Merge master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6

Conflicts:

	drivers/macintosh/adbhid.c
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 7916f4b..7bdae47 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -8,6 +8,8 @@
 
 source "drivers/mtd/Kconfig"
 
+source "drivers/of/Kconfig"
+
 source "drivers/parport/Kconfig"
 
 source "drivers/pnp/Kconfig"
@@ -56,6 +58,8 @@
 
 source "drivers/hwmon/Kconfig"
 
+source "drivers/ssb/Kconfig"
+
 source "drivers/mfd/Kconfig"
 
 source "drivers/media/Kconfig"
@@ -84,4 +88,7 @@
 
 source "drivers/kvm/Kconfig"
 
+source "drivers/uio/Kconfig"
+
+source "drivers/lguest/Kconfig"
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 503d825..a168eac 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -15,6 +15,8 @@
 obj-$(CONFIG_PNP)		+= pnp/
 obj-$(CONFIG_ARM_AMBA)		+= amba/
 
+obj-$(CONFIG_XEN)		+= xen/
+
 # char/ comes before serial/ etc so that the VT console is the boot-time
 # default.
 obj-y				+= char/
@@ -38,6 +40,7 @@
 obj-$(CONFIG_FUSION)		+= message/
 obj-$(CONFIG_FIREWIRE)		+= firewire/
 obj-$(CONFIG_IEEE1394)		+= ieee1394/
+obj-$(CONFIG_UIO)		+= uio/
 obj-y				+= cdrom/
 obj-y				+= auxdisplay/
 obj-$(CONFIG_MTD)		+= mtd/
@@ -63,6 +66,7 @@
 obj-$(CONFIG_W1)		+= w1/
 obj-$(CONFIG_POWER_SUPPLY)	+= power/
 obj-$(CONFIG_HWMON)		+= hwmon/
+obj-$(CONFIG_WATCHDOG)		+= char/watchdog/
 obj-$(CONFIG_PHONE)		+= telephony/
 obj-$(CONFIG_MD)		+= md/
 obj-$(CONFIG_BT)		+= bluetooth/
@@ -70,6 +74,7 @@
 obj-$(CONFIG_EDAC)		+= edac/
 obj-$(CONFIG_MCA)		+= mca/
 obj-$(CONFIG_EISA)		+= eisa/
+obj-$(CONFIG_LGUEST_GUEST)	+= lguest/
 obj-$(CONFIG_CPU_FREQ)		+= cpufreq/
 obj-$(CONFIG_MMC)		+= mmc/
 obj-$(CONFIG_NEW_LEDS)		+= leds/
@@ -82,3 +87,5 @@
 obj-$(CONFIG_DMA_ENGINE)	+= dma/
 obj-$(CONFIG_HID)		+= hid/
 obj-$(CONFIG_PPC_PS3)		+= ps3/
+obj-$(CONFIG_OF)		+= of/
+obj-$(CONFIG_SSB)		+= ssb/
diff --git a/drivers/acorn/README b/drivers/acorn/README
deleted file mode 100644
index d399c09..0000000
--- a/drivers/acorn/README
+++ /dev/null
@@ -1 +0,0 @@
-Drivers for the ACORN "podule" ARM specific bus.
diff --git a/drivers/acorn/block/Kconfig b/drivers/acorn/block/Kconfig
deleted file mode 100644
index a0ff25e..0000000
--- a/drivers/acorn/block/Kconfig
+++ /dev/null
@@ -1,36 +0,0 @@
-#
-# Block device driver configuration
-#
-
-menu "Acorn-specific block devices"
-	depends on ARCH_ARC || ARCH_A5K
-
-config BLK_DEV_FD1772
-	tristate "Old Archimedes floppy (1772) support"
-	depends on ARCH_ARC || ARCH_A5K
-	help
-	  Support the floppy drive on the Acorn Archimedes (A300, A4x0, A540,
-	  R140 and R260) series of computers; it supports only 720K floppies
-	  at the moment. If you don't have one of these machines just answer
-	  N.
-
-config BLK_DEV_MFM
-	tristate "MFM harddisk support"
-	depends on ARCH_ARC || ARCH_A5K
-	help
-	  Support the MFM hard drives on the Acorn Archimedes both
-	  on-board the A4x0 motherboards and via the Acorn MFM podules.
-	  Drives up to 64MB are supported. If you haven't got one of these
-	  machines or drives just say N.
-
-config BLK_DEV_MFM_AUTODETECT
-	bool "Autodetect hard drive geometry"
-	depends on BLK_DEV_MFM
-	help
-	  If you answer Y, the MFM code will attempt to automatically detect
-	  the cylinders/heads/sectors count on your hard drive. WARNING: This
-	  sometimes doesn't work and it also does some dodgy stuff which
-	  potentially might damage your drive.
-
-endmenu
-
diff --git a/drivers/acorn/block/Makefile b/drivers/acorn/block/Makefile
deleted file mode 100644
index 38a9afe..0000000
--- a/drivers/acorn/block/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Makefile for the Acorn block device drivers.
-#
-
-fd1772_mod-objs	:= fd1772.o fd1772dma.o
-mfmhd_mod-objs	:= mfmhd.o mfm.o
-
-obj-$(CONFIG_BLK_DEV_FD1772)	+= fd1772_mod.o
-obj-$(CONFIG_BLK_DEV_MFM)	+= mfmhd_mod.o
diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c
deleted file mode 100644
index 423ed08..0000000
--- a/drivers/acorn/block/fd1772.c
+++ /dev/null
@@ -1,1604 +0,0 @@
-/*
- *  linux/kernel/arch/arm/drivers/block/fd1772.c
- *  Based on ataflop.c in the m68k Linux
- *  Copyright (C) 1993  Greg Harp
- *  Atari Support by Bjoern Brauel, Roman Hodek
- *  Archimedes Support by Dave Gilbert (linux@treblig.org)
- *
- *  Big cleanup Sep 11..14 1994 Roman Hodek:
- *   - Driver now works interrupt driven
- *   - Support for two drives; should work, but I cannot test that :-(
- *   - Reading is done in whole tracks and buffered to speed up things
- *   - Disk change detection and drive deselecting after motor-off
- *     similar to TOS
- *   - Autodetection of disk format (DD/HD); untested yet, because I
- *     don't have an HD drive :-(
- *
- *  Fixes Nov 13 1994 Martin Schaller:
- *   - Autodetection works now
- *   - Support for 5 1/4" disks
- *   - Removed drive type (unknown on atari)
- *   - Do seeks with 8 Mhz
- *
- *  Changes by Andreas Schwab:
- *   - After errors in multiple read mode try again reading single sectors
- *  (Feb 1995):
- *   - Clean up error handling
- *   - Set blk_size for proper size checking
- *   - Initialize track register when testing presence of floppy
- *   - Implement some ioctl's
- *
- *  Changes by Torsten Lang:
- *   - When probing the floppies we should add the FDC1772CMDADD_H flag since
- *     the FDC1772 will otherwise wait forever when no disk is inserted...
- *
- *  Things left to do:
- *   - Formatting
- *   - Maybe a better strategy for disk change detection (does anyone
- *     know one?)
- *   - There are some strange problems left: The strangest one is
- *     that, at least on my TT (4+4MB), the first 2 Bytes of the last
- *     page of the TT-Ram (!) change their contents (some bits get
- *     set) while a floppy DMA is going on. But there are no accesses
- *     to these memory locations from the kernel... (I tested that by
- *     making the page read-only). I cannot explain what's going on...
- *   - Sometimes the drive-change-detection stops to work. The
- *     function is still called, but the WP bit always reads as 0...
- *     Maybe a problem with the status reg mode or a timing problem.
- *     Note 10/12/94: The change detection now seems to work reliably.
- *     There is no proof, but I've seen no hang for a long time...
- *
- * ARCHIMEDES changes: (gilbertd@cs.man.ac.uk)
- *     26/12/95 - Changed all names starting with FDC to FDC1772
- *                Removed all references to clock speed of FDC - we're stuck with 8MHz
- *                Modified disk_type structure to remove HD formats
- *
- *      7/ 1/96 - Wrote FIQ code, removed most remaining atariisms
- *
- *     13/ 1/96 - Well I think its read a single sector; but there is a problem
- *                fd_rwsec_done which is called in FIQ mode starts another transfer
- *                off (in fd_rwsec) while still in FIQ mode.  Because its still in
- *                FIQ mode it can't service the DMA and loses data. So need to
- *                heavily restructure.
- *     14/ 1/96 - Found that the definitions of the register numbers of the
- *                FDC were multiplied by 2 in the header for the 16bit words
- *                of the atari so half the writes were going in the wrong place.
- *                Also realised that the FIQ entry didn't make any attempt to
- *                preserve registers or return correctly; now in assembler.
- *
- *     11/ 2/96 - Hmm - doesn't work on real machine.  Auto detect doesn't
- *                and hacking that past seems to wait forever - check motor
- *                being turned on.
- *
- *     17/ 2/96 - still having problems - forcing track to -1 when selecting
- *                new drives seems to allow it to read first few sectors
- *                but then we get solid hangs at apparently random places
- *                which change depending what is happening.
- *
- *      9/ 3/96 - Fiddled a lot of stuff around to move to kernel 1.3.35
- *                A lot of fiddling in DMA stuff. Having problems with it
- *                constnatly thinking its timeing out. Ah - its timeout
- *                was set to (6*HZ) rather than jiffies+(6*HZ).  Now giving
- *                duff data!
- *
- *      5/ 4/96 - Made it use the new IOC_ macros rather than *ioc
- *                Hmm - giving unexpected FIQ and then timeouts
- *     18/ 8/96 - Ran through indent -kr -i8
- *                Some changes to disc change detect; don't know how well it
- *                works.
- *     24/ 8/96 - Put all the track buffering code back in from the atari
- *                code - I wonder if it will still work... No :-)
- *                Still works if I turn off track buffering.
- *     25/ 8/96 - Changed the timer expires that I'd added back to be 
- *                jiffies + ....; and it all sprang to life! Got 2.8K/sec
- *                off a cp -r of a 679K disc (showed 94% cpu usage!)
- *                (PC gets 14.3K/sec - 0% CPU!) Hmm - hard drive corrupt!
- *                Also perhaps that compile was with cache off.
- *                changed cli in fd_readtrack_check to cliIF
- *                changed vmallocs to kmalloc (whats the difference!!)
- *                Removed the busy wait loop in do_fd_request and replaced
- *                by a routine on tq_immediate; only 11% cpu on a dd off the
- *                raw disc - but the speed is the same.
- *	1/ 9/96 - Idea (failed!) - set the 'disable spin-up sequence'
- *		  when we read the track if we know the motor is on; didn't
- *		  help - perhaps we have to do it in stepping as well.
- *		  Nope. Still doesn't help.
- *		  Hmm - what seems to be happening is that fd_readtrack_check
- *		  is never getting called. Its job is to terminate the read
- *		  just after we think we should have got the data; otherwise
- *		  the fdc takes 1 second to timeout; which is what's happening
- *		  Now I can see 'readtrack_timer' being set (which should do the
- *		  call); but it never seems to be called - hmm!
- *		  OK - I've moved the check to my tq_immediate code -
- *		  and it WORKS! 13.95K/second at 19% CPU.
- *		  I wish I knew why that timer didn't work.....
- *
- *     16/11/96 - Fiddled and frigged for 2.0.18
- *
- * DAG 30/01/99 - Started frobbing for 2.2.1
- * DAG 20/06/99 - A little more frobbing:
- *		  Included include/asm/uaccess.h for get_user/put_user
- *
- * DAG  1/09/00 - Dusted off for 2.4.0-test7
- *                MAX_SECTORS was name clashing so it is now FD1772_...
- *                Minor parameter, name layouts for 2.4.x differences
- */
-
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/fcntl.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/workqueue.h>
-#include <linux/fd.h>
-#include <linux/fd1772.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/mm.h>
-#include <linux/bitops.h>
-
-#include <asm/arch/oldlatches.h>
-#include <asm/dma.h>
-#include <asm/hardware.h>
-#include <asm/hardware/ioc.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/mach-types.h>
-#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-
-/* Note: FD_MAX_UNITS could be redefined to 2 for the Atari (with
- * little additional rework in this file). But I'm not yet sure if
- * some other code depends on the number of floppies... (It is defined
- * in a public header!)
- */
-#if 0
-#undef FD_MAX_UNITS
-#define	FD_MAX_UNITS	2
-#endif
-
-/* Ditto worries for Arc - DAG */
-#define FD_MAX_UNITS 4
-#define TRACKBUFFER 0
-/*#define DEBUG*/
-
-#ifdef DEBUG
-#define DPRINT(a)	printk a
-#else
-#define DPRINT(a)
-#endif
-
-static struct request_queue *floppy_queue;
-
-#define MAJOR_NR FLOPPY_MAJOR
-#define FLOPPY_DMA 0
-#define DEVICE_NAME "floppy"
-#define QUEUE (floppy_queue)
-#define CURRENT elv_next_request(floppy_queue)
-
-/* Disk types: DD */
-static struct archy_disk_type {
-	const char *name;
-	unsigned spt;		/* sectors per track */
-	unsigned blocks;	/* total number of blocks */
-	unsigned stretch;	/* track doubling ? */
-} disk_type[] = {
-
-	{ "d360", 9, 720, 0 },			/* 360kB diskette */
-	{ "D360", 9, 720, 1 },			/* 360kb in 720kb drive */
-	{ "D720", 9, 1440, 0 },			/* 720kb diskette (DD) */
-	/*{ "D820", 10,1640, 0}, *//* DD disk with 82 tracks/10 sectors 
-	                              - DAG - can't see how type detect can distinguish this
-				      from 720K until it reads block 4 by which time its too late! */
-};
-
-#define	NUM_DISK_TYPES (sizeof(disk_type)/sizeof(*disk_type))
-
-/*
- * Maximum disk size (in kilobytes). This default is used whenever the
- * current disk size is unknown.
- */
-#define MAX_DISK_SIZE 720
-
-static struct gendisk *disks[FD_MAX_UNIT];
-
-/* current info on each unit */
-static struct archy_floppy_struct {
-	int connected;		/* !=0 : drive is connected */
-	int autoprobe;		/* !=0 : do autoprobe       */
-
-	struct archy_disk_type *disktype;	/* current type of disk */
-
-	int track;		/* current head position or -1
-				   * if unknown */
-	unsigned int steprate;	/* steprate setting */
-	unsigned int wpstat;	/* current state of WP signal
-				   * (for disk change detection) */
-} unit[FD_MAX_UNITS];
-
-/* DAG: On Arc we spin on a flag being cleared by fdc1772_comendhandler which
-   is an assembler routine */
-extern void fdc1772_comendhandler(void);	/* Actually doens't have these parameters - see fd1772.S */
-extern volatile int fdc1772_comendstatus;
-extern volatile int fdc1772_fdc_int_done;
-
-#define FDC1772BASE ((0x210000>>2)|0x80000000)
-
-#define FDC1772_READ(reg) inb(FDC1772BASE+(reg/2))
-
-/* DAG: You wouldn't be silly to ask why FDC1772_WRITE is a function rather
-   than the #def below - well simple - the #def won't compile - and I
-   don't understand why (__outwc not defined) */
-/* NOTE: Reg is 0,2,4,6 as opposed to 0,1,2,3 or 0,4,8,12 to keep compatibility
-   with the ST version of fd1772.h */
-/*#define FDC1772_WRITE(reg,val) outw(val,(reg+FDC1772BASE)); */
-void FDC1772_WRITE(int reg, unsigned char val)
-{
-	if (reg == FDC1772REG_CMD) {
-		DPRINT(("FDC1772_WRITE new command 0x%x @ %d\n", val,jiffies));
-		if (fdc1772_fdc_int_done) {
-			DPRINT(("FDC1772_WRITE: Hmm fdc1772_fdc_int_done true - resetting\n"));
-			fdc1772_fdc_int_done = 0;
-		};
-	};
-	outb(val, (reg / 2) + FDC1772BASE);
-};
-
-#define	FD1772_MAX_SECTORS	22
-
-unsigned char *DMABuffer;	/* buffer for writes */
-/*static unsigned long PhysDMABuffer; *//* physical address */
-/* DAG: On Arc we just go straight for the DMA buffer */
-#define PhysDMABuffer DMABuffer
-
-#ifdef TRACKBUFFER   
-unsigned char *TrackBuffer;       /* buffer for reads */
-#define PhysTrackBuffer TrackBuffer /* physical address */
-static int BufferDrive, BufferSide, BufferTrack;
-static int read_track;    /* non-zero if we are reading whole tracks */
-  
-#define SECTOR_BUFFER(sec)  (TrackBuffer + ((sec)-1)*512)
-#define IS_BUFFERED(drive,side,track) \
-    (BufferDrive == (drive) && BufferSide == (side) && BufferTrack == (track))
-#endif
-
-/*
- * These are global variables, as that's the easiest way to give
- * information to interrupts. They are the data used for the current
- * request.
- */
-static int SelectedDrive = 0;
-static int ReqCmd, ReqBlock;
-static int ReqSide, ReqTrack, ReqSector, ReqCnt;
-static int HeadSettleFlag = 0;
-static unsigned char *ReqData, *ReqBuffer;
-static int MotorOn = 0, MotorOffTrys;
-
-/* Synchronization of FDC1772 access. */
-static volatile int fdc_busy = 0;
-static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);
-
-
-/* long req'd for set_bit --RR */
-static unsigned long changed_floppies = 0xff, fake_change = 0;
-#define	CHECK_CHANGE_DELAY	HZ/2
-
-/* DAG - increased to 30*HZ - not sure if this is the correct thing to do */
-#define	FD_MOTOR_OFF_DELAY	(10*HZ)
-#define	FD_MOTOR_OFF_MAXTRY	(10*20)
-
-#define FLOPPY_TIMEOUT		(6*HZ)
-#define RECALIBRATE_ERRORS	4	/* After this many errors the drive
-					 * will be recalibrated. */
-#define MAX_ERRORS		8	/* After this many errors the driver
-					 * will give up. */
-
-#define	START_MOTOR_OFF_TIMER(delay)				\
-	do {							\
-		motor_off_timer.expires = jiffies + (delay);	\
-		add_timer( &motor_off_timer );			\
-		MotorOffTrys = 0;				\
-	} while(0)
-
-#define	START_CHECK_CHANGE_TIMER(delay)				\
-	do {							\
-	        mod_timer(&fd_timer, jiffies + (delay));	\
-	} while(0)
-
-#define	START_TIMEOUT()						\
-	do {							\
-		mod_timer(&timeout_timer, jiffies+FLOPPY_TIMEOUT); \
-	} while(0)
-
-#define	STOP_TIMEOUT()						\
-	do {							\
-		del_timer( &timeout_timer );			\
-	} while(0)
-
-#define ENABLE_IRQ() enable_irq(FIQ_FD1772+64);
-
-#define DISABLE_IRQ() disable_irq(FIQ_FD1772+64);
-
-static void fd1772_checkint(void);
-
-DECLARE_WORK(fd1772_tq, (void *)fd1772_checkint, NULL);
-/*
- * The driver is trying to determine the correct media format
- * while Probing is set. fd_rwsec_done() clears it after a
- * successful access.
- */
-static int Probing = 0;
-
-/* This flag is set when a dummy seek is necessary to make the WP
- * status bit accessible.
- */
-static int NeedSeek = 0;
-
-
-/***************************** Prototypes *****************************/
-
-static void fd_select_side(int side);
-static void fd_select_drive(int drive);
-static void fd_deselect(void);
-static void fd_motor_off_timer(unsigned long dummy);
-static void check_change(unsigned long dummy);
-static void floppy_irqconsequencehandler(void);
-static void fd_error(void);
-static void do_fd_action(int drive);
-static void fd_calibrate(void);
-static void fd_calibrate_done(int status);
-static void fd_seek(void);
-static void fd_seek_done(int status);
-static void fd_rwsec(void);
-#ifdef TRACKBUFFER   
-static void fd_readtrack_check( unsigned long dummy );  
-#endif
-static void fd_rwsec_done(int status);
-static void fd_times_out(unsigned long dummy);
-static void finish_fdc(void);
-static void finish_fdc_done(int dummy);
-static void floppy_off(unsigned int nr);
-static void setup_req_params(int drive);
-static void redo_fd_request(void);
-static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int
-		    cmd, unsigned long param);
-static void fd_probe(int drive);
-static int fd_test_drive_present(int drive);
-static void config_types(void);
-static int floppy_open(struct inode *inode, struct file *filp);
-static int floppy_release(struct inode *inode, struct file *filp);
-static void do_fd_request(request_queue_t *);
-
-/************************* End of Prototypes **************************/
-
-static DEFINE_TIMER(motor_off_timer, fd_motor_off_timer, 0, 0);
-
-#ifdef TRACKBUFFER
-static DEFINE_TIMER(readtrack_timer, fd_readtrack_check, 0, 0);
-#endif
-
-static DEFINE_TIMER(timeout_timer, fd_times_out, 0, 0);
-
-static DEFINE_TIMER(fd_timer, check_change, 0, 0);
-
-/* DAG: Haven't got a clue what this is? */
-int stdma_islocked(void)
-{
-	return 0;
-};
-
-/* Select the side to use. */
-
-static void fd_select_side(int side)
-{
-	oldlatch_aupdate(LATCHA_SIDESEL, side ? 0 : LATCHA_SIDESEL);
-}
-
-
-/* Select a drive, update the FDC1772's track register
- */
-
-static void fd_select_drive(int drive)
-{
-#ifdef DEBUG
-	printk("fd_select_drive:%d\n", drive);
-#endif
-	/* Hmm - nowhere do we seem to turn the motor on - I'm going to do it here! */
-	oldlatch_aupdate(LATCHA_MOTOR | LATCHA_INUSE, 0);
-
-	if (drive == SelectedDrive)
-		return;
-
-	oldlatch_aupdate(LATCHA_FDSELALL, 0xf - (1 << drive));
-
-	/* restore track register to saved value */
-	FDC1772_WRITE(FDC1772REG_TRACK, unit[drive].track);
-	udelay(25);
-
-	SelectedDrive = drive;
-}
-
-
-/* Deselect both drives. */
-
-static void fd_deselect(void)
-{
-	unsigned long flags;
-
-	DPRINT(("fd_deselect\n"));
-
-	oldlatch_aupdate(LATCHA_FDSELALL | LATCHA_MOTOR | LATCHA_INUSE, 0xf | LATCHA_MOTOR | LATCHA_INUSE);
-
-	SelectedDrive = -1;
-}
-
-
-/* This timer function deselects the drives when the FDC1772 switched the
- * motor off. The deselection cannot happen earlier because the FDC1772
- * counts the index signals, which arrive only if one drive is selected.
- */
-
-static void fd_motor_off_timer(unsigned long dummy)
-{
-	unsigned long flags;
-	unsigned char status;
-	int delay;
-
-	del_timer(&motor_off_timer);
-
-	if (SelectedDrive < 0)
-		/* no drive selected, needn't deselect anyone */
-		return;
-
-	save_flags(flags);
-	cli();
-
-	if (fdc_busy)		/* was stdma_islocked */
-		goto retry;
-
-	status = FDC1772_READ(FDC1772REG_STATUS);
-
-	if (!(status & 0x80)) {
-		/*
-		 * motor already turned off by FDC1772 -> deselect drives
-		 * In actual fact its this deselection which turns the motor
-		 * off on the Arc, since the motor control is actually on
-		 * Latch A
-		 */
-		DPRINT(("fdc1772: deselecting in fd_motor_off_timer\n"));
-		fd_deselect();
-		MotorOn = 0;
-		restore_flags(flags);
-		return;
-	}
-	/* not yet off, try again */
-
-retry:
-	restore_flags(flags);
-	/* Test again later; if tested too often, it seems there is no disk
-	 * in the drive and the FDC1772 will leave the motor on forever (or,
-	 * at least until a disk is inserted). So we'll test only twice
-	 * per second from then on...
-	 */
-	delay = (MotorOffTrys < FD_MOTOR_OFF_MAXTRY) ?
-	    (++MotorOffTrys, HZ / 20) : HZ / 2;
-	START_MOTOR_OFF_TIMER(delay);
-}
-
-
-/* This function is repeatedly called to detect disk changes (as good
- * as possible) and keep track of the current state of the write protection.
- */
-
-static void check_change(unsigned long dummy)
-{
-	static int drive = 0;
-
-	unsigned long flags;
-	int stat;
-
-	if (fdc_busy)
-		return;		/* Don't start poking about if the fdc is busy */
-
-	return;			/* let's just forget it for the mo DAG */
-
-	if (++drive > 1 || !unit[drive].connected)
-		drive = 0;
-
-	save_flags(flags);
-	cli();
-
-	if (!stdma_islocked()) {
-		stat = !!(FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_WPROT);
-
-		/* The idea here is that if the write protect line has changed then
-		the disc must have changed */
-		if (stat != unit[drive].wpstat) {
-			DPRINT(("wpstat[%d] = %d\n", drive, stat));
-			unit[drive].wpstat = stat;
-			set_bit(drive, &changed_floppies);
-		}
-	}
-	restore_flags(flags);
-
-	START_CHECK_CHANGE_TIMER(CHECK_CHANGE_DELAY);
-}
-
-
-/* Handling of the Head Settling Flag: This flag should be set after each
- * seek operation, because we don't use seeks with verify.
- */
-
-static inline void set_head_settle_flag(void)
-{
-	HeadSettleFlag = FDC1772CMDADD_E;
-}
-
-static inline int get_head_settle_flag(void)
-{
-	int tmp = HeadSettleFlag;
-	HeadSettleFlag = 0;
-	return (tmp);
-}
-
-
-
-
-/* General Interrupt Handling */
-
-static inline void copy_buffer(void *from, void *to)
-{
-	ulong *p1 = (ulong *) from, *p2 = (ulong *) to;
-	int cnt;
-
-	for (cnt = 512 / 4; cnt; cnt--)
-		*p2++ = *p1++;
-}
-
-static void (*FloppyIRQHandler) (int status) = NULL;
-
-static void floppy_irqconsequencehandler(void)
-{
-	unsigned char status;
-	void (*handler) (int);
-
-	fdc1772_fdc_int_done = 0;
-
-	handler = FloppyIRQHandler;
-	FloppyIRQHandler = NULL;
-
-	if (handler) {
-		nop();
-		status = (unsigned char) fdc1772_comendstatus;
-		DPRINT(("FDC1772 irq, status = %02x handler = %08lx\n", (unsigned int) status, (unsigned long) handler));
-		handler(status);
-	} else {
-		DPRINT(("FDC1772 irq, no handler status=%02x\n", fdc1772_comendstatus));
-	}
-	DPRINT(("FDC1772 irq: end of floppy_irq\n"));
-}
-
-
-/* Error handling: If some error happened, retry some times, then
- * recalibrate, then try again, and fail after MAX_ERRORS.
- */
-
-static void fd_error(void)
-{
-	printk("FDC1772: fd_error\n");
-	/*panic("fd1772: fd_error"); *//* DAG tmp */
-	if (!CURRENT)
-		return;
-	CURRENT->errors++;
-	if (CURRENT->errors >= MAX_ERRORS) {
-		printk("fd%d: too many errors.\n", SelectedDrive);
-		end_request(CURRENT, 0);
-	} else if (CURRENT->errors == RECALIBRATE_ERRORS) {
-		printk("fd%d: recalibrating\n", SelectedDrive);
-		if (SelectedDrive != -1)
-			unit[SelectedDrive].track = -1;
-	}
-	redo_fd_request();
-}
-
-
-
-#define	SET_IRQ_HANDLER(proc) do { FloppyIRQHandler = (proc); } while(0)
-
-
-/* do_fd_action() is the general procedure for a fd request: All
- * required parameter settings (drive select, side select, track
- * position) are checked and set if needed. For each of these
- * parameters and the actual reading or writing exist two functions:
- * one that starts the setting (or skips it if possible) and one
- * callback for the "done" interrupt. Each done func calls the next
- * set function to propagate the request down to fd_rwsec_done().
- */
-
-static void do_fd_action(int drive)
-{
-	struct request *req;
-	DPRINT(("do_fd_action unit[drive].track=%d\n", unit[drive].track));
-
-#ifdef TRACKBUFFER
-repeat:
-
-	if (IS_BUFFERED( drive, ReqSide, ReqTrack )) {
-		req = CURRENT;
-		if (ReqCmd == READ) {
-			copy_buffer( SECTOR_BUFFER(ReqSector), ReqData );
-			if (++ReqCnt < req->current_nr_sectors) {
-				/* read next sector */
-				setup_req_params( drive );
-				goto repeat;
-			} else {
-				/* all sectors finished */
-				req->nr_sectors -= req->current_nr_sectors;
-				req->sector += req->current_nr_sectors;
-				end_request(req, 1);
-				redo_fd_request();
-				return;
-			}
-		} else {
-			/* cmd == WRITE, pay attention to track buffer
-			 * consistency! */
-			copy_buffer( ReqData, SECTOR_BUFFER(ReqSector) );
-		}
-	}
-#endif
-
-	if (SelectedDrive != drive) {
-		/*unit[drive].track = -1; DAG */
-		fd_select_drive(drive);
-	};
-
-
-	if (unit[drive].track == -1)
-		fd_calibrate();
-	else if (unit[drive].track != ReqTrack << unit[drive].disktype->stretch)
-		fd_seek();
-	else
-		fd_rwsec();
-}
-
-
-/* Seek to track 0 if the current track is unknown */
-
-static void fd_calibrate(void)
-{
-	DPRINT(("fd_calibrate\n"));
-	if (unit[SelectedDrive].track >= 0) {
-		fd_calibrate_done(0);
-		return;
-	}
-	DPRINT(("fd_calibrate (after track compare)\n"));
-	SET_IRQ_HANDLER(fd_calibrate_done);
-	/* we can't verify, since the speed may be incorrect */
-	FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | unit[SelectedDrive].steprate);
-
-	NeedSeek = 1;
-	MotorOn = 1;
-	START_TIMEOUT();
-	/* wait for IRQ */
-}
-
-
-static void fd_calibrate_done(int status)
-{
-	DPRINT(("fd_calibrate_done()\n"));
-	STOP_TIMEOUT();
-
-	/* set the correct speed now */
-	if (status & FDC1772STAT_RECNF) {
-		printk("fd%d: restore failed\n", SelectedDrive);
-		fd_error();
-	} else {
-		unit[SelectedDrive].track = 0;
-		fd_seek();
-	}
-}
-
-
-/* Seek the drive to the requested track. The drive must have been
- * calibrated at some point before this.
- */
-
-static void fd_seek(void)
-{
-	unsigned long flags;
-	DPRINT(("fd_seek() to track %d (unit[SelectedDrive].track=%d)\n", ReqTrack,
-		unit[SelectedDrive].track));
-	if (unit[SelectedDrive].track == ReqTrack <<
-	    unit[SelectedDrive].disktype->stretch) {
-		fd_seek_done(0);
-		return;
-	}
-	FDC1772_WRITE(FDC1772REG_DATA, ReqTrack <<
-		      unit[SelectedDrive].disktype->stretch);
-	udelay(25);
-	save_flags(flags);
-	clf();
-	SET_IRQ_HANDLER(fd_seek_done);
-	FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK | unit[SelectedDrive].steprate |
-		/* DAG */
-		(MotorOn?FDC1772CMDADD_H:0));
-
-	restore_flags(flags);
-	MotorOn = 1;
-	set_head_settle_flag();
-	START_TIMEOUT();
-	/* wait for IRQ */
-}
-
-
-static void fd_seek_done(int status)
-{
-	DPRINT(("fd_seek_done()\n"));
-	STOP_TIMEOUT();
-
-	/* set the correct speed */
-	if (status & FDC1772STAT_RECNF) {
-		printk("fd%d: seek error (to track %d)\n",
-		       SelectedDrive, ReqTrack);
-		/* we don't know exactly which track we are on now! */
-		unit[SelectedDrive].track = -1;
-		fd_error();
-	} else {
-		unit[SelectedDrive].track = ReqTrack <<
-		    unit[SelectedDrive].disktype->stretch;
-		NeedSeek = 0;
-		fd_rwsec();
-	}
-}
-
-
-/* This does the actual reading/writing after positioning the head
- * over the correct track.
- */
-
-#ifdef TRACKBUFFER
-static int MultReadInProgress = 0;
-#endif
-
-
-static void fd_rwsec(void)
-{
-	unsigned long paddr, flags;
-	unsigned int rwflag, old_motoron;
-	unsigned int track;
-
-	DPRINT(("fd_rwsec(), Sec=%d, Access=%c\n", ReqSector, ReqCmd == WRITE ? 'w' : 'r'));
-	if (ReqCmd == WRITE) {
-		/*cache_push( (unsigned long)ReqData, 512 ); */
-		paddr = (unsigned long) ReqData;
-		rwflag = 0x100;
-	} else {
-		paddr = (unsigned long) PhysDMABuffer;
-#ifdef TRACKBUFFER
-		if (read_track)
-			paddr = (unsigned long)PhysTrackBuffer;
-#endif
-		rwflag = 0;
-	}
-
-	DPRINT(("fd_rwsec() before sidesel rwflag=%d sec=%d trk=%d\n", rwflag,
-		ReqSector, FDC1772_READ(FDC1772REG_TRACK)));
-	fd_select_side(ReqSide);
-
-	/*DPRINT(("fd_rwsec() before start sector \n")); */
-	/* Start sector of this operation */
-#ifdef TRACKBUFFER
-	FDC1772_WRITE( FDC1772REG_SECTOR, !read_track ? ReqSector : 1 );
-#else
-	FDC1772_WRITE( FDC1772REG_SECTOR, ReqSector );
-#endif
-
-	/* Cheat for track if stretch != 0 */
-	if (unit[SelectedDrive].disktype->stretch) {
-		track = FDC1772_READ(FDC1772REG_TRACK);
-		FDC1772_WRITE(FDC1772REG_TRACK, track >>
-			      unit[SelectedDrive].disktype->stretch);
-	}
-	udelay(25);
-
-	DPRINT(("fd_rwsec() before setup DMA \n"));
-	/* Setup DMA - Heavily modified by DAG */
-	save_flags(flags);
-	clf();
-	disable_dma(FLOPPY_DMA);
-	set_dma_mode(FLOPPY_DMA, rwflag ? DMA_MODE_WRITE : DMA_MODE_READ);
-	set_dma_addr(FLOPPY_DMA, (long) paddr);		/* DAG - changed from Atari specific */
-#ifdef TRACKBUFFER
-	set_dma_count(FLOPPY_DMA,(!read_track ? 1 : unit[SelectedDrive].disktype->spt)*512);
-#else
-	set_dma_count(FLOPPY_DMA, 512);		/* Block/sector size - going to have to change */
-#endif
-	SET_IRQ_HANDLER(fd_rwsec_done);
-	/* Turn on dma int */
-	enable_dma(FLOPPY_DMA);
-	/* Now give it something to do */
-	FDC1772_WRITE(FDC1772REG_CMD, (rwflag ? (FDC1772CMD_WRSEC | FDC1772CMDADD_P) : 
-#ifdef TRACKBUFFER
-	      (FDC1772CMD_RDSEC | (read_track ? FDC1772CMDADD_M : 0) |
-	      /* Hmm - the idea here is to stop the FDC spinning the disc
-	      up when we know that we already still have it spinning */
-	      (MotorOn?FDC1772CMDADD_H:0))
-#else
-	      FDC1772CMD_RDSEC
-#endif
-		));
-
-	restore_flags(flags);
-	DPRINT(("fd_rwsec() after DMA setup flags=0x%08x\n", flags));
-	/*sti(); *//* DAG - Hmm */
-	/* Hmm - should do something DAG */
-	old_motoron = MotorOn;
-	MotorOn = 1;
-	NeedSeek = 1;
-
-	/* wait for interrupt */
-
-#ifdef TRACKBUFFER
-	if (read_track) {
-		/*
-		 * If reading a whole track, wait about one disk rotation and
-		 * then check if all sectors are read. The FDC will even
-		 * search for the first non-existant sector and need 1 sec to
-		 * recognise that it isn't present :-(
-		 */
-		/* 1 rot. + 5 rot.s if motor was off  */
-		mod_timer(&readtrack_timer, jiffies + HZ/5 + (old_motoron ? 0 : HZ));
-		DPRINT(("Setting readtrack_timer to %d @ %d\n",
-			readtrack_timer.expires,jiffies));
-		MultReadInProgress = 1;
-	}
-#endif
-
-	/*DPRINT(("fd_rwsec() before START_TIMEOUT \n")); */
-	START_TIMEOUT();
-	/*DPRINT(("fd_rwsec() after START_TIMEOUT \n")); */
-}
-
-
-#ifdef TRACKBUFFER
-
-static void fd_readtrack_check(unsigned long dummy)
-{
-	unsigned long flags, addr;
-	extern unsigned char *fdc1772_dataaddr;
-
-	DPRINT(("fd_readtrack_check @ %d\n",jiffies));
-
-	save_flags(flags);
-	clf();
-
-	del_timer( &readtrack_timer );
-
-	if (!MultReadInProgress) {
-		/* This prevents a race condition that could arise if the
-		 * interrupt is triggered while the calling of this timer
-		 * callback function takes place. The IRQ function then has
-		 * already cleared 'MultReadInProgress'  when control flow
-		 * gets here.
-		 */
-		restore_flags(flags);
-		return;
-	}
-
-	/* get the current DMA address */
-	addr=(unsigned long)fdc1772_dataaddr; /* DAG - ? */
-	DPRINT(("fd_readtrack_check: addr=%x PhysTrackBuffer=%x\n",addr,PhysTrackBuffer));
-
-	if (addr >= (unsigned int)PhysTrackBuffer + unit[SelectedDrive].disktype->spt*512) {
-		/* already read enough data, force an FDC interrupt to stop
-		 * the read operation
-		 */
-		SET_IRQ_HANDLER( NULL );
-		restore_flags(flags);
-		DPRINT(("fd_readtrack_check(): done\n"));
-		FDC1772_WRITE( FDC1772REG_CMD, FDC1772CMD_FORCI );
-		udelay(25);
-
-		/* No error until now -- the FDC would have interrupted
-		 * otherwise!
-		 */
-		fd_rwsec_done( 0 );
-	} else {
-		/* not yet finished, wait another tenth rotation */
-		restore_flags(flags);
-		DPRINT(("fd_readtrack_check(): not yet finished\n"));
-		readtrack_timer.expires = jiffies + HZ/5/10;
-		add_timer( &readtrack_timer );
-	}
-}
-
-#endif
-
-static void fd_rwsec_done(int status)
-{
-	unsigned int track;
-
-	DPRINT(("fd_rwsec_done() status=%d @ %d\n", status,jiffies));
-
-#ifdef TRACKBUFFER
-	if (read_track && !MultReadInProgress)
-		return;
-
-	MultReadInProgress = 0;
-
-	STOP_TIMEOUT();
-
-	if (read_track)
-		del_timer( &readtrack_timer );
-#endif
-
-
-	/* Correct the track if stretch != 0 */
-	if (unit[SelectedDrive].disktype->stretch) {
-		track = FDC1772_READ(FDC1772REG_TRACK);
-		FDC1772_WRITE(FDC1772REG_TRACK, track <<
-			      unit[SelectedDrive].disktype->stretch);
-	}
-	if (ReqCmd == WRITE && (status & FDC1772STAT_WPROT)) {
-		printk("fd%d: is write protected\n", SelectedDrive);
-		goto err_end;
-	}
-	if ((status & FDC1772STAT_RECNF)
-#ifdef TRACKBUFFER
-	    /* RECNF is no error after a multiple read when the FDC
-	     * searched for a non-existant sector!
-	     */
-	    && !(read_track &&
-	       FDC1772_READ(FDC1772REG_SECTOR) > unit[SelectedDrive].disktype->spt)
-#endif
-	    ) {
-		if (Probing) {
-			if (unit[SelectedDrive].disktype > disk_type) {
-				/* try another disk type */
-				unit[SelectedDrive].disktype--;
-				set_capacity(disks[SelectedDrive],
-				    unit[SelectedDrive].disktype->blocks);
-			} else
-				Probing = 0;
-		} else {
-			/* record not found, but not probing. Maybe stretch wrong ? Restart probing */
-			if (unit[SelectedDrive].autoprobe) {
-				unit[SelectedDrive].disktype = disk_type + NUM_DISK_TYPES - 1;
-				set_capacity(disks[SelectedDrive],
-				    unit[SelectedDrive].disktype->blocks);
-				Probing = 1;
-			}
-		}
-		if (Probing) {
-			setup_req_params(SelectedDrive);
-#ifdef TRACKBUFFER
-			BufferDrive = -1;
-#endif
-			do_fd_action(SelectedDrive);
-			return;
-		}
-		printk("fd%d: sector %d not found (side %d, track %d)\n",
-		       SelectedDrive, FDC1772_READ(FDC1772REG_SECTOR), ReqSide, ReqTrack);
-		goto err_end;
-	}
-	if (status & FDC1772STAT_CRC) {
-		printk("fd%d: CRC error (side %d, track %d, sector %d)\n",
-		       SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR));
-		goto err_end;
-	}
-	if (status & FDC1772STAT_LOST) {
-		printk("fd%d: lost data (side %d, track %d, sector %d)\n",
-		       SelectedDrive, ReqSide, ReqTrack, FDC1772_READ(FDC1772REG_SECTOR));
-		goto err_end;
-	}
-	Probing = 0;
-
-	if (ReqCmd == READ) {
-#ifdef TRACKBUFFER
-		if (!read_track) {
-			/*cache_clear (PhysDMABuffer, 512);*/
-			copy_buffer (DMABuffer, ReqData);
-		} else {
-			/*cache_clear (PhysTrackBuffer, FD1772_MAX_SECTORS * 512);*/
-			BufferDrive = SelectedDrive;
-			BufferSide  = ReqSide;
-			BufferTrack = ReqTrack;
-			copy_buffer (SECTOR_BUFFER (ReqSector), ReqData);
-		}
-#else
-		/*cache_clear( PhysDMABuffer, 512 ); */
-		copy_buffer(DMABuffer, ReqData);
-#endif
-	}
-	if (++ReqCnt < CURRENT->current_nr_sectors) {
-		/* read next sector */
-		setup_req_params(SelectedDrive);
-		do_fd_action(SelectedDrive);
-	} else {
-		/* all sectors finished */
-		CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
-		CURRENT->sector += CURRENT->current_nr_sectors;
-		end_request(CURRENT, 1);
-		redo_fd_request();
-	}
-	return;
-
-err_end:
-#ifdef TRACKBUFFER
-	BufferDrive = -1;
-#endif
-
-	fd_error();
-}
-
-
-static void fd_times_out(unsigned long dummy)
-{
-	SET_IRQ_HANDLER(NULL);
-	/* If the timeout occurred while the readtrack_check timer was
-	 * active, we need to cancel it, else bad things will happen */
-	del_timer( &readtrack_timer ); 
-	FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI);
-	udelay(25);
-
-	printk("floppy timeout\n");
-	STOP_TIMEOUT();		/* hmm - should we do this ? */
-	fd_error();
-}
-
-
-/* The (noop) seek operation here is needed to make the WP bit in the
- * FDC1772 status register accessible for check_change. If the last disk
- * operation would have been a RDSEC, this bit would always read as 0
- * no matter what :-( To save time, the seek goes to the track we're
- * already on.
- */
-
-static void finish_fdc(void)
-{
-	/* DAG - just try without this dummy seek! */
-	finish_fdc_done(0);
-	return;
-
-	if (!NeedSeek) {
-		finish_fdc_done(0);
-	} else {
-		DPRINT(("finish_fdc: dummy seek started\n"));
-		FDC1772_WRITE(FDC1772REG_DATA, unit[SelectedDrive].track);
-		SET_IRQ_HANDLER(finish_fdc_done);
-		FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK);
-		MotorOn = 1;
-		START_TIMEOUT();
-		/* we must wait for the IRQ here, because the ST-DMA is
-		 * released immediately afterwards and the interrupt may be
-		 * delivered to the wrong driver.
-		 */
-	}
-}
-
-
-static void finish_fdc_done(int dummy)
-{
-	unsigned long flags;
-
-	DPRINT(("finish_fdc_done entered\n"));
-	STOP_TIMEOUT();
-	NeedSeek = 0;
-
-	if (timer_pending(&fd_timer) &&
-	    time_after(jiffies + 5, fd_timer.expires)) 
-		/* If the check for a disk change is done too early after this
-		 * last seek command, the WP bit still reads wrong :-((
-		 */
-		mod_timer(&fd_timer, jiffies + 5);
-	else {
-		/*      START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */
-	};
-	del_timer(&motor_off_timer);
-	START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY);
-
-	save_flags(flags);
-	cli();
-	/* stdma_release(); - not sure if I should do something DAG  */
-	fdc_busy = 0;
-	wake_up(&fdc_wait);
-	restore_flags(flags);
-
-	DPRINT(("finish_fdc() finished\n"));
-}
-
-
-/* Prevent "aliased" accesses. */
-static int fd_ref[4];
-static int fd_device[4];
-
-/* dummy for blk.h */
-static void floppy_off(unsigned int nr)
-{
-}
-
-
-/* On the old arcs write protect depends on the particular model
-   of machine.  On the A310, R140, and A440 there is a disc changed
-   detect, however on the A4x0/1 range there is not.  There
-   is nothing to tell you which machine your on.
-   At the moment I'm just marking changed always. I've
-   left the Atari's 'change on write protect change' code in this
-   part (but nothing sets it).
-   RiscOS apparently checks the disc serial number etc. to detect changes
-   - but if it sees a disc change line go high (?) it flips to using
-   it. Well  maybe I'll add that in the future (!?)
-*/
-static int check_floppy_change(struct gendisk *disk)
-{
-	struct archy_floppy_struct *p = disk->private_data;
-	unsigned int drive = p - unit;
-
-	if (test_bit(drive, &fake_change)) {
-		/* simulated change (e.g. after formatting) */
-		return 1;
-	}
-	if (test_bit(drive, &changed_floppies)) {
-		/* surely changed (the WP signal changed at least once) */
-		return 1;
-	}
-	if (p->wpstat) {
-		/* WP is on -> could be changed: to be sure, buffers should be
-		   * invalidated...
-		 */
-		return 1;
-	}
-	return 1; /* DAG - was 0 */
-}
-
-static int floppy_revalidate(struct gendisk *disk)
-{
-	struct archy_floppy_struct *p = disk->private_data;
-	unsigned int drive = p - unit;
-
-	if (test_bit(drive, &changed_floppies) || test_bit(drive, &fake_change)
-	    || unit[drive].disktype == 0) {
-#ifdef TRACKBUFFER
-		BufferDrive = -1;
-#endif
-		clear_bit(drive, &fake_change);
-		clear_bit(drive, &changed_floppies);
-		p->disktype = 0;
-	}
-	return 0;
-}
-
-/* This sets up the global variables describing the current request. */
-
-static void setup_req_params(int drive)
-{
-	int block = ReqBlock + ReqCnt;
-
-	ReqTrack = block / unit[drive].disktype->spt;
-	ReqSector = block - ReqTrack * unit[drive].disktype->spt + 1;
-	ReqSide = ReqTrack & 1;
-	ReqTrack >>= 1;
-	ReqData = ReqBuffer + 512 * ReqCnt;
-
-#ifdef TRACKBUFFER
-	read_track = (ReqCmd == READ && CURRENT->errors == 0);
-#endif
-
-	DPRINT(("Request params: Si=%d Tr=%d Se=%d Data=%08lx\n", ReqSide,
-		ReqTrack, ReqSector, (unsigned long) ReqData));
-}
-
-
-static void redo_fd_request(void)
-{
-	int drive, type;
-	struct archy_floppy_struct *floppy;
-
-	DPRINT(("redo_fd_request: CURRENT=%p dev=%s CURRENT->sector=%ld\n",
-		CURRENT, CURRENT ? CURRENT->rq_disk->disk_name : "",
-		CURRENT ? CURRENT->sector : 0));
-
-repeat:
-
-	if (!CURRENT)
-		goto the_end;
-
-	floppy = CURRENT->rq_disk->private_data;
-	drive = floppy - unit;
-	type = fd_device[drive];
-
-	if (!floppy->connected) {
-		/* drive not connected */
-		printk("Unknown Device: fd%d\n", drive);
-		end_request(CURRENT, 0);
-		goto repeat;
-	}
-	if (type == 0) {
-		if (!floppy->disktype) {
-			Probing = 1;
-			floppy->disktype = disk_type + NUM_DISK_TYPES - 1;
-			set_capacity(disks[drive], floppy->disktype->blocks);
-			floppy->autoprobe = 1;
-		}
-	} else {
-		/* user supplied disk type */
-		--type;
-		if (type >= NUM_DISK_TYPES) {
-			printk("fd%d: invalid disk format", drive);
-			end_request(CURRENT, 0);
-			goto repeat;
-		}
-		floppy->disktype = &disk_type[type];
-		set_capacity(disks[drive], floppy->disktype->blocks);
-		floppy->autoprobe = 0;
-	}
-
-	if (CURRENT->sector + 1 > floppy->disktype->blocks) {
-		end_request(CURRENT, 0);
-		goto repeat;
-	}
-	/* stop deselect timer */
-	del_timer(&motor_off_timer);
-
-	ReqCnt = 0;
-	ReqCmd = rq_data_dir(CURRENT);
-	ReqBlock = CURRENT->sector;
-	ReqBuffer = CURRENT->buffer;
-	setup_req_params(drive);
-	do_fd_action(drive);
-
-	return;
-
-the_end:
-	finish_fdc();
-}
-
-static void fd1772_checkint(void)
-{
-	extern int fdc1772_bytestogo;
-
-	/*printk("fd1772_checkint %d\n",fdc1772_fdc_int_done);*/
-	if (fdc1772_fdc_int_done)
-		floppy_irqconsequencehandler();
-	if ((MultReadInProgress) && (fdc1772_bytestogo==0)) fd_readtrack_check(0);
-	if (fdc_busy) {
-		schedule_work(&fd1772_tq);
-	}
-}
-
-static void do_fd_request(request_queue_t* q)
-{
-	unsigned long flags;
-
-	DPRINT(("do_fd_request for pid %d\n", current->pid));
-	if (fdc_busy) return;
-	save_flags(flags);
-	cli();
-	wait_event(fdc_wait, !fdc_busy);
-	fdc_busy = 1;
-	ENABLE_IRQ();
-	restore_flags(flags);
-
-	fdc1772_fdc_int_done = 0;
-
-	redo_fd_request();
-
-	schedule_work(&fd1772_tq);
-}
-
-
-static int invalidate_drive(struct block_device *bdev)
-{
-	struct archy_floppy_struct *p = bdev->bd_disk->private_data;
-	/* invalidate the buffer track to force a reread */
-#ifdef TRACKBUFFER
-	BufferDrive = -1;
-#endif
-
-	set_bit(p - unit, &fake_change);
-	return 0;
-}
-
-static int fd_ioctl(struct inode *inode, struct file *filp,
-		    unsigned int cmd, unsigned long param)
-{
-	struct block_device *bdev = inode->i_bdev;
-
-	switch (cmd) {
-	case FDFMTEND:
-	case FDFLUSH:
-		invalidate_drive(bdev);
-		check_disk_change(bdev);
-	case FDFMTBEG:
-		return 0;
-	default:
-		return -EINVAL;
-	}
-}
-
-
-/* Initialize the 'unit' variable for drive 'drive' */
-
-static void fd_probe(int drive)
-{
-	unit[drive].connected = 0;
-	unit[drive].disktype = NULL;
-
-	if (!fd_test_drive_present(drive))
-		return;
-
-	unit[drive].connected = 1;
-	unit[drive].track = -1; /* If we put the auto detect back in this can go to 0 */
-	unit[drive].steprate = FDC1772STEP_6;
-	MotorOn = 1;		/* from probe restore operation! */
-}
-
-
-/* This function tests the physical presence of a floppy drive (not
- * whether a disk is inserted). This is done by issuing a restore
- * command, waiting max. 2 seconds (that should be enough to move the
- * head across the whole disk) and looking at the state of the "TR00"
- * signal. This should now be raised if there is a drive connected
- * (and there is no hardware failure :-) Otherwise, the drive is
- * declared absent.
- */
-
-static int fd_test_drive_present(int drive)
-{
-	unsigned long timeout;
-	unsigned char status;
-	int ok;
-
-	printk("fd_test_drive_present %d\n", drive);
-	if (drive > 1)
-		return (0);
-	return (1);		/* Simple hack for the moment - the autodetect doesn't seem to work on arc */
-	fd_select_drive(drive);
-
-	/* disable interrupt temporarily */
-	DISABLE_IRQ();
-	FDC1772_WRITE(FDC1772REG_TRACK, 0x00);	/* was ff00 why? */
-	FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | FDC1772CMDADD_H | FDC1772STEP_6);
-
-	/*printk("fd_test_drive_present: Going into timeout loop\n"); */
-	for (ok = 0, timeout = jiffies + 2 * HZ + HZ / 2; time_before(jiffies, timeout);) {
-		/*  What does this piece of atariism do? - query for an interrupt? */
-		/*  if (!(mfp.par_dt_reg & 0x20))
-		   break; */
-		/* Well this is my nearest guess - quit when we get an FDC interrupt */
-		if (ioc_readb(IOC_FIQSTAT) & 2)
-			break;
-	}
-
-	/*printk("fd_test_drive_present: Coming out of timeout loop\n"); */
-	status = FDC1772_READ(FDC1772REG_STATUS);
-	ok = (status & FDC1772STAT_TR00) != 0;
-
-	/*printk("fd_test_drive_present: ok=%d\n",ok); */
-	/* force interrupt to abort restore operation (FDC1772 would try
-	 * about 50 seconds!) */
-	FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI);
-	udelay(500);
-	status = FDC1772_READ(FDC1772REG_STATUS);
-	udelay(20);
-	/*printk("fd_test_drive_present: just before OK code %d\n",ok); */
-
-	if (ok) {
-		/* dummy seek command to make WP bit accessible */
-		FDC1772_WRITE(FDC1772REG_DATA, 0);
-		FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_SEEK);
-		printk("fd_test_drive_present: just before wait for int\n");
-		/* DAG: Guess means wait for interrupt */
-		while (!(ioc_readb(IOC_FIQSTAT) & 2));
-		printk("fd_test_drive_present: just after wait for int\n");
-		status = FDC1772_READ(FDC1772REG_STATUS);
-	}
-	printk("fd_test_drive_present: just before ENABLE_IRQ\n");
-	ENABLE_IRQ();
-	printk("fd_test_drive_present: about to return\n");
-	return (ok);
-}
-
-
-/* Look how many and which kind of drives are connected. If there are
- * floppies, additionally start the disk-change and motor-off timers.
- */
-
-static void config_types(void)
-{
-	int drive, cnt = 0;
-
-	printk("Probing floppy drive(s):\n");
-	for (drive = 0; drive < FD_MAX_UNITS; drive++) {
-		fd_probe(drive);
-		if (unit[drive].connected) {
-			printk("fd%d\n", drive);
-			++cnt;
-		}
-	}
-
-	if (FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_BUSY) {
-		/* If FDC1772 is still busy from probing, give it another FORCI
-		 * command to abort the operation. If this isn't done, the FDC1772
-		 * will interrupt later and its IRQ line stays low, because
-		 * the status register isn't read. And this will block any
-		 * interrupts on this IRQ line :-(
-		 */
-		FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_FORCI);
-		udelay(500);
-		FDC1772_READ(FDC1772REG_STATUS);
-		udelay(20);
-	}
-	if (cnt > 0) {
-		START_MOTOR_OFF_TIMER(FD_MOTOR_OFF_DELAY);
-		if (cnt == 1)
-			fd_select_drive(0);
-		/*START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY ); */
-	}
-}
-
-/*
- * floppy_open check for aliasing (/dev/fd0 can be the same as
- * /dev/PS0 etc), and disallows simultaneous access to the same
- * drive with different device numbers.
- */
-
-static int floppy_open(struct inode *inode, struct file *filp)
-{
-	int drive = iminor(inode) & 3;
-	int type =  iminor(inode) >> 2;
-	int old_dev = fd_device[drive];
-
-	if (fd_ref[drive] && old_dev != type)
-		return -EBUSY;
-
-	if (fd_ref[drive] == -1 || (fd_ref[drive] && filp->f_flags & O_EXCL))
-		return -EBUSY;
-
-	if (filp->f_flags & O_EXCL)
-		fd_ref[drive] = -1;
-	else
-		fd_ref[drive]++;
-
-	fd_device[drive] = type;
-
-	if (filp->f_flags & O_NDELAY)
-		return 0;
-
-	if (filp->f_mode & 3) {
-		check_disk_change(inode->i_bdev);
-		if (filp->f_mode & 2) {
-			if (unit[drive].wpstat) {
-				floppy_release(inode, filp);
-				return -EROFS;
-			}
-		}
-	}
-	return 0;
-}
-
-
-static int floppy_release(struct inode *inode, struct file *filp)
-{
-	int drive = iminor(inode) & 3;
-
-	if (fd_ref[drive] < 0)
-		fd_ref[drive] = 0;
-	else if (!fd_ref[drive]--) {
-		printk("floppy_release with fd_ref == 0");
-		fd_ref[drive] = 0;
-	}
-
-	return 0;
-}
-
-static struct block_device_operations floppy_fops =
-{
-	.open		= floppy_open,
-	.release	= floppy_release,
-	.ioctl		= fd_ioctl,
-	.media_changed	= check_floppy_change,
-	.revalidate_disk= floppy_revalidate,
-};
-
-static struct kobject *floppy_find(dev_t dev, int *part, void *data)
-{
-	int drive = *part & 3;
-	if ((*part >> 2) > NUM_DISK_TYPES || drive >= FD_MAX_UNITS)
-		return NULL;
-	*part = 0;
-	return get_disk(disks[drive]);
-}
-
-int fd1772_init(void)
-{
-	static DEFINE_SPINLOCK(lock);
-	int i, err = -ENOMEM;
-
-	if (!machine_is_archimedes())
-		return 0;
-
-	for (i = 0; i < FD_MAX_UNITS; i++) {
-		disks[i] = alloc_disk(1);
-		if (!disks[i])
-			goto err_disk;
-	}
-
-	err = register_blkdev(MAJOR_NR, "fd");
-	if (err)
-		goto err_disk;
-
-	err = -EBUSY;
-	if (request_dma(FLOPPY_DMA, "fd1772")) {
-		printk("Unable to grab DMA%d for the floppy (1772) driver\n", FLOPPY_DMA);
-		goto err_blkdev;
-	};
-
-	if (request_dma(FIQ_FD1772, "fd1772 end")) {
-		printk("Unable to grab DMA%d for the floppy (1772) driver\n", FIQ_FD1772);
-		goto err_dma1;
-	};
-
-	/* initialize variables */
-	SelectedDrive = -1;
-#ifdef TRACKBUFFER
-	BufferDrive = BufferSide = BufferTrack = -1;
-	/* Atari uses 512 - I want to eventually cope with 1K sectors */
-	DMABuffer = kmalloc((FD1772_MAX_SECTORS+1)*512,GFP_KERNEL);
-	TrackBuffer = DMABuffer + 512;
-#else
-	/* Allocate memory for the DMAbuffer - on the Atari this takes it
-	   out of some special memory... */
-	DMABuffer = kmalloc(2048);	/* Copes with pretty large sectors */
-#endif
-	err = -ENOMEM;
-	if (!DMAbuffer)
-		goto err_dma2;
-
-	enable_dma(FIQ_FD1772);	/* This inserts a call to our command end routine */
-
-	floppy_queue = blk_init_queue(do_fd_request, &lock);
-	if (!floppy_queue)
-		goto err_queue;
-
-	for (i = 0; i < FD_MAX_UNITS; i++) {
-		unit[i].track = -1;
-		disks[i]->major = MAJOR_NR;
-		disks[i]->first_minor = 0;
-		disks[i]->fops = &floppy_fops;
-		sprintf(disks[i]->disk_name, "fd%d", i);
-		disks[i]->private_data = &unit[i];
-		disks[i]->queue = floppy_queue;
-		set_capacity(disks[i], MAX_DISK_SIZE * 2);
-	}
-	blk_register_region(MKDEV(MAJOR_NR, 0), 256, THIS_MODULE,
-				floppy_find, NULL, NULL);
-
-	for (i = 0; i < FD_MAX_UNITS; i++)
-		add_disk(disks[i]);
-
-	config_types();
-
-	return 0;
-
- err_queue:
-	kfree(DMAbuffer);
- err_dma2:
-	free_dma(FIQ_FD1772);
-
- err_dma1:
-	free_dma(FLOPPY_DMA);
-
- err_blkdev:
-	unregister_blkdev(MAJOR_NR, "fd");
-
- err_disk:
-	while (i--)
-		put_disk(disks[i]);
-	return err;
-}
diff --git a/drivers/acorn/block/fd1772dma.S b/drivers/acorn/block/fd1772dma.S
deleted file mode 100644
index 7964435..0000000
--- a/drivers/acorn/block/fd1772dma.S
+++ /dev/null
@@ -1,100 +0,0 @@
-#include <asm/hardware.h>
-
-@ Code for DMA with the 1772 fdc
-.text
-
-
-  .global fdc1772_dataaddr
-fdc1772_fiqdata:
-@ Number of bytes left to DMA
-  .global fdc1772_bytestogo
-fdc1772_bytestogo:
-  .word 0
-@ Place to put/get data from in DMA
-  .global fdc1772_dataaddr
-fdc1772_dataaddr:
-  .word 0
-  
-  .global fdc1772_fdc_int_done
-fdc1772_fdc_int_done:
-  .word 0
-  .global fdc1772_comendstatus
-fdc1772_comendstatus:
-  .word 0
-
-@ We hang this off DMA channel 1
-    .global fdc1772_comendhandler
-fdc1772_comendhandler:
-  mov      r8,#IOC_BASE
-  ldrb     r9,[r8,#0x34]    @ IOC FIQ status
-  tst      r9,#2
-  subeqs   pc,r14,#4        @ should I leave a space here
-  orr      r9,r8,#0x10000   @ FDC base
-  adr      r8,fdc1772_fdc_int_done
-  ldrb     r10,[r9,#0]  @ FDC status
-  mov      r9,#1        @ Got a FIQ flag
-  stmia    r8,{r9,r10}
-  subs     pc,r14,#4
-
-
-    .global fdc1772_dma_read
-fdc1772_dma_read:
-  mov      r8,#IOC_BASE
-  ldrb     r9,[r8,#0x34]    @ IOC FIQ status
-  tst      r9,#1
-  beq      fdc1772_dma_read_notours
-  orr      r8,r8,#0x10000   @ FDC base
-  ldrb     r10,[r8,#0xc]   @ Read from FDC data reg (also clears interrupt)
-  ldmia    r11,{r8,r9}
-  subs     r8,r8,#1        @ One less byte to go
-  @ If there was somewhere for this data to go then store it and update pointers
-  strplb   r10,[r9],#1     @ Store the data and increment the pointer
-  stmplia  r11,{r8,r9}     @ Update count/pointers
-  @ Handle any other interrupts if there are any
-fdc1772_dma_read_notours:
-  @ Cant branch because this code has been copied down to the FIQ vector
-  ldr pc,[pc,#-4]
-  .word fdc1772_comendhandler
-  .global fdc1772_dma_read_end
-fdc1772_dma_read_end:
-
-    .global fdc1772_dma_write
-fdc1772_dma_write:
-  mov      r8,#IOC_BASE
-  ldrb     r9,[r8,#0x34]    @ IOC FIQ status
-  tst      r9,#1
-  beq      fdc1772_dma_write_notours
-  orr      r8,r8,#0x10000   @ FDC base
-  ldmia    r11,{r9,r10}
-  subs     r9,r9,#1        @ One less byte to go
-  @ If there really is some data then get it, store it and update count
-  ldrplb   r12,[r10],#1
-  strplb   r12,[r8,#0xc]   @ write it to FDC data reg
-  stmplia  r11,{r9,r10}    @ Update count and pointer - should clear interrupt
-  @ Handle any other interrupts
-fdc1772_dma_write_notours:
-  @ Cant branch because this code has been copied down to the FIQ vector
-  ldr pc,[pc,#-4]
-  .word fdc1772_comendhandler
-
-  .global fdc1772_dma_write_end
-fdc1772_dma_write_end:
-  
-
-@ Setup the FIQ R11 to point to the data and store the count, address
-@ for this dma
-@ R0=count
-@ R1=address
-  .global fdc1772_setupdma
-fdc1772_setupdma:
-	@ The big job is flipping in and out of FIQ mode
-	adr	r2,fdc1772_fiqdata	@ This is what we really came here for
-  stmia  r2,{r0,r1}
-	mov	r3, pc
-	teqp	pc,#0x0c000001	@ Disable FIQs, IRQs and switch to FIQ mode
-	mov	r0,r0      	@ NOP
-	mov r11,r2
-	teqp	r3,#0		@ Normal mode
-	mov	r0,r0		@ NOP
-  mov pc,r14
-
diff --git a/drivers/acorn/block/mfm.S b/drivers/acorn/block/mfm.S
deleted file mode 100644
index c90cbd4..0000000
--- a/drivers/acorn/block/mfm.S
+++ /dev/null
@@ -1,162 +0,0 @@
-@ Read/Write DMA code for the ST506/MFM hard drive controllers on the A400 Acorn Archimedes
-@   motherboard and on ST506 expansion podules.
-@ (c) David Alan Gilbert (linux@treblig.org) 1996-1999
-
-#include <asm/assembler.h>
- 
-hdc63463_irqdata:
-@ Controller base address
-  .global hdc63463_baseaddress
-hdc63463_baseaddress:
-  .word 0
-
-  .global hdc63463_irqpolladdress
-hdc63463_irqpolladdress:
-  .word 0
- 
-  .global hdc63463_irqpollmask
-hdc63463_irqpollmask:
-  .word 0
-
-@ where to read/write data  from the kernel data space
-  .global hdc63463_dataptr
-hdc63463_dataptr:
-  .word 0
-
-@ Number of bytes left to transfer
-  .global hdc63463_dataleft
-hdc63463_dataleft:
-  .word 0
-
-@ -------------------------------------------------------------------------
-@ hdc63463_writedma: DMA from host to controller
-@  internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask
-@                      r3=data ptr, r4=data left, r5,r6=temporary
-  .global hdc63463_writedma
-hdc63463_writedma:
-  stmfd sp!,{r4-r7}
-  adr r5,hdc63463_irqdata
-  ldmia r5,{r0,r1,r2,r3,r4}
-
-writedma_again:
-
-  @ test number of remaining bytes to transfer
-  cmp r4,#0
-  beq writedma_end
-  bmi writedma_end
-
-  @ Check the hdc is interrupting
-  ldrb r5,[r1,#0]
-  tst r5,r2
-  beq writedma_end
-
-  @ Transfer a block of upto 256 bytes
-  cmp r4,#256
-  movlt r7,r4
-  movge r7,#256
-
-  @ Check the hdc is still busy and command has not ended and no errors
-  ldr r5,[r0,#32]     @ Status reg - 16 bit - its the top few bits which are status
-  @ think we should continue DMA until it drops busy - perhaps this was
-  @ the main problem with corrected errors causing a hang
-  @tst r5,#0x3c00        @ Test for things which should be off
-  @bne writedma_end
-  and r5,r5,#0x8000        @ This is test for things which should be on: Busy
-  cmp r5,#0x8000
-  bne writedma_end 
-
-  @ Bytes remaining at end
-  sub r4,r4,r7
-
-  @ HDC Write register location
-  add r0,r0,#32+8
-
-writedma_loop:
-  @ OK - pretty sure we should be doing this
-
-  ldr r5,[r3],#4          @ Get a word to be written
-  @ get bottom half to be sent first
-  mov r6,r5,lsl#16        @ Separate the first 2 bytes
-  orr r2,r6,r6,lsr #16    @ Duplicate them in the bottom half of the word
-  @ now the top half
-  mov r6,r5,lsr#16        @ Get 2nd 2 bytes
-  orr r6,r6,r6,lsl#16     @ Duplicate
-  @str r6,[r0]       @ to hdc
-  stmia r0,{r2,r6}
-  subs r7,r7,#4           @ Dec. number of bytes left
-  bne writedma_loop
-
-  @ If we were too slow we had better go through again - DAG - took out with new interrupt routine
-  @ sub r0,r0,#32+8
-  @ adr r2,hdc63463_irqdata
-  @ ldr r2,[r2,#8]
-  @ b writedma_again
-
-writedma_end:
-  adr r5,hdc63463_irqdata+12
-  stmia r5,{r3,r4}
-  ldmfd sp!,{r4-r7}
-  RETINSTR(mov,pc,lr)
-
-@ -------------------------------------------------------------------------
-@ hdc63463_readdma: DMA from controller to host
-@  internal reg usage: r0=hdc base address, r1=irq poll address, r2=poll mask
-@                      r3=data ptr, r4=data left, r5,r6=temporary
-  .global hdc63463_readdma
-hdc63463_readdma:
-  stmfd sp!,{r4-r7}
-  adr r5,hdc63463_irqdata
-  ldmia r5,{r0,r1,r2,r3,r4}
-
-readdma_again:
-  @ test number of remaining bytes to transfer
-  cmp r4,#0
-  beq readdma_end
-  bmi readdma_end
-
-  @ Check the hdc is interrupting
-  ldrb r5,[r1,#0]
-  tst r5,r2
-  beq readdma_end
-
-  @ Check the hdc is still busy and command has not ended and no errors
-  ldr r5,[r0,#32]     @ Status reg - 16 bit - its the top few bits which are status
-  @ think we should continue DMA until it drops busy - perhaps this was
-  @ the main problem with corrected errors causing a hang
-  @tst r5,#0x3c00      @ Test for things which should be off
-  @bne readdma_end
-  and r5,r5,#0x8000        @ This is test for things which should be on: Busy
-  cmp r5,#0x8000
-  bne readdma_end 
-
-  @ Transfer a block of upto 256 bytes
-  cmp r4,#256
-  movlt r7,r4
-  movge r7,#256
-
-  @ Bytes remaining at end
-  sub r4,r4,r7
-
-  @ Set a pointer to the data register in the HDC
-  add r0,r0,#8
-readdma_loop:
-  @ OK - pretty sure we should be doing this
-  ldmia r0,{r5,r6}
-  mov r5,r5,lsl#16
-  mov r6,r6,lsl#16
-  orr r6,r6,r5,lsr #16
-  str r6,[r3],#4
-  subs r7,r7,#4        @ Decrement bytes to go
-  bne readdma_loop
-
-  @ Try reading multiple blocks - if this was fast enough then I do not think
-  @ this should help - NO taken out DAG - new interrupt handler has
-  @ non-consecutive memory blocks
-  @ sub r0,r0,#8
-  @ b readdma_again
-
-readdma_end:
-  adr r5,hdc63463_irqdata+12
-  stmia r5,{r3,r4}
-  ldmfd sp!,{r4-r7}
-  RETINSTR(mov,pc,lr)
diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c
deleted file mode 100644
index d85520f..0000000
--- a/drivers/acorn/block/mfmhd.c
+++ /dev/null
@@ -1,1385 +0,0 @@
-/*
- * linux/drivers/acorn/block/mfmhd.c
- *
- * Copyright (C) 1995, 1996 Russell King, Dave Alan Gilbert (gilbertd@cs.man.ac.uk)
- *
- * MFM hard drive code [experimental]
- */
-
-/*
- * Change list:
- *
- *  3/2/96:DAG: Started a change list :-)
- *              Set the hardsect_size pointers up since we are running 256 byte
- *                sectors
- *              Added DMA code, put it into the rw_intr
- *              Moved RCAL out of generic interrupt code - don't want to do it
- *                while DMA'ing - its now in individual handlers.
- *              Took interrupt handlers off task queue lists and called
- *                directly - not sure of implications.
- *
- * 18/2/96:DAG: Well its reading OK I think, well enough for image file code
- *              to find the image file; but now I've discovered that I actually
- *              have to put some code in for image files.
- *
- *              Added stuff for image files; seems to work, but I've not
- *              got a multisegment image file (I don't think!).
- *              Put in a hack (yep a real hack) for multiple cylinder reads.
- *              Not convinced its working.
- *
- *  5/4/96:DAG: Added asm/hardware.h and use IOC_ macros
- *              Rewrote dma code in mfm.S (again!) - now takes a word at a time
- *              from main RAM for speed; still doesn't feel speedy!
- *
- * 20/4/96:DAG: After rewriting mfm.S a heck of a lot of times and speeding
- *              things up, I've finally figured out why its so damn slow.
- *              Linux is only reading a block at a time, and so you never
- *              get more than 1K per disc revoloution ~=60K/second.
- *
- * 27/4/96:DAG: On Russell's advice I change ll_rw_blk.c to ask it to
- *              join adjacent blocks together. Everything falls flat on its
- *              face.
- *              Four hours of debugging later; I hadn't realised that
- *              ll_rw_blk would be so generous as to join blocks whose
- *              results aren't going into consecutive buffers.
- * 
- *              OK; severe rehacking of mfm_rw_interrupt; now end_request's
- *              as soon as its DMA'd each request.  Odd thing is that
- *              we are sometimes getting interrupts where we are not transferring
- *              any data; why? Is that what happens when you miss? I doubt
- *              it; are we too fast? No - its just at command ends. Got 240K/s
- *              better than before, but RiscOS hits 480K/s
- *
- * 25/6/96:RMK: Fixed init code to allow the MFM podule to work.  Increased the
- *              number of errors for my Miniscribe drive (8425).
- *
- * 30/6/96:DAG: Russell suggested that a check drive 0 might turn the LEDs off
- *              - so in request_done just before it clears Busy it sends a
- *              check drive 0 - and the LEDs go off!!!!
- *
- *              Added test for mainboard controller. - Removes need for separate
- *              define.
- *
- * 13/7/96:DAG: Changed hardware sectore size to 512 in attempt to make
- *              IM drivers work.
- * 21/7/96:DAG: Took out old image file stuff (accessing it now produces an IO
- *              error.)
- *
- * 17/8/96:DAG: Ran through indent -kr -i8; evil - all my nice 2 character indents
- *              gone :-( Hand modified afterwards.
- *		Took out last remains of the older image map system.
- *
- * 22/9/96:DAG:	Changed mfm.S so it will carry on DMA'ing til; BSY is dropped
- *		Changed mfm_rw_intr so that it doesn't follow the error
- *		code until BSY is dropped. Nope - still broke. Problem
- *		may revolve around when it reads the results for the error
- *		number?
- *
- *16/11/96:DAG:	Modified for 2.0.18; request_irq changed
- *
- *17/12/96:RMK: Various cleanups, reorganisation, and the changes for new IO system.
- *		Improved probe for onboard MFM chip - it was hanging on my A5k.
- *		Added autodetect CHS code such that we don't rely on the presence
- *		of an ADFS boot block.  Added ioport resource manager calls so
- *		that we don't clash with already-running hardware (eg. RiscPC Ether
- *		card slots if someone tries this)!
- *
- * 17/1/97:RMK:	Upgraded to 2.1 kernels.
- *
- *  4/3/98:RMK:	Changed major number to 21.
- *
- * 27/6/98:RMK:	Changed asm/delay.h to linux/delay.h for mdelay().
- */
-
-/*
- * Possible enhancements:
- *  Multi-thread the code so that it is possible that while one drive
- *  is seeking, the other one can be reading data/seeking as well.
- *  This would be a performance boost with dual drive systems.
- */
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/genhd.h>
-#include <linux/major.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/blkpg.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/dma.h>
-#include <asm/hardware.h>
-#include <asm/ecard.h>
-#include <asm/hardware/ioc.h>
-
-static void (*do_mfm)(void) = NULL;
-static struct request_queue *mfm_queue;
-static DEFINE_SPINLOCK(mfm_lock);
-
-#define MAJOR_NR	MFM_ACORN_MAJOR
-#define QUEUE (mfm_queue)
-#define CURRENT elv_next_request(mfm_queue)
-
-/*
- * Configuration section
- *
- * This is the maximum number of drives that we accept
- */
-#define MFM_MAXDRIVES 2
-/*
- * Linux I/O address of onboard MFM controller or 0 to disable this
- */
-#define ONBOARD_MFM_ADDRESS ((0x002d0000 >> 2) | 0x80000000)
-/*
- * Uncomment this to enable debugging in the MFM driver...
- */
-#ifndef DEBUG
-/*#define DEBUG */
-#endif
-/*
- * End of configuration
- */
-
- 
-/*
- * This structure contains all information to do with a particular physical
- * device.
- */
-struct mfm_info {
-	unsigned char sectors;
-	unsigned char heads;
-	unsigned short cylinders;
-	unsigned short lowcurrent;
-	unsigned short precomp;
-#define NO_TRACK -1
-#define NEED_1_RECAL -2
-#define NEED_2_RECAL -3
-		 int cylinder;
-	struct {
-		char recal;
-		char report;
-		char abort;
-	} errors;
-} mfm_info[MFM_MAXDRIVES];
-
-#define MFM_DRV_INFO mfm_info[raw_cmd.dev]
-
-/* Stuff from the assembly routines */
-extern unsigned int hdc63463_baseaddress;	/* Controller base address */
-extern unsigned int hdc63463_irqpolladdress;	/* Address to read to test for int */
-extern unsigned int hdc63463_irqpollmask;	/* Mask for irq register */
-extern unsigned int hdc63463_dataptr;	/* Pointer to kernel data space to DMA */
-extern int hdc63463_dataleft;	/* Number of bytes left to transfer */
-
-
-
-
-static int lastspecifieddrive;
-static unsigned Busy;
-
-static unsigned int PartFragRead;	/* The number of sectors which have been read
-					   during a partial read split over two
-					   cylinders.  If 0 it means a partial
-					   read did not occur. */
-
-static unsigned int PartFragRead_RestartBlock;	/* Where to restart on a split access */
-static unsigned int PartFragRead_SectorsLeft;	/* Where to restart on a split access */
-
-static int Sectors256LeftInCurrent;	/* i.e. 256 byte sectors left in current */
-static int SectorsLeftInRequest;	/* i.e. blocks left in the thing mfm_request was called for */
-static int Copy_Sector;		/* The 256 byte sector we are currently at - fragments need to know 
-				   where to take over */
-static char *Copy_buffer;
-
-
-static void mfm_seek(void);
-static void mfm_rerequest(void);
-static void mfm_request(void);
-static void mfm_specify (void);
-static void issue_request(unsigned int block, unsigned int nsect,
-			  struct request *req);
-
-static unsigned int mfm_addr;		/* Controller address */
-static unsigned int mfm_IRQPollLoc;	/* Address to read for IRQ information */
-static unsigned int mfm_irqenable;	/* Podule IRQ enable location */
-static unsigned char mfm_irq;		/* Interrupt number */
-static int mfm_drives = 0;		/* drives available */
-static int mfm_status = 0;		/* interrupt status */
-static int *errors;
-
-static struct rawcmd {
-	unsigned int dev;
-	unsigned int cylinder;
-	unsigned int head;
-	unsigned int sector;
-	unsigned int cmdtype;
-	unsigned int cmdcode;
-	unsigned char cmddata[16];
-	unsigned int cmdlen;
-} raw_cmd;
-
-static unsigned char result[16];
-
-static struct cont {
-	void (*interrupt) (void);	/* interrupt handler */
-	void (*error) (void);	/* error handler */
-	void (*redo) (void);	/* redo handler */
-	void (*done) (int st);	/* done handler */
-} *cont = NULL;
-
-#if 0
-static struct tq_struct mfm_tq = {0, 0, (void (*)(void *)) NULL, 0};
-#endif
-
-int number_mfm_drives = 1;
-
-/* ------------------------------------------------------------------------------------------ */
-/*
- * From the HD63463 data sheet from Hitachi Ltd.
- */
-
-#define MFM_COMMAND (mfm_addr + 0)
-#define MFM_DATAOUT (mfm_addr + 1)
-#define MFM_STATUS  (mfm_addr + 8)
-#define MFM_DATAIN  (mfm_addr + 9)
-
-#define CMD_ABT		0xF0	/* Abort */
-#define CMD_SPC		0xE8	/* Specify */
-#define CMD_TST		0xE0	/* Test */
-#define CMD_RCLB	0xC8	/* Recalibrate */
-#define CMD_SEK		0xC0	/* Seek */
-#define CMD_WFS		0xAB	/* Write Format Skew */
-#define CMD_WFM		0xA3	/* Write Format */
-#define CMD_MTB		0x90	/* Memory to buffer */
-#define CMD_CMPD	0x88	/* Compare data */
-#define CMD_WD		0x87	/* Write data */
-#define CMD_RED		0x70	/* Read erroneous data */
-#define CMD_RIS		0x68	/* Read ID skew */
-#define CMD_FID		0x61	/* Find ID */
-#define CMD_RID		0x60	/* Read ID */
-#define CMD_BTM		0x50	/* Buffer to memory */
-#define CMD_CKD		0x48	/* Check data */
-#define CMD_RD		0x40	/* Read data */
-#define CMD_OPBW	0x38	/* Open buffer write */
-#define CMD_OPBR	0x30	/* Open buffer read */
-#define CMD_CKV		0x28	/* Check drive */
-#define CMD_CKE		0x20	/* Check ECC */
-#define CMD_POD		0x18	/* Polling disable */
-#define CMD_POL		0x10	/* Polling enable */
-#define CMD_RCAL	0x08	/* Recall */
-
-#define STAT_BSY	0x8000	/* Busy */
-#define STAT_CPR	0x4000	/* Command Parameter Rejection */
-#define STAT_CED	0x2000	/* Command end */
-#define STAT_SED	0x1000	/* Seek end */
-#define STAT_DER	0x0800	/* Drive error */
-#define STAT_ABN	0x0400	/* Abnormal end */
-#define STAT_POL	0x0200	/* Polling */
-
-/* ------------------------------------------------------------------------------------------ */
-#ifdef DEBUG
-static void console_printf(const char *fmt,...)
-{
-	static char buffer[2048];	/* Arbitary! */
-	extern void console_print(const char *);
-	unsigned long flags;
-	va_list ap;
-
-	local_irq_save(flags);
-
-	va_start(ap, fmt);
-	vsprintf(buffer, fmt, ap);
-	console_print(buffer);
-	va_end(fmt);
-
-	local_irq_restore(flags);
-};	/* console_printf */
-
-#define DBG(x...) console_printf(x)
-#else
-#define DBG(x...)
-#endif
-
-static void print_status(void)
-{
-	char *error;
-	static char *errors[] = {
-         "no error",
-	 "command aborted",
-	 "invalid command",
-	 "parameter error",
-	 "not initialised",
-	 "rejected TEST",
-	 "no useld",
-	 "write fault",
-	 "not ready",
-	 "no scp",
-	 "in seek",
-	 "invalid NCA",
-	 "invalid step rate",
-	 "seek error",
-	 "over run",
-	 "invalid PHA",
-	 "data field EEC error",
-	 "data field CRC error",
-	 "error corrected",
-	 "data field fatal error",
-	 "no data am",
-	 "not hit",
-	 "ID field CRC error",
-	 "time over",
-	 "no ID am",
-	 "not writable"
-	};
-	if (result[1] < 0x65)
-		error = errors[result[1] >> 2];
-	else
-		error = "unknown";
-	printk("(");
-	if (mfm_status & STAT_BSY) printk("BSY ");
-	if (mfm_status & STAT_CPR) printk("CPR ");
-	if (mfm_status & STAT_CED) printk("CED ");
-	if (mfm_status & STAT_SED) printk("SED ");
-	if (mfm_status & STAT_DER) printk("DER ");
-	if (mfm_status & STAT_ABN) printk("ABN ");
-	if (mfm_status & STAT_POL) printk("POL ");
-	printk(") SSB = %X (%s)\n", result[1], error);
-
-}
-
-/* ------------------------------------------------------------------------------------- */
-
-static void issue_command(int command, unsigned char *cmdb, int len)
-{
-	int status;
-#ifdef DEBUG
-	int i;
-	console_printf("issue_command: %02X: ", command);
-	for (i = 0; i < len; i++)
-		console_printf("%02X ", cmdb[i]);
-	console_printf("\n");
-#endif
-
-	do {
-		status = inw(MFM_STATUS);
-	} while (status & (STAT_BSY | STAT_POL));
-	DBG("issue_command: status after pol/bsy loop: %02X:\n ", status >> 8);
-
-	if (status & (STAT_CPR | STAT_CED | STAT_SED | STAT_DER | STAT_ABN)) {
-		outw(CMD_RCAL, MFM_COMMAND);
-		while (inw(MFM_STATUS) & STAT_BSY);
-	}
-	status = inw(MFM_STATUS);
-	DBG("issue_command: status before parameter issue: %02X:\n ", status >> 8);
-
-	while (len > 0) {
-		outw(cmdb[1] | (cmdb[0] << 8), MFM_DATAOUT);
-		len -= 2;
-		cmdb += 2;
-	}
-	status = inw(MFM_STATUS);
-	DBG("issue_command: status before command issue: %02X:\n ", status >> 8);
-
-	outw(command, MFM_COMMAND);
-	status = inw(MFM_STATUS);
-	DBG("issue_command: status immediately after command issue: %02X:\n ", status >> 8);
-}
-
-static void wait_for_completion(void)
-{
-	while ((mfm_status = inw(MFM_STATUS)) & STAT_BSY);
-}
-
-static void wait_for_command_end(void)
-{
-	int i;
-
-	while (!((mfm_status = inw(MFM_STATUS)) & STAT_CED));
-
-	for (i = 0; i < 16;) {
-		int in;
-		in = inw(MFM_DATAIN);
-		result[i++] = in >> 8;
-		result[i++] = in;
-	}
-	outw (CMD_RCAL, MFM_COMMAND);
-}
-
-/* ------------------------------------------------------------------------------------- */
-
-static void mfm_rw_intr(void)
-{
-	int old_status;		/* Holds status on entry, we read to see if the command just finished */
-#ifdef DEBUG
-	console_printf("mfm_rw_intr...dataleft=%d\n", hdc63463_dataleft);
-	print_status();
-#endif
-
-  /* Now don't handle the error until BSY drops */
-	if ((mfm_status & (STAT_DER | STAT_ABN)) && ((mfm_status&STAT_BSY)==0)) {
-		/* Something has gone wrong - let's try that again */
-		outw(CMD_RCAL, MFM_COMMAND);	/* Clear interrupt condition */
-		if (cont) {
-			DBG("mfm_rw_intr: DER/ABN err\n");
-			cont->error();
-			cont->redo();
-		};
-		return;
-	};
-
-	/* OK so what ever happened it's not an error, now I reckon we are left between
-	   a choice of command end or some data which is ready to be collected */
-	/* I think we have to transfer data while the interrupt line is on and its
-	   not any other type of interrupt */
-	if (rq_data_dir(CURRENT) == WRITE) {
-		extern void hdc63463_writedma(void);
-		if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) {
-			printk("mfm_rw_intr: Apparent DMA write request when no more to DMA\n");
-			if (cont) {
-				cont->error();
-				cont->redo();
-			};
-			return;
-		};
-		hdc63463_writedma();
-	} else {
-		extern void hdc63463_readdma(void);
-		if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) {
-			printk("mfm_rw_intr: Apparent DMA read request when no more to DMA\n");
-			if (cont) {
-				cont->error();
-				cont->redo();
-			};
-			return;
-		};
-		DBG("Going to try read dma..............status=0x%x, buffer=%p\n", mfm_status, hdc63463_dataptr);
-		hdc63463_readdma();
-	};			/* Read */
-
-	if (hdc63463_dataptr != ((unsigned int) Copy_buffer + 256)) {
-		/* If we didn't actually manage to get any data on this interrupt - but why? We got the interrupt */
-		/* Ah - well looking at the status its just when we get command end; so no problem */
-		/*console_printf("mfm: dataptr mismatch. dataptr=0x%08x Copy_buffer+256=0x%08p\n",
-		   hdc63463_dataptr,Copy_buffer+256);
-		   print_status(); */
-	} else {
-		Sectors256LeftInCurrent--;
-		Copy_buffer += 256;
-		Copy_Sector++;
-
-		/* We have come to the end of this request */
-		if (!Sectors256LeftInCurrent) {
-			DBG("mfm: end_request for CURRENT=0x%p CURRENT(sector=%d current_nr_sectors=%d nr_sectors=%d)\n",
-				       CURRENT, CURRENT->sector, CURRENT->current_nr_sectors, CURRENT->nr_sectors);
-
-			CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
-			CURRENT->sector += CURRENT->current_nr_sectors;
-			SectorsLeftInRequest -= CURRENT->current_nr_sectors;
-
-			end_request(CURRENT, 1);
-			if (SectorsLeftInRequest) {
-				hdc63463_dataptr = (unsigned int) CURRENT->buffer;
-				Copy_buffer = CURRENT->buffer;
-				Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;
-				errors = &(CURRENT->errors);
-				/* These should match the present calculations of the next logical sector
-				   on the device
-				   Copy_Sector=CURRENT->sector*2; */
-
-				if (Copy_Sector != CURRENT->sector * 2)
-#ifdef DEBUG
-					/*console_printf*/printk("mfm: Copy_Sector mismatch. Copy_Sector=%d CURRENT->sector*2=%d\n",
-					Copy_Sector, CURRENT->sector * 2);
-#else
-					printk("mfm: Copy_Sector mismatch! Eek!\n");
-#endif
-			};	/* CURRENT */
-		};	/* Sectors256LeftInCurrent */
-	};
-
-	old_status = mfm_status;
-	mfm_status = inw(MFM_STATUS);
-	if (mfm_status & (STAT_DER | STAT_ABN)) {
-		/* Something has gone wrong - let's try that again */
-		if (cont) {
-			DBG("mfm_rw_intr: DER/ABN error\n");
-			cont->error();
-			cont->redo();
-		};
-		return;
-	};
-
-	/* If this code wasn't entered due to command_end but there is
-	   now a command end we must read the command results out. If it was
-	   entered like this then mfm_interrupt_handler would have done the
-	   job. */
-	if ((!((old_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) &&
-	    ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) {
-		int len = 0;
-		while (len < 16) {
-			int in;
-			in = inw(MFM_DATAIN);
-			result[len++] = in >> 8;
-			result[len++] = in;
-		};
-	};			/* Result read */
-
-	/*console_printf ("mfm_rw_intr nearexit [%02X]\n", __raw_readb(mfm_IRQPollLoc)); */
-
-	/* If end of command move on */
-	if (mfm_status & (STAT_CED)) {
-		outw(CMD_RCAL, MFM_COMMAND);	/* Clear interrupt condition */
-		/* End of command - trigger the next command */
-		if (cont) {
-			cont->done(1);
-		}
-		DBG("mfm_rw_intr: returned from cont->done\n");
-	} else {
-		/* Its going to generate another interrupt */
-		do_mfm = mfm_rw_intr;
-	};
-}
-
-static void mfm_setup_rw(void)
-{
-	DBG("setting up for rw...\n");
-
-	do_mfm = mfm_rw_intr;
-	issue_command(raw_cmd.cmdcode, raw_cmd.cmddata, raw_cmd.cmdlen);
-}
-
-static void mfm_recal_intr(void)
-{
-#ifdef DEBUG
-	console_printf("recal intr - status = ");
-	print_status();
-#endif
-	outw(CMD_RCAL, MFM_COMMAND);	/* Clear interrupt condition */
-	if (mfm_status & (STAT_DER | STAT_ABN)) {
-		printk("recal failed\n");
-		MFM_DRV_INFO.cylinder = NEED_2_RECAL;
-		if (cont) {
-			cont->error();
-			cont->redo();
-		}
-		return;
-	}
-	/* Thats seek end - we are finished */
-	if (mfm_status & STAT_SED) {
-		issue_command(CMD_POD, NULL, 0);
-		MFM_DRV_INFO.cylinder = 0;
-		mfm_seek();
-		return;
-	}
-	/* Command end without seek end (see data sheet p.20) for parallel seek
-	   - we have to send a POL command to wait for the seek */
-	if (mfm_status & STAT_CED) {
-		do_mfm = mfm_recal_intr;
-		issue_command(CMD_POL, NULL, 0);
-		return;
-	}
-	printk("recal: unknown status\n");
-}
-
-static void mfm_seek_intr(void)
-{
-#ifdef DEBUG
-	console_printf("seek intr - status = ");
-	print_status();
-#endif
-	outw(CMD_RCAL, MFM_COMMAND);	/* Clear interrupt condition */
-	if (mfm_status & (STAT_DER | STAT_ABN)) {
-		printk("seek failed\n");
-		MFM_DRV_INFO.cylinder = NEED_2_RECAL;
-		if (cont) {
-			cont->error();
-			cont->redo();
-		}
-		return;
-	}
-	if (mfm_status & STAT_SED) {
-		issue_command(CMD_POD, NULL, 0);
-		MFM_DRV_INFO.cylinder = raw_cmd.cylinder;
-		mfm_seek();
-		return;
-	}
-	if (mfm_status & STAT_CED) {
-		do_mfm = mfm_seek_intr;
-		issue_command(CMD_POL, NULL, 0);
-		return;
-	}
-	printk("seek: unknown status\n");
-}
-
-/* IDEA2 seems to work better - its what RiscOS sets my
- * disc to - on its SECOND call to specify!
- */
-#define IDEA2
-#ifndef IDEA2
-#define SPEC_SL 0x16
-#define SPEC_SH 0xa9		/* Step pulse high=21, Record Length=001 (256 bytes) */
-#else
-#define SPEC_SL 0x00		/* OM2 - SL - step pulse low */
-#define SPEC_SH 0x21		/* Step pulse high=4, Record Length=001 (256 bytes) */
-#endif
-
-static void mfm_setupspecify (int drive, unsigned char *cmdb)
-{
-	cmdb[0]  = 0x1f;		/* OM0 - !SECT,!MOD,!DIF,PADP,ECD,CRCP,CRCI,ACOR */
-	cmdb[1]  = 0xc3;		/* OM1 - DTM,BRST,!CEDM,!SEDM,!DERM,0,AMEX,PSK */
-	cmdb[2]  = SPEC_SL;		/* OM2 - SL - step pulse low */
-	cmdb[3]  = (number_mfm_drives == 1) ? 0x02 : 0x06;	/* 1 or 2 drives */
-	cmdb[4]  = 0xfc | ((mfm_info[drive].cylinders - 1) >> 8);/* RW time over/high part of number of cylinders */
-	cmdb[5]  = mfm_info[drive].cylinders - 1;		/* low part of number of cylinders */
-	cmdb[6]  = mfm_info[drive].heads - 1;			/* Number of heads */
-	cmdb[7]  = mfm_info[drive].sectors - 1;			/* Number of sectors */
-	cmdb[8]  = SPEC_SH;
-	cmdb[9]  = 0x0a;		/* gap length 1 */
-	cmdb[10] = 0x0d;		/* gap length 2 */
-	cmdb[11] = 0x0c;		/* gap length 3 */
-	cmdb[12] = (mfm_info[drive].precomp - 1) >> 8;	/* pre comp cylinder */
-	cmdb[13] = mfm_info[drive].precomp - 1;
-	cmdb[14] = (mfm_info[drive].lowcurrent - 1) >> 8;	/* Low current cylinder */
-	cmdb[15] = mfm_info[drive].lowcurrent - 1;
-}
-
-static void mfm_specify (void)
-{
-	unsigned char cmdb[16];
-
-	DBG("specify...dev=%d lastspecified=%d\n", raw_cmd.dev, lastspecifieddrive);
-	mfm_setupspecify (raw_cmd.dev, cmdb);
-
-	issue_command (CMD_SPC, cmdb, 16);
-	/* Ensure that we will do another specify if we move to the other drive */
-	lastspecifieddrive = raw_cmd.dev;
-	wait_for_completion();
-}
-
-static void mfm_seek(void)
-{
-	unsigned char cmdb[4];
-
-	DBG("seeking...\n");
-	if (MFM_DRV_INFO.cylinder < 0) {
-		do_mfm = mfm_recal_intr;
-		DBG("mfm_seek: about to call specify\n");
-		mfm_specify ();	/* DAG added this */
-
-		cmdb[0] = raw_cmd.dev + 1;
-		cmdb[1] = 0;
-
-		issue_command(CMD_RCLB, cmdb, 2);
-		return;
-	}
-	if (MFM_DRV_INFO.cylinder != raw_cmd.cylinder) {
-		cmdb[0] = raw_cmd.dev + 1;
-		cmdb[1] = 0;	/* raw_cmd.head; DAG: My data sheet says this should be 0 */
-		cmdb[2] = raw_cmd.cylinder >> 8;
-		cmdb[3] = raw_cmd.cylinder;
-
-		do_mfm = mfm_seek_intr;
-		issue_command(CMD_SEK, cmdb, 4);
-	} else
-		mfm_setup_rw();
-}
-
-static void mfm_initialise(void)
-{
-	DBG("init...\n");
-	mfm_seek();
-}
-
-static void request_done(int uptodate)
-{
-	DBG("mfm:request_done\n");
-	if (uptodate) {
-		unsigned char block[2] = {0, 0};
-
-		/* Apparently worked - let's check bytes left to DMA */
-		if (hdc63463_dataleft != (PartFragRead_SectorsLeft * 256)) {
-			printk("mfm: request_done - dataleft=%d - should be %d - Eek!\n", hdc63463_dataleft, PartFragRead_SectorsLeft * 256);
-			end_request(CURRENT, 0);
-			Busy = 0;
-		};
-		/* Potentially this means that we've done; but we might be doing
-		   a partial access, (over two cylinders) or we may have a number
-		   of fragments in an image file.  First let's deal with partial accesss
-		 */
-		if (PartFragRead) {
-			/* Yep - a partial access */
-
-			/* and issue the remainder */
-			issue_request(PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT);
-			return;
-		}
-
-		/* ah well - perhaps there is another fragment to go */
-
-		/* Increment pointers/counts to start of next fragment */
-		if (SectorsLeftInRequest > 0) printk("mfm: SectorsLeftInRequest>0 - Eek! Shouldn't happen!\n");
-
-		/* No - its the end of the line */
-		/* end_request's should have happened at the end of sector DMAs */
-		/* Turns Drive LEDs off - may slow it down? */
-		if (!elv_next_request(QUEUE))
-			issue_command(CMD_CKV, block, 2);
-
-		Busy = 0;
-		DBG("request_done: About to mfm_request\n");
-		/* Next one please */
-		mfm_request();	/* Moved from mfm_rw_intr */
-		DBG("request_done: returned from mfm_request\n");
-	} else {
-		printk("mfm:request_done: update=0\n");
-		end_request(CURRENT, 0);
-		Busy = 0;
-	}
-}
-
-static void error_handler(void)
-{
-	printk("error detected... status = ");
-	print_status();
-	(*errors)++;
-	if (*errors > MFM_DRV_INFO.errors.abort)
-		cont->done(0);
-	if (*errors > MFM_DRV_INFO.errors.recal)
-		MFM_DRV_INFO.cylinder = NEED_2_RECAL;
-}
-
-static void rw_interrupt(void)
-{
-	printk("rw_interrupt\n");
-}
-
-static struct cont rw_cont =
-{
-	rw_interrupt,
-	error_handler,
-	mfm_rerequest,
-	request_done
-};
-
-/*
- * Actually gets round to issuing the request - note everything at this
- * point is in 256 byte sectors not Linux 512 byte blocks
- */
-static void issue_request(unsigned int block, unsigned int nsect,
-			  struct request *req)
-{
-	struct gendisk *disk = req->rq_disk;
-	struct mfm_info *p = disk->private_data;
-	int track, start_head, start_sector;
-	int sectors_to_next_cyl;
-	dev = p - mfm_info;
-
-	track = block / p->sectors;
-	start_sector = block % p->sectors;
-	start_head = track % p->heads;
-
-	/* First get the number of whole tracks which are free before the next
-	   track */
-	sectors_to_next_cyl = (p->heads - (start_head + 1)) * p->sectors;
-	/* Then add in the number of sectors left on this track */
-	sectors_to_next_cyl += (p->sectors - start_sector);
-
-	DBG("issue_request: mfm_info[dev].sectors=%d track=%d\n", p->sectors, track);
-
-	raw_cmd.dev = dev;
-	raw_cmd.sector = start_sector;
-	raw_cmd.head = start_head;
-	raw_cmd.cylinder = track / p->heads;
-	raw_cmd.cmdtype = CURRENT->cmd;
-	raw_cmd.cmdcode = rq_data_dir(CURRENT) == WRITE ? CMD_WD : CMD_RD;
-	raw_cmd.cmddata[0] = dev + 1;	/* DAG: +1 to get US */
-	raw_cmd.cmddata[1] = raw_cmd.head;
-	raw_cmd.cmddata[2] = raw_cmd.cylinder >> 8;
-	raw_cmd.cmddata[3] = raw_cmd.cylinder;
-	raw_cmd.cmddata[4] = raw_cmd.head;
-	raw_cmd.cmddata[5] = raw_cmd.sector;
-
-	/* Was == and worked - how the heck??? */
-	if (lastspecifieddrive != raw_cmd.dev)
-		mfm_specify ();
-
-	if (nsect <= sectors_to_next_cyl) {
-		raw_cmd.cmddata[6] = nsect >> 8;
-		raw_cmd.cmddata[7] = nsect;
-		PartFragRead = 0;	/* All in one */
-		PartFragRead_SectorsLeft = 0;	/* Must set this - used in DMA calcs */
-	} else {
-		raw_cmd.cmddata[6] = sectors_to_next_cyl >> 8;
-		raw_cmd.cmddata[7] = sectors_to_next_cyl;
-		PartFragRead = sectors_to_next_cyl;	/* only do this many this time */
-		PartFragRead_RestartBlock = block + sectors_to_next_cyl;	/* Where to restart from */
-		PartFragRead_SectorsLeft = nsect - sectors_to_next_cyl;
-	}
-	raw_cmd.cmdlen = 8;
-
-	/* Setup DMA pointers */
-	hdc63463_dataptr = (unsigned int) Copy_buffer;
-	hdc63463_dataleft = nsect * 256;	/* Better way? */
-
-	DBG("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n",
-	     raw_cmd.dev + 'a', rq_data_dir(CURRENT) == READ ? "read" : "writ",
-		       raw_cmd.cylinder,
-		       raw_cmd.head,
-	    raw_cmd.sector, nsect, (unsigned long) Copy_buffer, CURRENT);
-
-	cont = &rw_cont;
-	errors = &(CURRENT->errors);
-#if 0
-	mfm_tq.routine = (void (*)(void *)) mfm_initialise;
-	queue_task(&mfm_tq, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
-#else
-	mfm_initialise();
-#endif
-}				/* issue_request */
-
-/*
- * Called when an error has just happened - need to trick mfm_request
- * into thinking we weren't busy
- *
- * Turn off ints - mfm_request expects them this way
- */
-static void mfm_rerequest(void)
-{
-	DBG("mfm_rerequest\n");
-	cli();
-	Busy = 0;
-	mfm_request();
-}
-
-static struct gendisk *mfm_gendisk[2];
-
-static void mfm_request(void)
-{
-	DBG("mfm_request CURRENT=%p Busy=%d\n", CURRENT, Busy);
-
-	/* If we are still processing then return; we will get called again */
-	if (Busy) {
-		/* Again seems to be common in 1.3.45 */
-		/*DBG*/printk("mfm_request: Exiting due to busy\n");
-		return;
-	}
-	Busy = 1;
-
-	while (1) {
-		unsigned int block, nsect;
-		struct gendisk *disk;
-
-		DBG("mfm_request: loop start\n");
-		sti();
-
-		DBG("mfm_request: before !CURRENT\n");
-
-		if (!CURRENT) {
-			printk("mfm_request: Exiting due to empty queue (pre)\n");
-			do_mfm = NULL;
-			Busy = 0;
-			return;
-		}
-
-		DBG("mfm_request:                 before arg extraction\n");
-
-		disk = CURRENT->rq_disk;
-		block = CURRENT->sector;
-		nsect = CURRENT->nr_sectors;
-		if (block >= get_capacity(disk) ||
-		    block+nsect > get_capacity(disk)) {
-			printk("%s: bad access: block=%d, count=%d, nr_sects=%ld\n",
-			       disk->disk_name, block, nsect, get_capacity(disk));
-			printk("mfm: continue 1\n");
-			end_request(CURRENT, 0);
-			Busy = 0;
-			continue;
-		}
-
-		/* DAG: Linux doesn't cope with this - even though it has an array telling
-		   it the hardware block size - silly */
-		block <<= 1;	/* Now in 256 byte sectors */
-		nsect <<= 1;	/* Ditto */
-
-		SectorsLeftInRequest = nsect >> 1;
-		Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;
-		Copy_buffer = CURRENT->buffer;
-		Copy_Sector = CURRENT->sector << 1;
-
-		DBG("mfm_request: block after offset=%d\n", block);
-
-		issue_request(block, nsect, CURRENT);
-
-		break;
-	}
-	DBG("mfm_request: Dropping out bottom\n");
-}
-
-static void do_mfm_request(request_queue_t *q)
-{
-	DBG("do_mfm_request: about to mfm_request\n");
-	mfm_request();
-}
-
-static void mfm_interrupt_handler(int unused, void *dev_id)
-{
-	void (*handler) (void) = do_mfm;
-
-	do_mfm = NULL;
-
-	DBG("mfm_interrupt_handler (handler=0x%p)\n", handler);
-
-	mfm_status = inw(MFM_STATUS);
-
-	/* If CPR (Command Parameter Reject) and not busy it means that the command
-	   has some return message to give us */
-	if ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR) {
-		int len = 0;
-		while (len < 16) {
-			int in;
-			in = inw(MFM_DATAIN);
-			result[len++] = in >> 8;
-			result[len++] = in;
-		}
-	}
-	if (handler) {
-		handler();
-		return;
-	}
-	outw (CMD_RCAL, MFM_COMMAND);	/* Clear interrupt condition */
-	printk ("mfm: unexpected interrupt - status = ");
-	print_status ();
-	while (1);
-}
-
-
-
-
-
-/*
- * Tell the user about the drive if we decided it exists.
- */
-static void mfm_geometry(int drive)
-{
-	struct mfm_info *p = mfm_info + drive;
-	struct gendisk *disk = mfm_gendisk[drive];
-	disk->private_data = p;
-	if (p->cylinders)
-		printk ("%s: %dMB CHS=%d/%d/%d LCC=%d RECOMP=%d\n",
-			disk->disk_name,
-			p->cylinders * p->heads * p->sectors / 4096,
-			p->cylinders, p->heads, p->sectors,
-			p->lowcurrent, p->precomp);
-	set_capacity(disk, p->cylinders * p->heads * p->sectors / 2);
-}
-
-#ifdef CONFIG_BLK_DEV_MFM_AUTODETECT
-/*
- * Attempt to detect a drive and find its geometry.  The drive has already been
- * specified...
- *
- * We first recalibrate the disk, then try to probe sectors, heads and then
- * cylinders.  NOTE! the cylinder probe may break drives.  The xd disk driver
- * does something along these lines, so I assume that most drives are up to
- * this mistreatment...
- */
-static int mfm_detectdrive (int drive)
-{
-	unsigned int mingeo[3], maxgeo[3];
-	unsigned int attribute, need_recal = 1;
-	unsigned char cmdb[8];
-
-	memset (mingeo, 0, sizeof (mingeo));
-	maxgeo[0] = mfm_info[drive].sectors;
-	maxgeo[1] = mfm_info[drive].heads;
-	maxgeo[2] = mfm_info[drive].cylinders;
-
-	cmdb[0] = drive + 1;
-	cmdb[6] = 0;
-	cmdb[7] = 1;
-	for (attribute = 0; attribute < 3; attribute++) {
-		while (mingeo[attribute] != maxgeo[attribute]) {
-			unsigned int variable;
-
-			variable = (maxgeo[attribute] + mingeo[attribute]) >> 1;
-			cmdb[1] = cmdb[2] = cmdb[3] = cmdb[4] = cmdb[5] = 0;
-
-			if (need_recal) {
-				int tries = 5;
-
-				do {
-					issue_command (CMD_RCLB, cmdb, 2);
-					wait_for_completion ();
-					wait_for_command_end ();
-					if  (result[1] == 0x20)
-						break;
-				} while (result[1] && --tries);
-				if (result[1]) {
-					outw (CMD_RCAL, MFM_COMMAND);
-					return 0;
-				}
-				need_recal = 0;
-			}
-
-			switch (attribute) {
-			case 0:
-				cmdb[5] = variable;
-				issue_command (CMD_CMPD, cmdb, 8);
-				break;
-			case 1:
-				cmdb[1] = variable;
-				cmdb[4] = variable;
-				issue_command (CMD_CMPD, cmdb, 8);
-				break;
-			case 2:
-				cmdb[2] = variable >> 8;
-				cmdb[3] = variable;
-				issue_command (CMD_SEK, cmdb, 4);
-				break;
-			}
-			wait_for_completion ();
-			wait_for_command_end ();
-
-			switch (result[1]) {
-			case 0x00:
-			case 0x50:
-				mingeo[attribute] = variable + 1;
-				break;
-
-			case 0x20:
-				outw (CMD_RCAL, MFM_COMMAND);
-				return 0;
-
-			case 0x24:
-				need_recal = 1;
-			default:
-				maxgeo[attribute] = variable;
-				break;
-			}
-		}
-	}
-	mfm_info[drive].cylinders  = mingeo[2];
-	mfm_info[drive].lowcurrent = mingeo[2];
-	mfm_info[drive].precomp    = mingeo[2] / 2;
-	mfm_info[drive].heads 	   = mingeo[1];
-	mfm_info[drive].sectors	   = mingeo[0];
-	outw (CMD_RCAL, MFM_COMMAND);
-	return 1;
-}
-#endif
-
-/*
- * Initialise all drive information for this controller.
- */
-static int mfm_initdrives(void)
-{
-	int drive;
-
-	if (number_mfm_drives > MFM_MAXDRIVES) {
-		number_mfm_drives = MFM_MAXDRIVES;
-		printk("No. of ADFS MFM drives is greater than MFM_MAXDRIVES - you can't have that many!\n");
-	}
-
-	for (drive = 0; drive < number_mfm_drives; drive++) {
-		mfm_info[drive].lowcurrent = 1;
-		mfm_info[drive].precomp    = 1;
-		mfm_info[drive].cylinder   = -1;
-		mfm_info[drive].errors.recal  = 0;
-		mfm_info[drive].errors.report = 0;
-		mfm_info[drive].errors.abort  = 4;
-
-#ifdef CONFIG_BLK_DEV_MFM_AUTODETECT
-		mfm_info[drive].cylinders  = 1024;
-		mfm_info[drive].heads	   = 8;
-		mfm_info[drive].sectors	   = 64;
-		{
-			unsigned char cmdb[16];
-
-			mfm_setupspecify (drive, cmdb);
-			cmdb[1] &= ~0x81;
-			issue_command (CMD_SPC, cmdb, 16);
-			wait_for_completion ();
-			if (!mfm_detectdrive (drive)) {
-				mfm_info[drive].cylinders = 0;
-				mfm_info[drive].heads     = 0;
-				mfm_info[drive].sectors   = 0;
-			}
-			cmdb[0] = cmdb[1] = 0;
-			issue_command (CMD_CKV, cmdb, 2);
-		}
-#else
-		mfm_info[drive].cylinders  = 1;	/* its going to have to figure it out from the partition info */
-		mfm_info[drive].heads      = 4;
-		mfm_info[drive].sectors    = 32;
-#endif
-	}
-	return number_mfm_drives;
-}
-
-
-
-/*
- * The 'front' end of the mfm driver follows...
- */
-
-static int mfm_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
-	struct mfm_info *p = bdev->bd_disk->private_data;
-
-	geo->heads = p->heads;
-	geo->sectors = p->sectors;
-	geo->cylinders = p->cylinders;
-	return 0;
-}
-
-/*
- * This is to handle various kernel command line parameters
- * specific to this driver.
- */
-void mfm_setup(char *str, int *ints)
-{
-	return;
-}
-
-/*
- * Set the CHS from the ADFS boot block if it is present.  This is not ideal
- * since if there are any non-ADFS partitions on the disk, this won't work!
- * Hence, I want to get rid of this...
- */
-void xd_set_geometry(struct block_device *bdev, unsigned char secsptrack,
-			unsigned char heads, unsigned int secsize)
-{
-	struct mfm_info *p = bdev->bd_disk->private_data;
-	int drive = p - mfm_info;
-	unsigned long disksize = bdev->bd_inode->i_size;
-
-	if (p->cylinders == 1) {
-		p->sectors = secsptrack;
-		p->heads = heads;
-		p->cylinders = discsize / (secsptrack * heads * secsize);
-
-		if ((heads < 1) || (p->cylinders > 1024)) {
-			printk("%s: Insane disc shape! Setting to 512/4/32\n",
-				bdev->bd_disk->disk_name);
-
-			/* These values are fairly arbitary, but are there so that if your
-			 * lucky you can pick apart your disc to find out what is going on -
-			 * I reckon these figures won't hurt MOST drives
-			 */
-			p->sectors = 32;
-			p->heads = 4;
-			p->cylinders = 512;
-		}
-		if (raw_cmd.dev == drive)
-			mfm_specify ();
-		mfm_geometry (drive);
-	}
-}
-
-static struct block_device_operations mfm_fops =
-{
-	.owner		= THIS_MODULE,
-	.getgeo		= mfm_getgeo,
-};
-
-/*
- * See if there is a controller at the address presently at mfm_addr
- *
- * We check to see if the controller is busy - if it is, we abort it first,
- * and check that the chip is no longer busy after at least 180 clock cycles.
- * We then issue a command and check that the BSY or CPR bits are set.
- */
-static int mfm_probecontroller (unsigned int mfm_addr)
-{
-	if (inw (MFM_STATUS) & STAT_BSY) {
-		outw (CMD_ABT, MFM_COMMAND);
-		udelay (50);
-		if (inw (MFM_STATUS) & STAT_BSY)
-			return 0;
-	}
-
-	if (inw (MFM_STATUS) & STAT_CED)
-		outw (CMD_RCAL, MFM_COMMAND);
-
-	outw (CMD_SEK, MFM_COMMAND);
-
-	if (inw (MFM_STATUS) & (STAT_BSY | STAT_CPR)) {
-		unsigned int count = 2000;
-		while (inw (MFM_STATUS) & STAT_BSY) {
-			udelay (500);
-			if (!--count)
-				return 0;
-		}
-
-		outw (CMD_RCAL, MFM_COMMAND);
-	}
-	return 1;
-}
-
-static int mfm_do_init(unsigned char irqmask)
-{
-	int i, ret;
-
-	printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq);
-
-	ret = -EBUSY;
-	if (!request_region (mfm_addr, 10, "mfm"))
-		goto out1;
-
-	ret = register_blkdev(MAJOR_NR, "mfm");
-	if (ret)
-		goto out2;
-
-	/* Stuff for the assembler routines to get to */
-	hdc63463_baseaddress	= ioaddr(mfm_addr);
-	hdc63463_irqpolladdress	= mfm_IRQPollLoc;
-	hdc63463_irqpollmask	= irqmask;
-
-	mfm_queue = blk_init_queue(do_mfm_request, &mfm_lock);
-	if (!mfm_queue)
-		goto out2a;
-
-	Busy = 0;
-	lastspecifieddrive = -1;
-
-	mfm_drives = mfm_initdrives();
-	if (!mfm_drives) {
-		ret = -ENODEV;
-		goto out3;
-	}
-	
-	for (i = 0; i < mfm_drives; i++) {
-		struct gendisk *disk = alloc_disk(64);
-		if (!disk)
-			goto Enomem;
-		disk->major = MAJOR_NR;
-		disk->first_minor = i << 6;
-		disk->fops = &mfm_fops;
-		sprintf(disk->disk_name, "mfm%c", 'a'+i);
-		mfm_gendisk[i] = disk;
-	}
-
-	printk("mfm: detected %d hard drive%s\n", mfm_drives,
-				mfm_drives == 1 ? "" : "s");
-	ret = request_irq(mfm_irq, mfm_interrupt_handler, IRQF_DISABLED, "MFM harddisk", NULL);
-	if (ret) {
-		printk("mfm: unable to get IRQ%d\n", mfm_irq);
-		goto out4;
-	}
-
-	if (mfm_irqenable)
-		outw(0x80, mfm_irqenable);	/* Required to enable IRQs from MFM podule */
-
-	for (i = 0; i < mfm_drives; i++) {
-		mfm_geometry(i);
-		mfm_gendisk[i]->queue = mfm_queue;
-		add_disk(mfm_gendisk[i]);
-	}
-	return 0;
-
-out4:
-	for (i = 0; i < mfm_drives; i++)
-		put_disk(mfm_gendisk[i]);
-out3:
-	blk_cleanup_queue(mfm_queue);
-out2a:
-	unregister_blkdev(MAJOR_NR, "mfm");
-out2:
-	release_region(mfm_addr, 10);
-out1:
-	return ret;
-Enomem:
-	while (i--)
-		put_disk(mfm_gendisk[i]);
-	goto out3;
-}
-
-static void mfm_do_exit(void)
-{
-	int i;
-
-	free_irq(mfm_irq, NULL);
-	for (i = 0; i < mfm_drives; i++) {
-		del_gendisk(mfm_gendisk[i]);
-		put_disk(mfm_gendisk[i]);
-	}
-	blk_cleanup_queue(mfm_queue);
-	unregister_blkdev(MAJOR_NR, "mfm");
-	if (mfm_addr)
-		release_region(mfm_addr, 10);
-}
-
-static int __devinit mfm_probe(struct expansion_card *ec, struct ecard_id *id)
-{
-	if (mfm_addr)
-		return -EBUSY;
-
-	mfm_addr	= ecard_address(ec, ECARD_IOC, ECARD_MEDIUM) + 0x800;
-	mfm_IRQPollLoc	= ioaddr(mfm_addr + 0x400);
-	mfm_irqenable	= mfm_IRQPollLoc;
-	mfm_irq		= ec->irq;
-
-	return mfm_do_init(0x08);
-}
-
-static void __devexit mfm_remove(struct expansion_card *ec)
-{
-	outw (0, mfm_irqenable);	/* Required to enable IRQs from MFM podule */
-	mfm_do_exit();
-}
-
-static const struct ecard_id mfm_cids[] = {
-	{ MANU_ACORN, PROD_ACORN_MFM },
-	{ 0xffff, 0xffff },
-};
-
-static struct ecard_driver mfm_driver = {
-	.probe		= mfm_probe,
-	.remove		= __devexit(mfm_remove),
-	.id_table	= mfm_cids,
-	.drv = {
-		.name	= "mfm",
-	},
-};
-
-/*
- * Look for a MFM controller - first check the motherboard, then the podules
- * The podules have an extra interrupt enable that needs to be played with
- *
- * The HDC is accessed at MEDIUM IOC speeds.
- */
-static int __init mfm_init (void)
-{
-	unsigned char irqmask;
-
-	if (mfm_probecontroller(ONBOARD_MFM_ADDRESS)) {
-		mfm_addr	= ONBOARD_MFM_ADDRESS;
-		mfm_IRQPollLoc	= IOC_IRQSTATB;
-		mfm_irqenable	= 0;
-		mfm_irq		= IRQ_HARDDISK;
-		return mfm_do_init(0x08);	/* IL3 pin */
-	} else {
-		return ecard_register_driver(&mfm_driver);
-	}
-}
-
-static void __exit mfm_exit(void)
-{
-	if (mfm_addr == ONBOARD_MFM_ADDRESS)
-		mfm_do_exit();
-	else
-		ecard_unregister_driver(&mfm_driver);
-}
-
-module_init(mfm_init)
-module_exit(mfm_exit)
-MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 139f41f..4875f01 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -2,16 +2,12 @@
 # ACPI Configuration
 #
 
-menu "ACPI (Advanced Configuration and Power Interface) Support"
+menuconfig ACPI
+	bool "ACPI Support (Advanced Configuration and Power Interface) Support"
 	depends on !X86_NUMAQ
 	depends on !X86_VISWS
 	depends on !IA64_HP_SIM
 	depends on IA64 || X86
-	depends on PM
-
-config ACPI
-	bool "ACPI Support"
-	depends on IA64 || X86
 	depends on PCI
 	depends on PM
 	select PNP
@@ -47,52 +43,48 @@
 if ACPI
 
 config ACPI_SLEEP
-	bool "Sleep States"
-	depends on X86 && (!SMP || SUSPEND_SMP)
-	depends on PM
-	default y
-	---help---
-	  This option adds support for ACPI suspend states. 
-
-	  With this option, you will be able to put the system "to sleep". 
-	  Sleep states are low power states for the system and devices. All
-	  of the system operating state is saved to either memory or disk
-	  (depending on the state), to allow the system to resume operation
-	  quickly at your request.
-
-	  Although this option sounds really nifty, barely any of the device
-	  drivers have been converted to the new driver model and hence few
-	  have proper power management support. 
-
-	  This option is not recommended for anyone except those doing driver
-	  power management development.
-
-config ACPI_SLEEP_PROC_FS
 	bool
-	depends on ACPI_SLEEP && PROC_FS
+	depends on PM_SLEEP
 	default y
 
-config ACPI_SLEEP_PROC_SLEEP
-	bool "/proc/acpi/sleep (deprecated)"
-	depends on ACPI_SLEEP_PROC_FS
-	default n
-	---help---
-	  Create /proc/acpi/sleep
-	  Deprecated by /sys/power/state
-
 config ACPI_PROCFS
-	bool "Procfs interface (deprecated)"
-	depends on ACPI
+	bool "Deprecated /proc/acpi files"
+	depends on PROC_FS
+	---help---
+	  For backwards compatibility, this option allows
+	  depricated /proc/acpi/ files to exist, even when
+	  they have been replaced by functions in /sys.
+	  The deprecated files (and their replacements) include:
+
+	  /proc/acpi/sleep (/sys/power/state)
+	  /proc/acpi/info (/sys/modules/acpi/parameters/acpica_version)
+	  /proc/acpi/dsdt (/sys/firmware/acpi/tables/DSDT)
+	  /proc/acpi/fadt (/sys/firmware/acpi/tables/FACP)
+	  /proc/acpi/debug_layer (/sys/module/acpi/parameters/debug_layer)
+	  /proc/acpi/debug_level (/sys/module/acpi/parameters/debug_level)
+
+	  This option has no effect on /proc/acpi/ files
+	  and functions which do not yet exist in /sys.
+
+	  Say N to delete /proc/acpi/ files that have moved to /sys/
+
+config ACPI_PROC_EVENT
+	bool "Deprecated /proc/acpi/event support"
+	depends on PROC_FS
 	default y
 	---help---
-	  The Procfs interface for ACPI is made optional for backward compatibility.
-	  As the same functions are duplicated in the sysfs interface
-	  and this proc interface will be removed some time later,
-	  it's marked as deprecated.
-	  ( /proc/acpi/debug_layer && debug_level are deprecated by
-	    /sys/module/acpi/parameters/debug_layer && debug_level.
-	    /proc/acpi/info is deprecated by
-	    /sys/module/acpi/parameters/acpica_version )
+	  A user-space daemon, acpi, typically read /proc/acpi/event
+	  and handled all ACPI sub-system generated events.
+
+	  These events are now delivered to user-space via
+	  either the input layer, or as netlink events.
+
+	  This build option enables the old code for legacy
+	  user-space implementation.  After some time, this will
+	  be moved under CONFIG_ACPI_PROCFS, and then deleted.
+
+	  Say Y here to retain the old behaviour.  Say N if your
+	  user-space is newer than kernel 2.6.23 (September 2007).
 
 config ACPI_AC
 	tristate "AC Adapter"
@@ -124,7 +116,7 @@
 
 config ACPI_VIDEO
 	tristate "Video"
-	depends on X86 && BACKLIGHT_CLASS_DEVICE
+	depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
 	help
 	  This driver implement the ACPI Extensions For Display Adapters
 	  for integrated graphics devices on motherboard, as specified in
@@ -280,6 +272,14 @@
 	  of verbosity. Saying Y enables these statements. This will increase
 	  your kernel size by around 50K.
 
+config ACPI_DEBUG_FUNC_TRACE
+	bool "Additionally enable ACPI function tracing"
+	default n
+	depends on ACPI_DEBUG
+	help
+	  ACPI Debug Statements slow down ACPI processing. Function trace
+	  is about half of the penalty and is rarely useful.
+
 config ACPI_EC
 	bool
 	default y
@@ -330,7 +330,6 @@
 
 config ACPI_HOTPLUG_MEMORY
 	tristate "Memory Hotplug"
-	depends on ACPI
 	depends on MEMORY_HOTPLUG
 	default n
 	help
@@ -359,5 +358,3 @@
 	  to today's ACPI "Control Method" battery.
 
 endif	# ACPI
-
-endmenu
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 37c7dc4..26d7070 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -34,7 +34,6 @@
 
 #define ACPI_AC_COMPONENT		0x00020000
 #define ACPI_AC_CLASS			"ac_adapter"
-#define ACPI_AC_HID 			"ACPI0003"
 #define ACPI_AC_DEVICE_NAME		"AC Adapter"
 #define ACPI_AC_FILE_STATE		"state"
 #define ACPI_AC_NOTIFY_STATUS		0x80
@@ -56,10 +55,16 @@
 static int acpi_ac_remove(struct acpi_device *device, int type);
 static int acpi_ac_open_fs(struct inode *inode, struct file *file);
 
+const static struct acpi_device_id ac_device_ids[] = {
+	{"ACPI0003", 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, ac_device_ids);
+
 static struct acpi_driver acpi_ac_driver = {
 	.name = "ac",
 	.class = ACPI_AC_CLASS,
-	.ids = ACPI_AC_HID,
+	.ids = ac_device_ids,
 	.ops = {
 		.add = acpi_ac_add,
 		.remove = acpi_ac_remove,
@@ -199,7 +204,10 @@
 	case ACPI_NOTIFY_BUS_CHECK:
 	case ACPI_NOTIFY_DEVICE_CHECK:
 		acpi_ac_get_state(ac);
-		acpi_bus_generate_event(device, event, (u32) ac->state);
+		acpi_bus_generate_proc_event(device, event, (u32) ac->state);
+		acpi_bus_generate_netlink_event(device->pnp.device_class,
+						  device->dev.bus_id, event,
+						  (u32) ac->state);
 		break;
 	default:
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index e65628a..5f1127a 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -53,10 +53,16 @@
 static int acpi_memory_device_remove(struct acpi_device *device, int type);
 static int acpi_memory_device_start(struct acpi_device *device);
 
+static const struct acpi_device_id memory_device_ids[] = {
+	{ACPI_MEMORY_DEVICE_HID, 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, memory_device_ids);
+
 static struct acpi_driver acpi_memory_device_driver = {
 	.name = "acpi_memhotplug",
 	.class = ACPI_MEMORY_DEVICE_CLASS,
-	.ids = ACPI_MEMORY_DEVICE_HID,
+	.ids = memory_device_ids,
 	.ops = {
 		.add = acpi_memory_device_add,
 		.remove = acpi_memory_device_remove,
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index 3cd79ca..d915fec 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -56,7 +56,6 @@
 #define ACPI_HOTK_NAME          "Asus Laptop ACPI Extras Driver"
 #define ACPI_HOTK_CLASS         "hotkey"
 #define ACPI_HOTK_DEVICE_NAME   "Hotkey"
-#define ACPI_HOTK_HID           "ATK0100"
 
 /*
  * Some events we use, same for all Asus
@@ -426,14 +425,20 @@
 static struct asus_hotk *hotk;
 
 /*
- * The hotkey driver declaration
+ * The hotkey driver and autoloading declaration
  */
 static int asus_hotk_add(struct acpi_device *device);
 static int asus_hotk_remove(struct acpi_device *device, int type);
+static const struct acpi_device_id asus_device_ids[] = {
+	{"ATK0100", 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, asus_device_ids);
+
 static struct acpi_driver asus_hotk_driver = {
 	.name = "asus_acpi",
 	.class = ACPI_HOTK_CLASS,
-	.ids = ACPI_HOTK_HID,
+	.ids = asus_device_ids,
 	.ops = {
 		.add = asus_hotk_add,
 		.remove = asus_hotk_remove,
@@ -1064,7 +1069,7 @@
 		hotk->brightness = (event & ~((u32) BR_DOWN));
 	}
 
-	acpi_bus_generate_event(hotk->device, event,
+	acpi_bus_generate_proc_event(hotk->device, event,
 				hotk->event_count[event % 128]++);
 
 	return;
@@ -1187,6 +1192,7 @@
 			break;
 		default:
 			kfree(model);
+			model = NULL;
 			break;
 		}
 	}
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index e64c76c..9b2c0f7 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -41,23 +41,31 @@
 
 #define ACPI_BATTERY_COMPONENT		0x00040000
 #define ACPI_BATTERY_CLASS		"battery"
-#define ACPI_BATTERY_HID		"PNP0C0A"
 #define ACPI_BATTERY_DEVICE_NAME	"Battery"
-#define ACPI_BATTERY_FILE_INFO		"info"
-#define ACPI_BATTERY_FILE_STATUS	"state"
-#define ACPI_BATTERY_FILE_ALARM		"alarm"
 #define ACPI_BATTERY_NOTIFY_STATUS	0x80
 #define ACPI_BATTERY_NOTIFY_INFO	0x81
 #define ACPI_BATTERY_UNITS_WATTS	"mW"
 #define ACPI_BATTERY_UNITS_AMPS		"mA"
 
 #define _COMPONENT		ACPI_BATTERY_COMPONENT
+
+#define ACPI_BATTERY_UPDATE_TIME	0
+
+#define ACPI_BATTERY_NONE_UPDATE	0
+#define ACPI_BATTERY_EASY_UPDATE	1
+#define ACPI_BATTERY_INIT_UPDATE	2
+
 ACPI_MODULE_NAME("battery");
 
 MODULE_AUTHOR("Paul Diefenbaugh");
 MODULE_DESCRIPTION("ACPI Battery Driver");
 MODULE_LICENSE("GPL");
 
+static unsigned int update_time = ACPI_BATTERY_UPDATE_TIME;
+
+/* 0 - every time, > 0 - by update_time */
+module_param(update_time, uint, 0644);
+
 extern struct proc_dir_entry *acpi_lock_battery_dir(void);
 extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
 
@@ -65,10 +73,16 @@
 static int acpi_battery_remove(struct acpi_device *device, int type);
 static int acpi_battery_resume(struct acpi_device *device);
 
+static const struct acpi_device_id battery_device_ids[] = {
+	{"PNP0C0A", 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, battery_device_ids);
+
 static struct acpi_driver acpi_battery_driver = {
 	.name = "battery",
 	.class = ACPI_BATTERY_CLASS,
-	.ids = ACPI_BATTERY_HID,
+	.ids = battery_device_ids,
 	.ops = {
 		.add = acpi_battery_add,
 		.resume = acpi_battery_resume,
@@ -76,7 +90,7 @@
 		},
 };
 
-struct acpi_battery_status {
+struct acpi_battery_state {
 	acpi_integer state;
 	acpi_integer present_rate;
 	acpi_integer remaining_capacity;
@@ -99,33 +113,111 @@
 	acpi_string oem_info;
 };
 
-struct acpi_battery_flags {
-	u8 present:1;		/* Bay occupied? */
-	u8 power_unit:1;	/* 0=watts, 1=apms */
-	u8 alarm:1;		/* _BTP present? */
-	u8 reserved:5;
+enum acpi_battery_files{
+	ACPI_BATTERY_INFO = 0,
+	ACPI_BATTERY_STATE,
+	ACPI_BATTERY_ALARM,
+	ACPI_BATTERY_NUMFILES,
 };
 
-struct acpi_battery_trips {
-	unsigned long warning;
-	unsigned long low;
+struct acpi_battery_flags {
+	u8 battery_present_prev;
+	u8 alarm_present;
+	u8 init_update;
+	u8 update[ACPI_BATTERY_NUMFILES];
+	u8 power_unit;
 };
 
 struct acpi_battery {
-	struct acpi_device * device;
+	struct mutex mutex;
+	struct acpi_device *device;
 	struct acpi_battery_flags flags;
-	struct acpi_battery_trips trips;
+	struct acpi_buffer bif_data;
+	struct acpi_buffer bst_data;
 	unsigned long alarm;
-	struct acpi_battery_info *info;
+	unsigned long update_time[ACPI_BATTERY_NUMFILES];
 };
 
+inline int acpi_battery_present(struct acpi_battery *battery)
+{
+	return battery->device->status.battery_present;
+}
+inline char *acpi_battery_power_units(struct acpi_battery *battery)
+{
+	if (battery->flags.power_unit)
+		return ACPI_BATTERY_UNITS_AMPS;
+	else
+		return ACPI_BATTERY_UNITS_WATTS;
+}
+
+inline acpi_handle acpi_battery_handle(struct acpi_battery *battery)
+{
+	return battery->device->handle;
+}
+
 /* --------------------------------------------------------------------------
                                Battery Management
    -------------------------------------------------------------------------- */
 
-static int
-acpi_battery_get_info(struct acpi_battery *battery,
-		      struct acpi_battery_info **bif)
+static void acpi_battery_check_result(struct acpi_battery *battery, int result)
+{
+	if (!battery)
+		return;
+
+	if (result) {
+		battery->flags.init_update = 1;
+	}
+}
+
+static int acpi_battery_extract_package(struct acpi_battery *battery,
+					union acpi_object *package,
+					struct acpi_buffer *format,
+					struct acpi_buffer *data,
+					char *package_name)
+{
+	acpi_status status = AE_OK;
+	struct acpi_buffer data_null = { 0, NULL };
+
+	status = acpi_extract_package(package, format, &data_null);
+	if (status != AE_BUFFER_OVERFLOW) {
+		ACPI_EXCEPTION((AE_INFO, status, "Extracting size %s",
+				package_name));
+		return -ENODEV;
+	}
+
+	if (data_null.length != data->length) {
+		kfree(data->pointer);
+		data->pointer = kzalloc(data_null.length, GFP_KERNEL);
+		if (!data->pointer) {
+			ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "kzalloc()"));
+			return -ENOMEM;
+		}
+		data->length = data_null.length;
+	}
+
+	status = acpi_extract_package(package, format, data);
+	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "Extracting %s",
+				package_name));
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int acpi_battery_get_status(struct acpi_battery *battery)
+{
+	int result = 0;
+
+	result = acpi_bus_get_status(battery->device);
+	if (result) {
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA"));
+		return -ENODEV;
+	}
+	return result;
+}
+
+static int acpi_battery_get_info(struct acpi_battery *battery)
 {
 	int result = 0;
 	acpi_status status = 0;
@@ -133,16 +225,20 @@
 	struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF),
 		ACPI_BATTERY_FORMAT_BIF
 	};
-	struct acpi_buffer data = { 0, NULL };
 	union acpi_object *package = NULL;
+	struct acpi_buffer *data = NULL;
+	struct acpi_battery_info *bif = NULL;
 
+	battery->update_time[ACPI_BATTERY_INFO] = get_seconds();
 
-	if (!battery || !bif)
-		return -EINVAL;
+	if (!acpi_battery_present(battery))
+		return 0;
 
-	/* Evalute _BIF */
+	/* Evaluate _BIF */
 
-	status = acpi_evaluate_object(battery->device->handle, "_BIF", NULL, &buffer);
+	status =
+	    acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL,
+				 &buffer);
 	if (ACPI_FAILURE(status)) {
 		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF"));
 		return -ENODEV;
@@ -150,41 +246,29 @@
 
 	package = buffer.pointer;
 
+	data = &battery->bif_data;
+
 	/* Extract Package Data */
 
-	status = acpi_extract_package(package, &format, &data);
-	if (status != AE_BUFFER_OVERFLOW) {
-		ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
-		result = -ENODEV;
+	result =
+	    acpi_battery_extract_package(battery, package, &format, data,
+					 "_BIF");
+	if (result)
 		goto end;
-	}
-
-	data.pointer = kzalloc(data.length, GFP_KERNEL);
-	if (!data.pointer) {
-		result = -ENOMEM;
-		goto end;
-	}
-
-	status = acpi_extract_package(package, &format, &data);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
-		kfree(data.pointer);
-		result = -ENODEV;
-		goto end;
-	}
 
       end:
+
 	kfree(buffer.pointer);
 
-	if (!result)
-		(*bif) = data.pointer;
+	if (!result) {
+		bif = data->pointer;
+		battery->flags.power_unit = bif->power_unit;
+	}
 
 	return result;
 }
 
-static int
-acpi_battery_get_status(struct acpi_battery *battery,
-			struct acpi_battery_status **bst)
+static int acpi_battery_get_state(struct acpi_battery *battery)
 {
 	int result = 0;
 	acpi_status status = 0;
@@ -192,16 +276,19 @@
 	struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST),
 		ACPI_BATTERY_FORMAT_BST
 	};
-	struct acpi_buffer data = { 0, NULL };
 	union acpi_object *package = NULL;
+	struct acpi_buffer *data = NULL;
 
+	battery->update_time[ACPI_BATTERY_STATE] = get_seconds();
 
-	if (!battery || !bst)
-		return -EINVAL;
+	if (!acpi_battery_present(battery))
+		return 0;
 
-	/* Evalute _BST */
+	/* Evaluate _BST */
 
-	status = acpi_evaluate_object(battery->device->handle, "_BST", NULL, &buffer);
+	status =
+	    acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL,
+				 &buffer);
 	if (ACPI_FAILURE(status)) {
 		ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
 		return -ENODEV;
@@ -209,55 +296,49 @@
 
 	package = buffer.pointer;
 
+	data = &battery->bst_data;
+
 	/* Extract Package Data */
 
-	status = acpi_extract_package(package, &format, &data);
-	if (status != AE_BUFFER_OVERFLOW) {
-		ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
-		result = -ENODEV;
+	result =
+	    acpi_battery_extract_package(battery, package, &format, data,
+					 "_BST");
+	if (result)
 		goto end;
-	}
-
-	data.pointer = kzalloc(data.length, GFP_KERNEL);
-	if (!data.pointer) {
-		result = -ENOMEM;
-		goto end;
-	}
-
-	status = acpi_extract_package(package, &format, &data);
-	if (ACPI_FAILURE(status)) {
-		ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
-		kfree(data.pointer);
-		result = -ENODEV;
-		goto end;
-	}
 
       end:
 	kfree(buffer.pointer);
 
-	if (!result)
-		(*bst) = data.pointer;
-
 	return result;
 }
 
-static int
-acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm)
+static int acpi_battery_get_alarm(struct acpi_battery *battery)
+{
+	battery->update_time[ACPI_BATTERY_ALARM] = get_seconds();
+
+	return 0;
+}
+
+static int acpi_battery_set_alarm(struct acpi_battery *battery,
+				  unsigned long alarm)
 {
 	acpi_status status = 0;
 	union acpi_object arg0 = { ACPI_TYPE_INTEGER };
 	struct acpi_object_list arg_list = { 1, &arg0 };
 
+	battery->update_time[ACPI_BATTERY_ALARM] = get_seconds();
 
-	if (!battery)
-		return -EINVAL;
+	if (!acpi_battery_present(battery))
+		return -ENODEV;
 
-	if (!battery->flags.alarm)
+	if (!battery->flags.alarm_present)
 		return -ENODEV;
 
 	arg0.integer.value = alarm;
 
-	status = acpi_evaluate_object(battery->device->handle, "_BTP", &arg_list, NULL);
+	status =
+	    acpi_evaluate_object(acpi_battery_handle(battery), "_BTP",
+				 &arg_list, NULL);
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
@@ -268,65 +349,114 @@
 	return 0;
 }
 
-static int acpi_battery_check(struct acpi_battery *battery)
+static int acpi_battery_init_alarm(struct acpi_battery *battery)
 {
 	int result = 0;
 	acpi_status status = AE_OK;
 	acpi_handle handle = NULL;
-	struct acpi_device *device = NULL;
-	struct acpi_battery_info *bif = NULL;
+	struct acpi_battery_info *bif = battery->bif_data.pointer;
+	unsigned long alarm = battery->alarm;
 
+	/* See if alarms are supported, and if so, set default */
 
-	if (!battery)
-		return -EINVAL;
-
-	device = battery->device;
-
-	result = acpi_bus_get_status(device);
-	if (result)
-		return result;
-
-	/* Insertion? */
-
-	if (!battery->flags.present && device->status.battery_present) {
-
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery inserted\n"));
-
-		/* Evalute _BIF to get certain static information */
-
-		result = acpi_battery_get_info(battery, &bif);
-		if (result)
-			return result;
-
-		battery->flags.power_unit = bif->power_unit;
-		battery->trips.warning = bif->design_capacity_warning;
-		battery->trips.low = bif->design_capacity_low;
-		kfree(bif);
-
-		/* See if alarms are supported, and if so, set default */
-
-		status = acpi_get_handle(battery->device->handle, "_BTP", &handle);
-		if (ACPI_SUCCESS(status)) {
-			battery->flags.alarm = 1;
-			acpi_battery_set_alarm(battery, battery->trips.warning);
+	status = acpi_get_handle(acpi_battery_handle(battery), "_BTP", &handle);
+	if (ACPI_SUCCESS(status)) {
+		battery->flags.alarm_present = 1;
+		if (!alarm && bif) {
+			alarm = bif->design_capacity_warning;
 		}
+		result = acpi_battery_set_alarm(battery, alarm);
+		if (result)
+			goto end;
+	} else {
+		battery->flags.alarm_present = 0;
 	}
 
-	/* Removal? */
-
-	else if (battery->flags.present && !device->status.battery_present) {
-		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery removed\n"));
-	}
-
-	battery->flags.present = device->status.battery_present;
+      end:
 
 	return result;
 }
 
-static void acpi_battery_check_present(struct acpi_battery *battery)
+static int acpi_battery_init_update(struct acpi_battery *battery)
 {
-	if (!battery->flags.present) {
-		acpi_battery_check(battery);
+	int result = 0;
+
+	result = acpi_battery_get_status(battery);
+	if (result)
+		return result;
+
+	battery->flags.battery_present_prev = acpi_battery_present(battery);
+
+	if (acpi_battery_present(battery)) {
+		result = acpi_battery_get_info(battery);
+		if (result)
+			return result;
+		result = acpi_battery_get_state(battery);
+		if (result)
+			return result;
+
+		acpi_battery_init_alarm(battery);
+	}
+
+	return result;
+}
+
+static int acpi_battery_update(struct acpi_battery *battery,
+			       int update, int *update_result_ptr)
+{
+	int result = 0;
+	int update_result = ACPI_BATTERY_NONE_UPDATE;
+
+	if (!acpi_battery_present(battery)) {
+		update = 1;
+	}
+
+	if (battery->flags.init_update) {
+		result = acpi_battery_init_update(battery);
+		if (result)
+			goto end;
+		update_result = ACPI_BATTERY_INIT_UPDATE;
+	} else if (update) {
+		result = acpi_battery_get_status(battery);
+		if (result)
+			goto end;
+		if ((!battery->flags.battery_present_prev & acpi_battery_present(battery))
+		    || (battery->flags.battery_present_prev & !acpi_battery_present(battery))) {
+			result = acpi_battery_init_update(battery);
+			if (result)
+				goto end;
+			update_result = ACPI_BATTERY_INIT_UPDATE;
+		} else {
+			update_result = ACPI_BATTERY_EASY_UPDATE;
+		}
+	}
+
+      end:
+
+	battery->flags.init_update = (result != 0);
+
+	*update_result_ptr = update_result;
+
+	return result;
+}
+
+static void acpi_battery_notify_update(struct acpi_battery *battery)
+{
+	acpi_battery_get_status(battery);
+
+	if (battery->flags.init_update) {
+		return;
+	}
+
+	if ((!battery->flags.battery_present_prev &
+	     acpi_battery_present(battery)) ||
+	    (battery->flags.battery_present_prev &
+	     !acpi_battery_present(battery))) {
+		battery->flags.init_update = 1;
+	} else {
+		battery->flags.update[ACPI_BATTERY_INFO] = 1;
+		battery->flags.update[ACPI_BATTERY_STATE] = 1;
+		battery->flags.update[ACPI_BATTERY_ALARM] = 1;
 	}
 }
 
@@ -335,37 +465,33 @@
    -------------------------------------------------------------------------- */
 
 static struct proc_dir_entry *acpi_battery_dir;
-static int acpi_battery_read_info(struct seq_file *seq, void *offset)
+
+static int acpi_battery_print_info(struct seq_file *seq, int result)
 {
-	int result = 0;
 	struct acpi_battery *battery = seq->private;
 	struct acpi_battery_info *bif = NULL;
 	char *units = "?";
 
-
-	if (!battery)
+	if (result)
 		goto end;
 
-	acpi_battery_check_present(battery);
-
-	if (battery->flags.present)
+	if (acpi_battery_present(battery))
 		seq_printf(seq, "present:                 yes\n");
 	else {
 		seq_printf(seq, "present:                 no\n");
 		goto end;
 	}
 
-	/* Battery Info (_BIF) */
-
-	result = acpi_battery_get_info(battery, &bif);
-	if (result || !bif) {
-		seq_printf(seq, "ERROR: Unable to read battery information\n");
+	bif = battery->bif_data.pointer;
+	if (!bif) {
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BIF buffer is NULL"));
+		result = -ENODEV;
 		goto end;
 	}
 
-	units =
-	    bif->
-	    power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
+	/* Battery Units */
+
+	units = acpi_battery_power_units(battery);
 
 	if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
 		seq_printf(seq, "design capacity:         unknown\n");
@@ -396,7 +522,6 @@
 	else
 		seq_printf(seq, "design voltage:          %d mV\n",
 			   (u32) bif->design_voltage);
-
 	seq_printf(seq, "design capacity warning: %d %sh\n",
 		   (u32) bif->design_capacity_warning, units);
 	seq_printf(seq, "design capacity low:     %d %sh\n",
@@ -411,50 +536,40 @@
 	seq_printf(seq, "OEM info:                %s\n", bif->oem_info);
 
       end:
-	kfree(bif);
 
-	return 0;
+	if (result)
+		seq_printf(seq, "ERROR: Unable to read battery info\n");
+
+	return result;
 }
 
-static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
+static int acpi_battery_print_state(struct seq_file *seq, int result)
 {
-	return single_open(file, acpi_battery_read_info, PDE(inode)->data);
-}
-
-static int acpi_battery_read_state(struct seq_file *seq, void *offset)
-{
-	int result = 0;
 	struct acpi_battery *battery = seq->private;
-	struct acpi_battery_status *bst = NULL;
+	struct acpi_battery_state *bst = NULL;
 	char *units = "?";
 
-
-	if (!battery)
+	if (result)
 		goto end;
 
-	acpi_battery_check_present(battery);
-
-	if (battery->flags.present)
+	if (acpi_battery_present(battery))
 		seq_printf(seq, "present:                 yes\n");
 	else {
 		seq_printf(seq, "present:                 no\n");
 		goto end;
 	}
 
-	/* Battery Units */
-
-	units =
-	    battery->flags.
-	    power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
-
-	/* Battery Status (_BST) */
-
-	result = acpi_battery_get_status(battery, &bst);
-	if (result || !bst) {
-		seq_printf(seq, "ERROR: Unable to read battery status\n");
+	bst = battery->bst_data.pointer;
+	if (!bst) {
+		ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BST buffer is NULL"));
+		result = -ENODEV;
 		goto end;
 	}
 
+	/* Battery Units */
+
+	units = acpi_battery_power_units(battery);
+
 	if (!(bst->state & 0x04))
 		seq_printf(seq, "capacity state:          ok\n");
 	else
@@ -490,48 +605,43 @@
 			   (u32) bst->present_voltage);
 
       end:
-	kfree(bst);
 
-	return 0;
+	if (result) {
+		seq_printf(seq, "ERROR: Unable to read battery state\n");
+	}
+
+	return result;
 }
 
-static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
-{
-	return single_open(file, acpi_battery_read_state, PDE(inode)->data);
-}
-
-static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
+static int acpi_battery_print_alarm(struct seq_file *seq, int result)
 {
 	struct acpi_battery *battery = seq->private;
 	char *units = "?";
 
-
-	if (!battery)
+	if (result)
 		goto end;
 
-	acpi_battery_check_present(battery);
-
-	if (!battery->flags.present) {
+	if (!acpi_battery_present(battery)) {
 		seq_printf(seq, "present:                 no\n");
 		goto end;
 	}
 
 	/* Battery Units */
 
-	units =
-	    battery->flags.
-	    power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
-
-	/* Battery Alarm */
+	units = acpi_battery_power_units(battery);
 
 	seq_printf(seq, "alarm:                   ");
 	if (!battery->alarm)
 		seq_printf(seq, "unsupported\n");
 	else
-		seq_printf(seq, "%d %sh\n", (u32) battery->alarm, units);
+		seq_printf(seq, "%lu %sh\n", battery->alarm, units);
 
       end:
-	return 0;
+
+	if (result)
+		seq_printf(seq, "ERROR: Unable to read battery alarm\n");
+
+	return result;
 }
 
 static ssize_t
@@ -543,27 +653,113 @@
 	char alarm_string[12] = { '\0' };
 	struct seq_file *m = file->private_data;
 	struct acpi_battery *battery = m->private;
-
+	int update_result = ACPI_BATTERY_NONE_UPDATE;
 
 	if (!battery || (count > sizeof(alarm_string) - 1))
 		return -EINVAL;
 
-	acpi_battery_check_present(battery);
+	mutex_lock(&battery->mutex);
 
-	if (!battery->flags.present)
-		return -ENODEV;
+	result = acpi_battery_update(battery, 1, &update_result);
+	if (result) {
+		result = -ENODEV;
+		goto end;
+	}
 
-	if (copy_from_user(alarm_string, buffer, count))
-		return -EFAULT;
+	if (!acpi_battery_present(battery)) {
+		result = -ENODEV;
+		goto end;
+	}
+
+	if (copy_from_user(alarm_string, buffer, count)) {
+		result = -EFAULT;
+		goto end;
+	}
 
 	alarm_string[count] = '\0';
 
 	result = acpi_battery_set_alarm(battery,
 					simple_strtoul(alarm_string, NULL, 0));
 	if (result)
-		return result;
+		goto end;
 
-	return count;
+      end:
+
+	acpi_battery_check_result(battery, result);
+
+	if (!result)
+		result = count;
+
+	mutex_unlock(&battery->mutex);
+
+	return result;
+}
+
+typedef int(*print_func)(struct seq_file *seq, int result);
+typedef int(*get_func)(struct acpi_battery *battery);
+
+static struct acpi_read_mux {
+	print_func print;
+	get_func get;
+} acpi_read_funcs[ACPI_BATTERY_NUMFILES] = {
+	{.get = acpi_battery_get_info, .print = acpi_battery_print_info},
+	{.get = acpi_battery_get_state, .print = acpi_battery_print_state},
+	{.get = acpi_battery_get_alarm, .print = acpi_battery_print_alarm},
+};
+
+static int acpi_battery_read(int fid, struct seq_file *seq)
+{
+	struct acpi_battery *battery = seq->private;
+	int result = 0;
+	int update_result = ACPI_BATTERY_NONE_UPDATE;
+	int update = 0;
+
+	mutex_lock(&battery->mutex);
+
+	update = (get_seconds() - battery->update_time[fid] >= update_time);
+	update = (update | battery->flags.update[fid]);
+
+	result = acpi_battery_update(battery, update, &update_result);
+	if (result)
+		goto end;
+
+	if (update_result == ACPI_BATTERY_EASY_UPDATE) {
+		result = acpi_read_funcs[fid].get(battery);
+		if (result)
+			goto end;
+	}
+
+      end:
+	result = acpi_read_funcs[fid].print(seq, result);
+	acpi_battery_check_result(battery, result);
+	battery->flags.update[fid] = result;
+	mutex_unlock(&battery->mutex);
+	return result;
+}
+
+static int acpi_battery_read_info(struct seq_file *seq, void *offset)
+{
+	return acpi_battery_read(ACPI_BATTERY_INFO, seq);
+}
+
+static int acpi_battery_read_state(struct seq_file *seq, void *offset)
+{
+	return acpi_battery_read(ACPI_BATTERY_STATE, seq);
+}
+
+static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
+{
+	return acpi_battery_read(ACPI_BATTERY_ALARM, seq);
+}
+
+static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_battery_read_info, PDE(inode)->data);
+}
+
+static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
+{
+	return single_open(file, acpi_battery_read_state, PDE(inode)->data);
 }
 
 static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
@@ -571,35 +767,51 @@
 	return single_open(file, acpi_battery_read_alarm, PDE(inode)->data);
 }
 
-static const struct file_operations acpi_battery_info_ops = {
+static struct battery_file {
+	struct file_operations ops;
+	mode_t mode;
+	char *name;
+} acpi_battery_file[] = {
+	{
+	.name = "info",
+	.mode = S_IRUGO,
+	.ops = {
 	.open = acpi_battery_info_open_fs,
 	.read = seq_read,
 	.llseek = seq_lseek,
 	.release = single_release,
 	.owner = THIS_MODULE,
-};
-
-static const struct file_operations acpi_battery_state_ops = {
+	},
+	},
+	{
+	.name = "state",
+	.mode = S_IRUGO,
+	.ops = {
 	.open = acpi_battery_state_open_fs,
 	.read = seq_read,
 	.llseek = seq_lseek,
 	.release = single_release,
 	.owner = THIS_MODULE,
-};
-
-static const struct file_operations acpi_battery_alarm_ops = {
+	},
+	},
+	{
+	.name = "alarm",
+	.mode = S_IFREG | S_IRUGO | S_IWUSR,
+	.ops = {
 	.open = acpi_battery_alarm_open_fs,
 	.read = seq_read,
 	.write = acpi_battery_write_alarm,
 	.llseek = seq_lseek,
 	.release = single_release,
 	.owner = THIS_MODULE,
+	},
+	},
 };
 
 static int acpi_battery_add_fs(struct acpi_device *device)
 {
 	struct proc_dir_entry *entry = NULL;
-
+	int i;
 
 	if (!acpi_device_dir(device)) {
 		acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
@@ -609,38 +821,16 @@
 		acpi_device_dir(device)->owner = THIS_MODULE;
 	}
 
-	/* 'info' [R] */
-	entry = create_proc_entry(ACPI_BATTERY_FILE_INFO,
-				  S_IRUGO, acpi_device_dir(device));
-	if (!entry)
-		return -ENODEV;
-	else {
-		entry->proc_fops = &acpi_battery_info_ops;
-		entry->data = acpi_driver_data(device);
-		entry->owner = THIS_MODULE;
-	}
-
-	/* 'status' [R] */
-	entry = create_proc_entry(ACPI_BATTERY_FILE_STATUS,
-				  S_IRUGO, acpi_device_dir(device));
-	if (!entry)
-		return -ENODEV;
-	else {
-		entry->proc_fops = &acpi_battery_state_ops;
-		entry->data = acpi_driver_data(device);
-		entry->owner = THIS_MODULE;
-	}
-
-	/* 'alarm' [R/W] */
-	entry = create_proc_entry(ACPI_BATTERY_FILE_ALARM,
-				  S_IFREG | S_IRUGO | S_IWUSR,
-				  acpi_device_dir(device));
-	if (!entry)
-		return -ENODEV;
-	else {
-		entry->proc_fops = &acpi_battery_alarm_ops;
-		entry->data = acpi_driver_data(device);
-		entry->owner = THIS_MODULE;
+	for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) {
+		entry = create_proc_entry(acpi_battery_file[i].name,
+				  acpi_battery_file[i].mode, acpi_device_dir(device));
+		if (!entry)
+			return -ENODEV;
+		else {
+			entry->proc_fops = &acpi_battery_file[i].ops;
+			entry->data = acpi_driver_data(device);
+			entry->owner = THIS_MODULE;
+		}
 	}
 
 	return 0;
@@ -648,15 +838,12 @@
 
 static int acpi_battery_remove_fs(struct acpi_device *device)
 {
-
+	int i;
 	if (acpi_device_dir(device)) {
-		remove_proc_entry(ACPI_BATTERY_FILE_ALARM,
+		for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) {
+			remove_proc_entry(acpi_battery_file[i].name,
 				  acpi_device_dir(device));
-		remove_proc_entry(ACPI_BATTERY_FILE_STATUS,
-				  acpi_device_dir(device));
-		remove_proc_entry(ACPI_BATTERY_FILE_INFO,
-				  acpi_device_dir(device));
-
+		}
 		remove_proc_entry(acpi_device_bid(device), acpi_battery_dir);
 		acpi_device_dir(device) = NULL;
 	}
@@ -673,7 +860,6 @@
 	struct acpi_battery *battery = data;
 	struct acpi_device *device = NULL;
 
-
 	if (!battery)
 		return;
 
@@ -684,8 +870,13 @@
 	case ACPI_BATTERY_NOTIFY_INFO:
 	case ACPI_NOTIFY_BUS_CHECK:
 	case ACPI_NOTIFY_DEVICE_CHECK:
-		acpi_battery_check(battery);
-		acpi_bus_generate_event(device, event, battery->flags.present);
+		device = battery->device;
+		acpi_battery_notify_update(battery);
+		acpi_bus_generate_proc_event(device, event,
+					acpi_battery_present(battery));
+		acpi_bus_generate_netlink_event(device->pnp.device_class,
+						  device->dev.bus_id, event,
+						  acpi_battery_present(battery));
 		break;
 	default:
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -702,7 +893,6 @@
 	acpi_status status = 0;
 	struct acpi_battery *battery = NULL;
 
-
 	if (!device)
 		return -EINVAL;
 
@@ -710,15 +900,21 @@
 	if (!battery)
 		return -ENOMEM;
 
+	mutex_init(&battery->mutex);
+
+	mutex_lock(&battery->mutex);
+
 	battery->device = device;
 	strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
 	strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
 	acpi_driver_data(device) = battery;
 
-	result = acpi_battery_check(battery);
+	result = acpi_battery_get_status(battery);
 	if (result)
 		goto end;
 
+	battery->flags.init_update = 1;
+
 	result = acpi_battery_add_fs(device);
 	if (result)
 		goto end;
@@ -727,6 +923,7 @@
 					     ACPI_ALL_NOTIFY,
 					     acpi_battery_notify, battery);
 	if (ACPI_FAILURE(status)) {
+		ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler"));
 		result = -ENODEV;
 		goto end;
 	}
@@ -736,11 +933,14 @@
 	       device->status.battery_present ? "present" : "absent");
 
       end:
+
 	if (result) {
 		acpi_battery_remove_fs(device);
 		kfree(battery);
 	}
 
+	mutex_unlock(&battery->mutex);
+
 	return result;
 }
 
@@ -749,18 +949,27 @@
 	acpi_status status = 0;
 	struct acpi_battery *battery = NULL;
 
-
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
 
 	battery = acpi_driver_data(device);
 
+	mutex_lock(&battery->mutex);
+
 	status = acpi_remove_notify_handler(device->handle,
 					    ACPI_ALL_NOTIFY,
 					    acpi_battery_notify);
 
 	acpi_battery_remove_fs(device);
 
+	kfree(battery->bif_data.pointer);
+
+	kfree(battery->bst_data.pointer);
+
+	mutex_unlock(&battery->mutex);
+
+	mutex_destroy(&battery->mutex);
+
 	kfree(battery);
 
 	return 0;
@@ -775,7 +984,10 @@
 		return -EINVAL;
 
 	battery = device->driver_data;
-	return acpi_battery_check(battery);
+
+	battery->flags.init_update = 1;
+
+	return 0;
 }
 
 static int __init acpi_battery_init(void)
@@ -800,7 +1012,6 @@
 
 static void __exit acpi_battery_exit(void)
 {
-
 	acpi_bus_unregister_driver(&acpi_battery_driver);
 
 	acpi_unlock_battery_dir(acpi_battery_dir);
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
index fb3f31b..6daf6088 100644
--- a/drivers/acpi/bay.c
+++ b/drivers/acpi/bay.c
@@ -288,6 +288,11 @@
 	new_bay->pdev = pdev;
 	platform_set_drvdata(pdev, new_bay);
 
+	/*
+	 * we want the bay driver to be able to send uevents
+	 */
+	pdev->dev.uevent_suppress = 0;
+
 	if (acpi_bay_add_fs(new_bay)) {
 		platform_device_unregister(new_bay->pdev);
 		goto bay_add_err;
@@ -328,18 +333,12 @@
 {
 	struct bay *bay_dev = (struct bay *)data;
 	struct device *dev = &bay_dev->pdev->dev;
+	char event_string[12];
+	char *envp[] = { event_string, NULL };
 
 	bay_dprintk(handle, "Bay event");
-
-	switch(event) {
-	case ACPI_NOTIFY_BUS_CHECK:
-	case ACPI_NOTIFY_DEVICE_CHECK:
-	case ACPI_NOTIFY_EJECT_REQUEST:
-		kobject_uevent(&dev->kobj, KOBJ_CHANGE);
-		break;
-	default:
-		printk(KERN_ERR PREFIX "Bay: unknown event %d\n", event);
-	}
+	sprintf(event_string, "BAY_EVENT=%d", event);
+	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 }
 
 static acpi_status
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index e5084ec..cbfc815 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -194,7 +194,7 @@
 
 	if (!device->flags.power_manageable) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
-				device->dev.kobj.name));
+				kobject_name(&device->dev.kobj)));
 		return -ENODEV;
 	}
 	/*
@@ -262,10 +262,12 @@
 		printk(KERN_WARNING PREFIX
 			      "Transitioning device [%s] to D%d\n",
 			      device->pnp.bus_id, state);
-	else
+	else {
+		device->power.state = state;
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Device [%s] transitioned to D%d\n",
 				  device->pnp.bus_id, state));
+	}
 
 	return result;
 }
@@ -276,6 +278,7 @@
                                 Event Management
    -------------------------------------------------------------------------- */
 
+#ifdef CONFIG_ACPI_PROC_EVENT
 static DEFINE_SPINLOCK(acpi_bus_event_lock);
 
 LIST_HEAD(acpi_bus_event_list);
@@ -283,7 +286,7 @@
 
 extern int event_is_open;
 
-int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data)
+int acpi_bus_generate_proc_event(struct acpi_device *device, u8 type, int data)
 {
 	struct acpi_bus_event *event = NULL;
 	unsigned long flags = 0;
@@ -314,7 +317,7 @@
 	return 0;
 }
 
-EXPORT_SYMBOL(acpi_bus_generate_event);
+EXPORT_SYMBOL(acpi_bus_generate_proc_event);
 
 int acpi_bus_receive_event(struct acpi_bus_event *event)
 {
@@ -360,6 +363,7 @@
 }
 
 EXPORT_SYMBOL(acpi_bus_receive_event);
+#endif	/* CONFIG_ACPI_PROC_EVENT */
 
 /* --------------------------------------------------------------------------
                              Notification Handling
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index cb4110b..2e79a33 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -66,6 +66,16 @@
 MODULE_DESCRIPTION("ACPI Button Driver");
 MODULE_LICENSE("GPL");
 
+static const struct acpi_device_id button_device_ids[] = {
+	{ACPI_BUTTON_HID_LID,    0},
+	{ACPI_BUTTON_HID_SLEEP,  0},
+	{ACPI_BUTTON_HID_SLEEPF, 0},
+	{ACPI_BUTTON_HID_POWER,  0},
+	{ACPI_BUTTON_HID_POWERF, 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, button_device_ids);
+
 static int acpi_button_add(struct acpi_device *device);
 static int acpi_button_remove(struct acpi_device *device, int type);
 static int acpi_button_info_open_fs(struct inode *inode, struct file *file);
@@ -74,7 +84,7 @@
 static struct acpi_driver acpi_button_driver = {
 	.name = "button",
 	.class = ACPI_BUTTON_CLASS,
-	.ids = "button_power,button_sleep,PNP0C0D,PNP0C0C,PNP0C0E",
+	.ids = button_device_ids,
 	.ops = {
 		.add = acpi_button_add,
 		.remove = acpi_button_remove,
@@ -274,7 +284,7 @@
 		}
 		input_sync(input);
 
-		acpi_bus_generate_event(button->device, event,
+		acpi_bus_generate_proc_event(button->device, event,
 					++button->pushed);
 		break;
 	default:
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 0dd3bf7..3c25ec7 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -52,10 +52,18 @@
 static int acpi_container_add(struct acpi_device *device);
 static int acpi_container_remove(struct acpi_device *device, int type);
 
+static const struct acpi_device_id container_device_ids[] = {
+	{"ACPI0004", 0},
+	{"PNP0A05", 0},
+	{"PNP0A06", 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, container_device_ids);
+
 static struct acpi_driver acpi_container_driver = {
 	.name = "container",
 	.class = ACPI_CONTAINER_CLASS,
-	.ids = "ACPI0004,PNP0A05,PNP0A06",
+	.ids = container_device_ids,
 	.ops = {
 		.add = acpi_container_add,
 		.remove = acpi_container_remove,
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 4546bf8..1dabdf4 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -40,8 +40,15 @@
 MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION);
 MODULE_LICENSE("GPL");
 
+static int immediate_undock = 1;
+module_param(immediate_undock, bool, 0644);
+MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
+	"undock immediately when the undock button is pressed, 0 will cause"
+	" the driver to wait for userspace to write the undock sysfs file "
+	" before undocking");
+
 static struct atomic_notifier_head dock_notifier_list;
-static struct platform_device dock_device;
+static struct platform_device *dock_device;
 static char dock_device_name[] = "dock";
 
 struct dock_station {
@@ -63,6 +70,7 @@
 };
 
 #define DOCK_DOCKING	0x00000001
+#define DOCK_UNDOCKING  0x00000002
 #define DOCK_EVENT	3
 #define UNDOCK_EVENT	2
 
@@ -327,12 +335,20 @@
 
 static void dock_event(struct dock_station *ds, u32 event, int num)
 {
-	struct device *dev = &dock_device.dev;
+	struct device *dev = &dock_device->dev;
+	char event_string[13];
+	char *envp[] = { event_string, NULL };
+
+	if (num == UNDOCK_EVENT)
+		sprintf(event_string, "EVENT=undock");
+	else
+		sprintf(event_string, "EVENT=dock");
+
 	/*
 	 * Indicate that the status of the dock station has
 	 * changed.
 	 */
-	kobject_uevent(&dev->kobj, KOBJ_CHANGE);
+	kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
 }
 
 /**
@@ -380,12 +396,11 @@
 	union acpi_object arg;
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 	struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-	union acpi_object *obj;
 
 	acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer);
-	obj = name_buffer.pointer;
 
-	printk(KERN_INFO PREFIX "%s\n", dock ? "docking" : "undocking");
+	printk(KERN_INFO PREFIX "%s - %s\n",
+		(char *)name_buffer.pointer, dock ? "docking" : "undocking");
 
 	/* _DCK method has one argument */
 	arg_list.count = 1;
@@ -394,7 +409,8 @@
 	arg.integer.value = dock;
 	status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
 	if (ACPI_FAILURE(status))
-		pr_debug("%s: failed to execute _DCK\n", obj->string.pointer);
+		printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n",
+			 (char *)name_buffer.pointer);
 	kfree(buffer.pointer);
 	kfree(name_buffer.pointer);
 }
@@ -420,6 +436,16 @@
 	ds->last_dock_time = jiffies;
 }
 
+static inline void begin_undock(struct dock_station *ds)
+{
+	ds->flags |= DOCK_UNDOCKING;
+}
+
+static inline void complete_undock(struct dock_station *ds)
+{
+	ds->flags &= ~(DOCK_UNDOCKING);
+}
+
 /**
  * dock_in_progress - see if we are in the middle of handling a dock event
  * @ds: the dock station
@@ -550,7 +576,7 @@
 		printk(KERN_ERR PREFIX "Unable to undock!\n");
 		return -EBUSY;
 	}
-
+	complete_undock(ds);
 	return 0;
 }
 
@@ -594,7 +620,11 @@
 	 * to the driver who wish to hotplug.
          */
 	case ACPI_NOTIFY_EJECT_REQUEST:
-		handle_eject_request(ds, event);
+		begin_undock(ds);
+		if (immediate_undock)
+			handle_eject_request(ds, event);
+		else
+			dock_event(ds, event, UNDOCK_EVENT);
 		break;
 	default:
 		printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);
@@ -653,6 +683,17 @@
 DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
 
 /*
+ * show_flags - read method for flags file in sysfs
+ */
+static ssize_t show_flags(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
+
+}
+DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
+
+/*
  * write_undock - write method for "undock" file in sysfs
  */
 static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
@@ -675,16 +716,15 @@
 			     struct device_attribute *attr, char *buf)
 {
 	unsigned long lbuf;
-	acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf);
-	if(ACPI_FAILURE(status)) {
+	acpi_status status = acpi_evaluate_integer(dock_station->handle,
+					"_UID", NULL, &lbuf);
+	if (ACPI_FAILURE(status))
 	    return 0;
-	}
+
 	return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf);
 }
 DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
 
-
-
 /**
  * dock_add - add a new dock station
  * @handle: the dock station handle
@@ -711,33 +751,53 @@
 	ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
 
 	/* initialize platform device stuff */
-	dock_device.name = dock_device_name;
-	ret = platform_device_register(&dock_device);
-	if (ret) {
-		printk(KERN_ERR PREFIX "Error %d registering dock device\n", ret);
+	dock_device =
+		platform_device_register_simple(dock_device_name, 0, NULL, 0);
+	if (IS_ERR(dock_device)) {
 		kfree(dock_station);
-		return ret;
+		dock_station = NULL;
+		return PTR_ERR(dock_device);
 	}
-	ret = device_create_file(&dock_device.dev, &dev_attr_docked);
+
+	/* we want the dock device to send uevents */
+	dock_device->dev.uevent_suppress = 0;
+
+	ret = device_create_file(&dock_device->dev, &dev_attr_docked);
 	if (ret) {
 		printk("Error %d adding sysfs file\n", ret);
-		platform_device_unregister(&dock_device);
+		platform_device_unregister(dock_device);
 		kfree(dock_station);
+		dock_station = NULL;
 		return ret;
 	}
-	ret = device_create_file(&dock_device.dev, &dev_attr_undock);
+	ret = device_create_file(&dock_device->dev, &dev_attr_undock);
 	if (ret) {
 		printk("Error %d adding sysfs file\n", ret);
-		device_remove_file(&dock_device.dev, &dev_attr_docked);
-		platform_device_unregister(&dock_device);
+		device_remove_file(&dock_device->dev, &dev_attr_docked);
+		platform_device_unregister(dock_device);
 		kfree(dock_station);
+		dock_station = NULL;
 		return ret;
 	}
-	ret = device_create_file(&dock_device.dev, &dev_attr_uid);
+	ret = device_create_file(&dock_device->dev, &dev_attr_uid);
 	if (ret) {
 		printk("Error %d adding sysfs file\n", ret);
-		platform_device_unregister(&dock_device);
+		device_remove_file(&dock_device->dev, &dev_attr_docked);
+		device_remove_file(&dock_device->dev, &dev_attr_undock);
+		platform_device_unregister(dock_device);
 		kfree(dock_station);
+		dock_station = NULL;
+		return ret;
+	}
+	ret = device_create_file(&dock_device->dev, &dev_attr_flags);
+	if (ret) {
+		printk("Error %d adding sysfs file\n", ret);
+		device_remove_file(&dock_device->dev, &dev_attr_docked);
+		device_remove_file(&dock_device->dev, &dev_attr_undock);
+		device_remove_file(&dock_device->dev, &dev_attr_uid);
+		platform_device_unregister(dock_device);
+		kfree(dock_station);
+		dock_station = NULL;
 		return ret;
 	}
 
@@ -750,6 +810,7 @@
 	dd = alloc_dock_dependent_device(handle);
 	if (!dd) {
 		kfree(dock_station);
+		dock_station = NULL;
 		ret = -ENOMEM;
 		goto dock_add_err_unregister;
 	}
@@ -773,10 +834,13 @@
 dock_add_err:
 	kfree(dd);
 dock_add_err_unregister:
-	device_remove_file(&dock_device.dev, &dev_attr_docked);
-	device_remove_file(&dock_device.dev, &dev_attr_undock);
-	platform_device_unregister(&dock_device);
+	device_remove_file(&dock_device->dev, &dev_attr_docked);
+	device_remove_file(&dock_device->dev, &dev_attr_undock);
+	device_remove_file(&dock_device->dev, &dev_attr_uid);
+	device_remove_file(&dock_device->dev, &dev_attr_flags);
+	platform_device_unregister(dock_device);
 	kfree(dock_station);
+	dock_station = NULL;
 	return ret;
 }
 
@@ -804,12 +868,15 @@
 		printk(KERN_ERR "Error removing notify handler\n");
 
 	/* cleanup sysfs */
-	device_remove_file(&dock_device.dev, &dev_attr_docked);
-	device_remove_file(&dock_device.dev, &dev_attr_undock);
-	platform_device_unregister(&dock_device);
+	device_remove_file(&dock_device->dev, &dev_attr_docked);
+	device_remove_file(&dock_device->dev, &dev_attr_undock);
+	device_remove_file(&dock_device->dev, &dev_attr_uid);
+	device_remove_file(&dock_device->dev, &dev_attr_flags);
+	platform_device_unregister(dock_device);
 
 	/* free dock station memory */
 	kfree(dock_station);
+	dock_station = NULL;
 	return 0;
 }
 
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 82f496c..3f7935a 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -34,25 +34,25 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/interrupt.h>
+#include <linux/list.h>
 #include <asm/io.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 #include <acpi/actypes.h>
 
-#define _COMPONENT		ACPI_EC_COMPONENT
-ACPI_MODULE_NAME("ec");
-#define ACPI_EC_COMPONENT		0x00100000
 #define ACPI_EC_CLASS			"embedded_controller"
-#define ACPI_EC_HID			"PNP0C09"
 #define ACPI_EC_DEVICE_NAME		"Embedded Controller"
 #define ACPI_EC_FILE_INFO		"info"
+
 #undef PREFIX
 #define PREFIX				"ACPI: EC: "
+
 /* EC status register */
 #define ACPI_EC_FLAG_OBF	0x01	/* Output buffer full */
 #define ACPI_EC_FLAG_IBF	0x02	/* Input buffer full */
 #define ACPI_EC_FLAG_BURST	0x10	/* burst mode */
 #define ACPI_EC_FLAG_SCI	0x20	/* EC-SCI occurred */
+
 /* EC commands */
 enum ec_command {
 	ACPI_EC_COMMAND_READ = 0x80,
@@ -61,6 +61,7 @@
 	ACPI_EC_BURST_DISABLE = 0x83,
 	ACPI_EC_COMMAND_QUERY = 0x84,
 };
+
 /* EC events */
 enum ec_event {
 	ACPI_EC_EVENT_OBF_1 = 1,	/* Output buffer full */
@@ -80,10 +81,15 @@
 static int acpi_ec_stop(struct acpi_device *device, int type);
 static int acpi_ec_add(struct acpi_device *device);
 
+static const struct acpi_device_id ec_device_ids[] = {
+	{"PNP0C09", 0},
+	{"", 0},
+};
+
 static struct acpi_driver acpi_ec_driver = {
 	.name = "ec",
 	.class = ACPI_EC_CLASS,
-	.ids = ACPI_EC_HID,
+	.ids = ec_device_ids,
 	.ops = {
 		.add = acpi_ec_add,
 		.remove = acpi_ec_remove,
@@ -94,6 +100,16 @@
 
 /* If we find an EC via the ECDT, we need to keep a ptr to its context */
 /* External interfaces use first EC only, so remember */
+typedef int (*acpi_ec_query_func) (void *data);
+
+struct acpi_ec_query_handler {
+	struct list_head node;
+	acpi_ec_query_func func;
+	acpi_handle handle;
+	void *data;
+	u8 query_bit;
+};
+
 static struct acpi_ec {
 	acpi_handle handle;
 	unsigned long gpe;
@@ -104,6 +120,7 @@
 	atomic_t query_pending;
 	atomic_t event_count;
 	wait_queue_head_t wait;
+	struct list_head list;
 } *boot_ec, *first_ec;
 
 /* --------------------------------------------------------------------------
@@ -245,7 +262,7 @@
 
 	status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0, 0);
 	if (status) {
-		printk(KERN_DEBUG PREFIX
+		printk(KERN_ERR PREFIX
 		       "input buffer is not empty, aborting transaction\n");
 		goto end;
 	}
@@ -394,21 +411,66 @@
 /* --------------------------------------------------------------------------
                                 Event Management
    -------------------------------------------------------------------------- */
+int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
+			      acpi_handle handle, acpi_ec_query_func func,
+			      void *data)
+{
+	struct acpi_ec_query_handler *handler =
+	    kzalloc(sizeof(struct acpi_ec_query_handler), GFP_KERNEL);
+	if (!handler)
+		return -ENOMEM;
+
+	handler->query_bit = query_bit;
+	handler->handle = handle;
+	handler->func = func;
+	handler->data = data;
+	mutex_lock(&ec->lock);
+	list_add_tail(&handler->node, &ec->list);
+	mutex_unlock(&ec->lock);
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
+
+void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
+{
+	struct acpi_ec_query_handler *handler;
+	mutex_lock(&ec->lock);
+	list_for_each_entry(handler, &ec->list, node) {
+		if (query_bit == handler->query_bit) {
+			list_del(&handler->node);
+			kfree(handler);
+			break;
+		}
+	}
+	mutex_unlock(&ec->lock);
+}
+
+EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
 
 static void acpi_ec_gpe_query(void *ec_cxt)
 {
 	struct acpi_ec *ec = ec_cxt;
 	u8 value = 0;
-	char object_name[8];
+	struct acpi_ec_query_handler *handler, copy;
 
 	if (!ec || acpi_ec_query(ec, &value))
 		return;
-
-	snprintf(object_name, 8, "_Q%2.2X", value);
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name));
-
-	acpi_evaluate_object(ec->handle, object_name, NULL, NULL);
+	mutex_lock(&ec->lock);
+	list_for_each_entry(handler, &ec->list, node) {
+		if (value == handler->query_bit) {
+			/* have custom handler for this bit */
+			memcpy(&copy, handler, sizeof(copy));
+			mutex_unlock(&ec->lock);
+			if (copy.func) {
+				copy.func(copy.data);
+			} else if (copy.handle) {
+				acpi_evaluate_object(copy.handle, NULL, NULL, NULL);
+			}
+			return;
+		}
+	}
+	mutex_unlock(&ec->lock);
 }
 
 static u32 acpi_ec_gpe_handler(void *data)
@@ -427,8 +489,7 @@
 	if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) {
 		atomic_set(&ec->query_pending, 1);
 		status =
-		    acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query,
-				    ec);
+		    acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec);
 	}
 
 	return status == AE_OK ?
@@ -454,57 +515,35 @@
 }
 
 static acpi_status
-acpi_ec_space_handler(u32 function,
-		      acpi_physical_address address,
-		      u32 bit_width,
-		      acpi_integer * value,
+acpi_ec_space_handler(u32 function, acpi_physical_address address,
+		      u32 bits, acpi_integer *value,
 		      void *handler_context, void *region_context)
 {
-	int result = 0;
 	struct acpi_ec *ec = handler_context;
-	u64 temp = *value;
-	acpi_integer f_v = 0;
-	int i = 0;
+	int result = 0, i = 0;
+	u8 temp = 0;
 
 	if ((address > 0xFF) || !value || !handler_context)
 		return AE_BAD_PARAMETER;
 
-	if (bit_width != 8 && acpi_strict) {
+	if (function != ACPI_READ && function != ACPI_WRITE)
 		return AE_BAD_PARAMETER;
+
+	if (bits != 8 && acpi_strict)
+		return AE_BAD_PARAMETER;
+
+	while (bits - i > 0) {
+		if (function == ACPI_READ) {
+			result = acpi_ec_read(ec, address, &temp);
+			(*value) |= ((acpi_integer)temp) << i;
+		} else {
+			temp = 0xff & ((*value) >> i);
+			result = acpi_ec_write(ec, address, temp);
+		}
+		i += 8;
+		++address;
 	}
 
-      next_byte:
-	switch (function) {
-	case ACPI_READ:
-		temp = 0;
-		result = acpi_ec_read(ec, (u8) address, (u8 *) & temp);
-		break;
-	case ACPI_WRITE:
-		result = acpi_ec_write(ec, (u8) address, (u8) temp);
-		break;
-	default:
-		result = -EINVAL;
-		goto out;
-		break;
-	}
-
-	bit_width -= 8;
-	if (bit_width) {
-		if (function == ACPI_READ)
-			f_v |= temp << 8 * i;
-		if (function == ACPI_WRITE)
-			temp >>= 8;
-		i++;
-		address++;
-		goto next_byte;
-	}
-
-	if (function == ACPI_READ) {
-		f_v |= temp << 8 * i;
-		*value = f_v;
-	}
-
-      out:
 	switch (result) {
 	case -EINVAL:
 		return AE_BAD_PARAMETER;
@@ -597,9 +636,6 @@
 static acpi_status
 ec_parse_io_ports(struct acpi_resource *resource, void *context);
 
-static acpi_status
-ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval);
-
 static struct acpi_ec *make_acpi_ec(void)
 {
 	struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
@@ -610,13 +646,58 @@
 	atomic_set(&ec->event_count, 1);
 	mutex_init(&ec->lock);
 	init_waitqueue_head(&ec->wait);
+	INIT_LIST_HEAD(&ec->list);
 
 	return ec;
 }
 
+static acpi_status
+acpi_ec_register_query_methods(acpi_handle handle, u32 level,
+			       void *context, void **return_value)
+{
+	struct acpi_namespace_node *node = handle;
+	struct acpi_ec *ec = context;
+	int value = 0;
+	if (sscanf(node->name.ascii, "_Q%x", &value) == 1) {
+		acpi_ec_add_query_handler(ec, value, handle, NULL, NULL);
+	}
+	return AE_OK;
+}
+
+static acpi_status
+ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
+{
+	acpi_status status;
+
+	struct acpi_ec *ec = context;
+	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
+				     ec_parse_io_ports, ec);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	/* Get GPE bit assignment (EC events). */
+	/* TODO: Add support for _GPE returning a package */
+	status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
+	if (ACPI_FAILURE(status))
+		return status;
+
+	/* Find and register all query methods */
+	acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1,
+			    acpi_ec_register_query_methods, ec, NULL);
+
+	/* Use the global lock for all EC transactions? */
+	acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
+
+	ec->handle = handle;
+
+	printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n",
+			  ec->gpe, ec->command_addr, ec->data_addr);
+
+	return AE_CTRL_TERMINATE;
+}
+
 static int acpi_ec_add(struct acpi_device *device)
 {
-	acpi_status status = AE_OK;
 	struct acpi_ec *ec = NULL;
 
 	if (!device)
@@ -629,8 +710,8 @@
 	if (!ec)
 		return -ENOMEM;
 
-	status = ec_parse_device(device->handle, 0, ec, NULL);
-	if (status != AE_CTRL_TERMINATE) {
+	if (ec_parse_device(device->handle, 0, ec, NULL) !=
+	    AE_CTRL_TERMINATE) {
 		kfree(ec);
 		return -EINVAL;
 	}
@@ -641,6 +722,8 @@
 			/* We might have incorrect info for GL at boot time */
 			mutex_lock(&boot_ec->lock);
 			boot_ec->global_lock = ec->global_lock;
+			/* Copy handlers from new ec into boot ec */
+			list_splice(&ec->list, &boot_ec->list);
 			mutex_unlock(&boot_ec->lock);
 			kfree(ec);
 			ec = boot_ec;
@@ -651,22 +734,24 @@
 	acpi_driver_data(device) = ec;
 
 	acpi_ec_add_fs(device);
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
-			  acpi_device_name(device), acpi_device_bid(device),
-			  (u32) ec->gpe));
-
 	return 0;
 }
 
 static int acpi_ec_remove(struct acpi_device *device, int type)
 {
 	struct acpi_ec *ec;
+	struct acpi_ec_query_handler *handler, *tmp;
 
 	if (!device)
 		return -EINVAL;
 
 	ec = acpi_driver_data(device);
+	mutex_lock(&ec->lock);
+	list_for_each_entry_safe(handler, tmp, &ec->list, node) {
+		list_del(&handler->node);
+		kfree(handler);
+	}
+	mutex_unlock(&ec->lock);
 	acpi_ec_remove_fs(device);
 	acpi_driver_data(device) = NULL;
 	if (ec == first_ec)
@@ -722,15 +807,13 @@
 		return -ENODEV;
 	}
 
-	/* EC is fully operational, allow queries */
-	atomic_set(&ec->query_pending, 0);
-
 	return 0;
 }
 
 static int acpi_ec_start(struct acpi_device *device)
 {
 	struct acpi_ec *ec;
+	int ret = 0;
 
 	if (!device)
 		return -EINVAL;
@@ -740,14 +823,14 @@
 	if (!ec)
 		return -EINVAL;
 
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
-			  ec->gpe, ec->command_addr, ec->data_addr));
-
 	/* Boot EC is already working */
-	if (ec == boot_ec)
-		return 0;
+	if (ec != boot_ec)
+		ret = ec_install_handlers(ec);
 
-	return ec_install_handlers(ec);
+	/* EC is fully operational, allow queries */
+	atomic_set(&ec->query_pending, 0);
+
+	return ret;
 }
 
 static int acpi_ec_stop(struct acpi_device *device, int type)
@@ -779,34 +862,6 @@
 	return 0;
 }
 
-static acpi_status
-ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
-{
-	acpi_status status;
-
-	struct acpi_ec *ec = context;
-	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
-				     ec_parse_io_ports, ec);
-	if (ACPI_FAILURE(status))
-		return status;
-
-	/* Get GPE bit assignment (EC events). */
-	/* TODO: Add support for _GPE returning a package */
-	status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
-	if (ACPI_FAILURE(status))
-		return status;
-
-	/* Use the global lock for all EC transactions? */
-	acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
-
-	ec->handle = handle;
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
-			  ec->gpe, ec->command_addr, ec->data_addr));
-
-	return AE_CTRL_TERMINATE;
-}
-
 int __init acpi_ec_ecdt_probe(void)
 {
 	int ret;
@@ -819,18 +874,22 @@
 	/*
 	 * Generate a boot ec context
 	 */
-
 	status = acpi_get_table(ACPI_SIG_ECDT, 1,
 				(struct acpi_table_header **)&ecdt_ptr);
-	if (ACPI_FAILURE(status))
-		goto error;
-
-	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
-
-	boot_ec->command_addr = ecdt_ptr->control.address;
-	boot_ec->data_addr = ecdt_ptr->data.address;
-	boot_ec->gpe = ecdt_ptr->gpe;
-	boot_ec->handle = ACPI_ROOT_OBJECT;
+	if (ACPI_SUCCESS(status)) {
+		printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n\n");
+		boot_ec->command_addr = ecdt_ptr->control.address;
+		boot_ec->data_addr = ecdt_ptr->data.address;
+		boot_ec->gpe = ecdt_ptr->gpe;
+		boot_ec->handle = ACPI_ROOT_OBJECT;
+	} else {
+		printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n");
+		status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device,
+						boot_ec, NULL);
+		/* Check that acpi_get_devices actually find something */
+		if (ACPI_FAILURE(status) || !boot_ec->handle)
+			goto error;
+	}
 
 	ret = ec_install_handlers(boot_ec);
 	if (!ret) {
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index 3b23562..5c95863 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -11,10 +11,13 @@
 #include <linux/init.h>
 #include <linux/poll.h>
 #include <acpi/acpi_drivers.h>
+#include <net/netlink.h>
+#include <net/genetlink.h>
 
 #define _COMPONENT		ACPI_SYSTEM_COMPONENT
 ACPI_MODULE_NAME("event");
 
+#ifdef CONFIG_ACPI_PROC_EVENT
 /* Global vars for handling event proc entry */
 static DEFINE_SPINLOCK(acpi_system_event_lock);
 int event_is_open = 0;
@@ -48,7 +51,6 @@
 	static int chars_remaining = 0;
 	static char *ptr;
 
-
 	if (!chars_remaining) {
 		memset(&event, 0, sizeof(struct acpi_bus_event));
 
@@ -105,24 +107,173 @@
 	.release = acpi_system_close_event,
 	.poll = acpi_system_poll_event,
 };
+#endif	/* CONFIG_ACPI_PROC_EVENT */
+
+#ifdef CONFIG_NET
+static unsigned int acpi_event_seqnum;
+struct acpi_genl_event {
+	acpi_device_class device_class;
+	char bus_id[15];
+	u32 type;
+	u32 data;
+};
+
+/* attributes of acpi_genl_family */
+enum {
+	ACPI_GENL_ATTR_UNSPEC,
+	ACPI_GENL_ATTR_EVENT,	/* ACPI event info needed by user space */
+	__ACPI_GENL_ATTR_MAX,
+};
+#define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1)
+
+/* commands supported by the acpi_genl_family */
+enum {
+	ACPI_GENL_CMD_UNSPEC,
+	ACPI_GENL_CMD_EVENT,	/* kernel->user notifications for ACPI events */
+	__ACPI_GENL_CMD_MAX,
+};
+#define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1)
+
+#define ACPI_GENL_FAMILY_NAME		"acpi_event"
+#define ACPI_GENL_VERSION		0x01
+#define ACPI_GENL_MCAST_GROUP_NAME 	"acpi_mc_group"
+
+static struct genl_family acpi_event_genl_family = {
+	.id = GENL_ID_GENERATE,
+	.name = ACPI_GENL_FAMILY_NAME,
+	.version = ACPI_GENL_VERSION,
+	.maxattr = ACPI_GENL_ATTR_MAX,
+};
+
+static struct genl_multicast_group acpi_event_mcgrp = {
+	.name = ACPI_GENL_MCAST_GROUP_NAME,
+};
+
+int acpi_bus_generate_netlink_event(const char *device_class,
+				      const char *bus_id,
+				      u8 type, int data)
+{
+	struct sk_buff *skb;
+	struct nlattr *attr;
+	struct acpi_genl_event *event;
+	void *msg_header;
+	int size;
+	int result;
+
+	/* allocate memory */
+	size = nla_total_size(sizeof(struct acpi_genl_event)) +
+	    nla_total_size(0);
+
+	skb = genlmsg_new(size, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	/* add the genetlink message header */
+	msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++,
+				 &acpi_event_genl_family, 0,
+				 ACPI_GENL_CMD_EVENT);
+	if (!msg_header) {
+		nlmsg_free(skb);
+		return -ENOMEM;
+	}
+
+	/* fill the data */
+	attr =
+	    nla_reserve(skb, ACPI_GENL_ATTR_EVENT,
+			sizeof(struct acpi_genl_event));
+	if (!attr) {
+		nlmsg_free(skb);
+		return -EINVAL;
+	}
+
+	event = nla_data(attr);
+	if (!event) {
+		nlmsg_free(skb);
+		return -EINVAL;
+	}
+
+	memset(event, 0, sizeof(struct acpi_genl_event));
+
+	strcpy(event->device_class, device_class);
+	strcpy(event->bus_id, bus_id);
+	event->type = type;
+	event->data = data;
+
+	/* send multicast genetlink message */
+	result = genlmsg_end(skb, msg_header);
+	if (result < 0) {
+		nlmsg_free(skb);
+		return result;
+	}
+
+	result =
+	    genlmsg_multicast(skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC);
+	if (result)
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+				  "Failed to send a Genetlink message!\n"));
+	return 0;
+}
+
+EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
+
+static int acpi_event_genetlink_init(void)
+{
+	int result;
+
+	result = genl_register_family(&acpi_event_genl_family);
+	if (result)
+		return result;
+
+	result = genl_register_mc_group(&acpi_event_genl_family,
+					&acpi_event_mcgrp);
+	if (result)
+		genl_unregister_family(&acpi_event_genl_family);
+
+	return result;
+}
+
+#else
+int acpi_bus_generate_netlink_event(const char *device_class,
+				      const char *bus_id,
+				      u8 type, int data)
+{
+	return 0;
+}
+
+EXPORT_SYMBOL(acpi_bus_generate_netlink_event);
+
+static int acpi_event_genetlink_init(void)
+{
+	return -ENODEV;
+}
+#endif
 
 static int __init acpi_event_init(void)
 {
+#ifdef CONFIG_ACPI_PROC_EVENT
 	struct proc_dir_entry *entry;
+#endif
 	int error = 0;
 
-
 	if (acpi_disabled)
 		return 0;
 
+	/* create genetlink for acpi event */
+	error = acpi_event_genetlink_init();
+	if (error)
+		printk(KERN_WARNING PREFIX
+		       "Failed to create genetlink family for ACPI event\n");
+
+#ifdef CONFIG_ACPI_PROC_EVENT
 	/* 'event' [R] */
 	entry = create_proc_entry("event", S_IRUSR, acpi_root_dir);
 	if (entry)
 		entry->proc_fops = &acpi_system_event_ops;
-	else {
-		error = -ENODEV;
-	}
-	return error;
+	else
+		return -ENODEV;
+#endif
+
+	return 0;
 }
 
-subsys_initcall(acpi_event_init);
+fs_initcall(acpi_event_init);
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c
index 902c287..361ebe6 100644
--- a/drivers/acpi/events/evgpeblk.c
+++ b/drivers/acpi/events/evgpeblk.c
@@ -586,6 +586,10 @@
 	flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
 	if (gpe_xrupt->previous) {
 		gpe_xrupt->previous->next = gpe_xrupt->next;
+	} else {
+		/* No previous, update list head */
+
+		acpi_gbl_gpe_xrupt_list_head = gpe_xrupt->next;
 	}
 
 	if (gpe_xrupt->next) {
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index 400d90f..b1aaa0e 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -284,6 +284,7 @@
 	}
 
 	if (!pci_device_node) {
+		ACPI_FREE(pci_id);
 		return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
 	}
 
@@ -377,7 +378,7 @@
 static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
 {
 	acpi_status status;
-	struct acpi_device_id hid;
+	struct acpica_device_id hid;
 	struct acpi_compatible_id_list *cid;
 	acpi_native_uint i;
 
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index ec655c5..c81f6bd 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -50,10 +50,16 @@
 static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state);
 static int acpi_fan_resume(struct acpi_device *device);
 
+static const struct acpi_device_id fan_device_ids[] = {
+	{"PNP0C0B", 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, fan_device_ids);
+
 static struct acpi_driver acpi_fan_driver = {
 	.name = "fan",
 	.class = ACPI_FAN_CLASS,
-	.ids = "PNP0C0B",
+	.ids = fan_device_ids,
 	.ops = {
 		.add = acpi_fan_add,
 		.remove = acpi_fan_remove,
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 41427a4..4893e25 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -16,7 +16,7 @@
 #if ACPI_GLUE_DEBUG
 #define DBG(x...) printk(PREFIX x)
 #else
-#define DBG(x...)
+#define DBG(x...) do { } while(0)
 #endif
 static LIST_HEAD(bus_type_list);
 static DECLARE_RWSEM(bus_type_sem);
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index 76c525d..cf69c00 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -576,13 +576,10 @@
 		ACPI_EXCEPTION((AE_INFO, status, "During Method _BFS"));
 	}
 
-	status = acpi_evaluate_object(NULL, METHOD_NAME__WAK, &arg_list, NULL);
-	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
-		ACPI_EXCEPTION((AE_INFO, status, "During Method _WAK"));
-	}
-	/* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
-
 	/*
+	 * GPEs must be enabled before _WAK is called as GPEs
+	 * might get fired there
+	 *
 	 * Restore the GPEs:
 	 * 1) Disable/Clear all GPEs
 	 * 2) Enable all runtime GPEs
@@ -591,13 +588,19 @@
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
-	acpi_gbl_system_awake_and_running = TRUE;
-
 	status = acpi_hw_enable_all_runtime_gpes();
 	if (ACPI_FAILURE(status)) {
 		return_ACPI_STATUS(status);
 	}
 
+	status = acpi_evaluate_object(NULL, METHOD_NAME__WAK, &arg_list, NULL);
+	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+		ACPI_EXCEPTION((AE_INFO, status, "During Method _WAK"));
+	}
+	/* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
+
+	acpi_gbl_system_awake_and_running = TRUE;
+
 	/* Enable power button */
 
 	(void)
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index be4f289..f39fbc6 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -440,7 +440,7 @@
 	acpi_status status;
 	struct acpi_namespace_node *node;
 	u32 flags;
-	struct acpi_device_id hid;
+	struct acpica_device_id hid;
 	struct acpi_compatible_id_list *cid;
 	acpi_native_uint i;
 
@@ -540,7 +540,7 @@
  ******************************************************************************/
 
 acpi_status
-acpi_get_devices(char *HID,
+acpi_get_devices(const char *HID,
 		 acpi_walk_callback user_function,
 		 void *context, void **return_value)
 {
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 0c9f15c..ab04d84 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -36,13 +36,11 @@
 ACPI_MODULE_NAME("numa");
 
 static nodemask_t nodes_found_map = NODE_MASK_NONE;
-#define PXM_INVAL	-1
-#define NID_INVAL	-1
 
 /* maps to convert between proximity domain and logical node ID */
-static int pxm_to_node_map[MAX_PXM_DOMAINS]
+static int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS]
 				= { [0 ... MAX_PXM_DOMAINS - 1] = NID_INVAL };
-static int node_to_pxm_map[MAX_NUMNODES]
+static int __cpuinitdata node_to_pxm_map[MAX_NUMNODES]
 				= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
 
 int pxm_to_node(int pxm)
@@ -59,6 +57,12 @@
 	return node_to_pxm_map[node];
 }
 
+void __acpi_map_pxm_to_node(int pxm, int node)
+{
+	pxm_to_node_map[pxm] = node;
+	node_to_pxm_map[node] = pxm;
+}
+
 int acpi_map_pxm_to_node(int pxm)
 {
 	int node = pxm_to_node_map[pxm];
@@ -67,8 +71,7 @@
 		if (nodes_weight(nodes_found_map) >= MAX_NUMNODES)
 			return NID_INVAL;
 		node = first_unset_node(nodes_found_map);
-		pxm_to_node_map[pxm] = node;
-		node_to_pxm_map[node] = pxm;
+		__acpi_map_pxm_to_node(pxm, node);
 		node_set(node, nodes_found_map);
 	}
 
@@ -83,7 +86,8 @@
 	node_clear(node, nodes_found_map);
 }
 
-void __init acpi_table_print_srat_entry(struct acpi_subtable_header * header)
+static void __init
+acpi_table_print_srat_entry(struct acpi_subtable_header *header)
 {
 
 	ACPI_FUNCTION_NAME("acpi_table_print_srat_entry");
@@ -200,7 +204,7 @@
 	return 0;
 }
 
-int __init
+static int __init
 acpi_table_parse_srat(enum acpi_srat_type id,
 		      acpi_table_entry_handler handler, unsigned int max_entries)
 {
@@ -211,14 +215,13 @@
 
 int __init acpi_numa_init(void)
 {
-	int result;
-
 	/* SRAT: Static Resource Affinity Table */
 	if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) {
-		result = acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
-					       acpi_parse_processor_affinity,
-					       NR_CPUS);
-		result = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS);	// IA64 specific
+		acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
+				      acpi_parse_processor_affinity, NR_CPUS);
+		acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY,
+				      acpi_parse_memory_affinity,
+				      NR_NODE_MEMBLKS);
 	}
 
 	/* SLIT: System Locality Information Table */
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 2e7ba61..352cf81 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -77,13 +77,7 @@
 #define	OSI_STRING_LENGTH_MAX 64	/* arbitrary */
 static char osi_additional_string[OSI_STRING_LENGTH_MAX];
 
-#define OSI_LINUX_ENABLED
-#ifdef	OSI_LINUX_ENABLED
-int osi_linux = 1;	/* enable _OSI(Linux) by default */
-#else
-int osi_linux;		/* disable _OSI(Linux) by default */
-#endif
-
+static int osi_linux;		/* disable _OSI(Linux) by default */
 
 #ifdef CONFIG_DMI
 static struct __initdata dmi_system_id acpi_osl_dmi_table[];
@@ -1098,7 +1092,7 @@
 acpi_status
 acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache)
 {
-	*cache = kmem_cache_create(name, size, 0, 0, NULL, NULL);
+	*cache = kmem_cache_create(name, size, 0, 0, NULL);
 	if (*cache == NULL)
 		return AE_ERROR;
 	else
@@ -1183,17 +1177,10 @@
 	if (!strcmp("Linux", interface)) {
 		printk(KERN_WARNING PREFIX
 			"System BIOS is requesting _OSI(Linux)\n");
-#ifdef	OSI_LINUX_ENABLED
-		printk(KERN_WARNING PREFIX
-			"Please test with \"acpi_osi=!Linux\"\n"
-			"Please send dmidecode "
-			"to linux-acpi@vger.kernel.org\n");
-#else
 		printk(KERN_WARNING PREFIX
 			"If \"acpi_osi=Linux\" works better,\n"
 			"Please send dmidecode "
 			"to linux-acpi@vger.kernel.org\n");
-#endif
 		if(osi_linux)
 			return AE_OK;
 	}
@@ -1227,36 +1214,14 @@
 }
 
 #ifdef CONFIG_DMI
-#ifdef	OSI_LINUX_ENABLED
-static int dmi_osi_not_linux(struct dmi_system_id *d)
+static int dmi_osi_linux(const struct dmi_system_id *d)
 {
-	printk(KERN_NOTICE "%s detected: requires not _OSI(Linux)\n", d->ident);
-	enable_osi_linux(0);
-	return 0;
-}
-#else
-static int dmi_osi_linux(struct dmi_system_id *d)
-{
-	printk(KERN_NOTICE "%s detected: requires _OSI(Linux)\n", d->ident);
+	printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident);
 	enable_osi_linux(1);
 	return 0;
 }
-#endif
 
 static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
-#ifdef	OSI_LINUX_ENABLED
-	/*
-	 * Boxes that need NOT _OSI(Linux)
-	 */
-	{
-	 .callback = dmi_osi_not_linux,
-	 .ident = "Toshiba Satellite P100",
-	 .matches = {
-		     DMI_MATCH(DMI_BOARD_VENDOR, "TOSHIBA"),
-		     DMI_MATCH(DMI_BOARD_NAME, "Satellite P100"),
-		     },
-	 },
-#else
 	/*
 	 * Boxes that need _OSI(Linux)
 	 */
@@ -1268,7 +1233,6 @@
 		     DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"),
 		     },
 	 },
-#endif
 	{}
 };
 #endif /* CONFIG_DMI */
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index acc5947..c9f526e 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -46,7 +46,6 @@
 #define _COMPONENT		ACPI_PCI_COMPONENT
 ACPI_MODULE_NAME("pci_link");
 #define ACPI_PCI_LINK_CLASS		"pci_irq_routing"
-#define ACPI_PCI_LINK_HID		"PNP0C0F"
 #define ACPI_PCI_LINK_DEVICE_NAME	"PCI Interrupt Link"
 #define ACPI_PCI_LINK_FILE_INFO		"info"
 #define ACPI_PCI_LINK_FILE_STATUS	"state"
@@ -54,10 +53,16 @@
 static int acpi_pci_link_add(struct acpi_device *device);
 static int acpi_pci_link_remove(struct acpi_device *device, int type);
 
+static struct acpi_device_id link_device_ids[] = {
+	{"PNP0C0F", 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, link_device_ids);
+
 static struct acpi_driver acpi_pci_link_driver = {
 	.name = "pci_link",
 	.class = ACPI_PCI_LINK_CLASS,
-	.ids = ACPI_PCI_LINK_HID,
+	.ids = link_device_ids,
 	.ops = {
 		.add = acpi_pci_link_add,
 		.remove = acpi_pci_link_remove,
@@ -733,7 +738,7 @@
 	/* query and set link->irq.active */
 	acpi_pci_link_get_current(link);
 
-	printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device),
+	printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device),
 	       acpi_device_bid(device));
 	for (i = 0; i < link->irq.possible_count; i++) {
 		if (link->irq.active == link->irq.possible[i]) {
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index ad4145a..f14ff1f 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -38,16 +38,21 @@
 #define _COMPONENT		ACPI_PCI_COMPONENT
 ACPI_MODULE_NAME("pci_root");
 #define ACPI_PCI_ROOT_CLASS		"pci_bridge"
-#define ACPI_PCI_ROOT_HID		"PNP0A03"
 #define ACPI_PCI_ROOT_DEVICE_NAME	"PCI Root Bridge"
 static int acpi_pci_root_add(struct acpi_device *device);
 static int acpi_pci_root_remove(struct acpi_device *device, int type);
 static int acpi_pci_root_start(struct acpi_device *device);
 
+static struct acpi_device_id root_device_ids[] = {
+	{"PNP0A03", 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, root_device_ids);
+
 static struct acpi_driver acpi_pci_root_driver = {
 	.name = "pci_root",
 	.class = ACPI_PCI_ROOT_CLASS,
-	.ids = ACPI_PCI_ROOT_HID,
+	.ids = root_device_ids,
 	.ops = {
 		.add = acpi_pci_root_add,
 		.remove = acpi_pci_root_remove,
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 4ffecd1..57b9a29 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -59,10 +59,16 @@
 static int acpi_power_resume(struct acpi_device *device);
 static int acpi_power_open_fs(struct inode *inode, struct file *file);
 
+static struct acpi_device_id power_device_ids[] = {
+	{ACPI_POWER_HID, 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, power_device_ids);
+
 static struct acpi_driver acpi_power_driver = {
 	.name = "power",
 	.class = ACPI_POWER_CLASS,
-	.ids = ACPI_POWER_HID,
+	.ids = power_device_ids,
 	.ops = {
 		.add = acpi_power_add,
 		.remove = acpi_power_remove,
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index e1ca86d..9f11dc2 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -66,6 +66,7 @@
 #define ACPI_PROCESSOR_FILE_LIMIT	"limit"
 #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
 #define ACPI_PROCESSOR_NOTIFY_POWER	0x81
+#define ACPI_PROCESSOR_NOTIFY_THROTTLING	0x82
 
 #define ACPI_PROCESSOR_LIMIT_USER	0
 #define ACPI_PROCESSOR_LIMIT_THERMAL	1
@@ -84,15 +85,25 @@
 static void acpi_processor_notify(acpi_handle handle, u32 event, void *data);
 static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu);
 static int acpi_processor_handle_eject(struct acpi_processor *pr);
+extern int acpi_processor_tstate_has_changed(struct acpi_processor *pr);
+
+
+static const struct acpi_device_id processor_device_ids[] = {
+	{ACPI_PROCESSOR_HID, 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, processor_device_ids);
 
 static struct acpi_driver acpi_processor_driver = {
 	.name = "processor",
 	.class = ACPI_PROCESSOR_CLASS,
-	.ids = ACPI_PROCESSOR_HID,
+	.ids = processor_device_ids,
 	.ops = {
 		.add = acpi_processor_add,
 		.remove = acpi_processor_remove,
 		.start = acpi_processor_start,
+		.suspend = acpi_processor_suspend,
+		.resume = acpi_processor_resume,
 		},
 };
 
@@ -689,13 +700,23 @@
 	switch (event) {
 	case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:
 		acpi_processor_ppc_has_changed(pr);
-		acpi_bus_generate_event(device, event,
+		acpi_bus_generate_proc_event(device, event,
 					pr->performance_platform_limit);
+		acpi_bus_generate_netlink_event(device->pnp.device_class,
+						  device->dev.bus_id, event,
+						  pr->performance_platform_limit);
 		break;
 	case ACPI_PROCESSOR_NOTIFY_POWER:
 		acpi_processor_cst_has_changed(pr);
-		acpi_bus_generate_event(device, event, 0);
+		acpi_bus_generate_proc_event(device, event, 0);
+		acpi_bus_generate_netlink_event(device->pnp.device_class,
+						  device->dev.bus_id, event, 0);
 		break;
+	case ACPI_PROCESSOR_NOTIFY_THROTTLING:
+		acpi_processor_tstate_has_changed(pr);
+		acpi_bus_generate_proc_event(device, event, 0);
+		acpi_bus_generate_netlink_event(device->pnp.device_class,
+						  device->dev.bus_id, event, 0);
 	default:
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Unsupported event [0x%x]\n", event));
@@ -705,6 +726,25 @@
 	return;
 }
 
+static int acpi_cpu_soft_notify(struct notifier_block *nfb,
+		unsigned long action, void *hcpu)
+{
+	unsigned int cpu = (unsigned long)hcpu;
+	struct acpi_processor *pr = processors[cpu];
+
+	if (action == CPU_ONLINE && pr) {
+		acpi_processor_ppc_has_changed(pr);
+		acpi_processor_cst_has_changed(pr);
+		acpi_processor_tstate_has_changed(pr);
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block acpi_cpu_notifier =
+{
+	    .notifier_call = acpi_cpu_soft_notify,
+};
+
 static int acpi_processor_add(struct acpi_device *device)
 {
 	struct acpi_processor *pr = NULL;
@@ -968,6 +1008,7 @@
 			    ACPI_UINT32_MAX,
 			    processor_walk_namespace_cb, &action, NULL);
 #endif
+	register_hotcpu_notifier(&acpi_cpu_notifier);
 }
 
 static
@@ -980,6 +1021,7 @@
 			    ACPI_UINT32_MAX,
 			    processor_walk_namespace_cb, &action, NULL);
 #endif
+	unregister_hotcpu_notifier(&acpi_cpu_notifier);
 }
 
 /*
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 80ffc78..1f6fb38d 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -63,6 +63,7 @@
 ACPI_MODULE_NAME("processor_idle");
 #define ACPI_PROCESSOR_FILE_POWER	"power"
 #define US_TO_PM_TIMER_TICKS(t)		((t * (PM_TIMER_FREQUENCY/1000)) / 1000)
+#define PM_TIMER_TICK_NS		(1000000000ULL/PM_TIMER_FREQUENCY)
 #define C2_OVERHEAD			4	/* 1us (3.579 ticks per us) */
 #define C3_OVERHEAD			4	/* 1us (3.579 ticks per us) */
 static void (*pm_idle_save) (void) __read_mostly;
@@ -91,7 +92,7 @@
  *
  * To skip this limit, boot/load with a large max_cstate limit.
  */
-static int set_max_cstate(struct dmi_system_id *id)
+static int set_max_cstate(const struct dmi_system_id *id)
 {
 	if (max_cstate > ACPI_PROCESSOR_MAX_POWER)
 		return 0;
@@ -275,21 +276,12 @@
 
 static void acpi_propagate_timer_broadcast(struct acpi_processor *pr)
 {
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
 	unsigned long reason;
 
 	reason = pr->power.timer_broadcast_on_state < INT_MAX ?
 		CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF;
 
 	clockevents_notify(reason, &pr->id);
-#else
-	cpumask_t mask = cpumask_of_cpu(pr->id);
-
-	if (pr->power.timer_broadcast_on_state < INT_MAX)
-		on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1);
-	else
-		on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1);
-#endif
 }
 
 /* Power(C) State timer broadcast control */
@@ -297,8 +289,6 @@
 				       struct acpi_processor_cx *cx,
 				       int broadcast)
 {
-#ifdef CONFIG_GENERIC_CLOCKEVENTS
-
 	int state = cx - pr->power.states;
 
 	if (state >= pr->power.timer_broadcast_on_state) {
@@ -308,7 +298,6 @@
 			CLOCK_EVT_NOTIFY_BROADCAST_EXIT;
 		clockevents_notify(reason, &pr->id);
 	}
-#endif
 }
 
 #else
@@ -324,6 +313,23 @@
 
 #endif
 
+/*
+ * Suspend / resume control
+ */
+static int acpi_idle_suspend;
+
+int acpi_processor_suspend(struct acpi_device * device, pm_message_t state)
+{
+	acpi_idle_suspend = 1;
+	return 0;
+}
+
+int acpi_processor_resume(struct acpi_device * device)
+{
+	acpi_idle_suspend = 0;
+	return 0;
+}
+
 static void acpi_processor_idle(void)
 {
 	struct acpi_processor *pr = NULL;
@@ -354,7 +360,7 @@
 	}
 
 	cx = pr->power.state;
-	if (!cx) {
+	if (!cx || acpi_idle_suspend) {
 		if (pm_idle_save)
 			pm_idle_save();
 		else
@@ -462,6 +468,9 @@
 		 * TBD: Can't get time duration while in C1, as resumes
 		 *      go to an ISR rather than here.  Need to instrument
 		 *      base interrupt handler.
+		 *
+		 * Note: the TSC better not stop in C1, sched_clock() will
+		 *       skew otherwise.
 		 */
 		sleep_ticks = 0xFFFFFFFF;
 		break;
@@ -469,28 +478,45 @@
 	case ACPI_STATE_C2:
 		/* Get start time (ticks) */
 		t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+		/* Tell the scheduler that we are going deep-idle: */
+		sched_clock_idle_sleep_event();
 		/* Invoke C2 */
 		acpi_state_timer_broadcast(pr, cx, 1);
 		acpi_cstate_enter(cx);
 		/* Get end time (ticks) */
 		t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
 
-#ifdef CONFIG_GENERIC_TIME
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
 		/* TSC halts in C2, so notify users */
 		mark_tsc_unstable("possible TSC halt in C2");
 #endif
+		/* Compute time (ticks) that we were actually asleep */
+		sleep_ticks = ticks_elapsed(t1, t2);
+
+		/* Tell the scheduler how much we idled: */
+		sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
+
 		/* Re-enable interrupts */
 		local_irq_enable();
+		/* Do not account our idle-switching overhead: */
+		sleep_ticks -= cx->latency_ticks + C2_OVERHEAD;
+
 		current_thread_info()->status |= TS_POLLING;
-		/* Compute time (ticks) that we were actually asleep */
-		sleep_ticks =
-		    ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD;
 		acpi_state_timer_broadcast(pr, cx, 0);
 		break;
 
 	case ACPI_STATE_C3:
-
-		if (pr->flags.bm_check) {
+		/*
+		 * disable bus master
+		 * bm_check implies we need ARB_DIS
+		 * !bm_check implies we need cache flush
+		 * bm_control implies whether we can do ARB_DIS
+		 *
+		 * That leaves a case where bm_check is set and bm_control is
+		 * not set. In that case we cannot do much, we enter C3
+		 * without doing anything.
+		 */
+		if (pr->flags.bm_check && pr->flags.bm_control) {
 			if (atomic_inc_return(&c3_cpu_count) ==
 			    num_online_cpus()) {
 				/*
@@ -499,7 +525,7 @@
 				 */
 				acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
 			}
-		} else {
+		} else if (!pr->flags.bm_check) {
 			/* SMP with no shared cache... Invalidate cache  */
 			ACPI_FLUSH_CPU_CACHE();
 		}
@@ -508,25 +534,32 @@
 		t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
 		/* Invoke C3 */
 		acpi_state_timer_broadcast(pr, cx, 1);
+		/* Tell the scheduler that we are going deep-idle: */
+		sched_clock_idle_sleep_event();
 		acpi_cstate_enter(cx);
 		/* Get end time (ticks) */
 		t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
-		if (pr->flags.bm_check) {
+		if (pr->flags.bm_check && pr->flags.bm_control) {
 			/* Enable bus master arbitration */
 			atomic_dec(&c3_cpu_count);
 			acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
 		}
 
-#ifdef CONFIG_GENERIC_TIME
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
 		/* TSC halts in C3, so notify users */
 		mark_tsc_unstable("TSC halts in C3");
 #endif
+		/* Compute time (ticks) that we were actually asleep */
+		sleep_ticks = ticks_elapsed(t1, t2);
+		/* Tell the scheduler how much we idled: */
+		sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
+
 		/* Re-enable interrupts */
 		local_irq_enable();
+		/* Do not account our idle-switching overhead: */
+		sleep_ticks -= cx->latency_ticks + C3_OVERHEAD;
+
 		current_thread_info()->status |= TS_POLLING;
-		/* Compute time (ticks) that we were actually asleep */
-		sleep_ticks =
-		    ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD;
 		acpi_state_timer_broadcast(pr, cx, 0);
 		break;
 
@@ -959,11 +992,17 @@
 	}
 
 	if (pr->flags.bm_check) {
-		/* bus mastering control is necessary */
 		if (!pr->flags.bm_control) {
-			ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-					  "C3 support requires bus mastering control\n"));
-			return;
+			if (pr->flags.has_cst != 1) {
+				/* bus mastering control is necessary */
+				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+					"C3 support requires BM control\n"));
+				return;
+			} else {
+				/* Here we enter C3 without bus mastering */
+				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+					"C3 support without BM control\n"));
+			}
 		}
 	} else {
 		/*
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index c4efc0c..463b024 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -539,7 +539,7 @@
 }
 
 int acpi_processor_preregister_performance(
-		struct acpi_processor_performance **performance)
+		struct acpi_processor_performance *performance)
 {
 	int count, count_target;
 	int retval = 0;
@@ -567,12 +567,12 @@
 			continue;
 		}
 
-		if (!performance || !performance[i]) {
+		if (!performance || !percpu_ptr(performance, i)) {
 			retval = -EINVAL;
 			continue;
 		}
 
-		pr->performance = performance[i];
+		pr->performance = percpu_ptr(performance, i);
 		cpu_set(i, pr->performance->shared_cpu_map);
 		if (acpi_processor_get_psd(pr)) {
 			retval = -EINVAL;
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index b334860..0b8204e 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -44,17 +44,251 @@
 #define _COMPONENT              ACPI_PROCESSOR_COMPONENT
 ACPI_MODULE_NAME("processor_throttling");
 
+static int acpi_processor_get_throttling(struct acpi_processor *pr);
+int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
+
+/*
+ * _TPC - Throttling Present Capabilities
+ */
+static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
+{
+	acpi_status status = 0;
+	unsigned long tpc = 0;
+
+	if (!pr)
+		return -EINVAL;
+	status = acpi_evaluate_integer(pr->handle, "_TPC", NULL, &tpc);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND) {
+			ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TPC"));
+		}
+		return -ENODEV;
+	}
+	pr->throttling_platform_limit = (int)tpc;
+	return 0;
+}
+
+int acpi_processor_tstate_has_changed(struct acpi_processor *pr)
+{
+	return acpi_processor_get_platform_limit(pr);
+}
+
+/*
+ * _PTC - Processor Throttling Control (and status) register location
+ */
+static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
+{
+	int result = 0;
+	acpi_status status = 0;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	union acpi_object *ptc = NULL;
+	union acpi_object obj = { 0 };
+
+	status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND) {
+			ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTC"));
+		}
+		return -ENODEV;
+	}
+
+	ptc = (union acpi_object *)buffer.pointer;
+	if (!ptc || (ptc->type != ACPI_TYPE_PACKAGE)
+	    || (ptc->package.count != 2)) {
+		printk(KERN_ERR PREFIX "Invalid _PTC data\n");
+		result = -EFAULT;
+		goto end;
+	}
+
+	/*
+	 * control_register
+	 */
+
+	obj = ptc->package.elements[0];
+
+	if ((obj.type != ACPI_TYPE_BUFFER)
+	    || (obj.buffer.length < sizeof(struct acpi_ptc_register))
+	    || (obj.buffer.pointer == NULL)) {
+		printk(KERN_ERR PREFIX
+		       "Invalid _PTC data (control_register)\n");
+		result = -EFAULT;
+		goto end;
+	}
+	memcpy(&pr->throttling.control_register, obj.buffer.pointer,
+	       sizeof(struct acpi_ptc_register));
+
+	/*
+	 * status_register
+	 */
+
+	obj = ptc->package.elements[1];
+
+	if ((obj.type != ACPI_TYPE_BUFFER)
+	    || (obj.buffer.length < sizeof(struct acpi_ptc_register))
+	    || (obj.buffer.pointer == NULL)) {
+		printk(KERN_ERR PREFIX "Invalid _PTC data (status_register)\n");
+		result = -EFAULT;
+		goto end;
+	}
+
+	memcpy(&pr->throttling.status_register, obj.buffer.pointer,
+	       sizeof(struct acpi_ptc_register));
+
+      end:
+	kfree(buffer.pointer);
+
+	return result;
+}
+
+/*
+ * _TSS - Throttling Supported States
+ */
+static int acpi_processor_get_throttling_states(struct acpi_processor *pr)
+{
+	int result = 0;
+	acpi_status status = AE_OK;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
+	struct acpi_buffer state = { 0, NULL };
+	union acpi_object *tss = NULL;
+	int i;
+
+	status = acpi_evaluate_object(pr->handle, "_TSS", NULL, &buffer);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND) {
+			ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TSS"));
+		}
+		return -ENODEV;
+	}
+
+	tss = buffer.pointer;
+	if (!tss || (tss->type != ACPI_TYPE_PACKAGE)) {
+		printk(KERN_ERR PREFIX "Invalid _TSS data\n");
+		result = -EFAULT;
+		goto end;
+	}
+
+	ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d throttling states\n",
+			  tss->package.count));
+
+	pr->throttling.state_count = tss->package.count;
+	pr->throttling.states_tss =
+	    kmalloc(sizeof(struct acpi_processor_tx_tss) * tss->package.count,
+		    GFP_KERNEL);
+	if (!pr->throttling.states_tss) {
+		result = -ENOMEM;
+		goto end;
+	}
+
+	for (i = 0; i < pr->throttling.state_count; i++) {
+
+		struct acpi_processor_tx_tss *tx =
+		    (struct acpi_processor_tx_tss *)&(pr->throttling.
+						      states_tss[i]);
+
+		state.length = sizeof(struct acpi_processor_tx_tss);
+		state.pointer = tx;
+
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i));
+
+		status = acpi_extract_package(&(tss->package.elements[i]),
+					      &format, &state);
+		if (ACPI_FAILURE(status)) {
+			ACPI_EXCEPTION((AE_INFO, status, "Invalid _TSS data"));
+			result = -EFAULT;
+			kfree(pr->throttling.states_tss);
+			goto end;
+		}
+
+		if (!tx->freqpercentage) {
+			printk(KERN_ERR PREFIX
+			       "Invalid _TSS data: freq is zero\n");
+			result = -EFAULT;
+			kfree(pr->throttling.states_tss);
+			goto end;
+		}
+	}
+
+      end:
+	kfree(buffer.pointer);
+
+	return result;
+}
+
+/*
+ * _TSD - T-State Dependencies
+ */
+static int acpi_processor_get_tsd(struct acpi_processor *pr)
+{
+	int result = 0;
+	acpi_status status = AE_OK;
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
+	struct acpi_buffer state = { 0, NULL };
+	union acpi_object *tsd = NULL;
+	struct acpi_tsd_package *pdomain;
+
+	status = acpi_evaluate_object(pr->handle, "_TSD", NULL, &buffer);
+	if (ACPI_FAILURE(status)) {
+		if (status != AE_NOT_FOUND) {
+			ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TSD"));
+		}
+		return -ENODEV;
+	}
+
+	tsd = buffer.pointer;
+	if (!tsd || (tsd->type != ACPI_TYPE_PACKAGE)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+	if (tsd->package.count != 1) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+	pdomain = &(pr->throttling.domain_info);
+
+	state.length = sizeof(struct acpi_tsd_package);
+	state.pointer = pdomain;
+
+	status = acpi_extract_package(&(tsd->package.elements[0]),
+				      &format, &state);
+	if (ACPI_FAILURE(status)) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+	if (pdomain->num_entries != ACPI_TSD_REV0_ENTRIES) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:num_entries\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+	if (pdomain->revision != ACPI_TSD_REV0_REVISION) {
+		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:revision\n"));
+		result = -EFAULT;
+		goto end;
+	}
+
+      end:
+	kfree(buffer.pointer);
+	return result;
+}
+
 /* --------------------------------------------------------------------------
                               Throttling Control
    -------------------------------------------------------------------------- */
-static int acpi_processor_get_throttling(struct acpi_processor *pr)
+static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
 {
 	int state = 0;
 	u32 value = 0;
 	u32 duty_mask = 0;
 	u32 duty_value = 0;
 
-
 	if (!pr)
 		return -EINVAL;
 
@@ -94,13 +328,115 @@
 	return 0;
 }
 
-int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
+static int acpi_read_throttling_status(struct acpi_processor_throttling
+				       *throttling)
+{
+	int value = -1;
+	switch (throttling->status_register.space_id) {
+	case ACPI_ADR_SPACE_SYSTEM_IO:
+		acpi_os_read_port((acpi_io_address) throttling->status_register.
+				  address, &value,
+				  (u32) throttling->status_register.bit_width *
+				  8);
+		break;
+	case ACPI_ADR_SPACE_FIXED_HARDWARE:
+		printk(KERN_ERR PREFIX
+		       "HARDWARE addr space,NOT supported yet\n");
+		break;
+	default:
+		printk(KERN_ERR PREFIX "Unknown addr space %d\n",
+		       (u32) (throttling->status_register.space_id));
+	}
+	return value;
+}
+
+static int acpi_write_throttling_state(struct acpi_processor_throttling
+				       *throttling, int value)
+{
+	int ret = -1;
+
+	switch (throttling->control_register.space_id) {
+	case ACPI_ADR_SPACE_SYSTEM_IO:
+		acpi_os_write_port((acpi_io_address) throttling->
+				   control_register.address, value,
+				   (u32) throttling->control_register.
+				   bit_width * 8);
+		ret = 0;
+		break;
+	case ACPI_ADR_SPACE_FIXED_HARDWARE:
+		printk(KERN_ERR PREFIX
+		       "HARDWARE addr space,NOT supported yet\n");
+		break;
+	default:
+		printk(KERN_ERR PREFIX "Unknown addr space %d\n",
+		       (u32) (throttling->control_register.space_id));
+	}
+	return ret;
+}
+
+static int acpi_get_throttling_state(struct acpi_processor *pr, int value)
+{
+	int i;
+
+	for (i = 0; i < pr->throttling.state_count; i++) {
+		struct acpi_processor_tx_tss *tx =
+		    (struct acpi_processor_tx_tss *)&(pr->throttling.
+						      states_tss[i]);
+		if (tx->control == value)
+			break;
+	}
+	if (i > pr->throttling.state_count)
+		i = -1;
+	return i;
+}
+
+static int acpi_get_throttling_value(struct acpi_processor *pr, int state)
+{
+	int value = -1;
+	if (state >= 0 && state <= pr->throttling.state_count) {
+		struct acpi_processor_tx_tss *tx =
+		    (struct acpi_processor_tx_tss *)&(pr->throttling.
+						      states_tss[state]);
+		value = tx->control;
+	}
+	return value;
+}
+
+static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
+{
+	int state = 0;
+	u32 value = 0;
+
+	if (!pr)
+		return -EINVAL;
+
+	if (!pr->flags.throttling)
+		return -ENODEV;
+
+	pr->throttling.state = 0;
+	local_irq_disable();
+	value = acpi_read_throttling_status(&pr->throttling);
+	if (value >= 0) {
+		state = acpi_get_throttling_state(pr, value);
+		pr->throttling.state = state;
+	}
+	local_irq_enable();
+
+	return 0;
+}
+
+static int acpi_processor_get_throttling(struct acpi_processor *pr)
+{
+	return pr->throttling.acpi_processor_get_throttling(pr);
+}
+
+static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
+					      int state)
 {
 	u32 value = 0;
 	u32 duty_mask = 0;
 	u32 duty_value = 0;
 
-
 	if (!pr)
 		return -EINVAL;
 
@@ -113,6 +449,8 @@
 	if (state == pr->throttling.state)
 		return 0;
 
+	if (state < pr->throttling_platform_limit)
+		return -EPERM;
 	/*
 	 * Calculate the duty_value and duty_mask.
 	 */
@@ -165,13 +503,49 @@
 	return 0;
 }
 
+static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
+					     int state)
+{
+	u32 value = 0;
+
+	if (!pr)
+		return -EINVAL;
+
+	if ((state < 0) || (state > (pr->throttling.state_count - 1)))
+		return -EINVAL;
+
+	if (!pr->flags.throttling)
+		return -ENODEV;
+
+	if (state == pr->throttling.state)
+		return 0;
+
+	if (state < pr->throttling_platform_limit)
+		return -EPERM;
+
+	local_irq_disable();
+
+	value = acpi_get_throttling_value(pr, state);
+	if (value >= 0) {
+		acpi_write_throttling_state(&pr->throttling, value);
+		pr->throttling.state = state;
+	}
+	local_irq_enable();
+
+	return 0;
+}
+
+int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
+{
+	return pr->throttling.acpi_processor_set_throttling(pr, state);
+}
+
 int acpi_processor_get_throttling_info(struct acpi_processor *pr)
 {
 	int result = 0;
 	int step = 0;
 	int i = 0;
 
-
 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 			  "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
 			  pr->throttling.address,
@@ -181,7 +555,26 @@
 	if (!pr)
 		return -EINVAL;
 
-	/* TBD: Support ACPI 2.0 objects */
+	/*
+	 * Evaluate _PTC, _TSS and _TPC
+	 * They must all be present or none of them can be used.
+	 */
+	if (acpi_processor_get_throttling_control(pr) ||
+		acpi_processor_get_throttling_states(pr) ||
+		acpi_processor_get_platform_limit(pr))
+	{
+		pr->throttling.acpi_processor_get_throttling =
+		    &acpi_processor_get_throttling_fadt;
+		pr->throttling.acpi_processor_set_throttling =
+		    &acpi_processor_set_throttling_fadt;
+	} else {
+		pr->throttling.acpi_processor_get_throttling =
+		    &acpi_processor_get_throttling_ptc;
+		pr->throttling.acpi_processor_set_throttling =
+		    &acpi_processor_set_throttling_ptc;
+	}
+
+	acpi_processor_get_tsd(pr);
 
 	if (!pr->throttling.address) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n"));
@@ -262,7 +655,6 @@
 	int i = 0;
 	int result = 0;
 
-
 	if (!pr)
 		goto end;
 
@@ -280,15 +672,27 @@
 	}
 
 	seq_printf(seq, "state count:             %d\n"
-		   "active state:            T%d\n",
-		   pr->throttling.state_count, pr->throttling.state);
+		   "active state:            T%d\n"
+		   "state available: T%d to T%d\n",
+		   pr->throttling.state_count, pr->throttling.state,
+		   pr->throttling_platform_limit,
+		   pr->throttling.state_count - 1);
 
 	seq_puts(seq, "states:\n");
-	for (i = 0; i < pr->throttling.state_count; i++)
-		seq_printf(seq, "   %cT%d:                  %02d%%\n",
-			   (i == pr->throttling.state ? '*' : ' '), i,
-			   (pr->throttling.states[i].performance ? pr->
-			    throttling.states[i].performance / 10 : 0));
+	if (pr->throttling.acpi_processor_get_throttling ==
+			acpi_processor_get_throttling_fadt) {
+		for (i = 0; i < pr->throttling.state_count; i++)
+			seq_printf(seq, "   %cT%d:                  %02d%%\n",
+				   (i == pr->throttling.state ? '*' : ' '), i,
+				   (pr->throttling.states[i].performance ? pr->
+				    throttling.states[i].performance / 10 : 0));
+	} else {
+		for (i = 0; i < pr->throttling.state_count; i++)
+			seq_printf(seq, "   %cT%d:                  %02d%%\n",
+				   (i == pr->throttling.state ? '*' : ' '), i,
+				   (int)pr->throttling.states_tss[i].
+				   freqpercentage);
+	}
 
       end:
 	return 0;
@@ -301,7 +705,7 @@
 			   PDE(inode)->data);
 }
 
-static ssize_t acpi_processor_write_throttling(struct file * file,
+static ssize_t acpi_processor_write_throttling(struct file *file,
 					       const char __user * buffer,
 					       size_t count, loff_t * data)
 {
@@ -310,7 +714,6 @@
 	struct acpi_processor *pr = m->private;
 	char state_string[12] = { '\0' };
 
-
 	if (!pr || (count > sizeof(state_string) - 1))
 		return -EINVAL;
 
diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c
index f63813a..4c3fd4c 100644
--- a/drivers/acpi/resources/rsxface.c
+++ b/drivers/acpi/resources/rsxface.c
@@ -474,8 +474,6 @@
 	return (AE_CTRL_TERMINATE);
 }
 
-ACPI_EXPORT_SYMBOL(acpi_rs_match_vendor_resource)
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_walk_resources
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index c1bae10..a578986 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -38,7 +38,6 @@
 #define ACPI_SBS_CLASS			"sbs"
 #define ACPI_AC_CLASS			"ac_adapter"
 #define ACPI_BATTERY_CLASS		"battery"
-#define ACPI_SBS_HID			"ACPI0002"
 #define ACPI_SBS_DEVICE_NAME		"Smart Battery System"
 #define ACPI_SBS_FILE_INFO		"info"
 #define ACPI_SBS_FILE_STATE		"state"
@@ -124,10 +123,17 @@
 static int acpi_sbs_remove(struct acpi_device *device, int type);
 static int acpi_sbs_resume(struct acpi_device *device);
 
+static const struct acpi_device_id sbs_device_ids[] = {
+	{"ACPI0001", 0},
+	{"ACPI0005", 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, sbs_device_ids);
+
 static struct acpi_driver acpi_sbs_driver = {
 	.name = "sbs",
 	.class = ACPI_SBS_CLASS,
-	.ids = ACPI_SBS_HID,
+	.ids = sbs_device_ids,
 	.ops = {
 		.add = acpi_sbs_add,
 		.remove = acpi_sbs_remove,
@@ -176,10 +182,8 @@
 };
 
 struct acpi_sbs {
-	acpi_handle handle;
 	int base;
 	struct acpi_device *device;
-	struct acpi_ec_smbus *smbus;
 	struct mutex mutex;
 	int sbsm_present;
 	int sbsm_batteries_supported;
@@ -436,11 +440,12 @@
 	strcpy(acpi_device_bid(device), bid);
 	strcpy(acpi_device_class(device), class);
 
-	result = acpi_bus_generate_event(device, event, state);
+	result = acpi_bus_generate_proc_event(device, event, state);
 
 	strcpy(acpi_device_bid(device), bid_saved);
 	strcpy(acpi_device_class(device), class_saved);
 
+	acpi_bus_generate_netlink_event(class, bid, event, state);
 	return result;
 }
 
@@ -511,7 +516,7 @@
 				"acpi_sbs_read_word() failed"));
 		goto end;
 	}
-
+	sbs->sbsm_present = 1;
 	sbs->sbsm_batteries_supported = battery_system_info & 0x000f;
 
       end:
@@ -1411,7 +1416,7 @@
 	char dir_name[32];
 	int do_battery_init = 0, do_ac_init = 0;
 	int old_remaining_capacity = 0;
-	int update_ac = 1, update_battery = 1;
+	int update_battery = 1;
 	int up_tm = update_time;
 
 	if (sbs_zombie(sbs)) {
@@ -1431,10 +1436,6 @@
 
 	sbs->run_cnt++;
 
-	if (!update_ac && !update_battery) {
-		goto end;
-	}
-
 	old_ac_present = sbs->ac.ac_present;
 
 	result = acpi_ac_get_present(sbs);
@@ -1630,13 +1631,12 @@
 {
 	struct acpi_sbs *sbs = NULL;
 	int result = 0, remove_result = 0;
-	unsigned long sbs_obj;
 	int id;
 	acpi_status status = AE_OK;
 	unsigned long val;
 
 	status =
-	    acpi_evaluate_integer(device->parent->handle, "_EC", NULL, &val);
+	    acpi_evaluate_integer(device->handle, "_EC", NULL, &val);
 	if (ACPI_FAILURE(status)) {
 		ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC"));
 		return -EIO;
@@ -1653,7 +1653,7 @@
 
 	sbs_mutex_lock(sbs);
 
-	sbs->base = (val & 0xff00ull) >> 8;
+	sbs->base = 0xff & (val >> 8);
 	sbs->device = device;
 
 	strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
@@ -1665,24 +1665,10 @@
 		ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_ac_add() failed"));
 		goto end;
 	}
-	status = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);
-	if (status) {
-		ACPI_EXCEPTION((AE_INFO, status,
-				"acpi_evaluate_integer() failed"));
-		result = -EIO;
-		goto end;
-	}
-	if (sbs_obj > 0) {
-		result = acpi_sbsm_get_info(sbs);
-		if (result) {
-			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
-					"acpi_sbsm_get_info() failed"));
-			goto end;
-		}
-		sbs->sbsm_present = 1;
-	}
 
-	if (sbs->sbsm_present == 0) {
+	acpi_sbsm_get_info(sbs);
+
+	if (!sbs->sbsm_present) {
 		result = acpi_battery_add(sbs, 0);
 		if (result) {
 			ACPI_EXCEPTION((AE_INFO, AE_ERROR,
@@ -1702,8 +1688,6 @@
 		}
 	}
 
-	sbs->handle = device->handle;
-
 	init_timer(&sbs->update_timer);
 	result = acpi_check_update_proc(sbs);
 	if (result)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 6b3b8a5..5b4d462 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -16,7 +16,7 @@
 extern struct acpi_device *acpi_root;
 
 #define ACPI_BUS_CLASS			"system_bus"
-#define ACPI_BUS_HID			"ACPI_BUS"
+#define ACPI_BUS_HID			"LNXSYBUS"
 #define ACPI_BUS_DEVICE_NAME		"System Bus"
 
 static LIST_HEAD(acpi_device_list);
@@ -29,6 +29,63 @@
 	unsigned int instance_no;
 	struct list_head node;
 };
+
+/*
+ * Creates hid/cid(s) string needed for modalias and uevent
+ * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
+ * char *modalias: "acpi:IBM0001:ACPI0001"
+*/
+static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
+			   int size)
+{
+	int len;
+
+	if (!acpi_dev->flags.hardware_id)
+		return -ENODEV;
+
+	len = snprintf(modalias, size, "acpi:%s:",
+		       acpi_dev->pnp.hardware_id);
+	if (len < 0 || len >= size)
+		return -EINVAL;
+	size -= len;
+
+	if (acpi_dev->flags.compatible_ids) {
+		struct acpi_compatible_id_list *cid_list;
+		int i;
+		int count;
+
+		cid_list = acpi_dev->pnp.cid_list;
+		for (i = 0; i < cid_list->count; i++) {
+			count = snprintf(&modalias[len], size, "%s:",
+					 cid_list->id[i].value);
+			if (count < 0 || count >= size) {
+				printk(KERN_ERR "acpi: %s cid[%i] exceeds event buffer size",
+				       acpi_dev->pnp.device_name, i);
+				break;
+			}
+			len += count;
+			size -= count;
+		}
+	}
+
+	modalias[len] = '\0';
+	return len;
+}
+
+static ssize_t
+acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) {
+	struct acpi_device *acpi_dev = to_acpi_device(dev);
+	int len;
+
+	/* Device has no HID and no CID or string is >1024 */
+	len = create_modalias(acpi_dev, buf, 1024);
+	if (len <= 0)
+		return 0;
+	buf[len++] = '\n';
+	return len;
+}
+static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
+
 static int acpi_eject_operation(acpi_handle handle, int lockable)
 {
 	struct acpi_object_list arg_list;
@@ -154,6 +211,12 @@
 			goto end;
 	}
 
+	if (dev->flags.hardware_id || dev->flags.compatible_ids){
+		result = device_create_file(&dev->dev, &dev_attr_modalias);
+		if(result)
+			goto end;
+	}
+
         /*
          * If device has _EJ0, 'eject' file is created that is used to trigger
          * hot-removal function from userland.
@@ -178,6 +241,9 @@
 	if (ACPI_SUCCESS(status))
 		device_remove_file(&dev->dev, &dev_attr_eject);
 
+	if (dev->flags.hardware_id || dev->flags.compatible_ids)
+		device_remove_file(&dev->dev, &dev_attr_modalias);
+
 	if(dev->flags.hardware_id)
 		device_remove_file(&dev->dev, &dev_attr_hid);
 	if(dev->handle)
@@ -186,6 +252,37 @@
 /* --------------------------------------------------------------------------
 			ACPI Bus operations
    -------------------------------------------------------------------------- */
+
+int acpi_match_device_ids(struct acpi_device *device,
+			  const struct acpi_device_id *ids)
+{
+	const struct acpi_device_id *id;
+
+	if (device->flags.hardware_id) {
+		for (id = ids; id->id[0]; id++) {
+			if (!strcmp((char*)id->id, device->pnp.hardware_id))
+				return 0;
+		}
+	}
+
+	if (device->flags.compatible_ids) {
+		struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
+		int i;
+
+		for (id = ids; id->id[0]; id++) {
+			/* compare multiple _CID entries against driver ids */
+			for (i = 0; i < cid_list->count; i++) {
+				if (!strcmp((char*)id->id,
+					    cid_list->id[i].value))
+					return 0;
+			}
+		}
+	}
+
+	return -ENOENT;
+}
+EXPORT_SYMBOL(acpi_match_device_ids);
+
 static void acpi_device_release(struct device *dev)
 {
 	struct acpi_device *acpi_dev = to_acpi_device(dev);
@@ -219,37 +316,21 @@
 	struct acpi_device *acpi_dev = to_acpi_device(dev);
 	struct acpi_driver *acpi_drv = to_acpi_driver(drv);
 
-	return !acpi_match_ids(acpi_dev, acpi_drv->ids);
+	return !acpi_match_device_ids(acpi_dev, acpi_drv->ids);
 }
 
-static int acpi_device_uevent(struct device *dev, char **envp, int num_envp,
-	char *buffer, int buffer_size)
+static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct acpi_device *acpi_dev = to_acpi_device(dev);
-	int i = 0, length = 0, ret = 0;
+	int len;
 
-	if (acpi_dev->flags.hardware_id)
-		ret = add_uevent_var(envp, num_envp, &i,
-			buffer, buffer_size, &length,
-			"HWID=%s", acpi_dev->pnp.hardware_id);
-	if (ret)
+	if (add_uevent_var(env, "MODALIAS="))
 		return -ENOMEM;
-	if (acpi_dev->flags.compatible_ids) {
-		int j;
-		struct acpi_compatible_id_list *cid_list;
-
-		cid_list = acpi_dev->pnp.cid_list;
-
-		for (j = 0; j < cid_list->count; j++) {
-			ret = add_uevent_var(envp, num_envp, &i, buffer,
-				buffer_size, &length, "COMPTID=%s",
-				cid_list->id[j].value);
-			if (ret)
-				return -ENOMEM;
-		}
-	}
-
-	envp[i] = NULL;
+	len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
+			      sizeof(env->buf) - env->buflen);
+	if (len >= (sizeof(env->buf) - env->buflen))
+		return -ENOMEM;
+	env->buflen += len;
 	return 0;
 }
 
@@ -543,25 +624,6 @@
 	return;
 }
 
-int acpi_match_ids(struct acpi_device *device, char *ids)
-{
-	if (device->flags.hardware_id)
-		if (strstr(ids, device->pnp.hardware_id))
-			return 0;
-
-	if (device->flags.compatible_ids) {
-		struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
-		int i;
-
-		/* compare multiple _CID entries against driver ids */
-		for (i = 0; i < cid_list->count; i++) {
-			if (strstr(ids, cid_list->id[i].value))
-				return 0;
-		}
-	}
-	return -ENOENT;
-}
-
 static int acpi_bus_get_perf_flags(struct acpi_device *device)
 {
 	device->performance.state = ACPI_STATE_UNKNOWN;
@@ -624,6 +686,13 @@
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 	union acpi_object *package = NULL;
 
+	struct acpi_device_id button_device_ids[] = {
+		{"PNP0C0D", 0},
+		{"PNP0C0C", 0},
+		{"PNP0C0E", 0},
+		{"", 0},
+	};
+
 
 	/* _PRW */
 	status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
@@ -643,7 +712,7 @@
 
 	device->wakeup.flags.valid = 1;
 	/* Power button, Lid switch always enable wakeup */
-	if (!acpi_match_ids(device, "PNP0C0D,PNP0C0C,PNP0C0E"))
+	if (!acpi_match_device_ids(device, button_device_ids))
 		device->wakeup.flags.run_wake = 1;
 
       end:
diff --git a/drivers/acpi/sleep/Makefile b/drivers/acpi/sleep/Makefile
index d6c0177..f1fb888 100644
--- a/drivers/acpi/sleep/Makefile
+++ b/drivers/acpi/sleep/Makefile
@@ -1,5 +1,5 @@
-obj-y					:= poweroff.o wakeup.o
-obj-$(CONFIG_ACPI_SLEEP)		+= main.o
-obj-$(CONFIG_ACPI_SLEEP_PROC_FS)	+= proc.o
+obj-y					:= wakeup.o
+obj-y					+= main.o
+obj-$(CONFIG_ACPI_SLEEP)		+= proc.o
 
 EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index bc7e16e..5055acf 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -15,12 +15,41 @@
 #include <linux/dmi.h>
 #include <linux/device.h>
 #include <linux/suspend.h>
+
+#include <asm/io.h>
+
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 #include "sleep.h"
 
 u8 sleep_states[ACPI_S_STATE_COUNT];
 
+#ifdef CONFIG_PM_SLEEP
+static u32 acpi_target_sleep_state = ACPI_STATE_S0;
+#endif
+
+int acpi_sleep_prepare(u32 acpi_state)
+{
+#ifdef CONFIG_ACPI_SLEEP
+	/* do we have a wakeup address for S2 and S3? */
+	if (acpi_state == ACPI_STATE_S3) {
+		if (!acpi_wakeup_address) {
+			return -EFAULT;
+		}
+		acpi_set_firmware_waking_vector((acpi_physical_address)
+						virt_to_phys((void *)
+							     acpi_wakeup_address));
+
+	}
+	ACPI_FLUSH_CPU_CACHE();
+	acpi_enable_wakeup_device_prep(acpi_state);
+#endif
+	acpi_gpe_sleep_prepare(acpi_state);
+	acpi_enter_sleep_state_prep(acpi_state);
+	return 0;
+}
+
+#ifdef CONFIG_SUSPEND
 static struct pm_ops acpi_pm_ops;
 
 extern void do_suspend_lowlevel(void);
@@ -35,34 +64,49 @@
 static int init_8259A_after_S1;
 
 /**
- *	acpi_pm_prepare - Do preliminary suspend work.
- *	@pm_state:		suspend state we're entering.
- *
- *	Make sure we support the state. If we do, and we need it, set the
- *	firmware waking vector and do arch-specific nastiness to get the 
- *	wakeup code to the waking vector. 
+ *	acpi_pm_set_target - Set the target system sleep state to the state
+ *		associated with given @pm_state, if supported.
  */
 
-extern int acpi_sleep_prepare(u32 acpi_state);
-extern void acpi_power_off(void);
+static int acpi_pm_set_target(suspend_state_t pm_state)
+{
+	u32 acpi_state = acpi_suspend_states[pm_state];
+	int error = 0;
+
+	if (sleep_states[acpi_state]) {
+		acpi_target_sleep_state = acpi_state;
+	} else {
+		printk(KERN_ERR "ACPI does not support this state: %d\n",
+			pm_state);
+		error = -ENOSYS;
+	}
+	return error;
+}
+
+/**
+ *	acpi_pm_prepare - Do preliminary suspend work.
+ *	@pm_state: ignored
+ *
+ *	If necessary, set the firmware waking vector and do arch-specific
+ *	nastiness to get the wakeup code to the waking vector.
+ */
 
 static int acpi_pm_prepare(suspend_state_t pm_state)
 {
-	u32 acpi_state = acpi_suspend_states[pm_state];
+	int error = acpi_sleep_prepare(acpi_target_sleep_state);
 
-	if (!sleep_states[acpi_state]) {
-		printk("acpi_pm_prepare does not support %d \n", pm_state);
-		return -EPERM;
-	}
-	return acpi_sleep_prepare(acpi_state);
+	if (error)
+		acpi_target_sleep_state = ACPI_STATE_S0;
+
+	return error;
 }
 
 /**
  *	acpi_pm_enter - Actually enter a sleep state.
- *	@pm_state:		State we're entering.
+ *	@pm_state: ignored
  *
- *	Flush caches and go to sleep. For STR or STD, we have to call 
- *	arch-specific assembly, which in turn call acpi_enter_sleep_state().
+ *	Flush caches and go to sleep. For STR we have to call arch-specific
+ *	assembly, which in turn call acpi_enter_sleep_state().
  *	It's unfortunate, but it works. Please fix if you're feeling frisky.
  */
 
@@ -70,31 +114,31 @@
 {
 	acpi_status status = AE_OK;
 	unsigned long flags = 0;
-	u32 acpi_state = acpi_suspend_states[pm_state];
+	u32 acpi_state = acpi_target_sleep_state;
 
 	ACPI_FLUSH_CPU_CACHE();
 
 	/* Do arch specific saving of state. */
-	if (pm_state > PM_SUSPEND_STANDBY) {
+	if (acpi_state == ACPI_STATE_S3) {
 		int error = acpi_save_state_mem();
-		if (error)
+
+		if (error) {
+			acpi_target_sleep_state = ACPI_STATE_S0;
 			return error;
+		}
 	}
 
 	local_irq_save(flags);
 	acpi_enable_wakeup_device(acpi_state);
-	switch (pm_state) {
-	case PM_SUSPEND_STANDBY:
+	switch (acpi_state) {
+	case ACPI_STATE_S1:
 		barrier();
 		status = acpi_enter_sleep_state(acpi_state);
 		break;
 
-	case PM_SUSPEND_MEM:
+	case ACPI_STATE_S3:
 		do_suspend_lowlevel();
 		break;
-
-	default:
-		return -EINVAL;
 	}
 
 	/* ACPI 3.0 specs (P62) says that it's the responsabilty
@@ -107,12 +151,8 @@
 	local_irq_restore(flags);
 	printk(KERN_DEBUG "Back to C!\n");
 
-	/* restore processor state
-	 * We should only be here if we're coming back from STR or STD.
-	 * And, in the case of the latter, the memory image should have already
-	 * been loaded from disk.
-	 */
-	if (pm_state > PM_SUSPEND_STANDBY)
+	/* restore processor state */
+	if (acpi_state == ACPI_STATE_S3)
 		acpi_restore_state_mem();
 
 	return ACPI_SUCCESS(status) ? 0 : -EFAULT;
@@ -120,7 +160,7 @@
 
 /**
  *	acpi_pm_finish - Finish up suspend sequence.
- *	@pm_state:		State we're coming out of.
+ *	@pm_state: ignored
  *
  *	This is called after we wake back up (or if entering the sleep state
  *	failed). 
@@ -128,7 +168,7 @@
 
 static int acpi_pm_finish(suspend_state_t pm_state)
 {
-	u32 acpi_state = acpi_suspend_states[pm_state];
+	u32 acpi_state = acpi_target_sleep_state;
 
 	acpi_leave_sleep_state(acpi_state);
 	acpi_disable_wakeup_device(acpi_state);
@@ -136,28 +176,17 @@
 	/* reset firmware waking vector */
 	acpi_set_firmware_waking_vector((acpi_physical_address) 0);
 
+	acpi_target_sleep_state = ACPI_STATE_S0;
+
+#ifdef CONFIG_X86
 	if (init_8259A_after_S1) {
 		printk("Broken toshiba laptop -> kicking interrupts\n");
 		init_8259A(0);
 	}
+#endif
 	return 0;
 }
 
-int acpi_suspend(u32 acpi_state)
-{
-	suspend_state_t states[] = {
-		[1] = PM_SUSPEND_STANDBY,
-		[3] = PM_SUSPEND_MEM,
-		[5] = PM_SUSPEND_MAX
-	};
-
-	if (acpi_state < 6 && states[acpi_state])
-		return pm_suspend(states[acpi_state]);
-	if (acpi_state == 4)
-		return hibernate();
-	return -EINVAL;
-}
-
 static int acpi_pm_state_valid(suspend_state_t pm_state)
 {
 	u32 acpi_state;
@@ -176,12 +205,34 @@
 
 static struct pm_ops acpi_pm_ops = {
 	.valid = acpi_pm_state_valid,
+	.set_target = acpi_pm_set_target,
 	.prepare = acpi_pm_prepare,
 	.enter = acpi_pm_enter,
 	.finish = acpi_pm_finish,
 };
 
-#ifdef CONFIG_SOFTWARE_SUSPEND
+/*
+ * Toshiba fails to preserve interrupts over S1, reinitialization
+ * of 8259 is needed after S1 resume.
+ */
+static int __init init_ints_after_s1(const struct dmi_system_id *d)
+{
+	printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident);
+	init_8259A_after_S1 = 1;
+	return 0;
+}
+
+static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
+	{
+	 .callback = init_ints_after_s1,
+	 .ident = "Toshiba Satellite 4030cdt",
+	 .matches = {DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),},
+	 },
+	{},
+};
+#endif /* CONFIG_SUSPEND */
+
+#ifdef CONFIG_HIBERNATION
 static int acpi_hibernation_prepare(void)
 {
 	return acpi_sleep_prepare(ACPI_STATE_S4);
@@ -210,69 +261,180 @@
 
 	/* reset firmware waking vector */
 	acpi_set_firmware_waking_vector((acpi_physical_address) 0);
+}
 
-	if (init_8259A_after_S1) {
-		printk("Broken toshiba laptop -> kicking interrupts\n");
-		init_8259A(0);
-	}
+static int acpi_hibernation_pre_restore(void)
+{
+	acpi_status status;
+
+	status = acpi_hw_disable_all_gpes();
+
+	return ACPI_SUCCESS(status) ? 0 : -EFAULT;
+}
+
+static void acpi_hibernation_restore_cleanup(void)
+{
+	acpi_hw_enable_all_runtime_gpes();
 }
 
 static struct hibernation_ops acpi_hibernation_ops = {
 	.prepare = acpi_hibernation_prepare,
 	.enter = acpi_hibernation_enter,
 	.finish = acpi_hibernation_finish,
+	.pre_restore = acpi_hibernation_pre_restore,
+	.restore_cleanup = acpi_hibernation_restore_cleanup,
 };
-#endif				/* CONFIG_SOFTWARE_SUSPEND */
+#endif				/* CONFIG_HIBERNATION */
 
-/*
- * Toshiba fails to preserve interrupts over S1, reinitialization
- * of 8259 is needed after S1 resume.
- */
-static int __init init_ints_after_s1(struct dmi_system_id *d)
+int acpi_suspend(u32 acpi_state)
 {
-	printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident);
-	init_8259A_after_S1 = 1;
-	return 0;
+	suspend_state_t states[] = {
+		[1] = PM_SUSPEND_STANDBY,
+		[3] = PM_SUSPEND_MEM,
+		[5] = PM_SUSPEND_MAX
+	};
+
+	if (acpi_state < 6 && states[acpi_state])
+		return pm_suspend(states[acpi_state]);
+	if (acpi_state == 4)
+		return hibernate();
+	return -EINVAL;
 }
 
-static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
-	{
-	 .callback = init_ints_after_s1,
-	 .ident = "Toshiba Satellite 4030cdt",
-	 .matches = {DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),},
-	 },
-	{},
-};
+#ifdef CONFIG_PM_SLEEP
+/**
+ *	acpi_pm_device_sleep_state - return preferred power state of ACPI device
+ *		in the system sleep state given by %acpi_target_sleep_state
+ *	@dev: device to examine
+ *	@wake: if set, the device should be able to wake up the system
+ *	@d_min_p: used to store the upper limit of allowed states range
+ *	Return value: preferred power state of the device on success, -ENODEV on
+ *		failure (ie. if there's no 'struct acpi_device' for @dev)
+ *
+ *	Find the lowest power (highest number) ACPI device power state that
+ *	device @dev can be in while the system is in the sleep state represented
+ *	by %acpi_target_sleep_state.  If @wake is nonzero, the device should be
+ *	able to wake up the system from this sleep state.  If @d_min_p is set,
+ *	the highest power (lowest number) device power state of @dev allowed
+ *	in this system sleep state is stored at the location pointed to by it.
+ *
+ *	The caller must ensure that @dev is valid before using this function.
+ *	The caller is also responsible for figuring out if the device is
+ *	supposed to be able to wake up the system and passing this information
+ *	via @wake.
+ */
+
+int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p)
+{
+	acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
+	struct acpi_device *adev;
+	char acpi_method[] = "_SxD";
+	unsigned long d_min, d_max;
+
+	if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &adev))) {
+		printk(KERN_DEBUG "ACPI handle has no context!\n");
+		return -ENODEV;
+	}
+
+	acpi_method[2] = '0' + acpi_target_sleep_state;
+	/*
+	 * If the sleep state is S0, we will return D3, but if the device has
+	 * _S0W, we will use the value from _S0W
+	 */
+	d_min = ACPI_STATE_D0;
+	d_max = ACPI_STATE_D3;
+
+	/*
+	 * If present, _SxD methods return the minimum D-state (highest power
+	 * state) we can use for the corresponding S-states.  Otherwise, the
+	 * minimum D-state is D0 (ACPI 3.x).
+	 *
+	 * NOTE: We rely on acpi_evaluate_integer() not clobbering the integer
+	 * provided -- that's our fault recovery, we ignore retval.
+	 */
+	if (acpi_target_sleep_state > ACPI_STATE_S0)
+		acpi_evaluate_integer(handle, acpi_method, NULL, &d_min);
+
+	/*
+	 * If _PRW says we can wake up the system from the target sleep state,
+	 * the D-state returned by _SxD is sufficient for that (we assume a
+	 * wakeup-aware driver if wake is set).  Still, if _SxW exists
+	 * (ACPI 3.x), it should return the maximum (lowest power) D-state that
+	 * can wake the system.  _S0W may be valid, too.
+	 */
+	if (acpi_target_sleep_state == ACPI_STATE_S0 ||
+	    (wake && adev->wakeup.state.enabled &&
+	     adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
+		acpi_method[3] = 'W';
+		acpi_evaluate_integer(handle, acpi_method, NULL, &d_max);
+		/* Sanity check */
+		if (d_max < d_min)
+			d_min = d_max;
+	}
+
+	if (d_min_p)
+		*d_min_p = d_min;
+	return d_max;
+}
+#endif
+
+static void acpi_power_off_prepare(void)
+{
+	/* Prepare to power off the system */
+	acpi_sleep_prepare(ACPI_STATE_S5);
+}
+
+static void acpi_power_off(void)
+{
+	/* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
+	printk("%s called\n", __FUNCTION__);
+	local_irq_disable();
+	acpi_enter_sleep_state(ACPI_STATE_S5);
+}
 
 int __init acpi_sleep_init(void)
 {
+	acpi_status status;
+	u8 type_a, type_b;
+#ifdef CONFIG_SUSPEND
 	int i = 0;
 
 	dmi_check_system(acpisleep_dmi_table);
+#endif
 
 	if (acpi_disabled)
 		return 0;
 
-	printk(KERN_INFO PREFIX "(supports");
-	for (i = 0; i < ACPI_S_STATE_COUNT; i++) {
-		acpi_status status;
-		u8 type_a, type_b;
+	sleep_states[ACPI_STATE_S0] = 1;
+	printk(KERN_INFO PREFIX "(supports S0");
+
+#ifdef CONFIG_SUSPEND
+	for (i = ACPI_STATE_S1; i < ACPI_STATE_S4; i++) {
 		status = acpi_get_sleep_type_data(i, &type_a, &type_b);
 		if (ACPI_SUCCESS(status)) {
 			sleep_states[i] = 1;
 			printk(" S%d", i);
 		}
 	}
-	printk(")\n");
 
 	pm_set_ops(&acpi_pm_ops);
-
-#ifdef CONFIG_SOFTWARE_SUSPEND
-	if (sleep_states[ACPI_STATE_S4])
-		hibernation_set_ops(&acpi_hibernation_ops);
-#else
-	sleep_states[ACPI_STATE_S4] = 0;
 #endif
 
+#ifdef CONFIG_HIBERNATION
+	status = acpi_get_sleep_type_data(ACPI_STATE_S4, &type_a, &type_b);
+	if (ACPI_SUCCESS(status)) {
+		hibernation_set_ops(&acpi_hibernation_ops);
+		sleep_states[ACPI_STATE_S4] = 1;
+		printk(" S4");
+	}
+#endif
+	status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
+	if (ACPI_SUCCESS(status)) {
+		sleep_states[ACPI_STATE_S5] = 1;
+		printk(" S5");
+		pm_power_off_prepare = acpi_power_off_prepare;
+		pm_power_off = acpi_power_off;
+	}
+	printk(")\n");
 	return 0;
 }
diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c
deleted file mode 100644
index d9801ef..0000000
--- a/drivers/acpi/sleep/poweroff.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * poweroff.c - ACPI handler for powering off the system.
- *
- * AKA S5, but it is independent of whether or not the kernel supports
- * any other sleep support in the system.
- *
- * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
- *
- * This file is released under the GPLv2.
- */
-
-#include <linux/pm.h>
-#include <linux/init.h>
-#include <acpi/acpi_bus.h>
-#include <linux/sysdev.h>
-#include <asm/io.h>
-#include "sleep.h"
-
-int acpi_sleep_prepare(u32 acpi_state)
-{
-#ifdef CONFIG_ACPI_SLEEP
-	/* do we have a wakeup address for S2 and S3? */
-	if (acpi_state == ACPI_STATE_S3) {
-		if (!acpi_wakeup_address) {
-			return -EFAULT;
-		}
-		acpi_set_firmware_waking_vector((acpi_physical_address)
-						virt_to_phys((void *)
-							     acpi_wakeup_address));
-
-	}
-	ACPI_FLUSH_CPU_CACHE();
-	acpi_enable_wakeup_device_prep(acpi_state);
-#endif
-	acpi_gpe_sleep_prepare(acpi_state);
-	acpi_enter_sleep_state_prep(acpi_state);
-	return 0;
-}
-
-#ifdef CONFIG_PM
-
-void acpi_power_off(void)
-{
-	/* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
-	printk("%s called\n", __FUNCTION__);
-	local_irq_disable();
-	/* Some SMP machines only can poweroff in boot CPU */
-	acpi_enter_sleep_state(ACPI_STATE_S5);
-}
-
-static int acpi_shutdown(struct sys_device *x)
-{
-	switch (system_state) {
-	case SYSTEM_POWER_OFF:
-		/* Prepare to power off the system */
-		return acpi_sleep_prepare(ACPI_STATE_S5);
-	case SYSTEM_SUSPEND_DISK:
-		/* Prepare to suspend the system to disk */
-		return acpi_sleep_prepare(ACPI_STATE_S4);
-	default:
-		return 0;
-	}
-}
-
-static struct sysdev_class acpi_sysclass = {
-	set_kset_name("acpi"),
-	.shutdown = acpi_shutdown
-};
-
-static struct sys_device device_acpi = {
-	.id = 0,
-	.cls = &acpi_sysclass,
-};
-
-static int acpi_poweroff_init(void)
-{
-	if (!acpi_disabled) {
-		u8 type_a, type_b;
-		acpi_status status;
-
-		status =
-		    acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
-		if (ACPI_SUCCESS(status)) {
-			int error;
-			error = sysdev_class_register(&acpi_sysclass);
-			if (!error)
-				error = sysdev_register(&device_acpi);
-			if (!error)
-				pm_power_off = acpi_power_off;
-			return error;
-		}
-	}
-	return 0;
-}
-
-late_initcall(acpi_poweroff_init);
-
-#endif				/* CONFIG_PM */
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 61f1822..3839efd 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -14,8 +14,16 @@
 #include "sleep.h"
 
 #define _COMPONENT		ACPI_SYSTEM_COMPONENT
+
+/*
+ * this file provides support for:
+ * /proc/acpi/sleep
+ * /proc/acpi/alarm
+ * /proc/acpi/wakeup
+ */
+
 ACPI_MODULE_NAME("sleep")
-#ifdef	CONFIG_ACPI_SLEEP_PROC_SLEEP
+#ifdef	CONFIG_ACPI_PROCFS
 static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset)
 {
 	int i;
@@ -58,7 +66,7 @@
 		goto Done;
 	}
 	state = simple_strtoul(str, NULL, 0);
-#ifdef CONFIG_SOFTWARE_SUSPEND
+#ifdef CONFIG_HIBERNATION
 	if (state == 4) {
 		error = hibernate();
 		goto Done;
@@ -68,9 +76,9 @@
       Done:
 	return error ? error : count;
 }
-#endif				/* CONFIG_ACPI_SLEEP_PROC_SLEEP */
+#endif				/* CONFIG_ACPI_PROCFS */
 
-#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
+#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) || !defined(CONFIG_X86)
 /* use /sys/class/rtc/rtcX/wakealarm instead; it's not ACPI-specific */
 #else
 #define	HAVE_ACPI_LEGACY_ALARM
@@ -463,7 +471,7 @@
 	.release = single_release,
 };
 
-#ifdef	CONFIG_ACPI_SLEEP_PROC_SLEEP
+#ifdef	CONFIG_ACPI_PROCFS
 static const struct file_operations acpi_system_sleep_fops = {
 	.open = acpi_system_sleep_open_fs,
 	.read = seq_read,
@@ -471,7 +479,7 @@
 	.llseek = seq_lseek,
 	.release = single_release,
 };
-#endif				/* CONFIG_ACPI_SLEEP_PROC_SLEEP */
+#endif				/* CONFIG_ACPI_PROCFS */
 
 #ifdef	HAVE_ACPI_LEGACY_ALARM
 static const struct file_operations acpi_system_alarm_fops = {
@@ -498,14 +506,14 @@
 	if (acpi_disabled)
 		return 0;
 
-#ifdef	CONFIG_ACPI_SLEEP_PROC_SLEEP
+#ifdef	CONFIG_ACPI_PROCFS
 	/* 'sleep' [R/W] */
 	entry =
 	    create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR,
 			      acpi_root_dir);
 	if (entry)
 		entry->proc_fops = &acpi_system_sleep_fops;
-#endif
+#endif				/* CONFIG_ACPI_PROCFS */
 
 #ifdef	HAVE_ACPI_LEGACY_ALARM
 	/* 'alarm' [R/W] */
diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h
index f3e7039..ff1f850 100644
--- a/drivers/acpi/sleep/sleep.h
+++ b/drivers/acpi/sleep/sleep.h
@@ -6,3 +6,5 @@
 extern void acpi_enable_wakeup_device(u8 sleep_state);
 extern void acpi_disable_wakeup_device(u8 sleep_state);
 extern void acpi_gpe_sleep_prepare(u32 sleep_state);
+
+extern int acpi_sleep_prepare(u32 acpi_state);
diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c
index fab8f26..97c27dd 100644
--- a/drivers/acpi/sleep/wakeup.c
+++ b/drivers/acpi/sleep/wakeup.c
@@ -17,7 +17,6 @@
 extern struct list_head acpi_wakeup_device_list;
 extern spinlock_t acpi_device_lock;
 
-#ifdef CONFIG_ACPI_SLEEP
 /**
  * acpi_enable_wakeup_device_prep - prepare wakeup devices
  *	@sleep_state:	ACPI state
@@ -180,7 +179,6 @@
 }
 
 late_initcall(acpi_wakeup_device_init);
-#endif
 
 /*
  * Disable all wakeup GPEs before entering requested sleep state.
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 83a8d30..edee280 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -39,15 +39,12 @@
 
 #define ACPI_SYSTEM_CLASS		"system"
 #define ACPI_SYSTEM_DEVICE_NAME		"System"
-#define ACPI_SYSTEM_FILE_INFO		"info"
-#define ACPI_SYSTEM_FILE_EVENT		"event"
-#define ACPI_SYSTEM_FILE_DSDT		"dsdt"
-#define ACPI_SYSTEM_FILE_FADT		"fadt"
 
 /*
  * Make ACPICA version work as module param
  */
-static int param_get_acpica_version(char *buffer, struct kernel_param *kp) {
+static int param_get_acpica_version(char *buffer, struct kernel_param *kp)
+{
 	int result;
 
 	result = sprintf(buffer, "%x", ACPI_CA_VERSION);
@@ -58,9 +55,126 @@
 module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
 
 /* --------------------------------------------------------------------------
+                              FS Interface (/sys)
+   -------------------------------------------------------------------------- */
+static LIST_HEAD(acpi_table_attr_list);
+static struct kobject tables_kobj;
+
+struct acpi_table_attr {
+	struct bin_attribute attr;
+	char name[8];
+	int instance;
+	struct list_head node;
+};
+
+static ssize_t acpi_table_show(struct kobject *kobj,
+			       struct bin_attribute *bin_attr, char *buf,
+			       loff_t offset, size_t count)
+{
+	struct acpi_table_attr *table_attr =
+	    container_of(bin_attr, struct acpi_table_attr, attr);
+	struct acpi_table_header *table_header = NULL;
+	acpi_status status;
+	ssize_t ret_count = count;
+
+	status =
+	    acpi_get_table(table_attr->name, table_attr->instance,
+			   &table_header);
+	if (ACPI_FAILURE(status))
+		return -ENODEV;
+
+	if (offset >= table_header->length) {
+		ret_count = 0;
+		goto end;
+	}
+
+	if (offset + ret_count > table_header->length)
+		ret_count = table_header->length - offset;
+
+	memcpy(buf, ((char *)table_header) + offset, ret_count);
+
+      end:
+	return ret_count;
+}
+
+static void acpi_table_attr_init(struct acpi_table_attr *table_attr,
+				 struct acpi_table_header *table_header)
+{
+	struct acpi_table_header *header = NULL;
+	struct acpi_table_attr *attr = NULL;
+
+	memcpy(table_attr->name, table_header->signature, ACPI_NAME_SIZE);
+
+	list_for_each_entry(attr, &acpi_table_attr_list, node) {
+		if (!memcmp(table_header->signature, attr->name,
+			    ACPI_NAME_SIZE))
+			if (table_attr->instance < attr->instance)
+				table_attr->instance = attr->instance;
+	}
+	table_attr->instance++;
+
+	if (table_attr->instance > 1 || (table_attr->instance == 1 &&
+					 !acpi_get_table(table_header->
+							 signature, 2,
+							 &header)))
+		sprintf(table_attr->name + 4, "%d", table_attr->instance);
+
+	table_attr->attr.size = 0;
+	table_attr->attr.read = acpi_table_show;
+	table_attr->attr.attr.name = table_attr->name;
+	table_attr->attr.attr.mode = 0444;
+	table_attr->attr.attr.owner = THIS_MODULE;
+
+	return;
+}
+
+static int acpi_system_sysfs_init(void)
+{
+	struct acpi_table_attr *table_attr;
+	struct acpi_table_header *table_header = NULL;
+	int table_index = 0;
+	int result;
+
+	tables_kobj.parent = &acpi_subsys.kobj;
+	kobject_set_name(&tables_kobj, "tables");
+	result = kobject_register(&tables_kobj);
+	if (result)
+		return result;
+
+	do {
+		result = acpi_get_table_by_index(table_index, &table_header);
+		if (!result) {
+			table_index++;
+			table_attr = NULL;
+			table_attr =
+			    kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL);
+			if (!table_attr)
+				return -ENOMEM;
+
+			acpi_table_attr_init(table_attr, table_header);
+			result =
+			    sysfs_create_bin_file(&tables_kobj,
+						  &table_attr->attr);
+			if (result) {
+				kfree(table_attr);
+				return result;
+			} else
+				list_add_tail(&table_attr->node,
+					      &acpi_table_attr_list);
+		}
+	} while (!result);
+
+	return 0;
+}
+
+/* --------------------------------------------------------------------------
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
 #ifdef CONFIG_ACPI_PROCFS
+#define ACPI_SYSTEM_FILE_INFO		"info"
+#define ACPI_SYSTEM_FILE_EVENT		"event"
+#define ACPI_SYSTEM_FILE_DSDT		"dsdt"
+#define ACPI_SYSTEM_FILE_FADT		"fadt"
 
 static int acpi_system_read_info(struct seq_file *seq, void *offset)
 {
@@ -80,7 +194,6 @@
 	.llseek = seq_lseek,
 	.release = single_release,
 };
-#endif
 
 static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t,
 				     loff_t *);
@@ -97,13 +210,11 @@
 	struct acpi_table_header *dsdt = NULL;
 	ssize_t res;
 
-
 	status = acpi_get_table(ACPI_SIG_DSDT, 1, &dsdt);
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	res = simple_read_from_buffer(buffer, count, ppos,
-				      dsdt, dsdt->length);
+	res = simple_read_from_buffer(buffer, count, ppos, dsdt, dsdt->length);
 
 	return res;
 }
@@ -123,28 +234,21 @@
 	struct acpi_table_header *fadt = NULL;
 	ssize_t res;
 
-
 	status = acpi_get_table(ACPI_SIG_FADT, 1, &fadt);
 	if (ACPI_FAILURE(status))
 		return -ENODEV;
 
-	res = simple_read_from_buffer(buffer, count, ppos,
-				      fadt, fadt->length);
+	res = simple_read_from_buffer(buffer, count, ppos, fadt, fadt->length);
 
 	return res;
 }
 
-static int __init acpi_system_init(void)
+static int acpi_system_procfs_init(void)
 {
 	struct proc_dir_entry *entry;
 	int error = 0;
 	char *name;
 
-
-	if (acpi_disabled)
-		return 0;
-
-#ifdef CONFIG_ACPI_PROCFS
 	/* 'info' [R] */
 	name = ACPI_SYSTEM_FILE_INFO;
 	entry = create_proc_entry(name, S_IRUGO, acpi_root_dir);
@@ -153,7 +257,6 @@
 	else {
 		entry->proc_fops = &acpi_system_info_ops;
 	}
-#endif
 
 	/* 'dsdt' [R] */
 	name = ACPI_SYSTEM_FILE_DSDT;
@@ -177,12 +280,32 @@
       Error:
 	remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir);
 	remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir);
-#ifdef CONFIG_ACPI_PROCFS
 	remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir);
-#endif
 
 	error = -EFAULT;
 	goto Done;
 }
+#else
+static int acpi_system_procfs_init(void)
+{
+	return 0;
+}
+#endif
+
+static int __init acpi_system_init(void)
+{
+	int result = 0;
+
+	if (acpi_disabled)
+		return 0;
+
+	result = acpi_system_procfs_init();
+	if (result)
+		return result;
+
+	result = acpi_system_sysfs_init();
+
+	return result;
+}
 
 subsys_initcall(acpi_system_init);
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
index 1285e91..002bb33 100644
--- a/drivers/acpi/tables/tbfadt.c
+++ b/drivers/acpi/tables/tbfadt.c
@@ -211,14 +211,17 @@
  * DESCRIPTION: Get a local copy of the FADT and convert it to a common format.
  *              Performs validation on some important FADT fields.
  *
+ * NOTE:        We create a local copy of the FADT regardless of the version.
+ *
  ******************************************************************************/
 
 void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
 {
 
 	/*
-	 * Check if the FADT is larger than what we know about (ACPI 2.0 version).
-	 * Truncate the table, but make some noise.
+	 * Check if the FADT is larger than the largest table that we expect
+	 * (the ACPI 2.0/3.0 version). If so, truncate the table, and issue
+	 * a warning.
 	 */
 	if (length > sizeof(struct acpi_table_fadt)) {
 		ACPI_WARNING((AE_INFO,
@@ -227,10 +230,12 @@
 			      sizeof(struct acpi_table_fadt)));
 	}
 
-	/* Copy the entire FADT locally. Zero first for tb_convert_fadt */
+	/* Clear the entire local FADT */
 
 	ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt));
 
+	/* Copy the original FADT, up to sizeof (struct acpi_table_fadt) */
+
 	ACPI_MEMCPY(&acpi_gbl_FADT, table,
 		    ACPI_MIN(length, sizeof(struct acpi_table_fadt)));
 
@@ -251,7 +256,7 @@
  * RETURN:      None
  *
  * DESCRIPTION: Converts all versions of the FADT to a common internal format.
- *              -> Expand all 32-bit addresses to 64-bit.
+ *              Expand all 32-bit addresses to 64-bit.
  *
  * NOTE:        acpi_gbl_FADT must be of size (struct acpi_table_fadt),
  *              and must contain a copy of the actual FADT.
@@ -292,8 +297,23 @@
 	}
 
 	/*
-	 * Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address
-	 * structures as necessary.
+	 * For ACPI 1.0 FADTs (revision 1 or 2), ensure that reserved fields which
+	 * should be zero are indeed zero. This will workaround BIOSs that
+	 * inadvertently place values in these fields.
+	 *
+	 * The ACPI 1.0 reserved fields that will be zeroed are the bytes located at
+	 * offset 45, 55, 95, and the word located at offset 109, 110.
+	 */
+	if (acpi_gbl_FADT.header.revision < 3) {
+		acpi_gbl_FADT.preferred_profile = 0;
+		acpi_gbl_FADT.pstate_control = 0;
+		acpi_gbl_FADT.cst_control = 0;
+		acpi_gbl_FADT.boot_flags = 0;
+	}
+
+	/*
+	 * Expand the ACPI 1.0 32-bit V1.0 addresses to the ACPI 2.0 64-bit "X"
+	 * generic address structures as necessary.
 	 */
 	for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
 		target =
@@ -349,18 +369,6 @@
 		    acpi_gbl_FADT.xpm1a_event_block.space_id;
 
 	}
-
-	/*
-	 * For ACPI 1.0 FADTs, ensure that reserved fields (which should be zero)
-	 * are indeed zero. This will workaround BIOSs that inadvertently placed
-	 * values in these fields.
-	 */
-	if (acpi_gbl_FADT.header.revision < 3) {
-		acpi_gbl_FADT.preferred_profile = 0;
-		acpi_gbl_FADT.pstate_control = 0;
-		acpi_gbl_FADT.cst_control = 0;
-		acpi_gbl_FADT.boot_flags = 0;
-	}
 }
 
 /******************************************************************************
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
index 1da64b4..8cc9492 100644
--- a/drivers/acpi/tables/tbutils.c
+++ b/drivers/acpi/tables/tbutils.c
@@ -51,6 +51,65 @@
 static acpi_physical_address
 acpi_tb_get_root_table_entry(u8 * table_entry,
 			     acpi_native_uint table_entry_size);
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_check_xsdt
+ *
+ * PARAMETERS:  address                    - Pointer to the XSDT
+ *
+ * RETURN:      status
+ *		AE_OK - XSDT is okay
+ *		AE_NO_MEMORY - can't map XSDT
+ *		AE_INVALID_TABLE_LENGTH - invalid table length
+ *		AE_NULL_ENTRY - XSDT has NULL entry
+ *
+ * DESCRIPTION: validate XSDT
+******************************************************************************/
+
+static acpi_status
+acpi_tb_check_xsdt(acpi_physical_address address)
+{
+	struct acpi_table_header *table;
+	u32 length;
+	u64 xsdt_entry_address;
+	u8 *table_entry;
+	u32 table_count;
+	int i;
+
+	table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+	if (!table)
+		return AE_NO_MEMORY;
+
+	length = table->length;
+	acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
+	if (length < sizeof(struct acpi_table_header))
+		return AE_INVALID_TABLE_LENGTH;
+
+	table = acpi_os_map_memory(address, length);
+	if (!table)
+		return AE_NO_MEMORY;
+
+	/* Calculate the number of tables described in XSDT */
+	table_count =
+		(u32) ((table->length -
+		sizeof(struct acpi_table_header)) / sizeof(u64));
+	table_entry =
+		ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
+	for (i = 0; i < table_count; i++) {
+		ACPI_MOVE_64_TO_64(&xsdt_entry_address, table_entry);
+		if (!xsdt_entry_address) {
+			/* XSDT has NULL entry */
+			break;
+		}
+		table_entry += sizeof(u64);
+	}
+	acpi_os_unmap_memory(table, length);
+
+	if (i < table_count)
+		return AE_NULL_ENTRY;
+	else
+		return AE_OK;
+}
 
 /*******************************************************************************
  *
@@ -341,6 +400,7 @@
 	u32 table_count;
 	struct acpi_table_header *table;
 	acpi_physical_address address;
+	acpi_physical_address rsdt_address;
 	u32 length;
 	u8 *table_entry;
 	acpi_status status;
@@ -369,6 +429,8 @@
 		 */
 		address = (acpi_physical_address) rsdp->xsdt_physical_address;
 		table_entry_size = sizeof(u64);
+		rsdt_address = (acpi_physical_address)
+					rsdp->rsdt_physical_address;
 	} else {
 		/* Root table is an RSDT (32-bit physical addresses) */
 
@@ -382,6 +444,15 @@
 	 */
 	acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
 
+	if (table_entry_size == sizeof(u64)) {
+		if (acpi_tb_check_xsdt(address) == AE_NULL_ENTRY) {
+			/* XSDT has NULL entry, RSDT is used */
+			address = rsdt_address;
+			table_entry_size = sizeof(u32);
+			ACPI_WARNING((AE_INFO, "BIOS XSDT has NULL entry,"
+					"using RSDT"));
+		}
+	}
 	/* Map the RSDT/XSDT table header to get the full table length */
 
 	table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
index 5b302c4..a9e3331 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/tables/tbxface.c
@@ -52,6 +52,8 @@
 /* Local prototypes */
 static acpi_status acpi_tb_load_namespace(void);
 
+static int no_auto_ssdt;
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_allocate_root_table
@@ -536,6 +538,10 @@
 
 		ACPI_INFO((AE_INFO, "Table DSDT replaced by host OS"));
 		acpi_tb_print_table_header(0, table);
+
+		if (no_auto_ssdt == 0) {
+			printk(KERN_WARNING "ACPI: DSDT override uses original SSDTs unless \"acpi_no_auto_ssdt\"");
+		}
 	}
 
 	status =
@@ -577,6 +583,11 @@
 			continue;
 		}
 
+		if (no_auto_ssdt) {
+			printk(KERN_WARNING "ACPI: SSDT ignored due to \"acpi_no_auto_ssdt\"\n");
+			continue;
+		}
+
 		/* Ignore errors while loading tables, get as many as possible */
 
 		(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
@@ -622,3 +633,15 @@
 }
 
 ACPI_EXPORT_SYMBOL(acpi_load_tables)
+
+
+static int __init acpi_no_auto_ssdt_setup(char *s) {
+
+        printk(KERN_NOTICE "ACPI: SSDT auto-load disabled\n");
+
+        no_auto_ssdt = 1;
+
+        return 1;
+}
+
+__setup("acpi_no_auto_ssdt", acpi_no_auto_ssdt_setup);
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 88a6fc7..ad898e1 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -33,6 +33,7 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/dmi.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/proc_fs.h>
@@ -40,6 +41,7 @@
 #include <linux/jiffies.h>
 #include <linux/kmod.h>
 #include <linux/seq_file.h>
+#include <linux/reboot.h>
 #include <asm/uaccess.h>
 
 #include <acpi/acpi_bus.h>
@@ -59,7 +61,6 @@
 #define ACPI_THERMAL_NOTIFY_CRITICAL	0xF0
 #define ACPI_THERMAL_NOTIFY_HOT		0xF1
 #define ACPI_THERMAL_MODE_ACTIVE	0x00
-#define ACPI_THERMAL_PATH_POWEROFF	"/sbin/poweroff"
 
 #define ACPI_THERMAL_MAX_ACTIVE	10
 #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
@@ -74,9 +75,29 @@
 MODULE_DESCRIPTION("ACPI Thermal Zone Driver");
 MODULE_LICENSE("GPL");
 
+static int act;
+module_param(act, int, 0644);
+MODULE_PARM_DESC(act, "Disable or override all lowest active trip points.");
+
+static int crt;
+module_param(crt, int, 0644);
+MODULE_PARM_DESC(crt, "Disable or lower all critical trip points.");
+
 static int tzp;
-module_param(tzp, int, 0);
-MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
+module_param(tzp, int, 0444);
+MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.");
+
+static int nocrt;
+module_param(nocrt, int, 0);
+MODULE_PARM_DESC(nocrt, "Set to take no action upon ACPI thermal zone critical trips points.");
+
+static int off;
+module_param(off, int, 0);
+MODULE_PARM_DESC(off, "Set to disable ACPI thermal support.");
+
+static int psv;
+module_param(psv, int, 0644);
+MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
 
 static int acpi_thermal_add(struct acpi_device *device);
 static int acpi_thermal_remove(struct acpi_device *device, int type);
@@ -92,10 +113,16 @@
 static ssize_t acpi_thermal_write_polling(struct file *, const char __user *,
 					  size_t, loff_t *);
 
+static const struct acpi_device_id  thermal_device_ids[] = {
+	{ACPI_THERMAL_HID, 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
+
 static struct acpi_driver acpi_thermal_driver = {
 	.name = "thermal",
 	.class = ACPI_THERMAL_CLASS,
-	.ids = ACPI_THERMAL_HID,
+	.ids = thermal_device_ids,
 	.ops = {
 		.add = acpi_thermal_add,
 		.remove = acpi_thermal_remove,
@@ -317,6 +344,20 @@
 				  tz->trips.critical.temperature));
 	}
 
+	if (tz->trips.critical.flags.valid == 1) {
+		if (crt == -1) {
+			tz->trips.critical.flags.valid = 0;
+		} else if (crt > 0) {
+			unsigned long crt_k = CELSIUS_TO_KELVIN(crt);
+
+			/*
+			 * Allow override to lower critical threshold
+			 */
+			if (crt_k < tz->trips.critical.temperature)
+				tz->trips.critical.temperature = crt_k;
+		}
+	}
+
 	/* Critical Sleep (optional) */
 
 	status =
@@ -333,9 +374,16 @@
 
 	/* Passive: Processors (optional) */
 
-	status =
-	    acpi_evaluate_integer(tz->device->handle, "_PSV", NULL,
-				  &tz->trips.passive.temperature);
+	if (psv == -1) {
+		status = AE_SUPPORT;
+	} else if (psv > 0) {
+		tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);
+		status = AE_OK;
+	} else {
+		status = acpi_evaluate_integer(tz->device->handle,
+			"_PSV", NULL, &tz->trips.passive.temperature);
+	}
+
 	if (ACPI_FAILURE(status)) {
 		tz->trips.passive.flags.valid = 0;
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n"));
@@ -380,11 +428,33 @@
 
 		char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
 
-		status =
-		    acpi_evaluate_integer(tz->device->handle, name, NULL,
-					  &tz->trips.active[i].temperature);
-		if (ACPI_FAILURE(status))
+		if (act == -1)
+			break;	/* disable all active trip points */
+
+		status = acpi_evaluate_integer(tz->device->handle,
+			name, NULL, &tz->trips.active[i].temperature);
+
+		if (ACPI_FAILURE(status)) {
+			if (i == 0)	/* no active trip points */
+				break;
+			if (act <= 0)	/* no override requested */
+				break;
+			if (i == 1) {	/* 1 trip point */
+				tz->trips.active[0].temperature =
+					CELSIUS_TO_KELVIN(act);
+			} else {	/* multiple trips */
+				/*
+				 * Don't allow override higher than
+				 * the next higher trip point
+				 */
+				tz->trips.active[i - 1].temperature =
+				    (tz->trips.active[i - 2].temperature <
+					CELSIUS_TO_KELVIN(act) ?
+					tz->trips.active[i - 2].temperature :
+					CELSIUS_TO_KELVIN(act));
+			}
 			break;
+		}
 
 		name[2] = 'L';
 		status =
@@ -419,29 +489,9 @@
 	return 0;
 }
 
-static int acpi_thermal_call_usermode(char *path)
-{
-	char *argv[2] = { NULL, NULL };
-	char *envp[3] = { NULL, NULL, NULL };
-
-
-	if (!path)
-		return -EINVAL;
-
-	argv[0] = path;
-
-	/* minimal command environment */
-	envp[0] = "HOME=/";
-	envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
-
-	call_usermodehelper(argv[0], argv, envp, 0);
-
-	return 0;
-}
-
 static int acpi_thermal_critical(struct acpi_thermal *tz)
 {
-	if (!tz || !tz->trips.critical.flags.valid)
+	if (!tz || !tz->trips.critical.flags.valid || nocrt)
 		return -EINVAL;
 
 	if (tz->temperature >= tz->trips.critical.temperature) {
@@ -453,17 +503,21 @@
 	printk(KERN_EMERG
 	       "Critical temperature reached (%ld C), shutting down.\n",
 	       KELVIN_TO_CELSIUS(tz->temperature));
-	acpi_bus_generate_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
+	acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
 				tz->trips.critical.flags.enabled);
+	acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
+					  tz->device->dev.bus_id,
+					  ACPI_THERMAL_NOTIFY_CRITICAL,
+					  tz->trips.critical.flags.enabled);
 
-	acpi_thermal_call_usermode(ACPI_THERMAL_PATH_POWEROFF);
+	orderly_poweroff(true);
 
 	return 0;
 }
 
 static int acpi_thermal_hot(struct acpi_thermal *tz)
 {
-	if (!tz || !tz->trips.hot.flags.valid)
+	if (!tz || !tz->trips.hot.flags.valid || nocrt)
 		return -EINVAL;
 
 	if (tz->temperature >= tz->trips.hot.temperature) {
@@ -472,8 +526,12 @@
 	} else if (tz->trips.hot.flags.enabled)
 		tz->trips.hot.flags.enabled = 0;
 
-	acpi_bus_generate_event(tz->device, ACPI_THERMAL_NOTIFY_HOT,
+	acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_HOT,
 				tz->trips.hot.flags.enabled);
+	acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
+					  tz->device->dev.bus_id,
+					  ACPI_THERMAL_NOTIFY_HOT,
+					  tz->trips.hot.flags.enabled);
 
 	/* TBD: Call user-mode "sleep(S4)" function */
 
@@ -838,12 +896,14 @@
 		goto end;
 
 	if (tz->trips.critical.flags.valid)
-		seq_printf(seq, "critical (S5):           %ld C\n",
-			   KELVIN_TO_CELSIUS(tz->trips.critical.temperature));
+		seq_printf(seq, "critical (S5):           %ld C%s",
+			   KELVIN_TO_CELSIUS(tz->trips.critical.temperature),
+			   nocrt ? " <disabled>\n" : "\n");
 
 	if (tz->trips.hot.flags.valid)
-		seq_printf(seq, "hot (S4):                %ld C\n",
-			   KELVIN_TO_CELSIUS(tz->trips.hot.temperature));
+		seq_printf(seq, "hot (S4):                %ld C%s",
+			   KELVIN_TO_CELSIUS(tz->trips.hot.temperature),
+			   nocrt ? " <disabled>\n" : "\n");
 
 	if (tz->trips.passive.flags.valid) {
 		seq_printf(seq,
@@ -1033,9 +1093,9 @@
 		entry->owner = THIS_MODULE;
 	}
 
-	/* 'trip_points' [R/W] */
+	/* 'trip_points' [R] */
 	entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
-				  S_IFREG | S_IRUGO | S_IWUSR,
+				  S_IRUGO,
 				  acpi_device_dir(device));
 	if (!entry)
 		return -ENODEV;
@@ -1115,12 +1175,16 @@
 	case ACPI_THERMAL_NOTIFY_THRESHOLDS:
 		acpi_thermal_get_trip_points(tz);
 		acpi_thermal_check(tz);
-		acpi_bus_generate_event(device, event, 0);
+		acpi_bus_generate_proc_event(device, event, 0);
+		acpi_bus_generate_netlink_event(device->pnp.device_class,
+						  device->dev.bus_id, event, 0);
 		break;
 	case ACPI_THERMAL_NOTIFY_DEVICES:
 		if (tz->flags.devices)
 			acpi_thermal_get_devices(tz);
-		acpi_bus_generate_event(device, event, 0);
+		acpi_bus_generate_proc_event(device, event, 0);
+		acpi_bus_generate_netlink_event(device->pnp.device_class,
+						  device->dev.bus_id, event, 0);
 		break;
 	default:
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -1295,11 +1359,93 @@
 	return AE_OK;
 }
 
+#ifdef CONFIG_DMI
+static int thermal_act(const struct dmi_system_id *d) {
+
+	if (act == 0) {
+		printk(KERN_NOTICE "ACPI: %s detected: "
+			"disabling all active thermal trip points\n", d->ident);
+		act = -1;
+	}
+	return 0;
+}
+static int thermal_nocrt(const struct dmi_system_id *d) {
+
+	printk(KERN_NOTICE "ACPI: %s detected: "
+		"disabling all critical thermal trip point actions.\n", d->ident);
+	nocrt = 1;
+	return 0;
+}
+static int thermal_tzp(const struct dmi_system_id *d) {
+
+	if (tzp == 0) {
+		printk(KERN_NOTICE "ACPI: %s detected: "
+			"enabling thermal zone polling\n", d->ident);
+		tzp = 300;	/* 300 dS = 30 Seconds */
+	}
+	return 0;
+}
+static int thermal_psv(const struct dmi_system_id *d) {
+
+	if (psv == 0) {
+		printk(KERN_NOTICE "ACPI: %s detected: "
+			"disabling all passive thermal trip points\n", d->ident);
+		psv = -1;
+	}
+	return 0;
+}
+
+static struct dmi_system_id thermal_dmi_table[] __initdata = {
+	/*
+	 * Award BIOS on this AOpen makes thermal control almost worthless.
+	 * http://bugzilla.kernel.org/show_bug.cgi?id=8842
+	 */
+	{
+	 .callback = thermal_act,
+	 .ident = "AOpen i915GMm-HFS",
+	 .matches = {
+		DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+		DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
+		},
+	},
+	{
+	 .callback = thermal_psv,
+	 .ident = "AOpen i915GMm-HFS",
+	 .matches = {
+		DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+		DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
+		},
+	},
+	{
+	 .callback = thermal_tzp,
+	 .ident = "AOpen i915GMm-HFS",
+	 .matches = {
+		DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
+		DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
+		},
+	},
+	{
+	 .callback = thermal_nocrt,
+	 .ident = "Gigabyte GA-7ZX",
+	 .matches = {
+		DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
+		DMI_MATCH(DMI_BOARD_NAME, "7ZX"),
+		},
+	},
+	{}
+};
+#endif /* CONFIG_DMI */
+
 static int __init acpi_thermal_init(void)
 {
 	int result = 0;
 
+	dmi_check_system(thermal_dmi_table);
 
+	if (off) {
+		printk(KERN_NOTICE "ACPI: thermal control disabled\n");
+		return -ENODEV;
+	}
 	acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir);
 	if (!acpi_thermal_dir)
 		return -ENODEV;
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c
index 8ec6f8e..0042b7e 100644
--- a/drivers/acpi/utilities/uteval.c
+++ b/drivers/acpi/utilities/uteval.c
@@ -62,16 +62,13 @@
 static char *acpi_interfaces_supported[] = {
 	/* Operating System Vendor Strings */
 
-	"Windows 2000",
-	"Windows 2001",
-	"Windows 2001 SP0",
-	"Windows 2001 SP1",
-	"Windows 2001 SP2",
-	"Windows 2001 SP3",
-	"Windows 2001 SP4",
-	"Windows 2001.1",
-	"Windows 2001.1 SP1",	/* Added 03/2006 */
-	"Windows 2006",		/* Added 03/2006 */
+	"Windows 2000",		/* Windows 2000 */
+	"Windows 2001",		/* Windows XP */
+	"Windows 2001 SP1",	/* Windows XP SP1 */
+	"Windows 2001 SP2",	/* Windows XP SP2 */
+	"Windows 2001.1",	/* Windows Server 2003 */
+	"Windows 2001.1 SP1",	/* Windows Server 2003 SP1 - Added 03/2006 */
+	"Windows 2006",		/* Windows Vista - Added 03/2006 */
 
 	/* Feature Group Strings */
 
@@ -410,7 +407,7 @@
 
 acpi_status
 acpi_ut_execute_HID(struct acpi_namespace_node *device_node,
-		    struct acpi_device_id *hid)
+		    struct acpica_device_id *hid)
 {
 	union acpi_operand_object *obj_desc;
 	acpi_status status;
@@ -612,7 +609,7 @@
 
 acpi_status
 acpi_ut_execute_UID(struct acpi_namespace_node *device_node,
-		    struct acpi_device_id *uid)
+		    struct acpica_device_id *uid)
 {
 	union acpi_operand_object *obj_desc;
 	acpi_status status;
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index 1621655..93ea829 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -126,6 +126,7 @@
 			    "Unknown exception code: 0x%8.8X", status));
 
 		exception = "UNKNOWN_STATUS_CODE";
+		dump_stack();
 	}
 
 	return (ACPI_CAST_PTR(const char, exception));
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 00d25b3..b8a2095 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -31,8 +31,9 @@
 #include <linux/list.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-
+#include <linux/input.h>
 #include <linux/backlight.h>
+#include <linux/video_output.h>
 #include <asm/uaccess.h>
 
 #include <acpi/acpi_bus.h>
@@ -73,10 +74,16 @@
 static int acpi_video_bus_add(struct acpi_device *device);
 static int acpi_video_bus_remove(struct acpi_device *device, int type);
 
+static const struct acpi_device_id video_device_ids[] = {
+	{ACPI_VIDEO_HID, 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, video_device_ids);
+
 static struct acpi_driver acpi_video_bus = {
 	.name = "video",
 	.class = ACPI_VIDEO_CLASS,
-	.ids = ACPI_VIDEO_HID,
+	.ids = video_device_ids,
 	.ops = {
 		.add = acpi_video_bus_add,
 		.remove = acpi_video_bus_remove,
@@ -131,6 +138,8 @@
 	struct semaphore sem;
 	struct list_head video_device_list;
 	struct proc_dir_entry *dir;
+	struct input_dev *input;
+	char phys[32];	/* for input device */
 };
 
 struct acpi_video_device_flags {
@@ -169,6 +178,7 @@
 	struct acpi_device *dev;
 	struct acpi_video_device_brightness *brightness;
 	struct backlight_device *backlight;
+	struct output_device *output_dev;
 };
 
 /* bus */
@@ -272,13 +282,17 @@
 				     u32 level_current, u32 event);
 static void acpi_video_switch_brightness(struct acpi_video_device *device,
 					 int event);
+static int acpi_video_device_get_state(struct acpi_video_device *device,
+			    unsigned long *state);
+static int acpi_video_output_get(struct output_device *od);
+static int acpi_video_device_set_state(struct acpi_video_device *device, int state);
 
 /*backlight device sysfs support*/
 static int acpi_video_get_brightness(struct backlight_device *bd)
 {
 	unsigned long cur_level;
 	struct acpi_video_device *vd =
-		(struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+		(struct acpi_video_device *)bl_get_data(bd);
 	acpi_video_device_lcd_get_level_current(vd, &cur_level);
 	return (int) cur_level;
 }
@@ -287,7 +301,7 @@
 {
 	int request_level = bd->props.brightness;
 	struct acpi_video_device *vd =
-		(struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+		(struct acpi_video_device *)bl_get_data(bd);
 	acpi_video_device_lcd_set_level(vd, request_level);
 	return 0;
 }
@@ -297,6 +311,28 @@
 	.update_status  = acpi_video_set_brightness,
 };
 
+/*video output device sysfs support*/
+static int acpi_video_output_get(struct output_device *od)
+{
+	unsigned long state;
+	struct acpi_video_device *vd =
+		(struct acpi_video_device *)dev_get_drvdata(&od->dev);
+	acpi_video_device_get_state(vd, &state);
+	return (int)state;
+}
+
+static int acpi_video_output_set(struct output_device *od)
+{
+	unsigned long state = od->request_state;
+	struct acpi_video_device *vd=
+		(struct acpi_video_device *)dev_get_drvdata(&od->dev);
+	return acpi_video_device_set_state(vd, state);
+}
+
+static struct output_properties acpi_output_properties = {
+	.set_state = acpi_video_output_set,
+	.get_status = acpi_video_output_get,
+};
 /* --------------------------------------------------------------------------
                                Video Management
    -------------------------------------------------------------------------- */
@@ -381,7 +417,6 @@
 	arg0.integer.value = level;
 	status = acpi_evaluate_object(device->dev->handle, "_BCM", &args, NULL);
 
-	printk(KERN_DEBUG "set_level status: %x\n", status);
 	return status;
 }
 
@@ -531,7 +566,6 @@
 
 static void acpi_video_device_find_cap(struct acpi_video_device *device)
 {
-	acpi_integer status;
 	acpi_handle h_dummy1;
 	int i;
 	u32 max_level = 0;
@@ -565,50 +599,55 @@
 		device->cap._DSS = 1;
 	}
 
-	status = acpi_video_device_lcd_query_levels(device, &obj);
+	if (ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
 
-	if (obj && obj->type == ACPI_TYPE_PACKAGE && obj->package.count >= 2) {
-		int count = 0;
-		union acpi_object *o;
+		if (obj->package.count >= 2) {
+			int count = 0;
+			union acpi_object *o;
 
-		br = kzalloc(sizeof(*br), GFP_KERNEL);
-		if (!br) {
-			printk(KERN_ERR "can't allocate memory\n");
-		} else {
-			br->levels = kmalloc(obj->package.count *
-					     sizeof *(br->levels), GFP_KERNEL);
-			if (!br->levels)
-				goto out;
-
-			for (i = 0; i < obj->package.count; i++) {
-				o = (union acpi_object *)&obj->package.
-				    elements[i];
-				if (o->type != ACPI_TYPE_INTEGER) {
-					printk(KERN_ERR PREFIX "Invalid data\n");
-					continue;
-				}
-				br->levels[count] = (u32) o->integer.value;
-				if (br->levels[count] > max_level)
-					max_level = br->levels[count];
-				count++;
-			}
-		      out:
-			if (count < 2) {
-				kfree(br->levels);
-				kfree(br);
+			br = kzalloc(sizeof(*br), GFP_KERNEL);
+			if (!br) {
+				printk(KERN_ERR "can't allocate memory\n");
 			} else {
-				br->count = count;
-				device->brightness = br;
-				ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-						  "found %d brightness levels\n",
-						  count));
+				br->levels = kmalloc(obj->package.count *
+						     sizeof *(br->levels), GFP_KERNEL);
+				if (!br->levels)
+					goto out;
+
+				for (i = 0; i < obj->package.count; i++) {
+					o = (union acpi_object *)&obj->package.
+					    elements[i];
+					if (o->type != ACPI_TYPE_INTEGER) {
+						printk(KERN_ERR PREFIX "Invalid data\n");
+						continue;
+					}
+					br->levels[count] = (u32) o->integer.value;
+
+					if (br->levels[count] > max_level)
+						max_level = br->levels[count];
+					count++;
+				}
+			      out:
+				if (count < 2) {
+					kfree(br->levels);
+					kfree(br);
+				} else {
+					br->count = count;
+					device->brightness = br;
+					ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+							  "found %d brightness levels\n",
+							  count));
+				}
 			}
 		}
+
+	} else {
+		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available LCD brightness level\n"));
 	}
 
 	kfree(obj);
 
-	if (device->cap._BCL && device->cap._BCM && device->cap._BQC){
+	if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){
 		unsigned long tmp;
 		static int count = 0;
 		char *name;
@@ -626,6 +665,17 @@
 
 		kfree(name);
 	}
+	if (device->cap._DCS && device->cap._DSS){
+		static int count = 0;
+		char *name;
+		name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
+		if (!name)
+			return;
+		sprintf(name, "acpi_video%d", count++);
+		device->output_dev = video_output_register(name,
+				NULL, device, &acpi_output_properties);
+		kfree(name);
+	}
 	return;
 }
 
@@ -1669,6 +1719,7 @@
 					    ACPI_DEVICE_NOTIFY,
 					    acpi_video_device_notify);
 	backlight_device_unregister(device->backlight);
+	video_output_unregister(device->output_dev);
 	return 0;
 }
 
@@ -1702,7 +1753,7 @@
 
 static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
 {
-	return acpi_video_bus_DOS(video, 1, 0);
+	return acpi_video_bus_DOS(video, 0, 0);
 }
 
 static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
@@ -1714,6 +1765,9 @@
 {
 	struct acpi_video_bus *video = data;
 	struct acpi_device *device = NULL;
+	struct input_dev *input;
+	int keycode;
+
 
 	printk("video bus notify\n");
 
@@ -1721,11 +1775,13 @@
 		return;
 
 	device = video->device;
+	input = video->input;
 
 	switch (event) {
 	case ACPI_VIDEO_NOTIFY_SWITCH:	/* User requested a switch,
 					 * most likely via hotkey. */
-		acpi_bus_generate_event(device, event, 0);
+		acpi_bus_generate_proc_event(device, event, 0);
+		keycode = KEY_SWITCHVIDEOMODE;
 		break;
 
 	case ACPI_VIDEO_NOTIFY_PROBE:	/* User plugged in or removed a video
@@ -1733,22 +1789,38 @@
 		acpi_video_device_enumerate(video);
 		acpi_video_device_rebind(video);
 		acpi_video_switch_output(video, event);
-		acpi_bus_generate_event(device, event, 0);
+		acpi_bus_generate_proc_event(device, event, 0);
+		keycode = KEY_SWITCHVIDEOMODE;
 		break;
 
 	case ACPI_VIDEO_NOTIFY_CYCLE:	/* Cycle Display output hotkey pressed. */
+		acpi_video_switch_output(video, event);
+		acpi_bus_generate_proc_event(device, event, 0);
+		keycode = KEY_SWITCHVIDEOMODE;
+		break;
 	case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:	/* Next Display output hotkey pressed. */
+		acpi_video_switch_output(video, event);
+		acpi_bus_generate_proc_event(device, event, 0);
+		keycode = KEY_VIDEO_NEXT;
+		break;
 	case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:	/* previous Display output hotkey pressed. */
 		acpi_video_switch_output(video, event);
-		acpi_bus_generate_event(device, event, 0);
+		acpi_bus_generate_proc_event(device, event, 0);
+		keycode = KEY_VIDEO_PREV;
 		break;
 
 	default:
+		keycode = KEY_UNKNOWN;
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Unsupported event [0x%x]\n", event));
 		break;
 	}
 
+	input_report_key(input, keycode, 1);
+	input_sync(input);
+	input_report_key(input, keycode, 0);
+	input_sync(input);
+
 	return;
 }
 
@@ -1756,38 +1828,65 @@
 {
 	struct acpi_video_device *video_device = data;
 	struct acpi_device *device = NULL;
+	struct acpi_video_bus *bus;
+	struct input_dev *input;
+	int keycode;
 
 	if (!video_device)
 		return;
 
 	device = video_device->dev;
+	bus = video_device->video;
+	input = bus->input;
 
 	switch (event) {
-	case ACPI_VIDEO_NOTIFY_SWITCH:	/* change in status (cycle output device) */
-	case ACPI_VIDEO_NOTIFY_PROBE:	/* change in status (output device status) */
-		acpi_bus_generate_event(device, event, 0);
-		break;
 	case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:	/* Cycle brightness */
+		acpi_video_switch_brightness(video_device, event);
+		acpi_bus_generate_proc_event(device, event, 0);
+		keycode = KEY_BRIGHTNESS_CYCLE;
+		break;
 	case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:	/* Increase brightness */
+		acpi_video_switch_brightness(video_device, event);
+		acpi_bus_generate_proc_event(device, event, 0);
+		keycode = KEY_BRIGHTNESSUP;
+		break;
 	case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:	/* Decrease brightness */
+		acpi_video_switch_brightness(video_device, event);
+		acpi_bus_generate_proc_event(device, event, 0);
+		keycode = KEY_BRIGHTNESSDOWN;
+		break;
 	case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS:	/* zero brightnesss */
+		acpi_video_switch_brightness(video_device, event);
+		acpi_bus_generate_proc_event(device, event, 0);
+		keycode = KEY_BRIGHTNESS_ZERO;
+		break;
 	case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:	/* display device off */
 		acpi_video_switch_brightness(video_device, event);
-		acpi_bus_generate_event(device, event, 0);
+		acpi_bus_generate_proc_event(device, event, 0);
+		keycode = KEY_DISPLAY_OFF;
 		break;
 	default:
+		keycode = KEY_UNKNOWN;
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 				  "Unsupported event [0x%x]\n", event));
 		break;
 	}
+
+	input_report_key(input, keycode, 1);
+	input_sync(input);
+	input_report_key(input, keycode, 0);
+	input_sync(input);
+
 	return;
 }
 
+static int instance;
 static int acpi_video_bus_add(struct acpi_device *device)
 {
 	int result = 0;
 	acpi_status status = 0;
 	struct acpi_video_bus *video = NULL;
+	struct input_dev *input;
 
 
 	if (!device)
@@ -1797,6 +1896,13 @@
 	if (!video)
 		return -ENOMEM;
 
+	/* a hack to fix the duplicate name "VID" problem on T61 */
+	if (!strcmp(device->pnp.bus_id, "VID")) {
+		if (instance)
+			device->pnp.bus_id[3] = '0' + instance;
+		instance ++;
+	}
+
 	video->device = device;
 	strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
 	strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
@@ -1831,6 +1937,39 @@
 		goto end;
 	}
 
+
+	video->input = input = input_allocate_device();
+
+	snprintf(video->phys, sizeof(video->phys),
+		"%s/video/input0", acpi_device_hid(video->device));
+
+	input->name = acpi_device_name(video->device);
+	input->phys = video->phys;
+	input->id.bustype = BUS_HOST;
+	input->id.product = 0x06;
+	input->evbit[0] = BIT(EV_KEY);
+	set_bit(KEY_SWITCHVIDEOMODE, input->keybit);
+	set_bit(KEY_VIDEO_NEXT, input->keybit);
+	set_bit(KEY_VIDEO_PREV, input->keybit);
+	set_bit(KEY_BRIGHTNESS_CYCLE, input->keybit);
+	set_bit(KEY_BRIGHTNESSUP, input->keybit);
+	set_bit(KEY_BRIGHTNESSDOWN, input->keybit);
+	set_bit(KEY_BRIGHTNESS_ZERO, input->keybit);
+	set_bit(KEY_DISPLAY_OFF, input->keybit);
+	set_bit(KEY_UNKNOWN, input->keybit);
+	result = input_register_device(input);
+	if (result) {
+		acpi_remove_notify_handler(video->device->handle,
+						ACPI_DEVICE_NOTIFY,
+						acpi_video_bus_notify);
+		acpi_video_bus_stop_devices(video);
+		acpi_video_bus_put_devices(video);
+		kfree(video->attached_array);
+		acpi_video_bus_remove_fs(device);
+		goto end;
+        }
+
+
 	printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s  rom: %s  post: %s)\n",
 	       ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
 	       video->flags.multihead ? "yes" : "no",
@@ -1864,6 +2003,7 @@
 	acpi_video_bus_put_devices(video);
 	acpi_video_bus_remove_fs(device);
 
+	input_unregister_device(video->input);
 	kfree(video->attached_array);
 	kfree(video);
 
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 268e301..6b94fb7 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -44,15 +44,12 @@
 }
 
 #ifdef CONFIG_HOTPLUG
-static int amba_uevent(struct device *dev, char **envp, int nr_env, char *buf, int bufsz)
+static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct amba_device *pcdev = to_amba_device(dev);
-	int retval = 0, i = 0, len = 0;
+	int retval = 0;
 
-	retval = add_uevent_var(envp, nr_env, &i,
-				buf, bufsz, &len,
-				"AMBA_ID=%08x", pcdev->periphid);
-	envp[i] = NULL;
+	retval = add_uevent_var(env, "AMBA_ID=%08x", pcdev->periphid);
 	return retval;
 }
 #else
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index d8046a1..4672066 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -173,6 +173,15 @@
 	help
 	  This option enables support for Initio 162x Serial ATA.
 
+config PATA_ACPI
+	tristate "ACPI firmware driver for PATA"
+	depends on ATA_ACPI
+	help
+	  This option enables an ACPI method driver which drives
+	  motherboard PATA controller interfaces through the ACPI
+	  firmware in the BIOS. This driver can sometimes handle
+	  otherwise unsupported hardware.
+
 config PATA_ALI
 	tristate "ALi PATA support (Experimental)"
 	depends on PCI && EXPERIMENTAL
@@ -192,16 +201,25 @@
 	  If unsure, say N.
 
 config PATA_ARTOP
-	tristate "ARTOP 6210/6260 PATA support (Experimental)"
-	depends on PCI && EXPERIMENTAL
+	tristate "ARTOP 6210/6260 PATA support"
+	depends on PCI
 	help
 	  This option enables support for ARTOP PATA controllers.
 
 	  If unsure, say N.
 
+config PATA_AT32
+	tristate "Atmel AVR32 PATA support (Experimental)"
+	depends on AVR32 && PLATFORM_AT32AP && EXPERIMENTAL
+	help
+	  This option enables support for the IDE devices on the
+	  Atmel AT32AP platform.
+
+	  If unsure, say N.
+
 config PATA_ATIIXP
-	tristate "ATI PATA support (Experimental)"
-	depends on PCI && EXPERIMENTAL
+	tristate "ATI PATA support"
+	depends on PCI
 	help
 	  This option enables support for the ATI ATA interfaces
 	  found on the many ATI chipsets.
@@ -219,8 +237,8 @@
 	  If unsure, say N.
 
 config PATA_CMD64X
-	tristate "CMD64x PATA support (Very Experimental)"
-	depends on PCI&& EXPERIMENTAL
+	tristate "CMD64x PATA support"
+	depends on PCI
 	help
 	  This option enables support for the CMD64x series chips
 	  except for the CMD640.
@@ -282,8 +300,8 @@
 	  If unsure, say N.
 
 config PATA_HPT366
-	tristate "HPT 366/368 PATA support (Experimental)"
-	depends on PCI && EXPERIMENTAL
+	tristate "HPT 366/368 PATA support"
+	depends on PCI
 	help
 	  This option enables support for the HPT 366 and 368
 	  PATA controllers via the new ATA layer.
@@ -432,6 +450,15 @@
 
 	  If unsure, say N.
 
+config PATA_NS87415
+	tristate "Nat Semi NS87415 PATA support (Experimental)"
+	depends on PCI && EXPERIMENTAL
+	help
+	  This option enables support for the National Semiconductor
+	  NS87415 PCI-IDE controller.
+
+	  If unsure, say N.
+
 config PATA_OPTI
 	tristate "OPTI621/6215 PATA support (Very Experimental)"
 	depends on PCI && EXPERIMENTAL
@@ -596,4 +623,20 @@
 
 	  If unsure, say N.
 
+config PATA_BF54X
+	tristate "Blackfin 54x ATAPI support"
+	depends on BF542 || BF548 || BF549
+	help
+	  This option enables support for the built-in ATAPI controller on
+	  Blackfin 54x family chips.
+
+	  If unsure, say N.
+
+config PATA_BF54X_DMA
+	bool "DMA mode"
+	depends on PATA_BF54X
+	default y
+	help
+	  Enable DMA mode for Blackfin ATAPI controller.
+
 endif # ATA
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 8149c68..2a63645 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -21,6 +21,7 @@
 obj-$(CONFIG_PATA_ALI)		+= pata_ali.o
 obj-$(CONFIG_PATA_AMD)		+= pata_amd.o
 obj-$(CONFIG_PATA_ARTOP)	+= pata_artop.o
+obj-$(CONFIG_PATA_AT32)		+= pata_at32.o
 obj-$(CONFIG_PATA_ATIIXP)	+= pata_atiixp.o
 obj-$(CONFIG_PATA_CMD640_PCI)	+= pata_cmd640.o
 obj-$(CONFIG_PATA_CMD64X)	+= pata_cmd64x.o
@@ -39,6 +40,7 @@
 obj-$(CONFIG_PATA_JMICRON)	+= pata_jmicron.o
 obj-$(CONFIG_PATA_NETCELL)	+= pata_netcell.o
 obj-$(CONFIG_PATA_NS87410)	+= pata_ns87410.o
+obj-$(CONFIG_PATA_NS87415)	+= pata_ns87415.o
 obj-$(CONFIG_PATA_OPTI)		+= pata_opti.o
 obj-$(CONFIG_PATA_OPTIDMA)	+= pata_optidma.o
 obj-$(CONFIG_PATA_MPC52xx)	+= pata_mpc52xx.o
@@ -61,12 +63,16 @@
 obj-$(CONFIG_PATA_TRIFLEX)	+= pata_triflex.o
 obj-$(CONFIG_PATA_IXP4XX_CF)	+= pata_ixp4xx_cf.o
 obj-$(CONFIG_PATA_SCC)		+= pata_scc.o
+obj-$(CONFIG_PATA_BF54X)	+= pata_bf54x.o
 obj-$(CONFIG_PATA_PLATFORM)	+= pata_platform.o
 obj-$(CONFIG_PATA_ICSIDE)	+= pata_icside.o
+# Should be last but two libata driver
+obj-$(CONFIG_PATA_ACPI)		+= pata_acpi.o
 # Should be last but one libata driver
 obj-$(CONFIG_ATA_GENERIC)	+= ata_generic.o
 # Should be last libata driver
 obj-$(CONFIG_PATA_LEGACY)	+= pata_legacy.o
 
-libata-objs	:= libata-core.o libata-scsi.o libata-sff.o libata-eh.o
+libata-objs	:= libata-core.o libata-scsi.o libata-sff.o libata-eh.o \
+		   libata-pmp.o
 libata-$(CONFIG_ATA_ACPI)	+= libata-acpi.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 11e4eb9..10bc3f6 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -46,7 +46,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"ahci"
-#define DRV_VERSION	"2.3"
+#define DRV_VERSION	"3.0"
 
 
 enum {
@@ -77,11 +77,10 @@
 	RX_FIS_UNK		= 0x60, /* offset of Unknown FIS data */
 
 	board_ahci		= 0,
-	board_ahci_pi		= 1,
-	board_ahci_vt8251	= 2,
-	board_ahci_ign_iferr	= 3,
-	board_ahci_sb600	= 4,
-	board_ahci_mv		= 5,
+	board_ahci_vt8251	= 1,
+	board_ahci_ign_iferr	= 2,
+	board_ahci_sb600	= 3,
+	board_ahci_mv		= 4,
 
 	/* global controller registers */
 	HOST_CAP		= 0x00, /* host capabilities */
@@ -97,8 +96,10 @@
 
 	/* HOST_CAP bits */
 	HOST_CAP_SSC		= (1 << 14), /* Slumber capable */
+	HOST_CAP_PMP		= (1 << 17), /* Port Multiplier support */
 	HOST_CAP_CLO		= (1 << 24), /* Command List Override support */
 	HOST_CAP_SSS		= (1 << 27), /* Staggered Spin-up */
+	HOST_CAP_SNTF		= (1 << 29), /* SNotification register */
 	HOST_CAP_NCQ		= (1 << 30), /* Native Command Queueing */
 	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
 
@@ -113,11 +114,11 @@
 	PORT_TFDATA		= 0x20,	/* taskfile data */
 	PORT_SIG		= 0x24,	/* device TF signature */
 	PORT_CMD_ISSUE		= 0x38, /* command issue */
-	PORT_SCR		= 0x28, /* SATA phy register block */
 	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
 	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
 	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
 	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */
+	PORT_SCR_NTF		= 0x3c, /* SATA phy register: SNotification */
 
 	/* PORT_IRQ_{STAT,MASK} bits */
 	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
@@ -143,7 +144,8 @@
 				  PORT_IRQ_IF_ERR |
 				  PORT_IRQ_CONNECT |
 				  PORT_IRQ_PHYRDY |
-				  PORT_IRQ_UNK_FIS,
+				  PORT_IRQ_UNK_FIS |
+				  PORT_IRQ_BAD_PMP,
 	PORT_IRQ_ERROR		= PORT_IRQ_FREEZE |
 				  PORT_IRQ_TF_ERR |
 				  PORT_IRQ_HBUS_DATA_ERR,
@@ -153,6 +155,7 @@
 
 	/* PORT_CMD bits */
 	PORT_CMD_ATAPI		= (1 << 24), /* Device is ATAPI */
+	PORT_CMD_PMP		= (1 << 17), /* PMP attached */
 	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
 	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
 	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
@@ -166,19 +169,22 @@
 	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
 	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
 
+	/* hpriv->flags bits */
+	AHCI_HFLAG_NO_NCQ		= (1 << 0),
+	AHCI_HFLAG_IGN_IRQ_IF_ERR	= (1 << 1), /* ignore IRQ_IF_ERR */
+	AHCI_HFLAG_IGN_SERR_INTERNAL	= (1 << 2), /* ignore SERR_INTERNAL */
+	AHCI_HFLAG_32BIT_ONLY		= (1 << 3), /* force 32bit */
+	AHCI_HFLAG_MV_PATA		= (1 << 4), /* PATA port */
+	AHCI_HFLAG_NO_MSI		= (1 << 5), /* no PCI MSI */
+	AHCI_HFLAG_NO_PMP		= (1 << 6), /* no PMP */
+
 	/* ap->flags bits */
-	AHCI_FLAG_NO_NCQ		= (1 << 24),
-	AHCI_FLAG_IGN_IRQ_IF_ERR	= (1 << 25), /* ignore IRQ_IF_ERR */
-	AHCI_FLAG_HONOR_PI		= (1 << 26), /* honor PORTS_IMPL */
-	AHCI_FLAG_IGN_SERR_INTERNAL	= (1 << 27), /* ignore SERR_INTERNAL */
-	AHCI_FLAG_32BIT_ONLY		= (1 << 28), /* force 32bit */
-	AHCI_FLAG_MV_PATA		= (1 << 29), /* PATA port */
-	AHCI_FLAG_NO_MSI		= (1 << 30), /* no PCI MSI */
+	AHCI_FLAG_NO_HOTPLUG		= (1 << 24), /* ignore PxSERR.DIAG.N */
 
 	AHCI_FLAG_COMMON		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 					  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-					  ATA_FLAG_SKIP_D2H_BSY |
-					  ATA_FLAG_ACPI_SATA,
+					  ATA_FLAG_ACPI_SATA | ATA_FLAG_AN,
+	AHCI_LFLAG_COMMON		= ATA_LFLAG_SKIP_D2H_BSY,
 };
 
 struct ahci_cmd_hdr {
@@ -197,6 +203,7 @@
 };
 
 struct ahci_host_priv {
+	unsigned int		flags;		/* AHCI_HFLAG_* */
 	u32			cap;		/* cap to use */
 	u32			port_map;	/* port map to use */
 	u32			saved_cap;	/* saved initial cap */
@@ -204,6 +211,7 @@
 };
 
 struct ahci_port_priv {
+	struct ata_link		*active_link;
 	struct ahci_cmd_hdr	*cmd_slot;
 	dma_addr_t		cmd_slot_dma;
 	void			*cmd_tbl;
@@ -214,10 +222,11 @@
 	unsigned int		ncq_saw_d2h:1;
 	unsigned int		ncq_saw_dmas:1;
 	unsigned int		ncq_saw_sdb:1;
+	u32 			intr_mask;	/* interrupts to enable */
 };
 
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
 static void ahci_irq_clear(struct ata_port *ap);
@@ -228,6 +237,8 @@
 static u8 ahci_check_status(struct ata_port *ap);
 static void ahci_freeze(struct ata_port *ap);
 static void ahci_thaw(struct ata_port *ap);
+static void ahci_pmp_attach(struct ata_port *ap);
+static void ahci_pmp_detach(struct ata_port *ap);
 static void ahci_error_handler(struct ata_port *ap);
 static void ahci_vt8251_error_handler(struct ata_port *ap);
 static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
@@ -261,20 +272,17 @@
 };
 
 static const struct ata_port_operations ahci_ops = {
-	.port_disable		= ata_port_disable,
-
 	.check_status		= ahci_check_status,
 	.check_altstatus	= ahci_check_status,
 	.dev_select		= ata_noop_dev_select,
 
 	.tf_read		= ahci_tf_read,
 
+	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
 	.qc_prep		= ahci_qc_prep,
 	.qc_issue		= ahci_qc_issue,
 
 	.irq_clear		= ahci_irq_clear,
-	.irq_on			= ata_dummy_irq_on,
-	.irq_ack		= ata_dummy_irq_ack,
 
 	.scr_read		= ahci_scr_read,
 	.scr_write		= ahci_scr_write,
@@ -285,6 +293,9 @@
 	.error_handler		= ahci_error_handler,
 	.post_internal_cmd	= ahci_post_internal_cmd,
 
+	.pmp_attach		= ahci_pmp_attach,
+	.pmp_detach		= ahci_pmp_detach,
+
 #ifdef CONFIG_PM
 	.port_suspend		= ahci_port_suspend,
 	.port_resume		= ahci_port_resume,
@@ -295,20 +306,17 @@
 };
 
 static const struct ata_port_operations ahci_vt8251_ops = {
-	.port_disable		= ata_port_disable,
-
 	.check_status		= ahci_check_status,
 	.check_altstatus	= ahci_check_status,
 	.dev_select		= ata_noop_dev_select,
 
 	.tf_read		= ahci_tf_read,
 
+	.qc_defer		= sata_pmp_qc_defer_cmd_switch,
 	.qc_prep		= ahci_qc_prep,
 	.qc_issue		= ahci_qc_issue,
 
 	.irq_clear		= ahci_irq_clear,
-	.irq_on			= ata_dummy_irq_on,
-	.irq_ack		= ata_dummy_irq_ack,
 
 	.scr_read		= ahci_scr_read,
 	.scr_write		= ahci_scr_write,
@@ -319,6 +327,9 @@
 	.error_handler		= ahci_vt8251_error_handler,
 	.post_internal_cmd	= ahci_post_internal_cmd,
 
+	.pmp_attach		= ahci_pmp_attach,
+	.pmp_detach		= ahci_pmp_detach,
+
 #ifdef CONFIG_PM
 	.port_suspend		= ahci_port_suspend,
 	.port_resume		= ahci_port_resume,
@@ -328,53 +339,52 @@
 	.port_stop		= ahci_port_stop,
 };
 
+#define AHCI_HFLAGS(flags)	.private_data	= (void *)(flags)
+
 static const struct ata_port_info ahci_port_info[] = {
 	/* board_ahci */
 	{
 		.flags		= AHCI_FLAG_COMMON,
-		.pio_mask	= 0x1f, /* pio0-4 */
-		.udma_mask	= ATA_UDMA6,
-		.port_ops	= &ahci_ops,
-	},
-	/* board_ahci_pi */
-	{
-		.flags		= AHCI_FLAG_COMMON | AHCI_FLAG_HONOR_PI,
+		.link_flags	= AHCI_LFLAG_COMMON,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.udma_mask	= ATA_UDMA6,
 		.port_ops	= &ahci_ops,
 	},
 	/* board_ahci_vt8251 */
 	{
-		.flags		= AHCI_FLAG_COMMON | ATA_FLAG_HRST_TO_RESUME |
-				  AHCI_FLAG_NO_NCQ,
+		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
+		.flags		= AHCI_FLAG_COMMON,
+		.link_flags	= AHCI_LFLAG_COMMON | ATA_LFLAG_HRST_TO_RESUME,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.udma_mask	= ATA_UDMA6,
 		.port_ops	= &ahci_vt8251_ops,
 	},
 	/* board_ahci_ign_iferr */
 	{
-		.flags		= AHCI_FLAG_COMMON | AHCI_FLAG_IGN_IRQ_IF_ERR,
+		AHCI_HFLAGS	(AHCI_HFLAG_IGN_IRQ_IF_ERR),
+		.flags		= AHCI_FLAG_COMMON,
+		.link_flags	= AHCI_LFLAG_COMMON,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.udma_mask	= ATA_UDMA6,
 		.port_ops	= &ahci_ops,
 	},
 	/* board_ahci_sb600 */
 	{
-		.flags		= AHCI_FLAG_COMMON |
-				  AHCI_FLAG_IGN_SERR_INTERNAL |
-				  AHCI_FLAG_32BIT_ONLY,
+		AHCI_HFLAGS	(AHCI_HFLAG_IGN_SERR_INTERNAL |
+				 AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_PMP),
+		.flags		= AHCI_FLAG_COMMON,
+		.link_flags	= AHCI_LFLAG_COMMON,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.udma_mask	= ATA_UDMA6,
 		.port_ops	= &ahci_ops,
 	},
 	/* board_ahci_mv */
 	{
-		.sht		= &ahci_sht,
+		AHCI_HFLAGS	(AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
+				 AHCI_HFLAG_MV_PATA),
 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-				  ATA_FLAG_SKIP_D2H_BSY | AHCI_FLAG_HONOR_PI |
-				  AHCI_FLAG_NO_NCQ | AHCI_FLAG_NO_MSI |
-				  AHCI_FLAG_MV_PATA,
+				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
+		.link_flags	= AHCI_LFLAG_COMMON,
 		.pio_mask	= 0x1f, /* pio0-4 */
 		.udma_mask	= ATA_UDMA6,
 		.port_ops	= &ahci_ops,
@@ -393,23 +403,25 @@
 	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
 	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
 	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
-	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci_pi }, /* ICH8 */
-	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci_pi }, /* ICH8 */
-	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci_pi }, /* ICH8 */
-	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci_pi }, /* ICH8M */
-	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci_pi }, /* ICH8M */
-	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci_pi }, /* ICH9 */
-	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci_pi }, /* ICH9 */
-	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci_pi }, /* ICH9 */
-	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci_pi }, /* ICH9 */
-	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci_pi }, /* ICH9 */
-	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci_pi }, /* ICH9M */
-	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci_pi }, /* ICH9M */
-	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci_pi }, /* ICH9M */
-	{ PCI_VDEVICE(INTEL, 0x292c), board_ahci_pi }, /* ICH9M */
-	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci_pi }, /* ICH9M */
-	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci_pi }, /* ICH9 */
-	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci_pi }, /* ICH9M */
+	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
+	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
+	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
+	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
+	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
+	{ PCI_VDEVICE(INTEL, 0x2922), board_ahci }, /* ICH9 */
+	{ PCI_VDEVICE(INTEL, 0x2923), board_ahci }, /* ICH9 */
+	{ PCI_VDEVICE(INTEL, 0x2924), board_ahci }, /* ICH9 */
+	{ PCI_VDEVICE(INTEL, 0x2925), board_ahci }, /* ICH9 */
+	{ PCI_VDEVICE(INTEL, 0x2927), board_ahci }, /* ICH9 */
+	{ PCI_VDEVICE(INTEL, 0x2929), board_ahci }, /* ICH9M */
+	{ PCI_VDEVICE(INTEL, 0x292a), board_ahci }, /* ICH9M */
+	{ PCI_VDEVICE(INTEL, 0x292b), board_ahci }, /* ICH9M */
+	{ PCI_VDEVICE(INTEL, 0x292c), board_ahci }, /* ICH9M */
+	{ PCI_VDEVICE(INTEL, 0x292f), board_ahci }, /* ICH9M */
+	{ PCI_VDEVICE(INTEL, 0x294d), board_ahci }, /* ICH9 */
+	{ PCI_VDEVICE(INTEL, 0x294e), board_ahci }, /* ICH9M */
+	{ PCI_VDEVICE(INTEL, 0x502a), board_ahci }, /* Tolapai */
+	{ PCI_VDEVICE(INTEL, 0x502b), board_ahci }, /* Tolapai */
 
 	/* JMicron 360/1/3/5/6, match class to avoid IDE function */
 	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -417,7 +429,12 @@
 
 	/* ATI */
 	{ PCI_VDEVICE(ATI, 0x4380), board_ahci_sb600 }, /* ATI SB600 */
-	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700 */
+	{ PCI_VDEVICE(ATI, 0x4390), board_ahci_sb600 }, /* ATI SB700/800 */
+	{ PCI_VDEVICE(ATI, 0x4391), board_ahci_sb600 }, /* ATI SB700/800 */
+	{ PCI_VDEVICE(ATI, 0x4392), board_ahci_sb600 }, /* ATI SB700/800 */
+	{ PCI_VDEVICE(ATI, 0x4393), board_ahci_sb600 }, /* ATI SB700/800 */
+	{ PCI_VDEVICE(ATI, 0x4394), board_ahci_sb600 }, /* ATI SB700/800 */
+	{ PCI_VDEVICE(ATI, 0x4395), board_ahci_sb600 }, /* ATI SB700/800 */
 
 	/* VIA */
 	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
@@ -468,6 +485,14 @@
 	{ PCI_VDEVICE(NVIDIA, 0x0ad9), board_ahci },		/* MCP77 */
 	{ PCI_VDEVICE(NVIDIA, 0x0ada), board_ahci },		/* MCP77 */
 	{ PCI_VDEVICE(NVIDIA, 0x0adb), board_ahci },		/* MCP77 */
+	{ PCI_VDEVICE(NVIDIA, 0x0ab8), board_ahci },		/* MCP79 */
+	{ PCI_VDEVICE(NVIDIA, 0x0ab9), board_ahci },		/* MCP79 */
+	{ PCI_VDEVICE(NVIDIA, 0x0aba), board_ahci },		/* MCP79 */
+	{ PCI_VDEVICE(NVIDIA, 0x0abb), board_ahci },		/* MCP79 */
+	{ PCI_VDEVICE(NVIDIA, 0x0abc), board_ahci },		/* MCP79 */
+	{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci },		/* MCP79 */
+	{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci },		/* MCP79 */
+	{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci },		/* MCP79 */
 
 	/* SiS */
 	{ PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
@@ -518,7 +543,6 @@
 /**
  *	ahci_save_initial_config - Save and fixup initial config values
  *	@pdev: target PCI device
- *	@pi: associated ATA port info
  *	@hpriv: host private area to store config values
  *
  *	Some registers containing configuration info might be setup by
@@ -532,7 +556,6 @@
  *	None.
  */
 static void ahci_save_initial_config(struct pci_dev *pdev,
-				     const struct ata_port_info *pi,
 				     struct ahci_host_priv *hpriv)
 {
 	void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
@@ -545,21 +568,23 @@
 	hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
 	hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
 
-	/* some chips lie about 64bit support */
-	if ((cap & HOST_CAP_64) && (pi->flags & AHCI_FLAG_32BIT_ONLY)) {
+	/* some chips have errata preventing 64bit use */
+	if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
 		dev_printk(KERN_INFO, &pdev->dev,
 			   "controller can't do 64bit DMA, forcing 32bit\n");
 		cap &= ~HOST_CAP_64;
 	}
 
-	/* fixup zero port_map */
-	if (!port_map) {
-		port_map = (1 << ahci_nr_ports(cap)) - 1;
-		dev_printk(KERN_WARNING, &pdev->dev,
-			   "PORTS_IMPL is zero, forcing 0x%x\n", port_map);
+	if ((cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_NO_NCQ)) {
+		dev_printk(KERN_INFO, &pdev->dev,
+			   "controller can't do NCQ, turning off CAP_NCQ\n");
+		cap &= ~HOST_CAP_NCQ;
+	}
 
-		/* write the fixed up value to the PI register */
-		hpriv->saved_port_map = port_map;
+	if ((cap && HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) {
+		dev_printk(KERN_INFO, &pdev->dev,
+			   "controller can't do PMP, turning off CAP_PMP\n");
+		cap &= ~HOST_CAP_PMP;
 	}
 
 	/*
@@ -567,7 +592,7 @@
 	 * is asserted through the standard AHCI port
 	 * presence register, as bit 4 (counting from 0)
 	 */
-	if (pi->flags & AHCI_FLAG_MV_PATA) {
+	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
 		dev_printk(KERN_ERR, &pdev->dev,
 			   "MV_AHCI HACK: port_map %x -> %x\n",
 			   hpriv->port_map,
@@ -577,7 +602,7 @@
 	}
 
 	/* cross check port_map and cap.n_ports */
-	if (pi->flags & AHCI_FLAG_HONOR_PI) {
+	if (port_map) {
 		u32 tmp_port_map = port_map;
 		int n_ports = ahci_nr_ports(cap);
 
@@ -588,17 +613,26 @@
 			}
 		}
 
-		/* Whine if inconsistent.  No need to update cap.
-		 * port_map is used to determine number of ports.
+		/* If n_ports and port_map are inconsistent, whine and
+		 * clear port_map and let it be generated from n_ports.
 		 */
-		if (n_ports || tmp_port_map)
+		if (n_ports || tmp_port_map) {
 			dev_printk(KERN_WARNING, &pdev->dev,
 				   "nr_ports (%u) and implemented port map "
-				   "(0x%x) don't match\n",
+				   "(0x%x) don't match, using nr_ports\n",
 				   ahci_nr_ports(cap), port_map);
-	} else {
-		/* fabricate port_map from cap.nr_ports */
+			port_map = 0;
+		}
+	}
+
+	/* fabricate port_map from cap.nr_ports */
+	if (!port_map) {
 		port_map = (1 << ahci_nr_ports(cap)) - 1;
+		dev_printk(KERN_WARNING, &pdev->dev,
+			   "forcing PORTS_IMPL to 0x%x\n", port_map);
+
+		/* write the fixed up value to the PI register */
+		hpriv->saved_port_map = port_map;
 	}
 
 	/* record values to use during operation */
@@ -625,38 +659,45 @@
 	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
 }
 
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
+static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
 {
-	unsigned int sc_reg;
+	static const int offset[] = {
+		[SCR_STATUS]		= PORT_SCR_STAT,
+		[SCR_CONTROL]		= PORT_SCR_CTL,
+		[SCR_ERROR]		= PORT_SCR_ERR,
+		[SCR_ACTIVE]		= PORT_SCR_ACT,
+		[SCR_NOTIFICATION]	= PORT_SCR_NTF,
+	};
+	struct ahci_host_priv *hpriv = ap->host->private_data;
 
-	switch (sc_reg_in) {
-	case SCR_STATUS:	sc_reg = 0; break;
-	case SCR_CONTROL:	sc_reg = 1; break;
-	case SCR_ERROR:		sc_reg = 2; break;
-	case SCR_ACTIVE:	sc_reg = 3; break;
-	default:
-		return 0xffffffffU;
-	}
-
-	return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+	if (sc_reg < ARRAY_SIZE(offset) &&
+	    (sc_reg != SCR_NOTIFICATION || (hpriv->cap & HOST_CAP_SNTF)))
+		return offset[sc_reg];
+	return 0;
 }
 
-
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
-			       u32 val)
+static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
-	unsigned int sc_reg;
+	void __iomem *port_mmio = ahci_port_base(ap);
+	int offset = ahci_scr_offset(ap, sc_reg);
 
-	switch (sc_reg_in) {
-	case SCR_STATUS:	sc_reg = 0; break;
-	case SCR_CONTROL:	sc_reg = 1; break;
-	case SCR_ERROR:		sc_reg = 2; break;
-	case SCR_ACTIVE:	sc_reg = 3; break;
-	default:
-		return;
+	if (offset) {
+		*val = readl(port_mmio + offset);
+		return 0;
 	}
+	return -EINVAL;
+}
 
-	writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+	void __iomem *port_mmio = ahci_port_base(ap);
+	int offset = ahci_scr_offset(ap, sc_reg);
+
+	if (offset) {
+		writel(val, port_mmio + offset);
+		return 0;
+	}
+	return -EINVAL;
 }
 
 static void ahci_start_engine(struct ata_port *ap)
@@ -817,8 +858,14 @@
 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
 	u32 tmp;
 
-	/* global controller reset */
+	/* we must be in AHCI mode, before using anything
+	 * AHCI-specific, such as HOST_RESET.
+	 */
 	tmp = readl(mmio + HOST_CTL);
+	if (!(tmp & HOST_AHCI_EN))
+		writel(tmp | HOST_AHCI_EN, mmio + HOST_CTL);
+
+	/* global controller reset */
 	if ((tmp & HOST_RESET) == 0) {
 		writel(tmp | HOST_RESET, mmio + HOST_CTL);
 		readl(mmio + HOST_CTL); /* flush */
@@ -885,13 +932,14 @@
 
 static void ahci_init_controller(struct ata_host *host)
 {
+	struct ahci_host_priv *hpriv = host->private_data;
 	struct pci_dev *pdev = to_pci_dev(host->dev);
 	void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
 	int i;
 	void __iomem *port_mmio;
 	u32 tmp;
 
-	if (host->ports[0]->flags & AHCI_FLAG_MV_PATA) {
+	if (hpriv->flags & AHCI_HFLAG_MV_PATA) {
 		port_mmio = __ahci_port_base(host, 4);
 
 		writel(0, port_mmio + PORT_IRQ_MASK);
@@ -948,85 +996,115 @@
 	pp->cmd_slot[tag].tbl_addr_hi = cpu_to_le32((cmd_tbl_dma >> 16) >> 16);
 }
 
-static int ahci_clo(struct ata_port *ap)
+static int ahci_kick_engine(struct ata_port *ap, int force_restart)
 {
 	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
 	struct ahci_host_priv *hpriv = ap->host->private_data;
 	u32 tmp;
+	int busy, rc;
 
-	if (!(hpriv->cap & HOST_CAP_CLO))
-		return -EOPNOTSUPP;
+	/* do we need to kick the port? */
+	busy = ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ);
+	if (!busy && !force_restart)
+		return 0;
 
+	/* stop engine */
+	rc = ahci_stop_engine(ap);
+	if (rc)
+		goto out_restart;
+
+	/* need to do CLO? */
+	if (!busy) {
+		rc = 0;
+		goto out_restart;
+	}
+
+	if (!(hpriv->cap & HOST_CAP_CLO)) {
+		rc = -EOPNOTSUPP;
+		goto out_restart;
+	}
+
+	/* perform CLO */
 	tmp = readl(port_mmio + PORT_CMD);
 	tmp |= PORT_CMD_CLO;
 	writel(tmp, port_mmio + PORT_CMD);
 
+	rc = 0;
 	tmp = ata_wait_register(port_mmio + PORT_CMD,
 				PORT_CMD_CLO, PORT_CMD_CLO, 1, 500);
 	if (tmp & PORT_CMD_CLO)
-		return -EIO;
+		rc = -EIO;
+
+	/* restart engine */
+ out_restart:
+	ahci_start_engine(ap);
+	return rc;
+}
+
+static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
+				struct ata_taskfile *tf, int is_cmd, u16 flags,
+				unsigned long timeout_msec)
+{
+	const u32 cmd_fis_len = 5; /* five dwords */
+	struct ahci_port_priv *pp = ap->private_data;
+	void __iomem *port_mmio = ahci_port_base(ap);
+	u8 *fis = pp->cmd_tbl;
+	u32 tmp;
+
+	/* prep the command */
+	ata_tf_to_fis(tf, pmp, is_cmd, fis);
+	ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
+
+	/* issue & wait */
+	writel(1, port_mmio + PORT_CMD_ISSUE);
+
+	if (timeout_msec) {
+		tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1,
+					1, timeout_msec);
+		if (tmp & 0x1) {
+			ahci_kick_engine(ap, 1);
+			return -EBUSY;
+		}
+	} else
+		readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
 
 	return 0;
 }
 
-static int ahci_softreset(struct ata_port *ap, unsigned int *class,
-			  unsigned long deadline)
+static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
+			     int pmp, unsigned long deadline)
 {
-	struct ahci_port_priv *pp = ap->private_data;
-	void __iomem *port_mmio = ahci_port_base(ap);
-	const u32 cmd_fis_len = 5; /* five dwords */
+	struct ata_port *ap = link->ap;
 	const char *reason = NULL;
+	unsigned long now, msecs;
 	struct ata_taskfile tf;
-	u32 tmp;
-	u8 *fis;
 	int rc;
 
 	DPRINTK("ENTER\n");
 
-	if (ata_port_offline(ap)) {
+	if (ata_link_offline(link)) {
 		DPRINTK("PHY reports no device\n");
 		*class = ATA_DEV_NONE;
 		return 0;
 	}
 
 	/* prepare for SRST (AHCI-1.1 10.4.1) */
-	rc = ahci_stop_engine(ap);
-	if (rc) {
-		reason = "failed to stop engine";
-		goto fail_restart;
-	}
+	rc = ahci_kick_engine(ap, 1);
+	if (rc)
+		ata_link_printk(link, KERN_WARNING,
+				"failed to reset engine (errno=%d)", rc);
 
-	/* check BUSY/DRQ, perform Command List Override if necessary */
-	if (ahci_check_status(ap) & (ATA_BUSY | ATA_DRQ)) {
-		rc = ahci_clo(ap);
-
-		if (rc == -EOPNOTSUPP) {
-			reason = "port busy but CLO unavailable";
-			goto fail_restart;
-		} else if (rc) {
-			reason = "port busy but CLO failed";
-			goto fail_restart;
-		}
-	}
-
-	/* restart engine */
-	ahci_start_engine(ap);
-
-	ata_tf_init(ap->device, &tf);
-	fis = pp->cmd_tbl;
+	ata_tf_init(link->device, &tf);
 
 	/* issue the first D2H Register FIS */
-	ahci_fill_cmd_slot(pp, 0,
-			   cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
+	msecs = 0;
+	now = jiffies;
+	if (time_after(now, deadline))
+		msecs = jiffies_to_msecs(deadline - now);
 
 	tf.ctl |= ATA_SRST;
-	ata_tf_to_fis(&tf, fis, 0);
-	fis[1] &= ~(1 << 7);	/* turn off Command FIS bit */
-
-	writel(1, port_mmio + PORT_CMD_ISSUE);
-
-	tmp = ata_wait_register(port_mmio + PORT_CMD_ISSUE, 0x1, 0x1, 1, 500);
-	if (tmp & 0x1) {
+	if (ahci_exec_polled_cmd(ap, pmp, &tf, 0,
+				 AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY, msecs)) {
 		rc = -EIO;
 		reason = "1st FIS failed";
 		goto fail;
@@ -1036,14 +1114,8 @@
 	msleep(1);
 
 	/* issue the second D2H Register FIS */
-	ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
-
 	tf.ctl &= ~ATA_SRST;
-	ata_tf_to_fis(&tf, fis, 0);
-	fis[1] &= ~(1 << 7);	/* turn off Command FIS bit */
-
-	writel(1, port_mmio + PORT_CMD_ISSUE);
-	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
+	ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
 
 	/* spec mandates ">= 2ms" before checking status.
 	 * We wait 150ms, because that was the magic delay used for
@@ -1066,16 +1138,26 @@
 	DPRINTK("EXIT, class=%u\n", *class);
 	return 0;
 
- fail_restart:
-	ahci_start_engine(ap);
  fail:
-	ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
+	ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
 	return rc;
 }
 
-static int ahci_hardreset(struct ata_port *ap, unsigned int *class,
+static int ahci_softreset(struct ata_link *link, unsigned int *class,
 			  unsigned long deadline)
 {
+	int pmp = 0;
+
+	if (link->ap->flags & ATA_FLAG_PMP)
+		pmp = SATA_PMP_CTRL_PORT;
+
+	return ahci_do_softreset(link, class, pmp, deadline);
+}
+
+static int ahci_hardreset(struct ata_link *link, unsigned int *class,
+			  unsigned long deadline)
+{
+	struct ata_port *ap = link->ap;
 	struct ahci_port_priv *pp = ap->private_data;
 	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
 	struct ata_taskfile tf;
@@ -1086,37 +1168,40 @@
 	ahci_stop_engine(ap);
 
 	/* clear D2H reception area to properly wait for D2H FIS */
-	ata_tf_init(ap->device, &tf);
+	ata_tf_init(link->device, &tf);
 	tf.command = 0x80;
-	ata_tf_to_fis(&tf, d2h_fis, 0);
+	ata_tf_to_fis(&tf, 0, 0, d2h_fis);
 
-	rc = sata_std_hardreset(ap, class, deadline);
+	rc = sata_std_hardreset(link, class, deadline);
 
 	ahci_start_engine(ap);
 
-	if (rc == 0 && ata_port_online(ap))
+	if (rc == 0 && ata_link_online(link))
 		*class = ahci_dev_classify(ap);
-	if (*class == ATA_DEV_UNKNOWN)
+	if (rc != -EAGAIN && *class == ATA_DEV_UNKNOWN)
 		*class = ATA_DEV_NONE;
 
 	DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
 	return rc;
 }
 
-static int ahci_vt8251_hardreset(struct ata_port *ap, unsigned int *class,
+static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
 				 unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
+	u32 serror;
 	int rc;
 
 	DPRINTK("ENTER\n");
 
 	ahci_stop_engine(ap);
 
-	rc = sata_port_hardreset(ap, sata_ehc_deb_timing(&ap->eh_context),
+	rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
 				 deadline);
 
 	/* vt8251 needs SError cleared for the port to operate */
-	ahci_scr_write(ap, SCR_ERROR, ahci_scr_read(ap, SCR_ERROR));
+	ahci_scr_read(ap, SCR_ERROR, &serror);
+	ahci_scr_write(ap, SCR_ERROR, serror);
 
 	ahci_start_engine(ap);
 
@@ -1128,12 +1213,13 @@
 	return rc ?: -EAGAIN;
 }
 
-static void ahci_postreset(struct ata_port *ap, unsigned int *class)
+static void ahci_postreset(struct ata_link *link, unsigned int *class)
 {
+	struct ata_port *ap = link->ap;
 	void __iomem *port_mmio = ahci_port_base(ap);
 	u32 new_tmp, tmp;
 
-	ata_std_postreset(ap, class);
+	ata_std_postreset(link, class);
 
 	/* Make sure port's ATAPI bit is set appropriately */
 	new_tmp = tmp = readl(port_mmio + PORT_CMD);
@@ -1147,6 +1233,12 @@
 	}
 }
 
+static int ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
+			      unsigned long deadline)
+{
+	return ahci_do_softreset(link, class, link->pmp, deadline);
+}
+
 static u8 ahci_check_status(struct ata_port *ap)
 {
 	void __iomem *mmio = ap->ioaddr.cmd_addr;
@@ -1205,7 +1297,7 @@
 	 */
 	cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
 
-	ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
+	ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, cmd_tbl);
 	if (is_atapi) {
 		memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
 		memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
@@ -1218,7 +1310,7 @@
 	/*
 	 * Fill in command slot information.
 	 */
-	opts = cmd_fis_len | n_elem << 16;
+	opts = cmd_fis_len | n_elem << 16 | (qc->dev->link->pmp << 12);
 	if (qc->tf.flags & ATA_TFLAG_WRITE)
 		opts |= AHCI_CMD_WRITE;
 	if (is_atapi)
@@ -1229,66 +1321,87 @@
 
 static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
 {
+	struct ahci_host_priv *hpriv = ap->host->private_data;
 	struct ahci_port_priv *pp = ap->private_data;
-	struct ata_eh_info *ehi = &ap->eh_info;
-	unsigned int err_mask = 0, action = 0;
-	struct ata_queued_cmd *qc;
+	struct ata_eh_info *host_ehi = &ap->link.eh_info;
+	struct ata_link *link = NULL;
+	struct ata_queued_cmd *active_qc;
+	struct ata_eh_info *active_ehi;
 	u32 serror;
 
-	ata_ehi_clear_desc(ehi);
+	/* determine active link */
+	ata_port_for_each_link(link, ap)
+		if (ata_link_active(link))
+			break;
+	if (!link)
+		link = &ap->link;
+
+	active_qc = ata_qc_from_tag(ap, link->active_tag);
+	active_ehi = &link->eh_info;
+
+	/* record irq stat */
+	ata_ehi_clear_desc(host_ehi);
+	ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
 
 	/* AHCI needs SError cleared; otherwise, it might lock up */
-	serror = ahci_scr_read(ap, SCR_ERROR);
+	ahci_scr_read(ap, SCR_ERROR, &serror);
 	ahci_scr_write(ap, SCR_ERROR, serror);
-
-	/* analyze @irq_stat */
-	ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
+	host_ehi->serror |= serror;
 
 	/* some controllers set IRQ_IF_ERR on device errors, ignore it */
-	if (ap->flags & AHCI_FLAG_IGN_IRQ_IF_ERR)
+	if (hpriv->flags & AHCI_HFLAG_IGN_IRQ_IF_ERR)
 		irq_stat &= ~PORT_IRQ_IF_ERR;
 
 	if (irq_stat & PORT_IRQ_TF_ERR) {
-		err_mask |= AC_ERR_DEV;
-		if (ap->flags & AHCI_FLAG_IGN_SERR_INTERNAL)
-			serror &= ~SERR_INTERNAL;
-	}
+		/* If qc is active, charge it; otherwise, the active
+		 * link.  There's no active qc on NCQ errors.  It will
+		 * be determined by EH by reading log page 10h.
+		 */
+		if (active_qc)
+			active_qc->err_mask |= AC_ERR_DEV;
+		else
+			active_ehi->err_mask |= AC_ERR_DEV;
 
-	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
-		err_mask |= AC_ERR_HOST_BUS;
-		action |= ATA_EH_SOFTRESET;
-	}
-
-	if (irq_stat & PORT_IRQ_IF_ERR) {
-		err_mask |= AC_ERR_ATA_BUS;
-		action |= ATA_EH_SOFTRESET;
-		ata_ehi_push_desc(ehi, ", interface fatal error");
-	}
-
-	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
-		ata_ehi_hotplugged(ehi);
-		ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ?
-			"connection status changed" : "PHY RDY changed");
+		if (hpriv->flags & AHCI_HFLAG_IGN_SERR_INTERNAL)
+			host_ehi->serror &= ~SERR_INTERNAL;
 	}
 
 	if (irq_stat & PORT_IRQ_UNK_FIS) {
 		u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK);
 
-		err_mask |= AC_ERR_HSM;
-		action |= ATA_EH_SOFTRESET;
-		ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x",
+		active_ehi->err_mask |= AC_ERR_HSM;
+		active_ehi->action |= ATA_EH_SOFTRESET;
+		ata_ehi_push_desc(active_ehi,
+				  "unknown FIS %08x %08x %08x %08x" ,
 				  unk[0], unk[1], unk[2], unk[3]);
 	}
 
-	/* okay, let's hand over to EH */
-	ehi->serror |= serror;
-	ehi->action |= action;
+	if (ap->nr_pmp_links && (irq_stat & PORT_IRQ_BAD_PMP)) {
+		active_ehi->err_mask |= AC_ERR_HSM;
+		active_ehi->action |= ATA_EH_SOFTRESET;
+		ata_ehi_push_desc(active_ehi, "incorrect PMP");
+	}
 
-	qc = ata_qc_from_tag(ap, ap->active_tag);
-	if (qc)
-		qc->err_mask |= err_mask;
-	else
-		ehi->err_mask |= err_mask;
+	if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) {
+		host_ehi->err_mask |= AC_ERR_HOST_BUS;
+		host_ehi->action |= ATA_EH_SOFTRESET;
+		ata_ehi_push_desc(host_ehi, "host bus error");
+	}
+
+	if (irq_stat & PORT_IRQ_IF_ERR) {
+		host_ehi->err_mask |= AC_ERR_ATA_BUS;
+		host_ehi->action |= ATA_EH_SOFTRESET;
+		ata_ehi_push_desc(host_ehi, "interface fatal error");
+	}
+
+	if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) {
+		ata_ehi_hotplugged(host_ehi);
+		ata_ehi_push_desc(host_ehi, "%s",
+			irq_stat & PORT_IRQ_CONNECT ?
+			"connection status changed" : "PHY RDY changed");
+	}
+
+	/* okay, let's hand over to EH */
 
 	if (irq_stat & PORT_IRQ_FREEZE)
 		ata_port_freeze(ap);
@@ -1299,25 +1412,64 @@
 static void ahci_port_intr(struct ata_port *ap)
 {
 	void __iomem *port_mmio = ap->ioaddr.cmd_addr;
-	struct ata_eh_info *ehi = &ap->eh_info;
+	struct ata_eh_info *ehi = &ap->link.eh_info;
 	struct ahci_port_priv *pp = ap->private_data;
+	struct ahci_host_priv *hpriv = ap->host->private_data;
+	int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
 	u32 status, qc_active;
 	int rc, known_irq = 0;
 
 	status = readl(port_mmio + PORT_IRQ_STAT);
 	writel(status, port_mmio + PORT_IRQ_STAT);
 
+	/* ignore BAD_PMP while resetting */
+	if (unlikely(resetting))
+		status &= ~PORT_IRQ_BAD_PMP;
+
 	if (unlikely(status & PORT_IRQ_ERROR)) {
 		ahci_error_intr(ap, status);
 		return;
 	}
 
-	if (ap->sactive)
+	if (status & PORT_IRQ_SDB_FIS) {
+		/* If SNotification is available, leave notification
+		 * handling to sata_async_notification().  If not,
+		 * emulate it by snooping SDB FIS RX area.
+		 *
+		 * Snooping FIS RX area is probably cheaper than
+		 * poking SNotification but some constrollers which
+		 * implement SNotification, ICH9 for example, don't
+		 * store AN SDB FIS into receive area.
+		 */
+		if (hpriv->cap & HOST_CAP_SNTF)
+			sata_async_notification(ap);
+		else {
+			/* If the 'N' bit in word 0 of the FIS is set,
+			 * we just received asynchronous notification.
+			 * Tell libata about it.
+			 */
+			const __le32 *f = pp->rx_fis + RX_FIS_SDB;
+			u32 f0 = le32_to_cpu(f[0]);
+
+			if (f0 & (1 << 15))
+				sata_async_notification(ap);
+		}
+	}
+
+	/* pp->active_link is valid iff any command is in flight */
+	if (ap->qc_active && pp->active_link->sactive)
 		qc_active = readl(port_mmio + PORT_SCR_ACT);
 	else
 		qc_active = readl(port_mmio + PORT_CMD_ISSUE);
 
 	rc = ata_qc_complete_multiple(ap, qc_active, NULL);
+
+	/* If resetting, spurious or invalid completions are expected,
+	 * return unconditionally.
+	 */
+	if (resetting)
+		return;
+
 	if (rc > 0)
 		return;
 	if (rc < 0) {
@@ -1332,7 +1484,7 @@
 	/* if !NCQ, ignore.  No modern ATA device has broken HSM
 	 * implementation for non-NCQ commands.
 	 */
-	if (!ap->sactive)
+	if (!ap->link.sactive)
 		return;
 
 	if (status & PORT_IRQ_D2H_REG_FIS) {
@@ -1385,7 +1537,7 @@
 	if (!known_irq)
 		ata_port_printk(ap, KERN_INFO, "spurious interrupt "
 				"(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n",
-				status, ap->active_tag, ap->sactive);
+				status, ap->link.active_tag, ap->link.sactive);
 }
 
 static void ahci_irq_clear(struct ata_port *ap)
@@ -1450,6 +1602,13 @@
 {
 	struct ata_port *ap = qc->ap;
 	void __iomem *port_mmio = ahci_port_base(ap);
+	struct ahci_port_priv *pp = ap->private_data;
+
+	/* Keep track of the currently active link.  It will be used
+	 * in completion path to determine whether NCQ phase is in
+	 * progress.
+	 */
+	pp->active_link = qc->dev->link;
 
 	if (qc->tf.protocol == ATA_PROT_NCQ)
 		writel(1 << qc->tag, port_mmio + PORT_SCR_ACT);
@@ -1472,6 +1631,7 @@
 	void __iomem *mmio = ap->host->iomap[AHCI_PCI_BAR];
 	void __iomem *port_mmio = ahci_port_base(ap);
 	u32 tmp;
+	struct ahci_port_priv *pp = ap->private_data;
 
 	/* clear IRQ */
 	tmp = readl(port_mmio + PORT_IRQ_STAT);
@@ -1479,7 +1639,7 @@
 	writel(1 << ap->port_no, mmio + HOST_IRQ_STAT);
 
 	/* turn IRQ back on */
-	writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
+	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
 }
 
 static void ahci_error_handler(struct ata_port *ap)
@@ -1491,8 +1651,10 @@
 	}
 
 	/* perform recovery */
-	ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_hardreset,
-		  ahci_postreset);
+	sata_pmp_do_eh(ap, ata_std_prereset, ahci_softreset,
+		       ahci_hardreset, ahci_postreset,
+		       sata_pmp_std_prereset, ahci_pmp_softreset,
+		       sata_pmp_std_hardreset, sata_pmp_std_postreset);
 }
 
 static void ahci_vt8251_error_handler(struct ata_port *ap)
@@ -1512,11 +1674,50 @@
 {
 	struct ata_port *ap = qc->ap;
 
-	if (qc->flags & ATA_QCFLAG_FAILED) {
-		/* make DMA engine forget about the failed command */
-		ahci_stop_engine(ap);
-		ahci_start_engine(ap);
-	}
+	/* make DMA engine forget about the failed command */
+	if (qc->flags & ATA_QCFLAG_FAILED)
+		ahci_kick_engine(ap, 1);
+}
+
+static void ahci_pmp_attach(struct ata_port *ap)
+{
+	void __iomem *port_mmio = ahci_port_base(ap);
+	struct ahci_port_priv *pp = ap->private_data;
+	u32 cmd;
+
+	cmd = readl(port_mmio + PORT_CMD);
+	cmd |= PORT_CMD_PMP;
+	writel(cmd, port_mmio + PORT_CMD);
+
+	pp->intr_mask |= PORT_IRQ_BAD_PMP;
+	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+}
+
+static void ahci_pmp_detach(struct ata_port *ap)
+{
+	void __iomem *port_mmio = ahci_port_base(ap);
+	struct ahci_port_priv *pp = ap->private_data;
+	u32 cmd;
+
+	cmd = readl(port_mmio + PORT_CMD);
+	cmd &= ~PORT_CMD_PMP;
+	writel(cmd, port_mmio + PORT_CMD);
+
+	pp->intr_mask &= ~PORT_IRQ_BAD_PMP;
+	writel(pp->intr_mask, port_mmio + PORT_IRQ_MASK);
+}
+
+static int ahci_port_resume(struct ata_port *ap)
+{
+	ahci_power_up(ap);
+	ahci_start_port(ap);
+
+	if (ap->nr_pmp_links)
+		ahci_pmp_attach(ap);
+	else
+		ahci_pmp_detach(ap);
+
+	return 0;
 }
 
 #ifdef CONFIG_PM
@@ -1536,14 +1737,6 @@
 	return rc;
 }
 
-static int ahci_port_resume(struct ata_port *ap)
-{
-	ahci_power_up(ap);
-	ahci_start_port(ap);
-
-	return 0;
-}
-
 static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
 {
 	struct ata_host *host = dev_get_drvdata(&pdev->dev);
@@ -1635,6 +1828,12 @@
 	pp->cmd_tbl = mem;
 	pp->cmd_tbl_dma = mem_dma;
 
+	/*
+ 	 * Save off initial list of interrupts to be enabled.
+ 	 * This could be changed later
+ 	 */
+	pp->intr_mask = DEF_PORT_IRQ;
+
 	ap->private_data = pp;
 
 	/* engage engines, captain */
@@ -1734,12 +1933,13 @@
 
 	dev_printk(KERN_INFO, &pdev->dev,
 		"flags: "
-	       	"%s%s%s%s%s%s"
-	       	"%s%s%s%s%s%s%s\n"
+		"%s%s%s%s%s%s%s"
+		"%s%s%s%s%s%s%s\n"
 	       	,
 
 		cap & (1 << 31) ? "64bit " : "",
 		cap & (1 << 30) ? "ncq " : "",
+		cap & (1 << 29) ? "sntf " : "",
 		cap & (1 << 28) ? "ilck " : "",
 		cap & (1 << 27) ? "stag " : "",
 		cap & (1 << 26) ? "pm " : "",
@@ -1783,20 +1983,24 @@
 	if (rc)
 		return rc;
 
-	if ((pi.flags & AHCI_FLAG_NO_MSI) || pci_enable_msi(pdev))
-		pci_intx(pdev, 1);
-
 	hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
 	if (!hpriv)
 		return -ENOMEM;
+	hpriv->flags |= (unsigned long)pi.private_data;
+
+	if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
+		pci_intx(pdev, 1);
 
 	/* save initial config */
-	ahci_save_initial_config(pdev, &pi, hpriv);
+	ahci_save_initial_config(pdev, hpriv);
 
 	/* prepare host */
-	if (!(pi.flags & AHCI_FLAG_NO_NCQ) && (hpriv->cap & HOST_CAP_NCQ))
+	if (hpriv->cap & HOST_CAP_NCQ)
 		pi.flags |= ATA_FLAG_NCQ;
 
+	if (hpriv->cap & HOST_CAP_PMP)
+		pi.flags |= ATA_FLAG_PMP;
+
 	host = ata_host_alloc_pinfo(&pdev->dev, ppi, fls(hpriv->port_map));
 	if (!host)
 		return -ENOMEM;
@@ -1807,11 +2011,13 @@
 		struct ata_port *ap = host->ports[i];
 		void __iomem *port_mmio = ahci_port_base(ap);
 
+		ata_port_pbar_desc(ap, AHCI_PCI_BAR, -1, "abar");
+		ata_port_pbar_desc(ap, AHCI_PCI_BAR,
+				   0x100 + ap->port_no * 0x80, "port");
+
 		/* standard SATA port setup */
-		if (hpriv->port_map & (1 << i)) {
+		if (hpriv->port_map & (1 << i))
 			ap->ioaddr.cmd_addr = port_mmio;
-			ap->ioaddr.scr_addr = port_mmio + PORT_SCR;
-		}
 
 		/* disabled/not-implemented port */
 		else
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 430fcf4..9032998 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -26,7 +26,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "ata_generic"
-#define DRV_VERSION "0.2.12"
+#define DRV_VERSION "0.2.13"
 
 /*
  *	A generic parallel ATA driver using libata
@@ -34,7 +34,7 @@
 
 /**
  *	generic_set_mode	-	mode setting
- *	@ap: interface to set up
+ *	@link: link to set up
  *	@unused: returned device on error
  *
  *	Use a non standard set_mode function. We don't want to be tuned.
@@ -43,24 +43,24 @@
  *	and respect them.
  */
 
-static int generic_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int generic_set_mode(struct ata_link *link, struct ata_device **unused)
 {
+	struct ata_port *ap = link->ap;
 	int dma_enabled = 0;
-	int i;
+	struct ata_device *dev;
 
 	/* Bits 5 and 6 indicate if DMA is active on master/slave */
 	if (ap->ioaddr.bmdma_addr)
 		dma_enabled = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
+	ata_link_for_each_dev(dev, link) {
 		if (ata_dev_enabled(dev)) {
 			/* We don't really care */
 			dev->pio_mode = XFER_PIO_0;
 			dev->dma_mode = XFER_MW_DMA_0;
 			/* We do need the right mode information for DMA or PIO
 			   and this comes from the current configuration flags */
-			if (dma_enabled & (1 << (5 + i))) {
+			if (dma_enabled & (1 << (5 + dev->devno))) {
 				ata_id_to_dma_mode(dev, XFER_MW_DMA_0);
 				dev->flags &= ~ATA_DFLAG_PIO;
 			} else {
@@ -95,7 +95,6 @@
 static struct ata_port_operations generic_port_ops = {
 	.set_mode	= generic_set_mode,
 
-	.port_disable	= ata_port_disable,
 	.tf_load	= ata_tf_load,
 	.tf_read	= ata_tf_read,
 	.check_status 	= ata_check_status,
@@ -121,9 +120,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static int all_generic_ide;		/* Set to claim all devices */
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index d9fa329..e783e67 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -91,9 +91,10 @@
 #include <linux/device.h>
 #include <scsi/scsi_host.h>
 #include <linux/libata.h>
+#include <linux/dmi.h>
 
 #define DRV_NAME	"ata_piix"
-#define DRV_VERSION	"2.11"
+#define DRV_VERSION	"2.12"
 
 enum {
 	PIIX_IOCFG		= 0x54, /* IDE I/O configuration register */
@@ -122,13 +123,13 @@
 	ich_pata_33		= 1,	/* ICH up to UDMA 33 only */
 	ich_pata_66		= 2,	/* ICH up to 66 Mhz */
 	ich_pata_100		= 3,	/* ICH up to UDMA 100 */
-	ich_pata_133		= 4,	/* ICH up to UDMA 133 */
 	ich5_sata		= 5,
 	ich6_sata		= 6,
 	ich6_sata_ahci		= 7,
 	ich6m_sata_ahci		= 8,
 	ich8_sata_ahci		= 9,
 	piix_pata_mwdma		= 10,	/* PIIX3 MWDMA only */
+	tolapai_sata_ahci	= 11,
 
 	/* constants for mapping table */
 	P0			= 0,  /* port 0 */
@@ -140,6 +141,9 @@
 	RV			= -3, /* reserved */
 
 	PIIX_AHCI_DEVICE	= 6,
+
+	/* host->flags bits */
+	PIIX_HOST_BROKEN_SUSPEND = (1 << 24),
 };
 
 struct piix_map_db {
@@ -159,6 +163,10 @@
 static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
 static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev);
 static int ich_pata_cable_detect(struct ata_port *ap);
+#ifdef CONFIG_PM
+static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
+static int piix_pci_device_resume(struct pci_dev *pdev);
+#endif
 
 static unsigned int in_module_init = 1;
 
@@ -190,7 +198,7 @@
 	{ 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
 	{ 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
 	/* Intel ICH5 */
-	{ 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
+	{ 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
 	/* C-ICH (i810E2) */
 	{ 0x8086, 0x245B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
 	/* ESB (855GME/875P + 6300ESB) UDMA 100  */
@@ -198,7 +206,7 @@
 	/* ICH6 (and 6) (i915) UDMA 100 */
 	{ 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
 	/* ICH7/7-R (i945, i975) UDMA 100*/
-	{ 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
+	{ 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
 	{ 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
 	/* ICH8 Mobile PATA Controller */
 	{ 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
@@ -245,6 +253,8 @@
 	{ 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
 	/* SATA Controller IDE (ICH9M) */
 	{ 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+	/* SATA Controller IDE (Tolapai) */
+	{ 0x8086, 0x5028, PCI_ANY_ID, PCI_ANY_ID, 0, 0, tolapai_sata_ahci },
 
 	{ }	/* terminate list */
 };
@@ -255,8 +265,8 @@
 	.probe			= piix_init_one,
 	.remove			= ata_pci_remove_one,
 #ifdef CONFIG_PM
-	.suspend		= ata_pci_device_suspend,
-	.resume			= ata_pci_device_resume,
+	.suspend		= piix_pci_device_suspend,
+	.resume			= piix_pci_device_resume,
 #endif
 };
 
@@ -279,7 +289,6 @@
 };
 
 static const struct ata_port_operations piix_pata_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= piix_set_piomode,
 	.set_dmamode		= piix_set_dmamode,
 	.mode_filter		= ata_pci_default_filter,
@@ -307,13 +316,11 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	.port_start		= ata_port_start,
 };
 
 static const struct ata_port_operations ich_pata_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= piix_set_piomode,
 	.set_dmamode		= ich_set_dmamode,
 	.mode_filter		= ata_pci_default_filter,
@@ -341,14 +348,11 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	.port_start		= ata_port_start,
 };
 
 static const struct ata_port_operations piix_sata_ops = {
-	.port_disable		= ata_port_disable,
-
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
 	.check_status		= ata_check_status,
@@ -371,7 +375,6 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	.port_start		= ata_port_start,
 };
@@ -428,7 +431,19 @@
 		/* PM   PS   SM   SS       MAP */
 		{  P0,  P2,  P1,  P3 }, /* 00b (hardwired when in AHCI) */
 		{  RV,  RV,  RV,  RV },
-		{  IDE,  IDE,  NA,  NA }, /* 10b (IDE mode) */
+		{  P0,  P2, IDE, IDE }, /* 10b (IDE mode) */
+		{  RV,  RV,  RV,  RV },
+	},
+};
+
+static const struct piix_map_db tolapai_map_db = {
+	.mask = 0x3,
+	.port_enable = 0x3,
+	.map = {
+		/* PM   PS   SM   SS       MAP */
+		{  P0,  NA,  P1,  NA }, /* 00b */
+		{  RV,  RV,  RV,  RV }, /* 01b */
+		{  RV,  RV,  RV,  RV }, /* 10b */
 		{  RV,  RV,  RV,  RV },
 	},
 };
@@ -439,10 +454,11 @@
 	[ich6_sata_ahci]	= &ich6_map_db,
 	[ich6m_sata_ahci]	= &ich6m_map_db,
 	[ich8_sata_ahci]	= &ich8_map_db,
+	[tolapai_sata_ahci]	= &tolapai_map_db,
 };
 
 static struct ata_port_info piix_port_info[] = {
-	/* piix_pata_33: 0:  PIIX4 at 33MHz */
+	[piix_pata_33] =	/* PIIX4 at 33MHz */
 	{
 		.sht		= &piix_sht,
 		.flags		= PIIX_PATA_FLAGS,
@@ -452,7 +468,7 @@
 		.port_ops	= &piix_pata_ops,
 	},
 
-	/* ich_pata_33: 1 	ICH0 - ICH at 33Mhz*/
+	[ich_pata_33] = 	/* ICH0 - ICH at 33Mhz*/
 	{
 		.sht		= &piix_sht,
 		.flags		= PIIX_PATA_FLAGS,
@@ -461,7 +477,8 @@
 		.udma_mask	= ATA_UDMA2, /* UDMA33 */
 		.port_ops	= &ich_pata_ops,
 	},
-	/* ich_pata_66: 2 	ICH controllers up to 66MHz */
+
+	[ich_pata_66] = 	/* ICH controllers up to 66MHz */
 	{
 		.sht		= &piix_sht,
 		.flags		= PIIX_PATA_FLAGS,
@@ -471,7 +488,7 @@
 		.port_ops	= &ich_pata_ops,
 	},
 
-	/* ich_pata_100: 3 */
+	[ich_pata_100] =
 	{
 		.sht		= &piix_sht,
 		.flags		= PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
@@ -481,17 +498,7 @@
 		.port_ops	= &ich_pata_ops,
 	},
 
-	/* ich_pata_133: 4 	ICH with full UDMA6 */
-	{
-		.sht		= &piix_sht,
-		.flags		= PIIX_PATA_FLAGS | PIIX_FLAG_CHECKINTR,
-		.pio_mask 	= 0x1f,	/* pio 0-4 */
-		.mwdma_mask	= 0x06, /* Check: maybe 0x07  */
-		.udma_mask	= ATA_UDMA6, /* UDMA133 */
-		.port_ops	= &ich_pata_ops,
-	},
-
-	/* ich5_sata: 5 */
+	[ich5_sata] =
 	{
 		.sht		= &piix_sht,
 		.flags		= PIIX_SATA_FLAGS,
@@ -501,7 +508,7 @@
 		.port_ops	= &piix_sata_ops,
 	},
 
-	/* ich6_sata: 6 */
+	[ich6_sata] =
 	{
 		.sht		= &piix_sht,
 		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_SCR,
@@ -511,7 +518,7 @@
 		.port_ops	= &piix_sata_ops,
 	},
 
-	/* ich6_sata_ahci: 7 */
+	[ich6_sata_ahci] =
 	{
 		.sht		= &piix_sht,
 		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -522,7 +529,7 @@
 		.port_ops	= &piix_sata_ops,
 	},
 
-	/* ich6m_sata_ahci: 8 */
+	[ich6m_sata_ahci] =
 	{
 		.sht		= &piix_sht,
 		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -533,7 +540,7 @@
 		.port_ops	= &piix_sata_ops,
 	},
 
-	/* ich8_sata_ahci: 9 */
+	[ich8_sata_ahci] =
 	{
 		.sht		= &piix_sht,
 		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
@@ -544,7 +551,7 @@
 		.port_ops	= &piix_sata_ops,
 	},
 
-	/* piix_pata_mwdma: 10:  PIIX3 MWDMA only */
+	[piix_pata_mwdma] = 	/* PIIX3 MWDMA only */
 	{
 		.sht		= &piix_sht,
 		.flags		= PIIX_PATA_FLAGS,
@@ -552,6 +559,17 @@
 		.mwdma_mask	= 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
 		.port_ops	= &piix_pata_ops,
 	},
+
+	[tolapai_sata_ahci] =
+	{
+		.sht		= &piix_sht,
+		.flags		= PIIX_SATA_FLAGS | PIIX_FLAG_SCR |
+				  PIIX_FLAG_AHCI,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= ATA_UDMA6,
+		.port_ops	= &piix_sata_ops,
+	},
 };
 
 static struct pci_bits piix_enable_bits[] = {
@@ -580,6 +598,7 @@
 	{ 0x27DF, 0x0005, 0x0280 },	/* ICH7 on Acer 5602WLMi */
 	{ 0x27DF, 0x1025, 0x0110 },	/* ICH7 on Acer 3682WLMi */
 	{ 0x27DF, 0x1043, 0x1267 },	/* ICH7 on Asus W5F */
+	{ 0x27DF, 0x103C, 0x30A1 },	/* ICH7 on HP Compaq nc2400 */
 	{ 0x24CA, 0x1025, 0x0061 },	/* ICH4 on ACER Aspire 2023WLMi */
 	/* end marker */
 	{ 0, }
@@ -622,19 +641,20 @@
 
 /**
  *	piix_pata_prereset - prereset for PATA host controller
- *	@ap: Target port
+ *	@link: Target link
  *	@deadline: deadline jiffies for the operation
  *
  *	LOCKING:
  *	None (inherited from caller).
  */
-static int piix_pata_prereset(struct ata_port *ap, unsigned long deadline)
+static int piix_pata_prereset(struct ata_link *link, unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
 	if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
 		return -ENOENT;
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 static void piix_pata_error_handler(struct ata_port *ap)
@@ -881,6 +901,137 @@
 	do_pata_set_dmamode(ap, adev, 1);
 }
 
+#ifdef CONFIG_PM
+static int piix_broken_suspend(void)
+{
+	static const struct dmi_system_id sysids[] = {
+		{
+			.ident = "TECRA M3",
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+				DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M3"),
+			},
+		},
+		{
+			.ident = "TECRA M5",
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+				DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M5"),
+			},
+		},
+		{
+			.ident = "TECRA M7",
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+				DMI_MATCH(DMI_PRODUCT_NAME, "TECRA M7"),
+			},
+		},
+		{
+			.ident = "Satellite U200",
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+				DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U200"),
+			},
+		},
+		{
+			.ident = "Satellite U205",
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+				DMI_MATCH(DMI_PRODUCT_NAME, "Satellite U205"),
+			},
+		},
+		{
+			.ident = "Portege M500",
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+				DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M500"),
+			},
+		},
+
+		{ }	/* terminate list */
+	};
+	static const char *oemstrs[] = {
+		"Tecra M3,",
+	};
+	int i;
+
+	if (dmi_check_system(sysids))
+		return 1;
+
+	for (i = 0; i < ARRAY_SIZE(oemstrs); i++)
+		if (dmi_find_device(DMI_DEV_TYPE_OEM_STRING, oemstrs[i], NULL))
+			return 1;
+
+	return 0;
+}
+
+static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+	struct ata_host *host = dev_get_drvdata(&pdev->dev);
+	unsigned long flags;
+	int rc = 0;
+
+	rc = ata_host_suspend(host, mesg);
+	if (rc)
+		return rc;
+
+	/* Some braindamaged ACPI suspend implementations expect the
+	 * controller to be awake on entry; otherwise, it burns cpu
+	 * cycles and power trying to do something to the sleeping
+	 * beauty.
+	 */
+	if (piix_broken_suspend() && mesg.event == PM_EVENT_SUSPEND) {
+		pci_save_state(pdev);
+
+		/* mark its power state as "unknown", since we don't
+		 * know if e.g. the BIOS will change its device state
+		 * when we suspend.
+		 */
+		if (pdev->current_state == PCI_D0)
+			pdev->current_state = PCI_UNKNOWN;
+
+		/* tell resume that it's waking up from broken suspend */
+		spin_lock_irqsave(&host->lock, flags);
+		host->flags |= PIIX_HOST_BROKEN_SUSPEND;
+		spin_unlock_irqrestore(&host->lock, flags);
+	} else
+		ata_pci_device_do_suspend(pdev, mesg);
+
+	return 0;
+}
+
+static int piix_pci_device_resume(struct pci_dev *pdev)
+{
+	struct ata_host *host = dev_get_drvdata(&pdev->dev);
+	unsigned long flags;
+	int rc;
+
+	if (host->flags & PIIX_HOST_BROKEN_SUSPEND) {
+		spin_lock_irqsave(&host->lock, flags);
+		host->flags &= ~PIIX_HOST_BROKEN_SUSPEND;
+		spin_unlock_irqrestore(&host->lock, flags);
+
+		pci_set_power_state(pdev, PCI_D0);
+		pci_restore_state(pdev);
+
+		/* PCI device wasn't disabled during suspend.  Use
+		 * pci_reenable_device() to avoid affecting the enable
+		 * count.
+		 */
+		rc = pci_reenable_device(pdev);
+		if (rc)
+			dev_printk(KERN_ERR, &pdev->dev, "failed to enable "
+				   "device after resume (%d)\n", rc);
+	} else
+		rc = ata_pci_device_do_resume(pdev);
+
+	if (rc == 0)
+		ata_host_resume(host);
+
+	return rc;
+}
+#endif
+
 #define AHCI_PCI_BAR 5
 #define AHCI_GLOBAL_CTL 0x04
 #define AHCI_ENABLE (1 << 31)
@@ -1015,6 +1166,41 @@
 	hpriv->map = map;
 }
 
+static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
+{
+	static const struct dmi_system_id sysids[] = {
+		{
+			/* Clevo M570U sets IOCFG bit 18 if the cdrom
+			 * isn't used to boot the system which
+			 * disables the channel.
+			 */
+			.ident = "M570U",
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "Clevo Co."),
+				DMI_MATCH(DMI_PRODUCT_NAME, "M570U"),
+			},
+		},
+
+		{ }	/* terminate list */
+	};
+	u32 iocfg;
+
+	if (!dmi_check_system(sysids))
+		return;
+
+	/* The datasheet says that bit 18 is NOOP but certain systems
+	 * seem to use it to disable a channel.  Clear the bit on the
+	 * affected systems.
+	 */
+	pci_read_config_dword(pdev, PIIX_IOCFG, &iocfg);
+	if (iocfg & (1 << 18)) {
+		dev_printk(KERN_INFO, &pdev->dev,
+			   "applying IOCFG bit18 quirk\n");
+		iocfg &= ~(1 << 18);
+		pci_write_config_dword(pdev, PIIX_IOCFG, iocfg);
+	}
+}
+
 /**
  *	piix_init_one - Register PIIX ATA PCI device with kernel services
  *	@pdev: PCI device to register
@@ -1076,6 +1262,9 @@
 			      piix_map_db_table[ent->driver_data]);
 	}
 
+	/* apply IOCFG bit18 quirk */
+	piix_iocfg_bit18_quirk(pdev);
+
 	/* On ICH5, some BIOSen disable the interrupt using the
 	 * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
 	 * On ICH6, this bit has the same effect, but only when
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index c059f78..3f75335 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -14,6 +14,7 @@
 #include <linux/acpi.h>
 #include <linux/libata.h>
 #include <linux/pci.h>
+#include <scsi/scsi_device.h>
 #include "libata.h"
 
 #include <acpi/acpi_bus.h>
@@ -40,11 +41,40 @@
 	return (dev->bus == &pci_bus_type);
 }
 
-static void ata_acpi_associate_sata_port(struct ata_port *ap)
+/**
+ * ata_acpi_associate_sata_port - associate SATA port with ACPI objects
+ * @ap: target SATA port
+ *
+ * Look up ACPI objects associated with @ap and initialize acpi_handle
+ * fields of @ap, the port and devices accordingly.
+ *
+ * LOCKING:
+ * EH context.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+void ata_acpi_associate_sata_port(struct ata_port *ap)
 {
-	acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
+	WARN_ON(!(ap->flags & ATA_FLAG_ACPI_SATA));
 
-	ap->device->acpi_handle = acpi_get_child(ap->host->acpi_handle, adr);
+	if (!ap->nr_pmp_links) {
+		acpi_integer adr = SATA_ADR(ap->port_no, NO_PORT_MULT);
+
+		ap->link.device->acpi_handle =
+			acpi_get_child(ap->host->acpi_handle, adr);
+	} else {
+		struct ata_link *link;
+
+		ap->link.device->acpi_handle = NULL;
+
+		ata_port_for_each_link(link, ap) {
+			acpi_integer adr = SATA_ADR(ap->port_no, link->pmp);
+
+			link->device->acpi_handle =
+				acpi_get_child(ap->host->acpi_handle, adr);
+		}
+	}
 }
 
 static void ata_acpi_associate_ide_port(struct ata_port *ap)
@@ -60,12 +90,53 @@
 		max_devices++;
 
 	for (i = 0; i < max_devices; i++) {
-		struct ata_device *dev = &ap->device[i];
+		struct ata_device *dev = &ap->link.device[i];
 
 		dev->acpi_handle = acpi_get_child(ap->acpi_handle, i);
 	}
 }
 
+static void ata_acpi_handle_hotplug (struct ata_port *ap, struct kobject *kobj,
+				     u32 event)
+{
+	char event_string[12];
+	char *envp[] = { event_string, NULL };
+	struct ata_eh_info *ehi = &ap->link.eh_info;
+
+	if (event == 0 || event == 1) {
+	       unsigned long flags;
+	       spin_lock_irqsave(ap->lock, flags);
+	       ata_ehi_clear_desc(ehi);
+	       ata_ehi_push_desc(ehi, "ACPI event");
+	       ata_ehi_hotplugged(ehi);
+	       ata_port_freeze(ap);
+	       spin_unlock_irqrestore(ap->lock, flags);
+	}
+
+	if (kobj) {
+	        sprintf(event_string, "BAY_EVENT=%d", event);
+		kobject_uevent_env(kobj, KOBJ_CHANGE, envp);
+	}
+}
+
+static void ata_acpi_dev_notify(acpi_handle handle, u32 event, void *data)
+{
+	struct ata_device *dev = data;
+	struct kobject *kobj = NULL;
+
+	if (dev->sdev)
+		kobj = &dev->sdev->sdev_gendev.kobj;
+
+	ata_acpi_handle_hotplug (dev->link->ap, kobj, event);
+}
+
+static void ata_acpi_ap_notify(acpi_handle handle, u32 event, void *data)
+{
+	struct ata_port *ap = data;
+
+	ata_acpi_handle_hotplug (ap, &ap->dev->kobj, event);
+}
+
 /**
  * ata_acpi_associate - associate ATA host with ACPI objects
  * @host: target ATA host
@@ -81,7 +152,7 @@
  */
 void ata_acpi_associate(struct ata_host *host)
 {
-	int i;
+	int i, j;
 
 	if (!is_pci_dev(host->dev) || libata_noacpi)
 		return;
@@ -97,6 +168,22 @@
 			ata_acpi_associate_sata_port(ap);
 		else
 			ata_acpi_associate_ide_port(ap);
+
+		if (ap->acpi_handle)
+			acpi_install_notify_handler (ap->acpi_handle,
+						     ACPI_SYSTEM_NOTIFY,
+						     ata_acpi_ap_notify,
+						     ap);
+
+		for (j = 0; j < ata_link_max_devices(&ap->link); j++) {
+			struct ata_device *dev = &ap->link.device[j];
+
+			if (dev->acpi_handle)
+				acpi_install_notify_handler (dev->acpi_handle,
+							     ACPI_SYSTEM_NOTIFY,
+							     ata_acpi_dev_notify,
+							     dev);
+		}
 	}
 }
 
@@ -113,7 +200,7 @@
  * RETURNS:
  * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure.
  */
-static int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
+int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm)
 {
 	struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER };
 	union acpi_object *out_obj;
@@ -157,6 +244,8 @@
 	return rc;
 }
 
+EXPORT_SYMBOL_GPL(ata_acpi_gtm);
+
 /**
  * ata_acpi_stm - execute _STM
  * @ap: target ATA port
@@ -170,7 +259,7 @@
  * RETURNS:
  * 0 on success, -ENOENT if _STM doesn't exist, -errno on failure.
  */
-static int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
+int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm)
 {
 	acpi_status status;
 	struct acpi_object_list         input;
@@ -182,10 +271,10 @@
 	/* Buffers for id may need byteswapping ? */
 	in_params[1].type = ACPI_TYPE_BUFFER;
 	in_params[1].buffer.length = 512;
-	in_params[1].buffer.pointer = (u8 *)ap->device[0].id;
+	in_params[1].buffer.pointer = (u8 *)ap->link.device[0].id;
 	in_params[2].type = ACPI_TYPE_BUFFER;
 	in_params[2].buffer.length = 512;
-	in_params[2].buffer.pointer = (u8 *)ap->device[1].id;
+	in_params[2].buffer.pointer = (u8 *)ap->link.device[1].id;
 
 	input.count = 3;
 	input.pointer = in_params;
@@ -202,6 +291,8 @@
 	return 0;
 }
 
+EXPORT_SYMBOL_GPL(ata_acpi_stm);
+
 /**
  * ata_dev_get_GTF - get the drive bootup default taskfile settings
  * @dev: target ATA device
@@ -226,7 +317,7 @@
 static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf,
 			   void **ptr_to_free)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_port *ap = dev->link->ap;
 	acpi_status status;
 	struct acpi_buffer output;
 	union acpi_object *out_obj;
@@ -296,6 +387,44 @@
 }
 
 /**
+ * ata_acpi_cbl_80wire		-	Check for 80 wire cable
+ * @ap: Port to check
+ *
+ * Return 1 if the ACPI mode data for this port indicates the BIOS selected
+ * an 80wire mode.
+ */
+
+int ata_acpi_cbl_80wire(struct ata_port *ap)
+{
+	struct ata_acpi_gtm gtm;
+	int valid = 0;
+	
+	/* No _GTM data, no information */
+	if (ata_acpi_gtm(ap, &gtm) < 0)
+		return 0;
+		
+	/* Split timing, DMA enabled */
+	if ((gtm.flags & 0x11) == 0x11 && gtm.drive[0].dma < 55)
+		valid |= 1;
+	if ((gtm.flags & 0x14) == 0x14 && gtm.drive[1].dma < 55)
+		valid |= 2;
+	/* Shared timing, DMA enabled */
+	if ((gtm.flags & 0x11) == 0x01 && gtm.drive[0].dma < 55)
+		valid |= 1;
+	if ((gtm.flags & 0x14) == 0x04 && gtm.drive[0].dma < 55)
+		valid |= 2;
+
+	/* Drive check */
+	if ((valid & 1) && ata_dev_enabled(&ap->link.device[0]))
+		return 1;
+	if ((valid & 2) && ata_dev_enabled(&ap->link.device[1]))
+		return 1;
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire);
+
+/**
  * taskfile_load_raw - send taskfile registers to host controller
  * @dev: target ATA device
  * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
@@ -320,7 +449,7 @@
 static int taskfile_load_raw(struct ata_device *dev,
 			      const struct ata_acpi_gtf *gtf)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_port *ap = dev->link->ap;
 	struct ata_taskfile tf, rtf;
 	unsigned int err_mask;
 
@@ -349,7 +478,7 @@
 			       tf.lbal, tf.lbam, tf.lbah, tf.device);
 
 	rtf = tf;
-	err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0);
+	err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0, 0);
 	if (err_mask) {
 		ata_dev_printk(dev, KERN_ERR,
 			"ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x failed "
@@ -424,7 +553,7 @@
  */
 static int ata_acpi_push_id(struct ata_device *dev)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_port *ap = dev->link->ap;
 	int err;
 	acpi_status status;
 	struct acpi_object_list input;
@@ -508,7 +637,7 @@
  */
 void ata_acpi_on_resume(struct ata_port *ap)
 {
-	int i;
+	struct ata_device *dev;
 
 	if (ap->acpi_handle && (ap->pflags & ATA_PFLAG_GTM_VALID)) {
 		BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA);
@@ -518,8 +647,8 @@
 	}
 
 	/* schedule _GTF */
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		ap->device[i].flags |= ATA_DFLAG_ACPI_PENDING;
+	ata_link_for_each_dev(dev, &ap->link)
+		dev->flags |= ATA_DFLAG_ACPI_PENDING;
 }
 
 /**
@@ -538,8 +667,8 @@
  */
 int ata_acpi_on_devcfg(struct ata_device *dev)
 {
-	struct ata_port *ap = dev->ap;
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_port *ap = dev->link->ap;
+	struct ata_eh_context *ehc = &ap->link.eh_context;
 	int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA;
 	int rc;
 
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 88e2dd0..b05384a 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -59,8 +59,6 @@
 
 #include "libata.h"
 
-#define DRV_VERSION	"2.21"	/* must be exactly four chars */
-
 
 /* debounce timing parameters in msecs { interval, duration, timeout } */
 const unsigned long sata_deb_timing_normal[]		= {   5,  100, 2000 };
@@ -70,6 +68,7 @@
 static unsigned int ata_dev_init_params(struct ata_device *dev,
 					u16 heads, u16 sectors);
 static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
+static unsigned int ata_dev_set_AN(struct ata_device *dev, u8 enable);
 static void ata_dev_xfermask(struct ata_device *dev);
 static unsigned long ata_dev_blacklisted(const struct ata_device *dev);
 
@@ -86,6 +85,10 @@
 module_param(atapi_dmadir, int, 0444);
 MODULE_PARM_DESC(atapi_dmadir, "Enable ATAPI DMADIR bridge support (0=off, 1=on)");
 
+int atapi_passthru16 = 1;
+module_param(atapi_passthru16, int, 0444);
+MODULE_PARM_DESC(atapi_passthru16, "Enable ATA_16 passthru for ATAPI devices; on by default (0=off, 1=on)");
+
 int libata_fua = 0;
 module_param_named(fua, libata_fua, int, 0444);
 MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
@@ -94,13 +97,17 @@
 module_param_named(ignore_hpa, ata_ignore_hpa, int, 0644);
 MODULE_PARM_DESC(ignore_hpa, "Ignore HPA limit (0=keep BIOS limits, 1=ignore limits, using full disk)");
 
+static int libata_dma_mask = ATA_DMA_MASK_ATA|ATA_DMA_MASK_ATAPI|ATA_DMA_MASK_CFA;
+module_param_named(dma, libata_dma_mask, int, 0444);
+MODULE_PARM_DESC(dma, "DMA enable/disable (0x1==ATA, 0x2==ATAPI, 0x4==CF)");
+
 static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ;
 module_param(ata_probe_timeout, int, 0444);
 MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
 
-int libata_noacpi = 1;
+int libata_noacpi = 0;
 module_param_named(noacpi, libata_noacpi, int, 0444);
-MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in suspend/resume when set");
+MODULE_PARM_DESC(noacpi, "Disables the use of ACPI in probe/suspend/resume when set");
 
 MODULE_AUTHOR("Jeff Garzik");
 MODULE_DESCRIPTION("Library module for ATA devices");
@@ -111,8 +118,9 @@
 /**
  *	ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
  *	@tf: Taskfile to convert
- *	@fis: Buffer into which data will output
  *	@pmp: Port multiplier port
+ *	@is_cmd: This FIS is for command
+ *	@fis: Buffer into which data will output
  *
  *	Converts a standard ATA taskfile to a Serial ATA
  *	FIS structure (Register - Host to Device).
@@ -120,12 +128,13 @@
  *	LOCKING:
  *	Inherited from caller.
  */
-
-void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp)
+void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis)
 {
-	fis[0] = 0x27;	/* Register - Host to Device FIS */
-	fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
-					    bit 7 indicates Command FIS */
+	fis[0] = 0x27;			/* Register - Host to Device FIS */
+	fis[1] = pmp & 0xf;		/* Port multiplier number*/
+	if (is_cmd)
+		fis[1] |= (1 << 7);	/* bit 7 indicates Command FIS */
+
 	fis[2] = tf->command;
 	fis[3] = tf->feature;
 
@@ -233,7 +242,7 @@
 	if (dev->flags & ATA_DFLAG_PIO) {
 		tf->protocol = ATA_PROT_PIO;
 		index = dev->multi_count ? 0 : 8;
-	} else if (lba48 && (dev->ap->flags & ATA_FLAG_PIO_LBA48)) {
+	} else if (lba48 && (dev->link->ap->flags & ATA_FLAG_PIO_LBA48)) {
 		/* Unable to use DMA due to host limitation */
 		tf->protocol = ATA_PROT_PIO;
 		index = dev->multi_count ? 0 : 8;
@@ -602,7 +611,7 @@
 void ata_dev_disable(struct ata_device *dev)
 {
 	if (ata_dev_enabled(dev)) {
-		if (ata_msg_drv(dev->ap))
+		if (ata_msg_drv(dev->link->ap))
 			ata_dev_printk(dev, KERN_WARNING, "disabled\n");
 		ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 |
 					     ATA_DNXFER_QUIET);
@@ -665,37 +674,57 @@
  *	None.
  *
  *	RETURNS:
- *	Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, or %ATA_DEV_UNKNOWN
- *	the event of failure.
+ *	Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, %ATA_DEV_PMP or
+ *	%ATA_DEV_UNKNOWN the event of failure.
  */
-
 unsigned int ata_dev_classify(const struct ata_taskfile *tf)
 {
 	/* Apple's open source Darwin code hints that some devices only
 	 * put a proper signature into the LBA mid/high registers,
 	 * So, we only check those.  It's sufficient for uniqueness.
+	 *
+	 * ATA/ATAPI-7 (d1532v1r1: Feb. 19, 2003) specified separate
+	 * signatures for ATA and ATAPI devices attached on SerialATA,
+	 * 0x3c/0xc3 and 0x69/0x96 respectively.  However, SerialATA
+	 * spec has never mentioned about using different signatures
+	 * for ATA/ATAPI devices.  Then, Serial ATA II: Port
+	 * Multiplier specification began to use 0x69/0x96 to identify
+	 * port multpliers and 0x3c/0xc3 to identify SEMB device.
+	 * ATA/ATAPI-7 dropped descriptions about 0x3c/0xc3 and
+	 * 0x69/0x96 shortly and described them as reserved for
+	 * SerialATA.
+	 *
+	 * We follow the current spec and consider that 0x69/0x96
+	 * identifies a port multiplier and 0x3c/0xc3 a SEMB device.
 	 */
-
-	if (((tf->lbam == 0) && (tf->lbah == 0)) ||
-	    ((tf->lbam == 0x3c) && (tf->lbah == 0xc3))) {
+	if ((tf->lbam == 0) && (tf->lbah == 0)) {
 		DPRINTK("found ATA device by sig\n");
 		return ATA_DEV_ATA;
 	}
 
-	if (((tf->lbam == 0x14) && (tf->lbah == 0xeb)) ||
-	    ((tf->lbam == 0x69) && (tf->lbah == 0x96))) {
+	if ((tf->lbam == 0x14) && (tf->lbah == 0xeb)) {
 		DPRINTK("found ATAPI device by sig\n");
 		return ATA_DEV_ATAPI;
 	}
 
+	if ((tf->lbam == 0x69) && (tf->lbah == 0x96)) {
+		DPRINTK("found PMP device by sig\n");
+		return ATA_DEV_PMP;
+	}
+
+	if ((tf->lbam == 0x3c) && (tf->lbah == 0xc3)) {
+		printk("ata: SEMB device ignored\n");
+		return ATA_DEV_SEMB_UNSUP; /* not yet */
+	}
+
 	DPRINTK("unknown device\n");
 	return ATA_DEV_UNKNOWN;
 }
 
 /**
  *	ata_dev_try_classify - Parse returned ATA device signature
- *	@ap: ATA channel to examine
- *	@device: Device to examine (starting at zero)
+ *	@dev: ATA device to classify (starting at zero)
+ *	@present: device seems present
  *	@r_err: Value of error register on completion
  *
  *	After an event -- SRST, E.D.D., or SATA COMRESET -- occurs,
@@ -713,15 +742,15 @@
  *	RETURNS:
  *	Device type - %ATA_DEV_ATA, %ATA_DEV_ATAPI or %ATA_DEV_NONE.
  */
-
-unsigned int
-ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
+unsigned int ata_dev_try_classify(struct ata_device *dev, int present,
+				  u8 *r_err)
 {
+	struct ata_port *ap = dev->link->ap;
 	struct ata_taskfile tf;
 	unsigned int class;
 	u8 err;
 
-	ap->ops->dev_select(ap, device);
+	ap->ops->dev_select(ap, dev->devno);
 
 	memset(&tf, 0, sizeof(tf));
 
@@ -731,12 +760,12 @@
 		*r_err = err;
 
 	/* see if device passed diags: if master then continue and warn later */
-	if (err == 0 && device == 0)
+	if (err == 0 && dev->devno == 0)
 		/* diagnostic fail : do nothing _YET_ */
-		ap->device[device].horkage |= ATA_HORKAGE_DIAGNOSTIC;
+		dev->horkage |= ATA_HORKAGE_DIAGNOSTIC;
 	else if (err == 1)
 		/* do nothing */ ;
-	else if ((device == 0) && (err == 0x81))
+	else if ((dev->devno == 0) && (err == 0x81))
 		/* do nothing */ ;
 	else
 		return ATA_DEV_NONE;
@@ -744,10 +773,20 @@
 	/* determine if device is ATA or ATAPI */
 	class = ata_dev_classify(&tf);
 
-	if (class == ATA_DEV_UNKNOWN)
-		return ATA_DEV_NONE;
-	if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
-		return ATA_DEV_NONE;
+	if (class == ATA_DEV_UNKNOWN) {
+		/* If the device failed diagnostic, it's likely to
+		 * have reported incorrect device signature too.
+		 * Assume ATA device if the device seems present but
+		 * device signature is invalid with diagnostic
+		 * failure.
+		 */
+		if (present && (dev->horkage & ATA_HORKAGE_DIAGNOSTIC))
+			class = ATA_DEV_ATA;
+		else
+			class = ATA_DEV_NONE;
+	} else if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
+		class = ATA_DEV_NONE;
+
 	return class;
 }
 
@@ -814,6 +853,21 @@
 	*p = '\0';
 }
 
+static u64 ata_id_n_sectors(const u16 *id)
+{
+	if (ata_id_has_lba(id)) {
+		if (ata_id_has_lba48(id))
+			return ata_id_u64(id, 100);
+		else
+			return ata_id_u32(id, 60);
+	} else {
+		if (ata_id_current_chs_valid(id))
+			return ata_id_u32(id, 57);
+		else
+			return id[1] * id[3] * id[6];
+	}
+}
+
 static u64 ata_tf_to_lba48(struct ata_taskfile *tf)
 {
 	u64 sectors = 0;
@@ -841,129 +895,110 @@
 }
 
 /**
- *	ata_read_native_max_address_ext	-	LBA48 native max query
- *	@dev: Device to query
+ *	ata_read_native_max_address - Read native max address
+ *	@dev: target device
+ *	@max_sectors: out parameter for the result native max address
  *
- *	Perform an LBA48 size query upon the device in question. Return the
- *	actual LBA48 size or zero if the command fails.
+ *	Perform an LBA48 or LBA28 native size query upon the device in
+ *	question.
+ *
+ *	RETURNS:
+ *	0 on success, -EACCES if command is aborted by the drive.
+ *	-EIO on other errors.
  */
-
-static u64 ata_read_native_max_address_ext(struct ata_device *dev)
+static int ata_read_native_max_address(struct ata_device *dev, u64 *max_sectors)
 {
-	unsigned int err;
+	unsigned int err_mask;
 	struct ata_taskfile tf;
+	int lba48 = ata_id_has_lba48(dev->id);
 
 	ata_tf_init(dev, &tf);
 
-	tf.command = ATA_CMD_READ_NATIVE_MAX_EXT;
-	tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
-	tf.protocol |= ATA_PROT_NODATA;
-	tf.device |= 0x40;
-
-	err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
-	if (err)
-		return 0;
-
-	return ata_tf_to_lba48(&tf);
-}
-
-/**
- *	ata_read_native_max_address	-	LBA28 native max query
- *	@dev: Device to query
- *
- *	Performa an LBA28 size query upon the device in question. Return the
- *	actual LBA28 size or zero if the command fails.
- */
-
-static u64 ata_read_native_max_address(struct ata_device *dev)
-{
-	unsigned int err;
-	struct ata_taskfile tf;
-
-	ata_tf_init(dev, &tf);
-
-	tf.command = ATA_CMD_READ_NATIVE_MAX;
+	/* always clear all address registers */
 	tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+
+	if (lba48) {
+		tf.command = ATA_CMD_READ_NATIVE_MAX_EXT;
+		tf.flags |= ATA_TFLAG_LBA48;
+	} else
+		tf.command = ATA_CMD_READ_NATIVE_MAX;
+
 	tf.protocol |= ATA_PROT_NODATA;
-	tf.device |= 0x40;
+	tf.device |= ATA_LBA;
 
-	err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
-	if (err)
-		return 0;
+	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+	if (err_mask) {
+		ata_dev_printk(dev, KERN_WARNING, "failed to read native "
+			       "max address (err_mask=0x%x)\n", err_mask);
+		if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED))
+			return -EACCES;
+		return -EIO;
+	}
 
-	return ata_tf_to_lba(&tf);
+	if (lba48)
+		*max_sectors = ata_tf_to_lba48(&tf);
+	else
+		*max_sectors = ata_tf_to_lba(&tf);
+        if (dev->horkage & ATA_HORKAGE_HPA_SIZE)
+		(*max_sectors)--;
+	return 0;
 }
 
 /**
- *	ata_set_native_max_address_ext	-	LBA48 native max set
- *	@dev: Device to query
+ *	ata_set_max_sectors - Set max sectors
+ *	@dev: target device
  *	@new_sectors: new max sectors value to set for the device
  *
- *	Perform an LBA48 size set max upon the device in question. Return the
- *	actual LBA48 size or zero if the command fails.
+ *	Set max sectors of @dev to @new_sectors.
+ *
+ *	RETURNS:
+ *	0 on success, -EACCES if command is aborted or denied (due to
+ *	previous non-volatile SET_MAX) by the drive.  -EIO on other
+ *	errors.
  */
-
-static u64 ata_set_native_max_address_ext(struct ata_device *dev, u64 new_sectors)
+static int ata_set_max_sectors(struct ata_device *dev, u64 new_sectors)
 {
-	unsigned int err;
+	unsigned int err_mask;
 	struct ata_taskfile tf;
+	int lba48 = ata_id_has_lba48(dev->id);
 
 	new_sectors--;
 
 	ata_tf_init(dev, &tf);
 
-	tf.command = ATA_CMD_SET_MAX_EXT;
-	tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48 | ATA_TFLAG_ISADDR;
-	tf.protocol |= ATA_PROT_NODATA;
-	tf.device |= 0x40;
-
-	tf.lbal = (new_sectors >> 0) & 0xff;
-	tf.lbam = (new_sectors >> 8) & 0xff;
-	tf.lbah = (new_sectors >> 16) & 0xff;
-
-	tf.hob_lbal = (new_sectors >> 24) & 0xff;
-	tf.hob_lbam = (new_sectors >> 32) & 0xff;
-	tf.hob_lbah = (new_sectors >> 40) & 0xff;
-
-	err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
-	if (err)
-		return 0;
-
-	return ata_tf_to_lba48(&tf);
-}
-
-/**
- *	ata_set_native_max_address	-	LBA28 native max set
- *	@dev: Device to query
- *	@new_sectors: new max sectors value to set for the device
- *
- *	Perform an LBA28 size set max upon the device in question. Return the
- *	actual LBA28 size or zero if the command fails.
- */
-
-static u64 ata_set_native_max_address(struct ata_device *dev, u64 new_sectors)
-{
-	unsigned int err;
-	struct ata_taskfile tf;
-
-	new_sectors--;
-
-	ata_tf_init(dev, &tf);
-
-	tf.command = ATA_CMD_SET_MAX;
 	tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
+
+	if (lba48) {
+		tf.command = ATA_CMD_SET_MAX_EXT;
+		tf.flags |= ATA_TFLAG_LBA48;
+
+		tf.hob_lbal = (new_sectors >> 24) & 0xff;
+		tf.hob_lbam = (new_sectors >> 32) & 0xff;
+		tf.hob_lbah = (new_sectors >> 40) & 0xff;
+	} else {
+		tf.command = ATA_CMD_SET_MAX;
+
+		tf.device |= (new_sectors >> 24) & 0xf;
+	}
+
 	tf.protocol |= ATA_PROT_NODATA;
+	tf.device |= ATA_LBA;
 
 	tf.lbal = (new_sectors >> 0) & 0xff;
 	tf.lbam = (new_sectors >> 8) & 0xff;
 	tf.lbah = (new_sectors >> 16) & 0xff;
-	tf.device |= ((new_sectors >> 24) & 0x0f) | 0x40;
 
-	err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
-	if (err)
-		return 0;
+	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+	if (err_mask) {
+		ata_dev_printk(dev, KERN_WARNING, "failed to set "
+			       "max address (err_mask=0x%x)\n", err_mask);
+		if (err_mask == AC_ERR_DEV &&
+		    (tf.feature & (ATA_ABORTED | ATA_IDNF)))
+			return -EACCES;
+		return -EIO;
+	}
 
-	return ata_tf_to_lba(&tf);
+	return 0;
 }
 
 /**
@@ -973,60 +1008,93 @@
  *	Read the size of an LBA28 or LBA48 disk with HPA features and resize
  *	it if required to the full size of the media. The caller must check
  *	the drive has the HPA feature set enabled.
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
  */
-
-static u64 ata_hpa_resize(struct ata_device *dev)
+static int ata_hpa_resize(struct ata_device *dev)
 {
-	u64 sectors = dev->n_sectors;
-	u64 hpa_sectors;
+	struct ata_eh_context *ehc = &dev->link->eh_context;
+	int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
+	u64 sectors = ata_id_n_sectors(dev->id);
+	u64 native_sectors;
+	int rc;
 
-	if (ata_id_has_lba48(dev->id))
-		hpa_sectors = ata_read_native_max_address_ext(dev);
-	else
-		hpa_sectors = ata_read_native_max_address(dev);
+	/* do we need to do it? */
+	if (dev->class != ATA_DEV_ATA ||
+	    !ata_id_has_lba(dev->id) || !ata_id_hpa_enabled(dev->id) ||
+	    (dev->horkage & ATA_HORKAGE_BROKEN_HPA))
+		return 0;
 
-	if (hpa_sectors > sectors) {
-		ata_dev_printk(dev, KERN_INFO,
-			"Host Protected Area detected:\n"
-			"\tcurrent size: %lld sectors\n"
-			"\tnative size: %lld sectors\n",
-			(long long)sectors, (long long)hpa_sectors);
+	/* read native max address */
+	rc = ata_read_native_max_address(dev, &native_sectors);
+	if (rc) {
+		/* If HPA isn't going to be unlocked, skip HPA
+		 * resizing from the next try.
+		 */
+		if (!ata_ignore_hpa) {
+			ata_dev_printk(dev, KERN_WARNING, "HPA support seems "
+				       "broken, will skip HPA handling\n");
+			dev->horkage |= ATA_HORKAGE_BROKEN_HPA;
 
-		if (ata_ignore_hpa) {
-			if (ata_id_has_lba48(dev->id))
-				hpa_sectors = ata_set_native_max_address_ext(dev, hpa_sectors);
-			else
-				hpa_sectors = ata_set_native_max_address(dev,
-								hpa_sectors);
-
-			if (hpa_sectors) {
-				ata_dev_printk(dev, KERN_INFO, "native size "
-					"increased to %lld sectors\n",
-					(long long)hpa_sectors);
-				return hpa_sectors;
-			}
+			/* we can continue if device aborted the command */
+			if (rc == -EACCES)
+				rc = 0;
 		}
-	} else if (hpa_sectors < sectors)
-		ata_dev_printk(dev, KERN_WARNING, "%s 1: hpa sectors (%lld) "
-			       "is smaller than sectors (%lld)\n", __FUNCTION__,
-			       (long long)hpa_sectors, (long long)sectors);
 
-	return sectors;
-}
-
-static u64 ata_id_n_sectors(const u16 *id)
-{
-	if (ata_id_has_lba(id)) {
-		if (ata_id_has_lba48(id))
-			return ata_id_u64(id, 100);
-		else
-			return ata_id_u32(id, 60);
-	} else {
-		if (ata_id_current_chs_valid(id))
-			return ata_id_u32(id, 57);
-		else
-			return id[1] * id[3] * id[6];
+		return rc;
 	}
+
+	/* nothing to do? */
+	if (native_sectors <= sectors || !ata_ignore_hpa) {
+		if (!print_info || native_sectors == sectors)
+			return 0;
+
+		if (native_sectors > sectors)
+			ata_dev_printk(dev, KERN_INFO,
+				"HPA detected: current %llu, native %llu\n",
+				(unsigned long long)sectors,
+				(unsigned long long)native_sectors);
+		else if (native_sectors < sectors)
+			ata_dev_printk(dev, KERN_WARNING,
+				"native sectors (%llu) is smaller than "
+				"sectors (%llu)\n",
+				(unsigned long long)native_sectors,
+				(unsigned long long)sectors);
+		return 0;
+	}
+
+	/* let's unlock HPA */
+	rc = ata_set_max_sectors(dev, native_sectors);
+	if (rc == -EACCES) {
+		/* if device aborted the command, skip HPA resizing */
+		ata_dev_printk(dev, KERN_WARNING, "device aborted resize "
+			       "(%llu -> %llu), skipping HPA handling\n",
+			       (unsigned long long)sectors,
+			       (unsigned long long)native_sectors);
+		dev->horkage |= ATA_HORKAGE_BROKEN_HPA;
+		return 0;
+	} else if (rc)
+		return rc;
+
+	/* re-read IDENTIFY data */
+	rc = ata_dev_reread_id(dev, 0);
+	if (rc) {
+		ata_dev_printk(dev, KERN_ERR, "failed to re-read IDENTIFY "
+			       "data after HPA resizing\n");
+		return rc;
+	}
+
+	if (print_info) {
+		u64 new_sectors = ata_id_n_sectors(dev->id);
+		ata_dev_printk(dev, KERN_INFO,
+			"HPA unlocked: %llu -> %llu, native %llu\n",
+			(unsigned long long)sectors,
+			(unsigned long long)new_sectors,
+			(unsigned long long)native_sectors);
+	}
+
+	return 0;
 }
 
 /**
@@ -1148,7 +1216,7 @@
 	ap->ops->dev_select(ap, device);
 
 	if (wait) {
-		if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI)
+		if (can_sleep && ap->link.device[device].class == ATA_DEV_ATAPI)
 			msleep(150);
 		ata_wait_idle(ap);
 	}
@@ -1326,6 +1394,7 @@
  *	@dma_dir: Data tranfer direction of the command
  *	@sg: sg list for the data buffer of the command
  *	@n_elem: Number of sg entries
+ *	@timeout: Timeout in msecs (0 for default)
  *
  *	Executes libata internal command with timeout.  @tf contains
  *	command on entry and result on return.  Timeout and error
@@ -1342,13 +1411,15 @@
 unsigned ata_exec_internal_sg(struct ata_device *dev,
 			      struct ata_taskfile *tf, const u8 *cdb,
 			      int dma_dir, struct scatterlist *sg,
-			      unsigned int n_elem)
+			      unsigned int n_elem, unsigned long timeout)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_link *link = dev->link;
+	struct ata_port *ap = link->ap;
 	u8 command = tf->command;
 	struct ata_queued_cmd *qc;
 	unsigned int tag, preempted_tag;
 	u32 preempted_sactive, preempted_qc_active;
+	int preempted_nr_active_links;
 	DECLARE_COMPLETION_ONSTACK(wait);
 	unsigned long flags;
 	unsigned int err_mask;
@@ -1384,12 +1455,14 @@
 	qc->dev = dev;
 	ata_qc_reinit(qc);
 
-	preempted_tag = ap->active_tag;
-	preempted_sactive = ap->sactive;
+	preempted_tag = link->active_tag;
+	preempted_sactive = link->sactive;
 	preempted_qc_active = ap->qc_active;
-	ap->active_tag = ATA_TAG_POISON;
-	ap->sactive = 0;
+	preempted_nr_active_links = ap->nr_active_links;
+	link->active_tag = ATA_TAG_POISON;
+	link->sactive = 0;
 	ap->qc_active = 0;
+	ap->nr_active_links = 0;
 
 	/* prepare & issue qc */
 	qc->tf = *tf;
@@ -1414,7 +1487,10 @@
 
 	spin_unlock_irqrestore(ap->lock, flags);
 
-	rc = wait_for_completion_timeout(&wait, ata_probe_timeout);
+	if (!timeout)
+		timeout = ata_probe_timeout * 1000 / HZ;
+
+	rc = wait_for_completion_timeout(&wait, msecs_to_jiffies(timeout));
 
 	ata_port_flush_task(ap);
 
@@ -1465,9 +1541,10 @@
 	err_mask = qc->err_mask;
 
 	ata_qc_free(qc);
-	ap->active_tag = preempted_tag;
-	ap->sactive = preempted_sactive;
+	link->active_tag = preempted_tag;
+	link->sactive = preempted_sactive;
 	ap->qc_active = preempted_qc_active;
+	ap->nr_active_links = preempted_nr_active_links;
 
 	/* XXX - Some LLDDs (sata_mv) disable port on command failure.
 	 * Until those drivers are fixed, we detect the condition
@@ -1498,6 +1575,7 @@
  *	@dma_dir: Data tranfer direction of the command
  *	@buf: Data buffer of the command
  *	@buflen: Length of data buffer
+ *	@timeout: Timeout in msecs (0 for default)
  *
  *	Wrapper around ata_exec_internal_sg() which takes simple
  *	buffer instead of sg list.
@@ -1510,7 +1588,8 @@
  */
 unsigned ata_exec_internal(struct ata_device *dev,
 			   struct ata_taskfile *tf, const u8 *cdb,
-			   int dma_dir, void *buf, unsigned int buflen)
+			   int dma_dir, void *buf, unsigned int buflen,
+			   unsigned long timeout)
 {
 	struct scatterlist *psg = NULL, sg;
 	unsigned int n_elem = 0;
@@ -1522,7 +1601,8 @@
 		n_elem++;
 	}
 
-	return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem);
+	return ata_exec_internal_sg(dev, tf, cdb, dma_dir, psg, n_elem,
+				    timeout);
 }
 
 /**
@@ -1549,7 +1629,7 @@
 	tf.flags |= ATA_TFLAG_DEVICE;
 	tf.protocol = ATA_PROT_NODATA;
 
-	return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+	return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
 }
 
 /**
@@ -1564,7 +1644,7 @@
 {
 	/* Controller doesn't support  IORDY. Probably a pointless check
 	   as the caller should know this */
-	if (adev->ap->flags & ATA_FLAG_NO_IORDY)
+	if (adev->link->ap->flags & ATA_FLAG_NO_IORDY)
 		return 0;
 	/* PIO3 and higher it is mandatory */
 	if (adev->pio_mode > XFER_PIO_2)
@@ -1611,6 +1691,9 @@
  *	devices.  This function also issues ATA_CMD_INIT_DEV_PARAMS
  *	for pre-ATA4 drives.
  *
+ *	FIXME: ATA_CMD_ID_ATA is optional for early drives and right
+ *	now we abort if we hit that case. 
+ *
  *	LOCKING:
  *	Kernel thread context (may sleep)
  *
@@ -1620,7 +1703,7 @@
 int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
 		    unsigned int flags, u16 *id)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_port *ap = dev->link->ap;
 	unsigned int class = *p_class;
 	struct ata_taskfile tf;
 	unsigned int err_mask = 0;
@@ -1661,7 +1744,7 @@
 	tf.flags |= ATA_TFLAG_POLLING;
 
 	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
-				     id, sizeof(id[0]) * ATA_ID_WORDS);
+				     id, sizeof(id[0]) * ATA_ID_WORDS, 0);
 	if (err_mask) {
 		if (err_mask & AC_ERR_NODEV_HINT) {
 			DPRINTK("ata%u.%d: NODEV after polling detection\n",
@@ -1720,8 +1803,9 @@
 		tf.feature = SETFEATURES_SPINUP;
 		tf.protocol = ATA_PROT_NODATA;
 		tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
-		err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
-		if (err_mask) {
+		err_mask = ata_exec_internal(dev, &tf, NULL,
+					     DMA_NONE, NULL, 0, 0);
+		if (err_mask && id[2] != 0x738c) {
 			rc = -EIO;
 			reason = "SPINUP failed";
 			goto err_out;
@@ -1738,10 +1822,13 @@
 		/*
 		 * The exact sequence expected by certain pre-ATA4 drives is:
 		 * SRST RESET
-		 * IDENTIFY
-		 * INITIALIZE DEVICE PARAMETERS
+		 * IDENTIFY (optional in early ATA)
+		 * INITIALIZE DEVICE PARAMETERS (later IDE and ATA)
 		 * anything else..
 		 * Some drives were very specific about that exact sequence.
+		 *
+		 * Note that ATA4 says lba is mandatory so the second check
+		 * shoud never trigger.
 		 */
 		if (ata_id_major_version(id) < 4 || !ata_id_has_lba(id)) {
 			err_mask = ata_dev_init_params(dev, id[3], id[6]);
@@ -1772,13 +1859,14 @@
 
 static inline u8 ata_dev_knobble(struct ata_device *dev)
 {
-	return ((dev->ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
+	struct ata_port *ap = dev->link->ap;
+	return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(dev->id)));
 }
 
 static void ata_dev_config_ncq(struct ata_device *dev,
 			       char *desc, size_t desc_sz)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_port *ap = dev->link->ap;
 	int hdepth = 0, ddepth = ata_id_queue_depth(dev->id);
 
 	if (!ata_id_has_ncq(dev->id)) {
@@ -1815,8 +1903,8 @@
  */
 int ata_dev_configure(struct ata_device *dev)
 {
-	struct ata_port *ap = dev->ap;
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_port *ap = dev->link->ap;
+	struct ata_eh_context *ehc = &dev->link->eh_context;
 	int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
 	const u16 *id = dev->id;
 	unsigned int xfer_mask;
@@ -1842,6 +1930,11 @@
 	if (rc)
 		return rc;
 
+	/* massage HPA, do it early as it might change IDENTIFY data */
+	rc = ata_hpa_resize(dev);
+	if (rc)
+		return rc;
+
 	/* print device capabilities */
 	if (ata_msg_probe(ap))
 		ata_dev_printk(dev, KERN_DEBUG,
@@ -1909,9 +2002,6 @@
 					dev->flags |= ATA_DFLAG_FLUSH_EXT;
 			}
 
-			if (ata_id_hpa_enabled(dev->id))
-				dev->n_sectors = ata_hpa_resize(dev);
-
 			/* config NCQ */
 			ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
 
@@ -1960,7 +2050,9 @@
 
 	/* ATAPI-specific feature tests */
 	else if (dev->class == ATA_DEV_ATAPI) {
-		char *cdb_intr_string = "";
+		const char *cdb_intr_string = "";
+		const char *atapi_an_string = "";
+		u32 sntf;
 
 		rc = atapi_cdb_len(id);
 		if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
@@ -1972,6 +2064,28 @@
 		}
 		dev->cdb_len = (unsigned int) rc;
 
+		/* Enable ATAPI AN if both the host and device have
+		 * the support.  If PMP is attached, SNTF is required
+		 * to enable ATAPI AN to discern between PHY status
+		 * changed notifications and ATAPI ANs.
+		 */
+		if ((ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) &&
+		    (!ap->nr_pmp_links ||
+		     sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) {
+			unsigned int err_mask;
+
+			/* issue SET feature command to turn this on */
+			err_mask = ata_dev_set_AN(dev, SETFEATURES_SATA_ENABLE);
+			if (err_mask)
+				ata_dev_printk(dev, KERN_ERR,
+					"failed to enable ATAPI AN "
+					"(err_mask=0x%x)\n", err_mask);
+			else {
+				dev->flags |= ATA_DFLAG_AN;
+				atapi_an_string = ", ATAPI AN";
+			}
+		}
+
 		if (ata_id_cdb_intr(dev->id)) {
 			dev->flags |= ATA_DFLAG_CDB_INTR;
 			cdb_intr_string = ", CDB intr";
@@ -1980,10 +2094,10 @@
 		/* print device info to dmesg */
 		if (ata_msg_drv(ap) && print_info)
 			ata_dev_printk(dev, KERN_INFO,
-				       "ATAPI: %s, %s, max %s%s\n",
+				       "ATAPI: %s, %s, max %s%s%s\n",
 				       modelbuf, fwrevbuf,
 				       ata_mode_string(xfer_mask),
-				       cdb_intr_string);
+				       cdb_intr_string, atapi_an_string);
 	}
 
 	/* determine max_sectors */
@@ -2100,21 +2214,19 @@
 {
 	unsigned int classes[ATA_MAX_DEVICES];
 	int tries[ATA_MAX_DEVICES];
-	int i, rc;
+	int rc;
 	struct ata_device *dev;
 
 	ata_port_probe(ap);
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		tries[i] = ATA_PROBE_MAX_TRIES;
+	ata_link_for_each_dev(dev, &ap->link)
+		tries[dev->devno] = ATA_PROBE_MAX_TRIES;
 
  retry:
 	/* reset and determine device classes */
 	ap->ops->phy_reset(ap);
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->device[i];
-
+	ata_link_for_each_dev(dev, &ap->link) {
 		if (!(ap->flags & ATA_FLAG_DISABLED) &&
 		    dev->class != ATA_DEV_UNKNOWN)
 			classes[dev->devno] = dev->class;
@@ -2129,18 +2241,16 @@
 	/* after the reset the device state is PIO 0 and the controller
 	   state is undefined. Record the mode */
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		ap->device[i].pio_mode = XFER_PIO_0;
+	ata_link_for_each_dev(dev, &ap->link)
+		dev->pio_mode = XFER_PIO_0;
 
 	/* read IDENTIFY page and configure devices. We have to do the identify
 	   specific sequence bass-ackwards so that PDIAG- is released by
 	   the slave device */
 
-	for (i = ATA_MAX_DEVICES - 1; i >=  0; i--) {
-		dev = &ap->device[i];
-
-		if (tries[i])
-			dev->class = classes[i];
+	ata_link_for_each_dev(dev, &ap->link) {
+		if (tries[dev->devno])
+			dev->class = classes[dev->devno];
 
 		if (!ata_dev_enabled(dev))
 			continue;
@@ -2155,33 +2265,42 @@
 	if (ap->ops->cable_detect)
 		ap->cbl = ap->ops->cable_detect(ap);
 
+	/* We may have SATA bridge glue hiding here irrespective of the
+	   reported cable types and sensed types */
+	ata_link_for_each_dev(dev, &ap->link) {
+		if (!ata_dev_enabled(dev))
+			continue;
+		/* SATA drives indicate we have a bridge. We don't know which
+		   end of the link the bridge is which is a problem */
+		if (ata_id_is_sata(dev->id))
+			ap->cbl = ATA_CBL_SATA;
+	}
+
 	/* After the identify sequence we can now set up the devices. We do
 	   this in the normal order so that the user doesn't get confused */
 
-	for(i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->device[i];
+	ata_link_for_each_dev(dev, &ap->link) {
 		if (!ata_dev_enabled(dev))
 			continue;
 
-		ap->eh_context.i.flags |= ATA_EHI_PRINTINFO;
+		ap->link.eh_context.i.flags |= ATA_EHI_PRINTINFO;
 		rc = ata_dev_configure(dev);
-		ap->eh_context.i.flags &= ~ATA_EHI_PRINTINFO;
+		ap->link.eh_context.i.flags &= ~ATA_EHI_PRINTINFO;
 		if (rc)
 			goto fail;
 	}
 
 	/* configure transfer mode */
-	rc = ata_set_mode(ap, &dev);
+	rc = ata_set_mode(&ap->link, &dev);
 	if (rc)
 		goto fail;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		if (ata_dev_enabled(&ap->device[i]))
+	ata_link_for_each_dev(dev, &ap->link)
+		if (ata_dev_enabled(dev))
 			return 0;
 
 	/* no device present, disable port */
 	ata_port_disable(ap);
-	ap->ops->port_disable(ap);
 	return -ENODEV;
 
  fail:
@@ -2201,7 +2320,7 @@
 			/* This is the last chance, better to slow
 			 * down than lose it.
 			 */
-			sata_down_spd_limit(ap);
+			sata_down_spd_limit(&ap->link);
 			ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
 		}
 	}
@@ -2230,28 +2349,28 @@
 
 /**
  *	sata_print_link_status - Print SATA link status
- *	@ap: SATA port to printk link status about
+ *	@link: SATA link to printk link status about
  *
  *	This function prints link speed and status of a SATA link.
  *
  *	LOCKING:
  *	None.
  */
-void sata_print_link_status(struct ata_port *ap)
+void sata_print_link_status(struct ata_link *link)
 {
 	u32 sstatus, scontrol, tmp;
 
-	if (sata_scr_read(ap, SCR_STATUS, &sstatus))
+	if (sata_scr_read(link, SCR_STATUS, &sstatus))
 		return;
-	sata_scr_read(ap, SCR_CONTROL, &scontrol);
+	sata_scr_read(link, SCR_CONTROL, &scontrol);
 
-	if (ata_port_online(ap)) {
+	if (ata_link_online(link)) {
 		tmp = (sstatus >> 4) & 0xf;
-		ata_port_printk(ap, KERN_INFO,
+		ata_link_printk(link, KERN_INFO,
 				"SATA link up %s (SStatus %X SControl %X)\n",
 				sata_spd_string(tmp), sstatus, scontrol);
 	} else {
-		ata_port_printk(ap, KERN_INFO,
+		ata_link_printk(link, KERN_INFO,
 				"SATA link down (SStatus %X SControl %X)\n",
 				sstatus, scontrol);
 	}
@@ -2271,32 +2390,33 @@
  */
 void __sata_phy_reset(struct ata_port *ap)
 {
-	u32 sstatus;
+	struct ata_link *link = &ap->link;
 	unsigned long timeout = jiffies + (HZ * 5);
+	u32 sstatus;
 
 	if (ap->flags & ATA_FLAG_SATA_RESET) {
 		/* issue phy wake/reset */
-		sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+		sata_scr_write_flush(link, SCR_CONTROL, 0x301);
 		/* Couldn't find anything in SATA I/II specs, but
 		 * AHCI-1.1 10.4.2 says at least 1 ms. */
 		mdelay(1);
 	}
 	/* phy wake/clear reset */
-	sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+	sata_scr_write_flush(link, SCR_CONTROL, 0x300);
 
 	/* wait for phy to become ready, if necessary */
 	do {
 		msleep(200);
-		sata_scr_read(ap, SCR_STATUS, &sstatus);
+		sata_scr_read(link, SCR_STATUS, &sstatus);
 		if ((sstatus & 0xf) != 1)
 			break;
 	} while (time_before(jiffies, timeout));
 
 	/* print link status */
-	sata_print_link_status(ap);
+	sata_print_link_status(link);
 
 	/* TODO: phy layer with polling, timeouts, etc. */
-	if (!ata_port_offline(ap))
+	if (!ata_link_offline(link))
 		ata_port_probe(ap);
 	else
 		ata_port_disable(ap);
@@ -2341,8 +2461,8 @@
 
 struct ata_device *ata_dev_pair(struct ata_device *adev)
 {
-	struct ata_port *ap = adev->ap;
-	struct ata_device *pair = &ap->device[1 - adev->devno];
+	struct ata_link *link = adev->link;
+	struct ata_device *pair = &link->device[1 - adev->devno];
 	if (!ata_dev_enabled(pair))
 		return NULL;
 	return pair;
@@ -2363,16 +2483,16 @@
 
 void ata_port_disable(struct ata_port *ap)
 {
-	ap->device[0].class = ATA_DEV_NONE;
-	ap->device[1].class = ATA_DEV_NONE;
+	ap->link.device[0].class = ATA_DEV_NONE;
+	ap->link.device[1].class = ATA_DEV_NONE;
 	ap->flags |= ATA_FLAG_DISABLED;
 }
 
 /**
  *	sata_down_spd_limit - adjust SATA spd limit downward
- *	@ap: Port to adjust SATA spd limit for
+ *	@link: Link to adjust SATA spd limit for
  *
- *	Adjust SATA spd limit of @ap downward.  Note that this
+ *	Adjust SATA spd limit of @link downward.  Note that this
  *	function only adjusts the limit.  The change must be applied
  *	using sata_set_spd().
  *
@@ -2382,45 +2502,59 @@
  *	RETURNS:
  *	0 on success, negative errno on failure
  */
-int sata_down_spd_limit(struct ata_port *ap)
+int sata_down_spd_limit(struct ata_link *link)
 {
 	u32 sstatus, spd, mask;
 	int rc, highbit;
 
-	rc = sata_scr_read(ap, SCR_STATUS, &sstatus);
-	if (rc)
-		return rc;
+	if (!sata_scr_valid(link))
+		return -EOPNOTSUPP;
 
-	mask = ap->sata_spd_limit;
+	/* If SCR can be read, use it to determine the current SPD.
+	 * If not, use cached value in link->sata_spd.
+	 */
+	rc = sata_scr_read(link, SCR_STATUS, &sstatus);
+	if (rc == 0)
+		spd = (sstatus >> 4) & 0xf;
+	else
+		spd = link->sata_spd;
+
+	mask = link->sata_spd_limit;
 	if (mask <= 1)
 		return -EINVAL;
+
+	/* unconditionally mask off the highest bit */
 	highbit = fls(mask) - 1;
 	mask &= ~(1 << highbit);
 
-	spd = (sstatus >> 4) & 0xf;
-	if (spd <= 1)
-		return -EINVAL;
-	spd--;
-	mask &= (1 << spd) - 1;
+	/* Mask off all speeds higher than or equal to the current
+	 * one.  Force 1.5Gbps if current SPD is not available.
+	 */
+	if (spd > 1)
+		mask &= (1 << (spd - 1)) - 1;
+	else
+		mask &= 1;
+
+	/* were we already at the bottom? */
 	if (!mask)
 		return -EINVAL;
 
-	ap->sata_spd_limit = mask;
+	link->sata_spd_limit = mask;
 
-	ata_port_printk(ap, KERN_WARNING, "limiting SATA link speed to %s\n",
+	ata_link_printk(link, KERN_WARNING, "limiting SATA link speed to %s\n",
 			sata_spd_string(fls(mask)));
 
 	return 0;
 }
 
-static int __sata_set_spd_needed(struct ata_port *ap, u32 *scontrol)
+static int __sata_set_spd_needed(struct ata_link *link, u32 *scontrol)
 {
 	u32 spd, limit;
 
-	if (ap->sata_spd_limit == UINT_MAX)
+	if (link->sata_spd_limit == UINT_MAX)
 		limit = 0;
 	else
-		limit = fls(ap->sata_spd_limit);
+		limit = fls(link->sata_spd_limit);
 
 	spd = (*scontrol >> 4) & 0xf;
 	*scontrol = (*scontrol & ~0xf0) | ((limit & 0xf) << 4);
@@ -2430,10 +2564,10 @@
 
 /**
  *	sata_set_spd_needed - is SATA spd configuration needed
- *	@ap: Port in question
+ *	@link: Link in question
  *
  *	Test whether the spd limit in SControl matches
- *	@ap->sata_spd_limit.  This function is used to determine
+ *	@link->sata_spd_limit.  This function is used to determine
  *	whether hardreset is necessary to apply SATA spd
  *	configuration.
  *
@@ -2443,21 +2577,21 @@
  *	RETURNS:
  *	1 if SATA spd configuration is needed, 0 otherwise.
  */
-int sata_set_spd_needed(struct ata_port *ap)
+int sata_set_spd_needed(struct ata_link *link)
 {
 	u32 scontrol;
 
-	if (sata_scr_read(ap, SCR_CONTROL, &scontrol))
+	if (sata_scr_read(link, SCR_CONTROL, &scontrol))
 		return 0;
 
-	return __sata_set_spd_needed(ap, &scontrol);
+	return __sata_set_spd_needed(link, &scontrol);
 }
 
 /**
  *	sata_set_spd - set SATA spd according to spd limit
- *	@ap: Port to set SATA spd for
+ *	@link: Link to set SATA spd for
  *
- *	Set SATA spd of @ap according to sata_spd_limit.
+ *	Set SATA spd of @link according to sata_spd_limit.
  *
  *	LOCKING:
  *	Inherited from caller.
@@ -2466,18 +2600,18 @@
  *	0 if spd doesn't need to be changed, 1 if spd has been
  *	changed.  Negative errno if SCR registers are inaccessible.
  */
-int sata_set_spd(struct ata_port *ap)
+int sata_set_spd(struct ata_link *link)
 {
 	u32 scontrol;
 	int rc;
 
-	if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+	if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
 		return rc;
 
-	if (!__sata_set_spd_needed(ap, &scontrol))
+	if (!__sata_set_spd_needed(link, &scontrol))
 		return 0;
 
-	if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+	if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
 		return rc;
 
 	return 1;
@@ -2732,7 +2866,7 @@
 
 static int ata_dev_set_mode(struct ata_device *dev)
 {
-	struct ata_eh_context *ehc = &dev->ap->eh_context;
+	struct ata_eh_context *ehc = &dev->link->eh_context;
 	unsigned int err_mask;
 	int rc;
 
@@ -2744,7 +2878,11 @@
 	/* Old CFA may refuse this command, which is just fine */
 	if (dev->xfer_shift == ATA_SHIFT_PIO && ata_id_is_cfa(dev->id))
         	err_mask &= ~AC_ERR_DEV;
-
+	/* Some very old devices and some bad newer ones fail any kind of
+	   SET_XFERMODE request but support PIO0-2 timings and no IORDY */
+	if (dev->xfer_shift == ATA_SHIFT_PIO && !ata_id_has_iordy(dev->id) &&
+			dev->pio_mode <= XFER_PIO_2)
+		err_mask &= ~AC_ERR_DEV;
 	if (err_mask) {
 		ata_dev_printk(dev, KERN_ERR, "failed to set xfermode "
 			       "(err_mask=0x%x)\n", err_mask);
@@ -2752,7 +2890,7 @@
 	}
 
 	ehc->i.flags |= ATA_EHI_POST_SETMODE;
-	rc = ata_dev_revalidate(dev, 0);
+	rc = ata_dev_revalidate(dev, ATA_DEV_UNKNOWN, 0);
 	ehc->i.flags &= ~ATA_EHI_POST_SETMODE;
 	if (rc)
 		return rc;
@@ -2767,7 +2905,7 @@
 
 /**
  *	ata_do_set_mode - Program timings and issue SET FEATURES - XFER
- *	@ap: port on which timings will be programmed
+ *	@link: link on which timings will be programmed
  *	@r_failed_dev: out paramter for failed device
  *
  *	Standard implementation of the function used to tune and set
@@ -2782,25 +2920,36 @@
  *	0 on success, negative errno otherwise
  */
 
-int ata_do_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
 {
+	struct ata_port *ap = link->ap;
 	struct ata_device *dev;
-	int i, rc = 0, used_dma = 0, found = 0;
-
+	int rc = 0, used_dma = 0, found = 0;
 
 	/* step 1: calculate xfer_mask */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+	ata_link_for_each_dev(dev, link) {
 		unsigned int pio_mask, dma_mask;
-
-		dev = &ap->device[i];
+		unsigned int mode_mask;
 
 		if (!ata_dev_enabled(dev))
 			continue;
 
+		mode_mask = ATA_DMA_MASK_ATA;
+		if (dev->class == ATA_DEV_ATAPI)
+			mode_mask = ATA_DMA_MASK_ATAPI;
+		else if (ata_id_is_cfa(dev->id))
+			mode_mask = ATA_DMA_MASK_CFA;
+
 		ata_dev_xfermask(dev);
 
 		pio_mask = ata_pack_xfermask(dev->pio_mask, 0, 0);
 		dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
+
+		if (libata_dma_mask & mode_mask)
+			dma_mask = ata_pack_xfermask(0, dev->mwdma_mask, dev->udma_mask);
+		else
+			dma_mask = 0;
+
 		dev->pio_mode = ata_xfer_mask2mode(pio_mask);
 		dev->dma_mode = ata_xfer_mask2mode(dma_mask);
 
@@ -2812,8 +2961,7 @@
 		goto out;
 
 	/* step 2: always set host PIO timings */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->device[i];
+	ata_link_for_each_dev(dev, link) {
 		if (!ata_dev_enabled(dev))
 			continue;
 
@@ -2830,9 +2978,7 @@
 	}
 
 	/* step 3: set host DMA timings */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->device[i];
-
+	ata_link_for_each_dev(dev, link) {
 		if (!ata_dev_enabled(dev) || !dev->dma_mode)
 			continue;
 
@@ -2843,9 +2989,7 @@
 	}
 
 	/* step 4: update devices' xfer mode */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->device[i];
-
+	ata_link_for_each_dev(dev, link) {
 		/* don't update suspended devices' xfer mode */
 		if (!ata_dev_enabled(dev))
 			continue;
@@ -2869,7 +3013,7 @@
 
 /**
  *	ata_set_mode - Program timings and issue SET FEATURES - XFER
- *	@ap: port on which timings will be programmed
+ *	@link: link on which timings will be programmed
  *	@r_failed_dev: out paramter for failed device
  *
  *	Set ATA device disk transfer mode (PIO3, UDMA6, etc.).  If
@@ -2882,12 +3026,14 @@
  *	RETURNS:
  *	0 on success, negative errno otherwise
  */
-int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
 {
+	struct ata_port *ap = link->ap;
+
 	/* has private set_mode? */
 	if (ap->ops->set_mode)
-		return ap->ops->set_mode(ap, r_failed_dev);
-	return ata_do_set_mode(ap, r_failed_dev);
+		return ap->ops->set_mode(link, r_failed_dev);
+	return ata_do_set_mode(link, r_failed_dev);
 }
 
 /**
@@ -2990,7 +3136,7 @@
 
 		if (!(status & ATA_BUSY))
 			return 0;
-		if (!ata_port_online(ap) && status == 0xff)
+		if (!ata_link_online(&ap->link) && status == 0xff)
 			return -ENODEV;
 		if (time_after(now, deadline))
 			return -EBUSY;
@@ -3071,6 +3217,8 @@
 			     unsigned long deadline)
 {
 	struct ata_ioports *ioaddr = &ap->ioaddr;
+	struct ata_device *dev;
+	int i = 0;
 
 	DPRINTK("ata%u: bus reset via SRST\n", ap->print_id);
 
@@ -3081,6 +3229,25 @@
 	udelay(20);	/* FIXME: flush */
 	iowrite8(ap->ctl, ioaddr->ctl_addr);
 
+	/* If we issued an SRST then an ATA drive (not ATAPI)
+	 * may have changed configuration and be in PIO0 timing. If
+	 * we did a hard reset (or are coming from power on) this is
+	 * true for ATA or ATAPI. Until we've set a suitable controller
+	 * mode we should not touch the bus as we may be talking too fast.
+	 */
+
+	ata_link_for_each_dev(dev, &ap->link)
+		dev->pio_mode = XFER_PIO_0;
+
+	/* If the controller has a pio mode setup function then use
+	   it to set the chipset to rights. Don't touch the DMA setup
+	   as that will be dealt with when revalidating */
+	if (ap->ops->set_piomode) {
+		ata_link_for_each_dev(dev, &ap->link)
+			if (devmask & (1 << i++))
+				ap->ops->set_piomode(ap, dev);
+	}
+
 	/* spec mandates ">= 2ms" before checking status.
 	 * We wait 150ms, because that was the magic delay used for
 	 * ATAPI devices in Hale Landis's ATADRVR, for the period of time
@@ -3125,6 +3292,7 @@
 
 void ata_bus_reset(struct ata_port *ap)
 {
+	struct ata_device *device = ap->link.device;
 	struct ata_ioports *ioaddr = &ap->ioaddr;
 	unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
 	u8 err;
@@ -3160,19 +3328,19 @@
 	/*
 	 * determine by signature whether we have ATA or ATAPI devices
 	 */
-	ap->device[0].class = ata_dev_try_classify(ap, 0, &err);
+	device[0].class = ata_dev_try_classify(&device[0], dev0, &err);
 	if ((slave_possible) && (err != 0x81))
-		ap->device[1].class = ata_dev_try_classify(ap, 1, &err);
+		device[1].class = ata_dev_try_classify(&device[1], dev1, &err);
 
 	/* is double-select really necessary? */
-	if (ap->device[1].class != ATA_DEV_NONE)
+	if (device[1].class != ATA_DEV_NONE)
 		ap->ops->dev_select(ap, 1);
-	if (ap->device[0].class != ATA_DEV_NONE)
+	if (device[0].class != ATA_DEV_NONE)
 		ap->ops->dev_select(ap, 0);
 
 	/* if no devices were detected, disable this port */
-	if ((ap->device[0].class == ATA_DEV_NONE) &&
-	    (ap->device[1].class == ATA_DEV_NONE))
+	if ((device[0].class == ATA_DEV_NONE) &&
+	    (device[1].class == ATA_DEV_NONE))
 		goto err_out;
 
 	if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
@@ -3185,18 +3353,18 @@
 
 err_out:
 	ata_port_printk(ap, KERN_ERR, "disabling port\n");
-	ap->ops->port_disable(ap);
+	ata_port_disable(ap);
 
 	DPRINTK("EXIT\n");
 }
 
 /**
- *	sata_phy_debounce - debounce SATA phy status
- *	@ap: ATA port to debounce SATA phy status for
+ *	sata_link_debounce - debounce SATA phy status
+ *	@link: ATA link to debounce SATA phy status for
  *	@params: timing parameters { interval, duratinon, timeout } in msec
  *	@deadline: deadline jiffies for the operation
  *
- *	Make sure SStatus of @ap reaches stable state, determined by
+*	Make sure SStatus of @link reaches stable state, determined by
  *	holding the same value where DET is not 1 for @duration polled
  *	every @interval, before @timeout.  Timeout constraints the
  *	beginning of the stable state.  Because DET gets stuck at 1 on
@@ -3212,8 +3380,8 @@
  *	RETURNS:
  *	0 on success, -errno on failure.
  */
-int sata_phy_debounce(struct ata_port *ap, const unsigned long *params,
-		      unsigned long deadline)
+int sata_link_debounce(struct ata_link *link, const unsigned long *params,
+		       unsigned long deadline)
 {
 	unsigned long interval_msec = params[0];
 	unsigned long duration = msecs_to_jiffies(params[1]);
@@ -3225,7 +3393,7 @@
 	if (time_before(t, deadline))
 		deadline = t;
 
-	if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+	if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
 		return rc;
 	cur &= 0xf;
 
@@ -3234,7 +3402,7 @@
 
 	while (1) {
 		msleep(interval_msec);
-		if ((rc = sata_scr_read(ap, SCR_STATUS, &cur)))
+		if ((rc = sata_scr_read(link, SCR_STATUS, &cur)))
 			return rc;
 		cur &= 0xf;
 
@@ -3251,19 +3419,21 @@
 		last = cur;
 		last_jiffies = jiffies;
 
-		/* check deadline */
+		/* Check deadline.  If debouncing failed, return
+		 * -EPIPE to tell upper layer to lower link speed.
+		 */
 		if (time_after(jiffies, deadline))
-			return -EBUSY;
+			return -EPIPE;
 	}
 }
 
 /**
- *	sata_phy_resume - resume SATA phy
- *	@ap: ATA port to resume SATA phy for
+ *	sata_link_resume - resume SATA link
+ *	@link: ATA link to resume SATA
  *	@params: timing parameters { interval, duratinon, timeout } in msec
  *	@deadline: deadline jiffies for the operation
  *
- *	Resume SATA phy of @ap and debounce it.
+ *	Resume SATA phy @link and debounce it.
  *
  *	LOCKING:
  *	Kernel thread context (may sleep)
@@ -3271,18 +3441,18 @@
  *	RETURNS:
  *	0 on success, -errno on failure.
  */
-int sata_phy_resume(struct ata_port *ap, const unsigned long *params,
-		    unsigned long deadline)
+int sata_link_resume(struct ata_link *link, const unsigned long *params,
+		     unsigned long deadline)
 {
 	u32 scontrol;
 	int rc;
 
-	if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+	if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
 		return rc;
 
 	scontrol = (scontrol & 0x0f0) | 0x300;
 
-	if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+	if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
 		return rc;
 
 	/* Some PHYs react badly if SStatus is pounded immediately
@@ -3290,15 +3460,15 @@
 	 */
 	msleep(200);
 
-	return sata_phy_debounce(ap, params, deadline);
+	return sata_link_debounce(link, params, deadline);
 }
 
 /**
  *	ata_std_prereset - prepare for reset
- *	@ap: ATA port to be reset
+ *	@link: ATA link to be reset
  *	@deadline: deadline jiffies for the operation
  *
- *	@ap is about to be reset.  Initialize it.  Failure from
+ *	@link is about to be reset.  Initialize it.  Failure from
  *	prereset makes libata abort whole reset sequence and give up
  *	that port, so prereset should be best-effort.  It does its
  *	best to prepare for reset sequence but if things go wrong, it
@@ -3310,37 +3480,44 @@
  *	RETURNS:
  *	0 on success, -errno otherwise.
  */
-int ata_std_prereset(struct ata_port *ap, unsigned long deadline)
+int ata_std_prereset(struct ata_link *link, unsigned long deadline)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_port *ap = link->ap;
+	struct ata_eh_context *ehc = &link->eh_context;
 	const unsigned long *timing = sata_ehc_deb_timing(ehc);
 	int rc;
 
 	/* handle link resume */
 	if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
-	    (ap->flags & ATA_FLAG_HRST_TO_RESUME))
+	    (link->flags & ATA_LFLAG_HRST_TO_RESUME))
+		ehc->i.action |= ATA_EH_HARDRESET;
+
+	/* Some PMPs don't work with only SRST, force hardreset if PMP
+	 * is supported.
+	 */
+	if (ap->flags & ATA_FLAG_PMP)
 		ehc->i.action |= ATA_EH_HARDRESET;
 
 	/* if we're about to do hardreset, nothing more to do */
 	if (ehc->i.action & ATA_EH_HARDRESET)
 		return 0;
 
-	/* if SATA, resume phy */
+	/* if SATA, resume link */
 	if (ap->flags & ATA_FLAG_SATA) {
-		rc = sata_phy_resume(ap, timing, deadline);
+		rc = sata_link_resume(link, timing, deadline);
 		/* whine about phy resume failure but proceed */
 		if (rc && rc != -EOPNOTSUPP)
-			ata_port_printk(ap, KERN_WARNING, "failed to resume "
+			ata_link_printk(link, KERN_WARNING, "failed to resume "
 					"link for reset (errno=%d)\n", rc);
 	}
 
 	/* Wait for !BSY if the controller can wait for the first D2H
 	 * Reg FIS and we don't know that no device is attached.
 	 */
-	if (!(ap->flags & ATA_FLAG_SKIP_D2H_BSY) && !ata_port_offline(ap)) {
+	if (!(link->flags & ATA_LFLAG_SKIP_D2H_BSY) && !ata_link_offline(link)) {
 		rc = ata_wait_ready(ap, deadline);
 		if (rc && rc != -ENODEV) {
-			ata_port_printk(ap, KERN_WARNING, "device not ready "
+			ata_link_printk(link, KERN_WARNING, "device not ready "
 					"(errno=%d), forcing hardreset\n", rc);
 			ehc->i.action |= ATA_EH_HARDRESET;
 		}
@@ -3351,7 +3528,7 @@
 
 /**
  *	ata_std_softreset - reset host port via ATA SRST
- *	@ap: port to reset
+ *	@link: ATA link to reset
  *	@classes: resulting classes of attached devices
  *	@deadline: deadline jiffies for the operation
  *
@@ -3363,9 +3540,10 @@
  *	RETURNS:
  *	0 on success, -errno otherwise.
  */
-int ata_std_softreset(struct ata_port *ap, unsigned int *classes,
+int ata_std_softreset(struct ata_link *link, unsigned int *classes,
 		      unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
 	unsigned int devmask = 0;
 	int rc;
@@ -3373,7 +3551,7 @@
 
 	DPRINTK("ENTER\n");
 
-	if (ata_port_offline(ap)) {
+	if (ata_link_offline(link)) {
 		classes[0] = ATA_DEV_NONE;
 		goto out;
 	}
@@ -3391,15 +3569,17 @@
 	DPRINTK("about to softreset, devmask=%x\n", devmask);
 	rc = ata_bus_softreset(ap, devmask, deadline);
 	/* if link is occupied, -ENODEV too is an error */
-	if (rc && (rc != -ENODEV || sata_scr_valid(ap))) {
-		ata_port_printk(ap, KERN_ERR, "SRST failed (errno=%d)\n", rc);
+	if (rc && (rc != -ENODEV || sata_scr_valid(link))) {
+		ata_link_printk(link, KERN_ERR, "SRST failed (errno=%d)\n", rc);
 		return rc;
 	}
 
 	/* determine by signature whether we have ATA or ATAPI devices */
-	classes[0] = ata_dev_try_classify(ap, 0, &err);
+	classes[0] = ata_dev_try_classify(&link->device[0],
+					  devmask & (1 << 0), &err);
 	if (slave_possible && err != 0x81)
-		classes[1] = ata_dev_try_classify(ap, 1, &err);
+		classes[1] = ata_dev_try_classify(&link->device[1],
+						  devmask & (1 << 1), &err);
 
  out:
 	DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
@@ -3407,12 +3587,12 @@
 }
 
 /**
- *	sata_port_hardreset - reset port via SATA phy reset
- *	@ap: port to reset
+ *	sata_link_hardreset - reset link via SATA phy reset
+ *	@link: link to reset
  *	@timing: timing parameters { interval, duratinon, timeout } in msec
  *	@deadline: deadline jiffies for the operation
  *
- *	SATA phy-reset host port using DET bits of SControl register.
+ *	SATA phy-reset @link using DET bits of SControl register.
  *
  *	LOCKING:
  *	Kernel thread context (may sleep)
@@ -3420,7 +3600,7 @@
  *	RETURNS:
  *	0 on success, -errno otherwise.
  */
-int sata_port_hardreset(struct ata_port *ap, const unsigned long *timing,
+int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
 			unsigned long deadline)
 {
 	u32 scontrol;
@@ -3428,30 +3608,30 @@
 
 	DPRINTK("ENTER\n");
 
-	if (sata_set_spd_needed(ap)) {
+	if (sata_set_spd_needed(link)) {
 		/* SATA spec says nothing about how to reconfigure
 		 * spd.  To be on the safe side, turn off phy during
 		 * reconfiguration.  This works for at least ICH7 AHCI
 		 * and Sil3124.
 		 */
-		if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+		if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
 			goto out;
 
 		scontrol = (scontrol & 0x0f0) | 0x304;
 
-		if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
+		if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
 			goto out;
 
-		sata_set_spd(ap);
+		sata_set_spd(link);
 	}
 
 	/* issue phy wake/reset */
-	if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
+	if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
 		goto out;
 
 	scontrol = (scontrol & 0x0f0) | 0x301;
 
-	if ((rc = sata_scr_write_flush(ap, SCR_CONTROL, scontrol)))
+	if ((rc = sata_scr_write_flush(link, SCR_CONTROL, scontrol)))
 		goto out;
 
 	/* Couldn't find anything in SATA I/II specs, but AHCI-1.1
@@ -3459,8 +3639,8 @@
 	 */
 	msleep(1);
 
-	/* bring phy back */
-	rc = sata_phy_resume(ap, timing, deadline);
+	/* bring link back */
+	rc = sata_link_resume(link, timing, deadline);
  out:
 	DPRINTK("EXIT, rc=%d\n", rc);
 	return rc;
@@ -3468,7 +3648,7 @@
 
 /**
  *	sata_std_hardreset - reset host port via SATA phy reset
- *	@ap: port to reset
+ *	@link: link to reset
  *	@class: resulting class of attached device
  *	@deadline: deadline jiffies for the operation
  *
@@ -3481,24 +3661,25 @@
  *	RETURNS:
  *	0 on success, -errno otherwise.
  */
-int sata_std_hardreset(struct ata_port *ap, unsigned int *class,
+int sata_std_hardreset(struct ata_link *link, unsigned int *class,
 		       unsigned long deadline)
 {
-	const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context);
+	struct ata_port *ap = link->ap;
+	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
 	int rc;
 
 	DPRINTK("ENTER\n");
 
 	/* do hardreset */
-	rc = sata_port_hardreset(ap, timing, deadline);
+	rc = sata_link_hardreset(link, timing, deadline);
 	if (rc) {
-		ata_port_printk(ap, KERN_ERR,
+		ata_link_printk(link, KERN_ERR,
 				"COMRESET failed (errno=%d)\n", rc);
 		return rc;
 	}
 
 	/* TODO: phy layer with polling, timeouts, etc. */
-	if (ata_port_offline(ap)) {
+	if (ata_link_offline(link)) {
 		*class = ATA_DEV_NONE;
 		DPRINTK("EXIT, link offline\n");
 		return 0;
@@ -3507,17 +3688,27 @@
 	/* wait a while before checking status, see SRST for more info */
 	msleep(150);
 
+	/* If PMP is supported, we have to do follow-up SRST.  Note
+	 * that some PMPs don't send D2H Reg FIS after hardreset at
+	 * all if the first port is empty.  Wait for it just for a
+	 * second and request follow-up SRST.
+	 */
+	if (ap->flags & ATA_FLAG_PMP) {
+		ata_wait_ready(ap, jiffies + HZ);
+		return -EAGAIN;
+	}
+
 	rc = ata_wait_ready(ap, deadline);
 	/* link occupied, -ENODEV too is an error */
 	if (rc) {
-		ata_port_printk(ap, KERN_ERR,
+		ata_link_printk(link, KERN_ERR,
 				"COMRESET failed (errno=%d)\n", rc);
 		return rc;
 	}
 
 	ap->ops->dev_select(ap, 0);	/* probably unnecessary */
 
-	*class = ata_dev_try_classify(ap, 0, NULL);
+	*class = ata_dev_try_classify(link->device, 1, NULL);
 
 	DPRINTK("EXIT, class=%u\n", *class);
 	return 0;
@@ -3525,7 +3716,7 @@
 
 /**
  *	ata_std_postreset - standard postreset callback
- *	@ap: the target ata_port
+ *	@link: the target ata_link
  *	@classes: classes of attached devices
  *
  *	This function is invoked after a successful reset.  Note that
@@ -3535,18 +3726,19 @@
  *	LOCKING:
  *	Kernel thread context (may sleep)
  */
-void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
+void ata_std_postreset(struct ata_link *link, unsigned int *classes)
 {
+	struct ata_port *ap = link->ap;
 	u32 serror;
 
 	DPRINTK("ENTER\n");
 
 	/* print link status */
-	sata_print_link_status(ap);
+	sata_print_link_status(link);
 
 	/* clear SError */
-	if (sata_scr_read(ap, SCR_ERROR, &serror) == 0)
-		sata_scr_write(ap, SCR_ERROR, serror);
+	if (sata_scr_read(link, SCR_ERROR, &serror) == 0)
+		sata_scr_write(link, SCR_ERROR, serror);
 
 	/* is double-select really necessary? */
 	if (classes[0] != ATA_DEV_NONE)
@@ -3633,7 +3825,7 @@
 int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags)
 {
 	unsigned int class = dev->class;
-	u16 *id = (void *)dev->ap->sector_buf;
+	u16 *id = (void *)dev->link->ap->sector_buf;
 	int rc;
 
 	/* read ID data */
@@ -3652,6 +3844,7 @@
 /**
  *	ata_dev_revalidate - Revalidate ATA device
  *	@dev: device to revalidate
+ *	@new_class: new class code
  *	@readid_flags: read ID flags
  *
  *	Re-read IDENTIFY page, make sure @dev is still attached to the
@@ -3663,7 +3856,8 @@
  *	RETURNS:
  *	0 on success, negative errno otherwise
  */
-int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags)
+int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
+		       unsigned int readid_flags)
 {
 	u64 n_sectors = dev->n_sectors;
 	int rc;
@@ -3671,6 +3865,15 @@
 	if (!ata_dev_enabled(dev))
 		return -ENODEV;
 
+	/* fail early if !ATA && !ATAPI to avoid issuing [P]IDENTIFY to PMP */
+	if (ata_class_enabled(new_class) &&
+	    new_class != ATA_DEV_ATA && new_class != ATA_DEV_ATAPI) {
+		ata_dev_printk(dev, KERN_INFO, "class mismatch %u != %u\n",
+			       dev->class, new_class);
+		rc = -ENODEV;
+		goto fail;
+	}
+
 	/* re-read ID */
 	rc = ata_dev_reread_id(dev, readid_flags);
 	if (rc)
@@ -3682,11 +3885,16 @@
 		goto fail;
 
 	/* verify n_sectors hasn't changed */
-	if (dev->class == ATA_DEV_ATA && dev->n_sectors != n_sectors) {
+	if (dev->class == ATA_DEV_ATA && n_sectors &&
+	    dev->n_sectors != n_sectors) {
 		ata_dev_printk(dev, KERN_INFO, "n_sectors mismatch "
 			       "%llu != %llu\n",
 			       (unsigned long long)n_sectors,
 			       (unsigned long long)dev->n_sectors);
+
+		/* restore original n_sectors */
+		dev->n_sectors = n_sectors;
+
 		rc = -ENODEV;
 		goto fail;
 	}
@@ -3739,6 +3947,9 @@
 	{ "IOMEGA  ZIP 250       ATAPI", NULL,	ATA_HORKAGE_NODMA }, /* temporary fix */
 	{ "IOMEGA  ZIP 250       ATAPI       Floppy",
 				NULL,		ATA_HORKAGE_NODMA },
+	/* Odd clown on sil3726/4726 PMPs */
+	{ "Config  Disk",	NULL,		ATA_HORKAGE_NODMA |
+						ATA_HORKAGE_SKIP_PM },
 
 	/* Weird ATAPI devices */
 	{ "TORiSAN DVD-ROM DRD-N216", NULL,	ATA_HORKAGE_MAX_SEC_128 },
@@ -3751,13 +3962,12 @@
 	/* http://thread.gmane.org/gmane.linux.ide/14907 */
 	{ "FUJITSU MHT2060BH",	NULL,		ATA_HORKAGE_NONCQ },
 	/* NCQ is broken */
-	{ "Maxtor 6L250S0",     "BANC1G10",     ATA_HORKAGE_NONCQ },
-	{ "Maxtor 6B200M0",	"BANC1BM0",	ATA_HORKAGE_NONCQ },
-	{ "Maxtor 6B200M0",	"BANC1B10",	ATA_HORKAGE_NONCQ },
-	{ "HITACHI HDS7250SASUN500G 0621KTAWSD", "K2AOAJ0AHITACHI",
-	 ATA_HORKAGE_NONCQ },
-	/* NCQ hard hangs device under heavier load, needs hard power cycle */
-	{ "Maxtor 6B250S0",	"BANC1B70",	ATA_HORKAGE_NONCQ },
+	{ "Maxtor *",		"BANC*",	ATA_HORKAGE_NONCQ },
+	{ "Maxtor 7V300F0",	"VA111630",	ATA_HORKAGE_NONCQ },
+	{ "HITACHI HDS7250SASUN500G*", NULL,    ATA_HORKAGE_NONCQ },
+	{ "HITACHI HDS7225SBSUN250G*", NULL,    ATA_HORKAGE_NONCQ },
+	{ "ST380817AS",		"3.42",		ATA_HORKAGE_NONCQ },
+
 	/* Blacklist entries taken from Silicon Image 3124/3132
 	   Windows driver .inf file - also several Linux problem reports */
 	{ "HTS541060G9SA00",    "MB3OC60D",     ATA_HORKAGE_NONCQ, },
@@ -3766,16 +3976,49 @@
 	/* Drives which do spurious command completion */
 	{ "HTS541680J9SA00",	"SB2IC7EP",	ATA_HORKAGE_NONCQ, },
 	{ "HTS541612J9SA00",	"SBDIC7JP",	ATA_HORKAGE_NONCQ, },
+	{ "HDT722516DLA380",	"V43OA96A",	ATA_HORKAGE_NONCQ, },
 	{ "Hitachi HTS541616J9SA00", "SB4OC70P", ATA_HORKAGE_NONCQ, },
 	{ "WDC WD740ADFD-00NLR1", NULL,		ATA_HORKAGE_NONCQ, },
+	{ "WDC WD3200AAJS-00RYA0", "12.01B01",	ATA_HORKAGE_NONCQ, },
 	{ "FUJITSU MHV2080BH",	"00840028",	ATA_HORKAGE_NONCQ, },
+	{ "ST9120822AS",	"3.CLF",	ATA_HORKAGE_NONCQ, },
+	{ "ST9160821AS",	"3.CLF",	ATA_HORKAGE_NONCQ, },
+	{ "ST9160821AS",	"3.ALD",	ATA_HORKAGE_NONCQ, },
+	{ "ST3160812AS",	"3.ADJ",	ATA_HORKAGE_NONCQ, },
+	{ "ST980813AS",		"3.ADB",	ATA_HORKAGE_NONCQ, },
+	{ "SAMSUNG HD401LJ",	"ZZ100-15",	ATA_HORKAGE_NONCQ, },
 
-	/* Devices with NCQ limits */
+	/* devices which puke on READ_NATIVE_MAX */
+	{ "HDS724040KLSA80",	"KFAOA20N",	ATA_HORKAGE_BROKEN_HPA, },
+	{ "WDC WD3200JD-00KLB0", "WD-WCAMR1130137", ATA_HORKAGE_BROKEN_HPA },
+	{ "WDC WD2500JD-00HBB0", "WD-WMAL71490727", ATA_HORKAGE_BROKEN_HPA },
+	{ "MAXTOR 6L080L4",	"A93.0500",	ATA_HORKAGE_BROKEN_HPA },
+
+	/* Devices which report 1 sector over size HPA */
+	{ "ST340823A",		NULL,		ATA_HORKAGE_HPA_SIZE, },
+	{ "ST320413A",		NULL,		ATA_HORKAGE_HPA_SIZE, },
 
 	/* End Marker */
 	{ }
 };
 
+int strn_pattern_cmp(const char *patt, const char *name, int wildchar)
+{
+	const char *p;
+	int len;
+
+	/*
+	 * check for trailing wildcard: *\0
+	 */
+	p = strchr(patt, wildchar);
+	if (p && ((*(p + 1)) == 0))
+		len = p - patt;
+	else
+		len = strlen(name);
+
+	return strncmp(patt, name, len);
+}
+
 static unsigned long ata_dev_blacklisted(const struct ata_device *dev)
 {
 	unsigned char model_num[ATA_ID_PROD_LEN + 1];
@@ -3786,10 +4029,10 @@
 	ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev));
 
 	while (ad->model_num) {
-		if (!strcmp(ad->model_num, model_num)) {
+		if (!strn_pattern_cmp(ad->model_num, model_num, '*')) {
 			if (ad->model_rev == NULL)
 				return ad->horkage;
-			if (!strcmp(ad->model_rev, model_rev))
+			if (!strn_pattern_cmp(ad->model_rev, model_rev, '*'))
 				return ad->horkage;
 		}
 		ad++;
@@ -3803,7 +4046,7 @@
 	 * DMA blacklist those ATAPI devices with CDB-intr (and use PIO)
 	 * if the LLDD handles only interrupts in the HSM_ST_LAST state.
 	 */
-	if ((dev->ap->flags & ATA_FLAG_PIO_POLLING) &&
+	if ((dev->link->ap->flags & ATA_FLAG_PIO_POLLING) &&
 	    (dev->flags & ATA_DFLAG_CDB_INTR))
 		return 1;
 	return (dev->horkage & ATA_HORKAGE_NODMA) ? 1 : 0;
@@ -3823,7 +4066,8 @@
  */
 static void ata_dev_xfermask(struct ata_device *dev)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_link *link = dev->link;
+	struct ata_port *ap = link->ap;
 	struct ata_host *host = ap->host;
 	unsigned long xfer_mask;
 
@@ -3921,7 +4165,43 @@
 	tf.protocol = ATA_PROT_NODATA;
 	tf.nsect = dev->xfer_mode;
 
-	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+
+	DPRINTK("EXIT, err_mask=%x\n", err_mask);
+	return err_mask;
+}
+
+/**
+ *	ata_dev_set_AN - Issue SET FEATURES - SATA FEATURES
+ *	@dev: Device to which command will be sent
+ *	@enable: Whether to enable or disable the feature
+ *
+ *	Issue SET FEATURES - SATA FEATURES command to device @dev
+ *	on port @ap with sector count set to indicate Asynchronous
+ *	Notification feature
+ *
+ *	LOCKING:
+ *	PCI/etc. bus probe sem.
+ *
+ *	RETURNS:
+ *	0 on success, AC_ERR_* mask otherwise.
+ */
+static unsigned int ata_dev_set_AN(struct ata_device *dev, u8 enable)
+{
+	struct ata_taskfile tf;
+	unsigned int err_mask;
+
+	/* set up set-features taskfile */
+	DPRINTK("set features - SATA features\n");
+
+	ata_tf_init(dev, &tf);
+	tf.command = ATA_CMD_SET_FEATURES;
+	tf.feature = enable;
+	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	tf.protocol = ATA_PROT_NODATA;
+	tf.nsect = SATA_AN;
+
+	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
 
 	DPRINTK("EXIT, err_mask=%x\n", err_mask);
 	return err_mask;
@@ -3959,7 +4239,12 @@
 	tf.nsect = sectors;
 	tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */
 
-	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
+	/* A clean abort indicates an original or just out of spec drive
+	   and we should continue as we issue the setup based on the
+	   drive reported working geometry */
+	if (err_mask == AC_ERR_DEV && (tf.feature & ATA_ABORTED))
+		err_mask = 0;
 
 	DPRINTK("EXIT, err_mask=%x\n", err_mask);
 	return err_mask;
@@ -4168,6 +4453,36 @@
 }
 
 /**
+ *	ata_std_qc_defer - Check whether a qc needs to be deferred
+ *	@qc: ATA command in question
+ *
+ *	Non-NCQ commands cannot run with any other command, NCQ or
+ *	not.  As upper layer only knows the queue depth, we are
+ *	responsible for maintaining exclusion.  This function checks
+ *	whether a new command @qc can be issued.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ *
+ *	RETURNS:
+ *	ATA_DEFER_* if deferring is needed, 0 otherwise.
+ */
+int ata_std_qc_defer(struct ata_queued_cmd *qc)
+{
+	struct ata_link *link = qc->dev->link;
+
+	if (qc->tf.protocol == ATA_PROT_NCQ) {
+		if (!ata_tag_valid(link->active_tag))
+			return 0;
+	} else {
+		if (!ata_tag_valid(link->active_tag) && !link->sactive)
+			return 0;
+	}
+
+	return ATA_DEFER_LINK;
+}
+
+/**
  *	ata_qc_prep - Prepare taskfile for submission
  *	@qc: Metadata associated with taskfile to be prepared
  *
@@ -4443,7 +4758,7 @@
 void ata_data_xfer(struct ata_device *adev, unsigned char *buf,
 		   unsigned int buflen, int write_data)
 {
-	struct ata_port *ap = adev->ap;
+	struct ata_port *ap = adev->link->ap;
 	unsigned int words = buflen >> 1;
 
 	/* Transfer multiple of 2 bytes */
@@ -4572,6 +4887,8 @@
 			ata_pio_sector(qc);
 	} else
 		ata_pio_sector(qc);
+
+	ata_altstatus(qc->ap); /* flush */
 }
 
 /**
@@ -4746,6 +5063,7 @@
 	VPRINTK("ata%u: xfering %d bytes\n", ap->print_id, bytes);
 
 	__atapi_pio_bytes(qc, bytes);
+	ata_altstatus(ap); /* flush */
 
 	return;
 
@@ -4917,7 +5235,6 @@
 			 */
 			ap->hsm_task_state = HSM_ST;
 			ata_pio_sectors(qc);
-			ata_altstatus(ap); /* flush */
 		} else
 			/* send CDB */
 			atapi_send_cdb(ap, qc);
@@ -4998,7 +5315,6 @@
 
 				if (!(qc->tf.flags & ATA_TFLAG_WRITE)) {
 					ata_pio_sectors(qc);
-					ata_altstatus(ap);
 					status = ata_wait_idle(ap);
 				}
 
@@ -5018,13 +5334,11 @@
 			if (ap->hsm_task_state == HSM_ST_LAST &&
 			    (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
 				/* all data read */
-				ata_altstatus(ap);
 				status = ata_wait_idle(ap);
 				goto fsm_start;
 			}
 		}
 
-		ata_altstatus(ap); /* flush */
 		poll_next = 1;
 		break;
 
@@ -5149,7 +5463,7 @@
 
 struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_port *ap = dev->link->ap;
 	struct ata_queued_cmd *qc;
 
 	qc = ata_qc_new(ap);
@@ -5192,6 +5506,7 @@
 void __ata_qc_complete(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
+	struct ata_link *link = qc->dev->link;
 
 	WARN_ON(qc == NULL);	/* ata_qc_from_tag _might_ return NULL */
 	WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
@@ -5200,10 +5515,19 @@
 		ata_sg_clean(qc);
 
 	/* command should be marked inactive atomically with qc completion */
-	if (qc->tf.protocol == ATA_PROT_NCQ)
-		ap->sactive &= ~(1 << qc->tag);
-	else
-		ap->active_tag = ATA_TAG_POISON;
+	if (qc->tf.protocol == ATA_PROT_NCQ) {
+		link->sactive &= ~(1 << qc->tag);
+		if (!link->sactive)
+			ap->nr_active_links--;
+	} else {
+		link->active_tag = ATA_TAG_POISON;
+		ap->nr_active_links--;
+	}
+
+	/* clear exclusive status */
+	if (unlikely(qc->flags & ATA_QCFLAG_CLEAR_EXCL &&
+		     ap->excl_link == link))
+		ap->excl_link = NULL;
 
 	/* atapi: mark qc as inactive to prevent the interrupt handler
 	 * from completing the command twice later, before the error handler
@@ -5372,19 +5696,25 @@
 void ata_qc_issue(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
+	struct ata_link *link = qc->dev->link;
 
 	/* Make sure only one non-NCQ command is outstanding.  The
 	 * check is skipped for old EH because it reuses active qc to
 	 * request ATAPI sense.
 	 */
-	WARN_ON(ap->ops->error_handler && ata_tag_valid(ap->active_tag));
+	WARN_ON(ap->ops->error_handler && ata_tag_valid(link->active_tag));
 
 	if (qc->tf.protocol == ATA_PROT_NCQ) {
-		WARN_ON(ap->sactive & (1 << qc->tag));
-		ap->sactive |= 1 << qc->tag;
+		WARN_ON(link->sactive & (1 << qc->tag));
+
+		if (!link->sactive)
+			ap->nr_active_links++;
+		link->sactive |= 1 << qc->tag;
 	} else {
-		WARN_ON(ap->sactive);
-		ap->active_tag = qc->tag;
+		WARN_ON(link->sactive);
+
+		ap->nr_active_links++;
+		link->active_tag = qc->tag;
 	}
 
 	qc->flags |= ATA_QCFLAG_ACTIVE;
@@ -5567,7 +5897,7 @@
 inline unsigned int ata_host_intr (struct ata_port *ap,
 				   struct ata_queued_cmd *qc)
 {
-	struct ata_eh_info *ehi = &ap->eh_info;
+	struct ata_eh_info *ehi = &ap->link.eh_info;
 	u8 status, host_stat = 0;
 
 	VPRINTK("ata%u: protocol %d task_state %d\n",
@@ -5641,7 +5971,8 @@
 
 #ifdef ATA_IRQ_TRAP
 	if ((ap->stats.idle_irq % 1000) == 0) {
-		ap->ops->irq_ack(ap, 0); /* debug trap */
+		ata_chk_status(ap);
+		ap->ops->irq_clear(ap);
 		ata_port_printk(ap, KERN_WARNING, "irq trap\n");
 		return 1;
 	}
@@ -5682,7 +6013,7 @@
 		    !(ap->flags & ATA_FLAG_DISABLED)) {
 			struct ata_queued_cmd *qc;
 
-			qc = ata_qc_from_tag(ap, ap->active_tag);
+			qc = ata_qc_from_tag(ap, ap->link.active_tag);
 			if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
 			    (qc->flags & ATA_QCFLAG_ACTIVE))
 				handled |= ata_host_intr(ap, qc);
@@ -5696,9 +6027,9 @@
 
 /**
  *	sata_scr_valid - test whether SCRs are accessible
- *	@ap: ATA port to test SCR accessibility for
+ *	@link: ATA link to test SCR accessibility for
  *
- *	Test whether SCRs are accessible for @ap.
+ *	Test whether SCRs are accessible for @link.
  *
  *	LOCKING:
  *	None.
@@ -5706,64 +6037,74 @@
  *	RETURNS:
  *	1 if SCRs are accessible, 0 otherwise.
  */
-int sata_scr_valid(struct ata_port *ap)
+int sata_scr_valid(struct ata_link *link)
 {
+	struct ata_port *ap = link->ap;
+
 	return (ap->flags & ATA_FLAG_SATA) && ap->ops->scr_read;
 }
 
 /**
  *	sata_scr_read - read SCR register of the specified port
- *	@ap: ATA port to read SCR for
+ *	@link: ATA link to read SCR for
  *	@reg: SCR to read
  *	@val: Place to store read value
  *
- *	Read SCR register @reg of @ap into *@val.  This function is
- *	guaranteed to succeed if the cable type of the port is SATA
- *	and the port implements ->scr_read.
+ *	Read SCR register @reg of @link into *@val.  This function is
+ *	guaranteed to succeed if @link is ap->link, the cable type of
+ *	the port is SATA and the port implements ->scr_read.
  *
  *	LOCKING:
- *	None.
+ *	None if @link is ap->link.  Kernel thread context otherwise.
  *
  *	RETURNS:
  *	0 on success, negative errno on failure.
  */
-int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
+int sata_scr_read(struct ata_link *link, int reg, u32 *val)
 {
-	if (sata_scr_valid(ap)) {
-		*val = ap->ops->scr_read(ap, reg);
-		return 0;
+	if (ata_is_host_link(link)) {
+		struct ata_port *ap = link->ap;
+
+		if (sata_scr_valid(link))
+			return ap->ops->scr_read(ap, reg, val);
+		return -EOPNOTSUPP;
 	}
-	return -EOPNOTSUPP;
+
+	return sata_pmp_scr_read(link, reg, val);
 }
 
 /**
  *	sata_scr_write - write SCR register of the specified port
- *	@ap: ATA port to write SCR for
+ *	@link: ATA link to write SCR for
  *	@reg: SCR to write
  *	@val: value to write
  *
- *	Write @val to SCR register @reg of @ap.  This function is
- *	guaranteed to succeed if the cable type of the port is SATA
- *	and the port implements ->scr_read.
+ *	Write @val to SCR register @reg of @link.  This function is
+ *	guaranteed to succeed if @link is ap->link, the cable type of
+ *	the port is SATA and the port implements ->scr_read.
  *
  *	LOCKING:
- *	None.
+ *	None if @link is ap->link.  Kernel thread context otherwise.
  *
  *	RETURNS:
  *	0 on success, negative errno on failure.
  */
-int sata_scr_write(struct ata_port *ap, int reg, u32 val)
+int sata_scr_write(struct ata_link *link, int reg, u32 val)
 {
-	if (sata_scr_valid(ap)) {
-		ap->ops->scr_write(ap, reg, val);
-		return 0;
+	if (ata_is_host_link(link)) {
+		struct ata_port *ap = link->ap;
+
+		if (sata_scr_valid(link))
+			return ap->ops->scr_write(ap, reg, val);
+		return -EOPNOTSUPP;
 	}
-	return -EOPNOTSUPP;
+
+	return sata_pmp_scr_write(link, reg, val);
 }
 
 /**
  *	sata_scr_write_flush - write SCR register of the specified port and flush
- *	@ap: ATA port to write SCR for
+ *	@link: ATA link to write SCR for
  *	@reg: SCR to write
  *	@val: value to write
  *
@@ -5771,28 +6112,36 @@
  *	function performs flush after writing to the register.
  *
  *	LOCKING:
- *	None.
+ *	None if @link is ap->link.  Kernel thread context otherwise.
  *
  *	RETURNS:
  *	0 on success, negative errno on failure.
  */
-int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
+int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
 {
-	if (sata_scr_valid(ap)) {
-		ap->ops->scr_write(ap, reg, val);
-		ap->ops->scr_read(ap, reg);
-		return 0;
+	if (ata_is_host_link(link)) {
+		struct ata_port *ap = link->ap;
+		int rc;
+
+		if (sata_scr_valid(link)) {
+			rc = ap->ops->scr_write(ap, reg, val);
+			if (rc == 0)
+				rc = ap->ops->scr_read(ap, reg, &val);
+			return rc;
+		}
+		return -EOPNOTSUPP;
 	}
-	return -EOPNOTSUPP;
+
+	return sata_pmp_scr_write(link, reg, val);
 }
 
 /**
- *	ata_port_online - test whether the given port is online
- *	@ap: ATA port to test
+ *	ata_link_online - test whether the given link is online
+ *	@link: ATA link to test
  *
- *	Test whether @ap is online.  Note that this function returns 0
- *	if online status of @ap cannot be obtained, so
- *	ata_port_online(ap) != !ata_port_offline(ap).
+ *	Test whether @link is online.  Note that this function returns
+ *	0 if online status of @link cannot be obtained, so
+ *	ata_link_online(link) != !ata_link_offline(link).
  *
  *	LOCKING:
  *	None.
@@ -5800,22 +6149,23 @@
  *	RETURNS:
  *	1 if the port online status is available and online.
  */
-int ata_port_online(struct ata_port *ap)
+int ata_link_online(struct ata_link *link)
 {
 	u32 sstatus;
 
-	if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3)
+	if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
+	    (sstatus & 0xf) == 0x3)
 		return 1;
 	return 0;
 }
 
 /**
- *	ata_port_offline - test whether the given port is offline
- *	@ap: ATA port to test
+ *	ata_link_offline - test whether the given link is offline
+ *	@link: ATA link to test
  *
- *	Test whether @ap is offline.  Note that this function returns
- *	0 if offline status of @ap cannot be obtained, so
- *	ata_port_online(ap) != !ata_port_offline(ap).
+ *	Test whether @link is offline.  Note that this function
+ *	returns 0 if offline status of @link cannot be obtained, so
+ *	ata_link_online(link) != !ata_link_offline(link).
  *
  *	LOCKING:
  *	None.
@@ -5823,11 +6173,12 @@
  *	RETURNS:
  *	1 if the port offline status is available and offline.
  */
-int ata_port_offline(struct ata_port *ap)
+int ata_link_offline(struct ata_link *link)
 {
 	u32 sstatus;
 
-	if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3)
+	if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
+	    (sstatus & 0xf) != 0x3)
 		return 1;
 	return 0;
 }
@@ -5845,6 +6196,10 @@
 	else
 		cmd = ATA_CMD_FLUSH;
 
+	/* This is wrong. On a failed flush we get back the LBA of the lost
+	   sector and we should (assuming it wasn't aborted as unknown) issue
+	   a further flush command to continue the writeback until it 
+	   does not error */
 	err_mask = ata_do_simple_cmd(dev, cmd);
 	if (err_mask) {
 		ata_dev_printk(dev, KERN_ERR, "failed to flush cache\n");
@@ -5864,6 +6219,7 @@
 
 	for (i = 0; i < host->n_ports; i++) {
 		struct ata_port *ap = host->ports[i];
+		struct ata_link *link;
 
 		/* Previous resume operation might still be in
 		 * progress.  Wait for PM_PENDING to clear.
@@ -5883,8 +6239,10 @@
 		}
 
 		ap->pflags |= ATA_PFLAG_PM_PENDING;
-		ap->eh_info.action |= action;
-		ap->eh_info.flags |= ehi_flags;
+		__ata_port_for_each_link(link, ap) {
+			link->eh_info.action |= action;
+			link->eh_info.flags |= ehi_flags;
+		}
 
 		ata_port_schedule_eh(ap);
 
@@ -5988,11 +6346,13 @@
  */
 void ata_dev_init(struct ata_device *dev)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_link *link = dev->link;
+	struct ata_port *ap = link->ap;
 	unsigned long flags;
 
 	/* SATA spd limit is bound to the first device */
-	ap->sata_spd_limit = ap->hw_sata_spd_limit;
+	link->sata_spd_limit = link->hw_sata_spd_limit;
+	link->sata_spd = 0;
 
 	/* High bits of dev->flags are used to record warm plug
 	 * requests which occur asynchronously.  Synchronize using
@@ -6000,6 +6360,7 @@
 	 */
 	spin_lock_irqsave(ap->lock, flags);
 	dev->flags &= ~ATA_DFLAG_INIT_MASK;
+	dev->horkage = 0;
 	spin_unlock_irqrestore(ap->lock, flags);
 
 	memset((void *)dev + ATA_DEVICE_CLEAR_OFFSET, 0,
@@ -6010,6 +6371,70 @@
 }
 
 /**
+ *	ata_link_init - Initialize an ata_link structure
+ *	@ap: ATA port link is attached to
+ *	@link: Link structure to initialize
+ *	@pmp: Port multiplier port number
+ *
+ *	Initialize @link.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ */
+void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
+{
+	int i;
+
+	/* clear everything except for devices */
+	memset(link, 0, offsetof(struct ata_link, device[0]));
+
+	link->ap = ap;
+	link->pmp = pmp;
+	link->active_tag = ATA_TAG_POISON;
+	link->hw_sata_spd_limit = UINT_MAX;
+
+	/* can't use iterator, ap isn't initialized yet */
+	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+		struct ata_device *dev = &link->device[i];
+
+		dev->link = link;
+		dev->devno = dev - link->device;
+		ata_dev_init(dev);
+	}
+}
+
+/**
+ *	sata_link_init_spd - Initialize link->sata_spd_limit
+ *	@link: Link to configure sata_spd_limit for
+ *
+ *	Initialize @link->[hw_]sata_spd_limit to the currently
+ *	configured value.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+int sata_link_init_spd(struct ata_link *link)
+{
+	u32 scontrol, spd;
+	int rc;
+
+	rc = sata_scr_read(link, SCR_CONTROL, &scontrol);
+	if (rc)
+		return rc;
+
+	spd = (scontrol >> 4) & 0xf;
+	if (spd)
+		link->hw_sata_spd_limit &= (1 << spd) - 1;
+
+	link->sata_spd_limit = link->hw_sata_spd_limit;
+
+	return 0;
+}
+
+/**
  *	ata_port_alloc - allocate and initialize basic ATA port resources
  *	@host: ATA host this allocated port belongs to
  *
@@ -6024,7 +6449,6 @@
 struct ata_port *ata_port_alloc(struct ata_host *host)
 {
 	struct ata_port *ap;
-	unsigned int i;
 
 	DPRINTK("ENTER\n");
 
@@ -6039,9 +6463,6 @@
 	ap->ctl = ATA_DEVCTL_OBS;
 	ap->host = host;
 	ap->dev = host->dev;
-
-	ap->hw_sata_spd_limit = UINT_MAX;
-	ap->active_tag = ATA_TAG_POISON;
 	ap->last_ctl = 0xFF;
 
 #if defined(ATA_VERBOSE_DEBUG)
@@ -6058,15 +6479,13 @@
 	INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
 	INIT_LIST_HEAD(&ap->eh_done_q);
 	init_waitqueue_head(&ap->eh_wait_q);
+	init_timer_deferrable(&ap->fastdrain_timer);
+	ap->fastdrain_timer.function = ata_eh_fastdrain_timerfn;
+	ap->fastdrain_timer.data = (unsigned long)ap;
 
 	ap->cbl = ATA_CBL_NONE;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
-		dev->ap = ap;
-		dev->devno = i;
-		ata_dev_init(dev);
-	}
+	ata_link_init(ap, &ap->link, 0);
 
 #ifdef ATA_IRQ_TRAP
 	ap->stats.unhandled_irq = 1;
@@ -6102,6 +6521,7 @@
 		if (ap->scsi_host)
 			scsi_host_put(ap->scsi_host);
 
+		kfree(ap->pmp_link);
 		kfree(ap);
 		host->ports[i] = NULL;
 	}
@@ -6212,6 +6632,7 @@
 		ap->mwdma_mask = pi->mwdma_mask;
 		ap->udma_mask = pi->udma_mask;
 		ap->flags |= pi->flags;
+		ap->link.flags |= pi->link_flags;
 		ap->ops = pi->port_ops;
 
 		if (!host->ops && (pi->port_ops != &ata_dummy_port_ops))
@@ -6347,8 +6768,6 @@
 	/* set cable, sata_spd_limit and report */
 	for (i = 0; i < host->n_ports; i++) {
 		struct ata_port *ap = host->ports[i];
-		int irq_line;
-		u32 scontrol;
 		unsigned long xfer_mask;
 
 		/* set SATA cable type if still unset */
@@ -6356,32 +6775,20 @@
 			ap->cbl = ATA_CBL_SATA;
 
 		/* init sata_spd_limit to the current value */
-		if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
-			int spd = (scontrol >> 4) & 0xf;
-			if (spd)
-				ap->hw_sata_spd_limit &= (1 << spd) - 1;
-		}
-		ap->sata_spd_limit = ap->hw_sata_spd_limit;
+		sata_link_init_spd(&ap->link);
 
-		/* report the secondary IRQ for second channel legacy */
-		irq_line = host->irq;
-		if (i == 1 && host->irq2)
-			irq_line = host->irq2;
-
+		/* print per-port info to dmesg */
 		xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
 					      ap->udma_mask);
 
-		/* print per-port info to dmesg */
-		if (!ata_port_is_dummy(ap))
-			ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%p "
-					"ctl 0x%p bmdma 0x%p irq %d\n",
+		if (!ata_port_is_dummy(ap)) {
+			ata_port_printk(ap, KERN_INFO,
+					"%cATA max %s %s\n",
 					(ap->flags & ATA_FLAG_SATA) ? 'S' : 'P',
 					ata_mode_string(xfer_mask),
-					ap->ioaddr.cmd_addr,
-					ap->ioaddr.ctl_addr,
-					ap->ioaddr.bmdma_addr,
-					irq_line);
-		else
+					ap->link.eh_info.desc);
+			ata_ehi_clear_desc(&ap->link.eh_info);
+		} else
 			ata_port_printk(ap, KERN_INFO, "DUMMY\n");
 	}
 
@@ -6393,7 +6800,7 @@
 
 		/* probe */
 		if (ap->ops->error_handler) {
-			struct ata_eh_info *ehi = &ap->eh_info;
+			struct ata_eh_info *ehi = &ap->link.eh_info;
 			unsigned long flags;
 
 			ata_port_probe(ap);
@@ -6401,7 +6808,8 @@
 			/* kick EH for boot probing */
 			spin_lock_irqsave(ap->lock, flags);
 
-			ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+			ehi->probe_mask =
+				(1 << ata_link_max_devices(&ap->link)) - 1;
 			ehi->action |= ATA_EH_SOFTRESET;
 			ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
 
@@ -6434,7 +6842,7 @@
 	for (i = 0; i < host->n_ports; i++) {
 		struct ata_port *ap = host->ports[i];
 
-		ata_scsi_scan_host(ap);
+		ata_scsi_scan_host(ap, 1);
 	}
 
 	return 0;
@@ -6463,7 +6871,7 @@
 		      irq_handler_t irq_handler, unsigned long irq_flags,
 		      struct scsi_host_template *sht)
 {
-	int rc;
+	int i, rc;
 
 	rc = ata_host_start(host);
 	if (rc)
@@ -6474,8 +6882,8 @@
 	if (rc)
 		return rc;
 
-	/* Used to print device info at probe */
-	host->irq = irq;
+	for (i = 0; i < host->n_ports; i++)
+		ata_port_desc(host->ports[i], "irq %d", irq);
 
 	rc = ata_host_register(host, sht);
 	/* if failed, just free the IRQ and leave ports alone */
@@ -6499,7 +6907,8 @@
 void ata_port_detach(struct ata_port *ap)
 {
 	unsigned long flags;
-	int i;
+	struct ata_link *link;
+	struct ata_device *dev;
 
 	if (!ap->ops->error_handler)
 		goto skip_eh;
@@ -6516,8 +6925,10 @@
 	 */
 	spin_lock_irqsave(ap->lock, flags);
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		ata_dev_disable(&ap->device[i]);
+	ata_port_for_each_link(link, ap) {
+		ata_link_for_each_dev(dev, link)
+			ata_dev_disable(dev);
+	}
 
 	spin_unlock_irqrestore(ap->lock, flags);
 
@@ -6596,7 +7007,7 @@
  */
 void ata_pci_remove_one(struct pci_dev *pdev)
 {
-	struct device *dev = pci_dev_to_dev(pdev);
+	struct device *dev = &pdev->dev;
 	struct ata_host *host = dev_get_drvdata(dev);
 
 	ata_host_detach(host);
@@ -6804,7 +7215,6 @@
 }
 
 const struct ata_port_operations ata_dummy_port_ops = {
-	.port_disable		= ata_port_disable,
 	.check_status		= ata_dummy_check_status,
 	.check_altstatus	= ata_dummy_check_status,
 	.dev_select		= ata_noop_dev_select,
@@ -6866,6 +7276,7 @@
 EXPORT_SYMBOL_GPL(ata_do_set_mode);
 EXPORT_SYMBOL_GPL(ata_data_xfer);
 EXPORT_SYMBOL_GPL(ata_data_xfer_noirq);
+EXPORT_SYMBOL_GPL(ata_std_qc_defer);
 EXPORT_SYMBOL_GPL(ata_qc_prep);
 EXPORT_SYMBOL_GPL(ata_dumb_qc_prep);
 EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
@@ -6882,14 +7293,14 @@
 EXPORT_SYMBOL_GPL(ata_port_probe);
 EXPORT_SYMBOL_GPL(ata_dev_disable);
 EXPORT_SYMBOL_GPL(sata_set_spd);
-EXPORT_SYMBOL_GPL(sata_phy_debounce);
-EXPORT_SYMBOL_GPL(sata_phy_resume);
+EXPORT_SYMBOL_GPL(sata_link_debounce);
+EXPORT_SYMBOL_GPL(sata_link_resume);
 EXPORT_SYMBOL_GPL(sata_phy_reset);
 EXPORT_SYMBOL_GPL(__sata_phy_reset);
 EXPORT_SYMBOL_GPL(ata_bus_reset);
 EXPORT_SYMBOL_GPL(ata_std_prereset);
 EXPORT_SYMBOL_GPL(ata_std_softreset);
-EXPORT_SYMBOL_GPL(sata_port_hardreset);
+EXPORT_SYMBOL_GPL(sata_link_hardreset);
 EXPORT_SYMBOL_GPL(sata_std_hardreset);
 EXPORT_SYMBOL_GPL(ata_std_postreset);
 EXPORT_SYMBOL_GPL(ata_dev_classify);
@@ -6910,8 +7321,8 @@
 EXPORT_SYMBOL_GPL(sata_scr_read);
 EXPORT_SYMBOL_GPL(sata_scr_write);
 EXPORT_SYMBOL_GPL(sata_scr_write_flush);
-EXPORT_SYMBOL_GPL(ata_port_online);
-EXPORT_SYMBOL_GPL(ata_port_offline);
+EXPORT_SYMBOL_GPL(ata_link_online);
+EXPORT_SYMBOL_GPL(ata_link_offline);
 #ifdef CONFIG_PM
 EXPORT_SYMBOL_GPL(ata_host_suspend);
 EXPORT_SYMBOL_GPL(ata_host_resume);
@@ -6942,19 +7353,31 @@
 EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
 #endif /* CONFIG_PCI */
 
+EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch);
+EXPORT_SYMBOL_GPL(sata_pmp_std_prereset);
+EXPORT_SYMBOL_GPL(sata_pmp_std_hardreset);
+EXPORT_SYMBOL_GPL(sata_pmp_std_postreset);
+EXPORT_SYMBOL_GPL(sata_pmp_do_eh);
+
+EXPORT_SYMBOL_GPL(__ata_ehi_push_desc);
+EXPORT_SYMBOL_GPL(ata_ehi_push_desc);
+EXPORT_SYMBOL_GPL(ata_ehi_clear_desc);
+EXPORT_SYMBOL_GPL(ata_port_desc);
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL_GPL(ata_port_pbar_desc);
+#endif /* CONFIG_PCI */
 EXPORT_SYMBOL_GPL(ata_eng_timeout);
 EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
+EXPORT_SYMBOL_GPL(ata_link_abort);
 EXPORT_SYMBOL_GPL(ata_port_abort);
 EXPORT_SYMBOL_GPL(ata_port_freeze);
+EXPORT_SYMBOL_GPL(sata_async_notification);
 EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
 EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
 EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
 EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
 EXPORT_SYMBOL_GPL(ata_do_eh);
 EXPORT_SYMBOL_GPL(ata_irq_on);
-EXPORT_SYMBOL_GPL(ata_dummy_irq_on);
-EXPORT_SYMBOL_GPL(ata_irq_ack);
-EXPORT_SYMBOL_GPL(ata_dummy_irq_ack);
 EXPORT_SYMBOL_GPL(ata_dev_try_classify);
 
 EXPORT_SYMBOL_GPL(ata_cable_40wire);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 9aa62a0..2eaa39f 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -33,6 +33,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/pci.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_eh.h>
@@ -56,6 +57,7 @@
  */
 enum {
 	ATA_EH_PRERESET_TIMEOUT		= 10 * HZ,
+	ATA_EH_FASTDRAIN_INTERVAL	= 3 * HZ,
 };
 
 /* The following table determines how we sequence resets.  Each entry
@@ -73,7 +75,6 @@
 };
 
 static void __ata_port_freeze(struct ata_port *ap);
-static void ata_eh_finish(struct ata_port *ap);
 #ifdef CONFIG_PM
 static void ata_eh_handle_port_suspend(struct ata_port *ap);
 static void ata_eh_handle_port_resume(struct ata_port *ap);
@@ -85,6 +86,138 @@
 { }
 #endif /* CONFIG_PM */
 
+static void __ata_ehi_pushv_desc(struct ata_eh_info *ehi, const char *fmt,
+				 va_list args)
+{
+	ehi->desc_len += vscnprintf(ehi->desc + ehi->desc_len,
+				     ATA_EH_DESC_LEN - ehi->desc_len,
+				     fmt, args);
+}
+
+/**
+ *	__ata_ehi_push_desc - push error description without adding separator
+ *	@ehi: target EHI
+ *	@fmt: printf format string
+ *
+ *	Format string according to @fmt and append it to @ehi->desc.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ */
+void __ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	__ata_ehi_pushv_desc(ehi, fmt, args);
+	va_end(args);
+}
+
+/**
+ *	ata_ehi_push_desc - push error description with separator
+ *	@ehi: target EHI
+ *	@fmt: printf format string
+ *
+ *	Format string according to @fmt and append it to @ehi->desc.
+ *	If @ehi->desc is not empty, ", " is added in-between.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ */
+void ata_ehi_push_desc(struct ata_eh_info *ehi, const char *fmt, ...)
+{
+	va_list args;
+
+	if (ehi->desc_len)
+		__ata_ehi_push_desc(ehi, ", ");
+
+	va_start(args, fmt);
+	__ata_ehi_pushv_desc(ehi, fmt, args);
+	va_end(args);
+}
+
+/**
+ *	ata_ehi_clear_desc - clean error description
+ *	@ehi: target EHI
+ *
+ *	Clear @ehi->desc.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ */
+void ata_ehi_clear_desc(struct ata_eh_info *ehi)
+{
+	ehi->desc[0] = '\0';
+	ehi->desc_len = 0;
+}
+
+/**
+ *	ata_port_desc - append port description
+ *	@ap: target ATA port
+ *	@fmt: printf format string
+ *
+ *	Format string according to @fmt and append it to port
+ *	description.  If port description is not empty, " " is added
+ *	in-between.  This function is to be used while initializing
+ *	ata_host.  The description is printed on host registration.
+ *
+ *	LOCKING:
+ *	None.
+ */
+void ata_port_desc(struct ata_port *ap, const char *fmt, ...)
+{
+	va_list args;
+
+	WARN_ON(!(ap->pflags & ATA_PFLAG_INITIALIZING));
+
+	if (ap->link.eh_info.desc_len)
+		__ata_ehi_push_desc(&ap->link.eh_info, " ");
+
+	va_start(args, fmt);
+	__ata_ehi_pushv_desc(&ap->link.eh_info, fmt, args);
+	va_end(args);
+}
+
+#ifdef CONFIG_PCI
+
+/**
+ *	ata_port_pbar_desc - append PCI BAR description
+ *	@ap: target ATA port
+ *	@bar: target PCI BAR
+ *	@offset: offset into PCI BAR
+ *	@name: name of the area
+ *
+ *	If @offset is negative, this function formats a string which
+ *	contains the name, address, size and type of the BAR and
+ *	appends it to the port description.  If @offset is zero or
+ *	positive, only name and offsetted address is appended.
+ *
+ *	LOCKING:
+ *	None.
+ */
+void ata_port_pbar_desc(struct ata_port *ap, int bar, ssize_t offset,
+			const char *name)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+	char *type = "";
+	unsigned long long start, len;
+
+	if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
+		type = "m";
+	else if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
+		type = "i";
+
+	start = (unsigned long long)pci_resource_start(pdev, bar);
+	len = (unsigned long long)pci_resource_len(pdev, bar);
+
+	if (offset < 0)
+		ata_port_desc(ap, "%s %s%llu@0x%llx", name, type, len, start);
+	else
+		ata_port_desc(ap, "%s 0x%llx", name, start + offset);
+}
+
+#endif /* CONFIG_PCI */
+
 static void ata_ering_record(struct ata_ering *ering, int is_io,
 			     unsigned int err_mask)
 {
@@ -129,28 +262,29 @@
 
 static unsigned int ata_eh_dev_action(struct ata_device *dev)
 {
-	struct ata_eh_context *ehc = &dev->ap->eh_context;
+	struct ata_eh_context *ehc = &dev->link->eh_context;
 
 	return ehc->i.action | ehc->i.dev_action[dev->devno];
 }
 
-static void ata_eh_clear_action(struct ata_device *dev,
+static void ata_eh_clear_action(struct ata_link *link, struct ata_device *dev,
 				struct ata_eh_info *ehi, unsigned int action)
 {
-	int i;
+	struct ata_device *tdev;
 
 	if (!dev) {
 		ehi->action &= ~action;
-		for (i = 0; i < ATA_MAX_DEVICES; i++)
-			ehi->dev_action[i] &= ~action;
+		ata_link_for_each_dev(tdev, link)
+			ehi->dev_action[tdev->devno] &= ~action;
 	} else {
 		/* doesn't make sense for port-wide EH actions */
 		WARN_ON(!(action & ATA_EH_PERDEV_MASK));
 
 		/* break ehi->action into ehi->dev_action */
 		if (ehi->action & action) {
-			for (i = 0; i < ATA_MAX_DEVICES; i++)
-				ehi->dev_action[i] |= ehi->action & action;
+			ata_link_for_each_dev(tdev, link)
+				ehi->dev_action[tdev->devno] |=
+					ehi->action & action;
 			ehi->action &= ~action;
 		}
 
@@ -195,7 +329,7 @@
 
 	ret = EH_HANDLED;
 	spin_lock_irqsave(ap->lock, flags);
-	qc = ata_qc_from_tag(ap, ap->active_tag);
+	qc = ata_qc_from_tag(ap, ap->link.active_tag);
 	if (qc) {
 		WARN_ON(qc->scsicmd != cmd);
 		qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
@@ -224,7 +358,7 @@
 void ata_scsi_error(struct Scsi_Host *host)
 {
 	struct ata_port *ap = ata_shost_to_port(host);
-	int i, repeat_cnt = ATA_EH_MAX_REPEAT;
+	int i;
 	unsigned long flags;
 
 	DPRINTK("ENTER\n");
@@ -290,24 +424,35 @@
 			__ata_port_freeze(ap);
 
 		spin_unlock_irqrestore(ap->lock, flags);
+
+		/* initialize eh_tries */
+		ap->eh_tries = ATA_EH_MAX_TRIES;
 	} else
 		spin_unlock_wait(ap->lock);
 
  repeat:
 	/* invoke error handler */
 	if (ap->ops->error_handler) {
+		struct ata_link *link;
+
+		/* kill fast drain timer */
+		del_timer_sync(&ap->fastdrain_timer);
+
 		/* process port resume request */
 		ata_eh_handle_port_resume(ap);
 
 		/* fetch & clear EH info */
 		spin_lock_irqsave(ap->lock, flags);
 
-		memset(&ap->eh_context, 0, sizeof(ap->eh_context));
-		ap->eh_context.i = ap->eh_info;
-		memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+		__ata_port_for_each_link(link, ap) {
+			memset(&link->eh_context, 0, sizeof(link->eh_context));
+			link->eh_context.i = link->eh_info;
+			memset(&link->eh_info, 0, sizeof(link->eh_info));
+		}
 
 		ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
 		ap->pflags &= ~ATA_PFLAG_EH_PENDING;
+		ap->excl_link = NULL;	/* don't maintain exclusion over EH */
 
 		spin_unlock_irqrestore(ap->lock, flags);
 
@@ -327,20 +472,18 @@
 		spin_lock_irqsave(ap->lock, flags);
 
 		if (ap->pflags & ATA_PFLAG_EH_PENDING) {
-			if (--repeat_cnt) {
-				ata_port_printk(ap, KERN_INFO,
-					"EH pending after completion, "
-					"repeating EH (cnt=%d)\n", repeat_cnt);
+			if (--ap->eh_tries) {
 				spin_unlock_irqrestore(ap->lock, flags);
 				goto repeat;
 			}
 			ata_port_printk(ap, KERN_ERR, "EH pending after %d "
-					"tries, giving up\n", ATA_EH_MAX_REPEAT);
+					"tries, giving up\n", ATA_EH_MAX_TRIES);
 			ap->pflags &= ~ATA_PFLAG_EH_PENDING;
 		}
 
 		/* this run is complete, make sure EH info is clear */
-		memset(&ap->eh_info, 0, sizeof(ap->eh_info));
+		__ata_port_for_each_link(link, ap)
+			memset(&link->eh_info, 0, sizeof(link->eh_info));
 
 		/* Clear host_eh_scheduled while holding ap->lock such
 		 * that if exception occurs after this point but
@@ -351,7 +494,7 @@
 
 		spin_unlock_irqrestore(ap->lock, flags);
 	} else {
-		WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
+		WARN_ON(ata_qc_from_tag(ap, ap->link.active_tag) == NULL);
 		ap->ops->eng_timeout(ap);
 	}
 
@@ -506,11 +649,99 @@
 {
 	DPRINTK("ENTER\n");
 
-	ata_qc_timeout(ata_qc_from_tag(ap, ap->active_tag));
+	ata_qc_timeout(ata_qc_from_tag(ap, ap->link.active_tag));
 
 	DPRINTK("EXIT\n");
 }
 
+static int ata_eh_nr_in_flight(struct ata_port *ap)
+{
+	unsigned int tag;
+	int nr = 0;
+
+	/* count only non-internal commands */
+	for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++)
+		if (ata_qc_from_tag(ap, tag))
+			nr++;
+
+	return nr;
+}
+
+void ata_eh_fastdrain_timerfn(unsigned long arg)
+{
+	struct ata_port *ap = (void *)arg;
+	unsigned long flags;
+	int cnt;
+
+	spin_lock_irqsave(ap->lock, flags);
+
+	cnt = ata_eh_nr_in_flight(ap);
+
+	/* are we done? */
+	if (!cnt)
+		goto out_unlock;
+
+	if (cnt == ap->fastdrain_cnt) {
+		unsigned int tag;
+
+		/* No progress during the last interval, tag all
+		 * in-flight qcs as timed out and freeze the port.
+		 */
+		for (tag = 0; tag < ATA_MAX_QUEUE - 1; tag++) {
+			struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
+			if (qc)
+				qc->err_mask |= AC_ERR_TIMEOUT;
+		}
+
+		ata_port_freeze(ap);
+	} else {
+		/* some qcs have finished, give it another chance */
+		ap->fastdrain_cnt = cnt;
+		ap->fastdrain_timer.expires =
+			jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+		add_timer(&ap->fastdrain_timer);
+	}
+
+ out_unlock:
+	spin_unlock_irqrestore(ap->lock, flags);
+}
+
+/**
+ *	ata_eh_set_pending - set ATA_PFLAG_EH_PENDING and activate fast drain
+ *	@ap: target ATA port
+ *	@fastdrain: activate fast drain
+ *
+ *	Set ATA_PFLAG_EH_PENDING and activate fast drain if @fastdrain
+ *	is non-zero and EH wasn't pending before.  Fast drain ensures
+ *	that EH kicks in in timely manner.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ */
+static void ata_eh_set_pending(struct ata_port *ap, int fastdrain)
+{
+	int cnt;
+
+	/* already scheduled? */
+	if (ap->pflags & ATA_PFLAG_EH_PENDING)
+		return;
+
+	ap->pflags |= ATA_PFLAG_EH_PENDING;
+
+	if (!fastdrain)
+		return;
+
+	/* do we have in-flight qcs? */
+	cnt = ata_eh_nr_in_flight(ap);
+	if (!cnt)
+		return;
+
+	/* activate fast drain */
+	ap->fastdrain_cnt = cnt;
+	ap->fastdrain_timer.expires = jiffies + ATA_EH_FASTDRAIN_INTERVAL;
+	add_timer(&ap->fastdrain_timer);
+}
+
 /**
  *	ata_qc_schedule_eh - schedule qc for error handling
  *	@qc: command to schedule error handling for
@@ -528,7 +759,7 @@
 	WARN_ON(!ap->ops->error_handler);
 
 	qc->flags |= ATA_QCFLAG_FAILED;
-	qc->ap->pflags |= ATA_PFLAG_EH_PENDING;
+	ata_eh_set_pending(ap, 1);
 
 	/* The following will fail if timeout has already expired.
 	 * ata_scsi_error() takes care of such scmds on EH entry.
@@ -555,34 +786,25 @@
 	if (ap->pflags & ATA_PFLAG_INITIALIZING)
 		return;
 
-	ap->pflags |= ATA_PFLAG_EH_PENDING;
+	ata_eh_set_pending(ap, 1);
 	scsi_schedule_eh(ap->scsi_host);
 
 	DPRINTK("port EH scheduled\n");
 }
 
-/**
- *	ata_port_abort - abort all qc's on the port
- *	@ap: ATA port to abort qc's for
- *
- *	Abort all active qc's of @ap and schedule EH.
- *
- *	LOCKING:
- *	spin_lock_irqsave(host lock)
- *
- *	RETURNS:
- *	Number of aborted qc's.
- */
-int ata_port_abort(struct ata_port *ap)
+static int ata_do_link_abort(struct ata_port *ap, struct ata_link *link)
 {
 	int tag, nr_aborted = 0;
 
 	WARN_ON(!ap->ops->error_handler);
 
+	/* we're gonna abort all commands, no need for fast drain */
+	ata_eh_set_pending(ap, 0);
+
 	for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
 		struct ata_queued_cmd *qc = ata_qc_from_tag(ap, tag);
 
-		if (qc) {
+		if (qc && (!link || qc->dev->link == link)) {
 			qc->flags |= ATA_QCFLAG_FAILED;
 			ata_qc_complete(qc);
 			nr_aborted++;
@@ -596,6 +818,40 @@
 }
 
 /**
+ *	ata_link_abort - abort all qc's on the link
+ *	@link: ATA link to abort qc's for
+ *
+ *	Abort all active qc's active on @link and schedule EH.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ *
+ *	RETURNS:
+ *	Number of aborted qc's.
+ */
+int ata_link_abort(struct ata_link *link)
+{
+	return ata_do_link_abort(link->ap, link);
+}
+
+/**
+ *	ata_port_abort - abort all qc's on the port
+ *	@ap: ATA port to abort qc's for
+ *
+ *	Abort all active qc's of @ap and schedule EH.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Number of aborted qc's.
+ */
+int ata_port_abort(struct ata_port *ap)
+{
+	return ata_do_link_abort(ap, NULL);
+}
+
+/**
  *	__ata_port_freeze - freeze port
  *	@ap: ATA port to freeze
  *
@@ -650,6 +906,79 @@
 }
 
 /**
+ *	sata_async_notification - SATA async notification handler
+ *	@ap: ATA port where async notification is received
+ *
+ *	Handler to be called when async notification via SDB FIS is
+ *	received.  This function schedules EH if necessary.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ *
+ *	RETURNS:
+ *	1 if EH is scheduled, 0 otherwise.
+ */
+int sata_async_notification(struct ata_port *ap)
+{
+	u32 sntf;
+	int rc;
+
+	if (!(ap->flags & ATA_FLAG_AN))
+		return 0;
+
+	rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
+	if (rc == 0)
+		sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
+
+	if (!ap->nr_pmp_links || rc) {
+		/* PMP is not attached or SNTF is not available */
+		if (!ap->nr_pmp_links) {
+			/* PMP is not attached.  Check whether ATAPI
+			 * AN is configured.  If so, notify media
+			 * change.
+			 */
+			struct ata_device *dev = ap->link.device;
+
+			if ((dev->class == ATA_DEV_ATAPI) &&
+			    (dev->flags & ATA_DFLAG_AN))
+				ata_scsi_media_change_notify(dev);
+			return 0;
+		} else {
+			/* PMP is attached but SNTF is not available.
+			 * ATAPI async media change notification is
+			 * not used.  The PMP must be reporting PHY
+			 * status change, schedule EH.
+			 */
+			ata_port_schedule_eh(ap);
+			return 1;
+		}
+	} else {
+		/* PMP is attached and SNTF is available */
+		struct ata_link *link;
+
+		/* check and notify ATAPI AN */
+		ata_port_for_each_link(link, ap) {
+			if (!(sntf & (1 << link->pmp)))
+				continue;
+
+			if ((link->device->class == ATA_DEV_ATAPI) &&
+			    (link->device->flags & ATA_DFLAG_AN))
+				ata_scsi_media_change_notify(link->device);
+		}
+
+		/* If PMP is reporting that PHY status of some
+		 * downstream ports has changed, schedule EH.
+		 */
+		if (sntf & (1 << SATA_PMP_CTRL_PORT)) {
+			ata_port_schedule_eh(ap);
+			return 1;
+		}
+
+		return 0;
+	}
+}
+
+/**
  *	ata_eh_freeze_port - EH helper to freeze port
  *	@ap: ATA port to freeze
  *
@@ -760,9 +1089,10 @@
  *	LOCKING:
  *	None.
  */
-static void ata_eh_detach_dev(struct ata_device *dev)
+void ata_eh_detach_dev(struct ata_device *dev)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_link *link = dev->link;
+	struct ata_port *ap = link->ap;
 	unsigned long flags;
 
 	ata_dev_disable(dev);
@@ -777,31 +1107,32 @@
 	}
 
 	/* clear per-dev EH actions */
-	ata_eh_clear_action(dev, &ap->eh_info, ATA_EH_PERDEV_MASK);
-	ata_eh_clear_action(dev, &ap->eh_context.i, ATA_EH_PERDEV_MASK);
+	ata_eh_clear_action(link, dev, &link->eh_info, ATA_EH_PERDEV_MASK);
+	ata_eh_clear_action(link, dev, &link->eh_context.i, ATA_EH_PERDEV_MASK);
 
 	spin_unlock_irqrestore(ap->lock, flags);
 }
 
 /**
  *	ata_eh_about_to_do - about to perform eh_action
- *	@ap: target ATA port
+ *	@link: target ATA link
  *	@dev: target ATA dev for per-dev action (can be NULL)
  *	@action: action about to be performed
  *
  *	Called just before performing EH actions to clear related bits
- *	in @ap->eh_info such that eh actions are not unnecessarily
+ *	in @link->eh_info such that eh actions are not unnecessarily
  *	repeated.
  *
  *	LOCKING:
  *	None.
  */
-static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
-			       unsigned int action)
+void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
+			unsigned int action)
 {
+	struct ata_port *ap = link->ap;
+	struct ata_eh_info *ehi = &link->eh_info;
+	struct ata_eh_context *ehc = &link->eh_context;
 	unsigned long flags;
-	struct ata_eh_info *ehi = &ap->eh_info;
-	struct ata_eh_context *ehc = &ap->eh_context;
 
 	spin_lock_irqsave(ap->lock, flags);
 
@@ -818,7 +1149,7 @@
 		ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
 	}
 
-	ata_eh_clear_action(dev, ehi, action);
+	ata_eh_clear_action(link, dev, ehi, action);
 
 	if (!(ehc->i.flags & ATA_EHI_QUIET))
 		ap->pflags |= ATA_PFLAG_RECOVERED;
@@ -828,26 +1159,28 @@
 
 /**
  *	ata_eh_done - EH action complete
- *	@ap: target ATA port
+*	@ap: target ATA port
  *	@dev: target ATA dev for per-dev action (can be NULL)
  *	@action: action just completed
  *
  *	Called right after performing EH actions to clear related bits
- *	in @ap->eh_context.
+ *	in @link->eh_context.
  *
  *	LOCKING:
  *	None.
  */
-static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
-			unsigned int action)
+void ata_eh_done(struct ata_link *link, struct ata_device *dev,
+		 unsigned int action)
 {
+	struct ata_eh_context *ehc = &link->eh_context;
+
 	/* if reset is complete, clear all reset actions & reset modifier */
 	if (action & ATA_EH_RESET_MASK) {
 		action |= ATA_EH_RESET_MASK;
-		ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
+		ehc->i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
 	}
 
-	ata_eh_clear_action(dev, &ap->eh_context.i, action);
+	ata_eh_clear_action(link, dev, &ehc->i, action);
 }
 
 /**
@@ -917,7 +1250,7 @@
 	tf.protocol = ATA_PROT_PIO;
 
 	err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
-				     buf, sectors * ATA_SECT_SIZE);
+				     buf, sectors * ATA_SECT_SIZE, 0);
 
 	DPRINTK("EXIT, err_mask=%x\n", err_mask);
 	return err_mask;
@@ -941,7 +1274,7 @@
 static int ata_eh_read_log_10h(struct ata_device *dev,
 			       int *tag, struct ata_taskfile *tf)
 {
-	u8 *buf = dev->ap->sector_buf;
+	u8 *buf = dev->link->ap->sector_buf;
 	unsigned int err_mask;
 	u8 csum;
 	int i;
@@ -995,7 +1328,7 @@
 {
 	struct ata_device *dev = qc->dev;
 	unsigned char *sense_buf = qc->scsicmd->sense_buffer;
-	struct ata_port *ap = dev->ap;
+	struct ata_port *ap = dev->link->ap;
 	struct ata_taskfile tf;
 	u8 cdb[ATAPI_CDB_LEN];
 
@@ -1031,12 +1364,12 @@
 	}
 
 	return ata_exec_internal(dev, &tf, cdb, DMA_FROM_DEVICE,
-				 sense_buf, SCSI_SENSE_BUFFERSIZE);
+				 sense_buf, SCSI_SENSE_BUFFERSIZE, 0);
 }
 
 /**
  *	ata_eh_analyze_serror - analyze SError for a failed port
- *	@ap: ATA port to analyze SError for
+ *	@link: ATA link to analyze SError for
  *
  *	Analyze SError if available and further determine cause of
  *	failure.
@@ -1044,11 +1377,12 @@
  *	LOCKING:
  *	None.
  */
-static void ata_eh_analyze_serror(struct ata_port *ap)
+static void ata_eh_analyze_serror(struct ata_link *link)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_eh_context *ehc = &link->eh_context;
 	u32 serror = ehc->i.serror;
 	unsigned int err_mask = 0, action = 0;
+	u32 hotplug_mask;
 
 	if (serror & SERR_PERSISTENT) {
 		err_mask |= AC_ERR_ATA_BUS;
@@ -1067,7 +1401,20 @@
 		err_mask |= AC_ERR_SYSTEM;
 		action |= ATA_EH_HARDRESET;
 	}
-	if (serror & (SERR_PHYRDY_CHG | SERR_DEV_XCHG))
+
+	/* Determine whether a hotplug event has occurred.  Both
+	 * SError.N/X are considered hotplug events for enabled or
+	 * host links.  For disabled PMP links, only N bit is
+	 * considered as X bit is left at 1 for link plugging.
+	 */
+	hotplug_mask = 0;
+
+	if (!(link->flags & ATA_LFLAG_DISABLED) || ata_is_host_link(link))
+		hotplug_mask = SERR_PHYRDY_CHG | SERR_DEV_XCHG;
+	else
+		hotplug_mask = SERR_PHYRDY_CHG;
+
+	if (serror & hotplug_mask)
 		ata_ehi_hotplugged(&ehc->i);
 
 	ehc->i.err_mask |= err_mask;
@@ -1076,7 +1423,7 @@
 
 /**
  *	ata_eh_analyze_ncq_error - analyze NCQ error
- *	@ap: ATA port to analyze NCQ error for
+ *	@link: ATA link to analyze NCQ error for
  *
  *	Read log page 10h, determine the offending qc and acquire
  *	error status TF.  For NCQ device errors, all LLDDs have to do
@@ -1086,10 +1433,11 @@
  *	LOCKING:
  *	Kernel thread context (may sleep).
  */
-static void ata_eh_analyze_ncq_error(struct ata_port *ap)
+static void ata_eh_analyze_ncq_error(struct ata_link *link)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
-	struct ata_device *dev = ap->device;
+	struct ata_port *ap = link->ap;
+	struct ata_eh_context *ehc = &link->eh_context;
+	struct ata_device *dev = link->device;
 	struct ata_queued_cmd *qc;
 	struct ata_taskfile tf;
 	int tag, rc;
@@ -1099,7 +1447,7 @@
 		return;
 
 	/* is it NCQ device error? */
-	if (!ap->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
+	if (!link->sactive || !(ehc->i.err_mask & AC_ERR_DEV))
 		return;
 
 	/* has LLDD analyzed already? */
@@ -1116,13 +1464,13 @@
 	/* okay, this error is ours */
 	rc = ata_eh_read_log_10h(dev, &tag, &tf);
 	if (rc) {
-		ata_port_printk(ap, KERN_ERR, "failed to read log page 10h "
+		ata_link_printk(link, KERN_ERR, "failed to read log page 10h "
 				"(errno=%d)\n", rc);
 		return;
 	}
 
-	if (!(ap->sactive & (1 << tag))) {
-		ata_port_printk(ap, KERN_ERR, "log page 10h reported "
+	if (!(link->sactive & (1 << tag))) {
+		ata_link_printk(link, KERN_ERR, "log page 10h reported "
 				"inactive tag %d\n", tag);
 		return;
 	}
@@ -1130,7 +1478,7 @@
 	/* we've got the perpetrator, condemn it */
 	qc = __ata_qc_from_tag(ap, tag);
 	memcpy(&qc->result_tf, &tf, sizeof(tf));
-	qc->err_mask |= AC_ERR_DEV;
+	qc->err_mask |= AC_ERR_DEV | AC_ERR_NCQ;
 	ehc->i.err_mask &= ~AC_ERR_DEV;
 }
 
@@ -1337,7 +1685,7 @@
 	/* speed down? */
 	if (verdict & ATA_EH_SPDN_SPEED_DOWN) {
 		/* speed down SATA link speed if possible */
-		if (sata_down_spd_limit(dev->ap) == 0) {
+		if (sata_down_spd_limit(dev->link) == 0) {
 			action |= ATA_EH_HARDRESET;
 			goto done;
 		}
@@ -1368,7 +1716,7 @@
 	 * SATA.  Consider it only for PATA.
 	 */
 	if ((verdict & ATA_EH_SPDN_FALLBACK_TO_PIO) && (dev->spdn_cnt >= 2) &&
-	    (dev->ap->cbl != ATA_CBL_SATA) &&
+	    (dev->link->ap->cbl != ATA_CBL_SATA) &&
 	    (dev->xfer_shift != ATA_SHIFT_PIO)) {
 		if (ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO) == 0) {
 			dev->spdn_cnt = 0;
@@ -1385,19 +1733,20 @@
 }
 
 /**
- *	ata_eh_autopsy - analyze error and determine recovery action
- *	@ap: ATA port to perform autopsy on
+ *	ata_eh_link_autopsy - analyze error and determine recovery action
+ *	@link: host link to perform autopsy on
  *
- *	Analyze why @ap failed and determine which recovery action is
- *	needed.  This function also sets more detailed AC_ERR_* values
- *	and fills sense data for ATAPI CHECK SENSE.
+ *	Analyze why @link failed and determine which recovery actions
+ *	are needed.  This function also sets more detailed AC_ERR_*
+ *	values and fills sense data for ATAPI CHECK SENSE.
  *
  *	LOCKING:
  *	Kernel thread context (may sleep).
  */
-static void ata_eh_autopsy(struct ata_port *ap)
+static void ata_eh_link_autopsy(struct ata_link *link)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_port *ap = link->ap;
+	struct ata_eh_context *ehc = &link->eh_context;
 	unsigned int all_err_mask = 0;
 	int tag, is_io = 0;
 	u32 serror;
@@ -1409,15 +1758,19 @@
 		return;
 
 	/* obtain and analyze SError */
-	rc = sata_scr_read(ap, SCR_ERROR, &serror);
+	rc = sata_scr_read(link, SCR_ERROR, &serror);
 	if (rc == 0) {
 		ehc->i.serror |= serror;
-		ata_eh_analyze_serror(ap);
-	} else if (rc != -EOPNOTSUPP)
+		ata_eh_analyze_serror(link);
+	} else if (rc != -EOPNOTSUPP) {
+		/* SError read failed, force hardreset and probing */
+		ata_ehi_schedule_probe(&ehc->i);
 		ehc->i.action |= ATA_EH_HARDRESET;
+		ehc->i.err_mask |= AC_ERR_OTHER;
+	}
 
 	/* analyze NCQ failure */
-	ata_eh_analyze_ncq_error(ap);
+	ata_eh_analyze_ncq_error(link);
 
 	/* any real error trumps AC_ERR_OTHER */
 	if (ehc->i.err_mask & ~AC_ERR_OTHER)
@@ -1428,7 +1781,7 @@
 	for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
 		struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
 
-		if (!(qc->flags & ATA_QCFLAG_FAILED))
+		if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link)
 			continue;
 
 		/* inherit upper level err_mask */
@@ -1482,20 +1835,43 @@
 }
 
 /**
- *	ata_eh_report - report error handling to user
- *	@ap: ATA port EH is going on
+ *	ata_eh_autopsy - analyze error and determine recovery action
+ *	@ap: host port to perform autopsy on
+ *
+ *	Analyze all links of @ap and determine why they failed and
+ *	which recovery actions are needed.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ */
+void ata_eh_autopsy(struct ata_port *ap)
+{
+	struct ata_link *link;
+
+	__ata_port_for_each_link(link, ap)
+		ata_eh_link_autopsy(link);
+}
+
+/**
+ *	ata_eh_link_report - report error handling to user
+ *	@link: ATA link EH is going on
  *
  *	Report EH to user.
  *
  *	LOCKING:
  *	None.
  */
-static void ata_eh_report(struct ata_port *ap)
+static void ata_eh_link_report(struct ata_link *link)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_port *ap = link->ap;
+	struct ata_eh_context *ehc = &link->eh_context;
 	const char *frozen, *desc;
+	char tries_buf[6];
 	int tag, nr_failed = 0;
 
+	if (ehc->i.flags & ATA_EHI_QUIET)
+		return;
+
 	desc = NULL;
 	if (ehc->i.desc[0] != '\0')
 		desc = ehc->i.desc;
@@ -1503,7 +1879,7 @@
 	for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
 		struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
 
-		if (!(qc->flags & ATA_QCFLAG_FAILED))
+		if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link)
 			continue;
 		if (qc->flags & ATA_QCFLAG_SENSE_VALID && !qc->err_mask)
 			continue;
@@ -1518,22 +1894,48 @@
 	if (ap->pflags & ATA_PFLAG_FROZEN)
 		frozen = " frozen";
 
+	memset(tries_buf, 0, sizeof(tries_buf));
+	if (ap->eh_tries < ATA_EH_MAX_TRIES)
+		snprintf(tries_buf, sizeof(tries_buf) - 1, " t%d",
+			 ap->eh_tries);
+
 	if (ehc->i.dev) {
 		ata_dev_printk(ehc->i.dev, KERN_ERR, "exception Emask 0x%x "
-			       "SAct 0x%x SErr 0x%x action 0x%x%s\n",
-			       ehc->i.err_mask, ap->sactive, ehc->i.serror,
-			       ehc->i.action, frozen);
+			       "SAct 0x%x SErr 0x%x action 0x%x%s%s\n",
+			       ehc->i.err_mask, link->sactive, ehc->i.serror,
+			       ehc->i.action, frozen, tries_buf);
 		if (desc)
-			ata_dev_printk(ehc->i.dev, KERN_ERR, "(%s)\n", desc);
+			ata_dev_printk(ehc->i.dev, KERN_ERR, "%s\n", desc);
 	} else {
-		ata_port_printk(ap, KERN_ERR, "exception Emask 0x%x "
-				"SAct 0x%x SErr 0x%x action 0x%x%s\n",
-				ehc->i.err_mask, ap->sactive, ehc->i.serror,
-				ehc->i.action, frozen);
+		ata_link_printk(link, KERN_ERR, "exception Emask 0x%x "
+				"SAct 0x%x SErr 0x%x action 0x%x%s%s\n",
+				ehc->i.err_mask, link->sactive, ehc->i.serror,
+				ehc->i.action, frozen, tries_buf);
 		if (desc)
-			ata_port_printk(ap, KERN_ERR, "(%s)\n", desc);
+			ata_link_printk(link, KERN_ERR, "%s\n", desc);
 	}
 
+	if (ehc->i.serror)
+		ata_port_printk(ap, KERN_ERR,
+		  "SError: { %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s}\n",
+		  ehc->i.serror & SERR_DATA_RECOVERED ? "RecovData " : "",
+		  ehc->i.serror & SERR_COMM_RECOVERED ? "RecovComm " : "",
+		  ehc->i.serror & SERR_DATA ? "UnrecovData " : "",
+		  ehc->i.serror & SERR_PERSISTENT ? "Persist " : "",
+		  ehc->i.serror & SERR_PROTOCOL ? "Proto " : "",
+		  ehc->i.serror & SERR_INTERNAL ? "HostInt " : "",
+		  ehc->i.serror & SERR_PHYRDY_CHG ? "PHYRdyChg " : "",
+		  ehc->i.serror & SERR_PHY_INT_ERR ? "PHYInt " : "",
+		  ehc->i.serror & SERR_COMM_WAKE ? "CommWake " : "",
+		  ehc->i.serror & SERR_10B_8B_ERR ? "10B8B " : "",
+		  ehc->i.serror & SERR_DISPARITY ? "Dispar " : "",
+		  ehc->i.serror & SERR_CRC ? "BadCRC " : "",
+		  ehc->i.serror & SERR_HANDSHAKE ? "Handshk " : "",
+		  ehc->i.serror & SERR_LINK_SEQ_ERR ? "LinkSeq " : "",
+		  ehc->i.serror & SERR_TRANS_ST_ERROR ? "TrStaTrns " : "",
+		  ehc->i.serror & SERR_UNRECOG_FIS ? "UnrecFIS " : "",
+		  ehc->i.serror & SERR_DEV_XCHG ? "DevExch " : "" );
+
 	for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
 		static const char *dma_str[] = {
 			[DMA_BIDIRECTIONAL]	= "bidi",
@@ -1544,14 +1946,15 @@
 		struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
 		struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf;
 
-		if (!(qc->flags & ATA_QCFLAG_FAILED) || !qc->err_mask)
+		if (!(qc->flags & ATA_QCFLAG_FAILED) ||
+		    qc->dev->link != link || !qc->err_mask)
 			continue;
 
 		ata_dev_printk(qc->dev, KERN_ERR,
 			"cmd %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
 			"tag %d cdb 0x%x data %u %s\n         "
 			"res %02x/%02x:%02x:%02x:%02x:%02x/%02x:%02x:%02x:%02x:%02x/%02x "
-			"Emask 0x%x (%s)\n",
+			"Emask 0x%x (%s)%s\n",
 			cmd->command, cmd->feature, cmd->nsect,
 			cmd->lbal, cmd->lbam, cmd->lbah,
 			cmd->hob_feature, cmd->hob_nsect,
@@ -1562,19 +1965,62 @@
 			res->lbal, res->lbam, res->lbah,
 			res->hob_feature, res->hob_nsect,
 			res->hob_lbal, res->hob_lbam, res->hob_lbah,
-			res->device, qc->err_mask, ata_err_string(qc->err_mask));
+			res->device, qc->err_mask, ata_err_string(qc->err_mask),
+			qc->err_mask & AC_ERR_NCQ ? " <F>" : "");
+
+		if (res->command & (ATA_BUSY | ATA_DRDY | ATA_DF | ATA_DRQ |
+				    ATA_ERR) ) {
+			if (res->command & ATA_BUSY)
+				ata_dev_printk(qc->dev, KERN_ERR,
+				  "status: { Busy }\n" );
+			else
+				ata_dev_printk(qc->dev, KERN_ERR,
+				  "status: { %s%s%s%s}\n",
+				  res->command & ATA_DRDY ? "DRDY " : "",
+				  res->command & ATA_DF ? "DF " : "",
+				  res->command & ATA_DRQ ? "DRQ " : "",
+				  res->command & ATA_ERR ? "ERR " : "" );
+		}
+
+		if (cmd->command != ATA_CMD_PACKET &&
+		    (res->feature & (ATA_ICRC | ATA_UNC | ATA_IDNF |
+				     ATA_ABORTED)))
+			ata_dev_printk(qc->dev, KERN_ERR,
+			  "error: { %s%s%s%s}\n",
+			  res->feature & ATA_ICRC ? "ICRC " : "",
+			  res->feature & ATA_UNC ? "UNC " : "",
+			  res->feature & ATA_IDNF ? "IDNF " : "",
+			  res->feature & ATA_ABORTED ? "ABRT " : "" );
 	}
 }
 
-static int ata_do_reset(struct ata_port *ap, ata_reset_fn_t reset,
+/**
+ *	ata_eh_report - report error handling to user
+ *	@ap: ATA port to report EH about
+ *
+ *	Report EH to user.
+ *
+ *	LOCKING:
+ *	None.
+ */
+void ata_eh_report(struct ata_port *ap)
+{
+	struct ata_link *link;
+
+	__ata_port_for_each_link(link, ap)
+		ata_eh_link_report(link);
+}
+
+static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
 			unsigned int *classes, unsigned long deadline)
 {
-	int i, rc;
+	struct ata_device *dev;
+	int rc;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		classes[i] = ATA_DEV_UNKNOWN;
+	ata_link_for_each_dev(dev, link)
+		classes[dev->devno] = ATA_DEV_UNKNOWN;
 
-	rc = reset(ap, classes, deadline);
+	rc = reset(link, classes, deadline);
 	if (rc)
 		return rc;
 
@@ -1582,73 +2028,89 @@
 	 * is complete and convert all ATA_DEV_UNKNOWN to
 	 * ATA_DEV_NONE.
 	 */
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		if (classes[i] != ATA_DEV_UNKNOWN)
+	ata_link_for_each_dev(dev, link)
+		if (classes[dev->devno] != ATA_DEV_UNKNOWN)
 			break;
 
-	if (i < ATA_MAX_DEVICES)
-		for (i = 0; i < ATA_MAX_DEVICES; i++)
-			if (classes[i] == ATA_DEV_UNKNOWN)
-				classes[i] = ATA_DEV_NONE;
+	if (dev) {
+		ata_link_for_each_dev(dev, link) {
+			if (classes[dev->devno] == ATA_DEV_UNKNOWN)
+				classes[dev->devno] = ATA_DEV_NONE;
+		}
+	}
 
 	return 0;
 }
 
-static int ata_eh_followup_srst_needed(int rc, int classify,
+static int ata_eh_followup_srst_needed(struct ata_link *link,
+				       int rc, int classify,
 				       const unsigned int *classes)
 {
+	if (link->flags & ATA_LFLAG_NO_SRST)
+		return 0;
 	if (rc == -EAGAIN)
 		return 1;
 	if (rc != 0)
 		return 0;
-	if (classify && classes[0] == ATA_DEV_UNKNOWN)
+	if ((link->ap->flags & ATA_FLAG_PMP) && ata_is_host_link(link))
+		return 1;
+	if (classify && !(link->flags & ATA_LFLAG_ASSUME_CLASS) &&
+	    classes[0] == ATA_DEV_UNKNOWN)
 		return 1;
 	return 0;
 }
 
-static int ata_eh_reset(struct ata_port *ap, int classify,
-			ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
-			ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+int ata_eh_reset(struct ata_link *link, int classify,
+		 ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+		 ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_port *ap = link->ap;
+	struct ata_eh_context *ehc = &link->eh_context;
 	unsigned int *classes = ehc->classes;
 	int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
 	int try = 0;
+	struct ata_device *dev;
 	unsigned long deadline;
 	unsigned int action;
 	ata_reset_fn_t reset;
-	int i, rc;
+	unsigned long flags;
+	int rc;
 
 	/* about to reset */
-	ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
+	spin_lock_irqsave(ap->lock, flags);
+	ap->pflags |= ATA_PFLAG_RESETTING;
+	spin_unlock_irqrestore(ap->lock, flags);
+
+	ata_eh_about_to_do(link, NULL, ehc->i.action & ATA_EH_RESET_MASK);
 
 	/* Determine which reset to use and record in ehc->i.action.
 	 * prereset() may examine and modify it.
 	 */
 	action = ehc->i.action;
 	ehc->i.action &= ~ATA_EH_RESET_MASK;
-	if (softreset && (!hardreset || (!sata_set_spd_needed(ap) &&
+	if (softreset && (!hardreset || (!(link->flags & ATA_LFLAG_NO_SRST) &&
+					 !sata_set_spd_needed(link) &&
 					 !(action & ATA_EH_HARDRESET))))
 		ehc->i.action |= ATA_EH_SOFTRESET;
 	else
 		ehc->i.action |= ATA_EH_HARDRESET;
 
 	if (prereset) {
-		rc = prereset(ap, jiffies + ATA_EH_PRERESET_TIMEOUT);
+		rc = prereset(link, jiffies + ATA_EH_PRERESET_TIMEOUT);
 		if (rc) {
 			if (rc == -ENOENT) {
-				ata_port_printk(ap, KERN_DEBUG,
+				ata_link_printk(link, KERN_DEBUG,
 						"port disabled. ignoring.\n");
-				ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
+				ehc->i.action &= ~ATA_EH_RESET_MASK;
 
-				for (i = 0; i < ATA_MAX_DEVICES; i++)
-					classes[i] = ATA_DEV_NONE;
+				ata_link_for_each_dev(dev, link)
+					classes[dev->devno] = ATA_DEV_NONE;
 
 				rc = 0;
 			} else
-				ata_port_printk(ap, KERN_ERR,
+				ata_link_printk(link, KERN_ERR,
 					"prereset failed (errno=%d)\n", rc);
-			return rc;
+			goto out;
 		}
 	}
 
@@ -1659,9 +2121,10 @@
 		reset = softreset;
 	else {
 		/* prereset told us not to reset, bang classes and return */
-		for (i = 0; i < ATA_MAX_DEVICES; i++)
-			classes[i] = ATA_DEV_NONE;
-		return 0;
+		ata_link_for_each_dev(dev, link)
+			classes[dev->devno] = ATA_DEV_NONE;
+		rc = 0;
+		goto out;
 	}
 
 	/* did prereset() screw up?  if so, fix up to avoid oopsing */
@@ -1677,7 +2140,7 @@
 
 	/* shut up during boot probing */
 	if (verbose)
-		ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
+		ata_link_printk(link, KERN_INFO, "%s resetting link\n",
 				reset == softreset ? "soft" : "hard");
 
 	/* mark that this EH session started with reset */
@@ -1686,78 +2149,112 @@
 	else
 		ehc->i.flags |= ATA_EHI_DID_SOFTRESET;
 
-	rc = ata_do_reset(ap, reset, classes, deadline);
+	rc = ata_do_reset(link, reset, classes, deadline);
 
 	if (reset == hardreset &&
-	    ata_eh_followup_srst_needed(rc, classify, classes)) {
+	    ata_eh_followup_srst_needed(link, rc, classify, classes)) {
 		/* okay, let's do follow-up softreset */
 		reset = softreset;
 
 		if (!reset) {
-			ata_port_printk(ap, KERN_ERR,
+			ata_link_printk(link, KERN_ERR,
 					"follow-up softreset required "
 					"but no softreset avaliable\n");
-			return -EINVAL;
+			rc = -EINVAL;
+			goto out;
 		}
 
-		ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
-		rc = ata_do_reset(ap, reset, classes, deadline);
+		ata_eh_about_to_do(link, NULL, ATA_EH_RESET_MASK);
+		rc = ata_do_reset(link, reset, classes, deadline);
 
-		if (rc == 0 && classify &&
-		    classes[0] == ATA_DEV_UNKNOWN) {
-			ata_port_printk(ap, KERN_ERR,
+		if (rc == 0 && classify && classes[0] == ATA_DEV_UNKNOWN &&
+		    !(link->flags & ATA_LFLAG_ASSUME_CLASS)) {
+			ata_link_printk(link, KERN_ERR,
 					"classification failed\n");
-			return -EINVAL;
+			rc = -EINVAL;
+			goto out;
 		}
 	}
 
-	if (rc && try < ARRAY_SIZE(ata_eh_reset_timeouts)) {
+	/* if we skipped follow-up srst, clear rc */
+	if (rc == -EAGAIN)
+		rc = 0;
+
+	if (rc && rc != -ERESTART && try < ARRAY_SIZE(ata_eh_reset_timeouts)) {
 		unsigned long now = jiffies;
 
 		if (time_before(now, deadline)) {
 			unsigned long delta = deadline - jiffies;
 
-			ata_port_printk(ap, KERN_WARNING, "reset failed "
+			ata_link_printk(link, KERN_WARNING, "reset failed "
 				"(errno=%d), retrying in %u secs\n",
 				rc, (jiffies_to_msecs(delta) + 999) / 1000);
 
-			schedule_timeout_uninterruptible(delta);
+			while (delta)
+				delta = schedule_timeout_uninterruptible(delta);
 		}
 
-		if (reset == hardreset &&
+		if (rc == -EPIPE ||
 		    try == ARRAY_SIZE(ata_eh_reset_timeouts) - 1)
-			sata_down_spd_limit(ap);
+			sata_down_spd_limit(link);
 		if (hardreset)
 			reset = hardreset;
 		goto retry;
 	}
 
 	if (rc == 0) {
-		/* After the reset, the device state is PIO 0 and the
-		 * controller state is undefined.  Record the mode.
-		 */
-		for (i = 0; i < ATA_MAX_DEVICES; i++)
-			ap->device[i].pio_mode = XFER_PIO_0;
+		u32 sstatus;
+
+		ata_link_for_each_dev(dev, link) {
+			/* After the reset, the device state is PIO 0
+			 * and the controller state is undefined.
+			 * Record the mode.
+			 */
+			dev->pio_mode = XFER_PIO_0;
+
+			if (ata_link_offline(link))
+				continue;
+
+			/* apply class override and convert UNKNOWN to NONE */
+			if (link->flags & ATA_LFLAG_ASSUME_ATA)
+				classes[dev->devno] = ATA_DEV_ATA;
+			else if (link->flags & ATA_LFLAG_ASSUME_SEMB)
+				classes[dev->devno] = ATA_DEV_SEMB_UNSUP; /* not yet */
+			else if (classes[dev->devno] == ATA_DEV_UNKNOWN)
+				classes[dev->devno] = ATA_DEV_NONE;
+		}
+
+		/* record current link speed */
+		if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0)
+			link->sata_spd = (sstatus >> 4) & 0xf;
 
 		if (postreset)
-			postreset(ap, classes);
+			postreset(link, classes);
 
 		/* reset successful, schedule revalidation */
-		ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
+		ata_eh_done(link, NULL, ehc->i.action & ATA_EH_RESET_MASK);
 		ehc->i.action |= ATA_EH_REVALIDATE;
 	}
+ out:
+	/* clear hotplug flag */
+	ehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
+
+	spin_lock_irqsave(ap->lock, flags);
+	ap->pflags &= ~ATA_PFLAG_RESETTING;
+	spin_unlock_irqrestore(ap->lock, flags);
 
 	return rc;
 }
 
-static int ata_eh_revalidate_and_attach(struct ata_port *ap,
+static int ata_eh_revalidate_and_attach(struct ata_link *link,
 					struct ata_device **r_failed_dev)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_port *ap = link->ap;
+	struct ata_eh_context *ehc = &link->eh_context;
 	struct ata_device *dev;
 	unsigned int new_mask = 0;
 	unsigned long flags;
-	int i, rc = 0;
+	int rc = 0;
 
 	DPRINTK("ENTER\n");
 
@@ -1765,27 +2262,28 @@
 	 * be done backwards such that PDIAG- is released by the slave
 	 * device before the master device is identified.
 	 */
-	for (i = ATA_MAX_DEVICES - 1; i >= 0; i--) {
-		unsigned int action, readid_flags = 0;
-
-		dev = &ap->device[i];
-		action = ata_eh_dev_action(dev);
+	ata_link_for_each_dev_reverse(dev, link) {
+		unsigned int action = ata_eh_dev_action(dev);
+		unsigned int readid_flags = 0;
 
 		if (ehc->i.flags & ATA_EHI_DID_RESET)
 			readid_flags |= ATA_READID_POSTRESET;
 
 		if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) {
-			if (ata_port_offline(ap)) {
+			WARN_ON(dev->class == ATA_DEV_PMP);
+
+			if (ata_link_offline(link)) {
 				rc = -EIO;
 				goto err;
 			}
 
-			ata_eh_about_to_do(ap, dev, ATA_EH_REVALIDATE);
-			rc = ata_dev_revalidate(dev, readid_flags);
+			ata_eh_about_to_do(link, dev, ATA_EH_REVALIDATE);
+			rc = ata_dev_revalidate(dev, ehc->classes[dev->devno],
+						readid_flags);
 			if (rc)
 				goto err;
 
-			ata_eh_done(ap, dev, ATA_EH_REVALIDATE);
+			ata_eh_done(link, dev, ATA_EH_REVALIDATE);
 
 			/* Configuration may have changed, reconfigure
 			 * transfer mode.
@@ -1799,11 +2297,14 @@
 			   ata_class_enabled(ehc->classes[dev->devno])) {
 			dev->class = ehc->classes[dev->devno];
 
-			rc = ata_dev_read_id(dev, &dev->class, readid_flags,
-					     dev->id);
+			if (dev->class == ATA_DEV_PMP)
+				rc = sata_pmp_attach(dev);
+			else
+				rc = ata_dev_read_id(dev, &dev->class,
+						     readid_flags, dev->id);
 			switch (rc) {
 			case 0:
-				new_mask |= 1 << i;
+				new_mask |= 1 << dev->devno;
 				break;
 			case -ENOENT:
 				/* IDENTIFY was issued to non-existent
@@ -1821,16 +2322,16 @@
 	}
 
 	/* PDIAG- should have been released, ask cable type if post-reset */
-	if ((ehc->i.flags & ATA_EHI_DID_RESET) && ap->ops->cable_detect)
+	if (ata_is_host_link(link) && ap->ops->cable_detect &&
+	    (ehc->i.flags & ATA_EHI_DID_RESET))
 		ap->cbl = ap->ops->cable_detect(ap);
 
 	/* Configure new devices forward such that user doesn't see
 	 * device detection messages backwards.
 	 */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->device[i];
-
-		if (!(new_mask & (1 << i)))
+	ata_link_for_each_dev(dev, link) {
+		if (!(new_mask & (1 << dev->devno)) ||
+		    dev->class == ATA_DEV_PMP)
 			continue;
 
 		ehc->i.flags |= ATA_EHI_PRINTINFO;
@@ -1855,40 +2356,44 @@
 	return rc;
 }
 
-static int ata_port_nr_enabled(struct ata_port *ap)
+static int ata_link_nr_enabled(struct ata_link *link)
 {
-	int i, cnt = 0;
+	struct ata_device *dev;
+	int cnt = 0;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		if (ata_dev_enabled(&ap->device[i]))
+	ata_link_for_each_dev(dev, link)
+		if (ata_dev_enabled(dev))
 			cnt++;
 	return cnt;
 }
 
-static int ata_port_nr_vacant(struct ata_port *ap)
+static int ata_link_nr_vacant(struct ata_link *link)
 {
-	int i, cnt = 0;
+	struct ata_device *dev;
+	int cnt = 0;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		if (ap->device[i].class == ATA_DEV_UNKNOWN)
+	ata_link_for_each_dev(dev, link)
+		if (dev->class == ATA_DEV_UNKNOWN)
 			cnt++;
 	return cnt;
 }
 
-static int ata_eh_skip_recovery(struct ata_port *ap)
+static int ata_eh_skip_recovery(struct ata_link *link)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
-	int i;
+	struct ata_eh_context *ehc = &link->eh_context;
+	struct ata_device *dev;
+
+	/* skip disabled links */
+	if (link->flags & ATA_LFLAG_DISABLED)
+		return 1;
 
 	/* thaw frozen port, resume link and recover failed devices */
-	if ((ap->pflags & ATA_PFLAG_FROZEN) ||
-	    (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap))
+	if ((link->ap->pflags & ATA_PFLAG_FROZEN) ||
+	    (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_link_nr_enabled(link))
 		return 0;
 
 	/* skip if class codes for all vacant slots are ATA_DEV_NONE */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
-
+	ata_link_for_each_dev(dev, link) {
 		if (dev->class == ATA_DEV_UNKNOWN &&
 		    ehc->classes[dev->devno] != ATA_DEV_NONE)
 			return 0;
@@ -1897,10 +2402,9 @@
 	return 1;
 }
 
-static void ata_eh_handle_dev_fail(struct ata_device *dev, int err)
+static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
 {
-	struct ata_port *ap = dev->ap;
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_eh_context *ehc = &dev->link->eh_context;
 
 	ehc->tries[dev->devno]--;
 
@@ -1916,7 +2420,7 @@
 			/* This is the last chance, better to slow
 			 * down than lose it.
 			 */
-			sata_down_spd_limit(ap);
+			sata_down_spd_limit(dev->link);
 			ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
 		}
 	}
@@ -1926,7 +2430,7 @@
 		ata_dev_disable(dev);
 
 		/* detach if offline */
-		if (ata_port_offline(ap))
+		if (ata_link_offline(dev->link))
 			ata_eh_detach_dev(dev);
 
 		/* probe if requested */
@@ -1939,12 +2443,16 @@
 			ehc->did_probe_mask |= (1 << dev->devno);
 			ehc->i.action |= ATA_EH_SOFTRESET;
 		}
+
+		return 1;
 	} else {
 		/* soft didn't work?  be haaaaard */
 		if (ehc->i.flags & ATA_EHI_DID_RESET)
 			ehc->i.action |= ATA_EH_HARDRESET;
 		else
 			ehc->i.action |= ATA_EH_SOFTRESET;
+
+		return 0;
 	}
 }
 
@@ -1955,12 +2463,13 @@
  *	@softreset: softreset method (can be NULL)
  *	@hardreset: hardreset method (can be NULL)
  *	@postreset: postreset method (can be NULL)
+ *	@r_failed_link: out parameter for failed link
  *
  *	This is the alpha and omega, eum and yang, heart and soul of
  *	libata exception handling.  On entry, actions required to
- *	recover the port and hotplug requests are recorded in
- *	eh_context.  This function executes all the operations with
- *	appropriate retrials and fallbacks to resurrect failed
+ *	recover each link and hotplug requests are recorded in the
+ *	link's eh_context.  This function executes all the operations
+ *	with appropriate retrials and fallbacks to resurrect failed
  *	devices, detach goners and greet newcomers.
  *
  *	LOCKING:
@@ -1969,103 +2478,170 @@
  *	RETURNS:
  *	0 on success, -errno on failure.
  */
-static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
-			  ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
-			  ata_postreset_fn_t postreset)
+int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+		   ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+		   ata_postreset_fn_t postreset,
+		   struct ata_link **r_failed_link)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_link *link;
 	struct ata_device *dev;
-	int i, rc;
+	int nr_failed_devs, nr_disabled_devs;
+	int reset, rc;
+	unsigned long flags;
 
 	DPRINTK("ENTER\n");
 
 	/* prep for recovery */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		dev = &ap->device[i];
+	ata_port_for_each_link(link, ap) {
+		struct ata_eh_context *ehc = &link->eh_context;
 
-		ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
+		/* re-enable link? */
+		if (ehc->i.action & ATA_EH_ENABLE_LINK) {
+			ata_eh_about_to_do(link, NULL, ATA_EH_ENABLE_LINK);
+			spin_lock_irqsave(ap->lock, flags);
+			link->flags &= ~ATA_LFLAG_DISABLED;
+			spin_unlock_irqrestore(ap->lock, flags);
+			ata_eh_done(link, NULL, ATA_EH_ENABLE_LINK);
+		}
 
-		/* collect port action mask recorded in dev actions */
-		ehc->i.action |= ehc->i.dev_action[i] & ~ATA_EH_PERDEV_MASK;
-		ehc->i.dev_action[i] &= ATA_EH_PERDEV_MASK;
+		ata_link_for_each_dev(dev, link) {
+			if (link->flags & ATA_LFLAG_NO_RETRY)
+				ehc->tries[dev->devno] = 1;
+			else
+				ehc->tries[dev->devno] = ATA_EH_DEV_TRIES;
 
-		/* process hotplug request */
-		if (dev->flags & ATA_DFLAG_DETACH)
-			ata_eh_detach_dev(dev);
+			/* collect port action mask recorded in dev actions */
+			ehc->i.action |= ehc->i.dev_action[dev->devno] &
+					 ~ATA_EH_PERDEV_MASK;
+			ehc->i.dev_action[dev->devno] &= ATA_EH_PERDEV_MASK;
 
-		if (!ata_dev_enabled(dev) &&
-		    ((ehc->i.probe_mask & (1 << dev->devno)) &&
-		     !(ehc->did_probe_mask & (1 << dev->devno)))) {
-			ata_eh_detach_dev(dev);
-			ata_dev_init(dev);
-			ehc->did_probe_mask |= (1 << dev->devno);
-			ehc->i.action |= ATA_EH_SOFTRESET;
+			/* process hotplug request */
+			if (dev->flags & ATA_DFLAG_DETACH)
+				ata_eh_detach_dev(dev);
+
+			if (!ata_dev_enabled(dev) &&
+			    ((ehc->i.probe_mask & (1 << dev->devno)) &&
+			     !(ehc->did_probe_mask & (1 << dev->devno)))) {
+				ata_eh_detach_dev(dev);
+				ata_dev_init(dev);
+				ehc->did_probe_mask |= (1 << dev->devno);
+				ehc->i.action |= ATA_EH_SOFTRESET;
+			}
 		}
 	}
 
  retry:
 	rc = 0;
+	nr_failed_devs = 0;
+	nr_disabled_devs = 0;
+	reset = 0;
 
 	/* if UNLOADING, finish immediately */
 	if (ap->pflags & ATA_PFLAG_UNLOADING)
 		goto out;
 
-	/* skip EH if possible. */
-	if (ata_eh_skip_recovery(ap))
-		ehc->i.action = 0;
+	/* prep for EH */
+	ata_port_for_each_link(link, ap) {
+		struct ata_eh_context *ehc = &link->eh_context;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++)
-		ehc->classes[i] = ATA_DEV_UNKNOWN;
+		/* skip EH if possible. */
+		if (ata_eh_skip_recovery(link))
+			ehc->i.action = 0;
+
+		/* do we need to reset? */
+		if (ehc->i.action & ATA_EH_RESET_MASK)
+			reset = 1;
+
+		ata_link_for_each_dev(dev, link)
+			ehc->classes[dev->devno] = ATA_DEV_UNKNOWN;
+	}
 
 	/* reset */
-	if (ehc->i.action & ATA_EH_RESET_MASK) {
-		ata_eh_freeze_port(ap);
+	if (reset) {
+		/* if PMP is attached, this function only deals with
+		 * downstream links, port should stay thawed.
+		 */
+		if (!ap->nr_pmp_links)
+			ata_eh_freeze_port(ap);
 
-		rc = ata_eh_reset(ap, ata_port_nr_vacant(ap), prereset,
-				  softreset, hardreset, postreset);
-		if (rc) {
-			ata_port_printk(ap, KERN_ERR,
-					"reset failed, giving up\n");
-			goto out;
+		ata_port_for_each_link(link, ap) {
+			struct ata_eh_context *ehc = &link->eh_context;
+
+			if (!(ehc->i.action & ATA_EH_RESET_MASK))
+				continue;
+
+			rc = ata_eh_reset(link, ata_link_nr_vacant(link),
+					  prereset, softreset, hardreset,
+					  postreset);
+			if (rc) {
+				ata_link_printk(link, KERN_ERR,
+						"reset failed, giving up\n");
+				goto out;
+			}
 		}
 
-		ata_eh_thaw_port(ap);
+		if (!ap->nr_pmp_links)
+			ata_eh_thaw_port(ap);
 	}
 
-	/* revalidate existing devices and attach new ones */
-	rc = ata_eh_revalidate_and_attach(ap, &dev);
-	if (rc)
-		goto dev_fail;
+	/* the rest */
+	ata_port_for_each_link(link, ap) {
+		struct ata_eh_context *ehc = &link->eh_context;
 
-	/* configure transfer mode if necessary */
-	if (ehc->i.flags & ATA_EHI_SETMODE) {
-		rc = ata_set_mode(ap, &dev);
+		/* revalidate existing devices and attach new ones */
+		rc = ata_eh_revalidate_and_attach(link, &dev);
 		if (rc)
 			goto dev_fail;
-		ehc->i.flags &= ~ATA_EHI_SETMODE;
+
+		/* if PMP got attached, return, pmp EH will take care of it */
+		if (link->device->class == ATA_DEV_PMP) {
+			ehc->i.action = 0;
+			return 0;
+		}
+
+		/* configure transfer mode if necessary */
+		if (ehc->i.flags & ATA_EHI_SETMODE) {
+			rc = ata_set_mode(link, &dev);
+			if (rc)
+				goto dev_fail;
+			ehc->i.flags &= ~ATA_EHI_SETMODE;
+		}
+
+		/* this link is okay now */
+		ehc->i.flags = 0;
+		continue;
+
+	dev_fail:
+		nr_failed_devs++;
+		if (ata_eh_handle_dev_fail(dev, rc))
+			nr_disabled_devs++;
+
+		if (ap->pflags & ATA_PFLAG_FROZEN) {
+			/* PMP reset requires working host port.
+			 * Can't retry if it's frozen.
+			 */
+			if (ap->nr_pmp_links)
+				goto out;
+			break;
+		}
 	}
 
-	goto out;
+	if (nr_failed_devs) {
+		if (nr_failed_devs != nr_disabled_devs) {
+			ata_port_printk(ap, KERN_WARNING, "failed to recover "
+					"some devices, retrying in 5 secs\n");
+			ssleep(5);
+		} else {
+			/* no device left to recover, repeat fast */
+			msleep(500);
+		}
 
- dev_fail:
-	ata_eh_handle_dev_fail(dev, rc);
-
-	if (ata_port_nr_enabled(ap)) {
-		ata_port_printk(ap, KERN_WARNING, "failed to recover some "
-				"devices, retrying in 5 secs\n");
-		ssleep(5);
-	} else {
-		/* no device left, repeat fast */
-		msleep(500);
+		goto retry;
 	}
 
-	goto retry;
-
  out:
-	if (rc) {
-		for (i = 0; i < ATA_MAX_DEVICES; i++)
-			ata_dev_disable(&ap->device[i]);
-	}
+	if (rc && r_failed_link)
+		*r_failed_link = link;
 
 	DPRINTK("EXIT, rc=%d\n", rc);
 	return rc;
@@ -2081,7 +2657,7 @@
  *	LOCKING:
  *	None.
  */
-static void ata_eh_finish(struct ata_port *ap)
+void ata_eh_finish(struct ata_port *ap)
 {
 	int tag;
 
@@ -2111,6 +2687,10 @@
 			}
 		}
 	}
+
+	/* make sure nr_active_links is zero after EH */
+	WARN_ON(ap->nr_active_links);
+	ap->nr_active_links = 0;
 }
 
 /**
@@ -2130,9 +2710,19 @@
 	       ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
 	       ata_postreset_fn_t postreset)
 {
+	struct ata_device *dev;
+	int rc;
+
 	ata_eh_autopsy(ap);
 	ata_eh_report(ap);
-	ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
+
+	rc = ata_eh_recover(ap, prereset, softreset, hardreset, postreset,
+			    NULL);
+	if (rc) {
+		ata_link_for_each_dev(dev, &ap->link)
+			ata_dev_disable(dev);
+	}
+
 	ata_eh_finish(ap);
 }
 
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
new file mode 100644
index 0000000..c0c4dbc
--- /dev/null
+++ b/drivers/ata/libata-pmp.c
@@ -0,0 +1,1191 @@
+/*
+ * libata-pmp.c - libata port multiplier support
+ *
+ * Copyright (c) 2007  SUSE Linux Products GmbH
+ * Copyright (c) 2007  Tejun Heo <teheo@suse.de>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/libata.h>
+#include "libata.h"
+
+/**
+ *	sata_pmp_read - read PMP register
+ *	@link: link to read PMP register for
+ *	@reg: register to read
+ *	@r_val: resulting value
+ *
+ *	Read PMP register.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, AC_ERR_* mask on failure.
+ */
+static unsigned int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val)
+{
+	struct ata_port *ap = link->ap;
+	struct ata_device *pmp_dev = ap->link.device;
+	struct ata_taskfile tf;
+	unsigned int err_mask;
+
+	ata_tf_init(pmp_dev, &tf);
+	tf.command = ATA_CMD_PMP_READ;
+	tf.protocol = ATA_PROT_NODATA;
+	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	tf.feature = reg;
+	tf.device = link->pmp;
+
+	err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
+				     SATA_PMP_SCR_TIMEOUT);
+	if (err_mask)
+		return err_mask;
+
+	*r_val = tf.nsect | tf.lbal << 8 | tf.lbam << 16 | tf.lbah << 24;
+	return 0;
+}
+
+/**
+ *	sata_pmp_write - write PMP register
+ *	@link: link to write PMP register for
+ *	@reg: register to write
+ *	@r_val: value to write
+ *
+ *	Write PMP register.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, AC_ERR_* mask on failure.
+ */
+static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val)
+{
+	struct ata_port *ap = link->ap;
+	struct ata_device *pmp_dev = ap->link.device;
+	struct ata_taskfile tf;
+
+	ata_tf_init(pmp_dev, &tf);
+	tf.command = ATA_CMD_PMP_WRITE;
+	tf.protocol = ATA_PROT_NODATA;
+	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	tf.feature = reg;
+	tf.device = link->pmp;
+	tf.nsect = val & 0xff;
+	tf.lbal = (val >> 8) & 0xff;
+	tf.lbam = (val >> 16) & 0xff;
+	tf.lbah = (val >> 24) & 0xff;
+
+	return ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
+				 SATA_PMP_SCR_TIMEOUT);
+}
+
+/**
+ *	sata_pmp_qc_defer_cmd_switch - qc_defer for command switching PMP
+ *	@qc: ATA command in question
+ *
+ *	A host which has command switching PMP support cannot issue
+ *	commands to multiple links simultaneously.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ *
+ *	RETURNS:
+ *	ATA_DEFER_* if deferring is needed, 0 otherwise.
+ */
+int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc)
+{
+	struct ata_link *link = qc->dev->link;
+	struct ata_port *ap = link->ap;
+
+	if (ap->excl_link == NULL || ap->excl_link == link) {
+		if (ap->nr_active_links == 0 || ata_link_active(link)) {
+			qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+			return ata_std_qc_defer(qc);
+		}
+
+		ap->excl_link = link;
+	}
+
+	return ATA_DEFER_PORT;
+}
+
+/**
+ *	sata_pmp_scr_read - read PSCR
+ *	@link: ATA link to read PSCR for
+ *	@reg: PSCR to read
+ *	@r_val: resulting value
+ *
+ *	Read PSCR @reg into @r_val for @link, to be called from
+ *	ata_scr_read().
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *r_val)
+{
+	unsigned int err_mask;
+
+	if (reg > SATA_PMP_PSCR_CONTROL)
+		return -EINVAL;
+
+	err_mask = sata_pmp_read(link, reg, r_val);
+	if (err_mask) {
+		ata_link_printk(link, KERN_WARNING, "failed to read SCR %d "
+				"(Emask=0x%x)\n", reg, err_mask);
+		return -EIO;
+	}
+	return 0;
+}
+
+/**
+ *	sata_pmp_scr_write - write PSCR
+ *	@link: ATA link to write PSCR for
+ *	@reg: PSCR to write
+ *	@val: value to be written
+ *
+ *	Write @val to PSCR @reg for @link, to be called from
+ *	ata_scr_write() and ata_scr_write_flush().
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
+{
+	unsigned int err_mask;
+
+	if (reg > SATA_PMP_PSCR_CONTROL)
+		return -EINVAL;
+
+	err_mask = sata_pmp_write(link, reg, val);
+	if (err_mask) {
+		ata_link_printk(link, KERN_WARNING, "failed to write SCR %d "
+				"(Emask=0x%x)\n", reg, err_mask);
+		return -EIO;
+	}
+	return 0;
+}
+
+/**
+ *	sata_pmp_std_prereset - prepare PMP link for reset
+ *	@link: link to be reset
+ *	@deadline: deadline jiffies for the operation
+ *
+ *	@link is about to be reset.  Initialize it.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+int sata_pmp_std_prereset(struct ata_link *link, unsigned long deadline)
+{
+	struct ata_eh_context *ehc = &link->eh_context;
+	const unsigned long *timing = sata_ehc_deb_timing(ehc);
+	int rc;
+
+	/* force HRST? */
+	if (link->flags & ATA_LFLAG_NO_SRST)
+		ehc->i.action |= ATA_EH_HARDRESET;
+
+	/* handle link resume */
+	if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
+	    (link->flags & ATA_LFLAG_HRST_TO_RESUME))
+		ehc->i.action |= ATA_EH_HARDRESET;
+
+	/* if we're about to do hardreset, nothing more to do */
+	if (ehc->i.action & ATA_EH_HARDRESET)
+		return 0;
+
+	/* resume link */
+	rc = sata_link_resume(link, timing, deadline);
+	if (rc) {
+		/* phy resume failed */
+		ata_link_printk(link, KERN_WARNING, "failed to resume link "
+				"for reset (errno=%d)\n", rc);
+		return rc;
+	}
+
+	/* clear SError bits including .X which blocks the port when set */
+	rc = sata_scr_write(link, SCR_ERROR, 0xffffffff);
+	if (rc) {
+		ata_link_printk(link, KERN_ERR,
+				"failed to clear SError (errno=%d)\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ *	sata_pmp_std_hardreset - standard hardreset method for PMP link
+ *	@link: link to be reset
+ *	@class: resulting class of attached device
+ *	@deadline: deadline jiffies for the operation
+ *
+ *	Hardreset PMP port @link.  Note that this function doesn't
+ *	wait for BSY clearance.  There simply isn't a generic way to
+ *	wait the event.  Instead, this function return -EAGAIN thus
+ *	telling libata-EH to followup with softreset.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+int sata_pmp_std_hardreset(struct ata_link *link, unsigned int *class,
+			   unsigned long deadline)
+{
+	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+	u32 tmp;
+	int rc;
+
+	DPRINTK("ENTER\n");
+
+	/* do hardreset */
+	rc = sata_link_hardreset(link, timing, deadline);
+	if (rc) {
+		ata_link_printk(link, KERN_ERR,
+				"COMRESET failed (errno=%d)\n", rc);
+		goto out;
+	}
+
+	/* clear SError bits including .X which blocks the port when set */
+	rc = sata_scr_write(link, SCR_ERROR, 0xffffffff);
+	if (rc) {
+		ata_link_printk(link, KERN_ERR, "failed to clear SError "
+				"during hardreset (errno=%d)\n", rc);
+		goto out;
+	}
+
+	/* if device is present, follow up with srst to wait for !BSY */
+	if (ata_link_online(link))
+		rc = -EAGAIN;
+ out:
+	/* if SCR isn't accessible, we need to reset the PMP */
+	if (rc && rc != -EAGAIN && sata_scr_read(link, SCR_STATUS, &tmp))
+		rc = -ERESTART;
+
+	DPRINTK("EXIT, rc=%d\n", rc);
+	return rc;
+}
+
+/**
+ *	ata_std_postreset - standard postreset method for PMP link
+ *	@link: the target ata_link
+ *	@classes: classes of attached devices
+ *
+ *	This function is invoked after a successful reset.  Note that
+ *	the device might have been reset more than once using
+ *	different reset methods before postreset is invoked.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ */
+void sata_pmp_std_postreset(struct ata_link *link, unsigned int *class)
+{
+	u32 serror;
+
+	DPRINTK("ENTER\n");
+
+	/* clear SError */
+	if (sata_scr_read(link, SCR_ERROR, &serror) == 0)
+		sata_scr_write(link, SCR_ERROR, serror);
+
+	/* print link status */
+	sata_print_link_status(link);
+
+	DPRINTK("EXIT\n");
+}
+
+/**
+ *	sata_pmp_read_gscr - read GSCR block of SATA PMP
+ *	@dev: PMP device
+ *	@gscr: buffer to read GSCR block into
+ *
+ *	Read selected PMP GSCRs from the PMP at @dev.  This will serve
+ *	as configuration and identification info for the PMP.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+static int sata_pmp_read_gscr(struct ata_device *dev, u32 *gscr)
+{
+	static const int gscr_to_read[] = { 0, 1, 2, 32, 33, 64, 96 };
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(gscr_to_read); i++) {
+		int reg = gscr_to_read[i];
+		unsigned int err_mask;
+
+		err_mask = sata_pmp_read(dev->link, reg, &gscr[reg]);
+		if (err_mask) {
+			ata_dev_printk(dev, KERN_ERR, "failed to read PMP "
+				"GSCR[%d] (Emask=0x%x)\n", reg, err_mask);
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static const char *sata_pmp_spec_rev_str(const u32 *gscr)
+{
+	u32 rev = gscr[SATA_PMP_GSCR_REV];
+
+	if (rev & (1 << 2))
+		return "1.1";
+	if (rev & (1 << 1))
+		return "1.0";
+	return "<unknown>";
+}
+
+static int sata_pmp_configure(struct ata_device *dev, int print_info)
+{
+	struct ata_port *ap = dev->link->ap;
+	u32 *gscr = dev->gscr;
+	unsigned int err_mask = 0;
+	const char *reason;
+	int nr_ports, rc;
+
+	nr_ports = sata_pmp_gscr_ports(gscr);
+
+	if (nr_ports <= 0 || nr_ports > SATA_PMP_MAX_PORTS) {
+		rc = -EINVAL;
+		reason = "invalid nr_ports";
+		goto fail;
+	}
+
+	if ((ap->flags & ATA_FLAG_AN) &&
+	    (gscr[SATA_PMP_GSCR_FEAT] & SATA_PMP_FEAT_NOTIFY))
+		dev->flags |= ATA_DFLAG_AN;
+
+	/* monitor SERR_PHYRDY_CHG on fan-out ports */
+	err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_ERROR_EN,
+				  SERR_PHYRDY_CHG);
+	if (err_mask) {
+		rc = -EIO;
+		reason = "failed to write GSCR_ERROR_EN";
+		goto fail;
+	}
+
+	/* turn off notification till fan-out ports are reset and configured */
+	if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) {
+		gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY;
+
+		err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_FEAT_EN,
+					  gscr[SATA_PMP_GSCR_FEAT_EN]);
+		if (err_mask) {
+			rc = -EIO;
+			reason = "failed to write GSCR_FEAT_EN";
+			goto fail;
+		}
+	}
+
+	if (print_info) {
+		ata_dev_printk(dev, KERN_INFO, "Port Multiplier %s, "
+			       "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x\n",
+			       sata_pmp_spec_rev_str(gscr),
+			       sata_pmp_gscr_vendor(gscr),
+			       sata_pmp_gscr_devid(gscr),
+			       sata_pmp_gscr_rev(gscr),
+			       nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN],
+			       gscr[SATA_PMP_GSCR_FEAT]);
+
+		if (!(dev->flags & ATA_DFLAG_AN))
+			ata_dev_printk(dev, KERN_INFO,
+				"Asynchronous notification not supported, "
+				"hotplug won't\n         work on fan-out "
+				"ports. Use warm-plug instead.\n");
+	}
+
+	return 0;
+
+ fail:
+	ata_dev_printk(dev, KERN_ERR,
+		       "failed to configure Port Multiplier (%s, Emask=0x%x)\n",
+		       reason, err_mask);
+	return rc;
+}
+
+static int sata_pmp_init_links(struct ata_port *ap, int nr_ports)
+{
+	struct ata_link *pmp_link = ap->pmp_link;
+	int i;
+
+	if (!pmp_link) {
+		pmp_link = kzalloc(sizeof(pmp_link[0]) * SATA_PMP_MAX_PORTS,
+				   GFP_NOIO);
+		if (!pmp_link)
+			return -ENOMEM;
+
+		for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
+			ata_link_init(ap, &pmp_link[i], i);
+
+		ap->pmp_link = pmp_link;
+	}
+
+	for (i = 0; i < nr_ports; i++) {
+		struct ata_link *link = &pmp_link[i];
+		struct ata_eh_context *ehc = &link->eh_context;
+
+		link->flags = 0;
+		ehc->i.probe_mask |= 1;
+		ehc->i.action |= ATA_EH_SOFTRESET;
+		ehc->i.flags |= ATA_EHI_RESUME_LINK;
+	}
+
+	return 0;
+}
+
+static void sata_pmp_quirks(struct ata_port *ap)
+{
+	u32 *gscr = ap->link.device->gscr;
+	u16 vendor = sata_pmp_gscr_vendor(gscr);
+	u16 devid = sata_pmp_gscr_devid(gscr);
+	struct ata_link *link;
+
+	if (vendor == 0x1095 && devid == 0x3726) {
+		/* sil3726 quirks */
+		ata_port_for_each_link(link, ap) {
+			/* SError.N need a kick in the ass to get working */
+			link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+			/* class code report is unreliable */
+			if (link->pmp < 5)
+				link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+			/* port 5 is for SEMB device and it doesn't like SRST */
+			if (link->pmp == 5)
+				link->flags |= ATA_LFLAG_NO_SRST |
+					       ATA_LFLAG_ASSUME_SEMB;
+		}
+	} else if (vendor == 0x1095 && devid == 0x4723) {
+		/* sil4723 quirks */
+		ata_port_for_each_link(link, ap) {
+			/* SError.N need a kick in the ass to get working */
+			link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+			/* class code report is unreliable */
+			if (link->pmp < 2)
+				link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+			/* the config device at port 2 locks up on SRST */
+			if (link->pmp == 2)
+				link->flags |= ATA_LFLAG_NO_SRST |
+					       ATA_LFLAG_ASSUME_ATA;
+		}
+	} else if (vendor == 0x1095 && devid == 0x4726) {
+		/* sil4726 quirks */
+		ata_port_for_each_link(link, ap) {
+			/* SError.N need a kick in the ass to get working */
+			link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+
+			/* class code report is unreliable */
+			if (link->pmp < 5)
+				link->flags |= ATA_LFLAG_ASSUME_ATA;
+
+			/* The config device, which can be either at
+			 * port 0 or 5, locks up on SRST.
+			 */
+			if (link->pmp == 0 || link->pmp == 5)
+				link->flags |= ATA_LFLAG_NO_SRST |
+					       ATA_LFLAG_ASSUME_ATA;
+
+			/* Port 6 is for SEMB device which doesn't
+			 * like SRST either.
+			 */
+			if (link->pmp == 6)
+				link->flags |= ATA_LFLAG_NO_SRST |
+					       ATA_LFLAG_ASSUME_SEMB;
+		}
+	} else if (vendor == 0x1095 && (devid == 0x5723 || devid == 0x5733 ||
+					devid == 0x5734 || devid == 0x5744)) {
+		/* sil5723/5744 quirks */
+
+		/* sil5723/5744 has either two or three downstream
+		 * ports depending on operation mode.  The last port
+		 * is empty if any actual IO device is available or
+		 * occupied by a pseudo configuration device
+		 * otherwise.  Don't try hard to recover it.
+		 */
+		ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY;
+	} else if (vendor == 0x11ab && devid == 0x4140) {
+		/* Marvell 88SM4140 quirks.  Fan-out ports require PHY
+		 * reset to work; other than that, it behaves very
+		 * nicely.
+		 */
+		ata_port_for_each_link(link, ap)
+			link->flags |= ATA_LFLAG_HRST_TO_RESUME;
+	}
+}
+
+/**
+ *	sata_pmp_attach - attach a SATA PMP device
+ *	@dev: SATA PMP device to attach
+ *
+ *	Configure and attach SATA PMP device @dev.  This function is
+ *	also responsible for allocating and initializing PMP links.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+int sata_pmp_attach(struct ata_device *dev)
+{
+	struct ata_link *link = dev->link;
+	struct ata_port *ap = link->ap;
+	unsigned long flags;
+	struct ata_link *tlink;
+	int rc;
+
+	/* is it hanging off the right place? */
+	if (!(ap->flags & ATA_FLAG_PMP)) {
+		ata_dev_printk(dev, KERN_ERR,
+			       "host does not support Port Multiplier\n");
+		return -EINVAL;
+	}
+
+	if (!ata_is_host_link(link)) {
+		ata_dev_printk(dev, KERN_ERR,
+			       "Port Multipliers cannot be nested\n");
+		return -EINVAL;
+	}
+
+	if (dev->devno) {
+		ata_dev_printk(dev, KERN_ERR,
+			       "Port Multiplier must be the first device\n");
+		return -EINVAL;
+	}
+
+	WARN_ON(link->pmp != 0);
+	link->pmp = SATA_PMP_CTRL_PORT;
+
+	/* read GSCR block */
+	rc = sata_pmp_read_gscr(dev, dev->gscr);
+	if (rc)
+		goto fail;
+
+	/* config PMP */
+	rc = sata_pmp_configure(dev, 1);
+	if (rc)
+		goto fail;
+
+	rc = sata_pmp_init_links(ap, sata_pmp_gscr_ports(dev->gscr));
+	if (rc) {
+		ata_dev_printk(dev, KERN_INFO,
+			       "failed to initialize PMP links\n");
+		goto fail;
+	}
+
+	/* attach it */
+	spin_lock_irqsave(ap->lock, flags);
+	WARN_ON(ap->nr_pmp_links);
+	ap->nr_pmp_links = sata_pmp_gscr_ports(dev->gscr);
+	spin_unlock_irqrestore(ap->lock, flags);
+
+	sata_pmp_quirks(ap);
+
+	if (ap->ops->pmp_attach)
+		ap->ops->pmp_attach(ap);
+
+	ata_port_for_each_link(tlink, ap)
+		sata_link_init_spd(tlink);
+
+	ata_acpi_associate_sata_port(ap);
+
+	return 0;
+
+ fail:
+	link->pmp = 0;
+	return rc;
+}
+
+/**
+ *	sata_pmp_detach - detach a SATA PMP device
+ *	@dev: SATA PMP device to detach
+ *
+ *	Detach SATA PMP device @dev.  This function is also
+ *	responsible for deconfiguring PMP links.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ */
+static void sata_pmp_detach(struct ata_device *dev)
+{
+	struct ata_link *link = dev->link;
+	struct ata_port *ap = link->ap;
+	struct ata_link *tlink;
+	unsigned long flags;
+
+	ata_dev_printk(dev, KERN_INFO, "Port Multiplier detaching\n");
+
+	WARN_ON(!ata_is_host_link(link) || dev->devno ||
+		link->pmp != SATA_PMP_CTRL_PORT);
+
+	if (ap->ops->pmp_detach)
+		ap->ops->pmp_detach(ap);
+
+	ata_port_for_each_link(tlink, ap)
+		ata_eh_detach_dev(tlink->device);
+
+	spin_lock_irqsave(ap->lock, flags);
+	ap->nr_pmp_links = 0;
+	link->pmp = 0;
+	spin_unlock_irqrestore(ap->lock, flags);
+
+	ata_acpi_associate_sata_port(ap);
+}
+
+/**
+ *	sata_pmp_same_pmp - does new GSCR matches the configured PMP?
+ *	@dev: PMP device to compare against
+ *	@new_gscr: GSCR block of the new device
+ *
+ *	Compare @new_gscr against @dev and determine whether @dev is
+ *	the PMP described by @new_gscr.
+ *
+ *	LOCKING:
+ *	None.
+ *
+ *	RETURNS:
+ *	1 if @dev matches @new_gscr, 0 otherwise.
+ */
+static int sata_pmp_same_pmp(struct ata_device *dev, const u32 *new_gscr)
+{
+	const u32 *old_gscr = dev->gscr;
+	u16 old_vendor, new_vendor, old_devid, new_devid;
+	int old_nr_ports, new_nr_ports;
+
+	old_vendor = sata_pmp_gscr_vendor(old_gscr);
+	new_vendor = sata_pmp_gscr_vendor(new_gscr);
+	old_devid = sata_pmp_gscr_devid(old_gscr);
+	new_devid = sata_pmp_gscr_devid(new_gscr);
+	old_nr_ports = sata_pmp_gscr_ports(old_gscr);
+	new_nr_ports = sata_pmp_gscr_ports(new_gscr);
+
+	if (old_vendor != new_vendor) {
+		ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+			       "vendor mismatch '0x%x' != '0x%x'\n",
+			       old_vendor, new_vendor);
+		return 0;
+	}
+
+	if (old_devid != new_devid) {
+		ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+			       "device ID mismatch '0x%x' != '0x%x'\n",
+			       old_devid, new_devid);
+		return 0;
+	}
+
+	if (old_nr_ports != new_nr_ports) {
+		ata_dev_printk(dev, KERN_INFO, "Port Multiplier "
+			       "nr_ports mismatch '0x%x' != '0x%x'\n",
+			       old_nr_ports, new_nr_ports);
+		return 0;
+	}
+
+	return 1;
+}
+
+/**
+ *	sata_pmp_revalidate - revalidate SATA PMP
+ *	@dev: PMP device to revalidate
+ *	@new_class: new class code
+ *
+ *	Re-read GSCR block and make sure @dev is still attached to the
+ *	port and properly configured.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+static int sata_pmp_revalidate(struct ata_device *dev, unsigned int new_class)
+{
+	struct ata_link *link = dev->link;
+	struct ata_port *ap = link->ap;
+	u32 *gscr = (void *)ap->sector_buf;
+	int rc;
+
+	DPRINTK("ENTER\n");
+
+	ata_eh_about_to_do(link, NULL, ATA_EH_REVALIDATE);
+
+	if (!ata_dev_enabled(dev)) {
+		rc = -ENODEV;
+		goto fail;
+	}
+
+	/* wrong class? */
+	if (ata_class_enabled(new_class) && new_class != ATA_DEV_PMP) {
+		rc = -ENODEV;
+		goto fail;
+	}
+
+	/* read GSCR */
+	rc = sata_pmp_read_gscr(dev, gscr);
+	if (rc)
+		goto fail;
+
+	/* is the pmp still there? */
+	if (!sata_pmp_same_pmp(dev, gscr)) {
+		rc = -ENODEV;
+		goto fail;
+	}
+
+	memcpy(dev->gscr, gscr, sizeof(gscr[0]) * SATA_PMP_GSCR_DWORDS);
+
+	rc = sata_pmp_configure(dev, 0);
+	if (rc)
+		goto fail;
+
+	ata_eh_done(link, NULL, ATA_EH_REVALIDATE);
+
+	DPRINTK("EXIT, rc=0\n");
+	return 0;
+
+ fail:
+	ata_dev_printk(dev, KERN_ERR,
+		       "PMP revalidation failed (errno=%d)\n", rc);
+	DPRINTK("EXIT, rc=%d\n", rc);
+	return rc;
+}
+
+/**
+ *	sata_pmp_revalidate_quick - revalidate SATA PMP quickly
+ *	@dev: PMP device to revalidate
+ *
+ *	Make sure the attached PMP is accessible.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno otherwise.
+ */
+static int sata_pmp_revalidate_quick(struct ata_device *dev)
+{
+	unsigned int err_mask;
+	u32 prod_id;
+
+	err_mask = sata_pmp_read(dev->link, SATA_PMP_GSCR_PROD_ID, &prod_id);
+	if (err_mask) {
+		ata_dev_printk(dev, KERN_ERR, "failed to read PMP product ID "
+			       "(Emask=0x%x)\n", err_mask);
+		return -EIO;
+	}
+
+	if (prod_id != dev->gscr[SATA_PMP_GSCR_PROD_ID]) {
+		ata_dev_printk(dev, KERN_ERR, "PMP product ID mismatch\n");
+		/* something weird is going on, request full PMP recovery */
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ *	sata_pmp_eh_recover_pmp - recover PMP
+ *	@ap: ATA port PMP is attached to
+ *	@prereset: prereset method (can be NULL)
+ *	@softreset: softreset method
+ *	@hardreset: hardreset method
+ *	@postreset: postreset method (can be NULL)
+ *
+ *	Recover PMP attached to @ap.  Recovery procedure is somewhat
+ *	similar to that of ata_eh_recover() except that reset should
+ *	always be performed in hard->soft sequence and recovery
+ *	failure results in PMP detachment.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
+		ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+		ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+{
+	struct ata_link *link = &ap->link;
+	struct ata_eh_context *ehc = &link->eh_context;
+	struct ata_device *dev = link->device;
+	int tries = ATA_EH_PMP_TRIES;
+	int detach = 0, rc = 0;
+	int reval_failed = 0;
+
+	DPRINTK("ENTER\n");
+
+	if (dev->flags & ATA_DFLAG_DETACH) {
+		detach = 1;
+		goto fail;
+	}
+
+ retry:
+	ehc->classes[0] = ATA_DEV_UNKNOWN;
+
+	if (ehc->i.action & ATA_EH_RESET_MASK) {
+		struct ata_link *tlink;
+
+		ata_eh_freeze_port(ap);
+
+		/* reset */
+		ehc->i.action = ATA_EH_HARDRESET;
+		rc = ata_eh_reset(link, 0, prereset, softreset, hardreset,
+				  postreset);
+		if (rc) {
+			ata_link_printk(link, KERN_ERR,
+					"failed to reset PMP, giving up\n");
+			goto fail;
+		}
+
+		ata_eh_thaw_port(ap);
+
+		/* PMP is reset, SErrors cannot be trusted, scan all */
+		ata_port_for_each_link(tlink, ap)
+			ata_ehi_schedule_probe(&tlink->eh_context.i);
+	}
+
+	/* If revalidation is requested, revalidate and reconfigure;
+	 * otherwise, do quick revalidation.
+	 */
+	if (ehc->i.action & ATA_EH_REVALIDATE)
+		rc = sata_pmp_revalidate(dev, ehc->classes[0]);
+	else
+		rc = sata_pmp_revalidate_quick(dev);
+
+	if (rc) {
+		tries--;
+
+		if (rc == -ENODEV) {
+			ehc->i.probe_mask |= 1;
+			detach = 1;
+			/* give it just two more chances */
+			tries = min(tries, 2);
+		}
+
+		if (tries) {
+			int sleep = ehc->i.flags & ATA_EHI_DID_RESET;
+
+			/* consecutive revalidation failures? speed down */
+			if (reval_failed)
+				sata_down_spd_limit(link);
+			else
+				reval_failed = 1;
+
+			ata_dev_printk(dev, KERN_WARNING,
+				       "retrying hardreset%s\n",
+				       sleep ? " in 5 secs" : "");
+			if (sleep)
+				ssleep(5);
+			ehc->i.action |= ATA_EH_HARDRESET;
+			goto retry;
+		} else {
+			ata_dev_printk(dev, KERN_ERR, "failed to recover PMP "
+				       "after %d tries, giving up\n",
+				       ATA_EH_PMP_TRIES);
+			goto fail;
+		}
+	}
+
+	/* okay, PMP resurrected */
+	ehc->i.flags = 0;
+
+	DPRINTK("EXIT, rc=0\n");
+	return 0;
+
+ fail:
+	sata_pmp_detach(dev);
+	if (detach)
+		ata_eh_detach_dev(dev);
+	else
+		ata_dev_disable(dev);
+
+	DPRINTK("EXIT, rc=%d\n", rc);
+	return rc;
+}
+
+static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap)
+{
+	struct ata_link *link;
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(ap->lock, flags);
+
+	ata_port_for_each_link(link, ap) {
+		if (!(link->flags & ATA_LFLAG_DISABLED))
+			continue;
+
+		spin_unlock_irqrestore(ap->lock, flags);
+
+		/* Some PMPs require hardreset sequence to get
+		 * SError.N working.
+		 */
+		if ((link->flags & ATA_LFLAG_HRST_TO_RESUME) &&
+		    (link->eh_context.i.flags & ATA_EHI_RESUME_LINK))
+			sata_link_hardreset(link, sata_deb_timing_normal,
+					    jiffies + ATA_TMOUT_INTERNAL_QUICK);
+
+		/* unconditionally clear SError.N */
+		rc = sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
+		if (rc) {
+			ata_link_printk(link, KERN_ERR, "failed to clear "
+					"SError.N (errno=%d)\n", rc);
+			return rc;
+		}
+
+		spin_lock_irqsave(ap->lock, flags);
+	}
+
+	spin_unlock_irqrestore(ap->lock, flags);
+
+	return 0;
+}
+
+static int sata_pmp_handle_link_fail(struct ata_link *link, int *link_tries)
+{
+	struct ata_port *ap = link->ap;
+	unsigned long flags;
+
+	if (link_tries[link->pmp] && --link_tries[link->pmp])
+		return 1;
+
+	/* disable this link */
+	if (!(link->flags & ATA_LFLAG_DISABLED)) {
+		ata_link_printk(link, KERN_WARNING,
+			"failed to recover link after %d tries, disabling\n",
+			ATA_EH_PMP_LINK_TRIES);
+
+		spin_lock_irqsave(ap->lock, flags);
+		link->flags |= ATA_LFLAG_DISABLED;
+		spin_unlock_irqrestore(ap->lock, flags);
+	}
+
+	ata_dev_disable(link->device);
+	link->eh_context.i.action = 0;
+
+	return 0;
+}
+
+/**
+ *	sata_pmp_eh_recover - recover PMP-enabled port
+ *	@ap: ATA port to recover
+ *	@prereset: prereset method (can be NULL)
+ *	@softreset: softreset method
+ *	@hardreset: hardreset method
+ *	@postreset: postreset method (can be NULL)
+ *	@pmp_prereset: PMP prereset method (can be NULL)
+ *	@pmp_softreset: PMP softreset method (can be NULL)
+ *	@pmp_hardreset: PMP hardreset method (can be NULL)
+ *	@pmp_postreset: PMP postreset method (can be NULL)
+ *
+ *	Drive EH recovery operation for PMP enabled port @ap.  This
+ *	function recovers host and PMP ports with proper retrials and
+ *	fallbacks.  Actual recovery operations are performed using
+ *	ata_eh_recover() and sata_pmp_eh_recover_pmp().
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ *
+ *	RETURNS:
+ *	0 on success, -errno on failure.
+ */
+static int sata_pmp_eh_recover(struct ata_port *ap,
+		ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+		ata_reset_fn_t hardreset, ata_postreset_fn_t postreset,
+		ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset,
+		ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset)
+{
+	int pmp_tries, link_tries[SATA_PMP_MAX_PORTS];
+	struct ata_link *pmp_link = &ap->link;
+	struct ata_device *pmp_dev = pmp_link->device;
+	struct ata_eh_context *pmp_ehc = &pmp_link->eh_context;
+	struct ata_link *link;
+	struct ata_device *dev;
+	unsigned int err_mask;
+	u32 gscr_error, sntf;
+	int cnt, rc;
+
+	pmp_tries = ATA_EH_PMP_TRIES;
+	ata_port_for_each_link(link, ap)
+		link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
+
+ retry:
+	/* PMP attached? */
+	if (!ap->nr_pmp_links) {
+		rc = ata_eh_recover(ap, prereset, softreset, hardreset,
+				    postreset, NULL);
+		if (rc) {
+			ata_link_for_each_dev(dev, &ap->link)
+				ata_dev_disable(dev);
+			return rc;
+		}
+
+		if (pmp_dev->class != ATA_DEV_PMP)
+			return 0;
+
+		/* new PMP online */
+		ata_port_for_each_link(link, ap)
+			link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
+
+		/* fall through */
+	}
+
+	/* recover pmp */
+	rc = sata_pmp_eh_recover_pmp(ap, prereset, softreset, hardreset,
+				     postreset);
+	if (rc)
+		goto pmp_fail;
+
+	/* handle disabled links */
+	rc = sata_pmp_eh_handle_disabled_links(ap);
+	if (rc)
+		goto pmp_fail;
+
+	/* recover links */
+	rc = ata_eh_recover(ap, pmp_prereset, pmp_softreset, pmp_hardreset,
+			    pmp_postreset, &link);
+	if (rc)
+		goto link_fail;
+
+	/* Connection status might have changed while resetting other
+	 * links, check SATA_PMP_GSCR_ERROR before returning.
+	 */
+
+	/* clear SNotification */
+	rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
+	if (rc == 0)
+		sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
+
+	/* enable notification */
+	if (pmp_dev->flags & ATA_DFLAG_AN) {
+		pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
+
+		err_mask = sata_pmp_write(pmp_dev->link, SATA_PMP_GSCR_FEAT_EN,
+					  pmp_dev->gscr[SATA_PMP_GSCR_FEAT_EN]);
+		if (err_mask) {
+			ata_dev_printk(pmp_dev, KERN_ERR, "failed to write "
+				       "PMP_FEAT_EN (Emask=0x%x)\n", err_mask);
+			rc = -EIO;
+			goto pmp_fail;
+		}
+	}
+
+	/* check GSCR_ERROR */
+	err_mask = sata_pmp_read(pmp_link, SATA_PMP_GSCR_ERROR, &gscr_error);
+	if (err_mask) {
+		ata_dev_printk(pmp_dev, KERN_ERR, "failed to read "
+			       "PMP_GSCR_ERROR (Emask=0x%x)\n", err_mask);
+		rc = -EIO;
+		goto pmp_fail;
+	}
+
+	cnt = 0;
+	ata_port_for_each_link(link, ap) {
+		if (!(gscr_error & (1 << link->pmp)))
+			continue;
+
+		if (sata_pmp_handle_link_fail(link, link_tries)) {
+			ata_ehi_hotplugged(&link->eh_context.i);
+			cnt++;
+		} else {
+			ata_link_printk(link, KERN_WARNING,
+				"PHY status changed but maxed out on retries, "
+				"giving up\n");
+			ata_link_printk(link, KERN_WARNING,
+				"Manully issue scan to resume this link\n");
+		}
+	}
+
+	if (cnt) {
+		ata_port_printk(ap, KERN_INFO, "PMP SError.N set for some "
+				"ports, repeating recovery\n");
+		goto retry;
+	}
+
+	return 0;
+
+ link_fail:
+	if (sata_pmp_handle_link_fail(link, link_tries)) {
+		pmp_ehc->i.action |= ATA_EH_HARDRESET;
+		goto retry;
+	}
+
+	/* fall through */
+ pmp_fail:
+	/* Control always ends up here after detaching PMP.  Shut up
+	 * and return if we're unloading.
+	 */
+	if (ap->pflags & ATA_PFLAG_UNLOADING)
+		return rc;
+
+	if (!ap->nr_pmp_links)
+		goto retry;
+
+	if (--pmp_tries) {
+		ata_port_printk(ap, KERN_WARNING,
+				"failed to recover PMP, retrying in 5 secs\n");
+		pmp_ehc->i.action |= ATA_EH_HARDRESET;
+		ssleep(5);
+		goto retry;
+	}
+
+	ata_port_printk(ap, KERN_ERR,
+			"failed to recover PMP after %d tries, giving up\n",
+			ATA_EH_PMP_TRIES);
+	sata_pmp_detach(pmp_dev);
+	ata_dev_disable(pmp_dev);
+
+	return rc;
+}
+
+/**
+ *	sata_pmp_do_eh - do standard error handling for PMP-enabled host
+ *	@ap: host port to handle error for
+ *	@prereset: prereset method (can be NULL)
+ *	@softreset: softreset method
+ *	@hardreset: hardreset method
+ *	@postreset: postreset method (can be NULL)
+ *	@pmp_prereset: PMP prereset method (can be NULL)
+ *	@pmp_softreset: PMP softreset method (can be NULL)
+ *	@pmp_hardreset: PMP hardreset method (can be NULL)
+ *	@pmp_postreset: PMP postreset method (can be NULL)
+ *
+ *	Perform standard error handling sequence for PMP-enabled host
+ *	@ap.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep).
+ */
+void sata_pmp_do_eh(struct ata_port *ap,
+		ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+		ata_reset_fn_t hardreset, ata_postreset_fn_t postreset,
+		ata_prereset_fn_t pmp_prereset, ata_reset_fn_t pmp_softreset,
+		ata_reset_fn_t pmp_hardreset, ata_postreset_fn_t pmp_postreset)
+{
+	ata_eh_autopsy(ap);
+	ata_eh_report(ap);
+	sata_pmp_eh_recover(ap, prereset, softreset, hardreset, postreset,
+			    pmp_prereset, pmp_softreset, pmp_hardreset,
+			    pmp_postreset);
+	ata_eh_finish(ap);
+}
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index cfde22d..ea53e6a 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -71,11 +71,10 @@
 #define ALL_SUB_MPAGES 0xff
 
 
-static const u8 def_rw_recovery_mpage[] = {
+static const u8 def_rw_recovery_mpage[RW_RECOVERY_MPAGE_LEN] = {
 	RW_RECOVERY_MPAGE,
 	RW_RECOVERY_MPAGE_LEN - 2,
-	(1 << 7) |	/* AWRE, sat-r06 say it shall be 0 */
-	    (1 << 6),	/* ARRE (auto read reallocation) */
+	(1 << 7),	/* AWRE */
 	0,		/* read retry count */
 	0, 0, 0, 0,
 	0,		/* write retry count */
@@ -450,13 +449,8 @@
 		qc->scsicmd = cmd;
 		qc->scsidone = done;
 
-		if (cmd->use_sg) {
-			qc->__sg = (struct scatterlist *) cmd->request_buffer;
-			qc->n_elem = cmd->use_sg;
-		} else if (cmd->request_bufflen) {
-			qc->__sg = &qc->sgent;
-			qc->n_elem = 1;
-		}
+		qc->__sg = scsi_sglist(cmd);
+		qc->n_elem = scsi_sg_count(cmd);
 	} else {
 		cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
 		done(cmd);
@@ -755,6 +749,13 @@
 {
 	sdev->use_10_for_rw = 1;
 	sdev->use_10_for_ms = 1;
+
+	/* Schedule policy is determined by ->qc_defer() callback and
+	 * it needs to see every deferred qc.  Set dev_blocked to 1 to
+	 * prevent SCSI midlayer from automatically deferring
+	 * requests.
+	 */
+	sdev->max_device_blocked = 1;
 }
 
 static void ata_scsi_dev_config(struct scsi_device *sdev,
@@ -768,7 +769,7 @@
 	 * Decrement max hw segments accordingly.
 	 */
 	if (dev->class == ATA_DEV_ATAPI) {
-		request_queue_t *q = sdev->request_queue;
+		struct request_queue *q = sdev->request_queue;
 		blk_queue_max_hw_segments(q, q->max_hw_segments - 1);
 	}
 
@@ -943,6 +944,13 @@
 		goto invalid_fld;       /* LOEJ bit set not supported */
 	if (((cdb[4] >> 4) & 0xf) != 0)
 		goto invalid_fld;       /* power conditions not supported */
+
+	if (qc->dev->horkage & ATA_HORKAGE_SKIP_PM) {
+		/* the device lacks PM support, finish without doing anything */
+		scmd->result = SAM_STAT_GOOD;
+		return 1;
+	}
+
 	if (cdb[4] & 0x1) {
 		tf->nsect = 1;	/* 1 sector, lba=0 */
 
@@ -1368,14 +1376,14 @@
 		case ATA_CMD_SET_FEATURES:
 			if ((qc->tf.feature == SETFEATURES_WC_ON) ||
 			    (qc->tf.feature == SETFEATURES_WC_OFF)) {
-				ap->eh_info.action |= ATA_EH_REVALIDATE;
+				ap->link.eh_info.action |= ATA_EH_REVALIDATE;
 				ata_port_schedule_eh(ap);
 			}
 			break;
 
 		case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */
 		case ATA_CMD_SET_MULTI: /* multi_count changed */
-			ap->eh_info.action |= ATA_EH_REVALIDATE;
+			ap->link.eh_info.action |= ATA_EH_REVALIDATE;
 			ata_port_schedule_eh(ap);
 			break;
 		}
@@ -1422,37 +1430,6 @@
 }
 
 /**
- *	ata_scmd_need_defer - Check whether we need to defer scmd
- *	@dev: ATA device to which the command is addressed
- *	@is_io: Is the command IO (and thus possibly NCQ)?
- *
- *	NCQ and non-NCQ commands cannot run together.  As upper layer
- *	only knows the queue depth, we are responsible for maintaining
- *	exclusion.  This function checks whether a new command can be
- *	issued to @dev.
- *
- *	LOCKING:
- *	spin_lock_irqsave(host lock)
- *
- *	RETURNS:
- *	1 if deferring is needed, 0 otherwise.
- */
-static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
-{
-	struct ata_port *ap = dev->ap;
-	int is_ncq = is_io && ata_ncq_enabled(dev);
-
-	if (is_ncq) {
-		if (!ata_tag_valid(ap->active_tag))
-			return 0;
-	} else {
-		if (!ata_tag_valid(ap->active_tag) && !ap->sactive)
-			return 0;
-	}
-	return 1;
-}
-
-/**
  *	ata_scsi_translate - Translate then issue SCSI command to ATA device
  *	@dev: ATA device to which the command is addressed
  *	@cmd: SCSI command to execute
@@ -1483,14 +1460,12 @@
 			      void (*done)(struct scsi_cmnd *),
 			      ata_xlat_func_t xlat_func)
 {
+	struct ata_port *ap = dev->link->ap;
 	struct ata_queued_cmd *qc;
-	int is_io = xlat_func == ata_scsi_rw_xlat;
+	int rc;
 
 	VPRINTK("ENTER\n");
 
-	if (unlikely(ata_scmd_need_defer(dev, is_io)))
-		goto defer;
-
 	qc = ata_scsi_qc_new(dev, cmd, done);
 	if (!qc)
 		goto err_mem;
@@ -1498,17 +1473,13 @@
 	/* data is present; dma-map it */
 	if (cmd->sc_data_direction == DMA_FROM_DEVICE ||
 	    cmd->sc_data_direction == DMA_TO_DEVICE) {
-		if (unlikely(cmd->request_bufflen < 1)) {
+		if (unlikely(scsi_bufflen(cmd) < 1)) {
 			ata_dev_printk(dev, KERN_WARNING,
 				       "WARNING: zero len r/w req\n");
 			goto err_did;
 		}
 
-		if (cmd->use_sg)
-			ata_sg_init(qc, cmd->request_buffer, cmd->use_sg);
-		else
-			ata_sg_init_one(qc, cmd->request_buffer,
-					cmd->request_bufflen);
+		ata_sg_init(qc, scsi_sglist(cmd), scsi_sg_count(cmd));
 
 		qc->dma_dir = cmd->sc_data_direction;
 	}
@@ -1518,6 +1489,11 @@
 	if (xlat_func(qc))
 		goto early_finish;
 
+	if (ap->ops->qc_defer) {
+		if ((rc = ap->ops->qc_defer(qc)))
+			goto defer;
+	}
+
 	/* select device, send command to hardware */
 	ata_qc_issue(qc);
 
@@ -1539,8 +1515,12 @@
 	return 0;
 
 defer:
+	ata_qc_free(qc);
 	DPRINTK("EXIT - defer\n");
-	return SCSI_MLQUEUE_DEVICE_BUSY;
+	if (rc == ATA_DEFER_LINK)
+		return SCSI_MLQUEUE_DEVICE_BUSY;
+	else
+		return SCSI_MLQUEUE_HOST_BUSY;
 }
 
 /**
@@ -1562,15 +1542,14 @@
 	u8 *buf;
 	unsigned int buflen;
 
-	if (cmd->use_sg) {
-		struct scatterlist *sg;
+	struct scatterlist *sg = scsi_sglist(cmd);
 
-		sg = (struct scatterlist *) cmd->request_buffer;
+	if (sg) {
 		buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
 		buflen = sg->length;
 	} else {
-		buf = cmd->request_buffer;
-		buflen = cmd->request_bufflen;
+		buf = NULL;
+		buflen = 0;
 	}
 
 	*buf_out = buf;
@@ -1590,12 +1569,9 @@
 
 static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
 {
-	if (cmd->use_sg) {
-		struct scatterlist *sg;
-
-		sg = (struct scatterlist *) cmd->request_buffer;
+	struct scatterlist *sg = scsi_sglist(cmd);
+	if (sg)
 		kunmap_atomic(buf - sg->offset, KM_IRQ0);
-	}
 }
 
 /**
@@ -1817,6 +1793,62 @@
 }
 
 /**
+ *	ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info
+ *	@args: device IDENTIFY data / SCSI command of interest.
+ *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *	@buflen: Response buffer length.
+ *
+ *	Yields SAT-specified ATA VPD page.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host lock)
+ */
+
+unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
+			      unsigned int buflen)
+{
+	u8 pbuf[60];
+	struct ata_taskfile tf;
+	unsigned int i;
+
+	if (!buflen)
+		return 0;
+
+	memset(&pbuf, 0, sizeof(pbuf));
+	memset(&tf, 0, sizeof(tf));
+
+	pbuf[1] = 0x89;			/* our page code */
+	pbuf[2] = (0x238 >> 8);		/* page size fixed at 238h */
+	pbuf[3] = (0x238 & 0xff);
+
+	memcpy(&pbuf[8], "linux   ", 8);
+	memcpy(&pbuf[16], "libata          ", 16);
+	memcpy(&pbuf[32], DRV_VERSION, 4);
+	ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4);
+
+	/* we don't store the ATA device signature, so we fake it */
+
+	tf.command = ATA_DRDY;		/* really, this is Status reg */
+	tf.lbal = 0x1;
+	tf.nsect = 0x1;
+
+	ata_tf_to_fis(&tf, 0, 1, &pbuf[36]);	/* TODO: PMP? */
+	pbuf[36] = 0x34;		/* force D2H Reg FIS (34h) */
+
+	pbuf[56] = ATA_CMD_ID_ATA;
+
+	i = min(buflen, 60U);
+	memcpy(rbuf, &pbuf[0], i);
+	buflen -= i;
+
+	if (!buflen)
+		return 0;
+
+	memcpy(&rbuf[60], &args->id[0], min(buflen, 512U));
+	return 0;
+}
+
+/**
  *	ata_scsiop_noop - Command handler that simply returns success.
  *	@args: device IDENTIFY data / SCSI command of interest.
  *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
@@ -2273,8 +2305,8 @@
 		qc->tf.feature |= ATAPI_PKT_DMA;
 	} else {
 		qc->tf.protocol = ATA_PROT_ATAPI;
-		qc->tf.lbam = (8 * 1024) & 0xff;
-		qc->tf.lbah = (8 * 1024) >> 8;
+		qc->tf.lbam = SCSI_SENSE_BUFFERSIZE;
+		qc->tf.lbah = 0;
 	}
 	qc->nbytes = SCSI_SENSE_BUFFERSIZE;
 
@@ -2383,6 +2415,7 @@
 	struct ata_device *dev = qc->dev;
 	int using_pio = (dev->flags & ATA_DFLAG_PIO);
 	int nodata = (scmd->sc_data_direction == DMA_NONE);
+	unsigned int nbytes;
 
 	memset(qc->cdb, 0, dev->cdb_len);
 	memcpy(qc->cdb, scmd->cmnd, scmd->cmd_len);
@@ -2396,20 +2429,26 @@
 	}
 
 	qc->tf.command = ATA_CMD_PACKET;
-	qc->nbytes = scmd->request_bufflen;
+	qc->nbytes = scsi_bufflen(scmd);
 
 	/* check whether ATAPI DMA is safe */
 	if (!using_pio && ata_check_atapi_dma(qc))
 		using_pio = 1;
 
+	/* Some controller variants snoop this value for Packet transfers
+	   to do state machine and FIFO management. Thus we want to set it
+	   properly, and for DMA where it is effectively meaningless */
+	nbytes = min(qc->nbytes, (unsigned int)63 * 1024);
+
+	qc->tf.lbam = (nbytes & 0xFF);
+	qc->tf.lbah = (nbytes >> 8);
+
 	if (using_pio || nodata) {
 		/* no data, or PIO data xfer */
 		if (nodata)
 			qc->tf.protocol = ATA_PROT_ATAPI_NODATA;
 		else
 			qc->tf.protocol = ATA_PROT_ATAPI;
-		qc->tf.lbam = (8 * 1024) & 0xff;
-		qc->tf.lbah = (8 * 1024) >> 8;
 	} else {
 		/* DMA data xfer */
 		qc->tf.protocol = ATA_PROT_ATAPI_DMA;
@@ -2420,24 +2459,42 @@
 			qc->tf.feature |= ATAPI_DMADIR;
 	}
 
+
+	/* FIXME: We need to translate 0x05 READ_BLOCK_LIMITS to a MODE_SENSE
+	   as ATAPI tape drives don't get this right otherwise */
 	return 0;
 }
 
-static struct ata_device * ata_find_dev(struct ata_port *ap, int id)
+static struct ata_device * ata_find_dev(struct ata_port *ap, int devno)
 {
-	if (likely(id < ATA_MAX_DEVICES))
-		return &ap->device[id];
+	if (ap->nr_pmp_links == 0) {
+		if (likely(devno < ata_link_max_devices(&ap->link)))
+			return &ap->link.device[devno];
+	} else {
+		if (likely(devno < ap->nr_pmp_links))
+			return &ap->pmp_link[devno].device[0];
+	}
+
 	return NULL;
 }
 
 static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
 					const struct scsi_device *scsidev)
 {
-	/* skip commands not addressed to targets we simulate */
-	if (unlikely(scsidev->channel || scsidev->lun))
-		return NULL;
+	int devno;
 
-	return ata_find_dev(ap, scsidev->id);
+	/* skip commands not addressed to targets we simulate */
+	if (ap->nr_pmp_links == 0) {
+		if (unlikely(scsidev->channel || scsidev->lun))
+			return NULL;
+		devno = scsidev->id;
+	} else {
+		if (unlikely(scsidev->id || scsidev->lun))
+			return NULL;
+		devno = scsidev->channel;
+	}
+
+	return ata_find_dev(ap, devno);
 }
 
 /**
@@ -2458,7 +2515,7 @@
 	if (unlikely(!ata_dev_enabled(dev)))
 		return 0;
 
-	if (!atapi_enabled || (dev->ap->flags & ATA_FLAG_NO_ATAPI)) {
+	if (!atapi_enabled || (dev->link->ap->flags & ATA_FLAG_NO_ATAPI)) {
 		if (unlikely(dev->class == ATA_DEV_ATAPI)) {
 			ata_dev_printk(dev, KERN_WARNING,
 				       "WARNING: ATAPI is %s, device ignored.\n",
@@ -2631,7 +2688,7 @@
 	case ATA_CMD_WRITE_LONG_ONCE:
 		if (tf->protocol != ATA_PROT_PIO || tf->nsect != 1)
 			goto invalid_fld;
-		qc->sect_size = scmd->request_bufflen;
+		qc->sect_size = scsi_bufflen(scmd);
 	}
 
 	/*
@@ -2661,7 +2718,7 @@
 	 * TODO: find out if we need to do more here to
 	 *       cover scatter/gather case.
 	 */
-	qc->nbytes = scmd->request_bufflen;
+	qc->nbytes = scsi_bufflen(scmd);
 
 	/* request result TF */
 	qc->flags |= ATA_QCFLAG_RESULT_TF;
@@ -2746,28 +2803,48 @@
 				      void (*done)(struct scsi_cmnd *),
 				      struct ata_device *dev)
 {
+	u8 scsi_op = scmd->cmnd[0];
+	ata_xlat_func_t xlat_func;
 	int rc = 0;
 
-	if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len)) {
-		DPRINTK("bad CDB len=%u, max=%u\n",
-			scmd->cmd_len, dev->cdb_len);
-		scmd->result = DID_ERROR << 16;
-		done(scmd);
-		return 0;
+	if (dev->class == ATA_DEV_ATA) {
+		if (unlikely(!scmd->cmd_len || scmd->cmd_len > dev->cdb_len))
+			goto bad_cdb_len;
+
+		xlat_func = ata_get_xlat_func(dev, scsi_op);
+	} else {
+		if (unlikely(!scmd->cmd_len))
+			goto bad_cdb_len;
+
+		xlat_func = NULL;
+		if (likely((scsi_op != ATA_16) || !atapi_passthru16)) {
+			/* relay SCSI command to ATAPI device */
+			if (unlikely(scmd->cmd_len > dev->cdb_len))
+				goto bad_cdb_len;
+
+			xlat_func = atapi_xlat;
+		} else {
+			/* ATA_16 passthru, treat as an ATA command */
+			if (unlikely(scmd->cmd_len > 16))
+				goto bad_cdb_len;
+
+			xlat_func = ata_get_xlat_func(dev, scsi_op);
+		}
 	}
 
-	if (dev->class == ATA_DEV_ATA) {
-		ata_xlat_func_t xlat_func = ata_get_xlat_func(dev,
-							      scmd->cmnd[0]);
-
-		if (xlat_func)
-			rc = ata_scsi_translate(dev, scmd, done, xlat_func);
-		else
-			ata_scsi_simulate(dev, scmd, done);
-	} else
-		rc = ata_scsi_translate(dev, scmd, done, atapi_xlat);
+	if (xlat_func)
+		rc = ata_scsi_translate(dev, scmd, done, xlat_func);
+	else
+		ata_scsi_simulate(dev, scmd, done);
 
 	return rc;
+
+ bad_cdb_len:
+	DPRINTK("bad CDB len=%u, scsi_op=0x%02x, max=%u\n",
+		scmd->cmd_len, scsi_op, dev->cdb_len);
+	scmd->result = DID_ERROR << 16;
+	done(scmd);
+	return 0;
 }
 
 /**
@@ -2835,6 +2912,7 @@
 {
 	struct ata_scsi_args args;
 	const u8 *scsicmd = cmd->cmnd;
+	u8 tmp8;
 
 	args.dev = dev;
 	args.id = dev->id;
@@ -2842,15 +2920,9 @@
 	args.done = done;
 
 	switch(scsicmd[0]) {
-		/* no-op's, complete with success */
-		case SYNCHRONIZE_CACHE:
-		case REZERO_UNIT:
-		case SEEK_6:
-		case SEEK_10:
-		case TEST_UNIT_READY:
-		case FORMAT_UNIT:		/* FIXME: correct? */
-		case SEND_DIAGNOSTIC:		/* FIXME: correct? */
-			ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+		/* TODO: worth improving? */
+		case FORMAT_UNIT:
+			ata_scsi_invalid_field(cmd, done);
 			break;
 
 		case INQUIRY:
@@ -2858,14 +2930,23 @@
 				ata_scsi_invalid_field(cmd, done);
 			else if ((scsicmd[1] & 1) == 0)    /* is EVPD clear? */
 				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
-			else if (scsicmd[2] == 0x00)
+			else switch (scsicmd[2]) {
+			case 0x00:
 				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00);
-			else if (scsicmd[2] == 0x80)
+				break;
+			case 0x80:
 				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80);
-			else if (scsicmd[2] == 0x83)
+				break;
+			case 0x83:
 				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83);
-			else
+				break;
+			case 0x89:
+				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_89);
+				break;
+			default:
 				ata_scsi_invalid_field(cmd, done);
+				break;
+			}
 			break;
 
 		case MODE_SENSE:
@@ -2893,8 +2974,33 @@
 			ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns);
 			break;
 
-		/* mandatory commands we haven't implemented yet */
 		case REQUEST_SENSE:
+			ata_scsi_set_sense(cmd, 0, 0, 0);
+			cmd->result = (DRIVER_SENSE << 24);
+			done(cmd);
+			break;
+
+		/* if we reach this, then writeback caching is disabled,
+		 * turning this into a no-op.
+		 */
+		case SYNCHRONIZE_CACHE:
+			/* fall through */
+
+		/* no-op's, complete with success */
+		case REZERO_UNIT:
+		case SEEK_6:
+		case SEEK_10:
+		case TEST_UNIT_READY:
+			ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+			break;
+
+		case SEND_DIAGNOSTIC:
+			tmp8 = scsicmd[1] & ~(1 << 3);
+			if ((tmp8 == 0x4) && (!scsicmd[3]) && (!scsicmd[4]))
+				ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+			else
+				ata_scsi_invalid_field(cmd, done);
+			break;
 
 		/* all other commands */
 		default:
@@ -2928,6 +3034,13 @@
 		shost->max_channel = 1;
 		shost->max_cmd_len = 16;
 
+		/* Schedule policy is determined by ->qc_defer()
+		 * callback and it needs to see every deferred qc.
+		 * Set host_blocked to 1 to prevent SCSI midlayer from
+		 * automatically deferring requests.
+		 */
+		shost->max_host_blocked = 1;
+
 		rc = scsi_add_host(ap->scsi_host, ap->host->dev);
 		if (rc)
 			goto err_add;
@@ -2947,26 +3060,79 @@
 	return rc;
 }
 
-void ata_scsi_scan_host(struct ata_port *ap)
+void ata_scsi_scan_host(struct ata_port *ap, int sync)
 {
-	unsigned int i;
+	int tries = 5;
+	struct ata_device *last_failed_dev = NULL;
+	struct ata_link *link;
+	struct ata_device *dev;
 
 	if (ap->flags & ATA_FLAG_DISABLED)
 		return;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
-		struct scsi_device *sdev;
+ repeat:
+	ata_port_for_each_link(link, ap) {
+		ata_link_for_each_dev(dev, link) {
+			struct scsi_device *sdev;
+			int channel = 0, id = 0;
 
-		if (!ata_dev_enabled(dev) || dev->sdev)
-			continue;
+			if (!ata_dev_enabled(dev) || dev->sdev)
+				continue;
 
-		sdev = __scsi_add_device(ap->scsi_host, 0, i, 0, NULL);
-		if (!IS_ERR(sdev)) {
-			dev->sdev = sdev;
-			scsi_device_put(sdev);
+			if (ata_is_host_link(link))
+				id = dev->devno;
+			else
+				channel = link->pmp;
+
+			sdev = __scsi_add_device(ap->scsi_host, channel, id, 0,
+						 NULL);
+			if (!IS_ERR(sdev)) {
+				dev->sdev = sdev;
+				scsi_device_put(sdev);
+			}
 		}
 	}
+
+	/* If we scanned while EH was in progress or allocation
+	 * failure occurred, scan would have failed silently.  Check
+	 * whether all devices are attached.
+	 */
+	ata_port_for_each_link(link, ap) {
+		ata_link_for_each_dev(dev, link) {
+			if (ata_dev_enabled(dev) && !dev->sdev)
+				goto exit_loop;
+		}
+	}
+ exit_loop:
+	if (!link)
+		return;
+
+	/* we're missing some SCSI devices */
+	if (sync) {
+		/* If caller requested synchrnous scan && we've made
+		 * any progress, sleep briefly and repeat.
+		 */
+		if (dev != last_failed_dev) {
+			msleep(100);
+			last_failed_dev = dev;
+			goto repeat;
+		}
+
+		/* We might be failing to detect boot device, give it
+		 * a few more chances.
+		 */
+		if (--tries) {
+			msleep(100);
+			goto repeat;
+		}
+
+		ata_port_printk(ap, KERN_ERR, "WARNING: synchronous SCSI scan "
+				"failed without making any progress,\n"
+				"                  switching to async\n");
+	}
+
+	queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
+			   round_jiffies_relative(HZ));
 }
 
 /**
@@ -3005,7 +3171,7 @@
  */
 static void ata_scsi_remove_dev(struct ata_device *dev)
 {
-	struct ata_port *ap = dev->ap;
+	struct ata_port *ap = dev->link->ap;
 	struct scsi_device *sdev;
 	unsigned long flags;
 
@@ -3052,6 +3218,43 @@
 	}
 }
 
+static void ata_scsi_handle_link_detach(struct ata_link *link)
+{
+	struct ata_port *ap = link->ap;
+	struct ata_device *dev;
+
+	ata_link_for_each_dev(dev, link) {
+		unsigned long flags;
+
+		if (!(dev->flags & ATA_DFLAG_DETACHED))
+			continue;
+
+		spin_lock_irqsave(ap->lock, flags);
+		dev->flags &= ~ATA_DFLAG_DETACHED;
+		spin_unlock_irqrestore(ap->lock, flags);
+
+		ata_scsi_remove_dev(dev);
+	}
+}
+
+/**
+ *	ata_scsi_media_change_notify - send media change event
+ *	@atadev: Pointer to the disk device with media change event
+ *
+ *	Tell the block layer to send a media change notification
+ *	event.
+ *
+ * 	LOCKING:
+ * 	spin_lock_irqsave(host lock)
+ */
+void ata_scsi_media_change_notify(struct ata_device *dev)
+{
+#ifdef OTHER_AN_PATCHES_HAVE_BEEN_APPLIED
+	if (dev->sdev)
+		scsi_device_event_notify(dev->sdev, SDEV_MEDIA_CHANGE);
+#endif
+}
+
 /**
  *	ata_scsi_hotplug - SCSI part of hotplug
  *	@work: Pointer to ATA port to perform SCSI hotplug on
@@ -3077,36 +3280,17 @@
 
 	DPRINTK("ENTER\n");
 
-	/* unplug detached devices */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
-		unsigned long flags;
-
-		if (!(dev->flags & ATA_DFLAG_DETACHED))
-			continue;
-
-		spin_lock_irqsave(ap->lock, flags);
-		dev->flags &= ~ATA_DFLAG_DETACHED;
-		spin_unlock_irqrestore(ap->lock, flags);
-
-		ata_scsi_remove_dev(dev);
-	}
+	/* Unplug detached devices.  We cannot use link iterator here
+	 * because PMP links have to be scanned even if PMP is
+	 * currently not attached.  Iterate manually.
+	 */
+	ata_scsi_handle_link_detach(&ap->link);
+	if (ap->pmp_link)
+		for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
+			ata_scsi_handle_link_detach(&ap->pmp_link[i]);
 
 	/* scan for new ones */
-	ata_scsi_scan_host(ap);
-
-	/* If we scanned while EH was in progress, scan would have
-	 * failed silently.  Requeue if there are enabled but
-	 * unattached devices.
-	 */
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
-		if (ata_dev_enabled(dev) && !dev->sdev) {
-			queue_delayed_work(ata_aux_wq, &ap->hotplug_task,
-				round_jiffies_relative(HZ));
-			break;
-		}
-	}
+	ata_scsi_scan_host(ap, 0);
 
 	DPRINTK("EXIT\n");
 }
@@ -3132,27 +3316,42 @@
 {
 	struct ata_port *ap = ata_shost_to_port(shost);
 	unsigned long flags;
-	int rc = 0;
+	int devno, rc = 0;
 
 	if (!ap->ops->error_handler)
 		return -EOPNOTSUPP;
 
-	if ((channel != SCAN_WILD_CARD && channel != 0) ||
-	    (lun != SCAN_WILD_CARD && lun != 0))
+	if (lun != SCAN_WILD_CARD && lun)
 		return -EINVAL;
 
+	if (ap->nr_pmp_links == 0) {
+		if (channel != SCAN_WILD_CARD && channel)
+			return -EINVAL;
+		devno = id;
+	} else {
+		if (id != SCAN_WILD_CARD && id)
+			return -EINVAL;
+		devno = channel;
+	}
+
 	spin_lock_irqsave(ap->lock, flags);
 
-	if (id == SCAN_WILD_CARD) {
-		ap->eh_info.probe_mask |= (1 << ATA_MAX_DEVICES) - 1;
-		ap->eh_info.action |= ATA_EH_SOFTRESET;
+	if (devno == SCAN_WILD_CARD) {
+		struct ata_link *link;
+
+		ata_port_for_each_link(link, ap) {
+			struct ata_eh_info *ehi = &link->eh_info;
+			ehi->probe_mask |= (1 << ata_link_max_devices(link)) - 1;
+			ehi->action |= ATA_EH_SOFTRESET;
+		}
 	} else {
-		struct ata_device *dev = ata_find_dev(ap, id);
+		struct ata_device *dev = ata_find_dev(ap, devno);
 
 		if (dev) {
-			ap->eh_info.probe_mask |= 1 << dev->devno;
-			ap->eh_info.action |= ATA_EH_SOFTRESET;
-			ap->eh_info.flags |= ATA_EHI_RESUME_LINK;
+			struct ata_eh_info *ehi = &dev->link->eh_info;
+			ehi->probe_mask |= 1 << dev->devno;
+			ehi->action |= ATA_EH_SOFTRESET;
+			ehi->flags |= ATA_EHI_RESUME_LINK;
 		} else
 			rc = -EINVAL;
 	}
@@ -3183,24 +3382,26 @@
 {
 	struct ata_port *ap =
 		container_of(work, struct ata_port, scsi_rescan_task);
+	struct ata_link *link;
+	struct ata_device *dev;
 	unsigned long flags;
-	unsigned int i;
 
 	spin_lock_irqsave(ap->lock, flags);
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
-		struct scsi_device *sdev = dev->sdev;
+	ata_port_for_each_link(link, ap) {
+		ata_link_for_each_dev(dev, link) {
+			struct scsi_device *sdev = dev->sdev;
 
-		if (!ata_dev_enabled(dev) || !sdev)
-			continue;
-		if (scsi_device_get(sdev))
-			continue;
+			if (!ata_dev_enabled(dev) || !sdev)
+				continue;
+			if (scsi_device_get(sdev))
+				continue;
 
-		spin_unlock_irqrestore(ap->lock, flags);
-		scsi_rescan_device(&(sdev->sdev_gendev));
-		scsi_device_put(sdev);
-		spin_lock_irqsave(ap->lock, flags);
+			spin_unlock_irqrestore(ap->lock, flags);
+			scsi_rescan_device(&(sdev->sdev_gendev));
+			scsi_device_put(sdev);
+			spin_lock_irqsave(ap->lock, flags);
+		}
 	}
 
 	spin_unlock_irqrestore(ap->lock, flags);
@@ -3328,7 +3529,7 @@
 int ata_sas_slave_configure(struct scsi_device *sdev, struct ata_port *ap)
 {
 	ata_scsi_sdev_config(sdev);
-	ata_scsi_dev_config(sdev, ap->device);
+	ata_scsi_dev_config(sdev, ap->link.device);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(ata_sas_slave_configure);
@@ -3351,8 +3552,8 @@
 
 	ata_scsi_dump_cdb(ap, cmd);
 
-	if (likely(ata_scsi_dev_enabled(ap->device)))
-		rc = __ata_scsi_queuecmd(cmd, done, ap->device);
+	if (likely(ata_scsi_dev_enabled(ap->link.device)))
+		rc = __ata_scsi_queuecmd(cmd, done, ap->link.device);
 	else {
 		cmd->result = (DID_BAD_TARGET << 16);
 		done(cmd);
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index ca7d224..026439e 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -1,5 +1,5 @@
 /*
- *  libata-bmdma.c - helper library for PCI IDE BMDMA
+ *  libata-sff.c - helper library for PCI IDE BMDMA
  *
  *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
  *    		    Please ALWAYS copy linux-ide@vger.kernel.org
@@ -64,46 +64,6 @@
 	return tmp;
 }
 
-u8 ata_dummy_irq_on (struct ata_port *ap) 	{ return 0; }
-
-/**
- *	ata_irq_ack - Acknowledge a device interrupt.
- *	@ap: Port on which interrupts are enabled.
- *
- *	Wait up to 10 ms for legacy IDE device to become idle (BUSY
- *	or BUSY+DRQ clear).  Obtain dma status and port status from
- *	device.  Clear the interrupt.  Return port status.
- *
- *	LOCKING:
- */
-
-u8 ata_irq_ack(struct ata_port *ap, unsigned int chk_drq)
-{
-	unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
-	u8 host_stat = 0, post_stat = 0, status;
-
-	status = ata_busy_wait(ap, bits, 1000);
-	if (status & bits)
-		if (ata_msg_err(ap))
-			printk(KERN_ERR "abnormal status 0x%X\n", status);
-
-	if (ap->ioaddr.bmdma_addr) {
-		/* get controller status; clear intr, err bits */
-		host_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-		iowrite8(host_stat | ATA_DMA_INTR | ATA_DMA_ERR,
-			 ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-
-		post_stat = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
-	}
-	if (ata_msg_intr(ap))
-		printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
-			__FUNCTION__,
-			host_stat, post_stat, status);
-	return status;
-}
-
-u8 ata_dummy_irq_ack(struct ata_port *ap, unsigned int chk_drq) { return 0; }
-
 /**
  *	ata_tf_load - send taskfile registers to host controller
  *	@ap: Port to which output is sent
@@ -211,6 +171,8 @@
 		tf->hob_lbal = ioread8(ioaddr->lbal_addr);
 		tf->hob_lbam = ioread8(ioaddr->lbam_addr);
 		tf->hob_lbah = ioread8(ioaddr->lbah_addr);
+		iowrite8(tf->ctl, ioaddr->ctl_addr);
+		ap->last_ctl = tf->ctl;
 	}
 }
 
@@ -295,7 +257,7 @@
 	dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
 	iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
 
-	/* Strictly, one may wish to issue a readb() here, to
+	/* Strictly, one may wish to issue an ioread8() here, to
 	 * flush the mmio write.  However, control also passes
 	 * to the hardware at this point, and it will interrupt
 	 * us when we are to resume control.  So, in effect,
@@ -305,6 +267,9 @@
 	 * is expected, so I think it is best to not add a readb()
 	 * without first all the MMIO ATA cards/mobos.
 	 * Or maybe I'm just being paranoid.
+	 *
+	 * FIXME: The posting of this write means I/O starts are
+	 * unneccessarily delayed for MMIO
 	 */
 }
 
@@ -440,7 +405,7 @@
 	unsigned long flags;
 	int thaw = 0;
 
-	qc = __ata_qc_from_tag(ap, ap->active_tag);
+	qc = __ata_qc_from_tag(ap, ap->link.active_tag);
 	if (qc && !(qc->flags & ATA_QCFLAG_FAILED))
 		qc = NULL;
 
@@ -495,7 +460,7 @@
 	ata_reset_fn_t hardreset;
 
 	hardreset = NULL;
-	if (sata_scr_valid(ap))
+	if (sata_scr_valid(&ap->link))
 		hardreset = sata_std_hardreset;
 
 	ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, hardreset,
@@ -571,6 +536,10 @@
 	struct pci_dev *pdev = to_pci_dev(gdev);
 	int i, rc;
 
+	/* No BAR4 allocation: No DMA */
+	if (pci_resource_start(pdev, 4) == 0)
+		return 0;
+
 	/* TODO: If we get no DMA mask we should fall back to PIO */
 	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
 	if (rc)
@@ -598,6 +567,9 @@
 		if ((!(ap->flags & ATA_FLAG_IGN_SIMPLEX)) &&
 		    (ioread8(bmdma + 2) & 0x80))
 			host->flags |= ATA_HOST_SIMPLEX;
+
+		ata_port_desc(ap, "bmdma 0x%llx",
+			(unsigned long long)pci_resource_start(pdev, 4) + 8 * i);
 	}
 
 	return 0;
@@ -665,6 +637,10 @@
 			((unsigned long)iomap[base + 1] | ATA_PCI_CTL_OFS);
 		ata_std_ports(&ap->ioaddr);
 
+		ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
+			(unsigned long long)pci_resource_start(pdev, base),
+			(unsigned long long)pci_resource_start(pdev, base + 1));
+
 		mask |= 1 << i;
 	}
 
@@ -835,24 +811,30 @@
 				      IRQF_SHARED, DRV_NAME, host);
 		if (rc)
 			goto err_out;
-		host->irq = pdev->irq;
+
+		ata_port_desc(host->ports[0], "irq %d", pdev->irq);
+		ata_port_desc(host->ports[1], "irq %d", pdev->irq);
 	} else {
 		if (!ata_port_is_dummy(host->ports[0])) {
-			host->irq = ATA_PRIMARY_IRQ(pdev);
-			rc = devm_request_irq(dev, host->irq,
+			rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev),
 					      pi->port_ops->irq_handler,
 					      IRQF_SHARED, DRV_NAME, host);
 			if (rc)
 				goto err_out;
+
+			ata_port_desc(host->ports[0], "irq %d",
+				      ATA_PRIMARY_IRQ(pdev));
 		}
 
 		if (!ata_port_is_dummy(host->ports[1])) {
-			host->irq2 = ATA_SECONDARY_IRQ(pdev);
-			rc = devm_request_irq(dev, host->irq2,
+			rc = devm_request_irq(dev, ATA_SECONDARY_IRQ(pdev),
 					      pi->port_ops->irq_handler,
 					      IRQF_SHARED, DRV_NAME, host);
 			if (rc)
 				goto err_out;
+
+			ata_port_desc(host->ports[1], "irq %d",
+				      ATA_SECONDARY_IRQ(pdev));
 		}
 	}
 
@@ -900,7 +882,7 @@
 	/* Filter out DMA modes if the device has been configured by
 	   the BIOS as PIO only */
 
-	if (adev->ap->ioaddr.bmdma_addr == 0)
+	if (adev->link->ap->ioaddr.bmdma_addr == 0)
 		xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
 	return xfer_mask;
 }
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index ba17fc5..90df58a 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -29,6 +29,7 @@
 #define __LIBATA_H__
 
 #define DRV_NAME	"libata"
+#define DRV_VERSION	"3.00"	/* must be exactly four chars */
 
 struct ata_scsi_args {
 	struct ata_device	*dev;
@@ -56,6 +57,7 @@
 extern struct workqueue_struct *ata_aux_wq;
 extern int atapi_enabled;
 extern int atapi_dmadir;
+extern int atapi_passthru16;
 extern int libata_fua;
 extern int libata_noacpi;
 extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
@@ -67,21 +69,23 @@
 extern void ata_port_flush_task(struct ata_port *ap);
 extern unsigned ata_exec_internal(struct ata_device *dev,
 				  struct ata_taskfile *tf, const u8 *cdb,
-				  int dma_dir, void *buf, unsigned int buflen);
+				  int dma_dir, void *buf, unsigned int buflen,
+				  unsigned long timeout);
 extern unsigned ata_exec_internal_sg(struct ata_device *dev,
 				     struct ata_taskfile *tf, const u8 *cdb,
 				     int dma_dir, struct scatterlist *sg,
-				     unsigned int n_elem);
+				     unsigned int n_elem, unsigned long timeout);
 extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
 extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
 			   unsigned int flags, u16 *id);
 extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags);
-extern int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags);
+extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
+			      unsigned int readid_flags);
 extern int ata_dev_configure(struct ata_device *dev);
-extern int sata_down_spd_limit(struct ata_port *ap);
-extern int sata_set_spd_needed(struct ata_port *ap);
+extern int sata_down_spd_limit(struct ata_link *link);
+extern int sata_set_spd_needed(struct ata_link *link);
 extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
-extern int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev);
+extern int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
 extern void ata_sg_clean(struct ata_queued_cmd *qc);
 extern void ata_qc_free(struct ata_queued_cmd *qc);
 extern void ata_qc_issue(struct ata_queued_cmd *qc);
@@ -92,17 +96,21 @@
 extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
 extern int ata_flush_cache(struct ata_device *dev);
 extern void ata_dev_init(struct ata_device *dev);
+extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp);
+extern int sata_link_init_spd(struct ata_link *link);
 extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
 extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
 extern struct ata_port *ata_port_alloc(struct ata_host *host);
 
 /* libata-acpi.c */
 #ifdef CONFIG_ATA_ACPI
+extern void ata_acpi_associate_sata_port(struct ata_port *ap);
 extern void ata_acpi_associate(struct ata_host *host);
 extern int ata_acpi_on_suspend(struct ata_port *ap);
 extern void ata_acpi_on_resume(struct ata_port *ap);
 extern int ata_acpi_on_devcfg(struct ata_device *adev);
 #else
+static inline void ata_acpi_associate_sata_port(struct ata_port *ap) { }
 static inline void ata_acpi_associate(struct ata_host *host) { }
 static inline int ata_acpi_on_suspend(struct ata_port *ap) { return 0; }
 static inline void ata_acpi_on_resume(struct ata_port *ap) { }
@@ -112,8 +120,9 @@
 /* libata-scsi.c */
 extern int ata_scsi_add_hosts(struct ata_host *host,
 			      struct scsi_host_template *sht);
-extern void ata_scsi_scan_host(struct ata_port *ap);
+extern void ata_scsi_scan_host(struct ata_port *ap, int sync);
 extern int ata_scsi_offline_dev(struct ata_device *dev);
+extern void ata_scsi_media_change_notify(struct ata_device *dev);
 extern void ata_scsi_hotplug(struct work_struct *work);
 extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
 			       unsigned int buflen);
@@ -147,11 +156,32 @@
 extern void ata_scsi_dev_rescan(struct work_struct *work);
 extern int ata_bus_probe(struct ata_port *ap);
 
+/* libata-pmp.c */
+extern int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *val);
+extern int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val);
+extern int sata_pmp_attach(struct ata_device *dev);
+
 /* libata-eh.c */
 extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
 extern void ata_scsi_error(struct Scsi_Host *host);
 extern void ata_port_wait_eh(struct ata_port *ap);
+extern void ata_eh_fastdrain_timerfn(unsigned long arg);
 extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
+extern void ata_eh_detach_dev(struct ata_device *dev);
+extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
+			       unsigned int action);
+extern void ata_eh_done(struct ata_link *link, struct ata_device *dev,
+			unsigned int action);
+extern void ata_eh_autopsy(struct ata_port *ap);
+extern void ata_eh_report(struct ata_port *ap);
+extern int ata_eh_reset(struct ata_link *link, int classify,
+			ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+			ata_reset_fn_t hardreset, ata_postreset_fn_t postreset);
+extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+			  ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+			  ata_postreset_fn_t postreset,
+			  struct ata_link **r_failed_disk);
+extern void ata_eh_finish(struct ata_port *ap);
 
 /* libata-sff.c */
 extern u8 ata_irq_on(struct ata_port *ap);
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c
new file mode 100644
index 0000000..5d3920f
--- /dev/null
+++ b/drivers/ata/pata_acpi.c
@@ -0,0 +1,395 @@
+/*
+ *	ACPI PATA driver
+ *
+ *	(c) 2007 Red Hat  <alan@redhat.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acnames.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+#include <acpi/acexcep.h>
+#include <acpi/acmacros.h>
+#include <acpi/actypes.h>
+
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME	"pata_acpi"
+#define DRV_VERSION	"0.2.3"
+
+struct pata_acpi {
+	struct ata_acpi_gtm gtm;
+	void *last;
+	unsigned long mask[2];
+};
+
+/**
+ *	pacpi_pre_reset	-	check for 40/80 pin
+ *	@ap: Port
+ *	@deadline: deadline jiffies for the operation
+ *
+ *	Perform the PATA port setup we need.
+ */
+
+static int pacpi_pre_reset(struct ata_link *link, unsigned long deadline)
+{
+	struct ata_port *ap = link->ap;
+	struct pata_acpi *acpi = ap->private_data;
+	if (ap->acpi_handle == NULL || ata_acpi_gtm(ap, &acpi->gtm) < 0)
+		return -ENODEV;
+
+	return ata_std_prereset(link, deadline);
+}
+
+/**
+ *	pacpi_cable_detect	-	cable type detection
+ *	@ap: port to detect
+ *
+ *	Perform device specific cable detection
+ */
+
+static int pacpi_cable_detect(struct ata_port *ap)
+{
+	struct pata_acpi *acpi = ap->private_data;
+
+	if ((acpi->mask[0] | acpi->mask[1]) & (0xF8 << ATA_SHIFT_UDMA))
+		return ATA_CBL_PATA80;
+	else
+		return ATA_CBL_PATA40;
+}
+
+/**
+ *	pacpi_error_handler - Setup and error handler
+ *	@ap: Port to handle
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ */
+
+static void pacpi_error_handler(struct ata_port *ap)
+{
+	return ata_bmdma_drive_eh(ap, pacpi_pre_reset, ata_std_softreset,
+				  NULL, ata_std_postreset);
+}
+
+/* Welcome to ACPI, bring a bucket */
+static const unsigned int pio_cycle[7] = {
+	600, 383, 240, 180, 120, 100, 80
+};
+static const unsigned int mwdma_cycle[5] = {
+	480, 150, 120, 100, 80
+};
+static const unsigned int udma_cycle[7] = {
+	120, 80, 60, 45, 30, 20, 15
+};
+
+/**
+ *	pacpi_discover_modes	-	filter non ACPI modes
+ *	@adev: ATA device
+ *	@mask: proposed modes
+ *
+ *	Try the modes available and see which ones the ACPI method will
+ *	set up sensibly. From this we get a mask of ACPI modes we can use
+ */
+
+static unsigned long pacpi_discover_modes(struct ata_port *ap, struct ata_device *adev)
+{
+	int unit = adev->devno;
+	struct pata_acpi *acpi = ap->private_data;
+	int i;
+	u32 t;
+	unsigned long mask = (0x7f << ATA_SHIFT_UDMA) | (0x7 << ATA_SHIFT_MWDMA) | (0x1F << ATA_SHIFT_PIO);
+
+	struct ata_acpi_gtm probe;
+
+	probe = acpi->gtm;
+
+	/* We always use the 0 slot for crap hardware */
+	if (!(probe.flags & 0x10))
+		unit = 0;
+
+	ata_acpi_gtm(ap, &probe);
+
+	/* Start by scanning for PIO modes */
+	for (i = 0; i < 7; i++) {
+		t = probe.drive[unit].pio;
+		if (t <= pio_cycle[i]) {
+			mask |= (2 << (ATA_SHIFT_PIO + i)) - 1;
+			break;
+		}
+	}
+
+	/* See if we have MWDMA or UDMA data. We don't bother with MWDMA
+	   if UDMA is availabe as this means the BIOS set UDMA and our
+	   error changedown if it works is UDMA to PIO anyway */
+	if (probe.flags & (1 << (2 * unit))) {
+		/* MWDMA */
+		for (i = 0; i < 5; i++) {
+			t = probe.drive[unit].dma;
+			if (t <= mwdma_cycle[i]) {
+				mask |= (2 << (ATA_SHIFT_MWDMA + i)) - 1;
+				break;
+			}
+		}
+	} else {
+		/* UDMA */
+		for (i = 0; i < 7; i++) {
+			t = probe.drive[unit].dma;
+			if (t <= udma_cycle[i]) {
+				mask |= (2 << (ATA_SHIFT_UDMA + i)) - 1;
+				break;
+			}
+		}
+	}
+	if (mask & (0xF8 << ATA_SHIFT_UDMA))
+		ap->cbl = ATA_CBL_PATA80;
+	return mask;
+}
+
+/**
+ *	pacpi_mode_filter	-	mode filter for ACPI
+ *	@adev: device
+ *	@mask: mask of valid modes
+ *
+ *	Filter the valid mode list according to our own specific rules, in
+ *	this case the list of discovered valid modes obtained by ACPI probing
+ */
+
+static unsigned long pacpi_mode_filter(struct ata_device *adev, unsigned long mask)
+{
+	struct pata_acpi *acpi = adev->link->ap->private_data;
+	return ata_pci_default_filter(adev, mask & acpi->mask[adev->devno]);
+}
+
+/**
+ *	pacpi_set_piomode	-	set initial PIO mode data
+ *	@ap: ATA interface
+ *	@adev: ATA device
+ */
+
+static void pacpi_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+	int unit = adev->devno;
+	struct pata_acpi *acpi = ap->private_data;
+
+	if(!(acpi->gtm.flags & 0x10))
+		unit = 0;
+
+	/* Now stuff the nS values into the structure */
+	acpi->gtm.drive[unit].pio = pio_cycle[adev->pio_mode - XFER_PIO_0];
+	ata_acpi_stm(ap, &acpi->gtm);
+	/* See what mode we actually got */
+	ata_acpi_gtm(ap, &acpi->gtm);
+}
+
+/**
+ *	pacpi_set_dmamode	-	set initial DMA mode data
+ *	@ap: ATA interface
+ *	@adev: ATA device
+ */
+
+static void pacpi_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+	int unit = adev->devno;
+	struct pata_acpi *acpi = ap->private_data;
+
+	if(!(acpi->gtm.flags & 0x10))
+		unit = 0;
+
+	/* Now stuff the nS values into the structure */
+	if (adev->dma_mode >= XFER_UDMA_0) {
+		acpi->gtm.drive[unit].dma = udma_cycle[adev->dma_mode - XFER_UDMA_0];
+		acpi->gtm.flags |= (1 << (2 * unit));
+	} else {
+		acpi->gtm.drive[unit].dma = mwdma_cycle[adev->dma_mode - XFER_MW_DMA_0];
+		acpi->gtm.flags &= ~(1 << (2 * unit));
+	}
+	ata_acpi_stm(ap, &acpi->gtm);
+	/* See what mode we actually got */
+	ata_acpi_gtm(ap, &acpi->gtm);
+}
+
+/**
+ *	pacpi_qc_issue_prot	-	command issue
+ *	@qc: command pending
+ *
+ *	Called when the libata layer is about to issue a command. We wrap
+ *	this interface so that we can load the correct ATA timings if
+ *	neccessary.
+ */
+
+static unsigned int pacpi_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct ata_device *adev = qc->dev;
+	struct pata_acpi *acpi = ap->private_data;
+
+	if (acpi->gtm.flags & 0x10)
+		return ata_qc_issue_prot(qc);
+
+	if (adev != acpi->last) {
+		pacpi_set_piomode(ap, adev);
+		if (adev->dma_mode)
+			pacpi_set_dmamode(ap, adev);
+		acpi->last = adev;
+	}
+	return ata_qc_issue_prot(qc);
+}
+
+/**
+ *	pacpi_port_start	-	port setup
+ *	@ap: ATA port being set up
+ *
+ *	Use the port_start hook to maintain private control structures
+ */
+
+static int pacpi_port_start(struct ata_port *ap)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+	struct pata_acpi *acpi;
+
+	int ret;
+
+	if (ap->acpi_handle == NULL)
+		return -ENODEV;
+
+	acpi = ap->private_data = devm_kzalloc(&pdev->dev, sizeof(struct pata_acpi), GFP_KERNEL);
+	if (ap->private_data == NULL)
+		return -ENOMEM;
+	acpi->mask[0] = pacpi_discover_modes(ap, &ap->link.device[0]);
+	acpi->mask[1] = pacpi_discover_modes(ap, &ap->link.device[1]);
+	ret = ata_sff_port_start(ap);
+	if (ret < 0)
+		return ret;
+
+	return ret;
+}
+
+static struct scsi_host_template pacpi_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
+	/* Use standard CHS mapping rules */
+	.bios_param		= ata_std_bios_param,
+};
+
+static const struct ata_port_operations pacpi_ops = {
+	.set_piomode		= pacpi_set_piomode,
+	.set_dmamode		= pacpi_set_dmamode,
+	.mode_filter		= pacpi_mode_filter,
+
+	/* Task file is PCI ATA format, use helpers */
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.exec_command		= ata_exec_command,
+	.dev_select		= ata_std_dev_select,
+
+	.freeze			= ata_bmdma_freeze,
+	.thaw			= ata_bmdma_thaw,
+	.error_handler		= pacpi_error_handler,
+	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= pacpi_cable_detect,
+
+	/* BMDMA handling is PCI ATA format, use helpers */
+	.bmdma_setup		= ata_bmdma_setup,
+	.bmdma_start		= ata_bmdma_start,
+	.bmdma_stop		= ata_bmdma_stop,
+	.bmdma_status		= ata_bmdma_status,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= pacpi_qc_issue_prot,
+	.data_xfer		= ata_data_xfer,
+
+	/* Timeout handling */
+	.irq_handler		= ata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
+	.irq_on			= ata_irq_on,
+
+	/* Generic PATA PCI ATA helpers */
+	.port_start		= pacpi_port_start,
+};
+
+
+/**
+ *	pacpi_init_one - Register ACPI ATA PCI device with kernel services
+ *	@pdev: PCI device to register
+ *	@ent: Entry in pacpi_pci_tbl matching with @pdev
+ *
+ *	Called from kernel PCI layer.
+ *
+ *	LOCKING:
+ *	Inherited from PCI layer (may sleep).
+ *
+ *	RETURNS:
+ *	Zero on success, or -ERRNO value.
+ */
+
+static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	static const struct ata_port_info info = {
+		.sht		= &pacpi_sht,
+		.flags		= ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+
+		.pio_mask	= 0x1f,
+		.mwdma_mask	= 0x07,
+		.udma_mask 	= 0x7f,
+
+		.port_ops	= &pacpi_ops,
+	};
+	const struct ata_port_info *ppi[] = { &info, NULL };
+	return ata_pci_init_one(pdev, ppi);
+}
+
+static const struct pci_device_id pacpi_pci_tbl[] = {
+	{ PCI_ANY_ID,		PCI_ANY_ID,			   PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 1},
+	{ }	/* terminate list */
+};
+
+static struct pci_driver pacpi_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= pacpi_pci_tbl,
+	.probe			= pacpi_init_one,
+	.remove			= ata_pci_remove_one,
+	.suspend		= ata_pci_device_suspend,
+	.resume			= ata_pci_device_resume,
+};
+
+static int __init pacpi_init(void)
+{
+	return pci_register_driver(&pacpi_pci_driver);
+}
+
+static void __exit pacpi_exit(void)
+{
+	pci_unregister_driver(&pacpi_pci_driver);
+}
+
+module_init(pacpi_init);
+module_exit(pacpi_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for ATA in ACPI mode");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pacpi_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index 0104367..364534e 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -34,18 +34,25 @@
 #include <linux/dmi.h>
 
 #define DRV_NAME "pata_ali"
-#define DRV_VERSION "0.7.4"
+#define DRV_VERSION "0.7.5"
 
 /*
  *	Cable special cases
  */
 
-static struct dmi_system_id cable_dmi_table[] = {
+static const struct dmi_system_id cable_dmi_table[] = {
 	{
 		.ident = "HP Pavilion N5430",
 		.matches = {
 			DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
-			DMI_MATCH(DMI_BOARD_NAME, "OmniBook N32N-736"),
+			DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"),
+		},
+	},
+	{
+		.ident = "Toshiba Satelite S1800-814",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "S1800-814"),
 		},
 	},
 	{ }
@@ -298,7 +305,6 @@
  */
 
 static struct ata_port_operations ali_early_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= ali_set_piomode,
 	.tf_load	= ata_tf_load,
 	.tf_read	= ata_tf_read,
@@ -320,9 +326,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /*
@@ -330,8 +335,6 @@
  *	detect
  */
 static struct ata_port_operations ali_20_port_ops = {
-	.port_disable	= ata_port_disable,
-
 	.set_piomode	= ali_set_piomode,
 	.set_dmamode	= ali_set_dmamode,
 	.mode_filter	= ali_20_filter,
@@ -362,16 +365,14 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /*
  *	Port operations for DMA capable ALi with cable detect
  */
 static struct ata_port_operations ali_c2_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= ali_set_piomode,
 	.set_dmamode	= ali_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -401,16 +402,14 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /*
  *	Port operations for DMA capable ALi with cable detect and LBA48
  */
 static struct ata_port_operations ali_c5_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= ali_set_piomode,
 	.set_dmamode	= ali_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -439,9 +438,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index b09faca..c5779ad 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -25,7 +25,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_amd"
-#define DRV_VERSION "0.3.8"
+#define DRV_VERSION "0.3.9"
 
 /**
  *	timing_setup		-	shared timing computation and load
@@ -119,27 +119,28 @@
 }
 
 /**
- *	amd_probe_init		-	perform reset handling
- *	@ap: ATA port
+ *	amd_pre_reset		-	perform reset handling
+ *	@link: ATA link
  *	@deadline: deadline jiffies for the operation
  *
  *	Reset sequence checking enable bits to see which ports are
  *	active.
  */
 
-static int amd_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int amd_pre_reset(struct ata_link *link, unsigned long deadline)
 {
 	static const struct pci_bits amd_enable_bits[] = {
 		{ 0x40, 1, 0x02, 0x02 },
 		{ 0x40, 1, 0x01, 0x01 }
 	};
 
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
 	if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no]))
 		return -ENOENT;
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 static void amd_error_handler(struct ata_port *ap)
@@ -221,25 +222,26 @@
 
 /**
  *	nv_probe_init	-	cable detection
- *	@ap: ATA port
+ *	@lin: ATA link
  *
  *	Perform cable detection. The BIOS stores this in PCI config
  *	space for us.
  */
 
-static int nv_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int nv_pre_reset(struct ata_link *link, unsigned long deadline)
 {
 	static const struct pci_bits nv_enable_bits[] = {
 		{ 0x50, 1, 0x02, 0x02 },
 		{ 0x50, 1, 0x01, 0x01 }
 	};
 
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
 	if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no]))
 		return -ENOENT;
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 static void nv_error_handler(struct ata_port *ap)
@@ -268,6 +270,9 @@
  	pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma);
  	if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400)
 		cbl = ATA_CBL_PATA80;
+	/* And a triple check across suspend/resume with ACPI around */
+	if (ata_acpi_cbl_80wire(ap))
+		cbl = ATA_CBL_PATA80;
 	return cbl;
 }
 
@@ -327,7 +332,6 @@
 };
 
 static struct ata_port_operations amd33_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= amd33_set_piomode,
 	.set_dmamode	= amd33_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -356,13 +360,11 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static struct ata_port_operations amd66_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= amd66_set_piomode,
 	.set_dmamode	= amd66_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -391,13 +393,11 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static struct ata_port_operations amd100_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= amd100_set_piomode,
 	.set_dmamode	= amd100_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -426,13 +426,11 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static struct ata_port_operations amd133_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= amd133_set_piomode,
 	.set_dmamode	= amd133_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -461,13 +459,11 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static struct ata_port_operations nv100_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= nv100_set_piomode,
 	.set_dmamode	= nv100_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -496,13 +492,11 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static struct ata_port_operations nv133_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= nv133_set_piomode,
 	.set_dmamode	= nv133_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -531,9 +525,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
index ce589d9..d421831 100644
--- a/drivers/ata/pata_artop.c
+++ b/drivers/ata/pata_artop.c
@@ -2,6 +2,7 @@
  *    pata_artop.c - ARTOP ATA controller driver
  *
  *	(C) 2006 Red Hat <alan@redhat.com>
+ *	(C) 2007 Bartlomiej Zolnierkiewicz
  *
  *    Based in part on drivers/ide/pci/aec62xx.c
  *	Copyright (C) 1999-2002	Andre Hedrick <andre@linux-ide.org>
@@ -28,7 +29,7 @@
 #include <linux/ata.h>
 
 #define DRV_NAME	"pata_artop"
-#define DRV_VERSION	"0.4.3"
+#define DRV_VERSION	"0.4.4"
 
 /*
  *	The ARTOP has 33 Mhz and "over clocked" timing tables. Until we
@@ -39,8 +40,9 @@
 
 static int clock = 0;
 
-static int artop6210_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int artop6210_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	const struct pci_bits artop_enable_bits[] = {
 		{ 0x4AU, 1U, 0x02UL, 0x02UL },	/* port 0 */
@@ -50,7 +52,7 @@
 	if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
 		return -ENOENT;
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -70,27 +72,28 @@
 
 /**
  *	artop6260_pre_reset	-	check for 40/80 pin
- *	@ap: Port
+ *	@link: link
  *	@deadline: deadline jiffies for the operation
  *
  *	The ARTOP hardware reports the cable detect bits in register 0x49.
  *	Nothing complicated needed here.
  */
 
-static int artop6260_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int artop6260_pre_reset(struct ata_link *link, unsigned long deadline)
 {
 	static const struct pci_bits artop_enable_bits[] = {
 		{ 0x4AU, 1U, 0x02UL, 0x02UL },	/* port 0 */
 		{ 0x4AU, 1U, 0x04UL, 0x04UL },	/* port 1 */
 	};
 
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
 	/* Odd numbered device ids are the units with enable bits (the -R cards) */
 	if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
 		return -ENOENT;
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -329,7 +332,6 @@
 };
 
 static const struct ata_port_operations artop6210_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= artop6210_set_piomode,
 	.set_dmamode		= artop6210_set_dmamode,
 	.mode_filter		= ata_pci_default_filter,
@@ -358,13 +360,11 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
-	.port_start		= ata_port_start,
+	.port_start		= ata_sff_port_start,
 };
 
 static const struct ata_port_operations artop6260_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= artop6260_set_piomode,
 	.set_dmamode		= artop6260_set_dmamode,
 
@@ -391,9 +391,8 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
-	.port_start		= ata_port_start,
+	.port_start		= ata_sff_port_start,
 };
 
 
@@ -430,7 +429,7 @@
 		.udma_mask 	= ATA_UDMA4,
 		.port_ops	= &artop6260_ops,
 	};
-	static const struct ata_port_info info_626x_fast = {
+	static const struct ata_port_info info_628x = {
 		.sht		= &artop_sht,
 		.flags		= ATA_FLAG_SLAVE_POSS,
 		.pio_mask	= 0x1f,	/* pio0-4 */
@@ -438,6 +437,14 @@
 		.udma_mask 	= ATA_UDMA5,
 		.port_ops	= &artop6260_ops,
 	};
+	static const struct ata_port_info info_628x_fast = {
+		.sht		= &artop_sht,
+		.flags		= ATA_FLAG_SLAVE_POSS,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask 	= ATA_UDMA6,
+		.port_ops	= &artop6260_ops,
+	};
 	const struct ata_port_info *ppi[] = { NULL, NULL };
 
 	if (!printed_version++)
@@ -455,13 +462,13 @@
 	}
 	else if (id->driver_data == 1)	/* 6260 */
 		ppi[0] = &info_626x;
-	else if (id->driver_data == 2)	{ /* 6260 or 6260 + fast */
+	else if (id->driver_data == 2)	{ /* 6280 or 6280 + fast */
 		unsigned long io = pci_resource_start(pdev, 4);
 		u8 reg;
 
-		ppi[0] = &info_626x;
+		ppi[0] = &info_628x;
 		if (inb(io) & 0x10)
-			ppi[0] = &info_626x_fast;
+			ppi[0] = &info_628x_fast;
 		/* Mac systems come up with some registers not set as we
 		   will need them */
 
diff --git a/drivers/ata/pata_at32.c b/drivers/ata/pata_at32.c
new file mode 100644
index 0000000..bb250a4
--- /dev/null
+++ b/drivers/ata/pata_at32.c
@@ -0,0 +1,441 @@
+/*
+ * AVR32 SMC/CFC PATA Driver
+ *
+ * Copyright (C) 2007 Atmel Norway
+ *
+ * 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.
+ */
+
+#define DEBUG
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/smc.h>
+
+#define DRV_NAME "pata_at32"
+#define DRV_VERSION "0.0.2"
+
+/*
+ * CompactFlash controller memory layout relative to the base address:
+ *
+ *	Attribute memory:  0000 0000 -> 003f ffff
+ *	Common memory:	   0040 0000 -> 007f ffff
+ *	I/O memory:	   0080 0000 -> 00bf ffff
+ *	True IDE Mode:	   00c0 0000 -> 00df ffff
+ *	Alt IDE Mode:	   00e0 0000 -> 00ff ffff
+ *
+ * Only True IDE and Alt True IDE mode are needed for this driver.
+ *
+ *	True IDE mode	  => CS0 = 0, CS1 = 1 (cmd, error, stat, etc)
+ *	Alt True IDE mode => CS0 = 1, CS1 = 0 (ctl, alt_stat)
+ */
+#define CF_IDE_OFFSET	  0x00c00000
+#define CF_ALT_IDE_OFFSET 0x00e00000
+#define CF_RES_SIZE	  2048
+
+/*
+ * Define DEBUG_BUS if you are doing debugging of your own EBI -> PATA
+ * adaptor with a logic analyzer or similar.
+ */
+#undef DEBUG_BUS
+
+/*
+ * ATA PIO modes
+ *
+ *	Name	| Mb/s	| Min cycle time | Mask
+ *	--------+-------+----------------+--------
+ *	Mode 0	| 3.3	| 600 ns	 | 0x01
+ *	Mode 1	| 5.2	| 383 ns	 | 0x03
+ *	Mode 2	| 8.3	| 240 ns	 | 0x07
+ *	Mode 3	| 11.1	| 180 ns	 | 0x0f
+ *	Mode 4	| 16.7	| 120 ns	 | 0x1f
+ */
+#define PIO_MASK (0x1f)
+
+/*
+ * Struct containing private information about device.
+ */
+struct at32_ide_info {
+	unsigned int		irq;
+	struct resource		res_ide;
+	struct resource		res_alt;
+	void __iomem		*ide_addr;
+	void __iomem		*alt_addr;
+	unsigned int		cs;
+	struct smc_config	smc;
+};
+
+/*
+ * Setup SMC for the given ATA timing.
+ */
+static int pata_at32_setup_timing(struct device *dev,
+				  struct at32_ide_info *info,
+				  const struct ata_timing *timing)
+{
+	/* These two values are found through testing */
+	const int min_recover = 25;
+	const int ncs_hold    = 15;
+
+	struct smc_config *smc = &info->smc;
+
+	int active;
+	int recover;
+
+	/* Total cycle time */
+	smc->read_cycle	= timing->cyc8b;
+
+	/* DIOR <= CFIOR timings */
+	smc->nrd_setup = timing->setup;
+	smc->nrd_pulse = timing->act8b;
+
+	/* Compute recover, extend total cycle if needed */
+	active	= smc->nrd_setup + smc->nrd_pulse;
+	recover = smc->read_cycle - active;
+
+	if (recover < min_recover) {
+		smc->read_cycle = active + min_recover;
+		recover = min_recover;
+	}
+
+	/* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */
+	smc->ncs_read_setup  = 0;
+	smc->ncs_read_pulse  = active + ncs_hold;
+
+	/* Write timings same as read timings */
+	smc->write_cycle = smc->read_cycle;
+	smc->nwe_setup = smc->nrd_setup;
+	smc->nwe_pulse = smc->nrd_pulse;
+	smc->ncs_write_setup = smc->ncs_read_setup;
+	smc->ncs_write_pulse = smc->ncs_read_pulse;
+
+	/* Do some debugging output */
+	dev_dbg(dev, "SMC: C=%d S=%d P=%d R=%d NCSS=%d NCSP=%d NCSR=%d\n",
+		smc->read_cycle, smc->nrd_setup, smc->nrd_pulse,
+		recover, smc->ncs_read_setup, smc->ncs_read_pulse,
+		smc->read_cycle - smc->ncs_read_pulse);
+
+	/* Finally, configure the SMC */
+	return smc_set_configuration(info->cs, smc);
+}
+
+/*
+ * Procedures for libATA.
+ */
+static void pata_at32_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+	struct ata_timing timing;
+	struct at32_ide_info *info = ap->host->private_data;
+
+	int ret;
+
+	/* Compute ATA timing */
+	ret = ata_timing_compute(adev, adev->pio_mode, &timing, 1000, 0);
+	if (ret) {
+		dev_warn(ap->dev, "Failed to compute ATA timing %d\n", ret);
+		return;
+	}
+
+	/* Setup SMC to ATA timing */
+	ret = pata_at32_setup_timing(ap->dev, info, &timing);
+	if (ret) {
+		dev_warn(ap->dev, "Failed to setup ATA timing %d\n", ret);
+		return;
+	}
+}
+
+static void pata_at32_irq_clear(struct ata_port *ap)
+{
+	/* No DMA controller yet */
+}
+
+static struct scsi_host_template at32_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
+	.bios_param		= ata_std_bios_param,
+};
+
+static struct ata_port_operations at32_port_ops = {
+	.port_disable		= ata_port_disable,
+	.set_piomode		= pata_at32_set_piomode,
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.exec_command		= ata_exec_command,
+	.check_status		= ata_check_status,
+	.dev_select		= ata_std_dev_select,
+
+	.freeze			= ata_bmdma_freeze,
+	.thaw			= ata_bmdma_thaw,
+	.error_handler		= ata_bmdma_error_handler,
+	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= ata_cable_40wire,
+
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+
+	.data_xfer		= ata_data_xfer,
+
+	.irq_clear		= pata_at32_irq_clear,
+	.irq_on			= ata_irq_on,
+	.irq_ack		= ata_irq_ack,
+
+	.port_start		= ata_sff_port_start,
+};
+
+static int __init pata_at32_init_one(struct device *dev,
+				     struct at32_ide_info *info)
+{
+	struct ata_host *host;
+	struct ata_port *ap;
+
+	host = ata_host_alloc(dev, 1);
+	if (!host)
+		return -ENOMEM;
+
+	ap = host->ports[0];
+
+	/* Setup ATA bindings */
+	ap->ops	     = &at32_port_ops;
+	ap->pio_mask = PIO_MASK;
+	ap->flags    = ATA_FLAG_MMIO | ATA_FLAG_SLAVE_POSS
+		| ATA_FLAG_PIO_POLLING;
+
+	/*
+	 * Since all 8-bit taskfile transfers has to go on the lower
+	 * byte of the data bus and there is a bug in the SMC that
+	 * makes it impossible to alter the bus width during runtime,
+	 * we need to hardwire the address signals as follows:
+	 *
+	 *	A_IDE(2:0) <= A_EBI(3:1)
+	 *
+	 * This makes all addresses on the EBI even, thus all data
+	 * will be on the lower byte of the data bus.  All addresses
+	 * used by libATA need to be altered according to this.
+	 */
+	ap->ioaddr.altstatus_addr = info->alt_addr + (0x06 << 1);
+	ap->ioaddr.ctl_addr	  = info->alt_addr + (0x06 << 1);
+
+	ap->ioaddr.data_addr	  = info->ide_addr + (ATA_REG_DATA << 1);
+	ap->ioaddr.error_addr	  = info->ide_addr + (ATA_REG_ERR << 1);
+	ap->ioaddr.feature_addr	  = info->ide_addr + (ATA_REG_FEATURE << 1);
+	ap->ioaddr.nsect_addr	  = info->ide_addr + (ATA_REG_NSECT << 1);
+	ap->ioaddr.lbal_addr	  = info->ide_addr + (ATA_REG_LBAL << 1);
+	ap->ioaddr.lbam_addr	  = info->ide_addr + (ATA_REG_LBAM << 1);
+	ap->ioaddr.lbah_addr	  = info->ide_addr + (ATA_REG_LBAH << 1);
+	ap->ioaddr.device_addr	  = info->ide_addr + (ATA_REG_DEVICE << 1);
+	ap->ioaddr.status_addr	  = info->ide_addr + (ATA_REG_STATUS << 1);
+	ap->ioaddr.command_addr	  = info->ide_addr + (ATA_REG_CMD << 1);
+
+	/* Set info as private data of ATA host */
+	host->private_data = info;
+
+	/* Register ATA device and return */
+	return ata_host_activate(host, info->irq, ata_interrupt,
+				 IRQF_SHARED | IRQF_TRIGGER_RISING,
+				 &at32_sht);
+}
+
+/*
+ * This function may come in handy for people analyzing their own
+ * EBI -> PATA adaptors.
+ */
+#ifdef DEBUG_BUS
+
+static void __init pata_at32_debug_bus(struct device *dev,
+				       struct at32_ide_info *info)
+{
+	const int d1 = 0xff;
+	const int d2 = 0x00;
+
+	int i;
+
+	/* Write 8-bit values (registers) */
+	iowrite8(d1, info->alt_addr + (0x06 << 1));
+	iowrite8(d2, info->alt_addr + (0x06 << 1));
+
+	for (i = 0; i < 8; i++) {
+		iowrite8(d1, info->ide_addr + (i << 1));
+		iowrite8(d2, info->ide_addr + (i << 1));
+	}
+
+	/* Write 16 bit values (data) */
+	iowrite16(d1,	   info->ide_addr);
+	iowrite16(d1 << 8, info->ide_addr);
+
+	iowrite16(d1,	   info->ide_addr);
+	iowrite16(d1 << 8, info->ide_addr);
+}
+
+#endif
+
+static int __init pata_at32_probe(struct platform_device *pdev)
+{
+	const struct ata_timing initial_timing =
+		{XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0};
+
+	struct device		 *dev = &pdev->dev;
+	struct at32_ide_info	 *info;
+	struct ide_platform_data *board = pdev->dev.platform_data;
+	struct resource		 *res;
+
+	int irq;
+	int ret;
+
+	if (!board)
+		return -ENXIO;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
+
+	/* Retrive IRQ */
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	/* Setup struct containing private infomation */
+	info = kzalloc(sizeof(struct at32_ide_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	memset(info, 0, sizeof(struct at32_ide_info));
+
+	info->irq = irq;
+	info->cs  = board->cs;
+
+	/* Request memory resources */
+	info->res_ide.start = res->start + CF_IDE_OFFSET;
+	info->res_ide.end   = info->res_ide.start + CF_RES_SIZE - 1;
+	info->res_ide.name  = "ide";
+	info->res_ide.flags = IORESOURCE_MEM;
+
+	ret = request_resource(res, &info->res_ide);
+	if (ret)
+		goto err_req_res_ide;
+
+	info->res_alt.start = res->start + CF_ALT_IDE_OFFSET;
+	info->res_alt.end   = info->res_alt.start + CF_RES_SIZE - 1;
+	info->res_alt.name  = "alt";
+	info->res_alt.flags = IORESOURCE_MEM;
+
+	ret = request_resource(res, &info->res_alt);
+	if (ret)
+		goto err_req_res_alt;
+
+	/* Setup non-timing elements of SMC */
+	info->smc.bus_width	 = 2; /* 16 bit data bus */
+	info->smc.nrd_controlled = 1; /* Sample data on rising edge of NRD */
+	info->smc.nwe_controlled = 0; /* Drive data on falling edge of NCS */
+	info->smc.nwait_mode	 = 3; /* NWAIT is in READY mode */
+	info->smc.byte_write	 = 0; /* Byte select access type */
+	info->smc.tdf_mode	 = 0; /* TDF optimization disabled */
+	info->smc.tdf_cycles	 = 0; /* No TDF wait cycles */
+
+	/* Setup ATA timing */
+	ret = pata_at32_setup_timing(dev, info, &initial_timing);
+	if (ret)
+		goto err_setup_timing;
+
+	/* Setup ATA addresses */
+	ret = -ENOMEM;
+	info->ide_addr = devm_ioremap(dev, info->res_ide.start, 16);
+	info->alt_addr = devm_ioremap(dev, info->res_alt.start, 16);
+	if (!info->ide_addr || !info->alt_addr)
+		goto err_ioremap;
+
+#ifdef DEBUG_BUS
+	pata_at32_debug_bus(dev, info);
+#endif
+
+	/* Register ATA device */
+	ret = pata_at32_init_one(dev, info);
+	if (ret)
+		goto err_ata_device;
+
+	return 0;
+
+ err_ata_device:
+ err_ioremap:
+ err_setup_timing:
+	release_resource(&info->res_alt);
+ err_req_res_alt:
+	release_resource(&info->res_ide);
+ err_req_res_ide:
+	kfree(info);
+
+	return ret;
+}
+
+static int __exit pata_at32_remove(struct platform_device *pdev)
+{
+	struct ata_host *host = platform_get_drvdata(pdev);
+	struct at32_ide_info *info;
+
+	if (!host)
+		return 0;
+
+	info = host->private_data;
+	ata_host_detach(host);
+
+	if (!info)
+		return 0;
+
+	release_resource(&info->res_ide);
+	release_resource(&info->res_alt);
+
+	kfree(info);
+
+	return 0;
+}
+
+static struct platform_driver pata_at32_driver = {
+	.remove	       = __exit_p(pata_at32_remove),
+	.driver	       = {
+		.name  = "at32_ide",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init pata_at32_init(void)
+{
+	return platform_driver_probe(&pata_at32_driver, pata_at32_probe);
+}
+
+static void __exit pata_at32_exit(void)
+{
+	platform_driver_unregister(&pata_at32_driver);
+}
+
+module_init(pata_at32_init);
+module_exit(pata_at32_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AVR32 SMC/CFC PATA Driver");
+MODULE_AUTHOR("Kristoffer Nyborg Gregertsen <kngregertsen@norway.atmel.com>");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 80509be..9623f52 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -22,7 +22,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_atiixp"
-#define DRV_VERSION "0.4.5"
+#define DRV_VERSION "0.4.6"
 
 enum {
 	ATIIXP_IDE_PIO_TIMING	= 0x40,
@@ -33,8 +33,9 @@
 	ATIIXP_IDE_UDMA_MODE 	= 0x56
 };
 
-static int atiixp_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int atiixp_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	static const struct pci_bits atiixp_enable_bits[] = {
 		{ 0x48, 1, 0x01, 0x00 },
 		{ 0x48, 1, 0x08, 0x00 }
@@ -44,7 +45,7 @@
 	if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
 		return -ENOENT;
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 static void atiixp_error_handler(struct ata_port *ap)
@@ -172,6 +173,9 @@
  *
  *	When DMA begins we need to ensure that the UDMA control
  *	register for the channel is correctly set.
+ *
+ *	Note: The host lock held by the libata layer protects
+ *	us from two channels both trying to set DMA bits at once
  */
 
 static void atiixp_bmdma_start(struct ata_queued_cmd *qc)
@@ -198,6 +202,9 @@
  *
  *	DMA has completed. Clear the UDMA flag as the next operations will
  *	be PIO ones not UDMA data transfer.
+ *
+ *	Note: The host lock held by the libata layer protects
+ *	us from two channels both trying to set DMA bits at once
  */
 
 static void atiixp_bmdma_stop(struct ata_queued_cmd *qc)
@@ -232,7 +239,6 @@
 };
 
 static struct ata_port_operations atiixp_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= atiixp_set_piomode,
 	.set_dmamode	= atiixp_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -261,9 +267,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
new file mode 100644
index 0000000..747549e
--- /dev/null
+++ b/drivers/ata/pata_bf54x.c
@@ -0,0 +1,1627 @@
+/*
+ * File:         drivers/ata/pata_bf54x.c
+ * Author:       Sonic Zhang <sonic.zhang@analog.com>
+ *
+ * Created:
+ * Description:  PATA Driver for blackfin 54x
+ *
+ * Modified:
+ *               Copyright 2007 Analog Devices Inc.
+ *
+ * Bugs:         Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+#include <asm/dma.h>
+#include <asm/gpio.h>
+#include <asm/portmux.h>
+
+#define DRV_NAME		"pata-bf54x"
+#define DRV_VERSION		"0.9"
+
+#define ATA_REG_CTRL		0x0E
+#define ATA_REG_ALTSTATUS	ATA_REG_CTRL
+
+/* These are the offset of the controller's registers */
+#define ATAPI_OFFSET_CONTROL		0x00
+#define ATAPI_OFFSET_STATUS		0x04
+#define ATAPI_OFFSET_DEV_ADDR		0x08
+#define ATAPI_OFFSET_DEV_TXBUF		0x0c
+#define ATAPI_OFFSET_DEV_RXBUF		0x10
+#define ATAPI_OFFSET_INT_MASK		0x14
+#define ATAPI_OFFSET_INT_STATUS		0x18
+#define ATAPI_OFFSET_XFER_LEN		0x1c
+#define ATAPI_OFFSET_LINE_STATUS	0x20
+#define ATAPI_OFFSET_SM_STATE		0x24
+#define ATAPI_OFFSET_TERMINATE		0x28
+#define ATAPI_OFFSET_PIO_TFRCNT		0x2c
+#define ATAPI_OFFSET_DMA_TFRCNT		0x30
+#define ATAPI_OFFSET_UMAIN_TFRCNT	0x34
+#define ATAPI_OFFSET_UDMAOUT_TFRCNT	0x38
+#define ATAPI_OFFSET_REG_TIM_0		0x40
+#define ATAPI_OFFSET_PIO_TIM_0		0x44
+#define ATAPI_OFFSET_PIO_TIM_1		0x48
+#define ATAPI_OFFSET_MULTI_TIM_0	0x50
+#define ATAPI_OFFSET_MULTI_TIM_1	0x54
+#define ATAPI_OFFSET_MULTI_TIM_2	0x58
+#define ATAPI_OFFSET_ULTRA_TIM_0	0x60
+#define ATAPI_OFFSET_ULTRA_TIM_1	0x64
+#define ATAPI_OFFSET_ULTRA_TIM_2	0x68
+#define ATAPI_OFFSET_ULTRA_TIM_3	0x6c
+
+
+#define ATAPI_GET_CONTROL(base)\
+	bfin_read16(base + ATAPI_OFFSET_CONTROL)
+#define ATAPI_SET_CONTROL(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_CONTROL, val)
+#define ATAPI_GET_STATUS(base)\
+	bfin_read16(base + ATAPI_OFFSET_STATUS)
+#define ATAPI_GET_DEV_ADDR(base)\
+	bfin_read16(base + ATAPI_OFFSET_DEV_ADDR)
+#define ATAPI_SET_DEV_ADDR(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_DEV_ADDR, val)
+#define ATAPI_GET_DEV_TXBUF(base)\
+	bfin_read16(base + ATAPI_OFFSET_DEV_TXBUF)
+#define ATAPI_SET_DEV_TXBUF(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_DEV_TXBUF, val)
+#define ATAPI_GET_DEV_RXBUF(base)\
+	bfin_read16(base + ATAPI_OFFSET_DEV_RXBUF)
+#define ATAPI_SET_DEV_RXBUF(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_DEV_RXBUF, val)
+#define ATAPI_GET_INT_MASK(base)\
+	bfin_read16(base + ATAPI_OFFSET_INT_MASK)
+#define ATAPI_SET_INT_MASK(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_INT_MASK, val)
+#define ATAPI_GET_INT_STATUS(base)\
+	bfin_read16(base + ATAPI_OFFSET_INT_STATUS)
+#define ATAPI_SET_INT_STATUS(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_INT_STATUS, val)
+#define ATAPI_GET_XFER_LEN(base)\
+	bfin_read16(base + ATAPI_OFFSET_XFER_LEN)
+#define ATAPI_SET_XFER_LEN(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_XFER_LEN, val)
+#define ATAPI_GET_LINE_STATUS(base)\
+	bfin_read16(base + ATAPI_OFFSET_LINE_STATUS)
+#define ATAPI_GET_SM_STATE(base)\
+	bfin_read16(base + ATAPI_OFFSET_SM_STATE)
+#define ATAPI_GET_TERMINATE(base)\
+	bfin_read16(base + ATAPI_OFFSET_TERMINATE)
+#define ATAPI_SET_TERMINATE(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_TERMINATE, val)
+#define ATAPI_GET_PIO_TFRCNT(base)\
+	bfin_read16(base + ATAPI_OFFSET_PIO_TFRCNT)
+#define ATAPI_GET_DMA_TFRCNT(base)\
+	bfin_read16(base + ATAPI_OFFSET_DMA_TFRCNT)
+#define ATAPI_GET_UMAIN_TFRCNT(base)\
+	bfin_read16(base + ATAPI_OFFSET_UMAIN_TFRCNT)
+#define ATAPI_GET_UDMAOUT_TFRCNT(base)\
+	bfin_read16(base + ATAPI_OFFSET_UDMAOUT_TFRCNT)
+#define ATAPI_GET_REG_TIM_0(base)\
+	bfin_read16(base + ATAPI_OFFSET_REG_TIM_0)
+#define ATAPI_SET_REG_TIM_0(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_REG_TIM_0, val)
+#define ATAPI_GET_PIO_TIM_0(base)\
+	bfin_read16(base + ATAPI_OFFSET_PIO_TIM_0)
+#define ATAPI_SET_PIO_TIM_0(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_PIO_TIM_0, val)
+#define ATAPI_GET_PIO_TIM_1(base)\
+	bfin_read16(base + ATAPI_OFFSET_PIO_TIM_1)
+#define ATAPI_SET_PIO_TIM_1(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_PIO_TIM_1, val)
+#define ATAPI_GET_MULTI_TIM_0(base)\
+	bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_0)
+#define ATAPI_SET_MULTI_TIM_0(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_0, val)
+#define ATAPI_GET_MULTI_TIM_1(base)\
+	bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_1)
+#define ATAPI_SET_MULTI_TIM_1(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_1, val)
+#define ATAPI_GET_MULTI_TIM_2(base)\
+	bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_2)
+#define ATAPI_SET_MULTI_TIM_2(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_2, val)
+#define ATAPI_GET_ULTRA_TIM_0(base)\
+	bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_0)
+#define ATAPI_SET_ULTRA_TIM_0(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_0, val)
+#define ATAPI_GET_ULTRA_TIM_1(base)\
+	bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_1)
+#define ATAPI_SET_ULTRA_TIM_1(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_1, val)
+#define ATAPI_GET_ULTRA_TIM_2(base)\
+	bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_2)
+#define ATAPI_SET_ULTRA_TIM_2(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_2, val)
+#define ATAPI_GET_ULTRA_TIM_3(base)\
+	bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_3)
+#define ATAPI_SET_ULTRA_TIM_3(base, val)\
+	bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_3, val)
+
+/**
+ * PIO Mode - Frequency compatibility
+ */
+/* mode: 0         1         2         3         4 */
+static const u32 pio_fsclk[] =
+{ 33333333, 33333333, 33333333, 33333333, 33333333 };
+
+/**
+ * MDMA Mode - Frequency compatibility
+ */
+/*               mode:      0         1         2        */
+static const u32 mdma_fsclk[] = { 33333333, 33333333, 33333333 };
+
+/**
+ * UDMA Mode - Frequency compatibility
+ *
+ * UDMA5 - 100 MB/s   - SCLK  = 133 MHz
+ * UDMA4 - 66 MB/s    - SCLK >=  80 MHz
+ * UDMA3 - 44.4 MB/s  - SCLK >=  50 MHz
+ * UDMA2 - 33 MB/s    - SCLK >=  40 MHz
+ */
+/* mode: 0         1         2         3         4          5 */
+static const u32 udma_fsclk[] =
+{ 33333333, 33333333, 40000000, 50000000, 80000000, 133333333 };
+
+/**
+ * Register transfer timing table
+ */
+/*               mode:       0    1    2    3    4    */
+/* Cycle Time                     */
+static const u32 reg_t0min[]   = { 600, 383, 330, 180, 120 };
+/* DIOR/DIOW to end cycle         */
+static const u32 reg_t2min[]   = { 290, 290, 290, 70,  25  };
+/* DIOR/DIOW asserted pulse width */
+static const u32 reg_teocmin[] = { 290, 290, 290, 80,  70  };
+
+/**
+ * PIO timing table
+ */
+/*               mode:       0    1    2    3    4    */
+/* Cycle Time                     */
+static const u32 pio_t0min[]   = { 600, 383, 240, 180, 120 };
+/* Address valid to DIOR/DIORW    */
+static const u32 pio_t1min[]   = { 70,  50,  30,  30,  25  };
+/* DIOR/DIOW to end cycle         */
+static const u32 pio_t2min[]   = { 165, 125, 100, 80,  70  };
+/* DIOR/DIOW asserted pulse width */
+static const u32 pio_teocmin[] = { 165, 125, 100, 70,  25  };
+/* DIOW data hold                 */
+static const u32 pio_t4min[]   = { 30,  20,  15,  10,  10  };
+
+/* ******************************************************************
+ * Multiword DMA timing table
+ * ******************************************************************
+ */
+/*               mode:       0   1    2        */
+/* Cycle Time                     */
+static const u32 mdma_t0min[]  = { 480, 150, 120 };
+/* DIOR/DIOW asserted pulse width */
+static const u32 mdma_tdmin[]  = { 215, 80,  70  };
+/* DMACK to read data released    */
+static const u32 mdma_thmin[]  = { 20,  15,  10  };
+/* DIOR/DIOW to DMACK hold        */
+static const u32 mdma_tjmin[]  = { 20,  5,   5   };
+/* DIOR negated pulse width       */
+static const u32 mdma_tkrmin[] = { 50,  50,  25  };
+/* DIOR negated pulse width       */
+static const u32 mdma_tkwmin[] = { 215, 50,  25  };
+/* CS[1:0] valid to DIOR/DIOW     */
+static const u32 mdma_tmmin[]  = { 50,  30,  25  };
+/* DMACK to read data released    */
+static const u32 mdma_tzmax[]  = { 20,  25,  25  };
+
+/**
+ * Ultra DMA timing table
+ */
+/*               mode:         0    1    2    3    4    5       */
+static const u32 udma_tcycmin[]  = { 112, 73,  54,  39,  25,  17 };
+static const u32 udma_tdvsmin[]  = { 70,  48,  31,  20,  7,   5  };
+static const u32 udma_tenvmax[]  = { 70,  70,  70,  55,  55,  50 };
+static const u32 udma_trpmin[]   = { 160, 125, 100, 100, 100, 85 };
+static const u32 udma_tmin[]     = { 5,   5,   5,   5,   3,   3  };
+
+
+static const u32 udma_tmlimin = 20;
+static const u32 udma_tzahmin = 20;
+static const u32 udma_tenvmin = 20;
+static const u32 udma_tackmin = 20;
+static const u32 udma_tssmin = 50;
+
+/**
+ *
+ *	Function:       num_clocks_min
+ *
+ *	Description:
+ *	calculate number of SCLK cycles to meet minimum timing
+ */
+static unsigned short num_clocks_min(unsigned long tmin,
+				unsigned long fsclk)
+{
+	unsigned long tmp ;
+	unsigned short result;
+
+	tmp = tmin * (fsclk/1000/1000) / 1000;
+	result = (unsigned short)tmp;
+	if ((tmp*1000*1000) < (tmin*(fsclk/1000))) {
+		result++;
+	}
+
+	return result;
+}
+
+/**
+ *	bfin_set_piomode - Initialize host controller PATA PIO timings
+ *	@ap: Port whose timings we are configuring
+ *	@adev: um
+ *
+ *	Set PIO mode for device.
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ */
+
+static void bfin_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+	int mode = adev->pio_mode - XFER_PIO_0;
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+	unsigned int fsclk = get_sclk();
+	unsigned short teoc_reg, t2_reg, teoc_pio;
+	unsigned short t4_reg, t2_pio, t1_reg;
+	unsigned short n0, n6, t6min = 5;
+
+	/* the most restrictive timing value is t6 and tc, the DIOW - data hold
+	* If one SCLK pulse is longer than this minimum value then register
+	* transfers cannot be supported at this frequency.
+	*/
+	n6 = num_clocks_min(t6min, fsclk);
+	if (mode >= 0 && mode <= 4 && n6 >= 1) {
+		pr_debug("set piomode: mode=%d, fsclk=%ud\n", mode, fsclk);
+		/* calculate the timing values for register transfers. */
+		while (mode > 0 && pio_fsclk[mode] > fsclk)
+			mode--;
+
+		/* DIOR/DIOW to end cycle time */
+		t2_reg = num_clocks_min(reg_t2min[mode], fsclk);
+		/* DIOR/DIOW asserted pulse width */
+		teoc_reg = num_clocks_min(reg_teocmin[mode], fsclk);
+		/* Cycle Time */
+		n0  = num_clocks_min(reg_t0min[mode], fsclk);
+
+		/* increase t2 until we meed the minimum cycle length */
+		if (t2_reg + teoc_reg < n0)
+			t2_reg = n0 - teoc_reg;
+
+		/* calculate the timing values for pio transfers. */
+
+		/* DIOR/DIOW to end cycle time */
+		t2_pio = num_clocks_min(pio_t2min[mode], fsclk);
+		/* DIOR/DIOW asserted pulse width */
+		teoc_pio = num_clocks_min(pio_teocmin[mode], fsclk);
+		/* Cycle Time */
+		n0  = num_clocks_min(pio_t0min[mode], fsclk);
+
+		/* increase t2 until we meed the minimum cycle length */
+		if (t2_pio + teoc_pio < n0)
+			t2_pio = n0 - teoc_pio;
+
+		/* Address valid to DIOR/DIORW */
+		t1_reg = num_clocks_min(pio_t1min[mode], fsclk);
+
+		/* DIOW data hold */
+		t4_reg = num_clocks_min(pio_t4min[mode], fsclk);
+
+		ATAPI_SET_REG_TIM_0(base, (teoc_reg<<8 | t2_reg));
+		ATAPI_SET_PIO_TIM_0(base, (t4_reg<<12 | t2_pio<<4 | t1_reg));
+		ATAPI_SET_PIO_TIM_1(base, teoc_pio);
+		if (mode > 2) {
+			ATAPI_SET_CONTROL(base,
+				ATAPI_GET_CONTROL(base) | IORDY_EN);
+		} else {
+			ATAPI_SET_CONTROL(base,
+				ATAPI_GET_CONTROL(base) & ~IORDY_EN);
+		}
+
+		/* Disable host ATAPI PIO interrupts */
+		ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base)
+			& ~(PIO_DONE_MASK | HOST_TERM_XFER_MASK));
+		SSYNC();
+	}
+}
+
+/**
+ *	bfin_set_dmamode - Initialize host controller PATA DMA timings
+ *	@ap: Port whose timings we are configuring
+ *	@adev: um
+ *	@udma: udma mode, 0 - 6
+ *
+ *	Set UDMA mode for device.
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ */
+
+static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+	int mode;
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+	unsigned long fsclk = get_sclk();
+	unsigned short tenv, tack, tcyc_tdvs, tdvs, tmli, tss, trp, tzah;
+	unsigned short tm, td, tkr, tkw, teoc, th;
+	unsigned short n0, nf, tfmin = 5;
+	unsigned short nmin, tcyc;
+
+	mode = adev->dma_mode - XFER_UDMA_0;
+	if (mode >= 0 && mode <= 5) {
+		pr_debug("set udmamode: mode=%d\n", mode);
+		/* the most restrictive timing value is t6 and tc,
+		 * the DIOW - data hold. If one SCLK pulse is longer
+		 * than this minimum value then register
+		 * transfers cannot be supported at this frequency.
+		 */
+		while (mode > 0 && udma_fsclk[mode] > fsclk)
+			mode--;
+
+		nmin = num_clocks_min(udma_tmin[mode], fsclk);
+		if (nmin >= 1) {
+			/* calculate the timing values for Ultra DMA. */
+			tdvs = num_clocks_min(udma_tdvsmin[mode], fsclk);
+			tcyc = num_clocks_min(udma_tcycmin[mode], fsclk);
+			tcyc_tdvs = 2;
+
+			/* increase tcyc - tdvs (tcyc_tdvs) until we meed
+			 * the minimum cycle length
+			 */
+			if (tdvs + tcyc_tdvs < tcyc)
+				tcyc_tdvs = tcyc - tdvs;
+
+			/* Mow assign the values required for the timing
+			 * registers
+			 */
+			if (tcyc_tdvs < 2)
+				tcyc_tdvs = 2;
+
+			if (tdvs < 2)
+				tdvs = 2;
+
+			tack = num_clocks_min(udma_tackmin, fsclk);
+			tss = num_clocks_min(udma_tssmin, fsclk);
+			tmli = num_clocks_min(udma_tmlimin, fsclk);
+			tzah = num_clocks_min(udma_tzahmin, fsclk);
+			trp = num_clocks_min(udma_trpmin[mode], fsclk);
+			tenv = num_clocks_min(udma_tenvmin, fsclk);
+			if (tenv <= udma_tenvmax[mode]) {
+				ATAPI_SET_ULTRA_TIM_0(base, (tenv<<8 | tack));
+				ATAPI_SET_ULTRA_TIM_1(base,
+					(tcyc_tdvs<<8 | tdvs));
+				ATAPI_SET_ULTRA_TIM_2(base, (tmli<<8 | tss));
+				ATAPI_SET_ULTRA_TIM_3(base, (trp<<8 | tzah));
+
+				/* Enable host ATAPI Untra DMA interrupts */
+				ATAPI_SET_INT_MASK(base,
+					ATAPI_GET_INT_MASK(base)
+					| UDMAIN_DONE_MASK
+					| UDMAOUT_DONE_MASK
+					| UDMAIN_TERM_MASK
+					| UDMAOUT_TERM_MASK);
+			}
+		}
+	}
+
+	mode = adev->dma_mode - XFER_MW_DMA_0;
+	if (mode >= 0 && mode <= 2) {
+		pr_debug("set mdmamode: mode=%d\n", mode);
+		/* the most restrictive timing value is tf, the DMACK to
+		 * read data released. If one SCLK pulse is longer than
+		 * this maximum value then the MDMA mode
+		 * cannot be supported at this frequency.
+		 */
+		while (mode > 0 && mdma_fsclk[mode] > fsclk)
+			mode--;
+
+		nf = num_clocks_min(tfmin, fsclk);
+		if (nf >= 1) {
+			/* calculate the timing values for Multi-word DMA. */
+
+			/* DIOR/DIOW asserted pulse width */
+			td = num_clocks_min(mdma_tdmin[mode], fsclk);
+
+			/* DIOR negated pulse width */
+			tkw = num_clocks_min(mdma_tkwmin[mode], fsclk);
+
+			/* Cycle Time */
+			n0  = num_clocks_min(mdma_t0min[mode], fsclk);
+
+			/* increase tk until we meed the minimum cycle length */
+			if (tkw + td < n0)
+				tkw = n0 - td;
+
+			/* DIOR negated pulse width - read */
+			tkr = num_clocks_min(mdma_tkrmin[mode], fsclk);
+			/* CS{1:0] valid to DIOR/DIOW */
+			tm = num_clocks_min(mdma_tmmin[mode], fsclk);
+			/* DIOR/DIOW to DMACK hold */
+			teoc = num_clocks_min(mdma_tjmin[mode], fsclk);
+			/* DIOW Data hold */
+			th = num_clocks_min(mdma_thmin[mode], fsclk);
+
+			ATAPI_SET_MULTI_TIM_0(base, (tm<<8 | td));
+			ATAPI_SET_MULTI_TIM_1(base, (tkr<<8 | tkw));
+			ATAPI_SET_MULTI_TIM_2(base, (teoc<<8 | th));
+
+			/* Enable host ATAPI Multi DMA interrupts */
+			ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base)
+				| MULTI_DONE_MASK | MULTI_TERM_MASK);
+			SSYNC();
+		}
+	}
+	return;
+}
+
+/**
+ *
+ *    Function:       wait_complete
+ *
+ *    Description:    Waits the interrupt from device
+ *
+ */
+static inline void wait_complete(void __iomem *base, unsigned short mask)
+{
+	unsigned short status;
+	unsigned int i = 0;
+
+#define PATA_BF54X_WAIT_TIMEOUT		10000
+
+	for (i = 0; i < PATA_BF54X_WAIT_TIMEOUT; i++) {
+		status = ATAPI_GET_INT_STATUS(base) & mask;
+		if (status)
+			break;
+	}
+
+	ATAPI_SET_INT_STATUS(base, mask);
+}
+
+/**
+ *
+ *    Function:       write_atapi_register
+ *
+ *    Description:    Writes to ATA Device Resgister
+ *
+ */
+
+static void write_atapi_register(void __iomem *base,
+		unsigned long ata_reg, unsigned short value)
+{
+	/* Program the ATA_DEV_TXBUF register with write data (to be
+	 * written into the device).
+	 */
+	ATAPI_SET_DEV_TXBUF(base, value);
+
+	/* Program the ATA_DEV_ADDR register with address of the
+	 * device register (0x01 to 0x0F).
+	 */
+	ATAPI_SET_DEV_ADDR(base, ata_reg);
+
+	/* Program the ATA_CTRL register with dir set to write (1)
+	 */
+	ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR));
+
+	/* ensure PIO DMA is not set */
+	ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+	/* and start the transfer */
+	ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+	/* Wait for the interrupt to indicate the end of the transfer.
+	 * (We need to wait on and clear rhe ATA_DEV_INT interrupt status)
+	 */
+	wait_complete(base, PIO_DONE_INT);
+}
+
+/**
+ *
+ *	Function:       read_atapi_register
+ *
+ *Description:    Reads from ATA Device Resgister
+ *
+ */
+
+static unsigned short read_atapi_register(void __iomem *base,
+		unsigned long ata_reg)
+{
+	/* Program the ATA_DEV_ADDR register with address of the
+	 * device register (0x01 to 0x0F).
+	 */
+	ATAPI_SET_DEV_ADDR(base, ata_reg);
+
+	/* Program the ATA_CTRL register with dir set to read (0) and
+	 */
+	ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR));
+
+	/* ensure PIO DMA is not set */
+	ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+	/* and start the transfer */
+	ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+	/* Wait for the interrupt to indicate the end of the transfer.
+	 * (PIO_DONE interrupt is set and it doesn't seem to matter
+	 * that we don't clear it)
+	 */
+	wait_complete(base, PIO_DONE_INT);
+
+	/* Read the ATA_DEV_RXBUF register with write data (to be
+	 * written into the device).
+	 */
+	return ATAPI_GET_DEV_RXBUF(base);
+}
+
+/**
+ *
+ *    Function:       write_atapi_register_data
+ *
+ *    Description:    Writes to ATA Device Resgister
+ *
+ */
+
+static void write_atapi_data(void __iomem *base,
+		int len, unsigned short *buf)
+{
+	int i;
+
+	/* Set transfer length to 1 */
+	ATAPI_SET_XFER_LEN(base, 1);
+
+	/* Program the ATA_DEV_ADDR register with address of the
+	 * ATA_REG_DATA
+	 */
+	ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA);
+
+	/* Program the ATA_CTRL register with dir set to write (1)
+	 */
+	ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR));
+
+	/* ensure PIO DMA is not set */
+	ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+	for (i = 0; i < len; i++) {
+		/* Program the ATA_DEV_TXBUF register with write data (to be
+		 * written into the device).
+		 */
+		ATAPI_SET_DEV_TXBUF(base, buf[i]);
+
+		/* and start the transfer */
+		ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+		/* Wait for the interrupt to indicate the end of the transfer.
+		 * (We need to wait on and clear rhe ATA_DEV_INT
+		 * interrupt status)
+		 */
+		wait_complete(base, PIO_DONE_INT);
+	}
+}
+
+/**
+ *
+ *	Function:       read_atapi_register_data
+ *
+ *	Description:    Reads from ATA Device Resgister
+ *
+ */
+
+static void read_atapi_data(void __iomem *base,
+		int len, unsigned short *buf)
+{
+	int i;
+
+	/* Set transfer length to 1 */
+	ATAPI_SET_XFER_LEN(base, 1);
+
+	/* Program the ATA_DEV_ADDR register with address of the
+	 * ATA_REG_DATA
+	 */
+	ATAPI_SET_DEV_ADDR(base, ATA_REG_DATA);
+
+	/* Program the ATA_CTRL register with dir set to read (0) and
+	 */
+	ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~XFER_DIR));
+
+	/* ensure PIO DMA is not set */
+	ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA));
+
+	for (i = 0; i < len; i++) {
+		/* and start the transfer */
+		ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START));
+
+		/* Wait for the interrupt to indicate the end of the transfer.
+		 * (PIO_DONE interrupt is set and it doesn't seem to matter
+		 * that we don't clear it)
+		 */
+		wait_complete(base, PIO_DONE_INT);
+
+		/* Read the ATA_DEV_RXBUF register with write data (to be
+		 * written into the device).
+		 */
+		buf[i] = ATAPI_GET_DEV_RXBUF(base);
+	}
+}
+
+/**
+ *	bfin_tf_load - send taskfile registers to host controller
+ *	@ap: Port to which output is sent
+ *	@tf: ATA taskfile register set
+ *
+ *	Note: Original code is ata_tf_load().
+ */
+
+static void bfin_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
+{
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+	if (tf->ctl != ap->last_ctl) {
+		write_atapi_register(base, ATA_REG_CTRL, tf->ctl);
+		ap->last_ctl = tf->ctl;
+		ata_wait_idle(ap);
+	}
+
+	if (is_addr) {
+		if (tf->flags & ATA_TFLAG_LBA48) {
+			write_atapi_register(base, ATA_REG_FEATURE,
+						tf->hob_feature);
+			write_atapi_register(base, ATA_REG_NSECT,
+						tf->hob_nsect);
+			write_atapi_register(base, ATA_REG_LBAL, tf->hob_lbal);
+			write_atapi_register(base, ATA_REG_LBAM, tf->hob_lbam);
+			write_atapi_register(base, ATA_REG_LBAH, tf->hob_lbah);
+			pr_debug("hob: feat 0x%X nsect 0x%X, lba 0x%X "
+				 "0x%X 0x%X\n",
+				tf->hob_feature,
+				tf->hob_nsect,
+				tf->hob_lbal,
+				tf->hob_lbam,
+				tf->hob_lbah);
+		}
+
+		write_atapi_register(base, ATA_REG_FEATURE, tf->feature);
+		write_atapi_register(base, ATA_REG_NSECT, tf->nsect);
+		write_atapi_register(base, ATA_REG_LBAL, tf->lbal);
+		write_atapi_register(base, ATA_REG_LBAM, tf->lbam);
+		write_atapi_register(base, ATA_REG_LBAH, tf->lbah);
+		pr_debug("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+			tf->feature,
+			tf->nsect,
+			tf->lbal,
+			tf->lbam,
+			tf->lbah);
+	}
+
+	if (tf->flags & ATA_TFLAG_DEVICE) {
+		write_atapi_register(base, ATA_REG_DEVICE, tf->device);
+		pr_debug("device 0x%X\n", tf->device);
+	}
+
+	ata_wait_idle(ap);
+}
+
+/**
+ *	bfin_check_status - Read device status reg & clear interrupt
+ *	@ap: port where the device is
+ *
+ *	Note: Original code is ata_check_status().
+ */
+
+static u8 bfin_check_status(struct ata_port *ap)
+{
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+	return read_atapi_register(base, ATA_REG_STATUS);
+}
+
+/**
+ *	bfin_tf_read - input device's ATA taskfile shadow registers
+ *	@ap: Port from which input is read
+ *	@tf: ATA taskfile register set for storing input
+ *
+ *	Note: Original code is ata_tf_read().
+ */
+
+static void bfin_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+	tf->command = bfin_check_status(ap);
+	tf->feature = read_atapi_register(base, ATA_REG_ERR);
+	tf->nsect = read_atapi_register(base, ATA_REG_NSECT);
+	tf->lbal = read_atapi_register(base, ATA_REG_LBAL);
+	tf->lbam = read_atapi_register(base, ATA_REG_LBAM);
+	tf->lbah = read_atapi_register(base, ATA_REG_LBAH);
+	tf->device = read_atapi_register(base, ATA_REG_DEVICE);
+
+	if (tf->flags & ATA_TFLAG_LBA48) {
+		write_atapi_register(base, ATA_REG_CTRL, tf->ctl | ATA_HOB);
+		tf->hob_feature = read_atapi_register(base, ATA_REG_ERR);
+		tf->hob_nsect = read_atapi_register(base, ATA_REG_NSECT);
+		tf->hob_lbal = read_atapi_register(base, ATA_REG_LBAL);
+		tf->hob_lbam = read_atapi_register(base, ATA_REG_LBAM);
+		tf->hob_lbah = read_atapi_register(base, ATA_REG_LBAH);
+	}
+}
+
+/**
+ *	bfin_exec_command - issue ATA command to host controller
+ *	@ap: port to which command is being issued
+ *	@tf: ATA taskfile register set
+ *
+ *	Note: Original code is ata_exec_command().
+ */
+
+static void bfin_exec_command(struct ata_port *ap,
+			      const struct ata_taskfile *tf)
+{
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+	pr_debug("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+
+	write_atapi_register(base, ATA_REG_CMD, tf->command);
+	ata_pause(ap);
+}
+
+/**
+ *	bfin_check_altstatus - Read device alternate status reg
+ *	@ap: port where the device is
+ */
+
+static u8 bfin_check_altstatus(struct ata_port *ap)
+{
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+	return read_atapi_register(base, ATA_REG_ALTSTATUS);
+}
+
+/**
+ *	bfin_std_dev_select - Select device 0/1 on ATA bus
+ *	@ap: ATA channel to manipulate
+ *	@device: ATA device (numbered from zero) to select
+ *
+ *	Note: Original code is ata_std_dev_select().
+ */
+
+static void bfin_std_dev_select(struct ata_port *ap, unsigned int device)
+{
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+	u8 tmp;
+
+	if (device == 0)
+		tmp = ATA_DEVICE_OBS;
+	else
+		tmp = ATA_DEVICE_OBS | ATA_DEV1;
+
+	write_atapi_register(base, ATA_REG_DEVICE, tmp);
+	ata_pause(ap);
+}
+
+/**
+ *	bfin_bmdma_setup - Set up IDE DMA transaction
+ *	@qc: Info associated with this ATA transaction.
+ *
+ *	Note: Original code is ata_bmdma_setup().
+ */
+
+static void bfin_bmdma_setup(struct ata_queued_cmd *qc)
+{
+	unsigned short config = WDSIZE_16;
+	struct scatterlist *sg;
+
+	pr_debug("in atapi dma setup\n");
+	/* Program the ATA_CTRL register with dir */
+	if (qc->tf.flags & ATA_TFLAG_WRITE) {
+		/* fill the ATAPI DMA controller */
+		set_dma_config(CH_ATAPI_TX, config);
+		set_dma_x_modify(CH_ATAPI_TX, 2);
+		ata_for_each_sg(sg, qc) {
+			set_dma_start_addr(CH_ATAPI_TX, sg_dma_address(sg));
+			set_dma_x_count(CH_ATAPI_TX, sg_dma_len(sg) >> 1);
+		}
+	} else {
+		config |= WNR;
+		/* fill the ATAPI DMA controller */
+		set_dma_config(CH_ATAPI_RX, config);
+		set_dma_x_modify(CH_ATAPI_RX, 2);
+		ata_for_each_sg(sg, qc) {
+			set_dma_start_addr(CH_ATAPI_RX, sg_dma_address(sg));
+			set_dma_x_count(CH_ATAPI_RX, sg_dma_len(sg) >> 1);
+		}
+	}
+}
+
+/**
+ *	bfin_bmdma_start - Start an IDE DMA transaction
+ *	@qc: Info associated with this ATA transaction.
+ *
+ *	Note: Original code is ata_bmdma_start().
+ */
+
+static void bfin_bmdma_start(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+	struct scatterlist *sg;
+
+	pr_debug("in atapi dma start\n");
+	if (!(ap->udma_mask || ap->mwdma_mask))
+		return;
+
+	/* start ATAPI DMA controller*/
+	if (qc->tf.flags & ATA_TFLAG_WRITE) {
+		/*
+		 * On blackfin arch, uncacheable memory is not
+		 * allocated with flag GFP_DMA. DMA buffer from
+		 * common kenel code should be flushed if WB
+		 * data cache is enabled. Otherwise, this loop
+		 * is an empty loop and optimized out.
+		 */
+		ata_for_each_sg(sg, qc) {
+			flush_dcache_range(sg_dma_address(sg),
+				sg_dma_address(sg) + sg_dma_len(sg));
+		}
+		enable_dma(CH_ATAPI_TX);
+		pr_debug("enable udma write\n");
+
+		/* Send ATA DMA write command */
+		bfin_exec_command(ap, &qc->tf);
+
+		/* set ATA DMA write direction */
+		ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)
+			| XFER_DIR));
+	} else {
+		enable_dma(CH_ATAPI_RX);
+		pr_debug("enable udma read\n");
+
+		/* Send ATA DMA read command */
+		bfin_exec_command(ap, &qc->tf);
+
+		/* set ATA DMA read direction */
+		ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base)
+			& ~XFER_DIR));
+	}
+
+	/* Reset all transfer count */
+	ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | TFRCNT_RST);
+
+		/* Set transfer length to buffer len */
+	ata_for_each_sg(sg, qc) {
+		ATAPI_SET_XFER_LEN(base, (sg_dma_len(sg) >> 1));
+	}
+
+	/* Enable ATA DMA operation*/
+	if (ap->udma_mask)
+		ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base)
+			| ULTRA_START);
+	else
+		ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base)
+			| MULTI_START);
+}
+
+/**
+ *	bfin_bmdma_stop - Stop IDE DMA transfer
+ *	@qc: Command we are ending DMA for
+ */
+
+static void bfin_bmdma_stop(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct scatterlist *sg;
+
+	pr_debug("in atapi dma stop\n");
+	if (!(ap->udma_mask || ap->mwdma_mask))
+		return;
+
+	/* stop ATAPI DMA controller*/
+	if (qc->tf.flags & ATA_TFLAG_WRITE)
+		disable_dma(CH_ATAPI_TX);
+	else {
+		disable_dma(CH_ATAPI_RX);
+		if (ap->hsm_task_state & HSM_ST_LAST) {
+			/*
+			 * On blackfin arch, uncacheable memory is not
+			 * allocated with flag GFP_DMA. DMA buffer from
+			 * common kenel code should be invalidated if
+			 * data cache is enabled. Otherwise, this loop
+			 * is an empty loop and optimized out.
+			 */
+			ata_for_each_sg(sg, qc) {
+				invalidate_dcache_range(
+					sg_dma_address(sg),
+					sg_dma_address(sg)
+					+ sg_dma_len(sg));
+			}
+		}
+	}
+}
+
+/**
+ *	bfin_devchk - PATA device presence detection
+ *	@ap: ATA channel to examine
+ *	@device: Device to examine (starting at zero)
+ *
+ *	Note: Original code is ata_devchk().
+ */
+
+static unsigned int bfin_devchk(struct ata_port *ap,
+				unsigned int device)
+{
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+	u8 nsect, lbal;
+
+	bfin_std_dev_select(ap, device);
+
+	write_atapi_register(base, ATA_REG_NSECT, 0x55);
+	write_atapi_register(base, ATA_REG_LBAL, 0xaa);
+
+	write_atapi_register(base, ATA_REG_NSECT, 0xaa);
+	write_atapi_register(base, ATA_REG_LBAL, 0x55);
+
+	write_atapi_register(base, ATA_REG_NSECT, 0x55);
+	write_atapi_register(base, ATA_REG_LBAL, 0xaa);
+
+	nsect = read_atapi_register(base, ATA_REG_NSECT);
+	lbal = read_atapi_register(base, ATA_REG_LBAL);
+
+	if ((nsect == 0x55) && (lbal == 0xaa))
+		return 1;	/* we found a device */
+
+	return 0;		/* nothing found */
+}
+
+/**
+ *	bfin_bus_post_reset - PATA device post reset
+ *
+ *	Note: Original code is ata_bus_post_reset().
+ */
+
+static void bfin_bus_post_reset(struct ata_port *ap, unsigned int devmask)
+{
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+	unsigned int dev0 = devmask & (1 << 0);
+	unsigned int dev1 = devmask & (1 << 1);
+	unsigned long timeout;
+
+	/* if device 0 was found in ata_devchk, wait for its
+	 * BSY bit to clear
+	 */
+	if (dev0)
+		ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+	/* if device 1 was found in ata_devchk, wait for
+	 * register access, then wait for BSY to clear
+	 */
+	timeout = jiffies + ATA_TMOUT_BOOT;
+	while (dev1) {
+		u8 nsect, lbal;
+
+		bfin_std_dev_select(ap, 1);
+		nsect = read_atapi_register(base, ATA_REG_NSECT);
+		lbal = read_atapi_register(base, ATA_REG_LBAL);
+		if ((nsect == 1) && (lbal == 1))
+			break;
+		if (time_after(jiffies, timeout)) {
+			dev1 = 0;
+			break;
+		}
+		msleep(50);	/* give drive a breather */
+	}
+	if (dev1)
+		ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+	/* is all this really necessary? */
+	bfin_std_dev_select(ap, 0);
+	if (dev1)
+		bfin_std_dev_select(ap, 1);
+	if (dev0)
+		bfin_std_dev_select(ap, 0);
+}
+
+/**
+ *	bfin_bus_softreset - PATA device software reset
+ *
+ *	Note: Original code is ata_bus_softreset().
+ */
+
+static unsigned int bfin_bus_softreset(struct ata_port *ap,
+				       unsigned int devmask)
+{
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+	/* software reset.  causes dev0 to be selected */
+	write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+	udelay(20);
+	write_atapi_register(base, ATA_REG_CTRL, ap->ctl | ATA_SRST);
+	udelay(20);
+	write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+
+	/* spec mandates ">= 2ms" before checking status.
+	 * We wait 150ms, because that was the magic delay used for
+	 * ATAPI devices in Hale Landis's ATADRVR, for the period of time
+	 * between when the ATA command register is written, and then
+	 * status is checked.  Because waiting for "a while" before
+	 * checking status is fine, post SRST, we perform this magic
+	 * delay here as well.
+	 *
+	 * Old drivers/ide uses the 2mS rule and then waits for ready
+	 */
+	msleep(150);
+
+	/* Before we perform post reset processing we want to see if
+	 * the bus shows 0xFF because the odd clown forgets the D7
+	 * pulldown resistor.
+	 */
+	if (bfin_check_status(ap) == 0xFF)
+		return 0;
+
+	bfin_bus_post_reset(ap, devmask);
+
+	return 0;
+}
+
+/**
+ *	bfin_std_softreset - reset host port via ATA SRST
+ *	@ap: port to reset
+ *	@classes: resulting classes of attached devices
+ *
+ *	Note: Original code is ata_std_softreset().
+ */
+
+static int bfin_std_softreset(struct ata_port *ap, unsigned int *classes,
+		unsigned long deadline)
+{
+	unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+	unsigned int devmask = 0, err_mask;
+	u8 err;
+
+	if (ata_port_offline(ap)) {
+		classes[0] = ATA_DEV_NONE;
+		goto out;
+	}
+
+	/* determine if device 0/1 are present */
+	if (bfin_devchk(ap, 0))
+		devmask |= (1 << 0);
+	if (slave_possible && bfin_devchk(ap, 1))
+		devmask |= (1 << 1);
+
+	/* select device 0 again */
+	bfin_std_dev_select(ap, 0);
+
+	/* issue bus reset */
+	err_mask = bfin_bus_softreset(ap, devmask);
+	if (err_mask) {
+		ata_port_printk(ap, KERN_ERR, "SRST failed (err_mask=0x%x)\n",
+				err_mask);
+		return -EIO;
+	}
+
+	/* determine by signature whether we have ATA or ATAPI devices */
+	classes[0] = ata_dev_try_classify(ap, 0, &err);
+	if (slave_possible && err != 0x81)
+		classes[1] = ata_dev_try_classify(ap, 1, &err);
+
+ out:
+	return 0;
+}
+
+/**
+ *	bfin_bmdma_status - Read IDE DMA status
+ *	@ap: Port associated with this ATA transaction.
+ */
+
+static unsigned char bfin_bmdma_status(struct ata_port *ap)
+{
+	unsigned char host_stat = 0;
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+	unsigned short int_status = ATAPI_GET_INT_STATUS(base);
+
+	if (ATAPI_GET_STATUS(base) & (MULTI_XFER_ON|ULTRA_XFER_ON)) {
+		host_stat = ATA_DMA_ACTIVE;
+	}
+	if (int_status & (MULTI_DONE_INT|UDMAIN_DONE_INT|UDMAOUT_DONE_INT)) {
+		host_stat = ATA_DMA_INTR;
+	}
+	if (int_status & (MULTI_TERM_INT|UDMAIN_TERM_INT|UDMAOUT_TERM_INT)) {
+		host_stat = ATA_DMA_ERR;
+	}
+
+	return host_stat;
+}
+
+/**
+ *	bfin_data_xfer - Transfer data by PIO
+ *	@adev: device for this I/O
+ *	@buf: data buffer
+ *	@buflen: buffer length
+ *	@write_data: read/write
+ *
+ *	Note: Original code is ata_data_xfer().
+ */
+
+static void bfin_data_xfer(struct ata_device *adev, unsigned char *buf,
+			   unsigned int buflen, int write_data)
+{
+	struct ata_port *ap = adev->ap;
+	unsigned int words = buflen >> 1;
+	unsigned short *buf16 = (u16 *) buf;
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+	/* Transfer multiple of 2 bytes */
+	if (write_data) {
+		write_atapi_data(base, words, buf16);
+	} else {
+		read_atapi_data(base, words, buf16);
+	}
+
+	/* Transfer trailing 1 byte, if any. */
+	if (unlikely(buflen & 0x01)) {
+		unsigned short align_buf[1] = { 0 };
+		unsigned char *trailing_buf = buf + buflen - 1;
+
+		if (write_data) {
+			memcpy(align_buf, trailing_buf, 1);
+			write_atapi_data(base, 1, align_buf);
+		} else {
+			read_atapi_data(base, 1, align_buf);
+			memcpy(trailing_buf, align_buf, 1);
+		}
+	}
+}
+
+/**
+ *	bfin_irq_clear - Clear ATAPI interrupt.
+ *	@ap: Port associated with this ATA transaction.
+ *
+ *	Note: Original code is ata_bmdma_irq_clear().
+ */
+
+static void bfin_irq_clear(struct ata_port *ap)
+{
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+	pr_debug("in atapi irq clear\n");
+	ATAPI_SET_INT_STATUS(base, 0x1FF);
+}
+
+/**
+ *	bfin_irq_on - Enable interrupts on a port.
+ *	@ap: Port on which interrupts are enabled.
+ *
+ *	Note: Original code is ata_irq_on().
+ */
+
+static unsigned char bfin_irq_on(struct ata_port *ap)
+{
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+	u8 tmp;
+
+	pr_debug("in atapi irq on\n");
+	ap->ctl &= ~ATA_NIEN;
+	ap->last_ctl = ap->ctl;
+
+	write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+	tmp = ata_wait_idle(ap);
+
+	bfin_irq_clear(ap);
+
+	return tmp;
+}
+
+/**
+ *	bfin_irq_ack - Acknowledge a device interrupt.
+ *	@ap: Port on which interrupts are enabled.
+ *
+ *	Note: Original code is ata_irq_ack().
+ */
+
+static unsigned char bfin_irq_ack(struct ata_port *ap, unsigned int chk_drq)
+{
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+	unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
+	unsigned char status;
+
+	pr_debug("in atapi irq ack\n");
+	status = ata_busy_wait(ap, bits, 1000);
+	if (status & bits)
+		if (ata_msg_err(ap))
+			dev_err(ap->dev, "abnormal status 0x%X\n", status);
+
+	/* get controller status; clear intr, err bits */
+	ATAPI_SET_INT_STATUS(base, ATAPI_GET_INT_STATUS(base)|ATAPI_DEV_INT
+		| MULTI_DONE_INT | UDMAIN_DONE_INT | UDMAOUT_DONE_INT
+		| MULTI_TERM_INT | UDMAIN_TERM_INT | UDMAOUT_TERM_INT);
+
+	return bfin_bmdma_status(ap);
+}
+
+/**
+ *	bfin_bmdma_freeze - Freeze DMA controller port
+ *	@ap: port to freeze
+ *
+ *	Note: Original code is ata_bmdma_freeze().
+ */
+
+static void bfin_bmdma_freeze(struct ata_port *ap)
+{
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+	pr_debug("in atapi dma freeze\n");
+	ap->ctl |= ATA_NIEN;
+	ap->last_ctl = ap->ctl;
+
+	write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+
+	/* Under certain circumstances, some controllers raise IRQ on
+	 * ATA_NIEN manipulation.  Also, many controllers fail to mask
+	 * previously pending IRQ on ATA_NIEN assertion.  Clear it.
+	 */
+	ata_chk_status(ap);
+
+	bfin_irq_clear(ap);
+}
+
+/**
+ *	bfin_bmdma_thaw - Thaw DMA controller port
+ *	@ap: port to thaw
+ *
+ *	Note: Original code is ata_bmdma_thaw().
+ */
+
+void bfin_bmdma_thaw(struct ata_port *ap)
+{
+	bfin_check_status(ap);
+	bfin_irq_clear(ap);
+	bfin_irq_on(ap);
+}
+
+/**
+ *	bfin_std_postreset - standard postreset callback
+ *	@ap: the target ata_port
+ *	@classes: classes of attached devices
+ *
+ *	Note: Original code is ata_std_postreset().
+ */
+
+static void bfin_std_postreset(struct ata_port *ap, unsigned int *classes)
+{
+	void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr;
+
+	/* re-enable interrupts */
+	bfin_irq_on(ap);
+
+	/* is double-select really necessary? */
+	if (classes[0] != ATA_DEV_NONE)
+		bfin_std_dev_select(ap, 1);
+	if (classes[1] != ATA_DEV_NONE)
+		bfin_std_dev_select(ap, 0);
+
+	/* bail out if no device is present */
+	if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
+		return;
+	}
+
+	/* set up device control */
+	write_atapi_register(base, ATA_REG_CTRL, ap->ctl);
+}
+
+/**
+ *	bfin_error_handler - Stock error handler for DMA controller
+ *	@ap: port to handle error for
+ */
+
+static void bfin_error_handler(struct ata_port *ap)
+{
+	ata_bmdma_drive_eh(ap, ata_std_prereset, bfin_std_softreset, NULL,
+			   bfin_std_postreset);
+}
+
+static void bfin_port_stop(struct ata_port *ap)
+{
+	pr_debug("in atapi port stop\n");
+	if (ap->udma_mask != 0 || ap->mwdma_mask != 0) {
+		free_dma(CH_ATAPI_RX);
+		free_dma(CH_ATAPI_TX);
+	}
+}
+
+static int bfin_port_start(struct ata_port *ap)
+{
+	pr_debug("in atapi port start\n");
+	if (!(ap->udma_mask || ap->mwdma_mask))
+		return 0;
+
+	if (request_dma(CH_ATAPI_RX, "BFIN ATAPI RX DMA") >= 0) {
+		if (request_dma(CH_ATAPI_TX,
+			"BFIN ATAPI TX DMA") >= 0)
+			return 0;
+
+		free_dma(CH_ATAPI_RX);
+	}
+
+	ap->udma_mask = 0;
+	ap->mwdma_mask = 0;
+	dev_err(ap->dev, "Unable to request ATAPI DMA!"
+		" Continue in PIO mode.\n");
+
+	return 0;
+}
+
+static struct scsi_host_template bfin_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= SG_NONE,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
+	.bios_param		= ata_std_bios_param,
+#ifdef CONFIG_PM
+	.resume			= ata_scsi_device_resume,
+	.suspend		= ata_scsi_device_suspend,
+#endif
+};
+
+static const struct ata_port_operations bfin_pata_ops = {
+	.port_disable		= ata_port_disable,
+	.set_piomode		= bfin_set_piomode,
+	.set_dmamode		= bfin_set_dmamode,
+
+	.tf_load		= bfin_tf_load,
+	.tf_read		= bfin_tf_read,
+	.exec_command		= bfin_exec_command,
+	.check_status		= bfin_check_status,
+	.check_altstatus	= bfin_check_altstatus,
+	.dev_select		= bfin_std_dev_select,
+
+	.bmdma_setup		= bfin_bmdma_setup,
+	.bmdma_start		= bfin_bmdma_start,
+	.bmdma_stop		= bfin_bmdma_stop,
+	.bmdma_status		= bfin_bmdma_status,
+	.data_xfer		= bfin_data_xfer,
+
+	.qc_prep		= ata_noop_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+
+	.freeze			= bfin_bmdma_freeze,
+	.thaw			= bfin_bmdma_thaw,
+	.error_handler		= bfin_error_handler,
+	.post_internal_cmd	= bfin_bmdma_stop,
+
+	.irq_handler		= ata_interrupt,
+	.irq_clear		= bfin_irq_clear,
+	.irq_on			= bfin_irq_on,
+	.irq_ack		= bfin_irq_ack,
+
+	.port_start		= bfin_port_start,
+	.port_stop		= bfin_port_stop,
+};
+
+static struct ata_port_info bfin_port_info[] = {
+	{
+		.sht		= &bfin_sht,
+		.flags		= ATA_FLAG_SLAVE_POSS
+				| ATA_FLAG_MMIO
+				| ATA_FLAG_NO_LEGACY,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.mwdma_mask	= 0,
+#ifdef CONFIG_PATA_BF54X_DMA
+		.udma_mask	= ATA_UDMA5,
+#else
+		.udma_mask	= 0,
+#endif
+		.port_ops	= &bfin_pata_ops,
+	},
+};
+
+/**
+ *	bfin_reset_controller - initialize BF54x ATAPI controller.
+ */
+
+static int bfin_reset_controller(struct ata_host *host)
+{
+	void __iomem *base = (void __iomem *)host->ports[0]->ioaddr.ctl_addr;
+	int count;
+	unsigned short status;
+
+	/* Disable all ATAPI interrupts */
+	ATAPI_SET_INT_MASK(base, 0);
+	SSYNC();
+
+	/* Assert the RESET signal 25us*/
+	ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | DEV_RST);
+	udelay(30);
+
+	/* Negate the RESET signal for 2ms*/
+	ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) & ~DEV_RST);
+	msleep(2);
+
+	/* Wait on Busy flag to clear */
+	count = 10000000;
+	do {
+		status = read_atapi_register(base, ATA_REG_STATUS);
+	} while (count-- && (status & ATA_BUSY));
+
+	/* Enable only ATAPI Device interrupt */
+	ATAPI_SET_INT_MASK(base, 1);
+	SSYNC();
+
+	return (!count);
+}
+
+/**
+ *	atapi_io_port - define atapi peripheral port pins.
+ */
+static unsigned short atapi_io_port[] = {
+	P_ATAPI_RESET,
+	P_ATAPI_DIOR,
+	P_ATAPI_DIOW,
+	P_ATAPI_CS0,
+	P_ATAPI_CS1,
+	P_ATAPI_DMACK,
+	P_ATAPI_DMARQ,
+	P_ATAPI_INTRQ,
+	P_ATAPI_IORDY,
+	0
+};
+
+/**
+ *	bfin_atapi_probe	-	attach a bfin atapi interface
+ *	@pdev: platform device
+ *
+ *	Register a bfin atapi interface.
+ *
+ *
+ *	Platform devices are expected to contain 2 resources per port:
+ *
+ *		- I/O Base (IORESOURCE_IO)
+ *		- IRQ	   (IORESOURCE_IRQ)
+ *
+ */
+static int __devinit bfin_atapi_probe(struct platform_device *pdev)
+{
+	int board_idx = 0;
+	struct resource *res;
+	struct ata_host *host;
+	const struct ata_port_info *ppi[] =
+		{ &bfin_port_info[board_idx], NULL };
+
+	/*
+	 * Simple resource validation ..
+	 */
+	if (unlikely(pdev->num_resources != 2)) {
+		dev_err(&pdev->dev, "invalid number of resources\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Get the register base first
+	 */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL)
+		return -EINVAL;
+
+	/*
+	 * Now that that's out of the way, wire up the port..
+	 */
+	host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1);
+	if (!host)
+		return -ENOMEM;
+
+	host->ports[0]->ioaddr.ctl_addr = (void *)res->start;
+
+	if (peripheral_request_list(atapi_io_port, "atapi-io-port")) {
+		dev_err(&pdev->dev, "Requesting Peripherals faild\n");
+		return -EFAULT;
+	}
+
+	if (bfin_reset_controller(host)) {
+		peripheral_free_list(atapi_io_port);
+		dev_err(&pdev->dev, "Fail to reset ATAPI device\n");
+		return -EFAULT;
+	}
+
+	if (ata_host_activate(host, platform_get_irq(pdev, 0),
+		ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) {
+		peripheral_free_list(atapi_io_port);
+		dev_err(&pdev->dev, "Fail to attach ATAPI device\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/**
+ *	bfin_atapi_remove	-	unplug a bfin atapi interface
+ *	@pdev: platform device
+ *
+ *	A bfin atapi device has been unplugged. Perform the needed
+ *	cleanup. Also called on module unload for any active devices.
+ */
+static int __devexit bfin_atapi_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ata_host *host = dev_get_drvdata(dev);
+
+	ata_host_detach(host);
+
+	peripheral_free_list(atapi_io_port);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	return 0;
+}
+
+int bfin_atapi_resume(struct platform_device *pdev)
+{
+	return 0;
+}
+#endif
+
+static struct platform_driver bfin_atapi_driver = {
+	.probe			= bfin_atapi_probe,
+	.remove			= __devexit_p(bfin_atapi_remove),
+	.driver = {
+		.name		= DRV_NAME,
+		.owner		= THIS_MODULE,
+#ifdef CONFIG_PM
+		.suspend	= bfin_atapi_suspend,
+		.resume		= bfin_atapi_resume,
+#endif
+	},
+};
+
+static int __init bfin_atapi_init(void)
+{
+	pr_info("register bfin atapi driver\n");
+	return platform_driver_register(&bfin_atapi_driver);
+}
+
+static void __exit bfin_atapi_exit(void)
+{
+	platform_driver_unregister(&bfin_atapi_driver);
+}
+
+module_init(bfin_atapi_init);
+module_exit(bfin_atapi_exit);
+
+MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>");
+MODULE_DESCRIPTION("PATA driver for blackfin 54x ATAPI controller");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c
index 0feb5ae..43d198f 100644
--- a/drivers/ata/pata_cmd640.c
+++ b/drivers/ata/pata_cmd640.c
@@ -153,7 +153,7 @@
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	struct cmd640_reg *timing;
 
-	int ret = ata_port_start(ap);
+	int ret = ata_sff_port_start(ap);
 	if (ret < 0)
 		return ret;
 
@@ -184,7 +184,6 @@
 };
 
 static struct ata_port_operations cmd640_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= cmd640_set_piomode,
 	.mode_filter	= ata_pci_default_filter,
 	.tf_load	= ata_tf_load,
@@ -213,7 +212,6 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
 	.port_start	= cmd640_port_start,
 };
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index dc443e7..9e412c2 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -31,7 +31,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_cmd64x"
-#define DRV_VERSION "0.2.3"
+#define DRV_VERSION "0.2.5"
 
 /*
  * CMD64x specific registers definition.
@@ -88,14 +88,15 @@
 }
 
 /**
- *	cmd64x_set_piomode	-	set initial PIO mode data
+ *	cmd64x_set_piomode	-	set PIO and MWDMA timing
  *	@ap: ATA interface
  *	@adev: ATA device
+ *	@mode: mode
  *
- *	Called to do the PIO mode setup.
+ *	Called to do the PIO and MWDMA mode setup.
  */
 
-static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+static void cmd64x_set_timing(struct ata_port *ap, struct ata_device *adev, u8 mode)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	struct ata_timing t;
@@ -117,8 +118,9 @@
 	int arttim = arttim_port[ap->port_no][adev->devno];
 	int drwtim = drwtim_port[ap->port_no][adev->devno];
 
-
-	if (ata_timing_compute(adev, adev->pio_mode, &t, T, 0) < 0) {
+	/* ata_timing_compute is smart and will produce timings for MWDMA
+	   that don't violate the drives PIO capabilities. */
+	if (ata_timing_compute(adev, mode, &t, T, 0) < 0) {
 		printk(KERN_ERR DRV_NAME ": mode computation failed.\n");
 		return;
 	}
@@ -168,6 +170,20 @@
 }
 
 /**
+ *	cmd64x_set_piomode	-	set initial PIO mode data
+ *	@ap: ATA interface
+ *	@adev: ATA device
+ *
+ *	Used when configuring the devices ot set the PIO timings. All the
+ *	actual work is done by the PIO/MWDMA setting helper
+ */
+
+static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+	cmd64x_set_timing(ap, adev, adev->pio_mode);
+}
+
+/**
  *	cmd64x_set_dmamode	-	set initial DMA mode data
  *	@ap: ATA interface
  *	@adev: ATA device
@@ -180,9 +196,6 @@
 	static const u8 udma_data[] = {
 		0x30, 0x20, 0x10, 0x20, 0x10, 0x00
 	};
-	static const u8 mwdma_data[] = {
-		0x30, 0x20, 0x10
-	};
 
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	u8 regU, regD;
@@ -208,8 +221,10 @@
 		regU |= 1 << adev->devno; /* UDMA on */
 		if (adev->dma_mode > 2)	/* 15nS timing */
 			regU |= 4 << adev->devno;
-	} else
-		regD |= mwdma_data[adev->dma_mode - XFER_MW_DMA_0] << shift;
+	} else {
+		regU &= ~ (1 << adev->devno);	/* UDMA off */
+		cmd64x_set_timing(ap, adev, adev->dma_mode);
+	}
 
 	regD |= 0x20 << adev->devno;
 
@@ -269,7 +284,6 @@
 };
 
 static struct ata_port_operations cmd64x_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= cmd64x_set_piomode,
 	.set_dmamode	= cmd64x_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -298,13 +312,11 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
 	.port_start	= ata_port_start,
 };
 
 static struct ata_port_operations cmd646r1_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= cmd64x_set_piomode,
 	.set_dmamode	= cmd64x_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -333,13 +345,11 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
 	.port_start	= ata_port_start,
 };
 
 static struct ata_port_operations cmd648_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= cmd64x_set_piomode,
 	.set_dmamode	= cmd64x_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -368,7 +378,6 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
 	.port_start	= ata_port_start,
 };
@@ -397,7 +406,7 @@
 			.flags = ATA_FLAG_SLAVE_POSS,
 			.pio_mask = 0x1f,
 			.mwdma_mask = 0x07,
-			.udma_mask = ATA_UDMA1,
+			.udma_mask = ATA_UDMA2,
 			.port_ops = &cmd64x_port_ops
 		},
 		{	/* CMD 646 rev 1  */
@@ -412,7 +421,7 @@
 			.flags = ATA_FLAG_SLAVE_POSS,
 			.pio_mask = 0x1f,
 			.mwdma_mask = 0x07,
-			.udma_mask = ATA_UDMA2,
+			.udma_mask = ATA_UDMA4,
 			.port_ops = &cmd648_port_ops
 		},
 		{	/* CMD 649 */
@@ -420,7 +429,7 @@
 			.flags = ATA_FLAG_SLAVE_POSS,
 			.pio_mask = 0x1f,
 			.mwdma_mask = 0x07,
-			.udma_mask = ATA_UDMA3,
+			.udma_mask = ATA_UDMA5,
 			.port_ops = &cmd648_port_ops
 		}
 	};
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index 6bf037d..33f7f08 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -41,7 +41,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"pata_cs5520"
-#define DRV_VERSION	"0.6.5"
+#define DRV_VERSION	"0.6.6"
 
 struct pio_clocks
 {
@@ -158,7 +158,6 @@
 };
 
 static struct ata_port_operations cs5520_port_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= cs5520_set_piomode,
 	.set_dmamode		= cs5520_set_dmamode,
 
@@ -184,13 +183,14 @@
 
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
-	.port_start		= ata_port_start,
+	.port_start		= ata_sff_port_start,
 };
 
 static int __devinit cs5520_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
+	static const unsigned int cmd_port[] = { 0x1F0, 0x170 };
+	static const unsigned int ctl_port[] = { 0x3F6, 0x376 };
 	struct ata_port_info pi = {
 		.flags		= ATA_FLAG_SLAVE_POSS,
 		.pio_mask	= 0x1f,
@@ -244,10 +244,10 @@
 	}
 
 	/* Map IO ports and initialize host accordingly */
-	iomap[0] = devm_ioport_map(&pdev->dev, 0x1F0, 8);
-	iomap[1] = devm_ioport_map(&pdev->dev, 0x3F6, 1);
-	iomap[2] = devm_ioport_map(&pdev->dev, 0x170, 8);
-	iomap[3] = devm_ioport_map(&pdev->dev, 0x376, 1);
+	iomap[0] = devm_ioport_map(&pdev->dev, cmd_port[0], 8);
+	iomap[1] = devm_ioport_map(&pdev->dev, ctl_port[0], 1);
+	iomap[2] = devm_ioport_map(&pdev->dev, cmd_port[1], 8);
+	iomap[3] = devm_ioport_map(&pdev->dev, ctl_port[1], 1);
 	iomap[4] = pcim_iomap(pdev, 2, 0);
 
 	if (!iomap[0] || !iomap[1] || !iomap[2] || !iomap[3] || !iomap[4])
@@ -260,6 +260,10 @@
 	ioaddr->bmdma_addr = iomap[4];
 	ata_std_ports(ioaddr);
 
+	ata_port_desc(host->ports[0],
+		      "cmd 0x%x ctl 0x%x", cmd_port[0], ctl_port[0]);
+	ata_port_pbar_desc(host->ports[0], 4, 0, "bmdma");
+
 	ioaddr = &host->ports[1]->ioaddr;
 	ioaddr->cmd_addr = iomap[2];
 	ioaddr->ctl_addr = iomap[3];
@@ -267,6 +271,10 @@
 	ioaddr->bmdma_addr = iomap[4] + 8;
 	ata_std_ports(ioaddr);
 
+	ata_port_desc(host->ports[1],
+		      "cmd 0x%x ctl 0x%x", cmd_port[1], ctl_port[1]);
+	ata_port_pbar_desc(host->ports[1], 4, 8, "bmdma");
+
 	/* activate the host */
 	pci_set_master(pdev);
 	rc = ata_host_start(host);
@@ -275,7 +283,7 @@
 
 	for (i = 0; i < 2; i++) {
 		static const int irq[] = { 14, 15 };
-		struct ata_port *ap = host->ports[0];
+		struct ata_port *ap = host->ports[i];
 
 		if (ata_port_is_dummy(ap))
 			continue;
@@ -285,33 +293,12 @@
 		if (rc)
 			return rc;
 
-		if (i == 0)
-			host->irq = irq[0];
-		else
-			host->irq2 = irq[1];
+		ata_port_desc(ap, "irq %d", irq[i]);
 	}
 
 	return ata_host_register(host, &cs5520_sht);
 }
 
-/**
- *	cs5520_remove_one	-	device unload
- *	@pdev: PCI device being removed
- *
- *	Handle an unplug/unload event for a PCI device. Unload the
- *	PCI driver but do not use the default handler as we manage
- *	resources ourself and *MUST NOT* disable the device as it has
- *	other functions.
- */
-
-static void __devexit cs5520_remove_one(struct pci_dev *pdev)
-{
-	struct device *dev = pci_dev_to_dev(pdev);
-	struct ata_host *host = dev_get_drvdata(dev);
-
-	ata_host_detach(host);
-}
-
 #ifdef CONFIG_PM
 /**
  *	cs5520_reinit_one	-	device resume
@@ -368,7 +355,7 @@
 	.name 		= DRV_NAME,
 	.id_table	= pata_cs5520,
 	.probe 		= cs5520_init_one,
-	.remove		= cs5520_remove_one,
+	.remove		= ata_pci_remove_one,
 #ifdef CONFIG_PM
 	.suspend	= cs5520_pci_device_suspend,
 	.resume		= cs5520_reinit_one,
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index 68f150a..57e827e 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -35,7 +35,7 @@
 #include <linux/dmi.h>
 
 #define DRV_NAME	"pata_cs5530"
-#define DRV_VERSION	"0.7.3"
+#define DRV_VERSION	"0.7.4"
 
 static void __iomem *cs5530_port_base(struct ata_port *ap)
 {
@@ -179,7 +179,6 @@
 };
 
 static struct ata_port_operations cs5530_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= cs5530_set_piomode,
 	.set_dmamode	= cs5530_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -209,12 +208,11 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
-static struct dmi_system_id palmax_dmi_table[] = {
+static const struct dmi_system_id palmax_dmi_table[] = {
 	{
 		.ident = "Palmax PD1100",
 		.matches = {
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index 360b6f3..3578593 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -176,7 +176,6 @@
 };
 
 static struct ata_port_operations cs5535_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= cs5535_set_piomode,
 	.set_dmamode	= cs5535_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -206,9 +205,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /**
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index 6cbc877..fc5f9c4 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -128,7 +128,6 @@
 };
 
 static struct ata_port_operations cy82c693_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= cy82c693_set_piomode,
 	.set_dmamode	= cy82c693_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -158,9 +157,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index c8ba59c..043dcd3 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -26,25 +26,26 @@
 
 /**
  *	efar_pre_reset	-	Enable bits
- *	@ap: Port
+ *	@link: ATA link
  *	@deadline: deadline jiffies for the operation
  *
  *	Perform cable detection for the EFAR ATA interface. This is
  *	different to the PIIX arrangement
  */
 
-static int efar_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int efar_pre_reset(struct ata_link *link, unsigned long deadline)
 {
 	static const struct pci_bits efar_enable_bits[] = {
 		{ 0x41U, 1U, 0x80UL, 0x80UL },	/* port 0 */
 		{ 0x43U, 1U, 0x80UL, 0x80UL },	/* port 1 */
 	};
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
 	if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no]))
 		return -ENOENT;
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -250,7 +251,6 @@
 };
 
 static const struct ata_port_operations efar_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= efar_set_piomode,
 	.set_dmamode		= efar_set_dmamode,
 	.mode_filter		= ata_pci_default_filter,
@@ -278,9 +278,8 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
-	.port_start		= ata_port_start,
+	.port_start		= ata_sff_port_start,
 };
 
 
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index 6f7d34a..0713872 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -312,7 +312,6 @@
  */
 
 static struct ata_port_operations hpt366_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= hpt366_set_piomode,
 	.set_dmamode	= hpt366_set_dmamode,
 	.mode_filter	= hpt366_filter,
@@ -342,9 +341,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /**
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index b0af65a..e61cb1f 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -8,12 +8,10 @@
  * Copyright (C) 1999-2003		Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
  * Portions Copyright (C) 2003		Red Hat Inc
- * Portions Copyright (C) 2005-2006	MontaVista Software, Inc.
+ * Portions Copyright (C) 2005-2007	MontaVista Software, Inc.
  *
  * TODO
- *	PLL mode
- *	Look into engine reset on timeout errors. Should not be
- *		required.
+ *	Look into engine reset on timeout errors. Should not be	required.
  */
 
 #include <linux/kernel.h>
@@ -26,7 +24,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"pata_hpt37x"
-#define DRV_VERSION	"0.6.6"
+#define DRV_VERSION	"0.6.9"
 
 struct hpt_clock {
 	u8	xfer_speed;
@@ -306,15 +304,16 @@
 
 /**
  *	hpt37x_pre_reset	-	reset the hpt37x bus
- *	@ap: ATA port to reset
+ *	@link: ATA link to reset
  *	@deadline: deadline jiffies for the operation
  *
  *	Perform the initial reset handling for the 370/372 and 374 func 0
  */
 
-static int hpt37x_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int hpt37x_pre_reset(struct ata_link *link, unsigned long deadline)
 {
 	u8 scr2, ata66;
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	static const struct pci_bits hpt37x_enable_bits[] = {
 		{ 0x50, 1, 0x04, 0x04 },
@@ -339,7 +338,7 @@
 	pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
 	udelay(100);
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -354,7 +353,7 @@
 	ata_bmdma_drive_eh(ap, hpt37x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
 }
 
-static int hpt374_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int hpt374_pre_reset(struct ata_link *link, unsigned long deadline)
 {
 	static const struct pci_bits hpt37x_enable_bits[] = {
 		{ 0x50, 1, 0x04, 0x04 },
@@ -362,6 +361,7 @@
 	};
 	u16 mcr3, mcr6;
 	u8 ata66;
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
 	if (!pci_test_config_bits(pdev, &hpt37x_enable_bits[ap->port_no]))
@@ -389,7 +389,7 @@
 	pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
 	udelay(100);
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -644,7 +644,6 @@
  */
 
 static struct ata_port_operations hpt370_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= hpt370_set_piomode,
 	.set_dmamode	= hpt370_set_dmamode,
 	.mode_filter	= hpt370_filter,
@@ -673,9 +672,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /*
@@ -683,7 +681,6 @@
  */
 
 static struct ata_port_operations hpt370a_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= hpt370_set_piomode,
 	.set_dmamode	= hpt370_set_dmamode,
 	.mode_filter	= hpt370a_filter,
@@ -712,9 +709,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /*
@@ -723,7 +719,6 @@
  */
 
 static struct ata_port_operations hpt372_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= hpt372_set_piomode,
 	.set_dmamode	= hpt372_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -752,9 +747,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /*
@@ -763,7 +757,6 @@
  */
 
 static struct ata_port_operations hpt374_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= hpt372_set_piomode,
 	.set_dmamode	= hpt372_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -792,9 +785,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /**
@@ -1092,9 +1084,7 @@
 		int dpll, adjust;
 
 		/* Compute DPLL */
-		dpll = 2;
-		if (port->udma_mask & 0xE0)
-			dpll = 3;
+		dpll = (port->udma_mask & 0xC0) ? 3 : 2;
 
 		f_low = (MHz[clock_slot] * 48) / MHz[dpll];
 		f_high = f_low + 2;
@@ -1103,20 +1093,20 @@
 
 		/* Select the DPLL clock. */
 		pci_write_config_byte(dev, 0x5b, 0x21);
-		pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
+		pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low | 0x100);
 
 		for(adjust = 0; adjust < 8; adjust++) {
 			if (hpt37x_calibrate_dpll(dev))
 				break;
 			/* See if it'll settle at a fractionally different clock */
-			if ((adjust & 3) == 3) {
-				f_low --;
-				f_high ++;
-			}
-			pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
+			if (adjust & 1)
+				f_low -= adjust >> 1;
+			else
+				f_high += adjust >> 1;
+			pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low | 0x100);
 		}
 		if (adjust == 8) {
-			printk(KERN_WARNING "hpt37x: DPLL did not stabilize.\n");
+			printk(KERN_ERR "pata_hpt37x: DPLL did not stabilize!\n");
 			return -ENODEV;
 		}
 		if (dpll == 3)
@@ -1124,7 +1114,8 @@
 		else
 			private_data = (void *)hpt37x_timings_50;
 
-		printk(KERN_INFO "hpt37x: Bus clock %dMHz, using DPLL.\n", MHz[dpll]);
+		printk(KERN_INFO "pata_hpt37x: bus clock %dMHz, using %dMHz DPLL.\n",
+		       MHz[clock_slot], MHz[dpll]);
 	} else {
 		private_data = (void *)chip_table->clocks[clock_slot];
 		/*
@@ -1137,7 +1128,8 @@
 			port = &info_hpt370_33;
 		if (clock_slot < 2 && port == &info_hpt370a)
 			port = &info_hpt370a_33;
-		printk(KERN_INFO "hpt37x: %s: Bus clock %dMHz.\n", chip_table->name, MHz[clock_slot]);
+		printk(KERN_INFO "pata_hpt37x: %s using %dMHz bus clock.\n",
+		       chip_table->name, MHz[clock_slot]);
 	}
 
 	/* Now kick off ATA set up */
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index aa29cde..9f1c084 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -8,7 +8,7 @@
  * Copyright (C) 1999-2003		Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
  * Portions Copyright (C) 2003		Red Hat Inc
- * Portions Copyright (C) 2005-2006	MontaVista Software, Inc.
+ * Portions Copyright (C) 2005-2007	MontaVista Software, Inc.
  *
  *
  * TODO
@@ -25,7 +25,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"pata_hpt3x2n"
-#define DRV_VERSION	"0.3.3"
+#define DRV_VERSION	"0.3.4"
 
 enum {
 	HPT_PCI_FAST	=	(1 << 31),
@@ -141,21 +141,22 @@
 
 /**
  *	hpt3x2n_pre_reset	-	reset the hpt3x2n bus
- *	@ap: ATA port to reset
+ *	@link: ATA link to reset
  *	@deadline: deadline jiffies for the operation
  *
  *	Perform the initial reset handling for the 3x2n series controllers.
  *	Reset the hardware and state machine,
  */
 
-static int hpt3xn_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int hpt3xn_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	/* Reset the state machine */
 	pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
 	udelay(100);
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -360,7 +361,6 @@
  */
 
 static struct ata_port_operations hpt3x2n_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= hpt3x2n_set_piomode,
 	.set_dmamode	= hpt3x2n_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -390,9 +390,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /**
@@ -579,10 +578,12 @@
 		pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
 	}
 	if (adjust == 8) {
-		printk(KERN_WARNING "hpt3x2n: DPLL did not stabilize.\n");
+		printk(KERN_ERR "pata_hpt3x2n: DPLL did not stabilize!\n");
 		return -ENODEV;
 	}
 
+	printk(KERN_INFO "pata_hpt37x: bus clock %dMHz, using 66MHz DPLL.\n",
+	       pci_mhz);
 	/* Set our private data up. We only need a few flags so we use
 	   it directly */
 	port.private_data = NULL;
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index be0f05e..cb8bdb6 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -120,7 +120,6 @@
 };
 
 static struct ata_port_operations hpt3x3_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= hpt3x3_set_piomode,
 #if defined(CONFIG_PATA_HPT3X3_DMA)
 	.set_dmamode	= hpt3x3_set_dmamode,
@@ -153,9 +152,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /**
@@ -239,7 +237,8 @@
 	base = host->iomap[4];	/* Bus mastering base */
 
 	for (i = 0; i < host->n_ports; i++) {
-		struct ata_ioports *ioaddr = &host->ports[i]->ioaddr;
+		struct ata_port *ap = host->ports[i];
+		struct ata_ioports *ioaddr = &ap->ioaddr;
 
 		ioaddr->cmd_addr = base + offset_cmd[i];
 		ioaddr->altstatus_addr =
@@ -247,6 +246,9 @@
 		ioaddr->scr_addr = NULL;
 		ata_std_ports(ioaddr);
 		ioaddr->bmdma_addr = base + 8 * i;
+
+		ata_port_pbar_desc(ap, 4, -1, "ioport");
+		ata_port_pbar_desc(ap, 4, offset_cmd[i], "cmd");
 	}
 	pci_set_master(pdev);
 	return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED,
diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c
index 321d98b..be30923 100644
--- a/drivers/ata/pata_icside.c
+++ b/drivers/ata/pata_icside.c
@@ -70,6 +70,8 @@
 	unsigned int		mwdma_mask;
 	unsigned int		nr_ports;
 	const struct portinfo	*port[2];
+	unsigned long		raw_base;
+	unsigned long		raw_ioc_base;
 };
 
 #define ICS_TYPE_A3IN	0
@@ -330,17 +332,12 @@
 {
 }
 
-/*
- * We need to shut down unused ports to prevent spurious interrupts.
- * FIXME: the libata core doesn't call this function for PATA interfaces.
- */
-static void pata_icside_port_disable(struct ata_port *ap)
+static void pata_icside_postreset(struct ata_port *ap, unsigned int *classes)
 {
 	struct pata_icside_state *state = ap->host->private_data;
 
-	ata_port_printk(ap, KERN_ERR, "disabling icside port\n");
-
-	ata_port_disable(ap);
+	if (classes[0] != ATA_DEV_NONE || classes[1] != ATA_DEV_NONE)
+		return ata_std_postreset(ap, classes);
 
 	state->port[ap->port_no].disabled = 1;
 
@@ -356,26 +353,13 @@
 	}
 }
 
-static u8 pata_icside_irq_ack(struct ata_port *ap, unsigned int chk_drq)
+static void pata_icside_error_handler(struct ata_port *ap)
 {
-	unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
-	u8 status;
-
-	status = ata_busy_wait(ap, bits, 1000);
-	if (status & bits)
-		if (ata_msg_err(ap))
-			printk(KERN_ERR "abnormal status 0x%X\n", status);
-
-	if (ata_msg_intr(ap))
-		printk(KERN_INFO "%s: irq ack: drv_stat 0x%X\n",
-			__FUNCTION__, status);
-
-	return status;
+	ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, NULL,
+			   pata_icside_postreset);
 }
 
 static struct ata_port_operations pata_icside_port_ops = {
-	.port_disable		= pata_icside_port_disable,
-
 	.set_dmamode		= pata_icside_set_dmamode,
 
 	.tf_load		= ata_tf_load,
@@ -397,12 +381,11 @@
 
 	.freeze			= ata_bmdma_freeze,
 	.thaw			= ata_bmdma_thaw,
-	.error_handler		= ata_bmdma_error_handler,
+	.error_handler		= pata_icside_error_handler,
 	.post_internal_cmd	= pata_icside_bmdma_stop,
 
 	.irq_clear		= ata_dummy_noret,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= pata_icside_irq_ack,
 
 	.port_start		= pata_icside_port_start,
 
@@ -411,9 +394,10 @@
 };
 
 static void __devinit
-pata_icside_setup_ioaddr(struct ata_ioports *ioaddr, void __iomem *base,
+pata_icside_setup_ioaddr(struct ata_port *ap, void __iomem *base,
 			 const struct portinfo *info)
 {
+	struct ata_ioports *ioaddr = &ap->ioaddr;
 	void __iomem *cmd = base + info->dataoffset;
 
 	ioaddr->cmd_addr	= cmd;
@@ -430,6 +414,13 @@
 
 	ioaddr->ctl_addr	= base + info->ctrloffset;
 	ioaddr->altstatus_addr	= ioaddr->ctl_addr;
+
+	ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx",
+		      info->raw_base + info->dataoffset,
+		      info->raw_base + info->ctrloffset);
+
+	if (info->raw_ioc_base)
+		ata_port_desc(ap, "iocbase 0x%lx", info->raw_ioc_base);
 }
 
 static int __devinit pata_icside_register_v5(struct pata_icside_info *info)
@@ -450,6 +441,8 @@
 	info->nr_ports = 1;
 	info->port[0] = &pata_icside_portinfo_v5;
 
+	info->raw_base = ecard_resource_start(ec, ECARD_RES_MEMC);
+
 	return 0;
 }
 
@@ -484,19 +477,15 @@
 	state->port[0].port_sel = sel;
 	state->port[1].port_sel = sel | 1;
 
-	/*
-	 * FIXME: work around libata's aversion to calling port_disable.
-	 * This permanently disables interrupts on port 0 - bad luck if
-	 * you have a drive on that port.
-	 */
-	state->port[0].disabled = 1;
-
 	info->base = easi_base;
 	info->irqops = &pata_icside_ops_arcin_v6;
 	info->nr_ports = 2;
 	info->port[0] = &pata_icside_portinfo_v6_1;
 	info->port[1] = &pata_icside_portinfo_v6_2;
 
+	info->raw_base = ecard_resource_start(ec, ECARD_RES_EASI);
+	info->raw_ioc_base = ecard_resource_start(ec, ECARD_RES_IOCFAST);
+
 	return icside_dma_init(info);
 }
 
@@ -533,7 +522,7 @@
 		ap->flags |= ATA_FLAG_SLAVE_POSS;
 		ap->ops = &pata_icside_port_ops;
 
-		pata_icside_setup_ioaddr(&ap->ioaddr, info->base, info->port[i]);
+		pata_icside_setup_ioaddr(ap, info->base, info->port[i]);
 	}
 
 	return ata_host_activate(host, ec->irq, ata_interrupt, 0,
diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c
index 5525518..88ab0e1 100644
--- a/drivers/ata/pata_isapnp.c
+++ b/drivers/ata/pata_isapnp.c
@@ -17,7 +17,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_isapnp"
-#define DRV_VERSION "0.2.1"
+#define DRV_VERSION "0.2.2"
 
 static struct scsi_host_template isapnp_sht = {
 	.module			= THIS_MODULE,
@@ -38,7 +38,6 @@
 };
 
 static struct ata_port_operations isapnp_port_ops = {
-	.port_disable	= ata_port_disable,
 	.tf_load	= ata_tf_load,
 	.tf_read	= ata_tf_read,
 	.check_status 	= ata_check_status,
@@ -58,9 +57,8 @@
 
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /**
@@ -112,6 +110,10 @@
 
 	ata_std_ports(&ap->ioaddr);
 
+	ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
+		      (unsigned long long)pnp_port_start(idev, 0),
+		      (unsigned long long)pnp_port_start(idev, 1));
+
 	/* activate */
 	return ata_host_activate(host, pnp_irq(idev, 0), ata_interrupt, 0,
 				 &isapnp_sht);
@@ -139,6 +141,8 @@
 	{.id = ""}
 };
 
+MODULE_DEVICE_TABLE(pnp, isapnp_devices);
+
 static struct pnp_driver isapnp_driver = {
 	.name		= DRV_NAME,
 	.id_table	= isapnp_devices,
diff --git a/drivers/ata/pata_it8213.c b/drivers/ata/pata_it8213.c
index b8af55e..1eda821 100644
--- a/drivers/ata/pata_it8213.c
+++ b/drivers/ata/pata_it8213.c
@@ -23,23 +23,24 @@
 
 /**
  *	it8213_pre_reset	-	check for 40/80 pin
- *	@ap: Port
+ *	@link: link
  *	@deadline: deadline jiffies for the operation
  *
  *	Filter out ports by the enable bits before doing the normal reset
  *	and probe.
  */
 
-static int it8213_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int it8213_pre_reset(struct ata_link *link, unsigned long deadline)
 {
 	static const struct pci_bits it8213_enable_bits[] = {
 		{ 0x41U, 1U, 0x80UL, 0x80UL },	/* port 0 */
 	};
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	if (!pci_test_config_bits(pdev, &it8213_enable_bits[ap->port_no]))
 		return -ENOENT;
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -260,7 +261,6 @@
 };
 
 static const struct ata_port_operations it8213_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= it8213_set_piomode,
 	.set_dmamode		= it8213_set_dmamode,
 	.mode_filter		= ata_pci_default_filter,
@@ -288,9 +288,8 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
-	.port_start		= ata_port_start,
+	.port_start		= ata_sff_port_start,
 };
 
 
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 430673b..988ef73 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -80,7 +80,7 @@
 
 
 #define DRV_NAME "pata_it821x"
-#define DRV_VERSION "0.3.7"
+#define DRV_VERSION "0.3.8"
 
 struct it821x_dev
 {
@@ -391,7 +391,7 @@
 {
 	struct it821x_dev *itdev = ap->private_data;
 	if (itdev && device != itdev->last_device) {
-		struct ata_device *adev = &ap->device[device];
+		struct ata_device *adev = &ap->link.device[device];
 		it821x_program(ap, adev, itdev->pio[adev->devno]);
 		itdev->last_device = device;
 	}
@@ -450,7 +450,7 @@
 
 /**
  *	it821x_smart_set_mode	-	mode setting
- *	@ap: interface to set up
+ *	@link: interface to set up
  *	@unused: device that failed (error only)
  *
  *	Use a non standard set_mode function. We don't want to be tuned.
@@ -459,12 +459,11 @@
  *	and respect them.
  */
 
-static int it821x_smart_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unused)
 {
-	int i;
+	struct ata_device *dev;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
+	ata_link_for_each_dev(dev, link) {
 		if (ata_dev_enabled(dev)) {
 			/* We don't really care */
 			dev->pio_mode = XFER_PIO_0;
@@ -533,6 +532,10 @@
 	struct ata_port *ap = qc->ap;
 	struct it821x_dev *itdev = ap->private_data;
 
+	/* Only use dma for transfers to/from the media. */
+	if (qc->nbytes < 2048)
+		return -EOPNOTSUPP;
+
 	/* No ATAPI DMA in smart mode */
 	if (itdev->smart)
 		return -EOPNOTSUPP;
@@ -560,7 +563,7 @@
 	struct it821x_dev *itdev;
 	u8 conf;
 
-	int ret = ata_port_start(ap);
+	int ret = ata_sff_port_start(ap);
 	if (ret < 0)
 		return ret;
 
@@ -587,7 +590,7 @@
 	itdev->want[1][1] = ATA_ANY;
 	itdev->last_device = -1;
 
-	if (pdev->revision == 0x11) {
+	if (pdev->revision == 0x10) {
 		itdev->timing10 = 1;
 		/* Need to disable ATAPI DMA for this case */
 		if (!itdev->smart)
@@ -617,7 +620,6 @@
 
 static struct ata_port_operations it821x_smart_port_ops = {
 	.set_mode	= it821x_smart_set_mode,
-	.port_disable	= ata_port_disable,
 	.tf_load	= ata_tf_load,
 	.tf_read	= ata_tf_read,
 	.mode_filter	= ata_pci_default_filter,
@@ -647,13 +649,11 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
 	.port_start	= it821x_port_start,
 };
 
 static struct ata_port_operations it821x_passthru_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= it821x_passthru_set_piomode,
 	.set_dmamode	= it821x_passthru_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -684,7 +684,6 @@
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_handler	= ata_interrupt,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
 	.port_start	= it821x_port_start,
 };
diff --git a/drivers/ata/pata_ixp4xx_cf.c b/drivers/ata/pata_ixp4xx_cf.c
index 4ca7fd6..fcd532a 100644
--- a/drivers/ata/pata_ixp4xx_cf.c
+++ b/drivers/ata/pata_ixp4xx_cf.c
@@ -26,12 +26,11 @@
 #define DRV_NAME	"pata_ixp4xx_cf"
 #define DRV_VERSION	"0.2"
 
-static int ixp4xx_set_mode(struct ata_port *ap, struct ata_device **error)
+static int ixp4xx_set_mode(struct ata_link *link, struct ata_device **error)
 {
-	int i;
+	struct ata_device *dev;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
+	ata_link_for_each_dev(dev, link) {
 		if (ata_dev_enabled(dev)) {
 			ata_dev_printk(dev, KERN_INFO, "configured for PIO0\n");
 			dev->pio_mode = XFER_PIO_0;
@@ -49,7 +48,7 @@
 	unsigned int i;
 	unsigned int words = buflen >> 1;
 	u16 *buf16 = (u16 *) buf;
-	struct ata_port *ap = adev->ap;
+	struct ata_port *ap = adev->link->ap;
 	void __iomem *mmio = ap->ioaddr.data_addr;
 	struct ixp4xx_pata_data *data = ap->host->dev->platform_data;
 
@@ -108,7 +107,6 @@
 	.set_mode		= ixp4xx_set_mode,
 	.mode_filter		= ata_pci_default_filter,
 
-	.port_disable		= ata_port_disable,
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
 	.exec_command		= ata_exec_command,
@@ -128,14 +126,17 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_dummy_irq_ack,
 
 	.port_start		= ata_port_start,
 };
 
 static void ixp4xx_setup_port(struct ata_ioports *ioaddr,
-				struct ixp4xx_pata_data *data)
+			      struct ixp4xx_pata_data *data,
+			      unsigned long raw_cs0, unsigned long raw_cs1)
 {
+	unsigned long raw_cmd = raw_cs0;
+	unsigned long raw_ctl = raw_cs1 + 0x06;
+
 	ioaddr->cmd_addr	= data->cs0;
 	ioaddr->altstatus_addr	= data->cs1 + 0x06;
 	ioaddr->ctl_addr	= data->cs1 + 0x06;
@@ -161,7 +162,12 @@
 	*(unsigned long *)&ioaddr->device_addr		^= 0x03;
 	*(unsigned long *)&ioaddr->status_addr		^= 0x03;
 	*(unsigned long *)&ioaddr->command_addr		^= 0x03;
+
+	raw_cmd ^= 0x03;
+	raw_ctl ^= 0x03;
 #endif
+
+	ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", raw_cmd, raw_ctl);
 }
 
 static __devinit int ixp4xx_pata_probe(struct platform_device *pdev)
@@ -189,6 +195,9 @@
 	data->cs0 = devm_ioremap(&pdev->dev, cs0->start, 0x1000);
 	data->cs1 = devm_ioremap(&pdev->dev, cs1->start, 0x1000);
 
+	if (!data->cs0 || !data->cs1)
+		return -ENOMEM;
+
 	irq = platform_get_irq(pdev, 0);
 	if (irq)
 		set_irq_type(irq, IRQT_RISING);
@@ -203,7 +212,7 @@
 	ap->pio_mask = 0x1f; /* PIO4 */
 	ap->flags |= ATA_FLAG_MMIO | ATA_FLAG_NO_LEGACY | ATA_FLAG_NO_ATAPI;
 
-	ixp4xx_setup_port(&ap->ioaddr, data);
+	ixp4xx_setup_port(ap, data, cs0->start, cs1->start);
 
 	dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
 
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
index 4d67f23..225a722 100644
--- a/drivers/ata/pata_jmicron.c
+++ b/drivers/ata/pata_jmicron.c
@@ -29,7 +29,7 @@
 
 /**
  *	jmicron_pre_reset	-	check for 40/80 pin
- *	@ap: Port
+ *	@link: ATA link
  *	@deadline: deadline jiffies for the operation
  *
  *	Perform the PATA port setup we need.
@@ -39,9 +39,9 @@
  *	and setup here. We assume that has been done by init_one and the
  *	BIOS.
  */
-
-static int jmicron_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int jmicron_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	u32 control;
 	u32 control5;
@@ -103,7 +103,7 @@
 		ap->cbl = ATA_CBL_SATA;
 		break;
 	}
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -141,8 +141,6 @@
 };
 
 static const struct ata_port_operations jmicron_ops = {
-	.port_disable		= ata_port_disable,
-
 	/* Task file is PCI ATA format, use helpers */
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
@@ -168,7 +166,6 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	/* Generic PATA PCI ATA helpers */
 	.port_start		= ata_port_start,
@@ -207,17 +204,8 @@
 }
 
 static const struct pci_device_id jmicron_pci_tbl[] = {
-	{ PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361,
-	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 361 },
-	{ PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363,
-	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 363 },
-	{ PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365,
-	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 365 },
-	{ PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366,
-	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 366 },
-	{ PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368,
-	  PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 368 },
-
+	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+	  PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 },
 	{ }	/* terminate list */
 };
 
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index edffc25..7bed8d8 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -96,7 +96,7 @@
 
 /**
  *	legacy_set_mode		-	mode setting
- *	@ap: IDE interface
+ *	@link: IDE link
  *	@unused: Device that failed when error is returned
  *
  *	Use a non standard set_mode function. We don't want to be tuned.
@@ -107,12 +107,11 @@
  *	expand on this as per hdparm in the base kernel.
  */
 
-static int legacy_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int legacy_set_mode(struct ata_link *link, struct ata_device **unused)
 {
-	int i;
+	struct ata_device *dev;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
+	ata_link_for_each_dev(dev, link) {
 		if (ata_dev_enabled(dev)) {
 			ata_dev_printk(dev, KERN_INFO, "configured for PIO\n");
 			dev->pio_mode = XFER_PIO_0;
@@ -151,7 +150,6 @@
  */
 
 static struct ata_port_operations simple_port_ops = {
-	.port_disable	= ata_port_disable,
 	.tf_load	= ata_tf_load,
 	.tf_read	= ata_tf_read,
 	.check_status 	= ata_check_status,
@@ -172,7 +170,6 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
 	.port_start	= ata_port_start,
 };
@@ -180,7 +177,6 @@
 static struct ata_port_operations legacy_port_ops = {
 	.set_mode	= legacy_set_mode,
 
-	.port_disable	= ata_port_disable,
 	.tf_load	= ata_tf_load,
 	.tf_read	= ata_tf_read,
 	.check_status 	= ata_check_status,
@@ -201,7 +197,6 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
 	.port_start	= ata_port_start,
 };
@@ -256,7 +251,7 @@
 
 static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
 {
-	struct ata_port *ap = adev->ap;
+	struct ata_port *ap = adev->link->ap;
 	int slop = buflen & 3;
 	unsigned long flags;
 
@@ -296,7 +291,6 @@
 static struct ata_port_operations pdc20230_port_ops = {
 	.set_piomode	= pdc20230_set_piomode,
 
-	.port_disable	= ata_port_disable,
 	.tf_load	= ata_tf_load,
 	.tf_read	= ata_tf_read,
 	.check_status 	= ata_check_status,
@@ -317,7 +311,6 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
 	.port_start	= ata_port_start,
 };
@@ -352,7 +345,6 @@
 static struct ata_port_operations ht6560a_port_ops = {
 	.set_piomode	= ht6560a_set_piomode,
 
-	.port_disable	= ata_port_disable,
 	.tf_load	= ata_tf_load,
 	.tf_read	= ata_tf_read,
 	.check_status 	= ata_check_status,
@@ -373,7 +365,6 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
 	.port_start	= ata_port_start,
 };
@@ -419,7 +410,6 @@
 static struct ata_port_operations ht6560b_port_ops = {
 	.set_piomode	= ht6560b_set_piomode,
 
-	.port_disable	= ata_port_disable,
 	.tf_load	= ata_tf_load,
 	.tf_read	= ata_tf_read,
 	.check_status 	= ata_check_status,
@@ -440,7 +430,6 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
 	.port_start	= ata_port_start,
 };
@@ -541,7 +530,6 @@
 static struct ata_port_operations opti82c611a_port_ops = {
 	.set_piomode	= opti82c611a_set_piomode,
 
-	.port_disable	= ata_port_disable,
 	.tf_load	= ata_tf_load,
 	.tf_read	= ata_tf_read,
 	.check_status 	= ata_check_status,
@@ -562,7 +550,6 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
 	.port_start	= ata_port_start,
 };
@@ -675,7 +662,6 @@
 static struct ata_port_operations opti82c46x_port_ops = {
 	.set_piomode	= opti82c46x_set_piomode,
 
-	.port_disable	= ata_port_disable,
 	.tf_load	= ata_tf_load,
 	.tf_read	= ata_tf_read,
 	.check_status 	= ata_check_status,
@@ -696,7 +682,6 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
 	.port_start	= ata_port_start,
 };
@@ -814,6 +799,8 @@
 	ata_std_ports(&ap->ioaddr);
 	ap->private_data = ld;
 
+	ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io, ctrl);
+
 	ret = ata_host_activate(host, irq, ata_interrupt, 0, &legacy_sht);
 	if (ret)
 		goto fail;
diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c
index 87594c0..9afc8a3 100644
--- a/drivers/ata/pata_marvell.c
+++ b/drivers/ata/pata_marvell.c
@@ -24,14 +24,15 @@
 
 /**
  *	marvell_pre_reset	-	check for 40/80 pin
- *	@ap: Port
+ *	@link: link
  *	@deadline: deadline jiffies for the operation
  *
  *	Perform the PATA port setup we need.
  */
 
-static int marvell_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int marvell_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	u32 devices;
 	void __iomem *barp;
@@ -44,17 +45,17 @@
 		return -ENOMEM;
 	printk("BAR5:");
 	for(i = 0; i <= 0x0F; i++)
-		printk("%02X:%02X ", i, readb(barp + i));
+		printk("%02X:%02X ", i, ioread8(barp + i));
 	printk("\n");
 
-	devices = readl(barp + 0x0C);
+	devices = ioread32(barp + 0x0C);
 	pci_iounmap(pdev, barp);
 
 	if ((pdev->device == 0x6145) && (ap->port_no == 0) &&
 	    (!(devices & 0x10)))	/* PATA enable ? */
 		return -ENOENT;
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 static int marvell_cable_detect(struct ata_port *ap)
@@ -110,8 +111,6 @@
 };
 
 static const struct ata_port_operations marvell_ops = {
-	.port_disable		= ata_port_disable,
-
 	/* Task file is PCI ATA format, use helpers */
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
@@ -138,10 +137,9 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	/* Generic PATA PCI ATA helpers */
-	.port_start		= ata_port_start,
+	.port_start		= ata_sff_port_start,
 };
 
 
@@ -192,6 +190,8 @@
 
 static const struct pci_device_id marvell_pci_tbl[] = {
 	{ PCI_DEVICE(0x11AB, 0x6101), },
+	{ PCI_DEVICE(0x11AB, 0x6121), },
+	{ PCI_DEVICE(0x11AB, 0x6123), },
 	{ PCI_DEVICE(0x11AB, 0x6145), },
 	{ }	/* terminate list */
 };
diff --git a/drivers/ata/pata_mpc52xx.c b/drivers/ata/pata_mpc52xx.c
index 182e83c..412140f 100644
--- a/drivers/ata/pata_mpc52xx.c
+++ b/drivers/ata/pata_mpc52xx.c
@@ -24,7 +24,7 @@
 
 
 #define DRV_NAME	"mpc52xx_ata"
-#define DRV_VERSION	"0.1.0ac2"
+#define DRV_VERSION	"0.1.2"
 
 
 /* Private structures used by the driver */
@@ -283,7 +283,6 @@
 };
 
 static struct ata_port_operations mpc52xx_ata_port_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= mpc52xx_ata_set_piomode,
 	.dev_select		= mpc52xx_ata_dev_select,
 	.tf_load		= ata_tf_load,
@@ -299,12 +298,12 @@
 	.data_xfer		= ata_data_xfer,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 	.port_start		= ata_port_start,
 };
 
 static int __devinit
-mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv)
+mpc52xx_ata_init_one(struct device *dev, struct mpc52xx_ata_priv *priv,
+		     unsigned long raw_ata_regs)
 {
 	struct ata_host *host;
 	struct ata_port *ap;
@@ -338,6 +337,8 @@
 	aio->status_addr	= &priv->ata_regs->tf_command;
 	aio->command_addr	= &priv->ata_regs->tf_command;
 
+	ata_port_desc(ap, "ata_regs 0x%lx", raw_ata_regs);
+
 	/* activate host */
 	return ata_host_activate(host, priv->ata_irq, ata_interrupt, 0,
 				 &mpc52xx_ata_sht);
@@ -434,7 +435,7 @@
 	}
 
 	/* Register ourselves to libata */
-	rv = mpc52xx_ata_init_one(&op->dev, priv);
+	rv = mpc52xx_ata_init_one(&op->dev, priv, res_mem.start);
 	if (rv) {
 		printk(KERN_ERR DRV_NAME ": "
 			"Error while registering to ATA layer\n");
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
index 4ea4283..d548308 100644
--- a/drivers/ata/pata_mpiix.c
+++ b/drivers/ata/pata_mpiix.c
@@ -46,15 +46,16 @@
 	SECONDARY = (1 << 14)
 };
 
-static int mpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int mpiix_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	static const struct pci_bits mpiix_enable_bits = { 0x6D, 1, 0x80, 0x80 };
 
 	if (!pci_test_config_bits(pdev, &mpiix_enable_bits))
 		return -ENOENT;
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -168,7 +169,6 @@
 };
 
 static struct ata_port_operations mpiix_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= mpiix_set_piomode,
 
 	.tf_load	= ata_tf_load,
@@ -189,9 +189,8 @@
 
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
@@ -202,7 +201,7 @@
 	struct ata_port *ap;
 	void __iomem *cmd_addr, *ctl_addr;
 	u16 idetim;
-	int irq;
+	int cmd, ctl, irq;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
@@ -210,6 +209,7 @@
 	host = ata_host_alloc(&dev->dev, 1);
 	if (!host)
 		return -ENOMEM;
+	ap = host->ports[0];
 
 	/* MPIIX has many functions which can be turned on or off according
 	   to other devices present. Make sure IDE is enabled before we try
@@ -221,25 +221,28 @@
 
 	/* See if it's primary or secondary channel... */
 	if (!(idetim & SECONDARY)) {
+		cmd = 0x1F0;
+		ctl = 0x3F6;
 		irq = 14;
-		cmd_addr = devm_ioport_map(&dev->dev, 0x1F0, 8);
-		ctl_addr = devm_ioport_map(&dev->dev, 0x3F6, 1);
 	} else {
+		cmd = 0x170;
+		ctl = 0x376;
 		irq = 15;
-		cmd_addr = devm_ioport_map(&dev->dev, 0x170, 8);
-		ctl_addr = devm_ioport_map(&dev->dev, 0x376, 1);
 	}
 
+	cmd_addr = devm_ioport_map(&dev->dev, cmd, 8);
+	ctl_addr = devm_ioport_map(&dev->dev, ctl, 1);
 	if (!cmd_addr || !ctl_addr)
 		return -ENOMEM;
 
+	ata_port_desc(ap, "cmd 0x%x ctl 0x%x", cmd, ctl);
+
 	/* We do our own plumbing to avoid leaking special cases for whacko
 	   ancient hardware into the core code. There are two issues to
 	   worry about.  #1 The chip is a bridge so if in legacy mode and
 	   without BARs set fools the setup.  #2 If you pci_disable_device
 	   the MPIIX your box goes castors up */
 
-	ap = host->ports[0];
 	ap->ops = &mpiix_port_ops;
 	ap->pio_mask = 0x1F;
 	ap->flags |= ATA_FLAG_SLAVE_POSS;
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
index 40eb574..25c922a 100644
--- a/drivers/ata/pata_netcell.c
+++ b/drivers/ata/pata_netcell.c
@@ -40,8 +40,6 @@
 };
 
 static const struct ata_port_operations netcell_ops = {
-	.port_disable		= ata_port_disable,
-
 	/* Task file is PCI ATA format, use helpers */
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
@@ -68,10 +66,9 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	/* Generic PATA PCI ATA helpers */
-	.port_start		= ata_port_start,
+	.port_start		= ata_sff_port_start,
 };
 
 
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index 2f5d714..6e8e557 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -32,14 +32,15 @@
 
 /**
  *	ns87410_pre_reset		-	probe begin
- *	@ap: ATA port
+ *	@link: ATA link
  *	@deadline: deadline jiffies for the operation
  *
  *	Check enabled ports
  */
 
-static int ns87410_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int ns87410_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	static const struct pci_bits ns87410_enable_bits[] = {
 		{ 0x43, 1, 0x08, 0x08 },
@@ -49,7 +50,7 @@
 	if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no]))
 		return -ENOENT;
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -161,7 +162,6 @@
 };
 
 static struct ata_port_operations ns87410_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= ns87410_set_piomode,
 
 	.tf_load	= ata_tf_load,
@@ -184,9 +184,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_ns87415.c b/drivers/ata/pata_ns87415.c
new file mode 100644
index 0000000..bb97ef5
--- /dev/null
+++ b/drivers/ata/pata_ns87415.c
@@ -0,0 +1,467 @@
+/*
+ *    pata_ns87415.c - NS87415 (non PARISC) PATA
+ *
+ *	(C) 2005 Red Hat <alan@redhat.com>
+ *
+ *    This is a fairly generic MWDMA controller. It has some limitations
+ *    as it requires timing reloads on PIO/DMA transitions but it is otherwise
+ *    fairly well designed.
+ *
+ *    This driver assumes the firmware has left the chip in a valid ST506
+ *    compliant state, either legacy IRQ 14/15 or native INTA shared. You
+ *    may need to add platform code if your system fails to do this.
+ *
+ *    The same cell appears in the 87560 controller used by some PARISC
+ *    systems. This has its own special mountain of errata.
+ *
+ *    TODO:
+ *	Test PARISC SuperIO
+ *	Get someone to test on SPARC
+ *	Implement lazy pio/dma switching for better performance	
+ *	8bit shared timing.
+ *	See if we need to kill the FIFO for ATAPI
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME	"pata_ns87415"
+#define DRV_VERSION	"0.0.1"
+
+/**
+ *	ns87415_set_mode - Initialize host controller mode timings
+ *	@ap: Port whose timings we are configuring
+ *	@adev: Device whose timings we are configuring
+ *	@mode: Mode to set
+ *
+ *	Program the mode registers for this controller, channel and
+ *	device. Because the chip is quite an old design we have to do this
+ *	for PIO/DMA switches.
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ */
+
+static void ns87415_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode)
+{
+	struct pci_dev *dev	= to_pci_dev(ap->host->dev);
+	int unit		= 2 * ap->port_no + adev->devno;
+	int timing		= 0x44 + 2 * unit;
+	unsigned long T		= 1000000000 / 33333;	/* PCI clocks */
+	struct ata_timing t;
+	u16 clocking;
+	u8 iordy;
+	u8 status;
+	
+	/* Timing register format is 17 - low nybble read timing with
+	   the high nybble being 16 - x for recovery time in PCI clocks */
+   
+	ata_timing_compute(adev, adev->pio_mode, &t, T, 0);
+
+	clocking = 17 - FIT(t.active, 2, 17);
+	clocking |= (16 - FIT(t.recover, 1, 16)) << 4;
+ 	/* Use the same timing for read and write bytes */
+	clocking |= (clocking << 8);
+	pci_write_config_word(dev, timing, clocking);
+	
+	/* Set the IORDY enable versus DMA enable on or off properly */
+	pci_read_config_byte(dev, 0x42, &iordy);
+	iordy &= ~(1 << (4 + unit));
+	if (mode >= XFER_MW_DMA_0 || !ata_pio_need_iordy(adev))
+		iordy |= (1 << (4 + unit));
+
+	/* Paranoia: We shouldn't ever get here with busy write buffers
+	   but if so wait */
+
+	pci_read_config_byte(dev, 0x43, &status);
+	while (status & 0x03) {
+		udelay(1);
+		pci_read_config_byte(dev, 0x43, &status);
+	}
+	/* Flip the IORDY/DMA bits now we are sure the write buffers are
+	   clear */
+	pci_write_config_byte(dev, 0x42, iordy);
+
+	/* TODO: Set byte 54 command timing to the best 8bit
+	   mode shared by all four devices */
+}
+
+/**
+ *	ns87415_set_piomode - Initialize host controller PATA PIO timings
+ *	@ap: Port whose timings we are configuring
+ *	@adev: Device to program
+ *
+ *	Set PIO mode for device, in host controller PCI config space.
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ */
+
+static void ns87415_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+	ns87415_set_mode(ap, adev, adev->pio_mode);
+}
+
+/**
+ *	ns87415_bmdma_setup		-	Set up DMA
+ *	@qc: Command block
+ *
+ *	Set up for bus masterng DMA. We have to do this ourselves
+ *	rather than use the helper due to a chip erratum
+ */
+
+static void ns87415_bmdma_setup(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+	u8 dmactl;
+
+	/* load PRD table addr. */
+	mb();	/* make sure PRD table writes are visible to controller */
+	iowrite32(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
+
+	/* specify data direction, triple-check start bit is clear */
+	dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+	dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+	/* Due to an erratum we need to write these bits to the wrong
+	   place - which does save us an I/O bizarrely */
+	dmactl |= ATA_DMA_INTR | ATA_DMA_ERR;
+	if (!rw)
+		dmactl |= ATA_DMA_WR;
+	iowrite8(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+	/* issue r/w command */
+	ap->ops->exec_command(ap, &qc->tf);
+}
+
+/**
+ *	ns87415_bmdma_start		-	Begin DMA transfer
+ *	@qc: Command block
+ *
+ *	Switch the timings for the chip and set up for a DMA transfer
+ *	before the DMA burst begins.
+ *
+ *	FIXME: We should do lazy switching on bmdma_start versus
+ *	ata_pio_data_xfer for better performance.
+ */
+
+static void ns87415_bmdma_start(struct ata_queued_cmd *qc)
+{
+	ns87415_set_mode(qc->ap, qc->dev, qc->dev->dma_mode);
+	ata_bmdma_start(qc);
+}
+
+/**
+ *	ns87415_bmdma_stop		-	End DMA transfer
+ *	@qc: Command block
+ *
+ *	End DMA mode and switch the controller back into PIO mode
+ */
+
+static void ns87415_bmdma_stop(struct ata_queued_cmd *qc)
+{
+	ata_bmdma_stop(qc);
+	ns87415_set_mode(qc->ap, qc->dev, qc->dev->pio_mode);
+}
+
+/**
+ *	ns87415_bmdma_irq_clear		-	Clear interrupt
+ *	@ap: Channel to clear
+ *
+ *	Erratum: Due to a chip bug regisers 02 and 0A bit 1 and 2 (the
+ *	error bits) are reset by writing to register 00 or 08.
+ */
+
+static void ns87415_bmdma_irq_clear(struct ata_port *ap)
+{
+	void __iomem *mmio = ap->ioaddr.bmdma_addr;
+
+	if (!mmio)
+		return;
+	iowrite8((ioread8(mmio + ATA_DMA_CMD) | ATA_DMA_INTR | ATA_DMA_ERR), 
+			mmio + ATA_DMA_CMD);
+}
+
+/**
+ *	ns87415_check_atapi_dma		-	ATAPI DMA filter
+ *	@qc: Command block
+ *
+ *	Disable ATAPI DMA (for now). We may be able to do DMA if we
+ *	kill the prefetching. This isn't clear.
+ */
+
+static int ns87415_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+	return -EOPNOTSUPP;
+}
+
+#if defined(CONFIG_SUPERIO)
+
+/* SUPERIO 87560 is a PoS chip that NatSem denies exists.
+ * Unfortunately, it's built-in on all Astro-based PA-RISC workstations
+ * which use the integrated NS87514 cell for CD-ROM support.
+ * i.e we have to support for CD-ROM installs.
+ * See drivers/parisc/superio.c for more gory details.
+ *
+ * Workarounds taken from drivers/ide/pci/ns87415.c
+ */
+
+#include <asm/superio.h>
+
+/**
+ *	ns87560_read_buggy	-	workaround buggy Super I/O chip
+ *	@port: Port to read
+ *
+ *	Work around chipset problems in the 87560 SuperIO chip
+ */
+
+static u8 ns87560_read_buggy(void __iomem *port)
+{
+	u8 tmp;
+	int retries = SUPERIO_IDE_MAX_RETRIES;
+	do {
+		tmp = ioread8(port);
+		if (tmp != 0)
+			return tmp;
+		udelay(50);
+	} while(retries-- > 0);
+	return tmp;
+}
+
+/**
+ *	ns87560_check_status
+ *	@ap: channel to check
+ *
+ *	Return the status of the channel working around the
+ *	87560 flaws.
+ */
+
+static u8 ns87560_check_status(struct ata_port *ap)
+{
+	return ns87560_read_buggy(ap->ioaddr.status_addr);
+}
+
+/**
+ *	ns87560_tf_read - input device's ATA taskfile shadow registers
+ *	@ap: Port from which input is read
+ *	@tf: ATA taskfile register set for storing input
+ *
+ *	Reads ATA taskfile registers for currently-selected device
+ *	into @tf. Work around the 87560 bugs.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+void ns87560_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+
+	tf->command = ns87560_check_status(ap);
+	tf->feature = ioread8(ioaddr->error_addr);
+	tf->nsect = ioread8(ioaddr->nsect_addr);
+	tf->lbal = ioread8(ioaddr->lbal_addr);
+	tf->lbam = ioread8(ioaddr->lbam_addr);
+	tf->lbah = ioread8(ioaddr->lbah_addr);
+	tf->device = ns87560_read_buggy(ioaddr->device_addr);
+
+	if (tf->flags & ATA_TFLAG_LBA48) {
+		iowrite8(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+		tf->hob_feature = ioread8(ioaddr->error_addr);
+		tf->hob_nsect = ioread8(ioaddr->nsect_addr);
+		tf->hob_lbal = ioread8(ioaddr->lbal_addr);
+		tf->hob_lbam = ioread8(ioaddr->lbam_addr);
+		tf->hob_lbah = ioread8(ioaddr->lbah_addr);
+		iowrite8(tf->ctl, ioaddr->ctl_addr);
+		ap->last_ctl = tf->ctl;
+	}
+}
+
+/**
+ *	ns87560_bmdma_status
+ *	@ap: channel to check
+ *
+ *	Return the DMA status of the channel working around the
+ *	87560 flaws.
+ */
+
+static u8 ns87560_bmdma_status(struct ata_port *ap)
+{
+	return ns87560_read_buggy(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+}
+
+static const struct ata_port_operations ns87560_pata_ops = {
+	.set_piomode		= ns87415_set_piomode,
+	.mode_filter		= ata_pci_default_filter,
+
+	.tf_load		= ata_tf_load,
+	.tf_read		= ns87560_tf_read,
+	.check_status		= ns87560_check_status,
+	.check_atapi_dma	= ns87415_check_atapi_dma,
+	.exec_command		= ata_exec_command,
+	.dev_select		= ata_std_dev_select,
+
+	.freeze			= ata_bmdma_freeze,
+	.thaw			= ata_bmdma_thaw,
+	.error_handler		= ata_bmdma_error_handler,
+	.post_internal_cmd 	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= ata_cable_40wire,
+
+	.bmdma_setup		= ns87415_bmdma_setup,
+	.bmdma_start		= ns87415_bmdma_start,
+	.bmdma_stop		= ns87415_bmdma_stop,
+	.bmdma_status		= ns87560_bmdma_status,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+	.data_xfer		= ata_data_xfer,
+
+	.irq_handler		= ata_interrupt,
+	.irq_clear		= ns87415_bmdma_irq_clear,
+	.irq_on			= ata_irq_on,
+
+	.port_start		= ata_sff_port_start,
+};
+
+#endif		/* 87560 SuperIO Support */
+
+
+static const struct ata_port_operations ns87415_pata_ops = {
+	.set_piomode		= ns87415_set_piomode,
+	.mode_filter		= ata_pci_default_filter,
+
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.check_atapi_dma	= ns87415_check_atapi_dma,
+	.exec_command		= ata_exec_command,
+	.dev_select		= ata_std_dev_select,
+
+	.freeze			= ata_bmdma_freeze,
+	.thaw			= ata_bmdma_thaw,
+	.error_handler		= ata_bmdma_error_handler,
+	.post_internal_cmd 	= ata_bmdma_post_internal_cmd,
+	.cable_detect		= ata_cable_40wire,
+
+	.bmdma_setup		= ns87415_bmdma_setup,
+	.bmdma_start		= ns87415_bmdma_start,
+	.bmdma_stop		= ns87415_bmdma_stop,
+	.bmdma_status		= ata_bmdma_status,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+	.data_xfer		= ata_data_xfer,
+
+	.irq_handler		= ata_interrupt,
+	.irq_clear		= ns87415_bmdma_irq_clear,
+	.irq_on			= ata_irq_on,
+
+	.port_start		= ata_sff_port_start,
+};
+
+static struct scsi_host_template ns87415_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.slave_destroy		= ata_scsi_slave_destroy,
+	.bios_param		= ata_std_bios_param,
+};
+
+
+/**
+ *	ns87415_init_one - Register 87415 ATA PCI device with kernel services
+ *	@pdev: PCI device to register
+ *	@ent: Entry in ns87415_pci_tbl matching with @pdev
+ *
+ *	Called from kernel PCI layer.  We probe for combined mode (sigh),
+ *	and then hand over control to libata, for it to do the rest.
+ *
+ *	LOCKING:
+ *	Inherited from PCI layer (may sleep).
+ *
+ *	RETURNS:
+ *	Zero on success, or -ERRNO value.
+ */
+
+static int ns87415_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	static const struct ata_port_info info = {
+		.sht		= &ns87415_sht,
+		.flags		= ATA_FLAG_SLAVE_POSS,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.port_ops	= &ns87415_pata_ops,
+	};
+	const struct ata_port_info *ppi[] = { &info, NULL };
+#if defined(CONFIG_SUPERIO)
+	static const struct ata_port_info info87560 = {
+		.sht		= &ns87415_sht,
+		.flags		= ATA_FLAG_SLAVE_POSS,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.port_ops	= &ns87560_pata_ops,
+	};
+
+	if (PCI_SLOT(pdev->devfn) == 0x0E)
+		ppi[0] = &info87560;
+#endif
+	if (!printed_version++)
+		dev_printk(KERN_DEBUG, &pdev->dev,
+			   "version " DRV_VERSION "\n");
+	/* Select 512 byte sectors */
+	pci_write_config_byte(pdev, 0x55, 0xEE);
+	/* Select PIO0 8bit clocking */
+	pci_write_config_byte(pdev, 0x54, 0xB7);
+	return ata_pci_init_one(pdev, ppi);
+}
+
+static const struct pci_device_id ns87415_pci_tbl[] = {
+	{ PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87415), },
+
+	{ }	/* terminate list */
+};
+
+static struct pci_driver ns87415_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= ns87415_pci_tbl,
+	.probe			= ns87415_init_one,
+	.remove			= ata_pci_remove_one,
+#ifdef CONFIG_PM
+	.suspend		= ata_pci_device_suspend,
+	.resume			= ata_pci_device_resume,
+#endif
+};
+
+static int __init ns87415_init(void)
+{
+	return pci_register_driver(&ns87415_pci_driver);
+}
+
+static void __exit ns87415_exit(void)
+{
+	pci_unregister_driver(&ns87415_pci_driver);
+}
+
+module_init(ns87415_init);
+module_exit(ns87415_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("ATA low-level driver for NS87415 controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ns87415_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
index 091a70a..3cd5eb2 100644
--- a/drivers/ata/pata_oldpiix.c
+++ b/drivers/ata/pata_oldpiix.c
@@ -29,14 +29,15 @@
 
 /**
  *	oldpiix_pre_reset		-	probe begin
- *	@ap: ATA port
+ *	@link: ATA link
  *	@deadline: deadline jiffies for the operation
  *
  *	Set up cable type and use generic probe init
  */
 
-static int oldpiix_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int oldpiix_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	static const struct pci_bits oldpiix_enable_bits[] = {
 		{ 0x41U, 1U, 0x80UL, 0x80UL },	/* port 0 */
@@ -46,7 +47,7 @@
 	if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no]))
 		return -ENOENT;
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -237,7 +238,6 @@
 };
 
 static const struct ata_port_operations oldpiix_pata_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= oldpiix_set_piomode,
 	.set_dmamode		= oldpiix_set_dmamode,
 	.mode_filter		= ata_pci_default_filter,
@@ -265,9 +265,8 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
-	.port_start		= ata_port_start,
+	.port_start		= ata_sff_port_start,
 };
 
 
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
index 458bf67..8f79447 100644
--- a/drivers/ata/pata_opti.c
+++ b/drivers/ata/pata_opti.c
@@ -46,14 +46,15 @@
 
 /**
  *	opti_pre_reset		-	probe begin
- *	@ap: ATA port
+ *	@link: ATA link
  *	@deadline: deadline jiffies for the operation
  *
  *	Set up cable type and use generic probe init
  */
 
-static int opti_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int opti_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	static const struct pci_bits opti_enable_bits[] = {
 		{ 0x45, 1, 0x80, 0x00 },
@@ -63,7 +64,7 @@
 	if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no]))
 		return -ENOENT;
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -182,7 +183,6 @@
 };
 
 static struct ata_port_operations opti_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= opti_set_piomode,
 	.tf_load	= ata_tf_load,
 	.tf_read	= ata_tf_read,
@@ -209,9 +209,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
index f89bdfd..6b07b5b 100644
--- a/drivers/ata/pata_optidma.c
+++ b/drivers/ata/pata_optidma.c
@@ -47,14 +47,15 @@
 
 /**
  *	optidma_pre_reset		-	probe begin
- *	@ap: ATA port
+ *	@link: ATA link
  *	@deadline: deadline jiffies for the operation
  *
  *	Set up cable type and use generic probe init
  */
 
-static int optidma_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int optidma_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	static const struct pci_bits optidma_enable_bits = {
 		0x40, 1, 0x08, 0x00
@@ -63,7 +64,7 @@
 	if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits))
 		return -ENOENT;
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -323,25 +324,26 @@
 
 /**
  *	optidma_set_mode	-	mode setup
- *	@ap: port to set up
+ *	@link: link to set up
  *
  *	Use the standard setup to tune the chipset and then finalise the
  *	configuration by writing the nibble of extra bits of data into
  *	the chip.
  */
 
-static int optidma_set_mode(struct ata_port *ap, struct ata_device **r_failed)
+static int optidma_set_mode(struct ata_link *link, struct ata_device **r_failed)
 {
+	struct ata_port *ap = link->ap;
 	u8 r;
 	int nybble = 4 * ap->port_no;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-	int rc  = ata_do_set_mode(ap, r_failed);
+	int rc  = ata_do_set_mode(link, r_failed);
 	if (rc == 0) {
 		pci_read_config_byte(pdev, 0x43, &r);
 
 		r &= (0x0F << nybble);
-		r |= (optidma_make_bits43(&ap->device[0]) +
-		     (optidma_make_bits43(&ap->device[0]) << 2)) << nybble;
+		r |= (optidma_make_bits43(&link->device[0]) +
+		     (optidma_make_bits43(&link->device[0]) << 2)) << nybble;
 		pci_write_config_byte(pdev, 0x43, r);
 	}
 	return rc;
@@ -366,7 +368,6 @@
 };
 
 static struct ata_port_operations optidma_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= optidma_set_pio_mode,
 	.set_dmamode	= optidma_set_dma_mode,
 
@@ -396,13 +397,11 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static struct ata_port_operations optiplus_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= optiplus_set_pio_mode,
 	.set_dmamode	= optiplus_set_dma_mode,
 
@@ -432,9 +431,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /**
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index a56257c9..782ff4a 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -42,7 +42,7 @@
 
 
 #define DRV_NAME "pata_pcmcia"
-#define DRV_VERSION "0.3.1"
+#define DRV_VERSION "0.3.2"
 
 /*
  *	Private data structure to glue stuff together
@@ -56,7 +56,7 @@
 
 /**
  *	pcmcia_set_mode	-	PCMCIA specific mode setup
- *	@ap: Port
+ *	@link: link
  *	@r_failed_dev: Return pointer for failed device
  *
  *	Perform the tuning and setup of the devices and timings, which
@@ -65,13 +65,13 @@
  *	decode, which alas is embarrassingly common in the PC world
  */
 
-static int pcmcia_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
+static int pcmcia_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
 {
-	struct ata_device *master = &ap->device[0];
-	struct ata_device *slave = &ap->device[1];
+	struct ata_device *master = &link->device[0];
+	struct ata_device *slave = &link->device[1];
 
 	if (!ata_dev_enabled(master) || !ata_dev_enabled(slave))
-		return ata_do_set_mode(ap, r_failed_dev);
+		return ata_do_set_mode(link, r_failed_dev);
 
 	if (memcmp(master->id + ATA_ID_FW_REV,  slave->id + ATA_ID_FW_REV,
 			   ATA_ID_FW_REV_LEN + ATA_ID_PROD_LEN) == 0)
@@ -84,7 +84,7 @@
 			ata_dev_disable(slave);
 		}
 	}
-	return ata_do_set_mode(ap, r_failed_dev);
+	return ata_do_set_mode(link, r_failed_dev);
 }
 
 static struct scsi_host_template pcmcia_sht = {
@@ -107,7 +107,6 @@
 
 static struct ata_port_operations pcmcia_port_ops = {
 	.set_mode	= pcmcia_set_mode,
-	.port_disable	= ata_port_disable,
 	.tf_load	= ata_tf_load,
 	.tf_read	= ata_tf_read,
 	.check_status 	= ata_check_status,
@@ -127,7 +126,6 @@
 
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
 	.port_start	= ata_sff_port_start,
 };
@@ -304,6 +302,8 @@
 	ap->ioaddr.ctl_addr = ctl_addr;
 	ata_std_ports(&ap->ioaddr);
 
+	ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", io_base, ctl_base);
+
 	/* activate */
 	ret = ata_host_activate(host, pdev->irq.AssignedIRQ, ata_interrupt,
 				IRQF_SHARED, &pcmcia_sht);
@@ -382,6 +382,7 @@
 	PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
 	PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
 	PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+	PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
 	PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2      ", 0x547e66dc, 0x8671043b),
 	PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
 	PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index 69a5aa4..3d3f155 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -35,7 +35,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"pata_pdc2027x"
-#define DRV_VERSION	"0.9"
+#define DRV_VERSION	"1.0"
 #undef PDC_DEBUG
 
 #ifdef PDC_DEBUG
@@ -69,7 +69,7 @@
 static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc);
 static unsigned long pdc2027x_mode_filter(struct ata_device *adev, unsigned long mask);
 static int pdc2027x_cable_detect(struct ata_port *ap);
-static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed);
+static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed);
 
 /*
  * ATA Timing Tables based on 133MHz controller clock.
@@ -147,7 +147,6 @@
 };
 
 static struct ata_port_operations pdc2027x_pata100_ops = {
-	.port_disable		= ata_port_disable,
 	.mode_filter		= ata_pci_default_filter,
 
 	.tf_load		= ata_tf_load,
@@ -173,13 +172,11 @@
 
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
-	.port_start		= ata_port_start,
+	.port_start		= ata_sff_port_start,
 };
 
 static struct ata_port_operations pdc2027x_pata133_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= pdc2027x_set_piomode,
 	.set_dmamode		= pdc2027x_set_dmamode,
 	.set_mode		= pdc2027x_set_mode,
@@ -208,9 +205,8 @@
 
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
-	.port_start		= ata_port_start,
+	.port_start		= ata_sff_port_start,
 };
 
 static struct ata_port_info pdc2027x_port_info[] = {
@@ -277,7 +273,7 @@
 	u32 cgcr;
 
 	/* check cable detect results */
-	cgcr = readl(port_mmio(ap, PDC_GLOBAL_CTL));
+	cgcr = ioread32(port_mmio(ap, PDC_GLOBAL_CTL));
 	if (cgcr & (1 << 26))
 		goto cbl40;
 
@@ -295,12 +291,12 @@
  */
 static inline int pdc2027x_port_enabled(struct ata_port *ap)
 {
-	return readb(port_mmio(ap, PDC_ATA_CTL)) & 0x02;
+	return ioread8(port_mmio(ap, PDC_ATA_CTL)) & 0x02;
 }
 
 /**
  *	pdc2027x_prereset - prereset for PATA host controller
- *	@ap: Target port
+ *	@link: Target link
  *	@deadline: deadline jiffies for the operation
  *
  *	Probeinit including cable detection.
@@ -309,12 +305,12 @@
  *	None (inherited from caller).
  */
 
-static int pdc2027x_prereset(struct ata_port *ap, unsigned long deadline)
+static int pdc2027x_prereset(struct ata_link *link, unsigned long deadline)
 {
 	/* Check whether port enabled */
-	if (!pdc2027x_port_enabled(ap))
+	if (!pdc2027x_port_enabled(link->ap))
 		return -ENOENT;
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -387,16 +383,16 @@
 	/* Set the PIO timing registers using value table for 133MHz */
 	PDPRINTK("Set pio regs... \n");
 
-	ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0));
+	ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0));
 	ctcr0 &= 0xffff0000;
 	ctcr0 |= pdc2027x_pio_timing_tbl[pio].value0 |
 		(pdc2027x_pio_timing_tbl[pio].value1 << 8);
-	writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
+	iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
 
-	ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
+	ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1));
 	ctcr1 &= 0x00ffffff;
 	ctcr1 |= (pdc2027x_pio_timing_tbl[pio].value2 << 24);
-	writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
+	iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
 
 	PDPRINTK("Set pio regs done\n");
 
@@ -430,18 +426,18 @@
 			 * If tHOLD is '1', the hardware will add half clock for data hold time.
 			 * This code segment seems to be no effect. tHOLD will be overwritten below.
 			 */
-			ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
-			writel(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1));
+			ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1));
+			iowrite32(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1));
 		}
 
 		PDPRINTK("Set udma regs... \n");
 
-		ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
+		ctcr1 = ioread32(dev_mmio(ap, adev, PDC_CTCR1));
 		ctcr1 &= 0xff000000;
 		ctcr1 |= pdc2027x_udma_timing_tbl[udma_mode].value0 |
 			(pdc2027x_udma_timing_tbl[udma_mode].value1 << 8) |
 			(pdc2027x_udma_timing_tbl[udma_mode].value2 << 16);
-		writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
+		iowrite32(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
 
 		PDPRINTK("Set udma regs done\n");
 
@@ -453,13 +449,13 @@
 		unsigned int mdma_mode = dma_mode & 0x07;
 
 		PDPRINTK("Set mdma regs... \n");
-		ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0));
+		ctcr0 = ioread32(dev_mmio(ap, adev, PDC_CTCR0));
 
 		ctcr0 &= 0x0000ffff;
 		ctcr0 |= (pdc2027x_mdma_timing_tbl[mdma_mode].value0 << 16) |
 			(pdc2027x_mdma_timing_tbl[mdma_mode].value1 << 24);
 
-		writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
+		iowrite32(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
 		PDPRINTK("Set mdma regs done\n");
 
 		PDPRINTK("Set to mdma mode[%u] \n", mdma_mode);
@@ -470,24 +466,24 @@
 
 /**
  *	pdc2027x_set_mode - Set the timing registers back to correct values.
- *	@ap: Port to configure
+ *	@link: link to configure
  *	@r_failed: Returned device for failure
  *
  *	The pdc2027x hardware will look at "SET FEATURES" and change the timing registers
  *	automatically. The values set by the hardware might be incorrect, under 133Mhz PLL.
  *	This function overwrites the possibly incorrect values set by the hardware to be correct.
  */
-static int pdc2027x_set_mode(struct ata_port *ap, struct ata_device **r_failed)
+static int pdc2027x_set_mode(struct ata_link *link, struct ata_device **r_failed)
 {
-	int i;
+	struct ata_port *ap = link->ap;
+	struct ata_device *dev;
+	int rc;
 
-	i = ata_do_set_mode(ap, r_failed);
-	if (i < 0)
-		return i;
+	rc = ata_do_set_mode(link, r_failed);
+	if (rc < 0)
+		return rc;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
-
+	ata_link_for_each_dev(dev, link) {
 		if (ata_dev_enabled(dev)) {
 
 			pdc2027x_set_piomode(ap, dev);
@@ -496,9 +492,9 @@
 			 * Enable prefetch if the device support PIO only.
 			 */
 			if (dev->xfer_shift == ATA_SHIFT_PIO) {
-				u32 ctcr1 = readl(dev_mmio(ap, dev, PDC_CTCR1));
+				u32 ctcr1 = ioread32(dev_mmio(ap, dev, PDC_CTCR1));
 				ctcr1 |= (1 << 25);
-				writel(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));
+				iowrite32(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));
 
 				PDPRINTK("Turn on prefetch\n");
 			} else {
@@ -563,14 +559,12 @@
 	u32 bccrl, bccrh, bccrlv, bccrhv;
 
 retry:
-	bccrl = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff;
-	bccrh = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
-	rmb();
+	bccrl = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
+	bccrh = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
 
 	/* Read the counter values again for verification */
-	bccrlv = readl(mmio_base + PDC_BYTE_COUNT) & 0xffff;
-	bccrhv = readl(mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
-	rmb();
+	bccrlv = ioread32(mmio_base + PDC_BYTE_COUNT) & 0x7fff;
+	bccrhv = ioread32(mmio_base + PDC_BYTE_COUNT + 0x100) & 0x7fff;
 
 	counter = (bccrh << 15) | bccrl;
 
@@ -619,7 +613,7 @@
 	/* Show the current clock value of PLL control register
 	 * (maybe already configured by the firmware)
 	 */
-	pll_ctl = readw(mmio_base + PDC_PLL_CTL);
+	pll_ctl = ioread16(mmio_base + PDC_PLL_CTL);
 
 	PDPRINTK("pll_ctl[%X]\n", pll_ctl);
 #endif
@@ -659,8 +653,8 @@
 
 	PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl);
 
-	writew(pll_ctl, mmio_base + PDC_PLL_CTL);
-	readw(mmio_base + PDC_PLL_CTL); /* flush */
+	iowrite16(pll_ctl, mmio_base + PDC_PLL_CTL);
+	ioread16(mmio_base + PDC_PLL_CTL); /* flush */
 
 	/* Wait the PLL circuit to be stable */
 	mdelay(30);
@@ -670,7 +664,7 @@
 	 *  Show the current clock value of PLL control register
 	 * (maybe configured by the firmware)
 	 */
-	pll_ctl = readw(mmio_base + PDC_PLL_CTL);
+	pll_ctl = ioread16(mmio_base + PDC_PLL_CTL);
 
 	PDPRINTK("pll_ctl[%X]\n", pll_ctl);
 #endif
@@ -692,16 +686,16 @@
 	struct timeval start_time, end_time;
 	long pll_clock, usec_elapsed;
 
+	/* Start the test mode */
+	scr = ioread32(mmio_base + PDC_SYS_CTL);
+	PDPRINTK("scr[%X]\n", scr);
+	iowrite32(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL);
+	ioread32(mmio_base + PDC_SYS_CTL); /* flush */
+
 	/* Read current counter value */
 	start_count = pdc_read_counter(host);
 	do_gettimeofday(&start_time);
 
-	/* Start the test mode */
-	scr = readl(mmio_base + PDC_SYS_CTL);
-	PDPRINTK("scr[%X]\n", scr);
-	writel(scr | (0x01 << 14), mmio_base + PDC_SYS_CTL);
-	readl(mmio_base + PDC_SYS_CTL); /* flush */
-
 	/* Let the counter run for 100 ms. */
 	mdelay(100);
 
@@ -710,16 +704,16 @@
 	do_gettimeofday(&end_time);
 
 	/* Stop the test mode */
-	scr = readl(mmio_base + PDC_SYS_CTL);
+	scr = ioread32(mmio_base + PDC_SYS_CTL);
 	PDPRINTK("scr[%X]\n", scr);
-	writel(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL);
-	readl(mmio_base + PDC_SYS_CTL); /* flush */
+	iowrite32(scr & ~(0x01 << 14), mmio_base + PDC_SYS_CTL);
+	ioread32(mmio_base + PDC_SYS_CTL); /* flush */
 
 	/* calculate the input clock in Hz */
 	usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 +
 		(end_time.tv_usec - start_time.tv_usec);
 
-	pll_clock = (start_count - end_count) / 100 *
+	pll_clock = ((start_count - end_count) & 0x3fffffff) / 100 *
 		(100000000 / usec_elapsed);
 
 	PDPRINTK("start[%ld] end[%ld] \n", start_count, end_count);
@@ -745,9 +739,6 @@
 	 */
 	pll_clock = pdc_detect_pll_input_clock(host);
 
-	if (pll_clock < 0) /* counter overflow? Try again. */
-		pll_clock = pdc_detect_pll_input_clock(host);
-
 	dev_printk(KERN_INFO, host->dev, "PLL input clock %ld kHz\n", pll_clock/1000);
 
 	/* Adjust PLL control register */
@@ -791,12 +782,14 @@
 static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	static int printed_version;
+	static const unsigned long cmd_offset[] = { 0x17c0, 0x15c0 };
+	static const unsigned long bmdma_offset[] = { 0x1000, 0x1008 };
 	unsigned int board_idx = (unsigned int) ent->driver_data;
 	const struct ata_port_info *ppi[] =
 		{ &pdc2027x_port_info[board_idx], NULL };
 	struct ata_host *host;
 	void __iomem *mmio_base;
-	int rc;
+	int i, rc;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -826,10 +819,15 @@
 
 	mmio_base = host->iomap[PDC_MMIO_BAR];
 
-	pdc_ata_setup_port(&host->ports[0]->ioaddr, mmio_base + 0x17c0);
-	host->ports[0]->ioaddr.bmdma_addr = mmio_base + 0x1000;
-	pdc_ata_setup_port(&host->ports[1]->ioaddr, mmio_base + 0x15c0);
-	host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x1008;
+	for (i = 0; i < 2; i++) {
+		struct ata_port *ap = host->ports[i];
+
+		pdc_ata_setup_port(&ap->ioaddr, mmio_base + cmd_offset[i]);
+		ap->ioaddr.bmdma_addr = mmio_base + bmdma_offset[i];
+
+		ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
+		ata_port_pbar_desc(ap, PDC_MMIO_BAR, cmd_offset[i], "cmd");
+	}
 
 	//pci_enable_intx(pdev);
 
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index 92447bed..65d9516 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -9,7 +9,7 @@
  * First cut with LBA48/ATAPI
  *
  * TODO:
- *	Channel interlock/reset on both required
+ *	Channel interlock/reset on both required ?
  */
 
 #include <linux/kernel.h>
@@ -22,7 +22,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_pdc202xx_old"
-#define DRV_VERSION "0.4.2"
+#define DRV_VERSION "0.4.3"
 
 static int pdc2026x_cable_detect(struct ata_port *ap)
 {
@@ -106,9 +106,9 @@
 		{ 0x20, 0x01 }
 	};
 	static u8 mdma_timing[3][2] = {
-		{ 0x60, 0x03 },
-		{ 0x60, 0x04 },
 		{ 0xe0, 0x0f },
+		{ 0x60, 0x04 },
+		{ 0x60, 0x03 },
 	};
 	u8 r_bp, r_cp;
 
@@ -139,6 +139,9 @@
  *
  *	In UDMA3 or higher we have to clock switch for the duration of the
  *	DMA transfer sequence.
+ *
+ *	Note: The host lock held by the libata layer protects
+ *	us from two channels both trying to set DMA bits at once
  */
 
 static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
@@ -187,6 +190,9 @@
  *
  *	After a DMA completes we need to put the clock back to 33MHz for
  *	PIO timings.
+ *
+ *	Note: The host lock held by the libata layer protects
+ *	us from two channels both trying to set DMA bits at once
  */
 
 static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
@@ -206,7 +212,6 @@
 		iowrite32(0, atapi_reg);
 		iowrite8(ioread8(clock) & ~sel66, clock);
 	}
-	/* Check we keep host level locking here */
 	/* Flip back to 33Mhz for PIO */
 	if (adev->dma_mode >= XFER_UDMA_2)
 		iowrite8(ioread8(clock) & ~sel66, clock);
@@ -247,7 +252,6 @@
 };
 
 static struct ata_port_operations pdc2024x_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= pdc202xx_set_piomode,
 	.set_dmamode	= pdc202xx_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -275,13 +279,11 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static struct ata_port_operations pdc2026x_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= pdc202xx_set_piomode,
 	.set_dmamode	= pdc202xx_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -310,9 +312,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static int pdc202xx_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 79f841b..fc72a96 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -22,7 +22,7 @@
 #include <linux/pata_platform.h>
 
 #define DRV_NAME "pata_platform"
-#define DRV_VERSION "1.0"
+#define DRV_VERSION "1.1"
 
 static int pio_mask = 1;
 
@@ -30,13 +30,11 @@
  * Provide our own set_mode() as we don't want to change anything that has
  * already been configured..
  */
-static int pata_platform_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int pata_platform_set_mode(struct ata_link *link, struct ata_device **unused)
 {
-	int i;
+	struct ata_device *dev;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
-
+	ata_link_for_each_dev(dev, link) {
 		if (ata_dev_enabled(dev)) {
 			/* We don't really care */
 			dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
@@ -71,7 +69,6 @@
 static struct ata_port_operations pata_platform_port_ops = {
 	.set_mode		= pata_platform_set_mode,
 
-	.port_disable		= ata_port_disable,
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
 	.check_status		= ata_check_status,
@@ -91,7 +88,6 @@
 
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	.port_start		= ata_dummy_ret0,
 };
@@ -209,12 +205,17 @@
 
 	ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr;
 
-	pp_info = (struct pata_platform_info *)(pdev->dev.platform_data);
+	pp_info = pdev->dev.platform_data;
 	pata_platform_setup_port(&ap->ioaddr, pp_info);
 
+	ata_port_desc(ap, "%s cmd 0x%llx ctl 0x%llx", mmio ? "mmio" : "ioport",
+		      (unsigned long long)io_res->start,
+		      (unsigned long long)ctl_res->start);
+
 	/* activate */
-	return ata_host_activate(host, platform_get_irq(pdev, 0), ata_interrupt,
-				 pp_info->irq_flags, &pata_platform_sht);
+	return ata_host_activate(host, platform_get_irq(pdev, 0),
+				 ata_interrupt, pp_info ? pp_info->irq_flags
+				 : 0, &pata_platform_sht);
 }
 
 /**
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
index 1998c19..7d4c696 100644
--- a/drivers/ata/pata_qdi.c
+++ b/drivers/ata/pata_qdi.c
@@ -126,7 +126,7 @@
 
 static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
 {
-	struct ata_port *ap = adev->ap;
+	struct ata_port *ap = adev->link->ap;
 	int slop = buflen & 3;
 
 	if (ata_id_has_dword_io(adev->id)) {
@@ -170,7 +170,6 @@
 };
 
 static struct ata_port_operations qdi6500_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= qdi6500_set_piomode,
 
 	.tf_load	= ata_tf_load,
@@ -192,13 +191,11 @@
 
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static struct ata_port_operations qdi6580_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= qdi6580_set_piomode,
 
 	.tf_load	= ata_tf_load,
@@ -220,9 +217,8 @@
 
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /**
@@ -238,6 +234,7 @@
 
 static __init int qdi_init_one(unsigned long port, int type, unsigned long io, int irq, int fast)
 {
+	unsigned long ctl = io + 0x206;
 	struct platform_device *pdev;
 	struct ata_host *host;
 	struct ata_port *ap;
@@ -254,7 +251,7 @@
 
 	ret = -ENOMEM;
 	io_addr = devm_ioport_map(&pdev->dev, io, 8);
-	ctl_addr = devm_ioport_map(&pdev->dev, io + 0x206, 1);
+	ctl_addr = devm_ioport_map(&pdev->dev, ctl, 1);
 	if (!io_addr || !ctl_addr)
 		goto fail;
 
@@ -279,6 +276,8 @@
 	ap->ioaddr.ctl_addr = ctl_addr;
 	ata_std_ports(&ap->ioaddr);
 
+	ata_port_desc(ap, "cmd %lx ctl %lx", io, ctl);
+
 	/*
 	 *	Hook in a private data structure per channel
 	 */
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
index 7d1aabe..d5b7649 100644
--- a/drivers/ata/pata_radisys.c
+++ b/drivers/ata/pata_radisys.c
@@ -203,7 +203,6 @@
 };
 
 static const struct ata_port_operations radisys_pata_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= radisys_set_piomode,
 	.set_dmamode		= radisys_set_dmamode,
 	.mode_filter		= ata_pci_default_filter,
@@ -231,9 +230,8 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
-	.port_start		= ata_port_start,
+	.port_start		= ata_sff_port_start,
 };
 
 
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index 7632fcb..ba8a31c 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -26,7 +26,7 @@
 
 /**
  *	rz1000_set_mode		-	mode setting function
- *	@ap: ATA interface
+ *	@link: ATA link
  *	@unused: returned device on set_mode failure
  *
  *	Use a non standard set_mode function. We don't want to be tuned. We
@@ -34,12 +34,11 @@
  *	whacked out.
  */
 
-static int rz1000_set_mode(struct ata_port *ap, struct ata_device **unused)
+static int rz1000_set_mode(struct ata_link *link, struct ata_device **unused)
 {
-	int i;
+	struct ata_device *dev;
 
-	for (i = 0; i < ATA_MAX_DEVICES; i++) {
-		struct ata_device *dev = &ap->device[i];
+	ata_link_for_each_dev(dev, link) {
 		if (ata_dev_enabled(dev)) {
 			/* We don't really care */
 			dev->pio_mode = XFER_PIO_0;
@@ -74,7 +73,6 @@
 static struct ata_port_operations rz1000_port_ops = {
 	.set_mode	= rz1000_set_mode,
 
-	.port_disable	= ata_port_disable,
 	.tf_load	= ata_tf_load,
 	.tf_read	= ata_tf_read,
 	.check_status 	= ata_check_status,
@@ -100,9 +98,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static int rz1000_fifo_disable(struct pci_dev *pdev)
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index b8b2d11..21ebc48 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -40,7 +40,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"sc1200"
-#define DRV_VERSION	"0.2.5"
+#define DRV_VERSION	"0.2.6"
 
 #define SC1200_REV_A	0x00
 #define SC1200_REV_B1	0x01
@@ -197,7 +197,6 @@
 };
 
 static struct ata_port_operations sc1200_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= sc1200_set_piomode,
 	.set_dmamode	= sc1200_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -227,9 +226,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /**
diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c
index c55667e..5557613 100644
--- a/drivers/ata/pata_scc.c
+++ b/drivers/ata/pata_scc.c
@@ -43,7 +43,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME		"pata_scc"
-#define DRV_VERSION		"0.2"
+#define DRV_VERSION		"0.3"
 
 #define PCI_DEVICE_ID_TOSHIBA_SCC_ATA		0x01b4
 
@@ -238,12 +238,6 @@
 	else
 		offset = 0;	/* 100MHz */
 
-	/* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
-	if (adev->class == ATA_DEV_ATAPI && speed > XFER_UDMA_4) {
-		printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
-		speed = XFER_UDMA_4;
-	}
-
 	if (speed >= XFER_UDMA_0)
 		idx = speed - XFER_UDMA_0;
 	else
@@ -264,6 +258,17 @@
 		 JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]);
 }
 
+unsigned long scc_mode_filter(struct ata_device *adev, unsigned long mask)
+{
+	/* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
+	if (adev->class == ATA_DEV_ATAPI &&
+	    (mask & (0xE0 << ATA_SHIFT_UDMA))) {
+		printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
+		mask &= ~(0xE0 << ATA_SHIFT_UDMA);
+	}
+	return ata_pci_default_filter(adev, mask);
+}
+
 /**
  *	scc_tf_load - send taskfile registers to host controller
  *	@ap: Port to which output is sent
@@ -358,6 +363,8 @@
 		tf->hob_lbal = in_be32(ioaddr->lbal_addr);
 		tf->hob_lbam = in_be32(ioaddr->lbam_addr);
 		tf->hob_lbah = in_be32(ioaddr->lbah_addr);
+		out_be32(ioaddr->ctl_addr, tf->ctl);
+		ap->last_ctl = tf->ctl;
 	}
 }
 
@@ -596,16 +603,17 @@
  *	Note: Original code is ata_std_softreset().
  */
 
-static int scc_std_softreset (struct ata_port *ap, unsigned int *classes,
-                              unsigned long deadline)
+static int scc_std_softreset(struct ata_link *link, unsigned int *classes,
+                             unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
 	unsigned int devmask = 0, err_mask;
 	u8 err;
 
 	DPRINTK("ENTER\n");
 
-	if (ata_port_offline(ap)) {
+	if (ata_link_offline(link)) {
 		classes[0] = ATA_DEV_NONE;
 		goto out;
 	}
@@ -629,9 +637,11 @@
 	}
 
 	/* determine by signature whether we have ATA or ATAPI devices */
-	classes[0] = ata_dev_try_classify(ap, 0, &err);
+	classes[0] = ata_dev_try_classify(&ap->link.device[0],
+					  devmask & (1 << 0), &err);
 	if (slave_possible && err != 0x81)
-		classes[1] = ata_dev_try_classify(ap, 1, &err);
+		classes[1] = ata_dev_try_classify(&ap->link.device[1],
+						  devmask & (1 << 1), &err);
 
  out:
 	DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
@@ -694,7 +704,7 @@
 			printk(KERN_WARNING "%s: Internal Bus Error\n", DRV_NAME);
 			out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMSINT);
 			/* TBD: SW reset */
-			scc_std_softreset(ap, &classes, deadline);
+			scc_std_softreset(&ap->link, &classes, deadline);
 			continue;
 		}
 
@@ -733,7 +743,7 @@
 	void __iomem *mmio = ap->ioaddr.bmdma_addr;
 	u8 host_stat = in_be32(mmio + SCC_DMA_STATUS);
 	u32 int_status = in_be32(mmio + SCC_DMA_INTST);
-	struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+	struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
 	static int retry = 0;
 
 	/* return if IOS_SS is cleared */
@@ -741,7 +751,7 @@
 		return host_stat;
 
 	/* errata A252,A308 workaround: Step4 */
-	if (ata_altstatus(ap) & ATA_ERR && int_status & INTSTS_INTRQ)
+	if ((ata_altstatus(ap) & ATA_ERR) && (int_status & INTSTS_INTRQ))
 		return (host_stat | ATA_DMA_INTR);
 
 	/* errata A308 workaround Step5 */
@@ -752,11 +762,11 @@
 		if ((qc->tf.protocol == ATA_PROT_DMA &&
 		     qc->dev->xfer_mode > XFER_UDMA_4)) {
 			if (!(int_status & INTSTS_ACTEINT)) {
-				printk(KERN_WARNING "ata%u: data lost occurred. (ACTEINT==0, retry:%d)\n",
-				       ap->print_id, retry);
+				printk(KERN_WARNING "ata%u: operation failed (transfer data loss)\n",
+				       ap->print_id);
 				host_stat |= ATA_DMA_ERR;
 				if (retry++)
-					ap->udma_mask >>= 1;
+					ap->udma_mask &= ~(1 << qc->dev->xfer_mode);
 			} else
 				retry = 0;
 		}
@@ -778,7 +788,7 @@
 static void scc_data_xfer (struct ata_device *adev, unsigned char *buf,
 			   unsigned int buflen, int write_data)
 {
-	struct ata_port *ap = adev->ap;
+	struct ata_port *ap = adev->link->ap;
 	unsigned int words = buflen >> 1;
 	unsigned int i;
 	u16 *buf16 = (u16 *) buf;
@@ -832,38 +842,6 @@
 }
 
 /**
- *	scc_irq_ack - Acknowledge a device interrupt.
- *	@ap: Port on which interrupts are enabled.
- *
- *	Note: Original code is ata_irq_ack().
- */
-
-static u8 scc_irq_ack (struct ata_port *ap, unsigned int chk_drq)
-{
-	unsigned int bits = chk_drq ? ATA_BUSY | ATA_DRQ : ATA_BUSY;
-	u8 host_stat, post_stat, status;
-
-	status = ata_busy_wait(ap, bits, 1000);
-	if (status & bits)
-		if (ata_msg_err(ap))
-			printk(KERN_ERR "abnormal status 0x%X\n", status);
-
-	/* get controller status; clear intr, err bits */
-	host_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS);
-	out_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS,
-		 host_stat | ATA_DMA_INTR | ATA_DMA_ERR);
-
-	post_stat = in_be32(ap->ioaddr.bmdma_addr + SCC_DMA_STATUS);
-
-	if (ata_msg_intr(ap))
-		printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n",
-		       __FUNCTION__,
-		       host_stat, post_stat, status);
-
-	return status;
-}
-
-/**
  *	scc_bmdma_freeze - Freeze BMDMA controller port
  *	@ap: port to freeze
  *
@@ -894,10 +872,10 @@
  *	@deadline: deadline jiffies for the operation
  */
 
-static int scc_pata_prereset(struct ata_port *ap, unsigned long deadline)
+static int scc_pata_prereset(struct ata_link *link, unsigned long deadline)
 {
-	ap->cbl = ATA_CBL_PATA80;
-	return ata_std_prereset(ap, deadline);
+	link->ap->cbl = ATA_CBL_PATA80;
+	return ata_std_prereset(link, deadline);
 }
 
 /**
@@ -908,8 +886,10 @@
  *	Note: Original code is ata_std_postreset().
  */
 
-static void scc_std_postreset (struct ata_port *ap, unsigned int *classes)
+static void scc_std_postreset(struct ata_link *link, unsigned int *classes)
 {
+	struct ata_port *ap = link->ap;
+
 	DPRINTK("ENTER\n");
 
 	/* is double-select really necessary? */
@@ -1013,10 +993,9 @@
 };
 
 static const struct ata_port_operations scc_pata_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= scc_set_piomode,
 	.set_dmamode		= scc_set_dmamode,
-	.mode_filter		= ata_pci_default_filter,
+	.mode_filter		= scc_mode_filter,
 
 	.tf_load		= scc_tf_load,
 	.tf_read		= scc_tf_read,
@@ -1040,7 +1019,6 @@
 
 	.irq_clear		= scc_bmdma_irq_clear,
 	.irq_on			= scc_irq_on,
-	.irq_ack		= scc_irq_ack,
 
 	.port_start		= scc_port_start,
 	.port_stop		= scc_port_stop,
@@ -1186,6 +1164,9 @@
 		return rc;
 	host->iomap = pcim_iomap_table(pdev);
 
+	ata_port_pbar_desc(host->ports[0], SCC_CTRL_BAR, -1, "ctrl");
+	ata_port_pbar_desc(host->ports[0], SCC_BMID_BAR, -1, "bmid");
+
 	rc = scc_host_init(host);
 	if (rc)
 		return rc;
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index 8969154..df68806 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -41,7 +41,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_serverworks"
-#define DRV_VERSION "0.4.1"
+#define DRV_VERSION "0.4.2"
 
 #define SVWKS_CSB5_REVISION_NEW	0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
 #define SVWKS_CSB6_REVISION	0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
@@ -318,7 +318,6 @@
 };
 
 static struct ata_port_operations serverworks_osb4_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= serverworks_set_piomode,
 	.set_dmamode	= serverworks_set_dmamode,
 	.mode_filter	= serverworks_osb4_filter,
@@ -348,13 +347,11 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static struct ata_port_operations serverworks_csb_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= serverworks_set_piomode,
 	.set_dmamode	= serverworks_set_dmamode,
 	.mode_filter	= serverworks_csb_filter,
@@ -384,9 +381,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static int serverworks_fixup_osb4(struct pci_dev *pdev)
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index b0cd52d..2eb75cd 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -33,7 +33,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_sil680"
-#define DRV_VERSION "0.4.6"
+#define DRV_VERSION "0.4.7"
 
 #define SIL680_MMIO_BAR		5
 
@@ -95,15 +95,16 @@
 
 /**
  *	sil680_bus_reset	-	reset the SIL680 bus
- *	@ap: ATA port to reset
+ *	@link: ATA link to reset
  *	@deadline: deadline jiffies for the operation
  *
  *	Perform the SIL680 housekeeping when doing an ATA bus reset
  */
 
-static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes,
+static int sil680_bus_reset(struct ata_link *link, unsigned int *classes,
 			    unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	unsigned long addr = sil680_selreg(ap, 0);
 	u8 reset;
@@ -112,7 +113,7 @@
 	pci_write_config_byte(pdev, addr, reset | 0x03);
 	udelay(25);
 	pci_write_config_byte(pdev, addr, reset);
-	return ata_std_softreset(ap, classes, deadline);
+	return ata_std_softreset(link, classes, deadline);
 }
 
 static void sil680_error_handler(struct ata_port *ap)
@@ -237,7 +238,6 @@
 };
 
 static struct ata_port_operations sil680_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= sil680_set_piomode,
 	.set_dmamode	= sil680_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -266,9 +266,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /**
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index 9a829a7..3b5be77 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -2,6 +2,7 @@
  *    pata_sis.c - SiS ATA driver
  *
  *	(C) 2005 Red Hat <alan@redhat.com>
+ *	(C) 2007 Bartlomiej Zolnierkiewicz
  *
  *    Based upon linux/drivers/ide/pci/sis5513.c
  * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
@@ -35,7 +36,7 @@
 #include "sis.h"
 
 #define DRV_NAME	"pata_sis"
-#define DRV_VERSION	"0.5.1"
+#define DRV_VERSION	"0.5.2"
 
 struct sis_chipset {
 	u16 device;				/* PCI host ID */
@@ -53,6 +54,7 @@
 static const struct sis_laptop sis_laptop[] = {
 	/* devid, subvendor, subdev */
 	{ 0x5513, 0x1043, 0x1107 },	/* ASUS A6K */
+	{ 0x5513, 0x1734, 0x105F },	/* FSC Amilo A1630 */
 	/* end marker */
 	{ 0, }
 };
@@ -82,7 +84,7 @@
 
 static int sis_old_port_base(struct ata_device *adev)
 {
-	return  0x40 + (4 * adev->ap->port_no) +  (2 * adev->devno);
+	return  0x40 + (4 * adev->link->ap->port_no) +  (2 * adev->devno);
 }
 
 /**
@@ -131,19 +133,20 @@
 
 /**
  *	sis_pre_reset		-	probe begin
- *	@ap: ATA port
+ *	@link: ATA link
  *	@deadline: deadline jiffies for the operation
  *
  *	Set up cable type and use generic probe init
  */
 
-static int sis_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int sis_pre_reset(struct ata_link *link, unsigned long deadline)
 {
 	static const struct pci_bits sis_enable_bits[] = {
 		{ 0x4aU, 1U, 0x02UL, 0x02UL },	/* port 0 */
 		{ 0x4aU, 1U, 0x04UL, 0x04UL },	/* port 1 */
 	};
 
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
 	if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no]))
@@ -152,7 +155,7 @@
 	/* Clear the FIFO settings. We can't enable the FIFO until
 	   we know we are poking at a disk */
 	pci_write_config_byte(pdev, 0x4B, 0);
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 
@@ -237,7 +240,7 @@
 }
 
 /**
- *	sis_100_set_pioode - Initialize host controller PATA PIO timings
+ *	sis_100_set_piomode - Initialize host controller PATA PIO timings
  *	@ap: Port whose timings we are configuring
  *	@adev: Device we are configuring for.
  *
@@ -262,7 +265,7 @@
 }
 
 /**
- *	sis_133_set_pioode - Initialize host controller PATA PIO timings
+ *	sis_133_set_piomode - Initialize host controller PATA PIO timings
  *	@ap: Port whose timings we are configuring
  *	@adev: Device we are configuring for.
  *
@@ -334,7 +337,7 @@
 	int drive_pci = sis_old_port_base(adev);
 	u16 timing;
 
-	const u16 mwdma_bits[] = { 0x707, 0x202, 0x202 };
+	const u16 mwdma_bits[] = { 0x008, 0x302, 0x301 };
 	const u16 udma_bits[]  = { 0xE000, 0xC000, 0xA000 };
 
 	pci_read_config_word(pdev, drive_pci, &timing);
@@ -342,15 +345,15 @@
 	if (adev->dma_mode < XFER_UDMA_0) {
 		/* bits 3-0 hold recovery timing bits 8-10 active timing and
 		   the higer bits are dependant on the device */
-		timing &= ~ 0x870F;
+		timing &= ~0x870F;
 		timing |= mwdma_bits[speed];
-		pci_write_config_word(pdev, drive_pci, timing);
 	} else {
 		/* Bit 15 is UDMA on/off, bit 13-14 are cycle time */
 		speed = adev->dma_mode - XFER_UDMA_0;
 		timing &= ~0x6000;
 		timing |= udma_bits[speed];
 	}
+	pci_write_config_word(pdev, drive_pci, timing);
 }
 
 /**
@@ -373,8 +376,9 @@
 	int drive_pci = sis_old_port_base(adev);
 	u16 timing;
 
-	const u16 mwdma_bits[] = { 0x707, 0x202, 0x202 };
-	const u16 udma_bits[]  = { 0xF000, 0xD000, 0xB000, 0xA000, 0x9000};
+	/* MWDMA 0-2 and UDMA 0-5 */
+	const u16 mwdma_bits[] = { 0x008, 0x302, 0x301 };
+	const u16 udma_bits[]  = { 0xF000, 0xD000, 0xB000, 0xA000, 0x9000, 0x8000 };
 
 	pci_read_config_word(pdev, drive_pci, &timing);
 
@@ -432,8 +436,7 @@
  *	@adev: Device to program
  *
  *	Set UDMA/MWDMA mode for device, in host controller PCI config space.
- *	Handles early SiS 961 bridges. Supports MWDMA as well unlike
- *	the old ide/pci driver.
+ *	Handles early SiS 961 bridges.
  *
  *	LOCKING:
  *	None (inherited from caller).
@@ -467,8 +470,6 @@
  *	@adev: Device to program
  *
  *	Set UDMA/MWDMA mode for device, in host controller PCI config space.
- *	Handles early SiS 961 bridges. Supports MWDMA as well unlike
- *	the old ide/pci driver.
  *
  *	LOCKING:
  *	None (inherited from caller).
@@ -530,7 +531,6 @@
 };
 
 static const struct ata_port_operations sis_133_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= sis_133_set_piomode,
 	.set_dmamode		= sis_133_set_dmamode,
 	.mode_filter		= ata_pci_default_filter,
@@ -558,13 +558,11 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
-	.port_start		= ata_port_start,
+	.port_start		= ata_sff_port_start,
 };
 
 static const struct ata_port_operations sis_133_for_sata_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= sis_133_set_piomode,
 	.set_dmamode		= sis_133_set_dmamode,
 	.mode_filter		= ata_pci_default_filter,
@@ -592,13 +590,11 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
-	.port_start		= ata_port_start,
+	.port_start		= ata_sff_port_start,
 };
 
 static const struct ata_port_operations sis_133_early_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= sis_100_set_piomode,
 	.set_dmamode		= sis_133_early_set_dmamode,
 	.mode_filter		= ata_pci_default_filter,
@@ -626,13 +622,11 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
-	.port_start		= ata_port_start,
+	.port_start		= ata_sff_port_start,
 };
 
 static const struct ata_port_operations sis_100_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= sis_100_set_piomode,
 	.set_dmamode		= sis_100_set_dmamode,
 	.mode_filter		= ata_pci_default_filter,
@@ -660,13 +654,11 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
-	.port_start		= ata_port_start,
+	.port_start		= ata_sff_port_start,
 };
 
 static const struct ata_port_operations sis_66_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= sis_old_set_piomode,
 	.set_dmamode		= sis_66_set_dmamode,
 	.mode_filter		= ata_pci_default_filter,
@@ -694,13 +686,11 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
-	.port_start		= ata_port_start,
+	.port_start		= ata_sff_port_start,
 };
 
 static const struct ata_port_operations sis_old_ops = {
-	.port_disable		= ata_port_disable,
 	.set_piomode		= sis_old_set_piomode,
 	.set_dmamode		= sis_old_set_dmamode,
 	.mode_filter		= ata_pci_default_filter,
@@ -728,9 +718,8 @@
 	.irq_handler		= ata_interrupt,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
-	.port_start		= ata_port_start,
+	.port_start		= ata_sff_port_start,
 };
 
 static const struct ata_port_info sis_info = {
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index 8c2813a..1388cef5 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -26,7 +26,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_sl82c105"
-#define DRV_VERSION "0.3.1"
+#define DRV_VERSION "0.3.2"
 
 enum {
 	/*
@@ -43,23 +43,24 @@
 
 /**
  *	sl82c105_pre_reset		-	probe begin
- *	@ap: ATA port
+ *	@link: ATA link
  *	@deadline: deadline jiffies for the operation
  *
  *	Set up cable type and use generic probe init
  */
 
-static int sl82c105_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int sl82c105_pre_reset(struct ata_link *link, unsigned long deadline)
 {
 	static const struct pci_bits sl82c105_enable_bits[] = {
 		{ 0x40, 1, 0x01, 0x01 },
 		{ 0x40, 1, 0x10, 0x10 }
 	};
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
 	if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no]))
 		return -ENOENT;
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 
@@ -224,7 +225,6 @@
 };
 
 static struct ata_port_operations sl82c105_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= sl82c105_set_piomode,
 	.mode_filter	= ata_pci_default_filter,
 
@@ -253,9 +253,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /**
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index af21f44..403eafc 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -47,25 +47,26 @@
 
 /**
  *	triflex_prereset		-	probe begin
- *	@ap: ATA port
+ *	@link: ATA link
  *	@deadline: deadline jiffies for the operation
  *
  *	Set up cable type and use generic probe init
  */
 
-static int triflex_prereset(struct ata_port *ap, unsigned long deadline)
+static int triflex_prereset(struct ata_link *link, unsigned long deadline)
 {
 	static const struct pci_bits triflex_enable_bits[] = {
 		{ 0x80, 1, 0x01, 0x01 },
 		{ 0x80, 1, 0x02, 0x02 }
 	};
 
+	struct ata_port *ap = link->ap;
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 
 	if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no]))
 		return -ENOENT;
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 
@@ -197,7 +198,6 @@
 };
 
 static struct ata_port_operations triflex_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= triflex_set_piomode,
 	.mode_filter	= ata_pci_default_filter,
 
@@ -226,9 +226,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index f645fe2..5d41b66 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -63,7 +63,7 @@
 #include <linux/dmi.h>
 
 #define DRV_NAME "pata_via"
-#define DRV_VERSION "0.3.1"
+#define DRV_VERSION "0.3.2"
 
 /*
  *	The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx
@@ -97,6 +97,7 @@
 	u8 rev_max;
 	u16 flags;
 } via_isa_bridges[] = {
+	{ "vx800",	PCI_DEVICE_ID_VIA_VX800,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
 	{ "vt8237s",	PCI_DEVICE_ID_VIA_8237S,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
 	{ "vt8251",	PCI_DEVICE_ID_VIA_8251,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
 	{ "cx700",	PCI_DEVICE_ID_VIA_CX700,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
@@ -128,7 +129,7 @@
  *	Cable special cases
  */
 
-static struct dmi_system_id cable_dmi_table[] = {
+static const struct dmi_system_id cable_dmi_table[] = {
 	{
 		.ident = "Acer Ferrari 3400",
 		.matches = {
@@ -144,6 +145,9 @@
 	/* Systems by DMI */
 	if (dmi_check_system(cable_dmi_table))
 		return 1;
+	/* Arima W730-K8/Targa Visionary 811/... */
+	if (pdev->subsystem_vendor == 0x161F && pdev->subsystem_device == 0x2032)
+		return 1;
 	return 0;
 }
 
@@ -180,11 +184,15 @@
 	   two drives */
 	if (ata66 & (0x10100000 >> (16 * ap->port_no)))
 		return ATA_CBL_PATA80;
+	/* Check with ACPI so we can spot BIOS reported SATA bridges */
+	if (ata_acpi_cbl_80wire(ap))
+		return ATA_CBL_PATA80;
 	return ATA_CBL_PATA40;
 }
 
-static int via_pre_reset(struct ata_port *ap, unsigned long deadline)
+static int via_pre_reset(struct ata_link *link, unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	const struct via_isa_bridge *config = ap->host->private_data;
 
 	if (!(config->flags & VIA_NO_ENABLES)) {
@@ -197,7 +205,7 @@
 			return -ENOENT;
 	}
 
-	return ata_std_prereset(ap, deadline);
+	return ata_std_prereset(link, deadline);
 }
 
 
@@ -240,7 +248,6 @@
 	int ut;
 	int offset = 3 - (2*ap->port_no) - adev->devno;
 
-
 	/* Calculate the timing values we require */
 	ata_timing_compute(adev, mode, &t, T, UT);
 
@@ -287,9 +294,17 @@
 			ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07;
 			break;
 	}
+
 	/* Set UDMA unless device is not UDMA capable */
-	if (udma_type)
-		pci_write_config_byte(pdev, 0x50 + offset, ut);
+	if (udma_type) {
+		u8 cable80_status;
+
+		/* Get 80-wire cable detection bit */
+		pci_read_config_byte(pdev, 0x50 + offset, &cable80_status);
+		cable80_status &= 0x10;
+
+		pci_write_config_byte(pdev, 0x50 + offset, ut | cable80_status);
+	}
 }
 
 static void via_set_piomode(struct ata_port *ap, struct ata_device *adev)
@@ -333,7 +348,6 @@
 };
 
 static struct ata_port_operations via_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= via_set_piomode,
 	.set_dmamode	= via_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -363,13 +377,11 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 static struct ata_port_operations via_port_ops_noirq = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= via_set_piomode,
 	.set_dmamode	= via_set_dmamode,
 	.mode_filter	= ata_pci_default_filter,
@@ -399,9 +411,8 @@
 	.irq_handler	= ata_interrupt,
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /**
diff --git a/drivers/ata/pata_winbond.c b/drivers/ata/pata_winbond.c
index 83abfec..549cbbe 100644
--- a/drivers/ata/pata_winbond.c
+++ b/drivers/ata/pata_winbond.c
@@ -94,7 +94,7 @@
 
 static void winbond_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
 {
-	struct ata_port *ap = adev->ap;
+	struct ata_port *ap = adev->link->ap;
 	int slop = buflen & 3;
 
 	if (ata_id_has_dword_io(adev->id)) {
@@ -138,7 +138,6 @@
 };
 
 static struct ata_port_operations winbond_port_ops = {
-	.port_disable	= ata_port_disable,
 	.set_piomode	= winbond_set_piomode,
 
 	.tf_load	= ata_tf_load,
@@ -160,9 +159,8 @@
 
 	.irq_clear	= ata_bmdma_irq_clear,
 	.irq_on		= ata_irq_on,
-	.irq_ack	= ata_irq_ack,
 
-	.port_start	= ata_port_start,
+	.port_start	= ata_sff_port_start,
 };
 
 /**
@@ -199,6 +197,7 @@
 
 	for (i = 0; i < 2 ; i ++) {
 		unsigned long cmd_port = 0x1F0 - (0x80 * i);
+		unsigned long ctl_port = cmd_port + 0x206;
 		struct ata_host *host;
 		struct ata_port *ap;
 		void __iomem *cmd_addr, *ctl_addr;
@@ -214,14 +213,16 @@
 		host = ata_host_alloc(&pdev->dev, 1);
 		if (!host)
 			goto err_unregister;
+		ap = host->ports[0];
 
 		rc = -ENOMEM;
 		cmd_addr = devm_ioport_map(&pdev->dev, cmd_port, 8);
-		ctl_addr = devm_ioport_map(&pdev->dev, cmd_port + 0x0206, 1);
+		ctl_addr = devm_ioport_map(&pdev->dev, ctl_port, 1);
 		if (!cmd_addr || !ctl_addr)
 			goto err_unregister;
 
-		ap = host->ports[0];
+		ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", cmd_port, ctl_port);
+
 		ap->ops = &winbond_port_ops;
 		ap->pio_mask = 0x1F;
 		ap->flags |= ATA_FLAG_SLAVE_POSS;
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index bec1de5..8d1b03d 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -44,7 +44,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"pdc_adma"
-#define DRV_VERSION	"0.06"
+#define DRV_VERSION	"1.0"
 
 /* macro to calculate base address for ATA regs */
 #define ADMA_ATA_REGS(base,port_no)	((base) + ((port_no) * 0x40))
@@ -92,6 +92,8 @@
 
 	/* CPB bits */
 	cDONE			= (1 << 0),
+	cATERR			= (1 << 3),
+
 	cVLD			= (1 << 0),
 	cDAT			= (1 << 2),
 	cIEN			= (1 << 3),
@@ -131,14 +133,15 @@
 static int adma_port_start(struct ata_port *ap);
 static void adma_host_stop(struct ata_host *host);
 static void adma_port_stop(struct ata_port *ap);
-static void adma_phy_reset(struct ata_port *ap);
 static void adma_qc_prep(struct ata_queued_cmd *qc);
 static unsigned int adma_qc_issue(struct ata_queued_cmd *qc);
 static int adma_check_atapi_dma(struct ata_queued_cmd *qc);
 static void adma_bmdma_stop(struct ata_queued_cmd *qc);
 static u8 adma_bmdma_status(struct ata_port *ap);
 static void adma_irq_clear(struct ata_port *ap);
-static void adma_eng_timeout(struct ata_port *ap);
+static void adma_freeze(struct ata_port *ap);
+static void adma_thaw(struct ata_port *ap);
+static void adma_error_handler(struct ata_port *ap);
 
 static struct scsi_host_template adma_ata_sht = {
 	.module			= THIS_MODULE,
@@ -159,21 +162,20 @@
 };
 
 static const struct ata_port_operations adma_ata_ops = {
-	.port_disable		= ata_port_disable,
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
 	.exec_command		= ata_exec_command,
 	.check_status		= ata_check_status,
 	.dev_select		= ata_std_dev_select,
-	.phy_reset		= adma_phy_reset,
 	.check_atapi_dma	= adma_check_atapi_dma,
 	.data_xfer		= ata_data_xfer,
 	.qc_prep		= adma_qc_prep,
 	.qc_issue		= adma_qc_issue,
-	.eng_timeout		= adma_eng_timeout,
+	.freeze			= adma_freeze,
+	.thaw			= adma_thaw,
+	.error_handler		= adma_error_handler,
 	.irq_clear		= adma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 	.port_start		= adma_port_start,
 	.port_stop		= adma_port_stop,
 	.host_stop		= adma_host_stop,
@@ -184,7 +186,7 @@
 static struct ata_port_info adma_port_info[] = {
 	/* board_1841_idx */
 	{
-		.flags		= ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
+		.flags		= ATA_FLAG_SLAVE_POSS |
 				  ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO |
 				  ATA_FLAG_PIO_POLLING,
 		.pio_mask	= 0x10, /* pio4 */
@@ -273,24 +275,42 @@
 	readb(chan + ADMA_STATUS);	/* flush */
 }
 
-static void adma_phy_reset(struct ata_port *ap)
+static void adma_freeze(struct ata_port *ap)
 {
-	struct adma_port_priv *pp = ap->private_data;
+	void __iomem *chan = ADMA_PORT_REGS(ap);
 
-	pp->state = adma_state_idle;
-	adma_reinit_engine(ap);
-	ata_port_probe(ap);
-	ata_bus_reset(ap);
+	/* mask/clear ATA interrupts */
+	writeb(ATA_NIEN, ap->ioaddr.ctl_addr);
+	ata_check_status(ap);
+
+	/* reset ADMA to idle state */
+	writew(aPIOMD4 | aNIEN | aRSTADM, chan + ADMA_CONTROL);
+	udelay(2);
+	writew(aPIOMD4 | aNIEN, chan + ADMA_CONTROL);
+	udelay(2);
 }
 
-static void adma_eng_timeout(struct ata_port *ap)
+static void adma_thaw(struct ata_port *ap)
 {
+	adma_reinit_engine(ap);
+}
+
+static int adma_prereset(struct ata_link *link, unsigned long deadline)
+{
+	struct ata_port *ap = link->ap;
 	struct adma_port_priv *pp = ap->private_data;
 
 	if (pp->state != adma_state_idle) /* healthy paranoia */
 		pp->state = adma_state_mmio;
 	adma_reinit_engine(ap);
-	ata_eng_timeout(ap);
+
+	return ata_std_prereset(link, deadline);
+}
+
+static void adma_error_handler(struct ata_port *ap)
+{
+	ata_do_eh(ap, adma_prereset, ata_std_softreset, NULL,
+		  ata_std_postreset);
 }
 
 static int adma_fill_sg(struct ata_queued_cmd *qc)
@@ -464,14 +484,33 @@
 		pp = ap->private_data;
 		if (!pp || pp->state != adma_state_pkt)
 			continue;
-		qc = ata_qc_from_tag(ap, ap->active_tag);
+		qc = ata_qc_from_tag(ap, ap->link.active_tag);
 		if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
-			if ((status & (aPERR | aPSD | aUIRQ)))
+			if (status & aPERR)
+				qc->err_mask |= AC_ERR_HOST_BUS;
+			else if ((status & (aPSD | aUIRQ)))
 				qc->err_mask |= AC_ERR_OTHER;
+
+			if (pp->pkt[0] & cATERR)
+				qc->err_mask |= AC_ERR_DEV;
 			else if (pp->pkt[0] != cDONE)
 				qc->err_mask |= AC_ERR_OTHER;
 
-			ata_qc_complete(qc);
+			if (!qc->err_mask)
+				ata_qc_complete(qc);
+			else {
+				struct ata_eh_info *ehi = &ap->link.eh_info;
+				ata_ehi_clear_desc(ehi);
+				ata_ehi_push_desc(ehi,
+					"ADMA-status 0x%02X", status);
+				ata_ehi_push_desc(ehi,
+					"pkt[0] 0x%02X", pp->pkt[0]);
+
+				if (qc->err_mask == AC_ERR_DEV)
+					ata_port_abort(ap);
+				else
+					ata_port_freeze(ap);
+			}
 		}
 	}
 	return handled;
@@ -489,7 +528,7 @@
 			struct adma_port_priv *pp = ap->private_data;
 			if (!pp || pp->state != adma_state_mmio)
 				continue;
-			qc = ata_qc_from_tag(ap, ap->active_tag);
+			qc = ata_qc_from_tag(ap, ap->link.active_tag);
 			if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
 
 				/* check main status, clearing INTRQ */
@@ -502,7 +541,20 @@
 				/* complete taskfile transaction */
 				pp->state = adma_state_idle;
 				qc->err_mask |= ac_err_mask(status);
-				ata_qc_complete(qc);
+				if (!qc->err_mask)
+					ata_qc_complete(qc);
+				else {
+					struct ata_eh_info *ehi =
+						&ap->link.eh_info;
+					ata_ehi_clear_desc(ehi);
+					ata_ehi_push_desc(ehi,
+						"status 0x%02X", status);
+
+					if (qc->err_mask == AC_ERR_DEV)
+						ata_port_abort(ap);
+					else
+						ata_port_freeze(ap);
+				}
 				handled = 1;
 			}
 		}
@@ -652,9 +704,16 @@
 	if (rc)
 		return rc;
 
-	for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
-		adma_ata_setup_port(&host->ports[port_no]->ioaddr,
-				    ADMA_ATA_REGS(mmio_base, port_no));
+	for (port_no = 0; port_no < ADMA_PORTS; ++port_no) {
+		struct ata_port *ap = host->ports[port_no];
+		void __iomem *port_base = ADMA_ATA_REGS(mmio_base, port_no);
+		unsigned int offset = port_base - mmio_base;
+
+		adma_ata_setup_port(&ap->ioaddr, port_base);
+
+		ata_port_pbar_desc(ap, ADMA_MMIO_BAR, -1, "mmio");
+		ata_port_pbar_desc(ap, ADMA_MMIO_BAR, offset, "port");
+	}
 
 	/* initialize adapter */
 	adma_host_init(host, board_idx);
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index 3de1834..08595f3 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -28,7 +28,7 @@
 #include <scsi/scsi_device.h>
 
 #define DRV_NAME	"sata_inic162x"
-#define DRV_VERSION	"0.2"
+#define DRV_VERSION	"0.3"
 
 enum {
 	MMIO_BAR		= 5,
@@ -190,34 +190,34 @@
 	writew(ctl, idma_ctl);
 }
 
-static u32 inic_scr_read(struct ata_port *ap, unsigned sc_reg)
+static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
 {
 	void __iomem *scr_addr = ap->ioaddr.scr_addr;
 	void __iomem *addr;
-	u32 val;
 
 	if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
-		return 0xffffffffU;
+		return -EINVAL;
 
 	addr = scr_addr + scr_map[sc_reg] * 4;
-	val = readl(scr_addr + scr_map[sc_reg] * 4);
+	*val = readl(scr_addr + scr_map[sc_reg] * 4);
 
 	/* this controller has stuck DIAG.N, ignore it */
 	if (sc_reg == SCR_ERROR)
-		val &= ~SERR_PHYRDY_CHG;
-	return val;
+		*val &= ~SERR_PHYRDY_CHG;
+	return 0;
 }
 
-static void inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
 {
 	void __iomem *scr_addr = ap->ioaddr.scr_addr;
 	void __iomem *addr;
 
 	if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
-		return;
+		return -EINVAL;
 
 	addr = scr_addr + scr_map[sc_reg] * 4;
 	writel(val, scr_addr + scr_map[sc_reg] * 4);
+	return 0;
 }
 
 /*
@@ -285,7 +285,7 @@
 static void inic_host_intr(struct ata_port *ap)
 {
 	void __iomem *port_base = inic_port_base(ap);
-	struct ata_eh_info *ehi = &ap->eh_info;
+	struct ata_eh_info *ehi = &ap->link.eh_info;
 	u8 irq_stat;
 
 	/* fetch and clear irq */
@@ -293,7 +293,8 @@
 	writeb(irq_stat, port_base + PORT_IRQ_STAT);
 
 	if (likely(!(irq_stat & PIRQ_ERR))) {
-		struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+		struct ata_queued_cmd *qc =
+			ata_qc_from_tag(ap, ap->link.active_tag);
 
 		if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
 			ata_chk_status(ap);	/* clear ATA interrupt */
@@ -416,12 +417,13 @@
  * SRST and SControl hardreset don't give valid signature on this
  * controller.  Only controller specific hardreset mechanism works.
  */
-static int inic_hardreset(struct ata_port *ap, unsigned int *class,
+static int inic_hardreset(struct ata_link *link, unsigned int *class,
 			  unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	void __iomem *port_base = inic_port_base(ap);
 	void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
-	const unsigned long *timing = sata_ehc_deb_timing(&ap->eh_context);
+	const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
 	u16 val;
 	int rc;
 
@@ -434,15 +436,15 @@
 	msleep(1);
 	writew(val & ~IDMA_CTL_RST_ATA, idma_ctl);
 
-	rc = sata_phy_resume(ap, timing, deadline);
+	rc = sata_link_resume(link, timing, deadline);
 	if (rc) {
-		ata_port_printk(ap, KERN_WARNING, "failed to resume "
+		ata_link_printk(link, KERN_WARNING, "failed to resume "
 				"link after reset (errno=%d)\n", rc);
 		return rc;
 	}
 
 	*class = ATA_DEV_NONE;
-	if (ata_port_online(ap)) {
+	if (ata_link_online(link)) {
 		struct ata_taskfile tf;
 
 		/* wait a while before checking status */
@@ -451,7 +453,7 @@
 		rc = ata_wait_ready(ap, deadline);
 		/* link occupied, -ENODEV too is an error */
 		if (rc) {
-			ata_port_printk(ap, KERN_WARNING, "device not ready "
+			ata_link_printk(link, KERN_WARNING, "device not ready "
 					"after hardreset (errno=%d)\n", rc);
 			return rc;
 		}
@@ -550,7 +552,6 @@
 }
 
 static struct ata_port_operations inic_port_ops = {
-	.port_disable		= ata_port_disable,
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
 	.check_status		= ata_check_status,
@@ -567,7 +568,6 @@
 
 	.irq_clear		= inic_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	.qc_prep	 	= ata_qc_prep,
 	.qc_issue		= inic_qc_issue,
@@ -693,16 +693,24 @@
 	host->iomap = iomap = pcim_iomap_table(pdev);
 
 	for (i = 0; i < NR_PORTS; i++) {
-		struct ata_ioports *port = &host->ports[i]->ioaddr;
-		void __iomem *port_base = iomap[MMIO_BAR] + i * PORT_SIZE;
+		struct ata_port *ap = host->ports[i];
+		struct ata_ioports *port = &ap->ioaddr;
+		unsigned int offset = i * PORT_SIZE;
 
 		port->cmd_addr = iomap[2 * i];
 		port->altstatus_addr =
 		port->ctl_addr = (void __iomem *)
 			((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS);
-		port->scr_addr = port_base + PORT_SCR;
+		port->scr_addr = iomap[MMIO_BAR] + offset + PORT_SCR;
 
 		ata_std_ports(port);
+
+		ata_port_pbar_desc(ap, MMIO_BAR, -1, "mmio");
+		ata_port_pbar_desc(ap, MMIO_BAR, offset, "port");
+		ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
+		  (unsigned long long)pci_resource_start(pdev, 2 * i),
+		  (unsigned long long)pci_resource_start(pdev, (2 * i + 1)) |
+				      ATA_PCI_CTL_OFS);
 	}
 
 	hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index fb8a749..4df8311 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -35,8 +35,6 @@
 
   6) Add port multiplier support (intermediate)
 
-  7) Test and verify 3.0 Gbps support
-
   8) Develop a low-power-consumption strategy, and implement it.
 
   9) [Experiment, low priority] See if ATAPI can be supported using
@@ -71,10 +69,11 @@
 #include <linux/device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
 #include <linux/libata.h>
 
 #define DRV_NAME	"sata_mv"
-#define DRV_VERSION	"0.81"
+#define DRV_VERSION	"1.01"
 
 enum {
 	/* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -227,26 +226,26 @@
 
 	EDMA_ERR_IRQ_CAUSE_OFS	= 0x8,
 	EDMA_ERR_IRQ_MASK_OFS	= 0xc,
-	EDMA_ERR_D_PAR		= (1 << 0),
-	EDMA_ERR_PRD_PAR	= (1 << 1),
-	EDMA_ERR_DEV		= (1 << 2),
-	EDMA_ERR_DEV_DCON	= (1 << 3),
-	EDMA_ERR_DEV_CON	= (1 << 4),
-	EDMA_ERR_SERR		= (1 << 5),
+	EDMA_ERR_D_PAR		= (1 << 0),	/* UDMA data parity err */
+	EDMA_ERR_PRD_PAR	= (1 << 1),	/* UDMA PRD parity err */
+	EDMA_ERR_DEV		= (1 << 2),	/* device error */
+	EDMA_ERR_DEV_DCON	= (1 << 3),	/* device disconnect */
+	EDMA_ERR_DEV_CON	= (1 << 4),	/* device connected */
+	EDMA_ERR_SERR		= (1 << 5),	/* SError bits [WBDST] raised */
 	EDMA_ERR_SELF_DIS	= (1 << 7),	/* Gen II/IIE self-disable */
 	EDMA_ERR_SELF_DIS_5	= (1 << 8),	/* Gen I self-disable */
-	EDMA_ERR_BIST_ASYNC	= (1 << 8),
+	EDMA_ERR_BIST_ASYNC	= (1 << 8),	/* BIST FIS or Async Notify */
 	EDMA_ERR_TRANS_IRQ_7	= (1 << 8),	/* Gen IIE transprt layer irq */
-	EDMA_ERR_CRBQ_PAR	= (1 << 9),
-	EDMA_ERR_CRPB_PAR	= (1 << 10),
-	EDMA_ERR_INTRL_PAR	= (1 << 11),
-	EDMA_ERR_IORDY		= (1 << 12),
-	EDMA_ERR_LNK_CTRL_RX	= (0xf << 13),
+	EDMA_ERR_CRQB_PAR	= (1 << 9),	/* CRQB parity error */
+	EDMA_ERR_CRPB_PAR	= (1 << 10),	/* CRPB parity error */
+	EDMA_ERR_INTRL_PAR	= (1 << 11),	/* internal parity error */
+	EDMA_ERR_IORDY		= (1 << 12),	/* IORdy timeout */
+	EDMA_ERR_LNK_CTRL_RX	= (0xf << 13),	/* link ctrl rx error */
 	EDMA_ERR_LNK_CTRL_RX_2	= (1 << 15),
-	EDMA_ERR_LNK_DATA_RX	= (0xf << 17),
-	EDMA_ERR_LNK_CTRL_TX	= (0x1f << 21),
-	EDMA_ERR_LNK_DATA_TX	= (0x1f << 26),
-	EDMA_ERR_TRANS_PROTO	= (1 << 31),
+	EDMA_ERR_LNK_DATA_RX	= (0xf << 17),	/* link data rx error */
+	EDMA_ERR_LNK_CTRL_TX	= (0x1f << 21),	/* link ctrl tx error */
+	EDMA_ERR_LNK_DATA_TX	= (0x1f << 26),	/* link data tx error */
+	EDMA_ERR_TRANS_PROTO	= (1 << 31),	/* transport protocol error */
 	EDMA_ERR_OVERRUN_5	= (1 << 5),
 	EDMA_ERR_UNDERRUN_5	= (1 << 6),
 	EDMA_EH_FREEZE		= EDMA_ERR_D_PAR |
@@ -255,7 +254,7 @@
 				  EDMA_ERR_DEV_CON |
 				  EDMA_ERR_SERR |
 				  EDMA_ERR_SELF_DIS |
-				  EDMA_ERR_CRBQ_PAR |
+				  EDMA_ERR_CRQB_PAR |
 				  EDMA_ERR_CRPB_PAR |
 				  EDMA_ERR_INTRL_PAR |
 				  EDMA_ERR_IORDY |
@@ -270,7 +269,7 @@
 				  EDMA_ERR_OVERRUN_5 |
 				  EDMA_ERR_UNDERRUN_5 |
 				  EDMA_ERR_SELF_DIS_5 |
-				  EDMA_ERR_CRBQ_PAR |
+				  EDMA_ERR_CRQB_PAR |
 				  EDMA_ERR_CRPB_PAR |
 				  EDMA_ERR_INTRL_PAR |
 				  EDMA_ERR_IORDY,
@@ -286,10 +285,10 @@
 	EDMA_RSP_Q_OUT_PTR_OFS	= 0x24,		/* also contains BASE_LO */
 	EDMA_RSP_Q_PTR_SHIFT	= 3,
 
-	EDMA_CMD_OFS		= 0x28,
-	EDMA_EN			= (1 << 0),
-	EDMA_DS			= (1 << 1),
-	ATA_RST			= (1 << 2),
+	EDMA_CMD_OFS		= 0x28,		/* EDMA command register */
+	EDMA_EN			= (1 << 0),	/* enable EDMA */
+	EDMA_DS			= (1 << 1),	/* disable EDMA; self-negated */
+	ATA_RST			= (1 << 2),	/* reset trans/link/phy */
 
 	EDMA_IORDY_TMOUT	= 0x34,
 	EDMA_ARB_CFG		= 0x38,
@@ -301,14 +300,13 @@
 	MV_HP_ERRATA_60X1B2	= (1 << 3),
 	MV_HP_ERRATA_60X1C0	= (1 << 4),
 	MV_HP_ERRATA_XX42A0	= (1 << 5),
-	MV_HP_GEN_I		= (1 << 6),
-	MV_HP_GEN_II		= (1 << 7),
-	MV_HP_GEN_IIE		= (1 << 8),
+	MV_HP_GEN_I		= (1 << 6),	/* Generation I: 50xx */
+	MV_HP_GEN_II		= (1 << 7),	/* Generation II: 60xx */
+	MV_HP_GEN_IIE		= (1 << 8),	/* Generation IIE: 6042/7042 */
 
 	/* Port private flags (pp_flags) */
-	MV_PP_FLAG_EDMA_EN	= (1 << 0),
-	MV_PP_FLAG_EDMA_DS_ACT	= (1 << 1),
-	MV_PP_FLAG_HAD_A_RESET	= (1 << 2),
+	MV_PP_FLAG_EDMA_EN	= (1 << 0),	/* is EDMA engine enabled? */
+	MV_PP_FLAG_HAD_A_RESET	= (1 << 2),	/* 1st hard reset complete? */
 };
 
 #define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
@@ -316,10 +314,17 @@
 #define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
 
 enum {
-	MV_DMA_BOUNDARY		= 0xffffffffU,
+	/* DMA boundary 0xffff is required by the s/g splitting
+	 * we need on /length/ in mv_fill-sg().
+	 */
+	MV_DMA_BOUNDARY		= 0xffffU,
 
+	/* mask of register bits containing lower 32 bits
+	 * of EDMA request queue DMA address
+	 */
 	EDMA_REQ_Q_BASE_LO_MASK	= 0xfffffc00U,
 
+	/* ditto, for response queue */
 	EDMA_RSP_Q_BASE_LO_MASK	= 0xffffff00U,
 };
 
@@ -403,10 +408,10 @@
 };
 
 static void mv_irq_clear(struct ata_port *ap);
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
+static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
+static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
 static int mv_port_start(struct ata_port *ap);
 static void mv_port_stop(struct ata_port *ap);
 static void mv_qc_prep(struct ata_queued_cmd *qc);
@@ -416,6 +421,7 @@
 static void mv_post_int_cmd(struct ata_queued_cmd *qc);
 static void mv_eh_freeze(struct ata_port *ap);
 static void mv_eh_thaw(struct ata_port *ap);
+static int mv_slave_config(struct scsi_device *sdev);
 static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 
 static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
@@ -447,13 +453,13 @@
 	.queuecommand		= ata_scsi_queuecmd,
 	.can_queue		= ATA_DEF_QUEUE,
 	.this_id		= ATA_SHT_THIS_ID,
-	.sg_tablesize		= MV_MAX_SG_CT,
+	.sg_tablesize		= MV_MAX_SG_CT / 2,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
 	.use_clustering		= 1,
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= MV_DMA_BOUNDARY,
-	.slave_configure	= ata_scsi_slave_config,
+	.slave_configure	= mv_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 };
@@ -465,20 +471,18 @@
 	.queuecommand		= ata_scsi_queuecmd,
 	.can_queue		= ATA_DEF_QUEUE,
 	.this_id		= ATA_SHT_THIS_ID,
-	.sg_tablesize		= MV_MAX_SG_CT,
+	.sg_tablesize		= MV_MAX_SG_CT / 2,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
 	.use_clustering		= 1,
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= MV_DMA_BOUNDARY,
-	.slave_configure	= ata_scsi_slave_config,
+	.slave_configure	= mv_slave_config,
 	.slave_destroy		= ata_scsi_slave_destroy,
 	.bios_param		= ata_std_bios_param,
 };
 
 static const struct ata_port_operations mv5_ops = {
-	.port_disable		= ata_port_disable,
-
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
 	.check_status		= ata_check_status,
@@ -493,7 +497,6 @@
 
 	.irq_clear		= mv_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	.error_handler		= mv_error_handler,
 	.post_internal_cmd	= mv_post_int_cmd,
@@ -508,8 +511,6 @@
 };
 
 static const struct ata_port_operations mv6_ops = {
-	.port_disable		= ata_port_disable,
-
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
 	.check_status		= ata_check_status,
@@ -524,7 +525,6 @@
 
 	.irq_clear		= mv_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	.error_handler		= mv_error_handler,
 	.post_internal_cmd	= mv_post_int_cmd,
@@ -539,8 +539,6 @@
 };
 
 static const struct ata_port_operations mv_iie_ops = {
-	.port_disable		= ata_port_disable,
-
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
 	.check_status		= ata_check_status,
@@ -555,7 +553,6 @@
 
 	.irq_clear		= mv_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	.error_handler		= mv_error_handler,
 	.post_internal_cmd	= mv_post_int_cmd,
@@ -620,6 +617,9 @@
 	{ PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
 	{ PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
 	{ PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
+	/* RocketRAID 1740/174x have different identifiers */
+	{ PCI_VDEVICE(TTI, 0x1740), chip_508x },
+	{ PCI_VDEVICE(TTI, 0x1742), chip_508x },
 
 	{ PCI_VDEVICE(MARVELL, 0x6040), chip_604x },
 	{ PCI_VDEVICE(MARVELL, 0x6041), chip_604x },
@@ -756,6 +756,17 @@
 {
 }
 
+static int mv_slave_config(struct scsi_device *sdev)
+{
+	int rc = ata_scsi_slave_config(sdev);
+	if (rc)
+		return rc;
+
+	blk_queue_max_phys_segments(sdev->request_queue, MV_MAX_SG_CT / 2);
+
+	return 0;	/* scsi layer doesn't check return value, sigh */
+}
+
 static void mv_set_edma_ptrs(void __iomem *port_mmio,
 			     struct mv_host_priv *hpriv,
 			     struct mv_port_priv *pp)
@@ -823,7 +834,7 @@
 }
 
 /**
- *      mv_stop_dma - Disable eDMA engine
+ *      __mv_stop_dma - Disable eDMA engine
  *      @ap: ATA channel to manipulate
  *
  *      Verify the local cache of the eDMA state is accurate with a
@@ -832,7 +843,7 @@
  *      LOCKING:
  *      Inherited from caller.
  */
-static int mv_stop_dma(struct ata_port *ap)
+static int __mv_stop_dma(struct ata_port *ap)
 {
 	void __iomem *port_mmio = mv_ap_base(ap);
 	struct mv_port_priv *pp	= ap->private_data;
@@ -865,6 +876,18 @@
 	return err;
 }
 
+static int mv_stop_dma(struct ata_port *ap)
+{
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&ap->host->lock, flags);
+	rc = __mv_stop_dma(ap);
+	spin_unlock_irqrestore(&ap->host->lock, flags);
+
+	return rc;
+}
+
 #ifdef ATA_DEBUG
 static void mv_dump_mem(void __iomem *start, unsigned bytes)
 {
@@ -961,22 +984,26 @@
 	return ofs;
 }
 
-static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
 {
 	unsigned int ofs = mv_scr_offset(sc_reg_in);
 
-	if (0xffffffffU != ofs)
-		return readl(mv_ap_base(ap) + ofs);
-	else
-		return (u32) ofs;
+	if (ofs != 0xffffffffU) {
+		*val = readl(mv_ap_base(ap) + ofs);
+		return 0;
+	} else
+		return -EINVAL;
 }
 
-static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
 {
 	unsigned int ofs = mv_scr_offset(sc_reg_in);
 
-	if (0xffffffffU != ofs)
+	if (ofs != 0xffffffffU) {
 		writelfl(val, mv_ap_base(ap) + ofs);
+		return 0;
+	} else
+		return -EINVAL;
 }
 
 static void mv_edma_cfg(struct ata_port *ap, struct mv_host_priv *hpriv,
@@ -1029,6 +1056,7 @@
 	void __iomem *port_mmio = mv_ap_base(ap);
 	void *mem;
 	dma_addr_t mem_dma;
+	unsigned long flags;
 	int rc;
 
 	pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
@@ -1067,10 +1095,14 @@
 	pp->sg_tbl = mem;
 	pp->sg_tbl_dma = mem_dma;
 
+	spin_lock_irqsave(&ap->host->lock, flags);
+
 	mv_edma_cfg(ap, hpriv, port_mmio);
 
 	mv_set_edma_ptrs(port_mmio, hpriv, pp);
 
+	spin_unlock_irqrestore(&ap->host->lock, flags);
+
 	/* Don't turn on EDMA here...do it before DMA commands only.  Else
 	 * we'll be unable to send non-data, PIO, etc due to restricted access
 	 * to shadow regs.
@@ -1090,11 +1122,7 @@
  */
 static void mv_port_stop(struct ata_port *ap)
 {
-	unsigned long flags;
-
-	spin_lock_irqsave(&ap->host->lock, flags);
 	mv_stop_dma(ap);
-	spin_unlock_irqrestore(&ap->host->lock, flags);
 }
 
 /**
@@ -1106,10 +1134,9 @@
  *      LOCKING:
  *      Inherited from caller.
  */
-static unsigned int mv_fill_sg(struct ata_queued_cmd *qc)
+static void mv_fill_sg(struct ata_queued_cmd *qc)
 {
 	struct mv_port_priv *pp = qc->ap->private_data;
-	unsigned int n_sg = 0;
 	struct scatterlist *sg;
 	struct mv_sg *mv_sg;
 
@@ -1118,18 +1145,27 @@
 		dma_addr_t addr = sg_dma_address(sg);
 		u32 sg_len = sg_dma_len(sg);
 
-		mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
-		mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
-		mv_sg->flags_size = cpu_to_le32(sg_len & 0xffff);
+		while (sg_len) {
+			u32 offset = addr & 0xffff;
+			u32 len = sg_len;
 
-		if (ata_sg_is_last(sg, qc))
-			mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
+			if ((offset + sg_len > 0x10000))
+				len = 0x10000 - offset;
 
-		mv_sg++;
-		n_sg++;
+			mv_sg->addr = cpu_to_le32(addr & 0xffffffff);
+			mv_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16);
+			mv_sg->flags_size = cpu_to_le32(len & 0xffff);
+
+			sg_len -= len;
+			addr += len;
+
+			if (!sg_len && ata_sg_is_last(sg, qc))
+				mv_sg->flags_size |= cpu_to_le32(EPRD_FLAG_END_OF_TBL);
+
+			mv_sg++;
+		}
+
 	}
-
-	return n_sg;
 }
 
 static inline void mv_crqb_pack_cmd(__le16 *cmdw, u8 data, u8 addr, unsigned last)
@@ -1325,7 +1361,7 @@
 		 * port.  Turn off EDMA so there won't be problems accessing
 		 * shadow block, etc registers.
 		 */
-		mv_stop_dma(ap);
+		__mv_stop_dma(ap);
 		return ata_qc_issue_prot(qc);
 	}
 
@@ -1370,7 +1406,7 @@
 	struct mv_host_priv *hpriv = ap->host->private_data;
 	unsigned int edma_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN);
 	unsigned int action = 0, err_mask = 0;
-	struct ata_eh_info *ehi = &ap->eh_info;
+	struct ata_eh_info *ehi = &ap->link.eh_info;
 
 	ata_ehi_clear_desc(ehi);
 
@@ -1378,8 +1414,8 @@
 		/* just a guess: do we need to do this? should we
 		 * expand this, and do it in all cases?
 		 */
-		sata_scr_read(ap, SCR_ERROR, &serr);
-		sata_scr_write_flush(ap, SCR_ERROR, serr);
+		sata_scr_read(&ap->link, SCR_ERROR, &serr);
+		sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
 	}
 
 	edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
@@ -1393,16 +1429,16 @@
 	if (edma_err_cause & EDMA_ERR_DEV)
 		err_mask |= AC_ERR_DEV;
 	if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
-			EDMA_ERR_CRBQ_PAR | EDMA_ERR_CRPB_PAR |
+			EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR |
 			EDMA_ERR_INTRL_PAR)) {
 		err_mask |= AC_ERR_ATA_BUS;
 		action |= ATA_EH_HARDRESET;
-		ata_ehi_push_desc(ehi, ", parity error");
+		ata_ehi_push_desc(ehi, "parity error");
 	}
 	if (edma_err_cause & (EDMA_ERR_DEV_DCON | EDMA_ERR_DEV_CON)) {
 		ata_ehi_hotplugged(ehi);
 		ata_ehi_push_desc(ehi, edma_err_cause & EDMA_ERR_DEV_DCON ?
-			", dev disconnect" : ", dev connect");
+			"dev disconnect" : "dev connect");
 	}
 
 	if (IS_GEN_I(hpriv)) {
@@ -1411,7 +1447,7 @@
 		if (edma_err_cause & EDMA_ERR_SELF_DIS_5) {
 			struct mv_port_priv *pp	= ap->private_data;
 			pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
-			ata_ehi_push_desc(ehi, ", EDMA self-disable");
+			ata_ehi_push_desc(ehi, "EDMA self-disable");
 		}
 	} else {
 		eh_freeze_mask = EDMA_EH_FREEZE;
@@ -1419,12 +1455,12 @@
 		if (edma_err_cause & EDMA_ERR_SELF_DIS) {
 			struct mv_port_priv *pp	= ap->private_data;
 			pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
-			ata_ehi_push_desc(ehi, ", EDMA self-disable");
+			ata_ehi_push_desc(ehi, "EDMA self-disable");
 		}
 
 		if (edma_err_cause & EDMA_ERR_SERR) {
-			sata_scr_read(ap, SCR_ERROR, &serr);
-			sata_scr_write_flush(ap, SCR_ERROR, serr);
+			sata_scr_read(&ap->link, SCR_ERROR, &serr);
+			sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
 			err_mask = AC_ERR_ATA_BUS;
 			action |= ATA_EH_HARDRESET;
 		}
@@ -1463,7 +1499,7 @@
 		return;
 
 	/* get active ATA command */
-	qc = ata_qc_from_tag(ap, ap->active_tag);
+	qc = ata_qc_from_tag(ap, ap->link.active_tag);
 	if (unlikely(!qc))			/* no active tag */
 		return;
 	if (qc->tf.flags & ATA_TFLAG_POLLING)	/* polling; we don't own qc */
@@ -1489,33 +1525,30 @@
 
 	while (1) {
 		u16 status;
+		unsigned int tag;
 
 		/* get s/w response queue last-read pointer, and compare */
 		out_index = pp->resp_idx & MV_MAX_Q_DEPTH_MASK;
 		if (in_index == out_index)
 			break;
 
-		 
 		/* 50xx: get active ATA command */
-		if (IS_GEN_I(hpriv)) 
-			qc = ata_qc_from_tag(ap, ap->active_tag);
+		if (IS_GEN_I(hpriv))
+			tag = ap->link.active_tag;
 
-		/* 60xx: get active ATA command via tag, to enable support
-		 * for queueing.  this works transparently for queued and
-		 * non-queued modes.
+		/* Gen II/IIE: get active ATA command via tag, to enable
+		 * support for queueing.  this works transparently for
+		 * queued and non-queued modes.
 		 */
-		else {
-			unsigned int tag;
+		else if (IS_GEN_II(hpriv))
+			tag = (le16_to_cpu(pp->crpb[out_index].id)
+				>> CRPB_IOID_SHIFT_6) & 0x3f;
 
-			if (IS_GEN_II(hpriv))
-				tag = (le16_to_cpu(pp->crpb[out_index].id)
-					>> CRPB_IOID_SHIFT_6) & 0x3f;
-			else
-				tag = (le16_to_cpu(pp->crpb[out_index].id)
-					>> CRPB_IOID_SHIFT_7) & 0x3f;
+		else /* IS_GEN_IIE */
+			tag = (le16_to_cpu(pp->crpb[out_index].id)
+				>> CRPB_IOID_SHIFT_7) & 0x3f;
 
-			qc = ata_qc_from_tag(ap, tag);
-		}
+		qc = ata_qc_from_tag(ap, tag);
 
 		/* lower 8 bits of status are EDMA_ERR_IRQ_CAUSE_OFS
 		 * bits (WARNING: might not necessarily be associated
@@ -1535,7 +1568,7 @@
 			ata_qc_complete(qc);
 		}
 
-		/* advance software response queue pointer, to 
+		/* advance software response queue pointer, to
 		 * indicate (after the loop completes) to hardware
 		 * that we have consumed a response queue entry.
 		 */
@@ -1604,7 +1637,7 @@
 		if (unlikely(have_err_bits)) {
 			struct ata_queued_cmd *qc;
 
-			qc = ata_qc_from_tag(ap, ap->active_tag);
+			qc = ata_qc_from_tag(ap, ap->link.active_tag);
 			if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
 				continue;
 
@@ -1645,15 +1678,15 @@
 
 	for (i = 0; i < host->n_ports; i++) {
 		ap = host->ports[i];
-		if (!ata_port_offline(ap)) {
-			ehi = &ap->eh_info;
+		if (!ata_link_offline(&ap->link)) {
+			ehi = &ap->link.eh_info;
 			ata_ehi_clear_desc(ehi);
 			if (!printed++)
 				ata_ehi_push_desc(ehi,
 					"PCI err cause 0x%08x", err_cause);
 			err_mask = AC_ERR_HOST_BUS;
 			ehi->action = ATA_EH_HARDRESET;
-			qc = ata_qc_from_tag(ap, ap->active_tag);
+			qc = ata_qc_from_tag(ap, ap->link.active_tag);
 			if (qc)
 				qc->err_mask |= err_mask;
 			else
@@ -1741,26 +1774,30 @@
 	return ofs;
 }
 
-static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
+static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
 {
 	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
 	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
 	unsigned int ofs = mv5_scr_offset(sc_reg_in);
 
-	if (ofs != 0xffffffffU)
-		return readl(addr + ofs);
-	else
-		return (u32) ofs;
+	if (ofs != 0xffffffffU) {
+		*val = readl(addr + ofs);
+		return 0;
+	} else
+		return -EINVAL;
 }
 
-static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
+static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
 {
 	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
 	void __iomem *addr = mv5_phy_base(mmio, ap->port_no);
 	unsigned int ofs = mv5_scr_offset(sc_reg_in);
 
-	if (ofs != 0xffffffffU)
+	if (ofs != 0xffffffffU) {
 		writelfl(val, addr + ofs);
+		return 0;
+	} else
+		return -EINVAL;
 }
 
 static void mv5_reset_bus(struct pci_dev *pdev, void __iomem *mmio)
@@ -2138,20 +2175,28 @@
 
 	VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
 
-	DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
-		"SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
-		mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+#ifdef DEBUG
+	{
+		u32 sstatus, serror, scontrol;
+
+		mv_scr_read(ap, SCR_STATUS, &sstatus);
+		mv_scr_read(ap, SCR_ERROR, &serror);
+		mv_scr_read(ap, SCR_CONTROL, &scontrol);
+		DPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
+			"SCtrl 0x%08x\n", status, serror, scontrol);
+	}
+#endif
 
 	/* Issue COMRESET via SControl */
 comreset_retry:
-	sata_scr_write_flush(ap, SCR_CONTROL, 0x301);
+	sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x301);
 	msleep(1);
 
-	sata_scr_write_flush(ap, SCR_CONTROL, 0x300);
+	sata_scr_write_flush(&ap->link, SCR_CONTROL, 0x300);
 	msleep(20);
 
 	do {
-		sata_scr_read(ap, SCR_STATUS, &sstatus);
+		sata_scr_read(&ap->link, SCR_STATUS, &sstatus);
 		if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0))
 			break;
 
@@ -2164,11 +2209,19 @@
 	    (retry-- > 0))
 		goto comreset_retry;
 
-	DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
-		"SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
-		mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+#ifdef DEBUG
+	{
+		u32 sstatus, serror, scontrol;
 
-	if (ata_port_offline(ap)) {
+		mv_scr_read(ap, SCR_STATUS, &sstatus);
+		mv_scr_read(ap, SCR_ERROR, &serror);
+		mv_scr_read(ap, SCR_CONTROL, &scontrol);
+		DPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
+			"SCtrl 0x%08x\n", sstatus, serror, scontrol);
+	}
+#endif
+
+	if (ata_link_offline(&ap->link)) {
 		*class = ATA_DEV_NONE;
 		return;
 	}
@@ -2195,7 +2248,7 @@
 	 */
 
 	/* finally, read device signature from TF registers */
-	*class = ata_dev_try_classify(ap, 0, NULL);
+	*class = ata_dev_try_classify(ap->link.device, 1, NULL);
 
 	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
 
@@ -2204,12 +2257,13 @@
 	VPRINTK("EXIT\n");
 }
 
-static int mv_prereset(struct ata_port *ap, unsigned long deadline)
+static int mv_prereset(struct ata_link *link, unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	struct mv_port_priv *pp	= ap->private_data;
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_eh_context *ehc = &link->eh_context;
 	int rc;
-	
+
 	rc = mv_stop_dma(ap);
 	if (rc)
 		ehc->i.action |= ATA_EH_HARDRESET;
@@ -2223,7 +2277,7 @@
 	if (ehc->i.action & ATA_EH_HARDRESET)
 		return 0;
 
-	if (ata_port_online(ap))
+	if (ata_link_online(link))
 		rc = ata_wait_ready(ap, deadline);
 	else
 		rc = -ENODEV;
@@ -2231,9 +2285,10 @@
 	return rc;
 }
 
-static int mv_hardreset(struct ata_port *ap, unsigned int *class,
+static int mv_hardreset(struct ata_link *link, unsigned int *class,
 			unsigned long deadline)
 {
+	struct ata_port *ap = link->ap;
 	struct mv_host_priv *hpriv = ap->host->private_data;
 	void __iomem *mmio = ap->host->iomap[MV_PRIMARY_BAR];
 
@@ -2246,16 +2301,17 @@
 	return 0;
 }
 
-static void mv_postreset(struct ata_port *ap, unsigned int *classes)
+static void mv_postreset(struct ata_link *link, unsigned int *classes)
 {
+	struct ata_port *ap = link->ap;
 	u32 serr;
 
 	/* print link status */
-	sata_print_link_status(ap);
+	sata_print_link_status(link);
 
 	/* clear SError */
-	sata_scr_read(ap, SCR_ERROR, &serr);
-	sata_scr_write_flush(ap, SCR_ERROR, serr);
+	sata_scr_read(link, SCR_ERROR, &serr);
+	sata_scr_write_flush(link, SCR_ERROR, serr);
 
 	/* bail out if no device is present */
 	if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
@@ -2528,8 +2584,14 @@
 	}
 
 	for (port = 0; port < host->n_ports; port++) {
+		struct ata_port *ap = host->ports[port];
 		void __iomem *port_mmio = mv_port_base(mmio, port);
-		mv_port_init(&host->ports[port]->ioaddr, port_mmio);
+		unsigned int offset = port_mmio - mmio;
+
+		mv_port_init(&ap->ioaddr, port_mmio);
+
+		ata_port_pbar_desc(ap, MV_PRIMARY_BAR, -1, "mmio");
+		ata_port_pbar_desc(ap, MV_PRIMARY_BAR, offset, "port");
 	}
 
 	for (hc = 0; hc < n_hc; hc++) {
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index db81e3e..40557fe2 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -49,7 +49,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME			"sata_nv"
-#define DRV_VERSION			"3.4"
+#define DRV_VERSION			"3.5"
 
 #define NV_ADMA_DMA_BOUNDARY		0xffffffffUL
 
@@ -236,8 +236,8 @@
 static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
 static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
 static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int nv_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
 static void nv_nf2_freeze(struct ata_port *ap);
 static void nv_nf2_thaw(struct ata_port *ap);
@@ -340,7 +340,6 @@
 };
 
 static const struct ata_port_operations nv_generic_ops = {
-	.port_disable		= ata_port_disable,
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
 	.exec_command		= ata_exec_command,
@@ -359,14 +358,12 @@
 	.data_xfer		= ata_data_xfer,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 	.scr_read		= nv_scr_read,
 	.scr_write		= nv_scr_write,
 	.port_start		= ata_port_start,
 };
 
 static const struct ata_port_operations nv_nf2_ops = {
-	.port_disable		= ata_port_disable,
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
 	.exec_command		= ata_exec_command,
@@ -385,14 +382,12 @@
 	.data_xfer		= ata_data_xfer,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 	.scr_read		= nv_scr_read,
 	.scr_write		= nv_scr_write,
 	.port_start		= ata_port_start,
 };
 
 static const struct ata_port_operations nv_ck804_ops = {
-	.port_disable		= ata_port_disable,
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
 	.exec_command		= ata_exec_command,
@@ -411,7 +406,6 @@
 	.data_xfer		= ata_data_xfer,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 	.scr_read		= nv_scr_read,
 	.scr_write		= nv_scr_write,
 	.port_start		= ata_port_start,
@@ -419,7 +413,6 @@
 };
 
 static const struct ata_port_operations nv_adma_ops = {
-	.port_disable		= ata_port_disable,
 	.tf_load		= ata_tf_load,
 	.tf_read		= nv_adma_tf_read,
 	.check_atapi_dma	= nv_adma_check_atapi_dma,
@@ -430,6 +423,7 @@
 	.bmdma_start		= ata_bmdma_start,
 	.bmdma_stop		= ata_bmdma_stop,
 	.bmdma_status		= ata_bmdma_status,
+	.qc_defer		= ata_std_qc_defer,
 	.qc_prep		= nv_adma_qc_prep,
 	.qc_issue		= nv_adma_qc_issue,
 	.freeze			= nv_adma_freeze,
@@ -439,7 +433,6 @@
 	.data_xfer		= ata_data_xfer,
 	.irq_clear		= nv_adma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 	.scr_read		= nv_scr_read,
 	.scr_write		= nv_scr_write,
 	.port_start		= nv_adma_port_start,
@@ -455,8 +448,8 @@
 	/* generic */
 	{
 		.sht		= &nv_sht,
-		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_HRST_TO_RESUME,
+		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+		.link_flags	= ATA_LFLAG_HRST_TO_RESUME,
 		.pio_mask	= NV_PIO_MASK,
 		.mwdma_mask	= NV_MWDMA_MASK,
 		.udma_mask	= NV_UDMA_MASK,
@@ -466,8 +459,8 @@
 	/* nforce2/3 */
 	{
 		.sht		= &nv_sht,
-		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_HRST_TO_RESUME,
+		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+		.link_flags	= ATA_LFLAG_HRST_TO_RESUME,
 		.pio_mask	= NV_PIO_MASK,
 		.mwdma_mask	= NV_MWDMA_MASK,
 		.udma_mask	= NV_UDMA_MASK,
@@ -477,8 +470,8 @@
 	/* ck804 */
 	{
 		.sht		= &nv_sht,
-		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_HRST_TO_RESUME,
+		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+		.link_flags	= ATA_LFLAG_HRST_TO_RESUME,
 		.pio_mask	= NV_PIO_MASK,
 		.mwdma_mask	= NV_MWDMA_MASK,
 		.udma_mask	= NV_UDMA_MASK,
@@ -489,8 +482,8 @@
 	{
 		.sht		= &nv_adma_sht,
 		.flags		= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_HRST_TO_RESUME |
 				  ATA_FLAG_MMIO | ATA_FLAG_NCQ,
+		.link_flags	= ATA_LFLAG_HRST_TO_RESUME,
 		.pio_mask	= NV_PIO_MASK,
 		.mwdma_mask	= NV_MWDMA_MASK,
 		.udma_mask	= NV_UDMA_MASK,
@@ -594,7 +587,7 @@
 		/* Not a proper libata device, ignore */
 		return rc;
 
-	if (ap->device[sdev->id].class == ATA_DEV_ATAPI) {
+	if (ap->link.device[sdev->id].class == ATA_DEV_ATAPI) {
 		/*
 		 * NVIDIA reports that ADMA mode does not support ATAPI commands.
 		 * Therefore ATAPI commands are sent through the legacy interface.
@@ -711,23 +704,24 @@
 		     flags & (NV_CPB_RESP_ATA_ERR |
 			      NV_CPB_RESP_CMD_ERR |
 			      NV_CPB_RESP_CPB_ERR)))) {
-		struct ata_eh_info *ehi = &ap->eh_info;
+		struct ata_eh_info *ehi = &ap->link.eh_info;
 		int freeze = 0;
 
 		ata_ehi_clear_desc(ehi);
-		ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x", flags );
+		__ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x: ", flags );
 		if (flags & NV_CPB_RESP_ATA_ERR) {
-			ata_ehi_push_desc(ehi, ": ATA error");
+			ata_ehi_push_desc(ehi, "ATA error");
 			ehi->err_mask |= AC_ERR_DEV;
 		} else if (flags & NV_CPB_RESP_CMD_ERR) {
-			ata_ehi_push_desc(ehi, ": CMD error");
+			ata_ehi_push_desc(ehi, "CMD error");
 			ehi->err_mask |= AC_ERR_DEV;
 		} else if (flags & NV_CPB_RESP_CPB_ERR) {
-			ata_ehi_push_desc(ehi, ": CPB error");
+			ata_ehi_push_desc(ehi, "CPB error");
 			ehi->err_mask |= AC_ERR_SYSTEM;
 			freeze = 1;
 		} else {
 			/* notifier error, but no error in CPB flags? */
+			ata_ehi_push_desc(ehi, "unknown");
 			ehi->err_mask |= AC_ERR_OTHER;
 			freeze = 1;
 		}
@@ -746,7 +740,7 @@
 			DPRINTK("Completing qc from tag %d\n",cpb_num);
 			ata_qc_complete(qc);
 		} else {
-			struct ata_eh_info *ehi = &ap->eh_info;
+			struct ata_eh_info *ehi = &ap->link.eh_info;
 			/* Notifier bits set without a command may indicate the drive
 			   is misbehaving. Raise host state machine violation on this
 			   condition. */
@@ -763,7 +757,7 @@
 
 static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
 {
-	struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+	struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
 
 	/* freeze if hotplugged */
 	if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) {
@@ -816,7 +810,7 @@
 			if (pp->flags & NV_ADMA_PORT_REGISTER_MODE) {
 				u8 irq_stat = readb(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_CK804)
 					>> (NV_INT_PORT_SHIFT * i);
-				if(ata_tag_valid(ap->active_tag))
+				if(ata_tag_valid(ap->link.active_tag))
 					/** NV_INT_DEV indication seems unreliable at times
 					    at least in ADMA mode. Force it on always when a
 					    command is active, to prevent losing interrupts. */
@@ -851,23 +845,24 @@
 					       NV_ADMA_STAT_HOTUNPLUG |
 					       NV_ADMA_STAT_TIMEOUT |
 					       NV_ADMA_STAT_SERROR))) {
-				struct ata_eh_info *ehi = &ap->eh_info;
+				struct ata_eh_info *ehi = &ap->link.eh_info;
 
 				ata_ehi_clear_desc(ehi);
-				ata_ehi_push_desc(ehi, "ADMA status 0x%08x", status );
+				__ata_ehi_push_desc(ehi, "ADMA status 0x%08x: ", status );
 				if (status & NV_ADMA_STAT_TIMEOUT) {
 					ehi->err_mask |= AC_ERR_SYSTEM;
-					ata_ehi_push_desc(ehi, ": timeout");
+					ata_ehi_push_desc(ehi, "timeout");
 				} else if (status & NV_ADMA_STAT_HOTPLUG) {
 					ata_ehi_hotplugged(ehi);
-					ata_ehi_push_desc(ehi, ": hotplug");
+					ata_ehi_push_desc(ehi, "hotplug");
 				} else if (status & NV_ADMA_STAT_HOTUNPLUG) {
 					ata_ehi_hotplugged(ehi);
-					ata_ehi_push_desc(ehi, ": hot unplug");
+					ata_ehi_push_desc(ehi, "hot unplug");
 				} else if (status & NV_ADMA_STAT_SERROR) {
 					/* let libata analyze SError and figure out the cause */
-					ata_ehi_push_desc(ehi, ": SError");
-				}
+					ata_ehi_push_desc(ehi, "SError");
+				} else
+					ata_ehi_push_desc(ehi, "unknown");
 				ata_port_freeze(ap);
 				continue;
 			}
@@ -877,10 +872,10 @@
 				u32 check_commands;
 				int pos, error = 0;
 
-				if(ata_tag_valid(ap->active_tag))
-					check_commands = 1 << ap->active_tag;
+				if(ata_tag_valid(ap->link.active_tag))
+					check_commands = 1 << ap->link.active_tag;
 				else
-					check_commands = ap->sactive;
+					check_commands = ap->link.sactive;
 
 				/** Check CPBs for completed commands */
 				while ((pos = ffs(check_commands)) && !error) {
@@ -1331,7 +1326,7 @@
 		    !(ap->flags & ATA_FLAG_DISABLED)) {
 			struct ata_queued_cmd *qc;
 
-			qc = ata_qc_from_tag(ap, ap->active_tag);
+			qc = ata_qc_from_tag(ap, ap->link.active_tag);
 			if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
 				handled += ata_host_intr(ap, qc);
 			else
@@ -1391,20 +1386,22 @@
 	return ret;
 }
 
-static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return 0xffffffffU;
+		return -EINVAL;
 
-	return ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+	*val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+	return 0;
 }
 
-static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return;
+		return -EINVAL;
 
 	iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+	return 0;
 }
 
 static void nv_nf2_freeze(struct ata_port *ap)
@@ -1455,7 +1452,7 @@
 	writeb(mask, mmio_base + NV_INT_ENABLE_CK804);
 }
 
-static int nv_hardreset(struct ata_port *ap, unsigned int *class,
+static int nv_hardreset(struct ata_link *link, unsigned int *class,
 			unsigned long deadline)
 {
 	unsigned int dummy;
@@ -1464,7 +1461,7 @@
 	 * some controllers.  Don't classify on hardreset.  For more
 	 * info, see http://bugme.osdl.org/show_bug.cgi?id=3352
 	 */
-	return sata_std_hardreset(ap, &dummy, deadline);
+	return sata_std_hardreset(link, &dummy, deadline);
 }
 
 static void nv_error_handler(struct ata_port *ap)
@@ -1481,7 +1478,7 @@
 		int i;
 		u16 tmp;
 
-		if(ata_tag_valid(ap->active_tag) || ap->sactive) {
+		if(ata_tag_valid(ap->link.active_tag) || ap->link.sactive) {
 			u32 notifier = readl(mmio + NV_ADMA_NOTIFIER);
 			u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR);
 			u32 gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL);
@@ -1497,8 +1494,8 @@
 
 			for( i=0;i<NV_ADMA_MAX_CPBS;i++) {
 				struct nv_adma_cpb *cpb = &pp->cpb[i];
-				if( (ata_tag_valid(ap->active_tag) && i == ap->active_tag) ||
-				    ap->sactive & (1 << i) )
+				if( (ata_tag_valid(ap->link.active_tag) && i == ap->link.active_tag) ||
+				    ap->link.sactive & (1 << i) )
 					ata_port_printk(ap, KERN_ERR,
 						"CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n",
 						i, cpb->ctl_flags, cpb->resp_flags);
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index d2fcb9a..9032131 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -45,7 +45,7 @@
 #include "sata_promise.h"
 
 #define DRV_NAME	"sata_promise"
-#define DRV_VERSION	"2.09"
+#define DRV_VERSION	"2.10"
 
 enum {
 	PDC_MAX_PORTS		= 4,
@@ -128,8 +128,8 @@
 	dma_addr_t		pkt_dma;
 };
 
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static int pdc_common_port_start(struct ata_port *ap);
 static int pdc_sata_port_start(struct ata_port *ap);
@@ -167,7 +167,6 @@
 };
 
 static const struct ata_port_operations pdc_sata_ops = {
-	.port_disable		= ata_port_disable,
 	.tf_load		= pdc_tf_load_mmio,
 	.tf_read		= ata_tf_read,
 	.check_status		= ata_check_status,
@@ -185,7 +184,6 @@
 	.data_xfer		= ata_data_xfer,
 	.irq_clear		= pdc_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	.scr_read		= pdc_sata_scr_read,
 	.scr_write		= pdc_sata_scr_write,
@@ -194,7 +192,6 @@
 
 /* First-generation chips need a more restrictive ->check_atapi_dma op */
 static const struct ata_port_operations pdc_old_sata_ops = {
-	.port_disable		= ata_port_disable,
 	.tf_load		= pdc_tf_load_mmio,
 	.tf_read		= ata_tf_read,
 	.check_status		= ata_check_status,
@@ -212,7 +209,6 @@
 	.data_xfer		= ata_data_xfer,
 	.irq_clear		= pdc_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	.scr_read		= pdc_sata_scr_read,
 	.scr_write		= pdc_sata_scr_write,
@@ -220,7 +216,6 @@
 };
 
 static const struct ata_port_operations pdc_pata_ops = {
-	.port_disable		= ata_port_disable,
 	.tf_load		= pdc_tf_load_mmio,
 	.tf_read		= ata_tf_read,
 	.check_status		= ata_check_status,
@@ -238,7 +233,6 @@
 	.data_xfer		= ata_data_xfer,
 	.irq_clear		= pdc_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	.port_start		= pdc_common_port_start,
 };
@@ -328,8 +322,8 @@
 
 	{ PCI_VDEVICE(PROMISE, 0x3318), board_20319 },
 	{ PCI_VDEVICE(PROMISE, 0x3319), board_20319 },
-	{ PCI_VDEVICE(PROMISE, 0x3515), board_20319 },
-	{ PCI_VDEVICE(PROMISE, 0x3519), board_20319 },
+	{ PCI_VDEVICE(PROMISE, 0x3515), board_40518 },
+	{ PCI_VDEVICE(PROMISE, 0x3519), board_40518 },
 	{ PCI_VDEVICE(PROMISE, 0x3d17), board_40518 },
 	{ PCI_VDEVICE(PROMISE, 0x3d18), board_40518 },
 
@@ -427,19 +421,20 @@
 	return ATA_CBL_SATA;
 }
 
-static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return 0xffffffffU;
-	return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+		return -EINVAL;
+	*val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+	return 0;
 }
 
-static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
-			       u32 val)
+static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return;
+		return -EINVAL;
 	writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+	return 0;
 }
 
 static void pdc_atapi_pkt(struct ata_queued_cmd *qc)
@@ -474,7 +469,7 @@
 	buf32[2] = 0;				/* no next-packet */
 
 	/* select drive */
-	if (sata_scr_valid(ap)) {
+	if (sata_scr_valid(&ap->link)) {
 		dev_sel = PDC_DEVICE_SATA;
 	} else {
 		dev_sel = ATA_DEVICE_OBS;
@@ -625,7 +620,7 @@
 static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
 			   u32 port_status, u32 err_mask)
 {
-	struct ata_eh_info *ehi = &ap->eh_info;
+	struct ata_eh_info *ehi = &ap->link.eh_info;
 	unsigned int ac_err_mask = 0;
 
 	ata_ehi_clear_desc(ehi);
@@ -642,8 +637,12 @@
 			   | PDC_PCI_SYS_ERR | PDC1_PCI_PARITY_ERR))
 		ac_err_mask |= AC_ERR_HOST_BUS;
 
-	if (sata_scr_valid(ap))
-		ehi->serror |= pdc_sata_scr_read(ap, SCR_ERROR);
+	if (sata_scr_valid(&ap->link)) {
+		u32 serror;
+
+		pdc_sata_scr_read(ap, SCR_ERROR, &serror);
+		ehi->serror |= serror;
+	}
 
 	qc->err_mask |= ac_err_mask;
 
@@ -768,7 +767,7 @@
 		tmp = hotplug_status & (0x11 << ata_no);
 		if (tmp && ap &&
 		    !(ap->flags & ATA_FLAG_DISABLED)) {
-			struct ata_eh_info *ehi = &ap->eh_info;
+			struct ata_eh_info *ehi = &ap->link.eh_info;
 			ata_ehi_clear_desc(ehi);
 			ata_ehi_hotplugged(ehi);
 			ata_ehi_push_desc(ehi, "hotplug_status %#x", tmp);
@@ -783,7 +782,7 @@
 		    !(ap->flags & ATA_FLAG_DISABLED)) {
 			struct ata_queued_cmd *qc;
 
-			qc = ata_qc_from_tag(ap, ap->active_tag);
+			qc = ata_qc_from_tag(ap, ap->link.active_tag);
 			if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
 				handled += pdc_host_intr(ap, qc);
 		}
@@ -1004,10 +1003,15 @@
 
 	is_sataii_tx4 = pdc_is_sataii_tx4(pi->flags);
 	for (i = 0; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
 		unsigned int ata_no = pdc_port_no_to_ata_no(i, is_sataii_tx4);
-		pdc_ata_setup_port(host->ports[i],
-				   base + 0x200 + ata_no * 0x80,
-				   base + 0x400 + ata_no * 0x100);
+		unsigned int port_offset = 0x200 + ata_no * 0x80;
+		unsigned int scr_offset = 0x400 + ata_no * 0x100;
+
+		pdc_ata_setup_port(ap, base + port_offset, base + scr_offset);
+
+		ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
+		ata_port_pbar_desc(ap, PDC_MMIO_BAR, port_offset, "port");
 	}
 
 	/* initialize adapter */
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index 9ab554d..c4c4cd2 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -39,7 +39,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"sata_qstor"
-#define DRV_VERSION	"0.08"
+#define DRV_VERSION	"0.09"
 
 enum {
 	QS_MMIO_BAR		= 4,
@@ -111,8 +111,8 @@
 	qs_state_t		state;
 };
 
-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 static int qs_port_start(struct ata_port *ap);
 static void qs_host_stop(struct ata_host *host);
@@ -145,7 +145,6 @@
 };
 
 static const struct ata_port_operations qs_ata_ops = {
-	.port_disable		= ata_port_disable,
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
 	.check_status		= ata_check_status,
@@ -159,7 +158,6 @@
 	.eng_timeout		= qs_eng_timeout,
 	.irq_clear		= qs_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 	.scr_read		= qs_scr_read,
 	.scr_write		= qs_scr_write,
 	.port_start		= qs_port_start,
@@ -255,18 +253,20 @@
 	ata_eng_timeout(ap);
 }
 
-static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return ~0U;
-	return readl(ap->ioaddr.scr_addr + (sc_reg * 8));
+		return -EINVAL;
+	*val = readl(ap->ioaddr.scr_addr + (sc_reg * 8));
+	return 0;
 }
 
-static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return;
+		return -EINVAL;
 	writel(val, ap->ioaddr.scr_addr + (sc_reg * 8));
+	return 0;
 }
 
 static unsigned int qs_fill_sg(struct ata_queued_cmd *qc)
@@ -337,7 +337,7 @@
 	buf[28] = dflags;
 
 	/* frame information structure (FIS) */
-	ata_tf_to_fis(&qc->tf, &buf[32], 0);
+	ata_tf_to_fis(&qc->tf, 0, 1, &buf[32]);
 }
 
 static inline void qs_packet_start(struct ata_queued_cmd *qc)
@@ -402,7 +402,7 @@
 				struct qs_port_priv *pp = ap->private_data;
 				if (!pp || pp->state != qs_state_pkt)
 					continue;
-				qc = ata_qc_from_tag(ap, ap->active_tag);
+				qc = ata_qc_from_tag(ap, ap->link.active_tag);
 				if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
 					switch (sHST) {
 					case 0: /* successful CPB */
@@ -435,7 +435,7 @@
 			struct qs_port_priv *pp = ap->private_data;
 			if (!pp || pp->state != qs_state_mmio)
 				continue;
-			qc = ata_qc_from_tag(ap, ap->active_tag);
+			qc = ata_qc_from_tag(ap, ap->link.active_tag);
 			if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) {
 
 				/* check main status, clearing INTRQ */
@@ -635,9 +635,14 @@
 		return rc;
 
 	for (port_no = 0; port_no < host->n_ports; ++port_no) {
-		void __iomem *chan =
-			host->iomap[QS_MMIO_BAR] + (port_no * 0x4000);
-		qs_ata_setup_port(&host->ports[port_no]->ioaddr, chan);
+		struct ata_port *ap = host->ports[port_no];
+		unsigned int offset = port_no * 0x4000;
+		void __iomem *chan = host->iomap[QS_MMIO_BAR] + offset;
+
+		qs_ata_setup_port(&ap->ioaddr, chan);
+
+		ata_port_pbar_desc(ap, QS_MMIO_BAR, -1, "mmio");
+		ata_port_pbar_desc(ap, QS_MMIO_BAR, offset, "port");
 	}
 
 	/* initialize adapter */
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index 2a86dc4..ea3a0ab 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -46,7 +46,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"sata_sil"
-#define DRV_VERSION	"2.2"
+#define DRV_VERSION	"2.3"
 
 enum {
 	SIL_MMIO_BAR		= 5,
@@ -59,7 +59,8 @@
 	SIL_FLAG_MOD15WRITE	= (1 << 30),
 
 	SIL_DFL_PORT_FLAGS	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				  ATA_FLAG_MMIO | ATA_FLAG_HRST_TO_RESUME,
+				  ATA_FLAG_MMIO,
+	SIL_DFL_LINK_FLAGS	= ATA_LFLAG_HRST_TO_RESUME,
 
 	/*
 	 * Controller IDs
@@ -115,9 +116,9 @@
 static int sil_pci_device_resume(struct pci_dev *pdev);
 #endif
 static void sil_dev_config(struct ata_device *dev);
-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
-static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed);
+static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed);
 static void sil_freeze(struct ata_port *ap);
 static void sil_thaw(struct ata_port *ap);
 
@@ -185,7 +186,6 @@
 };
 
 static const struct ata_port_operations sil_ops = {
-	.port_disable		= ata_port_disable,
 	.dev_config		= sil_dev_config,
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
@@ -206,7 +206,6 @@
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 	.scr_read		= sil_scr_read,
 	.scr_write		= sil_scr_write,
 	.port_start		= ata_port_start,
@@ -216,6 +215,7 @@
 	/* sil_3112 */
 	{
 		.flags		= SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE,
+		.link_flags	= SIL_DFL_LINK_FLAGS,
 		.pio_mask	= 0x1f,			/* pio0-4 */
 		.mwdma_mask	= 0x07,			/* mwdma0-2 */
 		.udma_mask	= ATA_UDMA5,
@@ -225,6 +225,7 @@
 	{
 		.flags		= SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE |
 				  SIL_FLAG_NO_SATA_IRQ,
+		.link_flags	= SIL_DFL_LINK_FLAGS,
 		.pio_mask	= 0x1f,			/* pio0-4 */
 		.mwdma_mask	= 0x07,			/* mwdma0-2 */
 		.udma_mask	= ATA_UDMA5,
@@ -233,6 +234,7 @@
 	/* sil_3512 */
 	{
 		.flags		= SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
+		.link_flags	= SIL_DFL_LINK_FLAGS,
 		.pio_mask	= 0x1f,			/* pio0-4 */
 		.mwdma_mask	= 0x07,			/* mwdma0-2 */
 		.udma_mask	= ATA_UDMA5,
@@ -241,6 +243,7 @@
 	/* sil_3114 */
 	{
 		.flags		= SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
+		.link_flags	= SIL_DFL_LINK_FLAGS,
 		.pio_mask	= 0x1f,			/* pio0-4 */
 		.mwdma_mask	= 0x07,			/* mwdma0-2 */
 		.udma_mask	= ATA_UDMA5,
@@ -290,35 +293,33 @@
 
 /**
  *	sil_set_mode		-	wrap set_mode functions
- *	@ap: port to set up
+ *	@link: link to set up
  *	@r_failed: returned device when we fail
  *
  *	Wrap the libata method for device setup as after the setup we need
  *	to inspect the results and do some configuration work
  */
 
-static int sil_set_mode (struct ata_port *ap, struct ata_device **r_failed)
+static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed)
 {
-	struct ata_host *host = ap->host;
-	struct ata_device *dev;
-	void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];
+	struct ata_port *ap = link->ap;
+	void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
 	void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode;
-	u32 tmp, dev_mode[2];
-	unsigned int i;
+	struct ata_device *dev;
+	u32 tmp, dev_mode[2] = { };
 	int rc;
 
-	rc = ata_do_set_mode(ap, r_failed);
+	rc = ata_do_set_mode(link, r_failed);
 	if (rc)
 		return rc;
 
-	for (i = 0; i < 2; i++) {
-		dev = &ap->device[i];
+	ata_link_for_each_dev(dev, link) {
 		if (!ata_dev_enabled(dev))
-			dev_mode[i] = 0;	/* PIO0/1/2 */
+			dev_mode[dev->devno] = 0;	/* PIO0/1/2 */
 		else if (dev->flags & ATA_DFLAG_PIO)
-			dev_mode[i] = 1;	/* PIO3/4 */
+			dev_mode[dev->devno] = 1;	/* PIO3/4 */
 		else
-			dev_mode[i] = 3;	/* UDMA */
+			dev_mode[dev->devno] = 3;	/* UDMA */
 		/* value 2 indicates MDMA */
 	}
 
@@ -350,25 +351,32 @@
 	return NULL;
 }
 
-static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	void __iomem *mmio = sil_scr_addr(ap, sc_reg);
-	if (mmio)
-		return readl(mmio);
-	return 0xffffffffU;
+
+	if (mmio) {
+		*val = readl(mmio);
+		return 0;
+	}
+	return -EINVAL;
 }
 
-static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	void __iomem *mmio = sil_scr_addr(ap, sc_reg);
-	if (mmio)
+
+	if (mmio) {
 		writel(val, mmio);
+		return 0;
+	}
+	return -EINVAL;
 }
 
 static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
 {
-	struct ata_eh_info *ehi = &ap->eh_info;
-	struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
+	struct ata_eh_info *ehi = &ap->link.eh_info;
+	struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
 	u8 status;
 
 	if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) {
@@ -378,7 +386,7 @@
 		 * controllers continue to assert IRQ as long as
 		 * SError bits are pending.  Clear SError immediately.
 		 */
-		serror = sil_scr_read(ap, SCR_ERROR);
+		sil_scr_read(ap, SCR_ERROR, &serror);
 		sil_scr_write(ap, SCR_ERROR, serror);
 
 		/* Trigger hotplug and accumulate SError only if the
@@ -387,8 +395,8 @@
 		 * repeat probing needlessly.
 		 */
 		if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
-			ata_ehi_hotplugged(&ap->eh_info);
-			ap->eh_info.serror |= serror;
+			ata_ehi_hotplugged(&ap->link.eh_info);
+			ap->link.eh_info.serror |= serror;
 		}
 
 		goto freeze;
@@ -555,8 +563,8 @@
  */
 static void sil_dev_config(struct ata_device *dev)
 {
-	struct ata_port *ap = dev->ap;
-	int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO;
+	struct ata_port *ap = dev->link->ap;
+	int print_info = ap->link.eh_context.i.flags & ATA_EHI_PRINTINFO;
 	unsigned int n, quirks = 0;
 	unsigned char model_num[ATA_ID_PROD_LEN + 1];
 
@@ -679,7 +687,8 @@
 	mmio_base = host->iomap[SIL_MMIO_BAR];
 
 	for (i = 0; i < host->n_ports; i++) {
-		struct ata_ioports *ioaddr = &host->ports[i]->ioaddr;
+		struct ata_port *ap = host->ports[i];
+		struct ata_ioports *ioaddr = &ap->ioaddr;
 
 		ioaddr->cmd_addr = mmio_base + sil_port[i].tf;
 		ioaddr->altstatus_addr =
@@ -687,6 +696,9 @@
 		ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma;
 		ioaddr->scr_addr = mmio_base + sil_port[i].scr;
 		ata_std_ports(ioaddr);
+
+		ata_port_pbar_desc(ap, SIL_MMIO_BAR, -1, "mmio");
+		ata_port_pbar_desc(ap, SIL_MMIO_BAR, sil_port[i].tf, "tf");
 	}
 
 	/* initialize and activate */
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index ac43a30..b061927 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -30,7 +30,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"sata_sil24"
-#define DRV_VERSION	"0.9"
+#define DRV_VERSION	"1.1"
 
 /*
  * Port request block (PRB) 32 bytes
@@ -168,7 +168,7 @@
 
 	DEF_PORT_IRQ		= PORT_IRQ_COMPLETE | PORT_IRQ_ERROR |
 				  PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG |
-				  PORT_IRQ_UNK_FIS,
+				  PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_NOTIFY,
 
 	/* bits[27:16] are unmasked (raw) */
 	PORT_IRQ_RAW_SHIFT	= 16,
@@ -237,8 +237,9 @@
 	/* host flags */
 	SIL24_COMMON_FLAGS	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 				  ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
-				  ATA_FLAG_NCQ | ATA_FLAG_SKIP_D2H_BSY |
-				  ATA_FLAG_ACPI_SATA,
+				  ATA_FLAG_NCQ | ATA_FLAG_ACPI_SATA |
+				  ATA_FLAG_AN | ATA_FLAG_PMP,
+	SIL24_COMMON_LFLAGS	= ATA_LFLAG_SKIP_D2H_BSY,
 	SIL24_FLAG_PCIX_IRQ_WOC	= (1 << 24), /* IRQ loss errata on PCI-X */
 
 	IRQ_STAT_4PORTS		= 0xf,
@@ -322,16 +323,20 @@
 	union sil24_cmd_block *cmd_block;	/* 32 cmd blocks */
 	dma_addr_t cmd_block_dma;		/* DMA base addr for them */
 	struct ata_taskfile tf;			/* Cached taskfile registers */
+	int do_port_rst;
 };
 
 static void sil24_dev_config(struct ata_device *dev);
 static u8 sil24_check_status(struct ata_port *ap);
-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg);
-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
+static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val);
+static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val);
 static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
+static int sil24_qc_defer(struct ata_queued_cmd *qc);
 static void sil24_qc_prep(struct ata_queued_cmd *qc);
 static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
 static void sil24_irq_clear(struct ata_port *ap);
+static void sil24_pmp_attach(struct ata_port *ap);
+static void sil24_pmp_detach(struct ata_port *ap);
 static void sil24_freeze(struct ata_port *ap);
 static void sil24_thaw(struct ata_port *ap);
 static void sil24_error_handler(struct ata_port *ap);
@@ -340,6 +345,7 @@
 static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 #ifdef CONFIG_PM
 static int sil24_pci_device_resume(struct pci_dev *pdev);
+static int sil24_port_resume(struct ata_port *ap);
 #endif
 
 static const struct pci_device_id sil24_pci_tbl[] = {
@@ -384,8 +390,6 @@
 };
 
 static const struct ata_port_operations sil24_ops = {
-	.port_disable		= ata_port_disable,
-
 	.dev_config		= sil24_dev_config,
 
 	.check_status		= sil24_check_status,
@@ -394,22 +398,28 @@
 
 	.tf_read		= sil24_tf_read,
 
+	.qc_defer		= sil24_qc_defer,
 	.qc_prep		= sil24_qc_prep,
 	.qc_issue		= sil24_qc_issue,
 
 	.irq_clear		= sil24_irq_clear,
-	.irq_on			= ata_dummy_irq_on,
-	.irq_ack		= ata_dummy_irq_ack,
 
 	.scr_read		= sil24_scr_read,
 	.scr_write		= sil24_scr_write,
 
+	.pmp_attach		= sil24_pmp_attach,
+	.pmp_detach		= sil24_pmp_detach,
+
 	.freeze			= sil24_freeze,
 	.thaw			= sil24_thaw,
 	.error_handler		= sil24_error_handler,
 	.post_internal_cmd	= sil24_post_internal_cmd,
 
 	.port_start		= sil24_port_start,
+
+#ifdef CONFIG_PM
+	.port_resume		= sil24_port_resume,
+#endif
 };
 
 /*
@@ -424,6 +434,7 @@
 	{
 		.flags		= SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |
 				  SIL24_FLAG_PCIX_IRQ_WOC,
+		.link_flags	= SIL24_COMMON_LFLAGS,
 		.pio_mask	= 0x1f,			/* pio0-4 */
 		.mwdma_mask	= 0x07,			/* mwdma0-2 */
 		.udma_mask	= ATA_UDMA5,		/* udma0-5 */
@@ -432,6 +443,7 @@
 	/* sil_3132 */
 	{
 		.flags		= SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),
+		.link_flags	= SIL24_COMMON_LFLAGS,
 		.pio_mask	= 0x1f,			/* pio0-4 */
 		.mwdma_mask	= 0x07,			/* mwdma0-2 */
 		.udma_mask	= ATA_UDMA5,		/* udma0-5 */
@@ -440,6 +452,7 @@
 	/* sil_3131/sil_3531 */
 	{
 		.flags		= SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),
+		.link_flags	= SIL24_COMMON_LFLAGS,
 		.pio_mask	= 0x1f,			/* pio0-4 */
 		.mwdma_mask	= 0x07,			/* mwdma0-2 */
 		.udma_mask	= ATA_UDMA5,		/* udma0-5 */
@@ -456,7 +469,7 @@
 
 static void sil24_dev_config(struct ata_device *dev)
 {
-	void __iomem *port = dev->ap->ioaddr.cmd_addr;
+	void __iomem *port = dev->link->ap->ioaddr.cmd_addr;
 
 	if (dev->cdb_len == 16)
 		writel(PORT_CS_CDB16, port + PORT_CTRL_STAT);
@@ -464,15 +477,15 @@
 		writel(PORT_CS_CDB16, port + PORT_CTRL_CLR);
 }
 
-static inline void sil24_update_tf(struct ata_port *ap)
+static void sil24_read_tf(struct ata_port *ap, int tag, struct ata_taskfile *tf)
 {
-	struct sil24_port_priv *pp = ap->private_data;
 	void __iomem *port = ap->ioaddr.cmd_addr;
-	struct sil24_prb __iomem *prb = port;
+	struct sil24_prb __iomem *prb;
 	u8 fis[6 * 4];
 
-	memcpy_fromio(fis, prb->fis, 6 * 4);
-	ata_tf_from_fis(fis, &pp->tf);
+	prb = port + PORT_LRAM + sil24_tag(tag) * PORT_LRAM_SLOT_SZ;
+	memcpy_fromio(fis, prb->fis, sizeof(fis));
+	ata_tf_from_fis(fis, tf);
 }
 
 static u8 sil24_check_status(struct ata_port *ap)
@@ -488,25 +501,30 @@
 	[SCR_ACTIVE]	= 3,
 };
 
-static u32 sil24_scr_read(struct ata_port *ap, unsigned sc_reg)
+static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
 {
 	void __iomem *scr_addr = ap->ioaddr.scr_addr;
+
 	if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
 		void __iomem *addr;
 		addr = scr_addr + sil24_scr_map[sc_reg] * 4;
-		return readl(scr_addr + sil24_scr_map[sc_reg] * 4);
+		*val = readl(scr_addr + sil24_scr_map[sc_reg] * 4);
+		return 0;
 	}
-	return 0xffffffffU;
+	return -EINVAL;
 }
 
-static void sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
+static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
 {
 	void __iomem *scr_addr = ap->ioaddr.scr_addr;
+
 	if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
 		void __iomem *addr;
 		addr = scr_addr + sil24_scr_map[sc_reg] * 4;
 		writel(val, scr_addr + sil24_scr_map[sc_reg] * 4);
+		return 0;
 	}
+	return -EINVAL;
 }
 
 static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
@@ -515,35 +533,140 @@
 	*tf = pp->tf;
 }
 
+static void sil24_config_port(struct ata_port *ap)
+{
+	void __iomem *port = ap->ioaddr.cmd_addr;
+
+	/* configure IRQ WoC */
+	if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
+		writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
+	else
+		writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
+
+	/* zero error counters. */
+	writel(0x8000, port + PORT_DECODE_ERR_THRESH);
+	writel(0x8000, port + PORT_CRC_ERR_THRESH);
+	writel(0x8000, port + PORT_HSHK_ERR_THRESH);
+	writel(0x0000, port + PORT_DECODE_ERR_CNT);
+	writel(0x0000, port + PORT_CRC_ERR_CNT);
+	writel(0x0000, port + PORT_HSHK_ERR_CNT);
+
+	/* always use 64bit activation */
+	writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
+
+	/* clear port multiplier enable and resume bits */
+	writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);
+}
+
+static void sil24_config_pmp(struct ata_port *ap, int attached)
+{
+	void __iomem *port = ap->ioaddr.cmd_addr;
+
+	if (attached)
+		writel(PORT_CS_PMP_EN, port + PORT_CTRL_STAT);
+	else
+		writel(PORT_CS_PMP_EN, port + PORT_CTRL_CLR);
+}
+
+static void sil24_clear_pmp(struct ata_port *ap)
+{
+	void __iomem *port = ap->ioaddr.cmd_addr;
+	int i;
+
+	writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_CLR);
+
+	for (i = 0; i < SATA_PMP_MAX_PORTS; i++) {
+		void __iomem *pmp_base = port + PORT_PMP + i * PORT_PMP_SIZE;
+
+		writel(0, pmp_base + PORT_PMP_STATUS);
+		writel(0, pmp_base + PORT_PMP_QACTIVE);
+	}
+}
+
 static int sil24_init_port(struct ata_port *ap)
 {
 	void __iomem *port = ap->ioaddr.cmd_addr;
+	struct sil24_port_priv *pp = ap->private_data;
 	u32 tmp;
 
+	/* clear PMP error status */
+	if (ap->nr_pmp_links)
+		sil24_clear_pmp(ap);
+
 	writel(PORT_CS_INIT, port + PORT_CTRL_STAT);
 	ata_wait_register(port + PORT_CTRL_STAT,
 			  PORT_CS_INIT, PORT_CS_INIT, 10, 100);
 	tmp = ata_wait_register(port + PORT_CTRL_STAT,
 				PORT_CS_RDY, 0, 10, 100);
 
-	if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY)
+	if ((tmp & (PORT_CS_INIT | PORT_CS_RDY)) != PORT_CS_RDY) {
+		pp->do_port_rst = 1;
+		ap->link.eh_context.i.action |= ATA_EH_HARDRESET;
 		return -EIO;
+	}
+
 	return 0;
 }
 
-static int sil24_softreset(struct ata_port *ap, unsigned int *class,
-			   unsigned long deadline)
+static int sil24_exec_polled_cmd(struct ata_port *ap, int pmp,
+				 const struct ata_taskfile *tf,
+				 int is_cmd, u32 ctrl,
+				 unsigned long timeout_msec)
 {
 	void __iomem *port = ap->ioaddr.cmd_addr;
 	struct sil24_port_priv *pp = ap->private_data;
 	struct sil24_prb *prb = &pp->cmd_block[0].ata.prb;
 	dma_addr_t paddr = pp->cmd_block_dma;
-	u32 mask, irq_stat;
+	u32 irq_enabled, irq_mask, irq_stat;
+	int rc;
+
+	prb->ctrl = cpu_to_le16(ctrl);
+	ata_tf_to_fis(tf, pmp, is_cmd, prb->fis);
+
+	/* temporarily plug completion and error interrupts */
+	irq_enabled = readl(port + PORT_IRQ_ENABLE_SET);
+	writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR, port + PORT_IRQ_ENABLE_CLR);
+
+	writel((u32)paddr, port + PORT_CMD_ACTIVATE);
+	writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
+
+	irq_mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
+	irq_stat = ata_wait_register(port + PORT_IRQ_STAT, irq_mask, 0x0,
+				     10, timeout_msec);
+
+	writel(irq_mask, port + PORT_IRQ_STAT); /* clear IRQs */
+	irq_stat >>= PORT_IRQ_RAW_SHIFT;
+
+	if (irq_stat & PORT_IRQ_COMPLETE)
+		rc = 0;
+	else {
+		/* force port into known state */
+		sil24_init_port(ap);
+
+		if (irq_stat & PORT_IRQ_ERROR)
+			rc = -EIO;
+		else
+			rc = -EBUSY;
+	}
+
+	/* restore IRQ enabled */
+	writel(irq_enabled, port + PORT_IRQ_ENABLE_SET);
+
+	return rc;
+}
+
+static int sil24_do_softreset(struct ata_link *link, unsigned int *class,
+			      int pmp, unsigned long deadline)
+{
+	struct ata_port *ap = link->ap;
+	unsigned long timeout_msec = 0;
+	struct ata_taskfile tf;
 	const char *reason;
+	int rc;
 
 	DPRINTK("ENTER\n");
 
-	if (ata_port_offline(ap)) {
+	if (ata_link_offline(link)) {
 		DPRINTK("PHY reports no device\n");
 		*class = ATA_DEV_NONE;
 		goto out;
@@ -556,29 +679,22 @@
 	}
 
 	/* do SRST */
-	prb->ctrl = cpu_to_le16(PRB_CTRL_SRST);
-	prb->fis[1] = 0; /* no PMP yet */
+	if (time_after(deadline, jiffies))
+		timeout_msec = jiffies_to_msecs(deadline - jiffies);
 
-	writel((u32)paddr, port + PORT_CMD_ACTIVATE);
-	writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4);
-
-	mask = (PORT_IRQ_COMPLETE | PORT_IRQ_ERROR) << PORT_IRQ_RAW_SHIFT;
-	irq_stat = ata_wait_register(port + PORT_IRQ_STAT, mask, 0x0,
-				     100, jiffies_to_msecs(deadline - jiffies));
-
-	writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */
-	irq_stat >>= PORT_IRQ_RAW_SHIFT;
-
-	if (!(irq_stat & PORT_IRQ_COMPLETE)) {
-		if (irq_stat & PORT_IRQ_ERROR)
-			reason = "SRST command error";
-		else
-			reason = "timeout";
+	ata_tf_init(link->device, &tf);	/* doesn't really matter */
+	rc = sil24_exec_polled_cmd(ap, pmp, &tf, 0, PRB_CTRL_SRST,
+				   timeout_msec);
+	if (rc == -EBUSY) {
+		reason = "timeout";
+		goto err;
+	} else if (rc) {
+		reason = "SRST command error";
 		goto err;
 	}
 
-	sil24_update_tf(ap);
-	*class = ata_dev_classify(&pp->tf);
+	sil24_read_tf(ap, 0, &tf);
+	*class = ata_dev_classify(&tf);
 
 	if (*class == ATA_DEV_UNKNOWN)
 		*class = ATA_DEV_NONE;
@@ -588,23 +704,54 @@
 	return 0;
 
  err:
-	ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
+	ata_link_printk(link, KERN_ERR, "softreset failed (%s)\n", reason);
 	return -EIO;
 }
 
-static int sil24_hardreset(struct ata_port *ap, unsigned int *class,
+static int sil24_softreset(struct ata_link *link, unsigned int *class,
 			   unsigned long deadline)
 {
+	return sil24_do_softreset(link, class, SATA_PMP_CTRL_PORT, deadline);
+}
+
+static int sil24_hardreset(struct ata_link *link, unsigned int *class,
+			   unsigned long deadline)
+{
+	struct ata_port *ap = link->ap;
 	void __iomem *port = ap->ioaddr.cmd_addr;
+	struct sil24_port_priv *pp = ap->private_data;
+	int did_port_rst = 0;
 	const char *reason;
 	int tout_msec, rc;
 	u32 tmp;
 
+ retry:
+	/* Sometimes, DEV_RST is not enough to recover the controller.
+	 * This happens often after PM DMA CS errata.
+	 */
+	if (pp->do_port_rst) {
+		ata_port_printk(ap, KERN_WARNING, "controller in dubious "
+				"state, performing PORT_RST\n");
+
+		writel(PORT_CS_PORT_RST, port + PORT_CTRL_STAT);
+		msleep(10);
+		writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
+		ata_wait_register(port + PORT_CTRL_STAT, PORT_CS_RDY, 0,
+				  10, 5000);
+
+		/* restore port configuration */
+		sil24_config_port(ap);
+		sil24_config_pmp(ap, ap->nr_pmp_links);
+
+		pp->do_port_rst = 0;
+		did_port_rst = 1;
+	}
+
 	/* sil24 does the right thing(tm) without any protection */
-	sata_set_spd(ap);
+	sata_set_spd(link);
 
 	tout_msec = 100;
-	if (ata_port_online(ap))
+	if (ata_link_online(link))
 		tout_msec = 5000;
 
 	writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT);
@@ -614,14 +761,14 @@
 	/* SStatus oscillates between zero and valid status after
 	 * DEV_RST, debounce it.
 	 */
-	rc = sata_phy_debounce(ap, sata_deb_timing_long, deadline);
+	rc = sata_link_debounce(link, sata_deb_timing_long, deadline);
 	if (rc) {
 		reason = "PHY debouncing failed";
 		goto err;
 	}
 
 	if (tmp & PORT_CS_DEV_RST) {
-		if (ata_port_offline(ap))
+		if (ata_link_offline(link))
 			return 0;
 		reason = "link not ready";
 		goto err;
@@ -636,7 +783,12 @@
 	return -EAGAIN;
 
  err:
-	ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason);
+	if (!did_port_rst) {
+		pp->do_port_rst = 1;
+		goto retry;
+	}
+
+	ata_link_printk(link, KERN_ERR, "hardreset failed (%s)\n", reason);
 	return -EIO;
 }
 
@@ -656,6 +808,38 @@
 	}
 }
 
+static int sil24_qc_defer(struct ata_queued_cmd *qc)
+{
+	struct ata_link *link = qc->dev->link;
+	struct ata_port *ap = link->ap;
+	u8 prot = qc->tf.protocol;
+	int is_atapi = (prot == ATA_PROT_ATAPI ||
+			prot == ATA_PROT_ATAPI_NODATA ||
+			prot == ATA_PROT_ATAPI_DMA);
+
+	/* ATAPI commands completing with CHECK_SENSE cause various
+	 * weird problems if other commands are active.  PMP DMA CS
+	 * errata doesn't cover all and HSM violation occurs even with
+	 * only one other device active.  Always run an ATAPI command
+	 * by itself.
+	 */
+	if (unlikely(ap->excl_link)) {
+		if (link == ap->excl_link) {
+			if (ap->nr_active_links)
+				return ATA_DEFER_PORT;
+			qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+		} else
+			return ATA_DEFER_PORT;
+	} else if (unlikely(is_atapi)) {
+		ap->excl_link = link;
+		if (ap->nr_active_links)
+			return ATA_DEFER_PORT;
+		qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
+	}
+
+	return ata_std_qc_defer(qc);
+}
+
 static void sil24_qc_prep(struct ata_queued_cmd *qc)
 {
 	struct ata_port *ap = qc->ap;
@@ -699,7 +883,7 @@
 	}
 
 	prb->ctrl = cpu_to_le16(ctrl);
-	ata_tf_to_fis(&qc->tf, prb->fis, 0);
+	ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, prb->fis);
 
 	if (qc->flags & ATA_QCFLAG_DMAMAP)
 		sil24_fill_sg(qc, sge);
@@ -728,6 +912,39 @@
 	/* unused */
 }
 
+static void sil24_pmp_attach(struct ata_port *ap)
+{
+	sil24_config_pmp(ap, 1);
+	sil24_init_port(ap);
+}
+
+static void sil24_pmp_detach(struct ata_port *ap)
+{
+	sil24_init_port(ap);
+	sil24_config_pmp(ap, 0);
+}
+
+static int sil24_pmp_softreset(struct ata_link *link, unsigned int *class,
+			       unsigned long deadline)
+{
+	return sil24_do_softreset(link, class, link->pmp, deadline);
+}
+
+static int sil24_pmp_hardreset(struct ata_link *link, unsigned int *class,
+			       unsigned long deadline)
+{
+	int rc;
+
+	rc = sil24_init_port(link->ap);
+	if (rc) {
+		ata_link_printk(link, KERN_ERR,
+				"hardreset failed (port not ready)\n");
+		return rc;
+	}
+
+	return sata_pmp_std_hardreset(link, class, deadline);
+}
+
 static void sil24_freeze(struct ata_port *ap)
 {
 	void __iomem *port = ap->ioaddr.cmd_addr;
@@ -754,8 +971,11 @@
 static void sil24_error_intr(struct ata_port *ap)
 {
 	void __iomem *port = ap->ioaddr.cmd_addr;
-	struct ata_eh_info *ehi = &ap->eh_info;
-	int freeze = 0;
+	struct sil24_port_priv *pp = ap->private_data;
+	struct ata_queued_cmd *qc = NULL;
+	struct ata_link *link;
+	struct ata_eh_info *ehi;
+	int abort = 0, freeze = 0;
 	u32 irq_stat;
 
 	/* on error, we need to clear IRQ explicitly */
@@ -763,22 +983,29 @@
 	writel(irq_stat, port + PORT_IRQ_STAT);
 
 	/* first, analyze and record host port events */
+	link = &ap->link;
+	ehi = &link->eh_info;
 	ata_ehi_clear_desc(ehi);
 
 	ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat);
 
+	if (irq_stat & PORT_IRQ_SDB_NOTIFY) {
+		ata_ehi_push_desc(ehi, "SDB notify");
+		sata_async_notification(ap);
+	}
+
 	if (irq_stat & (PORT_IRQ_PHYRDY_CHG | PORT_IRQ_DEV_XCHG)) {
 		ata_ehi_hotplugged(ehi);
-		ata_ehi_push_desc(ehi, ", %s",
-			       irq_stat & PORT_IRQ_PHYRDY_CHG ?
-			       "PHY RDY changed" : "device exchanged");
+		ata_ehi_push_desc(ehi, "%s",
+				  irq_stat & PORT_IRQ_PHYRDY_CHG ?
+				  "PHY RDY changed" : "device exchanged");
 		freeze = 1;
 	}
 
 	if (irq_stat & PORT_IRQ_UNK_FIS) {
 		ehi->err_mask |= AC_ERR_HSM;
 		ehi->action |= ATA_EH_SOFTRESET;
-		ata_ehi_push_desc(ehi , ", unknown FIS");
+		ata_ehi_push_desc(ehi, "unknown FIS");
 		freeze = 1;
 	}
 
@@ -786,8 +1013,44 @@
 	if (irq_stat & PORT_IRQ_ERROR) {
 		struct sil24_cerr_info *ci = NULL;
 		unsigned int err_mask = 0, action = 0;
-		struct ata_queued_cmd *qc;
-		u32 cerr;
+		u32 context, cerr;
+		int pmp;
+
+		abort = 1;
+
+		/* DMA Context Switch Failure in Port Multiplier Mode
+		 * errata.  If we have active commands to 3 or more
+		 * devices, any error condition on active devices can
+		 * corrupt DMA context switching.
+		 */
+		if (ap->nr_active_links >= 3) {
+			ehi->err_mask |= AC_ERR_OTHER;
+			ehi->action |= ATA_EH_HARDRESET;
+			ata_ehi_push_desc(ehi, "PMP DMA CS errata");
+			pp->do_port_rst = 1;
+			freeze = 1;
+		}
+
+		/* find out the offending link and qc */
+		if (ap->nr_pmp_links) {
+			context = readl(port + PORT_CONTEXT);
+			pmp = (context >> 5) & 0xf;
+
+			if (pmp < ap->nr_pmp_links) {
+				link = &ap->pmp_link[pmp];
+				ehi = &link->eh_info;
+				qc = ata_qc_from_tag(ap, link->active_tag);
+
+				ata_ehi_clear_desc(ehi);
+				ata_ehi_push_desc(ehi, "irq_stat 0x%08x",
+						  irq_stat);
+			} else {
+				err_mask |= AC_ERR_HSM;
+				action |= ATA_EH_HARDRESET;
+				freeze = 1;
+			}
+		} else
+			qc = ata_qc_from_tag(ap, link->active_tag);
 
 		/* analyze CMD_ERR */
 		cerr = readl(port + PORT_CMD_ERR);
@@ -797,36 +1060,46 @@
 		if (ci && ci->desc) {
 			err_mask |= ci->err_mask;
 			action |= ci->action;
-			ata_ehi_push_desc(ehi, ", %s", ci->desc);
+			ata_ehi_push_desc(ehi, "%s", ci->desc);
 		} else {
 			err_mask |= AC_ERR_OTHER;
 			action |= ATA_EH_SOFTRESET;
-			ata_ehi_push_desc(ehi, ", unknown command error %d",
+			ata_ehi_push_desc(ehi, "unknown command error %d",
 					  cerr);
 		}
 
 		/* record error info */
-		qc = ata_qc_from_tag(ap, ap->active_tag);
 		if (qc) {
-			sil24_update_tf(ap);
+			sil24_read_tf(ap, qc->tag, &pp->tf);
 			qc->err_mask |= err_mask;
 		} else
 			ehi->err_mask |= err_mask;
 
 		ehi->action |= action;
+
+		/* if PMP, resume */
+		if (ap->nr_pmp_links)
+			writel(PORT_CS_PMP_RESUME, port + PORT_CTRL_STAT);
 	}
 
 	/* freeze or abort */
 	if (freeze)
 		ata_port_freeze(ap);
-	else
-		ata_port_abort(ap);
+	else if (abort) {
+		if (qc)
+			ata_link_abort(qc->dev->link);
+		else
+			ata_port_abort(ap);
+	}
 }
 
 static void sil24_finish_qc(struct ata_queued_cmd *qc)
 {
+	struct ata_port *ap = qc->ap;
+	struct sil24_port_priv *pp = ap->private_data;
+
 	if (qc->flags & ATA_QCFLAG_RESULT_TF)
-		sil24_update_tf(qc->ap);
+		sil24_read_tf(ap, qc->tag, &pp->tf);
 }
 
 static inline void sil24_host_intr(struct ata_port *ap)
@@ -835,6 +1108,16 @@
 	u32 slot_stat, qc_active;
 	int rc;
 
+	/* If PCIX_IRQ_WOC, there's an inherent race window between
+	 * clearing IRQ pending status and reading PORT_SLOT_STAT
+	 * which may cause spurious interrupts afterwards.  This is
+	 * unavoidable and much better than losing interrupts which
+	 * happens if IRQ pending is cleared after reading
+	 * PORT_SLOT_STAT.
+	 */
+	if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
+		writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT);
+
 	slot_stat = readl(port + PORT_SLOT_STAT);
 
 	if (unlikely(slot_stat & HOST_SSTAT_ATTN)) {
@@ -842,25 +1125,23 @@
 		return;
 	}
 
-	if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC)
-		writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT);
-
 	qc_active = slot_stat & ~HOST_SSTAT_ATTN;
 	rc = ata_qc_complete_multiple(ap, qc_active, sil24_finish_qc);
 	if (rc > 0)
 		return;
 	if (rc < 0) {
-		struct ata_eh_info *ehi = &ap->eh_info;
+		struct ata_eh_info *ehi = &ap->link.eh_info;
 		ehi->err_mask |= AC_ERR_HSM;
 		ehi->action |= ATA_EH_SOFTRESET;
 		ata_port_freeze(ap);
 		return;
 	}
 
-	if (ata_ratelimit())
+	/* spurious interrupts are expected if PCIX_IRQ_WOC */
+	if (!(ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) && ata_ratelimit())
 		ata_port_printk(ap, KERN_INFO, "spurious interrupt "
 			"(slot_stat 0x%x active_tag %d sactive 0x%x)\n",
-			slot_stat, ap->active_tag, ap->sactive);
+			slot_stat, ap->link.active_tag, ap->link.sactive);
 }
 
 static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
@@ -902,16 +1183,18 @@
 
 static void sil24_error_handler(struct ata_port *ap)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct sil24_port_priv *pp = ap->private_data;
 
-	if (sil24_init_port(ap)) {
+	if (sil24_init_port(ap))
 		ata_eh_freeze_port(ap);
-		ehc->i.action |= ATA_EH_HARDRESET;
-	}
 
 	/* perform recovery */
-	ata_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
-		  ata_std_postreset);
+	sata_pmp_do_eh(ap, ata_std_prereset, sil24_softreset, sil24_hardreset,
+		       ata_std_postreset, sata_pmp_std_prereset,
+		       sil24_pmp_softreset, sil24_pmp_hardreset,
+		       sata_pmp_std_postreset);
+
+	pp->do_port_rst = 0;
 }
 
 static void sil24_post_internal_cmd(struct ata_queued_cmd *qc)
@@ -919,8 +1202,8 @@
 	struct ata_port *ap = qc->ap;
 
 	/* make DMA engine forget about the failed command */
-	if (qc->flags & ATA_QCFLAG_FAILED)
-		sil24_init_port(ap);
+	if ((qc->flags & ATA_QCFLAG_FAILED) && sil24_init_port(ap))
+		ata_eh_freeze_port(ap);
 }
 
 static int sil24_port_start(struct ata_port *ap)
@@ -958,7 +1241,6 @@
 static void sil24_init_controller(struct ata_host *host)
 {
 	void __iomem *host_base = host->iomap[SIL24_HOST_BAR];
-	void __iomem *port_base = host->iomap[SIL24_PORT_BAR];
 	u32 tmp;
 	int i;
 
@@ -970,7 +1252,8 @@
 
 	/* init ports */
 	for (i = 0; i < host->n_ports; i++) {
-		void __iomem *port = port_base + i * PORT_REGS_SIZE;
+		struct ata_port *ap = host->ports[i];
+		void __iomem *port = ap->ioaddr.cmd_addr;
 
 		/* Initial PHY setting */
 		writel(0x20c, port + PORT_PHY_CFG);
@@ -987,26 +1270,8 @@
 				           "failed to clear port RST\n");
 		}
 
-		/* Configure IRQ WoC */
-		if (host->ports[0]->flags & SIL24_FLAG_PCIX_IRQ_WOC)
-			writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
-		else
-			writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
-
-		/* Zero error counters. */
-		writel(0x8000, port + PORT_DECODE_ERR_THRESH);
-		writel(0x8000, port + PORT_CRC_ERR_THRESH);
-		writel(0x8000, port + PORT_HSHK_ERR_THRESH);
-		writel(0x0000, port + PORT_DECODE_ERR_CNT);
-		writel(0x0000, port + PORT_CRC_ERR_CNT);
-		writel(0x0000, port + PORT_HSHK_ERR_CNT);
-
-		/* Always use 64bit activation */
-		writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
-
-		/* Clear port multiplier enable and resume bits */
-		writel(PORT_CS_PMP_EN | PORT_CS_PMP_RESUME,
-		       port + PORT_CTRL_CLR);
+		/* configure port */
+		sil24_config_port(ap);
 	}
 
 	/* Turn on interrupts */
@@ -1057,12 +1322,15 @@
 	host->iomap = iomap;
 
 	for (i = 0; i < host->n_ports; i++) {
-		void __iomem *port = iomap[SIL24_PORT_BAR] + i * PORT_REGS_SIZE;
+		struct ata_port *ap = host->ports[i];
+		size_t offset = ap->port_no * PORT_REGS_SIZE;
+		void __iomem *port = iomap[SIL24_PORT_BAR] + offset;
 
 		host->ports[i]->ioaddr.cmd_addr = port;
 		host->ports[i]->ioaddr.scr_addr = port + PORT_SCONTROL;
 
-		ata_std_ports(&host->ports[i]->ioaddr);
+		ata_port_pbar_desc(ap, SIL24_HOST_BAR, -1, "host");
+		ata_port_pbar_desc(ap, SIL24_PORT_BAR, offset, "port");
 	}
 
 	/* configure and activate the device */
@@ -1118,6 +1386,12 @@
 
 	return 0;
 }
+
+static int sil24_port_resume(struct ata_port *ap)
+{
+	sil24_config_pmp(ap, ap->nr_pmp_links);
+	return 0;
+}
 #endif
 
 static int __init sil24_init(void)
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 33716b0..8d98a9f 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -43,7 +43,7 @@
 #include "sis.h"
 
 #define DRV_NAME	"sata_sis"
-#define DRV_VERSION	"0.8"
+#define DRV_VERSION	"1.0"
 
 enum {
 	sis_180			= 0,
@@ -64,8 +64,8 @@
 };
 
 static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int sis_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
 static const struct pci_device_id sis_pci_tbl[] = {
 	{ PCI_VDEVICE(SI, 0x0180), sis_180 },		/* SiS 964/180 */
@@ -104,7 +104,6 @@
 };
 
 static const struct ata_port_operations sis_ops = {
-	.port_disable		= ata_port_disable,
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
 	.check_status		= ata_check_status,
@@ -123,7 +122,6 @@
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 	.scr_read		= sis_scr_read,
 	.scr_write		= sis_scr_write,
 	.port_start		= ata_port_start,
@@ -207,36 +205,37 @@
 		pci_write_config_dword(pdev, cfg_addr+0x10, val);
 }
 
-static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
-	u32 val, val2 = 0;
 	u8 pmr;
 
 	if (sc_reg > SCR_CONTROL)
-		return 0xffffffffU;
+		return -EINVAL;
 
 	if (ap->flags & SIS_FLAG_CFGSCR)
 		return sis_scr_cfg_read(ap, sc_reg);
 
 	pci_read_config_byte(pdev, SIS_PMR, &pmr);
 
-	val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
+	*val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
 
 	if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
 	    (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
-		val2 = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
+		*val |= ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
 
-	return (val | val2) &  0xfffffffb;
+	*val &= 0xfffffffb;
+
+	return 0;
 }
 
-static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	u8 pmr;
 
 	if (sc_reg > SCR_CONTROL)
-		return;
+		return -EINVAL;
 
 	pci_read_config_byte(pdev, SIS_PMR, &pmr);
 
@@ -248,6 +247,7 @@
 		    (pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
 			iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
 	}
+	return 0;
 }
 
 static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index 63fe99af..12d613c 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -53,7 +53,7 @@
 #endif /* CONFIG_PPC_OF */
 
 #define DRV_NAME	"sata_svw"
-#define DRV_VERSION	"2.2"
+#define DRV_VERSION	"2.3"
 
 enum {
 	/* ap->flags bits */
@@ -103,20 +103,21 @@
 	return 0;
 }
 
-static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int k2_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return 0xffffffffU;
-	return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+		return -EINVAL;
+	*val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+	return 0;
 }
 
 
-static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
-			       u32 val)
+static int k2_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return;
+		return -EINVAL;
 	writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+	return 0;
 }
 
 
@@ -328,7 +329,6 @@
 
 
 static const struct ata_port_operations k2_sata_ops = {
-	.port_disable		= ata_port_disable,
 	.tf_load		= k2_sata_tf_load,
 	.tf_read		= k2_sata_tf_read,
 	.check_status		= k2_stat_check_status,
@@ -348,7 +348,6 @@
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 	.scr_read		= k2_sata_scr_read,
 	.scr_write		= k2_sata_scr_write,
 	.port_start		= ata_port_start,
@@ -444,9 +443,15 @@
 	/* different controllers have different number of ports - currently 4 or 8 */
 	/* All ports are on the same function. Multi-function device is no
 	 * longer available. This should not be seen in any system. */
-	for (i = 0; i < host->n_ports; i++)
-		k2_sata_setup_port(&host->ports[i]->ioaddr,
-				   mmio_base + i * K2_SATA_PORT_OFFSET);
+	for (i = 0; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
+		unsigned int offset = i * K2_SATA_PORT_OFFSET;
+
+		k2_sata_setup_port(&ap->ioaddr, mmio_base + offset);
+
+		ata_port_pbar_desc(ap, 5, -1, "mmio");
+		ata_port_pbar_desc(ap, 5, offset, "port");
+	}
 
 	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
 	if (rc)
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 5193bd8..9f9f7b3 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -92,7 +92,7 @@
 #include "sata_promise.h"
 
 #define DRV_NAME	"sata_sx4"
-#define DRV_VERSION	"0.11"
+#define DRV_VERSION	"0.12"
 
 
 enum {
@@ -254,7 +254,6 @@
 };
 
 static const struct ata_port_operations pdc_20621_ops = {
-	.port_disable		= ata_port_disable,
 	.tf_load		= pdc_tf_load_mmio,
 	.tf_read		= ata_tf_read,
 	.check_status		= ata_check_status,
@@ -267,7 +266,6 @@
 	.eng_timeout		= pdc_eng_timeout,
 	.irq_clear		= pdc20621_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 	.port_start		= pdc_port_start,
 };
 
@@ -854,7 +852,7 @@
 		    !(ap->flags & ATA_FLAG_DISABLED)) {
 			struct ata_queued_cmd *qc;
 
-			qc = ata_qc_from_tag(ap, ap->active_tag);
+			qc = ata_qc_from_tag(ap, ap->link.active_tag);
 			if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)))
 				handled += pdc20621_host_intr(ap, qc, (i > 4),
 							      mmio_base);
@@ -881,7 +879,7 @@
 
 	spin_lock_irqsave(&host->lock, flags);
 
-	qc = ata_qc_from_tag(ap, ap->active_tag);
+	qc = ata_qc_from_tag(ap, ap->link.active_tag);
 
 	switch (qc->tf.protocol) {
 	case ATA_PROT_DMA:
@@ -1383,9 +1381,8 @@
 	const struct ata_port_info *ppi[] =
 		{ &pdc_port_info[ent->driver_data], NULL };
 	struct ata_host *host;
-	void __iomem *base;
 	struct pdc_host_priv *hpriv;
-	int rc;
+	int i, rc;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -1411,11 +1408,17 @@
 		return rc;
 	host->iomap = pcim_iomap_table(pdev);
 
-	base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
-	pdc_sata_setup_port(&host->ports[0]->ioaddr, base + 0x200);
-	pdc_sata_setup_port(&host->ports[1]->ioaddr, base + 0x280);
-	pdc_sata_setup_port(&host->ports[2]->ioaddr, base + 0x300);
-	pdc_sata_setup_port(&host->ports[3]->ioaddr, base + 0x380);
+	for (i = 0; i < 4; i++) {
+		struct ata_port *ap = host->ports[i];
+		void __iomem *base = host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS;
+		unsigned int offset = 0x200 + i * 0x80;
+
+		pdc_sata_setup_port(&ap->ioaddr, base + offset);
+
+		ata_port_pbar_desc(ap, PDC_MMIO_BAR, -1, "mmio");
+		ata_port_pbar_desc(ap, PDC_DIMM_BAR, -1, "dimm");
+		ata_port_pbar_desc(ap, PDC_MMIO_BAR, offset, "port");
+	}
 
 	/* configure and activate */
 	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index b52f83a..d394da0 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -36,7 +36,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"sata_uli"
-#define DRV_VERSION	"1.2"
+#define DRV_VERSION	"1.3"
 
 enum {
 	uli_5289		= 0,
@@ -57,8 +57,8 @@
 };
 
 static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
 static const struct pci_device_id uli_pci_tbl[] = {
 	{ PCI_VDEVICE(AL, 0x5289), uli_5289 },
@@ -94,8 +94,6 @@
 };
 
 static const struct ata_port_operations uli_ops = {
-	.port_disable		= ata_port_disable,
-
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
 	.check_status		= ata_check_status,
@@ -117,7 +115,6 @@
 
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	.scr_read		= uli_scr_read,
 	.scr_write		= uli_scr_write,
@@ -164,20 +161,22 @@
 	pci_write_config_dword(pdev, cfg_addr, val);
 }
 
-static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int uli_scr_read (struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return 0xffffffffU;
+		return -EINVAL;
 
-	return uli_scr_cfg_read(ap, sc_reg);
+	*val = uli_scr_cfg_read(ap, sc_reg);
+	return 0;
 }
 
-static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)	//SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
-		return;
+		return -EINVAL;
 
 	uli_scr_cfg_write(ap, sc_reg, val);
+	return 0;
 }
 
 static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -240,6 +239,12 @@
 		hpriv->scr_cfg_addr[2] = ULI5287_BASE + ULI5287_OFFS*4;
 		ata_std_ports(ioaddr);
 
+		ata_port_desc(host->ports[2],
+			"cmd 0x%llx ctl 0x%llx bmdma 0x%llx",
+			(unsigned long long)pci_resource_start(pdev, 0) + 8,
+			((unsigned long long)pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4,
+			(unsigned long long)pci_resource_start(pdev, 4) + 16);
+
 		ioaddr = &host->ports[3]->ioaddr;
 		ioaddr->cmd_addr = iomap[2] + 8;
 		ioaddr->altstatus_addr =
@@ -248,6 +253,13 @@
 		ioaddr->bmdma_addr = iomap[4] + 24;
 		hpriv->scr_cfg_addr[3] = ULI5287_BASE + ULI5287_OFFS*5;
 		ata_std_ports(ioaddr);
+
+		ata_port_desc(host->ports[2],
+			"cmd 0x%llx ctl 0x%llx bmdma 0x%llx",
+			(unsigned long long)pci_resource_start(pdev, 2) + 9,
+			((unsigned long long)pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4,
+			(unsigned long long)pci_resource_start(pdev, 4) + 24);
+
 		break;
 
 	case uli_5289:
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index c412447..1dc9b4f 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -46,7 +46,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"sata_via"
-#define DRV_VERSION	"2.2"
+#define DRV_VERSION	"2.3"
 
 enum board_ids_enum {
 	vt6420,
@@ -57,7 +57,6 @@
 	SATA_CHAN_ENAB		= 0x40, /* SATA channel enable */
 	SATA_INT_GATE		= 0x41, /* SATA interrupt gating */
 	SATA_NATIVE_MODE	= 0x42, /* Native mode enable */
-	SATA_PATA_SHARING	= 0x49, /* PATA/SATA sharing func ctrl */
 	PATA_UDMA_TIMING	= 0xB3, /* PATA timing for DMA/ cable detect */
 	PATA_PIO_TIMING		= 0xAB, /* PATA timing register */
 
@@ -68,12 +67,11 @@
 	NATIVE_MODE_ALL		= (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
 
 	SATA_EXT_PHY		= (1 << 6), /* 0==use PATA, 1==ext phy */
-	SATA_2DEV		= (1 << 5), /* SATA is master/slave */
 };
 
 static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val);
+static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val);
 static void svia_noop_freeze(struct ata_port *ap);
 static void vt6420_error_handler(struct ata_port *ap);
 static int vt6421_pata_cable_detect(struct ata_port *ap);
@@ -122,8 +120,6 @@
 };
 
 static const struct ata_port_operations vt6420_sata_ops = {
-	.port_disable		= ata_port_disable,
-
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
 	.check_status		= ata_check_status,
@@ -146,14 +142,11 @@
 
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	.port_start		= ata_port_start,
 };
 
 static const struct ata_port_operations vt6421_pata_ops = {
-	.port_disable		= ata_port_disable,
-
 	.set_piomode		= vt6421_set_pio_mode,
 	.set_dmamode		= vt6421_set_dma_mode,
 
@@ -180,14 +173,11 @@
 
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	.port_start		= ata_port_start,
 };
 
 static const struct ata_port_operations vt6421_sata_ops = {
-	.port_disable		= ata_port_disable,
-
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
 	.check_status		= ata_check_status,
@@ -211,7 +201,6 @@
 
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 
 	.scr_read		= svia_scr_read,
 	.scr_write		= svia_scr_write,
@@ -249,18 +238,20 @@
 MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
 MODULE_VERSION(DRV_VERSION);
 
-static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return 0xffffffffU;
-	return ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+		return -EINVAL;
+	*val = ioread32(ap->ioaddr.scr_addr + (4 * sc_reg));
+	return 0;
 }
 
-static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return;
+		return -EINVAL;
 	iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+	return 0;
 }
 
 static void svia_noop_freeze(struct ata_port *ap)
@@ -274,7 +265,7 @@
 
 /**
  *	vt6420_prereset - prereset for vt6420
- *	@ap: target ATA port
+ *	@link: target ATA link
  *	@deadline: deadline jiffies for the operation
  *
  *	SCR registers on vt6420 are pieces of shit and may hang the
@@ -292,9 +283,10 @@
  *	RETURNS:
  *	0 on success, -errno otherwise.
  */
-static int vt6420_prereset(struct ata_port *ap, unsigned long deadline)
+static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
 {
-	struct ata_eh_context *ehc = &ap->eh_context;
+	struct ata_port *ap = link->ap;
+	struct ata_eh_context *ehc = &ap->link.eh_context;
 	unsigned long timeout = jiffies + (HZ * 5);
 	u32 sstatus, scontrol;
 	int online;
@@ -305,18 +297,19 @@
 
 	/* Resume phy.  This is the old SATA resume sequence */
 	svia_scr_write(ap, SCR_CONTROL, 0x300);
-	svia_scr_read(ap, SCR_CONTROL); /* flush */
+	svia_scr_read(ap, SCR_CONTROL, &scontrol); /* flush */
 
 	/* wait for phy to become ready, if necessary */
 	do {
 		msleep(200);
-		if ((svia_scr_read(ap, SCR_STATUS) & 0xf) != 1)
+		svia_scr_read(ap, SCR_STATUS, &sstatus);
+		if ((sstatus & 0xf) != 1)
 			break;
 	} while (time_before(jiffies, timeout));
 
 	/* open code sata_print_link_status() */
-	sstatus = svia_scr_read(ap, SCR_STATUS);
-	scontrol = svia_scr_read(ap, SCR_CONTROL);
+	svia_scr_read(ap, SCR_STATUS, &sstatus);
+	svia_scr_read(ap, SCR_CONTROL, &scontrol);
 
 	online = (sstatus & 0xf) == 0x3;
 
@@ -325,7 +318,7 @@
 			online ? "up" : "down", sstatus, scontrol);
 
 	/* SStatus is read one more time */
-	svia_scr_read(ap, SCR_STATUS);
+	svia_scr_read(ap, SCR_STATUS, &sstatus);
 
 	if (!online) {
 		/* tell EH to bail */
@@ -368,7 +361,7 @@
 {
 	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
 	static const u8 udma_bits[] = { 0xEE, 0xE8, 0xE6, 0xE4, 0xE2, 0xE1, 0xE0, 0xE0 };
-	pci_write_config_byte(pdev, PATA_UDMA_TIMING, udma_bits[adev->pio_mode - XFER_UDMA_0]);
+	pci_write_config_byte(pdev, PATA_UDMA_TIMING, udma_bits[adev->dma_mode - XFER_UDMA_0]);
 }
 
 static const unsigned int svia_bar_sizes[] = {
@@ -404,6 +397,9 @@
 	ioaddr->scr_addr = vt6421_scr_addr(iomap[5], ap->port_no);
 
 	ata_std_ports(ioaddr);
+
+	ata_port_pbar_desc(ap, ap->port_no, -1, "port");
+	ata_port_pbar_desc(ap, 4, ap->port_no * 8, "bmdma");
 }
 
 static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
@@ -510,7 +506,6 @@
 	struct ata_host *host;
 	int board_id = (int) ent->driver_data;
 	const int *bar_sizes;
-	u8 tmp8;
 
 	if (!printed_version++)
 		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -519,19 +514,10 @@
 	if (rc)
 		return rc;
 
-	if (board_id == vt6420) {
-		pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
-		if (tmp8 & SATA_2DEV) {
-			dev_printk(KERN_ERR, &pdev->dev,
-				   "SATA master/slave not supported (0x%x)\n",
-		       		   (int) tmp8);
-			return -EIO;
-		}
-
+	if (board_id == vt6420)
 		bar_sizes = &svia_bar_sizes[0];
-	} else {
+	else
 		bar_sizes = &vt6421_bar_sizes[0];
-	}
 
 	for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
 		if ((pci_resource_start(pdev, i) == 0) ||
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index 1b5d81f..0d9be16 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -47,7 +47,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME	"sata_vsc"
-#define DRV_VERSION	"2.2"
+#define DRV_VERSION	"2.3"
 
 enum {
 	VSC_MMIO_BAR			= 0,
@@ -98,20 +98,21 @@
 			      VSC_SATA_INT_PHY_CHANGE),
 };
 
-static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+static int vsc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return 0xffffffffU;
-	return readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+		return -EINVAL;
+	*val = readl(ap->ioaddr.scr_addr + (sc_reg * 4));
+	return 0;
 }
 
 
-static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
-			       u32 val)
+static int vsc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
 {
 	if (sc_reg > SCR_CONTROL)
-		return;
+		return -EINVAL;
 	writel(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+	return 0;
 }
 
 
@@ -239,7 +240,7 @@
 		return;
 	}
 
-	qc = ata_qc_from_tag(ap, ap->active_tag);
+	qc = ata_qc_from_tag(ap, ap->link.active_tag);
 	if (qc && likely(!(qc->tf.flags & ATA_TFLAG_POLLING)))
 		handled = ata_host_intr(ap, qc);
 
@@ -316,7 +317,6 @@
 
 
 static const struct ata_port_operations vsc_sata_ops = {
-	.port_disable		= ata_port_disable,
 	.tf_load		= vsc_sata_tf_load,
 	.tf_read		= vsc_sata_tf_read,
 	.exec_command		= ata_exec_command,
@@ -335,7 +335,6 @@
 	.post_internal_cmd	= ata_bmdma_post_internal_cmd,
 	.irq_clear		= ata_bmdma_irq_clear,
 	.irq_on			= ata_irq_on,
-	.irq_ack		= ata_irq_ack,
 	.scr_read		= vsc_sata_scr_read,
 	.scr_write		= vsc_sata_scr_write,
 	.port_start		= ata_port_start,
@@ -407,9 +406,15 @@
 
 	mmio_base = host->iomap[VSC_MMIO_BAR];
 
-	for (i = 0; i < host->n_ports; i++)
-		vsc_sata_setup_port(&host->ports[i]->ioaddr,
-				    mmio_base + (i + 1) * VSC_SATA_PORT_OFFSET);
+	for (i = 0; i < host->n_ports; i++) {
+		struct ata_port *ap = host->ports[i];
+		unsigned int offset = (i + 1) * VSC_SATA_PORT_OFFSET;
+
+		vsc_sata_setup_port(&ap->ioaddr, mmio_base + offset);
+
+		ata_port_pbar_desc(ap, VSC_MMIO_BAR, -1, "mmio");
+		ata_port_pbar_desc(ap, VSC_MMIO_BAR, offset, "port");
+	}
 
 	/*
 	 * Use 32 bit DMA mask, because 64 bit address support is poor.
diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig
index bb4ae628..b554eda 100644
--- a/drivers/atm/Kconfig
+++ b/drivers/atm/Kconfig
@@ -6,6 +6,11 @@
 	bool "ATM drivers"
 	depends on NETDEVICES && ATM
 	default y
+	---help---
+	  Say Y here to get to see options for Asynchronous Transfer Mode
+	  device drivers. This option alone does not add any kernel code.
+
+	  If you say N, all options in this submenu will be skipped and disabled.
 
 if ATM_DRIVERS && NETDEVICES && ATM
 
@@ -172,7 +177,7 @@
 
 config ATM_NICSTAR
 	tristate "IDT 77201 (NICStAR) (ForeRunnerLE)"
-	depends on PCI && !64BIT
+	depends on PCI && !64BIT && VIRT_TO_BUS
 	help
 	  The NICStAR chipset family is used in a large number of ATM NICs for
 	  25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index 77637e7..41b2204 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -1738,7 +1738,8 @@
 			printk(KERN_ERR KERN_ERR DEV_LABEL "(itf %d): bad "
 			    "magic - expected 0x%x, got 0x%x\n",dev->number,
 			    ENI155_MAGIC,(unsigned) readl(&eprom->magic));
-			return -EINVAL;
+			error = -EINVAL;
+			goto unmap;
 		}
 	}
 	eni_dev->phy = base+PHY_BASE;
@@ -1765,17 +1766,27 @@
 		printk(")\n");
 		printk(KERN_ERR DEV_LABEL "(itf %d): ERROR - wrong id 0x%x\n",
 		    dev->number,(unsigned) eni_in(MID_RES_ID_MCON));
-		return -EINVAL;
+		error = -EINVAL;
+		goto unmap;
 	}
 	error = eni_dev->asic ? get_esi_asic(dev) : get_esi_fpga(dev,base);
-	if (error) return error;
+	if (error)
+		goto unmap;
 	for (i = 0; i < ESI_LEN; i++)
 		printk("%s%02X",i ? "-" : "",dev->esi[i]);
 	printk(")\n");
 	printk(KERN_NOTICE DEV_LABEL "(itf %d): %s,%s\n",dev->number,
 	    eni_in(MID_RES_ID_MCON) & 0x200 ? "ASIC" : "FPGA",
 	    media_name[eni_in(MID_RES_ID_MCON) & DAUGTHER_ID]);
-	return suni_init(dev);
+
+	error = suni_init(dev);
+	if (error)
+		goto unmap;
+out:
+	return error;
+unmap:
+	iounmap(base);
+	goto out;
 }
 
 
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index 38b688f..737cea4 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -1710,7 +1710,7 @@
 		/* This bit is documented as "RESERVED" */
 		if (isr & ISR_INIT_ERR) {
 			printk (KERN_ERR "Error initializing the FS... \n");
-			return 1;
+			goto unmap;
 		}
 		if (isr & ISR_INIT) {
 			fs_dprintk (FS_DEBUG_INIT, "Ha! Initialized OK!\n");
@@ -1723,7 +1723,7 @@
 
 	if (!to) {
 		printk (KERN_ERR "timeout initializing the FS... \n");
-		return 1;
+		goto unmap;
 	}
 
 	/* XXX fix for fs155 */
@@ -1803,7 +1803,7 @@
 	if (!dev->atm_vccs) {
 		printk (KERN_WARNING "Couldn't allocate memory for VCC buffers. Woops!\n");
 		/* XXX Clean up..... */
-		return 1;
+		goto unmap;
 	}
 
 	dev->tx_inuse = kzalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL);
@@ -1813,7 +1813,7 @@
 	if (!dev->tx_inuse) {
 		printk (KERN_WARNING "Couldn't allocate memory for tx_inuse bits!\n");
 		/* XXX Clean up..... */
-		return 1;
+		goto unmap;
 	}
 	/* -- RAS1 : FS155 and 50 differ. Default (0) should be OK for both */
 	/* -- RAS2 : FS50 only: Default is OK. */
@@ -1840,7 +1840,7 @@
 	if (request_irq (dev->irq, fs_irq, IRQF_SHARED, "firestream", dev)) {
 		printk (KERN_WARNING "couldn't get irq %d for firestream.\n", pci_dev->irq);
 		/* XXX undo all previous stuff... */
-		return 1;
+		goto unmap;
 	}
 	fs_dprintk (FS_DEBUG_INIT, "Grabbed irq %d for dev at %p.\n", dev->irq, dev);
   
@@ -1890,6 +1890,9 @@
   
 	func_exit ();
 	return 0;
+unmap:
+	iounmap(dev->base);
+	return 1;
 }
 
 static int __devinit firestream_init_one (struct pci_dev *pci_dev,
@@ -2012,6 +2015,7 @@
 		for (i=0;i < FS_NR_RX_QUEUES;i++)
 			free_queue (dev, &dev->rx_rq[i]);
 
+		iounmap(dev->base);
 		fs_dprintk (FS_DEBUG_ALLOC, "Free fs-dev: %p\n", dev);
 		nxtdev = dev->next;
 		kfree (dev);
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index 405ee5e..8b12925 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -2435,7 +2435,7 @@
 }
 
 
-static void __init
+static void __devinit
 fore200e_param_bs_queue(struct fore200e* fore200e,
 			enum buffer_scheme scheme, enum buffer_magn magn,
 			int queue_length, int pool_size, int supply_blksize)
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index 8f995ce..eee54c0 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -65,7 +65,7 @@
 static unsigned int vpibits = 1;
 
 
-#define CONFIG_ATM_IDT77252_SEND_IDLE 1
+#define ATM_IDT77252_SEND_IDLE 1
 
 
 /*
@@ -3404,7 +3404,7 @@
 	conf =	SAR_CFG_TX_FIFO_SIZE_9 |	/* Use maximum fifo size */
 		SAR_CFG_RXSTQ_SIZE_8k |		/* Receive Status Queue is 8k */
 		SAR_CFG_IDLE_CLP |		/* Set CLP on idle cells */
-#ifndef CONFIG_ATM_IDT77252_SEND_IDLE
+#ifndef ATM_IDT77252_SEND_IDLE
 		SAR_CFG_NO_IDLE |		/* Do not send idle cells */
 #endif
 		0;
@@ -3541,7 +3541,7 @@
 	printk("%s: Linkrate on ATM line : %u bit/s, %u cell/s.\n",
 	       card->name, linkrate, card->link_pcr);
 
-#ifdef CONFIG_ATM_IDT77252_SEND_IDLE
+#ifdef ATM_IDT77252_SEND_IDLE
 	card->utopia_pcr = card->link_pcr;
 #else
 	card->utopia_pcr = (160000000 / 8 / 54);
@@ -3576,7 +3576,7 @@
 	 * XXX: <hack>
 	 */
 	sprintf(tname, "eth%d", card->index);
-	tmp = dev_get_by_name(tname);	/* jhs: was "tmp = dev_get(tname);" */
+	tmp = dev_get_by_name(&init_net, tname);	/* jhs: was "tmp = dev_get(tname);" */
 	if (tmp) {
 		memcpy(card->atmdev->esi, tmp->dev_addr, 6);
 
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index a3b605a..ef524526 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -1601,14 +1601,14 @@
   
 	skb_queue_head_init(&iadev->rx_dma_q);  
 	iadev->rx_free_desc_qhead = NULL;   
-	iadev->rx_open = kmalloc(4*iadev->num_vc,GFP_KERNEL);
-	if (!iadev->rx_open)  
-	{  
+
+	iadev->rx_open = kzalloc(4 * iadev->num_vc, GFP_KERNEL);
+	if (!iadev->rx_open) {
 		printk(KERN_ERR DEV_LABEL "itf %d couldn't get free page\n",
 		dev->number);  
 		goto err_free_dle;
 	}  
-	memset(iadev->rx_open, 0, 4*iadev->num_vc);  
+
         iadev->rxing = 1;
         iadev->rx_pkt_cnt = 0;
 	/* Mode Register */  
@@ -3171,12 +3171,12 @@
         unsigned long flags;
 	int ret;
 
-	iadev = kmalloc(sizeof(*iadev), GFP_KERNEL); 
+	iadev = kzalloc(sizeof(*iadev), GFP_KERNEL);
 	if (!iadev) {
 		ret = -ENOMEM;
 		goto err_out;
 	}
-	memset(iadev, 0, sizeof(*iadev));
+
 	iadev->pci = pdev;
 
 	IF_INIT(printk("ia detected at bus:%d dev: %d function:%d\n",
diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c
index 0e2c1ae..144a49f 100644
--- a/drivers/atm/lanai.c
+++ b/drivers/atm/lanai.c
@@ -65,7 +65,6 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
 
 /* -------------------- TUNABLE PARAMATERS: */
 
@@ -552,8 +551,8 @@
 	writel(val, sram_addr(lanai, offset));
 }
 
-static int __init sram_test_word(
-	const struct lanai_dev *lanai, int offset, u32 pattern)
+static int __devinit sram_test_word(const struct lanai_dev *lanai,
+				    int offset, u32 pattern)
 {
 	u32 readback;
 	sram_write(lanai, pattern, offset);
diff --git a/drivers/atm/nicstarmac.c b/drivers/atm/nicstarmac.c
index 480947f..842e26c 100644
--- a/drivers/atm/nicstarmac.c
+++ b/drivers/atm/nicstarmac.c
@@ -134,7 +134,7 @@
    /* Send read instruction */
    val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0;
 
-   for (i=0; i<sizeof rdsrtab/sizeof rdsrtab[0]; i++)
+   for (i=0; i<ARRAY_SIZE(rdsrtab); i++)
    {
 	NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
 		(val | rdsrtab[i]) );
diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig
index de2fcce..043353b 100644
--- a/drivers/auxdisplay/Kconfig
+++ b/drivers/auxdisplay/Kconfig
@@ -8,6 +8,11 @@
 menuconfig AUXDISPLAY
 	depends on PARPORT
 	bool "Auxiliary Display support"
+	---help---
+	  Say Y here to get to see options for auxiliary display drivers.
+	  This option alone does not add any kernel code.
+
+	  If you say N, all options in this submenu will be skipped and disabled.
 
 if AUXDISPLAY && PARPORT
 
diff --git a/drivers/auxdisplay/cfag12864b.c b/drivers/auxdisplay/cfag12864b.c
index cb44cb4..80bb061 100644
--- a/drivers/auxdisplay/cfag12864b.c
+++ b/drivers/auxdisplay/cfag12864b.c
@@ -355,7 +355,7 @@
 
 	cfag12864b_cache = kmalloc(sizeof(unsigned char) *
 		CFAG12864B_SIZE, GFP_KERNEL);
-	if (cfag12864b_buffer == NULL) {
+	if (cfag12864b_cache == NULL) {
 		printk(KERN_ERR CFAG12864B_NAME ": ERROR: "
 			"can't alloc cache buffer (%i bytes)\n",
 			CFAG12864B_SIZE);
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 5d6312e3..d7da109 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -1,5 +1,13 @@
 menu "Generic Driver Options"
 
+config UEVENT_HELPER_PATH
+	string "path to uevent helper"
+	depends on HOTPLUG
+	default "/sbin/hotplug"
+	help
+	  Path to uevent helper program forked by the kernel for
+	  every uevent.
+
 config STANDALONE
 	bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
 	default y
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 47eb02d..10b2fb6 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -18,8 +18,6 @@
 extern int bus_add_device(struct device * dev);
 extern void bus_attach_device(struct device * dev);
 extern void bus_remove_device(struct device * dev);
-extern struct bus_type *get_bus(struct bus_type * bus);
-extern void put_bus(struct bus_type * bus);
 
 extern int bus_add_driver(struct device_driver *);
 extern void bus_remove_driver(struct device_driver *);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 61c6752..9a19b07 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -30,6 +30,17 @@
 static int __must_check bus_rescan_devices_helper(struct device *dev,
 						void *data);
 
+static struct bus_type *bus_get(struct bus_type *bus)
+{
+	return bus ? container_of(kset_get(&bus->subsys),
+				struct bus_type, subsys) : NULL;
+}
+
+static void bus_put(struct bus_type *bus)
+{
+	kset_put(&bus->subsys);
+}
+
 static ssize_t
 drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
 {
@@ -78,7 +89,7 @@
 	 */
 }
 
-static struct kobj_type ktype_driver = {
+static struct kobj_type driver_ktype = {
 	.sysfs_ops	= &driver_sysfs_ops,
 	.release	= driver_release,
 };
@@ -122,9 +133,9 @@
 int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
 {
 	int error;
-	if (get_bus(bus)) {
+	if (bus_get(bus)) {
 		error = sysfs_create_file(&bus->subsys.kobj, &attr->attr);
-		put_bus(bus);
+		bus_put(bus);
 	} else
 		error = -EINVAL;
 	return error;
@@ -132,9 +143,9 @@
 
 void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
 {
-	if (get_bus(bus)) {
+	if (bus_get(bus)) {
 		sysfs_remove_file(&bus->subsys.kobj, &attr->attr);
-		put_bus(bus);
+		bus_put(bus);
 	}
 }
 
@@ -172,7 +183,7 @@
 static ssize_t driver_unbind(struct device_driver *drv,
 			     const char *buf, size_t count)
 {
-	struct bus_type *bus = get_bus(drv->bus);
+	struct bus_type *bus = bus_get(drv->bus);
 	struct device *dev;
 	int err = -ENODEV;
 
@@ -186,7 +197,7 @@
 		err = count;
 	}
 	put_device(dev);
-	put_bus(bus);
+	bus_put(bus);
 	return err;
 }
 static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
@@ -199,7 +210,7 @@
 static ssize_t driver_bind(struct device_driver *drv,
 			   const char *buf, size_t count)
 {
-	struct bus_type *bus = get_bus(drv->bus);
+	struct bus_type *bus = bus_get(drv->bus);
 	struct device *dev;
 	int err = -ENODEV;
 
@@ -219,7 +230,7 @@
 			err = -ENODEV;
 	}
 	put_device(dev);
-	put_bus(bus);
+	bus_put(bus);
 	return err;
 }
 static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
@@ -430,7 +441,7 @@
  */
 int bus_add_device(struct device * dev)
 {
-	struct bus_type * bus = get_bus(dev->bus);
+	struct bus_type * bus = bus_get(dev->bus);
 	int error = 0;
 
 	if (bus) {
@@ -459,7 +470,7 @@
 out_id:
 	device_remove_attrs(bus, dev);
 out_put:
-	put_bus(dev->bus);
+	bus_put(dev->bus);
 	return error;
 }
 
@@ -509,7 +520,7 @@
 		}
 		pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id);
 		device_release_driver(dev);
-		put_bus(dev->bus);
+		bus_put(dev->bus);
 	}
 }
 
@@ -568,32 +579,29 @@
 	driver_remove_file(drv, &driver_attr_unbind);
 }
 
+static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe);
+static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,
+		show_drivers_autoprobe, store_drivers_autoprobe);
+
 static int add_probe_files(struct bus_type *bus)
 {
 	int retval;
 
-	bus->drivers_probe_attr.attr.name = "drivers_probe";
-	bus->drivers_probe_attr.attr.mode = S_IWUSR;
-	bus->drivers_probe_attr.store = store_drivers_probe;
-	retval = bus_create_file(bus, &bus->drivers_probe_attr);
+	retval = bus_create_file(bus, &bus_attr_drivers_probe);
 	if (retval)
 		goto out;
 
-	bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe";
-	bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO;
-	bus->drivers_autoprobe_attr.show = show_drivers_autoprobe;
-	bus->drivers_autoprobe_attr.store = store_drivers_autoprobe;
-	retval = bus_create_file(bus, &bus->drivers_autoprobe_attr);
+	retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
 	if (retval)
-		bus_remove_file(bus, &bus->drivers_probe_attr);
+		bus_remove_file(bus, &bus_attr_drivers_probe);
 out:
 	return retval;
 }
 
 static void remove_probe_files(struct bus_type *bus)
 {
-	bus_remove_file(bus, &bus->drivers_autoprobe_attr);
-	bus_remove_file(bus, &bus->drivers_probe_attr);
+	bus_remove_file(bus, &bus_attr_drivers_autoprobe);
+	bus_remove_file(bus, &bus_attr_drivers_probe);
 }
 #else
 static inline int add_bind_files(struct device_driver *drv) { return 0; }
@@ -602,6 +610,17 @@
 static inline void remove_probe_files(struct bus_type *bus) {}
 #endif
 
+static ssize_t driver_uevent_store(struct device_driver *drv,
+				   const char *buf, size_t count)
+{
+	enum kobject_action action;
+
+	if (kobject_action_type(buf, count, &action) == 0)
+		kobject_uevent(&drv->kobj, action);
+	return count;
+}
+static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
+
 /**
  *	bus_add_driver - Add a driver to the bus.
  *	@drv:	driver.
@@ -609,7 +628,7 @@
  */
 int bus_add_driver(struct device_driver *drv)
 {
-	struct bus_type * bus = get_bus(drv->bus);
+	struct bus_type * bus = bus_get(drv->bus);
 	int error = 0;
 
 	if (!bus)
@@ -632,6 +651,11 @@
 	klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
 	module_add_driver(drv->owner, drv);
 
+	error = driver_create_file(drv, &driver_attr_uevent);
+	if (error) {
+		printk(KERN_ERR "%s: uevent attr (%s) failed\n",
+			__FUNCTION__, drv->name);
+	}
 	error = driver_add_attrs(bus, drv);
 	if (error) {
 		/* How the hell do we get out of this pickle? Give up */
@@ -649,7 +673,7 @@
 out_unregister:
 	kobject_unregister(&drv->kobj);
 out_put_bus:
-	put_bus(bus);
+	bus_put(bus);
 	return error;
 }
 
@@ -669,12 +693,13 @@
 
 	remove_bind_files(drv);
 	driver_remove_attrs(drv->bus, drv);
+	driver_remove_file(drv, &driver_attr_uevent);
 	klist_remove(&drv->knode_bus);
 	pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
 	driver_detach(drv);
 	module_remove_driver(drv);
 	kobject_unregister(&drv->kobj);
-	put_bus(drv->bus);
+	bus_put(drv->bus);
 }
 
 
@@ -729,18 +754,6 @@
 }
 EXPORT_SYMBOL_GPL(device_reprobe);
 
-struct bus_type *get_bus(struct bus_type *bus)
-{
-	return bus ? container_of(subsys_get(&bus->subsys),
-				struct bus_type, subsys) : NULL;
-}
-
-void put_bus(struct bus_type * bus)
-{
-	subsys_put(&bus->subsys);
-}
-
-
 /**
  *	find_bus - locate bus by name.
  *	@name:	name of bus.
@@ -808,6 +821,17 @@
 	put_device(dev);
 }
 
+static ssize_t bus_uevent_store(struct bus_type *bus,
+				const char *buf, size_t count)
+{
+	enum kobject_action action;
+
+	if (kobject_action_type(buf, count, &action) == 0)
+		kobject_uevent(&bus->subsys.kobj, action);
+	return count;
+}
+static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);
+
 /**
  *	bus_register - register a bus with the system.
  *	@bus:	bus.
@@ -826,11 +850,16 @@
 	if (retval)
 		goto out;
 
-	subsys_set_kset(bus, bus_subsys);
+	bus->subsys.kobj.kset = &bus_subsys;
+
 	retval = subsystem_register(&bus->subsys);
 	if (retval)
 		goto out;
 
+	retval = bus_create_file(bus, &bus_attr_uevent);
+	if (retval)
+		goto bus_uevent_fail;
+
 	kobject_set_name(&bus->devices.kobj, "devices");
 	bus->devices.kobj.parent = &bus->subsys.kobj;
 	retval = kset_register(&bus->devices);
@@ -839,7 +868,7 @@
 
 	kobject_set_name(&bus->drivers.kobj, "drivers");
 	bus->drivers.kobj.parent = &bus->subsys.kobj;
-	bus->drivers.ktype = &ktype_driver;
+	bus->drivers.ktype = &driver_ktype;
 	retval = kset_register(&bus->drivers);
 	if (retval)
 		goto bus_drivers_fail;
@@ -866,6 +895,8 @@
 bus_drivers_fail:
 	kset_unregister(&bus->devices);
 bus_devices_fail:
+	bus_remove_file(bus, &bus_attr_uevent);
+bus_uevent_fail:
 	subsystem_unregister(&bus->subsys);
 out:
 	return retval;
@@ -876,7 +907,7 @@
  *	@bus:	bus.
  *
  *	Unregister the child subsystems and the bus itself.
- *	Finally, we call put_bus() to release the refcount
+ *	Finally, we call bus_put() to release the refcount
  */
 void bus_unregister(struct bus_type * bus)
 {
@@ -885,6 +916,7 @@
 	remove_probe_files(bus);
 	kset_unregister(&bus->drivers);
 	kset_unregister(&bus->devices);
+	bus_remove_file(bus, &bus_attr_uevent);
 	subsystem_unregister(&bus->subsys);
 }
 
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 4d22226..a863bb0 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -65,13 +65,13 @@
 	.store	= class_attr_store,
 };
 
-static struct kobj_type ktype_class = {
+static struct kobj_type class_ktype = {
 	.sysfs_ops	= &class_sysfs_ops,
 	.release	= class_release,
 };
 
 /* Hotplug events for classes go to the class_obj subsys */
-static decl_subsys(class, &ktype_class, NULL);
+static decl_subsys(class, &class_ktype, NULL);
 
 
 int class_create_file(struct class * cls, const struct class_attribute * attr)
@@ -93,14 +93,14 @@
 static struct class *class_get(struct class *cls)
 {
 	if (cls)
-		return container_of(subsys_get(&cls->subsys), struct class, subsys);
+		return container_of(kset_get(&cls->subsys), struct class, subsys);
 	return NULL;
 }
 
 static void class_put(struct class * cls)
 {
 	if (cls)
-		subsys_put(&cls->subsys);
+		kset_put(&cls->subsys);
 }
 
 
@@ -149,7 +149,7 @@
 	if (error)
 		return error;
 
-	subsys_set_kset(cls, class_subsys);
+	cls->subsys.kobj.kset = &class_subsys;
 
 	error = subsystem_register(&cls->subsys);
 	if (!error) {
@@ -180,8 +180,7 @@
 
 /* needed to allow these devices to have parent class devices */
 static int class_device_create_uevent(struct class_device *class_dev,
-				       char **envp, int num_envp,
-				       char *buffer, int buffer_size)
+				      struct kobj_uevent_env *env)
 {
 	pr_debug("%s called for %s\n", __FUNCTION__, class_dev->class_id);
 	return 0;
@@ -324,7 +323,7 @@
 	}
 }
 
-static struct kobj_type ktype_class_device = {
+static struct kobj_type class_device_ktype = {
 	.sysfs_ops	= &class_dev_sysfs_ops,
 	.release	= class_dev_release,
 };
@@ -333,7 +332,7 @@
 {
 	struct kobj_type *ktype = get_ktype(kobj);
 
-	if (ktype == &ktype_class_device) {
+	if (ktype == &class_device_ktype) {
 		struct class_device *class_dev = to_class_dev(kobj);
 		if (class_dev->class)
 			return 1;
@@ -403,64 +402,43 @@
 { }
 #endif
 
-static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp,
-			 int num_envp, char *buffer, int buffer_size)
+static int class_uevent(struct kset *kset, struct kobject *kobj,
+			struct kobj_uevent_env *env)
 {
 	struct class_device *class_dev = to_class_dev(kobj);
 	struct device *dev = class_dev->dev;
-	int i = 0;
-	int length = 0;
 	int retval = 0;
 
 	pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
 
 	if (MAJOR(class_dev->devt)) {
-		add_uevent_var(envp, num_envp, &i,
-			       buffer, buffer_size, &length,
-			       "MAJOR=%u", MAJOR(class_dev->devt));
+		add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt));
 
-		add_uevent_var(envp, num_envp, &i,
-			       buffer, buffer_size, &length,
-			       "MINOR=%u", MINOR(class_dev->devt));
+		add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt));
 	}
 
 	if (dev) {
 		const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
 		if (path) {
-			add_uevent_var(envp, num_envp, &i,
-				       buffer, buffer_size, &length,
-				       "PHYSDEVPATH=%s", path);
+			add_uevent_var(env, "PHYSDEVPATH=%s", path);
 			kfree(path);
 		}
 
 		if (dev->bus)
-			add_uevent_var(envp, num_envp, &i,
-				       buffer, buffer_size, &length,
-				       "PHYSDEVBUS=%s", dev->bus->name);
+			add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
 
 		if (dev->driver)
-			add_uevent_var(envp, num_envp, &i,
-				       buffer, buffer_size, &length,
-				       "PHYSDEVDRIVER=%s", dev->driver->name);
+			add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name);
 	}
 
-	/* terminate, set to next free slot, shrink available space */
-	envp[i] = NULL;
-	envp = &envp[i];
-	num_envp -= i;
-	buffer = &buffer[length];
-	buffer_size -= length;
-
 	if (class_dev->uevent) {
 		/* have the class device specific function add its stuff */
-		retval = class_dev->uevent(class_dev, envp, num_envp,
-					    buffer, buffer_size);
+		retval = class_dev->uevent(class_dev, env);
 		if (retval)
 			pr_debug("class_dev->uevent() returned %d\n", retval);
 	} else if (class_dev->class->uevent) {
 		/* have the class specific function add its stuff */
-		retval = class_dev->class->uevent(class_dev, envp, num_envp,
-						   buffer, buffer_size);
+		retval = class_dev->class->uevent(class_dev, env);
 		if (retval)
 			pr_debug("class->uevent() returned %d\n", retval);
 	}
@@ -474,7 +452,7 @@
 	.uevent =	class_uevent,
 };
 
-static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops);
+static decl_subsys(class_obj, &class_device_ktype, &class_uevent_ops);
 
 
 static int class_device_add_attrs(struct class_device * cd)
@@ -883,7 +861,7 @@
 
 	/* ick, this is ugly, the things we go through to keep from showing up
 	 * in sysfs... */
-	subsystem_init(&class_obj_subsys);
+	kset_init(&class_obj_subsys);
 	if (!class_obj_subsys.kobj.parent)
 		class_obj_subsys.kobj.parent = &class_obj_subsys.kobj;
 	return 0;
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 0455aa7..c134341 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -108,7 +108,7 @@
 	}
 }
 
-static struct kobj_type ktype_device = {
+static struct kobj_type device_ktype = {
 	.release	= device_release,
 	.sysfs_ops	= &dev_sysfs_ops,
 };
@@ -118,7 +118,7 @@
 {
 	struct kobj_type *ktype = get_ktype(kobj);
 
-	if (ktype == &ktype_device) {
+	if (ktype == &device_ktype) {
 		struct device *dev = to_dev(kobj);
 		if (dev->uevent_suppress)
 			return 0;
@@ -141,33 +141,23 @@
 	return NULL;
 }
 
-static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
-			int num_envp, char *buffer, int buffer_size)
+static int dev_uevent(struct kset *kset, struct kobject *kobj,
+		      struct kobj_uevent_env *env)
 {
 	struct device *dev = to_dev(kobj);
-	int i = 0;
-	int length = 0;
 	int retval = 0;
 
 	/* add the major/minor if present */
 	if (MAJOR(dev->devt)) {
-		add_uevent_var(envp, num_envp, &i,
-			       buffer, buffer_size, &length,
-			       "MAJOR=%u", MAJOR(dev->devt));
-		add_uevent_var(envp, num_envp, &i,
-			       buffer, buffer_size, &length,
-			       "MINOR=%u", MINOR(dev->devt));
+		add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt));
+		add_uevent_var(env, "MINOR=%u", MINOR(dev->devt));
 	}
 
 	if (dev->type && dev->type->name)
-		add_uevent_var(envp, num_envp, &i,
-			       buffer, buffer_size, &length,
-			       "DEVTYPE=%s", dev->type->name);
+		add_uevent_var(env, "DEVTYPE=%s", dev->type->name);
 
 	if (dev->driver)
-		add_uevent_var(envp, num_envp, &i,
-			       buffer, buffer_size, &length,
-			       "DRIVER=%s", dev->driver->name);
+		add_uevent_var(env, "DRIVER=%s", dev->driver->name);
 
 #ifdef CONFIG_SYSFS_DEPRECATED
 	if (dev->class) {
@@ -181,59 +171,43 @@
 
 			path = kobject_get_path(&parent->kobj, GFP_KERNEL);
 			if (path) {
-				add_uevent_var(envp, num_envp, &i,
-					       buffer, buffer_size, &length,
-					       "PHYSDEVPATH=%s", path);
+				add_uevent_var(env, "PHYSDEVPATH=%s", path);
 				kfree(path);
 			}
 
-			add_uevent_var(envp, num_envp, &i,
-				       buffer, buffer_size, &length,
-				       "PHYSDEVBUS=%s", parent->bus->name);
+			add_uevent_var(env, "PHYSDEVBUS=%s", parent->bus->name);
 
 			if (parent->driver)
-				add_uevent_var(envp, num_envp, &i,
-					       buffer, buffer_size, &length,
-					       "PHYSDEVDRIVER=%s", parent->driver->name);
+				add_uevent_var(env, "PHYSDEVDRIVER=%s",
+					       parent->driver->name);
 		}
 	} else if (dev->bus) {
-		add_uevent_var(envp, num_envp, &i,
-			       buffer, buffer_size, &length,
-			       "PHYSDEVBUS=%s", dev->bus->name);
+		add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
 
 		if (dev->driver)
-			add_uevent_var(envp, num_envp, &i,
-				       buffer, buffer_size, &length,
-				       "PHYSDEVDRIVER=%s", dev->driver->name);
+			add_uevent_var(env, "PHYSDEVDRIVER=%s", dev->driver->name);
 	}
 #endif
 
-	/* terminate, set to next free slot, shrink available space */
-	envp[i] = NULL;
-	envp = &envp[i];
-	num_envp -= i;
-	buffer = &buffer[length];
-	buffer_size -= length;
-
+	/* have the bus specific function add its stuff */
 	if (dev->bus && dev->bus->uevent) {
-		/* have the bus specific function add its stuff */
-		retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size);
+		retval = dev->bus->uevent(dev, env);
 		if (retval)
 			pr_debug ("%s: bus uevent() returned %d\n",
 				  __FUNCTION__, retval);
 	}
 
+	/* have the class specific function add its stuff */
 	if (dev->class && dev->class->dev_uevent) {
-		/* have the class specific function add its stuff */
-		retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size);
+		retval = dev->class->dev_uevent(dev, env);
 		if (retval)
 			pr_debug("%s: class uevent() returned %d\n",
 				 __FUNCTION__, retval);
 	}
 
+	/* have the device type specific fuction add its stuff */
 	if (dev->type && dev->type->uevent) {
-		/* have the device type specific fuction add its stuff */
-		retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size);
+		retval = dev->type->uevent(dev, env);
 		if (retval)
 			pr_debug("%s: dev_type uevent() returned %d\n",
 				 __FUNCTION__, retval);
@@ -253,22 +227,18 @@
 {
 	struct kobject *top_kobj;
 	struct kset *kset;
-	char *envp[32];
-	char *data = NULL;
-	char *pos;
+	struct kobj_uevent_env *env = NULL;
 	int i;
 	size_t count = 0;
 	int retval;
 
 	/* search the kset, the device belongs to */
 	top_kobj = &dev->kobj;
-	if (!top_kobj->kset && top_kobj->parent) {
-		do {
-			top_kobj = top_kobj->parent;
-		} while (!top_kobj->kset && top_kobj->parent);
-	}
+	while (!top_kobj->kset && top_kobj->parent)
+		top_kobj = top_kobj->parent;
 	if (!top_kobj->kset)
 		goto out;
+
 	kset = top_kobj->kset;
 	if (!kset->uevent_ops || !kset->uevent_ops->uevent)
 		goto out;
@@ -278,35 +248,37 @@
 		if (!kset->uevent_ops->filter(kset, &dev->kobj))
 			goto out;
 
-	data = (char *)get_zeroed_page(GFP_KERNEL);
-	if (!data)
+	env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL);
+	if (!env)
 		return -ENOMEM;
 
 	/* let the kset specific function add its keys */
-	pos = data;
-	retval = kset->uevent_ops->uevent(kset, &dev->kobj,
-					  envp, ARRAY_SIZE(envp),
-					  pos, PAGE_SIZE);
+	retval = kset->uevent_ops->uevent(kset, &dev->kobj, env);
 	if (retval)
 		goto out;
 
 	/* copy keys to file */
-	for (i = 0; envp[i]; i++) {
-		pos = &buf[count];
-		count += sprintf(pos, "%s\n", envp[i]);
-	}
+	for (i = 0; i < env->envp_idx; i++)
+		count += sprintf(&buf[count], "%s\n", env->envp[i]);
 out:
-	free_page((unsigned long)data);
+	kfree(env);
 	return count;
 }
 
 static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
 			    const char *buf, size_t count)
 {
-	if (memcmp(buf, "add", 3) != 0)
-		dev_err(dev, "uevent: unsupported action-string; this will "
-			"be ignored in a future kernel version");
+	enum kobject_action action;
+
+	if (kobject_action_type(buf, count, &action) == 0) {
+		kobject_uevent(&dev->kobj, action);
+		goto out;
+	}
+
+	dev_err(dev, "uevent: unsupported action-string; this will "
+		     "be ignored in a future kernel version\n");
 	kobject_uevent(&dev->kobj, KOBJ_ADD);
+out:
 	return count;
 }
 
@@ -433,7 +405,7 @@
  *	devices_subsys - structure to be registered with kobject core.
  */
 
-decl_subsys(devices, &ktype_device, &device_uevent_ops);
+decl_subsys(devices, &device_ktype, &device_uevent_ops);
 
 
 /**
@@ -570,9 +542,13 @@
 static struct kobject * get_device_parent(struct device *dev,
 					  struct device *parent)
 {
-	/* Set the parent to the class, not the parent device */
-	/* this keeps sysfs from having a symlink to make old udevs happy */
-	if (dev->class)
+	/*
+	 * Set the parent to the class, not the parent device
+	 * for topmost devices in class hierarchy.
+	 * This keeps sysfs from having a symlink to make old
+	 * udevs happy
+	 */
+	if (dev->class && (!parent || parent->class != dev->class))
 		return &dev->class->subsys.kobj;
 	else if (parent)
 		return &parent->kobj;
@@ -643,6 +619,98 @@
 	return 0;
 }
 
+static int device_add_class_symlinks(struct device *dev)
+{
+	int error;
+
+	if (!dev->class)
+		return 0;
+	error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
+				  "subsystem");
+	if (error)
+		goto out;
+	/*
+	 * If this is not a "fake" compatible device, then create the
+	 * symlink from the class to the device.
+	 */
+	if (dev->kobj.parent != &dev->class->subsys.kobj) {
+		error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
+					  dev->bus_id);
+		if (error)
+			goto out_subsys;
+	}
+	if (dev->parent) {
+#ifdef CONFIG_SYSFS_DEPRECATED
+		{
+			struct device *parent = dev->parent;
+			char *class_name;
+
+			/*
+			 * In old sysfs stacked class devices had 'device'
+			 * link pointing to real device instead of parent
+			 */
+			while (parent->class && !parent->bus && parent->parent)
+				parent = parent->parent;
+
+			error = sysfs_create_link(&dev->kobj,
+						  &parent->kobj,
+						  "device");
+			if (error)
+				goto out_busid;
+
+			class_name = make_class_name(dev->class->name,
+							&dev->kobj);
+			if (class_name)
+				error = sysfs_create_link(&dev->parent->kobj,
+							&dev->kobj, class_name);
+			kfree(class_name);
+			if (error)
+				goto out_device;
+		}
+#else
+		error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+					  "device");
+		if (error)
+			goto out_busid;
+#endif
+	}
+	return 0;
+
+#ifdef CONFIG_SYSFS_DEPRECATED
+out_device:
+	if (dev->parent)
+		sysfs_remove_link(&dev->kobj, "device");
+#endif
+out_busid:
+	if (dev->kobj.parent != &dev->class->subsys.kobj)
+		sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+out_subsys:
+	sysfs_remove_link(&dev->kobj, "subsystem");
+out:
+	return error;
+}
+
+static void device_remove_class_symlinks(struct device *dev)
+{
+	if (!dev->class)
+		return;
+	if (dev->parent) {
+#ifdef CONFIG_SYSFS_DEPRECATED
+		char *class_name;
+
+		class_name = make_class_name(dev->class->name, &dev->kobj);
+		if (class_name) {
+			sysfs_remove_link(&dev->parent->kobj, class_name);
+			kfree(class_name);
+		}
+#endif
+		sysfs_remove_link(&dev->kobj, "device");
+	}
+	if (dev->kobj.parent != &dev->class->subsys.kobj)
+		sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
+	sysfs_remove_link(&dev->kobj, "subsystem");
+}
+
 /**
  *	device_add - add device to device hierarchy.
  *	@dev:	device.
@@ -657,7 +725,6 @@
 int device_add(struct device *dev)
 {
 	struct device *parent = NULL;
-	char *class_name = NULL;
 	struct class_interface *class_intf;
 	int error = -EINVAL;
 
@@ -697,27 +764,9 @@
 			goto ueventattrError;
 	}
 
-	if (dev->class) {
-		sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
-				  "subsystem");
-		/* If this is not a "fake" compatible device, then create the
-		 * symlink from the class to the device. */
-		if (dev->kobj.parent != &dev->class->subsys.kobj)
-			sysfs_create_link(&dev->class->subsys.kobj,
-					  &dev->kobj, dev->bus_id);
-		if (parent) {
-			sysfs_create_link(&dev->kobj, &dev->parent->kobj,
-							"device");
-#ifdef CONFIG_SYSFS_DEPRECATED
-			class_name = make_class_name(dev->class->name,
-							&dev->kobj);
-			if (class_name)
-				sysfs_create_link(&dev->parent->kobj,
-						  &dev->kobj, class_name);
-#endif
-		}
-	}
-
+	error = device_add_class_symlinks(dev);
+	if (error)
+		goto SymlinkError;
 	error = device_add_attrs(dev);
 	if (error)
 		goto AttrsError;
@@ -744,7 +793,6 @@
 		up(&dev->class->sem);
 	}
  Done:
-	kfree(class_name);
 	put_device(dev);
 	return error;
  BusError:
@@ -755,6 +803,8 @@
 					     BUS_NOTIFY_DEL_DEVICE, dev);
 	device_remove_attrs(dev);
  AttrsError:
+	device_remove_class_symlinks(dev);
+ SymlinkError:
 	if (MAJOR(dev->devt))
 		device_remove_file(dev, &devt_attr);
 
@@ -1139,7 +1189,7 @@
 {
 	char *old_class_name = NULL;
 	char *new_class_name = NULL;
-	char *old_symlink_name = NULL;
+	char *old_device_name = NULL;
 	int error;
 
 	dev = get_device(dev);
@@ -1153,42 +1203,49 @@
 		old_class_name = make_class_name(dev->class->name, &dev->kobj);
 #endif
 
-	if (dev->class) {
-		old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
-		if (!old_symlink_name) {
-			error = -ENOMEM;
-			goto out_free_old_class;
-		}
-		strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE);
+	old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
+	if (!old_device_name) {
+		error = -ENOMEM;
+		goto out;
 	}
-
+	strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE);
 	strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
 
 	error = kobject_rename(&dev->kobj, new_name);
+	if (error) {
+		strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE);
+		goto out;
+	}
 
 #ifdef CONFIG_SYSFS_DEPRECATED
 	if (old_class_name) {
 		new_class_name = make_class_name(dev->class->name, &dev->kobj);
 		if (new_class_name) {
-			sysfs_create_link(&dev->parent->kobj, &dev->kobj,
-					  new_class_name);
+			error = sysfs_create_link(&dev->parent->kobj,
+						  &dev->kobj, new_class_name);
+			if (error)
+				goto out;
 			sysfs_remove_link(&dev->parent->kobj, old_class_name);
 		}
 	}
 #endif
 
 	if (dev->class) {
-		sysfs_remove_link(&dev->class->subsys.kobj,
-				  old_symlink_name);
-		sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
-				  dev->bus_id);
+		sysfs_remove_link(&dev->class->subsys.kobj, old_device_name);
+		error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
+					  dev->bus_id);
+		if (error) {
+			/* Uh... how to unravel this if restoring can fail? */
+			dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n",
+				__FUNCTION__, error);
+		}
 	}
+out:
 	put_device(dev);
 
 	kfree(new_class_name);
-	kfree(old_symlink_name);
- out_free_old_class:
 	kfree(old_class_name);
+	kfree(old_device_name);
 
 	return error;
 }
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index fe7ef33..4054507 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -53,7 +53,7 @@
 		ret = count;
 	return ret;
 }
-static SYSDEV_ATTR(online, 0600, show_online, store_online);
+static SYSDEV_ATTR(online, 0644, show_online, store_online);
 
 static void __devinit register_cpu_control(struct cpu *cpu)
 {
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 53f0ee6..0295855 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -88,19 +88,14 @@
 
 static void fw_dev_release(struct device *dev);
 
-static int firmware_uevent(struct device *dev, char **envp, int num_envp,
-			   char *buffer, int buffer_size)
+static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct firmware_priv *fw_priv = dev_get_drvdata(dev);
-	int i = 0, len = 0;
 
-	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-			   "FIRMWARE=%s", fw_priv->fw_id))
+	if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->fw_id))
 		return -ENOMEM;
-	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-			   "TIMEOUT=%i", loading_timeout))
+	if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout))
 		return -ENOMEM;
-	envp[i] = NULL;
 
 	return 0;
 }
@@ -232,6 +227,7 @@
 /**
  * firmware_data_write - write method for firmware
  * @kobj: kobject for the device
+ * @bin_attr: bin_attr structure
  * @buffer: buffer being written
  * @offset: buffer offset for write in total data store area
  * @count: buffer size
@@ -296,8 +292,7 @@
 
 static inline void fw_setup_device_id(struct device *f_dev, struct device *dev)
 {
-	/* XXX warning we should watch out for name collisions */
-	strlcpy(f_dev->bus_id, dev->bus_id, BUS_ID_SIZE);
+	snprintf(f_dev->bus_id, BUS_ID_SIZE, "firmware-%s", dev->bus_id);
 }
 
 static int fw_register_device(struct device **dev_p, const char *fw_name,
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 74b9679..cb99dae 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -34,8 +34,7 @@
 	return MEMORY_CLASS_NAME;
 }
 
-static int memory_uevent(struct kset *kset, struct kobject *kobj, char **envp,
-			int num_envp, char *buffer, int buffer_size)
+static int memory_uevent(struct kset *kset, struct kobj_uevent_env *env)
 {
 	int retval = 0;
 
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 869ff8c..fb56092 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -160,13 +160,8 @@
  *
  *	Create a platform device object which can have other objects attached
  *	to it, and which will have attached objects freed when it is released.
- *
- *	This device will be marked as not supporting hotpluggable drivers; no
- *	device add/remove uevents will be generated.  In the unusual case that
- *	the device isn't being dynamically allocated as a legacy "probe the
- *	hardware" driver, infrastructure code should reverse this marking.
  */
-struct platform_device *platform_device_alloc(const char *name, unsigned int id)
+struct platform_device *platform_device_alloc(const char *name, int id)
 {
 	struct platform_object *pa;
 
@@ -177,12 +172,6 @@
 		pa->pdev.id = id;
 		device_initialize(&pa->pdev.dev);
 		pa->pdev.dev.release = platform_device_release;
-
-		/* prevent hotplug "modprobe $(MODALIAS)" from causing trouble in
-		 * legacy probe-the-hardware drivers, which don't properly split
-		 * out device enumeration logic from drivers.
-		 */
-		pa->pdev.dev.uevent_suppress = 1;
 	}
 
 	return pa ? &pa->pdev : NULL;
@@ -256,7 +245,8 @@
 	pdev->dev.bus = &platform_bus_type;
 
 	if (pdev->id != -1)
-		snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id);
+		snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,
+			 pdev->id);
 	else
 		strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
 
@@ -370,7 +360,7 @@
  *	the Linux driver model.  In particular, when such drivers are built
  *	as modules, they can't be "hotplugged".
  */
-struct platform_device *platform_device_register_simple(char *name, unsigned int id,
+struct platform_device *platform_device_register_simple(char *name, int id,
 							struct resource *res, unsigned int num)
 {
 	struct platform_device *pdev;
@@ -530,7 +520,7 @@
 modalias_show(struct device *dev, struct device_attribute *a, char *buf)
 {
 	struct platform_device	*pdev = to_platform_device(dev);
-	int len = snprintf(buf, PAGE_SIZE, "%s\n", pdev->name);
+	int len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name);
 
 	return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len;
 }
@@ -540,13 +530,11 @@
 	__ATTR_NULL,
 };
 
-static int platform_uevent(struct device *dev, char **envp, int num_envp,
-		char *buffer, int buffer_size)
+static int platform_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct platform_device	*pdev = to_platform_device(dev);
 
-	envp[0] = buffer;
-	snprintf(buffer, buffer_size, "MODALIAS=%s", pdev->name);
+	add_uevent_var(env, "MODALIAS=platform:%s", pdev->name);
 	return 0;
 }
 
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 91f2309..a803733 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,10 +1,10 @@
 obj-y			:= shutdown.o
-obj-$(CONFIG_PM)	+= main.o suspend.o resume.o runtime.o sysfs.o
+obj-$(CONFIG_PM_SLEEP)	+= main.o sysfs.o
 obj-$(CONFIG_PM_TRACE)	+= trace.o
 
 ifeq ($(CONFIG_DEBUG_DRIVER),y)
 EXTRA_CFLAGS += -DDEBUG
 endif
-ifeq ($(CONFIG_PM_DEBUG),y)
+ifeq ($(CONFIG_PM_VERBOSE),y)
 EXTRA_CFLAGS += -DDEBUG
 endif
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index eb9f38d..0ab4ab2 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -20,19 +20,24 @@
  */
 
 #include <linux/device.h>
+#include <linux/kallsyms.h>
 #include <linux/mutex.h>
+#include <linux/pm.h>
+#include <linux/resume-trace.h>
 
+#include "../base.h"
 #include "power.h"
 
 LIST_HEAD(dpm_active);
-LIST_HEAD(dpm_off);
-LIST_HEAD(dpm_off_irq);
+static LIST_HEAD(dpm_off);
+static LIST_HEAD(dpm_off_irq);
 
-DEFINE_MUTEX(dpm_mtx);
-DEFINE_MUTEX(dpm_list_mtx);
+static DEFINE_MUTEX(dpm_mtx);
+static DEFINE_MUTEX(dpm_list_mtx);
 
 int (*platform_enable_wakeup)(struct device *dev, int is_on);
 
+
 int device_pm_add(struct device *dev)
 {
 	int error;
@@ -61,3 +66,334 @@
 }
 
 
+/*------------------------- Resume routines -------------------------*/
+
+/**
+ *	resume_device - Restore state for one device.
+ *	@dev:	Device.
+ *
+ */
+
+static int resume_device(struct device * dev)
+{
+	int error = 0;
+
+	TRACE_DEVICE(dev);
+	TRACE_RESUME(0);
+
+	down(&dev->sem);
+
+	if (dev->bus && dev->bus->resume) {
+		dev_dbg(dev,"resuming\n");
+		error = dev->bus->resume(dev);
+	}
+
+	if (!error && dev->type && dev->type->resume) {
+		dev_dbg(dev,"resuming\n");
+		error = dev->type->resume(dev);
+	}
+
+	if (!error && dev->class && dev->class->resume) {
+		dev_dbg(dev,"class resume\n");
+		error = dev->class->resume(dev);
+	}
+
+	up(&dev->sem);
+
+	TRACE_RESUME(error);
+	return error;
+}
+
+
+static int resume_device_early(struct device * dev)
+{
+	int error = 0;
+
+	TRACE_DEVICE(dev);
+	TRACE_RESUME(0);
+	if (dev->bus && dev->bus->resume_early) {
+		dev_dbg(dev,"EARLY resume\n");
+		error = dev->bus->resume_early(dev);
+	}
+	TRACE_RESUME(error);
+	return error;
+}
+
+/*
+ * Resume the devices that have either not gone through
+ * the late suspend, or that did go through it but also
+ * went through the early resume
+ */
+static void dpm_resume(void)
+{
+	mutex_lock(&dpm_list_mtx);
+	while(!list_empty(&dpm_off)) {
+		struct list_head * entry = dpm_off.next;
+		struct device * dev = to_device(entry);
+
+		get_device(dev);
+		list_move_tail(entry, &dpm_active);
+
+		mutex_unlock(&dpm_list_mtx);
+		resume_device(dev);
+		mutex_lock(&dpm_list_mtx);
+		put_device(dev);
+	}
+	mutex_unlock(&dpm_list_mtx);
+}
+
+
+/**
+ *	device_resume - Restore state of each device in system.
+ *
+ *	Walk the dpm_off list, remove each entry, resume the device,
+ *	then add it to the dpm_active list.
+ */
+
+void device_resume(void)
+{
+	might_sleep();
+	mutex_lock(&dpm_mtx);
+	dpm_resume();
+	mutex_unlock(&dpm_mtx);
+}
+
+EXPORT_SYMBOL_GPL(device_resume);
+
+
+/**
+ *	dpm_power_up - Power on some devices.
+ *
+ *	Walk the dpm_off_irq list and power each device up. This
+ *	is used for devices that required they be powered down with
+ *	interrupts disabled. As devices are powered on, they are moved
+ *	to the dpm_active list.
+ *
+ *	Interrupts must be disabled when calling this.
+ */
+
+static void dpm_power_up(void)
+{
+	while(!list_empty(&dpm_off_irq)) {
+		struct list_head * entry = dpm_off_irq.next;
+		struct device * dev = to_device(entry);
+
+		list_move_tail(entry, &dpm_off);
+		resume_device_early(dev);
+	}
+}
+
+
+/**
+ *	device_power_up - Turn on all devices that need special attention.
+ *
+ *	Power on system devices then devices that required we shut them down
+ *	with interrupts disabled.
+ *	Called with interrupts disabled.
+ */
+
+void device_power_up(void)
+{
+	sysdev_resume();
+	dpm_power_up();
+}
+
+EXPORT_SYMBOL_GPL(device_power_up);
+
+
+/*------------------------- Suspend routines -------------------------*/
+
+/*
+ * The entries in the dpm_active list are in a depth first order, simply
+ * because children are guaranteed to be discovered after parents, and
+ * are inserted at the back of the list on discovery.
+ *
+ * All list on the suspend path are done in reverse order, so we operate
+ * on the leaves of the device tree (or forests, depending on how you want
+ * to look at it ;) first. As nodes are removed from the back of the list,
+ * they are inserted into the front of their destintation lists.
+ *
+ * Things are the reverse on the resume path - iterations are done in
+ * forward order, and nodes are inserted at the back of their destination
+ * lists. This way, the ancestors will be accessed before their descendents.
+ */
+
+static inline char *suspend_verb(u32 event)
+{
+	switch (event) {
+	case PM_EVENT_SUSPEND:	return "suspend";
+	case PM_EVENT_FREEZE:	return "freeze";
+	case PM_EVENT_PRETHAW:	return "prethaw";
+	default:		return "(unknown suspend event)";
+	}
+}
+
+
+static void
+suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
+{
+	dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event),
+		((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ?
+		", may wakeup" : "");
+}
+
+/**
+ *	suspend_device - Save state of one device.
+ *	@dev:	Device.
+ *	@state:	Power state device is entering.
+ */
+
+static int suspend_device(struct device * dev, pm_message_t state)
+{
+	int error = 0;
+
+	down(&dev->sem);
+	if (dev->power.power_state.event) {
+		dev_dbg(dev, "PM: suspend %d-->%d\n",
+			dev->power.power_state.event, state.event);
+	}
+
+	if (dev->class && dev->class->suspend) {
+		suspend_device_dbg(dev, state, "class ");
+		error = dev->class->suspend(dev, state);
+		suspend_report_result(dev->class->suspend, error);
+	}
+
+	if (!error && dev->type && dev->type->suspend) {
+		suspend_device_dbg(dev, state, "type ");
+		error = dev->type->suspend(dev, state);
+		suspend_report_result(dev->type->suspend, error);
+	}
+
+	if (!error && dev->bus && dev->bus->suspend) {
+		suspend_device_dbg(dev, state, "");
+		error = dev->bus->suspend(dev, state);
+		suspend_report_result(dev->bus->suspend, error);
+	}
+	up(&dev->sem);
+	return error;
+}
+
+
+/*
+ * This is called with interrupts off, only a single CPU
+ * running. We can't acquire a mutex or semaphore (and we don't
+ * need the protection)
+ */
+static int suspend_device_late(struct device *dev, pm_message_t state)
+{
+	int error = 0;
+
+	if (dev->bus && dev->bus->suspend_late) {
+		suspend_device_dbg(dev, state, "LATE ");
+		error = dev->bus->suspend_late(dev, state);
+		suspend_report_result(dev->bus->suspend_late, error);
+	}
+	return error;
+}
+
+/**
+ *	device_suspend - Save state and stop all devices in system.
+ *	@state:		Power state to put each device in.
+ *
+ *	Walk the dpm_active list, call ->suspend() for each device, and move
+ *	it to the dpm_off list.
+ *
+ *	(For historical reasons, if it returns -EAGAIN, that used to mean
+ *	that the device would be called again with interrupts disabled.
+ *	These days, we use the "suspend_late()" callback for that, so we
+ *	print a warning and consider it an error).
+ *
+ *	If we get a different error, try and back out.
+ *
+ *	If we hit a failure with any of the devices, call device_resume()
+ *	above to bring the suspended devices back to life.
+ *
+ */
+
+int device_suspend(pm_message_t state)
+{
+	int error = 0;
+
+	might_sleep();
+	mutex_lock(&dpm_mtx);
+	mutex_lock(&dpm_list_mtx);
+	while (!list_empty(&dpm_active) && error == 0) {
+		struct list_head * entry = dpm_active.prev;
+		struct device * dev = to_device(entry);
+
+		get_device(dev);
+		mutex_unlock(&dpm_list_mtx);
+
+		error = suspend_device(dev, state);
+
+		mutex_lock(&dpm_list_mtx);
+
+		/* Check if the device got removed */
+		if (!list_empty(&dev->power.entry)) {
+			/* Move it to the dpm_off list */
+			if (!error)
+				list_move(&dev->power.entry, &dpm_off);
+		}
+		if (error)
+			printk(KERN_ERR "Could not suspend device %s: "
+				"error %d%s\n",
+				kobject_name(&dev->kobj), error,
+				error == -EAGAIN ? " (please convert to suspend_late)" : "");
+		put_device(dev);
+	}
+	mutex_unlock(&dpm_list_mtx);
+	if (error)
+		dpm_resume();
+
+	mutex_unlock(&dpm_mtx);
+	return error;
+}
+
+EXPORT_SYMBOL_GPL(device_suspend);
+
+/**
+ *	device_power_down - Shut down special devices.
+ *	@state:		Power state to enter.
+ *
+ *	Walk the dpm_off_irq list, calling ->power_down() for each device that
+ *	couldn't power down the device with interrupts enabled. When we're
+ *	done, power down system devices.
+ */
+
+int device_power_down(pm_message_t state)
+{
+	int error = 0;
+	struct device * dev;
+
+	while (!list_empty(&dpm_off)) {
+		struct list_head * entry = dpm_off.prev;
+
+		dev = to_device(entry);
+		error = suspend_device_late(dev, state);
+		if (error)
+			goto Error;
+		list_move(&dev->power.entry, &dpm_off_irq);
+	}
+
+	error = sysdev_suspend(state);
+ Done:
+	return error;
+ Error:
+	printk(KERN_ERR "Could not power down device %s: "
+		"error %d\n", kobject_name(&dev->kobj), error);
+	dpm_power_up();
+	goto Done;
+}
+
+EXPORT_SYMBOL_GPL(device_power_down);
+
+void __suspend_report_result(const char *function, void *fn, int ret)
+{
+	if (ret) {
+		printk(KERN_ERR "%s(): ", function);
+		print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn);
+		printk("%d\n", ret);
+	}
+}
+EXPORT_SYMBOL_GPL(__suspend_report_result);
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 2760f25..5c4efd4 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -5,38 +5,17 @@
 extern void device_shutdown(void);
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
 /*
  * main.c
  */
 
-/*
- * Used to synchronize global power management operations.
- */
-extern struct mutex dpm_mtx;
-
-/*
- * Used to serialize changes to the dpm_* lists.
- */
-extern struct mutex dpm_list_mtx;
-
-/*
- * The PM lists.
- */
-extern struct list_head dpm_active;
-extern struct list_head dpm_off;
-extern struct list_head dpm_off_irq;
-
-
-static inline struct dev_pm_info * to_pm_info(struct list_head * entry)
-{
-	return container_of(entry, struct dev_pm_info, entry);
-}
+extern struct list_head dpm_active;	/* The active device list */
 
 static inline struct device * to_device(struct list_head * entry)
 {
-	return container_of(to_pm_info(entry), struct device, power);
+	return container_of(entry, struct device, power.entry);
 }
 
 extern int device_pm_add(struct device *);
@@ -49,25 +28,7 @@
 extern int dpm_sysfs_add(struct device *);
 extern void dpm_sysfs_remove(struct device *);
 
-/*
- * resume.c
- */
-
-extern void dpm_resume(void);
-extern void dpm_power_up(void);
-extern int resume_device(struct device *);
-
-/*
- * suspend.c
- */
-extern int suspend_device(struct device *, pm_message_t);
-
-
-/*
- * runtime.c
- */
-
-#else /* CONFIG_PM */
+#else /* CONFIG_PM_SLEEP */
 
 
 static inline int device_pm_add(struct device * dev)
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c
deleted file mode 100644
index 00fd84a..0000000
--- a/drivers/base/power/resume.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * resume.c - Functions for waking devices up.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Labs
- *
- * This file is released under the GPLv2
- *
- */
-
-#include <linux/device.h>
-#include <linux/resume-trace.h>
-#include "../base.h"
-#include "power.h"
-
-
-/**
- *	resume_device - Restore state for one device.
- *	@dev:	Device.
- *
- */
-
-int resume_device(struct device * dev)
-{
-	int error = 0;
-
-	TRACE_DEVICE(dev);
-	TRACE_RESUME(0);
-
-	down(&dev->sem);
-
-	if (dev->bus && dev->bus->resume) {
-		dev_dbg(dev,"resuming\n");
-		error = dev->bus->resume(dev);
-	}
-
-	if (!error && dev->type && dev->type->resume) {
-		dev_dbg(dev,"resuming\n");
-		error = dev->type->resume(dev);
-	}
-
-	if (!error && dev->class && dev->class->resume) {
-		dev_dbg(dev,"class resume\n");
-		error = dev->class->resume(dev);
-	}
-
-	up(&dev->sem);
-
-	TRACE_RESUME(error);
-	return error;
-}
-
-
-static int resume_device_early(struct device * dev)
-{
-	int error = 0;
-
-	TRACE_DEVICE(dev);
-	TRACE_RESUME(0);
-	if (dev->bus && dev->bus->resume_early) {
-		dev_dbg(dev,"EARLY resume\n");
-		error = dev->bus->resume_early(dev);
-	}
-	TRACE_RESUME(error);
-	return error;
-}
-
-/*
- * Resume the devices that have either not gone through
- * the late suspend, or that did go through it but also
- * went through the early resume
- */
-void dpm_resume(void)
-{
-	mutex_lock(&dpm_list_mtx);
-	while(!list_empty(&dpm_off)) {
-		struct list_head * entry = dpm_off.next;
-		struct device * dev = to_device(entry);
-
-		get_device(dev);
-		list_move_tail(entry, &dpm_active);
-
-		mutex_unlock(&dpm_list_mtx);
-		resume_device(dev);
-		mutex_lock(&dpm_list_mtx);
-		put_device(dev);
-	}
-	mutex_unlock(&dpm_list_mtx);
-}
-
-
-/**
- *	device_resume - Restore state of each device in system.
- *
- *	Walk the dpm_off list, remove each entry, resume the device,
- *	then add it to the dpm_active list.
- */
-
-void device_resume(void)
-{
-	might_sleep();
-	mutex_lock(&dpm_mtx);
-	dpm_resume();
-	mutex_unlock(&dpm_mtx);
-}
-
-EXPORT_SYMBOL_GPL(device_resume);
-
-
-/**
- *	dpm_power_up - Power on some devices.
- *
- *	Walk the dpm_off_irq list and power each device up. This
- *	is used for devices that required they be powered down with
- *	interrupts disabled. As devices are powered on, they are moved
- *	to the dpm_active list.
- *
- *	Interrupts must be disabled when calling this.
- */
-
-void dpm_power_up(void)
-{
-	while(!list_empty(&dpm_off_irq)) {
-		struct list_head * entry = dpm_off_irq.next;
-		struct device * dev = to_device(entry);
-
-		list_move_tail(entry, &dpm_off);
-		resume_device_early(dev);
-	}
-}
-
-
-/**
- *	device_power_up - Turn on all devices that need special attention.
- *
- *	Power on system devices then devices that required we shut them down
- *	with interrupts disabled.
- *	Called with interrupts disabled.
- */
-
-void device_power_up(void)
-{
-	sysdev_resume();
-	dpm_power_up();
-}
-
-EXPORT_SYMBOL_GPL(device_power_up);
-
-
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
deleted file mode 100644
index df6174d..0000000
--- a/drivers/base/power/runtime.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * drivers/base/power/runtime.c - Handling dynamic device power management.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Lab
- *
- */
-
-#include <linux/device.h>
-#include "power.h"
-
-
-static void runtime_resume(struct device * dev)
-{
-	dev_dbg(dev, "resuming\n");
-	if (!dev->power.power_state.event)
-		return;
-	if (!resume_device(dev))
-		dev->power.power_state = PMSG_ON;
-}
-
-
-/**
- *	dpm_runtime_resume - Power one device back on.
- *	@dev:	Device.
- *
- *	Bring one device back to the on state by first powering it
- *	on, then restoring state. We only operate on devices that aren't
- *	already on.
- *	FIXME: We need to handle devices that are in an unknown state.
- */
-
-void dpm_runtime_resume(struct device * dev)
-{
-	mutex_lock(&dpm_mtx);
-	runtime_resume(dev);
-	mutex_unlock(&dpm_mtx);
-}
-EXPORT_SYMBOL(dpm_runtime_resume);
-
-
-/**
- *	dpm_runtime_suspend - Put one device in low-power state.
- *	@dev:	Device.
- *	@state:	State to enter.
- */
-
-int dpm_runtime_suspend(struct device * dev, pm_message_t state)
-{
-	int error = 0;
-
-	mutex_lock(&dpm_mtx);
-	if (dev->power.power_state.event == state.event)
-		goto Done;
-
-	if (dev->power.power_state.event)
-		runtime_resume(dev);
-
-	if (!(error = suspend_device(dev, state)))
-		dev->power.power_state = state;
- Done:
-	mutex_unlock(&dpm_mtx);
-	return error;
-}
-EXPORT_SYMBOL(dpm_runtime_suspend);
-
-
-#if 0
-/**
- *	dpm_set_power_state - Update power_state field.
- *	@dev:	Device.
- *	@state:	Power state device is in.
- *
- *	This is an update mechanism for drivers to notify the core
- *	what power state a device is in. Device probing code may not
- *	always be able to tell, but we need accurate information to
- *	work reliably.
- */
-void dpm_set_power_state(struct device * dev, pm_message_t state)
-{
-	mutex_lock(&dpm_mtx);
-	dev->power.power_state = state;
-	mutex_unlock(&dpm_mtx);
-}
-#endif  /*  0  */
diff --git a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c
index a47ee1b..56e8eaa 100644
--- a/drivers/base/power/shutdown.c
+++ b/drivers/base/power/shutdown.c
@@ -44,7 +44,5 @@
 			dev->driver->shutdown(dev);
 		}
 	}
-
-	sysdev_shutdown();
 }
 
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
deleted file mode 100644
index 26df9b2..0000000
--- a/drivers/base/power/suspend.c
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * suspend.c - Functions for putting devices to sleep.
- *
- * Copyright (c) 2003 Patrick Mochel
- * Copyright (c) 2003 Open Source Development Labs
- *
- * This file is released under the GPLv2
- *
- */
-
-#include <linux/device.h>
-#include <linux/kallsyms.h>
-#include <linux/pm.h>
-#include "../base.h"
-#include "power.h"
-
-/*
- * The entries in the dpm_active list are in a depth first order, simply
- * because children are guaranteed to be discovered after parents, and
- * are inserted at the back of the list on discovery.
- *
- * All list on the suspend path are done in reverse order, so we operate
- * on the leaves of the device tree (or forests, depending on how you want
- * to look at it ;) first. As nodes are removed from the back of the list,
- * they are inserted into the front of their destintation lists.
- *
- * Things are the reverse on the resume path - iterations are done in
- * forward order, and nodes are inserted at the back of their destination
- * lists. This way, the ancestors will be accessed before their descendents.
- */
-
-static inline char *suspend_verb(u32 event)
-{
-	switch (event) {
-	case PM_EVENT_SUSPEND:	return "suspend";
-	case PM_EVENT_FREEZE:	return "freeze";
-	case PM_EVENT_PRETHAW:	return "prethaw";
-	default:		return "(unknown suspend event)";
-	}
-}
-
-
-static void
-suspend_device_dbg(struct device *dev, pm_message_t state, char *info)
-{
-	dev_dbg(dev, "%s%s%s\n", info, suspend_verb(state.event),
-		((state.event == PM_EVENT_SUSPEND) && device_may_wakeup(dev)) ?
-		", may wakeup" : "");
-}
-
-/**
- *	suspend_device - Save state of one device.
- *	@dev:	Device.
- *	@state:	Power state device is entering.
- */
-
-int suspend_device(struct device * dev, pm_message_t state)
-{
-	int error = 0;
-
-	down(&dev->sem);
-	if (dev->power.power_state.event) {
-		dev_dbg(dev, "PM: suspend %d-->%d\n",
-			dev->power.power_state.event, state.event);
-	}
-
-	if (dev->class && dev->class->suspend) {
-		suspend_device_dbg(dev, state, "class ");
-		error = dev->class->suspend(dev, state);
-		suspend_report_result(dev->class->suspend, error);
-	}
-
-	if (!error && dev->type && dev->type->suspend) {
-		suspend_device_dbg(dev, state, "type ");
-		error = dev->type->suspend(dev, state);
-		suspend_report_result(dev->type->suspend, error);
-	}
-
-	if (!error && dev->bus && dev->bus->suspend) {
-		suspend_device_dbg(dev, state, "");
-		error = dev->bus->suspend(dev, state);
-		suspend_report_result(dev->bus->suspend, error);
-	}
-	up(&dev->sem);
-	return error;
-}
-
-
-/*
- * This is called with interrupts off, only a single CPU
- * running. We can't acquire a mutex or semaphore (and we don't
- * need the protection)
- */
-static int suspend_device_late(struct device *dev, pm_message_t state)
-{
-	int error = 0;
-
-	if (dev->bus && dev->bus->suspend_late) {
-		suspend_device_dbg(dev, state, "LATE ");
-		error = dev->bus->suspend_late(dev, state);
-		suspend_report_result(dev->bus->suspend_late, error);
-	}
-	return error;
-}
-
-/**
- *	device_suspend - Save state and stop all devices in system.
- *	@state:		Power state to put each device in.
- *
- *	Walk the dpm_active list, call ->suspend() for each device, and move
- *	it to the dpm_off list.
- *
- *	(For historical reasons, if it returns -EAGAIN, that used to mean
- *	that the device would be called again with interrupts disabled.
- *	These days, we use the "suspend_late()" callback for that, so we
- *	print a warning and consider it an error).
- *
- *	If we get a different error, try and back out.
- *
- *	If we hit a failure with any of the devices, call device_resume()
- *	above to bring the suspended devices back to life.
- *
- */
-
-int device_suspend(pm_message_t state)
-{
-	int error = 0;
-
-	might_sleep();
-	mutex_lock(&dpm_mtx);
-	mutex_lock(&dpm_list_mtx);
-	while (!list_empty(&dpm_active) && error == 0) {
-		struct list_head * entry = dpm_active.prev;
-		struct device * dev = to_device(entry);
-
-		get_device(dev);
-		mutex_unlock(&dpm_list_mtx);
-
-		error = suspend_device(dev, state);
-
-		mutex_lock(&dpm_list_mtx);
-
-		/* Check if the device got removed */
-		if (!list_empty(&dev->power.entry)) {
-			/* Move it to the dpm_off list */
-			if (!error)
-				list_move(&dev->power.entry, &dpm_off);
-		}
-		if (error)
-			printk(KERN_ERR "Could not suspend device %s: "
-				"error %d%s\n",
-				kobject_name(&dev->kobj), error,
-				error == -EAGAIN ? " (please convert to suspend_late)" : "");
-		put_device(dev);
-	}
-	mutex_unlock(&dpm_list_mtx);
-	if (error)
-		dpm_resume();
-
-	mutex_unlock(&dpm_mtx);
-	return error;
-}
-
-EXPORT_SYMBOL_GPL(device_suspend);
-
-/**
- *	device_power_down - Shut down special devices.
- *	@state:		Power state to enter.
- *
- *	Walk the dpm_off_irq list, calling ->power_down() for each device that
- *	couldn't power down the device with interrupts enabled. When we're
- *	done, power down system devices.
- */
-
-int device_power_down(pm_message_t state)
-{
-	int error = 0;
-	struct device * dev;
-
-	while (!list_empty(&dpm_off)) {
-		struct list_head * entry = dpm_off.prev;
-
-		dev = to_device(entry);
-		error = suspend_device_late(dev, state);
-		if (error)
-			goto Error;
-		list_move(&dev->power.entry, &dpm_off_irq);
-	}
-
-	error = sysdev_suspend(state);
- Done:
-	return error;
- Error:
-	printk(KERN_ERR "Could not power down device %s: "
-		"error %d\n", kobject_name(&dev->kobj), error);
-	dpm_power_up();
-	goto Done;
-}
-
-EXPORT_SYMBOL_GPL(device_power_down);
-
-void __suspend_report_result(const char *function, void *fn, int ret)
-{
-	if (ret) {
-		printk(KERN_ERR "%s(): ", function);
-		print_fn_descriptor_symbol("%s() returns ", (unsigned long)fn);
-		printk("%d\n", ret);
-	}
-}
-EXPORT_SYMBOL_GPL(__suspend_report_result);
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 2d47517..f2ed179 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -7,69 +7,6 @@
 #include "power.h"
 
 
-#ifdef	CONFIG_PM_SYSFS_DEPRECATED
-
-/**
- *	state - Control current power state of device
- *
- *	show() returns the current power state of the device. '0' indicates
- *	the device is on. Other values (2) indicate the device is in some low
- *	power state.
- *
- *	store() sets the current power state, which is an integer valued
- *	0, 2, or 3.  Devices with bus.suspend_late(), or bus.resume_early()
- *	methods fail this operation; those methods couldn't be called.
- *	Otherwise,
- *
- *	- If the recorded dev->power.power_state.event matches the
- *	  target value, nothing is done.
- *	- If the recorded event code is nonzero, the device is reactivated
- *	  by calling bus.resume() and/or class.resume().
- *	- If the target value is nonzero, the device is suspended by
- *	  calling class.suspend() and/or bus.suspend() with event code
- *	  PM_EVENT_SUSPEND.
- *
- *	This mechanism is DEPRECATED and should only be used for testing.
- */
-
-static ssize_t state_show(struct device * dev, struct device_attribute *attr, char * buf)
-{
-	if (dev->power.power_state.event)
-		return sprintf(buf, "2\n");
-	else
-		return sprintf(buf, "0\n");
-}
-
-static ssize_t state_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t n)
-{
-	pm_message_t state;
-	int error = -EINVAL;
-
-	/* disallow incomplete suspend sequences */
-	if (dev->bus && (dev->bus->suspend_late || dev->bus->resume_early))
-		return error;
-
-	state.event = PM_EVENT_SUSPEND;
-	/* Older apps expected to write "3" here - confused with PCI D3 */
-	if ((n == 1) && !strcmp(buf, "3"))
-		error = dpm_runtime_suspend(dev, state);
-
-	if ((n == 1) && !strcmp(buf, "2"))
-		error = dpm_runtime_suspend(dev, state);
-
-	if ((n == 1) && !strcmp(buf, "0")) {
-		dpm_runtime_resume(dev);
-		error = 0;
-	}
-
-	return error ? error : n;
-}
-
-static DEVICE_ATTR(state, 0644, state_show, state_store);
-
-
-#endif	/* CONFIG_PM_SYSFS_DEPRECATED */
-
 /*
  *	wakeup - Report/change current wakeup option for device
  *
@@ -143,9 +80,6 @@
 
 
 static struct attribute * power_attrs[] = {
-#ifdef	CONFIG_PM_SYSFS_DEPRECATED
-	&dev_attr_state.attr,
-#endif
 	&dev_attr_wakeup.attr,
 	NULL,
 };
diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c
index a9ab30f..2b0c601 100644
--- a/drivers/base/power/trace.c
+++ b/drivers/base/power/trace.c
@@ -142,6 +142,7 @@
 {
 	dev_hash_value = hash_string(DEVSEED, dev->bus_id, DEVHASH);
 }
+EXPORT_SYMBOL(set_trace_device);
 
 /*
  * We could just take the "tracedata" index into the .tracedata
@@ -162,6 +163,7 @@
 	file_hash_value = hash_string(lineno, file, FILEHASH);
 	set_magic_time(user_hash_value, file_hash_value, dev_hash_value);
 }
+EXPORT_SYMBOL(generate_resume_trace);
 
 extern char __tracedata_start, __tracedata_end;
 static int show_file_hash(unsigned int value)
@@ -170,7 +172,8 @@
 	char *tracedata;
 
 	match = 0;
-	for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ; tracedata += 6) {
+	for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ;
+			tracedata += 2 + sizeof(unsigned long)) {
 		unsigned short lineno = *(unsigned short *)tracedata;
 		const char *file = *(const char **)(tracedata + 2);
 		unsigned int hash = hash_string(lineno, file, FILEHASH);
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 18febe2..ac7ff6d 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -139,7 +139,7 @@
 		 kobject_name(&cls->kset.kobj));
 	INIT_LIST_HEAD(&cls->drivers);
 	cls->kset.kobj.parent = &system_subsys.kobj;
-	kset_set_kset_s(cls, system_subsys);
+	cls->kset.kobj.kset = &system_subsys;
 	return kset_register(&cls->kset);
 }
 
@@ -153,25 +153,22 @@
 EXPORT_SYMBOL_GPL(sysdev_class_register);
 EXPORT_SYMBOL_GPL(sysdev_class_unregister);
 
-
-static LIST_HEAD(sysdev_drivers);
 static DEFINE_MUTEX(sysdev_drivers_lock);
 
 /**
  *	sysdev_driver_register - Register auxillary driver
- * 	@cls:	Device class driver belongs to.
+ *	@cls:	Device class driver belongs to.
  *	@drv:	Driver.
  *
- *	If @cls is valid, then @drv is inserted into @cls->drivers to be
+ *	@drv is inserted into @cls->drivers to be
  *	called on each operation on devices of that class. The refcount
  *	of @cls is incremented.
- *	Otherwise, @drv is inserted into sysdev_drivers, and called for
- *	each device.
  */
 
-int sysdev_driver_register(struct sysdev_class * cls,
-			   struct sysdev_driver * drv)
+int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
 {
+	int err = 0;
+
 	mutex_lock(&sysdev_drivers_lock);
 	if (cls && kset_get(&cls->kset)) {
 		list_add_tail(&drv->entry, &cls->drivers);
@@ -182,10 +179,13 @@
 			list_for_each_entry(dev, &cls->kset.list, kobj.entry)
 				drv->add(dev);
 		}
-	} else
-		list_add_tail(&drv->entry, &sysdev_drivers);
+	} else {
+		err = -EINVAL;
+		printk(KERN_ERR "%s: invalid device class\n", __FUNCTION__);
+		WARN_ON(1);
+	}
 	mutex_unlock(&sysdev_drivers_lock);
-	return 0;
+	return err;
 }
 
 
@@ -251,12 +251,6 @@
 		 * code that should have called us.
 		 */
 
-		/* Notify global drivers */
-		list_for_each_entry(drv, &sysdev_drivers, entry) {
-			if (drv->add)
-				drv->add(sysdev);
-		}
-
 		/* Notify class auxillary drivers */
 		list_for_each_entry(drv, &cls->drivers, entry) {
 			if (drv->add)
@@ -272,11 +266,6 @@
 	struct sysdev_driver * drv;
 
 	mutex_lock(&sysdev_drivers_lock);
-	list_for_each_entry(drv, &sysdev_drivers, entry) {
-		if (drv->remove)
-			drv->remove(sysdev);
-	}
-
 	list_for_each_entry(drv, &sysdev->cls->drivers, entry) {
 		if (drv->remove)
 			drv->remove(sysdev);
@@ -293,7 +282,7 @@
  *
  *	Loop over each class of system devices, and the devices in each
  *	of those classes. For each device, we call the shutdown method for
- *	each driver registered for the device - the globals, the auxillaries,
+ *	each driver registered for the device - the auxillaries,
  *	and the class driver.
  *
  *	Note: The list is iterated in reverse order, so that we shut down
@@ -320,13 +309,7 @@
 			struct sysdev_driver * drv;
 			pr_debug(" %s\n", kobject_name(&sysdev->kobj));
 
-			/* Call global drivers first. */
-			list_for_each_entry(drv, &sysdev_drivers, entry) {
-				if (drv->shutdown)
-					drv->shutdown(sysdev);
-			}
-
-			/* Call auxillary drivers next. */
+			/* Call auxillary drivers first */
 			list_for_each_entry(drv, &cls->drivers, entry) {
 				if (drv->shutdown)
 					drv->shutdown(sysdev);
@@ -354,12 +337,6 @@
 		if (drv->resume)
 			drv->resume(dev);
 	}
-
-	/* Call global drivers. */
-	list_for_each_entry(drv, &sysdev_drivers, entry) {
-		if (drv->resume)
-			drv->resume(dev);
-	}
 }
 
 /**
@@ -393,16 +370,7 @@
 		list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
 			pr_debug(" %s\n", kobject_name(&sysdev->kobj));
 
-			/* Call global drivers first. */
-			list_for_each_entry(drv, &sysdev_drivers, entry) {
-				if (drv->suspend) {
-					ret = drv->suspend(sysdev, state);
-					if (ret)
-						goto gbl_driver;
-				}
-			}
-
-			/* Call auxillary drivers next. */
+			/* Call auxillary drivers first */
 			list_for_each_entry(drv, &cls->drivers, entry) {
 				if (drv->suspend) {
 					ret = drv->suspend(sysdev, state);
@@ -436,18 +404,7 @@
 		if (err_drv->resume)
 			err_drv->resume(sysdev);
 	}
-	drv = NULL;
 
-gbl_driver:
-	if (drv)
-		printk(KERN_ERR "sysdev driver suspend failed for %s\n",
-				kobject_name(&sysdev->kobj));
-	list_for_each_entry(err_drv, &sysdev_drivers, entry) {
-		if (err_drv == drv)
-			break;
-		if (err_drv->resume)
-			err_drv->resume(sysdev);
-	}
 	/* resume other sysdevs in current class */
 	list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
 		if (err_dev == sysdev)
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index 92bf868..84d6aa5 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -17,8 +17,8 @@
 */
 
 
-#define DAC960_DriverVersion			"2.5.48"
-#define DAC960_DriverDate			"14 May 2006"
+#define DAC960_DriverVersion			"2.5.49"
+#define DAC960_DriverDate			"21 Aug 2007"
 
 
 #include <linux/module.h>
@@ -31,6 +31,7 @@
 #include <linux/genhd.h>
 #include <linux/hdreg.h>
 #include <linux/blkpg.h>
+#include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/mm.h>
@@ -1165,9 +1166,9 @@
   int i;
 
   
-  if (pci_set_dma_mask(Controller->PCIDevice, DAC690_V1_PciDmaMask))
+  if (pci_set_dma_mask(Controller->PCIDevice, DMA_32BIT_MASK))
 	return DAC960_Failure(Controller, "DMA mask out of range");
-  Controller->BounceBufferLimit = DAC690_V1_PciDmaMask;
+  Controller->BounceBufferLimit = DMA_32BIT_MASK;
 
   if ((hw_type == DAC960_PD_Controller) || (hw_type == DAC960_P_Controller)) {
     CommandMailboxesSize =  0;
@@ -1368,9 +1369,12 @@
   dma_addr_t	CommandMailboxDMA;
   DAC960_V2_CommandStatus_T CommandStatus;
 
-  if (pci_set_dma_mask(Controller->PCIDevice, DAC690_V2_PciDmaMask))
-	return DAC960_Failure(Controller, "DMA mask out of range");
-  Controller->BounceBufferLimit = DAC690_V2_PciDmaMask;
+	if (!pci_set_dma_mask(Controller->PCIDevice, DMA_64BIT_MASK))
+		Controller->BounceBufferLimit = DMA_64BIT_MASK;
+	else if (!pci_set_dma_mask(Controller->PCIDevice, DMA_32BIT_MASK))
+		Controller->BounceBufferLimit = DMA_32BIT_MASK;
+	else
+		return DAC960_Failure(Controller, "DMA mask out of range");
 
   /* This is a temporary dma mapping, used only in the scope of this function */
   CommandMailbox = pci_alloc_consistent(PCI_Device,
diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h
index f5e2436c..85fa9bb 100644
--- a/drivers/block/DAC960.h
+++ b/drivers/block/DAC960.h
@@ -61,13 +61,6 @@
 #define DAC960_V2_MaxPhysicalDevices		272
 
 /*
-  Define the pci dma mask supported by DAC960 V1 and V2 Firmware Controlers
- */
-
-#define DAC690_V1_PciDmaMask	0xffffffff
-#define DAC690_V2_PciDmaMask	0xffffffffffffffffULL
-
-/*
   Define a 32/64 bit I/O Address data type.
 */
 
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 8f65b88..ca4d7f0 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -6,6 +6,12 @@
 	bool "Block devices"
 	depends on BLOCK
 	default y
+	---help---
+	  Say Y here to get to see options for various different block device
+	  drivers. This option alone does not add any kernel code.
+
+	  If you say N, all options in this submenu will be skipped and disabled;
+	  only do this if you know what you are doing.
 
 if BLK_DEV
 
@@ -62,6 +68,7 @@
 config BLK_DEV_XD
 	tristate "XT hard disk support"
 	depends on ISA && ISA_DMA_API
+	select CHECK_SIGNATURE
 	help
 	  Very old 8 bit hard disk controllers used in the IBM XT computer
 	  will be supported if you say Y here.
@@ -354,8 +361,7 @@
 	default "4096"
 	help
 	  The default value is 4096 kilobytes. Only change this if you know
-	  what are you doing. If you are using IBM S/390, then set this to
-	  8192.
+	  what are you doing.
 
 config BLK_DEV_RAM_BLOCKSIZE
 	int "Default RAM disk block size (bytes)"
@@ -427,4 +433,13 @@
 	help
 	  Include support for the Xilinx SystemACE CompactFlash interface
 
+config XEN_BLKDEV_FRONTEND
+	tristate "Xen virtual block device support"
+	depends on XEN
+	default y
+	help
+	  This driver implements the front-end of the Xen virtual
+	  block device driver.  It communicates with a back-end driver
+	  in another domain which drives the actual block device.
+
 endif # BLK_DEV
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 9ee08ab..014e721 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -8,6 +8,7 @@
 obj-$(CONFIG_MAC_FLOPPY)	+= swim3.o
 obj-$(CONFIG_BLK_DEV_FD)	+= floppy.o
 obj-$(CONFIG_AMIGA_FLOPPY)	+= amiflop.o
+obj-$(CONFIG_PS3_DISK)		+= ps3disk.o
 obj-$(CONFIG_ATARI_FLOPPY)	+= ataflop.o
 obj-$(CONFIG_AMIGA_Z2RAM)	+= z2ram.o
 obj-$(CONFIG_BLK_DEV_RAM)	+= rd.o
@@ -29,3 +30,5 @@
 obj-$(CONFIG_BLK_DEV_SX8)	+= sx8.o
 obj-$(CONFIG_BLK_DEV_UB)	+= ub.o
 
+obj-$(CONFIG_XEN_BLKDEV_FRONTEND)	+= xen-blkfront.o
+obj-$(CONFIG_LGUEST_BLOCK)	+= lguest_blk.o
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 6ce8b89..c9751b2 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -1422,7 +1422,7 @@
 	goto repeat;
 }
 
-static void do_fd_request(request_queue_t * q)
+static void do_fd_request(struct request_queue * q)
 {
 	redo_fd_request();
 }
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
index 1d84668..ba07f76 100644
--- a/drivers/block/aoe/aoe.h
+++ b/drivers/block/aoe/aoe.h
@@ -138,7 +138,7 @@
 	u16 maxbcnt;
 	struct work_struct work;/* disk create work struct */
 	struct gendisk *gd;
-	request_queue_t blkq;
+	struct request_queue blkq;
 	struct hd_geometry geo; 
 	sector_t ssize;
 	struct timer_list timer;
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index 478489c..b1d00ef 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -125,7 +125,7 @@
 }
 
 static int
-aoeblk_make_request(request_queue_t *q, struct bio *bio)
+aoeblk_make_request(struct request_queue *q, struct bio *bio)
 {
 	struct aoedev *d;
 	struct buf *buf;
@@ -138,7 +138,7 @@
 	buf = mempool_alloc(d->bufpool, GFP_NOIO);
 	if (buf == NULL) {
 		printk(KERN_INFO "aoe: buf allocation failure\n");
-		bio_endio(bio, bio->bi_size, -ENOMEM);
+		bio_endio(bio, -ENOMEM);
 		return 0;
 	}
 	memset(buf, 0, sizeof(*buf));
@@ -159,7 +159,7 @@
 			d->aoemajor, d->aoeminor);
 		spin_unlock_irqrestore(&d->lock, flags);
 		mempool_free(buf, d->bufpool);
-		bio_endio(bio, bio->bi_size, -ENXIO);
+		bio_endio(bio, -ENXIO);
 		return 0;
 	}
 
@@ -257,9 +257,9 @@
 int __init
 aoeblk_init(void)
 {
-	buf_pool_cache = kmem_cache_create("aoe_bufs", 
+	buf_pool_cache = kmem_cache_create("aoe_bufs",
 					   sizeof(struct buf),
-					   0, 0, NULL, NULL);
+					   0, 0, NULL);
 	if (buf_pool_cache == NULL)
 		return -ENOMEM;
 
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 01fbdd3..9967201 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -9,6 +9,7 @@
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/genhd.h>
+#include <net/net_namespace.h>
 #include <asm/unaligned.h>
 #include "aoe.h"
 
@@ -194,7 +195,7 @@
 	sl = sl_tail = NULL;
 
 	read_lock(&dev_base_lock);
-	for_each_netdev(ifp) {
+	for_each_netdev(&init_net, ifp) {
 		dev_hold(ifp);
 		if (!is_aoe_netif(ifp))
 			goto cont;
@@ -652,7 +653,7 @@
 			disk_stat_add(disk, sectors[rw], n_sect);
 			disk_stat_add(disk, io_ticks, duration);
 			n = (buf->flags & BUFFL_FAIL) ? -EIO : 0;
-			bio_endio(buf->bio, buf->bio->bi_size, n);
+			bio_endio(buf->bio, n);
 			mempool_free(buf, d->bufpool);
 		}
 	}
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index 05a9719..51f5071 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -119,7 +119,7 @@
 		bio = buf->bio;
 		if (--buf->nframesout == 0) {
 			mempool_free(buf, d->bufpool);
-			bio_endio(bio, bio->bi_size, -EIO);
+			bio_endio(bio, -EIO);
 		}
 		skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0;
 	}
@@ -130,7 +130,7 @@
 		list_del(d->bufq.next);
 		bio = buf->bio;
 		mempool_free(buf, d->bufpool);
-		bio_endio(bio, bio->bi_size, -EIO);
+		bio_endio(bio, -EIO);
 	}
 
 	if (d->gd)
diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
index f9ddfda..4dc0fb7 100644
--- a/drivers/block/aoe/aoenet.c
+++ b/drivers/block/aoe/aoenet.c
@@ -8,6 +8,7 @@
 #include <linux/blkdev.h>
 #include <linux/netdevice.h>
 #include <linux/moduleparam.h>
+#include <net/net_namespace.h>
 #include <asm/unaligned.h>
 #include "aoe.h"
 
@@ -114,6 +115,9 @@
 	struct aoe_hdr *h;
 	u32 n;
 
+	if (ifp->nd_net != &init_net)
+		goto exit;
+
 	skb = skb_share_check(skb, GFP_ATOMIC);
 	if (skb == NULL)
 		return 0;
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 14d6b94..94268c7 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -1466,7 +1466,7 @@
 }
 
 
-void do_fd_request(request_queue_t * q)
+void do_fd_request(struct request_queue * q)
 {
  	unsigned long flags;
 
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index a2d6612..28d1457 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -139,7 +139,7 @@
 
 static ctlr_info_t *hba[MAX_CTLR];
 
-static void do_cciss_request(request_queue_t *q);
+static void do_cciss_request(struct request_queue *q);
 static irqreturn_t do_cciss_intr(int irq, void *dev_id);
 static int cciss_open(struct inode *inode, struct file *filep);
 static int cciss_release(struct inode *inode, struct file *filep);
@@ -1194,7 +1194,7 @@
 		int nr_sectors = bio_sectors(bio);
 
 		bio->bi_next = NULL;
-		bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO);
+		bio_endio(bio, status ? 0 : -EIO);
 		bio = xbh;
 	}
 }
@@ -1584,7 +1584,7 @@
 	 */
 	if (h->gendisk[0] != disk) {
 		if (disk) {
-			request_queue_t *q = disk->queue;
+			struct request_queue *q = disk->queue;
 			if (disk->flags & GENHD_FL_UP)
 				del_gendisk(disk);
 			if (q) {
@@ -1977,12 +1977,13 @@
 {
 	ReadCapdata_struct *buf;
 	int return_code;
-	buf = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
-	if (buf == NULL) {
+
+	buf = kzalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+	if (!buf) {
 		printk(KERN_WARNING "cciss: out of memory\n");
 		return;
 	}
-	memset(buf, 0, sizeof(ReadCapdata_struct));
+
 	if (withirq)
 		return_code = sendcmd_withirq(CCISS_READ_CAPACITY,
 				ctlr, buf, sizeof(ReadCapdata_struct),
@@ -2003,7 +2004,6 @@
 		printk(KERN_INFO "      blocks= %llu block_size= %d\n",
 		(unsigned long long)*total_size+1, *block_size);
 	kfree(buf);
-	return;
 }
 
 static void
@@ -2011,12 +2011,13 @@
 {
 	ReadCapdata_struct_16 *buf;
 	int return_code;
-	buf = kmalloc(sizeof(ReadCapdata_struct_16), GFP_KERNEL);
-	if (buf == NULL) {
+
+	buf = kzalloc(sizeof(ReadCapdata_struct_16), GFP_KERNEL);
+	if (!buf) {
 		printk(KERN_WARNING "cciss: out of memory\n");
 		return;
 	}
-	memset(buf, 0, sizeof(ReadCapdata_struct_16));
+
 	if (withirq) {
 		return_code = sendcmd_withirq(CCISS_READ_CAPACITY_16,
 			ctlr, buf, sizeof(ReadCapdata_struct_16),
@@ -2038,7 +2039,6 @@
 	printk(KERN_INFO "      blocks= %llu block_size= %d\n",
 	       (unsigned long long)*total_size+1, *block_size);
 	kfree(buf);
-	return;
 }
 
 static int cciss_revalidate(struct gendisk *disk)
@@ -2511,7 +2511,7 @@
 /*
  * Get a request and submit it to the controller.
  */
-static void do_cciss_request(request_queue_t *q)
+static void do_cciss_request(struct request_queue *q)
 {
 	ctlr_info_t *h = q->queuedata;
 	CommandList_struct *c;
@@ -3227,12 +3227,15 @@
 	for (i = 0; i < MAX_CTLR; i++) {
 		if (!hba[i]) {
 			ctlr_info_t *p;
+
 			p = kzalloc(sizeof(ctlr_info_t), GFP_KERNEL);
 			if (!p)
 				goto Enomem;
 			p->gendisk[0] = alloc_disk(1 << NWD_SHIFT);
-			if (!p->gendisk[0])
+			if (!p->gendisk[0]) {
+				kfree(p);
 				goto Enomem;
+			}
 			hba[i] = p;
 			return i;
 		}
@@ -3380,7 +3383,7 @@
 	do {
 		drive_info_struct *drv = &(hba[i]->drv[j]);
 		struct gendisk *disk = hba[i]->gendisk[j];
-		request_queue_t *q;
+		struct request_queue *q;
 
 		/* Check if the disk was allocated already */
 		if (!disk){
@@ -3523,7 +3526,7 @@
 	for (j = 0; j < CISS_MAX_LUN; j++) {
 		struct gendisk *disk = hba[i]->gendisk[j];
 		if (disk) {
-			request_queue_t *q = disk->queue;
+			struct request_queue *q = disk->queue;
 
 			if (disk->flags & GENHD_FL_UP)
 				del_gendisk(disk);
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index b94cd1c..3853c9a 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -161,7 +161,7 @@
 static int ida_getgeo(struct block_device *bdev, struct hd_geometry *geo);
 static int ida_ctlr_ioctl(ctlr_info_t *h, int dsk, ida_ioctl_t *io);
 
-static void do_ida_request(request_queue_t *q);
+static void do_ida_request(struct request_queue *q);
 static void start_io(ctlr_info_t *h);
 
 static inline void addQ(cmdlist_t **Qptr, cmdlist_t *c);
@@ -391,7 +391,7 @@
 /* pdev is NULL for eisa */
 static int __init cpqarray_register_ctlr( int i, struct pci_dev *pdev)
 {
-	request_queue_t *q;
+	struct request_queue *q;
 	int j;
 
 	/* 
@@ -420,18 +420,17 @@
 			goto Enomem2;
 	}
 
-	hba[i]->cmd_pool = (cmdlist_t *)pci_alloc_consistent(
+	hba[i]->cmd_pool = pci_alloc_consistent(
 		hba[i]->pci_dev, NR_CMDS * sizeof(cmdlist_t),
 		&(hba[i]->cmd_pool_dhandle));
-	hba[i]->cmd_pool_bits = kmalloc(
-		((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long),
+	hba[i]->cmd_pool_bits = kcalloc(
+		(NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG, sizeof(unsigned long),
 		GFP_KERNEL);
 
 	if (!hba[i]->cmd_pool_bits || !hba[i]->cmd_pool)
 			goto Enomem1;
 
 	memset(hba[i]->cmd_pool, 0, NR_CMDS * sizeof(cmdlist_t));
-	memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long));
 	printk(KERN_INFO "cpqarray: Finding drives on %s",
 		hba[i]->devname);
 
@@ -886,7 +885,7 @@
  * are in here (either via the dummy do_ida_request functions or by being
  * called from the interrupt handler
  */
-static void do_ida_request(request_queue_t *q)
+static void do_ida_request(struct request_queue *q)
 {
 	ctlr_info_t *h = q->queuedata;
 	cmdlist_t *c;
@@ -988,7 +987,7 @@
 		xbh = bio->bi_next;
 		bio->bi_next = NULL;
 		
-		bio_endio(bio, nr_sectors << 9, ok ? 0 : -EIO);
+		bio_endio(bio, ok ? 0 : -EIO);
 
 		bio = xbh;
 	}
@@ -1660,45 +1659,30 @@
 
 	info_p->log_drv_map = 0;	
 	
-	id_ldrive = kmalloc(sizeof(id_log_drv_t), GFP_KERNEL);
-	if(id_ldrive == NULL)
-	{
+	id_ldrive = kzalloc(sizeof(id_log_drv_t), GFP_KERNEL);
+	if (!id_ldrive)	{
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
-		return;
+		goto err_0;
 	}
 
-	id_ctlr_buf = kmalloc(sizeof(id_ctlr_t), GFP_KERNEL);
-	if(id_ctlr_buf == NULL)
-	{
-		kfree(id_ldrive);
+	id_ctlr_buf = kzalloc(sizeof(id_ctlr_t), GFP_KERNEL);
+	if (!id_ctlr_buf) {
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
-		return;
+		goto err_1;
 	}
 
-	id_lstatus_buf = kmalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
-	if(id_lstatus_buf == NULL)
-	{
-		kfree(id_ctlr_buf);
-		kfree(id_ldrive);
+	id_lstatus_buf = kzalloc(sizeof(sense_log_drv_stat_t), GFP_KERNEL);
+	if (!id_lstatus_buf) {
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
-		return;
+		goto err_2;
 	}
 
-	sense_config_buf = kmalloc(sizeof(config_t), GFP_KERNEL);
-	if(sense_config_buf == NULL)
-	{
-		kfree(id_lstatus_buf);
-		kfree(id_ctlr_buf);
-		kfree(id_ldrive);
+	sense_config_buf = kzalloc(sizeof(config_t), GFP_KERNEL);
+	if (!sense_config_buf) {
 		printk( KERN_ERR "cpqarray:  out of memory.\n");
-		return;
+		goto err_3;
 	}
 
-	memset(id_ldrive, 0, sizeof(id_log_drv_t));
-	memset(id_ctlr_buf, 0, sizeof(id_ctlr_t));
-	memset(id_lstatus_buf, 0, sizeof(sense_log_drv_stat_t));
-	memset(sense_config_buf, 0, sizeof(config_t));
-
 	info_p->phys_drives = 0;
 	info_p->log_drv_map = 0;
 	info_p->drv_assign_map = 0;
@@ -1712,13 +1696,8 @@
 		 * so the idastubopen will fail on all logical drives
 		 * on the controller.
 		 */
-		 /* Free all the buffers and return */ 
 		printk(KERN_ERR "cpqarray: error sending ID controller\n");
-		kfree(sense_config_buf);
-                kfree(id_lstatus_buf);
-                kfree(id_ctlr_buf);
-                kfree(id_ldrive);
-                return;
+                goto err_4;
         }
 
 	info_p->log_drives = id_ctlr_buf->nr_drvs;
@@ -1764,12 +1743,7 @@
 				" failed to report status of logical drive %d\n"
 			 "Access to this controller has been disabled\n",
 				ctlr, log_unit);
-			/* Free all the buffers and return */
-                	kfree(sense_config_buf);
-                	kfree(id_lstatus_buf);
-                	kfree(id_ctlr_buf);
-                	kfree(id_ldrive);
-                	return;
+                	goto err_4;
 		}
 		/*
 		   Make sure the logical drive is configured
@@ -1798,14 +1772,8 @@
 				 sizeof(config_t), 0, 0, log_unit);
 				if (ret_code == IO_ERROR) {
 					info_p->log_drv_map = 0;
-					/* Free all the buffers and return */
                 			printk(KERN_ERR "cpqarray: error sending sense config\n");
-                			kfree(sense_config_buf);
-                			kfree(id_lstatus_buf);
-                			kfree(id_ctlr_buf);
-                			kfree(id_ldrive);
-                			return;
-
+                			goto err_4;
 				}
 
 				info_p->phys_drives =
@@ -1820,12 +1788,18 @@
 			log_index = log_index + 1;
 		}		/* end of if logical drive configured */
 	}			/* end of for log_unit */
-	kfree(sense_config_buf);
-  	kfree(id_ldrive);
-  	kfree(id_lstatus_buf);
-	kfree(id_ctlr_buf);
-	return;
 
+	/* Free all the buffers and return */
+err_4:
+	kfree(sense_config_buf);
+err_3:
+  	kfree(id_lstatus_buf);
+err_2:
+	kfree(id_ctlr_buf);
+err_1:
+  	kfree(id_ldrive);
+err_0:
+	return;
 }
 
 static void __exit cpqarray_exit(void)
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index fe08804..80483aa 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -251,7 +251,7 @@
 
 static struct request *current_req;
 static struct request_queue *floppy_queue;
-static void do_fd_request(request_queue_t * q);
+static void do_fd_request(struct request_queue * q);
 
 #ifndef fd_get_dma_residue
 #define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)
@@ -2437,22 +2437,19 @@
 /* Compute maximal contiguous buffer size. */
 static int buffer_chain_size(void)
 {
-	struct bio *bio;
 	struct bio_vec *bv;
-	int size, i;
+	int size;
+	struct req_iterator iter;
 	char *base;
 
 	base = bio_data(current_req->bio);
 	size = 0;
 
-	rq_for_each_bio(bio, current_req) {
-		bio_for_each_segment(bv, bio, i) {
-			if (page_address(bv->bv_page) + bv->bv_offset !=
-			    base + size)
-				break;
+	rq_for_each_segment(bv, current_req, iter) {
+		if (page_address(bv->bv_page) + bv->bv_offset != base + size)
+			break;
 
-			size += bv->bv_len;
-		}
+		size += bv->bv_len;
 	}
 
 	return size >> 9;
@@ -2479,9 +2476,9 @@
 {
 	int remaining;		/* number of transferred 512-byte sectors */
 	struct bio_vec *bv;
-	struct bio *bio;
 	char *buffer, *dma_buffer;
-	int size, i;
+	int size;
+	struct req_iterator iter;
 
 	max_sector = transfer_size(ssize,
 				   min(max_sector, max_sector_2),
@@ -2514,43 +2511,41 @@
 
 	size = current_req->current_nr_sectors << 9;
 
-	rq_for_each_bio(bio, current_req) {
-		bio_for_each_segment(bv, bio, i) {
-			if (!remaining)
-				break;
+	rq_for_each_segment(bv, current_req, iter) {
+		if (!remaining)
+			break;
 
-			size = bv->bv_len;
-			SUPBOUND(size, remaining);
+		size = bv->bv_len;
+		SUPBOUND(size, remaining);
 
-			buffer = page_address(bv->bv_page) + bv->bv_offset;
+		buffer = page_address(bv->bv_page) + bv->bv_offset;
 #ifdef FLOPPY_SANITY_CHECK
-			if (dma_buffer + size >
-			    floppy_track_buffer + (max_buffer_sectors << 10) ||
-			    dma_buffer < floppy_track_buffer) {
-				DPRINT("buffer overrun in copy buffer %d\n",
-				       (int)((floppy_track_buffer -
-					      dma_buffer) >> 9));
-				printk("fsector_t=%d buffer_min=%d\n",
-				       fsector_t, buffer_min);
-				printk("current_count_sectors=%ld\n",
-				       current_count_sectors);
-				if (CT(COMMAND) == FD_READ)
-					printk("read\n");
-				if (CT(COMMAND) == FD_WRITE)
-					printk("write\n");
-				break;
-			}
-			if (((unsigned long)buffer) % 512)
-				DPRINT("%p buffer not aligned\n", buffer);
-#endif
+		if (dma_buffer + size >
+		    floppy_track_buffer + (max_buffer_sectors << 10) ||
+		    dma_buffer < floppy_track_buffer) {
+			DPRINT("buffer overrun in copy buffer %d\n",
+			       (int)((floppy_track_buffer -
+				      dma_buffer) >> 9));
+			printk("fsector_t=%d buffer_min=%d\n",
+			       fsector_t, buffer_min);
+			printk("current_count_sectors=%ld\n",
+			       current_count_sectors);
 			if (CT(COMMAND) == FD_READ)
-				memcpy(buffer, dma_buffer, size);
-			else
-				memcpy(dma_buffer, buffer, size);
-
-			remaining -= size;
-			dma_buffer += size;
+				printk("read\n");
+			if (CT(COMMAND) == FD_WRITE)
+				printk("write\n");
+			break;
 		}
+		if (((unsigned long)buffer) % 512)
+			DPRINT("%p buffer not aligned\n", buffer);
+#endif
+		if (CT(COMMAND) == FD_READ)
+			memcpy(buffer, dma_buffer, size);
+		else
+			memcpy(dma_buffer, buffer, size);
+
+		remaining -= size;
+		dma_buffer += size;
 	}
 #ifdef FLOPPY_SANITY_CHECK
 	if (remaining) {
@@ -2981,7 +2976,7 @@
 	schedule_bh(redo_fd_request);
 }
 
-static void do_fd_request(request_queue_t * q)
+static void do_fd_request(struct request_queue * q)
 {
 	if (max_buffer_sectors == 0) {
 		printk("VFS: do_fd_request called on non-open device\n");
@@ -3815,14 +3810,10 @@
  * a disk in the drive, and whether that disk is writable.
  */
 
-static int floppy_rb0_complete(struct bio *bio, unsigned int bytes_done,
+static void floppy_rb0_complete(struct bio *bio,
 			       int err)
 {
-	if (bio->bi_size)
-		return 1;
-
 	complete((struct completion *)bio->bi_private);
-	return 0;
 }
 
 static int __floppy_read_block_0(struct block_device *bdev)
diff --git a/drivers/block/lguest_blk.c b/drivers/block/lguest_blk.c
new file mode 100644
index 0000000..fa8e423
--- /dev/null
+++ b/drivers/block/lguest_blk.c
@@ -0,0 +1,421 @@
+/*D:400
+ * The Guest block driver
+ *
+ * This is a simple block driver, which appears as /dev/lgba, lgbb, lgbc etc.
+ * The mechanism is simple: we place the information about the request in the
+ * device page, then use SEND_DMA (containing the data for a write, or an empty
+ * "ping" DMA for a read).
+ :*/
+/* Copyright 2006 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
+ *
+ * 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
+ */
+//#define DEBUG
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/lguest_bus.h>
+
+static char next_block_index = 'a';
+
+/*D:420 Here is the structure which holds all the information we need about
+ * each Guest block device.
+ *
+ * I'm sure at this stage, you're wondering "hey, where was the adventure I was
+ * promised?" and thinking "Rusty sucks, I shall say nasty things about him on
+ * my blog".  I think Real adventures have boring bits, too, and you're in the
+ * middle of one.  But it gets better.  Just not quite yet. */
+struct blockdev
+{
+	/* The block queue infrastructure wants a spinlock: it is held while it
+	 * calls our block request function.  We grab it in our interrupt
+	 * handler so the responses don't mess with new requests. */
+	spinlock_t lock;
+
+	/* The disk structure registered with kernel. */
+	struct gendisk *disk;
+
+	/* The major device number for this disk, and the interrupt.  We only
+	 * really keep them here for completeness; we'd need them if we
+	 * supported device unplugging. */
+	int major;
+	int irq;
+
+	/* The physical address of this device's memory page */
+	unsigned long phys_addr;
+	/* The mapped memory page for convenient acces. */
+	struct lguest_block_page *lb_page;
+
+	/* We only have a single request outstanding at a time: this is it. */
+	struct lguest_dma dma;
+	struct request *req;
+};
+
+/*D:495 We originally used end_request() throughout the driver, but it turns
+ * out that end_request() is deprecated, and doesn't actually end the request
+ * (which seems like a good reason to deprecate it!).  It simply ends the first
+ * bio.  So if we had 3 bios in a "struct request" we would do all 3,
+ * end_request(), do 2, end_request(), do 1 and end_request(): twice as much
+ * work as we needed to do.
+ *
+ * This reinforced to me that I do not understand the block layer.
+ *
+ * Nonetheless, Jens Axboe gave me this nice helper to end all chunks of a
+ * request.  This improved disk speed by 130%. */
+static void end_entire_request(struct request *req, int uptodate)
+{
+	if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
+		BUG();
+	add_disk_randomness(req->rq_disk);
+	blkdev_dequeue_request(req);
+	end_that_request_last(req, uptodate);
+}
+
+/* I'm told there are only two stories in the world worth telling: love and
+ * hate.  So there used to be a love scene here like this:
+ *
+ *  Launcher:	We could make beautiful I/O together, you and I.
+ *  Guest:	My, that's a big disk!
+ *
+ * Unfortunately, it was just too raunchy for our otherwise-gentle tale. */
+
+/*D:490 This is the interrupt handler, called when a block read or write has
+ * been completed for us. */
+static irqreturn_t lgb_irq(int irq, void *_bd)
+{
+	/* We handed our "struct blockdev" as the argument to request_irq(), so
+	 * it is passed through to us here.  This tells us which device we're
+	 * dealing with in case we have more than one. */
+	struct blockdev *bd = _bd;
+	unsigned long flags;
+
+	/* We weren't doing anything?  Strange, but could happen if we shared
+	 * interrupts (we don't!). */
+	if (!bd->req) {
+		pr_debug("No work!\n");
+		return IRQ_NONE;
+	}
+
+	/* Not done yet?  That's equally strange. */
+	if (!bd->lb_page->result) {
+		pr_debug("No result!\n");
+		return IRQ_NONE;
+	}
+
+	/* We have to grab the lock before ending the request. */
+	spin_lock_irqsave(&bd->lock, flags);
+	/* "result" is 1 for success, 2 for failure: end_entire_request() wants
+	 * to know whether this succeeded or not. */
+	end_entire_request(bd->req, bd->lb_page->result == 1);
+	/* Clear out request, it's done. */
+	bd->req = NULL;
+	/* Reset incoming DMA for next time. */
+	bd->dma.used_len = 0;
+	/* Ready for more reads or writes */
+	blk_start_queue(bd->disk->queue);
+	spin_unlock_irqrestore(&bd->lock, flags);
+
+	/* The interrupt was for us, we dealt with it. */
+	return IRQ_HANDLED;
+}
+
+/*D:480 The block layer's "struct request" contains a number of "struct bio"s,
+ * each of which contains "struct bio_vec"s, each of which contains a page, an
+ * offset and a length.
+ *
+ * Fortunately there are iterators to help us walk through the "struct
+ * request".  Even more fortunately, there were plenty of places to steal the
+ * code from.  We pack the "struct request" into our "struct lguest_dma" and
+ * return the total length. */
+static unsigned int req_to_dma(struct request *req, struct lguest_dma *dma)
+{
+	unsigned int i = 0, len = 0;
+	struct req_iterator iter;
+	struct bio_vec *bvec;
+
+	rq_for_each_segment(bvec, req, iter) {
+		/* We told the block layer not to give us too many. */
+		BUG_ON(i == LGUEST_MAX_DMA_SECTIONS);
+		/* If we had a zero-length segment, it would look like
+		 * the end of the data referred to by the "struct
+		 * lguest_dma", so make sure that doesn't happen. */
+		BUG_ON(!bvec->bv_len);
+		/* Convert page & offset to a physical address */
+		dma->addr[i] = page_to_phys(bvec->bv_page)
+			+ bvec->bv_offset;
+		dma->len[i] = bvec->bv_len;
+		len += bvec->bv_len;
+		i++;
+	}
+	/* If the array isn't full, we mark the end with a 0 length */
+	if (i < LGUEST_MAX_DMA_SECTIONS)
+		dma->len[i] = 0;
+	return len;
+}
+
+/* This creates an empty DMA, useful for prodding the Host without sending data
+ * (ie. when we want to do a read) */
+static void empty_dma(struct lguest_dma *dma)
+{
+	dma->len[0] = 0;
+}
+
+/*D:470 Setting up a request is fairly easy: */
+static void setup_req(struct blockdev *bd,
+		      int type, struct request *req, struct lguest_dma *dma)
+{
+	/* The type is 1 (write) or 0 (read). */
+	bd->lb_page->type = type;
+	/* The sector on disk where the read or write starts. */
+	bd->lb_page->sector = req->sector;
+	/* The result is initialized to 0 (unfinished). */
+	bd->lb_page->result = 0;
+	/* The current request (so we can end it in the interrupt handler). */
+	bd->req = req;
+	/* The number of bytes: returned as a side-effect of req_to_dma(),
+	 * which packs the block layer's "struct request" into our "struct
+	 * lguest_dma" */
+	bd->lb_page->bytes = req_to_dma(req, dma);
+}
+
+/*D:450 Write is pretty straightforward: we pack the request into a "struct
+ * lguest_dma", then use SEND_DMA to send the request. */
+static void do_write(struct blockdev *bd, struct request *req)
+{
+	struct lguest_dma send;
+
+	pr_debug("lgb: WRITE sector %li\n", (long)req->sector);
+	setup_req(bd, 1, req, &send);
+
+	lguest_send_dma(bd->phys_addr, &send);
+}
+
+/* Read is similar to write, except we pack the request into our receive
+ * "struct lguest_dma" and send through an empty DMA just to tell the Host that
+ * there's a request pending. */
+static void do_read(struct blockdev *bd, struct request *req)
+{
+	struct lguest_dma ping;
+
+	pr_debug("lgb: READ sector %li\n", (long)req->sector);
+	setup_req(bd, 0, req, &bd->dma);
+
+	empty_dma(&ping);
+	lguest_send_dma(bd->phys_addr, &ping);
+}
+
+/*D:440 This where requests come in: we get handed the request queue and are
+ * expected to pull a "struct request" off it until we've finished them or
+ * we're waiting for a reply: */
+static void do_lgb_request(struct request_queue *q)
+{
+	struct blockdev *bd;
+	struct request *req;
+
+again:
+	/* This sometimes returns NULL even on the very first time around.  I
+	 * wonder if it's something to do with letting elves handle the request
+	 * queue... */
+	req = elv_next_request(q);
+	if (!req)
+		return;
+
+	/* We attached the struct blockdev to the disk: get it back */
+	bd = req->rq_disk->private_data;
+	/* Sometimes we get repeated requests after blk_stop_queue(), but we
+	 * can only handle one at a time. */
+	if (bd->req)
+		return;
+
+	/* We only do reads and writes: no tricky business! */
+	if (!blk_fs_request(req)) {
+		pr_debug("Got non-command 0x%08x\n", req->cmd_type);
+		req->errors++;
+		end_entire_request(req, 0);
+		goto again;
+	}
+
+	if (rq_data_dir(req) == WRITE)
+		do_write(bd, req);
+	else
+		do_read(bd, req);
+
+	/* We've put out the request, so stop any more coming in until we get
+	 * an interrupt, which takes us to lgb_irq() to re-enable the queue. */
+	blk_stop_queue(q);
+}
+
+/*D:430 This is the "struct block_device_operations" we attach to the disk at
+ * the end of lguestblk_probe().  It doesn't seem to want much. */
+static struct block_device_operations lguestblk_fops = {
+	.owner = THIS_MODULE,
+};
+
+/*D:425 Setting up a disk device seems to involve a lot of code.  I'm not sure
+ * quite why.  I do know that the IDE code sent two or three of the maintainers
+ * insane, perhaps this is the fringe of the same disease?
+ *
+ * As in the console code, the probe function gets handed the generic
+ * lguest_device from lguest_bus.c: */
+static int lguestblk_probe(struct lguest_device *lgdev)
+{
+	struct blockdev *bd;
+	int err;
+	int irqflags = IRQF_SHARED;
+
+	/* First we allocate our own "struct blockdev" and initialize the easy
+	 * fields. */
+	bd = kmalloc(sizeof(*bd), GFP_KERNEL);
+	if (!bd)
+		return -ENOMEM;
+
+	spin_lock_init(&bd->lock);
+	bd->irq = lgdev_irq(lgdev);
+	bd->req = NULL;
+	bd->dma.used_len = 0;
+	bd->dma.len[0] = 0;
+	/* The descriptor in the lguest_devices array provided by the Host
+	 * gives the Guest the physical page number of the device's page. */
+	bd->phys_addr = (lguest_devices[lgdev->index].pfn << PAGE_SHIFT);
+
+	/* We use lguest_map() to get a pointer to the device page */
+	bd->lb_page = lguest_map(bd->phys_addr, 1);
+	if (!bd->lb_page) {
+		err = -ENOMEM;
+		goto out_free_bd;
+	}
+
+	/* We need a major device number: 0 means "assign one dynamically". */
+	bd->major = register_blkdev(0, "lguestblk");
+	if (bd->major < 0) {
+		err = bd->major;
+		goto out_unmap;
+	}
+
+	/* This allocates a "struct gendisk" where we pack all the information
+	 * about the disk which the rest of Linux sees.  The argument is the
+	 * number of minor devices desired: we need one minor for the main
+	 * disk, and one for each partition.  Of course, we can't possibly know
+	 * how many partitions are on the disk (add_disk does that).
+	 */
+	bd->disk = alloc_disk(16);
+	if (!bd->disk) {
+		err = -ENOMEM;
+		goto out_unregister_blkdev;
+	}
+
+	/* Every disk needs a queue for requests to come in: we set up the
+	 * queue with a callback function (the core of our driver) and the lock
+	 * to use. */
+	bd->disk->queue = blk_init_queue(do_lgb_request, &bd->lock);
+	if (!bd->disk->queue) {
+		err = -ENOMEM;
+		goto out_put_disk;
+	}
+
+	/* We can only handle a certain number of pointers in our SEND_DMA
+	 * call, so we set that with blk_queue_max_hw_segments().  This is not
+	 * to be confused with blk_queue_max_phys_segments() of course!  I
+	 * know, who could possibly confuse the two?
+	 *
+	 * Well, it's simple to tell them apart: this one seems to work and the
+	 * other one didn't. */
+	blk_queue_max_hw_segments(bd->disk->queue, LGUEST_MAX_DMA_SECTIONS);
+
+	/* Due to technical limitations of our Host (and simple coding) we
+	 * can't have a single buffer which crosses a page boundary.  Tell it
+	 * here.  This means that our maximum request size is 16
+	 * (LGUEST_MAX_DMA_SECTIONS) pages. */
+	blk_queue_segment_boundary(bd->disk->queue, PAGE_SIZE-1);
+
+	/* We name our disk: this becomes the device name when udev does its
+	 * magic thing and creates the device node, such as /dev/lgba.
+	 * next_block_index is a global which starts at 'a'.  Unfortunately
+	 * this simple increment logic means that the 27th disk will be called
+	 * "/dev/lgb{".  In that case, I recommend having at least 29 disks, so
+	 * your /dev directory will be balanced. */
+	sprintf(bd->disk->disk_name, "lgb%c", next_block_index++);
+
+	/* We look to the device descriptor again to see if this device's
+	 * interrupts are expected to be random.  If they are, we tell the irq
+	 * subsystem.  At the moment this bit is always set. */
+	if (lguest_devices[lgdev->index].features & LGUEST_DEVICE_F_RANDOMNESS)
+		irqflags |= IRQF_SAMPLE_RANDOM;
+
+	/* Now we have the name and irqflags, we can request the interrupt; we
+	 * give it the "struct blockdev" we have set up to pass to lgb_irq()
+	 * when there is an interrupt. */
+	err = request_irq(bd->irq, lgb_irq, irqflags, bd->disk->disk_name, bd);
+	if (err)
+		goto out_cleanup_queue;
+
+	/* We bind our one-entry DMA pool to the key for this block device so
+	 * the Host can reply to our requests.  The key is equal to the
+	 * physical address of the device's page, which is conveniently
+	 * unique. */
+	err = lguest_bind_dma(bd->phys_addr, &bd->dma, 1, bd->irq);
+	if (err)
+		goto out_free_irq;
+
+	/* We finish our disk initialization and add the disk to the system. */
+	bd->disk->major = bd->major;
+	bd->disk->first_minor = 0;
+	bd->disk->private_data = bd;
+	bd->disk->fops = &lguestblk_fops;
+	/* This is initialized to the disk size by the Launcher. */
+	set_capacity(bd->disk, bd->lb_page->num_sectors);
+	add_disk(bd->disk);
+
+	printk(KERN_INFO "%s: device %i at major %d\n",
+	       bd->disk->disk_name, lgdev->index, bd->major);
+
+	/* We don't need to keep the "struct blockdev" around, but if we ever
+	 * implemented device removal, we'd need this. */
+	lgdev->private = bd;
+	return 0;
+
+out_free_irq:
+	free_irq(bd->irq, bd);
+out_cleanup_queue:
+	blk_cleanup_queue(bd->disk->queue);
+out_put_disk:
+	put_disk(bd->disk);
+out_unregister_blkdev:
+	unregister_blkdev(bd->major, "lguestblk");
+out_unmap:
+	lguest_unmap(bd->lb_page);
+out_free_bd:
+	kfree(bd);
+	return err;
+}
+
+/*D:410 The boilerplate code for registering the lguest block driver is just
+ * like the console: */
+static struct lguest_driver lguestblk_drv = {
+	.name = "lguestblk",
+	.owner = THIS_MODULE,
+	.device_type = LGUEST_DEVICE_T_BLOCK,
+	.probe = lguestblk_probe,
+};
+
+static __init int lguestblk_init(void)
+{
+	return register_lguest_driver(&lguestblk_drv);
+}
+module_init(lguestblk_init);
+
+MODULE_DESCRIPTION("Lguest block driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index e425daa..b9233a0 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -529,7 +529,7 @@
 	return bio;
 }
 
-static int loop_make_request(request_queue_t *q, struct bio *old_bio)
+static int loop_make_request(struct request_queue *q, struct bio *old_bio)
 {
 	struct loop_device *lo = q->queuedata;
 	int rw = bio_rw(old_bio);
@@ -551,14 +551,14 @@
 
 out:
 	spin_unlock_irq(&lo->lo_lock);
-	bio_io_error(old_bio, old_bio->bi_size);
+	bio_io_error(old_bio);
 	return 0;
 }
 
 /*
  * kick off io on the underlying address space
  */
-static void loop_unplug(request_queue_t *q)
+static void loop_unplug(struct request_queue *q)
 {
 	struct loop_device *lo = q->queuedata;
 
@@ -580,7 +580,7 @@
 		bio_put(bio);
 	} else {
 		int ret = do_bio_filebacked(lo, bio);
-		bio_endio(bio, bio->bi_size, ret);
+		bio_endio(bio, ret);
 	}
 }
 
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index c129510..be5ec3a 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -100,7 +100,7 @@
 static void nbd_end_request(struct request *req)
 {
 	int uptodate = (req->errors == 0) ? 1 : 0;
-	request_queue_t *q = req->q;
+	struct request_queue *q = req->q;
 	unsigned long flags;
 
 	dprintk(DBG_BLKDEV, "%s: request %p: %s\n", req->rq_disk->disk_name,
@@ -180,7 +180,7 @@
 
 static int nbd_send_req(struct nbd_device *lo, struct request *req)
 {
-	int result, i, flags;
+	int result, flags;
 	struct nbd_request request;
 	unsigned long size = req->nr_sectors << 9;
 	struct socket *sock = lo->sock;
@@ -205,27 +205,23 @@
 	}
 
 	if (nbd_cmd(req) == NBD_CMD_WRITE) {
-		struct bio *bio;
+		struct req_iterator iter;
+		struct bio_vec *bvec;
 		/*
 		 * we are really probing at internals to determine
 		 * whether to set MSG_MORE or not...
 		 */
-		rq_for_each_bio(bio, req) {
-			struct bio_vec *bvec;
-			bio_for_each_segment(bvec, bio, i) {
-				flags = 0;
-				if ((i < (bio->bi_vcnt - 1)) || bio->bi_next)
-					flags = MSG_MORE;
-				dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n",
-						lo->disk->disk_name, req,
-						bvec->bv_len);
-				result = sock_send_bvec(sock, bvec, flags);
-				if (result <= 0) {
-					printk(KERN_ERR "%s: Send data failed (result %d)\n",
-							lo->disk->disk_name,
-							result);
-					goto error_out;
-				}
+		rq_for_each_segment(bvec, req, iter) {
+			flags = 0;
+			if (!rq_iter_last(req, iter))
+				flags = MSG_MORE;
+			dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n",
+					lo->disk->disk_name, req, bvec->bv_len);
+			result = sock_send_bvec(sock, bvec, flags);
+			if (result <= 0) {
+				printk(KERN_ERR "%s: Send data failed (result %d)\n",
+						lo->disk->disk_name, result);
+				goto error_out;
 			}
 		}
 	}
@@ -321,22 +317,19 @@
 	dprintk(DBG_RX, "%s: request %p: got reply\n",
 			lo->disk->disk_name, req);
 	if (nbd_cmd(req) == NBD_CMD_READ) {
-		int i;
-		struct bio *bio;
-		rq_for_each_bio(bio, req) {
-			struct bio_vec *bvec;
-			bio_for_each_segment(bvec, bio, i) {
-				result = sock_recv_bvec(sock, bvec);
-				if (result <= 0) {
-					printk(KERN_ERR "%s: Receive data failed (result %d)\n",
-							lo->disk->disk_name,
-							result);
-					req->errors++;
-					return req;
-				}
-				dprintk(DBG_RX, "%s: request %p: got %d bytes data\n",
-					lo->disk->disk_name, req, bvec->bv_len);
+		struct req_iterator iter;
+		struct bio_vec *bvec;
+
+		rq_for_each_segment(bvec, req, iter) {
+			result = sock_recv_bvec(sock, bvec);
+			if (result <= 0) {
+				printk(KERN_ERR "%s: Receive data failed (result %d)\n",
+						lo->disk->disk_name, result);
+				req->errors++;
+				return req;
 			}
+			dprintk(DBG_RX, "%s: request %p: got %d bytes data\n",
+				lo->disk->disk_name, req, bvec->bv_len);
 		}
 	}
 	return req;
@@ -410,7 +403,7 @@
  *   { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); }
  */
 
-static void do_nbd_request(request_queue_t * q)
+static void do_nbd_request(struct request_queue * q)
 {
 	struct request *req;
 	
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
index 1eeb8f2..b8a994a 100644
--- a/drivers/block/paride/pcd.c
+++ b/drivers/block/paride/pcd.c
@@ -183,7 +183,7 @@
 static int pcd_detect(void);
 static void pcd_probe_capabilities(void);
 static void do_pcd_read_drq(void);
-static void do_pcd_request(request_queue_t * q);
+static void do_pcd_request(struct request_queue * q);
 static void do_pcd_read(void);
 
 struct pcd_unit {
@@ -713,7 +713,7 @@
 /* I/O request processing */
 static struct request_queue *pcd_queue;
 
-static void do_pcd_request(request_queue_t * q)
+static void do_pcd_request(struct request_queue * q)
 {
 	if (pcd_busy)
 		return;
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 31e0148..df819f8 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -698,7 +698,7 @@
 
 /* end of io request engine */
 
-static void do_pd_request(request_queue_t * q)
+static void do_pd_request(struct request_queue * q)
 {
 	if (pd_req)
 		return;
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
index 5826508..ceffa60 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -202,7 +202,7 @@
 #define ATAPI_WRITE_10		0x2a
 
 static int pf_open(struct inode *inode, struct file *file);
-static void do_pf_request(request_queue_t * q);
+static void do_pf_request(struct request_queue * q);
 static int pf_ioctl(struct inode *inode, struct file *file,
 		    unsigned int cmd, unsigned long arg);
 static int pf_getgeo(struct block_device *bdev, struct hd_geometry *geo);
@@ -760,7 +760,7 @@
 	}
 }
 
-static void do_pf_request(request_queue_t * q)
+static void do_pf_request(struct request_queue * q)
 {
 	if (pf_busy)
 		return;
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 31be33e..540bf36 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -752,7 +752,7 @@
  */
 static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *cgc)
 {
-	request_queue_t *q = bdev_get_queue(pd->bdev);
+	struct request_queue *q = bdev_get_queue(pd->bdev);
 	struct request *rq;
 	int ret = 0;
 
@@ -979,7 +979,7 @@
  * Special care is needed if the underlying block device has a small
  * max_phys_segments value.
  */
-static int pkt_set_segment_merging(struct pktcdvd_device *pd, request_queue_t *q)
+static int pkt_set_segment_merging(struct pktcdvd_device *pd, struct request_queue *q)
 {
 	if ((pd->settings.size << 9) / CD_FRAMESIZE <= q->max_phys_segments) {
 		/*
@@ -1058,15 +1058,12 @@
 	}
 }
 
-static int pkt_end_io_read(struct bio *bio, unsigned int bytes_done, int err)
+static void pkt_end_io_read(struct bio *bio, int err)
 {
 	struct packet_data *pkt = bio->bi_private;
 	struct pktcdvd_device *pd = pkt->pd;
 	BUG_ON(!pd);
 
-	if (bio->bi_size)
-		return 1;
-
 	VPRINTK("pkt_end_io_read: bio=%p sec0=%llx sec=%llx err=%d\n", bio,
 		(unsigned long long)pkt->sector, (unsigned long long)bio->bi_sector, err);
 
@@ -1077,19 +1074,14 @@
 		wake_up(&pd->wqueue);
 	}
 	pkt_bio_finished(pd);
-
-	return 0;
 }
 
-static int pkt_end_io_packet_write(struct bio *bio, unsigned int bytes_done, int err)
+static void pkt_end_io_packet_write(struct bio *bio, int err)
 {
 	struct packet_data *pkt = bio->bi_private;
 	struct pktcdvd_device *pd = pkt->pd;
 	BUG_ON(!pd);
 
-	if (bio->bi_size)
-		return 1;
-
 	VPRINTK("pkt_end_io_packet_write: id=%d, err=%d\n", pkt->id, err);
 
 	pd->stats.pkt_ended++;
@@ -1098,7 +1090,6 @@
 	atomic_dec(&pkt->io_wait);
 	atomic_inc(&pkt->run_sm);
 	wake_up(&pd->wqueue);
-	return 0;
 }
 
 /*
@@ -1470,7 +1461,7 @@
 	while (bio) {
 		next = bio->bi_next;
 		bio->bi_next = NULL;
-		bio_endio(bio, bio->bi_size, uptodate ? 0 : -EIO);
+		bio_endio(bio, uptodate ? 0 : -EIO);
 		bio = next;
 	}
 	pkt->orig_bios = pkt->orig_bios_tail = NULL;
@@ -2314,7 +2305,7 @@
 {
 	int ret;
 	long lba;
-	request_queue_t *q;
+	struct request_queue *q;
 
 	/*
 	 * We need to re-open the cdrom device without O_NONBLOCK to be able
@@ -2462,22 +2453,18 @@
 }
 
 
-static int pkt_end_io_read_cloned(struct bio *bio, unsigned int bytes_done, int err)
+static void pkt_end_io_read_cloned(struct bio *bio, int err)
 {
 	struct packet_stacked_data *psd = bio->bi_private;
 	struct pktcdvd_device *pd = psd->pd;
 
-	if (bio->bi_size)
-		return 1;
-
 	bio_put(bio);
-	bio_endio(psd->bio, psd->bio->bi_size, err);
+	bio_endio(psd->bio, err);
 	mempool_free(psd, psd_pool);
 	pkt_bio_finished(pd);
-	return 0;
 }
 
-static int pkt_make_request(request_queue_t *q, struct bio *bio)
+static int pkt_make_request(struct request_queue *q, struct bio *bio)
 {
 	struct pktcdvd_device *pd;
 	char b[BDEVNAME_SIZE];
@@ -2620,13 +2607,13 @@
 	}
 	return 0;
 end_io:
-	bio_io_error(bio, bio->bi_size);
+	bio_io_error(bio);
 	return 0;
 }
 
 
 
-static int pkt_merge_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *bvec)
+static int pkt_merge_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *bvec)
 {
 	struct pktcdvd_device *pd = q->queuedata;
 	sector_t zone = ZONE(bio->bi_sector, pd);
@@ -2647,7 +2634,7 @@
 
 static void pkt_init_queue(struct pktcdvd_device *pd)
 {
-	request_queue_t *q = pd->disk->queue;
+	struct request_queue *q = pd->disk->queue;
 
 	blk_queue_make_request(q, pkt_make_request);
 	blk_queue_hardsect_size(q, CD_FRAMESIZE);
diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
index 688a4fb..3c796e2 100644
--- a/drivers/block/ps2esdi.c
+++ b/drivers/block/ps2esdi.c
@@ -64,7 +64,7 @@
 
 static int ps2esdi_geninit(void);
 
-static void do_ps2esdi_request(request_queue_t * q);
+static void do_ps2esdi_request(struct request_queue * q);
 
 static void ps2esdi_readwrite(int cmd, struct request *req);
 
@@ -473,7 +473,7 @@
 }
 
 /* strategy routine that handles most of the IO requests */
-static void do_ps2esdi_request(request_queue_t * q)
+static void do_ps2esdi_request(struct request_queue * q)
 {
 	struct request *req;
 	/* since, this routine is called with interrupts cleared - they 
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
new file mode 100644
index 0000000..06d0552
--- /dev/null
+++ b/drivers/block/ps3disk.c
@@ -0,0 +1,630 @@
+/*
+ * PS3 Disk Storage Driver
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony Corp.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/ata.h>
+#include <linux/blkdev.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
+#include <asm/firmware.h>
+
+
+#define DEVICE_NAME		"ps3disk"
+
+#define BOUNCE_SIZE		(64*1024)
+
+#define PS3DISK_MAX_DISKS	16
+#define PS3DISK_MINORS		16
+
+
+#define PS3DISK_NAME		"ps3d%c"
+
+
+struct ps3disk_private {
+	spinlock_t lock;		/* Request queue spinlock */
+	struct request_queue *queue;
+	struct gendisk *gendisk;
+	unsigned int blocking_factor;
+	struct request *req;
+	u64 raw_capacity;
+	unsigned char model[ATA_ID_PROD_LEN+1];
+};
+
+
+#define LV1_STORAGE_SEND_ATA_COMMAND	(2)
+#define LV1_STORAGE_ATA_HDDOUT		(0x23)
+
+struct lv1_ata_cmnd_block {
+	u16	features;
+	u16	sector_count;
+	u16	LBA_low;
+	u16	LBA_mid;
+	u16	LBA_high;
+	u8	device;
+	u8	command;
+	u32	is_ext;
+	u32	proto;
+	u32	in_out;
+	u32	size;
+	u64	buffer;
+	u32	arglen;
+};
+
+enum lv1_ata_proto {
+	NON_DATA_PROTO     = 0,
+	PIO_DATA_IN_PROTO  = 1,
+	PIO_DATA_OUT_PROTO = 2,
+	DMA_PROTO = 3
+};
+
+enum lv1_ata_in_out {
+	DIR_WRITE = 0,			/* memory -> device */
+	DIR_READ = 1			/* device -> memory */
+};
+
+static int ps3disk_major;
+
+
+static struct block_device_operations ps3disk_fops = {
+	.owner		= THIS_MODULE,
+};
+
+
+static void ps3disk_scatter_gather(struct ps3_storage_device *dev,
+				   struct request *req, int gather)
+{
+	unsigned int offset = 0;
+	struct req_iterator iter;
+	struct bio_vec *bvec;
+	unsigned int i = 0;
+	size_t size;
+	void *buf;
+
+	rq_for_each_segment(bvec, req, iter) {
+		unsigned long flags;
+		dev_dbg(&dev->sbd.core,
+			"%s:%u: bio %u: %u segs %u sectors from %lu\n",
+			__func__, __LINE__, i, bio_segments(iter.bio),
+			bio_sectors(iter.bio),
+			(unsigned long)iter.bio->bi_sector);
+
+		size = bvec->bv_len;
+		buf = bvec_kmap_irq(bvec, &flags);
+		if (gather)
+			memcpy(dev->bounce_buf+offset, buf, size);
+		else
+			memcpy(buf, dev->bounce_buf+offset, size);
+		offset += size;
+		flush_kernel_dcache_page(bvec->bv_page);
+		bvec_kunmap_irq(bvec, &flags);
+		i++;
+	}
+}
+
+static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
+				     struct request *req)
+{
+	struct ps3disk_private *priv = dev->sbd.core.driver_data;
+	int write = rq_data_dir(req), res;
+	const char *op = write ? "write" : "read";
+	u64 start_sector, sectors;
+	unsigned int region_id = dev->regions[dev->region_idx].id;
+
+#ifdef DEBUG
+	unsigned int n = 0;
+	struct bio_vec *bv;
+	struct req_iterator iter;
+
+	rq_for_each_segment(bv, req, iter)
+		n++;
+	dev_dbg(&dev->sbd.core,
+		"%s:%u: %s req has %u bvecs for %lu sectors %lu hard sectors\n",
+		__func__, __LINE__, op, n, req->nr_sectors,
+		req->hard_nr_sectors);
+#endif
+
+	start_sector = req->sector * priv->blocking_factor;
+	sectors = req->nr_sectors * priv->blocking_factor;
+	dev_dbg(&dev->sbd.core, "%s:%u: %s %lu sectors starting at %lu\n",
+		__func__, __LINE__, op, sectors, start_sector);
+
+	if (write) {
+		ps3disk_scatter_gather(dev, req, 1);
+
+		res = lv1_storage_write(dev->sbd.dev_id, region_id,
+					start_sector, sectors, 0,
+					dev->bounce_lpar, &dev->tag);
+	} else {
+		res = lv1_storage_read(dev->sbd.dev_id, region_id,
+				       start_sector, sectors, 0,
+				       dev->bounce_lpar, &dev->tag);
+	}
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__,
+			__LINE__, op, res);
+		end_request(req, 0);
+		return 0;
+	}
+
+	priv->req = req;
+	return 1;
+}
+
+static int ps3disk_submit_flush_request(struct ps3_storage_device *dev,
+					struct request *req)
+{
+	struct ps3disk_private *priv = dev->sbd.core.driver_data;
+	u64 res;
+
+	dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__);
+
+	res = lv1_storage_send_device_command(dev->sbd.dev_id,
+					      LV1_STORAGE_ATA_HDDOUT, 0, 0, 0,
+					      0, &dev->tag);
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%lx\n",
+			__func__, __LINE__, res);
+		end_request(req, 0);
+		return 0;
+	}
+
+	priv->req = req;
+	return 1;
+}
+
+static void ps3disk_do_request(struct ps3_storage_device *dev,
+			       struct request_queue *q)
+{
+	struct request *req;
+
+	dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
+
+	while ((req = elv_next_request(q))) {
+		if (blk_fs_request(req)) {
+			if (ps3disk_submit_request_sg(dev, req))
+				break;
+		} else if (req->cmd_type == REQ_TYPE_FLUSH) {
+			if (ps3disk_submit_flush_request(dev, req))
+				break;
+		} else {
+			blk_dump_rq_flags(req, DEVICE_NAME " bad request");
+			end_request(req, 0);
+			continue;
+		}
+	}
+}
+
+static void ps3disk_request(struct request_queue *q)
+{
+	struct ps3_storage_device *dev = q->queuedata;
+	struct ps3disk_private *priv = dev->sbd.core.driver_data;
+
+	if (priv->req) {
+		dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__);
+		return;
+	}
+
+	ps3disk_do_request(dev, q);
+}
+
+static irqreturn_t ps3disk_interrupt(int irq, void *data)
+{
+	struct ps3_storage_device *dev = data;
+	struct ps3disk_private *priv;
+	struct request *req;
+	int res, read, uptodate;
+	u64 tag, status;
+	unsigned long num_sectors;
+	const char *op;
+
+	res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
+
+	if (tag != dev->tag)
+		dev_err(&dev->sbd.core,
+			"%s:%u: tag mismatch, got %lx, expected %lx\n",
+			__func__, __LINE__, tag, dev->tag);
+
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+			__func__, __LINE__, res, status);
+		return IRQ_HANDLED;
+	}
+
+	priv = dev->sbd.core.driver_data;
+	req = priv->req;
+	if (!req) {
+		dev_dbg(&dev->sbd.core,
+			"%s:%u non-block layer request completed\n", __func__,
+			__LINE__);
+		dev->lv1_status = status;
+		complete(&dev->done);
+		return IRQ_HANDLED;
+	}
+
+	if (req->cmd_type == REQ_TYPE_FLUSH) {
+		read = 0;
+		num_sectors = req->hard_cur_sectors;
+		op = "flush";
+	} else {
+		read = !rq_data_dir(req);
+		num_sectors = req->nr_sectors;
+		op = read ? "read" : "write";
+	}
+	if (status) {
+		dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
+			__LINE__, op, status);
+		uptodate = 0;
+	} else {
+		dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__,
+			__LINE__, op);
+		uptodate = 1;
+		if (read)
+			ps3disk_scatter_gather(dev, req, 0);
+	}
+
+	spin_lock(&priv->lock);
+	if (!end_that_request_first(req, uptodate, num_sectors)) {
+		add_disk_randomness(req->rq_disk);
+		blkdev_dequeue_request(req);
+		end_that_request_last(req, uptodate);
+	}
+	priv->req = NULL;
+	ps3disk_do_request(dev, priv->queue);
+	spin_unlock(&priv->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int ps3disk_sync_cache(struct ps3_storage_device *dev)
+{
+	u64 res;
+
+	dev_dbg(&dev->sbd.core, "%s:%u: sync cache\n", __func__, __LINE__);
+
+	res = ps3stor_send_command(dev, LV1_STORAGE_ATA_HDDOUT, 0, 0, 0, 0);
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%lx\n",
+			__func__, __LINE__, res);
+		return -EIO;
+	}
+	return 0;
+}
+
+
+/* ATA helpers copied from drivers/ata/libata-core.c */
+
+static void swap_buf_le16(u16 *buf, unsigned int buf_words)
+{
+#ifdef __BIG_ENDIAN
+	unsigned int i;
+
+	for (i = 0; i < buf_words; i++)
+		buf[i] = le16_to_cpu(buf[i]);
+#endif /* __BIG_ENDIAN */
+}
+
+static u64 ata_id_n_sectors(const u16 *id)
+{
+	if (ata_id_has_lba(id)) {
+		if (ata_id_has_lba48(id))
+			return ata_id_u64(id, 100);
+		else
+			return ata_id_u32(id, 60);
+	} else {
+		if (ata_id_current_chs_valid(id))
+			return ata_id_u32(id, 57);
+		else
+			return id[1] * id[3] * id[6];
+	}
+}
+
+static void ata_id_string(const u16 *id, unsigned char *s, unsigned int ofs,
+			  unsigned int len)
+{
+	unsigned int c;
+
+	while (len > 0) {
+		c = id[ofs] >> 8;
+		*s = c;
+		s++;
+
+		c = id[ofs] & 0xff;
+		*s = c;
+		s++;
+
+		ofs++;
+		len -= 2;
+	}
+}
+
+static void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs,
+			    unsigned int len)
+{
+	unsigned char *p;
+
+	WARN_ON(!(len & 1));
+
+	ata_id_string(id, s, ofs, len - 1);
+
+	p = s + strnlen(s, len - 1);
+	while (p > s && p[-1] == ' ')
+		p--;
+	*p = '\0';
+}
+
+static int ps3disk_identify(struct ps3_storage_device *dev)
+{
+	struct ps3disk_private *priv = dev->sbd.core.driver_data;
+	struct lv1_ata_cmnd_block ata_cmnd;
+	u16 *id = dev->bounce_buf;
+	u64 res;
+
+	dev_dbg(&dev->sbd.core, "%s:%u: identify disk\n", __func__, __LINE__);
+
+	memset(&ata_cmnd, 0, sizeof(struct lv1_ata_cmnd_block));
+	ata_cmnd.command = ATA_CMD_ID_ATA;
+	ata_cmnd.sector_count = 1;
+	ata_cmnd.size = ata_cmnd.arglen = ATA_ID_WORDS * 2;
+	ata_cmnd.buffer = dev->bounce_lpar;
+	ata_cmnd.proto = PIO_DATA_IN_PROTO;
+	ata_cmnd.in_out = DIR_READ;
+
+	res = ps3stor_send_command(dev, LV1_STORAGE_SEND_ATA_COMMAND,
+				   ps3_mm_phys_to_lpar(__pa(&ata_cmnd)),
+				   sizeof(ata_cmnd), ata_cmnd.buffer,
+				   ata_cmnd.arglen);
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: identify disk failed 0x%lx\n",
+			__func__, __LINE__, res);
+		return -EIO;
+	}
+
+	swap_buf_le16(id, ATA_ID_WORDS);
+
+	/* All we're interested in are raw capacity and model name */
+	priv->raw_capacity = ata_id_n_sectors(id);
+	ata_id_c_string(id, priv->model, ATA_ID_PROD, sizeof(priv->model));
+	return 0;
+}
+
+static void ps3disk_prepare_flush(struct request_queue *q, struct request *req)
+{
+	struct ps3_storage_device *dev = q->queuedata;
+
+	dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
+
+	memset(req->cmd, 0, sizeof(req->cmd));
+	req->cmd_type = REQ_TYPE_FLUSH;
+}
+
+static int ps3disk_issue_flush(struct request_queue *q, struct gendisk *gendisk,
+			       sector_t *sector)
+{
+	struct ps3_storage_device *dev = q->queuedata;
+	struct request *req;
+	int res;
+
+	dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
+
+	req = blk_get_request(q, WRITE, __GFP_WAIT);
+	ps3disk_prepare_flush(q, req);
+	res = blk_execute_rq(q, gendisk, req, 0);
+	if (res)
+		dev_err(&dev->sbd.core, "%s:%u: flush request failed %d\n",
+			__func__, __LINE__, res);
+	blk_put_request(req);
+	return res;
+}
+
+
+static unsigned long ps3disk_mask;
+
+static DEFINE_MUTEX(ps3disk_mask_mutex);
+
+static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
+{
+	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+	struct ps3disk_private *priv;
+	int error;
+	unsigned int devidx;
+	struct request_queue *queue;
+	struct gendisk *gendisk;
+
+	if (dev->blk_size < 512) {
+		dev_err(&dev->sbd.core,
+			"%s:%u: cannot handle block size %lu\n", __func__,
+			__LINE__, dev->blk_size);
+		return -EINVAL;
+	}
+
+	BUILD_BUG_ON(PS3DISK_MAX_DISKS > BITS_PER_LONG);
+	mutex_lock(&ps3disk_mask_mutex);
+	devidx = find_first_zero_bit(&ps3disk_mask, PS3DISK_MAX_DISKS);
+	if (devidx >= PS3DISK_MAX_DISKS) {
+		dev_err(&dev->sbd.core, "%s:%u: Too many disks\n", __func__,
+			__LINE__);
+		mutex_unlock(&ps3disk_mask_mutex);
+		return -ENOSPC;
+	}
+	__set_bit(devidx, &ps3disk_mask);
+	mutex_unlock(&ps3disk_mask_mutex);
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		error = -ENOMEM;
+		goto fail;
+	}
+
+	dev->sbd.core.driver_data = priv;
+	spin_lock_init(&priv->lock);
+
+	dev->bounce_size = BOUNCE_SIZE;
+	dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA);
+	if (!dev->bounce_buf) {
+		error = -ENOMEM;
+		goto fail_free_priv;
+	}
+
+	error = ps3stor_setup(dev, ps3disk_interrupt);
+	if (error)
+		goto fail_free_bounce;
+
+	ps3disk_identify(dev);
+
+	queue = blk_init_queue(ps3disk_request, &priv->lock);
+	if (!queue) {
+		dev_err(&dev->sbd.core, "%s:%u: blk_init_queue failed\n",
+			__func__, __LINE__);
+		error = -ENOMEM;
+		goto fail_teardown;
+	}
+
+	priv->queue = queue;
+	queue->queuedata = dev;
+
+	blk_queue_bounce_limit(queue, BLK_BOUNCE_HIGH);
+
+	blk_queue_max_sectors(queue, dev->bounce_size >> 9);
+	blk_queue_segment_boundary(queue, -1UL);
+	blk_queue_dma_alignment(queue, dev->blk_size-1);
+	blk_queue_hardsect_size(queue, dev->blk_size);
+
+	blk_queue_issue_flush_fn(queue, ps3disk_issue_flush);
+	blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN_FLUSH,
+			  ps3disk_prepare_flush);
+
+	blk_queue_max_phys_segments(queue, -1);
+	blk_queue_max_hw_segments(queue, -1);
+	blk_queue_max_segment_size(queue, dev->bounce_size);
+
+	gendisk = alloc_disk(PS3DISK_MINORS);
+	if (!gendisk) {
+		dev_err(&dev->sbd.core, "%s:%u: alloc_disk failed\n", __func__,
+			__LINE__);
+		error = -ENOMEM;
+		goto fail_cleanup_queue;
+	}
+
+	priv->gendisk = gendisk;
+	gendisk->major = ps3disk_major;
+	gendisk->first_minor = devidx * PS3DISK_MINORS;
+	gendisk->fops = &ps3disk_fops;
+	gendisk->queue = queue;
+	gendisk->private_data = dev;
+	gendisk->driverfs_dev = &dev->sbd.core;
+	snprintf(gendisk->disk_name, sizeof(gendisk->disk_name), PS3DISK_NAME,
+		 devidx+'a');
+	priv->blocking_factor = dev->blk_size >> 9;
+	set_capacity(gendisk,
+		     dev->regions[dev->region_idx].size*priv->blocking_factor);
+
+	dev_info(&dev->sbd.core,
+		 "%s is a %s (%lu MiB total, %lu MiB for OtherOS)\n",
+		 gendisk->disk_name, priv->model, priv->raw_capacity >> 11,
+		 get_capacity(gendisk) >> 11);
+
+	add_disk(gendisk);
+	return 0;
+
+fail_cleanup_queue:
+	blk_cleanup_queue(queue);
+fail_teardown:
+	ps3stor_teardown(dev);
+fail_free_bounce:
+	kfree(dev->bounce_buf);
+fail_free_priv:
+	kfree(priv);
+	dev->sbd.core.driver_data = NULL;
+fail:
+	mutex_lock(&ps3disk_mask_mutex);
+	__clear_bit(devidx, &ps3disk_mask);
+	mutex_unlock(&ps3disk_mask_mutex);
+	return error;
+}
+
+static int ps3disk_remove(struct ps3_system_bus_device *_dev)
+{
+	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+	struct ps3disk_private *priv = dev->sbd.core.driver_data;
+
+	mutex_lock(&ps3disk_mask_mutex);
+	__clear_bit(priv->gendisk->first_minor / PS3DISK_MINORS,
+		    &ps3disk_mask);
+	mutex_unlock(&ps3disk_mask_mutex);
+	del_gendisk(priv->gendisk);
+	blk_cleanup_queue(priv->queue);
+	put_disk(priv->gendisk);
+	dev_notice(&dev->sbd.core, "Synchronizing disk cache\n");
+	ps3disk_sync_cache(dev);
+	ps3stor_teardown(dev);
+	kfree(dev->bounce_buf);
+	kfree(priv);
+	dev->sbd.core.driver_data = NULL;
+	return 0;
+}
+
+static struct ps3_system_bus_driver ps3disk = {
+	.match_id	= PS3_MATCH_ID_STOR_DISK,
+	.core.name	= DEVICE_NAME,
+	.core.owner	= THIS_MODULE,
+	.probe		= ps3disk_probe,
+	.remove		= ps3disk_remove,
+	.shutdown	= ps3disk_remove,
+};
+
+
+static int __init ps3disk_init(void)
+{
+	int error;
+
+	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+		return -ENODEV;
+
+	error = register_blkdev(0, DEVICE_NAME);
+	if (error <= 0) {
+		printk(KERN_ERR "%s:%u: register_blkdev failed %d\n", __func__,
+		       __LINE__, error);
+		return error;
+	}
+	ps3disk_major = error;
+
+	pr_info("%s:%u: registered block device major %d\n", __func__,
+		__LINE__, ps3disk_major);
+
+	error = ps3_system_bus_driver_register(&ps3disk);
+	if (error)
+		unregister_blkdev(ps3disk_major, DEVICE_NAME);
+
+	return error;
+}
+
+static void __exit ps3disk_exit(void)
+{
+	ps3_system_bus_driver_unregister(&ps3disk);
+	unregister_blkdev(ps3disk_major, DEVICE_NAME);
+}
+
+module_init(ps3disk_init);
+module_exit(ps3disk_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS3 Disk Storage Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_DISK);
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index a1512da..701ea77 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -264,7 +264,7 @@
  * 19-JAN-1998  Richard Gooch <rgooch@atnf.csiro.au>  Added devfs support
  *
  */
-static int rd_make_request(request_queue_t *q, struct bio *bio)
+static int rd_make_request(struct request_queue *q, struct bio *bio)
 {
 	struct block_device *bdev = bio->bi_bdev;
 	struct address_space * mapping = bdev->bd_inode->i_mapping;
@@ -287,10 +287,10 @@
 	if (ret)
 		goto fail;
 
-	bio_endio(bio, bio->bi_size, 0);
+	bio_endio(bio, 0);
 	return 0;
 fail:
-	bio_io_error(bio, bio->bi_size);
+	bio_io_error(bio);
 	return 0;
 } 
 
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 0f5e3ca..317a790 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -45,8 +45,6 @@
 struct vdc_port {
 	struct vio_driver_state	vio;
 
-	struct vdc		*vp;
-
 	struct gendisk		*disk;
 
 	struct vdc_completion	*cmp;
@@ -66,14 +64,11 @@
 	u64			operations;
 	u32			vdisk_size;
 	u8			vdisk_type;
-	u8			dev_no;
 
 	char			disk_name[32];
 
 	struct vio_disk_geom	geom;
 	struct vio_disk_vtoc	label;
-
-	struct list_head	list;
 };
 
 static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
@@ -81,15 +76,6 @@
 	return container_of(vio, struct vdc_port, vio);
 }
 
-struct vdc {
-	/* Protects prot_list.  */
-	spinlock_t		lock;
-
-	struct vio_dev		*dev;
-
-	struct list_head	port_list;
-};
-
 /* Ordered from largest major to lowest */
 static struct vio_version vdc_versions[] = {
 	{ .major = 1, .minor = 0 },
@@ -431,7 +417,7 @@
 	desc->req_id = port->req_id;
 	desc->operation = op;
 	if (port->vdisk_type == VD_DISK_TYPE_DISK) {
-		desc->slice = 2;
+		desc->slice = 0xff;
 	} else {
 		desc->slice = 0;
 	}
@@ -458,7 +444,7 @@
 	return err;
 }
 
-static void do_vdc_request(request_queue_t *q)
+static void do_vdc_request(struct request_queue *q)
 {
 	while (1) {
 		struct request *req = elv_next_request(q);
@@ -716,7 +702,7 @@
 	blk_queue_max_phys_segments(q, port->ring_cookies);
 	blk_queue_max_sectors(q, port->max_xfer_size);
 	g->major = vdc_major;
-	g->first_minor = port->dev_no << PARTITION_SHIFT;
+	g->first_minor = port->vio.vdev->dev_no << PARTITION_SHIFT;
 	strcpy(g->disk_name, port->disk_name);
 
 	g->fops = &vdc_fops;
@@ -747,32 +733,29 @@
 	.handshake_complete	= vdc_handshake_complete,
 };
 
+static void print_version(void)
+{
+	static int version_printed;
+
+	if (version_printed++ == 0)
+		printk(KERN_INFO "%s", version);
+}
+
 static int __devinit vdc_port_probe(struct vio_dev *vdev,
 				    const struct vio_device_id *id)
 {
 	struct mdesc_handle *hp;
 	struct vdc_port *port;
-	unsigned long flags;
-	struct vdc *vp;
-	const u64 *port_id;
 	int err;
 
-	vp = dev_get_drvdata(vdev->dev.parent);
-	if (!vp) {
-		printk(KERN_ERR PFX "Cannot find port parent vdc.\n");
-		return -ENODEV;
-	}
+	print_version();
 
 	hp = mdesc_grab();
 
-	port_id = mdesc_get_property(hp, vdev->mp, "id", NULL);
 	err = -ENODEV;
-	if (!port_id) {
-		printk(KERN_ERR PFX "Port lacks id property.\n");
-		goto err_out_release_mdesc;
-	}
-	if ((*port_id << PARTITION_SHIFT) & ~(u64)MINORMASK) {
-		printk(KERN_ERR PFX "Port id [%lu] too large.\n", *port_id);
+	if ((vdev->dev_no << PARTITION_SHIFT) & ~(u64)MINORMASK) {
+		printk(KERN_ERR PFX "Port id [%lu] too large.\n",
+		       vdev->dev_no);
 		goto err_out_release_mdesc;
 	}
 
@@ -783,17 +766,14 @@
 		goto err_out_release_mdesc;
 	}
 
-	port->vp = vp;
-	port->dev_no = *port_id;
-
-	if (port->dev_no >= 26)
+	if (vdev->dev_no >= 26)
 		snprintf(port->disk_name, sizeof(port->disk_name),
 			 VDCBLK_NAME "%c%c",
-			 'a' + (port->dev_no / 26) - 1,
-			 'a' + (port->dev_no % 26));
+			 'a' + ((int)vdev->dev_no / 26) - 1,
+			 'a' + ((int)vdev->dev_no % 26));
 	else
 		snprintf(port->disk_name, sizeof(port->disk_name),
-			 VDCBLK_NAME "%c", 'a' + (port->dev_no % 26));
+			 VDCBLK_NAME "%c", 'a' + ((int)vdev->dev_no % 26));
 
 	err = vio_driver_init(&port->vio, vdev, VDEV_DISK,
 			      vdc_versions, ARRAY_SIZE(vdc_versions),
@@ -818,12 +798,6 @@
 	if (err)
 		goto err_out_free_tx_ring;
 
-	INIT_LIST_HEAD(&port->list);
-
-	spin_lock_irqsave(&vp->lock, flags);
-	list_add(&port->list, &vp->port_list);
-	spin_unlock_irqrestore(&vp->lock, flags);
-
 	dev_set_drvdata(&vdev->dev, port);
 
 	mdesc_release(hp);
@@ -867,7 +841,7 @@
 	},
 	{},
 };
-MODULE_DEVICE_TABLE(vio, vdc_match);
+MODULE_DEVICE_TABLE(vio, vdc_port_match);
 
 static struct vio_driver vdc_port_driver = {
 	.id_table	= vdc_port_match,
@@ -879,58 +853,6 @@
 	}
 };
 
-static int __devinit vdc_probe(struct vio_dev *vdev,
-			       const struct vio_device_id *id)
-{
-	static int vdc_version_printed;
-	struct vdc *vp;
-
-	if (vdc_version_printed++ == 0)
-		printk(KERN_INFO "%s", version);
-
-	vp = kzalloc(sizeof(struct vdc), GFP_KERNEL);
-	if (!vp)
-		return -ENOMEM;
-
-	spin_lock_init(&vp->lock);
-	vp->dev = vdev;
-	INIT_LIST_HEAD(&vp->port_list);
-
-	dev_set_drvdata(&vdev->dev, vp);
-
-	return 0;
-}
-
-static int vdc_remove(struct vio_dev *vdev)
-{
-
-	struct vdc *vp = dev_get_drvdata(&vdev->dev);
-
-	if (vp) {
-		kfree(vp);
-		dev_set_drvdata(&vdev->dev, NULL);
-	}
-	return 0;
-}
-
-static struct vio_device_id vdc_match[] = {
-	{
-		.type = "block",
-	},
-	{},
-};
-MODULE_DEVICE_TABLE(vio, vdc_match);
-
-static struct vio_driver vdc_driver = {
-	.id_table	= vdc_match,
-	.probe		= vdc_probe,
-	.remove		= vdc_remove,
-	.driver		= {
-		.name	= "vdc",
-		.owner	= THIS_MODULE,
-	}
-};
-
 static int __init vdc_init(void)
 {
 	int err;
@@ -940,19 +862,13 @@
 		goto out_err;
 
 	vdc_major = err;
-	err = vio_register_driver(&vdc_driver);
-	if (err)
-		goto out_unregister_blkdev;
 
 	err = vio_register_driver(&vdc_port_driver);
 	if (err)
-		goto out_unregister_vdc;
+		goto out_unregister_blkdev;
 
 	return 0;
 
-out_unregister_vdc:
-	vio_unregister_driver(&vdc_driver);
-
 out_unregister_blkdev:
 	unregister_blkdev(vdc_major, VDCBLK_NAME);
 	vdc_major = 0;
@@ -964,7 +880,6 @@
 static void __exit vdc_exit(void)
 {
 	vio_unregister_driver(&vdc_port_driver);
-	vio_unregister_driver(&vdc_driver);
 	unregister_blkdev(vdc_major, VDCBLK_NAME);
 }
 
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index 1a65979..b4e462f 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -225,7 +225,7 @@
 static void swim3_select(struct floppy_state *fs, int sel);
 static void swim3_action(struct floppy_state *fs, int action);
 static int swim3_readbit(struct floppy_state *fs, int bit);
-static void do_fd_request(request_queue_t * q);
+static void do_fd_request(struct request_queue * q);
 static void start_request(struct floppy_state *fs);
 static void set_timeout(struct floppy_state *fs, int nticks,
 			void (*proc)(unsigned long));
@@ -290,7 +290,7 @@
 	return (stat & DATA) == 0;
 }
 
-static void do_fd_request(request_queue_t * q)
+static void do_fd_request(struct request_queue * q)
 {
 	int i;
 	for(i=0;i<floppy_count;i++)
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 54509eb..402209f 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -278,7 +278,7 @@
 	unsigned int			state;
 	u32				fw_ver;
 
-	request_queue_t			*oob_q;
+	struct request_queue		*oob_q;
 	unsigned int			n_oob;
 
 	unsigned int			hw_sg_used;
@@ -287,7 +287,7 @@
 
 	unsigned int			wait_q_prod;
 	unsigned int			wait_q_cons;
-	request_queue_t			*wait_q[CARM_MAX_WAIT_Q];
+	struct request_queue		*wait_q[CARM_MAX_WAIT_Q];
 
 	unsigned int			n_msgs;
 	u64				msg_alloc;
@@ -756,7 +756,7 @@
 	assert(rc == 0);
 }
 
-static inline void carm_push_q (struct carm_host *host, request_queue_t *q)
+static inline void carm_push_q (struct carm_host *host, struct request_queue *q)
 {
 	unsigned int idx = host->wait_q_prod % CARM_MAX_WAIT_Q;
 
@@ -768,7 +768,7 @@
 	BUG_ON(host->wait_q_prod == host->wait_q_cons); /* overrun */
 }
 
-static inline request_queue_t *carm_pop_q(struct carm_host *host)
+static inline struct request_queue *carm_pop_q(struct carm_host *host)
 {
 	unsigned int idx;
 
@@ -783,7 +783,7 @@
 
 static inline void carm_round_robin(struct carm_host *host)
 {
-	request_queue_t *q = carm_pop_q(host);
+	struct request_queue *q = carm_pop_q(host);
 	if (q) {
 		blk_start_queue(q);
 		VPRINTK("STARTED QUEUE %p\n", q);
@@ -802,7 +802,7 @@
 	}
 }
 
-static void carm_oob_rq_fn(request_queue_t *q)
+static void carm_oob_rq_fn(struct request_queue *q)
 {
 	struct carm_host *host = q->queuedata;
 	struct carm_request *crq;
@@ -833,7 +833,7 @@
 	}
 }
 
-static void carm_rq_fn(request_queue_t *q)
+static void carm_rq_fn(struct request_queue *q)
 {
 	struct carm_port *port = q->queuedata;
 	struct carm_host *host = port->host;
@@ -1494,7 +1494,7 @@
 
 	for (i = 0; i < CARM_MAX_PORTS; i++) {
 		struct gendisk *disk;
-		request_queue_t *q;
+		struct request_queue *q;
 		struct carm_port *port;
 
 		port = &host->port[i];
@@ -1538,7 +1538,7 @@
 	for (i = 0; i < CARM_MAX_PORTS; i++) {
 		struct gendisk *disk = host->port[i].disk;
 		if (disk) {
-			request_queue_t *q = disk->queue;
+			struct request_queue *q = disk->queue;
 
 			if (disk->flags & GENHD_FL_UP)
 				del_gendisk(disk);
@@ -1571,7 +1571,7 @@
 	struct carm_host *host;
 	unsigned int pci_dac;
 	int rc;
-	request_queue_t *q;
+	struct request_queue *q;
 	unsigned int i;
 
 	if (!printed_version++)
@@ -1608,7 +1608,7 @@
 	}
 #endif
 
-	host = kmalloc(sizeof(*host), GFP_KERNEL);
+	host = kzalloc(sizeof(*host), GFP_KERNEL);
 	if (!host) {
 		printk(KERN_ERR DRV_NAME "(%s): memory alloc failure\n",
 		       pci_name(pdev));
@@ -1616,7 +1616,6 @@
 		goto err_out_regions;
 	}
 
-	memset(host, 0, sizeof(*host));
 	host->pdev = pdev;
 	host->flags = pci_dac ? FL_DAC : 0;
 	spin_lock_init(&host->lock);
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index 8b13d7d..c57dd2b 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -503,7 +503,7 @@
 {
 	struct list_head *p;
 	struct ub_lun *lun;
-	request_queue_t *q;
+	struct request_queue *q;
 
 	while (!list_empty(&sc->luns)) {
 		p = sc->luns.next;
@@ -619,7 +619,7 @@
  * The request function is our main entry point
  */
 
-static void ub_request_fn(request_queue_t *q)
+static void ub_request_fn(struct request_queue *q)
 {
 	struct ub_lun *lun = q->queuedata;
 	struct request *rq;
@@ -2273,7 +2273,7 @@
 static int ub_probe_lun(struct ub_dev *sc, int lnum)
 {
 	struct ub_lun *lun;
-	request_queue_t *q;
+	struct request_queue *q;
 	struct gendisk *disk;
 	int rc;
 
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index dec74bd..99806f9 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -52,7 +52,7 @@
 #include <linux/fcntl.h>        /* O_ACCMODE */
 #include <linux/hdreg.h>  /* HDIO_GETGEO */
 
-#include <linux/umem.h>
+#include "umem.h"
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -67,9 +67,10 @@
  * Version Information
  */
 
-#define DRIVER_VERSION "v2.3"
-#define DRIVER_AUTHOR "San Mehat, Johannes Erdfelt, NeilBrown"
-#define DRIVER_DESC "Micro Memory(tm) PCI memory board block driver"
+#define DRIVER_NAME	"umem"
+#define DRIVER_VERSION	"v2.3"
+#define DRIVER_AUTHOR	"San Mehat, Johannes Erdfelt, NeilBrown"
+#define DRIVER_DESC	"Micro Memory(tm) PCI memory board block driver"
 
 static int debug;
 /* #define HW_TRACE(x)     writeb(x,cards[0].csr_remap + MEMCTRLSTATUS_MAGIC) */
@@ -97,15 +98,9 @@
 #include <linux/blkpg.h>
 
 struct cardinfo {
-	int		card_number;
 	struct pci_dev	*dev;
 
-	int		irq;
-
-	unsigned long	csr_base;
 	unsigned char	__iomem *csr_remap;
-	unsigned long	csr_len;
-	unsigned int	win_size; /* PCI window size */
 	unsigned int	mm_size;  /* size in kbytes */
 
 	unsigned int	init_size; /* initial segment, in sectors,
@@ -113,14 +108,17 @@
 				    * have been written
 				    */
 	struct bio	*bio, *currentbio, **biotail;
+	int		current_idx;
+	sector_t	current_sector;
 
-	request_queue_t *queue;
+	struct request_queue *queue;
 
 	struct mm_page {
 		dma_addr_t		page_dma;
 		struct mm_dma_desc	*desc;
 		int	 		cnt, headcnt;
 		struct bio		*bio, **biotail;
+		int			idx;
 	} mm_pages[2];
 #define DESC_PER_PAGE ((PAGE_SIZE*2)/sizeof(struct mm_dma_desc))
 
@@ -233,7 +231,7 @@
 */
 static void dump_dmastat(struct cardinfo *card, unsigned int dmastat)
 {
-	printk(KERN_DEBUG "MM%d*: DMAstat - ", card->card_number);
+	dev_printk(KERN_DEBUG, &card->dev->dev, "DMAstat - ");
 	if (dmastat & DMASCR_ANY_ERR)
 		printk("ANY_ERR ");
 	if (dmastat & DMASCR_MBE_ERR)
@@ -295,7 +293,7 @@
 	desc->control_bits &= ~cpu_to_le32(DMASCR_CHAIN_EN);
 	desc->sem_control_bits = desc->control_bits;
 
-			       
+
 	if (debug & DEBUG_LED_ON_TRANSFER)
 		set_led(card, LED_REMOVE, LED_ON);
 
@@ -329,7 +327,7 @@
 
 static void activate(struct cardinfo *card)
 {
-	/* if No page is Active, and Ready is 
+	/* if No page is Active, and Ready is
 	 * not empty, then switch Ready page
 	 * to active and start IO.
 	 * Then add any bh's that are available to Ready
@@ -357,7 +355,7 @@
 	page->biotail = & page->bio;
 }
 
-static void mm_unplug_device(request_queue_t *q)
+static void mm_unplug_device(struct request_queue *q)
 {
 	struct cardinfo *card = q->queuedata;
 	unsigned long flags;
@@ -368,7 +366,7 @@
 	spin_unlock_irqrestore(&card->lock, flags);
 }
 
-/* 
+/*
  * If there is room on Ready page, take
  * one bh off list and add it.
  * return 1 if there was room, else 0.
@@ -380,12 +378,16 @@
 	dma_addr_t dma_handle;
 	int offset;
 	struct bio *bio;
+	struct bio_vec *vec;
+	int idx;
 	int rw;
 	int len;
 
 	bio = card->currentbio;
 	if (!bio && card->bio) {
 		card->currentbio = card->bio;
+		card->current_idx = card->bio->bi_idx;
+		card->current_sector = card->bio->bi_sector;
 		card->bio = card->bio->bi_next;
 		if (card->bio == NULL)
 			card->biotail = &card->bio;
@@ -394,15 +396,17 @@
 	}
 	if (!bio)
 		return 0;
+	idx = card->current_idx;
 
 	rw = bio_rw(bio);
 	if (card->mm_pages[card->Ready].cnt >= DESC_PER_PAGE)
 		return 0;
 
-	len = bio_iovec(bio)->bv_len;
-	dma_handle = pci_map_page(card->dev, 
-				  bio_page(bio),
-				  bio_offset(bio),
+	vec = bio_iovec_idx(bio, idx);
+	len = vec->bv_len;
+	dma_handle = pci_map_page(card->dev,
+				  vec->bv_page,
+				  vec->bv_offset,
 				  len,
 				  (rw==READ) ?
 				  PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
@@ -410,6 +414,8 @@
 	p = &card->mm_pages[card->Ready];
 	desc = &p->desc[p->cnt];
 	p->cnt++;
+	if (p->bio == NULL)
+		p->idx = idx;
 	if ((p->biotail) != &bio->bi_next) {
 		*(p->biotail) = bio;
 		p->biotail = &(bio->bi_next);
@@ -419,7 +425,7 @@
 	desc->data_dma_handle = dma_handle;
 
 	desc->pci_addr = cpu_to_le64((u64)desc->data_dma_handle);
-	desc->local_addr= cpu_to_le64(bio->bi_sector << 9);
+	desc->local_addr = cpu_to_le64(card->current_sector << 9);
 	desc->transfer_size = cpu_to_le32(len);
 	offset = ( ((char*)&desc->sem_control_bits) - ((char*)p->desc));
 	desc->sem_addr = cpu_to_le64((u64)(p->page_dma+offset));
@@ -435,10 +441,10 @@
 		desc->control_bits |= cpu_to_le32(DMASCR_TRANSFER_READ);
 	desc->sem_control_bits = desc->control_bits;
 
-	bio->bi_sector += (len>>9);
-	bio->bi_size -= len;
-	bio->bi_idx++;
-	if (bio->bi_idx >= bio->bi_vcnt) 
+	card->current_sector += (len >> 9);
+	idx++;
+	card->current_idx = idx;
+	if (idx >= bio->bi_vcnt)
 		card->currentbio = NULL;
 
 	return 1;
@@ -461,7 +467,7 @@
 	if (card->Active < 0)
 		goto out_unlock;
 	page = &card->mm_pages[card->Active];
-	
+
 	while (page->headcnt < page->cnt) {
 		struct bio *bio = page->bio;
 		struct mm_dma_desc *desc = &page->desc[page->headcnt];
@@ -471,32 +477,34 @@
 
 		if (!(control & DMASCR_DMA_COMPLETE)) {
 			control = dma_status;
-			last=1; 
+			last=1;
 		}
 		page->headcnt++;
-		idx = bio->bi_phys_segments;
-		bio->bi_phys_segments++;
-		if (bio->bi_phys_segments >= bio->bi_vcnt)
+		idx = page->idx;
+		page->idx++;
+		if (page->idx >= bio->bi_vcnt) {
 			page->bio = bio->bi_next;
+			page->idx = page->bio->bi_idx;
+		}
 
-		pci_unmap_page(card->dev, desc->data_dma_handle, 
+		pci_unmap_page(card->dev, desc->data_dma_handle,
 			       bio_iovec_idx(bio,idx)->bv_len,
 				 (control& DMASCR_TRANSFER_READ) ?
 				PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
 		if (control & DMASCR_HARD_ERROR) {
 			/* error */
 			clear_bit(BIO_UPTODATE, &bio->bi_flags);
-			printk(KERN_WARNING "MM%d: I/O error on sector %d/%d\n",
-			       card->card_number, 
-			       le32_to_cpu(desc->local_addr)>>9,
-			       le32_to_cpu(desc->transfer_size));
+			dev_printk(KERN_WARNING, &card->dev->dev,
+				"I/O error on sector %d/%d\n",
+				le32_to_cpu(desc->local_addr)>>9,
+				le32_to_cpu(desc->transfer_size));
 			dump_dmastat(card, control);
 		} else if (test_bit(BIO_RW, &bio->bi_rw) &&
 			   le32_to_cpu(desc->local_addr)>>9 == card->init_size) {
 			card->init_size += le32_to_cpu(desc->transfer_size)>>9;
 			if (card->init_size>>1 >= card->mm_size) {
-				printk(KERN_INFO "MM%d: memory now initialised\n",
-				       card->card_number);
+				dev_printk(KERN_INFO, &card->dev->dev,
+					"memory now initialised\n");
 				set_userbit(card, MEMORY_INITIALIZED, 1);
 			}
 		}
@@ -532,7 +540,7 @@
 
 		return_bio = bio->bi_next;
 		bio->bi_next = NULL;
-		bio_endio(bio, bio->bi_size, 0);
+		bio_endio(bio, 0);
 	}
 }
 
@@ -541,13 +549,12 @@
 --                              mm_make_request
 -----------------------------------------------------------------------------------
 */
-static int mm_make_request(request_queue_t *q, struct bio *bio)
+static int mm_make_request(struct request_queue *q, struct bio *bio)
 {
 	struct cardinfo *card = q->queuedata;
 	pr_debug("mm_make_request %llu %u\n",
 		 (unsigned long long)bio->bi_sector, bio->bi_size);
 
-	bio->bi_phys_segments = bio->bi_idx; /* count of completed segments*/
 	spin_lock_irq(&card->lock);
 	*card->biotail = bio;
 	bio->bi_next = NULL;
@@ -585,7 +592,7 @@
 	else
 		writeb((DMASCR_DMA_COMPLETE|DMASCR_CHAIN_COMPLETE) >> 16,
 		       card->csr_remap+ DMA_STATUS_CTRL + 2);
-	
+
 	/* log errors and clear interrupt status */
 	if (dma_status & DMASCR_ANY_ERR) {
 		unsigned int	data_log1, data_log2;
@@ -606,46 +613,51 @@
 		dump_dmastat(card, dma_status);
 
 		if (stat & 0x01)
-			printk(KERN_ERR "MM%d*: Memory access error detected (err count %d)\n",
-				card->card_number, count);
+			dev_printk(KERN_ERR, &card->dev->dev,
+				"Memory access error detected (err count %d)\n",
+				count);
 		if (stat & 0x02)
-			printk(KERN_ERR "MM%d*: Multi-bit EDC error\n",
-				card->card_number);
+			dev_printk(KERN_ERR, &card->dev->dev,
+				"Multi-bit EDC error\n");
 
-		printk(KERN_ERR "MM%d*: Fault Address 0x%02x%08x, Fault Data 0x%08x%08x\n",
-			card->card_number, addr_log2, addr_log1, data_log2, data_log1);
-		printk(KERN_ERR "MM%d*: Fault Check 0x%02x, Fault Syndrome 0x%02x\n",
-			card->card_number, check, syndrome);
+		dev_printk(KERN_ERR, &card->dev->dev,
+			"Fault Address 0x%02x%08x, Fault Data 0x%08x%08x\n",
+			addr_log2, addr_log1, data_log2, data_log1);
+		dev_printk(KERN_ERR, &card->dev->dev,
+			"Fault Check 0x%02x, Fault Syndrome 0x%02x\n",
+			check, syndrome);
 
 		writeb(0, card->csr_remap + ERROR_COUNT);
 	}
 
 	if (dma_status & DMASCR_PARITY_ERR_REP) {
-		printk(KERN_ERR "MM%d*: PARITY ERROR REPORTED\n", card->card_number);
+		dev_printk(KERN_ERR, &card->dev->dev,
+			"PARITY ERROR REPORTED\n");
 		pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);
 		pci_write_config_word(card->dev, PCI_STATUS, cfg_status);
 	}
 
 	if (dma_status & DMASCR_PARITY_ERR_DET) {
-		printk(KERN_ERR "MM%d*: PARITY ERROR DETECTED\n", card->card_number); 
+		dev_printk(KERN_ERR, &card->dev->dev,
+			"PARITY ERROR DETECTED\n");
 		pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);
 		pci_write_config_word(card->dev, PCI_STATUS, cfg_status);
 	}
 
 	if (dma_status & DMASCR_SYSTEM_ERR_SIG) {
-		printk(KERN_ERR "MM%d*: SYSTEM ERROR\n", card->card_number); 
+		dev_printk(KERN_ERR, &card->dev->dev, "SYSTEM ERROR\n");
 		pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);
 		pci_write_config_word(card->dev, PCI_STATUS, cfg_status);
 	}
 
 	if (dma_status & DMASCR_TARGET_ABT) {
-		printk(KERN_ERR "MM%d*: TARGET ABORT\n", card->card_number); 
+		dev_printk(KERN_ERR, &card->dev->dev, "TARGET ABORT\n");
 		pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);
 		pci_write_config_word(card->dev, PCI_STATUS, cfg_status);
 	}
 
 	if (dma_status & DMASCR_MASTER_ABT) {
-		printk(KERN_ERR "MM%d*: MASTER ABORT\n", card->card_number); 
+		dev_printk(KERN_ERR, &card->dev->dev, "MASTER ABORT\n");
 		pci_read_config_word(card->dev, PCI_STATUS, &cfg_status);
 		pci_write_config_word(card->dev, PCI_STATUS, cfg_status);
 	}
@@ -656,7 +668,7 @@
 
 HW_TRACE(0x36);
 
-	return IRQ_HANDLED; 
+	return IRQ_HANDLED;
 }
 /*
 -----------------------------------------------------------------------------------
@@ -696,20 +708,20 @@
 		card->battery[battery].last_change = jiffies;
 
 		if (card->battery[battery].good) {
-			printk(KERN_ERR "MM%d: Battery %d now good\n",
-				card->card_number, battery + 1);
+			dev_printk(KERN_ERR, &card->dev->dev,
+				"Battery %d now good\n", battery + 1);
 			card->battery[battery].warned = 0;
 		} else
-			printk(KERN_ERR "MM%d: Battery %d now FAILED\n",
-				card->card_number, battery + 1);
+			dev_printk(KERN_ERR, &card->dev->dev,
+				"Battery %d now FAILED\n", battery + 1);
 
 		return 1;
 	} else if (!card->battery[battery].good &&
 		   !card->battery[battery].warned &&
 		   time_after_eq(jiffies, card->battery[battery].last_change +
 				 (HZ * 60 * 60 * 5))) {
-		printk(KERN_ERR "MM%d: Battery %d still FAILED after 5 hours\n",
-			card->card_number, battery + 1);
+		dev_printk(KERN_ERR, &card->dev->dev,
+			"Battery %d still FAILED after 5 hours\n", battery + 1);
 		card->battery[battery].warned = 1;
 
 		return 1;
@@ -733,8 +745,8 @@
 
 	status = readb(card->csr_remap + MEMCTRLSTATUS_BATTERY);
 	if (debug & DEBUG_BATTERY_POLLING)
-		printk(KERN_DEBUG "MM%d: checking battery status, 1 = %s, 2 = %s\n",
-		       card->card_number,
+		dev_printk(KERN_DEBUG, &card->dev->dev,
+			"checking battery status, 1 = %s, 2 = %s\n",
 		       (status & BATTERY_1_FAILURE) ? "FAILURE" : "OK",
 		       (status & BATTERY_2_FAILURE) ? "FAILURE" : "OK");
 
@@ -749,7 +761,7 @@
 {
 	int i;
 
-	for (i = 0; i < num_cards; i++) 
+	for (i = 0; i < num_cards; i++)
 		if (!(cards[i].flags & UM_FLAG_NO_BATT)) {
 			struct cardinfo *card = &cards[i];
 			spin_lock_bh(&card->lock);
@@ -853,45 +865,56 @@
 	unsigned char	mem_present;
 	unsigned char	batt_status;
 	unsigned int	saved_bar, data;
+	unsigned long	csr_base;
+	unsigned long	csr_len;
 	int		magic_number;
+	static int	printed_version;
 
-	if (pci_enable_device(dev) < 0)
-		return -ENODEV;
+	if (!printed_version++)
+		printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n");
+
+	ret = pci_enable_device(dev);
+	if (ret)
+		return ret;
 
 	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF8);
 	pci_set_master(dev);
 
 	card->dev         = dev;
-	card->card_number = num_cards;
 
-	card->csr_base = pci_resource_start(dev, 0);
-	card->csr_len  = pci_resource_len(dev, 0);
+	csr_base = pci_resource_start(dev, 0);
+	csr_len  = pci_resource_len(dev, 0);
+	if (!csr_base || !csr_len)
+		return -ENODEV;
 
-	printk(KERN_INFO "Micro Memory(tm) controller #%d found at %02x:%02x (PCI Mem Module (Battery Backup))\n",
-	       card->card_number, dev->bus->number, dev->devfn);
+	dev_printk(KERN_INFO, &dev->dev,
+		"Micro Memory(tm) controller found (PCI Mem Module (Battery Backup))\n");
 
 	if (pci_set_dma_mask(dev, DMA_64BIT_MASK) &&
 	    pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
-		printk(KERN_WARNING "MM%d: NO suitable DMA found\n",num_cards);
+		dev_printk(KERN_WARNING, &dev->dev, "NO suitable DMA found\n");
 		return  -ENOMEM;
 	}
-	if (!request_mem_region(card->csr_base, card->csr_len, "Micro Memory")) {
-		printk(KERN_ERR "MM%d: Unable to request memory region\n", card->card_number);
-		ret = -ENOMEM;
 
+	ret = pci_request_regions(dev, DRIVER_NAME);
+	if (ret) {
+		dev_printk(KERN_ERR, &card->dev->dev,
+			"Unable to request memory region\n");
 		goto failed_req_csr;
 	}
 
-	card->csr_remap = ioremap_nocache(card->csr_base, card->csr_len);
+	card->csr_remap = ioremap_nocache(csr_base, csr_len);
 	if (!card->csr_remap) {
-		printk(KERN_ERR "MM%d: Unable to remap memory region\n", card->card_number);
+		dev_printk(KERN_ERR, &card->dev->dev,
+			"Unable to remap memory region\n");
 		ret = -ENOMEM;
 
 		goto failed_remap_csr;
 	}
 
-	printk(KERN_INFO "MM%d: CSR 0x%08lx -> 0x%p (0x%lx)\n", card->card_number,
-	       card->csr_base, card->csr_remap, card->csr_len);
+	dev_printk(KERN_INFO, &card->dev->dev,
+		"CSR 0x%08lx -> 0x%p (0x%lx)\n",
+	       csr_base, card->csr_remap, csr_len);
 
 	switch(card->dev->device) {
 	case 0x5415:
@@ -915,7 +938,7 @@
 	}
 
 	if (readb(card->csr_remap + MEMCTRLSTATUS_MAGIC) != magic_number) {
-		printk(KERN_ERR "MM%d: Magic number invalid\n", card->card_number);
+		dev_printk(KERN_ERR, &card->dev->dev, "Magic number invalid\n");
 		ret = -ENOMEM;
 		goto failed_magic;
 	}
@@ -928,7 +951,7 @@
 						      &card->mm_pages[1].page_dma);
 	if (card->mm_pages[0].desc == NULL ||
 	    card->mm_pages[1].desc == NULL) {
-		printk(KERN_ERR "MM%d: alloc failed\n", card->card_number);
+		dev_printk(KERN_ERR, &card->dev->dev, "alloc failed\n");
 		goto failed_alloc;
 	}
 	reset_page(&card->mm_pages[0]);
@@ -949,7 +972,7 @@
 	tasklet_init(&card->tasklet, process_page, (unsigned long)card);
 
 	card->check_batteries = 0;
-	
+
 	mem_present = readb(card->csr_remap + MEMCTRLSTATUS_MEMORY);
 	switch (mem_present) {
 	case MEM_128_MB:
@@ -982,12 +1005,13 @@
 	card->battery[1].good = !(batt_status & BATTERY_2_FAILURE);
 	card->battery[0].last_change = card->battery[1].last_change = jiffies;
 
-	if (card->flags & UM_FLAG_NO_BATT) 
-		printk(KERN_INFO "MM%d: Size %d KB\n",
-		       card->card_number, card->mm_size);
+	if (card->flags & UM_FLAG_NO_BATT)
+		dev_printk(KERN_INFO, &card->dev->dev,
+			"Size %d KB\n", card->mm_size);
 	else {
-		printk(KERN_INFO "MM%d: Size %d KB, Battery 1 %s (%s), Battery 2 %s (%s)\n",
-		       card->card_number, card->mm_size,
+		dev_printk(KERN_INFO, &card->dev->dev,
+			"Size %d KB, Battery 1 %s (%s), Battery 2 %s (%s)\n",
+		       card->mm_size,
 		       (batt_status & BATTERY_1_DISABLED ? "Disabled" : "Enabled"),
 		       card->battery[0].good ? "OK" : "FAILURE",
 		       (batt_status & BATTERY_2_DISABLED ? "Disabled" : "Enabled"),
@@ -1005,19 +1029,16 @@
 	data = ~data;
 	data += 1;
 
-	card->win_size = data;
-
-
-	if (request_irq(dev->irq, mm_interrupt, IRQF_SHARED, "pci-umem", card)) {
-		printk(KERN_ERR "MM%d: Unable to allocate IRQ\n", card->card_number);
+	if (request_irq(dev->irq, mm_interrupt, IRQF_SHARED, DRIVER_NAME, card)) {
+		dev_printk(KERN_ERR, &card->dev->dev,
+			"Unable to allocate IRQ\n");
 		ret = -ENODEV;
 
 		goto failed_req_irq;
 	}
 
-	card->irq = dev->irq;
-	printk(KERN_INFO "MM%d: Window size %d bytes, IRQ %d\n", card->card_number,
-	       card->win_size, card->irq);
+	dev_printk(KERN_INFO, &card->dev->dev,
+		"Window size %d bytes, IRQ %d\n", data, dev->irq);
 
         spin_lock_init(&card->lock);
 
@@ -1037,10 +1058,12 @@
 	num_cards++;
 
 	if (!get_userbit(card, MEMORY_INITIALIZED)) {
-		printk(KERN_INFO "MM%d: memory NOT initialized. Consider over-writing whole device.\n", card->card_number);
+		dev_printk(KERN_INFO, &card->dev->dev,
+			"memory NOT initialized. Consider over-writing whole device.\n");
 		card->init_size = 0;
 	} else {
-		printk(KERN_INFO "MM%d: memory already initialized\n", card->card_number);
+		dev_printk(KERN_INFO, &card->dev->dev,
+			"memory already initialized\n");
 		card->init_size = card->mm_size;
 	}
 
@@ -1062,7 +1085,7 @@
  failed_magic:
 	iounmap(card->csr_remap);
  failed_remap_csr:
-	release_mem_region(card->csr_base, card->csr_len);
+	pci_release_regions(dev);
  failed_req_csr:
 
 	return ret;
@@ -1077,9 +1100,8 @@
 	struct cardinfo *card = pci_get_drvdata(dev);
 
 	tasklet_kill(&card->tasklet);
+	free_irq(dev->irq, card);
 	iounmap(card->csr_remap);
-	release_mem_region(card->csr_base, card->csr_len);
-	free_irq(card->irq, card);
 
 	if (card->mm_pages[0].desc)
 		pci_free_consistent(card->dev, PAGE_SIZE*2,
@@ -1090,6 +1112,9 @@
 				    card->mm_pages[1].desc,
 				    card->mm_pages[1].page_dma);
 	blk_cleanup_queue(card->queue);
+
+	pci_release_regions(dev);
+	pci_disable_device(dev);
 }
 
 static const struct pci_device_id mm_pci_ids[] = {
@@ -1109,11 +1134,12 @@
 MODULE_DEVICE_TABLE(pci, mm_pci_ids);
 
 static struct pci_driver mm_pci_driver = {
-	.name =		"umem",
-	.id_table =	mm_pci_ids,
-	.probe =	mm_pci_probe,
-	.remove =	mm_pci_remove,
+	.name		= DRIVER_NAME,
+	.id_table	= mm_pci_ids,
+	.probe		= mm_pci_probe,
+	.remove		= mm_pci_remove,
 };
+
 /*
 -----------------------------------------------------------------------------------
 --                               mm_init
@@ -1125,13 +1151,11 @@
 	int retval, i;
 	int err;
 
-	printk(KERN_INFO DRIVER_VERSION " : " DRIVER_DESC "\n");
-
 	retval = pci_register_driver(&mm_pci_driver);
 	if (retval)
 		return -ENOMEM;
 
-	err = major_nr = register_blkdev(0, "umem");
+	err = major_nr = register_blkdev(0, DRIVER_NAME);
 	if (err < 0) {
 		pci_unregister_driver(&mm_pci_driver);
 		return -EIO;
@@ -1157,13 +1181,13 @@
 	}
 
 	init_battery_timer();
-	printk("MM: desc_per_page = %ld\n", DESC_PER_PAGE);
+	printk(KERN_INFO "MM: desc_per_page = %ld\n", DESC_PER_PAGE);
 /* printk("mm_init: Done. 10-19-01 9:00\n"); */
 	return 0;
 
 out:
 	pci_unregister_driver(&mm_pci_driver);
-	unregister_blkdev(major_nr, "umem");
+	unregister_blkdev(major_nr, DRIVER_NAME);
 	while (i--)
 		put_disk(mm_gendisk[i]);
 	return -ENOMEM;
@@ -1186,7 +1210,7 @@
 
 	pci_unregister_driver(&mm_pci_driver);
 
-	unregister_blkdev(major_nr, "umem");
+	unregister_blkdev(major_nr, DRIVER_NAME);
 }
 
 module_init(mm_init);
diff --git a/drivers/block/umem.h b/drivers/block/umem.h
new file mode 100644
index 0000000..375c689
--- /dev/null
+++ b/drivers/block/umem.h
@@ -0,0 +1,133 @@
+
+/*
+ * This file contains defines for the
+ *   Micro Memory MM5415
+ * family PCI Memory Module with Battery Backup.
+ *
+ * Copyright Micro Memory INC 2001.  All rights reserved.
+ * Release under the terms of the GNU GENERAL PUBLIC LICENSE version 2.
+ * See the file COPYING.
+ */
+
+#ifndef _DRIVERS_BLOCK_MM_H
+#define _DRIVERS_BLOCK_MM_H
+
+
+#define IRQ_TIMEOUT (1 * HZ)
+
+/* CSR register definition */
+#define MEMCTRLSTATUS_MAGIC	0x00
+#define  MM_MAGIC_VALUE		(unsigned char)0x59
+
+#define MEMCTRLSTATUS_BATTERY	0x04
+#define  BATTERY_1_DISABLED	0x01
+#define  BATTERY_1_FAILURE	0x02
+#define  BATTERY_2_DISABLED	0x04
+#define  BATTERY_2_FAILURE	0x08
+
+#define MEMCTRLSTATUS_MEMORY	0x07
+#define  MEM_128_MB		0xfe
+#define  MEM_256_MB		0xfc
+#define  MEM_512_MB		0xf8
+#define  MEM_1_GB		0xf0
+#define  MEM_2_GB		0xe0
+
+#define MEMCTRLCMD_LEDCTRL	0x08
+#define  LED_REMOVE		2
+#define  LED_FAULT		4
+#define  LED_POWER		6
+#define	 LED_FLIP		255
+#define  LED_OFF		0x00
+#define  LED_ON			0x01
+#define  LED_FLASH_3_5		0x02
+#define  LED_FLASH_7_0		0x03
+#define  LED_POWER_ON		0x00
+#define  LED_POWER_OFF		0x01
+#define  USER_BIT1		0x01
+#define  USER_BIT2		0x02
+
+#define MEMORY_INITIALIZED	USER_BIT1
+
+#define MEMCTRLCMD_ERRCTRL	0x0C
+#define  EDC_NONE_DEFAULT	0x00
+#define  EDC_NONE		0x01
+#define  EDC_STORE_READ		0x02
+#define  EDC_STORE_CORRECT	0x03
+
+#define MEMCTRLCMD_ERRCNT	0x0D
+#define MEMCTRLCMD_ERRSTATUS	0x0E
+
+#define ERROR_DATA_LOG		0x20
+#define ERROR_ADDR_LOG		0x28
+#define ERROR_COUNT		0x3D
+#define ERROR_SYNDROME		0x3E
+#define ERROR_CHECK		0x3F
+
+#define DMA_PCI_ADDR		0x40
+#define DMA_LOCAL_ADDR		0x48
+#define DMA_TRANSFER_SIZE	0x50
+#define DMA_DESCRIPTOR_ADDR	0x58
+#define DMA_SEMAPHORE_ADDR	0x60
+#define DMA_STATUS_CTRL		0x68
+#define  DMASCR_GO		0x00001
+#define  DMASCR_TRANSFER_READ	0x00002
+#define  DMASCR_CHAIN_EN	0x00004
+#define  DMASCR_SEM_EN		0x00010
+#define  DMASCR_DMA_COMP_EN	0x00020
+#define  DMASCR_CHAIN_COMP_EN	0x00040
+#define  DMASCR_ERR_INT_EN	0x00080
+#define  DMASCR_PARITY_INT_EN	0x00100
+#define  DMASCR_ANY_ERR		0x00800
+#define  DMASCR_MBE_ERR		0x01000
+#define  DMASCR_PARITY_ERR_REP	0x02000
+#define  DMASCR_PARITY_ERR_DET	0x04000
+#define  DMASCR_SYSTEM_ERR_SIG	0x08000
+#define  DMASCR_TARGET_ABT	0x10000
+#define  DMASCR_MASTER_ABT	0x20000
+#define  DMASCR_DMA_COMPLETE	0x40000
+#define  DMASCR_CHAIN_COMPLETE	0x80000
+
+/*
+3.SOME PCs HAVE HOST BRIDGES WHICH APPARENTLY DO NOT CORRECTLY HANDLE
+READ-LINE (0xE) OR READ-MULTIPLE (0xC) PCI COMMAND CODES DURING DMA
+TRANSFERS. IN OTHER SYSTEMS THESE COMMAND CODES WILL CAUSE THE HOST BRIDGE
+TO ALLOW LONGER BURSTS DURING DMA READ OPERATIONS. THE UPPER FOUR BITS
+(31..28) OF THE DMA CSR HAVE BEEN MADE PROGRAMMABLE, SO THAT EITHER A 0x6,
+AN 0xE OR A 0xC CAN BE WRITTEN TO THEM TO SET THE COMMAND CODE USED DURING
+DMA READ OPERATIONS.
+*/
+#define        DMASCR_READ   0x60000000
+#define        DMASCR_READLINE   0xE0000000
+#define        DMASCR_READMULTI   0xC0000000
+
+
+#define DMASCR_ERROR_MASK	(DMASCR_MASTER_ABT | DMASCR_TARGET_ABT | DMASCR_SYSTEM_ERR_SIG | DMASCR_PARITY_ERR_DET | DMASCR_MBE_ERR | DMASCR_ANY_ERR)
+#define DMASCR_HARD_ERROR	(DMASCR_MASTER_ABT | DMASCR_TARGET_ABT | DMASCR_SYSTEM_ERR_SIG | DMASCR_PARITY_ERR_DET | DMASCR_MBE_ERR)
+
+#define WINDOWMAP_WINNUM	0x7B
+
+#define DMA_READ_FROM_HOST 0
+#define DMA_WRITE_TO_HOST 1
+
+struct mm_dma_desc {
+	__le64	pci_addr;
+	__le64	local_addr;
+	__le32	transfer_size;
+	u32	zero1;
+	__le64	next_desc_addr;
+	__le64	sem_addr;
+	__le32	control_bits;
+	u32	zero2;
+
+	dma_addr_t data_dma_handle;
+
+	/* Copy of the bits */
+	__le64	sem_control_bits;
+} __attribute__((aligned(8)));
+
+/* bits for card->flags */
+#define UM_FLAG_DMA_IN_REGS		1
+#define UM_FLAG_NO_BYTE_STATUS		2
+#define UM_FLAG_NO_BATTREG		4
+#define	UM_FLAG_NO_BATT			8
+#endif
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
index dae3991..e824b67 100644
--- a/drivers/block/viodasd.c
+++ b/drivers/block/viodasd.c
@@ -41,7 +41,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/completion.h>
 #include <linux/device.h>
-#include <linux/kernel.h>
 
 #include <asm/uaccess.h>
 #include <asm/vio.h>
@@ -75,53 +74,9 @@
 static DEFINE_SPINLOCK(viodasd_spinlock);
 
 #define VIOMAXREQ		16
-#define VIOMAXBLOCKDMA		12
 
 #define DEVICE_NO(cell)	((struct viodasd_device *)(cell) - &viodasd_devices[0])
 
-struct open_data {
-	u64	disk_size;
-	u16	max_disk;
-	u16	cylinders;
-	u16	tracks;
-	u16	sectors;
-	u16	bytes_per_sector;
-};
-
-struct rw_data {
-	u64	offset;
-	struct {
-		u32	token;
-		u32	reserved;
-		u64	len;
-	} dma_info[VIOMAXBLOCKDMA];
-};
-
-struct vioblocklpevent {
-	struct HvLpEvent	event;
-	u32			reserved;
-	u16			version;
-	u16			sub_result;
-	u16			disk;
-	u16			flags;
-	union {
-		struct open_data	open_data;
-		struct rw_data		rw_data;
-		u64			changed;
-	} u;
-};
-
-#define vioblockflags_ro   0x0001
-
-enum vioblocksubtype {
-	vioblockopen = 0x0001,
-	vioblockclose = 0x0002,
-	vioblockread = 0x0003,
-	vioblockwrite = 0x0004,
-	vioblockflush = 0x0005,
-	vioblockcheck = 0x0007
-};
-
 struct viodasd_waitevent {
 	struct completion	com;
 	int			rc;
@@ -400,7 +355,7 @@
 /*
  * This is the external request processing routine
  */
-static void do_viodasd_request(request_queue_t *q)
+static void do_viodasd_request(struct request_queue *q)
 {
 	struct request *req;
 
@@ -430,7 +385,7 @@
  * Probe a single disk and fill in the viodasd_device structure
  * for it.
  */
-static void probe_disk(struct viodasd_device *d)
+static int probe_disk(struct viodasd_device *d)
 {
 	HvLpEvent_Rc hvrc;
 	struct viodasd_waitevent we;
@@ -454,14 +409,14 @@
 			0, 0, 0);
 	if (hvrc != 0) {
 		printk(VIOD_KERN_WARNING "bad rc on HV open %d\n", (int)hvrc);
-		return;
+		return 0;
 	}
 
 	wait_for_completion(&we.com);
 
 	if (we.rc != 0) {
 		if (flags != 0)
-			return;
+			return 0;
 		/* try again with read only flag set */
 		flags = vioblockflags_ro;
 		goto retry;
@@ -491,15 +446,32 @@
 	if (hvrc != 0) {
 		printk(VIOD_KERN_WARNING
 		       "bad rc sending event to OS/400 %d\n", (int)hvrc);
-		return;
+		return 0;
 	}
+
+	if (d->dev == NULL) {
+		/* this is when we reprobe for new disks */
+		if (vio_create_viodasd(dev_no) == NULL) {
+			printk(VIOD_KERN_WARNING
+				"cannot allocate virtual device for disk %d\n",
+				dev_no);
+			return 0;
+		}
+		/*
+		 * The vio_create_viodasd will have recursed into this
+		 * routine with d->dev set to the new vio device and
+		 * will finish the setup of the disk below.
+		 */
+		return 1;
+	}
+
 	/* create the request queue for the disk */
 	spin_lock_init(&d->q_lock);
 	q = blk_init_queue(do_viodasd_request, &d->q_lock);
 	if (q == NULL) {
 		printk(VIOD_KERN_WARNING "cannot allocate queue for disk %d\n",
 				dev_no);
-		return;
+		return 0;
 	}
 	g = alloc_disk(1 << PARTITION_SHIFT);
 	if (g == NULL) {
@@ -507,7 +479,7 @@
 				"cannot allocate disk structure for disk %d\n",
 				dev_no);
 		blk_cleanup_queue(q);
-		return;
+		return 0;
 	}
 
 	d->disk = g;
@@ -539,6 +511,7 @@
 
 	/* register us in the global list */
 	add_disk(g);
+	return 1;
 }
 
 /* returns the total number of scatterlist elements converted */
@@ -719,8 +692,7 @@
 	struct viodasd_device *d = &viodasd_devices[vdev->unit_address];
 
 	d->dev = &vdev->dev;
-	probe_disk(d);
-	if (d->disk == NULL)
+	if (!probe_disk(d))
 		return -ENODEV;
 	return 0;
 }
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index 0d97b7e..624d30f 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -298,7 +298,7 @@
 }
 
 /* do_xd_request: handle an incoming request */
-static void do_xd_request (request_queue_t * q)
+static void do_xd_request (struct request_queue * q)
 {
 	struct request *req;
 
diff --git a/drivers/block/xd.h b/drivers/block/xd.h
index 82e090f..cffd44a 100644
--- a/drivers/block/xd.h
+++ b/drivers/block/xd.h
@@ -104,7 +104,7 @@
 static u_char xd_detect (u_char *controller, unsigned int *address);
 static u_char xd_initdrives (void (*init_drive)(u_char drive));
 
-static void do_xd_request (request_queue_t * q);
+static void do_xd_request (struct request_queue * q);
 static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg);
 static int xd_readwrite (u_char operation,XD_INFO *disk,char *buffer,u_int block,u_int count);
 static void xd_recalibrate (u_char drive);
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
new file mode 100644
index 0000000..2bdebcb
--- /dev/null
+++ b/drivers/block/xen-blkfront.c
@@ -0,0 +1,984 @@
+/*
+ * blkfront.c
+ *
+ * XenLinux virtual block device driver.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
+ * Copyright (c) 2004, Christian Limpach
+ * Copyright (c) 2004, Andrew Warfield
+ * Copyright (c) 2005, Christopher Clark
+ * Copyright (c) 2005, XenSource Ltd
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/module.h>
+
+#include <xen/xenbus.h>
+#include <xen/grant_table.h>
+#include <xen/events.h>
+#include <xen/page.h>
+
+#include <xen/interface/grant_table.h>
+#include <xen/interface/io/blkif.h>
+
+#include <asm/xen/hypervisor.h>
+
+enum blkif_state {
+	BLKIF_STATE_DISCONNECTED,
+	BLKIF_STATE_CONNECTED,
+	BLKIF_STATE_SUSPENDED,
+};
+
+struct blk_shadow {
+	struct blkif_request req;
+	unsigned long request;
+	unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+
+static struct block_device_operations xlvbd_block_fops;
+
+#define BLK_RING_SIZE __RING_SIZE((struct blkif_sring *)0, PAGE_SIZE)
+
+/*
+ * We have one of these per vbd, whether ide, scsi or 'other'.  They
+ * hang in private_data off the gendisk structure. We may end up
+ * putting all kinds of interesting stuff here :-)
+ */
+struct blkfront_info
+{
+	struct xenbus_device *xbdev;
+	dev_t dev;
+	struct gendisk *gd;
+	int vdevice;
+	blkif_vdev_t handle;
+	enum blkif_state connected;
+	int ring_ref;
+	struct blkif_front_ring ring;
+	unsigned int evtchn, irq;
+	struct request_queue *rq;
+	struct work_struct work;
+	struct gnttab_free_callback callback;
+	struct blk_shadow shadow[BLK_RING_SIZE];
+	unsigned long shadow_free;
+	int feature_barrier;
+
+	/**
+	 * The number of people holding this device open.  We won't allow a
+	 * hot-unplug unless this is 0.
+	 */
+	int users;
+};
+
+static DEFINE_SPINLOCK(blkif_io_lock);
+
+#define MAXIMUM_OUTSTANDING_BLOCK_REQS \
+	(BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE)
+#define GRANT_INVALID_REF	0
+
+#define PARTS_PER_DISK		16
+
+#define BLKIF_MAJOR(dev) ((dev)>>8)
+#define BLKIF_MINOR(dev) ((dev) & 0xff)
+
+#define DEV_NAME	"xvd"	/* name in /dev */
+
+/* Information about our VBDs. */
+#define MAX_VBDS 64
+static LIST_HEAD(vbds_list);
+
+static int get_id_from_freelist(struct blkfront_info *info)
+{
+	unsigned long free = info->shadow_free;
+	BUG_ON(free > BLK_RING_SIZE);
+	info->shadow_free = info->shadow[free].req.id;
+	info->shadow[free].req.id = 0x0fffffee; /* debug */
+	return free;
+}
+
+static void add_id_to_freelist(struct blkfront_info *info,
+			       unsigned long id)
+{
+	info->shadow[id].req.id  = info->shadow_free;
+	info->shadow[id].request = 0;
+	info->shadow_free = id;
+}
+
+static void blkif_restart_queue_callback(void *arg)
+{
+	struct blkfront_info *info = (struct blkfront_info *)arg;
+	schedule_work(&info->work);
+}
+
+/*
+ * blkif_queue_request
+ *
+ * request block io
+ *
+ * id: for guest use only.
+ * operation: BLKIF_OP_{READ,WRITE,PROBE}
+ * buffer: buffer to read/write into. this should be a
+ *   virtual address in the guest os.
+ */
+static int blkif_queue_request(struct request *req)
+{
+	struct blkfront_info *info = req->rq_disk->private_data;
+	unsigned long buffer_mfn;
+	struct blkif_request *ring_req;
+	struct req_iterator iter;
+	struct bio_vec *bvec;
+	unsigned long id;
+	unsigned int fsect, lsect;
+	int ref;
+	grant_ref_t gref_head;
+
+	if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
+		return 1;
+
+	if (gnttab_alloc_grant_references(
+		BLKIF_MAX_SEGMENTS_PER_REQUEST, &gref_head) < 0) {
+		gnttab_request_free_callback(
+			&info->callback,
+			blkif_restart_queue_callback,
+			info,
+			BLKIF_MAX_SEGMENTS_PER_REQUEST);
+		return 1;
+	}
+
+	/* Fill out a communications ring structure. */
+	ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
+	id = get_id_from_freelist(info);
+	info->shadow[id].request = (unsigned long)req;
+
+	ring_req->id = id;
+	ring_req->sector_number = (blkif_sector_t)req->sector;
+	ring_req->handle = info->handle;
+
+	ring_req->operation = rq_data_dir(req) ?
+		BLKIF_OP_WRITE : BLKIF_OP_READ;
+	if (blk_barrier_rq(req))
+		ring_req->operation = BLKIF_OP_WRITE_BARRIER;
+
+	ring_req->nr_segments = 0;
+	rq_for_each_segment(bvec, req, iter) {
+		BUG_ON(ring_req->nr_segments == BLKIF_MAX_SEGMENTS_PER_REQUEST);
+		buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page));
+		fsect = bvec->bv_offset >> 9;
+		lsect = fsect + (bvec->bv_len >> 9) - 1;
+		/* install a grant reference. */
+		ref = gnttab_claim_grant_reference(&gref_head);
+		BUG_ON(ref == -ENOSPC);
+
+		gnttab_grant_foreign_access_ref(
+				ref,
+				info->xbdev->otherend_id,
+				buffer_mfn,
+				rq_data_dir(req) );
+
+		info->shadow[id].frame[ring_req->nr_segments] =
+				mfn_to_pfn(buffer_mfn);
+
+		ring_req->seg[ring_req->nr_segments] =
+				(struct blkif_request_segment) {
+					.gref       = ref,
+					.first_sect = fsect,
+					.last_sect  = lsect };
+
+		ring_req->nr_segments++;
+	}
+
+	info->ring.req_prod_pvt++;
+
+	/* Keep a private copy so we can reissue requests when recovering. */
+	info->shadow[id].req = *ring_req;
+
+	gnttab_free_grant_references(gref_head);
+
+	return 0;
+}
+
+
+static inline void flush_requests(struct blkfront_info *info)
+{
+	int notify;
+
+	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify);
+
+	if (notify)
+		notify_remote_via_irq(info->irq);
+}
+
+/*
+ * do_blkif_request
+ *  read a block; request is in a request queue
+ */
+static void do_blkif_request(struct request_queue *rq)
+{
+	struct blkfront_info *info = NULL;
+	struct request *req;
+	int queued;
+
+	pr_debug("Entered do_blkif_request\n");
+
+	queued = 0;
+
+	while ((req = elv_next_request(rq)) != NULL) {
+		info = req->rq_disk->private_data;
+		if (!blk_fs_request(req)) {
+			end_request(req, 0);
+			continue;
+		}
+
+		if (RING_FULL(&info->ring))
+			goto wait;
+
+		pr_debug("do_blk_req %p: cmd %p, sec %lx, "
+			 "(%u/%li) buffer:%p [%s]\n",
+			 req, req->cmd, (unsigned long)req->sector,
+			 req->current_nr_sectors,
+			 req->nr_sectors, req->buffer,
+			 rq_data_dir(req) ? "write" : "read");
+
+
+		blkdev_dequeue_request(req);
+		if (blkif_queue_request(req)) {
+			blk_requeue_request(rq, req);
+wait:
+			/* Avoid pointless unplugs. */
+			blk_stop_queue(rq);
+			break;
+		}
+
+		queued++;
+	}
+
+	if (queued != 0)
+		flush_requests(info);
+}
+
+static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
+{
+	struct request_queue *rq;
+
+	rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
+	if (rq == NULL)
+		return -1;
+
+	elevator_init(rq, "noop");
+
+	/* Hard sector size and max sectors impersonate the equiv. hardware. */
+	blk_queue_hardsect_size(rq, sector_size);
+	blk_queue_max_sectors(rq, 512);
+
+	/* Each segment in a request is up to an aligned page in size. */
+	blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
+	blk_queue_max_segment_size(rq, PAGE_SIZE);
+
+	/* Ensure a merged request will fit in a single I/O ring slot. */
+	blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+	blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+
+	/* Make sure buffer addresses are sector-aligned. */
+	blk_queue_dma_alignment(rq, 511);
+
+	gd->queue = rq;
+
+	return 0;
+}
+
+
+static int xlvbd_barrier(struct blkfront_info *info)
+{
+	int err;
+
+	err = blk_queue_ordered(info->rq,
+				info->feature_barrier ? QUEUE_ORDERED_DRAIN : QUEUE_ORDERED_NONE,
+				NULL);
+
+	if (err)
+		return err;
+
+	printk(KERN_INFO "blkfront: %s: barriers %s\n",
+	       info->gd->disk_name,
+	       info->feature_barrier ? "enabled" : "disabled");
+	return 0;
+}
+
+
+static int xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity,
+			       int vdevice, u16 vdisk_info, u16 sector_size,
+			       struct blkfront_info *info)
+{
+	struct gendisk *gd;
+	int nr_minors = 1;
+	int err = -ENODEV;
+
+	BUG_ON(info->gd != NULL);
+	BUG_ON(info->rq != NULL);
+
+	if ((minor % PARTS_PER_DISK) == 0)
+		nr_minors = PARTS_PER_DISK;
+
+	gd = alloc_disk(nr_minors);
+	if (gd == NULL)
+		goto out;
+
+	if (nr_minors > 1)
+		sprintf(gd->disk_name, "%s%c", DEV_NAME,
+			'a' + minor / PARTS_PER_DISK);
+	else
+		sprintf(gd->disk_name, "%s%c%d", DEV_NAME,
+			'a' + minor / PARTS_PER_DISK,
+			minor % PARTS_PER_DISK);
+
+	gd->major = XENVBD_MAJOR;
+	gd->first_minor = minor;
+	gd->fops = &xlvbd_block_fops;
+	gd->private_data = info;
+	gd->driverfs_dev = &(info->xbdev->dev);
+	set_capacity(gd, capacity);
+
+	if (xlvbd_init_blk_queue(gd, sector_size)) {
+		del_gendisk(gd);
+		goto out;
+	}
+
+	info->rq = gd->queue;
+	info->gd = gd;
+
+	if (info->feature_barrier)
+		xlvbd_barrier(info);
+
+	if (vdisk_info & VDISK_READONLY)
+		set_disk_ro(gd, 1);
+
+	if (vdisk_info & VDISK_REMOVABLE)
+		gd->flags |= GENHD_FL_REMOVABLE;
+
+	if (vdisk_info & VDISK_CDROM)
+		gd->flags |= GENHD_FL_CD;
+
+	return 0;
+
+ out:
+	return err;
+}
+
+static void kick_pending_request_queues(struct blkfront_info *info)
+{
+	if (!RING_FULL(&info->ring)) {
+		/* Re-enable calldowns. */
+		blk_start_queue(info->rq);
+		/* Kick things off immediately. */
+		do_blkif_request(info->rq);
+	}
+}
+
+static void blkif_restart_queue(struct work_struct *work)
+{
+	struct blkfront_info *info = container_of(work, struct blkfront_info, work);
+
+	spin_lock_irq(&blkif_io_lock);
+	if (info->connected == BLKIF_STATE_CONNECTED)
+		kick_pending_request_queues(info);
+	spin_unlock_irq(&blkif_io_lock);
+}
+
+static void blkif_free(struct blkfront_info *info, int suspend)
+{
+	/* Prevent new requests being issued until we fix things up. */
+	spin_lock_irq(&blkif_io_lock);
+	info->connected = suspend ?
+		BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED;
+	/* No more blkif_request(). */
+	if (info->rq)
+		blk_stop_queue(info->rq);
+	/* No more gnttab callback work. */
+	gnttab_cancel_free_callback(&info->callback);
+	spin_unlock_irq(&blkif_io_lock);
+
+	/* Flush gnttab callback work. Must be done with no locks held. */
+	flush_scheduled_work();
+
+	/* Free resources associated with old device channel. */
+	if (info->ring_ref != GRANT_INVALID_REF) {
+		gnttab_end_foreign_access(info->ring_ref, 0,
+					  (unsigned long)info->ring.sring);
+		info->ring_ref = GRANT_INVALID_REF;
+		info->ring.sring = NULL;
+	}
+	if (info->irq)
+		unbind_from_irqhandler(info->irq, info);
+	info->evtchn = info->irq = 0;
+
+}
+
+static void blkif_completion(struct blk_shadow *s)
+{
+	int i;
+	for (i = 0; i < s->req.nr_segments; i++)
+		gnttab_end_foreign_access(s->req.seg[i].gref, 0, 0UL);
+}
+
+static irqreturn_t blkif_interrupt(int irq, void *dev_id)
+{
+	struct request *req;
+	struct blkif_response *bret;
+	RING_IDX i, rp;
+	unsigned long flags;
+	struct blkfront_info *info = (struct blkfront_info *)dev_id;
+	int uptodate;
+
+	spin_lock_irqsave(&blkif_io_lock, flags);
+
+	if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) {
+		spin_unlock_irqrestore(&blkif_io_lock, flags);
+		return IRQ_HANDLED;
+	}
+
+ again:
+	rp = info->ring.sring->rsp_prod;
+	rmb(); /* Ensure we see queued responses up to 'rp'. */
+
+	for (i = info->ring.rsp_cons; i != rp; i++) {
+		unsigned long id;
+		int ret;
+
+		bret = RING_GET_RESPONSE(&info->ring, i);
+		id   = bret->id;
+		req  = (struct request *)info->shadow[id].request;
+
+		blkif_completion(&info->shadow[id]);
+
+		add_id_to_freelist(info, id);
+
+		uptodate = (bret->status == BLKIF_RSP_OKAY);
+		switch (bret->operation) {
+		case BLKIF_OP_WRITE_BARRIER:
+			if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
+				printk(KERN_WARNING "blkfront: %s: write barrier op failed\n",
+				       info->gd->disk_name);
+				uptodate = -EOPNOTSUPP;
+				info->feature_barrier = 0;
+				xlvbd_barrier(info);
+			}
+			/* fall through */
+		case BLKIF_OP_READ:
+		case BLKIF_OP_WRITE:
+			if (unlikely(bret->status != BLKIF_RSP_OKAY))
+				dev_dbg(&info->xbdev->dev, "Bad return from blkdev data "
+					"request: %x\n", bret->status);
+
+			ret = end_that_request_first(req, uptodate,
+				req->hard_nr_sectors);
+			BUG_ON(ret);
+			end_that_request_last(req, uptodate);
+			break;
+		default:
+			BUG();
+		}
+	}
+
+	info->ring.rsp_cons = i;
+
+	if (i != info->ring.req_prod_pvt) {
+		int more_to_do;
+		RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do);
+		if (more_to_do)
+			goto again;
+	} else
+		info->ring.sring->rsp_event = i + 1;
+
+	kick_pending_request_queues(info);
+
+	spin_unlock_irqrestore(&blkif_io_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+
+static int setup_blkring(struct xenbus_device *dev,
+			 struct blkfront_info *info)
+{
+	struct blkif_sring *sring;
+	int err;
+
+	info->ring_ref = GRANT_INVALID_REF;
+
+	sring = (struct blkif_sring *)__get_free_page(GFP_KERNEL);
+	if (!sring) {
+		xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
+		return -ENOMEM;
+	}
+	SHARED_RING_INIT(sring);
+	FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
+
+	err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
+	if (err < 0) {
+		free_page((unsigned long)sring);
+		info->ring.sring = NULL;
+		goto fail;
+	}
+	info->ring_ref = err;
+
+	err = xenbus_alloc_evtchn(dev, &info->evtchn);
+	if (err)
+		goto fail;
+
+	err = bind_evtchn_to_irqhandler(info->evtchn,
+					blkif_interrupt,
+					IRQF_SAMPLE_RANDOM, "blkif", info);
+	if (err <= 0) {
+		xenbus_dev_fatal(dev, err,
+				 "bind_evtchn_to_irqhandler failed");
+		goto fail;
+	}
+	info->irq = err;
+
+	return 0;
+fail:
+	blkif_free(info, 0);
+	return err;
+}
+
+
+/* Common code used when first setting up, and when resuming. */
+static int talk_to_backend(struct xenbus_device *dev,
+			   struct blkfront_info *info)
+{
+	const char *message = NULL;
+	struct xenbus_transaction xbt;
+	int err;
+
+	/* Create shared ring, alloc event channel. */
+	err = setup_blkring(dev, info);
+	if (err)
+		goto out;
+
+again:
+	err = xenbus_transaction_start(&xbt);
+	if (err) {
+		xenbus_dev_fatal(dev, err, "starting transaction");
+		goto destroy_blkring;
+	}
+
+	err = xenbus_printf(xbt, dev->nodename,
+			    "ring-ref", "%u", info->ring_ref);
+	if (err) {
+		message = "writing ring-ref";
+		goto abort_transaction;
+	}
+	err = xenbus_printf(xbt, dev->nodename,
+			    "event-channel", "%u", info->evtchn);
+	if (err) {
+		message = "writing event-channel";
+		goto abort_transaction;
+	}
+
+	err = xenbus_transaction_end(xbt, 0);
+	if (err) {
+		if (err == -EAGAIN)
+			goto again;
+		xenbus_dev_fatal(dev, err, "completing transaction");
+		goto destroy_blkring;
+	}
+
+	xenbus_switch_state(dev, XenbusStateInitialised);
+
+	return 0;
+
+ abort_transaction:
+	xenbus_transaction_end(xbt, 1);
+	if (message)
+		xenbus_dev_fatal(dev, err, "%s", message);
+ destroy_blkring:
+	blkif_free(info, 0);
+ out:
+	return err;
+}
+
+
+/**
+ * Entry point to this code when a new device is created.  Allocate the basic
+ * structures and the ring buffer for communication with the backend, and
+ * inform the backend of the appropriate details for those.  Switch to
+ * Initialised state.
+ */
+static int blkfront_probe(struct xenbus_device *dev,
+			  const struct xenbus_device_id *id)
+{
+	int err, vdevice, i;
+	struct blkfront_info *info;
+
+	/* FIXME: Use dynamic device id if this is not set. */
+	err = xenbus_scanf(XBT_NIL, dev->nodename,
+			   "virtual-device", "%i", &vdevice);
+	if (err != 1) {
+		xenbus_dev_fatal(dev, err, "reading virtual-device");
+		return err;
+	}
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
+		return -ENOMEM;
+	}
+
+	info->xbdev = dev;
+	info->vdevice = vdevice;
+	info->connected = BLKIF_STATE_DISCONNECTED;
+	INIT_WORK(&info->work, blkif_restart_queue);
+
+	for (i = 0; i < BLK_RING_SIZE; i++)
+		info->shadow[i].req.id = i+1;
+	info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
+
+	/* Front end dir is a number, which is used as the id. */
+	info->handle = simple_strtoul(strrchr(dev->nodename, '/')+1, NULL, 0);
+	dev->dev.driver_data = info;
+
+	err = talk_to_backend(dev, info);
+	if (err) {
+		kfree(info);
+		dev->dev.driver_data = NULL;
+		return err;
+	}
+
+	return 0;
+}
+
+
+static int blkif_recover(struct blkfront_info *info)
+{
+	int i;
+	struct blkif_request *req;
+	struct blk_shadow *copy;
+	int j;
+
+	/* Stage 1: Make a safe copy of the shadow state. */
+	copy = kmalloc(sizeof(info->shadow), GFP_KERNEL);
+	if (!copy)
+		return -ENOMEM;
+	memcpy(copy, info->shadow, sizeof(info->shadow));
+
+	/* Stage 2: Set up free list. */
+	memset(&info->shadow, 0, sizeof(info->shadow));
+	for (i = 0; i < BLK_RING_SIZE; i++)
+		info->shadow[i].req.id = i+1;
+	info->shadow_free = info->ring.req_prod_pvt;
+	info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
+
+	/* Stage 3: Find pending requests and requeue them. */
+	for (i = 0; i < BLK_RING_SIZE; i++) {
+		/* Not in use? */
+		if (copy[i].request == 0)
+			continue;
+
+		/* Grab a request slot and copy shadow state into it. */
+		req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
+		*req = copy[i].req;
+
+		/* We get a new request id, and must reset the shadow state. */
+		req->id = get_id_from_freelist(info);
+		memcpy(&info->shadow[req->id], &copy[i], sizeof(copy[i]));
+
+		/* Rewrite any grant references invalidated by susp/resume. */
+		for (j = 0; j < req->nr_segments; j++)
+			gnttab_grant_foreign_access_ref(
+				req->seg[j].gref,
+				info->xbdev->otherend_id,
+				pfn_to_mfn(info->shadow[req->id].frame[j]),
+				rq_data_dir(
+					(struct request *)
+					info->shadow[req->id].request));
+		info->shadow[req->id].req = *req;
+
+		info->ring.req_prod_pvt++;
+	}
+
+	kfree(copy);
+
+	xenbus_switch_state(info->xbdev, XenbusStateConnected);
+
+	spin_lock_irq(&blkif_io_lock);
+
+	/* Now safe for us to use the shared ring */
+	info->connected = BLKIF_STATE_CONNECTED;
+
+	/* Send off requeued requests */
+	flush_requests(info);
+
+	/* Kick any other new requests queued since we resumed */
+	kick_pending_request_queues(info);
+
+	spin_unlock_irq(&blkif_io_lock);
+
+	return 0;
+}
+
+/**
+ * We are reconnecting to the backend, due to a suspend/resume, or a backend
+ * driver restart.  We tear down our blkif structure and recreate it, but
+ * leave the device-layer structures intact so that this is transparent to the
+ * rest of the kernel.
+ */
+static int blkfront_resume(struct xenbus_device *dev)
+{
+	struct blkfront_info *info = dev->dev.driver_data;
+	int err;
+
+	dev_dbg(&dev->dev, "blkfront_resume: %s\n", dev->nodename);
+
+	blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
+
+	err = talk_to_backend(dev, info);
+	if (info->connected == BLKIF_STATE_SUSPENDED && !err)
+		err = blkif_recover(info);
+
+	return err;
+}
+
+
+/*
+ * Invoked when the backend is finally 'ready' (and has told produced
+ * the details about the physical device - #sectors, size, etc).
+ */
+static void blkfront_connect(struct blkfront_info *info)
+{
+	unsigned long long sectors;
+	unsigned long sector_size;
+	unsigned int binfo;
+	int err;
+
+	if ((info->connected == BLKIF_STATE_CONNECTED) ||
+	    (info->connected == BLKIF_STATE_SUSPENDED) )
+		return;
+
+	dev_dbg(&info->xbdev->dev, "%s:%s.\n",
+		__func__, info->xbdev->otherend);
+
+	err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+			    "sectors", "%llu", &sectors,
+			    "info", "%u", &binfo,
+			    "sector-size", "%lu", &sector_size,
+			    NULL);
+	if (err) {
+		xenbus_dev_fatal(info->xbdev, err,
+				 "reading backend fields at %s",
+				 info->xbdev->otherend);
+		return;
+	}
+
+	err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+			    "feature-barrier", "%lu", &info->feature_barrier,
+			    NULL);
+	if (err)
+		info->feature_barrier = 0;
+
+	err = xlvbd_alloc_gendisk(BLKIF_MINOR(info->vdevice),
+				  sectors, info->vdevice,
+				  binfo, sector_size, info);
+	if (err) {
+		xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
+				 info->xbdev->otherend);
+		return;
+	}
+
+	xenbus_switch_state(info->xbdev, XenbusStateConnected);
+
+	/* Kick pending requests. */
+	spin_lock_irq(&blkif_io_lock);
+	info->connected = BLKIF_STATE_CONNECTED;
+	kick_pending_request_queues(info);
+	spin_unlock_irq(&blkif_io_lock);
+
+	add_disk(info->gd);
+}
+
+/**
+ * Handle the change of state of the backend to Closing.  We must delete our
+ * device-layer structures now, to ensure that writes are flushed through to
+ * the backend.  Once is this done, we can switch to Closed in
+ * acknowledgement.
+ */
+static void blkfront_closing(struct xenbus_device *dev)
+{
+	struct blkfront_info *info = dev->dev.driver_data;
+	unsigned long flags;
+
+	dev_dbg(&dev->dev, "blkfront_closing: %s removed\n", dev->nodename);
+
+	if (info->rq == NULL)
+		goto out;
+
+	spin_lock_irqsave(&blkif_io_lock, flags);
+
+	del_gendisk(info->gd);
+
+	/* No more blkif_request(). */
+	blk_stop_queue(info->rq);
+
+	/* No more gnttab callback work. */
+	gnttab_cancel_free_callback(&info->callback);
+	spin_unlock_irqrestore(&blkif_io_lock, flags);
+
+	/* Flush gnttab callback work. Must be done with no locks held. */
+	flush_scheduled_work();
+
+	blk_cleanup_queue(info->rq);
+	info->rq = NULL;
+
+ out:
+	xenbus_frontend_closed(dev);
+}
+
+/**
+ * Callback received when the backend's state changes.
+ */
+static void backend_changed(struct xenbus_device *dev,
+			    enum xenbus_state backend_state)
+{
+	struct blkfront_info *info = dev->dev.driver_data;
+	struct block_device *bd;
+
+	dev_dbg(&dev->dev, "blkfront:backend_changed.\n");
+
+	switch (backend_state) {
+	case XenbusStateInitialising:
+	case XenbusStateInitWait:
+	case XenbusStateInitialised:
+	case XenbusStateUnknown:
+	case XenbusStateClosed:
+		break;
+
+	case XenbusStateConnected:
+		blkfront_connect(info);
+		break;
+
+	case XenbusStateClosing:
+		bd = bdget(info->dev);
+		if (bd == NULL)
+			xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
+
+		mutex_lock(&bd->bd_mutex);
+		if (info->users > 0)
+			xenbus_dev_error(dev, -EBUSY,
+					 "Device in use; refusing to close");
+		else
+			blkfront_closing(dev);
+		mutex_unlock(&bd->bd_mutex);
+		bdput(bd);
+		break;
+	}
+}
+
+static int blkfront_remove(struct xenbus_device *dev)
+{
+	struct blkfront_info *info = dev->dev.driver_data;
+
+	dev_dbg(&dev->dev, "blkfront_remove: %s removed\n", dev->nodename);
+
+	blkif_free(info, 0);
+
+	kfree(info);
+
+	return 0;
+}
+
+static int blkif_open(struct inode *inode, struct file *filep)
+{
+	struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
+	info->users++;
+	return 0;
+}
+
+static int blkif_release(struct inode *inode, struct file *filep)
+{
+	struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
+	info->users--;
+	if (info->users == 0) {
+		/* Check whether we have been instructed to close.  We will
+		   have ignored this request initially, as the device was
+		   still mounted. */
+		struct xenbus_device *dev = info->xbdev;
+		enum xenbus_state state = xenbus_read_driver_state(dev->otherend);
+
+		if (state == XenbusStateClosing)
+			blkfront_closing(dev);
+	}
+	return 0;
+}
+
+static struct block_device_operations xlvbd_block_fops =
+{
+	.owner = THIS_MODULE,
+	.open = blkif_open,
+	.release = blkif_release,
+};
+
+
+static struct xenbus_device_id blkfront_ids[] = {
+	{ "vbd" },
+	{ "" }
+};
+
+static struct xenbus_driver blkfront = {
+	.name = "vbd",
+	.owner = THIS_MODULE,
+	.ids = blkfront_ids,
+	.probe = blkfront_probe,
+	.remove = blkfront_remove,
+	.resume = blkfront_resume,
+	.otherend_changed = backend_changed,
+};
+
+static int __init xlblk_init(void)
+{
+	if (!is_running_on_xen())
+		return -ENODEV;
+
+	if (register_blkdev(XENVBD_MAJOR, DEV_NAME)) {
+		printk(KERN_WARNING "xen_blk: can't get major %d with name %s\n",
+		       XENVBD_MAJOR, DEV_NAME);
+		return -ENODEV;
+	}
+
+	return xenbus_register_frontend(&blkfront);
+}
+module_init(xlblk_init);
+
+
+static void xlblk_exit(void)
+{
+	return xenbus_unregister_driver(&blkfront);
+}
+module_exit(xlblk_exit);
+
+MODULE_DESCRIPTION("Xen virtual block device frontend");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_BLOCKDEV_MAJOR(XENVBD_MAJOR);
diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c
index 732ec63..9e7652d 100644
--- a/drivers/block/xsysace.c
+++ b/drivers/block/xsysace.c
@@ -91,6 +91,10 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 #include <linux/platform_device.h>
+#if defined(CONFIG_OF)
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#endif
 
 MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
 MODULE_DESCRIPTION("Xilinx SystemACE device driver");
@@ -158,6 +162,9 @@
 #define ACE_FIFO_SIZE (32)
 #define ACE_BUF_PER_SECTOR (ACE_SECTOR_SIZE / ACE_FIFO_SIZE)
 
+#define ACE_BUS_WIDTH_8  0
+#define ACE_BUS_WIDTH_16 1
+
 struct ace_reg_ops;
 
 struct ace_device {
@@ -188,7 +195,7 @@
 
 	/* Details of hardware device */
 	unsigned long physaddr;
-	void *baseaddr;
+	void __iomem *baseaddr;
 	int irq;
 	int bus_width;		/* 0 := 8 bit; 1 := 16 bit */
 	struct ace_reg_ops *reg_ops;
@@ -220,20 +227,20 @@
 /* 8 Bit bus width */
 static u16 ace_in_8(struct ace_device *ace, int reg)
 {
-	void *r = ace->baseaddr + reg;
+	void __iomem *r = ace->baseaddr + reg;
 	return in_8(r) | (in_8(r + 1) << 8);
 }
 
 static void ace_out_8(struct ace_device *ace, int reg, u16 val)
 {
-	void *r = ace->baseaddr + reg;
+	void __iomem *r = ace->baseaddr + reg;
 	out_8(r, val);
 	out_8(r + 1, val >> 8);
 }
 
 static void ace_datain_8(struct ace_device *ace)
 {
-	void *r = ace->baseaddr + 0x40;
+	void __iomem *r = ace->baseaddr + 0x40;
 	u8 *dst = ace->data_ptr;
 	int i = ACE_FIFO_SIZE;
 	while (i--)
@@ -243,7 +250,7 @@
 
 static void ace_dataout_8(struct ace_device *ace)
 {
-	void *r = ace->baseaddr + 0x40;
+	void __iomem *r = ace->baseaddr + 0x40;
 	u8 *src = ace->data_ptr;
 	int i = ACE_FIFO_SIZE;
 	while (i--)
@@ -458,7 +465,7 @@
 }
 
 /* Get the next read/write request; ending requests that we don't handle */
-struct request *ace_get_next_request(request_queue_t * q)
+struct request *ace_get_next_request(struct request_queue * q)
 {
 	struct request *req;
 
@@ -825,7 +832,7 @@
 /* ---------------------------------------------------------------------
  * Block ops
  */
-static void ace_request(request_queue_t * q)
+static void ace_request(struct request_queue * q)
 {
 	struct request *req;
 	struct ace_device *ace;
@@ -902,26 +909,17 @@
 	return 0;
 }
 
-static int ace_ioctl(struct inode *inode, struct file *filp,
-		     unsigned int cmd, unsigned long arg)
+static int ace_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
-	struct ace_device *ace = inode->i_bdev->bd_disk->private_data;
-	struct hd_geometry __user *geo = (struct hd_geometry __user *)arg;
-	struct hd_geometry g;
-	dev_dbg(ace->dev, "ace_ioctl()\n");
+	struct ace_device *ace = bdev->bd_disk->private_data;
 
-	switch (cmd) {
-	case HDIO_GETGEO:
-		g.heads = ace->cf_id.heads;
-		g.sectors = ace->cf_id.sectors;
-		g.cylinders = ace->cf_id.cyls;
-		g.start = 0;
-		return copy_to_user(geo, &g, sizeof(g)) ? -EFAULT : 0;
+	dev_dbg(ace->dev, "ace_getgeo()\n");
 
-	default:
-		return -ENOTTY;
-	}
-	return -ENOTTY;
+	geo->heads = ace->cf_id.heads;
+	geo->sectors = ace->cf_id.sectors;
+	geo->cylinders = ace->cf_id.cyls;
+
+	return 0;
 }
 
 static struct block_device_operations ace_fops = {
@@ -930,7 +928,7 @@
 	.release = ace_release,
 	.media_changed = ace_media_changed,
 	.revalidate_disk = ace_revalidate_disk,
-	.ioctl = ace_ioctl,
+	.getgeo = ace_getgeo,
 };
 
 /* --------------------------------------------------------------------
@@ -940,9 +938,11 @@
 {
 	u16 version;
 	u16 val;
-
 	int rc;
 
+	dev_dbg(ace->dev, "ace_setup(ace=0x%p)\n", ace);
+	dev_dbg(ace->dev, "physaddr=0x%lx irq=%i\n", ace->physaddr, ace->irq);
+
 	spin_lock_init(&ace->lock);
 	init_completion(&ace->id_completion);
 
@@ -953,15 +953,6 @@
 	if (!ace->baseaddr)
 		goto err_ioremap;
 
-	if (ace->irq != NO_IRQ) {
-		rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace);
-		if (rc) {
-			/* Failure - fall back to polled mode */
-			dev_err(ace->dev, "request_irq failed\n");
-			ace->irq = NO_IRQ;
-		}
-	}
-
 	/*
 	 * Initialize the state machine tasklet and stall timer
 	 */
@@ -991,7 +982,7 @@
 	snprintf(ace->gd->disk_name, 32, "xs%c", ace->id + 'a');
 
 	/* set bus width */
-	if (ace->bus_width == 1) {
+	if (ace->bus_width == ACE_BUS_WIDTH_16) {
 		/* 0x0101 should work regardless of endianess */
 		ace_out_le16(ace, ACE_BUSMODE, 0x0101);
 
@@ -1014,6 +1005,16 @@
 	ace_out(ace, ACE_CTRL, ACE_CTRL_FORCECFGMODE |
 		ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ);
 
+	/* Now we can hook up the irq handler */
+	if (ace->irq != NO_IRQ) {
+		rc = request_irq(ace->irq, ace_interrupt, 0, "systemace", ace);
+		if (rc) {
+			/* Failure - fall back to polled mode */
+			dev_err(ace->dev, "request_irq failed\n");
+			ace->irq = NO_IRQ;
+		}
+	}
+
 	/* Enable interrupts */
 	val = ace_in(ace, ACE_CTRL);
 	val |= ACE_CTRL_DATABUFRDYIRQ | ACE_CTRL_ERRORIRQ;
@@ -1033,16 +1034,14 @@
 
 	return 0;
 
-      err_read:
+err_read:
 	put_disk(ace->gd);
-      err_alloc_disk:
+err_alloc_disk:
 	blk_cleanup_queue(ace->queue);
-      err_blk_initq:
+err_blk_initq:
 	iounmap(ace->baseaddr);
-	if (ace->irq != NO_IRQ)
-		free_irq(ace->irq, ace);
-      err_ioremap:
-	printk(KERN_INFO "xsysace: error initializing device at 0x%lx\n",
+err_ioremap:
+	dev_info(ace->dev, "xsysace: error initializing device at 0x%lx\n",
 	       ace->physaddr);
 	return -ENOMEM;
 }
@@ -1065,98 +1064,222 @@
 	iounmap(ace->baseaddr);
 }
 
+static int __devinit
+ace_alloc(struct device *dev, int id, unsigned long physaddr,
+	  int irq, int bus_width)
+{
+	struct ace_device *ace;
+	int rc;
+	dev_dbg(dev, "ace_alloc(%p)\n", dev);
+
+	if (!physaddr) {
+		rc = -ENODEV;
+		goto err_noreg;
+	}
+
+	/* Allocate and initialize the ace device structure */
+	ace = kzalloc(sizeof(struct ace_device), GFP_KERNEL);
+	if (!ace) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+
+	ace->dev = dev;
+	ace->id = id;
+	ace->physaddr = physaddr;
+	ace->irq = irq;
+	ace->bus_width = bus_width;
+
+	/* Call the setup code */
+	rc = ace_setup(ace);
+	if (rc)
+		goto err_setup;
+
+	dev_set_drvdata(dev, ace);
+	return 0;
+
+err_setup:
+	dev_set_drvdata(dev, NULL);
+	kfree(ace);
+err_alloc:
+err_noreg:
+	dev_err(dev, "could not initialize device, err=%i\n", rc);
+	return rc;
+}
+
+static void __devexit ace_free(struct device *dev)
+{
+	struct ace_device *ace = dev_get_drvdata(dev);
+	dev_dbg(dev, "ace_free(%p)\n", dev);
+
+	if (ace) {
+		ace_teardown(ace);
+		dev_set_drvdata(dev, NULL);
+		kfree(ace);
+	}
+}
+
 /* ---------------------------------------------------------------------
  * Platform Bus Support
  */
 
-static int __devinit ace_probe(struct device *device)
+static int __devinit ace_probe(struct platform_device *dev)
 {
-	struct platform_device *dev = to_platform_device(device);
-	struct ace_device *ace;
+	unsigned long physaddr = 0;
+	int bus_width = ACE_BUS_WIDTH_16; /* FIXME: should not be hard coded */
+	int id = dev->id;
+	int irq = NO_IRQ;
 	int i;
 
-	dev_dbg(device, "ace_probe(%p)\n", device);
-
-	/*
-	 * Allocate the ace device structure
-	 */
-	ace = kzalloc(sizeof(struct ace_device), GFP_KERNEL);
-	if (!ace)
-		goto err_alloc;
-
-	ace->dev = device;
-	ace->id = dev->id;
-	ace->irq = NO_IRQ;
+	dev_dbg(&dev->dev, "ace_probe(%p)\n", dev);
 
 	for (i = 0; i < dev->num_resources; i++) {
 		if (dev->resource[i].flags & IORESOURCE_MEM)
-			ace->physaddr = dev->resource[i].start;
+			physaddr = dev->resource[i].start;
 		if (dev->resource[i].flags & IORESOURCE_IRQ)
-			ace->irq = dev->resource[i].start;
+			irq = dev->resource[i].start;
 	}
 
-	/* FIXME: Should get bus_width from the platform_device struct */
-	ace->bus_width = 1;
-
-	dev_set_drvdata(&dev->dev, ace);
-
 	/* Call the bus-independant setup code */
-	if (ace_setup(ace) != 0)
-		goto err_setup;
-
-	return 0;
-
-      err_setup:
-	dev_set_drvdata(&dev->dev, NULL);
-	kfree(ace);
-      err_alloc:
-	printk(KERN_ERR "xsysace: could not initialize device\n");
-	return -ENOMEM;
+	return ace_alloc(&dev->dev, id, physaddr, irq, bus_width);
 }
 
 /*
  * Platform bus remove() method
  */
-static int __devexit ace_remove(struct device *device)
+static int __devexit ace_remove(struct platform_device *dev)
 {
-	struct ace_device *ace = dev_get_drvdata(device);
-
-	dev_dbg(device, "ace_remove(%p)\n", device);
-
-	if (ace) {
-		ace_teardown(ace);
-		kfree(ace);
-	}
-
+	ace_free(&dev->dev);
 	return 0;
 }
 
-static struct device_driver ace_driver = {
-	.name = "xsysace",
-	.bus = &platform_bus_type,
+static struct platform_driver ace_platform_driver = {
 	.probe = ace_probe,
 	.remove = __devexit_p(ace_remove),
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = "xsysace",
+	},
 };
 
 /* ---------------------------------------------------------------------
+ * OF_Platform Bus Support
+ */
+
+#if defined(CONFIG_OF)
+static int __devinit
+ace_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+	struct resource res;
+	unsigned long physaddr;
+	const u32 *id;
+	int irq, bus_width, rc;
+
+	dev_dbg(&op->dev, "ace_of_probe(%p, %p)\n", op, match);
+
+	/* device id */
+	id = of_get_property(op->node, "port-number", NULL);
+
+	/* physaddr */
+	rc = of_address_to_resource(op->node, 0, &res);
+	if (rc) {
+		dev_err(&op->dev, "invalid address\n");
+		return rc;
+	}
+	physaddr = res.start;
+
+	/* irq */
+	irq = irq_of_parse_and_map(op->node, 0);
+
+	/* bus width */
+	bus_width = ACE_BUS_WIDTH_16;
+	if (of_find_property(op->node, "8-bit", NULL))
+		bus_width = ACE_BUS_WIDTH_8;
+
+	/* Call the bus-independant setup code */
+	return ace_alloc(&op->dev, id ? *id : 0, physaddr, irq, bus_width);
+}
+
+static int __devexit ace_of_remove(struct of_device *op)
+{
+	ace_free(&op->dev);
+	return 0;
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id __devinit ace_of_match[] = {
+	{ .compatible = "xilinx,xsysace", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ace_of_match);
+
+static struct of_platform_driver ace_of_driver = {
+	.owner = THIS_MODULE,
+	.name = "xsysace",
+	.match_table = ace_of_match,
+	.probe = ace_of_probe,
+	.remove = __devexit_p(ace_of_remove),
+	.driver = {
+		.name = "xsysace",
+	},
+};
+
+/* Registration helpers to keep the number of #ifdefs to a minimum */
+static inline int __init ace_of_register(void)
+{
+	pr_debug("xsysace: registering OF binding\n");
+	return of_register_platform_driver(&ace_of_driver);
+}
+
+static inline void __exit ace_of_unregister(void)
+{
+	of_unregister_platform_driver(&ace_of_driver);
+}
+#else /* CONFIG_OF */
+/* CONFIG_OF not enabled; do nothing helpers */
+static inline int __init ace_of_register(void) { return 0; }
+static inline void __exit ace_of_unregister(void) { }
+#endif /* CONFIG_OF */
+
+/* ---------------------------------------------------------------------
  * Module init/exit routines
  */
 static int __init ace_init(void)
 {
+	int rc;
+
 	ace_major = register_blkdev(ace_major, "xsysace");
 	if (ace_major <= 0) {
-		printk(KERN_WARNING "xsysace: register_blkdev() failed\n");
-		return ace_major;
+		rc = -ENOMEM;
+		goto err_blk;
 	}
 
-	pr_debug("Registering Xilinx SystemACE driver, major=%i\n", ace_major);
-	return driver_register(&ace_driver);
+	rc = ace_of_register();
+	if (rc)
+		goto err_of;
+
+	pr_debug("xsysace: registering platform binding\n");
+	rc = platform_driver_register(&ace_platform_driver);
+	if (rc)
+		goto err_plat;
+
+	pr_info("Xilinx SystemACE device driver, major=%i\n", ace_major);
+	return 0;
+
+err_plat:
+	ace_of_unregister();
+err_of:
+	unregister_blkdev(ace_major, "xsysace");
+err_blk:
+	printk(KERN_ERR "xsysace: registration failed; err=%i\n", rc);
+	return rc;
 }
 
 static void __exit ace_exit(void)
 {
 	pr_debug("Unregistering Xilinx SystemACE driver\n");
-	driver_unregister(&ace_driver);
+	platform_driver_unregister(&ace_platform_driver);
+	ace_of_unregister();
 	unregister_blkdev(ace_major, "xsysace");
 }
 
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
index e40fa98..2d5853c 100644
--- a/drivers/block/z2ram.c
+++ b/drivers/block/z2ram.c
@@ -67,7 +67,7 @@
 static struct block_device_operations z2_fops;
 static struct gendisk *z2ram_gendisk;
 
-static void do_z2_request(request_queue_t *q)
+static void do_z2_request(struct request_queue *q)
 {
 	struct request *req;
 	while ((req = elv_next_request(q)) != NULL) {
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
index 59b0548..98a9cde 100644
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -691,15 +691,18 @@
 					urb->iso_frame_desc[i].offset,
 					urb->iso_frame_desc[i].actual_length);
 	
-			if (!urb->iso_frame_desc[i].status)
+			if (!urb->iso_frame_desc[i].status) {
+				husb->hdev->stat.byte_rx += urb->iso_frame_desc[i].actual_length;
 				hci_recv_fragment(husb->hdev, _urb->type, 
 					urb->transfer_buffer + urb->iso_frame_desc[i].offset,
 					urb->iso_frame_desc[i].actual_length);
+			}
 		}
 #else
 		;
 #endif
 	} else {
+		husb->hdev->stat.byte_rx += count;
 		err = hci_recv_fragment(husb->hdev, _urb->type, urb->transfer_buffer, count);
 		if (err < 0) { 
 			BT_ERR("%s corrupted packet: type %d count %d",
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 499019b..79245714 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -1032,6 +1032,10 @@
 	check_disk_change(ip->i_bdev);
 	return 0;
 err_release:
+	if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) {
+		cdi->ops->lock_door(cdi, 0);
+		cdinfo(CD_OPEN, "door unlocked.\n");
+	}
 	cdi->ops->release(cdi);
 err:
 	cdi->use_count--;
@@ -2094,7 +2098,7 @@
 static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
 			       int lba, int nframes)
 {
-	request_queue_t *q = cdi->disk->queue;
+	struct request_queue *q = cdi->disk->queue;
 	struct request *rq;
 	struct bio *bio;
 	unsigned int len;
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index 44cd7b2..880b5dc 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -56,30 +56,6 @@
 #define VIOCD_KERN_WARNING		KERN_WARNING "viocd: "
 #define VIOCD_KERN_INFO			KERN_INFO "viocd: "
 
-struct viocdlpevent {
-	struct HvLpEvent	event;
-	u32			reserved;
-	u16			version;
-	u16			sub_result;
-	u16			disk;
-	u16			flags;
-	u32			token;
-	u64			offset;		/* On open, max number of disks */
-	u64			len;		/* On open, size of the disk */
-	u32			block_size;	/* Only set on open */
-	u32			media_size;	/* Only set on open */
-};
-
-enum viocdsubtype {
-	viocdopen = 0x0001,
-	viocdclose = 0x0002,
-	viocdread = 0x0003,
-	viocdwrite = 0x0004,
-	viocdlockdoor = 0x0005,
-	viocdgetinfo = 0x0006,
-	viocdcheck = 0x0007
-};
-
 /*
  * Should probably make this a module parameter....sigh
  */
@@ -131,22 +107,13 @@
 /* These are our internal structures for keeping track of devices */
 static int viocd_numdev;
 
-struct cdrom_info {
-	char	rsrcname[10];
-	char	type[4];
-	char	model[3];
-};
-/*
- * This needs to be allocated since it is passed to the
- * Hypervisor and we may be a module.
- */
-static struct cdrom_info *viocd_unitinfo;
-static dma_addr_t unitinfo_dmaaddr;
-
 struct disk_info {
 	struct gendisk			*viocd_disk;
 	struct cdrom_device_info	viocd_info;
 	struct device			*dev;
+	const char			*rsrcname;
+	const char			*type;
+	const char			*model;
 };
 static struct disk_info viocd_diskinfo[VIOCD_MAX_CD];
 
@@ -164,9 +131,9 @@
 	for (i = 0; i < viocd_numdev; i++) {
 		seq_printf(m, "viocd device %d is iSeries resource %10.10s"
 				"type %4.4s, model %3.3s\n",
-				i, viocd_unitinfo[i].rsrcname,
-				viocd_unitinfo[i].type,
-				viocd_unitinfo[i].model);
+				i, viocd_diskinfo[i].rsrcname,
+				viocd_diskinfo[i].type,
+				viocd_diskinfo[i].model);
 	}
 	return 0;
 }
@@ -216,61 +183,6 @@
 	.media_changed =	viocd_blk_media_changed,
 };
 
-/* Get info on CD devices from OS/400 */
-static void __init get_viocd_info(void)
-{
-	HvLpEvent_Rc hvrc;
-	int i;
-	struct viocd_waitevent we;
-
-	viocd_unitinfo = dma_alloc_coherent(iSeries_vio_dev,
-			sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
-			&unitinfo_dmaaddr, GFP_ATOMIC);
-	if (viocd_unitinfo == NULL) {
-		printk(VIOCD_KERN_WARNING "error allocating unitinfo\n");
-		return;
-	}
-
-	memset(viocd_unitinfo, 0, sizeof(*viocd_unitinfo) * VIOCD_MAX_CD);
-
-	init_completion(&we.com);
-
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_cdio | viocdgetinfo,
-			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			(u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0,
-			sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, 0);
-	if (hvrc != HvLpEvent_Rc_Good) {
-		printk(VIOCD_KERN_WARNING "cdrom error sending event. rc %d\n",
-				(int)hvrc);
-		goto error_ret;
-	}
-
-	wait_for_completion(&we.com);
-
-	if (we.rc) {
-		const struct vio_error_entry *err =
-			vio_lookup_rc(viocd_err_table, we.sub_result);
-		printk(VIOCD_KERN_WARNING "bad rc %d:0x%04X on getinfo: %s\n",
-				we.rc, we.sub_result, err->msg);
-		goto error_ret;
-	}
-
-	for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++)
-		viocd_numdev++;
-
-error_ret:
-	if (viocd_numdev == 0) {
-		dma_free_coherent(iSeries_vio_dev,
-				sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
-				viocd_unitinfo, unitinfo_dmaaddr);
-		viocd_unitinfo = NULL;
-	}
-}
-
 static int viocd_open(struct cdrom_device_info *cdi, int purpose)
 {
         struct disk_info *diskinfo = cdi->handle;
@@ -398,7 +310,7 @@
 
 static int rwreq;
 
-static void do_viocd_request(request_queue_t *q)
+static void do_viocd_request(struct request_queue *q)
 {
 	struct request *req;
 
@@ -581,7 +493,6 @@
 					bevent->block_size / 512);
 		}
 		/* FALLTHROUGH !! */
-	case viocdgetinfo:
 	case viocdlockdoor:
 		pwe = (struct viocd_waitevent *)event->xCorrelationToken;
 return_complete:
@@ -665,22 +576,30 @@
 	int deviceno;
 	struct disk_info *d;
 	struct cdrom_device_info *c;
-	struct cdrom_info *ci;
 	struct request_queue *q;
+	struct device_node *node = vdev->dev.archdata.of_node;
 
 	deviceno = vdev->unit_address;
-	if (deviceno >= viocd_numdev)
+	if (deviceno > VIOCD_MAX_CD)
+		return -ENODEV;
+	if (!node)
 		return -ENODEV;
 
+	if (deviceno >= viocd_numdev)
+		viocd_numdev = deviceno + 1;
+
 	d = &viocd_diskinfo[deviceno];
+	d->rsrcname = of_get_property(node, "linux,vio_rsrcname", NULL);
+	d->type = of_get_property(node, "linux,vio_type", NULL);
+	d->model = of_get_property(node, "linux,vio_model", NULL);
+
 	c = &d->viocd_info;
-	ci = &viocd_unitinfo[deviceno];
 
 	c->ops = &viocd_dops;
 	c->speed = 4;
 	c->capacity = 1;
 	c->handle = d;
-	c->mask = ~find_capability(ci->type);
+	c->mask = ~find_capability(d->type);
 	sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno);
 
 	if (register_cdrom(c) != 0) {
@@ -690,7 +609,7 @@
 	}
 	printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s "
 			"type %4.4s, model %3.3s\n",
-			c->name, ci->rsrcname, ci->type, ci->model);
+			c->name, d->rsrcname, d->type, d->model);
 	q = blk_init_queue(do_viocd_request, &viocd_reqlock);
 	if (q == NULL) {
 		printk(VIOCD_KERN_WARNING "Cannot allocate queue for %s!\n",
@@ -799,8 +718,6 @@
 	/* Initialize our request handler */
 	vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event);
 
-	get_viocd_info();
-
 	spin_lock_init(&viocd_reqlock);
 
 	ret = vio_register_driver(&viocd_driver);
@@ -816,9 +733,6 @@
 	return 0;
 
 out_free_info:
-	dma_free_coherent(iSeries_vio_dev,
-			sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
-			viocd_unitinfo, unitinfo_dmaaddr);
 	vio_clearHandler(viomajorsubtype_cdio);
 	viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);
 out_unregister:
@@ -830,10 +744,6 @@
 {
 	remove_proc_entry("iSeries/viocd", NULL);
 	vio_unregister_driver(&viocd_driver);
-	if (viocd_unitinfo != NULL)
-		dma_free_coherent(iSeries_vio_dev,
-				sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
-				viocd_unitinfo, unitinfo_dmaaddr);
 	viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2);
 	vio_clearHandler(viomajorsubtype_cdio);
 	unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index d8d7125..b391776 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -130,6 +130,7 @@
 config CYCLADES
 	tristate "Cyclades async mux support"
 	depends on SERIAL_NONSTANDARD && (PCI || ISA)
+	select FW_LOADER
 	---help---
 	  This driver supports Cyclades Z and Y multiserial boards.
 	  You would need something like this to connect more than two modems to
@@ -185,7 +186,7 @@
 
 config MOXA_INTELLIO
 	tristate "Moxa Intellio support"
-	depends on SERIAL_NONSTANDARD
+	depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI)
 	help
 	  Say Y here if you have a Moxa Intellio multiport serial card.
 
@@ -241,7 +242,7 @@
 
 config SYNCLINKMP
 	tristate "SyncLink Multiport support"
-	depends on SERIAL_NONSTANDARD
+	depends on SERIAL_NONSTANDARD && PCI
 	help
 	  Enable support for the SyncLink Multiport (2 or 4 ports)
 	  serial adapter, running asynchronous and HDLC communications up
@@ -372,39 +373,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called istallion.
 
-config SERIAL_DEC
-	bool "DECstation serial support"
-	depends on MACH_DECSTATION
-	default y
-	help
-	  This selects whether you want to be asked about drivers for
-	  DECstation serial ports.
-
-	  Note that the answer to this question won't directly affect the
-	  kernel: saying N will just cause the configurator to skip all
-	  the questions about DECstation serial ports.
-
-config SERIAL_DEC_CONSOLE
-	bool "Support for console on a DECstation serial port"
-	depends on SERIAL_DEC
-	default y
-	help
-	  If you say Y here, it will be possible to use a serial port as the
-	  system console (the system console is the device which receives all
-	  kernel messages and warnings and which allows logins in single user
-	  mode).  Note that the firmware uses ttyS0 as the serial console on
-	  the Maxine and ttyS2 on the others.
-
-	  If unsure, say Y.
-
-config ZS
-	bool "Z85C30 Serial Support"
-	depends on SERIAL_DEC
-	default y
-	help
-	  Documentation on the Zilog 85C350 serial communications controller
-	  is downloadable at <http://www.zilog.com/pdfs/serial/z85c30.pdf>
-
 config A2232
 	tristate "Commodore A2232 serial support (EXPERIMENTAL)"
 	depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP
@@ -637,6 +605,14 @@
 	help
 	  Toshiba's Cell Reference Set Beat Console device driver
 
+config HVC_XEN
+	bool "Xen Hypervisor Console support"
+	depends on XEN
+	select HVC_DRIVER
+	default y
+	help
+	  Xen virtual console device driver
+
 config HVCS
 	tristate "IBM Hypervisor Virtual Console Server support"
 	depends on PPC_PSERIES
@@ -751,7 +727,7 @@
 
 config RTC
 	tristate "Enhanced Real Time Clock Support"
-	depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH && !S390
+	depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390
 	---help---
 	  If you say Y here and create a character special file /dev/rtc with
 	  major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -775,6 +751,28 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called rtc.
 
+config JS_RTC
+	tristate "Enhanced Real Time Clock Support"
+	depends on SPARC32 && PCI
+	---help---
+	  If you say Y here and create a character special file /dev/rtc with
+	  major number 10 and minor number 135 using mknod ("man mknod"), you
+	  will get access to the real time clock (or hardware clock) built
+	  into your computer.
+
+	  Every PC has such a clock built in. It can be used to generate
+	  signals from as low as 1Hz up to 8192Hz, and can also be used
+	  as a 24 hour alarm. It reports status information via the file
+	  /proc/driver/rtc and its behaviour is set by various ioctls on
+	  /dev/rtc.
+
+	  If you think you have a use for such a device (such as periodic data
+	  sampling), then say Y here, and read <file:Documentation/rtc.txt>
+	  for details.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called js-rtc.
+
 config SGI_DS1286
 	tristate "SGI DS1286 RTC support"
 	depends on SGI_IP22
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index f2996a9..c78ff26 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -42,12 +42,14 @@
 obj-$(CONFIG_N_HDLC)		+= n_hdlc.o
 obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
 obj-$(CONFIG_SX)		+= sx.o generic_serial.o
+obj-$(CONFIG_LGUEST_GUEST)	+= hvc_lguest.o
 obj-$(CONFIG_RIO)		+= rio/ generic_serial.o
 obj-$(CONFIG_HVC_CONSOLE)	+= hvc_vio.o hvsi.o
 obj-$(CONFIG_HVC_ISERIES)	+= hvc_iseries.o
 obj-$(CONFIG_HVC_RTAS)		+= hvc_rtas.o
 obj-$(CONFIG_HVC_BEAT)		+= hvc_beat.o
 obj-$(CONFIG_HVC_DRIVER)	+= hvc_console.o
+obj-$(CONFIG_HVC_XEN)		+= hvc_xen.o
 obj-$(CONFIG_RAW_DRIVER)	+= raw.o
 obj-$(CONFIG_SGI_SNSC)		+= snsc.o snsc_event.o
 obj-$(CONFIG_MSPEC)		+= mspec.o
@@ -95,7 +97,6 @@
 obj-$(CONFIG_GPIO_TB0219)	+= tb0219.o
 obj-$(CONFIG_TELCLOCK)		+= tlclk.o
 
-obj-$(CONFIG_WATCHDOG)		+= watchdog/
 obj-$(CONFIG_MWAVE)		+= mwave/
 obj-$(CONFIG_AGP)		+= agp/
 obj-$(CONFIG_DRM)		+= drm/
@@ -105,6 +106,11 @@
 obj-$(CONFIG_HANGCHECK_TIMER)	+= hangcheck-timer.o
 obj-$(CONFIG_TCG_TPM)		+= tpm/
 
+obj-$(CONFIG_PS3_FLASH)		+= ps3flash.o
+
+obj-$(CONFIG_JS_RTC)		+= js-rtc.o
+js-rtc-y = rtc.o
+
 # Files generated that shall be removed upon make clean
 clean-files := consolemap_deftbl.c defkeymap.c
 
@@ -123,7 +129,7 @@
 
 ifdef GENERATE_KEYMAP
 
-$(obj)/defkeymap.c $(obj)/%.c: $(src)/%.map
+$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map
 	loadkeys --mktable $< > $@.tmp
 	sed -e 's/^static *//' $@.tmp > $@
 	rm $@.tmp
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
index a9f9c48..713533d 100644
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -50,7 +50,7 @@
 
 config AGP_AMD
 	tristate "AMD Irongate, 761, and 762 chipset support"
-	depends on AGP && X86_32
+	depends on AGP && (X86_32 || ALPHA)
 	help
 	  This option gives you AGP support for the GLX component of
 	  X on AMD Irongate, 761, and 762 chipsets.
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 35ab1a9..8955e7f 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -176,7 +176,7 @@
 #define I830_GMCH_MEM_MASK		0x1
 #define I830_GMCH_MEM_64M		0x1
 #define I830_GMCH_MEM_128M		0
-#define I830_GMCH_GMS_MASK		0xF0
+#define I830_GMCH_GMS_MASK		0x70
 #define I830_GMCH_GMS_DISABLED		0x00
 #define I830_GMCH_GMS_LOCAL		0x10
 #define I830_GMCH_GMS_STOLEN_512	0x20
@@ -190,6 +190,7 @@
 #define INTEL_I830_ERRSTS	0x92
 
 /* Intel 855GM/852GM registers */
+#define I855_GMCH_GMS_MASK		0xF0
 #define I855_GMCH_GMS_STOLEN_0M		0x0
 #define I855_GMCH_GMS_STOLEN_1M		(0x1 << 4)
 #define I855_GMCH_GMS_STOLEN_4M		(0x2 << 4)
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index df0ddf1..f60bca7 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -223,6 +223,8 @@
 	pci_read_config_dword(agp_bridge->dev, AMD_MMBASE, &temp);
 	temp = (temp & PCI_BASE_ADDRESS_MEM_MASK);
 	amd_irongate_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096);
+	if (!amd_irongate_private.registers)
+		return -ENOMEM;
 
 	/* Write out the address of the gatt table */
 	writel(agp_bridge->gatt_bus_addr, amd_irongate_private.registers+AMD_ATTBASE);
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
index 780e59e..2d46b71 100644
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -123,21 +123,16 @@
 
 	for (i = 0; i < nr_tables; i++) {
 		entry = kzalloc(sizeof(struct ati_page_map), GFP_KERNEL);
+		tables[i] = entry;
 		if (entry == NULL) {
-			while (i > 0) {
-				kfree(tables[i-1]);
-				i--;
-			}
-			kfree(tables);
 			retval = -ENOMEM;
 			break;
 		}
-		tables[i] = entry;
 		retval = ati_create_page_map(entry);
 		if (retval != 0)
 			break;
 	}
-	ati_generic_private.num_tables = nr_tables;
+	ati_generic_private.num_tables = i;
 	ati_generic_private.gatt_pages = tables;
 
 	if (retval != 0)
@@ -218,6 +213,9 @@
 	temp = (temp & 0xfffff000);
 	ati_generic_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096);
 
+	if (!ati_generic_private.registers)
+		return -ENOMEM;
+
 	if (is_r200())
 		pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000);
 	else
diff --git a/drivers/char/agp/compat_ioctl.c b/drivers/char/agp/compat_ioctl.c
index fcb4b1b..ecd4248 100644
--- a/drivers/char/agp/compat_ioctl.c
+++ b/drivers/char/agp/compat_ioctl.c
@@ -28,6 +28,7 @@
 
 #include <linux/kernel.h>
 #include <linux/pci.h>
+#include <linux/fs.h>
 #include <linux/agpgart.h>
 #include <asm/uaccess.h>
 #include "agp.h"
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c
index df8da72..d78cd09 100644
--- a/drivers/char/agp/efficeon-agp.c
+++ b/drivers/char/agp/efficeon-agp.c
@@ -375,6 +375,7 @@
 	if (!r->start && r->end) {
 		if (pci_assign_resource(pdev, 0)) {
 			printk(KERN_ERR PFX "could not assign resource 0\n");
+			agp_put_bridge(bridge);
 			return -ENODEV;
 		}
 	}
@@ -386,6 +387,7 @@
 	*/
 	if (pci_enable_device(pdev)) {
 		printk(KERN_ERR PFX "Unable to Enable PCI device\n");
+		agp_put_bridge(bridge);
 		return -ENODEV;
 	}
 
diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c
index c7ed617..7791e98 100644
--- a/drivers/char/agp/frontend.c
+++ b/drivers/char/agp/frontend.c
@@ -37,6 +37,7 @@
 #include <linux/agpgart.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
+#include <linux/fs.h>
 #include <linux/sched.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index d535c40..3db4f40 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -1170,7 +1170,6 @@
 	map_page_into_agp(page);
 
 	get_page(page);
-	SetPageLocked(page);
 	atomic_inc(&agp_bridge->current_memory_agp);
 	return page_address(page);
 }
@@ -1187,7 +1186,6 @@
 	page = virt_to_page(addr);
 	unmap_page_from_agp(page);
 	put_page(page);
-	unlock_page(page);
 	free_page((unsigned long)addr);
 	atomic_dec(&agp_bridge->current_memory_agp);
 }
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
index bcdb149..313a133 100644
--- a/drivers/char/agp/hp-agp.c
+++ b/drivers/char/agp/hp-agp.c
@@ -221,6 +221,7 @@
 	if (cap != PCI_CAP_ID_AGP) {
 		printk(KERN_ERR PFX "Invalid capability ID 0x%02x at 0x%x\n",
 		       cap, hp->lba_cap_offset);
+		iounmap(hp->lba_regs);
 		return -ENODEV;
 	}
 
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index 53354bf..75d2aca 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -249,6 +249,10 @@
 	num_entries = A_SIZE_8(temp)->num_entries;
 
 	i460.gatt = ioremap(INTEL_I460_ATTBASE, PAGE_SIZE << page_order);
+	if (!i460.gatt) {
+		printk(KERN_ERR PFX "ioremap failed\n");
+		return -ENOMEM;
+	}
 
 	/* These are no good, the should be removed from the agp_bridge strucure... */
 	agp_bridge->gatt_table_real = NULL;
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index a124060..141ca17 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -20,7 +20,9 @@
 #define PCI_DEVICE_ID_INTEL_82965G_IG       0x29A2
 #define PCI_DEVICE_ID_INTEL_82965GM_HB      0x2A00
 #define PCI_DEVICE_ID_INTEL_82965GM_IG      0x2A02
+#define PCI_DEVICE_ID_INTEL_82965GME_HB     0x2A10
 #define PCI_DEVICE_ID_INTEL_82965GME_IG     0x2A12
+#define PCI_DEVICE_ID_INTEL_82945GME_HB     0x27AC
 #define PCI_DEVICE_ID_INTEL_82945GME_IG     0x27AE
 #define PCI_DEVICE_ID_INTEL_G33_HB          0x29C0
 #define PCI_DEVICE_ID_INTEL_G33_IG          0x29C2
@@ -33,7 +35,8 @@
                  agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_1_HB || \
                  agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \
                  agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \
-                 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB)
+                 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \
+                 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB)
 
 #define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \
 		agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \
@@ -213,7 +216,6 @@
 	}
 	global_flush_tlb();
 	get_page(page);
-	SetPageLocked(page);
 	atomic_inc(&agp_bridge->current_memory_agp);
 	return page_address(page);
 }
@@ -229,7 +231,6 @@
 	change_page_attr(page, 4, PAGE_KERNEL);
 	global_flush_tlb();
 	put_page(page);
-	unlock_page(page);
 	__free_pages(page, 2);
 	atomic_dec(&agp_bridge->current_memory_agp);
 }
@@ -505,7 +506,7 @@
 			break;
 		}
 	} else {
-		switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
+		switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
 		case I855_GMCH_GMS_STOLEN_1M:
 			gtt_entries = MB(1) - KB(size);
 			break;
@@ -527,6 +528,7 @@
 			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
 			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
 			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB ||
+			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB ||
 			    IS_I965 || IS_G33)
 				gtt_entries = MB(48) - KB(size);
 			else
@@ -538,6 +540,7 @@
 			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
 			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
 			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB ||
+			    agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB ||
 			    IS_I965 || IS_G33)
 				gtt_entries = MB(64) - KB(size);
 			else
@@ -911,6 +914,7 @@
 	struct aper_size_info_fixed *size;
 	int num_entries;
 	u32 temp, temp2;
+	int gtt_map_size = 256 * 1024;
 
 	size = agp_bridge->current_size;
 	page_order = size->page_order;
@@ -920,15 +924,19 @@
 	pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
 	pci_read_config_dword(intel_private.pcidev, I915_PTEADDR,&temp2);
 
-	intel_private.gtt = ioremap(temp2, 256 * 1024);
+	if (IS_G33)
+	    gtt_map_size = 1024 * 1024; /* 1M on G33 */
+	intel_private.gtt = ioremap(temp2, gtt_map_size);
 	if (!intel_private.gtt)
 		return -ENOMEM;
 
 	temp &= 0xfff80000;
 
 	intel_private.registers = ioremap(temp,128 * 4096);
-	if (!intel_private.registers)
+	if (!intel_private.registers) {
+		iounmap(intel_private.gtt);
 		return -ENOMEM;
+	}
 
 	temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
 	global_cache_flush();	/* FIXME: ? */
@@ -982,13 +990,15 @@
        temp &= 0xfff00000;
        intel_private.gtt = ioremap((temp + (512 * 1024)) , 512 * 1024);
 
-       if (!intel_private.gtt)
-               return -ENOMEM;
+	if (!intel_private.gtt)
+		return -ENOMEM;
 
 
        intel_private.registers = ioremap(temp,128 * 4096);
-       if (!intel_private.registers)
-               return -ENOMEM;
+       if (!intel_private.registers) {
+		iounmap(intel_private.gtt);
+		return -ENOMEM;
+	}
 
        temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
        global_cache_flush();   /* FIXME: ? */
@@ -1848,9 +1858,9 @@
 		NULL, &intel_915_driver },
 	{ PCI_DEVICE_ID_INTEL_82945G_HB, PCI_DEVICE_ID_INTEL_82945G_IG, 0, "945G",
 		NULL, &intel_915_driver },
-	{ PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, 1, "945GM",
+	{ PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, 0, "945GM",
 		NULL, &intel_915_driver },
-	{ PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, 0, "945GME",
+	{ PCI_DEVICE_ID_INTEL_82945GME_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, 0, "945GME",
 		NULL, &intel_915_driver },
 	{ PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, 0, "946GZ",
 		NULL, &intel_i965_driver },
@@ -1860,9 +1870,9 @@
 		NULL, &intel_i965_driver },
 	{ PCI_DEVICE_ID_INTEL_82965G_HB, PCI_DEVICE_ID_INTEL_82965G_IG, 0, "965G",
 		NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, 1, "965GM",
+	{ PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, 0, "965GM",
 		NULL, &intel_i965_driver },
-	{ PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, 0, "965GME/GLE",
+	{ PCI_DEVICE_ID_INTEL_82965GME_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, 0, "965GME/GLE",
 		NULL, &intel_i965_driver },
 	{ PCI_DEVICE_ID_INTEL_7505_0, 0, 0, "E7505", &intel_7505_driver, NULL },
 	{ PCI_DEVICE_ID_INTEL_7205_0, 0, 0, "E7205", &intel_7505_driver, NULL },
@@ -2051,11 +2061,13 @@
 	ID(PCI_DEVICE_ID_INTEL_82915GM_HB),
 	ID(PCI_DEVICE_ID_INTEL_82945G_HB),
 	ID(PCI_DEVICE_ID_INTEL_82945GM_HB),
+	ID(PCI_DEVICE_ID_INTEL_82945GME_HB),
 	ID(PCI_DEVICE_ID_INTEL_82946GZ_HB),
 	ID(PCI_DEVICE_ID_INTEL_82965G_1_HB),
 	ID(PCI_DEVICE_ID_INTEL_82965Q_HB),
 	ID(PCI_DEVICE_ID_INTEL_82965G_HB),
 	ID(PCI_DEVICE_ID_INTEL_82965GM_HB),
+	ID(PCI_DEVICE_ID_INTEL_82965GME_HB),
 	ID(PCI_DEVICE_ID_INTEL_G33_HB),
 	ID(PCI_DEVICE_ID_INTEL_Q35_HB),
 	ID(PCI_DEVICE_ID_INTEL_Q33_HB),
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index 6cd7373..225ed2a 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -157,6 +157,9 @@
 	nvidia_private.aperture =
 		(volatile u32 __iomem *) ioremap(apbase, 33 * PAGE_SIZE);
 
+	if (!nvidia_private.aperture)
+		return -ENOMEM;
+
 	return 0;
 }
 
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
index cda608c..98cf8ab 100644
--- a/drivers/char/agp/sgi-agp.c
+++ b/drivers/char/agp/sgi-agp.c
@@ -51,7 +51,6 @@
 		return NULL;
 
 	get_page(page);
-	SetPageLocked(page);
 	atomic_inc(&agp_bridge->current_memory_agp);
 	return page_address(page);
 }
diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
index 9aaf401..0ecc54d 100644
--- a/drivers/char/agp/via-agp.c
+++ b/drivers/char/agp/via-agp.c
@@ -399,6 +399,11 @@
 		.device_id  = PCI_DEVICE_ID_VIA_P4M890,
 		.chipset_name   = "P4M890",
 	},
+	/* P4M900 */
+	{
+		.device_id  = PCI_DEVICE_ID_VIA_VT3364,
+		.chipset_name   = "P4M900",
+	},
 	{ }, /* dummy final entry, always present */
 };
 
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 7b02bf1..3d468f5 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -1721,12 +1721,11 @@
 		*ret_info = sstate->info;
 		return 0;
 	}
-	info = kmalloc(sizeof(struct async_struct), GFP_KERNEL);
+	info = kzalloc(sizeof(struct async_struct), GFP_KERNEL);
 	if (!info) {
 		sstate->count--;
 		return -ENOMEM;
 	}
-	memset(info, 0, sizeof(struct async_struct));
 #ifdef DECLARE_WAITQUEUE
 	init_waitqueue_head(&info->open_wait);
 	init_waitqueue_head(&info->close_wait);
diff --git a/drivers/char/decserial.c b/drivers/char/decserial.c
deleted file mode 100644
index 8ea2bea..0000000
--- a/drivers/char/decserial.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * sercons.c
- *      choose the right serial device at boot time
- *
- * triemer 6-SEP-1998
- *      sercons.c is designed to allow the three different kinds 
- *      of serial devices under the decstation world to co-exist
- *      in the same kernel.  The idea here is to abstract 
- *      the pieces of the drivers that are common to this file
- *      so that they do not clash at compile time and runtime.
- *
- * HK 16-SEP-1998 v0.002
- *      removed the PROM console as this is not a real serial
- *      device. Added support for PROM console in drivers/char/tty_io.c
- *      instead. Although it may work to enable more than one 
- *      console device I strongly recommend to use only one.
- */
-
-#include <linux/init.h>
-#include <asm/dec/machtype.h>
-
-#ifdef CONFIG_ZS
-extern int zs_init(void);
-#endif
-
-#ifdef CONFIG_SERIAL_CONSOLE
-
-#ifdef CONFIG_ZS
-extern void zs_serial_console_init(void);
-#endif
-
-#endif
-
-/* rs_init - starts up the serial interface -
-   handle normal case of starting up the serial interface */
-
-#ifdef CONFIG_SERIAL
-
-int __init rs_init(void)
-{
-#ifdef CONFIG_ZS
-    if (IOASIC)
-	return zs_init();
-#endif
-    return -ENXIO;
-}
-
-__initcall(rs_init);
-
-#endif
-
-#ifdef CONFIG_SERIAL_CONSOLE
-
-/* serial_console_init handles the special case of starting
- *   up the console on the serial port
- */
-static int __init decserial_console_init(void)
-{
-#ifdef CONFIG_ZS
-    if (IOASIC)
-	zs_serial_console_init();
-#endif
-    return 0;
-}
-console_initcall(decserial_console_init);
-
-#endif
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index 923174c..c115b39 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -177,8 +177,14 @@
 						     MTRR_TYPE_WRCOMB, 1);
 			}
 		}
-		if (map->type == _DRM_REGISTERS)
+		if (map->type == _DRM_REGISTERS) {
 			map->handle = ioremap(map->offset, map->size);
+			if (!map->handle) {
+				drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+				return -ENOMEM;
+			}
+		}
+				
 		break;
 	case _DRM_SHM:
 		list = drm_find_matching_map(dev, map);
@@ -479,11 +485,6 @@
 		return -EINVAL;
 	}
 
-	if (!map) {
-		mutex_unlock(&dev->struct_mutex);
-		return -EINVAL;
-	}
-
 	/* Register and framebuffer maps are permanent */
 	if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) {
 		mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index 3359cc2..8e7d713 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -184,6 +184,8 @@
 	 * private backbuffer/depthbuffer usage.
 	 */
 	dev_priv->use_mi_batchbuffer_start = 0;
+	if (IS_I965G(dev)) /* 965 doesn't support older method */
+		dev_priv->use_mi_batchbuffer_start = 1;
 
 	/* Allow hardware batchbuffers unless told otherwise.
 	 */
@@ -517,8 +519,13 @@
 
 		if (dev_priv->use_mi_batchbuffer_start) {
 			BEGIN_LP_RING(2);
-			OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
-			OUT_RING(batch->start | MI_BATCH_NON_SECURE);
+			if (IS_I965G(dev)) {
+				OUT_RING(MI_BATCH_BUFFER_START | (2 << 6) | MI_BATCH_NON_SECURE_I965);
+				OUT_RING(batch->start);
+			} else {
+				OUT_RING(MI_BATCH_BUFFER_START | (2 << 6));
+				OUT_RING(batch->start | MI_BATCH_NON_SECURE);
+			}
 			ADVANCE_LP_RING();
 		} else {
 			BEGIN_LP_RING(4);
@@ -735,7 +742,8 @@
 
 	switch (param.param) {
 	case I915_SETPARAM_USE_MI_BATCHBUFFER_START:
-		dev_priv->use_mi_batchbuffer_start = param.value;
+		if (!IS_I965G(dev))
+			dev_priv->use_mi_batchbuffer_start = param.value;
 		break;
 	case I915_SETPARAM_TEX_LRU_LOG_GRANULARITY:
 		dev_priv->tex_lru_log_granularity = param.value;
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index fd91856..28b9873 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -210,6 +210,12 @@
 #define I915REG_INT_MASK_R 	0x020a8
 #define I915REG_INT_ENABLE_R	0x020a0
 
+#define I915REG_PIPEASTAT	0x70024
+#define I915REG_PIPEBSTAT	0x71024
+
+#define I915_VBLANK_INTERRUPT_ENABLE	(1UL<<17)
+#define I915_VBLANK_CLEAR		(1UL<<1)
+
 #define SRX_INDEX		0x3c4
 #define SRX_DATA		0x3c5
 #define SR01			1
@@ -282,6 +288,7 @@
 #define MI_BATCH_BUFFER_START 	(0x31<<23)
 #define MI_BATCH_BUFFER_END 	(0xA<<23)
 #define MI_BATCH_NON_SECURE	(1)
+#define MI_BATCH_NON_SECURE_I965 (1<<8)
 
 #define MI_WAIT_FOR_EVENT       ((0x3<<23))
 #define MI_WAIT_FOR_PLANE_A_FLIP      (1<<2)
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index 4b4b2ce..bb8e9e9 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -214,6 +214,10 @@
 	struct drm_device *dev = (struct drm_device *) arg;
 	drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
 	u16 temp;
+	u32 pipea_stats, pipeb_stats;
+
+	pipea_stats = I915_READ(I915REG_PIPEASTAT);
+	pipeb_stats = I915_READ(I915REG_PIPEBSTAT);
 
 	temp = I915_READ16(I915REG_INT_IDENTITY_R);
 
@@ -225,6 +229,8 @@
 		return IRQ_NONE;
 
 	I915_WRITE16(I915REG_INT_IDENTITY_R, temp);
+	(void) I915_READ16(I915REG_INT_IDENTITY_R);
+	DRM_READMEMORYBARRIER();
 
 	dev_priv->sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv);
 
@@ -252,6 +258,12 @@
 
 		if (dev_priv->swaps_pending > 0)
 			drm_locked_tasklet(dev, i915_vblank_tasklet);
+		I915_WRITE(I915REG_PIPEASTAT,
+			pipea_stats|I915_VBLANK_INTERRUPT_ENABLE|
+			I915_VBLANK_CLEAR);
+		I915_WRITE(I915REG_PIPEBSTAT,
+			pipeb_stats|I915_VBLANK_INTERRUPT_ENABLE|
+			I915_VBLANK_CLEAR);
 	}
 
 	return IRQ_HANDLED;
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c
index fdb8609..3dd1ed3 100644
--- a/drivers/char/drm/via_dmablit.c
+++ b/drivers/char/drm/via_dmablit.c
@@ -273,10 +273,9 @@
 	vsg->num_desc_pages = (vsg->num_desc + vsg->descriptors_per_page - 1) / 
 		vsg->descriptors_per_page;
 
-	if (NULL ==  (vsg->desc_pages = kmalloc(sizeof(void *) * vsg->num_desc_pages, GFP_KERNEL))) 
+	if (NULL ==  (vsg->desc_pages = kcalloc(vsg->num_desc_pages, sizeof(void *), GFP_KERNEL)))
 		return DRM_ERR(ENOMEM);
 	
-	memset(vsg->desc_pages, 0, sizeof(void *) * vsg->num_desc_pages);
 	vsg->state = dr_via_desc_pages_alloc;
 	for (i=0; i<vsg->num_desc_pages; ++i) {
 		if (NULL == (vsg->desc_pages[i] = 
@@ -561,7 +560,7 @@
 		blitq->head = 0;
 		blitq->cur = 0;
 		blitq->serviced = 0;
-		blitq->num_free = VIA_NUM_BLIT_SLOTS;
+		blitq->num_free = VIA_NUM_BLIT_SLOTS - 1;
 		blitq->num_outstanding = 0;
 		blitq->is_active = 0;
 		blitq->aborting = 0;
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index 9b8278e..acbfe1c 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -513,7 +513,7 @@
 		err = PTR_ERR(dsp56k_class);
 		goto out_chrdev;
 	}
-	class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k");
+	device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), "dsp56k");
 
 	printk(banner);
 	goto out;
@@ -527,7 +527,7 @@
 
 static void __exit dsp56k_cleanup_driver(void)
 {
-	class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
+	device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
 	class_destroy(dsp56k_class);
 	unregister_chrdev(DSP56K_MAJOR, "dsp56k");
 }
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 74cd511..2e7ae42 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -2459,7 +2459,7 @@
 		return 1;
 	}
 
-	info = kmalloc(sizeof(struct esp_struct), GFP_KERNEL);
+	info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL);
 
 	if (!info)
 	{
@@ -2469,7 +2469,6 @@
 		return 1;
 	}
 
-	memset((void *)info, 0, sizeof(struct esp_struct));
 	spin_lock_init(&info->lock);
 	/* rx_trigger, tx_trigger are needed by autoconfig */
 	info->config.rx_trigger = rx_trigger;
@@ -2527,7 +2526,7 @@
 		if (!dma)
 			info->stat_flags |= ESP_STAT_NEVER_DMA;
 
-		info = kmalloc(sizeof(struct esp_struct), GFP_KERNEL);
+		info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL);
 		if (!info)
 		{
 			printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n"); 
@@ -2536,7 +2535,6 @@
 			return 0;
 		}
 
-		memset((void *)info, 0, sizeof(struct esp_struct));
 		/* rx_trigger, tx_trigger are needed by autoconfig */
 		info->config.rx_trigger = rx_trigger;
 		info->config.tx_trigger = tx_trigger;
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 0be700f..4c16778 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -29,6 +29,7 @@
 #include <linux/bcd.h>
 #include <linux/seq_file.h>
 #include <linux/bitops.h>
+#include <linux/clocksource.h>
 
 #include <asm/current.h>
 #include <asm/uaccess.h>
@@ -51,8 +52,37 @@
 
 #define HPET_RANGE_SIZE		1024	/* from HPET spec */
 
+#if BITS_PER_LONG == 64
+#define	write_counter(V, MC)	writeq(V, MC)
+#define	read_counter(MC)	readq(MC)
+#else
+#define	write_counter(V, MC)	writel(V, MC)
+#define	read_counter(MC)	readl(MC)
+#endif
+
 static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ;
 
+/* This clocksource driver currently only works on ia64 */
+#ifdef CONFIG_IA64
+static void __iomem *hpet_mctr;
+
+static cycle_t read_hpet(void)
+{
+	return (cycle_t)read_counter((void __iomem *)hpet_mctr);
+}
+
+static struct clocksource clocksource_hpet = {
+        .name           = "hpet",
+        .rating         = 250,
+        .read           = read_hpet,
+        .mask           = CLOCKSOURCE_MASK(64),
+        .mult           = 0, /*to be caluclated*/
+        .shift          = 10,
+        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+static struct clocksource *hpet_clocksource;
+#endif
+
 /* A lock for concurrent access by app and isr hpet activity. */
 static DEFINE_SPINLOCK(hpet_lock);
 /* A lock for concurrent intermodule access to hpet and isr hpet activity. */
@@ -79,7 +109,7 @@
 	struct hpets *hp_next;
 	struct hpet __iomem *hp_hpet;
 	unsigned long hp_hpet_phys;
-	struct time_interpolator *hp_interpolator;
+	struct clocksource *hp_clocksource;
 	unsigned long long hp_tick_freq;
 	unsigned long hp_delta;
 	unsigned int hp_ntimer;
@@ -94,13 +124,6 @@
 #define	HPET_PERIODIC		0x0004
 #define	HPET_SHARED_IRQ		0x0008
 
-#if BITS_PER_LONG == 64
-#define	write_counter(V, MC)	writeq(V, MC)
-#define	read_counter(MC)	readq(MC)
-#else
-#define	write_counter(V, MC) 	writel(V, MC)
-#define	read_counter(MC)	readl(MC)
-#endif
 
 #ifndef readq
 static inline unsigned long long readq(void __iomem *addr)
@@ -737,27 +760,6 @@
 
 static struct ctl_table_header *sysctl_header;
 
-static void hpet_register_interpolator(struct hpets *hpetp)
-{
-#ifdef	CONFIG_TIME_INTERPOLATION
-	struct time_interpolator *ti;
-
-	ti = kzalloc(sizeof(*ti), GFP_KERNEL);
-	if (!ti)
-		return;
-
-	ti->source = TIME_SOURCE_MMIO64;
-	ti->shift = 10;
-	ti->addr = &hpetp->hp_hpet->hpet_mc;
-	ti->frequency = hpetp->hp_tick_freq;
-	ti->drift = HPET_DRIFT;
-	ti->mask = -1;
-
-	hpetp->hp_interpolator = ti;
-	register_time_interpolator(ti);
-#endif
-}
-
 /*
  * Adjustment for when arming the timer with
  * initial conditions.  That is, main counter
@@ -909,7 +911,19 @@
 	}
 
 	hpetp->hp_delta = hpet_calibrate(hpetp);
-	hpet_register_interpolator(hpetp);
+
+/* This clocksource driver currently only works on ia64 */
+#ifdef CONFIG_IA64
+	if (!hpet_clocksource) {
+		hpet_mctr = (void __iomem *)&hpetp->hp_hpet->hpet_mc;
+		CLKSRC_FSYS_MMIO_SET(clocksource_hpet.fsys_mmio, hpet_mctr);
+		clocksource_hpet.mult = clocksource_hz2mult(hpetp->hp_tick_freq,
+						clocksource_hpet.shift);
+		clocksource_register(&clocksource_hpet);
+		hpetp->hp_clocksource = &clocksource_hpet;
+		hpet_clocksource = &clocksource_hpet;
+	}
+#endif
 
 	return 0;
 }
@@ -932,14 +946,14 @@
 			printk(KERN_DEBUG "%s: 0x%lx is busy\n",
 				__FUNCTION__, hdp->hd_phys_address);
 			iounmap(hdp->hd_address);
-			return -EBUSY;
+			return AE_ALREADY_EXISTS;
 		}
 	} else if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
 		struct acpi_resource_fixed_memory32 *fixmem32;
 
 		fixmem32 = &res->data.fixed_memory32;
 		if (!fixmem32)
-			return -EINVAL;
+			return AE_NO_MEMORY;
 
 		hdp->hd_phys_address = fixmem32->address;
 		hdp->hd_address = ioremap(fixmem32->address,
@@ -949,7 +963,7 @@
 			printk(KERN_DEBUG "%s: 0x%lx is busy\n",
 				__FUNCTION__, hdp->hd_phys_address);
 			iounmap(hdp->hd_address);
-			return -EBUSY;
+			return AE_ALREADY_EXISTS;
 		}
 	} else if (res->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
 		struct acpi_resource_extended_irq *irqp;
@@ -995,13 +1009,19 @@
 
 static int hpet_acpi_remove(struct acpi_device *device, int type)
 {
-	/* XXX need to unregister interpolator, dealloc mem, etc */
+	/* XXX need to unregister clocksource, dealloc mem, etc */
 	return -EINVAL;
 }
 
+static const struct acpi_device_id hpet_device_ids[] = {
+	{"PNP0103", 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, hpet_device_ids);
+
 static struct acpi_driver hpet_acpi_driver = {
 	.name = "hpet",
-	.ids = "PNP0103",
+	.ids = hpet_device_ids,
 	.ops = {
 		.add = hpet_acpi_add,
 		.remove = hpet_acpi_remove,
diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c
index 6f019f1..e74bb94 100644
--- a/drivers/char/hvc_beat.c
+++ b/drivers/char/hvc_beat.c
@@ -97,7 +97,7 @@
 	return 0;
 }
 
-static int hvc_beat_console_init(void)
+static int __init hvc_beat_console_init(void)
 {
 	if (hvc_beat_useit && machine_is_compatible("Beat")) {
 		hvc_instantiate(0, 0, &hvc_beat_get_put_ops);
@@ -106,7 +106,7 @@
 }
 
 /* temp */
-static int hvc_beat_init(void)
+static int __init hvc_beat_init(void)
 {
 	struct hvc_struct *hp;
 
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
index b37f1d5..a08f8f9 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/char/hvc_iseries.c
@@ -472,7 +472,7 @@
 	}
 }
 
-static int send_open(HvLpIndex remoteLp, void *sem)
+static int __init send_open(HvLpIndex remoteLp, void *sem)
 {
 	return HvCallEvent_signalLpEventFast(remoteLp,
 			HvLpEvent_Type_VirtualIo,
@@ -484,7 +484,7 @@
 			0, 0, 0, 0);
 }
 
-static int hvc_vio_init(void)
+static int __init hvc_vio_init(void)
 {
 	atomic_t wait_flag;
 	int rc;
@@ -552,14 +552,14 @@
 }
 module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
 
-static void hvc_vio_exit(void)
+static void __exit hvc_vio_exit(void)
 {
 	vio_unregister_driver(&hvc_vio_driver);
 }
 module_exit(hvc_vio_exit);
 
 /* the device tree order defines our numbering */
-static int hvc_find_vtys(void)
+static int __init hvc_find_vtys(void)
 {
 	struct device_node *vty;
 	int num_found = 0;
diff --git a/drivers/char/hvc_lguest.c b/drivers/char/hvc_lguest.c
new file mode 100644
index 0000000..3d6bd0b
--- /dev/null
+++ b/drivers/char/hvc_lguest.c
@@ -0,0 +1,177 @@
+/*D:300
+ * The Guest console driver
+ *
+ * This is a trivial console driver: we use lguest's DMA mechanism to send
+ * bytes out, and register a DMA buffer to receive bytes in.  It is assumed to
+ * be present and available from the very beginning of boot.
+ *
+ * Writing console drivers is one of the few remaining Dark Arts in Linux.
+ * Fortunately for us, the path of virtual consoles has been well-trodden by
+ * the PowerPC folks, who wrote "hvc_console.c" to generically support any
+ * virtual console.  We use that infrastructure which only requires us to write
+ * the basic put_chars and get_chars functions and call the right register
+ * functions.
+ :*/
+
+/*M:002 The console can be flooded: while the Guest is processing input the
+ * Host can send more.  Buffering in the Host could alleviate this, but it is a
+ * difficult problem in general. :*/
+/* Copyright (C) 2006 Rusty Russell, IBM Corporation
+ *
+ * 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/err.h>
+#include <linux/init.h>
+#include <linux/lguest_bus.h>
+#include <asm/paravirt.h>
+#include "hvc_console.h"
+
+/*D:340 This is our single console input buffer, with associated "struct
+ * lguest_dma" referring to it.  Note the 0-terminated length array, and the
+ * use of physical address for the buffer itself. */
+static char inbuf[256];
+static struct lguest_dma cons_input = { .used_len = 0,
+					.addr[0] = __pa(inbuf),
+					.len[0] = sizeof(inbuf),
+					.len[1] = 0 };
+
+/*D:310 The put_chars() callback is pretty straightforward.
+ *
+ * First we put the pointer and length in a "struct lguest_dma": we only have
+ * one pointer, so we set the second length to 0.  Then we use SEND_DMA to send
+ * the data to (Host) buffers attached to the console key.  Usually a device's
+ * key is a physical address within the device's memory, but because the
+ * console device doesn't have any associated physical memory, we use the
+ * LGUEST_CONSOLE_DMA_KEY constant (aka 0). */
+static int put_chars(u32 vtermno, const char *buf, int count)
+{
+	struct lguest_dma dma;
+
+	/* FIXME: DMA buffers in a "struct lguest_dma" are not allowed
+	 * to go over page boundaries.  This never seems to happen,
+	 * but if it did we'd need to fix this code. */
+	dma.len[0] = count;
+	dma.len[1] = 0;
+	dma.addr[0] = __pa(buf);
+
+	lguest_send_dma(LGUEST_CONSOLE_DMA_KEY, &dma);
+	/* We're expected to return the amount of data we wrote: all of it. */
+	return count;
+}
+
+/*D:350 get_chars() is the callback from the hvc_console infrastructure when
+ * an interrupt is received.
+ *
+ * Firstly we see if our buffer has been filled: if not, we return.  The rest
+ * of the code deals with the fact that the hvc_console() infrastructure only
+ * asks us for 16 bytes at a time.  We keep a "cons_offset" variable for
+ * partially-read buffers. */
+static int get_chars(u32 vtermno, char *buf, int count)
+{
+	static int cons_offset;
+
+	/* Nothing left to see here... */
+	if (!cons_input.used_len)
+		return 0;
+
+	/* You want more than we have to give?  Well, try wanting less! */
+	if (cons_input.used_len - cons_offset < count)
+		count = cons_input.used_len - cons_offset;
+
+	/* Copy across to their buffer and increment offset. */
+	memcpy(buf, inbuf + cons_offset, count);
+	cons_offset += count;
+
+	/* Finished?  Zero offset, and reset cons_input so Host will use it
+	 * again. */
+	if (cons_offset == cons_input.used_len) {
+		cons_offset = 0;
+		cons_input.used_len = 0;
+	}
+	return count;
+}
+/*:*/
+
+static struct hv_ops lguest_cons = {
+	.get_chars = get_chars,
+	.put_chars = put_chars,
+};
+
+/*D:320 Console drivers are initialized very early so boot messages can go
+ * out.  At this stage, the console is output-only.  Our driver checks we're a
+ * Guest, and if so hands hvc_instantiate() the console number (0), priority
+ * (0), and the struct hv_ops containing the put_chars() function. */
+static int __init cons_init(void)
+{
+	if (strcmp(paravirt_ops.name, "lguest") != 0)
+		return 0;
+
+	return hvc_instantiate(0, 0, &lguest_cons);
+}
+console_initcall(cons_init);
+
+/*D:370 To set up and manage our virtual console, we call hvc_alloc() and
+ * stash the result in the private pointer of the "struct lguest_device".
+ * Since we never remove the console device we never need this pointer again,
+ * but using ->private is considered good form, and you never know who's going
+ * to copy your driver.
+ *
+ * Once the console is set up, we bind our input buffer ready for input. */
+static int lguestcons_probe(struct lguest_device *lgdev)
+{
+	int err;
+
+	/* The first argument of hvc_alloc() is the virtual console number, so
+	 * we use zero.  The second argument is the interrupt number.
+	 *
+	 * The third argument is a "struct hv_ops" containing the put_chars()
+	 * and get_chars() pointers.  The final argument is the output buffer
+	 * size: we use 256 and expect the Host to have room for us to send
+	 * that much. */
+	lgdev->private = hvc_alloc(0, lgdev_irq(lgdev), &lguest_cons, 256);
+	if (IS_ERR(lgdev->private))
+		return PTR_ERR(lgdev->private);
+
+	/* We bind a single DMA buffer at key LGUEST_CONSOLE_DMA_KEY.
+	 * "cons_input" is that statically-initialized global DMA buffer we saw
+	 * above, and we also give the interrupt we want. */
+	err = lguest_bind_dma(LGUEST_CONSOLE_DMA_KEY, &cons_input, 1,
+			      lgdev_irq(lgdev));
+	if (err)
+		printk("lguest console: failed to bind buffer.\n");
+	return err;
+}
+/* Note the use of lgdev_irq() for the interrupt number.  We tell hvc_alloc()
+ * to expect input when this interrupt is triggered, and then tell
+ * lguest_bind_dma() that is the interrupt to send us when input comes in. */
+
+/*D:360 From now on the console driver follows standard Guest driver form:
+ * register_lguest_driver() registers the device type and probe function, and
+ * the probe function sets up the device.
+ *
+ * The standard "struct lguest_driver": */
+static struct lguest_driver lguestcons_drv = {
+	.name = "lguestcons",
+	.owner = THIS_MODULE,
+	.device_type = LGUEST_DEVICE_T_CONSOLE,
+	.probe = lguestcons_probe,
+};
+
+/* The standard init function */
+static int __init hvc_lguest_init(void)
+{
+	return register_lguest_driver(&lguestcons_drv);
+}
+module_init(hvc_lguest_init);
diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c
index 4b97eaf..bb09413 100644
--- a/drivers/char/hvc_rtas.c
+++ b/drivers/char/hvc_rtas.c
@@ -115,7 +115,7 @@
 module_exit(hvc_rtas_exit);
 
 /* This will happen prior to module init.  There is no tty at this time? */
-static int hvc_rtas_console_init(void)
+static int __init hvc_rtas_console_init(void)
 {
 	rtascons_put_char_token = rtas_token("put-term-char");
 	if (rtascons_put_char_token == RTAS_UNKNOWN_SERVICE)
diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c
new file mode 100644
index 0000000..dd68f85
--- /dev/null
+++ b/drivers/char/hvc_xen.c
@@ -0,0 +1,159 @@
+/*
+ * xen console driver interface to hvc_console.c
+ *
+ * (c) 2007 Gerd Hoffmann <kraxel@suse.de>
+ *
+ * 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/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/types.h>
+
+#include <asm/xen/hypervisor.h>
+#include <xen/page.h>
+#include <xen/events.h>
+#include <xen/interface/io/console.h>
+#include <xen/hvc-console.h>
+
+#include "hvc_console.h"
+
+#define HVC_COOKIE   0x58656e /* "Xen" in hex */
+
+static struct hvc_struct *hvc;
+static int xencons_irq;
+
+/* ------------------------------------------------------------------ */
+
+static inline struct xencons_interface *xencons_interface(void)
+{
+	return mfn_to_virt(xen_start_info->console.domU.mfn);
+}
+
+static inline void notify_daemon(void)
+{
+	/* Use evtchn: this is called early, before irq is set up. */
+	notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
+}
+
+static int write_console(uint32_t vtermno, const char *data, int len)
+{
+	struct xencons_interface *intf = xencons_interface();
+	XENCONS_RING_IDX cons, prod;
+	int sent = 0;
+
+	cons = intf->out_cons;
+	prod = intf->out_prod;
+	mb();			/* update queue values before going on */
+	BUG_ON((prod - cons) > sizeof(intf->out));
+
+	while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
+		intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
+
+	wmb();			/* write ring before updating pointer */
+	intf->out_prod = prod;
+
+	notify_daemon();
+	return sent;
+}
+
+static int read_console(uint32_t vtermno, char *buf, int len)
+{
+	struct xencons_interface *intf = xencons_interface();
+	XENCONS_RING_IDX cons, prod;
+	int recv = 0;
+
+	cons = intf->in_cons;
+	prod = intf->in_prod;
+	mb();			/* get pointers before reading ring */
+	BUG_ON((prod - cons) > sizeof(intf->in));
+
+	while (cons != prod && recv < len)
+		buf[recv++] = intf->in[MASK_XENCONS_IDX(cons++, intf->in)];
+
+	mb();			/* read ring before consuming */
+	intf->in_cons = cons;
+
+	notify_daemon();
+	return recv;
+}
+
+static struct hv_ops hvc_ops = {
+	.get_chars = read_console,
+	.put_chars = write_console,
+};
+
+static int __init xen_init(void)
+{
+	struct hvc_struct *hp;
+
+	if (!is_running_on_xen())
+		return 0;
+
+	xencons_irq = bind_evtchn_to_irq(xen_start_info->console.domU.evtchn);
+	if (xencons_irq < 0)
+		xencons_irq = 0 /* NO_IRQ */;
+	hp = hvc_alloc(HVC_COOKIE, xencons_irq, &hvc_ops, 256);
+	if (IS_ERR(hp))
+		return PTR_ERR(hp);
+
+	hvc = hp;
+	return 0;
+}
+
+static void __exit xen_fini(void)
+{
+	if (hvc)
+		hvc_remove(hvc);
+}
+
+static int xen_cons_init(void)
+{
+	if (!is_running_on_xen())
+		return 0;
+
+	hvc_instantiate(HVC_COOKIE, 0, &hvc_ops);
+	return 0;
+}
+
+module_init(xen_init);
+module_exit(xen_fini);
+console_initcall(xen_cons_init);
+
+static void xenboot_write_console(struct console *console, const char *string,
+				  unsigned len)
+{
+	unsigned int linelen, off = 0;
+	const char *pos;
+
+	while (off < len && NULL != (pos = strchr(string+off, '\n'))) {
+		linelen = pos-string+off;
+		if (off + linelen > len)
+			break;
+		write_console(0, string+off, linelen);
+		write_console(0, "\r\n", 2);
+		off += linelen + 1;
+	}
+	if (off < len)
+		write_console(0, string+off, len-off);
+}
+
+struct console xenboot_console = {
+	.name		= "xenboot",
+	.write		= xenboot_write_console,
+	.flags		= CON_PRINTBUFFER | CON_BOOT,
+};
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
index 207f734..69d8866 100644
--- a/drivers/char/hvcs.c
+++ b/drivers/char/hvcs.c
@@ -210,9 +210,9 @@
 static int hvcs_parm_num_devs = -1;
 module_param(hvcs_parm_num_devs, int, 0);
 
-char hvcs_driver_name[] = "hvcs";
-char hvcs_device_node[] = "hvcs";
-char hvcs_driver_string[]
+static const char hvcs_driver_name[] = "hvcs";
+static const char hvcs_device_node[] = "hvcs";
+static const char hvcs_driver_string[]
 	= "IBM hvcs (Hypervisor Virtual Console Server) Driver";
 
 /* Status of partner info rescan triggered via sysfs. */
@@ -784,12 +784,10 @@
 		return -EFAULT;
 	}
 
-	hvcsd = kmalloc(sizeof(*hvcsd), GFP_KERNEL);
+	hvcsd = kzalloc(sizeof(*hvcsd), GFP_KERNEL);
 	if (!hvcsd)
 		return -ENODEV;
 
-	/* hvcsd->tty is zeroed out with the memset */
-	memset(hvcsd, 0x00, sizeof(*hvcsd));
 
 	spin_lock_init(&hvcsd->lock);
 	/* Automatically incs the refcount the first time */
@@ -1094,7 +1092,7 @@
  * NOTICE: Do NOT hold either the hvcs_struct.lock or hvcs_structs_lock when
  * calling this function or you will get deadlock.
  */
-struct hvcs_struct *hvcs_get_by_index(int index)
+static struct hvcs_struct *hvcs_get_by_index(int index)
 {
 	struct hvcs_struct *hvcsd = NULL;
 	unsigned long flags;
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 7cda04b..2d7cd48 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -41,7 +41,7 @@
 
 config HW_RANDOM_GEODE
 	tristate "AMD Geode HW Random Number Generator support"
-	depends on HW_RANDOM && X86 && PCI
+	depends on HW_RANDOM && X86_32 && PCI
 	default HW_RANDOM
 	---help---
 	  This driver provides kernel-side support for the Random Number
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 0289705..cd40641 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -98,9 +98,9 @@
 	unsigned int edi __attribute__ ((packed));
 };
 
-static inline char *i8k_get_dmi_data(int field)
+static inline const char *i8k_get_dmi_data(int field)
 {
-	char *dmi_data = dmi_get_system_info(field);
+	const char *dmi_data = dmi_get_system_info(field);
 
 	return dmi_data && *dmi_data ? dmi_data : "?";
 }
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 83c7258..bd94d5f 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -411,8 +411,8 @@
 			iiResetDelay( i2BoardPtrTable[i] );
 			/* free io addresses and Tibet */
 			release_region( ip2config.addr[i], 8 );
-			class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
-			class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
+			device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
+			device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
 		}
 		/* Disable and remove interrupt handler. */
 		if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) {	
@@ -425,9 +425,7 @@
 		printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
 	}
 	put_tty_driver(ip2_tty_driver);
-	if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) ) {
-		printk(KERN_ERR "IP2: failed to unregister IPL driver (%d)\n", err);
-	}
+	unregister_chrdev(IP2_IPL_MAJOR, pcIpl);
 	remove_proc_entry("ip2mem", &proc_root);
 
 	// free memory
@@ -502,7 +500,6 @@
 {
 	int i, j, box;
 	int err = 0;
-	int status = 0;
 	static int loaded;
 	i2eBordStrPtr pB = NULL;
 	int rc = -1;
@@ -590,6 +587,8 @@
 		case PCI:
 #ifdef CONFIG_PCI
 			{
+				int status;
+
 				pci_dev_i = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
 							  PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i);
 				if (pci_dev_i != NULL) {
@@ -719,12 +718,12 @@
 			}
 
 			if ( NULL != ( pB = i2BoardPtrTable[i] ) ) {
-				class_device_create(ip2_class, NULL,
+				device_create(ip2_class, NULL,
 						MKDEV(IP2_IPL_MAJOR, 4 * i),
-						NULL, "ipl%d", i);
-				class_device_create(ip2_class, NULL,
+						"ipl%d", i);
+				device_create(ip2_class, NULL,
 						MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
-						NULL, "stat%d", i);
+						"stat%d", i);
 
 			    for ( box = 0; box < ABS_MAX_BOXES; ++box )
 			    {
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index c2aa44e..0246a2b8 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -865,7 +865,7 @@
 	entry->dev = dev;
 
 	mutex_lock(&reg_list_mutex);
-	class_device_create(ipmi_class, NULL, dev, device, "ipmi%d", if_num);
+	device_create(ipmi_class, device, dev, "ipmi%d", if_num);
 	list_add(&entry->link, &reg_list);
 	mutex_unlock(&reg_list_mutex);
 }
@@ -883,7 +883,7 @@
 			break;
 		}
 	}
-	class_device_destroy(ipmi_class, dev);
+	device_destroy(ipmi_class, dev);
 	mutex_unlock(&reg_list_mutex);
 }
 
@@ -938,7 +938,7 @@
 	mutex_lock(&reg_list_mutex);
 	list_for_each_entry_safe(entry, entry2, &reg_list, link) {
 		list_del(&entry->link);
-		class_device_destroy(ipmi_class, entry->dev);
+		device_destroy(ipmi_class, entry->dev);
 		kfree(entry);
 	}
 	mutex_unlock(&reg_list_mutex);
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index b5df7e6..6a01dd9 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -2639,10 +2639,9 @@
 			return -ENODEV;
 	}
 
-	intf = kmalloc(sizeof(*intf), GFP_KERNEL);
+	intf = kzalloc(sizeof(*intf), GFP_KERNEL);
 	if (!intf)
 		return -ENOMEM;
-	memset(intf, 0, sizeof(*intf));
 
 	intf->ipmi_version_major = ipmi_version_major(device_id);
 	intf->ipmi_version_minor = ipmi_version_minor(device_id);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 4edfdda..a2894d4 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -1965,10 +1965,10 @@
 	u8              slave_addr;
 };
 
-static int __devinit decode_dmi(struct dmi_header *dm,
+static int __devinit decode_dmi(const struct dmi_header *dm,
 				struct dmi_ipmi_data *dmi)
 {
-	u8              *data = (u8 *)dm;
+	const u8	*data = (const u8 *)dm;
 	unsigned long  	base_addr;
 	u8		reg_spacing;
 	u8              len = dm->length;
@@ -2050,6 +2050,7 @@
 		info->si_type = SI_BT;
 		break;
 	default:
+		kfree(info);
 		return;
 	}
 
@@ -2090,13 +2091,14 @@
 
 static void __devinit dmi_find_bmc(void)
 {
-	struct dmi_device    *dev = NULL;
+	const struct dmi_device *dev = NULL;
 	struct dmi_ipmi_data data;
 	int                  rv;
 
 	while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) {
 		memset(&data, 0, sizeof(data));
-		rv = decode_dmi((struct dmi_header *) dev->device_data, &data);
+		rv = decode_dmi((const struct dmi_header *) dev->device_data,
+				&data);
 		if (!rv)
 			try_init_dmi(&data);
 	}
@@ -2214,7 +2216,8 @@
 
 static struct pci_device_id ipmi_pci_devices[] = {
 	{ PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) },
-	{ PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) }
+	{ PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) },
+	{ 0, }
 };
 MODULE_DEVICE_TABLE(pci, ipmi_pci_devices);
 
@@ -2250,19 +2253,19 @@
 		return ret;
 	}
 
-	regsize = get_property(np, "reg-size", &proplen);
+	regsize = of_get_property(np, "reg-size", &proplen);
 	if (regsize && proplen != 4) {
 		dev_warn(&dev->dev, PFX "invalid regsize from OF\n");
 		return -EINVAL;
 	}
 
-	regspacing = get_property(np, "reg-spacing", &proplen);
+	regspacing = of_get_property(np, "reg-spacing", &proplen);
 	if (regspacing && proplen != 4) {
 		dev_warn(&dev->dev, PFX "invalid regspacing from OF\n");
 		return -EINVAL;
 	}
 
-	regshift = get_property(np, "reg-shift", &proplen);
+	regshift = of_get_property(np, "reg-shift", &proplen);
 	if (regshift && proplen != 4) {
 		dev_warn(&dev->dev, PFX "invalid regshift from OF\n");
 		return -EINVAL;
@@ -2291,7 +2294,7 @@
 	info->irq		= irq_of_parse_and_map(dev->node, 0);
 	info->dev		= &dev->dev;
 
-	dev_dbg(&dev->dev, "addr 0x%lx regsize %ld spacing %ld irq %x\n",
+	dev_dbg(&dev->dev, "addr 0x%lx regsize %d spacing %d irq %x\n",
 		info->io.addr_data, info->io.regsize, info->io.regspacing,
 		info->irq);
 
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 3c66f40..1f27be1 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -4624,9 +4624,8 @@
 
 	istallion_class = class_create(THIS_MODULE, "staliomem");
 	for (i = 0; i < 4; i++)
-		class_device_create(istallion_class, NULL,
-				MKDEV(STL_SIOMEMMAJOR, i),
-				NULL, "staliomem%d", i);
+		device_create(istallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i),
+			      "staliomem%d", i);
 
 	return 0;
 err_deinit:
@@ -4659,8 +4658,7 @@
 	unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
 
 	for (j = 0; j < 4; j++)
-		class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR,
-					j));
+		device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, j));
 	class_destroy(istallion_class);
 
 	pci_unregister_driver(&stli_pcidriver);
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 2ce0af1..d95f316 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -1022,10 +1022,6 @@
 	308,310,313,314,315,317,318,319,320,357,322,323,324,325,276,330,
 	332,340,365,342,343,344,345,346,356,270,341,368,369,370,371,372 };
 
-#ifdef CONFIG_MAC_EMUMOUSEBTN
-extern int mac_hid_mouse_emulate_buttons(int, int, int);
-#endif /* CONFIG_MAC_EMUMOUSEBTN */
-
 #ifdef CONFIG_SPARC
 static int sparc_l1_a_state = 0;
 extern void sun_do_break(void);
diff --git a/drivers/char/lcd.c b/drivers/char/lcd.c
index 1f09626..4fe9206 100644
--- a/drivers/char/lcd.c
+++ b/drivers/char/lcd.c
@@ -25,7 +25,6 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
-#include <linux/delay.h>
 
 #include "lcd.h"
 
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 62051f8..c59e2a0 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -799,8 +799,7 @@
 	if (reset)
 		lp_reset(nr);
 
-	class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), port->dev,
-				"lp%d", nr);
+	device_create(lp_class, port->dev, MKDEV(LP_MAJOR, nr), "lp%d", nr);
 
 	printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, 
 	       (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");
@@ -971,7 +970,7 @@
 		if (lp_table[offset].dev == NULL)
 			continue;
 		parport_unregister_device(lp_table[offset].dev);
-		class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset));
+		device_destroy(lp_class, MKDEV(LP_MAJOR, offset));
 	}
 	class_destroy(lp_class);
 }
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
index 57f9115..7ee5d944 100644
--- a/drivers/char/mbcs.c
+++ b/drivers/char/mbcs.c
@@ -39,14 +39,14 @@
 #else
 #define DBG(fmt...)
 #endif
-int mbcs_major;
+static int mbcs_major;
 
-LIST_HEAD(soft_list);
+static LIST_HEAD(soft_list);
 
 /*
  * file operations
  */
-const struct file_operations mbcs_ops = {
+static const struct file_operations mbcs_ops = {
 	.open = mbcs_open,
 	.llseek = mbcs_sram_llseek,
 	.read = mbcs_sram_read,
@@ -377,7 +377,7 @@
 	return rv;
 }
 
-int mbcs_open(struct inode *ip, struct file *fp)
+static int mbcs_open(struct inode *ip, struct file *fp)
 {
 	struct mbcs_soft *soft;
 	int minor;
@@ -394,7 +394,7 @@
 	return -ENODEV;
 }
 
-ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * off)
+static ssize_t mbcs_sram_read(struct file * fp, char __user *buf, size_t len, loff_t * off)
 {
 	struct cx_dev *cx_dev = fp->private_data;
 	struct mbcs_soft *soft = cx_dev->soft;
@@ -418,7 +418,7 @@
 	return rv;
 }
 
-ssize_t
+static ssize_t
 mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * off)
 {
 	struct cx_dev *cx_dev = fp->private_data;
@@ -443,7 +443,7 @@
 	return rv;
 }
 
-loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence)
+static loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence)
 {
 	loff_t newpos;
 
@@ -491,7 +491,7 @@
 	soft->gscr_addr = mbcs_pioaddr(soft, MBCS_GSCR_START);
 }
 
-int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma)
+static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma)
 {
 	struct cx_dev *cx_dev = fp->private_data;
 	struct mbcs_soft *soft = cx_dev->soft;
@@ -793,7 +793,7 @@
 	return 0;
 }
 
-const struct cx_device_id __devinitdata mbcs_id_table[] = {
+static const struct cx_device_id __devinitdata mbcs_id_table[] = {
 	{
 	 .part_num = MBCS_PART_NUM,
 	 .mfg_num = MBCS_MFG_NUM,
@@ -807,7 +807,7 @@
 
 MODULE_DEVICE_TABLE(cx, mbcs_id_table);
 
-struct cx_drv mbcs_driver = {
+static struct cx_drv mbcs_driver = {
 	.name = DEVICE_NAME,
 	.id_table = mbcs_id_table,
 	.probe = mbcs_probe,
@@ -816,12 +816,7 @@
 
 static void __exit mbcs_exit(void)
 {
-	int rv;
-
-	rv = unregister_chrdev(mbcs_major, DEVICE_NAME);
-	if (rv < 0)
-		DBG(KERN_ALERT "Error in unregister_chrdev: %d\n", rv);
-
+	unregister_chrdev(mbcs_major, DEVICE_NAME);
 	cx_driver_unregister(&mbcs_driver);
 }
 
diff --git a/drivers/char/mbcs.h b/drivers/char/mbcs.h
index e7fd47e..c9905a3 100644
--- a/drivers/char/mbcs.h
+++ b/drivers/char/mbcs.h
@@ -542,12 +542,12 @@
 	struct semaphore algolock;
 };
 
-extern int mbcs_open(struct inode *ip, struct file *fp);
-extern ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len,
+static int mbcs_open(struct inode *ip, struct file *fp);
+static ssize_t mbcs_sram_read(struct file *fp, char __user *buf, size_t len,
 			      loff_t * off);
-extern ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len,
+static ssize_t mbcs_sram_write(struct file *fp, const char __user *buf, size_t len,
 			       loff_t * off);
-extern loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence);
-extern int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma);
+static loff_t mbcs_sram_llseek(struct file *filp, loff_t off, int whence);
+static int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma);
 
 #endif				// __MBCS_H__
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index 6e55cfb..e60a74c 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -25,6 +25,7 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
+#include <linux/fs.h>
 #include <linux/mmtimer.h>
 #include <linux/miscdevice.h>
 #include <linux/posix-timers.h>
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index c716ef0..04ac155 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -38,6 +38,7 @@
 #include <linux/miscdevice.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
+#include <linux/fs.h>
 #include <linux/vmalloc.h>
 #include <linux/string.h>
 #include <linux/slab.h>
@@ -66,7 +67,7 @@
 /*
  * Page types allocated by the device.
  */
-enum {
+enum mspec_page_type {
 	MSPEC_FETCHOP = 1,
 	MSPEC_CACHED,
 	MSPEC_UNCACHED
@@ -82,15 +83,25 @@
  * One of these structures is allocated when an mspec region is mmaped. The
  * structure is pointed to by the vma->vm_private_data field in the vma struct.
  * This structure is used to record the addresses of the mspec pages.
+ * This structure is shared by all vma's that are split off from the
+ * original vma when split_vma()'s are done.
+ *
+ * The refcnt is incremented atomically because mm->mmap_sem does not
+ * protect in fork case where multiple tasks share the vma_data.
  */
 struct vma_data {
 	atomic_t refcnt;	/* Number of vmas sharing the data. */
-	spinlock_t lock;	/* Serialize access to the vma. */
+	spinlock_t lock;	/* Serialize access to this structure. */
 	int count;		/* Number of pages allocated. */
-	int type;		/* Type of pages allocated. */
+	enum mspec_page_type type; /* Type of pages allocated. */
+	int flags;		/* See VMD_xxx below. */
+	unsigned long vm_start;	/* Original (unsplit) base. */
+	unsigned long vm_end;	/* Original (unsplit) end. */
 	unsigned long maddr[0];	/* Array of MSPEC addresses. */
 };
 
+#define VMD_VMALLOCED 0x1	/* vmalloc'd rather than kmalloc'd */
+
 /* used on shub2 to clear FOP cache in the HUB */
 static unsigned long scratch_page[MAX_NUMNODES];
 #define SH2_AMO_CACHE_ENTRIES	4
@@ -128,8 +139,8 @@
  * mspec_open
  *
  * Called when a device mapping is created by a means other than mmap
- * (via fork, etc.).  Increments the reference count on the underlying
- * mspec data so it is not freed prematurely.
+ * (via fork, munmap, etc.).  Increments the reference count on the
+ * underlying mspec data so it is not freed prematurely.
  */
 static void
 mspec_open(struct vm_area_struct *vma)
@@ -144,43 +155,43 @@
  * mspec_close
  *
  * Called when unmapping a device mapping. Frees all mspec pages
- * belonging to the vma.
+ * belonging to all the vma's sharing this vma_data structure.
  */
 static void
 mspec_close(struct vm_area_struct *vma)
 {
 	struct vma_data *vdata;
-	int i, pages, result, vdata_size;
+	int index, last_index;
+	unsigned long my_page;
 
 	vdata = vma->vm_private_data;
+
 	if (!atomic_dec_and_test(&vdata->refcnt))
 		return;
 
-	pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
-	vdata_size = sizeof(struct vma_data) + pages * sizeof(long);
-	for (i = 0; i < pages; i++) {
-		if (vdata->maddr[i] == 0)
+	last_index = (vdata->vm_end - vdata->vm_start) >> PAGE_SHIFT;
+	for (index = 0; index < last_index; index++) {
+		if (vdata->maddr[index] == 0)
 			continue;
 		/*
 		 * Clear the page before sticking it back
 		 * into the pool.
 		 */
-		result = mspec_zero_block(vdata->maddr[i], PAGE_SIZE);
-		if (!result)
-			uncached_free_page(vdata->maddr[i]);
+		my_page = vdata->maddr[index];
+		vdata->maddr[index] = 0;
+		if (!mspec_zero_block(my_page, PAGE_SIZE))
+			uncached_free_page(my_page);
 		else
 			printk(KERN_WARNING "mspec_close(): "
-			       "failed to zero page %i\n",
-			       result);
+			       "failed to zero page %ld\n", my_page);
 	}
 
-	if (vdata_size <= PAGE_SIZE)
-		kfree(vdata);
-	else
+	if (vdata->flags & VMD_VMALLOCED)
 		vfree(vdata);
+	else
+		kfree(vdata);
 }
 
-
 /*
  * mspec_nopfn
  *
@@ -194,7 +205,8 @@
 	int index;
 	struct vma_data *vdata = vma->vm_private_data;
 
-	index = (address - vma->vm_start) >> PAGE_SHIFT;
+	BUG_ON(address < vdata->vm_start || address >= vdata->vm_end);
+	index = (address - vdata->vm_start) >> PAGE_SHIFT;
 	maddr = (volatile unsigned long) vdata->maddr[index];
 	if (maddr == 0) {
 		maddr = uncached_alloc_page(numa_node_id());
@@ -236,10 +248,11 @@
  * underlying pages.
  */
 static int
-mspec_mmap(struct file *file, struct vm_area_struct *vma, int type)
+mspec_mmap(struct file *file, struct vm_area_struct *vma,
+					enum mspec_page_type type)
 {
 	struct vma_data *vdata;
-	int pages, vdata_size;
+	int pages, vdata_size, flags = 0;
 
 	if (vma->vm_pgoff != 0)
 		return -EINVAL;
@@ -254,12 +267,17 @@
 	vdata_size = sizeof(struct vma_data) + pages * sizeof(long);
 	if (vdata_size <= PAGE_SIZE)
 		vdata = kmalloc(vdata_size, GFP_KERNEL);
-	else
+	else {
 		vdata = vmalloc(vdata_size);
+		flags = VMD_VMALLOCED;
+	}
 	if (!vdata)
 		return -ENOMEM;
 	memset(vdata, 0, vdata_size);
 
+	vdata->vm_start = vma->vm_start;
+	vdata->vm_end = vma->vm_end;
+	vdata->flags = flags;
 	vdata->type = type;
 	spin_lock_init(&vdata->lock);
 	vdata->refcnt = ATOMIC_INIT(1);
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index fee58e0..cc5d777 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -1629,7 +1629,7 @@
 {
 	struct cm4000_dev *dev;
 	struct pcmcia_device *link;
-	int rc, minor = iminor(inode);
+	int minor = iminor(inode);
 
 	if (minor >= CM4000_MAX_DEV)
 		return -ENODEV;
@@ -1668,7 +1668,6 @@
 	start_monitor(dev);
 
 	link->open = 1;		/* only one open per device */
-	rc = 0;
 
 	DEBUGP(2, dev, "<- cmm_open\n");
 	return nonseekable_open(inode, filp);
@@ -1824,7 +1823,7 @@
 
 static void cm4000_release(struct pcmcia_device *link)
 {
-	cmm_cm4000_release(link->priv);	/* delay release until device closed */
+	cmm_cm4000_release(link);	/* delay release until device closed */
 	pcmcia_disable_device(link);
 }
 
@@ -1864,8 +1863,7 @@
 		return ret;
 	}
 
-	class_device_create(cmm_class, NULL, MKDEV(major, i), NULL,
-			    "cmm%d", i);
+	device_create(cmm_class, NULL, MKDEV(major, i), "cmm%d", i);
 
 	return 0;
 }
@@ -1889,7 +1887,7 @@
 	dev_table[devno] = NULL;
 	kfree(dev);
 
-	class_device_destroy(cmm_class, MKDEV(major, devno));
+	device_destroy(cmm_class, MKDEV(major, devno));
 
 	return;
 }
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index af88181..a0b9c87 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -599,7 +599,7 @@
 
 static void reader_release(struct pcmcia_device *link)
 {
-	cm4040_reader_release(link->priv);
+	cm4040_reader_release(link);
 	pcmcia_disable_device(link);
 }
 
@@ -642,8 +642,7 @@
 		return ret;
 	}
 
-	class_device_create(cmx_class, NULL, MKDEV(major, i), NULL,
-			    "cmx%d", i);
+	device_create(cmx_class, NULL, MKDEV(major, i), "cmx%d", i);
 
 	return 0;
 }
@@ -666,7 +665,7 @@
 	dev_table[devno] = NULL;
 	kfree(dev);
 
-	class_device_destroy(cmx_class, MKDEV(major, devno));
+	device_destroy(cmx_class, MKDEV(major, devno));
 
 	return;
 }
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 13808f6..2b88931 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -540,13 +540,12 @@
     if (debug_level >= DEBUG_LEVEL_INFO)
 	    printk("mgslpc_attach\n");
 
-    info = kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
+    info = kzalloc(sizeof(MGSLPC_INFO), GFP_KERNEL);
     if (!info) {
 	    printk("Error can't allocate device instance data\n");
 	    return -ENOMEM;
     }
 
-    memset(info, 0, sizeof(MGSLPC_INFO));
     info->magic = MGSLPC_MAGIC;
     INIT_WORK(&info->task, bh_handler);
     info->max_frame_size = 4096;
diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c
new file mode 100644
index 0000000..79b6f46
--- /dev/null
+++ b/drivers/char/ps3flash.c
@@ -0,0 +1,440 @@
+/*
+ * PS3 FLASH ROM Storage Driver
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony Corp.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
+
+
+#define DEVICE_NAME		"ps3flash"
+
+#define FLASH_BLOCK_SIZE	(256*1024)
+
+
+struct ps3flash_private {
+	struct mutex mutex;	/* Bounce buffer mutex */
+};
+
+static struct ps3_storage_device *ps3flash_dev;
+
+static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev,
+					   u64 lpar, u64 start_sector,
+					   u64 sectors, int write)
+{
+	u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors,
+					     write);
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__,
+			__LINE__, write ? "write" : "read", res);
+		return -EIO;
+	}
+	return sectors;
+}
+
+static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev,
+				     u64 start_sector, u64 sectors,
+				     unsigned int sector_offset)
+{
+	u64 max_sectors, lpar;
+
+	max_sectors = dev->bounce_size / dev->blk_size;
+	if (sectors > max_sectors) {
+		dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %lu\n",
+			__func__, __LINE__, max_sectors);
+		sectors = max_sectors;
+	}
+
+	lpar = dev->bounce_lpar + sector_offset * dev->blk_size;
+	return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors,
+					   0);
+}
+
+static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev,
+				    u64 start_sector)
+{
+       u64 sectors = dev->bounce_size / dev->blk_size;
+       return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector,
+					  sectors, 1);
+}
+
+static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
+{
+	struct ps3_storage_device *dev = ps3flash_dev;
+	loff_t res;
+
+	mutex_lock(&file->f_mapping->host->i_mutex);
+	switch (origin) {
+	case 1:
+		offset += file->f_pos;
+		break;
+	case 2:
+		offset += dev->regions[dev->region_idx].size*dev->blk_size;
+		break;
+	}
+	if (offset < 0) {
+		res = -EINVAL;
+		goto out;
+	}
+
+	file->f_pos = offset;
+	res = file->f_pos;
+
+out:
+	mutex_unlock(&file->f_mapping->host->i_mutex);
+	return res;
+}
+
+static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
+			     loff_t *pos)
+{
+	struct ps3_storage_device *dev = ps3flash_dev;
+	struct ps3flash_private *priv = dev->sbd.core.driver_data;
+	u64 size, start_sector, end_sector, offset;
+	ssize_t sectors_read;
+	size_t remaining, n;
+
+	dev_dbg(&dev->sbd.core,
+		"%s:%u: Reading %zu bytes at position %lld to user 0x%p\n",
+		__func__, __LINE__, count, *pos, buf);
+
+	size = dev->regions[dev->region_idx].size*dev->blk_size;
+	if (*pos >= size || !count)
+		return 0;
+
+	if (*pos + count > size) {
+		dev_dbg(&dev->sbd.core,
+			"%s:%u Truncating count from %zu to %llu\n", __func__,
+			__LINE__, count, size - *pos);
+		count = size - *pos;
+	}
+
+	start_sector = *pos / dev->blk_size;
+	offset = *pos % dev->blk_size;
+	end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size);
+
+	remaining = count;
+	do {
+		mutex_lock(&priv->mutex);
+
+		sectors_read = ps3flash_read_sectors(dev, start_sector,
+						     end_sector-start_sector,
+						     0);
+		if (sectors_read < 0) {
+			mutex_unlock(&priv->mutex);
+			goto fail;
+		}
+
+		n = min(remaining, sectors_read*dev->blk_size-offset);
+		dev_dbg(&dev->sbd.core,
+			"%s:%u: copy %lu bytes from 0x%p to user 0x%p\n",
+			__func__, __LINE__, n, dev->bounce_buf+offset, buf);
+		if (copy_to_user(buf, dev->bounce_buf+offset, n)) {
+			mutex_unlock(&priv->mutex);
+			sectors_read = -EFAULT;
+			goto fail;
+		}
+
+		mutex_unlock(&priv->mutex);
+
+		*pos += n;
+		buf += n;
+		remaining -= n;
+		start_sector += sectors_read;
+		offset = 0;
+	} while (remaining > 0);
+
+	return count;
+
+fail:
+	return sectors_read;
+}
+
+static ssize_t ps3flash_write(struct file *file, const char __user *buf,
+			      size_t count, loff_t *pos)
+{
+	struct ps3_storage_device *dev = ps3flash_dev;
+	struct ps3flash_private *priv = dev->sbd.core.driver_data;
+	u64 size, chunk_sectors, start_write_sector, end_write_sector,
+	    end_read_sector, start_read_sector, head, tail, offset;
+	ssize_t res;
+	size_t remaining, n;
+	unsigned int sec_off;
+
+	dev_dbg(&dev->sbd.core,
+		"%s:%u: Writing %zu bytes at position %lld from user 0x%p\n",
+		__func__, __LINE__, count, *pos, buf);
+
+	size = dev->regions[dev->region_idx].size*dev->blk_size;
+	if (*pos >= size || !count)
+		return 0;
+
+	if (*pos + count > size) {
+		dev_dbg(&dev->sbd.core,
+			"%s:%u Truncating count from %zu to %llu\n", __func__,
+			__LINE__, count, size - *pos);
+		count = size - *pos;
+	}
+
+	chunk_sectors = dev->bounce_size / dev->blk_size;
+
+	start_write_sector = *pos / dev->bounce_size * chunk_sectors;
+	offset = *pos % dev->bounce_size;
+	end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) *
+			   chunk_sectors;
+
+	end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size);
+	start_read_sector = (*pos + count) / dev->blk_size;
+
+	/*
+	 * As we have to write in 256 KiB chunks, while we can read in blk_size
+	 * (usually 512 bytes) chunks, we perform the following steps:
+	 *   1. Read from start_write_sector to end_read_sector ("head")
+	 *   2. Read from start_read_sector to end_write_sector ("tail")
+	 *   3. Copy data to buffer
+	 *   4. Write from start_write_sector to end_write_sector
+	 * All of this is complicated by using only one 256 KiB bounce buffer.
+	 */
+
+	head = end_read_sector - start_write_sector;
+	tail = end_write_sector - start_read_sector;
+
+	remaining = count;
+	do {
+		mutex_lock(&priv->mutex);
+
+		if (end_read_sector >= start_read_sector) {
+			/* Merge head and tail */
+			dev_dbg(&dev->sbd.core,
+				"Merged head and tail: %lu sectors at %lu\n",
+				chunk_sectors, start_write_sector);
+			res = ps3flash_read_sectors(dev, start_write_sector,
+						    chunk_sectors, 0);
+			if (res < 0)
+				goto fail;
+		} else {
+			if (head) {
+				/* Read head */
+				dev_dbg(&dev->sbd.core,
+					"head: %lu sectors at %lu\n", head,
+					start_write_sector);
+				res = ps3flash_read_sectors(dev,
+							    start_write_sector,
+							    head, 0);
+				if (res < 0)
+					goto fail;
+			}
+			if (start_read_sector <
+			    start_write_sector+chunk_sectors) {
+				/* Read tail */
+				dev_dbg(&dev->sbd.core,
+					"tail: %lu sectors at %lu\n", tail,
+					start_read_sector);
+				sec_off = start_read_sector-start_write_sector;
+				res = ps3flash_read_sectors(dev,
+							    start_read_sector,
+							    tail, sec_off);
+				if (res < 0)
+					goto fail;
+			}
+		}
+
+		n = min(remaining, dev->bounce_size-offset);
+		dev_dbg(&dev->sbd.core,
+			"%s:%u: copy %lu bytes from user 0x%p to 0x%p\n",
+			__func__, __LINE__, n, buf, dev->bounce_buf+offset);
+		if (copy_from_user(dev->bounce_buf+offset, buf, n)) {
+			res = -EFAULT;
+			goto fail;
+		}
+
+		res = ps3flash_write_chunk(dev, start_write_sector);
+		if (res < 0)
+			goto fail;
+
+		mutex_unlock(&priv->mutex);
+
+		*pos += n;
+		buf += n;
+		remaining -= n;
+		start_write_sector += chunk_sectors;
+		head = 0;
+		offset = 0;
+	} while (remaining > 0);
+
+	return count;
+
+fail:
+	mutex_unlock(&priv->mutex);
+	return res;
+}
+
+
+static irqreturn_t ps3flash_interrupt(int irq, void *data)
+{
+	struct ps3_storage_device *dev = data;
+	int res;
+	u64 tag, status;
+
+	res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
+
+	if (tag != dev->tag)
+		dev_err(&dev->sbd.core,
+			"%s:%u: tag mismatch, got %lx, expected %lx\n",
+			__func__, __LINE__, tag, dev->tag);
+
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+			__func__, __LINE__, res, status);
+	} else {
+		dev->lv1_status = status;
+		complete(&dev->done);
+	}
+	return IRQ_HANDLED;
+}
+
+
+static const struct file_operations ps3flash_fops = {
+	.owner	= THIS_MODULE,
+	.llseek	= ps3flash_llseek,
+	.read	= ps3flash_read,
+	.write	= ps3flash_write,
+};
+
+static struct miscdevice ps3flash_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= DEVICE_NAME,
+	.fops	= &ps3flash_fops,
+};
+
+static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
+{
+	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+	struct ps3flash_private *priv;
+	int error;
+	unsigned long tmp;
+
+	tmp = dev->regions[dev->region_idx].start*dev->blk_size;
+	if (tmp % FLASH_BLOCK_SIZE) {
+		dev_err(&dev->sbd.core,
+			"%s:%u region start %lu is not aligned\n", __func__,
+			__LINE__, tmp);
+		return -EINVAL;
+	}
+	tmp = dev->regions[dev->region_idx].size*dev->blk_size;
+	if (tmp % FLASH_BLOCK_SIZE) {
+		dev_err(&dev->sbd.core,
+			"%s:%u region size %lu is not aligned\n", __func__,
+			__LINE__, tmp);
+		return -EINVAL;
+	}
+
+	/* use static buffer, kmalloc cannot allocate 256 KiB */
+	if (!ps3flash_bounce_buffer.address)
+		return -ENODEV;
+
+	if (ps3flash_dev) {
+		dev_err(&dev->sbd.core,
+			"Only one FLASH device is supported\n");
+		return -EBUSY;
+	}
+
+	ps3flash_dev = dev;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv) {
+		error = -ENOMEM;
+		goto fail;
+	}
+
+	dev->sbd.core.driver_data = priv;
+	mutex_init(&priv->mutex);
+
+	dev->bounce_size = ps3flash_bounce_buffer.size;
+	dev->bounce_buf = ps3flash_bounce_buffer.address;
+
+	error = ps3stor_setup(dev, ps3flash_interrupt);
+	if (error)
+		goto fail_free_priv;
+
+	ps3flash_misc.parent = &dev->sbd.core;
+	error = misc_register(&ps3flash_misc);
+	if (error) {
+		dev_err(&dev->sbd.core, "%s:%u: misc_register failed %d\n",
+			__func__, __LINE__, error);
+		goto fail_teardown;
+	}
+
+	dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
+		 __func__, __LINE__, ps3flash_misc.minor);
+	return 0;
+
+fail_teardown:
+	ps3stor_teardown(dev);
+fail_free_priv:
+	kfree(priv);
+	dev->sbd.core.driver_data = NULL;
+fail:
+	ps3flash_dev = NULL;
+	return error;
+}
+
+static int ps3flash_remove(struct ps3_system_bus_device *_dev)
+{
+	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+
+	misc_deregister(&ps3flash_misc);
+	ps3stor_teardown(dev);
+	kfree(dev->sbd.core.driver_data);
+	dev->sbd.core.driver_data = NULL;
+	ps3flash_dev = NULL;
+	return 0;
+}
+
+
+static struct ps3_system_bus_driver ps3flash = {
+	.match_id	= PS3_MATCH_ID_STOR_FLASH,
+	.core.name	= DEVICE_NAME,
+	.core.owner	= THIS_MODULE,
+	.probe		= ps3flash_probe,
+	.remove		= ps3flash_remove,
+	.shutdown	= ps3flash_remove,
+};
+
+
+static int __init ps3flash_init(void)
+{
+	return ps3_system_bus_driver_register(&ps3flash);
+}
+
+static void __exit ps3flash_exit(void)
+{
+	ps3_system_bus_driver_unregister(&ps3flash);
+}
+
+module_init(ps3flash_init);
+module_exit(ps3flash_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS3 FLASH ROM Storage Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_FLASH);
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index de14aea..73de771 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -248,14 +248,19 @@
 	return -ENOIOCTLCMD;
 }
 
+static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
+module_param(legacy_count, int, 0);
+
 static void __init legacy_pty_init(void)
 {
+	if (legacy_count <= 0)
+		return;
 
-	pty_driver = alloc_tty_driver(NR_PTYS);
+	pty_driver = alloc_tty_driver(legacy_count);
 	if (!pty_driver)
 		panic("Couldn't allocate pty driver");
 
-	pty_slave_driver = alloc_tty_driver(NR_PTYS);
+	pty_slave_driver = alloc_tty_driver(legacy_count);
 	if (!pty_slave_driver)
 		panic("Couldn't allocate pty slave driver");
 
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 7f52712..af274e5 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -693,9 +693,14 @@
 
 	if (r->pull && r->entropy_count < nbytes * 8 &&
 	    r->entropy_count < r->poolinfo->POOLBITS) {
-		int bytes = max_t(int, random_read_wakeup_thresh / 8,
-				min_t(int, nbytes, sizeof(tmp)));
+		/* If we're limited, always leave two wakeup worth's BITS */
 		int rsvd = r->limit ? 0 : random_read_wakeup_thresh/4;
+		int bytes = nbytes;
+
+		/* pull at least as many as BYTES as wakeup BITS */
+		bytes = max_t(int, bytes, random_read_wakeup_thresh / 8);
+		/* but never more than the buffer size */
+		bytes = min_t(int, bytes, sizeof(tmp));
 
 		DEBUG_ENT("going to reseed %s with %d bits "
 			  "(%d of %d requested)\n",
@@ -1545,11 +1550,13 @@
 	 *	As close as possible to RFC 793, which
 	 *	suggests using a 250 kHz clock.
 	 *	Further reading shows this assumes 2 Mb/s networks.
-	 *	For 10 Gb/s Ethernet, a 1 GHz clock is appropriate.
-	 *	That's funny, Linux has one built in!  Use it!
-	 *	(Networks are faster now - should this be increased?)
+	 *	For 10 Mb/s Ethernet, a 1 MHz clock is appropriate.
+	 *	For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but
+	 *	we also need to limit the resolution so that the u32 seq
+	 *	overlaps less than one time per MSL (2 minutes).
+	 *	Choosing a clock of 64 ns period is OK. (period of 274 s)
 	 */
-	seq += ktime_get_real().tv64;
+	seq += ktime_get_real().tv64 >> 6;
 #if 0
 	printk("init_seq(%lx, %lx, %d, %d) = %d\n",
 	       saddr, daddr, sport, dport, seq);
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 1f0d7c6..bbfa0e2 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -255,10 +255,7 @@
 	.owner	=	THIS_MODULE,
 };
 
-static struct cdev raw_cdev = {
-	.kobj	=	{.name = "raw", },
-	.owner	=	THIS_MODULE,
-};
+static struct cdev raw_cdev;
 
 static int __init raw_init(void)
 {
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index 294e9cb..0ce9667 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -803,9 +803,7 @@
 {
 	void *p;
 
-	p = kmalloc(size, GFP_KERNEL);
-	if (p)
-		memset(p, 0, size);
+	p = kzalloc(size, GFP_KERNEL);
 	return p;
 }
 
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c
index 8cc60b6..7321d00 100644
--- a/drivers/char/rio/riocmd.c
+++ b/drivers/char/rio/riocmd.c
@@ -556,9 +556,7 @@
 {
 	struct CmdBlk *CmdBlkP;
 
-	CmdBlkP = kmalloc(sizeof(struct CmdBlk), GFP_ATOMIC);
-	if (CmdBlkP)
-		memset(CmdBlkP, 0, sizeof(struct CmdBlk));
+	CmdBlkP = kzalloc(sizeof(struct CmdBlk), GFP_ATOMIC);
 	return CmdBlkP;
 }
 
diff --git a/drivers/char/rio/riotable.c b/drivers/char/rio/riotable.c
index 7e98835..991119c 100644
--- a/drivers/char/rio/riotable.c
+++ b/drivers/char/rio/riotable.c
@@ -863,8 +863,7 @@
 		if (PortP->TxRingBuffer)
 			memset(PortP->TxRingBuffer, 0, p->RIOBufferSize);
 		else if (p->RIOBufferSize) {
-			PortP->TxRingBuffer = kmalloc(p->RIOBufferSize, GFP_KERNEL);
-			memset(PortP->TxRingBuffer, 0, p->RIOBufferSize);
+			PortP->TxRingBuffer = kzalloc(p->RIOBufferSize, GFP_KERNEL);
 		}
 		PortP->TxBufferOut = 0;
 		PortP->TxBufferIn = 0;
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 0270080..56cbba7 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -635,12 +635,11 @@
 	ctlp = sCtlNumToCtlPtr(board);
 
 	/*  Get a r_port struct for the port, fill it in and save it globally, indexed by line number */
-	info = kmalloc(sizeof (struct r_port), GFP_KERNEL);
+	info = kzalloc(sizeof (struct r_port), GFP_KERNEL);
 	if (!info) {
 		printk(KERN_INFO "Couldn't allocate info struct for line #%d\n", line);
 		return;
 	}
-	memset(info, 0, sizeof (struct r_port));
 
 	info->magic = RPORT_MAGIC;
 	info->line = line;
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index 22cf7aa..ec6b65e 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -82,16 +82,13 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-#if defined(__i386__)
+#ifdef CONFIG_X86
 #include <asm/hpet.h>
 #endif
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
 #include <linux/pci.h>
 #include <asm/ebus.h>
-#ifdef __sparc_v9__
-#include <asm/isa.h>
-#endif
 
 static unsigned long rtc_port;
 static int rtc_irq = PCI_IRQ_NONE;
@@ -930,13 +927,9 @@
 	unsigned int year, ctrl;
 	char *guess = NULL;
 #endif
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
 	struct linux_ebus *ebus;
 	struct linux_ebus_device *edev;
-#ifdef __sparc_v9__
-	struct sparc_isa_bridge *isa_br;
-	struct sparc_isa_device *isa_dev;
-#endif
 #else
 	void *r;
 #ifdef RTC_IRQ
@@ -944,7 +937,7 @@
 #endif
 #endif
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
 	for_each_ebus(ebus) {
 		for_each_ebusdev(edev, ebus) {
 			if(strcmp(edev->prom_node->name, "rtc") == 0) {
@@ -954,17 +947,6 @@
 			}
 		}
 	}
-#ifdef __sparc_v9__
-	for_each_isa(isa_br) {
-		for_each_isadev(isa_dev, isa_br) {
-			if (strcmp(isa_dev->prom_node->name, "rtc") == 0) {
-				rtc_port = isa_dev->resource.start;
-				rtc_irq = isa_dev->irq;
-				goto found;
-			}
-		}
-	}
-#endif
 	rtc_has_irq = 0;
 	printk(KERN_ERR "rtc_init: no PC rtc found\n");
 	return -EIO;
@@ -1020,7 +1002,7 @@
 
 #endif
 
-#endif /* __sparc__ vs. others */
+#endif /* CONFIG_SPARC32 vs. others */
 
 	if (misc_register(&rtc_dev)) {
 #ifdef RTC_IRQ
@@ -1105,7 +1087,7 @@
 	remove_proc_entry ("driver/rtc", NULL);
 	misc_deregister(&rtc_dev);
 
-#ifdef __sparc__
+#ifdef CONFIG_SPARC32
 	if (rtc_has_irq)
 		free_irq (rtc_irq, &rtc_port);
 #else
@@ -1117,7 +1099,7 @@
 	if (rtc_has_irq)
 		free_irq (RTC_IRQ, NULL);
 #endif
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC32 */
 }
 
 module_init(rtc_init);
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index c585b47..f1497ce 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -2573,16 +2573,10 @@
 	return cy_serial_driver;
 }
 
-static int __init serial167_console_setup(struct console *co, char *options)
-{
-	return 0;
-}
-
 static struct console sercons = {
 	.name = "ttyS",
 	.write = serial167_console_write,
 	.device = serial167_console_device,
-	.setup = serial167_console_setup,
 	.flags = CON_PRINTBUFFER,
 	.index = -1,
 };
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
index 52753e7..b9c1dba 100644
--- a/drivers/char/snsc.c
+++ b/drivers/char/snsc.c
@@ -441,8 +441,7 @@
 				continue;
 			}
 
-			class_device_create(snsc_class, NULL, dev, NULL,
-						"%s", devname);
+			device_create(snsc_class, NULL, dev, "%s", devname);
 
 			ia64_sn_irtr_intr_enable(scd->scd_nasid,
 						 0 /*ignored */ ,
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 73037a4..8598585 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -875,7 +875,7 @@
 
 #ifdef CONFIG_ACPI
 	if (sonypi_acpi_device)
-		acpi_bus_generate_event(sonypi_acpi_device, 1, event);
+		acpi_bus_generate_proc_event(sonypi_acpi_device, 1, event);
 #endif
 
 	kfifo_put(sonypi_device.fifo, (unsigned char *)&event, sizeof(event));
@@ -1147,10 +1147,15 @@
 	return 0;
 }
 
+const static struct acpi_device_id sonypi_device_ids[] = {
+	{"SNY6001", 0},
+	{"", 0},
+};
+
 static struct acpi_driver sonypi_acpi_driver = {
 	.name           = "sonypi",
 	.class          = "hkey",
-	.ids            = "SNY6001",
+	.ids            = sonypi_device_ids,
 	.ops            = {
 		           .add = sonypi_acpi_add,
 			   .remove = sonypi_acpi_remove,
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 93d0bb8..45758d5 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -4778,9 +4778,8 @@
 	if (IS_ERR(stallion_class))
 		printk("STALLION: failed to create class\n");
 	for (i = 0; i < 4; i++)
-		class_device_create(stallion_class, NULL,
-				    MKDEV(STL_SIOMEMMAJOR, i), NULL,
-				    "staliomem%d", i);
+		device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i),
+			      "staliomem%d", i);
 
 	return 0;
 err_unrtty:
@@ -4795,7 +4794,6 @@
 {
 	struct stlbrd *brdp;
 	unsigned int i, j;
-	int retval;
 
 	pr_debug("cleanup_module()\n");
 
@@ -4817,10 +4815,8 @@
 	}
 
 	for (i = 0; i < 4; i++)
-		class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
-	if ((retval = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
-		printk("STALLION: failed to un-register serial memory device, "
-			"errno=%d\n", -retval);
+		device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
+	unregister_chrdev(STL_SIOMEMMAJOR, "staliomem");
 	class_destroy(stallion_class);
 
 	pci_unregister_driver(&stl_pcidriver);
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index f53e51d..fdc256b 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -4324,13 +4324,12 @@
 {
 	struct mgsl_struct *info;
 	
-	info = kmalloc(sizeof(struct mgsl_struct),
+	info = kzalloc(sizeof(struct mgsl_struct),
 		 GFP_KERNEL);
 		 
 	if (!info) {
 		printk("Error can't allocate device instance data\n");
 	} else {
-		memset(info, 0, sizeof(struct mgsl_struct));
 		info->magic = MGSL_MAGIC;
 		INIT_WORK(&info->task, mgsl_bh_handler);
 		info->max_frame_size = 4096;
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 428b514..2f97d2f 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -1,5 +1,5 @@
 /*
- * $Id: synclink_gt.c,v 4.36 2006/08/28 20:47:14 paulkf Exp $
+ * $Id: synclink_gt.c,v 4.50 2007/07/25 19:29:25 paulkf Exp $
  *
  * Device driver for Microgate SyncLink GT serial adapters.
  *
@@ -93,7 +93,7 @@
  * module identification
  */
 static char *driver_name     = "SyncLink GT";
-static char *driver_version  = "$Revision: 4.36 $";
+static char *driver_version  = "$Revision: 4.50 $";
 static char *tty_driver_name = "synclink_gt";
 static char *tty_dev_prefix  = "ttySLG";
 MODULE_LICENSE("GPL");
@@ -477,6 +477,7 @@
 static unsigned int free_tbuf_count(struct slgt_info *info);
 static void reset_tbufs(struct slgt_info *info);
 static void tdma_reset(struct slgt_info *info);
+static void tdma_start(struct slgt_info *info);
 static void tx_load(struct slgt_info *info, const char *buf, unsigned int count);
 
 static void get_signals(struct slgt_info *info);
@@ -904,6 +905,8 @@
 		spin_lock_irqsave(&info->lock,flags);
 		if (!info->tx_active)
 		 	tx_start(info);
+		else
+			tdma_start(info);
 		spin_unlock_irqrestore(&info->lock,flags);
  	}
 
@@ -1562,6 +1565,9 @@
 	int rc;
 	unsigned long flags;
 
+	if (!try_module_get(THIS_MODULE))
+		return -EBUSY;
+
 	DBGINFO(("%s hdlcdev_open\n", dev->name));
 
 	/* generic HDLC layer open processing */
@@ -1631,6 +1637,7 @@
 	info->netcount=0;
 	spin_unlock_irqrestore(&info->netlock, flags);
 
+	module_put(THIS_MODULE);
 	return 0;
 }
 
@@ -3414,13 +3421,12 @@
 {
 	struct slgt_info *info;
 
-	info = kmalloc(sizeof(struct slgt_info), GFP_KERNEL);
+	info = kzalloc(sizeof(struct slgt_info), GFP_KERNEL);
 
 	if (!info) {
 		DBGERR(("%s device alloc failed adapter=%d port=%d\n",
 			driver_name, adapter_num, port_num));
 	} else {
-		memset(info, 0, sizeof(struct slgt_info));
 		info->magic = MGSL_MAGIC;
 		INIT_WORK(&info->task, bh_handler);
 		info->max_frame_size = 4096;
@@ -3872,44 +3878,58 @@
 			slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE);
 			/* clear tx idle and underrun status bits */
 			wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER));
-
-			if (!(rd_reg32(info, TDCSR) & BIT0)) {
-				/* tx DMA stopped, restart tx DMA */
-				tdma_reset(info);
-				/* set 1st descriptor address */
-				wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
-				switch(info->params.mode) {
-				case MGSL_MODE_RAW:
-				case MGSL_MODE_MONOSYNC:
-				case MGSL_MODE_BISYNC:
-					wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */
-					break;
-				default:
-					wr_reg32(info, TDCSR, BIT0); /* DMA enable */
-				}
-			}
-
 			if (info->params.mode == MGSL_MODE_HDLC)
 				mod_timer(&info->tx_timer, jiffies +
 						msecs_to_jiffies(5000));
 		} else {
-			tdma_reset(info);
-			/* set 1st descriptor address */
-			wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
-
 			slgt_irq_off(info, IRQ_TXDATA);
 			slgt_irq_on(info, IRQ_TXIDLE);
 			/* clear tx idle status bit */
 			wr_reg16(info, SSR, IRQ_TXIDLE);
-
-			/* enable tx DMA */
-			wr_reg32(info, TDCSR, BIT0);
 		}
-
+		tdma_start(info);
 		info->tx_active = 1;
 	}
 }
 
+/*
+ * start transmit DMA if inactive and there are unsent buffers
+ */
+static void tdma_start(struct slgt_info *info)
+{
+	unsigned int i;
+
+	if (rd_reg32(info, TDCSR) & BIT0)
+		return;
+
+	/* transmit DMA inactive, check for unsent buffers */
+	i = info->tbuf_start;
+	while (!desc_count(info->tbufs[i])) {
+		if (++i == info->tbuf_count)
+			i = 0;
+		if (i == info->tbuf_current)
+			return;
+	}
+	info->tbuf_start = i;
+
+	/* there are unsent buffers, start transmit DMA */
+
+	/* reset needed if previous error condition */
+	tdma_reset(info);
+
+	/* set 1st descriptor address */
+	wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
+	switch(info->params.mode) {
+	case MGSL_MODE_RAW:
+	case MGSL_MODE_MONOSYNC:
+	case MGSL_MODE_BISYNC:
+		wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */
+		break;
+	default:
+		wr_reg32(info, TDCSR, BIT0); /* DMA enable */
+	}
+}
+
 static void tx_stop(struct slgt_info *info)
 {
 	unsigned short val;
@@ -4643,8 +4663,8 @@
 			i=0;
 	} while (i != info->tbuf_current);
 
-	/* last buffer with zero count may be in use, assume it is */
-	if (count)
+	/* if tx DMA active, last zero count buffer is in use */
+	if (count && (rd_reg32(info, TDCSR) & BIT0))
 		--count;
 
 	return count;
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index a65407b..c63013b 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -3786,14 +3786,13 @@
 {
 	SLMP_INFO *info;
 
-	info = kmalloc(sizeof(SLMP_INFO),
+	info = kzalloc(sizeof(SLMP_INFO),
 		 GFP_KERNEL);
 
 	if (!info) {
 		printk("%s(%d) Error can't allocate device instance data for adapter %d, port %d\n",
 			__FILE__,__LINE__, adapter_num, port_num);
 	} else {
-		memset(info, 0, sizeof(SLMP_INFO));
 		info->magic = MGSL_MAGIC;
 		INIT_WORK(&info->task, bh_handler);
 		info->max_frame_size = 4096;
diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c
index 35b40b9..cef55c4 100644
--- a/drivers/char/tipar.c
+++ b/drivers/char/tipar.c
@@ -441,8 +441,8 @@
 		goto out;
 	}
 
-	class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR,
-			TIPAR_MINOR + nr), port->dev, "par%d", nr);
+	device_create(tipar_class, port->dev, MKDEV(TIPAR_MAJOR,
+			TIPAR_MINOR + nr), "par%d", nr);
 
 	/* Display informations */
 	pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq ==
@@ -534,7 +534,7 @@
 		if (table[i].dev == NULL)
 			continue;
 		parport_unregister_device(table[i].dev);
-		class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i));
+		device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i));
 	}
 	class_destroy(tipar_class);
 
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 9bb5429..39564b7 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -7,7 +7,7 @@
  * Reiner Sailer <sailer@watson.ibm.com>
  * Kylene Hall <kjhall@us.ibm.com>
  *
- * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  *
  * Device driver for TCG/TCPA TPM (trusted platform module).
  * Specifications at www.trustedcomputinggroup.org	 
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index b2e2b00..d15ccdd 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -7,7 +7,7 @@
  * Reiner Sailer <sailer@watson.ibm.com>
  * Kylene Hall <kjhall@us.ibm.com>
  *
- * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  *
  * Device driver for TCG/TCPA TPM (trusted platform module).
  * Specifications at www.trustedcomputinggroup.org	 
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index 1ab0896..d0e7926 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -7,7 +7,7 @@
  * Reiner Sailer <sailer@watson.ibm.com>
  * Kylene Hall <kjhall@us.ibm.com>
  *
- * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  *
  * Device driver for TCG/TCPA TPM (trusted platform module).
  * Specifications at www.trustedcomputinggroup.org	 
diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h
index 9363bcf..6c831f9 100644
--- a/drivers/char/tpm/tpm_atmel.h
+++ b/drivers/char/tpm/tpm_atmel.h
@@ -4,7 +4,7 @@
  * Authors:
  * Kylene Hall <kjhall@us.ibm.com>
  *
- * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  *
  * Device driver for TCG/TCPA TPM (trusted platform module).
  * Specifications at www.trustedcomputinggroup.org
diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c
index 4eba32b..60a2d26 100644
--- a/drivers/char/tpm/tpm_bios.c
+++ b/drivers/char/tpm/tpm_bios.c
@@ -7,6 +7,8 @@
  *	Reiner Sailer <sailer@watson.ibm.com>
  *	Kylene Hall <kjhall@us.ibm.com>
  *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
  * Access to the eventlog extended by the TCG BIOS of PC platform
  *
  * This program is free software; you can redistribute it and/or
@@ -427,7 +429,7 @@
 		return -ENOMEM;
 
 	if ((err = read_log(log)))
-		return err;
+		goto out_free;
 
 	/* now register seq file */
 	err = seq_open(file, &tpm_ascii_b_measurments_seqops);
@@ -435,10 +437,15 @@
 		seq = file->private_data;
 		seq->private = log;
 	} else {
-		kfree(log->bios_event_log);
-		kfree(log);
+		goto out_free;
 	}
+
+out:
 	return err;
+out_free:
+	kfree(log->bios_event_log);
+	kfree(log);
+	goto out;
 }
 
 const struct file_operations tpm_ascii_bios_measurements_ops = {
@@ -460,7 +467,7 @@
 		return -ENOMEM;
 
 	if ((err = read_log(log)))
-		return err;
+		goto out_free;
 
 	/* now register seq file */
 	err = seq_open(file, &tpm_binary_b_measurments_seqops);
@@ -468,10 +475,15 @@
 		seq = file->private_data;
 		seq->private = log;
 	} else {
-		kfree(log->bios_event_log);
-		kfree(log);
+		goto out_free;
 	}
+
+out:
 	return err;
+out_free:
+	kfree(log->bios_event_log);
+	kfree(log);
+	goto out;
 }
 
 const struct file_operations tpm_binary_bios_measurements_ops = {
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
index 608f730..6313326b 100644
--- a/drivers/char/tpm/tpm_nsc.c
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -7,7 +7,7 @@
  * Reiner Sailer <sailer@watson.ibm.com>
  * Kylene Hall <kjhall@us.ibm.com>
  *
- * Maintained by: <tpmdd_devel@lists.sourceforge.net>
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
  *
  * Device driver for TCG/TCPA TPM (trusted platform module).
  * Specifications at www.trustedcomputinggroup.org	 
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 483f3f6..23fa18a 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -5,6 +5,8 @@
  * Leendert van Doorn <leendert@watson.ibm.com>
  * Kylene Hall <kjhall@us.ibm.com>
  *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
  * Device driver for TCG/TCPA TPM (trusted platform module).
  * Specifications at www.trustedcomputinggroup.org
  *
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index de37ebc..9c867cf 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -369,25 +369,54 @@
 }
 
 /**
+ *	__tty_buffer_flush		-	flush full tty buffers
+ *	@tty: tty to flush
+ *
+ *	flush all the buffers containing receive data. Caller must
+ *	hold the buffer lock and must have ensured no parallel flush to
+ *	ldisc is running.
+ *
+ *	Locking: Caller must hold tty->buf.lock
+ */
+
+static void __tty_buffer_flush(struct tty_struct *tty)
+{
+	struct tty_buffer *thead;
+
+	while((thead = tty->buf.head) != NULL) {
+		tty->buf.head = thead->next;
+		tty_buffer_free(tty, thead);
+	}
+	tty->buf.tail = NULL;
+}
+
+/**
  *	tty_buffer_flush		-	flush full tty buffers
  *	@tty: tty to flush
  *
- *	flush all the buffers containing receive data
+ *	flush all the buffers containing receive data. If the buffer is
+ *	being processed by flush_to_ldisc then we defer the processing
+ *	to that function
  *
  *	Locking: none
  */
 
 static void tty_buffer_flush(struct tty_struct *tty)
 {
-	struct tty_buffer *thead;
 	unsigned long flags;
-
 	spin_lock_irqsave(&tty->buf.lock, flags);
-	while((thead = tty->buf.head) != NULL) {
-		tty->buf.head = thead->next;
-		tty_buffer_free(tty, thead);
-	}
-	tty->buf.tail = NULL;
+
+	/* If the data is being pushed to the tty layer then we can't
+	   process it here. Instead set a flag and the flush_to_ldisc
+	   path will process the flush request before it exits */
+	if (test_bit(TTY_FLUSHING, &tty->flags)) {
+		set_bit(TTY_FLUSHPENDING, &tty->flags);
+		spin_unlock_irqrestore(&tty->buf.lock, flags);
+		wait_event(tty->read_wait,
+				test_bit(TTY_FLUSHPENDING, &tty->flags) == 0);
+		return;
+	} else
+		__tty_buffer_flush(tty);
 	spin_unlock_irqrestore(&tty->buf.lock, flags);
 }
 
@@ -2034,8 +2063,7 @@
 	}
 
 	if (!*tp_loc) {
-		tp = (struct ktermios *) kmalloc(sizeof(struct ktermios),
-						GFP_KERNEL);
+		tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
 		if (!tp)
 			goto free_mem_out;
 		*tp = driver->init_termios;
@@ -2065,8 +2093,7 @@
 		}
 
 		if (!*o_tp_loc) {
-			o_tp = (struct ktermios *)
-				kmalloc(sizeof(struct ktermios), GFP_KERNEL);
+			o_tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
 			if (!o_tp)
 				goto free_mem_out;
 			*o_tp = driver->other->init_termios;
@@ -3594,6 +3621,7 @@
 		return;
 
 	spin_lock_irqsave(&tty->buf.lock, flags);
+	set_bit(TTY_FLUSHING, &tty->flags);	/* So we know a flush is running */
 	head = tty->buf.head;
 	if (head != NULL) {
 		tty->buf.head = NULL;
@@ -3607,6 +3635,11 @@
 				tty_buffer_free(tty, tbuf);
 				continue;
 			}
+			/* Ldisc or user is trying to flush the buffers
+			   we are feeding to the ldisc, stop feeding the
+			   line discipline as we want to empty the queue */
+			if (test_bit(TTY_FLUSHPENDING, &tty->flags))
+				break;
 			if (!tty->receive_room) {
 				schedule_delayed_work(&tty->buf.work, 1);
 				break;
@@ -3620,8 +3653,17 @@
 			disc->receive_buf(tty, char_buf, flag_buf, count);
 			spin_lock_irqsave(&tty->buf.lock, flags);
 		}
+		/* Restore the queue head */
 		tty->buf.head = head;
 	}
+	/* We may have a deferred request to flush the input buffer,
+	   if so pull the chain under the lock and empty the queue */
+	if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
+		__tty_buffer_flush(tty);
+		clear_bit(TTY_FLUSHPENDING, &tty->flags);
+		wake_up(&tty->read_wait);
+	}
+	clear_bit(TTY_FLUSHING, &tty->flags);
 	spin_unlock_irqrestore(&tty->buf.lock, flags);
 
 	tty_ldisc_deref(disc);
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 3423e9ee..3ee73cf 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -795,6 +795,7 @@
 			if (L_ICANON(tty))
 				retval = inq_canon(tty);
 			return put_user(retval, (unsigned int __user *) arg);
+#ifndef TCGETS2
 		case TIOCGLCKTRMIOS:
 			if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
 				return -EFAULT;
@@ -806,6 +807,19 @@
 			if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg))
 				return -EFAULT;
 			return 0;
+#else
+		case TIOCGLCKTRMIOS:
+			if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
+				return -EFAULT;
+			return 0;
+
+		case TIOCSLCKTRMIOS:
+			if (!capable(CAP_SYS_ADMIN))
+				return -EPERM;
+			if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg))
+				return -EFAULT;
+			return 0;
+#endif
 
 		case TIOCPKT:
 		{
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index db57277..db7a731 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -92,47 +92,6 @@
 #define VIOTAPOP_SETPART       14
 #define VIOTAPOP_UNLOAD        15
 
-struct viotapelpevent {
-	struct HvLpEvent event;
-	u32 reserved;
-	u16 version;
-	u16 sub_type_result;
-	u16 tape;
-	u16 flags;
-	u32 token;
-	u64 len;
-	union {
-		struct {
-			u32 tape_op;
-			u32 count;
-		} op;
-		struct {
-			u32 type;
-			u32 resid;
-			u32 dsreg;
-			u32 gstat;
-			u32 erreg;
-			u32 file_no;
-			u32 block_no;
-		} get_status;
-		struct {
-			u32 block_no;
-		} get_pos;
-	} u;
-};
-
-enum viotapesubtype {
-	viotapeopen = 0x0001,
-	viotapeclose = 0x0002,
-	viotaperead = 0x0003,
-	viotapewrite = 0x0004,
-	viotapegetinfo = 0x0005,
-	viotapeop = 0x0006,
-	viotapegetpos = 0x0007,
-	viotapesetpos = 0x0008,
-	viotapegetstatus = 0x0009
-};
-
 enum viotaperc {
 	viotape_InvalidRange = 0x0601,
 	viotape_InvalidToken = 0x0602,
@@ -223,14 +182,11 @@
 #define VIOT_WRITING		2
 
 /* Our info on the tapes */
-struct tape_descr {
-	char rsrcname[10];
-	char type[4];
-	char model[3];
-};
-
-static struct tape_descr *viotape_unitinfo;
-static dma_addr_t viotape_unitinfo_token;
+static struct {
+	const char *rsrcname;
+	const char *type;
+	const char *model;
+} viotape_unitinfo[VIOTAPE_MAX_TAPE];
 
 static struct mtget viomtget[VIOTAPE_MAX_TAPE];
 
@@ -381,53 +337,6 @@
 	return -err->errno;
 }
 
-/* Get info on all tapes from OS/400 */
-static int get_viotape_info(void)
-{
-	HvLpEvent_Rc hvrc;
-	int i;
-	size_t len = sizeof(*viotape_unitinfo) * VIOTAPE_MAX_TAPE;
-	struct op_struct *op = get_op_struct();
-
-	if (op == NULL)
-		return -ENOMEM;
-
-	viotape_unitinfo = dma_alloc_coherent(iSeries_vio_dev, len,
-		&viotape_unitinfo_token, GFP_ATOMIC);
-	if (viotape_unitinfo == NULL) {
-		free_op_struct(op);
-		return -ENOMEM;
-	}
-
-	memset(viotape_unitinfo, 0, len);
-
-	hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
-			HvLpEvent_Type_VirtualIo,
-			viomajorsubtype_tape | viotapegetinfo,
-			HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
-			viopath_sourceinst(viopath_hostLp),
-			viopath_targetinst(viopath_hostLp),
-			(u64) (unsigned long) op, VIOVERSION << 16,
-			viotape_unitinfo_token, len, 0, 0);
-	if (hvrc != HvLpEvent_Rc_Good) {
-		printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
-				(int)hvrc);
-		free_op_struct(op);
-		return -EIO;
-	}
-
-	wait_for_completion(&op->com);
-
-	free_op_struct(op);
-
-	for (i = 0;
-	     ((i < VIOTAPE_MAX_TAPE) && (viotape_unitinfo[i].rsrcname[0]));
-	     i++)
-		viotape_numdev++;
-	return 0;
-}
-
-
 /* Write */
 static ssize_t viotap_write(struct file *file, const char *buf,
 		size_t count, loff_t * ppos)
@@ -899,7 +808,6 @@
 	tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
 	op = (struct op_struct *)event->xCorrelationToken;
 	switch (tapeminor) {
-	case viotapegetinfo:
 	case viotapeopen:
 	case viotapeclose:
 		op->rc = tevent->sub_type_result;
@@ -942,19 +850,31 @@
 {
 	int i = vdev->unit_address;
 	int j;
+	struct device_node *node = vdev->dev.archdata.of_node;
 
-	if (i >= viotape_numdev)
+	if (i > VIOTAPE_MAX_TAPE)
+		return -ENODEV;
+	if (!node)
 		return -ENODEV;
 
+	if (i >= viotape_numdev)
+		viotape_numdev = i + 1;
+
 	tape_device[i] = &vdev->dev;
+	viotape_unitinfo[i].rsrcname = of_get_property(node,
+					"linux,vio_rsrcname", NULL);
+	viotape_unitinfo[i].type = of_get_property(node, "linux,vio_type",
+					NULL);
+	viotape_unitinfo[i].model = of_get_property(node, "linux,vio_model",
+					NULL);
 
 	state[i].cur_part = 0;
 	for (j = 0; j < MAX_PARTITIONS; ++j)
 		state[i].part_stat_rwi[j] = VIOT_IDLE;
-	class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL,
+	device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i),
 			"iseries!vt%d", i);
-	class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80),
-			NULL, "iseries!nvt%d", i);
+	device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80),
+			"iseries!nvt%d", i);
 	printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries "
 			"resource %10.10s type %4.4s, model %3.3s\n",
 			i, viotape_unitinfo[i].rsrcname,
@@ -966,8 +886,8 @@
 {
 	int i = vdev->unit_address;
 
-	class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
-	class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
+	device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
+	device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
 	return 0;
 }
 
@@ -1044,11 +964,6 @@
 		goto unreg_chrdev;
 	}
 
-	if ((ret = get_viotape_info()) < 0) {
-		printk(VIOTAPE_KERN_WARN "Unable to obtain virtual device information");
-		goto unreg_class;
-	}
-
 	ret = vio_register_driver(&viotape_driver);
 	if (ret)
 		goto unreg_class;
@@ -1098,19 +1013,10 @@
 /* Cleanup */
 static void __exit viotap_exit(void)
 {
-	int ret;
-
 	remove_proc_entry("iSeries/viotape", NULL);
 	vio_unregister_driver(&viotape_driver);
 	class_destroy(tape_class);
-	ret = unregister_chrdev(VIOTAPE_MAJOR, "viotape");
-	if (ret < 0)
-		printk(VIOTAPE_KERN_WARN "Error unregistering device: %d\n",
-				ret);
-	if (viotape_unitinfo)
-		dma_free_coherent(iSeries_vio_dev,
-				sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE,
-				viotape_unitinfo, viotape_unitinfo_token);
+	unregister_chrdev(VIOTAPE_MAJOR, "viotape");
 	viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2);
 	vio_clearHandler(viomajorsubtype_tape);
 	clear_op_struct_pool();
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index bef6d88..e122a0e 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -1013,18 +1013,10 @@
 	return scc_driver;
 }
 
-
-static int __init scc_console_setup(struct console *co, char *options)
-{
-	return 0;
-}
-
-
 static struct console sercons = {
 	.name		= "ttyS",
 	.write		= scc_console_write,
 	.device		= scc_console_device,
-	.setup		= scc_console_setup,
 	.flags		= CON_PRINTBUFFER,
 	.index		= -1,
 };
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index c6f6f42..7a61a2a 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -770,6 +770,7 @@
 		/*
 		 * Switching-from response
 		 */
+		acquire_console_sem();
 		if (vc->vt_newvt >= 0) {
 			if (arg == 0)
 				/*
@@ -784,7 +785,6 @@
 				 * complete the switch.
 				 */
 				int newvt;
-				acquire_console_sem();
 				newvt = vc->vt_newvt;
 				vc->vt_newvt = -1;
 				i = vc_allocate(newvt);
@@ -798,7 +798,6 @@
 				 * other console switches..
 				 */
 				complete_change_console(vc_cons[newvt].d);
-				release_console_sem();
 			}
 		}
 
@@ -810,9 +809,12 @@
 			/*
 			 * If it's just an ACK, ignore it
 			 */
-			if (arg != VT_ACKACQ)
+			if (arg != VT_ACKACQ) {
+				release_console_sem();
 				return -EINVAL;
+			}
 		}
+		release_console_sem();
 
 		return 0;
 
@@ -1030,7 +1032,7 @@
 
 /*
  * Sleeps until a vt is activated, or the task is interrupted. Returns
- * 0 if activation, -EINTR if interrupted.
+ * 0 if activation, -EINTR if interrupted by a signal handler.
  */
 int vt_waitactive(int vt)
 {
@@ -1055,7 +1057,7 @@
 			break;
 		}
 		release_console_sem();
-		retval = -EINTR;
+		retval = -ERESTARTNOHAND;
 		if (signal_pending(current))
 			break;
 		schedule();
@@ -1208,15 +1210,18 @@
 		/*
 		 * Send the signal as privileged - kill_pid() will
 		 * tell us if the process has gone or something else
-		 * is awry
+		 * is awry.
+		 *
+		 * We need to set vt_newvt *before* sending the signal or we
+		 * have a race.
 		 */
+		vc->vt_newvt = new_vc->vc_num;
 		if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
 			/*
 			 * It worked. Mark the vt to switch to and
 			 * return. The process needs to send us a
 			 * VT_RELDISP ioctl to complete the switch.
 			 */
-			vc->vt_newvt = new_vc->vc_num;
 			return;
 		}
 
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index 2f48ba3..37bddc1 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -55,6 +55,8 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called softdog.
 
+# ALPHA Architecture
+
 # ARM Architecture
 
 config AT91RM9200_WATCHDOG
@@ -187,15 +189,64 @@
 
 	  Say N if you are unsure.
 
+config IOP_WATCHDOG
+	tristate "IOP Watchdog"
+	depends on PLAT_IOP
+	select WATCHDOG_NOWAYOUT if (ARCH_IOP32X || ARCH_IOP33X)
+	help
+	  Say Y here if to include support for the watchdog timer
+	  in the Intel IOP3XX & IOP13XX I/O Processors.  This driver can
+	  be built as a module by choosing M. The module will
+	  be called iop_wdt.
+
+	  Note: The IOP13XX watchdog does an Internal Bus Reset which will
+	  affect both cores and the peripherals of the IOP.  The ATU-X
+	  and/or ATUe configuration registers will remain intact, but if
+	  operating as an Root Complex and/or Central Resource, the PCI-X
+	  and/or PCIe busses will also be reset.  THIS IS A VERY BIG HAMMER.
+
+config DAVINCI_WATCHDOG
+	tristate "DaVinci watchdog"
+	depends on ARCH_DAVINCI
+	help
+	  Say Y here if to include support for the watchdog timer
+	  in the DaVinci DM644x/DM646x processors.
+	  To compile this driver as a module, choose M here: the
+	  module will be called davinci_wdt.
+
+	  NOTE: once enabled, this timer cannot be disabled.
+	  Say N if you are unsure.
+
+# ARM26 Architecture
+
 # AVR32 Architecture
 
 config AT32AP700X_WDT
 	tristate "AT32AP700x watchdog"
-	depends on WATCHDOG && CPU_AT32AP7000
+	depends on CPU_AT32AP7000
 	help
 	  Watchdog timer embedded into AT32AP700x devices. This will reboot
 	  your system when the timeout is reached.
 
+# BLACKFIN Architecture
+
+config BFIN_WDT
+	tristate "Blackfin On-Chip Watchdog Timer"
+	depends on BLACKFIN
+	---help---
+	  If you say yes here you will get support for the Blackfin On-Chip
+	  Watchdog Timer. If you have one of these processors and wish to
+	  have watchdog support enabled, say Y, otherwise say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called bfin_wdt.
+
+# CRIS Architecture
+
+# FRV Architecture
+
+# H8300 Architecture
+
 # X86 (i386 + ia64 + x86_64) Architecture
 
 config ACQUIRE_WDT
@@ -524,7 +575,47 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called sbc_epx_c3.
 
-# PowerPC Architecture
+# M32R Architecture
+
+# M68K Architecture
+
+# M68KNOMMU Architecture
+
+# MIPS Architecture
+
+config INDYDOG
+	tristate "Indy/I2 Hardware Watchdog"
+	depends on SGI_IP22
+	help
+	  Hardware driver for the Indy's/I2's watchdog. This is a
+	  watchdog timer that will reboot the machine after a 60 second
+	  timer expired and no process has written to /dev/watchdog during
+	  that time.
+
+config WDT_MTX1
+	tristate "MTX-1 Hardware Watchdog"
+	depends on MIPS_MTX1
+	help
+	  Hardware driver for the MTX-1 boards. This is a watchdog timer that
+	  will reboot the machine after a 100 seconds timer expired.
+
+config WDT_RM9K_GPI
+	tristate "RM9000/GPI hardware watchdog"
+	depends on CPU_RM9000
+	help
+	  Watchdog implementation using the GPI hardware found on
+	  PMC-Sierra RM9xxx CPUs.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rm9k_wdt.
+
+# PARISC Architecture
+
+# POWERPC Architecture
+
+config MPC5200_WDT
+	tristate "MPC5200 Watchdog Timer"
+	depends on PPC_MPC52xx
 
 config 8xx_WDT
 	tristate "MPC8xx Watchdog Timer"
@@ -556,34 +647,6 @@
 	  To compile this driver as a module, choose M here. The module
 	  will be called wdrtas.
 
-# MIPS Architecture
-
-config INDYDOG
-	tristate "Indy/I2 Hardware Watchdog"
-	depends on SGI_IP22
-	help
-	  Hardware driver for the Indy's/I2's watchdog. This is a
-	  watchdog timer that will reboot the machine after a 60 second
-	  timer expired and no process has written to /dev/watchdog during
-	  that time.
-
-config WDT_MTX1
-	tristate "MTX-1 Hardware Watchdog"
-	depends on MIPS_MTX1
-	help
-	  Hardware driver for the MTX-1 boards. This is a watchdog timer that
-	  will reboot the machine after a 100 seconds timer expired.
-
-config WDT_RM9K_GPI
-	tristate "RM9000/GPI hardware watchdog"
-	depends on CPU_RM9000
-	help
-	  Watchdog implementation using the GPI hardware found on
-	  PMC-Sierra RM9xxx CPUs.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called rm9k_wdt.
-
 # S390 Architecture
 
 config ZVM_WATCHDOG
@@ -598,11 +661,11 @@
 	  To compile this driver as a module, choose M here. The module
 	  will be called vmwatchdog.
 
-# SUPERH Architecture
+# SUPERH (sh + sh64) Architecture
 
 config SH_WDT
 	tristate "SuperH Watchdog"
-	depends on SUPERH
+	depends on SUPERH && (CPU_SH3 || CPU_SH4)
 	help
 	  This driver adds watchdog support for the integrated watchdog in the
 	  SuperH processors. If you have one of these processors and wish
@@ -625,6 +688,8 @@
 	  If you say Y here, user applications will be able to mmap the
 	  WDT/CPG registers.
 
+# SPARC Architecture
+
 # SPARC64 Architecture
 
 config WATCHDOG_CP1XXX
@@ -649,6 +714,10 @@
 	  machines.  The watchdog timeout period is normally one minute but
 	  can be changed with a boot-time parameter.
 
+# V850 Architecture
+
+# XTENSA Architecture
+
 #
 # ISA-based Watchdog Cards
 #
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index 3907ec0..389f8b1 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -22,6 +22,8 @@
 # USB-based Watchdog Cards
 obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
 
+# ALPHA Architecture
+
 # ARM Architecture
 obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
 obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
@@ -35,10 +37,23 @@
 obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
 obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
 obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
+obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
+obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
+
+# ARM26 Architecture
 
 # AVR32 Architecture
 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
 
+# BLACKFIN Architecture
+obj-$(CONFIG_BFIN_WDT) += bfin_wdt.o
+
+# CRIS Architecture
+
+# FRV Architecture
+
+# H8300 Architecture
+
 # X86 (i386 + ia64 + x86_64) Architecture
 obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
 obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
@@ -65,8 +80,22 @@
 obj-$(CONFIG_MACHZ_WDT) += machzwd.o
 obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
 
-# PowerPC Architecture
+# M32R Architecture
+
+# M68K Architecture
+
+# M68KNOMMU Architecture
+
+# MIPS Architecture
+obj-$(CONFIG_INDYDOG) += indydog.o
+obj-$(CONFIG_WDT_MTX1)	+= mtx-1_wdt.o
+obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
+
+# PARISC Architecture
+
+# POWERPC Architecture
 obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
+obj-$(CONFIG_MPC5200_WDT) += mpc5200_wdt.o
 obj-$(CONFIG_83xx_WDT) += mpc83xx_wdt.o
 obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
 obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
@@ -74,17 +103,18 @@
 # PPC64 Architecture
 obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
 
-# MIPS Architecture
-obj-$(CONFIG_INDYDOG) += indydog.o
-obj-$(CONFIG_WDT_MTX1)	+= mtx-1_wdt.o
-obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
-
 # S390 Architecture
 
-# SUPERH Architecture
+# SUPERH (sh + sh64) Architecture
 obj-$(CONFIG_SH_WDT) += shwdt.o
 
+# SPARC Architecture
+
 # SPARC64 Architecture
 
+# V850 Architecture
+
+# XTENSA Architecture
+
 # Architecture Independant
 obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
diff --git a/drivers/char/watchdog/alim1535_wdt.c b/drivers/char/watchdog/alim1535_wdt.c
index e3f6a7d..c404fc6 100644
--- a/drivers/char/watchdog/alim1535_wdt.c
+++ b/drivers/char/watchdog/alim1535_wdt.c
@@ -312,6 +312,7 @@
  */
 
 static struct pci_device_id ali_pci_tbl[] = {
+	{ PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,},
 	{ PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,},
 	{ 0, },
 };
@@ -329,9 +330,11 @@
 	struct pci_dev *pdev;
 	u32 wdog;
 
-	/* Check for a 1535 series bridge */
+	/* Check for a 1533/1535 series bridge */
 	pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x1535, NULL);
-	if(pdev == NULL)
+	if (pdev == NULL)
+		pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x1533, NULL);
+	if (pdev == NULL)
 		return -ENODEV;
 	pci_dev_put(pdev);
 
diff --git a/drivers/char/watchdog/bfin_wdt.c b/drivers/char/watchdog/bfin_wdt.c
new file mode 100644
index 0000000..309d279
--- /dev/null
+++ b/drivers/char/watchdog/bfin_wdt.c
@@ -0,0 +1,490 @@
+/*
+ * Blackfin On-Chip Watchdog Driver
+ *  Supports BF53[123]/BF53[467]/BF54[2489]/BF561
+ *
+ * Originally based on softdog.c
+ * Copyright 2006-2007 Analog Devices Inc.
+ * Copyright 2006-2007 Michele d'Amico
+ * Copyright 1996 Alan Cox <alan@redhat.com>
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/blackfin.h>
+#include <asm/uaccess.h>
+
+#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
+#define stampit() stamp("here i am")
+
+#define WATCHDOG_NAME "bfin-wdt"
+#define PFX WATCHDOG_NAME ": "
+
+/* The BF561 has two watchdogs (one per core), but since Linux
+ * only runs on core A, we'll just work with that one.
+ */
+#ifdef BF561_FAMILY
+# define bfin_read_WDOG_CTL()    bfin_read_WDOGA_CTL()
+# define bfin_read_WDOG_CNT()    bfin_read_WDOGA_CNT()
+# define bfin_read_WDOG_STAT()   bfin_read_WDOGA_STAT()
+# define bfin_write_WDOG_CTL(x)  bfin_write_WDOGA_CTL(x)
+# define bfin_write_WDOG_CNT(x)  bfin_write_WDOGA_CNT(x)
+# define bfin_write_WDOG_STAT(x) bfin_write_WDOGA_STAT(x)
+#endif
+
+/* Bit in SWRST that indicates boot caused by watchdog */
+#define SWRST_RESET_WDOG 0x4000
+
+/* Bit in WDOG_CTL that indicates watchdog has expired (WDR0) */
+#define WDOG_EXPIRED 0x8000
+
+/* Masks for WDEV field in WDOG_CTL register */
+#define ICTL_RESET   0x0
+#define ICTL_NMI     0x2
+#define ICTL_GPI     0x4
+#define ICTL_NONE    0x6
+#define ICTL_MASK    0x6
+
+/* Masks for WDEN field in WDOG_CTL register */
+#define WDEN_MASK    0x0FF0
+#define WDEN_ENABLE  0x0000
+#define WDEN_DISABLE 0x0AD0
+
+/* some defaults */
+#define WATCHDOG_TIMEOUT 20
+
+static unsigned int timeout = WATCHDOG_TIMEOUT;
+static int nowayout = WATCHDOG_NOWAYOUT;
+static struct watchdog_info bfin_wdt_info;
+static unsigned long open_check;
+static char expect_close;
+static spinlock_t bfin_wdt_spinlock = SPIN_LOCK_UNLOCKED;
+
+/**
+ *	bfin_wdt_keepalive - Keep the Userspace Watchdog Alive
+ *
+ * 	The Userspace watchdog got a KeepAlive: schedule the next timeout.
+ */
+static int bfin_wdt_keepalive(void)
+{
+	stampit();
+	bfin_write_WDOG_STAT(0);
+	return 0;
+}
+
+/**
+ *	bfin_wdt_stop - Stop the Watchdog
+ *
+ *	Stops the on-chip watchdog.
+ */
+static int bfin_wdt_stop(void)
+{
+	stampit();
+	bfin_write_WDOG_CTL(WDEN_DISABLE);
+	return 0;
+}
+
+/**
+ *	bfin_wdt_start - Start the Watchdog
+ *
+ *	Starts the on-chip watchdog.  Automatically loads WDOG_CNT
+ *	into WDOG_STAT for us.
+ */
+static int bfin_wdt_start(void)
+{
+	stampit();
+	bfin_write_WDOG_CTL(WDEN_ENABLE | ICTL_RESET);
+	return 0;
+}
+
+/**
+ *	bfin_wdt_running - Check Watchdog status
+ *
+ *	See if the watchdog is running.
+ */
+static int bfin_wdt_running(void)
+{
+	stampit();
+	return ((bfin_read_WDOG_CTL() & WDEN_MASK) != WDEN_DISABLE);
+}
+
+/**
+ *	bfin_wdt_set_timeout - Set the Userspace Watchdog timeout
+ *	@t: new timeout value (in seconds)
+ *
+ *	Translate the specified timeout in seconds into System Clock
+ *	terms which is what the on-chip Watchdog requires.
+ */
+static int bfin_wdt_set_timeout(unsigned long t)
+{
+	u32 cnt;
+	unsigned long flags;
+
+	stampit();
+
+	cnt = t * get_sclk();
+	if (cnt < get_sclk()) {
+		printk(KERN_WARNING PFX "timeout value is too large\n");
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&bfin_wdt_spinlock, flags);
+	{
+		int run = bfin_wdt_running();
+		bfin_wdt_stop();
+		bfin_write_WDOG_CNT(cnt);
+		if (run) bfin_wdt_start();
+	}
+	spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
+
+	timeout = t;
+
+	return 0;
+}
+
+/**
+ *	bfin_wdt_open - Open the Device
+ *	@inode: inode of device
+ *	@file: file handle of device
+ *
+ *	Watchdog device is opened and started.
+ */
+static int bfin_wdt_open(struct inode *inode, struct file *file)
+{
+	stampit();
+
+	if (test_and_set_bit(0, &open_check))
+		return -EBUSY;
+
+	if (nowayout)
+		__module_get(THIS_MODULE);
+
+	bfin_wdt_keepalive();
+	bfin_wdt_start();
+
+	return nonseekable_open(inode, file);
+}
+
+/**
+ *	bfin_wdt_close - Close the Device
+ *	@inode: inode of device
+ *	@file: file handle of device
+ *
+ *	Watchdog device is closed and stopped.
+ */
+static int bfin_wdt_release(struct inode *inode, struct file *file)
+{
+	stampit();
+
+	if (expect_close == 42) {
+		bfin_wdt_stop();
+	} else {
+		printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+		bfin_wdt_keepalive();
+	}
+
+	expect_close = 0;
+	clear_bit(0, &open_check);
+
+	return 0;
+}
+
+/**
+ *	bfin_wdt_write - Write to Device
+ *	@file: file handle of device
+ *	@buf: buffer to write
+ *	@count: length of buffer
+ *	@ppos: offset
+ *
+ *	Pings the watchdog on write.
+ */
+static ssize_t bfin_wdt_write(struct file *file, const char __user *data,
+                              size_t len, loff_t *ppos)
+{
+	stampit();
+
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			expect_close = 0;
+
+			for (i = 0; i != len; i++) {
+				char c;
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 42;
+			}
+		}
+		bfin_wdt_keepalive();
+	}
+
+	return len;
+}
+
+/**
+ *	bfin_wdt_ioctl - Query Device
+ *	@inode: inode of device
+ *	@file: file handle of device
+ *	@cmd: watchdog command
+ *	@arg: argument
+ *
+ *	Query basic information from the device or ping it, as outlined by the
+ *	watchdog API.
+ */
+static int bfin_wdt_ioctl(struct inode *inode, struct file *file,
+                          unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+
+	stampit();
+
+	switch (cmd) {
+		default:
+			return -ENOTTY;
+
+		case WDIOC_GETSUPPORT:
+			if (copy_to_user(argp, &bfin_wdt_info, sizeof(bfin_wdt_info)))
+				return -EFAULT;
+			else
+				return 0;
+
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(!!(_bfin_swrst & SWRST_RESET_WDOG), p);
+
+		case WDIOC_KEEPALIVE:
+			bfin_wdt_keepalive();
+			return 0;
+
+		case WDIOC_SETTIMEOUT: {
+			int new_timeout;
+
+			if (get_user(new_timeout, p))
+				return -EFAULT;
+
+			if (bfin_wdt_set_timeout(new_timeout))
+				return -EINVAL;
+		}
+			/* Fall */
+		case WDIOC_GETTIMEOUT:
+			return put_user(timeout, p);
+
+		case WDIOC_SETOPTIONS: {
+			unsigned long flags;
+			int options, ret = -EINVAL;
+
+			if (get_user(options, p))
+				return -EFAULT;
+
+			spin_lock_irqsave(&bfin_wdt_spinlock, flags);
+
+			if (options & WDIOS_DISABLECARD) {
+				bfin_wdt_stop();
+				ret = 0;
+			}
+
+			if (options & WDIOS_ENABLECARD) {
+				bfin_wdt_start();
+				ret = 0;
+			}
+
+			spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
+
+			return ret;
+		}
+	}
+}
+
+/**
+ *	bfin_wdt_notify_sys - Notifier Handler
+ *	@this: notifier block
+ *	@code: notifier event
+ *	@unused: unused
+ *
+ *	Handles specific events, such as turning off the watchdog during a
+ *	shutdown event.
+ */
+static int bfin_wdt_notify_sys(struct notifier_block *this, unsigned long code,
+                               void *unused)
+{
+	stampit();
+
+	if (code == SYS_DOWN || code == SYS_HALT)
+		bfin_wdt_stop();
+
+	return NOTIFY_DONE;
+}
+
+#ifdef CONFIG_PM
+static int state_before_suspend;
+
+/**
+ *	bfin_wdt_suspend - suspend the watchdog
+ *	@pdev: device being suspended
+ *	@state: requested suspend state
+ *
+ *	Remember if the watchdog was running and stop it.
+ *	TODO: is this even right?  Doesn't seem to be any
+ *	      standard in the watchdog world ...
+ */
+static int bfin_wdt_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	stampit();
+
+	state_before_suspend = bfin_wdt_running();
+	bfin_wdt_stop();
+
+	return 0;
+}
+
+/**
+ *	bfin_wdt_resume - resume the watchdog
+ *	@pdev: device being resumed
+ *
+ *	If the watchdog was running, turn it back on.
+ */
+static int bfin_wdt_resume(struct platform_device *pdev)
+{
+	stampit();
+
+	if (state_before_suspend) {
+		bfin_wdt_set_timeout(timeout);
+		bfin_wdt_start();
+	}
+
+	return 0;
+}
+#else
+# define bfin_wdt_suspend NULL
+# define bfin_wdt_resume NULL
+#endif
+
+static struct platform_device bfin_wdt_device = {
+	.name          = WATCHDOG_NAME,
+	.id            = -1,
+};
+
+static struct platform_driver bfin_wdt_driver = {
+	.driver    = {
+		.name  = WATCHDOG_NAME,
+		.owner = THIS_MODULE,
+	},
+	.suspend   = bfin_wdt_suspend,
+	.resume    = bfin_wdt_resume,
+};
+
+static struct file_operations bfin_wdt_fops = {
+	.owner    = THIS_MODULE,
+	.llseek   = no_llseek,
+	.write    = bfin_wdt_write,
+	.ioctl    = bfin_wdt_ioctl,
+	.open     = bfin_wdt_open,
+	.release  = bfin_wdt_release,
+};
+
+static struct miscdevice bfin_wdt_miscdev = {
+	.minor    = WATCHDOG_MINOR,
+	.name     = "watchdog",
+	.fops     = &bfin_wdt_fops,
+};
+
+static struct watchdog_info bfin_wdt_info = {
+	.identity = "Blackfin Watchdog",
+	.options  = WDIOF_SETTIMEOUT |
+	            WDIOF_KEEPALIVEPING |
+	            WDIOF_MAGICCLOSE,
+};
+
+static struct notifier_block bfin_wdt_notifier = {
+	.notifier_call = bfin_wdt_notify_sys,
+};
+
+/**
+ *	bfin_wdt_init - Initialize module
+ *
+ *	Registers the device and notifier handler. Actual device
+ *	initialization is handled by bfin_wdt_open().
+ */
+static int __init bfin_wdt_init(void)
+{
+	int ret;
+
+	stampit();
+
+	/* Check that the timeout value is within range */
+	if (bfin_wdt_set_timeout(timeout))
+		return -EINVAL;
+
+	/* Since this is an on-chip device and needs no board-specific
+	 * resources, we'll handle all the platform device stuff here.
+	 */
+	ret = platform_device_register(&bfin_wdt_device);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_probe(&bfin_wdt_driver, NULL);
+	if (ret)
+		return ret;
+
+	ret = register_reboot_notifier(&bfin_wdt_notifier);
+	if (ret) {
+		printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret);
+		return ret;
+	}
+
+	ret = misc_register(&bfin_wdt_miscdev);
+	if (ret) {
+		printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+		       WATCHDOG_MINOR, ret);
+		unregister_reboot_notifier(&bfin_wdt_notifier);
+		return ret;
+	}
+
+	printk(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
+	       timeout, nowayout);
+
+	return 0;
+}
+
+/**
+ *	bfin_wdt_exit - Deinitialize module
+ *
+ *	Unregisters the device and notifier handler. Actual device
+ *	deinitialization is handled by bfin_wdt_close().
+ */
+static void __exit bfin_wdt_exit(void)
+{
+	misc_deregister(&bfin_wdt_miscdev);
+	unregister_reboot_notifier(&bfin_wdt_notifier);
+}
+
+module_init(bfin_wdt_init);
+module_exit(bfin_wdt_exit);
+
+MODULE_AUTHOR("Michele d'Amico, Mike Frysinger <vapier@gentoo.org>");
+MODULE_DESCRIPTION("Blackfin Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c
index 0f5c77d..d362f5b 100644
--- a/drivers/char/watchdog/booke_wdt.c
+++ b/drivers/char/watchdog/booke_wdt.c
@@ -144,7 +144,7 @@
 				booke_wdt_period);
 	}
 
-	return 0;
+	return nonseekable_open(inode, file);
 }
 
 static const struct file_operations booke_wdt_fops = {
diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c
index d0d45a8..5941ca6 100644
--- a/drivers/char/watchdog/cpu5wdt.c
+++ b/drivers/char/watchdog/cpu5wdt.c
@@ -162,6 +162,10 @@
 			if ( copy_to_user(argp, &value, sizeof(int)) )
 				return -EFAULT;
 			break;
+		case WDIOC_GETBOOTSTATUS:
+			if ( copy_to_user(argp, &value, sizeof(int)) )
+				return -EFAULT;
+			break;
 		case WDIOC_GETSUPPORT:
 			if ( copy_to_user(argp, &ident, sizeof(ident)) )
 				return -EFAULT;
diff --git a/drivers/char/watchdog/davinci_wdt.c b/drivers/char/watchdog/davinci_wdt.c
new file mode 100644
index 0000000..19db530
--- /dev/null
+++ b/drivers/char/watchdog/davinci_wdt.c
@@ -0,0 +1,281 @@
+/*
+ * drivers/char/watchdog/davinci_wdt.c
+ *
+ * Watchdog driver for DaVinci DM644x/DM646x processors
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#include <asm/hardware.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#define MODULE_NAME "DAVINCI-WDT: "
+
+#define DEFAULT_HEARTBEAT 60
+#define MAX_HEARTBEAT     600	/* really the max margin is 264/27MHz*/
+
+/* Timer register set definition */
+#define PID12	(0x0)
+#define EMUMGT	(0x4)
+#define TIM12	(0x10)
+#define TIM34	(0x14)
+#define PRD12	(0x18)
+#define PRD34	(0x1C)
+#define TCR	(0x20)
+#define TGCR	(0x24)
+#define WDTCR	(0x28)
+
+/* TCR bit definitions */
+#define ENAMODE12_DISABLED	(0 << 6)
+#define ENAMODE12_ONESHOT	(1 << 6)
+#define ENAMODE12_PERIODIC	(2 << 6)
+
+/* TGCR bit definitions */
+#define TIM12RS_UNRESET		(1 << 0)
+#define TIM34RS_UNRESET		(1 << 1)
+#define TIMMODE_64BIT_WDOG      (2 << 2)
+
+/* WDTCR bit definitions */
+#define WDEN			(1 << 14)
+#define WDFLAG			(1 << 15)
+#define WDKEY_SEQ0		(0xa5c6 << 16)
+#define WDKEY_SEQ1		(0xda7e << 16)
+
+static int heartbeat = DEFAULT_HEARTBEAT;
+
+static spinlock_t io_lock;
+static unsigned long wdt_status;
+#define WDT_IN_USE        0
+#define WDT_OK_TO_CLOSE   1
+#define WDT_REGION_INITED 2
+#define WDT_DEVICE_INITED 3
+
+static struct resource	*wdt_mem;
+static void __iomem	*wdt_base;
+
+static void wdt_service(void)
+{
+	spin_lock(&io_lock);
+
+	/* put watchdog in service state */
+	davinci_writel(WDKEY_SEQ0, wdt_base + WDTCR);
+	/* put watchdog in active state */
+	davinci_writel(WDKEY_SEQ1, wdt_base + WDTCR);
+
+	spin_unlock(&io_lock);
+}
+
+static void wdt_enable(void)
+{
+	u32 tgcr;
+	u32 timer_margin;
+
+	spin_lock(&io_lock);
+
+	/* disable, internal clock source */
+	davinci_writel(0, wdt_base + TCR);
+	/* reset timer, set mode to 64-bit watchdog, and unreset */
+	davinci_writel(0, wdt_base + TGCR);
+	tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET;
+	davinci_writel(tgcr, wdt_base + TGCR);
+	/* clear counter regs */
+	davinci_writel(0, wdt_base + TIM12);
+	davinci_writel(0, wdt_base + TIM34);
+	/* set timeout period */
+	timer_margin = (((u64)heartbeat * CLOCK_TICK_RATE) & 0xffffffff);
+	davinci_writel(timer_margin, wdt_base + PRD12);
+	timer_margin = (((u64)heartbeat * CLOCK_TICK_RATE) >> 32);
+	davinci_writel(timer_margin, wdt_base + PRD34);
+	/* enable run continuously */
+	davinci_writel(ENAMODE12_PERIODIC, wdt_base + TCR);
+	/* Once the WDT is in pre-active state write to
+	 * TIM12, TIM34, PRD12, PRD34, TCR, TGCR, WDTCR are
+	 * write protected (except for the WDKEY field)
+	 */
+	/* put watchdog in pre-active state */
+	davinci_writel(WDKEY_SEQ0 | WDEN, wdt_base + WDTCR);
+	/* put watchdog in active state */
+	davinci_writel(WDKEY_SEQ1 | WDEN, wdt_base + WDTCR);
+
+	spin_unlock(&io_lock);
+}
+
+static int davinci_wdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+		return -EBUSY;
+
+	wdt_enable();
+
+	return nonseekable_open(inode, file);
+}
+
+static ssize_t
+davinci_wdt_write(struct file *file, const char *data, size_t len,
+		  loff_t *ppos)
+{
+	if (len)
+		wdt_service();
+
+	return len;
+}
+
+static struct watchdog_info ident = {
+	.options = WDIOF_KEEPALIVEPING,
+	.identity = "DaVinci Watchdog",
+};
+
+static int
+davinci_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		  unsigned long arg)
+{
+	int ret = -ENOTTY;
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		ret = copy_to_user((struct watchdog_info *)arg, &ident,
+				   sizeof(ident)) ? -EFAULT : 0;
+		break;
+
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		ret = put_user(0, (int *)arg);
+		break;
+
+	case WDIOC_GETTIMEOUT:
+		ret = put_user(heartbeat, (int *)arg);
+		break;
+
+	case WDIOC_KEEPALIVE:
+		wdt_service();
+		ret = 0;
+		break;
+	}
+	return ret;
+}
+
+static int davinci_wdt_release(struct inode *inode, struct file *file)
+{
+	wdt_service();
+	clear_bit(WDT_IN_USE, &wdt_status);
+
+	return 0;
+}
+
+static const struct file_operations davinci_wdt_fops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.write = davinci_wdt_write,
+	.ioctl = davinci_wdt_ioctl,
+	.open = davinci_wdt_open,
+	.release = davinci_wdt_release,
+};
+
+static struct miscdevice davinci_wdt_miscdev = {
+	.minor = WATCHDOG_MINOR,
+	.name = "watchdog",
+	.fops = &davinci_wdt_fops,
+};
+
+static int davinci_wdt_probe(struct platform_device *pdev)
+{
+	int ret = 0, size;
+	struct resource *res;
+
+	spin_lock_init(&io_lock);
+
+	if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
+		heartbeat = DEFAULT_HEARTBEAT;
+
+	printk(KERN_INFO MODULE_NAME
+		"DaVinci Watchdog Timer: heartbeat %d sec\n", heartbeat);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		printk(KERN_INFO MODULE_NAME
+			"failed to get memory region resource\n");
+		return -ENOENT;
+	}
+
+	size = res->end - res->start + 1;
+	wdt_mem = request_mem_region(res->start, size, pdev->name);
+
+	if (wdt_mem == NULL) {
+		printk(KERN_INFO MODULE_NAME "failed to get memory region\n");
+		return -ENOENT;
+	}
+	wdt_base = (void __iomem *)(res->start);
+
+	ret = misc_register(&davinci_wdt_miscdev);
+	if (ret < 0) {
+		printk(KERN_ERR MODULE_NAME "cannot register misc device\n");
+		release_resource(wdt_mem);
+		kfree(wdt_mem);
+	} else {
+		set_bit(WDT_DEVICE_INITED, &wdt_status);
+	}
+
+	return ret;
+}
+
+static int davinci_wdt_remove(struct platform_device *pdev)
+{
+	misc_deregister(&davinci_wdt_miscdev);
+	if (wdt_mem) {
+		release_resource(wdt_mem);
+		kfree(wdt_mem);
+		wdt_mem = NULL;
+	}
+	return 0;
+}
+
+static struct platform_driver platform_wdt_driver = {
+	.driver = {
+		.name = "watchdog",
+	},
+	.probe = davinci_wdt_probe,
+	.remove = davinci_wdt_remove,
+};
+
+static int __init davinci_wdt_init(void)
+{
+	return platform_driver_register(&platform_wdt_driver);
+}
+
+static void __exit davinci_wdt_exit(void)
+{
+	return platform_driver_unregister(&platform_wdt_driver);
+}
+
+module_init(davinci_wdt_init);
+module_exit(davinci_wdt_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("DaVinci Watchdog Driver");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat,
+		 "Watchdog heartbeat period in seconds from 1 to "
+		 __MODULE_STRING(MAX_HEARTBEAT) ", default "
+		 __MODULE_STRING(DEFAULT_HEARTBEAT));
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c
index b070324..b14e9d1 100644
--- a/drivers/char/watchdog/eurotechwdt.c
+++ b/drivers/char/watchdog/eurotechwdt.c
@@ -1,5 +1,5 @@
 /*
- *	Eurotech CPU-1220/1410 on board WDT driver
+ *	Eurotech CPU-1220/1410/1420 on board WDT driver
  *
  *	(c) Copyright 2001 Ascensit <support@ascensit.com>
  *	(c) Copyright 2001 Rodolfo Giometti <giometti@ascensit.com>
@@ -25,6 +25,9 @@
 
 /* Changelog:
  *
+ * 2001 - Rodolfo Giometti
+ *	Initial release
+ *
  * 2002/04/25 - Rob Radez
  *	clean up #includes
  *	clean up locking
@@ -33,13 +36,15 @@
  *	add WDIOC_GETSTATUS and WDIOC_SETOPTIONS ioctls
  *	add expect_close support
  *
- * 2001 - Rodolfo Giometti
- *	Initial release
- *
  * 2002.05.30 - Joel Becker <joel.becker@oracle.com>
  * 	Added Matt Domsch's nowayout module option.
  */
 
+/*
+ *	The eurotech CPU-1220/1410/1420's watchdog is a part
+ *	of the on-board SUPER I/O device SMSC FDC 37B782.
+ */
+
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c
index eac4f9b..cd5a565 100644
--- a/drivers/char/watchdog/iTCO_wdt.c
+++ b/drivers/char/watchdog/iTCO_wdt.c
@@ -39,7 +39,12 @@
  *	82801HR  (ICH8R)     : document number 313056-002, 313057-004,
  *	82801HH  (ICH8DH)    : document number 313056-002, 313057-004,
  *	82801HO  (ICH8DO)    : document number 313056-002, 313057-004,
- *	6300ESB  (6300ESB)   : document number 300641-003
+ *	82801IB  (ICH9)      : document number 316972-001, 316973-001,
+ *	82801IR  (ICH9R)     : document number 316972-001, 316973-001,
+ *	82801IH  (ICH9DH)    : document number 316972-001, 316973-001,
+ *	6300ESB  (6300ESB)   : document number 300641-003, 300884-010,
+ *	631xESB  (631xESB)   : document number 313082-001, 313075-005,
+ *	632xESB  (632xESB)   : document number 313082-001, 313075-005
  */
 
 /*
@@ -48,8 +53,8 @@
 
 /* Module and version information */
 #define DRV_NAME        "iTCO_wdt"
-#define DRV_VERSION     "1.01"
-#define DRV_RELDATE     "21-Jan-2007"
+#define DRV_VERSION     "1.02"
+#define DRV_RELDATE     "26-Jul-2007"
 #define PFX		DRV_NAME ": "
 
 /* Includes */
@@ -92,6 +97,10 @@
 	TCO_ICH8,	/* ICH8 & ICH8R */
 	TCO_ICH8DH,	/* ICH8DH */
 	TCO_ICH8DO,	/* ICH8DO */
+	TCO_ICH9,	/* ICH9 */
+	TCO_ICH9R,	/* ICH9R */
+	TCO_ICH9DH,	/* ICH9DH */
+	TCO_631XESB,	/* 631xESB/632xESB */
 };
 
 static struct {
@@ -118,6 +127,10 @@
 	{"ICH8 or ICH8R", 2},
 	{"ICH8DH", 2},
 	{"ICH8DO", 2},
+	{"ICH9", 2},
+	{"ICH9R", 2},
+	{"ICH9DH", 2},
+	{"631xESB/632xESB", 2},
 	{NULL,0}
 };
 
@@ -148,6 +161,25 @@
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8    },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DH  },
 	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DO  },
+	{ PCI_VENDOR_ID_INTEL, 0x2918,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9    },
+	{ PCI_VENDOR_ID_INTEL, 0x2916,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9R    },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_2,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9DH    },
+	{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+	{ PCI_VENDOR_ID_INTEL, 0x2671,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+	{ PCI_VENDOR_ID_INTEL, 0x2672,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+	{ PCI_VENDOR_ID_INTEL, 0x2673,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+	{ PCI_VENDOR_ID_INTEL, 0x2674,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+	{ PCI_VENDOR_ID_INTEL, 0x2675,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+	{ PCI_VENDOR_ID_INTEL, 0x2676,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+	{ PCI_VENDOR_ID_INTEL, 0x2677,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+	{ PCI_VENDOR_ID_INTEL, 0x2678,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+	{ PCI_VENDOR_ID_INTEL, 0x2679,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+	{ PCI_VENDOR_ID_INTEL, 0x267a,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+	{ PCI_VENDOR_ID_INTEL, 0x267b,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+	{ PCI_VENDOR_ID_INTEL, 0x267c,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+	{ PCI_VENDOR_ID_INTEL, 0x267d,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+	{ PCI_VENDOR_ID_INTEL, 0x267e,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+	{ PCI_VENDOR_ID_INTEL, 0x267f,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
 	{ 0, },			/* End of list */
 };
 MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl);
diff --git a/drivers/char/watchdog/iop_wdt.c b/drivers/char/watchdog/iop_wdt.c
new file mode 100644
index 0000000..bbbd91a
--- /dev/null
+++ b/drivers/char/watchdog/iop_wdt.c
@@ -0,0 +1,262 @@
+/*
+ * drivers/char/watchdog/iop_wdt.c
+ *
+ * WDT driver for Intel I/O Processors
+ * Copyright (C) 2005, Intel Corporation.
+ *
+ * Based on ixp4xx driver, Copyright 2004 (c) MontaVista, Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ *	Curt E Bruns <curt.e.bruns@intel.com>
+ *	Peter Milne <peter.milne@d-tacq.com>
+ *	Dan Williams <dan.j.williams@intel.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/uaccess.h>
+#include <asm/hardware.h>
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static unsigned long wdt_status;
+static unsigned long boot_status;
+
+#define WDT_IN_USE		0
+#define WDT_OK_TO_CLOSE		1
+#define WDT_ENABLED		2
+
+static unsigned long iop_watchdog_timeout(void)
+{
+	return (0xffffffffUL / get_iop_tick_rate());
+}
+
+/**
+ * wdt_supports_disable - determine if we are accessing a iop13xx watchdog
+ * or iop3xx by whether it has a disable command
+ */
+static int wdt_supports_disable(void)
+{
+	int can_disable;
+
+	if (IOP_WDTCR_EN_ARM != IOP_WDTCR_DIS_ARM)
+		can_disable = 1;
+	else
+		can_disable = 0;
+
+	return can_disable;
+}
+
+static void wdt_enable(void)
+{
+	/* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF
+	 * Takes approx. 10.7s to timeout
+	 */
+	write_wdtcr(IOP_WDTCR_EN_ARM);
+	write_wdtcr(IOP_WDTCR_EN);
+}
+
+/* returns 0 if the timer was successfully disabled */
+static int wdt_disable(void)
+{
+	/* Stop Counting */
+	if (wdt_supports_disable()) {
+		write_wdtcr(IOP_WDTCR_DIS_ARM);
+		write_wdtcr(IOP_WDTCR_DIS);
+		clear_bit(WDT_ENABLED, &wdt_status);
+		printk(KERN_INFO "WATCHDOG: Disabled\n");
+		return 0;
+	} else
+		return 1;
+}
+
+static int iop_wdt_open(struct inode *inode, struct file *file)
+{
+	if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+		return -EBUSY;
+
+	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+	wdt_enable();
+
+	set_bit(WDT_ENABLED, &wdt_status);
+
+	return nonseekable_open(inode, file);
+}
+
+static ssize_t
+iop_wdt_write(struct file *file, const char *data, size_t len,
+		  loff_t *ppos)
+{
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+			for (i = 0; i != len; i++) {
+				char c;
+
+				if (get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+			}
+		}
+		wdt_enable();
+	}
+
+	return len;
+}
+
+static struct watchdog_info ident = {
+	.options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+	.identity = "iop watchdog",
+};
+
+static int
+iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		  unsigned long arg)
+{
+	int options;
+	int ret = -ENOTTY;
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		if (copy_to_user
+		    ((struct watchdog_info *)arg, &ident, sizeof ident))
+			ret = -EFAULT;
+		else
+			ret = 0;
+		break;
+
+	case WDIOC_GETSTATUS:
+		ret = put_user(0, (int *)arg);
+		break;
+
+	case WDIOC_GETBOOTSTATUS:
+		ret = put_user(boot_status, (int *)arg);
+		break;
+
+	case WDIOC_GETTIMEOUT:
+		ret = put_user(iop_watchdog_timeout(), (int *)arg);
+		break;
+
+	case WDIOC_KEEPALIVE:
+		wdt_enable();
+		ret = 0;
+		break;
+
+	case WDIOC_SETOPTIONS:
+		if (get_user(options, (int *)arg))
+			return -EFAULT;
+
+		if (options & WDIOS_DISABLECARD) {
+			if (!nowayout) {
+				if (wdt_disable() == 0) {
+					set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+					ret = 0;
+				} else
+					ret = -ENXIO;
+			} else
+				ret = 0;
+		}
+
+		if (options & WDIOS_ENABLECARD) {
+			wdt_enable();
+			ret = 0;
+		}
+		break;
+	}
+
+	return ret;
+}
+
+static int iop_wdt_release(struct inode *inode, struct file *file)
+{
+	int state = 1;
+	if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+		if (test_bit(WDT_ENABLED, &wdt_status))
+			state = wdt_disable();
+
+	/* if the timer is not disbaled reload and notify that we are still
+	 * going down
+	 */
+	if (state != 0) {
+		wdt_enable();
+		printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
+		       "reset in %lu seconds\n", iop_watchdog_timeout());
+	}
+
+	clear_bit(WDT_IN_USE, &wdt_status);
+	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+	return 0;
+}
+
+static const struct file_operations iop_wdt_fops = {
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.write = iop_wdt_write,
+	.ioctl = iop_wdt_ioctl,
+	.open = iop_wdt_open,
+	.release = iop_wdt_release,
+};
+
+static struct miscdevice iop_wdt_miscdev = {
+	.minor = WATCHDOG_MINOR,
+	.name = "watchdog",
+	.fops = &iop_wdt_fops,
+};
+
+static int __init iop_wdt_init(void)
+{
+	int ret;
+
+	ret = misc_register(&iop_wdt_miscdev);
+	if (ret == 0)
+		printk("iop watchdog timer: timeout %lu sec\n",
+		       iop_watchdog_timeout());
+
+	/* check if the reset was caused by the watchdog timer */
+	boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0;
+
+	/* Configure Watchdog Timeout to cause an Internal Bus (IB) Reset
+	 * NOTE: An IB Reset will Reset both cores in the IOP342
+	 */
+	write_wdtsr(IOP13XX_WDTCR_IB_RESET);
+
+	return ret;
+}
+
+static void __exit iop_wdt_exit(void)
+{
+	misc_deregister(&iop_wdt_miscdev);
+}
+
+module_init(iop_wdt_init);
+module_exit(iop_wdt_exit);
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_AUTHOR("Curt E Bruns <curt.e.bruns@intel.com>");
+MODULE_DESCRIPTION("iop watchdog timer driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c
index a0d2716..6d35bb1 100644
--- a/drivers/char/watchdog/machzwd.c
+++ b/drivers/char/watchdog/machzwd.c
@@ -321,6 +321,7 @@
 		break;
 
 	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
 		return put_user(0, p);
 
 	case WDIOC_KEEPALIVE:
diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c
index db2ccb8..1adf1d5 100644
--- a/drivers/char/watchdog/mixcomwd.c
+++ b/drivers/char/watchdog/mixcomwd.c
@@ -215,6 +215,11 @@
 				return -EFAULT;
 			}
 			break;
+		case WDIOC_GETBOOTSTATUS:
+			if (copy_to_user(p, &status, sizeof(int))) {
+				return -EFAULT;
+			}
+			break;
 		case WDIOC_GETSUPPORT:
 			if (copy_to_user(argp, &ident, sizeof(ident))) {
 				return -EFAULT;
diff --git a/drivers/char/watchdog/mpc5200_wdt.c b/drivers/char/watchdog/mpc5200_wdt.c
new file mode 100644
index 0000000..564143d
--- /dev/null
+++ b/drivers/char/watchdog/mpc5200_wdt.c
@@ -0,0 +1,286 @@
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <asm/of_platform.h>
+#include <asm/uaccess.h>
+#include <asm/mpc52xx.h>
+
+
+#define GPT_MODE_WDT		(1<<15)
+#define GPT_MODE_CE		(1<<12)
+#define GPT_MODE_MS_TIMER	(0x4)
+
+
+struct mpc5200_wdt {
+	unsigned count;	/* timer ticks before watchdog kicks in */
+	long ipb_freq;
+	struct miscdevice miscdev;
+	struct resource mem;
+	struct mpc52xx_gpt __iomem *regs;
+	spinlock_t io_lock;
+};
+
+/* is_active stores wether or not the /dev/watchdog device is opened */
+static unsigned long is_active;
+
+/* misc devices don't provide a way, to get back to 'dev' or 'miscdev' from
+ * file operations, which sucks. But there can be max 1 watchdog anyway, so...
+ */
+static struct mpc5200_wdt *wdt_global;
+
+
+/* helper to calculate timeout in timer counts */
+static void mpc5200_wdt_set_timeout(struct mpc5200_wdt *wdt, int timeout)
+{
+	/* use biggest prescaler of 64k */
+	wdt->count = (wdt->ipb_freq + 0xffff) / 0x10000 * timeout;
+
+	if (wdt->count > 0xffff)
+		wdt->count = 0xffff;
+}
+/* return timeout in seconds (calculated from timer count) */
+static int mpc5200_wdt_get_timeout(struct mpc5200_wdt *wdt)
+{
+	return wdt->count * 0x10000 / wdt->ipb_freq;
+}
+
+
+/* watchdog operations */
+static int mpc5200_wdt_start(struct mpc5200_wdt *wdt)
+{
+	spin_lock(&wdt->io_lock);
+	/* disable */
+	out_be32(&wdt->regs->mode, 0);
+	/* set timeout, with maximum prescaler */
+	out_be32(&wdt->regs->count, 0x0 | wdt->count);
+	/* enable watchdog */
+	out_be32(&wdt->regs->mode, GPT_MODE_CE | GPT_MODE_WDT | GPT_MODE_MS_TIMER);
+	spin_unlock(&wdt->io_lock);
+
+	return 0;
+}
+static int mpc5200_wdt_ping(struct mpc5200_wdt *wdt)
+{
+	spin_lock(&wdt->io_lock);
+	/* writing A5 to OCPW resets the watchdog */
+	out_be32(&wdt->regs->mode, 0xA5000000 | (0xffffff & in_be32(&wdt->regs->mode)));
+	spin_unlock(&wdt->io_lock);
+	return 0;
+}
+static int mpc5200_wdt_stop(struct mpc5200_wdt *wdt)
+{
+	spin_lock(&wdt->io_lock);
+	/* disable */
+	out_be32(&wdt->regs->mode, 0);
+	spin_unlock(&wdt->io_lock);
+	return 0;
+}
+
+
+/* file operations */
+static ssize_t mpc5200_wdt_write(struct file *file, const char *data,
+		size_t len, loff_t *ppos)
+{
+	struct mpc5200_wdt *wdt = file->private_data;
+	mpc5200_wdt_ping(wdt);
+	return 0;
+}
+static struct watchdog_info mpc5200_wdt_info = {
+	.options	= WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+	.identity	= "mpc5200 watchdog on GPT0",
+};
+static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	struct mpc5200_wdt *wdt = file->private_data;
+	int __user *data = (int __user *)arg;
+	int timeout;
+	int ret = 0;
+
+	switch (cmd) {
+	case WDIOC_GETSUPPORT:
+		ret = copy_to_user(data, &mpc5200_wdt_info,
+			sizeof(mpc5200_wdt_info));
+		if (ret)
+			ret = -EFAULT;
+		break;
+
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		ret = put_user(0, data);
+		break;
+
+	case WDIOC_KEEPALIVE:
+		mpc5200_wdt_ping(wdt);
+		break;
+
+	case WDIOC_SETTIMEOUT:
+		ret = get_user(timeout, data);
+		if (ret)
+			break;
+		mpc5200_wdt_set_timeout(wdt, timeout);
+		mpc5200_wdt_start(wdt);
+		/* fall through and return the timeout */
+
+	case WDIOC_GETTIMEOUT:
+		timeout = mpc5200_wdt_get_timeout(wdt);
+		ret = put_user(timeout, data);
+		break;
+
+	default:
+		ret = -ENOTTY;
+	}
+	return ret;
+}
+static int mpc5200_wdt_open(struct inode *inode, struct file *file)
+{
+	/* /dev/watchdog can only be opened once */
+	if (test_and_set_bit(0, &is_active))
+		return -EBUSY;
+
+	/* Set and activate the watchdog */
+	mpc5200_wdt_set_timeout(wdt_global, 30);
+	mpc5200_wdt_start(wdt_global);
+	file->private_data = wdt_global;
+	return nonseekable_open(inode, file);
+}
+static int mpc5200_wdt_release(struct inode *inode, struct file *file)
+{
+#if WATCHDOG_NOWAYOUT == 0
+	struct mpc5200_wdt *wdt = file->private_data;
+	mpc5200_wdt_stop(wdt);
+	wdt->count = 0;		/* == disabled */
+#endif
+	clear_bit(0, &is_active);
+	return 0;
+}
+
+static struct file_operations mpc5200_wdt_fops = {
+	.owner	= THIS_MODULE,
+	.write	= mpc5200_wdt_write,
+	.ioctl	= mpc5200_wdt_ioctl,
+	.open	= mpc5200_wdt_open,
+	.release = mpc5200_wdt_release,
+};
+
+/* module operations */
+static int mpc5200_wdt_probe(struct of_device *op, const struct of_device_id *match)
+{
+	struct mpc5200_wdt *wdt;
+	int err;
+	const void *has_wdt;
+	int size;
+
+	has_wdt = of_get_property(op->node, "has-wdt", NULL);
+	if (!has_wdt)
+		return -ENODEV;
+
+	wdt = kzalloc(sizeof(*wdt), GFP_KERNEL);
+	if (!wdt)
+		return -ENOMEM;
+
+	wdt->ipb_freq = mpc52xx_find_ipb_freq(op->node);
+
+	err = of_address_to_resource(op->node, 0, &wdt->mem);
+	if (err)
+		goto out_free;
+	size = wdt->mem.end - wdt->mem.start + 1;
+	if (!request_mem_region(wdt->mem.start, size, "mpc5200_wdt")) {
+		err = -ENODEV;
+		goto out_free;
+	}
+	wdt->regs = ioremap(wdt->mem.start, size);
+	if (!wdt->regs) {
+		err = -ENODEV;
+		goto out_release;
+	}
+
+	dev_set_drvdata(&op->dev, wdt);
+	spin_lock_init(&wdt->io_lock);
+
+	wdt->miscdev = (struct miscdevice) {
+		.minor	= WATCHDOG_MINOR,
+		.name	= "watchdog",
+		.fops	= &mpc5200_wdt_fops,
+		.parent = &op->dev,
+	};
+	wdt_global = wdt;
+	err = misc_register(&wdt->miscdev);
+	if (!err)
+		return 0;
+
+	iounmap(wdt->regs);
+ out_release:
+	release_mem_region(wdt->mem.start, size);
+ out_free:
+	kfree(wdt);
+	return err;
+}
+
+static int mpc5200_wdt_remove(struct of_device *op)
+{
+	struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
+
+	mpc5200_wdt_stop(wdt);
+	misc_deregister(&wdt->miscdev);
+	iounmap(wdt->regs);
+	release_mem_region(wdt->mem.start, wdt->mem.end - wdt->mem.start + 1);
+	kfree(wdt);
+
+	return 0;
+}
+static int mpc5200_wdt_suspend(struct of_device *op, pm_message_t state)
+{
+	struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
+	mpc5200_wdt_stop(wdt);
+	return 0;
+}
+static int mpc5200_wdt_resume(struct of_device *op)
+{
+	struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
+	if (wdt->count)
+		mpc5200_wdt_start(wdt);
+	return 0;
+}
+static int mpc5200_wdt_shutdown(struct of_device *op)
+{
+	struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
+	mpc5200_wdt_stop(wdt);
+	return 0;
+}
+
+static struct of_device_id mpc5200_wdt_match[] = {
+	{ .compatible = "mpc5200-gpt", },
+	{},
+};
+static struct of_platform_driver mpc5200_wdt_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "mpc5200-gpt-wdt",
+	.match_table	= mpc5200_wdt_match,
+	.probe		= mpc5200_wdt_probe,
+	.remove		= mpc5200_wdt_remove,
+	.suspend	= mpc5200_wdt_suspend,
+	.resume		= mpc5200_wdt_resume,
+	.shutdown	= mpc5200_wdt_shutdown,
+};
+
+
+static int __init mpc5200_wdt_init(void)
+{
+	return of_register_platform_driver(&mpc5200_wdt_driver);
+}
+
+static void __exit mpc5200_wdt_exit(void)
+{
+	of_unregister_platform_driver(&mpc5200_wdt_driver);
+}
+
+module_init(mpc5200_wdt_init);
+module_exit(mpc5200_wdt_exit);
+
+MODULE_AUTHOR("Domen Puncer <domen.puncer@telargo.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/mpc83xx_wdt.c b/drivers/char/watchdog/mpc83xx_wdt.c
index 18ca752..a0bf95f 100644
--- a/drivers/char/watchdog/mpc83xx_wdt.c
+++ b/drivers/char/watchdog/mpc83xx_wdt.c
@@ -119,6 +119,9 @@
 	switch (cmd) {
 	case WDIOC_GETSUPPORT:
 		return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
+	case WDIOC_GETSTATUS:
+	case WDIOC_GETBOOTSTATUS:
+		return put_user(0, p);
 	case WDIOC_KEEPALIVE:
 		mpc83xx_wdt_keepalive();
 		return 0;
diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c
index 8aaed10..85b5734 100644
--- a/drivers/char/watchdog/mpc8xx_wdt.c
+++ b/drivers/char/watchdog/mpc8xx_wdt.c
@@ -57,7 +57,7 @@
 	m8xx_wdt_reset();
 	mpc8xx_wdt_handler_disable();
 
-	return 0;
+	return nonseekable_open(inode, file);
 }
 
 static int mpc8xx_wdt_release(struct inode *inode, struct file *file)
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c
index e88947f..0d2b277 100644
--- a/drivers/char/watchdog/mpcore_wdt.c
+++ b/drivers/char/watchdog/mpcore_wdt.c
@@ -328,12 +328,11 @@
 		goto err_out;
 	}
 
-	wdt = kmalloc(sizeof(struct mpcore_wdt), GFP_KERNEL);
+	wdt = kzalloc(sizeof(struct mpcore_wdt), GFP_KERNEL);
 	if (!wdt) {
 		ret = -ENOMEM;
 		goto err_out;
 	}
-	memset(wdt, 0, sizeof(struct mpcore_wdt));
 
 	wdt->dev = &dev->dev;
 	wdt->irq = platform_get_irq(dev, 0);
diff --git a/drivers/char/watchdog/mtx-1_wdt.c b/drivers/char/watchdog/mtx-1_wdt.c
index 419ab44..dcfd401 100644
--- a/drivers/char/watchdog/mtx-1_wdt.c
+++ b/drivers/char/watchdog/mtx-1_wdt.c
@@ -143,6 +143,7 @@
 			mtx1_wdt_reset();
 			break;
 		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
 			if ( copy_to_user(argp, &value, sizeof(int)) )
 				return -EFAULT;
 			break;
diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c
index b887cdb..0365c31 100644
--- a/drivers/char/watchdog/mv64x60_wdt.c
+++ b/drivers/char/watchdog/mv64x60_wdt.c
@@ -23,83 +23,126 @@
 #include <linux/watchdog.h>
 #include <linux/platform_device.h>
 
-#include <asm/mv64x60.h>
+#include <linux/mv643xx.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-/* MV64x60 WDC (config) register access definitions */
-#define MV64x60_WDC_CTL1_MASK	(3 << 24)
-#define MV64x60_WDC_CTL1(val)	((val & 3) << 24)
-#define MV64x60_WDC_CTL2_MASK	(3 << 26)
-#define MV64x60_WDC_CTL2(val)	((val & 3) << 26)
+#define MV64x60_WDT_WDC_OFFSET	0
+
+/*
+ * The watchdog configuration register contains a pair of 2-bit fields,
+ *   1.  a reload field, bits 27-26, which triggers a reload of
+ *       the countdown register, and
+ *   2.  an enable field, bits 25-24, which toggles between
+ *       enabling and disabling the watchdog timer.
+ * Bit 31 is a read-only field which indicates whether the
+ * watchdog timer is currently enabled.
+ *
+ * The low 24 bits contain the timer reload value.
+ */
+#define MV64x60_WDC_ENABLE_SHIFT	24
+#define MV64x60_WDC_SERVICE_SHIFT	26
+#define MV64x60_WDC_ENABLED_SHIFT	31
+
+#define MV64x60_WDC_ENABLED_TRUE	1
+#define MV64x60_WDC_ENABLED_FALSE	0
 
 /* Flags bits */
 #define MV64x60_WDOG_FLAG_OPENED	0
-#define MV64x60_WDOG_FLAG_ENABLED	1
 
 static unsigned long wdt_flags;
 static int wdt_status;
-static void __iomem *mv64x60_regs;
+static void __iomem *mv64x60_wdt_regs;
 static int mv64x60_wdt_timeout;
+static int mv64x60_wdt_count;
+static unsigned int bus_clk;
+static char expect_close;
+static DEFINE_SPINLOCK(mv64x60_wdt_spinlock);
 
-static void mv64x60_wdt_reg_write(u32 val)
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static int mv64x60_wdt_toggle_wdc(int enabled_predicate, int field_shift)
 {
-	/* Allow write only to CTL1 / CTL2 fields, retaining values in
-	 * other fields.
-	 */
-	u32 data = readl(mv64x60_regs + MV64x60_WDT_WDC);
-	data &= ~(MV64x60_WDC_CTL1_MASK | MV64x60_WDC_CTL2_MASK);
-	data |= val;
-	writel(data, mv64x60_regs + MV64x60_WDT_WDC);
+	u32 data;
+	u32 enabled;
+	int ret = 0;
+
+	spin_lock(&mv64x60_wdt_spinlock);
+	data = readl(mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
+	enabled = (data >> MV64x60_WDC_ENABLED_SHIFT) & 1;
+
+	/* only toggle the requested field if enabled state matches predicate */
+	if ((enabled ^ enabled_predicate) == 0) {
+		/* We write a 1, then a 2 -- to the appropriate field */
+		data = (1 << field_shift) | mv64x60_wdt_count;
+		writel(data, mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
+
+		data = (2 << field_shift) | mv64x60_wdt_count;
+		writel(data, mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
+		ret = 1;
+	}
+	spin_unlock(&mv64x60_wdt_spinlock);
+
+	return ret;
 }
 
 static void mv64x60_wdt_service(void)
 {
-	/* Write 01 followed by 10 to CTL2 */
-	mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x01));
-	mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x02));
-}
-
-static void mv64x60_wdt_handler_disable(void)
-{
-	if (test_and_clear_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {
-		/* Write 01 followed by 10 to CTL1 */
-		mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));
-		mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
-		printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n");
-	}
+	mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE,
+			       MV64x60_WDC_SERVICE_SHIFT);
 }
 
 static void mv64x60_wdt_handler_enable(void)
 {
-	if (!test_and_set_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {
-		/* Write 01 followed by 10 to CTL1 */
-		mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));
-		mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
+	if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_FALSE,
+				   MV64x60_WDC_ENABLE_SHIFT)) {
+		mv64x60_wdt_service();
 		printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n");
 	}
 }
 
+static void mv64x60_wdt_handler_disable(void)
+{
+	if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE,
+				   MV64x60_WDC_ENABLE_SHIFT))
+		printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n");
+}
+
+static void mv64x60_wdt_set_timeout(unsigned int timeout)
+{
+	/* maximum bus cycle count is 0xFFFFFFFF */
+	if (timeout > 0xFFFFFFFF / bus_clk)
+		timeout = 0xFFFFFFFF / bus_clk;
+
+	mv64x60_wdt_count = timeout * bus_clk >> 8;
+	mv64x60_wdt_timeout = timeout;
+}
+
 static int mv64x60_wdt_open(struct inode *inode, struct file *file)
 {
 	if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags))
 		return -EBUSY;
 
-	mv64x60_wdt_service();
+	if (nowayout)
+		__module_get(THIS_MODULE);
+
 	mv64x60_wdt_handler_enable();
 
-	nonseekable_open(inode, file);
-
-	return 0;
+	return nonseekable_open(inode, file);
 }
 
 static int mv64x60_wdt_release(struct inode *inode, struct file *file)
 {
-	mv64x60_wdt_service();
-
-#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
-	mv64x60_wdt_handler_disable();
-#endif
+	if (expect_close == 42)
+		mv64x60_wdt_handler_disable();
+	else {
+		printk(KERN_CRIT
+		       "mv64x60_wdt: unexpected close, not stopping timer!\n");
+		mv64x60_wdt_service();
+	}
+	expect_close = 0;
 
 	clear_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags);
 
@@ -109,8 +152,22 @@
 static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data,
 				 size_t len, loff_t * ppos)
 {
-	if (len)
+	if (len) {
+		if (!nowayout) {
+			size_t i;
+
+			expect_close = 0;
+
+			for (i = 0; i != len; i++) {
+				char c;
+				if(get_user(c, data + i))
+					return -EFAULT;
+				if (c == 'V')
+					expect_close = 42;
+			}
+		}
 		mv64x60_wdt_service();
+	}
 
 	return len;
 }
@@ -119,9 +176,12 @@
 			     unsigned int cmd, unsigned long arg)
 {
 	int timeout;
+	int options;
 	void __user *argp = (void __user *)arg;
 	static struct watchdog_info info = {
-		.options = WDIOF_KEEPALIVEPING,
+		.options =	WDIOF_SETTIMEOUT	|
+				WDIOF_MAGICCLOSE	|
+				WDIOF_KEEPALIVEPING,
 		.firmware_version = 0,
 		.identity = "MV64x60 watchdog",
 	};
@@ -143,7 +203,15 @@
 		return -EOPNOTSUPP;
 
 	case WDIOC_SETOPTIONS:
-		return -EOPNOTSUPP;
+		if (get_user(options, (int __user *)argp))
+			return -EFAULT;
+
+		if (options & WDIOS_DISABLECARD)
+			mv64x60_wdt_handler_disable();
+
+		if (options & WDIOS_ENABLECARD)
+			mv64x60_wdt_handler_enable();
+		break;
 
 	case WDIOC_KEEPALIVE:
 		mv64x60_wdt_service();
@@ -151,11 +219,13 @@
 		break;
 
 	case WDIOC_SETTIMEOUT:
-		return -EOPNOTSUPP;
+		if (get_user(timeout, (int __user *)argp))
+			return -EFAULT;
+		mv64x60_wdt_set_timeout(timeout);
+		/* Fall through */
 
 	case WDIOC_GETTIMEOUT:
-		timeout = mv64x60_wdt_timeout * HZ;
-		if (put_user(timeout, (int __user *)argp))
+		if (put_user(mv64x60_wdt_timeout, (int __user *)argp))
 			return -EFAULT;
 		break;
 
@@ -184,18 +254,33 @@
 static int __devinit mv64x60_wdt_probe(struct platform_device *dev)
 {
 	struct mv64x60_wdt_pdata *pdata = dev->dev.platform_data;
-	int bus_clk = 133;
+	struct resource *r;
+	int timeout = 10;
 
-	mv64x60_wdt_timeout = 10;
+	bus_clk = 133;			/* in MHz */
 	if (pdata) {
-		mv64x60_wdt_timeout = pdata->timeout;
+		timeout = pdata->timeout;
 		bus_clk = pdata->bus_clk;
 	}
 
-	mv64x60_regs = mv64x60_get_bridge_vbase();
+	/* Since bus_clk is truncated MHz, actual frequency could be
+	 * up to 1MHz higher.  Round up, since it's better to time out
+	 * too late than too soon.
+	 */
+	bus_clk++;
+	bus_clk *= 1000000;		/* convert to Hz */
 
-	writel((mv64x60_wdt_timeout * (bus_clk * 1000000)) >> 8,
-	       mv64x60_regs + MV64x60_WDT_WDC);
+	r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	if (!r)
+		return -ENODEV;
+
+	mv64x60_wdt_regs = ioremap(r->start, r->end - r->start + 1);
+	if (mv64x60_wdt_regs == NULL)
+		return -ENOMEM;
+
+	mv64x60_wdt_set_timeout(timeout);
+
+	mv64x60_wdt_handler_disable();	/* in case timer was already running */
 
 	return misc_register(&mv64x60_wdt_miscdev);
 }
@@ -204,9 +289,10 @@
 {
 	misc_deregister(&mv64x60_wdt_miscdev);
 
-	mv64x60_wdt_service();
 	mv64x60_wdt_handler_disable();
 
+	iounmap(mv64x60_wdt_regs);
+
 	return 0;
 }
 
@@ -219,40 +305,16 @@
 	},
 };
 
-static struct platform_device *mv64x60_wdt_dev;
-
 static int __init mv64x60_wdt_init(void)
 {
-	int ret;
-
 	printk(KERN_INFO "MV64x60 watchdog driver\n");
 
-	mv64x60_wdt_dev = platform_device_alloc(MV64x60_WDT_NAME, -1);
-	if (!mv64x60_wdt_dev) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	ret = platform_device_add(mv64x60_wdt_dev);
-	if (ret) {
-		platform_device_put(mv64x60_wdt_dev);
-		goto out;
-	}
-
-	ret = platform_driver_register(&mv64x60_wdt_driver);
-	if (ret) {
-		platform_device_unregister(mv64x60_wdt_dev);
-		goto out;
-	}
-
- out:
-	return ret;
+	return platform_driver_register(&mv64x60_wdt_driver);
 }
 
 static void __exit mv64x60_wdt_exit(void)
 {
 	platform_driver_unregister(&mv64x60_wdt_driver);
-	platform_device_unregister(mv64x60_wdt_dev);
 }
 
 module_init(mv64x60_wdt_init);
diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c
index b36fa8d..719b066 100644
--- a/drivers/char/watchdog/omap_wdt.c
+++ b/drivers/char/watchdog/omap_wdt.c
@@ -142,7 +142,7 @@
 
 	omap_wdt_set_timeout();
 	omap_wdt_enable();
-	return 0;
+	return nonseekable_open(inode, file);
 }
 
 static int omap_wdt_release(struct inode *inode, struct file *file)
@@ -197,7 +197,7 @@
 
 	switch (cmd) {
 	default:
-		return -ENOIOCTLCMD;
+		return -ENOTTY;
 	case WDIOC_GETSUPPORT:
 		return copy_to_user((struct watchdog_info __user *)arg, &ident,
 				sizeof(ident));
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
index 1e7a671..0f3fd6c 100644
--- a/drivers/char/watchdog/pcwd_usb.c
+++ b/drivers/char/watchdog/pcwd_usb.c
@@ -626,12 +626,11 @@
 	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
 
 	/* allocate memory for our device and initialize it */
-	usb_pcwd = kmalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL);
+	usb_pcwd = kzalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL);
 	if (usb_pcwd == NULL) {
 		printk(KERN_ERR PFX "Out of memory\n");
 		goto error;
 	}
-	memset (usb_pcwd, 0x00, sizeof (*usb_pcwd));
 
 	usb_pcwd_device = usb_pcwd;
 
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
index 50430bc..5d1c15f 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -52,10 +52,10 @@
 
 #include <asm/arch/map.h>
 
-#undef S3C24XX_VA_WATCHDOG
-#define S3C24XX_VA_WATCHDOG (0)
+#undef S3C_VA_WATCHDOG
+#define S3C_VA_WATCHDOG (0)
 
-#include <asm/arch/regs-watchdog.h>
+#include <asm/plat-s3c/regs-watchdog.h>
 
 #define PFX "s3c2410-wdt: "
 
diff --git a/drivers/char/watchdog/sa1100_wdt.c b/drivers/char/watchdog/sa1100_wdt.c
index 33c1137..3475f47 100644
--- a/drivers/char/watchdog/sa1100_wdt.c
+++ b/drivers/char/watchdog/sa1100_wdt.c
@@ -45,7 +45,6 @@
  */
 static int sa1100dog_open(struct inode *inode, struct file *file)
 {
-	nonseekable_open(inode, file);
 	if (test_and_set_bit(1,&sa1100wdt_users))
 		return -EBUSY;
 
@@ -54,7 +53,7 @@
 	OSSR = OSSR_M3;
 	OWER = OWER_WME;
 	OIER |= OIER_E3;
-	return 0;
+	return nonseekable_open(inode, file);
 }
 
 /*
diff --git a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c
index b628203..e4f3cb6 100644
--- a/drivers/char/watchdog/sbc60xxwdt.c
+++ b/drivers/char/watchdog/sbc60xxwdt.c
@@ -191,8 +191,6 @@
 
 static int fop_open(struct inode * inode, struct file * file)
 {
-	nonseekable_open(inode, file);
-
 	/* Just in case we're already talking to someone... */
 	if(test_and_set_bit(0, &wdt_is_open))
 		return -EBUSY;
@@ -202,7 +200,7 @@
 
 	/* Good, fire up the show */
 	wdt_startup();
-	return 0;
+	return nonseekable_open(inode, file);
 }
 
 static int fop_close(struct inode * inode, struct file * file)
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c
index 2f7ba7a..9670d47 100644
--- a/drivers/char/watchdog/sc1200wdt.c
+++ b/drivers/char/watchdog/sc1200wdt.c
@@ -150,8 +150,6 @@
 
 static int sc1200wdt_open(struct inode *inode, struct file *file)
 {
-	nonseekable_open(inode, file);
-
 	/* allow one at a time */
 	if (down_trylock(&open_sem))
 		return -EBUSY;
@@ -162,7 +160,7 @@
 	sc1200wdt_start();
 	printk(KERN_INFO PFX "Watchdog enabled, timeout = %d min(s)", timeout);
 
-	return 0;
+	return nonseekable_open(inode, file);
 }
 
 
diff --git a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c
index 2676a43..e8594c6 100644
--- a/drivers/char/watchdog/sc520_wdt.c
+++ b/drivers/char/watchdog/sc520_wdt.c
@@ -248,8 +248,6 @@
 
 static int fop_open(struct inode * inode, struct file * file)
 {
-	nonseekable_open(inode, file);
-
 	/* Just in case we're already talking to someone... */
 	if(test_and_set_bit(0, &wdt_is_open))
 		return -EBUSY;
@@ -258,7 +256,7 @@
 
 	/* Good, fire up the show */
 	wdt_startup();
-	return 0;
+	return nonseekable_open(inode, file);
 }
 
 static int fop_close(struct inode * inode, struct file * file)
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c
index b46e7f4..df33b3b 100644
--- a/drivers/char/watchdog/w83627hf_wdt.c
+++ b/drivers/char/watchdog/w83627hf_wdt.c
@@ -4,7 +4,7 @@
  *	(c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
  *		added support for W83627THF.
  *
- *	(c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
+ *	(c) Copyright 2003,2007 Pádraig Brady <P@draigBrady.com>
  *
  *	Based on advantechwdt.c which is based on wdt.c.
  *	Original copyright messages:
@@ -42,7 +42,7 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
-#define WATCHDOG_NAME "w83627hf/thf WDT"
+#define WATCHDOG_NAME "w83627hf/thf/hg WDT"
 #define PFX WATCHDOG_NAME ": "
 #define WATCHDOG_TIMEOUT 60		/* 60 sec default timeout */
 
@@ -57,7 +57,7 @@
 
 static int timeout = WATCHDOG_TIMEOUT;	/* in seconds */
 module_param(timeout, int, 0);
-MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
 
 static int nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, int, 0);
@@ -78,9 +78,9 @@
 	outb_p(0x87, WDT_EFER); /* Enter extended function mode */
 	outb_p(0x87, WDT_EFER); /* Again according to manual */
 
-	outb(0x20, WDT_EFER); 	/* check chip version	*/
+	outb(0x20, WDT_EFER);	/* check chip version	*/
 	c = inb(WDT_EFDR);
-	if (c == 0x82) {	/* W83627THF 		*/
+	if (c == 0x82) {	/* W83627THF		*/
 		outb_p(0x2b, WDT_EFER); /* select GPIO3 */
 		c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */
 		outb_p(0x2b, WDT_EFER);
@@ -114,11 +114,17 @@
 		printk (KERN_INFO PFX "Watchdog already running. Resetting timeout to %d sec\n", timeout);
 		outb_p(timeout, WDT_EFDR);    /* Write back to CRF6 */
 	}
+
 	outb_p(0xF5, WDT_EFER); /* Select CRF5 */
 	t=inb_p(WDT_EFDR);      /* read CRF5 */
 	t&=~0x0C;               /* set second mode & disable keyboard turning off watchdog */
 	outb_p(t, WDT_EFDR);    /* Write back to CRF5 */
 
+	outb_p(0xF7, WDT_EFER); /* Select CRF7 */
+	t=inb_p(WDT_EFDR);      /* read CRF7 */
+	t&=~0xC0;               /* disable keyboard & mouse turning off watchdog */
+	outb_p(t, WDT_EFDR);    /* Write back to CRF7 */
+
 	w83627hf_unselect_wd_register();
 }
 
@@ -126,7 +132,7 @@
 wdt_ctrl(int timeout)
 {
 	spin_lock(&io_lock);
-	
+
 	w83627hf_select_wd_register();
 
 	outb_p(0xF6, WDT_EFER);    /* Select CRF6 */
@@ -154,7 +160,7 @@
 static int
 wdt_set_heartbeat(int t)
 {
-	if ((t < 1) || (t > 63))
+	if ((t < 1) || (t > 255))
 		return -EINVAL;
 
 	timeout = t;
@@ -324,11 +330,11 @@
 
 	spin_lock_init(&io_lock);
 
-	printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF Super I/O chip initialising.\n");
+	printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG Super I/O chip initialising.\n");
 
 	if (wdt_set_heartbeat(timeout)) {
 		wdt_set_heartbeat(WATCHDOG_TIMEOUT);
-		printk (KERN_INFO PFX "timeout value must be 1<=timeout<=63, using %d\n",
+		printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n",
 			WATCHDOG_TIMEOUT);
 	}
 
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index e783dbf..7b46faf 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -71,7 +71,7 @@
 	.rating		= 200,
 	.read		= acpi_pm_read,
 	.mask		= (cycle_t)ACPI_PM_MASK,
-	.mult		= 0, /*to be caluclated*/
+	.mult		= 0, /*to be calculated*/
 	.shift		= 22,
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index a7b9e9b..0e328d3 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -235,18 +235,6 @@
 }
 
 /*
- * Netlink socket input callback - dequeues the skbs and calls the
- * main netlink receiving function.
- */
-static void cn_input(struct sock *sk, int len)
-{
-	struct sk_buff *skb;
-
-	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL)
-		cn_rx_skb(skb);
-}
-
-/*
  * Notification routing.
  *
  * Gets id and checks if there are notification request for it's idx
@@ -442,11 +430,11 @@
 	struct cn_dev *dev = &cdev;
 	int err;
 
-	dev->input = cn_input;
+	dev->input = cn_rx_skb;
 	dev->id.idx = cn_idx;
 	dev->id.val = cn_val;
 
-	dev->nls = netlink_kernel_create(NETLINK_CONNECTOR,
+	dev->nls = netlink_kernel_create(&init_net, NETLINK_CONNECTOR,
 					 CN_NETLINK_USERS + 0xf,
 					 dev->input, NULL, THIS_MODULE);
 	if (!dev->nls)
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 993fa7b..721f86f 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -56,10 +56,6 @@
 
 	  If in doubt, say N.
 
-# Note that it is not currently possible to set the other governors (such as ondemand)
-# as the default, since if they fail to initialise, cpufreq will be
-# left in an undefined state.
-
 choice
 	prompt "Default CPUFreq governor"
 	default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110
@@ -85,6 +81,29 @@
 	  program shall be able to set the CPU dynamically without having
 	  to enable the userspace governor manually.
 
+config CPU_FREQ_DEFAULT_GOV_ONDEMAND
+	bool "ondemand"
+	select CPU_FREQ_GOV_ONDEMAND
+	select CPU_FREQ_GOV_PERFORMANCE
+	help
+	  Use the CPUFreq governor 'ondemand' as default. This allows
+	  you to get a full dynamic frequency capable system by simply
+	  loading your cpufreq low-level hardware driver.
+	  Be aware that not all cpufreq drivers support the ondemand
+	  governor. If unsure have a look at the help section of the
+	  driver. Fallback governor will be the performance governor.
+
+config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
+	bool "conservative"
+	select CPU_FREQ_GOV_CONSERVATIVE
+	select CPU_FREQ_GOV_PERFORMANCE
+	help
+	  Use the CPUFreq governor 'conservative' as default. This allows
+	  you to get a full dynamic frequency capable system by simply
+	  loading your cpufreq low-level hardware driver.
+	  Be aware that not all cpufreq drivers support the conservative
+	  governor. If unsure have a look at the help section of the
+	  driver. Fallback governor will be the performance governor.
 endchoice
 
 config CPU_FREQ_GOV_PERFORMANCE
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 2f6a73c..5e626b1 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -763,6 +763,8 @@
 	init_completion(&policy->kobj_unregister);
 	INIT_WORK(&policy->update, handle_update);
 
+	/* Set governor before ->init, so that driver could check it */
+	policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
 	/* call driver. From then on the cpufreq must be able
 	 * to accept all calls to ->verify and ->setpolicy for this CPU
 	 */
@@ -828,7 +830,7 @@
 	/* prepare interface data */
 	policy->kobj.parent = &sys_dev->kobj;
 	policy->kobj.ktype = &ktype_cpufreq;
-	strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN);
+	kobject_set_name(&policy->kobj, "cpufreq");
 
 	ret = kobject_register(&policy->kobj);
 	if (ret) {
@@ -1109,12 +1111,7 @@
 	unsigned int ret_freq = 0;
 
 	if (policy) {
-		if (unlikely(lock_policy_rwsem_read(cpu)))
-			return ret_freq;
-
 		ret_freq = policy->cur;
-
-		unlock_policy_rwsem_read(cpu);
 		cpufreq_cpu_put(policy);
 	}
 
@@ -1483,6 +1480,31 @@
 {
 	int ret;
 
+	/* Only must be defined when default governor is known to have latency
+	   restrictions, like e.g. conservative or ondemand.
+	   That this is the case is already ensured in Kconfig
+	*/
+#ifdef CONFIG_CPU_FREQ_GOV_PERFORMANCE
+	struct cpufreq_governor *gov = &cpufreq_gov_performance;
+#else
+	struct cpufreq_governor *gov = NULL;
+#endif
+
+	if (policy->governor->max_transition_latency &&
+	    policy->cpuinfo.transition_latency >
+	    policy->governor->max_transition_latency) {
+		if (!gov)
+			return -EINVAL;
+		else {
+			printk(KERN_WARNING "%s governor failed, too long"
+			       " transition latency of HW, fallback"
+			       " to %s governor\n",
+			       policy->governor->name,
+			       gov->name);
+			policy->governor = gov;
+		}
+	}
+
 	if (!try_module_get(policy->governor->owner))
 		return -EINVAL;
 
@@ -1703,7 +1725,7 @@
 }
 EXPORT_SYMBOL(cpufreq_update_policy);
 
-static int cpufreq_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit cpufreq_cpu_callback(struct notifier_block *nfb,
 					unsigned long action, void *hcpu)
 {
 	unsigned int cpu = (unsigned long)hcpu;
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index 26f440c..4bd33ce 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -58,7 +58,7 @@
 #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER	(1000)
 #define DEF_SAMPLING_DOWN_FACTOR		(1)
 #define MAX_SAMPLING_DOWN_FACTOR		(10)
-#define TRANSITION_LATENCY_LIMIT		(10 * 1000)
+#define TRANSITION_LATENCY_LIMIT		(10 * 1000 * 1000)
 
 static void do_dbs_timer(struct work_struct *work);
 
@@ -466,9 +466,6 @@
 		    (!policy->cur))
 			return -EINVAL;
 
-		if (policy->cpuinfo.transition_latency >
-				(TRANSITION_LATENCY_LIMIT * 1000))
-			return -EINVAL;
 		if (this_dbs_info->enable) /* Already enabled */
 			break;
 		 
@@ -551,15 +548,17 @@
 	return 0;
 }
 
-static struct cpufreq_governor cpufreq_gov_dbs = {
-	.name		= "conservative",
-	.governor	= cpufreq_governor_dbs,
-	.owner		= THIS_MODULE,
+struct cpufreq_governor cpufreq_gov_conservative = {
+	.name			= "conservative",
+	.governor		= cpufreq_governor_dbs,
+	.max_transition_latency	= TRANSITION_LATENCY_LIMIT,
+	.owner			= THIS_MODULE,
 };
+EXPORT_SYMBOL(cpufreq_gov_conservative);
 
 static int __init cpufreq_gov_dbs_init(void)
 {
-	return cpufreq_register_governor(&cpufreq_gov_dbs);
+	return cpufreq_register_governor(&cpufreq_gov_conservative);
 }
 
 static void __exit cpufreq_gov_dbs_exit(void)
@@ -567,7 +566,7 @@
 	/* Make sure that the scheduled work is indeed not running */
 	flush_scheduled_work();
 
-	cpufreq_unregister_governor(&cpufreq_gov_dbs);
+	cpufreq_unregister_governor(&cpufreq_gov_conservative);
 }
 
 
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index e794527..369f445 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -47,7 +47,7 @@
 			(def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
 #define MAX_SAMPLING_RATE			(500 * def_sampling_rate)
 #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER	(1000)
-#define TRANSITION_LATENCY_LIMIT		(10 * 1000)
+#define TRANSITION_LATENCY_LIMIT		(10 * 1000 * 1000)
 
 static void do_dbs_timer(struct work_struct *work);
 
@@ -508,12 +508,6 @@
 		if ((!cpu_online(cpu)) || (!policy->cur))
 			return -EINVAL;
 
-		if (policy->cpuinfo.transition_latency >
-				(TRANSITION_LATENCY_LIMIT * 1000)) {
-			printk(KERN_WARNING "ondemand governor failed to load "
-			       "due to too long transition latency\n");
-			return -EINVAL;
-		}
 		if (this_dbs_info->enable) /* Already enabled */
 			break;
 
@@ -585,11 +579,13 @@
 	return 0;
 }
 
-static struct cpufreq_governor cpufreq_gov_dbs = {
-	.name = "ondemand",
-	.governor = cpufreq_governor_dbs,
-	.owner = THIS_MODULE,
+struct cpufreq_governor cpufreq_gov_ondemand = {
+	.name			= "ondemand",
+	.governor		= cpufreq_governor_dbs,
+	.max_transition_latency = TRANSITION_LATENCY_LIMIT,
+	.owner			= THIS_MODULE,
 };
+EXPORT_SYMBOL(cpufreq_gov_ondemand);
 
 static int __init cpufreq_gov_dbs_init(void)
 {
@@ -598,12 +594,12 @@
 		printk(KERN_ERR "Creation of kondemand failed\n");
 		return -EFAULT;
 	}
-	return cpufreq_register_governor(&cpufreq_gov_dbs);
+	return cpufreq_register_governor(&cpufreq_gov_ondemand);
 }
 
 static void __exit cpufreq_gov_dbs_exit(void)
 {
-	cpufreq_unregister_governor(&cpufreq_gov_dbs);
+	cpufreq_unregister_governor(&cpufreq_gov_ondemand);
 	destroy_workqueue(kondemand_wq);
 }
 
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 917b9ba..8a45d0f 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -164,8 +164,7 @@
 	return -1;
 }
 
-static void
-cpufreq_stats_free_table (unsigned int cpu)
+static void __cpuexit cpufreq_stats_free_table(unsigned int cpu)
 {
 	struct cpufreq_stats *stat = cpufreq_stats_table[cpu];
 	struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
@@ -305,8 +304,9 @@
 	return 0;
 }
 
-static int cpufreq_stat_cpu_callback(struct notifier_block *nfb,
-					unsigned long action, void *hcpu)
+static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
+					       unsigned long action,
+					       void *hcpu)
 {
 	unsigned int cpu = (unsigned long)hcpu;
 
@@ -323,7 +323,7 @@
 	return NOTIFY_OK;
 }
 
-static struct notifier_block cpufreq_stat_cpu_notifier =
+static struct notifier_block cpufreq_stat_cpu_notifier __cpuinitdata =
 {
 	.notifier_call = cpufreq_stat_cpu_callback,
 };
@@ -356,8 +356,7 @@
 
 	register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
 	for_each_online_cpu(cpu) {
-		cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
-				CPU_ONLINE, (void *)(long)cpu);
+		cpufreq_update_policy(cpu);
 	}
 	return 0;
 }
@@ -372,13 +371,12 @@
 			CPUFREQ_TRANSITION_NOTIFIER);
 	unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
 	for_each_online_cpu(cpu) {
-		cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier,
-						CPU_DEAD, (void *)(long)cpu);
+		cpufreq_stats_free_table(cpu);
 	}
 }
 
 MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>");
-MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats"
+MODULE_DESCRIPTION ("'cpufreq_stats' - A driver to export cpufreq stats "
 				"through sysfs filesystem");
 MODULE_LICENSE ("GPL");
 
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 84ebfcc..5fd6688 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -2,6 +2,11 @@
 menuconfig CRYPTO_HW
 	bool "Hardware crypto devices"
 	default y
+	---help---
+	  Say Y here to get to see options for hardware crypto devices and
+	  processors. This option alone does not add any kernel code.
+
+	  If you say N, all options in this submenu will be skipped and disabled.
 
 if CRYPTO_HW
 
@@ -9,7 +14,6 @@
 	tristate "Support for VIA PadLock ACE"
 	depends on X86_32
 	select CRYPTO_ALGAPI
-	default m
 	help
 	  Some VIA processors come with an integrated crypto engine
 	  (so called VIA PadLock ACE, Advanced Cryptography Engine)
@@ -23,7 +27,6 @@
 	tristate "PadLock driver for AES algorithm"
 	depends on CRYPTO_DEV_PADLOCK
 	select CRYPTO_BLKCIPHER
-	default m
 	help
 	  Use VIA PadLock for AES algorithm.
 
@@ -37,7 +40,6 @@
 	depends on CRYPTO_DEV_PADLOCK
 	select CRYPTO_SHA1
 	select CRYPTO_SHA256
-	default m
 	help
 	  Use VIA PadLock for SHA1/SHA256 algorithms.
 
@@ -53,7 +55,6 @@
 	depends on X86_32 && PCI
 	select CRYPTO_ALGAPI
 	select CRYPTO_BLKCIPHER
-	default m
 	help
 	  Say 'Y' here to use the AMD Geode LX processor on-board AES
 	  engine for the CryptoAPI AES algorithm.
@@ -65,7 +66,6 @@
 	tristate "Support for PCI-attached cryptographic adapters"
 	depends on S390
 	select ZCRYPT_MONOLITHIC if ZCRYPT="y"
-	default "m"
 	help
 	  Select this option if you want to use a PCI-attached cryptographic
 	  adapter like:
diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c
index 6a86958..f9a34ab 100644
--- a/drivers/crypto/geode-aes.c
+++ b/drivers/crypto/geode-aes.c
@@ -473,6 +473,7 @@
 MODULE_AUTHOR("Advanced Micro Devices, Inc.");
 MODULE_DESCRIPTION("Geode LX Hardware AES driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("aes");
 
 module_init(geode_aes_init);
 module_exit(geode_aes_exit);
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index d4501dc..abbcff0 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 2004  Michal Ludvig <michal@logix.cz>
  *
- * Key expansion routine taken from crypto/aes.c
+ * Key expansion routine taken from crypto/aes_generic.c
  *
  * 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
@@ -660,4 +660,4 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Michal Ludvig");
 
-MODULE_ALIAS("aes-padlock");
+MODULE_ALIAS("aes");
diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
index a781fd2..4e8de16 100644
--- a/drivers/crypto/padlock-sha.c
+++ b/drivers/crypto/padlock-sha.c
@@ -13,6 +13,7 @@
  */
 
 #include <crypto/algapi.h>
+#include <crypto/sha.h>
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/init.h>
@@ -24,12 +25,7 @@
 #include "padlock.h"
 
 #define SHA1_DEFAULT_FALLBACK	"sha1-generic"
-#define SHA1_DIGEST_SIZE        20
-#define SHA1_HMAC_BLOCK_SIZE    64
-
 #define SHA256_DEFAULT_FALLBACK "sha256-generic"
-#define SHA256_DIGEST_SIZE      32
-#define SHA256_HMAC_BLOCK_SIZE  64
 
 struct padlock_sha_ctx {
 	char		*data;
@@ -107,11 +103,11 @@
 	char buf[128+16];
 	char *result = NEAREST_ALIGNED(buf);
 
-	((uint32_t *)result)[0] = 0x67452301;
-	((uint32_t *)result)[1] = 0xEFCDAB89;
-	((uint32_t *)result)[2] = 0x98BADCFE;
-	((uint32_t *)result)[3] = 0x10325476;
-	((uint32_t *)result)[4] = 0xC3D2E1F0;
+	((uint32_t *)result)[0] = SHA1_H0;
+	((uint32_t *)result)[1] = SHA1_H1;
+	((uint32_t *)result)[2] = SHA1_H2;
+	((uint32_t *)result)[3] = SHA1_H3;
+	((uint32_t *)result)[4] = SHA1_H4;
  
 	asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" /* rep xsha1 */
 		      : "+S"(in), "+D"(result)
@@ -128,14 +124,14 @@
 	char buf[128+16];
 	char *result = NEAREST_ALIGNED(buf);
 
-	((uint32_t *)result)[0] = 0x6A09E667;
-	((uint32_t *)result)[1] = 0xBB67AE85;
-	((uint32_t *)result)[2] = 0x3C6EF372;
-	((uint32_t *)result)[3] = 0xA54FF53A;
-	((uint32_t *)result)[4] = 0x510E527F;
-	((uint32_t *)result)[5] = 0x9B05688C;
-	((uint32_t *)result)[6] = 0x1F83D9AB;
-	((uint32_t *)result)[7] = 0x5BE0CD19;
+	((uint32_t *)result)[0] = SHA256_H0;
+	((uint32_t *)result)[1] = SHA256_H1;
+	((uint32_t *)result)[2] = SHA256_H2;
+	((uint32_t *)result)[3] = SHA256_H3;
+	((uint32_t *)result)[4] = SHA256_H4;
+	((uint32_t *)result)[5] = SHA256_H5;
+	((uint32_t *)result)[6] = SHA256_H6;
+	((uint32_t *)result)[7] = SHA256_H7;
 
 	asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" /* rep xsha256 */
 		      : "+S"(in), "+D"(result)
@@ -215,7 +211,7 @@
 	.cra_priority		=	PADLOCK_CRA_PRIORITY,
 	.cra_flags		=	CRYPTO_ALG_TYPE_DIGEST |
 					CRYPTO_ALG_NEED_FALLBACK,
-	.cra_blocksize		=	SHA1_HMAC_BLOCK_SIZE,
+	.cra_blocksize		=	SHA1_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct padlock_sha_ctx),
 	.cra_module		=	THIS_MODULE,
 	.cra_list		=	LIST_HEAD_INIT(sha1_alg.cra_list),
@@ -237,7 +233,7 @@
 	.cra_priority		=	PADLOCK_CRA_PRIORITY,
 	.cra_flags		=	CRYPTO_ALG_TYPE_DIGEST |
 					CRYPTO_ALG_NEED_FALLBACK,
-	.cra_blocksize		=	SHA256_HMAC_BLOCK_SIZE,
+	.cra_blocksize		=	SHA256_BLOCK_SIZE,
 	.cra_ctxsize		=	sizeof(struct padlock_sha_ctx),
 	.cra_module		=	THIS_MODULE,
 	.cra_list		=	LIST_HEAD_INIT(sha256_alg.cra_list),
@@ -253,19 +249,6 @@
 	}
 };
 
-static void __init padlock_sha_check_fallbacks(void)
-{
-	if (!crypto_has_hash("sha1", 0, CRYPTO_ALG_ASYNC |
-					CRYPTO_ALG_NEED_FALLBACK))
-		printk(KERN_WARNING PFX
-		       "Couldn't load fallback module for sha1.\n");
-
-	if (!crypto_has_hash("sha256", 0, CRYPTO_ALG_ASYNC |
-					CRYPTO_ALG_NEED_FALLBACK))
-		printk(KERN_WARNING PFX
-		       "Couldn't load fallback module for sha256.\n");
-}
-
 static int __init padlock_init(void)
 {
 	int rc = -ENODEV;
@@ -280,8 +263,6 @@
 		return -ENODEV;
 	}
 
-	padlock_sha_check_fallbacks();
-
 	rc = crypto_register_alg(&sha1_alg);
 	if (rc)
 		goto out;
@@ -314,5 +295,7 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Michal Ludvig");
 
+MODULE_ALIAS("sha1");
+MODULE_ALIAS("sha256");
 MODULE_ALIAS("sha1-padlock");
 MODULE_ALIAS("sha256-padlock");
diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioatdma.c
index 5fbe56b..41b18c5 100644
--- a/drivers/dma/ioatdma.c
+++ b/drivers/dma/ioatdma.c
@@ -191,17 +191,12 @@
 	int i;
 	LIST_HEAD(tmp_list);
 
-	/*
-	 * In-use bit automatically set by reading chanctrl
-	 * If 0, we got it, if 1, someone else did
-	 */
-	chanctrl = readw(ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET);
-	if (chanctrl & IOAT_CHANCTRL_CHANNEL_IN_USE)
-		return -EBUSY;
+	/* have we already been set up? */
+	if (!list_empty(&ioat_chan->free_desc))
+		return INITIAL_IOAT_DESC_COUNT;
 
         /* Setup register to interrupt and write completion status on error */
-	chanctrl = IOAT_CHANCTRL_CHANNEL_IN_USE |
-		IOAT_CHANCTRL_ERR_INT_EN |
+	chanctrl = IOAT_CHANCTRL_ERR_INT_EN |
 		IOAT_CHANCTRL_ANY_ERR_ABORT_EN |
 		IOAT_CHANCTRL_ERR_COMPLETION_EN;
         writew(chanctrl, ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET);
@@ -282,11 +277,6 @@
 			in_use_descs - 1);
 
 	ioat_chan->last_completion = ioat_chan->completion_addr = 0;
-
-	/* Tell hw the chan is free */
-	chanctrl = readw(ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET);
-	chanctrl &= ~IOAT_CHANCTRL_CHANNEL_IN_USE;
-	writew(chanctrl, ioat_chan->reg_base + IOAT_CHANCTRL_OFFSET);
 }
 
 static struct dma_async_tx_descriptor *
@@ -347,8 +337,7 @@
 	new->async_tx.ack = 0; /* client is in control of this ack */
 	new->async_tx.cookie = -EBUSY;
 
-	pci_unmap_len_set(new, src_len, orig_len);
-	pci_unmap_len_set(new, dst_len, orig_len);
+	pci_unmap_len_set(new, len, orig_len);
 	spin_unlock_bh(&ioat_chan->desc_lock);
 
 	return new ? &new->async_tx : NULL;
@@ -423,11 +412,11 @@
 			*/
 			pci_unmap_page(chan->device->pdev,
 					pci_unmap_addr(desc, dst),
-					pci_unmap_len(desc, dst_len),
+					pci_unmap_len(desc, len),
 					PCI_DMA_FROMDEVICE);
 			pci_unmap_page(chan->device->pdev,
 					pci_unmap_addr(desc, src),
-					pci_unmap_len(desc, src_len),
+					pci_unmap_len(desc, len),
 					PCI_DMA_TODEVICE);
 		}
 
diff --git a/drivers/dma/ioatdma.h b/drivers/dma/ioatdma.h
index d372647..bf4dad7 100644
--- a/drivers/dma/ioatdma.h
+++ b/drivers/dma/ioatdma.h
@@ -111,10 +111,9 @@
 	struct ioat_dma_descriptor *hw;
 	struct list_head node;
 	int tx_cnt;
+	DECLARE_PCI_UNMAP_LEN(len)
 	DECLARE_PCI_UNMAP_ADDR(src)
-	DECLARE_PCI_UNMAP_LEN(src_len)
 	DECLARE_PCI_UNMAP_ADDR(dst)
-	DECLARE_PCI_UNMAP_LEN(dst_len)
 	struct dma_async_tx_descriptor async_tx;
 };
 
diff --git a/drivers/dma/iovlock.c b/drivers/dma/iovlock.c
index d637555..e763d72 100644
--- a/drivers/dma/iovlock.c
+++ b/drivers/dma/iovlock.c
@@ -143,29 +143,6 @@
 	kfree(pinned_list);
 }
 
-static dma_cookie_t dma_memcpy_to_kernel_iovec(struct dma_chan *chan, struct
-	iovec *iov, unsigned char *kdata, size_t len)
-{
-	dma_cookie_t dma_cookie = 0;
-
-	while (len > 0) {
-		if (iov->iov_len) {
-			int copy = min_t(unsigned int, iov->iov_len, len);
-			dma_cookie = dma_async_memcpy_buf_to_buf(
-					chan,
-					iov->iov_base,
-					kdata,
-					copy);
-			kdata += copy;
-			len -= copy;
-			iov->iov_len -= copy;
-			iov->iov_base += copy;
-		}
-		iov++;
-	}
-
-	return dma_cookie;
-}
 
 /*
  * We have already pinned down the pages we will be using in the iovecs.
@@ -187,10 +164,6 @@
 	if (!chan)
 		return memcpy_toiovec(iov, kdata, len);
 
-	/* -> kernel copies (e.g. smbfs) */
-	if (!pinned_list)
-		return dma_memcpy_to_kernel_iovec(chan, iov, kdata, len);
-
 	iovec_idx = 0;
 	while (iovec_idx < pinned_list->nr_iovecs) {
 		struct dma_page_list *page_list;
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index debf1d8..98b6b4f 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -3,18 +3,18 @@
 #	Copyright (c) 2003 Linux Networx
 #	Licensed and distributed under the GPL
 #
-# $Id: Kconfig,v 1.4.2.7 2005/07/08 22:05:38 dsp_llnl Exp $
-#
 
 menuconfig EDAC
-	tristate "EDAC - error detection and reporting (EXPERIMENTAL)"
+	bool "EDAC - error detection and reporting (EXPERIMENTAL)"
 	depends on HAS_IOMEM
-	depends on X86 && EXPERIMENTAL
+	depends on EXPERIMENTAL
+	depends on X86 || PPC
 	help
 	  EDAC is designed to report errors in the core system.
 	  These are low-level errors that are reported in the CPU or
-	  supporting chipset: memory errors, cache errors, PCI errors,
-	  thermal throttling, etc..  If unsure, select 'Y'.
+	  supporting chipset or other subsystems:
+	  memory errors, cache errors, PCI errors, thermal throttling, etc..
+	  If unsure, select 'Y'.
 
 	  If this code is reporting problems on your system, please
 	  see the EDAC project web pages for more information at:
@@ -73,6 +73,14 @@
 	  Support for error detection and correction on the Intel
 	  E7520, E7525, E7320 server chipsets.
 
+config EDAC_I82443BXGX
+	tristate "Intel 82443BX/GX (440BX/GX)"
+	depends on EDAC_MM_EDAC && PCI && X86_32
+	depends on BROKEN
+	help
+	  Support for error detection and correction on the Intel
+	  82443BX/GX memory controllers (440BX/GX chipsets).
+
 config EDAC_I82875P
 	tristate "Intel 82875p (D82875P, E7210)"
 	depends on EDAC_MM_EDAC && PCI && X86_32
@@ -80,6 +88,20 @@
 	  Support for error detection and correction on the Intel
 	  DP82785P and E7210 server chipsets.
 
+config EDAC_I82975X
+	tristate "Intel 82975x (D82975x)"
+	depends on EDAC_MM_EDAC && PCI && X86
+	help
+	  Support for error detection and correction on the Intel
+	  DP82975x server chipsets.
+
+config EDAC_I3000
+	tristate "Intel 3000/3010"
+	depends on EDAC_MM_EDAC && PCI && X86_32
+	help
+	  Support for error detection and correction on the Intel
+	  3000 and 3010 server chipsets.
+
 config EDAC_I82860
 	tristate "Intel 82860"
 	depends on EDAC_MM_EDAC && PCI && X86_32
@@ -94,15 +116,20 @@
 	  Support for error detection and correction on the Radisys
 	  82600 embedded chipset.
 
-choice
-	prompt "Error detecting method"
-	default EDAC_POLL
-
-config EDAC_POLL
-	bool "Poll for errors"
+config EDAC_I5000
+	tristate "Intel Greencreek/Blackford chipset"
+	depends on EDAC_MM_EDAC && X86 && PCI
 	help
-	  Poll the chipset periodically to detect errors.
+	  Support for error detection and correction the Intel
+	  Greekcreek/Blackford chipsets.
 
-endchoice
+config EDAC_PASEMI
+	tristate "PA Semi PWRficient"
+	depends on EDAC_MM_EDAC && PCI
+	depends on PPC_PASEMI
+	help
+	  Support for error detection and correction on PA Semi
+	  PWRficient.
+
 
 endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 93137fd..02c09f0 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -5,14 +5,27 @@
 # This file may be distributed under the terms of the
 # GNU General Public License.
 #
-# $Id: Makefile,v 1.4.2.3 2005/07/08 22:05:38 dsp_llnl Exp $
 
 
-obj-$(CONFIG_EDAC_MM_EDAC)		+= edac_mc.o
+obj-$(CONFIG_EDAC)			:= edac_stub.o
+obj-$(CONFIG_EDAC_MM_EDAC)		+= edac_core.o
+
+edac_core-objs	:= edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
+edac_core-objs	+= edac_module.o edac_device_sysfs.o
+
+ifdef CONFIG_PCI
+edac_core-objs	+= edac_pci.o edac_pci_sysfs.o
+endif
+
 obj-$(CONFIG_EDAC_AMD76X)		+= amd76x_edac.o
+obj-$(CONFIG_EDAC_I5000)		+= i5000_edac.o
 obj-$(CONFIG_EDAC_E7XXX)		+= e7xxx_edac.o
 obj-$(CONFIG_EDAC_E752X)		+= e752x_edac.o
+obj-$(CONFIG_EDAC_I82443BXGX)		+= i82443bxgx_edac.o
 obj-$(CONFIG_EDAC_I82875P)		+= i82875p_edac.o
+obj-$(CONFIG_EDAC_I82975X)		+= i82975x_edac.o
+obj-$(CONFIG_EDAC_I3000)		+= i3000_edac.o
 obj-$(CONFIG_EDAC_I82860)		+= i82860_edac.o
 obj-$(CONFIG_EDAC_R82600)		+= r82600_edac.o
+obj-$(CONFIG_EDAC_PASEMI)		+= pasemi_edac.o
 
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c
index f79f6b5..f220754 100644
--- a/drivers/edac/amd76x_edac.c
+++ b/drivers/edac/amd76x_edac.c
@@ -17,9 +17,9 @@
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/slab.h>
-#include "edac_mc.h"
+#include "edac_core.h"
 
-#define AMD76X_REVISION	" Ver: 2.0.1 "  __DATE__
+#define AMD76X_REVISION	" Ver: 2.0.2 "  __DATE__
 #define EDAC_MOD_STR	"amd76x_edac"
 
 #define amd76x_printk(level, fmt, arg...) \
@@ -86,13 +86,13 @@
 
 static const struct amd76x_dev_info amd76x_devs[] = {
 	[AMD761] = {
-		.ctl_name = "AMD761"
-	},
+		.ctl_name = "AMD761"},
 	[AMD762] = {
-		.ctl_name = "AMD762"
-	},
+		.ctl_name = "AMD762"},
 };
 
+static struct edac_pci_ctl_info *amd76x_pci;
+
 /**
  *	amd76x_get_error_info	-	fetch error information
  *	@mci: Memory controller
@@ -102,21 +102,21 @@
  *	on the chip so that further errors will be reported
  */
 static void amd76x_get_error_info(struct mem_ctl_info *mci,
-		struct amd76x_error_info *info)
+				struct amd76x_error_info *info)
 {
 	struct pci_dev *pdev;
 
 	pdev = to_pci_dev(mci->dev);
 	pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS,
-				&info->ecc_mode_status);
+			&info->ecc_mode_status);
 
 	if (info->ecc_mode_status & BIT(8))
 		pci_write_bits32(pdev, AMD76X_ECC_MODE_STATUS,
-				(u32) BIT(8), (u32) BIT(8));
+				 (u32) BIT(8), (u32) BIT(8));
 
 	if (info->ecc_mode_status & BIT(9))
 		pci_write_bits32(pdev, AMD76X_ECC_MODE_STATUS,
-				(u32) BIT(9), (u32) BIT(9));
+				 (u32) BIT(9), (u32) BIT(9));
 }
 
 /**
@@ -130,7 +130,8 @@
  *	then attempt to handle and clean up after the error
  */
 static int amd76x_process_error_info(struct mem_ctl_info *mci,
-		struct amd76x_error_info *info, int handle_errors)
+				struct amd76x_error_info *info,
+				int handle_errors)
 {
 	int error_found;
 	u32 row;
@@ -138,7 +139,7 @@
 	error_found = 0;
 
 	/*
-	 *	Check for an uncorrectable error
+	 *      Check for an uncorrectable error
 	 */
 	if (info->ecc_mode_status & BIT(8)) {
 		error_found = 1;
@@ -146,12 +147,12 @@
 		if (handle_errors) {
 			row = (info->ecc_mode_status >> 4) & 0xf;
 			edac_mc_handle_ue(mci, mci->csrows[row].first_page, 0,
-				row, mci->ctl_name);
+					row, mci->ctl_name);
 		}
 	}
 
 	/*
-	 *	Check for a correctable error
+	 *      Check for a correctable error
 	 */
 	if (info->ecc_mode_status & BIT(9)) {
 		error_found = 1;
@@ -159,7 +160,7 @@
 		if (handle_errors) {
 			row = info->ecc_mode_status & 0xf;
 			edac_mc_handle_ce(mci, mci->csrows[row].first_page, 0,
-				0, row, 0, mci->ctl_name);
+					0, row, 0, mci->ctl_name);
 		}
 	}
 
@@ -182,7 +183,7 @@
 }
 
 static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
-		enum edac_type edac_mode)
+			enum edac_type edac_mode)
 {
 	struct csrow_info *csrow;
 	u32 mba, mba_base, mba_mask, dms;
@@ -193,8 +194,7 @@
 
 		/* find the DRAM Chip Select Base address and mask */
 		pci_read_config_dword(pdev,
-				      AMD76X_MEM_BASE_ADDR + (index * 4),
-				      &mba);
+				AMD76X_MEM_BASE_ADDR + (index * 4), &mba);
 
 		if (!(mba & BIT(0)))
 			continue;
@@ -238,7 +238,7 @@
 	debugf0("%s()\n", __func__);
 	pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems);
 	ems_mode = (ems >> 10) & 0x3;
-	mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS);
+	mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS, 0);
 
 	if (mci == NULL) {
 		return -ENOMEM;
@@ -249,24 +249,36 @@
 	mci->mtype_cap = MEM_FLAG_RDDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
 	mci->edac_cap = ems_mode ?
-			(EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE;
+		(EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE;
 	mci->mod_name = EDAC_MOD_STR;
 	mci->mod_ver = AMD76X_REVISION;
 	mci->ctl_name = amd76x_devs[dev_idx].ctl_name;
+	mci->dev_name = pci_name(pdev);
 	mci->edac_check = amd76x_check;
 	mci->ctl_page_to_phys = NULL;
 
 	amd76x_init_csrows(mci, pdev, ems_modes[ems_mode]);
-	amd76x_get_error_info(mci, &discard);  /* clear counters */
+	amd76x_get_error_info(mci, &discard);	/* clear counters */
 
 	/* Here we assume that we will never see multiple instances of this
 	 * type of memory controller.  The ID is therefore hardcoded to 0.
 	 */
-	if (edac_mc_add_mc(mci,0)) {
+	if (edac_mc_add_mc(mci)) {
 		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
 		goto fail;
 	}
 
+	/* allocating generic PCI control info */
+	amd76x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+	if (!amd76x_pci) {
+		printk(KERN_WARNING
+			"%s(): Unable to create PCI control\n",
+			__func__);
+		printk(KERN_WARNING
+			"%s(): PCI error report via EDAC not setup\n",
+			__func__);
+	}
+
 	/* get this far and it's successful */
 	debugf3("%s(): success\n", __func__);
 	return 0;
@@ -278,7 +290,7 @@
 
 /* returns count (>= 0), or negative on error */
 static int __devinit amd76x_init_one(struct pci_dev *pdev,
-		const struct pci_device_id *ent)
+				const struct pci_device_id *ent)
 {
 	debugf0("%s()\n", __func__);
 
@@ -300,6 +312,9 @@
 
 	debugf0("%s()\n", __func__);
 
+	if (amd76x_pci)
+		edac_pci_release_generic_ctl(amd76x_pci);
+
 	if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
 		return;
 
@@ -308,16 +323,14 @@
 
 static const struct pci_device_id amd76x_pci_tbl[] __devinitdata = {
 	{
-		PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		AMD762
-	},
+	 PCI_VEND_DEV(AMD, FE_GATE_700C), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	 AMD762},
 	{
-		PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		AMD761
-	},
+	 PCI_VEND_DEV(AMD, FE_GATE_700E), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	 AMD761},
 	{
-		0,
-	}	/* 0 terminated list. */
+	 0,
+	 }			/* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, amd76x_pci_tbl);
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 8bcc887..6eb4347 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -22,13 +22,16 @@
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/slab.h>
-#include "edac_mc.h"
+#include <linux/edac.h>
+#include "edac_core.h"
 
-#define E752X_REVISION	" Ver: 2.0.1 " __DATE__
+#define E752X_REVISION	" Ver: 2.0.2 " __DATE__
 #define EDAC_MOD_STR	"e752x_edac"
 
 static int force_function_unhide;
 
+static struct edac_pci_ctl_info *e752x_pci;
+
 #define e752x_printk(level, fmt, arg...) \
 	edac_printk(level, "e752x", fmt, ##arg)
 
@@ -203,25 +206,22 @@
 	[E7520] = {
 		.err_dev = PCI_DEVICE_ID_INTEL_7520_1_ERR,
 		.ctl_dev = PCI_DEVICE_ID_INTEL_7520_0,
-		.ctl_name = "E7520"
-	},
+		.ctl_name = "E7520"},
 	[E7525] = {
 		.err_dev = PCI_DEVICE_ID_INTEL_7525_1_ERR,
 		.ctl_dev = PCI_DEVICE_ID_INTEL_7525_0,
-		.ctl_name = "E7525"
-	},
+		.ctl_name = "E7525"},
 	[E7320] = {
 		.err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR,
 		.ctl_dev = PCI_DEVICE_ID_INTEL_7320_0,
-		.ctl_name = "E7320"
-	},
+		.ctl_name = "E7320"},
 };
 
 static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
-		unsigned long page)
+				unsigned long page)
 {
 	u32 remap;
-	struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+	struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
 
 	debugf3("%s()\n", __func__);
 
@@ -241,13 +241,13 @@
 }
 
 static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
-		u32 sec1_add, u16 sec1_syndrome)
+			u32 sec1_add, u16 sec1_syndrome)
 {
 	u32 page;
 	int row;
 	int channel;
 	int i;
-	struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+	struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
 
 	debugf3("%s()\n", __func__);
 
@@ -261,7 +261,8 @@
 		e752x_printk(KERN_WARNING,
 			"Test row %d Table %d %d %d %d %d %d %d %d\n", row,
 			pvt->map[0], pvt->map[1], pvt->map[2], pvt->map[3],
-			pvt->map[4], pvt->map[5], pvt->map[6], pvt->map[7]);
+			pvt->map[4], pvt->map[5], pvt->map[6],
+			pvt->map[7]);
 
 		/* test for channel remapping */
 		for (i = 0; i < 8; i++) {
@@ -275,24 +276,22 @@
 			row = i;
 		else
 			e752x_mc_printk(mci, KERN_WARNING,
-				"row %d not found in remap table\n", row);
+					"row %d not found in remap table\n",
+					row);
 	} else
 		row = edac_mc_find_csrow_by_page(mci, page);
 
 	/* 0 = channel A, 1 = channel B */
 	channel = !(error_one & 1);
 
-	if (!pvt->map_type)
-		row = 7 - row;
-
 	/* e752x mc reads 34:6 of the DRAM linear address */
 	edac_mc_handle_ce(mci, page, offset_in_page(sec1_add << 4),
 			sec1_syndrome, row, channel, "e752x CE");
 }
 
 static inline void process_ce(struct mem_ctl_info *mci, u16 error_one,
-		u32 sec1_add, u16 sec1_syndrome, int *error_found,
-		int handle_error)
+			u32 sec1_add, u16 sec1_syndrome, int *error_found,
+			int handle_error)
 {
 	*error_found = 1;
 
@@ -301,11 +300,11 @@
 }
 
 static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
-		u32 ded_add, u32 scrb_add)
+			u32 ded_add, u32 scrb_add)
 {
 	u32 error_2b, block_page;
 	int row;
-	struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+	struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
 
 	debugf3("%s()\n", __func__);
 
@@ -316,14 +315,14 @@
 		block_page = error_2b >> (PAGE_SHIFT - 4);
 
 		row = pvt->mc_symmetric ?
-			/* chip select are bits 14 & 13 */
+		/* chip select are bits 14 & 13 */
 			((block_page >> 1) & 3) :
 			edac_mc_find_csrow_by_page(mci, block_page);
 
 		/* e752x mc reads 34:6 of the DRAM linear address */
 		edac_mc_handle_ue(mci, block_page,
-					offset_in_page(error_2b << 4),
-					row, "e752x UE from Read");
+				offset_in_page(error_2b << 4),
+				row, "e752x UE from Read");
 	}
 	if (error_one & 0x0404) {
 		error_2b = scrb_add;
@@ -332,19 +331,20 @@
 		block_page = error_2b >> (PAGE_SHIFT - 4);
 
 		row = pvt->mc_symmetric ?
-			/* chip select are bits 14 & 13 */
+		/* chip select are bits 14 & 13 */
 			((block_page >> 1) & 3) :
 			edac_mc_find_csrow_by_page(mci, block_page);
 
 		/* e752x mc reads 34:6 of the DRAM linear address */
 		edac_mc_handle_ue(mci, block_page,
-					offset_in_page(error_2b << 4),
-					row, "e752x UE from Scruber");
+				offset_in_page(error_2b << 4),
+				row, "e752x UE from Scruber");
 	}
 }
 
 static inline void process_ue(struct mem_ctl_info *mci, u16 error_one,
-		u32 ded_add, u32 scrb_add, int *error_found, int handle_error)
+			u32 ded_add, u32 scrb_add, int *error_found,
+			int handle_error)
 {
 	*error_found = 1;
 
@@ -353,7 +353,7 @@
 }
 
 static inline void process_ue_no_info_wr(struct mem_ctl_info *mci,
-		int *error_found, int handle_error)
+					 int *error_found, int handle_error)
 {
 	*error_found = 1;
 
@@ -365,24 +365,24 @@
 }
 
 static void do_process_ded_retry(struct mem_ctl_info *mci, u16 error,
-		u32 retry_add)
+				 u32 retry_add)
 {
 	u32 error_1b, page;
 	int row;
-	struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
+	struct e752x_pvt *pvt = (struct e752x_pvt *)mci->pvt_info;
 
 	error_1b = retry_add;
-	page = error_1b >> (PAGE_SHIFT - 4); /* convert the addr to 4k page */
-	row = pvt->mc_symmetric ?
-		((page >> 1) & 3) : /* chip select are bits 14 & 13 */
+	page = error_1b >> (PAGE_SHIFT - 4);	/* convert the addr to 4k page */
+	row = pvt->mc_symmetric ? ((page >> 1) & 3) :	/* chip select are bits 14 & 13 */
 		edac_mc_find_csrow_by_page(mci, page);
 	e752x_mc_printk(mci, KERN_WARNING,
-		"CE page 0x%lx, row %d : Memory read retry\n",
-		(long unsigned int) page, row);
+			"CE page 0x%lx, row %d : Memory read retry\n",
+			(long unsigned int)page, row);
 }
 
 static inline void process_ded_retry(struct mem_ctl_info *mci, u16 error,
-		u32 retry_add, int *error_found, int handle_error)
+				u32 retry_add, int *error_found,
+				int handle_error)
 {
 	*error_found = 1;
 
@@ -391,7 +391,7 @@
 }
 
 static inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error,
-		int *error_found, int handle_error)
+					int *error_found, int handle_error)
 {
 	*error_found = 1;
 
@@ -420,7 +420,7 @@
 }
 
 static inline void global_error(int fatal, u32 errors, int *error_found,
-		int handle_error)
+				int handle_error)
 {
 	*error_found = 1;
 
@@ -447,7 +447,7 @@
 }
 
 static inline void hub_error(int fatal, u8 errors, int *error_found,
-		int handle_error)
+			int handle_error)
 {
 	*error_found = 1;
 
@@ -505,7 +505,7 @@
 }
 
 static inline void sysbus_error(int fatal, u32 errors, int *error_found,
-		int handle_error)
+				int handle_error)
 {
 	*error_found = 1;
 
@@ -514,7 +514,7 @@
 }
 
 static void e752x_check_hub_interface(struct e752x_error_info *info,
-		int *error_found, int handle_error)
+				int *error_found, int handle_error)
 {
 	u8 stat8;
 
@@ -522,33 +522,32 @@
 
 	stat8 = info->hi_ferr;
 
-	if(stat8 & 0x7f) { /* Error, so process */
-		stat8 &= 0x7f;
-
-		if(stat8 & 0x2b)
-			hub_error(1, stat8 & 0x2b, error_found, handle_error);
-
-		if(stat8 & 0x54)
-			hub_error(0, stat8 & 0x54, error_found, handle_error);
-	}
-
-	//pci_read_config_byte(dev,E752X_HI_NERR,&stat8);
-
-	stat8 = info->hi_nerr;
-
-	if(stat8 & 0x7f) { /* Error, so process */
+	if (stat8 & 0x7f) {	/* Error, so process */
 		stat8 &= 0x7f;
 
 		if (stat8 & 0x2b)
 			hub_error(1, stat8 & 0x2b, error_found, handle_error);
 
-		if(stat8 & 0x54)
+		if (stat8 & 0x54)
+			hub_error(0, stat8 & 0x54, error_found, handle_error);
+	}
+	//pci_read_config_byte(dev,E752X_HI_NERR,&stat8);
+
+	stat8 = info->hi_nerr;
+
+	if (stat8 & 0x7f) {	/* Error, so process */
+		stat8 &= 0x7f;
+
+		if (stat8 & 0x2b)
+			hub_error(1, stat8 & 0x2b, error_found, handle_error);
+
+		if (stat8 & 0x54)
 			hub_error(0, stat8 & 0x54, error_found, handle_error);
 	}
 }
 
 static void e752x_check_sysbus(struct e752x_error_info *info,
-		int *error_found, int handle_error)
+			int *error_found, int handle_error)
 {
 	u32 stat32, error32;
 
@@ -556,47 +555,47 @@
 	stat32 = info->sysbus_ferr + (info->sysbus_nerr << 16);
 
 	if (stat32 == 0)
-		return;  /* no errors */
+		return;		/* no errors */
 
 	error32 = (stat32 >> 16) & 0x3ff;
 	stat32 = stat32 & 0x3ff;
 
-	if(stat32 & 0x087)
+	if (stat32 & 0x087)
 		sysbus_error(1, stat32 & 0x087, error_found, handle_error);
 
-	if(stat32 & 0x378)
+	if (stat32 & 0x378)
 		sysbus_error(0, stat32 & 0x378, error_found, handle_error);
 
-	if(error32 & 0x087)
+	if (error32 & 0x087)
 		sysbus_error(1, error32 & 0x087, error_found, handle_error);
 
-	if(error32 & 0x378)
+	if (error32 & 0x378)
 		sysbus_error(0, error32 & 0x378, error_found, handle_error);
 }
 
-static void e752x_check_membuf (struct e752x_error_info *info,
-		int *error_found, int handle_error)
+static void e752x_check_membuf(struct e752x_error_info *info,
+			int *error_found, int handle_error)
 {
 	u8 stat8;
 
 	stat8 = info->buf_ferr;
 
-	if (stat8 & 0x0f) { /* Error, so process */
+	if (stat8 & 0x0f) {	/* Error, so process */
 		stat8 &= 0x0f;
 		membuf_error(stat8, error_found, handle_error);
 	}
 
 	stat8 = info->buf_nerr;
 
-	if (stat8 & 0x0f) { /* Error, so process */
+	if (stat8 & 0x0f) {	/* Error, so process */
 		stat8 &= 0x0f;
 		membuf_error(stat8, error_found, handle_error);
 	}
 }
 
-static void e752x_check_dram (struct mem_ctl_info *mci,
-		struct e752x_error_info *info, int *error_found,
-		int handle_error)
+static void e752x_check_dram(struct mem_ctl_info *mci,
+			struct e752x_error_info *info, int *error_found,
+			int handle_error)
 {
 	u16 error_one, error_next;
 
@@ -604,55 +603,52 @@
 	error_next = info->dram_nerr;
 
 	/* decode and report errors */
-	if(error_one & 0x0101)  /* check first error correctable */
+	if (error_one & 0x0101)	/* check first error correctable */
 		process_ce(mci, error_one, info->dram_sec1_add,
-			   info->dram_sec1_syndrome, error_found,
-			   handle_error);
+			info->dram_sec1_syndrome, error_found, handle_error);
 
-	if(error_next & 0x0101)  /* check next error correctable */
+	if (error_next & 0x0101)	/* check next error correctable */
 		process_ce(mci, error_next, info->dram_sec2_add,
-			   info->dram_sec2_syndrome, error_found,
-			   handle_error);
+			info->dram_sec2_syndrome, error_found, handle_error);
 
-	if(error_one & 0x4040)
+	if (error_one & 0x4040)
 		process_ue_no_info_wr(mci, error_found, handle_error);
 
-	if(error_next & 0x4040)
+	if (error_next & 0x4040)
 		process_ue_no_info_wr(mci, error_found, handle_error);
 
-	if(error_one & 0x2020)
+	if (error_one & 0x2020)
 		process_ded_retry(mci, error_one, info->dram_retr_add,
-				  error_found, handle_error);
+				error_found, handle_error);
 
-	if(error_next & 0x2020)
+	if (error_next & 0x2020)
 		process_ded_retry(mci, error_next, info->dram_retr_add,
-				  error_found, handle_error);
+				error_found, handle_error);
 
-	if(error_one & 0x0808)
-		process_threshold_ce(mci, error_one, error_found,
-				     handle_error);
+	if (error_one & 0x0808)
+		process_threshold_ce(mci, error_one, error_found, handle_error);
 
-	if(error_next & 0x0808)
+	if (error_next & 0x0808)
 		process_threshold_ce(mci, error_next, error_found,
-				     handle_error);
+				handle_error);
 
-	if(error_one & 0x0606)
+	if (error_one & 0x0606)
 		process_ue(mci, error_one, info->dram_ded_add,
-			   info->dram_scrb_add, error_found, handle_error);
+			info->dram_scrb_add, error_found, handle_error);
 
-	if(error_next & 0x0606)
+	if (error_next & 0x0606)
 		process_ue(mci, error_next, info->dram_ded_add,
-			   info->dram_scrb_add, error_found, handle_error);
+			info->dram_scrb_add, error_found, handle_error);
 }
 
-static void e752x_get_error_info (struct mem_ctl_info *mci,
-		struct e752x_error_info *info)
+static void e752x_get_error_info(struct mem_ctl_info *mci,
+				 struct e752x_error_info *info)
 {
 	struct pci_dev *dev;
 	struct e752x_pvt *pvt;
 
 	memset(info, 0, sizeof(*info));
-	pvt = (struct e752x_pvt *) mci->pvt_info;
+	pvt = (struct e752x_pvt *)mci->pvt_info;
 	dev = pvt->dev_d0f1;
 	pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global);
 
@@ -661,8 +657,7 @@
 		pci_read_config_word(dev, E752X_SYSBUS_FERR,
 				&info->sysbus_ferr);
 		pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr);
-		pci_read_config_word(dev, E752X_DRAM_FERR,
-				&info->dram_ferr);
+		pci_read_config_word(dev, E752X_DRAM_FERR, &info->dram_ferr);
 		pci_read_config_dword(dev, E752X_DRAM_SEC1_ADD,
 				&info->dram_sec1_add);
 		pci_read_config_word(dev, E752X_DRAM_SEC1_SYNDROME,
@@ -688,7 +683,7 @@
 
 		if (info->dram_ferr)
 			pci_write_bits16(pvt->bridge_ck, E752X_DRAM_FERR,
-					info->dram_ferr, info->dram_ferr);
+					 info->dram_ferr, info->dram_ferr);
 
 		pci_write_config_dword(dev, E752X_FERR_GLOBAL,
 				info->ferr_global);
@@ -701,8 +696,7 @@
 		pci_read_config_word(dev, E752X_SYSBUS_NERR,
 				&info->sysbus_nerr);
 		pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr);
-		pci_read_config_word(dev, E752X_DRAM_NERR,
-				&info->dram_nerr);
+		pci_read_config_word(dev, E752X_DRAM_NERR, &info->dram_nerr);
 		pci_read_config_dword(dev, E752X_DRAM_SEC2_ADD,
 				&info->dram_sec2_add);
 		pci_read_config_word(dev, E752X_DRAM_SEC2_SYNDROME,
@@ -722,15 +716,16 @@
 
 		if (info->dram_nerr)
 			pci_write_bits16(pvt->bridge_ck, E752X_DRAM_NERR,
-					info->dram_nerr, info->dram_nerr);
+					 info->dram_nerr, info->dram_nerr);
 
 		pci_write_config_dword(dev, E752X_NERR_GLOBAL,
 				info->nerr_global);
 	}
 }
 
-static int e752x_process_error_info (struct mem_ctl_info *mci,
-		struct e752x_error_info *info, int handle_errors)
+static int e752x_process_error_info(struct mem_ctl_info *mci,
+				struct e752x_error_info *info,
+				int handle_errors)
 {
 	u32 error32, stat32;
 	int error_found;
@@ -776,26 +771,38 @@
 	return (((ddrcsr >> 12) & 3) == 3);
 }
 
+/* Remap csrow index numbers if map_type is "reverse"
+ */
+static inline int remap_csrow_index(struct mem_ctl_info *mci, int index)
+{
+	struct e752x_pvt *pvt = mci->pvt_info;
+
+	if (!pvt->map_type)
+		return (7 - index);
+
+	return (index);
+}
+
 static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
-		u16 ddrcsr)
+			u16 ddrcsr)
 {
 	struct csrow_info *csrow;
 	unsigned long last_cumul_size;
 	int index, mem_dev, drc_chan;
-	int drc_drbg;  /* DRB granularity 0=64mb, 1=128mb */
-	int drc_ddim;  /* DRAM Data Integrity Mode 0=none, 2=edac */
+	int drc_drbg;		/* DRB granularity 0=64mb, 1=128mb */
+	int drc_ddim;		/* DRAM Data Integrity Mode 0=none, 2=edac */
 	u8 value;
 	u32 dra, drc, cumul_size;
 
 	dra = 0;
-	for (index=0; index < 4; index++) {
+	for (index = 0; index < 4; index++) {
 		u8 dra_reg;
-		pci_read_config_byte(pdev, E752X_DRA+index, &dra_reg);
+		pci_read_config_byte(pdev, E752X_DRA + index, &dra_reg);
 		dra |= dra_reg << (index * 8);
 	}
 	pci_read_config_dword(pdev, E752X_DRC, &drc);
 	drc_chan = dual_channel_active(ddrcsr);
-	drc_drbg = drc_chan + 1;  /* 128 in dual mode, 64 in single */
+	drc_drbg = drc_chan + 1;	/* 128 in dual mode, 64 in single */
 	drc_ddim = (drc >> 20) & 0x3;
 
 	/* The dram row boundary (DRB) reg values are boundary address for
@@ -806,7 +813,7 @@
 	for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
 		/* mem_dev 0=x8, 1=x4 */
 		mem_dev = (dra >> (index * 4 + 2)) & 0x3;
-		csrow = &mci->csrows[index];
+		csrow = &mci->csrows[remap_csrow_index(mci, index)];
 
 		mem_dev = (mem_dev == 2);
 		pci_read_config_byte(pdev, E752X_DRB + index, &value);
@@ -843,10 +850,10 @@
 }
 
 static void e752x_init_mem_map_table(struct pci_dev *pdev,
-		struct e752x_pvt *pvt)
+				struct e752x_pvt *pvt)
 {
 	int index;
-	u8 value, last, row, stat8;
+	u8 value, last, row;
 
 	last = 0;
 	row = 0;
@@ -858,7 +865,7 @@
 			/* no dimm in the slot, so flag it as empty */
 			pvt->map[index] = 0xff;
 			pvt->map[index + 1] = 0xff;
-		} else {        /* there is a dimm in the slot */
+		} else {	/* there is a dimm in the slot */
 			pvt->map[index] = row;
 			row++;
 			last = value;
@@ -866,31 +873,25 @@
 			 * sided
 			 */
 			pci_read_config_byte(pdev, E752X_DRB + index + 1,
-					     &value);
-			pvt->map[index + 1] = (value == last) ?
-			    0xff :      /* the dimm is single sided,
-					   so flag as empty */
-			    row;        /* this is a double sided dimm
-					   to save the next row # */
+					&value);
+
+			/* the dimm is single sided, so flag as empty */
+			/* this is a double sided dimm to save the next row #*/
+			pvt->map[index + 1] = (value == last) ? 0xff :	row;
 			row++;
 			last = value;
 		}
 	}
-
-	/* set the map type.  1 = normal, 0 = reversed */
-	pci_read_config_byte(pdev, E752X_DRM, &stat8);
-	pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f));
 }
 
 /* Return 0 on success or 1 on failure. */
 static int e752x_get_devs(struct pci_dev *pdev, int dev_idx,
-		struct e752x_pvt *pvt)
+			struct e752x_pvt *pvt)
 {
 	struct pci_dev *dev;
 
 	pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
-					pvt->dev_info->err_dev,
-					pvt->bridge_ck);
+					pvt->dev_info->err_dev, pvt->bridge_ck);
 
 	if (pvt->bridge_ck == NULL)
 		pvt->bridge_ck = pci_scan_single_device(pdev->bus,
@@ -898,13 +899,13 @@
 
 	if (pvt->bridge_ck == NULL) {
 		e752x_printk(KERN_ERR, "error reporting device not found:"
-		       "vendor %x device 0x%x (broken BIOS?)\n",
-		       PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
+			"vendor %x device 0x%x (broken BIOS?)\n",
+			PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
 		return 1;
 	}
 
 	dev = pci_get_device(PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].ctl_dev,
-			     NULL);
+			NULL);
 
 	if (dev == NULL)
 		goto fail;
@@ -942,12 +943,22 @@
 	struct mem_ctl_info *mci;
 	struct e752x_pvt *pvt;
 	u16 ddrcsr;
-	int drc_chan;	/* Number of channels 0=1chan,1=2chan */
+	int drc_chan;		/* Number of channels 0=1chan,1=2chan */
 	struct e752x_error_info discard;
 
 	debugf0("%s(): mci\n", __func__);
 	debugf0("Starting Probe1\n");
 
+	/* make sure error reporting method is sane */
+	switch (edac_op_state) {
+	case EDAC_OPSTATE_POLL:
+	case EDAC_OPSTATE_NMI:
+		break;
+	default:
+		edac_op_state = EDAC_OPSTATE_POLL;
+		break;
+	}
+
 	/* check to see if device 0 function 1 is enabled; if it isn't, we
 	 * assume the BIOS has reserved it for a reason and is expecting
 	 * exclusive access, we take care not to violate that assumption and
@@ -956,7 +967,7 @@
 	if (!force_function_unhide && !(stat8 & (1 << 5))) {
 		printk(KERN_INFO "Contact your BIOS vendor to see if the "
 			"E752x error registers can be safely un-hidden\n");
-		return -ENOMEM;
+		return -ENODEV;
 	}
 	stat8 |= (1 << 5);
 	pci_write_config_byte(pdev, E752X_DEVPRES1, stat8);
@@ -966,7 +977,7 @@
 	/* Dual channel = 1, Single channel = 0 */
 	drc_chan = dual_channel_active(ddrcsr);
 
-	mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1);
+	mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1, 0);
 
 	if (mci == NULL) {
 		return -ENOMEM;
@@ -975,14 +986,14 @@
 	debugf3("%s(): init mci\n", __func__);
 	mci->mtype_cap = MEM_FLAG_RDDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED |
-	    EDAC_FLAG_S4ECD4ED;
+		EDAC_FLAG_S4ECD4ED;
 	/* FIXME - what if different memory types are in different csrows? */
 	mci->mod_name = EDAC_MOD_STR;
 	mci->mod_ver = E752X_REVISION;
 	mci->dev = &pdev->dev;
 
 	debugf3("%s(): init pvt\n", __func__);
-	pvt = (struct e752x_pvt *) mci->pvt_info;
+	pvt = (struct e752x_pvt *)mci->pvt_info;
 	pvt->dev_info = &e752x_devs[dev_idx];
 	pvt->mc_symmetric = ((ddrcsr & 0x10) != 0);
 
@@ -993,16 +1004,20 @@
 
 	debugf3("%s(): more mci init\n", __func__);
 	mci->ctl_name = pvt->dev_info->ctl_name;
+	mci->dev_name = pci_name(pdev);
 	mci->edac_check = e752x_check;
 	mci->ctl_page_to_phys = ctl_page_to_phys;
 
-	e752x_init_csrows(mci, pdev, ddrcsr);
-	e752x_init_mem_map_table(pdev, pvt);
-
-	/* set the map type.  1 = normal, 0 = reversed */
+	/* set the map type.  1 = normal, 0 = reversed
+	 * Must be set before e752x_init_csrows in case csrow mapping
+	 * is reversed.
+	 */
 	pci_read_config_byte(pdev, E752X_DRM, &stat8);
 	pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f));
 
+	e752x_init_csrows(mci, pdev, ddrcsr);
+	e752x_init_mem_map_table(pdev, pvt);
+
 	mci->edac_cap |= EDAC_FLAG_NONE;
 	debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
 
@@ -1014,19 +1029,29 @@
 	pci_read_config_word(pdev, E752X_REMAPLIMIT, &pci_data);
 	pvt->remaplimit = ((u32) pci_data) << 14;
 	e752x_printk(KERN_INFO,
-		"tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm,
-		pvt->remapbase, pvt->remaplimit);
+			"tolm = %x, remapbase = %x, remaplimit = %x\n",
+			pvt->tolm, pvt->remapbase, pvt->remaplimit);
 
 	/* Here we assume that we will never see multiple instances of this
 	 * type of memory controller.  The ID is therefore hardcoded to 0.
 	 */
-	if (edac_mc_add_mc(mci,0)) {
+	if (edac_mc_add_mc(mci)) {
 		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
 		goto fail;
 	}
 
 	e752x_init_error_reporting_regs(pvt);
-	e752x_get_error_info(mci, &discard); /* clear other MCH errors */
+	e752x_get_error_info(mci, &discard);	/* clear other MCH errors */
+
+	/* allocating generic PCI control info */
+	e752x_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+	if (!e752x_pci) {
+		printk(KERN_WARNING
+			"%s(): Unable to create PCI control\n", __func__);
+		printk(KERN_WARNING
+			"%s(): PCI error report via EDAC not setup\n",
+			__func__);
+	}
 
 	/* get this far and it's successful */
 	debugf3("%s(): success\n", __func__);
@@ -1043,12 +1068,12 @@
 
 /* returns count (>= 0), or negative on error */
 static int __devinit e752x_init_one(struct pci_dev *pdev,
-		const struct pci_device_id *ent)
+				const struct pci_device_id *ent)
 {
 	debugf0("%s()\n", __func__);
 
 	/* wake up and enable device */
-	if(pci_enable_device(pdev) < 0)
+	if (pci_enable_device(pdev) < 0)
 		return -EIO;
 
 	return e752x_probe1(pdev, ent->driver_data);
@@ -1061,10 +1086,13 @@
 
 	debugf0("%s()\n", __func__);
 
+	if (e752x_pci)
+		edac_pci_release_generic_ctl(e752x_pci);
+
 	if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
 		return;
 
-	pvt = (struct e752x_pvt *) mci->pvt_info;
+	pvt = (struct e752x_pvt *)mci->pvt_info;
 	pci_dev_put(pvt->dev_d0f0);
 	pci_dev_put(pvt->dev_d0f1);
 	pci_dev_put(pvt->bridge_ck);
@@ -1073,20 +1101,17 @@
 
 static const struct pci_device_id e752x_pci_tbl[] __devinitdata = {
 	{
-		PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		E7520
-	},
+	 PCI_VEND_DEV(INTEL, 7520_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	 E7520},
 	{
-		PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		E7525
-	},
+	 PCI_VEND_DEV(INTEL, 7525_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	 E7525},
 	{
-		PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		E7320
-	},
+	 PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	 E7320},
 	{
-		0,
-	}	/* 0 terminated list. */
+	 0,
+	 }			/* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);
@@ -1122,5 +1147,6 @@
 
 module_param(force_function_unhide, int, 0444);
 MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:"
-" 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access");
-
+		 " 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access");
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c
index 310d91b..96ecc49 100644
--- a/drivers/edac/e7xxx_edac.c
+++ b/drivers/edac/e7xxx_edac.c
@@ -27,9 +27,10 @@
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/slab.h>
-#include "edac_mc.h"
+#include <linux/edac.h>
+#include "edac_core.h"
 
-#define	E7XXX_REVISION " Ver: 2.0.1 " __DATE__
+#define	E7XXX_REVISION " Ver: 2.0.2 " __DATE__
 #define	EDAC_MOD_STR	"e7xxx_edac"
 
 #define e7xxx_printk(level, fmt, arg...) \
@@ -143,23 +144,21 @@
 	u32 dram_uelog_add;
 };
 
+static struct edac_pci_ctl_info *e7xxx_pci;
+
 static const struct e7xxx_dev_info e7xxx_devs[] = {
 	[E7500] = {
 		.err_dev = PCI_DEVICE_ID_INTEL_7500_1_ERR,
-		.ctl_name = "E7500"
-	},
+		.ctl_name = "E7500"},
 	[E7501] = {
 		.err_dev = PCI_DEVICE_ID_INTEL_7501_1_ERR,
-		.ctl_name = "E7501"
-	},
+		.ctl_name = "E7501"},
 	[E7505] = {
 		.err_dev = PCI_DEVICE_ID_INTEL_7505_1_ERR,
-		.ctl_name = "E7505"
-	},
+		.ctl_name = "E7505"},
 	[E7205] = {
 		.err_dev = PCI_DEVICE_ID_INTEL_7205_1_ERR,
-		.ctl_name = "E7205"
-	},
+		.ctl_name = "E7205"},
 };
 
 /* FIXME - is this valid for both SECDED and S4ECD4ED? */
@@ -180,15 +179,15 @@
 }
 
 static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
-		unsigned long page)
+				unsigned long page)
 {
 	u32 remap;
-	struct e7xxx_pvt *pvt = (struct e7xxx_pvt *) mci->pvt_info;
+	struct e7xxx_pvt *pvt = (struct e7xxx_pvt *)mci->pvt_info;
 
 	debugf3("%s()\n", __func__);
 
 	if ((page < pvt->tolm) ||
-			((page >= 0x100000) && (page < pvt->remapbase)))
+		((page >= 0x100000) && (page < pvt->remapbase)))
 		return page;
 
 	remap = (page - pvt->tolm) + pvt->remapbase;
@@ -200,8 +199,7 @@
 	return pvt->tolm - 1;
 }
 
-static void process_ce(struct mem_ctl_info *mci,
-		struct e7xxx_error_info *info)
+static void process_ce(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
 {
 	u32 error_1b, page;
 	u16 syndrome;
@@ -212,7 +210,7 @@
 	/* read the error address */
 	error_1b = info->dram_celog_add;
 	/* FIXME - should use PAGE_SHIFT */
-	page = error_1b >> 6;  /* convert the address to 4k page */
+	page = error_1b >> 6;	/* convert the address to 4k page */
 	/* read the syndrome */
 	syndrome = info->dram_celog_syndrome;
 	/* FIXME - check for -1 */
@@ -228,8 +226,7 @@
 	edac_mc_handle_ce_no_info(mci, "e7xxx CE log register overflow");
 }
 
-static void process_ue(struct mem_ctl_info *mci,
-		struct e7xxx_error_info *info)
+static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
 {
 	u32 error_2b, block_page;
 	int row;
@@ -238,7 +235,7 @@
 	/* read the error address */
 	error_2b = info->dram_uelog_add;
 	/* FIXME - should use PAGE_SHIFT */
-	block_page = error_2b >> 6;  /* convert to 4k address */
+	block_page = error_2b >> 6;	/* convert to 4k address */
 	row = edac_mc_find_csrow_by_page(mci, block_page);
 	edac_mc_handle_ue(mci, block_page, 0, row, "e7xxx UE");
 }
@@ -249,16 +246,14 @@
 	edac_mc_handle_ue_no_info(mci, "e7xxx UE log register overflow");
 }
 
-static void e7xxx_get_error_info (struct mem_ctl_info *mci,
-		struct e7xxx_error_info *info)
+static void e7xxx_get_error_info(struct mem_ctl_info *mci,
+				 struct e7xxx_error_info *info)
 {
 	struct e7xxx_pvt *pvt;
 
-	pvt = (struct e7xxx_pvt *) mci->pvt_info;
-	pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_FERR,
-			&info->dram_ferr);
-	pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_NERR,
-			&info->dram_nerr);
+	pvt = (struct e7xxx_pvt *)mci->pvt_info;
+	pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_FERR, &info->dram_ferr);
+	pci_read_config_byte(pvt->bridge_ck, E7XXX_DRAM_NERR, &info->dram_nerr);
 
 	if ((info->dram_ferr & 1) || (info->dram_nerr & 1)) {
 		pci_read_config_dword(pvt->bridge_ck, E7XXX_DRAM_CELOG_ADD,
@@ -279,8 +274,9 @@
 		pci_write_bits8(pvt->bridge_ck, E7XXX_DRAM_NERR, 0x03, 0x03);
 }
 
-static int e7xxx_process_error_info (struct mem_ctl_info *mci,
-		struct e7xxx_error_info *info, int handle_errors)
+static int e7xxx_process_error_info(struct mem_ctl_info *mci,
+				struct e7xxx_error_info *info,
+				int handle_errors)
 {
 	int error_found;
 
@@ -341,7 +337,6 @@
 	return (dev_idx == E7501) ? ((drc >> 22) & 0x1) : 1;
 }
 
-
 /* Return DRB granularity (0=32mb, 1=64mb). */
 static inline int drb_granularity(u32 drc, int dev_idx)
 {
@@ -349,9 +344,8 @@
 	return (dev_idx == E7501) ? ((drc >> 18) & 0x3) : 1;
 }
 
-
 static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
-		int dev_idx, u32 drc)
+			int dev_idx, u32 drc)
 {
 	unsigned long last_cumul_size;
 	int index;
@@ -419,10 +413,21 @@
 	struct e7xxx_error_info discard;
 
 	debugf0("%s(): mci\n", __func__);
+
+	/* make sure error reporting method is sane */
+	switch (edac_op_state) {
+	case EDAC_OPSTATE_POLL:
+	case EDAC_OPSTATE_NMI:
+		break;
+	default:
+		edac_op_state = EDAC_OPSTATE_POLL;
+		break;
+	}
+
 	pci_read_config_dword(pdev, E7XXX_DRC, &drc);
 
 	drc_chan = dual_channel_active(drc, dev_idx);
-	mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1);
+	mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1, 0);
 
 	if (mci == NULL)
 		return -ENOMEM;
@@ -430,17 +435,16 @@
 	debugf3("%s(): init mci\n", __func__);
 	mci->mtype_cap = MEM_FLAG_RDDR;
 	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED |
-			EDAC_FLAG_S4ECD4ED;
+		EDAC_FLAG_S4ECD4ED;
 	/* FIXME - what if different memory types are in different csrows? */
 	mci->mod_name = EDAC_MOD_STR;
 	mci->mod_ver = E7XXX_REVISION;
 	mci->dev = &pdev->dev;
 	debugf3("%s(): init pvt\n", __func__);
-	pvt = (struct e7xxx_pvt *) mci->pvt_info;
+	pvt = (struct e7xxx_pvt *)mci->pvt_info;
 	pvt->dev_info = &e7xxx_devs[dev_idx];
 	pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
-					pvt->dev_info->err_dev,
-					pvt->bridge_ck);
+					pvt->dev_info->err_dev, pvt->bridge_ck);
 
 	if (!pvt->bridge_ck) {
 		e7xxx_printk(KERN_ERR, "error reporting device not found:"
@@ -451,6 +455,7 @@
 
 	debugf3("%s(): more mci init\n", __func__);
 	mci->ctl_name = pvt->dev_info->ctl_name;
+	mci->dev_name = pci_name(pdev);
 	mci->edac_check = e7xxx_check;
 	mci->ctl_page_to_phys = ctl_page_to_phys;
 	e7xxx_init_csrows(mci, pdev, dev_idx, drc);
@@ -473,11 +478,22 @@
 	/* Here we assume that we will never see multiple instances of this
 	 * type of memory controller.  The ID is therefore hardcoded to 0.
 	 */
-	if (edac_mc_add_mc(mci,0)) {
+	if (edac_mc_add_mc(mci)) {
 		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
 		goto fail1;
 	}
 
+	/* allocating generic PCI control info */
+	e7xxx_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+	if (!e7xxx_pci) {
+		printk(KERN_WARNING
+			"%s(): Unable to create PCI control\n",
+			__func__);
+		printk(KERN_WARNING
+			"%s(): PCI error report via EDAC not setup\n",
+			__func__);
+	}
+
 	/* get this far and it's successful */
 	debugf3("%s(): success\n", __func__);
 	return 0;
@@ -493,7 +509,7 @@
 
 /* returns count (>= 0), or negative on error */
 static int __devinit e7xxx_init_one(struct pci_dev *pdev,
-		const struct pci_device_id *ent)
+				const struct pci_device_id *ent)
 {
 	debugf0("%s()\n", __func__);
 
@@ -509,34 +525,33 @@
 
 	debugf0("%s()\n", __func__);
 
+	if (e7xxx_pci)
+		edac_pci_release_generic_ctl(e7xxx_pci);
+
 	if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
 		return;
 
-	pvt = (struct e7xxx_pvt *) mci->pvt_info;
+	pvt = (struct e7xxx_pvt *)mci->pvt_info;
 	pci_dev_put(pvt->bridge_ck);
 	edac_mc_free(mci);
 }
 
 static const struct pci_device_id e7xxx_pci_tbl[] __devinitdata = {
 	{
-		PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		E7205
-	},
+	 PCI_VEND_DEV(INTEL, 7205_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	 E7205},
 	{
-		PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		E7500
-	},
+	 PCI_VEND_DEV(INTEL, 7500_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	 E7500},
 	{
-		PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		E7501
-	},
+	 PCI_VEND_DEV(INTEL, 7501_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	 E7501},
 	{
-		PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		E7505
-	},
+	 PCI_VEND_DEV(INTEL, 7505_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	 E7505},
 	{
-		0,
-	}	/* 0 terminated list. */
+	 0,
+	 }			/* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, e7xxx_pci_tbl);
@@ -563,5 +578,7 @@
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n"
-	"Based on.work by Dan Hollis et al");
+		"Based on.work by Dan Hollis et al");
 MODULE_DESCRIPTION("MC support for Intel e7xxx memory controllers");
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
new file mode 100644
index 0000000..e80af67
--- /dev/null
+++ b/drivers/edac/edac_core.h
@@ -0,0 +1,851 @@
+/*
+ * Defines, structures, APIs for edac_core module
+ *
+ * (C) 2007 Linux Networx (http://lnxi.com)
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written by Thayne Harbaugh
+ * Based on work by Dan Hollis <goemon at anime dot net> and others.
+ *	http://www.anime.net/~goemon/linux-ecc/
+ *
+ * NMI handling support added by
+ *     Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>
+ *
+ * Refactored for multi-source files:
+ *	Doug Thompson <norsk5@xmission.com>
+ *
+ */
+
+#ifndef _EDAC_CORE_H_
+#define _EDAC_CORE_H_
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+#include <linux/pci.h>
+#include <linux/time.h>
+#include <linux/nmi.h>
+#include <linux/rcupdate.h>
+#include <linux/completion.h>
+#include <linux/kobject.h>
+#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/workqueue.h>
+#include <linux/version.h>
+
+#define EDAC_MC_LABEL_LEN	31
+#define EDAC_DEVICE_NAME_LEN	31
+#define EDAC_ATTRIB_VALUE_LEN	15
+#define MC_PROC_NAME_MAX_LEN	7
+
+#if PAGE_SHIFT < 20
+#define PAGES_TO_MiB( pages )	( ( pages ) >> ( 20 - PAGE_SHIFT ) )
+#else				/* PAGE_SHIFT > 20 */
+#define PAGES_TO_MiB( pages )	( ( pages ) << ( PAGE_SHIFT - 20 ) )
+#endif
+
+#define edac_printk(level, prefix, fmt, arg...) \
+	printk(level "EDAC " prefix ": " fmt, ##arg)
+
+#define edac_mc_printk(mci, level, fmt, arg...) \
+	printk(level "EDAC MC%d: " fmt, mci->mc_idx, ##arg)
+
+#define edac_mc_chipset_printk(mci, level, prefix, fmt, arg...) \
+	printk(level "EDAC " prefix " MC%d: " fmt, mci->mc_idx, ##arg)
+
+/* edac_device printk */
+#define edac_device_printk(ctl, level, fmt, arg...) \
+	printk(level "EDAC DEVICE%d: " fmt, ctl->dev_idx, ##arg)
+
+/* edac_pci printk */
+#define edac_pci_printk(ctl, level, fmt, arg...) \
+	printk(level "EDAC PCI%d: " fmt, ctl->pci_idx, ##arg)
+
+/* prefixes for edac_printk() and edac_mc_printk() */
+#define EDAC_MC "MC"
+#define EDAC_PCI "PCI"
+#define EDAC_DEBUG "DEBUG"
+
+#ifdef CONFIG_EDAC_DEBUG
+extern int edac_debug_level;
+
+#define edac_debug_printk(level, fmt, arg...)                            \
+	do {                                                             \
+		if (level <= edac_debug_level)                           \
+			edac_printk(KERN_DEBUG, EDAC_DEBUG, fmt, ##arg); \
+	} while(0)
+
+#define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ )
+#define debugf1( ... ) edac_debug_printk(1, __VA_ARGS__ )
+#define debugf2( ... ) edac_debug_printk(2, __VA_ARGS__ )
+#define debugf3( ... ) edac_debug_printk(3, __VA_ARGS__ )
+#define debugf4( ... ) edac_debug_printk(4, __VA_ARGS__ )
+
+#else				/* !CONFIG_EDAC_DEBUG */
+
+#define debugf0( ... )
+#define debugf1( ... )
+#define debugf2( ... )
+#define debugf3( ... )
+#define debugf4( ... )
+
+#endif				/* !CONFIG_EDAC_DEBUG */
+
+#define BIT(x) (1 << (x))
+
+#define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \
+	PCI_DEVICE_ID_ ## vend ## _ ## dev
+
+#define dev_name(dev) (dev)->dev_name
+
+/* memory devices */
+enum dev_type {
+	DEV_UNKNOWN = 0,
+	DEV_X1,
+	DEV_X2,
+	DEV_X4,
+	DEV_X8,
+	DEV_X16,
+	DEV_X32,		/* Do these parts exist? */
+	DEV_X64			/* Do these parts exist? */
+};
+
+#define DEV_FLAG_UNKNOWN	BIT(DEV_UNKNOWN)
+#define DEV_FLAG_X1		BIT(DEV_X1)
+#define DEV_FLAG_X2		BIT(DEV_X2)
+#define DEV_FLAG_X4		BIT(DEV_X4)
+#define DEV_FLAG_X8		BIT(DEV_X8)
+#define DEV_FLAG_X16		BIT(DEV_X16)
+#define DEV_FLAG_X32		BIT(DEV_X32)
+#define DEV_FLAG_X64		BIT(DEV_X64)
+
+/* memory types */
+enum mem_type {
+	MEM_EMPTY = 0,		/* Empty csrow */
+	MEM_RESERVED,		/* Reserved csrow type */
+	MEM_UNKNOWN,		/* Unknown csrow type */
+	MEM_FPM,		/* Fast page mode */
+	MEM_EDO,		/* Extended data out */
+	MEM_BEDO,		/* Burst Extended data out */
+	MEM_SDR,		/* Single data rate SDRAM */
+	MEM_RDR,		/* Registered single data rate SDRAM */
+	MEM_DDR,		/* Double data rate SDRAM */
+	MEM_RDDR,		/* Registered Double data rate SDRAM */
+	MEM_RMBS,		/* Rambus DRAM */
+	MEM_DDR2,		/* DDR2 RAM */
+	MEM_FB_DDR2,		/* fully buffered DDR2 */
+	MEM_RDDR2,		/* Registered DDR2 RAM */
+};
+
+#define MEM_FLAG_EMPTY		BIT(MEM_EMPTY)
+#define MEM_FLAG_RESERVED	BIT(MEM_RESERVED)
+#define MEM_FLAG_UNKNOWN	BIT(MEM_UNKNOWN)
+#define MEM_FLAG_FPM		BIT(MEM_FPM)
+#define MEM_FLAG_EDO		BIT(MEM_EDO)
+#define MEM_FLAG_BEDO		BIT(MEM_BEDO)
+#define MEM_FLAG_SDR		BIT(MEM_SDR)
+#define MEM_FLAG_RDR		BIT(MEM_RDR)
+#define MEM_FLAG_DDR		BIT(MEM_DDR)
+#define MEM_FLAG_RDDR		BIT(MEM_RDDR)
+#define MEM_FLAG_RMBS		BIT(MEM_RMBS)
+#define MEM_FLAG_DDR2           BIT(MEM_DDR2)
+#define MEM_FLAG_FB_DDR2        BIT(MEM_FB_DDR2)
+#define MEM_FLAG_RDDR2          BIT(MEM_RDDR2)
+
+/* chipset Error Detection and Correction capabilities and mode */
+enum edac_type {
+	EDAC_UNKNOWN = 0,	/* Unknown if ECC is available */
+	EDAC_NONE,		/* Doesnt support ECC */
+	EDAC_RESERVED,		/* Reserved ECC type */
+	EDAC_PARITY,		/* Detects parity errors */
+	EDAC_EC,		/* Error Checking - no correction */
+	EDAC_SECDED,		/* Single bit error correction, Double detection */
+	EDAC_S2ECD2ED,		/* Chipkill x2 devices - do these exist? */
+	EDAC_S4ECD4ED,		/* Chipkill x4 devices */
+	EDAC_S8ECD8ED,		/* Chipkill x8 devices */
+	EDAC_S16ECD16ED,	/* Chipkill x16 devices */
+};
+
+#define EDAC_FLAG_UNKNOWN	BIT(EDAC_UNKNOWN)
+#define EDAC_FLAG_NONE		BIT(EDAC_NONE)
+#define EDAC_FLAG_PARITY	BIT(EDAC_PARITY)
+#define EDAC_FLAG_EC		BIT(EDAC_EC)
+#define EDAC_FLAG_SECDED	BIT(EDAC_SECDED)
+#define EDAC_FLAG_S2ECD2ED	BIT(EDAC_S2ECD2ED)
+#define EDAC_FLAG_S4ECD4ED	BIT(EDAC_S4ECD4ED)
+#define EDAC_FLAG_S8ECD8ED	BIT(EDAC_S8ECD8ED)
+#define EDAC_FLAG_S16ECD16ED	BIT(EDAC_S16ECD16ED)
+
+/* scrubbing capabilities */
+enum scrub_type {
+	SCRUB_UNKNOWN = 0,	/* Unknown if scrubber is available */
+	SCRUB_NONE,		/* No scrubber */
+	SCRUB_SW_PROG,		/* SW progressive (sequential) scrubbing */
+	SCRUB_SW_SRC,		/* Software scrub only errors */
+	SCRUB_SW_PROG_SRC,	/* Progressive software scrub from an error */
+	SCRUB_SW_TUNABLE,	/* Software scrub frequency is tunable */
+	SCRUB_HW_PROG,		/* HW progressive (sequential) scrubbing */
+	SCRUB_HW_SRC,		/* Hardware scrub only errors */
+	SCRUB_HW_PROG_SRC,	/* Progressive hardware scrub from an error */
+	SCRUB_HW_TUNABLE	/* Hardware scrub frequency is tunable */
+};
+
+#define SCRUB_FLAG_SW_PROG	BIT(SCRUB_SW_PROG)
+#define SCRUB_FLAG_SW_SRC	BIT(SCRUB_SW_SRC)
+#define SCRUB_FLAG_SW_PROG_SRC	BIT(SCRUB_SW_PROG_SRC)
+#define SCRUB_FLAG_SW_TUN	BIT(SCRUB_SW_SCRUB_TUNABLE)
+#define SCRUB_FLAG_HW_PROG	BIT(SCRUB_HW_PROG)
+#define SCRUB_FLAG_HW_SRC	BIT(SCRUB_HW_SRC)
+#define SCRUB_FLAG_HW_PROG_SRC	BIT(SCRUB_HW_PROG_SRC)
+#define SCRUB_FLAG_HW_TUN	BIT(SCRUB_HW_TUNABLE)
+
+/* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */
+
+/* EDAC internal operation states */
+#define	OP_ALLOC		0x100
+#define OP_RUNNING_POLL		0x201
+#define OP_RUNNING_INTERRUPT	0x202
+#define OP_RUNNING_POLL_INTR	0x203
+#define OP_OFFLINE		0x300
+
+/*
+ * There are several things to be aware of that aren't at all obvious:
+ *
+ *
+ * SOCKETS, SOCKET SETS, BANKS, ROWS, CHIP-SELECT ROWS, CHANNELS, etc..
+ *
+ * These are some of the many terms that are thrown about that don't always
+ * mean what people think they mean (Inconceivable!).  In the interest of
+ * creating a common ground for discussion, terms and their definitions
+ * will be established.
+ *
+ * Memory devices:	The individual chip on a memory stick.  These devices
+ *			commonly output 4 and 8 bits each.  Grouping several
+ *			of these in parallel provides 64 bits which is common
+ *			for a memory stick.
+ *
+ * Memory Stick:	A printed circuit board that agregates multiple
+ *			memory devices in parallel.  This is the atomic
+ *			memory component that is purchaseable by Joe consumer
+ *			and loaded into a memory socket.
+ *
+ * Socket:		A physical connector on the motherboard that accepts
+ *			a single memory stick.
+ *
+ * Channel:		Set of memory devices on a memory stick that must be
+ *			grouped in parallel with one or more additional
+ *			channels from other memory sticks.  This parallel
+ *			grouping of the output from multiple channels are
+ *			necessary for the smallest granularity of memory access.
+ *			Some memory controllers are capable of single channel -
+ *			which means that memory sticks can be loaded
+ *			individually.  Other memory controllers are only
+ *			capable of dual channel - which means that memory
+ *			sticks must be loaded as pairs (see "socket set").
+ *
+ * Chip-select row:	All of the memory devices that are selected together.
+ *			for a single, minimum grain of memory access.
+ *			This selects all of the parallel memory devices across
+ *			all of the parallel channels.  Common chip-select rows
+ *			for single channel are 64 bits, for dual channel 128
+ *			bits.
+ *
+ * Single-Ranked stick:	A Single-ranked stick has 1 chip-select row of memmory.
+ *			Motherboards commonly drive two chip-select pins to
+ *			a memory stick. A single-ranked stick, will occupy
+ *			only one of those rows. The other will be unused.
+ *
+ * Double-Ranked stick:	A double-ranked stick has two chip-select rows which
+ *			access different sets of memory devices.  The two
+ *			rows cannot be accessed concurrently.
+ *
+ * Double-sided stick:	DEPRECATED TERM, see Double-Ranked stick.
+ *			A double-sided stick has two chip-select rows which
+ *			access different sets of memory devices.  The two
+ *			rows cannot be accessed concurrently.  "Double-sided"
+ *			is irrespective of the memory devices being mounted
+ *			on both sides of the memory stick.
+ *
+ * Socket set:		All of the memory sticks that are required for for
+ *			a single memory access or all of the memory sticks
+ *			spanned by a chip-select row.  A single socket set
+ *			has two chip-select rows and if double-sided sticks
+ *			are used these will occupy those chip-select rows.
+ *
+ * Bank:		This term is avoided because it is unclear when
+ *			needing to distinguish between chip-select rows and
+ *			socket sets.
+ *
+ * Controller pages:
+ *
+ * Physical pages:
+ *
+ * Virtual pages:
+ *
+ *
+ * STRUCTURE ORGANIZATION AND CHOICES
+ *
+ *
+ *
+ * PS - I enjoyed writing all that about as much as you enjoyed reading it.
+ */
+
+struct channel_info {
+	int chan_idx;		/* channel index */
+	u32 ce_count;		/* Correctable Errors for this CHANNEL */
+	char label[EDAC_MC_LABEL_LEN + 1];	/* DIMM label on motherboard */
+	struct csrow_info *csrow;	/* the parent */
+};
+
+struct csrow_info {
+	unsigned long first_page;	/* first page number in dimm */
+	unsigned long last_page;	/* last page number in dimm */
+	unsigned long page_mask;	/* used for interleaving -
+					 * 0UL for non intlv
+					 */
+	u32 nr_pages;		/* number of pages in csrow */
+	u32 grain;		/* granularity of reported error in bytes */
+	int csrow_idx;		/* the chip-select row */
+	enum dev_type dtype;	/* memory device type */
+	u32 ue_count;		/* Uncorrectable Errors for this csrow */
+	u32 ce_count;		/* Correctable Errors for this csrow */
+	enum mem_type mtype;	/* memory csrow type */
+	enum edac_type edac_mode;	/* EDAC mode for this csrow */
+	struct mem_ctl_info *mci;	/* the parent */
+
+	struct kobject kobj;	/* sysfs kobject for this csrow */
+
+	/* channel information for this csrow */
+	u32 nr_channels;
+	struct channel_info *channels;
+};
+
+/* mcidev_sysfs_attribute structure
+ *	used for driver sysfs attributes and in mem_ctl_info
+ * 	sysfs top level entries
+ */
+struct mcidev_sysfs_attribute {
+        struct attribute attr;
+        ssize_t (*show)(struct mem_ctl_info *,char *);
+        ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
+};
+
+/* MEMORY controller information structure
+ */
+struct mem_ctl_info {
+	struct list_head link;	/* for global list of mem_ctl_info structs */
+
+	struct module *owner;	/* Module owner of this control struct */
+
+	unsigned long mtype_cap;	/* memory types supported by mc */
+	unsigned long edac_ctl_cap;	/* Mem controller EDAC capabilities */
+	unsigned long edac_cap;	/* configuration capabilities - this is
+				 * closely related to edac_ctl_cap.  The
+				 * difference is that the controller may be
+				 * capable of s4ecd4ed which would be listed
+				 * in edac_ctl_cap, but if channels aren't
+				 * capable of s4ecd4ed then the edac_cap would
+				 * not have that capability.
+				 */
+	unsigned long scrub_cap;	/* chipset scrub capabilities */
+	enum scrub_type scrub_mode;	/* current scrub mode */
+
+	/* Translates sdram memory scrub rate given in bytes/sec to the
+	   internal representation and configures whatever else needs
+	   to be configured.
+	 */
+	int (*set_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 * bw);
+
+	/* Get the current sdram memory scrub rate from the internal
+	   representation and converts it to the closest matching
+	   bandwith in bytes/sec.
+	 */
+	int (*get_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 * bw);
+
+
+	/* pointer to edac checking routine */
+	void (*edac_check) (struct mem_ctl_info * mci);
+
+	/*
+	 * Remaps memory pages: controller pages to physical pages.
+	 * For most MC's, this will be NULL.
+	 */
+	/* FIXME - why not send the phys page to begin with? */
+	unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci,
+					   unsigned long page);
+	int mc_idx;
+	int nr_csrows;
+	struct csrow_info *csrows;
+	/*
+	 * FIXME - what about controllers on other busses? - IDs must be
+	 * unique.  dev pointer should be sufficiently unique, but
+	 * BUS:SLOT.FUNC numbers may not be unique.
+	 */
+	struct device *dev;
+	const char *mod_name;
+	const char *mod_ver;
+	const char *ctl_name;
+	const char *dev_name;
+	char proc_name[MC_PROC_NAME_MAX_LEN + 1];
+	void *pvt_info;
+	u32 ue_noinfo_count;	/* Uncorrectable Errors w/o info */
+	u32 ce_noinfo_count;	/* Correctable Errors w/o info */
+	u32 ue_count;		/* Total Uncorrectable Errors for this MC */
+	u32 ce_count;		/* Total Correctable Errors for this MC */
+	unsigned long start_time;	/* mci load start time (in jiffies) */
+
+	/* this stuff is for safe removal of mc devices from global list while
+	 * NMI handlers may be traversing list
+	 */
+	struct rcu_head rcu;
+	struct completion complete;
+
+	/* edac sysfs device control */
+	struct kobject edac_mci_kobj;
+
+	/* Additional top controller level attributes, but specified
+	 * by the low level driver.
+	 *
+	 * Set by the low level driver to provide attributes at the
+	 * controller level, same level as 'ue_count' and 'ce_count' above.
+	 * An array of structures, NULL terminated
+	 *
+	 * If attributes are desired, then set to array of attributes
+	 * If no attributes are desired, leave NULL
+	 */
+	struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes;
+
+	/* work struct for this MC */
+	struct delayed_work work;
+
+	/* the internal state of this controller instance */
+	int op_state;
+};
+
+/*
+ * The following are the structures to provide for a generic
+ * or abstract 'edac_device'. This set of structures and the
+ * code that implements the APIs for the same, provide for
+ * registering EDAC type devices which are NOT standard memory.
+ *
+ * CPU caches (L1 and L2)
+ * DMA engines
+ * Core CPU swithces
+ * Fabric switch units
+ * PCIe interface controllers
+ * other EDAC/ECC type devices that can be monitored for
+ * errors, etc.
+ *
+ * It allows for a 2 level set of hiearchry. For example:
+ *
+ * cache could be composed of L1, L2 and L3 levels of cache.
+ * Each CPU core would have its own L1 cache, while sharing
+ * L2 and maybe L3 caches.
+ *
+ * View them arranged, via the sysfs presentation:
+ * /sys/devices/system/edac/..
+ *
+ *	mc/		<existing memory device directory>
+ *	cpu/cpu0/..	<L1 and L2 block directory>
+ *		/L1-cache/ce_count
+ *			 /ue_count
+ *		/L2-cache/ce_count
+ *			 /ue_count
+ *	cpu/cpu1/..	<L1 and L2 block directory>
+ *		/L1-cache/ce_count
+ *			 /ue_count
+ *		/L2-cache/ce_count
+ *			 /ue_count
+ *	...
+ *
+ *	the L1 and L2 directories would be "edac_device_block's"
+ */
+
+struct edac_device_counter {
+	u32 ue_count;
+	u32 ce_count;
+};
+
+/* forward reference */
+struct edac_device_ctl_info;
+struct edac_device_block;
+
+/* edac_dev_sysfs_attribute structure
+ *	used for driver sysfs attributes in mem_ctl_info
+ *	for extra controls and attributes:
+ *		like high level error Injection controls
+ */
+struct edac_dev_sysfs_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct edac_device_ctl_info *, char *);
+	ssize_t (*store)(struct edac_device_ctl_info *, const char *, size_t);
+};
+
+/* edac_dev_sysfs_block_attribute structure
+ *
+ *	used in leaf 'block' nodes for adding controls/attributes
+ *
+ *	each block in each instance of the containing control structure
+ *	can have an array of the following. The show and store functions
+ *	will be filled in with the show/store function in the
+ *	low level driver.
+ *
+ *	The 'value' field will be the actual value field used for
+ *	counting
+ */
+struct edac_dev_sysfs_block_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct kobject *, struct attribute *, char *);
+	ssize_t (*store)(struct kobject *, struct attribute *,
+			const char *, size_t);
+	struct edac_device_block *block;
+
+	unsigned int value;
+};
+
+/* device block control structure */
+struct edac_device_block {
+	struct edac_device_instance *instance;	/* Up Pointer */
+	char name[EDAC_DEVICE_NAME_LEN + 1];
+
+	struct edac_device_counter counters;	/* basic UE and CE counters */
+
+	int nr_attribs;		/* how many attributes */
+
+	/* this block's attributes, could be NULL */
+	struct edac_dev_sysfs_block_attribute *block_attributes;
+
+	/* edac sysfs device control */
+	struct kobject kobj;
+};
+
+/* device instance control structure */
+struct edac_device_instance {
+	struct edac_device_ctl_info *ctl;	/* Up pointer */
+	char name[EDAC_DEVICE_NAME_LEN + 4];
+
+	struct edac_device_counter counters;	/* instance counters */
+
+	u32 nr_blocks;		/* how many blocks */
+	struct edac_device_block *blocks;	/* block array */
+
+	/* edac sysfs device control */
+	struct kobject kobj;
+};
+
+
+/*
+ * Abstract edac_device control info structure
+ *
+ */
+struct edac_device_ctl_info {
+	/* for global list of edac_device_ctl_info structs */
+	struct list_head link;
+
+	struct module *owner;	/* Module owner of this control struct */
+
+	int dev_idx;
+
+	/* Per instance controls for this edac_device */
+	int log_ue;		/* boolean for logging UEs */
+	int log_ce;		/* boolean for logging CEs */
+	int panic_on_ue;	/* boolean for panic'ing on an UE */
+	unsigned poll_msec;	/* number of milliseconds to poll interval */
+	unsigned long delay;	/* number of jiffies for poll_msec */
+
+	/* Additional top controller level attributes, but specified
+	 * by the low level driver.
+	 *
+	 * Set by the low level driver to provide attributes at the
+	 * controller level, same level as 'ue_count' and 'ce_count' above.
+	 * An array of structures, NULL terminated
+	 *
+	 * If attributes are desired, then set to array of attributes
+	 * If no attributes are desired, leave NULL
+	 */
+	struct edac_dev_sysfs_attribute *sysfs_attributes;
+
+	/* pointer to main 'edac' class in sysfs */
+	struct sysdev_class *edac_class;
+
+	/* the internal state of this controller instance */
+	int op_state;
+	/* work struct for this instance */
+	struct delayed_work work;
+
+	/* pointer to edac polling checking routine:
+	 *      If NOT NULL: points to polling check routine
+	 *      If NULL: Then assumes INTERRUPT operation, where
+	 *              MC driver will receive events
+	 */
+	void (*edac_check) (struct edac_device_ctl_info * edac_dev);
+
+	struct device *dev;	/* pointer to device structure */
+
+	const char *mod_name;	/* module name */
+	const char *ctl_name;	/* edac controller  name */
+	const char *dev_name;	/* pci/platform/etc... name */
+
+	void *pvt_info;		/* pointer to 'private driver' info */
+
+	unsigned long start_time;	/* edac_device load start time (jiffies) */
+
+	/* these are for safe removal of mc devices from global list while
+	 * NMI handlers may be traversing list
+	 */
+	struct rcu_head rcu;
+	struct completion removal_complete;
+
+	/* sysfs top name under 'edac' directory
+	 * and instance name:
+	 *      cpu/cpu0/...
+	 *      cpu/cpu1/...
+	 *      cpu/cpu2/...
+	 *      ...
+	 */
+	char name[EDAC_DEVICE_NAME_LEN + 1];
+
+	/* Number of instances supported on this control structure
+	 * and the array of those instances
+	 */
+	u32 nr_instances;
+	struct edac_device_instance *instances;
+
+	/* Event counters for the this whole EDAC Device */
+	struct edac_device_counter counters;
+
+	/* edac sysfs device control for the 'name'
+	 * device this structure controls
+	 */
+	struct kobject kobj;
+};
+
+/* To get from the instance's wq to the beginning of the ctl structure */
+#define to_edac_mem_ctl_work(w) \
+		container_of(w, struct mem_ctl_info, work)
+
+#define to_edac_device_ctl_work(w) \
+		container_of(w,struct edac_device_ctl_info,work)
+
+/*
+ * The alloc() and free() functions for the 'edac_device' control info
+ * structure. A MC driver will allocate one of these for each edac_device
+ * it is going to control/register with the EDAC CORE.
+ */
+extern struct edac_device_ctl_info *edac_device_alloc_ctl_info(
+		unsigned sizeof_private,
+		char *edac_device_name, unsigned nr_instances,
+		char *edac_block_name, unsigned nr_blocks,
+		unsigned offset_value,
+		struct edac_dev_sysfs_block_attribute *block_attributes,
+		unsigned nr_attribs,
+		int device_index);
+
+/* The offset value can be:
+ *	-1 indicating no offset value
+ *	0 for zero-based block numbers
+ *	1 for 1-based block number
+ *	other for other-based block number
+ */
+#define	BLOCK_OFFSET_VALUE_OFF	((unsigned) -1)
+
+extern void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info);
+
+#ifdef CONFIG_PCI
+
+struct edac_pci_counter {
+	atomic_t pe_count;
+	atomic_t npe_count;
+};
+
+/*
+ * Abstract edac_pci control info structure
+ *
+ */
+struct edac_pci_ctl_info {
+	/* for global list of edac_pci_ctl_info structs */
+	struct list_head link;
+
+	int pci_idx;
+
+	struct sysdev_class *edac_class;	/* pointer to class */
+
+	/* the internal state of this controller instance */
+	int op_state;
+	/* work struct for this instance */
+	struct delayed_work work;
+
+	/* pointer to edac polling checking routine:
+	 *      If NOT NULL: points to polling check routine
+	 *      If NULL: Then assumes INTERRUPT operation, where
+	 *              MC driver will receive events
+	 */
+	void (*edac_check) (struct edac_pci_ctl_info * edac_dev);
+
+	struct device *dev;	/* pointer to device structure */
+
+	const char *mod_name;	/* module name */
+	const char *ctl_name;	/* edac controller  name */
+	const char *dev_name;	/* pci/platform/etc... name */
+
+	void *pvt_info;		/* pointer to 'private driver' info */
+
+	unsigned long start_time;	/* edac_pci load start time (jiffies) */
+
+	/* these are for safe removal of devices from global list while
+	 * NMI handlers may be traversing list
+	 */
+	struct rcu_head rcu;
+	struct completion complete;
+
+	/* sysfs top name under 'edac' directory
+	 * and instance name:
+	 *      cpu/cpu0/...
+	 *      cpu/cpu1/...
+	 *      cpu/cpu2/...
+	 *      ...
+	 */
+	char name[EDAC_DEVICE_NAME_LEN + 1];
+
+	/* Event counters for the this whole EDAC Device */
+	struct edac_pci_counter counters;
+
+	/* edac sysfs device control for the 'name'
+	 * device this structure controls
+	 */
+	struct kobject kobj;
+	struct completion kobj_complete;
+};
+
+#define to_edac_pci_ctl_work(w) \
+		container_of(w, struct edac_pci_ctl_info,work)
+
+/* write all or some bits in a byte-register*/
+static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value,
+				   u8 mask)
+{
+	if (mask != 0xff) {
+		u8 buf;
+
+		pci_read_config_byte(pdev, offset, &buf);
+		value &= mask;
+		buf &= ~mask;
+		value |= buf;
+	}
+
+	pci_write_config_byte(pdev, offset, value);
+}
+
+/* write all or some bits in a word-register*/
+static inline void pci_write_bits16(struct pci_dev *pdev, int offset,
+				    u16 value, u16 mask)
+{
+	if (mask != 0xffff) {
+		u16 buf;
+
+		pci_read_config_word(pdev, offset, &buf);
+		value &= mask;
+		buf &= ~mask;
+		value |= buf;
+	}
+
+	pci_write_config_word(pdev, offset, value);
+}
+
+/* write all or some bits in a dword-register*/
+static inline void pci_write_bits32(struct pci_dev *pdev, int offset,
+				    u32 value, u32 mask)
+{
+	if (mask != 0xffff) {
+		u32 buf;
+
+		pci_read_config_dword(pdev, offset, &buf);
+		value &= mask;
+		buf &= ~mask;
+		value |= buf;
+	}
+
+	pci_write_config_dword(pdev, offset, value);
+}
+
+#endif				/* CONFIG_PCI */
+
+extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
+					  unsigned nr_chans, int edac_index);
+extern int edac_mc_add_mc(struct mem_ctl_info *mci);
+extern void edac_mc_free(struct mem_ctl_info *mci);
+extern struct mem_ctl_info *edac_mc_find(int idx);
+extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev);
+extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci,
+				      unsigned long page);
+
+/*
+ * The no info errors are used when error overflows are reported.
+ * There are a limited number of error logging registers that can
+ * be exausted.  When all registers are exhausted and an additional
+ * error occurs then an error overflow register records that an
+ * error occured and the type of error, but doesn't have any
+ * further information.  The ce/ue versions make for cleaner
+ * reporting logic and function interface - reduces conditional
+ * statement clutter and extra function arguments.
+ */
+extern void edac_mc_handle_ce(struct mem_ctl_info *mci,
+			      unsigned long page_frame_number,
+			      unsigned long offset_in_page,
+			      unsigned long syndrome, int row, int channel,
+			      const char *msg);
+extern void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci,
+				      const char *msg);
+extern void edac_mc_handle_ue(struct mem_ctl_info *mci,
+			      unsigned long page_frame_number,
+			      unsigned long offset_in_page, int row,
+			      const char *msg);
+extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci,
+				      const char *msg);
+extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, unsigned int csrow,
+				  unsigned int channel0, unsigned int channel1,
+				  char *msg);
+extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, unsigned int csrow,
+				  unsigned int channel, char *msg);
+
+/*
+ * edac_device APIs
+ */
+extern int edac_device_add_device(struct edac_device_ctl_info *edac_dev);
+extern struct edac_device_ctl_info *edac_device_del_device(struct device *dev);
+extern void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev,
+				int inst_nr, int block_nr, const char *msg);
+extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev,
+				int inst_nr, int block_nr, const char *msg);
+
+/*
+ * edac_pci APIs
+ */
+extern struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt,
+				const char *edac_pci_name);
+
+extern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci);
+
+extern void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
+				unsigned long value);
+
+extern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx);
+extern struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev);
+
+extern struct edac_pci_ctl_info *edac_pci_create_generic_ctl(
+				struct device *dev,
+				const char *mod_name);
+
+extern void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci);
+extern int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci);
+extern void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci);
+
+/*
+ * edac misc APIs
+ */
+extern char *edac_op_state_to_string(int op_state);
+
+#endif				/* _EDAC_CORE_H_ */
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
new file mode 100644
index 0000000..f3690a6
--- /dev/null
+++ b/drivers/edac/edac_device.c
@@ -0,0 +1,746 @@
+
+/*
+ * edac_device.c
+ * (C) 2007 www.douglaskthompson.com
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written by Doug Thompson <norsk5@xmission.com>
+ *
+ * edac_device API implementation
+ * 19 Jan 2007
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/sysctl.h>
+#include <linux/highmem.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/sysdev.h>
+#include <linux/ctype.h>
+#include <linux/workqueue.h>
+#include <asm/uaccess.h>
+#include <asm/page.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+/* lock for the list: 'edac_device_list', manipulation of this list
+ * is protected by the 'device_ctls_mutex' lock
+ */
+static DEFINE_MUTEX(device_ctls_mutex);
+static struct list_head edac_device_list = LIST_HEAD_INIT(edac_device_list);
+
+#ifdef CONFIG_EDAC_DEBUG
+static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
+{
+	debugf3("\tedac_dev = %p dev_idx=%d \n", edac_dev, edac_dev->dev_idx);
+	debugf4("\tedac_dev->edac_check = %p\n", edac_dev->edac_check);
+	debugf3("\tdev = %p\n", edac_dev->dev);
+	debugf3("\tmod_name:ctl_name = %s:%s\n",
+		edac_dev->mod_name, edac_dev->ctl_name);
+	debugf3("\tpvt_info = %p\n\n", edac_dev->pvt_info);
+}
+#endif				/* CONFIG_EDAC_DEBUG */
+
+
+/*
+ * edac_device_alloc_ctl_info()
+ *	Allocate a new edac device control info structure
+ *
+ *	The control structure is allocated in complete chunk
+ *	from the OS. It is in turn sub allocated to the
+ *	various objects that compose the struture
+ *
+ *	The structure has a 'nr_instance' array within itself.
+ *	Each instance represents a major component
+ *		Example:  L1 cache and L2 cache are 2 instance components
+ *
+ *	Within each instance is an array of 'nr_blocks' blockoffsets
+ */
+struct edac_device_ctl_info *edac_device_alloc_ctl_info(
+	unsigned sz_private,
+	char *edac_device_name, unsigned nr_instances,
+	char *edac_block_name, unsigned nr_blocks,
+	unsigned offset_value,		/* zero, 1, or other based offset */
+	struct edac_dev_sysfs_block_attribute *attrib_spec, unsigned nr_attrib,
+	int device_index)
+{
+	struct edac_device_ctl_info *dev_ctl;
+	struct edac_device_instance *dev_inst, *inst;
+	struct edac_device_block *dev_blk, *blk_p, *blk;
+	struct edac_dev_sysfs_block_attribute *dev_attrib, *attrib_p, *attrib;
+	unsigned total_size;
+	unsigned count;
+	unsigned instance, block, attr;
+	void *pvt;
+	int err;
+
+	debugf4("%s() instances=%d blocks=%d\n",
+		__func__, nr_instances, nr_blocks);
+
+	/* Calculate the size of memory we need to allocate AND
+	 * determine the offsets of the various item arrays
+	 * (instance,block,attrib) from the start of an  allocated structure.
+	 * We want the alignment of each item  (instance,block,attrib)
+	 * to be at least as stringent as what the compiler would
+	 * provide if we could simply hardcode everything into a single struct.
+	 */
+	dev_ctl = (struct edac_device_ctl_info *)NULL;
+
+	/* Calc the 'end' offset past end of ONE ctl_info structure
+	 * which will become the start of the 'instance' array
+	 */
+	dev_inst = edac_align_ptr(&dev_ctl[1], sizeof(*dev_inst));
+
+	/* Calc the 'end' offset past the instance array within the ctl_info
+	 * which will become the start of the block array
+	 */
+	dev_blk = edac_align_ptr(&dev_inst[nr_instances], sizeof(*dev_blk));
+
+	/* Calc the 'end' offset past the dev_blk array
+	 * which will become the start of the attrib array, if any.
+	 */
+	count = nr_instances * nr_blocks;
+	dev_attrib = edac_align_ptr(&dev_blk[count], sizeof(*dev_attrib));
+
+	/* Check for case of when an attribute array is specified */
+	if (nr_attrib > 0) {
+		/* calc how many nr_attrib we need */
+		count *= nr_attrib;
+
+		/* Calc the 'end' offset past the attributes array */
+		pvt = edac_align_ptr(&dev_attrib[count], sz_private);
+	} else {
+		/* no attribute array specificed */
+		pvt = edac_align_ptr(dev_attrib, sz_private);
+	}
+
+	/* 'pvt' now points to where the private data area is.
+	 * At this point 'pvt' (like dev_inst,dev_blk and dev_attrib)
+	 * is baselined at ZERO
+	 */
+	total_size = ((unsigned long)pvt) + sz_private;
+
+	/* Allocate the amount of memory for the set of control structures */
+	dev_ctl = kzalloc(total_size, GFP_KERNEL);
+	if (dev_ctl == NULL)
+		return NULL;
+
+	/* Adjust pointers so they point within the actual memory we
+	 * just allocated rather than an imaginary chunk of memory
+	 * located at address 0.
+	 * 'dev_ctl' points to REAL memory, while the others are
+	 * ZERO based and thus need to be adjusted to point within
+	 * the allocated memory.
+	 */
+	dev_inst = (struct edac_device_instance *)
+		(((char *)dev_ctl) + ((unsigned long)dev_inst));
+	dev_blk = (struct edac_device_block *)
+		(((char *)dev_ctl) + ((unsigned long)dev_blk));
+	dev_attrib = (struct edac_dev_sysfs_block_attribute *)
+		(((char *)dev_ctl) + ((unsigned long)dev_attrib));
+	pvt = sz_private ? (((char *)dev_ctl) + ((unsigned long)pvt)) : NULL;
+
+	/* Begin storing the information into the control info structure */
+	dev_ctl->dev_idx = device_index;
+	dev_ctl->nr_instances = nr_instances;
+	dev_ctl->instances = dev_inst;
+	dev_ctl->pvt_info = pvt;
+
+	/* Name of this edac device */
+	snprintf(dev_ctl->name,sizeof(dev_ctl->name),"%s",edac_device_name);
+
+	debugf4("%s() edac_dev=%p next after end=%p\n",
+		__func__, dev_ctl, pvt + sz_private );
+
+	/* Initialize every Instance */
+	for (instance = 0; instance < nr_instances; instance++) {
+		inst = &dev_inst[instance];
+		inst->ctl = dev_ctl;
+		inst->nr_blocks = nr_blocks;
+		blk_p = &dev_blk[instance * nr_blocks];
+		inst->blocks = blk_p;
+
+		/* name of this instance */
+		snprintf(inst->name, sizeof(inst->name),
+			 "%s%u", edac_device_name, instance);
+
+		/* Initialize every block in each instance */
+		for (block = 0; block < nr_blocks; block++) {
+			blk = &blk_p[block];
+			blk->instance = inst;
+			snprintf(blk->name, sizeof(blk->name),
+				 "%s%d", edac_block_name, block+offset_value);
+
+			debugf4("%s() instance=%d inst_p=%p block=#%d "
+				"block_p=%p name='%s'\n",
+				__func__, instance, inst, block,
+				blk, blk->name);
+
+			/* if there are NO attributes OR no attribute pointer
+			 * then continue on to next block iteration
+			 */
+			if ((nr_attrib == 0) || (attrib_spec == NULL))
+				continue;
+
+			/* setup the attribute array for this block */
+			blk->nr_attribs = nr_attrib;
+			attrib_p = &dev_attrib[block*nr_instances*nr_attrib];
+			blk->block_attributes = attrib_p;
+
+			debugf4("%s() THIS BLOCK_ATTRIB=%p\n",
+				__func__, blk->block_attributes);
+
+			/* Initialize every user specified attribute in this
+			 * block with the data the caller passed in
+			 * Each block gets its own copy of pointers,
+			 * and its unique 'value'
+			 */
+			for (attr = 0; attr < nr_attrib; attr++) {
+				attrib = &attrib_p[attr];
+
+				/* populate the unique per attrib
+				 * with the code pointers and info
+				 */
+				attrib->attr = attrib_spec[attr].attr;
+				attrib->show = attrib_spec[attr].show;
+				attrib->store = attrib_spec[attr].store;
+
+				attrib->block = blk;	/* up link */
+
+				debugf4("%s() alloc-attrib=%p attrib_name='%s' "
+					"attrib-spec=%p spec-name=%s\n",
+					__func__, attrib, attrib->attr.name,
+					&attrib_spec[attr],
+					attrib_spec[attr].attr.name
+					);
+			}
+		}
+	}
+
+	/* Mark this instance as merely ALLOCATED */
+	dev_ctl->op_state = OP_ALLOC;
+
+	/*
+	 * Initialize the 'root' kobj for the edac_device controller
+	 */
+	err = edac_device_register_sysfs_main_kobj(dev_ctl);
+	if (err) {
+		kfree(dev_ctl);
+		return NULL;
+	}
+
+	/* at this point, the root kobj is valid, and in order to
+	 * 'free' the object, then the function:
+	 *	edac_device_unregister_sysfs_main_kobj() must be called
+	 * which will perform kobj unregistration and the actual free
+	 * will occur during the kobject callback operation
+	 */
+
+	return dev_ctl;
+}
+EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info);
+
+/*
+ * edac_device_free_ctl_info()
+ *	frees the memory allocated by the edac_device_alloc_ctl_info()
+ *	function
+ */
+void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info)
+{
+	edac_device_unregister_sysfs_main_kobj(ctl_info);
+}
+EXPORT_SYMBOL_GPL(edac_device_free_ctl_info);
+
+/*
+ * find_edac_device_by_dev
+ *	scans the edac_device list for a specific 'struct device *'
+ *
+ *	lock to be held prior to call:	device_ctls_mutex
+ *
+ *	Return:
+ *		pointer to control structure managing 'dev'
+ *		NULL if not found on list
+ */
+static struct edac_device_ctl_info *find_edac_device_by_dev(struct device *dev)
+{
+	struct edac_device_ctl_info *edac_dev;
+	struct list_head *item;
+
+	debugf0("%s()\n", __func__);
+
+	list_for_each(item, &edac_device_list) {
+		edac_dev = list_entry(item, struct edac_device_ctl_info, link);
+
+		if (edac_dev->dev == dev)
+			return edac_dev;
+	}
+
+	return NULL;
+}
+
+/*
+ * add_edac_dev_to_global_list
+ *	Before calling this function, caller must
+ *	assign a unique value to edac_dev->dev_idx.
+ *
+ *	lock to be held prior to call:	device_ctls_mutex
+ *
+ *	Return:
+ *		0 on success
+ *		1 on failure.
+ */
+static int add_edac_dev_to_global_list(struct edac_device_ctl_info *edac_dev)
+{
+	struct list_head *item, *insert_before;
+	struct edac_device_ctl_info *rover;
+
+	insert_before = &edac_device_list;
+
+	/* Determine if already on the list */
+	rover = find_edac_device_by_dev(edac_dev->dev);
+	if (unlikely(rover != NULL))
+		goto fail0;
+
+	/* Insert in ascending order by 'dev_idx', so find position */
+	list_for_each(item, &edac_device_list) {
+		rover = list_entry(item, struct edac_device_ctl_info, link);
+
+		if (rover->dev_idx >= edac_dev->dev_idx) {
+			if (unlikely(rover->dev_idx == edac_dev->dev_idx))
+				goto fail1;
+
+			insert_before = item;
+			break;
+		}
+	}
+
+	list_add_tail_rcu(&edac_dev->link, insert_before);
+	return 0;
+
+fail0:
+	edac_printk(KERN_WARNING, EDAC_MC,
+			"%s (%s) %s %s already assigned %d\n",
+			rover->dev->bus_id, dev_name(rover),
+			rover->mod_name, rover->ctl_name, rover->dev_idx);
+	return 1;
+
+fail1:
+	edac_printk(KERN_WARNING, EDAC_MC,
+			"bug in low-level driver: attempt to assign\n"
+			"    duplicate dev_idx %d in %s()\n", rover->dev_idx,
+			__func__);
+	return 1;
+}
+
+/*
+ * complete_edac_device_list_del
+ *
+ *	callback function when reference count is zero
+ */
+static void complete_edac_device_list_del(struct rcu_head *head)
+{
+	struct edac_device_ctl_info *edac_dev;
+
+	edac_dev = container_of(head, struct edac_device_ctl_info, rcu);
+	INIT_LIST_HEAD(&edac_dev->link);
+	complete(&edac_dev->removal_complete);
+}
+
+/*
+ * del_edac_device_from_global_list
+ *
+ *	remove the RCU, setup for a callback call,
+ *	then wait for the callback to occur
+ */
+static void del_edac_device_from_global_list(struct edac_device_ctl_info
+						*edac_device)
+{
+	list_del_rcu(&edac_device->link);
+
+	init_completion(&edac_device->removal_complete);
+	call_rcu(&edac_device->rcu, complete_edac_device_list_del);
+	wait_for_completion(&edac_device->removal_complete);
+}
+
+/**
+ * edac_device_find
+ *	Search for a edac_device_ctl_info structure whose index is 'idx'.
+ *
+ * If found, return a pointer to the structure.
+ * Else return NULL.
+ *
+ * Caller must hold device_ctls_mutex.
+ */
+struct edac_device_ctl_info *edac_device_find(int idx)
+{
+	struct list_head *item;
+	struct edac_device_ctl_info *edac_dev;
+
+	/* Iterate over list, looking for exact match of ID */
+	list_for_each(item, &edac_device_list) {
+		edac_dev = list_entry(item, struct edac_device_ctl_info, link);
+
+		if (edac_dev->dev_idx >= idx) {
+			if (edac_dev->dev_idx == idx)
+				return edac_dev;
+
+			/* not on list, so terminate early */
+			break;
+		}
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(edac_device_find);
+
+/*
+ * edac_device_workq_function
+ *	performs the operation scheduled by a workq request
+ *
+ *	this workq is embedded within an edac_device_ctl_info
+ *	structure, that needs to be polled for possible error events.
+ *
+ *	This operation is to acquire the list mutex lock
+ *	(thus preventing insertation or deletion)
+ *	and then call the device's poll function IFF this device is
+ *	running polled and there is a poll function defined.
+ */
+static void edac_device_workq_function(struct work_struct *work_req)
+{
+	struct delayed_work *d_work = (struct delayed_work *)work_req;
+	struct edac_device_ctl_info *edac_dev = to_edac_device_ctl_work(d_work);
+
+	mutex_lock(&device_ctls_mutex);
+
+	/* Only poll controllers that are running polled and have a check */
+	if ((edac_dev->op_state == OP_RUNNING_POLL) &&
+		(edac_dev->edac_check != NULL)) {
+			edac_dev->edac_check(edac_dev);
+	}
+
+	mutex_unlock(&device_ctls_mutex);
+
+	/* Reschedule the workq for the next time period to start again
+	 * if the number of msec is for 1 sec, then adjust to the next
+	 * whole one second to save timers fireing all over the period
+	 * between integral seconds
+	 */
+	if (edac_dev->poll_msec == 1000)
+		queue_delayed_work(edac_workqueue, &edac_dev->work,
+				round_jiffies(edac_dev->delay));
+	else
+		queue_delayed_work(edac_workqueue, &edac_dev->work,
+				edac_dev->delay);
+}
+
+/*
+ * edac_device_workq_setup
+ *	initialize a workq item for this edac_device instance
+ *	passing in the new delay period in msec
+ */
+void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
+				unsigned msec)
+{
+	debugf0("%s()\n", __func__);
+
+	/* take the arg 'msec' and set it into the control structure
+	 * to used in the time period calculation
+	 * then calc the number of jiffies that represents
+	 */
+	edac_dev->poll_msec = msec;
+	edac_dev->delay = msecs_to_jiffies(msec);
+
+	INIT_DELAYED_WORK(&edac_dev->work, edac_device_workq_function);
+
+	/* optimize here for the 1 second case, which will be normal value, to
+	 * fire ON the 1 second time event. This helps reduce all sorts of
+	 * timers firing on sub-second basis, while they are happy
+	 * to fire together on the 1 second exactly
+	 */
+	if (edac_dev->poll_msec == 1000)
+		queue_delayed_work(edac_workqueue, &edac_dev->work,
+				round_jiffies(edac_dev->delay));
+	else
+		queue_delayed_work(edac_workqueue, &edac_dev->work,
+				edac_dev->delay);
+}
+
+/*
+ * edac_device_workq_teardown
+ *	stop the workq processing on this edac_dev
+ */
+void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
+{
+	int status;
+
+	status = cancel_delayed_work(&edac_dev->work);
+	if (status == 0) {
+		/* workq instance might be running, wait for it */
+		flush_workqueue(edac_workqueue);
+	}
+}
+
+/*
+ * edac_device_reset_delay_period
+ *
+ *	need to stop any outstanding workq queued up at this time
+ *	because we will be resetting the sleep time.
+ *	Then restart the workq on the new delay
+ */
+void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev,
+					unsigned long value)
+{
+	/* cancel the current workq request, without the mutex lock */
+	edac_device_workq_teardown(edac_dev);
+
+	/* acquire the mutex before doing the workq setup */
+	mutex_lock(&device_ctls_mutex);
+
+	/* restart the workq request, with new delay value */
+	edac_device_workq_setup(edac_dev, value);
+
+	mutex_unlock(&device_ctls_mutex);
+}
+
+/**
+ * edac_device_add_device: Insert the 'edac_dev' structure into the
+ * edac_device global list and create sysfs entries associated with
+ * edac_device structure.
+ * @edac_device: pointer to the edac_device structure to be added to the list
+ * 'edac_device' structure.
+ *
+ * Return:
+ *	0	Success
+ *	!0	Failure
+ */
+int edac_device_add_device(struct edac_device_ctl_info *edac_dev)
+{
+	debugf0("%s()\n", __func__);
+
+#ifdef CONFIG_EDAC_DEBUG
+	if (edac_debug_level >= 3)
+		edac_device_dump_device(edac_dev);
+#endif
+	mutex_lock(&device_ctls_mutex);
+
+	if (add_edac_dev_to_global_list(edac_dev))
+		goto fail0;
+
+	/* set load time so that error rate can be tracked */
+	edac_dev->start_time = jiffies;
+
+	/* create this instance's sysfs entries */
+	if (edac_device_create_sysfs(edac_dev)) {
+		edac_device_printk(edac_dev, KERN_WARNING,
+					"failed to create sysfs device\n");
+		goto fail1;
+	}
+
+	/* If there IS a check routine, then we are running POLLED */
+	if (edac_dev->edac_check != NULL) {
+		/* This instance is NOW RUNNING */
+		edac_dev->op_state = OP_RUNNING_POLL;
+
+		/*
+		 * enable workq processing on this instance,
+		 * default = 1000 msec
+		 */
+		edac_device_workq_setup(edac_dev, 1000);
+	} else {
+		edac_dev->op_state = OP_RUNNING_INTERRUPT;
+	}
+
+	/* Report action taken */
+	edac_device_printk(edac_dev, KERN_INFO,
+				"Giving out device to module '%s' controller "
+				"'%s': DEV '%s' (%s)\n",
+				edac_dev->mod_name,
+				edac_dev->ctl_name,
+				dev_name(edac_dev),
+				edac_op_state_to_string(edac_dev->op_state));
+
+	mutex_unlock(&device_ctls_mutex);
+	return 0;
+
+fail1:
+	/* Some error, so remove the entry from the lsit */
+	del_edac_device_from_global_list(edac_dev);
+
+fail0:
+	mutex_unlock(&device_ctls_mutex);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(edac_device_add_device);
+
+/**
+ * edac_device_del_device:
+ *	Remove sysfs entries for specified edac_device structure and
+ *	then remove edac_device structure from global list
+ *
+ * @pdev:
+ *	Pointer to 'struct device' representing edac_device
+ *	structure to remove.
+ *
+ * Return:
+ *	Pointer to removed edac_device structure,
+ *	OR NULL if device not found.
+ */
+struct edac_device_ctl_info *edac_device_del_device(struct device *dev)
+{
+	struct edac_device_ctl_info *edac_dev;
+
+	debugf0("%s()\n", __func__);
+
+	mutex_lock(&device_ctls_mutex);
+
+	/* Find the structure on the list, if not there, then leave */
+	edac_dev = find_edac_device_by_dev(dev);
+	if (edac_dev == NULL) {
+		mutex_unlock(&device_ctls_mutex);
+		return NULL;
+	}
+
+	/* mark this instance as OFFLINE */
+	edac_dev->op_state = OP_OFFLINE;
+
+	/* clear workq processing on this instance */
+	edac_device_workq_teardown(edac_dev);
+
+	/* deregister from global list */
+	del_edac_device_from_global_list(edac_dev);
+
+	mutex_unlock(&device_ctls_mutex);
+
+	/* Tear down the sysfs entries for this instance */
+	edac_device_remove_sysfs(edac_dev);
+
+	edac_printk(KERN_INFO, EDAC_MC,
+		"Removed device %d for %s %s: DEV %s\n",
+		edac_dev->dev_idx,
+		edac_dev->mod_name, edac_dev->ctl_name, dev_name(edac_dev));
+
+	return edac_dev;
+}
+EXPORT_SYMBOL_GPL(edac_device_del_device);
+
+static inline int edac_device_get_log_ce(struct edac_device_ctl_info *edac_dev)
+{
+	return edac_dev->log_ce;
+}
+
+static inline int edac_device_get_log_ue(struct edac_device_ctl_info *edac_dev)
+{
+	return edac_dev->log_ue;
+}
+
+static inline int edac_device_get_panic_on_ue(struct edac_device_ctl_info
+					*edac_dev)
+{
+	return edac_dev->panic_on_ue;
+}
+
+/*
+ * edac_device_handle_ce
+ *	perform a common output and handling of an 'edac_dev' CE event
+ */
+void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev,
+			int inst_nr, int block_nr, const char *msg)
+{
+	struct edac_device_instance *instance;
+	struct edac_device_block *block = NULL;
+
+	if ((inst_nr >= edac_dev->nr_instances) || (inst_nr < 0)) {
+		edac_device_printk(edac_dev, KERN_ERR,
+				"INTERNAL ERROR: 'instance' out of range "
+				"(%d >= %d)\n", inst_nr,
+				edac_dev->nr_instances);
+		return;
+	}
+
+	instance = edac_dev->instances + inst_nr;
+
+	if ((block_nr >= instance->nr_blocks) || (block_nr < 0)) {
+		edac_device_printk(edac_dev, KERN_ERR,
+				"INTERNAL ERROR: instance %d 'block' "
+				"out of range (%d >= %d)\n",
+				inst_nr, block_nr,
+				instance->nr_blocks);
+		return;
+	}
+
+	if (instance->nr_blocks > 0) {
+		block = instance->blocks + block_nr;
+		block->counters.ce_count++;
+	}
+
+	/* Propogate the count up the 'totals' tree */
+	instance->counters.ce_count++;
+	edac_dev->counters.ce_count++;
+
+	if (edac_device_get_log_ce(edac_dev))
+		edac_device_printk(edac_dev, KERN_WARNING,
+				"CE: %s instance: %s block: %s '%s'\n",
+				edac_dev->ctl_name, instance->name,
+				block ? block->name : "N/A", msg);
+}
+EXPORT_SYMBOL_GPL(edac_device_handle_ce);
+
+/*
+ * edac_device_handle_ue
+ *	perform a common output and handling of an 'edac_dev' UE event
+ */
+void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev,
+			int inst_nr, int block_nr, const char *msg)
+{
+	struct edac_device_instance *instance;
+	struct edac_device_block *block = NULL;
+
+	if ((inst_nr >= edac_dev->nr_instances) || (inst_nr < 0)) {
+		edac_device_printk(edac_dev, KERN_ERR,
+				"INTERNAL ERROR: 'instance' out of range "
+				"(%d >= %d)\n", inst_nr,
+				edac_dev->nr_instances);
+		return;
+	}
+
+	instance = edac_dev->instances + inst_nr;
+
+	if ((block_nr >= instance->nr_blocks) || (block_nr < 0)) {
+		edac_device_printk(edac_dev, KERN_ERR,
+				"INTERNAL ERROR: instance %d 'block' "
+				"out of range (%d >= %d)\n",
+				inst_nr, block_nr,
+				instance->nr_blocks);
+		return;
+	}
+
+	if (instance->nr_blocks > 0) {
+		block = instance->blocks + block_nr;
+		block->counters.ue_count++;
+	}
+
+	/* Propogate the count up the 'totals' tree */
+	instance->counters.ue_count++;
+	edac_dev->counters.ue_count++;
+
+	if (edac_device_get_log_ue(edac_dev))
+		edac_device_printk(edac_dev, KERN_EMERG,
+				"UE: %s instance: %s block: %s '%s'\n",
+				edac_dev->ctl_name, instance->name,
+				block ? block->name : "N/A", msg);
+
+	if (edac_device_get_panic_on_ue(edac_dev))
+		panic("EDAC %s: UE instance: %s block %s '%s'\n",
+			edac_dev->ctl_name, instance->name,
+			block ? block->name : "N/A", msg);
+}
+EXPORT_SYMBOL_GPL(edac_device_handle_ue);
diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c
new file mode 100644
index 0000000..70b837f
--- /dev/null
+++ b/drivers/edac/edac_device_sysfs.c
@@ -0,0 +1,896 @@
+/*
+ * file for managing the edac_device class of devices for EDAC
+ *
+ * (C) 2007 SoftwareBitMaker (http://www.softwarebitmaker.com)
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written Doug Thompson <norsk5@xmission.com>
+ *
+ */
+
+#include <linux/ctype.h>
+#include <linux/module.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+#define EDAC_DEVICE_SYMLINK	"device"
+
+#define to_edacdev(k) container_of(k, struct edac_device_ctl_info, kobj)
+#define to_edacdev_attr(a) container_of(a, struct edacdev_attribute, attr)
+
+
+/*
+ * Set of edac_device_ctl_info attribute store/show functions
+ */
+
+/* 'log_ue' */
+static ssize_t edac_device_ctl_log_ue_show(struct edac_device_ctl_info
+					*ctl_info, char *data)
+{
+	return sprintf(data, "%u\n", ctl_info->log_ue);
+}
+
+static ssize_t edac_device_ctl_log_ue_store(struct edac_device_ctl_info
+					*ctl_info, const char *data,
+					size_t count)
+{
+	/* if parameter is zero, turn off flag, if non-zero turn on flag */
+	ctl_info->log_ue = (simple_strtoul(data, NULL, 0) != 0);
+
+	return count;
+}
+
+/* 'log_ce' */
+static ssize_t edac_device_ctl_log_ce_show(struct edac_device_ctl_info
+					*ctl_info, char *data)
+{
+	return sprintf(data, "%u\n", ctl_info->log_ce);
+}
+
+static ssize_t edac_device_ctl_log_ce_store(struct edac_device_ctl_info
+					*ctl_info, const char *data,
+					size_t count)
+{
+	/* if parameter is zero, turn off flag, if non-zero turn on flag */
+	ctl_info->log_ce = (simple_strtoul(data, NULL, 0) != 0);
+
+	return count;
+}
+
+/* 'panic_on_ue' */
+static ssize_t edac_device_ctl_panic_on_ue_show(struct edac_device_ctl_info
+						*ctl_info, char *data)
+{
+	return sprintf(data, "%u\n", ctl_info->panic_on_ue);
+}
+
+static ssize_t edac_device_ctl_panic_on_ue_store(struct edac_device_ctl_info
+						 *ctl_info, const char *data,
+						 size_t count)
+{
+	/* if parameter is zero, turn off flag, if non-zero turn on flag */
+	ctl_info->panic_on_ue = (simple_strtoul(data, NULL, 0) != 0);
+
+	return count;
+}
+
+/* 'poll_msec' show and store functions*/
+static ssize_t edac_device_ctl_poll_msec_show(struct edac_device_ctl_info
+					*ctl_info, char *data)
+{
+	return sprintf(data, "%u\n", ctl_info->poll_msec);
+}
+
+static ssize_t edac_device_ctl_poll_msec_store(struct edac_device_ctl_info
+					*ctl_info, const char *data,
+					size_t count)
+{
+	unsigned long value;
+
+	/* get the value and enforce that it is non-zero, must be at least
+	 * one millisecond for the delay period, between scans
+	 * Then cancel last outstanding delay for the work request
+	 * and set a new one.
+	 */
+	value = simple_strtoul(data, NULL, 0);
+	edac_device_reset_delay_period(ctl_info, value);
+
+	return count;
+}
+
+/* edac_device_ctl_info specific attribute structure */
+struct ctl_info_attribute {
+	struct attribute attr;
+	ssize_t(*show) (struct edac_device_ctl_info *, char *);
+	ssize_t(*store) (struct edac_device_ctl_info *, const char *, size_t);
+};
+
+#define to_ctl_info(k) container_of(k, struct edac_device_ctl_info, kobj)
+#define to_ctl_info_attr(a) container_of(a,struct ctl_info_attribute,attr)
+
+/* Function to 'show' fields from the edac_dev 'ctl_info' structure */
+static ssize_t edac_dev_ctl_info_show(struct kobject *kobj,
+				struct attribute *attr, char *buffer)
+{
+	struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj);
+	struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr);
+
+	if (ctl_info_attr->show)
+		return ctl_info_attr->show(edac_dev, buffer);
+	return -EIO;
+}
+
+/* Function to 'store' fields into the edac_dev 'ctl_info' structure */
+static ssize_t edac_dev_ctl_info_store(struct kobject *kobj,
+				struct attribute *attr,
+				const char *buffer, size_t count)
+{
+	struct edac_device_ctl_info *edac_dev = to_ctl_info(kobj);
+	struct ctl_info_attribute *ctl_info_attr = to_ctl_info_attr(attr);
+
+	if (ctl_info_attr->store)
+		return ctl_info_attr->store(edac_dev, buffer, count);
+	return -EIO;
+}
+
+/* edac_dev file operations for an 'ctl_info' */
+static struct sysfs_ops device_ctl_info_ops = {
+	.show = edac_dev_ctl_info_show,
+	.store = edac_dev_ctl_info_store
+};
+
+#define CTL_INFO_ATTR(_name,_mode,_show,_store)        \
+static struct ctl_info_attribute attr_ctl_info_##_name = {      \
+	.attr = {.name = __stringify(_name), .mode = _mode },   \
+	.show   = _show,                                        \
+	.store  = _store,                                       \
+};
+
+/* Declare the various ctl_info attributes here and their respective ops */
+CTL_INFO_ATTR(log_ue, S_IRUGO | S_IWUSR,
+	edac_device_ctl_log_ue_show, edac_device_ctl_log_ue_store);
+CTL_INFO_ATTR(log_ce, S_IRUGO | S_IWUSR,
+	edac_device_ctl_log_ce_show, edac_device_ctl_log_ce_store);
+CTL_INFO_ATTR(panic_on_ue, S_IRUGO | S_IWUSR,
+	edac_device_ctl_panic_on_ue_show,
+	edac_device_ctl_panic_on_ue_store);
+CTL_INFO_ATTR(poll_msec, S_IRUGO | S_IWUSR,
+	edac_device_ctl_poll_msec_show, edac_device_ctl_poll_msec_store);
+
+/* Base Attributes of the EDAC_DEVICE ECC object */
+static struct ctl_info_attribute *device_ctrl_attr[] = {
+	&attr_ctl_info_panic_on_ue,
+	&attr_ctl_info_log_ue,
+	&attr_ctl_info_log_ce,
+	&attr_ctl_info_poll_msec,
+	NULL,
+};
+
+/*
+ * edac_device_ctrl_master_release
+ *
+ *	called when the reference count for the 'main' kobj
+ *	for a edac_device control struct reaches zero
+ *
+ *	Reference count model:
+ *		One 'main' kobject for each control structure allocated.
+ *		That main kobj is initially set to one AND
+ *		the reference count for the EDAC 'core' module is
+ *		bumped by one, thus added 'keep in memory' dependency.
+ *
+ *		Each new internal kobj (in instances and blocks) then
+ *		bumps the 'main' kobject.
+ *
+ *		When they are released their release functions decrement
+ *		the 'main' kobj.
+ *
+ *		When the main kobj reaches zero (0) then THIS function
+ *		is called which then decrements the EDAC 'core' module.
+ *		When the module reference count reaches zero then the
+ *		module no longer has dependency on keeping the release
+ *		function code in memory and module can be unloaded.
+ *
+ *		This will support several control objects as well, each
+ *		with its own 'main' kobj.
+ */
+static void edac_device_ctrl_master_release(struct kobject *kobj)
+{
+	struct edac_device_ctl_info *edac_dev = to_edacdev(kobj);
+
+	debugf4("%s() control index=%d\n", __func__, edac_dev->dev_idx);
+
+	/* decrement the EDAC CORE module ref count */
+	module_put(edac_dev->owner);
+
+	/* free the control struct containing the 'main' kobj
+	 * passed in to this routine
+	 */
+	kfree(edac_dev);
+}
+
+/* ktype for the main (master) kobject */
+static struct kobj_type ktype_device_ctrl = {
+	.release = edac_device_ctrl_master_release,
+	.sysfs_ops = &device_ctl_info_ops,
+	.default_attrs = (struct attribute **)device_ctrl_attr,
+};
+
+/*
+ * edac_device_register_sysfs_main_kobj
+ *
+ *	perform the high level setup for the new edac_device instance
+ *
+ * Return:  0 SUCCESS
+ *         !0 FAILURE
+ */
+int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
+{
+	struct sysdev_class *edac_class;
+	int err;
+
+	debugf1("%s()\n", __func__);
+
+	/* get the /sys/devices/system/edac reference */
+	edac_class = edac_get_edac_class();
+	if (edac_class == NULL) {
+		debugf1("%s() no edac_class error\n", __func__);
+		err = -ENODEV;
+		goto err_out;
+	}
+
+	/* Point to the 'edac_class' this instance 'reports' to */
+	edac_dev->edac_class = edac_class;
+
+	/* Init the devices's kobject */
+	memset(&edac_dev->kobj, 0, sizeof(struct kobject));
+	edac_dev->kobj.ktype = &ktype_device_ctrl;
+
+	/* set this new device under the edac_class kobject */
+	edac_dev->kobj.parent = &edac_class->kset.kobj;
+
+	/* generate sysfs "..../edac/<name>"   */
+	debugf4("%s() set name of kobject to: %s\n", __func__, edac_dev->name);
+	err = kobject_set_name(&edac_dev->kobj, "%s", edac_dev->name);
+	if (err)
+		goto err_out;
+
+	/* Record which module 'owns' this control structure
+	 * and bump the ref count of the module
+	 */
+	edac_dev->owner = THIS_MODULE;
+
+	if (!try_module_get(edac_dev->owner)) {
+		err = -ENODEV;
+		goto err_out;
+	}
+
+	/* register */
+	err = kobject_register(&edac_dev->kobj);
+	if (err) {
+		debugf1("%s()Failed to register '.../edac/%s'\n",
+			__func__, edac_dev->name);
+		goto err_kobj_reg;
+	}
+
+	/* At this point, to 'free' the control struct,
+	 * edac_device_unregister_sysfs_main_kobj() must be used
+	 */
+
+	debugf4("%s() Registered '.../edac/%s' kobject\n",
+		__func__, edac_dev->name);
+
+	return 0;
+
+	/* Error exit stack */
+err_kobj_reg:
+	module_put(edac_dev->owner);
+
+err_out:
+	return err;
+}
+
+/*
+ * edac_device_unregister_sysfs_main_kobj:
+ *	the '..../edac/<name>' kobject
+ */
+void edac_device_unregister_sysfs_main_kobj(
+					struct edac_device_ctl_info *edac_dev)
+{
+	debugf0("%s()\n", __func__);
+	debugf4("%s() name of kobject is: %s\n",
+		__func__, kobject_name(&edac_dev->kobj));
+
+	/*
+	 * Unregister the edac device's kobject and
+	 * allow for reference count to reach 0 at which point
+	 * the callback will be called to:
+	 *   a) module_put() this module
+	 *   b) 'kfree' the memory
+	 */
+	kobject_unregister(&edac_dev->kobj);
+}
+
+/* edac_dev -> instance information */
+
+/*
+ * Set of low-level instance attribute show functions
+ */
+static ssize_t instance_ue_count_show(struct edac_device_instance *instance,
+				char *data)
+{
+	return sprintf(data, "%u\n", instance->counters.ue_count);
+}
+
+static ssize_t instance_ce_count_show(struct edac_device_instance *instance,
+				char *data)
+{
+	return sprintf(data, "%u\n", instance->counters.ce_count);
+}
+
+#define to_instance(k) container_of(k, struct edac_device_instance, kobj)
+#define to_instance_attr(a) container_of(a,struct instance_attribute,attr)
+
+/* DEVICE instance kobject release() function */
+static void edac_device_ctrl_instance_release(struct kobject *kobj)
+{
+	struct edac_device_instance *instance;
+
+	debugf1("%s()\n", __func__);
+
+	/* map from this kobj to the main control struct
+	 * and then dec the main kobj count
+	 */
+	instance = to_instance(kobj);
+	kobject_put(&instance->ctl->kobj);
+}
+
+/* instance specific attribute structure */
+struct instance_attribute {
+	struct attribute attr;
+	ssize_t(*show) (struct edac_device_instance *, char *);
+	ssize_t(*store) (struct edac_device_instance *, const char *, size_t);
+};
+
+/* Function to 'show' fields from the edac_dev 'instance' structure */
+static ssize_t edac_dev_instance_show(struct kobject *kobj,
+				struct attribute *attr, char *buffer)
+{
+	struct edac_device_instance *instance = to_instance(kobj);
+	struct instance_attribute *instance_attr = to_instance_attr(attr);
+
+	if (instance_attr->show)
+		return instance_attr->show(instance, buffer);
+	return -EIO;
+}
+
+/* Function to 'store' fields into the edac_dev 'instance' structure */
+static ssize_t edac_dev_instance_store(struct kobject *kobj,
+				struct attribute *attr,
+				const char *buffer, size_t count)
+{
+	struct edac_device_instance *instance = to_instance(kobj);
+	struct instance_attribute *instance_attr = to_instance_attr(attr);
+
+	if (instance_attr->store)
+		return instance_attr->store(instance, buffer, count);
+	return -EIO;
+}
+
+/* edac_dev file operations for an 'instance' */
+static struct sysfs_ops device_instance_ops = {
+	.show = edac_dev_instance_show,
+	.store = edac_dev_instance_store
+};
+
+#define INSTANCE_ATTR(_name,_mode,_show,_store)        \
+static struct instance_attribute attr_instance_##_name = {      \
+	.attr = {.name = __stringify(_name), .mode = _mode },   \
+	.show   = _show,                                        \
+	.store  = _store,                                       \
+};
+
+/*
+ * Define attributes visible for the edac_device instance object
+ *	Each contains a pointer to a show and an optional set
+ *	function pointer that does the low level output/input
+ */
+INSTANCE_ATTR(ce_count, S_IRUGO, instance_ce_count_show, NULL);
+INSTANCE_ATTR(ue_count, S_IRUGO, instance_ue_count_show, NULL);
+
+/* list of edac_dev 'instance' attributes */
+static struct instance_attribute *device_instance_attr[] = {
+	&attr_instance_ce_count,
+	&attr_instance_ue_count,
+	NULL,
+};
+
+/* The 'ktype' for each edac_dev 'instance' */
+static struct kobj_type ktype_instance_ctrl = {
+	.release = edac_device_ctrl_instance_release,
+	.sysfs_ops = &device_instance_ops,
+	.default_attrs = (struct attribute **)device_instance_attr,
+};
+
+/* edac_dev -> instance -> block information */
+
+#define to_block(k) container_of(k, struct edac_device_block, kobj)
+#define to_block_attr(a) \
+	container_of(a, struct edac_dev_sysfs_block_attribute, attr)
+
+/*
+ * Set of low-level block attribute show functions
+ */
+static ssize_t block_ue_count_show(struct kobject *kobj,
+					struct attribute *attr, char *data)
+{
+	struct edac_device_block *block = to_block(kobj);
+
+	return sprintf(data, "%u\n", block->counters.ue_count);
+}
+
+static ssize_t block_ce_count_show(struct kobject *kobj,
+					struct attribute *attr, char *data)
+{
+	struct edac_device_block *block = to_block(kobj);
+
+	return sprintf(data, "%u\n", block->counters.ce_count);
+}
+
+/* DEVICE block kobject release() function */
+static void edac_device_ctrl_block_release(struct kobject *kobj)
+{
+	struct edac_device_block *block;
+
+	debugf1("%s()\n", __func__);
+
+	/* get the container of the kobj */
+	block = to_block(kobj);
+
+	/* map from 'block kobj' to 'block->instance->controller->main_kobj'
+	 * now 'release' the block kobject
+	 */
+	kobject_put(&block->instance->ctl->kobj);
+}
+
+
+/* Function to 'show' fields from the edac_dev 'block' structure */
+static ssize_t edac_dev_block_show(struct kobject *kobj,
+				struct attribute *attr, char *buffer)
+{
+	struct edac_dev_sysfs_block_attribute *block_attr =
+						to_block_attr(attr);
+
+	if (block_attr->show)
+		return block_attr->show(kobj, attr, buffer);
+	return -EIO;
+}
+
+/* Function to 'store' fields into the edac_dev 'block' structure */
+static ssize_t edac_dev_block_store(struct kobject *kobj,
+				struct attribute *attr,
+				const char *buffer, size_t count)
+{
+	struct edac_dev_sysfs_block_attribute *block_attr;
+
+	block_attr = to_block_attr(attr);
+
+	if (block_attr->store)
+		return block_attr->store(kobj, attr, buffer, count);
+	return -EIO;
+}
+
+/* edac_dev file operations for a 'block' */
+static struct sysfs_ops device_block_ops = {
+	.show = edac_dev_block_show,
+	.store = edac_dev_block_store
+};
+
+#define BLOCK_ATTR(_name,_mode,_show,_store)        \
+static struct edac_dev_sysfs_block_attribute attr_block_##_name = {	\
+	.attr = {.name = __stringify(_name), .mode = _mode },   \
+	.show   = _show,                                        \
+	.store  = _store,                                       \
+};
+
+BLOCK_ATTR(ce_count, S_IRUGO, block_ce_count_show, NULL);
+BLOCK_ATTR(ue_count, S_IRUGO, block_ue_count_show, NULL);
+
+/* list of edac_dev 'block' attributes */
+static struct edac_dev_sysfs_block_attribute *device_block_attr[] = {
+	&attr_block_ce_count,
+	&attr_block_ue_count,
+	NULL,
+};
+
+/* The 'ktype' for each edac_dev 'block' */
+static struct kobj_type ktype_block_ctrl = {
+	.release = edac_device_ctrl_block_release,
+	.sysfs_ops = &device_block_ops,
+	.default_attrs = (struct attribute **)device_block_attr,
+};
+
+/* block ctor/dtor  code */
+
+/*
+ * edac_device_create_block
+ */
+static int edac_device_create_block(struct edac_device_ctl_info *edac_dev,
+				struct edac_device_instance *instance,
+				struct edac_device_block *block)
+{
+	int i;
+	int err;
+	struct edac_dev_sysfs_block_attribute *sysfs_attrib;
+	struct kobject *main_kobj;
+
+	debugf4("%s() Instance '%s' inst_p=%p  block '%s'  block_p=%p\n",
+		__func__, instance->name, instance, block->name, block);
+	debugf4("%s() block kobj=%p  block kobj->parent=%p\n",
+		__func__, &block->kobj, &block->kobj.parent);
+
+	/* init this block's kobject */
+	memset(&block->kobj, 0, sizeof(struct kobject));
+	block->kobj.parent = &instance->kobj;
+	block->kobj.ktype = &ktype_block_ctrl;
+
+	err = kobject_set_name(&block->kobj, "%s", block->name);
+	if (err)
+		return err;
+
+	/* bump the main kobject's reference count for this controller
+	 * and this instance is dependant on the main
+	 */
+	main_kobj = kobject_get(&edac_dev->kobj);
+	if (!main_kobj) {
+		err = -ENODEV;
+		goto err_out;
+	}
+
+	/* Add this block's kobject */
+	err = kobject_register(&block->kobj);
+	if (err) {
+		debugf1("%s() Failed to register instance '%s'\n",
+			__func__, block->name);
+		kobject_put(main_kobj);
+		err = -ENODEV;
+		goto err_out;
+	}
+
+	/* If there are driver level block attributes, then added them
+	 * to the block kobject
+	 */
+	sysfs_attrib = block->block_attributes;
+	if (sysfs_attrib && block->nr_attribs) {
+		for (i = 0; i < block->nr_attribs; i++, sysfs_attrib++) {
+
+			debugf4("%s() creating block attrib='%s' "
+				"attrib->%p to kobj=%p\n",
+				__func__,
+				sysfs_attrib->attr.name,
+				sysfs_attrib, &block->kobj);
+
+			/* Create each block_attribute file */
+			err = sysfs_create_file(&block->kobj,
+				&sysfs_attrib->attr);
+			if (err)
+				goto err_on_attrib;
+		}
+	}
+
+	return 0;
+
+	/* Error unwind stack */
+err_on_attrib:
+	kobject_unregister(&block->kobj);
+
+err_out:
+	return err;
+}
+
+/*
+ * edac_device_delete_block(edac_dev,block);
+ */
+static void edac_device_delete_block(struct edac_device_ctl_info *edac_dev,
+				struct edac_device_block *block)
+{
+	struct edac_dev_sysfs_block_attribute *sysfs_attrib;
+	int i;
+
+	/* if this block has 'attributes' then we need to iterate over the list
+	 * and 'remove' the attributes on this block
+	 */
+	sysfs_attrib = block->block_attributes;
+	if (sysfs_attrib && block->nr_attribs) {
+		for (i = 0; i < block->nr_attribs; i++, sysfs_attrib++) {
+
+			/* remove each block_attrib file */
+			sysfs_remove_file(&block->kobj,
+				(struct attribute *) sysfs_attrib);
+		}
+	}
+
+	/* unregister this block's kobject, SEE:
+	 *	edac_device_ctrl_block_release() callback operation
+	 */
+	kobject_unregister(&block->kobj);
+}
+
+/* instance ctor/dtor code */
+
+/*
+ * edac_device_create_instance
+ *	create just one instance of an edac_device 'instance'
+ */
+static int edac_device_create_instance(struct edac_device_ctl_info *edac_dev,
+				int idx)
+{
+	int i, j;
+	int err;
+	struct edac_device_instance *instance;
+	struct kobject *main_kobj;
+
+	instance = &edac_dev->instances[idx];
+
+	/* Init the instance's kobject */
+	memset(&instance->kobj, 0, sizeof(struct kobject));
+
+	/* set this new device under the edac_device main kobject */
+	instance->kobj.parent = &edac_dev->kobj;
+	instance->kobj.ktype = &ktype_instance_ctrl;
+	instance->ctl = edac_dev;
+
+	err = kobject_set_name(&instance->kobj, "%s", instance->name);
+	if (err)
+		goto err_out;
+
+	/* bump the main kobject's reference count for this controller
+	 * and this instance is dependant on the main
+	 */
+	main_kobj = kobject_get(&edac_dev->kobj);
+	if (!main_kobj) {
+		err = -ENODEV;
+		goto err_out;
+	}
+
+	/* Formally register this instance's kobject */
+	err = kobject_register(&instance->kobj);
+	if (err != 0) {
+		debugf2("%s() Failed to register instance '%s'\n",
+			__func__, instance->name);
+		kobject_put(main_kobj);
+		goto err_out;
+	}
+
+	debugf4("%s() now register '%d' blocks for instance %d\n",
+		__func__, instance->nr_blocks, idx);
+
+	/* register all blocks of this instance */
+	for (i = 0; i < instance->nr_blocks; i++) {
+		err = edac_device_create_block(edac_dev, instance,
+						&instance->blocks[i]);
+		if (err) {
+			/* If any fail, remove all previous ones */
+			for (j = 0; j < i; j++)
+				edac_device_delete_block(edac_dev,
+							&instance->blocks[j]);
+			goto err_release_instance_kobj;
+		}
+	}
+
+	debugf4("%s() Registered instance %d '%s' kobject\n",
+		__func__, idx, instance->name);
+
+	return 0;
+
+	/* error unwind stack */
+err_release_instance_kobj:
+	kobject_unregister(&instance->kobj);
+
+err_out:
+	return err;
+}
+
+/*
+ * edac_device_remove_instance
+ *	remove an edac_device instance
+ */
+static void edac_device_delete_instance(struct edac_device_ctl_info *edac_dev,
+					int idx)
+{
+	struct edac_device_instance *instance;
+	int i;
+
+	instance = &edac_dev->instances[idx];
+
+	/* unregister all blocks in this instance */
+	for (i = 0; i < instance->nr_blocks; i++)
+		edac_device_delete_block(edac_dev, &instance->blocks[i]);
+
+	/* unregister this instance's kobject, SEE:
+	 *	edac_device_ctrl_instance_release() for callback operation
+	 */
+	kobject_unregister(&instance->kobj);
+}
+
+/*
+ * edac_device_create_instances
+ *	create the first level of 'instances' for this device
+ *	(ie  'cache' might have 'cache0', 'cache1', 'cache2', etc
+ */
+static int edac_device_create_instances(struct edac_device_ctl_info *edac_dev)
+{
+	int i, j;
+	int err;
+
+	debugf0("%s()\n", __func__);
+
+	/* iterate over creation of the instances */
+	for (i = 0; i < edac_dev->nr_instances; i++) {
+		err = edac_device_create_instance(edac_dev, i);
+		if (err) {
+			/* unwind previous instances on error */
+			for (j = 0; j < i; j++)
+				edac_device_delete_instance(edac_dev, j);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * edac_device_delete_instances(edac_dev);
+ *	unregister all the kobjects of the instances
+ */
+static void edac_device_delete_instances(struct edac_device_ctl_info *edac_dev)
+{
+	int i;
+
+	/* iterate over creation of the instances */
+	for (i = 0; i < edac_dev->nr_instances; i++)
+		edac_device_delete_instance(edac_dev, i);
+}
+
+/* edac_dev sysfs ctor/dtor  code */
+
+/*
+ * edac_device_add_main_sysfs_attributes
+ *	add some attributes to this instance's main kobject
+ */
+static int edac_device_add_main_sysfs_attributes(
+			struct edac_device_ctl_info *edac_dev)
+{
+	struct edac_dev_sysfs_attribute *sysfs_attrib;
+	int err = 0;
+
+	sysfs_attrib = edac_dev->sysfs_attributes;
+	if (sysfs_attrib) {
+		/* iterate over the array and create an attribute for each
+		 * entry in the list
+		 */
+		while (sysfs_attrib->attr.name != NULL) {
+			err = sysfs_create_file(&edac_dev->kobj,
+				(struct attribute*) sysfs_attrib);
+			if (err)
+				goto err_out;
+
+			sysfs_attrib++;
+		}
+	}
+
+err_out:
+	return err;
+}
+
+/*
+ * edac_device_remove_main_sysfs_attributes
+ *	remove any attributes to this instance's main kobject
+ */
+static void edac_device_remove_main_sysfs_attributes(
+			struct edac_device_ctl_info *edac_dev)
+{
+	struct edac_dev_sysfs_attribute *sysfs_attrib;
+
+	/* if there are main attributes, defined, remove them. First,
+	 * point to the start of the array and iterate over it
+	 * removing each attribute listed from this device's instance's kobject
+	 */
+	sysfs_attrib = edac_dev->sysfs_attributes;
+	if (sysfs_attrib) {
+		while (sysfs_attrib->attr.name != NULL) {
+			sysfs_remove_file(&edac_dev->kobj,
+					(struct attribute *) sysfs_attrib);
+			sysfs_attrib++;
+		}
+	}
+}
+
+/*
+ * edac_device_create_sysfs() Constructor
+ *
+ * accept a created edac_device control structure
+ * and 'export' it to sysfs. The 'main' kobj should already have been
+ * created. 'instance' and 'block' kobjects should be registered
+ * along with any 'block' attributes from the low driver. In addition,
+ * the main attributes (if any) are connected to the main kobject of
+ * the control structure.
+ *
+ * Return:
+ *	0	Success
+ *	!0	Failure
+ */
+int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev)
+{
+	int err;
+	struct kobject *edac_kobj = &edac_dev->kobj;
+
+	debugf0("%s() idx=%d\n", __func__, edac_dev->dev_idx);
+
+	/*  go create any main attributes callers wants */
+	err = edac_device_add_main_sysfs_attributes(edac_dev);
+	if (err) {
+		debugf0("%s() failed to add sysfs attribs\n", __func__);
+		goto err_out;
+	}
+
+	/* create a symlink from the edac device
+	 * to the platform 'device' being used for this
+	 */
+	err = sysfs_create_link(edac_kobj,
+				&edac_dev->dev->kobj, EDAC_DEVICE_SYMLINK);
+	if (err) {
+		debugf0("%s() sysfs_create_link() returned err= %d\n",
+			__func__, err);
+		goto err_remove_main_attribs;
+	}
+
+	/* Create the first level instance directories
+	 * In turn, the nested blocks beneath the instances will
+	 * be registered as well
+	 */
+	err = edac_device_create_instances(edac_dev);
+	if (err) {
+		debugf0("%s() edac_device_create_instances() "
+			"returned err= %d\n", __func__, err);
+		goto err_remove_link;
+	}
+
+
+	debugf4("%s() create-instances done, idx=%d\n",
+		__func__, edac_dev->dev_idx);
+
+	return 0;
+
+	/* Error unwind stack */
+err_remove_link:
+	/* remove the sym link */
+	sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK);
+
+err_remove_main_attribs:
+	edac_device_remove_main_sysfs_attributes(edac_dev);
+
+err_out:
+	return err;
+}
+
+/*
+ * edac_device_remove_sysfs() destructor
+ *
+ * given an edac_device struct, tear down the kobject resources
+ */
+void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev)
+{
+	debugf0("%s()\n", __func__);
+
+	/* remove any main attributes for this device */
+	edac_device_remove_main_sysfs_attributes(edac_dev);
+
+	/* remove the device sym link */
+	sysfs_remove_link(&edac_dev->kobj, EDAC_DEVICE_SYMLINK);
+
+	/* walk the instance/block kobject tree, deconstructing it */
+	edac_device_delete_instances(edac_dev);
+}
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 804875d..063a1bf 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -27,1200 +27,20 @@
 #include <linux/list.h>
 #include <linux/sysdev.h>
 #include <linux/ctype.h>
-#include <linux/kthread.h>
-#include <linux/freezer.h>
+#include <linux/edac.h>
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <asm/edac.h>
-#include "edac_mc.h"
-
-#define EDAC_MC_VERSION "Ver: 2.0.1 " __DATE__
-
-
-#ifdef CONFIG_EDAC_DEBUG
-/* Values of 0 to 4 will generate output */
-int edac_debug_level = 1;
-EXPORT_SYMBOL_GPL(edac_debug_level);
-#endif
-
-/* EDAC Controls, setable by module parameter, and sysfs */
-static int log_ue = 1;
-static int log_ce = 1;
-static int panic_on_ue;
-static int poll_msec = 1000;
+#include "edac_core.h"
+#include "edac_module.h"
 
 /* lock to memory controller's control array */
-static DECLARE_MUTEX(mem_ctls_mutex);
+static DEFINE_MUTEX(mem_ctls_mutex);
 static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices);
 
-static struct task_struct *edac_thread;
-
-#ifdef CONFIG_PCI
-static int check_pci_parity = 0;	/* default YES check PCI parity */
-static int panic_on_pci_parity;		/* default no panic on PCI Parity */
-static atomic_t pci_parity_count = ATOMIC_INIT(0);
-
-static struct kobject edac_pci_kobj; /* /sys/devices/system/edac/pci */
-static struct completion edac_pci_kobj_complete;
-#endif	/* CONFIG_PCI */
-
-/*  START sysfs data and methods */
-
-
-static const char *mem_types[] = {
-	[MEM_EMPTY] = "Empty",
-	[MEM_RESERVED] = "Reserved",
-	[MEM_UNKNOWN] = "Unknown",
-	[MEM_FPM] = "FPM",
-	[MEM_EDO] = "EDO",
-	[MEM_BEDO] = "BEDO",
-	[MEM_SDR] = "Unbuffered-SDR",
-	[MEM_RDR] = "Registered-SDR",
-	[MEM_DDR] = "Unbuffered-DDR",
-	[MEM_RDDR] = "Registered-DDR",
-	[MEM_RMBS] = "RMBS"
-};
-
-static const char *dev_types[] = {
-	[DEV_UNKNOWN] = "Unknown",
-	[DEV_X1] = "x1",
-	[DEV_X2] = "x2",
-	[DEV_X4] = "x4",
-	[DEV_X8] = "x8",
-	[DEV_X16] = "x16",
-	[DEV_X32] = "x32",
-	[DEV_X64] = "x64"
-};
-
-static const char *edac_caps[] = {
-	[EDAC_UNKNOWN] = "Unknown",
-	[EDAC_NONE] = "None",
-	[EDAC_RESERVED] = "Reserved",
-	[EDAC_PARITY] = "PARITY",
-	[EDAC_EC] = "EC",
-	[EDAC_SECDED] = "SECDED",
-	[EDAC_S2ECD2ED] = "S2ECD2ED",
-	[EDAC_S4ECD4ED] = "S4ECD4ED",
-	[EDAC_S8ECD8ED] = "S8ECD8ED",
-	[EDAC_S16ECD16ED] = "S16ECD16ED"
-};
-
-/* sysfs object: /sys/devices/system/edac */
-static struct sysdev_class edac_class = {
-	set_kset_name("edac"),
-};
-
-/* sysfs object:
- *	/sys/devices/system/edac/mc
- */
-static struct kobject edac_memctrl_kobj;
-
-/* We use these to wait for the reference counts on edac_memctrl_kobj and
- * edac_pci_kobj to reach 0.
- */
-static struct completion edac_memctrl_kobj_complete;
-
-/*
- * /sys/devices/system/edac/mc;
- *	data structures and methods
- */
-static ssize_t memctrl_int_show(void *ptr, char *buffer)
-{
-	int *value = (int*) ptr;
-	return sprintf(buffer, "%u\n", *value);
-}
-
-static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count)
-{
-	int *value = (int*) ptr;
-
-	if (isdigit(*buffer))
-		*value = simple_strtoul(buffer, NULL, 0);
-
-	return count;
-}
-
-struct memctrl_dev_attribute {
-	struct attribute attr;
-	void *value;
-	ssize_t (*show)(void *,char *);
-	ssize_t (*store)(void *, const char *, size_t);
-};
-
-/* Set of show/store abstract level functions for memory control object */
-static ssize_t memctrl_dev_show(struct kobject *kobj,
-		struct attribute *attr, char *buffer)
-{
-	struct memctrl_dev_attribute *memctrl_dev;
-	memctrl_dev = (struct memctrl_dev_attribute*)attr;
-
-	if (memctrl_dev->show)
-		return memctrl_dev->show(memctrl_dev->value, buffer);
-
-	return -EIO;
-}
-
-static ssize_t memctrl_dev_store(struct kobject *kobj, struct attribute *attr,
-		const char *buffer, size_t count)
-{
-	struct memctrl_dev_attribute *memctrl_dev;
-	memctrl_dev = (struct memctrl_dev_attribute*)attr;
-
-	if (memctrl_dev->store)
-		return memctrl_dev->store(memctrl_dev->value, buffer, count);
-
-	return -EIO;
-}
-
-static struct sysfs_ops memctrlfs_ops = {
-	.show   = memctrl_dev_show,
-	.store  = memctrl_dev_store
-};
-
-#define MEMCTRL_ATTR(_name,_mode,_show,_store)			\
-struct memctrl_dev_attribute attr_##_name = {			\
-	.attr = {.name = __stringify(_name), .mode = _mode },	\
-	.value  = &_name,					\
-	.show   = _show,					\
-	.store  = _store,					\
-};
-
-#define MEMCTRL_STRING_ATTR(_name,_data,_mode,_show,_store)	\
-struct memctrl_dev_attribute attr_##_name = {			\
-	.attr = {.name = __stringify(_name), .mode = _mode },	\
-	.value  = _data,					\
-	.show   = _show,					\
-	.store  = _store,					\
-};
-
-/* csrow<id> control files */
-MEMCTRL_ATTR(panic_on_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
-MEMCTRL_ATTR(log_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
-MEMCTRL_ATTR(log_ce,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
-MEMCTRL_ATTR(poll_msec,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
-
-/* Base Attributes of the memory ECC object */
-static struct memctrl_dev_attribute *memctrl_attr[] = {
-	&attr_panic_on_ue,
-	&attr_log_ue,
-	&attr_log_ce,
-	&attr_poll_msec,
-	NULL,
-};
-
-/* Main MC kobject release() function */
-static void edac_memctrl_master_release(struct kobject *kobj)
-{
-	debugf1("%s()\n", __func__);
-	complete(&edac_memctrl_kobj_complete);
-}
-
-static struct kobj_type ktype_memctrl = {
-	.release = edac_memctrl_master_release,
-	.sysfs_ops = &memctrlfs_ops,
-	.default_attrs = (struct attribute **) memctrl_attr,
-};
-
-/* Initialize the main sysfs entries for edac:
- *   /sys/devices/system/edac
- *
- * and children
- *
- * Return:  0 SUCCESS
- *         !0 FAILURE
- */
-static int edac_sysfs_memctrl_setup(void)
-{
-	int err = 0;
-
-	debugf1("%s()\n", __func__);
-
-	/* create the /sys/devices/system/edac directory */
-	err = sysdev_class_register(&edac_class);
-
-	if (err) {
-		debugf1("%s() error=%d\n", __func__, err);
-		return err;
-	}
-
-	/* Init the MC's kobject */
-	memset(&edac_memctrl_kobj, 0, sizeof (edac_memctrl_kobj));
-	edac_memctrl_kobj.parent = &edac_class.kset.kobj;
-	edac_memctrl_kobj.ktype = &ktype_memctrl;
-
-	/* generate sysfs "..../edac/mc"   */
-	err = kobject_set_name(&edac_memctrl_kobj,"mc");
-
-	if (err)
-		goto fail;
-
-	/* FIXME: maybe new sysdev_create_subdir() */
-	err = kobject_register(&edac_memctrl_kobj);
-
-	if (err) {
-		debugf1("Failed to register '.../edac/mc'\n");
-		goto fail;
-	}
-
-	debugf1("Registered '.../edac/mc' kobject\n");
-
-	return 0;
-
-fail:
-	sysdev_class_unregister(&edac_class);
-	return err;
-}
-
-/*
- * MC teardown:
- *	the '..../edac/mc' kobject followed by '..../edac' itself
- */
-static void edac_sysfs_memctrl_teardown(void)
-{
-	debugf0("MC: " __FILE__ ": %s()\n", __func__);
-
-	/* Unregister the MC's kobject and wait for reference count to reach
-	 * 0.
-	 */
-	init_completion(&edac_memctrl_kobj_complete);
-	kobject_unregister(&edac_memctrl_kobj);
-	wait_for_completion(&edac_memctrl_kobj_complete);
-
-	/* Unregister the 'edac' object */
-	sysdev_class_unregister(&edac_class);
-}
-
-#ifdef CONFIG_PCI
-static ssize_t edac_pci_int_show(void *ptr, char *buffer)
-{
-	int *value = ptr;
-	return sprintf(buffer,"%d\n",*value);
-}
-
-static ssize_t edac_pci_int_store(void *ptr, const char *buffer, size_t count)
-{
-	int *value = ptr;
-
-	if (isdigit(*buffer))
-		*value = simple_strtoul(buffer,NULL,0);
-
-	return count;
-}
-
-struct edac_pci_dev_attribute {
-	struct attribute attr;
-	void *value;
-	ssize_t (*show)(void *,char *);
-	ssize_t (*store)(void *, const char *,size_t);
-};
-
-/* Set of show/store abstract level functions for PCI Parity object */
-static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr,
-		char *buffer)
-{
-	struct edac_pci_dev_attribute *edac_pci_dev;
-	edac_pci_dev= (struct edac_pci_dev_attribute*)attr;
-
-	if (edac_pci_dev->show)
-		return edac_pci_dev->show(edac_pci_dev->value, buffer);
-	return -EIO;
-}
-
-static ssize_t edac_pci_dev_store(struct kobject *kobj,
-		struct attribute *attr, const char *buffer, size_t count)
-{
-	struct edac_pci_dev_attribute *edac_pci_dev;
-	edac_pci_dev= (struct edac_pci_dev_attribute*)attr;
-
-	if (edac_pci_dev->show)
-		return edac_pci_dev->store(edac_pci_dev->value, buffer, count);
-	return -EIO;
-}
-
-static struct sysfs_ops edac_pci_sysfs_ops = {
-	.show   = edac_pci_dev_show,
-	.store  = edac_pci_dev_store
-};
-
-#define EDAC_PCI_ATTR(_name,_mode,_show,_store)			\
-struct edac_pci_dev_attribute edac_pci_attr_##_name = {		\
-	.attr = {.name = __stringify(_name), .mode = _mode },	\
-	.value  = &_name,					\
-	.show   = _show,					\
-	.store  = _store,					\
-};
-
-#define EDAC_PCI_STRING_ATTR(_name,_data,_mode,_show,_store)	\
-struct edac_pci_dev_attribute edac_pci_attr_##_name = {		\
-	.attr = {.name = __stringify(_name), .mode = _mode },	\
-	.value  = _data,					\
-	.show   = _show,					\
-	.store  = _store,					\
-};
-
-/* PCI Parity control files */
-EDAC_PCI_ATTR(check_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show,
-	edac_pci_int_store);
-EDAC_PCI_ATTR(panic_on_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show,
-	edac_pci_int_store);
-EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL);
-
-/* Base Attributes of the memory ECC object */
-static struct edac_pci_dev_attribute *edac_pci_attr[] = {
-	&edac_pci_attr_check_pci_parity,
-	&edac_pci_attr_panic_on_pci_parity,
-	&edac_pci_attr_pci_parity_count,
-	NULL,
-};
-
-/* No memory to release */
-static void edac_pci_release(struct kobject *kobj)
-{
-	debugf1("%s()\n", __func__);
-	complete(&edac_pci_kobj_complete);
-}
-
-static struct kobj_type ktype_edac_pci = {
-	.release = edac_pci_release,
-	.sysfs_ops = &edac_pci_sysfs_ops,
-	.default_attrs = (struct attribute **) edac_pci_attr,
-};
-
-/**
- * edac_sysfs_pci_setup()
- *
- */
-static int edac_sysfs_pci_setup(void)
-{
-	int err;
-
-	debugf1("%s()\n", __func__);
-
-	memset(&edac_pci_kobj, 0, sizeof(edac_pci_kobj));
-	edac_pci_kobj.parent = &edac_class.kset.kobj;
-	edac_pci_kobj.ktype = &ktype_edac_pci;
-	err = kobject_set_name(&edac_pci_kobj, "pci");
-
-	if (!err) {
-		/* Instanstiate the csrow object */
-		/* FIXME: maybe new sysdev_create_subdir() */
-		err = kobject_register(&edac_pci_kobj);
-
-		if (err)
-			debugf1("Failed to register '.../edac/pci'\n");
-		else
-			debugf1("Registered '.../edac/pci' kobject\n");
-	}
-
-	return err;
-}
-
-static void edac_sysfs_pci_teardown(void)
-{
-	debugf0("%s()\n", __func__);
-	init_completion(&edac_pci_kobj_complete);
-	kobject_unregister(&edac_pci_kobj);
-	wait_for_completion(&edac_pci_kobj_complete);
-}
-
-
-static u16 get_pci_parity_status(struct pci_dev *dev, int secondary)
-{
-	int where;
-	u16 status;
-
-	where = secondary ? PCI_SEC_STATUS : PCI_STATUS;
-	pci_read_config_word(dev, where, &status);
-
-	/* If we get back 0xFFFF then we must suspect that the card has been
-	 * pulled but the Linux PCI layer has not yet finished cleaning up.
-	 * We don't want to report on such devices
-	 */
-
-	if (status == 0xFFFF) {
-		u32 sanity;
-
-		pci_read_config_dword(dev, 0, &sanity);
-
-		if (sanity == 0xFFFFFFFF)
-			return 0;
-	}
-
-	status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR |
-		PCI_STATUS_PARITY;
-
-	if (status)
-		/* reset only the bits we are interested in */
-		pci_write_config_word(dev, where, status);
-
-	return status;
-}
-
-typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev);
-
-/* Clear any PCI parity errors logged by this device. */
-static void edac_pci_dev_parity_clear(struct pci_dev *dev)
-{
-	u8 header_type;
-
-	get_pci_parity_status(dev, 0);
-
-	/* read the device TYPE, looking for bridges */
-	pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
-
-	if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE)
-		get_pci_parity_status(dev, 1);
-}
-
-/*
- *  PCI Parity polling
- *
- */
-static void edac_pci_dev_parity_test(struct pci_dev *dev)
-{
-	u16 status;
-	u8  header_type;
-
-	/* read the STATUS register on this device
-	 */
-	status = get_pci_parity_status(dev, 0);
-
-	debugf2("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id );
-
-	/* check the status reg for errors */
-	if (status) {
-		if (status & (PCI_STATUS_SIG_SYSTEM_ERROR))
-			edac_printk(KERN_CRIT, EDAC_PCI,
-				"Signaled System Error on %s\n",
-				pci_name(dev));
-
-		if (status & (PCI_STATUS_PARITY)) {
-			edac_printk(KERN_CRIT, EDAC_PCI,
-				"Master Data Parity Error on %s\n",
-				pci_name(dev));
-
-			atomic_inc(&pci_parity_count);
-		}
-
-		if (status & (PCI_STATUS_DETECTED_PARITY)) {
-			edac_printk(KERN_CRIT, EDAC_PCI,
-				"Detected Parity Error on %s\n",
-				pci_name(dev));
-
-			atomic_inc(&pci_parity_count);
-		}
-	}
-
-	/* read the device TYPE, looking for bridges */
-	pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
-
-	debugf2("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id );
-
-	if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
-		/* On bridges, need to examine secondary status register  */
-		status = get_pci_parity_status(dev, 1);
-
-		debugf2("PCI SEC_STATUS= 0x%04x %s\n",
-				status, dev->dev.bus_id );
-
-		/* check the secondary status reg for errors */
-		if (status) {
-			if (status & (PCI_STATUS_SIG_SYSTEM_ERROR))
-				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
-					"Signaled System Error on %s\n",
-					pci_name(dev));
-
-			if (status & (PCI_STATUS_PARITY)) {
-				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
-					"Master Data Parity Error on "
-					"%s\n", pci_name(dev));
-
-				atomic_inc(&pci_parity_count);
-			}
-
-			if (status & (PCI_STATUS_DETECTED_PARITY)) {
-				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
-					"Detected Parity Error on %s\n",
-					pci_name(dev));
-
-				atomic_inc(&pci_parity_count);
-			}
-		}
-	}
-}
-
-/*
- * pci_dev parity list iterator
- *	Scan the PCI device list for one iteration, looking for SERRORs
- *	Master Parity ERRORS or Parity ERRORs on primary or secondary devices
- */
-static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
-{
-	struct pci_dev *dev = NULL;
-
-	/* request for kernel access to the next PCI device, if any,
-	 * and while we are looking at it have its reference count
-	 * bumped until we are done with it
-	 */
-	while((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-		fn(dev);
-	}
-}
-
-static void do_pci_parity_check(void)
-{
-	unsigned long flags;
-	int before_count;
-
-	debugf3("%s()\n", __func__);
-
-	if (!check_pci_parity)
-		return;
-
-	before_count = atomic_read(&pci_parity_count);
-
-	/* scan all PCI devices looking for a Parity Error on devices and
-	 * bridges
-	 */
-	local_irq_save(flags);
-	edac_pci_dev_parity_iterator(edac_pci_dev_parity_test);
-	local_irq_restore(flags);
-
-	/* Only if operator has selected panic on PCI Error */
-	if (panic_on_pci_parity) {
-		/* If the count is different 'after' from 'before' */
-		if (before_count != atomic_read(&pci_parity_count))
-			panic("EDAC: PCI Parity Error");
-	}
-}
-
-static inline void clear_pci_parity_errors(void)
-{
-	/* Clear any PCI bus parity errors that devices initially have logged
-	 * in their registers.
-	 */
-	edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear);
-}
-
-#else	/* CONFIG_PCI */
-
-/* pre-process these away */
-#define	do_pci_parity_check()
-#define	clear_pci_parity_errors()
-#define	edac_sysfs_pci_teardown()
-#define	edac_sysfs_pci_setup()	(0)
-
-#endif	/* CONFIG_PCI */
-
-/* EDAC sysfs CSROW data structures and methods
- */
-
-/* Set of more default csrow<id> attribute show/store functions */
-static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data, int private)
-{
-	return sprintf(data,"%u\n", csrow->ue_count);
-}
-
-static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data, int private)
-{
-	return sprintf(data,"%u\n", csrow->ce_count);
-}
-
-static ssize_t csrow_size_show(struct csrow_info *csrow, char *data, int private)
-{
-	return sprintf(data,"%u\n", PAGES_TO_MiB(csrow->nr_pages));
-}
-
-static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data, int private)
-{
-	return sprintf(data,"%s\n", mem_types[csrow->mtype]);
-}
-
-static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data, int private)
-{
-	return sprintf(data,"%s\n", dev_types[csrow->dtype]);
-}
-
-static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data, int private)
-{
-	return sprintf(data,"%s\n", edac_caps[csrow->edac_mode]);
-}
-
-/* show/store functions for DIMM Label attributes */
-static ssize_t channel_dimm_label_show(struct csrow_info *csrow,
-		char *data, int channel)
-{
-	return snprintf(data, EDAC_MC_LABEL_LEN,"%s",
-			csrow->channels[channel].label);
-}
-
-static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
-				const char *data,
-				size_t count,
-				int channel)
-{
-	ssize_t max_size = 0;
-
-	max_size = min((ssize_t)count,(ssize_t)EDAC_MC_LABEL_LEN-1);
-	strncpy(csrow->channels[channel].label, data, max_size);
-	csrow->channels[channel].label[max_size] = '\0';
-
-	return max_size;
-}
-
-/* show function for dynamic chX_ce_count attribute */
-static ssize_t channel_ce_count_show(struct csrow_info *csrow,
-				char *data,
-				int channel)
-{
-	return sprintf(data, "%u\n", csrow->channels[channel].ce_count);
-}
-
-/* csrow specific attribute structure */
-struct csrowdev_attribute {
-	struct attribute attr;
-	ssize_t (*show)(struct csrow_info *,char *,int);
-	ssize_t (*store)(struct csrow_info *, const char *,size_t,int);
-	int    private;
-};
-
-#define to_csrow(k) container_of(k, struct csrow_info, kobj)
-#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr)
-
-/* Set of show/store higher level functions for default csrow attributes */
-static ssize_t csrowdev_show(struct kobject *kobj,
-			struct attribute *attr,
-			char *buffer)
-{
-	struct csrow_info *csrow = to_csrow(kobj);
-	struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
-
-	if (csrowdev_attr->show)
-		return csrowdev_attr->show(csrow,
-					buffer,
-					csrowdev_attr->private);
-	return -EIO;
-}
-
-static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
-		const char *buffer, size_t count)
-{
-	struct csrow_info *csrow = to_csrow(kobj);
-	struct csrowdev_attribute * csrowdev_attr = to_csrowdev_attr(attr);
-
-	if (csrowdev_attr->store)
-		return csrowdev_attr->store(csrow,
-					buffer,
-					count,
-					csrowdev_attr->private);
-	return -EIO;
-}
-
-static struct sysfs_ops csrowfs_ops = {
-	.show   = csrowdev_show,
-	.store  = csrowdev_store
-};
-
-#define CSROWDEV_ATTR(_name,_mode,_show,_store,_private)	\
-struct csrowdev_attribute attr_##_name = {			\
-	.attr = {.name = __stringify(_name), .mode = _mode },	\
-	.show   = _show,					\
-	.store  = _store,					\
-	.private = _private,					\
-};
-
-/* default cwrow<id>/attribute files */
-CSROWDEV_ATTR(size_mb,S_IRUGO,csrow_size_show,NULL,0);
-CSROWDEV_ATTR(dev_type,S_IRUGO,csrow_dev_type_show,NULL,0);
-CSROWDEV_ATTR(mem_type,S_IRUGO,csrow_mem_type_show,NULL,0);
-CSROWDEV_ATTR(edac_mode,S_IRUGO,csrow_edac_mode_show,NULL,0);
-CSROWDEV_ATTR(ue_count,S_IRUGO,csrow_ue_count_show,NULL,0);
-CSROWDEV_ATTR(ce_count,S_IRUGO,csrow_ce_count_show,NULL,0);
-
-/* default attributes of the CSROW<id> object */
-static struct csrowdev_attribute *default_csrow_attr[] = {
-	&attr_dev_type,
-	&attr_mem_type,
-	&attr_edac_mode,
-	&attr_size_mb,
-	&attr_ue_count,
-	&attr_ce_count,
-	NULL,
-};
-
-
-/* possible dynamic channel DIMM Label attribute files */
-CSROWDEV_ATTR(ch0_dimm_label,S_IRUGO|S_IWUSR,
-		channel_dimm_label_show,
-		channel_dimm_label_store,
-		0 );
-CSROWDEV_ATTR(ch1_dimm_label,S_IRUGO|S_IWUSR,
-		channel_dimm_label_show,
-		channel_dimm_label_store,
-		1 );
-CSROWDEV_ATTR(ch2_dimm_label,S_IRUGO|S_IWUSR,
-		channel_dimm_label_show,
-		channel_dimm_label_store,
-		2 );
-CSROWDEV_ATTR(ch3_dimm_label,S_IRUGO|S_IWUSR,
-		channel_dimm_label_show,
-		channel_dimm_label_store,
-		3 );
-CSROWDEV_ATTR(ch4_dimm_label,S_IRUGO|S_IWUSR,
-		channel_dimm_label_show,
-		channel_dimm_label_store,
-		4 );
-CSROWDEV_ATTR(ch5_dimm_label,S_IRUGO|S_IWUSR,
-		channel_dimm_label_show,
-		channel_dimm_label_store,
-		5 );
-
-/* Total possible dynamic DIMM Label attribute file table */
-static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = {
-		&attr_ch0_dimm_label,
-		&attr_ch1_dimm_label,
-		&attr_ch2_dimm_label,
-		&attr_ch3_dimm_label,
-		&attr_ch4_dimm_label,
-		&attr_ch5_dimm_label
-};
-
-/* possible dynamic channel ce_count attribute files */
-CSROWDEV_ATTR(ch0_ce_count,S_IRUGO|S_IWUSR,
-		channel_ce_count_show,
-		NULL,
-		0 );
-CSROWDEV_ATTR(ch1_ce_count,S_IRUGO|S_IWUSR,
-		channel_ce_count_show,
-		NULL,
-		1 );
-CSROWDEV_ATTR(ch2_ce_count,S_IRUGO|S_IWUSR,
-		channel_ce_count_show,
-		NULL,
-		2 );
-CSROWDEV_ATTR(ch3_ce_count,S_IRUGO|S_IWUSR,
-		channel_ce_count_show,
-		NULL,
-		3 );
-CSROWDEV_ATTR(ch4_ce_count,S_IRUGO|S_IWUSR,
-		channel_ce_count_show,
-		NULL,
-		4 );
-CSROWDEV_ATTR(ch5_ce_count,S_IRUGO|S_IWUSR,
-		channel_ce_count_show,
-		NULL,
-		5 );
-
-/* Total possible dynamic ce_count attribute file table */
-static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = {
-		&attr_ch0_ce_count,
-		&attr_ch1_ce_count,
-		&attr_ch2_ce_count,
-		&attr_ch3_ce_count,
-		&attr_ch4_ce_count,
-		&attr_ch5_ce_count
-};
-
-
-#define EDAC_NR_CHANNELS	6
-
-/* Create dynamic CHANNEL files, indexed by 'chan',  under specifed CSROW */
-static int edac_create_channel_files(struct kobject *kobj, int chan)
-{
-	int err=-ENODEV;
-
-	if (chan >= EDAC_NR_CHANNELS)
-		return err;
-
-	/* create the DIMM label attribute file */
-	err = sysfs_create_file(kobj,
-			(struct attribute *) dynamic_csrow_dimm_attr[chan]);
-
-	if (!err) {
-		/* create the CE Count attribute file */
-		err = sysfs_create_file(kobj,
-			(struct attribute *) dynamic_csrow_ce_count_attr[chan]);
-	} else {
-		debugf1("%s()  dimm labels and ce_count files created", __func__);
-	}
-
-	return err;
-}
-
-/* No memory to release for this kobj */
-static void edac_csrow_instance_release(struct kobject *kobj)
-{
-	struct csrow_info *cs;
-
-	cs = container_of(kobj, struct csrow_info, kobj);
-	complete(&cs->kobj_complete);
-}
-
-/* the kobj_type instance for a CSROW */
-static struct kobj_type ktype_csrow = {
-	.release = edac_csrow_instance_release,
-	.sysfs_ops = &csrowfs_ops,
-	.default_attrs = (struct attribute **) default_csrow_attr,
-};
-
-/* Create a CSROW object under specifed edac_mc_device */
-static int edac_create_csrow_object(
-		struct kobject *edac_mci_kobj,
-		struct csrow_info *csrow,
-		int index)
-{
-	int err = 0;
-	int chan;
-
-	memset(&csrow->kobj, 0, sizeof(csrow->kobj));
-
-	/* generate ..../edac/mc/mc<id>/csrow<index>   */
-
-	csrow->kobj.parent = edac_mci_kobj;
-	csrow->kobj.ktype = &ktype_csrow;
-
-	/* name this instance of csrow<id> */
-	err = kobject_set_name(&csrow->kobj,"csrow%d",index);
-	if (err)
-		goto error_exit;
-
-	/* Instanstiate the csrow object */
-	err = kobject_register(&csrow->kobj);
-	if (!err) {
-		/* Create the dyanmic attribute files on this csrow,
-		 * namely, the DIMM labels and the channel ce_count
-		 */
-		for (chan = 0; chan < csrow->nr_channels; chan++) {
-			err = edac_create_channel_files(&csrow->kobj,chan);
-			if (err)
-				break;
-		}
-	}
-
-error_exit:
-	return err;
-}
-
-/* default sysfs methods and data structures for the main MCI kobject */
-
-static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
-		const char *data, size_t count)
-{
-	int row, chan;
-
-	mci->ue_noinfo_count = 0;
-	mci->ce_noinfo_count = 0;
-	mci->ue_count = 0;
-	mci->ce_count = 0;
-
-	for (row = 0; row < mci->nr_csrows; row++) {
-		struct csrow_info *ri = &mci->csrows[row];
-
-		ri->ue_count = 0;
-		ri->ce_count = 0;
-
-		for (chan = 0; chan < ri->nr_channels; chan++)
-			ri->channels[chan].ce_count = 0;
-	}
-
-	mci->start_time = jiffies;
-	return count;
-}
-
-/* memory scrubbing */
-static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
-					const char *data, size_t count)
-{
-	u32 bandwidth = -1;
-
-	if (mci->set_sdram_scrub_rate) {
-
-		memctrl_int_store(&bandwidth, data, count);
-
-		if (!(*mci->set_sdram_scrub_rate)(mci, &bandwidth)) {
-			edac_printk(KERN_DEBUG, EDAC_MC,
-				"Scrub rate set successfully, applied: %d\n",
-				bandwidth);
-		} else {
-			/* FIXME: error codes maybe? */
-			edac_printk(KERN_DEBUG, EDAC_MC,
-				"Scrub rate set FAILED, could not apply: %d\n",
-				bandwidth);
-		}
-	} else {
-		/* FIXME: produce "not implemented" ERROR for user-side. */
-		edac_printk(KERN_WARNING, EDAC_MC,
-			"Memory scrubbing 'set'control is not implemented!\n");
-	}
-	return count;
-}
-
-static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
-{
-	u32 bandwidth = -1;
-
-	if (mci->get_sdram_scrub_rate) {
-		if (!(*mci->get_sdram_scrub_rate)(mci, &bandwidth)) {
-			edac_printk(KERN_DEBUG, EDAC_MC,
-				"Scrub rate successfully, fetched: %d\n",
-				bandwidth);
-		} else {
-			/* FIXME: error codes maybe? */
-			edac_printk(KERN_DEBUG, EDAC_MC,
-				"Scrub rate fetch FAILED, got: %d\n",
-				bandwidth);
-		}
-	} else {
-		/* FIXME: produce "not implemented" ERROR for user-side.  */
-		edac_printk(KERN_WARNING, EDAC_MC,
-			"Memory scrubbing 'get' control is not implemented!\n");
-	}
-	return sprintf(data, "%d\n", bandwidth);
-}
-
-/* default attribute files for the MCI object */
-static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
-{
-	return sprintf(data,"%d\n", mci->ue_count);
-}
-
-static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data)
-{
-	return sprintf(data,"%d\n", mci->ce_count);
-}
-
-static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data)
-{
-	return sprintf(data,"%d\n", mci->ce_noinfo_count);
-}
-
-static ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data)
-{
-	return sprintf(data,"%d\n", mci->ue_noinfo_count);
-}
-
-static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data)
-{
-	return sprintf(data,"%ld\n", (jiffies - mci->start_time) / HZ);
-}
-
-static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data)
-{
-	return sprintf(data,"%s\n", mci->ctl_name);
-}
-
-static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
-{
-	int total_pages, csrow_idx;
-
-	for (total_pages = csrow_idx = 0; csrow_idx < mci->nr_csrows;
-			csrow_idx++) {
-		struct csrow_info *csrow = &mci->csrows[csrow_idx];
-
-		if (!csrow->nr_pages)
-			continue;
-
-		total_pages += csrow->nr_pages;
-	}
-
-	return sprintf(data,"%u\n", PAGES_TO_MiB(total_pages));
-}
-
-struct mcidev_attribute {
-	struct attribute attr;
-	ssize_t (*show)(struct mem_ctl_info *,char *);
-	ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
-};
-
-#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj)
-#define to_mcidev_attr(a) container_of(a, struct mcidev_attribute, attr)
-
-/* MCI show/store functions for top most object */
-static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
-		char *buffer)
-{
-	struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
-	struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr);
-
-	if (mcidev_attr->show)
-		return mcidev_attr->show(mem_ctl_info, buffer);
-
-	return -EIO;
-}
-
-static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
-		const char *buffer, size_t count)
-{
-	struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
-	struct mcidev_attribute * mcidev_attr = to_mcidev_attr(attr);
-
-	if (mcidev_attr->store)
-		return mcidev_attr->store(mem_ctl_info, buffer, count);
-
-	return -EIO;
-}
-
-static struct sysfs_ops mci_ops = {
-	.show = mcidev_show,
-	.store = mcidev_store
-};
-
-#define MCIDEV_ATTR(_name,_mode,_show,_store)			\
-struct mcidev_attribute mci_attr_##_name = {			\
-	.attr = {.name = __stringify(_name), .mode = _mode },	\
-	.show   = _show,					\
-	.store  = _store,					\
-};
-
-/* default Control file */
-MCIDEV_ATTR(reset_counters,S_IWUSR,NULL,mci_reset_counters_store);
-
-/* default Attribute files */
-MCIDEV_ATTR(mc_name,S_IRUGO,mci_ctl_name_show,NULL);
-MCIDEV_ATTR(size_mb,S_IRUGO,mci_size_mb_show,NULL);
-MCIDEV_ATTR(seconds_since_reset,S_IRUGO,mci_seconds_show,NULL);
-MCIDEV_ATTR(ue_noinfo_count,S_IRUGO,mci_ue_noinfo_show,NULL);
-MCIDEV_ATTR(ce_noinfo_count,S_IRUGO,mci_ce_noinfo_show,NULL);
-MCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL);
-MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL);
-
-/* memory scrubber attribute file */
-MCIDEV_ATTR(sdram_scrub_rate,S_IRUGO|S_IWUSR,mci_sdram_scrub_rate_show,mci_sdram_scrub_rate_store);
-
-static struct mcidev_attribute *mci_attr[] = {
-	&mci_attr_reset_counters,
-	&mci_attr_mc_name,
-	&mci_attr_size_mb,
-	&mci_attr_seconds_since_reset,
-	&mci_attr_ue_noinfo_count,
-	&mci_attr_ce_noinfo_count,
-	&mci_attr_ue_count,
-	&mci_attr_ce_count,
-	&mci_attr_sdram_scrub_rate,
-	NULL
-};
-
-/*
- * Release of a MC controlling instance
- */
-static void edac_mci_instance_release(struct kobject *kobj)
-{
-	struct mem_ctl_info *mci;
-
-	mci = to_mci(kobj);
-	debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
-	complete(&mci->kobj_complete);
-}
-
-static struct kobj_type ktype_mci = {
-	.release = edac_mci_instance_release,
-	.sysfs_ops = &mci_ops,
-	.default_attrs = (struct attribute **) mci_attr,
-};
-
-
-#define EDAC_DEVICE_SYMLINK	"device"
-
-/*
- * Create a new Memory Controller kobject instance,
- *	mc<id> under the 'mc' directory
- *
- * Return:
- *	0	Success
- *	!0	Failure
- */
-static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
-{
-	int i;
-	int err;
-	struct csrow_info *csrow;
-	struct kobject *edac_mci_kobj=&mci->edac_mci_kobj;
-
-	debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
-	memset(edac_mci_kobj, 0, sizeof(*edac_mci_kobj));
-
-	/* set the name of the mc<id> object */
-	err = kobject_set_name(edac_mci_kobj,"mc%d",mci->mc_idx);
-	if (err)
-		return err;
-
-	/* link to our parent the '..../edac/mc' object */
-	edac_mci_kobj->parent = &edac_memctrl_kobj;
-	edac_mci_kobj->ktype = &ktype_mci;
-
-	/* register the mc<id> kobject */
-	err = kobject_register(edac_mci_kobj);
-	if (err)
-		return err;
-
-	/* create a symlink for the device */
-	err = sysfs_create_link(edac_mci_kobj, &mci->dev->kobj,
-				EDAC_DEVICE_SYMLINK);
-	if (err)
-		goto fail0;
-
-	/* Make directories for each CSROW object
-	 * under the mc<id> kobject
-	 */
-	for (i = 0; i < mci->nr_csrows; i++) {
-		csrow = &mci->csrows[i];
-
-		/* Only expose populated CSROWs */
-		if (csrow->nr_pages > 0) {
-			err = edac_create_csrow_object(edac_mci_kobj,csrow,i);
-			if (err)
-				goto fail1;
-		}
-	}
-
-	return 0;
-
-	/* CSROW error: backout what has already been registered,  */
-fail1:
-	for ( i--; i >= 0; i--) {
-		if (csrow->nr_pages > 0) {
-			init_completion(&csrow->kobj_complete);
-			kobject_unregister(&mci->csrows[i].kobj);
-			wait_for_completion(&csrow->kobj_complete);
-		}
-	}
-
-fail0:
-	init_completion(&mci->kobj_complete);
-	kobject_unregister(edac_mci_kobj);
-	wait_for_completion(&mci->kobj_complete);
-	return err;
-}
-
-/*
- * remove a Memory Controller instance
- */
-static void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
-{
-	int i;
-
-	debugf0("%s()\n", __func__);
-
-	/* remove all csrow kobjects */
-	for (i = 0; i < mci->nr_csrows; i++) {
-		if (mci->csrows[i].nr_pages > 0) {
-			init_completion(&mci->csrows[i].kobj_complete);
-			kobject_unregister(&mci->csrows[i].kobj);
-			wait_for_completion(&mci->csrows[i].kobj_complete);
-		}
-	}
-
-	sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);
-	init_completion(&mci->kobj_complete);
-	kobject_unregister(&mci->edac_mci_kobj);
-	wait_for_completion(&mci->kobj_complete);
-}
-
-/* END OF sysfs data and methods */
-
 #ifdef CONFIG_EDAC_DEBUG
 
-void edac_mc_dump_channel(struct channel_info *chan)
+static void edac_mc_dump_channel(struct channel_info *chan)
 {
 	debugf4("\tchannel = %p\n", chan);
 	debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx);
@@ -1228,25 +48,21 @@
 	debugf4("\tchannel->label = '%s'\n", chan->label);
 	debugf4("\tchannel->csrow = %p\n\n", chan->csrow);
 }
-EXPORT_SYMBOL_GPL(edac_mc_dump_channel);
 
-void edac_mc_dump_csrow(struct csrow_info *csrow)
+static void edac_mc_dump_csrow(struct csrow_info *csrow)
 {
 	debugf4("\tcsrow = %p\n", csrow);
 	debugf4("\tcsrow->csrow_idx = %d\n", csrow->csrow_idx);
-	debugf4("\tcsrow->first_page = 0x%lx\n",
-		csrow->first_page);
+	debugf4("\tcsrow->first_page = 0x%lx\n", csrow->first_page);
 	debugf4("\tcsrow->last_page = 0x%lx\n", csrow->last_page);
 	debugf4("\tcsrow->page_mask = 0x%lx\n", csrow->page_mask);
 	debugf4("\tcsrow->nr_pages = 0x%x\n", csrow->nr_pages);
-	debugf4("\tcsrow->nr_channels = %d\n",
-		csrow->nr_channels);
+	debugf4("\tcsrow->nr_channels = %d\n", csrow->nr_channels);
 	debugf4("\tcsrow->channels = %p\n", csrow->channels);
 	debugf4("\tcsrow->mci = %p\n\n", csrow->mci);
 }
-EXPORT_SYMBOL_GPL(edac_mc_dump_csrow);
 
-void edac_mc_dump_mci(struct mem_ctl_info *mci)
+static void edac_mc_dump_mci(struct mem_ctl_info *mci)
 {
 	debugf3("\tmci = %p\n", mci);
 	debugf3("\tmci->mtype_cap = %lx\n", mci->mtype_cap);
@@ -1256,13 +72,11 @@
 	debugf3("\tmci->nr_csrows = %d, csrows = %p\n",
 		mci->nr_csrows, mci->csrows);
 	debugf3("\tdev = %p\n", mci->dev);
-	debugf3("\tmod_name:ctl_name = %s:%s\n",
-		mci->mod_name, mci->ctl_name);
+	debugf3("\tmod_name:ctl_name = %s:%s\n", mci->mod_name, mci->ctl_name);
 	debugf3("\tpvt_info = %p\n\n", mci->pvt_info);
 }
-EXPORT_SYMBOL_GPL(edac_mc_dump_mci);
 
-#endif  /* CONFIG_EDAC_DEBUG */
+#endif				/* CONFIG_EDAC_DEBUG */
 
 /* 'ptr' points to a possibly unaligned item X such that sizeof(X) is 'size'.
  * Adjust 'ptr' so that its alignment is at least as stringent as what the
@@ -1271,7 +85,7 @@
  * If 'size' is a constant, the compiler will optimize this whole function
  * down to either a no-op or the addition of a constant to the value of 'ptr'.
  */
-static inline char * align_ptr(void *ptr, unsigned size)
+void *edac_align_ptr(void *ptr, unsigned size)
 {
 	unsigned align, r;
 
@@ -1288,14 +102,14 @@
 	else if (size > sizeof(char))
 		align = sizeof(short);
 	else
-		return (char *) ptr;
+		return (char *)ptr;
 
 	r = size % align;
 
 	if (r == 0)
-		return (char *) ptr;
+		return (char *)ptr;
 
-	return (char *) (((unsigned long) ptr) + align - r);
+	return (void *)(((unsigned long)ptr) + align - r);
 }
 
 /**
@@ -1315,7 +129,7 @@
  *	struct mem_ctl_info pointer
  */
 struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
-		unsigned nr_chans)
+				unsigned nr_chans, int edac_index)
 {
 	struct mem_ctl_info *mci;
 	struct csrow_info *csi, *csrow;
@@ -1323,30 +137,32 @@
 	void *pvt;
 	unsigned size;
 	int row, chn;
+	int err;
 
 	/* Figure out the offsets of the various items from the start of an mc
 	 * structure.  We want the alignment of each item to be at least as
 	 * stringent as what the compiler would provide if we could simply
 	 * hardcode everything into a single struct.
 	 */
-	mci = (struct mem_ctl_info *) 0;
-	csi = (struct csrow_info *)align_ptr(&mci[1], sizeof(*csi));
-	chi = (struct channel_info *)
-			align_ptr(&csi[nr_csrows], sizeof(*chi));
-	pvt = align_ptr(&chi[nr_chans * nr_csrows], sz_pvt);
-	size = ((unsigned long) pvt) + sz_pvt;
+	mci = (struct mem_ctl_info *)0;
+	csi = edac_align_ptr(&mci[1], sizeof(*csi));
+	chi = edac_align_ptr(&csi[nr_csrows], sizeof(*chi));
+	pvt = edac_align_ptr(&chi[nr_chans * nr_csrows], sz_pvt);
+	size = ((unsigned long)pvt) + sz_pvt;
 
-	if ((mci = kmalloc(size, GFP_KERNEL)) == NULL)
+	mci = kzalloc(size, GFP_KERNEL);
+	if (mci == NULL)
 		return NULL;
 
 	/* Adjust pointers so they point within the memory we just allocated
 	 * rather than an imaginary chunk of memory located at address 0.
 	 */
-	csi = (struct csrow_info *) (((char *) mci) + ((unsigned long) csi));
-	chi = (struct channel_info *) (((char *) mci) + ((unsigned long) chi));
-	pvt = sz_pvt ? (((char *) mci) + ((unsigned long) pvt)) : NULL;
+	csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi));
+	chi = (struct channel_info *)(((char *)mci) + ((unsigned long)chi));
+	pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL;
 
-	memset(mci, 0, size);  /* clear all fields */
+	/* setup index and various internal pointers */
+	mci->mc_idx = edac_index;
 	mci->csrows = csi;
 	mci->pvt_info = pvt;
 	mci->nr_csrows = nr_csrows;
@@ -1366,20 +182,45 @@
 		}
 	}
 
+	mci->op_state = OP_ALLOC;
+
+	/*
+	 * Initialize the 'root' kobj for the edac_mc controller
+	 */
+	err = edac_mc_register_sysfs_main_kobj(mci);
+	if (err) {
+		kfree(mci);
+		return NULL;
+	}
+
+	/* at this point, the root kobj is valid, and in order to
+	 * 'free' the object, then the function:
+	 *      edac_mc_unregister_sysfs_main_kobj() must be called
+	 * which will perform kobj unregistration and the actual free
+	 * will occur during the kobject callback operation
+	 */
 	return mci;
 }
 EXPORT_SYMBOL_GPL(edac_mc_alloc);
 
 /**
- * edac_mc_free:  Free a previously allocated 'mci' structure
+ * edac_mc_free
+ *	'Free' a previously allocated 'mci' structure
  * @mci: pointer to a struct mem_ctl_info structure
  */
 void edac_mc_free(struct mem_ctl_info *mci)
 {
-	kfree(mci);
+	edac_mc_unregister_sysfs_main_kobj(mci);
 }
 EXPORT_SYMBOL_GPL(edac_mc_free);
 
+
+/*
+ * find_mci_by_dev
+ *
+ *	scan list of controllers looking for the one that manages
+ *	the 'dev' device
+ */
 static struct mem_ctl_info *find_mci_by_dev(struct device *dev)
 {
 	struct mem_ctl_info *mci;
@@ -1397,18 +238,149 @@
 	return NULL;
 }
 
+/*
+ * handler for EDAC to check if NMI type handler has asserted interrupt
+ */
+static int edac_mc_assert_error_check_and_clear(void)
+{
+	int old_state;
+
+	if (edac_op_state == EDAC_OPSTATE_POLL)
+		return 1;
+
+	old_state = edac_err_assert;
+	edac_err_assert = 0;
+
+	return old_state;
+}
+
+/*
+ * edac_mc_workq_function
+ *	performs the operation scheduled by a workq request
+ */
+static void edac_mc_workq_function(struct work_struct *work_req)
+{
+	struct delayed_work *d_work = (struct delayed_work *)work_req;
+	struct mem_ctl_info *mci = to_edac_mem_ctl_work(d_work);
+
+	mutex_lock(&mem_ctls_mutex);
+
+	/* if this control struct has movd to offline state, we are done */
+	if (mci->op_state == OP_OFFLINE) {
+		mutex_unlock(&mem_ctls_mutex);
+		return;
+	}
+
+	/* Only poll controllers that are running polled and have a check */
+	if (edac_mc_assert_error_check_and_clear() && (mci->edac_check != NULL))
+		mci->edac_check(mci);
+
+	mutex_unlock(&mem_ctls_mutex);
+
+	/* Reschedule */
+	queue_delayed_work(edac_workqueue, &mci->work,
+			msecs_to_jiffies(edac_mc_get_poll_msec()));
+}
+
+/*
+ * edac_mc_workq_setup
+ *	initialize a workq item for this mci
+ *	passing in the new delay period in msec
+ *
+ *	locking model:
+ *
+ *		called with the mem_ctls_mutex held
+ */
+static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
+{
+	debugf0("%s()\n", __func__);
+
+	/* if this instance is not in the POLL state, then simply return */
+	if (mci->op_state != OP_RUNNING_POLL)
+		return;
+
+	INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
+	queue_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
+}
+
+/*
+ * edac_mc_workq_teardown
+ *	stop the workq processing on this mci
+ *
+ *	locking model:
+ *
+ *		called WITHOUT lock held
+ */
+static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
+{
+	int status;
+
+	status = cancel_delayed_work(&mci->work);
+	if (status == 0) {
+		debugf0("%s() not canceled, flush the queue\n",
+			__func__);
+
+		/* workq instance might be running, wait for it */
+		flush_workqueue(edac_workqueue);
+	}
+}
+
+/*
+ * edac_mc_reset_delay_period(unsigned long value)
+ *
+ *	user space has updated our poll period value, need to
+ *	reset our workq delays
+ */
+void edac_mc_reset_delay_period(int value)
+{
+	struct mem_ctl_info *mci;
+	struct list_head *item;
+
+	mutex_lock(&mem_ctls_mutex);
+
+	/* scan the list and turn off all workq timers, doing so under lock
+	 */
+	list_for_each(item, &mc_devices) {
+		mci = list_entry(item, struct mem_ctl_info, link);
+
+		if (mci->op_state == OP_RUNNING_POLL)
+			cancel_delayed_work(&mci->work);
+	}
+
+	mutex_unlock(&mem_ctls_mutex);
+
+
+	/* re-walk the list, and reset the poll delay */
+	mutex_lock(&mem_ctls_mutex);
+
+	list_for_each(item, &mc_devices) {
+		mci = list_entry(item, struct mem_ctl_info, link);
+
+		edac_mc_workq_setup(mci, (unsigned long) value);
+	}
+
+	mutex_unlock(&mem_ctls_mutex);
+}
+
+
+
 /* Return 0 on success, 1 on failure.
  * Before calling this function, caller must
  * assign a unique value to mci->mc_idx.
+ *
+ *	locking model:
+ *
+ *		called with the mem_ctls_mutex lock held
  */
-static int add_mc_to_global_list (struct mem_ctl_info *mci)
+static int add_mc_to_global_list(struct mem_ctl_info *mci)
 {
 	struct list_head *item, *insert_before;
 	struct mem_ctl_info *p;
 
 	insert_before = &mc_devices;
 
-	if (unlikely((p = find_mci_by_dev(mci->dev)) != NULL))
+	p = find_mci_by_dev(mci->dev);
+	if (unlikely(p != NULL))
 		goto fail0;
 
 	list_for_each(item, &mc_devices) {
@@ -1424,18 +396,19 @@
 	}
 
 	list_add_tail_rcu(&mci->link, insert_before);
+	atomic_inc(&edac_handlers);
 	return 0;
 
 fail0:
 	edac_printk(KERN_WARNING, EDAC_MC,
-		    "%s (%s) %s %s already assigned %d\n", p->dev->bus_id,
-		    dev_name(p->dev), p->mod_name, p->ctl_name, p->mc_idx);
+		"%s (%s) %s %s already assigned %d\n", p->dev->bus_id,
+		dev_name(mci), p->mod_name, p->ctl_name, p->mc_idx);
 	return 1;
 
 fail1:
 	edac_printk(KERN_WARNING, EDAC_MC,
-		    "bug in low-level driver: attempt to assign\n"
-		    "    duplicate mc_idx %d in %s()\n", p->mc_idx, __func__);
+		"bug in low-level driver: attempt to assign\n"
+		"    duplicate mc_idx %d in %s()\n", p->mc_idx, __func__);
 	return 1;
 }
 
@@ -1450,6 +423,7 @@
 
 static void del_mc_from_global_list(struct mem_ctl_info *mci)
 {
+	atomic_dec(&edac_handlers);
 	list_del_rcu(&mci->link);
 	init_completion(&mci->complete);
 	call_rcu(&mci->rcu, complete_mc_list_del);
@@ -1457,6 +431,34 @@
 }
 
 /**
+ * edac_mc_find: Search for a mem_ctl_info structure whose index is 'idx'.
+ *
+ * If found, return a pointer to the structure.
+ * Else return NULL.
+ *
+ * Caller must hold mem_ctls_mutex.
+ */
+struct mem_ctl_info *edac_mc_find(int idx)
+{
+	struct list_head *item;
+	struct mem_ctl_info *mci;
+
+	list_for_each(item, &mc_devices) {
+		mci = list_entry(item, struct mem_ctl_info, link);
+
+		if (mci->mc_idx >= idx) {
+			if (mci->mc_idx == idx)
+				return mci;
+
+			break;
+		}
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL(edac_mc_find);
+
+/**
  * edac_mc_add_mc: Insert the 'mci' structure into the mci global list and
  *                 create sysfs entries associated with mci structure
  * @mci: pointer to the mci structure to be added to the list
@@ -1468,10 +470,10 @@
  */
 
 /* FIXME - should a warning be printed if no error detection? correction? */
-int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx)
+int edac_mc_add_mc(struct mem_ctl_info *mci)
 {
 	debugf0("%s()\n", __func__);
-	mci->mc_idx = mc_idx;
+
 #ifdef CONFIG_EDAC_DEBUG
 	if (edac_debug_level >= 3)
 		edac_mc_dump_mci(mci);
@@ -1484,12 +486,12 @@
 
 			edac_mc_dump_csrow(&mci->csrows[i]);
 			for (j = 0; j < mci->csrows[i].nr_channels; j++)
-				edac_mc_dump_channel(
-					&mci->csrows[i].channels[j]);
+				edac_mc_dump_channel(&mci->csrows[i].
+						channels[j]);
 		}
 	}
 #endif
-	down(&mem_ctls_mutex);
+	mutex_lock(&mem_ctls_mutex);
 
 	if (add_mc_to_global_list(mci))
 		goto fail0;
@@ -1503,18 +505,28 @@
 		goto fail1;
 	}
 
-	/* Report action taken */
-	edac_mc_printk(mci, KERN_INFO, "Giving out device to %s %s: DEV %s\n",
-		mci->mod_name, mci->ctl_name, dev_name(mci->dev));
+	/* If there IS a check routine, then we are running POLLED */
+	if (mci->edac_check != NULL) {
+		/* This instance is NOW RUNNING */
+		mci->op_state = OP_RUNNING_POLL;
 
-	up(&mem_ctls_mutex);
+		edac_mc_workq_setup(mci, edac_mc_get_poll_msec());
+	} else {
+		mci->op_state = OP_RUNNING_INTERRUPT;
+	}
+
+	/* Report action taken */
+	edac_mc_printk(mci, KERN_INFO, "Giving out device to '%s' '%s':"
+		" DEV %s\n", mci->mod_name, mci->ctl_name, dev_name(mci));
+
+	mutex_unlock(&mem_ctls_mutex);
 	return 0;
 
 fail1:
 	del_mc_from_global_list(mci);
 
 fail0:
-	up(&mem_ctls_mutex);
+	mutex_unlock(&mem_ctls_mutex);
 	return 1;
 }
 EXPORT_SYMBOL_GPL(edac_mc_add_mc);
@@ -1526,29 +538,41 @@
  *
  * Return pointer to removed mci structure, or NULL if device not found.
  */
-struct mem_ctl_info * edac_mc_del_mc(struct device *dev)
+struct mem_ctl_info *edac_mc_del_mc(struct device *dev)
 {
 	struct mem_ctl_info *mci;
 
-	debugf0("MC: %s()\n", __func__);
-	down(&mem_ctls_mutex);
+	debugf0("%s()\n", __func__);
 
-	if ((mci = find_mci_by_dev(dev)) == NULL) {
-		up(&mem_ctls_mutex);
+	mutex_lock(&mem_ctls_mutex);
+
+	/* find the requested mci struct in the global list */
+	mci = find_mci_by_dev(dev);
+	if (mci == NULL) {
+		mutex_unlock(&mem_ctls_mutex);
 		return NULL;
 	}
 
-	edac_remove_sysfs_mci_device(mci);
+	/* marking MCI offline */
+	mci->op_state = OP_OFFLINE;
+
 	del_mc_from_global_list(mci);
-	up(&mem_ctls_mutex);
+	mutex_unlock(&mem_ctls_mutex);
+
+	/* flush workq processes and remove sysfs */
+	edac_mc_workq_teardown(mci);
+	edac_remove_sysfs_mci_device(mci);
+
 	edac_printk(KERN_INFO, EDAC_MC,
 		"Removed device %d for %s %s: DEV %s\n", mci->mc_idx,
-		mci->mod_name, mci->ctl_name, dev_name(mci->dev));
+		mci->mod_name, mci->ctl_name, dev_name(mci));
+
 	return mci;
 }
 EXPORT_SYMBOL_GPL(edac_mc_del_mc);
 
-void edac_mc_scrub_block(unsigned long page, unsigned long offset, u32 size)
+static void edac_mc_scrub_block(unsigned long page, unsigned long offset,
+				u32 size)
 {
 	struct page *pg;
 	void *virt_addr;
@@ -1557,7 +581,7 @@
 	debugf3("%s()\n", __func__);
 
 	/* ECC error page was not in our memory. Ignore it. */
-	if(!pfn_valid(page))
+	if (!pfn_valid(page))
 		return;
 
 	/* Find the actual page structure then map it and fix */
@@ -1577,7 +601,6 @@
 	if (PageHighMem(pg))
 		local_irq_restore(flags);
 }
-EXPORT_SYMBOL_GPL(edac_mc_scrub_block);
 
 /* FIXME - should return -1 */
 int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
@@ -1611,7 +634,7 @@
 	if (row == -1)
 		edac_mc_printk(mci, KERN_ERR,
 			"could not look up page error address %lx\n",
-			(unsigned long) page);
+			(unsigned long)page);
 
 	return row;
 }
@@ -1620,8 +643,9 @@
 /* FIXME - setable log (warning/emerg) levels */
 /* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */
 void edac_mc_handle_ce(struct mem_ctl_info *mci,
-		unsigned long page_frame_number, unsigned long offset_in_page,
-		unsigned long syndrome, int row, int channel, const char *msg)
+		unsigned long page_frame_number,
+		unsigned long offset_in_page, unsigned long syndrome,
+		int row, int channel, const char *msg)
 {
 	unsigned long remapped_page;
 
@@ -1647,7 +671,7 @@
 		return;
 	}
 
-	if (log_ce)
+	if (edac_mc_get_log_ce())
 		/* FIXME - put in DIMM location */
 		edac_mc_printk(mci, KERN_WARNING,
 			"CE page 0x%lx, offset 0x%lx, grain %d, syndrome "
@@ -1671,18 +695,18 @@
 		 * page - which can then be scrubbed.
 		 */
 		remapped_page = mci->ctl_page_to_phys ?
-		    mci->ctl_page_to_phys(mci, page_frame_number) :
-		    page_frame_number;
+			mci->ctl_page_to_phys(mci, page_frame_number) :
+			page_frame_number;
 
 		edac_mc_scrub_block(remapped_page, offset_in_page,
-					mci->csrows[row].grain);
+				mci->csrows[row].grain);
 	}
 }
 EXPORT_SYMBOL_GPL(edac_mc_handle_ce);
 
 void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg)
 {
-	if (log_ce)
+	if (edac_mc_get_log_ce())
 		edac_mc_printk(mci, KERN_WARNING,
 			"CE - no information available: %s\n", msg);
 
@@ -1692,8 +716,8 @@
 EXPORT_SYMBOL_GPL(edac_mc_handle_ce_no_info);
 
 void edac_mc_handle_ue(struct mem_ctl_info *mci,
-		unsigned long page_frame_number, unsigned long offset_in_page,
-		int row, const char *msg)
+		unsigned long page_frame_number,
+		unsigned long offset_in_page, int row, const char *msg)
 {
 	int len = EDAC_MC_LABEL_LEN * 4;
 	char labels[len + 1];
@@ -1714,26 +738,26 @@
 	}
 
 	chars = snprintf(pos, len + 1, "%s",
-			mci->csrows[row].channels[0].label);
+			 mci->csrows[row].channels[0].label);
 	len -= chars;
 	pos += chars;
 
 	for (chan = 1; (chan < mci->csrows[row].nr_channels) && (len > 0);
-	     chan++) {
+		chan++) {
 		chars = snprintf(pos, len + 1, ":%s",
-				mci->csrows[row].channels[chan].label);
+				 mci->csrows[row].channels[chan].label);
 		len -= chars;
 		pos += chars;
 	}
 
-	if (log_ue)
+	if (edac_mc_get_log_ue())
 		edac_mc_printk(mci, KERN_EMERG,
 			"UE page 0x%lx, offset 0x%lx, grain %d, row %d, "
 			"labels \"%s\": %s\n", page_frame_number,
-			offset_in_page, mci->csrows[row].grain, row, labels,
-			msg);
+			offset_in_page, mci->csrows[row].grain, row,
+			labels, msg);
 
-	if (panic_on_ue)
+	if (edac_mc_get_panic_on_ue())
 		panic("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, "
 			"row %d, labels \"%s\": %s\n", mci->mc_idx,
 			page_frame_number, offset_in_page,
@@ -1746,10 +770,10 @@
 
 void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
 {
-	if (panic_on_ue)
+	if (edac_mc_get_panic_on_ue())
 		panic("EDAC MC%d: Uncorrected Error", mci->mc_idx);
 
-	if (log_ue)
+	if (edac_mc_get_log_ue())
 		edac_mc_printk(mci, KERN_WARNING,
 			"UE - no information available: %s\n", msg);
 	mci->ue_noinfo_count++;
@@ -1757,16 +781,14 @@
 }
 EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info);
 
-
 /*************************************************************
  * On Fully Buffered DIMM modules, this help function is
  * called to process UE events
  */
 void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
-				unsigned int csrow,
-				unsigned int channela,
-				unsigned int channelb,
-				char *msg)
+			unsigned int csrow,
+			unsigned int channela,
+			unsigned int channelb, char *msg)
 {
 	int len = EDAC_MC_LABEL_LEN * 4;
 	char labels[len + 1];
@@ -1808,20 +830,21 @@
 	/* Generate the DIMM labels from the specified channels */
 	chars = snprintf(pos, len + 1, "%s",
 			 mci->csrows[csrow].channels[channela].label);
-	len -= chars; pos += chars;
+	len -= chars;
+	pos += chars;
 	chars = snprintf(pos, len + 1, "-%s",
 			 mci->csrows[csrow].channels[channelb].label);
 
-	if (log_ue)
+	if (edac_mc_get_log_ue())
 		edac_mc_printk(mci, KERN_EMERG,
 			"UE row %d, channel-a= %d channel-b= %d "
 			"labels \"%s\": %s\n", csrow, channela, channelb,
 			labels, msg);
 
-	if (panic_on_ue)
+	if (edac_mc_get_panic_on_ue())
 		panic("UE row %d, channel-a= %d channel-b= %d "
-				"labels \"%s\": %s\n", csrow, channela,
-				channelb, labels, msg);
+			"labels \"%s\": %s\n", csrow, channela,
+			channelb, labels, msg);
 }
 EXPORT_SYMBOL(edac_mc_handle_fbd_ue);
 
@@ -1830,9 +853,7 @@
  * called to process CE events
  */
 void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
-			   unsigned int csrow,
-			   unsigned int channel,
-			   char *msg)
+			unsigned int csrow, unsigned int channel, char *msg)
 {
 
 	/* Ensure boundary values */
@@ -1853,13 +874,12 @@
 		return;
 	}
 
-	if (log_ce)
+	if (edac_mc_get_log_ce())
 		/* FIXME - put in DIMM location */
 		edac_mc_printk(mci, KERN_WARNING,
 			"CE row %d, channel %d, label \"%s\": %s\n",
 			csrow, channel,
-			mci->csrows[csrow].channels[channel].label,
-			msg);
+			mci->csrows[csrow].channels[channel].label, msg);
 
 	mci->ce_count++;
 	mci->csrows[csrow].ce_count++;
@@ -1867,17 +887,16 @@
 }
 EXPORT_SYMBOL(edac_mc_handle_fbd_ce);
 
-
 /*
  * Iterate over all MC instances and check for ECC, et al, errors
  */
-static inline void check_mc_devices(void)
+void edac_check_mc_devices(void)
 {
 	struct list_head *item;
 	struct mem_ctl_info *mci;
 
 	debugf3("%s()\n", __func__);
-	down(&mem_ctls_mutex);
+	mutex_lock(&mem_ctls_mutex);
 
 	list_for_each(item, &mc_devices) {
 		mci = list_entry(item, struct mem_ctl_info, link);
@@ -1886,120 +905,5 @@
 			mci->edac_check(mci);
 	}
 
-	up(&mem_ctls_mutex);
+	mutex_unlock(&mem_ctls_mutex);
 }
-
-/*
- * Check MC status every poll_msec.
- * Check PCI status every poll_msec as well.
- *
- * This where the work gets done for edac.
- *
- * SMP safe, doesn't use NMI, and auto-rate-limits.
- */
-static void do_edac_check(void)
-{
-	debugf3("%s()\n", __func__);
-	check_mc_devices();
-	do_pci_parity_check();
-}
-
-static int edac_kernel_thread(void *arg)
-{
-	set_freezable();
-	while (!kthread_should_stop()) {
-		do_edac_check();
-
-		/* goto sleep for the interval */
-		schedule_timeout_interruptible((HZ * poll_msec) / 1000);
-		try_to_freeze();
-	}
-
-	return 0;
-}
-
-/*
- * edac_mc_init
- *      module initialization entry point
- */
-static int __init edac_mc_init(void)
-{
-	edac_printk(KERN_INFO, EDAC_MC, EDAC_MC_VERSION "\n");
-
-	/*
-	 * Harvest and clear any boot/initialization PCI parity errors
-	 *
-	 * FIXME: This only clears errors logged by devices present at time of
-	 * 	module initialization.  We should also do an initial clear
-	 *	of each newly hotplugged device.
-	 */
-	clear_pci_parity_errors();
-
-	/* Create the MC sysfs entries */
-	if (edac_sysfs_memctrl_setup()) {
-		edac_printk(KERN_ERR, EDAC_MC,
-			"Error initializing sysfs code\n");
-		return -ENODEV;
-	}
-
-	/* Create the PCI parity sysfs entries */
-	if (edac_sysfs_pci_setup()) {
-		edac_sysfs_memctrl_teardown();
-		edac_printk(KERN_ERR, EDAC_MC,
-			"EDAC PCI: Error initializing sysfs code\n");
-		return -ENODEV;
-	}
-
-	/* create our kernel thread */
-	edac_thread = kthread_run(edac_kernel_thread, NULL, "kedac");
-
-	if (IS_ERR(edac_thread)) {
-		/* remove the sysfs entries */
-		edac_sysfs_memctrl_teardown();
-		edac_sysfs_pci_teardown();
-		return PTR_ERR(edac_thread);
-	}
-
-	return 0;
-}
-
-/*
- * edac_mc_exit()
- *      module exit/termination functioni
- */
-static void __exit edac_mc_exit(void)
-{
-	debugf0("%s()\n", __func__);
-	kthread_stop(edac_thread);
-
-	/* tear down the sysfs device */
-	edac_sysfs_memctrl_teardown();
-	edac_sysfs_pci_teardown();
-}
-
-module_init(edac_mc_init);
-module_exit(edac_mc_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh et al\n"
-	"Based on work by Dan Hollis et al");
-MODULE_DESCRIPTION("Core library routines for MC reporting");
-
-module_param(panic_on_ue, int, 0644);
-MODULE_PARM_DESC(panic_on_ue, "Panic on uncorrected error: 0=off 1=on");
-#ifdef CONFIG_PCI
-module_param(check_pci_parity, int, 0644);
-MODULE_PARM_DESC(check_pci_parity, "Check for PCI bus parity errors: 0=off 1=on");
-module_param(panic_on_pci_parity, int, 0644);
-MODULE_PARM_DESC(panic_on_pci_parity, "Panic on PCI Bus Parity error: 0=off 1=on");
-#endif
-module_param(log_ue, int, 0644);
-MODULE_PARM_DESC(log_ue, "Log uncorrectable error to console: 0=off 1=on");
-module_param(log_ce, int, 0644);
-MODULE_PARM_DESC(log_ce, "Log correctable error to console: 0=off 1=on");
-module_param(poll_msec, int, 0644);
-MODULE_PARM_DESC(poll_msec, "Polling period in milliseconds");
-#ifdef CONFIG_EDAC_DEBUG
-module_param(edac_debug_level, int, 0644);
-MODULE_PARM_DESC(edac_debug_level, "Debug level");
-#endif
diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h
deleted file mode 100644
index 713444c..0000000
--- a/drivers/edac/edac_mc.h
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * MC kernel module
- * (C) 2003 Linux Networx (http://lnxi.com)
- * This file may be distributed under the terms of the
- * GNU General Public License.
- *
- * Written by Thayne Harbaugh
- * Based on work by Dan Hollis <goemon at anime dot net> and others.
- *	http://www.anime.net/~goemon/linux-ecc/
- *
- * NMI handling support added by
- *     Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>
- *
- * $Id: edac_mc.h,v 1.4.2.10 2005/10/05 00:43:44 dsp_llnl Exp $
- *
- */
-
-#ifndef _EDAC_MC_H_
-#define _EDAC_MC_H_
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/smp.h>
-#include <linux/pci.h>
-#include <linux/time.h>
-#include <linux/nmi.h>
-#include <linux/rcupdate.h>
-#include <linux/completion.h>
-#include <linux/kobject.h>
-#include <linux/platform_device.h>
-
-#define EDAC_MC_LABEL_LEN	31
-#define MC_PROC_NAME_MAX_LEN 7
-
-#if PAGE_SHIFT < 20
-#define PAGES_TO_MiB( pages )	( ( pages ) >> ( 20 - PAGE_SHIFT ) )
-#else				/* PAGE_SHIFT > 20 */
-#define PAGES_TO_MiB( pages )	( ( pages ) << ( PAGE_SHIFT - 20 ) )
-#endif
-
-#define edac_printk(level, prefix, fmt, arg...) \
-	printk(level "EDAC " prefix ": " fmt, ##arg)
-
-#define edac_mc_printk(mci, level, fmt, arg...) \
-	printk(level "EDAC MC%d: " fmt, mci->mc_idx, ##arg)
-
-#define edac_mc_chipset_printk(mci, level, prefix, fmt, arg...) \
-	printk(level "EDAC " prefix " MC%d: " fmt, mci->mc_idx, ##arg)
-
-/* prefixes for edac_printk() and edac_mc_printk() */
-#define EDAC_MC "MC"
-#define EDAC_PCI "PCI"
-#define EDAC_DEBUG "DEBUG"
-
-#ifdef CONFIG_EDAC_DEBUG
-extern int edac_debug_level;
-
-#define edac_debug_printk(level, fmt, arg...)                            \
-	do {                                                             \
-		if (level <= edac_debug_level)                           \
-			edac_printk(KERN_DEBUG, EDAC_DEBUG, fmt, ##arg); \
-	} while(0)
-
-#define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ )
-#define debugf1( ... ) edac_debug_printk(1, __VA_ARGS__ )
-#define debugf2( ... ) edac_debug_printk(2, __VA_ARGS__ )
-#define debugf3( ... ) edac_debug_printk(3, __VA_ARGS__ )
-#define debugf4( ... ) edac_debug_printk(4, __VA_ARGS__ )
-
-#else  /* !CONFIG_EDAC_DEBUG */
-
-#define debugf0( ... )
-#define debugf1( ... )
-#define debugf2( ... )
-#define debugf3( ... )
-#define debugf4( ... )
-
-#endif  /* !CONFIG_EDAC_DEBUG */
-
-#define BIT(x) (1 << (x))
-
-#define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \
-	PCI_DEVICE_ID_ ## vend ## _ ## dev
-
-#if defined(CONFIG_X86) && defined(CONFIG_PCI)
-#define dev_name(dev) pci_name(to_pci_dev(dev))
-#else
-#define dev_name(dev) to_platform_device(dev)->name
-#endif
-
-/* memory devices */
-enum dev_type {
-	DEV_UNKNOWN = 0,
-	DEV_X1,
-	DEV_X2,
-	DEV_X4,
-	DEV_X8,
-	DEV_X16,
-	DEV_X32,		/* Do these parts exist? */
-	DEV_X64			/* Do these parts exist? */
-};
-
-#define DEV_FLAG_UNKNOWN	BIT(DEV_UNKNOWN)
-#define DEV_FLAG_X1		BIT(DEV_X1)
-#define DEV_FLAG_X2		BIT(DEV_X2)
-#define DEV_FLAG_X4		BIT(DEV_X4)
-#define DEV_FLAG_X8		BIT(DEV_X8)
-#define DEV_FLAG_X16		BIT(DEV_X16)
-#define DEV_FLAG_X32		BIT(DEV_X32)
-#define DEV_FLAG_X64		BIT(DEV_X64)
-
-/* memory types */
-enum mem_type {
-	MEM_EMPTY = 0,		/* Empty csrow */
-	MEM_RESERVED,		/* Reserved csrow type */
-	MEM_UNKNOWN,		/* Unknown csrow type */
-	MEM_FPM,		/* Fast page mode */
-	MEM_EDO,		/* Extended data out */
-	MEM_BEDO,		/* Burst Extended data out */
-	MEM_SDR,		/* Single data rate SDRAM */
-	MEM_RDR,		/* Registered single data rate SDRAM */
-	MEM_DDR,		/* Double data rate SDRAM */
-	MEM_RDDR,		/* Registered Double data rate SDRAM */
-	MEM_RMBS,		/* Rambus DRAM */
-	MEM_DDR2,               /* DDR2 RAM */
-	MEM_FB_DDR2,            /* fully buffered DDR2 */
-};
-
-#define MEM_FLAG_EMPTY		BIT(MEM_EMPTY)
-#define MEM_FLAG_RESERVED	BIT(MEM_RESERVED)
-#define MEM_FLAG_UNKNOWN	BIT(MEM_UNKNOWN)
-#define MEM_FLAG_FPM		BIT(MEM_FPM)
-#define MEM_FLAG_EDO		BIT(MEM_EDO)
-#define MEM_FLAG_BEDO		BIT(MEM_BEDO)
-#define MEM_FLAG_SDR		BIT(MEM_SDR)
-#define MEM_FLAG_RDR		BIT(MEM_RDR)
-#define MEM_FLAG_DDR		BIT(MEM_DDR)
-#define MEM_FLAG_RDDR		BIT(MEM_RDDR)
-#define MEM_FLAG_RMBS		BIT(MEM_RMBS)
-#define MEM_FLAG_DDR2           BIT(MEM_DDR2)
-#define MEM_FLAG_FB_DDR2        BIT(MEM_FB_DDR2)
-
-/* chipset Error Detection and Correction capabilities and mode */
-enum edac_type {
-	EDAC_UNKNOWN = 0,	/* Unknown if ECC is available */
-	EDAC_NONE,		/* Doesnt support ECC */
-	EDAC_RESERVED,		/* Reserved ECC type */
-	EDAC_PARITY,		/* Detects parity errors */
-	EDAC_EC,		/* Error Checking - no correction */
-	EDAC_SECDED,		/* Single bit error correction, Double detection */
-	EDAC_S2ECD2ED,		/* Chipkill x2 devices - do these exist? */
-	EDAC_S4ECD4ED,		/* Chipkill x4 devices */
-	EDAC_S8ECD8ED,		/* Chipkill x8 devices */
-	EDAC_S16ECD16ED,	/* Chipkill x16 devices */
-};
-
-#define EDAC_FLAG_UNKNOWN	BIT(EDAC_UNKNOWN)
-#define EDAC_FLAG_NONE		BIT(EDAC_NONE)
-#define EDAC_FLAG_PARITY	BIT(EDAC_PARITY)
-#define EDAC_FLAG_EC		BIT(EDAC_EC)
-#define EDAC_FLAG_SECDED	BIT(EDAC_SECDED)
-#define EDAC_FLAG_S2ECD2ED	BIT(EDAC_S2ECD2ED)
-#define EDAC_FLAG_S4ECD4ED	BIT(EDAC_S4ECD4ED)
-#define EDAC_FLAG_S8ECD8ED	BIT(EDAC_S8ECD8ED)
-#define EDAC_FLAG_S16ECD16ED	BIT(EDAC_S16ECD16ED)
-
-/* scrubbing capabilities */
-enum scrub_type {
-	SCRUB_UNKNOWN = 0,	/* Unknown if scrubber is available */
-	SCRUB_NONE,		/* No scrubber */
-	SCRUB_SW_PROG,		/* SW progressive (sequential) scrubbing */
-	SCRUB_SW_SRC,		/* Software scrub only errors */
-	SCRUB_SW_PROG_SRC,	/* Progressive software scrub from an error */
-	SCRUB_SW_TUNABLE,	/* Software scrub frequency is tunable */
-	SCRUB_HW_PROG,		/* HW progressive (sequential) scrubbing */
-	SCRUB_HW_SRC,		/* Hardware scrub only errors */
-	SCRUB_HW_PROG_SRC,	/* Progressive hardware scrub from an error */
-	SCRUB_HW_TUNABLE	/* Hardware scrub frequency is tunable */
-};
-
-#define SCRUB_FLAG_SW_PROG	BIT(SCRUB_SW_PROG)
-#define SCRUB_FLAG_SW_SRC	BIT(SCRUB_SW_SRC_CORR)
-#define SCRUB_FLAG_SW_PROG_SRC	BIT(SCRUB_SW_PROG_SRC_CORR)
-#define SCRUB_FLAG_SW_TUN	BIT(SCRUB_SW_SCRUB_TUNABLE)
-#define SCRUB_FLAG_HW_PROG	BIT(SCRUB_HW_PROG)
-#define SCRUB_FLAG_HW_SRC	BIT(SCRUB_HW_SRC_CORR)
-#define SCRUB_FLAG_HW_PROG_SRC	BIT(SCRUB_HW_PROG_SRC_CORR)
-#define SCRUB_FLAG_HW_TUN	BIT(SCRUB_HW_TUNABLE)
-
-/* FIXME - should have notify capabilities: NMI, LOG, PROC, etc */
-
-/*
- * There are several things to be aware of that aren't at all obvious:
- *
- *
- * SOCKETS, SOCKET SETS, BANKS, ROWS, CHIP-SELECT ROWS, CHANNELS, etc..
- *
- * These are some of the many terms that are thrown about that don't always
- * mean what people think they mean (Inconceivable!).  In the interest of
- * creating a common ground for discussion, terms and their definitions
- * will be established.
- *
- * Memory devices:	The individual chip on a memory stick.  These devices
- *			commonly output 4 and 8 bits each.  Grouping several
- *			of these in parallel provides 64 bits which is common
- *			for a memory stick.
- *
- * Memory Stick:	A printed circuit board that agregates multiple
- *			memory devices in parallel.  This is the atomic
- *			memory component that is purchaseable by Joe consumer
- *			and loaded into a memory socket.
- *
- * Socket:		A physical connector on the motherboard that accepts
- *			a single memory stick.
- *
- * Channel:		Set of memory devices on a memory stick that must be
- *			grouped in parallel with one or more additional
- *			channels from other memory sticks.  This parallel
- *			grouping of the output from multiple channels are
- *			necessary for the smallest granularity of memory access.
- *			Some memory controllers are capable of single channel -
- *			which means that memory sticks can be loaded
- *			individually.  Other memory controllers are only
- *			capable of dual channel - which means that memory
- *			sticks must be loaded as pairs (see "socket set").
- *
- * Chip-select row:	All of the memory devices that are selected together.
- *			for a single, minimum grain of memory access.
- *			This selects all of the parallel memory devices across
- *			all of the parallel channels.  Common chip-select rows
- *			for single channel are 64 bits, for dual channel 128
- *			bits.
- *
- * Single-Ranked stick:	A Single-ranked stick has 1 chip-select row of memmory.
- *			Motherboards commonly drive two chip-select pins to
- *			a memory stick. A single-ranked stick, will occupy
- *			only one of those rows. The other will be unused.
- *
- * Double-Ranked stick:	A double-ranked stick has two chip-select rows which
- *			access different sets of memory devices.  The two
- *			rows cannot be accessed concurrently.
- *
- * Double-sided stick:	DEPRECATED TERM, see Double-Ranked stick.
- *			A double-sided stick has two chip-select rows which
- *			access different sets of memory devices.  The two
- *			rows cannot be accessed concurrently.  "Double-sided"
- *			is irrespective of the memory devices being mounted
- *			on both sides of the memory stick.
- *
- * Socket set:		All of the memory sticks that are required for for
- *			a single memory access or all of the memory sticks
- *			spanned by a chip-select row.  A single socket set
- *			has two chip-select rows and if double-sided sticks
- *			are used these will occupy those chip-select rows.
- *
- * Bank:		This term is avoided because it is unclear when
- *			needing to distinguish between chip-select rows and
- *			socket sets.
- *
- * Controller pages:
- *
- * Physical pages:
- *
- * Virtual pages:
- *
- *
- * STRUCTURE ORGANIZATION AND CHOICES
- *
- *
- *
- * PS - I enjoyed writing all that about as much as you enjoyed reading it.
- */
-
-struct channel_info {
-	int chan_idx;		/* channel index */
-	u32 ce_count;		/* Correctable Errors for this CHANNEL */
-	char label[EDAC_MC_LABEL_LEN + 1];  /* DIMM label on motherboard */
-	struct csrow_info *csrow;	/* the parent */
-};
-
-struct csrow_info {
-	unsigned long first_page;	/* first page number in dimm */
-	unsigned long last_page;	/* last page number in dimm */
-	unsigned long page_mask;	/* used for interleaving -
-					 * 0UL for non intlv
-					 */
-	u32 nr_pages;		/* number of pages in csrow */
-	u32 grain;		/* granularity of reported error in bytes */
-	int csrow_idx;		/* the chip-select row */
-	enum dev_type dtype;	/* memory device type */
-	u32 ue_count;		/* Uncorrectable Errors for this csrow */
-	u32 ce_count;		/* Correctable Errors for this csrow */
-	enum mem_type mtype;	/* memory csrow type */
-	enum edac_type edac_mode;	/* EDAC mode for this csrow */
-	struct mem_ctl_info *mci;	/* the parent */
-
-	struct kobject kobj;	/* sysfs kobject for this csrow */
-	struct completion kobj_complete;
-
-	/* FIXME the number of CHANNELs might need to become dynamic */
-	u32 nr_channels;
-	struct channel_info *channels;
-};
-
-struct mem_ctl_info {
-	struct list_head link;  /* for global list of mem_ctl_info structs */
-	unsigned long mtype_cap;	/* memory types supported by mc */
-	unsigned long edac_ctl_cap;	/* Mem controller EDAC capabilities */
-	unsigned long edac_cap;	/* configuration capabilities - this is
-				 * closely related to edac_ctl_cap.  The
-				 * difference is that the controller may be
-				 * capable of s4ecd4ed which would be listed
-				 * in edac_ctl_cap, but if channels aren't
-				 * capable of s4ecd4ed then the edac_cap would
-				 * not have that capability.
-				 */
-	unsigned long scrub_cap;	/* chipset scrub capabilities */
-	enum scrub_type scrub_mode;	/* current scrub mode */
-
-	/* Translates sdram memory scrub rate given in bytes/sec to the
-	   internal representation and configures whatever else needs
-	   to be configured.
-	*/
-	int (*set_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw);
-
-	/* Get the current sdram memory scrub rate from the internal
-	   representation and converts it to the closest matching
-	   bandwith in bytes/sec.
-	*/
-	int (*get_sdram_scrub_rate) (struct mem_ctl_info *mci, u32 *bw);
-
-	/* pointer to edac checking routine */
-	void (*edac_check) (struct mem_ctl_info * mci);
-
-	/*
-	 * Remaps memory pages: controller pages to physical pages.
-	 * For most MC's, this will be NULL.
-	 */
-	/* FIXME - why not send the phys page to begin with? */
-	unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci,
-					unsigned long page);
-	int mc_idx;
-	int nr_csrows;
-	struct csrow_info *csrows;
-	/*
-	 * FIXME - what about controllers on other busses? - IDs must be
-	 * unique.  dev pointer should be sufficiently unique, but
-	 * BUS:SLOT.FUNC numbers may not be unique.
-	 */
-	struct device *dev;
-	const char *mod_name;
-	const char *mod_ver;
-	const char *ctl_name;
-	char proc_name[MC_PROC_NAME_MAX_LEN + 1];
-	void *pvt_info;
-	u32 ue_noinfo_count;	/* Uncorrectable Errors w/o info */
-	u32 ce_noinfo_count;	/* Correctable Errors w/o info */
-	u32 ue_count;		/* Total Uncorrectable Errors for this MC */
-	u32 ce_count;		/* Total Correctable Errors for this MC */
-	unsigned long start_time;	/* mci load start time (in jiffies) */
-
-	/* this stuff is for safe removal of mc devices from global list while
-	 * NMI handlers may be traversing list
-	 */
-	struct rcu_head rcu;
-	struct completion complete;
-
-	/* edac sysfs device control */
-	struct kobject edac_mci_kobj;
-	struct completion kobj_complete;
-};
-
-#ifdef CONFIG_PCI
-
-/* write all or some bits in a byte-register*/
-static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value,
-		u8 mask)
-{
-	if (mask != 0xff) {
-		u8 buf;
-
-		pci_read_config_byte(pdev, offset, &buf);
-		value &= mask;
-		buf &= ~mask;
-		value |= buf;
-	}
-
-	pci_write_config_byte(pdev, offset, value);
-}
-
-/* write all or some bits in a word-register*/
-static inline void pci_write_bits16(struct pci_dev *pdev, int offset,
-		u16 value, u16 mask)
-{
-	if (mask != 0xffff) {
-		u16 buf;
-
-		pci_read_config_word(pdev, offset, &buf);
-		value &= mask;
-		buf &= ~mask;
-		value |= buf;
-	}
-
-	pci_write_config_word(pdev, offset, value);
-}
-
-/* write all or some bits in a dword-register*/
-static inline void pci_write_bits32(struct pci_dev *pdev, int offset,
-		u32 value, u32 mask)
-{
-	if (mask != 0xffff) {
-		u32 buf;
-
-		pci_read_config_dword(pdev, offset, &buf);
-		value &= mask;
-		buf &= ~mask;
-		value |= buf;
-	}
-
-	pci_write_config_dword(pdev, offset, value);
-}
-
-#endif /* CONFIG_PCI */
-
-#ifdef CONFIG_EDAC_DEBUG
-void edac_mc_dump_channel(struct channel_info *chan);
-void edac_mc_dump_mci(struct mem_ctl_info *mci);
-void edac_mc_dump_csrow(struct csrow_info *csrow);
-#endif  /* CONFIG_EDAC_DEBUG */
-
-extern int edac_mc_add_mc(struct mem_ctl_info *mci,int mc_idx);
-extern struct mem_ctl_info * edac_mc_del_mc(struct device *dev);
-extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci,
-					unsigned long page);
-extern void edac_mc_scrub_block(unsigned long page, unsigned long offset,
-		u32 size);
-
-/*
- * The no info errors are used when error overflows are reported.
- * There are a limited number of error logging registers that can
- * be exausted.  When all registers are exhausted and an additional
- * error occurs then an error overflow register records that an
- * error occured and the type of error, but doesn't have any
- * further information.  The ce/ue versions make for cleaner
- * reporting logic and function interface - reduces conditional
- * statement clutter and extra function arguments.
- */
-extern void edac_mc_handle_ce(struct mem_ctl_info *mci,
-		unsigned long page_frame_number, unsigned long offset_in_page,
-		unsigned long syndrome, int row, int channel,
-		const char *msg);
-extern void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci,
-		const char *msg);
-extern void edac_mc_handle_ue(struct mem_ctl_info *mci,
-		unsigned long page_frame_number, unsigned long offset_in_page,
-		int row, const char *msg);
-extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci,
-		const char *msg);
-extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
-		unsigned int csrow,
-		unsigned int channel0,
-		unsigned int channel1,
-		char *msg);
-extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
-		unsigned int csrow,
-		unsigned int channel,
-		char *msg);
-
-/*
- * This kmalloc's and initializes all the structures.
- * Can't be used if all structures don't have the same lifetime.
- */
-extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
-		unsigned nr_chans);
-
-/* Free an mc previously allocated by edac_mc_alloc() */
-extern void edac_mc_free(struct mem_ctl_info *mci);
-
-#endif				/* _EDAC_MC_H_ */
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
new file mode 100644
index 0000000..3706b2b
--- /dev/null
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -0,0 +1,1042 @@
+/*
+ * edac_mc kernel module
+ * (C) 2005-2007 Linux Networx (http://lnxi.com)
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written Doug Thompson <norsk5@xmission.com> www.softwarebitmaker.com
+ *
+ */
+
+#include <linux/ctype.h>
+#include <linux/bug.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+
+/* MC EDAC Controls, setable by module parameter, and sysfs */
+static int edac_mc_log_ue = 1;
+static int edac_mc_log_ce = 1;
+static int edac_mc_panic_on_ue;
+static int edac_mc_poll_msec = 1000;
+
+/* Getter functions for above */
+int edac_mc_get_log_ue(void)
+{
+	return edac_mc_log_ue;
+}
+
+int edac_mc_get_log_ce(void)
+{
+	return edac_mc_log_ce;
+}
+
+int edac_mc_get_panic_on_ue(void)
+{
+	return edac_mc_panic_on_ue;
+}
+
+/* this is temporary */
+int edac_mc_get_poll_msec(void)
+{
+	return edac_mc_poll_msec;
+}
+
+/* Parameter declarations for above */
+module_param(edac_mc_panic_on_ue, int, 0644);
+MODULE_PARM_DESC(edac_mc_panic_on_ue, "Panic on uncorrected error: 0=off 1=on");
+module_param(edac_mc_log_ue, int, 0644);
+MODULE_PARM_DESC(edac_mc_log_ue,
+		 "Log uncorrectable error to console: 0=off 1=on");
+module_param(edac_mc_log_ce, int, 0644);
+MODULE_PARM_DESC(edac_mc_log_ce,
+		 "Log correctable error to console: 0=off 1=on");
+module_param(edac_mc_poll_msec, int, 0644);
+MODULE_PARM_DESC(edac_mc_poll_msec, "Polling period in milliseconds");
+
+/*
+ * various constants for Memory Controllers
+ */
+static const char *mem_types[] = {
+	[MEM_EMPTY] = "Empty",
+	[MEM_RESERVED] = "Reserved",
+	[MEM_UNKNOWN] = "Unknown",
+	[MEM_FPM] = "FPM",
+	[MEM_EDO] = "EDO",
+	[MEM_BEDO] = "BEDO",
+	[MEM_SDR] = "Unbuffered-SDR",
+	[MEM_RDR] = "Registered-SDR",
+	[MEM_DDR] = "Unbuffered-DDR",
+	[MEM_RDDR] = "Registered-DDR",
+	[MEM_RMBS] = "RMBS",
+	[MEM_DDR2] = "Unbuffered-DDR2",
+	[MEM_FB_DDR2] = "FullyBuffered-DDR2",
+	[MEM_RDDR2] = "Registered-DDR2"
+};
+
+static const char *dev_types[] = {
+	[DEV_UNKNOWN] = "Unknown",
+	[DEV_X1] = "x1",
+	[DEV_X2] = "x2",
+	[DEV_X4] = "x4",
+	[DEV_X8] = "x8",
+	[DEV_X16] = "x16",
+	[DEV_X32] = "x32",
+	[DEV_X64] = "x64"
+};
+
+static const char *edac_caps[] = {
+	[EDAC_UNKNOWN] = "Unknown",
+	[EDAC_NONE] = "None",
+	[EDAC_RESERVED] = "Reserved",
+	[EDAC_PARITY] = "PARITY",
+	[EDAC_EC] = "EC",
+	[EDAC_SECDED] = "SECDED",
+	[EDAC_S2ECD2ED] = "S2ECD2ED",
+	[EDAC_S4ECD4ED] = "S4ECD4ED",
+	[EDAC_S8ECD8ED] = "S8ECD8ED",
+	[EDAC_S16ECD16ED] = "S16ECD16ED"
+};
+
+
+
+/*
+ * /sys/devices/system/edac/mc;
+ *	data structures and methods
+ */
+static ssize_t memctrl_int_show(void *ptr, char *buffer)
+{
+	int *value = (int *)ptr;
+	return sprintf(buffer, "%u\n", *value);
+}
+
+static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count)
+{
+	int *value = (int *)ptr;
+
+	if (isdigit(*buffer))
+		*value = simple_strtoul(buffer, NULL, 0);
+
+	return count;
+}
+
+/*
+ * mc poll_msec time value
+ */
+static ssize_t poll_msec_int_store(void *ptr, const char *buffer, size_t count)
+{
+	int *value = (int *)ptr;
+
+	if (isdigit(*buffer)) {
+		*value = simple_strtoul(buffer, NULL, 0);
+
+		/* notify edac_mc engine to reset the poll period */
+		edac_mc_reset_delay_period(*value);
+	}
+
+	return count;
+}
+
+
+/* EDAC sysfs CSROW data structures and methods
+ */
+
+/* Set of more default csrow<id> attribute show/store functions */
+static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data,
+				int private)
+{
+	return sprintf(data, "%u\n", csrow->ue_count);
+}
+
+static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data,
+				int private)
+{
+	return sprintf(data, "%u\n", csrow->ce_count);
+}
+
+static ssize_t csrow_size_show(struct csrow_info *csrow, char *data,
+				int private)
+{
+	return sprintf(data, "%u\n", PAGES_TO_MiB(csrow->nr_pages));
+}
+
+static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data,
+				int private)
+{
+	return sprintf(data, "%s\n", mem_types[csrow->mtype]);
+}
+
+static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data,
+				int private)
+{
+	return sprintf(data, "%s\n", dev_types[csrow->dtype]);
+}
+
+static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data,
+				int private)
+{
+	return sprintf(data, "%s\n", edac_caps[csrow->edac_mode]);
+}
+
+/* show/store functions for DIMM Label attributes */
+static ssize_t channel_dimm_label_show(struct csrow_info *csrow,
+				char *data, int channel)
+{
+	return snprintf(data, EDAC_MC_LABEL_LEN, "%s",
+			csrow->channels[channel].label);
+}
+
+static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
+					const char *data,
+					size_t count, int channel)
+{
+	ssize_t max_size = 0;
+
+	max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1);
+	strncpy(csrow->channels[channel].label, data, max_size);
+	csrow->channels[channel].label[max_size] = '\0';
+
+	return max_size;
+}
+
+/* show function for dynamic chX_ce_count attribute */
+static ssize_t channel_ce_count_show(struct csrow_info *csrow,
+				char *data, int channel)
+{
+	return sprintf(data, "%u\n", csrow->channels[channel].ce_count);
+}
+
+/* csrow specific attribute structure */
+struct csrowdev_attribute {
+	struct attribute attr;
+	 ssize_t(*show) (struct csrow_info *, char *, int);
+	 ssize_t(*store) (struct csrow_info *, const char *, size_t, int);
+	int private;
+};
+
+#define to_csrow(k) container_of(k, struct csrow_info, kobj)
+#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr)
+
+/* Set of show/store higher level functions for default csrow attributes */
+static ssize_t csrowdev_show(struct kobject *kobj,
+			struct attribute *attr, char *buffer)
+{
+	struct csrow_info *csrow = to_csrow(kobj);
+	struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
+
+	if (csrowdev_attr->show)
+		return csrowdev_attr->show(csrow,
+					buffer, csrowdev_attr->private);
+	return -EIO;
+}
+
+static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
+			const char *buffer, size_t count)
+{
+	struct csrow_info *csrow = to_csrow(kobj);
+	struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
+
+	if (csrowdev_attr->store)
+		return csrowdev_attr->store(csrow,
+					buffer,
+					count, csrowdev_attr->private);
+	return -EIO;
+}
+
+static struct sysfs_ops csrowfs_ops = {
+	.show = csrowdev_show,
+	.store = csrowdev_store
+};
+
+#define CSROWDEV_ATTR(_name,_mode,_show,_store,_private)	\
+static struct csrowdev_attribute attr_##_name = {			\
+	.attr = {.name = __stringify(_name), .mode = _mode },	\
+	.show   = _show,					\
+	.store  = _store,					\
+	.private = _private,					\
+};
+
+/* default cwrow<id>/attribute files */
+CSROWDEV_ATTR(size_mb, S_IRUGO, csrow_size_show, NULL, 0);
+CSROWDEV_ATTR(dev_type, S_IRUGO, csrow_dev_type_show, NULL, 0);
+CSROWDEV_ATTR(mem_type, S_IRUGO, csrow_mem_type_show, NULL, 0);
+CSROWDEV_ATTR(edac_mode, S_IRUGO, csrow_edac_mode_show, NULL, 0);
+CSROWDEV_ATTR(ue_count, S_IRUGO, csrow_ue_count_show, NULL, 0);
+CSROWDEV_ATTR(ce_count, S_IRUGO, csrow_ce_count_show, NULL, 0);
+
+/* default attributes of the CSROW<id> object */
+static struct csrowdev_attribute *default_csrow_attr[] = {
+	&attr_dev_type,
+	&attr_mem_type,
+	&attr_edac_mode,
+	&attr_size_mb,
+	&attr_ue_count,
+	&attr_ce_count,
+	NULL,
+};
+
+/* possible dynamic channel DIMM Label attribute files */
+CSROWDEV_ATTR(ch0_dimm_label, S_IRUGO | S_IWUSR,
+	channel_dimm_label_show, channel_dimm_label_store, 0);
+CSROWDEV_ATTR(ch1_dimm_label, S_IRUGO | S_IWUSR,
+	channel_dimm_label_show, channel_dimm_label_store, 1);
+CSROWDEV_ATTR(ch2_dimm_label, S_IRUGO | S_IWUSR,
+	channel_dimm_label_show, channel_dimm_label_store, 2);
+CSROWDEV_ATTR(ch3_dimm_label, S_IRUGO | S_IWUSR,
+	channel_dimm_label_show, channel_dimm_label_store, 3);
+CSROWDEV_ATTR(ch4_dimm_label, S_IRUGO | S_IWUSR,
+	channel_dimm_label_show, channel_dimm_label_store, 4);
+CSROWDEV_ATTR(ch5_dimm_label, S_IRUGO | S_IWUSR,
+	channel_dimm_label_show, channel_dimm_label_store, 5);
+
+/* Total possible dynamic DIMM Label attribute file table */
+static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = {
+	&attr_ch0_dimm_label,
+	&attr_ch1_dimm_label,
+	&attr_ch2_dimm_label,
+	&attr_ch3_dimm_label,
+	&attr_ch4_dimm_label,
+	&attr_ch5_dimm_label
+};
+
+/* possible dynamic channel ce_count attribute files */
+CSROWDEV_ATTR(ch0_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 0);
+CSROWDEV_ATTR(ch1_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 1);
+CSROWDEV_ATTR(ch2_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 2);
+CSROWDEV_ATTR(ch3_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 3);
+CSROWDEV_ATTR(ch4_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 4);
+CSROWDEV_ATTR(ch5_ce_count, S_IRUGO | S_IWUSR, channel_ce_count_show, NULL, 5);
+
+/* Total possible dynamic ce_count attribute file table */
+static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = {
+	&attr_ch0_ce_count,
+	&attr_ch1_ce_count,
+	&attr_ch2_ce_count,
+	&attr_ch3_ce_count,
+	&attr_ch4_ce_count,
+	&attr_ch5_ce_count
+};
+
+#define EDAC_NR_CHANNELS	6
+
+/* Create dynamic CHANNEL files, indexed by 'chan',  under specifed CSROW */
+static int edac_create_channel_files(struct kobject *kobj, int chan)
+{
+	int err = -ENODEV;
+
+	if (chan >= EDAC_NR_CHANNELS)
+		return err;
+
+	/* create the DIMM label attribute file */
+	err = sysfs_create_file(kobj,
+				(struct attribute *)
+				dynamic_csrow_dimm_attr[chan]);
+
+	if (!err) {
+		/* create the CE Count attribute file */
+		err = sysfs_create_file(kobj,
+					(struct attribute *)
+					dynamic_csrow_ce_count_attr[chan]);
+	} else {
+		debugf1("%s()  dimm labels and ce_count files created",
+			__func__);
+	}
+
+	return err;
+}
+
+/* No memory to release for this kobj */
+static void edac_csrow_instance_release(struct kobject *kobj)
+{
+	struct mem_ctl_info *mci;
+	struct csrow_info *cs;
+
+	debugf1("%s()\n", __func__);
+
+	cs = container_of(kobj, struct csrow_info, kobj);
+	mci = cs->mci;
+
+	kobject_put(&mci->edac_mci_kobj);
+}
+
+/* the kobj_type instance for a CSROW */
+static struct kobj_type ktype_csrow = {
+	.release = edac_csrow_instance_release,
+	.sysfs_ops = &csrowfs_ops,
+	.default_attrs = (struct attribute **)default_csrow_attr,
+};
+
+/* Create a CSROW object under specifed edac_mc_device */
+static int edac_create_csrow_object(struct mem_ctl_info *mci,
+					struct csrow_info *csrow, int index)
+{
+	struct kobject *kobj_mci = &mci->edac_mci_kobj;
+	struct kobject *kobj;
+	int chan;
+	int err;
+
+	/* generate ..../edac/mc/mc<id>/csrow<index>   */
+	memset(&csrow->kobj, 0, sizeof(csrow->kobj));
+	csrow->mci = mci;	/* include container up link */
+	csrow->kobj.parent = kobj_mci;
+	csrow->kobj.ktype = &ktype_csrow;
+
+	/* name this instance of csrow<id> */
+	err = kobject_set_name(&csrow->kobj, "csrow%d", index);
+	if (err)
+		goto err_out;
+
+	/* bump the mci instance's kobject's ref count */
+	kobj = kobject_get(&mci->edac_mci_kobj);
+	if (!kobj) {
+		err = -ENODEV;
+		goto err_out;
+	}
+
+	/* Instanstiate the csrow object */
+	err = kobject_register(&csrow->kobj);
+	if (err)
+		goto err_release_top_kobj;
+
+	/* At this point, to release a csrow kobj, one must
+	 * call the kobject_unregister and allow that tear down
+	 * to work the releasing
+	 */
+
+	/* Create the dyanmic attribute files on this csrow,
+	 * namely, the DIMM labels and the channel ce_count
+	 */
+	for (chan = 0; chan < csrow->nr_channels; chan++) {
+		err = edac_create_channel_files(&csrow->kobj, chan);
+		if (err) {
+			/* special case the unregister here */
+			kobject_unregister(&csrow->kobj);
+			goto err_out;
+		}
+	}
+
+	return 0;
+
+	/* error unwind stack */
+err_release_top_kobj:
+	kobject_put(&mci->edac_mci_kobj);
+
+err_out:
+	return err;
+}
+
+/* default sysfs methods and data structures for the main MCI kobject */
+
+static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
+					const char *data, size_t count)
+{
+	int row, chan;
+
+	mci->ue_noinfo_count = 0;
+	mci->ce_noinfo_count = 0;
+	mci->ue_count = 0;
+	mci->ce_count = 0;
+
+	for (row = 0; row < mci->nr_csrows; row++) {
+		struct csrow_info *ri = &mci->csrows[row];
+
+		ri->ue_count = 0;
+		ri->ce_count = 0;
+
+		for (chan = 0; chan < ri->nr_channels; chan++)
+			ri->channels[chan].ce_count = 0;
+	}
+
+	mci->start_time = jiffies;
+	return count;
+}
+
+/* memory scrubbing */
+static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
+					const char *data, size_t count)
+{
+	u32 bandwidth = -1;
+
+	if (mci->set_sdram_scrub_rate) {
+
+		memctrl_int_store(&bandwidth, data, count);
+
+		if (!(*mci->set_sdram_scrub_rate) (mci, &bandwidth)) {
+			edac_printk(KERN_DEBUG, EDAC_MC,
+				"Scrub rate set successfully, applied: %d\n",
+				bandwidth);
+		} else {
+			/* FIXME: error codes maybe? */
+			edac_printk(KERN_DEBUG, EDAC_MC,
+				"Scrub rate set FAILED, could not apply: %d\n",
+				bandwidth);
+		}
+	} else {
+		/* FIXME: produce "not implemented" ERROR for user-side. */
+		edac_printk(KERN_WARNING, EDAC_MC,
+			"Memory scrubbing 'set'control is not implemented!\n");
+	}
+	return count;
+}
+
+static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
+{
+	u32 bandwidth = -1;
+
+	if (mci->get_sdram_scrub_rate) {
+		if (!(*mci->get_sdram_scrub_rate) (mci, &bandwidth)) {
+			edac_printk(KERN_DEBUG, EDAC_MC,
+				"Scrub rate successfully, fetched: %d\n",
+				bandwidth);
+		} else {
+			/* FIXME: error codes maybe? */
+			edac_printk(KERN_DEBUG, EDAC_MC,
+				"Scrub rate fetch FAILED, got: %d\n",
+				bandwidth);
+		}
+	} else {
+		/* FIXME: produce "not implemented" ERROR for user-side.  */
+		edac_printk(KERN_WARNING, EDAC_MC,
+			"Memory scrubbing 'get' control is not implemented\n");
+	}
+	return sprintf(data, "%d\n", bandwidth);
+}
+
+/* default attribute files for the MCI object */
+static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
+{
+	return sprintf(data, "%d\n", mci->ue_count);
+}
+
+static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data)
+{
+	return sprintf(data, "%d\n", mci->ce_count);
+}
+
+static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data)
+{
+	return sprintf(data, "%d\n", mci->ce_noinfo_count);
+}
+
+static ssize_t mci_ue_noinfo_show(struct mem_ctl_info *mci, char *data)
+{
+	return sprintf(data, "%d\n", mci->ue_noinfo_count);
+}
+
+static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data)
+{
+	return sprintf(data, "%ld\n", (jiffies - mci->start_time) / HZ);
+}
+
+static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data)
+{
+	return sprintf(data, "%s\n", mci->ctl_name);
+}
+
+static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
+{
+	int total_pages, csrow_idx;
+
+	for (total_pages = csrow_idx = 0; csrow_idx < mci->nr_csrows;
+		csrow_idx++) {
+		struct csrow_info *csrow = &mci->csrows[csrow_idx];
+
+		if (!csrow->nr_pages)
+			continue;
+
+		total_pages += csrow->nr_pages;
+	}
+
+	return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages));
+}
+
+#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj)
+#define to_mcidev_attr(a) container_of(a,struct mcidev_sysfs_attribute,attr)
+
+/* MCI show/store functions for top most object */
+static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
+			char *buffer)
+{
+	struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
+	struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+
+	if (mcidev_attr->show)
+		return mcidev_attr->show(mem_ctl_info, buffer);
+
+	return -EIO;
+}
+
+static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
+			const char *buffer, size_t count)
+{
+	struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
+	struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+
+	if (mcidev_attr->store)
+		return mcidev_attr->store(mem_ctl_info, buffer, count);
+
+	return -EIO;
+}
+
+/* Intermediate show/store table */
+static struct sysfs_ops mci_ops = {
+	.show = mcidev_show,
+	.store = mcidev_store
+};
+
+#define MCIDEV_ATTR(_name,_mode,_show,_store)			\
+static struct mcidev_sysfs_attribute mci_attr_##_name = {			\
+	.attr = {.name = __stringify(_name), .mode = _mode },	\
+	.show   = _show,					\
+	.store  = _store,					\
+};
+
+/* default Control file */
+MCIDEV_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
+
+/* default Attribute files */
+MCIDEV_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
+MCIDEV_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
+MCIDEV_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
+MCIDEV_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
+MCIDEV_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
+MCIDEV_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
+MCIDEV_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
+
+/* memory scrubber attribute file */
+MCIDEV_ATTR(sdram_scrub_rate, S_IRUGO | S_IWUSR, mci_sdram_scrub_rate_show,
+	mci_sdram_scrub_rate_store);
+
+static struct mcidev_sysfs_attribute *mci_attr[] = {
+	&mci_attr_reset_counters,
+	&mci_attr_mc_name,
+	&mci_attr_size_mb,
+	&mci_attr_seconds_since_reset,
+	&mci_attr_ue_noinfo_count,
+	&mci_attr_ce_noinfo_count,
+	&mci_attr_ue_count,
+	&mci_attr_ce_count,
+	&mci_attr_sdram_scrub_rate,
+	NULL
+};
+
+
+/*
+ * Release of a MC controlling instance
+ *
+ *	each MC control instance has the following resources upon entry:
+ *		a) a ref count on the top memctl kobj
+ *		b) a ref count on this module
+ *
+ *	this function must decrement those ref counts and then
+ *	issue a free on the instance's memory
+ */
+static void edac_mci_control_release(struct kobject *kobj)
+{
+	struct mem_ctl_info *mci;
+
+	mci = to_mci(kobj);
+
+	debugf0("%s() mci instance idx=%d releasing\n", __func__, mci->mc_idx);
+
+	/* decrement the module ref count */
+	module_put(mci->owner);
+
+	/* free the mci instance memory here */
+	kfree(mci);
+}
+
+static struct kobj_type ktype_mci = {
+	.release = edac_mci_control_release,
+	.sysfs_ops = &mci_ops,
+	.default_attrs = (struct attribute **)mci_attr,
+};
+
+/* show/store, tables, etc for the MC kset */
+
+
+struct memctrl_dev_attribute {
+	struct attribute attr;
+	void *value;
+	 ssize_t(*show) (void *, char *);
+	 ssize_t(*store) (void *, const char *, size_t);
+};
+
+/* Set of show/store abstract level functions for memory control object */
+static ssize_t memctrl_dev_show(struct kobject *kobj,
+				struct attribute *attr, char *buffer)
+{
+	struct memctrl_dev_attribute *memctrl_dev;
+	memctrl_dev = (struct memctrl_dev_attribute *)attr;
+
+	if (memctrl_dev->show)
+		return memctrl_dev->show(memctrl_dev->value, buffer);
+
+	return -EIO;
+}
+
+static ssize_t memctrl_dev_store(struct kobject *kobj, struct attribute *attr,
+				 const char *buffer, size_t count)
+{
+	struct memctrl_dev_attribute *memctrl_dev;
+	memctrl_dev = (struct memctrl_dev_attribute *)attr;
+
+	if (memctrl_dev->store)
+		return memctrl_dev->store(memctrl_dev->value, buffer, count);
+
+	return -EIO;
+}
+
+static struct sysfs_ops memctrlfs_ops = {
+	.show = memctrl_dev_show,
+	.store = memctrl_dev_store
+};
+
+#define MEMCTRL_ATTR(_name, _mode, _show, _store)			\
+static struct memctrl_dev_attribute attr_##_name = {			\
+	.attr = {.name = __stringify(_name), .mode = _mode },	\
+	.value  = &_name,					\
+	.show   = _show,					\
+	.store  = _store,					\
+};
+
+#define MEMCTRL_STRING_ATTR(_name, _data, _mode, _show, _store)	\
+static struct memctrl_dev_attribute attr_##_name = {			\
+	.attr = {.name = __stringify(_name), .mode = _mode },	\
+	.value  = _data,					\
+	.show   = _show,					\
+	.store  = _store,					\
+};
+
+/* csrow<id> control files */
+MEMCTRL_ATTR(edac_mc_panic_on_ue,
+	S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);
+
+MEMCTRL_ATTR(edac_mc_log_ue,
+	S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);
+
+MEMCTRL_ATTR(edac_mc_log_ce,
+	S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);
+
+MEMCTRL_ATTR(edac_mc_poll_msec,
+	S_IRUGO | S_IWUSR, memctrl_int_show, poll_msec_int_store);
+
+/* Base Attributes of the memory ECC object */
+static struct memctrl_dev_attribute *memctrl_attr[] = {
+	&attr_edac_mc_panic_on_ue,
+	&attr_edac_mc_log_ue,
+	&attr_edac_mc_log_ce,
+	&attr_edac_mc_poll_msec,
+	NULL,
+};
+
+
+/* the ktype for the mc_kset internal kobj */
+static struct kobj_type ktype_mc_set_attribs = {
+	.sysfs_ops = &memctrlfs_ops,
+	.default_attrs = (struct attribute **)memctrl_attr,
+};
+
+/* EDAC memory controller sysfs kset:
+ *	/sys/devices/system/edac/mc
+ */
+static struct kset mc_kset = {
+	.kobj = {.ktype = &ktype_mc_set_attribs },
+	.ktype = &ktype_mci,
+};
+
+
+/*
+ * edac_mc_register_sysfs_main_kobj
+ *
+ *	setups and registers the main kobject for each mci
+ */
+int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci)
+{
+	struct kobject *kobj_mci;
+	int err;
+
+	debugf1("%s()\n", __func__);
+
+	kobj_mci = &mci->edac_mci_kobj;
+
+	/* Init the mci's kobject */
+	memset(kobj_mci, 0, sizeof(*kobj_mci));
+
+	/* this instance become part of the mc_kset */
+	kobj_mci->kset = &mc_kset;
+
+	/* set the name of the mc<id> object */
+	err = kobject_set_name(kobj_mci, "mc%d", mci->mc_idx);
+	if (err)
+		goto fail_out;
+
+	/* Record which module 'owns' this control structure
+	 * and bump the ref count of the module
+	 */
+	mci->owner = THIS_MODULE;
+
+	/* bump ref count on this module */
+	if (!try_module_get(mci->owner)) {
+		err = -ENODEV;
+		goto fail_out;
+	}
+
+	/* register the mc<id> kobject to the mc_kset */
+	err = kobject_register(kobj_mci);
+	if (err) {
+		debugf1("%s()Failed to register '.../edac/mc%d'\n",
+			__func__, mci->mc_idx);
+		goto kobj_reg_fail;
+	}
+
+	/* At this point, to 'free' the control struct,
+	 * edac_mc_unregister_sysfs_main_kobj() must be used
+	 */
+
+	debugf1("%s() Registered '.../edac/mc%d' kobject\n",
+		__func__, mci->mc_idx);
+
+	return 0;
+
+	/* Error exit stack */
+
+kobj_reg_fail:
+	module_put(mci->owner);
+
+fail_out:
+	return err;
+}
+
+/*
+ * edac_mc_register_sysfs_main_kobj
+ *
+ *	tears down and the main mci kobject from the mc_kset
+ */
+void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
+{
+	/* delete the kobj from the mc_kset */
+	kobject_unregister(&mci->edac_mci_kobj);
+}
+
+#define EDAC_DEVICE_SYMLINK	"device"
+
+/*
+ * edac_create_mci_instance_attributes
+ *	create MC driver specific attributes at the topmost level
+ *	directory of this mci instance.
+ */
+static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci)
+{
+	int err;
+	struct mcidev_sysfs_attribute *sysfs_attrib;
+
+	/* point to the start of the array and iterate over it
+	 * adding each attribute listed to this mci instance's kobject
+	 */
+	sysfs_attrib = mci->mc_driver_sysfs_attributes;
+
+	while (sysfs_attrib && sysfs_attrib->attr.name) {
+		err = sysfs_create_file(&mci->edac_mci_kobj,
+					(struct attribute*) sysfs_attrib);
+		if (err) {
+			return err;
+		}
+
+		sysfs_attrib++;
+	}
+
+	return 0;
+}
+
+/*
+ * edac_remove_mci_instance_attributes
+ *	remove MC driver specific attributes at the topmost level
+ *	directory of this mci instance.
+ */
+static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci)
+{
+	struct mcidev_sysfs_attribute *sysfs_attrib;
+
+	/* point to the start of the array and iterate over it
+	 * adding each attribute listed to this mci instance's kobject
+	 */
+	sysfs_attrib = mci->mc_driver_sysfs_attributes;
+
+	/* loop if there are attributes and until we hit a NULL entry */
+	while (sysfs_attrib && sysfs_attrib->attr.name) {
+		sysfs_remove_file(&mci->edac_mci_kobj,
+					(struct attribute *) sysfs_attrib);
+		sysfs_attrib++;
+	}
+}
+
+
+/*
+ * Create a new Memory Controller kobject instance,
+ *	mc<id> under the 'mc' directory
+ *
+ * Return:
+ *	0	Success
+ *	!0	Failure
+ */
+int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
+{
+	int i;
+	int err;
+	struct csrow_info *csrow;
+	struct kobject *kobj_mci = &mci->edac_mci_kobj;
+
+	debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
+
+	/* create a symlink for the device */
+	err = sysfs_create_link(kobj_mci, &mci->dev->kobj,
+				EDAC_DEVICE_SYMLINK);
+	if (err) {
+		debugf1("%s() failure to create symlink\n", __func__);
+		goto fail0;
+	}
+
+	/* If the low level driver desires some attributes,
+	 * then create them now for the driver.
+	 */
+	if (mci->mc_driver_sysfs_attributes) {
+		err = edac_create_mci_instance_attributes(mci);
+		if (err) {
+			debugf1("%s() failure to create mci attributes\n",
+				__func__);
+			goto fail0;
+		}
+	}
+
+	/* Make directories for each CSROW object under the mc<id> kobject
+	 */
+	for (i = 0; i < mci->nr_csrows; i++) {
+		csrow = &mci->csrows[i];
+
+		/* Only expose populated CSROWs */
+		if (csrow->nr_pages > 0) {
+			err = edac_create_csrow_object(mci, csrow, i);
+			if (err) {
+				debugf1("%s() failure: create csrow %d obj\n",
+					__func__, i);
+				goto fail1;
+			}
+		}
+	}
+
+	return 0;
+
+	/* CSROW error: backout what has already been registered,  */
+fail1:
+	for (i--; i >= 0; i--) {
+		if (csrow->nr_pages > 0) {
+			kobject_unregister(&mci->csrows[i].kobj);
+		}
+	}
+
+	/* remove the mci instance's attributes, if any */
+	edac_remove_mci_instance_attributes(mci);
+
+	/* remove the symlink */
+	sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK);
+
+fail0:
+	return err;
+}
+
+/*
+ * remove a Memory Controller instance
+ */
+void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
+{
+	int i;
+
+	debugf0("%s()\n", __func__);
+
+	/* remove all csrow kobjects */
+	for (i = 0; i < mci->nr_csrows; i++) {
+		if (mci->csrows[i].nr_pages > 0) {
+			debugf0("%s()  unreg csrow-%d\n", __func__, i);
+			kobject_unregister(&mci->csrows[i].kobj);
+		}
+	}
+
+	debugf0("%s()  remove_link\n", __func__);
+
+	/* remove the symlink */
+	sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK);
+
+	debugf0("%s()  remove_mci_instance\n", __func__);
+
+	/* remove this mci instance's attribtes */
+	edac_remove_mci_instance_attributes(mci);
+
+	debugf0("%s()  unregister this mci kobj\n", __func__);
+
+	/* unregister this instance's kobject */
+	kobject_unregister(&mci->edac_mci_kobj);
+}
+
+
+
+
+/*
+ * edac_setup_sysfs_mc_kset(void)
+ *
+ * Initialize the mc_kset for the 'mc' entry
+ *	This requires creating the top 'mc' directory with a kset
+ *	and its controls/attributes.
+ *
+ *	To this 'mc' kset, instance 'mci' will be grouped as children.
+ *
+ * Return:  0 SUCCESS
+ *         !0 FAILURE error code
+ */
+int edac_sysfs_setup_mc_kset(void)
+{
+	int err = 0;
+	struct sysdev_class *edac_class;
+
+	debugf1("%s()\n", __func__);
+
+	/* get the /sys/devices/system/edac class reference */
+	edac_class = edac_get_edac_class();
+	if (edac_class == NULL) {
+		debugf1("%s() no edac_class error=%d\n", __func__, err);
+		goto fail_out;
+	}
+
+	/* Init the MC's kobject */
+	kobject_set_name(&mc_kset.kobj, "mc");
+	mc_kset.kobj.parent = &edac_class->kset.kobj;
+
+	/* register the mc_kset */
+	err = kset_register(&mc_kset);
+	if (err) {
+		debugf1("%s() Failed to register '.../edac/mc'\n", __func__);
+		goto fail_out;
+	}
+
+	debugf1("%s() Registered '.../edac/mc' kobject\n", __func__);
+
+	return 0;
+
+
+	/* error unwind stack */
+fail_out:
+	return err;
+}
+
+/*
+ * edac_sysfs_teardown_mc_kset
+ *
+ *	deconstruct the mc_ket for memory controllers
+ */
+void edac_sysfs_teardown_mc_kset(void)
+{
+	kset_unregister(&mc_kset);
+}
+
diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c
new file mode 100644
index 0000000..e0c4a40
--- /dev/null
+++ b/drivers/edac/edac_module.c
@@ -0,0 +1,222 @@
+/*
+ * edac_module.c
+ *
+ * (C) 2007 www.softwarebitmaker.com
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * Author: Doug Thompson <dougthompson@xmission.com>
+ *
+ */
+#include <linux/edac.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+#define EDAC_VERSION "Ver: 2.1.0 " __DATE__
+
+#ifdef CONFIG_EDAC_DEBUG
+/* Values of 0 to 4 will generate output */
+int edac_debug_level = 2;
+EXPORT_SYMBOL_GPL(edac_debug_level);
+#endif
+
+/* scope is to module level only */
+struct workqueue_struct *edac_workqueue;
+
+/*
+ * sysfs object: /sys/devices/system/edac
+ *	need to export to other files in this modules
+ */
+static struct sysdev_class edac_class = {
+	set_kset_name("edac"),
+};
+static int edac_class_valid;
+
+/*
+ * edac_op_state_to_string()
+ */
+char *edac_op_state_to_string(int opstate)
+{
+	if (opstate == OP_RUNNING_POLL)
+		return "POLLED";
+	else if (opstate == OP_RUNNING_INTERRUPT)
+		return "INTERRUPT";
+	else if (opstate == OP_RUNNING_POLL_INTR)
+		return "POLL-INTR";
+	else if (opstate == OP_ALLOC)
+		return "ALLOC";
+	else if (opstate == OP_OFFLINE)
+		return "OFFLINE";
+
+	return "UNKNOWN";
+}
+
+/*
+ * edac_get_edac_class()
+ *
+ *	return pointer to the edac class of 'edac'
+ */
+struct sysdev_class *edac_get_edac_class(void)
+{
+	struct sysdev_class *classptr = NULL;
+
+	if (edac_class_valid)
+		classptr = &edac_class;
+
+	return classptr;
+}
+
+/*
+ * edac_register_sysfs_edac_name()
+ *
+ *	register the 'edac' into /sys/devices/system
+ *
+ * return:
+ *	0  success
+ *	!0 error
+ */
+static int edac_register_sysfs_edac_name(void)
+{
+	int err;
+
+	/* create the /sys/devices/system/edac directory */
+	err = sysdev_class_register(&edac_class);
+
+	if (err) {
+		debugf1("%s() error=%d\n", __func__, err);
+		return err;
+	}
+
+	edac_class_valid = 1;
+	return 0;
+}
+
+/*
+ * sysdev_class_unregister()
+ *
+ *	unregister the 'edac' from /sys/devices/system
+ */
+static void edac_unregister_sysfs_edac_name(void)
+{
+	/* only if currently registered, then unregister it */
+	if (edac_class_valid)
+		sysdev_class_unregister(&edac_class);
+
+	edac_class_valid = 0;
+}
+
+/*
+ * edac_workqueue_setup
+ *	initialize the edac work queue for polling operations
+ */
+static int edac_workqueue_setup(void)
+{
+	edac_workqueue = create_singlethread_workqueue("edac-poller");
+	if (edac_workqueue == NULL)
+		return -ENODEV;
+	else
+		return 0;
+}
+
+/*
+ * edac_workqueue_teardown
+ *	teardown the edac workqueue
+ */
+static void edac_workqueue_teardown(void)
+{
+	if (edac_workqueue) {
+		flush_workqueue(edac_workqueue);
+		destroy_workqueue(edac_workqueue);
+		edac_workqueue = NULL;
+	}
+}
+
+/*
+ * edac_init
+ *      module initialization entry point
+ */
+static int __init edac_init(void)
+{
+	int err = 0;
+
+	edac_printk(KERN_INFO, EDAC_MC, EDAC_VERSION "\n");
+
+	/*
+	 * Harvest and clear any boot/initialization PCI parity errors
+	 *
+	 * FIXME: This only clears errors logged by devices present at time of
+	 *      module initialization.  We should also do an initial clear
+	 *      of each newly hotplugged device.
+	 */
+	edac_pci_clear_parity_errors();
+
+	/*
+	 * perform the registration of the /sys/devices/system/edac class object
+	 */
+	if (edac_register_sysfs_edac_name()) {
+		edac_printk(KERN_ERR, EDAC_MC,
+			"Error initializing 'edac' kobject\n");
+		err = -ENODEV;
+		goto error;
+	}
+
+	/*
+	 * now set up the mc_kset under the edac class object
+	 */
+	err = edac_sysfs_setup_mc_kset();
+	if (err)
+		goto sysfs_setup_fail;
+
+	/* Setup/Initialize the workq for this core */
+	err = edac_workqueue_setup();
+	if (err) {
+		edac_printk(KERN_ERR, EDAC_MC, "init WorkQueue failure\n");
+		goto workq_fail;
+	}
+
+	return 0;
+
+	/* Error teardown stack */
+workq_fail:
+	edac_sysfs_teardown_mc_kset();
+
+sysfs_setup_fail:
+	edac_unregister_sysfs_edac_name();
+
+error:
+	return err;
+}
+
+/*
+ * edac_exit()
+ *      module exit/termination function
+ */
+static void __exit edac_exit(void)
+{
+	debugf0("%s()\n", __func__);
+
+	/* tear down the various subsystems */
+	edac_workqueue_teardown();
+	edac_sysfs_teardown_mc_kset();
+	edac_unregister_sysfs_edac_name();
+}
+
+/*
+ * Inform the kernel of our entry and exit points
+ */
+module_init(edac_init);
+module_exit(edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Doug Thompson www.softwarebitmaker.com, et al");
+MODULE_DESCRIPTION("Core library routines for EDAC reporting");
+
+/* refer to *_sysfs.c files for parameters that are exported via sysfs */
+
+#ifdef CONFIG_EDAC_DEBUG
+module_param(edac_debug_level, int, 0644);
+MODULE_PARM_DESC(edac_debug_level, "Debug level");
+#endif
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h
new file mode 100644
index 0000000..cbc419c
--- /dev/null
+++ b/drivers/edac/edac_module.h
@@ -0,0 +1,85 @@
+
+/*
+ * edac_module.h
+ *
+ * For defining functions/data for within the EDAC_CORE module only
+ *
+ * written by doug thompson <norsk5@xmission.h>
+ */
+
+#ifndef	__EDAC_MODULE_H__
+#define	__EDAC_MODULE_H__
+
+#include <linux/sysdev.h>
+
+#include "edac_core.h"
+
+/*
+ * INTERNAL EDAC MODULE:
+ * EDAC memory controller sysfs create/remove functions
+ * and setup/teardown functions
+ *
+ * edac_mc objects
+ */
+extern int edac_sysfs_setup_mc_kset(void);
+extern void edac_sysfs_teardown_mc_kset(void);
+extern int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci);
+extern void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci);
+extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci);
+extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci);
+extern void edac_check_mc_devices(void);
+extern int edac_get_log_ue(void);
+extern int edac_get_log_ce(void);
+extern int edac_get_panic_on_ue(void);
+extern int edac_mc_get_log_ue(void);
+extern int edac_mc_get_log_ce(void);
+extern int edac_mc_get_panic_on_ue(void);
+extern int edac_get_poll_msec(void);
+extern int edac_mc_get_poll_msec(void);
+
+extern int edac_device_register_sysfs_main_kobj(
+				struct edac_device_ctl_info *edac_dev);
+extern void edac_device_unregister_sysfs_main_kobj(
+				struct edac_device_ctl_info *edac_dev);
+extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev);
+extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev);
+extern struct sysdev_class *edac_get_edac_class(void);
+
+/* edac core workqueue: single CPU mode */
+extern struct workqueue_struct *edac_workqueue;
+extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
+				    unsigned msec);
+extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev);
+extern void edac_device_reset_delay_period(struct edac_device_ctl_info
+					   *edac_dev, unsigned long value);
+extern void edac_mc_reset_delay_period(int value);
+
+extern void *edac_align_ptr(void *ptr, unsigned size);
+
+/*
+ * EDAC PCI functions
+ */
+#ifdef	CONFIG_PCI
+extern void edac_pci_do_parity_check(void);
+extern void edac_pci_clear_parity_errors(void);
+extern int edac_sysfs_pci_setup(void);
+extern void edac_sysfs_pci_teardown(void);
+extern int edac_pci_get_check_errors(void);
+extern int edac_pci_get_poll_msec(void);
+extern void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci);
+extern void edac_pci_handle_pe(struct edac_pci_ctl_info *pci, const char *msg);
+extern void edac_pci_handle_npe(struct edac_pci_ctl_info *pci,
+				const char *msg);
+#else				/* CONFIG_PCI */
+/* pre-process these away */
+#define edac_pci_do_parity_check()
+#define edac_pci_clear_parity_errors()
+#define edac_sysfs_pci_setup()  (0)
+#define edac_sysfs_pci_teardown()
+#define edac_pci_get_check_errors()
+#define edac_pci_get_poll_msec()
+#define edac_pci_handle_pe()
+#define edac_pci_handle_npe()
+#endif				/* CONFIG_PCI */
+
+#endif				/* __EDAC_MODULE_H__ */
diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c
new file mode 100644
index 0000000..5dee9f5
--- /dev/null
+++ b/drivers/edac/edac_pci.c
@@ -0,0 +1,493 @@
+/*
+ * EDAC PCI component
+ *
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/sysctl.h>
+#include <linux/highmem.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/sysdev.h>
+#include <linux/ctype.h>
+#include <linux/workqueue.h>
+#include <asm/uaccess.h>
+#include <asm/page.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+static DEFINE_MUTEX(edac_pci_ctls_mutex);
+static struct list_head edac_pci_list = LIST_HEAD_INIT(edac_pci_list);
+
+/*
+ * edac_pci_alloc_ctl_info
+ *
+ *	The alloc() function for the 'edac_pci' control info
+ *	structure. The chip driver will allocate one of these for each
+ *	edac_pci it is going to control/register with the EDAC CORE.
+ */
+struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt,
+						const char *edac_pci_name)
+{
+	struct edac_pci_ctl_info *pci;
+	void *pvt;
+	unsigned int size;
+
+	debugf1("%s()\n", __func__);
+
+	pci = (struct edac_pci_ctl_info *)0;
+	pvt = edac_align_ptr(&pci[1], sz_pvt);
+	size = ((unsigned long)pvt) + sz_pvt;
+
+	/* Alloc the needed control struct memory */
+	pci = kzalloc(size, GFP_KERNEL);
+	if (pci  == NULL)
+		return NULL;
+
+	/* Now much private space */
+	pvt = sz_pvt ? ((char *)pci) + ((unsigned long)pvt) : NULL;
+
+	pci->pvt_info = pvt;
+	pci->op_state = OP_ALLOC;
+
+	snprintf(pci->name, strlen(edac_pci_name) + 1, "%s", edac_pci_name);
+
+	return pci;
+}
+EXPORT_SYMBOL_GPL(edac_pci_alloc_ctl_info);
+
+/*
+ * edac_pci_free_ctl_info()
+ *
+ *	Last action on the pci control structure.
+ *
+ *	call the remove sysfs informaton, which will unregister
+ *	this control struct's kobj. When that kobj's ref count
+ *	goes to zero, its release function will be call and then
+ *	kfree() the memory.
+ */
+void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci)
+{
+	debugf1("%s()\n", __func__);
+
+	edac_pci_remove_sysfs(pci);
+}
+EXPORT_SYMBOL_GPL(edac_pci_free_ctl_info);
+
+/*
+ * find_edac_pci_by_dev()
+ * 	scans the edac_pci list for a specific 'struct device *'
+ *
+ *	return NULL if not found, or return control struct pointer
+ */
+static struct edac_pci_ctl_info *find_edac_pci_by_dev(struct device *dev)
+{
+	struct edac_pci_ctl_info *pci;
+	struct list_head *item;
+
+	debugf1("%s()\n", __func__);
+
+	list_for_each(item, &edac_pci_list) {
+		pci = list_entry(item, struct edac_pci_ctl_info, link);
+
+		if (pci->dev == dev)
+			return pci;
+	}
+
+	return NULL;
+}
+
+/*
+ * add_edac_pci_to_global_list
+ * 	Before calling this function, caller must assign a unique value to
+ * 	edac_dev->pci_idx.
+ * 	Return:
+ * 		0 on success
+ * 		1 on failure
+ */
+static int add_edac_pci_to_global_list(struct edac_pci_ctl_info *pci)
+{
+	struct list_head *item, *insert_before;
+	struct edac_pci_ctl_info *rover;
+
+	debugf1("%s()\n", __func__);
+
+	insert_before = &edac_pci_list;
+
+	/* Determine if already on the list */
+	rover = find_edac_pci_by_dev(pci->dev);
+	if (unlikely(rover != NULL))
+		goto fail0;
+
+	/* Insert in ascending order by 'pci_idx', so find position */
+	list_for_each(item, &edac_pci_list) {
+		rover = list_entry(item, struct edac_pci_ctl_info, link);
+
+		if (rover->pci_idx >= pci->pci_idx) {
+			if (unlikely(rover->pci_idx == pci->pci_idx))
+				goto fail1;
+
+			insert_before = item;
+			break;
+		}
+	}
+
+	list_add_tail_rcu(&pci->link, insert_before);
+	return 0;
+
+fail0:
+	edac_printk(KERN_WARNING, EDAC_PCI,
+		"%s (%s) %s %s already assigned %d\n",
+		rover->dev->bus_id, dev_name(rover),
+		rover->mod_name, rover->ctl_name, rover->pci_idx);
+	return 1;
+
+fail1:
+	edac_printk(KERN_WARNING, EDAC_PCI,
+		"but in low-level driver: attempt to assign\n"
+		"\tduplicate pci_idx %d in %s()\n", rover->pci_idx,
+		__func__);
+	return 1;
+}
+
+/*
+ * complete_edac_pci_list_del
+ *
+ *	RCU completion callback to indicate item is deleted
+ */
+static void complete_edac_pci_list_del(struct rcu_head *head)
+{
+	struct edac_pci_ctl_info *pci;
+
+	pci = container_of(head, struct edac_pci_ctl_info, rcu);
+	INIT_LIST_HEAD(&pci->link);
+	complete(&pci->complete);
+}
+
+/*
+ * del_edac_pci_from_global_list
+ *
+ *	remove the PCI control struct from the global list
+ */
+static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci)
+{
+	list_del_rcu(&pci->link);
+	init_completion(&pci->complete);
+	call_rcu(&pci->rcu, complete_edac_pci_list_del);
+	wait_for_completion(&pci->complete);
+}
+
+/*
+ * edac_pci_find()
+ * 	Search for an edac_pci_ctl_info structure whose index is 'idx'
+ *
+ * If found, return a pointer to the structure
+ * Else return NULL.
+ *
+ * Caller must hold pci_ctls_mutex.
+ */
+struct edac_pci_ctl_info *edac_pci_find(int idx)
+{
+	struct list_head *item;
+	struct edac_pci_ctl_info *pci;
+
+	/* Iterage over list, looking for exact match of ID */
+	list_for_each(item, &edac_pci_list) {
+		pci = list_entry(item, struct edac_pci_ctl_info, link);
+
+		if (pci->pci_idx >= idx) {
+			if (pci->pci_idx == idx)
+				return pci;
+
+			/* not on list, so terminate early */
+			break;
+		}
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(edac_pci_find);
+
+/*
+ * edac_pci_workq_function()
+ *
+ * 	periodic function that performs the operation
+ *	scheduled by a workq request, for a given PCI control struct
+ */
+static void edac_pci_workq_function(struct work_struct *work_req)
+{
+	struct delayed_work *d_work = (struct delayed_work *)work_req;
+	struct edac_pci_ctl_info *pci = to_edac_pci_ctl_work(d_work);
+	int msec;
+	unsigned long delay;
+
+	debugf3("%s() checking\n", __func__);
+
+	mutex_lock(&edac_pci_ctls_mutex);
+
+	if (pci->op_state == OP_RUNNING_POLL) {
+		/* we might be in POLL mode, but there may NOT be a poll func
+		 */
+		if ((pci->edac_check != NULL) && edac_pci_get_check_errors())
+			pci->edac_check(pci);
+
+		/* if we are on a one second period, then use round */
+		msec = edac_pci_get_poll_msec();
+		if (msec == 1000)
+			delay = round_jiffies(msecs_to_jiffies(msec));
+		else
+			delay = msecs_to_jiffies(msec);
+
+		/* Reschedule only if we are in POLL mode */
+		queue_delayed_work(edac_workqueue, &pci->work, delay);
+	}
+
+	mutex_unlock(&edac_pci_ctls_mutex);
+}
+
+/*
+ * edac_pci_workq_setup()
+ * 	initialize a workq item for this edac_pci instance
+ * 	passing in the new delay period in msec
+ *
+ *	locking model:
+ *		called when 'edac_pci_ctls_mutex' is locked
+ */
+static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci,
+				 unsigned int msec)
+{
+	debugf0("%s()\n", __func__);
+
+	INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function);
+	queue_delayed_work(edac_workqueue, &pci->work,
+			msecs_to_jiffies(edac_pci_get_poll_msec()));
+}
+
+/*
+ * edac_pci_workq_teardown()
+ * 	stop the workq processing on this edac_pci instance
+ */
+static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
+{
+	int status;
+
+	debugf0("%s()\n", __func__);
+
+	status = cancel_delayed_work(&pci->work);
+	if (status == 0)
+		flush_workqueue(edac_workqueue);
+}
+
+/*
+ * edac_pci_reset_delay_period
+ *
+ *	called with a new period value for the workq period
+ *	a) stop current workq timer
+ *	b) restart workq timer with new value
+ */
+void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
+				 unsigned long value)
+{
+	debugf0("%s()\n", __func__);
+
+	edac_pci_workq_teardown(pci);
+
+	/* need to lock for the setup */
+	mutex_lock(&edac_pci_ctls_mutex);
+
+	edac_pci_workq_setup(pci, value);
+
+	mutex_unlock(&edac_pci_ctls_mutex);
+}
+EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period);
+
+/*
+ * edac_pci_add_device: Insert the 'edac_dev' structure into the
+ * edac_pci global list and create sysfs entries associated with
+ * edac_pci structure.
+ * @pci: pointer to the edac_device structure to be added to the list
+ * @edac_idx: A unique numeric identifier to be assigned to the
+ * 'edac_pci' structure.
+ *
+ * Return:
+ *      0       Success
+ *      !0      Failure
+ */
+int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)
+{
+	debugf0("%s()\n", __func__);
+
+	pci->pci_idx = edac_idx;
+	pci->start_time = jiffies;
+
+	mutex_lock(&edac_pci_ctls_mutex);
+
+	if (add_edac_pci_to_global_list(pci))
+		goto fail0;
+
+	if (edac_pci_create_sysfs(pci)) {
+		edac_pci_printk(pci, KERN_WARNING,
+				"failed to create sysfs pci\n");
+		goto fail1;
+	}
+
+	if (pci->edac_check != NULL) {
+		pci->op_state = OP_RUNNING_POLL;
+
+		edac_pci_workq_setup(pci, 1000);
+	} else {
+		pci->op_state = OP_RUNNING_INTERRUPT;
+	}
+
+	edac_pci_printk(pci, KERN_INFO,
+			"Giving out device to module '%s' controller '%s':"
+			" DEV '%s' (%s)\n",
+			pci->mod_name,
+			pci->ctl_name,
+			dev_name(pci), edac_op_state_to_string(pci->op_state));
+
+	mutex_unlock(&edac_pci_ctls_mutex);
+	return 0;
+
+	/* error unwind stack */
+fail1:
+	del_edac_pci_from_global_list(pci);
+fail0:
+	mutex_unlock(&edac_pci_ctls_mutex);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(edac_pci_add_device);
+
+/*
+ * edac_pci_del_device()
+ * 	Remove sysfs entries for specified edac_pci structure and
+ * 	then remove edac_pci structure from global list
+ *
+ * @dev:
+ * 	Pointer to 'struct device' representing edac_pci structure
+ * 	to remove
+ *
+ * Return:
+ * 	Pointer to removed edac_pci structure,
+ * 	or NULL if device not found
+ */
+struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev)
+{
+	struct edac_pci_ctl_info *pci;
+
+	debugf0("%s()\n", __func__);
+
+	mutex_lock(&edac_pci_ctls_mutex);
+
+	/* ensure the control struct is on the global list
+	 * if not, then leave
+	 */
+	pci = find_edac_pci_by_dev(dev);
+	if (pci  == NULL) {
+		mutex_unlock(&edac_pci_ctls_mutex);
+		return NULL;
+	}
+
+	pci->op_state = OP_OFFLINE;
+
+	del_edac_pci_from_global_list(pci);
+
+	mutex_unlock(&edac_pci_ctls_mutex);
+
+	/* stop the workq timer */
+	edac_pci_workq_teardown(pci);
+
+	edac_printk(KERN_INFO, EDAC_PCI,
+		"Removed device %d for %s %s: DEV %s\n",
+		pci->pci_idx, pci->mod_name, pci->ctl_name, dev_name(pci));
+
+	return pci;
+}
+EXPORT_SYMBOL_GPL(edac_pci_del_device);
+
+/*
+ * edac_pci_generic_check
+ *
+ *	a Generic parity check API
+ */
+void edac_pci_generic_check(struct edac_pci_ctl_info *pci)
+{
+	debugf4("%s()\n", __func__);
+	edac_pci_do_parity_check();
+}
+
+/* free running instance index counter */
+static int edac_pci_idx;
+#define EDAC_PCI_GENCTL_NAME	"EDAC PCI controller"
+
+struct edac_pci_gen_data {
+	int edac_idx;
+};
+
+/*
+ * edac_pci_create_generic_ctl
+ *
+ *	A generic constructor for a PCI parity polling device
+ *	Some systems have more than one domain of PCI busses.
+ *	For systems with one domain, then this API will
+ *	provide for a generic poller.
+ *
+ *	This routine calls the edac_pci_alloc_ctl_info() for
+ *	the generic device, with default values
+ */
+struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev,
+						const char *mod_name)
+{
+	struct edac_pci_ctl_info *pci;
+	struct edac_pci_gen_data *pdata;
+
+	pci = edac_pci_alloc_ctl_info(sizeof(*pdata), EDAC_PCI_GENCTL_NAME);
+	if (!pci)
+		return NULL;
+
+	pdata = pci->pvt_info;
+	pci->dev = dev;
+	dev_set_drvdata(pci->dev, pci);
+	pci->dev_name = pci_name(to_pci_dev(dev));
+
+	pci->mod_name = mod_name;
+	pci->ctl_name = EDAC_PCI_GENCTL_NAME;
+	pci->edac_check = edac_pci_generic_check;
+
+	pdata->edac_idx = edac_pci_idx++;
+
+	if (edac_pci_add_device(pci, pdata->edac_idx) > 0) {
+		debugf3("%s(): failed edac_pci_add_device()\n", __func__);
+		edac_pci_free_ctl_info(pci);
+		return NULL;
+	}
+
+	return pci;
+}
+EXPORT_SYMBOL_GPL(edac_pci_create_generic_ctl);
+
+/*
+ * edac_pci_release_generic_ctl
+ *
+ *	The release function of a generic EDAC PCI polling device
+ */
+void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci)
+{
+	debugf0("%s() pci mod=%s\n", __func__, pci->mod_name);
+
+	edac_pci_del_device(pci->dev);
+	edac_pci_free_ctl_info(pci);
+}
+EXPORT_SYMBOL_GPL(edac_pci_release_generic_ctl);
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c
new file mode 100644
index 0000000..69f5ddd
--- /dev/null
+++ b/drivers/edac/edac_pci_sysfs.c
@@ -0,0 +1,763 @@
+/*
+ * (C) 2005, 2006 Linux Networx (http://lnxi.com)
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written Doug Thompson <norsk5@xmission.com>
+ *
+ */
+#include <linux/module.h>
+#include <linux/sysdev.h>
+#include <linux/ctype.h>
+
+#include "edac_core.h"
+#include "edac_module.h"
+
+/* Turn off this whole feature if PCI is not configured */
+#ifdef CONFIG_PCI
+
+#define EDAC_PCI_SYMLINK	"device"
+
+/* data variables exported via sysfs */
+static int check_pci_errors;		/* default NO check PCI parity */
+static int edac_pci_panic_on_pe;	/* default NO panic on PCI Parity */
+static int edac_pci_log_pe = 1;		/* log PCI parity errors */
+static int edac_pci_log_npe = 1;	/* log PCI non-parity error errors */
+static int edac_pci_poll_msec = 1000;	/* one second workq period */
+
+static atomic_t pci_parity_count = ATOMIC_INIT(0);
+static atomic_t pci_nonparity_count = ATOMIC_INIT(0);
+
+static struct kobject edac_pci_top_main_kobj;
+static atomic_t edac_pci_sysfs_refcount = ATOMIC_INIT(0);
+
+/* getter functions for the data variables */
+int edac_pci_get_check_errors(void)
+{
+	return check_pci_errors;
+}
+
+int edac_pci_get_log_pe(void)
+{
+	return edac_pci_log_pe;
+}
+
+int edac_pci_get_log_npe(void)
+{
+	return edac_pci_log_npe;
+}
+
+int edac_pci_get_panic_on_pe(void)
+{
+	return edac_pci_panic_on_pe;
+}
+
+int edac_pci_get_poll_msec(void)
+{
+	return edac_pci_poll_msec;
+}
+
+/**************************** EDAC PCI sysfs instance *******************/
+static ssize_t instance_pe_count_show(struct edac_pci_ctl_info *pci, char *data)
+{
+	return sprintf(data, "%u\n", atomic_read(&pci->counters.pe_count));
+}
+
+static ssize_t instance_npe_count_show(struct edac_pci_ctl_info *pci,
+				char *data)
+{
+	return sprintf(data, "%u\n", atomic_read(&pci->counters.npe_count));
+}
+
+#define to_instance(k) container_of(k, struct edac_pci_ctl_info, kobj)
+#define to_instance_attr(a) container_of(a, struct instance_attribute, attr)
+
+/* DEVICE instance kobject release() function */
+static void edac_pci_instance_release(struct kobject *kobj)
+{
+	struct edac_pci_ctl_info *pci;
+
+	debugf0("%s()\n", __func__);
+
+	/* Form pointer to containing struct, the pci control struct */
+	pci = to_instance(kobj);
+
+	/* decrement reference count on top main kobj */
+	kobject_put(&edac_pci_top_main_kobj);
+
+	kfree(pci);	/* Free the control struct */
+}
+
+/* instance specific attribute structure */
+struct instance_attribute {
+	struct attribute attr;
+	ssize_t(*show) (struct edac_pci_ctl_info *, char *);
+	ssize_t(*store) (struct edac_pci_ctl_info *, const char *, size_t);
+};
+
+/* Function to 'show' fields from the edac_pci 'instance' structure */
+static ssize_t edac_pci_instance_show(struct kobject *kobj,
+				struct attribute *attr, char *buffer)
+{
+	struct edac_pci_ctl_info *pci = to_instance(kobj);
+	struct instance_attribute *instance_attr = to_instance_attr(attr);
+
+	if (instance_attr->show)
+		return instance_attr->show(pci, buffer);
+	return -EIO;
+}
+
+/* Function to 'store' fields into the edac_pci 'instance' structure */
+static ssize_t edac_pci_instance_store(struct kobject *kobj,
+				struct attribute *attr,
+				const char *buffer, size_t count)
+{
+	struct edac_pci_ctl_info *pci = to_instance(kobj);
+	struct instance_attribute *instance_attr = to_instance_attr(attr);
+
+	if (instance_attr->store)
+		return instance_attr->store(pci, buffer, count);
+	return -EIO;
+}
+
+/* fs_ops table */
+static struct sysfs_ops pci_instance_ops = {
+	.show = edac_pci_instance_show,
+	.store = edac_pci_instance_store
+};
+
+#define INSTANCE_ATTR(_name, _mode, _show, _store)	\
+static struct instance_attribute attr_instance_##_name = {	\
+	.attr	= {.name = __stringify(_name), .mode = _mode },	\
+	.show	= _show,					\
+	.store	= _store,					\
+};
+
+INSTANCE_ATTR(pe_count, S_IRUGO, instance_pe_count_show, NULL);
+INSTANCE_ATTR(npe_count, S_IRUGO, instance_npe_count_show, NULL);
+
+/* pci instance attributes */
+static struct instance_attribute *pci_instance_attr[] = {
+	&attr_instance_pe_count,
+	&attr_instance_npe_count,
+	NULL
+};
+
+/* the ktype for a pci instance */
+static struct kobj_type ktype_pci_instance = {
+	.release = edac_pci_instance_release,
+	.sysfs_ops = &pci_instance_ops,
+	.default_attrs = (struct attribute **)pci_instance_attr,
+};
+
+/*
+ * edac_pci_create_instance_kobj
+ *
+ *	construct one EDAC PCI instance's kobject for use
+ */
+static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
+{
+	struct kobject *main_kobj;
+	int err;
+
+	debugf0("%s()\n", __func__);
+
+	/* Set the parent and the instance's ktype */
+	pci->kobj.parent = &edac_pci_top_main_kobj;
+	pci->kobj.ktype = &ktype_pci_instance;
+
+	err = kobject_set_name(&pci->kobj, "pci%d", idx);
+	if (err)
+		return err;
+
+	/* First bump the ref count on the top main kobj, which will
+	 * track the number of PCI instances we have, and thus nest
+	 * properly on keeping the module loaded
+	 */
+	main_kobj = kobject_get(&edac_pci_top_main_kobj);
+	if (!main_kobj) {
+		err = -ENODEV;
+		goto error_out;
+	}
+
+	/* And now register this new kobject under the main kobj */
+	err = kobject_register(&pci->kobj);
+	if (err != 0) {
+		debugf2("%s() failed to register instance pci%d\n",
+			__func__, idx);
+		kobject_put(&edac_pci_top_main_kobj);
+		goto error_out;
+	}
+
+	debugf1("%s() Register instance 'pci%d' kobject\n", __func__, idx);
+
+	return 0;
+
+	/* Error unwind statck */
+error_out:
+	return err;
+}
+
+/*
+ * edac_pci_unregister_sysfs_instance_kobj
+ *
+ *	unregister the kobj for the EDAC PCI instance
+ */
+void edac_pci_unregister_sysfs_instance_kobj(struct edac_pci_ctl_info *pci)
+{
+	debugf0("%s()\n", __func__);
+
+	/* Unregister the instance kobject and allow its release
+	 * function release the main reference count and then
+	 * kfree the memory
+	 */
+	kobject_unregister(&pci->kobj);
+}
+
+/***************************** EDAC PCI sysfs root **********************/
+#define to_edacpci(k) container_of(k, struct edac_pci_ctl_info, kobj)
+#define to_edacpci_attr(a) container_of(a, struct edac_pci_attr, attr)
+
+/* simple show/store functions for attributes */
+static ssize_t edac_pci_int_show(void *ptr, char *buffer)
+{
+	int *value = ptr;
+	return sprintf(buffer, "%d\n", *value);
+}
+
+static ssize_t edac_pci_int_store(void *ptr, const char *buffer, size_t count)
+{
+	int *value = ptr;
+
+	if (isdigit(*buffer))
+		*value = simple_strtoul(buffer, NULL, 0);
+
+	return count;
+}
+
+struct edac_pci_dev_attribute {
+	struct attribute attr;
+	void *value;
+	 ssize_t(*show) (void *, char *);
+	 ssize_t(*store) (void *, const char *, size_t);
+};
+
+/* Set of show/store abstract level functions for PCI Parity object */
+static ssize_t edac_pci_dev_show(struct kobject *kobj, struct attribute *attr,
+				 char *buffer)
+{
+	struct edac_pci_dev_attribute *edac_pci_dev;
+	edac_pci_dev = (struct edac_pci_dev_attribute *)attr;
+
+	if (edac_pci_dev->show)
+		return edac_pci_dev->show(edac_pci_dev->value, buffer);
+	return -EIO;
+}
+
+static ssize_t edac_pci_dev_store(struct kobject *kobj,
+				struct attribute *attr, const char *buffer,
+				size_t count)
+{
+	struct edac_pci_dev_attribute *edac_pci_dev;
+	edac_pci_dev = (struct edac_pci_dev_attribute *)attr;
+
+	if (edac_pci_dev->show)
+		return edac_pci_dev->store(edac_pci_dev->value, buffer, count);
+	return -EIO;
+}
+
+static struct sysfs_ops edac_pci_sysfs_ops = {
+	.show = edac_pci_dev_show,
+	.store = edac_pci_dev_store
+};
+
+#define EDAC_PCI_ATTR(_name,_mode,_show,_store)			\
+static struct edac_pci_dev_attribute edac_pci_attr_##_name = {		\
+	.attr = {.name = __stringify(_name), .mode = _mode },	\
+	.value  = &_name,					\
+	.show   = _show,					\
+	.store  = _store,					\
+};
+
+#define EDAC_PCI_STRING_ATTR(_name,_data,_mode,_show,_store)	\
+static struct edac_pci_dev_attribute edac_pci_attr_##_name = {		\
+	.attr = {.name = __stringify(_name), .mode = _mode },	\
+	.value  = _data,					\
+	.show   = _show,					\
+	.store  = _store,					\
+};
+
+/* PCI Parity control files */
+EDAC_PCI_ATTR(check_pci_errors, S_IRUGO | S_IWUSR, edac_pci_int_show,
+	edac_pci_int_store);
+EDAC_PCI_ATTR(edac_pci_log_pe, S_IRUGO | S_IWUSR, edac_pci_int_show,
+	edac_pci_int_store);
+EDAC_PCI_ATTR(edac_pci_log_npe, S_IRUGO | S_IWUSR, edac_pci_int_show,
+	edac_pci_int_store);
+EDAC_PCI_ATTR(edac_pci_panic_on_pe, S_IRUGO | S_IWUSR, edac_pci_int_show,
+	edac_pci_int_store);
+EDAC_PCI_ATTR(pci_parity_count, S_IRUGO, edac_pci_int_show, NULL);
+EDAC_PCI_ATTR(pci_nonparity_count, S_IRUGO, edac_pci_int_show, NULL);
+
+/* Base Attributes of the memory ECC object */
+static struct edac_pci_dev_attribute *edac_pci_attr[] = {
+	&edac_pci_attr_check_pci_errors,
+	&edac_pci_attr_edac_pci_log_pe,
+	&edac_pci_attr_edac_pci_log_npe,
+	&edac_pci_attr_edac_pci_panic_on_pe,
+	&edac_pci_attr_pci_parity_count,
+	&edac_pci_attr_pci_nonparity_count,
+	NULL,
+};
+
+/*
+ * edac_pci_release_main_kobj
+ *
+ *	This release function is called when the reference count to the
+ *	passed kobj goes to zero.
+ *
+ *	This kobj is the 'main' kobject that EDAC PCI instances
+ *	link to, and thus provide for proper nesting counts
+ */
+static void edac_pci_release_main_kobj(struct kobject *kobj)
+{
+
+	debugf0("%s() here to module_put(THIS_MODULE)\n", __func__);
+
+	/* last reference to top EDAC PCI kobject has been removed,
+	 * NOW release our ref count on the core module
+	 */
+	module_put(THIS_MODULE);
+}
+
+/* ktype struct for the EDAC PCI main kobj */
+static struct kobj_type ktype_edac_pci_main_kobj = {
+	.release = edac_pci_release_main_kobj,
+	.sysfs_ops = &edac_pci_sysfs_ops,
+	.default_attrs = (struct attribute **)edac_pci_attr,
+};
+
+/**
+ * edac_pci_main_kobj_setup()
+ *
+ *	setup the sysfs for EDAC PCI attributes
+ *	assumes edac_class has already been initialized
+ */
+int edac_pci_main_kobj_setup(void)
+{
+	int err;
+	struct sysdev_class *edac_class;
+
+	debugf0("%s()\n", __func__);
+
+	/* check and count if we have already created the main kobject */
+	if (atomic_inc_return(&edac_pci_sysfs_refcount) != 1)
+		return 0;
+
+	/* First time, so create the main kobject and its
+	 * controls and atributes
+	 */
+	edac_class = edac_get_edac_class();
+	if (edac_class == NULL) {
+		debugf1("%s() no edac_class\n", __func__);
+		err = -ENODEV;
+		goto decrement_count_fail;
+	}
+
+	/* Need the kobject hook ups, and name setting */
+	edac_pci_top_main_kobj.ktype = &ktype_edac_pci_main_kobj;
+	edac_pci_top_main_kobj.parent = &edac_class->kset.kobj;
+
+	err = kobject_set_name(&edac_pci_top_main_kobj, "pci");
+	if (err)
+		goto decrement_count_fail;
+
+	/* Bump the reference count on this module to ensure the
+	 * modules isn't unloaded until we deconstruct the top
+	 * level main kobj for EDAC PCI
+	 */
+	if (!try_module_get(THIS_MODULE)) {
+		debugf1("%s() try_module_get() failed\n", __func__);
+		err = -ENODEV;
+		goto decrement_count_fail;
+	}
+
+	/* Instanstiate the pci object */
+	/* FIXME: maybe new sysdev_create_subdir() */
+	err = kobject_register(&edac_pci_top_main_kobj);
+	if (err) {
+		debugf1("Failed to register '.../edac/pci'\n");
+		goto kobject_register_fail;
+	}
+
+	/* At this point, to 'release' the top level kobject
+	 * for EDAC PCI, then edac_pci_main_kobj_teardown()
+	 * must be used, for resources to be cleaned up properly
+	 */
+	debugf1("Registered '.../edac/pci' kobject\n");
+
+	return 0;
+
+	/* Error unwind statck */
+kobject_register_fail:
+	module_put(THIS_MODULE);
+
+decrement_count_fail:
+	/* if are on this error exit, nothing to tear down */
+	atomic_dec(&edac_pci_sysfs_refcount);
+
+	return err;
+}
+
+/*
+ * edac_pci_main_kobj_teardown()
+ *
+ *	if no longer linked (needed) remove the top level EDAC PCI
+ *	kobject with its controls and attributes
+ */
+static void edac_pci_main_kobj_teardown(void)
+{
+	debugf0("%s()\n", __func__);
+
+	/* Decrement the count and only if no more controller instances
+	 * are connected perform the unregisteration of the top level
+	 * main kobj
+	 */
+	if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) {
+		debugf0("%s() called kobject_unregister on main kobj\n",
+			__func__);
+		kobject_unregister(&edac_pci_top_main_kobj);
+	}
+}
+
+/*
+ *
+ * edac_pci_create_sysfs
+ *
+ *	Create the controls/attributes for the specified EDAC PCI device
+ */
+int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci)
+{
+	int err;
+	struct kobject *edac_kobj = &pci->kobj;
+
+	debugf0("%s() idx=%d\n", __func__, pci->pci_idx);
+
+	/* create the top main EDAC PCI kobject, IF needed */
+	err = edac_pci_main_kobj_setup();
+	if (err)
+		return err;
+
+	/* Create this instance's kobject under the MAIN kobject */
+	err = edac_pci_create_instance_kobj(pci, pci->pci_idx);
+	if (err)
+		goto unregister_cleanup;
+
+	err = sysfs_create_link(edac_kobj, &pci->dev->kobj, EDAC_PCI_SYMLINK);
+	if (err) {
+		debugf0("%s() sysfs_create_link() returned err= %d\n",
+			__func__, err);
+		goto symlink_fail;
+	}
+
+	return 0;
+
+	/* Error unwind stack */
+symlink_fail:
+	edac_pci_unregister_sysfs_instance_kobj(pci);
+
+unregister_cleanup:
+	edac_pci_main_kobj_teardown();
+
+	return err;
+}
+
+/*
+ * edac_pci_remove_sysfs
+ *
+ *	remove the controls and attributes for this EDAC PCI device
+ */
+void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci)
+{
+	debugf0("%s() index=%d\n", __func__, pci->pci_idx);
+
+	/* Remove the symlink */
+	sysfs_remove_link(&pci->kobj, EDAC_PCI_SYMLINK);
+
+	/* remove this PCI instance's sysfs entries */
+	edac_pci_unregister_sysfs_instance_kobj(pci);
+
+	/* Call the main unregister function, which will determine
+	 * if this 'pci' is the last instance.
+	 * If it is, the main kobject will be unregistered as a result
+	 */
+	debugf0("%s() calling edac_pci_main_kobj_teardown()\n", __func__);
+	edac_pci_main_kobj_teardown();
+}
+
+/************************ PCI error handling *************************/
+static u16 get_pci_parity_status(struct pci_dev *dev, int secondary)
+{
+	int where;
+	u16 status;
+
+	where = secondary ? PCI_SEC_STATUS : PCI_STATUS;
+	pci_read_config_word(dev, where, &status);
+
+	/* If we get back 0xFFFF then we must suspect that the card has been
+	 * pulled but the Linux PCI layer has not yet finished cleaning up.
+	 * We don't want to report on such devices
+	 */
+
+	if (status == 0xFFFF) {
+		u32 sanity;
+
+		pci_read_config_dword(dev, 0, &sanity);
+
+		if (sanity == 0xFFFFFFFF)
+			return 0;
+	}
+
+	status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR |
+		PCI_STATUS_PARITY;
+
+	if (status)
+		/* reset only the bits we are interested in */
+		pci_write_config_word(dev, where, status);
+
+	return status;
+}
+
+
+/* Clear any PCI parity errors logged by this device. */
+static void edac_pci_dev_parity_clear(struct pci_dev *dev)
+{
+	u8 header_type;
+
+	debugf0("%s()\n", __func__);
+
+	get_pci_parity_status(dev, 0);
+
+	/* read the device TYPE, looking for bridges */
+	pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
+
+	if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE)
+		get_pci_parity_status(dev, 1);
+}
+
+/*
+ *  PCI Parity polling
+ *
+ *	Fucntion to retrieve the current parity status
+ *	and decode it
+ *
+ */
+static void edac_pci_dev_parity_test(struct pci_dev *dev)
+{
+	unsigned long flags;
+	u16 status;
+	u8 header_type;
+
+	/* stop any interrupts until we can acquire the status */
+	local_irq_save(flags);
+
+	/* read the STATUS register on this device */
+	status = get_pci_parity_status(dev, 0);
+
+	/* read the device TYPE, looking for bridges */
+	pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
+
+	local_irq_restore(flags);
+
+	debugf4("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id);
+
+	/* check the status reg for errors */
+	if (status) {
+		if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) {
+			edac_printk(KERN_CRIT, EDAC_PCI,
+				"Signaled System Error on %s\n",
+				pci_name(dev));
+			atomic_inc(&pci_nonparity_count);
+		}
+
+		if (status & (PCI_STATUS_PARITY)) {
+			edac_printk(KERN_CRIT, EDAC_PCI,
+				"Master Data Parity Error on %s\n",
+				pci_name(dev));
+
+			atomic_inc(&pci_parity_count);
+		}
+
+		if (status & (PCI_STATUS_DETECTED_PARITY)) {
+			edac_printk(KERN_CRIT, EDAC_PCI,
+				"Detected Parity Error on %s\n",
+				pci_name(dev));
+
+			atomic_inc(&pci_parity_count);
+		}
+	}
+
+
+	debugf4("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id);
+
+	if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
+		/* On bridges, need to examine secondary status register  */
+		status = get_pci_parity_status(dev, 1);
+
+		debugf4("PCI SEC_STATUS= 0x%04x %s\n", status, dev->dev.bus_id);
+
+		/* check the secondary status reg for errors */
+		if (status) {
+			if (status & (PCI_STATUS_SIG_SYSTEM_ERROR)) {
+				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
+					"Signaled System Error on %s\n",
+					pci_name(dev));
+				atomic_inc(&pci_nonparity_count);
+			}
+
+			if (status & (PCI_STATUS_PARITY)) {
+				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
+					"Master Data Parity Error on "
+					"%s\n", pci_name(dev));
+
+				atomic_inc(&pci_parity_count);
+			}
+
+			if (status & (PCI_STATUS_DETECTED_PARITY)) {
+				edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
+					"Detected Parity Error on %s\n",
+					pci_name(dev));
+
+				atomic_inc(&pci_parity_count);
+			}
+		}
+	}
+}
+
+/* reduce some complexity in definition of the iterator */
+typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev);
+
+/*
+ * pci_dev parity list iterator
+ *	Scan the PCI device list for one pass, looking for SERRORs
+ *	Master Parity ERRORS or Parity ERRORs on primary or secondary devices
+ */
+static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
+{
+	struct pci_dev *dev = NULL;
+
+	/* request for kernel access to the next PCI device, if any,
+	 * and while we are looking at it have its reference count
+	 * bumped until we are done with it
+	 */
+	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+		fn(dev);
+	}
+}
+
+/*
+ * edac_pci_do_parity_check
+ *
+ *	performs the actual PCI parity check operation
+ */
+void edac_pci_do_parity_check(void)
+{
+	int before_count;
+
+	debugf3("%s()\n", __func__);
+
+	/* if policy has PCI check off, leave now */
+	if (!check_pci_errors)
+		return;
+
+	before_count = atomic_read(&pci_parity_count);
+
+	/* scan all PCI devices looking for a Parity Error on devices and
+	 * bridges.
+	 * The iterator calls pci_get_device() which might sleep, thus
+	 * we cannot disable interrupts in this scan.
+	 */
+	edac_pci_dev_parity_iterator(edac_pci_dev_parity_test);
+
+	/* Only if operator has selected panic on PCI Error */
+	if (edac_pci_get_panic_on_pe()) {
+		/* If the count is different 'after' from 'before' */
+		if (before_count != atomic_read(&pci_parity_count))
+			panic("EDAC: PCI Parity Error");
+	}
+}
+
+/*
+ * edac_pci_clear_parity_errors
+ *
+ *	function to perform an iteration over the PCI devices
+ *	and clearn their current status
+ */
+void edac_pci_clear_parity_errors(void)
+{
+	/* Clear any PCI bus parity errors that devices initially have logged
+	 * in their registers.
+	 */
+	edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear);
+}
+
+/*
+ * edac_pci_handle_pe
+ *
+ *	Called to handle a PARITY ERROR event
+ */
+void edac_pci_handle_pe(struct edac_pci_ctl_info *pci, const char *msg)
+{
+
+	/* global PE counter incremented by edac_pci_do_parity_check() */
+	atomic_inc(&pci->counters.pe_count);
+
+	if (edac_pci_get_log_pe())
+		edac_pci_printk(pci, KERN_WARNING,
+				"Parity Error ctl: %s %d: %s\n",
+				pci->ctl_name, pci->pci_idx, msg);
+
+	/*
+	 * poke all PCI devices and see which one is the troublemaker
+	 * panic() is called if set
+	 */
+	edac_pci_do_parity_check();
+}
+EXPORT_SYMBOL_GPL(edac_pci_handle_pe);
+
+
+/*
+ * edac_pci_handle_npe
+ *
+ *	Called to handle a NON-PARITY ERROR event
+ */
+void edac_pci_handle_npe(struct edac_pci_ctl_info *pci, const char *msg)
+{
+
+	/* global NPE counter incremented by edac_pci_do_parity_check() */
+	atomic_inc(&pci->counters.npe_count);
+
+	if (edac_pci_get_log_npe())
+		edac_pci_printk(pci, KERN_WARNING,
+				"Non-Parity Error ctl: %s %d: %s\n",
+				pci->ctl_name, pci->pci_idx, msg);
+
+	/*
+	 * poke all PCI devices and see which one is the troublemaker
+	 * panic() is called if set
+	 */
+	edac_pci_do_parity_check();
+}
+EXPORT_SYMBOL_GPL(edac_pci_handle_npe);
+
+/*
+ * Define the PCI parameter to the module
+ */
+module_param(check_pci_errors, int, 0644);
+MODULE_PARM_DESC(check_pci_errors,
+		 "Check for PCI bus parity errors: 0=off 1=on");
+module_param(edac_pci_panic_on_pe, int, 0644);
+MODULE_PARM_DESC(edac_pci_panic_on_pe,
+		 "Panic on PCI Bus Parity error: 0=off 1=on");
+
+#endif				/* CONFIG_PCI */
diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c
new file mode 100644
index 0000000..20b428a
--- /dev/null
+++ b/drivers/edac/edac_stub.c
@@ -0,0 +1,46 @@
+/*
+ * common EDAC components that must be in kernel
+ *
+ * Author: Dave Jiang <djiang@mvista.com>
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ */
+#include <linux/module.h>
+#include <linux/edac.h>
+#include <asm/atomic.h>
+#include <asm/edac.h>
+
+int edac_op_state = EDAC_OPSTATE_INVAL;
+EXPORT_SYMBOL_GPL(edac_op_state);
+
+atomic_t edac_handlers = ATOMIC_INIT(0);
+EXPORT_SYMBOL_GPL(edac_handlers);
+
+int edac_err_assert = 0;
+EXPORT_SYMBOL_GPL(edac_err_assert);
+
+/*
+ * called to determine if there is an EDAC driver interested in
+ * knowing an event (such as NMI) occurred
+ */
+int edac_handler_set(void)
+{
+	if (edac_op_state == EDAC_OPSTATE_POLL)
+		return 0;
+
+	return atomic_read(&edac_handlers);
+}
+EXPORT_SYMBOL_GPL(edac_handler_set);
+
+/*
+ * handler for NMI type of interrupts to assert error
+ */
+void edac_atomic_assert_error(void)
+{
+	edac_err_assert++;
+}
+EXPORT_SYMBOL_GPL(edac_atomic_assert_error);
diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c
new file mode 100644
index 0000000..e895f9f
--- /dev/null
+++ b/drivers/edac/i3000_edac.c
@@ -0,0 +1,506 @@
+/*
+ * Intel 3000/3010 Memory Controller kernel module
+ * Copyright (C) 2007 Akamai Technologies, Inc.
+ * Shamelessly copied from:
+ * 	Intel D82875P Memory Controller kernel module
+ * 	(C) 2003 Linux Networx (http://lnxi.com)
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include "edac_core.h"
+
+#define I3000_REVISION		"1.1"
+
+#define EDAC_MOD_STR		"i3000_edac"
+
+#define I3000_RANKS		8
+#define I3000_RANKS_PER_CHANNEL	4
+#define I3000_CHANNELS		2
+
+/* Intel 3000 register addresses - device 0 function 0 - DRAM Controller */
+
+#define I3000_MCHBAR		0x44	/* MCH Memory Mapped Register BAR */
+#define I3000_MCHBAR_MASK	0xffffc000
+#define I3000_MMR_WINDOW_SIZE	16384
+
+#define I3000_EDEAP		0x70	/* Extended DRAM Error Address Pointer (8b)
+					 *
+					 * 7:1   reserved
+					 * 0     bit 32 of address
+					 */
+#define I3000_DEAP		0x58	/* DRAM Error Address Pointer (32b)
+					 *
+					 * 31:7  address
+					 * 6:1   reserved
+					 * 0     Error channel 0/1
+					 */
+#define I3000_DEAP_GRAIN	(1 << 7)
+#define I3000_DEAP_PFN(edeap, deap)	((((edeap) & 1) << (32 - PAGE_SHIFT)) | \
+					((deap) >> PAGE_SHIFT))
+#define I3000_DEAP_OFFSET(deap)		((deap) & ~(I3000_DEAP_GRAIN-1) & ~PAGE_MASK)
+#define I3000_DEAP_CHANNEL(deap)	((deap) & 1)
+
+#define I3000_DERRSYN		0x5c	/* DRAM Error Syndrome (8b)
+					 *
+					 *  7:0  DRAM ECC Syndrome
+					 */
+
+#define I3000_ERRSTS		0xc8	/* Error Status Register (16b)
+					 *
+					 * 15:12 reserved
+					 * 11    MCH Thermal Sensor Event for SMI/SCI/SERR
+					 * 10    reserved
+					 *  9    LOCK to non-DRAM Memory Flag (LCKF)
+					 *  8    Received Refresh Timeout Flag (RRTOF)
+					 *  7:2  reserved
+					 *  1    Multiple-bit DRAM ECC Error Flag (DMERR)
+					 *  0    Single-bit DRAM ECC Error Flag (DSERR)
+					 */
+#define I3000_ERRSTS_BITS	0x0b03	/* bits which indicate errors */
+#define I3000_ERRSTS_UE		0x0002
+#define I3000_ERRSTS_CE		0x0001
+
+#define I3000_ERRCMD		0xca	/* Error Command (16b)
+					 *
+					 * 15:12 reserved
+					 * 11    SERR on MCH Thermal Sensor Event (TSESERR)
+					 * 10    reserved
+					 *  9    SERR on LOCK to non-DRAM Memory (LCKERR)
+					 *  8    SERR on DRAM Refresh Timeout (DRTOERR)
+					 *  7:2  reserved
+					 *  1    SERR Multiple-Bit DRAM ECC Error (DMERR)
+					 *  0    SERR on Single-Bit ECC Error (DSERR)
+					 */
+
+/* Intel  MMIO register space - device 0 function 0 - MMR space */
+
+#define I3000_DRB_SHIFT 25	/* 32MiB grain */
+
+#define I3000_C0DRB		0x100	/* Channel 0 DRAM Rank Boundary (8b x 4)
+					 *
+					 * 7:0   Channel 0 DRAM Rank Boundary Address
+					 */
+#define I3000_C1DRB		0x180	/* Channel 1 DRAM Rank Boundary (8b x 4)
+					 *
+					 * 7:0   Channel 1 DRAM Rank Boundary Address
+					 */
+
+#define I3000_C0DRA		0x108	/* Channel 0 DRAM Rank Attribute (8b x 2)
+					 *
+					 * 7     reserved
+					 * 6:4   DRAM odd Rank Attribute
+					 * 3     reserved
+					 * 2:0   DRAM even Rank Attribute
+					 *
+					 * Each attribute defines the page
+					 * size of the corresponding rank:
+					 *     000: unpopulated
+					 *     001: reserved
+					 *     010: 4 KB
+					 *     011: 8 KB
+					 *     100: 16 KB
+					 *     Others: reserved
+					 */
+#define I3000_C1DRA		0x188	/* Channel 1 DRAM Rank Attribute (8b x 2) */
+#define ODD_RANK_ATTRIB(dra) (((dra) & 0x70) >> 4)
+#define EVEN_RANK_ATTRIB(dra) ((dra) & 0x07)
+
+#define I3000_C0DRC0		0x120	/* DRAM Controller Mode 0 (32b)
+					 *
+					 * 31:30 reserved
+					 * 29    Initialization Complete (IC)
+					 * 28:11 reserved
+					 * 10:8  Refresh Mode Select (RMS)
+					 * 7     reserved
+					 * 6:4   Mode Select (SMS)
+					 * 3:2   reserved
+					 * 1:0   DRAM Type (DT)
+					 */
+
+#define I3000_C0DRC1		0x124	/* DRAM Controller Mode 1 (32b)
+					 *
+					 * 31    Enhanced Addressing Enable (ENHADE)
+					 * 30:0  reserved
+					 */
+
+enum i3000p_chips {
+	I3000 = 0,
+};
+
+struct i3000_dev_info {
+	const char *ctl_name;
+};
+
+struct i3000_error_info {
+	u16 errsts;
+	u8 derrsyn;
+	u8 edeap;
+	u32 deap;
+	u16 errsts2;
+};
+
+static const struct i3000_dev_info i3000_devs[] = {
+	[I3000] = {
+		.ctl_name = "i3000"},
+};
+
+static struct pci_dev *mci_pdev;
+static int i3000_registered = 1;
+static struct edac_pci_ctl_info *i3000_pci;
+
+static void i3000_get_error_info(struct mem_ctl_info *mci,
+				 struct i3000_error_info *info)
+{
+	struct pci_dev *pdev;
+
+	pdev = to_pci_dev(mci->dev);
+
+	/*
+	 * This is a mess because there is no atomic way to read all the
+	 * registers at once and the registers can transition from CE being
+	 * overwritten by UE.
+	 */
+	pci_read_config_word(pdev, I3000_ERRSTS, &info->errsts);
+	if (!(info->errsts & I3000_ERRSTS_BITS))
+		return;
+	pci_read_config_byte(pdev, I3000_EDEAP, &info->edeap);
+	pci_read_config_dword(pdev, I3000_DEAP, &info->deap);
+	pci_read_config_byte(pdev, I3000_DERRSYN, &info->derrsyn);
+	pci_read_config_word(pdev, I3000_ERRSTS, &info->errsts2);
+
+	/*
+	 * If the error is the same for both reads then the first set
+	 * of reads is valid.  If there is a change then there is a CE
+	 * with no info and the second set of reads is valid and
+	 * should be UE info.
+	 */
+	if ((info->errsts ^ info->errsts2) & I3000_ERRSTS_BITS) {
+		pci_read_config_byte(pdev, I3000_EDEAP, &info->edeap);
+		pci_read_config_dword(pdev, I3000_DEAP, &info->deap);
+		pci_read_config_byte(pdev, I3000_DERRSYN, &info->derrsyn);
+	}
+
+	/* Clear any error bits.
+	 * (Yes, we really clear bits by writing 1 to them.)
+	 */
+	pci_write_bits16(pdev, I3000_ERRSTS, I3000_ERRSTS_BITS,
+			 I3000_ERRSTS_BITS);
+}
+
+static int i3000_process_error_info(struct mem_ctl_info *mci,
+				struct i3000_error_info *info,
+				int handle_errors)
+{
+	int row, multi_chan;
+	int pfn, offset, channel;
+
+	multi_chan = mci->csrows[0].nr_channels - 1;
+
+	if (!(info->errsts & I3000_ERRSTS_BITS))
+		return 0;
+
+	if (!handle_errors)
+		return 1;
+
+	if ((info->errsts ^ info->errsts2) & I3000_ERRSTS_BITS) {
+		edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
+		info->errsts = info->errsts2;
+	}
+
+	pfn = I3000_DEAP_PFN(info->edeap, info->deap);
+	offset = I3000_DEAP_OFFSET(info->deap);
+	channel = I3000_DEAP_CHANNEL(info->deap);
+
+	row = edac_mc_find_csrow_by_page(mci, pfn);
+
+	if (info->errsts & I3000_ERRSTS_UE)
+		edac_mc_handle_ue(mci, pfn, offset, row, "i3000 UE");
+	else
+		edac_mc_handle_ce(mci, pfn, offset, info->derrsyn, row,
+				multi_chan ? channel : 0, "i3000 CE");
+
+	return 1;
+}
+
+static void i3000_check(struct mem_ctl_info *mci)
+{
+	struct i3000_error_info info;
+
+	debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+	i3000_get_error_info(mci, &info);
+	i3000_process_error_info(mci, &info, 1);
+}
+
+static int i3000_is_interleaved(const unsigned char *c0dra,
+				const unsigned char *c1dra,
+				const unsigned char *c0drb,
+				const unsigned char *c1drb)
+{
+	int i;
+
+	/* If the channels aren't populated identically then
+	 * we're not interleaved.
+	 */
+	for (i = 0; i < I3000_RANKS_PER_CHANNEL / 2; i++)
+		if (ODD_RANK_ATTRIB(c0dra[i]) != ODD_RANK_ATTRIB(c1dra[i]) ||
+			EVEN_RANK_ATTRIB(c0dra[i]) !=
+						EVEN_RANK_ATTRIB(c1dra[i]))
+			return 0;
+
+	/* If the rank boundaries for the two channels are different
+	 * then we're not interleaved.
+	 */
+	for (i = 0; i < I3000_RANKS_PER_CHANNEL; i++)
+		if (c0drb[i] != c1drb[i])
+			return 0;
+
+	return 1;
+}
+
+static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
+{
+	int rc;
+	int i;
+	struct mem_ctl_info *mci = NULL;
+	unsigned long last_cumul_size;
+	int interleaved, nr_channels;
+	unsigned char dra[I3000_RANKS / 2], drb[I3000_RANKS];
+	unsigned char *c0dra = dra, *c1dra = &dra[I3000_RANKS_PER_CHANNEL / 2];
+	unsigned char *c0drb = drb, *c1drb = &drb[I3000_RANKS_PER_CHANNEL];
+	unsigned long mchbar;
+	void __iomem *window;
+
+	debugf0("MC: %s()\n", __func__);
+
+	pci_read_config_dword(pdev, I3000_MCHBAR, (u32 *) & mchbar);
+	mchbar &= I3000_MCHBAR_MASK;
+	window = ioremap_nocache(mchbar, I3000_MMR_WINDOW_SIZE);
+	if (!window) {
+		printk(KERN_ERR "i3000: cannot map mmio space at 0x%lx\n",
+			mchbar);
+		return -ENODEV;
+	}
+
+	c0dra[0] = readb(window + I3000_C0DRA + 0);	/* ranks 0,1 */
+	c0dra[1] = readb(window + I3000_C0DRA + 1);	/* ranks 2,3 */
+	c1dra[0] = readb(window + I3000_C1DRA + 0);	/* ranks 0,1 */
+	c1dra[1] = readb(window + I3000_C1DRA + 1);	/* ranks 2,3 */
+
+	for (i = 0; i < I3000_RANKS_PER_CHANNEL; i++) {
+		c0drb[i] = readb(window + I3000_C0DRB + i);
+		c1drb[i] = readb(window + I3000_C1DRB + i);
+	}
+
+	iounmap(window);
+
+	/* Figure out how many channels we have.
+	 *
+	 * If we have what the datasheet calls "asymmetric channels"
+	 * (essentially the same as what was called "virtual single
+	 * channel mode" in the i82875) then it's a single channel as
+	 * far as EDAC is concerned.
+	 */
+	interleaved = i3000_is_interleaved(c0dra, c1dra, c0drb, c1drb);
+	nr_channels = interleaved ? 2 : 1;
+	mci = edac_mc_alloc(0, I3000_RANKS / nr_channels, nr_channels, 0);
+	if (!mci)
+		return -ENOMEM;
+
+	debugf3("MC: %s(): init mci\n", __func__);
+
+	mci->dev = &pdev->dev;
+	mci->mtype_cap = MEM_FLAG_DDR2;
+
+	mci->edac_ctl_cap = EDAC_FLAG_SECDED;
+	mci->edac_cap = EDAC_FLAG_SECDED;
+
+	mci->mod_name = EDAC_MOD_STR;
+	mci->mod_ver = I3000_REVISION;
+	mci->ctl_name = i3000_devs[dev_idx].ctl_name;
+	mci->dev_name = pci_name(pdev);
+	mci->edac_check = i3000_check;
+	mci->ctl_page_to_phys = NULL;
+
+	/*
+	 * The dram rank boundary (DRB) reg values are boundary addresses
+	 * for each DRAM rank with a granularity of 32MB.  DRB regs are
+	 * cumulative; the last one will contain the total memory
+	 * contained in all ranks.
+	 *
+	 * If we're in interleaved mode then we're only walking through
+	 * the ranks of controller 0, so we double all the values we see.
+	 */
+	for (last_cumul_size = i = 0; i < mci->nr_csrows; i++) {
+		u8 value;
+		u32 cumul_size;
+		struct csrow_info *csrow = &mci->csrows[i];
+
+		value = drb[i];
+		cumul_size = value << (I3000_DRB_SHIFT - PAGE_SHIFT);
+		if (interleaved)
+			cumul_size <<= 1;
+		debugf3("MC: %s(): (%d) cumul_size 0x%x\n",
+			__func__, i, cumul_size);
+		if (cumul_size == last_cumul_size) {
+			csrow->mtype = MEM_EMPTY;
+			continue;
+		}
+
+		csrow->first_page = last_cumul_size;
+		csrow->last_page = cumul_size - 1;
+		csrow->nr_pages = cumul_size - last_cumul_size;
+		last_cumul_size = cumul_size;
+		csrow->grain = I3000_DEAP_GRAIN;
+		csrow->mtype = MEM_DDR2;
+		csrow->dtype = DEV_UNKNOWN;
+		csrow->edac_mode = EDAC_UNKNOWN;
+	}
+
+	/* Clear any error bits.
+	 * (Yes, we really clear bits by writing 1 to them.)
+	 */
+	pci_write_bits16(pdev, I3000_ERRSTS, I3000_ERRSTS_BITS,
+			 I3000_ERRSTS_BITS);
+
+	rc = -ENODEV;
+	if (edac_mc_add_mc(mci)) {
+		debugf3("MC: %s(): failed edac_mc_add_mc()\n", __func__);
+		goto fail;
+	}
+
+	/* allocating generic PCI control info */
+	i3000_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+	if (!i3000_pci) {
+		printk(KERN_WARNING
+			"%s(): Unable to create PCI control\n",
+			__func__);
+		printk(KERN_WARNING
+			"%s(): PCI error report via EDAC not setup\n",
+			__func__);
+	}
+
+	/* get this far and it's successful */
+	debugf3("MC: %s(): success\n", __func__);
+	return 0;
+
+      fail:
+	if (mci)
+		edac_mc_free(mci);
+
+	return rc;
+}
+
+/* returns count (>= 0), or negative on error */
+static int __devinit i3000_init_one(struct pci_dev *pdev,
+				const struct pci_device_id *ent)
+{
+	int rc;
+
+	debugf0("MC: %s()\n", __func__);
+
+	if (pci_enable_device(pdev) < 0)
+		return -EIO;
+
+	rc = i3000_probe1(pdev, ent->driver_data);
+	if (mci_pdev == NULL)
+		mci_pdev = pci_dev_get(pdev);
+
+	return rc;
+}
+
+static void __devexit i3000_remove_one(struct pci_dev *pdev)
+{
+	struct mem_ctl_info *mci;
+
+	debugf0("%s()\n", __func__);
+
+	if (i3000_pci)
+		edac_pci_release_generic_ctl(i3000_pci);
+
+	if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
+		return;
+
+	edac_mc_free(mci);
+}
+
+static const struct pci_device_id i3000_pci_tbl[] __devinitdata = {
+	{
+	 PCI_VEND_DEV(INTEL, 3000_HB), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	 I3000},
+	{
+	 0,
+	 }			/* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i3000_pci_tbl);
+
+static struct pci_driver i3000_driver = {
+	.name = EDAC_MOD_STR,
+	.probe = i3000_init_one,
+	.remove = __devexit_p(i3000_remove_one),
+	.id_table = i3000_pci_tbl,
+};
+
+static int __init i3000_init(void)
+{
+	int pci_rc;
+
+	debugf3("MC: %s()\n", __func__);
+	pci_rc = pci_register_driver(&i3000_driver);
+	if (pci_rc < 0)
+		goto fail0;
+
+	if (mci_pdev == NULL) {
+		i3000_registered = 0;
+		mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+					PCI_DEVICE_ID_INTEL_3000_HB, NULL);
+		if (!mci_pdev) {
+			debugf0("i3000 pci_get_device fail\n");
+			pci_rc = -ENODEV;
+			goto fail1;
+		}
+
+		pci_rc = i3000_init_one(mci_pdev, i3000_pci_tbl);
+		if (pci_rc < 0) {
+			debugf0("i3000 init fail\n");
+			pci_rc = -ENODEV;
+			goto fail1;
+		}
+	}
+
+	return 0;
+
+fail1:
+	pci_unregister_driver(&i3000_driver);
+
+fail0:
+	if (mci_pdev)
+		pci_dev_put(mci_pdev);
+
+	return pci_rc;
+}
+
+static void __exit i3000_exit(void)
+{
+	debugf3("MC: %s()\n", __func__);
+
+	pci_unregister_driver(&i3000_driver);
+	if (!i3000_registered) {
+		i3000_remove_one(mci_pdev);
+		pci_dev_put(mci_pdev);
+	}
+}
+
+module_init(i3000_init);
+module_exit(i3000_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Akamai Technologies Arthur Ulfeldt/Jason Uhlenkott");
+MODULE_DESCRIPTION("MC support for Intel 3000 memory hub controllers");
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
new file mode 100644
index 0000000..96f7e63
--- /dev/null
+++ b/drivers/edac/i5000_edac.c
@@ -0,0 +1,1505 @@
+/*
+ * Intel 5000(P/V/X) class Memory Controllers kernel module
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written by Douglas Thompson Linux Networx (http://lnxi.com)
+ *	norsk5@xmission.com
+ *
+ * This module is based on the following document:
+ *
+ * Intel 5000X Chipset Memory Controller Hub (MCH) - Datasheet
+ * 	http://developer.intel.com/design/chipsets/datashts/313070.htm
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include <linux/edac.h>
+#include <asm/mmzone.h>
+
+#include "edac_core.h"
+
+/*
+ * Alter this version for the I5000 module when modifications are made
+ */
+#define I5000_REVISION    " Ver: 2.0.12 " __DATE__
+#define EDAC_MOD_STR      "i5000_edac"
+
+#define i5000_printk(level, fmt, arg...) \
+        edac_printk(level, "i5000", fmt, ##arg)
+
+#define i5000_mc_printk(mci, level, fmt, arg...) \
+        edac_mc_chipset_printk(mci, level, "i5000", fmt, ##arg)
+
+#ifndef PCI_DEVICE_ID_INTEL_FBD_0
+#define PCI_DEVICE_ID_INTEL_FBD_0	0x25F5
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_FBD_1
+#define PCI_DEVICE_ID_INTEL_FBD_1	0x25F6
+#endif
+
+/* Device 16,
+ * Function 0: System Address
+ * Function 1: Memory Branch Map, Control, Errors Register
+ * Function 2: FSB Error Registers
+ *
+ * All 3 functions of Device 16 (0,1,2) share the SAME DID
+ */
+#define	PCI_DEVICE_ID_INTEL_I5000_DEV16	0x25F0
+
+/* OFFSETS for Function 0 */
+
+/* OFFSETS for Function 1 */
+#define		AMBASE			0x48
+#define		MAXCH			0x56
+#define		MAXDIMMPERCH		0x57
+#define		TOLM			0x6C
+#define		REDMEMB			0x7C
+#define			RED_ECC_LOCATOR(x)	((x) & 0x3FFFF)
+#define			REC_ECC_LOCATOR_EVEN(x)	((x) & 0x001FF)
+#define			REC_ECC_LOCATOR_ODD(x)	((x) & 0x3FE00)
+#define		MIR0			0x80
+#define		MIR1			0x84
+#define		MIR2			0x88
+#define		AMIR0			0x8C
+#define		AMIR1			0x90
+#define		AMIR2			0x94
+
+#define		FERR_FAT_FBD		0x98
+#define		NERR_FAT_FBD		0x9C
+#define			EXTRACT_FBDCHAN_INDX(x)	(((x)>>28) & 0x3)
+#define			FERR_FAT_FBDCHAN 0x30000000
+#define			FERR_FAT_M3ERR	0x00000004
+#define			FERR_FAT_M2ERR	0x00000002
+#define			FERR_FAT_M1ERR	0x00000001
+#define			FERR_FAT_MASK	(FERR_FAT_M1ERR | \
+						FERR_FAT_M2ERR | \
+						FERR_FAT_M3ERR)
+
+#define		FERR_NF_FBD		0xA0
+
+/* Thermal and SPD or BFD errors */
+#define			FERR_NF_M28ERR	0x01000000
+#define			FERR_NF_M27ERR	0x00800000
+#define			FERR_NF_M26ERR	0x00400000
+#define			FERR_NF_M25ERR	0x00200000
+#define			FERR_NF_M24ERR	0x00100000
+#define			FERR_NF_M23ERR	0x00080000
+#define			FERR_NF_M22ERR	0x00040000
+#define			FERR_NF_M21ERR	0x00020000
+
+/* Correctable errors */
+#define			FERR_NF_M20ERR	0x00010000
+#define			FERR_NF_M19ERR	0x00008000
+#define			FERR_NF_M18ERR	0x00004000
+#define			FERR_NF_M17ERR	0x00002000
+
+/* Non-Retry or redundant Retry errors */
+#define			FERR_NF_M16ERR	0x00001000
+#define			FERR_NF_M15ERR	0x00000800
+#define			FERR_NF_M14ERR	0x00000400
+#define			FERR_NF_M13ERR	0x00000200
+
+/* Uncorrectable errors */
+#define			FERR_NF_M12ERR	0x00000100
+#define			FERR_NF_M11ERR	0x00000080
+#define			FERR_NF_M10ERR	0x00000040
+#define			FERR_NF_M9ERR	0x00000020
+#define			FERR_NF_M8ERR	0x00000010
+#define			FERR_NF_M7ERR	0x00000008
+#define			FERR_NF_M6ERR	0x00000004
+#define			FERR_NF_M5ERR	0x00000002
+#define			FERR_NF_M4ERR	0x00000001
+
+#define			FERR_NF_UNCORRECTABLE	(FERR_NF_M12ERR | \
+							FERR_NF_M11ERR | \
+							FERR_NF_M10ERR | \
+							FERR_NF_M8ERR | \
+							FERR_NF_M7ERR | \
+							FERR_NF_M6ERR | \
+							FERR_NF_M5ERR | \
+							FERR_NF_M4ERR)
+#define			FERR_NF_CORRECTABLE	(FERR_NF_M20ERR | \
+							FERR_NF_M19ERR | \
+							FERR_NF_M18ERR | \
+							FERR_NF_M17ERR)
+#define			FERR_NF_DIMM_SPARE	(FERR_NF_M27ERR | \
+							FERR_NF_M28ERR)
+#define			FERR_NF_THERMAL		(FERR_NF_M26ERR | \
+							FERR_NF_M25ERR | \
+							FERR_NF_M24ERR | \
+							FERR_NF_M23ERR)
+#define			FERR_NF_SPD_PROTOCOL	(FERR_NF_M22ERR)
+#define			FERR_NF_NORTH_CRC	(FERR_NF_M21ERR)
+#define			FERR_NF_NON_RETRY	(FERR_NF_M13ERR | \
+							FERR_NF_M14ERR | \
+							FERR_NF_M15ERR)
+
+#define		NERR_NF_FBD		0xA4
+#define			FERR_NF_MASK		(FERR_NF_UNCORRECTABLE | \
+							FERR_NF_CORRECTABLE | \
+							FERR_NF_DIMM_SPARE | \
+							FERR_NF_THERMAL | \
+							FERR_NF_SPD_PROTOCOL | \
+							FERR_NF_NORTH_CRC | \
+							FERR_NF_NON_RETRY)
+
+#define		EMASK_FBD		0xA8
+#define			EMASK_FBD_M28ERR	0x08000000
+#define			EMASK_FBD_M27ERR	0x04000000
+#define			EMASK_FBD_M26ERR	0x02000000
+#define			EMASK_FBD_M25ERR	0x01000000
+#define			EMASK_FBD_M24ERR	0x00800000
+#define			EMASK_FBD_M23ERR	0x00400000
+#define			EMASK_FBD_M22ERR	0x00200000
+#define			EMASK_FBD_M21ERR	0x00100000
+#define			EMASK_FBD_M20ERR	0x00080000
+#define			EMASK_FBD_M19ERR	0x00040000
+#define			EMASK_FBD_M18ERR	0x00020000
+#define			EMASK_FBD_M17ERR	0x00010000
+
+#define			EMASK_FBD_M15ERR	0x00004000
+#define			EMASK_FBD_M14ERR	0x00002000
+#define			EMASK_FBD_M13ERR	0x00001000
+#define			EMASK_FBD_M12ERR	0x00000800
+#define			EMASK_FBD_M11ERR	0x00000400
+#define			EMASK_FBD_M10ERR	0x00000200
+#define			EMASK_FBD_M9ERR		0x00000100
+#define			EMASK_FBD_M8ERR		0x00000080
+#define			EMASK_FBD_M7ERR		0x00000040
+#define			EMASK_FBD_M6ERR		0x00000020
+#define			EMASK_FBD_M5ERR		0x00000010
+#define			EMASK_FBD_M4ERR		0x00000008
+#define			EMASK_FBD_M3ERR		0x00000004
+#define			EMASK_FBD_M2ERR		0x00000002
+#define			EMASK_FBD_M1ERR		0x00000001
+
+#define			ENABLE_EMASK_FBD_FATAL_ERRORS	(EMASK_FBD_M1ERR | \
+							EMASK_FBD_M2ERR | \
+							EMASK_FBD_M3ERR)
+
+#define 		ENABLE_EMASK_FBD_UNCORRECTABLE	(EMASK_FBD_M4ERR | \
+							EMASK_FBD_M5ERR | \
+							EMASK_FBD_M6ERR | \
+							EMASK_FBD_M7ERR | \
+							EMASK_FBD_M8ERR | \
+							EMASK_FBD_M9ERR | \
+							EMASK_FBD_M10ERR | \
+							EMASK_FBD_M11ERR | \
+							EMASK_FBD_M12ERR)
+#define 		ENABLE_EMASK_FBD_CORRECTABLE	(EMASK_FBD_M17ERR | \
+							EMASK_FBD_M18ERR | \
+							EMASK_FBD_M19ERR | \
+							EMASK_FBD_M20ERR)
+#define			ENABLE_EMASK_FBD_DIMM_SPARE	(EMASK_FBD_M27ERR | \
+							EMASK_FBD_M28ERR)
+#define			ENABLE_EMASK_FBD_THERMALS	(EMASK_FBD_M26ERR | \
+							EMASK_FBD_M25ERR | \
+							EMASK_FBD_M24ERR | \
+							EMASK_FBD_M23ERR)
+#define			ENABLE_EMASK_FBD_SPD_PROTOCOL	(EMASK_FBD_M22ERR)
+#define			ENABLE_EMASK_FBD_NORTH_CRC	(EMASK_FBD_M21ERR)
+#define			ENABLE_EMASK_FBD_NON_RETRY	(EMASK_FBD_M15ERR | \
+							EMASK_FBD_M14ERR | \
+							EMASK_FBD_M13ERR)
+
+#define		ENABLE_EMASK_ALL	(ENABLE_EMASK_FBD_NON_RETRY | \
+					ENABLE_EMASK_FBD_NORTH_CRC | \
+					ENABLE_EMASK_FBD_SPD_PROTOCOL | \
+					ENABLE_EMASK_FBD_THERMALS | \
+					ENABLE_EMASK_FBD_DIMM_SPARE | \
+					ENABLE_EMASK_FBD_FATAL_ERRORS | \
+					ENABLE_EMASK_FBD_CORRECTABLE | \
+					ENABLE_EMASK_FBD_UNCORRECTABLE)
+
+#define		ERR0_FBD		0xAC
+#define		ERR1_FBD		0xB0
+#define		ERR2_FBD		0xB4
+#define		MCERR_FBD		0xB8
+#define		NRECMEMA		0xBE
+#define			NREC_BANK(x)		(((x)>>12) & 0x7)
+#define			NREC_RDWR(x)		(((x)>>11) & 1)
+#define			NREC_RANK(x)		(((x)>>8) & 0x7)
+#define		NRECMEMB		0xC0
+#define			NREC_CAS(x)		(((x)>>16) & 0xFFFFFF)
+#define			NREC_RAS(x)		((x) & 0x7FFF)
+#define		NRECFGLOG		0xC4
+#define		NREEECFBDA		0xC8
+#define		NREEECFBDB		0xCC
+#define		NREEECFBDC		0xD0
+#define		NREEECFBDD		0xD4
+#define		NREEECFBDE		0xD8
+#define		REDMEMA			0xDC
+#define		RECMEMA			0xE2
+#define			REC_BANK(x)		(((x)>>12) & 0x7)
+#define			REC_RDWR(x)		(((x)>>11) & 1)
+#define			REC_RANK(x)		(((x)>>8) & 0x7)
+#define		RECMEMB			0xE4
+#define			REC_CAS(x)		(((x)>>16) & 0xFFFFFF)
+#define			REC_RAS(x)		((x) & 0x7FFF)
+#define		RECFGLOG		0xE8
+#define		RECFBDA			0xEC
+#define		RECFBDB			0xF0
+#define		RECFBDC			0xF4
+#define		RECFBDD			0xF8
+#define		RECFBDE			0xFC
+
+/* OFFSETS for Function 2 */
+
+/*
+ * Device 21,
+ * Function 0: Memory Map Branch 0
+ *
+ * Device 22,
+ * Function 0: Memory Map Branch 1
+ */
+#define PCI_DEVICE_ID_I5000_BRANCH_0	0x25F5
+#define PCI_DEVICE_ID_I5000_BRANCH_1	0x25F6
+
+#define AMB_PRESENT_0	0x64
+#define AMB_PRESENT_1	0x66
+#define MTR0		0x80
+#define MTR1		0x84
+#define MTR2		0x88
+#define MTR3		0x8C
+
+#define NUM_MTRS		4
+#define CHANNELS_PER_BRANCH	(2)
+
+/* Defines to extract the vaious fields from the
+ *	MTRx - Memory Technology Registers
+ */
+#define MTR_DIMMS_PRESENT(mtr)		((mtr) & (0x1 << 8))
+#define MTR_DRAM_WIDTH(mtr)		((((mtr) >> 6) & 0x1) ? 8 : 4)
+#define MTR_DRAM_BANKS(mtr)		((((mtr) >> 5) & 0x1) ? 8 : 4)
+#define MTR_DRAM_BANKS_ADDR_BITS(mtr)	((MTR_DRAM_BANKS(mtr) == 8) ? 3 : 2)
+#define MTR_DIMM_RANK(mtr)		(((mtr) >> 4) & 0x1)
+#define MTR_DIMM_RANK_ADDR_BITS(mtr)	(MTR_DIMM_RANK(mtr) ? 2 : 1)
+#define MTR_DIMM_ROWS(mtr)		(((mtr) >> 2) & 0x3)
+#define MTR_DIMM_ROWS_ADDR_BITS(mtr)	(MTR_DIMM_ROWS(mtr) + 13)
+#define MTR_DIMM_COLS(mtr)		((mtr) & 0x3)
+#define MTR_DIMM_COLS_ADDR_BITS(mtr)	(MTR_DIMM_COLS(mtr) + 10)
+
+#ifdef CONFIG_EDAC_DEBUG
+static char *numrow_toString[] = {
+	"8,192 - 13 rows",
+	"16,384 - 14 rows",
+	"32,768 - 15 rows",
+	"reserved"
+};
+
+static char *numcol_toString[] = {
+	"1,024 - 10 columns",
+	"2,048 - 11 columns",
+	"4,096 - 12 columns",
+	"reserved"
+};
+#endif
+
+/* Enumeration of supported devices */
+enum i5000_chips {
+	I5000P = 0,
+	I5000V = 1,		/* future */
+	I5000X = 2		/* future */
+};
+
+/* Device name and register DID (Device ID) */
+struct i5000_dev_info {
+	const char *ctl_name;	/* name for this device */
+	u16 fsb_mapping_errors;	/* DID for the branchmap,control */
+};
+
+/* Table of devices attributes supported by this driver */
+static const struct i5000_dev_info i5000_devs[] = {
+	[I5000P] = {
+		.ctl_name = "I5000",
+		.fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I5000_DEV16,
+	},
+};
+
+struct i5000_dimm_info {
+	int megabytes;		/* size, 0 means not present  */
+	int dual_rank;
+};
+
+#define	MAX_CHANNELS	6	/* max possible channels */
+#define MAX_CSROWS	(8*2)	/* max possible csrows per channel */
+
+/* driver private data structure */
+struct i5000_pvt {
+	struct pci_dev *system_address;	/* 16.0 */
+	struct pci_dev *branchmap_werrors;	/* 16.1 */
+	struct pci_dev *fsb_error_regs;	/* 16.2 */
+	struct pci_dev *branch_0;	/* 21.0 */
+	struct pci_dev *branch_1;	/* 22.0 */
+
+	u16 tolm;		/* top of low memory */
+	u64 ambase;		/* AMB BAR */
+
+	u16 mir0, mir1, mir2;
+
+	u16 b0_mtr[NUM_MTRS];	/* Memory Technlogy Reg */
+	u16 b0_ambpresent0;	/* Branch 0, Channel 0 */
+	u16 b0_ambpresent1;	/* Brnach 0, Channel 1 */
+
+	u16 b1_mtr[NUM_MTRS];	/* Memory Technlogy Reg */
+	u16 b1_ambpresent0;	/* Branch 1, Channel 8 */
+	u16 b1_ambpresent1;	/* Branch 1, Channel 1 */
+
+	/* DIMM infomation matrix, allocating architecture maximums */
+	struct i5000_dimm_info dimm_info[MAX_CSROWS][MAX_CHANNELS];
+
+	/* Actual values for this controller */
+	int maxch;		/* Max channels */
+	int maxdimmperch;	/* Max DIMMs per channel */
+};
+
+/* I5000 MCH error information retrieved from Hardware */
+struct i5000_error_info {
+
+	/* These registers are always read from the MC */
+	u32 ferr_fat_fbd;	/* First Errors Fatal */
+	u32 nerr_fat_fbd;	/* Next Errors Fatal */
+	u32 ferr_nf_fbd;	/* First Errors Non-Fatal */
+	u32 nerr_nf_fbd;	/* Next Errors Non-Fatal */
+
+	/* These registers are input ONLY if there was a Recoverable  Error */
+	u32 redmemb;		/* Recoverable Mem Data Error log B */
+	u16 recmema;		/* Recoverable Mem Error log A */
+	u32 recmemb;		/* Recoverable Mem Error log B */
+
+	/* These registers are input ONLY if there was a
+	 * Non-Recoverable Error */
+	u16 nrecmema;		/* Non-Recoverable Mem log A */
+	u16 nrecmemb;		/* Non-Recoverable Mem log B */
+
+};
+
+static struct edac_pci_ctl_info *i5000_pci;
+
+/*
+ *	i5000_get_error_info	Retrieve the hardware error information from
+ *				the hardware and cache it in the 'info'
+ *				structure
+ */
+static void i5000_get_error_info(struct mem_ctl_info *mci,
+				 struct i5000_error_info *info)
+{
+	struct i5000_pvt *pvt;
+	u32 value;
+
+	pvt = mci->pvt_info;
+
+	/* read in the 1st FATAL error register */
+	pci_read_config_dword(pvt->branchmap_werrors, FERR_FAT_FBD, &value);
+
+	/* Mask only the bits that the doc says are valid
+	 */
+	value &= (FERR_FAT_FBDCHAN | FERR_FAT_MASK);
+
+	/* If there is an error, then read in the */
+	/* NEXT FATAL error register and the Memory Error Log Register A */
+	if (value & FERR_FAT_MASK) {
+		info->ferr_fat_fbd = value;
+
+		/* harvest the various error data we need */
+		pci_read_config_dword(pvt->branchmap_werrors,
+				NERR_FAT_FBD, &info->nerr_fat_fbd);
+		pci_read_config_word(pvt->branchmap_werrors,
+				NRECMEMA, &info->nrecmema);
+		pci_read_config_word(pvt->branchmap_werrors,
+				NRECMEMB, &info->nrecmemb);
+
+		/* Clear the error bits, by writing them back */
+		pci_write_config_dword(pvt->branchmap_werrors,
+				FERR_FAT_FBD, value);
+	} else {
+		info->ferr_fat_fbd = 0;
+		info->nerr_fat_fbd = 0;
+		info->nrecmema = 0;
+		info->nrecmemb = 0;
+	}
+
+	/* read in the 1st NON-FATAL error register */
+	pci_read_config_dword(pvt->branchmap_werrors, FERR_NF_FBD, &value);
+
+	/* If there is an error, then read in the 1st NON-FATAL error
+	 * register as well */
+	if (value & FERR_NF_MASK) {
+		info->ferr_nf_fbd = value;
+
+		/* harvest the various error data we need */
+		pci_read_config_dword(pvt->branchmap_werrors,
+				NERR_NF_FBD, &info->nerr_nf_fbd);
+		pci_read_config_word(pvt->branchmap_werrors,
+				RECMEMA, &info->recmema);
+		pci_read_config_dword(pvt->branchmap_werrors,
+				RECMEMB, &info->recmemb);
+		pci_read_config_dword(pvt->branchmap_werrors,
+				REDMEMB, &info->redmemb);
+
+		/* Clear the error bits, by writing them back */
+		pci_write_config_dword(pvt->branchmap_werrors,
+				FERR_NF_FBD, value);
+	} else {
+		info->ferr_nf_fbd = 0;
+		info->nerr_nf_fbd = 0;
+		info->recmema = 0;
+		info->recmemb = 0;
+		info->redmemb = 0;
+	}
+}
+
+/*
+ * i5000_process_fatal_error_info(struct mem_ctl_info *mci,
+ * 					struct i5000_error_info *info,
+ * 					int handle_errors);
+ *
+ *	handle the Intel FATAL errors, if any
+ */
+static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
+					struct i5000_error_info *info,
+					int handle_errors)
+{
+	char msg[EDAC_MC_LABEL_LEN + 1 + 90];
+	u32 allErrors;
+	int branch;
+	int channel;
+	int bank;
+	int rank;
+	int rdwr;
+	int ras, cas;
+
+	/* mask off the Error bits that are possible */
+	allErrors = (info->ferr_fat_fbd & FERR_FAT_MASK);
+	if (!allErrors)
+		return;		/* if no error, return now */
+
+	/* ONLY ONE of the possible error bits will be set, as per the docs */
+	i5000_mc_printk(mci, KERN_ERR,
+			"FATAL ERRORS Found!!! 1st FATAL Err Reg= 0x%x\n",
+			allErrors);
+
+	branch = EXTRACT_FBDCHAN_INDX(info->ferr_fat_fbd);
+	channel = branch;
+
+	/* Use the NON-Recoverable macros to extract data */
+	bank = NREC_BANK(info->nrecmema);
+	rank = NREC_RANK(info->nrecmema);
+	rdwr = NREC_RDWR(info->nrecmema);
+	ras = NREC_RAS(info->nrecmemb);
+	cas = NREC_CAS(info->nrecmemb);
+
+	debugf0("\t\tCSROW= %d  Channels= %d,%d  (Branch= %d "
+		"DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+		rank, channel, channel + 1, branch >> 1, bank,
+		rdwr ? "Write" : "Read", ras, cas);
+
+	/* Only 1 bit will be on */
+	if (allErrors & FERR_FAT_M1ERR) {
+		i5000_mc_printk(mci, KERN_ERR,
+				"Alert on non-redundant retry or fast "
+				"reset timeout\n");
+
+	} else if (allErrors & FERR_FAT_M2ERR) {
+		i5000_mc_printk(mci, KERN_ERR,
+				"Northbound CRC error on non-redundant "
+				"retry\n");
+
+	} else if (allErrors & FERR_FAT_M3ERR) {
+		i5000_mc_printk(mci, KERN_ERR,
+				">Tmid Thermal event with intelligent "
+				"throttling disabled\n");
+	}
+
+	/* Form out message */
+	snprintf(msg, sizeof(msg),
+		 "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d CAS=%d "
+		 "FATAL Err=0x%x)",
+		 branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas,
+		 allErrors);
+
+	/* Call the helper to output message */
+	edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg);
+}
+
+/*
+ * i5000_process_fatal_error_info(struct mem_ctl_info *mci,
+ * 				struct i5000_error_info *info,
+ * 				int handle_errors);
+ *
+ *	handle the Intel NON-FATAL errors, if any
+ */
+static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
+					struct i5000_error_info *info,
+					int handle_errors)
+{
+	char msg[EDAC_MC_LABEL_LEN + 1 + 90];
+	u32 allErrors;
+	u32 ue_errors;
+	u32 ce_errors;
+	u32 misc_errors;
+	int branch;
+	int channel;
+	int bank;
+	int rank;
+	int rdwr;
+	int ras, cas;
+
+	/* mask off the Error bits that are possible */
+	allErrors = (info->ferr_nf_fbd & FERR_NF_MASK);
+	if (!allErrors)
+		return;		/* if no error, return now */
+
+	/* ONLY ONE of the possible error bits will be set, as per the docs */
+	i5000_mc_printk(mci, KERN_WARNING,
+			"NON-FATAL ERRORS Found!!! 1st NON-FATAL Err "
+			"Reg= 0x%x\n", allErrors);
+
+	ue_errors = allErrors & FERR_NF_UNCORRECTABLE;
+	if (ue_errors) {
+		debugf0("\tUncorrected bits= 0x%x\n", ue_errors);
+
+		branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd);
+		channel = branch;
+		bank = NREC_BANK(info->nrecmema);
+		rank = NREC_RANK(info->nrecmema);
+		rdwr = NREC_RDWR(info->nrecmema);
+		ras = NREC_RAS(info->nrecmemb);
+		cas = NREC_CAS(info->nrecmemb);
+
+		debugf0
+			("\t\tCSROW= %d  Channels= %d,%d  (Branch= %d "
+			"DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+			rank, channel, channel + 1, branch >> 1, bank,
+			rdwr ? "Write" : "Read", ras, cas);
+
+		/* Form out message */
+		snprintf(msg, sizeof(msg),
+			 "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d "
+			 "CAS=%d, UE Err=0x%x)",
+			 branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas,
+			 ue_errors);
+
+		/* Call the helper to output message */
+		edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg);
+	}
+
+	/* Check correctable errors */
+	ce_errors = allErrors & FERR_NF_CORRECTABLE;
+	if (ce_errors) {
+		debugf0("\tCorrected bits= 0x%x\n", ce_errors);
+
+		branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd);
+
+		channel = 0;
+		if (REC_ECC_LOCATOR_ODD(info->redmemb))
+			channel = 1;
+
+		/* Convert channel to be based from zero, instead of
+		 * from branch base of 0 */
+		channel += branch;
+
+		bank = REC_BANK(info->recmema);
+		rank = REC_RANK(info->recmema);
+		rdwr = REC_RDWR(info->recmema);
+		ras = REC_RAS(info->recmemb);
+		cas = REC_CAS(info->recmemb);
+
+		debugf0("\t\tCSROW= %d Channel= %d  (Branch %d "
+			"DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
+			rank, channel, branch >> 1, bank,
+			rdwr ? "Write" : "Read", ras, cas);
+
+		/* Form out message */
+		snprintf(msg, sizeof(msg),
+			 "(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d "
+			 "CAS=%d, CE Err=0x%x)", branch >> 1, bank,
+			 rdwr ? "Write" : "Read", ras, cas, ce_errors);
+
+		/* Call the helper to output message */
+		edac_mc_handle_fbd_ce(mci, rank, channel, msg);
+	}
+
+	/* See if any of the thermal errors have fired */
+	misc_errors = allErrors & FERR_NF_THERMAL;
+	if (misc_errors) {
+		i5000_printk(KERN_WARNING, "\tTHERMAL Error, bits= 0x%x\n",
+			misc_errors);
+	}
+
+	/* See if any of the thermal errors have fired */
+	misc_errors = allErrors & FERR_NF_NON_RETRY;
+	if (misc_errors) {
+		i5000_printk(KERN_WARNING, "\tNON-Retry  Errors, bits= 0x%x\n",
+			misc_errors);
+	}
+
+	/* See if any of the thermal errors have fired */
+	misc_errors = allErrors & FERR_NF_NORTH_CRC;
+	if (misc_errors) {
+		i5000_printk(KERN_WARNING,
+			"\tNORTHBOUND CRC  Error, bits= 0x%x\n",
+			misc_errors);
+	}
+
+	/* See if any of the thermal errors have fired */
+	misc_errors = allErrors & FERR_NF_SPD_PROTOCOL;
+	if (misc_errors) {
+		i5000_printk(KERN_WARNING,
+			"\tSPD Protocol  Error, bits= 0x%x\n",
+			misc_errors);
+	}
+
+	/* See if any of the thermal errors have fired */
+	misc_errors = allErrors & FERR_NF_DIMM_SPARE;
+	if (misc_errors) {
+		i5000_printk(KERN_WARNING, "\tDIMM-Spare  Error, bits= 0x%x\n",
+			misc_errors);
+	}
+}
+
+/*
+ *	i5000_process_error_info	Process the error info that is
+ *	in the 'info' structure, previously retrieved from hardware
+ */
+static void i5000_process_error_info(struct mem_ctl_info *mci,
+				struct i5000_error_info *info,
+				int handle_errors)
+{
+	/* First handle any fatal errors that occurred */
+	i5000_process_fatal_error_info(mci, info, handle_errors);
+
+	/* now handle any non-fatal errors that occurred */
+	i5000_process_nonfatal_error_info(mci, info, handle_errors);
+}
+
+/*
+ *	i5000_clear_error	Retrieve any error from the hardware
+ *				but do NOT process that error.
+ *				Used for 'clearing' out of previous errors
+ *				Called by the Core module.
+ */
+static void i5000_clear_error(struct mem_ctl_info *mci)
+{
+	struct i5000_error_info info;
+
+	i5000_get_error_info(mci, &info);
+}
+
+/*
+ *	i5000_check_error	Retrieve and process errors reported by the
+ *				hardware. Called by the Core module.
+ */
+static void i5000_check_error(struct mem_ctl_info *mci)
+{
+	struct i5000_error_info info;
+	debugf4("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+	i5000_get_error_info(mci, &info);
+	i5000_process_error_info(mci, &info, 1);
+}
+
+/*
+ *	i5000_get_devices	Find and perform 'get' operation on the MCH's
+ *			device/functions we want to reference for this driver
+ *
+ *			Need to 'get' device 16 func 1 and func 2
+ */
+static int i5000_get_devices(struct mem_ctl_info *mci, int dev_idx)
+{
+	//const struct i5000_dev_info *i5000_dev = &i5000_devs[dev_idx];
+	struct i5000_pvt *pvt;
+	struct pci_dev *pdev;
+
+	pvt = mci->pvt_info;
+
+	/* Attempt to 'get' the MCH register we want */
+	pdev = NULL;
+	while (1) {
+		pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+				PCI_DEVICE_ID_INTEL_I5000_DEV16, pdev);
+
+		/* End of list, leave */
+		if (pdev == NULL) {
+			i5000_printk(KERN_ERR,
+				"'system address,Process Bus' "
+				"device not found:"
+				"vendor 0x%x device 0x%x FUNC 1 "
+				"(broken BIOS?)\n",
+				PCI_VENDOR_ID_INTEL,
+				PCI_DEVICE_ID_INTEL_I5000_DEV16);
+
+			return 1;
+		}
+
+		/* Scan for device 16 func 1 */
+		if (PCI_FUNC(pdev->devfn) == 1)
+			break;
+	}
+
+	pvt->branchmap_werrors = pdev;
+
+	/* Attempt to 'get' the MCH register we want */
+	pdev = NULL;
+	while (1) {
+		pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+				PCI_DEVICE_ID_INTEL_I5000_DEV16, pdev);
+
+		if (pdev == NULL) {
+			i5000_printk(KERN_ERR,
+				"MC: 'branchmap,control,errors' "
+				"device not found:"
+				"vendor 0x%x device 0x%x Func 2 "
+				"(broken BIOS?)\n",
+				PCI_VENDOR_ID_INTEL,
+				PCI_DEVICE_ID_INTEL_I5000_DEV16);
+
+			pci_dev_put(pvt->branchmap_werrors);
+			return 1;
+		}
+
+		/* Scan for device 16 func 1 */
+		if (PCI_FUNC(pdev->devfn) == 2)
+			break;
+	}
+
+	pvt->fsb_error_regs = pdev;
+
+	debugf1("System Address, processor bus- PCI Bus ID: %s  %x:%x\n",
+		pci_name(pvt->system_address),
+		pvt->system_address->vendor, pvt->system_address->device);
+	debugf1("Branchmap, control and errors - PCI Bus ID: %s  %x:%x\n",
+		pci_name(pvt->branchmap_werrors),
+		pvt->branchmap_werrors->vendor, pvt->branchmap_werrors->device);
+	debugf1("FSB Error Regs - PCI Bus ID: %s  %x:%x\n",
+		pci_name(pvt->fsb_error_regs),
+		pvt->fsb_error_regs->vendor, pvt->fsb_error_regs->device);
+
+	pdev = NULL;
+	pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+			PCI_DEVICE_ID_I5000_BRANCH_0, pdev);
+
+	if (pdev == NULL) {
+		i5000_printk(KERN_ERR,
+			"MC: 'BRANCH 0' device not found:"
+			"vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n",
+			PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_I5000_BRANCH_0);
+
+		pci_dev_put(pvt->branchmap_werrors);
+		pci_dev_put(pvt->fsb_error_regs);
+		return 1;
+	}
+
+	pvt->branch_0 = pdev;
+
+	/* If this device claims to have more than 2 channels then
+	 * fetch Branch 1's information
+	 */
+	if (pvt->maxch >= CHANNELS_PER_BRANCH) {
+		pdev = NULL;
+		pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+				PCI_DEVICE_ID_I5000_BRANCH_1, pdev);
+
+		if (pdev == NULL) {
+			i5000_printk(KERN_ERR,
+				"MC: 'BRANCH 1' device not found:"
+				"vendor 0x%x device 0x%x Func 0 "
+				"(broken BIOS?)\n",
+				PCI_VENDOR_ID_INTEL,
+				PCI_DEVICE_ID_I5000_BRANCH_1);
+
+			pci_dev_put(pvt->branchmap_werrors);
+			pci_dev_put(pvt->fsb_error_regs);
+			pci_dev_put(pvt->branch_0);
+			return 1;
+		}
+
+		pvt->branch_1 = pdev;
+	}
+
+	return 0;
+}
+
+/*
+ *	i5000_put_devices	'put' all the devices that we have
+ *				reserved via 'get'
+ */
+static void i5000_put_devices(struct mem_ctl_info *mci)
+{
+	struct i5000_pvt *pvt;
+
+	pvt = mci->pvt_info;
+
+	pci_dev_put(pvt->branchmap_werrors);	/* FUNC 1 */
+	pci_dev_put(pvt->fsb_error_regs);	/* FUNC 2 */
+	pci_dev_put(pvt->branch_0);	/* DEV 21 */
+
+	/* Only if more than 2 channels do we release the second branch */
+	if (pvt->maxch >= CHANNELS_PER_BRANCH)
+		pci_dev_put(pvt->branch_1);	/* DEV 22 */
+}
+
+/*
+ *	determine_amb_resent
+ *
+ *		the information is contained in NUM_MTRS different registers
+ *		determineing which of the NUM_MTRS requires knowing
+ *		which channel is in question
+ *
+ *	2 branches, each with 2 channels
+ *		b0_ambpresent0 for channel '0'
+ *		b0_ambpresent1 for channel '1'
+ *		b1_ambpresent0 for channel '2'
+ *		b1_ambpresent1 for channel '3'
+ */
+static int determine_amb_present_reg(struct i5000_pvt *pvt, int channel)
+{
+	int amb_present;
+
+	if (channel < CHANNELS_PER_BRANCH) {
+		if (channel & 0x1)
+			amb_present = pvt->b0_ambpresent1;
+		else
+			amb_present = pvt->b0_ambpresent0;
+	} else {
+		if (channel & 0x1)
+			amb_present = pvt->b1_ambpresent1;
+		else
+			amb_present = pvt->b1_ambpresent0;
+	}
+
+	return amb_present;
+}
+
+/*
+ * determine_mtr(pvt, csrow, channel)
+ *
+ *	return the proper MTR register as determine by the csrow and channel desired
+ */
+static int determine_mtr(struct i5000_pvt *pvt, int csrow, int channel)
+{
+	int mtr;
+
+	if (channel < CHANNELS_PER_BRANCH)
+		mtr = pvt->b0_mtr[csrow >> 1];
+	else
+		mtr = pvt->b1_mtr[csrow >> 1];
+
+	return mtr;
+}
+
+/*
+ */
+static void decode_mtr(int slot_row, u16 mtr)
+{
+	int ans;
+
+	ans = MTR_DIMMS_PRESENT(mtr);
+
+	debugf2("\tMTR%d=0x%x:  DIMMs are %s\n", slot_row, mtr,
+		ans ? "Present" : "NOT Present");
+	if (!ans)
+		return;
+
+	debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
+	debugf2("\t\tNUMBANK: %d bank(s)\n", MTR_DRAM_BANKS(mtr));
+	debugf2("\t\tNUMRANK: %s\n", MTR_DIMM_RANK(mtr) ? "double" : "single");
+	debugf2("\t\tNUMROW: %s\n", numrow_toString[MTR_DIMM_ROWS(mtr)]);
+	debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
+}
+
+static void handle_channel(struct i5000_pvt *pvt, int csrow, int channel,
+			struct i5000_dimm_info *dinfo)
+{
+	int mtr;
+	int amb_present_reg;
+	int addrBits;
+
+	mtr = determine_mtr(pvt, csrow, channel);
+	if (MTR_DIMMS_PRESENT(mtr)) {
+		amb_present_reg = determine_amb_present_reg(pvt, channel);
+
+		/* Determine if there is  a  DIMM present in this DIMM slot */
+		if (amb_present_reg & (1 << (csrow >> 1))) {
+			dinfo->dual_rank = MTR_DIMM_RANK(mtr);
+
+			if (!((dinfo->dual_rank == 0) &&
+				((csrow & 0x1) == 0x1))) {
+				/* Start with the number of bits for a Bank
+				 * on the DRAM */
+				addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr);
+				/* Add thenumber of ROW bits */
+				addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr);
+				/* add the number of COLUMN bits */
+				addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr);
+
+				addrBits += 6;	/* add 64 bits per DIMM */
+				addrBits -= 20;	/* divide by 2^^20 */
+				addrBits -= 3;	/* 8 bits per bytes */
+
+				dinfo->megabytes = 1 << addrBits;
+			}
+		}
+	}
+}
+
+/*
+ *	calculate_dimm_size
+ *
+ *	also will output a DIMM matrix map, if debug is enabled, for viewing
+ *	how the DIMMs are populated
+ */
+static void calculate_dimm_size(struct i5000_pvt *pvt)
+{
+	struct i5000_dimm_info *dinfo;
+	int csrow, max_csrows;
+	char *p, *mem_buffer;
+	int space, n;
+	int channel;
+
+	/* ================= Generate some debug output ================= */
+	space = PAGE_SIZE;
+	mem_buffer = p = kmalloc(space, GFP_KERNEL);
+	if (p == NULL) {
+		i5000_printk(KERN_ERR, "MC: %s:%s() kmalloc() failed\n",
+			__FILE__, __func__);
+		return;
+	}
+
+	n = snprintf(p, space, "\n");
+	p += n;
+	space -= n;
+
+	/* Scan all the actual CSROWS (which is # of DIMMS * 2)
+	 * and calculate the information for each DIMM
+	 * Start with the highest csrow first, to display it first
+	 * and work toward the 0th csrow
+	 */
+	max_csrows = pvt->maxdimmperch * 2;
+	for (csrow = max_csrows - 1; csrow >= 0; csrow--) {
+
+		/* on an odd csrow, first output a 'boundary' marker,
+		 * then reset the message buffer  */
+		if (csrow & 0x1) {
+			n = snprintf(p, space, "---------------------------"
+				"--------------------------------");
+			p += n;
+			space -= n;
+			debugf2("%s\n", mem_buffer);
+			p = mem_buffer;
+			space = PAGE_SIZE;
+		}
+		n = snprintf(p, space, "csrow %2d    ", csrow);
+		p += n;
+		space -= n;
+
+		for (channel = 0; channel < pvt->maxch; channel++) {
+			dinfo = &pvt->dimm_info[csrow][channel];
+			handle_channel(pvt, csrow, channel, dinfo);
+			n = snprintf(p, space, "%4d MB   | ", dinfo->megabytes);
+			p += n;
+			space -= n;
+		}
+		n = snprintf(p, space, "\n");
+		p += n;
+		space -= n;
+	}
+
+	/* Output the last bottom 'boundary' marker */
+	n = snprintf(p, space, "---------------------------"
+		"--------------------------------\n");
+	p += n;
+	space -= n;
+
+	/* now output the 'channel' labels */
+	n = snprintf(p, space, "            ");
+	p += n;
+	space -= n;
+	for (channel = 0; channel < pvt->maxch; channel++) {
+		n = snprintf(p, space, "channel %d | ", channel);
+		p += n;
+		space -= n;
+	}
+	n = snprintf(p, space, "\n");
+	p += n;
+	space -= n;
+
+	/* output the last message and free buffer */
+	debugf2("%s\n", mem_buffer);
+	kfree(mem_buffer);
+}
+
+/*
+ *	i5000_get_mc_regs	read in the necessary registers and
+ *				cache locally
+ *
+ *			Fills in the private data members
+ */
+static void i5000_get_mc_regs(struct mem_ctl_info *mci)
+{
+	struct i5000_pvt *pvt;
+	u32 actual_tolm;
+	u16 limit;
+	int slot_row;
+	int maxch;
+	int maxdimmperch;
+	int way0, way1;
+
+	pvt = mci->pvt_info;
+
+	pci_read_config_dword(pvt->system_address, AMBASE,
+			(u32 *) & pvt->ambase);
+	pci_read_config_dword(pvt->system_address, AMBASE + sizeof(u32),
+			((u32 *) & pvt->ambase) + sizeof(u32));
+
+	maxdimmperch = pvt->maxdimmperch;
+	maxch = pvt->maxch;
+
+	debugf2("AMBASE= 0x%lx  MAXCH= %d  MAX-DIMM-Per-CH= %d\n",
+		(long unsigned int)pvt->ambase, pvt->maxch, pvt->maxdimmperch);
+
+	/* Get the Branch Map regs */
+	pci_read_config_word(pvt->branchmap_werrors, TOLM, &pvt->tolm);
+	pvt->tolm >>= 12;
+	debugf2("\nTOLM (number of 256M regions) =%u (0x%x)\n", pvt->tolm,
+		pvt->tolm);
+
+	actual_tolm = pvt->tolm << 28;
+	debugf2("Actual TOLM byte addr=%u (0x%x)\n", actual_tolm, actual_tolm);
+
+	pci_read_config_word(pvt->branchmap_werrors, MIR0, &pvt->mir0);
+	pci_read_config_word(pvt->branchmap_werrors, MIR1, &pvt->mir1);
+	pci_read_config_word(pvt->branchmap_werrors, MIR2, &pvt->mir2);
+
+	/* Get the MIR[0-2] regs */
+	limit = (pvt->mir0 >> 4) & 0x0FFF;
+	way0 = pvt->mir0 & 0x1;
+	way1 = pvt->mir0 & 0x2;
+	debugf2("MIR0: limit= 0x%x  WAY1= %u  WAY0= %x\n", limit, way1, way0);
+	limit = (pvt->mir1 >> 4) & 0x0FFF;
+	way0 = pvt->mir1 & 0x1;
+	way1 = pvt->mir1 & 0x2;
+	debugf2("MIR1: limit= 0x%x  WAY1= %u  WAY0= %x\n", limit, way1, way0);
+	limit = (pvt->mir2 >> 4) & 0x0FFF;
+	way0 = pvt->mir2 & 0x1;
+	way1 = pvt->mir2 & 0x2;
+	debugf2("MIR2: limit= 0x%x  WAY1= %u  WAY0= %x\n", limit, way1, way0);
+
+	/* Get the MTR[0-3] regs */
+	for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
+		int where = MTR0 + (slot_row * sizeof(u32));
+
+		pci_read_config_word(pvt->branch_0, where,
+				&pvt->b0_mtr[slot_row]);
+
+		debugf2("MTR%d where=0x%x B0 value=0x%x\n", slot_row, where,
+			pvt->b0_mtr[slot_row]);
+
+		if (pvt->maxch >= CHANNELS_PER_BRANCH) {
+			pci_read_config_word(pvt->branch_1, where,
+					&pvt->b1_mtr[slot_row]);
+			debugf2("MTR%d where=0x%x B1 value=0x%x\n", slot_row,
+				where, pvt->b0_mtr[slot_row]);
+		} else {
+			pvt->b1_mtr[slot_row] = 0;
+		}
+	}
+
+	/* Read and dump branch 0's MTRs */
+	debugf2("\nMemory Technology Registers:\n");
+	debugf2("   Branch 0:\n");
+	for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
+		decode_mtr(slot_row, pvt->b0_mtr[slot_row]);
+	}
+	pci_read_config_word(pvt->branch_0, AMB_PRESENT_0,
+			&pvt->b0_ambpresent0);
+	debugf2("\t\tAMB-Branch 0-present0 0x%x:\n", pvt->b0_ambpresent0);
+	pci_read_config_word(pvt->branch_0, AMB_PRESENT_1,
+			&pvt->b0_ambpresent1);
+	debugf2("\t\tAMB-Branch 0-present1 0x%x:\n", pvt->b0_ambpresent1);
+
+	/* Only if we have 2 branchs (4 channels) */
+	if (pvt->maxch < CHANNELS_PER_BRANCH) {
+		pvt->b1_ambpresent0 = 0;
+		pvt->b1_ambpresent1 = 0;
+	} else {
+		/* Read and dump  branch 1's MTRs */
+		debugf2("   Branch 1:\n");
+		for (slot_row = 0; slot_row < NUM_MTRS; slot_row++) {
+			decode_mtr(slot_row, pvt->b1_mtr[slot_row]);
+		}
+		pci_read_config_word(pvt->branch_1, AMB_PRESENT_0,
+				&pvt->b1_ambpresent0);
+		debugf2("\t\tAMB-Branch 1-present0 0x%x:\n",
+			pvt->b1_ambpresent0);
+		pci_read_config_word(pvt->branch_1, AMB_PRESENT_1,
+				&pvt->b1_ambpresent1);
+		debugf2("\t\tAMB-Branch 1-present1 0x%x:\n",
+			pvt->b1_ambpresent1);
+	}
+
+	/* Go and determine the size of each DIMM and place in an
+	 * orderly matrix */
+	calculate_dimm_size(pvt);
+}
+
+/*
+ *	i5000_init_csrows	Initialize the 'csrows' table within
+ *				the mci control	structure with the
+ *				addressing of memory.
+ *
+ *	return:
+ *		0	success
+ *		1	no actual memory found on this MC
+ */
+static int i5000_init_csrows(struct mem_ctl_info *mci)
+{
+	struct i5000_pvt *pvt;
+	struct csrow_info *p_csrow;
+	int empty, channel_count;
+	int max_csrows;
+	int mtr;
+	int csrow_megs;
+	int channel;
+	int csrow;
+
+	pvt = mci->pvt_info;
+
+	channel_count = pvt->maxch;
+	max_csrows = pvt->maxdimmperch * 2;
+
+	empty = 1;		/* Assume NO memory */
+
+	for (csrow = 0; csrow < max_csrows; csrow++) {
+		p_csrow = &mci->csrows[csrow];
+
+		p_csrow->csrow_idx = csrow;
+
+		/* use branch 0 for the basis */
+		mtr = pvt->b0_mtr[csrow >> 1];
+
+		/* if no DIMMS on this row, continue */
+		if (!MTR_DIMMS_PRESENT(mtr))
+			continue;
+
+		/* FAKE OUT VALUES, FIXME */
+		p_csrow->first_page = 0 + csrow * 20;
+		p_csrow->last_page = 9 + csrow * 20;
+		p_csrow->page_mask = 0xFFF;
+
+		p_csrow->grain = 8;
+
+		csrow_megs = 0;
+		for (channel = 0; channel < pvt->maxch; channel++) {
+			csrow_megs += pvt->dimm_info[csrow][channel].megabytes;
+		}
+
+		p_csrow->nr_pages = csrow_megs << 8;
+
+		/* Assume DDR2 for now */
+		p_csrow->mtype = MEM_FB_DDR2;
+
+		/* ask what device type on this row */
+		if (MTR_DRAM_WIDTH(mtr))
+			p_csrow->dtype = DEV_X8;
+		else
+			p_csrow->dtype = DEV_X4;
+
+		p_csrow->edac_mode = EDAC_S8ECD8ED;
+
+		empty = 0;
+	}
+
+	return empty;
+}
+
+/*
+ *	i5000_enable_error_reporting
+ *			Turn on the memory reporting features of the hardware
+ */
+static void i5000_enable_error_reporting(struct mem_ctl_info *mci)
+{
+	struct i5000_pvt *pvt;
+	u32 fbd_error_mask;
+
+	pvt = mci->pvt_info;
+
+	/* Read the FBD Error Mask Register */
+	pci_read_config_dword(pvt->branchmap_werrors, EMASK_FBD,
+			&fbd_error_mask);
+
+	/* Enable with a '0' */
+	fbd_error_mask &= ~(ENABLE_EMASK_ALL);
+
+	pci_write_config_dword(pvt->branchmap_werrors, EMASK_FBD,
+			fbd_error_mask);
+}
+
+/*
+ * i5000_get_dimm_and_channel_counts(pdev, &num_csrows, &num_channels)
+ *
+ *	ask the device how many channels are present and how many CSROWS
+ *	 as well
+ */
+static void i5000_get_dimm_and_channel_counts(struct pci_dev *pdev,
+					int *num_dimms_per_channel,
+					int *num_channels)
+{
+	u8 value;
+
+	/* Need to retrieve just how many channels and dimms per channel are
+	 * supported on this memory controller
+	 */
+	pci_read_config_byte(pdev, MAXDIMMPERCH, &value);
+	*num_dimms_per_channel = (int)value *2;
+
+	pci_read_config_byte(pdev, MAXCH, &value);
+	*num_channels = (int)value;
+}
+
+/*
+ *	i5000_probe1	Probe for ONE instance of device to see if it is
+ *			present.
+ *	return:
+ *		0 for FOUND a device
+ *		< 0 for error code
+ */
+static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
+{
+	struct mem_ctl_info *mci;
+	struct i5000_pvt *pvt;
+	int num_channels;
+	int num_dimms_per_channel;
+	int num_csrows;
+
+	debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n",
+		__func__,
+		pdev->bus->number,
+		PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+
+	/* We only are looking for func 0 of the set */
+	if (PCI_FUNC(pdev->devfn) != 0)
+		return -ENODEV;
+
+	/* make sure error reporting method is sane */
+	switch (edac_op_state) {
+	case EDAC_OPSTATE_POLL:
+	case EDAC_OPSTATE_NMI:
+		break;
+	default:
+		edac_op_state = EDAC_OPSTATE_POLL;
+		break;
+	}
+
+	/* Ask the devices for the number of CSROWS and CHANNELS so
+	 * that we can calculate the memory resources, etc
+	 *
+	 * The Chipset will report what it can handle which will be greater
+	 * or equal to what the motherboard manufacturer will implement.
+	 *
+	 * As we don't have a motherboard identification routine to determine
+	 * actual number of slots/dimms per channel, we thus utilize the
+	 * resource as specified by the chipset. Thus, we might have
+	 * have more DIMMs per channel than actually on the mobo, but this
+	 * allows the driver to support upto the chipset max, without
+	 * some fancy mobo determination.
+	 */
+	i5000_get_dimm_and_channel_counts(pdev, &num_dimms_per_channel,
+					&num_channels);
+	num_csrows = num_dimms_per_channel * 2;
+
+	debugf0("MC: %s(): Number of - Channels= %d  DIMMS= %d  CSROWS= %d\n",
+		__func__, num_channels, num_dimms_per_channel, num_csrows);
+
+	/* allocate a new MC control structure */
+	mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0);
+
+	if (mci == NULL)
+		return -ENOMEM;
+
+	debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+
+	mci->dev = &pdev->dev;	/* record ptr  to the generic device */
+
+	pvt = mci->pvt_info;
+	pvt->system_address = pdev;	/* Record this device in our private */
+	pvt->maxch = num_channels;
+	pvt->maxdimmperch = num_dimms_per_channel;
+
+	/* 'get' the pci devices we want to reserve for our use */
+	if (i5000_get_devices(mci, dev_idx))
+		goto fail0;
+
+	/* Time to get serious */
+	i5000_get_mc_regs(mci);	/* retrieve the hardware registers */
+
+	mci->mc_idx = 0;
+	mci->mtype_cap = MEM_FLAG_FB_DDR2;
+	mci->edac_ctl_cap = EDAC_FLAG_NONE;
+	mci->edac_cap = EDAC_FLAG_NONE;
+	mci->mod_name = "i5000_edac.c";
+	mci->mod_ver = I5000_REVISION;
+	mci->ctl_name = i5000_devs[dev_idx].ctl_name;
+	mci->dev_name = pci_name(pdev);
+	mci->ctl_page_to_phys = NULL;
+
+	/* Set the function pointer to an actual operation function */
+	mci->edac_check = i5000_check_error;
+
+	/* initialize the MC control structure 'csrows' table
+	 * with the mapping and control information */
+	if (i5000_init_csrows(mci)) {
+		debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n"
+			"    because i5000_init_csrows() returned nonzero "
+			"value\n");
+		mci->edac_cap = EDAC_FLAG_NONE;	/* no csrows found */
+	} else {
+		debugf1("MC: Enable error reporting now\n");
+		i5000_enable_error_reporting(mci);
+	}
+
+	/* add this new MC control structure to EDAC's list of MCs */
+	if (edac_mc_add_mc(mci)) {
+		debugf0("MC: " __FILE__
+			": %s(): failed edac_mc_add_mc()\n", __func__);
+		/* FIXME: perhaps some code should go here that disables error
+		 * reporting if we just enabled it
+		 */
+		goto fail1;
+	}
+
+	i5000_clear_error(mci);
+
+	/* allocating generic PCI control info */
+	i5000_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+	if (!i5000_pci) {
+		printk(KERN_WARNING
+			"%s(): Unable to create PCI control\n",
+			__func__);
+		printk(KERN_WARNING
+			"%s(): PCI error report via EDAC not setup\n",
+			__func__);
+	}
+
+	return 0;
+
+	/* Error exit unwinding stack */
+fail1:
+
+	i5000_put_devices(mci);
+
+fail0:
+	edac_mc_free(mci);
+	return -ENODEV;
+}
+
+/*
+ *	i5000_init_one	constructor for one instance of device
+ *
+ * 	returns:
+ *		negative on error
+ *		count (>= 0)
+ */
+static int __devinit i5000_init_one(struct pci_dev *pdev,
+				const struct pci_device_id *id)
+{
+	int rc;
+
+	debugf0("MC: " __FILE__ ": %s()\n", __func__);
+
+	/* wake up device */
+	rc = pci_enable_device(pdev);
+	if (rc == -EIO)
+		return rc;
+
+	/* now probe and enable the device */
+	return i5000_probe1(pdev, id->driver_data);
+}
+
+/*
+ *	i5000_remove_one	destructor for one instance of device
+ *
+ */
+static void __devexit i5000_remove_one(struct pci_dev *pdev)
+{
+	struct mem_ctl_info *mci;
+
+	debugf0(__FILE__ ": %s()\n", __func__);
+
+	if (i5000_pci)
+		edac_pci_release_generic_ctl(i5000_pci);
+
+	if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
+		return;
+
+	/* retrieve references to resources, and free those resources */
+	i5000_put_devices(mci);
+
+	edac_mc_free(mci);
+}
+
+/*
+ *	pci_device_id	table for which devices we are looking for
+ *
+ *	The "E500P" device is the first device supported.
+ */
+static const struct pci_device_id i5000_pci_tbl[] __devinitdata = {
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I5000_DEV16),
+	 .driver_data = I5000P},
+
+	{0,}			/* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i5000_pci_tbl);
+
+/*
+ *	i5000_driver	pci_driver structure for this module
+ *
+ */
+static struct pci_driver i5000_driver = {
+	.name = __stringify(KBUILD_BASENAME),
+	.probe = i5000_init_one,
+	.remove = __devexit_p(i5000_remove_one),
+	.id_table = i5000_pci_tbl,
+};
+
+/*
+ *	i5000_init		Module entry function
+ *			Try to initialize this module for its devices
+ */
+static int __init i5000_init(void)
+{
+	int pci_rc;
+
+	debugf2("MC: " __FILE__ ": %s()\n", __func__);
+
+	pci_rc = pci_register_driver(&i5000_driver);
+
+	return (pci_rc < 0) ? pci_rc : 0;
+}
+
+/*
+ *	i5000_exit()	Module exit function
+ *			Unregister the driver
+ */
+static void __exit i5000_exit(void)
+{
+	debugf2("MC: " __FILE__ ": %s()\n", __func__);
+	pci_unregister_driver(&i5000_driver);
+}
+
+module_init(i5000_init);
+module_exit(i5000_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR
+    ("Linux Networx (http://lnxi.com) Doug Thompson <norsk5@xmission.com>");
+MODULE_DESCRIPTION("MC Driver for Intel I5000 memory controllers - "
+		I5000_REVISION);
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c
new file mode 100644
index 0000000..83bfe37
--- /dev/null
+++ b/drivers/edac/i82443bxgx_edac.c
@@ -0,0 +1,402 @@
+/*
+ * Intel 82443BX/GX (440BX/GX chipset) Memory Controller EDAC kernel
+ * module (C) 2006 Tim Small
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License.
+ *
+ * Written by Tim Small <tim@buttersideup.com>, based on work by Linux
+ * Networx, Thayne Harbaugh, Dan Hollis <goemon at anime dot net> and
+ * others.
+ *
+ * 440GX fix by Jason Uhlenkott <juhlenko@akamai.com>.
+ *
+ * Written with reference to 82443BX Host Bridge Datasheet:
+ * http://www.intel.com/design/chipsets/440/documentation.htm
+ * references to this document given in [].
+ *
+ * This module doesn't support the 440LX, but it may be possible to
+ * make it do so (the 440LX's register definitions are different, but
+ * not completely so - I haven't studied them in enough detail to know
+ * how easy this would be).
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#include <linux/slab.h>
+
+#include "edac_core.h"
+
+#define I82443_REVISION	"0.1"
+
+#define EDAC_MOD_STR    "i82443bxgx_edac"
+
+/* The 82443BX supports SDRAM, or EDO (EDO for mobile only), "Memory
+ * Size: 8 MB to 512 MB (1GB with Registered DIMMs) with eight memory
+ * rows" "The 82443BX supports multiple-bit error detection and
+ * single-bit error correction when ECC mode is enabled and
+ * single/multi-bit error detection when correction is disabled.
+ * During writes to the DRAM, the 82443BX generates ECC for the data
+ * on a QWord basis. Partial QWord writes require a read-modify-write
+ * cycle when ECC is enabled."
+*/
+
+/* "Additionally, the 82443BX ensures that the data is corrected in
+ * main memory so that accumulation of errors is prevented. Another
+ * error within the same QWord would result in a double-bit error
+ * which is unrecoverable. This is known as hardware scrubbing since
+ * it requires no software intervention to correct the data in memory."
+ */
+
+/* [Also see page 100 (section 4.3), "DRAM Interface"]
+ * [Also see page 112 (section 4.6.1.4), ECC]
+ */
+
+#define I82443BXGX_NR_CSROWS 8
+#define I82443BXGX_NR_CHANS  1
+#define I82443BXGX_NR_DIMMS  4
+
+/* 82443 PCI Device 0 */
+#define I82443BXGX_NBXCFG 0x50	/* 32bit register starting at this PCI
+				 * config space offset */
+#define I82443BXGX_NBXCFG_OFFSET_NON_ECCROW 24	/* Array of bits, zero if
+						 * row is non-ECC */
+#define I82443BXGX_NBXCFG_OFFSET_DRAM_FREQ 12	/* 2 bits,00=100MHz,10=66 MHz */
+
+#define I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY 7	/* 2 bits:       */
+#define I82443BXGX_NBXCFG_INTEGRITY_NONE   0x0	/* 00 = Non-ECC */
+#define I82443BXGX_NBXCFG_INTEGRITY_EC     0x1	/* 01 = EC (only) */
+#define I82443BXGX_NBXCFG_INTEGRITY_ECC    0x2	/* 10 = ECC */
+#define I82443BXGX_NBXCFG_INTEGRITY_SCRUB  0x3	/* 11 = ECC + HW Scrub */
+
+#define I82443BXGX_NBXCFG_OFFSET_ECC_DIAG_ENABLE  6
+
+/* 82443 PCI Device 0 */
+#define I82443BXGX_EAP   0x80	/* 32bit register starting at this PCI
+				 * config space offset, Error Address
+				 * Pointer Register */
+#define I82443BXGX_EAP_OFFSET_EAP  12	/* High 20 bits of error address */
+#define I82443BXGX_EAP_OFFSET_MBE  BIT(1)	/* Err at EAP was multi-bit (W1TC) */
+#define I82443BXGX_EAP_OFFSET_SBE  BIT(0)	/* Err at EAP was single-bit (W1TC) */
+
+#define I82443BXGX_ERRCMD  0x90	/* 8bit register starting at this PCI
+				 * config space offset. */
+#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_MBE BIT(1)	/* 1 = enable */
+#define I82443BXGX_ERRCMD_OFFSET_SERR_ON_SBE BIT(0)	/* 1 = enable */
+
+#define I82443BXGX_ERRSTS  0x91	/* 16bit register starting at this PCI
+				 * config space offset. */
+#define I82443BXGX_ERRSTS_OFFSET_MBFRE 5	/* 3 bits - first err row multibit */
+#define I82443BXGX_ERRSTS_OFFSET_MEF   BIT(4)	/* 1 = MBE occurred */
+#define I82443BXGX_ERRSTS_OFFSET_SBFRE 1	/* 3 bits - first err row singlebit */
+#define I82443BXGX_ERRSTS_OFFSET_SEF   BIT(0)	/* 1 = SBE occurred */
+
+#define I82443BXGX_DRAMC 0x57	/* 8bit register starting at this PCI
+				 * config space offset. */
+#define I82443BXGX_DRAMC_OFFSET_DT 3	/* 2 bits, DRAM Type */
+#define I82443BXGX_DRAMC_DRAM_IS_EDO 0	/* 00 = EDO */
+#define I82443BXGX_DRAMC_DRAM_IS_SDRAM 1	/* 01 = SDRAM */
+#define I82443BXGX_DRAMC_DRAM_IS_RSDRAM 2	/* 10 = Registered SDRAM */
+
+#define I82443BXGX_DRB 0x60	/* 8x 8bit registers starting at this PCI
+				 * config space offset. */
+
+/* FIXME - don't poll when ECC disabled? */
+
+struct i82443bxgx_edacmc_error_info {
+	u32 eap;
+};
+
+static struct edac_pci_ctl_info *i82443bxgx_pci;
+
+static void i82443bxgx_edacmc_get_error_info(struct mem_ctl_info *mci,
+				struct i82443bxgx_edacmc_error_info
+				*info)
+{
+	struct pci_dev *pdev;
+	pdev = to_pci_dev(mci->dev);
+	pci_read_config_dword(pdev, I82443BXGX_EAP, &info->eap);
+	if (info->eap & I82443BXGX_EAP_OFFSET_SBE)
+		/* Clear error to allow next error to be reported [p.61] */
+		pci_write_bits32(pdev, I82443BXGX_EAP,
+				 I82443BXGX_EAP_OFFSET_SBE,
+				 I82443BXGX_EAP_OFFSET_SBE);
+
+	if (info->eap & I82443BXGX_EAP_OFFSET_MBE)
+		/* Clear error to allow next error to be reported [p.61] */
+		pci_write_bits32(pdev, I82443BXGX_EAP,
+				 I82443BXGX_EAP_OFFSET_MBE,
+				 I82443BXGX_EAP_OFFSET_MBE);
+}
+
+static int i82443bxgx_edacmc_process_error_info(struct mem_ctl_info *mci,
+						struct
+						i82443bxgx_edacmc_error_info
+						*info, int handle_errors)
+{
+	int error_found = 0;
+	u32 eapaddr, page, pageoffset;
+
+	/* bits 30:12 hold the 4kb block in which the error occurred
+	 * [p.61] */
+	eapaddr = (info->eap & 0xfffff000);
+	page = eapaddr >> PAGE_SHIFT;
+	pageoffset = eapaddr - (page << PAGE_SHIFT);
+
+	if (info->eap & I82443BXGX_EAP_OFFSET_SBE) {
+		error_found = 1;
+		if (handle_errors)
+			edac_mc_handle_ce(mci, page, pageoffset,
+				/* 440BX/GX don't make syndrome information
+				 * available */
+				0, edac_mc_find_csrow_by_page(mci, page), 0,
+				mci->ctl_name);
+	}
+
+	if (info->eap & I82443BXGX_EAP_OFFSET_MBE) {
+		error_found = 1;
+		if (handle_errors)
+			edac_mc_handle_ue(mci, page, pageoffset,
+					edac_mc_find_csrow_by_page(mci, page),
+					mci->ctl_name);
+	}
+
+	return error_found;
+}
+
+static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci)
+{
+	struct i82443bxgx_edacmc_error_info info;
+
+	debugf1("MC%d: " __FILE__ ": %s()\n", mci->mc_idx, __func__);
+	i82443bxgx_edacmc_get_error_info(mci, &info);
+	i82443bxgx_edacmc_process_error_info(mci, &info, 1);
+}
+
+static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
+				struct pci_dev *pdev,
+				enum edac_type edac_mode,
+				enum mem_type mtype)
+{
+	struct csrow_info *csrow;
+	int index;
+	u8 drbar, dramc;
+	u32 row_base, row_high_limit, row_high_limit_last;
+
+	pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
+	row_high_limit_last = 0;
+	for (index = 0; index < mci->nr_csrows; index++) {
+		csrow = &mci->csrows[index];
+		pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar);
+		debugf1("MC%d: " __FILE__ ": %s() Row=%d DRB = %#0x\n",
+			mci->mc_idx, __func__, index, drbar);
+		row_high_limit = ((u32) drbar << 23);
+		/* find the DRAM Chip Select Base address and mask */
+		debugf1("MC%d: " __FILE__ ": %s() Row=%d, "
+			"Boundry Address=%#0x, Last = %#0x \n",
+			mci->mc_idx, __func__, index, row_high_limit,
+			row_high_limit_last);
+
+		/* 440GX goes to 2GB, represented with a DRB of 0. */
+		if (row_high_limit_last && !row_high_limit)
+			row_high_limit = 1UL << 31;
+
+		/* This row is empty [p.49] */
+		if (row_high_limit == row_high_limit_last)
+			continue;
+		row_base = row_high_limit_last;
+		csrow->first_page = row_base >> PAGE_SHIFT;
+		csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1;
+		csrow->nr_pages = csrow->last_page - csrow->first_page + 1;
+		/* EAP reports in 4kilobyte granularity [61] */
+		csrow->grain = 1 << 12;
+		csrow->mtype = mtype;
+		/* I don't think 440BX can tell you device type? FIXME? */
+		csrow->dtype = DEV_UNKNOWN;
+		/* Mode is global to all rows on 440BX */
+		csrow->edac_mode = edac_mode;
+		row_high_limit_last = row_high_limit;
+	}
+}
+
+static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
+{
+	struct mem_ctl_info *mci;
+	u8 dramc;
+	u32 nbxcfg, ecc_mode;
+	enum mem_type mtype;
+	enum edac_type edac_mode;
+
+	debugf0("MC: " __FILE__ ": %s()\n", __func__);
+
+	/* Something is really hosed if PCI config space reads from
+	 * the MC aren't working.
+	 */
+	if (pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg))
+		return -EIO;
+
+	mci = edac_mc_alloc(0, I82443BXGX_NR_CSROWS, I82443BXGX_NR_CHANS, 0);
+
+	if (mci == NULL)
+		return -ENOMEM;
+
+	debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+	mci->dev = &pdev->dev;
+	mci->mtype_cap = MEM_FLAG_EDO | MEM_FLAG_SDR | MEM_FLAG_RDR;
+	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
+	pci_read_config_byte(pdev, I82443BXGX_DRAMC, &dramc);
+	switch ((dramc >> I82443BXGX_DRAMC_OFFSET_DT) & (BIT(0) | BIT(1))) {
+	case I82443BXGX_DRAMC_DRAM_IS_EDO:
+		mtype = MEM_EDO;
+		break;
+	case I82443BXGX_DRAMC_DRAM_IS_SDRAM:
+		mtype = MEM_SDR;
+		break;
+	case I82443BXGX_DRAMC_DRAM_IS_RSDRAM:
+		mtype = MEM_RDR;
+		break;
+	default:
+		debugf0("Unknown/reserved DRAM type value "
+			"in DRAMC register!\n");
+		mtype = -MEM_UNKNOWN;
+	}
+
+	if ((mtype == MEM_SDR) || (mtype == MEM_RDR))
+		mci->edac_cap = mci->edac_ctl_cap;
+	else
+		mci->edac_cap = EDAC_FLAG_NONE;
+
+	mci->scrub_cap = SCRUB_FLAG_HW_SRC;
+	pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg);
+	ecc_mode = ((nbxcfg >> I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY) &
+		(BIT(0) | BIT(1)));
+
+	mci->scrub_mode = (ecc_mode == I82443BXGX_NBXCFG_INTEGRITY_SCRUB)
+		? SCRUB_HW_SRC : SCRUB_NONE;
+
+	switch (ecc_mode) {
+	case I82443BXGX_NBXCFG_INTEGRITY_NONE:
+		edac_mode = EDAC_NONE;
+		break;
+	case I82443BXGX_NBXCFG_INTEGRITY_EC:
+		edac_mode = EDAC_EC;
+		break;
+	case I82443BXGX_NBXCFG_INTEGRITY_ECC:
+	case I82443BXGX_NBXCFG_INTEGRITY_SCRUB:
+		edac_mode = EDAC_SECDED;
+		break;
+	default:
+		debugf0("%s(): Unknown/reserved ECC state "
+			"in NBXCFG register!\n", __func__);
+		edac_mode = EDAC_UNKNOWN;
+		break;
+	}
+
+	i82443bxgx_init_csrows(mci, pdev, edac_mode, mtype);
+
+	/* Many BIOSes don't clear error flags on boot, so do this
+	 * here, or we get "phantom" errors occuring at module-load
+	 * time. */
+	pci_write_bits32(pdev, I82443BXGX_EAP,
+			(I82443BXGX_EAP_OFFSET_SBE |
+				I82443BXGX_EAP_OFFSET_MBE),
+			(I82443BXGX_EAP_OFFSET_SBE |
+				I82443BXGX_EAP_OFFSET_MBE));
+
+	mci->mod_name = EDAC_MOD_STR;
+	mci->mod_ver = I82443_REVISION;
+	mci->ctl_name = "I82443BXGX";
+	mci->dev_name = pci_name(pdev);
+	mci->edac_check = i82443bxgx_edacmc_check;
+	mci->ctl_page_to_phys = NULL;
+
+	if (edac_mc_add_mc(mci)) {
+		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+		goto fail;
+	}
+
+	/* allocating generic PCI control info */
+	i82443bxgx_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+	if (!i82443bxgx_pci) {
+		printk(KERN_WARNING
+			"%s(): Unable to create PCI control\n",
+			__func__);
+		printk(KERN_WARNING
+			"%s(): PCI error report via EDAC not setup\n",
+			__func__);
+	}
+
+	debugf3("MC: " __FILE__ ": %s(): success\n", __func__);
+	return 0;
+
+fail:
+	edac_mc_free(mci);
+	return -ENODEV;
+}
+
+EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_probe1);
+
+/* returns count (>= 0), or negative on error */
+static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
+						const struct pci_device_id *ent)
+{
+	debugf0("MC: " __FILE__ ": %s()\n", __func__);
+
+	/* don't need to call pci_device_enable() */
+	return i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
+}
+
+static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
+{
+	struct mem_ctl_info *mci;
+
+	debugf0(__FILE__ ": %s()\n", __func__);
+
+	if (i82443bxgx_pci)
+		edac_pci_release_generic_ctl(i82443bxgx_pci);
+
+	if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
+		return;
+
+	edac_mc_free(mci);
+}
+
+EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_remove_one);
+
+static const struct pci_device_id i82443bxgx_pci_tbl[] __devinitdata = {
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_0)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0)},
+	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2)},
+	{0,}			/* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i82443bxgx_pci_tbl);
+
+static struct pci_driver i82443bxgx_edacmc_driver = {
+	.name = EDAC_MOD_STR,
+	.probe = i82443bxgx_edacmc_init_one,
+	.remove = __devexit_p(i82443bxgx_edacmc_remove_one),
+	.id_table = i82443bxgx_pci_tbl,
+};
+
+static int __init i82443bxgx_edacmc_init(void)
+{
+	return pci_register_driver(&i82443bxgx_edacmc_driver);
+}
+
+static void __exit i82443bxgx_edacmc_exit(void)
+{
+	pci_unregister_driver(&i82443bxgx_edacmc_driver);
+}
+
+module_init(i82443bxgx_edacmc_init);
+module_exit(i82443bxgx_edacmc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD");
+MODULE_DESCRIPTION("EDAC MC support for Intel 82443BX/GX memory controllers");
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c
index e4bb298..f5ecd2c 100644
--- a/drivers/edac/i82860_edac.c
+++ b/drivers/edac/i82860_edac.c
@@ -14,9 +14,9 @@
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/slab.h>
-#include "edac_mc.h"
+#include "edac_core.h"
 
-#define  I82860_REVISION " Ver: 2.0.1 " __DATE__
+#define  I82860_REVISION " Ver: 2.0.2 " __DATE__
 #define EDAC_MOD_STR	"i82860_edac"
 
 #define i82860_printk(level, fmt, arg...) \
@@ -54,16 +54,16 @@
 
 static const struct i82860_dev_info i82860_devs[] = {
 	[I82860] = {
-		.ctl_name = "i82860"
-	},
+		.ctl_name = "i82860"},
 };
 
-static struct pci_dev *mci_pdev = NULL;	/* init dev: in case that AGP code
+static struct pci_dev *mci_pdev;	/* init dev: in case that AGP code
 					 * has already registered driver
 					 */
+static struct edac_pci_ctl_info *i82860_pci;
 
 static void i82860_get_error_info(struct mem_ctl_info *mci,
-		struct i82860_error_info *info)
+				struct i82860_error_info *info)
 {
 	struct pci_dev *pdev;
 
@@ -91,13 +91,13 @@
 
 	if ((info->errsts ^ info->errsts2) & 0x0003) {
 		pci_read_config_dword(pdev, I82860_EAP, &info->eap);
-		pci_read_config_word(pdev, I82860_DERRCTL_STS,
-				&info->derrsyn);
+		pci_read_config_word(pdev, I82860_DERRCTL_STS, &info->derrsyn);
 	}
 }
 
 static int i82860_process_error_info(struct mem_ctl_info *mci,
-		struct i82860_error_info *info, int handle_errors)
+				struct i82860_error_info *info,
+				int handle_errors)
 {
 	int row;
 
@@ -136,7 +136,7 @@
 static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
 {
 	unsigned long last_cumul_size;
-	u16 mchcfg_ddim;  /* DRAM Data Integrity Mode 0=none, 2=edac */
+	u16 mchcfg_ddim;	/* DRAM Data Integrity Mode 0=none, 2=edac */
 	u16 value;
 	u32 cumul_size;
 	struct csrow_info *csrow;
@@ -155,7 +155,7 @@
 		csrow = &mci->csrows[index];
 		pci_read_config_word(pdev, I82860_GBA + index * 2, &value);
 		cumul_size = (value & I82860_GBA_MASK) <<
-		    (I82860_GBA_SHIFT - PAGE_SHIFT);
+			(I82860_GBA_SHIFT - PAGE_SHIFT);
 		debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
 			cumul_size);
 
@@ -186,7 +186,7 @@
 	   the channel and the GRA registers map to physical devices so we are
 	   going to make 1 channel for group.
 	 */
-	mci = edac_mc_alloc(0, 16, 1);
+	mci = edac_mc_alloc(0, 16, 1, 0);
 
 	if (!mci)
 		return -ENOMEM;
@@ -200,19 +200,31 @@
 	mci->mod_name = EDAC_MOD_STR;
 	mci->mod_ver = I82860_REVISION;
 	mci->ctl_name = i82860_devs[dev_idx].ctl_name;
+	mci->dev_name = pci_name(pdev);
 	mci->edac_check = i82860_check;
 	mci->ctl_page_to_phys = NULL;
 	i82860_init_csrows(mci, pdev);
-	i82860_get_error_info(mci, &discard);  /* clear counters */
+	i82860_get_error_info(mci, &discard);	/* clear counters */
 
 	/* Here we assume that we will never see multiple instances of this
 	 * type of memory controller.  The ID is therefore hardcoded to 0.
 	 */
-	if (edac_mc_add_mc(mci,0)) {
+	if (edac_mc_add_mc(mci)) {
 		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
 		goto fail;
 	}
 
+	/* allocating generic PCI control info */
+	i82860_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+	if (!i82860_pci) {
+		printk(KERN_WARNING
+			"%s(): Unable to create PCI control\n",
+			__func__);
+		printk(KERN_WARNING
+			"%s(): PCI error report via EDAC not setup\n",
+			__func__);
+	}
+
 	/* get this far and it's successful */
 	debugf3("%s(): success\n", __func__);
 
@@ -225,7 +237,7 @@
 
 /* returns count (>= 0), or negative on error */
 static int __devinit i82860_init_one(struct pci_dev *pdev,
-		const struct pci_device_id *ent)
+				const struct pci_device_id *ent)
 {
 	int rc;
 
@@ -249,6 +261,9 @@
 
 	debugf0("%s()\n", __func__);
 
+	if (i82860_pci)
+		edac_pci_release_generic_ctl(i82860_pci);
+
 	if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
 		return;
 
@@ -257,12 +272,11 @@
 
 static const struct pci_device_id i82860_pci_tbl[] __devinitdata = {
 	{
-		PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		I82860
-	},
+	 PCI_VEND_DEV(INTEL, 82860_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	 I82860},
 	{
-		0,
-	}	/* 0 terminated list. */
+	 0,
+	 }			/* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, i82860_pci_tbl);
@@ -329,5 +343,5 @@
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) "
-	"Ben Woodard <woodard@redhat.com>");
+		"Ben Woodard <woodard@redhat.com>");
 MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers");
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index 2800b3e..031abad 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
@@ -18,9 +18,9 @@
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/slab.h>
-#include "edac_mc.h"
+#include "edac_core.h"
 
-#define I82875P_REVISION	" Ver: 2.0.1 " __DATE__
+#define I82875P_REVISION	" Ver: 2.0.2 " __DATE__
 #define EDAC_MOD_STR		"i82875p_edac"
 
 #define i82875p_printk(level, fmt, arg...) \
@@ -174,18 +174,19 @@
 
 static const struct i82875p_dev_info i82875p_devs[] = {
 	[I82875P] = {
-		.ctl_name = "i82875p"
-	},
+		.ctl_name = "i82875p"},
 };
 
-static struct pci_dev *mci_pdev = NULL;	/* init dev: in case that AGP code has
+static struct pci_dev *mci_pdev;	/* init dev: in case that AGP code has
 					 * already registered driver
 					 */
 
 static int i82875p_registered = 1;
 
+static struct edac_pci_ctl_info *i82875p_pci;
+
 static void i82875p_get_error_info(struct mem_ctl_info *mci,
-		struct i82875p_error_info *info)
+				struct i82875p_error_info *info)
 {
 	struct pci_dev *pdev;
 
@@ -197,38 +198,39 @@
 	 * overwritten by UE.
 	 */
 	pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts);
+
+	if (!(info->errsts & 0x0081))
+		return;
+
 	pci_read_config_dword(pdev, I82875P_EAP, &info->eap);
 	pci_read_config_byte(pdev, I82875P_DES, &info->des);
 	pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn);
 	pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts2);
 
-	pci_write_bits16(pdev, I82875P_ERRSTS, 0x0081, 0x0081);
-
 	/*
 	 * If the error is the same then we can for both reads then
 	 * the first set of reads is valid.  If there is a change then
 	 * there is a CE no info and the second set of reads is valid
 	 * and should be UE info.
 	 */
-	if (!(info->errsts2 & 0x0081))
-		return;
-
 	if ((info->errsts ^ info->errsts2) & 0x0081) {
 		pci_read_config_dword(pdev, I82875P_EAP, &info->eap);
 		pci_read_config_byte(pdev, I82875P_DES, &info->des);
-		pci_read_config_byte(pdev, I82875P_DERRSYN,
-				&info->derrsyn);
+		pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn);
 	}
+
+	pci_write_bits16(pdev, I82875P_ERRSTS, 0x0081, 0x0081);
 }
 
 static int i82875p_process_error_info(struct mem_ctl_info *mci,
-		struct i82875p_error_info *info, int handle_errors)
+				struct i82875p_error_info *info,
+				int handle_errors)
 {
 	int row, multi_chan;
 
 	multi_chan = mci->csrows[0].nr_channels - 1;
 
-	if (!(info->errsts2 & 0x0081))
+	if (!(info->errsts & 0x0081))
 		return 0;
 
 	if (!handle_errors)
@@ -263,10 +265,12 @@
 
 /* Return 0 on success or 1 on failure. */
 static int i82875p_setup_overfl_dev(struct pci_dev *pdev,
-		struct pci_dev **ovrfl_pdev, void __iomem **ovrfl_window)
+				struct pci_dev **ovrfl_pdev,
+				void __iomem **ovrfl_window)
 {
 	struct pci_dev *dev;
 	void __iomem *window;
+	int err;
 
 	*ovrfl_pdev = NULL;
 	*ovrfl_window = NULL;
@@ -284,14 +288,19 @@
 		if (dev == NULL)
 			return 1;
 
-        	pci_bus_add_device(dev);
+		err = pci_bus_add_device(dev);
+		if (err) {
+			i82875p_printk(KERN_ERR,
+				"%s(): pci_bus_add_device() Failed\n",
+				__func__);
+		}
 	}
 
 	*ovrfl_pdev = dev;
 
 	if (pci_enable_device(dev)) {
 		i82875p_printk(KERN_ERR, "%s(): Failed to enable overflow "
-			       "device\n", __func__);
+			"device\n", __func__);
 		return 1;
 	}
 
@@ -307,7 +316,7 @@
 
 	if (window == NULL) {
 		i82875p_printk(KERN_ERR, "%s(): Failed to ioremap bar6\n",
-			       __func__);
+			__func__);
 		goto fail1;
 	}
 
@@ -325,21 +334,20 @@
 	return 1;
 }
 
-
 /* Return 1 if dual channel mode is active.  Else return 0. */
 static inline int dual_channel_active(u32 drc)
 {
 	return (drc >> 21) & 0x1;
 }
 
-
 static void i82875p_init_csrows(struct mem_ctl_info *mci,
-		struct pci_dev *pdev, void __iomem *ovrfl_window, u32 drc)
+				struct pci_dev *pdev,
+				void __iomem * ovrfl_window, u32 drc)
 {
 	struct csrow_info *csrow;
 	unsigned long last_cumul_size;
 	u8 value;
-	u32 drc_ddim;  /* DRAM Data Integrity Mode 0=none,2=edac */
+	u32 drc_ddim;		/* DRAM Data Integrity Mode 0=none,2=edac */
 	u32 cumul_size;
 	int index;
 
@@ -392,7 +400,7 @@
 	drc = readl(ovrfl_window + I82875P_DRC);
 	nr_chans = dual_channel_active(drc) + 1;
 	mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans),
-				nr_chans);
+			nr_chans, 0);
 
 	if (!mci) {
 		rc = -ENOMEM;
@@ -407,23 +415,35 @@
 	mci->mod_name = EDAC_MOD_STR;
 	mci->mod_ver = I82875P_REVISION;
 	mci->ctl_name = i82875p_devs[dev_idx].ctl_name;
+	mci->dev_name = pci_name(pdev);
 	mci->edac_check = i82875p_check;
 	mci->ctl_page_to_phys = NULL;
 	debugf3("%s(): init pvt\n", __func__);
-	pvt = (struct i82875p_pvt *) mci->pvt_info;
+	pvt = (struct i82875p_pvt *)mci->pvt_info;
 	pvt->ovrfl_pdev = ovrfl_pdev;
 	pvt->ovrfl_window = ovrfl_window;
 	i82875p_init_csrows(mci, pdev, ovrfl_window, drc);
-	i82875p_get_error_info(mci, &discard);  /* clear counters */
+	i82875p_get_error_info(mci, &discard);	/* clear counters */
 
 	/* Here we assume that we will never see multiple instances of this
 	 * type of memory controller.  The ID is therefore hardcoded to 0.
 	 */
-	if (edac_mc_add_mc(mci,0)) {
+	if (edac_mc_add_mc(mci)) {
 		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
 		goto fail1;
 	}
 
+	/* allocating generic PCI control info */
+	i82875p_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+	if (!i82875p_pci) {
+		printk(KERN_WARNING
+			"%s(): Unable to create PCI control\n",
+			__func__);
+		printk(KERN_WARNING
+			"%s(): PCI error report via EDAC not setup\n",
+			__func__);
+	}
+
 	/* get this far and it's successful */
 	debugf3("%s(): success\n", __func__);
 	return 0;
@@ -442,7 +462,7 @@
 
 /* returns count (>= 0), or negative on error */
 static int __devinit i82875p_init_one(struct pci_dev *pdev,
-		const struct pci_device_id *ent)
+				const struct pci_device_id *ent)
 {
 	int rc;
 
@@ -467,10 +487,13 @@
 
 	debugf0("%s()\n", __func__);
 
+	if (i82875p_pci)
+		edac_pci_release_generic_ctl(i82875p_pci);
+
 	if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
 		return;
 
-	pvt = (struct i82875p_pvt *) mci->pvt_info;
+	pvt = (struct i82875p_pvt *)mci->pvt_info;
 
 	if (pvt->ovrfl_window)
 		iounmap(pvt->ovrfl_window);
@@ -488,12 +511,11 @@
 
 static const struct pci_device_id i82875p_pci_tbl[] __devinitdata = {
 	{
-		PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		I82875P
-	},
+	 PCI_VEND_DEV(INTEL, 82875_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	 I82875P},
 	{
-		0,
-	}	/* 0 terminated list. */
+	 0,
+	 }			/* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, i82875p_pci_tbl);
@@ -517,7 +539,7 @@
 
 	if (mci_pdev == NULL) {
 		mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
-				PCI_DEVICE_ID_INTEL_82875_0, NULL);
+					PCI_DEVICE_ID_INTEL_82875_0, NULL);
 
 		if (!mci_pdev) {
 			debugf0("875p pci_get_device fail\n");
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
new file mode 100644
index 0000000..0ee8884
--- /dev/null
+++ b/drivers/edac/i82975x_edac.c
@@ -0,0 +1,666 @@
+/*
+ * Intel 82975X Memory Controller kernel module
+ * (C) 2007 aCarLab (India) Pvt. Ltd. (http://acarlab.com)
+ * (C) 2007 jetzbroadband (http://jetzbroadband.com)
+ * This file may be distributed under the terms of the
+ * GNU General Public License.
+ *
+ * Written by Arvind R.
+ *   Copied from i82875p_edac.c source:
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+
+#include "edac_core.h"
+
+#define I82975X_REVISION	" Ver: 1.0.0 " __DATE__
+#define EDAC_MOD_STR		"i82975x_edac"
+
+#define i82975x_printk(level, fmt, arg...) \
+	edac_printk(level, "i82975x", fmt, ##arg)
+
+#define i82975x_mc_printk(mci, level, fmt, arg...) \
+	edac_mc_chipset_printk(mci, level, "i82975x", fmt, ##arg)
+
+#ifndef PCI_DEVICE_ID_INTEL_82975_0
+#define PCI_DEVICE_ID_INTEL_82975_0	0x277c
+#endif				/* PCI_DEVICE_ID_INTEL_82975_0 */
+
+#define I82975X_NR_CSROWS(nr_chans)		(8/(nr_chans))
+
+/* Intel 82975X register addresses - device 0 function 0 - DRAM Controller */
+#define I82975X_EAP		0x58	/* Dram Error Address Pointer (32b)
+					 *
+					 * 31:7  128 byte cache-line address
+					 * 6:1   reserved
+					 * 0     0: CH0; 1: CH1
+					 */
+
+#define I82975X_DERRSYN		0x5c	/* Dram Error SYNdrome (8b)
+					 *
+					 *  7:0  DRAM ECC Syndrome
+					 */
+
+#define I82975X_DES		0x5d	/* Dram ERRor DeSTination (8b)
+					 * 0h:    Processor Memory Reads
+					 * 1h:7h  reserved
+					 * More - See Page 65 of Intel DocSheet.
+					 */
+
+#define I82975X_ERRSTS		0xc8	/* Error Status Register (16b)
+					 *
+					 * 15:12 reserved
+					 * 11    Thermal Sensor Event
+					 * 10    reserved
+					 *  9    non-DRAM lock error (ndlock)
+					 *  8    Refresh Timeout
+					 *  7:2  reserved
+					 *  1    ECC UE (multibit DRAM error)
+					 *  0    ECC CE (singlebit DRAM error)
+					 */
+
+/* Error Reporting is supported by 3 mechanisms:
+  1. DMI SERR generation  ( ERRCMD )
+  2. SMI DMI  generation  ( SMICMD )
+  3. SCI DMI  generation  ( SCICMD )
+NOTE: Only ONE of the three must be enabled
+*/
+#define I82975X_ERRCMD		0xca	/* Error Command (16b)
+					 *
+					 * 15:12 reserved
+					 * 11    Thermal Sensor Event
+					 * 10    reserved
+					 *  9    non-DRAM lock error (ndlock)
+					 *  8    Refresh Timeout
+					 *  7:2  reserved
+					 *  1    ECC UE (multibit DRAM error)
+					 *  0    ECC CE (singlebit DRAM error)
+					 */
+
+#define I82975X_SMICMD		0xcc	/* Error Command (16b)
+					 *
+					 * 15:2  reserved
+					 *  1    ECC UE (multibit DRAM error)
+					 *  0    ECC CE (singlebit DRAM error)
+					 */
+
+#define I82975X_SCICMD		0xce	/* Error Command (16b)
+					 *
+					 * 15:2  reserved
+					 *  1    ECC UE (multibit DRAM error)
+					 *  0    ECC CE (singlebit DRAM error)
+					 */
+
+#define I82975X_XEAP	0xfc	/* Extended Dram Error Address Pointer (8b)
+					 *
+					 * 7:1   reserved
+					 * 0     Bit32 of the Dram Error Address
+					 */
+
+#define I82975X_MCHBAR		0x44	/*
+					 *
+					 * 31:14 Base Addr of 16K memory-mapped
+					 *	configuration space
+					 * 13:1  reserverd
+					 *  0    mem-mapped config space enable
+					 */
+
+/* NOTE: Following addresses have to indexed using MCHBAR offset (44h, 32b) */
+/* Intel 82975x memory mapped register space */
+
+#define I82975X_DRB_SHIFT 25	/* fixed 32MiB grain */
+
+#define I82975X_DRB		0x100	/* DRAM Row Boundary (8b x 8)
+					 *
+					 * 7   set to 1 in highest DRB of
+					 *	channel if 4GB in ch.
+					 * 6:2 upper boundary of rank in
+					 *	32MB grains
+					 * 1:0 set to 0
+					 */
+#define I82975X_DRB_CH0R0		0x100
+#define I82975X_DRB_CH0R1		0x101
+#define I82975X_DRB_CH0R2		0x102
+#define I82975X_DRB_CH0R3		0x103
+#define I82975X_DRB_CH1R0		0x180
+#define I82975X_DRB_CH1R1		0x181
+#define I82975X_DRB_CH1R2		0x182
+#define I82975X_DRB_CH1R3		0x183
+
+
+#define I82975X_DRA		0x108	/* DRAM Row Attribute (4b x 8)
+					 *  defines the PAGE SIZE to be used
+					 *	for the rank
+					 *  7    reserved
+					 *  6:4  row attr of odd rank, i.e. 1
+					 *  3    reserved
+					 *  2:0  row attr of even rank, i.e. 0
+					 *
+					 * 000 = unpopulated
+					 * 001 = reserved
+					 * 010 = 4KiB
+					 * 011 = 8KiB
+					 * 100 = 16KiB
+					 * others = reserved
+					 */
+#define I82975X_DRA_CH0R01		0x108
+#define I82975X_DRA_CH0R23		0x109
+#define I82975X_DRA_CH1R01		0x188
+#define I82975X_DRA_CH1R23		0x189
+
+
+#define I82975X_BNKARC	0x10e /* Type of device in each rank - Bank Arch (16b)
+					 *
+					 * 15:8  reserved
+					 * 7:6  Rank 3 architecture
+					 * 5:4  Rank 2 architecture
+					 * 3:2  Rank 1 architecture
+					 * 1:0  Rank 0 architecture
+					 *
+					 * 00 => x16 devices; i.e 4 banks
+					 * 01 => x8  devices; i.e 8 banks
+					 */
+#define I82975X_C0BNKARC	0x10e
+#define I82975X_C1BNKARC	0x18e
+
+
+
+#define I82975X_DRC		0x120 /* DRAM Controller Mode0 (32b)
+					 *
+					 * 31:30 reserved
+					 * 29    init complete
+					 * 28:11 reserved, according to Intel
+					 *    22:21 number of channels
+					 *		00=1 01=2 in 82875
+					 *		seems to be ECC mode
+					 *		bits in 82975 in Asus
+					 *		P5W
+					 *	 19:18 Data Integ Mode
+					 *		00=none 01=ECC in 82875
+					 * 10:8  refresh mode
+					 *  7    reserved
+					 *  6:4  mode select
+					 *  3:2  reserved
+					 *  1:0  DRAM type 10=Second Revision
+					 *		DDR2 SDRAM
+					 *         00, 01, 11 reserved
+					 */
+#define I82975X_DRC_CH0M0		0x120
+#define I82975X_DRC_CH1M0		0x1A0
+
+
+#define I82975X_DRC_M1	0x124 /* DRAM Controller Mode1 (32b)
+					 * 31	0=Standard Address Map
+					 *	1=Enhanced Address Map
+					 * 30:0	reserved
+					 */
+
+#define I82975X_DRC_CH0M1		0x124
+#define I82975X_DRC_CH1M1		0x1A4
+
+enum i82975x_chips {
+	I82975X = 0,
+};
+
+struct i82975x_pvt {
+	void __iomem *mch_window;
+};
+
+struct i82975x_dev_info {
+	const char *ctl_name;
+};
+
+struct i82975x_error_info {
+	u16 errsts;
+	u32 eap;
+	u8 des;
+	u8 derrsyn;
+	u16 errsts2;
+	u8 chan;		/* the channel is bit 0 of EAP */
+	u8 xeap;		/* extended eap bit */
+};
+
+static const struct i82975x_dev_info i82975x_devs[] = {
+	[I82975X] = {
+		.ctl_name = "i82975x"
+	},
+};
+
+static struct pci_dev *mci_pdev;	/* init dev: in case that AGP code has
+					 * already registered driver
+					 */
+
+static int i82975x_registered = 1;
+
+static void i82975x_get_error_info(struct mem_ctl_info *mci,
+		struct i82975x_error_info *info)
+{
+	struct pci_dev *pdev;
+
+	pdev = to_pci_dev(mci->dev);
+
+	/*
+	 * This is a mess because there is no atomic way to read all the
+	 * registers at once and the registers can transition from CE being
+	 * overwritten by UE.
+	 */
+	pci_read_config_word(pdev, I82975X_ERRSTS, &info->errsts);
+	pci_read_config_dword(pdev, I82975X_EAP, &info->eap);
+	pci_read_config_byte(pdev, I82975X_XEAP, &info->xeap);
+	pci_read_config_byte(pdev, I82975X_DES, &info->des);
+	pci_read_config_byte(pdev, I82975X_DERRSYN, &info->derrsyn);
+	pci_read_config_word(pdev, I82975X_ERRSTS, &info->errsts2);
+
+	pci_write_bits16(pdev, I82975X_ERRSTS, 0x0003, 0x0003);
+
+	/*
+	 * If the error is the same then we can for both reads then
+	 * the first set of reads is valid.  If there is a change then
+	 * there is a CE no info and the second set of reads is valid
+	 * and should be UE info.
+	 */
+	if (!(info->errsts2 & 0x0003))
+		return;
+
+	if ((info->errsts ^ info->errsts2) & 0x0003) {
+		pci_read_config_dword(pdev, I82975X_EAP, &info->eap);
+		pci_read_config_byte(pdev, I82975X_XEAP, &info->xeap);
+		pci_read_config_byte(pdev, I82975X_DES, &info->des);
+		pci_read_config_byte(pdev, I82975X_DERRSYN,
+				&info->derrsyn);
+	}
+}
+
+static int i82975x_process_error_info(struct mem_ctl_info *mci,
+		struct i82975x_error_info *info, int handle_errors)
+{
+	int row, multi_chan, chan;
+
+	multi_chan = mci->csrows[0].nr_channels - 1;
+
+	if (!(info->errsts2 & 0x0003))
+		return 0;
+
+	if (!handle_errors)
+		return 1;
+
+	if ((info->errsts ^ info->errsts2) & 0x0003) {
+		edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
+		info->errsts = info->errsts2;
+	}
+
+	chan = info->eap & 1;
+	info->eap >>= 1;
+	if (info->xeap )
+		info->eap |= 0x80000000;
+	info->eap >>= PAGE_SHIFT;
+	row = edac_mc_find_csrow_by_page(mci, info->eap);
+
+	if (info->errsts & 0x0002)
+		edac_mc_handle_ue(mci, info->eap, 0, row, "i82975x UE");
+	else
+		edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row,
+				multi_chan ? chan : 0,
+				"i82975x CE");
+
+	return 1;
+}
+
+static void i82975x_check(struct mem_ctl_info *mci)
+{
+	struct i82975x_error_info info;
+
+	debugf1("MC%d: %s()\n", mci->mc_idx, __func__);
+	i82975x_get_error_info(mci, &info);
+	i82975x_process_error_info(mci, &info, 1);
+}
+
+/* Return 1 if dual channel mode is active.  Else return 0. */
+static int dual_channel_active(void __iomem *mch_window)
+{
+	/*
+	 * We treat interleaved-symmetric configuration as dual-channel - EAP's
+	 * bit-0 giving the channel of the error location.
+	 *
+	 * All other configurations are treated as single channel - the EAP's
+	 * bit-0 will resolve ok in symmetric area of mixed
+	 * (symmetric/asymmetric) configurations
+	 */
+	u8	drb[4][2];
+	int	row;
+	int    dualch;
+
+	for (dualch = 1, row = 0; dualch && (row < 4); row++) {
+		drb[row][0] = readb(mch_window + I82975X_DRB + row);
+		drb[row][1] = readb(mch_window + I82975X_DRB + row + 0x80);
+		dualch = dualch && (drb[row][0] == drb[row][1]);
+	}
+	return dualch;
+}
+
+static enum dev_type i82975x_dram_type(void __iomem *mch_window, int rank)
+{
+	/*
+	 * ASUS P5W DH either does not program this register or programs
+	 * it wrong!
+	 * ECC is possible on i92975x ONLY with DEV_X8 which should mean 'val'
+	 * for each rank should be 01b - the LSB of the word should be 0x55;
+	 * but it reads 0!
+	 */
+	return DEV_X8;
+}
+
+static void i82975x_init_csrows(struct mem_ctl_info *mci,
+		struct pci_dev *pdev, void __iomem *mch_window)
+{
+	struct csrow_info *csrow;
+	unsigned long last_cumul_size;
+	u8 value;
+	u32 cumul_size;
+	int index;
+
+	last_cumul_size = 0;
+
+	/*
+	 * 82875 comment:
+	 * The dram row boundary (DRB) reg values are boundary address
+	 * for each DRAM row with a granularity of 32 or 64MB (single/dual
+	 * channel operation).  DRB regs are cumulative; therefore DRB7 will
+	 * contain the total memory contained in all eight rows.
+	 *
+	 * FIXME:
+	 *  EDAC currently works for Dual-channel Interleaved configuration.
+	 *  Other configurations, which the chip supports, need fixing/testing.
+	 *
+	 */
+
+	for (index = 0; index < mci->nr_csrows; index++) {
+		csrow = &mci->csrows[index];
+
+		value = readb(mch_window + I82975X_DRB + index +
+					((index >= 4) ? 0x80 : 0));
+		cumul_size = value;
+		cumul_size <<= (I82975X_DRB_SHIFT - PAGE_SHIFT);
+		debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
+			cumul_size);
+		if (cumul_size == last_cumul_size)
+			continue;	/* not populated */
+
+		csrow->first_page = last_cumul_size;
+		csrow->last_page = cumul_size - 1;
+		csrow->nr_pages = cumul_size - last_cumul_size;
+		last_cumul_size = cumul_size;
+		csrow->grain = 1 << 7;	/* I82975X_EAP has 128B resolution */
+		csrow->mtype = MEM_DDR; /* i82975x supports only DDR2 */
+		csrow->dtype = i82975x_dram_type(mch_window, index);
+		csrow->edac_mode = EDAC_SECDED; /* only supported */
+	}
+}
+
+/* #define  i82975x_DEBUG_IOMEM */
+
+#ifdef i82975x_DEBUG_IOMEM
+static void i82975x_print_dram_timings(void __iomem *mch_window)
+{
+	/*
+	 * The register meanings are from Intel specs;
+	 * (shows 13-5-5-5 for 800-DDR2)
+	 * Asus P5W Bios reports 15-5-4-4
+	 * What's your religion?
+	 */
+	static const int caslats[4] = { 5, 4, 3, 6 };
+	u32	dtreg[2];
+
+	dtreg[0] = readl(mch_window + 0x114);
+	dtreg[1] = readl(mch_window + 0x194);
+	i82975x_printk(KERN_INFO, "DRAM Timings :     Ch0    Ch1\n"
+		"                RAS Active Min = %d     %d\n"
+		"                CAS latency    =  %d      %d\n"
+		"                RAS to CAS     =  %d      %d\n"
+		"                RAS precharge  =  %d      %d\n",
+		(dtreg[0] >> 19 ) & 0x0f,
+			(dtreg[1] >> 19) & 0x0f,
+		caslats[(dtreg[0] >> 8) & 0x03],
+			caslats[(dtreg[1] >> 8) & 0x03],
+		((dtreg[0] >> 4) & 0x07) + 2,
+			((dtreg[1] >> 4) & 0x07) + 2,
+		(dtreg[0] & 0x07) + 2,
+			(dtreg[1] & 0x07) + 2
+	);
+
+}
+#endif
+
+static int i82975x_probe1(struct pci_dev *pdev, int dev_idx)
+{
+	int rc = -ENODEV;
+	struct mem_ctl_info *mci;
+	struct i82975x_pvt *pvt;
+	void __iomem *mch_window;
+	u32 mchbar;
+	u32 drc[2];
+	struct i82975x_error_info discard;
+	int	chans;
+#ifdef i82975x_DEBUG_IOMEM
+	u8 c0drb[4];
+	u8 c1drb[4];
+#endif
+
+	debugf0("%s()\n", __func__);
+
+	pci_read_config_dword(pdev, I82975X_MCHBAR, &mchbar);
+	if (!(mchbar & 1)) {
+		debugf3("%s(): failed, MCHBAR disabled!\n", __func__);
+		goto fail0;
+	}
+	mchbar &= 0xffffc000;	/* bits 31:14 used for 16K window */
+	mch_window = ioremap_nocache(mchbar, 0x1000);
+
+#ifdef i82975x_DEBUG_IOMEM
+	i82975x_printk(KERN_INFO, "MCHBAR real = %0x, remapped = %p\n",
+					mchbar, mch_window);
+
+	c0drb[0] = readb(mch_window + I82975X_DRB_CH0R0);
+	c0drb[1] = readb(mch_window + I82975X_DRB_CH0R1);
+	c0drb[2] = readb(mch_window + I82975X_DRB_CH0R2);
+	c0drb[3] = readb(mch_window + I82975X_DRB_CH0R3);
+	c1drb[0] = readb(mch_window + I82975X_DRB_CH1R0);
+	c1drb[1] = readb(mch_window + I82975X_DRB_CH1R1);
+	c1drb[2] = readb(mch_window + I82975X_DRB_CH1R2);
+	c1drb[3] = readb(mch_window + I82975X_DRB_CH1R3);
+	i82975x_printk(KERN_INFO, "DRBCH0R0 = 0x%02x\n", c0drb[0]);
+	i82975x_printk(KERN_INFO, "DRBCH0R1 = 0x%02x\n", c0drb[1]);
+	i82975x_printk(KERN_INFO, "DRBCH0R2 = 0x%02x\n", c0drb[2]);
+	i82975x_printk(KERN_INFO, "DRBCH0R3 = 0x%02x\n", c0drb[3]);
+	i82975x_printk(KERN_INFO, "DRBCH1R0 = 0x%02x\n", c1drb[0]);
+	i82975x_printk(KERN_INFO, "DRBCH1R1 = 0x%02x\n", c1drb[1]);
+	i82975x_printk(KERN_INFO, "DRBCH1R2 = 0x%02x\n", c1drb[2]);
+	i82975x_printk(KERN_INFO, "DRBCH1R3 = 0x%02x\n", c1drb[3]);
+#endif
+
+	drc[0] = readl(mch_window + I82975X_DRC_CH0M0);
+	drc[1] = readl(mch_window + I82975X_DRC_CH1M0);
+#ifdef i82975x_DEBUG_IOMEM
+	i82975x_printk(KERN_INFO, "DRC_CH0 = %0x, %s\n", drc[0],
+			((drc[0] >> 21) & 3) == 1 ?
+				"ECC enabled" : "ECC disabled");
+	i82975x_printk(KERN_INFO, "DRC_CH1 = %0x, %s\n", drc[1],
+			((drc[1] >> 21) & 3) == 1 ?
+				"ECC enabled" : "ECC disabled");
+
+	i82975x_printk(KERN_INFO, "C0 BNKARC = %0x\n",
+		readw(mch_window + I82975X_C0BNKARC));
+	i82975x_printk(KERN_INFO, "C1 BNKARC = %0x\n",
+		readw(mch_window + I82975X_C1BNKARC));
+	i82975x_print_dram_timings(mch_window);
+	goto fail1;
+#endif
+	if (!(((drc[0] >> 21) & 3) == 1 || ((drc[1] >> 21) & 3) == 1)) {
+		i82975x_printk(KERN_INFO, "ECC disabled on both channels.\n");
+		goto fail1;
+	}
+
+	chans = dual_channel_active(mch_window) + 1;
+
+	/* assuming only one controller, index thus is 0 */
+	mci = edac_mc_alloc(sizeof(*pvt), I82975X_NR_CSROWS(chans),
+					chans, 0);
+	if (!mci) {
+		rc = -ENOMEM;
+		goto fail1;
+	}
+
+	debugf3("%s(): init mci\n", __func__);
+	mci->dev = &pdev->dev;
+	mci->mtype_cap = MEM_FLAG_DDR;
+	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+	mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+	mci->mod_name = EDAC_MOD_STR;
+	mci->mod_ver = I82975X_REVISION;
+	mci->ctl_name = i82975x_devs[dev_idx].ctl_name;
+	mci->edac_check = i82975x_check;
+	mci->ctl_page_to_phys = NULL;
+	debugf3("%s(): init pvt\n", __func__);
+	pvt = (struct i82975x_pvt *) mci->pvt_info;
+	pvt->mch_window = mch_window;
+	i82975x_init_csrows(mci, pdev, mch_window);
+	i82975x_get_error_info(mci, &discard);  /* clear counters */
+
+	/* finalize this instance of memory controller with edac core */
+	if (edac_mc_add_mc(mci)) {
+		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+		goto fail2;
+	}
+
+	/* get this far and it's successful */
+	debugf3("%s(): success\n", __func__);
+	return 0;
+
+fail2:
+	edac_mc_free(mci);
+
+fail1:
+	iounmap(mch_window);
+fail0:
+	return rc;
+}
+
+/* returns count (>= 0), or negative on error */
+static int __devinit i82975x_init_one(struct pci_dev *pdev,
+		const struct pci_device_id *ent)
+{
+	int rc;
+
+	debugf0("%s()\n", __func__);
+
+	if (pci_enable_device(pdev) < 0)
+		return -EIO;
+
+	rc = i82975x_probe1(pdev, ent->driver_data);
+
+	if (mci_pdev == NULL)
+		mci_pdev = pci_dev_get(pdev);
+
+	return rc;
+}
+
+static void __devexit i82975x_remove_one(struct pci_dev *pdev)
+{
+	struct mem_ctl_info *mci;
+	struct i82975x_pvt *pvt;
+
+	debugf0("%s()\n", __func__);
+
+	mci = edac_mc_del_mc(&pdev->dev);
+	if (mci  == NULL)
+		return;
+
+	pvt = mci->pvt_info;
+	if (pvt->mch_window)
+		iounmap( pvt->mch_window );
+
+	edac_mc_free(mci);
+}
+
+static const struct pci_device_id i82975x_pci_tbl[] __devinitdata = {
+	{
+		PCI_VEND_DEV(INTEL, 82975_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		I82975X
+	},
+	{
+		0,
+	}	/* 0 terminated list. */
+};
+
+MODULE_DEVICE_TABLE(pci, i82975x_pci_tbl);
+
+static struct pci_driver i82975x_driver = {
+	.name = EDAC_MOD_STR,
+	.probe = i82975x_init_one,
+	.remove = __devexit_p(i82975x_remove_one),
+	.id_table = i82975x_pci_tbl,
+};
+
+static int __init i82975x_init(void)
+{
+	int pci_rc;
+
+	debugf3("%s()\n", __func__);
+
+	pci_rc = pci_register_driver(&i82975x_driver);
+	if (pci_rc < 0)
+		goto fail0;
+
+	if (mci_pdev == NULL) {
+		mci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+				PCI_DEVICE_ID_INTEL_82975_0, NULL);
+
+		if (!mci_pdev) {
+			debugf0("i82975x pci_get_device fail\n");
+			pci_rc = -ENODEV;
+			goto fail1;
+		}
+
+		pci_rc = i82975x_init_one(mci_pdev, i82975x_pci_tbl);
+
+		if (pci_rc < 0) {
+			debugf0("i82975x init fail\n");
+			pci_rc = -ENODEV;
+			goto fail1;
+		}
+	}
+
+	return 0;
+
+fail1:
+	pci_unregister_driver(&i82975x_driver);
+
+fail0:
+	if (mci_pdev != NULL)
+		pci_dev_put(mci_pdev);
+
+	return pci_rc;
+}
+
+static void __exit i82975x_exit(void)
+{
+	debugf3("%s()\n", __func__);
+
+	pci_unregister_driver(&i82975x_driver);
+
+	if (!i82975x_registered) {
+		i82975x_remove_one(mci_pdev);
+		pci_dev_put(mci_pdev);
+	}
+}
+
+module_init(i82975x_init);
+module_exit(i82975x_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Arvind R. <arvind@acarlab.com>");
+MODULE_DESCRIPTION("MC support for Intel 82975 memory hub controllers");
diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c
new file mode 100644
index 0000000..e66cdd4
--- /dev/null
+++ b/drivers/edac/pasemi_edac.c
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Author: Egor Martovetsky <egor@pasemi.com>
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Driver for the PWRficient onchip memory controllers
+ *
+ * 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.
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include "edac_core.h"
+
+#define MODULE_NAME "pasemi_edac"
+
+#define MCCFG_MCEN				0x300
+#define   MCCFG_MCEN_MMC_EN			0x00000001
+#define MCCFG_ERRCOR				0x388
+#define   MCCFG_ERRCOR_RNK_FAIL_DET_EN		0x00000100
+#define   MCCFG_ERRCOR_ECC_GEN_EN		0x00000010
+#define   MCCFG_ERRCOR_ECC_CRR_EN		0x00000001
+#define MCCFG_SCRUB				0x384
+#define   MCCFG_SCRUB_RGLR_SCRB_EN		0x00000001
+#define MCDEBUG_ERRCTL1				0x728
+#define   MCDEBUG_ERRCTL1_RFL_LOG_EN		0x00080000
+#define   MCDEBUG_ERRCTL1_MBE_LOG_EN		0x00040000
+#define   MCDEBUG_ERRCTL1_SBE_LOG_EN		0x00020000
+#define MCDEBUG_ERRSTA				0x730
+#define   MCDEBUG_ERRSTA_RFL_STATUS		0x00000004
+#define   MCDEBUG_ERRSTA_MBE_STATUS		0x00000002
+#define   MCDEBUG_ERRSTA_SBE_STATUS		0x00000001
+#define MCDEBUG_ERRCNT1				0x734
+#define   MCDEBUG_ERRCNT1_SBE_CNT_OVRFLO	0x00000080
+#define MCDEBUG_ERRLOG1A			0x738
+#define   MCDEBUG_ERRLOG1A_MERR_TYPE_M		0x30000000
+#define   MCDEBUG_ERRLOG1A_MERR_TYPE_NONE	0x00000000
+#define   MCDEBUG_ERRLOG1A_MERR_TYPE_SBE	0x10000000
+#define   MCDEBUG_ERRLOG1A_MERR_TYPE_MBE	0x20000000
+#define   MCDEBUG_ERRLOG1A_MERR_TYPE_RFL	0x30000000
+#define   MCDEBUG_ERRLOG1A_MERR_BA_M		0x00700000
+#define   MCDEBUG_ERRLOG1A_MERR_BA_S		20
+#define   MCDEBUG_ERRLOG1A_MERR_CS_M		0x00070000
+#define   MCDEBUG_ERRLOG1A_MERR_CS_S		16
+#define   MCDEBUG_ERRLOG1A_SYNDROME_M		0x0000ffff
+#define MCDRAM_RANKCFG				0x114
+#define   MCDRAM_RANKCFG_EN			0x00000001
+#define   MCDRAM_RANKCFG_TYPE_SIZE_M		0x000001c0
+#define   MCDRAM_RANKCFG_TYPE_SIZE_S		6
+
+#define PASEMI_EDAC_NR_CSROWS			8
+#define PASEMI_EDAC_NR_CHANS			1
+#define PASEMI_EDAC_ERROR_GRAIN			64
+
+static int last_page_in_mmc;
+static int system_mmc_id;
+
+
+static u32 pasemi_edac_get_error_info(struct mem_ctl_info *mci)
+{
+	struct pci_dev *pdev = to_pci_dev(mci->dev);
+	u32 tmp;
+
+	pci_read_config_dword(pdev, MCDEBUG_ERRSTA,
+			      &tmp);
+
+	tmp &= (MCDEBUG_ERRSTA_RFL_STATUS | MCDEBUG_ERRSTA_MBE_STATUS
+		| MCDEBUG_ERRSTA_SBE_STATUS);
+
+	if (tmp) {
+		if (tmp & MCDEBUG_ERRSTA_SBE_STATUS)
+			pci_write_config_dword(pdev, MCDEBUG_ERRCNT1,
+					       MCDEBUG_ERRCNT1_SBE_CNT_OVRFLO);
+		pci_write_config_dword(pdev, MCDEBUG_ERRSTA, tmp);
+	}
+
+	return tmp;
+}
+
+static void pasemi_edac_process_error_info(struct mem_ctl_info *mci, u32 errsta)
+{
+	struct pci_dev *pdev = to_pci_dev(mci->dev);
+	u32 errlog1a;
+	u32 cs;
+
+	if (!errsta)
+		return;
+
+	pci_read_config_dword(pdev, MCDEBUG_ERRLOG1A, &errlog1a);
+
+	cs = (errlog1a & MCDEBUG_ERRLOG1A_MERR_CS_M) >>
+		MCDEBUG_ERRLOG1A_MERR_CS_S;
+
+	/* uncorrectable/multi-bit errors */
+	if (errsta & (MCDEBUG_ERRSTA_MBE_STATUS |
+		      MCDEBUG_ERRSTA_RFL_STATUS)) {
+		edac_mc_handle_ue(mci, mci->csrows[cs].first_page, 0,
+				  cs, mci->ctl_name);
+	}
+
+	/* correctable/single-bit errors */
+	if (errsta & MCDEBUG_ERRSTA_SBE_STATUS) {
+		edac_mc_handle_ce(mci, mci->csrows[cs].first_page, 0,
+				  0, cs, 0, mci->ctl_name);
+	}
+}
+
+static void pasemi_edac_check(struct mem_ctl_info *mci)
+{
+	u32 errsta;
+
+	errsta = pasemi_edac_get_error_info(mci);
+	if (errsta)
+		pasemi_edac_process_error_info(mci, errsta);
+}
+
+static int pasemi_edac_init_csrows(struct mem_ctl_info *mci,
+				   struct pci_dev *pdev,
+				   enum edac_type edac_mode)
+{
+	struct csrow_info *csrow;
+	u32 rankcfg;
+	int index;
+
+	for (index = 0; index < mci->nr_csrows; index++) {
+		csrow = &mci->csrows[index];
+
+		pci_read_config_dword(pdev,
+				      MCDRAM_RANKCFG + (index * 12),
+				      &rankcfg);
+
+		if (!(rankcfg & MCDRAM_RANKCFG_EN))
+			continue;
+
+		switch ((rankcfg & MCDRAM_RANKCFG_TYPE_SIZE_M) >>
+			MCDRAM_RANKCFG_TYPE_SIZE_S) {
+		case 0:
+			csrow->nr_pages = 128 << (20 - PAGE_SHIFT);
+			break;
+		case 1:
+			csrow->nr_pages = 256 << (20 - PAGE_SHIFT);
+			break;
+		case 2:
+		case 3:
+			csrow->nr_pages = 512 << (20 - PAGE_SHIFT);
+			break;
+		case 4:
+			csrow->nr_pages = 1024 << (20 - PAGE_SHIFT);
+			break;
+		case 5:
+			csrow->nr_pages = 2048 << (20 - PAGE_SHIFT);
+			break;
+		default:
+			edac_mc_printk(mci, KERN_ERR,
+				"Unrecognized Rank Config. rankcfg=%u\n",
+				rankcfg);
+			return -EINVAL;
+		}
+
+		csrow->first_page = last_page_in_mmc;
+		csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
+		last_page_in_mmc += csrow->nr_pages;
+		csrow->page_mask = 0;
+		csrow->grain = PASEMI_EDAC_ERROR_GRAIN;
+		csrow->mtype = MEM_DDR;
+		csrow->dtype = DEV_UNKNOWN;
+		csrow->edac_mode = edac_mode;
+	}
+	return 0;
+}
+
+static int __devinit pasemi_edac_probe(struct pci_dev *pdev,
+		const struct pci_device_id *ent)
+{
+	struct mem_ctl_info *mci = NULL;
+	u32 errctl1, errcor, scrub, mcen;
+
+	pci_read_config_dword(pdev, MCCFG_MCEN, &mcen);
+	if (!(mcen & MCCFG_MCEN_MMC_EN))
+		return -ENODEV;
+
+	/*
+	 * We should think about enabling other error detection later on
+	 */
+
+	pci_read_config_dword(pdev, MCDEBUG_ERRCTL1, &errctl1);
+	errctl1 |= MCDEBUG_ERRCTL1_SBE_LOG_EN |
+		MCDEBUG_ERRCTL1_MBE_LOG_EN |
+		MCDEBUG_ERRCTL1_RFL_LOG_EN;
+	pci_write_config_dword(pdev, MCDEBUG_ERRCTL1, errctl1);
+
+	mci = edac_mc_alloc(0, PASEMI_EDAC_NR_CSROWS, PASEMI_EDAC_NR_CHANS,
+				system_mmc_id++);
+
+	if (mci == NULL)
+		return -ENOMEM;
+
+	pci_read_config_dword(pdev, MCCFG_ERRCOR, &errcor);
+	errcor |= MCCFG_ERRCOR_RNK_FAIL_DET_EN |
+		MCCFG_ERRCOR_ECC_GEN_EN |
+		MCCFG_ERRCOR_ECC_CRR_EN;
+
+	mci->dev = &pdev->dev;
+	mci->mtype_cap = MEM_FLAG_DDR | MEM_FLAG_RDDR;
+	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
+	mci->edac_cap = (errcor & MCCFG_ERRCOR_ECC_GEN_EN) ?
+		((errcor & MCCFG_ERRCOR_ECC_CRR_EN) ?
+		 (EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_EC) :
+		EDAC_FLAG_NONE;
+	mci->mod_name = MODULE_NAME;
+	mci->dev_name = pci_name(pdev);
+	mci->ctl_name = "pasemi,1682m-mc";
+	mci->edac_check = pasemi_edac_check;
+	mci->ctl_page_to_phys = NULL;
+	pci_read_config_dword(pdev, MCCFG_SCRUB, &scrub);
+	mci->scrub_cap = SCRUB_FLAG_HW_PROG | SCRUB_FLAG_HW_SRC;
+	mci->scrub_mode =
+		((errcor & MCCFG_ERRCOR_ECC_CRR_EN) ? SCRUB_FLAG_HW_SRC : 0) |
+		((scrub & MCCFG_SCRUB_RGLR_SCRB_EN) ? SCRUB_FLAG_HW_PROG : 0);
+
+	if (pasemi_edac_init_csrows(mci, pdev,
+				    (mci->edac_cap & EDAC_FLAG_SECDED) ?
+				    EDAC_SECDED :
+				    ((mci->edac_cap & EDAC_FLAG_EC) ?
+				     EDAC_EC : EDAC_NONE)))
+		goto fail;
+
+	/*
+	 * Clear status
+	 */
+	pasemi_edac_get_error_info(mci);
+
+	if (edac_mc_add_mc(mci))
+		goto fail;
+
+	/* get this far and it's successful */
+	return 0;
+
+fail:
+	edac_mc_free(mci);
+	return -ENODEV;
+}
+
+static void __devexit pasemi_edac_remove(struct pci_dev *pdev)
+{
+	struct mem_ctl_info *mci = edac_mc_del_mc(&pdev->dev);
+
+	if (!mci)
+		return;
+
+	edac_mc_free(mci);
+}
+
+
+static const struct pci_device_id pasemi_edac_pci_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa00a) },
+};
+
+MODULE_DEVICE_TABLE(pci, pasemi_edac_pci_tbl);
+
+static struct pci_driver pasemi_edac_driver = {
+	.name = MODULE_NAME,
+	.probe = pasemi_edac_probe,
+	.remove = __devexit_p(pasemi_edac_remove),
+	.id_table = pasemi_edac_pci_tbl,
+};
+
+static int __init pasemi_edac_init(void)
+{
+	return pci_register_driver(&pasemi_edac_driver);
+}
+
+static void __exit pasemi_edac_exit(void)
+{
+	pci_unregister_driver(&pasemi_edac_driver);
+}
+
+module_init(pasemi_edac_init);
+module_exit(pasemi_edac_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
+MODULE_DESCRIPTION("MC support for PA Semi PA6T-1682M memory controller");
diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c
index a49cf0a..e25f712 100644
--- a/drivers/edac/r82600_edac.c
+++ b/drivers/edac/r82600_edac.c
@@ -11,7 +11,7 @@
  *
  * Written with reference to 82600 High Integration Dual PCI System
  * Controller Data Book:
- * http://www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf
+ * www.radisys.com/files/support_downloads/007-01277-0002.82600DataBook.pdf
  * references to this document given in []
  */
 
@@ -20,9 +20,9 @@
 #include <linux/pci.h>
 #include <linux/pci_ids.h>
 #include <linux/slab.h>
-#include "edac_mc.h"
+#include "edac_core.h"
 
-#define R82600_REVISION	" Ver: 2.0.1 " __DATE__
+#define R82600_REVISION	" Ver: 2.0.2 " __DATE__
 #define EDAC_MOD_STR	"r82600_edac"
 
 #define r82600_printk(level, fmt, arg...) \
@@ -131,10 +131,12 @@
 	u32 eapr;
 };
 
-static unsigned int disable_hardware_scrub = 0;
+static unsigned int disable_hardware_scrub;
 
-static void r82600_get_error_info (struct mem_ctl_info *mci,
-		struct r82600_error_info *info)
+static struct edac_pci_ctl_info *r82600_pci;
+
+static void r82600_get_error_info(struct mem_ctl_info *mci,
+				struct r82600_error_info *info)
 {
 	struct pci_dev *pdev;
 
@@ -144,18 +146,19 @@
 	if (info->eapr & BIT(0))
 		/* Clear error to allow next error to be reported [p.62] */
 		pci_write_bits32(pdev, R82600_EAP,
-				((u32) BIT(0) & (u32) BIT(1)),
-				((u32) BIT(0) & (u32) BIT(1)));
+				 ((u32) BIT(0) & (u32) BIT(1)),
+				 ((u32) BIT(0) & (u32) BIT(1)));
 
 	if (info->eapr & BIT(1))
 		/* Clear error to allow next error to be reported [p.62] */
 		pci_write_bits32(pdev, R82600_EAP,
-				((u32) BIT(0) & (u32) BIT(1)),
-				((u32) BIT(0) & (u32) BIT(1)));
+				 ((u32) BIT(0) & (u32) BIT(1)),
+				 ((u32) BIT(0) & (u32) BIT(1)));
 }
 
-static int r82600_process_error_info (struct mem_ctl_info *mci,
-		struct r82600_error_info *info, int handle_errors)
+static int r82600_process_error_info(struct mem_ctl_info *mci,
+				struct r82600_error_info *info,
+				int handle_errors)
 {
 	int error_found;
 	u32 eapaddr, page;
@@ -172,25 +175,24 @@
 	 * granularity (upper 19 bits only)     */
 	page = eapaddr >> PAGE_SHIFT;
 
-	if (info->eapr & BIT(0)) {  /* CE? */
+	if (info->eapr & BIT(0)) {	/* CE? */
 		error_found = 1;
 
 		if (handle_errors)
-			edac_mc_handle_ce(mci, page, 0,  /* not avail */
+			edac_mc_handle_ce(mci, page, 0,	/* not avail */
 					syndrome,
 					edac_mc_find_csrow_by_page(mci, page),
-					0,  /* channel */
-					mci->ctl_name);
+					0, mci->ctl_name);
 	}
 
-	if (info->eapr & BIT(1)) {  /* UE? */
+	if (info->eapr & BIT(1)) {	/* UE? */
 		error_found = 1;
 
 		if (handle_errors)
 			/* 82600 doesn't give enough info */
 			edac_mc_handle_ue(mci, page, 0,
-				edac_mc_find_csrow_by_page(mci, page),
-				mci->ctl_name);
+					edac_mc_find_csrow_by_page(mci, page),
+					mci->ctl_name);
 	}
 
 	return error_found;
@@ -211,11 +213,11 @@
 }
 
 static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
-		u8 dramcr)
+			u8 dramcr)
 {
 	struct csrow_info *csrow;
 	int index;
-	u8 drbar;  /* SDRAM Row Boundry Address Register */
+	u8 drbar;		/* SDRAM Row Boundry Address Register */
 	u32 row_high_limit, row_high_limit_last;
 	u32 reg_sdram, ecc_on, row_base;
 
@@ -276,7 +278,7 @@
 	debugf2("%s(): sdram refresh rate = %#0x\n", __func__,
 		sdram_refresh_rate);
 	debugf2("%s(): DRAMC register = %#0x\n", __func__, dramcr);
-	mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS);
+	mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS, 0);
 
 	if (mci == NULL)
 		return -ENOMEM;
@@ -305,15 +307,16 @@
 	mci->mod_name = EDAC_MOD_STR;
 	mci->mod_ver = R82600_REVISION;
 	mci->ctl_name = "R82600";
+	mci->dev_name = pci_name(pdev);
 	mci->edac_check = r82600_check;
 	mci->ctl_page_to_phys = NULL;
 	r82600_init_csrows(mci, pdev, dramcr);
-	r82600_get_error_info(mci, &discard);  /* clear counters */
+	r82600_get_error_info(mci, &discard);	/* clear counters */
 
 	/* Here we assume that we will never see multiple instances of this
 	 * type of memory controller.  The ID is therefore hardcoded to 0.
 	 */
-	if (edac_mc_add_mc(mci,0)) {
+	if (edac_mc_add_mc(mci)) {
 		debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
 		goto fail;
 	}
@@ -326,6 +329,17 @@
 		pci_write_bits32(pdev, R82600_EAP, BIT(31), BIT(31));
 	}
 
+	/* allocating generic PCI control info */
+	r82600_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR);
+	if (!r82600_pci) {
+		printk(KERN_WARNING
+			"%s(): Unable to create PCI control\n",
+			__func__);
+		printk(KERN_WARNING
+			"%s(): PCI error report via EDAC not setup\n",
+			__func__);
+	}
+
 	debugf3("%s(): success\n", __func__);
 	return 0;
 
@@ -336,7 +350,7 @@
 
 /* returns count (>= 0), or negative on error */
 static int __devinit r82600_init_one(struct pci_dev *pdev,
-		const struct pci_device_id *ent)
+				const struct pci_device_id *ent)
 {
 	debugf0("%s()\n", __func__);
 
@@ -350,6 +364,9 @@
 
 	debugf0("%s()\n", __func__);
 
+	if (r82600_pci)
+		edac_pci_release_generic_ctl(r82600_pci);
+
 	if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
 		return;
 
@@ -358,11 +375,11 @@
 
 static const struct pci_device_id r82600_pci_tbl[] __devinitdata = {
 	{
-		PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)
-	},
+	 PCI_DEVICE(PCI_VENDOR_ID_RADISYS, R82600_BRIDGE_ID)
+	 },
 	{
-		0,
-	}	/* 0 terminated list. */
+	 0,
+	 }			/* 0 terminated list. */
 };
 
 MODULE_DEVICE_TABLE(pci, r82600_pci_tbl);
@@ -389,7 +406,7 @@
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD Ltd. "
-	"on behalf of EADS Astrium");
+		"on behalf of EADS Astrium");
 MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers");
 
 module_param(disable_hardware_scrub, bool, 0644);
diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c
index d944647..4d4a473 100644
--- a/drivers/eisa/eisa-bus.c
+++ b/drivers/eisa/eisa-bus.c
@@ -128,16 +128,11 @@
 	return 0;
 }
 
-static int eisa_bus_uevent(struct device *dev, char **envp, int num_envp,
-			   char *buffer, int buffer_size)
+static int eisa_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct eisa_device *edev = to_eisa_device(dev);
-	int i = 0;
-	int length = 0;
 
-	add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-		       "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig);
-	envp[i] = NULL;
+	add_uevent_var(env, "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig);
 	return 0;
 }
 
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index d011a76..fe9e768 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -11,7 +11,8 @@
 	  This is the "Juju" FireWire stack, a new alternative implementation
 	  designed for robustness and simplicity.  You can build either this
 	  stack, or the classic stack (the ieee1394 driver, ohci1394 etc.)
-	  or both.
+	  or both.  Please read http://wiki.linux1394.org/JujuMigration before
+	  you enable the new stack.
 
 	  To compile this driver as a module, say M here: the module will be
 	  called firewire-core.  It functionally replaces ieee1394, raw1394,
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c
index 0aeab32..3e97199 100644
--- a/drivers/firewire/fw-card.c
+++ b/drivers/firewire/fw-card.c
@@ -510,9 +510,11 @@
 	/* Set up the dummy driver. */
 	card->driver = &dummy_driver;
 
-	fw_flush_transactions(card);
-
 	fw_destroy_nodes(card);
+	flush_scheduled_work();
+
+	fw_flush_transactions(card);
+	del_timer_sync(&card->flush_timer);
 
 	fw_card_put(card);
 }
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
index 2b65863..56681b3 100644
--- a/drivers/firewire/fw-device.c
+++ b/drivers/firewire/fw-device.c
@@ -130,23 +130,16 @@
 }
 
 static int
-fw_unit_uevent(struct device *dev, char **envp, int num_envp,
-	       char *buffer, int buffer_size)
+fw_unit_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct fw_unit *unit = fw_unit(dev);
 	char modalias[64];
-	int length = 0;
-	int i = 0;
 
 	get_modalias(unit, modalias, sizeof(modalias));
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "MODALIAS=%s", modalias))
+	if (add_uevent_var(env, "MODALIAS=%s", modalias))
 		return -ENOMEM;
 
-	envp[i] = NULL;
-
 	return 0;
 }
 
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c
index 41476ab..e14c1ca7 100644
--- a/drivers/firewire/fw-ohci.c
+++ b/drivers/firewire/fw-ohci.c
@@ -224,6 +224,7 @@
 	u32 val, old;
 
 	reg_write(ohci, OHCI1394_PhyControl, OHCI1394_PhyControl_Read(addr));
+	flush_writes(ohci);
 	msleep(2);
 	val = reg_read(ohci, OHCI1394_PhyControl);
 	if ((val & OHCI1394_PhyControl_ReadDone) == 0) {
@@ -586,7 +587,7 @@
 			break;
 
 		fw_notify("context_stop: still active (0x%08x)\n", reg);
-		msleep(1);
+		mdelay(1);
 	}
 }
 
@@ -906,6 +907,8 @@
 	int self_id_count, i, j, reg;
 	int generation, new_generation;
 	unsigned long flags;
+	void *free_rom = NULL;
+	dma_addr_t free_rom_bus = 0;
 
 	reg = reg_read(ohci, OHCI1394_NodeID);
 	if (!(reg & OHCI1394_NodeID_idValid)) {
@@ -969,8 +972,8 @@
 	 */
 
 	if (ohci->next_config_rom != NULL) {
-		dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
-				  ohci->config_rom, ohci->config_rom_bus);
+		free_rom     = ohci->config_rom;
+		free_rom_bus = ohci->config_rom_bus;
 		ohci->config_rom      = ohci->next_config_rom;
 		ohci->config_rom_bus  = ohci->next_config_rom_bus;
 		ohci->next_config_rom = NULL;
@@ -989,6 +992,10 @@
 
 	spin_unlock_irqrestore(&ohci->lock, flags);
 
+	if (free_rom)
+		dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+				  free_rom, free_rom_bus);
+
 	fw_core_handle_bus_reset(&ohci->card, ohci->node_id, generation,
 				 self_id_count, ohci->self_id_buffer);
 }
@@ -1185,7 +1192,7 @@
 {
 	struct fw_ohci *ohci;
 	unsigned long flags;
-	int retval = 0;
+	int retval = -EBUSY;
 	__be32 *next_config_rom;
 	dma_addr_t next_config_rom_bus;
 
@@ -1239,10 +1246,7 @@
 
 		reg_write(ohci, OHCI1394_ConfigROMmap,
 			  ohci->next_config_rom_bus);
-	} else {
-		dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
-				  next_config_rom, next_config_rom_bus);
-		retval = -EBUSY;
+		retval = 0;
 	}
 
 	spin_unlock_irqrestore(&ohci->lock, flags);
@@ -1256,6 +1260,9 @@
 	 */
 	if (retval == 0)
 		fw_core_initiate_bus_reset(&ohci->card, 1);
+	else
+		dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
+				  next_config_rom, next_config_rom_bus);
 
 	return retval;
 }
@@ -1938,10 +1945,8 @@
 		return err;
 	}
 	err = pci_set_power_state(pdev, pci_choose_state(pdev, state));
-	if (err) {
-		fw_error("pci_set_power_state failed\n");
-		return err;
-	}
+	if (err)
+		fw_error("pci_set_power_state failed with %d\n", err);
 
 	return 0;
 }
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index 7c53be0..238730f 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -159,6 +159,7 @@
 
 struct sbp2_orb {
 	struct fw_transaction t;
+	struct kref kref;
 	dma_addr_t request_bus;
 	int rcode;
 	struct sbp2_pointer pointer;
@@ -280,6 +281,14 @@
 };
 
 static void
+free_orb(struct kref *kref)
+{
+	struct sbp2_orb *orb = container_of(kref, struct sbp2_orb, kref);
+
+	kfree(orb);
+}
+
+static void
 sbp2_status_write(struct fw_card *card, struct fw_request *request,
 		  int tcode, int destination, int source,
 		  int generation, int speed,
@@ -312,8 +321,8 @@
 	spin_lock_irqsave(&card->lock, flags);
 	list_for_each_entry(orb, &sd->orb_list, link) {
 		if (STATUS_GET_ORB_HIGH(status) == 0 &&
-		    STATUS_GET_ORB_LOW(status) == orb->request_bus &&
-		    orb->rcode == RCODE_COMPLETE) {
+		    STATUS_GET_ORB_LOW(status) == orb->request_bus) {
+			orb->rcode = RCODE_COMPLETE;
 			list_del(&orb->link);
 			break;
 		}
@@ -325,6 +334,8 @@
 	else
 		fw_error("status write for unknown orb\n");
 
+	kref_put(&orb->kref, free_orb);
+
 	fw_send_response(card, request, RCODE_COMPLETE);
 }
 
@@ -335,13 +346,27 @@
 	struct sbp2_orb *orb = data;
 	unsigned long flags;
 
-	orb->rcode = rcode;
-	if (rcode != RCODE_COMPLETE) {
-		spin_lock_irqsave(&card->lock, flags);
+	/*
+	 * This is a little tricky.  We can get the status write for
+	 * the orb before we get this callback.  The status write
+	 * handler above will assume the orb pointer transaction was
+	 * successful and set the rcode to RCODE_COMPLETE for the orb.
+	 * So this callback only sets the rcode if it hasn't already
+	 * been set and only does the cleanup if the transaction
+	 * failed and we didn't already get a status write.
+	 */
+	spin_lock_irqsave(&card->lock, flags);
+
+	if (orb->rcode == -1)
+		orb->rcode = rcode;
+	if (orb->rcode != RCODE_COMPLETE) {
 		list_del(&orb->link);
-		spin_unlock_irqrestore(&card->lock, flags);
 		orb->callback(orb, NULL);
 	}
+
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	kref_put(&orb->kref, free_orb);
 }
 
 static void
@@ -360,6 +385,10 @@
 	list_add_tail(&orb->link, &sd->orb_list);
 	spin_unlock_irqrestore(&device->card->lock, flags);
 
+	/* Take a ref for the orb list and for the transaction callback. */
+	kref_get(&orb->kref);
+	kref_get(&orb->kref);
+
 	fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST,
 			node_id, generation, device->max_speed, offset,
 			&orb->pointer, sizeof(orb->pointer),
@@ -416,6 +445,7 @@
 	if (orb == NULL)
 		return -ENOMEM;
 
+	kref_init(&orb->base.kref);
 	orb->response_bus =
 		dma_map_single(device->card->device, &orb->response,
 			       sizeof(orb->response), DMA_FROM_DEVICE);
@@ -490,7 +520,7 @@
 	if (response)
 		fw_memcpy_from_be32(response,
 				    orb->response, sizeof(orb->response));
-	kfree(orb);
+	kref_put(&orb->base.kref, free_orb);
 
 	return retval;
 }
@@ -840,7 +870,6 @@
 		container_of(base_orb, struct sbp2_command_orb, base);
 	struct fw_unit *unit = orb->unit;
 	struct fw_device *device = fw_device(unit->device.parent);
-	struct scatterlist *sg;
 	int result;
 
 	if (status != NULL) {
@@ -876,11 +905,10 @@
 	dma_unmap_single(device->card->device, orb->base.request_bus,
 			 sizeof(orb->request), DMA_TO_DEVICE);
 
-	if (orb->cmd->use_sg > 0) {
-		sg = (struct scatterlist *)orb->cmd->request_buffer;
-		dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg,
+	if (scsi_sg_count(orb->cmd) > 0)
+		dma_unmap_sg(device->card->device, scsi_sglist(orb->cmd),
+			     scsi_sg_count(orb->cmd),
 			     orb->cmd->sc_data_direction);
-	}
 
 	if (orb->page_table_bus != 0)
 		dma_unmap_single(device->card->device, orb->page_table_bus,
@@ -888,7 +916,6 @@
 
 	orb->cmd->result = result;
 	orb->done(orb->cmd);
-	kfree(orb);
 }
 
 static int sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
@@ -901,8 +928,8 @@
 	int sg_len, l, i, j, count;
 	dma_addr_t sg_addr;
 
-	sg = (struct scatterlist *)orb->cmd->request_buffer;
-	count = dma_map_sg(device->card->device, sg, orb->cmd->use_sg,
+	sg = scsi_sglist(orb->cmd);
+	count = dma_map_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
 			   orb->cmd->sc_data_direction);
 	if (count == 0)
 		goto fail;
@@ -971,7 +998,7 @@
 	return 0;
 
  fail_page_table:
-	dma_unmap_sg(device->card->device, sg, orb->cmd->use_sg,
+	dma_unmap_sg(device->card->device, sg, scsi_sg_count(orb->cmd),
 		     orb->cmd->sc_data_direction);
  fail:
 	return -ENOMEM;
@@ -986,6 +1013,7 @@
 	struct fw_unit *unit = sd->unit;
 	struct fw_device *device = fw_device(unit->device.parent);
 	struct sbp2_command_orb *orb;
+	unsigned max_payload;
 
 	/*
 	 * Bidirectional commands are not yet implemented, and unknown
@@ -1006,6 +1034,7 @@
 
 	/* Initialize rcode to something not RCODE_COMPLETE. */
 	orb->base.rcode = -1;
+	kref_init(&orb->base.kref);
 
 	orb->unit = unit;
 	orb->done = done;
@@ -1019,8 +1048,10 @@
 	 * specifies the max payload size as 2 ^ (max_payload + 2), so
 	 * if we set this to max_speed + 7, we get the right value.
 	 */
+	max_payload = min(device->max_speed + 7,
+			  device->card->max_receive - 1);
 	orb->request.misc =
-		COMMAND_ORB_MAX_PAYLOAD(device->max_speed + 7) |
+		COMMAND_ORB_MAX_PAYLOAD(max_payload) |
 		COMMAND_ORB_SPEED(device->max_speed) |
 		COMMAND_ORB_NOTIFY;
 
@@ -1031,7 +1062,7 @@
 		orb->request.misc |=
 			COMMAND_ORB_DIRECTION(SBP2_DIRECTION_TO_MEDIA);
 
-	if (cmd->use_sg && sbp2_command_orb_map_scatterlist(orb) < 0)
+	if (scsi_sg_count(cmd) && sbp2_command_orb_map_scatterlist(orb) < 0)
 		goto fail_mapping;
 
 	fw_memcpy_to_be32(&orb->request, &orb->request, sizeof(orb->request));
@@ -1050,10 +1081,11 @@
 	sbp2_send_orb(&orb->base, unit, sd->node_id, sd->generation,
 		      sd->command_block_agent_address + SBP2_ORB_POINTER);
 
+	kref_put(&orb->base.kref, free_orb);
 	return 0;
 
  fail_mapping:
-	kfree(orb);
+	kref_put(&orb->base.kref, free_orb);
  fail_alloc:
 	return SCSI_MLQUEUE_HOST_BUSY;
 }
@@ -1162,7 +1194,7 @@
 static struct scsi_host_template scsi_driver_template = {
 	.module			= THIS_MODULE,
 	.name			= "SBP-2 IEEE-1394",
-	.proc_name		= (char *)sbp2_driver_name,
+	.proc_name		= sbp2_driver_name,
 	.queuecommand		= sbp2_scsi_queuecommand,
 	.slave_alloc		= sbp2_scsi_slave_alloc,
 	.slave_configure	= sbp2_scsi_slave_configure,
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c
index 80d0121..3e1cb12 100644
--- a/drivers/firewire/fw-transaction.c
+++ b/drivers/firewire/fw-transaction.c
@@ -605,8 +605,10 @@
 	 * check is sufficient to ensure we don't send response to
 	 * broadcast packets or posted writes.
 	 */
-	if (request->ack != ACK_PENDING)
+	if (request->ack != ACK_PENDING) {
+		kfree(request);
 		return;
+	}
 
 	if (rcode == RCODE_COMPLETE)
 		fw_fill_response(&request->response, request->request_header,
@@ -628,11 +630,6 @@
 	unsigned long flags;
 	int tcode, destination, source;
 
-	if (p->payload_length > 2048) {
-		/* FIXME: send error response. */
-		return;
-	}
-
 	if (p->ack != ACK_PENDING && p->ack != ACK_COMPLETE)
 		return;
 
@@ -737,7 +734,7 @@
 }
 EXPORT_SYMBOL(fw_core_handle_response);
 
-const struct fw_address_region topology_map_region =
+static const struct fw_address_region topology_map_region =
 	{ .start = 0xfffff0001000ull, .end = 0xfffff0001400ull, };
 
 static void
@@ -775,7 +772,7 @@
 	.address_callback	= handle_topology_map,
 };
 
-const struct fw_address_region registers_region =
+static const struct fw_address_region registers_region =
 	{ .start = 0xfffff0000000ull, .end = 0xfffff0000400ull, };
 
 static void
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h
index 5abed19..fa7967b 100644
--- a/drivers/firewire/fw-transaction.h
+++ b/drivers/firewire/fw-transaction.h
@@ -123,6 +123,10 @@
 					  size_t length,
 					  void *callback_data);
 
+/*
+ * Important note:  The callback must guarantee that either fw_send_response()
+ * or kfree() is called on the @request.
+ */
 typedef void (*fw_address_callback_t)(struct fw_card *card,
 				      struct fw_request *request,
 				      int tcode, int destination, int source,
@@ -227,7 +231,7 @@
 	unsigned long reset_jiffies;
 
 	unsigned long long guid;
-	int max_receive;
+	unsigned max_receive;
 	int link_speed;
 	int config_rom_generation;
 
diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c
index 59c3b5a..b6e1eb7 100644
--- a/drivers/firmware/dmi-id.c
+++ b/drivers/firmware/dmi-id.c
@@ -13,21 +13,31 @@
 #include <linux/device.h>
 #include <linux/autoconf.h>
 
-#define DEFINE_DMI_ATTR(_name, _mode, _show)		\
-static struct device_attribute sys_dmi_##_name##_attr =	\
-	__ATTR(_name, _mode, _show, NULL);
+struct dmi_device_attribute{
+	struct device_attribute dev_attr;
+	int field;
+};
+#define to_dmi_dev_attr(_dev_attr) \
+	container_of(_dev_attr, struct dmi_device_attribute, dev_attr)
 
-#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field)			\
-static ssize_t sys_dmi_##_name##_show(struct device *dev,		\
-				      struct device_attribute *attr,	\
-				      char *page)			\
-{									\
-	ssize_t len;							\
-	len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(_field)); \
-	page[len-1] = '\n';						\
-	return len;							\
-}									\
-DEFINE_DMI_ATTR(_name, _mode, sys_dmi_##_name##_show);
+static ssize_t sys_dmi_field_show(struct device *dev,
+				  struct device_attribute *attr,
+				  char *page)
+{
+	int field = to_dmi_dev_attr(attr)->field;
+	ssize_t len;
+	len = scnprintf(page, PAGE_SIZE, "%s\n", dmi_get_system_info(field));
+	page[len-1] = '\n';
+	return len;
+}
+
+#define DMI_ATTR(_name, _mode, _show, _field)			\
+	{ .dev_attr = __ATTR(_name, _mode, _show, NULL),	\
+	  .field = _field }
+
+#define DEFINE_DMI_ATTR_WITH_SHOW(_name, _mode, _field)		\
+static struct dmi_device_attribute sys_dmi_##_name##_attr =	\
+	DMI_ATTR(_name, _mode, sys_dmi_field_show, _field);
 
 DEFINE_DMI_ATTR_WITH_SHOW(bios_vendor,		0444, DMI_BIOS_VENDOR);
 DEFINE_DMI_ATTR_WITH_SHOW(bios_version,		0444, DMI_BIOS_VERSION);
@@ -121,7 +131,8 @@
 	return r+1;
 }
 
-DEFINE_DMI_ATTR(modalias, 0444, sys_dmi_modalias_show);
+static struct device_attribute sys_dmi_modalias_attr =
+	__ATTR(modalias, 0444, sys_dmi_modalias_show, NULL);
 
 static struct attribute *sys_dmi_attributes[DMI_STRING_MAX+2];
 
@@ -134,14 +145,17 @@
 	NULL
 };
 
-static int dmi_dev_uevent(struct device *dev, char **envp,
-			    int num_envp, char *buffer, int buffer_size)
+static int dmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
-	strcpy(buffer, "MODALIAS=");
-	get_modalias(buffer+9, buffer_size-9);
-	envp[0] = buffer;
-	envp[1] = NULL;
+	ssize_t len;
 
+	if (add_uevent_var(env, "MODALIAS="))
+		return -ENOMEM;
+	len = get_modalias(&env->buf[env->buflen - 1],
+			   sizeof(env->buf) - env->buflen);
+	if (len >= (sizeof(env->buf) - env->buflen))
+		return -ENOMEM;
+	env->buflen += len;
 	return 0;
 }
 
@@ -157,7 +171,7 @@
 
 #define ADD_DMI_ATTR(_name, _field) \
 	if (dmi_get_system_info(_field)) \
-		sys_dmi_attributes[i++] = & sys_dmi_##_name##_attr.attr;
+		sys_dmi_attributes[i++] = &sys_dmi_##_name##_attr.dev_attr.attr;
 
 extern int dmi_available;
 
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index f7318b3..0cdadea 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -8,9 +8,9 @@
 #include <linux/slab.h>
 #include <asm/dmi.h>
 
-static char * __init dmi_string(struct dmi_header *dm, u8 s)
+static char * __init dmi_string(const struct dmi_header *dm, u8 s)
 {
-	u8 *bp = ((u8 *) dm) + dm->length;
+	const u8 *bp = ((u8 *) dm) + dm->length;
 	char *str = "";
 
 	if (s) {
@@ -37,7 +37,7 @@
  *	pointing to completely the wrong place for example
  */
 static int __init dmi_table(u32 base, int len, int num,
-			    void (*decode)(struct dmi_header *))
+			    void (*decode)(const struct dmi_header *))
 {
 	u8 *buf, *data;
 	int i = 0;
@@ -53,7 +53,8 @@
 	 *	OR we run off the end of the table (also happens)
 	 */
 	while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) {
-		struct dmi_header *dm = (struct dmi_header *)data;
+		const struct dmi_header *dm = (const struct dmi_header *)data;
+
 		/*
 		 *  We want to know the total length (formated area and strings)
 		 *  before decoding to make sure we won't run off the table in
@@ -71,7 +72,7 @@
 	return 0;
 }
 
-static int __init dmi_checksum(u8 *buf)
+static int __init dmi_checksum(const u8 *buf)
 {
 	u8 sum = 0;
 	int a;
@@ -89,9 +90,10 @@
 /*
  *	Save a DMI string
  */
-static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
+static void __init dmi_save_ident(const struct dmi_header *dm, int slot, int string)
 {
-	char *p, *d = (char*) dm;
+	const char *d = (const char*) dm;
+	char *p;
 
 	if (dmi_ident[slot])
 		return;
@@ -103,9 +105,9 @@
 	dmi_ident[slot] = p;
 }
 
-static void __init dmi_save_uuid(struct dmi_header *dm, int slot, int index)
+static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int index)
 {
-	u8 *d = (u8*) dm + index;
+	const u8 *d = (u8*) dm + index;
 	char *s;
 	int is_ff = 1, is_00 = 1, i;
 
@@ -132,9 +134,9 @@
         dmi_ident[slot] = s;
 }
 
-static void __init dmi_save_type(struct dmi_header *dm, int slot, int index)
+static void __init dmi_save_type(const struct dmi_header *dm, int slot, int index)
 {
-	u8 *d = (u8*) dm + index;
+	const u8 *d = (u8*) dm + index;
 	char *s;
 
 	if (dmi_ident[slot])
@@ -148,13 +150,13 @@
 	dmi_ident[slot] = s;
 }
 
-static void __init dmi_save_devices(struct dmi_header *dm)
+static void __init dmi_save_devices(const struct dmi_header *dm)
 {
 	int i, count = (dm->length - sizeof(struct dmi_header)) / 2;
 	struct dmi_device *dev;
 
 	for (i = 0; i < count; i++) {
-		char *d = (char *)(dm + 1) + (i * 2);
+		const char *d = (char *)(dm + 1) + (i * 2);
 
 		/* Skip disabled device */
 		if ((*d & 0x80) == 0)
@@ -173,7 +175,7 @@
 	}
 }
 
-static void __init dmi_save_oem_strings_devices(struct dmi_header *dm)
+static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm)
 {
 	int i, count = *(u8 *)(dm + 1);
 	struct dmi_device *dev;
@@ -194,7 +196,7 @@
 	}
 }
 
-static void __init dmi_save_ipmi_device(struct dmi_header *dm)
+static void __init dmi_save_ipmi_device(const struct dmi_header *dm)
 {
 	struct dmi_device *dev;
 	void * data;
@@ -225,7 +227,7 @@
  *	and machine entries. For 2.5 we should pull the smbus controller info
  *	out of here.
  */
-static void __init dmi_decode(struct dmi_header *dm)
+static void __init dmi_decode(const struct dmi_header *dm)
 {
 	switch(dm->type) {
 	case 0:		/* BIOS Information */
@@ -265,9 +267,10 @@
 	}
 }
 
-static int __init dmi_present(char __iomem *p)
+static int __init dmi_present(const char __iomem *p)
 {
 	u8 buf[15];
+
 	memcpy_fromio(buf, p, 15);
 	if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
 		u16 num = (buf[13] << 8) | buf[12];
@@ -348,10 +351,10 @@
  *	returns non zero or we hit the end. Callback function is called for
  *	each successful match. Returns the number of matches.
  */
-int dmi_check_system(struct dmi_system_id *list)
+int dmi_check_system(const struct dmi_system_id *list)
 {
 	int i, count = 0;
-	struct dmi_system_id *d = list;
+	const struct dmi_system_id *d = list;
 
 	while (d->ident) {
 		for (i = 0; i < ARRAY_SIZE(d->matches); i++) {
@@ -380,7 +383,7 @@
  *	Returns one DMI data value, can be used to perform
  *	complex DMI data checks.
  */
-char *dmi_get_system_info(int field)
+const char *dmi_get_system_info(int field)
 {
 	return dmi_ident[field];
 }
@@ -391,7 +394,7 @@
  *	dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information.
  *	@str: 	Case sensitive Name
  */
-int dmi_name_in_vendors(char *str)
+int dmi_name_in_vendors(const char *str)
 {
 	static int fields[] = { DMI_BIOS_VENDOR, DMI_BIOS_VERSION, DMI_SYS_VENDOR,
 				DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, DMI_BOARD_VENDOR,
@@ -418,13 +421,15 @@
  *	A new search is initiated by passing %NULL as the @from argument.
  *	If @from is not %NULL, searches continue from next device.
  */
-struct dmi_device * dmi_find_device(int type, const char *name,
-				    struct dmi_device *from)
+const struct dmi_device * dmi_find_device(int type, const char *name,
+				    const struct dmi_device *from)
 {
-	struct list_head *d, *head = from ? &from->list : &dmi_devices;
+	const struct list_head *head = from ? &from->list : &dmi_devices;
+	struct list_head *d;
 
 	for(d = head->next; d != &dmi_devices; d = d->next) {
-		struct dmi_device *dev = list_entry(d, struct dmi_device, list);
+		const struct dmi_device *dev =
+			list_entry(d, struct dmi_device, list);
 
 		if (((type == DMI_DEV_TYPE_ANY) || (dev->type == type)) &&
 		    ((name == NULL) || (strcmp(dev->name, name) == 0)))
@@ -444,7 +449,7 @@
 int dmi_get_year(int field)
 {
 	int year;
-	char *s = dmi_get_system_info(field);
+	const char *s = dmi_get_system_info(field);
 
 	if (!s)
 		return -1;
diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
index 0fb730e..6942e06 100644
--- a/drivers/firmware/edd.c
+++ b/drivers/firmware/edd.c
@@ -625,13 +625,13 @@
 	kfree(dev);
 }
 
-static struct kobj_type ktype_edd = {
+static struct kobj_type edd_ktype = {
 	.release	= edd_release,
 	.sysfs_ops	= &edd_attr_ops,
 	.default_attrs	= def_attrs,
 };
 
-static decl_subsys(edd,&ktype_edd,NULL);
+static decl_subsys(edd, &edd_ktype, NULL);
 
 
 /**
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index bfd2d67..858a7b9 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -402,7 +402,7 @@
 	NULL,
 };
 
-static struct kobj_type ktype_efivar = {
+static struct kobj_type efivar_ktype = {
 	.release = efivar_release,
 	.sysfs_ops = &efivar_attr_ops,
 	.default_attrs = def_attrs,
@@ -583,7 +583,7 @@
 	NULL,	/* maybe more in the future? */
 };
 
-static decl_subsys(vars, &ktype_efivar, NULL);
+static decl_subsys(vars, &efivar_ktype, NULL);
 static decl_subsys(efi, NULL, NULL);
 
 /*
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 3b63b0b..19667fc 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -5,6 +5,11 @@
 	bool "HID Devices"
 	depends on INPUT
 	default y
+	---help---
+	  Say Y here to get to see options for various computer-human interface
+	  device drivers. This option alone does not add any kernel code.
+
+	  If you say N, all options in this submenu will be skipped and disabled.
 
 if HID_SUPPORT
 
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index b2baeae..0a1f2b5 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -743,7 +743,7 @@
 	hid->quirks = quirks;
 
 	if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL)))
-		goto fail;
+		goto fail_no_usbhid;
 
 	hid->driver_data = usbhid;
 	usbhid->hid = hid;
@@ -878,6 +878,8 @@
 	usb_free_urb(usbhid->urbout);
 	usb_free_urb(usbhid->urbctrl);
 	hid_free_buffers(dev, hid);
+	kfree(usbhid);
+fail_no_usbhid:
 	hid_free_device(hid);
 
 	return NULL;
@@ -913,6 +915,7 @@
 	usb_free_urb(usbhid->urbout);
 
 	hid_free_buffers(hid_to_usb_dev(hid), hid);
+	kfree(usbhid);
 	hid_free_device(hid);
 }
 
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 775b9f3..6b21a21 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -61,7 +61,9 @@
 #define USB_DEVICE_ID_APPLE_GEYSER4_JIS	0x021c
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY	0x030a
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY	0x030b
-#define USB_DEVICE_ID_APPLE_IR		0x8240
+
+#define USB_VENDOR_ID_ASUS		0x0b05
+#define USB_DEVICE_ID_ASUS_LCM		0x1726
 
 #define USB_VENDOR_ID_ATEN		0x0557
 #define USB_DEVICE_ID_ATEN_UC100KM	0x2004
@@ -198,6 +200,70 @@
 
 #define USB_VENDOR_ID_LOGITECH		0x046d
 #define USB_DEVICE_ID_LOGITECH_RECEIVER	0xc101
+#define USB_DEVICE_ID_LOGITECH_HARMONY  0xc110
+#define USB_DEVICE_ID_LOGITECH_HARMONY_2 0xc111
+#define USB_DEVICE_ID_LOGITECH_HARMONY_3 0xc112
+#define USB_DEVICE_ID_LOGITECH_HARMONY_4 0xc113
+#define USB_DEVICE_ID_LOGITECH_HARMONY_5 0xc114
+#define USB_DEVICE_ID_LOGITECH_HARMONY_6 0xc115
+#define USB_DEVICE_ID_LOGITECH_HARMONY_7 0xc116
+#define USB_DEVICE_ID_LOGITECH_HARMONY_8 0xc117
+#define USB_DEVICE_ID_LOGITECH_HARMONY_9 0xc118
+#define USB_DEVICE_ID_LOGITECH_HARMONY_10 0xc119
+#define USB_DEVICE_ID_LOGITECH_HARMONY_11 0xc11a
+#define USB_DEVICE_ID_LOGITECH_HARMONY_12 0xc11b
+#define USB_DEVICE_ID_LOGITECH_HARMONY_13 0xc11c
+#define USB_DEVICE_ID_LOGITECH_HARMONY_14 0xc11d
+#define USB_DEVICE_ID_LOGITECH_HARMONY_15 0xc11e
+#define USB_DEVICE_ID_LOGITECH_HARMONY_16 0xc11f
+#define USB_DEVICE_ID_LOGITECH_HARMONY_17 0xc120
+#define USB_DEVICE_ID_LOGITECH_HARMONY_18 0xc121
+#define USB_DEVICE_ID_LOGITECH_HARMONY_19 0xc122
+#define USB_DEVICE_ID_LOGITECH_HARMONY_20 0xc123
+#define USB_DEVICE_ID_LOGITECH_HARMONY_21 0xc124
+#define USB_DEVICE_ID_LOGITECH_HARMONY_22 0xc125
+#define USB_DEVICE_ID_LOGITECH_HARMONY_23 0xc126
+#define USB_DEVICE_ID_LOGITECH_HARMONY_24 0xc127
+#define USB_DEVICE_ID_LOGITECH_HARMONY_25 0xc128
+#define USB_DEVICE_ID_LOGITECH_HARMONY_26 0xc129
+#define USB_DEVICE_ID_LOGITECH_HARMONY_27 0xc12a
+#define USB_DEVICE_ID_LOGITECH_HARMONY_28 0xc12b
+#define USB_DEVICE_ID_LOGITECH_HARMONY_29 0xc12c
+#define USB_DEVICE_ID_LOGITECH_HARMONY_30 0xc12d
+#define USB_DEVICE_ID_LOGITECH_HARMONY_31 0xc12e
+#define USB_DEVICE_ID_LOGITECH_HARMONY_32 0xc12f
+#define USB_DEVICE_ID_LOGITECH_HARMONY_33 0xc130
+#define USB_DEVICE_ID_LOGITECH_HARMONY_34 0xc131
+#define USB_DEVICE_ID_LOGITECH_HARMONY_35 0xc132
+#define USB_DEVICE_ID_LOGITECH_HARMONY_36 0xc133
+#define USB_DEVICE_ID_LOGITECH_HARMONY_37 0xc134
+#define USB_DEVICE_ID_LOGITECH_HARMONY_38 0xc135
+#define USB_DEVICE_ID_LOGITECH_HARMONY_39 0xc136
+#define USB_DEVICE_ID_LOGITECH_HARMONY_40 0xc137
+#define USB_DEVICE_ID_LOGITECH_HARMONY_41 0xc138
+#define USB_DEVICE_ID_LOGITECH_HARMONY_42 0xc139
+#define USB_DEVICE_ID_LOGITECH_HARMONY_43 0xc13a
+#define USB_DEVICE_ID_LOGITECH_HARMONY_44 0xc13b
+#define USB_DEVICE_ID_LOGITECH_HARMONY_45 0xc13c
+#define USB_DEVICE_ID_LOGITECH_HARMONY_46 0xc13d
+#define USB_DEVICE_ID_LOGITECH_HARMONY_47 0xc13e
+#define USB_DEVICE_ID_LOGITECH_HARMONY_48 0xc13f
+#define USB_DEVICE_ID_LOGITECH_HARMONY_49 0xc140
+#define USB_DEVICE_ID_LOGITECH_HARMONY_50 0xc141
+#define USB_DEVICE_ID_LOGITECH_HARMONY_51 0xc142
+#define USB_DEVICE_ID_LOGITECH_HARMONY_52 0xc143
+#define USB_DEVICE_ID_LOGITECH_HARMONY_53 0xc144
+#define USB_DEVICE_ID_LOGITECH_HARMONY_54 0xc145
+#define USB_DEVICE_ID_LOGITECH_HARMONY_55 0xc146
+#define USB_DEVICE_ID_LOGITECH_HARMONY_56 0xc147
+#define USB_DEVICE_ID_LOGITECH_HARMONY_57 0xc148
+#define USB_DEVICE_ID_LOGITECH_HARMONY_58 0xc149
+#define USB_DEVICE_ID_LOGITECH_HARMONY_59 0xc14a
+#define USB_DEVICE_ID_LOGITECH_HARMONY_60 0xc14b
+#define USB_DEVICE_ID_LOGITECH_HARMONY_61 0xc14c
+#define USB_DEVICE_ID_LOGITECH_HARMONY_62 0xc14d
+#define USB_DEVICE_ID_LOGITECH_HARMONY_63 0xc14e
+#define USB_DEVICE_ID_LOGITECH_HARMONY_64 0xc14f
 #define USB_DEVICE_ID_LOGITECH_WHEEL	0xc294
 #define USB_DEVICE_ID_LOGITECH_KBD	0xc311
 #define USB_DEVICE_ID_S510_RECEIVER	0xc50c
@@ -221,6 +287,9 @@
 #define USB_DEVICE_ID_NCR_FIRST		0x0300
 #define USB_DEVICE_ID_NCR_LAST		0x03ff
 
+#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
+#define USB_DEVICE_ID_N_S_HARMONY       0xc359
+
 #define USB_VENDOR_ID_NEC		0x073e
 #define USB_DEVICE_ID_NEC_USB_GAME_PAD	0x0301
 
@@ -315,7 +384,7 @@
 	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE},
 	{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
@@ -463,6 +532,71 @@
 
 	{ USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS },
 	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD, HID_QUIRK_RESET_LEDS },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_2, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_3, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_4, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_5, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_6, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_7, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_8, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_9, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_10, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_11, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_12, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_13, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_14, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_15, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_16, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_17, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_18, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_19, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_20, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_21, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_22, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_23, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_24, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_25, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_26, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_27, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_28, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_29, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_30, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_31, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_32, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_33, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_34, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_35, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_36, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_37, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_38, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_39, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_40, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_41, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_42, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_43, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_44, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_45, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_46, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_47, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_48, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_49, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_50, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_51, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_52, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_53, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_54, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_55, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_56, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_57, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_58, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_59, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_60, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_61, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_62, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_63, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_64, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY, HID_QUIRK_IGNORE },
 
 	{ 0, 0 }
 };
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 99c82b1..e8f44b5 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -29,17 +29,34 @@
 	default n
 
 config SENSORS_ABITUGURU
-	tristate "Abit uGuru"
+	tristate "Abit uGuru (rev 1 & 2)"
 	depends on EXPERIMENTAL
 	help
-	  If you say yes here you get support for the Abit uGuru chips
-	  sensor part. The voltage and frequency control parts of the Abit
-	  uGuru are not supported. The Abit uGuru chip can be found on Abit
-	  uGuru featuring motherboards (most modern Abit motherboards).
+	  If you say yes here you get support for the sensor part of the first
+	  and second revision of the Abit uGuru chip. The voltage and frequency
+	  control parts of the Abit uGuru are not supported. The Abit uGuru
+	  chip can be found on Abit uGuru featuring motherboards (most modern
+	  Abit motherboards from before end 2005). For more info and a list
+	  of which motherboards have which revision see
+	  Documentation/hwmon/abituguru
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called abituguru.
 
+config SENSORS_ABITUGURU3
+	tristate "Abit uGuru (rev 3)"
+	depends on HWMON && EXPERIMENTAL
+	help
+	  If you say yes here you get support for the sensor part of the
+	  third revision of the Abit uGuru chip. Only reading the sensors
+	  and their settings is supported. The third revision of the Abit
+	  uGuru chip can be found on recent Abit motherboards (since end
+	  2005). For more info and a list of which motherboards have which
+	  revision see Documentation/hwmon/abituguru3
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called abituguru3.
+
 config SENSORS_AD7418
 	tristate "Analog Devices AD7416, AD7417 and AD7418"
 	depends on I2C && EXPERIMENTAL
@@ -251,12 +268,10 @@
 
 config SENSORS_IT87
 	tristate "ITE IT87xx and compatibles"
-	depends on I2C
-	select I2C_ISA
 	select HWMON_VID
 	help
 	  If you say yes here you get support for ITE IT8705F, IT8712F,
-	  IT8716F and IT8718F sensor chips, and the SiS960 clone.
+	  IT8716F, IT8718F and IT8726F sensor chips, and the SiS960 clone.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called it87.
@@ -366,8 +381,8 @@
 	depends on I2C
 	help
 	  If you say yes here you get support for National Semiconductor LM90,
-	  LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and
-	  MAX6658 sensor chips.
+	  LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657,
+	  MAX6658, MAX6659, MAX6680 and MAX6681 sensor chips.
 
 	  The Analog Devices ADT7461 sensor chip is also supported, but only
 	  if found in ADM1032 compatibility mode.
@@ -385,6 +400,17 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called lm92.
 
+config SENSORS_LM93
+	tristate "National Semiconductor LM93 and compatibles"
+	depends on HWMON && I2C
+	select HWMON_VID
+	help
+	  If you say yes here you get support for National Semiconductor LM93
+	  sensor chips.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called lm93.
+
 config SENSORS_MAX1619
 	tristate "Maxim MAX1619 sensor chip"
 	depends on I2C
@@ -406,8 +432,6 @@
 
 config SENSORS_PC87360
 	tristate "National Semiconductor PC87360 family"
-	depends on I2C && EXPERIMENTAL
-	select I2C_ISA
 	select HWMON_VID
 	help
 	  If you say yes here you get access to the hardware monitoring
@@ -434,8 +458,7 @@
 
 config SENSORS_SIS5595
 	tristate "Silicon Integrated Systems Corp. SiS5595"
-	depends on I2C && PCI && EXPERIMENTAL
-	select I2C_ISA
+	depends on PCI
 	help
 	  If you say yes here you get support for the integrated sensors in
 	  SiS5595 South Bridges.
@@ -443,6 +466,18 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called sis5595.
 
+config SENSORS_DME1737
+	tristate "SMSC DME1737 and compatibles"
+	depends on I2C && EXPERIMENTAL
+	select HWMON_VID
+	help
+	  If you say yes here you get support for the hardware monitoring
+	  and fan control features of the SMSC DME1737 (and compatibles
+	  like the Asus A8000) Super-I/O chip.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called dme1737.
+
 config SENSORS_SMSC47M1
 	tristate "SMSC LPC47M10x and compatibles"
 	help
@@ -486,10 +521,19 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called smsc47b397.
 
+config SENSORS_THMC50
+	tristate "Texas Instruments THMC50 / Analog Devices ADM1022"
+	depends on I2C && EXPERIMENTAL
+	help
+	  If you say yes here you get support for Texas Instruments THMC50
+	  sensor chips and clones: the Analog Devices ADM1022.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called thmc50.
+
 config SENSORS_VIA686A
 	tristate "VIA686A"
-	depends on I2C && PCI
-	select I2C_ISA
+	depends on PCI
 	help
 	  If you say yes here you get support for the integrated sensors in
 	  Via 686A/B South Bridges.
@@ -510,9 +554,8 @@
 
 config SENSORS_VT8231
 	tristate "VIA VT8231"
-	depends on I2C && PCI && EXPERIMENTAL
+	depends on PCI
 	select HWMON_VID
-	select I2C_ISA
 	help
 	  If you say yes here then you get support for the integrated sensors
 	  in the VIA VT8231 device.
@@ -585,17 +628,16 @@
 	  will be called w83627hf.
 
 config SENSORS_W83627EHF
-	tristate "Winbond W83627EHF"
-	depends on I2C && EXPERIMENTAL
-	select I2C_ISA
+	tristate "Winbond W83627EHF/DHG"
+	select HWMON_VID
 	help
-	  If you say yes here you get preliminary support for the hardware
+	  If you say yes here you get support for the hardware
 	  monitoring functionality of the Winbond W83627EHF Super-I/O chip.
-	  Only fan and temperature inputs are supported at the moment, while
-	  the chip does much more than that.
 
 	  This driver also supports the W83627EHG, which is the lead-free
-	  version of the W83627EHF.
+	  version of the W83627EHF, and the W83627DHG, which is a similar
+	  chip suited for specific Intel processors that use PECI such as
+	  the Core 2 Duo.
 
 	  This driver can also be built as a module.  If so, the module
 	  will be called w83627ehf.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index cfaf338..d04f900 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -14,6 +14,7 @@
 obj-$(CONFIG_SENSORS_W83791D)	+= w83791d.o
 
 obj-$(CONFIG_SENSORS_ABITUGURU)	+= abituguru.o
+obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
 obj-$(CONFIG_SENSORS_AD7418)	+= ad7418.o
 obj-$(CONFIG_SENSORS_ADM1021)	+= adm1021.o
 obj-$(CONFIG_SENSORS_ADM1025)	+= adm1025.o
@@ -25,6 +26,7 @@
 obj-$(CONFIG_SENSORS_AMS)	+= ams/
 obj-$(CONFIG_SENSORS_ATXP1)	+= atxp1.o
 obj-$(CONFIG_SENSORS_CORETEMP)	+= coretemp.o
+obj-$(CONFIG_SENSORS_DME1737)	+= dme1737.o
 obj-$(CONFIG_SENSORS_DS1621)	+= ds1621.o
 obj-$(CONFIG_SENSORS_F71805F)	+= f71805f.o
 obj-$(CONFIG_SENSORS_FSCHER)	+= fscher.o
@@ -45,6 +47,7 @@
 obj-$(CONFIG_SENSORS_LM87)	+= lm87.o
 obj-$(CONFIG_SENSORS_LM90)	+= lm90.o
 obj-$(CONFIG_SENSORS_LM92)	+= lm92.o
+obj-$(CONFIG_SENSORS_LM93)	+= lm93.o
 obj-$(CONFIG_SENSORS_MAX1619)	+= max1619.o
 obj-$(CONFIG_SENSORS_MAX6650)	+= max6650.o
 obj-$(CONFIG_SENSORS_PC87360)	+= pc87360.o
@@ -53,6 +56,7 @@
 obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
 obj-$(CONFIG_SENSORS_SMSC47M1)	+= smsc47m1.o
 obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
+obj-$(CONFIG_SENSORS_THMC50)	+= thmc50.o
 obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
 obj-$(CONFIG_SENSORS_VT1211)	+= vt1211.o
 obj-$(CONFIG_SENSORS_VT8231)	+= vt8231.o
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
index bede4d9..2317f4b 100644
--- a/drivers/hwmon/abituguru.c
+++ b/drivers/hwmon/abituguru.c
@@ -16,9 +16,9 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 /*
-    This driver supports the sensor part of the custom Abit uGuru chip found
-    on Abit uGuru motherboards. Note: because of lack of specs the CPU / RAM /
-    etc voltage & frequency control is not supported!
+    This driver supports the sensor part of the first and second revision of
+    the custom Abit uGuru chip found on Abit uGuru motherboards. Note: because
+    of lack of specs the CPU/RAM voltage & frequency control is not supported!
 */
 #include <linux/module.h>
 #include <linux/sched.h>
@@ -31,6 +31,7 @@
 #include <linux/platform_device.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
+#include <linux/dmi.h>
 #include <asm/io.h>
 
 /* Banks */
@@ -418,7 +419,7 @@
 abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
 				   u8 sensor_addr)
 {
-	u8 val, buf[3];
+	u8 val, test_flag, buf[3];
 	int i, ret = -ENODEV; /* error is the most common used retval :| */
 
 	/* If overriden by the user return the user selected type */
@@ -436,7 +437,7 @@
 		return -ENODEV;
 
 	/* Test val is sane / usable for sensor type detection. */
-	if ((val < 10u) || (val > 240u)) {
+	if ((val < 10u) || (val > 250u)) {
 		printk(KERN_WARNING ABIT_UGURU_NAME
 			": bank1-sensor: %d reading (%d) too close to limits, "
 			"unable to determine sensor type, skipping sensor\n",
@@ -449,10 +450,20 @@
 
 	ABIT_UGURU_DEBUG(2, "testing bank1 sensor %d\n", (int)sensor_addr);
 	/* Volt sensor test, enable volt low alarm, set min value ridicously
-	   high. If its a volt sensor this should always give us an alarm. */
-	buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE;
-	buf[1] = 245;
-	buf[2] = 250;
+	   high, or vica versa if the reading is very high. If its a volt
+	   sensor this should always give us an alarm. */
+	if (val <= 240u) {
+		buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE;
+		buf[1] = 245;
+		buf[2] = 250;
+		test_flag = ABIT_UGURU_VOLT_LOW_ALARM_FLAG;
+	} else {
+		buf[0] = ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE;
+		buf[1] = 5;
+		buf[2] = 10;
+		test_flag = ABIT_UGURU_VOLT_HIGH_ALARM_FLAG;
+	}
+
 	if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
 			buf, 3) != 3)
 		goto abituguru_detect_bank1_sensor_type_exit;
@@ -469,13 +480,13 @@
 				sensor_addr, buf, 3,
 				ABIT_UGURU_MAX_RETRIES) != 3)
 			goto abituguru_detect_bank1_sensor_type_exit;
-		if (buf[0] & ABIT_UGURU_VOLT_LOW_ALARM_FLAG) {
+		if (buf[0] & test_flag) {
 			ABIT_UGURU_DEBUG(2, "  found volt sensor\n");
 			ret = ABIT_UGURU_IN_SENSOR;
 			goto abituguru_detect_bank1_sensor_type_exit;
 		} else
 			ABIT_UGURU_DEBUG(2, "  alarm raised during volt "
-				"sensor test, but volt low flag not set\n");
+				"sensor test, but volt range flag not set\n");
 	} else
 		ABIT_UGURU_DEBUG(2, "  alarm not raised during volt sensor "
 			"test\n");
@@ -1287,6 +1298,7 @@
 	for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
 		device_remove_file(&pdev->dev,
 			&abituguru_sysfs_attr[i].dev_attr);
+	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 	return res;
 }
@@ -1296,13 +1308,13 @@
 	int i;
 	struct abituguru_data *data = platform_get_drvdata(pdev);
 
-	platform_set_drvdata(pdev, NULL);
 	hwmon_device_unregister(data->class_dev);
 	for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
 		device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
 	for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
 		device_remove_file(&pdev->dev,
 			&abituguru_sysfs_attr[i].dev_attr);
+	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 
 	return 0;
@@ -1436,6 +1448,15 @@
 	int address, err;
 	struct resource res = { .flags = IORESOURCE_IO };
 
+#ifdef CONFIG_DMI
+	const char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
+
+	/* safety check, refuse to load on non Abit motherboards */
+	if (!force && (!board_vendor ||
+			strcmp(board_vendor, "http://www.abit.com.tw/")))
+		return -ENODEV;
+#endif
+
 	address = abituguru_detect();
 	if (address < 0)
 		return address;
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
new file mode 100644
index 0000000..cdd8b6d
--- /dev/null
+++ b/drivers/hwmon/abituguru3.c
@@ -0,0 +1,1141 @@
+/*
+    abituguru3.c Copyright (c) 2006 Hans de Goede <j.w.r.degoede@hhs.nl>
+
+    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.
+*/
+/*
+    This driver supports the sensor part of revision 3 of the custom Abit uGuru
+    chip found on newer Abit uGuru motherboards. Note: because of lack of specs
+    only reading the sensors and their settings is supported.
+*/
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/mutex.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <asm/io.h>
+
+/* uGuru3 bank addresses */
+#define ABIT_UGURU3_SETTINGS_BANK		0x01
+#define ABIT_UGURU3_SENSORS_BANK		0x08
+#define ABIT_UGURU3_MISC_BANK			0x09
+#define ABIT_UGURU3_ALARMS_START		0x1E
+#define ABIT_UGURU3_SETTINGS_START		0x24
+#define ABIT_UGURU3_VALUES_START		0x80
+#define ABIT_UGURU3_BOARD_ID			0x0A
+/* uGuru3 sensor bank flags */			     /* Alarm if: */
+#define ABIT_UGURU3_TEMP_HIGH_ALARM_ENABLE	0x01 /*  temp over warn */
+#define ABIT_UGURU3_VOLT_HIGH_ALARM_ENABLE	0x02 /*  volt over max */
+#define ABIT_UGURU3_VOLT_LOW_ALARM_ENABLE	0x04 /*  volt under min */
+#define ABIT_UGURU3_TEMP_HIGH_ALARM_FLAG	0x10 /* temp is over warn */
+#define ABIT_UGURU3_VOLT_HIGH_ALARM_FLAG	0x20 /* volt is over max */
+#define ABIT_UGURU3_VOLT_LOW_ALARM_FLAG		0x40 /* volt is under min */
+#define ABIT_UGURU3_FAN_LOW_ALARM_ENABLE	0x01 /*   fan under min */
+#define ABIT_UGURU3_BEEP_ENABLE			0x08 /* beep if alarm */
+#define ABIT_UGURU3_SHUTDOWN_ENABLE		0x80 /* shutdown if alarm */
+/* sensor types */
+#define ABIT_UGURU3_IN_SENSOR			0
+#define ABIT_UGURU3_TEMP_SENSOR			1
+#define ABIT_UGURU3_FAN_SENSOR			2
+
+/* Timeouts / Retries, if these turn out to need a lot of fiddling we could
+   convert them to params. Determined by trial and error. I assume this is
+   cpu-speed independent, since the ISA-bus and not the CPU should be the
+   bottleneck. */
+#define ABIT_UGURU3_WAIT_TIMEOUT		250
+/* Normally the 0xAC at the end of synchronize() is reported after the
+   first read, but sometimes not and we need to poll */
+#define ABIT_UGURU3_SYNCHRONIZE_TIMEOUT		5
+/* utility macros */
+#define ABIT_UGURU3_NAME			"abituguru3"
+#define ABIT_UGURU3_DEBUG(format, arg...)	\
+	if (verbose)				\
+		printk(KERN_DEBUG ABIT_UGURU3_NAME ": "	format , ## arg)
+
+/* Macros to help calculate the sysfs_names array length */
+#define ABIT_UGURU3_MAX_NO_SENSORS 26
+/* sum of strlen +1 of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0,
+   in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0, in??_label\0 */
+#define ABIT_UGURU3_IN_NAMES_LENGTH (11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14 + 11)
+/* sum of strlen +1 of: temp??_input\0, temp??_max\0, temp??_crit\0,
+   temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0,
+   temp??_label\0 */
+#define ABIT_UGURU3_TEMP_NAMES_LENGTH (13 + 11 + 12 + 13 + 20 + 12 + 16 + 13)
+/* sum of strlen +1 of: fan??_input\0, fan??_min\0, fan??_alarm\0,
+   fan??_alarm_enable\0, fan??_beep\0, fan??_shutdown\0, fan??_label\0 */
+#define ABIT_UGURU3_FAN_NAMES_LENGTH (12 + 10 + 12 + 19 + 11 + 15 + 12)
+/* Worst case scenario 16 in sensors (longest names_length) and the rest
+   temp sensors (second longest names_length). */
+#define ABIT_UGURU3_SYSFS_NAMES_LENGTH (16 * ABIT_UGURU3_IN_NAMES_LENGTH + \
+	(ABIT_UGURU3_MAX_NO_SENSORS - 16) * ABIT_UGURU3_TEMP_NAMES_LENGTH)
+
+/* All the macros below are named identical to the openguru2 program
+   reverse engineered by Louis Kruger, hence the names might not be 100%
+   logical. I could come up with better names, but I prefer keeping the names
+   identical so that this driver can be compared with his work more easily. */
+/* Two i/o-ports are used by uGuru */
+#define ABIT_UGURU3_BASE			0x00E0
+#define ABIT_UGURU3_CMD				0x00
+#define ABIT_UGURU3_DATA			0x04
+#define ABIT_UGURU3_REGION_LENGTH		5
+/* The wait_xxx functions return this on success and the last contents
+   of the DATA register (0-255) on failure. */
+#define ABIT_UGURU3_SUCCESS			-1
+/* uGuru status flags */
+#define ABIT_UGURU3_STATUS_READY_FOR_READ	0x01
+#define ABIT_UGURU3_STATUS_BUSY			0x02
+
+
+/* Structures */
+struct abituguru3_sensor_info {
+	const char* name;
+	int port;
+	int type;
+	int multiplier;
+	int divisor;
+	int offset;
+};
+
+struct abituguru3_motherboard_info {
+	u16 id;
+	const char *name;
+	/* + 1 -> end of sensors indicated by a sensor with name == NULL */
+	struct abituguru3_sensor_info sensors[ABIT_UGURU3_MAX_NO_SENSORS + 1];
+};
+
+/* For the Abit uGuru, we need to keep some data in memory.
+   The structure is dynamically allocated, at the same time when a new
+   abituguru3 device is allocated. */
+struct abituguru3_data {
+	struct class_device *class_dev; /* hwmon registered device */
+	struct mutex update_lock;	/* protect access to data and uGuru */
+	unsigned short addr;		/* uguru base address */
+	char valid;			/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+
+	/* For convenience the sysfs attr and their names are generated
+	   automatically. We have max 10 entries per sensor (for in sensors) */
+	struct sensor_device_attribute_2 sysfs_attr[ABIT_UGURU3_MAX_NO_SENSORS
+		* 10];
+
+	/* Buffer to store the dynamically generated sysfs names */
+	char sysfs_names[ABIT_UGURU3_SYSFS_NAMES_LENGTH];
+
+	/* Pointer to the sensors info for the detected motherboard */
+	const struct abituguru3_sensor_info *sensors;
+
+	/* The abituguru3 supports upto 48 sensors, and thus has registers
+	   sets for 48 sensors, for convienence reasons / simplicity of the
+	   code we always read and store all registers for all 48 sensors */
+
+	/* Alarms for all 48 sensors (1 bit per sensor) */
+	u8 alarms[48/8];
+
+	/* Value of all 48 sensors */
+	u8 value[48];
+
+	/* Settings of all 48 sensors, note in and temp sensors (the first 32
+	   sensors) have 3 bytes of settings, while fans only have 2 bytes,
+	   for convenience we use 3 bytes for all sensors */
+	u8 settings[48][3];
+};
+
+
+/* Constants */
+static const struct abituguru3_motherboard_info abituguru3_motherboards[] = {
+	{ 0x000C, "unknown", {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 10, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "MCH & PCIE 1.5V",	 4, 0, 10, 1, 0 },
+		{ "MCH 2.5V",		 5, 0, 20, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System ",		25, 1, 1, 1, 0 },
+		{ "PWM",		26, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS FAN",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		35, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x000D, "Abit AW8", {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 10, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "MCH & PCIE 1.5V",	 4, 0, 10, 1, 0 },
+		{ "MCH 2.5V",		 5, 0, 20, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System ",		25, 1, 1, 1, 0 },
+		{ "PWM1",		26, 1, 1, 1, 0 },
+		{ "PWM2",		27, 1, 1, 1, 0 },
+		{ "PWM3",		28, 1, 1, 1, 0 },
+		{ "PWM4",		29, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		36, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		37, 2, 60, 1, 0 },
+		{ "AUX4 Fan",		38, 2, 60, 1, 0 },
+		{ "AUX5 Fan",		39, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x000E, "AL-8", {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 10, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "MCH & PCIE 1.5V",	 4, 0, 10, 1, 0 },
+		{ "MCH 2.5V",		 5, 0, 20, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System ",		25, 1, 1, 1, 0 },
+		{ "PWM",		26, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x000F, "unknown", {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 10, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "MCH & PCIE 1.5V",	 4, 0, 10, 1, 0 },
+		{ "MCH 2.5V",		 5, 0, 20, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System ",		25, 1, 1, 1, 0 },
+		{ "PWM",		26, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0010, "Abit NI8 SLI GR", {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 10, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "NB 1.4V",		 4, 0, 10, 1, 0 },
+		{ "SB 1.5V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "SYS",		25, 1, 1, 1, 0 },
+		{ "PWM",		26, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		35, 2, 60, 1, 0 },
+		{ "OTES1 Fan",		36, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0011, "Abit AT8 32X", {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 20, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VDDA 2.5V",	 6, 0, 20, 1, 0 },
+		{ "NB 1.8V",		 4, 0, 10, 1, 0 },
+		{ "NB 1.8V Dual",	 5, 0, 10, 1, 0 },
+		{ "HTV 1.2",		 3, 0, 10, 1, 0 },
+		{ "PCIE 1.2V",		12, 0, 10, 1, 0 },
+		{ "NB 1.2V",		13, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "NB",			25, 1, 1, 1, 0 },
+		{ "System",		26, 1, 1, 1, 0 },
+		{ "PWM",		27, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		36, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0012, "Abit AN8 32X", {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 20, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "HyperTransport",	 3, 0, 10, 1, 0 },
+		{ "CPU VDDA 2.5V",	 5, 0, 20, 1, 0 },
+		{ "NB",			 4, 0, 10, 1, 0 },
+		{ "SB",			 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "SYS",		25, 1, 1, 1, 0 },
+		{ "PWM",		26, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		36, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0013, "unknown", {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 10, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "MCH & PCIE 1.5V",	 4, 0, 10, 1, 0 },
+		{ "MCH 2.5V",		 5, 0, 20, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System ",		25, 1, 1, 1, 0 },
+		{ "PWM1",		26, 1, 1, 1, 0 },
+		{ "PWM2",		27, 1, 1, 1, 0 },
+		{ "PWM3",		28, 1, 1, 1, 0 },
+		{ "PWM4",		29, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		36, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		37, 2, 60, 1, 0 },
+		{ "AUX4 Fan",		38, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0014, "Abit AB9 Pro", {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 10, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "MCH & PCIE 1.5V",	 4, 0, 10, 1, 0 },
+		{ "MCH 2.5V",		 5, 0, 20, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System ",		25, 1, 1, 1, 0 },
+		{ "PWM",		26, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0015, "unknown", {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR",		 1, 0, 20, 1, 0 },
+		{ "DDR VTT",		 2, 0, 10, 1, 0 },
+		{ "HyperTransport",	 3, 0, 10, 1, 0 },
+		{ "CPU VDDA 2.5V",	 5, 0, 20, 1, 0 },
+		{ "NB",			 4, 0, 10, 1, 0 },
+		{ "SB",			 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "SYS",		25, 1, 1, 1, 0 },
+		{ "PWM",		26, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		33, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		36, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0016, "AW9D-MAX", {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR2",		 1, 0, 20, 1, 0 },
+		{ "DDR2 VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "MCH & PCIE 1.5V",	 4, 0, 10, 1, 0 },
+		{ "MCH 2.5V",		 5, 0, 20, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System ",		25, 1, 1, 1, 0 },
+		{ "PWM1",		26, 1, 1, 1, 0 },
+		{ "PWM2",		27, 1, 1, 1, 0 },
+		{ "PWM3",		28, 1, 1, 1, 0 },
+		{ "PWM4",		29, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "NB Fan",		33, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		36, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		37, 2, 60, 1, 0 },
+		{ "OTES1 Fan",		38, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0017, "unknown", {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR2",		 1, 0, 20, 1, 0 },
+		{ "DDR2 VTT",		 2, 0, 10, 1, 0 },
+		{ "HyperTransport",	 3, 0, 10, 1, 0 },
+		{ "CPU VDDA 2.5V",	 6, 0, 20, 1, 0 },
+		{ "NB 1.8V",		 4, 0, 10, 1, 0 },
+		{ "NB 1.2V ",		13, 0, 10, 1, 0 },
+		{ "SB 1.2V",		 5, 0, 10, 1, 0 },
+		{ "PCIE 1.2V",		12, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "ATX +3.3V",		10, 0, 20, 1, 0 },
+		{ "ATX 5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System ",		26, 1, 1, 1, 0 },
+		{ "PWM",		27, 1, 1, 1, 0 },
+		{ "CPU FAN",		32, 2, 60, 1, 0 },
+		{ "SYS FAN",		34, 2, 60, 1, 0 },
+		{ "AUX1 FAN",		35, 2, 60, 1, 0 },
+		{ "AUX2 FAN",		36, 2, 60, 1, 0 },
+		{ "AUX3 FAN",		37, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0018, "unknown", {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR2",		 1, 0, 20, 1, 0 },
+		{ "DDR2 VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT",		 3, 0, 10, 1, 0 },
+		{ "MCH 1.25V",		 4, 0, 10, 1, 0 },
+		{ "ICHIO 1.5V",		 5, 0, 10, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System ",		25, 1, 1, 1, 0 },
+		{ "PWM Phase1",		26, 1, 1, 1, 0 },
+		{ "PWM Phase2",		27, 1, 1, 1, 0 },
+		{ "PWM Phase3",		28, 1, 1, 1, 0 },
+		{ "PWM Phase4",		29, 1, 1, 1, 0 },
+		{ "PWM Phase5",		30, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		33, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		36, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0019, "unknown", {
+		{ "CPU Core",		 7, 0, 10, 1, 0 },
+		{ "DDR2",		13, 0, 20, 1, 0 },
+		{ "DDR2 VTT",		14, 0, 10, 1, 0 },
+		{ "CPU VTT",		 3, 0, 20, 1, 0 },
+		{ "NB 1.2V ",		 4, 0, 10, 1, 0 },
+		{ "SB 1.5V",		 6, 0, 10, 1, 0 },
+		{ "HyperTransport",	 5, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	12, 0, 60, 1, 0 },
+		{ "ATX +12V (4-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "ATX +3.3V",		10, 0, 20, 1, 0 },
+		{ "ATX 5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System ",		25, 1, 1, 1, 0 },
+		{ "PWM Phase1",		26, 1, 1, 1, 0 },
+		{ "PWM Phase2",		27, 1, 1, 1, 0 },
+		{ "PWM Phase3",		28, 1, 1, 1, 0 },
+		{ "PWM Phase4",		29, 1, 1, 1, 0 },
+		{ "PWM Phase5",		30, 1, 1, 1, 0 },
+		{ "CPU FAN",		32, 2, 60, 1, 0 },
+		{ "SYS FAN",		34, 2, 60, 1, 0 },
+		{ "AUX1 FAN",		33, 2, 60, 1, 0 },
+		{ "AUX2 FAN",		35, 2, 60, 1, 0 },
+		{ "AUX3 FAN",		36, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x001A, "unknown", {
+		{ "CPU Core",		 0, 0, 10, 1, 0 },
+		{ "DDR2",		 1, 0, 20, 1, 0 },
+		{ "DDR2 VTT",		 2, 0, 10, 1, 0 },
+		{ "CPU VTT 1.2V",	 3, 0, 10, 1, 0 },
+		{ "MCH 1.25V",		 4, 0, 10, 1, 0 },
+		{ "ICHIO 1.5V",		 5, 0, 10, 1, 0 },
+		{ "ICH 1.05V",		 6, 0, 10, 1, 0 },
+		{ "ATX +12V (24-Pin)",	 7, 0, 60, 1, 0 },
+		{ "ATX +12V (8-pin)",	 8, 0, 60, 1, 0 },
+		{ "ATX +5V",		 9, 0, 30, 1, 0 },
+		{ "+3.3V",		10, 0, 20, 1, 0 },
+		{ "5VSB",		11, 0, 30, 1, 0 },
+		{ "CPU",		24, 1, 1, 1, 0 },
+		{ "System ",		25, 1, 1, 1, 0 },
+		{ "PWM ",		26, 1, 1, 1, 0 },
+		{ "PWM Phase2",		27, 1, 1, 1, 0 },
+		{ "PWM Phase3",		28, 1, 1, 1, 0 },
+		{ "PWM Phase4",		29, 1, 1, 1, 0 },
+		{ "PWM Phase5",		30, 1, 1, 1, 0 },
+		{ "CPU Fan",		32, 2, 60, 1, 0 },
+		{ "SYS Fan",		34, 2, 60, 1, 0 },
+		{ "AUX1 Fan",		33, 2, 60, 1, 0 },
+		{ "AUX2 Fan",		35, 2, 60, 1, 0 },
+		{ "AUX3 Fan",		36, 2, 60, 1, 0 },
+		{ NULL, 0, 0, 0, 0, 0 } }
+	},
+	{ 0x0000, NULL, { { NULL, 0, 0, 0, 0, 0 } } }
+};
+
+
+/* Insmod parameters */
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Set to one to force detection.");
+/* Default verbose is 1, since this driver is still in the testing phase */
+static int verbose = 1;
+module_param(verbose, bool, 0644);
+MODULE_PARM_DESC(verbose, "Enable/disable verbose error reporting");
+
+
+/* wait while the uguru is busy (usually after a write) */
+static int abituguru3_wait_while_busy(struct abituguru3_data *data)
+{
+	u8 x;
+	int timeout = ABIT_UGURU3_WAIT_TIMEOUT;
+
+	while ((x = inb_p(data->addr + ABIT_UGURU3_DATA)) &
+			ABIT_UGURU3_STATUS_BUSY) {
+		timeout--;
+		if (timeout == 0)
+			return x;
+		/* sleep a bit before our last try, to give the uGuru3 one
+		   last chance to respond. */
+		if (timeout == 1)
+			msleep(1);
+	}
+	return ABIT_UGURU3_SUCCESS;
+}
+
+/* wait till uguru is ready to be read */
+static int abituguru3_wait_for_read(struct abituguru3_data *data)
+{
+	u8 x;
+	int timeout = ABIT_UGURU3_WAIT_TIMEOUT;
+
+	while (!((x = inb_p(data->addr + ABIT_UGURU3_DATA)) &
+			ABIT_UGURU3_STATUS_READY_FOR_READ)) {
+		timeout--;
+		if (timeout == 0)
+			return x;
+		/* sleep a bit before our last try, to give the uGuru3 one
+		   last chance to respond. */
+		if (timeout == 1)
+			msleep(1);
+	}
+	return ABIT_UGURU3_SUCCESS;
+}
+
+/* This synchronizes us with the uGuru3's protocol state machine, this
+   must be done before each command. */
+static int abituguru3_synchronize(struct abituguru3_data *data)
+{
+	int x, timeout = ABIT_UGURU3_SYNCHRONIZE_TIMEOUT;
+
+	if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("synchronize timeout during initial busy "
+			"wait, status: 0x%02x\n", x);
+		return -EIO;
+	}
+
+	outb(0x20, data->addr + ABIT_UGURU3_DATA);
+	if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x20, "
+			"status: 0x%02x\n", x);
+		return -EIO;
+	}
+
+	outb(0x10, data->addr + ABIT_UGURU3_CMD);
+	if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x10, "
+			"status: 0x%02x\n", x);
+		return -EIO;
+	}
+
+	outb(0x00, data->addr + ABIT_UGURU3_CMD);
+	if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("synchronize timeout after sending 0x00, "
+			"status: 0x%02x\n", x);
+		return -EIO;
+	}
+
+	if ((x = abituguru3_wait_for_read(data)) != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("synchronize timeout waiting for read, "
+			"status: 0x%02x\n", x);
+		return -EIO;
+	}
+
+	while ((x = inb(data->addr + ABIT_UGURU3_CMD)) != 0xAC) {
+		timeout--;
+		if (timeout == 0) {
+			ABIT_UGURU3_DEBUG("synchronize timeout cmd does not "
+				"hold 0xAC after synchronize, cmd: 0x%02x\n",
+				x);
+			return -EIO;
+		}
+		msleep(1);
+	}
+	return 0;
+}
+
+/* Read count bytes from sensor sensor_addr in bank bank_addr and store the
+   result in buf */
+static int abituguru3_read(struct abituguru3_data *data, u8 bank, u8 offset,
+	u8 count, u8 *buf)
+{
+	int i, x;
+
+	if ((x = abituguru3_synchronize(data)))
+		return x;
+
+	outb(0x1A, data->addr + ABIT_UGURU3_DATA);
+	if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+			"sending 0x1A, status: 0x%02x\n", (unsigned int)bank,
+			(unsigned int)offset, x);
+		return -EIO;
+	}
+
+	outb(bank, data->addr + ABIT_UGURU3_CMD);
+	if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+			"sending the bank, status: 0x%02x\n",
+			(unsigned int)bank, (unsigned int)offset, x);
+		return -EIO;
+	}
+
+	outb(offset, data->addr + ABIT_UGURU3_CMD);
+	if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+			"sending the offset, status: 0x%02x\n",
+			(unsigned int)bank, (unsigned int)offset, x);
+		return -EIO;
+	}
+
+	outb(count, data->addr + ABIT_UGURU3_CMD);
+	if ((x = abituguru3_wait_while_busy(data)) != ABIT_UGURU3_SUCCESS) {
+		ABIT_UGURU3_DEBUG("read from 0x%02x:0x%02x timed out after "
+			"sending the count, status: 0x%02x\n",
+			(unsigned int)bank, (unsigned int)offset, x);
+		return -EIO;
+	}
+
+	for (i = 0; i < count; i++) {
+		if ((x = abituguru3_wait_for_read(data)) !=
+				ABIT_UGURU3_SUCCESS) {
+			ABIT_UGURU3_DEBUG("timeout reading byte %d from "
+				"0x%02x:0x%02x, status: 0x%02x\n", i,
+				(unsigned int)bank, (unsigned int)offset, x);
+			break;
+		}
+		buf[i] = inb(data->addr + ABIT_UGURU3_CMD);
+	}
+	return i;
+}
+
+/* Sensor settings are stored 1 byte per offset with the bytes
+   placed add consecutive offsets. */
+static int abituguru3_read_increment_offset(struct abituguru3_data *data,
+					    u8 bank, u8 offset, u8 count,
+					    u8 *buf, int offset_count)
+{
+	int i, x;
+
+	for (i = 0; i < offset_count; i++)
+		if ((x = abituguru3_read(data, bank, offset + i, count,
+				buf + i * count)) != count)
+			return i * count + (i && (x < 0)) ? 0 : x;
+
+	return i * count;
+}
+
+/* Following are the sysfs callback functions. These functions expect:
+   sensor_device_attribute_2->index:   index into the data->sensors array
+   sensor_device_attribute_2->nr:      register offset, bitmask or NA. */
+static struct abituguru3_data *abituguru3_update_device(struct device *dev);
+
+static ssize_t show_value(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	int value;
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru3_data *data = abituguru3_update_device(dev);
+	const struct abituguru3_sensor_info *sensor;
+
+	if (!data)
+		return -EIO;
+
+	sensor = &data->sensors[attr->index];
+
+	/* are we reading a setting, or is this a normal read? */
+	if (attr->nr)
+		value = data->settings[sensor->port][attr->nr];
+	else
+		value = data->value[sensor->port];
+
+	/* convert the value */
+	value = (value * sensor->multiplier) / sensor->divisor +
+		sensor->offset;
+
+	/* alternatively we could update the sensors settings struct for this,
+	   but then its contents would differ from the windows sw ini files */
+	if (sensor->type == ABIT_UGURU3_TEMP_SENSOR)
+		value *= 1000;
+
+	return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t show_alarm(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	int port;
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru3_data *data = abituguru3_update_device(dev);
+
+	if (!data)
+		return -EIO;
+
+	port = data->sensors[attr->index].port;
+
+	/* See if the alarm bit for this sensor is set and if a bitmask is
+	   given in attr->nr also check if the alarm matches the type of alarm
+	   we're looking for (for volt it can be either low or high). The type
+	   is stored in a few readonly bits in the settings of the sensor. */
+	if ((data->alarms[port / 8] & (0x01 << (port % 8))) &&
+			(!attr->nr || (data->settings[port][0] & attr->nr)))
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t show_mask(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru3_data *data = dev_get_drvdata(dev);
+
+	if (data->settings[data->sensors[attr->index].port][0] & attr->nr)
+		return sprintf(buf, "1\n");
+	else
+		return sprintf(buf, "0\n");
+}
+
+static ssize_t show_label(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	struct abituguru3_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->sensors[attr->index].name);
+}
+
+static ssize_t show_name(struct device *dev,
+	struct device_attribute *devattr, char *buf)
+{
+	return sprintf(buf, "%s\n", ABIT_UGURU3_NAME);
+}
+
+/* Sysfs attr templates, the real entries are generated automatically. */
+static const
+struct sensor_device_attribute_2 abituguru3_sysfs_templ[3][10] = { {
+	SENSOR_ATTR_2(in%d_input, 0444, show_value, NULL, 0, 0),
+	SENSOR_ATTR_2(in%d_min, 0444, show_value, NULL, 1, 0),
+	SENSOR_ATTR_2(in%d_max, 0444, show_value, NULL, 2, 0),
+	SENSOR_ATTR_2(in%d_min_alarm, 0444, show_alarm, NULL,
+		ABIT_UGURU3_VOLT_LOW_ALARM_FLAG, 0),
+	SENSOR_ATTR_2(in%d_max_alarm, 0444, show_alarm, NULL,
+		ABIT_UGURU3_VOLT_HIGH_ALARM_FLAG, 0),
+	SENSOR_ATTR_2(in%d_beep, 0444, show_mask, NULL,
+		ABIT_UGURU3_BEEP_ENABLE, 0),
+	SENSOR_ATTR_2(in%d_shutdown, 0444, show_mask, NULL,
+		ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
+	SENSOR_ATTR_2(in%d_min_alarm_enable, 0444, show_mask, NULL,
+		ABIT_UGURU3_VOLT_LOW_ALARM_ENABLE, 0),
+	SENSOR_ATTR_2(in%d_max_alarm_enable, 0444, show_mask, NULL,
+		ABIT_UGURU3_VOLT_HIGH_ALARM_ENABLE, 0),
+	SENSOR_ATTR_2(in%d_label, 0444, show_label, NULL, 0, 0)
+	}, {
+	SENSOR_ATTR_2(temp%d_input, 0444, show_value, NULL, 0, 0),
+	SENSOR_ATTR_2(temp%d_max, 0444, show_value, NULL, 1, 0),
+	SENSOR_ATTR_2(temp%d_crit, 0444, show_value, NULL, 2, 0),
+	SENSOR_ATTR_2(temp%d_alarm, 0444, show_alarm, NULL, 0, 0),
+	SENSOR_ATTR_2(temp%d_beep, 0444, show_mask, NULL,
+		ABIT_UGURU3_BEEP_ENABLE, 0),
+	SENSOR_ATTR_2(temp%d_shutdown, 0444, show_mask, NULL,
+		ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
+	SENSOR_ATTR_2(temp%d_alarm_enable, 0444, show_mask, NULL,
+		ABIT_UGURU3_TEMP_HIGH_ALARM_ENABLE, 0),
+	SENSOR_ATTR_2(temp%d_label, 0444, show_label, NULL, 0, 0)
+	}, {
+	SENSOR_ATTR_2(fan%d_input, 0444, show_value, NULL, 0, 0),
+	SENSOR_ATTR_2(fan%d_min, 0444, show_value, NULL, 1, 0),
+	SENSOR_ATTR_2(fan%d_alarm, 0444, show_alarm, NULL, 0, 0),
+	SENSOR_ATTR_2(fan%d_beep, 0444, show_mask, NULL,
+		ABIT_UGURU3_BEEP_ENABLE, 0),
+	SENSOR_ATTR_2(fan%d_shutdown, 0444, show_mask, NULL,
+		ABIT_UGURU3_SHUTDOWN_ENABLE, 0),
+	SENSOR_ATTR_2(fan%d_alarm_enable, 0444, show_mask, NULL,
+		ABIT_UGURU3_FAN_LOW_ALARM_ENABLE, 0),
+	SENSOR_ATTR_2(fan%d_label, 0444, show_label, NULL, 0, 0)
+} };
+
+static struct sensor_device_attribute_2 abituguru3_sysfs_attr[] = {
+	SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0),
+};
+
+static int __devinit abituguru3_probe(struct platform_device *pdev)
+{
+	const int no_sysfs_attr[3] = { 10, 8, 7 };
+	int sensor_index[3] = { 0, 1, 1 };
+	struct abituguru3_data *data;
+	int i, j, type, used, sysfs_names_free, sysfs_attr_i, res = -ENODEV;
+	char *sysfs_filename;
+	u8 buf[2];
+	u16 id;
+
+	if (!(data = kzalloc(sizeof(struct abituguru3_data), GFP_KERNEL)))
+		return -ENOMEM;
+
+	data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start;
+	mutex_init(&data->update_lock);
+	platform_set_drvdata(pdev, data);
+
+	/* Read the motherboard ID */
+	if ((i = abituguru3_read(data, ABIT_UGURU3_MISC_BANK,
+			ABIT_UGURU3_BOARD_ID, 2, buf)) != 2) {
+		goto abituguru3_probe_error;
+	}
+
+	/* Completely read the uGuru to see if one really is there */
+	if (!abituguru3_update_device(&pdev->dev))
+		goto abituguru3_probe_error;
+
+	/* lookup the ID in our motherboard table */
+	id = ((u16)buf[0] << 8) | (u16)buf[1];
+	for (i = 0; abituguru3_motherboards[i].id; i++)
+		if (abituguru3_motherboards[i].id == id)
+			break;
+	if (!abituguru3_motherboards[i].id) {
+		printk(KERN_ERR ABIT_UGURU3_NAME ": error unknown motherboard "
+			"ID: %04X. Please report this to the abituguru3 "
+			"maintainer (see MAINTAINERS)\n", (unsigned int)id);
+		goto abituguru3_probe_error;
+	}
+	data->sensors = abituguru3_motherboards[i].sensors;
+	printk(KERN_INFO ABIT_UGURU3_NAME ": found Abit uGuru3, motherboard "
+		"ID: %04X (%s)\n", (unsigned int)id,
+		abituguru3_motherboards[i].name);
+
+	/* Fill the sysfs attr array */
+	sysfs_attr_i = 0;
+	sysfs_filename = data->sysfs_names;
+	sysfs_names_free = ABIT_UGURU3_SYSFS_NAMES_LENGTH;
+	for (i = 0; data->sensors[i].name; i++) {
+		/* Fail safe check, this should never happen! */
+		if (i >= ABIT_UGURU3_MAX_NO_SENSORS) {
+			printk(KERN_ERR ABIT_UGURU3_NAME
+				": Fatal error motherboard has more sensors "
+				"then ABIT_UGURU3_MAX_NO_SENSORS. This should "
+				"never happen please report to the abituguru3 "
+				"maintainer (see MAINTAINERS)\n");
+			res = -ENAMETOOLONG;
+			goto abituguru3_probe_error;
+		}
+		type = data->sensors[i].type;
+		for (j = 0; j < no_sysfs_attr[type]; j++) {
+			used = snprintf(sysfs_filename, sysfs_names_free,
+				abituguru3_sysfs_templ[type][j].dev_attr.attr.
+				name, sensor_index[type]) + 1;
+			data->sysfs_attr[sysfs_attr_i] =
+				abituguru3_sysfs_templ[type][j];
+			data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name =
+				sysfs_filename;
+			data->sysfs_attr[sysfs_attr_i].index = i;
+			sysfs_filename += used;
+			sysfs_names_free -= used;
+			sysfs_attr_i++;
+		}
+		sensor_index[type]++;
+	}
+	/* Fail safe check, this should never happen! */
+	if (sysfs_names_free < 0) {
+		printk(KERN_ERR ABIT_UGURU3_NAME
+			": Fatal error ran out of space for sysfs attr names. "
+			"This should never happen please report to the "
+			"abituguru3 maintainer (see MAINTAINERS)\n");
+		res = -ENAMETOOLONG;
+		goto abituguru3_probe_error;
+	}
+
+	/* Register sysfs hooks */
+	for (i = 0; i < sysfs_attr_i; i++)
+		if (device_create_file(&pdev->dev,
+				&data->sysfs_attr[i].dev_attr))
+			goto abituguru3_probe_error;
+	for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
+		if (device_create_file(&pdev->dev,
+				&abituguru3_sysfs_attr[i].dev_attr))
+			goto abituguru3_probe_error;
+
+	data->class_dev = hwmon_device_register(&pdev->dev);
+	if (IS_ERR(data->class_dev)) {
+		res = PTR_ERR(data->class_dev);
+		goto abituguru3_probe_error;
+	}
+
+	return 0; /* success */
+
+abituguru3_probe_error:
+	for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
+		device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+	for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
+		device_remove_file(&pdev->dev,
+			&abituguru3_sysfs_attr[i].dev_attr);
+	kfree(data);
+	return res;
+}
+
+static int __devexit abituguru3_remove(struct platform_device *pdev)
+{
+	int i;
+	struct abituguru3_data *data = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+	hwmon_device_unregister(data->class_dev);
+	for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++)
+		device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr);
+	for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
+		device_remove_file(&pdev->dev,
+			&abituguru3_sysfs_attr[i].dev_attr);
+	kfree(data);
+
+	return 0;
+}
+
+static struct abituguru3_data *abituguru3_update_device(struct device *dev)
+{
+	int i;
+	struct abituguru3_data *data = dev_get_drvdata(dev);
+
+	mutex_lock(&data->update_lock);
+	if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
+		/* Clear data->valid while updating */
+		data->valid = 0;
+		/* Read alarms */
+		if (abituguru3_read_increment_offset(data,
+				ABIT_UGURU3_SETTINGS_BANK,
+				ABIT_UGURU3_ALARMS_START,
+				1, data->alarms, 48/8) != (48/8))
+			goto LEAVE_UPDATE;
+		/* Read in and temp sensors (3 byte settings / sensor) */
+		for (i = 0; i < 32; i++) {
+			if (abituguru3_read(data, ABIT_UGURU3_SENSORS_BANK,
+					ABIT_UGURU3_VALUES_START + i,
+					1, &data->value[i]) != 1)
+				goto LEAVE_UPDATE;
+			if (abituguru3_read_increment_offset(data,
+					ABIT_UGURU3_SETTINGS_BANK,
+					ABIT_UGURU3_SETTINGS_START + i * 3,
+					1,
+					data->settings[i], 3) != 3)
+				goto LEAVE_UPDATE;
+		}
+		/* Read temp sensors (2 byte settings / sensor) */
+		for (i = 0; i < 16; i++) {
+			if (abituguru3_read(data, ABIT_UGURU3_SENSORS_BANK,
+					ABIT_UGURU3_VALUES_START + 32 + i,
+					1, &data->value[32 + i]) != 1)
+				goto LEAVE_UPDATE;
+			if (abituguru3_read_increment_offset(data,
+					ABIT_UGURU3_SETTINGS_BANK,
+					ABIT_UGURU3_SETTINGS_START + 32 * 3 +
+						i * 2, 1,
+					data->settings[32 + i], 2) != 2)
+				goto LEAVE_UPDATE;
+		}
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+LEAVE_UPDATE:
+	mutex_unlock(&data->update_lock);
+	if (data->valid)
+		return data;
+	else
+		return NULL;
+}
+
+#ifdef CONFIG_PM
+static int abituguru3_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct abituguru3_data *data = platform_get_drvdata(pdev);
+	/* make sure all communications with the uguru3 are done and no new
+	   ones are started */
+	mutex_lock(&data->update_lock);
+	return 0;
+}
+
+static int abituguru3_resume(struct platform_device *pdev)
+{
+	struct abituguru3_data *data = platform_get_drvdata(pdev);
+	mutex_unlock(&data->update_lock);
+	return 0;
+}
+#else
+#define abituguru3_suspend	NULL
+#define abituguru3_resume	NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver abituguru3_driver = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= ABIT_UGURU3_NAME,
+	},
+	.probe	= abituguru3_probe,
+	.remove	= __devexit_p(abituguru3_remove),
+	.suspend = abituguru3_suspend,
+	.resume = abituguru3_resume
+};
+
+static int __init abituguru3_detect(void)
+{
+	/* See if there is an uguru3 there. An idle uGuru3 will hold 0x00 or
+	   0x08 at DATA and 0xAC at CMD. Sometimes the uGuru3 will hold 0x05
+	   at CMD instead, why is unknown. So we test for 0x05 too. */
+	u8 data_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_DATA);
+	u8 cmd_val = inb_p(ABIT_UGURU3_BASE + ABIT_UGURU3_CMD);
+	if (((data_val == 0x00) || (data_val == 0x08)) &&
+			((cmd_val == 0xAC) || (cmd_val == 0x05)))
+		return ABIT_UGURU3_BASE;
+
+	ABIT_UGURU3_DEBUG("no Abit uGuru3 found, data = 0x%02X, cmd = "
+		"0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val);
+
+	if (force) {
+		printk(KERN_INFO ABIT_UGURU3_NAME ": Assuming Abit uGuru3 is "
+				"present because of \"force\" parameter\n");
+		return ABIT_UGURU3_BASE;
+	}
+
+	/* No uGuru3 found */
+	return -ENODEV;
+}
+
+static struct platform_device *abituguru3_pdev;
+
+static int __init abituguru3_init(void)
+{
+	int address, err;
+	struct resource res = { .flags = IORESOURCE_IO };
+
+	address = abituguru3_detect();
+	if (address < 0)
+		return address;
+
+	err = platform_driver_register(&abituguru3_driver);
+	if (err)
+		goto exit;
+
+	abituguru3_pdev = platform_device_alloc(ABIT_UGURU3_NAME, address);
+	if (!abituguru3_pdev) {
+		printk(KERN_ERR ABIT_UGURU3_NAME
+			": Device allocation failed\n");
+		err = -ENOMEM;
+		goto exit_driver_unregister;
+	}
+
+	res.start = address;
+	res.end = address + ABIT_UGURU3_REGION_LENGTH - 1;
+	res.name = ABIT_UGURU3_NAME;
+
+	err = platform_device_add_resources(abituguru3_pdev, &res, 1);
+	if (err) {
+		printk(KERN_ERR ABIT_UGURU3_NAME
+			": Device resource addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(abituguru3_pdev);
+	if (err) {
+		printk(KERN_ERR ABIT_UGURU3_NAME
+			": Device addition failed (%d)\n", err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(abituguru3_pdev);
+exit_driver_unregister:
+	platform_driver_unregister(&abituguru3_driver);
+exit:
+	return err;
+}
+
+static void __exit abituguru3_exit(void)
+{
+	platform_device_unregister(abituguru3_pdev);
+	platform_driver_unregister(&abituguru3_driver);
+}
+
+MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>");
+MODULE_DESCRIPTION("Abit uGuru3 Sensor device");
+MODULE_LICENSE("GPL");
+
+module_init(abituguru3_init);
+module_exit(abituguru3_exit);
diff --git a/drivers/hwmon/ams/ams-core.c b/drivers/hwmon/ams/ams-core.c
index 6db9737..a112a03 100644
--- a/drivers/hwmon/ams/ams-core.c
+++ b/drivers/hwmon/ams/ams-core.c
@@ -23,7 +23,6 @@
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/init.h>
-#include <linux/module.h>
 #include <asm/pmac_pfunc.h>
 #include <asm/of_platform.h>
 
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index eb81a64..571f49e 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -79,11 +79,15 @@
 
 /*
  * Temperature sensors keys (sp78 - 2 bytes).
- * First set for Macbook(Pro), second for Macmini.
  */
 static const char* temperature_sensors_sets[][13] = {
+/* Set 0: Macbook Pro */
 	{ "TA0P", "TB0T", "TC0D", "TC0P", "TG0H", "TG0P", "TG0T", "Th0H",
 	  "Th1H", "Tm0P", "Ts0P", "Ts1P", NULL },
+/* Set 1: Macbook set */
+	{ "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TN1P", "Th0H", "Th0S",
+	  "Th1H", "Ts0P", NULL },
+/* Set 2: Macmini set */
 	{ "TC0D", "TC0P", NULL }
 };
 
@@ -1048,7 +1052,7 @@
 /*
  * applesmc_dmi_match - found a match.  return one, short-circuiting the hunt.
  */
-static int applesmc_dmi_match(struct dmi_system_id *id)
+static int applesmc_dmi_match(const struct dmi_system_id *id)
 {
 	int i = 0;
 	struct dmi_match_data* dmi_data = id->driver_data;
@@ -1129,10 +1133,10 @@
 static __initdata struct dmi_match_data applesmc_dmi_data[] = {
 /* MacBook Pro: accelerometer, backlight and temperature set 0 */
 	{ .accelerometer = 1, .light = 1, .temperature_set = 0 },
-/* MacBook: accelerometer and temperature set 0 */
-	{ .accelerometer = 1, .light = 0, .temperature_set = 0 },
-/* MacBook: temperature set 1 */
-	{ .accelerometer = 0, .light = 0, .temperature_set = 1 }
+/* MacBook: accelerometer and temperature set 1 */
+	{ .accelerometer = 1, .light = 0, .temperature_set = 1 },
+/* MacMini: temperature set 2 */
+	{ .accelerometer = 0, .light = 0, .temperature_set = 2 },
 };
 
 /* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1".
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 6d54c8c..7c17952 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -318,7 +318,7 @@
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-void coretemp_device_remove(unsigned int cpu)
+static void coretemp_device_remove(unsigned int cpu)
 {
 	struct pdev_entry *p, *n;
 	mutex_lock(&pdev_list_mutex);
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
new file mode 100644
index 0000000..e9cbc72
--- /dev/null
+++ b/drivers/hwmon/dme1737.c
@@ -0,0 +1,2080 @@
+/*
+ * dme1737.c - driver for the SMSC DME1737 and Asus A8000 Super-I/O chips
+ *             integrated hardware monitoring features.
+ * Copyright (c) 2007 Juerg Haefliger <juergh@gmail.com>
+ *
+ * This driver is based on the LM85 driver. The hardware monitoring
+ * capabilities of the DME1737 are very similar to the LM85 with some
+ * additional features. Even though the DME1737 is a Super-I/O chip, the
+ * hardware monitoring registers are only accessible via SMBus.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <asm/io.h>
+
+/* Module load parameters */
+static int force_start;
+module_param(force_start, bool, 0);
+MODULE_PARM_DESC(force_start, "Force the chip to start monitoring inputs");
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {0x2c, 0x2d, 0x2e, I2C_CLIENT_END};
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(dme1737);
+
+/* ---------------------------------------------------------------------
+ * Registers
+ *
+ * The sensors are defined as follows:
+ *
+ * Voltages                          Temperatures
+ * --------                          ------------
+ * in0   +5VTR (+5V stdby)           temp1   Remote diode 1
+ * in1   Vccp  (proc core)           temp2   Internal temp
+ * in2   VCC   (internal +3.3V)      temp3   Remote diode 2
+ * in3   +5V
+ * in4   +12V
+ * in5   VTR   (+3.3V stby)
+ * in6   Vbat
+ *
+ * --------------------------------------------------------------------- */
+
+/* Voltages (in) numbered 0-6 (ix) */
+#define	DME1737_REG_IN(ix)		((ix) < 5 ? 0x20 + (ix) \
+						  : 0x94 + (ix))
+#define	DME1737_REG_IN_MIN(ix)		((ix) < 5 ? 0x44 + (ix) * 2 \
+						  : 0x91 + (ix) * 2)
+#define	DME1737_REG_IN_MAX(ix)		((ix) < 5 ? 0x45 + (ix) * 2 \
+						  : 0x92 + (ix) * 2)
+
+/* Temperatures (temp) numbered 0-2 (ix) */
+#define DME1737_REG_TEMP(ix)		(0x25 + (ix))
+#define DME1737_REG_TEMP_MIN(ix)	(0x4e + (ix) * 2)
+#define DME1737_REG_TEMP_MAX(ix)	(0x4f + (ix) * 2)
+#define DME1737_REG_TEMP_OFFSET(ix)	((ix) == 0 ? 0x1f \
+						   : 0x1c + (ix))
+
+/* Voltage and temperature LSBs
+ * The LSBs (4 bits each) are stored in 5 registers with the following layouts:
+ *    IN_TEMP_LSB(0) = [in5, in6]
+ *    IN_TEMP_LSB(1) = [temp3, temp1]
+ *    IN_TEMP_LSB(2) = [in4, temp2]
+ *    IN_TEMP_LSB(3) = [in3, in0]
+ *    IN_TEMP_LSB(4) = [in2, in1] */
+#define DME1737_REG_IN_TEMP_LSB(ix)	(0x84 + (ix))
+static const u8 DME1737_REG_IN_LSB[] = {3, 4, 4, 3, 2, 0, 0};
+static const u8 DME1737_REG_IN_LSB_SHL[] = {4, 4, 0, 0, 0, 0, 4};
+static const u8 DME1737_REG_TEMP_LSB[] = {1, 2, 1};
+static const u8 DME1737_REG_TEMP_LSB_SHL[] = {4, 4, 0};
+
+/* Fans numbered 0-5 (ix) */
+#define DME1737_REG_FAN(ix)		((ix) < 4 ? 0x28 + (ix) * 2 \
+						  : 0xa1 + (ix) * 2)
+#define DME1737_REG_FAN_MIN(ix)		((ix) < 4 ? 0x54 + (ix) * 2 \
+						  : 0xa5 + (ix) * 2)
+#define DME1737_REG_FAN_OPT(ix)		((ix) < 4 ? 0x90 + (ix) \
+						  : 0xb2 + (ix))
+#define DME1737_REG_FAN_MAX(ix)		(0xb4 + (ix)) /* only for fan[4-5] */
+
+/* PWMs numbered 0-2, 4-5 (ix) */
+#define DME1737_REG_PWM(ix)		((ix) < 3 ? 0x30 + (ix) \
+						  : 0xa1 + (ix))
+#define DME1737_REG_PWM_CONFIG(ix)	(0x5c + (ix)) /* only for pwm[0-2] */
+#define DME1737_REG_PWM_MIN(ix)		(0x64 + (ix)) /* only for pwm[0-2] */
+#define DME1737_REG_PWM_FREQ(ix)	((ix) < 3 ? 0x5f + (ix) \
+						  : 0xa3 + (ix))
+/* The layout of the ramp rate registers is different from the other pwm
+ * registers. The bits for the 3 PWMs are stored in 2 registers:
+ *    PWM_RR(0) = [OFF3, OFF2,  OFF1,  RES,   RR1E, RR1-2, RR1-1, RR1-0]
+ *    PWM_RR(1) = [RR2E, RR2-2, RR2-1, RR2-0, RR3E, RR3-2, RR3-1, RR3-0] */
+#define DME1737_REG_PWM_RR(ix)		(0x62 + (ix)) /* only for pwm[0-2] */
+
+/* Thermal zones 0-2 */
+#define DME1737_REG_ZONE_LOW(ix)	(0x67 + (ix))
+#define DME1737_REG_ZONE_ABS(ix)	(0x6a + (ix))
+/* The layout of the hysteresis registers is different from the other zone
+ * registers. The bits for the 3 zones are stored in 2 registers:
+ *    ZONE_HYST(0) = [H1-3,  H1-2,  H1-1, H1-0, H2-3, H2-2, H2-1, H2-0]
+ *    ZONE_HYST(1) = [H3-3,  H3-2,  H3-1, H3-0, RES,  RES,  RES,  RES] */
+#define DME1737_REG_ZONE_HYST(ix)	(0x6d + (ix))
+
+/* Alarm registers and bit mapping
+ * The 3 8-bit alarm registers will be concatenated to a single 32-bit
+ * alarm value [0, ALARM3, ALARM2, ALARM1]. */
+#define DME1737_REG_ALARM1		0x41
+#define DME1737_REG_ALARM2		0x42
+#define DME1737_REG_ALARM3		0x83
+static const u8 DME1737_BIT_ALARM_IN[] = {0, 1, 2, 3, 8, 16, 17};
+static const u8 DME1737_BIT_ALARM_TEMP[] = {4, 5, 6};
+static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
+
+/* Miscellaneous registers */
+#define DME1737_REG_COMPANY		0x3e
+#define DME1737_REG_VERSTEP		0x3f
+#define DME1737_REG_CONFIG		0x40
+#define DME1737_REG_CONFIG2		0x7f
+#define DME1737_REG_VID			0x43
+#define DME1737_REG_TACH_PWM		0x81
+
+/* ---------------------------------------------------------------------
+ * Misc defines
+ * --------------------------------------------------------------------- */
+
+/* Chip identification */
+#define DME1737_COMPANY_SMSC	0x5c
+#define DME1737_VERSTEP		0x88
+#define DME1737_VERSTEP_MASK	0xf8
+
+/* ---------------------------------------------------------------------
+ * Data structures and manipulation thereof
+ * --------------------------------------------------------------------- */
+
+struct dme1737_data {
+	struct i2c_client client;
+	struct class_device *class_dev;
+
+	struct mutex update_lock;
+	int valid;			/* !=0 if following fields are valid */
+	unsigned long last_update;	/* in jiffies */
+	unsigned long last_vbat;	/* in jiffies */
+
+	u8 vid;
+	u8 pwm_rr_en;
+	u8 has_pwm;
+	u8 has_fan;
+
+	/* Register values */
+	u16 in[7];
+	u8  in_min[7];
+	u8  in_max[7];
+	s16 temp[3];
+	s8  temp_min[3];
+	s8  temp_max[3];
+	s8  temp_offset[3];
+	u8  config;
+	u8  config2;
+	u8  vrm;
+	u16 fan[6];
+	u16 fan_min[6];
+	u8  fan_max[2];
+	u8  fan_opt[6];
+	u8  pwm[6];
+	u8  pwm_min[3];
+	u8  pwm_config[3];
+	u8  pwm_acz[3];
+	u8  pwm_freq[6];
+	u8  pwm_rr[2];
+	u8  zone_low[3];
+	u8  zone_abs[3];
+	u8  zone_hyst[2];
+	u32 alarms;
+};
+
+/* Nominal voltage values */
+static const int IN_NOMINAL[] = {5000, 2250, 3300, 5000, 12000, 3300, 3300};
+
+/* Voltage input
+ * Voltage inputs have 16 bits resolution, limit values have 8 bits
+ * resolution. */
+static inline int IN_FROM_REG(int reg, int ix, int res)
+{
+	return (reg * IN_NOMINAL[ix] + (3 << (res - 3))) / (3 << (res - 2));
+}
+
+static inline int IN_TO_REG(int val, int ix)
+{
+	return SENSORS_LIMIT((val * 192 + IN_NOMINAL[ix] / 2) /
+			     IN_NOMINAL[ix], 0, 255);
+}
+
+/* Temperature input
+ * The register values represent temperatures in 2's complement notation from
+ * -127 degrees C to +127 degrees C. Temp inputs have 16 bits resolution, limit
+ * values have 8 bits resolution. */
+static inline int TEMP_FROM_REG(int reg, int res)
+{
+	return (reg * 1000) >> (res - 8);
+}
+
+static inline int TEMP_TO_REG(int val)
+{
+	return SENSORS_LIMIT((val < 0 ? val - 500 : val + 500) / 1000,
+			     -128, 127);
+}
+
+/* Temperature range */
+static const int TEMP_RANGE[] = {2000, 2500, 3333, 4000, 5000, 6666, 8000,
+				 10000, 13333, 16000, 20000, 26666, 32000,
+				 40000, 53333, 80000};
+
+static inline int TEMP_RANGE_FROM_REG(int reg)
+{
+	return TEMP_RANGE[(reg >> 4) & 0x0f];
+}
+
+static int TEMP_RANGE_TO_REG(int val, int reg)
+{
+	int i;
+
+	for (i = 15; i > 0; i--) {
+		if (val > (TEMP_RANGE[i] + TEMP_RANGE[i - 1] + 1) / 2) {
+			break;
+		}
+	}
+
+	return (reg & 0x0f) | (i << 4);
+}
+
+/* Temperature hysteresis
+ * Register layout:
+ *    reg[0] = [H1-3, H1-2, H1-1, H1-0, H2-3, H2-2, H2-1, H2-0]
+ *    reg[1] = [H3-3, H3-2, H3-1, H3-0, xxxx, xxxx, xxxx, xxxx] */
+static inline int TEMP_HYST_FROM_REG(int reg, int ix)
+{
+	return (((ix == 1) ? reg : reg >> 4) & 0x0f) * 1000;
+}
+
+static inline int TEMP_HYST_TO_REG(int val, int ix, int reg)
+{
+	int hyst = SENSORS_LIMIT((val + 500) / 1000, 0, 15);
+
+	return (ix == 1) ? (reg & 0xf0) | hyst : (reg & 0x0f) | (hyst << 4);
+}
+
+/* Fan input RPM */
+static inline int FAN_FROM_REG(int reg, int tpc)
+{
+	return (reg == 0 || reg == 0xffff) ? 0 :
+		(tpc == 0) ? 90000 * 60 / reg : tpc * reg;
+}
+
+static inline int FAN_TO_REG(int val, int tpc)
+{
+	return SENSORS_LIMIT((tpc == 0) ? 90000 * 60 / val : val / tpc,
+			     0, 0xffff);
+}
+
+/* Fan TPC (tach pulse count)
+ * Converts a register value to a TPC multiplier or returns 0 if the tachometer
+ * is configured in legacy (non-tpc) mode */
+static inline int FAN_TPC_FROM_REG(int reg)
+{
+	return (reg & 0x20) ? 0 : 60 >> (reg & 0x03);
+}
+
+/* Fan type
+ * The type of a fan is expressed in number of pulses-per-revolution that it
+ * emits */
+static inline int FAN_TYPE_FROM_REG(int reg)
+{
+	int edge = (reg >> 1) & 0x03;
+
+	return (edge > 0) ? 1 << (edge - 1) : 0;
+}
+
+static inline int FAN_TYPE_TO_REG(int val, int reg)
+{
+	int edge = (val == 4) ? 3 : val;
+
+	return (reg & 0xf9) | (edge << 1);
+}
+
+/* Fan max RPM */
+static const int FAN_MAX[] = {0x54, 0x38, 0x2a, 0x21, 0x1c, 0x18, 0x15, 0x12,
+			      0x11, 0x0f, 0x0e};
+
+static int FAN_MAX_FROM_REG(int reg)
+{
+	int i;
+
+	for (i = 10; i > 0; i--) {
+		if (reg == FAN_MAX[i]) {
+			break;
+		}
+	}
+
+	return 1000 + i * 500;
+}
+
+static int FAN_MAX_TO_REG(int val)
+{
+	int i;
+
+	for (i = 10; i > 0; i--) {
+		if (val > (1000 + (i - 1) * 500)) {
+			break;
+		}
+	}
+
+	return FAN_MAX[i];
+}
+
+/* PWM enable
+ * Register to enable mapping:
+ * 000:  2  fan on zone 1 auto
+ * 001:  2  fan on zone 2 auto
+ * 010:  2  fan on zone 3 auto
+ * 011:  0  fan full on
+ * 100: -1  fan disabled
+ * 101:  2  fan on hottest of zones 2,3 auto
+ * 110:  2  fan on hottest of zones 1,2,3 auto
+ * 111:  1  fan in manual mode */
+static inline int PWM_EN_FROM_REG(int reg)
+{
+	static const int en[] = {2, 2, 2, 0, -1, 2, 2, 1};
+
+	return en[(reg >> 5) & 0x07];
+}
+
+static inline int PWM_EN_TO_REG(int val, int reg)
+{
+	int en = (val == 1) ? 7 : 3;
+
+	return (reg & 0x1f) | ((en & 0x07) << 5);
+}
+
+/* PWM auto channels zone
+ * Register to auto channels zone mapping (ACZ is a bitfield with bit x
+ * corresponding to zone x+1):
+ * 000: 001  fan on zone 1 auto
+ * 001: 010  fan on zone 2 auto
+ * 010: 100  fan on zone 3 auto
+ * 011: 000  fan full on
+ * 100: 000  fan disabled
+ * 101: 110  fan on hottest of zones 2,3 auto
+ * 110: 111  fan on hottest of zones 1,2,3 auto
+ * 111: 000  fan in manual mode */
+static inline int PWM_ACZ_FROM_REG(int reg)
+{
+	static const int acz[] = {1, 2, 4, 0, 0, 6, 7, 0};
+
+	return acz[(reg >> 5) & 0x07];
+}
+
+static inline int PWM_ACZ_TO_REG(int val, int reg)
+{
+	int acz = (val == 4) ? 2 : val - 1;
+
+	return (reg & 0x1f) | ((acz & 0x07) << 5);
+}
+
+/* PWM frequency */
+static const int PWM_FREQ[] = {11, 15, 22, 29, 35, 44, 59, 88,
+			       15000, 20000, 30000, 25000, 0, 0, 0, 0};
+
+static inline int PWM_FREQ_FROM_REG(int reg)
+{
+	return PWM_FREQ[reg & 0x0f];
+}
+
+static int PWM_FREQ_TO_REG(int val, int reg)
+{
+	int i;
+
+	/* the first two cases are special - stupid chip design! */
+	if (val > 27500) {
+		i = 10;
+	} else if (val > 22500) {
+		i = 11;
+	} else {
+		for (i = 9; i > 0; i--) {
+			if (val > (PWM_FREQ[i] + PWM_FREQ[i - 1] + 1) / 2) {
+				break;
+			}
+		}
+	}
+
+	return (reg & 0xf0) | i;
+}
+
+/* PWM ramp rate
+ * Register layout:
+ *    reg[0] = [OFF3,  OFF2,  OFF1,  RES,   RR1-E, RR1-2, RR1-1, RR1-0]
+ *    reg[1] = [RR2-E, RR2-2, RR2-1, RR2-0, RR3-E, RR3-2, RR3-1, RR3-0] */
+static const u8 PWM_RR[] = {206, 104, 69, 41, 26, 18, 10, 5};
+
+static inline int PWM_RR_FROM_REG(int reg, int ix)
+{
+	int rr = (ix == 1) ? reg >> 4 : reg;
+
+	return (rr & 0x08) ? PWM_RR[rr & 0x07] : 0;
+}
+
+static int PWM_RR_TO_REG(int val, int ix, int reg)
+{
+	int i;
+
+	for (i = 0; i < 7; i++) {
+		if (val > (PWM_RR[i] + PWM_RR[i + 1] + 1) / 2) {
+			break;
+		}
+	}
+
+	return (ix == 1) ? (reg & 0x8f) | (i << 4) : (reg & 0xf8) | i;
+}
+
+/* PWM ramp rate enable */
+static inline int PWM_RR_EN_FROM_REG(int reg, int ix)
+{
+	return PWM_RR_FROM_REG(reg, ix) ? 1 : 0;
+}
+
+static inline int PWM_RR_EN_TO_REG(int val, int ix, int reg)
+{
+	int en = (ix == 1) ? 0x80 : 0x08;
+
+	return val ? reg | en : reg & ~en;
+}
+
+/* PWM min/off
+ * The PWM min/off bits are part of the PMW ramp rate register 0 (see above for
+ * the register layout). */
+static inline int PWM_OFF_FROM_REG(int reg, int ix)
+{
+	return (reg >> (ix + 5)) & 0x01;
+}
+
+static inline int PWM_OFF_TO_REG(int val, int ix, int reg)
+{
+	return (reg & ~(1 << (ix + 5))) | ((val & 0x01) << (ix + 5));
+}
+
+/* ---------------------------------------------------------------------
+ * Device I/O access
+ * --------------------------------------------------------------------- */
+
+static u8 dme1737_read(struct i2c_client *client, u8 reg)
+{
+	s32 val = i2c_smbus_read_byte_data(client, reg);
+
+	if (val < 0) {
+		dev_warn(&client->dev, "Read from register 0x%02x failed! "
+			 "Please report to the driver maintainer.\n", reg);
+	}
+
+	return val;
+}
+
+static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 value)
+{
+	s32 res = i2c_smbus_write_byte_data(client, reg, value);
+
+	if (res < 0) {
+		dev_warn(&client->dev, "Write to register 0x%02x failed! "
+			 "Please report to the driver maintainer.\n", reg);
+	}
+
+	return res;
+}
+
+static struct dme1737_data *dme1737_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct dme1737_data *data = i2c_get_clientdata(client);
+	int ix;
+	u8 lsb[5];
+
+	mutex_lock(&data->update_lock);
+
+	/* Enable a Vbat monitoring cycle every 10 mins */
+	if (time_after(jiffies, data->last_vbat + 600 * HZ) || !data->valid) {
+		dme1737_write(client, DME1737_REG_CONFIG, dme1737_read(client,
+						DME1737_REG_CONFIG) | 0x10);
+		data->last_vbat = jiffies;
+	}
+
+	/* Sample register contents every 1 sec */
+	if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
+		data->vid = dme1737_read(client, DME1737_REG_VID) & 0x3f;
+
+		/* In (voltage) registers */
+		for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
+			/* Voltage inputs are stored as 16 bit values even
+			 * though they have only 12 bits resolution. This is
+			 * to make it consistent with the temp inputs. */
+			data->in[ix] = dme1737_read(client,
+					DME1737_REG_IN(ix)) << 8;
+			data->in_min[ix] = dme1737_read(client,
+					DME1737_REG_IN_MIN(ix));
+			data->in_max[ix] = dme1737_read(client,
+					DME1737_REG_IN_MAX(ix));
+		}
+
+		/* Temp registers */
+		for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) {
+			/* Temp inputs are stored as 16 bit values even
+			 * though they have only 12 bits resolution. This is
+			 * to take advantage of implicit conversions between
+			 * register values (2's complement) and temp values
+			 * (signed decimal). */
+			data->temp[ix] = dme1737_read(client,
+					DME1737_REG_TEMP(ix)) << 8;
+			data->temp_min[ix] = dme1737_read(client,
+					DME1737_REG_TEMP_MIN(ix));
+			data->temp_max[ix] = dme1737_read(client,
+					DME1737_REG_TEMP_MAX(ix));
+			data->temp_offset[ix] = dme1737_read(client,
+					DME1737_REG_TEMP_OFFSET(ix));
+		}
+
+		/* In and temp LSB registers
+		 * The LSBs are latched when the MSBs are read, so the order in
+		 * which the registers are read (MSB first, then LSB) is
+		 * important! */
+		for (ix = 0; ix < ARRAY_SIZE(lsb); ix++) {
+			lsb[ix] = dme1737_read(client,
+					DME1737_REG_IN_TEMP_LSB(ix));
+		}
+		for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
+			data->in[ix] |= (lsb[DME1737_REG_IN_LSB[ix]] <<
+					DME1737_REG_IN_LSB_SHL[ix]) & 0xf0;
+		}
+		for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) {
+			data->temp[ix] |= (lsb[DME1737_REG_TEMP_LSB[ix]] <<
+					DME1737_REG_TEMP_LSB_SHL[ix]) & 0xf0;
+		}
+
+		/* Fan registers */
+		for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) {
+			/* Skip reading registers if optional fans are not
+			 * present */
+			if (!(data->has_fan & (1 << ix))) {
+				continue;
+			}
+			data->fan[ix] = dme1737_read(client,
+					DME1737_REG_FAN(ix));
+			data->fan[ix] |= dme1737_read(client,
+					DME1737_REG_FAN(ix) + 1) << 8;
+			data->fan_min[ix] = dme1737_read(client,
+					DME1737_REG_FAN_MIN(ix));
+			data->fan_min[ix] |= dme1737_read(client,
+					DME1737_REG_FAN_MIN(ix) + 1) << 8;
+			data->fan_opt[ix] = dme1737_read(client,
+					DME1737_REG_FAN_OPT(ix));
+			/* fan_max exists only for fan[5-6] */
+			if (ix > 3) {
+				data->fan_max[ix - 4] = dme1737_read(client,
+					DME1737_REG_FAN_MAX(ix));
+			}
+		}
+
+		/* PWM registers */
+		for (ix = 0; ix < ARRAY_SIZE(data->pwm); ix++) {
+			/* Skip reading registers if optional PWMs are not
+			 * present */
+			if (!(data->has_pwm & (1 << ix))) {
+				continue;
+			}
+			data->pwm[ix] = dme1737_read(client,
+					DME1737_REG_PWM(ix));
+			data->pwm_freq[ix] = dme1737_read(client,
+					DME1737_REG_PWM_FREQ(ix));
+			/* pwm_config and pwm_min exist only for pwm[1-3] */
+			if (ix < 3) {
+				data->pwm_config[ix] = dme1737_read(client,
+						DME1737_REG_PWM_CONFIG(ix));
+				data->pwm_min[ix] = dme1737_read(client,
+						DME1737_REG_PWM_MIN(ix));
+			}
+		}
+		for (ix = 0; ix < ARRAY_SIZE(data->pwm_rr); ix++) {
+			data->pwm_rr[ix] = dme1737_read(client,
+						DME1737_REG_PWM_RR(ix));
+		}
+
+		/* Thermal zone registers */
+		for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) {
+			data->zone_low[ix] = dme1737_read(client,
+					DME1737_REG_ZONE_LOW(ix));
+			data->zone_abs[ix] = dme1737_read(client,
+					DME1737_REG_ZONE_ABS(ix));
+		}
+		for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
+			data->zone_hyst[ix] = dme1737_read(client,
+						DME1737_REG_ZONE_HYST(ix));
+		}
+
+		/* Alarm registers */
+		data->alarms = dme1737_read(client,
+						DME1737_REG_ALARM1);
+		/* Bit 7 tells us if the other alarm registers are non-zero and
+		 * therefore also need to be read */
+		if (data->alarms & 0x80) {
+			data->alarms |= dme1737_read(client,
+						DME1737_REG_ALARM2) << 8;
+			data->alarms |= dme1737_read(client,
+						DME1737_REG_ALARM3) << 16;
+		}
+
+		data->last_update = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+/* ---------------------------------------------------------------------
+ * Voltage sysfs attributes
+ * ix = [0-5]
+ * --------------------------------------------------------------------- */
+
+#define SYS_IN_INPUT	0
+#define SYS_IN_MIN	1
+#define SYS_IN_MAX	2
+#define SYS_IN_ALARM	3
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+		       char *buf)
+{
+	struct dme1737_data *data = dme1737_update_device(dev);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	int res;
+
+	switch (fn) {
+	case SYS_IN_INPUT:
+		res = IN_FROM_REG(data->in[ix], ix, 16);
+		break;
+	case SYS_IN_MIN:
+		res = IN_FROM_REG(data->in_min[ix], ix, 8);
+		break;
+	case SYS_IN_MAX:
+		res = IN_FROM_REG(data->in_max[ix], ix, 8);
+		break;
+	case SYS_IN_ALARM:
+		res = (data->alarms >> DME1737_BIT_ALARM_IN[ix]) & 0x01;
+		break;
+	default:
+		res = 0;
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+
+	return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_in(struct device *dev, struct device_attribute *attr,
+		      const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct dme1737_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	long val = simple_strtol(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	switch (fn) {
+	case SYS_IN_MIN:
+		data->in_min[ix] = IN_TO_REG(val, ix);
+		dme1737_write(client, DME1737_REG_IN_MIN(ix),
+			      data->in_min[ix]);
+		break;
+	case SYS_IN_MAX:
+		data->in_max[ix] = IN_TO_REG(val, ix);
+		dme1737_write(client, DME1737_REG_IN_MAX(ix),
+			      data->in_max[ix]);
+		break;
+	default:
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Temperature sysfs attributes
+ * ix = [0-2]
+ * --------------------------------------------------------------------- */
+
+#define SYS_TEMP_INPUT			0
+#define SYS_TEMP_MIN			1
+#define SYS_TEMP_MAX			2
+#define SYS_TEMP_OFFSET			3
+#define SYS_TEMP_ALARM			4
+#define SYS_TEMP_FAULT			5
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct dme1737_data *data = dme1737_update_device(dev);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	int res;
+
+	switch (fn) {
+	case SYS_TEMP_INPUT:
+		res = TEMP_FROM_REG(data->temp[ix], 16);
+		break;
+	case SYS_TEMP_MIN:
+		res = TEMP_FROM_REG(data->temp_min[ix], 8);
+		break;
+	case SYS_TEMP_MAX:
+		res = TEMP_FROM_REG(data->temp_max[ix], 8);
+		break;
+	case SYS_TEMP_OFFSET:
+		res = TEMP_FROM_REG(data->temp_offset[ix], 8);
+		break;
+	case SYS_TEMP_ALARM:
+		res = (data->alarms >> DME1737_BIT_ALARM_TEMP[ix]) & 0x01;
+		break;
+	case SYS_TEMP_FAULT:
+		res = (((u16)data->temp[ix] & 0xff00) == 0x8000);
+		break;
+	default:
+		res = 0;
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+
+	return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct dme1737_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	long val = simple_strtol(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	switch (fn) {
+	case SYS_TEMP_MIN:
+		data->temp_min[ix] = TEMP_TO_REG(val);
+		dme1737_write(client, DME1737_REG_TEMP_MIN(ix),
+			      data->temp_min[ix]);
+		break;
+	case SYS_TEMP_MAX:
+		data->temp_max[ix] = TEMP_TO_REG(val);
+		dme1737_write(client, DME1737_REG_TEMP_MAX(ix),
+			      data->temp_max[ix]);
+		break;
+	case SYS_TEMP_OFFSET:
+		data->temp_offset[ix] = TEMP_TO_REG(val);
+		dme1737_write(client, DME1737_REG_TEMP_OFFSET(ix),
+			      data->temp_offset[ix]);
+		break;
+	default:
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Zone sysfs attributes
+ * ix = [0-2]
+ * --------------------------------------------------------------------- */
+
+#define SYS_ZONE_AUTO_CHANNELS_TEMP	0
+#define SYS_ZONE_AUTO_POINT1_TEMP_HYST	1
+#define SYS_ZONE_AUTO_POINT1_TEMP	2
+#define SYS_ZONE_AUTO_POINT2_TEMP	3
+#define SYS_ZONE_AUTO_POINT3_TEMP	4
+
+static ssize_t show_zone(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct dme1737_data *data = dme1737_update_device(dev);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	int res;
+
+	switch (fn) {
+	case SYS_ZONE_AUTO_CHANNELS_TEMP:
+		/* check config2 for non-standard temp-to-zone mapping */
+		if ((ix == 1) && (data->config2 & 0x02)) {
+			res = 4;
+		} else {
+			res = 1 << ix;
+		}
+		break;
+	case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
+		res = TEMP_FROM_REG(data->zone_low[ix], 8) -
+		      TEMP_HYST_FROM_REG(data->zone_hyst[ix == 2], ix);
+		break;
+	case SYS_ZONE_AUTO_POINT1_TEMP:
+		res = TEMP_FROM_REG(data->zone_low[ix], 8);
+		break;
+	case SYS_ZONE_AUTO_POINT2_TEMP:
+		/* pwm_freq holds the temp range bits in the upper nibble */
+		res = TEMP_FROM_REG(data->zone_low[ix], 8) +
+		      TEMP_RANGE_FROM_REG(data->pwm_freq[ix]);
+		break;
+	case SYS_ZONE_AUTO_POINT3_TEMP:
+		res = TEMP_FROM_REG(data->zone_abs[ix], 8);
+		break;
+	default:
+		res = 0;
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+
+	return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct dme1737_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	long val = simple_strtol(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	switch (fn) {
+	case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
+		/* Refresh the cache */
+		data->zone_low[ix] = dme1737_read(client,
+						  DME1737_REG_ZONE_LOW(ix));
+		/* Modify the temp hyst value */
+		data->zone_hyst[ix == 2] = TEMP_HYST_TO_REG(
+					TEMP_FROM_REG(data->zone_low[ix], 8) -
+					val, ix, dme1737_read(client,
+					DME1737_REG_ZONE_HYST(ix == 2)));
+		dme1737_write(client, DME1737_REG_ZONE_HYST(ix == 2),
+			      data->zone_hyst[ix == 2]);
+		break;
+	case SYS_ZONE_AUTO_POINT1_TEMP:
+		data->zone_low[ix] = TEMP_TO_REG(val);
+		dme1737_write(client, DME1737_REG_ZONE_LOW(ix),
+			      data->zone_low[ix]);
+		break;
+	case SYS_ZONE_AUTO_POINT2_TEMP:
+		/* Refresh the cache */
+		data->zone_low[ix] = dme1737_read(client,
+						  DME1737_REG_ZONE_LOW(ix));
+		/* Modify the temp range value (which is stored in the upper
+		 * nibble of the pwm_freq register) */
+		data->pwm_freq[ix] = TEMP_RANGE_TO_REG(val -
+					TEMP_FROM_REG(data->zone_low[ix], 8),
+					dme1737_read(client,
+					DME1737_REG_PWM_FREQ(ix)));
+		dme1737_write(client, DME1737_REG_PWM_FREQ(ix),
+			      data->pwm_freq[ix]);
+		break;
+	case SYS_ZONE_AUTO_POINT3_TEMP:
+		data->zone_abs[ix] = TEMP_TO_REG(val);
+		dme1737_write(client, DME1737_REG_ZONE_ABS(ix),
+			      data->zone_abs[ix]);
+		break;
+	default:
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Fan sysfs attributes
+ * ix = [0-5]
+ * --------------------------------------------------------------------- */
+
+#define SYS_FAN_INPUT	0
+#define SYS_FAN_MIN	1
+#define SYS_FAN_MAX	2
+#define SYS_FAN_ALARM	3
+#define SYS_FAN_TYPE	4
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct dme1737_data *data = dme1737_update_device(dev);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	int res;
+
+	switch (fn) {
+	case SYS_FAN_INPUT:
+		res = FAN_FROM_REG(data->fan[ix],
+				   ix < 4 ? 0 :
+				   FAN_TPC_FROM_REG(data->fan_opt[ix]));
+		break;
+	case SYS_FAN_MIN:
+		res = FAN_FROM_REG(data->fan_min[ix],
+				   ix < 4 ? 0 :
+				   FAN_TPC_FROM_REG(data->fan_opt[ix]));
+		break;
+	case SYS_FAN_MAX:
+		/* only valid for fan[5-6] */
+		res = FAN_MAX_FROM_REG(data->fan_max[ix - 4]);
+		break;
+	case SYS_FAN_ALARM:
+		res = (data->alarms >> DME1737_BIT_ALARM_FAN[ix]) & 0x01;
+		break;
+	case SYS_FAN_TYPE:
+		/* only valid for fan[1-4] */
+		res = FAN_TYPE_FROM_REG(data->fan_opt[ix]);
+		break;
+	default:
+		res = 0;
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+
+	return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct dme1737_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	long val = simple_strtol(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	switch (fn) {
+	case SYS_FAN_MIN:
+		if (ix < 4) {
+			data->fan_min[ix] = FAN_TO_REG(val, 0);
+		} else {
+			/* Refresh the cache */
+			data->fan_opt[ix] = dme1737_read(client,
+						DME1737_REG_FAN_OPT(ix));
+			/* Modify the fan min value */
+			data->fan_min[ix] = FAN_TO_REG(val,
+					FAN_TPC_FROM_REG(data->fan_opt[ix]));
+		}
+		dme1737_write(client, DME1737_REG_FAN_MIN(ix),
+			      data->fan_min[ix] & 0xff);
+		dme1737_write(client, DME1737_REG_FAN_MIN(ix) + 1,
+			      data->fan_min[ix] >> 8);
+		break;
+	case SYS_FAN_MAX:
+		/* Only valid for fan[5-6] */
+		data->fan_max[ix - 4] = FAN_MAX_TO_REG(val);
+		dme1737_write(client, DME1737_REG_FAN_MAX(ix),
+			      data->fan_max[ix - 4]);
+		break;
+	case SYS_FAN_TYPE:
+		/* Only valid for fan[1-4] */
+		if (!(val == 1 || val == 2 || val == 4)) {
+			count = -EINVAL;
+			dev_warn(&client->dev, "Fan type value %ld not "
+				 "supported. Choose one of 1, 2, or 4.\n",
+				 val);
+			goto exit;
+		}
+		data->fan_opt[ix] = FAN_TYPE_TO_REG(val, dme1737_read(client,
+					DME1737_REG_FAN_OPT(ix)));
+		dme1737_write(client, DME1737_REG_FAN_OPT(ix),
+			      data->fan_opt[ix]);
+		break;
+	default:
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+exit:
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* ---------------------------------------------------------------------
+ * PWM sysfs attributes
+ * ix = [0-4]
+ * --------------------------------------------------------------------- */
+
+#define SYS_PWM				0
+#define SYS_PWM_FREQ			1
+#define SYS_PWM_ENABLE			2
+#define SYS_PWM_RAMP_RATE		3
+#define SYS_PWM_AUTO_CHANNELS_ZONE	4
+#define SYS_PWM_AUTO_PWM_MIN		5
+#define SYS_PWM_AUTO_POINT1_PWM		6
+#define SYS_PWM_AUTO_POINT2_PWM		7
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct dme1737_data *data = dme1737_update_device(dev);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	int res;
+
+	switch (fn) {
+	case SYS_PWM:
+		if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 0) {
+			res = 255;
+		} else {
+			res = data->pwm[ix];
+		}
+		break;
+	case SYS_PWM_FREQ:
+		res = PWM_FREQ_FROM_REG(data->pwm_freq[ix]);
+		break;
+	case SYS_PWM_ENABLE:
+		if (ix > 3) {
+			res = 1; /* pwm[5-6] hard-wired to manual mode */
+		} else {
+			res = PWM_EN_FROM_REG(data->pwm_config[ix]);
+		}
+		break;
+	case SYS_PWM_RAMP_RATE:
+		/* Only valid for pwm[1-3] */
+		res = PWM_RR_FROM_REG(data->pwm_rr[ix > 0], ix);
+		break;
+	case SYS_PWM_AUTO_CHANNELS_ZONE:
+		/* Only valid for pwm[1-3] */
+		if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+			res = PWM_ACZ_FROM_REG(data->pwm_config[ix]);
+		} else {
+			res = data->pwm_acz[ix];
+		}
+		break;
+	case SYS_PWM_AUTO_PWM_MIN:
+		/* Only valid for pwm[1-3] */
+		if (PWM_OFF_FROM_REG(data->pwm_rr[0], ix)) {
+			res = data->pwm_min[ix];
+		} else {
+			res = 0;
+		}
+		break;
+	case SYS_PWM_AUTO_POINT1_PWM:
+		/* Only valid for pwm[1-3] */
+		res = data->pwm_min[ix];
+		break;
+	case SYS_PWM_AUTO_POINT2_PWM:
+		/* Only valid for pwm[1-3] */
+		res = 255; /* hard-wired */
+		break;
+	default:
+		res = 0;
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+
+	return sprintf(buf, "%d\n", res);
+}
+
+static struct attribute *dme1737_attr_pwm[];
+static void dme1737_chmod_file(struct i2c_client*, struct attribute*, mode_t);
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct dme1737_data *data = i2c_get_clientdata(client);
+	struct sensor_device_attribute_2
+		*sensor_attr_2 = to_sensor_dev_attr_2(attr);
+	int ix = sensor_attr_2->index;
+	int fn = sensor_attr_2->nr;
+	long val = simple_strtol(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	switch (fn) {
+	case SYS_PWM:
+		data->pwm[ix] = SENSORS_LIMIT(val, 0, 255);
+		dme1737_write(client, DME1737_REG_PWM(ix), data->pwm[ix]);
+		break;
+	case SYS_PWM_FREQ:
+		data->pwm_freq[ix] = PWM_FREQ_TO_REG(val, dme1737_read(client,
+						DME1737_REG_PWM_FREQ(ix)));
+		dme1737_write(client, DME1737_REG_PWM_FREQ(ix),
+			      data->pwm_freq[ix]);
+		break;
+	case SYS_PWM_ENABLE:
+		/* Only valid for pwm[1-3] */
+		if (val < 0 || val > 2) {
+			count = -EINVAL;
+			dev_warn(&client->dev, "PWM enable %ld not "
+				 "supported. Choose one of 0, 1, or 2.\n",
+				 val);
+			goto exit;
+		}
+		/* Refresh the cache */
+		data->pwm_config[ix] = dme1737_read(client,
+						DME1737_REG_PWM_CONFIG(ix));
+		if (val == PWM_EN_FROM_REG(data->pwm_config[ix])) {
+			/* Bail out if no change */
+			goto exit;
+		}
+		/* Do some housekeeping if we are currently in auto mode */
+		if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+			/* Save the current zone channel assignment */
+			data->pwm_acz[ix] = PWM_ACZ_FROM_REG(
+							data->pwm_config[ix]);
+			/* Save the current ramp rate state and disable it */
+			data->pwm_rr[ix > 0] = dme1737_read(client,
+						DME1737_REG_PWM_RR(ix > 0));
+			data->pwm_rr_en &= ~(1 << ix);
+			if (PWM_RR_EN_FROM_REG(data->pwm_rr[ix > 0], ix)) {
+				data->pwm_rr_en |= (1 << ix);
+				data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(0, ix,
+							data->pwm_rr[ix > 0]);
+				dme1737_write(client,
+					      DME1737_REG_PWM_RR(ix > 0),
+					      data->pwm_rr[ix > 0]);
+			}
+		}
+		/* Set the new PWM mode */
+		switch (val) {
+		case 0:
+			/* Change permissions of pwm[ix] to read-only */
+			dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+					   S_IRUGO);
+			/* Turn fan fully on */
+			data->pwm_config[ix] = PWM_EN_TO_REG(0,
+							data->pwm_config[ix]);
+			dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+				      data->pwm_config[ix]);
+			break;
+		case 1:
+			/* Turn on manual mode */
+			data->pwm_config[ix] = PWM_EN_TO_REG(1,
+							data->pwm_config[ix]);
+			dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+				      data->pwm_config[ix]);
+			/* Change permissions of pwm[ix] to read-writeable */
+			dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+					   S_IRUGO | S_IWUSR);
+			break;
+		case 2:
+			/* Change permissions of pwm[ix] to read-only */
+			dme1737_chmod_file(client, dme1737_attr_pwm[ix],
+					   S_IRUGO);
+			/* Turn on auto mode using the saved zone channel
+			 * assignment */
+			data->pwm_config[ix] = PWM_ACZ_TO_REG(
+							data->pwm_acz[ix],
+							data->pwm_config[ix]);
+			dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+				      data->pwm_config[ix]);
+			/* Enable PWM ramp rate if previously enabled */
+			if (data->pwm_rr_en & (1 << ix)) {
+				data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(1, ix,
+						dme1737_read(client,
+						DME1737_REG_PWM_RR(ix > 0)));
+				dme1737_write(client,
+					      DME1737_REG_PWM_RR(ix > 0),
+					      data->pwm_rr[ix > 0]);
+			}
+			break;
+		}
+		break;
+	case SYS_PWM_RAMP_RATE:
+		/* Only valid for pwm[1-3] */
+		/* Refresh the cache */
+		data->pwm_config[ix] = dme1737_read(client,
+						DME1737_REG_PWM_CONFIG(ix));
+		data->pwm_rr[ix > 0] = dme1737_read(client,
+						DME1737_REG_PWM_RR(ix > 0));
+		/* Set the ramp rate value */
+		if (val > 0) {
+			data->pwm_rr[ix > 0] = PWM_RR_TO_REG(val, ix,
+							data->pwm_rr[ix > 0]);
+		}
+		/* Enable/disable the feature only if the associated PWM
+		 * output is in automatic mode. */
+		if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+			data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(val > 0, ix,
+							data->pwm_rr[ix > 0]);
+		}
+		dme1737_write(client, DME1737_REG_PWM_RR(ix > 0),
+			      data->pwm_rr[ix > 0]);
+		break;
+	case SYS_PWM_AUTO_CHANNELS_ZONE:
+		/* Only valid for pwm[1-3] */
+		if (!(val == 1 || val == 2 || val == 4 ||
+		      val == 6 || val == 7)) {
+			count = -EINVAL;
+			dev_warn(&client->dev, "PWM auto channels zone %ld "
+				 "not supported. Choose one of 1, 2, 4, 6, "
+				 "or 7.\n", val);
+			goto exit;
+		}
+		/* Refresh the cache */
+		data->pwm_config[ix] = dme1737_read(client,
+						DME1737_REG_PWM_CONFIG(ix));
+		if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
+			/* PWM is already in auto mode so update the temp
+			 * channel assignment */
+			data->pwm_config[ix] = PWM_ACZ_TO_REG(val,
+						data->pwm_config[ix]);
+			dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+				      data->pwm_config[ix]);
+		} else {
+			/* PWM is not in auto mode so we save the temp
+			 * channel assignment for later use */
+			data->pwm_acz[ix] = val;
+		}
+		break;
+	case SYS_PWM_AUTO_PWM_MIN:
+		/* Only valid for pwm[1-3] */
+		/* Refresh the cache */
+		data->pwm_min[ix] = dme1737_read(client,
+						DME1737_REG_PWM_MIN(ix));
+		/* There are only 2 values supported for the auto_pwm_min
+		 * value: 0 or auto_point1_pwm. So if the temperature drops
+		 * below the auto_point1_temp_hyst value, the fan either turns
+		 * off or runs at auto_point1_pwm duty-cycle. */
+		if (val > ((data->pwm_min[ix] + 1) / 2)) {
+			data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix,
+						dme1737_read(client,
+						DME1737_REG_PWM_RR(0)));
+
+		} else {
+			data->pwm_rr[0] = PWM_OFF_TO_REG(0, ix,
+						dme1737_read(client,
+						DME1737_REG_PWM_RR(0)));
+
+		}
+		dme1737_write(client, DME1737_REG_PWM_RR(0),
+			      data->pwm_rr[0]);
+		break;
+	case SYS_PWM_AUTO_POINT1_PWM:
+		/* Only valid for pwm[1-3] */
+		data->pwm_min[ix] = SENSORS_LIMIT(val, 0, 255);
+		dme1737_write(client, DME1737_REG_PWM_MIN(ix),
+			      data->pwm_min[ix]);
+		break;
+	default:
+		dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+	}
+exit:
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Miscellaneous sysfs attributes
+ * --------------------------------------------------------------------- */
+
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct dme1737_data *data = i2c_get_clientdata(client);
+
+	return sprintf(buf, "%d\n", data->vrm);
+}
+
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
+		       const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct dme1737_data *data = i2c_get_clientdata(client);
+	long val = simple_strtol(buf, NULL, 10);
+
+	data->vrm = val;
+	return count;
+}
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct dme1737_data *data = dme1737_update_device(dev);
+
+	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+
+/* ---------------------------------------------------------------------
+ * Sysfs device attribute defines and structs
+ * --------------------------------------------------------------------- */
+
+/* Voltages 0-6 */
+
+#define SENSOR_DEVICE_ATTR_IN(ix) \
+static SENSOR_DEVICE_ATTR_2(in##ix##_input, S_IRUGO, \
+        show_in, NULL, SYS_IN_INPUT, ix); \
+static SENSOR_DEVICE_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \
+        show_in, set_in, SYS_IN_MIN, ix); \
+static SENSOR_DEVICE_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \
+        show_in, set_in, SYS_IN_MAX, ix); \
+static SENSOR_DEVICE_ATTR_2(in##ix##_alarm, S_IRUGO, \
+        show_in, NULL, SYS_IN_ALARM, ix)
+
+SENSOR_DEVICE_ATTR_IN(0);
+SENSOR_DEVICE_ATTR_IN(1);
+SENSOR_DEVICE_ATTR_IN(2);
+SENSOR_DEVICE_ATTR_IN(3);
+SENSOR_DEVICE_ATTR_IN(4);
+SENSOR_DEVICE_ATTR_IN(5);
+SENSOR_DEVICE_ATTR_IN(6);
+
+/* Temperatures 1-3 */
+
+#define SENSOR_DEVICE_ATTR_TEMP(ix) \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_input, S_IRUGO, \
+        show_temp, NULL, SYS_TEMP_INPUT, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_min, S_IRUGO | S_IWUSR, \
+        show_temp, set_temp, SYS_TEMP_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \
+        show_temp, set_temp, SYS_TEMP_MAX, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_offset, S_IRUGO, \
+        show_temp, set_temp, SYS_TEMP_OFFSET, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_alarm, S_IRUGO, \
+        show_temp, NULL, SYS_TEMP_ALARM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(temp##ix##_fault, S_IRUGO, \
+        show_temp, NULL, SYS_TEMP_FAULT, ix-1)
+
+SENSOR_DEVICE_ATTR_TEMP(1);
+SENSOR_DEVICE_ATTR_TEMP(2);
+SENSOR_DEVICE_ATTR_TEMP(3);
+
+/* Zones 1-3 */
+
+#define SENSOR_DEVICE_ATTR_ZONE(ix) \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_channels_temp, S_IRUGO, \
+        show_zone, NULL, SYS_ZONE_AUTO_CHANNELS_TEMP, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp_hyst, S_IRUGO, \
+        show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP_HYST, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point1_temp, S_IRUGO, \
+        show_zone, set_zone, SYS_ZONE_AUTO_POINT1_TEMP, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point2_temp, S_IRUGO, \
+        show_zone, set_zone, SYS_ZONE_AUTO_POINT2_TEMP, ix-1); \
+static SENSOR_DEVICE_ATTR_2(zone##ix##_auto_point3_temp, S_IRUGO, \
+        show_zone, set_zone, SYS_ZONE_AUTO_POINT3_TEMP, ix-1)
+
+SENSOR_DEVICE_ATTR_ZONE(1);
+SENSOR_DEVICE_ATTR_ZONE(2);
+SENSOR_DEVICE_ATTR_ZONE(3);
+
+/* Fans 1-4 */
+
+#define SENSOR_DEVICE_ATTR_FAN_1TO4(ix) \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
+        show_fan, NULL, SYS_FAN_INPUT, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
+        show_fan, set_fan, SYS_FAN_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
+        show_fan, NULL, SYS_FAN_ALARM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_type, S_IRUGO | S_IWUSR, \
+        show_fan, set_fan, SYS_FAN_TYPE, ix-1)
+
+SENSOR_DEVICE_ATTR_FAN_1TO4(1);
+SENSOR_DEVICE_ATTR_FAN_1TO4(2);
+SENSOR_DEVICE_ATTR_FAN_1TO4(3);
+SENSOR_DEVICE_ATTR_FAN_1TO4(4);
+
+/* Fans 5-6 */
+
+#define SENSOR_DEVICE_ATTR_FAN_5TO6(ix) \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_input, S_IRUGO, \
+        show_fan, NULL, SYS_FAN_INPUT, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
+        show_fan, set_fan, SYS_FAN_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_alarm, S_IRUGO, \
+        show_fan, NULL, SYS_FAN_ALARM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(fan##ix##_max, S_IRUGO | S_IWUSR, \
+        show_fan, set_fan, SYS_FAN_MAX, ix-1)
+
+SENSOR_DEVICE_ATTR_FAN_5TO6(5);
+SENSOR_DEVICE_ATTR_FAN_5TO6(6);
+
+/* PWMs 1-3 */
+
+#define SENSOR_DEVICE_ATTR_PWM_1TO3(ix) \
+static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO, \
+        show_pwm, set_pwm, SYS_PWM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO, \
+        show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
+        show_pwm, set_pwm, SYS_PWM_ENABLE, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_ramp_rate, S_IRUGO, \
+        show_pwm, set_pwm, SYS_PWM_RAMP_RATE, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_channels_zone, S_IRUGO, \
+        show_pwm, set_pwm, SYS_PWM_AUTO_CHANNELS_ZONE, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_pwm_min, S_IRUGO, \
+        show_pwm, set_pwm, SYS_PWM_AUTO_PWM_MIN, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point1_pwm, S_IRUGO, \
+        show_pwm, set_pwm, SYS_PWM_AUTO_POINT1_PWM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_auto_point2_pwm, S_IRUGO, \
+        show_pwm, NULL, SYS_PWM_AUTO_POINT2_PWM, ix-1)
+
+SENSOR_DEVICE_ATTR_PWM_1TO3(1);
+SENSOR_DEVICE_ATTR_PWM_1TO3(2);
+SENSOR_DEVICE_ATTR_PWM_1TO3(3);
+
+/* PWMs 5-6 */
+
+#define SENSOR_DEVICE_ATTR_PWM_5TO6(ix) \
+static SENSOR_DEVICE_ATTR_2(pwm##ix, S_IRUGO | S_IWUSR, \
+        show_pwm, set_pwm, SYS_PWM, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_freq, S_IRUGO | S_IWUSR, \
+        show_pwm, set_pwm, SYS_PWM_FREQ, ix-1); \
+static SENSOR_DEVICE_ATTR_2(pwm##ix##_enable, S_IRUGO, \
+        show_pwm, NULL, SYS_PWM_ENABLE, ix-1)
+
+SENSOR_DEVICE_ATTR_PWM_5TO6(5);
+SENSOR_DEVICE_ATTR_PWM_5TO6(6);
+
+/* Misc */
+
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+#define SENSOR_DEV_ATTR_IN(ix) \
+&sensor_dev_attr_in##ix##_input.dev_attr.attr, \
+&sensor_dev_attr_in##ix##_min.dev_attr.attr, \
+&sensor_dev_attr_in##ix##_max.dev_attr.attr, \
+&sensor_dev_attr_in##ix##_alarm.dev_attr.attr
+
+/* These attributes are read-writeable only if the chip is *not* locked */
+#define SENSOR_DEV_ATTR_TEMP_LOCK(ix) \
+&sensor_dev_attr_temp##ix##_offset.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_TEMP(ix) \
+SENSOR_DEV_ATTR_TEMP_LOCK(ix), \
+&sensor_dev_attr_temp##ix##_input.dev_attr.attr, \
+&sensor_dev_attr_temp##ix##_min.dev_attr.attr, \
+&sensor_dev_attr_temp##ix##_max.dev_attr.attr, \
+&sensor_dev_attr_temp##ix##_alarm.dev_attr.attr, \
+&sensor_dev_attr_temp##ix##_fault.dev_attr.attr
+
+/* These attributes are read-writeable only if the chip is *not* locked */
+#define SENSOR_DEV_ATTR_ZONE_LOCK(ix) \
+&sensor_dev_attr_zone##ix##_auto_point1_temp_hyst.dev_attr.attr, \
+&sensor_dev_attr_zone##ix##_auto_point1_temp.dev_attr.attr, \
+&sensor_dev_attr_zone##ix##_auto_point2_temp.dev_attr.attr, \
+&sensor_dev_attr_zone##ix##_auto_point3_temp.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_ZONE(ix) \
+SENSOR_DEV_ATTR_ZONE_LOCK(ix), \
+&sensor_dev_attr_zone##ix##_auto_channels_temp.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_FAN_1TO4(ix) \
+&sensor_dev_attr_fan##ix##_input.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_min.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_alarm.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_type.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_FAN_5TO6(ix) \
+&sensor_dev_attr_fan##ix##_input.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_min.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_alarm.dev_attr.attr, \
+&sensor_dev_attr_fan##ix##_max.dev_attr.attr
+
+/* These attributes are read-writeable only if the chip is *not* locked */
+#define SENSOR_DEV_ATTR_PWM_1TO3_LOCK(ix) \
+&sensor_dev_attr_pwm##ix##_freq.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_enable.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_ramp_rate.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_auto_channels_zone.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_auto_pwm_min.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_auto_point1_pwm.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_PWM_1TO3(ix) \
+SENSOR_DEV_ATTR_PWM_1TO3_LOCK(ix), \
+&sensor_dev_attr_pwm##ix.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_auto_point2_pwm.dev_attr.attr
+
+/* These attributes are read-writeable only if the chip is *not* locked */
+#define SENSOR_DEV_ATTR_PWM_5TO6_LOCK(ix) \
+&sensor_dev_attr_pwm##ix.dev_attr.attr, \
+&sensor_dev_attr_pwm##ix##_freq.dev_attr.attr
+
+#define SENSOR_DEV_ATTR_PWM_5TO6(ix) \
+SENSOR_DEV_ATTR_PWM_5TO6_LOCK(ix), \
+&sensor_dev_attr_pwm##ix##_enable.dev_attr.attr
+
+/* This struct holds all the attributes that are always present and need to be
+ * created unconditionally. The attributes that need modification of their
+ * permissions are created read-only and write permissions are added or removed
+ * on the fly when required */
+static struct attribute *dme1737_attr[] ={
+        /* Voltages */
+        SENSOR_DEV_ATTR_IN(0),
+        SENSOR_DEV_ATTR_IN(1),
+        SENSOR_DEV_ATTR_IN(2),
+        SENSOR_DEV_ATTR_IN(3),
+        SENSOR_DEV_ATTR_IN(4),
+        SENSOR_DEV_ATTR_IN(5),
+        SENSOR_DEV_ATTR_IN(6),
+        /* Temperatures */
+        SENSOR_DEV_ATTR_TEMP(1),
+        SENSOR_DEV_ATTR_TEMP(2),
+        SENSOR_DEV_ATTR_TEMP(3),
+        /* Zones */
+        SENSOR_DEV_ATTR_ZONE(1),
+        SENSOR_DEV_ATTR_ZONE(2),
+        SENSOR_DEV_ATTR_ZONE(3),
+        /* Misc */
+        &dev_attr_vrm.attr,
+        &dev_attr_cpu0_vid.attr,
+	NULL
+};
+
+static const struct attribute_group dme1737_group = {
+        .attrs = dme1737_attr,
+};
+
+/* The following structs hold the PWM attributes, some of which are optional.
+ * Their creation depends on the chip configuration which is determined during
+ * module load. */
+static struct attribute *dme1737_attr_pwm1[] = {
+        SENSOR_DEV_ATTR_PWM_1TO3(1),
+	NULL
+};
+static struct attribute *dme1737_attr_pwm2[] = {
+        SENSOR_DEV_ATTR_PWM_1TO3(2),
+	NULL
+};
+static struct attribute *dme1737_attr_pwm3[] = {
+        SENSOR_DEV_ATTR_PWM_1TO3(3),
+	NULL
+};
+static struct attribute *dme1737_attr_pwm5[] = {
+        SENSOR_DEV_ATTR_PWM_5TO6(5),
+	NULL
+};
+static struct attribute *dme1737_attr_pwm6[] = {
+        SENSOR_DEV_ATTR_PWM_5TO6(6),
+	NULL
+};
+
+static const struct attribute_group dme1737_pwm_group[] = {
+	{ .attrs = dme1737_attr_pwm1 },
+	{ .attrs = dme1737_attr_pwm2 },
+	{ .attrs = dme1737_attr_pwm3 },
+	{ .attrs = NULL },
+	{ .attrs = dme1737_attr_pwm5 },
+	{ .attrs = dme1737_attr_pwm6 },
+};
+
+/* The following structs hold the fan attributes, some of which are optional.
+ * Their creation depends on the chip configuration which is determined during
+ * module load. */
+static struct attribute *dme1737_attr_fan1[] = {
+        SENSOR_DEV_ATTR_FAN_1TO4(1),
+	NULL
+};
+static struct attribute *dme1737_attr_fan2[] = {
+        SENSOR_DEV_ATTR_FAN_1TO4(2),
+	NULL
+};
+static struct attribute *dme1737_attr_fan3[] = {
+        SENSOR_DEV_ATTR_FAN_1TO4(3),
+	NULL
+};
+static struct attribute *dme1737_attr_fan4[] = {
+        SENSOR_DEV_ATTR_FAN_1TO4(4),
+	NULL
+};
+static struct attribute *dme1737_attr_fan5[] = {
+        SENSOR_DEV_ATTR_FAN_5TO6(5),
+	NULL
+};
+static struct attribute *dme1737_attr_fan6[] = {
+        SENSOR_DEV_ATTR_FAN_5TO6(6),
+	NULL
+};
+
+static const struct attribute_group dme1737_fan_group[] = {
+	{ .attrs = dme1737_attr_fan1 },
+	{ .attrs = dme1737_attr_fan2 },
+	{ .attrs = dme1737_attr_fan3 },
+	{ .attrs = dme1737_attr_fan4 },
+	{ .attrs = dme1737_attr_fan5 },
+	{ .attrs = dme1737_attr_fan6 },
+};
+
+/* The permissions of all of the following attributes are changed to read-
+ * writeable if the chip is *not* locked. Otherwise they stay read-only. */
+static struct attribute *dme1737_attr_lock[] = {
+	/* Temperatures */
+	SENSOR_DEV_ATTR_TEMP_LOCK(1),
+	SENSOR_DEV_ATTR_TEMP_LOCK(2),
+	SENSOR_DEV_ATTR_TEMP_LOCK(3),
+	/* Zones */
+	SENSOR_DEV_ATTR_ZONE_LOCK(1),
+	SENSOR_DEV_ATTR_ZONE_LOCK(2),
+	SENSOR_DEV_ATTR_ZONE_LOCK(3),
+	NULL
+};
+
+static const struct attribute_group dme1737_lock_group = {
+	.attrs = dme1737_attr_lock,
+};
+
+/* The permissions of the following PWM attributes are changed to read-
+ * writeable if the chip is *not* locked and the respective PWM is available.
+ * Otherwise they stay read-only. */
+static struct attribute *dme1737_attr_pwm1_lock[] = {
+        SENSOR_DEV_ATTR_PWM_1TO3_LOCK(1),
+	NULL
+};
+static struct attribute *dme1737_attr_pwm2_lock[] = {
+        SENSOR_DEV_ATTR_PWM_1TO3_LOCK(2),
+	NULL
+};
+static struct attribute *dme1737_attr_pwm3_lock[] = {
+        SENSOR_DEV_ATTR_PWM_1TO3_LOCK(3),
+	NULL
+};
+static struct attribute *dme1737_attr_pwm5_lock[] = {
+        SENSOR_DEV_ATTR_PWM_5TO6_LOCK(5),
+	NULL
+};
+static struct attribute *dme1737_attr_pwm6_lock[] = {
+        SENSOR_DEV_ATTR_PWM_5TO6_LOCK(6),
+	NULL
+};
+
+static const struct attribute_group dme1737_pwm_lock_group[] = {
+	{ .attrs = dme1737_attr_pwm1_lock },
+	{ .attrs = dme1737_attr_pwm2_lock },
+	{ .attrs = dme1737_attr_pwm3_lock },
+	{ .attrs = NULL },
+	{ .attrs = dme1737_attr_pwm5_lock },
+	{ .attrs = dme1737_attr_pwm6_lock },
+};
+
+/* Pwm[1-3] are read-writeable if the associated pwm is in manual mode and the
+ * chip is not locked. Otherwise they are read-only. */
+static struct attribute *dme1737_attr_pwm[] = {
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm3.dev_attr.attr,
+};
+
+/* ---------------------------------------------------------------------
+ * Super-IO functions
+ * --------------------------------------------------------------------- */
+
+static inline int dme1737_sio_inb(int sio_cip, int reg)
+{
+	outb(reg, sio_cip);
+	return inb(sio_cip + 1);
+}
+
+static inline void dme1737_sio_outb(int sio_cip, int reg, int val)
+{
+	outb(reg, sio_cip);
+	outb(val, sio_cip + 1);
+}
+
+static int dme1737_sio_get_features(int sio_cip, struct i2c_client *client)
+{
+	struct dme1737_data *data = i2c_get_clientdata(client);
+	int err = 0, reg;
+	u16 addr;
+
+	/* Enter configuration mode */
+	outb(0x55, sio_cip);
+
+	/* Check device ID
+	 * The DME1737 can return either 0x78 or 0x77 as its device ID. */
+	reg = dme1737_sio_inb(sio_cip, 0x20);
+	if (!(reg == 0x77 || reg == 0x78)) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	/* Select logical device A (runtime registers) */
+	dme1737_sio_outb(sio_cip, 0x07, 0x0a);
+
+	/* Get the base address of the runtime registers */
+	if (!(addr = (dme1737_sio_inb(sio_cip, 0x60) << 8) |
+		      dme1737_sio_inb(sio_cip, 0x61))) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	/* Read the runtime registers to determine which optional features
+	 * are enabled and available. Bits [3:2] of registers 0x43-0x46 are set
+	 * to '10' if the respective feature is enabled. */
+	if ((inb(addr + 0x43) & 0x0c) == 0x08) { /* fan6 */
+		data->has_fan |= (1 << 5);
+	}
+	if ((inb(addr + 0x44) & 0x0c) == 0x08) { /* pwm6 */
+		data->has_pwm |= (1 << 5);
+	}
+	if ((inb(addr + 0x45) & 0x0c) == 0x08) { /* fan5 */
+		data->has_fan |= (1 << 4);
+	}
+	if ((inb(addr + 0x46) & 0x0c) == 0x08) { /* pwm5 */
+		data->has_pwm |= (1 << 4);
+	}
+
+exit:
+	/* Exit configuration mode */
+	outb(0xaa, sio_cip);
+
+	return err;
+}
+
+/* ---------------------------------------------------------------------
+ * Device detection, registration and initialization
+ * --------------------------------------------------------------------- */
+
+static struct i2c_driver dme1737_driver;
+
+static void dme1737_chmod_file(struct i2c_client *client,
+			       struct attribute *attr, mode_t mode)
+{
+	if (sysfs_chmod_file(&client->dev.kobj, attr, mode)) {
+		dev_warn(&client->dev, "Failed to change permissions of %s.\n",
+			 attr->name);
+	}
+}
+
+static void dme1737_chmod_group(struct i2c_client *client,
+				const struct attribute_group *group,
+				mode_t mode)
+{
+	struct attribute **attr;
+
+	for (attr = group->attrs; *attr; attr++) {
+		dme1737_chmod_file(client, *attr, mode);
+	}
+}
+
+static int dme1737_init_client(struct i2c_client *client)
+{
+	struct dme1737_data *data = i2c_get_clientdata(client);
+	int ix;
+	u8 reg;
+
+        data->config = dme1737_read(client, DME1737_REG_CONFIG);
+        /* Inform if part is not monitoring/started */
+        if (!(data->config & 0x01)) {
+                if (!force_start) {
+                        dev_err(&client->dev, "Device is not monitoring. "
+                                "Use the force_start load parameter to "
+                                "override.\n");
+                        return -EFAULT;
+                }
+
+                /* Force monitoring */
+                data->config |= 0x01;
+                dme1737_write(client, DME1737_REG_CONFIG, data->config);
+        }
+	/* Inform if part is not ready */
+	if (!(data->config & 0x04)) {
+		dev_err(&client->dev, "Device is not ready.\n");
+		return -EFAULT;
+	}
+
+	data->config2 = dme1737_read(client, DME1737_REG_CONFIG2);
+	/* Check if optional fan3 input is enabled */
+	if (data->config2 & 0x04) {
+		data->has_fan |= (1 << 2);
+	}
+
+	/* Fan4 and pwm3 are only available if the client's I2C address
+	 * is the default 0x2e. Otherwise the I/Os associated with these
+	 * functions are used for addr enable/select. */
+	if (client->addr == 0x2e) {
+		data->has_fan |= (1 << 3);
+		data->has_pwm |= (1 << 2);
+	}
+
+	/* Determine if the optional fan[5-6] and/or pwm[5-6] are enabled.
+	 * For this, we need to query the runtime registers through the
+	 * Super-IO LPC interface. Try both config ports 0x2e and 0x4e. */
+	if (dme1737_sio_get_features(0x2e, client) &&
+	    dme1737_sio_get_features(0x4e, client)) {
+		dev_warn(&client->dev, "Failed to query Super-IO for optional "
+			 "features.\n");
+	}
+
+	/* Fan1, fan2, pwm1, and pwm2 are always present */
+	data->has_fan |= 0x03;
+	data->has_pwm |= 0x03;
+
+	dev_info(&client->dev, "Optional features: pwm3=%s, pwm5=%s, pwm6=%s, "
+		 "fan3=%s, fan4=%s, fan5=%s, fan6=%s.\n",
+		 (data->has_pwm & (1 << 2)) ? "yes" : "no",
+		 (data->has_pwm & (1 << 4)) ? "yes" : "no",
+		 (data->has_pwm & (1 << 5)) ? "yes" : "no",
+		 (data->has_fan & (1 << 2)) ? "yes" : "no",
+		 (data->has_fan & (1 << 3)) ? "yes" : "no",
+		 (data->has_fan & (1 << 4)) ? "yes" : "no",
+		 (data->has_fan & (1 << 5)) ? "yes" : "no");
+
+	reg = dme1737_read(client, DME1737_REG_TACH_PWM);
+	/* Inform if fan-to-pwm mapping differs from the default */
+	if (reg != 0xa4) {
+		dev_warn(&client->dev, "Non-standard fan to pwm mapping: "
+			 "fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, "
+			 "fan4->pwm%d. Please report to the driver "
+			 "maintainer.\n",
+			 (reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
+			 ((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1);
+	}
+
+	/* Switch pwm[1-3] to manual mode if they are currently disabled and
+	 * set the duty-cycles to 0% (which is identical to the PWMs being
+	 * disabled). */
+	if (!(data->config & 0x02)) {
+		for (ix = 0; ix < 3; ix++) {
+			data->pwm_config[ix] = dme1737_read(client,
+						DME1737_REG_PWM_CONFIG(ix));
+			if ((data->has_pwm & (1 << ix)) &&
+			    (PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
+				dev_info(&client->dev, "Switching pwm%d to "
+					 "manual mode.\n", ix + 1);
+				data->pwm_config[ix] = PWM_EN_TO_REG(1,
+							data->pwm_config[ix]);
+				dme1737_write(client, DME1737_REG_PWM(ix), 0);
+				dme1737_write(client,
+					      DME1737_REG_PWM_CONFIG(ix),
+					      data->pwm_config[ix]);
+			}
+		}
+	}
+
+	/* Initialize the default PWM auto channels zone (acz) assignments */
+	data->pwm_acz[0] = 1;	/* pwm1 -> zone1 */
+	data->pwm_acz[1] = 2;	/* pwm2 -> zone2 */
+	data->pwm_acz[2] = 4;	/* pwm3 -> zone3 */
+
+	/* Set VRM */
+	data->vrm = vid_which_vrm();
+
+	return 0;
+}
+
+static int dme1737_detect(struct i2c_adapter *adapter, int address,
+			  int kind)
+{
+	u8 company, verstep = 0;
+	struct i2c_client *client;
+	struct dme1737_data *data;
+	int ix, err = 0;
+	const char *name;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		goto exit;
+	}
+
+	if (!(data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	client = &data->client;
+	i2c_set_clientdata(client, data);
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &dme1737_driver;
+
+	/* A negative kind means that the driver was loaded with no force
+	 * parameter (default), so we must identify the chip. */
+	if (kind < 0) {
+		company = dme1737_read(client, DME1737_REG_COMPANY);
+		verstep = dme1737_read(client, DME1737_REG_VERSTEP);
+
+		if (!((company == DME1737_COMPANY_SMSC) &&
+		      ((verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP))) {
+			err = -ENODEV;
+			goto exit_kfree;
+		}
+	}
+
+	kind = dme1737;
+	name = "dme1737";
+
+	/* Fill in the remaining client fields and put it into the global
+	 * list */
+	strlcpy(client->name, name, I2C_NAME_SIZE);
+	mutex_init(&data->update_lock);
+
+	/* Tell the I2C layer a new client has arrived */
+	if ((err = i2c_attach_client(client))) {
+		goto exit_kfree;
+	}
+
+	/* Initialize the DME1737 chip */
+	if ((err = dme1737_init_client(client))) {
+		goto exit_detach;
+	}
+
+	/* Create standard sysfs attributes */
+	if ((err = sysfs_create_group(&client->dev.kobj, &dme1737_group))) {
+                goto exit_detach;
+	}
+
+	/* Create fan sysfs attributes */
+	for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+		if (data->has_fan & (1 << ix)) {
+			if ((err = sysfs_create_group(&client->dev.kobj,
+						&dme1737_fan_group[ix]))) {
+				goto exit_remove;
+			}
+		}
+	}
+
+	/* Create PWM sysfs attributes */
+	for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+		if (data->has_pwm & (1 << ix)) {
+			if ((err = sysfs_create_group(&client->dev.kobj,
+						&dme1737_pwm_group[ix]))) {
+				goto exit_remove;
+			}
+		}
+	}
+
+	/* Inform if the device is locked. Otherwise change the permissions of
+	 * selected attributes from read-only to read-writeable. */
+	if (data->config & 0x02) {
+		dev_info(&client->dev, "Device is locked. Some attributes "
+			 "will be read-only.\n");
+	} else {
+		/* Change permissions of standard attributes */
+		dme1737_chmod_group(client, &dme1737_lock_group,
+				    S_IRUGO | S_IWUSR);
+
+		/* Change permissions of PWM attributes */
+		for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_lock_group); ix++) {
+			if (data->has_pwm & (1 << ix)) {
+				dme1737_chmod_group(client,
+						&dme1737_pwm_lock_group[ix],
+						S_IRUGO | S_IWUSR);
+			}
+		}
+
+		/* Change permissions of pwm[1-3] if in manual mode */
+		for (ix = 0; ix < 3; ix++) {
+			if ((data->has_pwm & (1 << ix)) &&
+			    (PWM_EN_FROM_REG(data->pwm_config[ix]) == 1)) {
+				dme1737_chmod_file(client,
+						   dme1737_attr_pwm[ix],
+						   S_IRUGO | S_IWUSR);
+			}
+		}
+	}
+
+	/* Register device */
+	data->class_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->class_dev)) {
+		err = PTR_ERR(data->class_dev);
+		goto exit_remove;
+	}
+
+	dev_info(&adapter->dev, "Found a DME1737 chip at 0x%02x "
+		 "(rev 0x%02x)\n", client->addr, verstep);
+
+	return 0;
+
+exit_remove:
+	for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+		if (data->has_fan & (1 << ix)) {
+			sysfs_remove_group(&client->dev.kobj,
+					   &dme1737_fan_group[ix]);
+		}
+	}
+	for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+		if (data->has_pwm & (1 << ix)) {
+			sysfs_remove_group(&client->dev.kobj,
+					   &dme1737_pwm_group[ix]);
+		}
+	}
+	sysfs_remove_group(&client->dev.kobj, &dme1737_group);
+exit_detach:
+	i2c_detach_client(client);
+exit_kfree:
+	kfree(data);
+exit:
+	return err;
+}
+
+static int dme1737_attach_adapter(struct i2c_adapter *adapter)
+{
+	if (!(adapter->class & I2C_CLASS_HWMON)) {
+		return 0;
+	}
+
+	return i2c_probe(adapter, &addr_data, dme1737_detect);
+}
+
+static int dme1737_detach_client(struct i2c_client *client)
+{
+	struct dme1737_data *data = i2c_get_clientdata(client);
+	int ix, err;
+
+	hwmon_device_unregister(data->class_dev);
+
+	for (ix = 0; ix < ARRAY_SIZE(dme1737_fan_group); ix++) {
+		if (data->has_fan & (1 << ix)) {
+			sysfs_remove_group(&client->dev.kobj,
+					   &dme1737_fan_group[ix]);
+		}
+	}
+	for (ix = 0; ix < ARRAY_SIZE(dme1737_pwm_group); ix++) {
+		if (data->has_pwm & (1 << ix)) {
+			sysfs_remove_group(&client->dev.kobj,
+					   &dme1737_pwm_group[ix]);
+		}
+	}
+	sysfs_remove_group(&client->dev.kobj, &dme1737_group);
+
+	if ((err = i2c_detach_client(client))) {
+		return err;
+	}
+
+	kfree(data);
+	return 0;
+}
+
+static struct i2c_driver dme1737_driver = {
+	.driver = {
+		.name = "dme1737",
+	},
+	.attach_adapter	= dme1737_attach_adapter,
+	.detach_client = dme1737_detach_client,
+};
+
+static int __init dme1737_init(void)
+{
+	return i2c_add_driver(&dme1737_driver);
+}
+
+static void __exit dme1737_exit(void)
+{
+	i2c_del_driver(&dme1737_driver);
+}
+
+MODULE_AUTHOR("Juerg Haefliger <juergh@gmail.com>");
+MODULE_DESCRIPTION("DME1737 sensors");
+MODULE_LICENSE("GPL");
+
+module_init(dme1737_init);
+module_exit(dme1737_exit);
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index d5ac422..1212d6b 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -27,6 +27,7 @@
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/sysfs.h>
@@ -52,9 +53,11 @@
 #define DS1621_REG_CONFIG_DONE		0x80
 
 /* The DS1621 registers */
-#define DS1621_REG_TEMP			0xAA /* word, RO */
-#define DS1621_REG_TEMP_MIN		0xA2 /* word, RW */
-#define DS1621_REG_TEMP_MAX		0xA1 /* word, RW */
+static const u8 DS1621_REG_TEMP[3] = {
+	0xAA,		/* input, word, RO */
+	0xA2,		/* min, word, RW */
+	0xA1,		/* max, word, RW */
+};
 #define DS1621_REG_CONF			0xAC /* byte, RW */
 #define DS1621_COM_START		0xEE /* no data */
 #define DS1621_COM_STOP			0x22 /* no data */
@@ -63,10 +66,7 @@
 #define DS1621_ALARM_TEMP_HIGH		0x40
 #define DS1621_ALARM_TEMP_LOW		0x20
 
-/* Conversions. Rounding and limit checking is only done on the TO_REG
-   variants. Note that you should be a bit careful with which arguments
-   these macros are called: arguments may be evaluated more than once.
-   Fixing this is just not worth it. */
+/* Conversions */
 #define ALARMS_FROM_REG(val) ((val) & \
                               (DS1621_ALARM_TEMP_HIGH | DS1621_ALARM_TEMP_LOW))
 
@@ -78,7 +78,7 @@
 	char valid;			/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
-	u16 temp, temp_min, temp_max;	/* Register values, word */
+	u16 temp[3];			/* Register values, word */
 	u8 conf;			/* Register encoding, combined */
 };
 
@@ -101,7 +101,7 @@
 
 /* All registers are word-sized, except for the configuration register.
    DS1621 uses a high-byte first convention, which is exactly opposite to
-   the usual practice. */
+   the SMBus standard. */
 static int ds1621_read_value(struct i2c_client *client, u8 reg)
 {
 	if (reg == DS1621_REG_CONF)
@@ -110,9 +110,6 @@
 		return swab16(i2c_smbus_read_word_data(client, reg));
 }
 
-/* All registers are word-sized, except for the configuration register.
-   DS1621 uses a high-byte first convention, which is exactly opposite to
-   the usual practice. */
 static int ds1621_write_value(struct i2c_client *client, u8 reg, u16 value)
 {
 	if (reg == DS1621_REG_CONF)
@@ -139,50 +136,61 @@
 	i2c_smbus_write_byte(client, DS1621_COM_START);
 }
 
-#define show(value)							\
-static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf)		\
-{									\
-	struct ds1621_data *data = ds1621_update_client(dev);		\
-	return sprintf(buf, "%d\n", LM75_TEMP_FROM_REG(data->value));	\
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+			 char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ds1621_data *data = ds1621_update_client(dev);
+	return sprintf(buf, "%d\n",
+		       LM75_TEMP_FROM_REG(data->temp[attr->index]));
 }
 
-show(temp);
-show(temp_min);
-show(temp_max);
+static ssize_t set_temp(struct device *dev, struct device_attribute *da,
+			const char *buf, size_t count)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ds1621_data *data = ds1621_update_client(dev);
+	u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10));
 
-#define set_temp(suffix, value, reg)					\
-static ssize_t set_temp_##suffix(struct device *dev, struct device_attribute *attr, const char *buf,	\
-				 size_t count)				\
-{									\
-	struct i2c_client *client = to_i2c_client(dev);			\
-	struct ds1621_data *data = ds1621_update_client(dev);		\
-	u16 val = LM75_TEMP_TO_REG(simple_strtoul(buf, NULL, 10));	\
-									\
-	mutex_lock(&data->update_lock);					\
-	data->value = val;						\
-	ds1621_write_value(client, reg, data->value);			\
-	mutex_unlock(&data->update_lock);				\
-	return count;							\
+	mutex_lock(&data->update_lock);
+	data->temp[attr->index] = val;
+	ds1621_write_value(client, DS1621_REG_TEMP[attr->index],
+			   data->temp[attr->index]);
+	mutex_unlock(&data->update_lock);
+	return count;
 }
 
-set_temp(min, temp_min, DS1621_REG_TEMP_MIN);
-set_temp(max, temp_max, DS1621_REG_TEMP_MAX);
-
-static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_alarms(struct device *dev, struct device_attribute *da,
+			   char *buf)
 {
 	struct ds1621_data *data = ds1621_update_client(dev);
 	return sprintf(buf, "%d\n", ALARMS_FROM_REG(data->conf));
 }
 
+static ssize_t show_alarm(struct device *dev, struct device_attribute *da,
+			  char *buf)
+{
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	struct ds1621_data *data = ds1621_update_client(dev);
+	return sprintf(buf, "%d\n", !!(data->conf & attr->index));
+}
+
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
-static DEVICE_ATTR(temp1_input, S_IRUGO , show_temp, NULL);
-static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO , show_temp_min, set_temp_min);
-static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL,
+		DS1621_ALARM_TEMP_LOW);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
+		DS1621_ALARM_TEMP_HIGH);
 
 static struct attribute *ds1621_attributes[] = {
-	&dev_attr_temp1_input.attr,
-	&dev_attr_temp1_min.attr,
-	&dev_attr_temp1_max.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
 	&dev_attr_alarms.attr,
 	NULL
 };
@@ -204,9 +212,9 @@
 			 int kind)
 {
 	int conf, temp;
-	struct i2c_client *new_client;
+	struct i2c_client *client;
 	struct ds1621_data *data;
-	int err = 0;
+	int i, err = 0;
 
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA 
 				     | I2C_FUNC_SMBUS_WORD_DATA 
@@ -221,55 +229,44 @@
 		goto exit;
 	}
 	
-	new_client = &data->client;
-	i2c_set_clientdata(new_client, data);
-	new_client->addr = address;
-	new_client->adapter = adapter;
-	new_client->driver = &ds1621_driver;
-	new_client->flags = 0;
-
+	client = &data->client;
+	i2c_set_clientdata(client, data);
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &ds1621_driver;
 
 	/* Now, we do the remaining detection. It is lousy. */
 	if (kind < 0) {
 		/* The NVB bit should be low if no EEPROM write has been 
 		   requested during the latest 10ms, which is highly 
 		   improbable in our case. */
-		conf = ds1621_read_value(new_client, DS1621_REG_CONF);
+		conf = ds1621_read_value(client, DS1621_REG_CONF);
 		if (conf & DS1621_REG_CONFIG_NVB)
 			goto exit_free;
 		/* The 7 lowest bits of a temperature should always be 0. */
-		temp = ds1621_read_value(new_client, DS1621_REG_TEMP);
-		if (temp & 0x007f)
-			goto exit_free;
-		temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MIN);
-		if (temp & 0x007f)
-			goto exit_free;
-		temp = ds1621_read_value(new_client, DS1621_REG_TEMP_MAX);
-		if (temp & 0x007f)
-			goto exit_free;
+		for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+			temp = ds1621_read_value(client, DS1621_REG_TEMP[i]);
+			if (temp & 0x007f)
+				goto exit_free;
+		}
 	}
 
-	/* Determine the chip type - only one kind supported! */
-	if (kind <= 0)
-		kind = ds1621;
-
 	/* Fill in remaining client fields and put it into the global list */
-	strlcpy(new_client->name, "ds1621", I2C_NAME_SIZE);
-	data->valid = 0;
+	strlcpy(client->name, "ds1621", I2C_NAME_SIZE);
 	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
-	if ((err = i2c_attach_client(new_client)))
+	if ((err = i2c_attach_client(client)))
 		goto exit_free;
 
 	/* Initialize the DS1621 chip */
-	ds1621_init_client(new_client);
+	ds1621_init_client(client);
 
 	/* Register sysfs hooks */
-	if ((err = sysfs_create_group(&new_client->dev.kobj, &ds1621_group)))
+	if ((err = sysfs_create_group(&client->dev.kobj, &ds1621_group)))
 		goto exit_detach;
 
-	data->class_dev = hwmon_device_register(&new_client->dev);
+	data->class_dev = hwmon_device_register(&client->dev);
 	if (IS_ERR(data->class_dev)) {
 		err = PTR_ERR(data->class_dev);
 		goto exit_remove_files;
@@ -278,9 +275,9 @@
 	return 0;
 
       exit_remove_files:
-	sysfs_remove_group(&new_client->dev.kobj, &ds1621_group);
+	sysfs_remove_group(&client->dev.kobj, &ds1621_group);
       exit_detach:
-	i2c_detach_client(new_client);
+	i2c_detach_client(client);
       exit_free:
 	kfree(data);
       exit:
@@ -314,23 +311,21 @@
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	    || !data->valid) {
+		int i;
 
 		dev_dbg(&client->dev, "Starting ds1621 update\n");
 
 		data->conf = ds1621_read_value(client, DS1621_REG_CONF);
 
-		data->temp = ds1621_read_value(client, DS1621_REG_TEMP);
-		
-		data->temp_min = ds1621_read_value(client,
-		                                    DS1621_REG_TEMP_MIN);
-		data->temp_max = ds1621_read_value(client,
-						    DS1621_REG_TEMP_MAX);
+		for (i = 0; i < ARRAY_SIZE(data->temp); i++)
+			data->temp[i] = ds1621_read_value(client,
+							  DS1621_REG_TEMP[i]);
 
 		/* reset alarms if necessary */
 		new_conf = data->conf;
-		if (data->temp > data->temp_min)
+		if (data->temp[0] > data->temp[1])	/* input > min */
 			new_conf &= ~DS1621_ALARM_TEMP_LOW;
-		if (data->temp < data->temp_max)
+		if (data->temp[0] < data->temp[2])	/* input < max */
 			new_conf &= ~DS1621_ALARM_TEMP_HIGH;
 		if (data->conf != new_conf)
 			ds1621_write_value(client, DS1621_REG_CONF,
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index cdbe309..6f60715 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -127,6 +127,13 @@
 #define F71805F_REG_TEMP_HIGH(nr)	(0x54 + 2 * (nr))
 #define F71805F_REG_TEMP_HYST(nr)	(0x55 + 2 * (nr))
 #define F71805F_REG_TEMP_MODE		0x01
+/* pwm/fan pwmnr from 0 to 2, auto point apnr from 0 to 2 */
+/* map Fintek numbers to our numbers as follows: 9->0, 5->1, 1->2 */
+#define F71805F_REG_PWM_AUTO_POINT_TEMP(pwmnr, apnr) \
+					(0xA0 + 0x10 * (pwmnr) + (2 - (apnr)))
+#define F71805F_REG_PWM_AUTO_POINT_FAN(pwmnr, apnr) \
+					(0xA4 + 0x10 * (pwmnr) + \
+						2 * (2 - (apnr)))
 
 #define F71805F_REG_START		0x00
 /* status nr from 0 to 2 */
@@ -144,6 +151,11 @@
  * Data structures and manipulation thereof
  */
 
+struct f71805f_auto_point {
+	u8 temp[3];
+	u16 fan[3];
+};
+
 struct f71805f_data {
 	unsigned short addr;
 	const char *name;
@@ -170,6 +182,7 @@
 	u8 temp_hyst[3];
 	u8 temp_mode;
 	unsigned long alarms;
+	struct f71805f_auto_point auto_points[3];
 };
 
 struct f71805f_sio_data {
@@ -312,7 +325,7 @@
 static struct f71805f_data *f71805f_update_device(struct device *dev)
 {
 	struct f71805f_data *data = dev_get_drvdata(dev);
-	int nr;
+	int nr, apnr;
 
 	mutex_lock(&data->update_lock);
 
@@ -342,6 +355,18 @@
 					      F71805F_REG_TEMP_HYST(nr));
 		}
 		data->temp_mode = f71805f_read8(data, F71805F_REG_TEMP_MODE);
+		for (nr = 0; nr < 3; nr++) {
+			for (apnr = 0; apnr < 3; apnr++) {
+				data->auto_points[nr].temp[apnr] =
+					f71805f_read8(data,
+					F71805F_REG_PWM_AUTO_POINT_TEMP(nr,
+									apnr));
+				data->auto_points[nr].fan[apnr] =
+					f71805f_read16(data,
+					F71805F_REG_PWM_AUTO_POINT_FAN(nr,
+								       apnr));
+			}
+		}
 
 		data->last_limits = jiffies;
 	}
@@ -705,6 +730,70 @@
 	return count;
 }
 
+static ssize_t show_pwm_auto_point_temp(struct device *dev,
+					struct device_attribute *devattr,
+					char* buf)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	int pwmnr = attr->nr;
+	int apnr = attr->index;
+
+	return sprintf(buf, "%ld\n",
+		       temp_from_reg(data->auto_points[pwmnr].temp[apnr]));
+}
+
+static ssize_t set_pwm_auto_point_temp(struct device *dev,
+				       struct device_attribute *devattr,
+				       const char* buf, size_t count)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	int pwmnr = attr->nr;
+	int apnr = attr->index;
+	unsigned long val = simple_strtol(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	data->auto_points[pwmnr].temp[apnr] = temp_to_reg(val);
+	f71805f_write8(data, F71805F_REG_PWM_AUTO_POINT_TEMP(pwmnr, apnr),
+		       data->auto_points[pwmnr].temp[apnr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
+static ssize_t show_pwm_auto_point_fan(struct device *dev,
+				       struct device_attribute *devattr,
+				       char* buf)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	int pwmnr = attr->nr;
+	int apnr = attr->index;
+
+	return sprintf(buf, "%ld\n",
+		       fan_from_reg(data->auto_points[pwmnr].fan[apnr]));
+}
+
+static ssize_t set_pwm_auto_point_fan(struct device *dev,
+				      struct device_attribute *devattr,
+				      const char* buf, size_t count)
+{
+	struct f71805f_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);
+	int pwmnr = attr->nr;
+	int apnr = attr->index;
+	unsigned long val = simple_strtoul(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	data->auto_points[pwmnr].fan[apnr] = fan_to_reg(val);
+	f71805f_write16(data, F71805F_REG_PWM_AUTO_POINT_FAN(pwmnr, apnr),
+		        data->auto_points[pwmnr].fan[apnr]);
+	mutex_unlock(&data->update_lock);
+
+	return count;
+}
+
 static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
 			 char *buf)
 {
@@ -932,6 +1021,63 @@
 			  show_pwm_freq, set_pwm_freq, 2);
 static SENSOR_DEVICE_ATTR(pwm3_mode, S_IRUGO, show_pwm_mode, NULL, 2);
 
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point1_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    0, 0);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point2_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    0, 1);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    0, 2);
+static SENSOR_DEVICE_ATTR_2(pwm1_auto_point3_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    0, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point1_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    1, 0);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point2_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    1, 1);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    1, 2);
+static SENSOR_DEVICE_ATTR_2(pwm2_auto_point3_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    1, 2);
+
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point1_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    2, 0);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    2, 1);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_temp, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_temp, set_pwm_auto_point_temp,
+			    2, 2);
+static SENSOR_DEVICE_ATTR_2(pwm3_auto_point3_fan, S_IRUGO | S_IWUSR,
+			    show_pwm_auto_point_fan, set_pwm_auto_point_fan,
+			    2, 2);
+
 static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
 static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
 static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
@@ -1014,6 +1160,25 @@
 	&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
 	&sensor_dev_attr_temp3_type.dev_attr.attr,
 
+	&sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point1_fan.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_fan.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point3_fan.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point1_fan.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point2_fan.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point3_fan.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point1_fan.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point2_fan.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point3_fan.dev_attr.attr,
+
 	&sensor_dev_attr_in0_alarm.dev_attr.attr,
 	&sensor_dev_attr_in1_alarm.dev_attr.attr,
 	&sensor_dev_attr_in2_alarm.dev_attr.attr,
@@ -1242,12 +1407,12 @@
 	struct resource *res;
 	int i;
 
-	platform_set_drvdata(pdev, NULL);
 	hwmon_device_unregister(data->class_dev);
 	sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
 	for (i = 0; i < 4; i++)
 		sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]);
 	sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq);
+	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -1290,15 +1455,12 @@
 		goto exit_device_put;
 	}
 
-	pdev->dev.platform_data = kmalloc(sizeof(struct f71805f_sio_data),
-					  GFP_KERNEL);
-	if (!pdev->dev.platform_data) {
-		err = -ENOMEM;
+	err = platform_device_add_data(pdev, sio_data,
+				       sizeof(struct f71805f_sio_data));
+	if (err) {
 		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
 		goto exit_device_put;
 	}
-	memcpy(pdev->dev.platform_data, sio_data,
-	       sizeof(struct f71805f_sio_data));
 
 	err = platform_device_add(pdev);
 	if (err) {
diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c
index 1971775..b34b546 100644
--- a/drivers/hwmon/fscher.c
+++ b/drivers/hwmon/fscher.c
@@ -441,6 +441,8 @@
 		data->watchdog[2] = fscher_read_value(client, FSCHER_REG_WDOG_CONTROL);
 
 		data->global_event = fscher_read_value(client, FSCHER_REG_EVENT_STATE);
+		data->global_control = fscher_read_value(client,
+							FSCHER_REG_CONTROL);
 
 		data->last_updated = jiffies;
 		data->valid = 1;                 
@@ -599,7 +601,7 @@
 	unsigned long v = simple_strtoul(buf, NULL, 10) & 0x01;
 
 	mutex_lock(&data->update_lock);
-	data->global_control &= ~v;
+	data->global_control = v;
 	fscher_write_value(client, reg, v);
 	mutex_unlock(&data->update_lock);
 	return count;
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index e0cf5e6..a7c6d40 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -480,14 +480,14 @@
 /* Module stuff */
 
 /* hdaps_dmi_match - found a match.  return one, short-circuiting the hunt. */
-static int __init hdaps_dmi_match(struct dmi_system_id *id)
+static int __init hdaps_dmi_match(const struct dmi_system_id *id)
 {
 	printk(KERN_INFO "hdaps: %s detected.\n", id->ident);
 	return 1;
 }
 
 /* hdaps_dmi_match_invert - found an inverted match. */
-static int __init hdaps_dmi_match_invert(struct dmi_system_id *id)
+static int __init hdaps_dmi_match_invert(const struct dmi_system_id *id)
 {
 	hdaps_invert = 1;
 	printk(KERN_INFO "hdaps: inverting axis readings.\n");
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 62afc63..d75dba9 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -6,6 +6,7 @@
               IT8712F  Super I/O chip w/LPC interface
               IT8716F  Super I/O chip w/LPC interface
               IT8718F  Super I/O chip w/LPC interface
+              IT8726F  Super I/O chip w/LPC interface
               Sis950   A clone of the IT8705F
 
     Copyright (C) 2001 Chris Gauthron <chrisg@0-in.com> 
@@ -30,8 +31,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/hwmon-vid.h>
@@ -40,10 +40,12 @@
 #include <linux/sysfs.h>
 #include <asm/io.h>
 
+#define DRVNAME "it87"
 
-static unsigned short isa_address;
 enum chips { it87, it8712, it8716, it8718 };
 
+static struct platform_device *pdev;
+
 #define	REG	0x2e	/* The register to read/write */
 #define	DEV	0x07	/* Register: Logical device select */
 #define	VAL	0x2f	/* The value to read/write */
@@ -97,6 +99,7 @@
 #define IT8705F_DEVID 0x8705
 #define IT8716F_DEVID 0x8716
 #define IT8718F_DEVID 0x8718
+#define IT8726F_DEVID 0x8726
 #define IT87_ACT_REG  0x30
 #define IT87_BASE_REG 0x60
 
@@ -110,10 +113,6 @@
 /* Not all BIOSes properly configure the PWM registers */
 static int fix_pwm_polarity;
 
-/* Values read from Super-I/O config space */
-static u16 chip_type;
-static u8 vid_value;
-
 /* Many IT87 constants specified below */
 
 /* Length of ISA address segment */
@@ -214,13 +213,20 @@
 };
 
 
+struct it87_sio_data {
+	enum chips type;
+	/* Values read from Super-I/O config space */
+	u8 vid_value;
+};
+
 /* For each registered chip, we need to keep some data in memory.
    The structure is dynamically allocated. */
 struct it87_data {
-	struct i2c_client client;
 	struct class_device *class_dev;
 	enum chips type;
 
+	unsigned short addr;
+	const char *name;
 	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
@@ -245,26 +251,25 @@
 };
 
 
-static int it87_detect(struct i2c_adapter *adapter);
-static int it87_detach_client(struct i2c_client *client);
+static int it87_probe(struct platform_device *pdev);
+static int __devexit it87_remove(struct platform_device *pdev);
 
-static int it87_read_value(struct i2c_client *client, u8 reg);
-static void it87_write_value(struct i2c_client *client, u8 reg, u8 value);
+static int it87_read_value(struct it87_data *data, u8 reg);
+static void it87_write_value(struct it87_data *data, u8 reg, u8 value);
 static struct it87_data *it87_update_device(struct device *dev);
-static int it87_check_pwm(struct i2c_client *client);
-static void it87_init_client(struct i2c_client *client, struct it87_data *data);
+static int it87_check_pwm(struct device *dev);
+static void it87_init_device(struct platform_device *pdev);
 
 
-static struct i2c_driver it87_isa_driver = {
+static struct platform_driver it87_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
-		.name	= "it87-isa",
+		.name	= DRVNAME,
 	},
-	.attach_adapter	= it87_detect,
-	.detach_client	= it87_detach_client,
+	.probe	= it87_probe,
+	.remove	= __devexit_p(it87_remove),
 };
 
-
 static ssize_t show_in(struct device *dev, struct device_attribute *attr,
 		char *buf)
 {
@@ -301,13 +306,12 @@
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
+	struct it87_data *data = dev_get_drvdata(dev);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->in_min[nr] = IN_TO_REG(val);
-	it87_write_value(client, IT87_REG_VIN_MIN(nr), 
+	it87_write_value(data, IT87_REG_VIN_MIN(nr),
 			data->in_min[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -318,13 +322,12 @@
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
+	struct it87_data *data = dev_get_drvdata(dev);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->in_max[nr] = IN_TO_REG(val);
-	it87_write_value(client, IT87_REG_VIN_MAX(nr), 
+	it87_write_value(data, IT87_REG_VIN_MAX(nr),
 			data->in_max[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -392,13 +395,12 @@
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
+	struct it87_data *data = dev_get_drvdata(dev);
 	int val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->temp_high[nr] = TEMP_TO_REG(val);
-	it87_write_value(client, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]);
+	it87_write_value(data, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -408,13 +410,12 @@
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
+	struct it87_data *data = dev_get_drvdata(dev);
 	int val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->temp_low[nr] = TEMP_TO_REG(val);
-	it87_write_value(client, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]);
+	it87_write_value(data, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -451,8 +452,7 @@
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
+	struct it87_data *data = dev_get_drvdata(dev);
 	int val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
@@ -468,7 +468,7 @@
 		mutex_unlock(&data->update_lock);
 		return -EINVAL;
 	}
-	it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor);
+	it87_write_value(data, IT87_REG_TEMP_ENABLE, data->sensor);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -542,13 +542,12 @@
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
+	struct it87_data *data = dev_get_drvdata(dev);
 	int val = simple_strtol(buf, NULL, 10);
 	u8 reg;
 
 	mutex_lock(&data->update_lock);
-	reg = it87_read_value(client, IT87_REG_FAN_DIV);
+	reg = it87_read_value(data, IT87_REG_FAN_DIV);
 	switch (nr) {
 	case 0: data->fan_div[nr] = reg & 0x07; break;
 	case 1: data->fan_div[nr] = (reg >> 3) & 0x07; break;
@@ -556,7 +555,7 @@
 	}
 
 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
-	it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+	it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -566,14 +565,13 @@
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
+	struct it87_data *data = dev_get_drvdata(dev);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 	int min;
 	u8 old;
 
 	mutex_lock(&data->update_lock);
-	old = it87_read_value(client, IT87_REG_FAN_DIV);
+	old = it87_read_value(data, IT87_REG_FAN_DIV);
 
 	/* Save fan min limit */
 	min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]));
@@ -594,11 +592,11 @@
 	val |= (data->fan_div[1] & 0x07) << 3;
 	if (data->fan_div[2] == 3)
 		val |= 0x1 << 6;
-	it87_write_value(client, IT87_REG_FAN_DIV, val);
+	it87_write_value(data, IT87_REG_FAN_DIV, val);
 
 	/* Restore fan min limit */
 	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
-	it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+	it87_write_value(data, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
 
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -609,8 +607,7 @@
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
+	struct it87_data *data = dev_get_drvdata(dev);
 	int val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
@@ -618,17 +615,17 @@
 	if (val == 0) {
 		int tmp;
 		/* make sure the fan is on when in on/off mode */
-		tmp = it87_read_value(client, IT87_REG_FAN_CTL);
-		it87_write_value(client, IT87_REG_FAN_CTL, tmp | (1 << nr));
+		tmp = it87_read_value(data, IT87_REG_FAN_CTL);
+		it87_write_value(data, IT87_REG_FAN_CTL, tmp | (1 << nr));
 		/* set on/off mode */
 		data->fan_main_ctrl &= ~(1 << nr);
-		it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
+		it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
 	} else if (val == 1) {
 		/* set SmartGuardian mode */
 		data->fan_main_ctrl |= (1 << nr);
-		it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
+		it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
 		/* set saved pwm value, clear FAN_CTLX PWM mode bit */
-		it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
+		it87_write_value(data, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
 	} else {
 		mutex_unlock(&data->update_lock);
 		return -EINVAL;
@@ -643,8 +640,7 @@
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
+	struct it87_data *data = dev_get_drvdata(dev);
 	int val = simple_strtol(buf, NULL, 10);
 
 	if (val < 0 || val > 255)
@@ -653,15 +649,14 @@
 	mutex_lock(&data->update_lock);
 	data->manual_pwm_ctl[nr] = val;
 	if (data->fan_main_ctrl & (1 << nr))
-		it87_write_value(client, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
+		it87_write_value(data, IT87_REG_PWM(nr), PWM_TO_REG(data->manual_pwm_ctl[nr]));
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t set_pwm_freq(struct device *dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
+	struct it87_data *data = dev_get_drvdata(dev);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 	int i;
 
@@ -672,9 +667,9 @@
 	}
 
 	mutex_lock(&data->update_lock);
-	data->fan_ctl = it87_read_value(client, IT87_REG_FAN_CTL) & 0x8f;
+	data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL) & 0x8f;
 	data->fan_ctl |= i << 4;
-	it87_write_value(client, IT87_REG_FAN_CTL, data->fan_ctl);
+	it87_write_value(data, IT87_REG_FAN_CTL, data->fan_ctl);
 	mutex_unlock(&data->update_lock);
 
 	return count;
@@ -729,15 +724,14 @@
 {
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
+	struct it87_data *data = dev_get_drvdata(dev);
 	int val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->fan_min[nr] = FAN16_TO_REG(val);
-	it87_write_value(client, IT87_REG_FAN_MIN(nr),
+	it87_write_value(data, IT87_REG_FAN_MIN(nr),
 			 data->fan_min[nr] & 0xff);
-	it87_write_value(client, IT87_REG_FANX_MIN(nr),
+	it87_write_value(data, IT87_REG_FANX_MIN(nr),
 			 data->fan_min[nr] >> 8);
 	mutex_unlock(&data->update_lock);
 	return count;
@@ -775,8 +769,7 @@
 static ssize_t
 store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
+	struct it87_data *data = dev_get_drvdata(dev);
 	u32 val;
 
 	val = simple_strtoul(buf, NULL, 10);
@@ -794,6 +787,14 @@
 }
 static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
 
+static ssize_t show_name(struct device *dev, struct device_attribute
+			 *devattr, char *buf)
+{
+	struct it87_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
 static struct attribute *it87_attributes[] = {
 	&sensor_dev_attr_in0_input.dev_attr.attr,
 	&sensor_dev_attr_in1_input.dev_attr.attr,
@@ -835,6 +836,7 @@
 	&sensor_dev_attr_temp3_type.dev_attr.attr,
 
 	&dev_attr_alarms.attr,
+	&dev_attr_name.attr,
 	NULL
 };
 
@@ -877,17 +879,36 @@
 };
 
 /* SuperIO detection - will change isa_address if a chip is found */
-static int __init it87_find(unsigned short *address)
+static int __init it87_find(unsigned short *address,
+	struct it87_sio_data *sio_data)
 {
 	int err = -ENODEV;
+	u16 chip_type;
 
 	superio_enter();
 	chip_type = superio_inw(DEVID);
-	if (chip_type != IT8712F_DEVID
-	 && chip_type != IT8716F_DEVID
-	 && chip_type != IT8718F_DEVID
-	 && chip_type != IT8705F_DEVID)
-	 	goto exit;
+
+	switch (chip_type) {
+	case IT8705F_DEVID:
+		sio_data->type = it87;
+		break;
+	case IT8712F_DEVID:
+		sio_data->type = it8712;
+		break;
+	case IT8716F_DEVID:
+	case IT8726F_DEVID:
+		sio_data->type = it8716;
+		break;
+	case IT8718F_DEVID:
+		sio_data->type = it8718;
+		break;
+	case 0xffff:	/* No device at all */
+		goto exit;
+	default:
+		pr_debug(DRVNAME ": Unsupported chip (DEVID=0x%x)\n",
+			 chip_type);
+		goto exit;
+	}
 
 	superio_select(PME);
 	if (!(superio_inb(IT87_ACT_REG) & 0x01)) {
@@ -911,7 +932,7 @@
 
 		superio_select(GPIO);
 		if (chip_type == it8718)
-			vid_value = superio_inb(IT87_SIO_VID_REG);
+			sio_data->vid_value = superio_inb(IT87_SIO_VID_REG);
 
 		reg = superio_inb(IT87_SIO_PINX2_REG);
 		if (reg & (1 << 0))
@@ -925,18 +946,26 @@
 	return err;
 }
 
-/* This function is called by i2c_probe */
-static int it87_detect(struct i2c_adapter *adapter)
+static int __devinit it87_probe(struct platform_device *pdev)
 {
-	struct i2c_client *new_client;
 	struct it87_data *data;
+	struct resource *res;
+	struct device *dev = &pdev->dev;
+	struct it87_sio_data *sio_data = dev->platform_data;
 	int err = 0;
-	const char *name;
 	int enable_pwm_interface;
+	static const char *names[] = {
+		"it87",
+		"it8712",
+		"it8716",
+		"it8718",
+	};
 
-	/* Reserve the ISA region */
-	if (!request_region(isa_address, IT87_EXTENT,
-			    it87_isa_driver.driver.name)){
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!request_region(res->start, IT87_EXTENT, DRVNAME)) {
+		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+			(unsigned long)res->start,
+			(unsigned long)(res->start + IT87_EXTENT - 1));
 		err = -EBUSY;
 		goto ERROR0;
 	}
@@ -946,129 +975,104 @@
 		goto ERROR1;
 	}
 
-	new_client = &data->client;
-	i2c_set_clientdata(new_client, data);
-	new_client->addr = isa_address;
-	new_client->adapter = adapter;
-	new_client->driver = &it87_isa_driver;
+	data->addr = res->start;
+	data->type = sio_data->type;
+	data->name = names[sio_data->type];
 
 	/* Now, we do the remaining detection. */
-	if ((it87_read_value(new_client, IT87_REG_CONFIG) & 0x80)
-	 || it87_read_value(new_client, IT87_REG_CHIPID) != 0x90) {
+	if ((it87_read_value(data, IT87_REG_CONFIG) & 0x80)
+	 || it87_read_value(data, IT87_REG_CHIPID) != 0x90) {
 		err = -ENODEV;
 		goto ERROR2;
 	}
 
-	/* Determine the chip type. */
-	switch (chip_type) {
-	case IT8712F_DEVID:
-		data->type = it8712;
-		name = "it8712";
-		break;
-	case IT8716F_DEVID:
-		data->type = it8716;
-		name = "it8716";
-		break;
-	case IT8718F_DEVID:
-		data->type = it8718;
-		name = "it8718";
-		break;
-	default:
-		data->type = it87;
-		name = "it87";
-	}
+	platform_set_drvdata(pdev, data);
 
-	/* Fill in the remaining client fields and put it into the global list */
-	strlcpy(new_client->name, name, I2C_NAME_SIZE);
 	mutex_init(&data->update_lock);
 
-	/* Tell the I2C layer a new client has arrived */
-	if ((err = i2c_attach_client(new_client)))
-		goto ERROR2;
-
 	/* Check PWM configuration */
-	enable_pwm_interface = it87_check_pwm(new_client);
+	enable_pwm_interface = it87_check_pwm(dev);
 
 	/* Initialize the IT87 chip */
-	it87_init_client(new_client, data);
+	it87_init_device(pdev);
 
 	/* Register sysfs hooks */
-	if ((err = sysfs_create_group(&new_client->dev.kobj, &it87_group)))
-		goto ERROR3;
+	if ((err = sysfs_create_group(&dev->kobj, &it87_group)))
+		goto ERROR2;
 
 	/* Do not create fan files for disabled fans */
 	if (data->type == it8716 || data->type == it8718) {
 		/* 16-bit tachometers */
 		if (data->has_fan & (1 << 0)) {
-			if ((err = device_create_file(&new_client->dev,
+			if ((err = device_create_file(dev,
 			     &sensor_dev_attr_fan1_input16.dev_attr))
-			 || (err = device_create_file(&new_client->dev,
+			 || (err = device_create_file(dev,
 			     &sensor_dev_attr_fan1_min16.dev_attr)))
 				goto ERROR4;
 		}
 		if (data->has_fan & (1 << 1)) {
-			if ((err = device_create_file(&new_client->dev,
+			if ((err = device_create_file(dev,
 			     &sensor_dev_attr_fan2_input16.dev_attr))
-			 || (err = device_create_file(&new_client->dev,
+			 || (err = device_create_file(dev,
 			     &sensor_dev_attr_fan2_min16.dev_attr)))
 				goto ERROR4;
 		}
 		if (data->has_fan & (1 << 2)) {
-			if ((err = device_create_file(&new_client->dev,
+			if ((err = device_create_file(dev,
 			     &sensor_dev_attr_fan3_input16.dev_attr))
-			 || (err = device_create_file(&new_client->dev,
+			 || (err = device_create_file(dev,
 			     &sensor_dev_attr_fan3_min16.dev_attr)))
 				goto ERROR4;
 		}
 	} else {
 		/* 8-bit tachometers with clock divider */
 		if (data->has_fan & (1 << 0)) {
-			if ((err = device_create_file(&new_client->dev,
+			if ((err = device_create_file(dev,
 			     &sensor_dev_attr_fan1_input.dev_attr))
-			 || (err = device_create_file(&new_client->dev,
+			 || (err = device_create_file(dev,
 			     &sensor_dev_attr_fan1_min.dev_attr))
-			 || (err = device_create_file(&new_client->dev,
+			 || (err = device_create_file(dev,
 			     &sensor_dev_attr_fan1_div.dev_attr)))
 				goto ERROR4;
 		}
 		if (data->has_fan & (1 << 1)) {
-			if ((err = device_create_file(&new_client->dev,
+			if ((err = device_create_file(dev,
 			     &sensor_dev_attr_fan2_input.dev_attr))
-			 || (err = device_create_file(&new_client->dev,
+			 || (err = device_create_file(dev,
 			     &sensor_dev_attr_fan2_min.dev_attr))
-			 || (err = device_create_file(&new_client->dev,
+			 || (err = device_create_file(dev,
 			     &sensor_dev_attr_fan2_div.dev_attr)))
 				goto ERROR4;
 		}
 		if (data->has_fan & (1 << 2)) {
-			if ((err = device_create_file(&new_client->dev,
+			if ((err = device_create_file(dev,
 			     &sensor_dev_attr_fan3_input.dev_attr))
-			 || (err = device_create_file(&new_client->dev,
+			 || (err = device_create_file(dev,
 			     &sensor_dev_attr_fan3_min.dev_attr))
-			 || (err = device_create_file(&new_client->dev,
+			 || (err = device_create_file(dev,
 			     &sensor_dev_attr_fan3_div.dev_attr)))
 				goto ERROR4;
 		}
 	}
 
 	if (enable_pwm_interface) {
-		if ((err = device_create_file(&new_client->dev,
+		if ((err = device_create_file(dev,
 		     &sensor_dev_attr_pwm1_enable.dev_attr))
-		 || (err = device_create_file(&new_client->dev,
+		 || (err = device_create_file(dev,
 		     &sensor_dev_attr_pwm2_enable.dev_attr))
-		 || (err = device_create_file(&new_client->dev,
+		 || (err = device_create_file(dev,
 		     &sensor_dev_attr_pwm3_enable.dev_attr))
-		 || (err = device_create_file(&new_client->dev,
+		 || (err = device_create_file(dev,
 		     &sensor_dev_attr_pwm1.dev_attr))
-		 || (err = device_create_file(&new_client->dev,
+		 || (err = device_create_file(dev,
 		     &sensor_dev_attr_pwm2.dev_attr))
-		 || (err = device_create_file(&new_client->dev,
+		 || (err = device_create_file(dev,
 		     &sensor_dev_attr_pwm3.dev_attr))
-		 || (err = device_create_file(&new_client->dev,
+		 || (err = device_create_file(dev,
 		     &dev_attr_pwm1_freq))
-		 || (err = device_create_file(&new_client->dev,
+		 || (err = device_create_file(dev,
 		     &dev_attr_pwm2_freq))
-		 || (err = device_create_file(&new_client->dev,
+		 || (err = device_create_file(dev,
 		     &dev_attr_pwm3_freq)))
 			goto ERROR4;
 	}
@@ -1077,15 +1081,15 @@
 	 || data->type == it8718) {
 		data->vrm = vid_which_vrm();
 		/* VID reading from Super-I/O config space if available */
-		data->vid = vid_value;
-		if ((err = device_create_file(&new_client->dev,
+		data->vid = sio_data->vid_value;
+		if ((err = device_create_file(dev,
 		     &dev_attr_vrm))
-		 || (err = device_create_file(&new_client->dev,
+		 || (err = device_create_file(dev,
 		     &dev_attr_cpu0_vid)))
 			goto ERROR4;
 	}
 
-	data->class_dev = hwmon_device_register(&new_client->dev);
+	data->class_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->class_dev)) {
 		err = PTR_ERR(data->class_dev);
 		goto ERROR4;
@@ -1094,31 +1098,27 @@
 	return 0;
 
 ERROR4:
-	sysfs_remove_group(&new_client->dev.kobj, &it87_group);
-	sysfs_remove_group(&new_client->dev.kobj, &it87_group_opt);
-ERROR3:
-	i2c_detach_client(new_client);
+	sysfs_remove_group(&dev->kobj, &it87_group);
+	sysfs_remove_group(&dev->kobj, &it87_group_opt);
 ERROR2:
+	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 ERROR1:
-	release_region(isa_address, IT87_EXTENT);
+	release_region(res->start, IT87_EXTENT);
 ERROR0:
 	return err;
 }
 
-static int it87_detach_client(struct i2c_client *client)
+static int __devexit it87_remove(struct platform_device *pdev)
 {
-	struct it87_data *data = i2c_get_clientdata(client);
-	int err;
+	struct it87_data *data = platform_get_drvdata(pdev);
 
 	hwmon_device_unregister(data->class_dev);
-	sysfs_remove_group(&client->dev.kobj, &it87_group);
-	sysfs_remove_group(&client->dev.kobj, &it87_group_opt);
+	sysfs_remove_group(&pdev->dev.kobj, &it87_group);
+	sysfs_remove_group(&pdev->dev.kobj, &it87_group_opt);
 
-	if ((err = i2c_detach_client(client)))
-		return err;
-
-	release_region(client->addr, IT87_EXTENT);
+	release_region(data->addr, IT87_EXTENT);
+	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 
 	return 0;
@@ -1127,28 +1127,29 @@
 /* Must be called with data->update_lock held, except during initialization.
    We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
    would slow down the IT87 access and should not be necessary. */
-static int it87_read_value(struct i2c_client *client, u8 reg)
+static int it87_read_value(struct it87_data *data, u8 reg)
 {
-	outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
-	return inb_p(client->addr + IT87_DATA_REG_OFFSET);
+	outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
+	return inb_p(data->addr + IT87_DATA_REG_OFFSET);
 }
 
 /* Must be called with data->update_lock held, except during initialization.
    We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,
    would slow down the IT87 access and should not be necessary. */
-static void it87_write_value(struct i2c_client *client, u8 reg, u8 value)
+static void it87_write_value(struct it87_data *data, u8 reg, u8 value)
 {
-	outb_p(reg, client->addr + IT87_ADDR_REG_OFFSET);
-	outb_p(value, client->addr + IT87_DATA_REG_OFFSET);
+	outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);
+	outb_p(value, data->addr + IT87_DATA_REG_OFFSET);
 }
 
 /* Return 1 if and only if the PWM interface is safe to use */
-static int it87_check_pwm(struct i2c_client *client)
+static int __devinit it87_check_pwm(struct device *dev)
 {
+	struct it87_data *data = dev_get_drvdata(dev);
 	/* Some BIOSes fail to correctly configure the IT87 fans. All fans off
 	 * and polarity set to active low is sign that this is the case so we
 	 * disable pwm control to protect the user. */
-	int tmp = it87_read_value(client, IT87_REG_FAN_CTL);
+	int tmp = it87_read_value(data, IT87_REG_FAN_CTL);
 	if ((tmp & 0x87) == 0) {
 		if (fix_pwm_polarity) {
 			/* The user asks us to attempt a chip reconfiguration.
@@ -1158,7 +1159,7 @@
 			u8 pwm[3];
 
 			for (i = 0; i < 3; i++)
-				pwm[i] = it87_read_value(client,
+				pwm[i] = it87_read_value(data,
 							 IT87_REG_PWM(i));
 
 			/* If any fan is in automatic pwm mode, the polarity
@@ -1166,26 +1167,26 @@
 			 * better don't change anything (but still disable the
 			 * PWM interface). */
 			if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) {
-				dev_info(&client->dev, "Reconfiguring PWM to "
+				dev_info(dev, "Reconfiguring PWM to "
 					 "active high polarity\n");
-				it87_write_value(client, IT87_REG_FAN_CTL,
+				it87_write_value(data, IT87_REG_FAN_CTL,
 						 tmp | 0x87);
 				for (i = 0; i < 3; i++)
-					it87_write_value(client,
+					it87_write_value(data,
 							 IT87_REG_PWM(i),
 							 0x7f & ~pwm[i]);
 				return 1;
 			}
 
-			dev_info(&client->dev, "PWM configuration is "
+			dev_info(dev, "PWM configuration is "
 				 "too broken to be fixed\n");
 		}
 
-		dev_info(&client->dev, "Detected broken BIOS "
+		dev_info(dev, "Detected broken BIOS "
 			 "defaults, disabling PWM interface\n");
 		return 0;
 	} else if (fix_pwm_polarity) {
-		dev_info(&client->dev, "PWM configuration looks "
+		dev_info(dev, "PWM configuration looks "
 			 "sane, won't touch\n");
 	}
 
@@ -1193,8 +1194,9 @@
 }
 
 /* Called when we have found a new IT87. */
-static void it87_init_client(struct i2c_client *client, struct it87_data *data)
+static void __devinit it87_init_device(struct platform_device *pdev)
 {
+	struct it87_data *data = platform_get_drvdata(pdev);
 	int tmp, i;
 
 	/* initialize to sane defaults:
@@ -1214,48 +1216,48 @@
 	 * means -1 degree C, which surprisingly doesn't trigger an alarm,
 	 * but is still confusing, so change to 127 degrees C. */
 	for (i = 0; i < 8; i++) {
-		tmp = it87_read_value(client, IT87_REG_VIN_MIN(i));
+		tmp = it87_read_value(data, IT87_REG_VIN_MIN(i));
 		if (tmp == 0xff)
-			it87_write_value(client, IT87_REG_VIN_MIN(i), 0);
+			it87_write_value(data, IT87_REG_VIN_MIN(i), 0);
 	}
 	for (i = 0; i < 3; i++) {
-		tmp = it87_read_value(client, IT87_REG_TEMP_HIGH(i));
+		tmp = it87_read_value(data, IT87_REG_TEMP_HIGH(i));
 		if (tmp == 0xff)
-			it87_write_value(client, IT87_REG_TEMP_HIGH(i), 127);
+			it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127);
 	}
 
 	/* Check if temperature channnels are reset manually or by some reason */
-	tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE);
+	tmp = it87_read_value(data, IT87_REG_TEMP_ENABLE);
 	if ((tmp & 0x3f) == 0) {
 		/* Temp1,Temp3=thermistor; Temp2=thermal diode */
 		tmp = (tmp & 0xc0) | 0x2a;
-		it87_write_value(client, IT87_REG_TEMP_ENABLE, tmp);
+		it87_write_value(data, IT87_REG_TEMP_ENABLE, tmp);
 	}
 	data->sensor = tmp;
 
 	/* Check if voltage monitors are reset manually or by some reason */
-	tmp = it87_read_value(client, IT87_REG_VIN_ENABLE);
+	tmp = it87_read_value(data, IT87_REG_VIN_ENABLE);
 	if ((tmp & 0xff) == 0) {
 		/* Enable all voltage monitors */
-		it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff);
+		it87_write_value(data, IT87_REG_VIN_ENABLE, 0xff);
 	}
 
 	/* Check if tachometers are reset manually or by some reason */
-	data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL);
+	data->fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL);
 	if ((data->fan_main_ctrl & 0x70) == 0) {
 		/* Enable all fan tachometers */
 		data->fan_main_ctrl |= 0x70;
-		it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
+		it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
 	}
 	data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
 
 	/* Set tachometers to 16-bit mode if needed */
 	if (data->type == it8716 || data->type == it8718) {
-		tmp = it87_read_value(client, IT87_REG_FAN_16BIT);
+		tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
 		if (~tmp & 0x07 & data->has_fan) {
-			dev_dbg(&client->dev,
+			dev_dbg(&pdev->dev,
 				"Setting fan1-3 to 16-bit mode\n");
-			it87_write_value(client, IT87_REG_FAN_16BIT,
+			it87_write_value(data, IT87_REG_FAN_16BIT,
 					 tmp | 0x07);
 		}
 	}
@@ -1265,7 +1267,7 @@
 	for (i = 0; i < 3; i++) {
 		if (data->fan_main_ctrl & (1 << i)) {
 			/* pwm mode */
-			tmp = it87_read_value(client, IT87_REG_PWM(i));
+			tmp = it87_read_value(data, IT87_REG_PWM(i));
 			if (tmp & 0x80) {
 				/* automatic pwm - not yet implemented, but
 				 * leave the settings made by the BIOS alone
@@ -1279,15 +1281,14 @@
  	}
 
 	/* Start monitoring */
-	it87_write_value(client, IT87_REG_CONFIG,
-			 (it87_read_value(client, IT87_REG_CONFIG) & 0x36)
+	it87_write_value(data, IT87_REG_CONFIG,
+			 (it87_read_value(data, IT87_REG_CONFIG) & 0x36)
 			 | (update_vbat ? 0x41 : 0x01));
 }
 
 static struct it87_data *it87_update_device(struct device *dev)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct it87_data *data = i2c_get_clientdata(client);
+	struct it87_data *data = dev_get_drvdata(dev);
 	int i;
 
 	mutex_lock(&data->update_lock);
@@ -1298,20 +1299,20 @@
 		if (update_vbat) {
 			/* Cleared after each update, so reenable.  Value
 		 	  returned by this read will be previous value */	
-			it87_write_value(client, IT87_REG_CONFIG,
-			   it87_read_value(client, IT87_REG_CONFIG) | 0x40);
+			it87_write_value(data, IT87_REG_CONFIG,
+			   it87_read_value(data, IT87_REG_CONFIG) | 0x40);
 		}
 		for (i = 0; i <= 7; i++) {
 			data->in[i] =
-			    it87_read_value(client, IT87_REG_VIN(i));
+			    it87_read_value(data, IT87_REG_VIN(i));
 			data->in_min[i] =
-			    it87_read_value(client, IT87_REG_VIN_MIN(i));
+			    it87_read_value(data, IT87_REG_VIN_MIN(i));
 			data->in_max[i] =
-			    it87_read_value(client, IT87_REG_VIN_MAX(i));
+			    it87_read_value(data, IT87_REG_VIN_MAX(i));
 		}
 		/* in8 (battery) has no limit registers */
 		data->in[8] =
-		    it87_read_value(client, IT87_REG_VIN(8));
+		    it87_read_value(data, IT87_REG_VIN(8));
 
 		for (i = 0; i < 3; i++) {
 			/* Skip disabled fans */
@@ -1319,46 +1320,47 @@
 				continue;
 
 			data->fan_min[i] =
-			    it87_read_value(client, IT87_REG_FAN_MIN(i));
-			data->fan[i] = it87_read_value(client,
+			    it87_read_value(data, IT87_REG_FAN_MIN(i));
+			data->fan[i] = it87_read_value(data,
 				       IT87_REG_FAN(i));
 			/* Add high byte if in 16-bit mode */
 			if (data->type == it8716 || data->type == it8718) {
-				data->fan[i] |= it87_read_value(client,
+				data->fan[i] |= it87_read_value(data,
 						IT87_REG_FANX(i)) << 8;
-				data->fan_min[i] |= it87_read_value(client,
+				data->fan_min[i] |= it87_read_value(data,
 						IT87_REG_FANX_MIN(i)) << 8;
 			}
 		}
 		for (i = 0; i < 3; i++) {
 			data->temp[i] =
-			    it87_read_value(client, IT87_REG_TEMP(i));
+			    it87_read_value(data, IT87_REG_TEMP(i));
 			data->temp_high[i] =
-			    it87_read_value(client, IT87_REG_TEMP_HIGH(i));
+			    it87_read_value(data, IT87_REG_TEMP_HIGH(i));
 			data->temp_low[i] =
-			    it87_read_value(client, IT87_REG_TEMP_LOW(i));
+			    it87_read_value(data, IT87_REG_TEMP_LOW(i));
 		}
 
 		/* Newer chips don't have clock dividers */
 		if ((data->has_fan & 0x07) && data->type != it8716
 		 && data->type != it8718) {
-			i = it87_read_value(client, IT87_REG_FAN_DIV);
+			i = it87_read_value(data, IT87_REG_FAN_DIV);
 			data->fan_div[0] = i & 0x07;
 			data->fan_div[1] = (i >> 3) & 0x07;
 			data->fan_div[2] = (i & 0x40) ? 3 : 1;
 		}
 
 		data->alarms =
-			it87_read_value(client, IT87_REG_ALARM1) |
-			(it87_read_value(client, IT87_REG_ALARM2) << 8) |
-			(it87_read_value(client, IT87_REG_ALARM3) << 16);
-		data->fan_main_ctrl = it87_read_value(client, IT87_REG_FAN_MAIN_CTRL);
-		data->fan_ctl = it87_read_value(client, IT87_REG_FAN_CTL);
+			it87_read_value(data, IT87_REG_ALARM1) |
+			(it87_read_value(data, IT87_REG_ALARM2) << 8) |
+			(it87_read_value(data, IT87_REG_ALARM3) << 16);
+		data->fan_main_ctrl = it87_read_value(data,
+				IT87_REG_FAN_MAIN_CTRL);
+		data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);
 
-		data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE);
+		data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);
 		/* The 8705 does not have VID capability */
 		if (data->type == it8712 || data->type == it8716) {
-			data->vid = it87_read_value(client, IT87_REG_VID);
+			data->vid = it87_read_value(data, IT87_REG_VID);
 			/* The older IT8712F revisions had only 5 VID pins,
 			   but we assume it is always safe to read 6 bits. */
 			data->vid &= 0x3f;
@@ -1372,24 +1374,85 @@
 	return data;
 }
 
+static int __init it87_device_add(unsigned short address,
+				  const struct it87_sio_data *sio_data)
+{
+	struct resource res = {
+		.start	= address ,
+		.end	= address + IT87_EXTENT - 1,
+		.name	= DRVNAME,
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	pdev = platform_device_alloc(DRVNAME, address);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device resource addition failed "
+		       "(%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add_data(pdev, sio_data,
+				       sizeof(struct it87_sio_data));
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
 static int __init sm_it87_init(void)
 {
-	int res;
+	int err;
+	unsigned short isa_address=0;
+	struct it87_sio_data sio_data;
 
-	if ((res = it87_find(&isa_address)))
-		return res;
-	return i2c_isa_add_driver(&it87_isa_driver);
+	err = it87_find(&isa_address, &sio_data);
+	if (err)
+		return err;
+	err = platform_driver_register(&it87_driver);
+	if (err)
+		return err;
+
+	err = it87_device_add(isa_address, &sio_data);
+	if (err){
+		platform_driver_unregister(&it87_driver);
+		return err;
+	}
+
+	return 0;
 }
 
 static void __exit sm_it87_exit(void)
 {
-	i2c_isa_del_driver(&it87_isa_driver);
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&it87_driver);
 }
 
 
 MODULE_AUTHOR("Chris Gauthron <chrisg@0-in.com>, "
 	      "Jean Delvare <khali@linux-fr.org>");
-MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F, SiS950 driver");
+MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F/8726F, SiS950 driver");
 module_param(update_vbat, bool, 0);
 MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
 module_param(fix_pwm_polarity, bool, 0);
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index d69f3cf..2162d69 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -364,7 +364,7 @@
 /* Individual alarm files */
 static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
 static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
 static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
 static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
@@ -383,7 +383,7 @@
 	&dev_attr_temp2_crit_hyst.attr,
 
 	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
-	&sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
 	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
 	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
 	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 9fb572f..6eea347 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -864,7 +864,7 @@
 	/* Determine the chip type */
 	outb_p(LM78_REG_CHIPID, address + LM78_ADDR_REG_OFFSET);
 	val = inb_p(address + LM78_DATA_REG_OFFSET);
-	if (val == 0x00			/* LM78 */
+	if (val == 0x00 || val == 0x20	/* LM78 */
 	 || val == 0x40			/* LM78-J */
 	 || (val & 0xfe) == 0xc0)	/* LM79 */
 		found = 1;
@@ -882,7 +882,7 @@
 {
 	struct resource res = {
 		.start	= address,
-		.end	= address + LM78_EXTENT,
+		.end	= address + LM78_EXTENT - 1,
 		.name	= "lm78",
 		.flags	= IORESOURCE_IO,
 	};
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
index feb87b4..654c0f7 100644
--- a/drivers/hwmon/lm83.c
+++ b/drivers/hwmon/lm83.c
@@ -223,14 +223,14 @@
 /* Individual alarm files */
 static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 2);
 static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 4);
 static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
 static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 8);
 static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
-static SENSOR_DEVICE_ATTR(temp4_input_fault, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_alarm, NULL, 10);
 static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 12);
-static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 13);
 static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 15);
 /* Raw alarm file for compatibility */
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
@@ -245,7 +245,7 @@
 
 	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
 	&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
-	&sensor_dev_attr_temp3_input_fault.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
 	&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
 	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
 	&dev_attr_alarms.attr,
@@ -266,9 +266,9 @@
 
 	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
 	&sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
-	&sensor_dev_attr_temp4_input_fault.dev_attr.attr,
+	&sensor_dev_attr_temp4_fault.dev_attr.attr,
 	&sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
-	&sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
 	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
 	NULL
 };
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index 6882ce7..af541d6 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -43,6 +43,13 @@
  * variants. The extra address and features of the MAX6659 are not
  * supported by this driver.
  *
+ * This driver also supports the MAX6680 and MAX6681, two other sensor
+ * chips made by Maxim. These are quite similar to the other Maxim
+ * chips. Complete datasheet can be obtained at:
+ *   http://www.maxim-ic.com/quick_view2.cfm/qv_pk/3370
+ * The MAX6680 and MAX6681 only differ in the pinout so they can be
+ * treated identically.
+ *
  * This driver also supports the ADT7461 chip from Analog Devices but
  * only in its "compatability mode". If an ADT7461 chip is found but
  * is configured in non-compatible mode (where its temperature
@@ -84,20 +91,25 @@
 /*
  * Addresses to scan
  * Address is fully defined internally and cannot be changed except for
- * MAX6659.
+ * MAX6659, MAX6680 and MAX6681.
  * LM86, LM89, LM90, LM99, ADM1032, ADM1032-1, ADT7461, MAX6657 and MAX6658
  * have address 0x4c.
  * ADM1032-2, ADT7461-2, LM89-1, and LM99-1 have address 0x4d.
  * MAX6659 can have address 0x4c, 0x4d or 0x4e (unsupported).
+ * MAX6680 and MAX6681 can have address 0x18, 0x19, 0x1a, 0x29, 0x2a, 0x2b,
+ * 0x4c, 0x4d or 0x4e.
  */
 
-static unsigned short normal_i2c[] = { 0x4c, 0x4d, I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
+				       0x29, 0x2a, 0x2b,
+				       0x4c, 0x4d, 0x4e,
+				       I2C_CLIENT_END };
 
 /*
  * Insmod parameters
  */
 
-I2C_CLIENT_INSMOD_6(lm90, adm1032, lm99, lm86, max6657, adt7461);
+I2C_CLIENT_INSMOD_7(lm90, adm1032, lm99, lm86, max6657, adt7461, max6680);
 
 /*
  * The LM90 registers
@@ -359,7 +371,7 @@
 /* Individual alarm files */
 static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2);
 static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
 static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
 static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
@@ -381,7 +393,7 @@
 
 	&sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
 	&sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
-	&sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
 	&sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
 	&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
 	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
@@ -429,7 +441,7 @@
  */
 
 /* The ADM1032 supports PEC but not on write byte transactions, so we need
-   to explicitely ask for a transaction without PEC. */
+   to explicitly ask for a transaction without PEC. */
 static inline s32 adm1032_write_byte(struct i2c_client *client, u8 value)
 {
 	return i2c_smbus_xfer(client->adapter, client->addr,
@@ -525,7 +537,8 @@
 		 		  &reg_convrate) < 0)
 			goto exit_free;
 		
-		if (man_id == 0x01) { /* National Semiconductor */
+		if ((address == 0x4C || address == 0x4D)
+		 && man_id == 0x01) { /* National Semiconductor */
 			u8 reg_config2;
 
 			if (lm90_read_reg(new_client, LM90_REG_R_CONFIG2,
@@ -548,7 +561,8 @@
 				}
 			}
 		} else
-		if (man_id == 0x41) { /* Analog Devices */
+		if ((address == 0x4C || address == 0x4D)
+		 && man_id == 0x41) { /* Analog Devices */
 			if ((chip_id & 0xF0) == 0x40 /* ADM1032 */
 			 && (reg_config1 & 0x3F) == 0x00
 			 && reg_convrate <= 0x0A) {
@@ -562,18 +576,30 @@
 		} else
 		if (man_id == 0x4D) { /* Maxim */
 			/*
-			 * The Maxim variants do NOT have a chip_id register.
-			 * Reading from that address will return the last read
-			 * value, which in our case is those of the man_id
-			 * register. Likewise, the config1 register seems to
-			 * lack a low nibble, so the value will be those of the
-			 * previous read, so in our case those of the man_id
-			 * register.
+			 * The MAX6657, MAX6658 and MAX6659 do NOT have a
+			 * chip_id register. Reading from that address will
+			 * return the last read value, which in our case is
+			 * those of the man_id register. Likewise, the config1
+			 * register seems to lack a low nibble, so the value
+			 * will be those of the previous read, so in our case
+			 * those of the man_id register.
 			 */
 			if (chip_id == man_id
+			 && (address == 0x4C || address == 0x4D)
 			 && (reg_config1 & 0x1F) == (man_id & 0x0F)
 			 && reg_convrate <= 0x09) {
 			 	kind = max6657;
+			} else
+			/* The chip_id register of the MAX6680 and MAX6681
+			 * holds the revision of the chip.
+			 * the lowest bit of the config1 register is unused
+			 * and should return zero when read, so should the
+			 * second to last bit of config1 (software reset)
+			 */
+			if (chip_id == 0x01
+			 && (reg_config1 & 0x03) == 0x00
+			 && reg_convrate <= 0x07) {
+			 	kind = max6680;
 			}
 		}
 
@@ -599,6 +625,8 @@
 		name = "lm86";
 	} else if (kind == max6657) {
 		name = "max6657";
+	} else if (kind == max6680) {
+		name = "max6680";
 	} else if (kind == adt7461) {
 		name = "adt7461";
 	}
@@ -646,7 +674,8 @@
 
 static void lm90_init_client(struct i2c_client *client)
 {
-	u8 config;
+	u8 config, config_orig;
+	struct lm90_data *data = i2c_get_clientdata(client);
 
 	/*
 	 * Start the conversions.
@@ -657,9 +686,20 @@
 		dev_warn(&client->dev, "Initialization failed!\n");
 		return;
 	}
-	if (config & 0x40)
-		i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1,
-					  config & 0xBF); /* run */
+	config_orig = config;
+
+	/*
+	 * Put MAX6680/MAX8881 into extended resolution (bit 0x10,
+	 * 0.125 degree resolution) and range (0x08, extend range
+	 * to -64 degree) mode for the remote temperature sensor.
+	 */
+	if (data->kind == max6680) {
+		config |= 0x18;
+	}
+
+	config &= 0xBF;	/* run */
+	if (config != config_orig) /* Only write if changed */
+		i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
 }
 
 static int lm90_detach_client(struct i2c_client *client)
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
new file mode 100644
index 0000000..d84f8bf
--- /dev/null
+++ b/drivers/hwmon/lm93.c
@@ -0,0 +1,2655 @@
+/*
+    lm93.c - Part of lm_sensors, Linux kernel modules for hardware monitoring
+
+    Author/Maintainer: Mark M. Hoffman <mhoffman@lightlink.com>
+	Copyright (c) 2004 Utilitek Systems, Inc.
+
+    derived in part from lm78.c:
+	Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
+
+    derived in part from lm85.c:
+	Copyright (c) 2002, 2003 Philip Pokorny <ppokorny@penguincomputing.com>
+	Copyright (c) 2003       Margit Schubert-While <margitsw@t-online.de>
+
+    derived in part from w83l785ts.c:
+	Copyright (c) 2003-2004 Jean Delvare <khali@linux-fr.org>
+
+    Ported to Linux 2.6 by Eric J. Bowersox <ericb@aspsys.com>
+	Copyright (c) 2005 Aspen Systems, Inc.
+
+    Adapted to 2.6.20 by Carsten Emde <cbe@osadl.org>
+        Copyright (c) 2006 Carsten Emde, Open Source Automation Development Lab
+
+    Modified for mainline integration by Hans J. Koch <hjk@linutronix.de>
+        Copyright (c) 2007 Hans J. Koch, Linutronix GmbH
+
+    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.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+
+/* LM93 REGISTER ADDRESSES */
+
+/* miscellaneous */
+#define LM93_REG_MFR_ID			0x3e
+#define LM93_REG_VER			0x3f
+#define LM93_REG_STATUS_CONTROL		0xe2
+#define LM93_REG_CONFIG			0xe3
+#define LM93_REG_SLEEP_CONTROL		0xe4
+
+/* alarm values start here */
+#define LM93_REG_HOST_ERROR_1		0x48
+
+/* voltage inputs: in1-in16 (nr => 0-15) */
+#define LM93_REG_IN(nr)			(0x56 + (nr))
+#define LM93_REG_IN_MIN(nr)		(0x90 + (nr) * 2)
+#define LM93_REG_IN_MAX(nr)		(0x91 + (nr) * 2)
+
+/* temperature inputs: temp1-temp4 (nr => 0-3) */
+#define LM93_REG_TEMP(nr)		(0x50 + (nr))
+#define LM93_REG_TEMP_MIN(nr)		(0x78 + (nr) * 2)
+#define LM93_REG_TEMP_MAX(nr)		(0x79 + (nr) * 2)
+
+/* temp[1-4]_auto_boost (nr => 0-3) */
+#define LM93_REG_BOOST(nr)		(0x80 + (nr))
+
+/* #PROCHOT inputs: prochot1-prochot2 (nr => 0-1) */
+#define LM93_REG_PROCHOT_CUR(nr)	(0x67 + (nr) * 2)
+#define LM93_REG_PROCHOT_AVG(nr)	(0x68 + (nr) * 2)
+#define LM93_REG_PROCHOT_MAX(nr)	(0xb0 + (nr))
+
+/* fan tach inputs: fan1-fan4 (nr => 0-3) */
+#define LM93_REG_FAN(nr)		(0x6e + (nr) * 2)
+#define LM93_REG_FAN_MIN(nr)		(0xb4 + (nr) * 2)
+
+/* pwm outputs: pwm1-pwm2 (nr => 0-1, reg => 0-3) */
+#define LM93_REG_PWM_CTL(nr,reg)	(0xc8 + (reg) + (nr) * 4)
+#define LM93_PWM_CTL1	0x0
+#define LM93_PWM_CTL2	0x1
+#define LM93_PWM_CTL3	0x2
+#define LM93_PWM_CTL4	0x3
+
+/* GPIO input state */
+#define LM93_REG_GPI			0x6b
+
+/* vid inputs: vid1-vid2 (nr => 0-1) */
+#define LM93_REG_VID(nr)		(0x6c + (nr))
+
+/* vccp1 & vccp2: VID relative inputs (nr => 0-1) */
+#define LM93_REG_VCCP_LIMIT_OFF(nr)	(0xb2 + (nr))
+
+/* temp[1-4]_auto_boost_hyst */
+#define LM93_REG_BOOST_HYST_12		0xc0
+#define LM93_REG_BOOST_HYST_34		0xc1
+#define LM93_REG_BOOST_HYST(nr)		(0xc0 + (nr)/2)
+
+/* temp[1-4]_auto_pwm_[min|hyst] */
+#define LM93_REG_PWM_MIN_HYST_12	0xc3
+#define LM93_REG_PWM_MIN_HYST_34	0xc4
+#define LM93_REG_PWM_MIN_HYST(nr)	(0xc3 + (nr)/2)
+
+/* prochot_override & prochot_interval */
+#define LM93_REG_PROCHOT_OVERRIDE	0xc6
+#define LM93_REG_PROCHOT_INTERVAL	0xc7
+
+/* temp[1-4]_auto_base (nr => 0-3) */
+#define LM93_REG_TEMP_BASE(nr)		(0xd0 + (nr))
+
+/* temp[1-4]_auto_offsets (step => 0-11) */
+#define LM93_REG_TEMP_OFFSET(step)	(0xd4 + (step))
+
+/* #PROCHOT & #VRDHOT PWM ramp control */
+#define LM93_REG_PWM_RAMP_CTL		0xbf
+
+/* miscellaneous */
+#define LM93_REG_SFC1		0xbc
+#define LM93_REG_SFC2		0xbd
+#define LM93_REG_GPI_VID_CTL	0xbe
+#define LM93_REG_SF_TACH_TO_PWM	0xe0
+
+/* error masks */
+#define LM93_REG_GPI_ERR_MASK	0xec
+#define LM93_REG_MISC_ERR_MASK	0xed
+
+/* LM93 REGISTER VALUES */
+#define LM93_MFR_ID		0x73
+#define LM93_MFR_ID_PROTOTYPE	0x72
+
+/* SMBus capabilities */
+#define LM93_SMBUS_FUNC_FULL (I2C_FUNC_SMBUS_BYTE_DATA | \
+		I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA)
+#define LM93_SMBUS_FUNC_MIN  (I2C_FUNC_SMBUS_BYTE_DATA | \
+		I2C_FUNC_SMBUS_WORD_DATA)
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_1(lm93);
+
+static int disable_block;
+module_param(disable_block, bool, 0);
+MODULE_PARM_DESC(disable_block,
+	"Set to non-zero to disable SMBus block data transactions.");
+
+static int init;
+module_param(init, bool, 0);
+MODULE_PARM_DESC(init, "Set to non-zero to force chip initialization.");
+
+static int vccp_limit_type[2] = {0,0};
+module_param_array(vccp_limit_type, int, NULL, 0);
+MODULE_PARM_DESC(vccp_limit_type, "Configures in7 and in8 limit modes.");
+
+static int vid_agtl;
+module_param(vid_agtl, int, 0);
+MODULE_PARM_DESC(vid_agtl, "Configures VID pin input thresholds.");
+
+/* Driver data */
+static struct i2c_driver lm93_driver;
+
+/* LM93 BLOCK READ COMMANDS */
+static const struct { u8 cmd; u8 len; } lm93_block_read_cmds[12] = {
+	{ 0xf2,  8 },
+	{ 0xf3,  8 },
+	{ 0xf4,  6 },
+	{ 0xf5, 16 },
+	{ 0xf6,  4 },
+	{ 0xf7,  8 },
+	{ 0xf8, 12 },
+	{ 0xf9, 32 },
+	{ 0xfa,  8 },
+	{ 0xfb,  8 },
+	{ 0xfc, 16 },
+	{ 0xfd,  9 },
+};
+
+/* ALARMS: SYSCTL format described further below
+   REG: 64 bits in 8 registers, as immediately below */
+struct block1_t {
+	u8 host_status_1;
+	u8 host_status_2;
+	u8 host_status_3;
+	u8 host_status_4;
+	u8 p1_prochot_status;
+	u8 p2_prochot_status;
+	u8 gpi_status;
+	u8 fan_status;
+};
+
+/*
+ * Client-specific data
+ */
+struct lm93_data {
+	struct i2c_client client;
+	struct class_device *class_dev;
+
+	struct mutex update_lock;
+	unsigned long last_updated;	/* In jiffies */
+
+	/* client update function */
+	void (*update)(struct lm93_data *, struct i2c_client *);
+
+	char valid; /* !=0 if following fields are valid */
+
+	/* register values, arranged by block read groups */
+	struct block1_t block1;
+
+	/* temp1 - temp4: unfiltered readings
+	   temp1 - temp2: filtered readings */
+	u8 block2[6];
+
+	/* vin1 - vin16: readings */
+	u8 block3[16];
+
+	/* prochot1 - prochot2: readings */
+	struct {
+		u8 cur;
+		u8 avg;
+	} block4[2];
+
+	/* fan counts 1-4 => 14-bits, LE, *left* justified */
+	u16 block5[4];
+
+	/* block6 has a lot of data we don't need */
+	struct {
+		u8 min;
+		u8 max;
+	} temp_lim[4];
+
+	/* vin1 - vin16: low and high limits */
+	struct {
+		u8 min;
+		u8 max;
+	} block7[16];
+
+	/* fan count limits 1-4 => same format as block5 */
+	u16 block8[4];
+
+	/* pwm control registers (2 pwms, 4 regs) */
+	u8 block9[2][4];
+
+	/* auto/pwm base temp and offset temp registers */
+	struct {
+		u8 base[4];
+		u8 offset[12];
+	} block10;
+
+	/* master config register */
+	u8 config;
+
+	/* VID1 & VID2 => register format, 6-bits, right justified */
+	u8 vid[2];
+
+	/* prochot1 - prochot2: limits */
+	u8 prochot_max[2];
+
+	/* vccp1 & vccp2 (in7 & in8): VID relative limits (register format) */
+	u8 vccp_limits[2];
+
+	/* GPIO input state (register format, i.e. inverted) */
+	u8 gpi;
+
+	/* #PROCHOT override (register format) */
+	u8 prochot_override;
+
+	/* #PROCHOT intervals (register format) */
+	u8 prochot_interval;
+
+	/* Fan Boost Temperatures (register format) */
+	u8 boost[4];
+
+	/* Fan Boost Hysteresis (register format) */
+	u8 boost_hyst[2];
+
+	/* Temperature Zone Min. PWM & Hysteresis (register format) */
+	u8 auto_pwm_min_hyst[2];
+
+	/* #PROCHOT & #VRDHOT PWM Ramp Control */
+	u8 pwm_ramp_ctl;
+
+	/* miscellaneous setup regs */
+	u8 sfc1;
+	u8 sfc2;
+	u8 sf_tach_to_pwm;
+
+	/* The two PWM CTL2  registers can read something other than what was
+	   last written for the OVR_DC field (duty cycle override).  So, we
+	   save the user-commanded value here. */
+	u8 pwm_override[2];
+};
+
+/* VID:	mV
+   REG: 6-bits, right justified, *always* using Intel VRM/VRD 10 */
+static int LM93_VID_FROM_REG(u8 reg)
+{
+	return vid_from_reg((reg & 0x3f), 100);
+}
+
+/* min, max, and nominal register values, per channel (u8) */
+static const u8 lm93_vin_reg_min[16] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae,
+};
+static const u8 lm93_vin_reg_max[16] = {
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+	0xff, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xd1,
+};
+/* Values from the datasheet. They're here for documentation only.
+static const u8 lm93_vin_reg_nom[16] = {
+	0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
+	0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x40, 0xc0,
+};
+*/
+
+/* min, max, and nominal voltage readings, per channel (mV)*/
+static const unsigned long lm93_vin_val_min[16] = {
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 3000,
+};
+
+static const unsigned long lm93_vin_val_max[16] = {
+	1236, 1236, 1236, 1600, 2000, 2000, 1600, 1600,
+	4400, 6500, 3333, 2625, 1312, 1312, 1236, 3600,
+};
+/* Values from the datasheet. They're here for documentation only.
+static const unsigned long lm93_vin_val_nom[16] = {
+	 927,  927,  927, 1200, 1500, 1500, 1200, 1200,
+	3300, 5000, 2500, 1969,  984,  984,  309, 3300,
+};
+*/
+
+static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
+{
+	const long uV_max = lm93_vin_val_max[nr] * 1000;
+	const long uV_min = lm93_vin_val_min[nr] * 1000;
+
+	const long slope = (uV_max - uV_min) /
+		(lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
+	const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
+
+	return (slope * reg + intercept + 500) / 1000;
+}
+
+/* IN: mV, limits determined by channel nr
+   REG: scaling determined by channel nr */
+static u8 LM93_IN_TO_REG(int nr, unsigned val)
+{
+	/* range limit */
+	const long mV = SENSORS_LIMIT(val,
+		lm93_vin_val_min[nr], lm93_vin_val_max[nr]);
+
+	/* try not to lose too much precision here */
+	const long uV = mV * 1000;
+	const long uV_max = lm93_vin_val_max[nr] * 1000;
+	const long uV_min = lm93_vin_val_min[nr] * 1000;
+
+	/* convert */
+	const long slope = (uV_max - uV_min) /
+		(lm93_vin_reg_max[nr] - lm93_vin_reg_min[nr]);
+	const long intercept = uV_min - slope * lm93_vin_reg_min[nr];
+
+	u8 result = ((uV - intercept + (slope/2)) / slope);
+	result = SENSORS_LIMIT(result,
+			lm93_vin_reg_min[nr], lm93_vin_reg_max[nr]);
+	return result;
+}
+
+/* vid in mV, upper == 0 indicates low limit, otherwise upper limit */
+static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, int vid)
+{
+	const long uV_offset = upper ? (((reg >> 4 & 0x0f) + 1) * 12500) :
+				(((reg >> 0 & 0x0f) + 1) * -25000);
+	const long uV_vid = vid * 1000;
+	return (uV_vid + uV_offset + 5000) / 10000;
+}
+
+#define LM93_IN_MIN_FROM_REG(reg,vid)	LM93_IN_REL_FROM_REG(reg,0,vid)
+#define LM93_IN_MAX_FROM_REG(reg,vid)	LM93_IN_REL_FROM_REG(reg,1,vid)
+
+/* vid in mV , upper == 0 indicates low limit, otherwise upper limit
+   upper also determines which nibble of the register is returned
+   (the other nibble will be 0x0) */
+static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid)
+{
+	long uV_offset = vid * 1000 - val * 10000;
+	if (upper) {
+		uV_offset = SENSORS_LIMIT(uV_offset, 12500, 200000);
+		return (u8)((uV_offset /  12500 - 1) << 4);
+	} else {
+		uV_offset = SENSORS_LIMIT(uV_offset, -400000, -25000);
+		return (u8)((uV_offset / -25000 - 1) << 0);
+	}
+}
+
+/* TEMP: 1/1000 degrees C (-128C to +127C)
+   REG: 1C/bit, two's complement */
+static int LM93_TEMP_FROM_REG(u8 reg)
+{
+	return (s8)reg * 1000;
+}
+
+#define LM93_TEMP_MIN (-128000)
+#define LM93_TEMP_MAX ( 127000)
+
+/* TEMP: 1/1000 degrees C (-128C to +127C)
+   REG: 1C/bit, two's complement */
+static u8 LM93_TEMP_TO_REG(int temp)
+{
+	int ntemp = SENSORS_LIMIT(temp, LM93_TEMP_MIN, LM93_TEMP_MAX);
+	ntemp += (ntemp<0 ? -500 : 500);
+	return (u8)(ntemp / 1000);
+}
+
+/* Determine 4-bit temperature offset resolution */
+static int LM93_TEMP_OFFSET_MODE_FROM_REG(u8 sfc2, int nr)
+{
+	/* mode: 0 => 1C/bit, nonzero => 0.5C/bit */
+	return sfc2 & (nr < 2 ? 0x10 : 0x20);
+}
+
+/* This function is common to all 4-bit temperature offsets
+   reg is 4 bits right justified
+   mode 0 => 1C/bit, mode !0 => 0.5C/bit */
+static int LM93_TEMP_OFFSET_FROM_REG(u8 reg, int mode)
+{
+	return (reg & 0x0f) * (mode ? 5 : 10);
+}
+
+#define LM93_TEMP_OFFSET_MIN  (  0)
+#define LM93_TEMP_OFFSET_MAX0 (150)
+#define LM93_TEMP_OFFSET_MAX1 ( 75)
+
+/* This function is common to all 4-bit temperature offsets
+   returns 4 bits right justified
+   mode 0 => 1C/bit, mode !0 => 0.5C/bit */
+static u8 LM93_TEMP_OFFSET_TO_REG(int off, int mode)
+{
+	int factor = mode ? 5 : 10;
+
+	off = SENSORS_LIMIT(off, LM93_TEMP_OFFSET_MIN,
+		mode ? LM93_TEMP_OFFSET_MAX1 : LM93_TEMP_OFFSET_MAX0);
+	return (u8)((off + factor/2) / factor);
+}
+
+/* 0 <= nr <= 3 */
+static int LM93_TEMP_AUTO_OFFSET_FROM_REG(u8 reg, int nr, int mode)
+{
+	/* temp1-temp2 (nr=0,1) use lower nibble */
+	if (nr < 2)
+		return LM93_TEMP_OFFSET_FROM_REG(reg & 0x0f, mode);
+
+	/* temp3-temp4 (nr=2,3) use upper nibble */
+	else
+		return LM93_TEMP_OFFSET_FROM_REG(reg >> 4 & 0x0f, mode);
+}
+
+/* TEMP: 1/10 degrees C (0C to +15C (mode 0) or +7.5C (mode non-zero))
+   REG: 1.0C/bit (mode 0) or 0.5C/bit (mode non-zero)
+   0 <= nr <= 3 */
+static u8 LM93_TEMP_AUTO_OFFSET_TO_REG(u8 old, int off, int nr, int mode)
+{
+	u8 new = LM93_TEMP_OFFSET_TO_REG(off, mode);
+
+	/* temp1-temp2 (nr=0,1) use lower nibble */
+	if (nr < 2)
+		return (old & 0xf0) | (new & 0x0f);
+
+	/* temp3-temp4 (nr=2,3) use upper nibble */
+	else
+		return (new << 4 & 0xf0) | (old & 0x0f);
+}
+
+static int LM93_AUTO_BOOST_HYST_FROM_REGS(struct lm93_data *data, int nr,
+		int mode)
+{
+	u8 reg;
+
+	switch (nr) {
+	case 0:
+		reg = data->boost_hyst[0] & 0x0f;
+		break;
+	case 1:
+		reg = data->boost_hyst[0] >> 4 & 0x0f;
+		break;
+	case 2:
+		reg = data->boost_hyst[1] & 0x0f;
+		break;
+	case 3:
+	default:
+		reg = data->boost_hyst[1] >> 4 & 0x0f;
+		break;
+	}
+
+	return LM93_TEMP_FROM_REG(data->boost[nr]) -
+			LM93_TEMP_OFFSET_FROM_REG(reg, mode);
+}
+
+static u8 LM93_AUTO_BOOST_HYST_TO_REG(struct lm93_data *data, long hyst,
+		int nr, int mode)
+{
+	u8 reg = LM93_TEMP_OFFSET_TO_REG(
+			(LM93_TEMP_FROM_REG(data->boost[nr]) - hyst), mode);
+
+	switch (nr) {
+	case 0:
+		reg = (data->boost_hyst[0] & 0xf0) | (reg & 0x0f);
+		break;
+	case 1:
+		reg = (reg << 4 & 0xf0) | (data->boost_hyst[0] & 0x0f);
+		break;
+	case 2:
+		reg = (data->boost_hyst[1] & 0xf0) | (reg & 0x0f);
+		break;
+	case 3:
+	default:
+		reg = (reg << 4 & 0xf0) | (data->boost_hyst[1] & 0x0f);
+		break;
+	}
+
+	return reg;
+}
+
+/* PWM: 0-255 per sensors documentation
+   REG: 0-13 as mapped below... right justified */
+typedef enum { LM93_PWM_MAP_HI_FREQ, LM93_PWM_MAP_LO_FREQ } pwm_freq_t;
+static int lm93_pwm_map[2][16] = {
+	{
+		0x00, /*   0.00% */ 0x40, /*  25.00% */
+		0x50, /*  31.25% */ 0x60, /*  37.50% */
+		0x70, /*  43.75% */ 0x80, /*  50.00% */
+		0x90, /*  56.25% */ 0xa0, /*  62.50% */
+		0xb0, /*  68.75% */ 0xc0, /*  75.00% */
+		0xd0, /*  81.25% */ 0xe0, /*  87.50% */
+		0xf0, /*  93.75% */ 0xff, /* 100.00% */
+		0xff, 0xff, /* 14, 15 are reserved and should never occur */
+	},
+	{
+		0x00, /*   0.00% */ 0x40, /*  25.00% */
+		0x49, /*  28.57% */ 0x52, /*  32.14% */
+		0x5b, /*  35.71% */ 0x64, /*  39.29% */
+		0x6d, /*  42.86% */ 0x76, /*  46.43% */
+		0x80, /*  50.00% */ 0x89, /*  53.57% */
+		0x92, /*  57.14% */ 0xb6, /*  71.43% */
+		0xdb, /*  85.71% */ 0xff, /* 100.00% */
+		0xff, 0xff, /* 14, 15 are reserved and should never occur */
+	},
+};
+
+static int LM93_PWM_FROM_REG(u8 reg, pwm_freq_t freq)
+{
+	return lm93_pwm_map[freq][reg & 0x0f];
+}
+
+/* round up to nearest match */
+static u8 LM93_PWM_TO_REG(int pwm, pwm_freq_t freq)
+{
+	int i;
+	for (i = 0; i < 13; i++)
+		if (pwm <= lm93_pwm_map[freq][i])
+			break;
+
+	/* can fall through with i==13 */
+	return (u8)i;
+}
+
+static int LM93_FAN_FROM_REG(u16 regs)
+{
+	const u16 count = le16_to_cpu(regs) >> 2;
+	return count==0 ? -1 : count==0x3fff ? 0: 1350000 / count;
+}
+
+/*
+ * RPM: (82.5 to 1350000)
+ * REG: 14-bits, LE, *left* justified
+ */
+static u16 LM93_FAN_TO_REG(long rpm)
+{
+	u16 count, regs;
+
+	if (rpm == 0) {
+		count = 0x3fff;
+	} else {
+		rpm = SENSORS_LIMIT(rpm, 1, 1000000);
+		count = SENSORS_LIMIT((1350000 + rpm) / rpm, 1, 0x3ffe);
+	}
+
+	regs = count << 2;
+	return cpu_to_le16(regs);
+}
+
+/* PWM FREQ: HZ
+   REG: 0-7 as mapped below */
+static int lm93_pwm_freq_map[8] = {
+	22500, 96, 84, 72, 60, 48, 36, 12
+};
+
+static int LM93_PWM_FREQ_FROM_REG(u8 reg)
+{
+	return lm93_pwm_freq_map[reg & 0x07];
+}
+
+/* round up to nearest match */
+static u8 LM93_PWM_FREQ_TO_REG(int freq)
+{
+	int i;
+	for (i = 7; i > 0; i--)
+		if (freq <= lm93_pwm_freq_map[i])
+			break;
+
+	/* can fall through with i==0 */
+	return (u8)i;
+}
+
+/* TIME: 1/100 seconds
+ * REG: 0-7 as mapped below */
+static int lm93_spinup_time_map[8] = {
+	0, 10, 25, 40, 70, 100, 200, 400,
+};
+
+static int LM93_SPINUP_TIME_FROM_REG(u8 reg)
+{
+	return lm93_spinup_time_map[reg >> 5 & 0x07];
+}
+
+/* round up to nearest match */
+static u8 LM93_SPINUP_TIME_TO_REG(int time)
+{
+	int i;
+	for (i = 0; i < 7; i++)
+		if (time <= lm93_spinup_time_map[i])
+			break;
+
+	/* can fall through with i==8 */
+	return (u8)i;
+}
+
+#define LM93_RAMP_MIN 0
+#define LM93_RAMP_MAX 75
+
+static int LM93_RAMP_FROM_REG(u8 reg)
+{
+	return (reg & 0x0f) * 5;
+}
+
+/* RAMP: 1/100 seconds
+   REG: 50mS/bit 4-bits right justified */
+static u8 LM93_RAMP_TO_REG(int ramp)
+{
+	ramp = SENSORS_LIMIT(ramp, LM93_RAMP_MIN, LM93_RAMP_MAX);
+	return (u8)((ramp + 2) / 5);
+}
+
+/* PROCHOT: 0-255, 0 => 0%, 255 => > 96.6%
+ * REG: (same) */
+static u8 LM93_PROCHOT_TO_REG(long prochot)
+{
+	prochot = SENSORS_LIMIT(prochot, 0, 255);
+	return (u8)prochot;
+}
+
+/* PROCHOT-INTERVAL: 73 - 37200 (1/100 seconds)
+ * REG: 0-9 as mapped below */
+static int lm93_interval_map[10] = {
+	73, 146, 290, 580, 1170, 2330, 4660, 9320, 18600, 37200,
+};
+
+static int LM93_INTERVAL_FROM_REG(u8 reg)
+{
+	return lm93_interval_map[reg & 0x0f];
+}
+
+/* round up to nearest match */
+static u8 LM93_INTERVAL_TO_REG(long interval)
+{
+	int i;
+	for (i = 0; i < 9; i++)
+		if (interval <= lm93_interval_map[i])
+			break;
+
+	/* can fall through with i==9 */
+	return (u8)i;
+}
+
+/* GPIO: 0-255, GPIO0 is LSB
+ * REG: inverted */
+static unsigned LM93_GPI_FROM_REG(u8 reg)
+{
+	return ~reg & 0xff;
+}
+
+/* alarm bitmask definitions
+   The LM93 has nearly 64 bits of error status... I've pared that down to
+   what I think is a useful subset in order to fit it into 32 bits.
+
+   Especially note that the #VRD_HOT alarms are missing because we provide
+   that information as values in another sysfs file.
+
+   If libsensors is extended to support 64 bit values, this could be revisited.
+*/
+#define LM93_ALARM_IN1		0x00000001
+#define LM93_ALARM_IN2		0x00000002
+#define LM93_ALARM_IN3		0x00000004
+#define LM93_ALARM_IN4		0x00000008
+#define LM93_ALARM_IN5		0x00000010
+#define LM93_ALARM_IN6		0x00000020
+#define LM93_ALARM_IN7		0x00000040
+#define LM93_ALARM_IN8		0x00000080
+#define LM93_ALARM_IN9		0x00000100
+#define LM93_ALARM_IN10		0x00000200
+#define LM93_ALARM_IN11		0x00000400
+#define LM93_ALARM_IN12		0x00000800
+#define LM93_ALARM_IN13		0x00001000
+#define LM93_ALARM_IN14		0x00002000
+#define LM93_ALARM_IN15		0x00004000
+#define LM93_ALARM_IN16		0x00008000
+#define LM93_ALARM_FAN1		0x00010000
+#define LM93_ALARM_FAN2		0x00020000
+#define LM93_ALARM_FAN3		0x00040000
+#define LM93_ALARM_FAN4		0x00080000
+#define LM93_ALARM_PH1_ERR	0x00100000
+#define LM93_ALARM_PH2_ERR	0x00200000
+#define LM93_ALARM_SCSI1_ERR	0x00400000
+#define LM93_ALARM_SCSI2_ERR	0x00800000
+#define LM93_ALARM_DVDDP1_ERR	0x01000000
+#define LM93_ALARM_DVDDP2_ERR	0x02000000
+#define LM93_ALARM_D1_ERR	0x04000000
+#define LM93_ALARM_D2_ERR	0x08000000
+#define LM93_ALARM_TEMP1	0x10000000
+#define LM93_ALARM_TEMP2	0x20000000
+#define LM93_ALARM_TEMP3	0x40000000
+
+static unsigned LM93_ALARMS_FROM_REG(struct block1_t b1)
+{
+	unsigned result;
+	result  = b1.host_status_2 & 0x3f;
+
+	if (vccp_limit_type[0])
+		result |= (b1.host_status_4 & 0x10) << 2;
+	else
+		result |= b1.host_status_2 & 0x40;
+
+	if (vccp_limit_type[1])
+		result |= (b1.host_status_4 & 0x20) << 2;
+	else
+		result |= b1.host_status_2 & 0x80;
+
+	result |= b1.host_status_3 << 8;
+	result |= (b1.fan_status & 0x0f) << 16;
+	result |= (b1.p1_prochot_status & 0x80) << 13;
+	result |= (b1.p2_prochot_status & 0x80) << 14;
+	result |= (b1.host_status_4 & 0xfc) << 20;
+	result |= (b1.host_status_1 & 0x07) << 28;
+	return result;
+}
+
+#define MAX_RETRIES 5
+
+static u8 lm93_read_byte(struct i2c_client *client, u8 reg)
+{
+	int value, i;
+
+	/* retry in case of read errors */
+	for (i=1; i<=MAX_RETRIES; i++) {
+		if ((value = i2c_smbus_read_byte_data(client, reg)) >= 0) {
+			return value;
+		} else {
+			dev_warn(&client->dev,"lm93: read byte data failed, "
+				"address 0x%02x.\n", reg);
+			mdelay(i + 3);
+		}
+
+	}
+
+	/* <TODO> what to return in case of error? */
+	dev_err(&client->dev,"lm93: All read byte retries failed!!\n");
+	return 0;
+}
+
+static int lm93_write_byte(struct i2c_client *client, u8 reg, u8 value)
+{
+	int result;
+
+	/* <TODO> how to handle write errors? */
+	result = i2c_smbus_write_byte_data(client, reg, value);
+
+	if (result < 0)
+		dev_warn(&client->dev,"lm93: write byte data failed, "
+			 "0x%02x at address 0x%02x.\n", value, reg);
+
+	return result;
+}
+
+static u16 lm93_read_word(struct i2c_client *client, u8 reg)
+{
+	int value, i;
+
+	/* retry in case of read errors */
+	for (i=1; i<=MAX_RETRIES; i++) {
+		if ((value = i2c_smbus_read_word_data(client, reg)) >= 0) {
+			return value;
+		} else {
+			dev_warn(&client->dev,"lm93: read word data failed, "
+				 "address 0x%02x.\n", reg);
+			mdelay(i + 3);
+		}
+
+	}
+
+	/* <TODO> what to return in case of error? */
+	dev_err(&client->dev,"lm93: All read word retries failed!!\n");
+	return 0;
+}
+
+static int lm93_write_word(struct i2c_client *client, u8 reg, u16 value)
+{
+	int result;
+
+	/* <TODO> how to handle write errors? */
+	result = i2c_smbus_write_word_data(client, reg, value);
+
+	if (result < 0)
+		dev_warn(&client->dev,"lm93: write word data failed, "
+			 "0x%04x at address 0x%02x.\n", value, reg);
+
+	return result;
+}
+
+static u8 lm93_block_buffer[I2C_SMBUS_BLOCK_MAX];
+
+/*
+	read block data into values, retry if not expected length
+	fbn => index to lm93_block_read_cmds table
+		(Fixed Block Number - section 14.5.2 of LM93 datasheet)
+*/
+static void lm93_read_block(struct i2c_client *client, u8 fbn, u8 *values)
+{
+	int i, result=0;
+
+	for (i = 1; i <= MAX_RETRIES; i++) {
+		result = i2c_smbus_read_block_data(client,
+			lm93_block_read_cmds[fbn].cmd, lm93_block_buffer);
+
+		if (result == lm93_block_read_cmds[fbn].len) {
+			break;
+		} else {
+			dev_warn(&client->dev,"lm93: block read data failed, "
+				 "command 0x%02x.\n",
+				 lm93_block_read_cmds[fbn].cmd);
+			mdelay(i + 3);
+		}
+	}
+
+	if (result == lm93_block_read_cmds[fbn].len) {
+		memcpy(values,lm93_block_buffer,lm93_block_read_cmds[fbn].len);
+	} else {
+		/* <TODO> what to do in case of error? */
+	}
+}
+
+static struct lm93_data *lm93_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	const unsigned long interval = HZ + (HZ / 2);
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + interval) ||
+		!data->valid) {
+
+		data->update(data, client);
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+	return data;
+}
+
+/* update routine for data that has no corresponding SMBus block command */
+static void lm93_update_client_common(struct lm93_data *data,
+				      struct i2c_client *client)
+{
+	int i;
+	u8 *ptr;
+
+	/* temp1 - temp4: limits */
+	for (i = 0; i < 4; i++) {
+		data->temp_lim[i].min =
+			lm93_read_byte(client, LM93_REG_TEMP_MIN(i));
+		data->temp_lim[i].max =
+			lm93_read_byte(client, LM93_REG_TEMP_MAX(i));
+	}
+
+	/* config register */
+	data->config = lm93_read_byte(client, LM93_REG_CONFIG);
+
+	/* vid1 - vid2: values */
+	for (i = 0; i < 2; i++)
+		data->vid[i] = lm93_read_byte(client, LM93_REG_VID(i));
+
+	/* prochot1 - prochot2: limits */
+	for (i = 0; i < 2; i++)
+		data->prochot_max[i] = lm93_read_byte(client,
+				LM93_REG_PROCHOT_MAX(i));
+
+	/* vccp1 - vccp2: VID relative limits */
+	for (i = 0; i < 2; i++)
+		data->vccp_limits[i] = lm93_read_byte(client,
+				LM93_REG_VCCP_LIMIT_OFF(i));
+
+	/* GPIO input state */
+	data->gpi = lm93_read_byte(client, LM93_REG_GPI);
+
+	/* #PROCHOT override state */
+	data->prochot_override = lm93_read_byte(client,
+			LM93_REG_PROCHOT_OVERRIDE);
+
+	/* #PROCHOT intervals */
+	data->prochot_interval = lm93_read_byte(client,
+			LM93_REG_PROCHOT_INTERVAL);
+
+	/* Fan Boost Termperature registers */
+	for (i = 0; i < 4; i++)
+		data->boost[i] = lm93_read_byte(client, LM93_REG_BOOST(i));
+
+	/* Fan Boost Temperature Hyst. registers */
+	data->boost_hyst[0] = lm93_read_byte(client, LM93_REG_BOOST_HYST_12);
+	data->boost_hyst[1] = lm93_read_byte(client, LM93_REG_BOOST_HYST_34);
+
+	/* Temperature Zone Min. PWM & Hysteresis registers */
+	data->auto_pwm_min_hyst[0] =
+			lm93_read_byte(client, LM93_REG_PWM_MIN_HYST_12);
+	data->auto_pwm_min_hyst[1] =
+			lm93_read_byte(client, LM93_REG_PWM_MIN_HYST_34);
+
+	/* #PROCHOT & #VRDHOT PWM Ramp Control register */
+	data->pwm_ramp_ctl = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL);
+
+	/* misc setup registers */
+	data->sfc1 = lm93_read_byte(client, LM93_REG_SFC1);
+	data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+	data->sf_tach_to_pwm = lm93_read_byte(client,
+			LM93_REG_SF_TACH_TO_PWM);
+
+	/* write back alarm values to clear */
+	for (i = 0, ptr = (u8 *)(&data->block1); i < 8; i++)
+		lm93_write_byte(client, LM93_REG_HOST_ERROR_1 + i, *(ptr + i));
+}
+
+/* update routine which uses SMBus block data commands */
+static void lm93_update_client_full(struct lm93_data *data,
+				    struct i2c_client *client)
+{
+	dev_dbg(&client->dev,"starting device update (block data enabled)\n");
+
+	/* in1 - in16: values & limits */
+	lm93_read_block(client, 3, (u8 *)(data->block3));
+	lm93_read_block(client, 7, (u8 *)(data->block7));
+
+	/* temp1 - temp4: values */
+	lm93_read_block(client, 2, (u8 *)(data->block2));
+
+	/* prochot1 - prochot2: values */
+	lm93_read_block(client, 4, (u8 *)(data->block4));
+
+	/* fan1 - fan4: values & limits */
+	lm93_read_block(client, 5, (u8 *)(data->block5));
+	lm93_read_block(client, 8, (u8 *)(data->block8));
+
+	/* pmw control registers */
+	lm93_read_block(client, 9, (u8 *)(data->block9));
+
+	/* alarm values */
+	lm93_read_block(client, 1, (u8 *)(&data->block1));
+
+	/* auto/pwm registers */
+	lm93_read_block(client, 10, (u8 *)(&data->block10));
+
+	lm93_update_client_common(data, client);
+}
+
+/* update routine which uses SMBus byte/word data commands only */
+static void lm93_update_client_min(struct lm93_data *data,
+				   struct i2c_client *client)
+{
+	int i,j;
+	u8 *ptr;
+
+	dev_dbg(&client->dev,"starting device update (block data disabled)\n");
+
+	/* in1 - in16: values & limits */
+	for (i = 0; i < 16; i++) {
+		data->block3[i] =
+			lm93_read_byte(client, LM93_REG_IN(i));
+		data->block7[i].min =
+			lm93_read_byte(client, LM93_REG_IN_MIN(i));
+		data->block7[i].max =
+			lm93_read_byte(client, LM93_REG_IN_MAX(i));
+	}
+
+	/* temp1 - temp4: values */
+	for (i = 0; i < 4; i++) {
+		data->block2[i] =
+			lm93_read_byte(client, LM93_REG_TEMP(i));
+	}
+
+	/* prochot1 - prochot2: values */
+	for (i = 0; i < 2; i++) {
+		data->block4[i].cur =
+			lm93_read_byte(client, LM93_REG_PROCHOT_CUR(i));
+		data->block4[i].avg =
+			lm93_read_byte(client, LM93_REG_PROCHOT_AVG(i));
+	}
+
+	/* fan1 - fan4: values & limits */
+	for (i = 0; i < 4; i++) {
+		data->block5[i] =
+			lm93_read_word(client, LM93_REG_FAN(i));
+		data->block8[i] =
+			lm93_read_word(client, LM93_REG_FAN_MIN(i));
+	}
+
+	/* pwm control registers */
+	for (i = 0; i < 2; i++) {
+		for (j = 0; j < 4; j++) {
+			data->block9[i][j] =
+				lm93_read_byte(client, LM93_REG_PWM_CTL(i,j));
+		}
+	}
+
+	/* alarm values */
+	for (i = 0, ptr = (u8 *)(&data->block1); i < 8; i++) {
+		*(ptr + i) =
+			lm93_read_byte(client, LM93_REG_HOST_ERROR_1 + i);
+	}
+
+	/* auto/pwm (base temp) registers */
+	for (i = 0; i < 4; i++) {
+		data->block10.base[i] =
+			lm93_read_byte(client, LM93_REG_TEMP_BASE(i));
+	}
+
+	/* auto/pwm (offset temp) registers */
+	for (i = 0; i < 12; i++) {
+		data->block10.offset[i] =
+			lm93_read_byte(client, LM93_REG_TEMP_OFFSET(i));
+	}
+
+	lm93_update_client_common(data, client);
+}
+
+/* following are the sysfs callback functions */
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf, "%d\n", LM93_IN_FROM_REG(nr, data->block3[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in, NULL, 4);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in, NULL, 5);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_in, NULL, 6);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_in, NULL, 7);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_in, NULL, 8);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_in, NULL, 9);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_in, NULL, 10);
+static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_in, NULL, 11);
+static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, show_in, NULL, 12);
+static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, show_in, NULL, 13);
+static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, show_in, NULL, 14);
+static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, show_in, NULL, 15);
+
+static ssize_t show_in_min(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	int vccp = nr - 6;
+	long rc, vid;
+
+	if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
+		vid = LM93_VID_FROM_REG(data->vid[vccp]);
+		rc = LM93_IN_MIN_FROM_REG(data->vccp_limits[vccp], vid);
+	}
+	else {
+		rc = LM93_IN_FROM_REG(nr, data->block7[nr].min); \
+	}
+	return sprintf(buf, "%ld\n", rc); \
+}
+
+static ssize_t store_in_min(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+	int vccp = nr - 6;
+	long vid;
+
+	mutex_lock(&data->update_lock);
+	if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
+		vid = LM93_VID_FROM_REG(data->vid[vccp]);
+		data->vccp_limits[vccp] = (data->vccp_limits[vccp] & 0xf0) |
+				LM93_IN_REL_TO_REG(val, 0, vid);
+		lm93_write_byte(client, LM93_REG_VCCP_LIMIT_OFF(vccp),
+				data->vccp_limits[vccp]);
+	}
+	else {
+		data->block7[nr].min = LM93_IN_TO_REG(nr,val);
+		lm93_write_byte(client, LM93_REG_IN_MIN(nr),
+				data->block7[nr].min);
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 0);
+static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 1);
+static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 2);
+static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 3);
+static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 4);
+static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 5);
+static SENSOR_DEVICE_ATTR(in7_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 6);
+static SENSOR_DEVICE_ATTR(in8_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 7);
+static SENSOR_DEVICE_ATTR(in9_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 8);
+static SENSOR_DEVICE_ATTR(in10_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 9);
+static SENSOR_DEVICE_ATTR(in11_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 10);
+static SENSOR_DEVICE_ATTR(in12_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 11);
+static SENSOR_DEVICE_ATTR(in13_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 12);
+static SENSOR_DEVICE_ATTR(in14_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 13);
+static SENSOR_DEVICE_ATTR(in15_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 14);
+static SENSOR_DEVICE_ATTR(in16_min, S_IWUSR | S_IRUGO,
+			  show_in_min, store_in_min, 15);
+
+static ssize_t show_in_max(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	int vccp = nr - 6;
+	long rc, vid;
+
+	if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
+		vid = LM93_VID_FROM_REG(data->vid[vccp]);
+		rc = LM93_IN_MAX_FROM_REG(data->vccp_limits[vccp],vid);
+	}
+	else {
+		rc = LM93_IN_FROM_REG(nr,data->block7[nr].max); \
+	}
+	return sprintf(buf,"%ld\n",rc); \
+}
+
+static ssize_t store_in_max(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+	int vccp = nr - 6;
+	long vid;
+
+	mutex_lock(&data->update_lock);
+	if ((nr==6 || nr==7) && (vccp_limit_type[vccp])) {
+		vid = LM93_VID_FROM_REG(data->vid[vccp]);
+		data->vccp_limits[vccp] = (data->vccp_limits[vccp] & 0x0f) |
+				LM93_IN_REL_TO_REG(val, 1, vid);
+		lm93_write_byte(client, LM93_REG_VCCP_LIMIT_OFF(vccp),
+				data->vccp_limits[vccp]);
+	}
+	else {
+		data->block7[nr].max = LM93_IN_TO_REG(nr,val);
+		lm93_write_byte(client, LM93_REG_IN_MAX(nr),
+				data->block7[nr].max);
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 0);
+static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 1);
+static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 2);
+static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 3);
+static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 4);
+static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 5);
+static SENSOR_DEVICE_ATTR(in7_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 6);
+static SENSOR_DEVICE_ATTR(in8_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 7);
+static SENSOR_DEVICE_ATTR(in9_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 8);
+static SENSOR_DEVICE_ATTR(in10_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 9);
+static SENSOR_DEVICE_ATTR(in11_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 10);
+static SENSOR_DEVICE_ATTR(in12_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 11);
+static SENSOR_DEVICE_ATTR(in13_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 12);
+static SENSOR_DEVICE_ATTR(in14_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 13);
+static SENSOR_DEVICE_ATTR(in15_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 14);
+static SENSOR_DEVICE_ATTR(in16_max, S_IWUSR | S_IRUGO,
+			  show_in_max, store_in_max, 15);
+
+static ssize_t show_temp(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->block2[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+
+static ssize_t show_temp_min(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->temp_lim[nr].min));
+}
+
+static ssize_t store_temp_min(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	data->temp_lim[nr].min = LM93_TEMP_TO_REG(val);
+	lm93_write_byte(client, LM93_REG_TEMP_MIN(nr), data->temp_lim[nr].min);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+			  show_temp_min, store_temp_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO,
+			  show_temp_min, store_temp_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO,
+			  show_temp_min, store_temp_min, 2);
+
+static ssize_t show_temp_max(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->temp_lim[nr].max));
+}
+
+static ssize_t store_temp_max(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	data->temp_lim[nr].max = LM93_TEMP_TO_REG(val);
+	lm93_write_byte(client, LM93_REG_TEMP_MAX(nr), data->temp_lim[nr].max);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+			  show_temp_max, store_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO,
+			  show_temp_max, store_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO,
+			  show_temp_max, store_temp_max, 2);
+
+static ssize_t show_temp_auto_base(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->block10.base[nr]));
+}
+
+static ssize_t store_temp_auto_base(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	data->block10.base[nr] = LM93_TEMP_TO_REG(val);
+	lm93_write_byte(client, LM93_REG_TEMP_BASE(nr), data->block10.base[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_base, S_IWUSR | S_IRUGO,
+			  show_temp_auto_base, store_temp_auto_base, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_base, S_IWUSR | S_IRUGO,
+			  show_temp_auto_base, store_temp_auto_base, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_base, S_IWUSR | S_IRUGO,
+			  show_temp_auto_base, store_temp_auto_base, 2);
+
+static ssize_t show_temp_auto_boost(struct device *dev,
+				    struct device_attribute *attr,char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",LM93_TEMP_FROM_REG(data->boost[nr]));
+}
+
+static ssize_t store_temp_auto_boost(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	data->boost[nr] = LM93_TEMP_TO_REG(val);
+	lm93_write_byte(client, LM93_REG_BOOST(nr), data->boost[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_boost, S_IWUSR | S_IRUGO,
+			  show_temp_auto_boost, store_temp_auto_boost, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_boost, S_IWUSR | S_IRUGO,
+			  show_temp_auto_boost, store_temp_auto_boost, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_boost, S_IWUSR | S_IRUGO,
+			  show_temp_auto_boost, store_temp_auto_boost, 2);
+
+static ssize_t show_temp_auto_boost_hyst(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr);
+	return sprintf(buf,"%d\n",
+		       LM93_AUTO_BOOST_HYST_FROM_REGS(data, nr, mode));
+}
+
+static ssize_t store_temp_auto_boost_hyst(struct device *dev,
+					  struct device_attribute *attr,
+					  const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	/* force 0.5C/bit mode */
+	data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+	data->sfc2 |= ((nr < 2) ? 0x10 : 0x20);
+	lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+	data->boost_hyst[nr/2] = LM93_AUTO_BOOST_HYST_TO_REG(data, val, nr, 1);
+	lm93_write_byte(client, LM93_REG_BOOST_HYST(nr),
+			data->boost_hyst[nr/2]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_boost_hyst, S_IWUSR | S_IRUGO,
+			  show_temp_auto_boost_hyst,
+			  store_temp_auto_boost_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_boost_hyst, S_IWUSR | S_IRUGO,
+			  show_temp_auto_boost_hyst,
+			  store_temp_auto_boost_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_boost_hyst, S_IWUSR | S_IRUGO,
+			  show_temp_auto_boost_hyst,
+			  store_temp_auto_boost_hyst, 2);
+
+static ssize_t show_temp_auto_offset(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr);
+	int nr = s_attr->index;
+	int ofs = s_attr->nr;
+	struct lm93_data *data = lm93_update_device(dev);
+	int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr);
+	return sprintf(buf,"%d\n",
+	       LM93_TEMP_AUTO_OFFSET_FROM_REG(data->block10.offset[ofs],
+					      nr,mode));
+}
+
+static ssize_t store_temp_auto_offset(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct sensor_device_attribute_2 *s_attr = to_sensor_dev_attr_2(attr);
+	int nr = s_attr->index;
+	int ofs = s_attr->nr;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	/* force 0.5C/bit mode */
+	data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+	data->sfc2 |= ((nr < 2) ? 0x10 : 0x20);
+	lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+	data->block10.offset[ofs] = LM93_TEMP_AUTO_OFFSET_TO_REG(
+			data->block10.offset[ofs], val, nr, 1);
+	lm93_write_byte(client, LM93_REG_TEMP_OFFSET(ofs),
+			data->block10.offset[ofs]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset1, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset2, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset3, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 2, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset4, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 3, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset5, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 4, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset6, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 5, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset7, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 6, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset8, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 7, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset9, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 8, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset10, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 9, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset11, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 10, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_auto_offset12, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 11, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset1, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 0, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset2, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 1, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset3, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 2, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset4, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 3, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset5, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 4, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset6, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 5, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset7, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 6, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset8, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 7, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset9, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 8, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset10, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 9, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset11, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 10, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_auto_offset12, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 11, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset1, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 0, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset2, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 1, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset3, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 2, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset4, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 3, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset5, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 4, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset6, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 5, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset7, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 6, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset8, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 7, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset9, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 8, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset10, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 9, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset11, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 10, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_auto_offset12, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset, store_temp_auto_offset, 11, 2);
+
+static ssize_t show_temp_auto_pwm_min(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	u8 reg, ctl4;
+	struct lm93_data *data = lm93_update_device(dev);
+	reg = data->auto_pwm_min_hyst[nr/2] >> 4 & 0x0f;
+	ctl4 = data->block9[nr][LM93_PWM_CTL4];
+	return sprintf(buf,"%d\n",LM93_PWM_FROM_REG(reg, (ctl4 & 0x07) ?
+				LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ));
+}
+
+static ssize_t store_temp_auto_pwm_min(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+	u8 reg, ctl4;
+
+	mutex_lock(&data->update_lock);
+	reg = lm93_read_byte(client, LM93_REG_PWM_MIN_HYST(nr));
+	ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4));
+	reg = (reg & 0x0f) |
+		LM93_PWM_TO_REG(val, (ctl4 & 0x07) ?
+				LM93_PWM_MAP_LO_FREQ :
+				LM93_PWM_MAP_HI_FREQ) << 4;
+	data->auto_pwm_min_hyst[nr/2] = reg;
+	lm93_write_byte(client, LM93_REG_PWM_MIN_HYST(nr), reg);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_pwm_min, S_IWUSR | S_IRUGO,
+			  show_temp_auto_pwm_min,
+			  store_temp_auto_pwm_min, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_pwm_min, S_IWUSR | S_IRUGO,
+			  show_temp_auto_pwm_min,
+			  store_temp_auto_pwm_min, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_pwm_min, S_IWUSR | S_IRUGO,
+			  show_temp_auto_pwm_min,
+			  store_temp_auto_pwm_min, 2);
+
+static ssize_t show_temp_auto_offset_hyst(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	int mode = LM93_TEMP_OFFSET_MODE_FROM_REG(data->sfc2, nr);
+	return sprintf(buf,"%d\n",LM93_TEMP_OFFSET_FROM_REG(
+					data->auto_pwm_min_hyst[nr/2], mode));
+}
+
+static ssize_t store_temp_auto_offset_hyst(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+	u8 reg;
+
+	mutex_lock(&data->update_lock);
+	/* force 0.5C/bit mode */
+	data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+	data->sfc2 |= ((nr < 2) ? 0x10 : 0x20);
+	lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+	reg = data->auto_pwm_min_hyst[nr/2];
+	reg = (reg & 0xf0) | (LM93_TEMP_OFFSET_TO_REG(val, 1) & 0x0f);
+	data->auto_pwm_min_hyst[nr/2] = reg;
+	lm93_write_byte(client, LM93_REG_PWM_MIN_HYST(nr), reg);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(temp1_auto_offset_hyst, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset_hyst,
+			  store_temp_auto_offset_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp2_auto_offset_hyst, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset_hyst,
+			  store_temp_auto_offset_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp3_auto_offset_hyst, S_IWUSR | S_IRUGO,
+			  show_temp_auto_offset_hyst,
+			  store_temp_auto_offset_hyst, 2);
+
+static ssize_t show_fan_input(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *s_attr = to_sensor_dev_attr(attr);
+	int nr = s_attr->index;
+	struct lm93_data *data = lm93_update_device(dev);
+
+	return sprintf(buf,"%d\n",LM93_FAN_FROM_REG(data->block5[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan_input, NULL, 3);
+
+static ssize_t show_fan_min(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+
+	return sprintf(buf,"%d\n",LM93_FAN_FROM_REG(data->block8[nr]));
+}
+
+static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	data->block8[nr] = LM93_FAN_TO_REG(val);
+	lm93_write_word(client,LM93_REG_FAN_MIN(nr),data->block8[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO,
+			  show_fan_min, store_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO,
+			  show_fan_min, store_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO,
+			  show_fan_min, store_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO,
+			  show_fan_min, store_fan_min, 3);
+
+/* some tedious bit-twiddling here to deal with the register format:
+
+	data->sf_tach_to_pwm: (tach to pwm mapping bits)
+
+		bit |  7  |  6  |  5  |  4  |  3  |  2  |  1  |  0
+		     T4:P2 T4:P1 T3:P2 T3:P1 T2:P2 T2:P1 T1:P2 T1:P1
+
+	data->sfc2: (enable bits)
+
+		bit |  3  |  2  |  1  |  0
+		       T4    T3    T2    T1
+*/
+
+static ssize_t show_fan_smart_tach(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	long rc = 0;
+	int mapping;
+
+	/* extract the relevant mapping */
+	mapping = (data->sf_tach_to_pwm >> (nr * 2)) & 0x03;
+
+	/* if there's a mapping and it's enabled */
+	if (mapping && ((data->sfc2 >> nr) & 0x01))
+		rc = mapping;
+	return sprintf(buf,"%ld\n",rc);
+}
+
+/* helper function - must grab data->update_lock before calling
+   fan is 0-3, indicating fan1-fan4 */
+static void lm93_write_fan_smart_tach(struct i2c_client *client,
+	struct lm93_data *data, int fan, long value)
+{
+	/* insert the new mapping and write it out */
+	data->sf_tach_to_pwm = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM);
+	data->sf_tach_to_pwm &= ~(0x3 << fan * 2);
+	data->sf_tach_to_pwm |= value << fan * 2;
+	lm93_write_byte(client, LM93_REG_SF_TACH_TO_PWM, data->sf_tach_to_pwm);
+
+	/* insert the enable bit and write it out */
+	data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+	if (value)
+		data->sfc2 |= 1 << fan;
+	else
+		data->sfc2 &= ~(1 << fan);
+	lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+}
+
+static ssize_t store_fan_smart_tach(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	/* sanity test, ignore the write otherwise */
+	if (0 <= val && val <= 2) {
+		/* can't enable if pwm freq is 22.5KHz */
+		if (val) {
+			u8 ctl4 = lm93_read_byte(client,
+				LM93_REG_PWM_CTL(val-1,LM93_PWM_CTL4));
+			if ((ctl4 & 0x07) == 0)
+				val = 0;
+		}
+		lm93_write_fan_smart_tach(client, data, nr, val);
+	}
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(fan1_smart_tach, S_IWUSR | S_IRUGO,
+			  show_fan_smart_tach, store_fan_smart_tach, 0);
+static SENSOR_DEVICE_ATTR(fan2_smart_tach, S_IWUSR | S_IRUGO,
+			  show_fan_smart_tach, store_fan_smart_tach, 1);
+static SENSOR_DEVICE_ATTR(fan3_smart_tach, S_IWUSR | S_IRUGO,
+			  show_fan_smart_tach, store_fan_smart_tach, 2);
+static SENSOR_DEVICE_ATTR(fan4_smart_tach, S_IWUSR | S_IRUGO,
+			  show_fan_smart_tach, store_fan_smart_tach, 3);
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	u8 ctl2, ctl4;
+	long rc;
+
+	ctl2 = data->block9[nr][LM93_PWM_CTL2];
+	ctl4 = data->block9[nr][LM93_PWM_CTL4];
+	if (ctl2 & 0x01) /* show user commanded value if enabled */
+		rc = data->pwm_override[nr];
+	else /* show present h/w value if manual pwm disabled */
+		rc = LM93_PWM_FROM_REG(ctl2 >> 4, (ctl4 & 0x07) ?
+			LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ);
+	return sprintf(buf,"%ld\n",rc);
+}
+
+static ssize_t store_pwm(struct device *dev, struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+	u8 ctl2, ctl4;
+
+	mutex_lock(&data->update_lock);
+	ctl2 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2));
+	ctl4 = lm93_read_byte(client, LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4));
+	ctl2 = (ctl2 & 0x0f) | LM93_PWM_TO_REG(val,(ctl4 & 0x07) ?
+			LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ) << 4;
+	/* save user commanded value */
+	data->pwm_override[nr] = LM93_PWM_FROM_REG(ctl2 >> 4,
+			(ctl4 & 0x07) ?  LM93_PWM_MAP_LO_FREQ :
+			LM93_PWM_MAP_HI_FREQ);
+	lm93_write_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2),ctl2);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1);
+
+static ssize_t show_pwm_enable(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	u8 ctl2;
+	long rc;
+
+	ctl2 = data->block9[nr][LM93_PWM_CTL2];
+	if (ctl2 & 0x01) /* manual override enabled ? */
+		rc = ((ctl2 & 0xF0) == 0xF0) ? 0 : 1;
+	else
+		rc = 2;
+	return sprintf(buf,"%ld\n",rc);
+}
+
+static ssize_t store_pwm_enable(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+	u8 ctl2;
+
+	mutex_lock(&data->update_lock);
+	ctl2 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2));
+
+	switch (val) {
+	case 0:
+		ctl2 |= 0xF1; /* enable manual override, set PWM to max */
+		break;
+	case 1: ctl2 |= 0x01; /* enable manual override */
+		break;
+	case 2: ctl2 &= ~0x01; /* disable manual override */
+		break;
+	default:
+		mutex_unlock(&data->update_lock);
+		return -EINVAL;
+	}
+
+	lm93_write_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL2),ctl2);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+				show_pwm_enable, store_pwm_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
+				show_pwm_enable, store_pwm_enable, 1);
+
+static ssize_t show_pwm_freq(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	u8 ctl4;
+
+	ctl4 = data->block9[nr][LM93_PWM_CTL4];
+	return sprintf(buf,"%d\n",LM93_PWM_FREQ_FROM_REG(ctl4));
+}
+
+/* helper function - must grab data->update_lock before calling
+   pwm is 0-1, indicating pwm1-pwm2
+   this disables smart tach for all tach channels bound to the given pwm */
+static void lm93_disable_fan_smart_tach(struct i2c_client *client,
+	struct lm93_data *data, int pwm)
+{
+	int mapping = lm93_read_byte(client, LM93_REG_SF_TACH_TO_PWM);
+	int mask;
+
+	/* collapse the mapping into a mask of enable bits */
+	mapping = (mapping >> pwm) & 0x55;
+	mask = mapping & 0x01;
+	mask |= (mapping & 0x04) >> 1;
+	mask |= (mapping & 0x10) >> 2;
+	mask |= (mapping & 0x40) >> 3;
+
+	/* disable smart tach according to the mask */
+	data->sfc2 = lm93_read_byte(client, LM93_REG_SFC2);
+	data->sfc2 &= ~mask;
+	lm93_write_byte(client, LM93_REG_SFC2, data->sfc2);
+}
+
+static ssize_t store_pwm_freq(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+	u8 ctl4;
+
+	mutex_lock(&data->update_lock);
+	ctl4 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4));
+	ctl4 = (ctl4 & 0xf8) | LM93_PWM_FREQ_TO_REG(val);
+	data->block9[nr][LM93_PWM_CTL4] = ctl4;
+	/* ctl4 == 0 -> 22.5KHz -> disable smart tach */
+	if (!ctl4)
+		lm93_disable_fan_smart_tach(client, data, nr);
+	lm93_write_byte(client,	LM93_REG_PWM_CTL(nr,LM93_PWM_CTL4), ctl4);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_freq, S_IWUSR | S_IRUGO,
+			  show_pwm_freq, store_pwm_freq, 0);
+static SENSOR_DEVICE_ATTR(pwm2_freq, S_IWUSR | S_IRUGO,
+			  show_pwm_freq, store_pwm_freq, 1);
+
+static ssize_t show_pwm_auto_channels(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",data->block9[nr][LM93_PWM_CTL1]);
+}
+
+static ssize_t store_pwm_auto_channels(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	data->block9[nr][LM93_PWM_CTL1] = SENSORS_LIMIT(val, 0, 255);
+	lm93_write_byte(client,	LM93_REG_PWM_CTL(nr,LM93_PWM_CTL1),
+				data->block9[nr][LM93_PWM_CTL1]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_channels, S_IWUSR | S_IRUGO,
+			  show_pwm_auto_channels, store_pwm_auto_channels, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_channels, S_IWUSR | S_IRUGO,
+			  show_pwm_auto_channels, store_pwm_auto_channels, 1);
+
+static ssize_t show_pwm_auto_spinup_min(struct device *dev,
+				struct device_attribute *attr,char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	u8 ctl3, ctl4;
+
+	ctl3 = data->block9[nr][LM93_PWM_CTL3];
+	ctl4 = data->block9[nr][LM93_PWM_CTL4];
+	return sprintf(buf,"%d\n",
+		       LM93_PWM_FROM_REG(ctl3 & 0x0f, (ctl4 & 0x07) ?
+			LM93_PWM_MAP_LO_FREQ : LM93_PWM_MAP_HI_FREQ));
+}
+
+static ssize_t store_pwm_auto_spinup_min(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+	u8 ctl3, ctl4;
+
+	mutex_lock(&data->update_lock);
+	ctl3 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3));
+	ctl4 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL4));
+	ctl3 = (ctl3 & 0xf0) | 	LM93_PWM_TO_REG(val, (ctl4 & 0x07) ?
+			LM93_PWM_MAP_LO_FREQ :
+			LM93_PWM_MAP_HI_FREQ);
+	data->block9[nr][LM93_PWM_CTL3] = ctl3;
+	lm93_write_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_spinup_min, S_IWUSR | S_IRUGO,
+			  show_pwm_auto_spinup_min,
+			  store_pwm_auto_spinup_min, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_spinup_min, S_IWUSR | S_IRUGO,
+			  show_pwm_auto_spinup_min,
+			  store_pwm_auto_spinup_min, 1);
+
+static ssize_t show_pwm_auto_spinup_time(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",LM93_SPINUP_TIME_FROM_REG(
+				data->block9[nr][LM93_PWM_CTL3]));
+}
+
+static ssize_t store_pwm_auto_spinup_time(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+	u8 ctl3;
+
+	mutex_lock(&data->update_lock);
+	ctl3 = lm93_read_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3));
+	ctl3 = (ctl3 & 0x1f) | (LM93_SPINUP_TIME_TO_REG(val) << 5 & 0xe0);
+	data->block9[nr][LM93_PWM_CTL3] = ctl3;
+	lm93_write_byte(client,LM93_REG_PWM_CTL(nr, LM93_PWM_CTL3), ctl3);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_spinup_time, S_IWUSR | S_IRUGO,
+			  show_pwm_auto_spinup_time,
+			  store_pwm_auto_spinup_time, 0);
+static SENSOR_DEVICE_ATTR(pwm2_auto_spinup_time, S_IWUSR | S_IRUGO,
+			  show_pwm_auto_spinup_time,
+			  store_pwm_auto_spinup_time, 1);
+
+static ssize_t show_pwm_auto_prochot_ramp(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",
+		       LM93_RAMP_FROM_REG(data->pwm_ramp_ctl >> 4 & 0x0f));
+}
+
+static ssize_t store_pwm_auto_prochot_ramp(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+	u8 ramp;
+
+	mutex_lock(&data->update_lock);
+	ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL);
+	ramp = (ramp & 0x0f) | (LM93_RAMP_TO_REG(val) << 4 & 0xf0);
+	lm93_write_byte(client, LM93_REG_PWM_RAMP_CTL, ramp);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(pwm_auto_prochot_ramp, S_IRUGO | S_IWUSR,
+			show_pwm_auto_prochot_ramp,
+			store_pwm_auto_prochot_ramp);
+
+static ssize_t show_pwm_auto_vrdhot_ramp(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",
+		       LM93_RAMP_FROM_REG(data->pwm_ramp_ctl & 0x0f));
+}
+
+static ssize_t store_pwm_auto_vrdhot_ramp(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+	u8 ramp;
+
+	mutex_lock(&data->update_lock);
+	ramp = lm93_read_byte(client, LM93_REG_PWM_RAMP_CTL);
+	ramp = (ramp & 0xf0) | (LM93_RAMP_TO_REG(val) & 0x0f);
+	lm93_write_byte(client, LM93_REG_PWM_RAMP_CTL, ramp);
+	mutex_unlock(&data->update_lock);
+	return 0;
+}
+
+static DEVICE_ATTR(pwm_auto_vrdhot_ramp, S_IRUGO | S_IWUSR,
+			show_pwm_auto_vrdhot_ramp,
+			store_pwm_auto_vrdhot_ramp);
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",LM93_VID_FROM_REG(data->vid[nr]));
+}
+
+static SENSOR_DEVICE_ATTR(vid1, S_IRUGO, show_vid, NULL, 0);
+static SENSOR_DEVICE_ATTR(vid2, S_IRUGO, show_vid, NULL, 1);
+
+static ssize_t show_prochot(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",data->block4[nr].cur);
+}
+
+static SENSOR_DEVICE_ATTR(prochot1, S_IRUGO, show_prochot, NULL, 0);
+static SENSOR_DEVICE_ATTR(prochot2, S_IRUGO, show_prochot, NULL, 1);
+
+static ssize_t show_prochot_avg(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",data->block4[nr].avg);
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_avg, S_IRUGO, show_prochot_avg, NULL, 0);
+static SENSOR_DEVICE_ATTR(prochot2_avg, S_IRUGO, show_prochot_avg, NULL, 1);
+
+static ssize_t show_prochot_max(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",data->prochot_max[nr]);
+}
+
+static ssize_t store_prochot_max(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	data->prochot_max[nr] = LM93_PROCHOT_TO_REG(val);
+	lm93_write_byte(client, LM93_REG_PROCHOT_MAX(nr),
+			data->prochot_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_max, S_IWUSR | S_IRUGO,
+			  show_prochot_max, store_prochot_max, 0);
+static SENSOR_DEVICE_ATTR(prochot2_max, S_IWUSR | S_IRUGO,
+			  show_prochot_max, store_prochot_max, 1);
+
+static const u8 prochot_override_mask[] = { 0x80, 0x40 };
+
+static ssize_t show_prochot_override(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",
+		(data->prochot_override & prochot_override_mask[nr]) ? 1 : 0);
+}
+
+static ssize_t store_prochot_override(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	if (val)
+		data->prochot_override |= prochot_override_mask[nr];
+	else
+		data->prochot_override &= (~prochot_override_mask[nr]);
+	lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE,
+			data->prochot_override);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_override, S_IWUSR | S_IRUGO,
+			  show_prochot_override, store_prochot_override, 0);
+static SENSOR_DEVICE_ATTR(prochot2_override, S_IWUSR | S_IRUGO,
+			  show_prochot_override, store_prochot_override, 1);
+
+static ssize_t show_prochot_interval(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	u8 tmp;
+	if (nr==1)
+		tmp = (data->prochot_interval & 0xf0) >> 4;
+	else
+		tmp = data->prochot_interval & 0x0f;
+	return sprintf(buf,"%d\n",LM93_INTERVAL_FROM_REG(tmp));
+}
+
+static ssize_t store_prochot_interval(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+	u8 tmp;
+
+	mutex_lock(&data->update_lock);
+	tmp = lm93_read_byte(client, LM93_REG_PROCHOT_INTERVAL);
+	if (nr==1)
+		tmp = (tmp & 0x0f) | (LM93_INTERVAL_TO_REG(val) << 4);
+	else
+		tmp = (tmp & 0xf0) | LM93_INTERVAL_TO_REG(val);
+	data->prochot_interval = tmp;
+	lm93_write_byte(client, LM93_REG_PROCHOT_INTERVAL, tmp);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static SENSOR_DEVICE_ATTR(prochot1_interval, S_IWUSR | S_IRUGO,
+			  show_prochot_interval, store_prochot_interval, 0);
+static SENSOR_DEVICE_ATTR(prochot2_interval, S_IWUSR | S_IRUGO,
+			  show_prochot_interval, store_prochot_interval, 1);
+
+static ssize_t show_prochot_override_duty_cycle(struct device *dev,
+						struct device_attribute *attr,
+						char *buf)
+{
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",data->prochot_override & 0x0f);
+}
+
+static ssize_t store_prochot_override_duty_cycle(struct device *dev,
+						struct device_attribute *attr,
+						const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	data->prochot_override = (data->prochot_override & 0xf0) |
+					SENSORS_LIMIT(val, 0, 15);
+	lm93_write_byte(client, LM93_REG_PROCHOT_OVERRIDE,
+			data->prochot_override);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(prochot_override_duty_cycle, S_IRUGO | S_IWUSR,
+			show_prochot_override_duty_cycle,
+			store_prochot_override_duty_cycle);
+
+static ssize_t show_prochot_short(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",(data->config & 0x10) ? 1 : 0);
+}
+
+static ssize_t store_prochot_short(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct lm93_data *data = i2c_get_clientdata(client);
+	u32 val = simple_strtoul(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	if (val)
+		data->config |= 0x10;
+	else
+		data->config &= ~0x10;
+	lm93_write_byte(client, LM93_REG_CONFIG, data->config);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static DEVICE_ATTR(prochot_short, S_IRUGO | S_IWUSR,
+		   show_prochot_short, store_prochot_short);
+
+static ssize_t show_vrdhot(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	int nr = (to_sensor_dev_attr(attr))->index;
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",
+		       data->block1.host_status_1 & (1 << (nr+4)) ? 1 : 0);
+}
+
+static SENSOR_DEVICE_ATTR(vrdhot1, S_IRUGO, show_vrdhot, NULL, 0);
+static SENSOR_DEVICE_ATTR(vrdhot2, S_IRUGO, show_vrdhot, NULL, 1);
+
+static ssize_t show_gpio(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",LM93_GPI_FROM_REG(data->gpi));
+}
+
+static DEVICE_ATTR(gpio, S_IRUGO, show_gpio, NULL);
+
+static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct lm93_data *data = lm93_update_device(dev);
+	return sprintf(buf,"%d\n",LM93_ALARMS_FROM_REG(data->block1));
+}
+
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static struct attribute *lm93_attrs[] = {
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in5_input.dev_attr.attr,
+	&sensor_dev_attr_in6_input.dev_attr.attr,
+	&sensor_dev_attr_in7_input.dev_attr.attr,
+	&sensor_dev_attr_in8_input.dev_attr.attr,
+	&sensor_dev_attr_in9_input.dev_attr.attr,
+	&sensor_dev_attr_in10_input.dev_attr.attr,
+	&sensor_dev_attr_in11_input.dev_attr.attr,
+	&sensor_dev_attr_in12_input.dev_attr.attr,
+	&sensor_dev_attr_in13_input.dev_attr.attr,
+	&sensor_dev_attr_in14_input.dev_attr.attr,
+	&sensor_dev_attr_in15_input.dev_attr.attr,
+	&sensor_dev_attr_in16_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in5_min.dev_attr.attr,
+	&sensor_dev_attr_in6_min.dev_attr.attr,
+	&sensor_dev_attr_in7_min.dev_attr.attr,
+	&sensor_dev_attr_in8_min.dev_attr.attr,
+	&sensor_dev_attr_in9_min.dev_attr.attr,
+	&sensor_dev_attr_in10_min.dev_attr.attr,
+	&sensor_dev_attr_in11_min.dev_attr.attr,
+	&sensor_dev_attr_in12_min.dev_attr.attr,
+	&sensor_dev_attr_in13_min.dev_attr.attr,
+	&sensor_dev_attr_in14_min.dev_attr.attr,
+	&sensor_dev_attr_in15_min.dev_attr.attr,
+	&sensor_dev_attr_in16_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
+	&sensor_dev_attr_in5_max.dev_attr.attr,
+	&sensor_dev_attr_in6_max.dev_attr.attr,
+	&sensor_dev_attr_in7_max.dev_attr.attr,
+	&sensor_dev_attr_in8_max.dev_attr.attr,
+	&sensor_dev_attr_in9_max.dev_attr.attr,
+	&sensor_dev_attr_in10_max.dev_attr.attr,
+	&sensor_dev_attr_in11_max.dev_attr.attr,
+	&sensor_dev_attr_in12_max.dev_attr.attr,
+	&sensor_dev_attr_in13_max.dev_attr.attr,
+	&sensor_dev_attr_in14_max.dev_attr.attr,
+	&sensor_dev_attr_in15_max.dev_attr.attr,
+	&sensor_dev_attr_in16_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_base.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_base.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_base.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_boost.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_boost.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_boost.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_boost_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_boost_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_boost_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset1.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset2.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset3.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset4.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset5.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset6.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset7.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset8.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset9.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset10.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset11.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset12.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset1.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset2.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset3.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset4.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset5.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset6.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset7.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset8.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset9.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset10.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset11.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset12.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset1.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset2.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset3.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset4.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset5.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset6.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset7.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset8.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset9.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset10.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset11.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset12.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_pwm_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_pwm_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_pwm_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_auto_offset_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_auto_offset_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_auto_offset_hyst.dev_attr.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan3_input.dev_attr.attr,
+	&sensor_dev_attr_fan4_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan3_min.dev_attr.attr,
+	&sensor_dev_attr_fan4_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_smart_tach.dev_attr.attr,
+	&sensor_dev_attr_fan2_smart_tach.dev_attr.attr,
+	&sensor_dev_attr_fan3_smart_tach.dev_attr.attr,
+	&sensor_dev_attr_fan4_smart_tach.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm2.dev_attr.attr,
+	&sensor_dev_attr_pwm1_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm2_enable.dev_attr.attr,
+	&sensor_dev_attr_pwm1_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm2_freq.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_channels.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_channels.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_spinup_min.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_spinup_min.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_spinup_time.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_spinup_time.dev_attr.attr,
+	&dev_attr_pwm_auto_prochot_ramp.attr,
+	&dev_attr_pwm_auto_vrdhot_ramp.attr,
+	&sensor_dev_attr_vid1.dev_attr.attr,
+	&sensor_dev_attr_vid2.dev_attr.attr,
+	&sensor_dev_attr_prochot1.dev_attr.attr,
+	&sensor_dev_attr_prochot2.dev_attr.attr,
+	&sensor_dev_attr_prochot1_avg.dev_attr.attr,
+	&sensor_dev_attr_prochot2_avg.dev_attr.attr,
+	&sensor_dev_attr_prochot1_max.dev_attr.attr,
+	&sensor_dev_attr_prochot2_max.dev_attr.attr,
+	&sensor_dev_attr_prochot1_override.dev_attr.attr,
+	&sensor_dev_attr_prochot2_override.dev_attr.attr,
+	&sensor_dev_attr_prochot1_interval.dev_attr.attr,
+	&sensor_dev_attr_prochot2_interval.dev_attr.attr,
+	&dev_attr_prochot_override_duty_cycle.attr,
+	&dev_attr_prochot_short.attr,
+	&sensor_dev_attr_vrdhot1.dev_attr.attr,
+	&sensor_dev_attr_vrdhot2.dev_attr.attr,
+	&dev_attr_gpio.attr,
+	&dev_attr_alarms.attr,
+	NULL
+};
+
+static struct attribute_group lm93_attr_grp = {
+	.attrs = lm93_attrs,
+};
+
+static void lm93_init_client(struct i2c_client *client)
+{
+	int i;
+	u8 reg;
+
+	/* configure VID pin input thresholds */
+	reg = lm93_read_byte(client, LM93_REG_GPI_VID_CTL);
+	lm93_write_byte(client, LM93_REG_GPI_VID_CTL,
+			reg | (vid_agtl ? 0x03 : 0x00));
+
+	if (init) {
+		/* enable #ALERT pin */
+		reg = lm93_read_byte(client, LM93_REG_CONFIG);
+		lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x08);
+
+		/* enable ASF mode for BMC status registers */
+		reg = lm93_read_byte(client, LM93_REG_STATUS_CONTROL);
+		lm93_write_byte(client, LM93_REG_STATUS_CONTROL, reg | 0x02);
+
+		/* set sleep state to S0 */
+		lm93_write_byte(client, LM93_REG_SLEEP_CONTROL, 0);
+
+		/* unmask #VRDHOT and dynamic VCCP (if nec) error events */
+		reg = lm93_read_byte(client, LM93_REG_MISC_ERR_MASK);
+		reg &= ~0x03;
+		reg &= ~(vccp_limit_type[0] ? 0x10 : 0);
+		reg &= ~(vccp_limit_type[1] ? 0x20 : 0);
+		lm93_write_byte(client, LM93_REG_MISC_ERR_MASK, reg);
+	}
+
+	/* start monitoring */
+	reg = lm93_read_byte(client, LM93_REG_CONFIG);
+	lm93_write_byte(client, LM93_REG_CONFIG, reg | 0x01);
+
+	/* spin until ready */
+	for (i=0; i<20; i++) {
+		msleep(10);
+		if ((lm93_read_byte(client, LM93_REG_CONFIG) & 0x80) == 0x80)
+			return;
+	}
+
+	dev_warn(&client->dev,"timed out waiting for sensor "
+		 "chip to signal ready!\n");
+}
+
+static int lm93_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct lm93_data *data;
+	struct i2c_client *client;
+
+	int err = -ENODEV, func;
+	void (*update)(struct lm93_data *, struct i2c_client *);
+
+	/* choose update routine based on bus capabilities */
+	func = i2c_get_functionality(adapter);
+	if ( ((LM93_SMBUS_FUNC_FULL & func) == LM93_SMBUS_FUNC_FULL) &&
+			(!disable_block) ) {
+		dev_dbg(&adapter->dev,"using SMBus block data transactions\n");
+		update = lm93_update_client_full;
+	} else if ((LM93_SMBUS_FUNC_MIN & func) == LM93_SMBUS_FUNC_MIN) {
+		dev_dbg(&adapter->dev,"disabled SMBus block data "
+			"transactions\n");
+		update = lm93_update_client_min;
+	} else {
+		dev_dbg(&adapter->dev,"detect failed, "
+			"smbus byte and/or word data not supported!\n");
+		goto err_out;
+	}
+
+	/* OK. For now, we presume we have a valid client. We now create the
+	   client structure, even though we cannot fill it completely yet.
+	   But it allows us to access lm78_{read,write}_value. */
+
+	if ( !(data = kzalloc(sizeof(struct lm93_data), GFP_KERNEL))) {
+		dev_dbg(&adapter->dev,"out of memory!\n");
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	client = &data->client;
+	i2c_set_clientdata(client, data);
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &lm93_driver;
+
+	/* detection */
+	if (kind < 0) {
+		int mfr = lm93_read_byte(client, LM93_REG_MFR_ID);
+
+		if (mfr != 0x01) {
+			dev_dbg(&adapter->dev,"detect failed, "
+				"bad manufacturer id 0x%02x!\n", mfr);
+			goto err_free;
+		}
+	}
+
+	if (kind <= 0) {
+		int ver = lm93_read_byte(client, LM93_REG_VER);
+
+		if ((ver == LM93_MFR_ID) || (ver == LM93_MFR_ID_PROTOTYPE)) {
+			kind = lm93;
+		} else {
+			dev_dbg(&adapter->dev,"detect failed, "
+				"bad version id 0x%02x!\n", ver);
+			if (kind == 0)
+				dev_dbg(&adapter->dev,
+					"(ignored 'force' parameter)\n");
+			goto err_free;
+		}
+	}
+
+	/* fill in remaining client fields */
+	strlcpy(client->name, "lm93", I2C_NAME_SIZE);
+	dev_dbg(&adapter->dev,"loading %s at %d,0x%02x\n",
+		client->name, i2c_adapter_id(client->adapter),
+		client->addr);
+
+	/* housekeeping */
+	data->valid = 0;
+	data->update = update;
+	mutex_init(&data->update_lock);
+
+	/* tell the I2C layer a new client has arrived */
+	if ((err = i2c_attach_client(client)))
+		goto err_free;
+
+	/* initialize the chip */
+	lm93_init_client(client);
+
+	err = sysfs_create_group(&client->dev.kobj, &lm93_attr_grp);
+	if (err)
+		goto err_detach;
+
+	/* Register hwmon driver class */
+	data->class_dev = hwmon_device_register(&client->dev);
+	if ( !IS_ERR(data->class_dev))
+		return 0;
+
+	err = PTR_ERR(data->class_dev);
+	dev_err(&client->dev, "error registering hwmon device.\n");
+	sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
+err_detach:
+	i2c_detach_client(client);
+err_free:
+	kfree(data);
+err_out:
+	return err;
+}
+
+/* This function is called when:
+     * lm93_driver is inserted (when this module is loaded), for each
+       available adapter
+     * when a new adapter is inserted (and lm93_driver is still present) */
+static int lm93_attach_adapter(struct i2c_adapter *adapter)
+{
+	return i2c_probe(adapter, &addr_data, lm93_detect);
+}
+
+static int lm93_detach_client(struct i2c_client *client)
+{
+	struct lm93_data *data = i2c_get_clientdata(client);
+	int err = 0;
+
+	hwmon_device_unregister(data->class_dev);
+	sysfs_remove_group(&client->dev.kobj, &lm93_attr_grp);
+
+	err = i2c_detach_client(client);
+	if (!err)
+		kfree(data);
+	return err;
+}
+
+static struct i2c_driver lm93_driver = {
+	.driver = {
+		.name	= "lm93",
+	},
+	.attach_adapter	= lm93_attach_adapter,
+	.detach_client	= lm93_detach_client,
+};
+
+static int __init lm93_init(void)
+{
+	return i2c_add_driver(&lm93_driver);
+}
+
+static void __exit lm93_exit(void)
+{
+	i2c_del_driver(&lm93_driver);
+}
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>, "
+		"Hans J. Koch <hjk@linutronix.de");
+MODULE_DESCRIPTION("LM93 driver");
+MODULE_LICENSE("GPL");
+
+module_init(lm93_init);
+module_exit(lm93_exit);
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index c8a21be..f57c75d 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -1,7 +1,7 @@
 /*
  *  pc87360.c - Part of lm_sensors, Linux kernel modules
  *              for hardware monitoring
- *  Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
+ *  Copyright (C) 2004, 2007 Jean Delvare <khali@linux-fr.org>
  *
  *  Copied from smsc47m1.c:
  *  Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
@@ -37,8 +37,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/hwmon-vid.h>
@@ -47,12 +46,10 @@
 #include <asm/io.h>
 
 static u8 devid;
-static unsigned short address;
+static struct platform_device *pdev;
 static unsigned short extra_isa[3];
 static u8 confreg[4];
 
-enum chips { any_chip, pc87360, pc87363, pc87364, pc87365, pc87366 };
-
 static int init = 1;
 module_param(init, int, 0);
 MODULE_PARM_DESC(init,
@@ -178,11 +175,11 @@
 					 ((val) + 500) / 1000)
 
 /*
- * Client data (each client gets its own)
+ * Device data
  */
 
 struct pc87360_data {
-	struct i2c_client client;
+	const char *name;
 	struct class_device *class_dev;
 	struct mutex lock;
 	struct mutex update_lock;
@@ -222,27 +219,28 @@
  * Functions declaration
  */
 
-static int pc87360_detect(struct i2c_adapter *adapter);
-static int pc87360_detach_client(struct i2c_client *client);
+static int pc87360_probe(struct platform_device *pdev);
+static int __devexit pc87360_remove(struct platform_device *pdev);
 
 static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,
 			      u8 reg);
 static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,
 				u8 reg, u8 value);
-static void pc87360_init_client(struct i2c_client *client, int use_thermistors);
+static void pc87360_init_device(struct platform_device *pdev,
+				int use_thermistors);
 static struct pc87360_data *pc87360_update_device(struct device *dev);
 
 /*
- * Driver data (common to all clients)
+ * Driver data
  */
 
-static struct i2c_driver pc87360_driver = {
+static struct platform_driver pc87360_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
 		.name	= "pc87360",
 	},
-	.attach_adapter	= pc87360_detect,
-	.detach_client	= pc87360_detach_client,
+	.probe		= pc87360_probe,
+	.remove		= __devexit_p(pc87360_remove),
 };
 
 /*
@@ -281,8 +279,7 @@
 	size_t count)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct i2c_client *client = to_i2c_client(dev);
-	struct pc87360_data *data = i2c_get_clientdata(client);
+	struct pc87360_data *data = dev_get_drvdata(dev);
 	long fan_min = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
@@ -347,8 +344,7 @@
 	size_t count)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct i2c_client *client = to_i2c_client(dev);
-	struct pc87360_data *data = i2c_get_clientdata(client);
+	struct pc87360_data *data = dev_get_drvdata(dev);
 	long val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
@@ -410,8 +406,7 @@
 	size_t count)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct i2c_client *client = to_i2c_client(dev);
-	struct pc87360_data *data = i2c_get_clientdata(client);
+	struct pc87360_data *data = dev_get_drvdata(dev);
 	long val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
@@ -425,8 +420,7 @@
 	size_t count)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct i2c_client *client = to_i2c_client(dev);
-	struct pc87360_data *data = i2c_get_clientdata(client);
+	struct pc87360_data *data = dev_get_drvdata(dev);
 	long val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
@@ -511,8 +505,7 @@
 }
 static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct pc87360_data *data = i2c_get_clientdata(client);
+	struct pc87360_data *data = dev_get_drvdata(dev);
 	data->vrm = simple_strtoul(buf, NULL, 10);
 	return count;
 }
@@ -584,8 +577,7 @@
 	size_t count)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct i2c_client *client = to_i2c_client(dev);
-	struct pc87360_data *data = i2c_get_clientdata(client);
+	struct pc87360_data *data = dev_get_drvdata(dev);
 	long val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
@@ -599,8 +591,7 @@
 	size_t count)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct i2c_client *client = to_i2c_client(dev);
-	struct pc87360_data *data = i2c_get_clientdata(client);
+	struct pc87360_data *data = dev_get_drvdata(dev);
 	long val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
@@ -614,8 +605,7 @@
 	size_t count)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct i2c_client *client = to_i2c_client(dev);
-	struct pc87360_data *data = i2c_get_clientdata(client);
+	struct pc87360_data *data = dev_get_drvdata(dev);
 	long val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
@@ -715,8 +705,7 @@
 	size_t count)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct i2c_client *client = to_i2c_client(dev);
-	struct pc87360_data *data = i2c_get_clientdata(client);
+	struct pc87360_data *data = dev_get_drvdata(dev);
 	long val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
@@ -730,8 +719,7 @@
 	size_t count)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct i2c_client *client = to_i2c_client(dev);
-	struct pc87360_data *data = i2c_get_clientdata(client);
+	struct pc87360_data *data = dev_get_drvdata(dev);
 	long val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
@@ -745,8 +733,7 @@
 	size_t count)
 {
 	struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-	struct i2c_client *client = to_i2c_client(dev);
-	struct pc87360_data *data = i2c_get_clientdata(client);
+	struct pc87360_data *data = dev_get_drvdata(dev);
 	long val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
@@ -818,6 +805,14 @@
 	.attrs = pc8736x_temp_attr_array,
 };
 
+static ssize_t show_name(struct device *dev, struct device_attribute
+			 *devattr, char *buf)
+{
+	struct pc87360_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
 /*
  * Device detection, registration and update
  */
@@ -912,28 +907,18 @@
 	return 0;
 }
 
-static int pc87360_detect(struct i2c_adapter *adapter)
+static int __devinit pc87360_probe(struct platform_device *pdev)
 {
 	int i;
-	struct i2c_client *client;
 	struct pc87360_data *data;
 	int err = 0;
 	const char *name = "pc87360";
 	int use_thermistors = 0;
-	struct device *dev;
+	struct device *dev = &pdev->dev;
 
 	if (!(data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL)))
 		return -ENOMEM;
 
-	client = &data->client;
-	dev = &client->dev;
-	i2c_set_clientdata(client, data);
-	client->addr = address;
-	mutex_init(&data->lock);
-	client->adapter = adapter;
-	client->driver = &pc87360_driver;
-	client->flags = 0;
-
 	data->fannr = 2;
 	data->innr = 0;
 	data->tempnr = 0;
@@ -960,15 +945,17 @@
 		break;
 	}
 
-	strlcpy(client->name, name, sizeof(client->name));
+	data->name = name;
 	data->valid = 0;
+	mutex_init(&data->lock);
 	mutex_init(&data->update_lock);
+	platform_set_drvdata(pdev, data);
 
 	for (i = 0; i < 3; i++) {
 		if (((data->address[i] = extra_isa[i]))
 		 && !request_region(extra_isa[i], PC87360_EXTENT,
 		 		    pc87360_driver.driver.name)) {
-			dev_err(&client->dev, "Region 0x%x-0x%x already "
+			dev_err(dev, "Region 0x%x-0x%x already "
 				"in use!\n", extra_isa[i],
 				extra_isa[i]+PC87360_EXTENT-1);
 			for (i--; i >= 0; i--)
@@ -982,9 +969,6 @@
 	if (data->fannr)
 		data->fan_conf = confreg[0] | (confreg[1] << 8);
 
-	if ((err = i2c_attach_client(client)))
-		goto ERROR2;
-
 	/* Use the correct reference voltage
 	   Unless both the VLM and the TMS logical devices agree to
 	   use an external Vref, the internal one is used. */
@@ -996,7 +980,7 @@
 						PC87365_REG_TEMP_CONFIG);
 		}
 		data->in_vref = (i&0x02) ? 3025 : 2966;
-		dev_dbg(&client->dev, "Using %s reference voltage\n",
+		dev_dbg(dev, "Using %s reference voltage\n",
 			(i&0x02) ? "external" : "internal");
 
 		data->vid_conf = confreg[3];
@@ -1015,18 +999,18 @@
 		if (devid == 0xe9 && data->address[1]) /* PC87366 */
 			use_thermistors = confreg[2] & 0x40;
 
-		pc87360_init_client(client, use_thermistors);
+		pc87360_init_device(pdev, use_thermistors);
 	}
 
 	/* Register all-or-nothing sysfs groups */
 
 	if (data->innr &&
-	    (err = sysfs_create_group(&client->dev.kobj,
+	    (err = sysfs_create_group(&dev->kobj,
 				      &pc8736x_vin_group)))
 		goto ERROR3;
 
 	if (data->innr == 14 &&
-	    (err = sysfs_create_group(&client->dev.kobj,
+	    (err = sysfs_create_group(&dev->kobj,
 				      &pc8736x_therm_group)))
 		goto ERROR3;
 
@@ -1067,7 +1051,10 @@
 			goto ERROR3;
 	}
 
-	data->class_dev = hwmon_device_register(&client->dev);
+	if ((err = device_create_file(dev, &dev_attr_name)))
+		goto ERROR3;
+
+	data->class_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->class_dev)) {
 		err = PTR_ERR(data->class_dev);
 		goto ERROR3;
@@ -1075,14 +1062,12 @@
 	return 0;
 
 ERROR3:
+	device_remove_file(dev, &dev_attr_name);
 	/* can still remove groups whose members were added individually */
-	sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
-	sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
-	sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
-	sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
-
-	i2c_detach_client(client);
-ERROR2:
+	sysfs_remove_group(&dev->kobj, &pc8736x_temp_group);
+	sysfs_remove_group(&dev->kobj, &pc8736x_fan_group);
+	sysfs_remove_group(&dev->kobj, &pc8736x_therm_group);
+	sysfs_remove_group(&dev->kobj, &pc8736x_vin_group);
 	for (i = 0; i < 3; i++) {
 		if (data->address[i]) {
 			release_region(data->address[i], PC87360_EXTENT);
@@ -1093,20 +1078,18 @@
 	return err;
 }
 
-static int pc87360_detach_client(struct i2c_client *client)
+static int __devexit pc87360_remove(struct platform_device *pdev)
 {
-	struct pc87360_data *data = i2c_get_clientdata(client);
+	struct pc87360_data *data = platform_get_drvdata(pdev);
 	int i;
 
 	hwmon_device_unregister(data->class_dev);
 
-	sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
-	sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
-	sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
-	sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
-
-	if ((i = i2c_detach_client(client)))
-		return i;
+	device_remove_file(&pdev->dev, &dev_attr_name);
+	sysfs_remove_group(&pdev->dev.kobj, &pc8736x_temp_group);
+	sysfs_remove_group(&pdev->dev.kobj, &pc8736x_fan_group);
+	sysfs_remove_group(&pdev->dev.kobj, &pc8736x_therm_group);
+	sysfs_remove_group(&pdev->dev.kobj, &pc8736x_vin_group);
 
 	for (i = 0; i < 3; i++) {
 		if (data->address[i]) {
@@ -1144,9 +1127,10 @@
 	mutex_unlock(&(data->lock));
 }
 
-static void pc87360_init_client(struct i2c_client *client, int use_thermistors)
+static void pc87360_init_device(struct platform_device *pdev,
+				int use_thermistors)
 {
-	struct pc87360_data *data = i2c_get_clientdata(client);
+	struct pc87360_data *data = platform_get_drvdata(pdev);
 	int i, nr;
 	const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 };
 	const u8 init_temp[3] = { 2, 2, 1 };
@@ -1155,7 +1139,7 @@
 	if (init >= 2 && data->innr) {
 		reg = pc87360_read_value(data, LD_IN, NO_BANK,
 					 PC87365_REG_IN_CONVRATE);
-		dev_info(&client->dev, "VLM conversion set to "
+		dev_info(&pdev->dev, "VLM conversion set to "
 			 "1s period, 160us delay\n");
 		pc87360_write_value(data, LD_IN, NO_BANK,
 				    PC87365_REG_IN_CONVRATE,
@@ -1169,7 +1153,7 @@
 			reg = pc87360_read_value(data, LD_IN, i,
 						 PC87365_REG_IN_STATUS);
 			if (!(reg & 0x01)) {
-				dev_dbg(&client->dev, "Forcibly "
+				dev_dbg(&pdev->dev, "Forcibly "
 					"enabling in%d\n", i);
 				pc87360_write_value(data, LD_IN, i,
 						    PC87365_REG_IN_STATUS,
@@ -1193,7 +1177,7 @@
 			reg = pc87360_read_value(data, LD_TEMP, i,
 						 PC87365_REG_TEMP_STATUS);
 			if (!(reg & 0x01)) {
-				dev_dbg(&client->dev, "Forcibly "
+				dev_dbg(&pdev->dev, "Forcibly "
 					"enabling temp%d\n", i+1);
 				pc87360_write_value(data, LD_TEMP, i,
 						    PC87365_REG_TEMP_STATUS,
@@ -1210,7 +1194,7 @@
 				reg = pc87360_read_value(data, LD_TEMP,
 				      (i-11)/2, PC87365_REG_TEMP_STATUS);
 				if (reg & 0x01) {
-					dev_dbg(&client->dev, "Skipping "
+					dev_dbg(&pdev->dev, "Skipping "
 						"temp%d, pin already in use "
 						"by temp%d\n", i-7, (i-11)/2);
 					continue;
@@ -1220,7 +1204,7 @@
 				reg = pc87360_read_value(data, LD_IN, i,
 							 PC87365_REG_IN_STATUS);
 				if (!(reg & 0x01)) {
-					dev_dbg(&client->dev, "Forcibly "
+					dev_dbg(&pdev->dev, "Forcibly "
 						"enabling temp%d\n", i-7);
 					pc87360_write_value(data, LD_IN, i,
 						PC87365_REG_TEMP_STATUS,
@@ -1234,7 +1218,7 @@
 		reg = pc87360_read_value(data, LD_IN, NO_BANK,
 					 PC87365_REG_IN_CONFIG);
 		if (reg & 0x01) {
-			dev_dbg(&client->dev, "Forcibly "
+			dev_dbg(&pdev->dev, "Forcibly "
 				"enabling monitoring (VLM)\n");
 			pc87360_write_value(data, LD_IN, NO_BANK,
 					    PC87365_REG_IN_CONFIG,
@@ -1246,7 +1230,7 @@
 		reg = pc87360_read_value(data, LD_TEMP, NO_BANK,
 					 PC87365_REG_TEMP_CONFIG);
 		if (reg & 0x01) {
-			dev_dbg(&client->dev, "Forcibly enabling "
+			dev_dbg(&pdev->dev, "Forcibly enabling "
 				"monitoring (TMS)\n");
 			pc87360_write_value(data, LD_TEMP, NO_BANK,
 					    PC87365_REG_TEMP_CONFIG,
@@ -1268,9 +1252,9 @@
 	}
 }
 
-static void pc87360_autodiv(struct i2c_client *client, int nr)
+static void pc87360_autodiv(struct device *dev, int nr)
 {
-	struct pc87360_data *data = i2c_get_clientdata(client);
+	struct pc87360_data *data = dev_get_drvdata(dev);
 	u8 old_min = data->fan_min[nr];
 
 	/* Increase clock divider if needed and possible */
@@ -1280,7 +1264,7 @@
 			data->fan_status[nr] += 0x20;
 			data->fan_min[nr] >>= 1;
 			data->fan[nr] >>= 1;
-			dev_dbg(&client->dev, "Increasing "
+			dev_dbg(dev, "Increasing "
 				"clock divider to %d for fan %d\n",
 				FAN_DIV_FROM_REG(data->fan_status[nr]), nr+1);
 		}
@@ -1292,7 +1276,7 @@
 			data->fan_status[nr] -= 0x20;
 			data->fan_min[nr] <<= 1;
 			data->fan[nr] <<= 1;
-			dev_dbg(&client->dev, "Decreasing "
+			dev_dbg(dev, "Decreasing "
 				"clock divider to %d for fan %d\n",
 				FAN_DIV_FROM_REG(data->fan_status[nr]),
 				nr+1);
@@ -1309,14 +1293,13 @@
 
 static struct pc87360_data *pc87360_update_device(struct device *dev)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct pc87360_data *data = i2c_get_clientdata(client);
+	struct pc87360_data *data = dev_get_drvdata(dev);
 	u8 i;
 
 	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) {
-		dev_dbg(&client->dev, "Data update\n");
+		dev_dbg(dev, "Data update\n");
 
 		/* Fans */
 		for (i = 0; i < data->fannr; i++) {
@@ -1330,7 +1313,7 @@
 						   LD_FAN, NO_BANK,
 						   PC87360_REG_FAN_MIN(i));
 				/* Change clock divider if needed */
-				pc87360_autodiv(client, i);
+				pc87360_autodiv(dev, i);
 				/* Clear bits and write new divider */
 				pc87360_write_value(data, LD_FAN, NO_BANK,
 						    PC87360_REG_FAN_STATUS(i),
@@ -1418,9 +1401,53 @@
 	return data;
 }
 
+static int __init pc87360_device_add(unsigned short address)
+{
+	struct resource res = {
+		.name	= "pc87360",
+		.flags	= IORESOURCE_IO,
+	};
+	int err, i;
+
+	pdev = platform_device_alloc("pc87360", address);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR "pc87360: Device allocation failed\n");
+		goto exit;
+	}
+
+	for (i = 0; i < 3; i++) {
+		if (!extra_isa[i])
+			continue;
+		res.start = extra_isa[i];
+		res.end = extra_isa[i] + PC87360_EXTENT - 1;
+		err = platform_device_add_resources(pdev, &res, 1);
+		if (err) {
+			printk(KERN_ERR "pc87360: Device resource[%d] "
+			       "addition failed (%d)\n", i, err);
+			goto exit_device_put;
+		}
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR "pc87360: Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
 static int __init pc87360_init(void)
 {
-	int i;
+	int err, i;
+	unsigned short address = 0;
 
 	if (pc87360_find(0x2e, &devid, extra_isa)
 	 && pc87360_find(0x4e, &devid, extra_isa)) {
@@ -1443,12 +1470,27 @@
 		return -ENODEV;
 	}
 
-	return i2c_isa_add_driver(&pc87360_driver);
+	err = platform_driver_register(&pc87360_driver);
+	if (err)
+		goto exit;
+
+	/* Sets global pdev as a side effect */
+	err = pc87360_device_add(address);
+	if (err)
+		goto exit_driver;
+
+	return 0;
+
+ exit_driver:
+	platform_driver_unregister(&pc87360_driver);
+ exit:
+	return err;
 }
 
 static void __exit pc87360_exit(void)
 {
-	i2c_isa_del_driver(&pc87360_driver);
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&pc87360_driver);
 }
 
 
diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c
index 29354fa..2915bc4 100644
--- a/drivers/hwmon/pc87427.c
+++ b/drivers/hwmon/pc87427.c
@@ -484,7 +484,6 @@
 	struct resource *res;
 	int i;
 
-	platform_set_drvdata(pdev, NULL);
 	hwmon_device_unregister(data->class_dev);
 	device_remove_file(&pdev->dev, &dev_attr_name);
 	for (i = 0; i < 8; i++) {
@@ -492,6 +491,7 @@
 			continue;
 		sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]);
 	}
+	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index 3f40026..92956eb 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -54,9 +54,9 @@
 #include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
 #include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/jiffies.h>
@@ -72,17 +72,13 @@
 MODULE_PARM_DESC(force_addr,
 		 "Initialize the base address of the sensors");
 
-/* Device address
-   Note that we can't determine the ISA address until we have initialized
-   our module */
-static unsigned short address;
+static struct platform_device *pdev;
 
 /* Many SIS5595 constants specified below */
 
 /* Length of ISA address segment */
 #define SIS5595_EXTENT 8
 /* PCI Config Registers */
-#define SIS5595_REVISION_REG 0x08
 #define SIS5595_BASE_REG 0x68
 #define SIS5595_PIN_REG 0x7A
 #define SIS5595_ENABLE_REG 0x7B
@@ -165,7 +161,8 @@
 /* For each registered chip, we need to keep some data in memory.
    The structure is dynamically allocated. */
 struct sis5595_data {
-	struct i2c_client client;
+	unsigned short addr;
+	const char *name;
 	struct class_device *class_dev;
 	struct mutex lock;
 
@@ -189,102 +186,88 @@
 
 static struct pci_dev *s_bridge;	/* pointer to the (only) sis5595 */
 
-static int sis5595_detect(struct i2c_adapter *adapter);
-static int sis5595_detach_client(struct i2c_client *client);
+static int sis5595_probe(struct platform_device *pdev);
+static int __devexit sis5595_remove(struct platform_device *pdev);
 
-static int sis5595_read_value(struct i2c_client *client, u8 reg);
-static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value);
+static int sis5595_read_value(struct sis5595_data *data, u8 reg);
+static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value);
 static struct sis5595_data *sis5595_update_device(struct device *dev);
-static void sis5595_init_client(struct i2c_client *client);
+static void sis5595_init_device(struct sis5595_data *data);
 
-static struct i2c_driver sis5595_driver = {
+static struct platform_driver sis5595_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
 		.name	= "sis5595",
 	},
-	.attach_adapter	= sis5595_detect,
-	.detach_client	= sis5595_detach_client,
+	.probe		= sis5595_probe,
+	.remove		= __devexit_p(sis5595_remove),
 };
 
 /* 4 Voltages */
-static ssize_t show_in(struct device *dev, char *buf, int nr)
+static ssize_t show_in(struct device *dev, struct device_attribute *da,
+		       char *buf)
 {
 	struct sis5595_data *data = sis5595_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr]));
 }
 
-static ssize_t show_in_min(struct device *dev, char *buf, int nr)
+static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
+			   char *buf)
 {
 	struct sis5595_data *data = sis5595_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr]));
 }
 
-static ssize_t show_in_max(struct device *dev, char *buf, int nr)
+static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
+			   char *buf)
 {
 	struct sis5595_data *data = sis5595_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr]));
 }
 
-static ssize_t set_in_min(struct device *dev, const char *buf,
-	       size_t count, int nr)
+static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
+			  const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct sis5595_data *data = i2c_get_clientdata(client);
+	struct sis5595_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->in_min[nr] = IN_TO_REG(val);
-	sis5595_write_value(client, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
+	sis5595_write_value(data, SIS5595_REG_IN_MIN(nr), data->in_min[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 
-static ssize_t set_in_max(struct device *dev, const char *buf,
-	       size_t count, int nr)
+static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
+			  const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct sis5595_data *data = i2c_get_clientdata(client);
+	struct sis5595_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->in_max[nr] = IN_TO_REG(val);
-	sis5595_write_value(client, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
+	sis5595_write_value(data, SIS5595_REG_IN_MAX(nr), data->in_max[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 
 #define show_in_offset(offset)					\
-static ssize_t							\
-	show_in##offset (struct device *dev, struct device_attribute *attr, char *buf)		\
-{								\
-	return show_in(dev, buf, offset);			\
-}								\
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, 		\
-		show_in##offset, NULL);				\
-static ssize_t							\
-	show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf)	\
-{								\
-	return show_in_min(dev, buf, offset);			\
-}								\
-static ssize_t							\
-	show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf)	\
-{								\
-	return show_in_max(dev, buf, offset);			\
-}								\
-static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr,	\
-		const char *buf, size_t count)			\
-{								\
-	return set_in_min(dev, buf, count, offset);		\
-}								\
-static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr,	\
-		const char *buf, size_t count)			\
-{								\
-	return set_in_max(dev, buf, count, offset);		\
-}								\
-static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,		\
-		show_in##offset##_min, set_in##offset##_min);	\
-static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,		\
-		show_in##offset##_max, set_in##offset##_max);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\
+		show_in, NULL, offset);				\
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,	\
+		show_in_min, set_in_min, offset);		\
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,	\
+		show_in_max, set_in_max, offset);
 
 show_in_offset(0);
 show_in_offset(1);
@@ -307,13 +290,12 @@
 
 static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct sis5595_data *data = i2c_get_clientdata(client);
+	struct sis5595_data *data = dev_get_drvdata(dev);
 	long val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->temp_over = TEMP_TO_REG(val);
-	sis5595_write_value(client, SIS5595_REG_TEMP_OVER, data->temp_over);
+	sis5595_write_value(data, SIS5595_REG_TEMP_OVER, data->temp_over);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -326,13 +308,12 @@
 
 static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct sis5595_data *data = i2c_get_clientdata(client);
+	struct sis5595_data *data = dev_get_drvdata(dev);
 	long val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->temp_hyst = TEMP_TO_REG(val);
-	sis5595_write_value(client, SIS5595_REG_TEMP_HYST, data->temp_hyst);
+	sis5595_write_value(data, SIS5595_REG_TEMP_HYST, data->temp_hyst);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -344,37 +325,47 @@
 		show_temp_hyst, set_temp_hyst);
 
 /* 2 Fans */
-static ssize_t show_fan(struct device *dev, char *buf, int nr)
+static ssize_t show_fan(struct device *dev, struct device_attribute *da,
+			char *buf)
 {
 	struct sis5595_data *data = sis5595_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
 		DIV_FROM_REG(data->fan_div[nr])) );
 }
 
-static ssize_t show_fan_min(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
+			    char *buf)
 {
 	struct sis5595_data *data = sis5595_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	return sprintf(buf,"%d\n", FAN_FROM_REG(data->fan_min[nr],
 		DIV_FROM_REG(data->fan_div[nr])) );
 }
 
-static ssize_t set_fan_min(struct device *dev, const char *buf,
-		size_t count, int nr)
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
+			   const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct sis5595_data *data = i2c_get_clientdata(client);
+	struct sis5595_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
-	sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
+	sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 
-static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
+			    char *buf)
 {
 	struct sis5595_data *data = sis5595_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
 }
 
@@ -382,11 +373,12 @@
    determined in part by the fan divisor.  This follows the principle of
    least surprise; the user doesn't expect the fan minimum to change just
    because the divisor changed. */
-static ssize_t set_fan_div(struct device *dev, const char *buf,
-	size_t count, int nr)
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
+			   const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct sis5595_data *data = i2c_get_clientdata(client);
+	struct sis5595_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	unsigned long min;
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 	int reg;
@@ -394,7 +386,7 @@
 	mutex_lock(&data->update_lock);
 	min = FAN_FROM_REG(data->fan_min[nr],
 			DIV_FROM_REG(data->fan_div[nr]));
-	reg = sis5595_read_value(client, SIS5595_REG_FANDIV);
+	reg = sis5595_read_value(data, SIS5595_REG_FANDIV);
 
 	switch (val) {
 	case 1: data->fan_div[nr] = 0; break;
@@ -402,7 +394,7 @@
 	case 4: data->fan_div[nr] = 2; break;
 	case 8: data->fan_div[nr] = 3; break;
 	default:
-		dev_err(&client->dev, "fan_div value %ld not "
+		dev_err(dev, "fan_div value %ld not "
 			"supported. Choose one of 1, 2, 4 or 8!\n", val);
 		mutex_unlock(&data->update_lock);
 		return -EINVAL;
@@ -416,55 +408,25 @@
 		reg = (reg & 0x3f) | (data->fan_div[nr] << 6);
 		break;
 	}
-	sis5595_write_value(client, SIS5595_REG_FANDIV, reg);
+	sis5595_write_value(data, SIS5595_REG_FANDIV, reg);
 	data->fan_min[nr] =
 		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
-	sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
+	sis5595_write_value(data, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 
 #define show_fan_offset(offset)						\
-static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf)	\
-{									\
-	return show_fan(dev, buf, offset - 1);			\
-}									\
-static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf)	\
-{									\
-	return show_fan_min(dev, buf, offset - 1);			\
-}									\
-static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf)	\
-{									\
-	return show_fan_div(dev, buf, offset - 1);			\
-}									\
-static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr,		\
-		const char *buf, size_t count)				\
-{									\
-	return set_fan_min(dev, buf, count, offset - 1);		\
-}									\
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
-		show_fan_##offset##_min, set_fan_##offset##_min);
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,			\
+		show_fan, NULL, offset - 1);				\
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
+		show_fan_min, set_fan_min, offset - 1);			\
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\
+		show_fan_div, set_fan_div, offset - 1);
 
 show_fan_offset(1);
 show_fan_offset(2);
 
-static ssize_t set_fan_1_div(struct device *dev, struct device_attribute *attr, const char *buf,
-		size_t count)
-{
-	return set_fan_div(dev, buf, count, 0) ;
-}
-
-static ssize_t set_fan_2_div(struct device *dev, struct device_attribute *attr, const char *buf,
-		size_t count)
-{
-	return set_fan_div(dev, buf, count, 1) ;
-}
-static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,
-		show_fan_1_div, set_fan_1_div);
-static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,
-		show_fan_2_div, set_fan_2_div);
-
 /* Alarms */
 static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
 {
@@ -473,28 +435,37 @@
 }
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 
-static struct attribute *sis5595_attributes[] = {
-	&dev_attr_in0_input.attr,
-	&dev_attr_in0_min.attr,
-	&dev_attr_in0_max.attr,
-	&dev_attr_in1_input.attr,
-	&dev_attr_in1_min.attr,
-	&dev_attr_in1_max.attr,
-	&dev_attr_in2_input.attr,
-	&dev_attr_in2_min.attr,
-	&dev_attr_in2_max.attr,
-	&dev_attr_in3_input.attr,
-	&dev_attr_in3_min.attr,
-	&dev_attr_in3_max.attr,
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct sis5595_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
-	&dev_attr_fan1_input.attr,
-	&dev_attr_fan1_min.attr,
-	&dev_attr_fan1_div.attr,
-	&dev_attr_fan2_input.attr,
-	&dev_attr_fan2_min.attr,
-	&dev_attr_fan2_div.attr,
+static struct attribute *sis5595_attributes[] = {
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
 
 	&dev_attr_alarms.attr,
+	&dev_attr_name.attr,
 	NULL
 };
 
@@ -503,9 +474,9 @@
 };
 
 static struct attribute *sis5595_attributes_opt[] = {
-	&dev_attr_in4_input.attr,
-	&dev_attr_in4_min.attr,
-	&dev_attr_in4_max.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
 
 	&dev_attr_temp1_input.attr,
 	&dev_attr_temp1_max.attr,
@@ -518,68 +489,35 @@
 };
  
 /* This is called when the module is loaded */
-static int sis5595_detect(struct i2c_adapter *adapter)
+static int __devinit sis5595_probe(struct platform_device *pdev)
 {
 	int err = 0;
 	int i;
-	struct i2c_client *new_client;
 	struct sis5595_data *data;
+	struct resource *res;
 	char val;
-	u16 a;
 
-	if (force_addr)
-		address = force_addr & ~(SIS5595_EXTENT - 1);
 	/* Reserve the ISA region */
-	if (!request_region(address, SIS5595_EXTENT,
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!request_region(res->start, SIS5595_EXTENT,
 			    sis5595_driver.driver.name)) {
 		err = -EBUSY;
 		goto exit;
 	}
-	if (force_addr) {
-		dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", address);
-		if (PCIBIOS_SUCCESSFUL !=
-		    pci_write_config_word(s_bridge, SIS5595_BASE_REG, address))
-			goto exit_release;
-		if (PCIBIOS_SUCCESSFUL !=
-		    pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a))
-			goto exit_release;
-		if ((a & ~(SIS5595_EXTENT - 1)) != address)
-			/* doesn't work for some chips? */
-			goto exit_release;
-	}
-
-	if (PCIBIOS_SUCCESSFUL !=
-	    pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) {
-		goto exit_release;
-	}
-	if ((val & 0x80) == 0) {
-		if (PCIBIOS_SUCCESSFUL !=
-		    pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG,
-					  val | 0x80))
-			goto exit_release;
-		if (PCIBIOS_SUCCESSFUL !=
-		    pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val))
-			goto exit_release;
-		if ((val & 0x80) == 0) 
-			/* doesn't work for some chips! */
-			goto exit_release;
-	}
 
 	if (!(data = kzalloc(sizeof(struct sis5595_data), GFP_KERNEL))) {
 		err = -ENOMEM;
 		goto exit_release;
 	}
 
-	new_client = &data->client;
-	new_client->addr = address;
 	mutex_init(&data->lock);
-	i2c_set_clientdata(new_client, data);
-	new_client->adapter = adapter;
-	new_client->driver = &sis5595_driver;
-	new_client->flags = 0;
+	mutex_init(&data->update_lock);
+	data->addr = res->start;
+	data->name = "sis5595";
+	platform_set_drvdata(pdev, data);
 
 	/* Check revision and pin registers to determine whether 4 or 5 voltages */
-	pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision));
+	pci_read_config_byte(s_bridge, PCI_REVISION_ID, &data->revision);
 	/* 4 voltages, 1 temp */
 	data->maxins = 3;
 	if (data->revision >= REV2MIN) {
@@ -589,47 +527,37 @@
 			data->maxins = 4;
 	}
 	
-	/* Fill in the remaining client fields and put it into the global list */
-	strlcpy(new_client->name, "sis5595", I2C_NAME_SIZE);
-
-	data->valid = 0;
-	mutex_init(&data->update_lock);
-
-	/* Tell the I2C layer a new client has arrived */
-	if ((err = i2c_attach_client(new_client)))
-		goto exit_free;
-	
 	/* Initialize the SIS5595 chip */
-	sis5595_init_client(new_client);
+	sis5595_init_device(data);
 
 	/* A few vars need to be filled upon startup */
 	for (i = 0; i < 2; i++) {
-		data->fan_min[i] = sis5595_read_value(new_client,
+		data->fan_min[i] = sis5595_read_value(data,
 					SIS5595_REG_FAN_MIN(i));
 	}
 
 	/* Register sysfs hooks */
-	if ((err = sysfs_create_group(&new_client->dev.kobj, &sis5595_group)))
-		goto exit_detach;
+	if ((err = sysfs_create_group(&pdev->dev.kobj, &sis5595_group)))
+		goto exit_free;
 	if (data->maxins == 4) {
-		if ((err = device_create_file(&new_client->dev,
-					      &dev_attr_in4_input))
-		 || (err = device_create_file(&new_client->dev,
-					      &dev_attr_in4_min))
-		 || (err = device_create_file(&new_client->dev,
-					      &dev_attr_in4_max)))
+		if ((err = device_create_file(&pdev->dev,
+					&sensor_dev_attr_in4_input.dev_attr))
+		 || (err = device_create_file(&pdev->dev,
+					&sensor_dev_attr_in4_min.dev_attr))
+		 || (err = device_create_file(&pdev->dev,
+					&sensor_dev_attr_in4_max.dev_attr)))
 			goto exit_remove_files;
 	} else {
-		if ((err = device_create_file(&new_client->dev,
+		if ((err = device_create_file(&pdev->dev,
 					      &dev_attr_temp1_input))
-		 || (err = device_create_file(&new_client->dev,
+		 || (err = device_create_file(&pdev->dev,
 					      &dev_attr_temp1_max))
-		 || (err = device_create_file(&new_client->dev,
+		 || (err = device_create_file(&pdev->dev,
 					      &dev_attr_temp1_max_hyst)))
 			goto exit_remove_files;
 	}
 
-	data->class_dev = hwmon_device_register(&new_client->dev);
+	data->class_dev = hwmon_device_register(&pdev->dev);
 	if (IS_ERR(data->class_dev)) {
 		err = PTR_ERR(data->class_dev);
 		goto exit_remove_files;
@@ -638,32 +566,26 @@
 	return 0;
 
 exit_remove_files:
-	sysfs_remove_group(&new_client->dev.kobj, &sis5595_group);
-	sysfs_remove_group(&new_client->dev.kobj, &sis5595_group_opt);
-exit_detach:
-	i2c_detach_client(new_client);
+	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
+	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt);
 exit_free:
 	kfree(data);
 exit_release:
-	release_region(address, SIS5595_EXTENT);
+	release_region(res->start, SIS5595_EXTENT);
 exit:
 	return err;
 }
 
-static int sis5595_detach_client(struct i2c_client *client)
+static int __devexit sis5595_remove(struct platform_device *pdev)
 {
-	struct sis5595_data *data = i2c_get_clientdata(client);
-	int err;
+	struct sis5595_data *data = platform_get_drvdata(pdev);
 
 	hwmon_device_unregister(data->class_dev);
-	sysfs_remove_group(&client->dev.kobj, &sis5595_group);
-	sysfs_remove_group(&client->dev.kobj, &sis5595_group_opt);
+	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group);
+	sysfs_remove_group(&pdev->dev.kobj, &sis5595_group_opt);
 
-	if ((err = i2c_detach_client(client)))
-		return err;
-
-	release_region(client->addr, SIS5595_EXTENT);
-
+	release_region(data->addr, SIS5595_EXTENT);
+	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 
 	return 0;
@@ -671,41 +593,37 @@
 
 
 /* ISA access must be locked explicitly. */
-static int sis5595_read_value(struct i2c_client *client, u8 reg)
+static int sis5595_read_value(struct sis5595_data *data, u8 reg)
 {
 	int res;
 
-	struct sis5595_data *data = i2c_get_clientdata(client);
 	mutex_lock(&data->lock);
-	outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
-	res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET);
+	outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
+	res = inb_p(data->addr + SIS5595_DATA_REG_OFFSET);
 	mutex_unlock(&data->lock);
 	return res;
 }
 
-static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value)
+static void sis5595_write_value(struct sis5595_data *data, u8 reg, u8 value)
 {
-	struct sis5595_data *data = i2c_get_clientdata(client);
 	mutex_lock(&data->lock);
-	outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);
-	outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET);
+	outb_p(reg, data->addr + SIS5595_ADDR_REG_OFFSET);
+	outb_p(value, data->addr + SIS5595_DATA_REG_OFFSET);
 	mutex_unlock(&data->lock);
-	return 0;
 }
 
 /* Called when we have found a new SIS5595. */
-static void sis5595_init_client(struct i2c_client *client)
+static void __devinit sis5595_init_device(struct sis5595_data *data)
 {
-	u8 config = sis5595_read_value(client, SIS5595_REG_CONFIG);
+	u8 config = sis5595_read_value(data, SIS5595_REG_CONFIG);
 	if (!(config & 0x01))
-		sis5595_write_value(client, SIS5595_REG_CONFIG,
+		sis5595_write_value(data, SIS5595_REG_CONFIG,
 				(config & 0xf7) | 0x01);
 }
 
 static struct sis5595_data *sis5595_update_device(struct device *dev)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct sis5595_data *data = i2c_get_clientdata(client);
+	struct sis5595_data *data = dev_get_drvdata(dev);
 	int i;
 
 	mutex_lock(&data->update_lock);
@@ -715,35 +633,35 @@
 
 		for (i = 0; i <= data->maxins; i++) {
 			data->in[i] =
-			    sis5595_read_value(client, SIS5595_REG_IN(i));
+			    sis5595_read_value(data, SIS5595_REG_IN(i));
 			data->in_min[i] =
-			    sis5595_read_value(client,
+			    sis5595_read_value(data,
 					       SIS5595_REG_IN_MIN(i));
 			data->in_max[i] =
-			    sis5595_read_value(client,
+			    sis5595_read_value(data,
 					       SIS5595_REG_IN_MAX(i));
 		}
 		for (i = 0; i < 2; i++) {
 			data->fan[i] =
-			    sis5595_read_value(client, SIS5595_REG_FAN(i));
+			    sis5595_read_value(data, SIS5595_REG_FAN(i));
 			data->fan_min[i] =
-			    sis5595_read_value(client,
+			    sis5595_read_value(data,
 					       SIS5595_REG_FAN_MIN(i));
 		}
 		if (data->maxins == 3) {
 			data->temp =
-			    sis5595_read_value(client, SIS5595_REG_TEMP);
+			    sis5595_read_value(data, SIS5595_REG_TEMP);
 			data->temp_over =
-			    sis5595_read_value(client, SIS5595_REG_TEMP_OVER);
+			    sis5595_read_value(data, SIS5595_REG_TEMP_OVER);
 			data->temp_hyst =
-			    sis5595_read_value(client, SIS5595_REG_TEMP_HYST);
+			    sis5595_read_value(data, SIS5595_REG_TEMP_HYST);
 		}
-		i = sis5595_read_value(client, SIS5595_REG_FANDIV);
+		i = sis5595_read_value(data, SIS5595_REG_FANDIV);
 		data->fan_div[0] = (i >> 4) & 0x03;
 		data->fan_div[1] = i >> 6;
 		data->alarms =
-		    sis5595_read_value(client, SIS5595_REG_ALARM1) |
-		    (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8);
+		    sis5595_read_value(data, SIS5595_REG_ALARM1) |
+		    (sis5595_read_value(data, SIS5595_REG_ALARM2) << 8);
 		data->last_updated = jiffies;
 		data->valid = 1;
 	}
@@ -774,10 +692,50 @@
 	PCI_DEVICE_ID_SI_5598,
 	0 };
 
+static int __devinit sis5595_device_add(unsigned short address)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + SIS5595_EXTENT - 1,
+		.name	= "sis5595",
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	pdev = platform_device_alloc("sis5595", address);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR "sis5595: Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		printk(KERN_ERR "sis5595: Device resource addition failed "
+		       "(%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR "sis5595: Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
 static int __devinit sis5595_pci_probe(struct pci_dev *dev,
 				       const struct pci_device_id *id)
 {
-	u16 val;
+	u16 address;
+	u8 enable;
 	int *i;
 
 	for (i = blacklist; *i != 0; i++) {
@@ -790,27 +748,68 @@
 		}
 	}
 	
+	force_addr &= ~(SIS5595_EXTENT - 1);
+	if (force_addr) {
+		dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", force_addr);
+		pci_write_config_word(dev, SIS5595_BASE_REG, force_addr);
+	}
+
 	if (PCIBIOS_SUCCESSFUL !=
-	    pci_read_config_word(dev, SIS5595_BASE_REG, &val))
+	    pci_read_config_word(dev, SIS5595_BASE_REG, &address)) {
+		dev_err(&dev->dev, "Failed to read ISA address\n");
 		return -ENODEV;
+	}
 	
-	address = val & ~(SIS5595_EXTENT - 1);
-	if (address == 0 && force_addr == 0) {
+	address &= ~(SIS5595_EXTENT - 1);
+	if (!address) {
 		dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n");
 		return -ENODEV;
 	}
+	if (force_addr && address != force_addr) {
+		/* doesn't work for some chips? */
+		dev_err(&dev->dev, "Failed to force ISA address\n");
+		return -ENODEV;
+	}
+
+	if (PCIBIOS_SUCCESSFUL !=
+	    pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable)) {
+		dev_err(&dev->dev, "Failed to read enable register\n");
+		return -ENODEV;
+	}
+	if (!(enable & 0x80)) {
+		if ((PCIBIOS_SUCCESSFUL !=
+		     pci_write_config_byte(dev, SIS5595_ENABLE_REG,
+					   enable | 0x80))
+		 || (PCIBIOS_SUCCESSFUL !=
+		     pci_read_config_byte(dev, SIS5595_ENABLE_REG, &enable))
+		 || (!(enable & 0x80))) {
+			/* doesn't work for some chips! */
+			dev_err(&dev->dev, "Failed to enable HWM device\n");
+			return -ENODEV;
+		}
+	}
+
+	if (platform_driver_register(&sis5595_driver)) {
+		dev_dbg(&dev->dev, "Failed to register sis5595 driver\n");
+		goto exit;
+	}
 
 	s_bridge = pci_dev_get(dev);
-	if (i2c_isa_add_driver(&sis5595_driver)) {
-		pci_dev_put(s_bridge);
-		s_bridge = NULL;
-	}
+	/* Sets global pdev as a side effect */
+	if (sis5595_device_add(address))
+		goto exit_unregister;
 
 	/* Always return failure here.  This is to allow other drivers to bind
 	 * to this pci device.  We don't really want to have control over the
 	 * pci device, we only wanted to read as few register values from it.
 	 */
 	return -ENODEV;
+
+exit_unregister:
+	pci_dev_put(dev);
+	platform_driver_unregister(&sis5595_driver);
+exit:
+	return -ENODEV;
 }
 
 static struct pci_driver sis5595_pci_driver = {
@@ -828,7 +827,8 @@
 {
 	pci_unregister_driver(&sis5595_pci_driver);
 	if (s_bridge != NULL) {
-		i2c_isa_del_driver(&sis5595_driver);
+		platform_device_unregister(pdev);
+		platform_driver_unregister(&sis5595_driver);
 		pci_dev_put(s_bridge);
 		s_bridge = NULL;
 	}
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index 943abbd..45266b3 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -174,6 +174,8 @@
    REG: count of 90kHz pulses / revolution */
 static int fan_from_reg(u16 reg)
 {
+	if (reg == 0 || reg == 0xffff)
+		return 0;
 	return 90000 * 60 / reg;
 }
 
@@ -333,7 +335,7 @@
 	superio_enter();
 	id = superio_inb(SUPERIO_REG_DEVID);
 
-	if ((id != 0x6f) && (id != 0x81)) {
+	if ((id != 0x6f) && (id != 0x81) && (id != 0x85)) {
 		superio_exit();
 		return -ENODEV;
 	}
@@ -346,7 +348,8 @@
 
 	printk(KERN_INFO DRVNAME ": found SMSC %s "
 		"(base address 0x%04x, revision %u)\n",
-		id == 0x81 ? "SCH5307-NS" : "LPC47B397-NC", *addr, rev);
+		id == 0x81 ? "SCH5307-NS" : id == 0x85 ? "SCH5317" :
+	       "LPC47B397-NC", *addr, rev);
 
 	superio_exit();
 	return 0;
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index 1e21c8c..d318196 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -134,7 +134,7 @@
 
 
 static int smsc47m1_probe(struct platform_device *pdev);
-static int smsc47m1_remove(struct platform_device *pdev);
+static int __devexit smsc47m1_remove(struct platform_device *pdev);
 static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
 		int init);
 
@@ -585,6 +585,8 @@
 
 	if ((err = device_create_file(dev, &dev_attr_alarms)))
 		goto error_remove_files;
+	if ((err = device_create_file(dev, &dev_attr_name)))
+		goto error_remove_files;
 
 	data->class_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->class_dev)) {
@@ -597,6 +599,7 @@
 error_remove_files:
 	sysfs_remove_group(&dev->kobj, &smsc47m1_group);
 error_free:
+	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 error_release:
 	release_region(res->start, SMSC_EXTENT);
@@ -608,12 +611,12 @@
 	struct smsc47m1_data *data = platform_get_drvdata(pdev);
 	struct resource *res;
 
-	platform_set_drvdata(pdev, NULL);
 	hwmon_device_unregister(data->class_dev);
 	sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group);
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
 	release_region(res->start, SMSC_EXTENT);
+	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 
 	return 0;
@@ -693,15 +696,12 @@
 		goto exit_device_put;
 	}
 
-	pdev->dev.platform_data = kmalloc(sizeof(struct smsc47m1_sio_data),
-					  GFP_KERNEL);
-	if (!pdev->dev.platform_data) {
-		err = -ENOMEM;
+	err = platform_device_add_data(pdev, sio_data,
+				       sizeof(struct smsc47m1_sio_data));
+	if (err) {
 		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
 		goto exit_device_put;
 	}
-	memcpy(pdev->dev.platform_data, sio_data,
-	       sizeof(struct smsc47m1_sio_data));
 
 	err = platform_device_add(pdev);
 	if (err) {
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
index a012f39..d3a3ba0 100644
--- a/drivers/hwmon/smsc47m192.c
+++ b/drivers/hwmon/smsc47m192.c
@@ -31,6 +31,7 @@
 #include <linux/hwmon-vid.h>
 #include <linux/err.h>
 #include <linux/sysfs.h>
+#include <linux/mutex.h>
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
@@ -97,7 +98,7 @@
 struct smsc47m192_data {
 	struct i2c_client client;
 	struct class_device *class_dev;
-	struct semaphore update_lock;
+	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
 	unsigned long last_updated;	/* In jiffies */
 
@@ -164,11 +165,11 @@
 	struct smsc47m192_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_min[nr] = IN_TO_REG(val, nr);
 	i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MIN(nr),
 							data->in_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -181,11 +182,11 @@
 	struct smsc47m192_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->in_max[nr] = IN_TO_REG(val, nr);
 	i2c_smbus_write_byte_data(client, SMSC47M192_REG_IN_MAX(nr),
 							data->in_max[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -243,11 +244,11 @@
 	struct smsc47m192_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_min[nr] = TEMP_TO_REG(val);
 	i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MIN[nr],
 						data->temp_min[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -260,11 +261,11 @@
 	struct smsc47m192_data *data = i2c_get_clientdata(client);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_max[nr] = TEMP_TO_REG(val);
 	i2c_smbus_write_byte_data(client, SMSC47M192_REG_TEMP_MAX[nr],
 						data->temp_max[nr]);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -287,7 +288,7 @@
 	u8 sfr = i2c_smbus_read_byte_data(client, SMSC47M192_REG_SFR);
 	long val = simple_strtol(buf, NULL, 10);
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 	data->temp_offset[nr] = TEMP_TO_REG(val);
 	if (nr>1)
 		i2c_smbus_write_byte_data(client,
@@ -303,7 +304,7 @@
 	} else if ((sfr & 0x10) == (nr==0 ? 0x10 : 0))
 		i2c_smbus_write_byte_data(client,
 					SMSC47M192_REG_TEMP_OFFSET(nr), 0);
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 	return count;
 }
 
@@ -360,8 +361,8 @@
 static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 0x0010);
 static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 0x0020);
 static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 0x0040);
-static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 0x4000);
-static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 0x8000);
+static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 0x4000);
+static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_alarm, NULL, 0x8000);
 static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0x0001);
 static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 0x0002);
 static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 0x0004);
@@ -411,13 +412,13 @@
 	&sensor_dev_attr_temp2_min.dev_attr.attr,
 	&sensor_dev_attr_temp2_offset.dev_attr.attr,
 	&sensor_dev_attr_temp2_alarm.dev_attr.attr,
-	&sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+	&sensor_dev_attr_temp2_fault.dev_attr.attr,
 	&sensor_dev_attr_temp3_input.dev_attr.attr,
 	&sensor_dev_attr_temp3_max.dev_attr.attr,
 	&sensor_dev_attr_temp3_min.dev_attr.attr,
 	&sensor_dev_attr_temp3_offset.dev_attr.attr,
 	&sensor_dev_attr_temp3_alarm.dev_attr.attr,
-	&sensor_dev_attr_temp3_input_fault.dev_attr.attr,
+	&sensor_dev_attr_temp3_fault.dev_attr.attr,
 
 	&dev_attr_cpu0_vid.attr,
 	&dev_attr_vrm.attr,
@@ -531,7 +532,7 @@
 	/* Fill in the remaining client fields and put into the global list */
 	strlcpy(client->name, "smsc47m192", I2C_NAME_SIZE);
 	data->vrm = vid_which_vrm();
-	init_MUTEX(&data->update_lock);
+	mutex_init(&data->update_lock);
 
 	/* Tell the I2C layer a new client has arrived */
 	if ((err = i2c_attach_client(client)))
@@ -594,7 +595,7 @@
 	struct smsc47m192_data *data = i2c_get_clientdata(client);
 	int i, config;
 
-	down(&data->update_lock);
+	mutex_lock(&data->update_lock);
 
 	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
 	 || !data->valid) {
@@ -645,7 +646,7 @@
 		data->valid = 1;
 	}
 
-	up(&data->update_lock);
+	mutex_unlock(&data->update_lock);
 
 	return data;
 }
diff --git a/drivers/hwmon/thmc50.c b/drivers/hwmon/thmc50.c
new file mode 100644
index 0000000..9395b52
--- /dev/null
+++ b/drivers/hwmon/thmc50.c
@@ -0,0 +1,440 @@
+/*
+    thmc50.c - Part of lm_sensors, Linux kernel modules for hardware
+             monitoring
+    Copyright (C) 2007 Krzysztof Helt <krzysztof.h1@wp.pl>
+    Based on 2.4 driver by Frodo Looijaard <frodol@dds.nl> and
+    Philip Edelbrock <phil@netroedge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+MODULE_LICENSE("GPL");
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD_2(thmc50, adm1022);
+I2C_CLIENT_MODULE_PARM(adm1022_temp3, "List of adapter,address pairs "
+			"to enable 3rd temperature (ADM1022 only)");
+
+/* Many THMC50 constants specified below */
+
+/* The THMC50 registers */
+#define THMC50_REG_CONF				0x40
+#define THMC50_REG_COMPANY_ID			0x3E
+#define THMC50_REG_DIE_CODE			0x3F
+#define THMC50_REG_ANALOG_OUT			0x19
+
+const static u8 THMC50_REG_TEMP[] = { 0x27, 0x26, 0x20 };
+const static u8 THMC50_REG_TEMP_MIN[] = { 0x3A, 0x38, 0x2C };
+const static u8 THMC50_REG_TEMP_MAX[] = { 0x39, 0x37, 0x2B };
+
+#define THMC50_REG_CONF_nFANOFF			0x20
+
+/* Each client has this additional data */
+struct thmc50_data {
+	struct i2c_client client;
+	struct class_device *class_dev;
+
+	struct mutex update_lock;
+	enum chips type;
+	unsigned long last_updated;	/* In jiffies */
+	char has_temp3;		/* !=0 if it is ADM1022 in temp3 mode */
+	char valid;		/* !=0 if following fields are valid */
+
+	/* Register values */
+	s8 temp_input[3];
+	s8 temp_max[3];
+	s8 temp_min[3];
+	u8 analog_out;
+};
+
+static int thmc50_attach_adapter(struct i2c_adapter *adapter);
+static int thmc50_detach_client(struct i2c_client *client);
+static void thmc50_init_client(struct i2c_client *client);
+static struct thmc50_data *thmc50_update_device(struct device *dev);
+
+static struct i2c_driver thmc50_driver = {
+	.driver = {
+		.name = "thmc50",
+	},
+	.attach_adapter = thmc50_attach_adapter,
+	.detach_client = thmc50_detach_client,
+};
+
+static ssize_t show_analog_out(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct thmc50_data *data = thmc50_update_device(dev);
+	return sprintf(buf, "%d\n", data->analog_out);
+}
+
+static ssize_t set_analog_out(struct device *dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct thmc50_data *data = i2c_get_clientdata(client);
+	int tmp = simple_strtoul(buf, NULL, 10);
+	int config;
+
+	mutex_lock(&data->update_lock);
+	data->analog_out = SENSORS_LIMIT(tmp, 0, 255);
+	i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT,
+				  data->analog_out);
+
+	config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
+	if (data->analog_out == 0)
+		config &= ~THMC50_REG_CONF_nFANOFF;
+	else
+		config |= THMC50_REG_CONF_nFANOFF;
+	i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config);
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+/* There is only one PWM mode = DC */
+static ssize_t show_pwm_mode(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	return sprintf(buf, "0\n");
+}
+
+/* Temperatures */
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct thmc50_data *data = thmc50_update_device(dev);
+	return sprintf(buf, "%d\n", data->temp_input[nr] * 1000);
+}
+
+static ssize_t show_temp_min(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct thmc50_data *data = thmc50_update_device(dev);
+	return sprintf(buf, "%d\n", data->temp_min[nr] * 1000);
+}
+
+static ssize_t set_temp_min(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct thmc50_data *data = i2c_get_clientdata(client);
+	int val = simple_strtol(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	data->temp_min[nr] = SENSORS_LIMIT(val / 1000, -128, 127);
+	i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MIN[nr],
+				  data->temp_min[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct thmc50_data *data = thmc50_update_device(dev);
+	return sprintf(buf, "%d\n", data->temp_max[nr] * 1000);
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	int nr = to_sensor_dev_attr(attr)->index;
+	struct i2c_client *client = to_i2c_client(dev);
+	struct thmc50_data *data = i2c_get_clientdata(client);
+	int val = simple_strtol(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+	data->temp_max[nr] = SENSORS_LIMIT(val / 1000, -128, 127);
+	i2c_smbus_write_byte_data(client, THMC50_REG_TEMP_MAX[nr],
+				  data->temp_max[nr]);
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define temp_reg(offset)						\
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp,	\
+			NULL, offset - 1);				\
+static SENSOR_DEVICE_ATTR(temp##offset##_min, S_IRUGO | S_IWUSR,	\
+			show_temp_min, set_temp_min, offset - 1);	\
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,	\
+			show_temp_max, set_temp_max, offset - 1);
+
+temp_reg(1);
+temp_reg(2);
+temp_reg(3);
+
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_analog_out,
+			  set_analog_out, 0);
+static SENSOR_DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL, 0);
+
+static struct attribute *thmc50_attributes[] = {
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_min.dev_attr.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_min.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_pwm1.dev_attr.attr,
+	&sensor_dev_attr_pwm1_mode.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group thmc50_group = {
+	.attrs = thmc50_attributes,
+};
+
+/* for ADM1022 3rd temperature mode */
+static struct attribute *adm1022_attributes[] = {
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_min.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group adm1022_group = {
+	.attrs = adm1022_attributes,
+};
+
+static int thmc50_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	unsigned company;
+	unsigned revision;
+	unsigned config;
+	struct i2c_client *client;
+	struct thmc50_data *data;
+	struct device *dev;
+	int err = 0;
+	const char *type_name = "";
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		pr_debug("thmc50: detect failed, "
+			 "smbus byte data not supported!\n");
+		goto exit;
+	}
+
+	/* OK. For now, we presume we have a valid client. We now create the
+	   client structure, even though we cannot fill it completely yet.
+	   But it allows us to access thmc50 registers. */
+	if (!(data = kzalloc(sizeof(struct thmc50_data), GFP_KERNEL))) {
+		pr_debug("thmc50: detect failed, kzalloc failed!\n");
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	client = &data->client;
+	i2c_set_clientdata(client, data);
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &thmc50_driver;
+	dev = &client->dev;
+
+	pr_debug("thmc50: Probing for THMC50 at 0x%2X on bus %d\n",
+		 client->addr, i2c_adapter_id(client->adapter));
+
+	/* Now, we do the remaining detection. */
+	company = i2c_smbus_read_byte_data(client, THMC50_REG_COMPANY_ID);
+	revision = i2c_smbus_read_byte_data(client, THMC50_REG_DIE_CODE);
+	config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
+
+	if (kind == 0)
+		kind = thmc50;
+	else if (kind < 0) {
+		err = -ENODEV;
+		if (revision >= 0xc0 && ((config & 0x10) == 0)) {
+			if (company == 0x49) {
+				kind = thmc50;
+				err = 0;
+			} else if (company == 0x41) {
+				kind = adm1022;
+				err = 0;
+			}
+		}
+	}
+	if (err == -ENODEV) {
+		pr_debug("thmc50: Detection of THMC50/ADM1022 failed\n");
+		goto exit_free;
+	}
+	pr_debug("thmc50: Detected %s (version %x, revision %x)\n",
+		 type_name, (revision >> 4) - 0xc, revision & 0xf);
+	data->type = kind;
+
+	if (kind == thmc50)
+		type_name = "thmc50";
+	else if (kind == adm1022) {
+		int id = i2c_adapter_id(client->adapter);
+		int i;
+
+		type_name = "adm1022";
+		data->has_temp3 = (config >> 7) & 1;	/* config MSB */
+		for (i = 0; i + 1 < adm1022_temp3_num; i += 2)
+			if (adm1022_temp3[i] == id &&
+			    adm1022_temp3[i + 1] == address) {
+				/* enable 2nd remote temp */
+				data->has_temp3 = 1;
+				break;
+			}
+	}
+
+	/* Fill in the remaining client fields & put it into the global list */
+	strlcpy(client->name, type_name, I2C_NAME_SIZE);
+	mutex_init(&data->update_lock);
+
+	/* Tell the I2C layer a new client has arrived */
+	if ((err = i2c_attach_client(client)))
+		goto exit_free;
+
+	thmc50_init_client(client);
+
+	/* Register sysfs hooks */
+	if ((err = sysfs_create_group(&client->dev.kobj, &thmc50_group)))
+		goto exit_detach;
+
+	/* Register ADM1022 sysfs hooks */
+	if (data->type == adm1022)
+		if ((err = sysfs_create_group(&client->dev.kobj,
+					      &adm1022_group)))
+			goto exit_remove_sysfs_thmc50;
+
+	/* Register a new directory entry with module sensors */
+	data->class_dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->class_dev)) {
+		err = PTR_ERR(data->class_dev);
+		goto exit_remove_sysfs;
+	}
+
+	return 0;
+
+exit_remove_sysfs:
+	if (data->type == adm1022)
+		sysfs_remove_group(&client->dev.kobj, &adm1022_group);
+exit_remove_sysfs_thmc50:
+	sysfs_remove_group(&client->dev.kobj, &thmc50_group);
+exit_detach:
+	i2c_detach_client(client);
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
+static int thmc50_attach_adapter(struct i2c_adapter *adapter)
+{
+	if (!(adapter->class & I2C_CLASS_HWMON))
+		return 0;
+	return i2c_probe(adapter, &addr_data, thmc50_detect);
+}
+
+static int thmc50_detach_client(struct i2c_client *client)
+{
+	struct thmc50_data *data = i2c_get_clientdata(client);
+	int err;
+
+	hwmon_device_unregister(data->class_dev);
+	sysfs_remove_group(&client->dev.kobj, &thmc50_group);
+	if (data->type == adm1022)
+		sysfs_remove_group(&client->dev.kobj, &adm1022_group);
+
+	if ((err = i2c_detach_client(client)))
+		return err;
+
+	kfree(data);
+
+	return 0;
+}
+
+static void thmc50_init_client(struct i2c_client *client)
+{
+	struct thmc50_data *data = i2c_get_clientdata(client);
+	int config;
+
+	data->analog_out = i2c_smbus_read_byte_data(client,
+						    THMC50_REG_ANALOG_OUT);
+	/* set up to at least 1 */
+	if (data->analog_out == 0) {
+		data->analog_out = 1;
+		i2c_smbus_write_byte_data(client, THMC50_REG_ANALOG_OUT,
+					  data->analog_out);
+	}
+	config = i2c_smbus_read_byte_data(client, THMC50_REG_CONF);
+	config |= 0x1;	/* start the chip if it is in standby mode */
+	if (data->has_temp3)
+		config |= 0x80;		/* enable 2nd remote temp */
+	i2c_smbus_write_byte_data(client, THMC50_REG_CONF, config);
+}
+
+static struct thmc50_data *thmc50_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct thmc50_data *data = i2c_get_clientdata(client);
+	int timeout = HZ / 5 + (data->type == thmc50 ? HZ : 0);
+
+	mutex_lock(&data->update_lock);
+
+	if (time_after(jiffies, data->last_updated + timeout)
+	    || !data->valid) {
+
+		int temps = data->has_temp3 ? 3 : 2;
+		int i;
+		for (i = 0; i < temps; i++) {
+			data->temp_input[i] = i2c_smbus_read_byte_data(client,
+						THMC50_REG_TEMP[i]);
+			data->temp_max[i] = i2c_smbus_read_byte_data(client,
+						THMC50_REG_TEMP_MAX[i]);
+			data->temp_min[i] = i2c_smbus_read_byte_data(client,
+						THMC50_REG_TEMP_MIN[i]);
+		}
+		data->analog_out =
+		    i2c_smbus_read_byte_data(client, THMC50_REG_ANALOG_OUT);
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->update_lock);
+
+	return data;
+}
+
+static int __init sm_thmc50_init(void)
+{
+	return i2c_add_driver(&thmc50_driver);
+}
+
+static void __exit sm_thmc50_exit(void)
+{
+	i2c_del_driver(&thmc50_driver);
+}
+
+MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>");
+MODULE_DESCRIPTION("THMC50 driver");
+
+module_init(sm_thmc50_init);
+module_exit(sm_thmc50_exit);
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index 9a440c8..696c8a2 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -34,9 +34,9 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
 #include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/mutex.h>
@@ -51,10 +51,7 @@
 MODULE_PARM_DESC(force_addr,
 		 "Initialize the base address of the sensors");
 
-/* Device address
-   Note that we can't determine the ISA address until we have initialized
-   our module */
-static unsigned short address;
+static struct platform_device *pdev;
 
 /*
    The Via 686a southbridge has a LM78-like chip integrated on the same IC.
@@ -295,7 +292,8 @@
 /* For each registered chip, we need to keep some data in memory.
    The structure is dynamically allocated. */
 struct via686a_data {
-	struct i2c_client client;
+	unsigned short addr;
+	const char *name;
 	struct class_device *class_dev;
 	struct mutex update_lock;
 	char valid;		/* !=0 if following fields are valid */
@@ -315,98 +313,85 @@
 
 static struct pci_dev *s_bridge;	/* pointer to the (only) via686a */
 
-static int via686a_detect(struct i2c_adapter *adapter);
-static int via686a_detach_client(struct i2c_client *client);
+static int via686a_probe(struct platform_device *pdev);
+static int __devexit via686a_remove(struct platform_device *pdev);
 
-static inline int via686a_read_value(struct i2c_client *client, u8 reg)
+static inline int via686a_read_value(struct via686a_data *data, u8 reg)
 {
-	return (inb_p(client->addr + reg));
+	return inb_p(data->addr + reg);
 }
 
-static inline void via686a_write_value(struct i2c_client *client, u8 reg,
+static inline void via686a_write_value(struct via686a_data *data, u8 reg,
 				       u8 value)
 {
-	outb_p(value, client->addr + reg);
+	outb_p(value, data->addr + reg);
 }
 
 static struct via686a_data *via686a_update_device(struct device *dev);
-static void via686a_init_client(struct i2c_client *client);
+static void via686a_init_device(struct via686a_data *data);
 
 /* following are the sysfs callback functions */
 
 /* 7 voltage sensors */
-static ssize_t show_in(struct device *dev, char *buf, int nr) {
+static ssize_t show_in(struct device *dev, struct device_attribute *da,
+		char *buf) {
 	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr));
 }
 
-static ssize_t show_in_min(struct device *dev, char *buf, int nr) {
+static ssize_t show_in_min(struct device *dev, struct device_attribute *da,
+		char *buf) {
 	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr));
 }
 
-static ssize_t show_in_max(struct device *dev, char *buf, int nr) {
+static ssize_t show_in_max(struct device *dev, struct device_attribute *da,
+		char *buf) {
 	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr));
 }
 
-static ssize_t set_in_min(struct device *dev, const char *buf,
-		size_t count, int nr) {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_in_min(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count) {
+	struct via686a_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->in_min[nr] = IN_TO_REG(val, nr);
-	via686a_write_value(client, VIA686A_REG_IN_MIN(nr),
+	via686a_write_value(data, VIA686A_REG_IN_MIN(nr),
 			data->in_min[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
-static ssize_t set_in_max(struct device *dev, const char *buf,
-		size_t count, int nr) {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_in_max(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count) {
+	struct via686a_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->in_max[nr] = IN_TO_REG(val, nr);
-	via686a_write_value(client, VIA686A_REG_IN_MAX(nr),
+	via686a_write_value(data, VIA686A_REG_IN_MAX(nr),
 			data->in_max[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 #define show_in_offset(offset)					\
-static ssize_t 							\
-	show_in##offset (struct device *dev, struct device_attribute *attr, char *buf)		\
-{								\
-	return show_in(dev, buf, offset);			\
-}								\
-static ssize_t 							\
-	show_in##offset##_min (struct device *dev, struct device_attribute *attr, char *buf)	\
-{								\
-	return show_in_min(dev, buf, offset);		\
-}								\
-static ssize_t 							\
-	show_in##offset##_max (struct device *dev, struct device_attribute *attr, char *buf)	\
-{								\
-	return show_in_max(dev, buf, offset);		\
-}								\
-static ssize_t set_in##offset##_min (struct device *dev, struct device_attribute *attr, 	\
-		const char *buf, size_t count) 			\
-{								\
-	return set_in_min(dev, buf, count, offset);		\
-}								\
-static ssize_t set_in##offset##_max (struct device *dev, struct device_attribute *attr,	\
-			const char *buf, size_t count)		\
-{								\
-	return set_in_max(dev, buf, count, offset);		\
-}								\
-static DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in##offset, NULL);\
-static DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, 	\
-		show_in##offset##_min, set_in##offset##_min);	\
-static DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, 	\
-		show_in##offset##_max, set_in##offset##_max);
+static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO,		\
+		show_in, NULL, offset);				\
+static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR,	\
+		show_in_min, set_in_min, offset);		\
+static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR,	\
+		show_in_max, set_in_max, offset);
 
 show_in_offset(0);
 show_in_offset(1);
@@ -415,150 +400,128 @@
 show_in_offset(4);
 
 /* 3 temperatures */
-static ssize_t show_temp(struct device *dev, char *buf, int nr) {
+static ssize_t show_temp(struct device *dev, struct device_attribute *da,
+		char *buf) {
 	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	return sprintf(buf, "%ld\n", TEMP_FROM_REG10(data->temp[nr]));
 }
-static ssize_t show_temp_over(struct device *dev, char *buf, int nr) {
+static ssize_t show_temp_over(struct device *dev, struct device_attribute *da,
+		char *buf) {
 	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_over[nr]));
 }
-static ssize_t show_temp_hyst(struct device *dev, char *buf, int nr) {
+static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da,
+		char *buf) {
 	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	return sprintf(buf, "%ld\n", TEMP_FROM_REG(data->temp_hyst[nr]));
 }
-static ssize_t set_temp_over(struct device *dev, const char *buf,
-		size_t count, int nr) {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_temp_over(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count) {
+	struct via686a_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	int val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->temp_over[nr] = TEMP_TO_REG(val);
-	via686a_write_value(client, VIA686A_REG_TEMP_OVER[nr],
+	via686a_write_value(data, VIA686A_REG_TEMP_OVER[nr],
 			    data->temp_over[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
-static ssize_t set_temp_hyst(struct device *dev, const char *buf,
-		size_t count, int nr) {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count) {
+	struct via686a_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	int val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->temp_hyst[nr] = TEMP_TO_REG(val);
-	via686a_write_value(client, VIA686A_REG_TEMP_HYST[nr],
+	via686a_write_value(data, VIA686A_REG_TEMP_HYST[nr],
 			    data->temp_hyst[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 #define show_temp_offset(offset)					\
-static ssize_t show_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf)	\
-{									\
-	return show_temp(dev, buf, offset - 1);				\
-}									\
-static ssize_t								\
-show_temp_##offset##_over (struct device *dev, struct device_attribute *attr, char *buf)		\
-{									\
-	return show_temp_over(dev, buf, offset - 1);			\
-}									\
-static ssize_t								\
-show_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, char *buf)		\
-{									\
-	return show_temp_hyst(dev, buf, offset - 1);			\
-}									\
-static ssize_t set_temp_##offset##_over (struct device *dev, struct device_attribute *attr, 		\
-		const char *buf, size_t count) 				\
-{									\
-	return set_temp_over(dev, buf, count, offset - 1);		\
-}									\
-static ssize_t set_temp_##offset##_hyst (struct device *dev, struct device_attribute *attr, 		\
-		const char *buf, size_t count) 				\
-{									\
-	return set_temp_hyst(dev, buf, count, offset - 1);		\
-}									\
-static DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_temp_##offset, NULL);\
-static DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, 		\
-		show_temp_##offset##_over, set_temp_##offset##_over);	\
-static DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, 		\
-		show_temp_##offset##_hyst, set_temp_##offset##_hyst);
+static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO,		\
+		show_temp, NULL, offset - 1);				\
+static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR,	\
+		show_temp_over, set_temp_over, offset - 1);		\
+static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR,	\
+		show_temp_hyst, set_temp_hyst, offset - 1);
 
 show_temp_offset(1);
 show_temp_offset(2);
 show_temp_offset(3);
 
 /* 2 Fans */
-static ssize_t show_fan(struct device *dev, char *buf, int nr) {
+static ssize_t show_fan(struct device *dev, struct device_attribute *da,
+		char *buf) {
 	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr],
 				DIV_FROM_REG(data->fan_div[nr])) );
 }
-static ssize_t show_fan_min(struct device *dev, char *buf, int nr) {
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *da,
+		char *buf) {
 	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	return sprintf(buf, "%d\n",
 		FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr])) );
 }
-static ssize_t show_fan_div(struct device *dev, char *buf, int nr) {
+static ssize_t show_fan_div(struct device *dev, struct device_attribute *da,
+		char *buf) {
 	struct via686a_data *data = via686a_update_device(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[nr]) );
 }
-static ssize_t set_fan_min(struct device *dev, const char *buf,
-		size_t count, int nr) {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_fan_min(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count) {
+	struct via686a_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	int val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
-	via686a_write_value(client, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
+	via686a_write_value(data, VIA686A_REG_FAN_MIN(nr+1), data->fan_min[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
-static ssize_t set_fan_div(struct device *dev, const char *buf,
-		size_t count, int nr) {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct via686a_data *data = i2c_get_clientdata(client);
+static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
+		const char *buf, size_t count) {
+	struct via686a_data *data = dev_get_drvdata(dev);
+	struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+	int nr = attr->index;
 	int val = simple_strtol(buf, NULL, 10);
 	int old;
 
 	mutex_lock(&data->update_lock);
-	old = via686a_read_value(client, VIA686A_REG_FANDIV);
+	old = via686a_read_value(data, VIA686A_REG_FANDIV);
 	data->fan_div[nr] = DIV_TO_REG(val);
 	old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
-	via686a_write_value(client, VIA686A_REG_FANDIV, old);
+	via686a_write_value(data, VIA686A_REG_FANDIV, old);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 
 #define show_fan_offset(offset)						\
-static ssize_t show_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf)	\
-{									\
-	return show_fan(dev, buf, offset - 1);				\
-}									\
-static ssize_t show_fan_##offset##_min (struct device *dev, struct device_attribute *attr, char *buf)	\
-{									\
-	return show_fan_min(dev, buf, offset - 1);			\
-}									\
-static ssize_t show_fan_##offset##_div (struct device *dev, struct device_attribute *attr, char *buf)	\
-{									\
-	return show_fan_div(dev, buf, offset - 1);			\
-}									\
-static ssize_t set_fan_##offset##_min (struct device *dev, struct device_attribute *attr, 		\
-	const char *buf, size_t count) 					\
-{									\
-	return set_fan_min(dev, buf, count, offset - 1);		\
-}									\
-static ssize_t set_fan_##offset##_div (struct device *dev, struct device_attribute *attr, 		\
-		const char *buf, size_t count) 				\
-{									\
-	return set_fan_div(dev, buf, count, offset - 1);		\
-}									\
-static DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\
-static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, 		\
-		show_fan_##offset##_min, set_fan_##offset##_min);	\
-static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, 		\
-		show_fan_##offset##_div, set_fan_##offset##_div);
+static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO,			\
+		show_fan, NULL, offset - 1);				\
+static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\
+		show_fan_min, set_fan_min, offset - 1);			\
+static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\
+		show_fan_div, set_fan_div, offset - 1);
 
 show_fan_offset(1);
 show_fan_offset(2);
@@ -570,41 +533,50 @@
 }
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 
+static ssize_t show_name(struct device *dev, struct device_attribute
+			 *devattr, char *buf)
+{
+	struct via686a_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
 static struct attribute *via686a_attributes[] = {
-	&dev_attr_in0_input.attr,
-	&dev_attr_in1_input.attr,
-	&dev_attr_in2_input.attr,
-	&dev_attr_in3_input.attr,
-	&dev_attr_in4_input.attr,
-	&dev_attr_in0_min.attr,
-	&dev_attr_in1_min.attr,
-	&dev_attr_in2_min.attr,
-	&dev_attr_in3_min.attr,
-	&dev_attr_in4_min.attr,
-	&dev_attr_in0_max.attr,
-	&dev_attr_in1_max.attr,
-	&dev_attr_in2_max.attr,
-	&dev_attr_in3_max.attr,
-	&dev_attr_in4_max.attr,
+	&sensor_dev_attr_in0_input.dev_attr.attr,
+	&sensor_dev_attr_in1_input.dev_attr.attr,
+	&sensor_dev_attr_in2_input.dev_attr.attr,
+	&sensor_dev_attr_in3_input.dev_attr.attr,
+	&sensor_dev_attr_in4_input.dev_attr.attr,
+	&sensor_dev_attr_in0_min.dev_attr.attr,
+	&sensor_dev_attr_in1_min.dev_attr.attr,
+	&sensor_dev_attr_in2_min.dev_attr.attr,
+	&sensor_dev_attr_in3_min.dev_attr.attr,
+	&sensor_dev_attr_in4_min.dev_attr.attr,
+	&sensor_dev_attr_in0_max.dev_attr.attr,
+	&sensor_dev_attr_in1_max.dev_attr.attr,
+	&sensor_dev_attr_in2_max.dev_attr.attr,
+	&sensor_dev_attr_in3_max.dev_attr.attr,
+	&sensor_dev_attr_in4_max.dev_attr.attr,
 
-	&dev_attr_temp1_input.attr,
-	&dev_attr_temp2_input.attr,
-	&dev_attr_temp3_input.attr,
-	&dev_attr_temp1_max.attr,
-	&dev_attr_temp2_max.attr,
-	&dev_attr_temp3_max.attr,
-	&dev_attr_temp1_max_hyst.attr,
-	&dev_attr_temp2_max_hyst.attr,
-	&dev_attr_temp3_max_hyst.attr,
+	&sensor_dev_attr_temp1_input.dev_attr.attr,
+	&sensor_dev_attr_temp2_input.dev_attr.attr,
+	&sensor_dev_attr_temp3_input.dev_attr.attr,
+	&sensor_dev_attr_temp1_max.dev_attr.attr,
+	&sensor_dev_attr_temp2_max.dev_attr.attr,
+	&sensor_dev_attr_temp3_max.dev_attr.attr,
+	&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+	&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
 
-	&dev_attr_fan1_input.attr,
-	&dev_attr_fan2_input.attr,
-	&dev_attr_fan1_min.attr,
-	&dev_attr_fan2_min.attr,
-	&dev_attr_fan1_div.attr,
-	&dev_attr_fan2_div.attr,
+	&sensor_dev_attr_fan1_input.dev_attr.attr,
+	&sensor_dev_attr_fan2_input.dev_attr.attr,
+	&sensor_dev_attr_fan1_min.dev_attr.attr,
+	&sensor_dev_attr_fan2_min.dev_attr.attr,
+	&sensor_dev_attr_fan1_div.dev_attr.attr,
+	&sensor_dev_attr_fan2_div.dev_attr.attr,
 
 	&dev_attr_alarms.attr,
+	&dev_attr_name.attr,
 	NULL
 };
 
@@ -612,58 +584,29 @@
 	.attrs = via686a_attributes,
 };
 
-/* The driver. I choose to use type i2c_driver, as at is identical to both
-   smbus_driver and isa_driver, and clients could be of either kind */
-static struct i2c_driver via686a_driver = {
+static struct platform_driver via686a_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
 		.name	= "via686a",
 	},
-	.attach_adapter	= via686a_detect,
-	.detach_client	= via686a_detach_client,
+	.probe		= via686a_probe,
+	.remove		= __devexit_p(via686a_remove),
 };
 
 
 /* This is called when the module is loaded */
-static int via686a_detect(struct i2c_adapter *adapter)
+static int __devinit via686a_probe(struct platform_device *pdev)
 {
-	struct i2c_client *new_client;
 	struct via686a_data *data;
-	int err = 0;
-	const char client_name[] = "via686a";
-	u16 val;
-
-	/* 8231 requires multiple of 256, we enforce that on 686 as well */
-	if (force_addr) {
-		address = force_addr & 0xFF00;
-		dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n",
-			 address);
-		if (PCIBIOS_SUCCESSFUL !=
-		    pci_write_config_word(s_bridge, VIA686A_BASE_REG, address))
-			return -ENODEV;
-	}
-	if (PCIBIOS_SUCCESSFUL !=
-	    pci_read_config_word(s_bridge, VIA686A_ENABLE_REG, &val))
-		return -ENODEV;
-	if (!(val & 0x0001)) {
-		if (force_addr) {
-			dev_info(&adapter->dev, "enabling sensors\n");
-			if (PCIBIOS_SUCCESSFUL !=
-			    pci_write_config_word(s_bridge, VIA686A_ENABLE_REG,
-						  val | 0x0001))
-				return -ENODEV;
-		} else {
-			dev_warn(&adapter->dev, "sensors disabled - enable "
-				 "with force_addr=0x%x\n", address);
-			return -ENODEV;
-		}
-	}
+	struct resource *res;
+	int err;
 
 	/* Reserve the ISA region */
-	if (!request_region(address, VIA686A_EXTENT,
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!request_region(res->start, VIA686A_EXTENT,
 			    via686a_driver.driver.name)) {
-		dev_err(&adapter->dev, "region 0x%x already in use!\n",
-			address);
+		dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
+			(unsigned long)res->start, (unsigned long)res->end);
 		return -ENODEV;
 	}
 
@@ -672,30 +615,19 @@
 		goto exit_release;
 	}
 
-	new_client = &data->client;
-	i2c_set_clientdata(new_client, data);
-	new_client->addr = address;
-	new_client->adapter = adapter;
-	new_client->driver = &via686a_driver;
-	new_client->flags = 0;
-
-	/* Fill in the remaining client fields and put into the global list */
-	strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
-
-	data->valid = 0;
+	platform_set_drvdata(pdev, data);
+	data->addr = res->start;
+	data->name = "via686a";
 	mutex_init(&data->update_lock);
-	/* Tell the I2C layer a new client has arrived */
-	if ((err = i2c_attach_client(new_client)))
-		goto exit_free;
 
 	/* Initialize the VIA686A chip */
-	via686a_init_client(new_client);
+	via686a_init_device(data);
 
 	/* Register sysfs hooks */
-	if ((err = sysfs_create_group(&new_client->dev.kobj, &via686a_group)))
-		goto exit_detach;
+	if ((err = sysfs_create_group(&pdev->dev.kobj, &via686a_group)))
+		goto exit_free;
 
-	data->class_dev = hwmon_device_register(&new_client->dev);
+	data->class_dev = hwmon_device_register(&pdev->dev);
 	if (IS_ERR(data->class_dev)) {
 		err = PTR_ERR(data->class_dev);
 		goto exit_remove_files;
@@ -704,51 +636,46 @@
 	return 0;
 
 exit_remove_files:
-	sysfs_remove_group(&new_client->dev.kobj, &via686a_group);
-exit_detach:
-	i2c_detach_client(new_client);
+	sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
 exit_free:
 	kfree(data);
 exit_release:
-	release_region(address, VIA686A_EXTENT);
+	release_region(res->start, VIA686A_EXTENT);
 	return err;
 }
 
-static int via686a_detach_client(struct i2c_client *client)
+static int __devexit via686a_remove(struct platform_device *pdev)
 {
-	struct via686a_data *data = i2c_get_clientdata(client);
-	int err;
+	struct via686a_data *data = platform_get_drvdata(pdev);
 
 	hwmon_device_unregister(data->class_dev);
-	sysfs_remove_group(&client->dev.kobj, &via686a_group);
+	sysfs_remove_group(&pdev->dev.kobj, &via686a_group);
 
-	if ((err = i2c_detach_client(client)))
-		return err;
-
-	release_region(client->addr, VIA686A_EXTENT);
+	release_region(data->addr, VIA686A_EXTENT);
+	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 
 	return 0;
 }
 
-static void via686a_init_client(struct i2c_client *client)
+static void __devinit via686a_init_device(struct via686a_data *data)
 {
 	u8 reg;
 
 	/* Start monitoring */
-	reg = via686a_read_value(client, VIA686A_REG_CONFIG);
-	via686a_write_value(client, VIA686A_REG_CONFIG, (reg|0x01)&0x7F);
+	reg = via686a_read_value(data, VIA686A_REG_CONFIG);
+	via686a_write_value(data, VIA686A_REG_CONFIG, (reg | 0x01) & 0x7F);
 
 	/* Configure temp interrupt mode for continuous-interrupt operation */
-	via686a_write_value(client, VIA686A_REG_TEMP_MODE,
-			    via686a_read_value(client, VIA686A_REG_TEMP_MODE) &
-			    !(VIA686A_TEMP_MODE_MASK | VIA686A_TEMP_MODE_CONTINUOUS));
+	reg = via686a_read_value(data, VIA686A_REG_TEMP_MODE);
+	via686a_write_value(data, VIA686A_REG_TEMP_MODE,
+			    (reg & ~VIA686A_TEMP_MODE_MASK)
+			    | VIA686A_TEMP_MODE_CONTINUOUS);
 }
 
 static struct via686a_data *via686a_update_device(struct device *dev)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct via686a_data *data = i2c_get_clientdata(client);
+	struct via686a_data *data = dev_get_drvdata(dev);
 	int i;
 
 	mutex_lock(&data->update_lock);
@@ -757,27 +684,27 @@
 	    || !data->valid) {
 		for (i = 0; i <= 4; i++) {
 			data->in[i] =
-			    via686a_read_value(client, VIA686A_REG_IN(i));
-			data->in_min[i] = via686a_read_value(client,
+			    via686a_read_value(data, VIA686A_REG_IN(i));
+			data->in_min[i] = via686a_read_value(data,
 							     VIA686A_REG_IN_MIN
 							     (i));
 			data->in_max[i] =
-			    via686a_read_value(client, VIA686A_REG_IN_MAX(i));
+			    via686a_read_value(data, VIA686A_REG_IN_MAX(i));
 		}
 		for (i = 1; i <= 2; i++) {
 			data->fan[i - 1] =
-			    via686a_read_value(client, VIA686A_REG_FAN(i));
-			data->fan_min[i - 1] = via686a_read_value(client,
+			    via686a_read_value(data, VIA686A_REG_FAN(i));
+			data->fan_min[i - 1] = via686a_read_value(data,
 						     VIA686A_REG_FAN_MIN(i));
 		}
 		for (i = 0; i <= 2; i++) {
-			data->temp[i] = via686a_read_value(client,
+			data->temp[i] = via686a_read_value(data,
 						 VIA686A_REG_TEMP[i]) << 2;
 			data->temp_over[i] =
-			    via686a_read_value(client,
+			    via686a_read_value(data,
 					       VIA686A_REG_TEMP_OVER[i]);
 			data->temp_hyst[i] =
-			    via686a_read_value(client,
+			    via686a_read_value(data,
 					       VIA686A_REG_TEMP_HYST[i]);
 		}
 		/* add in lower 2 bits
@@ -785,23 +712,23 @@
 		   temp2 uses bits 5-4 of VIA686A_REG_TEMP_LOW23
 		   temp3 uses bits 7-6 of VIA686A_REG_TEMP_LOW23
 		 */
-		data->temp[0] |= (via686a_read_value(client,
+		data->temp[0] |= (via686a_read_value(data,
 						     VIA686A_REG_TEMP_LOW1)
 				  & 0xc0) >> 6;
 		data->temp[1] |=
-		    (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) &
+		    (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
 		     0x30) >> 4;
 		data->temp[2] |=
-		    (via686a_read_value(client, VIA686A_REG_TEMP_LOW23) &
+		    (via686a_read_value(data, VIA686A_REG_TEMP_LOW23) &
 		     0xc0) >> 6;
 
-		i = via686a_read_value(client, VIA686A_REG_FANDIV);
+		i = via686a_read_value(data, VIA686A_REG_FANDIV);
 		data->fan_div[0] = (i >> 4) & 0x03;
 		data->fan_div[1] = i >> 6;
 		data->alarms =
-		    via686a_read_value(client,
+		    via686a_read_value(data,
 				       VIA686A_REG_ALARM1) |
-		    (via686a_read_value(client, VIA686A_REG_ALARM2) << 8);
+		    (via686a_read_value(data, VIA686A_REG_ALARM2) << 8);
 		data->last_updated = jiffies;
 		data->valid = 1;
 	}
@@ -818,32 +745,102 @@
 
 MODULE_DEVICE_TABLE(pci, via686a_pci_ids);
 
+static int __devinit via686a_device_add(unsigned short address)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + VIA686A_EXTENT - 1,
+		.name	= "via686a",
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	pdev = platform_device_alloc("via686a", address);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR "via686a: Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		printk(KERN_ERR "via686a: Device resource addition failed "
+		       "(%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR "via686a: Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
 static int __devinit via686a_pci_probe(struct pci_dev *dev,
 				       const struct pci_device_id *id)
 {
-	u16 val;
+	u16 address, val;
 
+	if (force_addr) {
+		address = force_addr & ~(VIA686A_EXTENT - 1);
+		dev_warn(&dev->dev, "Forcing ISA address 0x%x\n", address);
+		if (PCIBIOS_SUCCESSFUL !=
+		    pci_write_config_word(dev, VIA686A_BASE_REG, address | 1))
+			return -ENODEV;
+	}
 	if (PCIBIOS_SUCCESSFUL !=
 	    pci_read_config_word(dev, VIA686A_BASE_REG, &val))
 		return -ENODEV;
 
 	address = val & ~(VIA686A_EXTENT - 1);
-	if (address == 0 && force_addr == 0) {
+	if (address == 0) {
 		dev_err(&dev->dev, "base address not set - upgrade BIOS "
 			"or use force_addr=0xaddr\n");
 		return -ENODEV;
 	}
 
-	s_bridge = pci_dev_get(dev);
-	if (i2c_isa_add_driver(&via686a_driver)) {
-		pci_dev_put(s_bridge);
-		s_bridge = NULL;
+	if (PCIBIOS_SUCCESSFUL !=
+	    pci_read_config_word(dev, VIA686A_ENABLE_REG, &val))
+		return -ENODEV;
+	if (!(val & 0x0001)) {
+		if (!force_addr) {
+			dev_warn(&dev->dev, "Sensors disabled, enable "
+				 "with force_addr=0x%x\n", address);
+			return -ENODEV;
+		}
+
+		dev_warn(&dev->dev, "Enabling sensors\n");
+		if (PCIBIOS_SUCCESSFUL !=
+		    pci_write_config_word(dev, VIA686A_ENABLE_REG,
+					  val | 0x0001))
+			return -ENODEV;
 	}
 
+	if (platform_driver_register(&via686a_driver))
+		goto exit;
+
+	/* Sets global pdev as a side effect */
+	if (via686a_device_add(address))
+		goto exit_unregister;
+
 	/* Always return failure here.  This is to allow other drivers to bind
 	 * to this pci device.  We don't really want to have control over the
 	 * pci device, we only wanted to read as few register values from it.
 	 */
+	s_bridge = pci_dev_get(dev);
+	return -ENODEV;
+
+exit_unregister:
+	platform_driver_unregister(&via686a_driver);
+exit:
 	return -ENODEV;
 }
 
@@ -862,7 +859,8 @@
 {
 	pci_unregister_driver(&via686a_pci_driver);
 	if (s_bridge != NULL) {
-		i2c_isa_del_driver(&via686a_driver);
+		platform_device_unregister(pdev);
+		platform_driver_unregister(&via686a_driver);
 		pci_dev_put(s_bridge);
 		s_bridge = NULL;
 	}
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index a6a4aa0..3e63eaf 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -29,8 +29,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/jiffies.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/platform_device.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/hwmon-vid.h>
@@ -42,10 +41,7 @@
 module_param(force_addr, int, 0);
 MODULE_PARM_DESC(force_addr, "Initialize the base address of the sensors");
 
-/* Device address
-   Note that we can't determine the ISA address until we have initialized
-   our module */
-static unsigned short isa_address;
+static struct platform_device *pdev;
 
 #define VT8231_EXTENT 0x80
 #define VT8231_BASE_REG 0x70
@@ -148,7 +144,9 @@
 #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : 1310720 / ((val) * (div)))
 
 struct vt8231_data {
-	struct i2c_client client;
+	unsigned short addr;
+	const char *name;
+
 	struct mutex update_lock;
 	struct class_device *class_dev;
 	char valid;		/* !=0 if following fields are valid */
@@ -168,20 +166,20 @@
 };
 
 static struct pci_dev *s_bridge;
-static int vt8231_detect(struct i2c_adapter *adapter);
-static int vt8231_detach_client(struct i2c_client *client);
+static int vt8231_probe(struct platform_device *pdev);
+static int __devexit vt8231_remove(struct platform_device *pdev);
 static struct vt8231_data *vt8231_update_device(struct device *dev);
-static void vt8231_init_client(struct i2c_client *client);
+static void vt8231_init_device(struct vt8231_data *data);
 
-static inline int vt8231_read_value(struct i2c_client *client, u8 reg)
+static inline int vt8231_read_value(struct vt8231_data *data, u8 reg)
 {
-	return inb_p(client->addr + reg);
+	return inb_p(data->addr + reg);
 }
 
-static inline void vt8231_write_value(struct i2c_client *client, u8 reg,
+static inline void vt8231_write_value(struct vt8231_data *data, u8 reg,
 					u8 value)
 {
-	outb_p(value, client->addr + reg);
+	outb_p(value, data->addr + reg);
 }
 
 /* following are the sysfs callback functions */
@@ -220,13 +218,12 @@
 {
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	struct i2c_client *client = to_i2c_client(dev);
-	struct vt8231_data *data = i2c_get_clientdata(client);
+	struct vt8231_data *data = dev_get_drvdata(dev);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->in_min[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255);
-	vt8231_write_value(client, regvoltmin[nr], data->in_min[nr]);
+	vt8231_write_value(data, regvoltmin[nr], data->in_min[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -236,13 +233,12 @@
 {
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	struct i2c_client *client = to_i2c_client(dev);
-	struct vt8231_data *data = i2c_get_clientdata(client);
+	struct vt8231_data *data = dev_get_drvdata(dev);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->in_max[nr] = SENSORS_LIMIT(((val * 958) / 10000) + 3, 0, 255);
-	vt8231_write_value(client, regvoltmax[nr], data->in_max[nr]);
+	vt8231_write_value(data, regvoltmax[nr], data->in_max[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -278,14 +274,13 @@
 static ssize_t set_in5_min(struct device *dev, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct vt8231_data *data = i2c_get_clientdata(client);
+	struct vt8231_data *data = dev_get_drvdata(dev);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->in_min[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3,
 					0, 255);
-	vt8231_write_value(client, regvoltmin[5], data->in_min[5]);
+	vt8231_write_value(data, regvoltmin[5], data->in_min[5]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -293,14 +288,13 @@
 static ssize_t set_in5_max(struct device *dev, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct vt8231_data *data = i2c_get_clientdata(client);
+	struct vt8231_data *data = dev_get_drvdata(dev);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->in_max[5] = SENSORS_LIMIT(((val * 958 * 34) / (10000 * 54)) + 3,
 					0, 255);
-	vt8231_write_value(client, regvoltmax[5], data->in_max[5]);
+	vt8231_write_value(data, regvoltmax[5], data->in_max[5]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -348,26 +342,24 @@
 static ssize_t set_temp0_max(struct device *dev, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct vt8231_data *data = i2c_get_clientdata(client);
+	struct vt8231_data *data = dev_get_drvdata(dev);
 	int val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->temp_max[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255);
-	vt8231_write_value(client, regtempmax[0], data->temp_max[0]);
+	vt8231_write_value(data, regtempmax[0], data->temp_max[0]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
 static ssize_t set_temp0_min(struct device *dev, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct vt8231_data *data = i2c_get_clientdata(client);
+	struct vt8231_data *data = dev_get_drvdata(dev);
 	int val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->temp_min[0] = SENSORS_LIMIT((val + 500) / 1000, 0, 255);
-	vt8231_write_value(client, regtempmin[0], data->temp_min[0]);
+	vt8231_write_value(data, regtempmin[0], data->temp_min[0]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -404,13 +396,12 @@
 {
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	struct i2c_client *client = to_i2c_client(dev);
-	struct vt8231_data *data = i2c_get_clientdata(client);
+	struct vt8231_data *data = dev_get_drvdata(dev);
 	int val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->temp_max[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255);
-	vt8231_write_value(client, regtempmax[nr], data->temp_max[nr]);
+	vt8231_write_value(data, regtempmax[nr], data->temp_max[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -419,13 +410,12 @@
 {
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	struct i2c_client *client = to_i2c_client(dev);
-	struct vt8231_data *data = i2c_get_clientdata(client);
+	struct vt8231_data *data = dev_get_drvdata(dev);
 	int val = simple_strtol(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->temp_min[nr] = SENSORS_LIMIT(TEMP_MAXMIN_TO_REG(val), 0, 255);
-	vt8231_write_value(client, regtempmin[nr], data->temp_min[nr]);
+	vt8231_write_value(data, regtempmin[nr], data->temp_min[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -486,13 +476,12 @@
 {
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
-	struct i2c_client *client = to_i2c_client(dev);
-	struct vt8231_data *data = i2c_get_clientdata(client);
+	struct vt8231_data *data = dev_get_drvdata(dev);
 	int val = simple_strtoul(buf, NULL, 10);
 
 	mutex_lock(&data->update_lock);
 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
-	vt8231_write_value(client, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
+	vt8231_write_value(data, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -500,12 +489,11 @@
 static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct vt8231_data *data = i2c_get_clientdata(client);
+	struct vt8231_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	unsigned long val = simple_strtoul(buf, NULL, 10);
 	int nr = sensor_attr->index;
-	int old = vt8231_read_value(client, VT8231_REG_FANDIV);
+	int old = vt8231_read_value(data, VT8231_REG_FANDIV);
 	long min = FAN_FROM_REG(data->fan_min[nr],
 				 DIV_FROM_REG(data->fan_div[nr]));
 
@@ -516,7 +504,7 @@
 	case 4: data->fan_div[nr] = 2; break;
 	case 8: data->fan_div[nr] = 3; break;
 	default:
-		dev_err(&client->dev, "fan_div value %ld not supported."
+		dev_err(dev, "fan_div value %ld not supported."
 		        "Choose one of 1, 2, 4 or 8!\n", val);
 		mutex_unlock(&data->update_lock);
 		return -EINVAL;
@@ -524,10 +512,10 @@
 
 	/* Correct the fan minimum speed */
 	data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
-	vt8231_write_value(client, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
+	vt8231_write_value(data, VT8231_REG_FAN_MIN(nr), data->fan_min[nr]);
 
 	old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
-	vt8231_write_value(client, VT8231_REG_FANDIV, old);
+	vt8231_write_value(data, VT8231_REG_FANDIV, old);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -551,9 +539,16 @@
 	struct vt8231_data *data = vt8231_update_device(dev);
 	return sprintf(buf, "%d\n", data->alarms);
 }
-
 static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
 
+static ssize_t show_name(struct device *dev, struct device_attribute
+			 *devattr, char *buf)
+{
+	struct vt8231_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
 static struct attribute *vt8231_attributes_temps[6][4] = {
 	{
 		&dev_attr_temp1_input.attr,
@@ -648,6 +643,7 @@
 	&sensor_dev_attr_fan1_div.dev_attr.attr,
 	&sensor_dev_attr_fan2_div.dev_attr.attr,
 	&dev_attr_alarms.attr,
+	&dev_attr_name.attr,
 	NULL
 };
 
@@ -655,13 +651,13 @@
 	.attrs = vt8231_attributes,
 };
 
-static struct i2c_driver vt8231_driver = {
+static struct platform_driver vt8231_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
 		.name	= "vt8231",
 	},
-	.attach_adapter	= vt8231_detect,
-	.detach_client	= vt8231_detach_client,
+	.probe	= vt8231_probe,
+	.remove	= __devexit_p(vt8231_remove),
 };
 
 static struct pci_device_id vt8231_pci_ids[] = {
@@ -680,40 +676,18 @@
 	.probe		= vt8231_pci_probe,
 };
 
-int vt8231_detect(struct i2c_adapter *adapter)
+int vt8231_probe(struct platform_device *pdev)
 {
-	struct i2c_client *client;
+	struct resource *res;
 	struct vt8231_data *data;
 	int err = 0, i;
-	u16 val;
-
-	/* 8231 requires multiple of 256 */
-	if (force_addr)	{
-		isa_address = force_addr & 0xFF00;
-		dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n",
-				 isa_address);
-		if (PCIBIOS_SUCCESSFUL != pci_write_config_word(s_bridge,
-						VT8231_BASE_REG, isa_address))
-			return -ENODEV;
-	}
-
-	if (PCIBIOS_SUCCESSFUL !=
-		pci_read_config_word(s_bridge, VT8231_ENABLE_REG, &val))
-		return -ENODEV;
-
-	if (!(val & 0x0001)) {
-		dev_warn(&adapter->dev, "enabling sensors\n");
-		if (PCIBIOS_SUCCESSFUL !=
-			pci_write_config_word(s_bridge, VT8231_ENABLE_REG,
-							  val | 0x0001))
-			return -ENODEV;
-	}
 
 	/* Reserve the ISA region */
-	if (!request_region(isa_address, VT8231_EXTENT,
-			    vt8231_pci_driver.name)) {
-		dev_err(&adapter->dev, "region 0x%x already in use!\n",
-			   isa_address);
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!request_region(res->start, VT8231_EXTENT,
+			    vt8231_driver.driver.name)) {
+		dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
+			(unsigned long)res->start, (unsigned long)res->end);
 		return -ENODEV;
 	}
 
@@ -722,33 +696,23 @@
 		goto exit_release;
 	}
 
-	client = &data->client;
-	i2c_set_clientdata(client, data);
-	client->addr = isa_address;
-	client->adapter = adapter;
-	client->driver = &vt8231_driver;
-
-	/* Fill in the remaining client fields and put into the global list */
-	strlcpy(client->name, "vt8231", I2C_NAME_SIZE);
+	platform_set_drvdata(pdev, data);
+	data->addr = res->start;
+	data->name = "vt8231";
 
 	mutex_init(&data->update_lock);
-
-	/* Tell the I2C layer a new client has arrived */
-	if ((err = i2c_attach_client(client)))
-		goto exit_free;
-
-	vt8231_init_client(client);
+	vt8231_init_device(data);
 
 	/* Register sysfs hooks */
-	if ((err = sysfs_create_group(&client->dev.kobj, &vt8231_group)))
-		goto exit_detach;
+	if ((err = sysfs_create_group(&pdev->dev.kobj, &vt8231_group)))
+		goto exit_free;
 
 	/* Must update device information to find out the config field */
-	data->uch_config = vt8231_read_value(client, VT8231_REG_UCH_CONFIG);
+	data->uch_config = vt8231_read_value(data, VT8231_REG_UCH_CONFIG);
 
 	for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++) {
 		if (ISTEMP(i, data->uch_config)) {
-			if ((err = sysfs_create_group(&client->dev.kobj,
+			if ((err = sysfs_create_group(&pdev->dev.kobj,
 					&vt8231_group_temps[i])))
 				goto exit_remove_files;
 		}
@@ -756,13 +720,13 @@
 
 	for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++) {
 		if (ISVOLT(i, data->uch_config)) {
-			if ((err = sysfs_create_group(&client->dev.kobj,
+			if ((err = sysfs_create_group(&pdev->dev.kobj,
 					&vt8231_group_volts[i])))
 				goto exit_remove_files;
 		}
 	}
 
-	data->class_dev = hwmon_device_register(&client->dev);
+	data->class_dev = hwmon_device_register(&pdev->dev);
 	if (IS_ERR(data->class_dev)) {
 		err = PTR_ERR(data->class_dev);
 		goto exit_remove_files;
@@ -771,56 +735,52 @@
 
 exit_remove_files:
 	for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
-		sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
+		sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]);
 
 	for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
-		sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
+		sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]);
 
-	sysfs_remove_group(&client->dev.kobj, &vt8231_group);
-exit_detach:
-	i2c_detach_client(client);
+	sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
+
 exit_free:
+	platform_set_drvdata(pdev, NULL);
 	kfree(data);
+
 exit_release:
-	release_region(isa_address, VT8231_EXTENT);
+	release_region(res->start, VT8231_EXTENT);
 	return err;
 }
 
-static int vt8231_detach_client(struct i2c_client *client)
+static int __devexit vt8231_remove(struct platform_device *pdev)
 {
-	struct vt8231_data *data = i2c_get_clientdata(client);
-	int err, i;
+	struct vt8231_data *data = platform_get_drvdata(pdev);
+	int i;
 
 	hwmon_device_unregister(data->class_dev);
 
 	for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
-		sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
+		sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_volts[i]);
 
 	for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
-		sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
+		sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]);
 
-	sysfs_remove_group(&client->dev.kobj, &vt8231_group);
+	sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
 
-	if ((err = i2c_detach_client(client))) {
-		return err;
-	}
-
-	release_region(client->addr, VT8231_EXTENT);
+	release_region(data->addr, VT8231_EXTENT);
+	platform_set_drvdata(pdev, NULL);
 	kfree(data);
-
 	return 0;
 }
 
-static void vt8231_init_client(struct i2c_client *client)
+static void vt8231_init_device(struct vt8231_data *data)
 {
-	vt8231_write_value(client, VT8231_REG_TEMP1_CONFIG, 0);
-	vt8231_write_value(client, VT8231_REG_TEMP2_CONFIG, 0);
+	vt8231_write_value(data, VT8231_REG_TEMP1_CONFIG, 0);
+	vt8231_write_value(data, VT8231_REG_TEMP2_CONFIG, 0);
 }
 
 static struct vt8231_data *vt8231_update_device(struct device *dev)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct vt8231_data *data = i2c_get_clientdata(client);
+	struct vt8231_data *data = dev_get_drvdata(dev);
 	int i;
 	u16 low;
 
@@ -830,41 +790,41 @@
 	    || !data->valid) {
 		for (i = 0; i < 6; i++) {
 			if (ISVOLT(i, data->uch_config)) {
-				data->in[i] = vt8231_read_value(client,
+				data->in[i] = vt8231_read_value(data,
 						regvolt[i]);
-				data->in_min[i] = vt8231_read_value(client,
+				data->in_min[i] = vt8231_read_value(data,
 						regvoltmin[i]);
-				data->in_max[i] = vt8231_read_value(client,
+				data->in_max[i] = vt8231_read_value(data,
 						regvoltmax[i]);
 			}
 		}
 		for (i = 0; i < 2; i++) {
-			data->fan[i] = vt8231_read_value(client,
+			data->fan[i] = vt8231_read_value(data,
 						VT8231_REG_FAN(i));
-			data->fan_min[i] = vt8231_read_value(client,
+			data->fan_min[i] = vt8231_read_value(data,
 						VT8231_REG_FAN_MIN(i));
 		}
 
-		low = vt8231_read_value(client, VT8231_REG_TEMP_LOW01);
+		low = vt8231_read_value(data, VT8231_REG_TEMP_LOW01);
 		low = (low >> 6) | ((low & 0x30) >> 2)
-		    | (vt8231_read_value(client, VT8231_REG_TEMP_LOW25) << 4);
+		    | (vt8231_read_value(data, VT8231_REG_TEMP_LOW25) << 4);
 		for (i = 0; i < 6; i++) {
 			if (ISTEMP(i, data->uch_config)) {
-				data->temp[i] = (vt8231_read_value(client,
+				data->temp[i] = (vt8231_read_value(data,
 						       regtemp[i]) << 2)
 						| ((low >> (2 * i)) & 0x03);
-				data->temp_max[i] = vt8231_read_value(client,
+				data->temp_max[i] = vt8231_read_value(data,
 						      regtempmax[i]);
-				data->temp_min[i] = vt8231_read_value(client,
+				data->temp_min[i] = vt8231_read_value(data,
 						      regtempmin[i]);
 			}
 		}
 
-		i = vt8231_read_value(client, VT8231_REG_FANDIV);
+		i = vt8231_read_value(data, VT8231_REG_FANDIV);
 		data->fan_div[0] = (i >> 4) & 0x03;
 		data->fan_div[1] = i >> 6;
-		data->alarms = vt8231_read_value(client, VT8231_REG_ALARM1) |
-			(vt8231_read_value(client, VT8231_REG_ALARM2) << 8);
+		data->alarms = vt8231_read_value(data, VT8231_REG_ALARM1) |
+			(vt8231_read_value(data, VT8231_REG_ALARM2) << 8);
 
 		/* Set alarm flags correctly */
 		if (!data->fan[0] && data->fan_min[0]) {
@@ -888,33 +848,102 @@
 	return data;
 }
 
+static int __devinit vt8231_device_add(unsigned short address)
+{
+	struct resource res = {
+		.start	= address,
+		.end	= address + VT8231_EXTENT - 1,
+		.name	= "vt8231",
+		.flags	= IORESOURCE_IO,
+	};
+	int err;
+
+	pdev = platform_device_alloc("vt8231", address);
+	if (!pdev) {
+		err = -ENOMEM;
+		printk(KERN_ERR "vt8231: Device allocation failed\n");
+		goto exit;
+	}
+
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		printk(KERN_ERR "vt8231: Device resource addition failed "
+		       "(%d)\n", err);
+		goto exit_device_put;
+	}
+
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR "vt8231: Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit:
+	return err;
+}
+
 static int __devinit vt8231_pci_probe(struct pci_dev *dev,
 				const struct pci_device_id *id)
 {
-	u16 val;
+	u16 address, val;
+	if (force_addr) {
+		address = force_addr & 0xff00;
+		dev_warn(&dev->dev, "Forcing ISA address 0x%x\n",
+			 address);
+
+		if (PCIBIOS_SUCCESSFUL !=
+		    pci_write_config_word(dev, VT8231_BASE_REG, address | 1))
+			return -ENODEV;
+	}
 
 	if (PCIBIOS_SUCCESSFUL != pci_read_config_word(dev, VT8231_BASE_REG,
 							&val))
 		return -ENODEV;
 
-	isa_address = val & ~(VT8231_EXTENT - 1);
-	if (isa_address == 0 && force_addr == 0) {
+	address = val & ~(VT8231_EXTENT - 1);
+	if (address == 0) {
 		dev_err(&dev->dev, "base address not set -\
 				 upgrade BIOS or use force_addr=0xaddr\n");
 		return -ENODEV;
 	}
 
-	s_bridge = pci_dev_get(dev);
+	if (PCIBIOS_SUCCESSFUL != pci_read_config_word(dev, VT8231_ENABLE_REG,
+							&val))
+		return -ENODEV;
 
-	if (i2c_isa_add_driver(&vt8231_driver)) {
-		pci_dev_put(s_bridge);
-		s_bridge = NULL;
+	if (!(val & 0x0001)) {
+		dev_warn(&dev->dev, "enabling sensors\n");
+		if (PCIBIOS_SUCCESSFUL !=
+			pci_write_config_word(dev, VT8231_ENABLE_REG,
+							val | 0x0001))
+			return -ENODEV;
 	}
 
+	if (platform_driver_register(&vt8231_driver))
+		goto exit;
+
+	/* Sets global pdev as a side effect */
+	if (vt8231_device_add(address))
+		goto exit_unregister;
+
 	/* Always return failure here.  This is to allow other drivers to bind
 	 * to this pci device.  We don't really want to have control over the
 	 * pci device, we only wanted to read as few register values from it.
 	 */
+
+	/* We do, however, mark ourselves as using the PCI device to stop it
+	   getting unloaded. */
+	s_bridge = pci_dev_get(dev);
+	return -ENODEV;
+
+exit_unregister:
+	platform_driver_unregister(&vt8231_driver);
+exit:
 	return -ENODEV;
 }
 
@@ -927,7 +956,8 @@
 {
 	pci_unregister_driver(&vt8231_pci_driver);
 	if (s_bridge != NULL) {
-		i2c_isa_del_driver(&vt8231_driver);
+		platform_device_unregister(pdev);
+		platform_driver_unregister(&vt8231_driver);
 		pci_dev_put(s_bridge);
 		s_bridge = NULL;
 	}
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 30a7640..d9a9ec7 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -41,41 +41,39 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <asm/io.h>
 #include "lm75.h"
 
-/* The actual ISA address is read from Super-I/O configuration space */
-static unsigned short address;
+enum kinds { w83627ehf, w83627dhg };
+
+/* used to set data->name = w83627ehf_device_names[data->sio_kind] */
+static const char * w83627ehf_device_names[] = {
+	"w83627ehf",
+	"w83627dhg",
+};
+
+#define DRVNAME "w83627ehf"
 
 /*
  * Super-I/O constants and functions
  */
 
-/*
- * The three following globals are initialized in w83627ehf_find(), before
- * the i2c-isa device is created. Otherwise, they could be stored in
- * w83627ehf_data. This is ugly, but necessary, and when the driver is next
- * updated to become a platform driver, the globals will disappear.
- */
-static int REG;		/* The register to read/write */
-static int VAL;		/* The value to read/write */
-/* The w83627ehf/ehg have 10 voltage inputs, but the w83627dhg has 9. This
- * value is also used in w83627ehf_detect() to export a device name in sysfs
- * (e.g. w83627ehf or w83627dhg) */
-static int w83627ehf_num_in;
-
 #define W83627EHF_LD_HWM	0x0b
 
 #define SIO_REG_LDSEL		0x07	/* Logical device select */
 #define SIO_REG_DEVID		0x20	/* Device ID (2 bytes) */
+#define SIO_REG_EN_VRM10	0x2C	/* GPIO3, GPIO4 selection */
 #define SIO_REG_ENABLE		0x30	/* Logical device enable */
 #define SIO_REG_ADDR		0x60	/* Logical device address (2 bytes) */
+#define SIO_REG_VID_CTRL	0xF0	/* VID control */
+#define SIO_REG_VID_DATA	0xF1	/* VID data */
 
 #define SIO_W83627EHF_ID	0x8850
 #define SIO_W83627EHG_ID	0x8860
@@ -83,38 +81,38 @@
 #define SIO_ID_MASK		0xFFF0
 
 static inline void
-superio_outb(int reg, int val)
+superio_outb(int ioreg, int reg, int val)
 {
-	outb(reg, REG);
-	outb(val, VAL);
+	outb(reg, ioreg);
+	outb(val, ioreg + 1);
 }
 
 static inline int
-superio_inb(int reg)
+superio_inb(int ioreg, int reg)
 {
-	outb(reg, REG);
-	return inb(VAL);
+	outb(reg, ioreg);
+	return inb(ioreg + 1);
 }
 
 static inline void
-superio_select(int ld)
+superio_select(int ioreg, int ld)
 {
-	outb(SIO_REG_LDSEL, REG);
-	outb(ld, VAL);
+	outb(SIO_REG_LDSEL, ioreg);
+	outb(ld, ioreg + 1);
 }
 
 static inline void
-superio_enter(void)
+superio_enter(int ioreg)
 {
-	outb(0x87, REG);
-	outb(0x87, REG);
+	outb(0x87, ioreg);
+	outb(0x87, ioreg);
 }
 
 static inline void
-superio_exit(void)
+superio_exit(int ioreg)
 {
-	outb(0x02, REG);
-	outb(0x02, VAL);
+	outb(0x02, ioreg);
+	outb(0x02, ioreg + 1);
 }
 
 /*
@@ -124,8 +122,8 @@
 #define IOREGION_ALIGNMENT	~7
 #define IOREGION_OFFSET		5
 #define IOREGION_LENGTH		2
-#define ADDR_REG_OFFSET		5
-#define DATA_REG_OFFSET		6
+#define ADDR_REG_OFFSET		0
+#define DATA_REG_OFFSET		1
 
 #define W83627EHF_REG_BANK		0x4E
 #define W83627EHF_REG_CONFIG		0x40
@@ -255,7 +253,9 @@
  */
 
 struct w83627ehf_data {
-	struct i2c_client client;
+	int addr;	/* IO base of hw monitor block */
+	const char *name;
+
 	struct class_device *class_dev;
 	struct mutex lock;
 
@@ -264,6 +264,7 @@
 	unsigned long last_updated;	/* In jiffies */
 
 	/* Register values */
+	u8 in_num;		/* number of in inputs we have */
 	u8 in[10];		/* Register value */
 	u8 in_max[10];		/* Register value */
 	u8 in_min[10];		/* Register value */
@@ -271,6 +272,7 @@
 	u8 fan_min[5];
 	u8 fan_div[5];
 	u8 has_fan;		/* some fan inputs can be disabled */
+	u8 temp_type[3];
 	s8 temp1;
 	s8 temp1_max;
 	s8 temp1_max_hyst;
@@ -288,6 +290,14 @@
 
 	u8 fan_min_output[4]; /* minimum fan speed */
 	u8 fan_stop_time[4];
+
+	u8 vid;
+	u8 vrm;
+};
+
+struct w83627ehf_sio_data {
+	int sioreg;
+	enum kinds kind;
 };
 
 static inline int is_word_sized(u16 reg)
@@ -299,160 +309,161 @@
 	      || (reg & 0x00ff) == 0x55));
 }
 
-/* We assume that the default bank is 0, thus the following two functions do
-   nothing for registers which live in bank 0. For others, they respectively
-   set the bank register to the correct value (before the register is
-   accessed), and back to 0 (afterwards). */
-static inline void w83627ehf_set_bank(struct i2c_client *client, u16 reg)
+/* Registers 0x50-0x5f are banked */
+static inline void w83627ehf_set_bank(struct w83627ehf_data *data, u16 reg)
 {
-	if (reg & 0xff00) {
-		outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
-		outb_p(reg >> 8, client->addr + DATA_REG_OFFSET);
+	if ((reg & 0x00f0) == 0x50) {
+		outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
+		outb_p(reg >> 8, data->addr + DATA_REG_OFFSET);
 	}
 }
 
-static inline void w83627ehf_reset_bank(struct i2c_client *client, u16 reg)
+/* Not strictly necessary, but play it safe for now */
+static inline void w83627ehf_reset_bank(struct w83627ehf_data *data, u16 reg)
 {
 	if (reg & 0xff00) {
-		outb_p(W83627EHF_REG_BANK, client->addr + ADDR_REG_OFFSET);
-		outb_p(0, client->addr + DATA_REG_OFFSET);
+		outb_p(W83627EHF_REG_BANK, data->addr + ADDR_REG_OFFSET);
+		outb_p(0, data->addr + DATA_REG_OFFSET);
 	}
 }
 
-static u16 w83627ehf_read_value(struct i2c_client *client, u16 reg)
+static u16 w83627ehf_read_value(struct w83627ehf_data *data, u16 reg)
 {
-	struct w83627ehf_data *data = i2c_get_clientdata(client);
 	int res, word_sized = is_word_sized(reg);
 
 	mutex_lock(&data->lock);
 
-	w83627ehf_set_bank(client, reg);
-	outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
-	res = inb_p(client->addr + DATA_REG_OFFSET);
+	w83627ehf_set_bank(data, reg);
+	outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
+	res = inb_p(data->addr + DATA_REG_OFFSET);
 	if (word_sized) {
 		outb_p((reg & 0xff) + 1,
-		       client->addr + ADDR_REG_OFFSET);
-		res = (res << 8) + inb_p(client->addr + DATA_REG_OFFSET);
+		       data->addr + ADDR_REG_OFFSET);
+		res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET);
 	}
-	w83627ehf_reset_bank(client, reg);
+	w83627ehf_reset_bank(data, reg);
 
 	mutex_unlock(&data->lock);
 
 	return res;
 }
 
-static int w83627ehf_write_value(struct i2c_client *client, u16 reg, u16 value)
+static int w83627ehf_write_value(struct w83627ehf_data *data, u16 reg, u16 value)
 {
-	struct w83627ehf_data *data = i2c_get_clientdata(client);
 	int word_sized = is_word_sized(reg);
 
 	mutex_lock(&data->lock);
 
-	w83627ehf_set_bank(client, reg);
-	outb_p(reg & 0xff, client->addr + ADDR_REG_OFFSET);
+	w83627ehf_set_bank(data, reg);
+	outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET);
 	if (word_sized) {
-		outb_p(value >> 8, client->addr + DATA_REG_OFFSET);
+		outb_p(value >> 8, data->addr + DATA_REG_OFFSET);
 		outb_p((reg & 0xff) + 1,
-		       client->addr + ADDR_REG_OFFSET);
+		       data->addr + ADDR_REG_OFFSET);
 	}
-	outb_p(value & 0xff, client->addr + DATA_REG_OFFSET);
-	w83627ehf_reset_bank(client, reg);
+	outb_p(value & 0xff, data->addr + DATA_REG_OFFSET);
+	w83627ehf_reset_bank(data, reg);
 
 	mutex_unlock(&data->lock);
 	return 0;
 }
 
 /* This function assumes that the caller holds data->update_lock */
-static void w83627ehf_write_fan_div(struct i2c_client *client, int nr)
+static void w83627ehf_write_fan_div(struct w83627ehf_data *data, int nr)
 {
-	struct w83627ehf_data *data = i2c_get_clientdata(client);
 	u8 reg;
 
 	switch (nr) {
 	case 0:
-		reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf)
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0xcf)
 		    | ((data->fan_div[0] & 0x03) << 4);
 		/* fan5 input control bit is write only, compute the value */
 		reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
-		w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
-		reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf)
+		w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xdf)
 		    | ((data->fan_div[0] & 0x04) << 3);
-		w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
+		w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
 		break;
 	case 1:
-		reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f)
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV1) & 0x3f)
 		    | ((data->fan_div[1] & 0x03) << 6);
 		/* fan5 input control bit is write only, compute the value */
 		reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
-		w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
-		reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf)
+		w83627ehf_write_value(data, W83627EHF_REG_FANDIV1, reg);
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0xbf)
 		    | ((data->fan_div[1] & 0x04) << 4);
-		w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
+		w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
 		break;
 	case 2:
-		reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV2) & 0x3f)
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_FANDIV2) & 0x3f)
 		    | ((data->fan_div[2] & 0x03) << 6);
-		w83627ehf_write_value(client, W83627EHF_REG_FANDIV2, reg);
-		reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0x7f)
+		w83627ehf_write_value(data, W83627EHF_REG_FANDIV2, reg);
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_VBAT) & 0x7f)
 		    | ((data->fan_div[2] & 0x04) << 5);
-		w83627ehf_write_value(client, W83627EHF_REG_VBAT, reg);
+		w83627ehf_write_value(data, W83627EHF_REG_VBAT, reg);
 		break;
 	case 3:
-		reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0xfc)
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0xfc)
 		    | (data->fan_div[3] & 0x03);
-		w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
-		reg = (w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT) & 0x7f)
+		w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT) & 0x7f)
 		    | ((data->fan_div[3] & 0x04) << 5);
-		w83627ehf_write_value(client, W83627EHF_REG_SMI_OVT, reg);
+		w83627ehf_write_value(data, W83627EHF_REG_SMI_OVT, reg);
 		break;
 	case 4:
-		reg = (w83627ehf_read_value(client, W83627EHF_REG_DIODE) & 0x73)
+		reg = (w83627ehf_read_value(data, W83627EHF_REG_DIODE) & 0x73)
 		    | ((data->fan_div[4] & 0x03) << 2)
 		    | ((data->fan_div[4] & 0x04) << 5);
-		w83627ehf_write_value(client, W83627EHF_REG_DIODE, reg);
+		w83627ehf_write_value(data, W83627EHF_REG_DIODE, reg);
 		break;
 	}
 }
 
+static void w83627ehf_update_fan_div(struct w83627ehf_data *data)
+{
+	int i;
+
+	i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
+	data->fan_div[0] = (i >> 4) & 0x03;
+	data->fan_div[1] = (i >> 6) & 0x03;
+	i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV2);
+	data->fan_div[2] = (i >> 6) & 0x03;
+	i = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
+	data->fan_div[0] |= (i >> 3) & 0x04;
+	data->fan_div[1] |= (i >> 4) & 0x04;
+	data->fan_div[2] |= (i >> 5) & 0x04;
+	if (data->has_fan & ((1 << 3) | (1 << 4))) {
+		i = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
+		data->fan_div[3] = i & 0x03;
+		data->fan_div[4] = ((i >> 2) & 0x03)
+				 | ((i >> 5) & 0x04);
+	}
+	if (data->has_fan & (1 << 3)) {
+		i = w83627ehf_read_value(data, W83627EHF_REG_SMI_OVT);
+		data->fan_div[3] |= (i >> 5) & 0x04;
+	}
+}
+
 static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83627ehf_data *data = i2c_get_clientdata(client);
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
 	int i;
 
 	mutex_lock(&data->update_lock);
 
-	if (time_after(jiffies, data->last_updated + HZ)
+	if (time_after(jiffies, data->last_updated + HZ + HZ/2)
 	 || !data->valid) {
 		/* Fan clock dividers */
-		i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
-		data->fan_div[0] = (i >> 4) & 0x03;
-		data->fan_div[1] = (i >> 6) & 0x03;
-		i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV2);
-		data->fan_div[2] = (i >> 6) & 0x03;
-		i = w83627ehf_read_value(client, W83627EHF_REG_VBAT);
-		data->fan_div[0] |= (i >> 3) & 0x04;
-		data->fan_div[1] |= (i >> 4) & 0x04;
-		data->fan_div[2] |= (i >> 5) & 0x04;
-		if (data->has_fan & ((1 << 3) | (1 << 4))) {
-			i = w83627ehf_read_value(client, W83627EHF_REG_DIODE);
-			data->fan_div[3] = i & 0x03;
-			data->fan_div[4] = ((i >> 2) & 0x03)
-					 | ((i >> 5) & 0x04);
-		}
-		if (data->has_fan & (1 << 3)) {
-			i = w83627ehf_read_value(client, W83627EHF_REG_SMI_OVT);
-			data->fan_div[3] |= (i >> 5) & 0x04;
-		}
+		w83627ehf_update_fan_div(data);
 
 		/* Measured voltages and limits */
-		for (i = 0; i < w83627ehf_num_in; i++) {
-			data->in[i] = w83627ehf_read_value(client,
+		for (i = 0; i < data->in_num; i++) {
+			data->in[i] = w83627ehf_read_value(data,
 				      W83627EHF_REG_IN(i));
-			data->in_min[i] = w83627ehf_read_value(client,
+			data->in_min[i] = w83627ehf_read_value(data,
 					  W83627EHF_REG_IN_MIN(i));
-			data->in_max[i] = w83627ehf_read_value(client,
+			data->in_max[i] = w83627ehf_read_value(data,
 					  W83627EHF_REG_IN_MAX(i));
 		}
 
@@ -461,9 +472,9 @@
 			if (!(data->has_fan & (1 << i)))
 				continue;
 
-			data->fan[i] = w83627ehf_read_value(client,
+			data->fan[i] = w83627ehf_read_value(data,
 				       W83627EHF_REG_FAN[i]);
-			data->fan_min[i] = w83627ehf_read_value(client,
+			data->fan_min[i] = w83627ehf_read_value(data,
 					   W83627EHF_REG_FAN_MIN[i]);
 
 			/* If we failed to measure the fan speed and clock
@@ -471,16 +482,16 @@
 			   time */
 			if (data->fan[i] == 0xff
 			 && data->fan_div[i] < 0x07) {
-			 	dev_dbg(&client->dev, "Increasing fan%d "
+			 	dev_dbg(dev, "Increasing fan%d "
 					"clock divider from %u to %u\n",
 					i + 1, div_from_reg(data->fan_div[i]),
 					div_from_reg(data->fan_div[i] + 1));
 				data->fan_div[i]++;
-				w83627ehf_write_fan_div(client, i);
+				w83627ehf_write_fan_div(data, i);
 				/* Preserve min limit if possible */
 				if (data->fan_min[i] >= 2
 				 && data->fan_min[i] != 255)
-					w83627ehf_write_value(client,
+					w83627ehf_write_value(data,
 						W83627EHF_REG_FAN_MIN[i],
 						(data->fan_min[i] /= 2));
 			}
@@ -489,9 +500,9 @@
 		for (i = 0; i < 4; i++) {
 			/* pwmcfg, tolarance mapped for i=0, i=1 to same reg */
 			if (i != 1) {
-				pwmcfg = w83627ehf_read_value(client,
+				pwmcfg = w83627ehf_read_value(data,
 						W83627EHF_REG_PWM_ENABLE[i]);
-				tolerance = w83627ehf_read_value(client,
+				tolerance = w83627ehf_read_value(data,
 						W83627EHF_REG_TOLERANCE[i]);
 			}
 			data->pwm_mode[i] =
@@ -500,14 +511,14 @@
 			data->pwm_enable[i] =
 					((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
 						& 3) + 1;
-			data->pwm[i] = w83627ehf_read_value(client,
+			data->pwm[i] = w83627ehf_read_value(data,
 						W83627EHF_REG_PWM[i]);
-			data->fan_min_output[i] = w83627ehf_read_value(client,
+			data->fan_min_output[i] = w83627ehf_read_value(data,
 						W83627EHF_REG_FAN_MIN_OUTPUT[i]);
-			data->fan_stop_time[i] = w83627ehf_read_value(client,
+			data->fan_stop_time[i] = w83627ehf_read_value(data,
 						W83627EHF_REG_FAN_STOP_TIME[i]);
 			data->target_temp[i] =
-				w83627ehf_read_value(client,
+				w83627ehf_read_value(data,
 					W83627EHF_REG_TARGET[i]) &
 					(data->pwm_mode[i] == 1 ? 0x7f : 0xff);
 			data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
@@ -515,26 +526,26 @@
 		}
 
 		/* Measured temperatures and limits */
-		data->temp1 = w83627ehf_read_value(client,
+		data->temp1 = w83627ehf_read_value(data,
 			      W83627EHF_REG_TEMP1);
-		data->temp1_max = w83627ehf_read_value(client,
+		data->temp1_max = w83627ehf_read_value(data,
 				  W83627EHF_REG_TEMP1_OVER);
-		data->temp1_max_hyst = w83627ehf_read_value(client,
+		data->temp1_max_hyst = w83627ehf_read_value(data,
 				       W83627EHF_REG_TEMP1_HYST);
 		for (i = 0; i < 2; i++) {
-			data->temp[i] = w83627ehf_read_value(client,
+			data->temp[i] = w83627ehf_read_value(data,
 					W83627EHF_REG_TEMP[i]);
-			data->temp_max[i] = w83627ehf_read_value(client,
+			data->temp_max[i] = w83627ehf_read_value(data,
 					    W83627EHF_REG_TEMP_OVER[i]);
-			data->temp_max_hyst[i] = w83627ehf_read_value(client,
+			data->temp_max_hyst[i] = w83627ehf_read_value(data,
 						 W83627EHF_REG_TEMP_HYST[i]);
 		}
 
-		data->alarms = w83627ehf_read_value(client,
+		data->alarms = w83627ehf_read_value(data,
 					W83627EHF_REG_ALARM1) |
-			       (w83627ehf_read_value(client,
+			       (w83627ehf_read_value(data,
 					W83627EHF_REG_ALARM2) << 8) |
-			       (w83627ehf_read_value(client,
+			       (w83627ehf_read_value(data,
 					W83627EHF_REG_ALARM3) << 16);
 
 		data->last_updated = jiffies;
@@ -567,15 +578,14 @@
 store_in_##reg (struct device *dev, struct device_attribute *attr, \
 			const char *buf, size_t count) \
 { \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct w83627ehf_data *data = i2c_get_clientdata(client); \
+	struct w83627ehf_data *data = dev_get_drvdata(dev); \
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	u32 val = simple_strtoul(buf, NULL, 10); \
  \
 	mutex_lock(&data->update_lock); \
 	data->in_##reg[nr] = in_to_reg(val, nr); \
-	w83627ehf_write_value(client, W83627EHF_REG_IN_##REG(nr), \
+	w83627ehf_write_value(data, W83627EHF_REG_IN_##REG(nr), \
 			      data->in_##reg[nr]); \
 	mutex_unlock(&data->update_lock); \
 	return count; \
@@ -673,8 +683,7 @@
 store_fan_min(struct device *dev, struct device_attribute *attr,
 	      const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83627ehf_data *data = i2c_get_clientdata(client);
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	unsigned int val = simple_strtoul(buf, NULL, 10);
@@ -716,18 +725,25 @@
 	/* Write both the fan clock divider (if it changed) and the new
 	   fan min (unconditionally) */
 	if (new_div != data->fan_div[nr]) {
-		if (new_div > data->fan_div[nr])
-			data->fan[nr] >>= (data->fan_div[nr] - new_div);
-		else
-			data->fan[nr] <<= (new_div - data->fan_div[nr]);
+		/* Preserve the fan speed reading */
+		if (data->fan[nr] != 0xff) {
+			if (new_div > data->fan_div[nr])
+				data->fan[nr] >>= new_div - data->fan_div[nr];
+			else if (data->fan[nr] & 0x80)
+				data->fan[nr] = 0xff;
+			else
+				data->fan[nr] <<= data->fan_div[nr] - new_div;
+		}
 
 		dev_dbg(dev, "fan%u clock divider changed from %u to %u\n",
 			nr + 1, div_from_reg(data->fan_div[nr]),
 			div_from_reg(new_div));
 		data->fan_div[nr] = new_div;
-		w83627ehf_write_fan_div(client, nr);
+		w83627ehf_write_fan_div(data, nr);
+		/* Give the chip time to sample a new speed value */
+		data->last_updated = jiffies;
 	}
-	w83627ehf_write_value(client, W83627EHF_REG_FAN_MIN[nr],
+	w83627ehf_write_value(data, W83627EHF_REG_FAN_MIN[nr],
 			      data->fan_min[nr]);
 	mutex_unlock(&data->update_lock);
 
@@ -788,13 +804,12 @@
 store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
 		  const char *buf, size_t count) \
 { \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct w83627ehf_data *data = i2c_get_clientdata(client); \
+	struct w83627ehf_data *data = dev_get_drvdata(dev); \
 	u32 val = simple_strtoul(buf, NULL, 10); \
  \
 	mutex_lock(&data->update_lock); \
 	data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
-	w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \
+	w83627ehf_write_value(data, W83627EHF_REG_TEMP1_##REG, \
 			      data->temp1_##reg); \
 	mutex_unlock(&data->update_lock); \
 	return count; \
@@ -822,15 +837,14 @@
 store_##reg(struct device *dev, struct device_attribute *attr, \
 	    const char *buf, size_t count) \
 { \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct w83627ehf_data *data = i2c_get_clientdata(client); \
+	struct w83627ehf_data *data = dev_get_drvdata(dev); \
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	u32 val = simple_strtoul(buf, NULL, 10); \
  \
 	mutex_lock(&data->update_lock); \
 	data->reg[nr] = LM75_TEMP_TO_REG(val); \
-	w83627ehf_write_value(client, W83627EHF_REG_TEMP_##REG[nr], \
+	w83627ehf_write_value(data, W83627EHF_REG_TEMP_##REG[nr], \
 			      data->reg[nr]); \
 	mutex_unlock(&data->update_lock); \
 	return count; \
@@ -838,6 +852,15 @@
 store_temp_reg(OVER, temp_max);
 store_temp_reg(HYST, temp_max_hyst);
 
+static ssize_t
+show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627ehf_data *data = w83627ehf_update_device(dev);
+	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+	int nr = sensor_attr->index;
+	return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
+}
+
 static struct sensor_device_attribute sda_temp[] = {
 	SENSOR_ATTR(temp1_input, S_IRUGO, show_temp1, NULL, 0),
 	SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 0),
@@ -857,6 +880,9 @@
 	SENSOR_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4),
 	SENSOR_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5),
 	SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
+	SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
+	SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
+	SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
 };
 
 #define show_pwm_reg(reg) \
@@ -877,8 +903,7 @@
 store_pwm_mode(struct device *dev, struct device_attribute *attr,
 			const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83627ehf_data *data = i2c_get_clientdata(client);
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	u32 val = simple_strtoul(buf, NULL, 10);
@@ -887,12 +912,12 @@
 	if (val > 1)
 		return -EINVAL;
 	mutex_lock(&data->update_lock);
-	reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
+	reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
 	data->pwm_mode[nr] = val;
 	reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
 	if (!val)
 		reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
-	w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
+	w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -901,15 +926,14 @@
 store_pwm(struct device *dev, struct device_attribute *attr,
 			const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83627ehf_data *data = i2c_get_clientdata(client);
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
 
 	mutex_lock(&data->update_lock);
 	data->pwm[nr] = val;
-	w83627ehf_write_value(client, W83627EHF_REG_PWM[nr], val);
+	w83627ehf_write_value(data, W83627EHF_REG_PWM[nr], val);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -918,8 +942,7 @@
 store_pwm_enable(struct device *dev, struct device_attribute *attr,
 			const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83627ehf_data *data = i2c_get_clientdata(client);
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	u32 val = simple_strtoul(buf, NULL, 10);
@@ -928,11 +951,11 @@
 	if (!val || (val > 2))	/* only modes 1 and 2 are supported */
 		return -EINVAL;
 	mutex_lock(&data->update_lock);
-	reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
+	reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]);
 	data->pwm_enable[nr] = val;
 	reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
 	reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
-	w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
+	w83627ehf_write_value(data, W83627EHF_REG_PWM_ENABLE[nr], reg);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -955,15 +978,14 @@
 store_target_temp(struct device *dev, struct device_attribute *attr,
 			const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83627ehf_data *data = i2c_get_clientdata(client);
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
 
 	mutex_lock(&data->update_lock);
 	data->target_temp[nr] = val;
-	w83627ehf_write_value(client, W83627EHF_REG_TARGET[nr], val);
+	w83627ehf_write_value(data, W83627EHF_REG_TARGET[nr], val);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -972,8 +994,7 @@
 store_tolerance(struct device *dev, struct device_attribute *attr,
 			const char *buf, size_t count)
 {
-	struct i2c_client *client = to_i2c_client(dev);
-	struct w83627ehf_data *data = i2c_get_clientdata(client);
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
 	int nr = sensor_attr->index;
 	u16 reg;
@@ -981,13 +1002,13 @@
 	u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
 
 	mutex_lock(&data->update_lock);
-	reg = w83627ehf_read_value(client, W83627EHF_REG_TOLERANCE[nr]);
+	reg = w83627ehf_read_value(data, W83627EHF_REG_TOLERANCE[nr]);
 	data->tolerance[nr] = val;
 	if (nr == 1)
 		reg = (reg & 0x0f) | (val << 4);
 	else
 		reg = (reg & 0xf0) | val;
-	w83627ehf_write_value(client, W83627EHF_REG_TOLERANCE[nr], reg);
+	w83627ehf_write_value(data, W83627EHF_REG_TOLERANCE[nr], reg);
 	mutex_unlock(&data->update_lock);
 	return count;
 }
@@ -1058,14 +1079,13 @@
 store_##reg(struct device *dev, struct device_attribute *attr, \
 			    const char *buf, size_t count) \
 {\
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct w83627ehf_data *data = i2c_get_clientdata(client); \
+	struct w83627ehf_data *data = dev_get_drvdata(dev); \
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
 	mutex_lock(&data->update_lock); \
 	data->reg[nr] = val; \
-	w83627ehf_write_value(client, W83627EHF_REG_##REG[nr],  val); \
+	w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
 	mutex_unlock(&data->update_lock); \
 	return count; \
 }
@@ -1087,21 +1107,28 @@
 store_##reg(struct device *dev, struct device_attribute *attr, \
 			const char *buf, size_t count) \
 { \
-	struct i2c_client *client = to_i2c_client(dev); \
-	struct w83627ehf_data *data = i2c_get_clientdata(client); \
+	struct w83627ehf_data *data = dev_get_drvdata(dev); \
 	struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
 	int nr = sensor_attr->index; \
 	u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
 					data->pwm_mode[nr]); \
 	mutex_lock(&data->update_lock); \
 	data->reg[nr] = val; \
-	w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \
+	w83627ehf_write_value(data, W83627EHF_REG_##REG[nr], val); \
 	mutex_unlock(&data->update_lock); \
 	return count; \
 } \
 
 fan_time_functions(fan_stop_time, FAN_STOP_TIME)
 
+static ssize_t show_name(struct device *dev, struct device_attribute *attr,
+			 char *buf)
+{
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", data->name);
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
 static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
 	SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
@@ -1125,8 +1152,16 @@
 		    store_fan_min_output, 2),
 };
 
+static ssize_t
+show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
+	return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
 /*
- * Driver and client management
+ * Driver and device management
  */
 
 static void w83627ehf_device_remove_files(struct device *dev)
@@ -1134,12 +1169,13 @@
 	/* some entries in the following arrays may not have been used in
 	 * device_create_file(), but device_remove_file() will ignore them */
 	int i;
+	struct w83627ehf_data *data = dev_get_drvdata(dev);
 
 	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
 		device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
 	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
 		device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
-	for (i = 0; i < w83627ehf_num_in; i++) {
+	for (i = 0; i < data->in_num; i++) {
 		device_remove_file(dev, &sda_in_input[i].dev_attr);
 		device_remove_file(dev, &sda_in_alarm[i].dev_attr);
 		device_remove_file(dev, &sda_in_min[i].dev_attr);
@@ -1160,43 +1196,64 @@
 	}
 	for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
 		device_remove_file(dev, &sda_temp[i].dev_attr);
+
+	device_remove_file(dev, &dev_attr_name);
+	if (data->vid != 0x3f)
+		device_remove_file(dev, &dev_attr_cpu0_vid);
 }
 
-static struct i2c_driver w83627ehf_driver;
-
-static void w83627ehf_init_client(struct i2c_client *client)
+/* Get the monitoring functions started */
+static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data)
 {
 	int i;
-	u8 tmp;
+	u8 tmp, diode;
 
 	/* Start monitoring is needed */
-	tmp = w83627ehf_read_value(client, W83627EHF_REG_CONFIG);
+	tmp = w83627ehf_read_value(data, W83627EHF_REG_CONFIG);
 	if (!(tmp & 0x01))
-		w83627ehf_write_value(client, W83627EHF_REG_CONFIG,
+		w83627ehf_write_value(data, W83627EHF_REG_CONFIG,
 				      tmp | 0x01);
 
 	/* Enable temp2 and temp3 if needed */
 	for (i = 0; i < 2; i++) {
-		tmp = w83627ehf_read_value(client,
+		tmp = w83627ehf_read_value(data,
 					   W83627EHF_REG_TEMP_CONFIG[i]);
 		if (tmp & 0x01)
-			w83627ehf_write_value(client,
+			w83627ehf_write_value(data,
 					      W83627EHF_REG_TEMP_CONFIG[i],
 					      tmp & 0xfe);
 	}
+
+	/* Enable VBAT monitoring if needed */
+	tmp = w83627ehf_read_value(data, W83627EHF_REG_VBAT);
+	if (!(tmp & 0x01))
+		w83627ehf_write_value(data, W83627EHF_REG_VBAT, tmp | 0x01);
+
+	/* Get thermal sensor types */
+	diode = w83627ehf_read_value(data, W83627EHF_REG_DIODE);
+	for (i = 0; i < 3; i++) {
+		if ((tmp & (0x02 << i)))
+			data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 2;
+		else
+			data->temp_type[i] = 4; /* thermistor */
+	}
 }
 
-static int w83627ehf_detect(struct i2c_adapter *adapter)
+static int __devinit w83627ehf_probe(struct platform_device *pdev)
 {
-	struct i2c_client *client;
+	struct device *dev = &pdev->dev;
+	struct w83627ehf_sio_data *sio_data = dev->platform_data;
 	struct w83627ehf_data *data;
-	struct device *dev;
-	u8 fan4pin, fan5pin;
+	struct resource *res;
+	u8 fan4pin, fan5pin, en_vrm10;
 	int i, err = 0;
 
-	if (!request_region(address + IOREGION_OFFSET, IOREGION_LENGTH,
-	                    w83627ehf_driver.driver.name)) {
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!request_region(res->start, IOREGION_LENGTH, DRVNAME)) {
 		err = -EBUSY;
+		dev_err(dev, "Failed to request region 0x%lx-0x%lx\n",
+			(unsigned long)res->start,
+			(unsigned long)res->start + IOREGION_LENGTH - 1);
 		goto exit;
 	}
 
@@ -1205,41 +1262,47 @@
 		goto exit_release;
 	}
 
-	client = &data->client;
-	i2c_set_clientdata(client, data);
-	client->addr = address;
+	data->addr = res->start;
 	mutex_init(&data->lock);
-	client->adapter = adapter;
-	client->driver = &w83627ehf_driver;
-	client->flags = 0;
-	dev = &client->dev;
-
-	if (w83627ehf_num_in == 9)
-		strlcpy(client->name, "w83627dhg", I2C_NAME_SIZE);
-	else	/* just say ehf. 627EHG is 627EHF in lead-free packaging. */
-		strlcpy(client->name, "w83627ehf", I2C_NAME_SIZE);
-
-	data->valid = 0;
 	mutex_init(&data->update_lock);
+	data->name = w83627ehf_device_names[sio_data->kind];
+	platform_set_drvdata(pdev, data);
 
-	/* Tell the i2c layer a new client has arrived */
-	if ((err = i2c_attach_client(client)))
-		goto exit_free;
+	/* 627EHG and 627EHF have 10 voltage inputs; DHG has 9 */
+	data->in_num = (sio_data->kind == w83627dhg) ? 9 : 10;
 
 	/* Initialize the chip */
-	w83627ehf_init_client(client);
+	w83627ehf_init_device(data);
 
-	/* A few vars need to be filled upon startup */
-	for (i = 0; i < 5; i++)
-		data->fan_min[i] = w83627ehf_read_value(client,
-				   W83627EHF_REG_FAN_MIN[i]);
+	data->vrm = vid_which_vrm();
+	superio_enter(sio_data->sioreg);
+	/* Set VID input sensibility if needed. In theory the BIOS should
+	   have set it, but in practice it's not always the case. */
+	en_vrm10 = superio_inb(sio_data->sioreg, SIO_REG_EN_VRM10);
+	if ((en_vrm10 & 0x08) && data->vrm != 100) {
+		dev_warn(dev, "Setting VID input voltage to TTL\n");
+		superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
+			     en_vrm10 & ~0x08);
+	} else if (!(en_vrm10 & 0x08) && data->vrm == 100) {
+		dev_warn(dev, "Setting VID input voltage to VRM10\n");
+		superio_outb(sio_data->sioreg, SIO_REG_EN_VRM10,
+			     en_vrm10 | 0x08);
+	}
+	/* Read VID value */
+	superio_select(sio_data->sioreg, W83627EHF_LD_HWM);
+	if (superio_inb(sio_data->sioreg, SIO_REG_VID_CTRL) & 0x80)
+		data->vid = superio_inb(sio_data->sioreg, SIO_REG_VID_DATA) & 0x3f;
+	else {
+		dev_info(dev, "VID pins in output mode, CPU VID not "
+			 "available\n");
+		data->vid = 0x3f;
+	}
 
 	/* fan4 and fan5 share some pins with the GPIO and serial flash */
 
-	superio_enter();
-	fan5pin = superio_inb(0x24) & 0x2;
-	fan4pin = superio_inb(0x29) & 0x6;
-	superio_exit();
+	fan5pin = superio_inb(sio_data->sioreg, 0x24) & 0x2;
+	fan4pin = superio_inb(sio_data->sioreg, 0x29) & 0x6;
+	superio_exit(sio_data->sioreg);
 
 	/* It looks like fan4 and fan5 pins can be alternatively used
 	   as fan on/off switches, but fan5 control is write only :/
@@ -1248,12 +1311,15 @@
 	   is not the default. */
 
 	data->has_fan = 0x07; /* fan1, fan2 and fan3 */
-	i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
+	i = w83627ehf_read_value(data, W83627EHF_REG_FANDIV1);
 	if ((i & (1 << 2)) && (!fan4pin))
 		data->has_fan |= (1 << 3);
 	if (!(i & (1 << 1)) && (!fan5pin))
 		data->has_fan |= (1 << 4);
 
+	/* Read fan clock dividers immediately */
+	w83627ehf_update_fan_div(data);
+
 	/* Register sysfs hooks */
   	for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
 		if ((err = device_create_file(dev,
@@ -1268,7 +1334,7 @@
 				goto exit_remove;
 		}
 
-	for (i = 0; i < w83627ehf_num_in; i++)
+	for (i = 0; i < data->in_num; i++)
 		if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
 			|| (err = device_create_file(dev,
 				&sda_in_alarm[i].dev_attr))
@@ -1308,6 +1374,16 @@
 		if ((err = device_create_file(dev, &sda_temp[i].dev_attr)))
 			goto exit_remove;
 
+	err = device_create_file(dev, &dev_attr_name);
+	if (err)
+		goto exit_remove;
+
+	if (data->vid != 0x3f) {
+		err = device_create_file(dev, &dev_attr_cpu0_vid);
+		if (err)
+			goto exit_remove;
+	}
+
 	data->class_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->class_dev)) {
 		err = PTR_ERR(data->class_dev);
@@ -1318,95 +1394,172 @@
 
 exit_remove:
 	w83627ehf_device_remove_files(dev);
-	i2c_detach_client(client);
-exit_free:
 	kfree(data);
+	platform_set_drvdata(pdev, NULL);
 exit_release:
-	release_region(address + IOREGION_OFFSET, IOREGION_LENGTH);
+	release_region(res->start, IOREGION_LENGTH);
 exit:
 	return err;
 }
 
-static int w83627ehf_detach_client(struct i2c_client *client)
+static int __devexit w83627ehf_remove(struct platform_device *pdev)
 {
-	struct w83627ehf_data *data = i2c_get_clientdata(client);
-	int err;
+	struct w83627ehf_data *data = platform_get_drvdata(pdev);
 
 	hwmon_device_unregister(data->class_dev);
-	w83627ehf_device_remove_files(&client->dev);
-
-	if ((err = i2c_detach_client(client)))
-		return err;
-	release_region(client->addr + IOREGION_OFFSET, IOREGION_LENGTH);
+	w83627ehf_device_remove_files(&pdev->dev);
+	release_region(data->addr, IOREGION_LENGTH);
+	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 
 	return 0;
 }
 
-static struct i2c_driver w83627ehf_driver = {
+static struct platform_driver w83627ehf_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
-		.name	= "w83627ehf",
+		.name	= DRVNAME,
 	},
-	.attach_adapter	= w83627ehf_detect,
-	.detach_client	= w83627ehf_detach_client,
+	.probe		= w83627ehf_probe,
+	.remove		= __devexit_p(w83627ehf_remove),
 };
 
-static int __init w83627ehf_find(int sioaddr, unsigned short *addr)
+/* w83627ehf_find() looks for a '627 in the Super-I/O config space */
+static int __init w83627ehf_find(int sioaddr, unsigned short *addr,
+				 struct w83627ehf_sio_data *sio_data)
 {
+	static const char __initdata sio_name_W83627EHF[] = "W83627EHF";
+	static const char __initdata sio_name_W83627EHG[] = "W83627EHG";
+	static const char __initdata sio_name_W83627DHG[] = "W83627DHG";
+
 	u16 val;
+	const char *sio_name;
 
-	REG = sioaddr;
-	VAL = sioaddr + 1;
-	superio_enter();
+	superio_enter(sioaddr);
 
-	val = (superio_inb(SIO_REG_DEVID) << 8)
-	    | superio_inb(SIO_REG_DEVID + 1);
+	val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8)
+	    | superio_inb(sioaddr, SIO_REG_DEVID + 1);
 	switch (val & SIO_ID_MASK) {
-	case SIO_W83627DHG_ID:
-		w83627ehf_num_in = 9;
-		break;
 	case SIO_W83627EHF_ID:
+		sio_data->kind = w83627ehf;
+		sio_name = sio_name_W83627EHF;
+		break;
 	case SIO_W83627EHG_ID:
-		w83627ehf_num_in = 10;
+		sio_data->kind = w83627ehf;
+		sio_name = sio_name_W83627EHG;
+		break;
+	case SIO_W83627DHG_ID:
+		sio_data->kind = w83627dhg;
+		sio_name = sio_name_W83627DHG;
 		break;
 	default:
-		printk(KERN_WARNING "w83627ehf: unsupported chip ID: 0x%04x\n",
-			val);
-		superio_exit();
+		if (val != 0xffff)
+			pr_debug(DRVNAME ": unsupported chip ID: 0x%04x\n",
+				 val);
+		superio_exit(sioaddr);
 		return -ENODEV;
 	}
 
-	superio_select(W83627EHF_LD_HWM);
-	val = (superio_inb(SIO_REG_ADDR) << 8)
-	    | superio_inb(SIO_REG_ADDR + 1);
+	/* We have a known chip, find the HWM I/O address */
+	superio_select(sioaddr, W83627EHF_LD_HWM);
+	val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8)
+	    | superio_inb(sioaddr, SIO_REG_ADDR + 1);
 	*addr = val & IOREGION_ALIGNMENT;
 	if (*addr == 0) {
-		superio_exit();
+		printk(KERN_ERR DRVNAME ": Refusing to enable a Super-I/O "
+		       "device with a base I/O port 0.\n");
+		superio_exit(sioaddr);
 		return -ENODEV;
 	}
 
 	/* Activate logical device if needed */
-	val = superio_inb(SIO_REG_ENABLE);
-	if (!(val & 0x01))
-		superio_outb(SIO_REG_ENABLE, val | 0x01);
+	val = superio_inb(sioaddr, SIO_REG_ENABLE);
+	if (!(val & 0x01)) {
+		printk(KERN_WARNING DRVNAME ": Forcibly enabling Super-I/O. "
+		       "Sensor is probably unusable.\n");
+		superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
+	}
 
-	superio_exit();
+	superio_exit(sioaddr);
+	pr_info(DRVNAME ": Found %s chip at %#x\n", sio_name, *addr);
+	sio_data->sioreg = sioaddr;
+
 	return 0;
 }
 
+/* when Super-I/O functions move to a separate file, the Super-I/O
+ * bus will manage the lifetime of the device and this module will only keep
+ * track of the w83627ehf driver. But since we platform_device_alloc(), we
+ * must keep track of the device */
+static struct platform_device *pdev;
+
 static int __init sensors_w83627ehf_init(void)
 {
-	if (w83627ehf_find(0x2e, &address)
-	 && w83627ehf_find(0x4e, &address))
+	int err;
+	unsigned short address;
+	struct resource res;
+	struct w83627ehf_sio_data sio_data;
+
+	/* initialize sio_data->kind and sio_data->sioreg.
+	 *
+	 * when Super-I/O functions move to a separate file, the Super-I/O
+	 * driver will probe 0x2e and 0x4e and auto-detect the presence of a
+	 * w83627ehf hardware monitor, and call probe() */
+	if (w83627ehf_find(0x2e, &address, &sio_data) &&
+	    w83627ehf_find(0x4e, &address, &sio_data))
 		return -ENODEV;
 
-	return i2c_isa_add_driver(&w83627ehf_driver);
+	err = platform_driver_register(&w83627ehf_driver);
+	if (err)
+		goto exit;
+
+	if (!(pdev = platform_device_alloc(DRVNAME, address))) {
+		err = -ENOMEM;
+		printk(KERN_ERR DRVNAME ": Device allocation failed\n");
+		goto exit_unregister;
+	}
+
+	err = platform_device_add_data(pdev, &sio_data,
+				       sizeof(struct w83627ehf_sio_data));
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
+		goto exit_device_put;
+	}
+
+	memset(&res, 0, sizeof(res));
+	res.name = DRVNAME;
+	res.start = address + IOREGION_OFFSET;
+	res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1;
+	res.flags = IORESOURCE_IO;
+	err = platform_device_add_resources(pdev, &res, 1);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device resource addition failed "
+		       "(%d)\n", err);
+		goto exit_device_put;
+	}
+
+	/* platform_device_add calls probe() */
+	err = platform_device_add(pdev);
+	if (err) {
+		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+		       err);
+		goto exit_device_put;
+	}
+
+	return 0;
+
+exit_device_put:
+	platform_device_put(pdev);
+exit_unregister:
+	platform_driver_unregister(&w83627ehf_driver);
+exit:
+	return err;
 }
 
 static void __exit sensors_w83627ehf_exit(void)
 {
-	i2c_isa_del_driver(&w83627ehf_driver);
+	platform_device_unregister(pdev);
+	platform_driver_unregister(&w83627ehf_driver);
 }
 
 MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 12cb40a..7a4a15f 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -220,6 +220,18 @@
 #define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \
                                      regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1])
 
+#define W83627HF_REG_PWM_FREQ		0x5C	/* Only for the 627HF */
+
+#define W83637HF_REG_PWM_FREQ1		0x00	/* 697HF/687THF too */
+#define W83637HF_REG_PWM_FREQ2		0x02	/* 697HF/687THF too */
+#define W83637HF_REG_PWM_FREQ3		0x10	/* 687THF too */
+
+static const u8 W83637HF_REG_PWM_FREQ[] = { W83637HF_REG_PWM_FREQ1,
+					W83637HF_REG_PWM_FREQ2,
+					W83637HF_REG_PWM_FREQ3 };
+
+#define W83627HF_BASE_PWM_FREQ	46870
+
 #define W83781D_REG_I2C_ADDR 0x48
 #define W83781D_REG_I2C_SUBADDR 0x4A
 
@@ -267,6 +279,49 @@
 
 #define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255))
 
+static inline unsigned long pwm_freq_from_reg_627hf(u8 reg)
+{
+	unsigned long freq;
+	freq = W83627HF_BASE_PWM_FREQ >> reg;
+	return freq;
+}
+static inline u8 pwm_freq_to_reg_627hf(unsigned long val)
+{
+	u8 i;
+	/* Only 5 dividers (1 2 4 8 16)
+	   Search for the nearest available frequency */
+	for (i = 0; i < 4; i++) {
+		if (val > (((W83627HF_BASE_PWM_FREQ >> i) +
+			    (W83627HF_BASE_PWM_FREQ >> (i+1))) / 2))
+			break;
+	}
+	return i;
+}
+
+static inline unsigned long pwm_freq_from_reg(u8 reg)
+{
+	/* Clock bit 8 -> 180 kHz or 24 MHz */
+	unsigned long clock = (reg & 0x80) ? 180000UL : 24000000UL;
+
+	reg &= 0x7f;
+	/* This should not happen but anyway... */
+	if (reg == 0)
+		reg++;
+	return (clock / (reg << 8));
+}
+static inline u8 pwm_freq_to_reg(unsigned long val)
+{
+	/* Minimum divider value is 0x01 and maximum is 0x7F */
+	if (val >= 93750)	/* The highest we can do */
+		return 0x01;
+	if (val >= 720)	/* Use 24 MHz clock */
+		return (24000000UL / (val << 8));
+	if (val < 6)		/* The lowest we can do */
+		return 0xFF;
+	else			/* Use 180 kHz clock */
+		return (0x80 | (180000UL / (val << 8)));
+}
+
 #define BEEP_MASK_FROM_REG(val)		 (val)
 #define BEEP_MASK_TO_REG(val)		((val) & 0xffffff)
 #define BEEP_ENABLE_TO_REG(val)		((val)?1:0)
@@ -316,6 +371,7 @@
 	u32 beep_mask;		/* Register encoding, combined */
 	u8 beep_enable;		/* Boolean */
 	u8 pwm[3];		/* Register value */
+	u8 pwm_freq[3];		/* Register value */
 	u16 sens[3];		/* 782D/783S only.
 				   1 = pentium diode; 2 = 3904 diode;
 				   3000-5000 = thermistor beta.
@@ -331,7 +387,7 @@
 
 
 static int w83627hf_probe(struct platform_device *pdev);
-static int w83627hf_remove(struct platform_device *pdev);
+static int __devexit w83627hf_remove(struct platform_device *pdev);
 
 static int w83627hf_read_value(struct w83627hf_data *data, u16 reg);
 static int w83627hf_write_value(struct w83627hf_data *data, u16 reg, u16 value);
@@ -852,6 +908,64 @@
 sysfs_pwm(3);
 
 static ssize_t
+show_pwm_freq_reg(struct device *dev, char *buf, int nr)
+{
+	struct w83627hf_data *data = w83627hf_update_device(dev);
+	if (data->type == w83627hf)
+		return sprintf(buf, "%ld\n",
+			pwm_freq_from_reg_627hf(data->pwm_freq[nr - 1]));
+	else
+		return sprintf(buf, "%ld\n",
+			pwm_freq_from_reg(data->pwm_freq[nr - 1]));
+}
+
+static ssize_t
+store_pwm_freq_reg(struct device *dev, const char *buf, size_t count, int nr)
+{
+	struct w83627hf_data *data = dev_get_drvdata(dev);
+	static const u8 mask[]={0xF8, 0x8F};
+	u32 val;
+
+	val = simple_strtoul(buf, NULL, 10);
+
+	mutex_lock(&data->update_lock);
+
+	if (data->type == w83627hf) {
+		data->pwm_freq[nr - 1] = pwm_freq_to_reg_627hf(val);
+		w83627hf_write_value(data, W83627HF_REG_PWM_FREQ,
+				(data->pwm_freq[nr - 1] << ((nr - 1)*4)) |
+				(w83627hf_read_value(data,
+				W83627HF_REG_PWM_FREQ) & mask[nr - 1]));
+	} else {
+		data->pwm_freq[nr - 1] = pwm_freq_to_reg(val);
+		w83627hf_write_value(data, W83637HF_REG_PWM_FREQ[nr - 1],
+				data->pwm_freq[nr - 1]);
+	}
+
+	mutex_unlock(&data->update_lock);
+	return count;
+}
+
+#define sysfs_pwm_freq(offset) \
+static ssize_t show_regs_pwm_freq_##offset(struct device *dev, \
+		struct device_attribute *attr, char *buf) \
+{ \
+	return show_pwm_freq_reg(dev, buf, offset); \
+} \
+static ssize_t \
+store_regs_pwm_freq_##offset(struct device *dev, \
+		struct device_attribute *attr, const char *buf, size_t count) \
+{ \
+	return store_pwm_freq_reg(dev, buf, count, offset); \
+} \
+static DEVICE_ATTR(pwm##offset##_freq, S_IRUGO | S_IWUSR, \
+		  show_regs_pwm_freq_##offset, store_regs_pwm_freq_##offset);
+
+sysfs_pwm_freq(1);
+sysfs_pwm_freq(2);
+sysfs_pwm_freq(3);
+
+static ssize_t
 show_sensor_reg(struct device *dev, char *buf, int nr)
 {
 	struct w83627hf_data *data = w83627hf_update_device(dev);
@@ -1077,6 +1191,9 @@
 
 	&dev_attr_pwm3.attr,
 
+	&dev_attr_pwm1_freq.attr,
+	&dev_attr_pwm2_freq.attr,
+	&dev_attr_pwm3_freq.attr,
 	NULL
 };
 
@@ -1139,7 +1256,9 @@
 		 || (err = device_create_file(dev, &dev_attr_in5_max))
 		 || (err = device_create_file(dev, &dev_attr_in6_input))
 		 || (err = device_create_file(dev, &dev_attr_in6_min))
-		 || (err = device_create_file(dev, &dev_attr_in6_max)))
+		 || (err = device_create_file(dev, &dev_attr_in6_max))
+		 || (err = device_create_file(dev, &dev_attr_pwm1_freq))
+		 || (err = device_create_file(dev, &dev_attr_pwm2_freq)))
 			goto ERROR4;
 
 	if (data->type != w83697hf)
@@ -1169,6 +1288,12 @@
 		if ((err = device_create_file(dev, &dev_attr_pwm3)))
 			goto ERROR4;
 
+	if (data->type == w83637hf || data->type == w83687thf)
+		if ((err = device_create_file(dev, &dev_attr_pwm1_freq))
+		 || (err = device_create_file(dev, &dev_attr_pwm2_freq))
+		 || (err = device_create_file(dev, &dev_attr_pwm3_freq)))
+			goto ERROR4;
+
 	data->class_dev = hwmon_device_register(dev);
 	if (IS_ERR(data->class_dev)) {
 		err = PTR_ERR(data->class_dev);
@@ -1181,6 +1306,7 @@
 	sysfs_remove_group(&dev->kobj, &w83627hf_group);
 	sysfs_remove_group(&dev->kobj, &w83627hf_group_opt);
       ERROR3:
+	platform_set_drvdata(pdev, NULL);
 	kfree(data);
       ERROR1:
 	release_region(res->start, WINB_REGION_SIZE);
@@ -1193,11 +1319,11 @@
 	struct w83627hf_data *data = platform_get_drvdata(pdev);
 	struct resource *res;
 
-	platform_set_drvdata(pdev, NULL);
 	hwmon_device_unregister(data->class_dev);
 
 	sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group);
 	sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt);
+	platform_set_drvdata(pdev, NULL);
 	kfree(data);
 
 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
@@ -1472,6 +1598,20 @@
 			   (data->type == w83627hf || data->type == w83697hf))
 				break;
 		}
+		if (data->type == w83627hf) {
+				u8 tmp = w83627hf_read_value(data,
+						W83627HF_REG_PWM_FREQ);
+				data->pwm_freq[0] = tmp & 0x07;
+				data->pwm_freq[1] = (tmp >> 4) & 0x07;
+		} else if (data->type != w83627thf) {
+			for (i = 1; i <= 3; i++) {
+				data->pwm_freq[i - 1] =
+					w83627hf_read_value(data,
+						W83637HF_REG_PWM_FREQ[i - 1]);
+				if (i == 2 && (data->type == w83697hf))
+					break;
+			}
+		}
 
 		data->temp = w83627hf_read_value(data, W83781D_REG_TEMP(1));
 		data->temp_max =
@@ -1548,15 +1688,12 @@
 		goto exit_device_put;
 	}
 
-	pdev->dev.platform_data = kmalloc(sizeof(struct w83627hf_sio_data),
-					  GFP_KERNEL);
-	if (!pdev->dev.platform_data) {
-		err = -ENOMEM;
+	err = platform_device_add_data(pdev, sio_data,
+				       sizeof(struct w83627hf_sio_data));
+	if (err) {
 		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");
 		goto exit_device_put;
 	}
-	memcpy(pdev->dev.platform_data, sio_data,
-	       sizeof(struct w83627hf_sio_data));
 
 	err = platform_device_add(pdev);
 	if (err) {
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index f85b48f..dcc941a 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -740,9 +740,9 @@
 static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO | S_IWUSR,
 	show_sensor, store_sensor, 0);
 static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR,
-	show_sensor, store_sensor, 0);
+	show_sensor, store_sensor, 1);
 static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR,
-	show_sensor, store_sensor, 0);
+	show_sensor, store_sensor, 2);
 
 /* I2C devices get this name attribute automatically, but for ISA devices
    we must create it by ourselves. */
@@ -1746,7 +1746,7 @@
 {
 	struct resource res = {
 		.start	= address,
-		.end	= address + W83781D_EXTENT,
+		.end	= address + W83781D_EXTENT - 1,
 		.name	= "w83781d",
 		.flags	= IORESOURCE_IO,
 	};
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index 8a5f582..7f0a0a6 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -357,13 +357,29 @@
 	return wrcount;
 }
 
+static int acknak(struct i2c_adapter *i2c_adap, int is_ack)
+{
+	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
+
+	/* assert: sda is high */
+	if (is_ack)		/* send ack */
+		setsda(adap, 0);
+	udelay((adap->udelay + 1) / 2);
+	if (sclhi(adap) < 0) {	/* timeout */
+		dev_err(&i2c_adap->dev, "readbytes: ack/nak timeout\n");
+		return -ETIMEDOUT;
+	}
+	scllo(adap);
+	return 0;
+}
+
 static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
 {
 	int inval;
 	int rdcount=0;   	/* counts bytes read */
-	struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
 	unsigned char *temp = msg->buf;
 	int count = msg->len;
+	const unsigned flags = msg->flags;
 
 	while (count > 0) {
 		inval = i2c_inb(i2c_adap);
@@ -377,28 +393,12 @@
 		temp++;
 		count--;
 
-		if (msg->flags & I2C_M_NO_RD_ACK) {
-			bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x\n",
-				inval);
-			continue;
-		}
-
-		/* assert: sda is high */
-		if (count)		/* send ack */
-			setsda(adap, 0);
-		udelay((adap->udelay + 1) / 2);
-		bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x %s\n", inval,
-			count ? "A" : "NA");
-		if (sclhi(adap)<0) {	/* timeout */
-			dev_err(&i2c_adap->dev, "readbytes: timeout at ack\n");
-			return -ETIMEDOUT;
-		};
-		scllo(adap);
-
 		/* Some SMBus transactions require that we receive the
 		   transaction length as the first read byte. */
-		if (rdcount == 1 && (msg->flags & I2C_M_RECV_LEN)) {
+		if (rdcount == 1 && (flags & I2C_M_RECV_LEN)) {
 			if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) {
+				if (!(flags & I2C_M_NO_RD_ACK))
+					acknak(i2c_adap, 0);
 				dev_err(&i2c_adap->dev, "readbytes: invalid "
 					"block length (%d)\n", inval);
 				return -EREMOTEIO;
@@ -409,6 +409,18 @@
 			count += inval;
 			msg->len += inval;
 		}
+
+		bit_dbg(2, &i2c_adap->dev, "readbytes: 0x%02x %s\n",
+			inval,
+			(flags & I2C_M_NO_RD_ACK)
+				? "(no ack/nak)"
+				: (count ? "A" : "NA"));
+
+		if (!(flags & I2C_M_NO_RD_ACK)) {
+			inval = acknak(i2c_adap, count);
+			if (inval < 0)
+				return inval;
+		}
 	}
 	return rdcount;
 }
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 1c77e14..9f3a4cd 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -92,9 +92,9 @@
 
 config I2C_BLACKFIN_TWI
 	tristate "Blackfin TWI I2C support"
-	depends on BF534 || BF536 || BF537
+	depends on BF534 || BF536 || BF537 || BF54x
 	help
-	  This is the TWI I2C device driver for Blackfin 534/536/537.
+	  This is the TWI I2C device driver for Blackfin 534/536/537/54x.
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-bfin-twi.
 
@@ -208,6 +208,7 @@
 	    ATI IXP400
 	    ATI SB600
 	    ATI SB700
+	    ATI SB800
 	    Serverworks OSB4
 	    Serverworks CSB5
 	    Serverworks CSB6
@@ -237,9 +238,6 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-iop3xx.
 
-config I2C_ISA
-	tristate
-
 config I2C_IXP4XX
 	tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)"
 	depends on ARCH_IXP4XX
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index a6db4e3..5b752e4 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -18,7 +18,6 @@
 obj-$(CONFIG_I2C_I810)		+= i2c-i810.o
 obj-$(CONFIG_I2C_IBM_IIC)	+= i2c-ibm_iic.o
 obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
-obj-$(CONFIG_I2C_ISA)		+= i2c-isa.o
 obj-$(CONFIG_I2C_IXP2000)	+= i2c-ixp2000.o
 obj-$(CONFIG_I2C_IXP4XX)	+= i2c-ixp4xx.o
 obj-$(CONFIG_I2C_POWERMAC)	+= i2c-powermac.o
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index 025f194..44e1cd2 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -147,7 +147,7 @@
 	 * The reason to do so is to avoid sysfs names that only make
 	 * sense when there are multiple adapters.
 	 */
-	adap->nr = pdev->id >= 0 ? pdev->id : 0;
+	adap->nr = (pdev->id != -1) ? pdev->id : 0;
 	ret = i2c_bit_add_numbered_bus(adap);
 	if (ret)
 		goto err_add_bus;
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 8f5c686..289816d 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -272,11 +272,11 @@
 		/* Make sure the SMBus host is ready to start transmitting */
 		temp = inb_p(SMBHSTSTS);
 		if (i == 1) {
-			/* Erronenous conditions before transaction:
+			/* Erroneous conditions before transaction:
 			 * Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
 			errmask = 0x9f;
 		} else {
-			/* Erronenous conditions during transaction:
+			/* Erroneous conditions during transaction:
 			 * Failed, Bus_Err, Dev_Err, Intr */
 			errmask = 0x1e;
 		}
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index 440342b..ace644e 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -490,6 +490,7 @@
 	memcpy(new_adapter->name, pdev->name, strlen(pdev->name));
 	new_adapter->id = I2C_HW_IOP3XX;
 	new_adapter->owner = THIS_MODULE;
+	new_adapter->class = I2C_CLASS_HWMON;
 	new_adapter->dev.parent = &pdev->dev;
 	new_adapter->nr = pdev->id;
 
diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c
deleted file mode 100644
index b0e1370..0000000
--- a/drivers/i2c/busses/i2c-isa.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
-    i2c-isa.c - an i2c-core-like thing for ISA hardware monitoring chips
-    Copyright (C) 2005  Jean Delvare <khali@linux-fr.org>
-
-    Based on the i2c-isa pseudo-adapter from the lm_sensors project
-    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> 
-
-    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.
-*/
-
-/* This implements an i2c-core-like thing for ISA hardware monitoring
-   chips. Such chips are linked to the i2c subsystem for historical
-   reasons (because the early ISA hardware monitoring chips such as the
-   LM78 had both an I2C and an ISA interface). They used to be
-   registered with the main i2c-core, but as a first step in the
-   direction of a clean separation between I2C and ISA chip drivers,
-   we now have this separate core for ISA ones. It is significantly
-   more simple than the real one, of course, because we don't have to
-   handle multiple busses: there is only one (fake) ISA adapter.
-   It is worth noting that we still rely on i2c-core for some things
-   at the moment - but hopefully this won't last. */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/i2c.h>
-#include <linux/i2c-isa.h>
-#include <linux/platform_device.h>
-#include <linux/completion.h>
-
-/* Exported by i2c-core for i2c-isa only */
-extern void i2c_adapter_dev_release(struct device *dev);
-extern struct class i2c_adapter_class;
-
-static u32 isa_func(struct i2c_adapter *adapter);
-
-/* This is the actual algorithm we define */
-static const struct i2c_algorithm isa_algorithm = {
-	.functionality	= isa_func,
-};
-
-/* There can only be one... */
-static struct i2c_adapter isa_adapter = {
-	.owner		= THIS_MODULE,
-	.id		= I2C_HW_ISA,
-	.class          = I2C_CLASS_HWMON,
-	.algo		= &isa_algorithm,
-	.name		= "ISA main adapter",
-};
-
-/* We can't do a thing... */
-static u32 isa_func(struct i2c_adapter *adapter)
-{
-	return 0;
-}
-
-
-/* We implement an interface which resembles i2c_{add,del}_driver,
-   but for i2c-isa drivers. We don't have to remember and handle lists
-   of drivers and adapters so this is much more simple, of course. */
-
-int i2c_isa_add_driver(struct i2c_driver *driver)
-{
-	int res;
-
-	/* Add the driver to the list of i2c drivers in the driver core */
-	driver->driver.bus = &i2c_bus_type;
-	res = driver_register(&driver->driver);
-	if (res)
-		return res;
-	dev_dbg(&isa_adapter.dev, "Driver %s registered\n", driver->driver.name);
-
-	/* Now look for clients */
-	res = driver->attach_adapter(&isa_adapter);
-	if (res) {
-		dev_dbg(&isa_adapter.dev,
-			"Driver %s failed to attach adapter, unregistering\n",
-			driver->driver.name);
-		driver_unregister(&driver->driver);
-	}
-	return res;
-}
-
-int i2c_isa_del_driver(struct i2c_driver *driver)
-{
-	struct list_head *item, *_n;
-	struct i2c_client *client;
-	int res;
-
-	/* Detach all clients belonging to this one driver */
-	list_for_each_safe(item, _n, &isa_adapter.clients) {
-		client = list_entry(item, struct i2c_client, list);
-		if (client->driver != driver)
-			continue;
-		dev_dbg(&isa_adapter.dev, "Detaching client %s at 0x%x\n",
-			client->name, client->addr);
-		if ((res = driver->detach_client(client))) {
-			dev_err(&isa_adapter.dev, "Failed, driver "
-				"%s not unregistered!\n",
-				driver->driver.name);
-			return res;
-		}
-	}
-
-	/* Get the driver off the core list */
-	driver_unregister(&driver->driver);
-	dev_dbg(&isa_adapter.dev, "Driver %s unregistered\n", driver->driver.name);
-
-	return 0;
-}
-
-
-static int __init i2c_isa_init(void)
-{
-	int err;
-
-	mutex_init(&isa_adapter.clist_lock);
-	INIT_LIST_HEAD(&isa_adapter.clients);
-
-	isa_adapter.nr = ANY_I2C_ISA_BUS;
-	isa_adapter.dev.parent = &platform_bus;
-	sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr);
-	isa_adapter.dev.release = &i2c_adapter_dev_release;
-	isa_adapter.dev.class = &i2c_adapter_class;
-	err = device_register(&isa_adapter.dev);
-	if (err) {
-		printk(KERN_ERR "i2c-isa: Failed to register device\n");
-		goto exit;
-	}
-
-	dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name);
-
-	return 0;
-
-exit:
-	return err;
-}
-
-static void __exit i2c_isa_exit(void)
-{
-#ifdef DEBUG
-	struct list_head  *item, *_n;
-	struct i2c_client *client = NULL;
-#endif
-
-	/* There should be no more active client */
-#ifdef DEBUG
-	dev_dbg(&isa_adapter.dev, "Looking for clients\n");
-	list_for_each_safe(item, _n, &isa_adapter.clients) {
-		client = list_entry(item, struct i2c_client, list);
-		dev_err(&isa_adapter.dev, "Driver %s still has an active "
-			"ISA client at 0x%x\n", client->driver->driver.name,
-			client->addr);
-	}
-	if (client != NULL)
-		return;
-#endif
-
-	/* Clean up the sysfs representation */
-	dev_dbg(&isa_adapter.dev, "Unregistering from sysfs\n");
-	init_completion(&isa_adapter.dev_released);
-	device_unregister(&isa_adapter.dev);
-
-	/* Wait for sysfs to drop all references */
-	dev_dbg(&isa_adapter.dev, "Waiting for sysfs completion\n");
-	wait_for_completion(&isa_adapter.dev_released);
-
-	dev_dbg(&isa_adapter.dev, "%s unregistered\n", isa_adapter.name);
-}
-
-EXPORT_SYMBOL(i2c_isa_add_driver);
-EXPORT_SYMBOL(i2c_isa_del_driver);
-
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
-MODULE_DESCRIPTION("ISA bus access through i2c");
-MODULE_LICENSE("GPL");
-
-module_init(i2c_isa_init);
-module_exit(i2c_isa_exit);
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 851c3ed..d8de4ac 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -105,6 +105,7 @@
 			schedule();
 			if (time_after(jiffies, orig_jiffies + timeout)) {
 				pr_debug("I2C: timeout\n");
+				writeccr(i2c, 0);
 				result = -EIO;
 				break;
 			}
@@ -116,10 +117,12 @@
 		result = wait_event_interruptible_timeout(i2c->queue,
 			(i2c->interrupt & CSR_MIF), timeout * HZ);
 
-		if (unlikely(result < 0))
+		if (unlikely(result < 0)) {
 			pr_debug("I2C: wait interrupted\n");
-		else if (unlikely(!(i2c->interrupt & CSR_MIF))) {
+			writeccr(i2c, 0);
+		} else if (unlikely(!(i2c->interrupt & CSR_MIF))) {
 			pr_debug("I2C: wait timeout\n");
+			writeccr(i2c, 0);
 			result = -ETIMEDOUT;
 		}
 
@@ -172,7 +175,6 @@
 static void mpc_i2c_stop(struct mpc_i2c *i2c)
 {
 	writeccr(i2c, CCR_MEN);
-	writeccr(i2c, 0);
 }
 
 static int mpc_write(struct mpc_i2c *i2c, int target,
@@ -261,6 +263,7 @@
 	while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
 		if (signal_pending(current)) {
 			pr_debug("I2C: Interrupted\n");
+			writeccr(i2c, 0);
 			return -EINTR;
 		}
 		if (time_after(jiffies, orig_jiffies + HZ)) {
@@ -362,7 +365,7 @@
 
       fail_add:
 	if (i2c->irq != 0)
-		free_irq(i2c->irq, NULL);
+		free_irq(i2c->irq, i2c);
       fail_irq:
 	iounmap(i2c->base);
       fail_map:
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 251154a..bb7bf68 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -107,6 +107,21 @@
  *
  *****************************************************************************
  */
+
+/* Reset hardware and initialize FSM */
+static void
+mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
+{
+	writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET);
+	writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)),
+		drv_data->reg_base + MV64XXX_I2C_REG_BAUD);
+	writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR);
+	writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
+	writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
+		drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
+	drv_data->state = MV64XXX_I2C_STATE_IDLE;
+}
+
 static void
 mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
 {
@@ -203,7 +218,7 @@
 			 drv_data->state, status, drv_data->msg->addr,
 			 drv_data->msg->flags);
 		drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
-		drv_data->state = MV64XXX_I2C_STATE_IDLE;
+		mv64xxx_i2c_hw_init(drv_data);
 		drv_data->rc = -EIO;
 	}
 }
@@ -367,6 +382,7 @@
 				"mv64xxx: I2C bus locked, block: %d, "
 				"time_left: %d\n", drv_data->block,
 				(int)time_left);
+			mv64xxx_i2c_hw_init(drv_data);
 		}
 	} else
 		spin_unlock_irqrestore(&drv_data->lock, flags);
@@ -443,19 +459,6 @@
  *
  *****************************************************************************
  */
-static void __devinit
-mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
-{
-	writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET);
-	writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)),
-		drv_data->reg_base + MV64XXX_I2C_REG_BAUD);
-	writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR);
-	writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR);
-	writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP,
-		drv_data->reg_base + MV64XXX_I2C_REG_CONTROL);
-	drv_data->state = MV64XXX_I2C_STATE_IDLE;
-}
-
 static int __devinit
 mv64xxx_i2c_map_regs(struct platform_device *pd,
 	struct mv64xxx_i2c_data *drv_data)
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index debc76c..167e413 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -23,7 +23,7 @@
    Supports:
 	Intel PIIX4, 440MX
 	Serverworks OSB4, CSB5, CSB6, HT-1000
-	ATI IXP200, IXP300, IXP400, SB600, SB700
+	ATI IXP200, IXP300, IXP400, SB600, SB700, SB800
 	SMSC Victory66
 
    Note: we assume there can only be one device, with one SMBus interface.
@@ -397,9 +397,7 @@
 	  .driver_data = 0 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SMBUS),
 	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SMBUS),
-	  .driver_data = 0 },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_SMBUS),
+	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS),
 	  .driver_data = 0 },
 	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4),
 	  .driver_data = 0 },
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 9d6b790..bb5466b27 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -926,7 +926,7 @@
 	 * The reason to do so is to avoid sysfs names that only make
 	 * sense when there are multiple adapters.
 	 */
-	i2c->adap.nr = dev->id >= 0 ? dev->id : 0;
+	i2c->adap.nr = dev->id != -1 ? dev->id : 0;
 
 	ret = i2c_add_numbered_adapter(&i2c->adap);
 	if (ret < 0) {
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index e4540fc..c44ada5 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -39,8 +39,8 @@
 #include <asm/io.h>
 
 #include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-iic.h>
-#include <asm/arch/iic.h>
+#include <asm/plat-s3c/regs-iic.h>
+#include <asm/plat-s3c/iic.h>
 
 /* i2c controller state */
 
diff --git a/drivers/i2c/chips/ds1682.c b/drivers/i2c/chips/ds1682.c
index 5879f0f..9e94542 100644
--- a/drivers/i2c/chips/ds1682.c
+++ b/drivers/i2c/chips/ds1682.c
@@ -75,7 +75,8 @@
 	/* Special case: the 32 bit regs are time values with 1/4s
 	 * resolution, scale them up to milliseconds */
 	if (sattr->nr == 4)
-		return sprintf(buf, "%llu\n", ((u64) le32_to_cpu(val)) * 250);
+		return sprintf(buf, "%llu\n",
+			((unsigned long long)le32_to_cpu(val)) * 250);
 
 	/* Format the output string and return # of bytes */
 	return sprintf(buf, "%li\n", (long)le32_to_cpu(val));
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
index 9fafadb..fe04e46 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -18,8 +18,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-#undef	DEBUG
-#undef	VERBOSE
 
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -44,7 +42,7 @@
 
 
 #define	DRIVER_VERSION	"24 August 2004"
-#define	DRIVER_NAME	(isp1301_driver.name)
+#define	DRIVER_NAME	(isp1301_driver.driver.name)
 
 MODULE_DESCRIPTION("ISP1301 USB OTG Transceiver Driver");
 MODULE_LICENSE("GPL");
@@ -55,6 +53,7 @@
 	void			(*i2c_release)(struct device *dev);
 
 	int			irq;
+	int			irq_type;
 
 	u32			last_otg_ctrl;
 	unsigned		working:1;
@@ -63,7 +62,7 @@
 
 	/* use keventd context to change the state for us */
 	struct work_struct	work;
-	
+
 	unsigned long		todo;
 #		define WORK_UPDATE_ISP	0	/* update ISP from OTG */
 #		define WORK_UPDATE_OTG	1	/* update OTG from ISP */
@@ -94,7 +93,7 @@
 
 /* board-specific PM hooks */
 
-#include <asm/arch/gpio.h>
+#include <asm/gpio.h>
 #include <asm/arch/mux.h>
 #include <asm/mach-types.h>
 
@@ -291,7 +290,7 @@
 {
 	// isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
 	isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND_REG);
-	
+
 	/* do this only when cpu is driving transceiver,
 	 * so host won't see a low speed device...
 	 */
@@ -799,7 +798,7 @@
 		/* role is host */
 		} else {
 			if (!(otg_ctrl & OTG_ID)) {
-		 		otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
+				otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
 				OTG_CTRL_REG = otg_ctrl | OTG_A_BUSREQ;
 			}
 
@@ -1100,9 +1099,9 @@
 }
 
 static void
-isp1301_work(void *data)
+isp1301_work(struct work_struct *work)
 {
-	struct isp1301	*isp = data;
+	struct isp1301	*isp = container_of(work, struct isp1301, work);
 	int		stop;
 
 	/* implicit lock:  we're the only task using this device */
@@ -1244,7 +1243,7 @@
  *  - DEVICE mode, for when there's a B/Mini-B (device) connector
  *
  * As a rule, you won't have an isp1301 chip unless it's there to
- * support the OTG mode.  Other modes help testing USB controllers 
+ * support the OTG mode.  Other modes help testing USB controllers
  * in isolation from (full) OTG support, or maybe so later board
  * revisions can help to support those feature.
  */
@@ -1260,9 +1259,9 @@
 	 * a few more interrupts than are strictly needed.
 	 */
 	isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
-	 	INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
+		INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
 	isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
-	 	INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
+		INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
 
 	dev_info(&isp->client.dev, "ready for dual-role USB ...\n");
 
@@ -1306,9 +1305,9 @@
 
 	dev_info(&isp->client.dev, "A-Host sessions ok\n");
 	isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
-	 	INTR_ID_GND);
+		INTR_ID_GND);
 	isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
-	 	INTR_ID_GND);
+		INTR_ID_GND);
 
 	/* If this has a Mini-AB connector, this mode is highly
 	 * nonstandard ... but can be handy for testing, especially with
@@ -1368,9 +1367,9 @@
 		isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
 
 	isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
-	 	INTR_SESS_VLD);
+		INTR_SESS_VLD);
 	isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
-	 	INTR_VBUS_VLD);
+		INTR_VBUS_VLD);
 	dev_info(&isp->client.dev, "B-Peripheral sessions ok\n");
 	dump_regs(isp, __FUNCTION__);
 
@@ -1494,7 +1493,7 @@
 	if (!isp)
 		return 0;
 
-	INIT_WORK(&isp->work, isp1301_work, isp);
+	INIT_WORK(&isp->work, isp1301_work);
 	init_timer(&isp->timer);
 	isp->timer.function = isp1301_timer;
 	isp->timer.data = (unsigned long) isp;
@@ -1572,13 +1571,14 @@
 		/* IRQ wired at M14 */
 		omap_cfg_reg(M14_1510_GPIO2);
 		isp->irq = OMAP_GPIO_IRQ(2);
-		omap_request_gpio(2);
-		omap_set_gpio_direction(2, 1);
-		omap_set_gpio_edge_ctrl(2, OMAP_GPIO_FALLING_EDGE);
+		if (gpio_request(2, "isp1301") == 0)
+			gpio_direction_input(2);
+		isp->irq_type = IRQF_TRIGGER_FALLING;
 	}
 
+	isp->irq_type |= IRQF_SAMPLE_RANDOM;
 	status = request_irq(isp->irq, isp1301_irq,
-			IRQF_SAMPLE_RANDOM, DRIVER_NAME, isp);
+			isp->irq_type, DRIVER_NAME, isp);
 	if (status < 0) {
 		dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
 				isp->irq, status);
diff --git a/drivers/i2c/chips/menelaus.c b/drivers/i2c/chips/menelaus.c
index 48a7e2f..d9c92c5 100644
--- a/drivers/i2c/chips/menelaus.c
+++ b/drivers/i2c/chips/menelaus.c
@@ -1,4 +1,3 @@
-#define DEBUG
 /*
  * Copyright (C) 2004 Texas Instruments, Inc.
  *
@@ -933,7 +932,7 @@
 		return status;
 	status = menelaus_write_reg(MENELAUS_RTC_WKDAY, BIN2BCD(t->tm_wday));
 	if (status < 0) {
-		dev_err(&the_menelaus->client->dev, "rtc write reg %02x",
+		dev_err(&the_menelaus->client->dev, "rtc write reg %02x "
 				"err %d\n", MENELAUS_RTC_WKDAY, status);
 		return status;
 	}
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index 3c3f2eb..503ffec 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -352,7 +352,7 @@
 			/* REVISIT:  this might need its own workqueue
 			 * plus tweaks including deadlock avoidance ...
 			 * also needs to get error handling and probably
-			 * an #ifdef CONFIG_SOFTWARE_SUSPEND
+			 * an #ifdef CONFIG_HIBERNATION
 			 */
 			hibernate();
 #endif
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 6971a62..910a62d 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -67,20 +67,16 @@
 #ifdef	CONFIG_HOTPLUG
 
 /* uevent helps with hotplug: modprobe -q $(MODALIAS) */
-static int i2c_device_uevent(struct device *dev, char **envp, int num_envp,
-		      char *buffer, int buffer_size)
+static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct i2c_client	*client = to_i2c_client(dev);
-	int			i = 0, length = 0;
 
 	/* by definition, legacy drivers can't hotplug */
 	if (dev->driver || !client->driver_name)
 		return 0;
 
-	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-			"MODALIAS=%s", client->driver_name))
+	if (add_uevent_var(env, "MODALIAS=%s", client->driver_name))
 		return -ENOMEM;
-	envp[i] = NULL;
 	dev_dbg(dev, "uevent\n");
 	return 0;
 }
@@ -288,7 +284,6 @@
 	struct i2c_adapter *adap = to_i2c_adapter(dev);
 	complete(&adap->dev_released);
 }
-EXPORT_SYMBOL_GPL(i2c_adapter_dev_release);	/* exported to i2c-isa */
 
 static ssize_t
 show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf)
@@ -307,7 +302,6 @@
 	.name			= "i2c-adapter",
 	.dev_attrs		= i2c_adapter_attrs,
 };
-EXPORT_SYMBOL_GPL(i2c_adapter_class);		/* exported to i2c-isa */
 
 static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
 {
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index b1a9b81..aa0e0c9 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -304,9 +304,17 @@
 
 config IDE_GENERIC
 	tristate "generic/default IDE chipset support"
-	default y
+	default H8300
 	help
-	  If unsure, say Y.
+	  If unsure, say N.
+
+config BLK_DEV_PLATFORM
+	tristate "Platform driver for IDE interfaces"
+	help
+	  This is the platform IDE driver, used mostly for Memory Mapped
+	  IDE devices, like Compact Flashes running in True IDE mode.
+
+	  If unsure, say N.
 
 config BLK_DEV_CMD640
 	bool "CMD640 chipset bugfix/support"
@@ -345,22 +353,22 @@
 config BLK_DEV_IDEPNP
 	bool "PNP EIDE support"
 	depends on PNP
+	select IDE_GENERIC
 	help
 	  If you have a PnP (Plug and Play) compatible EIDE card and
 	  would like the kernel to automatically detect and activate
 	  it, say Y here.
 
+if PCI
+
+comment "PCI IDE chipsets support"
+
 config BLK_DEV_IDEPCI
-	bool "PCI IDE chipset support" if PCI
-	default BLK_DEV_IDEDMA_PMAC if PPC_PMAC && BLK_DEV_IDEDMA_PMAC
-	help
-	  Say Y here for PCI systems which use IDE drive(s).
-	  This option helps the IDE driver to automatically detect and
-	  configure all PCI-based IDE interfaces in your system.
+	bool
 
 config IDEPCI_SHARE_IRQ
 	bool "Sharing PCI IDE interrupts support"
-	depends on PCI && BLK_DEV_IDEPCI
+	depends on BLK_DEV_IDEPCI
 	help
 	  Some ATA/IDE chipsets have hardware support which allows for
 	  sharing a single IRQ with other cards. To enable support for
@@ -370,11 +378,11 @@
 	  If unsure, say N.
 
 config IDEPCI_PCIBUS_ORDER
-	def_bool PCI && BLK_DEV_IDE=y && BLK_DEV_IDEPCI
+	def_bool BLK_DEV_IDE=y && BLK_DEV_IDEPCI
 
 config BLK_DEV_OFFBOARD
 	bool "Boot off-board chipsets first support"
-	depends on PCI && BLK_DEV_IDEPCI
+	depends on BLK_DEV_IDEPCI
 	help
 	  Normally, IDE controllers built into the motherboard (on-board
 	  controllers) are assigned to ide0 and ide1 while those on add-in PCI
@@ -397,21 +405,23 @@
 
 config BLK_DEV_GENERIC
 	tristate "Generic PCI IDE Chipset Support"
-	depends on BLK_DEV_IDEPCI
+	select BLK_DEV_IDEPCI
         help
           This option provides generic support for various PCI IDE Chipsets
           which otherwise might not be supported.
 
 config BLK_DEV_OPTI621
 	tristate "OPTi 82C621 chipset enhanced support (EXPERIMENTAL)"
-	depends on PCI && BLK_DEV_IDEPCI && EXPERIMENTAL
+	depends on EXPERIMENTAL
+	select BLK_DEV_IDEPCI
 	help
 	  This is a driver for the OPTi 82C621 EIDE controller.
 	  Please read the comments at the top of <file:drivers/ide/pci/opti621.c>.
 
 config BLK_DEV_RZ1000
 	tristate "RZ1000 chipset bugfix/support"
-	depends on PCI && BLK_DEV_IDEPCI && X86
+	depends on X86
+	select BLK_DEV_IDEPCI
 	help
 	  The PC-Technologies RZ1000 IDE chip is used on many common 486 and
 	  Pentium motherboards, usually along with the "Neptune" chipset.
@@ -422,35 +432,21 @@
 	  things will operate 100% reliably.
 
 config BLK_DEV_IDEDMA_PCI
-	bool "Generic PCI bus-master DMA support"
-	depends on PCI && BLK_DEV_IDEPCI
-	---help---
-	  If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and
-	  is capable of bus-master DMA operation (most Pentium PCI systems),
-	  you will want to say Y here to reduce CPU overhead. You can then use
-	  the "hdparm" utility to enable DMA for drives for which it was not
-	  enabled automatically. By default, DMA is not enabled automatically
-	  for these drives, but you can change that by saying Y to the
-	  following question "Use DMA by default when available". You can get
-	  the latest version of the hdparm utility from
-	  <ftp://ibiblio.org/pub/Linux/system/hardware/>.
-
-	  Read the comments at the beginning of <file:drivers/ide/ide-dma.c>
-	  and the file <file:Documentation/ide.txt> for more information.
-
-	  It is safe to say Y to this question.
-
-if BLK_DEV_IDEDMA_PCI
+	bool
+	select BLK_DEV_IDEPCI
 
 config BLK_DEV_IDEDMA_FORCED
 	bool "Force enable legacy 2.0.X HOSTS to use DMA"
+	depends on BLK_DEV_IDEDMA_PCI
 	help
 	  This is an old piece of lost code from Linux 2.0 Kernels.
 
 	  Generally say N here.
 
+# TODO: remove it
 config IDEDMA_ONLYDISK
 	bool "Enable DMA only for disks "
+	depends on BLK_DEV_IDEDMA_PCI
 	help
 	  This is used if you know your ATAPI Devices are going to fail DMA
 	  Transfers.
@@ -459,6 +455,7 @@
 
 config BLK_DEV_AEC62XX
 	tristate "AEC62XX chipset support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver adds explicit support for Acard AEC62xx (Artop ATP8xx)
 	  IDE controllers. This allows the kernel to change PIO, DMA and UDMA
@@ -466,6 +463,7 @@
 
 config BLK_DEV_ALI15X3
 	tristate "ALI M15x3 chipset support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C
 	  onboard chipsets.  It also tests for Simplex mode and enables
@@ -494,6 +492,7 @@
 
 config BLK_DEV_AMD74XX
 	tristate "AMD and nVidia IDE support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver adds explicit support for AMD-7xx and AMD-8111 chips
 	  and also for the nVidia nForce chip.  This allows the kernel to
@@ -503,6 +502,7 @@
 config BLK_DEV_ATIIXP
 	tristate "ATI IXP chipset IDE support"
 	depends on X86
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver adds explicit support for ATI IXP chipset.
 	  This allows the kernel to change PIO, DMA and UDMA speeds
@@ -512,18 +512,21 @@
 
 config BLK_DEV_CMD64X
 	tristate "CMD64{3|6|8|9} chipset support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  Say Y here if you have an IDE controller which uses any of these
 	  chipsets: CMD643, CMD646, or CMD648.
 
 config BLK_DEV_TRIFLEX
 	tristate "Compaq Triflex IDE support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  Say Y here if you have a Compaq Triflex IDE controller, such
 	  as those commonly found on Compaq Pentium-Pro systems
 
 config BLK_DEV_CY82C693
 	tristate "CY82C693 chipset support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver adds detection and support for the CY82C693 chipset
 	  used on Digital's PC-Alpha 164SX boards.
@@ -534,6 +537,7 @@
 config BLK_DEV_CS5520
 	tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)"
 	depends on EXPERIMENTAL
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  Include support for PIO tuning and virtual DMA on the Cyrix MediaGX
 	  5510/5520 chipset. This will automatically be detected and
@@ -543,6 +547,7 @@
 
 config BLK_DEV_CS5530
 	tristate "Cyrix/National Semiconductor CS5530 MediaGX chipset support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  Include support for UDMA on the Cyrix MediaGX 5530 chipset. This
 	  will automatically be detected and configured if found.
@@ -552,6 +557,7 @@
 config BLK_DEV_CS5535
 	tristate "AMD CS5535 chipset support"
 	depends on X86 && !X86_64
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  Include support for UDMA on the NSC/AMD CS5535 companion chipset.
 	  This will automatically be detected and configured if found.
@@ -560,6 +566,7 @@
 
 config BLK_DEV_HPT34X
 	tristate "HPT34X chipset support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver adds up to 4 more EIDE devices sharing a single
 	  interrupt. The HPT343 chipset in its current form is a non-bootable
@@ -580,7 +587,8 @@
 
 config BLK_DEV_HPT366
 	tristate "HPT36X/37X chipset support"
-	---help---
+	select BLK_DEV_IDEDMA_PCI
+	help
 	  HPT366 is an Ultra DMA chipset for ATA-66.
 	  HPT368 is an Ultra DMA chipset for ATA-66 RAID Based.
 	  HPT370 is an Ultra DMA chipset for ATA-100.
@@ -604,18 +612,21 @@
 
 config BLK_DEV_JMICRON
 	tristate "JMicron JMB36x support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  Basic support for the JMicron ATA controllers. For full support
 	  use the libata drivers.
 
 config BLK_DEV_SC1200
 	tristate "National SCx200 chipset support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver adds support for the built in IDE on the National
 	  SCx200 series of embedded x86 "Geode" systems
 
 config BLK_DEV_PIIX
 	tristate "Intel PIIXn chipsets support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver adds explicit support for Intel PIIX and ICH chips
 	  and also for the Efar Victory66 (slc90e66) chip.  This allows
@@ -624,17 +635,20 @@
 
 config BLK_DEV_IT8213
 	tristate "IT8213 IDE support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	 This driver adds support for the ITE 8213 IDE controller.
 
 config BLK_DEV_IT821X
 	tristate "IT821X IDE support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver adds support for the ITE 8211 IDE controller and the
 	  IT 8212 IDE RAID controller in both RAID and pass-through mode.
 
 config BLK_DEV_NS87415
 	tristate "NS87415 chipset support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver adds detection and support for the NS87415 chip
 	  (used mainly on SPARC64 and PA-RISC machines).
@@ -643,6 +657,7 @@
 
 config BLK_DEV_PDC202XX_OLD
 	tristate "PROMISE PDC202{46|62|65|67} support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  Promise Ultra33 or PDC20246
 	  Promise Ultra66 or PDC20262
@@ -684,9 +699,11 @@
 
 config BLK_DEV_PDC202XX_NEW
 	tristate "PROMISE PDC202{68|69|70|71|75|76|77} support"
+	select BLK_DEV_IDEDMA_PCI
 
 config BLK_DEV_SVWKS
 	tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5
 	  chipsets.
@@ -695,6 +712,7 @@
 	tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support"
 	depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4
 	select IDEPCI_SHARE_IRQ
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4
 	  chipset, which has one channel and can support two devices.
@@ -702,6 +720,7 @@
 
 config BLK_DEV_SIIMAGE
 	tristate "Silicon Image chipset support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver adds PIO/(U)DMA support for the SI CMD680 and SII
 	  3112 (Serial ATA) chips.
@@ -709,7 +728,8 @@
 config BLK_DEV_SIS5513
 	tristate "SiS5513 chipset support"
 	depends on X86
-	---help---
+	select BLK_DEV_IDEDMA_PCI
+	help
 	  This driver ensures (U)DMA support for SIS5513 chipset family based
 	  mainboards.
 
@@ -728,6 +748,7 @@
 config BLK_DEV_SL82C105
 	tristate "Winbond SL82c105 support"
 	depends on (PPC || ARM)
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  If you have a Winbond SL82c105 IDE controller, say Y here to enable
 	  special configuration for this chip. This is common on various CHRP
@@ -735,6 +756,7 @@
 
 config BLK_DEV_SLC90E66
 	tristate "SLC90E66 chipset support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver ensures (U)DMA support for Victory66 SouthBridges for
 	  SMsC with Intel NorthBridges.  This is an Ultra66 based chipset.
@@ -750,6 +772,7 @@
 
 config BLK_DEV_TRM290
 	tristate "Tekram TRM290 chipset support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver adds support for bus master DMA transfers
 	  using the Tekram TRM290 PCI IDE chip. Volunteers are
@@ -758,6 +781,7 @@
 
 config BLK_DEV_VIA82CXXX
 	tristate "VIA82CXXX chipset support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver adds explicit support for VIA BusMastering IDE chips.
 	  This allows the kernel to change PIO, DMA and UDMA speeds and to
@@ -765,12 +789,14 @@
 
 config BLK_DEV_TC86C001
 	tristate "Toshiba TC86C001 support"
+	select BLK_DEV_IDEDMA_PCI
 	help
 	This driver adds support for Toshiba TC86C001 GOKU-S chip.
 
 config BLK_DEV_CELLEB
 	tristate "Toshiba's Cell Reference Set IDE support"
 	depends on PPC_CELLEB
+	select BLK_DEV_IDEDMA_PCI
 	help
 	  This driver provides support for the built-in IDE controller on
 	  Toshiba Cell Reference Board.
@@ -780,7 +806,7 @@
 
 config BLK_DEV_IDE_PMAC
 	bool "Builtin PowerMac IDE support"
-	depends on PPC_PMAC && IDE=y
+	depends on PPC_PMAC && IDE=y && BLK_DEV_IDE=y
 	help
 	  This driver provides support for the built-in IDE controller on
 	  most of the recent Apple Power Macintoshes and PowerBooks.
@@ -833,7 +859,8 @@
        depends on BLK_DEV_IDE_AU1XXX
 
 config IDE_ARM
-	def_bool ARM && (ARCH_A5K || ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
+	def_bool ARM && (ARCH_CLPS7500 || ARCH_RPC || ARCH_SHARK)
+	select IDE_GENERIC
 
 config BLK_DEV_IDE_ICSIDE
 	tristate "ICS IDE interface support"
@@ -867,6 +894,7 @@
 config BLK_DEV_GAYLE
 	bool "Amiga Gayle IDE interface support"
 	depends on AMIGA
+	select IDE_GENERIC
 	help
 	  This is the IDE driver for the Amiga Gayle IDE interface. It supports
 	  both the `A1200 style' and `A4000 style' of the Gayle IDE interface,
@@ -898,6 +926,7 @@
 config BLK_DEV_BUDDHA
 	bool "Buddha/Catweasel/X-Surf IDE interface support (EXPERIMENTAL)"
 	depends on ZORRO && EXPERIMENTAL
+	select IDE_GENERIC
 	help
 	  This is the IDE driver for the IDE interfaces on the Buddha, 
 	  Catweasel and X-Surf expansion boards.  It supports up to two interfaces 
@@ -910,6 +939,7 @@
 config BLK_DEV_FALCON_IDE
 	bool "Falcon IDE interface support"
 	depends on ATARI
+	select IDE_GENERIC
 	help
 	  This is the IDE driver for the builtin IDE interface on the Atari
 	  Falcon. Say Y if you have a Falcon and want to use IDE devices (hard
@@ -919,6 +949,7 @@
 config BLK_DEV_MAC_IDE
 	bool "Macintosh Quadra/Powerbook IDE interface support"
 	depends on MAC
+	select IDE_GENERIC
 	help
 	  This is the IDE driver for the builtin IDE interface on some m68k
 	  Macintosh models. It supports both the `Quadra style' (used in
@@ -932,6 +963,7 @@
 config BLK_DEV_Q40IDE
 	bool "Q40/Q60 IDE interface support"
 	depends on Q40
+	select IDE_GENERIC
 	help
 	  Enable the on-board IDE controller in the Q40/Q60.  This should
 	  normally be on; disable it only if you are running a custom hard
@@ -939,7 +971,8 @@
 
 config BLK_DEV_MPC8xx_IDE
 	bool "MPC8xx IDE support"
-	depends on 8xx && IDE=y && BLK_DEV_IDE=y
+	depends on 8xx && IDE=y && BLK_DEV_IDE=y && !PPC_MERGE
+	select IDE_GENERIC
 	help
 	  This option provides support for IDE on Motorola MPC8xx Systems.
 	  Please see 'Type of MPC8xx IDE interface' for details.
@@ -977,24 +1010,9 @@
 endchoice
 
 # no isa -> no vlb
-config IDE_CHIPSETS
-	bool "Other IDE chipset support"
-	depends on ISA
-	---help---
-	  Say Y here if you want to include enhanced support for various IDE
-	  interface chipsets used on motherboards and add-on cards. You can
-	  then pick your particular IDE chip from among the following options.
-	  This enhanced support may be necessary for Linux to be able to
-	  access the 3rd/4th drives in some systems. It may also enable
-	  setting of higher speed I/O rates to improve system performance with
-	  these chipsets. Most of these also require special kernel boot
-	  parameters to actually turn on the support at runtime; you can find
-	  a list of these in the file <file:Documentation/ide.txt>.
+if ISA
 
-	  People with SCSI-only systems can say N here.
-
-if IDE_CHIPSETS
-
+comment "Other IDE chipsets support"
 comment "Note: most of these also require special kernel boot parameters"
 
 config BLK_DEV_4DRIVES
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
index c89b5f4..7912a47 100644
--- a/drivers/ide/arm/icside.c
+++ b/drivers/ide/arm/icside.c
@@ -248,15 +248,9 @@
  *	MW1	80	50	50	150	C
  *	MW2	70	25	25	120	C
  */
-static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode)
+static int icside_set_speed(ide_drive_t *drive, const u8 xfer_mode)
 {
-	int on = 0, cycle_time = 0, use_dma_info = 0;
-
-	/*
-	 * Limit the transfer speed to MW_DMA_2.
-	 */
-	if (xfer_mode > XFER_MW_DMA_2)
-		xfer_mode = XFER_MW_DMA_2;
+	int cycle_time, use_dma_info = 0;
 
 	switch (xfer_mode) {
 	case XFER_MW_DMA_2:
@@ -278,6 +272,8 @@
 	case XFER_SW_DMA_0:
 		cycle_time = 480;
 		break;
+	default:
+		return 1;
 	}
 
 	/*
@@ -289,17 +285,10 @@
 
 	drive->drive_data = cycle_time;
 
-	if (cycle_time && ide_config_drive_speed(drive, xfer_mode) == 0)
-		on = 1;
-	else
-		drive->drive_data = 480;
-
 	printk("%s: %s selected (peak %dMB/s)\n", drive->name,
 		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
 
-	drive->current_speed = xfer_mode;
-
-	return on;
+	return ide_config_drive_speed(drive, xfer_mode);
 }
 
 static void icside_dma_host_off(ide_drive_t *drive)
@@ -326,8 +315,7 @@
 {
 	struct hd_driveid *id = drive->id;
 	ide_hwif_t *hwif = HWIF(drive);
-	int xfer_mode = XFER_PIO_2;
-	int on;
+	int xfer_mode = 0;
 
 	if (!(id->capability & 1) || !hwif->autodma)
 		goto out;
@@ -356,9 +344,10 @@
 	}
 
 out:
-	on = icside_set_speed(drive, xfer_mode);
+	if (xfer_mode == 0)
+		return -1;
 
-	return on ? 0 : -1;
+	return icside_set_speed(drive, xfer_mode) ? -1 : 0;
 }
 
 static int icside_dma_end(ide_drive_t *drive)
@@ -693,13 +682,12 @@
 	if (ret)
 		goto out;
 
-	state = kmalloc(sizeof(struct icside_state), GFP_KERNEL);
+	state = kzalloc(sizeof(struct icside_state), GFP_KERNEL);
 	if (!state) {
 		ret = -ENOMEM;
 		goto release;
 	}
 
-	memset(state, 0, sizeof(state));
 	state->type	= ICS_TYPE_NOTYPE;
 	state->dev	= &ec->dev;
 
diff --git a/drivers/ide/arm/ide_arm.c b/drivers/ide/arm/ide_arm.c
index a3d6744..bce2bec 100644
--- a/drivers/ide/arm/ide_arm.c
+++ b/drivers/ide/arm/ide_arm.c
@@ -1,5 +1,5 @@
 /*
- * ARM/ARM26 default IDE host driver
+ * ARM default IDE host driver
  *
  * Copyright (C) 2004 Bartlomiej Zolnierkiewicz
  * Based on code by: Russell King, Ian Molton and Alexander Schulz.
@@ -14,12 +14,6 @@
 #include <asm/mach-types.h>
 #include <asm/irq.h>
 
-#ifdef CONFIG_ARM26
-# define IDE_ARM_HOST	(machine_is_a5k())
-#else
-# define IDE_ARM_HOST	(1)
-#endif
-
 #ifdef CONFIG_ARCH_CLPS7500
 # include <asm/arch/hardware.h>
 #
@@ -32,12 +26,10 @@
 
 void __init ide_arm_init(void)
 {
-	if (IDE_ARM_HOST) {
-		hw_regs_t hw;
+	hw_regs_t hw;
 
-		memset(&hw, 0, sizeof(hw));
-		ide_std_init_ports(&hw, IDE_ARM_IO, IDE_ARM_IO + 0x206);
-		hw.irq = IDE_ARM_IRQ;
-		ide_register_hw(&hw, 1, NULL);
-	}
+	memset(&hw, 0, sizeof(hw));
+	ide_std_init_ports(&hw, IDE_ARM_IO, IDE_ARM_IO + 0x206);
+	hw.irq = IDE_ARM_IRQ;
+	ide_register_hw(&hw, 1, NULL);
 }
diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
index 886091b..4bb42b3 100644
--- a/drivers/ide/cris/ide-cris.c
+++ b/drivers/ide/cris/ide-cris.c
@@ -414,12 +414,6 @@
 #ifdef CONFIG_ETRAX_IDE_G27_RESET
 	REG_SHADOW_SET(R_PORT_G_DATA, port_g_data_shadow, 27, val);
 #endif
-#ifdef CONFIG_ETRAX_IDE_CSE1_16_RESET
-	REG_SHADOW_SET(port_cse1_addr, port_cse1_shadow, 16, val);
-#endif
-#ifdef CONFIG_ETRAX_IDE_CSP0_8_RESET
-	REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, 8, val);
-#endif
 #ifdef CONFIG_ETRAX_IDE_PB7_RESET
 	port_pb_dir_shadow = port_pb_dir_shadow |
 		IO_STATE(R_PORT_PB_DIR, dir7, output);
@@ -686,7 +680,7 @@
 {
 }
 
-static void tune_cris_ide(ide_drive_t *drive, u8 pio)
+static void cris_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
 	int setup, strobe, hold;
 
@@ -722,17 +716,14 @@
 	}
 
 	cris_ide_set_speed(TYPE_PIO, setup, strobe, hold);
+
+	(void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
-static int speed_cris_ide(ide_drive_t *drive, u8 speed)
+static int speed_cris_ide(ide_drive_t *drive, const u8 speed)
 {
 	int cyc = 0, dvs = 0, strobe = 0, hold = 0;
 
-	if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
-		tune_cris_ide(drive, speed - XFER_PIO_0);
-		return ide_config_drive_speed(drive, speed);
-	}
-
 	switch(speed)
 	{
 		case XFER_UDMA_0:
@@ -799,7 +790,7 @@
 		ide_register_hw(&hw, 1, &hwif);
 		hwif->mmio = 1;
 		hwif->chipset = ide_etrax100;
-		hwif->tuneproc = &tune_cris_ide;
+		hwif->set_pio_mode = &cris_set_pio_mode;
 		hwif->speedproc = &speed_cris_ide;
 		hwif->ata_input_data = &cris_ide_input_data;
 		hwif->ata_output_data = &cris_ide_output_data;
@@ -820,6 +811,7 @@
 		hwif->dma_host_on = &cris_dma_on;
 		hwif->dma_off_quietly = &cris_dma_off;
 		hwif->cbl = ATA_CBL_PATA40;
+		hwif->pio_mask = ATA_PIO4,
 		hwif->ultra_mask = cris_ultra_mask;
 		hwif->mwdma_mask = 0x07; /* Multiword DMA 0-2 */
 		hwif->autodma = 1;
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index 17aea65..6bff81a 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -612,6 +612,46 @@
 EXPORT_SYMBOL_GPL(ide_acpi_push_timing);
 
 /**
+ * ide_acpi_set_state - set the channel power state
+ * @hwif: target IDE interface
+ * @on: state, on/off
+ *
+ * This function executes the _PS0/_PS3 ACPI method to set the power state.
+ * ACPI spec requires _PS0 when IDE power on and _PS3 when power off
+ */
+void ide_acpi_set_state(ide_hwif_t *hwif, int on)
+{
+	int unit;
+
+	if (ide_noacpi)
+		return;
+
+	DEBPRINT("ENTER:\n");
+
+	if (!hwif->acpidata) {
+		DEBPRINT("no ACPI data for %s\n", hwif->name);
+		return;
+	}
+	/* channel first and then drives for power on and verse versa for power off */
+	if (on)
+		acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0);
+	for (unit = 0; unit < MAX_DRIVES; ++unit) {
+		ide_drive_t *drive = &hwif->drives[unit];
+
+		if (!drive->acpidata->obj_handle)
+			drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
+
+		if (drive->acpidata->obj_handle && drive->present) {
+			acpi_bus_set_power(drive->acpidata->obj_handle,
+				on? ACPI_STATE_D0: ACPI_STATE_D3);
+		}
+	}
+	if (!on)
+		acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3);
+}
+EXPORT_SYMBOL_GPL(ide_acpi_set_state);
+
+/**
  * ide_acpi_init - initialize the ACPI link for an IDE interface
  * @hwif: target IDE interface (channel)
  *
@@ -679,6 +719,8 @@
 		return;
 	}
 
+	/* ACPI _PS0 before _STM */
+	ide_acpi_set_state(hwif, 1);
 	/*
 	 * ACPI requires us to call _STM on startup
 	 */
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 1486eb2..ca84352 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -3071,7 +3071,7 @@
 /*
  * standard prep_rq_fn that builds 10 byte cmds
  */
-static int ide_cdrom_prep_fs(request_queue_t *q, struct request *rq)
+static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq)
 {
 	int hard_sect = queue_hardsect_size(q);
 	long block = (long)rq->hard_sector / (hard_sect >> 9);
@@ -3137,7 +3137,7 @@
 	return BLKPREP_OK;
 }
 
-static int ide_cdrom_prep_fn(request_queue_t *q, struct request *rq)
+static int ide_cdrom_prep_fn(struct request_queue *q, struct request *rq)
 {
 	if (blk_fs_request(rq))
 		return ide_cdrom_prep_fs(q, rq);
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index b1304a7..4754769 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -481,6 +481,16 @@
 	       && id->lba_capacity_2;
 }
 
+/*
+ * Some disks report total number of sectors instead of
+ * maximum sector address.  We list them here.
+ */
+static const struct drive_list_entry hpa_list[] = {
+	{ "ST340823A",	NULL },
+	{ "ST320413A",	NULL },
+	{ NULL,		NULL }
+};
+
 static void idedisk_check_hpa(ide_drive_t *drive)
 {
 	unsigned long long capacity, set_max;
@@ -492,6 +502,15 @@
 	else
 		set_max = idedisk_read_native_max_address(drive);
 
+	if (ide_in_drive_list(drive->id, hpa_list)) {
+		/*
+		 * Since we are inclusive wrt to firmware revisions do this
+		 * extra check and apply the workaround only when needed.
+		 */
+		if (set_max == capacity + 1)
+			set_max--;
+	}
+
 	if (set_max <= capacity)
 		return;
 
@@ -679,7 +698,7 @@
 };
 #endif	/* CONFIG_IDE_PROC_FS */
 
-static void idedisk_prepare_flush(request_queue_t *q, struct request *rq)
+static void idedisk_prepare_flush(struct request_queue *q, struct request *rq)
 {
 	ide_drive_t *drive = q->queuedata;
 
@@ -697,7 +716,7 @@
 	rq->buffer = rq->cmd;
 }
 
-static int idedisk_issue_flush(request_queue_t *q, struct gendisk *disk,
+static int idedisk_issue_flush(struct request_queue *q, struct gendisk *disk,
 			       sector_t *error_sector)
 {
 	ide_drive_t *drive = q->queuedata;
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 5fe1d72..6000c08f 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -135,25 +135,6 @@
 };
 
 /**
- *	ide_in_drive_list	-	look for drive in black/white list
- *	@id: drive identifier
- *	@drive_table: list to inspect
- *
- *	Look for a drive in the blacklist and the whitelist tables
- *	Returns 1 if the drive is found in the table.
- */
-
-int ide_in_drive_list(struct hd_driveid *id, const struct drive_list_entry *drive_table)
-{
-	for ( ; drive_table->id_model ; drive_table++)
-		if ((!strcmp(drive_table->id_model, id->model)) &&
-		    (!drive_table->id_firmware ||
-		     strstr(id->fw_rev, drive_table->id_firmware)))
-			return 1;
-	return 0;
-}
-
-/**
  *	ide_dma_intr	-	IDE DMA interrupt handler
  *	@drive: the drive the interrupt is for
  *
@@ -349,9 +330,17 @@
  
 static int config_drive_for_dma (ide_drive_t *drive)
 {
+	ide_hwif_t *hwif = drive->hwif;
 	struct hd_driveid *id = drive->id;
 
-	if ((id->capability & 1) && drive->hwif->autodma) {
+	/* consult the list of known "bad" drives */
+	if (__ide_dma_bad_drive(drive))
+		return -1;
+
+	if (drive->media != ide_disk && hwif->atapi_dma == 0)
+		return -1;
+
+	if ((id->capability & 1) && drive->autodma) {
 		/*
 		 * Enable DMA on any drive that has
 		 * UltraDMA (mode 0/1/2/3/4/5/6) enabled
@@ -514,20 +503,6 @@
 EXPORT_SYMBOL(__ide_dma_on);
 
 /**
- *	__ide_dma_check		-	check DMA setup
- *	@drive: drive to check
- *
- *	Don't use - due for extermination
- */
- 
-int __ide_dma_check (ide_drive_t *drive)
-{
-	return config_drive_for_dma(drive);
-}
-
-EXPORT_SYMBOL(__ide_dma_check);
-
-/**
  *	ide_dma_setup	-	begin a DMA phase
  *	@drive: target device
  *
@@ -678,7 +653,7 @@
 	XFER_SW_DMA_0,
 };
 
-static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base)
+static unsigned int ide_get_mode_mask(ide_drive_t *drive, u8 base, u8 req_mode)
 {
 	struct hd_driveid *id = drive->id;
 	ide_hwif_t *hwif = drive->hwif;
@@ -689,17 +664,28 @@
 		if ((id->field_valid & 4) == 0)
 			break;
 
-		mask = id->dma_ultra & hwif->ultra_mask;
-
 		if (hwif->udma_filter)
-			mask &= hwif->udma_filter(drive);
+			mask = hwif->udma_filter(drive);
+		else
+			mask = hwif->ultra_mask;
+		mask &= id->dma_ultra;
 
-		if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
-			mask &= 0x07;
+		/*
+		 * avoid false cable warning from eighty_ninty_three()
+		 */
+		if (req_mode > XFER_UDMA_2) {
+			if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
+				mask &= 0x07;
+		}
 		break;
 	case XFER_MW_DMA_0:
-		if (id->field_valid & 2)
-			mask = id->dma_mword & hwif->mwdma_mask;
+		if ((id->field_valid & 2) == 0)
+			break;
+		if (hwif->mdma_filter)
+			mask = hwif->mdma_filter(drive);
+		else
+			mask = hwif->mwdma_mask;
+		mask &= id->dma_mword;
 		break;
 	case XFER_SW_DMA_0:
 		if (id->field_valid & 2) {
@@ -728,15 +714,18 @@
 }
 
 /**
- *	ide_max_dma_mode	-	compute DMA speed
+ *	ide_find_dma_mode	-	compute DMA speed
  *	@drive: IDE device
+ *	@req_mode: requested mode
  *
- *	Checks the drive capabilities and returns the speed to use
- *	for the DMA transfer.  Returns 0 if the drive is incapable
- *	of DMA transfers.
+ *	Checks the drive/host capabilities and finds the speed to use for
+ *	the DMA transfer.  The speed is then limited by the requested mode.
+ *
+ *	Returns 0 if the drive/host combination is incapable of DMA transfers
+ *	or if the requested mode is not a DMA mode.
  */
 
-u8 ide_max_dma_mode(ide_drive_t *drive)
+u8 ide_find_dma_mode(ide_drive_t *drive, u8 req_mode)
 {
 	ide_hwif_t *hwif = drive->hwif;
 	unsigned int mask;
@@ -747,7 +736,9 @@
 		return 0;
 
 	for (i = 0; i < ARRAY_SIZE(xfer_mode_bases); i++) {
-		mask = ide_get_mode_mask(drive, xfer_mode_bases[i]);
+		if (req_mode < xfer_mode_bases[i])
+			continue;
+		mask = ide_get_mode_mask(drive, xfer_mode_bases[i], req_mode);
 		x = fls(mask) - 1;
 		if (x >= 0) {
 			mode = xfer_mode_bases[i] + x;
@@ -757,10 +748,10 @@
 
 	printk(KERN_DEBUG "%s: selected mode 0x%x\n", drive->name, mode);
 
-	return mode;
+	return min(mode, req_mode);
 }
 
-EXPORT_SYMBOL_GPL(ide_max_dma_mode);
+EXPORT_SYMBOL_GPL(ide_find_dma_mode);
 
 int ide_tune_dma(ide_drive_t *drive)
 {
@@ -1021,7 +1012,7 @@
 	if (!hwif->dma_host_on)
 		hwif->dma_host_on = &ide_dma_host_on;
 	if (!hwif->ide_dma_check)
-		hwif->ide_dma_check = &__ide_dma_check;
+		hwif->ide_dma_check = &config_drive_for_dma;
 	if (!hwif->dma_setup)
 		hwif->dma_setup = &ide_dma_setup;
 	if (!hwif->dma_exec_cmd)
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index a21f585..04a3578 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -99,6 +99,8 @@
 #include <linux/bitops.h>
 #include <linux/mutex.h>
 
+#include <scsi/scsi_ioctl.h>
+
 #include <asm/byteorder.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
@@ -604,26 +606,24 @@
 {
 	struct request *rq = pc->rq;
 	struct bio_vec *bvec;
-	struct bio *bio;
+	struct req_iterator iter;
 	unsigned long flags;
 	char *data;
-	int count, i, done = 0;
+	int count, done = 0;
 
-	rq_for_each_bio(bio, rq) {
-		bio_for_each_segment(bvec, bio, i) {
-			if (!bcount)
-				break;
+	rq_for_each_segment(bvec, rq, iter) {
+		if (!bcount)
+			break;
 
-			count = min(bvec->bv_len, bcount);
+		count = min(bvec->bv_len, bcount);
 
-			data = bvec_kmap_irq(bvec, &flags);
-			drive->hwif->atapi_input_bytes(drive, data, count);
-			bvec_kunmap_irq(data, &flags);
+		data = bvec_kmap_irq(bvec, &flags);
+		drive->hwif->atapi_input_bytes(drive, data, count);
+		bvec_kunmap_irq(data, &flags);
 
-			bcount -= count;
-			pc->b_count += count;
-			done += count;
-		}
+		bcount -= count;
+		pc->b_count += count;
+		done += count;
 	}
 
 	idefloppy_do_end_request(drive, 1, done >> 9);
@@ -637,27 +637,25 @@
 static void idefloppy_output_buffers (ide_drive_t *drive, idefloppy_pc_t *pc, unsigned int bcount)
 {
 	struct request *rq = pc->rq;
-	struct bio *bio;
+	struct req_iterator iter;
 	struct bio_vec *bvec;
 	unsigned long flags;
-	int count, i, done = 0;
+	int count, done = 0;
 	char *data;
 
-	rq_for_each_bio(bio, rq) {
-		bio_for_each_segment(bvec, bio, i) {
-			if (!bcount)
-				break;
+	rq_for_each_segment(bvec, rq, iter) {
+		if (!bcount)
+			break;
 
-			count = min(bvec->bv_len, bcount);
+		count = min(bvec->bv_len, bcount);
 
-			data = bvec_kmap_irq(bvec, &flags);
-			drive->hwif->atapi_output_bytes(drive, data, count);
-			bvec_kunmap_irq(data, &flags);
+		data = bvec_kmap_irq(bvec, &flags);
+		drive->hwif->atapi_output_bytes(drive, data, count);
+		bvec_kunmap_irq(data, &flags);
 
-			bcount -= count;
-			pc->b_count += count;
-			done += count;
-		}
+		bcount -= count;
+		pc->b_count += count;
+		done += count;
 	}
 
 	idefloppy_do_end_request(drive, 1, done >> 9);
@@ -2099,7 +2097,21 @@
 	case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
 		return idefloppy_get_format_progress(drive, argp);
 	}
-	return generic_ide_ioctl(drive, file, bdev, cmd, arg);
+
+	/*
+	 * skip SCSI_IOCTL_SEND_COMMAND (deprecated)
+	 * and CDROM_SEND_PACKET (legacy) ioctls
+	 */
+	if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND)
+		err = scsi_cmd_ioctl(file, bdev->bd_disk->queue,
+					bdev->bd_disk, cmd, argp);
+	else
+		err = -ENOTTY;
+
+	if (err == -ENOTTY)
+		err = generic_ide_ioctl(drive, file, bdev, cmd, arg);
+
+	return err;
 }
 
 static int idefloppy_media_changed(struct gendisk *disk)
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index c5b5011..9560a8f 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -55,7 +55,7 @@
 #include <asm/bitops.h>
 
 static int __ide_end_request(ide_drive_t *drive, struct request *rq,
-			     int uptodate, int nr_sectors)
+			     int uptodate, unsigned int nr_bytes)
 {
 	int ret = 1;
 
@@ -64,7 +64,7 @@
 	 * complete the whole request right now
 	 */
 	if (blk_noretry_request(rq) && end_io_error(uptodate))
-		nr_sectors = rq->hard_nr_sectors;
+		nr_bytes = rq->hard_nr_sectors << 9;
 
 	if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors)
 		rq->errors = -EIO;
@@ -78,7 +78,7 @@
 		HWGROUP(drive)->hwif->ide_dma_on(drive);
 	}
 
-	if (!end_that_request_first(rq, uptodate, nr_sectors)) {
+	if (!end_that_request_chunk(rq, uptodate, nr_bytes)) {
 		add_disk_randomness(rq->rq_disk);
 		if (!list_empty(&rq->queuelist))
 			blkdev_dequeue_request(rq);
@@ -103,6 +103,7 @@
 
 int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors)
 {
+	unsigned int nr_bytes = nr_sectors << 9;
 	struct request *rq;
 	unsigned long flags;
 	int ret = 1;
@@ -114,10 +115,14 @@
 	spin_lock_irqsave(&ide_lock, flags);
 	rq = HWGROUP(drive)->rq;
 
-	if (!nr_sectors)
-		nr_sectors = rq->hard_cur_sectors;
+	if (!nr_bytes) {
+		if (blk_pc_request(rq))
+			nr_bytes = rq->data_len;
+		else
+			nr_bytes = rq->hard_cur_sectors << 9;
+	}
 
-	ret = __ide_end_request(drive, rq, uptodate, nr_sectors);
+	ret = __ide_end_request(drive, rq, uptodate, nr_bytes);
 
 	spin_unlock_irqrestore(&ide_lock, flags);
 	return ret;
@@ -196,8 +201,7 @@
 		return do_rw_taskfile(drive, args);
 
 	case idedisk_pm_restore_pio:	/* Resume step 1 (restore PIO) */
-		if (drive->hwif->tuneproc != NULL)
-			drive->hwif->tuneproc(drive, 255);
+		ide_set_max_pio(drive);
 		/*
 		 * skip idedisk_pm_idle for ATAPI devices
 		 */
@@ -219,11 +223,12 @@
 		 * we could be smarter and check for current xfer_speed
 		 * in struct drive etc...
 		 */
-		if ((drive->id->capability & 1) == 0)
-			break;
 		if (drive->hwif->ide_dma_check == NULL)
 			break;
 		drive->hwif->dma_off_quietly(drive);
+		/*
+		 * TODO: respect ->using_dma setting
+		 */
 		ide_set_dma(drive);
 		break;
 	}
@@ -782,6 +787,30 @@
 	return ide_started;
 }
 
+/*
+ * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away
+ */
+static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio)
+{
+	switch (req_pio) {
+	case 202:
+	case 201:
+	case 200:
+	case 102:
+	case 101:
+	case 100:
+		return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0;
+	case 9:
+	case 8:
+		return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0;
+	case 7:
+	case 6:
+		return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0;
+	default:
+		return 0;
+	}
+}
+
 /**
  *	do_special		-	issue some special commands
  *	@drive: drive the command is for
@@ -799,9 +828,17 @@
 	printk("%s: do_special: 0x%02x\n", drive->name, s->all);
 #endif
 	if (s->b.set_tune) {
+		ide_hwif_t *hwif = drive->hwif;
+		u8 req_pio = drive->tune_req;
+
 		s->b.set_tune = 0;
-		if (HWIF(drive)->tuneproc != NULL)
-			HWIF(drive)->tuneproc(drive, drive->tune_req);
+
+		if (set_pio_mode_abuse(drive->hwif, req_pio)) {
+			if (hwif->set_pio_mode)
+				hwif->set_pio_mode(drive, req_pio);
+		} else
+			ide_set_pio(drive, req_pio);
+
 		return ide_stopped;
 	} else {
 		if (drive->media == ide_disk)
@@ -1321,7 +1358,7 @@
 /*
  * Passes the stuff to ide_do_request
  */
-void do_ide_request(request_queue_t *q)
+void do_ide_request(struct request_queue *q)
 {
 	ide_drive_t *drive = q->queuedata;
 
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 92578b6..cf0678b 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -565,6 +565,36 @@
 
 EXPORT_SYMBOL(ide_wait_stat);
 
+/**
+ *	ide_in_drive_list	-	look for drive in black/white list
+ *	@id: drive identifier
+ *	@drive_table: list to inspect
+ *
+ *	Look for a drive in the blacklist and the whitelist tables
+ *	Returns 1 if the drive is found in the table.
+ */
+
+int ide_in_drive_list(struct hd_driveid *id, const struct drive_list_entry *drive_table)
+{
+	for ( ; drive_table->id_model; drive_table++)
+		if ((!strcmp(drive_table->id_model, id->model)) &&
+		    (!drive_table->id_firmware ||
+		     strstr(id->fw_rev, drive_table->id_firmware)))
+			return 1;
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(ide_in_drive_list);
+
+/*
+ * Early UDMA66 devices don't set bit14 to 1, only bit13 is valid.
+ * We list them here and depend on the device side cable detection for them.
+ */
+static const struct drive_list_entry ivb_list[] = {
+	{ "QUANTUM FIREBALLlct10 05"	, "A03.0900"	},
+	{ NULL				, NULL		}
+};
+
 /*
  *  All hosts that use the 80c ribbon must use!
  *  The name is derived from upper byte of word 93 and the 80c ribbon.
@@ -573,25 +603,29 @@
 {
 	ide_hwif_t *hwif = drive->hwif;
 	struct hd_driveid *id = drive->id;
+	int ivb = ide_in_drive_list(id, ivb_list);
 
 	if (hwif->cbl == ATA_CBL_PATA40_SHORT)
 		return 1;
 
-	if (hwif->cbl != ATA_CBL_PATA80)
+	if (ivb)
+		printk(KERN_DEBUG "%s: skipping word 93 validity check\n",
+				  drive->name);
+
+	if (hwif->cbl != ATA_CBL_PATA80 && !ivb)
 		goto no_80w;
 
-	/* Check for SATA but only if we are ATA5 or higher */
-	if (id->hw_config == 0 && (id->major_rev_num & 0x7FE0))
+	if (ide_dev_is_sata(id))
 		return 1;
 
 	/*
 	 * FIXME:
 	 * - change master/slave IDENTIFY order
-	 * - force bit13 (80c cable present) check
+	 * - force bit13 (80c cable present) check also for !ivb devices
 	 *   (unless the slave device is pre-ATA3)
 	 */
 #ifndef CONFIG_IDEDMA_IVB
-	if (id->hw_config & 0x4000)
+	if ((id->hw_config & 0x4000) || (ivb && (id->hw_config & 0x2000)))
 #else
 	if (id->hw_config & 0x6000)
 #endif
@@ -746,12 +780,6 @@
 
 /*
  * Similar to ide_wait_stat(), except it never calls ide_error internally.
- * This is a kludge to handle the new ide_config_drive_speed() function,
- * and should not otherwise be used anywhere.  Eventually, the tuneproc's
- * should be updated to return ide_startstop_t, in which case we can get
- * rid of this abomination again.  :)   -ml
- *
- * It is gone..........
  *
  * const char *msg == consider adding for verbose errors.
  */
@@ -795,7 +823,7 @@
 		hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
 	hwif->OUTB(speed, IDE_NSECTOR_REG);
 	hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);
-	hwif->OUTB(WIN_SETFEATURES, IDE_COMMAND_REG);
+	hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG);
 	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))
 		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);
 	udelay(1);
@@ -822,7 +850,7 @@
 	 */
 	for (i = 0; i < 10; i++) {
 		udelay(1);
-		if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
+		if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), drive->ready_stat, BUSY_STAT|DRQ_STAT|ERR_STAT)) {
 			error = 0;
 			break;
 		}
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index 074bb32..d97390c 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -76,41 +76,26 @@
  *	Given the available transfer modes this function returns
  *	the best available speed at or below the speed requested.
  *
- *	FIXME: filter also PIO/SWDMA/MWDMA modes
+ *	TODO: check device PIO capabilities
  */
 
-u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
+static u8 ide_rate_filter(ide_drive_t *drive, u8 speed)
 {
-#ifdef CONFIG_BLK_DEV_IDEDMA
 	ide_hwif_t *hwif = drive->hwif;
-	u8 mask = hwif->ultra_mask, mode = XFER_MW_DMA_2;
+	u8 mode = ide_find_dma_mode(drive, speed);
 
-	if (hwif->udma_filter)
-		mask = hwif->udma_filter(drive);
-
-	/*
-	 * TODO: speed > XFER_UDMA_2 extra check is needed to avoid false
-	 * cable warning from eighty_ninty_three(), moving ide_rate_filter()
-	 * calls from ->speedproc to core code will make this hack go away
-	 */
-	if (speed > XFER_UDMA_2) {
-		if ((mask & 0x78) && (eighty_ninty_three(drive) == 0))
-			mask &= 0x07;
+	if (mode == 0) {
+		if (hwif->pio_mask)
+			mode = fls(hwif->pio_mask) - 1 + XFER_PIO_0;
+		else
+			mode = XFER_PIO_4;
 	}
 
-	if (mask)
-		mode = fls(mask) - 1 + XFER_UDMA_0;
-
 //	printk("%s: mode 0x%02x, speed 0x%02x\n", __FUNCTION__, mode, speed);
 
 	return min(speed, mode);
-#else /* !CONFIG_BLK_DEV_IDEDMA */
-	return min(speed, (u8)XFER_PIO_4);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
 }
 
-EXPORT_SYMBOL(ide_rate_filter);
-
 int ide_use_fast_pio(ide_drive_t *drive)
 {
 	struct hd_driveid *id = drive->id;
@@ -249,12 +234,34 @@
 	return -1;
 }
 
+unsigned int ide_pio_cycle_time(ide_drive_t *drive, u8 pio)
+{
+	struct hd_driveid *id = drive->id;
+	int cycle_time = 0;
+
+	if (id->field_valid & 2) {
+		if (id->capability & 8)
+			cycle_time = id->eide_pio_iordy;
+		else
+			cycle_time = id->eide_pio;
+	}
+
+	/* conservative "downgrade" for all pre-ATA2 drives */
+	if (pio < 3) {
+		if (cycle_time && cycle_time < ide_pio_timings[pio].cycle_time)
+			cycle_time = 0; /* use standard timing */
+	}
+
+	return cycle_time ? cycle_time : ide_pio_timings[pio].cycle_time;
+}
+
+EXPORT_SYMBOL_GPL(ide_pio_cycle_time);
+
 /**
  *	ide_get_best_pio_mode	-	get PIO mode from drive
  *	@drive: drive to consider
  *	@mode_wanted: preferred mode
  *	@max_mode: highest allowed mode
- *	@d: PIO data
  *
  *	This routine returns the recommended PIO settings for a given drive,
  *	based on the drive->id information and the ide_pio_blacklist[].
@@ -263,22 +270,18 @@
  *	This is used by most chipset support modules when "auto-tuning".
  */
 
-u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode, ide_pio_data_t *d)
+u8 ide_get_best_pio_mode (ide_drive_t *drive, u8 mode_wanted, u8 max_mode)
 {
 	int pio_mode;
-	int cycle_time = 0;
-	int use_iordy = 0;
 	struct hd_driveid* id = drive->id;
 	int overridden  = 0;
 
-	if (mode_wanted != 255) {
-		pio_mode = mode_wanted;
-		use_iordy = (pio_mode > 2);
-	} else if (!drive->id) {
-		pio_mode = 0;
-	} else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
-		overridden = 1;
-		use_iordy = (pio_mode > 2);
+	if (mode_wanted != 255)
+		return min_t(u8, mode_wanted, max_mode);
+
+	if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_BLACKLIST) == 0 &&
+	    (pio_mode = ide_scan_pio_blacklist(id->model)) != -1) {
+		printk(KERN_INFO "%s: is on PIO blacklist\n", drive->name);
 	} else {
 		pio_mode = id->tPIO;
 		if (pio_mode > 2) {	/* 2 is maximum allowed tPIO value */
@@ -286,9 +289,7 @@
 			overridden = 1;
 		}
 		if (id->field_valid & 2) {	  /* drive implements ATA2? */
-			if (id->capability & 8) { /* drive supports use_iordy? */
-				use_iordy = 1;
-				cycle_time = id->eide_pio_iordy;
+			if (id->capability & 8) { /* IORDY supported? */
 				if (id->eide_pio_modes & 7) {
 					overridden = 0;
 					if (id->eide_pio_modes & 4)
@@ -298,36 +299,61 @@
 					else
 						pio_mode = 3;
 				}
-			} else {
-				cycle_time = id->eide_pio;
 			}
 		}
 
+		if (overridden)
+			printk(KERN_INFO "%s: tPIO > 2, assuming tPIO = 2\n",
+					 drive->name);
+
 		/*
 		 * Conservative "downgrade" for all pre-ATA2 drives
 		 */
-		if (pio_mode && pio_mode < 4) {
+		if ((drive->hwif->host_flags & IDE_HFLAG_PIO_NO_DOWNGRADE) == 0 &&
+		    pio_mode && pio_mode < 4) {
 			pio_mode--;
-			overridden = 1;
-			if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time)
-				cycle_time = 0; /* use standard timing */
+			printk(KERN_INFO "%s: applying conservative "
+					 "PIO \"downgrade\"\n", drive->name);
 		}
 	}
-	if (pio_mode > max_mode) {
+
+	if (pio_mode > max_mode)
 		pio_mode = max_mode;
-		cycle_time = 0;
-	}
-	if (d) {
-		d->pio_mode = pio_mode;
-		d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time;
-		d->use_iordy = use_iordy;
-		d->overridden = overridden;
-	}
+
 	return pio_mode;
 }
 
 EXPORT_SYMBOL_GPL(ide_get_best_pio_mode);
 
+/* req_pio == "255" for auto-tune */
+void ide_set_pio(ide_drive_t *drive, u8 req_pio)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	u8 host_pio, pio;
+
+	if (hwif->set_pio_mode == NULL)
+		return;
+
+	BUG_ON(hwif->pio_mask == 0x00);
+
+	host_pio = fls(hwif->pio_mask) - 1;
+
+	pio = ide_get_best_pio_mode(drive, req_pio, host_pio);
+
+	/*
+	 * TODO:
+	 * - report device max PIO mode
+	 * - check req_pio != 255 against device max PIO mode
+	 */
+	printk(KERN_DEBUG "%s: host max PIO%d wanted PIO%d%s selected PIO%d\n",
+			  drive->name, host_pio, req_pio,
+			  req_pio == 255 ? "(auto-tune)" : "", pio);
+
+	hwif->set_pio_mode(drive, pio);
+}
+
+EXPORT_SYMBOL_GPL(ide_set_pio);
+
 /**
  *	ide_toggle_bounce	-	handle bounce buffering
  *	@drive: drive to update
@@ -365,13 +391,26 @@
  
 int ide_set_xfer_rate(ide_drive_t *drive, u8 rate)
 {
-#ifndef CONFIG_BLK_DEV_IDEDMA
-	rate = min(rate, (u8) XFER_PIO_4);
-#endif
-	if(HWIF(drive)->speedproc)
-		return HWIF(drive)->speedproc(drive, rate);
-	else
+	ide_hwif_t *hwif = drive->hwif;
+
+	if (hwif->speedproc == NULL)
 		return -1;
+
+	rate = ide_rate_filter(drive, rate);
+
+	if (rate >= XFER_PIO_0 && rate <= XFER_PIO_5) {
+		if (hwif->set_pio_mode)
+			hwif->set_pio_mode(drive, rate - XFER_PIO_0);
+
+		/*
+		 * FIXME: this is incorrect to return zero here but
+		 * since all users of ide_set_xfer_rate() ignore
+		 * the return value it is not a problem currently
+		 */
+		return 0;
+	}
+
+	return hwif->speedproc(drive, rate);
 }
 
 static void ide_dump_opcode(ide_drive_t *drive)
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 5a4c5ea..b4c9f63 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -827,10 +827,8 @@
 		ide_drive_t *drive = &hwif->drives[unit];
 
 		if (drive->present) {
-			if (hwif->tuneproc != NULL && 
-				drive->autotune == IDE_TUNE_AUTO)
-				/* auto-tune PIO mode */
-				hwif->tuneproc(drive, 255);
+			if (drive->autotune == IDE_TUNE_AUTO)
+				ide_set_max_pio(drive);
 
 			if (drive->autotune != IDE_TUNE_DEFAULT &&
 			    drive->autotune != IDE_TUNE_AUTO)
@@ -945,7 +943,7 @@
  */
 static int ide_init_queue(ide_drive_t *drive)
 {
-	request_queue_t *q;
+	struct request_queue *q;
 	ide_hwif_t *hwif = HWIF(drive);
 	int max_sectors = 256;
 	int max_sg_entries = PRD_ENTRIES;
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index e82bfa5..1fa5794 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -640,7 +640,7 @@
 } idetape_chrdev_direction_t;
 
 struct idetape_bh {
-	unsigned short b_size;
+	u32 b_size;
 	atomic_t b_count;
 	struct idetape_bh *b_reqnext;
 	char *b_data;
diff --git a/drivers/ide/ide-timing.h b/drivers/ide/ide-timing.h
index e6cb859..daffbb9 100644
--- a/drivers/ide/ide-timing.h
+++ b/drivers/ide/ide-timing.h
@@ -106,23 +106,6 @@
 #define XFER_EPIO	0x01
 #define XFER_PIO	0x00
 
-static short ide_find_best_pio_mode(ide_drive_t *drive)
-{
-	struct hd_driveid *id = drive->id;
-	short best = 0;
-
-	if (id->field_valid & 2) {	/* EIDE PIO modes */
-
-		if ((best = (drive->id->eide_pio_modes & 4) ? XFER_PIO_5 :
-			    (drive->id->eide_pio_modes & 2) ? XFER_PIO_4 :
-			    (drive->id->eide_pio_modes & 1) ? XFER_PIO_3 : 0)) return best;
-	}
-	
-	return  (drive->id->tPIO == 2) ? XFER_PIO_2 :
-		(drive->id->tPIO == 1) ? XFER_PIO_1 :
-		(drive->id->tPIO == 0) ? XFER_PIO_0 : XFER_PIO_SLOW;
-}
-
 static void ide_timing_quantize(struct ide_timing *t, struct ide_timing *q, int T, int UT)
 {
 	q->setup   = EZ(t->setup   * 1000,  T);
@@ -212,7 +195,8 @@
  */
 
 	if ((speed & XFER_MODE) != XFER_PIO) {
-		ide_timing_compute(drive, ide_find_best_pio_mode(drive), &p, T, UT);
+		u8 pio = ide_get_best_pio_mode(drive, 255, 5);
+		ide_timing_compute(drive, XFER_PIO_0 + pio, &p, T, UT);
 		ide_timing_merge(&p, t, t, IDE_TIMING_ALL);
 	}
 
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 077fb67..a96a8b1 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -16,10 +16,6 @@
  *   (usually 14 & 15).
  * There can be up to two drives per interface, as per the ATA-2 spec.
  *
- * Primary:    ide0, port 0x1f0; major=3;  hda is minor=0; hdb is minor=64
- * Secondary:  ide1, port 0x170; major=22; hdc is minor=0; hdd is minor=64
- * Tertiary:   ide2, port 0x???; major=33; hde is minor=0; hdf is minor=64
- * Quaternary: ide3, port 0x???; major=34; hdg is minor=0; hdh is minor=64
  * ...
  *
  *  From hd.c:
@@ -47,80 +43,6 @@
  *  This was a rewrite of just about everything from hd.c, though some original
  *  code is still sprinkled about.  Think of it as a major evolution, with
  *  inspiration from lots of linux users, esp.  hamish@zot.apana.org.au
- *
- *  Version 1.0 ALPHA	initial code, primary i/f working okay
- *  Version 1.3 BETA	dual i/f on shared irq tested & working!
- *  Version 1.4 BETA	added auto probing for irq(s)
- *  Version 1.5 BETA	added ALPHA (untested) support for IDE cd-roms,
- *  ...
- * Version 5.50		allow values as small as 20 for idebus=
- * Version 5.51		force non io_32bit in drive_cmd_intr()
- *			change delay_10ms() to delay_50ms() to fix problems
- * Version 5.52		fix incorrect invalidation of removable devices
- *			add "hdx=slow" command line option
- * Version 5.60		start to modularize the driver; the disk and ATAPI
- *			 drivers can be compiled as loadable modules.
- *			move IDE probe code to ide-probe.c
- *			move IDE disk code to ide-disk.c
- *			add support for generic IDE device subdrivers
- *			add m68k code from Geert Uytterhoeven
- *			probe all interfaces by default
- *			add ioctl to (re)probe an interface
- * Version 6.00		use per device request queues
- *			attempt to optimize shared hwgroup performance
- *			add ioctl to manually adjust bandwidth algorithms
- *			add kerneld support for the probe module
- *			fix bug in ide_error()
- *			fix bug in the first ide_get_lock() call for Atari
- *			don't flush leftover data for ATAPI devices
- * Version 6.01		clear hwgroup->active while the hwgroup sleeps
- *			support HDIO_GETGEO for floppies
- * Version 6.02		fix ide_ack_intr() call
- *			check partition table on floppies
- * Version 6.03		handle bad status bit sequencing in ide_wait_stat()
- * Version 6.10		deleted old entries from this list of updates
- *			replaced triton.c with ide-dma.c generic PCI DMA
- *			added support for BIOS-enabled UltraDMA
- *			rename all "promise" things to "pdc4030"
- *			fix EZ-DRIVE handling on small disks
- * Version 6.11		fix probe error in ide_scan_devices()
- *			fix ancient "jiffies" polling bugs
- *			mask all hwgroup interrupts on each irq entry
- * Version 6.12		integrate ioctl and proc interfaces
- *			fix parsing of "idex=" command line parameter
- * Version 6.13		add support for ide4/ide5 courtesy rjones@orchestream.com
- * Version 6.14		fixed IRQ sharing among PCI devices
- * Version 6.15		added SMP awareness to IDE drivers
- * Version 6.16		fixed various bugs; even more SMP friendly
- * Version 6.17		fix for newest EZ-Drive problem
- * Version 6.18		default unpartitioned-disk translation now "BIOS LBA"
- * Version 6.19		Re-design for a UNIFORM driver for all platforms,
- *			  model based on suggestions from Russell King and
- *			  Geert Uytterhoeven
- *			Promise DC4030VL now supported.
- *			add support for ide6/ide7
- *			delay_50ms() changed to ide_delay_50ms() and exported.
- * Version 6.20		Added/Fixed Generic ATA-66 support and hwif detection.
- *			Added hdx=flash to allow for second flash disk
- *			  detection w/o the hang loop.
- *			Added support for ide8/ide9
- *			Added idex=ata66 for the quirky chipsets that are
- *			  ATA-66 compliant, but have yet to determine a method
- *			  of verification of the 80c cable presence.
- *			  Specifically Promise's PDC20262 chipset.
- * Version 6.21		Fixing/Fixed SMP spinlock issue with insight from an old
- *			  hat that clarified original low level driver design.
- * Version 6.30		Added SMP support; fixed multmode issues.  -ml
- * Version 6.31		Debug Share INTR's and request queue streaming
- *			Native ATA-100 support
- *			Prep for Cascades Project
- * Version 7.00alpha	First named revision of ide rearrange
- *
- *  Some additional driver compile-time options are in ./include/linux/ide.h
- *
- *  To do, in likely order of completion:
- *	- modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
- *
  */
 
 #define	REVISION	"Revision: 7.00alpha2"
@@ -455,6 +377,10 @@
 	hwif->straight8			= tmp_hwif->straight8;
 	hwif->bus_state			= tmp_hwif->bus_state;
 
+	hwif->host_flags		= tmp_hwif->host_flags;
+
+	hwif->pio_mask			= tmp_hwif->pio_mask;
+
 	hwif->atapi_dma			= tmp_hwif->atapi_dma;
 	hwif->ultra_mask		= tmp_hwif->ultra_mask;
 	hwif->mwdma_mask		= tmp_hwif->mwdma_mask;
@@ -470,8 +396,9 @@
 	hwif->cds			= tmp_hwif->cds;
 #endif
 
-	hwif->tuneproc			= tmp_hwif->tuneproc;
+	hwif->set_pio_mode		= tmp_hwif->set_pio_mode;
 	hwif->speedproc			= tmp_hwif->speedproc;
+	hwif->mdma_filter		= tmp_hwif->mdma_filter;
 	hwif->udma_filter		= tmp_hwif->udma_filter;
 	hwif->selectproc		= tmp_hwif->selectproc;
 	hwif->reset_poll		= tmp_hwif->reset_poll;
@@ -940,8 +867,9 @@
 	if (arg < 0 || arg > 255)
 		return -EINVAL;
 
-	if (!HWIF(drive)->tuneproc)
+	if (drive->hwif->set_pio_mode == NULL)
 		return -ENOSYS;
+
 	if (drive->special.b.set_tune)
 		return -EBUSY;
 	ide_init_drive_cmd(&rq);
@@ -988,6 +916,7 @@
 	struct request rq;
 	struct request_pm_state rqpm;
 	ide_task_t args;
+	int ret;
 
 	/* Call ACPI _GTM only once */
 	if (!(drive->dn % 2))
@@ -1004,7 +933,14 @@
 		mesg.event = PM_EVENT_FREEZE;
 	rqpm.pm_state = mesg.event;
 
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
+	ret = ide_do_drive_cmd(drive, &rq, ide_wait);
+	/* only call ACPI _PS3 after both drivers are suspended */
+	if (!ret && (((drive->dn % 2) && hwif->drives[0].present
+		 && hwif->drives[1].present)
+		 || !hwif->drives[0].present
+		 || !hwif->drives[1].present))
+		ide_acpi_set_state(hwif, 0);
+	return ret;
 }
 
 static int generic_ide_resume(struct device *dev)
@@ -1017,8 +953,10 @@
 	int err;
 
 	/* Call ACPI _STM only once */
-	if (!(drive->dn % 2))
+	if (!(drive->dn % 2)) {
+		ide_acpi_set_state(hwif, 1);
 		ide_acpi_push_timing(hwif);
+	}
 
 	ide_acpi_exec_tfs(drive);
 
@@ -1171,10 +1109,6 @@
 			return 0;
 		}
 
-		case CDROMEJECT:
-		case CDROMCLOSETRAY:
-			return scsi_cmd_ioctl(file, bdev->bd_disk->queue, bdev->bd_disk, cmd, p);
-
 		case HDIO_GET_BUSSTATE:
 			if (!capable(CAP_SYS_ADMIN))
 				return -EACCES;
@@ -1729,20 +1663,13 @@
 	__ATTR_NULL
 };
 
-static int ide_uevent(struct device *dev, char **envp, int num_envp,
-		      char *buffer, int buffer_size)
+static int ide_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	ide_drive_t *drive = to_ide_device(dev);
-	int i = 0;
-	int length = 0;
 
-	add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-		       "MEDIA=%s", media_string(drive));
-	add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-		       "DRIVENAME=%s", drive->name);
-	add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-		       "MODALIAS=ide:m-%s", media_string(drive));
-	envp[i] = NULL;
+	add_uevent_var(env, "MEDIA=%s", media_string(drive));
+	add_uevent_var(env, "DRIVENAME=%s", drive->name);
+	add_uevent_var(env, "MODALIAS=ide:m-%s", media_string(drive));
 	return 0;
 }
 
diff --git a/drivers/ide/legacy/Makefile b/drivers/ide/legacy/Makefile
index c797106..4098223 100644
--- a/drivers/ide/legacy/Makefile
+++ b/drivers/ide/legacy/Makefile
@@ -7,6 +7,8 @@
 
 obj-$(CONFIG_BLK_DEV_IDECS)		+= ide-cs.o
 
+obj-$(CONFIG_BLK_DEV_PLATFORM)		+= ide_platform.o
+
 # Last of all
 obj-$(CONFIG_BLK_DEV_HD)		+= hd.o
 
diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c
index df17ed6..2f0ef9b 100644
--- a/drivers/ide/legacy/ali14xx.c
+++ b/drivers/ide/legacy/ali14xx.c
@@ -68,8 +68,6 @@
 	{0x35, 0x03}, {0x00, 0x00}
 };
 
-#define ALI_MAX_PIO 4
-
 /* timing parameter registers for each drive */
 static struct { u8 reg1, reg2, reg3, reg4; } regTab[4] = {
 	{0x03, 0x26, 0x04, 0x27},     /* drive 0 */
@@ -109,19 +107,16 @@
  * This function computes timing parameters
  * and sets controller registers accordingly.
  */
-static void ali14xx_tune_drive (ide_drive_t *drive, u8 pio)
+static void ali14xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
 	int driveNum;
 	int time1, time2;
 	u8 param1, param2, param3, param4;
 	unsigned long flags;
-	ide_pio_data_t d;
 	int bus_speed = system_bus_clock();
 
-	pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d);
-
 	/* calculate timing, according to PIO mode */
-	time1 = d.cycle_time;
+	time1 = ide_pio_cycle_time(drive, pio);
 	time2 = ide_pio_timings[pio].active_time;
 	param3 = param1 = (time2 * bus_speed + 999) / 1000;
 	param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1;
@@ -212,11 +207,13 @@
 	mate = &ide_hwifs[1];
 
 	hwif->chipset = ide_ali14xx;
-	hwif->tuneproc = &ali14xx_tune_drive;
+	hwif->pio_mask = ATA_PIO4;
+	hwif->set_pio_mode = &ali14xx_set_pio_mode;
 	hwif->mate = mate;
 
 	mate->chipset = ide_ali14xx;
-	mate->tuneproc = &ali14xx_tune_drive;
+	mate->pio_mask = ATA_PIO4;
+	mate->set_pio_mode = &ali14xx_set_pio_mode;
 	mate->mate = hwif;
 	mate->channel = 1;
 
diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c
index 36a3f0a..f165212 100644
--- a/drivers/ide/legacy/dtc2278.c
+++ b/drivers/ide/legacy/dtc2278.c
@@ -67,12 +67,10 @@
 	}
 }
 
-static void tune_dtc2278 (ide_drive_t *drive, u8 pio)
+static void dtc2278_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
 	unsigned long flags;
 
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-
 	if (pio >= 3) {
 		spin_lock_irqsave(&ide_lock, flags);
 		/*
@@ -123,7 +121,8 @@
 
 	hwif->serialized = 1;
 	hwif->chipset = ide_dtc2278;
-	hwif->tuneproc = &tune_dtc2278;
+	hwif->pio_mask = ATA_PIO4;
+	hwif->set_pio_mode = &dtc2278_set_pio_mode;
 	hwif->drives[0].no_unmask = 1;
 	hwif->drives[1].no_unmask = 1;
 	hwif->mate = mate;
diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c
index e1e9d9d..f0829b8 100644
--- a/drivers/ide/legacy/falconide.c
+++ b/drivers/ide/legacy/falconide.c
@@ -8,6 +8,7 @@
  *  more details.
  */
 
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
@@ -54,6 +55,7 @@
      */
 
 int falconide_intr_lock;
+EXPORT_SYMBOL(falconide_intr_lock);
 
 
     /*
diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
index 8f2db8d..8e05d88 100644
--- a/drivers/ide/legacy/hd.c
+++ b/drivers/ide/legacy/hd.c
@@ -652,7 +652,7 @@
 	}
 }
 
-static void do_hd_request (request_queue_t * q)
+static void do_hd_request (struct request_queue * q)
 {
 	disable_irq(HD_IRQ);
 	hd_request();
diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
index c8f353b..2e5a9cc 100644
--- a/drivers/ide/legacy/ht6560b.c
+++ b/drivers/ide/legacy/ht6560b.c
@@ -199,23 +199,24 @@
 	return 1;
 }
 
-static u8 ht_pio2timings(ide_drive_t *drive, u8 pio)
+static u8 ht_pio2timings(ide_drive_t *drive, const u8 pio)
 {
 	int active_time, recovery_time;
 	int active_cycles, recovery_cycles;
-	ide_pio_data_t d;
 	int bus_speed = system_bus_clock();
 	
         if (pio) {
-		pio = ide_get_best_pio_mode(drive, pio, 5, &d);
-		
+		unsigned int cycle_time;
+
+		cycle_time = ide_pio_cycle_time(drive, pio);
+
 		/*
 		 *  Just like opti621.c we try to calculate the
 		 *  actual cycle time for recovery and activity
 		 *  according system bus speed.
 		 */
 		active_time = ide_pio_timings[pio].active_time;
-		recovery_time = d.cycle_time 
+		recovery_time = cycle_time
 			- active_time
 			- ide_pio_timings[pio].setup_time;
 		/*
@@ -275,7 +276,7 @@
 #endif
 }
 
-static void tune_ht6560b (ide_drive_t *drive, u8 pio)
+static void ht6560b_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
 	unsigned long flags;
 	u8 timing;
@@ -331,13 +332,17 @@
 
 	hwif->chipset = ide_ht6560b;
 	hwif->selectproc = &ht6560b_selectproc;
-	hwif->tuneproc = &tune_ht6560b;
+	hwif->host_flags = IDE_HFLAG_ABUSE_PREFETCH;
+	hwif->pio_mask = ATA_PIO5;
+	hwif->set_pio_mode = &ht6560b_set_pio_mode;
 	hwif->serialized = 1;	/* is this needed? */
 	hwif->mate = mate;
 
 	mate->chipset = ide_ht6560b;
 	mate->selectproc = &ht6560b_selectproc;
-	mate->tuneproc = &tune_ht6560b;
+	mate->host_flags = IDE_HFLAG_ABUSE_PREFETCH;
+	mate->pio_mask = ATA_PIO5;
+	mate->set_pio_mode = &ht6560b_set_pio_mode;
 	mate->serialized = 1;	/* is this needed? */
 	mate->mate = hwif;
 	mate->channel = 1;
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index 2f3977f..4cdb519 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -386,6 +386,7 @@
 	PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
 	PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
 	PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+	PCMCIA_DEVICE_PROD_ID12("KINGSTON", "CF8GB", 0x2e6d1829, 0xacbe682e),
 	PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2      ", 0x547e66dc, 0x8671043b),
 	PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
 	PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
diff --git a/drivers/ide/legacy/ide_platform.c b/drivers/ide/legacy/ide_platform.c
new file mode 100644
index 0000000..ccfb989
--- /dev/null
+++ b/drivers/ide/legacy/ide_platform.c
@@ -0,0 +1,182 @@
+/*
+ * Platform IDE driver
+ *
+ * Copyright (C) 2007 MontaVista Software
+ *
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/ide.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/pata_platform.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+static struct {
+	void __iomem *plat_ide_mapbase;
+	void __iomem *plat_ide_alt_mapbase;
+	ide_hwif_t *hwif;
+	int index;
+} hwif_prop;
+
+static ide_hwif_t *__devinit plat_ide_locate_hwif(void __iomem *base,
+	    void __iomem *ctrl, struct pata_platform_info *pdata, int irq,
+	    int mmio)
+{
+	unsigned long port = (unsigned long)base;
+	ide_hwif_t *hwif;
+	int index, i;
+
+	for (index = 0; index < MAX_HWIFS; ++index) {
+		hwif = ide_hwifs + index;
+		if (hwif->io_ports[IDE_DATA_OFFSET] == port)
+			goto found;
+	}
+
+	for (index = 0; index < MAX_HWIFS; ++index) {
+		hwif = ide_hwifs + index;
+		if (hwif->io_ports[IDE_DATA_OFFSET] == 0)
+			goto found;
+	}
+
+	return NULL;
+
+found:
+
+	hwif->hw.io_ports[IDE_DATA_OFFSET] = port;
+
+	port += (1 << pdata->ioport_shift);
+	for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET;
+	     i++, port += (1 << pdata->ioport_shift))
+		hwif->hw.io_ports[i] = port;
+
+	hwif->hw.io_ports[IDE_CONTROL_OFFSET] = (unsigned long)ctrl;
+
+	memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
+	hwif->hw.irq = hwif->irq = irq;
+
+	hwif->hw.dma = NO_DMA;
+	hwif->hw.chipset = ide_generic;
+
+	if (mmio) {
+		hwif->mmio = 1;
+		default_hwif_mmiops(hwif);
+	}
+
+	hwif_prop.hwif = hwif;
+	hwif_prop.index = index;
+
+	return hwif;
+}
+
+static int __devinit plat_ide_probe(struct platform_device *pdev)
+{
+	struct resource *res_base, *res_alt, *res_irq;
+	ide_hwif_t *hwif;
+	struct pata_platform_info *pdata;
+	int ret = 0;
+	int mmio = 0;
+
+	pdata = pdev->dev.platform_data;
+
+	/* get a pointer to the register memory */
+	res_base = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	res_alt = platform_get_resource(pdev, IORESOURCE_IO, 1);
+
+	if (!res_base || !res_alt) {
+		res_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		res_alt = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+		if (!res_base || !res_alt) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		mmio = 1;
+	}
+
+	res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res_irq) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (mmio) {
+		hwif_prop.plat_ide_mapbase = devm_ioremap(&pdev->dev,
+			res_base->start, res_base->end - res_base->start + 1);
+		hwif_prop.plat_ide_alt_mapbase = devm_ioremap(&pdev->dev,
+			res_alt->start, res_alt->end - res_alt->start + 1);
+	} else {
+		hwif_prop.plat_ide_mapbase = devm_ioport_map(&pdev->dev,
+			res_base->start, res_base->end - res_base->start + 1);
+		hwif_prop.plat_ide_alt_mapbase = devm_ioport_map(&pdev->dev,
+			res_alt->start, res_alt->end - res_alt->start + 1);
+	}
+
+	hwif = plat_ide_locate_hwif(hwif_prop.plat_ide_mapbase,
+	         hwif_prop.plat_ide_alt_mapbase, pdata, res_irq->start, mmio);
+
+	if (!hwif) {
+		ret = -ENODEV;
+		goto out;
+	}
+	hwif->gendev.parent = &pdev->dev;
+	hwif->noprobe = 0;
+
+	probe_hwif_init(hwif);
+
+	platform_set_drvdata(pdev, hwif);
+	ide_proc_register_port(hwif);
+
+	return 0;
+
+out:
+	return ret;
+}
+
+static int __devexit plat_ide_remove(struct platform_device *pdev)
+{
+	ide_hwif_t *hwif = pdev->dev.driver_data;
+
+	if (hwif != hwif_prop.hwif) {
+		dev_printk(KERN_DEBUG, &pdev->dev, "%s: hwif value error",
+		           pdev->name);
+	} else {
+		ide_unregister(hwif_prop.index);
+		hwif_prop.index = 0;
+		hwif_prop.hwif = NULL;
+	}
+
+	return 0;
+}
+
+static struct platform_driver platform_ide_driver = {
+	.driver = {
+		.name = "pata_platform",
+	},
+	.probe = plat_ide_probe,
+	.remove = __devexit_p(plat_ide_remove),
+};
+
+static int __init platform_ide_init(void)
+{
+	return platform_driver_register(&platform_ide_driver);
+}
+
+static void __exit platform_ide_exit(void)
+{
+	platform_driver_unregister(&platform_ide_driver);
+}
+
+MODULE_DESCRIPTION("Platform IDE driver");
+MODULE_LICENSE("GPL");
+
+module_init(platform_ide_init);
+module_exit(platform_ide_exit);
diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
index 7783745..0c81d2d 100644
--- a/drivers/ide/legacy/qd65xx.c
+++ b/drivers/ide/legacy/qd65xx.c
@@ -224,15 +224,14 @@
 	printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
 }
 
-/*
- * qd6500_tune_drive
- */
-
-static void qd6500_tune_drive (ide_drive_t *drive, u8 pio)
+static void qd6500_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
 	int active_time   = 175;
 	int recovery_time = 415; /* worst case values from the dos driver */
 
+	/*
+	 * FIXME: use "pio" value
+	 */
 	if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)
 		&& drive->id->tPIO && (drive->id->field_valid & 0x02)
 		&& drive->id->eide_pio >= 240) {
@@ -246,44 +245,39 @@
 	qd_set_timing(drive, qd6500_compute_timing(HWIF(drive), active_time, recovery_time));
 }
 
-/*
- * qd6580_tune_drive
- */
-
-static void qd6580_tune_drive (ide_drive_t *drive, u8 pio)
+static void qd6580_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	ide_pio_data_t d;
 	int base = HWIF(drive)->select_data;
+	unsigned int cycle_time;
 	int active_time   = 175;
 	int recovery_time = 415; /* worst case values from the dos driver */
 
 	if (drive->id && !qd_find_disk_type(drive, &active_time, &recovery_time)) {
-		pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+		cycle_time = ide_pio_cycle_time(drive, pio);
 
 		switch (pio) {
 			case 0: break;
 			case 3:
-				if (d.cycle_time >= 110) {
+				if (cycle_time >= 110) {
 					active_time = 86;
-					recovery_time = d.cycle_time - 102;
+					recovery_time = cycle_time - 102;
 				} else
 					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
 				break;
 			case 4:
-				if (d.cycle_time >= 69) {
+				if (cycle_time >= 69) {
 					active_time = 70;
-					recovery_time = d.cycle_time - 61;
+					recovery_time = cycle_time - 61;
 				} else
 					printk(KERN_WARNING "%s: Strange recovery time !\n",drive->name);
 				break;
 			default:
-				if (d.cycle_time >= 180) {
+				if (cycle_time >= 180) {
 					active_time = 110;
-					recovery_time = d.cycle_time - 120;
+					recovery_time = cycle_time - 120;
 				} else {
 					active_time = ide_pio_timings[pio].active_time;
-					recovery_time = d.cycle_time
-							-active_time;
+					recovery_time = cycle_time - active_time;
 				}
 		}
 		printk(KERN_INFO "%s: PIO mode%d\n", drive->name,pio);
@@ -335,8 +329,7 @@
  */
 
 static void __init qd_setup(ide_hwif_t *hwif, int base, int config,
-			    unsigned int data0, unsigned int data1,
-			    void (*tuneproc) (ide_drive_t *, u8 pio))
+			    unsigned int data0, unsigned int data1)
 {
 	hwif->chipset = ide_qd65xx;
 	hwif->channel = hwif->index;
@@ -346,8 +339,7 @@
 	hwif->drives[1].drive_data = data1;
 	hwif->drives[0].io_32bit =
 	hwif->drives[1].io_32bit = 1;
-	hwif->tuneproc = tuneproc;
-	probe_hwif_init(hwif);
+	hwif->pio_mask = ATA_PIO4;
 }
 
 /*
@@ -360,7 +352,7 @@
 {
 	u8 config = hwif->config_data;
 	int base = hwif->select_data;
-	void *tuneproc = (void *) hwif->tuneproc;
+	void *set_pio_mode = (void *)hwif->set_pio_mode;
 
 	if (hwif->chipset != ide_qd65xx)
 		return;
@@ -368,12 +360,12 @@
 	printk(KERN_NOTICE "%s: back to defaults\n", hwif->name);
 
 	hwif->selectproc = NULL;
-	hwif->tuneproc = NULL;
+	hwif->set_pio_mode = NULL;
 
-	if (tuneproc == (void *) qd6500_tune_drive) {
+	if (set_pio_mode == (void *)qd6500_set_pio_mode) {
 		// will do it for both
 		qd_write_reg(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
-	} else if (tuneproc == (void *) qd6580_tune_drive) {
+	} else if (set_pio_mode == (void *)qd6580_set_pio_mode) {
 		if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) {
 			qd_write_reg(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
 			qd_write_reg(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1]));
@@ -423,8 +415,11 @@
 			return 1;
 		}
 
-		qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA,
-			 &qd6500_tune_drive);
+		qd_setup(hwif, base, config, QD6500_DEF_DATA, QD6500_DEF_DATA);
+
+		hwif->set_pio_mode = &qd6500_set_pio_mode;
+
+		probe_hwif_init(hwif);
 
 		ide_proc_register_port(hwif);
 
@@ -454,8 +449,12 @@
 			printk(KERN_INFO "%s: qd6580: single IDE board\n",
 					 hwif->name);
 			qd_setup(hwif, base, config | (control << 8),
-				 QD6580_DEF_DATA, QD6580_DEF_DATA2,
-				 &qd6580_tune_drive);
+				 QD6580_DEF_DATA, QD6580_DEF_DATA2);
+
+			hwif->set_pio_mode = &qd6580_set_pio_mode;
+
+			probe_hwif_init(hwif);
+
 			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
 
 			ide_proc_register_port(hwif);
@@ -471,11 +470,19 @@
 					hwif->name, mate->name);
 
 			qd_setup(hwif, base, config | (control << 8),
-				 QD6580_DEF_DATA, QD6580_DEF_DATA,
-				 &qd6580_tune_drive);
+				 QD6580_DEF_DATA, QD6580_DEF_DATA);
+
+			hwif->set_pio_mode = &qd6580_set_pio_mode;
+
+			probe_hwif_init(hwif);
+
 			qd_setup(mate, base, config | (control << 8),
-				 QD6580_DEF_DATA2, QD6580_DEF_DATA2,
-				 &qd6580_tune_drive);
+				 QD6580_DEF_DATA2, QD6580_DEF_DATA2);
+
+			mate->set_pio_mode = &qd6580_set_pio_mode;
+
+			probe_hwif_init(mate);
+
 			qd_write_reg(QD_DEF_CONTR,QD_CONTROL_PORT);
 
 			ide_proc_register_port(hwif);
diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c
index ddc403a..1151c92 100644
--- a/drivers/ide/legacy/umc8672.c
+++ b/drivers/ide/legacy/umc8672.c
@@ -105,12 +105,11 @@
 		speeds[0], speeds[1], speeds[2], speeds[3]);
 }
 
-static void tune_umc (ide_drive_t *drive, u8 pio)
+static void umc_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
 	unsigned long flags;
 	ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup;
 
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
 	printk("%s: setting umc8672 to PIO mode%d (speed %d)\n",
 		drive->name, pio, pio_to_umc[pio]);
 	spin_lock_irqsave(&ide_lock, flags);
@@ -149,11 +148,13 @@
 	mate = &ide_hwifs[1];
 
 	hwif->chipset = ide_umc8672;
-	hwif->tuneproc = &tune_umc;
+	hwif->pio_mask = ATA_PIO4;
+	hwif->set_pio_mode = &umc_set_pio_mode;
 	hwif->mate = mate;
 
 	mate->chipset = ide_umc8672;
-	mate->tuneproc = &tune_umc;
+	mate->pio_mask = ATA_PIO4;
+	mate->set_pio_mode = &umc_set_pio_mode;
 	mate->mate = hwif;
 	mate->channel = 1;
 
diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
index 2e7013a..85819ae 100644
--- a/drivers/ide/mips/au1xxx-ide.c
+++ b/drivers/ide/mips/au1xxx-ide.c
@@ -99,18 +99,12 @@
 
 #endif
 
-static void auide_tune_drive(ide_drive_t *drive, byte pio)
+static void au1xxx_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
 	int mem_sttime;
 	int mem_stcfg;
 	u8 speed;
 
-	/* get the best pio mode for the drive */
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-
-	printk(KERN_INFO "%s: setting Au1XXX IDE to PIO mode%d\n",
-	       drive->name, pio);
-
 	mem_sttime = 0;
 	mem_stcfg  = au_readl(MEM_STCFG2);
 
@@ -175,7 +169,7 @@
 	ide_config_drive_speed(drive, speed);
 }
 
-static int auide_tune_chipset (ide_drive_t *drive, u8 speed)
+static int auide_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	int mem_sttime;
 	int mem_stcfg;
@@ -183,11 +177,6 @@
 	mem_sttime = 0;
 	mem_stcfg  = au_readl(MEM_STCFG2);
 
-	if (speed >= XFER_PIO_0 && speed <= XFER_PIO_4) {
-		auide_tune_drive(drive, speed - XFER_PIO_0);
-		return 0;
-	}
-
 	switch(speed) {
 #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
 	case XFER_MW_DMA_2:
@@ -692,6 +681,8 @@
 	hwif->swdma_mask                = 0x0;
 #endif
 
+	hwif->pio_mask = ATA_PIO4;
+
 	hwif->noprobe = 0;
 	hwif->drives[0].unmask          = 1;
 	hwif->drives[1].unmask          = 1;
@@ -710,7 +701,7 @@
 	hwif->OUTSW                     = auide_outsw;
 #endif
 
-	hwif->tuneproc                  = &auide_tune_drive;
+	hwif->set_pio_mode		= &au1xxx_set_pio_mode;
 	hwif->speedproc                 = &auide_tune_chipset;
 
 #ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
index 6e935d7..c2e2957 100644
--- a/drivers/ide/mips/swarm.c
+++ b/drivers/ide/mips/swarm.c
@@ -165,12 +165,11 @@
 		goto out;
 	}
 
-        if (!(pldev = kmalloc(sizeof (*pldev), GFP_KERNEL))) {
+        if (!(pldev = kzalloc(sizeof (*pldev), GFP_KERNEL))) {
 		err = -ENOMEM;
 		goto out_unregister_driver;
 	}
 
-	memset (pldev, 0, sizeof (*pldev));
 	pldev->name		= swarm_ide_string;
 	pldev->id		= 0;
 	pldev->dev.release	= swarm_ide_platform_release;
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index e5d0936..0d5f62c 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -87,12 +87,11 @@
 	return chipset_table->ultra_settings;
 }
 
-static int aec6210_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static int aec6210_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
 	u16 d_conf		= 0;
-	u8 speed		= ide_rate_filter(drive, xferspeed);
 	u8 ultra = 0, ultra_conf = 0;
 	u8 tmp0 = 0, tmp1 = 0, tmp2 = 0;
 	unsigned long flags;
@@ -115,11 +114,10 @@
 	return(ide_config_drive_speed(drive, speed));
 }
 
-static int aec6260_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static int aec6260_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
-	u8 speed	= ide_rate_filter(drive, xferspeed);
 	u8 unit		= (drive->select.b.unit & 0x01);
 	u8 tmp1 = 0, tmp2 = 0;
 	u8 ultra = 0, drive_conf = 0, ultra_conf = 0;
@@ -140,9 +138,8 @@
 	return(ide_config_drive_speed(drive, speed));
 }
 
-static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio)
+static void aec_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
 	(void) HWIF(drive)->speedproc(drive, pio + XFER_PIO_0);
 }
 
@@ -152,7 +149,7 @@
 		return 0;
 
 	if (ide_use_fast_pio(drive))
-		aec62xx_tune_drive(drive, 255);
+		ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -174,12 +171,6 @@
 {
 	int bus_speed = system_bus_clock();
 
-	if (dev->resource[PCI_ROM_RESOURCE].start) {
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
-			(unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
-	}
-
 	if (bus_speed <= 33)
 		pci_set_drvdata(dev, (void *) aec6xxx_33_base);
 	else
@@ -209,7 +200,7 @@
 	u8 reg54 = 0,  mask	= hwif->channel ? 0xf0 : 0x0f;
 	unsigned long flags;
 
-	hwif->tuneproc = &aec62xx_tune_drive;
+	hwif->set_pio_mode = &aec_set_pio_mode;
 
 	if (dev->device == PCI_DEVICE_ID_ARTOP_ATP850UF) {
 		if(hwif->mate)
@@ -271,48 +262,48 @@
 		.init_setup	= init_setup_aec62xx,
 		.init_chipset	= init_chipset_aec62xx,
 		.init_hwif	= init_hwif_aec62xx,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
 		.bootable	= OFF_BOARD,
+		.pio_mask	= ATA_PIO4,
 		.udma_mask	= 0x07, /* udma0-2 */
 	},{	/* 1 */
 		.name		= "AEC6260",
 		.init_setup	= init_setup_aec62xx,
 		.init_chipset	= init_chipset_aec62xx,
 		.init_hwif	= init_hwif_aec62xx,
-		.channels	= 2,
 		.autodma	= NOAUTODMA,
 		.bootable	= OFF_BOARD,
+		.pio_mask	= ATA_PIO4,
 		.udma_mask	= 0x1f, /* udma0-4 */
 	},{	/* 2 */
 		.name		= "AEC6260R",
 		.init_setup	= init_setup_aec62xx,
 		.init_chipset	= init_chipset_aec62xx,
 		.init_hwif	= init_hwif_aec62xx,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
 		.bootable	= NEVER_BOARD,
+		.pio_mask	= ATA_PIO4,
 		.udma_mask	= 0x1f, /* udma0-4 */
 	},{	/* 3 */
 		.name		= "AEC6280",
 		.init_setup	= init_setup_aec6x80,
 		.init_chipset	= init_chipset_aec62xx,
 		.init_hwif	= init_hwif_aec62xx,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
+		.pio_mask	= ATA_PIO4,
 		.udma_mask	= 0x3f, /* udma0-5 */
 	},{	/* 4 */
 		.name		= "AEC6280R",
 		.init_setup	= init_setup_aec6x80,
 		.init_chipset	= init_chipset_aec62xx,
 		.init_hwif	= init_hwif_aec62xx,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
 		.bootable	= OFF_BOARD,
+		.pio_mask	= ATA_PIO4,
 		.udma_mask	= 0x3f, /* udma0-5 */
 	}
 };
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index ba0fb92b..d04b966 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/alim15x3.c		Version 0.25	Jun 9 2007
+ * linux/drivers/ide/pci/alim15x3.c		Version 0.26	Jul 14 2007
  *
  *  Copyright (C) 1998-2000 Michel Aubry, Maintainer
  *  Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
@@ -283,19 +283,15 @@
 #endif  /* defined(DISPLAY_ALI_TIMINGS) && defined(CONFIG_IDE_PROC_FS) */
 
 /**
- *	ali15x3_tune_pio	-	set up chipset for PIO mode
- *	@drive: drive to tune
- *	@pio: desired mode
+ *	ali_tune_pio	-	set host controller for PIO mode
+ *	@drive: drive
+ *	@pio: PIO mode number
  *
- *	Select the best PIO mode for the drive in question.
- *	Then program the controller for this mode.
- *
- *	Returns the PIO mode programmed.
+ *	Program the controller for the given PIO mode.
  */
- 
-static u8 ali15x3_tune_pio (ide_drive_t *drive, u8 pio)
+
+static void ali_tune_pio(ide_drive_t *drive, const u8 pio)
 {
-	ide_pio_data_t d;
 	ide_hwif_t *hwif = HWIF(drive);
 	struct pci_dev *dev = hwif->pci_dev;
 	int s_time, a_time, c_time;
@@ -307,7 +303,6 @@
 	u8 cd_dma_fifo = 0;
 	int unit = drive->select.b.unit & 1;
 
-	pio = ide_get_best_pio_mode(drive, pio, 5, &d);
 	s_time = ide_pio_timings[pio].setup_time;
 	a_time = ide_pio_timings[pio].active_time;
 	if ((s_clc = (s_time * bus_speed + 999) / 1000) >= 8)
@@ -360,22 +355,20 @@
 	 * { 25,   70,     25  },   PIO Mode 4 with IORDY  ns
 	 * { 20,   50,     30  }    PIO Mode 5 with IORDY (nonstandard)
 	 */
-
-	return pio;
 }
 
 /**
- *	ali15x3_tune_drive	-	set up drive for PIO mode
+ *	ali_set_pio_mode	-	set up drive for PIO mode
  *	@drive: drive to tune
  *	@pio: desired mode
  *
- *	Program the controller with the best PIO timing for the given drive.
+ *	Program the controller with the desired PIO timing for the given drive.
  *	Then set up the drive itself.
  */
 
-static void ali15x3_tune_drive (ide_drive_t *drive, u8 pio)
+static void ali_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	pio = ali15x3_tune_pio(drive, pio);
+	ali_tune_pio(drive, pio);
 	(void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
@@ -410,22 +403,24 @@
 /**
  *	ali15x3_tune_chipset	-	set up chipset/drive for new speed
  *	@drive: drive to configure for
- *	@xferspeed: desired speed
+ *	@speed: desired speed
  *
  *	Configure the hardware for the desired IDE transfer mode.
  *	We also do the needed drive configuration through helpers
  */
- 
-static int ali15x3_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+
+static int ali15x3_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
-	u8 speed		= ide_rate_filter(drive, xferspeed);
 	u8 speed1		= speed;
 	u8 unit			= (drive->select.b.unit & 0x01);
 	u8 tmpbyte		= 0x00;
 	int m5229_udma		= (hwif->channel) ? 0x57 : 0x56;
 
+	if (speed < XFER_PIO_0)
+		return 1;
+
 	if (speed == XFER_UDMA_6)
 		speed1 = 0x47;
 
@@ -438,8 +433,9 @@
 		tmpbyte &= ultra_enable;
 		pci_write_config_byte(dev, m5229_udma, tmpbyte);
 
-		if (speed < XFER_SW_DMA_0)
-			(void) ali15x3_tune_pio(drive, speed - XFER_PIO_0);
+		/*
+		 * FIXME: Oh, my... DMA timings are never set.
+		 */
 	} else {
 		pci_read_config_byte(dev, m5229_udma, &tmpbyte);
 		tmpbyte &= (0x0f << ((1-unit) << 2));
@@ -472,7 +468,7 @@
 	if (ide_tune_dma(drive))
 		return 0;
 
-	ali15x3_tune_drive(drive, 255);
+	ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -589,12 +585,19 @@
  *	Cable special cases
  */
 
-static struct dmi_system_id cable_dmi_table[] = {
+static const struct dmi_system_id cable_dmi_table[] = {
 	{
 		.ident = "HP Pavilion N5430",
 		.matches = {
 			DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
-			DMI_MATCH(DMI_BOARD_NAME, "OmniBook N32N-736"),
+			DMI_MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736"),
+		},
+	},
+	{
+		.ident = "Toshiba Satellite S1800-814",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "S1800-814"),
 		},
 	},
 	{ }
@@ -695,7 +698,7 @@
 static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif)
 {
 	hwif->autodma = 0;
-	hwif->tuneproc = &ali15x3_tune_drive;
+	hwif->set_pio_mode = &ali_set_pio_mode;
 	hwif->speedproc = &ali15x3_tune_chipset;
 	hwif->udma_filter = &ali_udma_filter;
 
@@ -817,9 +820,9 @@
 	.init_chipset	= init_chipset_ali15x3,
 	.init_hwif	= init_hwif_ali15x3,
 	.init_dma	= init_dma_ali15x3,
-	.channels	= 2,
 	.autodma	= AUTODMA,
 	.bootable	= ON_BOARD,
+	.pio_mask	= ATA_PIO5,
 };
 
 /**
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index 8d30b99..513205e 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -1,5 +1,5 @@
 /*
- * Version 2.20
+ * Version 2.22
  *
  * AMD 755/756/766/8111 and nVidia nForce/2/2s/3/3s/CK804/MCP04
  * IDE driver for Linux.
@@ -234,7 +234,7 @@
  * by upper layers.
  */
 
-static int amd_set_drive(ide_drive_t *drive, u8 speed)
+static int amd_set_drive(ide_drive_t *drive, const u8 speed)
 {
 	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
 	struct ide_timing t, p;
@@ -266,32 +266,21 @@
 }
 
 /*
- * amd74xx_tune_drive() is a callback from upper layers for
- * PIO-only tuning.
+ * amd_set_pio_mode() is a callback from upper layers for PIO-only tuning.
  */
 
-static void amd74xx_tune_drive(ide_drive_t *drive, u8 pio)
+static void amd_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	if (pio == 255) {
-		amd_set_drive(drive, ide_find_best_pio_mode(drive));
-		return;
-	}
-
-	amd_set_drive(drive, XFER_PIO_0 + min_t(byte, pio, 5));
+	amd_set_drive(drive, XFER_PIO_0 + pio);
 }
 
 static int amd74xx_ide_dma_check(ide_drive_t *drive)
 {
-	u8 speed = ide_max_dma_mode(drive);
-
-	if (speed == 0)
-		speed = ide_find_best_pio_mode(drive);
-
-	amd_set_drive(drive, speed);
-
-	if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+	if (ide_tune_dma(drive))
 		return 0;
 
+	ide_set_max_pio(drive);
+
 	return -1;
 }
 
@@ -409,7 +398,7 @@
 
 	hwif->autodma = 0;
 
-	hwif->tuneproc = &amd74xx_tune_drive;
+	hwif->set_pio_mode = &amd_set_pio_mode;
 	hwif->speedproc = &amd_set_drive;
 
 	for (i = 0; i < 2; i++) {
@@ -448,10 +437,12 @@
 		.name		= name_str,				\
 		.init_chipset	= init_chipset_amd74xx,			\
 		.init_hwif	= init_hwif_amd74xx,			\
-		.channels	= 2,					\
 		.autodma	= AUTODMA,				\
 		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},	\
 		.bootable	= ON_BOARD,				\
+		.host_flags	= IDE_HFLAG_PIO_NO_BLACKLIST		\
+				| IDE_HFLAG_PIO_NO_DOWNGRADE,		\
+		.pio_mask	= ATA_PIO5,				\
 	}
 
 #define DECLARE_NV_DEV(name_str)					\
@@ -459,10 +450,12 @@
 		.name		= name_str,				\
 		.init_chipset	= init_chipset_amd74xx,			\
 		.init_hwif	= init_hwif_amd74xx,			\
-		.channels	= 2,					\
 		.autodma	= AUTODMA,				\
 		.enablebits	= {{0x50,0x02,0x02}, {0x50,0x01,0x01}},	\
 		.bootable	= ON_BOARD,				\
+		.host_flags	= IDE_HFLAG_PIO_NO_BLACKLIST		\
+				| IDE_HFLAG_PIO_NO_DOWNGRADE,		\
+		.pio_mask	= ATA_PIO5,				\
 	}
 
 static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
index 2761510..178876a3 100644
--- a/drivers/ide/pci/atiixp.c
+++ b/drivers/ide/pci/atiixp.c
@@ -1,9 +1,8 @@
 /*
- *  linux/drivers/ide/pci/atiixp.c	Version 0.01-bart2	Feb. 26, 2004
+ *  linux/drivers/ide/pci/atiixp.c	Version 0.02	Jun 16 2007
  *
  *  Copyright (C) 2003 ATI Inc. <hyu@ati.com>
- *  Copyright (C) 2004 Bartlomiej Zolnierkiewicz
- *
+ *  Copyright (C) 2004,2007 Bartlomiej Zolnierkiewicz
  */
 
 #include <linux/types.h>
@@ -123,14 +122,14 @@
 }
 
 /**
- *	atiixp_tune_drive		-	tune a drive attached to a ATIIXP
+ *	atiixp_tune_pio	-	tune a drive attached to a ATIIXP
  *	@drive: drive to tune
  *	@pio: desired PIO mode
  *
  *	Set the interface PIO mode.
  */
 
-static void atiixp_tuneproc(ide_drive_t *drive, u8 pio)
+static void atiixp_tune_pio(ide_drive_t *drive, u8 pio)
 {
 	struct pci_dev *dev = drive->hwif->pci_dev;
 	unsigned long flags;
@@ -154,26 +153,30 @@
 	spin_unlock_irqrestore(&atiixp_lock, flags);
 }
 
+static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+	atiixp_tune_pio(drive, pio);
+	(void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
+}
+
 /**
  *	atiixp_tune_chipset	-	tune a ATIIXP interface
  *	@drive: IDE drive to tune
- *	@xferspeed: speed to configure
+ *	@speed: speed to configure
  *
  *	Set a ATIIXP interface channel to the desired speeds. This involves
  *	requires the right timing data into the ATIIXP configuration space
  *	then setting the drive parameters appropriately
  */
 
-static int atiixp_speedproc(ide_drive_t *drive, u8 xferspeed)
+static int atiixp_speedproc(ide_drive_t *drive, const u8 speed)
 {
 	struct pci_dev *dev = drive->hwif->pci_dev;
 	unsigned long flags;
 	int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
 	u32 tmp32;
 	u16 tmp16;
-	u8 speed, pio;
-
-	speed = ide_rate_filter(drive, xferspeed);
+	u8 pio;
 
 	spin_lock_irqsave(&atiixp_lock, flags);
 
@@ -201,7 +204,7 @@
 	else
 		pio = speed - XFER_PIO_0;
 
-	atiixp_tuneproc(drive, pio);
+	atiixp_tune_pio(drive, pio);
 
 	return ide_config_drive_speed(drive, speed);
 }
@@ -216,18 +219,13 @@
 
 static int atiixp_dma_check(ide_drive_t *drive)
 {
-	u8 tspeed, speed;
-
 	drive->init_speed = 0;
 
 	if (ide_tune_dma(drive))
 		return 0;
 
-	if (ide_use_fast_pio(drive)) {
-		tspeed = ide_get_best_pio_mode(drive, 255, 5, NULL);
-		speed = atiixp_dma_2_pio(XFER_PIO_0 + tspeed) + XFER_PIO_0;
-		atiixp_speedproc(drive, speed);
-	}
+	if (ide_use_fast_pio(drive))
+		ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -250,7 +248,7 @@
 		hwif->irq = ch ? 15 : 14;
 
 	hwif->autodma = 0;
-	hwif->tuneproc = &atiixp_tuneproc;
+	hwif->set_pio_mode = &atiixp_set_pio_mode;
 	hwif->speedproc = &atiixp_speedproc;
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
@@ -285,17 +283,18 @@
 	{	/* 0 */
 		.name		= "ATIIXP",
 		.init_hwif	= init_hwif_atiixp,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
 		.bootable	= ON_BOARD,
+		.pio_mask	= ATA_PIO4,
 	},{	/* 1 */
 		.name		= "SB600_PATA",
 		.init_hwif	= init_hwif_atiixp,
-		.channels	= 1,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x48,0x01,0x00}, {0x00,0x00,0x00}},
  		.bootable	= ON_BOARD,
+ 		.host_flags	= IDE_HFLAG_SINGLE,
+		.pio_mask	= ATA_PIO4,
  	},
 };
 
@@ -318,7 +317,7 @@
 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
-	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+	{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP700_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ 0, },
 };
 MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl);
diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
index dc43f00..f369645 100644
--- a/drivers/ide/pci/cmd640.c
+++ b/drivers/ide/pci/cmd640.c
@@ -628,50 +628,42 @@
 	program_drive_counts (index);
 }
 
-/*
- * Drive PIO mode selection:
- */
-static void cmd640_tune_drive (ide_drive_t *drive, u8 mode_wanted)
+static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
+	unsigned int index = 0, cycle_time;
 	u8 b;
-	ide_pio_data_t  d;
-	unsigned int index = 0;
 
 	while (drive != cmd_drives[index]) {
 		if (++index > 3) {
-			printk("%s: bad news in cmd640_tune_drive\n", drive->name);
+			printk(KERN_ERR "%s: bad news in %s\n",
+					drive->name, __FUNCTION__);
 			return;
 		}
 	}
-	switch (mode_wanted) {
+	switch (pio) {
 		case 6: /* set fast-devsel off */
 		case 7: /* set fast-devsel on */
-			mode_wanted &= 1;
 			b = get_cmd640_reg(CNTRL) & ~0x27;
-			if (mode_wanted)
+			if (pio & 1)
 				b |= 0x27;
 			put_cmd640_reg(CNTRL, b);
-			printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis");
+			printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, (pio & 1) ? "en" : "dis");
 			return;
 
 		case 8: /* set prefetch off */
 		case 9: /* set prefetch on */
-			mode_wanted &= 1;
-			set_prefetch_mode(index, mode_wanted);
-			printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
+			set_prefetch_mode(index, pio & 1);
+			printk("%s: %sabled cmd640 prefetch\n", drive->name, (pio & 1) ? "en" : "dis");
 			return;
 	}
 
-	(void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
-	cmd640_set_mode (index, d.pio_mode, d.cycle_time);
+	cycle_time = ide_pio_cycle_time(drive, pio);
+	cmd640_set_mode(index, pio, cycle_time);
 
-	printk ("%s: selected cmd640 PIO mode%d (%dns)%s",
-		drive->name,
-		d.pio_mode,
-		d.cycle_time,
-		d.overridden ? " (overriding vendor mode)" : "");
+	printk("%s: selected cmd640 PIO mode%d (%dns)",
+		drive->name, pio, cycle_time);
+
 	display_clocks(index);
-	return;
 }
 
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
@@ -769,7 +761,10 @@
 	       cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
 	cmd_hwif0->chipset = ide_cmd640;
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-	cmd_hwif0->tuneproc = &cmd640_tune_drive;
+	cmd_hwif0->host_flags = IDE_HFLAG_ABUSE_PREFETCH |
+				IDE_HFLAG_ABUSE_FAST_DEVSEL;
+	cmd_hwif0->pio_mask = ATA_PIO5;
+	cmd_hwif0->set_pio_mode = &cmd640_set_pio_mode;
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 
 	/*
@@ -824,7 +819,10 @@
 		cmd_hwif1->mate = cmd_hwif0;
 		cmd_hwif1->channel = 1;
 #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
-		cmd_hwif1->tuneproc = &cmd640_tune_drive;
+		cmd_hwif1->host_flags = IDE_HFLAG_ABUSE_PREFETCH |
+					IDE_HFLAG_ABUSE_FAST_DEVSEL;
+		cmd_hwif1->pio_mask = ATA_PIO5;
+		cmd_hwif1->set_pio_mode = &cmd640_set_pio_mode;
 #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
 	}
 	printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index 1e89dd6..0b568c6 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -214,27 +214,25 @@
 }
 
 /*
- * This routine selects drive's best PIO mode and writes into the chipset
- * registers setup/active/recovery timings.
+ * This routine writes into the chipset registers
+ * PIO setup/active/recovery timings.
  */
-static u8 cmd64x_tune_pio (ide_drive_t *drive, u8 mode_wanted)
+static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
-	ide_pio_data_t pio;
-	u8 pio_mode, setup_count, arttim = 0;
+	unsigned int cycle_time;
+	u8 setup_count, arttim = 0;
+
 	static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0};
 	static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
-	pio_mode = ide_get_best_pio_mode(drive, mode_wanted, 5, &pio);
 
-	cmdprintk("%s: PIO mode wanted %d, selected %d (%d ns)%s\n",
-		  drive->name, mode_wanted, pio_mode, pio.cycle_time,
-		  pio.overridden ? " (overriding vendor mode)" : "");
+	cycle_time = ide_pio_cycle_time(drive, pio);
 
-	program_cycle_times(drive, pio.cycle_time,
-			    ide_pio_timings[pio_mode].active_time);
+	program_cycle_times(drive, cycle_time,
+			    ide_pio_timings[pio].active_time);
 
-	setup_count = quantize_timing(ide_pio_timings[pio_mode].setup_time,
+	setup_count = quantize_timing(ide_pio_timings[pio].setup_time,
 				      1000 / system_bus_clock());
 
 	/*
@@ -265,16 +263,14 @@
 	arttim |= setup_values[setup_count];
 	(void) pci_write_config_byte(dev, arttim_regs[drive->dn], arttim);
 	cmdprintk("Write 0x%02x to reg 0x%x\n", arttim, arttim_regs[drive->dn]);
-
-	return pio_mode;
 }
 
 /*
  * Attempts to set drive's PIO mode.
- * Special cases are 8: prefetch off, 9: prefetch on (both never worked),
- * and 255: auto-select best mode (used at boot time).
+ * Special cases are 8: prefetch off, 9: prefetch on (both never worked)
  */
-static void cmd64x_tune_drive (ide_drive_t *drive, u8 pio)
+
+static void cmd64x_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
 	/*
 	 * Filter out the prefetch control values
@@ -283,19 +279,17 @@
 	if (pio == 8 || pio == 9)
 		return;
 
-	pio = cmd64x_tune_pio(drive, pio);
+	cmd64x_tune_pio(drive, pio);
 	(void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
-static int cmd64x_tune_chipset (ide_drive_t *drive, u8 speed)
+static int cmd64x_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
 	u8 unit			= drive->dn & 0x01;
 	u8 regU = 0, pciU	= hwif->channel ? UDIDETCR1 : UDIDETCR0;
 
-	speed = ide_rate_filter(drive, speed);
-
 	if (speed >= XFER_SW_DMA_0) {
 		(void) pci_read_config_byte(dev, pciU, &regU);
 		regU &= ~(unit ? 0xCA : 0x35);
@@ -329,14 +323,6 @@
 	case XFER_MW_DMA_0:
 		program_cycle_times(drive, 480, 215);
 		break;
-	case XFER_PIO_5:
-	case XFER_PIO_4:
-	case XFER_PIO_3:
-	case XFER_PIO_2:
-	case XFER_PIO_1:
-	case XFER_PIO_0:
-		(void) cmd64x_tune_pio(drive, speed - XFER_PIO_0);
-		break;
 	default:
 		return 1;
 	}
@@ -353,7 +339,7 @@
 		return 0;
 
 	if (ide_use_fast_pio(drive))
-		cmd64x_tune_drive(drive, 255);
+		ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -474,11 +460,11 @@
 		switch (rev) {
 		case 0x07:
 		case 0x05:
-			printk("%s: UltraDMA capable", name);
+			printk("%s: UltraDMA capable\n", name);
 			break;
 		case 0x03:
 		default:
-			printk("%s: MultiWord DMA force limited", name);
+			printk("%s: MultiWord DMA force limited\n", name);
 			break;
 		case 0x01:
 			printk("%s: MultiWord DMA limited, "
@@ -537,7 +523,7 @@
 
 	pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
 
-	hwif->tuneproc  = &cmd64x_tune_drive;
+	hwif->set_pio_mode = &cmd64x_set_pio_mode;
 	hwif->speedproc = &cmd64x_tune_chipset;
 
 	hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
@@ -618,40 +604,44 @@
 		.init_setup	= init_setup_cmd64x,
 		.init_chipset	= init_chipset_cmd64x,
 		.init_hwif	= init_hwif_cmd64x,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x00,0x00,0x00}, {0x51,0x08,0x08}},
 		.bootable	= ON_BOARD,
+		.host_flags	= IDE_HFLAG_ABUSE_PREFETCH,
+		.pio_mask	= ATA_PIO5,
 		.udma_mask	= 0x00, /* no udma */
 	},{	/* 1 */
 		.name		= "CMD646",
 		.init_setup	= init_setup_cmd646,
 		.init_chipset	= init_chipset_cmd64x,
 		.init_hwif	= init_hwif_cmd64x,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
 		.bootable	= ON_BOARD,
+		.host_flags	= IDE_HFLAG_ABUSE_PREFETCH,
+		.pio_mask	= ATA_PIO5,
 		.udma_mask	= 0x07, /* udma0-2 */
 	},{	/* 2 */
 		.name		= "CMD648",
 		.init_setup	= init_setup_cmd64x,
 		.init_chipset	= init_chipset_cmd64x,
 		.init_hwif	= init_hwif_cmd64x,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
 		.bootable	= ON_BOARD,
+		.host_flags	= IDE_HFLAG_ABUSE_PREFETCH,
+		.pio_mask	= ATA_PIO5,
 		.udma_mask	= 0x1f, /* udma0-4 */
 	},{	/* 3 */
 		.name		= "CMD649",
 		.init_setup	= init_setup_cmd64x,
 		.init_chipset	= init_chipset_cmd64x,
 		.init_hwif	= init_hwif_cmd64x,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x51,0x04,0x04}, {0x51,0x08,0x08}},
 		.bootable	= ON_BOARD,
+		.host_flags	= IDE_HFLAG_ABUSE_PREFETCH,
+		.pio_mask	= ATA_PIO5,
 		.udma_mask	= 0x3f, /* udma0-5 */
 	}
 };
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
index 3b88a3a..1217d2a 100644
--- a/drivers/ide/pci/cs5520.c
+++ b/drivers/ide/pci/cs5520.c
@@ -66,32 +66,13 @@
 	{1, 2, 1}
 };
 
-static int cs5520_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static void cs5520_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
 	ide_hwif_t *hwif = HWIF(drive);
 	struct pci_dev *pdev = hwif->pci_dev;
-	u8 speed = min((u8)XFER_PIO_4, xferspeed);
-	int pio = speed;
-	u8 reg;
 	int controller = drive->dn > 1 ? 1 : 0;
-	int error;
-	
-	switch(speed)
-	{
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			pio -= XFER_PIO_0;
-			break;
-		default:
-			pio = 0;
-			printk(KERN_ERR "cs55x0: bad ide timing.\n");
-	}
-	
-	printk("PIO clocking = %d\n", pio);
-	
+	u8 reg;
+
 	/* FIXME: if DMA = 1 do we need to set the DMA bit here ? */
 
 	/* 8bit CAT/CRT - 8bit command timing for channel */
@@ -115,25 +96,28 @@
 	reg = inb(hwif->dma_base + 0x02 + 8*controller);
 	reg |= 1<<((drive->dn&1)+5);
 	outb(reg, hwif->dma_base + 0x02 + 8*controller);
-		
-	error = ide_config_drive_speed(drive, speed);
-	/* ATAPI is harder so leave it for now */
-	if(!error && drive->media == ide_disk)
-		error = hwif->ide_dma_on(drive);
 
-	return error;
-}	
-	
-static void cs5520_tune_drive(ide_drive_t *drive, u8 pio)
+	(void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
+}
+
+static int cs5520_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-	cs5520_tune_chipset(drive, (XFER_PIO_0 + pio));
+	printk(KERN_ERR "cs55x0: bad ide timing.\n");
+
+	cs5520_set_pio_mode(drive, 0);
+
+	/*
+	 * FIXME: this is incorrect to return zero here but
+	 * since all users of ide_set_xfer_rate() ignore
+	 * the return value it is not a problem currently
+	 */
+	return 0;
 }
 
 static int cs5520_config_drive_xfer_rate(ide_drive_t *drive)
 {
 	/* Tune the drive for PIO modes up to PIO 4 */	
-	cs5520_tune_drive(drive, 4);
+	ide_set_max_pio(drive);
 
 	/* Then tell the core to use DMA operations */
 	return 0;
@@ -165,7 +149,7 @@
 
 static void __devinit init_hwif_cs5520(ide_hwif_t *hwif)
 {
-	hwif->tuneproc = &cs5520_tune_drive;
+	hwif->set_pio_mode = &cs5520_set_pio_mode;
 	hwif->speedproc = &cs5520_tune_chipset;
 	hwif->ide_dma_check = &cs5520_config_drive_xfer_rate;
 	hwif->ide_dma_on = &cs5520_dma_on;
@@ -179,7 +163,8 @@
 		hwif->drives[1].autotune = 1;
 		return;
 	}
-	
+
+	/* ATAPI is harder so leave it for now */
 	hwif->atapi_dma = 0;
 	hwif->ultra_mask = 0;
 	hwif->swdma_mask = 0;
@@ -194,10 +179,10 @@
 		.name		= name_str,			\
 		.init_setup_dma = cs5520_init_setup_dma,	\
 		.init_hwif	= init_hwif_cs5520,		\
-		.channels	= 2,				\
 		.autodma	= AUTODMA,			\
 		.bootable	= ON_BOARD,			\
-		.flags		= IDEPCI_FLAG_ISA_PORTS,	\
+		.host_flags	= IDE_HFLAG_ISA_PORTS,		\
+		.pio_mask	= ATA_PIO4,			\
 	}
 
 static ide_pci_device_t cyrix_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
index b5c00d1..741507b 100644
--- a/drivers/ide/pci/cs5530.c
+++ b/drivers/ide/pci/cs5530.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/cs5530.c		Version 0.73	Mar 10 2007
+ * linux/drivers/ide/pci/cs5530.c		Version 0.74	Jul 28 2007
  *
  * Copyright (C) 2000			Andre Hedrick <andre@linux-ide.org>
  * Copyright (C) 2000			Mark Lord <mlord@pobox.com>
@@ -71,19 +71,18 @@
 }
 
 /**
- *	cs5530_tuneproc		-	select/set PIO modes
+ *	cs5530_set_pio_mode	-	set PIO mode
+ *	@drive: drive
+ *	@pio: PIO mode number
  *
- *	cs5530_tuneproc() handles selection/setting of PIO modes
- *	for both the chipset and drive.
+ *	Handles setting of PIO mode for both the chipset and drive.
  *
- *	The ide_init_cs5530() routine guarantees that all drives
+ *	The init_hwif_cs5530() routine guarantees that all drives
  *	will have valid default PIO timings set up before we get here.
  */
 
-static void cs5530_tuneproc (ide_drive_t *drive, u8 pio)	/* pio=255 means "autotune" */
+static void cs5530_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-
 	if (cs5530_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0)
 		cs5530_tunepio(drive, pio);
 }
@@ -143,13 +142,11 @@
 	return 1;
 }
 
-static int cs5530_tune_chipset(ide_drive_t *drive, u8 mode)
+static int cs5530_tune_chipset(ide_drive_t *drive, const u8 mode)
 {
 	unsigned long basereg;
 	unsigned int reg, timings = 0;
 
-	mode = ide_rate_filter(drive, mode);
-
 	/*
 	 * Tell the drive to switch to the new mode; abort on failure.
 	 */
@@ -166,13 +163,6 @@
 		case XFER_MW_DMA_0:	timings = 0x00077771; break;
 		case XFER_MW_DMA_1:	timings = 0x00012121; break;
 		case XFER_MW_DMA_2:	timings = 0x00002020; break;
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			cs5530_tunepio(drive, mode - XFER_PIO_0);
-			return 0;
 		default:
 			BUG();
 			break;
@@ -207,6 +197,9 @@
 	struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
 	unsigned long flags;
 
+	if (pci_resource_start(dev, 4) == 0)
+		return -EFAULT;
+
 	dev = NULL;
 	while ((dev = pci_get_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) {
 		switch (dev->device) {
@@ -305,7 +298,7 @@
 	if (hwif->mate)
 		hwif->serialized = hwif->mate->serialized = 1;
 
-	hwif->tuneproc = &cs5530_tuneproc;
+	hwif->set_pio_mode = &cs5530_set_pio_mode;
 	hwif->speedproc = &cs5530_tune_chipset;
 
 	basereg = CS5530_BASEREG(hwif);
@@ -325,6 +318,9 @@
 			/* needs autotuning later */
 	}
 
+	if (hwif->dma_base == 0)
+		return;
+
 	hwif->atapi_dma = 1;
 	hwif->ultra_mask = 0x07;
 	hwif->mwdma_mask = 0x07;
@@ -341,9 +337,9 @@
 	.name		= "CS5530",
 	.init_chipset	= init_chipset_cs5530,
 	.init_hwif	= init_hwif_cs5530,
-	.channels	= 2,
 	.autodma	= AUTODMA,
 	.bootable	= ON_BOARD,
+	.pio_mask	= ATA_PIO4,
 };
 
 static int __devinit cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c
index 10f61f3..383b7ec 100644
--- a/drivers/ide/pci/cs5535.c
+++ b/drivers/ide/pci/cs5535.c
@@ -2,6 +2,7 @@
  * linux/drivers/ide/pci/cs5535.c
  *
  * Copyright (C) 2004-2005 Advanced Micro Devices, Inc.
+ * Copyright (C)      2007 Bartlomiej Zolnierkiewicz
  *
  * History:
  * 09/20/2005 - Jaya Kumar <jayakumar.ide@gmail.com>
@@ -74,7 +75,7 @@
  *
  *	cs5535_set_speed() configures the chipset to a new speed.
  */
-static void cs5535_set_speed(ide_drive_t *drive, u8 speed)
+static void cs5535_set_speed(ide_drive_t *drive, const u8 speed)
 {
 
 	u32 reg = 0, dummy;
@@ -83,14 +84,17 @@
 
 	/* Set the PIO timings */
 	if ((speed & XFER_MODE) == XFER_PIO) {
-		u8 pioa;
-		u8 piob;
-		u8 cmd;
+		ide_drive_t *pair = &drive->hwif->drives[drive->dn ^ 1];
+		u8 cmd, pioa;
 
-		pioa = speed - XFER_PIO_0;
-		piob = ide_get_best_pio_mode(&(drive->hwif->drives[!unit]),
-						255, 4, NULL);
-		cmd = pioa < piob ? pioa : piob;
+		cmd = pioa = speed - XFER_PIO_0;
+
+		if (pair->present) {
+			u8 piob = ide_get_best_pio_mode(pair, 255, 4);
+
+			if (piob < cmd)
+				cmd = piob;
+		}
 
 		/* Write the speed of the current drive */
 		reg = (cs5535_pio_cmd_timings[cmd] << 16) |
@@ -116,7 +120,7 @@
 
 		reg &= 0x80000000UL;  /* Preserve the PIO format bit */
 
-		if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_7)
+		if (speed >= XFER_UDMA_0 && speed <= XFER_UDMA_4)
 			reg |= cs5535_udma_timings[speed - XFER_UDMA_0];
 		else if (speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2)
 			reg |= cs5535_mwdma_timings[speed - XFER_MW_DMA_0];
@@ -137,46 +141,35 @@
  */
 static int cs5535_set_drive(ide_drive_t *drive, u8 speed)
 {
-	speed = ide_rate_filter(drive, speed);
 	ide_config_drive_speed(drive, speed);
 	cs5535_set_speed(drive, speed);
 
 	return 0;
 }
 
-/****
- *	cs5535_tuneproc    -       PIO setup
- *	@drive: drive to set up
- *	@pio: mode to use (255 for 'best possible')
+/**
+ *	cs5535_set_pio_mode	-	PIO setup
+ *	@drive: drive
+ *	@pio: PIO mode number
  *
  *	A callback from the upper layers for PIO-only tuning.
  */
-static void cs5535_tuneproc(ide_drive_t *drive, u8 xferspeed)
-{
-	u8 modes[] = {	XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3,
-			XFER_PIO_4 };
 
-	/* cs5535 max pio is pio 4, best_pio will check the blacklist.
-	i think we don't need to rate_filter the incoming xferspeed
-	since we know we're only going to choose pio */
-	xferspeed = ide_get_best_pio_mode(drive, xferspeed, 4, NULL);
-	ide_config_drive_speed(drive, modes[xferspeed]);
-	cs5535_set_speed(drive, xferspeed);
+static void cs5535_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+	ide_config_drive_speed(drive, XFER_PIO_0 + pio);
+	cs5535_set_speed(drive, XFER_PIO_0 + pio);
 }
 
 static int cs5535_dma_check(ide_drive_t *drive)
 {
-	u8 speed;
-
 	drive->init_speed = 0;
 
 	if (ide_tune_dma(drive))
 		return 0;
 
-	if (ide_use_fast_pio(drive)) {
-		speed = ide_get_best_pio_mode(drive, 255, 4, NULL);
-		cs5535_set_drive(drive, speed);
-	}
+	if (ide_use_fast_pio(drive))
+		ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -205,7 +198,7 @@
 
 	hwif->autodma = 0;
 
-	hwif->tuneproc = &cs5535_tuneproc;
+	hwif->set_pio_mode = &cs5535_set_pio_mode;
 	hwif->speedproc = &cs5535_set_drive;
 	hwif->ide_dma_check = &cs5535_dma_check;
 
@@ -228,9 +221,10 @@
 static ide_pci_device_t cs5535_chipset __devinitdata = {
 	.name		= "CS5535",
 	.init_hwif	= init_hwif_cs5535,
-	.channels	= 1,
 	.autodma	= AUTODMA,
 	.bootable	= ON_BOARD,
+	.host_flags	= IDE_HFLAG_SINGLE,
+	.pio_mask	= ATA_PIO4,
 };
 
 static int __devinit cs5535_init_one(struct pci_dev *dev,
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
index 103b9db..dc27802 100644
--- a/drivers/ide/pci/cy82c693.c
+++ b/drivers/ide/pci/cy82c693.c
@@ -97,9 +97,6 @@
 #define CY82_INDEX_CHANNEL1	0x31
 #define CY82_INDEX_TIMEOUT	0x32
 
-/* the max PIO mode - from datasheet */
-#define CY82C693_MAX_PIO	4
-
 /* the min and max PCI bus speed in MHz - from datasheet */
 #define CY82C963_MIN_BUS_SPEED	25
 #define CY82C963_MAX_BUS_SPEED	33
@@ -148,9 +145,6 @@
 	 * so you can play with the idebus=xx parameter
 	 */
 
-	if (pio > CY82C693_MAX_PIO)
-		pio = CY82C693_MAX_PIO;
-
 	/* let's calc the address setup time clocks */
 	p_pclk->address_time = (u8)calc_clk(ide_pio_timings[pio].setup_time, bus_speed);
 
@@ -269,10 +263,7 @@
         return __ide_dma_on(drive);
 }
 
-/*
- * tune ide drive - set PIO mode
- */
-static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio)
+static void cy82c693_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
 	ide_hwif_t *hwif = HWIF(drive);
 	struct pci_dev *dev = hwif->pci_dev;
@@ -329,13 +320,6 @@
 		addrCtrl, pclk.time_16r, pclk.time_16w, pclk.time_8);
 #endif /* CY82C693_DEBUG_LOGS */
 
-	/* first let's calc the pio modes */
-	pio = ide_get_best_pio_mode(drive, pio, CY82C693_MAX_PIO, NULL);
-
-#if CY82C693_DEBUG_INFO
-	printk (KERN_INFO "%s: Selected PIO mode %d\n", drive->name, pio);
-#endif /* CY82C693_DEBUG_INFO */
-
 	/* let's calc the values for this PIO mode */
 	compute_clocks(pio, &pclk);
 
@@ -447,7 +431,7 @@
 	hwif->autodma = 0;
 
 	hwif->chipset = ide_cy82c693;
-	hwif->tuneproc = &cy82c693_tune_drive;
+	hwif->set_pio_mode = &cy82c693_set_pio_mode;
 
 	if (!hwif->dma_base) {
 		hwif->drives[0].autotune = 1;
@@ -483,9 +467,10 @@
 	.init_chipset	= init_chipset_cy82c693,
 	.init_iops	= init_iops_cy82c693,
 	.init_hwif	= init_hwif_cy82c693,
-	.channels	= 1,
 	.autodma	= AUTODMA,
 	.bootable	= ON_BOARD,
+	.host_flags	= IDE_HFLAG_SINGLE,
+	.pio_mask	= ATA_PIO4,
 };
 
 static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
index 0d51a11..48caa46 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/pci/generic.c
@@ -95,92 +95,77 @@
 	{	/* 0 */
 		.name		= "Unknown",
 		.init_hwif	= init_hwif_generic,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= ON_BOARD,
 	},{	/* 1 */
 		.name		= "NS87410",
 		.init_hwif	= init_hwif_generic,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
 		.bootable	= ON_BOARD,
         },{	/* 2 */
 		.name		= "SAMURAI",
 		.init_hwif	= init_hwif_generic,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= ON_BOARD,
 	},{	/* 3 */
 		.name		= "HT6565",
 		.init_hwif	= init_hwif_generic,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= ON_BOARD,
 	},{	/* 4 */
 		.name		= "UM8673F",
 		.init_hwif	= init_hwif_generic,
-		.channels	= 2,
 		.autodma	= NODMA,
 		.bootable	= ON_BOARD,
 	},{	/* 5 */
 		.name		= "UM8886A",
 		.init_hwif	= init_hwif_generic,
-		.channels	= 2,
 		.autodma	= NODMA,
 		.bootable	= ON_BOARD,
 	},{	/* 6 */
 		.name		= "UM8886BF",
 		.init_hwif	= init_hwif_generic,
-		.channels	= 2,
 		.autodma	= NODMA,
 		.bootable	= ON_BOARD,
 	},{	/* 7 */
 		.name		= "HINT_IDE",
 		.init_hwif	= init_hwif_generic,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= ON_BOARD,
 	},{	/* 8 */
 		.name		= "VIA_IDE",
 		.init_hwif	= init_hwif_generic,
-		.channels	= 2,
 		.autodma	= NOAUTODMA,
 		.bootable	= ON_BOARD,
 	},{	/* 9 */
 		.name		= "OPTI621V",
 		.init_hwif	= init_hwif_generic,
-		.channels	= 2,
 		.autodma	= NOAUTODMA,
 		.bootable	= ON_BOARD,
 	},{	/* 10 */
 		.name		= "VIA8237SATA",
 		.init_hwif	= init_hwif_generic,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
 	},{	/* 11 */
 		.name 		= "Piccolo0102",
 		.init_hwif	= init_hwif_generic,
-		.channels	= 2,
 		.autodma	= NOAUTODMA,
 		.bootable	= ON_BOARD,
 	},{	/* 12 */
 		.name 		= "Piccolo0103",
 		.init_hwif	= init_hwif_generic,
-		.channels	= 2,
 		.autodma	= NOAUTODMA,
 		.bootable	= ON_BOARD,
 	},{	/* 13 */
 		.name 		= "Piccolo0105",
 		.init_hwif	= init_hwif_generic,
-		.channels	= 2,
 		.autodma	= NOAUTODMA,
 		.bootable	= ON_BOARD,
 	},{	/* 14 */
 		.name		= "Revolution",
 		.init_hwif	= init_hwif_generic,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
 	}
diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
index 2c24c3d..a1bb101 100644
--- a/drivers/ide/pci/hpt34x.c
+++ b/drivers/ide/pci/hpt34x.c
@@ -43,10 +43,9 @@
 
 #define HPT343_DEBUG_DRIVE_INFO		0
 
-static int hpt34x_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static int hpt34x_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	struct pci_dev *dev	= HWIF(drive)->pci_dev;
-	u8 speed = ide_rate_filter(drive, xferspeed);
 	u32 reg1= 0, tmp1 = 0, reg2 = 0, tmp2 = 0;
 	u8			hi_speed, lo_speed;
 
@@ -78,9 +77,8 @@
 	return(ide_config_drive_speed(drive, speed));
 }
 
-static void hpt34x_tune_drive (ide_drive_t *drive, u8 pio)
+static void hpt34x_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
 	(void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio));
 }
 
@@ -89,14 +87,10 @@
 	drive->init_speed = 0;
 
 	if (ide_tune_dma(drive))
-#ifndef CONFIG_HPT34X_AUTODMA
 		return -1;
-#else
-		return 0;
-#endif
 
 	if (ide_use_fast_pio(drive))
-		hpt34x_tune_drive(drive, 255);
+		ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -120,17 +114,10 @@
 	pci_write_config_byte(dev, HPT34X_PCI_INIT_REG, 0x00);
 	pci_read_config_word(dev, PCI_COMMAND, &cmd);
 
-	if (cmd & PCI_COMMAND_MEMORY) {
-		if (pci_resource_start(dev, PCI_ROM_RESOURCE)) {
-			pci_write_config_dword(dev, PCI_ROM_ADDRESS,
-				dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-			printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n",
-				(unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
-		}
+	if (cmd & PCI_COMMAND_MEMORY)
 		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
-	} else {
+	else
 		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
-	}
 
 	/*
 	 * Since 20-23 can be assigned and are R/W, we correct them.
@@ -157,7 +144,7 @@
 
 	hwif->autodma = 0;
 
-	hwif->tuneproc = &hpt34x_tune_drive;
+	hwif->set_pio_mode = &hpt34x_set_pio_mode;
 	hwif->speedproc = &hpt34x_tune_chipset;
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
@@ -167,9 +154,11 @@
 	if (!hwif->dma_base)
 		return;
 
+#ifdef CONFIG_HPT34X_AUTODMA
 	hwif->ultra_mask = 0x07;
 	hwif->mwdma_mask = 0x07;
 	hwif->swdma_mask = 0x07;
+#endif
 
 	hwif->ide_dma_check = &hpt34x_config_drive_xfer_rate;
 	if (!noautodma)
@@ -182,10 +171,10 @@
 	.name		= "HPT34X",
 	.init_chipset	= init_chipset_hpt34x,
 	.init_hwif	= init_hwif_hpt34x,
-	.channels	= 2,
 	.autodma	= NOAUTODMA,
 	.bootable	= NEVER_BOARD,
-	.extra		= 16
+	.extra		= 16,
+	.pio_mask	= ATA_PIO5,
 };
 
 static int __devinit hpt34x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index e9b07a9..0e7d3b6 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/hpt366.c		Version 1.10	Jun 29, 2007
+ * linux/drivers/ide/pci/hpt366.c		Version 1.13	Sep 29, 2007
  *
  * Copyright (C) 1999-2003		Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001	        Sun Microsystems, Inc.
@@ -68,7 +68,8 @@
  *   HPT37x chip family; save space by introducing the separate transfer mode
  *   table in which the mode lookup is done
  * - use f_CNT value saved by  the HighPoint BIOS as reading it directly gives
- *   the wrong PCI frequency since DPLL has already been calibrated by BIOS
+ *   the wrong PCI frequency since DPLL has already been calibrated by BIOS;
+ *   read it only from the function 0 of HPT374 chips
  * - fix the hotswap code:  it caused RESET- to glitch when tristating the bus,
  *   and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead
  * - pass to init_chipset() handlers a copy of the IDE PCI device structure as
@@ -113,6 +114,7 @@
  *   unify HPT36x/37x timing setup code and the speedproc handlers by joining
  *   the register setting lists into the table indexed by the clock selected
  * - set the correct hwif->ultra_mask for each individual chip
+ * - add Ultra and MW DMA mode filtering for the HPT37[24] based SATA cards
  *	Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com>
  */
 
@@ -517,47 +519,67 @@
 }
 
 /*
- *	Note for the future; the SATA hpt37x we must set
- *	either PIO or UDMA modes 0,4,5
+ * The Marvell bridge chips used on the HighPoint SATA cards do not seem
+ * to support the UltraDMA modes 1, 2, and 3 as well as any MWDMA modes...
  */
 
 static u8 hpt3xx_udma_filter(ide_drive_t *drive)
 {
-	struct hpt_info *info	= pci_get_drvdata(HWIF(drive)->pci_dev);
-	u8 mask;
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hpt_info *info	= pci_get_drvdata(hwif->pci_dev);
+	u8 mask 		= hwif->ultra_mask;
 
 	switch (info->chip_type) {
-	case HPT370A:
-		if (!HPT370_ALLOW_ATA100_5 ||
-		    check_in_drive_list(drive, bad_ata100_5))
-			return 0x1f;
-		else
-			return 0x3f;
-	case HPT370:
-		if (!HPT370_ALLOW_ATA100_5 ||
-		    check_in_drive_list(drive, bad_ata100_5))
-			mask = 0x1f;
-		else
-			mask = 0x3f;
-		break;
 	case HPT36x:
 		if (!HPT366_ALLOW_ATA66_4 ||
 		    check_in_drive_list(drive, bad_ata66_4))
-			mask = 0x0f;
-		else
-			mask = 0x1f;
+			mask = ATA_UDMA3;
 
 		if (!HPT366_ALLOW_ATA66_3 ||
 		    check_in_drive_list(drive, bad_ata66_3))
-			mask = 0x07;
+			mask = ATA_UDMA2;
 		break;
+	case HPT370:
+		if (!HPT370_ALLOW_ATA100_5 ||
+		    check_in_drive_list(drive, bad_ata100_5))
+			mask = ATA_UDMA4;
+		break;
+	case HPT370A:
+		if (!HPT370_ALLOW_ATA100_5 ||
+		    check_in_drive_list(drive, bad_ata100_5))
+			return ATA_UDMA4;
+	case HPT372 :
+	case HPT372A:
+	case HPT372N:
+	case HPT374 :
+		if (ide_dev_is_sata(drive->id))
+			mask &= ~0x0e;
+		/* Fall thru */
 	default:
-		return 0x7f;
+		return mask;
 	}
 
 	return check_in_drive_list(drive, bad_ata33) ? 0x00 : mask;
 }
 
+static u8 hpt3xx_mdma_filter(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif	= HWIF(drive);
+	struct hpt_info *info	= pci_get_drvdata(hwif->pci_dev);
+
+	switch (info->chip_type) {
+	case HPT372 :
+	case HPT372A:
+	case HPT372N:
+	case HPT374 :
+		if (ide_dev_is_sata(drive->id))
+			return 0x00;
+		/* Fall thru */
+	default:
+		return 0x07;
+	}
+}
+
 static u32 get_speed_setting(u8 speed, struct hpt_info *info)
 {
 	int i;
@@ -578,20 +600,15 @@
 	return (*info->settings)[i];
 }
 
-static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int hpt36x_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev  *dev	= hwif->pci_dev;
 	struct hpt_info	*info	= pci_get_drvdata(dev);
-	u8  speed		= ide_rate_filter(drive, xferspeed);
 	u8  itr_addr		= drive->dn ? 0x44 : 0x40;
 	u32 old_itr		= 0;
 	u32 itr_mask, new_itr;
 
-	/* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */
-	if (drive->media != ide_disk)
-		speed = min_t(u8, speed, XFER_PIO_4);
-
 	itr_mask = speed < XFER_MW_DMA_0 ? 0x30070000 :
 		  (speed < XFER_UDMA_0   ? 0xc0070000 : 0xc03800ff);
 
@@ -610,20 +627,15 @@
 	return ide_config_drive_speed(drive, speed);
 }
 
-static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int hpt37x_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev  *dev	= hwif->pci_dev;
 	struct hpt_info	*info	= pci_get_drvdata(dev);
-	u8  speed		= ide_rate_filter(drive, xferspeed);
 	u8  itr_addr		= 0x40 + (drive->dn * 4);
 	u32 old_itr		= 0;
 	u32 itr_mask, new_itr;
 
-	/* TODO: move this to ide_rate_filter() [ check ->atapi_dma ] */
-	if (drive->media != ide_disk)
-		speed = min_t(u8, speed, XFER_PIO_4);
-
 	itr_mask = speed < XFER_MW_DMA_0 ? 0x303c0000 :
 		  (speed < XFER_UDMA_0   ? 0xc03c0000 : 0xc1c001ff);
 
@@ -650,9 +662,8 @@
 		return hpt36x_tune_chipset(drive, speed);
 }
 
-static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio)
+static void hpt3xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
 	(void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
 }
 
@@ -714,7 +725,7 @@
 		return 0;
 
 	if (ide_use_fast_pio(drive))
-		hpt3xx_tune_drive(drive, 255);
+		ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -981,6 +992,7 @@
 	struct hpt_info *info	= kmalloc(sizeof(struct hpt_info), GFP_KERNEL);
 	unsigned long io_base	= pci_resource_start(dev, 4);
 	u8 pci_clk,  dpll_clk	= 0;	/* PCI and DPLL clock in MHz */
+	u8 chip_type;
 	enum ata_clock	clock;
 
 	if (info == NULL) {
@@ -992,15 +1004,8 @@
 	 * Copy everything from a static "template" structure
 	 * to just allocated per-chip hpt_info structure.
 	 */
-	*info = *(struct hpt_info *)pci_get_drvdata(dev);
-
-	/*
-	 * FIXME: Not portable. Also, why do we enable the ROM in the first place?
-	 * We don't seem to be using it.
-	 */
-	if (dev->resource[PCI_ROM_RESOURCE].start)
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS,
-			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+	memcpy(info, pci_get_drvdata(dev), sizeof(struct hpt_info));
+	chip_type = info->chip_type;
 
 	pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
 	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
@@ -1010,7 +1015,7 @@
 	/*
 	 * First, try to estimate the PCI clock frequency...
 	 */
-	if (info->chip_type >= HPT370) {
+	if (chip_type >= HPT370) {
 		u8  scr1  = 0;
 		u16 f_cnt = 0;
 		u32 temp  = 0;
@@ -1024,7 +1029,7 @@
 		 * HighPoint does this for HPT372A.
 		 * NOTE: This register is only writeable via I/O space.
 		 */
-		if (info->chip_type == HPT372A)
+		if (chip_type == HPT372A)
 			outb(0x0e, io_base + 0x9c);
 
 		/*
@@ -1042,13 +1047,28 @@
 		 * First try reading the register in which the HighPoint BIOS
 		 * saves f_CNT value before  reprogramming the DPLL from its
 		 * default setting (which differs for the various chips).
-		 * NOTE: This register is only accessible via I/O space.
 		 *
-		 * In case the signature check fails, we'll have to resort to
-		 * reading the f_CNT register itself in hopes that nobody has
-		 * touched the DPLL yet...
+		 * NOTE: This register is only accessible via I/O space;
+		 * HPT374 BIOS only saves it for the function 0, so we have to
+		 * always read it from there -- no need to check the result of
+		 * pci_get_slot() for the function 0 as the whole device has
+		 * been already "pinned" (via function 1) in init_setup_hpt374()
 		 */
-		temp = inl(io_base + 0x90);
+		if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
+			struct pci_dev	*dev1 = pci_get_slot(dev->bus,
+							     dev->devfn - 1);
+			unsigned long io_base = pci_resource_start(dev1, 4);
+
+			temp =	inl(io_base + 0x90);
+			pci_dev_put(dev1);
+		} else
+			temp =	inl(io_base + 0x90);
+
+		/*
+		 * In case the signature check fails, we'll have to
+		 * resort to reading the f_CNT register itself in hopes
+		 * that nobody has touched the DPLL yet...
+		 */
 		if ((temp & 0xFFFFF000) != 0xABCDE000) {
 			int i;
 
@@ -1128,7 +1148,7 @@
 	 * We also  don't like using  the DPLL because this causes glitches
 	 * on PRST-/SRST- when the state engine gets reset...
 	 */
-	if (info->chip_type >= HPT374 || info->settings[clock] == NULL) {
+	if (chip_type >= HPT374 || info->settings[clock] == NULL) {
 		u16 f_low, delta = pci_clk < 50 ? 2 : 4;
 		int adjust;
 
@@ -1198,7 +1218,7 @@
 	/* Point to this chip's own instance of the hpt_info structure. */
 	pci_set_drvdata(dev, info);
 
-	if (info->chip_type >= HPT370) {
+	if (chip_type >= HPT370) {
 		u8  mcr1, mcr4;
 
 		/*
@@ -1217,7 +1237,7 @@
 	 * the MISC. register to stretch the UltraDMA Tss timing.
 	 * NOTE: This register is only writeable via I/O space.
 	 */
-	if (info->chip_type == HPT371N && clock == ATA_CLOCK_66MHZ)
+	if (chip_type == HPT371N && clock == ATA_CLOCK_66MHZ)
 
 		outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c);
 
@@ -1226,25 +1246,25 @@
 
 static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
 {
-	struct pci_dev	*dev		= hwif->pci_dev;
-	struct hpt_info *info		= pci_get_drvdata(dev);
-	int serialize			= HPT_SERIALIZE_IO;
-	u8  scr1 = 0, ata66		= hwif->channel ? 0x01 : 0x02;
-	u8  chip_type			= info->chip_type;
-	u8  new_mcr, old_mcr 		= 0;
+	struct pci_dev	*dev	= hwif->pci_dev;
+	struct hpt_info *info	= pci_get_drvdata(dev);
+	int serialize		= HPT_SERIALIZE_IO;
+	u8  scr1 = 0, ata66	= hwif->channel ? 0x01 : 0x02;
+	u8  chip_type		= info->chip_type;
+	u8  new_mcr, old_mcr	= 0;
 
 	/* Cache the channel's MISC. control registers' offset */
-	hwif->select_data		= hwif->channel ? 0x54 : 0x50;
+	hwif->select_data	= hwif->channel ? 0x54 : 0x50;
 
-	hwif->tuneproc			= &hpt3xx_tune_drive;
-	hwif->speedproc			= &hpt3xx_tune_chipset;
-	hwif->quirkproc			= &hpt3xx_quirkproc;
-	hwif->intrproc			= &hpt3xx_intrproc;
-	hwif->maskproc			= &hpt3xx_maskproc;
-	hwif->busproc			= &hpt3xx_busproc;
+	hwif->set_pio_mode	= &hpt3xx_set_pio_mode;
+	hwif->speedproc		= &hpt3xx_tune_chipset;
+	hwif->quirkproc		= &hpt3xx_quirkproc;
+	hwif->intrproc		= &hpt3xx_intrproc;
+	hwif->maskproc		= &hpt3xx_maskproc;
+	hwif->busproc		= &hpt3xx_busproc;
 
-	if (chip_type <= HPT370A)
-		hwif->udma_filter	= &hpt3xx_udma_filter;
+	hwif->udma_filter	= &hpt3xx_udma_filter;
+	hwif->mdma_filter	= &hpt3xx_mdma_filter;
 
 	/*
 	 * HPT3xxN chips have some complications:
@@ -1491,22 +1511,22 @@
 		 * to both functions -- really stupid design decision... :-(
 		 * Bit 4 is for the primary channel, bit 5 for the secondary.
 		 */
-		d->channels = 1;
+		d->host_flags |= IDE_HFLAG_SINGLE;
 		d->enablebits[0].mask = d->enablebits[0].val = 0x10;
 
-		d->udma_mask = HPT366_ALLOW_ATA66_3 ?
-			      (HPT366_ALLOW_ATA66_4 ? 0x1f : 0x0f) : 0x07;
+		d->udma_mask = HPT366_ALLOW_ATA66_3 ? (HPT366_ALLOW_ATA66_4 ?
+			       ATA_UDMA4 : ATA_UDMA3) : ATA_UDMA2;
 		break;
 	case 3:
 	case 4:
-		d->udma_mask = HPT370_ALLOW_ATA100_5 ? 0x3f : 0x1f;
+		d->udma_mask = HPT370_ALLOW_ATA100_5 ? ATA_UDMA5 : ATA_UDMA4;
 		break;
 	default:
 		rev = 6;
 		/* fall thru */
 	case 5:
 	case 6:
-		d->udma_mask = HPT372_ALLOW_ATA133_6 ? 0x7f : 0x3f;
+		d->udma_mask = HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5;
 		break;
 	}
 
@@ -1554,71 +1574,71 @@
 		.init_chipset	= init_chipset_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
 		.bootable	= OFF_BOARD,
-		.extra		= 240
+		.extra		= 240,
+		.pio_mask	= ATA_PIO4,
 	},{	/* 1 */
 		.name		= "HPT372A",
 		.init_setup	= init_setup_hpt372a,
 		.init_chipset	= init_chipset_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
-		.udma_mask	= HPT372_ALLOW_ATA133_6 ? 0x7f : 0x3f,
+		.udma_mask	= HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
 		.bootable	= OFF_BOARD,
-		.extra		= 240
+		.extra		= 240,
+		.pio_mask	= ATA_PIO4,
 	},{	/* 2 */
 		.name		= "HPT302",
 		.init_setup	= init_setup_hpt302,
 		.init_chipset	= init_chipset_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
-		.udma_mask	= HPT302_ALLOW_ATA133_6 ? 0x7f : 0x3f,
+		.udma_mask	= HPT302_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
 		.bootable	= OFF_BOARD,
-		.extra		= 240
+		.extra		= 240,
+		.pio_mask	= ATA_PIO4,
 	},{	/* 3 */
 		.name		= "HPT371",
 		.init_setup	= init_setup_hpt371,
 		.init_chipset	= init_chipset_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
-		.udma_mask	= HPT371_ALLOW_ATA133_6 ? 0x7f : 0x3f,
+		.udma_mask	= HPT371_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
 		.bootable	= OFF_BOARD,
-		.extra		= 240
+		.extra		= 240,
+		.pio_mask	= ATA_PIO4,
 	},{	/* 4 */
 		.name		= "HPT374",
 		.init_setup	= init_setup_hpt374,
 		.init_chipset	= init_chipset_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
-		.channels	= 2,	/* 4 */
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
-		.udma_mask	= 0x3f,
+		.udma_mask	= ATA_UDMA5,
 		.bootable	= OFF_BOARD,
-		.extra		= 240
+		.extra		= 240,
+		.pio_mask	= ATA_PIO4,
 	},{	/* 5 */
 		.name		= "HPT372N",
 		.init_setup	= init_setup_hpt372n,
 		.init_chipset	= init_chipset_hpt366,
 		.init_hwif	= init_hwif_hpt366,
 		.init_dma	= init_dma_hpt366,
-		.channels	= 2,	/* 4 */
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
-		.udma_mask	= HPT372_ALLOW_ATA133_6 ? 0x7f : 0x3f,
+		.udma_mask	= HPT372_ALLOW_ATA133_6 ? ATA_UDMA6 : ATA_UDMA5,
 		.bootable	= OFF_BOARD,
-		.extra		= 240
+		.extra		= 240,
+		.pio_mask	= ATA_PIO4,
 	}
 };
 
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
index ff48c23..76e91ff 100644
--- a/drivers/ide/pci/it8213.c
+++ b/drivers/ide/pci/it8213.c
@@ -21,7 +21,7 @@
  *	it8213_dma_2_pio		-	return the PIO mode matching DMA
  *	@xfer_rate: transfer speed
  *
- *	Returns the nearest equivalent PIO timing for the PIO or DMA
+ *	Returns the nearest equivalent PIO timing for the DMA
  *	mode requested by the controller.
  */
 
@@ -35,34 +35,28 @@
 		case XFER_UDMA_1:
 		case XFER_UDMA_0:
 		case XFER_MW_DMA_2:
-		case XFER_PIO_4:
 			return 4;
 		case XFER_MW_DMA_1:
-		case XFER_PIO_3:
 			return 3;
 		case XFER_SW_DMA_2:
-		case XFER_PIO_2:
 			return 2;
 		case XFER_MW_DMA_0:
 		case XFER_SW_DMA_1:
 		case XFER_SW_DMA_0:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-		case XFER_PIO_SLOW:
 		default:
 			return 0;
 	}
 }
 
 /*
- *	it8213_tuneproc	-	tune a drive
+ *	it8213_tune_pio	-	tune a drive
  *	@drive: drive to tune
  *	@pio: desired PIO mode
  *
  *	Set the interface PIO mode.
  */
 
-static void it8213_tuneproc (ide_drive_t *drive, u8 pio)
+static void it8213_tune_pio(ide_drive_t *drive, const u8 pio)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
@@ -82,8 +76,6 @@
 					{ 2, 1 },
 					{ 2, 3 }, };
 
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-
 	spin_lock_irqsave(&tune_lock, flags);
 	pci_read_config_word(dev, master_port, &master_data);
 
@@ -113,23 +105,25 @@
 	spin_unlock_irqrestore(&tune_lock, flags);
 }
 
+static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+	it8213_tune_pio(drive, pio);
+	ide_config_drive_speed(drive, XFER_PIO_0 + pio);
+}
+
 /**
  *	it8213_tune_chipset	-	set controller timings
  *	@drive: Drive to set up
- *	@xferspeed: speed we want to achieve
+ *	@speed: speed we want to achieve
  *
- *	Tune the ITE chipset for the desired mode. If we can't achieve
- *	the desired mode then tune for a lower one, but ultimately
- *	make the thing work.
+ *	Tune the ITE chipset for the desired mode.
  */
 
-static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static int it8213_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
-
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
 	u8 maslave		= 0x40;
-	u8 speed		= ide_rate_filter(drive, xferspeed);
 	int a_speed		= 3 << (drive->dn * 4);
 	int u_flag		= 1 << drive->dn;
 	int v_flag		= 0x01 << drive->dn;
@@ -157,12 +151,6 @@
 		case XFER_MW_DMA_1:
 		case XFER_SW_DMA_2:
 			break;
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			break;
 		default:
 			return -1;
 	}
@@ -193,7 +181,9 @@
 		if (reg55 & w_flag)
 			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
 	}
-	it8213_tuneproc(drive, it8213_dma_2_pio(speed));
+
+	it8213_tune_pio(drive, it8213_dma_2_pio(speed));
+
 	return ide_config_drive_speed(drive, speed);
 }
 
@@ -209,13 +199,10 @@
 
 static int it8213_config_drive_for_dma (ide_drive_t *drive)
 {
-	u8 pio;
-
 	if (ide_tune_dma(drive))
 		return 0;
 
-	pio = ide_get_best_pio_mode(drive, 255, 4, NULL);
-	it8213_tune_chipset(drive, XFER_PIO_0 + pio);
+	ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -234,7 +221,7 @@
 	u8 reg42h = 0;
 
 	hwif->speedproc = &it8213_tune_chipset;
-	hwif->tuneproc	= &it8213_tuneproc;
+	hwif->set_pio_mode = &it8213_set_pio_mode;
 
 	hwif->autodma = 0;
 
@@ -272,10 +259,11 @@
 	{						\
 		.name		= name_str,		\
 		.init_hwif	= init_hwif_it8213,	\
-		.channels	= 1,			\
 		.autodma	= AUTODMA,		\
 		.enablebits	= {{0x41,0x80,0x80}}, \
 		.bootable	= ON_BOARD,		\
+		.host_flags	= IDE_HFLAG_SINGLE,	\
+		.pio_mask	= ATA_PIO4,		\
 	}
 
 static ide_pci_device_t it8213_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index 8197b65..758a982 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -255,7 +255,7 @@
 	 * on the cable.
 	 */
 	if (pair) {
-		u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4, NULL);
+		u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4);
 		/* trim PIO to the slowest of the master/slave */
 		if (pair_pio < set_pio)
 			set_pio = pair_pio;
@@ -274,9 +274,8 @@
 	return ide_config_drive_speed(drive, XFER_PIO_0 + set_pio);
 }
 
-static void it821x_tuneproc(ide_drive_t *drive, u8 pio)
+static void it821x_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
 	(void)it821x_tunepio(drive, pio);
 }
 
@@ -405,32 +404,19 @@
 	return ret;
 }
 
-
 /**
  *	it821x_tune_chipset	-	set controller timings
  *	@drive: Drive to set up
- *	@xferspeed: speed we want to achieve
+ *	@speed: speed we want to achieve
  *
- *	Tune the ITE chipset for the desired mode. If we can't achieve
- *	the desired mode then tune for a lower one, but ultimately
- *	make the thing work.
+ *	Tune the ITE chipset for the desired mode.
  */
 
-static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed)
+static int it821x_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 
 	ide_hwif_t *hwif	= drive->hwif;
 	struct it821x_dev *itdev = ide_get_hwifdata(hwif);
-	u8 speed		= ide_rate_filter(drive, xferspeed);
-
-	switch (speed) {
-	case XFER_PIO_4:
-	case XFER_PIO_3:
-	case XFER_PIO_2:
-	case XFER_PIO_1:
-	case XFER_PIO_0:
-		return it821x_tunepio(drive, speed - XFER_PIO_0);
-	}
 
 	if (itdev->smart == 0) {
 		switch (speed) {
@@ -477,7 +463,7 @@
 	if (ide_tune_dma(drive))
 		return 0;
 
-	it821x_tuneproc(drive, 255);
+	ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -644,7 +630,7 @@
 	}
 
 	hwif->speedproc = &it821x_tune_chipset;
-	hwif->tuneproc	= &it821x_tuneproc;
+	hwif->set_pio_mode = &it821x_set_pio_mode;
 
 	/* MWDMA/PIO clock switching for pass through mode */
 	if(!idev->smart) {
@@ -718,10 +704,10 @@
 		.name		= name_str,		\
 		.init_chipset	= init_chipset_it821x,	\
 		.init_hwif	= init_hwif_it821x,	\
-		.channels	= 2,			\
 		.autodma	= AUTODMA,		\
 		.bootable	= ON_BOARD,		\
-		.fixup	 	= it821x_fixups		\
+		.fixup	 	= it821x_fixups,	\
+		.pio_mask	= ATA_PIO4,		\
 	}
 
 static ide_pci_device_t it821x_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c
index a6008f6..d379fba 100644
--- a/drivers/ide/pci/jmicron.c
+++ b/drivers/ide/pci/jmicron.c
@@ -83,39 +83,22 @@
 	return ATA_CBL_PATA80;
 }
 
-static void jmicron_tuneproc (ide_drive_t *drive, byte mode_wanted)
+static void jmicron_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	return;
-}
-
-/**
- *	config_jmicron_chipset_for_pio	-	set drive timings
- *	@drive: drive to tune
- *	@speed we want
- *
- */
-
-static void config_jmicron_chipset_for_pio (ide_drive_t *drive, byte set_speed)
-{
-	u8 speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
-	if (set_speed)
-		(void) ide_config_drive_speed(drive, speed);
+	ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
 /**
  *	jmicron_tune_chipset	-	set controller timings
  *	@drive: Drive to set up
- *	@xferspeed: speed we want to achieve
+ *	@speed: speed we want to achieve
  *
  *	As the JMicron snoops for timings all we actually need to do is
- *	make sure we don't set an invalid mode. We do need to honour
- *	the cable detect here.
+ *	set the transfer mode on the device.
  */
 
-static int jmicron_tune_chipset (ide_drive_t *drive, byte xferspeed)
+static int jmicron_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
-	u8 speed = ide_rate_filter(drive, xferspeed);
-
 	return ide_config_drive_speed(drive, speed);
 }
 
@@ -132,7 +115,7 @@
 	if (ide_tune_dma(drive))
 		return 0;
 
-	config_jmicron_chipset_for_pio(drive, 1);
+	ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -147,7 +130,7 @@
 static void __devinit init_hwif_jmicron(ide_hwif_t *hwif)
 {
 	hwif->speedproc = &jmicron_tune_chipset;
-	hwif->tuneproc	= &jmicron_tuneproc;
+	hwif->set_pio_mode = &jmicron_set_pio_mode;
 
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
@@ -173,22 +156,13 @@
 	return;
 }
 
-#define DECLARE_JMB_DEV(name_str)			\
-	{						\
-		.name		= name_str,		\
-		.init_hwif	= init_hwif_jmicron,	\
-		.channels	= 2,			\
-		.autodma	= AUTODMA,		\
-		.bootable	= ON_BOARD,		\
-		.enablebits	= { {0x40, 1, 1}, {0x40, 0x10, 0x10} }, \
-	}
-
-static ide_pci_device_t jmicron_chipsets[] __devinitdata = {
-	/* 0 */ DECLARE_JMB_DEV("JMB361"),
-	/* 1 */ DECLARE_JMB_DEV("JMB363"),
-	/* 2 */ DECLARE_JMB_DEV("JMB365"),
-	/* 3 */ DECLARE_JMB_DEV("JMB366"),
-	/* 4 */ DECLARE_JMB_DEV("JMB368"),
+static ide_pci_device_t jmicron_chipset __devinitdata = {
+	.name		= "JMB",
+	.init_hwif	= init_hwif_jmicron,
+	.autodma	= AUTODMA,
+	.bootable	= ON_BOARD,
+	.enablebits	= { { 0x40, 0x01, 0x01 }, { 0x40, 0x10, 0x10 } },
+	.pio_mask	= ATA_PIO5,
 };
 
 /**
@@ -202,35 +176,29 @@
 
 static int __devinit jmicron_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
-	ide_setup_pci_device(dev, &jmicron_chipsets[id->driver_data]);
+	ide_setup_pci_device(dev, &jmicron_chipset);
 	return 0;
 }
 
-/* If libata is configured, jmicron PCI quirk will configure it such
- * that the SATA ports are in AHCI function while the PATA ports are
- * in a separate IDE function.  In such cases, match device class and
- * attach only to IDE.  If libata isn't configured, keep the old
- * behavior for backward compatibility.
+/* All JMB PATA controllers have and will continue to have the same
+ * interface.  Matching vendor and device class is enough for all
+ * current and future controllers if the controller is programmed
+ * properly.
+ *
+ * If libata is configured, jmicron PCI quirk programs the controller
+ * into the correct mode.  If libata isn't configured, match known
+ * device IDs too to maintain backward compatibility.
  */
-#if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE)
-#define JMB_CLASS	PCI_CLASS_STORAGE_IDE << 8
-#define JMB_CLASS_MASK	0xffff00
-#else
-#define JMB_CLASS	0
-#define JMB_CLASS_MASK	0
-#endif
-
 static struct pci_device_id jmicron_pci_tbl[] = {
-	{ PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361,
-	  PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 0},
-	{ PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363,
-	  PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 1},
-	{ PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365,
-	  PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 2},
-	{ PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366,
-	  PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 3},
-	{ PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368,
-	  PCI_ANY_ID, PCI_ANY_ID, JMB_CLASS, JMB_CLASS_MASK, 4},
+#if !defined(CONFIG_ATA) && !defined(CONFIG_ATA_MODULE)
+	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361) },
+	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363) },
+	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365) },
+	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366) },
+	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368) },
+#endif
+	{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+	  PCI_CLASS_STORAGE_IDE << 8, 0xffff00, 0 },
 	{ 0, },
 };
 
diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
index b310c4f..465c935 100644
--- a/drivers/ide/pci/ns87415.c
+++ b/drivers/ide/pci/ns87415.c
@@ -187,14 +187,6 @@
 	return 1;
 }
 
-static int ns87415_ide_dma_check (ide_drive_t *drive)
-{
-	if (drive->media != ide_disk)
-		return -1;
-
-	return __ide_dma_check(drive);
-}
-
 static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
 {
 	struct pci_dev *dev = hwif->pci_dev;
@@ -266,7 +258,6 @@
 
 	outb(0x60, hwif->dma_status);
 	hwif->dma_setup = &ns87415_ide_dma_setup;
-	hwif->ide_dma_check = &ns87415_ide_dma_check;
 	hwif->ide_dma_end = &ns87415_ide_dma_end;
 
 	if (!noautodma)
@@ -281,7 +272,6 @@
 	.init_iops	= init_iops_ns87415,
 #endif
 	.init_hwif	= init_hwif_ns87415,
-	.channels	= 2,
 	.autodma	= AUTODMA,
 	.bootable	= ON_BOARD,
 };
diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c
index aede7ee..9fa0639 100644
--- a/drivers/ide/pci/opti621.c
+++ b/drivers/ide/pci/opti621.c
@@ -47,7 +47,7 @@
  * The main problem with OPTi is that some timings for master
  * and slave must be the same. For example, if you have master
  * PIO 3 and slave PIO 0, driver have to set some timings of
- * master for PIO 0. Second problem is that opti621_tune_drive
+ * master for PIO 0. Second problem is that opti621_set_pio_mode
  * got only one drive to set, but have to set both drives.
  * This is solved in compute_pios. If you don't set
  * the second drive, compute_pios use ide_get_best_pio_mode
@@ -103,7 +103,7 @@
 
 #include <asm/io.h>
 
-#define OPTI621_MAX_PIO 3
+//#define OPTI621_MAX_PIO 3
 /* In fact, I do not have any PIO 4 drive
  * (address: 25 ns, data: 70 ns, recovery: 35 ns),
  * but OPTi 82C621 is programmable and it can do (minimal values):
@@ -136,8 +136,8 @@
 #define PIO_NOT_EXIST 254
 #define PIO_DONT_KNOW 255
 
-/* there are stored pio numbers from other calls of opti621_tune_drive */
-static void compute_pios(ide_drive_t *drive, u8 pio)
+/* there are stored pio numbers from other calls of opti621_set_pio_mode */
+static void compute_pios(ide_drive_t *drive, const u8 pio)
 /* Store values into drive->drive_data
  *	second_contr - 0 for primary controller, 1 for secondary
  *	slave_drive - 0 -> pio is for master, 1 -> pio is for slave
@@ -147,12 +147,13 @@
 	int d;
 	ide_hwif_t *hwif = HWIF(drive);
 
-	drive->drive_data = ide_get_best_pio_mode(drive, pio, OPTI621_MAX_PIO, NULL);
+	drive->drive_data = pio;
+
 	for (d = 0; d < 2; ++d) {
 		drive = &hwif->drives[d];
 		if (drive->present) {
 			if (drive->drive_data == PIO_DONT_KNOW)
-				drive->drive_data = ide_get_best_pio_mode(drive, 255, OPTI621_MAX_PIO, NULL);
+				drive->drive_data = ide_get_best_pio_mode(drive, 255, 3);
 #ifdef OPTI621_DEBUG
 			printk("%s: Selected PIO mode %d\n",
 				drive->name, drive->drive_data);
@@ -240,8 +241,7 @@
  
 }
 
-/* Main tune procedure, called from tuneproc. */
-static void opti621_tune_drive (ide_drive_t *drive, u8 pio)
+static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
 	/* primary and secondary drives share some registers,
 	 * so we have to program both drives
@@ -331,7 +331,8 @@
 	hwif->autodma = 0;
 	hwif->drives[0].drive_data = PIO_DONT_KNOW;
 	hwif->drives[1].drive_data = PIO_DONT_KNOW;
-	hwif->tuneproc = &opti621_tune_drive;
+
+	hwif->set_pio_mode = &opti621_set_pio_mode;
 
 	if (!(hwif->dma_base))
 		return;
@@ -350,17 +351,17 @@
 	{	/* 0 */
 		.name		= "OPTI621",
 		.init_hwif	= init_hwif_opti621,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
 		.bootable	= ON_BOARD,
+		.pio_mask	= ATA_PIO3,
 	},{	/* 1 */
 		.name		= "OPTI621X",
 		.init_hwif	= init_hwif_opti621,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x45,0x80,0x00}, {0x40,0x08,0x00}},
 		.bootable	= ON_BOARD,
+		.pio_mask	= ATA_PIO3,
 	}
 };
 
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index ee5020d..5fb1eed 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -9,7 +9,7 @@
  *  Split from:
  *  linux/drivers/ide/pdc202xx.c	Version 0.35	Mar. 30, 2002
  *  Copyright (C) 1998-2002		Andre Hedrick <andre@linux-ide.org>
- *  Copyright (C) 2005-2006		MontaVista Software, Inc.
+ *  Copyright (C) 2005-2007		MontaVista Software, Inc.
  *  Portions Copyright (C) 1999 Promise Technology, Inc.
  *  Author: Frank Tiernan (frankt@promise.com)
  *  Released under terms of General Public License
@@ -146,14 +146,12 @@
 	{ 0x1a, 0x01, 0xcb },	/* UDMA mode 6 */
 };
 
-static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed)
+static int pdcnew_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	u8 adj			= (drive->dn & 1) ? 0x08 : 0x00;
 	int			err;
 
-	speed = ide_rate_filter(drive, speed);
-
 	/*
 	 * Issue SETFEATURES_XFER to the drive first. PDC202xx hardware will
 	 * automatically set the timing registers based on 100 MHz PLL output.
@@ -217,9 +215,8 @@
 	return err;
 }
 
-static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
+static void pdcnew_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
 	(void)pdcnew_tune_chipset(drive, XFER_PIO_0 + pio);
 }
 
@@ -239,7 +236,7 @@
 		return 0;
 
 	if (ide_use_fast_pio(drive))
-		pdcnew_tune_drive(drive, 255);
+		ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -341,7 +338,7 @@
 	 */
 	usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 +
 		(end_time.tv_usec - start_time.tv_usec);
-	pll_input = ((start_count - end_count) & 0x3ffffff) / 10 *
+	pll_input = ((start_count - end_count) & 0x3fffffff) / 10 *
 		(10000000 / usec_elapsed);
 
 	DBG("start[%ld] end[%ld]\n", start_count, end_count);
@@ -378,12 +375,8 @@
 	int f, r;
 	u8 pll_ctl0, pll_ctl1;
 
-	if (dev->resource[PCI_ROM_RESOURCE].start) {
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS,
-			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
-			(unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
-	}
+	if (dma_base == 0)
+		return -EFAULT;
 
 #ifdef CONFIG_PPC_PMAC
 	apple_kiwi_init(dev);
@@ -496,20 +489,24 @@
 {
 	hwif->autodma = 0;
 
-	hwif->tuneproc  = &pdcnew_tune_drive;
+	hwif->set_pio_mode = &pdcnew_set_pio_mode;
+
 	hwif->quirkproc = &pdcnew_quirkproc;
 	hwif->speedproc = &pdcnew_tune_chipset;
 	hwif->resetproc = &pdcnew_reset;
 
+	hwif->err_stops_fifo = 1;
+
 	hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
 
+	if (hwif->dma_base == 0)
+		return;
+
 	hwif->atapi_dma  = 1;
 
 	hwif->ultra_mask = hwif->cds->udma_mask;
 	hwif->mwdma_mask = 0x07;
 
-	hwif->err_stops_fifo = 1;
-
 	hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
 
 	if (hwif->cbl != ATA_CBL_PATA40_SHORT)
@@ -525,43 +522,52 @@
 	return ide_setup_pci_device(dev, d);
 }
 
-static int __devinit init_setup_pdc20270(struct pci_dev *dev,
-					 ide_pci_device_t *d)
+static int __devinit init_setup_pdc20270(struct pci_dev *dev, ide_pci_device_t *d)
 {
-	struct pci_dev *findev = NULL;
-	int ret;
+	struct pci_dev *bridge = dev->bus->self;
 
-	if ((dev->bus->self &&
-	     dev->bus->self->vendor == PCI_VENDOR_ID_DEC) &&
-	    (dev->bus->self->device == PCI_DEVICE_ID_DEC_21150)) {
+	if (bridge != NULL &&
+	    bridge->vendor == PCI_VENDOR_ID_DEC &&
+	    bridge->device == PCI_DEVICE_ID_DEC_21150) {
+		struct pci_dev *dev2;
+
 		if (PCI_SLOT(dev->devfn) & 2)
 			return -ENODEV;
-		d->extra = 0;
-		while ((findev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
-			if ((findev->vendor == dev->vendor) &&
-			    (findev->device == dev->device) &&
-			    (PCI_SLOT(findev->devfn) & 2)) {
-				if (findev->irq != dev->irq) {
-					findev->irq = dev->irq;
-				}
-				ret = ide_setup_pci_devices(dev, findev, d);
-				pci_dev_put(findev);
-				return ret;
+
+		dev2 = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn) + 2,
+							PCI_FUNC(dev->devfn)));
+		if (dev2 != NULL &&
+		    dev2->vendor == dev->vendor &&
+		    dev2->device == dev->device) {
+			int ret;
+
+			if (dev2->irq != dev->irq) {
+				dev2->irq = dev->irq;
+
+				printk(KERN_WARNING "%s: PCI config space "
+				       "interrupt fixed.\n", d->name);
 			}
+
+			ret = ide_setup_pci_devices(dev, dev2, d);
+			if (ret < 0)
+				pci_dev_put(dev2);
+			return ret;
 		}
 	}
 	return ide_setup_pci_device(dev, d);
 }
 
-static int __devinit init_setup_pdc20276(struct pci_dev *dev,
-					 ide_pci_device_t *d)
+static int __devinit init_setup_pdc20276(struct pci_dev *dev, ide_pci_device_t *d)
 {
-	if ((dev->bus->self) &&
-	    (dev->bus->self->vendor == PCI_VENDOR_ID_INTEL) &&
-	    ((dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960) ||
-	     (dev->bus->self->device == PCI_DEVICE_ID_INTEL_I960RM))) {
-		printk(KERN_INFO "ide: Skipping Promise PDC20276 "
-			"attached to I2O RAID controller.\n");
+	struct pci_dev *bridge = dev->bus->self;
+
+	if (bridge != NULL &&
+	    bridge->vendor == PCI_VENDOR_ID_INTEL &&
+	   (bridge->device == PCI_DEVICE_ID_INTEL_I960 ||
+	    bridge->device == PCI_DEVICE_ID_INTEL_I960RM)) {
+
+		printk(KERN_INFO "%s: attached to I2O RAID controller, "
+				 "skipping.\n", d->name);
 		return -ENODEV;
 	}
 	return ide_setup_pci_device(dev, d);
@@ -573,63 +579,63 @@
 		.init_setup	= init_setup_pdcnew,
 		.init_chipset	= init_chipset_pdcnew,
 		.init_hwif	= init_hwif_pdc202new,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
+		.pio_mask	= ATA_PIO4,
 		.udma_mask	= 0x3f, /* udma0-5 */
 	},{	/* 1 */
 		.name		= "PDC20269",
 		.init_setup	= init_setup_pdcnew,
 		.init_chipset	= init_chipset_pdcnew,
 		.init_hwif	= init_hwif_pdc202new,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
+		.pio_mask	= ATA_PIO4,
 		.udma_mask	= 0x7f, /* udma0-6*/
 	},{	/* 2 */
 		.name		= "PDC20270",
 		.init_setup	= init_setup_pdc20270,
 		.init_chipset	= init_chipset_pdcnew,
 		.init_hwif	= init_hwif_pdc202new,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
+		.pio_mask	= ATA_PIO4,
 		.udma_mask	= 0x3f, /* udma0-5 */
 	},{	/* 3 */
 		.name		= "PDC20271",
 		.init_setup	= init_setup_pdcnew,
 		.init_chipset	= init_chipset_pdcnew,
 		.init_hwif	= init_hwif_pdc202new,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
+		.pio_mask	= ATA_PIO4,
 		.udma_mask	= 0x7f, /* udma0-6*/
 	},{	/* 4 */
 		.name		= "PDC20275",
 		.init_setup	= init_setup_pdcnew,
 		.init_chipset	= init_chipset_pdcnew,
 		.init_hwif	= init_hwif_pdc202new,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
+		.pio_mask	= ATA_PIO4,
 		.udma_mask	= 0x7f, /* udma0-6*/
 	},{	/* 5 */
 		.name		= "PDC20276",
 		.init_setup	= init_setup_pdc20276,
 		.init_chipset	= init_chipset_pdcnew,
 		.init_hwif	= init_hwif_pdc202new,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
+		.pio_mask	= ATA_PIO4,
 		.udma_mask	= 0x7f, /* udma0-6*/
 	},{	/* 6 */
 		.name		= "PDC20277",
 		.init_setup	= init_setup_pdcnew,
 		.init_chipset	= init_chipset_pdcnew,
 		.init_hwif	= init_hwif_pdc202new,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
+		.pio_mask	= ATA_PIO4,
 		.udma_mask	= 0x7f, /* udma0-6*/
 	}
 };
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index 41ac4a9..b578307 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/pci/pdc202xx_old.c	Version 0.50	Mar 3, 2007
+ *  linux/drivers/ide/pci/pdc202xx_old.c	Version 0.51	Jul 27, 2007
  *
  *  Copyright (C) 1998-2002		Andre Hedrick <andre@linux-ide.org>
  *  Copyright (C) 2006-2007		MontaVista Software, Inc.
@@ -63,12 +63,11 @@
 
 static void pdc_old_disable_66MHz_clock(ide_hwif_t *);
 
-static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static int pdc202xx_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
 	u8 drive_pci		= 0x60 + (drive->dn << 2);
-	u8 speed		= ide_rate_filter(drive, xferspeed);
 
 	u8			AP = 0, BP = 0, CP = 0;
 	u8			TA = 0, TB = 0, TC = 0;
@@ -143,9 +142,8 @@
 	return ide_config_drive_speed(drive, speed);
 }
 
-static void pdc202xx_tune_drive(ide_drive_t *drive, u8 pio)
+static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
 	pdc202xx_tune_chipset(drive, XFER_PIO_0 + pio);
 }
 
@@ -191,7 +189,7 @@
 		return 0;
 
 	if (ide_use_fast_pio(drive))
-		pdc202xx_tune_drive(drive, 255);
+		ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -307,23 +305,16 @@
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	ide_hwif_t *mate	= hwif->mate;
-	
+
 	pdc202xx_reset_host(hwif);
 	pdc202xx_reset_host(mate);
-	pdc202xx_tune_drive(drive, 255);
+
+	ide_set_max_pio(drive);
 }
 
 static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
 							const char *name)
 {
-	/* This doesn't appear needed */
-	if (dev->resource[PCI_ROM_RESOURCE].start) {
-		pci_write_config_dword(dev, PCI_ROM_ADDRESS,
-			dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
-		printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
-			(unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
-	}
-
 	return dev->irq;
 }
 
@@ -337,7 +328,9 @@
 		hwif->rqsize = 256;
 
 	hwif->autodma = 0;
-	hwif->tuneproc  = &pdc202xx_tune_drive;
+
+	hwif->set_pio_mode = &pdc202xx_set_pio_mode;
+
 	hwif->quirkproc = &pdc202xx_quirkproc;
 
 	if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246)
@@ -345,15 +338,18 @@
 
 	hwif->speedproc = &pdc202xx_tune_chipset;
 
+	hwif->err_stops_fifo = 1;
+
 	hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
 
+	if (hwif->dma_base == 0)
+		return;
+
 	hwif->ultra_mask = hwif->cds->udma_mask;
 	hwif->mwdma_mask = 0x07;
 	hwif->swdma_mask = 0x07;
 	hwif->atapi_dma = 1;
 
-	hwif->err_stops_fifo = 1;
-
 	hwif->ide_dma_check = &pdc202xx_config_drive_xfer_rate;
 	hwif->dma_lost_irq = &pdc202xx_dma_lost_irq;
 	hwif->dma_timeout = &pdc202xx_dma_timeout;
@@ -449,10 +445,10 @@
 		.init_chipset	= init_chipset_pdc202xx,
 		.init_hwif	= init_hwif_pdc202xx,
 		.init_dma	= init_dma_pdc202xx,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
 		.extra		= 16,
+		.pio_mask	= ATA_PIO4,
 		.udma_mask	= 0x07, /* udma0-2 */
 	},{	/* 1 */
 		.name		= "PDC20262",
@@ -460,10 +456,10 @@
 		.init_chipset	= init_chipset_pdc202xx,
 		.init_hwif	= init_hwif_pdc202xx,
 		.init_dma	= init_dma_pdc202xx,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
 		.extra		= 48,
+		.pio_mask	= ATA_PIO4,
 		.udma_mask	= 0x1f, /* udma0-4 */
 	},{	/* 2 */
 		.name		= "PDC20263",
@@ -471,10 +467,10 @@
 		.init_chipset	= init_chipset_pdc202xx,
 		.init_hwif	= init_hwif_pdc202xx,
 		.init_dma	= init_dma_pdc202xx,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
 		.extra		= 48,
+		.pio_mask	= ATA_PIO4,
 		.udma_mask	= 0x1f, /* udma0-4 */
 	},{	/* 3 */
 		.name		= "PDC20265",
@@ -482,10 +478,10 @@
 		.init_chipset	= init_chipset_pdc202xx,
 		.init_hwif	= init_hwif_pdc202xx,
 		.init_dma	= init_dma_pdc202xx,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
 		.extra		= 48,
+		.pio_mask	= ATA_PIO4,
 		.udma_mask	= 0x3f, /* udma0-5 */
 	},{	/* 4 */
 		.name		= "PDC20267",
@@ -493,10 +489,10 @@
 		.init_chipset	= init_chipset_pdc202xx,
 		.init_hwif	= init_hwif_pdc202xx,
 		.init_dma	= init_dma_pdc202xx,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= OFF_BOARD,
 		.extra		= 48,
+		.pio_mask	= ATA_PIO4,
 		.udma_mask	= 0x3f, /* udma0-5 */
 	}
 };
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index 1372c35..fd8214a 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/pci/piix.c	Version 0.50	Jun 10, 2007
+ *  linux/drivers/ide/pci/piix.c	Version 0.52	Jul 14, 2007
  *
  *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
  *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
@@ -17,11 +17,11 @@
  *                 41
  *                 43
  *
- * | PIO 0       | c0 | 80 | 0 | 	piix_tune_drive(drive, 0);
- * | PIO 2 | SW2 | d0 | 90 | 4 | 	piix_tune_drive(drive, 2);
- * | PIO 3 | MW1 | e1 | a1 | 9 | 	piix_tune_drive(drive, 3);
- * | PIO 4 | MW2 | e3 | a3 | b | 	piix_tune_drive(drive, 4);
- * 
+ * | PIO 0       | c0 | 80 | 0 |
+ * | PIO 2 | SW2 | d0 | 90 | 4 |
+ * | PIO 3 | MW1 | e1 | a1 | 9 |
+ * | PIO 4 | MW2 | e3 | a3 | b |
+ *
  * sitre = word40 & 0x4000; primary
  * sitre = word42 & 0x4000; secondary
  *
@@ -109,7 +109,7 @@
  *	piix_dma_2_pio		-	return the PIO mode matching DMA
  *	@xfer_rate: transfer speed
  *
- *	Returns the nearest equivalent PIO timing for the PIO or DMA
+ *	Returns the nearest equivalent PIO timing for the DMA
  *	mode requested by the controller.
  */
  
@@ -123,20 +123,14 @@
 		case XFER_UDMA_1:
 		case XFER_UDMA_0:
 		case XFER_MW_DMA_2:
-		case XFER_PIO_4:
 			return 4;
 		case XFER_MW_DMA_1:
-		case XFER_PIO_3:
 			return 3;
 		case XFER_SW_DMA_2:
-		case XFER_PIO_2:
 			return 2;
 		case XFER_MW_DMA_0:
 		case XFER_SW_DMA_1:
 		case XFER_SW_DMA_0:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-		case XFER_PIO_SLOW:
 		default:
 			return 0;
 	}
@@ -210,16 +204,16 @@
 }
 
 /**
- *	piix_tune_drive		-	tune a drive attached to PIIX
+ *	piix_set_pio_mode	-	set PIO mode
  *	@drive: drive to tune
  *	@pio: desired PIO mode
  *
  *	Set the drive's PIO mode (might be useful if drive is not registered
  *	in CMOS for any reason).
  */
-static void piix_tune_drive (ide_drive_t *drive, u8 pio)
+
+static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
 	piix_tune_pio(drive, pio);
 	(void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
@@ -227,19 +221,18 @@
 /**
  *	piix_tune_chipset	-	tune a PIIX interface
  *	@drive: IDE drive to tune
- *	@xferspeed: speed to configure
+ *	@speed: speed to configure
  *
  *	Set a PIIX interface channel to the desired speeds. This involves
  *	requires the right timing data into the PIIX configuration space
  *	then setting the drive parameters appropriately
  */
- 
-static int piix_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+
+static int piix_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
 	u8 maslave		= hwif->channel ? 0x42 : 0x40;
-	u8 speed		= ide_rate_filter(drive, xferspeed);
 	int a_speed		= 3 << (drive->dn * 4);
 	int u_flag		= 1 << drive->dn;
 	int v_flag		= 0x01 << drive->dn;
@@ -266,10 +259,6 @@
 		case XFER_MW_DMA_2:
 		case XFER_MW_DMA_1:
 		case XFER_SW_DMA_2:	break;
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_0:	break;
 		default:		return -1;
 	}
 
@@ -300,6 +289,7 @@
 	}
 
 	piix_tune_pio(drive, piix_dma_2_pio(speed));
+
 	return ide_config_drive_speed(drive, speed);
 }
 
@@ -319,7 +309,7 @@
 		return 0;
 
 	if (ide_use_fast_pio(drive))
-		piix_tune_drive(drive, 255);
+		ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -456,7 +446,8 @@
 	}
 
 	hwif->autodma = 0;
-	hwif->tuneproc = &piix_tune_drive;
+
+	hwif->set_pio_mode = &piix_set_pio_mode;
 	hwif->speedproc = &piix_tune_chipset;
 	hwif->drives[0].autotune = 1;
 	hwif->drives[1].autotune = 1;
@@ -495,10 +486,10 @@
 		.name		= name_str,		\
 		.init_chipset	= init_chipset_piix,	\
 		.init_hwif	= init_hwif_piix,	\
-		.channels	= 2,			\
 		.autodma	= AUTODMA,		\
 		.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}}, \
 		.bootable	= ON_BOARD,		\
+		.pio_mask	= ATA_PIO4,		\
 		.udma_mask	= udma,			\
 	}
 
@@ -514,11 +505,11 @@
 		 */
 		.name		= "MPIIX",
 		.init_hwif	= init_hwif_piix,
-		.channels	= 2,
 		.autodma	= NODMA,
 		.enablebits	= {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}},
 		.bootable	= ON_BOARD,
-		.flags		= IDEPCI_FLAG_ISA_PORTS
+		.host_flags	= IDE_HFLAG_ISA_PORTS,
+		.pio_mask	= ATA_PIO4,
 	},
 
 	/*  3 */ DECLARE_PIIX_DEV("PIIX3", 0x00),	/* no udma */
diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c
index f8c9546..10e1ae7 100644
--- a/drivers/ide/pci/rz1000.c
+++ b/drivers/ide/pci/rz1000.c
@@ -52,7 +52,6 @@
 static ide_pci_device_t rz1000_chipset __devinitdata = {
 	.name		= "RZ100x",
 	.init_hwif	= init_hwif_rz1000,
-	.channels	= 2,
 	.autodma	= NODMA,
 	.bootable	= ON_BOARD,
 };
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
index 523363c..79ecab6 100644
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/pci/sc1200.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/sc1200.c		Version 0.94	Mar 10 2007
+ * linux/drivers/ide/pci/sc1200.c		Version 0.95	Jun 16 2007
  *
  * Copyright (C) 2000-2002		Mark Lord <mlord@pobox.com>
  * Copyright (C)      2007		Bartlomiej Zolnierkiewicz
@@ -138,7 +138,7 @@
 	return mask;
 }
 
-static int sc1200_tune_chipset(ide_drive_t *drive, u8 mode)
+static int sc1200_tune_chipset(ide_drive_t *drive, const u8 mode)
 {
 	ide_hwif_t		*hwif = HWIF(drive);
 	int			unit = drive->select.b.unit;
@@ -146,25 +146,11 @@
 	unsigned short		pci_clock;
 	unsigned int		basereg = hwif->channel ? 0x50 : 0x40;
 
-	mode = ide_rate_filter(drive, mode);
-
 	/*
 	 * Tell the drive to switch to the new mode; abort on failure.
 	 */
-	if (sc1200_set_xfer_mode(drive, mode)) {
-		printk("SC1200: set xfer mode failure\n");
+	if (sc1200_set_xfer_mode(drive, mode))
 		return 1;	/* failure */
-	}
-
-	switch (mode) {
-	case XFER_PIO_4:
-	case XFER_PIO_3:
-	case XFER_PIO_2:
-	case XFER_PIO_1:
-	case XFER_PIO_0:
-		sc1200_tunepio(drive, mode - XFER_PIO_0);
-		return 0;
-	}
 
 	pci_clock = sc1200_get_pci_clock();
 
@@ -274,19 +260,20 @@
 }
 
 /*
- * sc1200_tuneproc() handles selection/setting of PIO modes
+ * sc1200_set_pio_mode() handles setting of PIO modes
  * for both the chipset and drive.
  *
  * All existing BIOSs for this chipset guarantee that all drives
  * will have valid default PIO timings set up before we get here.
  */
-static void sc1200_tuneproc (ide_drive_t *drive, byte pio)	/* mode=255 means "autotune" */
+
+static void sc1200_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
 	ide_hwif_t	*hwif = HWIF(drive);
 	int		mode = -1;
 
 	/*
-	 * bad abuse of ->tuneproc interface
+	 * bad abuse of ->set_pio_mode interface
 	 */
 	switch (pio) {
 		case 200: mode = XFER_UDMA_0;	break;
@@ -304,9 +291,6 @@
 		return;
 	}
 
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-	printk("SC1200: %s: setting PIO mode%d\n", drive->name, pio);
-
 	if (sc1200_set_xfer_mode(drive, XFER_PIO_0 + pio) == 0)
 		sc1200_tunepio(drive, pio);
 }
@@ -390,7 +374,7 @@
 	// loop over all interfaces that are part of this pci device:
 	//
 	while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
-		unsigned int		basereg, r, d, format;
+		unsigned int		basereg, r;
 		sc1200_saved_state_t	*ss = (sc1200_saved_state_t *)hwif->config_data;
 
 		//
@@ -402,41 +386,6 @@
 				pci_write_config_dword(hwif->pci_dev, basereg + (r<<2), ss->regs[r]);
 			}
 		}
-		//
-		// Re-program drive PIO modes
-		//
-		pci_read_config_dword(hwif->pci_dev, basereg+4, &format);
-		format = (format >> 31) & 1;
-		if (format)
-			format += sc1200_get_pci_clock();
-		for (d = 0; d < 2; ++d) {
-			ide_drive_t *drive = &(hwif->drives[d]);
-			if (drive->present) {
-				unsigned int pio, timings;
-				pci_read_config_dword(hwif->pci_dev, basereg+(drive->select.b.unit << 3), &timings);
-				for (pio = 0; pio <= 4; ++pio) {
-					if (sc1200_pio_timings[format][pio] == timings)
-						break;
-				}
-				if (pio > 4)
-					pio = 255; /* autotune */
-				(void)sc1200_tuneproc(drive, pio);
-			}
-		}
-		//
-		// Re-program drive DMA modes
-		//
-		for (d = 0; d < MAX_DRIVES; ++d) {
-			ide_drive_t *drive = &(hwif->drives[d]);
-			if (drive->present && !__ide_dma_bad_drive(drive)) {
-				int enable_dma = drive->using_dma;
-				hwif->dma_off_quietly(drive);
-				if (sc1200_config_dma(drive))
-					enable_dma = 0;
-				if (enable_dma)
-					hwif->dma_host_on(drive);
-			}
-		}
 	}
 	return 0;
 }
@@ -457,7 +406,8 @@
 		hwif->ide_dma_end   = &sc1200_ide_dma_end;
         	if (!noautodma)
                 	hwif->autodma = 1;
-		hwif->tuneproc = &sc1200_tuneproc;
+
+		hwif->set_pio_mode = &sc1200_set_pio_mode;
 		hwif->speedproc = &sc1200_tune_chipset;
 	}
         hwif->atapi_dma = 1;
@@ -471,9 +421,10 @@
 static ide_pci_device_t sc1200_chipset __devinitdata = {
 	.name		= "SC1200",
 	.init_hwif	= init_hwif_sc1200,
-	.channels	= 2,
 	.autodma	= AUTODMA,
 	.bootable	= ON_BOARD,
+	.host_flags	= IDE_HFLAG_ABUSE_DMA_MODES,
+	.pio_mask	= ATA_PIO4,
 };
 
 static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/scc_pata.c b/drivers/ide/pci/scc_pata.c
index 7b87488..66a526e 100644
--- a/drivers/ide/pci/scc_pata.c
+++ b/drivers/ide/pci/scc_pata.c
@@ -165,9 +165,9 @@
 	ide_hwif_t *hwif = HWIF(drive);
 
 	out_be32((void*)port, addr);
-	__asm__ __volatile__("eieio":::"memory");
+	eieio();
 	in_be32((void*)(hwif->dma_base + 0x01c));
-	__asm__ __volatile__("eieio":::"memory");
+	eieio();
 }
 
 static void
@@ -190,7 +190,7 @@
 }
 
 /**
- *	scc_tuneproc	-	tune a drive PIO mode
+ *	scc_tune_pio	-	tune a drive PIO mode
  *	@drive: drive to tune
  *	@mode_wanted: the target operating mode
  *
@@ -198,7 +198,7 @@
  *	controller.
  */
 
-static void scc_tuneproc(ide_drive_t *drive, byte mode_wanted)
+static void scc_tune_pio(ide_drive_t *drive, const u8 pio)
 {
 	ide_hwif_t *hwif = HWIF(drive);
 	struct scc_ports *ports = ide_get_hwifdata(hwif);
@@ -207,56 +207,38 @@
 	unsigned long piosht_port = ctl_base + 0x000;
 	unsigned long pioct_port = ctl_base + 0x004;
 	unsigned long reg;
-	unsigned char speed = XFER_PIO_0;
 	int offset;
 
-	mode_wanted = ide_get_best_pio_mode(drive, mode_wanted, 4, NULL);
-	switch (mode_wanted) {
-	case 4:
-		speed = XFER_PIO_4;
-		break;
-	case 3:
-		speed = XFER_PIO_3;
-		break;
-	case 2:
-		speed = XFER_PIO_2;
-		break;
-	case 1:
-		speed = XFER_PIO_1;
-		break;
-	case 0:
-	default:
-		speed = XFER_PIO_0;
-		break;
-	}
-
 	reg = in_be32((void __iomem *)cckctrl_port);
 	if (reg & CCKCTRL_ATACLKOEN) {
 		offset = 1; /* 133MHz */
 	} else {
 		offset = 0; /* 100MHz */
 	}
-	reg = JCHSTtbl[offset][mode_wanted] << 16 | JCHHTtbl[offset][mode_wanted];
+	reg = JCHSTtbl[offset][pio] << 16 | JCHHTtbl[offset][pio];
 	out_be32((void __iomem *)piosht_port, reg);
-	reg = JCHCTtbl[offset][mode_wanted];
+	reg = JCHCTtbl[offset][pio];
 	out_be32((void __iomem *)pioct_port, reg);
+}
 
-	ide_config_drive_speed(drive, speed);
+static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio)
+{
+	scc_tune_pio(drive, pio);
+	ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
 /**
  *	scc_tune_chipset	-	tune a drive DMA mode
  *	@drive: Drive to set up
- *	@xferspeed: speed we want to achieve
+ *	@speed: speed we want to achieve
  *
  *	Load the timing settings for this device mode into the
  *	controller.
  */
 
-static int scc_tune_chipset(ide_drive_t *drive, byte xferspeed)
+static int scc_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	ide_hwif_t *hwif = HWIF(drive);
-	u8 speed = ide_rate_filter(drive, xferspeed);
 	struct scc_ports *ports = ide_get_hwifdata(hwif);
 	unsigned long ctl_base = ports->ctl;
 	unsigned long cckctrl_port = ctl_base + 0xff0;
@@ -280,25 +262,13 @@
 
 	switch (speed) {
 	case XFER_UDMA_6:
-		idx = 6;
-		break;
 	case XFER_UDMA_5:
-		idx = 5;
-		break;
 	case XFER_UDMA_4:
-		idx = 4;
-		break;
 	case XFER_UDMA_3:
-		idx = 3;
-		break;
 	case XFER_UDMA_2:
-		idx = 2;
-		break;
 	case XFER_UDMA_1:
-		idx = 1;
-		break;
 	case XFER_UDMA_0:
-		idx = 0;
+		idx = speed - XFER_UDMA_0;
 		break;
 	default:
 		return 1;
@@ -329,7 +299,7 @@
  *	required.
  *      If the drive isn't suitable for DMA or we hit other problems
  *      then we will drop down to PIO and set up PIO appropriately.
- *      (return 1)
+ *      (return -1)
  */
 
 static int scc_config_drive_for_dma(ide_drive_t *drive)
@@ -338,7 +308,7 @@
 		return 0;
 
 	if (ide_use_fast_pio(drive))
-		scc_tuneproc(drive, 4);
+		ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -401,6 +371,33 @@
 	ide_hwif_t *hwif = HWIF(drive);
 	unsigned long intsts_port = hwif->dma_base + 0x014;
 	u32 reg;
+	int dma_stat, data_loss = 0;
+	static int retry = 0;
+
+	/* errata A308 workaround: Step5 (check data loss) */
+	/* We don't check non ide_disk because it is limited to UDMA4 */
+	if (!(in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT) &&
+	    drive->media == ide_disk && drive->current_speed > XFER_UDMA_4) {
+		reg = in_be32((void __iomem *)intsts_port);
+		if (!(reg & INTSTS_ACTEINT)) {
+			printk(KERN_WARNING "%s: operation failed (transfer data loss)\n",
+			       drive->name);
+			data_loss = 1;
+			if (retry++) {
+				struct request *rq = HWGROUP(drive)->rq;
+				int unit;
+				/* ERROR_RESET and drive->crc_count are needed
+				 * to reduce DMA transfer mode in retry process.
+				 */
+				if (rq)
+					rq->errors |= ERROR_RESET;
+				for (unit = 0; unit < MAX_DRIVES; unit++) {
+					ide_drive_t *drive = &hwif->drives[unit];
+					drive->crc_count++;
+				}
+			}
+		}
+	}
 
 	while (1) {
 		reg = in_be32((void __iomem *)intsts_port);
@@ -469,27 +466,25 @@
 		break;
 	}
 
-	return __ide_dma_end(drive);
+	dma_stat = __ide_dma_end(drive);
+	if (data_loss)
+		dma_stat |= 2; /* emulate DMA error (to retry command) */
+	return dma_stat;
 }
 
 /* returns 1 if dma irq issued, 0 otherwise */
 static int scc_dma_test_irq(ide_drive_t *drive)
 {
-	ide_hwif_t *hwif	= HWIF(drive);
-	u8 dma_stat		= hwif->INB(hwif->dma_status);
+	ide_hwif_t *hwif = HWIF(drive);
+	u32 int_stat = in_be32((void __iomem *)hwif->dma_base + 0x014);
 
-	/* return 1 if INTR asserted */
-	if ((dma_stat & 4) == 4)
+	/* SCC errata A252,A308 workaround: Step4 */
+	if ((in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT) &&
+	    (int_stat & INTSTS_INTRQ))
 		return 1;
 
-	/* Workaround for PTERADD: emulate DMA_INTR when
-	 * - IDE_STATUS[ERR] = 1
-	 * - INT_STATUS[INTRQ] = 1
-	 * - DMA_STATUS[IORACTA] = 1
-	 */
-	if (in_be32((void __iomem *)IDE_ALTSTATUS_REG) & ERR_STAT &&
-	    in_be32((void __iomem *)(hwif->dma_base + 0x014)) & INTSTS_INTRQ &&
-		dma_stat & 1)
+	/* SCC errata A308 workaround: Step5 (polling IOIRQS) */
+	if (int_stat & INTSTS_IOIRQS)
 		return 1;
 
 	if (!drive->waiting_for_dma)
@@ -498,6 +493,21 @@
 	return 0;
 }
 
+static u8 scc_udma_filter(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	u8 mask = hwif->ultra_mask;
+
+	/* errata A308 workaround: limit non ide_disk drive to UDMA4 */
+	if ((drive->media != ide_disk) && (mask & 0xE0)) {
+		printk(KERN_INFO "%s: limit %s to UDMA4\n",
+		       SCC_PATA_NAME, drive->name);
+		mask = 0x1F;
+	}
+
+	return mask;
+}
+
 /**
  *	setup_mmio_scc	-	map CTRL/BMID region
  *	@dev: PCI device we are configuring
@@ -511,8 +521,8 @@
 	unsigned long dma_base = pci_resource_start(dev, 1);
 	unsigned long ctl_size = pci_resource_len(dev, 0);
 	unsigned long dma_size = pci_resource_len(dev, 1);
-	void *ctl_addr;
-	void *dma_addr;
+	void __iomem *ctl_addr;
+	void __iomem *dma_addr;
 	int i;
 
 	for (i = 0; i < MAX_HWIFS; i++) {
@@ -699,9 +709,10 @@
 	hwif->dma_setup = scc_dma_setup;
 	hwif->ide_dma_end = scc_ide_dma_end;
 	hwif->speedproc = scc_tune_chipset;
-	hwif->tuneproc = scc_tuneproc;
+	hwif->set_pio_mode = scc_set_pio_mode;
 	hwif->ide_dma_check = scc_config_drive_for_dma;
 	hwif->ide_dma_test_irq = scc_dma_test_irq;
+	hwif->udma_filter = scc_udma_filter;
 
 	hwif->drives[0].autotune = IDE_TUNE_AUTO;
 	hwif->drives[1].autotune = IDE_TUNE_AUTO;
@@ -731,9 +742,10 @@
       .init_setup	= init_setup_scc,		\
       .init_iops	= init_iops_scc,		\
       .init_hwif	= init_hwif_scc,		\
-      .channels	= 1,					\
       .autodma	= AUTODMA,				\
       .bootable	= ON_BOARD,				\
+      .host_flags	= IDE_HFLAG_SINGLE,		\
+      .pio_mask		= ATA_PIO4,			\
   }
 
 static ide_pci_device_t scc_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index ed04e0c..0351cf2 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/serverworks.c		Version 0.20	Jun 3 2007
+ * linux/drivers/ide/pci/serverworks.c		Version 0.22	Jun 27 2007
  *
  * Copyright (C) 1998-2000 Michel Aubry
  * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
@@ -123,23 +123,39 @@
 	}
 	return 0;
 }
-static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+
+static void svwks_tune_pio(ide_drive_t *drive, const u8 pio)
+{
+	static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+	static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
+
+	struct pci_dev *dev = drive->hwif->pci_dev;
+
+	pci_write_config_byte(dev, drive_pci[drive->dn], pio_modes[pio]);
+
+	if (svwks_csb_check(dev)) {
+		u16 csb_pio = 0;
+
+		pci_read_config_word(dev, 0x4a, &csb_pio);
+
+		csb_pio &= ~(0x0f << (4 * drive->dn));
+		csb_pio |= (pio << (4 * drive->dn));
+
+		pci_write_config_word(dev, 0x4a, csb_pio);
+	}
+}
+
+static int svwks_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	static const u8 udma_modes[]		= { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
 	static const u8 dma_modes[]		= { 0x77, 0x21, 0x20 };
-	static const u8 pio_modes[]		= { 0x5d, 0x47, 0x34, 0x22, 0x20 };
-	static const u8 drive_pci[]		= { 0x41, 0x40, 0x43, 0x42 };
 	static const u8 drive_pci2[]		= { 0x45, 0x44, 0x47, 0x46 };
 
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
-	u8 speed		= ide_rate_filter(drive, xferspeed);
-	u8 pio			= ide_get_best_pio_mode(drive, 255, 4, NULL);
 	u8 unit			= (drive->select.b.unit & 0x01);
-	u8 csb5			= svwks_csb_check(dev);
-	u8 ultra_enable		= 0, ultra_timing = 0;
-	u8 dma_timing		= 0, pio_timing = 0;
-	u16 csb5_pio		= 0;
+
+	u8 ultra_enable	 = 0, ultra_timing = 0, dma_timing = 0;
 
 	/* If we are about to put a disk into UDMA mode we screwed up.
 	   Our code assumes we never _ever_ do this on an OSB4 */
@@ -149,31 +165,15 @@
 			BUG();
 
 	pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing);
-	pci_read_config_word(dev, 0x4A, &csb5_pio);
 	pci_read_config_byte(dev, 0x54, &ultra_enable);
 
 	ultra_timing	&= ~(0x0F << (4*unit));
 	ultra_enable	&= ~(0x01 << drive->dn);
-	csb5_pio	&= ~(0x0F << (4*drive->dn));
 
 	switch(speed) {
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			pio_timing |= pio_modes[speed - XFER_PIO_0];
-			csb5_pio   |= ((speed - XFER_PIO_0) << (4*drive->dn));
-			break;
-
 		case XFER_MW_DMA_2:
 		case XFER_MW_DMA_1:
 		case XFER_MW_DMA_0:
-			/*
-			 * TODO: always setup PIO mode so this won't be needed
-			 */
-			pio_timing |= pio_modes[pio];
-			csb5_pio   |= (pio << (4*drive->dn));
 			dma_timing |= dma_modes[speed - XFER_MW_DMA_0];
 			break;
 
@@ -183,11 +183,6 @@
 		case XFER_UDMA_2:
 		case XFER_UDMA_1:
 		case XFER_UDMA_0:
-			/*
-			 * TODO: always setup PIO mode so this won't be needed
-			 */
-			pio_timing   |= pio_modes[pio];
-			csb5_pio     |= (pio << (4*drive->dn));
 			dma_timing   |= dma_modes[2];
 			ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit));
 			ultra_enable |= (0x01 << drive->dn);
@@ -195,10 +190,6 @@
 			break;
 	}
 
-	pci_write_config_byte(dev, drive_pci[drive->dn], pio_timing);
-	if (csb5)
-		pci_write_config_word(dev, 0x4A, csb5_pio);
-
 	pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing);
 	pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing);
 	pci_write_config_byte(dev, 0x54, ultra_enable);
@@ -206,10 +197,10 @@
 	return (ide_config_drive_speed(drive, speed));
 }
 
-static void svwks_tune_drive (ide_drive_t *drive, u8 pio)
+static void svwks_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-	(void)svwks_tune_chipset(drive, XFER_PIO_0 + pio);
+	svwks_tune_pio(drive, pio);
+	(void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
 static int svwks_config_drive_xfer_rate (ide_drive_t *drive)
@@ -220,7 +211,7 @@
 		return 0;
 
 	if (ide_use_fast_pio(drive))
-		svwks_tune_drive(drive, 255);
+		ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -389,12 +380,10 @@
 
 static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
 {
-	u8 dma_stat = 0;
-
 	if (!hwif->irq)
 		hwif->irq = hwif->channel ? 15 : 14;
 
-	hwif->tuneproc = &svwks_tune_drive;
+	hwif->set_pio_mode = &svwks_set_pio_mode;
 	hwif->speedproc = &svwks_tune_chipset;
 	hwif->udma_filter = &svwks_udma_filter;
 
@@ -407,11 +396,11 @@
 
 	hwif->autodma = 0;
 
-	if (!hwif->dma_base) {
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
+	hwif->drives[0].autotune = 1;
+	hwif->drives[1].autotune = 1;
+
+	if (!hwif->dma_base)
 		return;
-	}
 
 	hwif->ide_dma_check = &svwks_config_drive_xfer_rate;
 	if (hwif->pci_dev->device != PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
@@ -421,11 +410,7 @@
 	if (!noautodma)
 		hwif->autodma = 1;
 
-	dma_stat = inb(hwif->dma_status);
-	hwif->drives[0].autodma = (dma_stat & 0x20);
-	hwif->drives[1].autodma = (dma_stat & 0x40);
-	hwif->drives[0].autotune = (!(dma_stat & 0x20));
-	hwif->drives[1].autotune = (!(dma_stat & 0x40));
+	hwif->drives[0].autodma = hwif->drives[1].autodma = 1;
 }
 
 static int __devinit init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
@@ -441,9 +426,12 @@
 			d->bootable = ON_BOARD;
 	}
 
-	d->channels = ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE ||
-			dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) &&
-		       (!(PCI_FUNC(dev->devfn) & 1))) ? 1 : 2;
+	if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE ||
+	    dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) &&
+	    (!(PCI_FUNC(dev->devfn) & 1)))
+		d->host_flags |= IDE_HFLAG_SINGLE;
+	else
+		d->host_flags &= ~IDE_HFLAG_SINGLE;
 
 	return ide_setup_pci_device(dev, d);
 }
@@ -454,41 +442,43 @@
 		.init_setup	= init_setup_svwks,
 		.init_chipset	= init_chipset_svwks,
 		.init_hwif	= init_hwif_svwks,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= ON_BOARD,
+		.pio_mask	= ATA_PIO4,
 	},{	/* 1 */
 		.name		= "SvrWks CSB5",
 		.init_setup	= init_setup_svwks,
 		.init_chipset	= init_chipset_svwks,
 		.init_hwif	= init_hwif_svwks,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= ON_BOARD,
+		.pio_mask	= ATA_PIO4,
 	},{	/* 2 */
 		.name		= "SvrWks CSB6",
 		.init_setup	= init_setup_csb6,
 		.init_chipset	= init_chipset_svwks,
 		.init_hwif	= init_hwif_svwks,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.bootable	= ON_BOARD,
+		.pio_mask	= ATA_PIO4,
 	},{	/* 3 */
 		.name		= "SvrWks CSB6",
 		.init_setup	= init_setup_csb6,
 		.init_chipset	= init_chipset_svwks,
 		.init_hwif	= init_hwif_svwks,
-		.channels	= 1,	/* 2 */
 		.autodma	= AUTODMA,
 		.bootable	= ON_BOARD,
+		.host_flags	= IDE_HFLAG_SINGLE,
+		.pio_mask	= ATA_PIO4,
 	},{	/* 4 */
 		.name		= "SvrWks HT1000",
 		.init_setup	= init_setup_svwks,
 		.init_chipset	= init_chipset_svwks,
 		.init_hwif	= init_hwif_svwks,
-		.channels	= 1,	/* 2 */
 		.autodma	= AUTODMA,
 		.bootable	= ON_BOARD,
+		.host_flags	= IDE_HFLAG_SINGLE,
+		.pio_mask	= ATA_PIO4,
 	}
 };
 
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index d396b29..c292e1d 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -34,6 +34,8 @@
 
 #include <linux/ide.h>
 
+#define DRV_NAME "SGIIOC4"
+
 /* IOC4 Specific Definitions */
 #define IOC4_CMD_OFFSET		0x100
 #define IOC4_CTRL_OFFSET	0x120
@@ -289,15 +291,26 @@
 	drive->hwif->dma_host_off(drive);
 }
 
+static int sgiioc4_speedproc(ide_drive_t *drive, const u8 speed)
+{
+	if (speed != XFER_MW_DMA_2)
+		return 1;
+
+	return ide_config_drive_speed(drive, speed);
+}
+
 static int sgiioc4_ide_dma_check(ide_drive_t *drive)
 {
-	/* FIXME: check for available DMA modes */
-	if (ide_config_drive_speed(drive, XFER_MW_DMA_2) != 0) {
-		printk(KERN_WARNING "%s: couldn't set MWDMA2 mode, "
-				    "using PIO instead\n", drive->name);
-		return -1;
-	} else
+	if (ide_tune_dma(drive))
 		return 0;
+
+	/*
+	 * ->set_pio_mode is not implemented currently
+	 * so this is just for the completness
+	 */
+	ide_set_max_pio(drive);
+
+	return -1;
 }
 
 /* returns 1 if dma irq issued, 0 otherwise */
@@ -353,7 +366,7 @@
 }
 
 /* Creates a dma map for the scatter-gather list entries */
-static void __devinit
+static int __devinit
 ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
 {
 	void __iomem *virt_dma_base;
@@ -369,7 +382,7 @@
 		       "ALREADY in use\n",
 		       __FUNCTION__, hwif->name, (void *) dma_base,
 		       (void *) dma_base + num_ports - 1);
-		goto dma_alloc_failure;
+		return -1;
 	}
 
 	virt_dma_base = ioremap(dma_base, num_ports);
@@ -395,7 +408,7 @@
 
 	if (pad) {
 		ide_set_hwifdata(hwif, pad);
-		return;
+		return 0;
 	}
 
 	pci_free_consistent(hwif->pci_dev,
@@ -413,10 +426,7 @@
 dma_remap_failure:
 	release_mem_region(dma_base, num_ports);
 
-dma_alloc_failure:
-	/* Disable DMA because we couldnot allocate any DMA maps */
-	hwif->autodma = 0;
-	hwif->atapi_dma = 0;
+	return -1;
 }
 
 /* Initializes the IOC4 DMA Engine */
@@ -581,13 +591,11 @@
 ide_init_sgiioc4(ide_hwif_t * hwif)
 {
 	hwif->mmio = 1;
-	hwif->autodma = 1;
 	hwif->atapi_dma = 1;
-	hwif->ultra_mask = 0x0;	/* Disable Ultra DMA */
-	hwif->mwdma_mask = 0x2;	/* Multimode-2 DMA  */
-	hwif->swdma_mask = 0x2;
-	hwif->tuneproc = NULL;	/* Sets timing for PIO mode */
-	hwif->speedproc = NULL;	/* Sets timing for DMA &/or PIO modes */
+	hwif->mwdma_mask = 0x04;
+	hwif->pio_mask = 0x00;
+	hwif->set_pio_mode = NULL; /* Sets timing for PIO mode */
+	hwif->speedproc = &sgiioc4_speedproc;
 	hwif->selectproc = NULL;/* Use the default routine to select drive */
 	hwif->reset_poll = NULL;/* No HBA specific reset_poll needed */
 	hwif->pre_reset = NULL;	/* No HBA specific pre_set needed */
@@ -614,7 +622,7 @@
 }
 
 static int __devinit
-sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
+sgiioc4_ide_setup_pci_device(struct pci_dev *dev)
 {
 	unsigned long cmd_base, dma_base, irqport;
 	unsigned long bar0, cmd_phys_base, ctl;
@@ -631,7 +639,8 @@
 			break;
 	}
 	if (h == MAX_HWIFS) {
-		printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n", d->name);
+		printk(KERN_ERR "%s: too many IDE interfaces, no room in table\n",
+				DRV_NAME);
 		return -ENOMEM;
 	}
 
@@ -640,7 +649,7 @@
 	virt_base = ioremap(bar0, pci_resource_len(dev, 0));
 	if (virt_base == NULL) {
 		printk(KERN_ERR "%s: Unable to remap BAR 0 address: 0x%lx\n",
-			d->name, bar0);
+				DRV_NAME, bar0);
 		return -ENOMEM;
 	}
 	cmd_base = (unsigned long) virt_base + IOC4_CMD_OFFSET;
@@ -671,7 +680,6 @@
 	hwif->chipset = ide_pci;
 	hwif->pci_dev = dev;
 	hwif->channel = 0;	/* Single Channel chip */
-	hwif->cds = (struct ide_pci_device_s *) d;
 	hwif->gendev.parent = &dev->dev;/* setup proper ancestral information */
 
 	/* The IOC4 uses MMIO rather than Port IO. */
@@ -682,11 +690,14 @@
 
 	ide_init_sgiioc4(hwif);
 
-	if (dma_base)
-		ide_dma_sgiioc4(hwif, dma_base);
-	else
+	hwif->autodma = 0;
+
+	if (dma_base && ide_dma_sgiioc4(hwif, dma_base) == 0) {
+		hwif->autodma = 1;
+		hwif->drives[1].autodma = hwif->drives[0].autodma = 1;
+	} else
 		printk(KERN_INFO "%s: %s Bus-Master DMA disabled\n",
-		       hwif->name, d->name);
+				 hwif->name, DRV_NAME);
 
 	if (probe_hwif_init(hwif))
 		return -EIO;
@@ -698,7 +709,7 @@
 }
 
 static unsigned int __devinit
-pci_init_sgiioc4(struct pci_dev *dev, ide_pci_device_t * d)
+pci_init_sgiioc4(struct pci_dev *dev)
 {
 	unsigned int class_rev;
 	int ret;
@@ -706,30 +717,20 @@
 	pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
 	class_rev &= 0xff;
 	printk(KERN_INFO "%s: IDE controller at PCI slot %s, revision %d\n",
-			d->name, pci_name(dev), class_rev);
+			 DRV_NAME, pci_name(dev), class_rev);
 	if (class_rev < IOC4_SUPPORTED_FIRMWARE_REV) {
 		printk(KERN_ERR "Skipping %s IDE controller in slot %s: "
-			"firmware is obsolete - please upgrade to revision"
-			"46 or higher\n", d->name, pci_name(dev));
+				"firmware is obsolete - please upgrade to "
+				"revision46 or higher\n",
+				DRV_NAME, pci_name(dev));
 		ret = -EAGAIN;
 		goto out;
 	}
-	ret = sgiioc4_ide_setup_pci_device(dev, d);
+	ret = sgiioc4_ide_setup_pci_device(dev);
 out:
 	return ret;
 }
 
-static ide_pci_device_t sgiioc4_chipset __devinitdata = {
-	 /* Channel 0 */
-	 .name = "SGIIOC4",
-	 .init_hwif = ide_init_sgiioc4,
-	 .init_dma = ide_dma_sgiioc4,
-	 .channels = 1,
-	 .autodma = AUTODMA,
-	 /* SGI IOC4 doesn't have enablebits. */
-	 .bootable = ON_BOARD,
-};
-
 int
 ioc4_ide_attach_one(struct ioc4_driver_data *idd)
 {
@@ -739,7 +740,7 @@
 	if (idd->idd_variant == IOC4_VARIANT_PCI_RT)
 		return 0;
 
-	return pci_init_sgiioc4(idd->idd_pdev, &sgiioc4_chipset);
+	return pci_init_sgiioc4(idd->idd_pdev);
 }
 
 static struct ioc4_submodule ioc4_ide_submodule = {
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 1c3e354..5d1e5e5 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -1,9 +1,10 @@
 /*
- * linux/drivers/ide/pci/siimage.c		Version 1.12	Mar 10 2007
+ * linux/drivers/ide/pci/siimage.c		Version 1.16	Jul 13 2007
  *
  * Copyright (C) 2001-2002	Andre Hedrick <andre@linux-ide.org>
  * Copyright (C) 2003		Red Hat <alan@redhat.com>
  * Copyright (C) 2007		MontaVista Software, Inc.
+ * Copyright (C) 2007		Bartlomiej Zolnierkiewicz
  *
  *  May be copied or modified under the terms of the GNU General Public License
  *
@@ -31,6 +32,10 @@
  *  unplugging/replugging the virtual CD interface when the DRAC is reset.
  *  This often causes drivers/ide/siimage to panic but is ok with the rather
  *  smarter code in libata.
+ *
+ * TODO:
+ * - IORDY fixes
+ * - VDMA support
  */
 
 #include <linux/types.h>
@@ -160,140 +165,90 @@
 }
 
 /**
- *	siimage_taskfile_timing	-	turn timing data to a mode
- *	@hwif: interface to query
- *
- *	Read the timing data for the interface and return the 
- *	mode that is being used.
- */
- 
-static byte siimage_taskfile_timing (ide_hwif_t *hwif)
-{
-	u16 timing	= 0x328a;
-	unsigned long addr = siimage_selreg(hwif, 2);
-
-	if (hwif->mmio)
-		timing = hwif->INW(addr);
-	else
-		pci_read_config_word(hwif->pci_dev, addr, &timing);
-
-	switch (timing) {
-		case 0x10c1:	return 4;
-		case 0x10c3:	return 3;
-		case 0x1104:
-		case 0x1281:	return 2;
-		case 0x2283:	return 1;
-		case 0x328a:
-		default:	return 0;
-	}
-}
-
-/**
- *	simmage_tuneproc	-	tune a drive
+ *	sil_tune_pio	-	tune a drive
  *	@drive: drive to tune
- *	@mode_wanted: the target operating mode
+ *	@pio: the desired PIO mode
  *
  *	Load the timing settings for this device mode into the
  *	controller. If we are in PIO mode 3 or 4 turn on IORDY
  *	monitoring (bit 9). The TF timing is bits 31:16
  */
- 
-static void siimage_tuneproc (ide_drive_t *drive, byte mode_wanted)
+
+static void sil_tune_pio(ide_drive_t *drive, u8 pio)
 {
+	const u16 tf_speed[]	= { 0x328a, 0x2283, 0x1281, 0x10c3, 0x10c1 };
+	const u16 data_speed[]	= { 0x328a, 0x2283, 0x1104, 0x10c3, 0x10c1 };
+
 	ide_hwif_t *hwif	= HWIF(drive);
+	ide_drive_t *pair	= &hwif->drives[drive->dn ^ 1];
 	u32 speedt		= 0;
 	u16 speedp		= 0;
 	unsigned long addr	= siimage_seldev(drive, 0x04);
 	unsigned long tfaddr	= siimage_selreg(hwif, 0x02);
-	
-	/* cheat for now and use the docs */
-	switch (mode_wanted) {
-	case 4:
-		speedp = 0x10c1;
-		speedt = 0x10c1;
-		break;
-	case 3:
-		speedp = 0x10c3;
-		speedt = 0x10c3;
-		break;
-	case 2:
-		speedp = 0x1104;
-		speedt = 0x1281;
-		break;
-	case 1:
-		speedp = 0x2283;
-		speedt = 0x2283;
-		break;
-	case 0:
-	default:
-		speedp = 0x328a;
-		speedt = 0x328a;
-		break;
+	unsigned long base	= (unsigned long)hwif->hwif_data;
+	u8 tf_pio		= pio;
+	u8 addr_mask		= hwif->channel ? (hwif->mmio ? 0xF4 : 0x84)
+						: (hwif->mmio ? 0xB4 : 0x80);
+	u8 mode			= 0;
+	u8 unit			= drive->select.b.unit;
+
+	/* trim *taskfile* PIO to the slowest of the master/slave */
+	if (pair->present) {
+		u8 pair_pio = ide_get_best_pio_mode(pair, 255, 4);
+
+		if (pair_pio < tf_pio)
+			tf_pio = pair_pio;
 	}
 
+	/* cheat for now and use the docs */
+	speedp = data_speed[pio];
+	speedt = tf_speed[tf_pio];
+
 	if (hwif->mmio) {
 		hwif->OUTW(speedp, addr);
 		hwif->OUTW(speedt, tfaddr);
 		/* Now set up IORDY */
-		if(mode_wanted == 3 || mode_wanted == 4)
+		if (pio > 2)
 			hwif->OUTW(hwif->INW(tfaddr-2)|0x200, tfaddr-2);
 		else
 			hwif->OUTW(hwif->INW(tfaddr-2)&~0x200, tfaddr-2);
+
+		mode = hwif->INB(base + addr_mask);
+		mode &= ~(unit ? 0x30 : 0x03);
+		mode |= (unit ? 0x10 : 0x01);
+		hwif->OUTB(mode, base + addr_mask);
 	} else {
 		pci_write_config_word(hwif->pci_dev, addr, speedp);
 		pci_write_config_word(hwif->pci_dev, tfaddr, speedt);
 		pci_read_config_word(hwif->pci_dev, tfaddr-2, &speedp);
 		speedp &= ~0x200;
 		/* Set IORDY for mode 3 or 4 */
-		if(mode_wanted == 3 || mode_wanted == 4)
+		if (pio > 2)
 			speedp |= 0x200;
 		pci_write_config_word(hwif->pci_dev, tfaddr-2, speedp);
+
+		pci_read_config_byte(hwif->pci_dev, addr_mask, &mode);
+		mode &= ~(unit ? 0x30 : 0x03);
+		mode |= (unit ? 0x10 : 0x01);
+		pci_write_config_byte(hwif->pci_dev, addr_mask, mode);
 	}
 }
 
-/**
- *	config_siimage_chipset_for_pio	-	set drive timings
- *	@drive: drive to tune
- *	@speed we want
- *
- *	Compute the best pio mode we can for a given device. Also honour
- *	the timings for the driver when dealing with mixed devices. Some
- *	of this is ugly but its all wrapped up here
- *
- *	The SI680 can also do VDMA - we need to start using that
- *
- *	FIXME: we use the BIOS channel timings to avoid driving the task
- *	files too fast at the disk. We need to compute the master/slave
- *	drive PIO mode properly so that we can up the speed on a hotplug
- *	system.
- */
- 
-static void config_siimage_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+static void sil_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	u8 channel_timings	= siimage_taskfile_timing(HWIF(drive));
-	u8 speed = 0, set_pio	= ide_get_best_pio_mode(drive, 4, 5, NULL);
-
-	/* WARNING PIO timing mess is going to happen b/w devices, argh */
-	if ((channel_timings != set_pio) && (set_pio > channel_timings))
-		set_pio = channel_timings;
-
-	siimage_tuneproc(drive, set_pio);
-	speed = XFER_PIO_0 + set_pio;
-	if (set_speed)
-		(void) ide_config_drive_speed(drive, speed);
+	sil_tune_pio(drive, pio);
+	(void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
 /**
  *	siimage_tune_chipset	-	set controller timings
  *	@drive: Drive to set up
- *	@xferspeed: speed we want to achieve
+ *	@speed: speed we want to achieve
  *
- *	Tune the SII chipset for the desired mode. If we can't achieve
- *	the desired mode then tune for a lower one, but ultimately
- *	make the thing work.
+ *	Tune the SII chipset for the desired mode.
  */
- 
-static int siimage_tune_chipset (ide_drive_t *drive, byte xferspeed)
+
+static int siimage_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	u8 ultra6[]		= { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 };
 	u8 ultra5[]		= { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01 };
@@ -302,7 +257,6 @@
 	ide_hwif_t *hwif	= HWIF(drive);
 	u16 ultra = 0, multi	= 0;
 	u8 mode = 0, unit	= drive->select.b.unit;
-	u8 speed		= ide_rate_filter(drive, xferspeed);
 	unsigned long base	= (unsigned long)hwif->hwif_data;
 	u8 scsc = 0, addr_mask	= ((hwif->channel) ?
 				    ((hwif->mmio) ? 0xF4 : 0x84) :
@@ -330,20 +284,11 @@
 	scsc = is_sata(hwif) ? 1 : scsc;
 
 	switch(speed) {
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			siimage_tuneproc(drive, (speed - XFER_PIO_0));
-			mode |= ((unit) ? 0x10 : 0x01);
-			break;
 		case XFER_MW_DMA_2:
 		case XFER_MW_DMA_1:
 		case XFER_MW_DMA_0:
 			multi = dma[speed - XFER_MW_DMA_0];
 			mode |= ((unit) ? 0x20 : 0x02);
-			config_siimage_chipset_for_pio(drive, 0);
 			break;
 		case XFER_UDMA_6:
 		case XFER_UDMA_5:
@@ -356,7 +301,6 @@
 			ultra |= ((scsc) ? (ultra6[speed - XFER_UDMA_0]) :
 					   (ultra5[speed - XFER_UDMA_0]));
 			mode |= ((unit) ? 0x30 : 0x03);
-			config_siimage_chipset_for_pio(drive, 0);
 			break;
 		default:
 			return 1;
@@ -390,7 +334,7 @@
 		return 0;
 
 	if (ide_use_fast_pio(drive))
-		config_siimage_chipset_for_pio(drive, 1);
+		ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -961,7 +905,7 @@
 	
 	hwif->resetproc = &siimage_reset;
 	hwif->speedproc = &siimage_tune_chipset;
-	hwif->tuneproc	= &siimage_tuneproc;
+	hwif->set_pio_mode = &sil_set_pio_mode;
 	hwif->reset_poll = &siimage_reset_poll;
 	hwif->pre_reset = &siimage_pre_reset;
 	hwif->udma_filter = &sil_udma_filter;
@@ -976,11 +920,11 @@
 			first = 0;
 		}
 	}
-	if (!hwif->dma_base) {
-		hwif->drives[0].autotune = 1;
-		hwif->drives[1].autotune = 1;
+
+	hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+
+	if (hwif->dma_base == 0)
 		return;
-	}
 
 	hwif->ultra_mask = 0x7f;
 	hwif->mwdma_mask = 0x07;
@@ -1016,9 +960,9 @@
 		.init_iops	= init_iops_siimage,	\
 		.init_hwif	= init_hwif_siimage,	\
 		.fixup		= siimage_fixup,	\
-		.channels	= 2,			\
 		.autodma	= AUTODMA,		\
 		.bootable	= ON_BOARD,		\
+		.pio_mask	= ATA_PIO4,		\
 	}
 
 static ide_pci_device_t siimage_chipsets[] __devinitdata = {
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
index 756a9b6..3e18899 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/sis5513.c	Version 0.25	Jun 10, 2007
+ * linux/drivers/ide/pci/sis5513.c	Version 0.27	Jul 14, 2007
  *
  * Copyright (C) 1999-2000	Andre Hedrick <andre@linux-ide.org>
  * Copyright (C) 2002		Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
@@ -519,27 +519,18 @@
 	}
 }
 
-static int sis5513_tune_drive(ide_drive_t *drive, u8 pio)
+static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
 	config_art_rwp_pio(drive, pio);
-	return ide_config_drive_speed(drive, XFER_PIO_0 + pio);
+	(void)ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
-static void sis5513_tuneproc(ide_drive_t *drive, u8 pio)
-{
-	(void)sis5513_tune_drive(drive, pio);
-}
-
-static int sis5513_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static int sis5513_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
-
-	u8 drive_pci, reg, speed;
 	u32 regdw;
-
-	speed = ide_rate_filter(drive, xferspeed);
+	u8 drive_pci, reg;
 
 	/* See config_art_rwp_pio for drive pci config registers */
 	drive_pci = 0x40;
@@ -582,9 +573,6 @@
 					regdw |= (unsigned long)cycle_time_value[ATA_133][speed-XFER_UDMA_0] << 4;
 					regdw |= (unsigned long)cvs_time_value[ATA_133][speed-XFER_UDMA_0] << 8;
 				} else {
-				/* if ATA133 disable, we should not set speed above UDMA5 */
-					if (speed > XFER_UDMA_5)
-						speed = XFER_UDMA_5;
 					regdw |= (unsigned long)cycle_time_value[ATA_100][speed-XFER_UDMA_0] << 4;
 					regdw |= (unsigned long)cvs_time_value[ATA_100][speed-XFER_UDMA_0] << 8;
 				}
@@ -608,12 +596,6 @@
 		case XFER_SW_DMA_1:
 		case XFER_SW_DMA_0:
 			break;
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			return sis5513_tune_drive(drive, speed - XFER_PIO_0);
 		default:
 			BUG();
 			break;
@@ -627,7 +609,7 @@
 	/*
 	 * TODO: always set PIO mode and remove this
 	 */
-	sis5513_tuneproc(drive, 255);
+	ide_set_max_pio(drive);
 
 	drive->init_speed = 0;
 
@@ -635,11 +617,25 @@
 		return 0;
 
 	if (ide_use_fast_pio(drive))
-		sis5513_tuneproc(drive, 255);
+		ide_set_max_pio(drive);
 
 	return -1;
 }
 
+static u8 sis5513_ata133_udma_filter(ide_drive_t *drive)
+{
+	struct pci_dev *dev = drive->hwif->pci_dev;
+	int drive_pci;
+	u32 reg54 = 0, regdw = 0;
+
+	pci_read_config_dword(dev, 0x54, &reg54);
+	drive_pci = ((reg54 & 0x40000000) ? 0x70 : 0x40) + drive->dn * 4;
+	pci_read_config_dword(dev, drive_pci, &regdw);
+
+	/* if ATA133 disable, we should not set speed above UDMA5 */
+	return (regdw & 0x08) ? ATA_UDMA6 : ATA_UDMA5;
+}
+
 /* Chip detection and general config */
 static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const char *name)
 {
@@ -801,6 +797,7 @@
 static const struct sis_laptop sis_laptop[] = {
 	/* devid, subvendor, subdev */
 	{ 0x5513, 0x1043, 0x1107 },	/* ASUS A6K */
+	{ 0x5513, 0x1734, 0x105f },	/* FSC Amilo A1630 */
 	/* end marker */
 	{ 0, }
 };
@@ -843,9 +840,12 @@
 	if (!hwif->irq)
 		hwif->irq = hwif->channel ? 15 : 14;
 
-	hwif->tuneproc = &sis5513_tuneproc;
+	hwif->set_pio_mode = &sis_set_pio_mode;
 	hwif->speedproc = &sis5513_tune_chipset;
 
+	if (chipset_family >= ATA_133)
+		hwif->udma_filter = sis5513_ata133_udma_filter;
+
 	if (!(hwif->dma_base)) {
 		hwif->drives[0].autotune = 1;
 		hwif->drives[1].autotune = 1;
@@ -878,10 +878,10 @@
 	.name		= "SIS5513",
 	.init_chipset	= init_chipset_sis5513,
 	.init_hwif	= init_hwif_sis5513,
-	.channels	= 2,
 	.autodma	= NOAUTODMA,
 	.enablebits	= {{0x4a,0x02,0x02}, {0x4a,0x04,0x04}},
 	.bootable	= ON_BOARD,
+	.pio_mask	= ATA_PIO4,
 };
 
 static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index a7323d2..f492318 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -52,12 +52,13 @@
  * Convert a PIO mode and cycle time to the required on/off times
  * for the interface.  This has protection against runaway timings.
  */
-static unsigned int get_pio_timings(ide_pio_data_t *p)
+static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio)
 {
 	unsigned int cmd_on, cmd_off;
+	u8 iordy = 0;
 
-	cmd_on  = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
-	cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
+	cmd_on  = (ide_pio_timings[pio].active_time + 29) / 30;
+	cmd_off = (ide_pio_cycle_time(drive, pio) - 30 * cmd_on + 29) / 30;
 
 	if (cmd_on == 0)
 		cmd_on = 1;
@@ -65,24 +66,22 @@
 	if (cmd_off == 0)
 		cmd_off = 1;
 
-	return (cmd_on - 1) << 8 | (cmd_off - 1) | (p->use_iordy ? 0x40 : 0x00);
+	if (pio > 2 || ide_dev_has_iordy(drive->id))
+		iordy = 0x40;
+
+	return (cmd_on - 1) << 8 | (cmd_off - 1) | iordy;
 }
 
 /*
  * Configure the chipset for PIO mode.
  */
-static u8 sl82c105_tune_pio(ide_drive_t *drive, u8 pio)
+static void sl82c105_tune_pio(ide_drive_t *drive, const u8 pio)
 {
 	struct pci_dev *dev	= HWIF(drive)->pci_dev;
 	int reg			= 0x44 + drive->dn * 4;
-	ide_pio_data_t p;
 	u16 drv_ctrl;
 
-	DBG(("sl82c105_tune_pio(drive:%s, pio:%u)\n", drive->name, pio));
-
-	pio = ide_get_best_pio_mode(drive, pio, 5, &p);
-
-	drv_ctrl = get_pio_timings(&p);
+	drv_ctrl = get_pio_timings(drive, pio);
 
 	/*
 	 * Store the PIO timings so that we can restore them
@@ -101,15 +100,14 @@
 	}
 
 	printk(KERN_DEBUG "%s: selected %s (%dns) (%04X)\n", drive->name,
-	       ide_xfer_verbose(pio + XFER_PIO_0), p.cycle_time, drv_ctrl);
-
-	return pio;
+			  ide_xfer_verbose(pio + XFER_PIO_0),
+			  ide_pio_cycle_time(drive, pio), drv_ctrl);
 }
 
 /*
  * Configure the drive and chipset for a new transfer speed.
  */
-static int sl82c105_tune_chipset(ide_drive_t *drive, u8 speed)
+static int sl82c105_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	static u16 mwdma_timings[] = {0x0707, 0x0201, 0x0200};
 	u16 drv_ctrl;
@@ -117,8 +115,6 @@
  	DBG(("sl82c105_tune_chipset(drive:%s, speed:%s)\n",
 	     drive->name, ide_xfer_verbose(speed)));
 
-	speed = ide_rate_filter(drive, speed);
-
 	switch (speed) {
 	case XFER_MW_DMA_2:
 	case XFER_MW_DMA_1:
@@ -143,14 +139,6 @@
 			pci_write_config_word(dev, reg, drv_ctrl);
 		}
 		break;
-	case XFER_PIO_5:
-	case XFER_PIO_4:
-	case XFER_PIO_3:
-	case XFER_PIO_2:
-	case XFER_PIO_1:
-	case XFER_PIO_0:
-		(void) sl82c105_tune_pio(drive, speed - XFER_PIO_0);
-		break;
 	default:
 		return -1;
 	}
@@ -323,11 +311,10 @@
  * We only deal with PIO mode here - DMA mode 'using_dma' is not
  * initialised at the point that this function is called.
  */
-static void sl82c105_tune_drive(ide_drive_t *drive, u8 pio)
+static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	DBG(("sl82c105_tune_drive(drive:%s, pio:%u)\n", drive->name, pio));
+	sl82c105_tune_pio(drive, pio);
 
-	pio = sl82c105_tune_pio(drive, pio);
 	(void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
@@ -395,7 +382,7 @@
 
 	DBG(("init_hwif_sl82c105(hwif: ide%d)\n", hwif->index));
 
-	hwif->tuneproc		= &sl82c105_tune_drive;
+	hwif->set_pio_mode	= &sl82c105_set_pio_mode;
 	hwif->speedproc 	= &sl82c105_tune_chipset;
 	hwif->selectproc	= &sl82c105_selectproc;
 	hwif->resetproc 	= &sl82c105_resetproc;
@@ -449,10 +436,10 @@
 	.name		= "W82C105",
 	.init_chipset	= init_chipset_sl82c105,
 	.init_hwif	= init_hwif_sl82c105,
-	.channels	= 2,
 	.autodma	= NOAUTODMA,
 	.enablebits	= {{0x40,0x01,0x01}, {0x40,0x10,0x10}},
 	.bootable	= ON_BOARD,
+	.pio_mask	= ATA_PIO5,
 };
 
 static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index 575dbbd..ae8e913 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/pci/slc90e66.c	Version 0.14	February 8, 2007
+ *  linux/drivers/ide/pci/slc90e66.c	Version 0.16	Jul 14, 2007
  *
  *  Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
  *  Copyright (C) 2006-2007 MontaVista Software, Inc. <source@mvista.com>
@@ -29,20 +29,14 @@
 		case XFER_UDMA_1:
 		case XFER_UDMA_0:
 		case XFER_MW_DMA_2:
-		case XFER_PIO_4:
 			return 4;
 		case XFER_MW_DMA_1:
-		case XFER_PIO_3:
 			return 3;
 		case XFER_SW_DMA_2:
-		case XFER_PIO_2:
 			return 2;
 		case XFER_MW_DMA_0:
 		case XFER_SW_DMA_1:
 		case XFER_SW_DMA_0:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-		case XFER_PIO_SLOW:
 		default:
 			return 0;
 	}
@@ -101,19 +95,17 @@
 	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
-static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
+static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
 	slc90e66_tune_pio(drive, pio);
 	(void) ide_config_drive_speed(drive, XFER_PIO_0 + pio);
 }
 
-static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+static int slc90e66_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	struct pci_dev *dev	= hwif->pci_dev;
 	u8 maslave		= hwif->channel ? 0x42 : 0x40;
-	u8 speed		= ide_rate_filter(drive, xferspeed);
 	int sitre = 0, a_speed	= 7 << (drive->dn * 4);
 	int u_speed = 0, u_flag = 1 << drive->dn;
 	u16			reg4042, reg44, reg48, reg4a;
@@ -133,10 +125,6 @@
 		case XFER_MW_DMA_2:
 		case XFER_MW_DMA_1:
 		case XFER_SW_DMA_2:	break;
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_0:        break;
 		default:		return -1;
 	}
 
@@ -157,6 +145,7 @@
 	}
 
 	slc90e66_tune_pio(drive, slc90e66_dma_2_pio(speed));
+
 	return ide_config_drive_speed(drive, speed);
 }
 
@@ -168,7 +157,7 @@
 		return 0;
 
 	if (ide_use_fast_pio(drive))
-		slc90e66_tune_drive(drive, 255);
+		ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -184,7 +173,7 @@
 		hwif->irq = hwif->channel ? 15 : 14;
 
 	hwif->speedproc = &slc90e66_tune_chipset;
-	hwif->tuneproc	= &slc90e66_tune_drive;
+	hwif->set_pio_mode = &slc90e66_set_pio_mode;
 
 	pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
 
@@ -214,10 +203,10 @@
 static ide_pci_device_t slc90e66_chipset __devinitdata = {
 	.name		= "SLC90E66",
 	.init_hwif	= init_hwif_slc90e66,
-	.channels	= 2,
 	.autodma	= AUTODMA,
 	.enablebits	= {{0x41,0x80,0x80}, {0x43,0x80,0x80}},
 	.bootable	= ON_BOARD,
+	.pio_mask	= ATA_PIO4,
 };
 
 static int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_device_id *id)
diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
index 8de1f8e..e23b9cf 100644
--- a/drivers/ide/pci/tc86c001.c
+++ b/drivers/ide/pci/tc86c001.c
@@ -13,14 +13,12 @@
 #include <linux/pci.h>
 #include <linux/ide.h>
 
-static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed)
+static int tc86c001_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	ide_hwif_t *hwif	= HWIF(drive);
 	unsigned long scr_port	= hwif->config_data + (drive->dn ? 0x02 : 0x00);
 	u16 mode, scr		= hwif->INW(scr_port);
 
-	speed = ide_rate_filter(drive, speed);
-
 	switch (speed) {
 		case XFER_UDMA_4:	mode = 0x00c0; break;
 		case XFER_UDMA_3:	mode = 0x00b0; break;
@@ -45,9 +43,8 @@
 	return ide_config_drive_speed(drive, speed);
 }
 
-static void tc86c001_tune_drive(ide_drive_t *drive, u8 pio)
+static void tc86c001_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	pio =  ide_get_best_pio_mode(drive, pio, 4, NULL);
 	(void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio);
 }
 
@@ -173,7 +170,7 @@
 		return 0;
 
 	if (ide_use_fast_pio(drive))
-		tc86c001_tune_drive(drive, 255);
+		ide_set_max_pio(drive);
 
 	return -1;
 }
@@ -195,7 +192,7 @@
 	/* Store the system control register base for convenience... */
 	hwif->config_data = sc_base;
 
-	hwif->tuneproc	= &tc86c001_tune_drive;
+	hwif->set_pio_mode = &tc86c001_set_pio_mode;
 	hwif->speedproc = &tc86c001_tune_chipset;
 	hwif->busproc	= &tc86c001_busproc;
 
@@ -248,9 +245,10 @@
 	.name		= "TC86C001",
 	.init_chipset	= init_chipset_tc86c001,
 	.init_hwif	= init_hwif_tc86c001,
-	.channels	= 1,
 	.autodma	= AUTODMA,
-	.bootable	= OFF_BOARD
+	.bootable	= OFF_BOARD,
+	.host_flags	= IDE_HFLAG_SINGLE,
+	.pio_mask	= ATA_PIO4,
 };
 
 static int __devinit tc86c001_init_one(struct pci_dev *dev,
diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
index 35e8c61..c3ff066 100644
--- a/drivers/ide/pci/triflex.c
+++ b/drivers/ide/pci/triflex.c
@@ -40,7 +40,7 @@
 #include <linux/ide.h>
 #include <linux/init.h>
 
-static int triflex_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int triflex_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	ide_hwif_t *hwif = HWIF(drive);
 	struct pci_dev *dev = hwif->pci_dev;
@@ -48,7 +48,6 @@
 	u16 timing = 0;
 	u32 triflex_timings = 0;
 	u8 unit = (drive->select.b.unit & 0x01);
-	u8 speed = ide_rate_filter(drive, xferspeed);
 	
 	pci_read_config_dword(dev, channel_offset, &triflex_timings);
 	
@@ -94,10 +93,9 @@
 	return (ide_config_drive_speed(drive, speed));
 }
 
-static void triflex_tune_drive(ide_drive_t *drive, u8 pio)
+static void triflex_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	int use_pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
-	(void) triflex_tune_chipset(drive, (XFER_PIO_0 + use_pio));
+	(void)triflex_tune_chipset(drive, XFER_PIO_0 + pio);
 }
 
 static int triflex_config_drive_xfer_rate(ide_drive_t *drive)
@@ -105,16 +103,19 @@
 	if (ide_tune_dma(drive))
 		return 0;
 
-	triflex_tune_drive(drive, 255);
+	ide_set_max_pio(drive);
 
 	return -1;
 }
 
 static void __devinit init_hwif_triflex(ide_hwif_t *hwif)
 {
-	hwif->tuneproc = &triflex_tune_drive;
+	hwif->set_pio_mode = &triflex_set_pio_mode;
 	hwif->speedproc = &triflex_tune_chipset;
 
+	if (hwif->dma_base == 0)
+		return;
+
 	hwif->atapi_dma  = 1;
 	hwif->mwdma_mask = 0x07;
 	hwif->swdma_mask = 0x07;
@@ -129,10 +130,10 @@
 static ide_pci_device_t triflex_device __devinitdata = {
 	.name		= "TRIFLEX",
 	.init_hwif	= init_hwif_triflex,
-	.channels	= 2,
 	.autodma	= AUTODMA,
 	.enablebits	= {{0x80, 0x01, 0x01}, {0x80, 0x02, 0x02}},
 	.bootable	= ON_BOARD,
+	.pio_mask	= ATA_PIO4,
 };
 
 static int __devinit triflex_init_one(struct pci_dev *dev, 
diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
index cbb1b11..dc4f4e2 100644
--- a/drivers/ide/pci/trm290.c
+++ b/drivers/ide/pci/trm290.c
@@ -327,7 +327,6 @@
 static ide_pci_device_t trm290_chipset __devinitdata = {
 	.name		= "TRM290",
 	.init_hwif	= init_hwif_trm290,
-	.channels	= 2,
 	.autodma	= NOAUTODMA,
 	.bootable	= ON_BOARD,
 };
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
index 27e92fb..378feb4 100644
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/pci/via82cxxx.c
@@ -1,6 +1,6 @@
 /*
  *
- * Version 3.45
+ * Version 3.48
  *
  * VIA IDE driver for Linux. Supported southbridges:
  *
@@ -74,6 +74,7 @@
 	u8 udma_mask;
 	u8 flags;
 } via_isa_bridges[] = {
+	{ "vx800",	PCI_DEVICE_ID_VIA_VX800,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
 	{ "cx700",	PCI_DEVICE_ID_VIA_CX700,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
 	{ "vt8237s",	PCI_DEVICE_ID_VIA_8237S,    0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
 	{ "vt6410",	PCI_DEVICE_ID_VIA_6410,     0x00, 0x2f, ATA_UDMA6, VIA_BAD_AST },
@@ -157,7 +158,7 @@
  *	by upper layers.
  */
 
-static int via_set_drive(ide_drive_t *drive, u8 speed)
+static int via_set_drive(ide_drive_t *drive, const u8 speed)
 {
 	ide_drive_t *peer = HWIF(drive)->drives + (~drive->dn & 1);
 	struct via82cxxx_dev *vdev = pci_get_drvdata(drive->hwif->pci_dev);
@@ -194,21 +195,16 @@
 }
 
 /**
- *	via82cxxx_tune_drive	-	PIO setup
- *	@drive: drive to set up
- *	@pio: mode to use (255 for 'best possible')
+ *	via_set_pio_mode	-	PIO setup
+ *	@drive: drive
+ *	@pio: PIO mode number
  *
  *	A callback from the upper layers for PIO-only tuning.
  */
 
-static void via82cxxx_tune_drive(ide_drive_t *drive, u8 pio)
+static void via_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	if (pio == 255) {
-		via_set_drive(drive, ide_find_best_pio_mode(drive));
-		return;
-	}
-
-	via_set_drive(drive, XFER_PIO_0 + min_t(u8, pio, 5));
+	via_set_drive(drive, XFER_PIO_0 + pio);
 }
 
 /**
@@ -221,16 +217,11 @@
  
 static int via82cxxx_ide_dma_check (ide_drive_t *drive)
 {
-	u8 speed = ide_max_dma_mode(drive);
-
-	if (speed == 0)
-		speed = ide_find_best_pio_mode(drive);
-
-	via_set_drive(drive, speed);
-
-	if (drive->autodma && (speed & XFER_MODE) != XFER_PIO)
+	if (ide_tune_dma(drive))
 		return 0;
 
+	ide_set_max_pio(drive);
+
 	return -1;
 }
 
@@ -418,7 +409,7 @@
  *	Cable special cases
  */
 
-static struct dmi_system_id cable_dmi_table[] = {
+static const struct dmi_system_id cable_dmi_table[] = {
 	{
 		.ident = "Acer Ferrari 3400",
 		.matches = {
@@ -429,19 +420,26 @@
 	{ }
 };
 
-static int via_cable_override(void)
+static int via_cable_override(struct pci_dev *pdev)
 {
 	/* Systems by DMI */
 	if (dmi_check_system(cable_dmi_table))
 		return 1;
+
+	/* Arima W730-K8/Targa Visionary 811/... */
+	if (pdev->subsystem_vendor == 0x161F &&
+	    pdev->subsystem_device == 0x2032)
+		return 1;
+
 	return 0;
 }
 
 static u8 __devinit via82cxxx_cable_detect(ide_hwif_t *hwif)
 {
-	struct via82cxxx_dev *vdev = pci_get_drvdata(hwif->pci_dev);
+	struct pci_dev *pdev = hwif->pci_dev;
+	struct via82cxxx_dev *vdev = pci_get_drvdata(pdev);
 
-	if (via_cable_override())
+	if (via_cable_override(pdev))
 		return ATA_CBL_PATA40_SHORT;
 
 	if ((vdev->via_80w >> hwif->channel) & 1)
@@ -457,7 +455,7 @@
 
 	hwif->autodma = 0;
 
-	hwif->tuneproc = &via82cxxx_tune_drive;
+	hwif->set_pio_mode = &via_set_pio_mode;
 	hwif->speedproc = &via_set_drive;
 
 
@@ -498,18 +496,22 @@
 		.name		= "VP_IDE",
 		.init_chipset	= init_chipset_via82cxxx,
 		.init_hwif	= init_hwif_via82cxxx,
-		.channels	= 2,
 		.autodma	= NOAUTODMA,
 		.enablebits	= {{0x40,0x02,0x02}, {0x40,0x01,0x01}},
-		.bootable	= ON_BOARD
+		.bootable	= ON_BOARD,
+		.host_flags	= IDE_HFLAG_PIO_NO_BLACKLIST
+				| IDE_HFLAG_PIO_NO_DOWNGRADE,
+		.pio_mask	= ATA_PIO5,
 	},{	/* 1 */
 		.name		= "VP_IDE",
 		.init_chipset	= init_chipset_via82cxxx,
 		.init_hwif	= init_hwif_via82cxxx,
-		.channels	= 2,
 		.autodma	= AUTODMA,
 		.enablebits	= {{0x00,0x00,0x00}, {0x00,0x00,0x00}},
 		.bootable	= ON_BOARD,
+		.host_flags	= IDE_HFLAG_PIO_NO_BLACKLIST
+				| IDE_HFLAG_PIO_NO_DOWNGRADE,
+		.pio_mask	= ATA_PIO5,
 	}
 };
 
diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c
index 82de2d7..df2e920 100644
--- a/drivers/ide/ppc/mpc8xx.c
+++ b/drivers/ide/ppc/mpc8xx.c
@@ -32,7 +32,6 @@
 #include <asm/mpc8xx.h>
 #include <asm/mmu.h>
 #include <asm/processor.h>
-#include <asm/residual.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/ide.h>
@@ -46,7 +45,7 @@
 static int check_ide_device (unsigned long base);
 
 static void ide_interrupt_ack (void *dev);
-static void m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio);
+static void m8xx_ide_set_pio_mode(ide_drive_t *drive, const u8 pio);
 
 typedef	struct ide_ioport_desc {
 	unsigned long	base_off;		/* Offset to PCMCIA memory	*/
@@ -315,8 +314,8 @@
 #endif	/* CONFIG_IDE_8xx_PCCARD */
 	}
 
-	/* register routine to tune PIO mode */
-	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
+	ide_hwifs[data_port].pio_mask = ATA_PIO4;
+	ide_hwifs[data_port].set_pio_mode = m8xx_ide_set_pio_mode;
 
 	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
 	/* Enable Harddisk Interrupt,
@@ -401,8 +400,8 @@
 		*irq = ioport_dsc[data_port].irq;
 	}
 
-	/* register routine to tune PIO mode */
-	ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc;
+	ide_hwifs[data_port].pio_mask = ATA_PIO4;
+	ide_hwifs[data_port].set_pio_mode = m8xx_ide_set_pio_mode;
 
 	hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack;
 	/* Enable Harddisk Interrupt,
@@ -426,25 +425,13 @@
 #define PCMCIA_SL(t) ((t==32) ? 0 : ((t & 0x1F)<<7)) /* Strobe Length	*/
 #endif
 
-
 /* Calculate PIO timings */
-static void
-m8xx_ide_tuneproc(ide_drive_t *drive, u8 pio)
+static void m8xx_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	ide_pio_data_t d;
 #if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
 	volatile pcmconf8xx_t	*pcmp;
 	ulong timing, mask, reg;
-#endif
 
-	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
-
-#if 1
-	printk("%s[%d] %s: best PIO mode: %d\n",
-		__FILE__,__LINE__,__FUNCTION__, pio);
-#endif
-
-#if defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_DIRECT)
 	pcmp = (pcmconf8xx_t *)(&(((immap_t *)IMAP_ADDR)->im_pcmcia));
 
 	mask = ~(PCMCIA_SHT(0xFF) | PCMCIA_SST(0xFF) | PCMCIA_SL(0xFF));
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index e46f4720..f759a53 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -6,6 +6,7 @@
  * for doing DMA.
  *
  *  Copyright (C) 1998-2003 Paul Mackerras & Ben. Herrenschmidt
+ *  Copyright (C)      2007 Bartlomiej Zolnierkiewicz
  *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
@@ -311,7 +312,8 @@
 	{ 240	, 0x0800038b },
 	{ 239	, 0x0800030c },
 	{ 180	, 0x05000249 },
-	{ 120	, 0x04000148 }
+	{ 120	, 0x04000148 },
+	{ 0	, 0 },
 };
 
 static struct kauai_timing	kauai_mdma_timings[] =
@@ -351,7 +353,8 @@
 	{ 240	, 0x040003cd },
 	{ 239	, 0x040003cd },
 	{ 180	, 0x0400028b },
-	{ 120	, 0x0400010a }
+	{ 120	, 0x0400010a },
+	{ 0	, 0 },
 };
 
 static struct kauai_timing	shasta_mdma_timings[] =
@@ -411,8 +414,6 @@
 
 static void pmac_ide_setup_dma(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif);
 static int pmac_ide_build_dmatable(ide_drive_t *drive, struct request *rq);
-static int pmac_ide_tune_chipset(ide_drive_t *drive, u8 speed);
-static void pmac_ide_tuneproc(ide_drive_t *drive, u8 pio);
 static void pmac_ide_selectproc(ide_drive_t *drive);
 static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
 
@@ -604,6 +605,9 @@
 				drive->id->dma_1word |= 0x0101; break;
 			default: break;
 		}
+		if (!drive->init_speed)
+			drive->init_speed = command;
+		drive->current_speed = command;
 	}
 	enable_irq(hwif->irq);
 	return result;
@@ -613,26 +617,26 @@
  * Old tuning functions (called on hdparm -p), sets up drive PIO timings
  */
 static void
-pmac_ide_tuneproc(ide_drive_t *drive, u8 pio)
+pmac_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
-	ide_pio_data_t d;
 	u32 *timings;
 	unsigned accessTicks, recTicks;
 	unsigned accessTime, recTime;
 	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)HWIF(drive)->hwif_data;
-	
+	unsigned int cycle_time;
+
 	if (pmif == NULL)
 		return;
 		
 	/* which drive is it ? */
 	timings = &pmif->timings[drive->select.b.unit & 0x01];
 
-	pio = ide_get_best_pio_mode(drive, pio, 4, &d);
+	cycle_time = ide_pio_cycle_time(drive, pio);
 
 	switch (pmif->kind) {
 	case controller_sh_ata6: {
 		/* 133Mhz cell */
-		u32 tr = kauai_lookup_timing(shasta_pio_timings, d.cycle_time);
+		u32 tr = kauai_lookup_timing(shasta_pio_timings, cycle_time);
 		if (tr == 0)
 			return;
 		*timings = ((*timings) & ~TR_133_PIOREG_PIO_MASK) | tr;
@@ -641,7 +645,7 @@
 	case controller_un_ata6:
 	case controller_k2_ata6: {
 		/* 100Mhz cell */
-		u32 tr = kauai_lookup_timing(kauai_pio_timings, d.cycle_time);
+		u32 tr = kauai_lookup_timing(kauai_pio_timings, cycle_time);
 		if (tr == 0)
 			return;
 		*timings = ((*timings) & ~TR_100_PIOREG_PIO_MASK) | tr;
@@ -649,7 +653,7 @@
 		}
 	case controller_kl_ata4:
 		/* 66Mhz cell */
-		recTime = d.cycle_time - ide_pio_timings[pio].active_time
+		recTime = cycle_time - ide_pio_timings[pio].active_time
 				- ide_pio_timings[pio].setup_time;
 		recTime = max(recTime, 150U);
 		accessTime = ide_pio_timings[pio].active_time;
@@ -665,7 +669,7 @@
 	default: {
 		/* 33Mhz cell */
 		int ebit = 0;
-		recTime = d.cycle_time - ide_pio_timings[pio].active_time
+		recTime = cycle_time - ide_pio_timings[pio].active_time
 				- ide_pio_timings[pio].setup_time;
 		recTime = max(recTime, 150U);
 		accessTime = ide_pio_timings[pio].active_time;
@@ -694,8 +698,10 @@
 		drive->name, pio,  *timings);
 #endif	
 
-	if (drive->select.all == HWIF(drive)->INB(IDE_SELECT_REG))
-		pmac_ide_do_update_timings(drive);
+	if (pmac_ide_do_setfeature(drive, XFER_PIO_0 + pio))
+		return;
+
+	pmac_ide_do_update_timings(drive);
 }
 
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
@@ -911,13 +917,12 @@
 
 /* 
  * Speedproc. This function is called by the core to set any of the standard
- * timing (PIO, MDMA or UDMA) to both the drive and the controller.
+ * DMA timing (MDMA or UDMA) to both the drive and the controller.
  * You may notice we don't use this function on normal "dma check" operation,
  * our dedicated function is more precise as it uses the drive provided
  * cycle time value. We should probably fix this one to deal with that too...
  */
-static int
-pmac_ide_tune_chipset (ide_drive_t *drive, byte speed)
+static int pmac_ide_tune_chipset(ide_drive_t *drive, const u8 speed)
 {
 	int unit = (drive->select.b.unit & 0x01);
 	int ret = 0;
@@ -933,17 +938,9 @@
 	switch(speed) {
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 		case XFER_UDMA_6:
-		        if (pmif->kind != controller_sh_ata6)
-				return 1;
 		case XFER_UDMA_5:
-			if (pmif->kind != controller_un_ata6 &&
-			    pmif->kind != controller_k2_ata6 &&
-			    pmif->kind != controller_sh_ata6)
-				return 1;
 		case XFER_UDMA_4:
 		case XFER_UDMA_3:
-			if (drive->hwif->cbl != ATA_CBL_PATA80)
-				return 1;
 		case XFER_UDMA_2:
 		case XFER_UDMA_1:
 		case XFER_UDMA_0:
@@ -967,13 +964,6 @@
 		case XFER_SW_DMA_0:
 			return 1;
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
-		case XFER_PIO_4:
-		case XFER_PIO_3:
-		case XFER_PIO_2:
-		case XFER_PIO_1:
-		case XFER_PIO_0:
-			pmac_ide_tuneproc(drive, speed & 0x07);
-			break;
 		default:
 			ret = 1;
 	}
@@ -985,7 +975,6 @@
 		return ret;
 		
 	pmac_ide_do_update_timings(drive);	
-	drive->current_speed = speed;
 
 	return 0;
 }
@@ -1247,7 +1236,8 @@
 	hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40;
 	hwif->drives[0].unmask = 1;
 	hwif->drives[1].unmask = 1;
-	hwif->tuneproc = pmac_ide_tuneproc;
+	hwif->pio_mask = ATA_PIO4;
+	hwif->set_pio_mode = pmac_ide_set_pio_mode;
 	if (pmif->kind == controller_un_ata6
 	    || pmif->kind == controller_k2_ata6
 	    || pmif->kind == controller_sh_ata6)
@@ -1542,6 +1532,7 @@
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_IPID2_ATA,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{},
 };
 
 static struct pci_driver pmac_ide_pci_driver = {
@@ -1735,11 +1726,6 @@
 	/* Apply timings to controller */
 	*timings = timing_local[0];
 	*timings2 = timing_local[1];
-	
-	/* Set speed info in drive */
-	drive->current_speed = mode;	
-	if (!drive->init_speed)
-		drive->init_speed = mode;
 
 	return 1;
 }
@@ -1791,11 +1777,6 @@
 	*timings = timing_local[0];
 	*timings2 = timing_local[1];
 
-	/* Set speed info in drive */
-	drive->current_speed = mode;	
-	if (!drive->init_speed)
-		drive->init_speed = mode;
-
 	return 1;
 }
 
@@ -1808,9 +1789,7 @@
 {
 	struct hd_driveid *id = drive->id;
 	ide_hwif_t *hwif = HWIF(drive);
-	pmac_ide_hwif_t* pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
 	int enable = 1;
-	int map;
 	drive->using_dma = 0;
 	
 	if (drive->media == ide_floppy)
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index c88d332..1129f8c 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -5,12 +5,6 @@
  *
  *  Copyright (c) 1995-1998  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
- *
- *  Recent Changes
- *	Split the set up function into multiple functions
- *	Use pci_set_master
- *	Fix misreporting of I/O v MMIO problems
- *	Initial fixups for simplex devices
  */
 
 /*
@@ -407,7 +401,7 @@
 	unsigned long ctl = 0, base = 0;
 	ide_hwif_t *hwif;
 
-	if ((d->flags & IDEPCI_FLAG_ISA_PORTS) == 0) {
+	if ((d->host_flags & IDE_HFLAG_ISA_PORTS) == 0) {
 		/*  Possibly we should fail if these checks report true */
 		ide_pci_check_iomem(dev, d, 2*port);
 		ide_pci_check_iomem(dev, d, 2*port+1);
@@ -571,7 +565,7 @@
  
 void ide_pci_setup_ports(struct pci_dev *dev, ide_pci_device_t *d, int pciirq, ata_index_t *index)
 {
-	int port;
+	int channels = (d->host_flags & IDE_HFLAG_SINGLE) ? 1 : 2, port;
 	int at_least_one_hwif_enabled = 0;
 	ide_hwif_t *hwif, *mate = NULL;
 	u8 tmp;
@@ -582,16 +576,13 @@
 	 * Set up the IDE ports
 	 */
 	 
-	for (port = 0; port <= 1; ++port) {
+	for (port = 0; port < channels; ++port) {
 		ide_pci_enablebit_t *e = &(d->enablebits[port]);
 	
 		if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
 		    (tmp & e->mask) != e->val))
 			continue;	/* port not enabled */
 
-		if (d->channels	<= port)
-			break;
-	
 		if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL)
 			continue;
 
@@ -616,6 +607,9 @@
 		else
 			ide_hwif_setup_dma(dev, d, hwif);
 bypass_legacy_dma:
+		hwif->host_flags = d->host_flags;
+		hwif->pio_mask = d->pio_mask;
+
 		if (d->init_hwif)
 			/* Call chipset-specific routine
 			 * for each enabled hwif
@@ -822,19 +816,15 @@
 	struct list_head *l;
 	struct pci_driver *d;
 	
-	list_for_each(l, &ide_pci_drivers)
-	{
+	list_for_each(l, &ide_pci_drivers) {
 		d = list_entry(l, struct pci_driver, node);
-		if(d->id_table)
-		{
-			const struct pci_device_id *id = pci_match_id(d->id_table, dev);
-			if(id != NULL)
-			{
-				if(d->probe(dev, id) >= 0)
-				{
-					dev->driver = d;
-					return 1;
-				}
+		if (d->id_table) {
+			const struct pci_device_id *id = pci_match_id(d->id_table,
+								      dev);
+			if (id != NULL && d->probe(dev, id) >= 0) {
+				dev->driver = d;
+				pci_dev_get(dev);
+				return 1;
 			}
 		}
 	}
@@ -857,15 +847,13 @@
 	struct list_head *l, *n;
 
 	pre_init = 0;
-	if (!scan_direction) {
-		while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+	if (!scan_direction)
+		while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
 			ide_scan_pcidev(dev);
-		}
-	} else {
-		while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+	else
+		while ((dev = pci_get_device_reverse(PCI_ANY_ID, PCI_ANY_ID, dev))
+		       != NULL)
 			ide_scan_pcidev(dev);
-		}
-	}
 	
 	/*
 	 *	Hand the drivers over to the PCI layer now we
@@ -875,12 +863,9 @@
 	list_for_each_safe(l, n, &ide_pci_drivers) {
 		list_del(l);
 		d = list_entry(l, struct pci_driver, node);
-		if (__pci_register_driver(d, d->driver.owner,
-					d->driver.mod_name)) {
-			printk(KERN_ERR "%s: failed to register driver "
-					"for %s\n", __FUNCTION__,
-					 d->driver.mod_name);
-		}
+		if (__pci_register_driver(d, d->driver.owner, d->driver.mod_name))
+			printk(KERN_ERR "%s: failed to register driver for %s\n",
+			       __FUNCTION__, d->driver.mod_name);
 	}
 }
 #endif
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index 8012b3b..545663e 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -97,7 +97,7 @@
 
 config IEEE1394_SBP2_PHYS_DMA
 	bool "Enable replacement for physical DMA in SBP2"
-	depends on IEEE1394 && IEEE1394_SBP2 && EXPERIMENTAL && (X86_32 || PPC_32)
+	depends on IEEE1394_SBP2 && VIRT_TO_BUS && EXPERIMENTAL
 	help
 	  This builds sbp2 for use with non-OHCI host adapters which do not
 	  support physical DMA or for when ohci1394 is run with phys_dma=0.
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index 93362ee..dc9dce2 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -159,14 +159,16 @@
 
 
 static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
-			    unsigned short type, void *daddr, void *saddr,
-			    unsigned len);
+			    unsigned short type, const void *daddr,
+			    const void *saddr, unsigned len);
 static int ether1394_rebuild_header(struct sk_buff *skb);
-static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr);
-static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh);
+static int ether1394_header_parse(const struct sk_buff *skb,
+				  unsigned char *haddr);
+static int ether1394_header_cache(const struct neighbour *neigh,
+				  struct hh_cache *hh);
 static void ether1394_header_cache_update(struct hh_cache *hh,
-					  struct net_device *dev,
-					  unsigned char *haddr);
+					  const struct net_device *dev,
+					  const unsigned char *haddr);
 static int ether1394_tx(struct sk_buff *skb, struct net_device *dev);
 static void ether1394_iso(struct hpsb_iso *iso);
 
@@ -506,6 +508,14 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
 
+static const struct header_ops ether1394_header_ops = {
+	.create		= ether1394_header,
+	.rebuild	= ether1394_rebuild_header,
+	.cache  	= ether1394_header_cache,
+	.cache_update	= ether1394_header_cache_update,
+	.parse		= ether1394_header_parse,
+};
+
 static void ether1394_init_dev(struct net_device *dev)
 {
 	dev->open		= ether1394_open;
@@ -515,11 +525,7 @@
 	dev->tx_timeout		= ether1394_tx_timeout;
 	dev->change_mtu		= ether1394_change_mtu;
 
-	dev->hard_header	= ether1394_header;
-	dev->rebuild_header	= ether1394_rebuild_header;
-	dev->hard_header_cache	= ether1394_header_cache;
-	dev->header_cache_update= ether1394_header_cache_update;
-	dev->hard_header_parse	= ether1394_header_parse;
+	dev->header_ops		= &ether1394_header_ops;
 
 	SET_ETHTOOL_OPS(dev, &ethtool_ops);
 
@@ -598,7 +604,6 @@
 		goto out;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &host->device);
 
 	priv = netdev_priv(dev);
@@ -711,8 +716,8 @@
  * saddr=NULL means use device source address
  * daddr=NULL means leave destination address (eg unresolved arp). */
 static int ether1394_header(struct sk_buff *skb, struct net_device *dev,
-			    unsigned short type, void *daddr, void *saddr,
-			    unsigned len)
+			    unsigned short type, const void *daddr,
+			    const void *saddr, unsigned len)
 {
 	struct eth1394hdr *eth =
 			(struct eth1394hdr *)skb_push(skb, ETH1394_HLEN);
@@ -752,15 +757,15 @@
 	return 0;
 }
 
-static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr)
+static int ether1394_header_parse(const struct sk_buff *skb,
+				  unsigned char *haddr)
 {
-	struct net_device *dev = skb->dev;
-
-	memcpy(haddr, dev->dev_addr, ETH1394_ALEN);
+	memcpy(haddr, skb->dev->dev_addr, ETH1394_ALEN);
 	return ETH1394_ALEN;
 }
 
-static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+static int ether1394_header_cache(const struct neighbour *neigh,
+				  struct hh_cache *hh)
 {
 	unsigned short type = hh->hh_type;
 	struct net_device *dev = neigh->dev;
@@ -779,8 +784,8 @@
 
 /* Called by Address Resolution module to notify changes in address. */
 static void ether1394_header_cache_update(struct hh_cache *hh,
-					  struct net_device *dev,
-					  unsigned char * haddr)
+					  const struct net_device *dev,
+					  const unsigned char * haddr)
 {
 	memcpy((u8 *)hh->hh_data + 16 - ETH1394_HLEN, haddr, dev->addr_len);
 }
@@ -900,8 +905,8 @@
 	}
 
 	/* Now add the ethernet header. */
-	if (dev->hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL,
-			     skb->len) >= 0)
+	if (dev_hard_header(skb, dev, ntohs(ether_type), &dest_hw, NULL,
+			    skb->len) >= 0)
 		ret = ether1394_type_trans(skb, dev);
 
 	return ret;
@@ -1729,7 +1734,7 @@
 
 	packet_task_cache = kmem_cache_create("packet_task",
 					      sizeof(struct packet_task),
-					      0, 0, NULL, NULL);
+					      0, 0, NULL);
 	if (!packet_task_cache)
 		return -ENOMEM;
 
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index ee452595..98fd985 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -1273,7 +1273,7 @@
 	unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
 }
 
-fs_initcall(ieee1394_init); /* same as ohci1394 */
+module_init(ieee1394_init);
 module_exit(ieee1394_cleanup);
 
 /* Exported symbols */
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 2ffd534..1939fee 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -153,8 +153,7 @@
 };
 
 static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
-			  char *buffer, int buffer_size);
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env);
 static void nodemgr_resume_ne(struct node_entry *ne);
 static void nodemgr_remove_ne(struct node_entry *ne);
 static struct node_entry *find_entry_by_guid(u64 guid);
@@ -1160,12 +1159,9 @@
 
 #ifdef CONFIG_HOTPLUG
 
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
-			  char *buffer, int buffer_size)
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct unit_directory *ud;
-	int i = 0;
-	int length = 0;
 	int retval = 0;
 	/* ieee1394:venNmoNspNverN */
 	char buf[8 + 1 + 3 + 8 + 2 + 8 + 2 + 8 + 3 + 8 + 1];
@@ -1180,9 +1176,7 @@
 
 #define PUT_ENVP(fmt,val) 					\
 do {								\
-	retval = add_uevent_var(envp, num_envp, &i,		\
-				buffer, buffer_size, &length,	\
-				fmt, val);			\
+	retval = add_uevent_var(env, fmt, val);		\
 	if (retval)						\
 		return retval;					\
 } while (0)
@@ -1201,15 +1195,12 @@
 
 #undef PUT_ENVP
 
-	envp[i] = NULL;
-
 	return 0;
 }
 
 #else
 
-static int nodemgr_uevent(struct device *dev, char **envp, int num_envp,
-			  char *buffer, int buffer_size)
+static int nodemgr_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	return -ENODEV;
 }
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 5667c81..372c5c1 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -3537,7 +3537,5 @@
 	return pci_register_driver(&ohci1394_pci_driver);
 }
 
-/* Register before most other device drivers.
- * Useful for remote debugging via physical DMA, e.g. using firescope. */
-fs_initcall(ohci1394_init);
+module_init(ohci1394_init);
 module_exit(ohci1394_cleanup);
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index 336e5ff..cadf047 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -2677,7 +2677,7 @@
                                           struct raw1394_iso_packets32 __user *arg)
 {
 	compat_uptr_t infos32;
-	void *infos;
+	void __user *infos;
 	long err = -EFAULT;
 	struct raw1394_iso_packets __user *dst = compat_alloc_user_space(sizeof(struct raw1394_iso_packets));
 
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index e882cb9..a81ba8f 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -513,9 +513,9 @@
 	return 0;
 }
 
-static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu)
+static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu,
+					     struct hpsb_host *host)
 {
-	struct hpsb_host *host = lu->hi->host;
 	struct list_head *lh, *next;
 	struct sbp2_command_info *cmd;
 	unsigned long flags;
@@ -773,11 +773,6 @@
 			SBP2_ERR("failed to register lower 4GB address range");
 			goto failed_alloc;
 		}
-#else
-		if (dma_set_mask(hi->host->device.parent, DMA_32BIT_MASK)) {
-			SBP2_ERR("failed to set 4GB DMA mask");
-			goto failed_alloc;
-		}
 #endif
 	}
 
@@ -927,15 +922,16 @@
 
 	if (!lu)
 		return;
-
 	hi = lu->hi;
+	if (!hi)
+		goto no_hi;
 
 	if (lu->shost) {
 		scsi_remove_host(lu->shost);
 		scsi_host_put(lu->shost);
 	}
 	flush_scheduled_work();
-	sbp2util_remove_command_orb_pool(lu);
+	sbp2util_remove_command_orb_pool(lu, hi->host);
 
 	list_del(&lu->lu_list);
 
@@ -976,9 +972,8 @@
 
 	lu->ud->device.driver_data = NULL;
 
-	if (hi)
-		module_put(hi->host->driver->owner);
-
+	module_put(hi->host->driver->owner);
+no_hi:
 	kfree(lu);
 }
 
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index a91001c..5381c80 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -161,8 +161,7 @@
 	if (ip_route_output_key(&rt, &fl))
 		return;
 
-	arp_send(ARPOP_REQUEST, ETH_P_ARP, rt->rt_gateway, rt->idev->dev,
-		 rt->rt_src, NULL, rt->idev->dev->dev_addr, NULL);
+	neigh_event_send(rt->u.dst.neighbour, NULL);
 	ip_rt_put(rt);
 }
 
@@ -295,10 +294,9 @@
 	struct addr_req *req;
 	int ret = 0;
 
-	req = kmalloc(sizeof *req, GFP_KERNEL);
+	req = kzalloc(sizeof *req, GFP_KERNEL);
 	if (!req)
 		return -ENOMEM;
-	memset(req, 0, sizeof *req);
 
 	if (src_addr)
 		memcpy(&req->src_addr, src_addr, ip_addr_size(src_addr));
diff --git a/drivers/infiniband/core/agent.c b/drivers/infiniband/core/agent.c
index db2633e..ae7c288 100644
--- a/drivers/infiniband/core/agent.c
+++ b/drivers/infiniband/core/agent.c
@@ -78,15 +78,14 @@
 	return entry;
 }
 
-int agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
-			struct ib_wc *wc, struct ib_device *device,
-			int port_num, int qpn)
+void agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
+			 struct ib_wc *wc, struct ib_device *device,
+			 int port_num, int qpn)
 {
 	struct ib_agent_port_private *port_priv;
 	struct ib_mad_agent *agent;
 	struct ib_mad_send_buf *send_buf;
 	struct ib_ah *ah;
-	int ret;
 	struct ib_mad_send_wr_private *mad_send_wr;
 
 	if (device->node_type == RDMA_NODE_IB_SWITCH)
@@ -96,23 +95,21 @@
 
 	if (!port_priv) {
 		printk(KERN_ERR SPFX "Unable to find port agent\n");
-		return -ENODEV;
+		return;
 	}
 
 	agent = port_priv->agent[qpn];
 	ah = ib_create_ah_from_wc(agent->qp->pd, wc, grh, port_num);
 	if (IS_ERR(ah)) {
-		ret = PTR_ERR(ah);
-		printk(KERN_ERR SPFX "ib_create_ah_from_wc error:%d\n", ret);
-		return ret;
+		printk(KERN_ERR SPFX "ib_create_ah_from_wc error\n");
+		return;
 	}
 
 	send_buf = ib_create_send_mad(agent, wc->src_qp, wc->pkey_index, 0,
 				      IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA,
 				      GFP_KERNEL);
 	if (IS_ERR(send_buf)) {
-		ret = PTR_ERR(send_buf);
-		printk(KERN_ERR SPFX "ib_create_send_mad error:%d\n", ret);
+		printk(KERN_ERR SPFX "ib_create_send_mad error\n");
 		goto err1;
 	}
 
@@ -126,16 +123,15 @@
 		mad_send_wr->send_wr.wr.ud.port_num = port_num;
 	}
 
-	if ((ret = ib_post_send_mad(send_buf, NULL))) {
-		printk(KERN_ERR SPFX "ib_post_send_mad error:%d\n", ret);
+	if (ib_post_send_mad(send_buf, NULL)) {
+		printk(KERN_ERR SPFX "ib_post_send_mad error\n");
 		goto err2;
 	}
-	return 0;
+	return;
 err2:
 	ib_free_send_mad(send_buf);
 err1:
 	ib_destroy_ah(ah);
-	return ret;
 }
 
 static void agent_send_handler(struct ib_mad_agent *mad_agent,
diff --git a/drivers/infiniband/core/agent.h b/drivers/infiniband/core/agent.h
index 86d72fa..fb9ed14 100644
--- a/drivers/infiniband/core/agent.h
+++ b/drivers/infiniband/core/agent.h
@@ -46,8 +46,8 @@
 
 extern int ib_agent_port_close(struct ib_device *device, int port_num);
 
-extern int agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
-			       struct ib_wc *wc, struct ib_device *device,
-			       int port_num, int qpn);
+extern void agent_send_response(struct ib_mad *mad, struct ib_grh *grh,
+				struct ib_wc *wc, struct ib_device *device,
+				int port_num, int qpn);
 
 #endif	/* __AGENT_H_ */
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 9820c67..2e39236 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -2219,6 +2219,9 @@
 {
 	struct cm_id_private *cm_id_priv;
 	struct ib_mad_send_buf *msg;
+	enum ib_cm_state cm_state;
+	enum ib_cm_lap_state lap_state;
+	enum cm_msg_response msg_response;
 	void *data;
 	unsigned long flags;
 	int ret;
@@ -2235,48 +2238,40 @@
 	spin_lock_irqsave(&cm_id_priv->lock, flags);
 	switch(cm_id_priv->id.state) {
 	case IB_CM_REQ_RCVD:
-		ret = cm_alloc_msg(cm_id_priv, &msg);
-		if (ret)
-			goto error1;
-
-		cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
-			      CM_MSG_RESPONSE_REQ, service_timeout,
-			      private_data, private_data_len);
-		ret = ib_post_send_mad(msg, NULL);
-		if (ret)
-			goto error2;
-		cm_id->state = IB_CM_MRA_REQ_SENT;
+		cm_state = IB_CM_MRA_REQ_SENT;
+		lap_state = cm_id->lap_state;
+		msg_response = CM_MSG_RESPONSE_REQ;
 		break;
 	case IB_CM_REP_RCVD:
-		ret = cm_alloc_msg(cm_id_priv, &msg);
-		if (ret)
-			goto error1;
-
-		cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
-			      CM_MSG_RESPONSE_REP, service_timeout,
-			      private_data, private_data_len);
-		ret = ib_post_send_mad(msg, NULL);
-		if (ret)
-			goto error2;
-		cm_id->state = IB_CM_MRA_REP_SENT;
+		cm_state = IB_CM_MRA_REP_SENT;
+		lap_state = cm_id->lap_state;
+		msg_response = CM_MSG_RESPONSE_REP;
 		break;
 	case IB_CM_ESTABLISHED:
-		ret = cm_alloc_msg(cm_id_priv, &msg);
-		if (ret)
-			goto error1;
-
-		cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
-			      CM_MSG_RESPONSE_OTHER, service_timeout,
-			      private_data, private_data_len);
-		ret = ib_post_send_mad(msg, NULL);
-		if (ret)
-			goto error2;
-		cm_id->lap_state = IB_CM_MRA_LAP_SENT;
+		cm_state = cm_id->state;
+		lap_state = IB_CM_MRA_LAP_SENT;
+		msg_response = CM_MSG_RESPONSE_OTHER;
 		break;
 	default:
 		ret = -EINVAL;
 		goto error1;
 	}
+
+	if (!(service_timeout & IB_CM_MRA_FLAG_DELAY)) {
+		ret = cm_alloc_msg(cm_id_priv, &msg);
+		if (ret)
+			goto error1;
+
+		cm_format_mra((struct cm_mra_msg *) msg->mad, cm_id_priv,
+			      msg_response, service_timeout,
+			      private_data, private_data_len);
+		ret = ib_post_send_mad(msg, NULL);
+		if (ret)
+			goto error2;
+	}
+
+	cm_id->state = cm_state;
+	cm_id->lap_state = lap_state;
 	cm_id_priv->service_timeout = service_timeout;
 	cm_set_private_data(cm_id_priv, data, private_data_len);
 	spin_unlock_irqrestore(&cm_id_priv->lock, flags);
@@ -3374,7 +3369,7 @@
 }
 EXPORT_SYMBOL(ib_cm_init_qp_attr);
 
-void cm_get_ack_delay(struct cm_device *cm_dev)
+static void cm_get_ack_delay(struct cm_device *cm_dev)
 {
 	struct ib_device_attr attr;
 
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 23af7a0..93644f8 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -52,6 +52,7 @@
 
 #define CMA_CM_RESPONSE_TIMEOUT 20
 #define CMA_MAX_CM_RETRIES 15
+#define CMA_CM_MRA_SETTING (IB_CM_MRA_FLAG_DELAY | 24)
 
 static void cma_add_one(struct ib_device *device);
 static void cma_remove_one(struct ib_device *device);
@@ -138,6 +139,7 @@
 	u32			qkey;
 	u32			qp_num;
 	u8			srq;
+	u8			tos;
 };
 
 struct cma_multicast {
@@ -573,7 +575,7 @@
 		break;
 	case RDMA_TRANSPORT_IWARP:
 		if (!id_priv->cm_id.iw) {
-			qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE;
+			qp_attr->qp_access_flags = 0;
 			*qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS;
 		} else
 			ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr,
@@ -1089,6 +1091,7 @@
 		event.param.ud.private_data_len =
 				IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset;
 	} else {
+		ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0);
 		conn_id = cma_new_conn_id(&listen_id->id, ib_event);
 		cma_set_req_event_data(&event, &ib_event->param.req_rcvd,
 				       ib_event->private_data, offset);
@@ -1474,6 +1477,15 @@
 }
 EXPORT_SYMBOL(rdma_listen);
 
+void rdma_set_service_type(struct rdma_cm_id *id, int tos)
+{
+	struct rdma_id_private *id_priv;
+
+	id_priv = container_of(id, struct rdma_id_private, id);
+	id_priv->tos = (u8) tos;
+}
+EXPORT_SYMBOL(rdma_set_service_type);
+
 static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec,
 			      void *context)
 {
@@ -1498,23 +1510,37 @@
 static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
 			      struct cma_work *work)
 {
-	struct rdma_dev_addr *addr = &id_priv->id.route.addr.dev_addr;
+	struct rdma_addr *addr = &id_priv->id.route.addr;
 	struct ib_sa_path_rec path_rec;
+	ib_sa_comp_mask comp_mask;
+	struct sockaddr_in6 *sin6;
 
 	memset(&path_rec, 0, sizeof path_rec);
-	ib_addr_get_sgid(addr, &path_rec.sgid);
-	ib_addr_get_dgid(addr, &path_rec.dgid);
-	path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr));
+	ib_addr_get_sgid(&addr->dev_addr, &path_rec.sgid);
+	ib_addr_get_dgid(&addr->dev_addr, &path_rec.dgid);
+	path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(&addr->dev_addr));
 	path_rec.numb_path = 1;
 	path_rec.reversible = 1;
+	path_rec.service_id = cma_get_service_id(id_priv->id.ps, &addr->dst_addr);
+
+	comp_mask = IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
+		    IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH |
+		    IB_SA_PATH_REC_REVERSIBLE | IB_SA_PATH_REC_SERVICE_ID;
+
+	if (addr->src_addr.sa_family == AF_INET) {
+		path_rec.qos_class = cpu_to_be16((u16) id_priv->tos);
+		comp_mask |= IB_SA_PATH_REC_QOS_CLASS;
+	} else {
+		sin6 = (struct sockaddr_in6 *) &addr->src_addr;
+		path_rec.traffic_class = (u8) (be32_to_cpu(sin6->sin6_flowinfo) >> 20);
+		comp_mask |= IB_SA_PATH_REC_TRAFFIC_CLASS;
+	}
 
 	id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device,
-				id_priv->id.port_num, &path_rec,
-				IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
-				IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH |
-				IB_SA_PATH_REC_REVERSIBLE,
-				timeout_ms, GFP_KERNEL,
-				cma_query_handler, work, &id_priv->query);
+					       id_priv->id.port_num, &path_rec,
+					       comp_mask, timeout_ms,
+					       GFP_KERNEL, cma_query_handler,
+					       work, &id_priv->query);
 
 	return (id_priv->query_id < 0) ? id_priv->query_id : 0;
 }
@@ -1866,13 +1892,14 @@
 static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv)
 {
 	struct rdma_bind_list *bind_list;
-	int port, ret;
+	int port, ret, low, high;
 
 	bind_list = kzalloc(sizeof *bind_list, GFP_KERNEL);
 	if (!bind_list)
 		return -ENOMEM;
 
 retry:
+	/* FIXME: add proper port randomization per like inet_csk_get_port */
 	do {
 		ret = idr_get_new_above(ps, bind_list, next_port, &port);
 	} while ((ret == -EAGAIN) && idr_pre_get(ps, GFP_KERNEL));
@@ -1880,18 +1907,19 @@
 	if (ret)
 		goto err1;
 
-	if (port > sysctl_local_port_range[1]) {
-		if (next_port != sysctl_local_port_range[0]) {
+	inet_get_local_port_range(&low, &high);
+	if (port > high) {
+		if (next_port != low) {
 			idr_remove(ps, port);
-			next_port = sysctl_local_port_range[0];
+			next_port = low;
 			goto retry;
 		}
 		ret = -EADDRNOTAVAIL;
 		goto err2;
 	}
 
-	if (port == sysctl_local_port_range[1])
-		next_port = sysctl_local_port_range[0];
+	if (port == high)
+		next_port = low;
 	else
 		next_port = port + 1;
 
@@ -2769,12 +2797,12 @@
 
 static int cma_init(void)
 {
-	int ret;
+	int ret, low, high;
 
 	get_random_bytes(&next_port, sizeof next_port);
-	next_port = ((unsigned int) next_port %
-		    (sysctl_local_port_range[1] - sysctl_local_port_range[0])) +
-		    sysctl_local_port_range[0];
+	inet_get_local_port_range(&low, &high);
+	next_port = ((unsigned int) next_port % (high - low)) + low;
+
 	cma_wq = create_singlethread_workqueue("rdma_cm");
 	if (!cma_wq)
 		return -ENOMEM;
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index 3ada17c..5ac5ffe 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -120,12 +120,12 @@
 
 static int alloc_name(char *name)
 {
-	long *inuse;
+	unsigned long *inuse;
 	char buf[IB_DEVICE_NAME_MAX];
 	struct ib_device *device;
 	int i;
 
-	inuse = (long *) get_zeroed_page(GFP_KERNEL);
+	inuse = (unsigned long *) get_zeroed_page(GFP_KERNEL);
 	if (!inuse)
 		return -ENOMEM;
 
@@ -702,7 +702,7 @@
 		if (ret)
 			return ret;
 
-		if (pkey == tmp_pkey) {
+		if ((pkey & 0x7fff) == (tmp_pkey & 0x7fff)) {
 			*index = i;
 			return 0;
 		}
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
index a06bcc6..d7f6452 100644
--- a/drivers/infiniband/core/fmr_pool.c
+++ b/drivers/infiniband/core/fmr_pool.c
@@ -152,7 +152,7 @@
 
 #ifdef DEBUG
 		if (fmr->ref_count !=0) {
-			printk(KERN_WARNING PFX "Unmapping FMR 0x%08x with ref count %d",
+			printk(KERN_WARNING PFX "Unmapping FMR 0x%08x with ref count %d\n",
 			       fmr, fmr->ref_count);
 		}
 #endif
@@ -170,7 +170,7 @@
 
 	ret = ib_unmap_fmr(&fmr_list);
 	if (ret)
-		printk(KERN_WARNING PFX "ib_unmap_fmr returned %d", ret);
+		printk(KERN_WARNING PFX "ib_unmap_fmr returned %d\n", ret);
 
 	spin_lock_irq(&pool->pool_lock);
 	list_splice(&unmap_list, &pool->free_list);
@@ -235,13 +235,13 @@
 
 	attr = kmalloc(sizeof *attr, GFP_KERNEL);
 	if (!attr) {
-		printk(KERN_WARNING PFX "couldn't allocate device attr struct");
+		printk(KERN_WARNING PFX "couldn't allocate device attr struct\n");
 		return ERR_PTR(-ENOMEM);
 	}
 
 	ret = ib_query_device(device, attr);
 	if (ret) {
-		printk(KERN_WARNING PFX "couldn't query device: %d", ret);
+		printk(KERN_WARNING PFX "couldn't query device: %d\n", ret);
 		kfree(attr);
 		return ERR_PTR(ret);
 	}
@@ -255,7 +255,7 @@
 
 	pool = kmalloc(sizeof *pool, GFP_KERNEL);
 	if (!pool) {
-		printk(KERN_WARNING PFX "couldn't allocate pool struct");
+		printk(KERN_WARNING PFX "couldn't allocate pool struct\n");
 		return ERR_PTR(-ENOMEM);
 	}
 
@@ -272,7 +272,7 @@
 			kmalloc(IB_FMR_HASH_SIZE * sizeof *pool->cache_bucket,
 				GFP_KERNEL);
 		if (!pool->cache_bucket) {
-			printk(KERN_WARNING PFX "Failed to allocate cache in pool");
+			printk(KERN_WARNING PFX "Failed to allocate cache in pool\n");
 			ret = -ENOMEM;
 			goto out_free_pool;
 		}
@@ -296,7 +296,7 @@
 				      "ib_fmr(%s)",
 				      device->name);
 	if (IS_ERR(pool->thread)) {
-		printk(KERN_WARNING PFX "couldn't start cleanup thread");
+		printk(KERN_WARNING PFX "couldn't start cleanup thread\n");
 		ret = PTR_ERR(pool->thread);
 		goto out_free_pool;
 	}
@@ -314,7 +314,7 @@
 				      GFP_KERNEL);
 			if (!fmr) {
 				printk(KERN_WARNING PFX "failed to allocate fmr "
-				       "struct for FMR %d", i);
+				       "struct for FMR %d\n", i);
 				goto out_fail;
 			}
 
@@ -326,7 +326,7 @@
 			fmr->fmr = ib_alloc_fmr(pd, params->access, &fmr_attr);
 			if (IS_ERR(fmr->fmr)) {
 				printk(KERN_WARNING PFX "fmr_create failed "
-				       "for FMR %d", i);
+				       "for FMR %d\n", i);
 				kfree(fmr);
 				goto out_fail;
 			}
@@ -381,7 +381,7 @@
 	}
 
 	if (i < pool->pool_size)
-		printk(KERN_WARNING PFX "pool still has %d regions registered",
+		printk(KERN_WARNING PFX "pool still has %d regions registered\n",
 		       pool->pool_size - i);
 
 	kfree(pool->cache_bucket);
@@ -518,7 +518,7 @@
 
 #ifdef DEBUG
 	if (fmr->ref_count < 0)
-		printk(KERN_WARNING PFX "FMR %p has ref count %d < 0",
+		printk(KERN_WARNING PFX "FMR %p has ref count %d < 0\n",
 		       fmr, fmr->ref_count);
 #endif
 
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 6b8faca..6f42877 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -1842,16 +1842,11 @@
 {
 	struct ib_mad_qp_info *qp_info;
 	struct ib_mad_private_header *mad_priv_hdr;
-	struct ib_mad_private *recv, *response;
+	struct ib_mad_private *recv, *response = NULL;
 	struct ib_mad_list_head *mad_list;
 	struct ib_mad_agent_private *mad_agent;
 	int port_num;
 
-	response = kmem_cache_alloc(ib_mad_cache, GFP_KERNEL);
-	if (!response)
-		printk(KERN_ERR PFX "ib_mad_recv_done_handler no memory "
-		       "for response buffer\n");
-
 	mad_list = (struct ib_mad_list_head *)(unsigned long)wc->wr_id;
 	qp_info = mad_list->mad_queue->qp_info;
 	dequeue_mad(mad_list);
@@ -1879,6 +1874,13 @@
 	if (!validate_mad(&recv->mad.mad, qp_info->qp->qp_num))
 		goto out;
 
+	response = kmem_cache_alloc(ib_mad_cache, GFP_KERNEL);
+	if (!response) {
+		printk(KERN_ERR PFX "ib_mad_recv_done_handler no memory "
+		       "for response buffer\n");
+		goto out;
+	}
+
 	if (port_priv->device->node_type == RDMA_NODE_IB_SWITCH)
 		port_num = wc->port_num;
 	else
@@ -1914,12 +1916,11 @@
 			response->header.recv_wc.recv_buf.mad = &response->mad.mad;
 			response->header.recv_wc.recv_buf.grh = &response->grh;
 
-			if (!agent_send_response(&response->mad.mad,
-						 &response->grh, wc,
-						 port_priv->device,
-						 smi_get_fwd_port(&recv->mad.smp),
-						 qp_info->qp->qp_num))
-				response = NULL;
+			agent_send_response(&response->mad.mad,
+					    &response->grh, wc,
+					    port_priv->device,
+					    smi_get_fwd_port(&recv->mad.smp),
+					    qp_info->qp->qp_num);
 
 			goto out;
 		}
@@ -2998,7 +2999,6 @@
 					 sizeof(struct ib_mad_private),
 					 0,
 					 SLAB_HWCACHE_ALIGN,
-					 NULL,
 					 NULL);
 	if (!ib_mad_cache) {
 		printk(KERN_ERR PFX "Couldn't create ib_mad cache\n");
diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c
index 3663fd7..d43bc62 100644
--- a/drivers/infiniband/core/mad_rmpp.c
+++ b/drivers/infiniband/core/mad_rmpp.c
@@ -163,8 +163,10 @@
 				 hdr_len, 0, GFP_KERNEL);
 	if (IS_ERR(msg))
 		ib_destroy_ah(ah);
-	else
+	else {
 		msg->ah = ah;
+		msg->context[0] = ah;
+	}
 
 	return msg;
 }
@@ -197,9 +199,7 @@
 
 void ib_rmpp_send_handler(struct ib_mad_send_wc *mad_send_wc)
 {
-	struct ib_rmpp_mad *rmpp_mad = mad_send_wc->send_buf->mad;
-
-	if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_ACK)
+	if (mad_send_wc->send_buf->context[0] == mad_send_wc->send_buf->ah)
 		ib_destroy_ah(mad_send_wc->send_buf->ah);
 	ib_free_send_mad(mad_send_wc->send_buf);
 }
diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c
index 15b4c4d..1bc1fe6 100644
--- a/drivers/infiniband/core/multicast.c
+++ b/drivers/infiniband/core/multicast.c
@@ -196,7 +196,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&group->lock, flags);
-	list_add(&member->list, &group->pending_list);
+	list_add_tail(&member->list, &group->pending_list);
 	if (group->state == MCAST_IDLE) {
 		group->state = MCAST_BUSY;
 		atomic_inc(&group->refcount);
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 20ab6b3..cf474ec 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -123,14 +123,10 @@
 	.field_name          = "sa_path_rec:" #field
 
 static const struct ib_field path_rec_table[] = {
-	{ RESERVED,
+	{ PATH_REC_FIELD(service_id),
 	  .offset_words = 0,
 	  .offset_bits  = 0,
-	  .size_bits    = 32 },
-	{ RESERVED,
-	  .offset_words = 1,
-	  .offset_bits  = 0,
-	  .size_bits    = 32 },
+	  .size_bits    = 64 },
 	{ PATH_REC_FIELD(dgid),
 	  .offset_words = 2,
 	  .offset_bits  = 0,
@@ -179,7 +175,7 @@
 	  .offset_words = 12,
 	  .offset_bits  = 16,
 	  .size_bits    = 16 },
-	{ RESERVED,
+	{ PATH_REC_FIELD(qos_class),
 	  .offset_words = 13,
 	  .offset_bits  = 0,
 	  .size_bits    = 12 },
@@ -385,9 +381,7 @@
 
 	new_ah->pkey_index = 0;
 	if (ib_find_pkey(port->agent->device, port->port_num,
-			 IB_DEFAULT_PKEY_FULL, &new_ah->pkey_index) &&
-	    ib_find_pkey(port->agent->device, port->port_num,
-			 IB_DEFAULT_PKEY_PARTIAL, &new_ah->pkey_index))
+			 IB_DEFAULT_PKEY_FULL, &new_ah->pkey_index))
 		printk(KERN_ERR "Couldn't find index for default PKey\n");
 
 	memset(&ah_attr, 0, sizeof ah_attr);
@@ -533,7 +527,7 @@
 					    query->sm_ah->pkey_index,
 					    0, IB_MGMT_SA_HDR, IB_MGMT_SA_DATA,
 					    gfp_mask);
-	if (!query->mad_buf) {
+	if (IS_ERR(query->mad_buf)) {
 		kref_put(&query->sm_ah->ref, free_sm_ah);
 		return -ENOMEM;
 	}
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 70b77ae..3d40506 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -434,21 +434,18 @@
 	kfree(dev);
 }
 
-static int ib_device_uevent(struct class_device *cdev, char **envp,
-			    int num_envp, char *buf, int size)
+static int ib_device_uevent(struct class_device *cdev,
+			    struct kobj_uevent_env *env)
 {
 	struct ib_device *dev = container_of(cdev, struct ib_device, class_dev);
-	int i = 0, len = 0;
 
-	if (add_uevent_var(envp, num_envp, &i, buf, size, &len,
-			   "NAME=%s", dev->name))
+	if (add_uevent_var(env, "NAME=%s", dev->name))
 		return -ENOMEM;
 
 	/*
 	 * It would be nice to pass the node GUID with the event...
 	 */
 
-	envp[i] = NULL;
 	return 0;
 }
 
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 53b4c94..90d675a 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -792,6 +792,78 @@
 	return ret;
 }
 
+static int ucma_set_option_id(struct ucma_context *ctx, int optname,
+			      void *optval, size_t optlen)
+{
+	int ret = 0;
+
+	switch (optname) {
+	case RDMA_OPTION_ID_TOS:
+		if (optlen != sizeof(u8)) {
+			ret = -EINVAL;
+			break;
+		}
+		rdma_set_service_type(ctx->cm_id, *((u8 *) optval));
+		break;
+	default:
+		ret = -ENOSYS;
+	}
+
+	return ret;
+}
+
+static int ucma_set_option_level(struct ucma_context *ctx, int level,
+				 int optname, void *optval, size_t optlen)
+{
+	int ret;
+
+	switch (level) {
+	case RDMA_OPTION_ID:
+		ret = ucma_set_option_id(ctx, optname, optval, optlen);
+		break;
+	default:
+		ret = -ENOSYS;
+	}
+
+	return ret;
+}
+
+static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf,
+			       int in_len, int out_len)
+{
+	struct rdma_ucm_set_option cmd;
+	struct ucma_context *ctx;
+	void *optval;
+	int ret;
+
+	if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
+		return -EFAULT;
+
+	ctx = ucma_get_ctx(file, cmd.id);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+
+	optval = kmalloc(cmd.optlen, GFP_KERNEL);
+	if (!optval) {
+		ret = -ENOMEM;
+		goto out1;
+	}
+
+	if (copy_from_user(optval, (void __user *) (unsigned long) cmd.optval,
+			   cmd.optlen)) {
+		ret = -EFAULT;
+		goto out2;
+	}
+
+	ret = ucma_set_option_level(ctx, cmd.level, cmd.optname, optval,
+				    cmd.optlen);
+out2:
+	kfree(optval);
+out1:
+	ucma_put_ctx(ctx);
+	return ret;
+}
+
 static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,
 			   int in_len, int out_len)
 {
@@ -936,7 +1008,7 @@
 	[RDMA_USER_CM_CMD_INIT_QP_ATTR]	= ucma_init_qp_attr,
 	[RDMA_USER_CM_CMD_GET_EVENT]	= ucma_get_event,
 	[RDMA_USER_CM_CMD_GET_OPTION]	= NULL,
-	[RDMA_USER_CM_CMD_SET_OPTION]	= NULL,
+	[RDMA_USER_CM_CMD_SET_OPTION]	= ucma_set_option,
 	[RDMA_USER_CM_CMD_NOTIFY]	= ucma_notify,
 	[RDMA_USER_CM_CMD_JOIN_MCAST]	= ucma_join_multicast,
 	[RDMA_USER_CM_CMD_LEAVE_MCAST]	= ucma_leave_multicast,
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index 26d0470..2f54e29 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -37,9 +37,15 @@
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
 #include <linux/sched.h>
+#include <linux/hugetlb.h>
 
 #include "uverbs.h"
 
+#define IB_UMEM_MAX_PAGE_CHUNK						\
+	((PAGE_SIZE - offsetof(struct ib_umem_chunk, page_list)) /	\
+	 ((void *) &((struct ib_umem_chunk *) 0)->page_list[1] -	\
+	  (void *) &((struct ib_umem_chunk *) 0)->page_list[0]))
+
 static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int dirty)
 {
 	struct ib_umem_chunk *chunk, *tmp;
@@ -70,6 +76,7 @@
 {
 	struct ib_umem *umem;
 	struct page **page_list;
+	struct vm_area_struct **vma_list;
 	struct ib_umem_chunk *chunk;
 	unsigned long locked;
 	unsigned long lock_limit;
@@ -99,6 +106,9 @@
 	 */
 	umem->writable  = !!(access & ~IB_ACCESS_REMOTE_READ);
 
+	/* We assume the memory is from hugetlb until proved otherwise */
+	umem->hugetlb   = 1;
+
 	INIT_LIST_HEAD(&umem->chunk_list);
 
 	page_list = (struct page **) __get_free_page(GFP_KERNEL);
@@ -107,6 +117,14 @@
 		return ERR_PTR(-ENOMEM);
 	}
 
+	/*
+	 * if we can't alloc the vma_list, it's not so bad;
+	 * just assume the memory is not hugetlb memory
+	 */
+	vma_list = (struct vm_area_struct **) __get_free_page(GFP_KERNEL);
+	if (!vma_list)
+		umem->hugetlb = 0;
+
 	npages = PAGE_ALIGN(size + umem->offset) >> PAGE_SHIFT;
 
 	down_write(&current->mm->mmap_sem);
@@ -126,7 +144,7 @@
 		ret = get_user_pages(current, current->mm, cur_base,
 				     min_t(int, npages,
 					   PAGE_SIZE / sizeof (struct page *)),
-				     1, !umem->writable, page_list, NULL);
+				     1, !umem->writable, page_list, vma_list);
 
 		if (ret < 0)
 			goto out;
@@ -147,6 +165,9 @@
 
 			chunk->nents = min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK);
 			for (i = 0; i < chunk->nents; ++i) {
+				if (vma_list &&
+				    !is_vm_hugetlb_page(vma_list[i + off]))
+					umem->hugetlb = 0;
 				chunk->page_list[i].page   = page_list[i + off];
 				chunk->page_list[i].offset = 0;
 				chunk->page_list[i].length = PAGE_SIZE;
@@ -181,6 +202,8 @@
 		current->mm->locked_vm = locked;
 
 	up_write(&current->mm->mmap_sem);
+	if (vma_list)
+		free_page((unsigned long) vma_list);
 	free_page((unsigned long) page_list);
 
 	return ret < 0 ? ERR_PTR(ret) : umem;
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index d97ded2..b53eac4 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -44,6 +44,7 @@
 #include <linux/poll.h>
 #include <linux/rwsem.h>
 #include <linux/kref.h>
+#include <linux/compat.h>
 
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
@@ -118,6 +119,8 @@
 	wait_queue_head_t	recv_wait;
 	struct ib_mad_agent    *agent[IB_UMAD_MAX_AGENTS];
 	int			agents_dead;
+	u8			use_pkey_index;
+	u8			already_used;
 };
 
 struct ib_umad_packet {
@@ -147,6 +150,12 @@
 	kfree(dev);
 }
 
+static int hdr_size(struct ib_umad_file *file)
+{
+	return file->use_pkey_index ? sizeof (struct ib_user_mad_hdr) :
+		sizeof (struct ib_user_mad_hdr_old);
+}
+
 /* caller must hold port->mutex at least for reading */
 static struct ib_mad_agent *__get_agent(struct ib_umad_file *file, int id)
 {
@@ -221,13 +230,13 @@
 	packet->length = mad_recv_wc->mad_len;
 	packet->recv_wc = mad_recv_wc;
 
-	packet->mad.hdr.status    = 0;
-	packet->mad.hdr.length    = sizeof (struct ib_user_mad) +
-				    mad_recv_wc->mad_len;
-	packet->mad.hdr.qpn 	  = cpu_to_be32(mad_recv_wc->wc->src_qp);
-	packet->mad.hdr.lid 	  = cpu_to_be16(mad_recv_wc->wc->slid);
-	packet->mad.hdr.sl  	  = mad_recv_wc->wc->sl;
-	packet->mad.hdr.path_bits = mad_recv_wc->wc->dlid_path_bits;
+	packet->mad.hdr.status	   = 0;
+	packet->mad.hdr.length	   = hdr_size(file) + mad_recv_wc->mad_len;
+	packet->mad.hdr.qpn	   = cpu_to_be32(mad_recv_wc->wc->src_qp);
+	packet->mad.hdr.lid	   = cpu_to_be16(mad_recv_wc->wc->slid);
+	packet->mad.hdr.sl	   = mad_recv_wc->wc->sl;
+	packet->mad.hdr.path_bits  = mad_recv_wc->wc->dlid_path_bits;
+	packet->mad.hdr.pkey_index = mad_recv_wc->wc->pkey_index;
 	packet->mad.hdr.grh_present = !!(mad_recv_wc->wc->wc_flags & IB_WC_GRH);
 	if (packet->mad.hdr.grh_present) {
 		struct ib_ah_attr ah_attr;
@@ -253,8 +262,8 @@
 	ib_free_recv_mad(mad_recv_wc);
 }
 
-static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet,
-			     size_t count)
+static ssize_t copy_recv_mad(struct ib_umad_file *file, char __user *buf,
+			     struct ib_umad_packet *packet, size_t count)
 {
 	struct ib_mad_recv_buf *recv_buf;
 	int left, seg_payload, offset, max_seg_payload;
@@ -262,15 +271,15 @@
 	/* We need enough room to copy the first (or only) MAD segment. */
 	recv_buf = &packet->recv_wc->recv_buf;
 	if ((packet->length <= sizeof (*recv_buf->mad) &&
-	     count < sizeof (packet->mad) + packet->length) ||
+	     count < hdr_size(file) + packet->length) ||
 	    (packet->length > sizeof (*recv_buf->mad) &&
-	     count < sizeof (packet->mad) + sizeof (*recv_buf->mad)))
+	     count < hdr_size(file) + sizeof (*recv_buf->mad)))
 		return -EINVAL;
 
-	if (copy_to_user(buf, &packet->mad, sizeof (packet->mad)))
+	if (copy_to_user(buf, &packet->mad, hdr_size(file)))
 		return -EFAULT;
 
-	buf += sizeof (packet->mad);
+	buf += hdr_size(file);
 	seg_payload = min_t(int, packet->length, sizeof (*recv_buf->mad));
 	if (copy_to_user(buf, recv_buf->mad, seg_payload))
 		return -EFAULT;
@@ -280,7 +289,7 @@
 		 * Multipacket RMPP MAD message. Copy remainder of message.
 		 * Note that last segment may have a shorter payload.
 		 */
-		if (count < sizeof (packet->mad) + packet->length) {
+		if (count < hdr_size(file) + packet->length) {
 			/*
 			 * The buffer is too small, return the first RMPP segment,
 			 * which includes the RMPP message length.
@@ -300,18 +309,23 @@
 				return -EFAULT;
 		}
 	}
-	return sizeof (packet->mad) + packet->length;
+	return hdr_size(file) + packet->length;
 }
 
-static ssize_t copy_send_mad(char __user *buf, struct ib_umad_packet *packet,
-			     size_t count)
+static ssize_t copy_send_mad(struct ib_umad_file *file, char __user *buf,
+			     struct ib_umad_packet *packet, size_t count)
 {
-	ssize_t size = sizeof (packet->mad) + packet->length;
+	ssize_t size = hdr_size(file) + packet->length;
 
 	if (count < size)
 		return -EINVAL;
 
-	if (copy_to_user(buf, &packet->mad, size))
+	if (copy_to_user(buf, &packet->mad, hdr_size(file)))
+		return -EFAULT;
+
+	buf += hdr_size(file);
+
+	if (copy_to_user(buf, packet->mad.data, packet->length))
 		return -EFAULT;
 
 	return size;
@@ -324,7 +338,7 @@
 	struct ib_umad_packet *packet;
 	ssize_t ret;
 
-	if (count < sizeof (struct ib_user_mad))
+	if (count < hdr_size(file))
 		return -EINVAL;
 
 	spin_lock_irq(&file->recv_lock);
@@ -348,9 +362,9 @@
 	spin_unlock_irq(&file->recv_lock);
 
 	if (packet->recv_wc)
-		ret = copy_recv_mad(buf, packet, count);
+		ret = copy_recv_mad(file, buf, packet, count);
 	else
-		ret = copy_send_mad(buf, packet, count);
+		ret = copy_send_mad(file, buf, packet, count);
 
 	if (ret < 0) {
 		/* Requeue packet */
@@ -442,15 +456,14 @@
 	__be64 *tid;
 	int ret, data_len, hdr_len, copy_offset, rmpp_active;
 
-	if (count < sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR)
+	if (count < hdr_size(file) + IB_MGMT_RMPP_HDR)
 		return -EINVAL;
 
 	packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL);
 	if (!packet)
 		return -ENOMEM;
 
-	if (copy_from_user(&packet->mad, buf,
-			    sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR)) {
+	if (copy_from_user(&packet->mad, buf, hdr_size(file))) {
 		ret = -EFAULT;
 		goto err;
 	}
@@ -461,6 +474,13 @@
 		goto err;
 	}
 
+	buf += hdr_size(file);
+
+	if (copy_from_user(packet->mad.data, buf, IB_MGMT_RMPP_HDR)) {
+		ret = -EFAULT;
+		goto err;
+	}
+
 	down_read(&file->port->mutex);
 
 	agent = __get_agent(file, packet->mad.hdr.id);
@@ -500,11 +520,11 @@
 			      IB_MGMT_RMPP_FLAG_ACTIVE;
 	}
 
-	data_len = count - sizeof (struct ib_user_mad) - hdr_len;
+	data_len = count - hdr_size(file) - hdr_len;
 	packet->msg = ib_create_send_mad(agent,
 					 be32_to_cpu(packet->mad.hdr.qpn),
-					 0, rmpp_active, hdr_len,
-					 data_len, GFP_KERNEL);
+					 packet->mad.hdr.pkey_index, rmpp_active,
+					 hdr_len, data_len, GFP_KERNEL);
 	if (IS_ERR(packet->msg)) {
 		ret = PTR_ERR(packet->msg);
 		goto err_ah;
@@ -517,7 +537,6 @@
 
 	/* Copy MAD header.  Any RMPP header is already in place. */
 	memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR);
-	buf += sizeof (struct ib_user_mad);
 
 	if (!rmpp_active) {
 		if (copy_from_user(packet->msg->mad + copy_offset,
@@ -589,7 +608,8 @@
 	return mask;
 }
 
-static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg)
+static int ib_umad_reg_agent(struct ib_umad_file *file, void __user *arg,
+			     int compat_method_mask)
 {
 	struct ib_user_mad_reg_req ureq;
 	struct ib_mad_reg_req req;
@@ -604,7 +624,7 @@
 		goto out;
 	}
 
-	if (copy_from_user(&ureq, (void __user *) arg, sizeof ureq)) {
+	if (copy_from_user(&ureq, arg, sizeof ureq)) {
 		ret = -EFAULT;
 		goto out;
 	}
@@ -625,8 +645,18 @@
 	if (ureq.mgmt_class) {
 		req.mgmt_class         = ureq.mgmt_class;
 		req.mgmt_class_version = ureq.mgmt_class_version;
-		memcpy(req.method_mask, ureq.method_mask, sizeof req.method_mask);
-		memcpy(req.oui,         ureq.oui,         sizeof req.oui);
+		memcpy(req.oui, ureq.oui, sizeof req.oui);
+
+		if (compat_method_mask) {
+			u32 *umm = (u32 *) ureq.method_mask;
+			int i;
+
+			for (i = 0; i < BITS_TO_LONGS(IB_MGMT_MAX_METHODS); ++i)
+				req.method_mask[i] =
+					umm[i * 2] | ((u64) umm[i * 2 + 1] << 32);
+		} else
+			memcpy(req.method_mask, ureq.method_mask,
+			       sizeof req.method_mask);
 	}
 
 	agent = ib_register_mad_agent(file->port->ib_dev, file->port->port_num,
@@ -646,6 +676,16 @@
 		goto out;
 	}
 
+	if (!file->already_used) {
+		file->already_used = 1;
+		if (!file->use_pkey_index) {
+			printk(KERN_WARNING "user_mad: process %s did not enable "
+			       "P_Key index support.\n", current->comm);
+			printk(KERN_WARNING "user_mad:   Documentation/infiniband/user_mad.txt "
+			       "has info on the new ABI.\n");
+		}
+	}
+
 	file->agent[agent_id] = agent;
 	ret = 0;
 
@@ -654,13 +694,13 @@
 	return ret;
 }
 
-static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg)
+static int ib_umad_unreg_agent(struct ib_umad_file *file, u32 __user *arg)
 {
 	struct ib_mad_agent *agent = NULL;
 	u32 id;
 	int ret = 0;
 
-	if (get_user(id, (u32 __user *) arg))
+	if (get_user(id, arg))
 		return -EFAULT;
 
 	down_write(&file->port->mutex);
@@ -682,19 +722,52 @@
 	return ret;
 }
 
+static long ib_umad_enable_pkey(struct ib_umad_file *file)
+{
+	int ret = 0;
+
+	down_write(&file->port->mutex);
+	if (file->already_used)
+		ret = -EINVAL;
+	else
+		file->use_pkey_index = 1;
+	up_write(&file->port->mutex);
+
+	return ret;
+}
+
 static long ib_umad_ioctl(struct file *filp, unsigned int cmd,
 			  unsigned long arg)
 {
 	switch (cmd) {
 	case IB_USER_MAD_REGISTER_AGENT:
-		return ib_umad_reg_agent(filp->private_data, arg);
+		return ib_umad_reg_agent(filp->private_data, (void __user *) arg, 0);
 	case IB_USER_MAD_UNREGISTER_AGENT:
-		return ib_umad_unreg_agent(filp->private_data, arg);
+		return ib_umad_unreg_agent(filp->private_data, (__u32 __user *) arg);
+	case IB_USER_MAD_ENABLE_PKEY:
+		return ib_umad_enable_pkey(filp->private_data);
 	default:
 		return -ENOIOCTLCMD;
 	}
 }
 
+#ifdef CONFIG_COMPAT
+static long ib_umad_compat_ioctl(struct file *filp, unsigned int cmd,
+				 unsigned long arg)
+{
+	switch (cmd) {
+	case IB_USER_MAD_REGISTER_AGENT:
+		return ib_umad_reg_agent(filp->private_data, compat_ptr(arg), 1);
+	case IB_USER_MAD_UNREGISTER_AGENT:
+		return ib_umad_unreg_agent(filp->private_data, compat_ptr(arg));
+	case IB_USER_MAD_ENABLE_PKEY:
+		return ib_umad_enable_pkey(filp->private_data);
+	default:
+		return -ENOIOCTLCMD;
+	}
+}
+#endif
+
 static int ib_umad_open(struct inode *inode, struct file *filp)
 {
 	struct ib_umad_port *port;
@@ -782,7 +855,9 @@
 	.write 	 	= ib_umad_write,
 	.poll 	 	= ib_umad_poll,
 	.unlocked_ioctl = ib_umad_ioctl,
-	.compat_ioctl 	= ib_umad_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl 	= ib_umad_compat_ioctl,
+#endif
 	.open 	 	= ib_umad_open,
 	.release 	= ib_umad_close
 };
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index c33546f..c75eb6c 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -148,7 +148,6 @@
 
 struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
 					int is_async, int *fd);
-void ib_uverbs_release_event_file(struct kref *ref);
 struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd);
 
 void ib_uverbs_release_ucq(struct ib_uverbs_file *file,
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index 14d7ccd..7c2ac39 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -125,6 +125,14 @@
 	complete(&dev->comp);
 }
 
+static void ib_uverbs_release_event_file(struct kref *ref)
+{
+	struct ib_uverbs_event_file *file =
+		container_of(ref, struct ib_uverbs_event_file, ref);
+
+	kfree(file);
+}
+
 void ib_uverbs_release_ucq(struct ib_uverbs_file *file,
 			  struct ib_uverbs_event_file *ev_file,
 			  struct ib_ucq_object *uobj)
@@ -331,14 +339,6 @@
 	return pollflags;
 }
 
-void ib_uverbs_release_event_file(struct kref *ref)
-{
-	struct ib_uverbs_event_file *file =
-		container_of(ref, struct ib_uverbs_event_file, ref);
-
-	kfree(file);
-}
-
 static int ib_uverbs_event_fasync(int fd, struct file *filp, int on)
 {
 	struct ib_uverbs_event_file *file = filp->private_data;
diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c
index 0aecea6..f283a9f 100644
--- a/drivers/infiniband/hw/amso1100/c2.c
+++ b/drivers/infiniband/hw/amso1100/c2.c
@@ -886,7 +886,6 @@
 		return NULL;
 	}
 
-	SET_MODULE_OWNER(netdev);
 	SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev);
 
 	netdev->open = c2_up;
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c
index 997cf15..7a6cece 100644
--- a/drivers/infiniband/hw/amso1100/c2_provider.c
+++ b/drivers/infiniband/hw/amso1100/c2_provider.c
@@ -715,7 +715,6 @@
 
 static void setup(struct net_device *netdev)
 {
-	SET_MODULE_OWNER(netdev);
 	netdev->open = c2_pseudo_up;
 	netdev->stop = c2_pseudo_down;
 	netdev->hard_start_xmit = c2_pseudo_xmit_frame;
diff --git a/drivers/infiniband/hw/amso1100/c2_qp.c b/drivers/infiniband/hw/amso1100/c2_qp.c
index 420c138..01d0786 100644
--- a/drivers/infiniband/hw/amso1100/c2_qp.c
+++ b/drivers/infiniband/hw/amso1100/c2_qp.c
@@ -506,6 +506,7 @@
 	qp->send_sgl_depth = qp_attrs->cap.max_send_sge;
 	qp->rdma_write_sgl_depth = qp_attrs->cap.max_send_sge;
 	qp->recv_sgl_depth = qp_attrs->cap.max_recv_sge;
+	init_waitqueue_head(&qp->wait);
 
 	/* Initialize the SQ MQ */
 	q_size = be32_to_cpu(reply->sq_depth);
diff --git a/drivers/infiniband/hw/amso1100/c2_vq.c b/drivers/infiniband/hw/amso1100/c2_vq.c
index 36620a2..cfdacb1 100644
--- a/drivers/infiniband/hw/amso1100/c2_vq.c
+++ b/drivers/infiniband/hw/amso1100/c2_vq.c
@@ -85,7 +85,7 @@
 		(char) ('0' + c2dev->devnum));
 	c2dev->host_msg_cache =
 	    kmem_cache_create(c2dev->vq_cache_name, c2dev->rep_vq.msg_size, 0,
-			      SLAB_HWCACHE_ALIGN, NULL, NULL);
+			      SLAB_HWCACHE_ALIGN, NULL);
 	if (c2dev->host_msg_cache == NULL) {
 		return -ENOMEM;
 	}
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index 1518b41..eec6a30 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -37,6 +37,7 @@
 #include <linux/spinlock.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
+#include <net/net_namespace.h>
 
 #include "cxio_resource.h"
 #include "cxio_hal.h"
@@ -894,7 +895,7 @@
 		if (cxio_hal_find_rdev_by_name(rdev_p->dev_name)) {
 			return -EBUSY;
 		}
-		netdev_p = dev_get_by_name(rdev_p->dev_name);
+		netdev_p = dev_get_by_name(&init_net, rdev_p->dev_name);
 		if (!netdev_p) {
 			return -EINVAL;
 		}
@@ -916,7 +917,7 @@
 	PDBG("%s opening rnic dev %s\n", __FUNCTION__, rdev_p->dev_name);
 	memset(&rdev_p->ctrl_qp, 0, sizeof(rdev_p->ctrl_qp));
 	if (!rdev_p->t3cdev_p)
-		rdev_p->t3cdev_p = T3CDEV(netdev_p);
+		rdev_p->t3cdev_p = dev2t3cdev(netdev_p);
 	rdev_p->t3cdev_p->ulp = (void *) rdev_p;
 	err = rdev_p->t3cdev_p->ctl(rdev_p->t3cdev_p, RDMA_GET_PARAMS,
 					 &(rdev_p->rnic_info));
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 3b41dc0..20ba372 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -63,37 +63,37 @@
 };
 
 static int ep_timeout_secs = 10;
-module_param(ep_timeout_secs, int, 0444);
+module_param(ep_timeout_secs, int, 0644);
 MODULE_PARM_DESC(ep_timeout_secs, "CM Endpoint operation timeout "
 				   "in seconds (default=10)");
 
 static int mpa_rev = 1;
-module_param(mpa_rev, int, 0444);
+module_param(mpa_rev, int, 0644);
 MODULE_PARM_DESC(mpa_rev, "MPA Revision, 0 supports amso1100, "
 		 "1 is spec compliant. (default=1)");
 
 static int markers_enabled = 0;
-module_param(markers_enabled, int, 0444);
+module_param(markers_enabled, int, 0644);
 MODULE_PARM_DESC(markers_enabled, "Enable MPA MARKERS (default(0)=disabled)");
 
 static int crc_enabled = 1;
-module_param(crc_enabled, int, 0444);
+module_param(crc_enabled, int, 0644);
 MODULE_PARM_DESC(crc_enabled, "Enable MPA CRC (default(1)=enabled)");
 
 static int rcv_win = 256 * 1024;
-module_param(rcv_win, int, 0444);
+module_param(rcv_win, int, 0644);
 MODULE_PARM_DESC(rcv_win, "TCP receive window in bytes (default=256)");
 
 static int snd_win = 32 * 1024;
-module_param(snd_win, int, 0444);
+module_param(snd_win, int, 0644);
 MODULE_PARM_DESC(snd_win, "TCP send window in bytes (default=32KB)");
 
 static unsigned int nocong = 0;
-module_param(nocong, uint, 0444);
+module_param(nocong, uint, 0644);
 MODULE_PARM_DESC(nocong, "Turn off congestion control (default=0)");
 
 static unsigned int cong_flavor = 1;
-module_param(cong_flavor, uint, 0444);
+module_param(cong_flavor, uint, 0644);
 MODULE_PARM_DESC(cong_flavor, "TCP Congestion control flavor (default=1)");
 
 static void process_work(struct work_struct *work);
@@ -139,7 +139,7 @@
 	req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
 	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, hwtid));
 	skb->priority = CPL_PRIORITY_SETUP;
-	tdev->send(tdev, skb);
+	cxgb3_ofld_send(tdev, skb);
 	return;
 }
 
@@ -161,7 +161,7 @@
 	req->val = cpu_to_be64(1 << S_TCB_RX_QUIESCE);
 
 	skb->priority = CPL_PRIORITY_DATA;
-	ep->com.tdev->send(ep->com.tdev, skb);
+	cxgb3_ofld_send(ep->com.tdev, skb);
 	return 0;
 }
 
@@ -183,7 +183,7 @@
 	req->val = 0;
 
 	skb->priority = CPL_PRIORITY_DATA;
-	ep->com.tdev->send(ep->com.tdev, skb);
+	cxgb3_ofld_send(ep->com.tdev, skb);
 	return 0;
 }
 
@@ -229,9 +229,8 @@
 {
 	struct iwch_ep_common *epc;
 
-	epc = kmalloc(size, gfp);
+	epc = kzalloc(size, gfp);
 	if (epc) {
-		memset(epc, 0, size);
 		kref_init(&epc->kref);
 		spin_lock_init(&epc->lock);
 		init_waitqueue_head(&epc->waitq);
@@ -785,7 +784,7 @@
 	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RX_DATA_ACK, ep->hwtid));
 	req->credit_dack = htonl(V_RX_CREDITS(credits) | V_RX_FORCE_ACK(1));
 	skb->priority = CPL_PRIORITY_ACK;
-	ep->com.tdev->send(ep->com.tdev, skb);
+	cxgb3_ofld_send(ep->com.tdev, skb);
 	return credits;
 }
 
@@ -1153,7 +1152,7 @@
 	req->opt1 = htonl(V_CONN_POLICY(CPL_CONN_POLICY_ASK));
 
 	skb->priority = 1;
-	ep->com.tdev->send(ep->com.tdev, skb);
+	cxgb3_ofld_send(ep->com.tdev, skb);
 	return 0;
 }
 
@@ -1187,7 +1186,7 @@
 	req->cpu_idx = 0;
 	OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, ep->stid));
 	skb->priority = 1;
-	ep->com.tdev->send(ep->com.tdev, skb);
+	cxgb3_ofld_send(ep->com.tdev, skb);
 	return 0;
 }
 
@@ -1265,7 +1264,7 @@
 		rpl->opt0l_status = htonl(CPL_PASS_OPEN_REJECT);
 		rpl->opt2 = 0;
 		rpl->rsvd = rpl->opt2;
-		tdev->send(tdev, skb);
+		cxgb3_ofld_send(tdev, skb);
 	}
 }
 
@@ -1558,7 +1557,7 @@
 	rpl->wr.wr_lo = htonl(V_WR_TID(ep->hwtid));
 	OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, ep->hwtid));
 	rpl->cmd = CPL_ABORT_NO_RST;
-	ep->com.tdev->send(ep->com.tdev, rpl_skb);
+	cxgb3_ofld_send(ep->com.tdev, rpl_skb);
 	if (state != ABORTING) {
 		state_set(&ep->com, DEAD);
 		release_ep_resources(ep);
@@ -1914,6 +1913,7 @@
 fail3:
 	cxgb3_free_stid(ep->com.tdev, ep->stid);
 fail2:
+	cm_id->rem_ref(cm_id);
 	put_ep(&ep->com);
 fail1:
 out:
diff --git a/drivers/infiniband/hw/ehca/ehca_av.c b/drivers/infiniband/hw/ehca/ehca_av.c
index 3cd6bf3..97d1086 100644
--- a/drivers/infiniband/hw/ehca/ehca_av.c
+++ b/drivers/infiniband/hw/ehca/ehca_av.c
@@ -79,7 +79,7 @@
 			av->av.ipd = (ah_mult > 0) ?
 				((ehca_mult - 1) / ah_mult) : 0;
 	} else
-	        av->av.ipd = ehca_static_rate;
+		av->av.ipd = ehca_static_rate;
 
 	av->av.lnh = ah_attr->ah_flags;
 	av->av.grh.word_0 = EHCA_BMASK_SET(GRH_IPVERSION_MASK, 6);
@@ -259,7 +259,7 @@
 	av_cache = kmem_cache_create("ehca_cache_av",
 				   sizeof(struct ehca_av), 0,
 				   SLAB_HWCACHE_ALIGN,
-				   NULL, NULL);
+				   NULL);
 	if (!av_cache)
 		return -ENOMEM;
 	return 0;
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index daf823e..0f7a55d 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -43,7 +43,6 @@
 #ifndef __EHCA_CLASSES_H__
 #define __EHCA_CLASSES_H__
 
-
 struct ehca_module;
 struct ehca_qp;
 struct ehca_cq;
@@ -54,6 +53,7 @@
 struct ehca_av;
 
 #include <linux/wait.h>
+#include <linux/mutex.h>
 
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_user_verbs.h>
@@ -100,6 +100,11 @@
 	struct ehca_sma_attr saved_attr;
 };
 
+#define HCA_CAP_MR_PGSIZE_4K  0x80000000
+#define HCA_CAP_MR_PGSIZE_64K 0x40000000
+#define HCA_CAP_MR_PGSIZE_1M  0x20000000
+#define HCA_CAP_MR_PGSIZE_16M 0x10000000
+
 struct ehca_shca {
 	struct ib_device ib_device;
 	struct ibmebus_dev *ibmebus_dev;
@@ -115,6 +120,8 @@
 	struct h_galpas galpas;
 	struct mutex modify_mutex;
 	u64 hca_cap;
+	/* MR pgsize: bit 0-3 means 4K, 64K, 1M, 16M respectively */
+	u32 hca_cap_mr_pgsize;
 	int max_mtu;
 };
 
@@ -122,6 +129,10 @@
 	struct ib_pd ib_pd;
 	struct ipz_pd fw_pd;
 	u32 ownpid;
+	/* small queue mgmt */
+	struct mutex lock;
+	struct list_head free[2];
+	struct list_head full[2];
 };
 
 enum ehca_ext_qp_type {
@@ -204,11 +215,12 @@
 	spinlock_t mrlock;
 
 	enum ehca_mr_flag flags;
-	u32 num_pages;		/* number of MR pages */
-	u32 num_4k;		/* number of 4k "page" portions to form MR */
+	u32 num_kpages;		/* number of kernel pages */
+	u32 num_hwpages;	/* number of hw pages to form MR */
+	u64 hwpage_size;	/* hw page size used for this MR */
 	int acl;		/* ACL (stored here for usage in reregister) */
 	u64 *start;		/* virtual start address (stored here for */
-	                        /* usage in reregister) */
+				/* usage in reregister) */
 	u64 size;		/* size (stored here for usage in reregister) */
 	u32 fmr_page_size;	/* page size for FMR */
 	u32 fmr_max_pages;	/* max pages for FMR */
@@ -217,9 +229,6 @@
 	/* fw specific data */
 	struct ipz_mrmw_handle ipz_mr_handle;	/* MR handle for h-calls */
 	struct h_galpas galpas;
-	/* data for userspace bridge */
-	u32 nr_of_pages;
-	void *pagearray;
 };
 
 struct ehca_mw {
@@ -241,26 +250,30 @@
 
 struct ehca_mr_pginfo {
 	enum ehca_mr_pgi_type type;
-	u64 num_pages;
-	u64 page_cnt;
-	u64 num_4k;       /* number of 4k "page" portions */
-	u64 page_4k_cnt;  /* counter for 4k "page" portions */
-	u64 next_4k;      /* next 4k "page" portion in buffer/chunk/listelem */
+	u64 num_kpages;
+	u64 kpage_cnt;
+	u64 hwpage_size;     /* hw page size used for this MR */
+	u64 num_hwpages;     /* number of hw pages */
+	u64 hwpage_cnt;      /* counter for hw pages */
+	u64 next_hwpage;     /* next hw page in buffer/chunk/listelem */
 
-	/* type EHCA_MR_PGI_PHYS section */
-	int num_phys_buf;
-	struct ib_phys_buf *phys_buf_array;
-	u64 next_buf;
-
-	/* type EHCA_MR_PGI_USER section */
-	struct ib_umem *region;
-	struct ib_umem_chunk *next_chunk;
-	u64 next_nmap;
-
-	/* type EHCA_MR_PGI_FMR section */
-	u64 *page_list;
-	u64 next_listelem;
-	/* next_4k also used within EHCA_MR_PGI_FMR */
+	union {
+		struct { /* type EHCA_MR_PGI_PHYS section */
+			int num_phys_buf;
+			struct ib_phys_buf *phys_buf_array;
+			u64 next_buf;
+		} phy;
+		struct { /* type EHCA_MR_PGI_USER section */
+			struct ib_umem *region;
+			struct ib_umem_chunk *next_chunk;
+			u64 next_nmap;
+		} usr;
+		struct { /* type EHCA_MR_PGI_FMR section */
+			u64 fmr_pgsize;
+			u64 *page_list;
+			u64 next_listelem;
+		} fmr;
+	} u;
 };
 
 /* output parameters for MR/FMR hipz calls */
@@ -298,6 +311,8 @@
 void ehca_cleanup_av_cache(void);
 int ehca_init_mrmw_cache(void);
 void ehca_cleanup_mrmw_cache(void);
+int ehca_init_small_qp_cache(void);
+void ehca_cleanup_small_qp_cache(void);
 
 extern rwlock_t ehca_qp_idr_lock;
 extern rwlock_t ehca_cq_idr_lock;
@@ -308,6 +323,7 @@
 extern int ehca_port_act_time;
 extern int ehca_use_hp_mr;
 extern int ehca_scaling_code;
+extern int ehca_mr_largepage;
 
 struct ipzu_queue_resp {
 	u32 qe_size;      /* queue entry size */
@@ -315,13 +331,15 @@
 	u32 queue_length; /* queue length allocated in bytes */
 	u32 pagesize;
 	u32 toggle_state;
-	u32 dummy; /* padding for 8 byte alignment */
+	u32 offset; /* save offset within a page for small_qp */
 };
 
 struct ehca_create_cq_resp {
 	u32 cq_number;
 	u32 token;
 	struct ipzu_queue_resp ipz_queue;
+	u32 fw_handle_ofs;
+	u32 dummy;
 };
 
 struct ehca_create_qp_resp {
@@ -332,7 +350,8 @@
 	u32 qkey;
 	/* qp_num assigned by ehca: sqp0/1 may have got different numbers */
 	u32 real_qp_num;
-	u32 dummy; /* padding for 8 byte alignment */
+	u32 fw_handle_ofs;
+	u32 dummy;
 	struct ipzu_queue_resp ipz_squeue;
 	struct ipzu_queue_resp ipz_rqueue;
 };
@@ -357,15 +376,29 @@
 	LLQP_COMP_MASK = 0x60,
 };
 
+struct ehca_alloc_queue_parms {
+	/* input parameters */
+	int max_wr;
+	int max_sge;
+	int page_size;
+	int is_small;
+
+	/* output parameters */
+	u16 act_nr_wqes;
+	u8  act_nr_sges;
+	u32 queue_size; /* bytes for small queues, pages otherwise */
+};
+
 struct ehca_alloc_qp_parms {
-/* input parameters */
+	struct ehca_alloc_queue_parms squeue;
+	struct ehca_alloc_queue_parms rqueue;
+
+	/* input parameters */
 	enum ehca_service_type servicetype;
+	int qp_storage;
 	int sigtype;
 	enum ehca_ext_qp_type ext_type;
 	enum ehca_ll_comp_flags ll_comp_flags;
-
-	int max_send_wr, max_recv_wr;
-	int max_send_sge, max_recv_sge;
 	int ud_av_l_key_ctl;
 
 	u32 token;
@@ -375,22 +408,14 @@
 
 	u32 srq_qpn, srq_token, srq_limit;
 
-/* output parameters */
+	/* output parameters */
 	u32 real_qp_num;
 	struct ipz_qp_handle qp_handle;
 	struct h_galpas galpas;
-
-	u16 act_nr_send_wqes;
-	u16 act_nr_recv_wqes;
-	u8  act_nr_recv_sges;
-	u8  act_nr_send_sges;
-
-	u32 nr_rq_pages;
-	u32 nr_sq_pages;
 };
 
 int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp);
 int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int qp_num);
-struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int qp_num);
+struct ehca_qp *ehca_cq_get_qp(struct ehca_cq *cq, int qp_num);
 
 #endif
diff --git a/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
index fb3df5c..1798e64 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
@@ -154,83 +154,83 @@
 	u32 reserved_70_127[58];       /* 70 */
 };
 
-#define MQPCB_MASK_QKEY                         EHCA_BMASK_IBM(0,0)
-#define MQPCB_MASK_SEND_PSN                     EHCA_BMASK_IBM(2,2)
-#define MQPCB_MASK_RECEIVE_PSN                  EHCA_BMASK_IBM(3,3)
-#define MQPCB_MASK_PRIM_PHYS_PORT               EHCA_BMASK_IBM(4,4)
-#define MQPCB_PRIM_PHYS_PORT                    EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_ALT_PHYS_PORT                EHCA_BMASK_IBM(5,5)
-#define MQPCB_MASK_PRIM_P_KEY_IDX               EHCA_BMASK_IBM(6,6)
-#define MQPCB_PRIM_P_KEY_IDX                    EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_ALT_P_KEY_IDX                EHCA_BMASK_IBM(7,7)
-#define MQPCB_MASK_RDMA_ATOMIC_CTRL             EHCA_BMASK_IBM(8,8)
-#define MQPCB_MASK_QP_STATE                     EHCA_BMASK_IBM(9,9)
-#define MQPCB_QP_STATE                          EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES      EHCA_BMASK_IBM(11,11)
-#define MQPCB_MASK_PATH_MIGRATION_STATE         EHCA_BMASK_IBM(12,12)
-#define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP    EHCA_BMASK_IBM(13,13)
-#define MQPCB_MASK_DEST_QP_NR                   EHCA_BMASK_IBM(14,14)
-#define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD      EHCA_BMASK_IBM(15,15)
-#define MQPCB_MASK_SERVICE_LEVEL                EHCA_BMASK_IBM(16,16)
-#define MQPCB_MASK_SEND_GRH_FLAG                EHCA_BMASK_IBM(17,17)
-#define MQPCB_MASK_RETRY_COUNT                  EHCA_BMASK_IBM(18,18)
-#define MQPCB_MASK_TIMEOUT                      EHCA_BMASK_IBM(19,19)
-#define MQPCB_MASK_PATH_MTU                     EHCA_BMASK_IBM(20,20)
-#define MQPCB_PATH_MTU                          EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_MAX_STATIC_RATE              EHCA_BMASK_IBM(21,21)
-#define MQPCB_MAX_STATIC_RATE                   EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_DLID                         EHCA_BMASK_IBM(22,22)
-#define MQPCB_DLID                              EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_RNR_RETRY_COUNT              EHCA_BMASK_IBM(23,23)
-#define MQPCB_RNR_RETRY_COUNT                   EHCA_BMASK_IBM(29,31)
-#define MQPCB_MASK_SOURCE_PATH_BITS             EHCA_BMASK_IBM(24,24)
-#define MQPCB_SOURCE_PATH_BITS                  EHCA_BMASK_IBM(25,31)
-#define MQPCB_MASK_TRAFFIC_CLASS                EHCA_BMASK_IBM(25,25)
-#define MQPCB_TRAFFIC_CLASS                     EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_HOP_LIMIT                    EHCA_BMASK_IBM(26,26)
-#define MQPCB_HOP_LIMIT                         EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_SOURCE_GID_IDX               EHCA_BMASK_IBM(27,27)
-#define MQPCB_SOURCE_GID_IDX                    EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_FLOW_LABEL                   EHCA_BMASK_IBM(28,28)
-#define MQPCB_FLOW_LABEL                        EHCA_BMASK_IBM(12,31)
-#define MQPCB_MASK_DEST_GID                     EHCA_BMASK_IBM(30,30)
-#define MQPCB_MASK_SERVICE_LEVEL_AL             EHCA_BMASK_IBM(31,31)
-#define MQPCB_SERVICE_LEVEL_AL                  EHCA_BMASK_IBM(28,31)
-#define MQPCB_MASK_SEND_GRH_FLAG_AL             EHCA_BMASK_IBM(32,32)
-#define MQPCB_SEND_GRH_FLAG_AL                  EHCA_BMASK_IBM(31,31)
-#define MQPCB_MASK_RETRY_COUNT_AL               EHCA_BMASK_IBM(33,33)
-#define MQPCB_RETRY_COUNT_AL                    EHCA_BMASK_IBM(29,31)
-#define MQPCB_MASK_TIMEOUT_AL                   EHCA_BMASK_IBM(34,34)
-#define MQPCB_TIMEOUT_AL                        EHCA_BMASK_IBM(27,31)
-#define MQPCB_MASK_MAX_STATIC_RATE_AL           EHCA_BMASK_IBM(35,35)
-#define MQPCB_MAX_STATIC_RATE_AL                EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_DLID_AL                      EHCA_BMASK_IBM(36,36)
-#define MQPCB_DLID_AL                           EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_RNR_RETRY_COUNT_AL           EHCA_BMASK_IBM(37,37)
-#define MQPCB_RNR_RETRY_COUNT_AL                EHCA_BMASK_IBM(29,31)
-#define MQPCB_MASK_SOURCE_PATH_BITS_AL          EHCA_BMASK_IBM(38,38)
-#define MQPCB_SOURCE_PATH_BITS_AL               EHCA_BMASK_IBM(25,31)
-#define MQPCB_MASK_TRAFFIC_CLASS_AL             EHCA_BMASK_IBM(39,39)
-#define MQPCB_TRAFFIC_CLASS_AL                  EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_HOP_LIMIT_AL                 EHCA_BMASK_IBM(40,40)
-#define MQPCB_HOP_LIMIT_AL                      EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_SOURCE_GID_IDX_AL            EHCA_BMASK_IBM(41,41)
-#define MQPCB_SOURCE_GID_IDX_AL                 EHCA_BMASK_IBM(24,31)
-#define MQPCB_MASK_FLOW_LABEL_AL                EHCA_BMASK_IBM(42,42)
-#define MQPCB_FLOW_LABEL_AL                     EHCA_BMASK_IBM(12,31)
-#define MQPCB_MASK_DEST_GID_AL                  EHCA_BMASK_IBM(44,44)
-#define MQPCB_MASK_MAX_NR_OUTST_SEND_WR         EHCA_BMASK_IBM(45,45)
-#define MQPCB_MAX_NR_OUTST_SEND_WR              EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_MAX_NR_OUTST_RECV_WR         EHCA_BMASK_IBM(46,46)
-#define MQPCB_MAX_NR_OUTST_RECV_WR              EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK     EHCA_BMASK_IBM(47,47)
-#define MQPCB_DISABLE_ETE_CREDIT_CHECK          EHCA_BMASK_IBM(31,31)
-#define MQPCB_QP_NUMBER                         EHCA_BMASK_IBM(8,31)
-#define MQPCB_MASK_QP_ENABLE                    EHCA_BMASK_IBM(48,48)
-#define MQPCB_QP_ENABLE                         EHCA_BMASK_IBM(31,31)
-#define MQPCB_MASK_CURR_SRQ_LIMIT               EHCA_BMASK_IBM(49,49)
-#define MQPCB_CURR_SRQ_LIMIT                    EHCA_BMASK_IBM(16,31)
-#define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG       EHCA_BMASK_IBM(50,50)
-#define MQPCB_MASK_SHARED_RQ_HNDL               EHCA_BMASK_IBM(51,51)
+#define MQPCB_MASK_QKEY                         EHCA_BMASK_IBM( 0,  0)
+#define MQPCB_MASK_SEND_PSN                     EHCA_BMASK_IBM( 2,  2)
+#define MQPCB_MASK_RECEIVE_PSN                  EHCA_BMASK_IBM( 3,  3)
+#define MQPCB_MASK_PRIM_PHYS_PORT               EHCA_BMASK_IBM( 4,  4)
+#define MQPCB_PRIM_PHYS_PORT                    EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_ALT_PHYS_PORT                EHCA_BMASK_IBM( 5,  5)
+#define MQPCB_MASK_PRIM_P_KEY_IDX               EHCA_BMASK_IBM( 6,  6)
+#define MQPCB_PRIM_P_KEY_IDX                    EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_ALT_P_KEY_IDX                EHCA_BMASK_IBM( 7,  7)
+#define MQPCB_MASK_RDMA_ATOMIC_CTRL             EHCA_BMASK_IBM( 8,  8)
+#define MQPCB_MASK_QP_STATE                     EHCA_BMASK_IBM( 9,  9)
+#define MQPCB_QP_STATE                          EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES      EHCA_BMASK_IBM(11, 11)
+#define MQPCB_MASK_PATH_MIGRATION_STATE         EHCA_BMASK_IBM(12, 12)
+#define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP    EHCA_BMASK_IBM(13, 13)
+#define MQPCB_MASK_DEST_QP_NR                   EHCA_BMASK_IBM(14, 14)
+#define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD      EHCA_BMASK_IBM(15, 15)
+#define MQPCB_MASK_SERVICE_LEVEL                EHCA_BMASK_IBM(16, 16)
+#define MQPCB_MASK_SEND_GRH_FLAG                EHCA_BMASK_IBM(17, 17)
+#define MQPCB_MASK_RETRY_COUNT                  EHCA_BMASK_IBM(18, 18)
+#define MQPCB_MASK_TIMEOUT                      EHCA_BMASK_IBM(19, 19)
+#define MQPCB_MASK_PATH_MTU                     EHCA_BMASK_IBM(20, 20)
+#define MQPCB_PATH_MTU                          EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_MAX_STATIC_RATE              EHCA_BMASK_IBM(21, 21)
+#define MQPCB_MAX_STATIC_RATE                   EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_DLID                         EHCA_BMASK_IBM(22, 22)
+#define MQPCB_DLID                              EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_RNR_RETRY_COUNT              EHCA_BMASK_IBM(23, 23)
+#define MQPCB_RNR_RETRY_COUNT                   EHCA_BMASK_IBM(29, 31)
+#define MQPCB_MASK_SOURCE_PATH_BITS             EHCA_BMASK_IBM(24, 24)
+#define MQPCB_SOURCE_PATH_BITS                  EHCA_BMASK_IBM(25, 31)
+#define MQPCB_MASK_TRAFFIC_CLASS                EHCA_BMASK_IBM(25, 25)
+#define MQPCB_TRAFFIC_CLASS                     EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_HOP_LIMIT                    EHCA_BMASK_IBM(26, 26)
+#define MQPCB_HOP_LIMIT                         EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_SOURCE_GID_IDX               EHCA_BMASK_IBM(27, 27)
+#define MQPCB_SOURCE_GID_IDX                    EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_FLOW_LABEL                   EHCA_BMASK_IBM(28, 28)
+#define MQPCB_FLOW_LABEL                        EHCA_BMASK_IBM(12, 31)
+#define MQPCB_MASK_DEST_GID                     EHCA_BMASK_IBM(30, 30)
+#define MQPCB_MASK_SERVICE_LEVEL_AL             EHCA_BMASK_IBM(31, 31)
+#define MQPCB_SERVICE_LEVEL_AL                  EHCA_BMASK_IBM(28, 31)
+#define MQPCB_MASK_SEND_GRH_FLAG_AL             EHCA_BMASK_IBM(32, 32)
+#define MQPCB_SEND_GRH_FLAG_AL                  EHCA_BMASK_IBM(31, 31)
+#define MQPCB_MASK_RETRY_COUNT_AL               EHCA_BMASK_IBM(33, 33)
+#define MQPCB_RETRY_COUNT_AL                    EHCA_BMASK_IBM(29, 31)
+#define MQPCB_MASK_TIMEOUT_AL                   EHCA_BMASK_IBM(34, 34)
+#define MQPCB_TIMEOUT_AL                        EHCA_BMASK_IBM(27, 31)
+#define MQPCB_MASK_MAX_STATIC_RATE_AL           EHCA_BMASK_IBM(35, 35)
+#define MQPCB_MAX_STATIC_RATE_AL                EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_DLID_AL                      EHCA_BMASK_IBM(36, 36)
+#define MQPCB_DLID_AL                           EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_RNR_RETRY_COUNT_AL           EHCA_BMASK_IBM(37, 37)
+#define MQPCB_RNR_RETRY_COUNT_AL                EHCA_BMASK_IBM(29, 31)
+#define MQPCB_MASK_SOURCE_PATH_BITS_AL          EHCA_BMASK_IBM(38, 38)
+#define MQPCB_SOURCE_PATH_BITS_AL               EHCA_BMASK_IBM(25, 31)
+#define MQPCB_MASK_TRAFFIC_CLASS_AL             EHCA_BMASK_IBM(39, 39)
+#define MQPCB_TRAFFIC_CLASS_AL                  EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_HOP_LIMIT_AL                 EHCA_BMASK_IBM(40, 40)
+#define MQPCB_HOP_LIMIT_AL                      EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_SOURCE_GID_IDX_AL            EHCA_BMASK_IBM(41, 41)
+#define MQPCB_SOURCE_GID_IDX_AL                 EHCA_BMASK_IBM(24, 31)
+#define MQPCB_MASK_FLOW_LABEL_AL                EHCA_BMASK_IBM(42, 42)
+#define MQPCB_FLOW_LABEL_AL                     EHCA_BMASK_IBM(12, 31)
+#define MQPCB_MASK_DEST_GID_AL                  EHCA_BMASK_IBM(44, 44)
+#define MQPCB_MASK_MAX_NR_OUTST_SEND_WR         EHCA_BMASK_IBM(45, 45)
+#define MQPCB_MAX_NR_OUTST_SEND_WR              EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_MAX_NR_OUTST_RECV_WR         EHCA_BMASK_IBM(46, 46)
+#define MQPCB_MAX_NR_OUTST_RECV_WR              EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK     EHCA_BMASK_IBM(47, 47)
+#define MQPCB_DISABLE_ETE_CREDIT_CHECK          EHCA_BMASK_IBM(31, 31)
+#define MQPCB_QP_NUMBER                         EHCA_BMASK_IBM( 8, 31)
+#define MQPCB_MASK_QP_ENABLE                    EHCA_BMASK_IBM(48, 48)
+#define MQPCB_QP_ENABLE                         EHCA_BMASK_IBM(31, 31)
+#define MQPCB_MASK_CURR_SRQ_LIMIT               EHCA_BMASK_IBM(49, 49)
+#define MQPCB_CURR_SRQ_LIMIT                    EHCA_BMASK_IBM(16, 31)
+#define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG       EHCA_BMASK_IBM(50, 50)
+#define MQPCB_MASK_SHARED_RQ_HNDL               EHCA_BMASK_IBM(51, 51)
 
 #endif /* __EHCA_CLASSES_PSERIES_H__ */
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index 01d4a14..79c25f5 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -97,7 +97,7 @@
 	return ret;
 }
 
-struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num)
+struct ehca_qp *ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num)
 {
 	struct ehca_qp *ret = NULL;
 	unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1);
@@ -166,7 +166,6 @@
 		write_lock_irqsave(&ehca_cq_idr_lock, flags);
 		ret = idr_get_new(&ehca_cq_idr, my_cq, &my_cq->token);
 		write_unlock_irqrestore(&ehca_cq_idr_lock, flags);
-
 	} while (ret == -EAGAIN);
 
 	if (ret) {
@@ -176,6 +175,12 @@
 		goto create_cq_exit1;
 	}
 
+	if (my_cq->token > 0x1FFFFFF) {
+		cq = ERR_PTR(-ENOMEM);
+		ehca_err(device, "Invalid number of cq. device=%p", device);
+		goto create_cq_exit2;
+	}
+
 	/*
 	 * CQs maximum depth is 4GB-64, but we need additional 20 as buffer
 	 * for receiving errors CQEs.
@@ -185,15 +190,15 @@
 
 	if (h_ret != H_SUCCESS) {
 		ehca_err(device, "hipz_h_alloc_resource_cq() failed "
-			 "h_ret=%lx device=%p", h_ret, device);
+			 "h_ret=%li device=%p", h_ret, device);
 		cq = ERR_PTR(ehca2ib_return_code(h_ret));
 		goto create_cq_exit2;
 	}
 
-	ipz_rc = ipz_queue_ctor(&my_cq->ipz_queue, param.act_pages,
-				EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0);
+	ipz_rc = ipz_queue_ctor(NULL, &my_cq->ipz_queue, param.act_pages,
+				EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0, 0);
 	if (!ipz_rc) {
-		ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%x device=%p",
+		ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%i device=%p",
 			 ipz_rc, device);
 		cq = ERR_PTR(-EINVAL);
 		goto create_cq_exit3;
@@ -221,7 +226,7 @@
 
 		if (h_ret < H_SUCCESS) {
 			ehca_err(device, "hipz_h_register_rpage_cq() failed "
-				 "ehca_cq=%p cq_num=%x h_ret=%lx counter=%i "
+				 "ehca_cq=%p cq_num=%x h_ret=%li counter=%i "
 				 "act_pages=%i", my_cq, my_cq->cq_number,
 				 h_ret, counter, param.act_pages);
 			cq = ERR_PTR(-EINVAL);
@@ -233,7 +238,7 @@
 			if ((h_ret != H_SUCCESS) || vpage) {
 				ehca_err(device, "Registration of pages not "
 					 "complete ehca_cq=%p cq_num=%x "
-					 "h_ret=%lx", my_cq, my_cq->cq_number,
+					 "h_ret=%li", my_cq, my_cq->cq_number,
 					 h_ret);
 				cq = ERR_PTR(-EAGAIN);
 				goto create_cq_exit4;
@@ -241,7 +246,7 @@
 		} else {
 			if (h_ret != H_PAGE_REGISTERED) {
 				ehca_err(device, "Registration of page failed "
-					 "ehca_cq=%p cq_num=%x h_ret=%lx"
+					 "ehca_cq=%p cq_num=%x h_ret=%li"
 					 "counter=%i act_pages=%i",
 					 my_cq, my_cq->cq_number,
 					 h_ret, counter, param.act_pages);
@@ -276,6 +281,8 @@
 		resp.ipz_queue.queue_length = ipz_queue->queue_length;
 		resp.ipz_queue.pagesize = ipz_queue->pagesize;
 		resp.ipz_queue.toggle_state = ipz_queue->toggle_state;
+		resp.fw_handle_ofs = (u32)
+			(my_cq->galpas.user.fw_handle & (PAGE_SIZE - 1));
 		if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
 			ehca_err(device, "Copy to udata failed.");
 			goto create_cq_exit4;
@@ -285,13 +292,13 @@
 	return cq;
 
 create_cq_exit4:
-	ipz_queue_dtor(&my_cq->ipz_queue);
+	ipz_queue_dtor(NULL, &my_cq->ipz_queue);
 
 create_cq_exit3:
 	h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1);
 	if (h_ret != H_SUCCESS)
 		ehca_err(device, "hipz_h_destroy_cq() failed ehca_cq=%p "
-			 "cq_num=%x h_ret=%lx", my_cq, my_cq->cq_number, h_ret);
+			 "cq_num=%x h_ret=%li", my_cq, my_cq->cq_number, h_ret);
 
 create_cq_exit2:
 	write_lock_irqsave(&ehca_cq_idr_lock, flags);
@@ -355,11 +362,11 @@
 				 cq_num);
 	}
 	if (h_ret != H_SUCCESS) {
-		ehca_err(device, "hipz_h_destroy_cq() failed h_ret=%lx "
+		ehca_err(device, "hipz_h_destroy_cq() failed h_ret=%li "
 			 "ehca_cq=%p cq_num=%x", h_ret, my_cq, cq_num);
 		return ehca2ib_return_code(h_ret);
 	}
-	ipz_queue_dtor(&my_cq->ipz_queue);
+	ipz_queue_dtor(NULL, &my_cq->ipz_queue);
 	kmem_cache_free(cq_cache, my_cq);
 
 	return 0;
@@ -387,7 +394,7 @@
 	cq_cache = kmem_cache_create("ehca_cache_cq",
 				     sizeof(struct ehca_cq), 0,
 				     SLAB_HWCACHE_ALIGN,
-				     NULL, NULL);
+				     NULL);
 	if (!cq_cache)
 		return -ENOMEM;
 	return 0;
diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c
index 4961eb8..1d41faa 100644
--- a/drivers/infiniband/hw/ehca/ehca_eq.c
+++ b/drivers/infiniband/hw/ehca/ehca_eq.c
@@ -86,8 +86,8 @@
 		return -EINVAL;
 	}
 
-	ret = ipz_queue_ctor(&eq->ipz_queue, nr_pages,
-			     EHCA_PAGESIZE, sizeof(struct ehca_eqe), 0);
+	ret = ipz_queue_ctor(NULL, &eq->ipz_queue, nr_pages,
+			     EHCA_PAGESIZE, sizeof(struct ehca_eqe), 0, 0);
 	if (!ret) {
 		ehca_err(ib_dev, "Can't allocate EQ pages eq=%p", eq);
 		goto create_eq_exit1;
@@ -96,7 +96,8 @@
 	for (i = 0; i < nr_pages; i++) {
 		u64 rpage;
 
-		if (!(vpage = ipz_qpageit_get_inc(&eq->ipz_queue))) {
+		vpage = ipz_qpageit_get_inc(&eq->ipz_queue);
+		if (!vpage) {
 			ret = H_RESOURCE;
 			goto create_eq_exit2;
 		}
@@ -144,7 +145,7 @@
 	return 0;
 
 create_eq_exit2:
-	ipz_queue_dtor(&eq->ipz_queue);
+	ipz_queue_dtor(NULL, &eq->ipz_queue);
 
 create_eq_exit1:
 	hipz_h_destroy_eq(shca->ipz_hca_handle, eq);
@@ -180,7 +181,7 @@
 		ehca_err(&shca->ib_device, "Can't free EQ resources.");
 		return -EINVAL;
 	}
-	ipz_queue_dtor(&eq->ipz_queue);
+	ipz_queue_dtor(NULL, &eq->ipz_queue);
 
 	return 0;
 }
diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c
index bbd3c6a..4aa3ffa 100644
--- a/drivers/infiniband/hw/ehca/ehca_hca.c
+++ b/drivers/infiniband/hw/ehca/ehca_hca.c
@@ -82,33 +82,37 @@
 	props->vendor_id       = rblock->vendor_id >> 8;
 	props->vendor_part_id  = rblock->vendor_part_id >> 16;
 	props->hw_ver          = rblock->hw_ver;
-	props->max_qp          = min_t(int, rblock->max_qp, INT_MAX);
-	props->max_qp_wr       = min_t(int, rblock->max_wqes_wq, INT_MAX);
-	props->max_sge         = min_t(int, rblock->max_sge, INT_MAX);
-	props->max_sge_rd      = min_t(int, rblock->max_sge_rd, INT_MAX);
-	props->max_cq          = min_t(int, rblock->max_cq, INT_MAX);
-	props->max_cqe         = min_t(int, rblock->max_cqe, INT_MAX);
-	props->max_mr          = min_t(int, rblock->max_mr, INT_MAX);
-	props->max_mw          = min_t(int, rblock->max_mw, INT_MAX);
-	props->max_pd          = min_t(int, rblock->max_pd, INT_MAX);
-	props->max_ah          = min_t(int, rblock->max_ah, INT_MAX);
-	props->max_fmr         = min_t(int, rblock->max_mr, INT_MAX);
-	props->max_srq         = 0;
-	props->max_srq_wr      = 0;
-	props->max_srq_sge     = 0;
+	props->max_qp          = min_t(unsigned, rblock->max_qp, INT_MAX);
+	props->max_qp_wr       = min_t(unsigned, rblock->max_wqes_wq, INT_MAX);
+	props->max_sge         = min_t(unsigned, rblock->max_sge, INT_MAX);
+	props->max_sge_rd      = min_t(unsigned, rblock->max_sge_rd, INT_MAX);
+	props->max_cq          = min_t(unsigned, rblock->max_cq, INT_MAX);
+	props->max_cqe         = min_t(unsigned, rblock->max_cqe, INT_MAX);
+	props->max_mr          = min_t(unsigned, rblock->max_mr, INT_MAX);
+	props->max_mw          = min_t(unsigned, rblock->max_mw, INT_MAX);
+	props->max_pd          = min_t(unsigned, rblock->max_pd, INT_MAX);
+	props->max_ah          = min_t(unsigned, rblock->max_ah, INT_MAX);
+	props->max_fmr         = min_t(unsigned, rblock->max_mr, INT_MAX);
+
+	if (EHCA_BMASK_GET(HCA_CAP_SRQ, shca->hca_cap)) {
+		props->max_srq         = props->max_qp;
+		props->max_srq_wr      = props->max_qp_wr;
+		props->max_srq_sge     = 3;
+	}
+
 	props->max_pkeys       = 16;
 	props->local_ca_ack_delay
 		= rblock->local_ca_ack_delay;
 	props->max_raw_ipv6_qp
-		= min_t(int, rblock->max_raw_ipv6_qp, INT_MAX);
+		= min_t(unsigned, rblock->max_raw_ipv6_qp, INT_MAX);
 	props->max_raw_ethy_qp
-		= min_t(int, rblock->max_raw_ethy_qp, INT_MAX);
+		= min_t(unsigned, rblock->max_raw_ethy_qp, INT_MAX);
 	props->max_mcast_grp
-		= min_t(int, rblock->max_mcast_grp, INT_MAX);
+		= min_t(unsigned, rblock->max_mcast_grp, INT_MAX);
 	props->max_mcast_qp_attach
-		= min_t(int, rblock->max_mcast_qp_attach, INT_MAX);
+		= min_t(unsigned, rblock->max_mcast_qp_attach, INT_MAX);
 	props->max_total_mcast_qp_attach
-		= min_t(int, rblock->max_total_mcast_qp_attach, INT_MAX);
+		= min_t(unsigned, rblock->max_total_mcast_qp_attach, INT_MAX);
 
 	/* translate device capabilities */
 	props->device_cap_flags = IB_DEVICE_SYS_IMAGE_GUID |
@@ -127,6 +131,7 @@
 		    u8 port, struct ib_port_attr *props)
 {
 	int ret = 0;
+	u64 h_ret;
 	struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
 					      ib_device);
 	struct hipz_query_port *rblock;
@@ -137,7 +142,8 @@
 		return -ENOMEM;
 	}
 
-	if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+	h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+	if (h_ret != H_SUCCESS) {
 		ehca_err(&shca->ib_device, "Can't query port properties");
 		ret = -EINVAL;
 		goto query_port1;
@@ -197,6 +203,7 @@
 			u8 port, struct ehca_sma_attr *attr)
 {
 	int ret = 0;
+	u64 h_ret;
 	struct hipz_query_port *rblock;
 
 	rblock = ehca_alloc_fw_ctrlblock(GFP_ATOMIC);
@@ -205,7 +212,8 @@
 		return -ENOMEM;
 	}
 
-	if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+	h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+	if (h_ret != H_SUCCESS) {
 		ehca_err(&shca->ib_device, "Can't query port properties");
 		ret = -EINVAL;
 		goto query_sma_attr1;
@@ -230,9 +238,11 @@
 int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
 {
 	int ret = 0;
-	struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device);
+	u64 h_ret;
+	struct ehca_shca *shca;
 	struct hipz_query_port *rblock;
 
+	shca = container_of(ibdev, struct ehca_shca, ib_device);
 	if (index > 16) {
 		ehca_err(&shca->ib_device, "Invalid index: %x.", index);
 		return -EINVAL;
@@ -244,7 +254,8 @@
 		return -ENOMEM;
 	}
 
-	if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+	h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+	if (h_ret != H_SUCCESS) {
 		ehca_err(&shca->ib_device, "Can't query port properties");
 		ret = -EINVAL;
 		goto query_pkey1;
@@ -262,6 +273,7 @@
 		   int index, union ib_gid *gid)
 {
 	int ret = 0;
+	u64 h_ret;
 	struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
 					      ib_device);
 	struct hipz_query_port *rblock;
@@ -277,7 +289,8 @@
 		return -ENOMEM;
 	}
 
-	if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+	h_ret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+	if (h_ret != H_SUCCESS) {
 		ehca_err(&shca->ib_device, "Can't query port properties");
 		ret = -EINVAL;
 		goto query_gid1;
@@ -302,11 +315,12 @@
 		     struct ib_port_modify *props)
 {
 	int ret = 0;
-	struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device);
+	struct ehca_shca *shca;
 	struct hipz_query_port *rblock;
 	u32 cap;
 	u64 hret;
 
+	shca = container_of(ibdev, struct ehca_shca, ib_device);
 	if ((props->set_port_cap_mask | props->clr_port_cap_mask)
 	    & ~allowed_port_caps) {
 		ehca_err(&shca->ib_device, "Non-changeable bits set in masks  "
@@ -325,7 +339,8 @@
 		goto modify_port1;
 	}
 
-	if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+	hret = hipz_h_query_port(shca->ipz_hca_handle, port, rblock);
+	if (hret != H_SUCCESS) {
 		ehca_err(&shca->ib_device, "Can't query port properties");
 		ret = -EINVAL;
 		goto modify_port2;
@@ -337,7 +352,8 @@
 	hret = hipz_h_modify_port(shca->ipz_hca_handle, port,
 				  cap, props->init_type, port_modify_mask);
 	if (hret != H_SUCCESS) {
-		ehca_err(&shca->ib_device, "Modify port failed  hret=%lx", hret);
+		ehca_err(&shca->ib_device, "Modify port failed  h_ret=%li",
+			 hret);
 		ret = -EINVAL;
 	}
 
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index 96eba38..3f617b2 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -49,29 +49,26 @@
 #include "hipz_fns.h"
 #include "ipz_pt_fn.h"
 
-#define EQE_COMPLETION_EVENT   EHCA_BMASK_IBM(1,1)
-#define EQE_CQ_QP_NUMBER       EHCA_BMASK_IBM(8,31)
-#define EQE_EE_IDENTIFIER      EHCA_BMASK_IBM(2,7)
-#define EQE_CQ_NUMBER          EHCA_BMASK_IBM(8,31)
-#define EQE_QP_NUMBER          EHCA_BMASK_IBM(8,31)
-#define EQE_QP_TOKEN           EHCA_BMASK_IBM(32,63)
-#define EQE_CQ_TOKEN           EHCA_BMASK_IBM(32,63)
+#define EQE_COMPLETION_EVENT   EHCA_BMASK_IBM( 1,  1)
+#define EQE_CQ_QP_NUMBER       EHCA_BMASK_IBM( 8, 31)
+#define EQE_EE_IDENTIFIER      EHCA_BMASK_IBM( 2,  7)
+#define EQE_CQ_NUMBER          EHCA_BMASK_IBM( 8, 31)
+#define EQE_QP_NUMBER          EHCA_BMASK_IBM( 8, 31)
+#define EQE_QP_TOKEN           EHCA_BMASK_IBM(32, 63)
+#define EQE_CQ_TOKEN           EHCA_BMASK_IBM(32, 63)
 
-#define NEQE_COMPLETION_EVENT  EHCA_BMASK_IBM(1,1)
-#define NEQE_EVENT_CODE        EHCA_BMASK_IBM(2,7)
-#define NEQE_PORT_NUMBER       EHCA_BMASK_IBM(8,15)
-#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16,16)
-#define NEQE_DISRUPTIVE        EHCA_BMASK_IBM(16,16)
+#define NEQE_COMPLETION_EVENT  EHCA_BMASK_IBM( 1,  1)
+#define NEQE_EVENT_CODE        EHCA_BMASK_IBM( 2,  7)
+#define NEQE_PORT_NUMBER       EHCA_BMASK_IBM( 8, 15)
+#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16, 16)
+#define NEQE_DISRUPTIVE        EHCA_BMASK_IBM(16, 16)
 
-#define ERROR_DATA_LENGTH      EHCA_BMASK_IBM(52,63)
-#define ERROR_DATA_TYPE        EHCA_BMASK_IBM(0,7)
+#define ERROR_DATA_LENGTH      EHCA_BMASK_IBM(52, 63)
+#define ERROR_DATA_TYPE        EHCA_BMASK_IBM( 0,  7)
 
 static void queue_comp_task(struct ehca_cq *__cq);
 
-static struct ehca_comp_pool* pool;
-#ifdef CONFIG_HOTPLUG_CPU
-static struct notifier_block comp_pool_callback_nb;
-#endif
+static struct ehca_comp_pool *pool;
 
 static inline void comp_event_callback(struct ehca_cq *cq)
 {
@@ -85,8 +82,8 @@
 	return;
 }
 
-static void print_error_data(struct ehca_shca * shca, void* data,
-			     u64* rblock, int length)
+static void print_error_data(struct ehca_shca *shca, void *data,
+			     u64 *rblock, int length)
 {
 	u64 type = EHCA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]);
 	u64 resource = rblock[1];
@@ -94,7 +91,7 @@
 	switch (type) {
 	case 0x1: /* Queue Pair */
 	{
-		struct ehca_qp *qp = (struct ehca_qp*)data;
+		struct ehca_qp *qp = (struct ehca_qp *)data;
 
 		/* only print error data if AER is set */
 		if (rblock[6] == 0)
@@ -107,7 +104,7 @@
 	}
 	case 0x4: /* Completion Queue */
 	{
-		struct ehca_cq *cq = (struct ehca_cq*)data;
+		struct ehca_cq *cq = (struct ehca_cq *)data;
 
 		ehca_err(&shca->ib_device,
 			 "CQ 0x%x (resource=%lx) has errors.",
@@ -116,7 +113,7 @@
 	}
 	default:
 		ehca_err(&shca->ib_device,
-			 "Unknown errror type: %lx on %s.",
+			 "Unknown error type: %lx on %s.",
 			 type, shca->ib_device.name);
 		break;
 	}
@@ -175,11 +172,32 @@
 
 }
 
-static void qp_event_callback(struct ehca_shca *shca,
-			      u64 eqe,
+static void dispatch_qp_event(struct ehca_shca *shca, struct ehca_qp *qp,
 			      enum ib_event_type event_type)
 {
 	struct ib_event event;
+
+	event.device = &shca->ib_device;
+	event.event = event_type;
+
+	if (qp->ext_type == EQPT_SRQ) {
+		if (!qp->ib_srq.event_handler)
+			return;
+
+		event.element.srq = &qp->ib_srq;
+		qp->ib_srq.event_handler(&event, qp->ib_srq.srq_context);
+	} else {
+		if (!qp->ib_qp.event_handler)
+			return;
+
+		event.element.qp = &qp->ib_qp;
+		qp->ib_qp.event_handler(&event, qp->ib_qp.qp_context);
+	}
+}
+
+static void qp_event_callback(struct ehca_shca *shca, u64 eqe,
+			      enum ib_event_type event_type, int fatal)
+{
 	struct ehca_qp *qp;
 	u32 token = EHCA_BMASK_GET(EQE_QP_TOKEN, eqe);
 
@@ -187,20 +205,22 @@
 	qp = idr_find(&ehca_qp_idr, token);
 	read_unlock(&ehca_qp_idr_lock);
 
-
 	if (!qp)
 		return;
 
-	ehca_error_data(shca, qp, qp->ipz_qp_handle.handle);
+	if (fatal)
+		ehca_error_data(shca, qp, qp->ipz_qp_handle.handle);
 
-	if (!qp->ib_qp.event_handler)
-		return;
+	dispatch_qp_event(shca, qp, fatal && qp->ext_type == EQPT_SRQ ?
+			  IB_EVENT_SRQ_ERR : event_type);
 
-	event.device     = &shca->ib_device;
-	event.event      = event_type;
-	event.element.qp = &qp->ib_qp;
-
-	qp->ib_qp.event_handler(&event, qp->ib_qp.qp_context);
+	/*
+	 * eHCA only processes one WQE at a time for SRQ base QPs,
+	 * so the last WQE has been processed as soon as the QP enters
+	 * error state.
+	 */
+	if (fatal && qp->ext_type == EQPT_SRQBASE)
+		dispatch_qp_event(shca, qp, IB_EVENT_QP_LAST_WQE_REACHED);
 
 	return;
 }
@@ -234,17 +254,17 @@
 
 	switch (identifier) {
 	case 0x02: /* path migrated */
-		qp_event_callback(shca, eqe, IB_EVENT_PATH_MIG);
+		qp_event_callback(shca, eqe, IB_EVENT_PATH_MIG, 0);
 		break;
 	case 0x03: /* communication established */
-		qp_event_callback(shca, eqe, IB_EVENT_COMM_EST);
+		qp_event_callback(shca, eqe, IB_EVENT_COMM_EST, 0);
 		break;
 	case 0x04: /* send queue drained */
-		qp_event_callback(shca, eqe, IB_EVENT_SQ_DRAINED);
+		qp_event_callback(shca, eqe, IB_EVENT_SQ_DRAINED, 0);
 		break;
 	case 0x05: /* QP error */
 	case 0x06: /* QP error */
-		qp_event_callback(shca, eqe, IB_EVENT_QP_FATAL);
+		qp_event_callback(shca, eqe, IB_EVENT_QP_FATAL, 1);
 		break;
 	case 0x07: /* CQ error */
 	case 0x08: /* CQ error */
@@ -271,13 +291,18 @@
 	case 0x11: /* unaffiliated access error */
 		ehca_err(&shca->ib_device, "Unaffiliated access error.");
 		break;
-	case 0x12: /* path migrating error */
-		ehca_err(&shca->ib_device, "Path migration error.");
+	case 0x12: /* path migrating */
+		ehca_err(&shca->ib_device, "Path migrating.");
 		break;
 	case 0x13: /* interface trace stopped */
 		ehca_err(&shca->ib_device, "Interface trace stopped.");
 		break;
 	case 0x14: /* first error capture info available */
+		ehca_info(&shca->ib_device, "First error capture available");
+		break;
+	case 0x15: /* SRQ limit reached */
+		qp_event_callback(shca, eqe, IB_EVENT_SRQ_LIMIT_REACHED, 0);
+		break;
 	default:
 		ehca_err(&shca->ib_device, "Unknown identifier: %x on %s.",
 			 identifier, shca->ib_device.name);
@@ -572,7 +597,7 @@
 	ehca_process_eq((struct ehca_shca*)data, 1);
 }
 
-static inline int find_next_online_cpu(struct ehca_comp_pool* pool)
+static inline int find_next_online_cpu(struct ehca_comp_pool *pool)
 {
 	int cpu;
 	unsigned long flags;
@@ -636,7 +661,7 @@
 	__queue_comp_task(__cq, cct);
 }
 
-static void run_comp_task(struct ehca_cpu_comp_task* cct)
+static void run_comp_task(struct ehca_cpu_comp_task *cct)
 {
 	struct ehca_cq *cq;
 	unsigned long flags;
@@ -666,12 +691,12 @@
 
 static int comp_task(void *__cct)
 {
-	struct ehca_cpu_comp_task* cct = __cct;
+	struct ehca_cpu_comp_task *cct = __cct;
 	int cql_empty;
 	DECLARE_WAITQUEUE(wait, current);
 
 	set_current_state(TASK_INTERRUPTIBLE);
-	while(!kthread_should_stop()) {
+	while (!kthread_should_stop()) {
 		add_wait_queue(&cct->wait_queue, &wait);
 
 		spin_lock_irq(&cct->task_lock);
@@ -732,9 +757,7 @@
 		kthread_stop(task);
 }
 
-#ifdef CONFIG_HOTPLUG_CPU
-static void take_over_work(struct ehca_comp_pool *pool,
-			   int cpu)
+static void __cpuinit take_over_work(struct ehca_comp_pool *pool, int cpu)
 {
 	struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
 	LIST_HEAD(list);
@@ -745,7 +768,7 @@
 
 	list_splice_init(&cct->cq_list, &list);
 
-	while(!list_empty(&list)) {
+	while (!list_empty(&list)) {
 		cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
 
 		list_del(&cq->entry);
@@ -757,9 +780,9 @@
 
 }
 
-static int comp_pool_callback(struct notifier_block *nfb,
-			      unsigned long action,
-			      void *hcpu)
+static int __cpuinit comp_pool_callback(struct notifier_block *nfb,
+					unsigned long action,
+					void *hcpu)
 {
 	unsigned int cpu = (unsigned long)hcpu;
 	struct ehca_cpu_comp_task *cct;
@@ -768,7 +791,7 @@
 	case CPU_UP_PREPARE:
 	case CPU_UP_PREPARE_FROZEN:
 		ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu);
-		if(!create_comp_task(pool, cpu)) {
+		if (!create_comp_task(pool, cpu)) {
 			ehca_gen_err("Can't create comp_task for cpu: %x", cpu);
 			return NOTIFY_BAD;
 		}
@@ -805,7 +828,11 @@
 
 	return NOTIFY_OK;
 }
-#endif
+
+static struct notifier_block comp_pool_callback_nb __cpuinitdata = {
+	.notifier_call	= comp_pool_callback,
+	.priority	= 0,
+};
 
 int ehca_create_comp_pool(void)
 {
@@ -836,11 +863,7 @@
 		}
 	}
 
-#ifdef CONFIG_HOTPLUG_CPU
-	comp_pool_callback_nb.notifier_call = comp_pool_callback;
-	comp_pool_callback_nb.priority =0;
-	register_cpu_notifier(&comp_pool_callback_nb);
-#endif
+	register_hotcpu_notifier(&comp_pool_callback_nb);
 
 	printk(KERN_INFO "eHCA scaling code enabled\n");
 
@@ -854,9 +877,7 @@
 	if (!ehca_scaling_code)
 		return;
 
-#ifdef CONFIG_HOTPLUG_CPU
-	unregister_cpu_notifier(&comp_pool_callback_nb);
-#endif
+	unregister_hotcpu_notifier(&comp_pool_callback_nb);
 
 	for (i = 0; i < NR_CPUS; i++) {
 		if (cpu_online(i))
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
index 77aeca6..dce503b 100644
--- a/drivers/infiniband/hw/ehca/ehca_iverbs.h
+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
@@ -81,8 +81,9 @@
 			       int num_phys_buf,
 			       int mr_access_flags, u64 *iova_start);
 
-struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt,
-			       int mr_access_flags, struct ib_udata *udata);
+struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+			       u64 virt, int mr_access_flags,
+			       struct ib_udata *udata);
 
 int ehca_rereg_phys_mr(struct ib_mr *mr,
 		       int mr_rereg_mask,
@@ -192,7 +193,7 @@
 void *ehca_alloc_fw_ctrlblock(gfp_t flags);
 void ehca_free_fw_ctrlblock(void *ptr);
 #else
-#define ehca_alloc_fw_ctrlblock(flags) ((void *) get_zeroed_page(flags))
+#define ehca_alloc_fw_ctrlblock(flags) ((void *)get_zeroed_page(flags))
 #define ehca_free_fw_ctrlblock(ptr) free_page((unsigned long)(ptr))
 #endif
 
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 28ba2dd..403467f 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -49,10 +49,12 @@
 #include "ehca_tools.h"
 #include "hcp_if.h"
 
+#define HCAD_VERSION "0024"
+
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
 MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");
-MODULE_VERSION("SVNEHCA_0023");
+MODULE_VERSION(HCAD_VERSION);
 
 int ehca_open_aqp1     = 0;
 int ehca_debug_level   = 0;
@@ -63,16 +65,18 @@
 int ehca_poll_all_eqs  = 1;
 int ehca_static_rate   = -1;
 int ehca_scaling_code  = 0;
+int ehca_mr_largepage  = 0;
 
-module_param_named(open_aqp1,     ehca_open_aqp1,     int, 0);
-module_param_named(debug_level,   ehca_debug_level,   int, 0);
-module_param_named(hw_level,      ehca_hw_level,      int, 0);
-module_param_named(nr_ports,      ehca_nr_ports,      int, 0);
-module_param_named(use_hp_mr,     ehca_use_hp_mr,     int, 0);
-module_param_named(port_act_time, ehca_port_act_time, int, 0);
-module_param_named(poll_all_eqs,  ehca_poll_all_eqs,  int, 0);
-module_param_named(static_rate,   ehca_static_rate,   int, 0);
-module_param_named(scaling_code,   ehca_scaling_code,   int, 0);
+module_param_named(open_aqp1,     ehca_open_aqp1,     int, S_IRUGO);
+module_param_named(debug_level,   ehca_debug_level,   int, S_IRUGO);
+module_param_named(hw_level,      ehca_hw_level,      int, S_IRUGO);
+module_param_named(nr_ports,      ehca_nr_ports,      int, S_IRUGO);
+module_param_named(use_hp_mr,     ehca_use_hp_mr,     int, S_IRUGO);
+module_param_named(port_act_time, ehca_port_act_time, int, S_IRUGO);
+module_param_named(poll_all_eqs,  ehca_poll_all_eqs,  int, S_IRUGO);
+module_param_named(static_rate,   ehca_static_rate,   int, S_IRUGO);
+module_param_named(scaling_code,  ehca_scaling_code,  int, S_IRUGO);
+module_param_named(mr_largepage,  ehca_mr_largepage,  int, S_IRUGO);
 
 MODULE_PARM_DESC(open_aqp1,
 		 "AQP1 on startup (0: no (default), 1: yes)");
@@ -95,6 +99,9 @@
 		 "set permanent static rate (default: disabled)");
 MODULE_PARM_DESC(scaling_code,
 		 "set scaling code (0: disabled/default, 1: enabled)");
+MODULE_PARM_DESC(mr_largepage,
+		 "use large page for MR (0: use PAGE_SIZE (default), "
+		 "1: use large page depending on MR size");
 
 DEFINE_RWLOCK(ehca_qp_idr_lock);
 DEFINE_RWLOCK(ehca_cq_idr_lock);
@@ -107,7 +114,7 @@
 static struct timer_list poll_eqs_timer;
 
 #ifdef CONFIG_PPC_64K_PAGES
-static struct kmem_cache *ctblk_cache = NULL;
+static struct kmem_cache *ctblk_cache;
 
 void *ehca_alloc_fw_ctrlblock(gfp_t flags)
 {
@@ -125,6 +132,23 @@
 }
 #endif
 
+int ehca2ib_return_code(u64 ehca_rc)
+{
+	switch (ehca_rc) {
+	case H_SUCCESS:
+		return 0;
+	case H_RESOURCE:             /* Resource in use */
+	case H_BUSY:
+		return -EBUSY;
+	case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
+	case H_CONSTRAINED:          /* resource constraint */
+	case H_NO_MEM:
+		return -ENOMEM;
+	default:
+		return -EINVAL;
+	}
+}
+
 static int ehca_create_slab_caches(void)
 {
 	int ret;
@@ -159,19 +183,28 @@
 		goto create_slab_caches5;
 	}
 
+	ret = ehca_init_small_qp_cache();
+	if (ret) {
+		ehca_gen_err("Cannot create small queue SLAB cache.");
+		goto create_slab_caches6;
+	}
+
 #ifdef CONFIG_PPC_64K_PAGES
 	ctblk_cache = kmem_cache_create("ehca_cache_ctblk",
 					EHCA_PAGESIZE, H_CB_ALIGNMENT,
 					SLAB_HWCACHE_ALIGN,
-					NULL, NULL);
+					NULL);
 	if (!ctblk_cache) {
 		ehca_gen_err("Cannot create ctblk SLAB cache.");
-		ehca_cleanup_mrmw_cache();
-		goto create_slab_caches5;
+		ehca_cleanup_small_qp_cache();
+		goto create_slab_caches6;
 	}
 #endif
 	return 0;
 
+create_slab_caches6:
+	ehca_cleanup_mrmw_cache();
+
 create_slab_caches5:
 	ehca_cleanup_av_cache();
 
@@ -189,6 +222,7 @@
 
 static void ehca_destroy_slab_caches(void)
 {
+	ehca_cleanup_small_qp_cache();
 	ehca_cleanup_mrmw_cache();
 	ehca_cleanup_av_cache();
 	ehca_cleanup_qp_cache();
@@ -200,8 +234,8 @@
 #endif
 }
 
-#define EHCA_HCAAVER  EHCA_BMASK_IBM(32,39)
-#define EHCA_REVID    EHCA_BMASK_IBM(40,63)
+#define EHCA_HCAAVER  EHCA_BMASK_IBM(32, 39)
+#define EHCA_REVID    EHCA_BMASK_IBM(40, 63)
 
 static struct cap_descr {
 	u64 mask;
@@ -241,7 +275,7 @@
 
 	h_ret = hipz_h_query_hca(shca->ipz_hca_handle, rblock);
 	if (h_ret != H_SUCCESS) {
-		ehca_gen_err("Cannot query device properties. h_ret=%lx",
+		ehca_gen_err("Cannot query device properties. h_ret=%li",
 			     h_ret);
 		ret = -EPERM;
 		goto sense_attributes1;
@@ -263,22 +297,27 @@
 
 		ehca_gen_dbg(" ... hardware version=%x:%x", hcaaver, revid);
 
-		if ((hcaaver == 1) && (revid == 0))
-			shca->hw_level = 0x11;
-		else if ((hcaaver == 1) && (revid == 1))
-			shca->hw_level = 0x12;
-		else if ((hcaaver == 1) && (revid == 2))
-			shca->hw_level = 0x13;
-		else if ((hcaaver == 2) && (revid == 0))
-			shca->hw_level = 0x21;
-		else if ((hcaaver == 2) && (revid == 0x10))
-			shca->hw_level = 0x22;
-		else {
+		if (hcaaver == 1) {
+			if (revid <= 3)
+				shca->hw_level = 0x10 | (revid + 1);
+			else
+				shca->hw_level = 0x14;
+		} else if (hcaaver == 2) {
+			if (revid == 0)
+				shca->hw_level = 0x21;
+			else if (revid == 0x10)
+				shca->hw_level = 0x22;
+			else if (revid == 0x20 || revid == 0x21)
+				shca->hw_level = 0x23;
+		}
+
+		if (!shca->hw_level) {
 			ehca_gen_warn("unknown hardware version"
 				      " - assuming default level");
 			shca->hw_level = 0x22;
 		}
-	}
+	} else
+		shca->hw_level = ehca_hw_level;
 	ehca_gen_dbg(" ... hardware level=%x", shca->hw_level);
 
 	shca->sport[0].rate = IB_RATE_30_GBPS;
@@ -290,10 +329,12 @@
 		if (EHCA_BMASK_GET(hca_cap_descr[i].mask, shca->hca_cap))
 			ehca_gen_dbg("   %s", hca_cap_descr[i].descr);
 
-	port = (struct hipz_query_port *) rblock;
+	shca->hca_cap_mr_pgsize = rblock->memory_page_size_supported;
+
+	port = (struct hipz_query_port *)rblock;
 	h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port);
 	if (h_ret != H_SUCCESS) {
-		ehca_gen_err("Cannot query port properties. h_ret=%lx",
+		ehca_gen_err("Cannot query port properties. h_ret=%li",
 			     h_ret);
 		ret = -EPERM;
 		goto sense_attributes1;
@@ -341,7 +382,7 @@
 	strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX);
 	shca->ib_device.owner               = THIS_MODULE;
 
-	shca->ib_device.uverbs_abi_ver	    = 7;
+	shca->ib_device.uverbs_abi_ver	    = 8;
 	shca->ib_device.uverbs_cmd_mask	    =
 		(1ull << IB_USER_VERBS_CMD_GET_CONTEXT)		|
 		(1ull << IB_USER_VERBS_CMD_QUERY_DEVICE)	|
@@ -439,7 +480,7 @@
 		return -EPERM;
 	}
 
-	ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10, 0);
+	ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void *)(-1), 10, 0);
 	if (IS_ERR(ibcq)) {
 		ehca_err(&shca->ib_device, "Cannot create AQP1 CQ.");
 		return PTR_ERR(ibcq);
@@ -487,13 +528,13 @@
 
 	ret = ib_destroy_qp(sport->ibqp_aqp1);
 	if (ret) {
-		ehca_gen_err("Cannot destroy AQP1 QP. ret=%x", ret);
+		ehca_gen_err("Cannot destroy AQP1 QP. ret=%i", ret);
 		return ret;
 	}
 
 	ret = ib_destroy_cq(sport->ibcq_aqp1);
 	if (ret)
-		ehca_gen_err("Cannot destroy AQP1 CQ. ret=%x", ret);
+		ehca_gen_err("Cannot destroy AQP1 CQ. ret=%i", ret);
 
 	return ret;
 }
@@ -585,6 +626,14 @@
 }
 static DEVICE_ATTR(adapter_handle, S_IRUGO, ehca_show_adapter_handle, NULL);
 
+static ssize_t ehca_show_mr_largepage(struct device *dev,
+				      struct device_attribute *attr,
+				      char *buf)
+{
+	return sprintf(buf, "%d\n", ehca_mr_largepage);
+}
+static DEVICE_ATTR(mr_largepage, S_IRUGO, ehca_show_mr_largepage, NULL);
+
 static struct attribute *ehca_dev_attrs[] = {
 	&dev_attr_adapter_handle.attr,
 	&dev_attr_num_ports.attr,
@@ -601,6 +650,7 @@
 	&dev_attr_cur_mw.attr,
 	&dev_attr_max_pd.attr,
 	&dev_attr_max_ah.attr,
+	&dev_attr_mr_largepage.attr,
 	NULL
 };
 
@@ -666,7 +716,7 @@
 	}
 
 	/* create internal protection domain */
-	ibpd = ehca_alloc_pd(&shca->ib_device, (void*)(-1), NULL);
+	ibpd = ehca_alloc_pd(&shca->ib_device, (void *)(-1), NULL);
 	if (IS_ERR(ibpd)) {
 		ehca_err(&shca->ib_device, "Cannot create internal PD.");
 		ret = PTR_ERR(ibpd);
@@ -680,7 +730,7 @@
 	ret = ehca_reg_internal_maxmr(shca, shca->pd, &shca->maxmr);
 
 	if (ret) {
-		ehca_err(&shca->ib_device, "Cannot create internal MR ret=%x",
+		ehca_err(&shca->ib_device, "Cannot create internal MR ret=%i",
 			 ret);
 		goto probe5;
 	}
@@ -688,7 +738,7 @@
 	ret = ib_register_device(&shca->ib_device);
 	if (ret) {
 		ehca_err(&shca->ib_device,
-			 "ib_register_device() failed ret=%x", ret);
+			 "ib_register_device() failed ret=%i", ret);
 		goto probe6;
 	}
 
@@ -729,7 +779,7 @@
 	ret = ehca_destroy_aqp1(&shca->sport[0]);
 	if (ret)
 		ehca_err(&shca->ib_device,
-			 "Cannot destroy AQP1 for port 1. ret=%x", ret);
+			 "Cannot destroy AQP1 for port 1. ret=%i", ret);
 
 probe7:
 	ib_unregister_device(&shca->ib_device);
@@ -778,7 +828,7 @@
 			if (ret)
 				ehca_err(&shca->ib_device,
 					 "Cannot destroy AQP1 for port %x "
-					 "ret=%x", ret, i);
+					 "ret=%i", ret, i);
 		}
 	}
 
@@ -787,20 +837,20 @@
 	ret = ehca_dereg_internal_maxmr(shca);
 	if (ret)
 		ehca_err(&shca->ib_device,
-			 "Cannot destroy internal MR. ret=%x", ret);
+			 "Cannot destroy internal MR. ret=%i", ret);
 
 	ret = ehca_dealloc_pd(&shca->pd->ib_pd);
 	if (ret)
 		ehca_err(&shca->ib_device,
-			 "Cannot destroy internal PD. ret=%x", ret);
+			 "Cannot destroy internal PD. ret=%i", ret);
 
 	ret = ehca_destroy_eq(shca, &shca->eq);
 	if (ret)
-		ehca_err(&shca->ib_device, "Cannot destroy EQ. ret=%x", ret);
+		ehca_err(&shca->ib_device, "Cannot destroy EQ. ret=%i", ret);
 
 	ret = ehca_destroy_eq(shca, &shca->neq);
 	if (ret)
-		ehca_err(&shca->ib_device, "Canot destroy NEQ. ret=%x", ret);
+		ehca_err(&shca->ib_device, "Canot destroy NEQ. ret=%i", ret);
 
 	ib_dealloc_device(&shca->ib_device);
 
@@ -861,20 +911,23 @@
 	int ret;
 
 	printk(KERN_INFO "eHCA Infiniband Device Driver "
-	       "(Rel.: SVNEHCA_0023)\n");
+	       "(Version " HCAD_VERSION ")\n");
 
-	if ((ret = ehca_create_comp_pool())) {
+	ret = ehca_create_comp_pool();
+	if (ret) {
 		ehca_gen_err("Cannot create comp pool.");
 		return ret;
 	}
 
-	if ((ret = ehca_create_slab_caches())) {
+	ret = ehca_create_slab_caches();
+	if (ret) {
 		ehca_gen_err("Cannot create SLAB caches");
 		ret = -ENOMEM;
 		goto module_init1;
 	}
 
-	if ((ret = ibmebus_register_driver(&ehca_driver))) {
+	ret = ibmebus_register_driver(&ehca_driver);
+	if (ret) {
 		ehca_gen_err("Cannot register eHCA device driver");
 		ret = -EINVAL;
 		goto module_init2;
diff --git a/drivers/infiniband/hw/ehca/ehca_mcast.c b/drivers/infiniband/hw/ehca/ehca_mcast.c
index 32a8706..e3ef026 100644
--- a/drivers/infiniband/hw/ehca/ehca_mcast.c
+++ b/drivers/infiniband/hw/ehca/ehca_mcast.c
@@ -88,7 +88,7 @@
 	if (h_ret != H_SUCCESS)
 		ehca_err(ibqp->device,
 			 "ehca_qp=%p qp_num=%x hipz_h_attach_mcqp() failed "
-			 "h_ret=%lx", my_qp, ibqp->qp_num, h_ret);
+			 "h_ret=%li", my_qp, ibqp->qp_num, h_ret);
 
 	return ehca2ib_return_code(h_ret);
 }
@@ -125,7 +125,7 @@
 	if (h_ret != H_SUCCESS)
 		ehca_err(ibqp->device,
 			 "ehca_qp=%p qp_num=%x hipz_h_detach_mcqp() failed "
-			 "h_ret=%lx", my_qp, ibqp->qp_num, h_ret);
+			 "h_ret=%li", my_qp, ibqp->qp_num, h_ret);
 
 	return ehca2ib_return_code(h_ret);
 }
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c
index add79bd..da88738 100644
--- a/drivers/infiniband/hw/ehca/ehca_mrmw.c
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c
@@ -5,6 +5,7 @@
  *
  *  Authors: Dietmar Decker <ddecker@de.ibm.com>
  *           Christoph Raisch <raisch@de.ibm.com>
+ *           Hoang-Nam Nguyen <hnguyen@de.ibm.com>
  *
  *  Copyright (c) 2005 IBM Corporation
  *
@@ -39,26 +40,66 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <rdma/ib_umem.h>
-
 #include <asm/current.h>
 
+#include <rdma/ib_umem.h>
+
 #include "ehca_iverbs.h"
 #include "ehca_mrmw.h"
 #include "hcp_if.h"
 #include "hipz_hw.h"
 
+#define NUM_CHUNKS(length, chunk_size) \
+	(((length) + (chunk_size - 1)) / (chunk_size))
+
+/* max number of rpages (per hcall register_rpages) */
+#define MAX_RPAGES 512
+
 static struct kmem_cache *mr_cache;
 static struct kmem_cache *mw_cache;
 
+enum ehca_mr_pgsize {
+	EHCA_MR_PGSIZE4K  = 0x1000L,
+	EHCA_MR_PGSIZE64K = 0x10000L,
+	EHCA_MR_PGSIZE1M  = 0x100000L,
+	EHCA_MR_PGSIZE16M = 0x1000000L
+};
+
+#define EHCA_MR_PGSHIFT4K  12
+#define EHCA_MR_PGSHIFT64K 16
+#define EHCA_MR_PGSHIFT1M  20
+#define EHCA_MR_PGSHIFT16M 24
+
+static u32 ehca_encode_hwpage_size(u32 pgsize)
+{
+	u32 idx = 0;
+	pgsize >>= 12;
+	/*
+	 * map mr page size into hw code:
+	 * 0, 1, 2, 3 for 4K, 64K, 1M, 64M
+	 */
+	while (!(pgsize & 1)) {
+		idx++;
+		pgsize >>= 4;
+	}
+	return idx;
+}
+
+static u64 ehca_get_max_hwpage_size(struct ehca_shca *shca)
+{
+	if (shca->hca_cap_mr_pgsize & HCA_CAP_MR_PGSIZE_16M)
+		return EHCA_MR_PGSIZE16M;
+	return EHCA_MR_PGSIZE4K;
+}
+
 static struct ehca_mr *ehca_mr_new(void)
 {
 	struct ehca_mr *me;
 
 	me = kmem_cache_zalloc(mr_cache, GFP_KERNEL);
-	if (me) {
+	if (me)
 		spin_lock_init(&me->mrlock);
-	} else
+	else
 		ehca_gen_err("alloc failed");
 
 	return me;
@@ -74,9 +115,9 @@
 	struct ehca_mw *me;
 
 	me = kmem_cache_zalloc(mw_cache, GFP_KERNEL);
-	if (me) {
+	if (me)
 		spin_lock_init(&me->mwlock);
-	} else
+	else
 		ehca_gen_err("alloc failed");
 
 	return me;
@@ -106,11 +147,12 @@
 			goto get_dma_mr_exit0;
 		}
 
-		ret = ehca_reg_maxmr(shca, e_maxmr, (u64*)KERNELBASE,
+		ret = ehca_reg_maxmr(shca, e_maxmr, (u64 *)KERNELBASE,
 				     mr_access_flags, e_pd,
 				     &e_maxmr->ib.ib_mr.lkey,
 				     &e_maxmr->ib.ib_mr.rkey);
 		if (ret) {
+			ehca_mr_delete(e_maxmr);
 			ib_mr = ERR_PTR(ret);
 			goto get_dma_mr_exit0;
 		}
@@ -123,7 +165,7 @@
 
 get_dma_mr_exit0:
 	if (IS_ERR(ib_mr))
-		ehca_err(&shca->ib_device, "rc=%lx pd=%p mr_access_flags=%x ",
+		ehca_err(&shca->ib_device, "h_ret=%li pd=%p mr_access_flags=%x",
 			 PTR_ERR(ib_mr), pd, mr_access_flags);
 	return ib_mr;
 } /* end ehca_get_dma_mr() */
@@ -144,9 +186,6 @@
 	struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
 
 	u64 size;
-	struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
-	u32 num_pages_mr;
-	u32 num_pages_4k; /* 4k portion "pages" */
 
 	if ((num_phys_buf <= 0) || !phys_buf_array) {
 		ehca_err(pd->device, "bad input values: num_phys_buf=%x "
@@ -190,12 +229,6 @@
 		goto reg_phys_mr_exit0;
 	}
 
-	/* determine number of MR pages */
-	num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size +
-			 PAGE_SIZE - 1) / PAGE_SIZE);
-	num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size +
-			 EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
-
 	/* register MR on HCA */
 	if (ehca_mr_is_maxmr(size, iova_start)) {
 		e_mr->flags |= EHCA_MR_FLAG_MAXMR;
@@ -207,13 +240,26 @@
 			goto reg_phys_mr_exit1;
 		}
 	} else {
-		pginfo.type           = EHCA_MR_PGI_PHYS;
-		pginfo.num_pages      = num_pages_mr;
-		pginfo.num_4k         = num_pages_4k;
-		pginfo.num_phys_buf   = num_phys_buf;
-		pginfo.phys_buf_array = phys_buf_array;
-		pginfo.next_4k        = (((u64)iova_start & ~PAGE_MASK) /
-					 EHCA_PAGESIZE);
+		struct ehca_mr_pginfo pginfo;
+		u32 num_kpages;
+		u32 num_hwpages;
+		u64 hw_pgsize;
+
+		num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size,
+					PAGE_SIZE);
+		/* for kernel space we try most possible pgsize */
+		hw_pgsize = ehca_get_max_hwpage_size(shca);
+		num_hwpages = NUM_CHUNKS(((u64)iova_start % hw_pgsize) + size,
+					 hw_pgsize);
+		memset(&pginfo, 0, sizeof(pginfo));
+		pginfo.type = EHCA_MR_PGI_PHYS;
+		pginfo.num_kpages = num_kpages;
+		pginfo.hwpage_size = hw_pgsize;
+		pginfo.num_hwpages = num_hwpages;
+		pginfo.u.phy.num_phys_buf = num_phys_buf;
+		pginfo.u.phy.phys_buf_array = phys_buf_array;
+		pginfo.next_hwpage =
+			((u64)iova_start & ~(hw_pgsize - 1)) / hw_pgsize;
 
 		ret = ehca_reg_mr(shca, e_mr, iova_start, size, mr_access_flags,
 				  e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
@@ -231,7 +277,7 @@
 	ehca_mr_delete(e_mr);
 reg_phys_mr_exit0:
 	if (IS_ERR(ib_mr))
-		ehca_err(pd->device, "rc=%lx pd=%p phys_buf_array=%p "
+		ehca_err(pd->device, "h_ret=%li pd=%p phys_buf_array=%p "
 			 "num_phys_buf=%x mr_access_flags=%x iova_start=%p",
 			 PTR_ERR(ib_mr), pd, phys_buf_array,
 			 num_phys_buf, mr_access_flags, iova_start);
@@ -240,18 +286,20 @@
 
 /*----------------------------------------------------------------------*/
 
-struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt,
-			       int mr_access_flags, struct ib_udata *udata)
+struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
+			       u64 virt, int mr_access_flags,
+			       struct ib_udata *udata)
 {
 	struct ib_mr *ib_mr;
 	struct ehca_mr *e_mr;
 	struct ehca_shca *shca =
 		container_of(pd->device, struct ehca_shca, ib_device);
 	struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
-	struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+	struct ehca_mr_pginfo pginfo;
 	int ret;
-	u32 num_pages_mr;
-	u32 num_pages_4k; /* 4k portion "pages" */
+	u32 num_kpages;
+	u32 num_hwpages;
+	u64 hwpage_size;
 
 	if (!pd) {
 		ehca_gen_err("bad pd=%p", pd);
@@ -289,7 +337,7 @@
 	e_mr->umem = ib_umem_get(pd->uobject->context, start, length,
 				 mr_access_flags);
 	if (IS_ERR(e_mr->umem)) {
-		ib_mr = (void *) e_mr->umem;
+		ib_mr = (void *)e_mr->umem;
 		goto reg_user_mr_exit1;
 	}
 
@@ -301,23 +349,51 @@
 	}
 
 	/* determine number of MR pages */
-	num_pages_mr = (((virt % PAGE_SIZE) + length + PAGE_SIZE - 1) /
-			PAGE_SIZE);
-	num_pages_4k = (((virt % EHCA_PAGESIZE) + length + EHCA_PAGESIZE - 1) /
-			EHCA_PAGESIZE);
+	num_kpages = NUM_CHUNKS((virt % PAGE_SIZE) + length, PAGE_SIZE);
+	/* select proper hw_pgsize */
+	if (ehca_mr_largepage &&
+	    (shca->hca_cap_mr_pgsize & HCA_CAP_MR_PGSIZE_16M)) {
+		int page_shift = PAGE_SHIFT;
+		if (e_mr->umem->hugetlb) {
+			/* determine page_shift, clamp between 4K and 16M */
+			page_shift = (fls64(length - 1) + 3) & ~3;
+			page_shift = min(max(page_shift, EHCA_MR_PGSHIFT4K),
+					 EHCA_MR_PGSHIFT16M);
+		}
+		hwpage_size = 1UL << page_shift;
+	} else
+		hwpage_size = EHCA_MR_PGSIZE4K; /* ehca1 only supports 4k */
+	ehca_dbg(pd->device, "hwpage_size=%lx", hwpage_size);
 
+reg_user_mr_fallback:
+	num_hwpages = NUM_CHUNKS((virt % hwpage_size) + length, hwpage_size);
 	/* register MR on HCA */
-	pginfo.type       = EHCA_MR_PGI_USER;
-	pginfo.num_pages  = num_pages_mr;
-	pginfo.num_4k     = num_pages_4k;
-	pginfo.region     = e_mr->umem;
-	pginfo.next_4k	  = e_mr->umem->offset / EHCA_PAGESIZE;
-	pginfo.next_chunk = list_prepare_entry(pginfo.next_chunk,
-					       (&e_mr->umem->chunk_list),
-					       list);
+	memset(&pginfo, 0, sizeof(pginfo));
+	pginfo.type = EHCA_MR_PGI_USER;
+	pginfo.hwpage_size = hwpage_size;
+	pginfo.num_kpages = num_kpages;
+	pginfo.num_hwpages = num_hwpages;
+	pginfo.u.usr.region = e_mr->umem;
+	pginfo.next_hwpage = e_mr->umem->offset / hwpage_size;
+	pginfo.u.usr.next_chunk = list_prepare_entry(pginfo.u.usr.next_chunk,
+						     (&e_mr->umem->chunk_list),
+						     list);
 
-	ret = ehca_reg_mr(shca, e_mr, (u64*) virt, length, mr_access_flags, e_pd,
-			  &pginfo, &e_mr->ib.ib_mr.lkey, &e_mr->ib.ib_mr.rkey);
+	ret = ehca_reg_mr(shca, e_mr, (u64 *)virt, length, mr_access_flags,
+			  e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
+			  &e_mr->ib.ib_mr.rkey);
+	if (ret == -EINVAL && pginfo.hwpage_size > PAGE_SIZE) {
+		ehca_warn(pd->device, "failed to register mr "
+			  "with hwpage_size=%lx", hwpage_size);
+		ehca_info(pd->device, "try to register mr with "
+			  "kpage_size=%lx", PAGE_SIZE);
+		/*
+		 * this means kpages are not contiguous for a hw page
+		 * try kernel page size as fallback solution
+		 */
+		hwpage_size = PAGE_SIZE;
+		goto reg_user_mr_fallback;
+	}
 	if (ret) {
 		ib_mr = ERR_PTR(ret);
 		goto reg_user_mr_exit2;
@@ -332,8 +408,7 @@
 	ehca_mr_delete(e_mr);
 reg_user_mr_exit0:
 	if (IS_ERR(ib_mr))
-		ehca_err(pd->device, "rc=%lx pd=%p mr_access_flags=%x"
-			 " udata=%p",
+		ehca_err(pd->device, "rc=%li pd=%p mr_access_flags=%x udata=%p",
 			 PTR_ERR(ib_mr), pd, mr_access_flags, udata);
 	return ib_mr;
 } /* end ehca_reg_user_mr() */
@@ -360,9 +435,9 @@
 	struct ehca_pd *new_pd;
 	u32 tmp_lkey, tmp_rkey;
 	unsigned long sl_flags;
-	u32 num_pages_mr = 0;
-	u32 num_pages_4k = 0; /* 4k portion "pages" */
-	struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+	u32 num_kpages = 0;
+	u32 num_hwpages = 0;
+	struct ehca_mr_pginfo pginfo;
 	u32 cur_pid = current->tgid;
 
 	if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
@@ -414,7 +489,7 @@
 			goto rereg_phys_mr_exit0;
 		}
 		if (!phys_buf_array || num_phys_buf <= 0) {
-			ehca_err(mr->device, "bad input values: mr_rereg_mask=%x"
+			ehca_err(mr->device, "bad input values mr_rereg_mask=%x"
 				 " phys_buf_array=%p num_phys_buf=%x",
 				 mr_rereg_mask, phys_buf_array, num_phys_buf);
 			ret = -EINVAL;
@@ -438,12 +513,14 @@
 
 	/* set requested values dependent on rereg request */
 	spin_lock_irqsave(&e_mr->mrlock, sl_flags);
-	new_start = e_mr->start;  /* new == old address */
-	new_size  = e_mr->size;	  /* new == old length */
-	new_acl   = e_mr->acl;	  /* new == old access control */
-	new_pd    = container_of(mr->pd,struct ehca_pd,ib_pd); /*new == old PD*/
+	new_start = e_mr->start;
+	new_size = e_mr->size;
+	new_acl = e_mr->acl;
+	new_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
 
 	if (mr_rereg_mask & IB_MR_REREG_TRANS) {
+		u64 hw_pgsize = ehca_get_max_hwpage_size(shca);
+
 		new_start = iova_start;	/* change address */
 		/* check physical buffer list and calculate size */
 		ret = ehca_mr_chk_buf_and_calc_size(phys_buf_array,
@@ -458,17 +535,19 @@
 			ret = -EINVAL;
 			goto rereg_phys_mr_exit1;
 		}
-		num_pages_mr = ((((u64)new_start % PAGE_SIZE) + new_size +
-				 PAGE_SIZE - 1) / PAGE_SIZE);
-		num_pages_4k = ((((u64)new_start % EHCA_PAGESIZE) + new_size +
-				 EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
-		pginfo.type           = EHCA_MR_PGI_PHYS;
-		pginfo.num_pages      = num_pages_mr;
-		pginfo.num_4k         = num_pages_4k;
-		pginfo.num_phys_buf   = num_phys_buf;
-		pginfo.phys_buf_array = phys_buf_array;
-		pginfo.next_4k        = (((u64)iova_start & ~PAGE_MASK) /
-					 EHCA_PAGESIZE);
+		num_kpages = NUM_CHUNKS(((u64)new_start % PAGE_SIZE) +
+					new_size, PAGE_SIZE);
+		num_hwpages = NUM_CHUNKS(((u64)new_start % hw_pgsize) +
+					 new_size, hw_pgsize);
+		memset(&pginfo, 0, sizeof(pginfo));
+		pginfo.type = EHCA_MR_PGI_PHYS;
+		pginfo.num_kpages = num_kpages;
+		pginfo.hwpage_size = hw_pgsize;
+		pginfo.num_hwpages = num_hwpages;
+		pginfo.u.phy.num_phys_buf = num_phys_buf;
+		pginfo.u.phy.phys_buf_array = phys_buf_array;
+		pginfo.next_hwpage =
+			((u64)iova_start & ~(hw_pgsize - 1)) / hw_pgsize;
 	}
 	if (mr_rereg_mask & IB_MR_REREG_ACCESS)
 		new_acl = mr_access_flags;
@@ -490,7 +569,7 @@
 	spin_unlock_irqrestore(&e_mr->mrlock, sl_flags);
 rereg_phys_mr_exit0:
 	if (ret)
-		ehca_err(mr->device, "ret=%x mr=%p mr_rereg_mask=%x pd=%p "
+		ehca_err(mr->device, "ret=%i mr=%p mr_rereg_mask=%x pd=%p "
 			 "phys_buf_array=%p num_phys_buf=%x mr_access_flags=%x "
 			 "iova_start=%p",
 			 ret, mr, mr_rereg_mask, pd, phys_buf_array,
@@ -510,7 +589,7 @@
 	struct ehca_pd *my_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
 	u32 cur_pid = current->tgid;
 	unsigned long sl_flags;
-	struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+	struct ehca_mr_hipzout_parms hipzout;
 
 	if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
 	    (my_pd->ownpid != cur_pid)) {
@@ -532,25 +611,25 @@
 
 	h_ret = hipz_h_query_mr(shca->ipz_hca_handle, e_mr, &hipzout);
 	if (h_ret != H_SUCCESS) {
-		ehca_err(mr->device, "hipz_mr_query failed, h_ret=%lx mr=%p "
+		ehca_err(mr->device, "hipz_mr_query failed, h_ret=%li mr=%p "
 			 "hca_hndl=%lx mr_hndl=%lx lkey=%x",
 			 h_ret, mr, shca->ipz_hca_handle.handle,
 			 e_mr->ipz_mr_handle.handle, mr->lkey);
-		ret = ehca_mrmw_map_hrc_query_mr(h_ret);
+		ret = ehca2ib_return_code(h_ret);
 		goto query_mr_exit1;
 	}
-	mr_attr->pd               = mr->pd;
+	mr_attr->pd = mr->pd;
 	mr_attr->device_virt_addr = hipzout.vaddr;
-	mr_attr->size             = hipzout.len;
-	mr_attr->lkey             = hipzout.lkey;
-	mr_attr->rkey             = hipzout.rkey;
+	mr_attr->size = hipzout.len;
+	mr_attr->lkey = hipzout.lkey;
+	mr_attr->rkey = hipzout.rkey;
 	ehca_mrmw_reverse_map_acl(&hipzout.acl, &mr_attr->mr_access_flags);
 
 query_mr_exit1:
 	spin_unlock_irqrestore(&e_mr->mrlock, sl_flags);
 query_mr_exit0:
 	if (ret)
-		ehca_err(mr->device, "ret=%x mr=%p mr_attr=%p",
+		ehca_err(mr->device, "ret=%i mr=%p mr_attr=%p",
 			 ret, mr, mr_attr);
 	return ret;
 } /* end ehca_query_mr() */
@@ -592,11 +671,11 @@
 	/* TODO: BUSY: MR still has bound window(s) */
 	h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
 	if (h_ret != H_SUCCESS) {
-		ehca_err(mr->device, "hipz_free_mr failed, h_ret=%lx shca=%p "
+		ehca_err(mr->device, "hipz_free_mr failed, h_ret=%li shca=%p "
 			 "e_mr=%p hca_hndl=%lx mr_hndl=%lx mr->lkey=%x",
 			 h_ret, shca, e_mr, shca->ipz_hca_handle.handle,
 			 e_mr->ipz_mr_handle.handle, mr->lkey);
-		ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+		ret = ehca2ib_return_code(h_ret);
 		goto dereg_mr_exit0;
 	}
 
@@ -608,7 +687,7 @@
 
 dereg_mr_exit0:
 	if (ret)
-		ehca_err(mr->device, "ret=%x mr=%p", ret, mr);
+		ehca_err(mr->device, "ret=%i mr=%p", ret, mr);
 	return ret;
 } /* end ehca_dereg_mr() */
 
@@ -622,7 +701,7 @@
 	struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
 	struct ehca_shca *shca =
 		container_of(pd->device, struct ehca_shca, ib_device);
-	struct ehca_mw_hipzout_parms hipzout = {{0},0};
+	struct ehca_mw_hipzout_parms hipzout;
 
 	e_mw = ehca_mw_new();
 	if (!e_mw) {
@@ -633,10 +712,10 @@
 	h_ret = hipz_h_alloc_resource_mw(shca->ipz_hca_handle, e_mw,
 					 e_pd->fw_pd, &hipzout);
 	if (h_ret != H_SUCCESS) {
-		ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%lx "
+		ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%li "
 			 "shca=%p hca_hndl=%lx mw=%p",
 			 h_ret, shca, shca->ipz_hca_handle.handle, e_mw);
-		ib_mw = ERR_PTR(ehca_mrmw_map_hrc_alloc(h_ret));
+		ib_mw = ERR_PTR(ehca2ib_return_code(h_ret));
 		goto alloc_mw_exit1;
 	}
 	/* successful MW allocation */
@@ -648,7 +727,7 @@
 	ehca_mw_delete(e_mw);
 alloc_mw_exit0:
 	if (IS_ERR(ib_mw))
-		ehca_err(pd->device, "rc=%lx pd=%p", PTR_ERR(ib_mw), pd);
+		ehca_err(pd->device, "h_ret=%li pd=%p", PTR_ERR(ib_mw), pd);
 	return ib_mw;
 } /* end ehca_alloc_mw() */
 
@@ -675,11 +754,11 @@
 
 	h_ret = hipz_h_free_resource_mw(shca->ipz_hca_handle, e_mw);
 	if (h_ret != H_SUCCESS) {
-		ehca_err(mw->device, "hipz_free_mw failed, h_ret=%lx shca=%p "
+		ehca_err(mw->device, "hipz_free_mw failed, h_ret=%li shca=%p "
 			 "mw=%p rkey=%x hca_hndl=%lx mw_hndl=%lx",
 			 h_ret, shca, mw, mw->rkey, shca->ipz_hca_handle.handle,
 			 e_mw->ipz_mw_handle.handle);
-		return ehca_mrmw_map_hrc_free_mw(h_ret);
+		return ehca2ib_return_code(h_ret);
 	}
 	/* successful deallocation */
 	ehca_mw_delete(e_mw);
@@ -699,7 +778,8 @@
 	struct ehca_mr *e_fmr;
 	int ret;
 	u32 tmp_lkey, tmp_rkey;
-	struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+	struct ehca_mr_pginfo pginfo;
+	u64 hw_pgsize;
 
 	/* check other parameters */
 	if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
@@ -729,8 +809,8 @@
 		ib_fmr = ERR_PTR(-EINVAL);
 		goto alloc_fmr_exit0;
 	}
-	if (((1 << fmr_attr->page_shift) != EHCA_PAGESIZE) &&
-	    ((1 << fmr_attr->page_shift) != PAGE_SIZE)) {
+	hw_pgsize = ehca_get_max_hwpage_size(shca);
+	if ((1 << fmr_attr->page_shift) != hw_pgsize) {
 		ehca_err(pd->device, "unsupported fmr_attr->page_shift=%x",
 			 fmr_attr->page_shift);
 		ib_fmr = ERR_PTR(-EINVAL);
@@ -745,6 +825,11 @@
 	e_fmr->flags |= EHCA_MR_FLAG_FMR;
 
 	/* register MR on HCA */
+	memset(&pginfo, 0, sizeof(pginfo));
+	/*
+	 * pginfo.num_hwpages==0, ie register_rpages() will not be called
+	 * but deferred to map_phys_fmr()
+	 */
 	ret = ehca_reg_mr(shca, e_fmr, NULL,
 			  fmr_attr->max_pages * (1 << fmr_attr->page_shift),
 			  mr_access_flags, e_pd, &pginfo,
@@ -755,6 +840,7 @@
 	}
 
 	/* successful */
+	e_fmr->hwpage_size = hw_pgsize;
 	e_fmr->fmr_page_size = 1 << fmr_attr->page_shift;
 	e_fmr->fmr_max_pages = fmr_attr->max_pages;
 	e_fmr->fmr_max_maps = fmr_attr->max_maps;
@@ -764,10 +850,6 @@
 alloc_fmr_exit1:
 	ehca_mr_delete(e_fmr);
 alloc_fmr_exit0:
-	if (IS_ERR(ib_fmr))
-		ehca_err(pd->device, "rc=%lx pd=%p mr_access_flags=%x "
-			 "fmr_attr=%p", PTR_ERR(ib_fmr), pd,
-			 mr_access_flags, fmr_attr);
 	return ib_fmr;
 } /* end ehca_alloc_fmr() */
 
@@ -783,7 +865,7 @@
 		container_of(fmr->device, struct ehca_shca, ib_device);
 	struct ehca_mr *e_fmr = container_of(fmr, struct ehca_mr, ib.ib_fmr);
 	struct ehca_pd *e_pd = container_of(fmr->pd, struct ehca_pd, ib_pd);
-	struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+	struct ehca_mr_pginfo pginfo;
 	u32 tmp_lkey, tmp_rkey;
 
 	if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) {
@@ -809,14 +891,18 @@
 			  fmr, e_fmr->fmr_map_cnt, e_fmr->fmr_max_maps);
 	}
 
-	pginfo.type      = EHCA_MR_PGI_FMR;
-	pginfo.num_pages = list_len;
-	pginfo.num_4k    = list_len * (e_fmr->fmr_page_size / EHCA_PAGESIZE);
-	pginfo.page_list = page_list;
-	pginfo.next_4k   = ((iova & (e_fmr->fmr_page_size-1)) /
-			    EHCA_PAGESIZE);
+	memset(&pginfo, 0, sizeof(pginfo));
+	pginfo.type = EHCA_MR_PGI_FMR;
+	pginfo.num_kpages = list_len;
+	pginfo.hwpage_size = e_fmr->hwpage_size;
+	pginfo.num_hwpages =
+		list_len * e_fmr->fmr_page_size / pginfo.hwpage_size;
+	pginfo.u.fmr.page_list = page_list;
+	pginfo.next_hwpage =
+		(iova & (e_fmr->fmr_page_size-1)) / pginfo.hwpage_size;
+	pginfo.u.fmr.fmr_pgsize = e_fmr->fmr_page_size;
 
-	ret = ehca_rereg_mr(shca, e_fmr, (u64*)iova,
+	ret = ehca_rereg_mr(shca, e_fmr, (u64 *)iova,
 			    list_len * e_fmr->fmr_page_size,
 			    e_fmr->acl, e_pd, &pginfo, &tmp_lkey, &tmp_rkey);
 	if (ret)
@@ -830,9 +916,8 @@
 
 map_phys_fmr_exit0:
 	if (ret)
-		ehca_err(fmr->device, "ret=%x fmr=%p page_list=%p list_len=%x "
-			 "iova=%lx",
-			 ret, fmr, page_list, list_len, iova);
+		ehca_err(fmr->device, "ret=%i fmr=%p page_list=%p list_len=%x "
+			 "iova=%lx", ret, fmr, page_list, list_len, iova);
 	return ret;
 } /* end ehca_map_phys_fmr() */
 
@@ -894,7 +979,7 @@
 
 unmap_fmr_exit0:
 	if (ret)
-		ehca_gen_err("ret=%x fmr_list=%p num_fmr=%x unmap_fmr_cnt=%x",
+		ehca_gen_err("ret=%i fmr_list=%p num_fmr=%x unmap_fmr_cnt=%x",
 			     ret, fmr_list, num_fmr, unmap_fmr_cnt);
 	return ret;
 } /* end ehca_unmap_fmr() */
@@ -918,11 +1003,11 @@
 
 	h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
 	if (h_ret != H_SUCCESS) {
-		ehca_err(fmr->device, "hipz_free_mr failed, h_ret=%lx e_fmr=%p "
+		ehca_err(fmr->device, "hipz_free_mr failed, h_ret=%li e_fmr=%p "
 			 "hca_hndl=%lx fmr_hndl=%lx fmr->lkey=%x",
 			 h_ret, e_fmr, shca->ipz_hca_handle.handle,
 			 e_fmr->ipz_mr_handle.handle, fmr->lkey);
-		ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+		ret = ehca2ib_return_code(h_ret);
 		goto free_fmr_exit0;
 	}
 	/* successful deregistration */
@@ -931,7 +1016,7 @@
 
 free_fmr_exit0:
 	if (ret)
-		ehca_err(&shca->ib_device, "ret=%x fmr=%p", ret, fmr);
+		ehca_err(&shca->ib_device, "ret=%i fmr=%p", ret, fmr);
 	return ret;
 } /* end ehca_dealloc_fmr() */
 
@@ -950,20 +1035,20 @@
 	int ret;
 	u64 h_ret;
 	u32 hipz_acl;
-	struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+	struct ehca_mr_hipzout_parms hipzout;
 
 	ehca_mrmw_map_acl(acl, &hipz_acl);
-	ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+	ehca_mrmw_set_pgsize_hipz_acl(pginfo->hwpage_size, &hipz_acl);
 	if (ehca_use_hp_mr == 1)
-	        hipz_acl |= 0x00000001;
+		hipz_acl |= 0x00000001;
 
 	h_ret = hipz_h_alloc_resource_mr(shca->ipz_hca_handle, e_mr,
 					 (u64)iova_start, size, hipz_acl,
 					 e_pd->fw_pd, &hipzout);
 	if (h_ret != H_SUCCESS) {
-		ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%lx "
+		ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%li "
 			 "hca_hndl=%lx", h_ret, shca->ipz_hca_handle.handle);
-		ret = ehca_mrmw_map_hrc_alloc(h_ret);
+		ret = ehca2ib_return_code(h_ret);
 		goto ehca_reg_mr_exit0;
 	}
 
@@ -974,11 +1059,12 @@
 		goto ehca_reg_mr_exit1;
 
 	/* successful registration */
-	e_mr->num_pages = pginfo->num_pages;
-	e_mr->num_4k    = pginfo->num_4k;
-	e_mr->start     = iova_start;
-	e_mr->size      = size;
-	e_mr->acl       = acl;
+	e_mr->num_kpages = pginfo->num_kpages;
+	e_mr->num_hwpages = pginfo->num_hwpages;
+	e_mr->hwpage_size = pginfo->hwpage_size;
+	e_mr->start = iova_start;
+	e_mr->size = size;
+	e_mr->acl = acl;
 	*lkey = hipzout.lkey;
 	*rkey = hipzout.rkey;
 	return 0;
@@ -986,22 +1072,22 @@
 ehca_reg_mr_exit1:
 	h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
 	if (h_ret != H_SUCCESS) {
-		ehca_err(&shca->ib_device, "h_ret=%lx shca=%p e_mr=%p "
+		ehca_err(&shca->ib_device, "h_ret=%li shca=%p e_mr=%p "
 			 "iova_start=%p size=%lx acl=%x e_pd=%p lkey=%x "
-			 "pginfo=%p num_pages=%lx num_4k=%lx ret=%x",
+			 "pginfo=%p num_kpages=%lx num_hwpages=%lx ret=%i",
 			 h_ret, shca, e_mr, iova_start, size, acl, e_pd,
-			 hipzout.lkey, pginfo, pginfo->num_pages,
-			 pginfo->num_4k, ret);
+			 hipzout.lkey, pginfo, pginfo->num_kpages,
+			 pginfo->num_hwpages, ret);
 		ehca_err(&shca->ib_device, "internal error in ehca_reg_mr, "
 			 "not recoverable");
 	}
 ehca_reg_mr_exit0:
 	if (ret)
-		ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p "
+		ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p "
 			 "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
-			 "num_pages=%lx num_4k=%lx",
+			 "num_kpages=%lx num_hwpages=%lx",
 			 ret, shca, e_mr, iova_start, size, acl, e_pd, pginfo,
-			 pginfo->num_pages, pginfo->num_4k);
+			 pginfo->num_kpages, pginfo->num_hwpages);
 	return ret;
 } /* end ehca_reg_mr() */
 
@@ -1018,6 +1104,9 @@
 	u32 i;
 	u64 *kpage;
 
+	if (!pginfo->num_hwpages) /* in case of fmr */
+		return 0;
+
 	kpage = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
 	if (!kpage) {
 		ehca_err(&shca->ib_device, "kpage alloc failed");
@@ -1025,25 +1114,25 @@
 		goto ehca_reg_mr_rpages_exit0;
 	}
 
-	/* max 512 pages per shot */
-	for (i = 0; i < ((pginfo->num_4k + 512 - 1) / 512); i++) {
+	/* max MAX_RPAGES ehca mr pages per register call */
+	for (i = 0; i < NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES); i++) {
 
-		if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) {
-			rnum = pginfo->num_4k % 512; /* last shot */
+		if (i == NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES) - 1) {
+			rnum = pginfo->num_hwpages % MAX_RPAGES; /* last shot */
 			if (rnum == 0)
-				rnum = 512;      /* last shot is full */
+				rnum = MAX_RPAGES;      /* last shot is full */
 		} else
-			rnum = 512;
+			rnum = MAX_RPAGES;
+
+		ret = ehca_set_pagebuf(pginfo, rnum, kpage);
+		if (ret) {
+			ehca_err(&shca->ib_device, "ehca_set_pagebuf "
+				 "bad rc, ret=%i rnum=%x kpage=%p",
+				 ret, rnum, kpage);
+			goto ehca_reg_mr_rpages_exit1;
+		}
 
 		if (rnum > 1) {
-			ret = ehca_set_pagebuf(e_mr, pginfo, rnum, kpage);
-			if (ret) {
-				ehca_err(&shca->ib_device, "ehca_set_pagebuf "
-					 "bad rc, ret=%x rnum=%x kpage=%p",
-					 ret, rnum, kpage);
-				ret = -EFAULT;
-				goto ehca_reg_mr_rpages_exit1;
-			}
 			rpage = virt_to_abs(kpage);
 			if (!rpage) {
 				ehca_err(&shca->ib_device, "kpage=%p i=%x",
@@ -1051,45 +1140,39 @@
 				ret = -EFAULT;
 				goto ehca_reg_mr_rpages_exit1;
 			}
-		} else {  /* rnum==1 */
-			ret = ehca_set_pagebuf_1(e_mr, pginfo, &rpage);
-			if (ret) {
-				ehca_err(&shca->ib_device, "ehca_set_pagebuf_1 "
-					 "bad rc, ret=%x i=%x", ret, i);
-				ret = -EFAULT;
-				goto ehca_reg_mr_rpages_exit1;
-			}
-		}
+		} else
+			rpage = *kpage;
 
-		h_ret = hipz_h_register_rpage_mr(shca->ipz_hca_handle, e_mr,
-						 0, /* pagesize 4k */
-						 0, rpage, rnum);
+		h_ret = hipz_h_register_rpage_mr(
+			shca->ipz_hca_handle, e_mr,
+			ehca_encode_hwpage_size(pginfo->hwpage_size),
+			0, rpage, rnum);
 
-		if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) {
+		if (i == NUM_CHUNKS(pginfo->num_hwpages, MAX_RPAGES) - 1) {
 			/*
 			 * check for 'registration complete'==H_SUCCESS
 			 * and for 'page registered'==H_PAGE_REGISTERED
 			 */
 			if (h_ret != H_SUCCESS) {
 				ehca_err(&shca->ib_device, "last "
-					 "hipz_reg_rpage_mr failed, h_ret=%lx "
+					 "hipz_reg_rpage_mr failed, h_ret=%li "
 					 "e_mr=%p i=%x hca_hndl=%lx mr_hndl=%lx"
 					 " lkey=%x", h_ret, e_mr, i,
 					 shca->ipz_hca_handle.handle,
 					 e_mr->ipz_mr_handle.handle,
 					 e_mr->ib.ib_mr.lkey);
-				ret = ehca_mrmw_map_hrc_rrpg_last(h_ret);
+				ret = ehca2ib_return_code(h_ret);
 				break;
 			} else
 				ret = 0;
 		} else if (h_ret != H_PAGE_REGISTERED) {
 			ehca_err(&shca->ib_device, "hipz_reg_rpage_mr failed, "
-				 "h_ret=%lx e_mr=%p i=%x lkey=%x hca_hndl=%lx "
+				 "h_ret=%li e_mr=%p i=%x lkey=%x hca_hndl=%lx "
 				 "mr_hndl=%lx", h_ret, e_mr, i,
 				 e_mr->ib.ib_mr.lkey,
 				 shca->ipz_hca_handle.handle,
 				 e_mr->ipz_mr_handle.handle);
-			ret = ehca_mrmw_map_hrc_rrpg_notlast(h_ret);
+			ret = ehca2ib_return_code(h_ret);
 			break;
 		} else
 			ret = 0;
@@ -1100,9 +1183,9 @@
 	ehca_free_fw_ctrlblock(kpage);
 ehca_reg_mr_rpages_exit0:
 	if (ret)
-		ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p pginfo=%p "
-			 "num_pages=%lx num_4k=%lx", ret, shca, e_mr, pginfo,
-			 pginfo->num_pages, pginfo->num_4k);
+		ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p pginfo=%p "
+			 "num_kpages=%lx num_hwpages=%lx", ret, shca, e_mr,
+			 pginfo, pginfo->num_kpages, pginfo->num_hwpages);
 	return ret;
 } /* end ehca_reg_mr_rpages() */
 
@@ -1124,10 +1207,10 @@
 	u64 *kpage;
 	u64 rpage;
 	struct ehca_mr_pginfo pginfo_save;
-	struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+	struct ehca_mr_hipzout_parms hipzout;
 
 	ehca_mrmw_map_acl(acl, &hipz_acl);
-	ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+	ehca_mrmw_set_pgsize_hipz_acl(pginfo->hwpage_size, &hipz_acl);
 
 	kpage = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
 	if (!kpage) {
@@ -1137,12 +1220,12 @@
 	}
 
 	pginfo_save = *pginfo;
-	ret = ehca_set_pagebuf(e_mr, pginfo, pginfo->num_4k, kpage);
+	ret = ehca_set_pagebuf(pginfo, pginfo->num_hwpages, kpage);
 	if (ret) {
 		ehca_err(&shca->ib_device, "set pagebuf failed, e_mr=%p "
-			 "pginfo=%p type=%x num_pages=%lx num_4k=%lx kpage=%p",
-			 e_mr, pginfo, pginfo->type, pginfo->num_pages,
-			 pginfo->num_4k,kpage);
+			 "pginfo=%p type=%x num_kpages=%lx num_hwpages=%lx "
+			 "kpage=%p", e_mr, pginfo, pginfo->type,
+			 pginfo->num_kpages, pginfo->num_hwpages, kpage);
 		goto ehca_rereg_mr_rereg1_exit1;
 	}
 	rpage = virt_to_abs(kpage);
@@ -1161,10 +1244,10 @@
 		 * (MW bound or MR is shared)
 		 */
 		ehca_warn(&shca->ib_device, "hipz_h_reregister_pmr failed "
-			  "(Rereg1), h_ret=%lx e_mr=%p", h_ret, e_mr);
+			  "(Rereg1), h_ret=%li e_mr=%p", h_ret, e_mr);
 		*pginfo = pginfo_save;
 		ret = -EAGAIN;
-	} else if ((u64*)hipzout.vaddr != iova_start) {
+	} else if ((u64 *)hipzout.vaddr != iova_start) {
 		ehca_err(&shca->ib_device, "PHYP changed iova_start in "
 			 "rereg_pmr, iova_start=%p iova_start_out=%lx e_mr=%p "
 			 "mr_handle=%lx lkey=%x lkey_out=%x", iova_start,
@@ -1176,11 +1259,12 @@
 		 * successful reregistration
 		 * note: start and start_out are identical for eServer HCAs
 		 */
-		e_mr->num_pages = pginfo->num_pages;
-		e_mr->num_4k    = pginfo->num_4k;
-		e_mr->start     = iova_start;
-		e_mr->size      = size;
-		e_mr->acl       = acl;
+		e_mr->num_kpages = pginfo->num_kpages;
+		e_mr->num_hwpages = pginfo->num_hwpages;
+		e_mr->hwpage_size = pginfo->hwpage_size;
+		e_mr->start = iova_start;
+		e_mr->size = size;
+		e_mr->acl = acl;
 		*lkey = hipzout.lkey;
 		*rkey = hipzout.rkey;
 	}
@@ -1189,10 +1273,10 @@
 	ehca_free_fw_ctrlblock(kpage);
 ehca_rereg_mr_rereg1_exit0:
 	if ( ret && (ret != -EAGAIN) )
-		ehca_err(&shca->ib_device, "ret=%x lkey=%x rkey=%x "
-			 "pginfo=%p num_pages=%lx num_4k=%lx",
-			 ret, *lkey, *rkey, pginfo, pginfo->num_pages,
-			 pginfo->num_4k);
+		ehca_err(&shca->ib_device, "ret=%i lkey=%x rkey=%x "
+			 "pginfo=%p num_kpages=%lx num_hwpages=%lx",
+			 ret, *lkey, *rkey, pginfo, pginfo->num_kpages,
+			 pginfo->num_hwpages);
 	return ret;
 } /* end ehca_rereg_mr_rereg1() */
 
@@ -1214,10 +1298,12 @@
 	int rereg_3_hcall = 0; /* 1: use 3 hipz calls for reregistration */
 
 	/* first determine reregistration hCall(s) */
-	if ((pginfo->num_4k > 512) || (e_mr->num_4k > 512) ||
-	    (pginfo->num_4k > e_mr->num_4k)) {
-		ehca_dbg(&shca->ib_device, "Rereg3 case, pginfo->num_4k=%lx "
-			 "e_mr->num_4k=%x", pginfo->num_4k, e_mr->num_4k);
+	if ((pginfo->num_hwpages > MAX_RPAGES) ||
+	    (e_mr->num_hwpages > MAX_RPAGES) ||
+	    (pginfo->num_hwpages > e_mr->num_hwpages)) {
+		ehca_dbg(&shca->ib_device, "Rereg3 case, "
+			 "pginfo->num_hwpages=%lx e_mr->num_hwpages=%x",
+			 pginfo->num_hwpages, e_mr->num_hwpages);
 		rereg_1_hcall = 0;
 		rereg_3_hcall = 1;
 	}
@@ -1248,12 +1334,12 @@
 		h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
 		if (h_ret != H_SUCCESS) {
 			ehca_err(&shca->ib_device, "hipz_free_mr failed, "
-				 "h_ret=%lx e_mr=%p hca_hndl=%lx mr_hndl=%lx "
+				 "h_ret=%li e_mr=%p hca_hndl=%lx mr_hndl=%lx "
 				 "mr->lkey=%x",
 				 h_ret, e_mr, shca->ipz_hca_handle.handle,
 				 e_mr->ipz_mr_handle.handle,
 				 e_mr->ib.ib_mr.lkey);
-			ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+			ret = ehca2ib_return_code(h_ret);
 			goto ehca_rereg_mr_exit0;
 		}
 		/* clean ehca_mr_t, without changing struct ib_mr and lock */
@@ -1262,13 +1348,14 @@
 
 		/* set some MR values */
 		e_mr->flags = save_mr.flags;
+		e_mr->hwpage_size = save_mr.hwpage_size;
 		e_mr->fmr_page_size = save_mr.fmr_page_size;
 		e_mr->fmr_max_pages = save_mr.fmr_max_pages;
 		e_mr->fmr_max_maps = save_mr.fmr_max_maps;
 		e_mr->fmr_map_cnt = save_mr.fmr_map_cnt;
 
 		ret = ehca_reg_mr(shca, e_mr, iova_start, size, acl,
-				      e_pd, pginfo, lkey, rkey);
+				  e_pd, pginfo, lkey, rkey);
 		if (ret) {
 			u32 offset = (u64)(&e_mr->flags) - (u64)e_mr;
 			memcpy(&e_mr->flags, &(save_mr.flags),
@@ -1279,11 +1366,11 @@
 
 ehca_rereg_mr_exit0:
 	if (ret)
-		ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p "
+		ehca_err(&shca->ib_device, "ret=%i shca=%p e_mr=%p "
 			 "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
-			 "num_pages=%lx lkey=%x rkey=%x rereg_1_hcall=%x "
+			 "num_kpages=%lx lkey=%x rkey=%x rereg_1_hcall=%x "
 			 "rereg_3_hcall=%x", ret, shca, e_mr, iova_start, size,
-			 acl, e_pd, pginfo, pginfo->num_pages, *lkey, *rkey,
+			 acl, e_pd, pginfo, pginfo->num_kpages, *lkey, *rkey,
 			 rereg_1_hcall, rereg_3_hcall);
 	return ret;
 } /* end ehca_rereg_mr() */
@@ -1295,97 +1382,84 @@
 {
 	int ret = 0;
 	u64 h_ret;
-	int rereg_1_hcall = 1; /* 1: use hipz_mr_reregister directly */
-	int rereg_3_hcall = 0; /* 1: use 3 hipz calls for unmapping */
 	struct ehca_pd *e_pd =
 		container_of(e_fmr->ib.ib_fmr.pd, struct ehca_pd, ib_pd);
 	struct ehca_mr save_fmr;
 	u32 tmp_lkey, tmp_rkey;
-	struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
-	struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+	struct ehca_mr_pginfo pginfo;
+	struct ehca_mr_hipzout_parms hipzout;
+	struct ehca_mr save_mr;
 
-	/* first check if reregistration hCall can be used for unmap */
-	if (e_fmr->fmr_max_pages > 512) {
-		rereg_1_hcall = 0;
-		rereg_3_hcall = 1;
-	}
-
-	if (rereg_1_hcall) {
+	if (e_fmr->fmr_max_pages <= MAX_RPAGES) {
 		/*
 		 * note: after using rereg hcall with len=0,
 		 * rereg hcall must be used again for registering pages
 		 */
 		h_ret = hipz_h_reregister_pmr(shca->ipz_hca_handle, e_fmr, 0,
 					      0, 0, e_pd->fw_pd, 0, &hipzout);
-		if (h_ret != H_SUCCESS) {
-			/*
-			 * should not happen, because length checked above,
-			 * FMRs are not shared and no MW bound to FMRs
-			 */
-			ehca_err(&shca->ib_device, "hipz_reregister_pmr failed "
-				 "(Rereg1), h_ret=%lx e_fmr=%p hca_hndl=%lx "
-				 "mr_hndl=%lx lkey=%x lkey_out=%x",
-				 h_ret, e_fmr, shca->ipz_hca_handle.handle,
-				 e_fmr->ipz_mr_handle.handle,
-				 e_fmr->ib.ib_fmr.lkey, hipzout.lkey);
-			rereg_3_hcall = 1;
-		} else {
+		if (h_ret == H_SUCCESS) {
 			/* successful reregistration */
 			e_fmr->start = NULL;
 			e_fmr->size = 0;
 			tmp_lkey = hipzout.lkey;
 			tmp_rkey = hipzout.rkey;
+			return 0;
 		}
+		/*
+		 * should not happen, because length checked above,
+		 * FMRs are not shared and no MW bound to FMRs
+		 */
+		ehca_err(&shca->ib_device, "hipz_reregister_pmr failed "
+			 "(Rereg1), h_ret=%li e_fmr=%p hca_hndl=%lx "
+			 "mr_hndl=%lx lkey=%x lkey_out=%x",
+			 h_ret, e_fmr, shca->ipz_hca_handle.handle,
+			 e_fmr->ipz_mr_handle.handle,
+			 e_fmr->ib.ib_fmr.lkey, hipzout.lkey);
+		/* try free and rereg */
 	}
 
-	if (rereg_3_hcall) {
-		struct ehca_mr save_mr;
+	/* first free old FMR */
+	h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
+	if (h_ret != H_SUCCESS) {
+		ehca_err(&shca->ib_device, "hipz_free_mr failed, "
+			 "h_ret=%li e_fmr=%p hca_hndl=%lx mr_hndl=%lx "
+			 "lkey=%x",
+			 h_ret, e_fmr, shca->ipz_hca_handle.handle,
+			 e_fmr->ipz_mr_handle.handle,
+			 e_fmr->ib.ib_fmr.lkey);
+		ret = ehca2ib_return_code(h_ret);
+		goto ehca_unmap_one_fmr_exit0;
+	}
+	/* clean ehca_mr_t, without changing lock */
+	save_fmr = *e_fmr;
+	ehca_mr_deletenew(e_fmr);
 
-		/* first free old FMR */
-		h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
-		if (h_ret != H_SUCCESS) {
-			ehca_err(&shca->ib_device, "hipz_free_mr failed, "
-				 "h_ret=%lx e_fmr=%p hca_hndl=%lx mr_hndl=%lx "
-				 "lkey=%x",
-				 h_ret, e_fmr, shca->ipz_hca_handle.handle,
-				 e_fmr->ipz_mr_handle.handle,
-				 e_fmr->ib.ib_fmr.lkey);
-			ret = ehca_mrmw_map_hrc_free_mr(h_ret);
-			goto ehca_unmap_one_fmr_exit0;
-		}
-		/* clean ehca_mr_t, without changing lock */
-		save_fmr = *e_fmr;
-		ehca_mr_deletenew(e_fmr);
+	/* set some MR values */
+	e_fmr->flags = save_fmr.flags;
+	e_fmr->hwpage_size = save_fmr.hwpage_size;
+	e_fmr->fmr_page_size = save_fmr.fmr_page_size;
+	e_fmr->fmr_max_pages = save_fmr.fmr_max_pages;
+	e_fmr->fmr_max_maps = save_fmr.fmr_max_maps;
+	e_fmr->fmr_map_cnt = save_fmr.fmr_map_cnt;
+	e_fmr->acl = save_fmr.acl;
 
-		/* set some MR values */
-		e_fmr->flags = save_fmr.flags;
-		e_fmr->fmr_page_size = save_fmr.fmr_page_size;
-		e_fmr->fmr_max_pages = save_fmr.fmr_max_pages;
-		e_fmr->fmr_max_maps = save_fmr.fmr_max_maps;
-		e_fmr->fmr_map_cnt = save_fmr.fmr_map_cnt;
-		e_fmr->acl = save_fmr.acl;
-
-		pginfo.type      = EHCA_MR_PGI_FMR;
-		pginfo.num_pages = 0;
-		pginfo.num_4k    = 0;
-		ret = ehca_reg_mr(shca, e_fmr, NULL,
-				  (e_fmr->fmr_max_pages * e_fmr->fmr_page_size),
-				  e_fmr->acl, e_pd, &pginfo, &tmp_lkey,
-				  &tmp_rkey);
-		if (ret) {
-			u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr;
-			memcpy(&e_fmr->flags, &(save_mr.flags),
-			       sizeof(struct ehca_mr) - offset);
-			goto ehca_unmap_one_fmr_exit0;
-		}
+	memset(&pginfo, 0, sizeof(pginfo));
+	pginfo.type = EHCA_MR_PGI_FMR;
+	ret = ehca_reg_mr(shca, e_fmr, NULL,
+			  (e_fmr->fmr_max_pages * e_fmr->fmr_page_size),
+			  e_fmr->acl, e_pd, &pginfo, &tmp_lkey,
+			  &tmp_rkey);
+	if (ret) {
+		u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr;
+		memcpy(&e_fmr->flags, &(save_mr.flags),
+		       sizeof(struct ehca_mr) - offset);
 	}
 
 ehca_unmap_one_fmr_exit0:
 	if (ret)
-		ehca_err(&shca->ib_device, "ret=%x tmp_lkey=%x tmp_rkey=%x "
-			 "fmr_max_pages=%x rereg_1_hcall=%x rereg_3_hcall=%x",
-			 ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages,
-			 rereg_1_hcall, rereg_3_hcall);
+		ehca_err(&shca->ib_device, "ret=%i tmp_lkey=%x tmp_rkey=%x "
+			 "fmr_max_pages=%x",
+			 ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages);
 	return ret;
 } /* end ehca_unmap_one_fmr() */
 
@@ -1403,31 +1477,32 @@
 	int ret = 0;
 	u64 h_ret;
 	u32 hipz_acl;
-	struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+	struct ehca_mr_hipzout_parms hipzout;
 
 	ehca_mrmw_map_acl(acl, &hipz_acl);
-	ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+	ehca_mrmw_set_pgsize_hipz_acl(e_origmr->hwpage_size, &hipz_acl);
 
 	h_ret = hipz_h_register_smr(shca->ipz_hca_handle, e_newmr, e_origmr,
 				    (u64)iova_start, hipz_acl, e_pd->fw_pd,
 				    &hipzout);
 	if (h_ret != H_SUCCESS) {
-		ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lx "
+		ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%li "
 			 "shca=%p e_origmr=%p e_newmr=%p iova_start=%p acl=%x "
 			 "e_pd=%p hca_hndl=%lx mr_hndl=%lx lkey=%x",
 			 h_ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd,
 			 shca->ipz_hca_handle.handle,
 			 e_origmr->ipz_mr_handle.handle,
 			 e_origmr->ib.ib_mr.lkey);
-		ret = ehca_mrmw_map_hrc_reg_smr(h_ret);
+		ret = ehca2ib_return_code(h_ret);
 		goto ehca_reg_smr_exit0;
 	}
 	/* successful registration */
-	e_newmr->num_pages     = e_origmr->num_pages;
-	e_newmr->num_4k        = e_origmr->num_4k;
-	e_newmr->start         = iova_start;
-	e_newmr->size          = e_origmr->size;
-	e_newmr->acl           = acl;
+	e_newmr->num_kpages = e_origmr->num_kpages;
+	e_newmr->num_hwpages = e_origmr->num_hwpages;
+	e_newmr->hwpage_size   = e_origmr->hwpage_size;
+	e_newmr->start = iova_start;
+	e_newmr->size = e_origmr->size;
+	e_newmr->acl = acl;
 	e_newmr->ipz_mr_handle = hipzout.handle;
 	*lkey = hipzout.lkey;
 	*rkey = hipzout.rkey;
@@ -1435,7 +1510,7 @@
 
 ehca_reg_smr_exit0:
 	if (ret)
-		ehca_err(&shca->ib_device, "ret=%x shca=%p e_origmr=%p "
+		ehca_err(&shca->ib_device, "ret=%i shca=%p e_origmr=%p "
 			 "e_newmr=%p iova_start=%p acl=%x e_pd=%p",
 			 ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd);
 	return ret;
@@ -1453,10 +1528,11 @@
 	struct ehca_mr *e_mr;
 	u64 *iova_start;
 	u64 size_maxmr;
-	struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+	struct ehca_mr_pginfo pginfo;
 	struct ib_phys_buf ib_pbuf;
-	u32 num_pages_mr;
-	u32 num_pages_4k; /* 4k portion "pages" */
+	u32 num_kpages;
+	u32 num_hwpages;
+	u64 hw_pgsize;
 
 	e_mr = ehca_mr_new();
 	if (!e_mr) {
@@ -1468,28 +1544,31 @@
 
 	/* register internal max-MR on HCA */
 	size_maxmr = (u64)high_memory - PAGE_OFFSET;
-	iova_start = (u64*)KERNELBASE;
+	iova_start = (u64 *)KERNELBASE;
 	ib_pbuf.addr = 0;
 	ib_pbuf.size = size_maxmr;
-	num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size_maxmr +
-			 PAGE_SIZE - 1) / PAGE_SIZE);
-	num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size_maxmr +
-			 EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
+	num_kpages = NUM_CHUNKS(((u64)iova_start % PAGE_SIZE) + size_maxmr,
+				PAGE_SIZE);
+	hw_pgsize = ehca_get_max_hwpage_size(shca);
+	num_hwpages = NUM_CHUNKS(((u64)iova_start % hw_pgsize) + size_maxmr,
+				 hw_pgsize);
 
-	pginfo.type           = EHCA_MR_PGI_PHYS;
-	pginfo.num_pages      = num_pages_mr;
-	pginfo.num_4k         = num_pages_4k;
-	pginfo.num_phys_buf   = 1;
-	pginfo.phys_buf_array = &ib_pbuf;
+	memset(&pginfo, 0, sizeof(pginfo));
+	pginfo.type = EHCA_MR_PGI_PHYS;
+	pginfo.num_kpages = num_kpages;
+	pginfo.num_hwpages = num_hwpages;
+	pginfo.hwpage_size = hw_pgsize;
+	pginfo.u.phy.num_phys_buf = 1;
+	pginfo.u.phy.phys_buf_array = &ib_pbuf;
 
 	ret = ehca_reg_mr(shca, e_mr, iova_start, size_maxmr, 0, e_pd,
 			  &pginfo, &e_mr->ib.ib_mr.lkey,
 			  &e_mr->ib.ib_mr.rkey);
 	if (ret) {
 		ehca_err(&shca->ib_device, "reg of internal max MR failed, "
-			 "e_mr=%p iova_start=%p size_maxmr=%lx num_pages_mr=%x "
-			 "num_pages_4k=%x", e_mr, iova_start, size_maxmr,
-			 num_pages_mr, num_pages_4k);
+			 "e_mr=%p iova_start=%p size_maxmr=%lx num_kpages=%x "
+			 "num_hwpages=%x", e_mr, iova_start, size_maxmr,
+			 num_kpages, num_hwpages);
 		goto ehca_reg_internal_maxmr_exit1;
 	}
 
@@ -1506,7 +1585,7 @@
 	ehca_mr_delete(e_mr);
 ehca_reg_internal_maxmr_exit0:
 	if (ret)
-		ehca_err(&shca->ib_device, "ret=%x shca=%p e_pd=%p e_maxmr=%p",
+		ehca_err(&shca->ib_device, "ret=%i shca=%p e_pd=%p e_maxmr=%p",
 			 ret, shca, e_pd, e_maxmr);
 	return ret;
 } /* end ehca_reg_internal_maxmr() */
@@ -1524,28 +1603,29 @@
 	u64 h_ret;
 	struct ehca_mr *e_origmr = shca->maxmr;
 	u32 hipz_acl;
-	struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+	struct ehca_mr_hipzout_parms hipzout;
 
 	ehca_mrmw_map_acl(acl, &hipz_acl);
-	ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+	ehca_mrmw_set_pgsize_hipz_acl(e_origmr->hwpage_size, &hipz_acl);
 
 	h_ret = hipz_h_register_smr(shca->ipz_hca_handle, e_newmr, e_origmr,
 				    (u64)iova_start, hipz_acl, e_pd->fw_pd,
 				    &hipzout);
 	if (h_ret != H_SUCCESS) {
-		ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lx "
+		ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%li "
 			 "e_origmr=%p hca_hndl=%lx mr_hndl=%lx lkey=%x",
 			 h_ret, e_origmr, shca->ipz_hca_handle.handle,
 			 e_origmr->ipz_mr_handle.handle,
 			 e_origmr->ib.ib_mr.lkey);
-		return ehca_mrmw_map_hrc_reg_smr(h_ret);
+		return ehca2ib_return_code(h_ret);
 	}
 	/* successful registration */
-	e_newmr->num_pages     = e_origmr->num_pages;
-	e_newmr->num_4k        = e_origmr->num_4k;
-	e_newmr->start         = iova_start;
-	e_newmr->size          = e_origmr->size;
-	e_newmr->acl           = acl;
+	e_newmr->num_kpages = e_origmr->num_kpages;
+	e_newmr->num_hwpages = e_origmr->num_hwpages;
+	e_newmr->hwpage_size = e_origmr->hwpage_size;
+	e_newmr->start = iova_start;
+	e_newmr->size = e_origmr->size;
+	e_newmr->acl = acl;
 	e_newmr->ipz_mr_handle = hipzout.handle;
 	*lkey = hipzout.lkey;
 	*rkey = hipzout.rkey;
@@ -1573,7 +1653,7 @@
 	ret = ehca_dereg_mr(&e_maxmr->ib.ib_mr);
 	if (ret) {
 		ehca_err(&shca->ib_device, "dereg internal max-MR failed, "
-			 "ret=%x e_maxmr=%p shca=%p lkey=%x",
+			 "ret=%i e_maxmr=%p shca=%p lkey=%x",
 			 ret, e_maxmr, shca, e_maxmr->ib.ib_mr.lkey);
 		shca->maxmr = e_maxmr;
 		goto ehca_dereg_internal_maxmr_exit0;
@@ -1583,7 +1663,7 @@
 
 ehca_dereg_internal_maxmr_exit0:
 	if (ret)
-		ehca_err(&shca->ib_device, "ret=%x shca=%p shca->maxmr=%p",
+		ehca_err(&shca->ib_device, "ret=%i shca=%p shca->maxmr=%p",
 			 ret, shca, shca->maxmr);
 	return ret;
 } /* end ehca_dereg_internal_maxmr() */
@@ -1677,302 +1757,355 @@
 
 /*----------------------------------------------------------------------*/
 
+/* PAGE_SIZE >= pginfo->hwpage_size */
+static int ehca_set_pagebuf_user1(struct ehca_mr_pginfo *pginfo,
+				  u32 number,
+				  u64 *kpage)
+{
+	int ret = 0;
+	struct ib_umem_chunk *prev_chunk;
+	struct ib_umem_chunk *chunk;
+	u64 pgaddr;
+	u32 i = 0;
+	u32 j = 0;
+	int hwpages_per_kpage = PAGE_SIZE / pginfo->hwpage_size;
+
+	/* loop over desired chunk entries */
+	chunk      = pginfo->u.usr.next_chunk;
+	prev_chunk = pginfo->u.usr.next_chunk;
+	list_for_each_entry_continue(
+		chunk, (&(pginfo->u.usr.region->chunk_list)), list) {
+		for (i = pginfo->u.usr.next_nmap; i < chunk->nmap; ) {
+			pgaddr = page_to_pfn(chunk->page_list[i].page)
+				<< PAGE_SHIFT ;
+			*kpage = phys_to_abs(pgaddr +
+					     (pginfo->next_hwpage *
+					      pginfo->hwpage_size));
+			if ( !(*kpage) ) {
+				ehca_gen_err("pgaddr=%lx "
+					     "chunk->page_list[i]=%lx "
+					     "i=%x next_hwpage=%lx",
+					     pgaddr, (u64)sg_dma_address(
+						     &chunk->page_list[i]),
+					     i, pginfo->next_hwpage);
+				return -EFAULT;
+			}
+			(pginfo->hwpage_cnt)++;
+			(pginfo->next_hwpage)++;
+			kpage++;
+			if (pginfo->next_hwpage % hwpages_per_kpage == 0) {
+				(pginfo->kpage_cnt)++;
+				(pginfo->u.usr.next_nmap)++;
+				pginfo->next_hwpage = 0;
+				i++;
+			}
+			j++;
+			if (j >= number) break;
+		}
+		if ((pginfo->u.usr.next_nmap >= chunk->nmap) &&
+		    (j >= number)) {
+			pginfo->u.usr.next_nmap = 0;
+			prev_chunk = chunk;
+			break;
+		} else if (pginfo->u.usr.next_nmap >= chunk->nmap) {
+			pginfo->u.usr.next_nmap = 0;
+			prev_chunk = chunk;
+		} else if (j >= number)
+			break;
+		else
+			prev_chunk = chunk;
+	}
+	pginfo->u.usr.next_chunk =
+		list_prepare_entry(prev_chunk,
+				   (&(pginfo->u.usr.region->chunk_list)),
+				   list);
+	return ret;
+}
+
+/*
+ * check given pages for contiguous layout
+ * last page addr is returned in prev_pgaddr for further check
+ */
+static int ehca_check_kpages_per_ate(struct scatterlist *page_list,
+				     int start_idx, int end_idx,
+				     u64 *prev_pgaddr)
+{
+	int t;
+	for (t = start_idx; t <= end_idx; t++) {
+		u64 pgaddr = page_to_pfn(page_list[t].page) << PAGE_SHIFT;
+		ehca_gen_dbg("chunk_page=%lx value=%016lx", pgaddr,
+			     *(u64 *)abs_to_virt(phys_to_abs(pgaddr)));
+		if (pgaddr - PAGE_SIZE != *prev_pgaddr) {
+			ehca_gen_err("uncontiguous page found pgaddr=%lx "
+				     "prev_pgaddr=%lx page_list_i=%x",
+				     pgaddr, *prev_pgaddr, t);
+			return -EINVAL;
+		}
+		*prev_pgaddr = pgaddr;
+	}
+	return 0;
+}
+
+/* PAGE_SIZE < pginfo->hwpage_size */
+static int ehca_set_pagebuf_user2(struct ehca_mr_pginfo *pginfo,
+				  u32 number,
+				  u64 *kpage)
+{
+	int ret = 0;
+	struct ib_umem_chunk *prev_chunk;
+	struct ib_umem_chunk *chunk;
+	u64 pgaddr, prev_pgaddr;
+	u32 i = 0;
+	u32 j = 0;
+	int kpages_per_hwpage = pginfo->hwpage_size / PAGE_SIZE;
+	int nr_kpages = kpages_per_hwpage;
+
+	/* loop over desired chunk entries */
+	chunk      = pginfo->u.usr.next_chunk;
+	prev_chunk = pginfo->u.usr.next_chunk;
+	list_for_each_entry_continue(
+		chunk, (&(pginfo->u.usr.region->chunk_list)), list) {
+		for (i = pginfo->u.usr.next_nmap; i < chunk->nmap; ) {
+			if (nr_kpages == kpages_per_hwpage) {
+				pgaddr = ( page_to_pfn(chunk->page_list[i].page)
+					   << PAGE_SHIFT );
+				*kpage = phys_to_abs(pgaddr);
+				if ( !(*kpage) ) {
+					ehca_gen_err("pgaddr=%lx i=%x",
+						     pgaddr, i);
+					ret = -EFAULT;
+					return ret;
+				}
+				/*
+				 * The first page in a hwpage must be aligned;
+				 * the first MR page is exempt from this rule.
+				 */
+				if (pgaddr & (pginfo->hwpage_size - 1)) {
+					if (pginfo->hwpage_cnt) {
+						ehca_gen_err(
+							"invalid alignment "
+							"pgaddr=%lx i=%x "
+							"mr_pgsize=%lx",
+							pgaddr, i,
+							pginfo->hwpage_size);
+						ret = -EFAULT;
+						return ret;
+					}
+					/* first MR page */
+					pginfo->kpage_cnt =
+						(pgaddr &
+						 (pginfo->hwpage_size - 1)) >>
+						PAGE_SHIFT;
+					nr_kpages -= pginfo->kpage_cnt;
+					*kpage = phys_to_abs(
+						pgaddr &
+						~(pginfo->hwpage_size - 1));
+				}
+				ehca_gen_dbg("kpage=%lx chunk_page=%lx "
+					     "value=%016lx", *kpage, pgaddr,
+					     *(u64 *)abs_to_virt(
+						     phys_to_abs(pgaddr)));
+				prev_pgaddr = pgaddr;
+				i++;
+				pginfo->kpage_cnt++;
+				pginfo->u.usr.next_nmap++;
+				nr_kpages--;
+				if (!nr_kpages)
+					goto next_kpage;
+				continue;
+			}
+			if (i + nr_kpages > chunk->nmap) {
+				ret = ehca_check_kpages_per_ate(
+					chunk->page_list, i,
+					chunk->nmap - 1, &prev_pgaddr);
+				if (ret) return ret;
+				pginfo->kpage_cnt += chunk->nmap - i;
+				pginfo->u.usr.next_nmap += chunk->nmap - i;
+				nr_kpages -= chunk->nmap - i;
+				break;
+			}
+
+			ret = ehca_check_kpages_per_ate(chunk->page_list, i,
+							i + nr_kpages - 1,
+							&prev_pgaddr);
+			if (ret) return ret;
+			i += nr_kpages;
+			pginfo->kpage_cnt += nr_kpages;
+			pginfo->u.usr.next_nmap += nr_kpages;
+next_kpage:
+			nr_kpages = kpages_per_hwpage;
+			(pginfo->hwpage_cnt)++;
+			kpage++;
+			j++;
+			if (j >= number) break;
+		}
+		if ((pginfo->u.usr.next_nmap >= chunk->nmap) &&
+		    (j >= number)) {
+			pginfo->u.usr.next_nmap = 0;
+			prev_chunk = chunk;
+			break;
+		} else if (pginfo->u.usr.next_nmap >= chunk->nmap) {
+			pginfo->u.usr.next_nmap = 0;
+			prev_chunk = chunk;
+		} else if (j >= number)
+			break;
+		else
+			prev_chunk = chunk;
+	}
+	pginfo->u.usr.next_chunk =
+		list_prepare_entry(prev_chunk,
+				   (&(pginfo->u.usr.region->chunk_list)),
+				   list);
+	return ret;
+}
+
+int ehca_set_pagebuf_phys(struct ehca_mr_pginfo *pginfo,
+			  u32 number,
+			  u64 *kpage)
+{
+	int ret = 0;
+	struct ib_phys_buf *pbuf;
+	u64 num_hw, offs_hw;
+	u32 i = 0;
+
+	/* loop over desired phys_buf_array entries */
+	while (i < number) {
+		pbuf   = pginfo->u.phy.phys_buf_array + pginfo->u.phy.next_buf;
+		num_hw  = NUM_CHUNKS((pbuf->addr % pginfo->hwpage_size) +
+				     pbuf->size, pginfo->hwpage_size);
+		offs_hw = (pbuf->addr & ~(pginfo->hwpage_size - 1)) /
+			pginfo->hwpage_size;
+		while (pginfo->next_hwpage < offs_hw + num_hw) {
+			/* sanity check */
+			if ((pginfo->kpage_cnt >= pginfo->num_kpages) ||
+			    (pginfo->hwpage_cnt >= pginfo->num_hwpages)) {
+				ehca_gen_err("kpage_cnt >= num_kpages, "
+					     "kpage_cnt=%lx num_kpages=%lx "
+					     "hwpage_cnt=%lx "
+					     "num_hwpages=%lx i=%x",
+					     pginfo->kpage_cnt,
+					     pginfo->num_kpages,
+					     pginfo->hwpage_cnt,
+					     pginfo->num_hwpages, i);
+				return -EFAULT;
+			}
+			*kpage = phys_to_abs(
+				(pbuf->addr & ~(pginfo->hwpage_size - 1)) +
+				(pginfo->next_hwpage * pginfo->hwpage_size));
+			if ( !(*kpage) && pbuf->addr ) {
+				ehca_gen_err("pbuf->addr=%lx pbuf->size=%lx "
+					     "next_hwpage=%lx", pbuf->addr,
+					     pbuf->size, pginfo->next_hwpage);
+				return -EFAULT;
+			}
+			(pginfo->hwpage_cnt)++;
+			(pginfo->next_hwpage)++;
+			if (PAGE_SIZE >= pginfo->hwpage_size) {
+				if (pginfo->next_hwpage %
+				    (PAGE_SIZE / pginfo->hwpage_size) == 0)
+					(pginfo->kpage_cnt)++;
+			} else
+				pginfo->kpage_cnt += pginfo->hwpage_size /
+					PAGE_SIZE;
+			kpage++;
+			i++;
+			if (i >= number) break;
+		}
+		if (pginfo->next_hwpage >= offs_hw + num_hw) {
+			(pginfo->u.phy.next_buf)++;
+			pginfo->next_hwpage = 0;
+		}
+	}
+	return ret;
+}
+
+int ehca_set_pagebuf_fmr(struct ehca_mr_pginfo *pginfo,
+			 u32 number,
+			 u64 *kpage)
+{
+	int ret = 0;
+	u64 *fmrlist;
+	u32 i;
+
+	/* loop over desired page_list entries */
+	fmrlist = pginfo->u.fmr.page_list + pginfo->u.fmr.next_listelem;
+	for (i = 0; i < number; i++) {
+		*kpage = phys_to_abs((*fmrlist & ~(pginfo->hwpage_size - 1)) +
+				     pginfo->next_hwpage * pginfo->hwpage_size);
+		if ( !(*kpage) ) {
+			ehca_gen_err("*fmrlist=%lx fmrlist=%p "
+				     "next_listelem=%lx next_hwpage=%lx",
+				     *fmrlist, fmrlist,
+				     pginfo->u.fmr.next_listelem,
+				     pginfo->next_hwpage);
+			return -EFAULT;
+		}
+		(pginfo->hwpage_cnt)++;
+		if (pginfo->u.fmr.fmr_pgsize >= pginfo->hwpage_size) {
+			if (pginfo->next_hwpage %
+			    (pginfo->u.fmr.fmr_pgsize /
+			     pginfo->hwpage_size) == 0) {
+				(pginfo->kpage_cnt)++;
+				(pginfo->u.fmr.next_listelem)++;
+				fmrlist++;
+				pginfo->next_hwpage = 0;
+			} else
+				(pginfo->next_hwpage)++;
+		} else {
+			unsigned int cnt_per_hwpage = pginfo->hwpage_size /
+				pginfo->u.fmr.fmr_pgsize;
+			unsigned int j;
+			u64 prev = *kpage;
+			/* check if adrs are contiguous */
+			for (j = 1; j < cnt_per_hwpage; j++) {
+				u64 p = phys_to_abs(fmrlist[j] &
+						    ~(pginfo->hwpage_size - 1));
+				if (prev + pginfo->u.fmr.fmr_pgsize != p) {
+					ehca_gen_err("uncontiguous fmr pages "
+						     "found prev=%lx p=%lx "
+						     "idx=%x", prev, p, i + j);
+					return -EINVAL;
+				}
+				prev = p;
+			}
+			pginfo->kpage_cnt += cnt_per_hwpage;
+			pginfo->u.fmr.next_listelem += cnt_per_hwpage;
+			fmrlist += cnt_per_hwpage;
+		}
+		kpage++;
+	}
+	return ret;
+}
+
 /* setup page buffer from page info */
-int ehca_set_pagebuf(struct ehca_mr *e_mr,
-		     struct ehca_mr_pginfo *pginfo,
+int ehca_set_pagebuf(struct ehca_mr_pginfo *pginfo,
 		     u32 number,
 		     u64 *kpage)
 {
-	int ret = 0;
-	struct ib_umem_chunk *prev_chunk;
-	struct ib_umem_chunk *chunk;
-	struct ib_phys_buf *pbuf;
-	u64 *fmrlist;
-	u64 num4k, pgaddr, offs4k;
-	u32 i = 0;
-	u32 j = 0;
+	int ret;
 
-	if (pginfo->type == EHCA_MR_PGI_PHYS) {
-		/* loop over desired phys_buf_array entries */
-		while (i < number) {
-			pbuf   = pginfo->phys_buf_array + pginfo->next_buf;
-			num4k  = ((pbuf->addr % EHCA_PAGESIZE) + pbuf->size +
-				  EHCA_PAGESIZE - 1) / EHCA_PAGESIZE;
-			offs4k = (pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
-			while (pginfo->next_4k < offs4k + num4k) {
-				/* sanity check */
-				if ((pginfo->page_cnt >= pginfo->num_pages) ||
-				    (pginfo->page_4k_cnt >= pginfo->num_4k)) {
-					ehca_gen_err("page_cnt >= num_pages, "
-						     "page_cnt=%lx "
-						     "num_pages=%lx "
-						     "page_4k_cnt=%lx "
-						     "num_4k=%lx i=%x",
-						     pginfo->page_cnt,
-						     pginfo->num_pages,
-						     pginfo->page_4k_cnt,
-						     pginfo->num_4k, i);
-					ret = -EFAULT;
-					goto ehca_set_pagebuf_exit0;
-				}
-				*kpage = phys_to_abs(
-					(pbuf->addr & EHCA_PAGEMASK)
-					+ (pginfo->next_4k * EHCA_PAGESIZE));
-				if ( !(*kpage) && pbuf->addr ) {
-					ehca_gen_err("pbuf->addr=%lx "
-						     "pbuf->size=%lx "
-						     "next_4k=%lx", pbuf->addr,
-						     pbuf->size,
-						     pginfo->next_4k);
-					ret = -EFAULT;
-					goto ehca_set_pagebuf_exit0;
-				}
-				(pginfo->page_4k_cnt)++;
-				(pginfo->next_4k)++;
-				if (pginfo->next_4k %
-				    (PAGE_SIZE / EHCA_PAGESIZE) == 0)
-					(pginfo->page_cnt)++;
-				kpage++;
-				i++;
-				if (i >= number) break;
-			}
-			if (pginfo->next_4k >= offs4k + num4k) {
-				(pginfo->next_buf)++;
-				pginfo->next_4k = 0;
-			}
-		}
-	} else if (pginfo->type == EHCA_MR_PGI_USER) {
-		/* loop over desired chunk entries */
-		chunk      = pginfo->next_chunk;
-		prev_chunk = pginfo->next_chunk;
-		list_for_each_entry_continue(chunk,
-					     (&(pginfo->region->chunk_list)),
-					     list) {
-			for (i = pginfo->next_nmap; i < chunk->nmap; ) {
-				pgaddr = ( page_to_pfn(chunk->page_list[i].page)
-					   << PAGE_SHIFT );
-				*kpage = phys_to_abs(pgaddr +
-						     (pginfo->next_4k *
-						      EHCA_PAGESIZE));
-				if ( !(*kpage) ) {
-					ehca_gen_err("pgaddr=%lx "
-						     "chunk->page_list[i]=%lx "
-						     "i=%x next_4k=%lx mr=%p",
-						     pgaddr,
-						     (u64)sg_dma_address(
-							     &chunk->
-							     page_list[i]),
-						     i, pginfo->next_4k, e_mr);
-					ret = -EFAULT;
-					goto ehca_set_pagebuf_exit0;
-				}
-				(pginfo->page_4k_cnt)++;
-				(pginfo->next_4k)++;
-				kpage++;
-				if (pginfo->next_4k %
-				    (PAGE_SIZE / EHCA_PAGESIZE) == 0) {
-					(pginfo->page_cnt)++;
-					(pginfo->next_nmap)++;
-					pginfo->next_4k = 0;
-					i++;
-				}
-				j++;
-				if (j >= number) break;
-			}
-			if ((pginfo->next_nmap >= chunk->nmap) &&
-			    (j >= number)) {
-				pginfo->next_nmap = 0;
-				prev_chunk = chunk;
-				break;
-			} else if (pginfo->next_nmap >= chunk->nmap) {
-				pginfo->next_nmap = 0;
-				prev_chunk = chunk;
-			} else if (j >= number)
-				break;
-			else
-				prev_chunk = chunk;
-		}
-		pginfo->next_chunk =
-			list_prepare_entry(prev_chunk,
-					   (&(pginfo->region->chunk_list)),
-					   list);
-	} else if (pginfo->type == EHCA_MR_PGI_FMR) {
-		/* loop over desired page_list entries */
-		fmrlist = pginfo->page_list + pginfo->next_listelem;
-		for (i = 0; i < number; i++) {
-			*kpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) +
-					     pginfo->next_4k * EHCA_PAGESIZE);
-			if ( !(*kpage) ) {
-				ehca_gen_err("*fmrlist=%lx fmrlist=%p "
-					     "next_listelem=%lx next_4k=%lx",
-					     *fmrlist, fmrlist,
-					     pginfo->next_listelem,
-					     pginfo->next_4k);
-				ret = -EFAULT;
-				goto ehca_set_pagebuf_exit0;
-			}
-			(pginfo->page_4k_cnt)++;
-			(pginfo->next_4k)++;
-			kpage++;
-			if (pginfo->next_4k %
-			    (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) {
-				(pginfo->page_cnt)++;
-				(pginfo->next_listelem)++;
-				fmrlist++;
-				pginfo->next_4k = 0;
-			}
-		}
-	} else {
+	switch (pginfo->type) {
+	case EHCA_MR_PGI_PHYS:
+		ret = ehca_set_pagebuf_phys(pginfo, number, kpage);
+		break;
+	case EHCA_MR_PGI_USER:
+		ret = PAGE_SIZE >= pginfo->hwpage_size ?
+			ehca_set_pagebuf_user1(pginfo, number, kpage) :
+			ehca_set_pagebuf_user2(pginfo, number, kpage);
+		break;
+	case EHCA_MR_PGI_FMR:
+		ret = ehca_set_pagebuf_fmr(pginfo, number, kpage);
+		break;
+	default:
 		ehca_gen_err("bad pginfo->type=%x", pginfo->type);
 		ret = -EFAULT;
-		goto ehca_set_pagebuf_exit0;
+		break;
 	}
-
-ehca_set_pagebuf_exit0:
-	if (ret)
-		ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
-			     "num_4k=%lx next_buf=%lx next_4k=%lx number=%x "
-			     "kpage=%p page_cnt=%lx page_4k_cnt=%lx i=%x "
-			     "next_listelem=%lx region=%p next_chunk=%p "
-			     "next_nmap=%lx", ret, e_mr, pginfo, pginfo->type,
-			     pginfo->num_pages, pginfo->num_4k,
-			     pginfo->next_buf, pginfo->next_4k, number, kpage,
-			     pginfo->page_cnt, pginfo->page_4k_cnt, i,
-			     pginfo->next_listelem, pginfo->region,
-			     pginfo->next_chunk, pginfo->next_nmap);
 	return ret;
 } /* end ehca_set_pagebuf() */
 
 /*----------------------------------------------------------------------*/
 
-/* setup 1 page from page info page buffer */
-int ehca_set_pagebuf_1(struct ehca_mr *e_mr,
-		       struct ehca_mr_pginfo *pginfo,
-		       u64 *rpage)
-{
-	int ret = 0;
-	struct ib_phys_buf *tmp_pbuf;
-	u64 *fmrlist;
-	struct ib_umem_chunk *chunk;
-	struct ib_umem_chunk *prev_chunk;
-	u64 pgaddr, num4k, offs4k;
-
-	if (pginfo->type == EHCA_MR_PGI_PHYS) {
-		/* sanity check */
-		if ((pginfo->page_cnt >= pginfo->num_pages) ||
-		    (pginfo->page_4k_cnt >= pginfo->num_4k)) {
-			ehca_gen_err("page_cnt >= num_pages, page_cnt=%lx "
-				     "num_pages=%lx page_4k_cnt=%lx num_4k=%lx",
-				     pginfo->page_cnt, pginfo->num_pages,
-				     pginfo->page_4k_cnt, pginfo->num_4k);
-			ret = -EFAULT;
-			goto ehca_set_pagebuf_1_exit0;
-		}
-		tmp_pbuf = pginfo->phys_buf_array + pginfo->next_buf;
-		num4k  = ((tmp_pbuf->addr % EHCA_PAGESIZE) + tmp_pbuf->size +
-			  EHCA_PAGESIZE - 1) / EHCA_PAGESIZE;
-		offs4k = (tmp_pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
-		*rpage = phys_to_abs((tmp_pbuf->addr & EHCA_PAGEMASK) +
-				     (pginfo->next_4k * EHCA_PAGESIZE));
-		if ( !(*rpage) && tmp_pbuf->addr ) {
-			ehca_gen_err("tmp_pbuf->addr=%lx"
-				     " tmp_pbuf->size=%lx next_4k=%lx",
-				     tmp_pbuf->addr, tmp_pbuf->size,
-				     pginfo->next_4k);
-			ret = -EFAULT;
-			goto ehca_set_pagebuf_1_exit0;
-		}
-		(pginfo->page_4k_cnt)++;
-		(pginfo->next_4k)++;
-		if (pginfo->next_4k % (PAGE_SIZE / EHCA_PAGESIZE) == 0)
-			(pginfo->page_cnt)++;
-		if (pginfo->next_4k >= offs4k + num4k) {
-			(pginfo->next_buf)++;
-			pginfo->next_4k = 0;
-		}
-	} else if (pginfo->type == EHCA_MR_PGI_USER) {
-		chunk      = pginfo->next_chunk;
-		prev_chunk = pginfo->next_chunk;
-		list_for_each_entry_continue(chunk,
-					     (&(pginfo->region->chunk_list)),
-					     list) {
-			pgaddr = ( page_to_pfn(chunk->page_list[
-						       pginfo->next_nmap].page)
-				   << PAGE_SHIFT);
-			*rpage = phys_to_abs(pgaddr +
-					     (pginfo->next_4k * EHCA_PAGESIZE));
-			if ( !(*rpage) ) {
-				ehca_gen_err("pgaddr=%lx chunk->page_list[]=%lx"
-					     " next_nmap=%lx next_4k=%lx mr=%p",
-					     pgaddr, (u64)sg_dma_address(
-						     &chunk->page_list[
-							     pginfo->
-							     next_nmap]),
-					     pginfo->next_nmap, pginfo->next_4k,
-					     e_mr);
-				ret = -EFAULT;
-				goto ehca_set_pagebuf_1_exit0;
-			}
-			(pginfo->page_4k_cnt)++;
-			(pginfo->next_4k)++;
-			if (pginfo->next_4k %
-			    (PAGE_SIZE / EHCA_PAGESIZE) == 0) {
-				(pginfo->page_cnt)++;
-				(pginfo->next_nmap)++;
-				pginfo->next_4k = 0;
-			}
-			if (pginfo->next_nmap >= chunk->nmap) {
-				pginfo->next_nmap = 0;
-				prev_chunk = chunk;
-			}
-			break;
-		}
-		pginfo->next_chunk =
-			list_prepare_entry(prev_chunk,
-					   (&(pginfo->region->chunk_list)),
-					   list);
-	} else if (pginfo->type == EHCA_MR_PGI_FMR) {
-		fmrlist = pginfo->page_list + pginfo->next_listelem;
-		*rpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) +
-				     pginfo->next_4k * EHCA_PAGESIZE);
-		if ( !(*rpage) ) {
-			ehca_gen_err("*fmrlist=%lx fmrlist=%p "
-				     "next_listelem=%lx next_4k=%lx",
-				     *fmrlist, fmrlist, pginfo->next_listelem,
-				     pginfo->next_4k);
-			ret = -EFAULT;
-			goto ehca_set_pagebuf_1_exit0;
-		}
-		(pginfo->page_4k_cnt)++;
-		(pginfo->next_4k)++;
-		if (pginfo->next_4k %
-		    (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) {
-			(pginfo->page_cnt)++;
-			(pginfo->next_listelem)++;
-			pginfo->next_4k = 0;
-		}
-	} else {
-		ehca_gen_err("bad pginfo->type=%x", pginfo->type);
-		ret = -EFAULT;
-		goto ehca_set_pagebuf_1_exit0;
-	}
-
-ehca_set_pagebuf_1_exit0:
-	if (ret)
-		ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
-			     "num_4k=%lx next_buf=%lx next_4k=%lx rpage=%p "
-			     "page_cnt=%lx page_4k_cnt=%lx next_listelem=%lx "
-			     "region=%p next_chunk=%p next_nmap=%lx", ret, e_mr,
-			     pginfo, pginfo->type, pginfo->num_pages,
-			     pginfo->num_4k, pginfo->next_buf, pginfo->next_4k,
-			     rpage, pginfo->page_cnt, pginfo->page_4k_cnt,
-			     pginfo->next_listelem, pginfo->region,
-			     pginfo->next_chunk, pginfo->next_nmap);
-	return ret;
-} /* end ehca_set_pagebuf_1() */
-
-/*----------------------------------------------------------------------*/
-
 /*
  * check MR if it is a max-MR, i.e. uses whole memory
  * in case it's a max-MR 1 is returned, else 0
@@ -1982,7 +2115,7 @@
 {
 	/* a MR is treated as max-MR only if it fits following: */
 	if ((size == ((u64)high_memory - PAGE_OFFSET)) &&
-	    (iova_start == (void*)KERNELBASE)) {
+	    (iova_start == (void *)KERNELBASE)) {
 		ehca_gen_dbg("this is a max-MR");
 		return 1;
 	} else
@@ -2011,9 +2144,9 @@
 /*----------------------------------------------------------------------*/
 
 /* sets page size in hipz access control for MR/MW. */
-void ehca_mrmw_set_pgsize_hipz_acl(u32 *hipz_acl) /*INOUT*/
+void ehca_mrmw_set_pgsize_hipz_acl(u32 pgsize, u32 *hipz_acl) /*INOUT*/
 {
-	return; /* HCA supports only 4k */
+	*hipz_acl |= (ehca_encode_hwpage_size(pgsize) << 24);
 } /* end ehca_mrmw_set_pgsize_hipz_acl() */
 
 /*----------------------------------------------------------------------*/
@@ -2042,196 +2175,23 @@
 /*----------------------------------------------------------------------*/
 
 /*
- * map HIPZ rc to IB retcodes for MR/MW allocations
- * Used for hipz_mr_reg_alloc and hipz_mw_alloc.
- */
-int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc)
-{
-	switch (hipz_rc) {
-	case H_SUCCESS:	             /* successful completion */
-		return 0;
-	case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
-	case H_CONSTRAINED:          /* resource constraint */
-	case H_NO_MEM:
-		return -ENOMEM;
-	case H_BUSY:                 /* long busy */
-		return -EBUSY;
-	default:
-		return -EINVAL;
-	}
-} /* end ehca_mrmw_map_hrc_alloc() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for MR register rpage
- * Used for hipz_h_register_rpage_mr at registering last page
- */
-int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc)
-{
-	switch (hipz_rc) {
-	case H_SUCCESS:         /* registration complete */
-		return 0;
-	case H_PAGE_REGISTERED:	/* page registered */
-	case H_ADAPTER_PARM:    /* invalid adapter handle */
-	case H_RH_PARM:         /* invalid resource handle */
-/*	case H_QT_PARM:            invalid queue type */
-	case H_PARAMETER:       /*
-				 * invalid logical address,
-				 * or count zero or greater 512
-				 */
-	case H_TABLE_FULL:      /* page table full */
-	case H_HARDWARE:        /* HCA not operational */
-		return -EINVAL;
-	case H_BUSY:            /* long busy */
-		return -EBUSY;
-	default:
-		return -EINVAL;
-	}
-} /* end ehca_mrmw_map_hrc_rrpg_last() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for MR register rpage
- * Used for hipz_h_register_rpage_mr at registering one page, but not last page
- */
-int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc)
-{
-	switch (hipz_rc) {
-	case H_PAGE_REGISTERED:	/* page registered */
-		return 0;
-	case H_SUCCESS:         /* registration complete */
-	case H_ADAPTER_PARM:    /* invalid adapter handle */
-	case H_RH_PARM:         /* invalid resource handle */
-/*	case H_QT_PARM:            invalid queue type */
-	case H_PARAMETER:       /*
-				 * invalid logical address,
-				 * or count zero or greater 512
-				 */
-	case H_TABLE_FULL:      /* page table full */
-	case H_HARDWARE:        /* HCA not operational */
-		return -EINVAL;
-	case H_BUSY:            /* long busy */
-		return -EBUSY;
-	default:
-		return -EINVAL;
-	}
-} /* end ehca_mrmw_map_hrc_rrpg_notlast() */
-
-/*----------------------------------------------------------------------*/
-
-/* map HIPZ rc to IB retcodes for MR query. Used for hipz_mr_query. */
-int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc)
-{
-	switch (hipz_rc) {
-	case H_SUCCESS:	             /* successful completion */
-		return 0;
-	case H_ADAPTER_PARM:         /* invalid adapter handle */
-	case H_RH_PARM:              /* invalid resource handle */
-		return -EINVAL;
-	case H_BUSY:                 /* long busy */
-		return -EBUSY;
-	default:
-		return -EINVAL;
-	}
-} /* end ehca_mrmw_map_hrc_query_mr() */
-
-/*----------------------------------------------------------------------*/
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for freeing MR resource
- * Used for hipz_h_free_resource_mr
- */
-int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc)
-{
-	switch (hipz_rc) {
-	case H_SUCCESS:      /* resource freed */
-		return 0;
-	case H_ADAPTER_PARM: /* invalid adapter handle */
-	case H_RH_PARM:      /* invalid resource handle */
-	case H_R_STATE:      /* invalid resource state */
-	case H_HARDWARE:     /* HCA not operational */
-		return -EINVAL;
-	case H_RESOURCE:     /* Resource in use */
-	case H_BUSY:         /* long busy */
-		return -EBUSY;
-	default:
-		return -EINVAL;
-	}
-} /* end ehca_mrmw_map_hrc_free_mr() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for freeing MW resource
- * Used for hipz_h_free_resource_mw
- */
-int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc)
-{
-	switch (hipz_rc) {
-	case H_SUCCESS:	     /* resource freed */
-		return 0;
-	case H_ADAPTER_PARM: /* invalid adapter handle */
-	case H_RH_PARM:      /* invalid resource handle */
-	case H_R_STATE:      /* invalid resource state */
-	case H_HARDWARE:     /* HCA not operational */
-		return -EINVAL;
-	case H_RESOURCE:     /* Resource in use */
-	case H_BUSY:         /* long busy */
-		return -EBUSY;
-	default:
-		return -EINVAL;
-	}
-} /* end ehca_mrmw_map_hrc_free_mw() */
-
-/*----------------------------------------------------------------------*/
-
-/*
- * map HIPZ rc to IB retcodes for SMR registrations
- * Used for hipz_h_register_smr.
- */
-int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc)
-{
-	switch (hipz_rc) {
-	case H_SUCCESS:	             /* successful completion */
-		return 0;
-	case H_ADAPTER_PARM:         /* invalid adapter handle */
-	case H_RH_PARM:              /* invalid resource handle */
-	case H_MEM_PARM:             /* invalid MR virtual address */
-	case H_MEM_ACCESS_PARM:      /* invalid access controls */
-	case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
-		return -EINVAL;
-	case H_BUSY:                 /* long busy */
-		return -EBUSY;
-	default:
-		return -EINVAL;
-	}
-} /* end ehca_mrmw_map_hrc_reg_smr() */
-
-/*----------------------------------------------------------------------*/
-
-/*
  * MR destructor and constructor
  * used in Reregister MR verb, sets all fields in ehca_mr_t to 0,
  * except struct ib_mr and spinlock
  */
 void ehca_mr_deletenew(struct ehca_mr *mr)
 {
-	mr->flags         = 0;
-	mr->num_pages     = 0;
-	mr->num_4k        = 0;
-	mr->acl           = 0;
-	mr->start         = NULL;
+	mr->flags = 0;
+	mr->num_kpages = 0;
+	mr->num_hwpages = 0;
+	mr->acl = 0;
+	mr->start = NULL;
 	mr->fmr_page_size = 0;
 	mr->fmr_max_pages = 0;
-	mr->fmr_max_maps  = 0;
-	mr->fmr_map_cnt   = 0;
+	mr->fmr_max_maps = 0;
+	mr->fmr_map_cnt = 0;
 	memset(&mr->ipz_mr_handle, 0, sizeof(mr->ipz_mr_handle));
 	memset(&mr->galpas, 0, sizeof(mr->galpas));
-	mr->nr_of_pages   = 0;
-	mr->pagearray     = NULL;
 } /* end ehca_mr_deletenew() */
 
 int ehca_init_mrmw_cache(void)
@@ -2239,13 +2199,13 @@
 	mr_cache = kmem_cache_create("ehca_cache_mr",
 				     sizeof(struct ehca_mr), 0,
 				     SLAB_HWCACHE_ALIGN,
-				     NULL, NULL);
+				     NULL);
 	if (!mr_cache)
 		return -ENOMEM;
 	mw_cache = kmem_cache_create("ehca_cache_mw",
 				     sizeof(struct ehca_mw), 0,
 				     SLAB_HWCACHE_ALIGN,
-				     NULL, NULL);
+				     NULL);
 	if (!mw_cache) {
 		kmem_cache_destroy(mr_cache);
 		mr_cache = NULL;
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.h b/drivers/infiniband/hw/ehca/ehca_mrmw.h
index d936e40..bc8f4e3 100644
--- a/drivers/infiniband/hw/ehca/ehca_mrmw.h
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.h
@@ -101,40 +101,21 @@
 			     u64 *page_list,
 			     int list_len);
 
-int ehca_set_pagebuf(struct ehca_mr *e_mr,
-		     struct ehca_mr_pginfo *pginfo,
+int ehca_set_pagebuf(struct ehca_mr_pginfo *pginfo,
 		     u32 number,
 		     u64 *kpage);
 
-int ehca_set_pagebuf_1(struct ehca_mr *e_mr,
-		       struct ehca_mr_pginfo *pginfo,
-		       u64 *rpage);
-
 int ehca_mr_is_maxmr(u64 size,
 		     u64 *iova_start);
 
 void ehca_mrmw_map_acl(int ib_acl,
 		       u32 *hipz_acl);
 
-void ehca_mrmw_set_pgsize_hipz_acl(u32 *hipz_acl);
+void ehca_mrmw_set_pgsize_hipz_acl(u32 pgsize, u32 *hipz_acl);
 
 void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
 			       int *ib_acl);
 
-int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc);
-
-int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc);
-
 void ehca_mr_deletenew(struct ehca_mr *mr);
 
 #endif  /*_EHCA_MRMW_H_*/
diff --git a/drivers/infiniband/hw/ehca/ehca_pd.c b/drivers/infiniband/hw/ehca/ehca_pd.c
index 79d0591..43bcf08 100644
--- a/drivers/infiniband/hw/ehca/ehca_pd.c
+++ b/drivers/infiniband/hw/ehca/ehca_pd.c
@@ -49,6 +49,7 @@
 			    struct ib_ucontext *context, struct ib_udata *udata)
 {
 	struct ehca_pd *pd;
+	int i;
 
 	pd = kmem_cache_zalloc(pd_cache, GFP_KERNEL);
 	if (!pd) {
@@ -58,6 +59,11 @@
 	}
 
 	pd->ownpid = current->tgid;
+	for (i = 0; i < 2; i++) {
+		INIT_LIST_HEAD(&pd->free[i]);
+		INIT_LIST_HEAD(&pd->full[i]);
+	}
+	mutex_init(&pd->lock);
 
 	/*
 	 * Kernel PD: when device = -1, 0
@@ -81,6 +87,8 @@
 {
 	u32 cur_pid = current->tgid;
 	struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);
+	int i, leftovers = 0;
+	struct ipz_small_queue_page *page, *tmp;
 
 	if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
 	    my_pd->ownpid != cur_pid) {
@@ -89,8 +97,20 @@
 		return -EINVAL;
 	}
 
-	kmem_cache_free(pd_cache,
-			container_of(pd, struct ehca_pd, ib_pd));
+	for (i = 0; i < 2; i++) {
+		list_splice(&my_pd->full[i], &my_pd->free[i]);
+		list_for_each_entry_safe(page, tmp, &my_pd->free[i], list) {
+			leftovers = 1;
+			free_page(page->page);
+			kmem_cache_free(small_qp_cache, page);
+		}
+	}
+
+	if (leftovers)
+		ehca_warn(pd->device,
+			  "Some small queue pages were not freed");
+
+	kmem_cache_free(pd_cache, my_pd);
 
 	return 0;
 }
@@ -100,7 +120,7 @@
 	pd_cache = kmem_cache_create("ehca_cache_pd",
 				     sizeof(struct ehca_pd), 0,
 				     SLAB_HWCACHE_ALIGN,
-				     NULL, NULL);
+				     NULL);
 	if (!pd_cache)
 		return -ENOMEM;
 	return 0;
diff --git a/drivers/infiniband/hw/ehca/ehca_qes.h b/drivers/infiniband/hw/ehca/ehca_qes.h
index 8707d29..8188030 100644
--- a/drivers/infiniband/hw/ehca/ehca_qes.h
+++ b/drivers/infiniband/hw/ehca/ehca_qes.h
@@ -53,13 +53,13 @@
 	u32 length;
 };
 
-#define GRH_FLAG_MASK        EHCA_BMASK_IBM(7,7)
-#define GRH_IPVERSION_MASK   EHCA_BMASK_IBM(0,3)
-#define GRH_TCLASS_MASK      EHCA_BMASK_IBM(4,12)
-#define GRH_FLOWLABEL_MASK   EHCA_BMASK_IBM(13,31)
-#define GRH_PAYLEN_MASK      EHCA_BMASK_IBM(32,47)
-#define GRH_NEXTHEADER_MASK  EHCA_BMASK_IBM(48,55)
-#define GRH_HOPLIMIT_MASK    EHCA_BMASK_IBM(56,63)
+#define GRH_FLAG_MASK        EHCA_BMASK_IBM( 7,  7)
+#define GRH_IPVERSION_MASK   EHCA_BMASK_IBM( 0,  3)
+#define GRH_TCLASS_MASK      EHCA_BMASK_IBM( 4, 12)
+#define GRH_FLOWLABEL_MASK   EHCA_BMASK_IBM(13, 31)
+#define GRH_PAYLEN_MASK      EHCA_BMASK_IBM(32, 47)
+#define GRH_NEXTHEADER_MASK  EHCA_BMASK_IBM(48, 55)
+#define GRH_HOPLIMIT_MASK    EHCA_BMASK_IBM(56, 63)
 
 /*
  * Unreliable Datagram Address Vector Format
@@ -206,10 +206,10 @@
 
 };
 
-#define WC_SEND_RECEIVE EHCA_BMASK_IBM(0,0)
-#define WC_IMM_DATA     EHCA_BMASK_IBM(1,1)
-#define WC_GRH_PRESENT  EHCA_BMASK_IBM(2,2)
-#define WC_SE_BIT       EHCA_BMASK_IBM(3,3)
+#define WC_SEND_RECEIVE EHCA_BMASK_IBM(0, 0)
+#define WC_IMM_DATA     EHCA_BMASK_IBM(1, 1)
+#define WC_GRH_PRESENT  EHCA_BMASK_IBM(2, 2)
+#define WC_SE_BIT       EHCA_BMASK_IBM(3, 3)
 #define WC_STATUS_ERROR_BIT 0x80000000
 #define WC_STATUS_REMOTE_ERROR_FLAGS 0x0000F800
 #define WC_STATUS_PURGE_BIT 0x10
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index 7467125..e2bd62b 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -273,38 +273,44 @@
 	resp->queue_length = queue->queue_length;
 	resp->pagesize = queue->pagesize;
 	resp->toggle_state = queue->toggle_state;
-}
-
-static inline int ll_qp_msg_size(int nr_sge)
-{
-	return 128 << nr_sge;
+	resp->offset = queue->offset;
 }
 
 /*
  * init_qp_queue initializes/constructs r/squeue and registers queue pages.
  */
 static inline int init_qp_queue(struct ehca_shca *shca,
+				struct ehca_pd *pd,
 				struct ehca_qp *my_qp,
 				struct ipz_queue *queue,
 				int q_type,
 				u64 expected_hret,
-				int nr_q_pages,
-				int wqe_size,
-				int nr_sges)
+				struct ehca_alloc_queue_parms *parms,
+				int wqe_size)
 {
-	int ret, cnt, ipz_rc;
+	int ret, cnt, ipz_rc, nr_q_pages;
 	void *vpage;
 	u64 rpage, h_ret;
 	struct ib_device *ib_dev = &shca->ib_device;
 	struct ipz_adapter_handle ipz_hca_handle = shca->ipz_hca_handle;
 
-	if (!nr_q_pages)
+	if (!parms->queue_size)
 		return 0;
 
-	ipz_rc = ipz_queue_ctor(queue, nr_q_pages, EHCA_PAGESIZE,
-				wqe_size, nr_sges);
+	if (parms->is_small) {
+		nr_q_pages = 1;
+		ipz_rc = ipz_queue_ctor(pd, queue, nr_q_pages,
+					128 << parms->page_size,
+					wqe_size, parms->act_nr_sges, 1);
+	} else {
+		nr_q_pages = parms->queue_size;
+		ipz_rc = ipz_queue_ctor(pd, queue, nr_q_pages,
+					EHCA_PAGESIZE, wqe_size,
+					parms->act_nr_sges, 0);
+	}
+
 	if (!ipz_rc) {
-		ehca_err(ib_dev, "Cannot allocate page for queue. ipz_rc=%x",
+		ehca_err(ib_dev, "Cannot allocate page for queue. ipz_rc=%i",
 			 ipz_rc);
 		return -EBUSY;
 	}
@@ -323,12 +329,12 @@
 		h_ret = hipz_h_register_rpage_qp(ipz_hca_handle,
 						 my_qp->ipz_qp_handle,
 						 NULL, 0, q_type,
-						 rpage, 1,
+						 rpage, parms->is_small ? 0 : 1,
 						 my_qp->galpas.kernel);
 		if (cnt == (nr_q_pages - 1)) {	/* last page! */
 			if (h_ret != expected_hret) {
 				ehca_err(ib_dev, "hipz_qp_register_rpage() "
-					 "h_ret= %lx ", h_ret);
+					 "h_ret=%li", h_ret);
 				ret = ehca2ib_return_code(h_ret);
 				goto init_qp_queue1;
 			}
@@ -342,7 +348,7 @@
 		} else {
 			if (h_ret != H_PAGE_REGISTERED) {
 				ehca_err(ib_dev, "hipz_qp_register_rpage() "
-					 "h_ret= %lx ", h_ret);
+					 "h_ret=%li", h_ret);
 				ret = ehca2ib_return_code(h_ret);
 				goto init_qp_queue1;
 			}
@@ -354,19 +360,55 @@
 	return 0;
 
 init_qp_queue1:
-	ipz_queue_dtor(queue);
+	ipz_queue_dtor(pd, queue);
 	return ret;
 }
 
+static inline int ehca_calc_wqe_size(int act_nr_sge, int is_llqp)
+{
+	if (is_llqp)
+		return 128 << act_nr_sge;
+	else
+		return offsetof(struct ehca_wqe,
+				u.nud.sg_list[act_nr_sge]);
+}
+
+static void ehca_determine_small_queue(struct ehca_alloc_queue_parms *queue,
+				       int req_nr_sge, int is_llqp)
+{
+	u32 wqe_size, q_size;
+	int act_nr_sge = req_nr_sge;
+
+	if (!is_llqp)
+		/* round up #SGEs so WQE size is a power of 2 */
+		for (act_nr_sge = 4; act_nr_sge <= 252;
+		     act_nr_sge = 4 + 2 * act_nr_sge)
+			if (act_nr_sge >= req_nr_sge)
+				break;
+
+	wqe_size = ehca_calc_wqe_size(act_nr_sge, is_llqp);
+	q_size = wqe_size * (queue->max_wr + 1);
+
+	if (q_size <= 512)
+		queue->page_size = 2;
+	else if (q_size <= 1024)
+		queue->page_size = 3;
+	else
+		queue->page_size = 0;
+
+	queue->is_small = (queue->page_size != 0);
+}
+
 /*
  * Create an ib_qp struct that is either a QP or an SRQ, depending on
  * the value of the is_srq parameter. If init_attr and srq_init_attr share
  * fields, the field out of init_attr is used.
  */
-struct ehca_qp *internal_create_qp(struct ib_pd *pd,
-				   struct ib_qp_init_attr *init_attr,
-				   struct ib_srq_init_attr *srq_init_attr,
-				   struct ib_udata *udata, int is_srq)
+static struct ehca_qp *internal_create_qp(
+	struct ib_pd *pd,
+	struct ib_qp_init_attr *init_attr,
+	struct ib_srq_init_attr *srq_init_attr,
+	struct ib_udata *udata, int is_srq)
 {
 	struct ehca_qp *my_qp;
 	struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);
@@ -471,7 +513,7 @@
 			} else if (init_attr->cap.max_send_wr > 255) {
 				ehca_err(pd->device,
 					 "Invalid Number of "
-					 "ax_send_wr=%x for UD QP_TYPE=%x",
+					 "max_send_wr=%x for UD QP_TYPE=%x",
 					 init_attr->cap.max_send_wr, qp_type);
 				return ERR_PTR(-EINVAL);
 			}
@@ -482,6 +524,18 @@
 			return ERR_PTR(-EINVAL);
 			break;
 		}
+	} else {
+		int max_sge = (qp_type == IB_QPT_UD || qp_type == IB_QPT_SMI
+			       || qp_type == IB_QPT_GSI) ? 250 : 252;
+
+		if (init_attr->cap.max_send_sge > max_sge
+		    || init_attr->cap.max_recv_sge > max_sge) {
+			ehca_err(pd->device, "Invalid number of SGEs requested "
+				 "send_sge=%x recv_sge=%x max_sge=%x",
+				 init_attr->cap.max_send_sge,
+				 init_attr->cap.max_recv_sge, max_sge);
+			return ERR_PTR(-EINVAL);
+		}
 	}
 
 	if (pd->uobject && udata)
@@ -515,7 +569,6 @@
 		write_lock_irqsave(&ehca_qp_idr_lock, flags);
 		ret = idr_get_new(&ehca_qp_idr, my_qp, &my_qp->token);
 		write_unlock_irqrestore(&ehca_qp_idr_lock, flags);
-
 	} while (ret == -EAGAIN);
 
 	if (ret) {
@@ -524,11 +577,17 @@
 		goto create_qp_exit0;
 	}
 
+	if (my_qp->token > 0x1FFFFFF) {
+		ret = -EINVAL;
+		ehca_err(pd->device, "Invalid number of qp");
+		goto create_qp_exit1;
+	}
+
 	parms.servicetype = ibqptype2servicetype(qp_type);
 	if (parms.servicetype < 0) {
 		ret = -EINVAL;
 		ehca_err(pd->device, "Invalid qp_type=%x", qp_type);
-		goto create_qp_exit0;
+		goto create_qp_exit1;
 	}
 
 	if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
@@ -552,14 +611,25 @@
 	if (my_qp->recv_cq)
 		parms.recv_cq_handle = my_qp->recv_cq->ipz_cq_handle;
 
-	parms.max_send_wr = init_attr->cap.max_send_wr;
-	parms.max_recv_wr = init_attr->cap.max_recv_wr;
-	parms.max_send_sge = max_send_sge;
-	parms.max_recv_sge = max_recv_sge;
+	parms.squeue.max_wr = init_attr->cap.max_send_wr;
+	parms.rqueue.max_wr = init_attr->cap.max_recv_wr;
+	parms.squeue.max_sge = max_send_sge;
+	parms.rqueue.max_sge = max_recv_sge;
+
+	if (EHCA_BMASK_GET(HCA_CAP_MINI_QP, shca->hca_cap)) {
+		if (HAS_SQ(my_qp))
+			ehca_determine_small_queue(
+				&parms.squeue, max_send_sge, is_llqp);
+		if (HAS_RQ(my_qp))
+			ehca_determine_small_queue(
+				&parms.rqueue, max_recv_sge, is_llqp);
+		parms.qp_storage =
+			(parms.squeue.is_small || parms.rqueue.is_small);
+	}
 
 	h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, &parms);
 	if (h_ret != H_SUCCESS) {
-		ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%lx",
+		ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%li",
 			 h_ret);
 		ret = ehca2ib_return_code(h_ret);
 		goto create_qp_exit1;
@@ -569,50 +639,33 @@
 	my_qp->ipz_qp_handle = parms.qp_handle;
 	my_qp->galpas = parms.galpas;
 
+	swqe_size = ehca_calc_wqe_size(parms.squeue.act_nr_sges, is_llqp);
+	rwqe_size = ehca_calc_wqe_size(parms.rqueue.act_nr_sges, is_llqp);
+
 	switch (qp_type) {
 	case IB_QPT_RC:
-		if (!is_llqp) {
-			swqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[
-					     (parms.act_nr_send_sges)]);
-			rwqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[
-					     (parms.act_nr_recv_sges)]);
-		} else { /* for LLQP we need to use msg size, not wqe size */
-			swqe_size = ll_qp_msg_size(max_send_sge);
-			rwqe_size = ll_qp_msg_size(max_recv_sge);
-			parms.act_nr_send_sges = 1;
-			parms.act_nr_recv_sges = 1;
+		if (is_llqp) {
+			parms.squeue.act_nr_sges = 1;
+			parms.rqueue.act_nr_sges = 1;
 		}
 		break;
-	case IB_QPT_UC:
-		swqe_size = offsetof(struct ehca_wqe,
-				     u.nud.sg_list[parms.act_nr_send_sges]);
-		rwqe_size = offsetof(struct ehca_wqe,
-				     u.nud.sg_list[parms.act_nr_recv_sges]);
-		break;
-
 	case IB_QPT_UD:
 	case IB_QPT_GSI:
 	case IB_QPT_SMI:
+		/* UD circumvention */
 		if (is_llqp) {
-			swqe_size = ll_qp_msg_size(parms.act_nr_send_sges);
-			rwqe_size = ll_qp_msg_size(parms.act_nr_recv_sges);
-			parms.act_nr_send_sges = 1;
-			parms.act_nr_recv_sges = 1;
+			parms.squeue.act_nr_sges = 1;
+			parms.rqueue.act_nr_sges = 1;
 		} else {
-			/* UD circumvention */
-			parms.act_nr_send_sges -= 2;
-			parms.act_nr_recv_sges -= 2;
-			swqe_size = offsetof(struct ehca_wqe,
-					     u.ud_av.sg_list[parms.act_nr_send_sges]);
-			rwqe_size = offsetof(struct ehca_wqe,
-					     u.ud_av.sg_list[parms.act_nr_recv_sges]);
+			parms.squeue.act_nr_sges -= 2;
+			parms.rqueue.act_nr_sges -= 2;
 		}
 
 		if (IB_QPT_GSI == qp_type || IB_QPT_SMI == qp_type) {
-			parms.act_nr_send_wqes = init_attr->cap.max_send_wr;
-			parms.act_nr_recv_wqes = init_attr->cap.max_recv_wr;
-			parms.act_nr_send_sges = init_attr->cap.max_send_sge;
-			parms.act_nr_recv_sges = init_attr->cap.max_recv_sge;
+			parms.squeue.act_nr_wqes = init_attr->cap.max_send_wr;
+			parms.rqueue.act_nr_wqes = init_attr->cap.max_recv_wr;
+			parms.squeue.act_nr_sges = init_attr->cap.max_send_sge;
+			parms.rqueue.act_nr_sges = init_attr->cap.max_recv_sge;
 			ib_qp_num = (qp_type == IB_QPT_SMI) ? 0 : 1;
 		}
 
@@ -625,25 +678,23 @@
 	/* initialize r/squeue and register queue pages */
 	if (HAS_SQ(my_qp)) {
 		ret = init_qp_queue(
-			shca, my_qp, &my_qp->ipz_squeue, 0,
+			shca, my_pd, my_qp, &my_qp->ipz_squeue, 0,
 			HAS_RQ(my_qp) ? H_PAGE_REGISTERED : H_SUCCESS,
-			parms.nr_sq_pages, swqe_size,
-			parms.act_nr_send_sges);
+			&parms.squeue, swqe_size);
 		if (ret) {
 			ehca_err(pd->device, "Couldn't initialize squeue "
-				 "and pages  ret=%x", ret);
+				 "and pages ret=%i", ret);
 			goto create_qp_exit2;
 		}
 	}
 
 	if (HAS_RQ(my_qp)) {
 		ret = init_qp_queue(
-			shca, my_qp, &my_qp->ipz_rqueue, 1,
-			H_SUCCESS, parms.nr_rq_pages, rwqe_size,
-			parms.act_nr_recv_sges);
+			shca, my_pd, my_qp, &my_qp->ipz_rqueue, 1,
+			H_SUCCESS, &parms.rqueue, rwqe_size);
 		if (ret) {
 			ehca_err(pd->device, "Couldn't initialize rqueue "
-				 "and pages ret=%x", ret);
+				 "and pages ret=%i", ret);
 			goto create_qp_exit3;
 		}
 	}
@@ -670,18 +721,16 @@
 	}
 
 	init_attr->cap.max_inline_data = 0; /* not supported yet */
-	init_attr->cap.max_recv_sge = parms.act_nr_recv_sges;
-	init_attr->cap.max_recv_wr = parms.act_nr_recv_wqes;
-	init_attr->cap.max_send_sge = parms.act_nr_send_sges;
-	init_attr->cap.max_send_wr = parms.act_nr_send_wqes;
+	init_attr->cap.max_recv_sge = parms.rqueue.act_nr_sges;
+	init_attr->cap.max_recv_wr = parms.rqueue.act_nr_wqes;
+	init_attr->cap.max_send_sge = parms.squeue.act_nr_sges;
+	init_attr->cap.max_send_wr = parms.squeue.act_nr_wqes;
 	my_qp->init_attr = *init_attr;
 
 	/* NOTE: define_apq0() not supported yet */
 	if (qp_type == IB_QPT_GSI) {
 		h_ret = ehca_define_sqp(shca, my_qp, init_attr);
 		if (h_ret != H_SUCCESS) {
-			ehca_err(pd->device, "ehca_define_sqp() failed rc=%lx",
-				 h_ret);
 			ret = ehca2ib_return_code(h_ret);
 			goto create_qp_exit4;
 		}
@@ -690,8 +739,8 @@
 	if (my_qp->send_cq) {
 		ret = ehca_cq_assign_qp(my_qp->send_cq, my_qp);
 		if (ret) {
-			ehca_err(pd->device, "Couldn't assign qp to send_cq ret=%x",
-				 ret);
+			ehca_err(pd->device,
+				 "Couldn't assign qp to send_cq ret=%i", ret);
 			goto create_qp_exit4;
 		}
 	}
@@ -707,10 +756,13 @@
 		resp.ext_type = my_qp->ext_type;
 		resp.qkey = my_qp->qkey;
 		resp.real_qp_num = my_qp->real_qp_num;
+
 		if (HAS_SQ(my_qp))
 			queue2resp(&resp.ipz_squeue, &my_qp->ipz_squeue);
 		if (HAS_RQ(my_qp))
 			queue2resp(&resp.ipz_rqueue, &my_qp->ipz_rqueue);
+		resp.fw_handle_ofs = (u32)
+			(my_qp->galpas.user.fw_handle & (PAGE_SIZE - 1));
 
 		if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
 			ehca_err(pd->device, "Copy to udata failed");
@@ -723,11 +775,11 @@
 
 create_qp_exit4:
 	if (HAS_RQ(my_qp))
-		ipz_queue_dtor(&my_qp->ipz_rqueue);
+		ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
 
 create_qp_exit3:
 	if (HAS_SQ(my_qp))
-		ipz_queue_dtor(&my_qp->ipz_squeue);
+		ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
 
 create_qp_exit2:
 	hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
@@ -749,11 +801,11 @@
 	struct ehca_qp *ret;
 
 	ret = internal_create_qp(pd, qp_init_attr, NULL, udata, 0);
-	return IS_ERR(ret) ? (struct ib_qp *) ret : &ret->ib_qp;
+	return IS_ERR(ret) ? (struct ib_qp *)ret : &ret->ib_qp;
 }
 
-int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
-			struct ib_uobject *uobject);
+static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
+			       struct ib_uobject *uobject);
 
 struct ib_srq *ehca_create_srq(struct ib_pd *pd,
 			       struct ib_srq_init_attr *srq_init_attr,
@@ -780,7 +832,7 @@
 
 	my_qp = internal_create_qp(pd, &qp_init_attr, srq_init_attr, udata, 1);
 	if (IS_ERR(my_qp))
-		return (struct ib_srq *) my_qp;
+		return (struct ib_srq *)my_qp;
 
 	/* copy back return values */
 	srq_init_attr->attr.max_wr = qp_init_attr.cap.max_recv_wr;
@@ -805,7 +857,7 @@
 				mqpcb, my_qp->galpas.kernel);
 	if (hret != H_SUCCESS) {
 		ehca_err(pd->device, "Could not modify SRQ to INIT"
-			 "ehca_qp=%p qp_num=%x hret=%lx",
+			 "ehca_qp=%p qp_num=%x h_ret=%li",
 			 my_qp, my_qp->real_qp_num, hret);
 		goto create_srq2;
 	}
@@ -819,7 +871,7 @@
 				mqpcb, my_qp->galpas.kernel);
 	if (hret != H_SUCCESS) {
 		ehca_err(pd->device, "Could not enable SRQ"
-			 "ehca_qp=%p qp_num=%x hret=%lx",
+			 "ehca_qp=%p qp_num=%x h_ret=%li",
 			 my_qp, my_qp->real_qp_num, hret);
 		goto create_srq2;
 	}
@@ -833,11 +885,13 @@
 				mqpcb, my_qp->galpas.kernel);
 	if (hret != H_SUCCESS) {
 		ehca_err(pd->device, "Could not modify SRQ to RTR"
-			 "ehca_qp=%p qp_num=%x hret=%lx",
+			 "ehca_qp=%p qp_num=%x h_ret=%li",
 			 my_qp, my_qp->real_qp_num, hret);
 		goto create_srq2;
 	}
 
+	ehca_free_fw_ctrlblock(mqpcb);
+
 	return &my_qp->ib_srq;
 
 create_srq2:
@@ -871,11 +925,11 @@
 					   &bad_send_wqe_p, NULL, 2);
 	if (h_ret != H_SUCCESS) {
 		ehca_err(&shca->ib_device, "hipz_h_disable_and_get_wqe() failed"
-			 " ehca_qp=%p qp_num=%x h_ret=%lx",
+			 " ehca_qp=%p qp_num=%x h_ret=%li",
 			 my_qp, qp_num, h_ret);
 		return ehca2ib_return_code(h_ret);
 	}
-	bad_send_wqe_p = (void*)((u64)bad_send_wqe_p & (~(1L<<63)));
+	bad_send_wqe_p = (void *)((u64)bad_send_wqe_p & (~(1L << 63)));
 	ehca_dbg(&shca->ib_device, "qp_num=%x bad_send_wqe_p=%p",
 		 qp_num, bad_send_wqe_p);
 	/* convert wqe pointer to vadr */
@@ -890,7 +944,7 @@
 	}
 
 	/* loop sets wqe's purge bit */
-	wqe = (struct ehca_wqe*)ipz_qeit_calc(squeue, q_ofs);
+	wqe = (struct ehca_wqe *)ipz_qeit_calc(squeue, q_ofs);
 	*bad_wqe_cnt = 0;
 	while (wqe->optype != 0xff && wqe->wqef != 0xff) {
 		if (ehca_debug_level)
@@ -898,7 +952,7 @@
 		wqe->nr_of_data_seg = 0; /* suppress data access */
 		wqe->wqef = WQEF_PURGE; /* WQE to be purged */
 		q_ofs = ipz_queue_advance_offset(squeue, q_ofs);
-		wqe = (struct ehca_wqe*)ipz_qeit_calc(squeue, q_ofs);
+		wqe = (struct ehca_wqe *)ipz_qeit_calc(squeue, q_ofs);
 		*bad_wqe_cnt = (*bad_wqe_cnt)+1;
 	}
 	/*
@@ -949,7 +1003,7 @@
 				mqpcb, my_qp->galpas.kernel);
 	if (h_ret != H_SUCCESS) {
 		ehca_err(ibqp->device, "hipz_h_query_qp() failed "
-			 "ehca_qp=%p qp_num=%x h_ret=%lx",
+			 "ehca_qp=%p qp_num=%x h_ret=%li",
 			 my_qp, ibqp->qp_num, h_ret);
 		ret = ehca2ib_return_code(h_ret);
 		goto modify_qp_exit1;
@@ -985,7 +1039,7 @@
 			ibqp, &smiqp_attr, smiqp_attr_mask, 1);
 		if (smirc) {
 			ehca_err(ibqp->device, "SMI RESET -> INIT failed. "
-				 "ehca_modify_qp() rc=%x", smirc);
+				 "ehca_modify_qp() rc=%i", smirc);
 			ret = H_PARAMETER;
 			goto modify_qp_exit1;
 		}
@@ -1003,7 +1057,7 @@
 		goto modify_qp_exit1;
 	}
 
-	ehca_dbg(ibqp->device,"ehca_qp=%p qp_num=%x current qp_state=%x "
+	ehca_dbg(ibqp->device, "ehca_qp=%p qp_num=%x current qp_state=%x "
 		 "new qp_state=%x attribute_mask=%x",
 		 my_qp, ibqp->qp_num, qp_cur_state, attr->qp_state, attr_mask);
 
@@ -1019,7 +1073,8 @@
 		goto modify_qp_exit1;
 	}
 
-	if ((mqpcb->qp_state = ib2ehca_qp_state(qp_new_state)))
+	mqpcb->qp_state = ib2ehca_qp_state(qp_new_state);
+	if (mqpcb->qp_state)
 		update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_STATE, 1);
 	else {
 		ret = -EINVAL;
@@ -1077,7 +1132,7 @@
 			spin_lock_irqsave(&my_qp->spinlock_s, flags);
 			squeue_locked = 1;
 			/* mark next free wqe */
-			wqe = (struct ehca_wqe*)
+			wqe = (struct ehca_wqe *)
 				ipz_qeit_get(&my_qp->ipz_squeue);
 			wqe->optype = wqe->wqef = 0xff;
 			ehca_dbg(ibqp->device, "qp_num=%x next_free_wqe=%p",
@@ -1086,7 +1141,7 @@
 		ret = prepare_sqe_rts(my_qp, shca, &bad_wqe_cnt);
 		if (ret) {
 			ehca_err(ibqp->device, "prepare_sqe_rts() failed "
-				 "ehca_qp=%p qp_num=%x ret=%x",
+				 "ehca_qp=%p qp_num=%x ret=%i",
 				 my_qp, ibqp->qp_num, ret);
 			goto modify_qp_exit2;
 		}
@@ -1112,6 +1167,13 @@
 	}
 
 	if (attr_mask & IB_QP_PKEY_INDEX) {
+		if (attr->pkey_index >= 16) {
+			ret = -EINVAL;
+			ehca_err(ibqp->device, "Invalid pkey_index=%x. "
+				 "ehca_qp=%p qp_num=%x max_pkey_index=f",
+				 attr->pkey_index, my_qp, ibqp->qp_num);
+			goto modify_qp_exit2;
+		}
 		mqpcb->prim_p_key_idx = attr->pkey_index;
 		update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_P_KEY_IDX, 1);
 	}
@@ -1220,50 +1282,78 @@
 		int ehca_mult = ib_rate_to_mult(
 			shca->sport[my_qp->init_attr.port_num].rate);
 
-		mqpcb->dlid_al = attr->alt_ah_attr.dlid;
-		update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DLID_AL, 1);
-		mqpcb->source_path_bits_al = attr->alt_ah_attr.src_path_bits;
-		update_mask |=
-			EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS_AL, 1);
-		mqpcb->service_level_al = attr->alt_ah_attr.sl;
-		update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL_AL, 1);
+		if (attr->alt_port_num < 1
+		    || attr->alt_port_num > shca->num_ports) {
+			ret = -EINVAL;
+			ehca_err(ibqp->device, "Invalid alt_port=%x. "
+				 "ehca_qp=%p qp_num=%x num_ports=%x",
+				 attr->alt_port_num, my_qp, ibqp->qp_num,
+				 shca->num_ports);
+			goto modify_qp_exit2;
+		}
+		mqpcb->alt_phys_port = attr->alt_port_num;
 
-		if (ah_mult < ehca_mult)
-			mqpcb->max_static_rate = (ah_mult > 0) ?
-			((ehca_mult - 1) / ah_mult) : 0;
+		if (attr->alt_pkey_index >= 16) {
+			ret = -EINVAL;
+			ehca_err(ibqp->device, "Invalid alt_pkey_index=%x. "
+				 "ehca_qp=%p qp_num=%x max_pkey_index=f",
+				 attr->pkey_index, my_qp, ibqp->qp_num);
+			goto modify_qp_exit2;
+		}
+		mqpcb->alt_p_key_idx = attr->alt_pkey_index;
+
+		mqpcb->timeout_al = attr->alt_timeout;
+		mqpcb->dlid_al = attr->alt_ah_attr.dlid;
+		mqpcb->source_path_bits_al = attr->alt_ah_attr.src_path_bits;
+		mqpcb->service_level_al = attr->alt_ah_attr.sl;
+
+		if (ah_mult > 0 && ah_mult < ehca_mult)
+			mqpcb->max_static_rate_al = (ehca_mult - 1) / ah_mult;
 		else
 			mqpcb->max_static_rate_al = 0;
 
-		update_mask |= EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE_AL, 1);
+		/* OpenIB doesn't support alternate retry counts - copy them */
+		mqpcb->retry_count_al = mqpcb->retry_count;
+		mqpcb->rnr_retry_count_al = mqpcb->rnr_retry_count;
+
+		update_mask |= EHCA_BMASK_SET(MQPCB_MASK_ALT_PHYS_PORT, 1)
+			| EHCA_BMASK_SET(MQPCB_MASK_ALT_P_KEY_IDX, 1)
+			| EHCA_BMASK_SET(MQPCB_MASK_TIMEOUT_AL, 1)
+			| EHCA_BMASK_SET(MQPCB_MASK_DLID_AL, 1)
+			| EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS_AL, 1)
+			| EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL_AL, 1)
+			| EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE_AL, 1)
+			| EHCA_BMASK_SET(MQPCB_MASK_RETRY_COUNT_AL, 1)
+			| EHCA_BMASK_SET(MQPCB_MASK_RNR_RETRY_COUNT_AL, 1);
+
+		/*
+		 * Always supply the GRH flag, even if it's zero, to give the
+		 * hypervisor a clear "yes" or "no" instead of a "perhaps"
+		 */
+		update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG_AL, 1);
 
 		/*
 		 * only if GRH is TRUE we might consider SOURCE_GID_IDX
 		 * and DEST_GID otherwise phype will return H_ATTR_PARM!!!
 		 */
 		if (attr->alt_ah_attr.ah_flags == IB_AH_GRH) {
-			mqpcb->send_grh_flag_al = 1 << 31;
-			update_mask |=
-				EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG_AL, 1);
-			mqpcb->source_gid_idx_al =
-				attr->alt_ah_attr.grh.sgid_index;
-			update_mask |=
-				EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX_AL, 1);
+			mqpcb->send_grh_flag_al = 1;
 
 			for (cnt = 0; cnt < 16; cnt++)
 				mqpcb->dest_gid_al.byte[cnt] =
 					attr->alt_ah_attr.grh.dgid.raw[cnt];
-
-			update_mask |=
-				EHCA_BMASK_SET(MQPCB_MASK_DEST_GID_AL, 1);
+			mqpcb->source_gid_idx_al =
+				attr->alt_ah_attr.grh.sgid_index;
 			mqpcb->flow_label_al = attr->alt_ah_attr.grh.flow_label;
-			update_mask |=
-				EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL_AL, 1);
 			mqpcb->hop_limit_al = attr->alt_ah_attr.grh.hop_limit;
-			update_mask |=
-				EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT_AL, 1);
 			mqpcb->traffic_class_al =
 				attr->alt_ah_attr.grh.traffic_class;
+
 			update_mask |=
+				EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX_AL, 1)
+				| EHCA_BMASK_SET(MQPCB_MASK_DEST_GID_AL, 1)
+				| EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL_AL, 1)
+				| EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT_AL, 1) |
 				EHCA_BMASK_SET(MQPCB_MASK_TRAFFIC_CLASS_AL, 1);
 		}
 	}
@@ -1285,7 +1375,14 @@
 	}
 
 	if (attr_mask & IB_QP_PATH_MIG_STATE) {
-		mqpcb->path_migration_state = attr->path_mig_state;
+		if (attr->path_mig_state != IB_MIG_REARM
+		    && attr->path_mig_state != IB_MIG_MIGRATED) {
+			ret = -EINVAL;
+			ehca_err(ibqp->device, "Invalid mig_state=%x",
+				 attr->path_mig_state);
+			goto modify_qp_exit2;
+		}
+		mqpcb->path_migration_state = attr->path_mig_state + 1;
 		update_mask |=
 			EHCA_BMASK_SET(MQPCB_MASK_PATH_MIGRATION_STATE, 1);
 	}
@@ -1311,8 +1408,8 @@
 
 	if (h_ret != H_SUCCESS) {
 		ret = ehca2ib_return_code(h_ret);
-		ehca_err(ibqp->device, "hipz_h_modify_qp() failed rc=%lx "
-			 "ehca_qp=%p qp_num=%x",h_ret, my_qp, ibqp->qp_num);
+		ehca_err(ibqp->device, "hipz_h_modify_qp() failed h_ret=%li "
+			 "ehca_qp=%p qp_num=%x", h_ret, my_qp, ibqp->qp_num);
 		goto modify_qp_exit2;
 	}
 
@@ -1344,7 +1441,7 @@
 			ret = ehca2ib_return_code(h_ret);
 			ehca_err(ibqp->device, "ENABLE in context of "
 				 "RESET_2_INIT failed! Maybe you didn't get "
-				 "a LID h_ret=%lx ehca_qp=%p qp_num=%x",
+				 "a LID h_ret=%li ehca_qp=%p qp_num=%x",
 				 h_ret, my_qp, ibqp->qp_num);
 			goto modify_qp_exit2;
 		}
@@ -1411,7 +1508,7 @@
 	}
 
 	if (qp_attr_mask & QP_ATTR_QUERY_NOT_SUPPORTED) {
-		ehca_err(qp->device,"Invalid attribute mask "
+		ehca_err(qp->device, "Invalid attribute mask "
 			 "ehca_qp=%p qp_num=%x qp_attr_mask=%x ",
 			 my_qp, qp->qp_num, qp_attr_mask);
 		return -EINVAL;
@@ -1419,7 +1516,7 @@
 
 	qpcb = ehca_alloc_fw_ctrlblock(GFP_KERNEL);
 	if (!qpcb) {
-		ehca_err(qp->device,"Out of memory for qpcb "
+		ehca_err(qp->device, "Out of memory for qpcb "
 			 "ehca_qp=%p qp_num=%x", my_qp, qp->qp_num);
 		return -ENOMEM;
 	}
@@ -1431,8 +1528,8 @@
 
 	if (h_ret != H_SUCCESS) {
 		ret = ehca2ib_return_code(h_ret);
-		ehca_err(qp->device,"hipz_h_query_qp() failed "
-			 "ehca_qp=%p qp_num=%x h_ret=%lx",
+		ehca_err(qp->device, "hipz_h_query_qp() failed "
+			 "ehca_qp=%p qp_num=%x h_ret=%li",
 			 my_qp, qp->qp_num, h_ret);
 		goto query_qp_exit1;
 	}
@@ -1442,7 +1539,7 @@
 
 	if (qp_attr->cur_qp_state == -EINVAL) {
 		ret = -EINVAL;
-		ehca_err(qp->device,"Got invalid ehca_qp_state=%x "
+		ehca_err(qp->device, "Got invalid ehca_qp_state=%x "
 			 "ehca_qp=%p qp_num=%x",
 			 qpcb->qp_state, my_qp, qp->qp_num);
 		goto query_qp_exit1;
@@ -1453,7 +1550,7 @@
 
 	qp_attr->qkey = qpcb->qkey;
 	qp_attr->path_mtu = qpcb->path_mtu;
-	qp_attr->path_mig_state = qpcb->path_migration_state;
+	qp_attr->path_mig_state = qpcb->path_migration_state - 1;
 	qp_attr->rq_psn = qpcb->receive_psn;
 	qp_attr->sq_psn = qpcb->send_psn;
 	qp_attr->min_rnr_timer = qpcb->min_rnr_nak_timer_field;
@@ -1607,7 +1704,7 @@
 
 	if (h_ret != H_SUCCESS) {
 		ret = ehca2ib_return_code(h_ret);
-		ehca_err(ibsrq->device, "hipz_h_modify_qp() failed rc=%lx "
+		ehca_err(ibsrq->device, "hipz_h_modify_qp() failed h_ret=%li "
 			 "ehca_qp=%p qp_num=%x",
 			 h_ret, my_qp, my_qp->real_qp_num);
 	}
@@ -1650,12 +1747,13 @@
 	if (h_ret != H_SUCCESS) {
 		ret = ehca2ib_return_code(h_ret);
 		ehca_err(srq->device, "hipz_h_query_qp() failed "
-			 "ehca_qp=%p qp_num=%x h_ret=%lx",
+			 "ehca_qp=%p qp_num=%x h_ret=%li",
 			 my_qp, my_qp->real_qp_num, h_ret);
 		goto query_srq_exit1;
 	}
 
 	srq_attr->max_wr = qpcb->max_nr_outst_recv_wr - 1;
+	srq_attr->max_sge = qpcb->actual_nr_sges_in_rq_wqe;
 	srq_attr->srq_limit = EHCA_BMASK_GET(
 		MQPCB_CURR_SRQ_LIMIT, qpcb->curr_srq_limit);
 
@@ -1668,8 +1766,8 @@
 	return ret;
 }
 
-int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
-			struct ib_uobject *uobject)
+static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
+			       struct ib_uobject *uobject)
 {
 	struct ehca_shca *shca = container_of(dev, struct ehca_shca, ib_device);
 	struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
@@ -1700,7 +1798,7 @@
 		ret = ehca_cq_unassign_qp(my_qp->send_cq, qp_num);
 		if (ret) {
 			ehca_err(dev, "Couldn't unassign qp from "
-				 "send_cq ret=%x qp_num=%x cq_num=%x", ret,
+				 "send_cq ret=%i qp_num=%x cq_num=%x", ret,
 				 qp_num, my_qp->send_cq->cq_number);
 			return ret;
 		}
@@ -1712,7 +1810,7 @@
 
 	h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
 	if (h_ret != H_SUCCESS) {
-		ehca_err(dev, "hipz_h_destroy_qp() failed rc=%lx "
+		ehca_err(dev, "hipz_h_destroy_qp() failed h_ret=%li "
 			 "ehca_qp=%p qp_num=%x", h_ret, my_qp, qp_num);
 		return ehca2ib_return_code(h_ret);
 	}
@@ -1733,9 +1831,9 @@
 	}
 
 	if (HAS_RQ(my_qp))
-		ipz_queue_dtor(&my_qp->ipz_rqueue);
+		ipz_queue_dtor(my_pd, &my_qp->ipz_rqueue);
 	if (HAS_SQ(my_qp))
-		ipz_queue_dtor(&my_qp->ipz_squeue);
+		ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
 	kmem_cache_free(qp_cache, my_qp);
 	return 0;
 }
@@ -1759,7 +1857,7 @@
 	qp_cache = kmem_cache_create("ehca_cache_qp",
 				     sizeof(struct ehca_qp), 0,
 				     SLAB_HWCACHE_ALIGN,
-				     NULL, NULL);
+				     NULL);
 	if (!qp_cache)
 		return -ENOMEM;
 	return 0;
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
index 61da65e..ea91360 100644
--- a/drivers/infiniband/hw/ehca/ehca_reqs.c
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -79,7 +79,8 @@
 	}
 
 	if (ehca_debug_level) {
-		ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p", ipz_rqueue);
+		ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p",
+			     ipz_rqueue);
 		ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
 	}
 
@@ -99,7 +100,7 @@
 		struct ib_mad_hdr *mad_hdr = send_wr->wr.ud.mad_hdr;
 		struct ib_sge *sge = send_wr->sg_list;
 		ehca_gen_dbg("send_wr#%x wr_id=%lx num_sge=%x "
-			     "send_flags=%x opcode=%x",idx, send_wr->wr_id,
+			     "send_flags=%x opcode=%x", idx, send_wr->wr_id,
 			     send_wr->num_sge, send_wr->send_flags,
 			     send_wr->opcode);
 		if (mad_hdr) {
@@ -116,7 +117,7 @@
 				     mad_hdr->attr_mod);
 		}
 		for (j = 0; j < send_wr->num_sge; j++) {
-			u8 *data = (u8 *) abs_to_virt(sge->addr);
+			u8 *data = (u8 *)abs_to_virt(sge->addr);
 			ehca_gen_dbg("send_wr#%x sge#%x addr=%p length=%x "
 				     "lkey=%x",
 				     idx, j, data, sge->length, sge->lkey);
@@ -525,7 +526,7 @@
 	if (!cqe) {
 		ret = -EAGAIN;
 		ehca_dbg(cq->device, "Completion queue is empty ehca_cq=%p "
-			 "cq_num=%x ret=%x", my_cq, my_cq->cq_number, ret);
+			 "cq_num=%x ret=%i", my_cq, my_cq->cq_number, ret);
 		goto  poll_cq_one_exit0;
 	}
 
@@ -534,9 +535,11 @@
 
 	cqe_count++;
 	if (unlikely(cqe->status & WC_STATUS_PURGE_BIT)) {
-		struct ehca_qp *qp=ehca_cq_get_qp(my_cq, cqe->local_qp_number);
+		struct ehca_qp *qp;
 		int purgeflag;
 		unsigned long flags;
+
+		qp = ehca_cq_get_qp(my_cq, cqe->local_qp_number);
 		if (!qp) {
 			ehca_err(cq->device, "cq_num=%x qp_num=%x "
 				 "could not find qp -> ignore cqe",
@@ -551,8 +554,8 @@
 		spin_unlock_irqrestore(&qp->spinlock_s, flags);
 
 		if (purgeflag) {
-			ehca_dbg(cq->device, "Got CQE with purged bit qp_num=%x "
-				 "src_qp=%x",
+			ehca_dbg(cq->device,
+				 "Got CQE with purged bit qp_num=%x src_qp=%x",
 				 cqe->local_qp_number, cqe->remote_qp_number);
 			if (ehca_debug_level)
 				ehca_dmp(cqe, 64, "qp_num=%x src_qp=%x",
diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c
index 9f16e9c..f0792e5 100644
--- a/drivers/infiniband/hw/ehca/ehca_sqp.c
+++ b/drivers/infiniband/hw/ehca/ehca_sqp.c
@@ -82,7 +82,7 @@
 
 		if (ret != H_SUCCESS) {
 			ehca_err(&shca->ib_device,
-				 "Can't define AQP1 for port %x. rc=%lx",
+				 "Can't define AQP1 for port %x. h_ret=%li",
 				 port, ret);
 			return ret;
 		}
diff --git a/drivers/infiniband/hw/ehca/ehca_tools.h b/drivers/infiniband/hw/ehca/ehca_tools.h
index 03b185f..4a8346a 100644
--- a/drivers/infiniband/hw/ehca/ehca_tools.h
+++ b/drivers/infiniband/hw/ehca/ehca_tools.h
@@ -73,40 +73,37 @@
 		if (unlikely(ehca_debug_level)) \
 			dev_printk(KERN_DEBUG, (ib_dev)->dma_device, \
 				   "PU%04x EHCA_DBG:%s " format "\n", \
-				   get_paca()->paca_index, __FUNCTION__, \
+				   raw_smp_processor_id(), __FUNCTION__, \
 				   ## arg); \
 	} while (0)
 
 #define ehca_info(ib_dev, format, arg...) \
 	dev_info((ib_dev)->dma_device, "PU%04x EHCA_INFO:%s " format "\n", \
-		 get_paca()->paca_index, __FUNCTION__, ## arg)
+		 raw_smp_processor_id(), __FUNCTION__, ## arg)
 
 #define ehca_warn(ib_dev, format, arg...) \
 	dev_warn((ib_dev)->dma_device, "PU%04x EHCA_WARN:%s " format "\n", \
-		 get_paca()->paca_index, __FUNCTION__, ## arg)
+		 raw_smp_processor_id(), __FUNCTION__, ## arg)
 
 #define ehca_err(ib_dev, format, arg...) \
 	dev_err((ib_dev)->dma_device, "PU%04x EHCA_ERR:%s " format "\n", \
-		get_paca()->paca_index, __FUNCTION__, ## arg)
+		raw_smp_processor_id(), __FUNCTION__, ## arg)
 
 /* use this one only if no ib_dev available */
 #define ehca_gen_dbg(format, arg...) \
 	do { \
 		if (unlikely(ehca_debug_level)) \
-			printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n",\
-			       get_paca()->paca_index, __FUNCTION__, ## arg); \
+			printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n", \
+			       raw_smp_processor_id(), __FUNCTION__, ## arg); \
 	} while (0)
 
 #define ehca_gen_warn(format, arg...) \
-	do { \
-		if (unlikely(ehca_debug_level)) \
-			printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n",\
-			       get_paca()->paca_index, __FUNCTION__, ## arg); \
-	} while (0)
+	printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n", \
+	       raw_smp_processor_id(), __FUNCTION__, ## arg)
 
 #define ehca_gen_err(format, arg...) \
 	printk(KERN_ERR "PU%04x EHCA_ERR:%s " format "\n", \
-		get_paca()->paca_index, __FUNCTION__, ## arg)
+	       raw_smp_processor_id(), __FUNCTION__, ## arg)
 
 /**
  * ehca_dmp - printk a memory block, whose length is n*8 bytes.
@@ -114,12 +111,12 @@
  * <format string> adr=X ofs=Y <8 bytes hex> <8 bytes hex>
  */
 #define ehca_dmp(adr, len, format, args...) \
-	do {				       \
-		unsigned int x;			      \
+	do { \
+		unsigned int x; \
 		unsigned int l = (unsigned int)(len); \
-		unsigned char *deb = (unsigned char*)(adr);	\
+		unsigned char *deb = (unsigned char *)(adr); \
 		for (x = 0; x < l; x += 16) { \
-			printk("EHCA_DMP:%s " format \
+			printk(KERN_INFO "EHCA_DMP:%s " format \
 			       " adr=%p ofs=%04x %016lx %016lx\n", \
 			       __FUNCTION__, ##args, deb, x, \
 			       *((u64 *)&deb[0]), *((u64 *)&deb[8])); \
@@ -128,16 +125,16 @@
 	} while (0)
 
 /* define a bitmask, little endian version */
-#define EHCA_BMASK(pos,length) (((pos)<<16)+(length))
+#define EHCA_BMASK(pos, length) (((pos) << 16) + (length))
 
 /* define a bitmask, the ibm way... */
-#define EHCA_BMASK_IBM(from,to) (((63-to)<<16)+((to)-(from)+1))
+#define EHCA_BMASK_IBM(from, to) (((63 - to) << 16) + ((to) - (from) + 1))
 
 /* internal function, don't use */
-#define EHCA_BMASK_SHIFTPOS(mask) (((mask)>>16)&0xffff)
+#define EHCA_BMASK_SHIFTPOS(mask) (((mask) >> 16) & 0xffff)
 
 /* internal function, don't use */
-#define EHCA_BMASK_MASK(mask) (0xffffffffffffffffULL >> ((64-(mask))&0xffff))
+#define EHCA_BMASK_MASK(mask) (~0ULL >> ((64 - (mask)) & 0xffff))
 
 /**
  * EHCA_BMASK_SET - return value shifted and masked by mask
@@ -145,30 +142,16 @@
  * variable&=~EHCA_BMASK_SET(MY_MASK,-1) clears the bits from the mask
  * in variable
  */
-#define EHCA_BMASK_SET(mask,value) \
-	((EHCA_BMASK_MASK(mask) & ((u64)(value)))<<EHCA_BMASK_SHIFTPOS(mask))
+#define EHCA_BMASK_SET(mask, value) \
+	((EHCA_BMASK_MASK(mask) & ((u64)(value))) << EHCA_BMASK_SHIFTPOS(mask))
 
 /**
  * EHCA_BMASK_GET - extract a parameter from value by mask
  */
-#define EHCA_BMASK_GET(mask,value) \
-	(EHCA_BMASK_MASK(mask)& (((u64)(value))>>EHCA_BMASK_SHIFTPOS(mask)))
-
+#define EHCA_BMASK_GET(mask, value) \
+	(EHCA_BMASK_MASK(mask) & (((u64)(value)) >> EHCA_BMASK_SHIFTPOS(mask)))
 
 /* Converts ehca to ib return code */
-static inline int ehca2ib_return_code(u64 ehca_rc)
-{
-	switch (ehca_rc) {
-	case H_SUCCESS:
-		return 0;
-	case H_BUSY:
-		return -EBUSY;
-	case H_NO_MEM:
-		return -ENOMEM;
-	default:
-		return -EINVAL;
-	}
-}
-
+int ehca2ib_return_code(u64 ehca_rc);
 
 #endif /* EHCA_TOOLS_H */
diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c
index 3031b3b..5234d6c 100644
--- a/drivers/infiniband/hw/ehca/ehca_uverbs.c
+++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c
@@ -70,7 +70,7 @@
 
 static void ehca_mm_open(struct vm_area_struct *vma)
 {
-	u32 *count = (u32*)vma->vm_private_data;
+	u32 *count = (u32 *)vma->vm_private_data;
 	if (!count) {
 		ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
 			     vma->vm_start, vma->vm_end);
@@ -86,7 +86,7 @@
 
 static void ehca_mm_close(struct vm_area_struct *vma)
 {
-	u32 *count = (u32*)vma->vm_private_data;
+	u32 *count = (u32 *)vma->vm_private_data;
 	if (!count) {
 		ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
 			     vma->vm_start, vma->vm_end);
@@ -109,7 +109,7 @@
 	u64 vsize, physical;
 
 	vsize = vma->vm_end - vma->vm_start;
-	if (vsize != EHCA_PAGESIZE) {
+	if (vsize < EHCA_PAGESIZE) {
 		ehca_gen_err("invalid vsize=%lx", vma->vm_end - vma->vm_start);
 		return -EINVAL;
 	}
@@ -118,10 +118,10 @@
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 	ehca_gen_dbg("vsize=%lx physical=%lx", vsize, physical);
 	/* VM_IO | VM_RESERVED are set by remap_pfn_range() */
-	ret = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT,
-			      vsize, vma->vm_page_prot);
+	ret = remap_4k_pfn(vma, vma->vm_start, physical >> EHCA_PAGESHIFT,
+			   vma->vm_page_prot);
 	if (unlikely(ret)) {
-		ehca_gen_err("remap_pfn_range() failed ret=%x", ret);
+		ehca_gen_err("remap_pfn_range() failed ret=%i", ret);
 		return -ENOMEM;
 	}
 
@@ -146,10 +146,10 @@
 		page = virt_to_page(virt_addr);
 		ret = vm_insert_page(vma, start, page);
 		if (unlikely(ret)) {
-			ehca_gen_err("vm_insert_page() failed rc=%x", ret);
+			ehca_gen_err("vm_insert_page() failed rc=%i", ret);
 			return ret;
 		}
-		start +=  PAGE_SIZE;
+		start += PAGE_SIZE;
 	}
 	vma->vm_private_data = mm_count;
 	(*mm_count)++;
@@ -164,23 +164,23 @@
 	int ret;
 
 	switch (rsrc_type) {
-	case 1: /* galpa fw handle */
+	case 0: /* galpa fw handle */
 		ehca_dbg(cq->ib_cq.device, "cq_num=%x fw", cq->cq_number);
 		ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa);
 		if (unlikely(ret)) {
 			ehca_err(cq->ib_cq.device,
-				 "ehca_mmap_fw() failed rc=%x cq_num=%x",
+				 "ehca_mmap_fw() failed rc=%i cq_num=%x",
 				 ret, cq->cq_number);
 			return ret;
 		}
 		break;
 
-	case 2: /* cq queue_addr */
+	case 1: /* cq queue_addr */
 		ehca_dbg(cq->ib_cq.device, "cq_num=%x queue", cq->cq_number);
 		ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue);
 		if (unlikely(ret)) {
 			ehca_err(cq->ib_cq.device,
-				 "ehca_mmap_queue() failed rc=%x cq_num=%x",
+				 "ehca_mmap_queue() failed rc=%i cq_num=%x",
 				 ret, cq->cq_number);
 			return ret;
 		}
@@ -201,36 +201,38 @@
 	int ret;
 
 	switch (rsrc_type) {
-	case 1: /* galpa fw handle */
+	case 0: /* galpa fw handle */
 		ehca_dbg(qp->ib_qp.device, "qp_num=%x fw", qp->ib_qp.qp_num);
 		ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa);
 		if (unlikely(ret)) {
 			ehca_err(qp->ib_qp.device,
-				 "remap_pfn_range() failed ret=%x qp_num=%x",
+				 "remap_pfn_range() failed ret=%i qp_num=%x",
 				 ret, qp->ib_qp.qp_num);
 			return -ENOMEM;
 		}
 		break;
 
-	case 2: /* qp rqueue_addr */
+	case 1: /* qp rqueue_addr */
 		ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue",
 			 qp->ib_qp.qp_num);
-		ret = ehca_mmap_queue(vma, &qp->ipz_rqueue, &qp->mm_count_rqueue);
+		ret = ehca_mmap_queue(vma, &qp->ipz_rqueue,
+				      &qp->mm_count_rqueue);
 		if (unlikely(ret)) {
 			ehca_err(qp->ib_qp.device,
-				 "ehca_mmap_queue(rq) failed rc=%x qp_num=%x",
+				 "ehca_mmap_queue(rq) failed rc=%i qp_num=%x",
 				 ret, qp->ib_qp.qp_num);
 			return ret;
 		}
 		break;
 
-	case 3: /* qp squeue_addr */
+	case 2: /* qp squeue_addr */
 		ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue",
 			 qp->ib_qp.qp_num);
-		ret = ehca_mmap_queue(vma, &qp->ipz_squeue, &qp->mm_count_squeue);
+		ret = ehca_mmap_queue(vma, &qp->ipz_squeue,
+				      &qp->mm_count_squeue);
 		if (unlikely(ret)) {
 			ehca_err(qp->ib_qp.device,
-				 "ehca_mmap_queue(sq) failed rc=%x qp_num=%x",
+				 "ehca_mmap_queue(sq) failed rc=%i qp_num=%x",
 				 ret, qp->ib_qp.qp_num);
 			return ret;
 		}
@@ -247,10 +249,10 @@
 
 int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
 {
-	u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
-	u32 idr_handle = fileoffset >> 32;
-	u32 q_type = (fileoffset >> 28) & 0xF;	  /* CQ, QP,...        */
-	u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
+	u64 fileoffset = vma->vm_pgoff;
+	u32 idr_handle = fileoffset & 0x1FFFFFF;
+	u32 q_type = (fileoffset >> 27) & 0x1;	  /* CQ, QP,...        */
+	u32 rsrc_type = (fileoffset >> 25) & 0x3; /* sq,rq,cmnd_window */
 	u32 cur_pid = current->tgid;
 	u32 ret;
 	struct ehca_cq *cq;
@@ -259,7 +261,7 @@
 	struct ib_uobject *uobject;
 
 	switch (q_type) {
-	case  1: /* CQ */
+	case  0: /* CQ */
 		read_lock(&ehca_cq_idr_lock);
 		cq = idr_find(&ehca_cq_idr, idr_handle);
 		read_unlock(&ehca_cq_idr_lock);
@@ -281,13 +283,13 @@
 		ret = ehca_mmap_cq(vma, cq, rsrc_type);
 		if (unlikely(ret)) {
 			ehca_err(cq->ib_cq.device,
-				 "ehca_mmap_cq() failed rc=%x cq_num=%x",
+				 "ehca_mmap_cq() failed rc=%i cq_num=%x",
 				 ret, cq->cq_number);
 			return ret;
 		}
 		break;
 
-	case 2: /* QP */
+	case 1: /* QP */
 		read_lock(&ehca_qp_idr_lock);
 		qp = idr_find(&ehca_qp_idr, idr_handle);
 		read_unlock(&ehca_qp_idr_lock);
@@ -311,7 +313,7 @@
 		ret = ehca_mmap_qp(vma, qp, rsrc_type);
 		if (unlikely(ret)) {
 			ehca_err(qp->ib_qp.device,
-				 "ehca_mmap_qp() failed rc=%x qp_num=%x",
+				 "ehca_mmap_qp() failed rc=%i qp_num=%x",
 				 ret, qp->ib_qp.qp_num);
 			return ret;
 		}
diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c
index 4776a8b..c16a213 100644
--- a/drivers/infiniband/hw/ehca/hcp_if.c
+++ b/drivers/infiniband/hw/ehca/hcp_if.c
@@ -52,10 +52,13 @@
 #define H_ALL_RES_QP_ENHANCED_OPS       EHCA_BMASK_IBM(9, 11)
 #define H_ALL_RES_QP_PTE_PIN            EHCA_BMASK_IBM(12, 12)
 #define H_ALL_RES_QP_SERVICE_TYPE       EHCA_BMASK_IBM(13, 15)
+#define H_ALL_RES_QP_STORAGE            EHCA_BMASK_IBM(16, 17)
 #define H_ALL_RES_QP_LL_RQ_CQE_POSTING  EHCA_BMASK_IBM(18, 18)
 #define H_ALL_RES_QP_LL_SQ_CQE_POSTING  EHCA_BMASK_IBM(19, 21)
 #define H_ALL_RES_QP_SIGNALING_TYPE     EHCA_BMASK_IBM(22, 23)
 #define H_ALL_RES_QP_UD_AV_LKEY_CTRL    EHCA_BMASK_IBM(31, 31)
+#define H_ALL_RES_QP_SMALL_SQ_PAGE_SIZE EHCA_BMASK_IBM(32, 35)
+#define H_ALL_RES_QP_SMALL_RQ_PAGE_SIZE EHCA_BMASK_IBM(36, 39)
 #define H_ALL_RES_QP_RESOURCE_TYPE      EHCA_BMASK_IBM(56, 63)
 
 #define H_ALL_RES_QP_MAX_OUTST_SEND_WR  EHCA_BMASK_IBM(0, 15)
@@ -81,6 +84,10 @@
 #define H_MP_SHUTDOWN                   EHCA_BMASK_IBM(48, 48)
 #define H_MP_RESET_QKEY_CTR             EHCA_BMASK_IBM(49, 49)
 
+#define HCALL4_REGS_FORMAT "r4=%lx r5=%lx r6=%lx r7=%lx"
+#define HCALL7_REGS_FORMAT HCALL4_REGS_FORMAT " r8=%lx r9=%lx r10=%lx"
+#define HCALL9_REGS_FORMAT HCALL7_REGS_FORMAT " r11=%lx r12=%lx"
+
 static DEFINE_SPINLOCK(hcall_lock);
 
 static u32 get_longbusy_msecs(int longbusy_rc)
@@ -113,16 +120,28 @@
 				    unsigned long arg7)
 {
 	long ret;
-	int i, sleep_msecs;
+	int i, sleep_msecs, do_lock;
+	unsigned long flags;
 
-	ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx "
-		     "arg5=%lx arg6=%lx arg7=%lx",
+	ehca_gen_dbg("opcode=%lx " HCALL7_REGS_FORMAT,
 		     opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
 
+	/* lock H_FREE_RESOURCE(MR) against itself and H_ALLOC_RESOURCE(MR) */
+	if ((opcode == H_FREE_RESOURCE) && (arg7 == 5)) {
+		arg7 = 0; /* better not upset firmware */
+		do_lock = 1;
+	}
+
 	for (i = 0; i < 5; i++) {
+		if (do_lock)
+			spin_lock_irqsave(&hcall_lock, flags);
+
 		ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4,
 					 arg5, arg6, arg7);
 
+		if (do_lock)
+			spin_unlock_irqrestore(&hcall_lock, flags);
+
 		if (H_IS_LONG_BUSY(ret)) {
 			sleep_msecs = get_longbusy_msecs(ret);
 			msleep_interruptible(sleep_msecs);
@@ -130,16 +149,13 @@
 		}
 
 		if (ret < H_SUCCESS)
-			ehca_gen_err("opcode=%lx ret=%lx"
-				     " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
-				     " arg5=%lx arg6=%lx arg7=%lx ",
-				     opcode, ret,
-				     arg1, arg2, arg3, arg4, arg5,
-				     arg6, arg7);
+			ehca_gen_err("opcode=%lx ret=%li " HCALL7_REGS_FORMAT,
+				     opcode, ret, arg1, arg2, arg3,
+				     arg4, arg5, arg6, arg7);
+		else
+			ehca_gen_dbg("opcode=%lx ret=%li", opcode, ret);
 
-		ehca_gen_dbg("opcode=%lx ret=%lx", opcode, ret);
 		return ret;
-
 	}
 
 	return H_BUSY;
@@ -158,25 +174,24 @@
 			      unsigned long arg9)
 {
 	long ret;
-	int i, sleep_msecs, lock_is_set = 0;
+	int i, sleep_msecs, do_lock;
 	unsigned long flags = 0;
 
-	ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx "
-		     "arg5=%lx arg6=%lx arg7=%lx arg8=%lx arg9=%lx",
-		     opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
-		     arg8, arg9);
+	ehca_gen_dbg("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT, opcode,
+		     arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
+
+	/* lock H_ALLOC_RESOURCE(MR) against itself and H_FREE_RESOURCE(MR) */
+	do_lock = ((opcode == H_ALLOC_RESOURCE) && (arg2 == 5));
 
 	for (i = 0; i < 5; i++) {
-		if ((opcode == H_ALLOC_RESOURCE) && (arg2 == 5)) {
+		if (do_lock)
 			spin_lock_irqsave(&hcall_lock, flags);
-			lock_is_set = 1;
-		}
 
 		ret = plpar_hcall9(opcode, outs,
 				   arg1, arg2, arg3, arg4, arg5,
 				   arg6, arg7, arg8, arg9);
 
-		if (lock_is_set)
+		if (do_lock)
 			spin_unlock_irqrestore(&hcall_lock, flags);
 
 		if (H_IS_LONG_BUSY(ret)) {
@@ -185,26 +200,19 @@
 			continue;
 		}
 
-		if (ret < H_SUCCESS)
-			ehca_gen_err("opcode=%lx ret=%lx"
-				     " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
-				     " arg5=%lx arg6=%lx arg7=%lx arg8=%lx"
-				     " arg9=%lx"
-				     " out1=%lx out2=%lx out3=%lx out4=%lx"
-				     " out5=%lx out6=%lx out7=%lx out8=%lx"
-				     " out9=%lx",
-				     opcode, ret,
-				     arg1, arg2, arg3, arg4, arg5,
-				     arg6, arg7, arg8, arg9,
-				     outs[0], outs[1], outs[2], outs[3],
+		if (ret < H_SUCCESS) {
+			ehca_gen_err("INPUT -- opcode=%lx " HCALL9_REGS_FORMAT,
+				     opcode, arg1, arg2, arg3, arg4, arg5,
+				     arg6, arg7, arg8, arg9);
+			ehca_gen_err("OUTPUT -- ret=%li " HCALL9_REGS_FORMAT,
+				     ret, outs[0], outs[1], outs[2], outs[3],
 				     outs[4], outs[5], outs[6], outs[7],
 				     outs[8]);
-
-		ehca_gen_dbg("opcode=%lx ret=%lx out1=%lx out2=%lx out3=%lx "
-			     "out4=%lx out5=%lx out6=%lx out7=%lx out8=%lx "
-			     "out9=%lx",
-			     opcode, ret, outs[0], outs[1], outs[2], outs[3],
-			     outs[4], outs[5], outs[6], outs[7], outs[8]);
+		} else
+			ehca_gen_dbg("OUTPUT -- ret=%li " HCALL9_REGS_FORMAT,
+				     ret, outs[0], outs[1], outs[2], outs[3],
+				     outs[4], outs[5], outs[6], outs[7],
+				     outs[8]);
 		return ret;
 	}
 
@@ -244,7 +252,7 @@
 	*eq_ist = (u32)outs[5];
 
 	if (ret == H_NOT_ENOUGH_RESOURCES)
-		ehca_gen_err("Not enough resource - ret=%lx ", ret);
+		ehca_gen_err("Not enough resource - ret=%li ", ret);
 
 	return ret;
 }
@@ -282,7 +290,7 @@
 		hcp_galpas_ctor(&cq->galpas, outs[5], outs[6]);
 
 	if (ret == H_NOT_ENOUGH_RESOURCES)
-		ehca_gen_err("Not enough resources. ret=%lx", ret);
+		ehca_gen_err("Not enough resources. ret=%li", ret);
 
 	return ret;
 }
@@ -299,6 +307,11 @@
 		| EHCA_BMASK_SET(H_ALL_RES_QP_PTE_PIN, 0)
 		| EHCA_BMASK_SET(H_ALL_RES_QP_SERVICE_TYPE, parms->servicetype)
 		| EHCA_BMASK_SET(H_ALL_RES_QP_SIGNALING_TYPE, parms->sigtype)
+		| EHCA_BMASK_SET(H_ALL_RES_QP_STORAGE, parms->qp_storage)
+		| EHCA_BMASK_SET(H_ALL_RES_QP_SMALL_SQ_PAGE_SIZE,
+				 parms->squeue.page_size)
+		| EHCA_BMASK_SET(H_ALL_RES_QP_SMALL_RQ_PAGE_SIZE,
+				 parms->rqueue.page_size)
 		| EHCA_BMASK_SET(H_ALL_RES_QP_LL_RQ_CQE_POSTING,
 				 !!(parms->ll_comp_flags & LLQP_RECV_COMP))
 		| EHCA_BMASK_SET(H_ALL_RES_QP_LL_SQ_CQE_POSTING,
@@ -309,13 +322,13 @@
 
 	max_r10_reg =
 		EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_SEND_WR,
-			       parms->max_send_wr + 1)
+			       parms->squeue.max_wr + 1)
 		| EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_RECV_WR,
-				 parms->max_recv_wr + 1)
+				 parms->rqueue.max_wr + 1)
 		| EHCA_BMASK_SET(H_ALL_RES_QP_MAX_SEND_SGE,
-				 parms->max_send_sge)
+				 parms->squeue.max_sge)
 		| EHCA_BMASK_SET(H_ALL_RES_QP_MAX_RECV_SGE,
-				 parms->max_recv_sge);
+				 parms->rqueue.max_sge);
 
 	r11 = EHCA_BMASK_SET(H_ALL_RES_QP_SRQ_QP_TOKEN, parms->srq_token);
 
@@ -335,24 +348,24 @@
 
 	parms->qp_handle.handle = outs[0];
 	parms->real_qp_num = (u32)outs[1];
-	parms->act_nr_send_wqes =
+	parms->squeue.act_nr_wqes =
 		(u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_SEND_WR, outs[2]);
-	parms->act_nr_recv_wqes =
+	parms->rqueue.act_nr_wqes =
 		(u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_RECV_WR, outs[2]);
-	parms->act_nr_send_sges =
+	parms->squeue.act_nr_sges =
 		(u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_SEND_SGE, outs[3]);
-	parms->act_nr_recv_sges =
+	parms->rqueue.act_nr_sges =
 		(u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_RECV_SGE, outs[3]);
-	parms->nr_sq_pages =
+	parms->squeue.queue_size =
 		(u32)EHCA_BMASK_GET(H_ALL_RES_QP_SQUEUE_SIZE_PAGES, outs[4]);
-	parms->nr_rq_pages =
+	parms->rqueue.queue_size =
 		(u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, outs[4]);
 
 	if (ret == H_SUCCESS)
 		hcp_galpas_ctor(&parms->galpas, outs[6], outs[6]);
 
 	if (ret == H_NOT_ENOUGH_RESOURCES)
-		ehca_gen_err("Not enough resources. ret=%lx", ret);
+		ehca_gen_err("Not enough resources. ret=%li", ret);
 
 	return ret;
 }
@@ -427,7 +440,8 @@
 {
 	return ehca_plpar_hcall_norets(H_REGISTER_RPAGES,
 				       adapter_handle.handle,      /* r4  */
-				       queue_type | pagesize << 8, /* r5  */
+				       (u64)queue_type | ((u64)pagesize) << 8,
+				       /* r5  */
 				       resource_handle,	           /* r6  */
 				       logical_address_of_page,    /* r7  */
 				       count,	                   /* r8  */
@@ -496,13 +510,13 @@
 			     const u64 count,
 			     const struct h_galpa galpa)
 {
-	if (count != 1) {
+	if (count > 1) {
 		ehca_gen_err("Page counter=%lx", count);
 		return H_PARAMETER;
 	}
 
-	return hipz_h_register_rpage(adapter_handle,pagesize,queue_type,
-				     qp_handle.handle,logical_address_of_page,
+	return hipz_h_register_rpage(adapter_handle, pagesize, queue_type,
+				     qp_handle.handle, logical_address_of_page,
 				     count);
 }
 
@@ -522,9 +536,9 @@
 				qp_handle.handle,	   /* r6 */
 				0, 0, 0, 0, 0, 0);
 	if (log_addr_next_sq_wqe2processed)
-		*log_addr_next_sq_wqe2processed = (void*)outs[0];
+		*log_addr_next_sq_wqe2processed = (void *)outs[0];
 	if (log_addr_next_rq_wqe2processed)
-		*log_addr_next_rq_wqe2processed = (void*)outs[1];
+		*log_addr_next_rq_wqe2processed = (void *)outs[1];
 
 	return ret;
 }
@@ -546,7 +560,7 @@
 				0, 0, 0, 0, 0);
 
 	if (ret == H_NOT_ENOUGH_RESOURCES)
-		ehca_gen_err("Insufficient resources ret=%lx", ret);
+		ehca_gen_err("Insufficient resources ret=%li", ret);
 
 	return ret;
 }
@@ -582,7 +596,7 @@
 				qp->ipz_qp_handle.handle,  /* r6 */
 				0, 0, 0, 0, 0, 0);
 	if (ret == H_HARDWARE)
-		ehca_gen_err("HCA not operational. ret=%lx", ret);
+		ehca_gen_err("HCA not operational. ret=%li", ret);
 
 	ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE,
 				      adapter_handle.handle,     /* r4 */
@@ -590,7 +604,7 @@
 				      0, 0, 0, 0, 0);
 
 	if (ret == H_RESOURCE)
-		ehca_gen_err("Resource still in use. ret=%lx", ret);
+		ehca_gen_err("Resource still in use. ret=%li", ret);
 
 	return ret;
 }
@@ -625,7 +639,7 @@
 	*bma_qp_nr = (u32)outs[1];
 
 	if (ret == H_ALIAS_EXIST)
-		ehca_gen_err("AQP1 already exists. ret=%lx", ret);
+		ehca_gen_err("AQP1 already exists. ret=%li", ret);
 
 	return ret;
 }
@@ -647,7 +661,7 @@
 				      0, 0);
 
 	if (ret == H_NOT_ENOUGH_RESOURCES)
-		ehca_gen_err("Not enough resources. ret=%lx", ret);
+		ehca_gen_err("Not enough resources. ret=%li", ret);
 
 	return ret;
 }
@@ -686,7 +700,7 @@
 				      0, 0, 0, 0);
 
 	if (ret == H_RESOURCE)
-		ehca_gen_err("H_FREE_RESOURCE failed ret=%lx ", ret);
+		ehca_gen_err("H_FREE_RESOURCE failed ret=%li ", ret);
 
 	return ret;
 }
@@ -708,7 +722,7 @@
 				      0, 0, 0, 0, 0);
 
 	if (ret == H_RESOURCE)
-		ehca_gen_err("Resource in use. ret=%lx ", ret);
+		ehca_gen_err("Resource in use. ret=%li ", ret);
 
 	return ret;
 }
@@ -724,6 +738,9 @@
 	u64 ret;
 	u64 outs[PLPAR_HCALL9_BUFSIZE];
 
+	ehca_gen_dbg("kernel PAGE_SIZE=%x access_ctrl=%016x "
+		     "vaddr=%lx length=%lx",
+		     (u32)PAGE_SIZE, access_ctrl, vaddr, length);
 	ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
 				adapter_handle.handle,            /* r4 */
 				5,                                /* r5 */
@@ -748,6 +765,19 @@
 {
 	u64 ret;
 
+	if (unlikely(ehca_debug_level >= 2)) {
+		if (count > 1) {
+			u64 *kpage;
+			int i;
+			kpage = (u64 *)abs_to_virt(logical_address_of_page);
+			for (i = 0; i < count; i++)
+				ehca_gen_dbg("kpage[%d]=%p",
+					     i, (void *)kpage[i]);
+		} else
+			ehca_gen_dbg("kpage=%p",
+				     (void *)logical_address_of_page);
+	}
+
 	if ((count > 1) && (logical_address_of_page & (EHCA_PAGESIZE-1))) {
 		ehca_gen_err("logical_address_of_page not on a 4k boundary "
 			     "adapter_handle=%lx mr=%p mr_handle=%lx "
@@ -791,7 +821,7 @@
 	return ehca_plpar_hcall_norets(H_FREE_RESOURCE,
 				       adapter_handle.handle,    /* r4 */
 				       mr->ipz_mr_handle.handle, /* r5 */
-				       0, 0, 0, 0, 0);
+				       0, 0, 0, 0, 5);
 }
 
 u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle,
diff --git a/drivers/infiniband/hw/ehca/hcp_phyp.c b/drivers/infiniband/hw/ehca/hcp_phyp.c
index 0b1a477..2148210 100644
--- a/drivers/infiniband/hw/ehca/hcp_phyp.c
+++ b/drivers/infiniband/hw/ehca/hcp_phyp.c
@@ -50,7 +50,7 @@
 
 int hcall_unmap_page(u64 mapaddr)
 {
-	iounmap((volatile void __iomem*)mapaddr);
+	iounmap((volatile void __iomem *) mapaddr);
 	return 0;
 }
 
diff --git a/drivers/infiniband/hw/ehca/hipz_fns_core.h b/drivers/infiniband/hw/ehca/hipz_fns_core.h
index 20898a1..868735f 100644
--- a/drivers/infiniband/hw/ehca/hipz_fns_core.h
+++ b/drivers/infiniband/hw/ehca/hipz_fns_core.h
@@ -53,10 +53,10 @@
 #define hipz_galpa_load_cq(gal, offset) \
 	hipz_galpa_load(gal, CQTEMM_OFFSET(offset))
 
-#define hipz_galpa_store_qp(gal,offset, value) \
+#define hipz_galpa_store_qp(gal, offset, value) \
 	hipz_galpa_store(gal, QPTEMM_OFFSET(offset), value)
 #define hipz_galpa_load_qp(gal, offset) \
-	hipz_galpa_load(gal,QPTEMM_OFFSET(offset))
+	hipz_galpa_load(gal, QPTEMM_OFFSET(offset))
 
 static inline void hipz_update_sqa(struct ehca_qp *qp, u16 nr_wqes)
 {
diff --git a/drivers/infiniband/hw/ehca/hipz_hw.h b/drivers/infiniband/hw/ehca/hipz_hw.h
index dad6dea..d9739e5 100644
--- a/drivers/infiniband/hw/ehca/hipz_hw.h
+++ b/drivers/infiniband/hw/ehca/hipz_hw.h
@@ -161,11 +161,11 @@
 /* 0x1000      */
 };
 
-#define QPX_SQADDER EHCA_BMASK_IBM(48,63)
-#define QPX_RQADDER EHCA_BMASK_IBM(48,63)
-#define QPX_AAELOG_RESET_SRQ_LIMIT EHCA_BMASK_IBM(3,3)
+#define QPX_SQADDER EHCA_BMASK_IBM(48, 63)
+#define QPX_RQADDER EHCA_BMASK_IBM(48, 63)
+#define QPX_AAELOG_RESET_SRQ_LIMIT EHCA_BMASK_IBM(3, 3)
 
-#define QPTEMM_OFFSET(x) offsetof(struct hipz_qptemm,x)
+#define QPTEMM_OFFSET(x) offsetof(struct hipz_qptemm, x)
 
 /* MRMWPT Entry Memory Map */
 struct hipz_mrmwmm {
@@ -187,7 +187,7 @@
 
 };
 
-#define MRMWMM_OFFSET(x) offsetof(struct hipz_mrmwmm,x)
+#define MRMWMM_OFFSET(x) offsetof(struct hipz_mrmwmm, x)
 
 struct hipz_qpedmm {
 	/* 0x00 */
@@ -238,7 +238,7 @@
 	u64 qpedx_rrva3;
 };
 
-#define QPEDMM_OFFSET(x) offsetof(struct hipz_qpedmm,x)
+#define QPEDMM_OFFSET(x) offsetof(struct hipz_qpedmm, x)
 
 /* CQ Table Entry Memory Map */
 struct hipz_cqtemm {
@@ -263,12 +263,12 @@
 /* 0x1000 */
 };
 
-#define CQX_FEC_CQE_CNT           EHCA_BMASK_IBM(32,63)
-#define CQX_FECADDER              EHCA_BMASK_IBM(32,63)
-#define CQX_N0_GENERATE_SOLICITED_COMP_EVENT EHCA_BMASK_IBM(0,0)
-#define CQX_N1_GENERATE_COMP_EVENT EHCA_BMASK_IBM(0,0)
+#define CQX_FEC_CQE_CNT           EHCA_BMASK_IBM(32, 63)
+#define CQX_FECADDER              EHCA_BMASK_IBM(32, 63)
+#define CQX_N0_GENERATE_SOLICITED_COMP_EVENT EHCA_BMASK_IBM(0, 0)
+#define CQX_N1_GENERATE_COMP_EVENT EHCA_BMASK_IBM(0, 0)
 
-#define CQTEMM_OFFSET(x) offsetof(struct hipz_cqtemm,x)
+#define CQTEMM_OFFSET(x) offsetof(struct hipz_cqtemm, x)
 
 /* EQ Table Entry Memory Map */
 struct hipz_eqtemm {
@@ -293,7 +293,7 @@
 
 };
 
-#define EQTEMM_OFFSET(x) offsetof(struct hipz_eqtemm,x)
+#define EQTEMM_OFFSET(x) offsetof(struct hipz_eqtemm, x)
 
 /* access control defines for MR/MW */
 #define HIPZ_ACCESSCTRL_L_WRITE  0x00800000
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.c b/drivers/infiniband/hw/ehca/ipz_pt_fn.c
index bf7a400..661f8db 100644
--- a/drivers/infiniband/hw/ehca/ipz_pt_fn.c
+++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.c
@@ -40,6 +40,11 @@
 
 #include "ehca_tools.h"
 #include "ipz_pt_fn.h"
+#include "ehca_classes.h"
+
+#define PAGES_PER_KPAGE (PAGE_SIZE >> EHCA_PAGESHIFT)
+
+struct kmem_cache *small_qp_cache;
 
 void *ipz_qpageit_get_inc(struct ipz_queue *queue)
 {
@@ -49,7 +54,7 @@
 		queue->current_q_offset -= queue->pagesize;
 		ret = NULL;
 	}
-	if (((u64)ret) % EHCA_PAGESIZE) {
+	if (((u64)ret) % queue->pagesize) {
 		ehca_gen_err("ERROR!! not at PAGE-Boundary");
 		return NULL;
 	}
@@ -83,80 +88,196 @@
 	return -EINVAL;
 }
 
-int ipz_queue_ctor(struct ipz_queue *queue,
-		   const u32 nr_of_pages,
-		   const u32 pagesize, const u32 qe_size, const u32 nr_of_sg)
-{
-	int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT;
-	int f;
+#if PAGE_SHIFT < EHCA_PAGESHIFT
+#error Kernel pages must be at least as large than eHCA pages (4K) !
+#endif
 
-	if (pagesize > PAGE_SIZE) {
-		ehca_gen_err("FATAL ERROR: pagesize=%x is greater "
-			     "than kernel page size", pagesize);
-		return 0;
-	}
-	if (!pages_per_kpage) {
-		ehca_gen_err("FATAL ERROR: invalid kernel page size. "
-			     "pages_per_kpage=%x", pages_per_kpage);
-		return 0;
-	}
-	queue->queue_length = nr_of_pages * pagesize;
-	queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
-	if (!queue->queue_pages) {
-		ehca_gen_err("ERROR!! didn't get the memory");
-		return 0;
-	}
-	memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *));
-	/*
-	 * allocate pages for queue:
-	 * outer loop allocates whole kernel pages (page aligned) and
-	 * inner loop divides a kernel page into smaller hca queue pages
-	 */
-	f = 0;
+/*
+ * allocate pages for queue:
+ * outer loop allocates whole kernel pages (page aligned) and
+ * inner loop divides a kernel page into smaller hca queue pages
+ */
+static int alloc_queue_pages(struct ipz_queue *queue, const u32 nr_of_pages)
+{
+	int k, f = 0;
+	u8 *kpage;
+
 	while (f < nr_of_pages) {
-		u8 *kpage = (u8*)get_zeroed_page(GFP_KERNEL);
-		int k;
+		kpage = (u8 *)get_zeroed_page(GFP_KERNEL);
 		if (!kpage)
-			goto ipz_queue_ctor_exit0; /*NOMEM*/
-		for (k = 0; k < pages_per_kpage && f < nr_of_pages; k++) {
-			(queue->queue_pages)[f] = (struct ipz_page *)kpage;
+			goto out;
+
+		for (k = 0; k < PAGES_PER_KPAGE && f < nr_of_pages; k++) {
+			queue->queue_pages[f] = (struct ipz_page *)kpage;
 			kpage += EHCA_PAGESIZE;
 			f++;
 		}
 	}
-
-	queue->current_q_offset = 0;
-	queue->qe_size = qe_size;
-	queue->act_nr_of_sg = nr_of_sg;
-	queue->pagesize = pagesize;
-	queue->toggle_state = 1;
 	return 1;
 
- ipz_queue_ctor_exit0:
-	ehca_gen_err("Couldn't get alloc pages queue=%p f=%x nr_of_pages=%x",
-		     queue, f, nr_of_pages);
-	for (f = 0; f < nr_of_pages; f += pages_per_kpage) {
-		if (!(queue->queue_pages)[f])
-			break;
+out:
+	for (f = 0; f < nr_of_pages && queue->queue_pages[f];
+	     f += PAGES_PER_KPAGE)
 		free_page((unsigned long)(queue->queue_pages)[f]);
-	}
 	return 0;
 }
 
-int ipz_queue_dtor(struct ipz_queue *queue)
+static int alloc_small_queue_page(struct ipz_queue *queue, struct ehca_pd *pd)
 {
-	int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT;
-	int g;
-	int nr_pages;
+	int order = ilog2(queue->pagesize) - 9;
+	struct ipz_small_queue_page *page;
+	unsigned long bit;
+
+	mutex_lock(&pd->lock);
+
+	if (!list_empty(&pd->free[order]))
+		page = list_entry(pd->free[order].next,
+				  struct ipz_small_queue_page, list);
+	else {
+		page = kmem_cache_zalloc(small_qp_cache, GFP_KERNEL);
+		if (!page)
+			goto out;
+
+		page->page = get_zeroed_page(GFP_KERNEL);
+		if (!page->page) {
+			kmem_cache_free(small_qp_cache, page);
+			goto out;
+		}
+
+		list_add(&page->list, &pd->free[order]);
+	}
+
+	bit = find_first_zero_bit(page->bitmap, IPZ_SPAGE_PER_KPAGE >> order);
+	__set_bit(bit, page->bitmap);
+	page->fill++;
+
+	if (page->fill == IPZ_SPAGE_PER_KPAGE >> order)
+		list_move(&page->list, &pd->full[order]);
+
+	mutex_unlock(&pd->lock);
+
+	queue->queue_pages[0] = (void *)(page->page | (bit << (order + 9)));
+	queue->small_page = page;
+	queue->offset = bit << (order + 9);
+	return 1;
+
+out:
+	ehca_err(pd->ib_pd.device, "failed to allocate small queue page");
+	return 0;
+}
+
+static void free_small_queue_page(struct ipz_queue *queue, struct ehca_pd *pd)
+{
+	int order = ilog2(queue->pagesize) - 9;
+	struct ipz_small_queue_page *page = queue->small_page;
+	unsigned long bit;
+	int free_page = 0;
+
+	bit = ((unsigned long)queue->queue_pages[0] & ~PAGE_MASK)
+		>> (order + 9);
+
+	mutex_lock(&pd->lock);
+
+	__clear_bit(bit, page->bitmap);
+	page->fill--;
+
+	if (page->fill == 0) {
+		list_del(&page->list);
+		free_page = 1;
+	}
+
+	if (page->fill == (IPZ_SPAGE_PER_KPAGE >> order) - 1)
+		/* the page was full until we freed the chunk */
+		list_move_tail(&page->list, &pd->free[order]);
+
+	mutex_unlock(&pd->lock);
+
+	if (free_page) {
+		free_page(page->page);
+		kmem_cache_free(small_qp_cache, page);
+	}
+}
+
+int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue,
+		   const u32 nr_of_pages, const u32 pagesize,
+		   const u32 qe_size, const u32 nr_of_sg,
+		   int is_small)
+{
+	if (pagesize > PAGE_SIZE) {
+		ehca_gen_err("FATAL ERROR: pagesize=%x "
+			     "is greater than kernel page size", pagesize);
+		return 0;
+	}
+
+	/* init queue fields */
+	queue->queue_length = nr_of_pages * pagesize;
+	queue->pagesize = pagesize;
+	queue->qe_size = qe_size;
+	queue->act_nr_of_sg = nr_of_sg;
+	queue->current_q_offset = 0;
+	queue->toggle_state = 1;
+	queue->small_page = NULL;
+
+	/* allocate queue page pointers */
+	queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
+	if (!queue->queue_pages) {
+		ehca_gen_err("Couldn't allocate queue page list");
+		return 0;
+	}
+	memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *));
+
+	/* allocate actual queue pages */
+	if (is_small) {
+		if (!alloc_small_queue_page(queue, pd))
+			goto ipz_queue_ctor_exit0;
+	} else
+		if (!alloc_queue_pages(queue, nr_of_pages))
+			goto ipz_queue_ctor_exit0;
+
+	return 1;
+
+ipz_queue_ctor_exit0:
+	ehca_gen_err("Couldn't alloc pages queue=%p "
+		 "nr_of_pages=%x",  queue, nr_of_pages);
+	vfree(queue->queue_pages);
+
+	return 0;
+}
+
+int ipz_queue_dtor(struct ehca_pd *pd, struct ipz_queue *queue)
+{
+	int i, nr_pages;
 
 	if (!queue || !queue->queue_pages) {
 		ehca_gen_dbg("queue or queue_pages is NULL");
 		return 0;
 	}
-	nr_pages = queue->queue_length / queue->pagesize;
-	for (g = 0; g < nr_pages; g += pages_per_kpage)
-		free_page((unsigned long)(queue->queue_pages)[g]);
+
+	if (queue->small_page)
+		free_small_queue_page(queue, pd);
+	else {
+		nr_pages = queue->queue_length / queue->pagesize;
+		for (i = 0; i < nr_pages; i += PAGES_PER_KPAGE)
+			free_page((unsigned long)queue->queue_pages[i]);
+	}
+
 	vfree(queue->queue_pages);
 
 	return 1;
 }
+
+int ehca_init_small_qp_cache(void)
+{
+	small_qp_cache = kmem_cache_create("ehca_cache_small_qp",
+					   sizeof(struct ipz_small_queue_page),
+					   0, SLAB_HWCACHE_ALIGN, NULL);
+	if (!small_qp_cache)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void ehca_cleanup_small_qp_cache(void)
+{
+	kmem_cache_destroy(small_qp_cache);
+}
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.h b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
index 007f088..a801274 100644
--- a/drivers/infiniband/hw/ehca/ipz_pt_fn.h
+++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
@@ -51,11 +51,27 @@
 #include "ehca_tools.h"
 #include "ehca_qes.h"
 
+struct ehca_pd;
+struct ipz_small_queue_page;
+
+extern struct kmem_cache *small_qp_cache;
+
 /* struct generic ehca page */
 struct ipz_page {
 	u8 entries[EHCA_PAGESIZE];
 };
 
+#define IPZ_SPAGE_PER_KPAGE (PAGE_SIZE / 512)
+
+struct ipz_small_queue_page {
+	unsigned long page;
+	unsigned long bitmap[IPZ_SPAGE_PER_KPAGE / BITS_PER_LONG];
+	int fill;
+	void *mapped_addr;
+	u32 mmap_count;
+	struct list_head list;
+};
+
 /* struct generic queue in linux kernel virtual memory (kv) */
 struct ipz_queue {
 	u64 current_q_offset;	/* current queue entry */
@@ -66,7 +82,8 @@
 	u32 queue_length;	/* queue length allocated in bytes */
 	u32 pagesize;
 	u32 toggle_state;	/* toggle flag - per page */
-	u32 dummy3;		/* 64 bit alignment */
+	u32 offset; /* save offset within page for small_qp */
+	struct ipz_small_queue_page *small_page;
 };
 
 /*
@@ -188,9 +205,10 @@
  * see ipz_qpt_ctor()
  * returns true if ok, false if out of memory
  */
-int ipz_queue_ctor(struct ipz_queue *queue, const u32 nr_of_pages,
-		   const u32 pagesize, const u32 qe_size,
-		   const u32 nr_of_sg);
+int ipz_queue_ctor(struct ehca_pd *pd, struct ipz_queue *queue,
+		   const u32 nr_of_pages, const u32 pagesize,
+		   const u32 qe_size, const u32 nr_of_sg,
+		   int is_small);
 
 /*
  * destructor for a ipz_queue_t
@@ -198,7 +216,7 @@
  *  see ipz_queue_ctor()
  *  returns true if ok, false if queue was NULL-ptr of free failed
  */
-int ipz_queue_dtor(struct ipz_queue *queue);
+int ipz_queue_dtor(struct ehca_pd *pd, struct ipz_queue *queue);
 
 /*
  * constructor for a ipz_qpt_t,
@@ -240,7 +258,7 @@
 static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
 {
 	void *ret = ipz_qeit_get(queue);
-	u32 qe = *(u8 *) ret;
+	u32 qe = *(u8 *)ret;
 	if ((qe >> 7) != (queue->toggle_state & 1))
 		return NULL;
 	ipz_qeit_eq_get_inc(queue); /* this is a good one */
@@ -250,7 +268,7 @@
 static inline void *ipz_eqit_eq_peek_valid(struct ipz_queue *queue)
 {
 	void *ret = ipz_qeit_get(queue);
-	u32 qe = *(u8 *) ret;
+	u32 qe = *(u8 *)ret;
 	if ((qe >> 7) != (queue->toggle_state & 1))
 		return NULL;
 	return ret;
diff --git a/drivers/infiniband/hw/ipath/Makefile b/drivers/infiniband/hw/ipath/Makefile
index ec2e603..fe67388 100644
--- a/drivers/infiniband/hw/ipath/Makefile
+++ b/drivers/infiniband/hw/ipath/Makefile
@@ -14,7 +14,6 @@
 	ipath_init_chip.o \
 	ipath_intr.o \
 	ipath_keys.o \
-	ipath_layer.o \
 	ipath_mad.o \
 	ipath_mmap.o \
 	ipath_mr.o \
diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h
index b4b786d..851df8a 100644
--- a/drivers/infiniband/hw/ipath/ipath_common.h
+++ b/drivers/infiniband/hw/ipath/ipath_common.h
@@ -100,8 +100,7 @@
 	__u64 sps_hwerrs;
 	/* number of times IB link changed state unexpectedly */
 	__u64 sps_iblink;
-	/* kernel receive interrupts that didn't read intstat */
-	__u64 sps_fastrcvint;
+	__u64 sps_unused; /* was fastrcvint, no longer implemented */
 	/* number of kernel (port0) packets received */
 	__u64 sps_port0pkts;
 	/* number of "ethernet" packets sent by driver */
@@ -190,6 +189,8 @@
 #define IPATH_RUNTIME_RCVHDR_COPY	0x8
 #define IPATH_RUNTIME_MASTER	0x10
 /* 0x20 and 0x40 are no longer used, but are reserved for ABI compatibility */
+#define IPATH_RUNTIME_FORCE_PIOAVAIL 0x400
+#define IPATH_RUNTIME_PIO_REGSWAPPED 0x800
 
 /*
  * This structure is returned by ipath_userinit() immediately after
@@ -351,7 +352,7 @@
  * may not be implemented; the user code must deal with this if it
  * cares, or it must abort after initialization reports the difference.
  */
-#define IPATH_USER_SWMINOR 5
+#define IPATH_USER_SWMINOR 6
 
 #define IPATH_USER_SWVERSION ((IPATH_USER_SWMAJOR<<16) | IPATH_USER_SWMINOR)
 
diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c
index a6f04d2..645ed71 100644
--- a/drivers/infiniband/hw/ipath/ipath_cq.c
+++ b/drivers/infiniband/hw/ipath/ipath_cq.c
@@ -76,22 +76,25 @@
 		}
 		return;
 	}
-	wc->queue[head].wr_id = entry->wr_id;
-	wc->queue[head].status = entry->status;
-	wc->queue[head].opcode = entry->opcode;
-	wc->queue[head].vendor_err = entry->vendor_err;
-	wc->queue[head].byte_len = entry->byte_len;
-	wc->queue[head].imm_data = (__u32 __force)entry->imm_data;
-	wc->queue[head].qp_num = entry->qp->qp_num;
-	wc->queue[head].src_qp = entry->src_qp;
-	wc->queue[head].wc_flags = entry->wc_flags;
-	wc->queue[head].pkey_index = entry->pkey_index;
-	wc->queue[head].slid = entry->slid;
-	wc->queue[head].sl = entry->sl;
-	wc->queue[head].dlid_path_bits = entry->dlid_path_bits;
-	wc->queue[head].port_num = entry->port_num;
-	/* Make sure queue entry is written before the head index. */
-	smp_wmb();
+	if (cq->ip) {
+		wc->uqueue[head].wr_id = entry->wr_id;
+		wc->uqueue[head].status = entry->status;
+		wc->uqueue[head].opcode = entry->opcode;
+		wc->uqueue[head].vendor_err = entry->vendor_err;
+		wc->uqueue[head].byte_len = entry->byte_len;
+		wc->uqueue[head].imm_data = (__u32 __force)entry->imm_data;
+		wc->uqueue[head].qp_num = entry->qp->qp_num;
+		wc->uqueue[head].src_qp = entry->src_qp;
+		wc->uqueue[head].wc_flags = entry->wc_flags;
+		wc->uqueue[head].pkey_index = entry->pkey_index;
+		wc->uqueue[head].slid = entry->slid;
+		wc->uqueue[head].sl = entry->sl;
+		wc->uqueue[head].dlid_path_bits = entry->dlid_path_bits;
+		wc->uqueue[head].port_num = entry->port_num;
+		/* Make sure entry is written before the head index. */
+		smp_wmb();
+	} else
+		wc->kqueue[head] = *entry;
 	wc->head = next;
 
 	if (cq->notify == IB_CQ_NEXT_COMP ||
@@ -130,6 +133,12 @@
 	int npolled;
 	u32 tail;
 
+	/* The kernel can only poll a kernel completion queue */
+	if (cq->ip) {
+		npolled = -EINVAL;
+		goto bail;
+	}
+
 	spin_lock_irqsave(&cq->lock, flags);
 
 	wc = cq->queue;
@@ -137,31 +146,10 @@
 	if (tail > (u32) cq->ibcq.cqe)
 		tail = (u32) cq->ibcq.cqe;
 	for (npolled = 0; npolled < num_entries; ++npolled, ++entry) {
-		struct ipath_qp *qp;
-
 		if (tail == wc->head)
 			break;
-		/* Make sure entry is read after head index is read. */
-		smp_rmb();
-		qp = ipath_lookup_qpn(&to_idev(cq->ibcq.device)->qp_table,
-				      wc->queue[tail].qp_num);
-		entry->qp = &qp->ibqp;
-		if (atomic_dec_and_test(&qp->refcount))
-			wake_up(&qp->wait);
-
-		entry->wr_id = wc->queue[tail].wr_id;
-		entry->status = wc->queue[tail].status;
-		entry->opcode = wc->queue[tail].opcode;
-		entry->vendor_err = wc->queue[tail].vendor_err;
-		entry->byte_len = wc->queue[tail].byte_len;
-		entry->imm_data = wc->queue[tail].imm_data;
-		entry->src_qp = wc->queue[tail].src_qp;
-		entry->wc_flags = wc->queue[tail].wc_flags;
-		entry->pkey_index = wc->queue[tail].pkey_index;
-		entry->slid = wc->queue[tail].slid;
-		entry->sl = wc->queue[tail].sl;
-		entry->dlid_path_bits = wc->queue[tail].dlid_path_bits;
-		entry->port_num = wc->queue[tail].port_num;
+		/* The kernel doesn't need a RMB since it has the lock. */
+		*entry = wc->kqueue[tail];
 		if (tail >= cq->ibcq.cqe)
 			tail = 0;
 		else
@@ -171,6 +159,7 @@
 
 	spin_unlock_irqrestore(&cq->lock, flags);
 
+bail:
 	return npolled;
 }
 
@@ -215,6 +204,7 @@
 	struct ipath_cq *cq;
 	struct ipath_cq_wc *wc;
 	struct ib_cq *ret;
+	u32 sz;
 
 	if (entries < 1 || entries > ib_ipath_max_cqes) {
 		ret = ERR_PTR(-EINVAL);
@@ -235,7 +225,12 @@
 	 * We need to use vmalloc() in order to support mmap and large
 	 * numbers of entries.
 	 */
-	wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * entries);
+	sz = sizeof(*wc);
+	if (udata && udata->outlen >= sizeof(__u64))
+		sz += sizeof(struct ib_uverbs_wc) * (entries + 1);
+	else
+		sz += sizeof(struct ib_wc) * (entries + 1);
+	wc = vmalloc_user(sz);
 	if (!wc) {
 		ret = ERR_PTR(-ENOMEM);
 		goto bail_cq;
@@ -247,9 +242,8 @@
 	 */
 	if (udata && udata->outlen >= sizeof(__u64)) {
 		int err;
-		u32 s = sizeof *wc + sizeof(struct ib_wc) * entries;
 
-		cq->ip = ipath_create_mmap_info(dev, s, context, wc);
+		cq->ip = ipath_create_mmap_info(dev, sz, context, wc);
 		if (!cq->ip) {
 			ret = ERR_PTR(-ENOMEM);
 			goto bail_wc;
@@ -380,6 +374,7 @@
 	struct ipath_cq_wc *wc;
 	u32 head, tail, n;
 	int ret;
+	u32 sz;
 
 	if (cqe < 1 || cqe > ib_ipath_max_cqes) {
 		ret = -EINVAL;
@@ -389,7 +384,12 @@
 	/*
 	 * Need to use vmalloc() if we want to support large #s of entries.
 	 */
-	wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * cqe);
+	sz = sizeof(*wc);
+	if (udata && udata->outlen >= sizeof(__u64))
+		sz += sizeof(struct ib_uverbs_wc) * (cqe + 1);
+	else
+		sz += sizeof(struct ib_wc) * (cqe + 1);
+	wc = vmalloc_user(sz);
 	if (!wc) {
 		ret = -ENOMEM;
 		goto bail;
@@ -430,7 +430,10 @@
 		goto bail;
 	}
 	for (n = 0; tail != head; n++) {
-		wc->queue[n] = old_wc->queue[tail];
+		if (cq->ip)
+			wc->uqueue[n] = old_wc->uqueue[tail];
+		else
+			wc->kqueue[n] = old_wc->kqueue[tail];
 		if (tail == (u32) cq->ibcq.cqe)
 			tail = 0;
 		else
@@ -447,9 +450,8 @@
 	if (cq->ip) {
 		struct ipath_ibdev *dev = to_idev(ibcq->device);
 		struct ipath_mmap_info *ip = cq->ip;
-		u32 s = sizeof *wc + sizeof(struct ib_wc) * cqe;
 
-		ipath_update_mmap_info(dev, ip, s, wc);
+		ipath_update_mmap_info(dev, ip, sz, wc);
 		spin_lock_irq(&dev->pending_lock);
 		if (list_empty(&ip->pending_mmaps))
 			list_add(&ip->pending_mmaps, &dev->pending_mmaps);
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c
index a698f19..4137c77 100644
--- a/drivers/infiniband/hw/ipath/ipath_diag.c
+++ b/drivers/infiniband/hw/ipath/ipath_diag.c
@@ -44,6 +44,7 @@
 #include <linux/io.h>
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
+#include <linux/fs.h>
 #include <asm/uaccess.h>
 
 #include "ipath_kernel.h"
@@ -445,19 +446,21 @@
 			   dd->ipath_unit, plen - 1, pbufn);
 
 	if (dp.pbc_wd == 0)
-		/* Legacy operation, use computed pbc_wd */
 		dp.pbc_wd = plen;
-
-	/* we have to flush after the PBC for correctness on some cpus
-	 * or WC buffer can be written out of order */
 	writeq(dp.pbc_wd, piobuf);
-	ipath_flush_wc();
-	/* copy all by the trigger word, then flush, so it's written
+	/*
+	 * Copy all by the trigger word, then flush, so it's written
 	 * to chip before trigger word, then write trigger word, then
-	 * flush again, so packet is sent. */
-	__iowrite32_copy(piobuf + 2, tmpbuf, clen - 1);
-	ipath_flush_wc();
-	__raw_writel(tmpbuf[clen - 1], piobuf + clen + 1);
+	 * flush again, so packet is sent.
+	 */
+	if (dd->ipath_flags & IPATH_PIO_FLUSH_WC) {
+		ipath_flush_wc();
+		__iowrite32_copy(piobuf + 2, tmpbuf, clen - 1);
+		ipath_flush_wc();
+		__raw_writel(tmpbuf[clen - 1], piobuf + clen + 1);
+	} else
+		__iowrite32_copy(piobuf + 2, tmpbuf, clen);
+
 	ipath_flush_wc();
 
 	ret = sizeof(dp);
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index 9361f5a..1f152de 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -34,6 +34,7 @@
 #include <linux/spinlock.h>
 #include <linux/idr.h>
 #include <linux/pci.h>
+#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
 #include <linux/vmalloc.h>
@@ -280,6 +281,89 @@
 {
 }
 
+/*
+ * Perform a PIO buffer bandwidth write test, to verify proper system
+ * configuration.  Even when all the setup calls work, occasionally
+ * BIOS or other issues can prevent write combining from working, or
+ * can cause other bandwidth problems to the chip.
+ *
+ * This test simply writes the same buffer over and over again, and
+ * measures close to the peak bandwidth to the chip (not testing
+ * data bandwidth to the wire).   On chips that use an address-based
+ * trigger to send packets to the wire, this is easy.  On chips that
+ * use a count to trigger, we want to make sure that the packet doesn't
+ * go out on the wire, or trigger flow control checks.
+ */
+static void ipath_verify_pioperf(struct ipath_devdata *dd)
+{
+	u32 pbnum, cnt, lcnt;
+	u32 __iomem *piobuf;
+	u32 *addr;
+	u64 msecs, emsecs;
+
+	piobuf = ipath_getpiobuf(dd, &pbnum);
+	if (!piobuf) {
+		dev_info(&dd->pcidev->dev,
+			"No PIObufs for checking perf, skipping\n");
+		return;
+	}
+
+	/*
+	 * Enough to give us a reasonable test, less than piobuf size, and
+	 * likely multiple of store buffer length.
+	 */
+	cnt = 1024;
+
+	addr = vmalloc(cnt);
+	if (!addr) {
+		dev_info(&dd->pcidev->dev,
+			"Couldn't get memory for checking PIO perf,"
+			" skipping\n");
+		goto done;
+	}
+
+	preempt_disable();  /* we want reasonably accurate elapsed time */
+	msecs = 1 + jiffies_to_msecs(jiffies);
+	for (lcnt = 0; lcnt < 10000U; lcnt++) {
+		/* wait until we cross msec boundary */
+		if (jiffies_to_msecs(jiffies) >= msecs)
+			break;
+		udelay(1);
+	}
+
+	writeq(0, piobuf); /* length 0, no dwords actually sent */
+	ipath_flush_wc();
+
+	/*
+	 * this is only roughly accurate, since even with preempt we
+	 * still take interrupts that could take a while.   Running for
+	 * >= 5 msec seems to get us "close enough" to accurate values
+	 */
+	msecs = jiffies_to_msecs(jiffies);
+	for (emsecs = lcnt = 0; emsecs <= 5UL; lcnt++) {
+		__iowrite32_copy(piobuf + 64, addr, cnt >> 2);
+		emsecs = jiffies_to_msecs(jiffies) - msecs;
+	}
+
+	/* 1 GiB/sec, slightly over IB SDR line rate */
+	if (lcnt < (emsecs * 1024U))
+		ipath_dev_err(dd,
+			"Performance problem: bandwidth to PIO buffers is "
+			"only %u MiB/sec\n",
+			lcnt / (u32) emsecs);
+	else
+		ipath_dbg("PIO buffer bandwidth %u MiB/sec is OK\n",
+			lcnt / (u32) emsecs);
+
+	preempt_enable();
+
+	vfree(addr);
+
+done:
+	/* disarm piobuf, so it's available again */
+	ipath_disarm_piobufs(dd, pbnum, 1);
+}
+
 static int __devinit ipath_init_one(struct pci_dev *pdev,
 				    const struct pci_device_id *ent)
 {
@@ -298,8 +382,6 @@
 
 	ipath_cdbg(VERBOSE, "initializing unit #%u\n", dd->ipath_unit);
 
-	read_bars(dd, pdev, &bar0, &bar1);
-
 	ret = pci_enable_device(pdev);
 	if (ret) {
 		/* This can happen iff:
@@ -445,9 +527,6 @@
 		goto bail_regions;
 	}
 
-	dd->ipath_deviceid = ent->device;	/* save for later use */
-	dd->ipath_vendorid = ent->vendor;
-
 	dd->ipath_pcirev = pdev->revision;
 
 #if defined(__powerpc__)
@@ -515,6 +594,8 @@
 		ret = 0;
 	}
 
+	ipath_verify_pioperf(dd);
+
 	ipath_device_create_group(&pdev->dev, dd);
 	ipathfs_add_device(dd);
 	ipath_user_add(dd);
@@ -740,7 +821,7 @@
 	 * pioavail updates to memory to stop.
 	 */
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-			 sendorig & ~IPATH_S_PIOBUFAVAILUPD);
+			 sendorig & ~INFINIPATH_S_PIOBUFAVAILUPD);
 	sendorig = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
 			 dd->ipath_sendctrl);
@@ -1614,7 +1695,7 @@
  * it's safer to always do it.
  * PIOAvail bits are updated by the chip as if normal send had happened.
  */
-void ipath_cancel_sends(struct ipath_devdata *dd)
+void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl)
 {
 	ipath_dbg("Cancelling all in-progress send buffers\n");
 	dd->ipath_lastcancel = jiffies+HZ/2; /* skip armlaunch errs a bit */
@@ -1627,6 +1708,9 @@
 	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
 	ipath_disarm_piobufs(dd, 0,
 		(unsigned)(dd->ipath_piobcnt2k + dd->ipath_piobcnt4k));
+	if (restore_sendctrl) /* else done by caller later */
+		ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+				 dd->ipath_sendctrl);
 
 	/* and again, be sure all have hit the chip */
 	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
@@ -1655,7 +1739,7 @@
 	/* flush all queued sends when going to DOWN or INIT, to be sure that
 	 * they don't block MAD packets */
 	if (!linkcmd || linkcmd == INFINIPATH_IBCC_LINKCMD_INIT)
-		ipath_cancel_sends(dd);
+		ipath_cancel_sends(dd, 1);
 
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
 			 dd->ipath_ibcctrl | which);
@@ -1889,7 +1973,7 @@
 /* Below is "non-zero" to force override, but both actual LEDs are off */
 #define LED_OVER_BOTH_OFF (8)
 
-void ipath_run_led_override(unsigned long opaque)
+static void ipath_run_led_override(unsigned long opaque)
 {
 	struct ipath_devdata *dd = (struct ipath_devdata *)opaque;
 	int timeoff;
@@ -2000,7 +2084,9 @@
 
 	ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_DISABLE <<
 			    INFINIPATH_IBCC_LINKINITCMD_SHIFT);
-	ipath_cancel_sends(dd);
+	ipath_cancel_sends(dd, 0);
+
+	signal_ib_event(dd, IB_EVENT_PORT_ERR);
 
 	/* disable IBC */
 	dd->ipath_control &= ~INFINIPATH_C_LINKENABLE;
diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c
index 6b91479..bcfa3cc 100644
--- a/drivers/infiniband/hw/ipath/ipath_eeprom.c
+++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c
@@ -426,8 +426,8 @@
  * @buffer: data to write
  * @len: number of bytes to write
  */
-int ipath_eeprom_internal_write(struct ipath_devdata *dd, u8 eeprom_offset,
-				const void *buffer, int len)
+static int ipath_eeprom_internal_write(struct ipath_devdata *dd, u8 eeprom_offset,
+				       const void *buffer, int len)
 {
 	u8 single_byte;
 	int sub_len;
@@ -596,7 +596,11 @@
 		goto bail;
 	}
 
-	len = offsetof(struct ipath_flash, if_future);
+	/*
+	 * read full flash, not just currently used part, since it may have
+	 * been written with a newer definition
+	 * */
+	len = sizeof(struct ipath_flash);
 	buf = vmalloc(len);
 	if (!buf) {
 		ipath_dev_err(dd, "Couldn't allocate memory to read %u "
@@ -737,8 +741,10 @@
 	/*
 	 * The quick-check above determined that there is something worthy
 	 * of logging, so get current contents and do a more detailed idea.
+	 * read full flash, not just currently used part, since it may have
+	 * been written with a newer definition
 	 */
-	len = offsetof(struct ipath_flash, if_future);
+	len = sizeof(struct ipath_flash);
 	buf = vmalloc(len);
 	ret = 1;
 	if (!buf) {
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index 33ab0d6..5de3243 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -538,6 +538,9 @@
 			continue;
 		cnt++;
 		if (dd->ipath_pageshadow[porttid + tid]) {
+			struct page *p;
+			p = dd->ipath_pageshadow[porttid + tid];
+			dd->ipath_pageshadow[porttid + tid] = NULL;
 			ipath_cdbg(VERBOSE, "PID %u freeing TID %u\n",
 				   pd->port_pid, tid);
 			dd->ipath_f_put_tid(dd, &tidbase[tid],
@@ -546,9 +549,7 @@
 			pci_unmap_page(dd->pcidev,
 				dd->ipath_physshadow[porttid + tid],
 				PAGE_SIZE, PCI_DMA_FROMDEVICE);
-			ipath_release_user_pages(
-				&dd->ipath_pageshadow[porttid + tid], 1);
-			dd->ipath_pageshadow[porttid + tid] = NULL;
+			ipath_release_user_pages(&p, 1);
 			ipath_stats.sps_pageunlocks++;
 		} else
 			ipath_dbg("Unused tid %u, ignoring\n", tid);
@@ -1341,6 +1342,19 @@
 	return ret;
 }
 
+static unsigned ipath_poll_hdrqfull(struct ipath_portdata *pd)
+{
+	unsigned pollflag = 0;
+
+	if ((pd->poll_type & IPATH_POLL_TYPE_OVERFLOW) &&
+	    pd->port_hdrqfull != pd->port_hdrqfull_poll) {
+		pollflag |= POLLIN | POLLRDNORM;
+		pd->port_hdrqfull_poll = pd->port_hdrqfull;
+	}
+
+	return pollflag;
+}
+
 static unsigned int ipath_poll_urgent(struct ipath_portdata *pd,
 				      struct file *fp,
 				      struct poll_table_struct *pt)
@@ -1350,22 +1364,20 @@
 
 	dd = pd->port_dd;
 
-	if (test_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag)) {
-		pollflag |= POLLERR;
-		clear_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag);
-	}
+	/* variable access in ipath_poll_hdrqfull() needs this */
+	rmb();
+	pollflag = ipath_poll_hdrqfull(pd);
 
-	if (test_bit(IPATH_PORT_WAITING_URG, &pd->int_flag)) {
+	if (pd->port_urgent != pd->port_urgent_poll) {
 		pollflag |= POLLIN | POLLRDNORM;
-		clear_bit(IPATH_PORT_WAITING_URG, &pd->int_flag);
+		pd->port_urgent_poll = pd->port_urgent;
 	}
 
 	if (!pollflag) {
+		/* this saves a spin_lock/unlock in interrupt handler... */
 		set_bit(IPATH_PORT_WAITING_URG, &pd->port_flag);
-		if (pd->poll_type & IPATH_POLL_TYPE_OVERFLOW)
-			set_bit(IPATH_PORT_WAITING_OVERFLOW,
-				&pd->port_flag);
-
+		/* flush waiting flag so don't miss an event... */
+		wmb();
 		poll_wait(fp, &pd->port_wait, pt);
 	}
 
@@ -1376,31 +1388,27 @@
 				    struct file *fp,
 				    struct poll_table_struct *pt)
 {
-	u32 head, tail;
+	u32 head;
+	u32 tail;
 	unsigned pollflag = 0;
 	struct ipath_devdata *dd;
 
 	dd = pd->port_dd;
 
+	/* variable access in ipath_poll_hdrqfull() needs this */
+	rmb();
+	pollflag = ipath_poll_hdrqfull(pd);
+
 	head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port);
 	tail = *(volatile u64 *)pd->port_rcvhdrtail_kvaddr;
 
-	if (test_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag)) {
-		pollflag |= POLLERR;
-		clear_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag);
-	}
-
-	if (tail != head ||
-	    test_bit(IPATH_PORT_WAITING_RCV, &pd->int_flag)) {
+	if (head != tail)
 		pollflag |= POLLIN | POLLRDNORM;
-		clear_bit(IPATH_PORT_WAITING_RCV, &pd->int_flag);
-	}
-
-	if (!pollflag) {
+	else {
+		/* this saves a spin_lock/unlock in interrupt handler */
 		set_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag);
-		if (pd->poll_type & IPATH_POLL_TYPE_OVERFLOW)
-			set_bit(IPATH_PORT_WAITING_OVERFLOW,
-				&pd->port_flag);
+		/* flush waiting flag so we don't miss an event */
+		wmb();
 
 		set_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
 			&dd->ipath_rcvctrl);
@@ -1917,6 +1925,12 @@
 	ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n",
 		pd->port_port, head32);
 	pd->port_tidcursor = 0;	/* start at beginning after open */
+
+	/* initialize poll variables... */
+	pd->port_urgent = 0;
+	pd->port_urgent_poll = 0;
+	pd->port_hdrqfull_poll = pd->port_hdrqfull;
+
 	/*
 	 * now enable the port; the tail registers will be written to memory
 	 * by the chip as soon as it sees the write to
@@ -2039,9 +2053,11 @@
 
 	if (dd->ipath_kregbase) {
 		int i;
-		/* atomically clear receive enable port. */
+		/* atomically clear receive enable port and intr avail. */
 		clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port,
 			  &dd->ipath_rcvctrl);
+		clear_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
+			  &dd->ipath_rcvctrl);
 		ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl,
 			dd->ipath_rcvctrl);
 		/* and read back from chip to be sure that nothing
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index 2e689b9..262c25d 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -130,175 +130,6 @@
 	.read = atomic_counters_read,
 };
 
-static ssize_t atomic_node_info_read(struct file *file, char __user *buf,
-				     size_t count, loff_t *ppos)
-{
-	u32 nodeinfo[10];
-	struct ipath_devdata *dd;
-	u64 guid;
-
-	dd = file->f_path.dentry->d_inode->i_private;
-
-	guid = be64_to_cpu(dd->ipath_guid);
-
-	nodeinfo[0] =			/* BaseVersion is SMA */
-		/* ClassVersion is SMA */
-		(1 << 8)		/* NodeType  */
-		| (1 << 0);		/* NumPorts */
-	nodeinfo[1] = (u32) (guid >> 32);
-	nodeinfo[2] = (u32) (guid & 0xffffffff);
-	/* PortGUID == SystemImageGUID for us */
-	nodeinfo[3] = nodeinfo[1];
-	/* PortGUID == SystemImageGUID for us */
-	nodeinfo[4] = nodeinfo[2];
-	/* PortGUID == NodeGUID for us */
-	nodeinfo[5] = nodeinfo[3];
-	/* PortGUID == NodeGUID for us */
-	nodeinfo[6] = nodeinfo[4];
-	nodeinfo[7] = (4 << 16) /* we support 4 pkeys */
-		| (dd->ipath_deviceid << 0);
-	/* our chip version as 16 bits major, 16 bits minor */
-	nodeinfo[8] = dd->ipath_minrev | (dd->ipath_majrev << 16);
-	nodeinfo[9] = (dd->ipath_unit << 24) | (dd->ipath_vendorid << 0);
-
-	return simple_read_from_buffer(buf, count, ppos, nodeinfo,
-				       sizeof nodeinfo);
-}
-
-static const struct file_operations atomic_node_info_ops = {
-	.read = atomic_node_info_read,
-};
-
-static ssize_t atomic_port_info_read(struct file *file, char __user *buf,
-				     size_t count, loff_t *ppos)
-{
-	u32 portinfo[13];
-	u32 tmp, tmp2;
-	struct ipath_devdata *dd;
-
-	dd = file->f_path.dentry->d_inode->i_private;
-
-	/* so we only initialize non-zero fields. */
-	memset(portinfo, 0, sizeof portinfo);
-
-	/*
-	 * Notimpl yet M_Key (64)
-	 * Notimpl yet GID (64)
-	 */
-
-	portinfo[4] = (dd->ipath_lid << 16);
-
-	/*
-	 * Notimpl yet SMLID.
-	 * CapabilityMask is 0, we don't support any of these
-	 * DiagCode is 0; we don't store any diag info for now Notimpl yet
-	 * M_KeyLeasePeriod (we don't support M_Key)
-	 */
-
-	/* LocalPortNum is whichever port number they ask for */
-	portinfo[7] = (dd->ipath_unit << 24)
-		/* LinkWidthEnabled */
-		| (2 << 16)
-		/* LinkWidthSupported (really 2, but not IB valid) */
-		| (3 << 8)
-		/* LinkWidthActive */
-		| (2 << 0);
-	tmp = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK;
-	tmp2 = 5;
-	if (tmp == IPATH_IBSTATE_INIT)
-		tmp = 2;
-	else if (tmp == IPATH_IBSTATE_ARM)
-		tmp = 3;
-	else if (tmp == IPATH_IBSTATE_ACTIVE)
-		tmp = 4;
-	else {
-		tmp = 0;	/* down */
-		tmp2 = tmp & 0xf;
-	}
-
-	portinfo[8] = (1 << 28)	/* LinkSpeedSupported */
-		| (tmp << 24)	/* PortState */
-		| (tmp2 << 20)	/* PortPhysicalState */
-		| (2 << 16)
-
-		/* LinkDownDefaultState */
-		/* M_KeyProtectBits == 0 */
-		/* NotImpl yet LMC == 0 (we can support all values) */
-		| (1 << 4)	/* LinkSpeedActive */
-		| (1 << 0);	/* LinkSpeedEnabled */
-	switch (dd->ipath_ibmtu) {
-	case 4096:
-		tmp = 5;
-		break;
-	case 2048:
-		tmp = 4;
-		break;
-	case 1024:
-		tmp = 3;
-		break;
-	case 512:
-		tmp = 2;
-		break;
-	case 256:
-		tmp = 1;
-		break;
-	default:		/* oops, something is wrong */
-		ipath_dbg("Problem, ipath_ibmtu 0x%x not a valid IB MTU, "
-			  "treat as 2048\n", dd->ipath_ibmtu);
-		tmp = 4;
-		break;
-	}
-	portinfo[9] = (tmp << 28)
-		/* NeighborMTU */
-		/* Notimpl MasterSMSL */
-		| (1 << 20)
-
-		/* VLCap */
-		/* Notimpl InitType (actually, an SMA decision) */
-		/* VLHighLimit is 0 (only one VL) */
-		; /* VLArbitrationHighCap is 0 (only one VL) */
-	/*
-	 * Note: the chips support a maximum MTU of 4096, but the driver
-	 * hasn't implemented this feature yet, so set the maximum
-	 * to 2048.
-	 */
-	portinfo[10] = 	/* VLArbitrationLowCap is 0 (only one VL) */
-		/* InitTypeReply is SMA decision */
-		(4 << 16)	/* MTUCap 2048 */
-		| (7 << 13)	/* VLStallCount */
-		| (0x1f << 8)	/* HOQLife */
-		| (1 << 4)
-
-		/* OperationalVLs 0 */
-		/* PartitionEnforcementInbound */
-		/* PartitionEnforcementOutbound not enforced */
-		/* FilterRawinbound not enforced */
-		;		/* FilterRawOutbound not enforced */
-	/* M_KeyViolations are not counted by hardware, SMA can count */
-	tmp = ipath_read_creg32(dd, dd->ipath_cregs->cr_errpkey);
-	/* P_KeyViolations are counted by hardware. */
-	portinfo[11] = ((tmp & 0xffff) << 0);
-	portinfo[12] =
-		/* Q_KeyViolations are not counted by hardware */
-		(1 << 8)
-
-		/* GUIDCap */
-		/* SubnetTimeOut handled by SMA */
-		/* RespTimeValue handled by SMA */
-		;
-	/* LocalPhyErrors are programmed to max */
-	portinfo[12] |= (0xf << 20)
-		| (0xf << 16)   /* OverRunErrors are programmed to max */
-		;
-
-	return simple_read_from_buffer(buf, count, ppos, portinfo,
-				       sizeof portinfo);
-}
-
-static const struct file_operations atomic_port_info_ops = {
-	.read = atomic_port_info_read,
-};
-
 static ssize_t flash_read(struct file *file, char __user *buf,
 			  size_t count, loff_t *ppos)
 {
@@ -427,22 +258,6 @@
 		goto bail;
 	}
 
-	ret = create_file("node_info", S_IFREG|S_IRUGO, dir, &tmp,
-			  &atomic_node_info_ops, dd);
-	if (ret) {
-		printk(KERN_ERR "create_file(%s/node_info) "
-		       "failed: %d\n", unit, ret);
-		goto bail;
-	}
-
-	ret = create_file("port_info", S_IFREG|S_IRUGO, dir, &tmp,
-			  &atomic_port_info_ops, dd);
-	if (ret) {
-		printk(KERN_ERR "create_file(%s/port_info) "
-		       "failed: %d\n", unit, ret);
-		goto bail;
-	}
-
 	ret = create_file("flash", S_IFREG|S_IWUSR|S_IRUGO, dir, &tmp,
 			  &flash_ops, dd);
 	if (ret) {
@@ -508,8 +323,6 @@
 	}
 
 	remove_file(dir, "flash");
-	remove_file(dir, "port_info");
-	remove_file(dir, "node_info");
 	remove_file(dir, "atomic_counters");
 	d_delete(dir);
 	ret = simple_rmdir(root->d_inode, dir);
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c
index 650745d..ddbebe4 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6110.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
@@ -631,56 +631,35 @@
 {
 	char *n = NULL;
 	u8 boardrev = dd->ipath_boardrev;
-	int ret;
+	int ret = 0;
 
 	switch (boardrev) {
-	case 4:		/* Ponderosa is one of the bringup boards */
-		n = "Ponderosa";
-		break;
 	case 5:
 		/*
 		 * original production board; two production levels, with
 		 * different serial number ranges.   See ipath_ht_early_init() for
 		 * case where we enable IPATH_GPIO_INTR for later serial # range.
+		 * Original 112* serial number is no longer supported.
 		 */
 		n = "InfiniPath_QHT7040";
 		break;
-	case 6:
-		n = "OEM_Board_3";
-		break;
 	case 7:
 		/* small form factor production board */
 		n = "InfiniPath_QHT7140";
 		break;
-	case 8:
-		n = "LS/X-1";
-		break;
-	case 9:		/* Comstock bringup test board */
-		n = "Comstock";
-		break;
-	case 10:
-		n = "OEM_Board_2";
-		break;
-	case 11:
-		n = "InfiniPath_HT-470"; /* obsoleted */
-		break;
-	case 12:
-		n = "OEM_Board_4";
-		break;
 	default:		/* don't know, just print the number */
 		ipath_dev_err(dd, "Don't yet know about board "
 			      "with ID %u\n", boardrev);
 		snprintf(name, namelen, "Unknown_InfiniPath_QHT7xxx_%u",
 			 boardrev);
+		ret = 1;
 		break;
 	}
 	if (n)
 		snprintf(name, namelen, "%s", n);
 
-	if (dd->ipath_boardrev != 6 && dd->ipath_boardrev != 7 &&
-	    dd->ipath_boardrev != 11) {
+	if (ret) {
 		ipath_dev_err(dd, "Unsupported InfiniPath board %s!\n", name);
-		ret = 1;
 		goto bail;
 	}
 	if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 ||
@@ -1554,10 +1533,25 @@
 		 * can use GPIO interrupts.  They have serial #'s starting
 		 * with 128, rather than 112.
 		 */
-		dd->ipath_flags |= IPATH_GPIO_INTR;
-	} else
-		ipath_dev_err(dd, "Unsupported InfiniPath serial "
-			      "number %.16s!\n", dd->ipath_serial);
+		if (dd->ipath_serial[0] == '1' &&
+		    dd->ipath_serial[1] == '2' &&
+		    dd->ipath_serial[2] == '8')
+			dd->ipath_flags |= IPATH_GPIO_INTR;
+		else {
+			ipath_dev_err(dd, "Unsupported InfiniPath board "
+				"(serial number %.16s)!\n",
+				dd->ipath_serial);
+			return 1;
+		}
+	}
+
+	if (dd->ipath_minrev >= 4) {
+		/* Rev4+ reports extra errors via internal GPIO pins */
+		dd->ipath_flags |= IPATH_GPIO_ERRINTRS;
+		dd->ipath_gpio_mask |= IPATH_GPIO_ERRINTR_MASK;
+		ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask,
+				 dd->ipath_gpio_mask);
+	}
 
 	return 0;
 }
@@ -1592,7 +1586,10 @@
 	struct ipath_base_info *kinfo = kbase;
 
 	kinfo->spi_runtime_flags |= IPATH_RUNTIME_HT |
-		IPATH_RUNTIME_RCVHDR_COPY;
+		IPATH_RUNTIME_PIO_REGSWAPPED;
+
+	if (pd->port_dd->ipath_minrev < 4)
+		kinfo->spi_runtime_flags |= IPATH_RUNTIME_RCVHDR_COPY;
 
 	return 0;
 }
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c
index 9868ccd..0103d6f 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6120.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c
@@ -321,6 +321,8 @@
 		        << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)
 
 static int ipath_pe_txe_recover(struct ipath_devdata *);
+static void ipath_pe_put_tid_2(struct ipath_devdata *, u64 __iomem *,
+			       u32, unsigned long);
 
 /**
  * ipath_pe_handle_hwerrors - display hardware errors.
@@ -555,8 +557,11 @@
 		ipath_dev_err(dd, "Unsupported InfiniPath hardware revision %u.%u!\n",
 			      dd->ipath_majrev, dd->ipath_minrev);
 		ret = 1;
-	} else
+	} else {
 		ret = 0;
+		if (dd->ipath_minrev >= 2)
+			dd->ipath_f_put_tid = ipath_pe_put_tid_2;
+	}
 
 	return ret;
 }
@@ -1138,11 +1143,14 @@
 			pa |= 2 << 29;
 	}
 
-	/* workaround chip bug 9437 by writing each TID twice
-	 * and holding a spinlock around the writes, so they don't
-	 * intermix with other TID (eager or expected) writes
-	 * Unfortunately, this call can be done from interrupt level
-	 * for the port 0 eager TIDs, so we have to use irqsave
+	/*
+	 * Workaround chip bug 9437 by writing the scratch register
+	 * before and after the TID, and with an io write barrier.
+	 * We use a spinlock around the writes, so they can't intermix
+	 * with other TID (eager or expected) writes (the chip bug
+	 * is triggered by back to back TID writes). Unfortunately, this
+	 * call can be done from interrupt level for the port 0 eager TIDs,
+	 * so we have to use irqsave locks.
 	 */
 	spin_lock_irqsave(&dd->ipath_tid_lock, flags);
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_scratch, 0xfeeddeaf);
@@ -1220,7 +1228,7 @@
 		 port * dd->ipath_rcvtidcnt * sizeof(*tidbase));
 
 	for (i = 0; i < dd->ipath_rcvtidcnt; i++)
-		ipath_pe_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EXPECTED,
+		dd->ipath_f_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EXPECTED,
 				 tidinv);
 
 	tidbase = (u64 __iomem *)
@@ -1229,7 +1237,7 @@
 		 port * dd->ipath_rcvegrcnt * sizeof(*tidbase));
 
 	for (i = 0; i < dd->ipath_rcvegrcnt; i++)
-		ipath_pe_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EAGER,
+		dd->ipath_f_put_tid(dd, &tidbase[i], RCVHQ_RCV_TYPE_EAGER,
 				 tidinv);
 }
 
@@ -1268,6 +1276,8 @@
 static int ipath_pe_early_init(struct ipath_devdata *dd)
 {
 	dd->ipath_flags |= IPATH_4BYTE_TID;
+	if (ipath_unordered_wc())
+		dd->ipath_flags |= IPATH_PIO_FLUSH_WC;
 
 	/*
 	 * For openfabrics, we need to be able to handle an IB header of
@@ -1338,7 +1348,8 @@
 	dd = pd->port_dd;
 
 done:
-	kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE;
+	kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE |
+		IPATH_RUNTIME_FORCE_PIOAVAIL | IPATH_RUNTIME_PIO_REGSWAPPED;
 	return 0;
 }
 
@@ -1395,10 +1406,11 @@
 	dd->ipath_f_quiet_serdes = ipath_pe_quiet_serdes;
 	dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes;
 	dd->ipath_f_clear_tids = ipath_pe_clear_tids;
-	if (dd->ipath_minrev >= 2)
-		dd->ipath_f_put_tid = ipath_pe_put_tid_2;
-	else
-		dd->ipath_f_put_tid = ipath_pe_put_tid;
+	/*
+	 * this may get changed after we read the chip revision,
+	 * but we start with the safe version for all revs
+	 */
+	dd->ipath_f_put_tid = ipath_pe_put_tid;
 	dd->ipath_f_cleanup = ipath_setup_pe_cleanup;
 	dd->ipath_f_setextled = ipath_setup_pe_setextled;
 	dd->ipath_f_get_base_info = ipath_pe_get_base_info;
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c
index 49951d5..9dd0bac 100644
--- a/drivers/infiniband/hw/ipath/ipath_init_chip.c
+++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c
@@ -782,7 +782,7 @@
 	 * Follows early_init because some chips have to initialize
 	 * PIO buffers in early_init to avoid false parity errors.
 	 */
-	ipath_cancel_sends(dd);
+	ipath_cancel_sends(dd, 0);
 
 	/* early_init sets rcvhdrentsize and rcvhdrsize, so this must be
 	 * done after early_init */
@@ -851,13 +851,14 @@
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
 			 dd->ipath_hwerrmask);
 
-	dd->ipath_maskederrs = dd->ipath_ignorederrs;
 	/* clear all */
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear, -1LL);
 	/* enable errors that are masked, at least this first time. */
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
 			 ~dd->ipath_maskederrs);
-	/* clear any interrups up to this point (ints still not enabled) */
+	dd->ipath_errormask = ipath_read_kreg64(dd,
+		dd->ipath_kregs->kr_errormask);
+	/* clear any interrupts up to this point (ints still not enabled) */
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, -1LL);
 
 	/*
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
index 47aa434..6a5dd5c 100644
--- a/drivers/infiniband/hw/ipath/ipath_intr.c
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c
@@ -70,7 +70,7 @@
  * If rewrite is true, and bits are set in the sendbufferror registers,
  * we'll write to the buffer, for error recovery on parity errors.
  */
-void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
+static void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
 {
 	u32 piobcnt;
 	unsigned long sbuf[4];
@@ -275,6 +275,16 @@
 	return ret;
 }
 
+void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev)
+{
+	struct ib_event event;
+
+	event.device = &dd->verbs_dev->ibdev;
+	event.element.port_num = 1;
+	event.event = ev;
+	ib_dispatch_event(&event);
+}
+
 static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
 				     ipath_err_t errs, int noprint)
 {
@@ -303,7 +313,7 @@
 		 * Flush all queued sends when link went to DOWN or INIT,
 		 * to be sure that they don't block SMA and other MAD packets
 		 */
-		ipath_cancel_sends(dd);
+		ipath_cancel_sends(dd, 1);
 	}
 	else if (lstate == IPATH_IBSTATE_INIT || lstate == IPATH_IBSTATE_ARM ||
 	    lstate == IPATH_IBSTATE_ACTIVE) {
@@ -373,6 +383,8 @@
 	dd->ipath_ibpollcnt = 0;	/* some state other than 2 or 3 */
 	ipath_stats.sps_iblink++;
 	if (ltstate != INFINIPATH_IBCS_LT_STATE_LINKUP) {
+		if (dd->ipath_flags & IPATH_LINKACTIVE)
+			signal_ib_event(dd, IB_EVENT_PORT_ERR);
 		dd->ipath_flags |= IPATH_LINKDOWN;
 		dd->ipath_flags &= ~(IPATH_LINKUNK | IPATH_LINKINIT
 				     | IPATH_LINKACTIVE |
@@ -405,7 +417,10 @@
 		*dd->ipath_statusp |=
 			IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF;
 		dd->ipath_f_setextled(dd, lstate, ltstate);
+		signal_ib_event(dd, IB_EVENT_PORT_ACTIVE);
 	} else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_INIT) {
+		if (dd->ipath_flags & IPATH_LINKACTIVE)
+			signal_ib_event(dd, IB_EVENT_PORT_ERR);
 		/*
 		 * set INIT and DOWN.  Down is checked by most of the other
 		 * code, but INIT is useful to know in a few places.
@@ -418,6 +433,8 @@
 					| IPATH_STATUS_IB_READY);
 		dd->ipath_f_setextled(dd, lstate, ltstate);
 	} else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_ARM) {
+		if (dd->ipath_flags & IPATH_LINKACTIVE)
+			signal_ib_event(dd, IB_EVENT_PORT_ERR);
 		dd->ipath_flags |= IPATH_LINKARMED;
 		dd->ipath_flags &=
 			~(IPATH_LINKUNK | IPATH_LINKDOWN | IPATH_LINKINIT |
@@ -517,10 +534,7 @@
 
 	supp_msgs = handle_frequent_errors(dd, errs, msg, &noprint);
 
-	/*
-	 * don't report errors that are masked (includes those always
-	 * ignored)
-	 */
+	/* don't report errors that are masked */
 	errs &= ~dd->ipath_maskederrs;
 
 	/* do these first, they are most important */
@@ -566,19 +580,19 @@
 		 * ones on this particular interrupt, which also isn't great
 		 */
 		dd->ipath_maskederrs |= dd->ipath_lasterror | errs;
+		dd->ipath_errormask &= ~dd->ipath_maskederrs;
 		ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
-				 ~dd->ipath_maskederrs);
+			dd->ipath_errormask);
 		s_iserr = ipath_decode_err(msg, sizeof msg,
-				 (dd->ipath_maskederrs & ~dd->
-				  ipath_ignorederrs));
+			dd->ipath_maskederrs);
 
-		if ((dd->ipath_maskederrs & ~dd->ipath_ignorederrs) &
+		if (dd->ipath_maskederrs &
 			~(INFINIPATH_E_RRCVEGRFULL |
 			INFINIPATH_E_RRCVHDRFULL | INFINIPATH_E_PKTERRS))
 			ipath_dev_err(dd, "Temporarily disabling "
 			    "error(s) %llx reporting; too frequent (%s)\n",
-				(unsigned long long) (dd->ipath_maskederrs &
-				~dd->ipath_ignorederrs), msg);
+				(unsigned long long)dd->ipath_maskederrs,
+				msg);
 		else {
 			/*
 			 * rcvegrfull and rcvhdrqfull are "normal",
@@ -691,17 +705,9 @@
 					chkerrpkts = 1;
 				dd->ipath_lastrcvhdrqtails[i] = tl;
 				pd->port_hdrqfull++;
-				if (test_bit(IPATH_PORT_WAITING_OVERFLOW,
-					     &pd->port_flag)) {
-					clear_bit(
-					  IPATH_PORT_WAITING_OVERFLOW,
-					  &pd->port_flag);
-					set_bit(
-					  IPATH_PORT_WAITING_OVERFLOW,
-					  &pd->int_flag);
-					wake_up_interruptible(
-					  &pd->port_wait);
-				}
+				/* flush hdrqfull so that poll() sees it */
+				wmb();
+				wake_up_interruptible(&pd->port_wait);
 			}
 		}
 	}
@@ -793,19 +799,22 @@
 	/* disable error interrupts, to avoid confusion */
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, 0ULL);
 
+	/* also disable interrupts; errormask is sometimes overwriten */
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, 0ULL);
+
 	/*
 	 * clear all sends, because they have may been
 	 * completed by usercode while in freeze mode, and
 	 * therefore would not be sent, and eventually
 	 * might cause the process to run out of bufs
 	 */
-	ipath_cancel_sends(dd);
+	ipath_cancel_sends(dd, 0);
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
 			 dd->ipath_control);
 
 	/* ensure pio avail updates continue */
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-		 dd->ipath_sendctrl & ~IPATH_S_PIOBUFAVAILUPD);
+		 dd->ipath_sendctrl & ~INFINIPATH_S_PIOBUFAVAILUPD);
 	ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
 		 dd->ipath_sendctrl);
@@ -817,7 +826,7 @@
 	for (i = 0; i < dd->ipath_pioavregs; i++) {
 		/* deal with 6110 chip bug */
 		im = i > 3 ? ((i&1) ? i-1 : i+1) : i;
-		val = ipath_read_kreg64(dd, 0x1000+(im*sizeof(u64)));
+		val = ipath_read_kreg64(dd, (0x1000/sizeof(u64))+im);
 		dd->ipath_pioavailregs_dma[i] = dd->ipath_pioavailshadow[i]
 			= le64_to_cpu(val);
 	}
@@ -832,7 +841,8 @@
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear,
 		E_SPKT_ERRS_IGNORE);
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
-		~dd->ipath_maskederrs);
+		dd->ipath_errormask);
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, -1LL);
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, 0ULL);
 }
 
@@ -959,6 +969,8 @@
 	int i;
 	int rcvdint = 0;
 
+	/* test_bit below needs this... */
+	rmb();
 	portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) &
 		 dd->ipath_i_rcvavail_mask)
 		| ((istat >> INFINIPATH_I_RCVURG_SHIFT) &
@@ -966,22 +978,15 @@
 	for (i = 1; i < dd->ipath_cfgports; i++) {
 		struct ipath_portdata *pd = dd->ipath_pd[i];
 		if (portr & (1 << i) && pd && pd->port_cnt) {
-			if (test_bit(IPATH_PORT_WAITING_RCV,
-				     &pd->port_flag)) {
-				clear_bit(IPATH_PORT_WAITING_RCV,
-					  &pd->port_flag);
-				set_bit(IPATH_PORT_WAITING_RCV,
-					&pd->int_flag);
+			if (test_and_clear_bit(IPATH_PORT_WAITING_RCV,
+					       &pd->port_flag)) {
 				clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT,
 					  &dd->ipath_rcvctrl);
 				wake_up_interruptible(&pd->port_wait);
 				rcvdint = 1;
-			} else if (test_bit(IPATH_PORT_WAITING_URG,
-					    &pd->port_flag)) {
-				clear_bit(IPATH_PORT_WAITING_URG,
-					  &pd->port_flag);
-				set_bit(IPATH_PORT_WAITING_URG,
-					&pd->int_flag);
+			} else if (test_and_clear_bit(IPATH_PORT_WAITING_URG,
+						      &pd->port_flag)) {
+				pd->port_urgent++;
 				wake_up_interruptible(&pd->port_wait);
 			}
 		}
@@ -1002,7 +1007,6 @@
 	u32 istat, chk0rcv = 0;
 	ipath_err_t estat = 0;
 	irqreturn_t ret;
-	u32 oldhead, curtail;
 	static unsigned unexpected = 0;
 	static const u32 port0rbits = (1U<<INFINIPATH_I_RCVAVAIL_SHIFT) |
 		 (1U<<INFINIPATH_I_RCVURG_SHIFT);
@@ -1035,36 +1039,6 @@
 		goto bail;
 	}
 
-	/*
-	 * We try to avoid reading the interrupt status register, since
-	 * that's a PIO read, and stalls the processor for up to about
-	 * ~0.25 usec. The idea is that if we processed a port0 packet,
-	 * we blindly clear the  port 0 receive interrupt bits, and nothing
-	 * else, then return.  If other interrupts are pending, the chip
-	 * will re-interrupt us as soon as we write the intclear register.
-	 * We then won't process any more kernel packets (if not the 2nd
-	 * time, then the 3rd or 4th) and we'll then handle the other
-	 * interrupts.   We clear the interrupts first so that we don't
-	 * lose intr for later packets that arrive while we are processing.
-	 */
-	oldhead = dd->ipath_port0head;
-	curtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr);
-	if (oldhead != curtail) {
-		if (dd->ipath_flags & IPATH_GPIO_INTR) {
-			ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
-					 (u64) (1 << IPATH_GPIO_PORT0_BIT));
-			istat = port0rbits | INFINIPATH_I_GPIO;
-		}
-		else
-			istat = port0rbits;
-		ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, istat);
-		ipath_kreceive(dd);
-		if (oldhead != dd->ipath_port0head) {
-			ipath_stats.sps_fastrcvint++;
-			goto done;
-		}
-	}
-
 	istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus);
 
 	if (unlikely(!istat)) {
@@ -1115,8 +1089,8 @@
 		 * GPIO_2 indicates (on some HT4xx boards) that a packet
 		 *        has arrived for Port 0. Checking for this
 		 *        is controlled by flag IPATH_GPIO_INTR.
-		 * GPIO_3..5 on IBA6120 Rev2 chips indicate errors
-		 *        that we need to count. Checking for this
+		 * GPIO_3..5 on IBA6120 Rev2 and IBA6110 Rev4 chips indicate
+		 *        errors that we need to count. Checking for this
 		 *        is controlled by flag IPATH_GPIO_ERRINTRS.
 		 */
 		u32 gpiostatus;
@@ -1167,10 +1141,8 @@
 			/*
 			 * Some unexpected bits remain. If they could have
 			 * caused the interrupt, complain and clear.
-			 * MEA: this is almost certainly non-ideal.
-			 * we should look into auto-disable of unexpected
-			 * GPIO interrupts, possibly on a "three strikes"
-			 * basis.
+			 * To avoid repetition of this condition, also clear
+			 * the mask. It is almost certainly due to error.
 			 */
 			const u32 mask = (u32) dd->ipath_gpio_mask;
 
@@ -1178,6 +1150,10 @@
 				ipath_dbg("Unexpected GPIO IRQ bits %x\n",
 				  gpiostatus & mask);
 				to_clear |= (gpiostatus & mask);
+				dd->ipath_gpio_mask &= ~(gpiostatus & mask);
+				ipath_write_kreg(dd,
+					dd->ipath_kregs->kr_gpio_mask,
+					dd->ipath_gpio_mask);
 			}
 		}
 		if (to_clear) {
@@ -1225,7 +1201,6 @@
 		handle_layer_pioavail(dd);
 	}
 
-done:
 	ret = IRQ_HANDLED;
 
 bail:
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 3105005..8786dd7 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -42,6 +42,7 @@
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <asm/io.h>
+#include <rdma/ib_verbs.h>
 
 #include "ipath_common.h"
 #include "ipath_debug.h"
@@ -139,6 +140,12 @@
 	u32 port_pionowait;
 	/* total number of rcvhdrqfull errors */
 	u32 port_hdrqfull;
+	/* saved total number of rcvhdrqfull errors for poll edge trigger */
+	u32 port_hdrqfull_poll;
+	/* total number of polled urgent packets */
+	u32 port_urgent;
+	/* saved total number of polled urgent packets for poll edge trigger */
+	u32 port_urgent_poll;
 	/* pid of process using this port */
 	pid_t port_pid;
 	/* same size as task_struct .comm[] */
@@ -261,18 +268,10 @@
 	 * limiting of hwerror reporting
 	 */
 	ipath_err_t ipath_lasthwerror;
-	/*
-	 * errors masked because they occur too fast, also includes errors
-	 * that are always ignored (ipath_ignorederrs)
-	 */
+	/* errors masked because they occur too fast */
 	ipath_err_t ipath_maskederrs;
 	/* time in jiffies at which to re-enable maskederrs */
 	unsigned long ipath_unmasktime;
-	/*
-	 * errors always ignored (masked), at least for a given
-	 * chip/device, because they are wrong or not useful
-	 */
-	ipath_err_t ipath_ignorederrs;
 	/* count of egrfull errors, combined for all ports */
 	u64 ipath_last_tidfull;
 	/* for ipath_qcheck() */
@@ -436,6 +435,7 @@
 	u64 ipath_lastibcstat;
 	/* hwerrmask shadow */
 	ipath_err_t ipath_hwerrmask;
+	ipath_err_t ipath_errormask; /* errormask shadow */
 	/* interrupt config reg shadow */
 	u64 ipath_intconfig;
 	/* kr_sendpiobufbase value */
@@ -683,7 +683,7 @@
 
 void ipath_disarm_piobufs(struct ipath_devdata *, unsigned first,
 			  unsigned cnt);
-void ipath_cancel_sends(struct ipath_devdata *);
+void ipath_cancel_sends(struct ipath_devdata *, int);
 
 int ipath_create_rcvhdrq(struct ipath_devdata *, struct ipath_portdata *);
 void ipath_free_pddata(struct ipath_devdata *, struct ipath_portdata *);
@@ -731,6 +731,8 @@
 #define IPATH_LINKACTIVE    0x200
 		/* link current state is unknown */
 #define IPATH_LINKUNK       0x400
+		/* Write combining flush needed for PIO */
+#define IPATH_PIO_FLUSH_WC  0x1000
 		/* no IB cable, or no device on IB cable */
 #define IPATH_NOCABLE       0x4000
 		/* Supports port zero per packet receive interrupts via
@@ -762,8 +764,6 @@
 #define IPATH_PORT_MASTER_UNINIT 4
 		/* waiting for an urgent packet to arrive */
 #define IPATH_PORT_WAITING_URG 5
-		/* waiting for a header overflow */
-#define IPATH_PORT_WAITING_OVERFLOW 6
 
 /* free up any allocated data at closes */
 void ipath_free_data(struct ipath_portdata *dd);
@@ -776,7 +776,7 @@
 int ipath_update_eeprom_log(struct ipath_devdata *dd);
 void ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr);
 u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg);
-void ipath_disarm_senderrbufs(struct ipath_devdata *, int);
+void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev);
 
 /*
  * Set LED override, only the two LSBs have "public" meaning, but
@@ -820,7 +820,6 @@
 #define IPATH_MDIO_CTRL_8355_REG_10 0x1D
 
 int ipath_get_user_pages(unsigned long, size_t, struct page **);
-int ipath_get_user_pages_nocopy(unsigned long, struct page **);
 void ipath_release_user_pages(struct page **, size_t);
 void ipath_release_user_pages_on_close(struct page **, size_t);
 int ipath_eeprom_read(struct ipath_devdata *, u8, void *, int);
diff --git a/drivers/infiniband/hw/ipath/ipath_layer.c b/drivers/infiniband/hw/ipath/ipath_layer.c
deleted file mode 100644
index 82616b7..0000000
--- a/drivers/infiniband/hw/ipath/ipath_layer.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, 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
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * These are the routines used by layered drivers, currently just the
- * layered ethernet driver and verbs layer.
- */
-
-#include <linux/io.h>
-#include <asm/byteorder.h>
-
-#include "ipath_kernel.h"
-#include "ipath_layer.h"
-#include "ipath_verbs.h"
-#include "ipath_common.h"
-
-/* Acquire before ipath_devs_lock. */
-static DEFINE_MUTEX(ipath_layer_mutex);
-
-u16 ipath_layer_rcv_opcode;
-
-static int (*layer_intr)(void *, u32);
-static int (*layer_rcv)(void *, void *, struct sk_buff *);
-static int (*layer_rcv_lid)(void *, void *);
-
-static void *(*layer_add_one)(int, struct ipath_devdata *);
-static void (*layer_remove_one)(void *);
-
-int __ipath_layer_intr(struct ipath_devdata *dd, u32 arg)
-{
-	int ret = -ENODEV;
-
-	if (dd->ipath_layer.l_arg && layer_intr)
-		ret = layer_intr(dd->ipath_layer.l_arg, arg);
-
-	return ret;
-}
-
-int ipath_layer_intr(struct ipath_devdata *dd, u32 arg)
-{
-	int ret;
-
-	mutex_lock(&ipath_layer_mutex);
-
-	ret = __ipath_layer_intr(dd, arg);
-
-	mutex_unlock(&ipath_layer_mutex);
-
-	return ret;
-}
-
-int __ipath_layer_rcv(struct ipath_devdata *dd, void *hdr,
-		      struct sk_buff *skb)
-{
-	int ret = -ENODEV;
-
-	if (dd->ipath_layer.l_arg && layer_rcv)
-		ret = layer_rcv(dd->ipath_layer.l_arg, hdr, skb);
-
-	return ret;
-}
-
-int __ipath_layer_rcv_lid(struct ipath_devdata *dd, void *hdr)
-{
-	int ret = -ENODEV;
-
-	if (dd->ipath_layer.l_arg && layer_rcv_lid)
-		ret = layer_rcv_lid(dd->ipath_layer.l_arg, hdr);
-
-	return ret;
-}
-
-void ipath_layer_lid_changed(struct ipath_devdata *dd)
-{
-	mutex_lock(&ipath_layer_mutex);
-
-	if (dd->ipath_layer.l_arg && layer_intr)
-		layer_intr(dd->ipath_layer.l_arg, IPATH_LAYER_INT_LID);
-
-	mutex_unlock(&ipath_layer_mutex);
-}
-
-void ipath_layer_add(struct ipath_devdata *dd)
-{
-	mutex_lock(&ipath_layer_mutex);
-
-	if (layer_add_one)
-		dd->ipath_layer.l_arg =
-			layer_add_one(dd->ipath_unit, dd);
-
-	mutex_unlock(&ipath_layer_mutex);
-}
-
-void ipath_layer_remove(struct ipath_devdata *dd)
-{
-	mutex_lock(&ipath_layer_mutex);
-
-	if (dd->ipath_layer.l_arg && layer_remove_one) {
-		layer_remove_one(dd->ipath_layer.l_arg);
-		dd->ipath_layer.l_arg = NULL;
-	}
-
-	mutex_unlock(&ipath_layer_mutex);
-}
-
-int ipath_layer_register(void *(*l_add)(int, struct ipath_devdata *),
-			 void (*l_remove)(void *),
-			 int (*l_intr)(void *, u32),
-			 int (*l_rcv)(void *, void *, struct sk_buff *),
-			 u16 l_rcv_opcode,
-			 int (*l_rcv_lid)(void *, void *))
-{
-	struct ipath_devdata *dd, *tmp;
-	unsigned long flags;
-
-	mutex_lock(&ipath_layer_mutex);
-
-	layer_add_one = l_add;
-	layer_remove_one = l_remove;
-	layer_intr = l_intr;
-	layer_rcv = l_rcv;
-	layer_rcv_lid = l_rcv_lid;
-	ipath_layer_rcv_opcode = l_rcv_opcode;
-
-	spin_lock_irqsave(&ipath_devs_lock, flags);
-
-	list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
-		if (!(dd->ipath_flags & IPATH_INITTED))
-			continue;
-
-		if (dd->ipath_layer.l_arg)
-			continue;
-
-		spin_unlock_irqrestore(&ipath_devs_lock, flags);
-		dd->ipath_layer.l_arg = l_add(dd->ipath_unit, dd);
-		spin_lock_irqsave(&ipath_devs_lock, flags);
-	}
-
-	spin_unlock_irqrestore(&ipath_devs_lock, flags);
-	mutex_unlock(&ipath_layer_mutex);
-
-	return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_register);
-
-void ipath_layer_unregister(void)
-{
-	struct ipath_devdata *dd, *tmp;
-	unsigned long flags;
-
-	mutex_lock(&ipath_layer_mutex);
-	spin_lock_irqsave(&ipath_devs_lock, flags);
-
-	list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
-		if (dd->ipath_layer.l_arg && layer_remove_one) {
-			spin_unlock_irqrestore(&ipath_devs_lock, flags);
-			layer_remove_one(dd->ipath_layer.l_arg);
-			spin_lock_irqsave(&ipath_devs_lock, flags);
-			dd->ipath_layer.l_arg = NULL;
-		}
-	}
-
-	spin_unlock_irqrestore(&ipath_devs_lock, flags);
-
-	layer_add_one = NULL;
-	layer_remove_one = NULL;
-	layer_intr = NULL;
-	layer_rcv = NULL;
-	layer_rcv_lid = NULL;
-
-	mutex_unlock(&ipath_layer_mutex);
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_unregister);
-
-int ipath_layer_open(struct ipath_devdata *dd, u32 * pktmax)
-{
-	int ret;
-	u32 intval = 0;
-
-	mutex_lock(&ipath_layer_mutex);
-
-	if (!dd->ipath_layer.l_arg) {
-		ret = -EINVAL;
-		goto bail;
-	}
-
-	ret = ipath_setrcvhdrsize(dd, IPATH_HEADER_QUEUE_WORDS);
-
-	if (ret < 0)
-		goto bail;
-
-	*pktmax = dd->ipath_ibmaxlen;
-
-	if (*dd->ipath_statusp & IPATH_STATUS_IB_READY)
-		intval |= IPATH_LAYER_INT_IF_UP;
-	if (dd->ipath_lid)
-		intval |= IPATH_LAYER_INT_LID;
-	if (dd->ipath_mlid)
-		intval |= IPATH_LAYER_INT_BCAST;
-	/*
-	 * do this on open, in case low level is already up and
-	 * just layered driver was reloaded, etc.
-	 */
-	if (intval)
-		layer_intr(dd->ipath_layer.l_arg, intval);
-
-	ret = 0;
-bail:
-	mutex_unlock(&ipath_layer_mutex);
-
-	return ret;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_open);
-
-u16 ipath_layer_get_lid(struct ipath_devdata *dd)
-{
-	return dd->ipath_lid;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_lid);
-
-/**
- * ipath_layer_get_mac - get the MAC address
- * @dd: the infinipath device
- * @mac: the MAC is put here
- *
- * This is the EUID-64 OUI octets (top 3), then
- * skip the next 2 (which should both be zero or 0xff).
- * The returned MAC is in network order
- * mac points to at least 6 bytes of buffer
- * We assume that by the time the LID is set, that the GUID is as valid
- * as it's ever going to be, rather than adding yet another status bit.
- */
-
-int ipath_layer_get_mac(struct ipath_devdata *dd, u8 * mac)
-{
-	u8 *guid;
-
-	guid = (u8 *) &dd->ipath_guid;
-
-	mac[0] = guid[0];
-	mac[1] = guid[1];
-	mac[2] = guid[2];
-	mac[3] = guid[5];
-	mac[4] = guid[6];
-	mac[5] = guid[7];
-	if ((guid[3] || guid[4]) && !(guid[3] == 0xff && guid[4] == 0xff))
-		ipath_dbg("Warning, guid bytes 3 and 4 not 0 or 0xffff: "
-			  "%x %x\n", guid[3], guid[4]);
-	return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_mac);
-
-u16 ipath_layer_get_bcast(struct ipath_devdata *dd)
-{
-	return dd->ipath_mlid;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_bcast);
-
-int ipath_layer_send_hdr(struct ipath_devdata *dd, struct ether_header *hdr)
-{
-	int ret = 0;
-	u32 __iomem *piobuf;
-	u32 plen, *uhdr;
-	size_t count;
-	__be16 vlsllnh;
-
-	if (!(dd->ipath_flags & IPATH_RCVHDRSZ_SET)) {
-		ipath_dbg("send while not open\n");
-		ret = -EINVAL;
-	} else
-		if ((dd->ipath_flags & (IPATH_LINKUNK | IPATH_LINKDOWN)) ||
-		    dd->ipath_lid == 0) {
-			/*
-			 * lid check is for when sma hasn't yet configured
-			 */
-			ret = -ENETDOWN;
-			ipath_cdbg(VERBOSE, "send while not ready, "
-				   "mylid=%u, flags=0x%x\n",
-				   dd->ipath_lid, dd->ipath_flags);
-		}
-
-	vlsllnh = *((__be16 *) hdr);
-	if (vlsllnh != htons(IPATH_LRH_BTH)) {
-		ipath_dbg("Warning: lrh[0] wrong (%x, not %x); "
-			  "not sending\n", be16_to_cpu(vlsllnh),
-			  IPATH_LRH_BTH);
-		ret = -EINVAL;
-	}
-	if (ret)
-		goto done;
-
-	/* Get a PIO buffer to use. */
-	piobuf = ipath_getpiobuf(dd, NULL);
-	if (piobuf == NULL) {
-		ret = -EBUSY;
-		goto done;
-	}
-
-	plen = (sizeof(*hdr) >> 2); /* actual length */
-	ipath_cdbg(EPKT, "0x%x+1w pio %p\n", plen, piobuf);
-
-	writeq(plen+1, piobuf); /* len (+1 for pad) to pbc, no flags */
-	ipath_flush_wc();
-	piobuf += 2;
-	uhdr = (u32 *)hdr;
-	count = plen-1; /* amount we can copy before trigger word */
-	__iowrite32_copy(piobuf, uhdr, count);
-	ipath_flush_wc();
-	__raw_writel(uhdr[count], piobuf + count);
-	ipath_flush_wc(); /* ensure it's sent, now */
-
-	ipath_stats.sps_ether_spkts++;	/* ether packet sent */
-
-done:
-	return ret;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_send_hdr);
-
-int ipath_layer_set_piointbufavail_int(struct ipath_devdata *dd)
-{
-	set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
-
-	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
-			 dd->ipath_sendctrl);
-	return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_set_piointbufavail_int);
diff --git a/drivers/infiniband/hw/ipath/ipath_layer.h b/drivers/infiniband/hw/ipath/ipath_layer.h
deleted file mode 100644
index 415709c..0000000
--- a/drivers/infiniband/hw/ipath/ipath_layer.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, 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
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- *     Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *      - Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *
- *      - Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _IPATH_LAYER_H
-#define _IPATH_LAYER_H
-
-/*
- * This header file is for symbols shared between the infinipath driver
- * and drivers layered upon it (such as ipath).
- */
-
-struct sk_buff;
-struct ipath_devdata;
-struct ether_header;
-
-int ipath_layer_register(void *(*l_add)(int, struct ipath_devdata *),
-			 void (*l_remove)(void *),
-			 int (*l_intr)(void *, u32),
-			 int (*l_rcv)(void *, void *,
-				      struct sk_buff *),
-			 u16 rcv_opcode,
-			 int (*l_rcv_lid)(void *, void *));
-void ipath_layer_unregister(void);
-int ipath_layer_open(struct ipath_devdata *, u32 * pktmax);
-u16 ipath_layer_get_lid(struct ipath_devdata *dd);
-int ipath_layer_get_mac(struct ipath_devdata *dd, u8 *);
-u16 ipath_layer_get_bcast(struct ipath_devdata *dd);
-int ipath_layer_send_hdr(struct ipath_devdata *dd,
-			 struct ether_header *hdr);
-int ipath_layer_set_piointbufavail_int(struct ipath_devdata *dd);
-
-/* ipath_ether interrupt values */
-#define IPATH_LAYER_INT_IF_UP 0x2
-#define IPATH_LAYER_INT_IF_DOWN 0x4
-#define IPATH_LAYER_INT_LID 0x8
-#define IPATH_LAYER_INT_SEND_CONTINUE 0x10
-#define IPATH_LAYER_INT_BCAST 0x40
-
-extern unsigned ipath_debug; /* debugging bit mask */
-
-#endif				/* _IPATH_LAYER_H */
diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c
index d61c030..3d1432d 100644
--- a/drivers/infiniband/hw/ipath/ipath_mad.c
+++ b/drivers/infiniband/hw/ipath/ipath_mad.c
@@ -245,7 +245,7 @@
 
 	/* Only return the mkey if the protection field allows it. */
 	if (smp->method == IB_MGMT_METHOD_SET || dev->mkey == smp->mkey ||
-	    (dev->mkeyprot_resv_lmc >> 6) == 0)
+	    dev->mkeyprot == 0)
 		pip->mkey = dev->mkey;
 	pip->gid_prefix = dev->gid_prefix;
 	lid = dev->dd->ipath_lid;
@@ -264,7 +264,7 @@
 	pip->portphysstate_linkdown =
 		(ipath_cvt_physportstate[ibcstat & 0xf] << 4) |
 		(get_linkdowndefaultstate(dev->dd) ? 1 : 2);
-	pip->mkeyprot_resv_lmc = dev->mkeyprot_resv_lmc;
+	pip->mkeyprot_resv_lmc = (dev->mkeyprot << 6) | dev->dd->ipath_lmc;
 	pip->linkspeedactive_enabled = 0x11;	/* 2.5Gbps, 2.5Gbps */
 	switch (dev->dd->ipath_ibmtu) {
 	case 4096:
@@ -401,7 +401,7 @@
 	struct ib_port_info *pip = (struct ib_port_info *)smp->data;
 	struct ib_event event;
 	struct ipath_ibdev *dev;
-	u32 flags;
+	struct ipath_devdata *dd;
 	char clientrereg = 0;
 	u16 lid, smlid;
 	u8 lwe;
@@ -415,6 +415,7 @@
 		goto err;
 
 	dev = to_idev(ibdev);
+	dd = dev->dd;
 	event.device = ibdev;
 	event.element.port_num = port;
 
@@ -423,11 +424,12 @@
 	dev->mkey_lease_period = be16_to_cpu(pip->mkey_lease_period);
 
 	lid = be16_to_cpu(pip->lid);
-	if (lid != dev->dd->ipath_lid) {
+	if (dd->ipath_lid != lid ||
+	    dd->ipath_lmc != (pip->mkeyprot_resv_lmc & 7)) {
 		/* Must be a valid unicast LID address. */
 		if (lid == 0 || lid >= IPATH_MULTICAST_LID_BASE)
 			goto err;
-		ipath_set_lid(dev->dd, lid, pip->mkeyprot_resv_lmc & 7);
+		ipath_set_lid(dd, lid, pip->mkeyprot_resv_lmc & 7);
 		event.event = IB_EVENT_LID_CHANGE;
 		ib_dispatch_event(&event);
 	}
@@ -461,18 +463,18 @@
 	case 0: /* NOP */
 		break;
 	case 1: /* SLEEP */
-		if (set_linkdowndefaultstate(dev->dd, 1))
+		if (set_linkdowndefaultstate(dd, 1))
 			goto err;
 		break;
 	case 2: /* POLL */
-		if (set_linkdowndefaultstate(dev->dd, 0))
+		if (set_linkdowndefaultstate(dd, 0))
 			goto err;
 		break;
 	default:
 		goto err;
 	}
 
-	dev->mkeyprot_resv_lmc = pip->mkeyprot_resv_lmc;
+	dev->mkeyprot = pip->mkeyprot_resv_lmc >> 6;
 	dev->vl_high_limit = pip->vl_high_limit;
 
 	switch ((pip->neighbormtu_mastersmsl >> 4) & 0xF) {
@@ -495,7 +497,7 @@
 		/* XXX We have already partially updated our state! */
 		goto err;
 	}
-	ipath_set_mtu(dev->dd, mtu);
+	ipath_set_mtu(dd, mtu);
 
 	dev->sm_sl = pip->neighbormtu_mastersmsl & 0xF;
 
@@ -511,16 +513,16 @@
 	 * later.
 	 */
 	if (pip->pkey_violations == 0)
-		dev->z_pkey_violations = ipath_get_cr_errpkey(dev->dd);
+		dev->z_pkey_violations = ipath_get_cr_errpkey(dd);
 
 	if (pip->qkey_violations == 0)
 		dev->qkey_violations = 0;
 
 	ore = pip->localphyerrors_overrunerrors;
-	if (set_phyerrthreshold(dev->dd, (ore >> 4) & 0xF))
+	if (set_phyerrthreshold(dd, (ore >> 4) & 0xF))
 		goto err;
 
-	if (set_overrunthreshold(dev->dd, (ore & 0xF)))
+	if (set_overrunthreshold(dd, (ore & 0xF)))
 		goto err;
 
 	dev->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F;
@@ -538,7 +540,6 @@
 	 * is down or is being set to down.
 	 */
 	state = pip->linkspeed_portstate & 0xF;
-	flags = dev->dd->ipath_flags;
 	lstate = (pip->portphysstate_linkdown >> 4) & 0xF;
 	if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP))
 		goto err;
@@ -554,7 +555,7 @@
 		/* FALLTHROUGH */
 	case IB_PORT_DOWN:
 		if (lstate == 0)
-			if (get_linkdowndefaultstate(dev->dd))
+			if (get_linkdowndefaultstate(dd))
 				lstate = IPATH_IB_LINKDOWN_SLEEP;
 			else
 				lstate = IPATH_IB_LINKDOWN;
@@ -566,27 +567,13 @@
 			lstate = IPATH_IB_LINKDOWN_DISABLE;
 		else
 			goto err;
-		ipath_set_linkstate(dev->dd, lstate);
-		if (flags & IPATH_LINKACTIVE) {
-			event.event = IB_EVENT_PORT_ERR;
-			ib_dispatch_event(&event);
-		}
+		ipath_set_linkstate(dd, lstate);
 		break;
 	case IB_PORT_ARMED:
-		if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE)))
-			break;
-		ipath_set_linkstate(dev->dd, IPATH_IB_LINKARM);
-		if (flags & IPATH_LINKACTIVE) {
-			event.event = IB_EVENT_PORT_ERR;
-			ib_dispatch_event(&event);
-		}
+		ipath_set_linkstate(dd, IPATH_IB_LINKARM);
 		break;
 	case IB_PORT_ACTIVE:
-		if (!(flags & IPATH_LINKARMED))
-			break;
-		ipath_set_linkstate(dev->dd, IPATH_IB_LINKACTIVE);
-		event.event = IB_EVENT_PORT_ACTIVE;
-		ib_dispatch_event(&event);
+		ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE);
 		break;
 	default:
 		/* XXX We have already partially updated our state! */
@@ -1350,7 +1337,7 @@
 	if (dev->mkey_lease_timeout && jiffies >= dev->mkey_lease_timeout) {
 		/* Clear timeout and mkey protection field. */
 		dev->mkey_lease_timeout = 0;
-		dev->mkeyprot_resv_lmc &= 0x3F;
+		dev->mkeyprot = 0;
 	}
 
 	/*
@@ -1361,7 +1348,7 @@
 	    dev->mkey != smp->mkey &&
 	    (smp->method == IB_MGMT_METHOD_SET ||
 	     (smp->method == IB_MGMT_METHOD_GET &&
-	      (dev->mkeyprot_resv_lmc >> 7) != 0))) {
+	      dev->mkeyprot >= 2))) {
 		if (dev->mkey_violations != 0xFFFF)
 			++dev->mkey_violations;
 		if (dev->mkey_lease_timeout ||
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
index 1324b35..6a41fdb 100644
--- a/drivers/infiniband/hw/ipath/ipath_qp.c
+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
@@ -338,6 +338,7 @@
 	qp->s_busy = 0;
 	qp->s_flags &= IPATH_S_SIGNAL_REQ_WR;
 	qp->s_hdrwords = 0;
+	qp->s_wqe = NULL;
 	qp->s_psn = 0;
 	qp->r_psn = 0;
 	qp->r_msn = 0;
@@ -376,13 +377,15 @@
  * @err: the receive completion error to signal if a RWQE is active
  *
  * Flushes both send and receive work queues.
+ * Returns true if last WQE event should be generated.
  * The QP s_lock should be held and interrupts disabled.
  */
 
-void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
+int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
 {
 	struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
 	struct ib_wc wc;
+	int ret = 0;
 
 	ipath_dbg("QP%d/%d in error state\n",
 		  qp->ibqp.qp_num, qp->remote_qpn);
@@ -453,7 +456,10 @@
 		wq->tail = tail;
 
 		spin_unlock(&qp->r_rq.lock);
-	}
+	} else if (qp->ibqp.event_handler)
+		ret = 1;
+
+	return ret;
 }
 
 /**
@@ -472,6 +478,7 @@
 	struct ipath_qp *qp = to_iqp(ibqp);
 	enum ib_qp_state cur_state, new_state;
 	unsigned long flags;
+	int lastwqe = 0;
 	int ret;
 
 	spin_lock_irqsave(&qp->s_lock, flags);
@@ -531,7 +538,7 @@
 		break;
 
 	case IB_QPS_ERR:
-		ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
+		lastwqe = ipath_error_qp(qp, IB_WC_WR_FLUSH_ERR);
 		break;
 
 	default:
@@ -590,6 +597,14 @@
 	qp->state = new_state;
 	spin_unlock_irqrestore(&qp->s_lock, flags);
 
+	if (lastwqe) {
+		struct ib_event ev;
+
+		ev.device = qp->ibqp.device;
+		ev.element.qp = &qp->ibqp;
+		ev.event = IB_EVENT_QP_LAST_WQE_REACHED;
+		qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
+	}
 	ret = 0;
 	goto bail;
 
@@ -751,6 +766,9 @@
 	switch (init_attr->qp_type) {
 	case IB_QPT_UC:
 	case IB_QPT_RC:
+	case IB_QPT_UD:
+	case IB_QPT_SMI:
+	case IB_QPT_GSI:
 		sz = sizeof(struct ipath_sge) *
 			init_attr->cap.max_send_sge +
 			sizeof(struct ipath_swqe);
@@ -759,10 +777,6 @@
 			ret = ERR_PTR(-ENOMEM);
 			goto bail;
 		}
-		/* FALLTHROUGH */
-	case IB_QPT_UD:
-	case IB_QPT_SMI:
-	case IB_QPT_GSI:
 		sz = sizeof(*qp);
 		if (init_attr->srq) {
 			struct ipath_srq *srq = to_isrq(init_attr->srq);
@@ -805,8 +819,7 @@
 		spin_lock_init(&qp->r_rq.lock);
 		atomic_set(&qp->refcount, 0);
 		init_waitqueue_head(&qp->wait);
-		tasklet_init(&qp->s_task, ipath_do_ruc_send,
-			     (unsigned long)qp);
+		tasklet_init(&qp->s_task, ipath_do_send, (unsigned long)qp);
 		INIT_LIST_HEAD(&qp->piowait);
 		INIT_LIST_HEAD(&qp->timerwait);
 		qp->state = IB_QPS_RESET;
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index 46744ea..5c29b2b 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -81,9 +81,8 @@
  * Note that we are in the responder's side of the QP context.
  * Note the QP s_lock must be held.
  */
-static int ipath_make_rc_ack(struct ipath_qp *qp,
-			     struct ipath_other_headers *ohdr,
-			     u32 pmtu, u32 *bth0p, u32 *bth2p)
+static int ipath_make_rc_ack(struct ipath_ibdev *dev, struct ipath_qp *qp,
+			     struct ipath_other_headers *ohdr, u32 pmtu)
 {
 	struct ipath_ack_entry *e;
 	u32 hwords;
@@ -192,8 +191,7 @@
 	}
 	qp->s_hdrwords = hwords;
 	qp->s_cur_size = len;
-	*bth0p = bth0 | (1 << 22); /* Set M bit */
-	*bth2p = bth2;
+	ipath_make_ruc_header(dev, qp, ohdr, bth0, bth2);
 	return 1;
 
 bail:
@@ -203,32 +201,39 @@
 /**
  * ipath_make_rc_req - construct a request packet (SEND, RDMA r/w, ATOMIC)
  * @qp: a pointer to the QP
- * @ohdr: a pointer to the IB header being constructed
- * @pmtu: the path MTU
- * @bth0p: pointer to the BTH opcode word
- * @bth2p: pointer to the BTH PSN word
  *
  * Return 1 if constructed; otherwise, return 0.
- * Note the QP s_lock must be held and interrupts disabled.
  */
-int ipath_make_rc_req(struct ipath_qp *qp,
-		      struct ipath_other_headers *ohdr,
-		      u32 pmtu, u32 *bth0p, u32 *bth2p)
+int ipath_make_rc_req(struct ipath_qp *qp)
 {
 	struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
+	struct ipath_other_headers *ohdr;
 	struct ipath_sge_state *ss;
 	struct ipath_swqe *wqe;
 	u32 hwords;
 	u32 len;
 	u32 bth0;
 	u32 bth2;
+	u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
 	char newreq;
+	unsigned long flags;
+	int ret = 0;
+
+	ohdr = &qp->s_hdr.u.oth;
+	if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
+		ohdr = &qp->s_hdr.u.l.oth;
+
+	/*
+	 * The lock is needed to synchronize between the sending tasklet,
+	 * the receive interrupt handler, and timeout resends.
+	 */
+	spin_lock_irqsave(&qp->s_lock, flags);
 
 	/* Sending responses has higher priority over sending requests. */
 	if ((qp->r_head_ack_queue != qp->s_tail_ack_queue ||
 	     (qp->s_flags & IPATH_S_ACK_PENDING) ||
 	     qp->s_ack_state != OP(ACKNOWLEDGE)) &&
-	    ipath_make_rc_ack(qp, ohdr, pmtu, bth0p, bth2p))
+	    ipath_make_rc_ack(dev, qp, ohdr, pmtu))
 		goto done;
 
 	if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK) ||
@@ -560,13 +565,12 @@
 	qp->s_hdrwords = hwords;
 	qp->s_cur_sge = ss;
 	qp->s_cur_size = len;
-	*bth0p = bth0 | (qp->s_state << 24);
-	*bth2p = bth2;
+	ipath_make_ruc_header(dev, qp, ohdr, bth0 | (qp->s_state << 24), bth2);
 done:
-	return 1;
-
+	ret = 1;
 bail:
-	return 0;
+	spin_unlock_irqrestore(&qp->s_lock, flags);
+	return ret;
 }
 
 /**
@@ -627,7 +631,7 @@
 	/*
 	 * If we can send the ACK, clear the ACK state.
 	 */
-	if (ipath_verbs_send(dev->dd, hwords, (u32 *) &hdr, 0, NULL) == 0) {
+	if (ipath_verbs_send(qp, &hdr, hwords, NULL, 0) == 0) {
 		dev->n_unicast_xmit++;
 		goto done;
 	}
@@ -757,7 +761,9 @@
 		wc->vendor_err = 0;
 		wc->byte_len = 0;
 		wc->qp = &qp->ibqp;
+		wc->imm_data = 0;
 		wc->src_qp = qp->remote_qpn;
+		wc->wc_flags = 0;
 		wc->pkey_index = 0;
 		wc->slid = qp->remote_ah_attr.dlid;
 		wc->sl = qp->remote_ah_attr.sl;
@@ -1041,7 +1047,9 @@
 			wc.vendor_err = 0;
 			wc.byte_len = 0;
 			wc.qp = &qp->ibqp;
+			wc.imm_data = 0;
 			wc.src_qp = qp->remote_qpn;
+			wc.wc_flags = 0;
 			wc.pkey_index = 0;
 			wc.slid = qp->remote_ah_attr.dlid;
 			wc.sl = qp->remote_ah_attr.sl;
@@ -1454,6 +1462,19 @@
 			goto send_ack;
 		}
 		/*
+		 * Try to send a simple ACK to work around a Mellanox bug
+		 * which doesn't accept a RDMA read response or atomic
+		 * response as an ACK for earlier SENDs or RDMA writes.
+		 */
+		if (qp->r_head_ack_queue == qp->s_tail_ack_queue &&
+		    !(qp->s_flags & IPATH_S_ACK_PENDING) &&
+		    qp->s_ack_state == OP(ACKNOWLEDGE)) {
+			spin_unlock_irqrestore(&qp->s_lock, flags);
+			qp->r_nak_state = 0;
+			qp->r_ack_psn = qp->s_ack_queue[i].psn - 1;
+			goto send_ack;
+		}
+		/*
 		 * Resend the RDMA read or atomic op which
 		 * ACKs this duplicate request.
 		 */
@@ -1476,11 +1497,21 @@
 static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err)
 {
 	unsigned long flags;
+	int lastwqe;
 
 	spin_lock_irqsave(&qp->s_lock, flags);
 	qp->state = IB_QPS_ERR;
-	ipath_error_qp(qp, err);
+	lastwqe = ipath_error_qp(qp, err);
 	spin_unlock_irqrestore(&qp->s_lock, flags);
+
+	if (lastwqe) {
+		struct ib_event ev;
+
+		ev.device = qp->ibqp.device;
+		ev.element.qp = &qp->ibqp;
+		ev.event = IB_EVENT_QP_LAST_WQE_REACHED;
+		qp->ibqp.event_handler(&ev, qp->ibqp.qp_context);
+	}
 }
 
 static inline void ipath_update_ack_queue(struct ipath_qp *qp, unsigned n)
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index 8525674..4b6b7ee 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -31,6 +31,8 @@
  * SOFTWARE.
  */
 
+#include <linux/spinlock.h>
+
 #include "ipath_verbs.h"
 #include "ipath_kernel.h"
 
@@ -106,27 +108,30 @@
 	spin_unlock_irqrestore(&dev->pending_lock, flags);
 }
 
-static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe)
+/**
+ * ipath_init_sge - Validate a RWQE and fill in the SGE state
+ * @qp: the QP
+ *
+ * Return 1 if OK.
+ */
+int ipath_init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
+		   u32 *lengthp, struct ipath_sge_state *ss)
 {
-	int user = to_ipd(qp->ibqp.pd)->user;
 	int i, j, ret;
 	struct ib_wc wc;
 
-	qp->r_len = 0;
+	*lengthp = 0;
 	for (i = j = 0; i < wqe->num_sge; i++) {
 		if (wqe->sg_list[i].length == 0)
 			continue;
 		/* Check LKEY */
-		if ((user && wqe->sg_list[i].lkey == 0) ||
-		    !ipath_lkey_ok(qp, &qp->r_sg_list[j], &wqe->sg_list[i],
-				   IB_ACCESS_LOCAL_WRITE))
+		if (!ipath_lkey_ok(qp, j ? &ss->sg_list[j - 1] : &ss->sge,
+				   &wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE))
 			goto bad_lkey;
-		qp->r_len += wqe->sg_list[i].length;
+		*lengthp += wqe->sg_list[i].length;
 		j++;
 	}
-	qp->r_sge.sge = qp->r_sg_list[0];
-	qp->r_sge.sg_list = qp->r_sg_list + 1;
-	qp->r_sge.num_sge = j;
+	ss->num_sge = j;
 	ret = 1;
 	goto bail;
 
@@ -172,6 +177,8 @@
 	u32 tail;
 	int ret;
 
+	qp->r_sge.sg_list = qp->r_sg_list;
+
 	if (qp->ibqp.srq) {
 		srq = to_isrq(qp->ibqp.srq);
 		handler = srq->ibsrq.event_handler;
@@ -199,7 +206,8 @@
 		wqe = get_rwqe_ptr(rq, tail);
 		if (++tail >= rq->size)
 			tail = 0;
-	} while (!wr_id_only && !init_sge(qp, wqe));
+	} while (!wr_id_only && !ipath_init_sge(qp, wqe, &qp->r_len,
+						&qp->r_sge));
 	qp->r_wr_id = wqe->wr_id;
 	wq->tail = tail;
 
@@ -239,9 +247,9 @@
 
 /**
  * ipath_ruc_loopback - handle UC and RC lookback requests
- * @sqp: the loopback QP
+ * @sqp: the sending QP
  *
- * This is called from ipath_do_uc_send() or ipath_do_rc_send() to
+ * This is called from ipath_do_send() to
  * forward a WQE addressed to the same HCA.
  * Note that although we are single threaded due to the tasklet, we still
  * have to protect against post_send().  We don't have to worry about
@@ -450,40 +458,18 @@
 	wc.byte_len = wqe->length;
 	wc.qp = &qp->ibqp;
 	wc.src_qp = qp->remote_qpn;
-	/* XXX do we know which pkey matched? Only needed for GSI. */
 	wc.pkey_index = 0;
 	wc.slid = qp->remote_ah_attr.dlid;
 	wc.sl = qp->remote_ah_attr.sl;
 	wc.dlid_path_bits = 0;
+	wc.port_num = 1;
 	/* Signal completion event if the solicited bit is set. */
 	ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
 		       wqe->wr.send_flags & IB_SEND_SOLICITED);
 
 send_comp:
 	sqp->s_rnr_retry = sqp->s_rnr_retry_cnt;
-
-	if (!(sqp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
-	    (wqe->wr.send_flags & IB_SEND_SIGNALED)) {
-		wc.wr_id = wqe->wr.wr_id;
-		wc.status = IB_WC_SUCCESS;
-		wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
-		wc.vendor_err = 0;
-		wc.byte_len = wqe->length;
-		wc.qp = &sqp->ibqp;
-		wc.src_qp = 0;
-		wc.pkey_index = 0;
-		wc.slid = 0;
-		wc.sl = 0;
-		wc.dlid_path_bits = 0;
-		wc.port_num = 0;
-		ipath_cq_enter(to_icq(sqp->ibqp.send_cq), &wc, 0);
-	}
-
-	/* Update s_last now that we are finished with the SWQE */
-	spin_lock_irqsave(&sqp->s_lock, flags);
-	if (++sqp->s_last >= sqp->s_size)
-		sqp->s_last = 0;
-	spin_unlock_irqrestore(&sqp->s_lock, flags);
+	ipath_send_complete(sqp, wqe, IB_WC_SUCCESS);
 	goto again;
 
 done:
@@ -491,13 +477,11 @@
 		wake_up(&qp->wait);
 }
 
-static int want_buffer(struct ipath_devdata *dd)
+static void want_buffer(struct ipath_devdata *dd)
 {
 	set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
 	ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
 			 dd->ipath_sendctrl);
-
-	return 0;
 }
 
 /**
@@ -507,14 +491,11 @@
  *
  * Called when we run out of PIO buffers.
  */
-void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev)
+static void ipath_no_bufs_available(struct ipath_qp *qp,
+				    struct ipath_ibdev *dev)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&dev->pending_lock, flags);
-	if (list_empty(&qp->piowait))
-		list_add_tail(&qp->piowait, &dev->piowait);
-	spin_unlock_irqrestore(&dev->pending_lock, flags);
 	/*
 	 * Note that as soon as want_buffer() is called and
 	 * possibly before it returns, ipath_ib_piobufavail()
@@ -524,101 +505,14 @@
 	 * We leave the busy flag set so that another post send doesn't
 	 * try to put the same QP on the piowait list again.
 	 */
+	spin_lock_irqsave(&dev->pending_lock, flags);
+	list_add_tail(&qp->piowait, &dev->piowait);
+	spin_unlock_irqrestore(&dev->pending_lock, flags);
 	want_buffer(dev->dd);
 	dev->n_piowait++;
 }
 
 /**
- * ipath_post_ruc_send - post RC and UC sends
- * @qp: the QP to post on
- * @wr: the work request to send
- */
-int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr)
-{
-	struct ipath_swqe *wqe;
-	unsigned long flags;
-	u32 next;
-	int i, j;
-	int acc;
-	int ret;
-
-	/*
-	 * Don't allow RDMA reads or atomic operations on UC or
-	 * undefined operations.
-	 * Make sure buffer is large enough to hold the result for atomics.
-	 */
-	if (qp->ibqp.qp_type == IB_QPT_UC) {
-		if ((unsigned) wr->opcode >= IB_WR_RDMA_READ) {
-			ret = -EINVAL;
-			goto bail;
-		}
-	} else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD) {
-		ret = -EINVAL;
-		goto bail;
-	} else if (wr->opcode >= IB_WR_ATOMIC_CMP_AND_SWP &&
-		   (wr->num_sge == 0 ||
-		    wr->sg_list[0].length < sizeof(u64) ||
-		    wr->sg_list[0].addr & (sizeof(u64) - 1))) {
-		ret = -EINVAL;
-		goto bail;
-	} else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic) {
-		ret = -EINVAL;
-		goto bail;
-	}
-	/* IB spec says that num_sge == 0 is OK. */
-	if (wr->num_sge > qp->s_max_sge) {
-		ret = -ENOMEM;
-		goto bail;
-	}
-	spin_lock_irqsave(&qp->s_lock, flags);
-	next = qp->s_head + 1;
-	if (next >= qp->s_size)
-		next = 0;
-	if (next == qp->s_last) {
-		spin_unlock_irqrestore(&qp->s_lock, flags);
-		ret = -EINVAL;
-		goto bail;
-	}
-
-	wqe = get_swqe_ptr(qp, qp->s_head);
-	wqe->wr = *wr;
-	wqe->ssn = qp->s_ssn++;
-	wqe->sg_list[0].mr = NULL;
-	wqe->sg_list[0].vaddr = NULL;
-	wqe->sg_list[0].length = 0;
-	wqe->sg_list[0].sge_length = 0;
-	wqe->length = 0;
-	acc = wr->opcode >= IB_WR_RDMA_READ ? IB_ACCESS_LOCAL_WRITE : 0;
-	for (i = 0, j = 0; i < wr->num_sge; i++) {
-		if (to_ipd(qp->ibqp.pd)->user && wr->sg_list[i].lkey == 0) {
-			spin_unlock_irqrestore(&qp->s_lock, flags);
-			ret = -EINVAL;
-			goto bail;
-		}
-		if (wr->sg_list[i].length == 0)
-			continue;
-		if (!ipath_lkey_ok(qp, &wqe->sg_list[j], &wr->sg_list[i],
-				   acc)) {
-			spin_unlock_irqrestore(&qp->s_lock, flags);
-			ret = -EINVAL;
-			goto bail;
-		}
-		wqe->length += wr->sg_list[i].length;
-		j++;
-	}
-	wqe->wr.num_sge = j;
-	qp->s_head = next;
-	spin_unlock_irqrestore(&qp->s_lock, flags);
-
-	ipath_do_ruc_send((unsigned long) qp);
-
-	ret = 0;
-
-bail:
-	return ret;
-}
-
-/**
  * ipath_make_grh - construct a GRH header
  * @dev: a pointer to the ipath device
  * @hdr: a pointer to the GRH header being constructed
@@ -648,81 +542,16 @@
 	return sizeof(struct ib_grh) / sizeof(u32);
 }
 
-/**
- * ipath_do_ruc_send - perform a send on an RC or UC QP
- * @data: contains a pointer to the QP
- *
- * Process entries in the send work queue until credit or queue is
- * exhausted.  Only allow one CPU to send a packet per QP (tasklet).
- * Otherwise, after we drop the QP s_lock, two threads could send
- * packets out of order.
- */
-void ipath_do_ruc_send(unsigned long data)
+void ipath_make_ruc_header(struct ipath_ibdev *dev, struct ipath_qp *qp,
+			   struct ipath_other_headers *ohdr,
+			   u32 bth0, u32 bth2)
 {
-	struct ipath_qp *qp = (struct ipath_qp *)data;
-	struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
-	unsigned long flags;
 	u16 lrh0;
 	u32 nwords;
 	u32 extra_bytes;
-	u32 bth0;
-	u32 bth2;
-	u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
-	struct ipath_other_headers *ohdr;
-
-	if (test_and_set_bit(IPATH_S_BUSY, &qp->s_busy))
-		goto bail;
-
-	if (unlikely(qp->remote_ah_attr.dlid == dev->dd->ipath_lid)) {
-		ipath_ruc_loopback(qp);
-		goto clear;
-	}
-
-	ohdr = &qp->s_hdr.u.oth;
-	if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
-		ohdr = &qp->s_hdr.u.l.oth;
-
-again:
-	/* Check for a constructed packet to be sent. */
-	if (qp->s_hdrwords != 0) {
-		/*
-		 * If no PIO bufs are available, return.  An interrupt will
-		 * call ipath_ib_piobufavail() when one is available.
-		 */
-		if (ipath_verbs_send(dev->dd, qp->s_hdrwords,
-				     (u32 *) &qp->s_hdr, qp->s_cur_size,
-				     qp->s_cur_sge)) {
-			ipath_no_bufs_available(qp, dev);
-			goto bail;
-		}
-		dev->n_unicast_xmit++;
-		/* Record that we sent the packet and s_hdr is empty. */
-		qp->s_hdrwords = 0;
-	}
-
-	/*
-	 * The lock is needed to synchronize between setting
-	 * qp->s_ack_state, resend timer, and post_send().
-	 */
-	spin_lock_irqsave(&qp->s_lock, flags);
-
-	if (!((qp->ibqp.qp_type == IB_QPT_RC) ?
-	       ipath_make_rc_req(qp, ohdr, pmtu, &bth0, &bth2) :
-	       ipath_make_uc_req(qp, ohdr, pmtu, &bth0, &bth2))) {
-		/*
-		 * Clear the busy bit before unlocking to avoid races with
-		 * adding new work queue items and then failing to process
-		 * them.
-		 */
-		clear_bit(IPATH_S_BUSY, &qp->s_busy);
-		spin_unlock_irqrestore(&qp->s_lock, flags);
-		goto bail;
-	}
-
-	spin_unlock_irqrestore(&qp->s_lock, flags);
 
 	/* Construct the header. */
-	extra_bytes = (4 - qp->s_cur_size) & 3;
+	extra_bytes = -qp->s_cur_size & 3;
 	nwords = (qp->s_cur_size + extra_bytes) >> 2;
 	lrh0 = IPATH_LRH_BTH;
 	if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) {
@@ -734,20 +563,99 @@
 	lrh0 |= qp->remote_ah_attr.sl << 4;
 	qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
 	qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
-	qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords +
-				       SIZE_OF_CRC);
+	qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC);
 	qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid);
 	bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index);
 	bth0 |= extra_bytes << 20;
-	ohdr->bth[0] = cpu_to_be32(bth0);
+	ohdr->bth[0] = cpu_to_be32(bth0 | (1 << 22));
 	ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
 	ohdr->bth[2] = cpu_to_be32(bth2);
+}
 
-	/* Check for more work to do. */
-	goto again;
+/**
+ * ipath_do_send - perform a send on a QP
+ * @data: contains a pointer to the QP
+ *
+ * Process entries in the send work queue until credit or queue is
+ * exhausted.  Only allow one CPU to send a packet per QP (tasklet).
+ * Otherwise, two threads could send packets out of order.
+ */
+void ipath_do_send(unsigned long data)
+{
+	struct ipath_qp *qp = (struct ipath_qp *)data;
+	struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
+	int (*make_req)(struct ipath_qp *qp);
 
+	if (test_and_set_bit(IPATH_S_BUSY, &qp->s_busy))
+		goto bail;
+
+	if ((qp->ibqp.qp_type == IB_QPT_RC ||
+	     qp->ibqp.qp_type == IB_QPT_UC) &&
+	    qp->remote_ah_attr.dlid == dev->dd->ipath_lid) {
+		ipath_ruc_loopback(qp);
+		goto clear;
+	}
+
+	if (qp->ibqp.qp_type == IB_QPT_RC)
+	       make_req = ipath_make_rc_req;
+	else if (qp->ibqp.qp_type == IB_QPT_UC)
+	       make_req = ipath_make_uc_req;
+	else
+	       make_req = ipath_make_ud_req;
+
+again:
+	/* Check for a constructed packet to be sent. */
+	if (qp->s_hdrwords != 0) {
+		/*
+		 * If no PIO bufs are available, return.  An interrupt will
+		 * call ipath_ib_piobufavail() when one is available.
+		 */
+		if (ipath_verbs_send(qp, &qp->s_hdr, qp->s_hdrwords,
+				     qp->s_cur_sge, qp->s_cur_size)) {
+			ipath_no_bufs_available(qp, dev);
+			goto bail;
+		}
+		dev->n_unicast_xmit++;
+		/* Record that we sent the packet and s_hdr is empty. */
+		qp->s_hdrwords = 0;
+	}
+
+	if (make_req(qp))
+		goto again;
 clear:
 	clear_bit(IPATH_S_BUSY, &qp->s_busy);
-bail:
-	return;
+bail:;
+}
+
+void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe,
+			 enum ib_wc_status status)
+{
+	u32 last = qp->s_last;
+
+	if (++last == qp->s_size)
+		last = 0;
+	qp->s_last = last;
+
+	/* See ch. 11.2.4.1 and 10.7.3.1 */
+	if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
+	    (wqe->wr.send_flags & IB_SEND_SIGNALED) ||
+	    status != IB_WC_SUCCESS) {
+		struct ib_wc wc;
+
+		wc.wr_id = wqe->wr.wr_id;
+		wc.status = status;
+		wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
+		wc.vendor_err = 0;
+		wc.byte_len = wqe->length;
+		wc.imm_data = 0;
+		wc.qp = &qp->ibqp;
+		wc.src_qp = 0;
+		wc.wc_flags = 0;
+		wc.pkey_index = 0;
+		wc.slid = 0;
+		wc.sl = 0;
+		wc.dlid_path_bits = 0;
+		wc.port_num = 0;
+		ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0);
+	}
 }
diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c
index 73ed17d..f027141 100644
--- a/drivers/infiniband/hw/ipath/ipath_stats.c
+++ b/drivers/infiniband/hw/ipath/ipath_stats.c
@@ -55,7 +55,6 @@
 	u64 val64;
 	unsigned long t0, t1;
 	u64 ret;
-	unsigned long flags;
 
 	t0 = jiffies;
 	/* If fast increment counters are only 32 bits, snapshot them,
@@ -92,18 +91,12 @@
 	if (creg == dd->ipath_cregs->cr_wordsendcnt) {
 		if (val != dd->ipath_lastsword) {
 			dd->ipath_sword += val - dd->ipath_lastsword;
-			spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
-			dd->ipath_traffic_wds += val - dd->ipath_lastsword;
-			spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
 			dd->ipath_lastsword = val;
 		}
 		val64 = dd->ipath_sword;
 	} else if (creg == dd->ipath_cregs->cr_wordrcvcnt) {
 		if (val != dd->ipath_lastrword) {
 			dd->ipath_rword += val - dd->ipath_lastrword;
-			spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
-			dd->ipath_traffic_wds += val - dd->ipath_lastrword;
-			spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
 			dd->ipath_lastrword = val;
 		}
 		val64 = dd->ipath_rword;
@@ -196,6 +189,45 @@
 	}
 }
 
+static void ipath_chk_errormask(struct ipath_devdata *dd)
+{
+	static u32 fixed;
+	u32 ctrl;
+	unsigned long errormask;
+	unsigned long hwerrs;
+
+	if (!dd->ipath_errormask || !(dd->ipath_flags & IPATH_INITTED))
+		return;
+
+	errormask = ipath_read_kreg64(dd, dd->ipath_kregs->kr_errormask);
+
+	if (errormask == dd->ipath_errormask)
+		return;
+	fixed++;
+
+	hwerrs = ipath_read_kreg64(dd, dd->ipath_kregs->kr_hwerrstatus);
+	ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
+
+	ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
+		dd->ipath_errormask);
+
+	if ((hwerrs & dd->ipath_hwerrmask) ||
+		(ctrl & INFINIPATH_C_FREEZEMODE)) {
+		/* force re-interrupt of pending events, just in case */
+		ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrclear, 0ULL);
+		ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear, 0ULL);
+		ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, 0ULL);
+		dev_info(&dd->pcidev->dev,
+			"errormask fixed(%u) %lx -> %lx, ctrl %x hwerr %lx\n",
+			fixed, errormask, (unsigned long)dd->ipath_errormask,
+			ctrl, hwerrs);
+	} else
+		ipath_dbg("errormask fixed(%u) %lx -> %lx, no freeze\n",
+			fixed, errormask,
+			(unsigned long)dd->ipath_errormask);
+}
+
+
 /**
  * ipath_get_faststats - get word counters from chip before they overflow
  * @opaque - contains a pointer to the infinipath device ipath_devdata
@@ -208,6 +240,7 @@
 	u32 val;
 	static unsigned cnt;
 	unsigned long flags;
+	u64 traffic_wds;
 
 	/*
 	 * don't access the chip while running diags, or memory diags can
@@ -223,12 +256,13 @@
 	 * exceeding a threshold, so we need to check the word-counts
 	 * even if they are 64-bit.
 	 */
-	ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
-	ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
+	traffic_wds = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt) +
+		ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
 	spin_lock_irqsave(&dd->ipath_eep_st_lock, flags);
-	if (dd->ipath_traffic_wds  >= IPATH_TRAFFIC_ACTIVE_THRESHOLD)
+	traffic_wds -= dd->ipath_traffic_wds;
+	dd->ipath_traffic_wds += traffic_wds;
+	if (traffic_wds  >= IPATH_TRAFFIC_ACTIVE_THRESHOLD)
 		atomic_add(5, &dd->ipath_active_time); /* S/B #define */
-	dd->ipath_traffic_wds = 0;
 	spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags);
 
 	if (dd->ipath_flags & IPATH_32BITCOUNTERS) {
@@ -251,14 +285,13 @@
 		dd->ipath_lasterror = 0;
 	if (dd->ipath_lasthwerror)
 		dd->ipath_lasthwerror = 0;
-	if ((dd->ipath_maskederrs & ~dd->ipath_ignorederrs)
+	if (dd->ipath_maskederrs
 	    && time_after(jiffies, dd->ipath_unmasktime)) {
 		char ebuf[256];
 		int iserr;
 		iserr = ipath_decode_err(ebuf, sizeof ebuf,
-				 (dd->ipath_maskederrs & ~dd->
-				  ipath_ignorederrs));
-		if ((dd->ipath_maskederrs & ~dd->ipath_ignorederrs) &
+			dd->ipath_maskederrs);
+		if (dd->ipath_maskederrs &
 				~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL |
 				INFINIPATH_E_PKTERRS ))
 			ipath_dev_err(dd, "Re-enabling masked errors "
@@ -278,9 +311,12 @@
 				ipath_cdbg(ERRPKT, "Re-enabling packet"
 						" problem interrupt (%s)\n", ebuf);
 		}
-		dd->ipath_maskederrs = dd->ipath_ignorederrs;
+
+		/* re-enable masked errors */
+		dd->ipath_errormask |= dd->ipath_maskederrs;
 		ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask,
-				 ~dd->ipath_maskederrs);
+			dd->ipath_errormask);
+		dd->ipath_maskederrs = 0;
 	}
 
 	/* limit qfull messages to ~one per minute per port */
@@ -294,6 +330,7 @@
 		}
 	}
 
+	ipath_chk_errormask(dd);
 done:
 	mod_timer(&dd->ipath_stats_timer, jiffies + HZ * 5);
 }
diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c
index 16238cd..e1ad7cf 100644
--- a/drivers/infiniband/hw/ipath/ipath_sysfs.c
+++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c
@@ -163,6 +163,42 @@
 	return scnprintf(buf, PAGE_SIZE, "%s", dd->ipath_boardversion);
 }
 
+static ssize_t show_lmc(struct device *dev,
+			struct device_attribute *attr,
+			char *buf)
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_lmc);
+}
+
+static ssize_t store_lmc(struct device *dev,
+			 struct device_attribute *attr,
+			 const char *buf,
+			 size_t count)
+{
+	struct ipath_devdata *dd = dev_get_drvdata(dev);
+	u16 lmc = 0;
+	int ret;
+
+	ret = ipath_parse_ushort(buf, &lmc);
+	if (ret < 0)
+		goto invalid;
+
+	if (lmc > 7) {
+		ret = -EINVAL;
+		goto invalid;
+	}
+
+	ipath_set_lid(dd, dd->ipath_lid, lmc);
+
+	goto bail;
+invalid:
+	ipath_dev_err(dd, "attempt to set invalid LMC %u\n", lmc);
+bail:
+	return ret;
+}
+
 static ssize_t show_lid(struct device *dev,
 			struct device_attribute *attr,
 			char *buf)
@@ -190,7 +226,7 @@
 		goto invalid;
 	}
 
-	ipath_set_lid(dd, lid, 0);
+	ipath_set_lid(dd, lid, dd->ipath_lmc);
 
 	goto bail;
 invalid:
@@ -648,6 +684,7 @@
 };
 
 static DEVICE_ATTR(guid, S_IWUSR | S_IRUGO, show_guid, store_guid);
+static DEVICE_ATTR(lmc, S_IWUSR | S_IRUGO, show_lmc, store_lmc);
 static DEVICE_ATTR(lid, S_IWUSR | S_IRUGO, show_lid, store_lid);
 static DEVICE_ATTR(link_state, S_IWUSR, NULL, store_link_state);
 static DEVICE_ATTR(mlid, S_IWUSR | S_IRUGO, show_mlid, store_mlid);
@@ -667,6 +704,7 @@
 
 static struct attribute *dev_attributes[] = {
 	&dev_attr_guid.attr,
+	&dev_attr_lmc.attr,
 	&dev_attr_lid.attr,
 	&dev_attr_link_state.attr,
 	&dev_attr_mlid.attr,
diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c
index 8380fbc..2dd8de2 100644
--- a/drivers/infiniband/hw/ipath/ipath_uc.c
+++ b/drivers/infiniband/hw/ipath/ipath_uc.c
@@ -37,72 +37,40 @@
 /* cut down ridiculously long IB macro names */
 #define OP(x) IB_OPCODE_UC_##x
 
-static void complete_last_send(struct ipath_qp *qp, struct ipath_swqe *wqe,
-			       struct ib_wc *wc)
-{
-	if (++qp->s_last == qp->s_size)
-		qp->s_last = 0;
-	if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
-	    (wqe->wr.send_flags & IB_SEND_SIGNALED)) {
-		wc->wr_id = wqe->wr.wr_id;
-		wc->status = IB_WC_SUCCESS;
-		wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
-		wc->vendor_err = 0;
-		wc->byte_len = wqe->length;
-		wc->qp = &qp->ibqp;
-		wc->src_qp = qp->remote_qpn;
-		wc->pkey_index = 0;
-		wc->slid = qp->remote_ah_attr.dlid;
-		wc->sl = qp->remote_ah_attr.sl;
-		wc->dlid_path_bits = 0;
-		wc->port_num = 0;
-		ipath_cq_enter(to_icq(qp->ibqp.send_cq), wc, 0);
-	}
-}
-
 /**
  * ipath_make_uc_req - construct a request packet (SEND, RDMA write)
  * @qp: a pointer to the QP
- * @ohdr: a pointer to the IB header being constructed
- * @pmtu: the path MTU
- * @bth0p: pointer to the BTH opcode word
- * @bth2p: pointer to the BTH PSN word
  *
  * Return 1 if constructed; otherwise, return 0.
- * Note the QP s_lock must be held and interrupts disabled.
  */
-int ipath_make_uc_req(struct ipath_qp *qp,
-		      struct ipath_other_headers *ohdr,
-		      u32 pmtu, u32 *bth0p, u32 *bth2p)
+int ipath_make_uc_req(struct ipath_qp *qp)
 {
+	struct ipath_other_headers *ohdr;
 	struct ipath_swqe *wqe;
 	u32 hwords;
 	u32 bth0;
 	u32 len;
-	struct ib_wc wc;
+	u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
+	int ret = 0;
 
 	if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK))
 		goto done;
 
+	ohdr = &qp->s_hdr.u.oth;
+	if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
+		ohdr = &qp->s_hdr.u.l.oth;
+
 	/* header size in 32-bit words LRH+BTH = (8+12)/4. */
 	hwords = 5;
 	bth0 = 1 << 22; /* Set M bit */
 
 	/* Get the next send request. */
-	wqe = get_swqe_ptr(qp, qp->s_last);
+	wqe = get_swqe_ptr(qp, qp->s_cur);
+	qp->s_wqe = NULL;
 	switch (qp->s_state) {
 	default:
-		/*
-		 * Signal the completion of the last send
-		 * (if there is one).
-		 */
-		if (qp->s_last != qp->s_tail) {
-			complete_last_send(qp, wqe, &wc);
-			wqe = get_swqe_ptr(qp, qp->s_last);
-		}
-
 		/* Check if send work queue is empty. */
-		if (qp->s_tail == qp->s_head)
+		if (qp->s_cur == qp->s_head)
 			goto done;
 		/*
 		 * Start a new request.
@@ -131,6 +99,9 @@
 			}
 			if (wqe->wr.send_flags & IB_SEND_SOLICITED)
 				bth0 |= 1 << 23;
+			qp->s_wqe = wqe;
+			if (++qp->s_cur >= qp->s_size)
+				qp->s_cur = 0;
 			break;
 
 		case IB_WR_RDMA_WRITE:
@@ -157,13 +128,14 @@
 				if (wqe->wr.send_flags & IB_SEND_SOLICITED)
 					bth0 |= 1 << 23;
 			}
+			qp->s_wqe = wqe;
+			if (++qp->s_cur >= qp->s_size)
+				qp->s_cur = 0;
 			break;
 
 		default:
 			goto done;
 		}
-		if (++qp->s_tail >= qp->s_size)
-			qp->s_tail = 0;
 		break;
 
 	case OP(SEND_FIRST):
@@ -185,6 +157,9 @@
 		}
 		if (wqe->wr.send_flags & IB_SEND_SOLICITED)
 			bth0 |= 1 << 23;
+		qp->s_wqe = wqe;
+		if (++qp->s_cur >= qp->s_size)
+			qp->s_cur = 0;
 		break;
 
 	case OP(RDMA_WRITE_FIRST):
@@ -207,18 +182,22 @@
 			if (wqe->wr.send_flags & IB_SEND_SOLICITED)
 				bth0 |= 1 << 23;
 		}
+		qp->s_wqe = wqe;
+		if (++qp->s_cur >= qp->s_size)
+			qp->s_cur = 0;
 		break;
 	}
 	qp->s_len -= len;
 	qp->s_hdrwords = hwords;
 	qp->s_cur_sge = &qp->s_sge;
 	qp->s_cur_size = len;
-	*bth0p = bth0 | (qp->s_state << 24);
-	*bth2p = qp->s_next_psn++ & IPATH_PSN_MASK;
-	return 1;
+	ipath_make_ruc_header(to_idev(qp->ibqp.device),
+			      qp, ohdr, bth0 | (qp->s_state << 24),
+			      qp->s_next_psn++ & IPATH_PSN_MASK);
+	ret = 1;
 
 done:
-	return 0;
+	return ret;
 }
 
 /**
@@ -485,6 +464,16 @@
 
 	case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE):
 	rdma_last_imm:
+		if (header_in_data) {
+			wc.imm_data = *(__be32 *) data;
+			data += sizeof(__be32);
+		} else {
+			/* Immediate data comes after BTH */
+			wc.imm_data = ohdr->u.imm_data;
+		}
+		hdrsize += 4;
+		wc.wc_flags = IB_WC_WITH_IMM;
+
 		/* Get the number of bytes the message was padded by. */
 		pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3;
 		/* Check for invalid length. */
@@ -505,16 +494,7 @@
 			dev->n_pkt_drops++;
 			goto done;
 		}
-		if (header_in_data) {
-			wc.imm_data = *(__be32 *) data;
-			data += sizeof(__be32);
-		} else {
-			/* Immediate data comes after BTH */
-			wc.imm_data = ohdr->u.imm_data;
-		}
-		hdrsize += 4;
-		wc.wc_flags = IB_WC_WITH_IMM;
-		wc.byte_len = 0;
+		wc.byte_len = qp->r_len;
 		goto last_imm;
 
 	case OP(RDMA_WRITE_LAST):
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
index f9a3338..16a2a93 100644
--- a/drivers/infiniband/hw/ipath/ipath_ud.c
+++ b/drivers/infiniband/hw/ipath/ipath_ud.c
@@ -36,68 +36,17 @@
 #include "ipath_verbs.h"
 #include "ipath_kernel.h"
 
-static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
-		    u32 *lengthp, struct ipath_sge_state *ss)
-{
-	int user = to_ipd(qp->ibqp.pd)->user;
-	int i, j, ret;
-	struct ib_wc wc;
-
-	*lengthp = 0;
-	for (i = j = 0; i < wqe->num_sge; i++) {
-		if (wqe->sg_list[i].length == 0)
-			continue;
-		/* Check LKEY */
-		if ((user && wqe->sg_list[i].lkey == 0) ||
-		    !ipath_lkey_ok(qp, j ? &ss->sg_list[j - 1] : &ss->sge,
-				   &wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE))
-			goto bad_lkey;
-		*lengthp += wqe->sg_list[i].length;
-		j++;
-	}
-	ss->num_sge = j;
-	ret = 1;
-	goto bail;
-
-bad_lkey:
-	wc.wr_id = wqe->wr_id;
-	wc.status = IB_WC_LOC_PROT_ERR;
-	wc.opcode = IB_WC_RECV;
-	wc.vendor_err = 0;
-	wc.byte_len = 0;
-	wc.imm_data = 0;
-	wc.qp = &qp->ibqp;
-	wc.src_qp = 0;
-	wc.wc_flags = 0;
-	wc.pkey_index = 0;
-	wc.slid = 0;
-	wc.sl = 0;
-	wc.dlid_path_bits = 0;
-	wc.port_num = 0;
-	/* Signal solicited completion event. */
-	ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
-	ret = 0;
-bail:
-	return ret;
-}
-
 /**
  * ipath_ud_loopback - handle send on loopback QPs
- * @sqp: the QP
- * @ss: the SGE state
- * @length: the length of the data to send
- * @wr: the work request
- * @wc: the work completion entry
+ * @sqp: the sending QP
+ * @swqe: the send work request
  *
- * This is called from ipath_post_ud_send() to forward a WQE addressed
+ * This is called from ipath_make_ud_req() to forward a WQE addressed
  * to the same HCA.
  * Note that the receive interrupt handler may be calling ipath_ud_rcv()
  * while this is being called.
  */
-static void ipath_ud_loopback(struct ipath_qp *sqp,
-			      struct ipath_sge_state *ss,
-			      u32 length, struct ib_send_wr *wr,
-			      struct ib_wc *wc)
+static void ipath_ud_loopback(struct ipath_qp *sqp, struct ipath_swqe *swqe)
 {
 	struct ipath_ibdev *dev = to_idev(sqp->ibqp.device);
 	struct ipath_qp *qp;
@@ -110,12 +59,18 @@
 	struct ipath_rwq *wq;
 	struct ipath_rwqe *wqe;
 	void (*handler)(struct ib_event *, void *);
+	struct ib_wc wc;
 	u32 tail;
 	u32 rlen;
+	u32 length;
 
-	qp = ipath_lookup_qpn(&dev->qp_table, wr->wr.ud.remote_qpn);
-	if (!qp)
-		return;
+	qp = ipath_lookup_qpn(&dev->qp_table, swqe->wr.wr.ud.remote_qpn);
+	if (!qp) {
+		dev->n_pkt_drops++;
+		goto send_comp;
+	}
+
+	rsge.sg_list = NULL;
 
 	/*
 	 * Check that the qkey matches (except for QP0, see 9.6.1.4.1).
@@ -123,39 +78,34 @@
 	 * qkey from the QP context instead of the WR (see 10.2.5).
 	 */
 	if (unlikely(qp->ibqp.qp_num &&
-		     ((int) wr->wr.ud.remote_qkey < 0
-		      ? qp->qkey : wr->wr.ud.remote_qkey) != qp->qkey)) {
+		     ((int) swqe->wr.wr.ud.remote_qkey < 0 ?
+		      sqp->qkey : swqe->wr.wr.ud.remote_qkey) != qp->qkey)) {
 		/* XXX OK to lose a count once in a while. */
 		dev->qkey_violations++;
 		dev->n_pkt_drops++;
-		goto done;
+		goto drop;
 	}
 
 	/*
 	 * A GRH is expected to preceed the data even if not
 	 * present on the wire.
 	 */
-	wc->byte_len = length + sizeof(struct ib_grh);
+	length = swqe->length;
+	wc.byte_len = length + sizeof(struct ib_grh);
 
-	if (wr->opcode == IB_WR_SEND_WITH_IMM) {
-		wc->wc_flags = IB_WC_WITH_IMM;
-		wc->imm_data = wr->imm_data;
+	if (swqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
+		wc.wc_flags = IB_WC_WITH_IMM;
+		wc.imm_data = swqe->wr.imm_data;
 	} else {
-		wc->wc_flags = 0;
-		wc->imm_data = 0;
+		wc.wc_flags = 0;
+		wc.imm_data = 0;
 	}
 
-	if (wr->num_sge > 1) {
-		rsge.sg_list = kmalloc((wr->num_sge - 1) *
-					sizeof(struct ipath_sge),
-				       GFP_ATOMIC);
-	} else
-		rsge.sg_list = NULL;
-
 	/*
-	 * Get the next work request entry to find where to put the data.
-	 * Note that it is safe to drop the lock after changing rq->tail
-	 * since ipath_post_receive() won't fill the empty slot.
+	 * This would be a lot simpler if we could call ipath_get_rwqe()
+	 * but that uses state that the receive interrupt handler uses
+	 * so we would need to lock out receive interrupts while doing
+	 * local loopback.
 	 */
 	if (qp->ibqp.srq) {
 		srq = to_isrq(qp->ibqp.srq);
@@ -167,32 +117,53 @@
 		rq = &qp->r_rq;
 	}
 
+	if (rq->max_sge > 1) {
+		/*
+		 * XXX We could use GFP_KERNEL if ipath_do_send()
+		 * was always called from the tasklet instead of
+		 * from ipath_post_send().
+		 */
+		rsge.sg_list = kmalloc((rq->max_sge - 1) *
+					sizeof(struct ipath_sge),
+				       GFP_ATOMIC);
+		if (!rsge.sg_list) {
+			dev->n_pkt_drops++;
+			goto drop;
+		}
+	}
+
+	/*
+	 * Get the next work request entry to find where to put the data.
+	 * Note that it is safe to drop the lock after changing rq->tail
+	 * since ipath_post_receive() won't fill the empty slot.
+	 */
 	spin_lock_irqsave(&rq->lock, flags);
 	wq = rq->wq;
 	tail = wq->tail;
-	while (1) {
-		if (unlikely(tail == wq->head)) {
-			spin_unlock_irqrestore(&rq->lock, flags);
-			dev->n_pkt_drops++;
-			goto bail_sge;
-		}
-		/* Make sure entry is read after head index is read. */
-		smp_rmb();
-		wqe = get_rwqe_ptr(rq, tail);
-		if (++tail >= rq->size)
-			tail = 0;
-		if (init_sge(qp, wqe, &rlen, &rsge))
-			break;
-		wq->tail = tail;
-	}
-	/* Silently drop packets which are too big. */
-	if (wc->byte_len > rlen) {
+	/* Validate tail before using it since it is user writable. */
+	if (tail >= rq->size)
+		tail = 0;
+	if (unlikely(tail == wq->head)) {
 		spin_unlock_irqrestore(&rq->lock, flags);
 		dev->n_pkt_drops++;
-		goto bail_sge;
+		goto drop;
 	}
+	wqe = get_rwqe_ptr(rq, tail);
+	if (!ipath_init_sge(qp, wqe, &rlen, &rsge)) {
+		spin_unlock_irqrestore(&rq->lock, flags);
+		dev->n_pkt_drops++;
+		goto drop;
+	}
+	/* Silently drop packets which are too big. */
+	if (wc.byte_len > rlen) {
+		spin_unlock_irqrestore(&rq->lock, flags);
+		dev->n_pkt_drops++;
+		goto drop;
+	}
+	if (++tail >= rq->size)
+		tail = 0;
 	wq->tail = tail;
-	wc->wr_id = wqe->wr_id;
+	wc.wr_id = wqe->wr_id;
 	if (handler) {
 		u32 n;
 
@@ -221,13 +192,13 @@
 	} else
 		spin_unlock_irqrestore(&rq->lock, flags);
 
-	ah_attr = &to_iah(wr->wr.ud.ah)->attr;
+	ah_attr = &to_iah(swqe->wr.wr.ud.ah)->attr;
 	if (ah_attr->ah_flags & IB_AH_GRH) {
 		ipath_copy_sge(&rsge, &ah_attr->grh, sizeof(struct ib_grh));
-		wc->wc_flags |= IB_WC_GRH;
+		wc.wc_flags |= IB_WC_GRH;
 	} else
 		ipath_skip_sge(&rsge, sizeof(struct ib_grh));
-	sge = &ss->sge;
+	sge = swqe->sg_list;
 	while (length) {
 		u32 len = sge->length;
 
@@ -241,8 +212,8 @@
 		sge->length -= len;
 		sge->sge_length -= len;
 		if (sge->sge_length == 0) {
-			if (--ss->num_sge)
-				*sge = *ss->sg_list++;
+			if (--swqe->wr.num_sge)
+				sge++;
 		} else if (sge->length == 0 && sge->mr != NULL) {
 			if (++sge->n >= IPATH_SEGSZ) {
 				if (++sge->m >= sge->mr->mapsz)
@@ -256,123 +227,60 @@
 		}
 		length -= len;
 	}
-	wc->status = IB_WC_SUCCESS;
-	wc->opcode = IB_WC_RECV;
-	wc->vendor_err = 0;
-	wc->qp = &qp->ibqp;
-	wc->src_qp = sqp->ibqp.qp_num;
+	wc.status = IB_WC_SUCCESS;
+	wc.opcode = IB_WC_RECV;
+	wc.vendor_err = 0;
+	wc.qp = &qp->ibqp;
+	wc.src_qp = sqp->ibqp.qp_num;
 	/* XXX do we know which pkey matched? Only needed for GSI. */
-	wc->pkey_index = 0;
-	wc->slid = dev->dd->ipath_lid |
+	wc.pkey_index = 0;
+	wc.slid = dev->dd->ipath_lid |
 		(ah_attr->src_path_bits &
-		 ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1));
-	wc->sl = ah_attr->sl;
-	wc->dlid_path_bits =
-		ah_attr->dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+		 ((1 << dev->dd->ipath_lmc) - 1));
+	wc.sl = ah_attr->sl;
+	wc.dlid_path_bits =
+		ah_attr->dlid & ((1 << dev->dd->ipath_lmc) - 1);
+	wc.port_num = 1;
 	/* Signal completion event if the solicited bit is set. */
-	ipath_cq_enter(to_icq(qp->ibqp.recv_cq), wc,
-		       wr->send_flags & IB_SEND_SOLICITED);
-
-bail_sge:
+	ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
+		       swqe->wr.send_flags & IB_SEND_SOLICITED);
+drop:
 	kfree(rsge.sg_list);
-done:
 	if (atomic_dec_and_test(&qp->refcount))
 		wake_up(&qp->wait);
+send_comp:
+	ipath_send_complete(sqp, swqe, IB_WC_SUCCESS);
 }
 
 /**
- * ipath_post_ud_send - post a UD send on QP
+ * ipath_make_ud_req - construct a UD request packet
  * @qp: the QP
- * @wr: the work request
  *
- * Note that we actually send the data as it is posted instead of putting
- * the request into a ring buffer.  If we wanted to use a ring buffer,
- * we would need to save a reference to the destination address in the SWQE.
+ * Return 1 if constructed; otherwise, return 0.
  */
-int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
+int ipath_make_ud_req(struct ipath_qp *qp)
 {
 	struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
 	struct ipath_other_headers *ohdr;
 	struct ib_ah_attr *ah_attr;
-	struct ipath_sge_state ss;
-	struct ipath_sge *sg_list;
-	struct ib_wc wc;
-	u32 hwords;
+	struct ipath_swqe *wqe;
 	u32 nwords;
-	u32 len;
 	u32 extra_bytes;
 	u32 bth0;
 	u16 lrh0;
 	u16 lid;
-	int i;
-	int ret;
+	int ret = 0;
 
-	if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)) {
-		ret = 0;
+	if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK)))
 		goto bail;
-	}
 
-	if (wr->wr.ud.ah->pd != qp->ibqp.pd) {
-		ret = -EPERM;
+	if (qp->s_cur == qp->s_head)
 		goto bail;
-	}
 
-	/* IB spec says that num_sge == 0 is OK. */
-	if (wr->num_sge > qp->s_max_sge) {
-		ret = -EINVAL;
-		goto bail;
-	}
-
-	if (wr->num_sge > 1) {
-		sg_list = kmalloc((qp->s_max_sge - 1) * sizeof(*sg_list),
-				  GFP_ATOMIC);
-		if (!sg_list) {
-			ret = -ENOMEM;
-			goto bail;
-		}
-	} else
-		sg_list = NULL;
-
-	/* Check the buffer to send. */
-	ss.sg_list = sg_list;
-	ss.sge.mr = NULL;
-	ss.sge.vaddr = NULL;
-	ss.sge.length = 0;
-	ss.sge.sge_length = 0;
-	ss.num_sge = 0;
-	len = 0;
-	for (i = 0; i < wr->num_sge; i++) {
-		/* Check LKEY */
-		if (to_ipd(qp->ibqp.pd)->user && wr->sg_list[i].lkey == 0) {
-			ret = -EINVAL;
-			goto bail;
-		}
-
-		if (wr->sg_list[i].length == 0)
-			continue;
-		if (!ipath_lkey_ok(qp, ss.num_sge ?
-				   sg_list + ss.num_sge - 1 : &ss.sge,
-				   &wr->sg_list[i], 0)) {
-			ret = -EINVAL;
-			goto bail;
-		}
-		len += wr->sg_list[i].length;
-		ss.num_sge++;
-	}
-	/* Check for invalid packet size. */
-	if (len > dev->dd->ipath_ibmtu) {
-		ret = -EINVAL;
-		goto bail;
-	}
-	extra_bytes = (4 - len) & 3;
-	nwords = (len + extra_bytes) >> 2;
+	wqe = get_swqe_ptr(qp, qp->s_cur);
 
 	/* Construct the header. */
-	ah_attr = &to_iah(wr->wr.ud.ah)->attr;
-	if (ah_attr->dlid == 0) {
-		ret = -EINVAL;
-		goto bail;
-	}
+	ah_attr = &to_iah(wqe->wr.wr.ud.ah)->attr;
 	if (ah_attr->dlid >= IPATH_MULTICAST_LID_BASE) {
 		if (ah_attr->dlid != IPATH_PERMISSIVE_LID)
 			dev->n_multicast_xmit++;
@@ -381,74 +289,63 @@
 	} else {
 		dev->n_unicast_xmit++;
 		lid = ah_attr->dlid &
-			~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+			~((1 << dev->dd->ipath_lmc) - 1);
 		if (unlikely(lid == dev->dd->ipath_lid)) {
-			/*
-			 * Pass in an uninitialized ib_wc to save stack
-			 * space.
-			 */
-			ipath_ud_loopback(qp, &ss, len, wr, &wc);
+			ipath_ud_loopback(qp, wqe);
 			goto done;
 		}
 	}
+
+	extra_bytes = -wqe->length & 3;
+	nwords = (wqe->length + extra_bytes) >> 2;
+
+	/* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */
+	qp->s_hdrwords = 7;
+	if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM)
+		qp->s_hdrwords++;
+	qp->s_cur_size = wqe->length;
+	qp->s_cur_sge = &qp->s_sge;
+	qp->s_wqe = wqe;
+	qp->s_sge.sge = wqe->sg_list[0];
+	qp->s_sge.sg_list = wqe->sg_list + 1;
+	qp->s_sge.num_sge = wqe->wr.num_sge;
+
 	if (ah_attr->ah_flags & IB_AH_GRH) {
 		/* Header size in 32-bit words. */
-		hwords = 17;
+		qp->s_hdrwords += ipath_make_grh(dev, &qp->s_hdr.u.l.grh,
+						 &ah_attr->grh,
+						 qp->s_hdrwords, nwords);
 		lrh0 = IPATH_LRH_GRH;
 		ohdr = &qp->s_hdr.u.l.oth;
-		qp->s_hdr.u.l.grh.version_tclass_flow =
-			cpu_to_be32((6 << 28) |
-				    (ah_attr->grh.traffic_class << 20) |
-				    ah_attr->grh.flow_label);
-		qp->s_hdr.u.l.grh.paylen =
-			cpu_to_be16(((wr->opcode ==
-				      IB_WR_SEND_WITH_IMM ? 6 : 5) +
-				     nwords + SIZE_OF_CRC) << 2);
-		/* next_hdr is defined by C8-7 in ch. 8.4.1 */
-		qp->s_hdr.u.l.grh.next_hdr = 0x1B;
-		qp->s_hdr.u.l.grh.hop_limit = ah_attr->grh.hop_limit;
-		/* The SGID is 32-bit aligned. */
-		qp->s_hdr.u.l.grh.sgid.global.subnet_prefix =
-			dev->gid_prefix;
-		qp->s_hdr.u.l.grh.sgid.global.interface_id =
-			dev->dd->ipath_guid;
-		qp->s_hdr.u.l.grh.dgid = ah_attr->grh.dgid;
 		/*
 		 * Don't worry about sending to locally attached multicast
 		 * QPs.  It is unspecified by the spec. what happens.
 		 */
 	} else {
 		/* Header size in 32-bit words. */
-		hwords = 7;
 		lrh0 = IPATH_LRH_BTH;
 		ohdr = &qp->s_hdr.u.oth;
 	}
-	if (wr->opcode == IB_WR_SEND_WITH_IMM) {
-		ohdr->u.ud.imm_data = wr->imm_data;
-		wc.imm_data = wr->imm_data;
-		hwords += 1;
+	if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
+		ohdr->u.ud.imm_data = wqe->wr.imm_data;
 		bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24;
-	} else if (wr->opcode == IB_WR_SEND) {
-		wc.imm_data = 0;
+	} else
 		bth0 = IB_OPCODE_UD_SEND_ONLY << 24;
-	} else {
-		ret = -EINVAL;
-		goto bail;
-	}
 	lrh0 |= ah_attr->sl << 4;
 	if (qp->ibqp.qp_type == IB_QPT_SMI)
 		lrh0 |= 0xF000;	/* Set VL (see ch. 13.5.3.1) */
 	qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
 	qp->s_hdr.lrh[1] = cpu_to_be16(ah_attr->dlid);	/* DEST LID */
-	qp->s_hdr.lrh[2] = cpu_to_be16(hwords + nwords + SIZE_OF_CRC);
+	qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords +
+					   SIZE_OF_CRC);
 	lid = dev->dd->ipath_lid;
 	if (lid) {
 		lid |= ah_attr->src_path_bits &
-			((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+			((1 << dev->dd->ipath_lmc) - 1);
 		qp->s_hdr.lrh[3] = cpu_to_be16(lid);
 	} else
 		qp->s_hdr.lrh[3] = IB_LID_PERMISSIVE;
-	if (wr->send_flags & IB_SEND_SOLICITED)
+	if (wqe->wr.send_flags & IB_SEND_SOLICITED)
 		bth0 |= 1 << 23;
 	bth0 |= extra_bytes << 20;
 	bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? IPATH_DEFAULT_P_KEY :
@@ -460,38 +357,20 @@
 	ohdr->bth[1] = ah_attr->dlid >= IPATH_MULTICAST_LID_BASE &&
 		ah_attr->dlid != IPATH_PERMISSIVE_LID ?
 		__constant_cpu_to_be32(IPATH_MULTICAST_QPN) :
-		cpu_to_be32(wr->wr.ud.remote_qpn);
-	/* XXX Could lose a PSN count but not worth locking */
+		cpu_to_be32(wqe->wr.wr.ud.remote_qpn);
 	ohdr->bth[2] = cpu_to_be32(qp->s_next_psn++ & IPATH_PSN_MASK);
 	/*
 	 * Qkeys with the high order bit set mean use the
 	 * qkey from the QP context instead of the WR (see 10.2.5).
 	 */
-	ohdr->u.ud.deth[0] = cpu_to_be32((int)wr->wr.ud.remote_qkey < 0 ?
-					 qp->qkey : wr->wr.ud.remote_qkey);
+	ohdr->u.ud.deth[0] = cpu_to_be32((int)wqe->wr.wr.ud.remote_qkey < 0 ?
+					 qp->qkey : wqe->wr.wr.ud.remote_qkey);
 	ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num);
-	if (ipath_verbs_send(dev->dd, hwords, (u32 *) &qp->s_hdr,
-			     len, &ss))
-		dev->n_no_piobuf++;
 
 done:
-	/* Queue the completion status entry. */
-	if (!(qp->s_flags & IPATH_S_SIGNAL_REQ_WR) ||
-	    (wr->send_flags & IB_SEND_SIGNALED)) {
-		wc.wr_id = wr->wr_id;
-		wc.status = IB_WC_SUCCESS;
-		wc.vendor_err = 0;
-		wc.opcode = IB_WC_SEND;
-		wc.byte_len = len;
-		wc.qp = &qp->ibqp;
-		wc.src_qp = 0;
-		wc.wc_flags = 0;
-		/* XXX initialize other fields? */
-		ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0);
-	}
-	kfree(sg_list);
-
-	ret = 0;
+	if (++qp->s_cur >= qp->s_size)
+		qp->s_cur = 0;
+	ret = 1;
 
 bail:
 	return ret;
@@ -672,7 +551,8 @@
 	 * Save the LMC lower bits if the destination LID is a unicast LID.
 	 */
 	wc.dlid_path_bits = dlid >= IPATH_MULTICAST_LID_BASE ? 0 :
-		dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+		dlid & ((1 << dev->dd->ipath_lmc) - 1);
+	wc.port_num = 1;
 	/* Signal completion event if the solicited bit is set. */
 	ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
 		       (ohdr->bth[0] &
diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/infiniband/hw/ipath/ipath_user_pages.c
index 27034d3..0190edc 100644
--- a/drivers/infiniband/hw/ipath/ipath_user_pages.c
+++ b/drivers/infiniband/hw/ipath/ipath_user_pages.c
@@ -171,32 +171,6 @@
 	return ret;
 }
 
-/**
- * ipath_get_user_pages_nocopy - lock a single page for I/O and mark shared
- * @start_page: the page to lock
- * @p: the output page structure
- *
- * This is similar to ipath_get_user_pages, but it's always one page, and we
- * mark the page as locked for I/O, and shared.  This is used for the user
- * process page that contains the destination address for the rcvhdrq tail
- * update, so we need to have the vma. If we don't do this, the page can be
- * taken away from us on fork, even if the child never touches it, and then
- * the user process never sees the tail register updates.
- */
-int ipath_get_user_pages_nocopy(unsigned long page, struct page **p)
-{
-	struct vm_area_struct *vma;
-	int ret;
-
-	down_write(&current->mm->mmap_sem);
-
-	ret = __get_user_pages(page, 1, p, &vma);
-
-	up_write(&current->mm->mmap_sem);
-
-	return ret;
-}
-
 void ipath_release_user_pages(struct page **p, size_t num_pages)
 {
 	down_write(&current->mm->mmap_sem);
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index 65f7181..74f77e7 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -230,6 +230,121 @@
 	}
 }
 
+static void ipath_flush_wqe(struct ipath_qp *qp, struct ib_send_wr *wr)
+{
+	struct ib_wc wc;
+
+	memset(&wc, 0, sizeof(wc));
+	wc.wr_id = wr->wr_id;
+	wc.status = IB_WC_WR_FLUSH_ERR;
+	wc.opcode = ib_ipath_wc_opcode[wr->opcode];
+	wc.qp = &qp->ibqp;
+	ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 1);
+}
+
+/**
+ * ipath_post_one_send - post one RC, UC, or UD send work request
+ * @qp: the QP to post on
+ * @wr: the work request to send
+ */
+static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr)
+{
+	struct ipath_swqe *wqe;
+	u32 next;
+	int i;
+	int j;
+	int acc;
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&qp->s_lock, flags);
+
+	/* Check that state is OK to post send. */
+	if (unlikely(!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK))) {
+		if (qp->state != IB_QPS_SQE && qp->state != IB_QPS_ERR)
+			goto bail_inval;
+		/* C10-96 says generate a flushed completion entry. */
+		ipath_flush_wqe(qp, wr);
+		ret = 0;
+		goto bail;
+	}
+
+	/* IB spec says that num_sge == 0 is OK. */
+	if (wr->num_sge > qp->s_max_sge)
+		goto bail_inval;
+
+	/*
+	 * Don't allow RDMA reads or atomic operations on UC or
+	 * undefined operations.
+	 * Make sure buffer is large enough to hold the result for atomics.
+	 */
+	if (qp->ibqp.qp_type == IB_QPT_UC) {
+		if ((unsigned) wr->opcode >= IB_WR_RDMA_READ)
+			goto bail_inval;
+	} else if (qp->ibqp.qp_type == IB_QPT_UD) {
+		/* Check UD opcode */
+		if (wr->opcode != IB_WR_SEND &&
+		    wr->opcode != IB_WR_SEND_WITH_IMM)
+			goto bail_inval;
+		/* Check UD destination address PD */
+		if (qp->ibqp.pd != wr->wr.ud.ah->pd)
+			goto bail_inval;
+	} else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD)
+		goto bail_inval;
+	else if (wr->opcode >= IB_WR_ATOMIC_CMP_AND_SWP &&
+		   (wr->num_sge == 0 ||
+		    wr->sg_list[0].length < sizeof(u64) ||
+		    wr->sg_list[0].addr & (sizeof(u64) - 1)))
+		goto bail_inval;
+	else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic)
+		goto bail_inval;
+
+	next = qp->s_head + 1;
+	if (next >= qp->s_size)
+		next = 0;
+	if (next == qp->s_last)
+		goto bail_inval;
+
+	wqe = get_swqe_ptr(qp, qp->s_head);
+	wqe->wr = *wr;
+	wqe->ssn = qp->s_ssn++;
+	wqe->length = 0;
+	if (wr->num_sge) {
+		acc = wr->opcode >= IB_WR_RDMA_READ ?
+			IB_ACCESS_LOCAL_WRITE : 0;
+		for (i = 0, j = 0; i < wr->num_sge; i++) {
+			u32 length = wr->sg_list[i].length;
+			int ok;
+
+			if (length == 0)
+				continue;
+			ok = ipath_lkey_ok(qp, &wqe->sg_list[j],
+					   &wr->sg_list[i], acc);
+			if (!ok)
+				goto bail_inval;
+			wqe->length += length;
+			j++;
+		}
+		wqe->wr.num_sge = j;
+	}
+	if (qp->ibqp.qp_type == IB_QPT_UC ||
+	    qp->ibqp.qp_type == IB_QPT_RC) {
+		if (wqe->length > 0x80000000U)
+			goto bail_inval;
+	} else if (wqe->length > to_idev(qp->ibqp.device)->dd->ipath_ibmtu)
+		goto bail_inval;
+	qp->s_head = next;
+
+	ret = 0;
+	goto bail;
+
+bail_inval:
+	ret = -EINVAL;
+bail:
+	spin_unlock_irqrestore(&qp->s_lock, flags);
+	return ret;
+}
+
 /**
  * ipath_post_send - post a send on a QP
  * @ibqp: the QP to post the send on
@@ -244,35 +359,17 @@
 	struct ipath_qp *qp = to_iqp(ibqp);
 	int err = 0;
 
-	/* Check that state is OK to post send. */
-	if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK)) {
-		*bad_wr = wr;
-		err = -EINVAL;
-		goto bail;
-	}
-
 	for (; wr; wr = wr->next) {
-		switch (qp->ibqp.qp_type) {
-		case IB_QPT_UC:
-		case IB_QPT_RC:
-			err = ipath_post_ruc_send(qp, wr);
-			break;
-
-		case IB_QPT_SMI:
-		case IB_QPT_GSI:
-		case IB_QPT_UD:
-			err = ipath_post_ud_send(qp, wr);
-			break;
-
-		default:
-			err = -EINVAL;
-		}
+		err = ipath_post_one_send(qp, wr);
 		if (err) {
 			*bad_wr = wr;
-			break;
+			goto bail;
 		}
 	}
 
+	/* Try to do the send work in the caller's context. */
+	ipath_do_send((unsigned long) qp);
+
 bail:
 	return err;
 }
@@ -416,7 +513,7 @@
 	/* Check for a valid destination LID (see ch. 7.11.1). */
 	lid = be16_to_cpu(hdr->lrh[1]);
 	if (lid < IPATH_MULTICAST_LID_BASE) {
-		lid &= ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
+		lid &= ~((1 << dev->dd->ipath_lmc) - 1);
 		if (unlikely(lid != dev->dd->ipath_lid)) {
 			dev->rcv_errors++;
 			goto bail;
@@ -488,7 +585,7 @@
  * This is called from ipath_do_rcv_timer() at interrupt level to check for
  * QPs which need retransmits and to collect performance numbers.
  */
-void ipath_ib_timer(struct ipath_ibdev *dev)
+static void ipath_ib_timer(struct ipath_ibdev *dev)
 {
 	struct ipath_qp *resend = NULL;
 	struct list_head *last;
@@ -631,7 +728,7 @@
 #endif
 
 static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss,
-		    u32 length)
+		    u32 length, unsigned flush_wc)
 {
 	u32 extra = 0;
 	u32 data = 0;
@@ -641,11 +738,11 @@
 		u32 len = ss->sge.length;
 		u32 off;
 
-		BUG_ON(len == 0);
 		if (len > length)
 			len = length;
 		if (len > ss->sge.sge_length)
 			len = ss->sge.sge_length;
+		BUG_ON(len == 0);
 		/* If the source address is not aligned, try to align it. */
 		off = (unsigned long)ss->sge.vaddr & (sizeof(u32) - 1);
 		if (off) {
@@ -757,36 +854,25 @@
 	}
 	/* Update address before sending packet. */
 	update_sge(ss, length);
-	/* must flush early everything before trigger word */
-	ipath_flush_wc();
-	__raw_writel(last, piobuf);
-	/* be sure trigger word is written */
-	ipath_flush_wc();
+	if (flush_wc) {
+		/* must flush early everything before trigger word */
+		ipath_flush_wc();
+		__raw_writel(last, piobuf);
+		/* be sure trigger word is written */
+		ipath_flush_wc();
+	} else
+		__raw_writel(last, piobuf);
 }
 
-/**
- * ipath_verbs_send - send a packet
- * @dd: the infinipath device
- * @hdrwords: the number of words in the header
- * @hdr: the packet header
- * @len: the length of the packet in bytes
- * @ss: the SGE to send
- */
-int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
-		     u32 *hdr, u32 len, struct ipath_sge_state *ss)
+static int ipath_verbs_send_pio(struct ipath_qp *qp, u32 *hdr, u32 hdrwords,
+				struct ipath_sge_state *ss, u32 len,
+				u32 plen, u32 dwords)
 {
+	struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd;
 	u32 __iomem *piobuf;
-	u32 plen;
+	unsigned flush_wc;
 	int ret;
 
-	/* +1 is for the qword padding of pbc */
-	plen = hdrwords + ((len + 3) >> 2) + 1;
-	if (unlikely((plen << 2) > dd->ipath_ibmaxlen)) {
-		ret = -EINVAL;
-		goto bail;
-	}
-
-	/* Get a PIO buffer to use. */
 	piobuf = ipath_getpiobuf(dd, NULL);
 	if (unlikely(piobuf == NULL)) {
 		ret = -EBUSY;
@@ -799,51 +885,90 @@
 	 * or WC buffer can be written out of order.
 	 */
 	writeq(plen, piobuf);
-	ipath_flush_wc();
 	piobuf += 2;
+
+	flush_wc = dd->ipath_flags & IPATH_PIO_FLUSH_WC;
 	if (len == 0) {
 		/*
 		 * If there is just the header portion, must flush before
 		 * writing last word of header for correctness, and after
 		 * the last header word (trigger word).
 		 */
-		__iowrite32_copy(piobuf, hdr, hdrwords - 1);
-		ipath_flush_wc();
-		__raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1);
-		ipath_flush_wc();
-		ret = 0;
-		goto bail;
+		if (flush_wc) {
+			ipath_flush_wc();
+			__iowrite32_copy(piobuf, hdr, hdrwords - 1);
+			ipath_flush_wc();
+			__raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1);
+			ipath_flush_wc();
+		} else
+			__iowrite32_copy(piobuf, hdr, hdrwords);
+		goto done;
 	}
 
+	if (flush_wc)
+		ipath_flush_wc();
 	__iowrite32_copy(piobuf, hdr, hdrwords);
 	piobuf += hdrwords;
 
 	/* The common case is aligned and contained in one segment. */
 	if (likely(ss->num_sge == 1 && len <= ss->sge.length &&
 		   !((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) {
-		u32 w;
 		u32 *addr = (u32 *) ss->sge.vaddr;
 
 		/* Update address before sending packet. */
 		update_sge(ss, len);
-		/* Need to round up for the last dword in the packet. */
-		w = (len + 3) >> 2;
-		__iowrite32_copy(piobuf, addr, w - 1);
-		/* must flush early everything before trigger word */
-		ipath_flush_wc();
-		__raw_writel(addr[w - 1], piobuf + w - 1);
-		/* be sure trigger word is written */
-		ipath_flush_wc();
-		ret = 0;
-		goto bail;
+		if (flush_wc) {
+			__iowrite32_copy(piobuf, addr, dwords - 1);
+			/* must flush early everything before trigger word */
+			ipath_flush_wc();
+			__raw_writel(addr[dwords - 1], piobuf + dwords - 1);
+			/* be sure trigger word is written */
+			ipath_flush_wc();
+		} else
+			__iowrite32_copy(piobuf, addr, dwords);
+		goto done;
 	}
-	copy_io(piobuf, ss, len);
+	copy_io(piobuf, ss, len, flush_wc);
+done:
+	if (qp->s_wqe)
+		ipath_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS);
 	ret = 0;
-
 bail:
 	return ret;
 }
 
+/**
+ * ipath_verbs_send - send a packet
+ * @qp: the QP to send on
+ * @hdr: the packet header
+ * @hdrwords: the number of words in the header
+ * @ss: the SGE to send
+ * @len: the length of the packet in bytes
+ */
+int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr,
+		     u32 hdrwords, struct ipath_sge_state *ss, u32 len)
+{
+	struct ipath_devdata *dd = to_idev(qp->ibqp.device)->dd;
+	u32 plen;
+	int ret;
+	u32 dwords = (len + 3) >> 2;
+
+	/* +1 is for the qword padding of pbc */
+	plen = hdrwords + dwords + 1;
+
+	/* Drop non-VL15 packets if we are not in the active state */
+	if (!(dd->ipath_flags & IPATH_LINKACTIVE) &&
+	    qp->ibqp.qp_type != IB_QPT_SMI) {
+		if (qp->s_wqe)
+			ipath_send_complete(qp, qp->s_wqe, IB_WC_SUCCESS);
+		ret = 0;
+	} else
+		ret = ipath_verbs_send_pio(qp, (u32 *) hdr, hdrwords,
+					   ss, len, plen, dwords);
+
+	return ret;
+}
+
 int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords,
 			    u64 *rwords, u64 *spkts, u64 *rpkts,
 			    u64 *xmit_wait)
@@ -852,7 +977,6 @@
 
 	if (!(dd->ipath_flags & IPATH_INITTED)) {
 		/* no hardware, freeze, etc. */
-		ipath_dbg("unit %u not usable\n", dd->ipath_unit);
 		ret = -EINVAL;
 		goto bail;
 	}
@@ -878,48 +1002,44 @@
 int ipath_get_counters(struct ipath_devdata *dd,
 		       struct ipath_verbs_counters *cntrs)
 {
+	struct ipath_cregs const *crp = dd->ipath_cregs;
 	int ret;
 
 	if (!(dd->ipath_flags & IPATH_INITTED)) {
 		/* no hardware, freeze, etc. */
-		ipath_dbg("unit %u not usable\n", dd->ipath_unit);
 		ret = -EINVAL;
 		goto bail;
 	}
 	cntrs->symbol_error_counter =
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_ibsymbolerrcnt);
+		ipath_snap_cntr(dd, crp->cr_ibsymbolerrcnt);
 	cntrs->link_error_recovery_counter =
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt);
+		ipath_snap_cntr(dd, crp->cr_iblinkerrrecovcnt);
 	/*
 	 * The link downed counter counts when the other side downs the
 	 * connection.  We add in the number of times we downed the link
 	 * due to local link integrity errors to compensate.
 	 */
 	cntrs->link_downed_counter =
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkdowncnt);
+		ipath_snap_cntr(dd, crp->cr_iblinkdowncnt);
 	cntrs->port_rcv_errors =
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_rxdroppktcnt) +
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvovflcnt) +
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_portovflcnt) +
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_err_rlencnt) +
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_invalidrlencnt) +
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_erricrccnt) +
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_errvcrccnt) +
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlpcrccnt) +
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_badformatcnt) +
+		ipath_snap_cntr(dd, crp->cr_rxdroppktcnt) +
+		ipath_snap_cntr(dd, crp->cr_rcvovflcnt) +
+		ipath_snap_cntr(dd, crp->cr_portovflcnt) +
+		ipath_snap_cntr(dd, crp->cr_err_rlencnt) +
+		ipath_snap_cntr(dd, crp->cr_invalidrlencnt) +
+		ipath_snap_cntr(dd, crp->cr_errlinkcnt) +
+		ipath_snap_cntr(dd, crp->cr_erricrccnt) +
+		ipath_snap_cntr(dd, crp->cr_errvcrccnt) +
+		ipath_snap_cntr(dd, crp->cr_errlpcrccnt) +
+		ipath_snap_cntr(dd, crp->cr_badformatcnt) +
 		dd->ipath_rxfc_unsupvl_errs;
 	cntrs->port_rcv_remphys_errors =
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvebpcnt);
-	cntrs->port_xmit_discards =
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_unsupvlcnt);
-	cntrs->port_xmit_data =
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
-	cntrs->port_rcv_data =
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
-	cntrs->port_xmit_packets =
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt);
-	cntrs->port_rcv_packets =
-		ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt);
+		ipath_snap_cntr(dd, crp->cr_rcvebpcnt);
+	cntrs->port_xmit_discards = ipath_snap_cntr(dd, crp->cr_unsupvlcnt);
+	cntrs->port_xmit_data = ipath_snap_cntr(dd, crp->cr_wordsendcnt);
+	cntrs->port_rcv_data = ipath_snap_cntr(dd, crp->cr_wordrcvcnt);
+	cntrs->port_xmit_packets = ipath_snap_cntr(dd, crp->cr_pktsendcnt);
+	cntrs->port_rcv_packets = ipath_snap_cntr(dd, crp->cr_pktrcvcnt);
 	cntrs->local_link_integrity_errors =
 		(dd->ipath_flags & IPATH_GPIO_ERRINTRS) ?
 		dd->ipath_lli_errs : dd->ipath_lli_errors;
@@ -1033,25 +1153,26 @@
 			    u8 port, struct ib_port_attr *props)
 {
 	struct ipath_ibdev *dev = to_idev(ibdev);
+	struct ipath_devdata *dd = dev->dd;
 	enum ib_mtu mtu;
-	u16 lid = dev->dd->ipath_lid;
+	u16 lid = dd->ipath_lid;
 	u64 ibcstat;
 
 	memset(props, 0, sizeof(*props));
 	props->lid = lid ? lid : __constant_be16_to_cpu(IB_LID_PERMISSIVE);
-	props->lmc = dev->mkeyprot_resv_lmc & 7;
+	props->lmc = dd->ipath_lmc;
 	props->sm_lid = dev->sm_lid;
 	props->sm_sl = dev->sm_sl;
-	ibcstat = dev->dd->ipath_lastibcstat;
+	ibcstat = dd->ipath_lastibcstat;
 	props->state = ((ibcstat >> 4) & 0x3) + 1;
 	/* See phys_state_show() */
 	props->phys_state = ipath_cvt_physportstate[
-		dev->dd->ipath_lastibcstat & 0xf];
+		dd->ipath_lastibcstat & 0xf];
 	props->port_cap_flags = dev->port_cap_flags;
 	props->gid_tbl_len = 1;
 	props->max_msg_sz = 0x80000000;
-	props->pkey_tbl_len = ipath_get_npkeys(dev->dd);
-	props->bad_pkey_cntr = ipath_get_cr_errpkey(dev->dd) -
+	props->pkey_tbl_len = ipath_get_npkeys(dd);
+	props->bad_pkey_cntr = ipath_get_cr_errpkey(dd) -
 		dev->z_pkey_violations;
 	props->qkey_viol_cntr = dev->qkey_violations;
 	props->active_width = IB_WIDTH_4X;
@@ -1061,12 +1182,12 @@
 	props->init_type_reply = 0;
 
 	/*
-	 * Note: the chips support a maximum MTU of 4096, but the driver
+	 * Note: the chip supports a maximum MTU of 4096, but the driver
 	 * hasn't implemented this feature yet, so set the maximum value
 	 * to 2048.
 	 */
 	props->max_mtu = IB_MTU_2048;
-	switch (dev->dd->ipath_ibmtu) {
+	switch (dd->ipath_ibmtu) {
 	case 4096:
 		mtu = IB_MTU_4096;
 		break;
@@ -1415,9 +1536,7 @@
 {
 	/* Disable GPIO bit 2 interrupt */
 	if (dd->ipath_flags & IPATH_GPIO_INTR) {
-                u64 val;
                 /* Disable GPIO bit 2 interrupt */
-                val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask);
 		dd->ipath_gpio_mask &= ~((u64) (1 << IPATH_GPIO_PORT0_BIT));
 		ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask,
 				 dd->ipath_gpio_mask);
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
index f3d1f2c..6ccb54f 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.h
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
@@ -42,7 +42,7 @@
 #include <rdma/ib_pack.h>
 #include <rdma/ib_user_verbs.h>
 
-#include "ipath_layer.h"
+#include "ipath_kernel.h"
 
 #define IPATH_MAX_RDMA_ATOMIC	4
 
@@ -61,6 +61,7 @@
  */
 #define IB_CQ_NONE	(IB_CQ_NEXT_COMP + 1)
 
+/* AETH NAK opcode values */
 #define IB_RNR_NAK			0x20
 #define IB_NAK_PSN_ERROR		0x60
 #define IB_NAK_INVALID_REQUEST		0x61
@@ -68,6 +69,7 @@
 #define IB_NAK_REMOTE_OPERATIONAL_ERROR 0x63
 #define IB_NAK_INVALID_RD_REQUEST	0x64
 
+/* Flags for checking QP state (see ib_ipath_state_ops[]) */
 #define IPATH_POST_SEND_OK		0x01
 #define IPATH_POST_RECV_OK		0x02
 #define IPATH_PROCESS_RECV_OK		0x04
@@ -189,7 +191,11 @@
 struct ipath_cq_wc {
 	u32 head;		/* index of next entry to fill */
 	u32 tail;		/* index of next ib_poll_cq() entry */
-	struct ib_uverbs_wc queue[1]; /* this is actually size ibcq.cqe + 1 */
+	union {
+		/* these are actually size ibcq.cqe + 1 */
+		struct ib_uverbs_wc uqueue[0];
+		struct ib_wc kqueue[0];
+	};
 };
 
 /*
@@ -241,7 +247,7 @@
  */
 struct ipath_sge {
 	struct ipath_mregion *mr;
-	void *vaddr;		/* current pointer into the segment */
+	void *vaddr;		/* kernel virtual address of segment */
 	u32 sge_length;		/* length of the SGE */
 	u32 length;		/* remaining length of the segment */
 	u16 m;			/* current index: mr->map[m] */
@@ -409,6 +415,7 @@
 	u32 s_ssn;		/* SSN of tail entry */
 	u32 s_lsn;		/* limit sequence number (credit) */
 	struct ipath_swqe *s_wq;	/* send work queue */
+	struct ipath_swqe *s_wqe;
 	struct ipath_rq r_rq;		/* receive work queue */
 	struct ipath_sge r_sg_list[0];	/* verified SGEs */
 };
@@ -494,7 +501,7 @@
 	int ib_unit;		/* This is the device number */
 	u16 sm_lid;		/* in host order */
 	u8 sm_sl;
-	u8 mkeyprot_resv_lmc;
+	u8 mkeyprot;
 	/* non-zero when timer is set */
 	unsigned long mkey_lease_timeout;
 
@@ -669,7 +676,7 @@
 
 int ipath_destroy_qp(struct ib_qp *ibqp);
 
-void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err);
+int ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err);
 
 int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
 		    int attr_mask, struct ib_udata *udata);
@@ -685,8 +692,8 @@
 
 void ipath_get_credit(struct ipath_qp *qp, u32 aeth);
 
-int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
-		     u32 *hdr, u32 len, struct ipath_sge_state *ss);
+int ipath_verbs_send(struct ipath_qp *qp, struct ipath_ib_header *hdr,
+		     u32 hdrwords, struct ipath_sge_state *ss, u32 len);
 
 void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig);
 
@@ -694,8 +701,6 @@
 
 void ipath_skip_sge(struct ipath_sge_state *ss, u32 length);
 
-int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr);
-
 void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
 		  int has_grh, void *data, u32 tlen, struct ipath_qp *qp);
 
@@ -735,6 +740,8 @@
 
 int ipath_destroy_srq(struct ib_srq *ibsrq);
 
+void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig);
+
 int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
 
 struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries, int comp_vector,
@@ -782,22 +789,30 @@
 
 int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
 
-void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev);
-
 void ipath_insert_rnr_queue(struct ipath_qp *qp);
 
+int ipath_init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
+		   u32 *lengthp, struct ipath_sge_state *ss);
+
 int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only);
 
 u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr,
 		   struct ib_global_route *grh, u32 hwords, u32 nwords);
 
-void ipath_do_ruc_send(unsigned long data);
+void ipath_make_ruc_header(struct ipath_ibdev *dev, struct ipath_qp *qp,
+			   struct ipath_other_headers *ohdr,
+			   u32 bth0, u32 bth2);
 
-int ipath_make_rc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr,
-		      u32 pmtu, u32 *bth0p, u32 *bth2p);
+void ipath_do_send(unsigned long data);
 
-int ipath_make_uc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr,
-		      u32 pmtu, u32 *bth0p, u32 *bth2p);
+void ipath_send_complete(struct ipath_qp *qp, struct ipath_swqe *wqe,
+			 enum ib_wc_status status);
+
+int ipath_make_rc_req(struct ipath_qp *qp);
+
+int ipath_make_uc_req(struct ipath_qp *qp);
+
+int ipath_make_ud_req(struct ipath_qp *qp);
 
 int ipath_register_ib_device(struct ipath_devdata *);
 
@@ -807,8 +822,6 @@
 
 int ipath_ib_piobufavail(struct ipath_ibdev *);
 
-void ipath_ib_timer(struct ipath_ibdev *);
-
 unsigned ipath_get_npkeys(struct ipath_devdata *);
 
 u32 ipath_get_cr_errpkey(struct ipath_devdata *);
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index 660b27a..8bf44da 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -389,7 +389,7 @@
 			wc->opcode    = IB_WC_SEND;
 			break;
 		case MLX4_OPCODE_RDMA_READ:
-			wc->opcode    = IB_WC_SEND;
+			wc->opcode    = IB_WC_RDMA_READ;
 			wc->byte_len  = be32_to_cpu(cqe->byte_cnt);
 			break;
 		case MLX4_OPCODE_ATOMIC_CS:
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
index 3330917..0ed02b7 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -109,7 +109,7 @@
 			   in_modifier, op_modifier,
 			   MLX4_CMD_MAD_IFC, MLX4_CMD_TIME_CLASS_C);
 
-	if (!err);
+	if (!err)
 		memcpy(response_mad, outmailbox->buf, 256);
 
 	mlx4_free_cmd_mailbox(dev->dev, inmailbox);
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index dde8fe9..d8287d9 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -476,9 +476,48 @@
 	return err;
 }
 
+static ssize_t show_hca(struct class_device *cdev, char *buf)
+{
+	struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev);
+	return sprintf(buf, "MT%d\n", dev->dev->pdev->device);
+}
+
+static ssize_t show_fw_ver(struct class_device *cdev, char *buf)
+{
+	struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev);
+	return sprintf(buf, "%d.%d.%d\n", (int) (dev->dev->caps.fw_ver >> 32),
+		       (int) (dev->dev->caps.fw_ver >> 16) & 0xffff,
+		       (int) dev->dev->caps.fw_ver & 0xffff);
+}
+
+static ssize_t show_rev(struct class_device *cdev, char *buf)
+{
+	struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev);
+	return sprintf(buf, "%x\n", dev->dev->rev_id);
+}
+
+static ssize_t show_board(struct class_device *cdev, char *buf)
+{
+	struct mlx4_ib_dev *dev = container_of(cdev, struct mlx4_ib_dev, ib_dev.class_dev);
+	return sprintf(buf, "%.*s\n", MLX4_BOARD_ID_LEN, dev->dev->board_id);
+}
+
+static CLASS_DEVICE_ATTR(hw_rev,   S_IRUGO, show_rev,    NULL);
+static CLASS_DEVICE_ATTR(fw_ver,   S_IRUGO, show_fw_ver, NULL);
+static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca,    NULL);
+static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_board,  NULL);
+
+static struct class_device_attribute *mlx4_class_attributes[] = {
+	&class_device_attr_hw_rev,
+	&class_device_attr_fw_ver,
+	&class_device_attr_hca_type,
+	&class_device_attr_board_id
+};
+
 static void *mlx4_ib_add(struct mlx4_dev *dev)
 {
 	struct mlx4_ib_dev *ibdev;
+	int i;
 
 	ibdev = (struct mlx4_ib_dev *) ib_alloc_device(sizeof *ibdev);
 	if (!ibdev) {
@@ -568,6 +607,11 @@
 	ibdev->ib_dev.detach_mcast	= mlx4_ib_mcg_detach;
 	ibdev->ib_dev.process_mad	= mlx4_ib_process_mad;
 
+	ibdev->ib_dev.alloc_fmr		= mlx4_ib_fmr_alloc;
+	ibdev->ib_dev.map_phys_fmr	= mlx4_ib_map_phys_fmr;
+	ibdev->ib_dev.unmap_fmr		= mlx4_ib_unmap_fmr;
+	ibdev->ib_dev.dealloc_fmr	= mlx4_ib_fmr_dealloc;
+
 	if (init_node_data(ibdev))
 		goto err_map;
 
@@ -580,6 +624,12 @@
 	if (mlx4_ib_mad_init(ibdev))
 		goto err_reg;
 
+	for (i = 0; i < ARRAY_SIZE(mlx4_class_attributes); ++i) {
+		if (class_device_create_file(&ibdev->ib_dev.class_dev,
+					       mlx4_class_attributes[i]))
+			goto err_reg;
+	}
+
 	return ibdev;
 
 err_reg:
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
index 705ff2f..2869765 100644
--- a/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -93,6 +93,11 @@
 	struct ib_umem	       *umem;
 };
 
+struct mlx4_ib_fmr {
+	struct ib_fmr           ibfmr;
+	struct mlx4_fmr         mfmr;
+};
+
 struct mlx4_ib_wq {
 	u64		       *wrid;
 	spinlock_t		lock;
@@ -199,6 +204,10 @@
 	return container_of(ibmr, struct mlx4_ib_mr, ibmr);
 }
 
+static inline struct mlx4_ib_fmr *to_mfmr(struct ib_fmr *ibfmr)
+{
+	return container_of(ibfmr, struct mlx4_ib_fmr, ibfmr);
+}
 static inline struct mlx4_ib_qp *to_mqp(struct ib_qp *ibqp)
 {
 	return container_of(ibqp, struct mlx4_ib_qp, ibqp);
@@ -284,6 +293,13 @@
 int mlx4_ib_mad_init(struct mlx4_ib_dev *dev);
 void mlx4_ib_mad_cleanup(struct mlx4_ib_dev *dev);
 
+struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int mr_access_flags,
+				  struct ib_fmr_attr *fmr_attr);
+int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, int npages,
+			 u64 iova);
+int mlx4_ib_unmap_fmr(struct list_head *fmr_list);
+int mlx4_ib_fmr_dealloc(struct ib_fmr *fmr);
+
 static inline int mlx4_ib_ah_grh_present(struct mlx4_ib_ah *ah)
 {
 	return !!(ah->av.g_slid & 0x80);
diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c
index 85ae906..7dc91a3 100644
--- a/drivers/infiniband/hw/mlx4/mr.c
+++ b/drivers/infiniband/hw/mlx4/mr.c
@@ -96,11 +96,10 @@
 				pages[i++] = sg_dma_address(&chunk->page_list[j]) +
 					umem->page_size * k;
 				/*
-				 * Be friendly to WRITE_MTT firmware
-				 * command, and pass it chunks of
-				 * appropriate size.
+				 * Be friendly to mlx4_write_mtt() and
+				 * pass it chunks of appropriate size.
 				 */
-				if (i == PAGE_SIZE / sizeof (u64) - 2) {
+				if (i == PAGE_SIZE / sizeof (u64)) {
 					err = mlx4_write_mtt(dev->dev, mtt, n,
 							     i, pages);
 					if (err)
@@ -182,3 +181,96 @@
 
 	return 0;
 }
+
+struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int acc,
+				 struct ib_fmr_attr *fmr_attr)
+{
+	struct mlx4_ib_dev *dev = to_mdev(pd->device);
+	struct mlx4_ib_fmr *fmr;
+	int err = -ENOMEM;
+
+	fmr = kmalloc(sizeof *fmr, GFP_KERNEL);
+	if (!fmr)
+		return ERR_PTR(-ENOMEM);
+
+	err = mlx4_fmr_alloc(dev->dev, to_mpd(pd)->pdn, convert_access(acc),
+			     fmr_attr->max_pages, fmr_attr->max_maps,
+			     fmr_attr->page_shift, &fmr->mfmr);
+	if (err)
+		goto err_free;
+
+	err = mlx4_mr_enable(to_mdev(pd->device)->dev, &fmr->mfmr.mr);
+	if (err)
+		goto err_mr;
+
+	fmr->ibfmr.rkey = fmr->ibfmr.lkey = fmr->mfmr.mr.key;
+
+	return &fmr->ibfmr;
+
+err_mr:
+	mlx4_mr_free(to_mdev(pd->device)->dev, &fmr->mfmr.mr);
+
+err_free:
+	kfree(fmr);
+
+	return ERR_PTR(err);
+}
+
+int mlx4_ib_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,
+		      int npages, u64 iova)
+{
+	struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr);
+	struct mlx4_ib_dev *dev = to_mdev(ifmr->ibfmr.device);
+
+	return mlx4_map_phys_fmr(dev->dev, &ifmr->mfmr, page_list, npages, iova,
+				 &ifmr->ibfmr.lkey, &ifmr->ibfmr.rkey);
+}
+
+int mlx4_ib_unmap_fmr(struct list_head *fmr_list)
+{
+	struct ib_fmr *ibfmr;
+	int err;
+	struct mlx4_dev *mdev = NULL;
+
+	list_for_each_entry(ibfmr, fmr_list, list) {
+		if (mdev && to_mdev(ibfmr->device)->dev != mdev)
+			return -EINVAL;
+		mdev = to_mdev(ibfmr->device)->dev;
+	}
+
+	if (!mdev)
+		return 0;
+
+	list_for_each_entry(ibfmr, fmr_list, list) {
+		struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr);
+
+		mlx4_fmr_unmap(mdev, &ifmr->mfmr, &ifmr->ibfmr.lkey, &ifmr->ibfmr.rkey);
+	}
+
+	/*
+	 * Make sure all MPT status updates are visible before issuing
+	 * SYNC_TPT firmware command.
+	 */
+	wmb();
+
+	err = mlx4_SYNC_TPT(mdev);
+	if (err)
+		printk(KERN_WARNING "mlx4_ib: SYNC_TPT error %d when "
+		       "unmapping FMRs\n", err);
+
+	return 0;
+}
+
+int mlx4_ib_fmr_dealloc(struct ib_fmr *ibfmr)
+{
+	struct mlx4_ib_fmr *ifmr = to_mfmr(ibfmr);
+	struct mlx4_ib_dev *dev = to_mdev(ibfmr->device);
+	int err;
+
+	err = mlx4_fmr_free(dev->dev, &ifmr->mfmr);
+
+	if (!err)
+		kfree(ifmr);
+
+	return err;
+}
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 4004218..31a480e 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -415,9 +415,11 @@
 	return 0;
 
 err_wrid:
-	if (pd->uobject && !init_attr->srq)
-		mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), &qp->db);
-	else {
+	if (pd->uobject) {
+		if (!init_attr->srq)
+			mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context),
+					      &qp->db);
+	} else {
 		kfree(qp->sq.wrid);
 		kfree(qp->rq.wrid);
 	}
@@ -742,7 +744,7 @@
 		if (attr->path_mtu < IB_MTU_256 || attr->path_mtu > IB_MTU_4096) {
 			printk(KERN_ERR "path MTU (%u) is invalid\n",
 			       attr->path_mtu);
-			return -EINVAL;
+			goto out;
 		}
 		context->mtu_msgmax = (attr->path_mtu << 5) | 31;
 	}
@@ -781,10 +783,8 @@
 
 	if (attr_mask & IB_QP_AV) {
 		if (mlx4_set_path(dev, &attr->ah_attr, &context->pri_path,
-				  attr_mask & IB_QP_PORT ? attr->port_num : qp->port)) {
-			err = -EINVAL;
+				  attr_mask & IB_QP_PORT ? attr->port_num : qp->port))
 			goto out;
-		}
 
 		optpar |= (MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH |
 			   MLX4_QP_OPTPAR_SCHED_QUEUE);
@@ -798,15 +798,15 @@
 	if (attr_mask & IB_QP_ALT_PATH) {
 		if (attr->alt_port_num == 0 ||
 		    attr->alt_port_num > dev->dev->caps.num_ports)
-			return -EINVAL;
+			goto out;
 
 		if (attr->alt_pkey_index >=
 		    dev->dev->caps.pkey_table_len[attr->alt_port_num])
-			return -EINVAL;
+			goto out;
 
 		if (mlx4_set_path(dev, &attr->alt_ah_attr, &context->alt_path,
 				  attr->alt_port_num))
-			return -EINVAL;
+			goto out;
 
 		context->alt_path.pkey_index = attr->alt_pkey_index;
 		context->alt_path.ackto = attr->alt_timeout << 3;
@@ -1183,12 +1183,86 @@
 	return cur + nreq >= wq->max_post;
 }
 
+static __always_inline void set_raddr_seg(struct mlx4_wqe_raddr_seg *rseg,
+					  u64 remote_addr, u32 rkey)
+{
+	rseg->raddr    = cpu_to_be64(remote_addr);
+	rseg->rkey     = cpu_to_be32(rkey);
+	rseg->reserved = 0;
+}
+
+static void set_atomic_seg(struct mlx4_wqe_atomic_seg *aseg, struct ib_send_wr *wr)
+{
+	if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+		aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap);
+		aseg->compare  = cpu_to_be64(wr->wr.atomic.compare_add);
+	} else {
+		aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
+		aseg->compare  = 0;
+	}
+
+}
+
+static void set_datagram_seg(struct mlx4_wqe_datagram_seg *dseg,
+			     struct ib_send_wr *wr)
+{
+	memcpy(dseg->av, &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av));
+	dseg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
+	dseg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+}
+
+static void set_mlx_icrc_seg(void *dseg)
+{
+	u32 *t = dseg;
+	struct mlx4_wqe_inline_seg *iseg = dseg;
+
+	t[1] = 0;
+
+	/*
+	 * Need a barrier here before writing the byte_count field to
+	 * make sure that all the data is visible before the
+	 * byte_count field is set.  Otherwise, if the segment begins
+	 * a new cacheline, the HCA prefetcher could grab the 64-byte
+	 * chunk and get a valid (!= * 0xffffffff) byte count but
+	 * stale data, and end up sending the wrong data.
+	 */
+	wmb();
+
+	iseg->byte_count = cpu_to_be32((1 << 31) | 4);
+}
+
+static void set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg)
+{
+	dseg->lkey       = cpu_to_be32(sg->lkey);
+	dseg->addr       = cpu_to_be64(sg->addr);
+
+	/*
+	 * Need a barrier here before writing the byte_count field to
+	 * make sure that all the data is visible before the
+	 * byte_count field is set.  Otherwise, if the segment begins
+	 * a new cacheline, the HCA prefetcher could grab the 64-byte
+	 * chunk and get a valid (!= * 0xffffffff) byte count but
+	 * stale data, and end up sending the wrong data.
+	 */
+	wmb();
+
+	dseg->byte_count = cpu_to_be32(sg->length);
+}
+
+static void __set_data_seg(struct mlx4_wqe_data_seg *dseg, struct ib_sge *sg)
+{
+	dseg->byte_count = cpu_to_be32(sg->length);
+	dseg->lkey       = cpu_to_be32(sg->lkey);
+	dseg->addr       = cpu_to_be64(sg->addr);
+}
+
 int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 		      struct ib_send_wr **bad_wr)
 {
 	struct mlx4_ib_qp *qp = to_mqp(ibqp);
 	void *wqe;
 	struct mlx4_wqe_ctrl_seg *ctrl;
+	struct mlx4_wqe_data_seg *dseg;
 	unsigned long flags;
 	int nreq;
 	int err = 0;
@@ -1238,26 +1312,13 @@
 			switch (wr->opcode) {
 			case IB_WR_ATOMIC_CMP_AND_SWP:
 			case IB_WR_ATOMIC_FETCH_AND_ADD:
-				((struct mlx4_wqe_raddr_seg *) wqe)->raddr =
-					cpu_to_be64(wr->wr.atomic.remote_addr);
-				((struct mlx4_wqe_raddr_seg *) wqe)->rkey =
-					cpu_to_be32(wr->wr.atomic.rkey);
-				((struct mlx4_wqe_raddr_seg *) wqe)->reserved = 0;
-
+				set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
+					      wr->wr.atomic.rkey);
 				wqe  += sizeof (struct mlx4_wqe_raddr_seg);
 
-				if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
-					((struct mlx4_wqe_atomic_seg *) wqe)->swap_add =
-						cpu_to_be64(wr->wr.atomic.swap);
-					((struct mlx4_wqe_atomic_seg *) wqe)->compare =
-						cpu_to_be64(wr->wr.atomic.compare_add);
-				} else {
-					((struct mlx4_wqe_atomic_seg *) wqe)->swap_add =
-						cpu_to_be64(wr->wr.atomic.compare_add);
-					((struct mlx4_wqe_atomic_seg *) wqe)->compare = 0;
-				}
-
+				set_atomic_seg(wqe, wr);
 				wqe  += sizeof (struct mlx4_wqe_atomic_seg);
+
 				size += (sizeof (struct mlx4_wqe_raddr_seg) +
 					 sizeof (struct mlx4_wqe_atomic_seg)) / 16;
 
@@ -1266,15 +1327,10 @@
 			case IB_WR_RDMA_READ:
 			case IB_WR_RDMA_WRITE:
 			case IB_WR_RDMA_WRITE_WITH_IMM:
-				((struct mlx4_wqe_raddr_seg *) wqe)->raddr =
-					cpu_to_be64(wr->wr.rdma.remote_addr);
-				((struct mlx4_wqe_raddr_seg *) wqe)->rkey =
-					cpu_to_be32(wr->wr.rdma.rkey);
-				((struct mlx4_wqe_raddr_seg *) wqe)->reserved = 0;
-
+				set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+					      wr->wr.rdma.rkey);
 				wqe  += sizeof (struct mlx4_wqe_raddr_seg);
 				size += sizeof (struct mlx4_wqe_raddr_seg) / 16;
-
 				break;
 
 			default:
@@ -1284,13 +1340,7 @@
 			break;
 
 		case IB_QPT_UD:
-			memcpy(((struct mlx4_wqe_datagram_seg *) wqe)->av,
-			       &to_mah(wr->wr.ud.ah)->av, sizeof (struct mlx4_av));
-			((struct mlx4_wqe_datagram_seg *) wqe)->dqpn =
-				cpu_to_be32(wr->wr.ud.remote_qpn);
-			((struct mlx4_wqe_datagram_seg *) wqe)->qkey =
-				cpu_to_be32(wr->wr.ud.remote_qkey);
-
+			set_datagram_seg(wqe, wr);
 			wqe  += sizeof (struct mlx4_wqe_datagram_seg);
 			size += sizeof (struct mlx4_wqe_datagram_seg) / 16;
 			break;
@@ -1312,27 +1362,27 @@
 			break;
 		}
 
-		for (i = 0; i < wr->num_sge; ++i) {
-			((struct mlx4_wqe_data_seg *) wqe)->byte_count =
-				cpu_to_be32(wr->sg_list[i].length);
-			((struct mlx4_wqe_data_seg *) wqe)->lkey =
-				cpu_to_be32(wr->sg_list[i].lkey);
-			((struct mlx4_wqe_data_seg *) wqe)->addr =
-				cpu_to_be64(wr->sg_list[i].addr);
+		/*
+		 * Write data segments in reverse order, so as to
+		 * overwrite cacheline stamp last within each
+		 * cacheline.  This avoids issues with WQE
+		 * prefetching.
+		 */
 
-			wqe  += sizeof (struct mlx4_wqe_data_seg);
-			size += sizeof (struct mlx4_wqe_data_seg) / 16;
-		}
+		dseg = wqe;
+		dseg += wr->num_sge - 1;
+		size += wr->num_sge * (sizeof (struct mlx4_wqe_data_seg) / 16);
 
 		/* Add one more inline data segment for ICRC for MLX sends */
-		if (qp->ibqp.qp_type == IB_QPT_SMI || qp->ibqp.qp_type == IB_QPT_GSI) {
-			((struct mlx4_wqe_inline_seg *) wqe)->byte_count =
-				cpu_to_be32((1 << 31) | 4);
-			((u32 *) wqe)[1] = 0;
-			wqe  += sizeof (struct mlx4_wqe_data_seg);
+		if (unlikely(qp->ibqp.qp_type == IB_QPT_SMI ||
+			     qp->ibqp.qp_type == IB_QPT_GSI)) {
+			set_mlx_icrc_seg(dseg + 1);
 			size += sizeof (struct mlx4_wqe_data_seg) / 16;
 		}
 
+		for (i = wr->num_sge - 1; i >= 0; --i, --dseg)
+			set_data_seg(dseg, wr->sg_list + i);
+
 		ctrl->fence_size = (wr->send_flags & IB_SEND_FENCE ?
 				    MLX4_WQE_CTRL_FENCE : 0) | size;
 
@@ -1421,11 +1471,8 @@
 
 		scat = get_recv_wqe(qp, ind);
 
-		for (i = 0; i < wr->num_sge; ++i) {
-			scat[i].byte_count = cpu_to_be32(wr->sg_list[i].length);
-			scat[i].lkey       = cpu_to_be32(wr->sg_list[i].lkey);
-			scat[i].addr       = cpu_to_be64(wr->sg_list[i].addr);
-		}
+		for (i = 0; i < wr->num_sge; ++i)
+			__set_data_seg(scat + i, wr->sg_list + i);
 
 		if (i < qp->rq.max_gs) {
 			scat[i].byte_count = 0;
@@ -1498,7 +1545,7 @@
 static void to_ib_ah_attr(struct mlx4_dev *dev, struct ib_ah_attr *ib_ah_attr,
 				struct mlx4_qp_path *path)
 {
-	memset(ib_ah_attr, 0, sizeof *path);
+	memset(ib_ah_attr, 0, sizeof *ib_ah_attr);
 	ib_ah_attr->port_num	  = path->sched_queue & 0x40 ? 2 : 1;
 
 	if (ib_ah_attr->port_num == 0 || ib_ah_attr->port_num > dev->caps.num_ports)
@@ -1515,7 +1562,7 @@
 		ib_ah_attr->grh.traffic_class =
 			(be32_to_cpu(path->tclass_flowlabel) >> 20) & 0xff;
 		ib_ah_attr->grh.flow_label =
-			be32_to_cpu(path->tclass_flowlabel) & 0xffffff;
+			be32_to_cpu(path->tclass_flowlabel) & 0xfffff;
 		memcpy(ib_ah_attr->grh.dgid.raw,
 			path->rgid, sizeof ib_ah_attr->grh.dgid.raw);
 	}
@@ -1560,7 +1607,10 @@
 	}
 
 	qp_attr->pkey_index = context.pri_path.pkey_index & 0x7f;
-	qp_attr->port_num   = context.pri_path.sched_queue & 0x40 ? 2 : 1;
+	if (qp_attr->qp_state == IB_QPS_INIT)
+		qp_attr->port_num = qp->port;
+	else
+		qp_attr->port_num = context.pri_path.sched_queue & 0x40 ? 2 : 1;
 
 	/* qp_attr->en_sqd_async_notify is only applicable in modify qp */
 	qp_attr->sq_draining = mlx4_state == MLX4_QP_STATE_SQ_DRAINING;
@@ -1578,17 +1628,25 @@
 
 done:
 	qp_attr->cur_qp_state	     = qp_attr->qp_state;
+	qp_attr->cap.max_recv_wr     = qp->rq.wqe_cnt;
+	qp_attr->cap.max_recv_sge    = qp->rq.max_gs;
+
 	if (!ibqp->uobject) {
-		qp_attr->cap.max_send_wr     = qp->sq.wqe_cnt;
-		qp_attr->cap.max_recv_wr     = qp->rq.wqe_cnt;
-		qp_attr->cap.max_send_sge    = qp->sq.max_gs;
-		qp_attr->cap.max_recv_sge    = qp->rq.max_gs;
-		qp_attr->cap.max_inline_data = (1 << qp->sq.wqe_shift) -
-			send_wqe_overhead(qp->ibqp.qp_type) -
-			sizeof (struct mlx4_wqe_inline_seg);
-		qp_init_attr->cap	     = qp_attr->cap;
+		qp_attr->cap.max_send_wr  = qp->sq.wqe_cnt;
+		qp_attr->cap.max_send_sge = qp->sq.max_gs;
+	} else {
+		qp_attr->cap.max_send_wr  = 0;
+		qp_attr->cap.max_send_sge = 0;
 	}
 
+	/*
+	 * We don't support inline sends for kernel QPs (yet), and we
+	 * don't know what userspace's value should be.
+	 */
+	qp_attr->cap.max_inline_data = 0;
+
+	qp_init_attr->cap	     = qp_attr->cap;
+
 	return 0;
 }
 
diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c
index 408748f..e7e9a3d 100644
--- a/drivers/infiniband/hw/mlx4/srq.c
+++ b/drivers/infiniband/hw/mlx4/srq.c
@@ -251,7 +251,7 @@
 	if (ret)
 		return ret;
 
-	srq_attr->srq_limit = be16_to_cpu(limit_watermark);
+	srq_attr->srq_limit = limit_watermark;
 	srq_attr->max_wr    = srq->msrq.max - 1;
 	srq_attr->max_sge   = srq->msrq.max_gs;
 
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index f40558d..6966f94 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -290,6 +290,12 @@
 		err = mthca_cmd_post_hcr(dev, in_param, out_param, in_modifier,
 					 op_modifier, op, token, event);
 
+	/*
+	 * Make sure that our HCR writes don't get mixed in with
+	 * writes from another CPU starting a FW command.
+	 */
+	mmiowb();
+
 	mutex_unlock(&dev->cmd.hcr_mutex);
 	return err;
 }
@@ -357,8 +363,6 @@
 	context->status    = status;
 	context->out_param = out_param;
 
-	context->token += dev->cmd.token_mask + 1;
-
 	complete(&context->done);
 }
 
@@ -380,6 +384,7 @@
 	spin_lock(&dev->cmd.context_lock);
 	BUG_ON(dev->cmd.free_head < 0);
 	context = &dev->cmd.context[dev->cmd.free_head];
+	context->token += dev->cmd.token_mask + 1;
 	dev->cmd.free_head = context->next;
 	spin_unlock(&dev->cmd.context_lock);
 
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index 9bae3cc..15aa32e 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -83,7 +83,7 @@
 	MTHCA_QP_CONTEXT_SIZE = 0x200,
 	MTHCA_RDB_ENTRY_SIZE  =  0x20,
 	MTHCA_AV_SIZE         =  0x20,
-	MTHCA_MGM_ENTRY_SIZE  =  0x40,
+	MTHCA_MGM_ENTRY_SIZE  = 0x100,
 
 	/* Arbel FW gives us these, but we need them for Tavor */
 	MTHCA_MPT_ENTRY_SIZE  =  0x40,
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index aa563e6..60de6f9 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -61,13 +61,13 @@
 
 #ifdef CONFIG_PCI_MSI
 
-static int msi_x = 0;
+static int msi_x = 1;
 module_param(msi_x, int, 0444);
 MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
 
 static int msi = 0;
 module_param(msi, int, 0444);
-MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero");
+MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero (deprecated, use MSI-X instead)");
 
 #else /* CONFIG_PCI_MSI */
 
@@ -137,40 +137,23 @@
 
 static int mthca_tune_pci(struct mthca_dev *mdev)
 {
-	int cap;
-	u16 val;
-
 	if (!tune_pci)
 		return 0;
 
 	/* First try to max out Read Byte Count */
-	cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX);
-	if (cap) {
-		if (pci_read_config_word(mdev->pdev, cap + PCI_X_CMD, &val)) {
-			mthca_err(mdev, "Couldn't read PCI-X command register, "
-				  "aborting.\n");
-			return -ENODEV;
-		}
-		val = (val & ~PCI_X_CMD_MAX_READ) | (3 << 2);
-		if (pci_write_config_word(mdev->pdev, cap + PCI_X_CMD, val)) {
-			mthca_err(mdev, "Couldn't write PCI-X command register, "
-				  "aborting.\n");
+	if (pci_find_capability(mdev->pdev, PCI_CAP_ID_PCIX)) {
+		if (pcix_set_mmrbc(mdev->pdev, pcix_get_max_mmrbc(mdev->pdev))) {
+			mthca_err(mdev, "Couldn't set PCI-X max read count, "
+				"aborting.\n");
 			return -ENODEV;
 		}
 	} else if (!(mdev->mthca_flags & MTHCA_FLAG_PCIE))
 		mthca_info(mdev, "No PCI-X capability, not setting RBC.\n");
 
-	cap = pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP);
-	if (cap) {
-		if (pci_read_config_word(mdev->pdev, cap + PCI_EXP_DEVCTL, &val)) {
-			mthca_err(mdev, "Couldn't read PCI Express device control "
-				  "register, aborting.\n");
-			return -ENODEV;
-		}
-		val = (val & ~PCI_EXP_DEVCTL_READRQ) | (5 << 12);
-		if (pci_write_config_word(mdev->pdev, cap + PCI_EXP_DEVCTL, val)) {
-			mthca_err(mdev, "Couldn't write PCI Express device control "
-				  "register, aborting.\n");
+	if (pci_find_capability(mdev->pdev, PCI_CAP_ID_EXP)) {
+		if (pcie_set_readrq(mdev->pdev, 4096)) {
+			mthca_err(mdev, "Couldn't write PCI Express read request, "
+				"aborting.\n");
 			return -ENODEV;
 		}
 	} else if (mdev->mthca_flags & MTHCA_FLAG_PCIE)
@@ -833,14 +816,19 @@
 
 	err = mthca_NOP(dev, &status);
 	if (err || status) {
-		mthca_err(dev, "NOP command failed to generate interrupt (IRQ %d), aborting.\n",
-			  dev->mthca_flags & MTHCA_FLAG_MSI_X ?
-			  dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector :
-			  dev->pdev->irq);
-		if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X))
-			mthca_err(dev, "Try again with MSI/MSI-X disabled.\n");
-		else
+		if (dev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X)) {
+			mthca_warn(dev, "NOP command failed to generate interrupt "
+				   "(IRQ %d).\n",
+				   dev->mthca_flags & MTHCA_FLAG_MSI_X ?
+				   dev->eq_table.eq[MTHCA_EQ_CMD].msi_x_vector :
+				   dev->pdev->irq);
+			mthca_warn(dev, "Trying again with MSI/MSI-X disabled.\n");
+		} else {
+			mthca_err(dev, "NOP command failed to generate interrupt "
+				  "(IRQ %d), aborting.\n",
+				  dev->pdev->irq);
 			mthca_err(dev, "BIOS or ACPI interrupt routing problem?\n");
+		}
 
 		goto err_cmd_poll;
 	}
@@ -1115,12 +1103,6 @@
 		goto err_free_dev;
 	}
 
-	if (msi_x && !mthca_enable_msi_x(mdev))
-		mdev->mthca_flags |= MTHCA_FLAG_MSI_X;
-	if (msi && !(mdev->mthca_flags & MTHCA_FLAG_MSI_X) &&
-	    !pci_enable_msi(pdev))
-		mdev->mthca_flags |= MTHCA_FLAG_MSI;
-
 	if (mthca_cmd_init(mdev)) {
 		mthca_err(mdev, "Failed to init command interface, aborting.\n");
 		goto err_free_dev;
@@ -1135,7 +1117,7 @@
 		goto err_cmd;
 
 	if (mdev->fw_ver < mthca_hca_table[hca_type].latest_fw) {
-		mthca_warn(mdev, "HCA FW version %d.%d.%3d is old (%d.%d.%3d is current).\n",
+		mthca_warn(mdev, "HCA FW version %d.%d.%03d is old (%d.%d.%03d is current).\n",
 			   (int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,
 			   (int) (mdev->fw_ver & 0xffff),
 			   (int) (mthca_hca_table[hca_type].latest_fw >> 32),
@@ -1144,7 +1126,35 @@
 		mthca_warn(mdev, "If you have problems, try updating your HCA FW.\n");
 	}
 
+	if (msi_x && !mthca_enable_msi_x(mdev))
+		mdev->mthca_flags |= MTHCA_FLAG_MSI_X;
+	else if (msi) {
+		static int warned;
+
+		if (!warned) {
+			printk(KERN_WARNING PFX "WARNING: MSI support will be "
+			       "removed from the ib_mthca driver in January 2008.\n");
+			printk(KERN_WARNING "    If you are using MSI and cannot "
+			       "switch to MSI-X, please tell "
+			       "<general@lists.openfabrics.org>.\n");
+			++warned;
+		}
+
+		if (!pci_enable_msi(pdev))
+			mdev->mthca_flags |= MTHCA_FLAG_MSI;
+	}
+
 	err = mthca_setup_hca(mdev);
+	if (err == -EBUSY && (mdev->mthca_flags & (MTHCA_FLAG_MSI | MTHCA_FLAG_MSI_X))) {
+		if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
+			pci_disable_msix(pdev);
+		if (mdev->mthca_flags & MTHCA_FLAG_MSI)
+			pci_disable_msi(pdev);
+		mdev->mthca_flags &= ~(MTHCA_FLAG_MSI_X | MTHCA_FLAG_MSI);
+
+		err = mthca_setup_hca(mdev);
+	}
+
 	if (err)
 		goto err_close;
 
@@ -1180,17 +1190,17 @@
 	mthca_cleanup_uar_table(mdev);
 
 err_close:
+	if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
+		pci_disable_msix(pdev);
+	if (mdev->mthca_flags & MTHCA_FLAG_MSI)
+		pci_disable_msi(pdev);
+
 	mthca_close_hca(mdev);
 
 err_cmd:
 	mthca_cmd_cleanup(mdev);
 
 err_free_dev:
-	if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
-		pci_disable_msix(pdev);
-	if (mdev->mthca_flags & MTHCA_FLAG_MSI)
-		pci_disable_msi(pdev);
-
 	ib_dealloc_device(&mdev->ib_dev);
 
 err_free_res:
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 11f1d99..df01b20 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -1578,6 +1578,45 @@
 	return cur + nreq >= wq->max;
 }
 
+static __always_inline void set_raddr_seg(struct mthca_raddr_seg *rseg,
+					  u64 remote_addr, u32 rkey)
+{
+	rseg->raddr    = cpu_to_be64(remote_addr);
+	rseg->rkey     = cpu_to_be32(rkey);
+	rseg->reserved = 0;
+}
+
+static __always_inline void set_atomic_seg(struct mthca_atomic_seg *aseg,
+					   struct ib_send_wr *wr)
+{
+	if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
+		aseg->swap_add = cpu_to_be64(wr->wr.atomic.swap);
+		aseg->compare  = cpu_to_be64(wr->wr.atomic.compare_add);
+	} else {
+		aseg->swap_add = cpu_to_be64(wr->wr.atomic.compare_add);
+		aseg->compare  = 0;
+	}
+
+}
+
+static void set_tavor_ud_seg(struct mthca_tavor_ud_seg *useg,
+			     struct ib_send_wr *wr)
+{
+	useg->lkey    = cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
+	useg->av_addr =	cpu_to_be64(to_mah(wr->wr.ud.ah)->avdma);
+	useg->dqpn    =	cpu_to_be32(wr->wr.ud.remote_qpn);
+	useg->qkey    =	cpu_to_be32(wr->wr.ud.remote_qkey);
+
+}
+
+static void set_arbel_ud_seg(struct mthca_arbel_ud_seg *useg,
+			     struct ib_send_wr *wr)
+{
+	memcpy(useg->av, to_mah(wr->wr.ud.ah)->av, MTHCA_AV_SIZE);
+	useg->dqpn = cpu_to_be32(wr->wr.ud.remote_qpn);
+	useg->qkey = cpu_to_be32(wr->wr.ud.remote_qkey);
+}
+
 int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 			  struct ib_send_wr **bad_wr)
 {
@@ -1590,8 +1629,15 @@
 	int nreq;
 	int i;
 	int size;
-	int size0 = 0;
-	u32 f0 = 0;
+	/*
+	 * f0 and size0 are only used if nreq != 0, and they will
+	 * always be initialized the first time through the main loop
+	 * before nreq is incremented.  So nreq cannot become non-zero
+	 * without initializing f0 and size0, and they are in fact
+	 * never used uninitialized.
+	 */
+	int uninitialized_var(size0);
+	u32 uninitialized_var(f0);
 	int ind;
 	u8 op0 = 0;
 
@@ -1636,25 +1682,11 @@
 			switch (wr->opcode) {
 			case IB_WR_ATOMIC_CMP_AND_SWP:
 			case IB_WR_ATOMIC_FETCH_AND_ADD:
-				((struct mthca_raddr_seg *) wqe)->raddr =
-					cpu_to_be64(wr->wr.atomic.remote_addr);
-				((struct mthca_raddr_seg *) wqe)->rkey =
-					cpu_to_be32(wr->wr.atomic.rkey);
-				((struct mthca_raddr_seg *) wqe)->reserved = 0;
-
+				set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
+					      wr->wr.atomic.rkey);
 				wqe += sizeof (struct mthca_raddr_seg);
 
-				if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
-					((struct mthca_atomic_seg *) wqe)->swap_add =
-						cpu_to_be64(wr->wr.atomic.swap);
-					((struct mthca_atomic_seg *) wqe)->compare =
-						cpu_to_be64(wr->wr.atomic.compare_add);
-				} else {
-					((struct mthca_atomic_seg *) wqe)->swap_add =
-						cpu_to_be64(wr->wr.atomic.compare_add);
-					((struct mthca_atomic_seg *) wqe)->compare = 0;
-				}
-
+				set_atomic_seg(wqe, wr);
 				wqe += sizeof (struct mthca_atomic_seg);
 				size += (sizeof (struct mthca_raddr_seg) +
 					 sizeof (struct mthca_atomic_seg)) / 16;
@@ -1663,12 +1695,9 @@
 			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);
+				set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+					      wr->wr.rdma.rkey);
+				wqe  += sizeof (struct mthca_raddr_seg);
 				size += sizeof (struct mthca_raddr_seg) / 16;
 				break;
 
@@ -1683,12 +1712,9 @@
 			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);
+				set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+					      wr->wr.rdma.rkey);
+				wqe  += sizeof (struct mthca_raddr_seg);
 				size += sizeof (struct mthca_raddr_seg) / 16;
 				break;
 
@@ -1700,16 +1726,8 @@
 			break;
 
 		case UD:
-			((struct mthca_tavor_ud_seg *) wqe)->lkey =
-				cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
-			((struct mthca_tavor_ud_seg *) wqe)->av_addr =
-				cpu_to_be64(to_mah(wr->wr.ud.ah)->avdma);
-			((struct mthca_tavor_ud_seg *) wqe)->dqpn =
-				cpu_to_be32(wr->wr.ud.remote_qpn);
-			((struct mthca_tavor_ud_seg *) wqe)->qkey =
-				cpu_to_be32(wr->wr.ud.remote_qkey);
-
-			wqe += sizeof (struct mthca_tavor_ud_seg);
+			set_tavor_ud_seg(wqe, wr);
+			wqe  += sizeof (struct mthca_tavor_ud_seg);
 			size += sizeof (struct mthca_tavor_ud_seg) / 16;
 			break;
 
@@ -1734,13 +1752,8 @@
 		}
 
 		for (i = 0; i < wr->num_sge; ++i) {
-			((struct mthca_data_seg *) wqe)->byte_count =
-				cpu_to_be32(wr->sg_list[i].length);
-			((struct mthca_data_seg *) wqe)->lkey =
-				cpu_to_be32(wr->sg_list[i].lkey);
-			((struct mthca_data_seg *) wqe)->addr =
-				cpu_to_be64(wr->sg_list[i].addr);
-			wqe += sizeof (struct mthca_data_seg);
+			mthca_set_data_seg(wqe, wr->sg_list + i);
+			wqe  += sizeof (struct mthca_data_seg);
 			size += sizeof (struct mthca_data_seg) / 16;
 		}
 
@@ -1768,11 +1781,11 @@
 				    mthca_opcode[wr->opcode]);
 		wmb();
 		((struct mthca_next_seg *) prev_wqe)->ee_nds =
-			cpu_to_be32((size0 ? 0 : MTHCA_NEXT_DBD) | size |
+			cpu_to_be32((nreq ? 0 : MTHCA_NEXT_DBD) | size |
 				    ((wr->send_flags & IB_SEND_FENCE) ?
 				    MTHCA_NEXT_FENCE : 0));
 
-		if (!size0) {
+		if (!nreq) {
 			size0 = size;
 			op0   = mthca_opcode[wr->opcode];
 			f0    = wr->send_flags & IB_SEND_FENCE ?
@@ -1822,7 +1835,14 @@
 	int nreq;
 	int i;
 	int size;
-	int size0 = 0;
+	/*
+	 * size0 is only used if nreq != 0, and it will always be
+	 * initialized the first time through the main loop before
+	 * nreq is incremented.  So nreq cannot become non-zero
+	 * without initializing size0, and it is in fact never used
+	 * uninitialized.
+	 */
+	int uninitialized_var(size0);
 	int ind;
 	void *wqe;
 	void *prev_wqe;
@@ -1863,13 +1883,8 @@
 		}
 
 		for (i = 0; i < wr->num_sge; ++i) {
-			((struct mthca_data_seg *) wqe)->byte_count =
-				cpu_to_be32(wr->sg_list[i].length);
-			((struct mthca_data_seg *) wqe)->lkey =
-				cpu_to_be32(wr->sg_list[i].lkey);
-			((struct mthca_data_seg *) wqe)->addr =
-				cpu_to_be64(wr->sg_list[i].addr);
-			wqe += sizeof (struct mthca_data_seg);
+			mthca_set_data_seg(wqe, wr->sg_list + i);
+			wqe  += sizeof (struct mthca_data_seg);
 			size += sizeof (struct mthca_data_seg) / 16;
 		}
 
@@ -1881,7 +1896,7 @@
 		((struct mthca_next_seg *) prev_wqe)->ee_nds =
 			cpu_to_be32(MTHCA_NEXT_DBD | size);
 
-		if (!size0)
+		if (!nreq)
 			size0 = size;
 
 		++ind;
@@ -1903,7 +1918,6 @@
 
 			qp->rq.next_ind = ind;
 			qp->rq.head += MTHCA_TAVOR_MAX_WQES_PER_RECV_DB;
-			size0 = 0;
 		}
 	}
 
@@ -1945,8 +1959,15 @@
 	int nreq;
 	int i;
 	int size;
-	int size0 = 0;
-	u32 f0 = 0;
+	/*
+	 * f0 and size0 are only used if nreq != 0, and they will
+	 * always be initialized the first time through the main loop
+	 * before nreq is incremented.  So nreq cannot become non-zero
+	 * without initializing f0 and size0, and they are in fact
+	 * never used uninitialized.
+	 */
+	int uninitialized_var(size0);
+	u32 uninitialized_var(f0);
 	int ind;
 	u8 op0 = 0;
 
@@ -1966,7 +1987,6 @@
 			doorbell[1] = cpu_to_be32((qp->qpn << 8) | size0);
 
 			qp->sq.head += MTHCA_ARBEL_MAX_WQES_PER_SEND_DB;
-			size0 = 0;
 
 			/*
 			 * Make sure that descriptors are written before
@@ -2017,26 +2037,12 @@
 			switch (wr->opcode) {
 			case IB_WR_ATOMIC_CMP_AND_SWP:
 			case IB_WR_ATOMIC_FETCH_AND_ADD:
-				((struct mthca_raddr_seg *) wqe)->raddr =
-					cpu_to_be64(wr->wr.atomic.remote_addr);
-				((struct mthca_raddr_seg *) wqe)->rkey =
-					cpu_to_be32(wr->wr.atomic.rkey);
-				((struct mthca_raddr_seg *) wqe)->reserved = 0;
-
+				set_raddr_seg(wqe, wr->wr.atomic.remote_addr,
+					      wr->wr.atomic.rkey);
 				wqe += sizeof (struct mthca_raddr_seg);
 
-				if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) {
-					((struct mthca_atomic_seg *) wqe)->swap_add =
-						cpu_to_be64(wr->wr.atomic.swap);
-					((struct mthca_atomic_seg *) wqe)->compare =
-						cpu_to_be64(wr->wr.atomic.compare_add);
-				} else {
-					((struct mthca_atomic_seg *) wqe)->swap_add =
-						cpu_to_be64(wr->wr.atomic.compare_add);
-					((struct mthca_atomic_seg *) wqe)->compare = 0;
-				}
-
-				wqe += sizeof (struct mthca_atomic_seg);
+				set_atomic_seg(wqe, wr);
+				wqe  += sizeof (struct mthca_atomic_seg);
 				size += (sizeof (struct mthca_raddr_seg) +
 					 sizeof (struct mthca_atomic_seg)) / 16;
 				break;
@@ -2044,12 +2050,9 @@
 			case IB_WR_RDMA_READ:
 			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);
+				set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+					      wr->wr.rdma.rkey);
+				wqe  += sizeof (struct mthca_raddr_seg);
 				size += sizeof (struct mthca_raddr_seg) / 16;
 				break;
 
@@ -2064,12 +2067,9 @@
 			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);
+				set_raddr_seg(wqe, wr->wr.rdma.remote_addr,
+					      wr->wr.rdma.rkey);
+				wqe  += sizeof (struct mthca_raddr_seg);
 				size += sizeof (struct mthca_raddr_seg) / 16;
 				break;
 
@@ -2081,14 +2081,8 @@
 			break;
 
 		case UD:
-			memcpy(((struct mthca_arbel_ud_seg *) wqe)->av,
-			       to_mah(wr->wr.ud.ah)->av, MTHCA_AV_SIZE);
-			((struct mthca_arbel_ud_seg *) wqe)->dqpn =
-				cpu_to_be32(wr->wr.ud.remote_qpn);
-			((struct mthca_arbel_ud_seg *) wqe)->qkey =
-				cpu_to_be32(wr->wr.ud.remote_qkey);
-
-			wqe += sizeof (struct mthca_arbel_ud_seg);
+			set_arbel_ud_seg(wqe, wr);
+			wqe  += sizeof (struct mthca_arbel_ud_seg);
 			size += sizeof (struct mthca_arbel_ud_seg) / 16;
 			break;
 
@@ -2113,13 +2107,8 @@
 		}
 
 		for (i = 0; i < wr->num_sge; ++i) {
-			((struct mthca_data_seg *) wqe)->byte_count =
-				cpu_to_be32(wr->sg_list[i].length);
-			((struct mthca_data_seg *) wqe)->lkey =
-				cpu_to_be32(wr->sg_list[i].lkey);
-			((struct mthca_data_seg *) wqe)->addr =
-				cpu_to_be64(wr->sg_list[i].addr);
-			wqe += sizeof (struct mthca_data_seg);
+			mthca_set_data_seg(wqe, wr->sg_list + i);
+			wqe  += sizeof (struct mthca_data_seg);
 			size += sizeof (struct mthca_data_seg) / 16;
 		}
 
@@ -2151,7 +2140,7 @@
 				    ((wr->send_flags & IB_SEND_FENCE) ?
 				     MTHCA_NEXT_FENCE : 0));
 
-		if (!size0) {
+		if (!nreq) {
 			size0 = size;
 			op0   = mthca_opcode[wr->opcode];
 			f0    = wr->send_flags & IB_SEND_FENCE ?
@@ -2241,20 +2230,12 @@
 		}
 
 		for (i = 0; i < wr->num_sge; ++i) {
-			((struct mthca_data_seg *) wqe)->byte_count =
-				cpu_to_be32(wr->sg_list[i].length);
-			((struct mthca_data_seg *) wqe)->lkey =
-				cpu_to_be32(wr->sg_list[i].lkey);
-			((struct mthca_data_seg *) wqe)->addr =
-				cpu_to_be64(wr->sg_list[i].addr);
+			mthca_set_data_seg(wqe, wr->sg_list + i);
 			wqe += sizeof (struct mthca_data_seg);
 		}
 
-		if (i < qp->rq.max_gs) {
-			((struct mthca_data_seg *) wqe)->byte_count = 0;
-			((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
-			((struct mthca_data_seg *) wqe)->addr = 0;
-		}
+		if (i < qp->rq.max_gs)
+			mthca_set_data_seg_inval(wqe);
 
 		qp->wrid[ind] = wr->wr_id;
 
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c
index b8f05a5..3f58c11 100644
--- a/drivers/infiniband/hw/mthca/mthca_srq.c
+++ b/drivers/infiniband/hw/mthca/mthca_srq.c
@@ -509,7 +509,7 @@
 	for (nreq = 0; wr; wr = wr->next) {
 		ind = srq->first_free;
 
-		if (ind < 0) {
+		if (unlikely(ind < 0)) {
 			mthca_err(dev, "SRQ %06x full\n", srq->srqn);
 			err = -ENOMEM;
 			*bad_wr = wr;
@@ -519,7 +519,7 @@
 		wqe       = get_wqe(srq, ind);
 		next_ind  = *wqe_to_link(wqe);
 
-		if (next_ind < 0) {
+		if (unlikely(next_ind < 0)) {
 			mthca_err(dev, "SRQ %06x full\n", srq->srqn);
 			err = -ENOMEM;
 			*bad_wr = wr;
@@ -543,20 +543,12 @@
 		}
 
 		for (i = 0; i < wr->num_sge; ++i) {
-			((struct mthca_data_seg *) wqe)->byte_count =
-				cpu_to_be32(wr->sg_list[i].length);
-			((struct mthca_data_seg *) wqe)->lkey =
-				cpu_to_be32(wr->sg_list[i].lkey);
-			((struct mthca_data_seg *) wqe)->addr =
-				cpu_to_be64(wr->sg_list[i].addr);
+			mthca_set_data_seg(wqe, wr->sg_list + i);
 			wqe += sizeof (struct mthca_data_seg);
 		}
 
-		if (i < srq->max_gs) {
-			((struct mthca_data_seg *) wqe)->byte_count = 0;
-			((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
-			((struct mthca_data_seg *) wqe)->addr = 0;
-		}
+		if (i < srq->max_gs)
+			mthca_set_data_seg_inval(wqe);
 
 		((struct mthca_next_seg *) prev_wqe)->nda_op =
 			cpu_to_be32((ind << srq->wqe_shift) | 1);
@@ -631,7 +623,7 @@
 	for (nreq = 0; wr; ++nreq, wr = wr->next) {
 		ind = srq->first_free;
 
-		if (ind < 0) {
+		if (unlikely(ind < 0)) {
 			mthca_err(dev, "SRQ %06x full\n", srq->srqn);
 			err = -ENOMEM;
 			*bad_wr = wr;
@@ -641,7 +633,7 @@
 		wqe       = get_wqe(srq, ind);
 		next_ind  = *wqe_to_link(wqe);
 
-		if (next_ind < 0) {
+		if (unlikely(next_ind < 0)) {
 			mthca_err(dev, "SRQ %06x full\n", srq->srqn);
 			err = -ENOMEM;
 			*bad_wr = wr;
@@ -662,20 +654,12 @@
 		}
 
 		for (i = 0; i < wr->num_sge; ++i) {
-			((struct mthca_data_seg *) wqe)->byte_count =
-				cpu_to_be32(wr->sg_list[i].length);
-			((struct mthca_data_seg *) wqe)->lkey =
-				cpu_to_be32(wr->sg_list[i].lkey);
-			((struct mthca_data_seg *) wqe)->addr =
-				cpu_to_be64(wr->sg_list[i].addr);
+			mthca_set_data_seg(wqe, wr->sg_list + i);
 			wqe += sizeof (struct mthca_data_seg);
 		}
 
-		if (i < srq->max_gs) {
-			((struct mthca_data_seg *) wqe)->byte_count = 0;
-			((struct mthca_data_seg *) wqe)->lkey = cpu_to_be32(MTHCA_INVAL_LKEY);
-			((struct mthca_data_seg *) wqe)->addr = 0;
-		}
+		if (i < srq->max_gs)
+			mthca_set_data_seg_inval(wqe);
 
 		srq->wrid[ind]  = wr->wr_id;
 		srq->first_free = next_ind;
diff --git a/drivers/infiniband/hw/mthca/mthca_wqe.h b/drivers/infiniband/hw/mthca/mthca_wqe.h
index e7d2c1e..f6a66fe 100644
--- a/drivers/infiniband/hw/mthca/mthca_wqe.h
+++ b/drivers/infiniband/hw/mthca/mthca_wqe.h
@@ -113,4 +113,19 @@
 	__be16 vcrc;
 };
 
+static __always_inline void mthca_set_data_seg(struct mthca_data_seg *dseg,
+					       struct ib_sge *sg)
+{
+	dseg->byte_count = cpu_to_be32(sg->length);
+	dseg->lkey       = cpu_to_be32(sg->lkey);
+	dseg->addr       = cpu_to_be64(sg->addr);
+}
+
+static __always_inline void mthca_set_data_seg_inval(struct mthca_data_seg *dseg)
+{
+	dseg->byte_count = 0;
+	dseg->lkey       = cpu_to_be32(MTHCA_INVAL_LKEY);
+	dseg->addr       = 0;
+}
+
 #endif /* MTHCA_WQE_H */
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 285c143..6545fa7 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -86,6 +86,7 @@
 	IPOIB_MCAST_STARTED       = 8,
 	IPOIB_FLAG_NETIF_STOPPED  = 9,
 	IPOIB_FLAG_ADMIN_CM 	  = 10,
+	IPOIB_FLAG_UMCAST	  = 11,
 
 	IPOIB_MAX_BACKOFF_SECONDS = 16,
 
@@ -113,7 +114,27 @@
 	u8  hwaddr[INFINIBAND_ALEN];
 };
 
-struct ipoib_mcast;
+/* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */
+struct ipoib_mcast {
+	struct ib_sa_mcmember_rec mcmember;
+	struct ib_sa_multicast	 *mc;
+	struct ipoib_ah          *ah;
+
+	struct rb_node    rb_node;
+	struct list_head  list;
+
+	unsigned long created;
+	unsigned long backoff;
+
+	unsigned long flags;
+	unsigned char logcount;
+
+	struct list_head  neigh_list;
+
+	struct sk_buff_head pkt_queue;
+
+	struct net_device *dev;
+};
 
 struct ipoib_rx_buf {
 	struct sk_buff *skb;
@@ -228,6 +249,8 @@
 
 	struct net_device *dev;
 
+	struct napi_struct napi;
+
 	unsigned long flags;
 
 	struct mutex mcast_mutex;
@@ -278,8 +301,6 @@
 
 	struct ib_event_handler event_handler;
 
-	struct net_device_stats stats;
-
 	struct net_device *parent;
 	struct list_head child_intfs;
 	struct list_head list;
@@ -351,7 +372,7 @@
 
 /* functions */
 
-int ipoib_poll(struct net_device *dev, int *budget);
+int ipoib_poll(struct napi_struct *napi, int budget);
 void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr);
 
 struct ipoib_ah *ipoib_create_ah(struct net_device *dev,
@@ -364,6 +385,7 @@
 
 int ipoib_open(struct net_device *dev);
 int ipoib_add_pkey_attr(struct net_device *dev);
+int ipoib_add_umcast_attr(struct net_device *dev);
 
 void ipoib_send(struct net_device *dev, struct sk_buff *skb,
 		struct ipoib_ah *address, u32 qpn);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 08b4676..0a0dcb8 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -430,7 +430,7 @@
 		ipoib_dbg(priv, "cm recv error "
 			   "(status=%d, wrid=%d vend_err %x)\n",
 			   wc->status, wr_id, wc->vendor_err);
-		++priv->stats.rx_dropped;
+		++dev->stats.rx_dropped;
 		goto repost;
 	}
 
@@ -457,7 +457,7 @@
 		 * this packet and reuse the old buffer.
 		 */
 		ipoib_dbg(priv, "failed to allocate receive buffer %d\n", wr_id);
-		++priv->stats.rx_dropped;
+		++dev->stats.rx_dropped;
 		goto repost;
 	}
 
@@ -474,8 +474,8 @@
 	skb_pull(skb, IPOIB_ENCAP_LEN);
 
 	dev->last_rx = jiffies;
-	++priv->stats.rx_packets;
-	priv->stats.rx_bytes += skb->len;
+	++dev->stats.rx_packets;
+	dev->stats.rx_bytes += skb->len;
 
 	skb->dev = dev;
 	/* XXX get correct PACKET_ type here */
@@ -512,8 +512,8 @@
 	if (unlikely(skb->len > tx->mtu)) {
 		ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",
 			   skb->len, tx->mtu);
-		++priv->stats.tx_dropped;
-		++priv->stats.tx_errors;
+		++dev->stats.tx_dropped;
+		++dev->stats.tx_errors;
 		ipoib_cm_skb_too_long(dev, skb, tx->mtu - IPOIB_ENCAP_LEN);
 		return;
 	}
@@ -532,7 +532,7 @@
 	tx_req->skb = skb;
 	addr = ib_dma_map_single(priv->ca, skb->data, skb->len, DMA_TO_DEVICE);
 	if (unlikely(ib_dma_mapping_error(priv->ca, addr))) {
-		++priv->stats.tx_errors;
+		++dev->stats.tx_errors;
 		dev_kfree_skb_any(skb);
 		return;
 	}
@@ -542,7 +542,7 @@
 	if (unlikely(post_send(priv, tx, tx->tx_head & (ipoib_sendq_size - 1),
 			        addr, skb->len))) {
 		ipoib_warn(priv, "post_send failed\n");
-		++priv->stats.tx_errors;
+		++dev->stats.tx_errors;
 		ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE);
 		dev_kfree_skb_any(skb);
 	} else {
@@ -580,8 +580,8 @@
 	ib_dma_unmap_single(priv->ca, tx_req->mapping, tx_req->skb->len, DMA_TO_DEVICE);
 
 	/* FIXME: is this right? Shouldn't we only increment on success? */
-	++priv->stats.tx_packets;
-	priv->stats.tx_bytes += tx_req->skb->len;
+	++dev->stats.tx_packets;
+	dev->stats.tx_bytes += tx_req->skb->len;
 
 	dev_kfree_skb_any(tx_req->skb);
 
@@ -810,14 +810,16 @@
 static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ib_cq *cq)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
-	struct ib_qp_init_attr attr = {};
-	attr.recv_cq = priv->cq;
-	attr.srq = priv->cm.srq;
-	attr.cap.max_send_wr = ipoib_sendq_size;
-	attr.cap.max_send_sge = 1;
-	attr.sq_sig_type = IB_SIGNAL_ALL_WR;
-	attr.qp_type = IB_QPT_RC;
-	attr.send_cq = cq;
+	struct ib_qp_init_attr attr = {
+		.send_cq		= cq,
+		.recv_cq		= priv->cq,
+		.srq			= priv->cm.srq,
+		.cap.max_send_wr	= ipoib_sendq_size,
+		.cap.max_send_sge	= 1,
+		.sq_sig_type		= IB_SIGNAL_ALL_WR,
+		.qp_type		= IB_QPT_RC,
+        };
+
 	return ib_create_qp(priv->pd, &attr);
 }
 
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 1094488..1a77e79 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -208,7 +208,7 @@
 	 * this packet and reuse the old buffer.
 	 */
 	if (unlikely(ipoib_alloc_rx_skb(dev, wr_id))) {
-		++priv->stats.rx_dropped;
+		++dev->stats.rx_dropped;
 		goto repost;
 	}
 
@@ -225,8 +225,8 @@
 	skb_pull(skb, IPOIB_ENCAP_LEN);
 
 	dev->last_rx = jiffies;
-	++priv->stats.rx_packets;
-	priv->stats.rx_bytes += skb->len;
+	++dev->stats.rx_packets;
+	dev->stats.rx_bytes += skb->len;
 
 	skb->dev = dev;
 	/* XXX get correct PACKET_ type here */
@@ -260,8 +260,8 @@
 	ib_dma_unmap_single(priv->ca, tx_req->mapping,
 			    tx_req->skb->len, DMA_TO_DEVICE);
 
-	++priv->stats.tx_packets;
-	priv->stats.tx_bytes += tx_req->skb->len;
+	++dev->stats.tx_packets;
+	dev->stats.tx_bytes += tx_req->skb->len;
 
 	dev_kfree_skb_any(tx_req->skb);
 
@@ -281,63 +281,58 @@
 			   wc->status, wr_id, wc->vendor_err);
 }
 
-int ipoib_poll(struct net_device *dev, int *budget)
+int ipoib_poll(struct napi_struct *napi, int budget)
 {
-	struct ipoib_dev_priv *priv = netdev_priv(dev);
-	int max = min(*budget, dev->quota);
+	struct ipoib_dev_priv *priv = container_of(napi, struct ipoib_dev_priv, napi);
+	struct net_device *dev = priv->dev;
 	int done;
 	int t;
-	int empty;
 	int n, i;
 
 	done  = 0;
-	empty = 0;
 
-	while (max) {
+poll_more:
+	while (done < budget) {
+		int max = (budget - done);
+
 		t = min(IPOIB_NUM_WC, max);
 		n = ib_poll_cq(priv->cq, t, priv->ibwc);
 
-		for (i = 0; i < n; ++i) {
+		for (i = 0; i < n; i++) {
 			struct ib_wc *wc = priv->ibwc + i;
 
 			if (wc->wr_id & IPOIB_CM_OP_SRQ) {
 				++done;
-				--max;
 				ipoib_cm_handle_rx_wc(dev, wc);
 			} else if (wc->wr_id & IPOIB_OP_RECV) {
 				++done;
-				--max;
 				ipoib_ib_handle_rx_wc(dev, wc);
 			} else
 				ipoib_ib_handle_tx_wc(dev, wc);
 		}
 
-		if (n != t) {
-			empty = 1;
+		if (n != t)
 			break;
-		}
 	}
 
-	dev->quota -= done;
-	*budget    -= done;
-
-	if (empty) {
-		netif_rx_complete(dev);
+	if (done < budget) {
+		netif_rx_complete(dev, napi);
 		if (unlikely(ib_req_notify_cq(priv->cq,
 					      IB_CQ_NEXT_COMP |
 					      IB_CQ_REPORT_MISSED_EVENTS)) &&
-		    netif_rx_reschedule(dev, 0))
-			return 1;
-
-		return 0;
+		    netif_rx_reschedule(dev, napi))
+			goto poll_more;
 	}
 
-	return 1;
+	return done;
 }
 
 void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr)
 {
-	netif_rx_schedule(dev_ptr);
+	struct net_device *dev = dev_ptr;
+	struct ipoib_dev_priv *priv = netdev_priv(dev);
+
+	netif_rx_schedule(dev, &priv->napi);
 }
 
 static inline int post_send(struct ipoib_dev_priv *priv,
@@ -367,8 +362,8 @@
 	if (unlikely(skb->len > priv->mcast_mtu + IPOIB_ENCAP_LEN)) {
 		ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",
 			   skb->len, priv->mcast_mtu + IPOIB_ENCAP_LEN);
-		++priv->stats.tx_dropped;
-		++priv->stats.tx_errors;
+		++dev->stats.tx_dropped;
+		++dev->stats.tx_errors;
 		ipoib_cm_skb_too_long(dev, skb, priv->mcast_mtu);
 		return;
 	}
@@ -388,7 +383,7 @@
 	addr = ib_dma_map_single(priv->ca, skb->data, skb->len,
 				 DMA_TO_DEVICE);
 	if (unlikely(ib_dma_mapping_error(priv->ca, addr))) {
-		++priv->stats.tx_errors;
+		++dev->stats.tx_errors;
 		dev_kfree_skb_any(skb);
 		return;
 	}
@@ -397,7 +392,7 @@
 	if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1),
 			       address->ah, qpn, addr, skb->len))) {
 		ipoib_warn(priv, "post_send failed\n");
-		++priv->stats.tx_errors;
+		++dev->stats.tx_errors;
 		ib_dma_unmap_single(priv->ca, addr, skb->len, DMA_TO_DEVICE);
 		dev_kfree_skb_any(skb);
 	} else {
@@ -558,6 +553,14 @@
 	do {
 		n = ib_poll_cq(priv->cq, IPOIB_NUM_WC, priv->ibwc);
 		for (i = 0; i < n; ++i) {
+			/*
+			 * Convert any successful completions to flush
+			 * errors to avoid passing packets up the
+			 * stack after bringing the device down.
+			 */
+			if (priv->ibwc[i].status == IB_WC_SUCCESS)
+				priv->ibwc[i].status = IB_WC_WR_FLUSH_ERR;
+
 			if (priv->ibwc[i].wr_id & IPOIB_CM_OP_SRQ)
 				ipoib_cm_handle_rx_wc(dev, priv->ibwc + i);
 			else if (priv->ibwc[i].wr_id & IPOIB_OP_RECV)
@@ -577,7 +580,6 @@
 	int i;
 
 	clear_bit(IPOIB_FLAG_INITIALIZED, &priv->flags);
-	netif_poll_disable(dev);
 
 	ipoib_cm_dev_stop(dev);
 
@@ -660,7 +662,6 @@
 		msleep(1);
 	}
 
-	netif_poll_enable(dev);
 	ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP);
 
 	return 0;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 894b1dcd..e072f3c 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -98,16 +98,20 @@
 
 	ipoib_dbg(priv, "bringing up interface\n");
 
+	napi_enable(&priv->napi);
 	set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags);
 
 	if (ipoib_pkey_dev_delay_open(dev))
 		return 0;
 
-	if (ipoib_ib_dev_open(dev))
+	if (ipoib_ib_dev_open(dev)) {
+		napi_disable(&priv->napi);
 		return -EINVAL;
+	}
 
 	if (ipoib_ib_dev_up(dev)) {
 		ipoib_ib_dev_stop(dev, 1);
+		napi_disable(&priv->napi);
 		return -EINVAL;
 	}
 
@@ -140,6 +144,7 @@
 	ipoib_dbg(priv, "stopping interface\n");
 
 	clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags);
+	napi_disable(&priv->napi);
 
 	netif_stop_queue(dev);
 
@@ -468,9 +473,10 @@
 	INIT_LIST_HEAD(&path->neigh_list);
 
 	memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid));
-	path->pathrec.sgid      = priv->local_gid;
-	path->pathrec.pkey      = cpu_to_be16(priv->pkey);
-	path->pathrec.numb_path = 1;
+	path->pathrec.sgid          = priv->local_gid;
+	path->pathrec.pkey          = cpu_to_be16(priv->pkey);
+	path->pathrec.numb_path     = 1;
+	path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class;
 
 	return path;
 }
@@ -491,6 +497,7 @@
 				   IB_SA_PATH_REC_DGID		|
 				   IB_SA_PATH_REC_SGID		|
 				   IB_SA_PATH_REC_NUMB_PATH	|
+				   IB_SA_PATH_REC_TRAFFIC_CLASS |
 				   IB_SA_PATH_REC_PKEY,
 				   1000, GFP_ATOMIC,
 				   path_rec_completion,
@@ -512,7 +519,7 @@
 
 	neigh = ipoib_neigh_alloc(skb->dst->neighbour);
 	if (!neigh) {
-		++priv->stats.tx_dropped;
+		++dev->stats.tx_dropped;
 		dev_kfree_skb_any(skb);
 		return;
 	}
@@ -577,7 +584,7 @@
 err_path:
 	ipoib_neigh_free(dev, neigh);
 err_drop:
-	++priv->stats.tx_dropped;
+	++dev->stats.tx_dropped;
 	dev_kfree_skb_any(skb);
 
 	spin_unlock(&priv->lock);
@@ -626,7 +633,7 @@
 			} else
 				__path_add(dev, path);
 		} else {
-			++priv->stats.tx_dropped;
+			++dev->stats.tx_dropped;
 			dev_kfree_skb_any(skb);
 		}
 
@@ -645,7 +652,7 @@
 		skb_push(skb, sizeof *phdr);
 		__skb_queue_tail(&path->queue, skb);
 	} else {
-		++priv->stats.tx_dropped;
+		++dev->stats.tx_dropped;
 		dev_kfree_skb_any(skb);
 	}
 
@@ -713,7 +720,7 @@
 			__skb_queue_tail(&neigh->queue, skb);
 			spin_unlock(&priv->lock);
 		} else {
-			++priv->stats.tx_dropped;
+			++dev->stats.tx_dropped;
 			dev_kfree_skb_any(skb);
 		}
 	} else {
@@ -739,7 +746,7 @@
 					   IPOIB_QPN(phdr->hwaddr),
 					   IPOIB_GID_RAW_ARG(phdr->hwaddr + 4));
 				dev_kfree_skb_any(skb);
-				++priv->stats.tx_dropped;
+				++dev->stats.tx_dropped;
 				goto out;
 			}
 
@@ -753,13 +760,6 @@
 	return NETDEV_TX_OK;
 }
 
-static struct net_device_stats *ipoib_get_stats(struct net_device *dev)
-{
-	struct ipoib_dev_priv *priv = netdev_priv(dev);
-
-	return &priv->stats;
-}
-
 static void ipoib_timeout(struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -775,7 +775,7 @@
 static int ipoib_hard_header(struct sk_buff *skb,
 			     struct net_device *dev,
 			     unsigned short type,
-			     void *daddr, void *saddr, unsigned len)
+			     const void *daddr, const void *saddr, unsigned len)
 {
 	struct ipoib_header *header;
 
@@ -856,11 +856,10 @@
 
 void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh)
 {
-	struct ipoib_dev_priv *priv = netdev_priv(dev);
 	struct sk_buff *skb;
 	*to_ipoib_neigh(neigh->neighbour) = NULL;
 	while ((skb = __skb_dequeue(&neigh->queue))) {
-		++priv->stats.tx_dropped;
+		++dev->stats.tx_dropped;
 		dev_kfree_skb_any(skb);
 	}
 	if (ipoib_cm_get(neigh))
@@ -935,6 +934,10 @@
 	priv->tx_ring = NULL;
 }
 
+static const struct header_ops ipoib_header_ops = {
+	.create	= ipoib_hard_header,
+};
+
 static void ipoib_setup(struct net_device *dev)
 {
 	struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -943,13 +946,12 @@
 	dev->stop 		 = ipoib_stop;
 	dev->change_mtu 	 = ipoib_change_mtu;
 	dev->hard_start_xmit 	 = ipoib_start_xmit;
-	dev->get_stats 		 = ipoib_get_stats;
 	dev->tx_timeout 	 = ipoib_timeout;
-	dev->hard_header 	 = ipoib_hard_header;
+	dev->header_ops 	 = &ipoib_header_ops;
 	dev->set_multicast_list  = ipoib_set_mcast_list;
 	dev->neigh_setup         = ipoib_neigh_setup_dev;
-	dev->poll                = ipoib_poll;
-	dev->weight              = 100;
+
+	netif_napi_add(dev, &priv->napi, ipoib_poll, 100);
 
 	dev->watchdog_timeo 	 = HZ;
 
@@ -973,8 +975,6 @@
 
 	netif_carrier_off(dev);
 
-	SET_MODULE_OWNER(dev);
-
 	priv->dev = dev;
 
 	spin_lock_init(&priv->lock);
@@ -1017,6 +1017,37 @@
 }
 static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
 
+static ssize_t show_umcast(struct device *dev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev));
+
+	return sprintf(buf, "%d\n", test_bit(IPOIB_FLAG_UMCAST, &priv->flags));
+}
+
+static ssize_t set_umcast(struct device *dev,
+			  struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev));
+	unsigned long umcast_val = simple_strtoul(buf, NULL, 0);
+
+	if (umcast_val > 0) {
+		set_bit(IPOIB_FLAG_UMCAST, &priv->flags);
+		ipoib_warn(priv, "ignoring multicast groups joined directly "
+				"by userspace\n");
+	} else
+		clear_bit(IPOIB_FLAG_UMCAST, &priv->flags);
+
+	return count;
+}
+static DEVICE_ATTR(umcast, S_IWUSR | S_IRUGO, show_umcast, set_umcast);
+
+int ipoib_add_umcast_attr(struct net_device *dev)
+{
+	return device_create_file(&dev->dev, &dev_attr_umcast);
+}
+
 static ssize_t create_child(struct device *dev,
 			    struct device_attribute *attr,
 			    const char *buf, size_t count)
@@ -1083,7 +1114,7 @@
 	if (result) {
 		printk(KERN_WARNING "%s: ib_query_pkey port %d failed (ret = %d)\n",
 		       hca->name, port, result);
-		goto alloc_mem_failed;
+		goto device_init_failed;
 	}
 
 	/*
@@ -1099,7 +1130,7 @@
 	if (result) {
 		printk(KERN_WARNING "%s: ib_query_gid port %d failed (ret = %d)\n",
 		       hca->name, port, result);
-		goto alloc_mem_failed;
+		goto device_init_failed;
 	} else
 		memcpy(priv->dev->dev_addr + 4, priv->local_gid.raw, sizeof (union ib_gid));
 
@@ -1134,6 +1165,8 @@
 		goto sysfs_failed;
 	if (ipoib_add_pkey_attr(priv->dev))
 		goto sysfs_failed;
+	if (ipoib_add_umcast_attr(priv->dev))
+		goto sysfs_failed;
 	if (device_create_file(&priv->dev->dev, &dev_attr_create_child))
 		goto sysfs_failed;
 	if (device_create_file(&priv->dev->dev, &dev_attr_delete_child))
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index aae3670..827820e 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -57,28 +57,6 @@
 
 static DEFINE_MUTEX(mcast_mutex);
 
-/* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */
-struct ipoib_mcast {
-	struct ib_sa_mcmember_rec mcmember;
-	struct ib_sa_multicast	 *mc;
-	struct ipoib_ah          *ah;
-
-	struct rb_node    rb_node;
-	struct list_head  list;
-
-	unsigned long created;
-	unsigned long backoff;
-
-	unsigned long flags;
-	unsigned char logcount;
-
-	struct list_head  neigh_list;
-
-	struct sk_buff_head pkt_queue;
-
-	struct net_device *dev;
-};
-
 struct ipoib_mcast_iter {
 	struct net_device *dev;
 	union ib_gid       mgid;
@@ -125,7 +103,7 @@
 	}
 
 	spin_lock_irqsave(&priv->tx_lock, flags);
-	priv->stats.tx_dropped += tx_dropped;
+	dev->stats.tx_dropped += tx_dropped;
 	spin_unlock_irqrestore(&priv->tx_lock, flags);
 
 	kfree(mcast);
@@ -320,7 +298,7 @@
 		/* Flush out any queued packets */
 		spin_lock_irq(&priv->tx_lock);
 		while (!skb_queue_empty(&mcast->pkt_queue)) {
-			++priv->stats.tx_dropped;
+			++dev->stats.tx_dropped;
 			dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
 		}
 		spin_unlock_irq(&priv->tx_lock);
@@ -675,7 +653,7 @@
 	if (!test_bit(IPOIB_MCAST_STARTED, &priv->flags)	||
 	    !priv->broadcast					||
 	    !test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) {
-		++priv->stats.tx_dropped;
+		++dev->stats.tx_dropped;
 		dev_kfree_skb_any(skb);
 		goto unlock;
 	}
@@ -690,7 +668,7 @@
 		if (!mcast) {
 			ipoib_warn(priv, "unable to allocate memory for "
 				   "multicast structure\n");
-			++priv->stats.tx_dropped;
+			++dev->stats.tx_dropped;
 			dev_kfree_skb_any(skb);
 			goto out;
 		}
@@ -705,7 +683,7 @@
 		if (skb_queue_len(&mcast->pkt_queue) < IPOIB_MAX_MCAST_QUEUE)
 			skb_queue_tail(&mcast->pkt_queue, skb);
 		else {
-			++priv->stats.tx_dropped;
+			++dev->stats.tx_dropped;
 			dev_kfree_skb_any(skb);
 		}
 
@@ -783,6 +761,7 @@
 	struct ipoib_mcast *mcast, *tmcast;
 	LIST_HEAD(remove_list);
 	unsigned long flags;
+	struct ib_sa_mcmember_rec rec;
 
 	ipoib_dbg_mcast(priv, "restarting multicast task\n");
 
@@ -816,6 +795,14 @@
 		if (!mcast || test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) {
 			struct ipoib_mcast *nmcast;
 
+			/* ignore group which is directly joined by userspace */
+			if (test_bit(IPOIB_FLAG_UMCAST, &priv->flags) &&
+			    !ib_sa_get_mcmember_rec(priv->ca, priv->port, &mgid, &rec)) {
+				ipoib_dbg_mcast(priv, "ignoring multicast entry for mgid "
+						IPOIB_GID_FMT "\n", IPOIB_GID_ARG(mgid));
+				continue;
+			}
+
 			/* Not found or send-only group, let's add a new entry */
 			ipoib_dbg_mcast(priv, "adding multicast entry for mgid "
 					IPOIB_GID_FMT "\n", IPOIB_GID_ARG(mgid));
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index 982eb88..3c6e45d 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -185,7 +185,7 @@
 		goto out_free_cq;
 
 	init_attr.send_cq = priv->cq;
-	init_attr.recv_cq = priv->cq,
+	init_attr.recv_cq = priv->cq;
 
 	priv->qp = ib_create_qp(priv->pd, &init_attr);
 	if (IS_ERR(priv->qp)) {
@@ -211,6 +211,7 @@
 
 out_free_mr:
 	ib_dereg_mr(priv->mr);
+	ipoib_cm_dev_cleanup(dev);
 
 out_free_pd:
 	ib_dealloc_pd(priv->pd);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index 6762988..293f5b8 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -119,6 +119,8 @@
 		goto sysfs_failed;
 	if (ipoib_add_pkey_attr(priv->dev))
 		goto sysfs_failed;
+	if (ipoib_add_umcast_attr(priv->dev))
+		goto sysfs_failed;
 
 	if (device_create_file(&priv->dev->dev, &dev_attr_parent))
 		goto sysfs_failed;
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index effdee2..bad8dac 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -548,6 +548,7 @@
 }
 
 static struct scsi_host_template iscsi_iser_sht = {
+	.module                 = THIS_MODULE,
 	.name                   = "iSCSI Initiator over iSER, v." DRV_VER,
 	.queuecommand           = iscsi_queuecommand,
 	.can_queue		= ISCSI_DEF_XMIT_CMDS_MAX - 1,
@@ -637,7 +638,7 @@
 	ig.desc_cache = kmem_cache_create("iser_descriptors",
 					  sizeof (struct iser_desc),
 					  0, SLAB_HWCACHE_ALIGN,
-					  NULL, NULL);
+					  NULL);
 	if (ig.desc_cache == NULL)
 		return -ENOMEM;
 
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index e235370..1ee867b 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -310,8 +310,6 @@
 
 void iser_conn_terminate(struct iser_conn *ib_conn);
 
-void iser_conn_release(struct iser_conn *ib_conn);
-
 void iser_rcv_completion(struct iser_desc *desc,
 			 unsigned long    dto_xfer_len);
 
@@ -329,9 +327,6 @@
 		     struct iser_regd_buf    *regd_buf,
 		     enum dma_data_direction direction);
 
-int  iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task    *ctask,
-				  enum iser_data_dir            cmd_dir);
-
 void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *ctask,
 				     enum iser_data_dir         cmd_dir);
 
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 9ea5b9a..a6f2303 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -34,8 +34,6 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
-#include <asm/io.h>
-#include <asm/scatterlist.h>
 #include <linux/scatterlist.h>
 #include <linux/kfifo.h>
 #include <scsi/scsi_cmnd.h>
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
index fc9f1fd..e05690e 100644
--- a/drivers/infiniband/ulp/iser/iser_memory.c
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -36,8 +36,6 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/highmem.h>
-#include <asm/io.h>
-#include <asm/scatterlist.h>
 #include <linux/scatterlist.h>
 
 #include "iscsi_iser.h"
@@ -103,8 +101,8 @@
 /**
  * iser_start_rdma_unaligned_sg
  */
-int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task  *iser_ctask,
-				 enum iser_data_dir cmd_dir)
+static int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
+					enum iser_data_dir cmd_dir)
 {
 	int dma_nents;
 	struct ib_device *dev;
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 2044de1..654a4dc 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -32,7 +32,6 @@
  *
  * $Id: iser_verbs.c 7051 2006-05-10 12:29:11Z ogerlitz $
  */
-#include <asm/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -311,6 +310,29 @@
 }
 
 /**
+ * Frees all conn objects and deallocs conn descriptor
+ */
+static void iser_conn_release(struct iser_conn *ib_conn)
+{
+	struct iser_device  *device = ib_conn->device;
+
+	BUG_ON(ib_conn->state != ISER_CONN_DOWN);
+
+	mutex_lock(&ig.connlist_mutex);
+	list_del(&ib_conn->conn_list);
+	mutex_unlock(&ig.connlist_mutex);
+
+	iser_free_ib_conn_res(ib_conn);
+	ib_conn->device = NULL;
+	/* on EVENT_ADDR_ERROR there's no device yet for this conn */
+	if (device != NULL)
+		iser_device_try_release(device);
+	if (ib_conn->iser_conn)
+		ib_conn->iser_conn->ib_conn = NULL;
+	kfree(ib_conn);
+}
+
+/**
  * triggers start of the disconnect procedures and wait for them to be done
  */
 void iser_conn_terminate(struct iser_conn *ib_conn)
@@ -550,30 +572,6 @@
 }
 
 /**
- * Frees all conn objects and deallocs conn descriptor
- */
-void iser_conn_release(struct iser_conn *ib_conn)
-{
-	struct iser_device  *device = ib_conn->device;
-
-	BUG_ON(ib_conn->state != ISER_CONN_DOWN);
-
-	mutex_lock(&ig.connlist_mutex);
-	list_del(&ib_conn->conn_list);
-	mutex_unlock(&ig.connlist_mutex);
-
-	iser_free_ib_conn_res(ib_conn);
-	ib_conn->device = NULL;
-	/* on EVENT_ADDR_ERROR there's no device yet for this conn */
-	if (device != NULL)
-		iser_device_try_release(device);
-	if (ib_conn->iser_conn)
-		ib_conn->iser_conn->ib_conn = NULL;
-	kfree(ib_conn);
-}
-
-
-/**
  * iser_reg_page_vec - Register physical memory
  *
  * returns: 0 on success, errno code on failure
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index f01ca18..9ccc638 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -75,16 +75,12 @@
 MODULE_PARM_DESC(topspin_workarounds,
 		 "Enable workarounds for Topspin/Cisco SRP target bugs if != 0");
 
-static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad };
-
 static int mellanox_workarounds = 1;
 
 module_param(mellanox_workarounds, int, 0444);
 MODULE_PARM_DESC(mellanox_workarounds,
 		 "Enable workarounds for Mellanox SRP target bugs if != 0");
 
-static const u8 mellanox_oui[3] = { 0x00, 0x02, 0xc9 };
-
 static void srp_add_one(struct ib_device *device);
 static void srp_remove_one(struct ib_device *device);
 static void srp_completion(struct ib_cq *cq, void *target_ptr);
@@ -108,6 +104,24 @@
 	return host_to_target(host)->target_name;
 }
 
+static int srp_target_is_topspin(struct srp_target_port *target)
+{
+	static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad };
+	static const u8 cisco_oui[3]   = { 0x00, 0x1b, 0x0d };
+
+	return topspin_workarounds &&
+		(!memcmp(&target->ioc_guid, topspin_oui, sizeof topspin_oui) ||
+		 !memcmp(&target->ioc_guid, cisco_oui, sizeof cisco_oui));
+}
+
+static int srp_target_is_mellanox(struct srp_target_port *target)
+{
+	static const u8 mellanox_oui[3] = { 0x00, 0x02, 0xc9 };
+
+	return mellanox_workarounds &&
+		!memcmp(&target->ioc_guid, mellanox_oui, sizeof mellanox_oui);
+}
+
 static struct srp_iu *srp_alloc_iu(struct srp_host *host, size_t size,
 				   gfp_t gfp_mask,
 				   enum dma_data_direction direction)
@@ -271,6 +285,7 @@
 						   target->srp_host->dev->dev,
 						   target->srp_host->port,
 						   &target->path,
+						   IB_SA_PATH_REC_SERVICE_ID	|
 						   IB_SA_PATH_REC_DGID		|
 						   IB_SA_PATH_REC_SGID		|
 						   IB_SA_PATH_REC_NUMB_PATH	|
@@ -360,7 +375,7 @@
 	 * zero out the first 8 bytes of our initiator port ID and set
 	 * the second 8 bytes to the local node GUID.
 	 */
-	if (topspin_workarounds && !memcmp(&target->ioc_guid, topspin_oui, 3)) {
+	if (srp_target_is_topspin(target)) {
 		printk(KERN_DEBUG PFX "Topspin/Cisco initiator port ID workaround "
 		       "activated for target GUID %016llx\n",
 		       (unsigned long long) be64_to_cpu(target->ioc_guid));
@@ -585,8 +600,8 @@
 	if (!dev->fmr_pool)
 		return -ENODEV;
 
-	if ((ib_sg_dma_address(ibdev, &scat[0]) & ~dev->fmr_page_mask) &&
-	    mellanox_workarounds && !memcmp(&target->ioc_guid, mellanox_oui, 3))
+	if (srp_target_is_mellanox(target) &&
+	    (ib_sg_dma_address(ibdev, &scat[0]) & ~dev->fmr_page_mask))
 		return -EINVAL;
 
 	len = page_cnt = 0;
@@ -1087,8 +1102,7 @@
 		break;
 
 	case IB_CM_REJ_PORT_REDIRECT:
-		if (topspin_workarounds &&
-		    !memcmp(&target->ioc_guid, topspin_oui, 3)) {
+		if (srp_target_is_topspin(target)) {
 			/*
 			 * Topspin/Cisco SRP gateways incorrectly send
 			 * reject reason code 25 when they mean 24
@@ -1679,6 +1693,7 @@
 				goto out;
 			}
 			target->service_id = cpu_to_be64(simple_strtoull(p, NULL, 16));
+			target->path.service_id = target->service_id;
 			kfree(p);
 			break;
 
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index d404aa8..27026f7 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -312,7 +312,7 @@
 #elif defined(CONFIG_S390)
 #  define COMPAT_TEST test_thread_flag(TIF_31BIT)
 #elif defined(CONFIG_MIPS)
-#  define COMPAT_TEST (current->thread.mflags & MF_32BIT_ADDR)
+#  define COMPAT_TEST test_thread_flag(TIF_32BIT_ADDR)
 #else
 #  define COMPAT_TEST test_thread_flag(TIF_32BIT)
 #endif
diff --git a/drivers/input/input.c b/drivers/input/input.c
index c59544f..3070c7a 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -1067,87 +1067,66 @@
  * Input uevent interface - loading event handlers based on
  * device bitfields.
  */
-static int input_add_uevent_bm_var(char **envp, int num_envp, int *cur_index,
-				   char *buffer, int buffer_size, int *cur_len,
+static int input_add_uevent_bm_var(struct kobj_uevent_env *env,
 				   const char *name, unsigned long *bitmap, int max)
 {
-	if (*cur_index >= num_envp - 1)
+	int len;
+
+	if (add_uevent_var(env, "%s=", name))
 		return -ENOMEM;
 
-	envp[*cur_index] = buffer + *cur_len;
-
-	*cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0), name);
-	if (*cur_len >= buffer_size)
+	len = input_print_bitmap(&env->buf[env->buflen - 1],
+				 sizeof(env->buf) - env->buflen,
+				 bitmap, max, 0);
+	if (len >= (sizeof(env->buf) - env->buflen))
 		return -ENOMEM;
 
-	*cur_len += input_print_bitmap(buffer + *cur_len,
-					max(buffer_size - *cur_len, 0),
-					bitmap, max, 0) + 1;
-	if (*cur_len > buffer_size)
-		return -ENOMEM;
-
-	(*cur_index)++;
+	env->buflen += len;
 	return 0;
 }
 
-static int input_add_uevent_modalias_var(char **envp, int num_envp, int *cur_index,
-					 char *buffer, int buffer_size, int *cur_len,
+static int input_add_uevent_modalias_var(struct kobj_uevent_env *env,
 					 struct input_dev *dev)
 {
-	if (*cur_index >= num_envp - 1)
+	int len;
+
+	if (add_uevent_var(env, "MODALIAS="))
 		return -ENOMEM;
 
-	envp[*cur_index] = buffer + *cur_len;
-
-	*cur_len += snprintf(buffer + *cur_len, max(buffer_size - *cur_len, 0),
-			     "MODALIAS=");
-	if (*cur_len >= buffer_size)
+	len = input_print_modalias(&env->buf[env->buflen - 1],
+				   sizeof(env->buf) - env->buflen,
+				   dev, 0);
+	if (len >= (sizeof(env->buf) - env->buflen))
 		return -ENOMEM;
 
-	*cur_len += input_print_modalias(buffer + *cur_len,
-					 max(buffer_size - *cur_len, 0),
-					 dev, 0) + 1;
-	if (*cur_len > buffer_size)
-		return -ENOMEM;
-
-	(*cur_index)++;
+	env->buflen += len;
 	return 0;
 }
 
 #define INPUT_ADD_HOTPLUG_VAR(fmt, val...)				\
 	do {								\
-		int err = add_uevent_var(envp, num_envp, &i,		\
-					buffer, buffer_size, &len,	\
-					fmt, val);			\
+		int err = add_uevent_var(env, fmt, val);		\
 		if (err)						\
 			return err;					\
 	} while (0)
 
 #define INPUT_ADD_HOTPLUG_BM_VAR(name, bm, max)				\
 	do {								\
-		int err = input_add_uevent_bm_var(envp, num_envp, &i,	\
-					buffer, buffer_size, &len,	\
-					name, bm, max);			\
+		int err = input_add_uevent_bm_var(env, name, bm, max);	\
 		if (err)						\
 			return err;					\
 	} while (0)
 
 #define INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev)				\
 	do {								\
-		int err = input_add_uevent_modalias_var(envp,		\
-					num_envp, &i,			\
-					buffer, buffer_size, &len,	\
-					dev);				\
+		int err = input_add_uevent_modalias_var(env, dev);	\
 		if (err)						\
 			return err;					\
 	} while (0)
 
-static int input_dev_uevent(struct device *device, char **envp,
-			    int num_envp, char *buffer, int buffer_size)
+static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env)
 {
 	struct input_dev *dev = to_input_dev(device);
-	int i = 0;
-	int len = 0;
 
 	INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x",
 				dev->id.bustype, dev->id.vendor,
@@ -1179,7 +1158,6 @@
 
 	INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev);
 
-	envp[i] = NULL;
 	return 0;
 }
 
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
index 3154ccd..45c4939 100644
--- a/drivers/input/joystick/iforce/iforce-packets.c
+++ b/drivers/input/joystick/iforce/iforce-packets.c
@@ -246,13 +246,12 @@
 
 int iforce_get_id_packet(struct iforce *iforce, char *packet)
 {
-	int status;
-
 	switch (iforce->bus) {
 
-	case IFORCE_USB:
-
+	case IFORCE_USB: {
 #ifdef CONFIG_JOYSTICK_IFORCE_USB
+		int status;
+
 		iforce->cr.bRequest = packet[0];
 		iforce->ctrl->dev = iforce->usbdev;
 
@@ -273,6 +272,7 @@
 #else
 		dbg("iforce_get_id_packet: iforce->bus = USB!");
 #endif
+		}
 		break;
 
 	case IFORCE_232:
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 3d6820b..e2a3293 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -22,7 +22,6 @@
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/input.h>
-#include <linux/irq.h>
 #include <linux/gpio_keys.h>
 
 #include <asm/gpio.h>
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 9b26574..d602b8f 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -68,6 +68,7 @@
 	select INPUT_POLLDEV
 	select NEW_LEDS
 	select LEDS_CLASS
+	select CHECK_SIGNATURE
 	help
 	  Say Y here for support of Winstron laptop button interface, used on
 	  laptops of various brands, including Acer and Fujitsu-Siemens. If
diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c
index 0acc3a1..e43e92f 100644
--- a/drivers/input/misc/atlas_btns.c
+++ b/drivers/input/misc/atlas_btns.c
@@ -31,7 +31,6 @@
 
 #define ACPI_ATLAS_NAME			"Atlas ACPI"
 #define ACPI_ATLAS_CLASS		"Atlas"
-#define ACPI_ATLAS_BUTTON_HID		"ASIM0000"
 
 static struct input_dev *input_dev;
 
@@ -130,10 +129,16 @@
 	return status;
 }
 
+static const struct acpi_device_id atlas_device_ids[] = {
+	{"ASIM0000", 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, atlas_device_ids);
+
 static struct acpi_driver atlas_acpi_driver = {
 	.name	= ACPI_ATLAS_NAME,
 	.class	= ACPI_ATLAS_CLASS,
-	.ids	= ACPI_ATLAS_BUTTON_HID,
+	.ids	= atlas_device_ids,
 	.ops	= {
 		.add	= atlas_acpi_button_add,
 		.remove	= atlas_acpi_button_remove,
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index 31989dc..c19f77f 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -17,14 +17,20 @@
 #include <linux/init.h>
 #include <linux/input.h>
 #include <linux/platform_device.h>
-#include <asm/8253pit.h>
 #include <asm/io.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("PC Speaker beeper driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pcspkr");
 
-static DEFINE_SPINLOCK(i8253_beep_lock);
+#ifdef CONFIG_X86
+/* Use the global PIT lock ! */
+#include <asm/i8253.h>
+#else
+#include <asm/8253pit.h>
+static DEFINE_SPINLOCK(i8253_lock);
+#endif
 
 static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
 {
@@ -43,7 +49,7 @@
 	if (value > 20 && value < 32767)
 		count = PIT_TICK_RATE / value;
 
-	spin_lock_irqsave(&i8253_beep_lock, flags);
+	spin_lock_irqsave(&i8253_lock, flags);
 
 	if (count) {
 		/* enable counter 2 */
@@ -58,7 +64,7 @@
 		outb(inb_p(0x61) & 0xFC, 0x61);
 	}
 
-	spin_unlock_irqrestore(&i8253_beep_lock, flags);
+	spin_unlock_irqrestore(&i8253_lock, flags);
 
 	return 0;
 }
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index 60121f1..b438d99 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -247,7 +247,7 @@
 static int have_bluetooth;
 static int have_leds;
 
-static int __init dmi_matched(struct dmi_system_id *dmi)
+static int __init dmi_matched(const struct dmi_system_id *dmi)
 {
 	const struct key_entry *key;
 
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index e321526..a1804bf 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -155,6 +155,8 @@
 	int			xy_acc[ATP_XSENSORS + ATP_YSENSORS];
 	int			overflowwarn;	/* overflow warning printed? */
 	int			datalen;	/* size of an USB urb transfer */
+	int			idlecount;      /* number of empty packets */
+	struct work_struct      work;
 };
 
 #define dbg_dump(msg, tab) \
@@ -208,6 +210,55 @@
 		(productId == GEYSER4_JIS_PRODUCT_ID);
 }
 
+/*
+ * By default Geyser 3 device sends standard USB HID mouse
+ * packets (Report ID 2). This code changes device mode, so it
+ * sends raw sensor reports (Report ID 5).
+ */
+static int atp_geyser3_init(struct usb_device *udev)
+{
+	char data[8];
+	int size;
+
+	size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+			ATP_GEYSER3_MODE_READ_REQUEST_ID,
+			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			ATP_GEYSER3_MODE_REQUEST_VALUE,
+			ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+	if (size != 8) {
+		err("Could not do mode read request from device"
+		    " (Geyser 3 mode)");
+		return -EIO;
+	}
+
+	/* Apply the mode switch */
+	data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
+
+	size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
+			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+			ATP_GEYSER3_MODE_REQUEST_VALUE,
+			ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
+
+	if (size != 8) {
+		err("Could not do mode write request to device"
+		    " (Geyser 3 mode)");
+		return -EIO;
+	}
+	return 0;
+}
+
+/* Reinitialise the device if it's a geyser 3 */
+static void atp_reinit(struct work_struct *work)
+{
+	struct atp *dev = container_of(work, struct atp, work);
+	struct usb_device *udev = dev->udev;
+
+	dev->idlecount = 0;
+	atp_geyser3_init(udev);
+}
+
 static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact,
 			     int *z, int *fingers)
 {
@@ -277,6 +328,7 @@
 {
 	int x, y, x_z, y_z, x_f, y_f;
 	int retval, i, j;
+	int key;
 	struct atp *dev = urb->context;
 
 	switch (urb->status) {
@@ -417,6 +469,7 @@
 			      ATP_XFACT, &x_z, &x_f);
 	y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
 			      ATP_YFACT, &y_z, &y_f);
+	key = dev->data[dev->datalen - 1] & 1;
 
 	if (x && y) {
 		if (dev->x_old != -1) {
@@ -439,8 +492,8 @@
 		}
 		dev->x_old = x;
 		dev->y_old = y;
-	}
-	else if (!x && !y) {
+
+	} else if (!x && !y) {
 
 		dev->x_old = dev->y_old = -1;
 		input_report_key(dev->input, BTN_TOUCH, 0);
@@ -449,11 +502,21 @@
 
 		/* reset the accumulator on release */
 		memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
+
+		/* Geyser 3 will continue to send packets continually after
+		   the first touch unless reinitialised. Do so if it's been
+		   idle for a while in order to avoid waking the kernel up
+		   several hundred times a second */
+		if (!key && atp_is_geyser_3(dev)) {
+			dev->idlecount++;
+			if (dev->idlecount == 10) {
+				dev->valid = 0;
+				schedule_work(&dev->work);
+			}
+		}
 	}
 
-	input_report_key(dev->input, BTN_LEFT,
-			 !!dev->data[dev->datalen - 1]);
-
+	input_report_key(dev->input, BTN_LEFT, key);
 	input_sync(dev->input);
 
 exit:
@@ -480,6 +543,7 @@
 	struct atp *dev = input_get_drvdata(input);
 
 	usb_kill_urb(dev->urb);
+	cancel_work_sync(&dev->work);
 	dev->open = 0;
 }
 
@@ -528,40 +592,10 @@
 		dev->datalen = 81;
 
 	if (atp_is_geyser_3(dev)) {
-		/*
-		 * By default Geyser 3 device sends standard USB HID mouse
-		 * packets (Report ID 2). This code changes device mode, so it
-		 * sends raw sensor reports (Report ID 5).
-		 */
-		char data[8];
-		int size;
-
-		size = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-			ATP_GEYSER3_MODE_READ_REQUEST_ID,
-			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-			ATP_GEYSER3_MODE_REQUEST_VALUE,
-			ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
-
-		if (size != 8) {
-			err("Could not do mode read request from device"
-							" (Geyser 3 mode)");
+		/* switch to raw sensor mode */
+		if (atp_geyser3_init(udev))
 			goto err_free_devs;
-		}
 
-		/* Apply the mode switch */
-		data[0] = ATP_GEYSER3_MODE_VENDOR_VALUE;
-
-		size = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
-			ATP_GEYSER3_MODE_WRITE_REQUEST_ID,
-			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-			ATP_GEYSER3_MODE_REQUEST_VALUE,
-			ATP_GEYSER3_MODE_REQUEST_INDEX, &data, 8, 5000);
-
-		if (size != 8) {
-			err("Could not do mode write request to device"
-							" (Geyser 3 mode)");
-			goto err_free_devs;
-		}
 		printk("appletouch Geyser 3 inited.\n");
 	}
 
@@ -636,6 +670,8 @@
 	/* save our data pointer in this interface device */
 	usb_set_intfdata(iface, dev);
 
+	INIT_WORK(&dev->work, atp_reinit);
+
 	return 0;
 
  err_free_buffer:
@@ -669,14 +705,17 @@
 static int atp_suspend(struct usb_interface *iface, pm_message_t message)
 {
 	struct atp *dev = usb_get_intfdata(iface);
+
 	usb_kill_urb(dev->urb);
 	dev->valid = 0;
+
 	return 0;
 }
 
 static int atp_resume(struct usb_interface *iface)
 {
 	struct atp *dev = usb_get_intfdata(iface);
+
 	if (dev->open && usb_submit_urb(dev->urb, GFP_ATOMIC))
 		return -EIO;
 
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index 9561dee..d7de4c5 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -27,7 +27,7 @@
 
 static const char *desired_serio_phys;
 
-static int lifebook_set_serio_phys(struct dmi_system_id *d)
+static int lifebook_set_serio_phys(const struct dmi_system_id *d)
 {
 	desired_serio_phys = d->driver_data;
 	return 0;
@@ -35,13 +35,13 @@
 
 static unsigned char lifebook_use_6byte_proto;
 
-static int lifebook_set_6byte_proto(struct dmi_system_id *d)
+static int lifebook_set_6byte_proto(const struct dmi_system_id *d)
 {
 	lifebook_use_6byte_proto = 1;
 	return 0;
 }
 
-static struct dmi_system_id lifebook_dmi_table[] = {
+static const struct dmi_system_id lifebook_dmi_table[] = {
 	{
 		.ident = "FLORA-ie 55mi",
 		.matches = {
@@ -117,7 +117,7 @@
 {
 	struct lifebook_data *priv = psmouse->private;
 	struct input_dev *dev1 = psmouse->dev;
-	struct input_dev *dev2 = priv->dev2;
+	struct input_dev *dev2 = priv ? priv->dev2 : NULL;
 	unsigned char *packet = psmouse->packet;
 	int relative_packet = packet[0] & 0x08;
 
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 666ad3a..d349c4a5e 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -602,7 +602,7 @@
 
 #if defined(__i386__)
 #include <linux/dmi.h>
-static struct dmi_system_id toshiba_dmi_table[] = {
+static const struct dmi_system_id toshiba_dmi_table[] = {
 	{
 		.ident = "Toshiba Satellite",
 		.matches = {
diff --git a/drivers/input/mouse/touchkit_ps2.h b/drivers/input/mouse/touchkit_ps2.h
index 61e9dfd..8a0dd35 100644
--- a/drivers/input/mouse/touchkit_ps2.h
+++ b/drivers/input/mouse/touchkit_ps2.h
@@ -15,7 +15,8 @@
 #ifdef CONFIG_MOUSE_PS2_TOUCHKIT
 int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties);
 #else
-inline int touchkit_ps2_detect(struct psmouse *psmouse, int set_properties)
+static inline int touchkit_ps2_detect(struct psmouse *psmouse,
+				      int set_properties)
 {
 	return -ENOSYS;
 }
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index adef447..5ce632c 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -21,7 +21,7 @@
 config SERIO_I8042
 	tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
 	default y
-	depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && !M68K
+	depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && !M68K && !BFIN
 	---help---
 	  i8042 is the chip over which the standard AT keyboard and PS/2
 	  mouse are connected to the computer. If you use these devices,
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
index 5a7b49c..b10ffae 100644
--- a/drivers/input/serio/ambakmi.c
+++ b/drivers/input/serio/ambakmi.c
@@ -117,15 +117,13 @@
 	if (ret)
 		return ret;
 
-	kmi = kmalloc(sizeof(struct amba_kmi_port), GFP_KERNEL);
-	io = kmalloc(sizeof(struct serio), GFP_KERNEL);
+	kmi = kzalloc(sizeof(struct amba_kmi_port), GFP_KERNEL);
+	io = kzalloc(sizeof(struct serio), GFP_KERNEL);
 	if (!kmi || !io) {
 		ret = -ENOMEM;
 		goto out;
 	}
 
-	memset(kmi, 0, sizeof(struct amba_kmi_port));
-	memset(io, 0, sizeof(struct serio));
 
 	io->id.type	= SERIO_8042;
 	io->write	= amba_kmi_write;
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index 74f14e0..3e99df6 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -340,8 +340,8 @@
 	if (dev->id.sversion == 0x96)
 		hpa += GSC_DINO_OFFSET;
 
-	ps2port = kmalloc(sizeof(struct gscps2port), GFP_KERNEL);
-	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+	ps2port = kzalloc(sizeof(struct gscps2port), GFP_KERNEL);
+	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
 	if (!ps2port || !serio) {
 		ret = -ENOMEM;
 		goto fail_nomem;
@@ -349,8 +349,6 @@
 
 	dev_set_drvdata(&dev->dev, ps2port);
 
-	memset(ps2port, 0, sizeof(struct gscps2port));
-	memset(serio, 0, sizeof(struct serio));
 	ps2port->port = serio;
 	ps2port->padev = dev;
 	ps2port->addr = ioremap_nocache(hpa, GSC_STATUS + 4);
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 702a526..f8fe421 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -211,6 +211,16 @@
 		},
 	},
 	{
+		/*
+		 * Like DV4017EA does not raise AUXERR for errors on MUX ports.
+		 */
+		.ident = "HP Pavilion DV4270ca",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion dv4000 (EH476UA#ABL)"),
+		},
+	},
+	{
 		.ident = "Toshiba P10",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 42aa4ec7..11dafc0 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -516,6 +516,7 @@
 {
 	unsigned long flags;
 	unsigned char str, data;
+	int ret = 0;
 
 	spin_lock_irqsave(&i8042_lock, flags);
 	str = i8042_read_status();
@@ -524,10 +525,11 @@
 		if (i8042_irq_being_tested &&
 		    data == 0xa5 && (str & I8042_STR_AUXDATA))
 			complete(&i8042_aux_irq_delivered);
+		ret = 1;
 	}
 	spin_unlock_irqrestore(&i8042_lock, flags);
 
-	return IRQ_HANDLED;
+	return IRQ_RETVAL(ret);
 }
 
 /*
@@ -1042,7 +1044,7 @@
 	}
 }
 
-static void __devinit i8042_unregister_ports(void)
+static void __devexit i8042_unregister_ports(void)
 {
 	int i;
 
diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c
index ea5e3c6..1b404f9 100644
--- a/drivers/input/serio/pcips2.c
+++ b/drivers/input/serio/pcips2.c
@@ -140,15 +140,13 @@
 	if (ret)
 		goto disable;
 
-	ps2if = kmalloc(sizeof(struct pcips2_data), GFP_KERNEL);
-	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+	ps2if = kzalloc(sizeof(struct pcips2_data), GFP_KERNEL);
+	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
 	if (!ps2if || !serio) {
 		ret = -ENOMEM;
 		goto release;
 	}
 
-	memset(ps2if, 0, sizeof(struct pcips2_data));
-	memset(serio, 0, sizeof(struct serio));
 
 	serio->id.type		= SERIO_8042;
 	serio->write		= pcips2_write;
diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
index d31ece8..2ad8878 100644
--- a/drivers/input/serio/sa1111ps2.c
+++ b/drivers/input/serio/sa1111ps2.c
@@ -234,15 +234,13 @@
 	struct serio *serio;
 	int ret;
 
-	ps2if = kmalloc(sizeof(struct ps2if), GFP_KERNEL);
-	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+	ps2if = kzalloc(sizeof(struct ps2if), GFP_KERNEL);
+	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
 	if (!ps2if || !serio) {
 		ret = -ENOMEM;
 		goto free;
 	}
 
-	memset(ps2if, 0, sizeof(struct ps2if));
-	memset(serio, 0, sizeof(struct serio));
 
 	serio->id.type		= SERIO_8042;
 	serio->write		= ps2_write;
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 372ca49..b3bc15a 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -876,18 +876,14 @@
 
 #define SERIO_ADD_UEVENT_VAR(fmt, val...)				\
 	do {								\
-		int err = add_uevent_var(envp, num_envp, &i,	\
-					buffer, buffer_size, &len,	\
-					fmt, val);			\
+		int err = add_uevent_var(env, fmt, val);		\
 		if (err)						\
 			return err;					\
 	} while (0)
 
-static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct serio *serio;
-	int i = 0;
-	int len = 0;
 
 	if (!dev)
 		return -ENODEV;
@@ -900,7 +896,6 @@
 	SERIO_ADD_UEVENT_VAR("SERIO_EXTRA=%02x", serio->id.extra);
 	SERIO_ADD_UEVENT_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X",
 				serio->id.type, serio->id.proto, serio->id.id, serio->id.extra);
-	envp[i] = NULL;
 
 	return 0;
 }
@@ -908,7 +903,7 @@
 
 #else
 
-static int serio_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	return -ENODEV;
 }
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 9b3a26c..9fb3d5c3 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -856,7 +856,7 @@
 			 le16_to_cpu(udev->descriptor.idProduct));
 
 	usb_make_path(udev, usbtouch->phys, sizeof(usbtouch->phys));
-	strlcpy(usbtouch->phys, "/input0", sizeof(usbtouch->phys));
+	strlcat(usbtouch->phys, "/input0", sizeof(usbtouch->phys));
 
 	input_dev->name = usbtouch->name;
 	input_dev->phys = usbtouch->phys;
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig
index cf906c8..66f946a 100644
--- a/drivers/isdn/Kconfig
+++ b/drivers/isdn/Kconfig
@@ -21,9 +21,7 @@
 
 if ISDN
 
-menu "Old ISDN4Linux"
-
-config ISDN_I4L
+menuconfig ISDN_I4L
 	tristate "Old ISDN4Linux (deprecated)"
 	---help---
 	  This driver allows you to use an ISDN adapter for networking
@@ -45,12 +43,8 @@
 source "drivers/isdn/i4l/Kconfig"
 endif
 
-endmenu
-
-comment "CAPI subsystem"
-
-config ISDN_CAPI
-	tristate "CAPI2.0 support"
+menuconfig ISDN_CAPI
+	tristate "CAPI 2.0 subsystem"
 	help
 	  This provides the CAPI (Common ISDN Application Programming
 	  Interface, a standard making it easy for programs to access ISDN
diff --git a/drivers/isdn/act2000/Kconfig b/drivers/isdn/act2000/Kconfig
index 78e6ad8..3fc1a54 100644
--- a/drivers/isdn/act2000/Kconfig
+++ b/drivers/isdn/act2000/Kconfig
@@ -3,7 +3,7 @@
 #
 config ISDN_DRV_ACT2000
 	tristate "IBM Active 2000 support"
-	depends on ISDN_I4L && ISA
+	depends on ISA
 	help
 	  Say Y here if you have an IBM Active 2000 ISDN card. In order to use
 	  this card, additional firmware is necessary, which has to be loaded
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index be77ee6..4fd4c468 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -17,6 +17,7 @@
 #include <linux/fs.h>
 #endif
 #include <linux/isdnif.h>
+#include <net/net_namespace.h>
 #include "isdn_divert.h"
 
 
@@ -70,6 +71,8 @@
 	wake_up_interruptible(&(rd_queue));
 }				/* put_info_buffer */
 
+#ifdef CONFIG_PROC_FS
+
 /**********************************/
 /* deflection device read routine */
 /**********************************/
@@ -253,8 +256,6 @@
 	return copy_to_user((void __user *)arg, &dioctl, sizeof(dioctl)) ? -EFAULT : 0;
 }				/* isdn_divert_ioctl */
 
-
-#ifdef CONFIG_PROC_FS
 static const struct file_operations isdn_fops =
 {
 	.owner          = THIS_MODULE,
@@ -284,12 +285,12 @@
 	init_waitqueue_head(&rd_queue);
 
 #ifdef CONFIG_PROC_FS
-	isdn_proc_entry = proc_mkdir("net/isdn", NULL);
+	isdn_proc_entry = proc_mkdir("isdn", init_net.proc_net);
 	if (!isdn_proc_entry)
 		return (-1);
 	isdn_divert_entry = create_proc_entry("divert", S_IFREG | S_IRUGO, isdn_proc_entry);
 	if (!isdn_divert_entry) {
-		remove_proc_entry("net/isdn", NULL);
+		remove_proc_entry("isdn", init_net.proc_net);
 		return (-1);
 	}
 	isdn_divert_entry->proc_fops = &isdn_fops; 
@@ -309,7 +310,7 @@
 
 #ifdef CONFIG_PROC_FS
 	remove_proc_entry("divert", isdn_proc_entry);
-	remove_proc_entry("net/isdn", NULL);
+	remove_proc_entry("isdn", init_net.proc_net);
 #endif	/* CONFIG_PROC_FS */
 
 	return (0);
diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig
index bcbb650..0017e50 100644
--- a/drivers/isdn/gigaset/Kconfig
+++ b/drivers/isdn/gigaset/Kconfig
@@ -1,9 +1,5 @@
-menu "Siemens Gigaset"
-	depends on ISDN_I4L
-
-config ISDN_DRV_GIGASET
+menuconfig ISDN_DRV_GIGASET
 	tristate "Siemens Gigaset support (isdn)"
-	depends on ISDN_I4L
 	select CRC_CCITT
 	select BITREVERSE
 	help
@@ -55,6 +51,4 @@
 	  features like configuration mode of M105, say yes. If you
 	  care about your device, say no.
 
-endif
-
-endmenu
+endif # ISDN_DRV_GIGASET != n
diff --git a/drivers/isdn/hardware/eicon/diva_didd.c b/drivers/isdn/hardware/eicon/diva_didd.c
index d755d90..993b14c 100644
--- a/drivers/isdn/hardware/eicon/diva_didd.c
+++ b/drivers/isdn/hardware/eicon/diva_didd.c
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
+#include <net/net_namespace.h>
 
 #include "platform.h"
 #include "di_defs.h"
@@ -86,7 +87,7 @@
 
 static int DIVA_INIT_FUNCTION create_proc(void)
 {
-	proc_net_eicon = proc_mkdir("net/eicon", NULL);
+	proc_net_eicon = proc_mkdir("eicon", init_net.proc_net);
 
 	if (proc_net_eicon) {
 		if ((proc_didd =
@@ -102,7 +103,7 @@
 static void remove_proc(void)
 {
 	remove_proc_entry(DRIVERLNAME, proc_net_eicon);
-	remove_proc_entry("net/eicon", NULL);
+	remove_proc_entry("eicon", init_net.proc_net);
 }
 
 static int DIVA_INIT_FUNCTION divadidd_init(void)
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig
index 12d91fb..a3b945a 100644
--- a/drivers/isdn/hisax/Kconfig
+++ b/drivers/isdn/hisax/Kconfig
@@ -1,6 +1,5 @@
 
 menu "Passive cards"
-	depends on ISDN_I4L
 
 config ISDN_DRV_HISAX
 	tristate "HiSax SiemensChipSet driver support"
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index b04a178..f8b7978 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -20,7 +20,6 @@
 #include <linux/isapnp.h>
 #include <linux/interrupt.h>
 
-extern const char *CardType[];
 static const char *avm_pci_rev = "$Revision: 1.29.2.4 $";
 
 #define  AVM_FRITZ_PCI		1
@@ -726,100 +725,15 @@
 	return(0);
 }
 
-#ifdef CONFIG_PCI
-static struct pci_dev *dev_avm __devinitdata = NULL;
-#endif
-#ifdef __ISAPNP__
-static struct pnp_card *pnp_avm_c __devinitdata = NULL;
-#endif
-
-int __devinit
-setup_avm_pcipnp(struct IsdnCard *card)
+static int __devinit avm_setup_rest(struct IsdnCardState *cs)
 {
 	u_int val, ver;
-	struct IsdnCardState *cs = card->cs;
-	char tmp[64];
 
-	strcpy(tmp, avm_pci_rev);
-	printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
-	if (cs->typ != ISDN_CTYPE_FRITZPCI)
-		return (0);
-	if (card->para[1]) {
-		/* old manual method */
-		cs->hw.avm.cfg_reg = card->para[1];
-		cs->irq = card->para[0];
-		cs->subtyp = AVM_FRITZ_PNP;
-		goto ready;
-	}
-#ifdef __ISAPNP__
-	if (isapnp_present()) {
-		struct pnp_dev *pnp_avm_d = NULL;
-		if ((pnp_avm_c = pnp_find_card(
-			ISAPNP_VENDOR('A', 'V', 'M'),
-			ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
-			if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
-				ISAPNP_VENDOR('A', 'V', 'M'),
-				ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
-				int err;
-
-				pnp_disable_dev(pnp_avm_d);
-				err = pnp_activate_dev(pnp_avm_d);
-				if (err<0) {
-					printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
-						__FUNCTION__, err);
-					return(0);
-				}
-				cs->hw.avm.cfg_reg =
-					pnp_port_start(pnp_avm_d, 0);
-				cs->irq = pnp_irq(pnp_avm_d, 0);
-				if (!cs->irq) {
-					printk(KERN_ERR "FritzPnP:No IRQ\n");
-					return(0);
-				}
-				if (!cs->hw.avm.cfg_reg) {
-					printk(KERN_ERR "FritzPnP:No IO address\n");
-					return(0);
-				}
-				cs->subtyp = AVM_FRITZ_PNP;
-				goto ready;
-			}
-		}
-	} else {
-		printk(KERN_INFO "FritzPnP: no ISA PnP present\n");
-	}
-#endif
-#ifdef CONFIG_PCI
-	if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
-		PCI_DEVICE_ID_AVM_A1,  dev_avm))) {
-		if (pci_enable_device(dev_avm))
-			return(0);
-		cs->irq = dev_avm->irq;
-		if (!cs->irq) {
-			printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
-			return(0);
-		}
-		cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
-		if (!cs->hw.avm.cfg_reg) {
-			printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
-			return(0);
-		}
-		cs->subtyp = AVM_FRITZ_PCI;
-	} else {
-		printk(KERN_WARNING "FritzPCI: No PCI card found\n");
-		return(0);
-	}
-	cs->irq_flags |= IRQF_SHARED;
-#else
-	printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n");
-	return (0);
-#endif /* CONFIG_PCI */
-ready:
 	cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
 	if (!request_region(cs->hw.avm.cfg_reg, 32,
 		(cs->subtyp == AVM_FRITZ_PCI) ? "avm PCI" : "avm PnP")) {
 		printk(KERN_WARNING
-		       "HiSax: %s config port %x-%x already in use\n",
-		       CardType[card->typ],
+		       "HiSax: Fritz!PCI/PNP config port %x-%x already in use\n",
 		       cs->hw.avm.cfg_reg,
 		       cs->hw.avm.cfg_reg + 31);
 		return (0);
@@ -860,3 +774,137 @@
 	ISACVersion(cs, (cs->subtyp == AVM_FRITZ_PCI) ? "AVM PCI:" : "AVM PnP:");
 	return (1);
 }
+
+#ifndef __ISAPNP__
+
+static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
+{
+	return(1);	/* no-op: success */
+}
+
+#else
+
+static struct pnp_card *pnp_avm_c __devinitdata = NULL;
+
+static int __devinit avm_pnp_setup(struct IsdnCardState *cs)
+{
+	struct pnp_dev *pnp_avm_d = NULL;
+
+	if (!isapnp_present())
+		return(1);	/* no-op: success */
+
+	if ((pnp_avm_c = pnp_find_card(
+		ISAPNP_VENDOR('A', 'V', 'M'),
+		ISAPNP_FUNCTION(0x0900), pnp_avm_c))) {
+		if ((pnp_avm_d = pnp_find_dev(pnp_avm_c,
+			ISAPNP_VENDOR('A', 'V', 'M'),
+			ISAPNP_FUNCTION(0x0900), pnp_avm_d))) {
+			int err;
+
+			pnp_disable_dev(pnp_avm_d);
+			err = pnp_activate_dev(pnp_avm_d);
+			if (err<0) {
+				printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+					__FUNCTION__, err);
+				return(0);
+			}
+			cs->hw.avm.cfg_reg =
+				pnp_port_start(pnp_avm_d, 0);
+			cs->irq = pnp_irq(pnp_avm_d, 0);
+			if (!cs->irq) {
+				printk(KERN_ERR "FritzPnP:No IRQ\n");
+				return(0);
+			}
+			if (!cs->hw.avm.cfg_reg) {
+				printk(KERN_ERR "FritzPnP:No IO address\n");
+				return(0);
+			}
+			cs->subtyp = AVM_FRITZ_PNP;
+
+			return (2);	/* goto 'ready' label */
+		}
+	}
+
+	return (1);
+}
+
+#endif /* __ISAPNP__ */
+
+#ifndef CONFIG_PCI
+
+static int __devinit avm_pci_setup(struct IsdnCardState *cs)
+{
+	return(1);	/* no-op: success */
+}
+
+#else
+
+static struct pci_dev *dev_avm __devinitdata = NULL;
+
+static int __devinit avm_pci_setup(struct IsdnCardState *cs)
+{
+	if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
+		PCI_DEVICE_ID_AVM_A1, dev_avm))) {
+
+		if (pci_enable_device(dev_avm))
+			return(0);
+
+		cs->irq = dev_avm->irq;
+		if (!cs->irq) {
+			printk(KERN_ERR "FritzPCI: No IRQ for PCI card found\n");
+			return(0);
+		}
+
+		cs->hw.avm.cfg_reg = pci_resource_start(dev_avm, 1);
+		if (!cs->hw.avm.cfg_reg) {
+			printk(KERN_ERR "FritzPCI: No IO-Adr for PCI card found\n");
+			return(0);
+		}
+
+		cs->subtyp = AVM_FRITZ_PCI;
+	} else {
+		printk(KERN_WARNING "FritzPCI: No PCI card found\n");
+		return(0);
+	}
+
+	cs->irq_flags |= IRQF_SHARED;
+
+	return (1);
+}
+
+#endif /* CONFIG_PCI */
+
+int __devinit
+setup_avm_pcipnp(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
+	int rc;
+
+	strcpy(tmp, avm_pci_rev);
+	printk(KERN_INFO "HiSax: AVM PCI driver Rev. %s\n", HiSax_getrev(tmp));
+
+	if (cs->typ != ISDN_CTYPE_FRITZPCI)
+		return (0);
+
+	if (card->para[1]) {
+		/* old manual method */
+		cs->hw.avm.cfg_reg = card->para[1];
+		cs->irq = card->para[0];
+		cs->subtyp = AVM_FRITZ_PNP;
+		goto ready;
+	}
+
+	rc = avm_pnp_setup(cs);
+	if (rc < 1)
+		return (0);
+	if (rc == 2)
+		goto ready;
+
+	rc = avm_pci_setup(cs);
+	if (rc < 1)
+		return (0);
+
+ready:
+	return avm_setup_rest(cs);
+}
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
index 6339bb4..99ef3b4 100644
--- a/drivers/isdn/hisax/bkm_a8.c
+++ b/drivers/isdn/hisax/bkm_a8.c
@@ -20,8 +20,6 @@
 #include <linux/pci.h>
 #include "bkm_ax.h"
 
-#ifdef CONFIG_PCI
-
 #define	ATTEMPT_PCI_REMAPPING	/* Required for PLX rev 1 */
 
 extern const char *CardType[];
@@ -279,12 +277,9 @@
 static u_char pci_device_fn __devinitdata = 0;
 static u_char pci_irq __devinitdata = 0;
 
-#endif /* CONFIG_PCI */
-
 int __devinit
 setup_sct_quadro(struct IsdnCard *card)
 {
-#ifdef CONFIG_PCI
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
 	u_int found = 0;
@@ -442,7 +437,4 @@
 		sct_quadro_subtypes[cs->subtyp],
 		readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
 	return (1);
-#else
-	printk(KERN_ERR "HiSax: bkm_a8 only supported on PCI Systems\n");
-#endif /* CONFIG_PCI */
 }
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index 5f7907e..97097ef 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -1146,14 +1146,12 @@
 	}
 	if (ret) {
 		closecard(cardnr);
-		ret = 0;
 		goto outf_cs;
 	}
 	init_tei(cs, cs->protocol);
 	ret = CallcNewChan(cs);
 	if (ret) {
 		closecard(cardnr);
-		ret = 0;
 		goto outf_cs;
 	}
 	/* ISAR needs firmware download first */
@@ -1165,7 +1163,7 @@
 outf_cs:
 	kfree(cs);
 	card->cs = NULL;
-	return ret;
+	return 0;
 }
 
 static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockowner)
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index 6eebeb4..8267450 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -25,8 +25,6 @@
 #include <linux/pci.h>
 #include <linux/isapnp.h>
 
-extern const char *CardType[];
-
 static const char *Diva_revision = "$Revision: 1.33.2.6 $";
 
 #define byteout(addr,val) outb(val,addr)
@@ -906,225 +904,15 @@
 	return(0);
 }
 
-static struct pci_dev *dev_diva __devinitdata = NULL;
-static struct pci_dev *dev_diva_u __devinitdata = NULL;
-static struct pci_dev *dev_diva201 __devinitdata = NULL;
-static struct pci_dev *dev_diva202 __devinitdata = NULL;
-
-#ifdef __ISAPNP__
-static struct isapnp_device_id diva_ids[] __devinitdata = {
-	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
-	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), 
-	  (unsigned long) "Diva picola" },
-	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
-	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), 
-	  (unsigned long) "Diva picola" },
-	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
-	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), 
-	  (unsigned long) "Diva 2.0" },
-	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
-	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), 
-	  (unsigned long) "Diva 2.0" },
-	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
-	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), 
-	  (unsigned long) "Diva 2.01" },
-	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
-	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), 
-	  (unsigned long) "Diva 2.01" },
-	{ 0, }
-};
-
-static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
-static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
-
-
-int __devinit
-setup_diva(struct IsdnCard *card)
+static int __devinit setup_diva_common(struct IsdnCardState *cs)
 {
-	int bytecnt = 8;
+	int bytecnt;
 	u_char val;
-	struct IsdnCardState *cs = card->cs;
-	char tmp[64];
 
-	strcpy(tmp, Diva_revision);
-	printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
-	if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
-		return(0);
-	cs->hw.diva.status = 0;
-	if (card->para[1]) {
-		cs->hw.diva.ctrl_reg = 0;
-		cs->hw.diva.cfg_reg = card->para[1];
-		val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
-			cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
-		printk(KERN_INFO "Diva: IPAC version %x\n", val);
-		if ((val == 1) || (val==2)) {
-			cs->subtyp = DIVA_IPAC_ISA;
-			cs->hw.diva.ctrl = 0;
-			cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
-			cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
-			cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
-			cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
-			test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-		} else {
-			cs->subtyp = DIVA_ISA;
-			cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
-			cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
-			cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
-			cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
-			cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
-		}
-		cs->irq = card->para[0];
-	} else {
-#ifdef __ISAPNP__
-		if (isapnp_present()) {
-			struct pnp_dev *pnp_d;
-			while(ipid->card_vendor) {
-				if ((pnp_c = pnp_find_card(ipid->card_vendor,
-					ipid->card_device, pnp_c))) {
-					pnp_d = NULL;
-					if ((pnp_d = pnp_find_dev(pnp_c,
-						ipid->vendor, ipid->function, pnp_d))) {
-						int err;
-
-						printk(KERN_INFO "HiSax: %s detected\n",
-							(char *)ipid->driver_data);
-						pnp_disable_dev(pnp_d);
-						err = pnp_activate_dev(pnp_d);
-						if (err<0) {
-							printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
-								__FUNCTION__, err);
-							return(0);
-						}
-						card->para[1] = pnp_port_start(pnp_d, 0);
-						card->para[0] = pnp_irq(pnp_d, 0);
-						if (!card->para[0] || !card->para[1]) {
-							printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
-								card->para[0], card->para[1]);
-							pnp_disable_dev(pnp_d); 
-							return(0);
-						}
-						cs->hw.diva.cfg_reg  = card->para[1];
-						cs->irq = card->para[0];
-						if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
-							cs->subtyp = DIVA_IPAC_ISA;
-							cs->hw.diva.ctrl = 0;
-							cs->hw.diva.isac =
-								card->para[1] + DIVA_IPAC_DATA;
-							cs->hw.diva.hscx =
-								card->para[1] + DIVA_IPAC_DATA;
-							cs->hw.diva.isac_adr =
-								card->para[1] + DIVA_IPAC_ADR;
-							cs->hw.diva.hscx_adr =
-								card->para[1] + DIVA_IPAC_ADR;
-							test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-						} else {
-							cs->subtyp = DIVA_ISA;
-							cs->hw.diva.ctrl =
-								card->para[1] + DIVA_ISA_CTRL;
-							cs->hw.diva.isac =
-								card->para[1] + DIVA_ISA_ISAC_DATA;
-							cs->hw.diva.hscx =
-								card->para[1] + DIVA_HSCX_DATA;
-							cs->hw.diva.isac_adr =
-								card->para[1] + DIVA_ISA_ISAC_ADR;
-							cs->hw.diva.hscx_adr =
-								card->para[1] + DIVA_HSCX_ADR;
-						}
-						goto ready;
-					} else {
-						printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
-						return(0);
-					}
-				}
-				ipid++;
-				pnp_c=NULL;
-			} 
-			if (!ipid->card_vendor) {
-				printk(KERN_INFO "Diva PnP: no ISAPnP card found\n");
-			}
-		}
-#endif
-#ifdef CONFIG_PCI
-		cs->subtyp = 0;
-		if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
-			PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
-			if (pci_enable_device(dev_diva))
-				return(0);
-			cs->subtyp = DIVA_PCI;
-			cs->irq = dev_diva->irq;
-			cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
-		} else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
-			PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
-			if (pci_enable_device(dev_diva_u))
-				return(0);
-			cs->subtyp = DIVA_PCI;
-			cs->irq = dev_diva_u->irq;
-			cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
-		} else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
-			PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
-			if (pci_enable_device(dev_diva201))
-				return(0);
-			cs->subtyp = DIVA_IPAC_PCI;
-			cs->irq = dev_diva201->irq;
-			cs->hw.diva.pci_cfg =
-				(ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
-			cs->hw.diva.cfg_reg =
-				(ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
-		} else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
-			PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
-			if (pci_enable_device(dev_diva202))
-				return(0);
-			cs->subtyp = DIVA_IPACX_PCI;
-			cs->irq = dev_diva202->irq;
-			cs->hw.diva.pci_cfg =
-				(ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
-			cs->hw.diva.cfg_reg =
-				(ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
-		} else {
-			printk(KERN_WARNING "Diva: No PCI card found\n");
-			return(0);
-		}
-
-		if (!cs->irq) {
-			printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
-			iounmap_diva(cs);
-			return(0);
-		}
-
-		if (!cs->hw.diva.cfg_reg) {
-			printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
-			iounmap_diva(cs);
-			return(0);
-		}
-		cs->irq_flags |= IRQF_SHARED;
-#else
-		printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n");
-		printk(KERN_WARNING "Diva: unable to config DIVA PCI\n");
-		return (0);
-#endif /* CONFIG_PCI */
-		if ((cs->subtyp == DIVA_IPAC_PCI) ||
-		    (cs->subtyp == DIVA_IPACX_PCI)   ) {
-			cs->hw.diva.ctrl = 0;
-			cs->hw.diva.isac = 0;
-			cs->hw.diva.hscx = 0;
-			cs->hw.diva.isac_adr = 0;
-			cs->hw.diva.hscx_adr = 0;
-			test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-			bytecnt = 0;
-		} else {
-			cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
-			cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
-			cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
-			cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
-			cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
-			bytecnt = 32;
-		}
-	}
-
-#ifdef __ISAPNP__
-ready:
-#endif
+	if ((cs->subtyp == DIVA_ISA) || (cs->subtyp == DIVA_IPAC_ISA))
+		bytecnt = 8;
+	else
+		bytecnt = 32;
 
 	printk(KERN_INFO
 		"Diva: %s card configured at %#lx IRQ %d\n",
@@ -1145,7 +933,7 @@
 		if (!request_region(cs->hw.diva.cfg_reg, bytecnt, "diva isdn")) {
 			printk(KERN_WARNING
 			       "HiSax: %s config port %lx-%lx already in use\n",
-			       CardType[card->typ],
+			       "diva",
 			       cs->hw.diva.cfg_reg,
 			       cs->hw.diva.cfg_reg + bytecnt);
 			iounmap_diva(cs);
@@ -1206,3 +994,290 @@
 	}
 	return (1);
 }
+
+#ifdef CONFIG_ISA
+
+static int __devinit setup_diva_isa(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+	u_char val;
+
+	if (!card->para[1])
+		return (-1);	/* card not found; continue search */
+
+	cs->hw.diva.ctrl_reg = 0;
+	cs->hw.diva.cfg_reg = card->para[1];
+	val = readreg(cs->hw.diva.cfg_reg + DIVA_IPAC_ADR,
+		cs->hw.diva.cfg_reg + DIVA_IPAC_DATA, IPAC_ID);
+	printk(KERN_INFO "Diva: IPAC version %x\n", val);
+	if ((val == 1) || (val==2)) {
+		cs->subtyp = DIVA_IPAC_ISA;
+		cs->hw.diva.ctrl = 0;
+		cs->hw.diva.isac = card->para[1] + DIVA_IPAC_DATA;
+		cs->hw.diva.hscx = card->para[1] + DIVA_IPAC_DATA;
+		cs->hw.diva.isac_adr = card->para[1] + DIVA_IPAC_ADR;
+		cs->hw.diva.hscx_adr = card->para[1] + DIVA_IPAC_ADR;
+		test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+	} else {
+		cs->subtyp = DIVA_ISA;
+		cs->hw.diva.ctrl = card->para[1] + DIVA_ISA_CTRL;
+		cs->hw.diva.isac = card->para[1] + DIVA_ISA_ISAC_DATA;
+		cs->hw.diva.hscx = card->para[1] + DIVA_HSCX_DATA;
+		cs->hw.diva.isac_adr = card->para[1] + DIVA_ISA_ISAC_ADR;
+		cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
+	}
+	cs->irq = card->para[0];
+
+	return (1);		/* card found */
+}
+
+#else	/* if !CONFIG_ISA */
+
+static int __devinit setup_diva_isa(struct IsdnCard *card)
+{
+	return (-1);	/* card not found; continue search */
+}
+
+#endif	/* CONFIG_ISA */
+
+#ifdef __ISAPNP__
+static struct isapnp_device_id diva_ids[] __devinitdata = {
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), 
+	  (unsigned long) "Diva picola" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), 
+	  (unsigned long) "Diva picola" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), 
+	  (unsigned long) "Diva 2.0" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), 
+	  (unsigned long) "Diva 2.0" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), 
+	  (unsigned long) "Diva 2.01" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), 
+	  (unsigned long) "Diva 2.01" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
+static struct pnp_card *pnp_c __devinitdata = NULL;
+
+static int __devinit setup_diva_isapnp(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+	struct pnp_dev *pnp_d;
+
+	if (!isapnp_present())
+		return (-1);	/* card not found; continue search */
+
+	while(ipid->card_vendor) {
+		if ((pnp_c = pnp_find_card(ipid->card_vendor,
+			ipid->card_device, pnp_c))) {
+			pnp_d = NULL;
+			if ((pnp_d = pnp_find_dev(pnp_c,
+				ipid->vendor, ipid->function, pnp_d))) {
+				int err;
+
+				printk(KERN_INFO "HiSax: %s detected\n",
+					(char *)ipid->driver_data);
+				pnp_disable_dev(pnp_d);
+				err = pnp_activate_dev(pnp_d);
+				if (err<0) {
+					printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+						__FUNCTION__, err);
+					return(0);
+				}
+				card->para[1] = pnp_port_start(pnp_d, 0);
+				card->para[0] = pnp_irq(pnp_d, 0);
+				if (!card->para[0] || !card->para[1]) {
+					printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
+						card->para[0], card->para[1]);
+					pnp_disable_dev(pnp_d); 
+					return(0);
+				}
+				cs->hw.diva.cfg_reg  = card->para[1];
+				cs->irq = card->para[0];
+				if (ipid->function == ISAPNP_FUNCTION(0xA1)) {
+					cs->subtyp = DIVA_IPAC_ISA;
+					cs->hw.diva.ctrl = 0;
+					cs->hw.diva.isac =
+						card->para[1] + DIVA_IPAC_DATA;
+					cs->hw.diva.hscx =
+						card->para[1] + DIVA_IPAC_DATA;
+					cs->hw.diva.isac_adr =
+						card->para[1] + DIVA_IPAC_ADR;
+					cs->hw.diva.hscx_adr =
+						card->para[1] + DIVA_IPAC_ADR;
+					test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+				} else {
+					cs->subtyp = DIVA_ISA;
+					cs->hw.diva.ctrl =
+						card->para[1] + DIVA_ISA_CTRL;
+					cs->hw.diva.isac =
+						card->para[1] + DIVA_ISA_ISAC_DATA;
+					cs->hw.diva.hscx =
+						card->para[1] + DIVA_HSCX_DATA;
+					cs->hw.diva.isac_adr =
+						card->para[1] + DIVA_ISA_ISAC_ADR;
+					cs->hw.diva.hscx_adr =
+						card->para[1] + DIVA_HSCX_ADR;
+				}
+				return (1);		/* card found */
+			} else {
+				printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
+				return(0);
+			}
+		}
+		ipid++;
+		pnp_c=NULL;
+	} 
+
+	return (-1);	/* card not found; continue search */
+}
+
+#else	/* if !ISAPNP */
+
+static int __devinit setup_diva_isapnp(struct IsdnCard *card)
+{
+	return (-1);	/* card not found; continue search */
+}
+
+#endif	/* ISAPNP */
+
+#ifdef CONFIG_PCI
+static struct pci_dev *dev_diva __devinitdata = NULL;
+static struct pci_dev *dev_diva_u __devinitdata = NULL;
+static struct pci_dev *dev_diva201 __devinitdata = NULL;
+static struct pci_dev *dev_diva202 __devinitdata = NULL;
+
+static int __devinit setup_diva_pci(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+
+	cs->subtyp = 0;
+	if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
+		PCI_DEVICE_ID_EICON_DIVA20, dev_diva))) {
+		if (pci_enable_device(dev_diva))
+			return(0);
+		cs->subtyp = DIVA_PCI;
+		cs->irq = dev_diva->irq;
+		cs->hw.diva.cfg_reg = pci_resource_start(dev_diva, 2);
+	} else if ((dev_diva_u = pci_find_device(PCI_VENDOR_ID_EICON,
+		PCI_DEVICE_ID_EICON_DIVA20_U, dev_diva_u))) {
+		if (pci_enable_device(dev_diva_u))
+			return(0);
+		cs->subtyp = DIVA_PCI;
+		cs->irq = dev_diva_u->irq;
+		cs->hw.diva.cfg_reg = pci_resource_start(dev_diva_u, 2);
+	} else if ((dev_diva201 = pci_find_device(PCI_VENDOR_ID_EICON,
+		PCI_DEVICE_ID_EICON_DIVA201, dev_diva201))) {
+		if (pci_enable_device(dev_diva201))
+			return(0);
+		cs->subtyp = DIVA_IPAC_PCI;
+		cs->irq = dev_diva201->irq;
+		cs->hw.diva.pci_cfg =
+			(ulong) ioremap(pci_resource_start(dev_diva201, 0), 4096);
+		cs->hw.diva.cfg_reg =
+			(ulong) ioremap(pci_resource_start(dev_diva201, 1), 4096);
+	} else if ((dev_diva202 = pci_find_device(PCI_VENDOR_ID_EICON,
+		PCI_DEVICE_ID_EICON_DIVA202, dev_diva202))) {
+		if (pci_enable_device(dev_diva202))
+			return(0);
+		cs->subtyp = DIVA_IPACX_PCI;
+		cs->irq = dev_diva202->irq;
+		cs->hw.diva.pci_cfg =
+			(ulong) ioremap(pci_resource_start(dev_diva202, 0), 4096);
+		cs->hw.diva.cfg_reg =
+			(ulong) ioremap(pci_resource_start(dev_diva202, 1), 4096);
+	} else {
+		return (-1);	/* card not found; continue search */
+	}
+
+	if (!cs->irq) {
+		printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
+		iounmap_diva(cs);
+		return(0);
+	}
+
+	if (!cs->hw.diva.cfg_reg) {
+		printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
+		iounmap_diva(cs);
+		return(0);
+	}
+	cs->irq_flags |= IRQF_SHARED;
+
+	if ((cs->subtyp == DIVA_IPAC_PCI) ||
+	    (cs->subtyp == DIVA_IPACX_PCI)   ) {
+		cs->hw.diva.ctrl = 0;
+		cs->hw.diva.isac = 0;
+		cs->hw.diva.hscx = 0;
+		cs->hw.diva.isac_adr = 0;
+		cs->hw.diva.hscx_adr = 0;
+		test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+	} else {
+		cs->hw.diva.ctrl = cs->hw.diva.cfg_reg + DIVA_PCI_CTRL;
+		cs->hw.diva.isac = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_DATA;
+		cs->hw.diva.hscx = cs->hw.diva.cfg_reg + DIVA_HSCX_DATA;
+		cs->hw.diva.isac_adr = cs->hw.diva.cfg_reg + DIVA_PCI_ISAC_ADR;
+		cs->hw.diva.hscx_adr = cs->hw.diva.cfg_reg + DIVA_HSCX_ADR;
+	}
+
+	return (1);		/* card found */
+}
+
+#else	/* if !CONFIG_PCI */
+
+static int __devinit setup_diva_pci(struct IsdnCard *card)
+{
+	return (-1);	/* card not found; continue search */
+}
+
+#endif	/* CONFIG_PCI */
+
+int __devinit
+setup_diva(struct IsdnCard *card)
+{
+	int rc, have_card = 0;
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
+
+	strcpy(tmp, Diva_revision);
+	printk(KERN_INFO "HiSax: Eicon.Diehl Diva driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_DIEHLDIVA)
+		return(0);
+	cs->hw.diva.status = 0;
+
+	rc = setup_diva_isa(card);
+	if (!rc)
+		return rc;
+	if (rc > 0) {
+		have_card = 1;
+		goto ready;
+	}
+
+	rc = setup_diva_isapnp(card);
+	if (!rc)
+		return rc;
+	if (rc > 0) {
+		have_card = 1;
+		goto ready;
+	}
+
+	rc = setup_diva_pci(card);
+	if (!rc)
+		return rc;
+	if (rc > 0)
+		have_card = 1;
+
+ready:
+	if (!have_card) {
+		printk(KERN_WARNING "Diva: No ISA, ISAPNP or PCI card found\n");
+		return(0);
+	}
+
+	return setup_diva_common(card->cs);
+}
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index fab3e4e..0c1351b 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -30,8 +30,6 @@
 #include <linux/serial.h>
 #include <linux/serial_reg.h>
 
-extern const char *CardType[];
-
 static const char *Elsa_revision = "$Revision: 2.32.2.4 $";
 static const char *Elsa_Types[] =
 {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
@@ -832,8 +830,75 @@
 	return (CARD_portlist[i]);
 }
 
-static 	struct pci_dev *dev_qs1000 __devinitdata = NULL;
-static 	struct pci_dev *dev_qs3000 __devinitdata = NULL;
+static int __devinit
+setup_elsa_isa(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+	u_char val;
+
+	cs->hw.elsa.base = card->para[0];
+	printk(KERN_INFO "Elsa: Microlink IO probing\n");
+	if (cs->hw.elsa.base) {
+		if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
+						  cs->typ))) {
+			printk(KERN_WARNING
+			       "Elsa: no Elsa Microlink at %#lx\n",
+			       cs->hw.elsa.base);
+			return (0);
+		}
+	} else
+		cs->hw.elsa.base = probe_elsa(cs);
+
+	if (!cs->hw.elsa.base) {
+		printk(KERN_WARNING
+		       "No Elsa Microlink found\n");
+		return (0);
+	}
+
+	cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+	cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+	cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+	cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+	cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
+	cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+	cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+	cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+	val = bytein(cs->hw.elsa.cfg);
+	if (cs->subtyp == ELSA_PC) {
+		const u_char CARD_IrqTab[8] =
+		{7, 3, 5, 9, 0, 0, 0, 0};
+		cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
+	} else if (cs->subtyp == ELSA_PCC8) {
+		const u_char CARD_IrqTab[8] =
+		{7, 3, 5, 9, 0, 0, 0, 0};
+		cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
+	} else {
+		const u_char CARD_IrqTab[8] =
+		{15, 10, 15, 3, 11, 5, 11, 9};
+		cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
+	}
+	val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
+	if (val < 3)
+		val |= 8;
+	val += 'A' - 3;
+	if (val == 'B' || val == 'C')
+		val ^= 1;
+	if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
+		val = 'C';
+	printk(KERN_INFO
+	       "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
+	       Elsa_Types[cs->subtyp],
+	       cs->hw.elsa.base,
+	       val, cs->irq);
+	val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
+	if (val) {
+		printk(KERN_WARNING
+		   "Elsa: Microlink S0 bus power bad\n");
+		cs->hw.elsa.status |= ELSA_BAD_PWR;
+	}
+
+	return (1);
+}
 
 #ifdef __ISAPNP__
 static struct isapnp_device_id elsa_ids[] __devinitdata = {
@@ -848,233 +913,194 @@
 
 static struct isapnp_device_id *ipid __devinitdata = &elsa_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
+#endif	/* __ISAPNP__ */
 
-int __devinit
-setup_elsa(struct IsdnCard *card)
+static int __devinit
+setup_elsa_isapnp(struct IsdnCard *card)
 {
-	int bytecnt;
-	u_char val;
 	struct IsdnCardState *cs = card->cs;
-	char tmp[64];
 
-	strcpy(tmp, Elsa_revision);
-	printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
-	cs->hw.elsa.ctrl_reg = 0;
-	cs->hw.elsa.status = 0;
-	cs->hw.elsa.MFlag = 0;
-	cs->subtyp = 0;
-	if (cs->typ == ISDN_CTYPE_ELSA) {
-		cs->hw.elsa.base = card->para[0];
-		printk(KERN_INFO "Elsa: Microlink IO probing\n");
-		if (cs->hw.elsa.base) {
-			if (!(cs->subtyp = probe_elsa_adr(cs->hw.elsa.base,
-							  cs->typ))) {
-				printk(KERN_WARNING
-				       "Elsa: no Elsa Microlink at %#lx\n",
-				       cs->hw.elsa.base);
-				return (0);
-			}
-		} else
-			cs->hw.elsa.base = probe_elsa(cs);
-		if (cs->hw.elsa.base) {
-			cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
-			cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
-			cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
-			cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
-			cs->hw.elsa.itac = cs->hw.elsa.base + ELSA_ITAC;
-			cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
-			cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
-			cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
-			val = bytein(cs->hw.elsa.cfg);
-			if (cs->subtyp == ELSA_PC) {
-				const u_char CARD_IrqTab[8] =
-				{7, 3, 5, 9, 0, 0, 0, 0};
-				cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PC) >> 2];
-			} else if (cs->subtyp == ELSA_PCC8) {
-				const u_char CARD_IrqTab[8] =
-				{7, 3, 5, 9, 0, 0, 0, 0};
-				cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX_PCC8) >> 4];
-			} else {
-				const u_char CARD_IrqTab[8] =
-				{15, 10, 15, 3, 11, 5, 11, 9};
-				cs->irq = CARD_IrqTab[(val & ELSA_IRQ_IDX) >> 3];
-			}
-			val = bytein(cs->hw.elsa.ale) & ELSA_HW_RELEASE;
-			if (val < 3)
-				val |= 8;
-			val += 'A' - 3;
-			if (val == 'B' || val == 'C')
-				val ^= 1;
-			if ((cs->subtyp == ELSA_PCFPRO) && (val = 'G'))
-				val = 'C';
-			printk(KERN_INFO
-			       "Elsa: %s found at %#lx Rev.:%c IRQ %d\n",
-			       Elsa_Types[cs->subtyp],
-			       cs->hw.elsa.base,
-			       val, cs->irq);
-			val = bytein(cs->hw.elsa.ale) & ELSA_S0_POWER_BAD;
-			if (val) {
-				printk(KERN_WARNING
-				   "Elsa: Microlink S0 bus power bad\n");
-				cs->hw.elsa.status |= ELSA_BAD_PWR;
-			}
-		} else {
-			printk(KERN_WARNING
-			       "No Elsa Microlink found\n");
-			return (0);
-		}
-	} else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
 #ifdef __ISAPNP__
-		if (!card->para[1] && isapnp_present()) {
-			struct pnp_dev *pnp_d;
-			while(ipid->card_vendor) {
-				if ((pnp_c = pnp_find_card(ipid->card_vendor,
-					ipid->card_device, pnp_c))) {
-					pnp_d = NULL;
-					if ((pnp_d = pnp_find_dev(pnp_c,
-						ipid->vendor, ipid->function, pnp_d))) {
-						int err;
+	if (!card->para[1] && isapnp_present()) {
+		struct pnp_dev *pnp_d;
+		while(ipid->card_vendor) {
+			if ((pnp_c = pnp_find_card(ipid->card_vendor,
+				ipid->card_device, pnp_c))) {
+				pnp_d = NULL;
+				if ((pnp_d = pnp_find_dev(pnp_c,
+					ipid->vendor, ipid->function, pnp_d))) {
+					int err;
 
-						printk(KERN_INFO "HiSax: %s detected\n",
-							(char *)ipid->driver_data);
-						pnp_disable_dev(pnp_d);
-						err = pnp_activate_dev(pnp_d);
-						if (err<0) {
-							printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
-								__FUNCTION__, err);
-							return(0);
-						}
-						card->para[1] = pnp_port_start(pnp_d, 0);
-						card->para[0] = pnp_irq(pnp_d, 0);
-
-						if (!card->para[0] || !card->para[1]) {
-							printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
-								card->para[0], card->para[1]);
-							pnp_disable_dev(pnp_d);
-							return(0);
-						}
-						if (ipid->function == ISAPNP_FUNCTION(0x133))
-							cs->subtyp = ELSA_QS1000;
-						else
-							cs->subtyp = ELSA_QS3000;
-						break;
-					} else {
-						printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
+					printk(KERN_INFO "HiSax: %s detected\n",
+						(char *)ipid->driver_data);
+					pnp_disable_dev(pnp_d);
+					err = pnp_activate_dev(pnp_d);
+					if (err<0) {
+						printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+							__FUNCTION__, err);
 						return(0);
 					}
+					card->para[1] = pnp_port_start(pnp_d, 0);
+					card->para[0] = pnp_irq(pnp_d, 0);
+
+					if (!card->para[0] || !card->para[1]) {
+						printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
+							card->para[0], card->para[1]);
+						pnp_disable_dev(pnp_d);
+						return(0);
+					}
+					if (ipid->function == ISAPNP_FUNCTION(0x133))
+						cs->subtyp = ELSA_QS1000;
+					else
+						cs->subtyp = ELSA_QS3000;
+					break;
+				} else {
+					printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
+					return(0);
 				}
-				ipid++;
-				pnp_c=NULL;
-			} 
-			if (!ipid->card_vendor) {
-				printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
-				return(0);
 			}
+			ipid++;
+			pnp_c=NULL;
+		} 
+		if (!ipid->card_vendor) {
+			printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
+			return(0);
 		}
-#endif
-		if (card->para[1] && card->para[0]) { 
-			cs->hw.elsa.base = card->para[1];
-			cs->irq = card->para[0];
-			if (!cs->subtyp)
-				cs->subtyp = ELSA_QS1000;
-		} else {
-			printk(KERN_ERR "Elsa PnP: no parameter\n");
-		}
-		cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
-		cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
-		cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
-		cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
-		cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
-		cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
-		cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
-		printk(KERN_INFO
-		       "Elsa: %s defined at %#lx IRQ %d\n",
-		       Elsa_Types[cs->subtyp],
-		       cs->hw.elsa.base,
-		       cs->irq);
-	} else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA) {
+	}
+#endif	/* __ISAPNP__ */
+
+	if (card->para[1] && card->para[0]) { 
 		cs->hw.elsa.base = card->para[1];
 		cs->irq = card->para[0];
-		val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
-		if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
-			cs->subtyp = ELSA_PCMCIA_IPAC;
-			cs->hw.elsa.ale = cs->hw.elsa.base + 0;
-			cs->hw.elsa.isac = cs->hw.elsa.base + 2;
-			cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
-			test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-		} else {
-			cs->subtyp = ELSA_PCMCIA;
-			cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
-			cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
-			cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
-		}
-		cs->hw.elsa.timer = 0;
-		cs->hw.elsa.trig = 0;
-		cs->hw.elsa.ctrl = 0;
-		cs->irq_flags |= IRQF_SHARED;
-		printk(KERN_INFO
-		       "Elsa: %s defined at %#lx IRQ %d\n",
-		       Elsa_Types[cs->subtyp],
-		       cs->hw.elsa.base,
-		       cs->irq);
-	} else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
-#ifdef CONFIG_PCI
-		cs->subtyp = 0;
-		if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
-			PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
-			if (pci_enable_device(dev_qs1000))
-				return(0);
-			cs->subtyp = ELSA_QS1000PCI;
-			cs->irq = dev_qs1000->irq;
-			cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
-			cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
-		} else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
-			PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
-			if (pci_enable_device(dev_qs3000))
-				return(0);
-			cs->subtyp = ELSA_QS3000PCI;
-			cs->irq = dev_qs3000->irq;
-			cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
-			cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
-		} else {
-			printk(KERN_WARNING "Elsa: No PCI card found\n");
-			return(0);
-		}
-		if (!cs->irq) {
-			printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
-			return(0);
-		}
+		if (!cs->subtyp)
+			cs->subtyp = ELSA_QS1000;
+	} else {
+		printk(KERN_ERR "Elsa PnP: no parameter\n");
+	}
+	cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
+	cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
+	cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
+	cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+	cs->hw.elsa.trig = cs->hw.elsa.base + ELSA_TRIG_IRQ;
+	cs->hw.elsa.timer = cs->hw.elsa.base + ELSA_START_TIMER;
+	cs->hw.elsa.ctrl = cs->hw.elsa.base + ELSA_CONTROL;
+	printk(KERN_INFO
+	       "Elsa: %s defined at %#lx IRQ %d\n",
+	       Elsa_Types[cs->subtyp],
+	       cs->hw.elsa.base,
+	       cs->irq);
 
-		if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
-			printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
-			return(0);
-		}
-		if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
-			printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
-			printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
-			printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
-		}
-		cs->hw.elsa.ale  = cs->hw.elsa.base;
-		cs->hw.elsa.isac = cs->hw.elsa.base +1;
-		cs->hw.elsa.hscx = cs->hw.elsa.base +1; 
+	return (1);
+}
+
+static void __devinit
+setup_elsa_pcmcia(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+	u_char val;
+
+	cs->hw.elsa.base = card->para[1];
+	cs->irq = card->para[0];
+	val = readreg(cs->hw.elsa.base + 0, cs->hw.elsa.base + 2, IPAC_ID);
+	if ((val == 1) || (val == 2)) { /* IPAC version 1.1/1.2 */
+		cs->subtyp = ELSA_PCMCIA_IPAC;
+		cs->hw.elsa.ale = cs->hw.elsa.base + 0;
+		cs->hw.elsa.isac = cs->hw.elsa.base + 2;
+		cs->hw.elsa.hscx = cs->hw.elsa.base + 2;
 		test_and_set_bit(HW_IPAC, &cs->HW_Flags);
-		cs->hw.elsa.timer = 0;
-		cs->hw.elsa.trig  = 0;
-		cs->irq_flags |= IRQF_SHARED;
-		printk(KERN_INFO
-		       "Elsa: %s defined at %#lx/0x%x IRQ %d\n",
-		       Elsa_Types[cs->subtyp],
-		       cs->hw.elsa.base,
-		       cs->hw.elsa.cfg,
-		       cs->irq);
+	} else {
+		cs->subtyp = ELSA_PCMCIA;
+		cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE_PCM;
+		cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC_PCM;
+		cs->hw.elsa.hscx = cs->hw.elsa.base + ELSA_HSCX;
+	}
+	cs->hw.elsa.timer = 0;
+	cs->hw.elsa.trig = 0;
+	cs->hw.elsa.ctrl = 0;
+	cs->irq_flags |= IRQF_SHARED;
+	printk(KERN_INFO
+	       "Elsa: %s defined at %#lx IRQ %d\n",
+	       Elsa_Types[cs->subtyp],
+	       cs->hw.elsa.base,
+	       cs->irq);
+}
+
+#ifdef CONFIG_PCI
+static 	struct pci_dev *dev_qs1000 __devinitdata = NULL;
+static 	struct pci_dev *dev_qs3000 __devinitdata = NULL;
+
+static int __devinit
+setup_elsa_pci(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+
+	cs->subtyp = 0;
+	if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+		PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
+		if (pci_enable_device(dev_qs1000))
+			return(0);
+		cs->subtyp = ELSA_QS1000PCI;
+		cs->irq = dev_qs1000->irq;
+		cs->hw.elsa.cfg = pci_resource_start(dev_qs1000, 1);
+		cs->hw.elsa.base = pci_resource_start(dev_qs1000, 3);
+	} else if ((dev_qs3000 = pci_find_device(PCI_VENDOR_ID_ELSA,
+		PCI_DEVICE_ID_ELSA_QS3000, dev_qs3000))) {
+		if (pci_enable_device(dev_qs3000))
+			return(0);
+		cs->subtyp = ELSA_QS3000PCI;
+		cs->irq = dev_qs3000->irq;
+		cs->hw.elsa.cfg = pci_resource_start(dev_qs3000, 1);
+		cs->hw.elsa.base = pci_resource_start(dev_qs3000, 3);
+	} else {
+		printk(KERN_WARNING "Elsa: No PCI card found\n");
+		return(0);
+	}
+	if (!cs->irq) {
+		printk(KERN_WARNING "Elsa: No IRQ for PCI card found\n");
+		return(0);
+	}
+
+	if (!(cs->hw.elsa.base && cs->hw.elsa.cfg)) {
+		printk(KERN_WARNING "Elsa: No IO-Adr for PCI card found\n");
+		return(0);
+	}
+	if ((cs->hw.elsa.cfg & 0xff) || (cs->hw.elsa.base & 0xf)) {
+		printk(KERN_WARNING "Elsa: You may have a wrong PCI bios\n");
+		printk(KERN_WARNING "Elsa: If your system hangs now, read\n");
+		printk(KERN_WARNING "Elsa: Documentation/isdn/README.HiSax\n");
+	}
+	cs->hw.elsa.ale  = cs->hw.elsa.base;
+	cs->hw.elsa.isac = cs->hw.elsa.base +1;
+	cs->hw.elsa.hscx = cs->hw.elsa.base +1; 
+	test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+	cs->hw.elsa.timer = 0;
+	cs->hw.elsa.trig  = 0;
+	cs->irq_flags |= IRQF_SHARED;
+	printk(KERN_INFO
+	       "Elsa: %s defined at %#lx/0x%x IRQ %d\n",
+	       Elsa_Types[cs->subtyp],
+	       cs->hw.elsa.base,
+	       cs->hw.elsa.cfg,
+	       cs->irq);
+
+	return (1);
+}
+
 #else
-		printk(KERN_WARNING "Elsa: Elsa PCI and NO_PCI_BIOS\n");
-		printk(KERN_WARNING "Elsa: unable to config Elsa PCI\n");
-		return (0);
+
+static void __devinit
+setup_elsa_pci(struct IsdnCard *card)
+{
+	return (1);
+}
 #endif /* CONFIG_PCI */
-	} else 
-		return (0);
+
+static int __devinit
+setup_elsa_common(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+	u_char val;
+	int bytecnt;
 
 	switch (cs->subtyp) {
 		case ELSA_PC:
@@ -1104,8 +1130,7 @@
 	   here, it would fail. */
 	if (cs->typ != ISDN_CTYPE_ELSA_PCMCIA && !request_region(cs->hw.elsa.base, bytecnt, "elsa isdn")) {
 		printk(KERN_WARNING
-		       "HiSax: %s config port %#lx-%#lx already in use\n",
-		       CardType[card->typ],
+		       "HiSax: ELSA config port %#lx-%#lx already in use\n",
 		       cs->hw.elsa.base,
 		       cs->hw.elsa.base + bytecnt);
 		return (0);
@@ -1113,8 +1138,7 @@
 	if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
 		if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) {
 			printk(KERN_WARNING
-			       "HiSax: %s pci port %x-%x already in use\n",
-				CardType[card->typ],
+			       "HiSax: ELSA pci port %x-%x already in use\n",
 				cs->hw.elsa.cfg,
 				cs->hw.elsa.cfg + 0x80);
 			release_region(cs->hw.elsa.base, bytecnt);
@@ -1186,3 +1210,41 @@
 	}
 	return (1);
 }
+
+int __devinit
+setup_elsa(struct IsdnCard *card)
+{
+	int rc;
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
+
+	strcpy(tmp, Elsa_revision);
+	printk(KERN_INFO "HiSax: Elsa driver Rev. %s\n", HiSax_getrev(tmp));
+	cs->hw.elsa.ctrl_reg = 0;
+	cs->hw.elsa.status = 0;
+	cs->hw.elsa.MFlag = 0;
+	cs->subtyp = 0;
+
+	if (cs->typ == ISDN_CTYPE_ELSA) {
+		rc = setup_elsa_isa(card);
+		if (!rc)
+			return (0);
+
+	} else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
+		rc = setup_elsa_isapnp(card);
+		if (!rc)
+			return (0);
+
+	} else if (cs->typ == ISDN_CTYPE_ELSA_PCMCIA)
+		setup_elsa_pcmcia(card);
+
+	else if (cs->typ == ISDN_CTYPE_ELSA_PCI) {
+		rc = setup_elsa_pci(card);
+		if (!rc)
+			return (0);
+
+	} else 
+		return (0);
+
+	return setup_elsa_common(card);
+}
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index b1a26e0..60843b3 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -1,12 +1,12 @@
 /*
  * hfc_usb.c
  *
- * $Id: hfc_usb.c,v 2.3.2.13 2006/02/17 17:17:22 mbachem Exp $
+ * $Id: hfc_usb.c,v 2.3.2.20 2007/08/20 14:07:54 mbachem Exp $
  *
  * modular HiSax ISDN driver for Colognechip HFC-S USB chip
  *
- * Authors : Peter Sprenger  (sprenger@moving-bytes.de)
- *           Martin Bachem   (info@colognechip.com)
+ * Authors : Peter Sprenger (sprenger@moving-bytes.de)
+ *           Martin Bachem (m.bachem@gmx.de, info@colognechip.com)
  *
  *           based on the first hfc_usb driver of
  *           Werner Cornelius (werner@isdn-development.de)
@@ -37,24 +37,25 @@
 #include <linux/kernel_stat.h>
 #include <linux/usb.h>
 #include <linux/kernel.h>
+#include <linux/smp_lock.h>
+#include <linux/sched.h>
+#include <linux/moduleparam.h>
 #include "hisax.h"
 #include "hisax_if.h"
 #include "hfc_usb.h"
 
 static const char *hfcusb_revision =
-    "$Revision: 2.3.2.13 $ $Date: 2006/02/17 17:17:22 $ ";
+    "$Revision: 2.3.2.20 $ $Date: 2007/08/20 14:07:54 $ ";
 
 /* Hisax debug support
-* use "modprobe debug=x" where x is bitfield of USB_DBG & ISDN_DBG
+*  debug flags defined in hfc_usb.h as HFCUSB_DBG_[*]
 */
-#ifdef CONFIG_HISAX_DEBUG
-#include <linux/moduleparam.h>
 #define __debug_variable hfc_debug
 #include "hisax_debug.h"
 static u_int debug;
 module_param(debug, uint, 0);
 static int hfc_debug;
-#endif
+
 
 /* private vendor specific data */
 typedef struct {
@@ -63,9 +64,7 @@
 	char *vend_name;	// device name
 } hfcsusb_vdata;
 
-/****************************************/
-/* data defining the devices to be used */
-/****************************************/
+/* VID/PID device list */
 static struct usb_device_id hfcusb_idtab[] = {
 	{
 	 USB_DEVICE(0x0959, 0x2bd0),
@@ -90,49 +89,47 @@
 	 .driver_info = (unsigned long) &((hfcsusb_vdata)
 			  {LED_SCHEME1, {4, 0, 2, 1},
 			   "Stollmann USB TA"}),
-	 },
+	},
 	{
 	 USB_DEVICE(0x0742, 0x2009),
 	 .driver_info = (unsigned long) &((hfcsusb_vdata)
 			  {LED_SCHEME1, {4, 0, 2, 1},
 			   "Aceex USB ISDN TA"}),
-	 },
+	},
 	{
 	 USB_DEVICE(0x0742, 0x200A),
 	 .driver_info = (unsigned long) &((hfcsusb_vdata)
 			  {LED_SCHEME1, {4, 0, 2, 1},
 			   "OEM USB ISDN TA"}),
-	 },
+	},
 	{
 	 USB_DEVICE(0x08e3, 0x0301),
 	 .driver_info = (unsigned long) &((hfcsusb_vdata)
 			  {LED_SCHEME1, {2, 0, 1, 4},
 			   "Olitec USB RNIS"}),
-	 },
+	},
 	{
 	 USB_DEVICE(0x07fa, 0x0846),
 	 .driver_info = (unsigned long) &((hfcsusb_vdata)
 			  {LED_SCHEME1, {0x80, -64, -32, -16},
 			   "Bewan Modem RNIS USB"}),
-	 },
+	},
 	{
 	 USB_DEVICE(0x07fa, 0x0847),
 	 .driver_info = (unsigned long) &((hfcsusb_vdata)
 			  {LED_SCHEME1, {0x80, -64, -32, -16},
 			   "Djinn Numeris USB"}),
-	 },
+	},
 	{
 	 USB_DEVICE(0x07b0, 0x0006),
 	 .driver_info = (unsigned long) &((hfcsusb_vdata)
 			  {LED_SCHEME1, {0x80, -64, -32, -16},
 			   "Twister ISDN TA"}),
-	 },
+	},
 	{ }
 };
 
-/***************************************************************/
 /* structure defining input+output fifos (interrupt/bulk mode) */
-/***************************************************************/
 struct usb_fifo;		/* forward definition */
 typedef struct iso_urb_struct {
 	struct urb *purb;
@@ -140,8 +137,8 @@
 	struct usb_fifo *owner_fifo;	/* pointer to owner fifo */
 } iso_urb_struct;
 
-
 struct hfcusb_data;		/* forward definition */
+
 typedef struct usb_fifo {
 	int fifonum;		/* fifo index attached to this structure */
 	int active;		/* fifo is currently active */
@@ -160,15 +157,12 @@
 	struct hisax_if *hif;	/* hisax interface */
 	int delete_flg;		/* only delete skbuff once */
 	int last_urblen;	/* remember length of last packet */
-
 } usb_fifo;
 
-/*********************************************/
 /* structure holding all data for one device */
-/*********************************************/
 typedef struct hfcusb_data {
 	/* HiSax Interface for loadable Layer1 drivers */
-	struct hisax_d_if d_if;	/* see hisax_if.h */
+	struct hisax_d_if d_if;		/* see hisax_if.h */
 	struct hisax_b_if b_if[2];	/* see hisax_if.h */
 	int protocol;
 
@@ -176,12 +170,13 @@
 	int if_used;		/* used interface number */
 	int alt_used;		/* used alternate config */
 	int ctrl_paksize;	/* control pipe packet size */
-	int ctrl_in_pipe, ctrl_out_pipe;	/* handles for control pipe */
+	int ctrl_in_pipe,	/* handles for control pipe */
+	    ctrl_out_pipe;
 	int cfg_used;		/* configuration index used */
 	int vend_idx;		/* vendor found */
 	int b_mode[2];		/* B-channel mode */
 	int l1_activated;	/* layer 1 activated */
-	int disc_flag;		/* 'true' if device was disonnected to avoid some USB actions */
+	int disc_flag;		/* TRUE if device was disonnected to avoid some USB actions */
 	int packet_size, iso_packet_size;
 
 	/* control pipe background handling */
@@ -208,7 +203,6 @@
 static void collect_rx_frame(usb_fifo * fifo, __u8 * data, int len,
 			     int finish);
 
-
 static inline const char *
 symbolic(struct hfcusb_symbolic_list list[], const int num)
 {
@@ -219,10 +213,6 @@
 	return "<unknown ERROR>";
 }
 
-
-/******************************************************/
-/* start next background transfer for control channel */
-/******************************************************/
 static void
 ctrl_start_transfer(hfcusb_data * hfc)
 {
@@ -240,10 +230,6 @@
 	}
 }				/* ctrl_start_transfer */
 
-/************************************/
-/* queue a control transfer request */
-/* return 0 on success.             */
-/************************************/
 static int
 queue_control_request(hfcusb_data * hfc, __u8 reg, __u8 val, int action)
 {
@@ -260,19 +246,8 @@
 	if (++hfc->ctrl_cnt == 1)
 		ctrl_start_transfer(hfc);
 	return (0);
-}				/* queue_control_request */
-
-static int
-control_action_handler(hfcusb_data * hfc, int reg, int val, int action)
-{
-	if (!action)
-		return (1);	/* no action defined */
-	return (0);
 }
 
-/***************************************************************/
-/* control completion routine handling background control cmds */
-/***************************************************************/
 static void
 ctrl_complete(struct urb *urb)
 {
@@ -282,9 +257,6 @@
 	urb->dev = hfc->dev;
 	if (hfc->ctrl_cnt) {
 		buf = &hfc->ctrl_buff[hfc->ctrl_out_idx];
-		control_action_handler(hfc, buf->hfc_reg, buf->reg_val,
-				       buf->action);
-
 		hfc->ctrl_cnt--;	/* decrement actual count */
 		if (++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE)
 			hfc->ctrl_out_idx = 0;	/* pointer wrap */
@@ -293,9 +265,7 @@
 	}
 }				/* ctrl_complete */
 
-/***************************************************/
 /* write led data to auxport & invert if necessary */
-/***************************************************/
 static void
 write_led(hfcusb_data * hfc, __u8 led_state)
 {
@@ -305,9 +275,6 @@
 	}
 }
 
-/**************************/
-/* handle LED bits        */
-/**************************/
 static void
 set_led_bit(hfcusb_data * hfc, signed short led_bits, int unset)
 {
@@ -324,9 +291,7 @@
 	}
 }
 
-/**************************/
-/* handle LED requests    */
-/**************************/
+/* handle LED requests */
 static void
 handle_led(hfcusb_data * hfc, int event)
 {
@@ -339,85 +304,73 @@
 
 	switch (event) {
 		case LED_POWER_ON:
-			set_led_bit(hfc, driver_info->led_bits[0],
-				    0);
-			set_led_bit(hfc, driver_info->led_bits[1],
-				    1);
-			set_led_bit(hfc, driver_info->led_bits[2],
-				    1);
-			set_led_bit(hfc, driver_info->led_bits[3],
-				    1);
+			set_led_bit(hfc, driver_info->led_bits[0], 0);
+			set_led_bit(hfc, driver_info->led_bits[1], 1);
+			set_led_bit(hfc, driver_info->led_bits[2], 1);
+			set_led_bit(hfc, driver_info->led_bits[3], 1);
 			break;
-		case LED_POWER_OFF:	/* no Power off handling */
+		case LED_POWER_OFF:
+			set_led_bit(hfc, driver_info->led_bits[0], 1);
+			set_led_bit(hfc, driver_info->led_bits[1], 1);
+			set_led_bit(hfc, driver_info->led_bits[2], 1);
+			set_led_bit(hfc, driver_info->led_bits[3], 1);
 			break;
 		case LED_S0_ON:
-			set_led_bit(hfc, driver_info->led_bits[1],
-				    0);
+			set_led_bit(hfc, driver_info->led_bits[1], 0);
 			break;
 		case LED_S0_OFF:
-			set_led_bit(hfc, driver_info->led_bits[1],
-				    1);
+			set_led_bit(hfc, driver_info->led_bits[1], 1);
 			break;
 		case LED_B1_ON:
-			set_led_bit(hfc, driver_info->led_bits[2],
-				    0);
+			set_led_bit(hfc, driver_info->led_bits[2], 0);
 			break;
 		case LED_B1_OFF:
-			set_led_bit(hfc, driver_info->led_bits[2],
-				    1);
+			set_led_bit(hfc, driver_info->led_bits[2], 1);
 			break;
 		case LED_B2_ON:
-			set_led_bit(hfc, driver_info->led_bits[3],
-				    0);
+			set_led_bit(hfc, driver_info->led_bits[3], 0);
 			break;
 		case LED_B2_OFF:
-			set_led_bit(hfc, driver_info->led_bits[3],
-				    1);
+			set_led_bit(hfc, driver_info->led_bits[3], 1);
 			break;
 	}
 	write_led(hfc, hfc->led_state);
 }
 
-/********************************/
-/* called when timer t3 expires */
-/********************************/
+/* ISDN l1 timer T3 expires */
 static void
 l1_timer_expire_t3(hfcusb_data * hfc)
 {
 	hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION,
 			   NULL);
-#ifdef CONFIG_HISAX_DEBUG
-	DBG(ISDN_DBG,
+
+	DBG(HFCUSB_DBG_STATES,
 	    "HFC-S USB: PH_DEACTIVATE | INDICATION sent (T3 expire)");
-#endif
-	hfc->l1_activated = false;
+
+	hfc->l1_activated = 0;
 	handle_led(hfc, LED_S0_OFF);
 	/* deactivate : */
 	queue_control_request(hfc, HFCUSB_STATES, 0x10, 1);
 	queue_control_request(hfc, HFCUSB_STATES, 3, 1);
 }
 
-/********************************/
-/* called when timer t4 expires */
-/********************************/
+/* ISDN l1 timer T4 expires */
 static void
 l1_timer_expire_t4(hfcusb_data * hfc)
 {
 	hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION,
 			   NULL);
-#ifdef CONFIG_HISAX_DEBUG
-	DBG(ISDN_DBG,
+
+	DBG(HFCUSB_DBG_STATES,
 	    "HFC-S USB: PH_DEACTIVATE | INDICATION sent (T4 expire)");
-#endif
-	hfc->l1_activated = false;
+
+	hfc->l1_activated = 0;
 	handle_led(hfc, LED_S0_OFF);
 }
 
-/*****************************/
-/* handle S0 state changes   */
-/*****************************/
+/* S0 state changed */
 static void
-state_handler(hfcusb_data * hfc, __u8 state)
+s0_state_handler(hfcusb_data * hfc, __u8 state)
 {
 	__u8 old_state;
 
@@ -425,38 +378,29 @@
 	if (state == old_state || state < 1 || state > 8)
 		return;
 
-#ifdef CONFIG_HISAX_DEBUG
-	DBG(ISDN_DBG, "HFC-S USB: new S0 state:%d old_state:%d", state,
-	    old_state);
-#endif
+	DBG(HFCUSB_DBG_STATES, "HFC-S USB: S0 statechange(%d -> %d)",
+	    old_state, state);
+
 	if (state < 4 || state == 7 || state == 8) {
 		if (timer_pending(&hfc->t3_timer))
 			del_timer(&hfc->t3_timer);
-#ifdef CONFIG_HISAX_DEBUG
-		DBG(ISDN_DBG, "HFC-S USB: T3 deactivated");
-#endif
+		DBG(HFCUSB_DBG_STATES, "HFC-S USB: T3 deactivated");
 	}
 	if (state >= 7) {
 		if (timer_pending(&hfc->t4_timer))
 			del_timer(&hfc->t4_timer);
-#ifdef CONFIG_HISAX_DEBUG
-		DBG(ISDN_DBG, "HFC-S USB: T4 deactivated");
-#endif
+		DBG(HFCUSB_DBG_STATES, "HFC-S USB: T4 deactivated");
 	}
 
 	if (state == 7 && !hfc->l1_activated) {
 		hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
 				   PH_ACTIVATE | INDICATION, NULL);
-#ifdef CONFIG_HISAX_DEBUG
-		DBG(ISDN_DBG, "HFC-S USB: PH_ACTIVATE | INDICATION sent");
-#endif
-		hfc->l1_activated = true;
+		DBG(HFCUSB_DBG_STATES, "HFC-S USB: PH_ACTIVATE | INDICATION sent");
+		hfc->l1_activated = 1;
 		handle_led(hfc, LED_S0_ON);
 	} else if (state <= 3 /* && activated */ ) {
 		if (old_state == 7 || old_state == 8) {
-#ifdef CONFIG_HISAX_DEBUG
-			DBG(ISDN_DBG, "HFC-S USB: T4 activated");
-#endif
+			DBG(HFCUSB_DBG_STATES, "HFC-S USB: T4 activated");
 			if (!timer_pending(&hfc->t4_timer)) {
 				hfc->t4_timer.expires =
 				    jiffies + (HFC_TIMER_T4 * HZ) / 1000;
@@ -466,18 +410,15 @@
 			hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
 					   PH_DEACTIVATE | INDICATION,
 					   NULL);
-#ifdef CONFIG_HISAX_DEBUG
-			DBG(ISDN_DBG,
+			DBG(HFCUSB_DBG_STATES,
 			    "HFC-S USB: PH_DEACTIVATE | INDICATION sent");
-#endif
-			hfc->l1_activated = false;
+			hfc->l1_activated = 0;
 			handle_led(hfc, LED_S0_OFF);
 		}
 	}
 	hfc->l1_state = state;
 }
 
-/* prepare iso urb */
 static void
 fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe,
 	      void *buf, int num_packets, int packet_size, int interval,
@@ -503,15 +444,16 @@
 }
 
 /* allocs urbs and start isoc transfer with two pending urbs to avoid
-   gaps in the transfer chain */
+ * gaps in the transfer chain
+ */
 static int
 start_isoc_chain(usb_fifo * fifo, int num_packets_per_urb,
 		 usb_complete_t complete, int packet_size)
 {
 	int i, k, errcode;
 
-	printk(KERN_INFO "HFC-S USB: starting ISO-chain for Fifo %i\n",
-	       fifo->fifonum);
+	DBG(HFCUSB_DBG_INIT, "HFC-S USB: starting ISO-URBs for fifo:%d\n",
+	    fifo->fifonum);
 
 	/* allocate Memory for Iso out Urbs */
 	for (i = 0; i < 2; i++) {
@@ -556,10 +498,9 @@
 
 		errcode = usb_submit_urb(fifo->iso[i].purb, GFP_KERNEL);
 		fifo->active = (errcode >= 0) ? 1 : 0;
-		if (errcode < 0) {
-			printk(KERN_INFO "HFC-S USB: %s  URB nr:%d\n",
-			       symbolic(urb_errlist, errcode), i);
-		};
+		if (errcode < 0)
+			printk(KERN_INFO "HFC-S USB: usb_submit_urb URB nr:%d, error(%i): '%s'\n",
+			       i, errcode, symbolic(urb_errlist, errcode));
 	}
 	return (fifo->active);
 }
@@ -572,16 +513,15 @@
 
 	for (i = 0; i < 2; i++) {
 		if (fifo->iso[i].purb) {
-#ifdef CONFIG_HISAX_DEBUG
-			DBG(USB_DBG,
+			DBG(HFCUSB_DBG_INIT,
 			    "HFC-S USB: Stopping iso chain for fifo %i.%i",
 			    fifo->fifonum, i);
-#endif
 			usb_kill_urb(fifo->iso[i].purb);
 			usb_free_urb(fifo->iso[i].purb);
 			fifo->iso[i].purb = NULL;
 		}
 	}
+
 	usb_kill_urb(fifo->urb);
 	usb_free_urb(fifo->urb);
 	fifo->urb = NULL;
@@ -594,9 +534,6 @@
 	ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D
 };
 
-/*****************************************************/
-/* transmit completion routine for all ISO tx fifos */
-/*****************************************************/
 static void
 tx_iso_complete(struct urb *urb)
 {
@@ -607,20 +544,38 @@
 	    errcode;
 	int frame_complete, transp_mode, fifon, status;
 	__u8 threshbit;
-	__u8 threshtable[8] = { 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80 };
 
 	fifon = fifo->fifonum;
 	status = urb->status;
 
 	tx_offset = 0;
 
+	/* ISO transfer only partially completed,
+	   look at individual frame status for details */
+	if (status == -EXDEV) {
+		DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: tx_iso_complete with -EXDEV"
+		    ", urb->status %d, fifonum %d\n",
+		    status, fifon);
+
+		for (k = 0; k < iso_packets[fifon]; ++k) {
+			errcode = urb->iso_frame_desc[k].status;
+			if (errcode)
+				DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: tx_iso_complete "
+				       "packet %i, status: %i\n",
+				       k, errcode);
+		}
+
+		// clear status, so go on with ISO transfers
+		status = 0;
+	}
+
 	if (fifo->active && !status) {
 		transp_mode = 0;
 		if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS)
-			transp_mode = true;
+			transp_mode = 1;
 
 		/* is FifoFull-threshold set for our channel? */
-		threshbit = threshtable[fifon] & hfc->threshold_mask;
+		threshbit = (hfc->threshold_mask & (1 << fifon));
 		num_isoc_packets = iso_packets[fifon];
 
 		/* predict dataflow to avoid fifo overflow */
@@ -635,8 +590,9 @@
 			      tx_iso_complete, urb->context);
 		memset(context_iso_urb->buffer, 0,
 		       sizeof(context_iso_urb->buffer));
-		frame_complete = false;
-		/* Generate next Iso Packets */
+		frame_complete = 0;
+
+		/* Generate next ISO Packets */
 		for (k = 0; k < num_isoc_packets; ++k) {
 			if (fifo->skbuff) {
 				len = fifo->skbuff->len;
@@ -661,7 +617,7 @@
 						/* add 2 byte flags and 16bit CRC at end of ISDN frame */
 						fifo->bit_line += 32;
 					}
-					frame_complete = true;
+					frame_complete = 1;
 				}
 
 				memcpy(context_iso_urb->buffer +
@@ -688,7 +644,7 @@
 			}
 
 			if (frame_complete) {
-				fifo->delete_flg = true;
+				fifo->delete_flg = 1;
 				fifo->hif->l1l2(fifo->hif,
 						PH_DATA | CONFIRM,
 						(void *) (unsigned long) fifo->skbuff->
@@ -696,30 +652,26 @@
 				if (fifo->skbuff && fifo->delete_flg) {
 					dev_kfree_skb_any(fifo->skbuff);
 					fifo->skbuff = NULL;
-					fifo->delete_flg = false;
+					fifo->delete_flg = 0;
 				}
-				frame_complete = false;
+				frame_complete = 0;
 			}
 		}
 		errcode = usb_submit_urb(urb, GFP_ATOMIC);
 		if (errcode < 0) {
 			printk(KERN_INFO
-			       "HFC-S USB: error submitting ISO URB: %d \n",
+			       "HFC-S USB: error submitting ISO URB: %d\n",
 			       errcode);
 		}
 	} else {
 		if (status && !hfc->disc_flag) {
 			printk(KERN_INFO
-			       "HFC-S USB: tx_iso_complete : urb->status %s (%i), fifonum=%d\n",
-			       symbolic(urb_errlist, status), status,
-			       fifon);
+			       "HFC-S USB: tx_iso_complete: error(%i): '%s', fifonum=%d\n",
+			       status, symbolic(urb_errlist, status), fifon);
 		}
 	}
-}				/* tx_iso_complete */
+}
 
-/*****************************************************/
-/* receive completion routine for all ISO tx fifos   */
-/*****************************************************/
 static void
 rx_iso_complete(struct urb *urb)
 {
@@ -731,21 +683,25 @@
 	unsigned int iso_status;
 	__u8 *buf;
 	static __u8 eof[8];
-#ifdef CONFIG_HISAX_DEBUG
-	__u8 i;
-#endif
 
 	fifon = fifo->fifonum;
 	status = urb->status;
 
 	if (urb->status == -EOVERFLOW) {
-#ifdef CONFIG_HISAX_DEBUG
-		DBG(USB_DBG,
-		    "HFC-USB: ignoring USB DATAOVERRUN  for fifo  %i \n",
-		    fifon);
-#endif
+		DBG(HFCUSB_DBG_VERBOSE_USB,
+		    "HFC-USB: ignoring USB DATAOVERRUN fifo(%i)", fifon);
 		status = 0;
 	}
+
+	/* ISO transfer only partially completed,
+	   look at individual frame status for details */
+	if (status == -EXDEV) {
+		DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: rx_iso_complete with -EXDEV "
+		    "urb->status %d, fifonum %d\n",
+		    status, fifon);
+		status = 0;
+	}
+
 	if (fifo->active && !status) {
 		num_isoc_packets = iso_packets[fifon];
 		maxlen = fifo->usb_packet_maxlen;
@@ -754,40 +710,38 @@
 			offset = urb->iso_frame_desc[k].offset;
 			buf = context_iso_urb->buffer + offset;
 			iso_status = urb->iso_frame_desc[k].status;
-#ifdef CONFIG_HISAX_DEBUG
-			if (iso_status && !hfc->disc_flag)
-				DBG(USB_DBG,
-				    "HFC-S USB: ISO packet failure - status:%x",
-				    iso_status);
 
-			if ((fifon == 5) && (debug > 1)) {
-				printk(KERN_INFO
+			if (iso_status && !hfc->disc_flag)
+				DBG(HFCUSB_DBG_VERBOSE_USB,
+				    "HFC-S USB: rx_iso_complete "
+				    "ISO packet %i, status: %i\n",
+				    k, iso_status);
+
+			if (fifon == HFCUSB_D_RX) {
+				DBG(HFCUSB_DBG_VERBOSE_USB,
 				       "HFC-S USB: ISO-D-RX lst_urblen:%2d "
-				       "act_urblen:%2d max-urblen:%2d "
-				       "EOF:0x%0x DATA: ",
+				       "act_urblen:%2d max-urblen:%2d EOF:0x%0x",
 				       fifo->last_urblen, len, maxlen,
 				       eof[5]);
-				for (i = 0; i < len; i++)
-					printk("%.2x ", buf[i]);
-				printk("\n");
+
+				DBG_PACKET(HFCUSB_DBG_VERBOSE_USB, buf, len);
 			}
-#endif
+
 			if (fifo->last_urblen != maxlen) {
 				/* the threshold mask is in the 2nd status byte */
 				hfc->threshold_mask = buf[1];
 				/* care for L1 state only for D-Channel
 				   to avoid overlapped iso completions */
-				if (fifon == 5) {
+				if (fifon == HFCUSB_D_RX) {
 					/* the S0 state is in the upper half
 					   of the 1st status byte */
-					state_handler(hfc, buf[0] >> 4);
+					s0_state_handler(hfc, buf[0] >> 4);
 				}
 				eof[fifon] = buf[0] & 1;
 				if (len > 2)
 					collect_rx_frame(fifo, buf + 2,
 							 len - 2,
-							 (len <
-							  maxlen) ?
+							 (len < maxlen) ?
 							 eof[fifon] : 0);
 			} else {
 				collect_rx_frame(fifo, buf, len,
@@ -804,41 +758,37 @@
 			      rx_iso_complete, urb->context);
 		errcode = usb_submit_urb(urb, GFP_ATOMIC);
 		if (errcode < 0) {
-			printk(KERN_INFO
-			       "HFC-S USB: error submitting ISO URB: %d \n",
+			printk(KERN_ERR
+			       "HFC-S USB: error submitting ISO URB: %d\n",
 			       errcode);
 		}
 	} else {
 		if (status && !hfc->disc_flag) {
-			printk(KERN_INFO
+			printk(KERN_ERR
 			       "HFC-S USB: rx_iso_complete : "
 			       "urb->status %d, fifonum %d\n",
 			       status, fifon);
 		}
 	}
-}				/* rx_iso_complete */
+}
 
-/*****************************************************/
-/* collect data from interrupt or isochron in        */
-/*****************************************************/
+/* collect rx data from INT- and ISO-URBs  */
 static void
 collect_rx_frame(usb_fifo * fifo, __u8 * data, int len, int finish)
 {
 	hfcusb_data *hfc = fifo->hfc;
 	int transp_mode, fifon;
-#ifdef CONFIG_HISAX_DEBUG
-	int i;
-#endif
+
 	fifon = fifo->fifonum;
 	transp_mode = 0;
 	if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS)
-		transp_mode = true;
+		transp_mode = 1;
 
 	if (!fifo->skbuff) {
 		fifo->skbuff = dev_alloc_skb(fifo->max_size + 3);
 		if (!fifo->skbuff) {
-			printk(KERN_INFO
-			       "HFC-S USB: cannot allocate buffer (dev_alloc_skb) fifo:%d\n",
+			printk(KERN_ERR
+			       "HFC-S USB: cannot allocate buffer for fifo(%d)\n",
 			       fifon);
 			return;
 		}
@@ -847,17 +797,11 @@
 		if (fifo->skbuff->len + len < fifo->max_size) {
 			memcpy(skb_put(fifo->skbuff, len), data, len);
 		} else {
-#ifdef CONFIG_HISAX_DEBUG
-			printk(KERN_INFO "HFC-S USB: ");
-			for (i = 0; i < 15; i++)
-				printk("%.2x ",
-				       fifo->skbuff->data[fifo->skbuff->
-							  len - 15 + i]);
-			printk("\n");
-#endif
-			printk(KERN_INFO
-			       "HCF-USB: got frame exceeded fifo->max_size:%d on fifo:%d\n",
+			DBG(HFCUSB_DBG_FIFO_ERR,
+			       "HCF-USB: got frame exceeded fifo->max_size(%d) fifo(%d)",
 			       fifo->max_size, fifon);
+			DBG_SKB(HFCUSB_DBG_VERBOSE_USB, fifo->skbuff);
+			skb_trim(fifo->skbuff, 0);
 		}
 	}
 	if (transp_mode && fifo->skbuff->len >= 128) {
@@ -870,6 +814,13 @@
 	if (finish) {
 		if ((!fifo->skbuff->data[fifo->skbuff->len - 1])
 		    && (fifo->skbuff->len > 3)) {
+
+			if (fifon == HFCUSB_D_RX) {
+				DBG(HFCUSB_DBG_DCHANNEL,
+				    "HFC-S USB: D-RX len(%d)", fifo->skbuff->len);
+				DBG_SKB(HFCUSB_DBG_DCHANNEL, fifo->skbuff);
+			}
+
 			/* remove CRC & status */
 			skb_trim(fifo->skbuff, fifo->skbuff->len - 3);
 			if (fifon == HFCUSB_PCM_RX) {
@@ -882,39 +833,17 @@
 						fifo->skbuff);
 			fifo->skbuff = NULL;	/* buffer was freed from upper layer */
 		} else {
-			if (fifo->skbuff->len > 3) {
-				printk(KERN_INFO
-				       "HFC-S USB: got frame %d bytes but CRC ERROR on fifo:%d!!!\n",
-				       fifo->skbuff->len, fifon);
-#ifdef CONFIG_HISAX_DEBUG
-				if (debug > 1) {
-					printk(KERN_INFO "HFC-S USB: ");
-					for (i = 0; i < 15; i++)
-						printk("%.2x ",
-						       fifo->skbuff->
-						       data[fifo->skbuff->
-							    len - 15 + i]);
-					printk("\n");
-				}
-#endif
-			}
-#ifdef CONFIG_HISAX_DEBUG
-			else {
-				printk(KERN_INFO
-				       "HFC-S USB: frame to small (%d bytes)!!!\n",
-				       fifo->skbuff->len);
-			}
-#endif
+			DBG(HFCUSB_DBG_FIFO_ERR,
+			    "HFC-S USB: ERROR frame len(%d) fifo(%d)",
+			    fifo->skbuff->len, fifon);
+			DBG_SKB(HFCUSB_DBG_VERBOSE_USB, fifo->skbuff);
 			skb_trim(fifo->skbuff, 0);
 		}
 	}
 }
 
-/***********************************************/
-/* receive completion routine for all rx fifos */
-/***********************************************/
 static void
-rx_complete(struct urb *urb)
+rx_int_complete(struct urb *urb)
 {
 	int len;
 	int status;
@@ -922,18 +851,14 @@
 	usb_fifo *fifo = (usb_fifo *) urb->context;
 	hfcusb_data *hfc = fifo->hfc;
 	static __u8 eof[8];
-#ifdef CONFIG_HISAX_DEBUG
-	__u8 i;
-#endif
 
 	urb->dev = hfc->dev;	/* security init */
 
 	fifon = fifo->fifonum;
 	if ((!fifo->active) || (urb->status)) {
-#ifdef CONFIG_HISAX_DEBUG
-		DBG(USB_DBG, "HFC-S USB: RX-Fifo %i is going down (%i)",
+		DBG(HFCUSB_DBG_INIT, "HFC-S USB: RX-Fifo %i is going down (%i)",
 		    fifon, urb->status);
-#endif
+
 		fifo->urb->interval = 0;	/* cancel automatic rescheduling */
 		if (fifo->skbuff) {
 			dev_kfree_skb_any(fifo->skbuff);
@@ -945,22 +870,20 @@
 	buf = fifo->buffer;
 	maxlen = fifo->usb_packet_maxlen;
 
-#ifdef CONFIG_HISAX_DEBUG
-	if ((fifon == 5) && (debug > 1)) {
-		printk(KERN_INFO
-		       "HFC-S USB: INT-D-RX lst_urblen:%2d act_urblen:%2d max-urblen:%2d EOF:0x%0x DATA: ",
-		       fifo->last_urblen, len, maxlen, eof[5]);
-		for (i = 0; i < len; i++)
-			printk("%.2x ", buf[i]);
-		printk("\n");
+	if (fifon == HFCUSB_D_RX) {
+		DBG(HFCUSB_DBG_VERBOSE_USB,
+		       "HFC-S USB: INT-D-RX lst_urblen:%2d "
+		       "act_urblen:%2d max-urblen:%2d EOF:0x%0x",
+		       fifo->last_urblen, len, maxlen,
+		       eof[5]);
+		DBG_PACKET(HFCUSB_DBG_VERBOSE_USB, buf, len);
 	}
-#endif
 
 	if (fifo->last_urblen != fifo->usb_packet_maxlen) {
 		/* the threshold mask is in the 2nd status byte */
 		hfc->threshold_mask = buf[1];
 		/* the S0 state is in the upper half of the 1st status byte */
-		state_handler(hfc, buf[0] >> 4);
+		s0_state_handler(hfc, buf[0] >> 4);
 		eof[fifon] = buf[0] & 1;
 		/* if we have more than the 2 status bytes -> collect data */
 		if (len > 2)
@@ -975,20 +898,19 @@
 	status = usb_submit_urb(urb, GFP_ATOMIC);
 	if (status) {
 		printk(KERN_INFO
-		       "HFC-S USB: error resubmitting URN at rx_complete...\n");
+		       "HFC-S USB: %s error resubmitting URB fifo(%d)\n",
+		       __FUNCTION__, fifon);
 	}
-}				/* rx_complete */
+}
 
-/***************************************************/
-/* start the interrupt transfer for the given fifo */
-/***************************************************/
+/* start initial INT-URB for certain fifo */
 static void
 start_int_fifo(usb_fifo * fifo)
 {
 	int errcode;
 
-	printk(KERN_INFO "HFC-S USB: starting intr IN fifo:%d\n",
-	       fifo->fifonum);
+	DBG(HFCUSB_DBG_INIT, "HFC-S USB: starting RX INT-URB for fifo:%d\n",
+	    fifo->fifonum);
 
 	if (!fifo->urb) {
 		fifo->urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -997,33 +919,28 @@
 	}
 	usb_fill_int_urb(fifo->urb, fifo->hfc->dev, fifo->pipe,
 			 fifo->buffer, fifo->usb_packet_maxlen,
-			 rx_complete, fifo, fifo->intervall);
+			 rx_int_complete, fifo, fifo->intervall);
 	fifo->active = 1;	/* must be marked active */
 	errcode = usb_submit_urb(fifo->urb, GFP_KERNEL);
 	if (errcode) {
-		printk(KERN_INFO
+		printk(KERN_ERR
 		       "HFC-S USB: submit URB error(start_int_info): status:%i\n",
 		       errcode);
 		fifo->active = 0;
 		fifo->skbuff = NULL;
 	}
-}				/* start_int_fifo */
+}
 
-/*****************************/
-/* set the B-channel mode    */
-/*****************************/
 static void
-set_hfcmode(hfcusb_data * hfc, int channel, int mode)
+setup_bchannel(hfcusb_data * hfc, int channel, int mode)
 {
 	__u8 val, idx_table[2] = { 0, 2 };
 
 	if (hfc->disc_flag) {
 		return;
 	}
-#ifdef CONFIG_HISAX_DEBUG
-	DBG(ISDN_DBG, "HFC-S USB: setting channel %d to mode %d", channel,
-	    mode);
-#endif
+	DBG(HFCUSB_DBG_STATES, "HFC-S USB: setting channel %d to mode %d",
+	    channel, mode);
 	hfc->b_mode[channel] = mode;
 
 	/* setup CON_HDLC */
@@ -1080,20 +997,17 @@
 	switch (pr) {
 		case PH_ACTIVATE | REQUEST:
 			if (fifo->fifonum == HFCUSB_D_TX) {
-#ifdef CONFIG_HISAX_DEBUG
-				DBG(ISDN_DBG,
+				DBG(HFCUSB_DBG_STATES,
 				    "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_ACTIVATE | REQUEST");
-#endif
+
 				if (hfc->l1_state != 3
 				    && hfc->l1_state != 7) {
 					hfc->d_if.ifc.l1l2(&hfc->d_if.ifc,
 							   PH_DEACTIVATE |
 							   INDICATION,
 							   NULL);
-#ifdef CONFIG_HISAX_DEBUG
-					DBG(ISDN_DBG,
+					DBG(HFCUSB_DBG_STATES,
 					    "HFC-S USB: PH_DEACTIVATE | INDICATION sent (not state 3 or 7)");
-#endif
 				} else {
 					if (hfc->l1_state == 7) {	/* l1 already active */
 						hfc->d_if.ifc.l1l2(&hfc->
@@ -1103,10 +1017,8 @@
 								   |
 								   INDICATION,
 								   NULL);
-#ifdef CONFIG_HISAX_DEBUG
-						DBG(ISDN_DBG,
+						DBG(HFCUSB_DBG_STATES,
 						    "HFC-S USB: PH_ACTIVATE | INDICATION sent again ;)");
-#endif
 					} else {
 						/* force sending sending INFO1 */
 						queue_control_request(hfc,
@@ -1132,11 +1044,9 @@
 					}
 				}
 			} else {
-#ifdef CONFIG_HISAX_DEBUG
-				DBG(ISDN_DBG,
-				    "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_ACTIVATE | REQUEST");
-#endif
-				set_hfcmode(hfc,
+				DBG(HFCUSB_DBG_STATES,
+				    "HFC_USB: hfc_usb_d_l2l1 B-chan: PH_ACTIVATE | REQUEST");
+				setup_bchannel(hfc,
 					    (fifo->fifonum ==
 					     HFCUSB_B1_TX) ? 0 : 1,
 					    (long) arg);
@@ -1147,18 +1057,12 @@
 			break;
 		case PH_DEACTIVATE | REQUEST:
 			if (fifo->fifonum == HFCUSB_D_TX) {
-#ifdef CONFIG_HISAX_DEBUG
-				DBG(ISDN_DBG,
+				DBG(HFCUSB_DBG_STATES,
 				    "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DEACTIVATE | REQUEST");
-#endif
-				printk(KERN_INFO
-				       "HFC-S USB: ISDN TE device should not deativate...\n");
 			} else {
-#ifdef CONFIG_HISAX_DEBUG
-				DBG(ISDN_DBG,
+				DBG(HFCUSB_DBG_STATES,
 				    "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DEACTIVATE | REQUEST");
-#endif
-				set_hfcmode(hfc,
+				setup_bchannel(hfc,
 					    (fifo->fifonum ==
 					     HFCUSB_B1_TX) ? 0 : 1,
 					    (int) L1_MODE_NULL);
@@ -1171,25 +1075,20 @@
 			if (fifo->skbuff && fifo->delete_flg) {
 				dev_kfree_skb_any(fifo->skbuff);
 				fifo->skbuff = NULL;
-				fifo->delete_flg = false;
+				fifo->delete_flg = 0;
 			}
 			fifo->skbuff = arg;	/* we have a new buffer */
 			break;
 		default:
-			printk(KERN_INFO
-			       "HFC_USB: hfc_usb_d_l2l1: unkown state : %#x\n",
-			       pr);
+			DBG(HFCUSB_DBG_STATES,
+			       "HFC_USB: hfc_usb_d_l2l1: unkown state : %#x", pr);
 			break;
 	}
 }
 
-/***************************************************************************/
-/* usb_init is called once when a new matching device is detected to setup */
-/* main parameters. It registers the driver at the main hisax module.      */
-/* on success 0 is returned.                                               */
-/***************************************************************************/
+/* initial init HFC-S USB chip registers, HiSax interface, USB URBs */
 static int
-usb_init(hfcusb_data * hfc)
+hfc_usb_init(hfcusb_data * hfc)
 {
 	usb_fifo *fifo;
 	int i, err;
@@ -1214,11 +1113,11 @@
 	/* aux = output, reset off */
 	write_usb(hfc, HFCUSB_CIRM, 0x10);
 
-	/* set USB_SIZE to match the wMaxPacketSize for INT or BULK transfers */
+	/* set USB_SIZE to match wMaxPacketSize for INT or BULK transfers */
 	write_usb(hfc, HFCUSB_USB_SIZE,
 		  (hfc->packet_size / 8) | ((hfc->packet_size / 8) << 4));
 
-	/* set USB_SIZE_I to match the wMaxPacketSize for ISO transfers */
+	/* set USB_SIZE_I to match wMaxPacketSize for ISO transfers */
 	write_usb(hfc, HFCUSB_USB_SIZE_I, hfc->iso_packet_size);
 
 	/* enable PCM/GCI master mode */
@@ -1257,8 +1156,8 @@
 	hfc->b_mode[0] = L1_MODE_NULL;
 	hfc->b_mode[1] = L1_MODE_NULL;
 
-	hfc->l1_activated = false;
-	hfc->disc_flag = false;
+	hfc->l1_activated = 0;
+	hfc->disc_flag = 0;
 	hfc->led_state = 0;
 	hfc->led_new_data = 0;
 	hfc->old_led_state = 0;
@@ -1349,11 +1248,9 @@
 	handle_led(hfc, LED_POWER_ON);
 
 	return (0);
-}				/* usb_init */
+}
 
-/*************************************************/
-/* function called to probe a new plugged device */
-/*************************************************/
+/* initial callback for each plugged USB device */
 static int
 hfc_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
@@ -1378,11 +1275,6 @@
 		}
 	}
 
-#ifdef CONFIG_HISAX_DEBUG
-	DBG(USB_DBG,
-	    "HFC-USB: probing interface(%d) actalt(%d) minor(%d)\n", ifnum,
-	    iface->desc.bAlternateSetting, intf->minor);
-#endif
 	printk(KERN_INFO
 	       "HFC-S USB: probing interface(%d) actalt(%d) minor(%d)\n",
 	       ifnum, iface->desc.bAlternateSetting, intf->minor);
@@ -1403,15 +1295,11 @@
 
 			/* check for config EOL element */
 			while (validconf[cfg_used][0]) {
-				cfg_found = true;
+				cfg_found = 1;
 				vcf = validconf[cfg_used];
 				/* first endpoint descriptor */
 				ep = iface->endpoint;
-#ifdef CONFIG_HISAX_DEBUG
-				DBG(USB_DBG,
-				    "HFC-S USB: (if=%d alt=%d cfg_used=%d)\n",
-				    ifnum, probe_alt_setting, cfg_used);
-#endif
+
 				memcpy(cmptbl, vcf, 16 * sizeof(int));
 
 				/* check for all endpoints in this alternate setting */
@@ -1425,7 +1313,7 @@
 						idx++;
 					attr = ep->desc.bmAttributes;
 					if (cmptbl[idx] == EP_NUL) {
-						cfg_found = false;
+						cfg_found = 0;
 					}
 					if (attr == USB_ENDPOINT_XFER_INT
 					    && cmptbl[idx] == EP_INT)
@@ -1438,16 +1326,9 @@
 						cmptbl[idx] = EP_NUL;
 
 					/* check if all INT endpoints match minimum interval */
-					if (attr == USB_ENDPOINT_XFER_INT
-					    && ep->desc.bInterval <
-					    vcf[17]) {
-#ifdef CONFIG_HISAX_DEBUG
-						if (cfg_found)
-							DBG(USB_DBG,
-							    "HFC-S USB: Interrupt Endpoint interval < %d found - skipping config",
-							    vcf[17]);
-#endif
-						cfg_found = false;
+					if ((attr == USB_ENDPOINT_XFER_INT)
+					    && (ep->desc.bInterval < vcf[17])) {
+						cfg_found = 0;
 					}
 					ep++;
 				}
@@ -1455,7 +1336,7 @@
 					/* all entries must be EP_NOP or EP_NUL for a valid config */
 					if (cmptbl[i] != EP_NOP
 					    && cmptbl[i] != EP_NUL)
-						cfg_found = false;
+						cfg_found = 0;
 				}
 				if (cfg_found) {
 					if (cfg_used < small_match) {
@@ -1464,23 +1345,16 @@
 						    probe_alt_setting;
 						iface_used = iface;
 					}
-#ifdef CONFIG_HISAX_DEBUG
-					DBG(USB_DBG,
-					    "HFC-USB: small_match=%x %x\n",
-					    small_match, alt_used);
-#endif
 				}
 				cfg_used++;
 			}
 			alt_idx++;
-		}		/* (alt_idx < intf->num_altsetting) */
+		} /* (alt_idx < intf->num_altsetting) */
 
 		/* found a valid USB Ta Endpint config */
 		if (small_match != 0xffff) {
 			iface = iface_used;
-			if (!
-			    (context =
-			     kzalloc(sizeof(hfcusb_data), GFP_KERNEL)))
+			if (!(context = kzalloc(sizeof(hfcusb_data), GFP_KERNEL)))
 				return (-ENOMEM);	/* got no mem */
 
 			ep = iface->endpoint;
@@ -1613,20 +1487,15 @@
 			    driver_info;
 			printk(KERN_INFO "HFC-S USB: detected \"%s\"\n",
 			       driver_info->vend_name);
-#ifdef CONFIG_HISAX_DEBUG
-			DBG(USB_DBG,
-			    "HFC-S USB: Endpoint-Config: %s (if=%d alt=%d)\n",
+
+			DBG(HFCUSB_DBG_INIT,
+			    "HFC-S USB: Endpoint-Config: %s (if=%d alt=%d), E-Channel(%d)",
 			    conf_str[small_match], context->if_used,
-			    context->alt_used);
-			printk(KERN_INFO
-			       "HFC-S USB: E-channel (\"ECHO:\") logging ");
-			if (validconf[small_match][18])
-				printk(" possible\n");
-			else
-				printk("NOT possible\n");
-#endif
+			    context->alt_used,
+			    validconf[small_match][18]);
+
 			/* init the chip and register the driver */
-			if (usb_init(context)) {
+			if (hfc_usb_init(context)) {
 				usb_kill_urb(context->ctrl_urb);
 				usb_free_urb(context->ctrl_urb);
 				context->ctrl_urb = NULL;
@@ -1643,17 +1512,19 @@
 	return (-EIO);
 }
 
-/****************************************************/
-/* function called when an active device is removed */
-/****************************************************/
+/* callback for unplugged USB device */
 static void
 hfc_usb_disconnect(struct usb_interface
 		   *intf)
 {
 	hfcusb_data *context = usb_get_intfdata(intf);
 	int i;
+
+	handle_led(context, LED_POWER_OFF);
+	schedule_timeout((10 * HZ) / 1000);
+
 	printk(KERN_INFO "HFC-S USB: device disconnect\n");
-	context->disc_flag = true;
+	context->disc_flag = 1;
 	usb_set_intfdata(intf, NULL);
 	if (!context)
 		return;
@@ -1661,25 +1532,22 @@
 		del_timer(&context->t3_timer);
 	if (timer_pending(&context->t4_timer))
 		del_timer(&context->t4_timer);
+
 	/* tell all fifos to terminate */
 	for (i = 0; i < HFCUSB_NUM_FIFOS; i++) {
 		if (context->fifos[i].usb_transfer_mode == USB_ISOC) {
 			if (context->fifos[i].active > 0) {
 				stop_isoc_chain(&context->fifos[i]);
-#ifdef CONFIG_HISAX_DEBUG
-				DBG(USB_DBG,
-				    "HFC-S USB: hfc_usb_disconnect: stopping ISOC chain Fifo no %i",
-				    i);
-#endif
+				DBG(HFCUSB_DBG_INIT,
+				    "HFC-S USB: %s stopping ISOC chain Fifo(%i)",
+				    __FUNCTION__, i);
 			}
 		} else {
 			if (context->fifos[i].active > 0) {
 				context->fifos[i].active = 0;
-#ifdef CONFIG_HISAX_DEBUG
-				DBG(USB_DBG,
-				    "HFC-S USB: hfc_usb_disconnect: unlinking URB for Fifo no %i",
-				    i);
-#endif
+				DBG(HFCUSB_DBG_INIT,
+				    "HFC-S USB: %s unlinking URB for Fifo(%i)",
+				    __FUNCTION__, i);
 			}
 			usb_kill_urb(context->fifos[i].urb);
 			usb_free_urb(context->fifos[i].urb);
@@ -1692,34 +1560,29 @@
 	context->ctrl_urb = NULL;
 	hisax_unregister(&context->d_if);
 	kfree(context);		/* free our structure again */
-}				/* hfc_usb_disconnect */
+}
 
-/************************************/
-/* our driver information structure */
-/************************************/
 static struct usb_driver hfc_drv = {
 	.name  = "hfc_usb",
 	.id_table = hfcusb_idtab,
 	.probe = hfc_usb_probe,
 	.disconnect = hfc_usb_disconnect,
 };
+
 static void __exit
-hfc_usb_exit(void)
+hfc_usb_mod_exit(void)
 {
-#ifdef CONFIG_HISAX_DEBUG
-	DBG(USB_DBG, "HFC-S USB: calling \"hfc_usb_exit\" ...");
-#endif
-	usb_deregister(&hfc_drv);	/* release our driver */
+	usb_deregister(&hfc_drv); /* release our driver */
 	printk(KERN_INFO "HFC-S USB: module removed\n");
 }
 
 static int __init
-hfc_usb_init(void)
+hfc_usb_mod_init(void)
 {
-#ifndef CONFIG_HISAX_DEBUG
-	unsigned int debug = -1;
-#endif
 	char revstr[30], datestr[30], dummy[30];
+#ifndef CONFIG_HISAX_DEBUG
+	hfc_debug = debug;
+#endif
 	sscanf(hfcusb_revision,
 	       "%s %s $ %s %s %s $ ", dummy, revstr,
 	       dummy, datestr, dummy);
@@ -1734,8 +1597,8 @@
 	return (0);
 }
 
-module_init(hfc_usb_init);
-module_exit(hfc_usb_exit);
+module_init(hfc_usb_mod_init);
+module_exit(hfc_usb_mod_exit);
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
diff --git a/drivers/isdn/hisax/hfc_usb.h b/drivers/isdn/hisax/hfc_usb.h
index 471f235..e79f565 100644
--- a/drivers/isdn/hisax/hfc_usb.h
+++ b/drivers/isdn/hisax/hfc_usb.h
@@ -1,8 +1,8 @@
 /*
-* hfc_usb.h
-*
-* $Id: hfc_usb.h,v 4.2 2005/04/07 15:27:17 martinb1 Exp $
-*/
+ * hfc_usb.h
+ *
+ * $Id: hfc_usb.h,v 1.1.2.5 2007/08/20 14:36:03 mbachem Exp $
+ */
 
 #ifndef __HFC_USB_H__
 #define __HFC_USB_H__
@@ -10,25 +10,20 @@
 #define DRIVER_AUTHOR   "Peter Sprenger (sprenger@moving-byters.de)"
 #define DRIVER_DESC     "HFC-S USB based HiSAX ISDN driver"
 
-#define VERBOSE_USB_DEBUG
 
+#define HFC_CTRL_TIMEOUT	20	/* 5ms timeout writing/reading regs */
+#define HFC_TIMER_T3		8000	/* timeout for l1 activation timer */
+#define HFC_TIMER_T4		500	/* time for state change interval */
 
-/***********/
-/* defines */
-/***********/
-#define HFC_CTRL_TIMEOUT 20	/* 5ms timeout writing/reading regs */
-#define HFC_TIMER_T3 8000	/* timeout for l1 activation timer */
-#define HFC_TIMER_T4 500	/* time for state change interval */
+#define HFCUSB_L1_STATECHANGE	0	/* L1 state changed */
+#define HFCUSB_L1_DRX		1	/* D-frame received */
+#define HFCUSB_L1_ERX		2	/* E-frame received */
+#define HFCUSB_L1_DTX		4	/* D-frames completed */
 
-#define HFCUSB_L1_STATECHANGE 0	/* L1 state changed */
-#define HFCUSB_L1_DRX 1		/* D-frame received */
-#define HFCUSB_L1_ERX 2		/* E-frame received */
-#define HFCUSB_L1_DTX 4		/* D-frames completed */
+#define MAX_BCH_SIZE		2048	/* allowed B-channel packet size */
 
-#define MAX_BCH_SIZE 2048	/* allowed B-channel packet size */
-
-#define HFCUSB_RX_THRESHOLD 64	/* threshold for fifo report bit rx */
-#define HFCUSB_TX_THRESHOLD 64	/* threshold for fifo report bit tx */
+#define HFCUSB_RX_THRESHOLD	64	/* threshold for fifo report bit rx */
+#define HFCUSB_TX_THRESHOLD	64	/* threshold for fifo report bit tx */
 
 #define HFCUSB_CHIP_ID		0x16	/* Chip ID register index */
 #define HFCUSB_CIRM		0x00	/* cirm register index */
@@ -52,9 +47,8 @@
 
 #define HFCUSB_CHIPID		0x40	/* ID value of HFC-S USB */
 
-/******************/
+
 /* fifo registers */
-/******************/
 #define HFCUSB_NUM_FIFOS	8	/* maximum number of fifos */
 #define HFCUSB_B1_TX		0	/* index for B1 transmit bulk/int */
 #define HFCUSB_B1_RX		1	/* index for B1 receive bulk/int */
@@ -66,9 +60,9 @@
 #define HFCUSB_PCM_RX		7
 
 /*
-* used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just
-* supports ISO out, while the Cologne Chip EVAL TA just supports BULK out
-*/
+ * used to switch snd_transfer_mode for different TA modes e.g. the Billion USB TA just
+ * supports ISO out, while the Cologne Chip EVAL TA just supports BULK out
+ */
 #define USB_INT		0
 #define USB_BULK	1
 #define USB_ISOC	2
@@ -77,49 +71,36 @@
 #define ISOC_PACKETS_B	8
 #define ISO_BUFFER_SIZE	128
 
-// ISO send definitions
+/* Fifo flow Control for TX ISO */
 #define SINK_MAX	68
 #define SINK_MIN	48
 #define SINK_DMIN	12
 #define SINK_DMAX	18
 #define BITLINE_INF	(-64*8)
 
-
-/**********/
-/* macros */
-/**********/
+/* HFC-S USB register access by Control-URSs */
 #define write_usb(a,b,c)usb_control_msg((a)->dev,(a)->ctrl_out_pipe,0,0x40,(c),(b),NULL,0,HFC_CTRL_TIMEOUT)
 #define read_usb(a,b,c) usb_control_msg((a)->dev,(a)->ctrl_in_pipe,1,0xC0,0,(b),(c),1,HFC_CTRL_TIMEOUT)
-
-
-/*******************/
-/* Debugging Flags */
-/*******************/
-#define USB_DBG   1
-#define ISDN_DBG  2
-
-
-/* *********************/
-/* USB related defines */
-/***********************/
 #define HFC_CTRL_BUFSIZE 32
 
-
-
-/*************************************************/
 /* entry and size of output/input control buffer */
-/*************************************************/
 typedef struct {
 	__u8 hfc_reg;		/* register number */
 	__u8 reg_val;		/* value to be written (or read) */
 	int action;		/* data for action handler */
 } ctrl_buft;
 
+/* Debugging Flags */
+#define HFCUSB_DBG_INIT		0x0001
+#define HFCUSB_DBG_STATES	0x0002
+#define HFCUSB_DBG_DCHANNEL	0x0080
+#define HFCUSB_DBG_FIFO_ERR	0x4000
+#define HFCUSB_DBG_VERBOSE_USB	0x8000
 
-/********************/
-/* URB error codes: */
-/********************/
-/* Used to represent a list of values and their respective symbolic names */
+/*
+ * URB error codes:
+ * Used to represent a list of values and their respective symbolic names
+ */
 struct hfcusb_symbolic_list {
 	const int num;
 	const char *name;
@@ -134,20 +115,20 @@
 	{-ENXIO, "URB already queued"},
 	{-EFBIG, "Too much ISO frames requested"},
 	{-ENOSR, "Buffer error (overrun)"},
-	{-EPIPE, "Specified endpoint is stalled"},
+	{-EPIPE, "Specified endpoint is stalled (device not responding)"},
 	{-EOVERFLOW, "Babble (bad cable?)"},
 	{-EPROTO, "Bit-stuff error (bad cable?)"},
-	{-EILSEQ, "CRC or missing token"},
-	{-ETIME, "Device did not respond"},
+	{-EILSEQ, "CRC/Timeout"},
+	{-ETIMEDOUT, "NAK (device does not respond)"},
 	{-ESHUTDOWN, "Device unplugged"},
 	{-1, NULL}
 };
 
 
-/*****************************************************/
-/* device dependant information to support different */
-/* ISDN Ta's using the HFC-S USB chip                */
-/*****************************************************/
+/*
+ * device dependant information to support different
+ * ISDN Ta's using the HFC-S USB chip
+ */
 
 /* USB descriptor need to contain one of the following EndPoint combination: */
 #define CNF_4INT3ISO	1	// 4 INT IN, 3 ISO OUT
@@ -155,16 +136,19 @@
 #define CNF_4ISO3ISO	3	// 4 ISO IN, 3 ISO OUT
 #define CNF_3ISO3ISO	4	// 3 ISO IN, 3 ISO OUT
 
-#define EP_NUL 1		// Endpoint at this position not allowed
-#define EP_NOP 2		// all type of endpoints allowed at this position
-#define EP_ISO 3		// Isochron endpoint mandatory at this position
-#define EP_BLK 4		// Bulk endpoint mandatory at this position
-#define EP_INT 5		// Interrupt endpoint mandatory at this position
+#define EP_NUL	1	// Endpoint at this position not allowed
+#define EP_NOP	2	// all type of endpoints allowed at this position
+#define EP_ISO	3	// Isochron endpoint mandatory at this position
+#define EP_BLK	4	// Bulk endpoint mandatory at this position
+#define EP_INT	5	// Interrupt endpoint mandatory at this position
 
-/* this array represents all endpoints possible in the HCF-USB the last
-* 3 entries are the configuration number, the minimum interval for
-* Interrupt endpoints & boolean if E-channel logging possible
-*/
+/*
+ * List of all supported endpoint configuration sets, used to find the
+ * best matching endpoint configuration within a devices' USB descriptor.
+ * We need at least 3 RX endpoints, and 3 TX endpoints, either
+ * INT-in and ISO-out, or ISO-in and ISO-out)
+ * with 4 RX endpoints even E-Channel logging is possible
+ */
 static int validconf[][19] = {
 	// INT in, ISO out config
 	{EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NOP, EP_INT,
@@ -193,7 +177,6 @@
 };
 #endif
 
-
 typedef struct {
 	int vendor;		// vendor id
 	int prod_id;		// product id
@@ -202,9 +185,9 @@
 	signed short led_bits[8];	// array of 8 possible LED bitmask settings
 } vendor_data;
 
-#define LED_OFF      0		// no LED support
-#define LED_SCHEME1  1		// LED standard scheme
-#define LED_SCHEME2  2		// not used yet...
+#define LED_OFF		0	// no LED support
+#define LED_SCHEME1	1	// LED standard scheme
+#define LED_SCHEME2	2	// not used yet...
 
 #define LED_POWER_ON	1
 #define LED_POWER_OFF	2
@@ -217,11 +200,8 @@
 #define LED_B2_OFF	9
 #define LED_B2_DATA	10
 
-#define LED_NORMAL   0		// LEDs are normal
-#define LED_INVERTED 1		// LEDs are inverted
-
-/* time in ms to perform a Flashing LED when B-Channel has traffic */
-#define LED_TIME      250
+#define LED_NORMAL   	0	// LEDs are normal
+#define LED_INVERTED 	1	// LEDs are inverted
 
 
-#endif				// __HFC_USB_H__
+#endif	// __HFC_USB_H__
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index ad06f3c..03dfc32 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -518,8 +518,6 @@
 	return(0);
 }
 
-static struct pci_dev *dev_sedl __devinitdata = NULL;
-
 #ifdef __ISAPNP__
 static struct isapnp_device_id sedl_ids[] __devinitdata = {
 	{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
@@ -533,15 +531,158 @@
 
 static struct isapnp_device_id *ipid __devinitdata = &sedl_ids[0];
 static struct pnp_card *pnp_c __devinitdata = NULL;
-#endif
+
+static int __devinit
+setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
+{
+	struct IsdnCardState *cs = card->cs;
+	struct pnp_dev *pnp_d;
+
+	if (!isapnp_present())
+		return -1;
+
+	while(ipid->card_vendor) {
+		if ((pnp_c = pnp_find_card(ipid->card_vendor,
+			ipid->card_device, pnp_c))) {
+			pnp_d = NULL;
+			if ((pnp_d = pnp_find_dev(pnp_c,
+				ipid->vendor, ipid->function, pnp_d))) {
+				int err;
+
+				printk(KERN_INFO "HiSax: %s detected\n",
+					(char *)ipid->driver_data);
+				pnp_disable_dev(pnp_d);
+				err = pnp_activate_dev(pnp_d);
+				if (err<0) {
+					printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
+						__FUNCTION__, err);
+					return(0);
+				}
+				card->para[1] = pnp_port_start(pnp_d, 0);
+				card->para[0] = pnp_irq(pnp_d, 0);
+
+				if (!card->para[0] || !card->para[1]) {
+					printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
+						card->para[0], card->para[1]);
+					pnp_disable_dev(pnp_d);
+					return(0);
+				}
+				cs->hw.sedl.cfg_reg = card->para[1];
+				cs->irq = card->para[0];
+				if (ipid->function == ISAPNP_FUNCTION(0x2)) {
+					cs->subtyp = SEDL_SPEED_FAX;
+					cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+					*bytecnt = 16;
+				} else {
+					cs->subtyp = SEDL_SPEED_CARD_WIN;
+					cs->hw.sedl.chip = SEDL_CHIP_TEST;
+				}
+
+				return (1);
+			} else {
+				printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
+				return(0);
+			}
+		}
+		ipid++;
+		pnp_c = NULL;
+	} 
+
+	printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
+	return -1;
+}
+#else
+
+static int __devinit
+setup_sedlbauer_isapnp(struct IsdnCard *card, int *bytecnt)
+{
+	return -1;
+}
+#endif /* __ISAPNP__ */
+
+#ifdef CONFIG_PCI
+static struct pci_dev *dev_sedl __devinitdata = NULL;
+
+static int __devinit
+setup_sedlbauer_pci(struct IsdnCard *card)
+{
+	struct IsdnCardState *cs = card->cs;
+	u16 sub_vendor_id, sub_id;
+
+	if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+			PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
+		if (pci_enable_device(dev_sedl))
+			return(0);
+		cs->irq = dev_sedl->irq;
+		if (!cs->irq) {
+			printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
+			return(0);
+		}
+		cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
+	} else {
+		printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
+		return(0);
+	}
+	cs->irq_flags |= IRQF_SHARED;
+	cs->hw.sedl.bus = SEDL_BUS_PCI;
+	sub_vendor_id = dev_sedl->subsystem_vendor;
+	sub_id = dev_sedl->subsystem_device;
+	printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
+		sub_vendor_id, sub_id);
+	printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
+		cs->hw.sedl.cfg_reg);
+	if (sub_id != PCI_SUB_ID_SEDLBAUER) {
+		printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
+		return(0);
+	}
+	if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
+		cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+		cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
+	} else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
+		cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+		cs->subtyp = SEDL_SPEEDFAX_PCI;
+	} else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
+		cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+		cs->subtyp = HST_SAPHIR3;
+	} else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
+		cs->hw.sedl.chip = SEDL_CHIP_IPAC;
+		cs->subtyp = SEDL_SPEED_PCI;
+	} else {
+		printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
+			sub_vendor_id);
+		return(0);
+	}
+
+	cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
+	cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
+	byteout(cs->hw.sedl.cfg_reg, 0xff);
+	byteout(cs->hw.sedl.cfg_reg, 0x00);
+	byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
+	byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */
+	byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
+	mdelay(2);
+	byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
+	mdelay(10);
+
+	return (1);
+}
+
+#else
+
+static int __devinit
+setup_sedlbauer_pci(struct IsdnCard *card)
+{
+	return (1);
+}
+
+#endif /* CONFIG_PCI */
 
 int __devinit
 setup_sedlbauer(struct IsdnCard *card)
 {
-	int bytecnt, ver, val;
+	int bytecnt = 8, ver, val, rc;
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
-	u16 sub_vendor_id, sub_id;
 
 	strcpy(tmp, Sedlbauer_revision);
 	printk(KERN_INFO "HiSax: Sedlbauer driver Rev. %s\n", HiSax_getrev(tmp));
@@ -569,124 +710,21 @@
 			bytecnt = 16;
 		}
 	} else {
-#ifdef __ISAPNP__
-		if (isapnp_present()) {
-			struct pnp_dev *pnp_d;
-			while(ipid->card_vendor) {
-				if ((pnp_c = pnp_find_card(ipid->card_vendor,
-					ipid->card_device, pnp_c))) {
-					pnp_d = NULL;
-					if ((pnp_d = pnp_find_dev(pnp_c,
-						ipid->vendor, ipid->function, pnp_d))) {
-						int err;
+		rc = setup_sedlbauer_isapnp(card, &bytecnt);
+		if (!rc)
+			return (0);
+		if (rc > 0)
+			goto ready;
 
-						printk(KERN_INFO "HiSax: %s detected\n",
-							(char *)ipid->driver_data);
-						pnp_disable_dev(pnp_d);
-						err = pnp_activate_dev(pnp_d);
-						if (err<0) {
-							printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
-								__FUNCTION__, err);
-							return(0);
-						}
-						card->para[1] = pnp_port_start(pnp_d, 0);
-						card->para[0] = pnp_irq(pnp_d, 0);
+		/* Probe for Sedlbauer speed pci */
+		rc = setup_sedlbauer_pci(card);
+		if (!rc)
+			return (0);
 
-						if (!card->para[0] || !card->para[1]) {
-							printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
-								card->para[0], card->para[1]);
-							pnp_disable_dev(pnp_d);
-							return(0);
-						}
-						cs->hw.sedl.cfg_reg = card->para[1];
-						cs->irq = card->para[0];
-						if (ipid->function == ISAPNP_FUNCTION(0x2)) {
-							cs->subtyp = SEDL_SPEED_FAX;
-							cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
-							bytecnt = 16;
-						} else {
-							cs->subtyp = SEDL_SPEED_CARD_WIN;
-							cs->hw.sedl.chip = SEDL_CHIP_TEST;
-						}
-						goto ready;
-					} else {
-						printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
-						return(0);
-					}
-				}
-				ipid++;
-				pnp_c = NULL;
-			} 
-			if (!ipid->card_vendor) {
-				printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
-			}
-		}
-#endif
-/* Probe for Sedlbauer speed pci */
-#ifdef CONFIG_PCI
-		if ((dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
-				PCI_DEVICE_ID_TIGERJET_100, dev_sedl))) {
-			if (pci_enable_device(dev_sedl))
-				return(0);
-			cs->irq = dev_sedl->irq;
-			if (!cs->irq) {
-				printk(KERN_WARNING "Sedlbauer: No IRQ for PCI card found\n");
-				return(0);
-			}
-			cs->hw.sedl.cfg_reg = pci_resource_start(dev_sedl, 0);
-		} else {
-			printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
-			return(0);
-		}
-		cs->irq_flags |= IRQF_SHARED;
-		cs->hw.sedl.bus = SEDL_BUS_PCI;
-		sub_vendor_id = dev_sedl->subsystem_vendor;
-		sub_id = dev_sedl->subsystem_device;
-		printk(KERN_INFO "Sedlbauer: PCI subvendor:%x subid %x\n",
-			sub_vendor_id, sub_id);
-		printk(KERN_INFO "Sedlbauer: PCI base adr %#x\n",
-			cs->hw.sedl.cfg_reg);
-		if (sub_id != PCI_SUB_ID_SEDLBAUER) {
-			printk(KERN_ERR "Sedlbauer: unknown sub id %#x\n", sub_id);
-			return(0);
-		}
-		if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PYRAMID) {
-			cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
-			cs->subtyp = SEDL_SPEEDFAX_PYRAMID;
-		} else if (sub_vendor_id == PCI_SUBVENDOR_SPEEDFAX_PCI) {
-			cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
-			cs->subtyp = SEDL_SPEEDFAX_PCI;
-		} else if (sub_vendor_id == PCI_SUBVENDOR_HST_SAPHIR3) {
-			cs->hw.sedl.chip = SEDL_CHIP_IPAC;
-			cs->subtyp = HST_SAPHIR3;
-		} else if (sub_vendor_id == PCI_SUBVENDOR_SEDLBAUER_PCI) {
-			cs->hw.sedl.chip = SEDL_CHIP_IPAC;
-			cs->subtyp = SEDL_SPEED_PCI;
-		} else {
-			printk(KERN_ERR "Sedlbauer: unknown sub vendor id %#x\n",
-				sub_vendor_id);
-			return(0);
-		}
 		bytecnt = 256;
-		cs->hw.sedl.reset_on = SEDL_ISAR_PCI_ISAR_RESET_ON;
-		cs->hw.sedl.reset_off = SEDL_ISAR_PCI_ISAR_RESET_OFF;
-		byteout(cs->hw.sedl.cfg_reg, 0xff);
-		byteout(cs->hw.sedl.cfg_reg, 0x00);
-		byteout(cs->hw.sedl.cfg_reg+ 2, 0xdd);
-		byteout(cs->hw.sedl.cfg_reg+ 5, 0); /* disable all IRQ */
-		byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_on);
-		mdelay(2);
-		byteout(cs->hw.sedl.cfg_reg +3, cs->hw.sedl.reset_off);
-		mdelay(10);
-#else
-		printk(KERN_WARNING "Sedlbauer: NO_PCI_BIOS\n");
-		return (0);
-#endif /* CONFIG_PCI */
 	}	
 
-#ifdef __ISAPNP__
 ready:	
-#endif
 
 	/* In case of the sedlbauer pcmcia card, this region is in use,
 	 * reserved for us by the card manager. So we do not check it
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
index d09f6d0..4393003 100644
--- a/drivers/isdn/hisax/telespci.c
+++ b/drivers/isdn/hisax/telespci.c
@@ -295,11 +295,12 @@
 #ifdef __BIG_ENDIAN
 #error "not running on big endian machines now"
 #endif
+
 	strcpy(tmp, telespci_revision);
 	printk(KERN_INFO "HiSax: Teles/PCI driver Rev. %s\n", HiSax_getrev(tmp));
 	if (cs->typ != ISDN_CTYPE_TELESPCI)
 		return (0);
-#ifdef CONFIG_PCI
+
 	if ((dev_tel = pci_find_device (PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36120, dev_tel))) {
 		if (pci_enable_device(dev_tel))
 			return(0);
@@ -317,11 +318,6 @@
 		printk(KERN_WARNING "TelesPCI: No PCI card found\n");
 		return(0);
 	}
-#else
-	printk(KERN_WARNING "HiSax: Teles/PCI and NO_PCI_BIOS\n");
-	printk(KERN_WARNING "HiSax: Teles/PCI unable to config\n");
-	return (0);
-#endif /* CONFIG_PCI */
 
 	/* Initialize Zoran PCI controller */
 	writel(0x00000000, cs->hw.teles0.membase + 0x28);
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index 3aeceaf..39129b9 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -1009,7 +1009,7 @@
 	printk(KERN_INFO "HiSax: W6692 driver Rev. %s\n", HiSax_getrev(tmp));
 	if (cs->typ != ISDN_CTYPE_W6692)
 		return (0);
-#ifdef CONFIG_PCI
+
 	while (id_list[id_idx].vendor_id) {
 		dev_w6692 = pci_find_device(id_list[id_idx].vendor_id,
 					    id_list[id_idx].device_id,
@@ -1061,11 +1061,6 @@
 		       cs->hw.w6692.iobase + 255);
 		return (0);
 	}
-#else
-	printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n");
-	printk(KERN_WARNING "HiSax: W6692 unable to config\n");
-	return (0);
-#endif				/* CONFIG_PCI */
 
 	printk(KERN_INFO
 	       "HiSax: %s config irq:%d I/O:%x\n",
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c
index 9e01748..b7cc5c2 100644
--- a/drivers/isdn/hysdn/hysdn_init.c
+++ b/drivers/isdn/hysdn/hysdn_init.c
@@ -20,10 +20,15 @@
 #include "hysdn_defs.h"
 
 static struct pci_device_id hysdn_pci_tbl[] = {
-	{PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO},
-	{PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2},
-	{PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO},
-	{PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX, PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO},
+	{ PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+	  PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_METRO, 0, 0, BD_METRO },
+	{ PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+	  PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, 0, 0, BD_CHAMP2 },
+	{ PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+	  PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, 0, 0, BD_ERGO },
+	{ PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
+	  PCI_ANY_ID, PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, 0, 0, BD_ERGO },
+
 	{ }				/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, hysdn_pci_tbl);
@@ -34,128 +39,7 @@
 static char *hysdn_init_revision = "$Revision: 1.6.6.6 $";
 static int cardmax;		/* number of found cards */
 hysdn_card *card_root = NULL;	/* pointer to first card */
-
-/**********************************************/
-/* table assigning PCI-sub ids to board types */
-/* the last entry contains all 0              */
-/**********************************************/
-static struct {
-	unsigned short subid;		/* PCI sub id */
-	unsigned char cardtyp;		/* card type assigned */
-} pci_subid_map[] = {
-
-	{
-		PCI_SUBDEVICE_ID_HYPERCOPE_METRO, BD_METRO
-	},
-	{
-		PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2, BD_CHAMP2
-	},
-	{
-		PCI_SUBDEVICE_ID_HYPERCOPE_ERGO, BD_ERGO
-	},
-	{
-		PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO, BD_ERGO
-	},
-	{
-		0, 0
-	}			/* terminating entry */
-};
-
-
-/*********************************************************************/
-/* search_cards searches for available cards in the pci config data. */
-/* If a card is found, the card structure is allocated and the cards */
-/* ressources are reserved. cardmax is incremented.                  */
-/*********************************************************************/
-static void
-search_cards(void)
-{
-	struct pci_dev *akt_pcidev = NULL;
-	hysdn_card *card, *card_last;
-	int i;
-
-	card_root = NULL;
-	card_last = NULL;
-	while ((akt_pcidev = pci_find_device(PCI_VENDOR_ID_HYPERCOPE, PCI_DEVICE_ID_HYPERCOPE_PLX,
-					     akt_pcidev)) != NULL) {
-		if (pci_enable_device(akt_pcidev))
-			continue;
-
-		if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) {
-			printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
-			return;
-		}
-		card->myid = cardmax;	/* set own id */
-		card->bus = akt_pcidev->bus->number;
-		card->devfn = akt_pcidev->devfn;	/* slot + function */
-		card->subsysid = akt_pcidev->subsystem_device;
-		card->irq = akt_pcidev->irq;
-		card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE);
-		card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE);
-		card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE);
-		card->brdtype = BD_NONE;	/* unknown */
-		card->debug_flags = DEF_DEB_FLAGS;	/* set default debug */
-		card->faxchans = 0;	/* default no fax channels */
-		card->bchans = 2;	/* and 2 b-channels */
-		for (i = 0; pci_subid_map[i].subid; i++)
-			if (pci_subid_map[i].subid == card->subsysid) {
-				card->brdtype = pci_subid_map[i].cardtyp;
-				break;
-			}
-		if (card->brdtype != BD_NONE) {
-			if (ergo_inithardware(card)) {
-				printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
-				kfree(card);
-				continue;
-			}
-		} else {
-			printk(KERN_WARNING "HYSDN: unknown card id 0x%04x\n", card->subsysid);
-			kfree(card);	/* release mem */
-			continue;
-		}
-		cardmax++;
-		card->next = NULL;	/*end of chain */
-		if (card_last)
-			card_last->next = card;		/* pointer to next card */
-		else
-			card_root = card;
-		card_last = card;	/* new chain end */
-	}			/* device found */
-}				/* search_cards */
-
-/************************************************************************************/
-/* free_resources frees the acquired PCI resources and returns the allocated memory */
-/************************************************************************************/
-static void
-free_resources(void)
-{
-	hysdn_card *card;
-
-	while (card_root) {
-		card = card_root;
-		if (card->releasehardware)
-			card->releasehardware(card);	/* free all hardware resources */
-		card_root = card_root->next;	/* remove card from chain */
-		kfree(card);	/* return mem */
-
-	}			/* while card_root */
-}				/* free_resources */
-
-/**************************************************************************/
-/* stop_cards disables (hardware resets) all cards and disables interrupt */
-/**************************************************************************/
-static void
-stop_cards(void)
-{
-	hysdn_card *card;
-
-	card = card_root;	/* first in chain */
-	while (card) {
-		if (card->stopcard)
-			card->stopcard(card);
-		card = card->next;	/* remove card from chain */
-	}			/* while card */
-}				/* stop_cards */
+static hysdn_card *card_last = NULL;	/* pointer to first card */
 
 
 /****************************************************************************/
@@ -191,31 +75,138 @@
 /* and the module is added to the list in /proc/modules, otherwise an error */
 /* is assumed and the module will not be kept in memory.                    */
 /****************************************************************************/
+
+static int __devinit hysdn_pci_init_one(struct pci_dev *akt_pcidev,
+					const struct pci_device_id *ent)
+{
+	hysdn_card *card;
+	int rc;
+
+	rc = pci_enable_device(akt_pcidev);
+	if (rc)
+		return rc;
+
+	if (!(card = kzalloc(sizeof(hysdn_card), GFP_KERNEL))) {
+		printk(KERN_ERR "HYSDN: unable to alloc device mem \n");
+		rc = -ENOMEM;
+		goto err_out;
+	}
+	card->myid = cardmax;	/* set own id */
+	card->bus = akt_pcidev->bus->number;
+	card->devfn = akt_pcidev->devfn;	/* slot + function */
+	card->subsysid = akt_pcidev->subsystem_device;
+	card->irq = akt_pcidev->irq;
+	card->iobase = pci_resource_start(akt_pcidev, PCI_REG_PLX_IO_BASE);
+	card->plxbase = pci_resource_start(akt_pcidev, PCI_REG_PLX_MEM_BASE);
+	card->membase = pci_resource_start(akt_pcidev, PCI_REG_MEMORY_BASE);
+	card->brdtype = BD_NONE;	/* unknown */
+	card->debug_flags = DEF_DEB_FLAGS;	/* set default debug */
+	card->faxchans = 0;	/* default no fax channels */
+	card->bchans = 2;	/* and 2 b-channels */
+	card->brdtype = ent->driver_data;
+
+	if (ergo_inithardware(card)) {
+		printk(KERN_WARNING "HYSDN: card at io 0x%04x already in use\n", card->iobase);
+		rc = -EBUSY;
+		goto err_out_card;
+	}
+
+	cardmax++;
+	card->next = NULL;	/*end of chain */
+	if (card_last)
+		card_last->next = card;		/* pointer to next card */
+	else
+		card_root = card;
+	card_last = card;	/* new chain end */
+
+	pci_set_drvdata(akt_pcidev, card);
+	return 0;
+
+err_out_card:
+	kfree(card);
+err_out:
+	pci_disable_device(akt_pcidev);
+	return rc;
+}
+
+static void __devexit hysdn_pci_remove_one(struct pci_dev *akt_pcidev)
+{
+	hysdn_card *card = pci_get_drvdata(akt_pcidev);
+
+	pci_set_drvdata(akt_pcidev, NULL);
+
+	if (card->stopcard)
+		card->stopcard(card);
+
+#ifdef CONFIG_HYSDN_CAPI
+	hycapi_capi_release(card);
+#endif
+
+	if (card->releasehardware)
+		card->releasehardware(card);   /* free all hardware resources */
+
+	if (card == card_root) {
+		card_root = card_root->next;
+		if (!card_root)
+			card_last = NULL;
+	} else {
+		hysdn_card *tmp = card_root;
+		while (tmp) {
+			if (tmp->next == card)
+				tmp->next = card->next;
+			card_last = tmp;
+			tmp = tmp->next;
+		}
+	}
+
+	kfree(card);
+	pci_disable_device(akt_pcidev);
+}
+
+static struct pci_driver hysdn_pci_driver = {
+	.name		= "hysdn",
+	.id_table	= hysdn_pci_tbl,
+	.probe		= hysdn_pci_init_one,
+	.remove		= __devexit_p(hysdn_pci_remove_one),
+};
+
+static int hysdn_have_procfs;
+
 static int __init
 hysdn_init(void)
 {
 	char tmp[50];
+	int rc;
 
 	strcpy(tmp, hysdn_init_revision);
 	printk(KERN_NOTICE "HYSDN: module Rev: %s loaded\n", hysdn_getrev(tmp));
 	strcpy(tmp, hysdn_net_revision);
 	printk(KERN_NOTICE "HYSDN: network interface Rev: %s \n", hysdn_getrev(tmp));
-	search_cards();
+
+	rc = pci_register_driver(&hysdn_pci_driver);
+	if (rc)
+		return rc;
+
 	printk(KERN_INFO "HYSDN: %d card(s) found.\n", cardmax);
 
-	if (hysdn_procconf_init()) {
-		free_resources();	/* proc file_sys not created */
-		return (-1);
-	}
+	if (!hysdn_procconf_init())
+		hysdn_have_procfs = 1;
+
 #ifdef CONFIG_HYSDN_CAPI
 	if(cardmax > 0) {
 		if(hycapi_init()) {
 			printk(KERN_ERR "HYCAPI: init failed\n");
-			return(-1);
+
+			if (hysdn_have_procfs)
+				hysdn_procconf_release();
+
+			pci_unregister_driver(&hysdn_pci_driver);
+			return -ESPIPE;
 		}
 	}
 #endif /* CONFIG_HYSDN_CAPI */
-	return (0);		/* no error */
+
+	return 0;		/* no error */
 }				/* init_module */
 
 
@@ -230,20 +221,15 @@
 static void __exit
 hysdn_exit(void)
 {
+	if (hysdn_have_procfs)
+		hysdn_procconf_release();
+
+	pci_unregister_driver(&hysdn_pci_driver);
+
 #ifdef CONFIG_HYSDN_CAPI
-	hysdn_card *card;
-#endif /* CONFIG_HYSDN_CAPI */
-	stop_cards();
-#ifdef CONFIG_HYSDN_CAPI
-	card = card_root;	/* first in chain */
-	while (card) {
-		hycapi_capi_release(card);
-		card = card->next;	/* remove card from chain */
-	}			/* while card */
 	hycapi_cleanup();
 #endif /* CONFIG_HYSDN_CAPI */
-	hysdn_procconf_release();
-	free_resources();
+
 	printk(KERN_NOTICE "HYSDN: module unloaded\n");
 }				/* cleanup_module */
 
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index dc477e0..27d890b 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -16,6 +16,7 @@
 #include <linux/proc_fs.h>
 #include <linux/pci.h>
 #include <linux/smp_lock.h>
+#include <net/net_namespace.h>
 
 #include "hysdn_defs.h"
 
@@ -392,7 +393,7 @@
 	hysdn_card *card;
 	unsigned char conf_name[20];
 
-	hysdn_proc_entry = proc_mkdir(PROC_SUBDIR_NAME, proc_net);
+	hysdn_proc_entry = proc_mkdir(PROC_SUBDIR_NAME, init_net.proc_net);
 	if (!hysdn_proc_entry) {
 		printk(KERN_ERR "HYSDN: unable to create hysdn subdir\n");
 		return (-1);
@@ -437,5 +438,5 @@
 		card = card->next;	/* point to next card */
 	}
 
-	remove_proc_entry(PROC_SUBDIR_NAME, proc_net);
+	remove_proc_entry(PROC_SUBDIR_NAME, init_net.proc_net);
 }
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig
index e91c187..36778b2 100644
--- a/drivers/isdn/i4l/Kconfig
+++ b/drivers/isdn/i4l/Kconfig
@@ -99,7 +99,6 @@
 
 config ISDN_DIVERSION
 	tristate "Support isdn diversion services"
-	depends on ISDN_I4L
 	help
 	  This option allows you to use some supplementary diversion
 	  services in conjunction with the HiSax driver on an EURO/DSS1
@@ -119,13 +118,11 @@
 endmenu
 
 comment "ISDN4Linux hardware drivers"
-	depends on ISDN_I4L
 
 source "drivers/isdn/hisax/Kconfig"
 
 
 menu "Active cards"
-	depends on ISDN_I4L!=n
 
 source "drivers/isdn/icn/Kconfig"
 
diff --git a/drivers/isdn/i4l/isdn_bsdcomp.c b/drivers/isdn/i4l/isdn_bsdcomp.c
index 90a2379..02d9918 100644
--- a/drivers/isdn/i4l/isdn_bsdcomp.c
+++ b/drivers/isdn/i4l/isdn_bsdcomp.c
@@ -341,7 +341,7 @@
 	 * Allocate space for the dictionary. This may be more than one page in
 	 * length.
 	 */
-	db->dict = (struct bsd_dict *) vmalloc (hsize * sizeof (struct bsd_dict));
+	db->dict = vmalloc(hsize * sizeof(struct bsd_dict));
 	if (!db->dict) {
 		bsd_free (db);
 		return NULL;
@@ -354,8 +354,7 @@
 	if (!decomp)
 		db->lens = NULL;
 	else {
-		db->lens = (unsigned short *) vmalloc ((maxmaxcode + 1) *
-			sizeof (db->lens[0]));
+		db->lens = vmalloc((maxmaxcode + 1) * sizeof(db->lens[0]));
 		if (!db->lens) {
 			bsd_free (db);
 			return (NULL);
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index c97330b..4910bca 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -1135,7 +1135,7 @@
 			if (count > dev->drv[drvidx]->stavail)
 				count = dev->drv[drvidx]->stavail;
 			len = dev->drv[drvidx]->interface->readstat(buf, count,
-						drvidx, isdn_minor2chan(minor));
+				drvidx, isdn_minor2chan(minor - ISDN_MINOR_CTRL));
 			if (len < 0) {
 				retval = len;
 				goto out;
@@ -1207,7 +1207,8 @@
 		 */
 		if (dev->drv[drvidx]->interface->writecmd)
 			retval = dev->drv[drvidx]->interface->
-				writecmd(buf, count, drvidx, isdn_minor2chan(minor));
+				writecmd(buf, count, drvidx,
+				isdn_minor2chan(minor - ISDN_MINOR_CTRL));
 		else
 			retval = count;
 		goto out;
@@ -2291,7 +2292,7 @@
 	int i;
 	char tmprev[50];
 
-	if (!(dev = (isdn_dev *) vmalloc(sizeof(isdn_dev)))) {
+	if (!(dev = vmalloc(sizeof(isdn_dev)))) {
 		printk(KERN_WARNING "isdn: Could not allocate device-struct.\n");
 		return -EIO;
 	}
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index aa83277..7c9cb7e 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -77,7 +77,7 @@
 	if (lp->master) 
 		dev = lp->master;
 	else
-		dev = &n->dev;
+		dev = n->dev;
 	return netif_running(dev);
 }
 
@@ -90,7 +90,7 @@
 	if (lp->master) 
 		netif_wake_queue(lp->master);
 	else
-		netif_wake_queue(&lp->netdev->dev);
+		netif_wake_queue(lp->netdev->dev);
 }
 
 /*
@@ -102,7 +102,7 @@
 	if (lp->master)
 		netif_stop_queue(lp->master);
 	else
-		netif_stop_queue(&lp->netdev->dev);
+		netif_stop_queue(lp->netdev->dev);
 }
 
 /*
@@ -287,7 +287,7 @@
 		   BEWARE! This chunk of code cannot be called from hardware
 		   interrupt handler. I hope it is true. --ANK
 		 */
-		qdisc_reset(lp->netdev->dev.qdisc);
+		qdisc_reset(lp->netdev->dev->qdisc);
 	}
 	lp->dialstate = 0;
 	dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
@@ -345,27 +345,27 @@
 						l->chargetime += l->chargeint;
 					if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ))
 						if (l->outgoing || l->hupflags & ISDN_INHUP)
-							isdn_net_hangup(&p->dev);
+							isdn_net_hangup(p->dev);
 				} else if (l->outgoing) {
 					if (l->hupflags & ISDN_CHARGEHUP) {
 						if (l->hupflags & ISDN_WAITCHARGE) {
 							printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n",
 							       l->name, l->hupflags);
-							isdn_net_hangup(&p->dev);
+							isdn_net_hangup(p->dev);
 						} else if (time_after(jiffies, l->chargetime + l->chargeint)) {
 							printk(KERN_DEBUG
 							       "isdn_net: %s: chtime = %lu, chint = %d\n",
 							       l->name, l->chargetime, l->chargeint);
-							isdn_net_hangup(&p->dev);
+							isdn_net_hangup(p->dev);
 						}
 					} else
-						isdn_net_hangup(&p->dev);
+						isdn_net_hangup(p->dev);
 				} else if (l->hupflags & ISDN_INHUP)
-					isdn_net_hangup(&p->dev);
+					isdn_net_hangup(p->dev);
 			}
 
 			if(dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) {
-				isdn_net_hangup(&p->dev);
+				isdn_net_hangup(p->dev);
 				break;
 			}
 		}
@@ -579,7 +579,7 @@
 				if (!lp->dial) {
 					printk(KERN_WARNING "%s: phone number deleted?\n",
 					       lp->name);
-					isdn_net_hangup(&p->dev);
+					isdn_net_hangup(p->dev);
 					break;
 				}
 				anymore = 1;
@@ -616,8 +616,8 @@
 						s = "dial suppressed: isdn system stopped";
 					else
 						s = "dial suppressed: dialmode `off'";
-					isdn_net_unreachable(&p->dev, NULL, s);
-					isdn_net_hangup(&p->dev);
+					isdn_net_unreachable(p->dev, NULL, s);
+					isdn_net_hangup(p->dev);
 					break;
 				}
 				cmd.driver = lp->isdn_device;
@@ -633,7 +633,7 @@
 				if (!lp->dial) {
 					printk(KERN_WARNING "%s: phone number deleted?\n",
 					       lp->name);
-					isdn_net_hangup(&p->dev);
+					isdn_net_hangup(p->dev);
 					break;
 				}
 				if (!strncmp(lp->dial->num, "LEASED", strlen("LEASED"))) {
@@ -644,8 +644,8 @@
 						if (time_after(jiffies, lp->dialstarted + lp->dialtimeout)) {
 							lp->dialwait_timer = jiffies + lp->dialwait;
 							lp->dialstarted = 0;
-							isdn_net_unreachable(&p->dev, NULL, "dial: timed out");
-							isdn_net_hangup(&p->dev);
+							isdn_net_unreachable(p->dev, NULL, "dial: timed out");
+							isdn_net_hangup(p->dev);
 							break;
 						}
 
@@ -674,9 +674,9 @@
 							if (lp->dialtimeout == 0) {
 								lp->dialwait_timer = jiffies + lp->dialwait;
 								lp->dialstarted = 0;
-								isdn_net_unreachable(&p->dev, NULL, "dial: tried all numbers dialmax times");
+								isdn_net_unreachable(p->dev, NULL, "dial: tried all numbers dialmax times");
 							}
-							isdn_net_hangup(&p->dev);
+							isdn_net_hangup(p->dev);
 							break;
 						}
 					}
@@ -758,7 +758,7 @@
 				cmd.arg = lp->isdn_channel + (lp->l3_proto << 8);
 				isdn_command(&cmd);
 				if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT15)
-					isdn_net_hangup(&p->dev);
+					isdn_net_hangup(p->dev);
 				else {
 					anymore = 1;
 					lp->dialstate++;
@@ -781,7 +781,7 @@
 				printk(KERN_DEBUG "dialtimer4: %d\n", lp->dtimer);
 #endif
 				if (lp->dtimer++ > ISDN_TIMER_DTIMEOUT10)
-					isdn_net_hangup(&p->dev);
+					isdn_net_hangup(p->dev);
 				else
 					anymore = 1;
 				break;
@@ -1618,7 +1618,7 @@
 	__be32 addr = 0;		/* local ipv4 address */
 	__be32 mask = 0;		/* local netmask */
 
-	if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) {
+	if ((in_dev = lp->netdev->dev->ip_ptr) != NULL) {
 		/* take primary(first) address of interface */
 		struct in_ifaddr *ifa = in_dev->ifa_list;
 		if (ifa != NULL) {
@@ -1866,61 +1866,21 @@
 		isdn_net_local *lp = p->local;
 		if ((lp->flags & ISDN_NET_CONNECTED) &&
 		    (!lp->dialstate)) {
-			isdn_net_receive(&p->dev, skb);
+			isdn_net_receive(p->dev, skb);
 			return 1;
 		}
 	}
 	return 0;
 }
 
-static int
-my_eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-	      void *daddr, void *saddr, unsigned len)
-{
-	struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
-
-	/*
-	 * Set the protocol type. For a packet of type ETH_P_802_3 we
-	 * put the length here instead. It is up to the 802.2 layer to
-	 * carry protocol information.
-	 */
-
-	if (type != ETH_P_802_3)
-		eth->h_proto = htons(type);
-	else
-		eth->h_proto = htons(len);
-
-	/*
-	 * Set the source hardware address.
-	 */
-	if (saddr)
-		memcpy(eth->h_source, saddr, dev->addr_len);
-	else
-		memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
-
-	/*
-	 * Anyway, the loopback-device should never use this function...
-	 */
-
-	if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) {
-		memset(eth->h_dest, 0, dev->addr_len);
-		return ETH_HLEN /*(dev->hard_header_len)*/;
-	}
-	if (daddr) {
-		memcpy(eth->h_dest, daddr, dev->addr_len);
-		return ETH_HLEN /*dev->hard_header_len*/;
-	}
-	return -ETH_HLEN /*dev->hard_header_len*/;
-}
-
 /*
  *  build an header
  *  depends on encaps that is being used.
  */
 
-static int
-isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-		void *daddr, void *saddr, unsigned plen)
+static int isdn_net_header(struct sk_buff *skb, struct net_device *dev,
+			   unsigned short type,
+			   const void *daddr, const void *saddr, unsigned plen)
 {
 	isdn_net_local *lp = dev->priv;
 	unsigned char *p;
@@ -1928,7 +1888,7 @@
 
 	switch (lp->p_encap) {
 		case ISDN_NET_ENCAP_ETHER:
-			len = my_eth_header(skb, dev, type, daddr, saddr, plen);
+			len = eth_header(skb, dev, type, daddr, saddr, plen);
 			break;
 #ifdef CONFIG_ISDN_PPP
 		case ISDN_NET_ENCAP_SYNCPPP:
@@ -2005,6 +1965,32 @@
 	return ret;
 }
 
+static int isdn_header_cache(const struct neighbour *neigh, struct hh_cache *hh)
+{
+	const struct net_device *dev = neigh->dev;
+	isdn_net_local *lp = dev->priv;
+
+	if (lp->p_encap == ISDN_NET_ENCAP_ETHER)
+		return eth_header_cache(neigh, hh);
+	return -1;
+}
+
+static void isdn_header_cache_update(struct hh_cache *hh,
+				     const struct net_device *dev,
+				     const unsigned char *haddr)
+{
+	isdn_net_local *lp = dev->priv;
+	if (lp->p_encap == ISDN_NET_ENCAP_ETHER)
+		return eth_header_cache_update(hh, dev, haddr);
+}
+
+static const struct header_ops isdn_header_ops = {
+	.create = isdn_net_header,
+	.rebuild = isdn_net_rebuild_header,
+	.cache = isdn_header_cache,
+	.cache_update = isdn_header_cache_update,
+};
+
 /*
  * Interface-setup. (just after registering a new interface)
  */
@@ -2012,18 +1998,12 @@
 isdn_net_init(struct net_device *ndev)
 {
 	ushort max_hlhdr_len = 0;
-	isdn_net_local *lp = (isdn_net_local *) ndev->priv;
-	int drvidx, i;
+	int drvidx;
 
 	ether_setup(ndev);
-	lp->org_hhc = ndev->hard_header_cache;
-	lp->org_hcu = ndev->header_cache_update;
+	ndev->header_ops = NULL;
 
 	/* Setup the generic properties */
-
-	ndev->hard_header = NULL;
-	ndev->hard_header_cache = NULL;
-	ndev->header_cache_update = NULL;
 	ndev->mtu = 1500;
 	ndev->flags = IFF_NOARP|IFF_POINTOPOINT;
 	ndev->type = ARPHRD_ETHER;
@@ -2032,9 +2012,6 @@
 	/* for clients with MPPP maybe higher values better */
 	ndev->tx_queue_len = 30;
 
-	for (i = 0; i < ETH_ALEN; i++)
-		ndev->broadcast[i] = 0xff;
-
 	/* The ISDN-specific entries in the device structure. */
 	ndev->open = &isdn_net_open;
 	ndev->hard_start_xmit = &isdn_net_start_xmit;
@@ -2052,7 +2029,6 @@
 	ndev->hard_header_len = ETH_HLEN + max_hlhdr_len;
 	ndev->stop = &isdn_net_close;
 	ndev->get_stats = &isdn_net_get_stats;
-	ndev->rebuild_header = &isdn_net_rebuild_header;
 	ndev->do_ioctl = NULL;
 	return 0;
 }
@@ -2531,6 +2507,42 @@
 }
 
 /*
+ * Helper for alloc_netdev()
+ */
+static void _isdn_setup(struct net_device *dev)
+{
+	isdn_net_local *lp = dev->priv;
+
+	dev->flags = IFF_NOARP | IFF_POINTOPOINT;
+	lp->p_encap = ISDN_NET_ENCAP_RAWIP;
+	lp->magic = ISDN_NET_MAGIC;
+	lp->last = lp;
+	lp->next = lp;
+	lp->isdn_device = -1;
+	lp->isdn_channel = -1;
+	lp->pre_device = -1;
+	lp->pre_channel = -1;
+	lp->exclusive = -1;
+	lp->ppp_slot = -1;
+	lp->pppbind = -1;
+	skb_queue_head_init(&lp->super_tx_queue);
+	lp->l2_proto = ISDN_PROTO_L2_X75I;
+	lp->l3_proto = ISDN_PROTO_L3_TRANS;
+	lp->triggercps = 6000;
+	lp->slavedelay = 10 * HZ;
+	lp->hupflags = ISDN_INHUP;	/* Do hangup even on incoming calls */
+	lp->onhtime = 10;	/* Default hangup-time for saving costs */
+	lp->dialmax = 1;
+	/* Hangup before Callback, manual dial */
+	lp->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL;
+	lp->cbdelay = 25;	/* Wait 5 secs before Callback */
+	lp->dialtimeout = -1;  /* Infinite Dial-Timeout */
+	lp->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
+	lp->dialstarted = 0;   /* Jiffies of last dial-start */
+	lp->dialwait_timer = 0;  /* Jiffies of earliest next dial-start */
+}
+
+/*
  * Allocate a new network-interface and initialize its data structures.
  */
 char *
@@ -2543,23 +2555,21 @@
 		printk(KERN_WARNING "isdn_net: interface %s already exists\n", name);
 		return NULL;
 	}
+	if (name == NULL)
+		name = "         ";
 	if (!(netdev = kzalloc(sizeof(isdn_net_dev), GFP_KERNEL))) {
 		printk(KERN_WARNING "isdn_net: Could not allocate net-device\n");
 		return NULL;
 	}
-	if (!(netdev->local = kzalloc(sizeof(isdn_net_local), GFP_KERNEL))) {
-		printk(KERN_WARNING "isdn_net: Could not allocate device locals\n");
+	netdev->dev = alloc_netdev(sizeof(isdn_net_local), name, _isdn_setup);
+	if (!netdev->dev) {
+		printk(KERN_WARNING "isdn_net: Could not allocate network device\n");
 		kfree(netdev);
 		return NULL;
 	}
-	if (name == NULL)
-		strcpy(netdev->local->name, "         ");
-	else
-		strcpy(netdev->local->name, name);
-	strcpy(netdev->dev.name, netdev->local->name);
-	netdev->dev.priv = netdev->local;
-	netdev->dev.init = isdn_net_init;
-	netdev->local->p_encap = ISDN_NET_ENCAP_RAWIP;
+	netdev->local = netdev->dev->priv;
+	strcpy(netdev->local->name, netdev->dev->name);
+	netdev->dev->init = isdn_net_init;
 	if (master) {
 		/* Device shall be a slave */
 		struct net_device *p = (((isdn_net_local *) master->priv)->slave);
@@ -2571,60 +2581,33 @@
 			q = p;
 			p = (((isdn_net_local *) p->priv)->slave);
 		}
-		((isdn_net_local *) q->priv)->slave = &(netdev->dev);
+		((isdn_net_local *) q->priv)->slave = netdev->dev;
 	} else {
 		/* Device shall be a master */
 		/*
 		 * Watchdog timer (currently) for master only.
 		 */
-		netdev->dev.tx_timeout = isdn_net_tx_timeout;
-		netdev->dev.watchdog_timeo = ISDN_NET_TX_TIMEOUT;
-		if (register_netdev(&netdev->dev) != 0) {
+		netdev->dev->tx_timeout = isdn_net_tx_timeout;
+		netdev->dev->watchdog_timeo = ISDN_NET_TX_TIMEOUT;
+		if (register_netdev(netdev->dev) != 0) {
 			printk(KERN_WARNING "isdn_net: Could not register net-device\n");
-			kfree(netdev->local);
+			free_netdev(netdev->dev);
 			kfree(netdev);
 			return NULL;
 		}
 	}
-	netdev->local->magic = ISDN_NET_MAGIC;
-
 	netdev->queue = netdev->local;
 	spin_lock_init(&netdev->queue_lock);
 
-	netdev->local->last = netdev->local;
 	netdev->local->netdev = netdev;
-	netdev->local->next = netdev->local;
 
 	INIT_WORK(&netdev->local->tqueue, isdn_net_softint);
 	spin_lock_init(&netdev->local->xmit_lock);
 
-	netdev->local->isdn_device = -1;
-	netdev->local->isdn_channel = -1;
-	netdev->local->pre_device = -1;
-	netdev->local->pre_channel = -1;
-	netdev->local->exclusive = -1;
-	netdev->local->ppp_slot = -1;
-	netdev->local->pppbind = -1;
-	skb_queue_head_init(&netdev->local->super_tx_queue);
-	netdev->local->l2_proto = ISDN_PROTO_L2_X75I;
-	netdev->local->l3_proto = ISDN_PROTO_L3_TRANS;
-	netdev->local->triggercps = 6000;
-	netdev->local->slavedelay = 10 * HZ;
-	netdev->local->hupflags = ISDN_INHUP;	/* Do hangup even on incoming calls */
-	netdev->local->onhtime = 10;	/* Default hangup-time for saving costs
-	   of those who forget configuring this */
-	netdev->local->dialmax = 1;
-	netdev->local->flags = ISDN_NET_CBHUP | ISDN_NET_DM_MANUAL;	/* Hangup before Callback, manual dial */
-	netdev->local->cbdelay = 25;	/* Wait 5 secs before Callback */
-	netdev->local->dialtimeout = -1;  /* Infinite Dial-Timeout */
-	netdev->local->dialwait = 5 * HZ; /* Wait 5 sec. after failed dial */
-	netdev->local->dialstarted = 0;   /* Jiffies of last dial-start */
-	netdev->local->dialwait_timer = 0;  /* Jiffies of earliest next dial-start */
-
 	/* Put into to netdev-chain */
 	netdev->next = (void *) dev->netdev;
 	dev->netdev = netdev;
-	return netdev->dev.name;
+	return netdev->dev->name;
 }
 
 char *
@@ -2649,7 +2632,7 @@
 		/* Master must not be started yet */
 		if (isdn_net_device_started(n)) 
 			return NULL;
-		return (isdn_net_new(newname, &(n->dev)));
+		return (isdn_net_new(newname, n->dev));
 	}
 	return NULL;
 }
@@ -2718,9 +2701,9 @@
 			       lp->name);
 			return -EINVAL;
 #else
-			p->dev.type = ARPHRD_PPP;	/* change ARP type */
-			p->dev.addr_len = 0;
-			p->dev.do_ioctl = isdn_ppp_dev_ioctl;
+			p->dev->type = ARPHRD_PPP;	/* change ARP type */
+			p->dev->addr_len = 0;
+			p->dev->do_ioctl = isdn_ppp_dev_ioctl;
 #endif
 			break;
 		case ISDN_NET_ENCAP_X25IFACE:
@@ -2729,12 +2712,12 @@
 			       p->local->name);
 			return -EINVAL;
 #else
-			p->dev.type = ARPHRD_X25;	/* change ARP type */
-			p->dev.addr_len = 0;
+			p->dev->type = ARPHRD_X25;	/* change ARP type */
+			p->dev->addr_len = 0;
 #endif
 			break;
 		case ISDN_NET_ENCAP_CISCOHDLCK:
-			p->dev.do_ioctl = isdn_ciscohdlck_dev_ioctl;
+			p->dev->do_ioctl = isdn_ciscohdlck_dev_ioctl;
 			break;
 		default:
 			if( cfg->p_encap >= 0 &&
@@ -2861,21 +2844,14 @@
 		}
 		if (cfg->p_encap != lp->p_encap) {
 			if (cfg->p_encap == ISDN_NET_ENCAP_RAWIP) {
-				p->dev.hard_header = NULL;
-				p->dev.hard_header_cache = NULL;
-				p->dev.header_cache_update = NULL;
-				p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
+				p->dev->header_ops = NULL;
+				p->dev->flags = IFF_NOARP|IFF_POINTOPOINT;
 			} else {
-				p->dev.hard_header = isdn_net_header;
-				if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) {
-					p->dev.hard_header_cache = lp->org_hhc;
-					p->dev.header_cache_update = lp->org_hcu;
-					p->dev.flags = IFF_BROADCAST | IFF_MULTICAST;
-				} else {
-					p->dev.hard_header_cache = NULL;
-					p->dev.header_cache_update = NULL;
-					p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
-				}
+				p->dev->header_ops = &isdn_header_ops;
+				if (cfg->p_encap == ISDN_NET_ENCAP_ETHER)
+					p->dev->flags = IFF_BROADCAST | IFF_MULTICAST;
+				else
+					p->dev->flags = IFF_NOARP|IFF_POINTOPOINT;
 			}
 		}
 		lp->p_encap = cfg->p_encap;
@@ -3095,7 +3071,7 @@
 			isdn_net_hangup(q);
 			q = (((isdn_net_local *) q->priv)->slave);
 		}
-		isdn_net_hangup(&p->dev);
+		isdn_net_hangup(p->dev);
 		return 0;
 	}
 	return -ENODEV;
@@ -3123,13 +3099,11 @@
 		isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel);
 	if (p->local->master) {
 		/* It's a slave-device, so update master's slave-pointer if necessary */
-		if (((isdn_net_local *) (p->local->master->priv))->slave == &p->dev)
+		if (((isdn_net_local *) (p->local->master->priv))->slave == p->dev)
 			((isdn_net_local *) (p->local->master->priv))->slave = p->local->slave;
 	} else {
 		/* Unregister only if it's a master-device */
-		p->dev.hard_header_cache = p->local->org_hhc;
-		p->dev.header_cache_update = p->local->org_hcu;
-		unregister_netdev(&p->dev);
+		unregister_netdev(p->dev);
 	}
 	/* Unlink device from chain */
 	spin_lock_irqsave(&dev->lock, flags);
@@ -3157,7 +3131,7 @@
 	/* If no more net-devices remain, disable auto-hangup timer */
 	if (dev->netdev == NULL)
 		isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, 0);
-	kfree(p->local);
+	free_netdev(p->dev);
 	kfree(p);
 
 	return 0;
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 387392c..0e5e59f 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -360,7 +360,7 @@
 		 * isdn_ppp_free() sets is->lp to NULL and lp->ppp_slot to -1
 		 * removing the IPPP_CONNECT flag omits calling of isdn_ppp_wakeup_daemon()
 		 */
-		isdn_net_hangup(&p->dev);
+		isdn_net_hangup(p->dev);
 	}
 	for (i = 0; i < NUM_RCV_BUFFS; i++) {
 		kfree(is->rq[i].buf);
@@ -531,7 +531,7 @@
 				if (lp) {
 					/* OK .. we are ready to send buffers */
 					is->pppcfg = val; /* isdn_ppp_xmit test for SC_ENABLE_IP !!! */
-					netif_wake_queue(&lp->netdev->dev);
+					netif_wake_queue(lp->netdev->dev);
 					break;
 				}
 			}
@@ -1023,7 +1023,7 @@
 static void
 isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto)
 {
-	struct net_device *dev = &net_dev->dev;
+	struct net_device *dev = net_dev->dev;
  	struct ippp_struct *is, *mis;
 	isdn_net_local *mlp = NULL;
 	int slot;
diff --git a/drivers/isdn/icn/Kconfig b/drivers/isdn/icn/Kconfig
index fcb99f5..89d15ee 100644
--- a/drivers/isdn/icn/Kconfig
+++ b/drivers/isdn/icn/Kconfig
@@ -3,7 +3,7 @@
 #
 config ISDN_DRV_ICN
 	tristate "ICN 2B and 4B support"
-	depends on ISDN_I4L && ISA
+	depends on ISA
 	help
 	  This enables support for two kinds of ISDN-cards made by a German
 	  company called ICN.  2B is the standard version for a single ISDN
diff --git a/drivers/isdn/pcbit/Kconfig b/drivers/isdn/pcbit/Kconfig
index 0933881..ffba6ec 100644
--- a/drivers/isdn/pcbit/Kconfig
+++ b/drivers/isdn/pcbit/Kconfig
@@ -3,7 +3,7 @@
 #
 config ISDN_DRV_PCBIT
 	tristate "PCBIT-D support"
-	depends on ISDN_I4L && ISA && (BROKEN || X86)
+	depends on ISA && (BROKEN || X86)
 	help
 	  This enables support for the PCBIT ISDN-card.  This card is
 	  manufactured in Portugal by Octal.  For running this card,
diff --git a/drivers/isdn/sc/Kconfig b/drivers/isdn/sc/Kconfig
index 5346e33..e6510ca 100644
--- a/drivers/isdn/sc/Kconfig
+++ b/drivers/isdn/sc/Kconfig
@@ -3,7 +3,7 @@
 #
 config ISDN_DRV_SC
 	tristate "Spellcaster support"
-	depends on ISDN_I4L && ISA
+	depends on ISA
 	help
 	  This enables support for the Spellcaster BRI ISDN boards.  This
 	  driver currently builds only in a modularized version.
diff --git a/drivers/isdn/sc/card.h b/drivers/isdn/sc/card.h
index 4fbfa82..5992f63 100644
--- a/drivers/isdn/sc/card.h
+++ b/drivers/isdn/sc/card.h
@@ -125,7 +125,7 @@
 int receivemessage(int card, RspMessage *rspmsg);
 int sc_ioctl(int card, scs_ioctl *data);
 int setup_buffers(int card, int c);
-void check_reset(unsigned long data);
+void sc_check_reset(unsigned long data);
 void check_phystat(unsigned long data);
 
 #endif /* CARD_H */
diff --git a/drivers/isdn/sc/command.c b/drivers/isdn/sc/command.c
index b7bb7cb..0e4969c 100644
--- a/drivers/isdn/sc/command.c
+++ b/drivers/isdn/sc/command.c
@@ -344,7 +344,7 @@
 
 	spin_lock_irqsave(&sc_adapter[card]->lock, flags);
 	init_timer(&sc_adapter[card]->reset_timer);
-	sc_adapter[card]->reset_timer.function = check_reset;
+	sc_adapter[card]->reset_timer.function = sc_check_reset;
 	sc_adapter[card]->reset_timer.data = card;
 	sc_adapter[card]->reset_timer.expires = jiffies + CHECKRESET_TIME;
 	add_timer(&sc_adapter[card]->reset_timer);
diff --git a/drivers/isdn/sc/timer.c b/drivers/isdn/sc/timer.c
index cc1b886..91fbe0d 100644
--- a/drivers/isdn/sc/timer.c
+++ b/drivers/isdn/sc/timer.c
@@ -43,7 +43,7 @@
  * Then, check to see if the signate has been set. Next, set the
  * signature to a known value and issue a startproc if needed.
  */
-void check_reset(unsigned long data)
+void sc_check_reset(unsigned long data)
 {
 	unsigned long flags;
 	unsigned long sig;
diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig
index 33fa28a..0a419a0 100644
--- a/drivers/kvm/Kconfig
+++ b/drivers/kvm/Kconfig
@@ -5,13 +5,19 @@
 	bool "Virtualization"
 	depends on X86
 	default y
+	---help---
+	  Say Y here to get to see options for using your Linux host to run other
+	  operating systems inside virtual machines (guests).
+	  This option alone does not add any kernel code.
+
+	  If you say N, all options in this submenu will be skipped and disabled.
 
 if VIRTUALIZATION
 
 config KVM
 	tristate "Kernel-based Virtual Machine (KVM) support"
 	depends on X86 && EXPERIMENTAL
-	depends on X86_CMPXCHG64 || 64BIT
+	select ANON_INODES
 	---help---
 	  Support hosting fully virtualized guest machines using hardware
 	  virtualization extensions.  You will need a fairly recent
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index a7c5e6b..336be86 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -121,7 +121,7 @@
  *   bits 4:7 - page table level for this shadow (1-4)
  *   bits 8:9 - page table quadrant for 2-level guests
  *   bit   16 - "metaphysical" - gfn is not a real page (huge page/real mode)
- *   bits 17:18 - "access" - the user and writable bits of a huge page pde
+ *   bits 17:19 - "access" - the user, writable, and nx bits of a huge page pde
  */
 union kvm_mmu_page_role {
 	unsigned word;
@@ -131,7 +131,7 @@
 		unsigned quadrant : 2;
 		unsigned pad_for_nice_hex_output : 6;
 		unsigned metaphysical : 1;
-		unsigned hugepage_access : 2;
+		unsigned hugepage_access : 3;
 	};
 };
 
@@ -535,8 +535,8 @@
 int kvm_mmu_setup(struct kvm_vcpu *vcpu);
 
 int kvm_mmu_reset_context(struct kvm_vcpu *vcpu);
-void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot);
-void kvm_mmu_zap_all(struct kvm_vcpu *vcpu);
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot);
+void kvm_mmu_zap_all(struct kvm *kvm);
 
 hpa_t gpa_to_hpa(struct kvm_vcpu *vcpu, gpa_t gpa);
 #define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
@@ -569,6 +569,8 @@
 unsigned long realmode_get_cr(struct kvm_vcpu *vcpu, int cr);
 void realmode_set_cr(struct kvm_vcpu *vcpu, int cr, unsigned long value,
 		     unsigned long *rflags);
+int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
+int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
 
 struct x86_emulate_ctxt;
 
@@ -617,7 +619,7 @@
 void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
 		       const u8 *old, const u8 *new, int bytes);
 int kvm_mmu_unprotect_page_virt(struct kvm_vcpu *vcpu, gva_t gva);
-void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
+void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu);
 int kvm_mmu_load(struct kvm_vcpu *vcpu);
 void kvm_mmu_unload(struct kvm_vcpu *vcpu);
 
@@ -626,11 +628,15 @@
 static inline int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
 				     u32 error_code)
 {
-	if (unlikely(vcpu->kvm->n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
-		kvm_mmu_free_some_pages(vcpu);
 	return vcpu->mmu.page_fault(vcpu, gva, error_code);
 }
 
+static inline void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
+{
+	if (unlikely(vcpu->kvm->n_free_mmu_pages < KVM_MIN_FREE_MMU_PAGES))
+		__kvm_mmu_free_some_pages(vcpu);
+}
+
 static inline int kvm_mmu_reload(struct kvm_vcpu *vcpu)
 {
 	if (likely(vcpu->mmu.root_hpa != INVALID_PAGE))
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index 1b206f1..cd05579 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -238,23 +238,6 @@
 	kvm_arch_ops->vcpu_load(vcpu);
 }
 
-/*
- * Switches to specified vcpu, until a matching vcpu_put(). Will return NULL
- * if the slot is not populated.
- */
-static struct kvm_vcpu *vcpu_load_slot(struct kvm *kvm, int slot)
-{
-	struct kvm_vcpu *vcpu = &kvm->vcpus[slot];
-
-	mutex_lock(&vcpu->mutex);
-	if (!vcpu->vmcs) {
-		mutex_unlock(&vcpu->mutex);
-		return NULL;
-	}
-	kvm_arch_ops->vcpu_load(vcpu);
-	return vcpu;
-}
-
 static void vcpu_put(struct kvm_vcpu *vcpu)
 {
 	kvm_arch_ops->vcpu_put(vcpu);
@@ -314,9 +297,6 @@
 	kvm_io_bus_init(&kvm->pio_bus);
 	spin_lock_init(&kvm->lock);
 	INIT_LIST_HEAD(&kvm->active_mmu_pages);
-	spin_lock(&kvm_lock);
-	list_add(&kvm->vm_list, &vm_list);
-	spin_unlock(&kvm_lock);
 	kvm_io_bus_init(&kvm->mmio_bus);
 	for (i = 0; i < KVM_MAX_VCPUS; ++i) {
 		struct kvm_vcpu *vcpu = &kvm->vcpus[i];
@@ -326,6 +306,9 @@
 		vcpu->kvm = kvm;
 		vcpu->mmu.root_hpa = INVALID_PAGE;
 	}
+	spin_lock(&kvm_lock);
+	list_add(&kvm->vm_list, &vm_list);
+	spin_unlock(&kvm_lock);
 	return kvm;
 }
 
@@ -663,13 +646,6 @@
 }
 EXPORT_SYMBOL_GPL(fx_init);
 
-static void do_remove_write_access(struct kvm_vcpu *vcpu, int slot)
-{
-	spin_lock(&vcpu->kvm->lock);
-	kvm_mmu_slot_remove_write_access(vcpu, slot);
-	spin_unlock(&vcpu->kvm->lock);
-}
-
 /*
  * Allocate some memory and give it an address in the guest physical address
  * space.
@@ -792,20 +768,11 @@
 	*memslot = new;
 	++kvm->memory_config_version;
 
+	kvm_mmu_slot_remove_write_access(kvm, mem->slot);
+	kvm_flush_remote_tlbs(kvm);
+
 	spin_unlock(&kvm->lock);
 
-	for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-		struct kvm_vcpu *vcpu;
-
-		vcpu = vcpu_load_slot(kvm, i);
-		if (!vcpu)
-			continue;
-		if (new.flags & KVM_MEM_LOG_DIRTY_PAGES)
-			do_remove_write_access(vcpu, mem->slot);
-		kvm_mmu_reset_context(vcpu);
-		vcpu_put(vcpu);
-	}
-
 	kvm_free_physmem_slot(&old, &new);
 	return 0;
 
@@ -826,7 +793,6 @@
 	struct kvm_memory_slot *memslot;
 	int r, i;
 	int n;
-	int cleared;
 	unsigned long any = 0;
 
 	spin_lock(&kvm->lock);
@@ -855,23 +821,11 @@
 	if (copy_to_user(log->dirty_bitmap, memslot->dirty_bitmap, n))
 		goto out;
 
-	if (any) {
-		cleared = 0;
-		for (i = 0; i < KVM_MAX_VCPUS; ++i) {
-			struct kvm_vcpu *vcpu;
-
-			vcpu = vcpu_load_slot(kvm, i);
-			if (!vcpu)
-				continue;
-			if (!cleared) {
-				do_remove_write_access(vcpu, log->slot);
-				memset(memslot->dirty_bitmap, 0, n);
-				cleared = 1;
-			}
-			kvm_arch_ops->tlb_flush(vcpu);
-			vcpu_put(vcpu);
-		}
-	}
+	spin_lock(&kvm->lock);
+	kvm_mmu_slot_remove_write_access(kvm, log->slot);
+	kvm_flush_remote_tlbs(kvm);
+	memset(memslot->dirty_bitmap, 0, n);
+	spin_unlock(&kvm->lock);
 
 	r = 0;
 
@@ -920,13 +874,9 @@
 			break;
 	kvm->naliases = n;
 
-	spin_unlock(&kvm->lock);
+	kvm_mmu_zap_all(kvm);
 
-	vcpu_load(&kvm->vcpus[0]);
-	spin_lock(&kvm->lock);
-	kvm_mmu_zap_all(&kvm->vcpus[0]);
 	spin_unlock(&kvm->lock);
-	vcpu_put(&kvm->vcpus[0]);
 
 	return 0;
 
@@ -1120,18 +1070,16 @@
 		return 0;
 	mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT);
 	virt = kmap_atomic(page, KM_USER0);
-	if (memcmp(virt + offset_in_page(gpa), val, bytes)) {
-		kvm_mmu_pte_write(vcpu, gpa, virt + offset, val, bytes);
-		memcpy(virt + offset_in_page(gpa), val, bytes);
-	}
+	kvm_mmu_pte_write(vcpu, gpa, virt + offset, val, bytes);
+	memcpy(virt + offset_in_page(gpa), val, bytes);
 	kunmap_atomic(virt, KM_USER0);
 	return 1;
 }
 
-static int emulator_write_emulated(unsigned long addr,
-				   const void *val,
-				   unsigned int bytes,
-				   struct x86_emulate_ctxt *ctxt)
+static int emulator_write_emulated_onepage(unsigned long addr,
+					   const void *val,
+					   unsigned int bytes,
+					   struct x86_emulate_ctxt *ctxt)
 {
 	struct kvm_vcpu      *vcpu = ctxt->vcpu;
 	struct kvm_io_device *mmio_dev;
@@ -1163,6 +1111,26 @@
 	return X86EMUL_CONTINUE;
 }
 
+static int emulator_write_emulated(unsigned long addr,
+				   const void *val,
+				   unsigned int bytes,
+				   struct x86_emulate_ctxt *ctxt)
+{
+	/* Crossing a page boundary? */
+	if (((addr + bytes - 1) ^ addr) & PAGE_MASK) {
+		int rc, now;
+
+		now = -addr & ~PAGE_MASK;
+		rc = emulator_write_emulated_onepage(addr, val, now, ctxt);
+		if (rc != X86EMUL_CONTINUE)
+			return rc;
+		addr += now;
+		val += now;
+		bytes -= now;
+	}
+	return emulator_write_emulated_onepage(addr, val, bytes, ctxt);
+}
+
 static int emulator_cmpxchg_emulated(unsigned long addr,
 				     const void *old,
 				     const void *new,
@@ -1567,7 +1535,7 @@
  * Returns 0 on success, non-0 otherwise.
  * Assumes vcpu_load() was already called.
  */
-static int get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
+int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
 {
 	return kvm_arch_ops->get_msr(vcpu, msr_index, pdata);
 }
@@ -1645,7 +1613,7 @@
  * Returns 0 on success, non-0 otherwise.
  * Assumes vcpu_load() was already called.
  */
-static int set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
+int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
 {
 	return kvm_arch_ops->set_msr(vcpu, msr_index, data);
 }
@@ -2183,7 +2151,7 @@
  */
 static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
 {
-	return set_msr(vcpu, index, *data);
+	return kvm_set_msr(vcpu, index, *data);
 }
 
 /*
@@ -2464,9 +2432,9 @@
 			break;
 		}
 	}
-	if (entry && (entry->edx & EFER_NX) && !(efer & EFER_NX)) {
+	if (entry && (entry->edx & (1 << 20)) && !(efer & EFER_NX)) {
 		entry->edx &= ~(1 << 20);
-		printk(KERN_INFO ": guest NX capability removed\n");
+		printk(KERN_INFO "kvm: guest NX capability removed\n");
 	}
 }
 
@@ -2667,7 +2635,7 @@
 		break;
 	}
 	case KVM_GET_MSRS:
-		r = msr_io(vcpu, argp, get_msr, 1);
+		r = msr_io(vcpu, argp, kvm_get_msr, 1);
 		break;
 	case KVM_SET_MSRS:
 		r = msr_io(vcpu, argp, do_set_msr, 0);
@@ -3006,6 +2974,10 @@
 	switch (val) {
 	case CPU_DYING:
 	case CPU_DYING_FROZEN:
+		printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
+		       cpu);
+		hardware_disable(NULL);
+		break;
 	case CPU_UP_CANCELED:
 	case CPU_UP_CANCELED_FROZEN:
 		printk(KERN_INFO "kvm: disabling virtualization on CPU%d\n",
diff --git a/drivers/kvm/mmu.c b/drivers/kvm/mmu.c
index b297a6b..23965aa 100644
--- a/drivers/kvm/mmu.c
+++ b/drivers/kvm/mmu.c
@@ -154,7 +154,6 @@
 
 static struct kmem_cache *pte_chain_cache;
 static struct kmem_cache *rmap_desc_cache;
-static struct kmem_cache *mmu_page_cache;
 static struct kmem_cache *mmu_page_header_cache;
 
 static int is_write_protection(struct kvm_vcpu *vcpu)
@@ -225,6 +224,29 @@
 		kfree(mc->objects[--mc->nobjs]);
 }
 
+static int mmu_topup_memory_cache_page(struct kvm_mmu_memory_cache *cache,
+				       int min, gfp_t gfp_flags)
+{
+	struct page *page;
+
+	if (cache->nobjs >= min)
+		return 0;
+	while (cache->nobjs < ARRAY_SIZE(cache->objects)) {
+		page = alloc_page(gfp_flags);
+		if (!page)
+			return -ENOMEM;
+		set_page_private(page, 0);
+		cache->objects[cache->nobjs++] = page_address(page);
+	}
+	return 0;
+}
+
+static void mmu_free_memory_cache_page(struct kvm_mmu_memory_cache *mc)
+{
+	while (mc->nobjs)
+		free_page((unsigned long)mc->objects[--mc->nobjs]);
+}
+
 static int __mmu_topup_memory_caches(struct kvm_vcpu *vcpu, gfp_t gfp_flags)
 {
 	int r;
@@ -237,8 +259,7 @@
 				   rmap_desc_cache, 1, gfp_flags);
 	if (r)
 		goto out;
-	r = mmu_topup_memory_cache(&vcpu->mmu_page_cache,
-				   mmu_page_cache, 4, gfp_flags);
+	r = mmu_topup_memory_cache_page(&vcpu->mmu_page_cache, 4, gfp_flags);
 	if (r)
 		goto out;
 	r = mmu_topup_memory_cache(&vcpu->mmu_page_header_cache,
@@ -252,12 +273,14 @@
 	int r;
 
 	r = __mmu_topup_memory_caches(vcpu, GFP_NOWAIT);
+	kvm_mmu_free_some_pages(vcpu);
 	if (r < 0) {
 		spin_unlock(&vcpu->kvm->lock);
 		kvm_arch_ops->vcpu_put(vcpu);
 		r = __mmu_topup_memory_caches(vcpu, GFP_KERNEL);
 		kvm_arch_ops->vcpu_load(vcpu);
 		spin_lock(&vcpu->kvm->lock);
+		kvm_mmu_free_some_pages(vcpu);
 	}
 	return r;
 }
@@ -266,7 +289,7 @@
 {
 	mmu_free_memory_cache(&vcpu->mmu_pte_chain_cache);
 	mmu_free_memory_cache(&vcpu->mmu_rmap_desc_cache);
-	mmu_free_memory_cache(&vcpu->mmu_page_cache);
+	mmu_free_memory_cache_page(&vcpu->mmu_page_cache);
 	mmu_free_memory_cache(&vcpu->mmu_page_header_cache);
 }
 
@@ -281,24 +304,15 @@
 	return p;
 }
 
-static void mmu_memory_cache_free(struct kvm_mmu_memory_cache *mc, void *obj)
-{
-	if (mc->nobjs < KVM_NR_MEM_OBJS)
-		mc->objects[mc->nobjs++] = obj;
-	else
-		kfree(obj);
-}
-
 static struct kvm_pte_chain *mmu_alloc_pte_chain(struct kvm_vcpu *vcpu)
 {
 	return mmu_memory_cache_alloc(&vcpu->mmu_pte_chain_cache,
 				      sizeof(struct kvm_pte_chain));
 }
 
-static void mmu_free_pte_chain(struct kvm_vcpu *vcpu,
-			       struct kvm_pte_chain *pc)
+static void mmu_free_pte_chain(struct kvm_pte_chain *pc)
 {
-	mmu_memory_cache_free(&vcpu->mmu_pte_chain_cache, pc);
+	kfree(pc);
 }
 
 static struct kvm_rmap_desc *mmu_alloc_rmap_desc(struct kvm_vcpu *vcpu)
@@ -307,10 +321,9 @@
 				      sizeof(struct kvm_rmap_desc));
 }
 
-static void mmu_free_rmap_desc(struct kvm_vcpu *vcpu,
-			       struct kvm_rmap_desc *rd)
+static void mmu_free_rmap_desc(struct kvm_rmap_desc *rd)
 {
-	mmu_memory_cache_free(&vcpu->mmu_rmap_desc_cache, rd);
+	kfree(rd);
 }
 
 /*
@@ -355,8 +368,7 @@
 	}
 }
 
-static void rmap_desc_remove_entry(struct kvm_vcpu *vcpu,
-				   struct page *page,
+static void rmap_desc_remove_entry(struct page *page,
 				   struct kvm_rmap_desc *desc,
 				   int i,
 				   struct kvm_rmap_desc *prev_desc)
@@ -376,10 +388,10 @@
 			prev_desc->more = desc->more;
 		else
 			set_page_private(page,(unsigned long)desc->more | 1);
-	mmu_free_rmap_desc(vcpu, desc);
+	mmu_free_rmap_desc(desc);
 }
 
-static void rmap_remove(struct kvm_vcpu *vcpu, u64 *spte)
+static void rmap_remove(u64 *spte)
 {
 	struct page *page;
 	struct kvm_rmap_desc *desc;
@@ -407,7 +419,7 @@
 		while (desc) {
 			for (i = 0; i < RMAP_EXT && desc->shadow_ptes[i]; ++i)
 				if (desc->shadow_ptes[i] == spte) {
-					rmap_desc_remove_entry(vcpu, page,
+					rmap_desc_remove_entry(page,
 							       desc, i,
 							       prev_desc);
 					return;
@@ -442,7 +454,7 @@
 		BUG_ON(!(*spte & PT_PRESENT_MASK));
 		BUG_ON(!(*spte & PT_WRITABLE_MASK));
 		rmap_printk("rmap_write_protect: spte %p %llx\n", spte, *spte);
-		rmap_remove(vcpu, spte);
+		rmap_remove(spte);
 		set_shadow_pte(spte, *spte & ~PT_WRITABLE_MASK);
 		kvm_flush_remote_tlbs(vcpu->kvm);
 	}
@@ -464,14 +476,14 @@
 }
 #endif
 
-static void kvm_mmu_free_page(struct kvm_vcpu *vcpu,
+static void kvm_mmu_free_page(struct kvm *kvm,
 			      struct kvm_mmu_page *page_head)
 {
 	ASSERT(is_empty_shadow_page(page_head->spt));
 	list_del(&page_head->link);
-	mmu_memory_cache_free(&vcpu->mmu_page_cache, page_head->spt);
-	mmu_memory_cache_free(&vcpu->mmu_page_header_cache, page_head);
-	++vcpu->kvm->n_free_mmu_pages;
+	__free_page(virt_to_page(page_head->spt));
+	kfree(page_head);
+	++kvm->n_free_mmu_pages;
 }
 
 static unsigned kvm_page_table_hashfn(gfn_t gfn)
@@ -537,8 +549,7 @@
 	pte_chain->parent_ptes[0] = parent_pte;
 }
 
-static void mmu_page_remove_parent_pte(struct kvm_vcpu *vcpu,
-				       struct kvm_mmu_page *page,
+static void mmu_page_remove_parent_pte(struct kvm_mmu_page *page,
 				       u64 *parent_pte)
 {
 	struct kvm_pte_chain *pte_chain;
@@ -565,7 +576,7 @@
 			pte_chain->parent_ptes[i] = NULL;
 			if (i == 0) {
 				hlist_del(&pte_chain->link);
-				mmu_free_pte_chain(vcpu, pte_chain);
+				mmu_free_pte_chain(pte_chain);
 				if (hlist_empty(&page->parent_ptes)) {
 					page->multimapped = 0;
 					page->parent_pte = NULL;
@@ -643,7 +654,7 @@
 	return page;
 }
 
-static void kvm_mmu_page_unlink_children(struct kvm_vcpu *vcpu,
+static void kvm_mmu_page_unlink_children(struct kvm *kvm,
 					 struct kvm_mmu_page *page)
 {
 	unsigned i;
@@ -655,10 +666,10 @@
 	if (page->role.level == PT_PAGE_TABLE_LEVEL) {
 		for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
 			if (pt[i] & PT_PRESENT_MASK)
-				rmap_remove(vcpu, &pt[i]);
+				rmap_remove(&pt[i]);
 			pt[i] = 0;
 		}
-		kvm_flush_remote_tlbs(vcpu->kvm);
+		kvm_flush_remote_tlbs(kvm);
 		return;
 	}
 
@@ -669,19 +680,18 @@
 		if (!(ent & PT_PRESENT_MASK))
 			continue;
 		ent &= PT64_BASE_ADDR_MASK;
-		mmu_page_remove_parent_pte(vcpu, page_header(ent), &pt[i]);
+		mmu_page_remove_parent_pte(page_header(ent), &pt[i]);
 	}
-	kvm_flush_remote_tlbs(vcpu->kvm);
+	kvm_flush_remote_tlbs(kvm);
 }
 
-static void kvm_mmu_put_page(struct kvm_vcpu *vcpu,
-			     struct kvm_mmu_page *page,
+static void kvm_mmu_put_page(struct kvm_mmu_page *page,
 			     u64 *parent_pte)
 {
-	mmu_page_remove_parent_pte(vcpu, page, parent_pte);
+	mmu_page_remove_parent_pte(page, parent_pte);
 }
 
-static void kvm_mmu_zap_page(struct kvm_vcpu *vcpu,
+static void kvm_mmu_zap_page(struct kvm *kvm,
 			     struct kvm_mmu_page *page)
 {
 	u64 *parent_pte;
@@ -697,15 +707,15 @@
 			parent_pte = chain->parent_ptes[0];
 		}
 		BUG_ON(!parent_pte);
-		kvm_mmu_put_page(vcpu, page, parent_pte);
+		kvm_mmu_put_page(page, parent_pte);
 		set_shadow_pte(parent_pte, 0);
 	}
-	kvm_mmu_page_unlink_children(vcpu, page);
+	kvm_mmu_page_unlink_children(kvm, page);
 	if (!page->root_count) {
 		hlist_del(&page->hash_link);
-		kvm_mmu_free_page(vcpu, page);
+		kvm_mmu_free_page(kvm, page);
 	} else
-		list_move(&page->link, &vcpu->kvm->active_mmu_pages);
+		list_move(&page->link, &kvm->active_mmu_pages);
 }
 
 static int kvm_mmu_unprotect_page(struct kvm_vcpu *vcpu, gfn_t gfn)
@@ -724,7 +734,7 @@
 		if (page->gfn == gfn && !page->role.metaphysical) {
 			pgprintk("%s: gfn %lx role %x\n", __FUNCTION__, gfn,
 				 page->role.word);
-			kvm_mmu_zap_page(vcpu, page);
+			kvm_mmu_zap_page(vcpu->kvm, page);
 			r = 1;
 		}
 	return r;
@@ -737,7 +747,7 @@
 	while ((page = kvm_mmu_lookup_page(vcpu, gfn)) != NULL) {
 		pgprintk("%s: zap %lx %x\n",
 			 __FUNCTION__, gfn, page->role.word);
-		kvm_mmu_zap_page(vcpu, page);
+		kvm_mmu_zap_page(vcpu->kvm, page);
 	}
 }
 
@@ -1089,10 +1099,10 @@
 	pte = *spte;
 	if (is_present_pte(pte)) {
 		if (page->role.level == PT_PAGE_TABLE_LEVEL)
-			rmap_remove(vcpu, spte);
+			rmap_remove(spte);
 		else {
 			child = page_header(pte & PT64_BASE_ADDR_MASK);
-			mmu_page_remove_parent_pte(vcpu, child, spte);
+			mmu_page_remove_parent_pte(child, spte);
 		}
 	}
 	*spte = 0;
@@ -1161,7 +1171,7 @@
 			 */
 			pgprintk("misaligned: gpa %llx bytes %d role %x\n",
 				 gpa, bytes, page->role.word);
-			kvm_mmu_zap_page(vcpu, page);
+			kvm_mmu_zap_page(vcpu->kvm, page);
 			continue;
 		}
 		page_offset = offset;
@@ -1200,17 +1210,16 @@
 	return kvm_mmu_unprotect_page(vcpu, gpa >> PAGE_SHIFT);
 }
 
-void kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
+void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu)
 {
 	while (vcpu->kvm->n_free_mmu_pages < KVM_REFILL_PAGES) {
 		struct kvm_mmu_page *page;
 
 		page = container_of(vcpu->kvm->active_mmu_pages.prev,
 				    struct kvm_mmu_page, link);
-		kvm_mmu_zap_page(vcpu, page);
+		kvm_mmu_zap_page(vcpu->kvm, page);
 	}
 }
-EXPORT_SYMBOL_GPL(kvm_mmu_free_some_pages);
 
 static void free_mmu_pages(struct kvm_vcpu *vcpu)
 {
@@ -1219,7 +1228,7 @@
 	while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
 		page = container_of(vcpu->kvm->active_mmu_pages.next,
 				    struct kvm_mmu_page, link);
-		kvm_mmu_zap_page(vcpu, page);
+		kvm_mmu_zap_page(vcpu->kvm, page);
 	}
 	free_page((unsigned long)vcpu->mmu.pae_root);
 }
@@ -1277,9 +1286,8 @@
 	mmu_free_memory_caches(vcpu);
 }
 
-void kvm_mmu_slot_remove_write_access(struct kvm_vcpu *vcpu, int slot)
+void kvm_mmu_slot_remove_write_access(struct kvm *kvm, int slot)
 {
-	struct kvm *kvm = vcpu->kvm;
 	struct kvm_mmu_page *page;
 
 	list_for_each_entry(page, &kvm->active_mmu_pages, link) {
@@ -1293,27 +1301,20 @@
 		for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
 			/* avoid RMW */
 			if (pt[i] & PT_WRITABLE_MASK) {
-				rmap_remove(vcpu, &pt[i]);
+				rmap_remove(&pt[i]);
 				pt[i] &= ~PT_WRITABLE_MASK;
 			}
 	}
 }
 
-void kvm_mmu_zap_all(struct kvm_vcpu *vcpu)
+void kvm_mmu_zap_all(struct kvm *kvm)
 {
-	destroy_kvm_mmu(vcpu);
+	struct kvm_mmu_page *page, *node;
 
-	while (!list_empty(&vcpu->kvm->active_mmu_pages)) {
-		struct kvm_mmu_page *page;
+	list_for_each_entry_safe(page, node, &kvm->active_mmu_pages, link)
+		kvm_mmu_zap_page(kvm, page);
 
-		page = container_of(vcpu->kvm->active_mmu_pages.next,
-				    struct kvm_mmu_page, link);
-		kvm_mmu_zap_page(vcpu, page);
-	}
-
-	mmu_free_memory_caches(vcpu);
-	kvm_flush_remote_tlbs(vcpu->kvm);
-	init_kvm_mmu(vcpu);
+	kvm_flush_remote_tlbs(kvm);
 }
 
 void kvm_mmu_module_exit(void)
@@ -1322,8 +1323,6 @@
 		kmem_cache_destroy(pte_chain_cache);
 	if (rmap_desc_cache)
 		kmem_cache_destroy(rmap_desc_cache);
-	if (mmu_page_cache)
-		kmem_cache_destroy(mmu_page_cache);
 	if (mmu_page_header_cache)
 		kmem_cache_destroy(mmu_page_header_cache);
 }
@@ -1332,24 +1331,18 @@
 {
 	pte_chain_cache = kmem_cache_create("kvm_pte_chain",
 					    sizeof(struct kvm_pte_chain),
-					    0, 0, NULL, NULL);
+					    0, 0, NULL);
 	if (!pte_chain_cache)
 		goto nomem;
 	rmap_desc_cache = kmem_cache_create("kvm_rmap_desc",
 					    sizeof(struct kvm_rmap_desc),
-					    0, 0, NULL, NULL);
+					    0, 0, NULL);
 	if (!rmap_desc_cache)
 		goto nomem;
 
-	mmu_page_cache = kmem_cache_create("kvm_mmu_page",
-					   PAGE_SIZE,
-					   PAGE_SIZE, 0, NULL, NULL);
-	if (!mmu_page_cache)
-		goto nomem;
-
 	mmu_page_header_cache = kmem_cache_create("kvm_mmu_page_header",
 						  sizeof(struct kvm_mmu_page),
-						  0, 0, NULL, NULL);
+						  0, 0, NULL);
 	if (!mmu_page_header_cache)
 		goto nomem;
 
diff --git a/drivers/kvm/paging_tmpl.h b/drivers/kvm/paging_tmpl.h
index a7c5cb0..4b5391c 100644
--- a/drivers/kvm/paging_tmpl.h
+++ b/drivers/kvm/paging_tmpl.h
@@ -366,6 +366,8 @@
 			metaphysical = 1;
 			hugepage_access = *guest_ent;
 			hugepage_access &= PT_USER_MASK | PT_WRITABLE_MASK;
+			if (*guest_ent & PT64_NX_MASK)
+				hugepage_access |= (1 << 2);
 			hugepage_access >>= PT_WRITABLE_SHIFT;
 			table_gfn = (*guest_ent & PT_BASE_ADDR_MASK)
 				>> PAGE_SHIFT;
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c
index f60012d..4b8a0cc9 100644
--- a/drivers/kvm/x86_emulate.c
+++ b/drivers/kvm/x86_emulate.c
@@ -163,7 +163,7 @@
 	ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0,
 	0, 0, 0, 0, 0, 0, 0, 0,
 	/* 0x30 - 0x3F */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 	/* 0x40 - 0x47 */
 	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
 	DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
@@ -486,6 +486,7 @@
 	unsigned long modrm_ea;
 	int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0;
 	int no_wb = 0;
+	u64 msr_data;
 
 	/* Shadow copy of register state. Committed on successful emulation. */
 	unsigned long _regs[NR_VCPU_REGS];
@@ -1177,6 +1178,8 @@
 twobyte_insn:
 	switch (b) {
 	case 0x01: /* lgdt, lidt, lmsw */
+		/* Disable writeback. */
+		no_wb = 1;
 		switch (modrm_reg) {
 			u16 size;
 			unsigned long address;
@@ -1214,11 +1217,13 @@
 		}
 		break;
 	case 0x21: /* mov from dr to reg */
+		no_wb = 1;
 		if (modrm_mod != 3)
 			goto cannot_emulate;
 		rc = emulator_get_dr(ctxt, modrm_reg, &_regs[modrm_rm]);
 		break;
 	case 0x23: /* mov from reg to dr */
+		no_wb = 1;
 		if (modrm_mod != 3)
 			goto cannot_emulate;
 		rc = emulator_set_dr(ctxt, modrm_reg, _regs[modrm_rm]);
@@ -1344,6 +1349,29 @@
 			goto cannot_emulate;
 		realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags);
 		break;
+	case 0x30:
+		/* wrmsr */
+		msr_data = (u32)_regs[VCPU_REGS_RAX]
+			| ((u64)_regs[VCPU_REGS_RDX] << 32);
+		rc = kvm_set_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], msr_data);
+		if (rc) {
+			kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+			_eip = ctxt->vcpu->rip;
+		}
+		rc = X86EMUL_CONTINUE;
+		break;
+	case 0x32:
+		/* rdmsr */
+		rc = kvm_get_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], &msr_data);
+		if (rc) {
+			kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+			_eip = ctxt->vcpu->rip;
+		} else {
+			_regs[VCPU_REGS_RAX] = (u32)msr_data;
+			_regs[VCPU_REGS_RDX] = msr_data >> 32;
+		}
+		rc = X86EMUL_CONTINUE;
+		break;
 	case 0xc7:		/* Grp9 (cmpxchg8b) */
 		{
 			u64 old, new;
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 87d2046..3cb2321 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -1,9 +1,6 @@
-
-menu "LED devices"
-	depends on HAS_IOMEM
-
-config NEW_LEDS
+menuconfig NEW_LEDS
 	bool "LED Support"
+	depends on HAS_IOMEM
 	help
 	  Say Y to enable Linux LED support.  This allows control of supported
 	  LEDs from both userspace and optionally, by kernel events (triggers).
@@ -11,9 +8,10 @@
 	  This is not related to standard keyboard LEDs which are controlled
 	  via the input system.
 
+if NEW_LEDS
+
 config LEDS_CLASS
 	tristate "LED Class Support"
-	depends on NEW_LEDS
 	help
 	  This option enables the led sysfs class in /sys/class/leds.  You'll
 	  need this to do anything useful with LEDs.  If unsure, say N.
@@ -89,17 +87,31 @@
 	help
 	  This option enables support for the LEDs on the h1940.
 
-config LEDS_COBALT
-	tristate "LED Support for Cobalt Server front LED"
+config LEDS_COBALT_QUBE
+	tristate "LED Support for the Cobalt Qube series front LED"
 	depends on LEDS_CLASS && MIPS_COBALT
 	help
-	  This option enables support for the front LED on Cobalt Server
+	  This option enables support for the front LED on Cobalt Qube series
+
+config LEDS_COBALT_RAQ
+	bool "LED Support for the Cobalt Raq series"
+	depends on LEDS_CLASS && MIPS_COBALT
+	select LEDS_TRIGGERS
+	help
+	  This option enables support for the Cobalt Raq series LEDs.
+
+config LEDS_GPIO
+	tristate "LED Support for GPIO connected LEDs"
+	depends on LEDS_CLASS && GENERIC_GPIO
+	help
+	  This option enables support for the LEDs connected to GPIO
+	  outputs. To be useful the particular board must have LEDs
+	  and they must be connected to the GPIO lines.
 
 comment "LED Triggers"
 
 config LEDS_TRIGGERS
 	bool "LED Trigger support"
-	depends on NEW_LEDS
 	help
 	  This option enables trigger support for the leds class.
 	  These triggers allow kernel events to drive the LEDs and can
@@ -128,5 +140,4 @@
 	  load average.
 	  If unsure, say Y.
 
-endmenu
-
+endif # NEW_LEDS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index aa2c18e..d2ca1ab 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -15,7 +15,9 @@
 obj-$(CONFIG_LEDS_NET48XX)		+= leds-net48xx.o
 obj-$(CONFIG_LEDS_WRAP)			+= leds-wrap.o
 obj-$(CONFIG_LEDS_H1940)		+= leds-h1940.o
-obj-$(CONFIG_LEDS_COBALT)		+= leds-cobalt.o
+obj-$(CONFIG_LEDS_COBALT_QUBE)		+= leds-cobalt-qube.o
+obj-$(CONFIG_LEDS_COBALT_RAQ)		+= leds-cobalt-raq.o
+obj-$(CONFIG_LEDS_GPIO)			+= leds-gpio.o
 
 # LED Triggers
 obj-$(CONFIG_LEDS_TRIGGER_TIMER)	+= ledtrig-timer.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 3c17112..4211293 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -2,7 +2,7 @@
  * LED Class Core
  *
  * Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
- * Copyright (C) 2005-2006 Richard Purdie <rpurdie@openedhand.com>
+ * Copyright (C) 2005-2007 Richard Purdie <rpurdie@openedhand.com>
  *
  * 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
@@ -24,9 +24,10 @@
 
 static struct class *leds_class;
 
-static ssize_t led_brightness_show(struct class_device *dev, char *buf)
+static ssize_t led_brightness_show(struct device *dev, 
+		struct device_attribute *attr, char *buf)
 {
-	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 	ssize_t ret = 0;
 
 	/* no lock needed for this */
@@ -36,10 +37,10 @@
 	return ret;
 }
 
-static ssize_t led_brightness_store(struct class_device *dev,
-				const char *buf, size_t size)
+static ssize_t led_brightness_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
 {
-	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 	ssize_t ret = -EINVAL;
 	char *after;
 	unsigned long state = simple_strtoul(buf, &after, 10);
@@ -56,10 +57,9 @@
 	return ret;
 }
 
-static CLASS_DEVICE_ATTR(brightness, 0644, led_brightness_show,
-			led_brightness_store);
+static DEVICE_ATTR(brightness, 0644, led_brightness_show, led_brightness_store);
 #ifdef CONFIG_LEDS_TRIGGERS
-static CLASS_DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
+static DEVICE_ATTR(trigger, 0644, led_trigger_show, led_trigger_store);
 #endif
 
 /**
@@ -93,16 +93,15 @@
 {
 	int rc;
 
-	led_cdev->class_dev = class_device_create(leds_class, NULL, 0,
-						parent, "%s", led_cdev->name);
-	if (unlikely(IS_ERR(led_cdev->class_dev)))
-		return PTR_ERR(led_cdev->class_dev);
+	led_cdev->dev = device_create(leds_class, parent, 0, "%s",
+					    led_cdev->name);
+	if (unlikely(IS_ERR(led_cdev->dev)))
+		return PTR_ERR(led_cdev->dev);
 
-	class_set_devdata(led_cdev->class_dev, led_cdev);
+	dev_set_drvdata(led_cdev->dev, led_cdev);
 
 	/* register the attributes */
-	rc = class_device_create_file(led_cdev->class_dev,
-				      &class_device_attr_brightness);
+	rc = device_create_file(led_cdev->dev, &dev_attr_brightness);
 	if (rc)
 		goto err_out;
 
@@ -114,8 +113,7 @@
 #ifdef CONFIG_LEDS_TRIGGERS
 	rwlock_init(&led_cdev->trigger_lock);
 
-	rc = class_device_create_file(led_cdev->class_dev,
-				      &class_device_attr_trigger);
+	rc = device_create_file(led_cdev->dev, &dev_attr_trigger);
 	if (rc)
 		goto err_out_led_list;
 
@@ -123,18 +121,17 @@
 #endif
 
 	printk(KERN_INFO "Registered led device: %s\n",
-			led_cdev->class_dev->class_id);
+			led_cdev->name);
 
 	return 0;
 
 #ifdef CONFIG_LEDS_TRIGGERS
 err_out_led_list:
-	class_device_remove_file(led_cdev->class_dev,
-				&class_device_attr_brightness);
+	device_remove_file(led_cdev->dev, &dev_attr_brightness);
 	list_del(&led_cdev->node);
 #endif
 err_out:
-	class_device_unregister(led_cdev->class_dev);
+	device_unregister(led_cdev->dev);
 	return rc;
 }
 EXPORT_SYMBOL_GPL(led_classdev_register);
@@ -147,18 +144,16 @@
  */
 void led_classdev_unregister(struct led_classdev *led_cdev)
 {
-	class_device_remove_file(led_cdev->class_dev,
-				&class_device_attr_brightness);
+	device_remove_file(led_cdev->dev, &dev_attr_brightness);
 #ifdef CONFIG_LEDS_TRIGGERS
-	class_device_remove_file(led_cdev->class_dev,
-				&class_device_attr_trigger);
+	device_remove_file(led_cdev->dev, &dev_attr_trigger);
 	write_lock(&led_cdev->trigger_lock);
 	if (led_cdev->trigger)
 		led_trigger_set(led_cdev, NULL);
 	write_unlock(&led_cdev->trigger_lock);
 #endif
 
-	class_device_unregister(led_cdev->class_dev);
+	device_unregister(led_cdev->dev);
 
 	write_lock(&leds_list_lock);
 	list_del(&led_cdev->node);
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 454fb09..575368c 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -1,7 +1,7 @@
 /*
  * LED Triggers Core
  *
- * Copyright 2005-2006 Openedhand Ltd.
+ * Copyright 2005-2007 Openedhand Ltd.
  *
  * Author: Richard Purdie <rpurdie@openedhand.com>
  *
@@ -28,10 +28,10 @@
 static DEFINE_RWLOCK(triggers_list_lock);
 static LIST_HEAD(trigger_list);
 
-ssize_t led_trigger_store(struct class_device *dev, const char *buf,
-			size_t count)
+ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
 {
-	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 	char trigger_name[TRIG_NAME_MAX];
 	struct led_trigger *trig;
 	size_t len;
@@ -67,9 +67,10 @@
 }
 
 
-ssize_t led_trigger_show(struct class_device *dev, char *buf)
+ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
-	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 	struct led_trigger *trig;
 	int len = 0;
 
@@ -183,13 +184,20 @@
 void led_trigger_register_simple(const char *name, struct led_trigger **tp)
 {
 	struct led_trigger *trigger;
+	int err;
 
 	trigger = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
 
 	if (trigger) {
 		trigger->name = name;
-		led_trigger_register(trigger);
-	}
+		err = led_trigger_register(trigger);
+		if (err < 0)
+			printk(KERN_WARNING "LED trigger %s failed to register"
+				" (%d)\n", name, err);
+	} else
+		printk(KERN_WARNING "LED trigger %s failed to register"
+			" (no memory)\n", name);
+
 	*tp = trigger;
 }
 
@@ -215,7 +223,8 @@
 
 void led_trigger_unregister_simple(struct led_trigger *trigger)
 {
-	led_trigger_unregister(trigger);
+	if (trigger)
+		led_trigger_unregister(trigger);
 	kfree(trigger);
 }
 
diff --git a/drivers/leds/leds-cobalt-qube.c b/drivers/leds/leds-cobalt-qube.c
new file mode 100644
index 0000000..d2b54b5
--- /dev/null
+++ b/drivers/leds/leds-cobalt-qube.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2006 - Florian Fainelli <florian@openwrt.org>
+ *
+ * Control the Cobalt Qube/RaQ front LED
+ */
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+
+#define LED_FRONT_LEFT	0x01
+#define LED_FRONT_RIGHT	0x02
+
+static void __iomem *led_port;
+static u8 led_value;
+
+static void qube_front_led_set(struct led_classdev *led_cdev,
+                               enum led_brightness brightness)
+{
+	if (brightness)
+		led_value = LED_FRONT_LEFT | LED_FRONT_RIGHT;
+	else
+		led_value = ~(LED_FRONT_LEFT | LED_FRONT_RIGHT);
+	writeb(led_value, led_port);
+}
+
+static struct led_classdev qube_front_led = {
+	.name			= "qube-front",
+	.brightness		= LED_FULL,
+	.brightness_set		= qube_front_led_set,
+	.default_trigger	= "ide-disk",
+};
+
+static int __devinit cobalt_qube_led_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int retval;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EBUSY;
+
+	led_port = ioremap(res->start, res->end - res->start + 1);
+	if (!led_port)
+		return -ENOMEM;
+
+	led_value = LED_FRONT_LEFT | LED_FRONT_RIGHT;
+	writeb(led_value, led_port);
+
+	retval = led_classdev_register(&pdev->dev, &qube_front_led);
+	if (retval)
+		goto err_iounmap;
+
+	return 0;
+
+err_iounmap:
+	iounmap(led_port);
+	led_port = NULL;
+
+	return retval;
+}
+
+static int __devexit cobalt_qube_led_remove(struct platform_device *pdev)
+{
+	led_classdev_unregister(&qube_front_led);
+
+	if (led_port) {
+		iounmap(led_port);
+		led_port = NULL;
+	}
+
+	return 0;
+}
+
+static struct platform_driver cobalt_qube_led_driver = {
+	.probe	= cobalt_qube_led_probe,
+	.remove	= __devexit_p(cobalt_qube_led_remove),
+	.driver	= {
+		.name	= "cobalt-qube-leds",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init cobalt_qube_led_init(void)
+{
+	return platform_driver_register(&cobalt_qube_led_driver);
+}
+
+static void __exit cobalt_qube_led_exit(void)
+{
+	platform_driver_unregister(&cobalt_qube_led_driver);
+}
+
+module_init(cobalt_qube_led_init);
+module_exit(cobalt_qube_led_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Front LED support for Cobalt Server");
+MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
diff --git a/drivers/leds/leds-cobalt-raq.c b/drivers/leds/leds-cobalt-raq.c
new file mode 100644
index 0000000..6ebfff3
--- /dev/null
+++ b/drivers/leds/leds-cobalt-raq.c
@@ -0,0 +1,138 @@
+/*
+ *  LEDs driver for the Cobalt Raq series.
+ *
+ *  Copyright (C) 2007  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *
+ *  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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#define LED_WEB		0x04
+#define LED_POWER_OFF	0x08
+
+static void __iomem *led_port;
+static u8 led_value;
+static DEFINE_SPINLOCK(led_value_lock);
+
+static void raq_web_led_set(struct led_classdev *led_cdev,
+                            enum led_brightness brightness)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&led_value_lock, flags);
+
+	if (brightness)
+		led_value |= LED_WEB;
+	else
+		led_value &= ~LED_WEB;
+	writeb(led_value, led_port);
+
+	spin_unlock_irqrestore(&led_value_lock, flags);
+}
+
+static struct led_classdev raq_web_led = {
+	.name		= "raq-web",
+	.brightness_set	= raq_web_led_set,
+};
+
+static void raq_power_off_led_set(struct led_classdev *led_cdev,
+                                  enum led_brightness brightness)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&led_value_lock, flags);
+
+	if (brightness)
+		led_value |= LED_POWER_OFF;
+	else
+		led_value &= ~LED_POWER_OFF;
+	writeb(led_value, led_port);
+
+	spin_unlock_irqrestore(&led_value_lock, flags);
+}
+
+static struct led_classdev raq_power_off_led = {
+	.name			= "raq-power-off",
+	.brightness_set		= raq_power_off_led_set,
+	.default_trigger	= "power-off",
+};
+
+static int __devinit cobalt_raq_led_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	int retval;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -EBUSY;
+
+	led_port = ioremap(res->start, res->end - res->start + 1);
+	if (!led_port)
+		return -ENOMEM;
+
+	retval = led_classdev_register(&pdev->dev, &raq_power_off_led);
+	if (retval)
+		goto err_iounmap;
+
+	retval = led_classdev_register(&pdev->dev, &raq_web_led);
+	if (retval)
+		goto err_unregister;
+
+	return 0;
+
+err_unregister:
+	led_classdev_unregister(&raq_power_off_led);
+
+err_iounmap:
+	iounmap(led_port);
+	led_port = NULL;
+
+	return retval;
+}
+
+static int __devexit cobalt_raq_led_remove(struct platform_device *pdev)
+{
+	led_classdev_unregister(&raq_power_off_led);
+	led_classdev_unregister(&raq_web_led);
+
+	if (led_port) {
+		iounmap(led_port);
+		led_port = NULL;
+	}
+
+	return 0;
+}
+
+static struct platform_driver cobalt_raq_led_driver = {
+	.probe	= cobalt_raq_led_probe,
+	.remove	= __devexit_p(cobalt_raq_led_remove),
+	.driver = {
+		.name	= "cobalt-raq-leds",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init cobalt_raq_led_init(void)
+{
+	return platform_driver_register(&cobalt_raq_led_driver);
+}
+
+module_init(cobalt_raq_led_init);
diff --git a/drivers/leds/leds-cobalt.c b/drivers/leds/leds-cobalt.c
deleted file mode 100644
index d16439c..0000000
--- a/drivers/leds/leds-cobalt.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2006 - Florian Fainelli <florian@openwrt.org>
- *
- * Control the Cobalt Qube/RaQ front LED
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/leds.h>
-#include <asm/mach-cobalt/cobalt.h>
-
-static void cobalt_led_set(struct led_classdev *led_cdev, enum led_brightness brightness)
-{
-	if (brightness)
-		COBALT_LED_PORT = COBALT_LED_BAR_LEFT | COBALT_LED_BAR_RIGHT;
-	else
-		COBALT_LED_PORT = 0;
-}
-
-static struct led_classdev cobalt_led = {
-       .name = "cobalt-front-led",
-       .brightness_set = cobalt_led_set,
-       .default_trigger = "ide-disk",
-};
-
-static int __init cobalt_led_init(void)
-{
-	return led_classdev_register(NULL, &cobalt_led);
-}
-
-static void __exit cobalt_led_exit(void)
-{
-	led_classdev_unregister(&cobalt_led);
-}
-
-module_init(cobalt_led_init);
-module_exit(cobalt_led_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Front LED support for Cobalt Server");
-MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
new file mode 100644
index 0000000..47d90db
--- /dev/null
+++ b/drivers/leds/leds-gpio.c
@@ -0,0 +1,199 @@
+/*
+ * LEDs driver for GPIOs
+ *
+ * Copyright (C) 2007 8D Technologies inc.
+ * Raphael Assenat <raph@8d.com>
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/workqueue.h>
+
+#include <asm/gpio.h>
+
+struct gpio_led_data {
+	struct led_classdev cdev;
+	unsigned gpio;
+	struct work_struct work;
+	u8 new_level;
+	u8 can_sleep;
+	u8 active_low;
+};
+
+static void gpio_led_work(struct work_struct *work)
+{
+	struct gpio_led_data	*led_dat =
+		container_of(work, struct gpio_led_data, work);
+
+	gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
+}
+
+static void gpio_led_set(struct led_classdev *led_cdev,
+	enum led_brightness value)
+{
+	struct gpio_led_data *led_dat =
+		container_of(led_cdev, struct gpio_led_data, cdev);
+	int level;
+
+	if (value == LED_OFF)
+		level = 0;
+	else
+		level = 1;
+
+	if (led_dat->active_low)
+		level = !level;
+
+	/* setting GPIOs with I2C/etc requires a preemptible task context */
+	if (led_dat->can_sleep) {
+		if (preempt_count()) {
+			led_dat->new_level = level;
+			schedule_work(&led_dat->work);
+		} else
+			gpio_set_value_cansleep(led_dat->gpio, level);
+	} else
+		gpio_set_value(led_dat->gpio, level);
+}
+
+static int __init gpio_led_probe(struct platform_device *pdev)
+{
+	struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+	struct gpio_led *cur_led;
+	struct gpio_led_data *leds_data, *led_dat;
+	int i, ret = 0;
+
+	if (!pdata)
+		return -EBUSY;
+
+	leds_data = kzalloc(sizeof(struct gpio_led_data) * pdata->num_leds,
+				GFP_KERNEL);
+	if (!leds_data)
+		return -ENOMEM;
+
+	for (i = 0; i < pdata->num_leds; i++) {
+		cur_led = &pdata->leds[i];
+		led_dat = &leds_data[i];
+
+		led_dat->cdev.name = cur_led->name;
+		led_dat->cdev.default_trigger = cur_led->default_trigger;
+		led_dat->gpio = cur_led->gpio;
+		led_dat->can_sleep = gpio_cansleep(cur_led->gpio);
+		led_dat->active_low = cur_led->active_low;
+		led_dat->cdev.brightness_set = gpio_led_set;
+		led_dat->cdev.brightness = cur_led->active_low ? LED_FULL : LED_OFF;
+
+		ret = gpio_request(led_dat->gpio, led_dat->cdev.name);
+		if (ret < 0)
+			goto err;
+
+		gpio_direction_output(led_dat->gpio, led_dat->active_low);
+
+		ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
+		if (ret < 0) {
+			gpio_free(led_dat->gpio);
+			goto err;
+		}
+
+		INIT_WORK(&led_dat->work, gpio_led_work);
+	}
+
+	platform_set_drvdata(pdev, leds_data);
+
+	return 0;
+
+err:
+	if (i > 0) {
+		for (i = i - 1; i >= 0; i--) {
+			led_classdev_unregister(&leds_data[i].cdev);
+			gpio_free(leds_data[i].gpio);
+		}
+	}
+
+	flush_scheduled_work();
+	kfree(leds_data);
+
+	return ret;
+}
+
+static int __exit gpio_led_remove(struct platform_device *pdev)
+{
+	int i;
+	struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+	struct gpio_led_data *leds_data;
+
+	leds_data = platform_get_drvdata(pdev);
+
+	for (i = 0; i < pdata->num_leds; i++) {
+		led_classdev_unregister(&leds_data[i].cdev);
+		gpio_free(leds_data[i].gpio);
+	}
+	
+	kfree(leds_data);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int gpio_led_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+	struct gpio_led_data *leds_data;
+	int i;
+	
+	leds_data = platform_get_drvdata(pdev);
+
+	for (i = 0; i < pdata->num_leds; i++)
+		led_classdev_suspend(&leds_data[i].cdev);
+
+	return 0;
+}
+
+static int gpio_led_resume(struct platform_device *pdev)
+{
+	struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+	struct gpio_led_data *leds_data;
+	int i;
+
+	leds_data = platform_get_drvdata(pdev);
+
+	for (i = 0; i < pdata->num_leds; i++)
+		led_classdev_resume(&leds_data[i].cdev);
+
+	return 0;
+}
+#else
+#define gpio_led_suspend NULL
+#define gpio_led_resume NULL
+#endif
+
+static struct platform_driver gpio_led_driver = {
+	.remove		= __exit_p(gpio_led_remove),
+	.suspend	= gpio_led_suspend,
+	.resume		= gpio_led_resume,
+	.driver		= {
+		.name	= "leds-gpio",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init gpio_led_init(void)
+{
+	return platform_driver_probe(&gpio_led_driver, gpio_led_probe);
+}
+
+static void __exit gpio_led_exit(void)
+{
+	platform_driver_unregister(&gpio_led_driver);
+}
+
+module_init(gpio_led_init);
+module_exit(gpio_led_exit);
+
+MODULE_AUTHOR("Raphael Assenat <raph@8d.com>");
+MODULE_DESCRIPTION("GPIO LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c
index 6f2d449..bfac499 100644
--- a/drivers/leds/leds-locomo.c
+++ b/drivers/leds/leds-locomo.c
@@ -19,7 +19,7 @@
 static void locomoled_brightness_set(struct led_classdev *led_cdev,
 				enum led_brightness value, int offset)
 {
-	struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->class_dev->dev);
+	struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->dev);
 	unsigned long flags;
 
 	local_irq_save(flags);
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index a715c4e..f2f3884 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -13,6 +13,7 @@
 #ifndef __LEDS_H_INCLUDED
 #define __LEDS_H_INCLUDED
 
+#include <linux/device.h>
 #include <linux/leds.h>
 
 static inline void led_set_brightness(struct led_classdev *led_cdev,
@@ -37,8 +38,9 @@
 #define led_trigger_set(x, y) do {} while(0)
 #endif
 
-ssize_t led_trigger_store(struct class_device *dev, const char *buf,
-			size_t count);
-ssize_t led_trigger_show(struct class_device *dev, char *buf);
+ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count);
+ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
+			char *buf);
 
 #endif	/* __LEDS_H_INCLUDED */
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index d756bdb..ed9ff02 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -52,9 +52,10 @@
 	mod_timer(&timer_data->timer, jiffies + msecs_to_jiffies(delay));
 }
 
-static ssize_t led_delay_on_show(struct class_device *dev, char *buf)
+static ssize_t led_delay_on_show(struct device *dev, 
+		struct device_attribute *attr, char *buf)
 {
-	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 	struct timer_trig_data *timer_data = led_cdev->trigger_data;
 
 	sprintf(buf, "%lu\n", timer_data->delay_on);
@@ -62,10 +63,10 @@
 	return strlen(buf) + 1;
 }
 
-static ssize_t led_delay_on_store(struct class_device *dev, const char *buf,
-				size_t size)
+static ssize_t led_delay_on_store(struct device *dev, 
+		struct device_attribute *attr, const char *buf, size_t size)
 {
-	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 	struct timer_trig_data *timer_data = led_cdev->trigger_data;
 	int ret = -EINVAL;
 	char *after;
@@ -84,9 +85,10 @@
 	return ret;
 }
 
-static ssize_t led_delay_off_show(struct class_device *dev, char *buf)
+static ssize_t led_delay_off_show(struct device *dev, 
+		struct device_attribute *attr, char *buf)
 {
-	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 	struct timer_trig_data *timer_data = led_cdev->trigger_data;
 
 	sprintf(buf, "%lu\n", timer_data->delay_off);
@@ -94,10 +96,10 @@
 	return strlen(buf) + 1;
 }
 
-static ssize_t led_delay_off_store(struct class_device *dev, const char *buf,
-				size_t size)
+static ssize_t led_delay_off_store(struct device *dev, 
+		struct device_attribute *attr, const char *buf, size_t size)
 {
-	struct led_classdev *led_cdev = class_get_devdata(dev);
+	struct led_classdev *led_cdev = dev_get_drvdata(dev);
 	struct timer_trig_data *timer_data = led_cdev->trigger_data;
 	int ret = -EINVAL;
 	char *after;
@@ -116,10 +118,8 @@
 	return ret;
 }
 
-static CLASS_DEVICE_ATTR(delay_on, 0644, led_delay_on_show,
-			led_delay_on_store);
-static CLASS_DEVICE_ATTR(delay_off, 0644, led_delay_off_show,
-			led_delay_off_store);
+static DEVICE_ATTR(delay_on, 0644, led_delay_on_show, led_delay_on_store);
+static DEVICE_ATTR(delay_off, 0644, led_delay_off_show, led_delay_off_store);
 
 static void timer_trig_activate(struct led_classdev *led_cdev)
 {
@@ -136,18 +136,17 @@
 	timer_data->timer.function = led_timer_function;
 	timer_data->timer.data = (unsigned long) led_cdev;
 
-	rc = class_device_create_file(led_cdev->class_dev,
-				&class_device_attr_delay_on);
-	if (rc) goto err_out;
-	rc = class_device_create_file(led_cdev->class_dev,
-				&class_device_attr_delay_off);
-	if (rc) goto err_out_delayon;
+	rc = device_create_file(led_cdev->dev, &dev_attr_delay_on);
+	if (rc)
+		goto err_out;
+	rc = device_create_file(led_cdev->dev, &dev_attr_delay_off);
+	if (rc)
+		goto err_out_delayon;
 
 	return;
 
 err_out_delayon:
-	class_device_remove_file(led_cdev->class_dev,
-				&class_device_attr_delay_on);
+	device_remove_file(led_cdev->dev, &dev_attr_delay_on);
 err_out:
 	led_cdev->trigger_data = NULL;
 	kfree(timer_data);
@@ -158,10 +157,8 @@
 	struct timer_trig_data *timer_data = led_cdev->trigger_data;
 
 	if (timer_data) {
-		class_device_remove_file(led_cdev->class_dev,
-					&class_device_attr_delay_on);
-		class_device_remove_file(led_cdev->class_dev,
-					&class_device_attr_delay_off);
+		device_remove_file(led_cdev->dev, &dev_attr_delay_on);
+		device_remove_file(led_cdev->dev, &dev_attr_delay_off);
 		del_timer_sync(&timer_data->timer);
 		kfree(timer_data);
 	}
diff --git a/drivers/lguest/Kconfig b/drivers/lguest/Kconfig
new file mode 100644
index 0000000..41e2250
--- /dev/null
+++ b/drivers/lguest/Kconfig
@@ -0,0 +1,30 @@
+config LGUEST
+	tristate "Linux hypervisor example code"
+	depends on X86 && PARAVIRT && EXPERIMENTAL && !X86_PAE && FUTEX
+	select LGUEST_GUEST
+	select HVC_DRIVER
+	---help---
+	  This is a very simple module which allows you to run
+	  multiple instances of the same Linux kernel, using the
+	  "lguest" command found in the Documentation/lguest directory.
+	  Note that "lguest" is pronounced to rhyme with "fell quest",
+	  not "rustyvisor".  See Documentation/lguest/lguest.txt.
+
+	  If unsure, say N.  If curious, say M.  If masochistic, say Y.
+
+config LGUEST_GUEST
+	bool
+	help
+	  The guest needs code built-in, even if the host has lguest
+	  support as a module.  The drivers are tiny, so we build them
+	  in too.
+
+config LGUEST_NET
+	tristate
+	default y
+	depends on LGUEST_GUEST && NET
+
+config LGUEST_BLOCK
+	tristate
+	default y
+	depends on LGUEST_GUEST && BLOCK
diff --git a/drivers/lguest/Makefile b/drivers/lguest/Makefile
new file mode 100644
index 0000000..e504747
--- /dev/null
+++ b/drivers/lguest/Makefile
@@ -0,0 +1,19 @@
+# Guest requires the paravirt_ops replacement and the bus driver.
+obj-$(CONFIG_LGUEST_GUEST) += lguest.o lguest_asm.o lguest_bus.o
+
+# Host requires the other files, which can be a module.
+obj-$(CONFIG_LGUEST)	+= lg.o
+lg-y := core.o hypercalls.o page_tables.o interrupts_and_traps.o \
+	segments.o io.o lguest_user.o switcher.o
+
+Preparation Preparation!: PREFIX=P
+Guest: PREFIX=G
+Drivers: PREFIX=D
+Launcher: PREFIX=L
+Host: PREFIX=H
+Switcher: PREFIX=S
+Mastery: PREFIX=M
+Beer:
+	@for f in Preparation Guest Drivers Launcher Host Switcher Mastery; do echo "{==- $$f -==}"; make -s $$f; done; echo "{==-==}"
+Preparation Preparation! Guest Drivers Launcher Host Switcher Mastery:
+	@sh ../../Documentation/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'`
diff --git a/drivers/lguest/README b/drivers/lguest/README
new file mode 100644
index 0000000..b7db39a
--- /dev/null
+++ b/drivers/lguest/README
@@ -0,0 +1,47 @@
+Welcome, friend reader, to lguest.
+
+Lguest is an adventure, with you, the reader, as Hero.  I can't think of many
+5000-line projects which offer both such capability and glimpses of future
+potential; it is an exciting time to be delving into the source!
+
+But be warned; this is an arduous journey of several hours or more!  And as we
+know, all true Heroes are driven by a Noble Goal.  Thus I offer a Beer (or
+equivalent) to anyone I meet who has completed this documentation.
+
+So get comfortable and keep your wits about you (both quick and humorous).
+Along your way to the Noble Goal, you will also gain masterly insight into
+lguest, and hypervisors and x86 virtualization in general.
+
+Our Quest is in seven parts: (best read with C highlighting turned on)
+
+I) Preparation
+	- In which our potential hero is flown quickly over the landscape for a
+	  taste of its scope.  Suitable for the armchair coders and other such
+	  persons of faint constitution.
+
+II) Guest
+	- Where we encounter the first tantalising wisps of code, and come to
+	  understand the details of the life of a Guest kernel.
+
+III) Drivers
+	- Whereby the Guest finds its voice and become useful, and our
+	  understanding of the Guest is completed.
+
+IV) Launcher
+	- Where we trace back to the creation of the Guest, and thus begin our
+	  understanding of the Host.
+
+V) Host
+	- Where we master the Host code, through a long and tortuous journey.
+	  Indeed, it is here that our hero is tested in the Bit of Despair.
+
+VI) Switcher
+	- Where our understanding of the intertwined nature of Guests and Hosts
+	  is completed.
+
+VII) Mastery
+	- Where our fully fledged hero grapples with the Great Question:
+	  "What next?"
+
+make Preparation!
+Rusty Russell.
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c
new file mode 100644
index 0000000..4a315f0
--- /dev/null
+++ b/drivers/lguest/core.c
@@ -0,0 +1,776 @@
+/*P:400 This contains run_guest() which actually calls into the Host<->Guest
+ * Switcher and analyzes the return, such as determining if the Guest wants the
+ * Host to do something.  This file also contains useful helper routines, and a
+ * couple of non-obvious setup and teardown pieces which were implemented after
+ * days of debugging pain. :*/
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include <linux/stddef.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/cpu.h>
+#include <linux/freezer.h>
+#include <asm/paravirt.h>
+#include <asm/desc.h>
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/poll.h>
+#include <asm/highmem.h>
+#include <asm/asm-offsets.h>
+#include <asm/i387.h>
+#include "lg.h"
+
+/* Found in switcher.S */
+extern char start_switcher_text[], end_switcher_text[], switch_to_guest[];
+extern unsigned long default_idt_entries[];
+
+/* Every guest maps the core switcher code. */
+#define SHARED_SWITCHER_PAGES \
+	DIV_ROUND_UP(end_switcher_text - start_switcher_text, PAGE_SIZE)
+/* Pages for switcher itself, then two pages per cpu */
+#define TOTAL_SWITCHER_PAGES (SHARED_SWITCHER_PAGES + 2 * NR_CPUS)
+
+/* We map at -4M for ease of mapping into the guest (one PTE page). */
+#define SWITCHER_ADDR 0xFFC00000
+
+static struct vm_struct *switcher_vma;
+static struct page **switcher_page;
+
+static int cpu_had_pge;
+static struct {
+	unsigned long offset;
+	unsigned short segment;
+} lguest_entry;
+
+/* This One Big lock protects all inter-guest data structures. */
+DEFINE_MUTEX(lguest_lock);
+static DEFINE_PER_CPU(struct lguest *, last_guest);
+
+/* FIXME: Make dynamic. */
+#define MAX_LGUEST_GUESTS 16
+struct lguest lguests[MAX_LGUEST_GUESTS];
+
+/* Offset from where switcher.S was compiled to where we've copied it */
+static unsigned long switcher_offset(void)
+{
+	return SWITCHER_ADDR - (unsigned long)start_switcher_text;
+}
+
+/* This cpu's struct lguest_pages. */
+static struct lguest_pages *lguest_pages(unsigned int cpu)
+{
+	return &(((struct lguest_pages *)
+		  (SWITCHER_ADDR + SHARED_SWITCHER_PAGES*PAGE_SIZE))[cpu]);
+}
+
+/*H:010 We need to set up the Switcher at a high virtual address.  Remember the
+ * Switcher is a few hundred bytes of assembler code which actually changes the
+ * CPU to run the Guest, and then changes back to the Host when a trap or
+ * interrupt happens.
+ *
+ * The Switcher code must be at the same virtual address in the Guest as the
+ * Host since it will be running as the switchover occurs.
+ *
+ * Trying to map memory at a particular address is an unusual thing to do, so
+ * it's not a simple one-liner.  We also set up the per-cpu parts of the
+ * Switcher here.
+ */
+static __init int map_switcher(void)
+{
+	int i, err;
+	struct page **pagep;
+
+	/*
+	 * Map the Switcher in to high memory.
+	 *
+	 * It turns out that if we choose the address 0xFFC00000 (4MB under the
+	 * top virtual address), it makes setting up the page tables really
+	 * easy.
+	 */
+
+	/* We allocate an array of "struct page"s.  map_vm_area() wants the
+	 * pages in this form, rather than just an array of pointers. */
+	switcher_page = kmalloc(sizeof(switcher_page[0])*TOTAL_SWITCHER_PAGES,
+				GFP_KERNEL);
+	if (!switcher_page) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	/* Now we actually allocate the pages.  The Guest will see these pages,
+	 * so we make sure they're zeroed. */
+	for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) {
+		unsigned long addr = get_zeroed_page(GFP_KERNEL);
+		if (!addr) {
+			err = -ENOMEM;
+			goto free_some_pages;
+		}
+		switcher_page[i] = virt_to_page(addr);
+	}
+
+	/* Now we reserve the "virtual memory area" we want: 0xFFC00000
+	 * (SWITCHER_ADDR).  We might not get it in theory, but in practice
+	 * it's worked so far. */
+	switcher_vma = __get_vm_area(TOTAL_SWITCHER_PAGES * PAGE_SIZE,
+				       VM_ALLOC, SWITCHER_ADDR, VMALLOC_END);
+	if (!switcher_vma) {
+		err = -ENOMEM;
+		printk("lguest: could not map switcher pages high\n");
+		goto free_pages;
+	}
+
+	/* This code actually sets up the pages we've allocated to appear at
+	 * SWITCHER_ADDR.  map_vm_area() takes the vma we allocated above, the
+	 * kind of pages we're mapping (kernel pages), and a pointer to our
+	 * array of struct pages.  It increments that pointer, but we don't
+	 * care. */
+	pagep = switcher_page;
+	err = map_vm_area(switcher_vma, PAGE_KERNEL, &pagep);
+	if (err) {
+		printk("lguest: map_vm_area failed: %i\n", err);
+		goto free_vma;
+	}
+
+	/* Now the switcher is mapped at the right address, we can't fail!
+	 * Copy in the compiled-in Switcher code (from switcher.S). */
+	memcpy(switcher_vma->addr, start_switcher_text,
+	       end_switcher_text - start_switcher_text);
+
+	/* Most of the switcher.S doesn't care that it's been moved; on Intel,
+	 * jumps are relative, and it doesn't access any references to external
+	 * code or data.
+	 *
+	 * The only exception is the interrupt handlers in switcher.S: their
+	 * addresses are placed in a table (default_idt_entries), so we need to
+	 * update the table with the new addresses.  switcher_offset() is a
+	 * convenience function which returns the distance between the builtin
+	 * switcher code and the high-mapped copy we just made. */
+	for (i = 0; i < IDT_ENTRIES; i++)
+		default_idt_entries[i] += switcher_offset();
+
+	/*
+	 * Set up the Switcher's per-cpu areas.
+	 *
+	 * Each CPU gets two pages of its own within the high-mapped region
+	 * (aka. "struct lguest_pages").  Much of this can be initialized now,
+	 * but some depends on what Guest we are running (which is set up in
+	 * copy_in_guest_info()).
+	 */
+	for_each_possible_cpu(i) {
+		/* lguest_pages() returns this CPU's two pages. */
+		struct lguest_pages *pages = lguest_pages(i);
+		/* This is a convenience pointer to make the code fit one
+		 * statement to a line. */
+		struct lguest_ro_state *state = &pages->state;
+
+		/* The Global Descriptor Table: the Host has a different one
+		 * for each CPU.  We keep a descriptor for the GDT which says
+		 * where it is and how big it is (the size is actually the last
+		 * byte, not the size, hence the "-1"). */
+		state->host_gdt_desc.size = GDT_SIZE-1;
+		state->host_gdt_desc.address = (long)get_cpu_gdt_table(i);
+
+		/* All CPUs on the Host use the same Interrupt Descriptor
+		 * Table, so we just use store_idt(), which gets this CPU's IDT
+		 * descriptor. */
+		store_idt(&state->host_idt_desc);
+
+		/* The descriptors for the Guest's GDT and IDT can be filled
+		 * out now, too.  We copy the GDT & IDT into ->guest_gdt and
+		 * ->guest_idt before actually running the Guest. */
+		state->guest_idt_desc.size = sizeof(state->guest_idt)-1;
+		state->guest_idt_desc.address = (long)&state->guest_idt;
+		state->guest_gdt_desc.size = sizeof(state->guest_gdt)-1;
+		state->guest_gdt_desc.address = (long)&state->guest_gdt;
+
+		/* We know where we want the stack to be when the Guest enters
+		 * the switcher: in pages->regs.  The stack grows upwards, so
+		 * we start it at the end of that structure. */
+		state->guest_tss.esp0 = (long)(&pages->regs + 1);
+		/* And this is the GDT entry to use for the stack: we keep a
+		 * couple of special LGUEST entries. */
+		state->guest_tss.ss0 = LGUEST_DS;
+
+		/* x86 can have a finegrained bitmap which indicates what I/O
+		 * ports the process can use.  We set it to the end of our
+		 * structure, meaning "none". */
+		state->guest_tss.io_bitmap_base = sizeof(state->guest_tss);
+
+		/* Some GDT entries are the same across all Guests, so we can
+		 * set them up now. */
+		setup_default_gdt_entries(state);
+		/* Most IDT entries are the same for all Guests, too.*/
+		setup_default_idt_entries(state, default_idt_entries);
+
+		/* The Host needs to be able to use the LGUEST segments on this
+		 * CPU, too, so put them in the Host GDT. */
+		get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
+		get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
+	}
+
+	/* In the Switcher, we want the %cs segment register to use the
+	 * LGUEST_CS GDT entry: we've put that in the Host and Guest GDTs, so
+	 * it will be undisturbed when we switch.  To change %cs and jump we
+	 * need this structure to feed to Intel's "lcall" instruction. */
+	lguest_entry.offset = (long)switch_to_guest + switcher_offset();
+	lguest_entry.segment = LGUEST_CS;
+
+	printk(KERN_INFO "lguest: mapped switcher at %p\n",
+	       switcher_vma->addr);
+	/* And we succeeded... */
+	return 0;
+
+free_vma:
+	vunmap(switcher_vma->addr);
+free_pages:
+	i = TOTAL_SWITCHER_PAGES;
+free_some_pages:
+	for (--i; i >= 0; i--)
+		__free_pages(switcher_page[i], 0);
+	kfree(switcher_page);
+out:
+	return err;
+}
+/*:*/
+
+/* Cleaning up the mapping when the module is unloaded is almost...
+ * too easy. */
+static void unmap_switcher(void)
+{
+	unsigned int i;
+
+	/* vunmap() undoes *both* map_vm_area() and __get_vm_area(). */
+	vunmap(switcher_vma->addr);
+	/* Now we just need to free the pages we copied the switcher into */
+	for (i = 0; i < TOTAL_SWITCHER_PAGES; i++)
+		__free_pages(switcher_page[i], 0);
+}
+
+/*H:130 Our Guest is usually so well behaved; it never tries to do things it
+ * isn't allowed to.  Unfortunately, "struct paravirt_ops" isn't quite
+ * complete, because it doesn't contain replacements for the Intel I/O
+ * instructions.  As a result, the Guest sometimes fumbles across one during
+ * the boot process as it probes for various things which are usually attached
+ * to a PC.
+ *
+ * When the Guest uses one of these instructions, we get trap #13 (General
+ * Protection Fault) and come here.  We see if it's one of those troublesome
+ * instructions and skip over it.  We return true if we did. */
+static int emulate_insn(struct lguest *lg)
+{
+	u8 insn;
+	unsigned int insnlen = 0, in = 0, shift = 0;
+	/* The eip contains the *virtual* address of the Guest's instruction:
+	 * guest_pa just subtracts the Guest's page_offset. */
+	unsigned long physaddr = guest_pa(lg, lg->regs->eip);
+
+	/* The guest_pa() function only works for Guest kernel addresses, but
+	 * that's all we're trying to do anyway. */
+	if (lg->regs->eip < lg->page_offset)
+		return 0;
+
+	/* Decoding x86 instructions is icky. */
+	lgread(lg, &insn, physaddr, 1);
+
+	/* 0x66 is an "operand prefix".  It means it's using the upper 16 bits
+	   of the eax register. */
+	if (insn == 0x66) {
+		shift = 16;
+		/* The instruction is 1 byte so far, read the next byte. */
+		insnlen = 1;
+		lgread(lg, &insn, physaddr + insnlen, 1);
+	}
+
+	/* We can ignore the lower bit for the moment and decode the 4 opcodes
+	 * we need to emulate. */
+	switch (insn & 0xFE) {
+	case 0xE4: /* in     <next byte>,%al */
+		insnlen += 2;
+		in = 1;
+		break;
+	case 0xEC: /* in     (%dx),%al */
+		insnlen += 1;
+		in = 1;
+		break;
+	case 0xE6: /* out    %al,<next byte> */
+		insnlen += 2;
+		break;
+	case 0xEE: /* out    %al,(%dx) */
+		insnlen += 1;
+		break;
+	default:
+		/* OK, we don't know what this is, can't emulate. */
+		return 0;
+	}
+
+	/* If it was an "IN" instruction, they expect the result to be read
+	 * into %eax, so we change %eax.  We always return all-ones, which
+	 * traditionally means "there's nothing there". */
+	if (in) {
+		/* Lower bit tells is whether it's a 16 or 32 bit access */
+		if (insn & 0x1)
+			lg->regs->eax = 0xFFFFFFFF;
+		else
+			lg->regs->eax |= (0xFFFF << shift);
+	}
+	/* Finally, we've "done" the instruction, so move past it. */
+	lg->regs->eip += insnlen;
+	/* Success! */
+	return 1;
+}
+/*:*/
+
+/*L:305
+ * Dealing With Guest Memory.
+ *
+ * When the Guest gives us (what it thinks is) a physical address, we can use
+ * the normal copy_from_user() & copy_to_user() on that address: remember,
+ * Guest physical == Launcher virtual.
+ *
+ * But we can't trust the Guest: it might be trying to access the Launcher
+ * code.  We have to check that the range is below the pfn_limit the Launcher
+ * gave us.  We have to make sure that addr + len doesn't give us a false
+ * positive by overflowing, too. */
+int lguest_address_ok(const struct lguest *lg,
+		      unsigned long addr, unsigned long len)
+{
+	return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr);
+}
+
+/* This is a convenient routine to get a 32-bit value from the Guest (a very
+ * common operation).  Here we can see how useful the kill_lguest() routine we
+ * met in the Launcher can be: we return a random value (0) instead of needing
+ * to return an error. */
+u32 lgread_u32(struct lguest *lg, unsigned long addr)
+{
+	u32 val = 0;
+
+	/* Don't let them access lguest binary. */
+	if (!lguest_address_ok(lg, addr, sizeof(val))
+	    || get_user(val, (u32 __user *)addr) != 0)
+		kill_guest(lg, "bad read address %#lx", addr);
+	return val;
+}
+
+/* Same thing for writing a value. */
+void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val)
+{
+	if (!lguest_address_ok(lg, addr, sizeof(val))
+	    || put_user(val, (u32 __user *)addr) != 0)
+		kill_guest(lg, "bad write address %#lx", addr);
+}
+
+/* This routine is more generic, and copies a range of Guest bytes into a
+ * buffer.  If the copy_from_user() fails, we fill the buffer with zeroes, so
+ * the caller doesn't end up using uninitialized kernel memory. */
+void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes)
+{
+	if (!lguest_address_ok(lg, addr, bytes)
+	    || copy_from_user(b, (void __user *)addr, bytes) != 0) {
+		/* copy_from_user should do this, but as we rely on it... */
+		memset(b, 0, bytes);
+		kill_guest(lg, "bad read address %#lx len %u", addr, bytes);
+	}
+}
+
+/* Similarly, our generic routine to copy into a range of Guest bytes. */
+void lgwrite(struct lguest *lg, unsigned long addr, const void *b,
+	     unsigned bytes)
+{
+	if (!lguest_address_ok(lg, addr, bytes)
+	    || copy_to_user((void __user *)addr, b, bytes) != 0)
+		kill_guest(lg, "bad write address %#lx len %u", addr, bytes);
+}
+/* (end of memory access helper routines) :*/
+
+static void set_ts(void)
+{
+	u32 cr0;
+
+	cr0 = read_cr0();
+	if (!(cr0 & 8))
+		write_cr0(cr0|8);
+}
+
+/*S:010
+ * We are getting close to the Switcher.
+ *
+ * Remember that each CPU has two pages which are visible to the Guest when it
+ * runs on that CPU.  This has to contain the state for that Guest: we copy the
+ * state in just before we run the Guest.
+ *
+ * Each Guest has "changed" flags which indicate what has changed in the Guest
+ * since it last ran.  We saw this set in interrupts_and_traps.c and
+ * segments.c.
+ */
+static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages)
+{
+	/* Copying all this data can be quite expensive.  We usually run the
+	 * same Guest we ran last time (and that Guest hasn't run anywhere else
+	 * meanwhile).  If that's not the case, we pretend everything in the
+	 * Guest has changed. */
+	if (__get_cpu_var(last_guest) != lg || lg->last_pages != pages) {
+		__get_cpu_var(last_guest) = lg;
+		lg->last_pages = pages;
+		lg->changed = CHANGED_ALL;
+	}
+
+	/* These copies are pretty cheap, so we do them unconditionally: */
+	/* Save the current Host top-level page directory. */
+	pages->state.host_cr3 = __pa(current->mm->pgd);
+	/* Set up the Guest's page tables to see this CPU's pages (and no
+	 * other CPU's pages). */
+	map_switcher_in_guest(lg, pages);
+	/* Set up the two "TSS" members which tell the CPU what stack to use
+	 * for traps which do directly into the Guest (ie. traps at privilege
+	 * level 1). */
+	pages->state.guest_tss.esp1 = lg->esp1;
+	pages->state.guest_tss.ss1 = lg->ss1;
+
+	/* Copy direct-to-Guest trap entries. */
+	if (lg->changed & CHANGED_IDT)
+		copy_traps(lg, pages->state.guest_idt, default_idt_entries);
+
+	/* Copy all GDT entries which the Guest can change. */
+	if (lg->changed & CHANGED_GDT)
+		copy_gdt(lg, pages->state.guest_gdt);
+	/* If only the TLS entries have changed, copy them. */
+	else if (lg->changed & CHANGED_GDT_TLS)
+		copy_gdt_tls(lg, pages->state.guest_gdt);
+
+	/* Mark the Guest as unchanged for next time. */
+	lg->changed = 0;
+}
+
+/* Finally: the code to actually call into the Switcher to run the Guest. */
+static void run_guest_once(struct lguest *lg, struct lguest_pages *pages)
+{
+	/* This is a dummy value we need for GCC's sake. */
+	unsigned int clobber;
+
+	/* Copy the guest-specific information into this CPU's "struct
+	 * lguest_pages". */
+	copy_in_guest_info(lg, pages);
+
+	/* Set the trap number to 256 (impossible value).  If we fault while
+	 * switching to the Guest (bad segment registers or bug), this will
+	 * cause us to abort the Guest. */
+	lg->regs->trapnum = 256;
+
+	/* Now: we push the "eflags" register on the stack, then do an "lcall".
+	 * This is how we change from using the kernel code segment to using
+	 * the dedicated lguest code segment, as well as jumping into the
+	 * Switcher.
+	 *
+	 * The lcall also pushes the old code segment (KERNEL_CS) onto the
+	 * stack, then the address of this call.  This stack layout happens to
+	 * exactly match the stack of an interrupt... */
+	asm volatile("pushf; lcall *lguest_entry"
+		     /* This is how we tell GCC that %eax ("a") and %ebx ("b")
+		      * are changed by this routine.  The "=" means output. */
+		     : "=a"(clobber), "=b"(clobber)
+		     /* %eax contains the pages pointer.  ("0" refers to the
+		      * 0-th argument above, ie "a").  %ebx contains the
+		      * physical address of the Guest's top-level page
+		      * directory. */
+		     : "0"(pages), "1"(__pa(lg->pgdirs[lg->pgdidx].pgdir))
+		     /* We tell gcc that all these registers could change,
+		      * which means we don't have to save and restore them in
+		      * the Switcher. */
+		     : "memory", "%edx", "%ecx", "%edi", "%esi");
+}
+/*:*/
+
+/*H:030 Let's jump straight to the the main loop which runs the Guest.
+ * Remember, this is called by the Launcher reading /dev/lguest, and we keep
+ * going around and around until something interesting happens. */
+int run_guest(struct lguest *lg, unsigned long __user *user)
+{
+	/* We stop running once the Guest is dead. */
+	while (!lg->dead) {
+		/* We need to initialize this, otherwise gcc complains.  It's
+		 * not (yet) clever enough to see that it's initialized when we
+		 * need it. */
+		unsigned int cr2 = 0; /* Damn gcc */
+
+		/* First we run any hypercalls the Guest wants done: either in
+		 * the hypercall ring in "struct lguest_data", or directly by
+		 * using int 31 (LGUEST_TRAP_ENTRY). */
+		do_hypercalls(lg);
+		/* It's possible the Guest did a SEND_DMA hypercall to the
+		 * Launcher, in which case we return from the read() now. */
+		if (lg->dma_is_pending) {
+			if (put_user(lg->pending_dma, user) ||
+			    put_user(lg->pending_key, user+1))
+				return -EFAULT;
+			return sizeof(unsigned long)*2;
+		}
+
+		/* Check for signals */
+		if (signal_pending(current))
+			return -ERESTARTSYS;
+
+		/* If Waker set break_out, return to Launcher. */
+		if (lg->break_out)
+			return -EAGAIN;
+
+		/* Check if there are any interrupts which can be delivered
+		 * now: if so, this sets up the hander to be executed when we
+		 * next run the Guest. */
+		maybe_do_interrupt(lg);
+
+		/* All long-lived kernel loops need to check with this horrible
+		 * thing called the freezer.  If the Host is trying to suspend,
+		 * it stops us. */
+		try_to_freeze();
+
+		/* Just make absolutely sure the Guest is still alive.  One of
+		 * those hypercalls could have been fatal, for example. */
+		if (lg->dead)
+			break;
+
+		/* If the Guest asked to be stopped, we sleep.  The Guest's
+		 * clock timer or LHCALL_BREAK from the Waker will wake us. */
+		if (lg->halted) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			continue;
+		}
+
+		/* OK, now we're ready to jump into the Guest.  First we put up
+		 * the "Do Not Disturb" sign: */
+		local_irq_disable();
+
+		/* Remember the awfully-named TS bit?  If the Guest has asked
+		 * to set it we set it now, so we can trap and pass that trap
+		 * to the Guest if it uses the FPU. */
+		if (lg->ts)
+			set_ts();
+
+		/* SYSENTER is an optimized way of doing system calls.  We
+		 * can't allow it because it always jumps to privilege level 0.
+		 * A normal Guest won't try it because we don't advertise it in
+		 * CPUID, but a malicious Guest (or malicious Guest userspace
+		 * program) could, so we tell the CPU to disable it before
+		 * running the Guest. */
+		if (boot_cpu_has(X86_FEATURE_SEP))
+			wrmsr(MSR_IA32_SYSENTER_CS, 0, 0);
+
+		/* Now we actually run the Guest.  It will pop back out when
+		 * something interesting happens, and we can examine its
+		 * registers to see what it was doing. */
+		run_guest_once(lg, lguest_pages(raw_smp_processor_id()));
+
+		/* The "regs" pointer contains two extra entries which are not
+		 * really registers: a trap number which says what interrupt or
+		 * trap made the switcher code come back, and an error code
+		 * which some traps set.  */
+
+		/* If the Guest page faulted, then the cr2 register will tell
+		 * us the bad virtual address.  We have to grab this now,
+		 * because once we re-enable interrupts an interrupt could
+		 * fault and thus overwrite cr2, or we could even move off to a
+		 * different CPU. */
+		if (lg->regs->trapnum == 14)
+			cr2 = read_cr2();
+		/* Similarly, if we took a trap because the Guest used the FPU,
+		 * we have to restore the FPU it expects to see. */
+		else if (lg->regs->trapnum == 7)
+			math_state_restore();
+
+		/* Restore SYSENTER if it's supposed to be on. */
+		if (boot_cpu_has(X86_FEATURE_SEP))
+			wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
+
+		/* Now we're ready to be interrupted or moved to other CPUs */
+		local_irq_enable();
+
+		/* OK, so what happened? */
+		switch (lg->regs->trapnum) {
+		case 13: /* We've intercepted a GPF. */
+			/* Check if this was one of those annoying IN or OUT
+			 * instructions which we need to emulate.  If so, we
+			 * just go back into the Guest after we've done it. */
+			if (lg->regs->errcode == 0) {
+				if (emulate_insn(lg))
+					continue;
+			}
+			break;
+		case 14: /* We've intercepted a page fault. */
+			/* The Guest accessed a virtual address that wasn't
+			 * mapped.  This happens a lot: we don't actually set
+			 * up most of the page tables for the Guest at all when
+			 * we start: as it runs it asks for more and more, and
+			 * we set them up as required. In this case, we don't
+			 * even tell the Guest that the fault happened.
+			 *
+			 * The errcode tells whether this was a read or a
+			 * write, and whether kernel or userspace code. */
+			if (demand_page(lg, cr2, lg->regs->errcode))
+				continue;
+
+			/* OK, it's really not there (or not OK): the Guest
+			 * needs to know.  We write out the cr2 value so it
+			 * knows where the fault occurred.
+			 *
+			 * Note that if the Guest were really messed up, this
+			 * could happen before it's done the INITIALIZE
+			 * hypercall, so lg->lguest_data will be NULL, so
+			 * &lg->lguest_data->cr2 will be address 8.  Writing
+			 * into that address won't hurt the Host at all,
+			 * though. */
+			if (put_user(cr2, &lg->lguest_data->cr2))
+				kill_guest(lg, "Writing cr2");
+			break;
+		case 7: /* We've intercepted a Device Not Available fault. */
+			/* If the Guest doesn't want to know, we already
+			 * restored the Floating Point Unit, so we just
+			 * continue without telling it. */
+			if (!lg->ts)
+				continue;
+			break;
+		case 32 ... 255:
+			/* These values mean a real interrupt occurred, in
+			 * which case the Host handler has already been run.
+			 * We just do a friendly check if another process
+			 * should now be run, then fall through to loop
+			 * around: */
+			cond_resched();
+		case LGUEST_TRAP_ENTRY: /* Handled at top of loop */
+			continue;
+		}
+
+		/* If we get here, it's a trap the Guest wants to know
+		 * about. */
+		if (deliver_trap(lg, lg->regs->trapnum))
+			continue;
+
+		/* If the Guest doesn't have a handler (either it hasn't
+		 * registered any yet, or it's one of the faults we don't let
+		 * it handle), it dies with a cryptic error message. */
+		kill_guest(lg, "unhandled trap %li at %#lx (%#lx)",
+			   lg->regs->trapnum, lg->regs->eip,
+			   lg->regs->trapnum == 14 ? cr2 : lg->regs->errcode);
+	}
+	/* The Guest is dead => "No such file or directory" */
+	return -ENOENT;
+}
+
+/* Now we can look at each of the routines this calls, in increasing order of
+ * complexity: do_hypercalls(), emulate_insn(), maybe_do_interrupt(),
+ * deliver_trap() and demand_page().  After all those, we'll be ready to
+ * examine the Switcher, and our philosophical understanding of the Host/Guest
+ * duality will be complete. :*/
+
+int find_free_guest(void)
+{
+	unsigned int i;
+	for (i = 0; i < MAX_LGUEST_GUESTS; i++)
+		if (!lguests[i].tsk)
+			return i;
+	return -1;
+}
+
+static void adjust_pge(void *on)
+{
+	if (on)
+		write_cr4(read_cr4() | X86_CR4_PGE);
+	else
+		write_cr4(read_cr4() & ~X86_CR4_PGE);
+}
+
+/*H:000
+ * Welcome to the Host!
+ *
+ * By this point your brain has been tickled by the Guest code and numbed by
+ * the Launcher code; prepare for it to be stretched by the Host code.  This is
+ * the heart.  Let's begin at the initialization routine for the Host's lg
+ * module.
+ */
+static int __init init(void)
+{
+	int err;
+
+	/* Lguest can't run under Xen, VMI or itself.  It does Tricky Stuff. */
+	if (paravirt_enabled()) {
+		printk("lguest is afraid of %s\n", paravirt_ops.name);
+		return -EPERM;
+	}
+
+	/* First we put the Switcher up in very high virtual memory. */
+	err = map_switcher();
+	if (err)
+		return err;
+
+	/* Now we set up the pagetable implementation for the Guests. */
+	err = init_pagetables(switcher_page, SHARED_SWITCHER_PAGES);
+	if (err) {
+		unmap_switcher();
+		return err;
+	}
+
+	/* The I/O subsystem needs some things initialized. */
+	lguest_io_init();
+
+	/* /dev/lguest needs to be registered. */
+	err = lguest_device_init();
+	if (err) {
+		free_pagetables();
+		unmap_switcher();
+		return err;
+	}
+
+	/* Finally, we need to turn off "Page Global Enable".  PGE is an
+	 * optimization where page table entries are specially marked to show
+	 * they never change.  The Host kernel marks all the kernel pages this
+	 * way because it's always present, even when userspace is running.
+	 *
+	 * Lguest breaks this: unbeknownst to the rest of the Host kernel, we
+	 * switch to the Guest kernel.  If you don't disable this on all CPUs,
+	 * you'll get really weird bugs that you'll chase for two days.
+	 *
+	 * I used to turn PGE off every time we switched to the Guest and back
+	 * on when we return, but that slowed the Switcher down noticibly. */
+
+	/* We don't need the complexity of CPUs coming and going while we're
+	 * doing this. */
+	lock_cpu_hotplug();
+	if (cpu_has_pge) { /* We have a broader idea of "global". */
+		/* Remember that this was originally set (for cleanup). */
+		cpu_had_pge = 1;
+		/* adjust_pge is a helper function which sets or unsets the PGE
+		 * bit on its CPU, depending on the argument (0 == unset). */
+		on_each_cpu(adjust_pge, (void *)0, 0, 1);
+		/* Turn off the feature in the global feature set. */
+		clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
+	}
+	unlock_cpu_hotplug();
+
+	/* All good! */
+	return 0;
+}
+
+/* Cleaning up is just the same code, backwards.  With a little French. */
+static void __exit fini(void)
+{
+	lguest_device_remove();
+	free_pagetables();
+	unmap_switcher();
+
+	/* If we had PGE before we started, turn it back on now. */
+	lock_cpu_hotplug();
+	if (cpu_had_pge) {
+		set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
+		/* adjust_pge's argument "1" means set PGE. */
+		on_each_cpu(adjust_pge, (void *)1, 0, 1);
+	}
+	unlock_cpu_hotplug();
+}
+
+/* The Host side of lguest can be a module.  This is a nice way for people to
+ * play with it.  */
+module_init(init);
+module_exit(fini);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c
new file mode 100644
index 0000000..db6caac
--- /dev/null
+++ b/drivers/lguest/hypercalls.c
@@ -0,0 +1,300 @@
+/*P:500 Just as userspace programs request kernel operations through a system
+ * call, the Guest requests Host operations through a "hypercall".  You might
+ * notice this nomenclature doesn't really follow any logic, but the name has
+ * been around for long enough that we're stuck with it.  As you'd expect, this
+ * code is basically a one big switch statement. :*/
+
+/*  Copyright (C) 2006 Rusty Russell IBM Corporation
+
+    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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+*/
+#include <linux/uaccess.h>
+#include <linux/syscalls.h>
+#include <linux/mm.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <irq_vectors.h>
+#include "lg.h"
+
+/*H:120 This is the core hypercall routine: where the Guest gets what it
+ * wants.  Or gets killed.  Or, in the case of LHCALL_CRASH, both.
+ *
+ * Remember from the Guest: %eax == which call to make, and the arguments are
+ * packed into %edx, %ebx and %ecx if needed. */
+static void do_hcall(struct lguest *lg, struct lguest_regs *regs)
+{
+	switch (regs->eax) {
+	case LHCALL_FLUSH_ASYNC:
+		/* This call does nothing, except by breaking out of the Guest
+		 * it makes us process all the asynchronous hypercalls. */
+		break;
+	case LHCALL_LGUEST_INIT:
+		/* You can't get here unless you're already initialized.  Don't
+		 * do that. */
+		kill_guest(lg, "already have lguest_data");
+		break;
+	case LHCALL_CRASH: {
+		/* Crash is such a trivial hypercall that we do it in four
+		 * lines right here. */
+		char msg[128];
+		/* If the lgread fails, it will call kill_guest() itself; the
+		 * kill_guest() with the message will be ignored. */
+		lgread(lg, msg, regs->edx, sizeof(msg));
+		msg[sizeof(msg)-1] = '\0';
+		kill_guest(lg, "CRASH: %s", msg);
+		break;
+	}
+	case LHCALL_FLUSH_TLB:
+		/* FLUSH_TLB comes in two flavors, depending on the
+		 * argument: */
+		if (regs->edx)
+			guest_pagetable_clear_all(lg);
+		else
+			guest_pagetable_flush_user(lg);
+		break;
+	case LHCALL_BIND_DMA:
+		/* BIND_DMA really wants four arguments, but it's the only call
+		 * which does.  So the Guest packs the number of buffers and
+		 * the interrupt number into the final argument, and we decode
+		 * it here.  This can legitimately fail, since we currently
+		 * place a limit on the number of DMA pools a Guest can have.
+		 * So we return true or false from this call. */
+		regs->eax = bind_dma(lg, regs->edx, regs->ebx,
+				     regs->ecx >> 8, regs->ecx & 0xFF);
+		break;
+
+	/* All these calls simply pass the arguments through to the right
+	 * routines. */
+	case LHCALL_SEND_DMA:
+		send_dma(lg, regs->edx, regs->ebx);
+		break;
+	case LHCALL_LOAD_GDT:
+		load_guest_gdt(lg, regs->edx, regs->ebx);
+		break;
+	case LHCALL_LOAD_IDT_ENTRY:
+		load_guest_idt_entry(lg, regs->edx, regs->ebx, regs->ecx);
+		break;
+	case LHCALL_NEW_PGTABLE:
+		guest_new_pagetable(lg, regs->edx);
+		break;
+	case LHCALL_SET_STACK:
+		guest_set_stack(lg, regs->edx, regs->ebx, regs->ecx);
+		break;
+	case LHCALL_SET_PTE:
+		guest_set_pte(lg, regs->edx, regs->ebx, mkgpte(regs->ecx));
+		break;
+	case LHCALL_SET_PMD:
+		guest_set_pmd(lg, regs->edx, regs->ebx);
+		break;
+	case LHCALL_LOAD_TLS:
+		guest_load_tls(lg, regs->edx);
+		break;
+	case LHCALL_SET_CLOCKEVENT:
+		guest_set_clockevent(lg, regs->edx);
+		break;
+
+	case LHCALL_TS:
+		/* This sets the TS flag, as we saw used in run_guest(). */
+		lg->ts = regs->edx;
+		break;
+	case LHCALL_HALT:
+		/* Similarly, this sets the halted flag for run_guest(). */
+		lg->halted = 1;
+		break;
+	default:
+		kill_guest(lg, "Bad hypercall %li\n", regs->eax);
+	}
+}
+
+/* Asynchronous hypercalls are easy: we just look in the array in the Guest's
+ * "struct lguest_data" and see if there are any new ones marked "ready".
+ *
+ * We are careful to do these in order: obviously we respect the order the
+ * Guest put them in the ring, but we also promise the Guest that they will
+ * happen before any normal hypercall (which is why we check this before
+ * checking for a normal hcall). */
+static void do_async_hcalls(struct lguest *lg)
+{
+	unsigned int i;
+	u8 st[LHCALL_RING_SIZE];
+
+	/* For simplicity, we copy the entire call status array in at once. */
+	if (copy_from_user(&st, &lg->lguest_data->hcall_status, sizeof(st)))
+		return;
+
+
+	/* We process "struct lguest_data"s hcalls[] ring once. */
+	for (i = 0; i < ARRAY_SIZE(st); i++) {
+		struct lguest_regs regs;
+		/* We remember where we were up to from last time.  This makes
+		 * sure that the hypercalls are done in the order the Guest
+		 * places them in the ring. */
+		unsigned int n = lg->next_hcall;
+
+		/* 0xFF means there's no call here (yet). */
+		if (st[n] == 0xFF)
+			break;
+
+		/* OK, we have hypercall.  Increment the "next_hcall" cursor,
+		 * and wrap back to 0 if we reach the end. */
+		if (++lg->next_hcall == LHCALL_RING_SIZE)
+			lg->next_hcall = 0;
+
+		/* We copy the hypercall arguments into a fake register
+		 * structure.  This makes life simple for do_hcall(). */
+		if (get_user(regs.eax, &lg->lguest_data->hcalls[n].eax)
+		    || get_user(regs.edx, &lg->lguest_data->hcalls[n].edx)
+		    || get_user(regs.ecx, &lg->lguest_data->hcalls[n].ecx)
+		    || get_user(regs.ebx, &lg->lguest_data->hcalls[n].ebx)) {
+			kill_guest(lg, "Fetching async hypercalls");
+			break;
+		}
+
+		/* Do the hypercall, same as a normal one. */
+		do_hcall(lg, &regs);
+
+		/* Mark the hypercall done. */
+		if (put_user(0xFF, &lg->lguest_data->hcall_status[n])) {
+			kill_guest(lg, "Writing result for async hypercall");
+			break;
+		}
+
+ 		/* Stop doing hypercalls if we've just done a DMA to the
+		 * Launcher: it needs to service this first. */
+		if (lg->dma_is_pending)
+			break;
+	}
+}
+
+/* Last of all, we look at what happens first of all.  The very first time the
+ * Guest makes a hypercall, we end up here to set things up: */
+static void initialize(struct lguest *lg)
+{
+	u32 tsc_speed;
+
+	/* You can't do anything until you're initialized.  The Guest knows the
+	 * rules, so we're unforgiving here. */
+	if (lg->regs->eax != LHCALL_LGUEST_INIT) {
+		kill_guest(lg, "hypercall %li before LGUEST_INIT",
+			   lg->regs->eax);
+		return;
+	}
+
+	/* We insist that the Time Stamp Counter exist and doesn't change with
+	 * cpu frequency.  Some devious chip manufacturers decided that TSC
+	 * changes could be handled in software.  I decided that time going
+	 * backwards might be good for benchmarks, but it's bad for users.
+	 *
+	 * We also insist that the TSC be stable: the kernel detects unreliable
+	 * TSCs for its own purposes, and we use that here. */
+	if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC) && !check_tsc_unstable())
+		tsc_speed = tsc_khz;
+	else
+		tsc_speed = 0;
+
+	/* The pointer to the Guest's "struct lguest_data" is the only
+	 * argument. */
+	lg->lguest_data = (struct lguest_data __user *)lg->regs->edx;
+	/* If we check the address they gave is OK now, we can simply
+	 * copy_to_user/from_user from now on rather than using lgread/lgwrite.
+	 * I put this in to show that I'm not immune to writing stupid
+	 * optimizations. */
+	if (!lguest_address_ok(lg, lg->regs->edx, sizeof(*lg->lguest_data))) {
+		kill_guest(lg, "bad guest page %p", lg->lguest_data);
+		return;
+	}
+	/* The Guest tells us where we're not to deliver interrupts by putting
+	 * the range of addresses into "struct lguest_data". */
+	if (get_user(lg->noirq_start, &lg->lguest_data->noirq_start)
+	    || get_user(lg->noirq_end, &lg->lguest_data->noirq_end)
+	    /* We tell the Guest that it can't use the top 4MB of virtual
+	     * addresses used by the Switcher. */
+	    || put_user(4U*1024*1024, &lg->lguest_data->reserve_mem)
+	    || put_user(tsc_speed, &lg->lguest_data->tsc_khz)
+	    /* We also give the Guest a unique id, as used in lguest_net.c. */
+	    || put_user(lg->guestid, &lg->lguest_data->guestid))
+		kill_guest(lg, "bad guest page %p", lg->lguest_data);
+
+	/* We write the current time into the Guest's data page once now. */
+	write_timestamp(lg);
+
+	/* This is the one case where the above accesses might have been the
+	 * first write to a Guest page.  This may have caused a copy-on-write
+	 * fault, but the Guest might be referring to the old (read-only)
+	 * page. */
+	guest_pagetable_clear_all(lg);
+}
+/* Now we've examined the hypercall code; our Guest can make requests.  There
+ * is one other way we can do things for the Guest, as we see in
+ * emulate_insn(). */
+
+/*H:110 Tricky point: we mark the hypercall as "done" once we've done it.
+ * Normally we don't need to do this: the Guest will run again and update the
+ * trap number before we come back around the run_guest() loop to
+ * do_hypercalls().
+ *
+ * However, if we are signalled or the Guest sends DMA to the Launcher, that
+ * loop will exit without running the Guest.  When it comes back it would try
+ * to re-run the hypercall. */
+static void clear_hcall(struct lguest *lg)
+{
+	lg->regs->trapnum = 255;
+}
+
+/*H:100
+ * Hypercalls
+ *
+ * Remember from the Guest, hypercalls come in two flavors: normal and
+ * asynchronous.  This file handles both of types.
+ */
+void do_hypercalls(struct lguest *lg)
+{
+	/* Not initialized yet? */
+	if (unlikely(!lg->lguest_data)) {
+		/* Did the Guest make a hypercall?  We might have come back for
+		 * some other reason (an interrupt, a different trap). */
+		if (lg->regs->trapnum == LGUEST_TRAP_ENTRY) {
+			/* Set up the "struct lguest_data" */
+			initialize(lg);
+			/* The hypercall is done. */
+			clear_hcall(lg);
+		}
+		return;
+	}
+
+	/* The Guest has initialized.
+	 *
+	 * Look in the hypercall ring for the async hypercalls: */
+	do_async_hcalls(lg);
+
+	/* If we stopped reading the hypercall ring because the Guest did a
+	 * SEND_DMA to the Launcher, we want to return now.  Otherwise if the
+	 * Guest asked us to do a hypercall, we do it. */
+	if (!lg->dma_is_pending && lg->regs->trapnum == LGUEST_TRAP_ENTRY) {
+		do_hcall(lg, lg->regs);
+		/* The hypercall is done. */
+		clear_hcall(lg);
+	}
+}
+
+/* This routine supplies the Guest with time: it's used for wallclock time at
+ * initial boot and as a rough time source if the TSC isn't available. */
+void write_timestamp(struct lguest *lg)
+{
+	struct timespec now;
+	ktime_get_real_ts(&now);
+	if (put_user(now, &lg->lguest_data->time))
+		kill_guest(lg, "Writing timestamp");
+}
diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c
new file mode 100644
index 0000000..3973123
--- /dev/null
+++ b/drivers/lguest/interrupts_and_traps.c
@@ -0,0 +1,446 @@
+/*P:800 Interrupts (traps) are complicated enough to earn their own file.
+ * There are three classes of interrupts:
+ *
+ * 1) Real hardware interrupts which occur while we're running the Guest,
+ * 2) Interrupts for virtual devices attached to the Guest, and
+ * 3) Traps and faults from the Guest.
+ *
+ * Real hardware interrupts must be delivered to the Host, not the Guest.
+ * Virtual interrupts must be delivered to the Guest, but we make them look
+ * just like real hardware would deliver them.  Traps from the Guest can be set
+ * up to go directly back into the Guest, but sometimes the Host wants to see
+ * them first, so we also have a way of "reflecting" them into the Guest as if
+ * they had been delivered to it directly. :*/
+#include <linux/uaccess.h>
+#include "lg.h"
+
+/* The address of the interrupt handler is split into two bits: */
+static unsigned long idt_address(u32 lo, u32 hi)
+{
+	return (lo & 0x0000FFFF) | (hi & 0xFFFF0000);
+}
+
+/* The "type" of the interrupt handler is a 4 bit field: we only support a
+ * couple of types. */
+static int idt_type(u32 lo, u32 hi)
+{
+	return (hi >> 8) & 0xF;
+}
+
+/* An IDT entry can't be used unless the "present" bit is set. */
+static int idt_present(u32 lo, u32 hi)
+{
+	return (hi & 0x8000);
+}
+
+/* We need a helper to "push" a value onto the Guest's stack, since that's a
+ * big part of what delivering an interrupt does. */
+static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val)
+{
+	/* Stack grows upwards: move stack then write value. */
+	*gstack -= 4;
+	lgwrite_u32(lg, *gstack, val);
+}
+
+/*H:210 The set_guest_interrupt() routine actually delivers the interrupt or
+ * trap.  The mechanics of delivering traps and interrupts to the Guest are the
+ * same, except some traps have an "error code" which gets pushed onto the
+ * stack as well: the caller tells us if this is one.
+ *
+ * "lo" and "hi" are the two parts of the Interrupt Descriptor Table for this
+ * interrupt or trap.  It's split into two parts for traditional reasons: gcc
+ * on i386 used to be frightened by 64 bit numbers.
+ *
+ * We set up the stack just like the CPU does for a real interrupt, so it's
+ * identical for the Guest (and the standard "iret" instruction will undo
+ * it). */
+static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
+{
+	unsigned long gstack;
+	u32 eflags, ss, irq_enable;
+
+	/* There are two cases for interrupts: one where the Guest is already
+	 * in the kernel, and a more complex one where the Guest is in
+	 * userspace.  We check the privilege level to find out. */
+	if ((lg->regs->ss&0x3) != GUEST_PL) {
+		/* The Guest told us their kernel stack with the SET_STACK
+		 * hypercall: both the virtual address and the segment */
+		gstack = guest_pa(lg, lg->esp1);
+		ss = lg->ss1;
+		/* We push the old stack segment and pointer onto the new
+		 * stack: when the Guest does an "iret" back from the interrupt
+		 * handler the CPU will notice they're dropping privilege
+		 * levels and expect these here. */
+		push_guest_stack(lg, &gstack, lg->regs->ss);
+		push_guest_stack(lg, &gstack, lg->regs->esp);
+	} else {
+		/* We're staying on the same Guest (kernel) stack. */
+		gstack = guest_pa(lg, lg->regs->esp);
+		ss = lg->regs->ss;
+	}
+
+	/* Remember that we never let the Guest actually disable interrupts, so
+	 * the "Interrupt Flag" bit is always set.  We copy that bit from the
+	 * Guest's "irq_enabled" field into the eflags word: the Guest copies
+	 * it back in "lguest_iret". */
+	eflags = lg->regs->eflags;
+	if (get_user(irq_enable, &lg->lguest_data->irq_enabled) == 0
+	    && !(irq_enable & X86_EFLAGS_IF))
+		eflags &= ~X86_EFLAGS_IF;
+
+	/* An interrupt is expected to push three things on the stack: the old
+	 * "eflags" word, the old code segment, and the old instruction
+	 * pointer. */
+	push_guest_stack(lg, &gstack, eflags);
+	push_guest_stack(lg, &gstack, lg->regs->cs);
+	push_guest_stack(lg, &gstack, lg->regs->eip);
+
+	/* For the six traps which supply an error code, we push that, too. */
+	if (has_err)
+		push_guest_stack(lg, &gstack, lg->regs->errcode);
+
+	/* Now we've pushed all the old state, we change the stack, the code
+	 * segment and the address to execute. */
+	lg->regs->ss = ss;
+	lg->regs->esp = gstack + lg->page_offset;
+	lg->regs->cs = (__KERNEL_CS|GUEST_PL);
+	lg->regs->eip = idt_address(lo, hi);
+
+	/* There are two kinds of interrupt handlers: 0xE is an "interrupt
+	 * gate" which expects interrupts to be disabled on entry. */
+	if (idt_type(lo, hi) == 0xE)
+		if (put_user(0, &lg->lguest_data->irq_enabled))
+			kill_guest(lg, "Disabling interrupts");
+}
+
+/*H:200
+ * Virtual Interrupts.
+ *
+ * maybe_do_interrupt() gets called before every entry to the Guest, to see if
+ * we should divert the Guest to running an interrupt handler. */
+void maybe_do_interrupt(struct lguest *lg)
+{
+	unsigned int irq;
+	DECLARE_BITMAP(blk, LGUEST_IRQS);
+	struct desc_struct *idt;
+
+	/* If the Guest hasn't even initialized yet, we can do nothing. */
+	if (!lg->lguest_data)
+		return;
+
+	/* Take our "irqs_pending" array and remove any interrupts the Guest
+	 * wants blocked: the result ends up in "blk". */
+	if (copy_from_user(&blk, lg->lguest_data->blocked_interrupts,
+			   sizeof(blk)))
+		return;
+
+	bitmap_andnot(blk, lg->irqs_pending, blk, LGUEST_IRQS);
+
+	/* Find the first interrupt. */
+	irq = find_first_bit(blk, LGUEST_IRQS);
+	/* None?  Nothing to do */
+	if (irq >= LGUEST_IRQS)
+		return;
+
+	/* They may be in the middle of an iret, where they asked us never to
+	 * deliver interrupts. */
+	if (lg->regs->eip >= lg->noirq_start && lg->regs->eip < lg->noirq_end)
+		return;
+
+	/* If they're halted, interrupts restart them. */
+	if (lg->halted) {
+		/* Re-enable interrupts. */
+		if (put_user(X86_EFLAGS_IF, &lg->lguest_data->irq_enabled))
+			kill_guest(lg, "Re-enabling interrupts");
+		lg->halted = 0;
+	} else {
+		/* Otherwise we check if they have interrupts disabled. */
+		u32 irq_enabled;
+		if (get_user(irq_enabled, &lg->lguest_data->irq_enabled))
+			irq_enabled = 0;
+		if (!irq_enabled)
+			return;
+	}
+
+	/* Look at the IDT entry the Guest gave us for this interrupt.  The
+	 * first 32 (FIRST_EXTERNAL_VECTOR) entries are for traps, so we skip
+	 * over them. */
+	idt = &lg->idt[FIRST_EXTERNAL_VECTOR+irq];
+	/* If they don't have a handler (yet?), we just ignore it */
+	if (idt_present(idt->a, idt->b)) {
+		/* OK, mark it no longer pending and deliver it. */
+		clear_bit(irq, lg->irqs_pending);
+		/* set_guest_interrupt() takes the interrupt descriptor and a
+		 * flag to say whether this interrupt pushes an error code onto
+		 * the stack as well: virtual interrupts never do. */
+		set_guest_interrupt(lg, idt->a, idt->b, 0);
+	}
+
+	/* Every time we deliver an interrupt, we update the timestamp in the
+	 * Guest's lguest_data struct.  It would be better for the Guest if we
+	 * did this more often, but it can actually be quite slow: doing it
+	 * here is a compromise which means at least it gets updated every
+	 * timer interrupt. */
+	write_timestamp(lg);
+}
+
+/*H:220 Now we've got the routines to deliver interrupts, delivering traps
+ * like page fault is easy.  The only trick is that Intel decided that some
+ * traps should have error codes: */
+static int has_err(unsigned int trap)
+{
+	return (trap == 8 || (trap >= 10 && trap <= 14) || trap == 17);
+}
+
+/* deliver_trap() returns true if it could deliver the trap. */
+int deliver_trap(struct lguest *lg, unsigned int num)
+{
+	/* Trap numbers are always 8 bit, but we set an impossible trap number
+	 * for traps inside the Switcher, so check that here. */
+	if (num >= ARRAY_SIZE(lg->idt))
+		return 0;
+
+	/* Early on the Guest hasn't set the IDT entries (or maybe it put a
+	 * bogus one in): if we fail here, the Guest will be killed. */
+	if (!idt_present(lg->idt[num].a, lg->idt[num].b))
+		return 0;
+	set_guest_interrupt(lg, lg->idt[num].a, lg->idt[num].b, has_err(num));
+	return 1;
+}
+
+/*H:250 Here's the hard part: returning to the Host every time a trap happens
+ * and then calling deliver_trap() and re-entering the Guest is slow.
+ * Particularly because Guest userspace system calls are traps (trap 128).
+ *
+ * So we'd like to set up the IDT to tell the CPU to deliver traps directly
+ * into the Guest.  This is possible, but the complexities cause the size of
+ * this file to double!  However, 150 lines of code is worth writing for taking
+ * system calls down from 1750ns to 270ns.  Plus, if lguest didn't do it, all
+ * the other hypervisors would tease it.
+ *
+ * This routine determines if a trap can be delivered directly. */
+static int direct_trap(const struct lguest *lg,
+		       const struct desc_struct *trap,
+		       unsigned int num)
+{
+	/* Hardware interrupts don't go to the Guest at all (except system
+	 * call). */
+	if (num >= FIRST_EXTERNAL_VECTOR && num != SYSCALL_VECTOR)
+		return 0;
+
+	/* The Host needs to see page faults (for shadow paging and to save the
+	 * fault address), general protection faults (in/out emulation) and
+	 * device not available (TS handling), and of course, the hypercall
+	 * trap. */
+	if (num == 14 || num == 13 || num == 7 || num == LGUEST_TRAP_ENTRY)
+		return 0;
+
+	/* Only trap gates (type 15) can go direct to the Guest.  Interrupt
+	 * gates (type 14) disable interrupts as they are entered, which we
+	 * never let the Guest do.  Not present entries (type 0x0) also can't
+	 * go direct, of course 8) */
+	return idt_type(trap->a, trap->b) == 0xF;
+}
+/*:*/
+
+/*M:005 The Guest has the ability to turn its interrupt gates into trap gates,
+ * if it is careful.  The Host will let trap gates can go directly to the
+ * Guest, but the Guest needs the interrupts atomically disabled for an
+ * interrupt gate.  It can do this by pointing the trap gate at instructions
+ * within noirq_start and noirq_end, where it can safely disable interrupts. */
+
+/*M:006 The Guests do not use the sysenter (fast system call) instruction,
+ * because it's hardcoded to enter privilege level 0 and so can't go direct.
+ * It's about twice as fast as the older "int 0x80" system call, so it might
+ * still be worthwhile to handle it in the Switcher and lcall down to the
+ * Guest.  The sysenter semantics are hairy tho: search for that keyword in
+ * entry.S :*/
+
+/*H:260 When we make traps go directly into the Guest, we need to make sure
+ * the kernel stack is valid (ie. mapped in the page tables).  Otherwise, the
+ * CPU trying to deliver the trap will fault while trying to push the interrupt
+ * words on the stack: this is called a double fault, and it forces us to kill
+ * the Guest.
+ *
+ * Which is deeply unfair, because (literally!) it wasn't the Guests' fault. */
+void pin_stack_pages(struct lguest *lg)
+{
+	unsigned int i;
+
+	/* Depending on the CONFIG_4KSTACKS option, the Guest can have one or
+	 * two pages of stack space. */
+	for (i = 0; i < lg->stack_pages; i++)
+		/* The stack grows *upwards*, so the address we're given is the
+		 * start of the page after the kernel stack.  Subtract one to
+		 * get back onto the first stack page, and keep subtracting to
+		 * get to the rest of the stack pages. */
+		pin_page(lg, lg->esp1 - 1 - i * PAGE_SIZE);
+}
+
+/* Direct traps also mean that we need to know whenever the Guest wants to use
+ * a different kernel stack, so we can change the IDT entries to use that
+ * stack.  The IDT entries expect a virtual address, so unlike most addresses
+ * the Guest gives us, the "esp" (stack pointer) value here is virtual, not
+ * physical.
+ *
+ * In Linux each process has its own kernel stack, so this happens a lot: we
+ * change stacks on each context switch. */
+void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages)
+{
+	/* You are not allowd have a stack segment with privilege level 0: bad
+	 * Guest! */
+	if ((seg & 0x3) != GUEST_PL)
+		kill_guest(lg, "bad stack segment %i", seg);
+	/* We only expect one or two stack pages. */
+	if (pages > 2)
+		kill_guest(lg, "bad stack pages %u", pages);
+	/* Save where the stack is, and how many pages */
+	lg->ss1 = seg;
+	lg->esp1 = esp;
+	lg->stack_pages = pages;
+	/* Make sure the new stack pages are mapped */
+	pin_stack_pages(lg);
+}
+
+/* All this reference to mapping stacks leads us neatly into the other complex
+ * part of the Host: page table handling. */
+
+/*H:235 This is the routine which actually checks the Guest's IDT entry and
+ * transfers it into our entry in "struct lguest": */
+static void set_trap(struct lguest *lg, struct desc_struct *trap,
+		     unsigned int num, u32 lo, u32 hi)
+{
+	u8 type = idt_type(lo, hi);
+
+	/* We zero-out a not-present entry */
+	if (!idt_present(lo, hi)) {
+		trap->a = trap->b = 0;
+		return;
+	}
+
+	/* We only support interrupt and trap gates. */
+	if (type != 0xE && type != 0xF)
+		kill_guest(lg, "bad IDT type %i", type);
+
+	/* We only copy the handler address, present bit, privilege level and
+	 * type.  The privilege level controls where the trap can be triggered
+	 * manually with an "int" instruction.  This is usually GUEST_PL,
+	 * except for system calls which userspace can use. */
+	trap->a = ((__KERNEL_CS|GUEST_PL)<<16) | (lo&0x0000FFFF);
+	trap->b = (hi&0xFFFFEF00);
+}
+
+/*H:230 While we're here, dealing with delivering traps and interrupts to the
+ * Guest, we might as well complete the picture: how the Guest tells us where
+ * it wants them to go.  This would be simple, except making traps fast
+ * requires some tricks.
+ *
+ * We saw the Guest setting Interrupt Descriptor Table (IDT) entries with the
+ * LHCALL_LOAD_IDT_ENTRY hypercall before: that comes here. */
+void load_guest_idt_entry(struct lguest *lg, unsigned int num, u32 lo, u32 hi)
+{
+	/* Guest never handles: NMI, doublefault, spurious interrupt or
+	 * hypercall.  We ignore when it tries to set them. */
+	if (num == 2 || num == 8 || num == 15 || num == LGUEST_TRAP_ENTRY)
+		return;
+
+	/* Mark the IDT as changed: next time the Guest runs we'll know we have
+	 * to copy this again. */
+	lg->changed |= CHANGED_IDT;
+
+	/* The IDT which we keep in "struct lguest" only contains 32 entries
+	 * for the traps and LGUEST_IRQS (32) entries for interrupts.  We
+	 * ignore attempts to set handlers for higher interrupt numbers, except
+	 * for the system call "interrupt" at 128: we have a special IDT entry
+	 * for that. */
+	if (num < ARRAY_SIZE(lg->idt))
+		set_trap(lg, &lg->idt[num], num, lo, hi);
+	else if (num == SYSCALL_VECTOR)
+		set_trap(lg, &lg->syscall_idt, num, lo, hi);
+}
+
+/* The default entry for each interrupt points into the Switcher routines which
+ * simply return to the Host.  The run_guest() loop will then call
+ * deliver_trap() to bounce it back into the Guest. */
+static void default_idt_entry(struct desc_struct *idt,
+			      int trap,
+			      const unsigned long handler)
+{
+	/* A present interrupt gate. */
+	u32 flags = 0x8e00;
+
+	/* Set the privilege level on the entry for the hypercall: this allows
+	 * the Guest to use the "int" instruction to trigger it. */
+	if (trap == LGUEST_TRAP_ENTRY)
+		flags |= (GUEST_PL << 13);
+
+	/* Now pack it into the IDT entry in its weird format. */
+	idt->a = (LGUEST_CS<<16) | (handler&0x0000FFFF);
+	idt->b = (handler&0xFFFF0000) | flags;
+}
+
+/* When the Guest first starts, we put default entries into the IDT. */
+void setup_default_idt_entries(struct lguest_ro_state *state,
+			       const unsigned long *def)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(state->guest_idt); i++)
+		default_idt_entry(&state->guest_idt[i], i, def[i]);
+}
+
+/*H:240 We don't use the IDT entries in the "struct lguest" directly, instead
+ * we copy them into the IDT which we've set up for Guests on this CPU, just
+ * before we run the Guest.  This routine does that copy. */
+void copy_traps(const struct lguest *lg, struct desc_struct *idt,
+		const unsigned long *def)
+{
+	unsigned int i;
+
+	/* We can simply copy the direct traps, otherwise we use the default
+	 * ones in the Switcher: they will return to the Host. */
+	for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) {
+		if (direct_trap(lg, &lg->idt[i], i))
+			idt[i] = lg->idt[i];
+		else
+			default_idt_entry(&idt[i], i, def[i]);
+	}
+
+	/* Don't forget the system call trap!  The IDT entries for other
+	 * interupts never change, so no need to copy them. */
+	i = SYSCALL_VECTOR;
+	if (direct_trap(lg, &lg->syscall_idt, i))
+		idt[i] = lg->syscall_idt;
+	else
+		default_idt_entry(&idt[i], i, def[i]);
+}
+
+void guest_set_clockevent(struct lguest *lg, unsigned long delta)
+{
+	ktime_t expires;
+
+	if (unlikely(delta == 0)) {
+		/* Clock event device is shutting down. */
+		hrtimer_cancel(&lg->hrt);
+		return;
+	}
+
+	expires = ktime_add_ns(ktime_get_real(), delta);
+	hrtimer_start(&lg->hrt, expires, HRTIMER_MODE_ABS);
+}
+
+static enum hrtimer_restart clockdev_fn(struct hrtimer *timer)
+{
+	struct lguest *lg = container_of(timer, struct lguest, hrt);
+
+	set_bit(0, lg->irqs_pending);
+	if (lg->halted)
+		wake_up_process(lg->tsk);
+	return HRTIMER_NORESTART;
+}
+
+void init_clockdev(struct lguest *lg)
+{
+	hrtimer_init(&lg->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS);
+	lg->hrt.function = clockdev_fn;
+}
diff --git a/drivers/lguest/io.c b/drivers/lguest/io.c
new file mode 100644
index 0000000..ea68613
--- /dev/null
+++ b/drivers/lguest/io.c
@@ -0,0 +1,626 @@
+/*P:300 The I/O mechanism in lguest is simple yet flexible, allowing the Guest
+ * to talk to the Launcher or directly to another Guest.  It uses familiar
+ * concepts of DMA and interrupts, plus some neat code stolen from
+ * futexes... :*/
+
+/* Copyright (C) 2006 Rusty Russell IBM Corporation
+ *
+ *  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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+#include <linux/types.h>
+#include <linux/futex.h>
+#include <linux/jhash.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/uaccess.h>
+#include "lg.h"
+
+/*L:300
+ * I/O
+ *
+ * Getting data in and out of the Guest is quite an art.  There are numerous
+ * ways to do it, and they all suck differently.  We try to keep things fairly
+ * close to "real" hardware so our Guest's drivers don't look like an alien
+ * visitation in the middle of the Linux code, and yet make sure that Guests
+ * can talk directly to other Guests, not just the Launcher.
+ *
+ * To do this, the Guest gives us a key when it binds or sends DMA buffers.
+ * The key corresponds to a "physical" address inside the Guest (ie. a virtual
+ * address inside the Launcher process).  We don't, however, use this key
+ * directly.
+ *
+ * We want Guests which share memory to be able to DMA to each other: two
+ * Launchers can mmap memory the same file, then the Guests can communicate.
+ * Fortunately, the futex code provides us with a way to get a "union
+ * futex_key" corresponding to the memory lying at a virtual address: if the
+ * two processes share memory, the "union futex_key" for that memory will match
+ * even if the memory is mapped at different addresses in each.  So we always
+ * convert the keys to "union futex_key"s to compare them.
+ *
+ * Before we dive into this though, we need to look at another set of helper
+ * routines used throughout the Host kernel code to access Guest memory.
+ :*/
+static struct list_head dma_hash[61];
+
+/* An unfortunate side effect of the Linux double-linked list implementation is
+ * that there's no good way to statically initialize an array of linked
+ * lists. */
+void lguest_io_init(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(dma_hash); i++)
+		INIT_LIST_HEAD(&dma_hash[i]);
+}
+
+/* FIXME: allow multi-page lengths. */
+static int check_dma_list(struct lguest *lg, const struct lguest_dma *dma)
+{
+	unsigned int i;
+
+	for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) {
+		if (!dma->len[i])
+			return 1;
+		if (!lguest_address_ok(lg, dma->addr[i], dma->len[i]))
+			goto kill;
+		if (dma->len[i] > PAGE_SIZE)
+			goto kill;
+		/* We could do over a page, but is it worth it? */
+		if ((dma->addr[i] % PAGE_SIZE) + dma->len[i] > PAGE_SIZE)
+			goto kill;
+	}
+	return 1;
+
+kill:
+	kill_guest(lg, "bad DMA entry: %u@%#lx", dma->len[i], dma->addr[i]);
+	return 0;
+}
+
+/*L:330 This is our hash function, using the wonderful Jenkins hash.
+ *
+ * The futex key is a union with three parts: an unsigned long word, a pointer,
+ * and an int "offset".  We could use jhash_2words() which takes three u32s.
+ * (Ok, the hash functions are great: the naming sucks though).
+ *
+ * It's nice to be portable to 64-bit platforms, so we use the more generic
+ * jhash2(), which takes an array of u32, the number of u32s, and an initial
+ * u32 to roll in.  This is uglier, but breaks down to almost the same code on
+ * 32-bit platforms like this one.
+ *
+ * We want a position in the array, so we modulo ARRAY_SIZE(dma_hash) (ie. 61).
+ */
+static unsigned int hash(const union futex_key *key)
+{
+	return jhash2((u32*)&key->both.word,
+		      (sizeof(key->both.word)+sizeof(key->both.ptr))/4,
+		      key->both.offset)
+		% ARRAY_SIZE(dma_hash);
+}
+
+/* This is a convenience routine to compare two keys.  It's a much bemoaned C
+ * weakness that it doesn't allow '==' on structures or unions, so we have to
+ * open-code it like this. */
+static inline int key_eq(const union futex_key *a, const union futex_key *b)
+{
+	return (a->both.word == b->both.word
+		&& a->both.ptr == b->both.ptr
+		&& a->both.offset == b->both.offset);
+}
+
+/*L:360 OK, when we need to actually free up a Guest's DMA array we do several
+ * things, so we have a convenient function to do it.
+ *
+ * The caller must hold a read lock on dmainfo owner's current->mm->mmap_sem
+ * for the drop_futex_key_refs(). */
+static void unlink_dma(struct lguest_dma_info *dmainfo)
+{
+	/* You locked this too, right? */
+	BUG_ON(!mutex_is_locked(&lguest_lock));
+	/* This is how we know that the entry is free. */
+	dmainfo->interrupt = 0;
+	/* Remove it from the hash table. */
+	list_del(&dmainfo->list);
+	/* Drop the references we were holding (to the inode or mm). */
+	drop_futex_key_refs(&dmainfo->key);
+}
+
+/*L:350 This is the routine which we call when the Guest asks to unregister a
+ * DMA array attached to a given key.  Returns true if the array was found. */
+static int unbind_dma(struct lguest *lg,
+		      const union futex_key *key,
+		      unsigned long dmas)
+{
+	int i, ret = 0;
+
+	/* We don't bother with the hash table, just look through all this
+	 * Guest's DMA arrays. */
+	for (i = 0; i < LGUEST_MAX_DMA; i++) {
+		/* In theory it could have more than one array on the same key,
+		 * or one array on multiple keys, so we check both */
+		if (key_eq(key, &lg->dma[i].key) && dmas == lg->dma[i].dmas) {
+			unlink_dma(&lg->dma[i]);
+			ret = 1;
+			break;
+		}
+	}
+	return ret;
+}
+
+/*L:340 BIND_DMA: this is the hypercall which sets up an array of "struct
+ * lguest_dma" for receiving I/O.
+ *
+ * The Guest wants to bind an array of "struct lguest_dma"s to a particular key
+ * to receive input.  This only happens when the Guest is setting up a new
+ * device, so it doesn't have to be very fast.
+ *
+ * It returns 1 on a successful registration (it can fail if we hit the limit
+ * of registrations for this Guest).
+ */
+int bind_dma(struct lguest *lg,
+	     unsigned long ukey, unsigned long dmas, u16 numdmas, u8 interrupt)
+{
+	unsigned int i;
+	int ret = 0;
+	union futex_key key;
+	/* Futex code needs the mmap_sem. */
+	struct rw_semaphore *fshared = &current->mm->mmap_sem;
+
+	/* Invalid interrupt?  (We could kill the guest here). */
+	if (interrupt >= LGUEST_IRQS)
+		return 0;
+
+	/* We need to grab the Big Lguest Lock, because other Guests may be
+	 * trying to look through this Guest's DMAs to send something while
+	 * we're doing this. */
+	mutex_lock(&lguest_lock);
+	down_read(fshared);
+	if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
+		kill_guest(lg, "bad dma key %#lx", ukey);
+		goto unlock;
+	}
+
+	/* We want to keep this key valid once we drop mmap_sem, so we have to
+	 * hold a reference. */
+	get_futex_key_refs(&key);
+
+	/* If the Guest specified an interrupt of 0, that means they want to
+	 * unregister this array of "struct lguest_dma"s. */
+	if (interrupt == 0)
+		ret = unbind_dma(lg, &key, dmas);
+	else {
+		/* Look through this Guest's dma array for an unused entry. */
+		for (i = 0; i < LGUEST_MAX_DMA; i++) {
+			/* If the interrupt is non-zero, the entry is already
+			 * used. */
+			if (lg->dma[i].interrupt)
+				continue;
+
+			/* OK, a free one!  Fill on our details. */
+			lg->dma[i].dmas = dmas;
+			lg->dma[i].num_dmas = numdmas;
+			lg->dma[i].next_dma = 0;
+			lg->dma[i].key = key;
+			lg->dma[i].guestid = lg->guestid;
+			lg->dma[i].interrupt = interrupt;
+
+			/* Now we add it to the hash table: the position
+			 * depends on the futex key that we got. */
+			list_add(&lg->dma[i].list, &dma_hash[hash(&key)]);
+			/* Success! */
+			ret = 1;
+			goto unlock;
+		}
+	}
+	/* If we didn't find a slot to put the key in, drop the reference
+	 * again. */
+	drop_futex_key_refs(&key);
+unlock:
+	/* Unlock and out. */
+ 	up_read(fshared);
+	mutex_unlock(&lguest_lock);
+	return ret;
+}
+
+/*L:385 Note that our routines to access a different Guest's memory are called
+ * lgread_other() and lgwrite_other(): these names emphasize that they are only
+ * used when the Guest is *not* the current Guest.
+ *
+ * The interface for copying from another process's memory is called
+ * access_process_vm(), with a final argument of 0 for a read, and 1 for a
+ * write.
+ *
+ * We need lgread_other() to read the destination Guest's "struct lguest_dma"
+ * array. */
+static int lgread_other(struct lguest *lg,
+			void *buf, u32 addr, unsigned bytes)
+{
+	if (!lguest_address_ok(lg, addr, bytes)
+	    || access_process_vm(lg->tsk, addr, buf, bytes, 0) != bytes) {
+		memset(buf, 0, bytes);
+		kill_guest(lg, "bad address in registered DMA struct");
+		return 0;
+	}
+	return 1;
+}
+
+/* "lgwrite()" to another Guest: used to update the destination "used_len" once
+ * we've transferred data into the buffer. */
+static int lgwrite_other(struct lguest *lg, u32 addr,
+			 const void *buf, unsigned bytes)
+{
+	if (!lguest_address_ok(lg, addr, bytes)
+	    || (access_process_vm(lg->tsk, addr, (void *)buf, bytes, 1)
+		!= bytes)) {
+		kill_guest(lg, "bad address writing to registered DMA");
+		return 0;
+	}
+	return 1;
+}
+
+/*L:400 This is the generic engine which copies from a source "struct
+ * lguest_dma" from this Guest into another Guest's "struct lguest_dma".  The
+ * destination Guest's pages have already been mapped, as contained in the
+ * pages array.
+ *
+ * If you're wondering if there's a nice "copy from one process to another"
+ * routine, so was I.  But Linux isn't really set up to copy between two
+ * unrelated processes, so we have to write it ourselves.
+ */
+static u32 copy_data(struct lguest *srclg,
+		     const struct lguest_dma *src,
+		     const struct lguest_dma *dst,
+		     struct page *pages[])
+{
+	unsigned int totlen, si, di, srcoff, dstoff;
+	void *maddr = NULL;
+
+	/* We return the total length transferred. */
+	totlen = 0;
+
+	/* We keep indexes into the source and destination "struct lguest_dma",
+	 * and an offset within each region. */
+	si = di = 0;
+	srcoff = dstoff = 0;
+
+	/* We loop until the source or destination is exhausted. */
+	while (si < LGUEST_MAX_DMA_SECTIONS && src->len[si]
+	       && di < LGUEST_MAX_DMA_SECTIONS && dst->len[di]) {
+		/* We can only transfer the rest of the src buffer, or as much
+		 * as will fit into the destination buffer. */
+		u32 len = min(src->len[si] - srcoff, dst->len[di] - dstoff);
+
+		/* For systems using "highmem" we need to use kmap() to access
+		 * the page we want.  We often use the same page over and over,
+		 * so rather than kmap() it on every loop, we set the maddr
+		 * pointer to NULL when we need to move to the next
+		 * destination page. */
+		if (!maddr)
+			maddr = kmap(pages[di]);
+
+		/* Copy directly from (this Guest's) source address to the
+		 * destination Guest's kmap()ed buffer.  Note that maddr points
+		 * to the start of the page: we need to add the offset of the
+		 * destination address and offset within the buffer. */
+
+		/* FIXME: This is not completely portable.  I looked at
+		 * copy_to_user_page(), and some arch's seem to need special
+		 * flushes.  x86 is fine. */
+		if (copy_from_user(maddr + (dst->addr[di] + dstoff)%PAGE_SIZE,
+				   (void __user *)src->addr[si], len) != 0) {
+			/* If a copy failed, it's the source's fault. */
+			kill_guest(srclg, "bad address in sending DMA");
+			totlen = 0;
+			break;
+		}
+
+		/* Increment the total and src & dst offsets */
+		totlen += len;
+		srcoff += len;
+		dstoff += len;
+
+		/* Presumably we reached the end of the src or dest buffers: */
+		if (srcoff == src->len[si]) {
+			/* Move to the next buffer at offset 0 */
+			si++;
+			srcoff = 0;
+		}
+		if (dstoff == dst->len[di]) {
+			/* We need to unmap that destination page and reset
+			 * maddr ready for the next one. */
+			kunmap(pages[di]);
+			maddr = NULL;
+			di++;
+			dstoff = 0;
+		}
+	}
+
+	/* If we still had a page mapped at the end, unmap now. */
+	if (maddr)
+		kunmap(pages[di]);
+
+	return totlen;
+}
+
+/*L:390 This is how we transfer a "struct lguest_dma" from the source Guest
+ * (the current Guest which called SEND_DMA) to another Guest. */
+static u32 do_dma(struct lguest *srclg, const struct lguest_dma *src,
+		  struct lguest *dstlg, const struct lguest_dma *dst)
+{
+	int i;
+	u32 ret;
+	struct page *pages[LGUEST_MAX_DMA_SECTIONS];
+
+	/* We check that both source and destination "struct lguest_dma"s are
+	 * within the bounds of the source and destination Guests */
+	if (!check_dma_list(dstlg, dst) || !check_dma_list(srclg, src))
+		return 0;
+
+	/* We need to map the pages which correspond to each parts of
+	 * destination buffer. */
+	for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) {
+		if (dst->len[i] == 0)
+			break;
+		/* get_user_pages() is a complicated function, especially since
+		 * we only want a single page.  But it works, and returns the
+		 * number of pages.  Note that we're holding the destination's
+		 * mmap_sem, as get_user_pages() requires. */
+		if (get_user_pages(dstlg->tsk, dstlg->mm,
+				   dst->addr[i], 1, 1, 1, pages+i, NULL)
+		    != 1) {
+			/* This means the destination gave us a bogus buffer */
+			kill_guest(dstlg, "Error mapping DMA pages");
+			ret = 0;
+			goto drop_pages;
+		}
+	}
+
+	/* Now copy the data until we run out of src or dst. */
+	ret = copy_data(srclg, src, dst, pages);
+
+drop_pages:
+	while (--i >= 0)
+		put_page(pages[i]);
+	return ret;
+}
+
+/*L:380 Transferring data from one Guest to another is not as simple as I'd
+ * like.  We've found the "struct lguest_dma_info" bound to the same address as
+ * the send, we need to copy into it.
+ *
+ * This function returns true if the destination array was empty. */
+static int dma_transfer(struct lguest *srclg,
+			unsigned long udma,
+			struct lguest_dma_info *dst)
+{
+	struct lguest_dma dst_dma, src_dma;
+	struct lguest *dstlg;
+	u32 i, dma = 0;
+
+	/* From the "struct lguest_dma_info" we found in the hash, grab the
+	 * Guest. */
+	dstlg = &lguests[dst->guestid];
+	/* Read in the source "struct lguest_dma" handed to SEND_DMA. */
+	lgread(srclg, &src_dma, udma, sizeof(src_dma));
+
+	/* We need the destination's mmap_sem, and we already hold the source's
+	 * mmap_sem for the futex key lookup.  Normally this would suggest that
+	 * we could deadlock if the destination Guest was trying to send to
+	 * this source Guest at the same time, which is another reason that all
+	 * I/O is done under the big lguest_lock. */
+	down_read(&dstlg->mm->mmap_sem);
+
+	/* Look through the destination DMA array for an available buffer. */
+	for (i = 0; i < dst->num_dmas; i++) {
+		/* We keep a "next_dma" pointer which often helps us avoid
+		 * looking at lots of previously-filled entries. */
+		dma = (dst->next_dma + i) % dst->num_dmas;
+		if (!lgread_other(dstlg, &dst_dma,
+				  dst->dmas + dma * sizeof(struct lguest_dma),
+				  sizeof(dst_dma))) {
+			goto fail;
+		}
+		if (!dst_dma.used_len)
+			break;
+	}
+
+	/* If we found a buffer, we do the actual data copy. */
+	if (i != dst->num_dmas) {
+		unsigned long used_lenp;
+		unsigned int ret;
+
+		ret = do_dma(srclg, &src_dma, dstlg, &dst_dma);
+		/* Put used length in the source "struct lguest_dma"'s used_len
+		 * field.  It's a little tricky to figure out where that is,
+		 * though. */
+		lgwrite_u32(srclg,
+			    udma+offsetof(struct lguest_dma, used_len), ret);
+		/* Tranferring 0 bytes is OK if the source buffer was empty. */
+		if (ret == 0 && src_dma.len[0] != 0)
+			goto fail;
+
+		/* The destination Guest might be running on a different CPU:
+		 * we have to make sure that it will see the "used_len" field
+		 * change to non-zero *after* it sees the data we copied into
+		 * the buffer.  Hence a write memory barrier. */
+		wmb();
+		/* Figuring out where the destination's used_len field for this
+		 * "struct lguest_dma" in the array is also a little ugly. */
+		used_lenp = dst->dmas
+			+ dma * sizeof(struct lguest_dma)
+			+ offsetof(struct lguest_dma, used_len);
+		lgwrite_other(dstlg, used_lenp, &ret, sizeof(ret));
+		/* Move the cursor for next time. */
+		dst->next_dma++;
+	}
+ 	up_read(&dstlg->mm->mmap_sem);
+
+	/* We trigger the destination interrupt, even if the destination was
+	 * empty and we didn't transfer anything: this gives them a chance to
+	 * wake up and refill. */
+	set_bit(dst->interrupt, dstlg->irqs_pending);
+	/* Wake up the destination process. */
+	wake_up_process(dstlg->tsk);
+	/* If we passed the last "struct lguest_dma", the receive had no
+	 * buffers left. */
+	return i == dst->num_dmas;
+
+fail:
+	up_read(&dstlg->mm->mmap_sem);
+	return 0;
+}
+
+/*L:370 This is the counter-side to the BIND_DMA hypercall; the SEND_DMA
+ * hypercall.  We find out who's listening, and send to them. */
+void send_dma(struct lguest *lg, unsigned long ukey, unsigned long udma)
+{
+	union futex_key key;
+	int empty = 0;
+	struct rw_semaphore *fshared = &current->mm->mmap_sem;
+
+again:
+	mutex_lock(&lguest_lock);
+	down_read(fshared);
+	/* Get the futex key for the key the Guest gave us */
+	if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
+		kill_guest(lg, "bad sending DMA key");
+		goto unlock;
+	}
+	/* Since the key must be a multiple of 4, the futex key uses the lower
+	 * bit of the "offset" field (which would always be 0) to indicate a
+	 * mapping which is shared with other processes (ie. Guests). */
+	if (key.shared.offset & 1) {
+		struct lguest_dma_info *i;
+		/* Look through the hash for other Guests. */
+		list_for_each_entry(i, &dma_hash[hash(&key)], list) {
+			/* Don't send to ourselves. */
+			if (i->guestid == lg->guestid)
+				continue;
+			if (!key_eq(&key, &i->key))
+				continue;
+
+			/* If dma_transfer() tells us the destination has no
+			 * available buffers, we increment "empty". */
+			empty += dma_transfer(lg, udma, i);
+			break;
+		}
+		/* If the destination is empty, we release our locks and
+		 * give the destination Guest a brief chance to restock. */
+		if (empty == 1) {
+			/* Give any recipients one chance to restock. */
+			up_read(&current->mm->mmap_sem);
+			mutex_unlock(&lguest_lock);
+			/* Next time, we won't try again. */
+			empty++;
+			goto again;
+		}
+	} else {
+		/* Private mapping: Guest is sending to its Launcher.  We set
+		 * the "dma_is_pending" flag so that the main loop will exit
+		 * and the Launcher's read() from /dev/lguest will return. */
+		lg->dma_is_pending = 1;
+		lg->pending_dma = udma;
+		lg->pending_key = ukey;
+	}
+unlock:
+	up_read(fshared);
+	mutex_unlock(&lguest_lock);
+}
+/*:*/
+
+void release_all_dma(struct lguest *lg)
+{
+	unsigned int i;
+
+	BUG_ON(!mutex_is_locked(&lguest_lock));
+
+	down_read(&lg->mm->mmap_sem);
+	for (i = 0; i < LGUEST_MAX_DMA; i++) {
+		if (lg->dma[i].interrupt)
+			unlink_dma(&lg->dma[i]);
+	}
+	up_read(&lg->mm->mmap_sem);
+}
+
+/*M:007 We only return a single DMA buffer to the Launcher, but it would be
+ * more efficient to return a pointer to the entire array of DMA buffers, which
+ * it can cache and choose one whenever it wants.
+ *
+ * Currently the Launcher uses a write to /dev/lguest, and the return value is
+ * the address of the DMA structure with the interrupt number placed in
+ * dma->used_len.  If we wanted to return the entire array, we need to return
+ * the address, array size and interrupt number: this seems to require an
+ * ioctl(). :*/
+
+/*L:320 This routine looks for a DMA buffer registered by the Guest on the
+ * given key (using the BIND_DMA hypercall). */
+unsigned long get_dma_buffer(struct lguest *lg,
+			     unsigned long ukey, unsigned long *interrupt)
+{
+	unsigned long ret = 0;
+	union futex_key key;
+	struct lguest_dma_info *i;
+	struct rw_semaphore *fshared = &current->mm->mmap_sem;
+
+	/* Take the Big Lguest Lock to stop other Guests sending this Guest DMA
+	 * at the same time. */
+	mutex_lock(&lguest_lock);
+	/* To match between Guests sharing the same underlying memory we steal
+	 * code from the futex infrastructure.  This requires that we hold the
+	 * "mmap_sem" for our process (the Launcher), and pass it to the futex
+	 * code. */
+	down_read(fshared);
+
+	/* This can fail if it's not a valid address, or if the address is not
+	 * divisible by 4 (the futex code needs that, we don't really). */
+	if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
+		kill_guest(lg, "bad registered DMA buffer");
+		goto unlock;
+	}
+	/* Search the hash table for matching entries (the Launcher can only
+	 * send to its own Guest for the moment, so the entry must be for this
+	 * Guest) */
+	list_for_each_entry(i, &dma_hash[hash(&key)], list) {
+		if (key_eq(&key, &i->key) && i->guestid == lg->guestid) {
+			unsigned int j;
+			/* Look through the registered DMA array for an
+			 * available buffer. */
+			for (j = 0; j < i->num_dmas; j++) {
+				struct lguest_dma dma;
+
+				ret = i->dmas + j * sizeof(struct lguest_dma);
+				lgread(lg, &dma, ret, sizeof(dma));
+				if (dma.used_len == 0)
+					break;
+			}
+			/* Store the interrupt the Guest wants when the buffer
+			 * is used. */
+			*interrupt = i->interrupt;
+			break;
+		}
+	}
+unlock:
+	up_read(fshared);
+	mutex_unlock(&lguest_lock);
+	return ret;
+}
+/*:*/
+
+/*L:410 This really has completed the Launcher.  Not only have we now finished
+ * the longest chapter in our journey, but this also means we are over halfway
+ * through!
+ *
+ * Enough prevaricating around the bush: it is time for us to dive into the
+ * core of the Host, in "make Host".
+ */
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
new file mode 100644
index 0000000..64f0abe
--- /dev/null
+++ b/drivers/lguest/lg.h
@@ -0,0 +1,300 @@
+#ifndef _LGUEST_H
+#define _LGUEST_H
+
+#include <asm/desc.h>
+
+#define GDT_ENTRY_LGUEST_CS	10
+#define GDT_ENTRY_LGUEST_DS	11
+#define LGUEST_CS		(GDT_ENTRY_LGUEST_CS * 8)
+#define LGUEST_DS		(GDT_ENTRY_LGUEST_DS * 8)
+
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/stringify.h>
+#include <linux/binfmts.h>
+#include <linux/futex.h>
+#include <linux/lguest.h>
+#include <linux/lguest_launcher.h>
+#include <linux/wait.h>
+#include <linux/err.h>
+#include <asm/semaphore.h>
+#include "irq_vectors.h"
+
+#define GUEST_PL 1
+
+struct lguest_regs
+{
+	/* Manually saved part. */
+	unsigned long ebx, ecx, edx;
+	unsigned long esi, edi, ebp;
+	unsigned long gs;
+	unsigned long eax;
+	unsigned long fs, ds, es;
+	unsigned long trapnum, errcode;
+	/* Trap pushed part */
+	unsigned long eip;
+	unsigned long cs;
+	unsigned long eflags;
+	unsigned long esp;
+	unsigned long ss;
+};
+
+void free_pagetables(void);
+int init_pagetables(struct page **switcher_page, unsigned int pages);
+
+/* Full 4G segment descriptors, suitable for CS and DS. */
+#define FULL_EXEC_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9b00})
+#define FULL_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9300})
+
+struct lguest_dma_info
+{
+	struct list_head list;
+	union futex_key key;
+	unsigned long dmas;
+	u16 next_dma;
+	u16 num_dmas;
+	u16 guestid;
+	u8 interrupt; 	/* 0 when not registered */
+};
+
+/*H:310 The page-table code owes a great debt of gratitude to Andi Kleen.  He
+ * reviewed the original code which used "u32" for all page table entries, and
+ * insisted that it would be far clearer with explicit typing.  I thought it
+ * was overkill, but he was right: it is much clearer than it was before.
+ *
+ * We have separate types for the Guest's ptes & pgds and the shadow ptes &
+ * pgds.  There's already a Linux type for these (pte_t and pgd_t) but they
+ * change depending on kernel config options (PAE). */
+
+/* Each entry is identical: lower 12 bits of flags and upper 20 bits for the
+ * "page frame number" (0 == first physical page, etc).  They are different
+ * types so the compiler will warn us if we mix them improperly. */
+typedef union {
+	struct { unsigned flags:12, pfn:20; };
+	struct { unsigned long val; } raw;
+} spgd_t;
+typedef union {
+	struct { unsigned flags:12, pfn:20; };
+	struct { unsigned long val; } raw;
+} spte_t;
+typedef union {
+	struct { unsigned flags:12, pfn:20; };
+	struct { unsigned long val; } raw;
+} gpgd_t;
+typedef union {
+	struct { unsigned flags:12, pfn:20; };
+	struct { unsigned long val; } raw;
+} gpte_t;
+
+/* We have two convenient macros to convert a "raw" value as handed to us by
+ * the Guest into the correct Guest PGD or PTE type. */
+#define mkgpte(_val) ((gpte_t){.raw.val = _val})
+#define mkgpgd(_val) ((gpgd_t){.raw.val = _val})
+/*:*/
+
+struct pgdir
+{
+	unsigned long cr3;
+	spgd_t *pgdir;
+};
+
+/* This is a guest-specific page (mapped ro) into the guest. */
+struct lguest_ro_state
+{
+	/* Host information we need to restore when we switch back. */
+	u32 host_cr3;
+	struct Xgt_desc_struct host_idt_desc;
+	struct Xgt_desc_struct host_gdt_desc;
+	u32 host_sp;
+
+	/* Fields which are used when guest is running. */
+	struct Xgt_desc_struct guest_idt_desc;
+	struct Xgt_desc_struct guest_gdt_desc;
+	struct i386_hw_tss guest_tss;
+	struct desc_struct guest_idt[IDT_ENTRIES];
+	struct desc_struct guest_gdt[GDT_ENTRIES];
+};
+
+/* We have two pages shared with guests, per cpu.  */
+struct lguest_pages
+{
+	/* This is the stack page mapped rw in guest */
+	char spare[PAGE_SIZE - sizeof(struct lguest_regs)];
+	struct lguest_regs regs;
+
+	/* This is the host state & guest descriptor page, ro in guest */
+	struct lguest_ro_state state;
+} __attribute__((aligned(PAGE_SIZE)));
+
+#define CHANGED_IDT		1
+#define CHANGED_GDT		2
+#define CHANGED_GDT_TLS		4 /* Actually a subset of CHANGED_GDT */
+#define CHANGED_ALL	        3
+
+/* The private info the thread maintains about the guest. */
+struct lguest
+{
+	/* At end of a page shared mapped over lguest_pages in guest.  */
+	unsigned long regs_page;
+	struct lguest_regs *regs;
+	struct lguest_data __user *lguest_data;
+	struct task_struct *tsk;
+	struct mm_struct *mm; 	/* == tsk->mm, but that becomes NULL on exit */
+	u16 guestid;
+	u32 pfn_limit;
+	u32 page_offset;
+	u32 cr2;
+	int halted;
+	int ts;
+	u32 next_hcall;
+	u32 esp1;
+	u8 ss1;
+
+	/* Do we need to stop what we're doing and return to userspace? */
+	int break_out;
+	wait_queue_head_t break_wq;
+
+	/* Bitmap of what has changed: see CHANGED_* above. */
+	int changed;
+	struct lguest_pages *last_pages;
+
+	/* We keep a small number of these. */
+	u32 pgdidx;
+	struct pgdir pgdirs[4];
+
+	/* Cached wakeup: we hold a reference to this task. */
+	struct task_struct *wake;
+
+	unsigned long noirq_start, noirq_end;
+	int dma_is_pending;
+	unsigned long pending_dma; /* struct lguest_dma */
+	unsigned long pending_key; /* address they're sending to */
+
+	unsigned int stack_pages;
+	u32 tsc_khz;
+
+	struct lguest_dma_info dma[LGUEST_MAX_DMA];
+
+	/* Dead? */
+	const char *dead;
+
+	/* The GDT entries copied into lguest_ro_state when running. */
+	struct desc_struct gdt[GDT_ENTRIES];
+
+	/* The IDT entries: some copied into lguest_ro_state when running. */
+	struct desc_struct idt[FIRST_EXTERNAL_VECTOR+LGUEST_IRQS];
+	struct desc_struct syscall_idt;
+
+	/* Virtual clock device */
+	struct hrtimer hrt;
+
+	/* Pending virtual interrupts */
+	DECLARE_BITMAP(irqs_pending, LGUEST_IRQS);
+};
+
+extern struct lguest lguests[];
+extern struct mutex lguest_lock;
+
+/* core.c: */
+u32 lgread_u32(struct lguest *lg, unsigned long addr);
+void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val);
+void lgread(struct lguest *lg, void *buf, unsigned long addr, unsigned len);
+void lgwrite(struct lguest *lg, unsigned long, const void *buf, unsigned len);
+int find_free_guest(void);
+int lguest_address_ok(const struct lguest *lg,
+		      unsigned long addr, unsigned long len);
+int run_guest(struct lguest *lg, unsigned long __user *user);
+
+
+/* interrupts_and_traps.c: */
+void maybe_do_interrupt(struct lguest *lg);
+int deliver_trap(struct lguest *lg, unsigned int num);
+void load_guest_idt_entry(struct lguest *lg, unsigned int i, u32 low, u32 hi);
+void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages);
+void pin_stack_pages(struct lguest *lg);
+void setup_default_idt_entries(struct lguest_ro_state *state,
+			       const unsigned long *def);
+void copy_traps(const struct lguest *lg, struct desc_struct *idt,
+		const unsigned long *def);
+void guest_set_clockevent(struct lguest *lg, unsigned long delta);
+void init_clockdev(struct lguest *lg);
+
+/* segments.c: */
+void setup_default_gdt_entries(struct lguest_ro_state *state);
+void setup_guest_gdt(struct lguest *lg);
+void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num);
+void guest_load_tls(struct lguest *lg, unsigned long tls_array);
+void copy_gdt(const struct lguest *lg, struct desc_struct *gdt);
+void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt);
+
+/* page_tables.c: */
+int init_guest_pagetable(struct lguest *lg, unsigned long pgtable);
+void free_guest_pagetable(struct lguest *lg);
+void guest_new_pagetable(struct lguest *lg, unsigned long pgtable);
+void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 i);
+void guest_pagetable_clear_all(struct lguest *lg);
+void guest_pagetable_flush_user(struct lguest *lg);
+void guest_set_pte(struct lguest *lg, unsigned long cr3,
+		   unsigned long vaddr, gpte_t val);
+void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages);
+int demand_page(struct lguest *info, unsigned long cr2, int errcode);
+void pin_page(struct lguest *lg, unsigned long vaddr);
+
+/* lguest_user.c: */
+int lguest_device_init(void);
+void lguest_device_remove(void);
+
+/* io.c: */
+void lguest_io_init(void);
+int bind_dma(struct lguest *lg,
+	     unsigned long key, unsigned long udma, u16 numdmas, u8 interrupt);
+void send_dma(struct lguest *info, unsigned long key, unsigned long udma);
+void release_all_dma(struct lguest *lg);
+unsigned long get_dma_buffer(struct lguest *lg, unsigned long key,
+			     unsigned long *interrupt);
+
+/* hypercalls.c: */
+void do_hypercalls(struct lguest *lg);
+void write_timestamp(struct lguest *lg);
+
+/*L:035
+ * Let's step aside for the moment, to study one important routine that's used
+ * widely in the Host code.
+ *
+ * There are many cases where the Guest does something invalid, like pass crap
+ * to a hypercall.  Since only the Guest kernel can make hypercalls, it's quite
+ * acceptable to simply terminate the Guest and give the Launcher a nicely
+ * formatted reason.  It's also simpler for the Guest itself, which doesn't
+ * need to check most hypercalls for "success"; if you're still running, it
+ * succeeded.
+ *
+ * Once this is called, the Guest will never run again, so most Host code can
+ * call this then continue as if nothing had happened.  This means many
+ * functions don't have to explicitly return an error code, which keeps the
+ * code simple.
+ *
+ * It also means that this can be called more than once: only the first one is
+ * remembered.  The only trick is that we still need to kill the Guest even if
+ * we can't allocate memory to store the reason.  Linux has a neat way of
+ * packing error codes into invalid pointers, so we use that here.
+ *
+ * Like any macro which uses an "if", it is safely wrapped in a run-once "do {
+ * } while(0)".
+ */
+#define kill_guest(lg, fmt...)					\
+do {								\
+	if (!(lg)->dead) {					\
+		(lg)->dead = kasprintf(GFP_ATOMIC, fmt);	\
+		if (!(lg)->dead)				\
+			(lg)->dead = ERR_PTR(-ENOMEM);		\
+	}							\
+} while(0)
+/* (End of aside) :*/
+
+static inline unsigned long guest_pa(struct lguest *lg, unsigned long vaddr)
+{
+	return vaddr - lg->page_offset;
+}
+#endif	/* __ASSEMBLY__ */
+#endif	/* _LGUEST_H */
diff --git a/drivers/lguest/lguest.c b/drivers/lguest/lguest.c
new file mode 100644
index 0000000..ee1c6d0
--- /dev/null
+++ b/drivers/lguest/lguest.c
@@ -0,0 +1,1102 @@
+/*P:010
+ * A hypervisor allows multiple Operating Systems to run on a single machine.
+ * To quote David Wheeler: "Any problem in computer science can be solved with
+ * another layer of indirection."
+ *
+ * We keep things simple in two ways.  First, we start with a normal Linux
+ * kernel and insert a module (lg.ko) which allows us to run other Linux
+ * kernels the same way we'd run processes.  We call the first kernel the Host,
+ * and the others the Guests.  The program which sets up and configures Guests
+ * (such as the example in Documentation/lguest/lguest.c) is called the
+ * Launcher.
+ *
+ * Secondly, we only run specially modified Guests, not normal kernels.  When
+ * you set CONFIG_LGUEST to 'y' or 'm', this automatically sets
+ * CONFIG_LGUEST_GUEST=y, which compiles this file into the kernel so it knows
+ * how to be a Guest.  This means that you can use the same kernel you boot
+ * normally (ie. as a Host) as a Guest.
+ *
+ * These Guests know that they cannot do privileged operations, such as disable
+ * interrupts, and that they have to ask the Host to do such things explicitly.
+ * This file consists of all the replacements for such low-level native
+ * hardware operations: these special Guest versions call the Host.
+ *
+ * So how does the kernel know it's a Guest?  The Guest starts at a special
+ * entry point marked with a magic string, which sets up a few things then
+ * calls here.  We replace the native functions in "struct paravirt_ops"
+ * with our Guest versions, then boot like normal. :*/
+
+/*
+ * Copyright (C) 2006, Rusty Russell <rusty@rustcorp.com.au> IBM Corporation.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT.  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.
+ */
+#include <linux/kernel.h>
+#include <linux/start_kernel.h>
+#include <linux/string.h>
+#include <linux/console.h>
+#include <linux/screen_info.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/lguest.h>
+#include <linux/lguest_launcher.h>
+#include <linux/lguest_bus.h>
+#include <asm/paravirt.h>
+#include <asm/param.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/desc.h>
+#include <asm/setup.h>
+#include <asm/e820.h>
+#include <asm/mce.h>
+#include <asm/io.h>
+
+/*G:010 Welcome to the Guest!
+ *
+ * The Guest in our tale is a simple creature: identical to the Host but
+ * behaving in simplified but equivalent ways.  In particular, the Guest is the
+ * same kernel as the Host (or at least, built from the same source code). :*/
+
+/* Declarations for definitions in lguest_guest.S */
+extern char lguest_noirq_start[], lguest_noirq_end[];
+extern const char lgstart_cli[], lgend_cli[];
+extern const char lgstart_sti[], lgend_sti[];
+extern const char lgstart_popf[], lgend_popf[];
+extern const char lgstart_pushf[], lgend_pushf[];
+extern const char lgstart_iret[], lgend_iret[];
+extern void lguest_iret(void);
+
+struct lguest_data lguest_data = {
+	.hcall_status = { [0 ... LHCALL_RING_SIZE-1] = 0xFF },
+	.noirq_start = (u32)lguest_noirq_start,
+	.noirq_end = (u32)lguest_noirq_end,
+	.blocked_interrupts = { 1 }, /* Block timer interrupts */
+};
+struct lguest_device_desc *lguest_devices;
+static cycle_t clock_base;
+
+/*G:035 Notice the lazy_hcall() above, rather than hcall().  This is our first
+ * real optimization trick!
+ *
+ * When lazy_mode is set, it means we're allowed to defer all hypercalls and do
+ * them as a batch when lazy_mode is eventually turned off.  Because hypercalls
+ * are reasonably expensive, batching them up makes sense.  For example, a
+ * large mmap might update dozens of page table entries: that code calls
+ * lguest_lazy_mode(PARAVIRT_LAZY_MMU), does the dozen updates, then calls
+ * lguest_lazy_mode(PARAVIRT_LAZY_NONE).
+ *
+ * So, when we're in lazy mode, we call async_hypercall() to store the call for
+ * future processing.  When lazy mode is turned off we issue a hypercall to
+ * flush the stored calls.
+ *
+ * There's also a hack where "mode" is set to "PARAVIRT_LAZY_FLUSH" which
+ * indicates we're to flush any outstanding calls immediately.  This is used
+ * when an interrupt handler does a kmap_atomic(): the page table changes must
+ * happen immediately even if we're in the middle of a batch.  Usually we're
+ * not, though, so there's nothing to do. */
+static enum paravirt_lazy_mode lazy_mode; /* Note: not SMP-safe! */
+static void lguest_lazy_mode(enum paravirt_lazy_mode mode)
+{
+	if (mode == PARAVIRT_LAZY_FLUSH) {
+		if (unlikely(lazy_mode != PARAVIRT_LAZY_NONE))
+			hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0);
+	} else {
+		lazy_mode = mode;
+		if (mode == PARAVIRT_LAZY_NONE)
+			hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0);
+	}
+}
+
+static void lazy_hcall(unsigned long call,
+		       unsigned long arg1,
+		       unsigned long arg2,
+		       unsigned long arg3)
+{
+	if (lazy_mode == PARAVIRT_LAZY_NONE)
+		hcall(call, arg1, arg2, arg3);
+	else
+		async_hcall(call, arg1, arg2, arg3);
+}
+
+/* async_hcall() is pretty simple: I'm quite proud of it really.  We have a
+ * ring buffer of stored hypercalls which the Host will run though next time we
+ * do a normal hypercall.  Each entry in the ring has 4 slots for the hypercall
+ * arguments, and a "hcall_status" word which is 0 if the call is ready to go,
+ * and 255 once the Host has finished with it.
+ *
+ * If we come around to a slot which hasn't been finished, then the table is
+ * full and we just make the hypercall directly.  This has the nice side
+ * effect of causing the Host to run all the stored calls in the ring buffer
+ * which empties it for next time! */
+void async_hcall(unsigned long call,
+		 unsigned long arg1, unsigned long arg2, unsigned long arg3)
+{
+	/* Note: This code assumes we're uniprocessor. */
+	static unsigned int next_call;
+	unsigned long flags;
+
+	/* Disable interrupts if not already disabled: we don't want an
+	 * interrupt handler making a hypercall while we're already doing
+	 * one! */
+	local_irq_save(flags);
+	if (lguest_data.hcall_status[next_call] != 0xFF) {
+		/* Table full, so do normal hcall which will flush table. */
+		hcall(call, arg1, arg2, arg3);
+	} else {
+		lguest_data.hcalls[next_call].eax = call;
+		lguest_data.hcalls[next_call].edx = arg1;
+		lguest_data.hcalls[next_call].ebx = arg2;
+		lguest_data.hcalls[next_call].ecx = arg3;
+		/* Arguments must all be written before we mark it to go */
+		wmb();
+		lguest_data.hcall_status[next_call] = 0;
+		if (++next_call == LHCALL_RING_SIZE)
+			next_call = 0;
+	}
+	local_irq_restore(flags);
+}
+/*:*/
+
+/* Wrappers for the SEND_DMA and BIND_DMA hypercalls.  This is mainly because
+ * Jeff Garzik complained that __pa() should never appear in drivers, and this
+ * helps remove most of them.   But also, it wraps some ugliness. */
+void lguest_send_dma(unsigned long key, struct lguest_dma *dma)
+{
+	/* The hcall might not write this if something goes wrong */
+	dma->used_len = 0;
+	hcall(LHCALL_SEND_DMA, key, __pa(dma), 0);
+}
+
+int lguest_bind_dma(unsigned long key, struct lguest_dma *dmas,
+		    unsigned int num, u8 irq)
+{
+	/* This is the only hypercall which actually wants 5 arguments, and we
+	 * only support 4.  Fortunately the interrupt number is always less
+	 * than 256, so we can pack it with the number of dmas in the final
+	 * argument.  */
+	if (!hcall(LHCALL_BIND_DMA, key, __pa(dmas), (num << 8) | irq))
+		return -ENOMEM;
+	return 0;
+}
+
+/* Unbinding is the same hypercall as binding, but with 0 num & irq. */
+void lguest_unbind_dma(unsigned long key, struct lguest_dma *dmas)
+{
+	hcall(LHCALL_BIND_DMA, key, __pa(dmas), 0);
+}
+
+/* For guests, device memory can be used as normal memory, so we cast away the
+ * __iomem to quieten sparse. */
+void *lguest_map(unsigned long phys_addr, unsigned long pages)
+{
+	return (__force void *)ioremap(phys_addr, PAGE_SIZE*pages);
+}
+
+void lguest_unmap(void *addr)
+{
+	iounmap((__force void __iomem *)addr);
+}
+
+/*G:033
+ * Here are our first native-instruction replacements: four functions for
+ * interrupt control.
+ *
+ * The simplest way of implementing these would be to have "turn interrupts
+ * off" and "turn interrupts on" hypercalls.  Unfortunately, this is too slow:
+ * these are by far the most commonly called functions of those we override.
+ *
+ * So instead we keep an "irq_enabled" field inside our "struct lguest_data",
+ * which the Guest can update with a single instruction.  The Host knows to
+ * check there when it wants to deliver an interrupt.
+ */
+
+/* save_flags() is expected to return the processor state (ie. "eflags").  The
+ * eflags word contains all kind of stuff, but in practice Linux only cares
+ * about the interrupt flag.  Our "save_flags()" just returns that. */
+static unsigned long save_fl(void)
+{
+	return lguest_data.irq_enabled;
+}
+
+/* "restore_flags" just sets the flags back to the value given. */
+static void restore_fl(unsigned long flags)
+{
+	lguest_data.irq_enabled = flags;
+}
+
+/* Interrupts go off... */
+static void irq_disable(void)
+{
+	lguest_data.irq_enabled = 0;
+}
+
+/* Interrupts go on... */
+static void irq_enable(void)
+{
+	lguest_data.irq_enabled = X86_EFLAGS_IF;
+}
+/*:*/
+/*M:003 Note that we don't check for outstanding interrupts when we re-enable
+ * them (or when we unmask an interrupt).  This seems to work for the moment,
+ * since interrupts are rare and we'll just get the interrupt on the next timer
+ * tick, but when we turn on CONFIG_NO_HZ, we should revisit this.  One way
+ * would be to put the "irq_enabled" field in a page by itself, and have the
+ * Host write-protect it when an interrupt comes in when irqs are disabled.
+ * There will then be a page fault as soon as interrupts are re-enabled. :*/
+
+/*G:034
+ * The Interrupt Descriptor Table (IDT).
+ *
+ * The IDT tells the processor what to do when an interrupt comes in.  Each
+ * entry in the table is a 64-bit descriptor: this holds the privilege level,
+ * address of the handler, and... well, who cares?  The Guest just asks the
+ * Host to make the change anyway, because the Host controls the real IDT.
+ */
+static void lguest_write_idt_entry(struct desc_struct *dt,
+				   int entrynum, u32 low, u32 high)
+{
+	/* Keep the local copy up to date. */
+	write_dt_entry(dt, entrynum, low, high);
+	/* Tell Host about this new entry. */
+	hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, low, high);
+}
+
+/* Changing to a different IDT is very rare: we keep the IDT up-to-date every
+ * time it is written, so we can simply loop through all entries and tell the
+ * Host about them. */
+static void lguest_load_idt(const struct Xgt_desc_struct *desc)
+{
+	unsigned int i;
+	struct desc_struct *idt = (void *)desc->address;
+
+	for (i = 0; i < (desc->size+1)/8; i++)
+		hcall(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b);
+}
+
+/*
+ * The Global Descriptor Table.
+ *
+ * The Intel architecture defines another table, called the Global Descriptor
+ * Table (GDT).  You tell the CPU where it is (and its size) using the "lgdt"
+ * instruction, and then several other instructions refer to entries in the
+ * table.  There are three entries which the Switcher needs, so the Host simply
+ * controls the entire thing and the Guest asks it to make changes using the
+ * LOAD_GDT hypercall.
+ *
+ * This is the opposite of the IDT code where we have a LOAD_IDT_ENTRY
+ * hypercall and use that repeatedly to load a new IDT.  I don't think it
+ * really matters, but wouldn't it be nice if they were the same?
+ */
+static void lguest_load_gdt(const struct Xgt_desc_struct *desc)
+{
+	BUG_ON((desc->size+1)/8 != GDT_ENTRIES);
+	hcall(LHCALL_LOAD_GDT, __pa(desc->address), GDT_ENTRIES, 0);
+}
+
+/* For a single GDT entry which changes, we do the lazy thing: alter our GDT,
+ * then tell the Host to reload the entire thing.  This operation is so rare
+ * that this naive implementation is reasonable. */
+static void lguest_write_gdt_entry(struct desc_struct *dt,
+				   int entrynum, u32 low, u32 high)
+{
+	write_dt_entry(dt, entrynum, low, high);
+	hcall(LHCALL_LOAD_GDT, __pa(dt), GDT_ENTRIES, 0);
+}
+
+/* OK, I lied.  There are three "thread local storage" GDT entries which change
+ * on every context switch (these three entries are how glibc implements
+ * __thread variables).  So we have a hypercall specifically for this case. */
+static void lguest_load_tls(struct thread_struct *t, unsigned int cpu)
+{
+	/* There's one problem which normal hardware doesn't have: the Host
+	 * can't handle us removing entries we're currently using.  So we clear
+	 * the GS register here: if it's needed it'll be reloaded anyway. */
+	loadsegment(gs, 0);
+	lazy_hcall(LHCALL_LOAD_TLS, __pa(&t->tls_array), cpu, 0);
+}
+
+/*G:038 That's enough excitement for now, back to ploughing through each of
+ * the paravirt_ops (we're about 1/3 of the way through).
+ *
+ * This is the Local Descriptor Table, another weird Intel thingy.  Linux only
+ * uses this for some strange applications like Wine.  We don't do anything
+ * here, so they'll get an informative and friendly Segmentation Fault. */
+static void lguest_set_ldt(const void *addr, unsigned entries)
+{
+}
+
+/* This loads a GDT entry into the "Task Register": that entry points to a
+ * structure called the Task State Segment.  Some comments scattered though the
+ * kernel code indicate that this used for task switching in ages past, along
+ * with blood sacrifice and astrology.
+ *
+ * Now there's nothing interesting in here that we don't get told elsewhere.
+ * But the native version uses the "ltr" instruction, which makes the Host
+ * complain to the Guest about a Segmentation Fault and it'll oops.  So we
+ * override the native version with a do-nothing version. */
+static void lguest_load_tr_desc(void)
+{
+}
+
+/* The "cpuid" instruction is a way of querying both the CPU identity
+ * (manufacturer, model, etc) and its features.  It was introduced before the
+ * Pentium in 1993 and keeps getting extended by both Intel and AMD.  As you
+ * might imagine, after a decade and a half this treatment, it is now a giant
+ * ball of hair.  Its entry in the current Intel manual runs to 28 pages.
+ *
+ * This instruction even it has its own Wikipedia entry.  The Wikipedia entry
+ * has been translated into 4 languages.  I am not making this up!
+ *
+ * We could get funky here and identify ourselves as "GenuineLguest", but
+ * instead we just use the real "cpuid" instruction.  Then I pretty much turned
+ * off feature bits until the Guest booted.  (Don't say that: you'll damage
+ * lguest sales!)  Shut up, inner voice!  (Hey, just pointing out that this is
+ * hardly future proof.)  Noone's listening!  They don't like you anyway,
+ * parenthetic weirdo!
+ *
+ * Replacing the cpuid so we can turn features off is great for the kernel, but
+ * anyone (including userspace) can just use the raw "cpuid" instruction and
+ * the Host won't even notice since it isn't privileged.  So we try not to get
+ * too worked up about it. */
+static void lguest_cpuid(unsigned int *eax, unsigned int *ebx,
+			 unsigned int *ecx, unsigned int *edx)
+{
+	int function = *eax;
+
+	native_cpuid(eax, ebx, ecx, edx);
+	switch (function) {
+	case 1:	/* Basic feature request. */
+		/* We only allow kernel to see SSE3, CMPXCHG16B and SSSE3 */
+		*ecx &= 0x00002201;
+		/* SSE, SSE2, FXSR, MMX, CMOV, CMPXCHG8B, FPU. */
+		*edx &= 0x07808101;
+		/* The Host can do a nice optimization if it knows that the
+		 * kernel mappings (addresses above 0xC0000000 or whatever
+		 * PAGE_OFFSET is set to) haven't changed.  But Linux calls
+		 * flush_tlb_user() for both user and kernel mappings unless
+		 * the Page Global Enable (PGE) feature bit is set. */
+		*edx |= 0x00002000;
+		break;
+	case 0x80000000:
+		/* Futureproof this a little: if they ask how much extended
+		 * processor information there is, limit it to known fields. */
+		if (*eax > 0x80000008)
+			*eax = 0x80000008;
+		break;
+	}
+}
+
+/* Intel has four control registers, imaginatively named cr0, cr2, cr3 and cr4.
+ * I assume there's a cr1, but it hasn't bothered us yet, so we'll not bother
+ * it.  The Host needs to know when the Guest wants to change them, so we have
+ * a whole series of functions like read_cr0() and write_cr0().
+ *
+ * We start with CR0.  CR0 allows you to turn on and off all kinds of basic
+ * features, but Linux only really cares about one: the horrifically-named Task
+ * Switched (TS) bit at bit 3 (ie. 8)
+ *
+ * What does the TS bit do?  Well, it causes the CPU to trap (interrupt 7) if
+ * the floating point unit is used.  Which allows us to restore FPU state
+ * lazily after a task switch, and Linux uses that gratefully, but wouldn't a
+ * name like "FPUTRAP bit" be a little less cryptic?
+ *
+ * We store cr0 (and cr3) locally, because the Host never changes it.  The
+ * Guest sometimes wants to read it and we'd prefer not to bother the Host
+ * unnecessarily. */
+static unsigned long current_cr0, current_cr3;
+static void lguest_write_cr0(unsigned long val)
+{
+	/* 8 == TS bit. */
+	lazy_hcall(LHCALL_TS, val & 8, 0, 0);
+	current_cr0 = val;
+}
+
+static unsigned long lguest_read_cr0(void)
+{
+	return current_cr0;
+}
+
+/* Intel provided a special instruction to clear the TS bit for people too cool
+ * to use write_cr0() to do it.  This "clts" instruction is faster, because all
+ * the vowels have been optimized out. */
+static void lguest_clts(void)
+{
+	lazy_hcall(LHCALL_TS, 0, 0, 0);
+	current_cr0 &= ~8U;
+}
+
+/* CR2 is the virtual address of the last page fault, which the Guest only ever
+ * reads.  The Host kindly writes this into our "struct lguest_data", so we
+ * just read it out of there. */
+static unsigned long lguest_read_cr2(void)
+{
+	return lguest_data.cr2;
+}
+
+/* CR3 is the current toplevel pagetable page: the principle is the same as
+ * cr0.  Keep a local copy, and tell the Host when it changes. */
+static void lguest_write_cr3(unsigned long cr3)
+{
+	lazy_hcall(LHCALL_NEW_PGTABLE, cr3, 0, 0);
+	current_cr3 = cr3;
+}
+
+static unsigned long lguest_read_cr3(void)
+{
+	return current_cr3;
+}
+
+/* CR4 is used to enable and disable PGE, but we don't care. */
+static unsigned long lguest_read_cr4(void)
+{
+	return 0;
+}
+
+static void lguest_write_cr4(unsigned long val)
+{
+}
+
+/*
+ * Page Table Handling.
+ *
+ * Now would be a good time to take a rest and grab a coffee or similarly
+ * relaxing stimulant.  The easy parts are behind us, and the trek gradually
+ * winds uphill from here.
+ *
+ * Quick refresher: memory is divided into "pages" of 4096 bytes each.  The CPU
+ * maps virtual addresses to physical addresses using "page tables".  We could
+ * use one huge index of 1 million entries: each address is 4 bytes, so that's
+ * 1024 pages just to hold the page tables.   But since most virtual addresses
+ * are unused, we use a two level index which saves space.  The CR3 register
+ * contains the physical address of the top level "page directory" page, which
+ * contains physical addresses of up to 1024 second-level pages.  Each of these
+ * second level pages contains up to 1024 physical addresses of actual pages,
+ * or Page Table Entries (PTEs).
+ *
+ * Here's a diagram, where arrows indicate physical addresses:
+ *
+ * CR3 ---> +---------+
+ *	    |  	   --------->+---------+
+ *	    |	      |	     | PADDR1  |
+ *	  Top-level   |	     | PADDR2  |
+ *	  (PMD) page  |	     | 	       |
+ *	    |	      |	   Lower-level |
+ *	    |	      |	   (PTE) page  |
+ *	    |	      |	     |	       |
+ *	      ....    	     	 ....
+ *
+ * So to convert a virtual address to a physical address, we look up the top
+ * level, which points us to the second level, which gives us the physical
+ * address of that page.  If the top level entry was not present, or the second
+ * level entry was not present, then the virtual address is invalid (we
+ * say "the page was not mapped").
+ *
+ * Put another way, a 32-bit virtual address is divided up like so:
+ *
+ *  1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ * |<---- 10 bits ---->|<---- 10 bits ---->|<------ 12 bits ------>|
+ *    Index into top     Index into second      Offset within page
+ *  page directory page    pagetable page
+ *
+ * The kernel spends a lot of time changing both the top-level page directory
+ * and lower-level pagetable pages.  The Guest doesn't know physical addresses,
+ * so while it maintains these page tables exactly like normal, it also needs
+ * to keep the Host informed whenever it makes a change: the Host will create
+ * the real page tables based on the Guests'.
+ */
+
+/* The Guest calls this to set a second-level entry (pte), ie. to map a page
+ * into a process' address space.  We set the entry then tell the Host the
+ * toplevel and address this corresponds to.  The Guest uses one pagetable per
+ * process, so we need to tell the Host which one we're changing (mm->pgd). */
+static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr,
+			      pte_t *ptep, pte_t pteval)
+{
+	*ptep = pteval;
+	lazy_hcall(LHCALL_SET_PTE, __pa(mm->pgd), addr, pteval.pte_low);
+}
+
+/* The Guest calls this to set a top-level entry.  Again, we set the entry then
+ * tell the Host which top-level page we changed, and the index of the entry we
+ * changed. */
+static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval)
+{
+	*pmdp = pmdval;
+	lazy_hcall(LHCALL_SET_PMD, __pa(pmdp)&PAGE_MASK,
+		   (__pa(pmdp)&(PAGE_SIZE-1))/4, 0);
+}
+
+/* There are a couple of legacy places where the kernel sets a PTE, but we
+ * don't know the top level any more.  This is useless for us, since we don't
+ * know which pagetable is changing or what address, so we just tell the Host
+ * to forget all of them.  Fortunately, this is very rare.
+ *
+ * ... except in early boot when the kernel sets up the initial pagetables,
+ * which makes booting astonishingly slow.  So we don't even tell the Host
+ * anything changed until we've done the first page table switch.
+ */
+static void lguest_set_pte(pte_t *ptep, pte_t pteval)
+{
+	*ptep = pteval;
+	/* Don't bother with hypercall before initial setup. */
+	if (current_cr3)
+		lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0);
+}
+
+/* Unfortunately for Lguest, the paravirt_ops for page tables were based on
+ * native page table operations.  On native hardware you can set a new page
+ * table entry whenever you want, but if you want to remove one you have to do
+ * a TLB flush (a TLB is a little cache of page table entries kept by the CPU).
+ *
+ * So the lguest_set_pte_at() and lguest_set_pmd() functions above are only
+ * called when a valid entry is written, not when it's removed (ie. marked not
+ * present).  Instead, this is where we come when the Guest wants to remove a
+ * page table entry: we tell the Host to set that entry to 0 (ie. the present
+ * bit is zero). */
+static void lguest_flush_tlb_single(unsigned long addr)
+{
+	/* Simply set it to zero: if it was not, it will fault back in. */
+	lazy_hcall(LHCALL_SET_PTE, current_cr3, addr, 0);
+}
+
+/* This is what happens after the Guest has removed a large number of entries.
+ * This tells the Host that any of the page table entries for userspace might
+ * have changed, ie. virtual addresses below PAGE_OFFSET. */
+static void lguest_flush_tlb_user(void)
+{
+	lazy_hcall(LHCALL_FLUSH_TLB, 0, 0, 0);
+}
+
+/* This is called when the kernel page tables have changed.  That's not very
+ * common (unless the Guest is using highmem, which makes the Guest extremely
+ * slow), so it's worth separating this from the user flushing above. */
+static void lguest_flush_tlb_kernel(void)
+{
+	lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0);
+}
+
+/*
+ * The Unadvanced Programmable Interrupt Controller.
+ *
+ * This is an attempt to implement the simplest possible interrupt controller.
+ * I spent some time looking though routines like set_irq_chip_and_handler,
+ * set_irq_chip_and_handler_name, set_irq_chip_data and set_phasers_to_stun and
+ * I *think* this is as simple as it gets.
+ *
+ * We can tell the Host what interrupts we want blocked ready for using the
+ * lguest_data.interrupts bitmap, so disabling (aka "masking") them is as
+ * simple as setting a bit.  We don't actually "ack" interrupts as such, we
+ * just mask and unmask them.  I wonder if we should be cleverer?
+ */
+static void disable_lguest_irq(unsigned int irq)
+{
+	set_bit(irq, lguest_data.blocked_interrupts);
+}
+
+static void enable_lguest_irq(unsigned int irq)
+{
+	clear_bit(irq, lguest_data.blocked_interrupts);
+}
+
+/* This structure describes the lguest IRQ controller. */
+static struct irq_chip lguest_irq_controller = {
+	.name		= "lguest",
+	.mask		= disable_lguest_irq,
+	.mask_ack	= disable_lguest_irq,
+	.unmask		= enable_lguest_irq,
+};
+
+/* This sets up the Interrupt Descriptor Table (IDT) entry for each hardware
+ * interrupt (except 128, which is used for system calls), and then tells the
+ * Linux infrastructure that each interrupt is controlled by our level-based
+ * lguest interrupt controller. */
+static void __init lguest_init_IRQ(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < LGUEST_IRQS; i++) {
+		int vector = FIRST_EXTERNAL_VECTOR + i;
+		if (vector != SYSCALL_VECTOR) {
+			set_intr_gate(vector, interrupt[i]);
+			set_irq_chip_and_handler(i, &lguest_irq_controller,
+						 handle_level_irq);
+		}
+	}
+	/* This call is required to set up for 4k stacks, where we have
+	 * separate stacks for hard and soft interrupts. */
+	irq_ctx_init(smp_processor_id());
+}
+
+/*
+ * Time.
+ *
+ * It would be far better for everyone if the Guest had its own clock, but
+ * until then the Host gives us the time on every interrupt.
+ */
+static unsigned long lguest_get_wallclock(void)
+{
+	return lguest_data.time.tv_sec;
+}
+
+static cycle_t lguest_clock_read(void)
+{
+	unsigned long sec, nsec;
+
+	/* If the Host tells the TSC speed, we can trust that. */
+	if (lguest_data.tsc_khz)
+		return native_read_tsc();
+
+	/* If we can't use the TSC, we read the time value written by the Host.
+	 * Since it's in two parts (seconds and nanoseconds), we risk reading
+	 * it just as it's changing from 99 & 0.999999999 to 100 and 0, and
+	 * getting 99 and 0.  As Linux tends to come apart under the stress of
+	 * time travel, we must be careful: */
+	do {
+		/* First we read the seconds part. */
+		sec = lguest_data.time.tv_sec;
+		/* This read memory barrier tells the compiler and the CPU that
+		 * this can't be reordered: we have to complete the above
+		 * before going on. */
+		rmb();
+		/* Now we read the nanoseconds part. */
+		nsec = lguest_data.time.tv_nsec;
+		/* Make sure we've done that. */
+		rmb();
+		/* Now if the seconds part has changed, try again. */
+	} while (unlikely(lguest_data.time.tv_sec != sec));
+
+	/* Our non-TSC clock is in real nanoseconds. */
+	return sec*1000000000ULL + nsec;
+}
+
+/* This is what we tell the kernel is our clocksource.  */
+static struct clocksource lguest_clock = {
+	.name		= "lguest",
+	.rating		= 400,
+	.read		= lguest_clock_read,
+	.mask		= CLOCKSOURCE_MASK(64),
+	.mult		= 1 << 22,
+	.shift		= 22,
+};
+
+/* The "scheduler clock" is just our real clock, adjusted to start at zero */
+static unsigned long long lguest_sched_clock(void)
+{
+	return cyc2ns(&lguest_clock, lguest_clock_read() - clock_base);
+}
+
+/* We also need a "struct clock_event_device": Linux asks us to set it to go
+ * off some time in the future.  Actually, James Morris figured all this out, I
+ * just applied the patch. */
+static int lguest_clockevent_set_next_event(unsigned long delta,
+                                           struct clock_event_device *evt)
+{
+	if (delta < LG_CLOCK_MIN_DELTA) {
+		if (printk_ratelimit())
+			printk(KERN_DEBUG "%s: small delta %lu ns\n",
+			       __FUNCTION__, delta);
+		return -ETIME;
+	}
+	hcall(LHCALL_SET_CLOCKEVENT, delta, 0, 0);
+	return 0;
+}
+
+static void lguest_clockevent_set_mode(enum clock_event_mode mode,
+                                      struct clock_event_device *evt)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		/* A 0 argument shuts the clock down. */
+		hcall(LHCALL_SET_CLOCKEVENT, 0, 0, 0);
+		break;
+	case CLOCK_EVT_MODE_ONESHOT:
+		/* This is what we expect. */
+		break;
+	case CLOCK_EVT_MODE_PERIODIC:
+		BUG();
+	case CLOCK_EVT_MODE_RESUME:
+		break;
+	}
+}
+
+/* This describes our primitive timer chip. */
+static struct clock_event_device lguest_clockevent = {
+	.name                   = "lguest",
+	.features               = CLOCK_EVT_FEAT_ONESHOT,
+	.set_next_event         = lguest_clockevent_set_next_event,
+	.set_mode               = lguest_clockevent_set_mode,
+	.rating                 = INT_MAX,
+	.mult                   = 1,
+	.shift                  = 0,
+	.min_delta_ns           = LG_CLOCK_MIN_DELTA,
+	.max_delta_ns           = LG_CLOCK_MAX_DELTA,
+};
+
+/* This is the Guest timer interrupt handler (hardware interrupt 0).  We just
+ * call the clockevent infrastructure and it does whatever needs doing. */
+static void lguest_time_irq(unsigned int irq, struct irq_desc *desc)
+{
+	unsigned long flags;
+
+	/* Don't interrupt us while this is running. */
+	local_irq_save(flags);
+	lguest_clockevent.event_handler(&lguest_clockevent);
+	local_irq_restore(flags);
+}
+
+/* At some point in the boot process, we get asked to set up our timing
+ * infrastructure.  The kernel doesn't expect timer interrupts before this, but
+ * we cleverly initialized the "blocked_interrupts" field of "struct
+ * lguest_data" so that timer interrupts were blocked until now. */
+static void lguest_time_init(void)
+{
+	/* Set up the timer interrupt (0) to go to our simple timer routine */
+	set_irq_handler(0, lguest_time_irq);
+
+	/* Our clock structure look like arch/i386/kernel/tsc.c if we can use
+	 * the TSC, otherwise it's a dumb nanosecond-resolution clock.  Either
+	 * way, the "rating" is initialized so high that it's always chosen
+	 * over any other clocksource. */
+	if (lguest_data.tsc_khz) {
+		lguest_clock.mult = clocksource_khz2mult(lguest_data.tsc_khz,
+							 lguest_clock.shift);
+		lguest_clock.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+	}
+	clock_base = lguest_clock_read();
+	clocksource_register(&lguest_clock);
+
+	/* Now we've set up our clock, we can use it as the scheduler clock */
+	paravirt_ops.sched_clock = lguest_sched_clock;
+
+	/* We can't set cpumask in the initializer: damn C limitations!  Set it
+	 * here and register our timer device. */
+	lguest_clockevent.cpumask = cpumask_of_cpu(0);
+	clockevents_register_device(&lguest_clockevent);
+
+	/* Finally, we unblock the timer interrupt. */
+	enable_lguest_irq(0);
+}
+
+/*
+ * Miscellaneous bits and pieces.
+ *
+ * Here is an oddball collection of functions which the Guest needs for things
+ * to work.  They're pretty simple.
+ */
+
+/* The Guest needs to tell the host what stack it expects traps to use.  For
+ * native hardware, this is part of the Task State Segment mentioned above in
+ * lguest_load_tr_desc(), but to help hypervisors there's this special call.
+ *
+ * We tell the Host the segment we want to use (__KERNEL_DS is the kernel data
+ * segment), the privilege level (we're privilege level 1, the Host is 0 and
+ * will not tolerate us trying to use that), the stack pointer, and the number
+ * of pages in the stack. */
+static void lguest_load_esp0(struct tss_struct *tss,
+				     struct thread_struct *thread)
+{
+	lazy_hcall(LHCALL_SET_STACK, __KERNEL_DS|0x1, thread->esp0,
+		   THREAD_SIZE/PAGE_SIZE);
+}
+
+/* Let's just say, I wouldn't do debugging under a Guest. */
+static void lguest_set_debugreg(int regno, unsigned long value)
+{
+	/* FIXME: Implement */
+}
+
+/* There are times when the kernel wants to make sure that no memory writes are
+ * caught in the cache (that they've all reached real hardware devices).  This
+ * doesn't matter for the Guest which has virtual hardware.
+ *
+ * On the Pentium 4 and above, cpuid() indicates that the Cache Line Flush
+ * (clflush) instruction is available and the kernel uses that.  Otherwise, it
+ * uses the older "Write Back and Invalidate Cache" (wbinvd) instruction.
+ * Unlike clflush, wbinvd can only be run at privilege level 0.  So we can
+ * ignore clflush, but replace wbinvd.
+ */
+static void lguest_wbinvd(void)
+{
+}
+
+/* If the Guest expects to have an Advanced Programmable Interrupt Controller,
+ * we play dumb by ignoring writes and returning 0 for reads.  So it's no
+ * longer Programmable nor Controlling anything, and I don't think 8 lines of
+ * code qualifies for Advanced.  It will also never interrupt anything.  It
+ * does, however, allow us to get through the Linux boot code. */
+#ifdef CONFIG_X86_LOCAL_APIC
+static void lguest_apic_write(unsigned long reg, unsigned long v)
+{
+}
+
+static unsigned long lguest_apic_read(unsigned long reg)
+{
+	return 0;
+}
+#endif
+
+/* STOP!  Until an interrupt comes in. */
+static void lguest_safe_halt(void)
+{
+	hcall(LHCALL_HALT, 0, 0, 0);
+}
+
+/* Perhaps CRASH isn't the best name for this hypercall, but we use it to get a
+ * message out when we're crashing as well as elegant termination like powering
+ * off.
+ *
+ * Note that the Host always prefers that the Guest speak in physical addresses
+ * rather than virtual addresses, so we use __pa() here. */
+static void lguest_power_off(void)
+{
+	hcall(LHCALL_CRASH, __pa("Power down"), 0, 0);
+}
+
+/*
+ * Panicing.
+ *
+ * Don't.  But if you did, this is what happens.
+ */
+static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p)
+{
+	hcall(LHCALL_CRASH, __pa(p), 0, 0);
+	/* The hcall won't return, but to keep gcc happy, we're "done". */
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block paniced = {
+	.notifier_call = lguest_panic
+};
+
+/* Setting up memory is fairly easy. */
+static __init char *lguest_memory_setup(void)
+{
+	/* We do this here and not earlier because lockcheck barfs if we do it
+	 * before start_kernel() */
+	atomic_notifier_chain_register(&panic_notifier_list, &paniced);
+
+	/* The Linux bootloader header contains an "e820" memory map: the
+	 * Launcher populated the first entry with our memory limit. */
+	add_memory_region(E820_MAP->addr, E820_MAP->size, E820_MAP->type);
+
+	/* This string is for the boot messages. */
+	return "LGUEST";
+}
+
+/*G:050
+ * Patching (Powerfully Placating Performance Pedants)
+ *
+ * We have already seen that "struct paravirt_ops" lets us replace simple
+ * native instructions with calls to the appropriate back end all throughout
+ * the kernel.  This allows the same kernel to run as a Guest and as a native
+ * kernel, but it's slow because of all the indirect branches.
+ *
+ * Remember that David Wheeler quote about "Any problem in computer science can
+ * be solved with another layer of indirection"?  The rest of that quote is
+ * "... But that usually will create another problem."  This is the first of
+ * those problems.
+ *
+ * Our current solution is to allow the paravirt back end to optionally patch
+ * over the indirect calls to replace them with something more efficient.  We
+ * patch the four most commonly called functions: disable interrupts, enable
+ * interrupts, restore interrupts and save interrupts.  We usually have 10
+ * bytes to patch into: the Guest versions of these operations are small enough
+ * that we can fit comfortably.
+ *
+ * First we need assembly templates of each of the patchable Guest operations,
+ * and these are in lguest_asm.S. */
+
+/*G:060 We construct a table from the assembler templates: */
+static const struct lguest_insns
+{
+	const char *start, *end;
+} lguest_insns[] = {
+	[PARAVIRT_PATCH(irq_disable)] = { lgstart_cli, lgend_cli },
+	[PARAVIRT_PATCH(irq_enable)] = { lgstart_sti, lgend_sti },
+	[PARAVIRT_PATCH(restore_fl)] = { lgstart_popf, lgend_popf },
+	[PARAVIRT_PATCH(save_fl)] = { lgstart_pushf, lgend_pushf },
+};
+
+/* Now our patch routine is fairly simple (based on the native one in
+ * paravirt.c).  If we have a replacement, we copy it in and return how much of
+ * the available space we used. */
+static unsigned lguest_patch(u8 type, u16 clobber, void *ibuf,
+			     unsigned long addr, unsigned len)
+{
+	unsigned int insn_len;
+
+	/* Don't do anything special if we don't have a replacement */
+	if (type >= ARRAY_SIZE(lguest_insns) || !lguest_insns[type].start)
+		return paravirt_patch_default(type, clobber, ibuf, addr, len);
+
+	insn_len = lguest_insns[type].end - lguest_insns[type].start;
+
+	/* Similarly if we can't fit replacement (shouldn't happen, but let's
+	 * be thorough). */
+	if (len < insn_len)
+		return paravirt_patch_default(type, clobber, ibuf, addr, len);
+
+	/* Copy in our instructions. */
+	memcpy(ibuf, lguest_insns[type].start, insn_len);
+	return insn_len;
+}
+
+/*G:030 Once we get to lguest_init(), we know we're a Guest.  The paravirt_ops
+ * structure in the kernel provides a single point for (almost) every routine
+ * we have to override to avoid privileged instructions. */
+__init void lguest_init(void *boot)
+{
+	/* Copy boot parameters first: the Launcher put the physical location
+	 * in %esi, and head.S converted that to a virtual address and handed
+	 * it to us.  We use "__memcpy" because "memcpy" sometimes tries to do
+	 * tricky things to go faster, and we're not ready for that. */
+	__memcpy(&boot_params, boot, PARAM_SIZE);
+	/* The boot parameters also tell us where the command-line is: save
+	 * that, too. */
+	__memcpy(boot_command_line, __va(boot_params.hdr.cmd_line_ptr),
+	       COMMAND_LINE_SIZE);
+
+	/* We're under lguest, paravirt is enabled, and we're running at
+	 * privilege level 1, not 0 as normal. */
+	paravirt_ops.name = "lguest";
+	paravirt_ops.paravirt_enabled = 1;
+	paravirt_ops.kernel_rpl = 1;
+
+	/* We set up all the lguest overrides for sensitive operations.  These
+	 * are detailed with the operations themselves. */
+	paravirt_ops.save_fl = save_fl;
+	paravirt_ops.restore_fl = restore_fl;
+	paravirt_ops.irq_disable = irq_disable;
+	paravirt_ops.irq_enable = irq_enable;
+	paravirt_ops.load_gdt = lguest_load_gdt;
+	paravirt_ops.memory_setup = lguest_memory_setup;
+	paravirt_ops.cpuid = lguest_cpuid;
+	paravirt_ops.write_cr3 = lguest_write_cr3;
+	paravirt_ops.flush_tlb_user = lguest_flush_tlb_user;
+	paravirt_ops.flush_tlb_single = lguest_flush_tlb_single;
+	paravirt_ops.flush_tlb_kernel = lguest_flush_tlb_kernel;
+	paravirt_ops.set_pte = lguest_set_pte;
+	paravirt_ops.set_pte_at = lguest_set_pte_at;
+	paravirt_ops.set_pmd = lguest_set_pmd;
+#ifdef CONFIG_X86_LOCAL_APIC
+	paravirt_ops.apic_write = lguest_apic_write;
+	paravirt_ops.apic_write_atomic = lguest_apic_write;
+	paravirt_ops.apic_read = lguest_apic_read;
+#endif
+	paravirt_ops.load_idt = lguest_load_idt;
+	paravirt_ops.iret = lguest_iret;
+	paravirt_ops.load_esp0 = lguest_load_esp0;
+	paravirt_ops.load_tr_desc = lguest_load_tr_desc;
+	paravirt_ops.set_ldt = lguest_set_ldt;
+	paravirt_ops.load_tls = lguest_load_tls;
+	paravirt_ops.set_debugreg = lguest_set_debugreg;
+	paravirt_ops.clts = lguest_clts;
+	paravirt_ops.read_cr0 = lguest_read_cr0;
+	paravirt_ops.write_cr0 = lguest_write_cr0;
+	paravirt_ops.init_IRQ = lguest_init_IRQ;
+	paravirt_ops.read_cr2 = lguest_read_cr2;
+	paravirt_ops.read_cr3 = lguest_read_cr3;
+	paravirt_ops.read_cr4 = lguest_read_cr4;
+	paravirt_ops.write_cr4 = lguest_write_cr4;
+	paravirt_ops.write_gdt_entry = lguest_write_gdt_entry;
+	paravirt_ops.write_idt_entry = lguest_write_idt_entry;
+	paravirt_ops.patch = lguest_patch;
+	paravirt_ops.safe_halt = lguest_safe_halt;
+	paravirt_ops.get_wallclock = lguest_get_wallclock;
+	paravirt_ops.time_init = lguest_time_init;
+	paravirt_ops.set_lazy_mode = lguest_lazy_mode;
+	paravirt_ops.wbinvd = lguest_wbinvd;
+	/* Now is a good time to look at the implementations of these functions
+	 * before returning to the rest of lguest_init(). */
+
+	/*G:070 Now we've seen all the paravirt_ops, we return to
+	 * lguest_init() where the rest of the fairly chaotic boot setup
+	 * occurs.
+	 *
+	 * The Host expects our first hypercall to tell it where our "struct
+	 * lguest_data" is, so we do that first. */
+	hcall(LHCALL_LGUEST_INIT, __pa(&lguest_data), 0, 0);
+
+	/* The native boot code sets up initial page tables immediately after
+	 * the kernel itself, and sets init_pg_tables_end so they're not
+	 * clobbered.  The Launcher places our initial pagetables somewhere at
+	 * the top of our physical memory, so we don't need extra space: set
+	 * init_pg_tables_end to the end of the kernel. */
+	init_pg_tables_end = __pa(pg0);
+
+	/* Load the %fs segment register (the per-cpu segment register) with
+	 * the normal data segment to get through booting. */
+	asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_DS) : "memory");
+
+	/* Clear the part of the kernel data which is expected to be zero.
+	 * Normally it will be anyway, but if we're loading from a bzImage with
+	 * CONFIG_RELOCATALE=y, the relocations will be sitting here. */
+	memset(__bss_start, 0, __bss_stop - __bss_start);
+
+	/* The Host uses the top of the Guest's virtual address space for the
+	 * Host<->Guest Switcher, and it tells us how much it needs in
+	 * lguest_data.reserve_mem, set up on the LGUEST_INIT hypercall. */
+	reserve_top_address(lguest_data.reserve_mem);
+
+	/* If we don't initialize the lock dependency checker now, it crashes
+	 * paravirt_disable_iospace. */
+	lockdep_init();
+
+	/* The IDE code spends about 3 seconds probing for disks: if we reserve
+	 * all the I/O ports up front it can't get them and so doesn't probe.
+	 * Other device drivers are similar (but less severe).  This cuts the
+	 * kernel boot time on my machine from 4.1 seconds to 0.45 seconds. */
+	paravirt_disable_iospace();
+
+	/* This is messy CPU setup stuff which the native boot code does before
+	 * start_kernel, so we have to do, too: */
+	cpu_detect(&new_cpu_data);
+	/* head.S usually sets up the first capability word, so do it here. */
+	new_cpu_data.x86_capability[0] = cpuid_edx(1);
+
+	/* Math is always hard! */
+	new_cpu_data.hard_math = 1;
+
+#ifdef CONFIG_X86_MCE
+	mce_disabled = 1;
+#endif
+#ifdef CONFIG_ACPI
+	acpi_disabled = 1;
+	acpi_ht = 0;
+#endif
+
+	/* We set the perferred console to "hvc".  This is the "hypervisor
+	 * virtual console" driver written by the PowerPC people, which we also
+	 * adapted for lguest's use. */
+	add_preferred_console("hvc", 0, NULL);
+
+	/* Last of all, we set the power management poweroff hook to point to
+	 * the Guest routine to power off. */
+	pm_power_off = lguest_power_off;
+
+	/* Now we're set up, call start_kernel() in init/main.c and we proceed
+	 * to boot as normal.  It never returns. */
+	start_kernel();
+}
+/*
+ * This marks the end of stage II of our journey, The Guest.
+ *
+ * It is now time for us to explore the nooks and crannies of the three Guest
+ * devices and complete our understanding of the Guest in "make Drivers".
+ */
diff --git a/drivers/lguest/lguest_asm.S b/drivers/lguest/lguest_asm.S
new file mode 100644
index 0000000..1ddcd5c
--- /dev/null
+++ b/drivers/lguest/lguest_asm.S
@@ -0,0 +1,93 @@
+#include <linux/linkage.h>
+#include <linux/lguest.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+#include <asm/processor-flags.h>
+
+/*G:020 This is where we begin: we have a magic signature which the launcher
+ * looks for.  The plan is that the Linux boot protocol will be extended with a
+ * "platform type" field which will guide us here from the normal entry point,
+ * but for the moment this suffices.  The normal boot code uses %esi for the
+ * boot header, so we do too.  We convert it to a virtual address by adding
+ * PAGE_OFFSET, and hand it to lguest_init() as its argument (ie. %eax).
+ *
+ * The .section line puts this code in .init.text so it will be discarded after
+ * boot. */
+.section .init.text, "ax", @progbits
+.ascii "GenuineLguest"
+	/* Set up initial stack. */
+ 	movl $(init_thread_union+THREAD_SIZE),%esp
+	movl %esi, %eax
+	addl $__PAGE_OFFSET, %eax
+	jmp lguest_init
+
+/*G:055 We create a macro which puts the assembler code between lgstart_ and
+ * lgend_ markers.  These templates are put in the .text section: they can't be
+ * discarded after boot as we may need to patch modules, too. */
+.text
+#define LGUEST_PATCH(name, insns...)			\
+	lgstart_##name:	insns; lgend_##name:;		\
+	.globl lgstart_##name; .globl lgend_##name
+
+LGUEST_PATCH(cli, movl $0, lguest_data+LGUEST_DATA_irq_enabled)
+LGUEST_PATCH(sti, movl $X86_EFLAGS_IF, lguest_data+LGUEST_DATA_irq_enabled)
+LGUEST_PATCH(popf, movl %eax, lguest_data+LGUEST_DATA_irq_enabled)
+LGUEST_PATCH(pushf, movl lguest_data+LGUEST_DATA_irq_enabled, %eax)
+/*:*/
+
+/* These demark the EIP range where host should never deliver interrupts. */
+.global lguest_noirq_start
+.global lguest_noirq_end
+
+/*M:004 When the Host reflects a trap or injects an interrupt into the Guest,
+ * it sets the eflags interrupt bit on the stack based on
+ * lguest_data.irq_enabled, so the Guest iret logic does the right thing when
+ * restoring it.  However, when the Host sets the Guest up for direct traps,
+ * such as system calls, the processor is the one to push eflags onto the
+ * stack, and the interrupt bit will be 1 (in reality, interrupts are always
+ * enabled in the Guest).
+ *
+ * This turns out to be harmless: the only trap which should happen under Linux
+ * with interrupts disabled is Page Fault (due to our lazy mapping of vmalloc
+ * regions), which has to be reflected through the Host anyway.  If another
+ * trap *does* go off when interrupts are disabled, the Guest will panic, and
+ * we'll never get to this iret! :*/
+
+/*G:045 There is one final paravirt_op that the Guest implements, and glancing
+ * at it you can see why I left it to last.  It's *cool*!  It's in *assembler*!
+ *
+ * The "iret" instruction is used to return from an interrupt or trap.  The
+ * stack looks like this:
+ *   old address
+ *   old code segment & privilege level
+ *   old processor flags ("eflags")
+ *
+ * The "iret" instruction pops those values off the stack and restores them all
+ * at once.  The only problem is that eflags includes the Interrupt Flag which
+ * the Guest can't change: the CPU will simply ignore it when we do an "iret".
+ * So we have to copy eflags from the stack to lguest_data.irq_enabled before
+ * we do the "iret".
+ *
+ * There are two problems with this: firstly, we need to use a register to do
+ * the copy and secondly, the whole thing needs to be atomic.  The first
+ * problem is easy to solve: push %eax on the stack so we can use it, and then
+ * restore it at the end just before the real "iret".
+ *
+ * The second is harder: copying eflags to lguest_data.irq_enabled will turn
+ * interrupts on before we're finished, so we could be interrupted before we
+ * return to userspace or wherever.  Our solution to this is to surround the
+ * code with lguest_noirq_start: and lguest_noirq_end: labels.  We tell the
+ * Host that it is *never* to interrupt us there, even if interrupts seem to be
+ * enabled. */
+ENTRY(lguest_iret)
+	pushl	%eax
+	movl	12(%esp), %eax
+lguest_noirq_start:
+	/* Note the %ss: segment prefix here.  Normal data accesses use the
+	 * "ds" segment, but that will have already been restored for whatever
+	 * we're returning to (such as userspace): we can't trust it.  The %ss:
+	 * prefix makes sure we use the stack segment, which is still valid. */
+	movl	%eax,%ss:lguest_data+LGUEST_DATA_irq_enabled
+	popl	%eax
+	iret
+lguest_noirq_end:
diff --git a/drivers/lguest/lguest_bus.c b/drivers/lguest/lguest_bus.c
new file mode 100644
index 0000000..9e7752c
--- /dev/null
+++ b/drivers/lguest/lguest_bus.c
@@ -0,0 +1,218 @@
+/*P:050 Lguest guests use a very simple bus for devices.  It's a simple array
+ * of device descriptors contained just above the top of normal memory.  The
+ * lguest bus is 80% tedious boilerplate code. :*/
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/lguest_bus.h>
+#include <asm/io.h>
+#include <asm/paravirt.h>
+
+static ssize_t type_show(struct device *_dev,
+                         struct device_attribute *attr, char *buf)
+{
+	struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+	return sprintf(buf, "%hu", lguest_devices[dev->index].type);
+}
+static ssize_t features_show(struct device *_dev,
+                             struct device_attribute *attr, char *buf)
+{
+	struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+	return sprintf(buf, "%hx", lguest_devices[dev->index].features);
+}
+static ssize_t pfn_show(struct device *_dev,
+			 struct device_attribute *attr, char *buf)
+{
+	struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+	return sprintf(buf, "%u", lguest_devices[dev->index].pfn);
+}
+static ssize_t status_show(struct device *_dev,
+                           struct device_attribute *attr, char *buf)
+{
+	struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+	return sprintf(buf, "%hx", lguest_devices[dev->index].status);
+}
+static ssize_t status_store(struct device *_dev, struct device_attribute *attr,
+                            const char *buf, size_t count)
+{
+	struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+	if (sscanf(buf, "%hi", &lguest_devices[dev->index].status) != 1)
+		return -EINVAL;
+	return count;
+}
+static struct device_attribute lguest_dev_attrs[] = {
+	__ATTR_RO(type),
+	__ATTR_RO(features),
+	__ATTR_RO(pfn),
+	__ATTR(status, 0644, status_show, status_store),
+	__ATTR_NULL
+};
+
+/*D:130 The generic bus infrastructure requires a function which says whether a
+ * device matches a driver.  For us, it is simple: "struct lguest_driver"
+ * contains a "device_type" field which indicates what type of device it can
+ * handle, so we just cast the args and compare: */
+static int lguest_dev_match(struct device *_dev, struct device_driver *_drv)
+{
+	struct lguest_device *dev = container_of(_dev,struct lguest_device,dev);
+	struct lguest_driver *drv = container_of(_drv,struct lguest_driver,drv);
+
+	return (drv->device_type == lguest_devices[dev->index].type);
+}
+/*:*/
+
+struct lguest_bus {
+	struct bus_type bus;
+	struct device dev;
+};
+
+static struct lguest_bus lguest_bus = {
+	.bus = {
+		.name  = "lguest",
+		.match = lguest_dev_match,
+		.dev_attrs = lguest_dev_attrs,
+	},
+	.dev = {
+		.parent = NULL,
+		.bus_id = "lguest",
+	}
+};
+
+/*D:140 This is the callback which occurs once the bus infrastructure matches
+ * up a device and driver, ie. in response to add_lguest_device() calling
+ * device_register(), or register_lguest_driver() calling driver_register().
+ *
+ * At the moment it's always the latter: the devices are added first, since
+ * scan_devices() is called from a "core_initcall", and the drivers themselves
+ * called later as a normal "initcall".  But it would work the other way too.
+ *
+ * So now we have the happy couple, we add the status bit to indicate that we
+ * found a driver.  If the driver truly loves the device, it will return
+ * happiness from its probe function (ok, perhaps this wasn't my greatest
+ * analogy), and we set the final "driver ok" bit so the Host sees it's all
+ * green. */
+static int lguest_dev_probe(struct device *_dev)
+{
+	int ret;
+	struct lguest_device*dev = container_of(_dev,struct lguest_device,dev);
+	struct lguest_driver*drv = container_of(dev->dev.driver,
+						struct lguest_driver, drv);
+
+	lguest_devices[dev->index].status |= LGUEST_DEVICE_S_DRIVER;
+	ret = drv->probe(dev);
+	if (ret == 0)
+		lguest_devices[dev->index].status |= LGUEST_DEVICE_S_DRIVER_OK;
+	return ret;
+}
+
+/* The last part of the bus infrastructure is the function lguest drivers use
+ * to register themselves.  Firstly, we do nothing if there's no lguest bus
+ * (ie. this is not a Guest), otherwise we fill in the embedded generic "struct
+ * driver" fields and call the generic driver_register(). */
+int register_lguest_driver(struct lguest_driver *drv)
+{
+	if (!lguest_devices)
+		return 0;
+
+	drv->drv.bus = &lguest_bus.bus;
+	drv->drv.name = drv->name;
+	drv->drv.owner = drv->owner;
+	drv->drv.probe = lguest_dev_probe;
+
+	return driver_register(&drv->drv);
+}
+
+/* At the moment we build all the drivers into the kernel because they're so
+ * simple: 8144 bytes for all three of them as I type this.  And as the console
+ * really needs to be built in, it's actually only 3527 bytes for the network
+ * and block drivers.
+ *
+ * If they get complex it will make sense for them to be modularized, so we
+ * need to explicitly export the symbol.
+ *
+ * I don't think non-GPL modules make sense, so it's a GPL-only export.
+ */
+EXPORT_SYMBOL_GPL(register_lguest_driver);
+
+/*D:120 This is the core of the lguest bus: actually adding a new device.
+ * It's a separate function because it's neater that way, and because an
+ * earlier version of the code supported hotplug and unplug.  They were removed
+ * early on because they were never used.
+ *
+ * As Andrew Tridgell says, "Untested code is buggy code".
+ *
+ * It's worth reading this carefully: we start with an index into the array of
+ * "struct lguest_device_desc"s indicating the device which is new: */
+static void add_lguest_device(unsigned int index)
+{
+	struct lguest_device *new;
+
+	/* Each "struct lguest_device_desc" has a "status" field, which the
+	 * Guest updates as the device is probed.  In the worst case, the Host
+	 * can look at these bits to tell what part of device setup failed,
+	 * even if the console isn't available. */
+	lguest_devices[index].status |= LGUEST_DEVICE_S_ACKNOWLEDGE;
+	new = kmalloc(sizeof(struct lguest_device), GFP_KERNEL);
+	if (!new) {
+		printk(KERN_EMERG "Cannot allocate lguest device %u\n", index);
+		lguest_devices[index].status |= LGUEST_DEVICE_S_FAILED;
+		return;
+	}
+
+	/* The "struct lguest_device" setup is pretty straight-forward example
+	 * code. */
+	new->index = index;
+	new->private = NULL;
+	memset(&new->dev, 0, sizeof(new->dev));
+	new->dev.parent = &lguest_bus.dev;
+	new->dev.bus = &lguest_bus.bus;
+	sprintf(new->dev.bus_id, "%u", index);
+
+	/* device_register() causes the bus infrastructure to look for a
+	 * matching driver. */
+	if (device_register(&new->dev) != 0) {
+		printk(KERN_EMERG "Cannot register lguest device %u\n", index);
+		lguest_devices[index].status |= LGUEST_DEVICE_S_FAILED;
+		kfree(new);
+	}
+}
+
+/*D:110 scan_devices() simply iterates through the device array.  The type 0
+ * is reserved to mean "no device", and anything else means we have found a
+ * device: add it. */
+static void scan_devices(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < LGUEST_MAX_DEVICES; i++)
+		if (lguest_devices[i].type)
+			add_lguest_device(i);
+}
+
+/*D:100 Fairly early in boot, lguest_bus_init() is called to set up the lguest
+ * bus.  We check that we are a Guest by checking paravirt_ops.name: there are
+ * other ways of checking, but this seems most obvious to me.
+ *
+ * So we can access the array of "struct lguest_device_desc"s easily, we map
+ * that memory and store the pointer in the global "lguest_devices".  Then we
+ * register the bus with the core.  Doing two registrations seems clunky to me,
+ * but it seems to be the correct sysfs incantation.
+ *
+ * Finally we call scan_devices() which adds all the devices found in the
+ * "struct lguest_device_desc" array. */
+static int __init lguest_bus_init(void)
+{
+	if (strcmp(paravirt_ops.name, "lguest") != 0)
+		return 0;
+
+	/* Devices are in a single page above top of "normal" mem */
+	lguest_devices = lguest_map(max_pfn<<PAGE_SHIFT, 1);
+
+	if (bus_register(&lguest_bus.bus) != 0
+	    || device_register(&lguest_bus.dev) != 0)
+		panic("lguest bus registration failed");
+
+	scan_devices();
+	return 0;
+}
+/* Do this after core stuff, before devices. */
+postcore_initcall(lguest_bus_init);
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
new file mode 100644
index 0000000..80d1b58
--- /dev/null
+++ b/drivers/lguest/lguest_user.c
@@ -0,0 +1,382 @@
+/*P:200 This contains all the /dev/lguest code, whereby the userspace launcher
+ * controls and communicates with the Guest.  For example, the first write will
+ * tell us the memory size, pagetable, entry point and kernel address offset.
+ * A read will run the Guest until a signal is pending (-EINTR), or the Guest
+ * does a DMA out to the Launcher.  Writes are also used to get a DMA buffer
+ * registered by the Guest and to send the Guest an interrupt. :*/
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include "lg.h"
+
+/*L:030 setup_regs() doesn't really belong in this file, but it gives us an
+ * early glimpse deeper into the Host so it's worth having here.
+ *
+ * Most of the Guest's registers are left alone: we used get_zeroed_page() to
+ * allocate the structure, so they will be 0. */
+static void setup_regs(struct lguest_regs *regs, unsigned long start)
+{
+	/* There are four "segment" registers which the Guest needs to boot:
+	 * The "code segment" register (cs) refers to the kernel code segment
+	 * __KERNEL_CS, and the "data", "extra" and "stack" segment registers
+	 * refer to the kernel data segment __KERNEL_DS.
+	 *
+	 * The privilege level is packed into the lower bits.  The Guest runs
+	 * at privilege level 1 (GUEST_PL).*/
+	regs->ds = regs->es = regs->ss = __KERNEL_DS|GUEST_PL;
+	regs->cs = __KERNEL_CS|GUEST_PL;
+
+	/* The "eflags" register contains miscellaneous flags.  Bit 1 (0x002)
+	 * is supposed to always be "1".  Bit 9 (0x200) controls whether
+	 * interrupts are enabled.  We always leave interrupts enabled while
+	 * running the Guest. */
+	regs->eflags = 0x202;
+
+	/* The "Extended Instruction Pointer" register says where the Guest is
+	 * running. */
+	regs->eip = start;
+
+	/* %esi points to our boot information, at physical address 0, so don't
+	 * touch it. */
+}
+
+/*L:310 To send DMA into the Guest, the Launcher needs to be able to ask for a
+ * DMA buffer.  This is done by writing LHREQ_GETDMA and the key to
+ * /dev/lguest. */
+static long user_get_dma(struct lguest *lg, const u32 __user *input)
+{
+	unsigned long key, udma, irq;
+
+	/* Fetch the key they wrote to us. */
+	if (get_user(key, input) != 0)
+		return -EFAULT;
+	/* Look for a free Guest DMA buffer bound to that key. */
+	udma = get_dma_buffer(lg, key, &irq);
+	if (!udma)
+		return -ENOENT;
+
+	/* We need to tell the Launcher what interrupt the Guest expects after
+	 * the buffer is filled.  We stash it in udma->used_len. */
+	lgwrite_u32(lg, udma + offsetof(struct lguest_dma, used_len), irq);
+
+	/* The (guest-physical) address of the DMA buffer is returned from
+	 * the write(). */
+	return udma;
+}
+
+/*L:315 To force the Guest to stop running and return to the Launcher, the
+ * Waker sets writes LHREQ_BREAK and the value "1" to /dev/lguest.  The
+ * Launcher then writes LHREQ_BREAK and "0" to release the Waker. */
+static int break_guest_out(struct lguest *lg, const u32 __user *input)
+{
+	unsigned long on;
+
+	/* Fetch whether they're turning break on or off.. */
+	if (get_user(on, input) != 0)
+		return -EFAULT;
+
+	if (on) {
+		lg->break_out = 1;
+		/* Pop it out (may be running on different CPU) */
+		wake_up_process(lg->tsk);
+		/* Wait for them to reset it */
+		return wait_event_interruptible(lg->break_wq, !lg->break_out);
+	} else {
+		lg->break_out = 0;
+		wake_up(&lg->break_wq);
+		return 0;
+	}
+}
+
+/*L:050 Sending an interrupt is done by writing LHREQ_IRQ and an interrupt
+ * number to /dev/lguest. */
+static int user_send_irq(struct lguest *lg, const u32 __user *input)
+{
+	u32 irq;
+
+	if (get_user(irq, input) != 0)
+		return -EFAULT;
+	if (irq >= LGUEST_IRQS)
+		return -EINVAL;
+	/* Next time the Guest runs, the core code will see if it can deliver
+	 * this interrupt. */
+	set_bit(irq, lg->irqs_pending);
+	return 0;
+}
+
+/*L:040 Once our Guest is initialized, the Launcher makes it run by reading
+ * from /dev/lguest. */
+static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
+{
+	struct lguest *lg = file->private_data;
+
+	/* You must write LHREQ_INITIALIZE first! */
+	if (!lg)
+		return -EINVAL;
+
+	/* If you're not the task which owns the guest, go away. */
+	if (current != lg->tsk)
+		return -EPERM;
+
+	/* If the guest is already dead, we indicate why */
+	if (lg->dead) {
+		size_t len;
+
+		/* lg->dead either contains an error code, or a string. */
+		if (IS_ERR(lg->dead))
+			return PTR_ERR(lg->dead);
+
+		/* We can only return as much as the buffer they read with. */
+		len = min(size, strlen(lg->dead)+1);
+		if (copy_to_user(user, lg->dead, len) != 0)
+			return -EFAULT;
+		return len;
+	}
+
+	/* If we returned from read() last time because the Guest sent DMA,
+	 * clear the flag. */
+	if (lg->dma_is_pending)
+		lg->dma_is_pending = 0;
+
+	/* Run the Guest until something interesting happens. */
+	return run_guest(lg, (unsigned long __user *)user);
+}
+
+/*L:020 The initialization write supplies 4 32-bit values (in addition to the
+ * 32-bit LHREQ_INITIALIZE value).  These are:
+ *
+ * pfnlimit: The highest (Guest-physical) page number the Guest should be
+ * allowed to access.  The Launcher has to live in Guest memory, so it sets
+ * this to ensure the Guest can't reach it.
+ *
+ * pgdir: The (Guest-physical) address of the top of the initial Guest
+ * pagetables (which are set up by the Launcher).
+ *
+ * start: The first instruction to execute ("eip" in x86-speak).
+ *
+ * page_offset: The PAGE_OFFSET constant in the Guest kernel.  We should
+ * probably wean the code off this, but it's a very useful constant!  Any
+ * address above this is within the Guest kernel, and any kernel address can
+ * quickly converted from physical to virtual by adding PAGE_OFFSET.  It's
+ * 0xC0000000 (3G) by default, but it's configurable at kernel build time.
+ */
+static int initialize(struct file *file, const u32 __user *input)
+{
+	/* "struct lguest" contains everything we (the Host) know about a
+	 * Guest. */
+	struct lguest *lg;
+	int err, i;
+	u32 args[4];
+
+	/* We grab the Big Lguest lock, which protects the global array
+	 * "lguests" and multiple simultaneous initializations. */
+	mutex_lock(&lguest_lock);
+	/* You can't initialize twice!  Close the device and start again... */
+	if (file->private_data) {
+		err = -EBUSY;
+		goto unlock;
+	}
+
+	if (copy_from_user(args, input, sizeof(args)) != 0) {
+		err = -EFAULT;
+		goto unlock;
+	}
+
+	/* Find an unused guest. */
+	i = find_free_guest();
+	if (i < 0) {
+		err = -ENOSPC;
+		goto unlock;
+	}
+	/* OK, we have an index into the "lguest" array: "lg" is a convenient
+	 * pointer. */
+	lg = &lguests[i];
+
+	/* Populate the easy fields of our "struct lguest" */
+	lg->guestid = i;
+	lg->pfn_limit = args[0];
+	lg->page_offset = args[3];
+
+	/* We need a complete page for the Guest registers: they are accessible
+	 * to the Guest and we can only grant it access to whole pages. */
+	lg->regs_page = get_zeroed_page(GFP_KERNEL);
+	if (!lg->regs_page) {
+		err = -ENOMEM;
+		goto release_guest;
+	}
+	/* We actually put the registers at the bottom of the page. */
+	lg->regs = (void *)lg->regs_page + PAGE_SIZE - sizeof(*lg->regs);
+
+	/* Initialize the Guest's shadow page tables, using the toplevel
+	 * address the Launcher gave us.  This allocates memory, so can
+	 * fail. */
+	err = init_guest_pagetable(lg, args[1]);
+	if (err)
+		goto free_regs;
+
+	/* Now we initialize the Guest's registers, handing it the start
+	 * address. */
+	setup_regs(lg->regs, args[2]);
+
+	/* There are a couple of GDT entries the Guest expects when first
+	 * booting. */
+	setup_guest_gdt(lg);
+
+	/* The timer for lguest's clock needs initialization. */
+	init_clockdev(lg);
+
+	/* We keep a pointer to the Launcher task (ie. current task) for when
+	 * other Guests want to wake this one (inter-Guest I/O). */
+	lg->tsk = current;
+	/* We need to keep a pointer to the Launcher's memory map, because if
+	 * the Launcher dies we need to clean it up.  If we don't keep a
+	 * reference, it is destroyed before close() is called. */
+	lg->mm = get_task_mm(lg->tsk);
+
+	/* Initialize the queue for the waker to wait on */
+	init_waitqueue_head(&lg->break_wq);
+
+	/* We remember which CPU's pages this Guest used last, for optimization
+	 * when the same Guest runs on the same CPU twice. */
+	lg->last_pages = NULL;
+
+	/* We keep our "struct lguest" in the file's private_data. */
+	file->private_data = lg;
+
+	mutex_unlock(&lguest_lock);
+
+	/* And because this is a write() call, we return the length used. */
+	return sizeof(args);
+
+free_regs:
+	free_page(lg->regs_page);
+release_guest:
+	memset(lg, 0, sizeof(*lg));
+unlock:
+	mutex_unlock(&lguest_lock);
+	return err;
+}
+
+/*L:010 The first operation the Launcher does must be a write.  All writes
+ * start with a 32 bit number: for the first write this must be
+ * LHREQ_INITIALIZE to set up the Guest.  After that the Launcher can use
+ * writes of other values to get DMA buffers and send interrupts. */
+static ssize_t write(struct file *file, const char __user *input,
+		     size_t size, loff_t *off)
+{
+	/* Once the guest is initialized, we hold the "struct lguest" in the
+	 * file private data. */
+	struct lguest *lg = file->private_data;
+	u32 req;
+
+	if (get_user(req, input) != 0)
+		return -EFAULT;
+	input += sizeof(req);
+
+	/* If you haven't initialized, you must do that first. */
+	if (req != LHREQ_INITIALIZE && !lg)
+		return -EINVAL;
+
+	/* Once the Guest is dead, all you can do is read() why it died. */
+	if (lg && lg->dead)
+		return -ENOENT;
+
+	/* If you're not the task which owns the Guest, you can only break */
+	if (lg && current != lg->tsk && req != LHREQ_BREAK)
+		return -EPERM;
+
+	switch (req) {
+	case LHREQ_INITIALIZE:
+		return initialize(file, (const u32 __user *)input);
+	case LHREQ_GETDMA:
+		return user_get_dma(lg, (const u32 __user *)input);
+	case LHREQ_IRQ:
+		return user_send_irq(lg, (const u32 __user *)input);
+	case LHREQ_BREAK:
+		return break_guest_out(lg, (const u32 __user *)input);
+	default:
+		return -EINVAL;
+	}
+}
+
+/*L:060 The final piece of interface code is the close() routine.  It reverses
+ * everything done in initialize().  This is usually called because the
+ * Launcher exited.
+ *
+ * Note that the close routine returns 0 or a negative error number: it can't
+ * really fail, but it can whine.  I blame Sun for this wart, and K&R C for
+ * letting them do it. :*/
+static int close(struct inode *inode, struct file *file)
+{
+	struct lguest *lg = file->private_data;
+
+	/* If we never successfully initialized, there's nothing to clean up */
+	if (!lg)
+		return 0;
+
+	/* We need the big lock, to protect from inter-guest I/O and other
+	 * Launchers initializing guests. */
+	mutex_lock(&lguest_lock);
+	/* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
+	hrtimer_cancel(&lg->hrt);
+	/* Free any DMA buffers the Guest had bound. */
+	release_all_dma(lg);
+	/* Free up the shadow page tables for the Guest. */
+	free_guest_pagetable(lg);
+	/* Now all the memory cleanups are done, it's safe to release the
+	 * Launcher's memory management structure. */
+	mmput(lg->mm);
+	/* If lg->dead doesn't contain an error code it will be NULL or a
+	 * kmalloc()ed string, either of which is ok to hand to kfree(). */
+	if (!IS_ERR(lg->dead))
+		kfree(lg->dead);
+	/* We can free up the register page we allocated. */
+	free_page(lg->regs_page);
+	/* We clear the entire structure, which also marks it as free for the
+	 * next user. */
+	memset(lg, 0, sizeof(*lg));
+	/* Release lock and exit. */
+	mutex_unlock(&lguest_lock);
+
+	return 0;
+}
+
+/*L:000
+ * Welcome to our journey through the Launcher!
+ *
+ * The Launcher is the Host userspace program which sets up, runs and services
+ * the Guest.  In fact, many comments in the Drivers which refer to "the Host"
+ * doing things are inaccurate: the Launcher does all the device handling for
+ * the Guest.  The Guest can't tell what's done by the the Launcher and what by
+ * the Host.
+ *
+ * Just to confuse you: to the Host kernel, the Launcher *is* the Guest and we
+ * shall see more of that later.
+ *
+ * We begin our understanding with the Host kernel interface which the Launcher
+ * uses: reading and writing a character device called /dev/lguest.  All the
+ * work happens in the read(), write() and close() routines: */
+static struct file_operations lguest_fops = {
+	.owner	 = THIS_MODULE,
+	.release = close,
+	.write	 = write,
+	.read	 = read,
+};
+
+/* This is a textbook example of a "misc" character device.  Populate a "struct
+ * miscdevice" and register it with misc_register(). */
+static struct miscdevice lguest_dev = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "lguest",
+	.fops	= &lguest_fops,
+};
+
+int __init lguest_device_init(void)
+{
+	return misc_register(&lguest_dev);
+}
+
+void __exit lguest_device_remove(void)
+{
+	misc_deregister(&lguest_dev);
+}
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c
new file mode 100644
index 0000000..b7a924a
--- /dev/null
+++ b/drivers/lguest/page_tables.c
@@ -0,0 +1,680 @@
+/*P:700 The pagetable code, on the other hand, still shows the scars of
+ * previous encounters.  It's functional, and as neat as it can be in the
+ * circumstances, but be wary, for these things are subtle and break easily.
+ * The Guest provides a virtual to physical mapping, but we can neither trust
+ * it nor use it: we verify and convert it here to point the hardware to the
+ * actual Guest pages when running the Guest. :*/
+
+/* Copyright (C) Rusty Russell IBM Corporation 2006.
+ * GPL v2 and any later version */
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+#include <linux/percpu.h>
+#include <asm/tlbflush.h>
+#include "lg.h"
+
+/*M:008 We hold reference to pages, which prevents them from being swapped.
+ * It'd be nice to have a callback in the "struct mm_struct" when Linux wants
+ * to swap out.  If we had this, and a shrinker callback to trim PTE pages, we
+ * could probably consider launching Guests as non-root. :*/
+
+/*H:300
+ * The Page Table Code
+ *
+ * We use two-level page tables for the Guest.  If you're not entirely
+ * comfortable with virtual addresses, physical addresses and page tables then
+ * I recommend you review lguest.c's "Page Table Handling" (with diagrams!).
+ *
+ * The Guest keeps page tables, but we maintain the actual ones here: these are
+ * called "shadow" page tables.  Which is a very Guest-centric name: these are
+ * the real page tables the CPU uses, although we keep them up to date to
+ * reflect the Guest's.  (See what I mean about weird naming?  Since when do
+ * shadows reflect anything?)
+ *
+ * Anyway, this is the most complicated part of the Host code.  There are seven
+ * parts to this:
+ *  (i) Setting up a page table entry for the Guest when it faults,
+ *  (ii) Setting up the page table entry for the Guest stack,
+ *  (iii) Setting up a page table entry when the Guest tells us it has changed,
+ *  (iv) Switching page tables,
+ *  (v) Flushing (thowing away) page tables,
+ *  (vi) Mapping the Switcher when the Guest is about to run,
+ *  (vii) Setting up the page tables initially.
+ :*/
+
+/* Pages a 4k long, and each page table entry is 4 bytes long, giving us 1024
+ * (or 2^10) entries per page. */
+#define PTES_PER_PAGE_SHIFT 10
+#define PTES_PER_PAGE (1 << PTES_PER_PAGE_SHIFT)
+
+/* 1024 entries in a page table page maps 1024 pages: 4MB.  The Switcher is
+ * conveniently placed at the top 4MB, so it uses a separate, complete PTE
+ * page.  */
+#define SWITCHER_PGD_INDEX (PTES_PER_PAGE - 1)
+
+/* We actually need a separate PTE page for each CPU.  Remember that after the
+ * Switcher code itself comes two pages for each CPU, and we don't want this
+ * CPU's guest to see the pages of any other CPU. */
+static DEFINE_PER_CPU(spte_t *, switcher_pte_pages);
+#define switcher_pte_page(cpu) per_cpu(switcher_pte_pages, cpu)
+
+/*H:320 With our shadow and Guest types established, we need to deal with
+ * them: the page table code is curly enough to need helper functions to keep
+ * it clear and clean.
+ *
+ * The first helper takes a virtual address, and says which entry in the top
+ * level page table deals with that address.  Since each top level entry deals
+ * with 4M, this effectively divides by 4M. */
+static unsigned vaddr_to_pgd_index(unsigned long vaddr)
+{
+	return vaddr >> (PAGE_SHIFT + PTES_PER_PAGE_SHIFT);
+}
+
+/* There are two functions which return pointers to the shadow (aka "real")
+ * page tables.
+ *
+ * spgd_addr() takes the virtual address and returns a pointer to the top-level
+ * page directory entry for that address.  Since we keep track of several page
+ * tables, the "i" argument tells us which one we're interested in (it's
+ * usually the current one). */
+static spgd_t *spgd_addr(struct lguest *lg, u32 i, unsigned long vaddr)
+{
+	unsigned int index = vaddr_to_pgd_index(vaddr);
+
+	/* We kill any Guest trying to touch the Switcher addresses. */
+	if (index >= SWITCHER_PGD_INDEX) {
+		kill_guest(lg, "attempt to access switcher pages");
+		index = 0;
+	}
+	/* Return a pointer index'th pgd entry for the i'th page table. */
+	return &lg->pgdirs[i].pgdir[index];
+}
+
+/* This routine then takes the PGD entry given above, which contains the
+ * address of the PTE page.  It then returns a pointer to the PTE entry for the
+ * given address. */
+static spte_t *spte_addr(struct lguest *lg, spgd_t spgd, unsigned long vaddr)
+{
+	spte_t *page = __va(spgd.pfn << PAGE_SHIFT);
+	/* You should never call this if the PGD entry wasn't valid */
+	BUG_ON(!(spgd.flags & _PAGE_PRESENT));
+	return &page[(vaddr >> PAGE_SHIFT) % PTES_PER_PAGE];
+}
+
+/* These two functions just like the above two, except they access the Guest
+ * page tables.  Hence they return a Guest address. */
+static unsigned long gpgd_addr(struct lguest *lg, unsigned long vaddr)
+{
+	unsigned int index = vaddr >> (PAGE_SHIFT + PTES_PER_PAGE_SHIFT);
+	return lg->pgdirs[lg->pgdidx].cr3 + index * sizeof(gpgd_t);
+}
+
+static unsigned long gpte_addr(struct lguest *lg,
+			       gpgd_t gpgd, unsigned long vaddr)
+{
+	unsigned long gpage = gpgd.pfn << PAGE_SHIFT;
+	BUG_ON(!(gpgd.flags & _PAGE_PRESENT));
+	return gpage + ((vaddr>>PAGE_SHIFT) % PTES_PER_PAGE) * sizeof(gpte_t);
+}
+
+/*H:350 This routine takes a page number given by the Guest and converts it to
+ * an actual, physical page number.  It can fail for several reasons: the
+ * virtual address might not be mapped by the Launcher, the write flag is set
+ * and the page is read-only, or the write flag was set and the page was
+ * shared so had to be copied, but we ran out of memory.
+ *
+ * This holds a reference to the page, so release_pte() is careful to
+ * put that back. */
+static unsigned long get_pfn(unsigned long virtpfn, int write)
+{
+	struct page *page;
+	/* This value indicates failure. */
+	unsigned long ret = -1UL;
+
+	/* get_user_pages() is a complex interface: it gets the "struct
+	 * vm_area_struct" and "struct page" assocated with a range of pages.
+	 * It also needs the task's mmap_sem held, and is not very quick.
+	 * It returns the number of pages it got. */
+	down_read(&current->mm->mmap_sem);
+	if (get_user_pages(current, current->mm, virtpfn << PAGE_SHIFT,
+			   1, write, 1, &page, NULL) == 1)
+		ret = page_to_pfn(page);
+	up_read(&current->mm->mmap_sem);
+	return ret;
+}
+
+/*H:340 Converting a Guest page table entry to a shadow (ie. real) page table
+ * entry can be a little tricky.  The flags are (almost) the same, but the
+ * Guest PTE contains a virtual page number: the CPU needs the real page
+ * number. */
+static spte_t gpte_to_spte(struct lguest *lg, gpte_t gpte, int write)
+{
+	spte_t spte;
+	unsigned long pfn;
+
+	/* The Guest sets the global flag, because it thinks that it is using
+	 * PGE.  We only told it to use PGE so it would tell us whether it was
+	 * flushing a kernel mapping or a userspace mapping.  We don't actually
+	 * use the global bit, so throw it away. */
+	spte.flags = (gpte.flags & ~_PAGE_GLOBAL);
+
+	/* We need a temporary "unsigned long" variable to hold the answer from
+	 * get_pfn(), because it returns 0xFFFFFFFF on failure, which wouldn't
+	 * fit in spte.pfn.  get_pfn() finds the real physical number of the
+	 * page, given the virtual number. */
+	pfn = get_pfn(gpte.pfn, write);
+	if (pfn == -1UL) {
+		kill_guest(lg, "failed to get page %u", gpte.pfn);
+		/* When we destroy the Guest, we'll go through the shadow page
+		 * tables and release_pte() them.  Make sure we don't think
+		 * this one is valid! */
+		spte.flags = 0;
+	}
+	/* Now we assign the page number, and our shadow PTE is complete. */
+	spte.pfn = pfn;
+	return spte;
+}
+
+/*H:460 And to complete the chain, release_pte() looks like this: */
+static void release_pte(spte_t pte)
+{
+	/* Remember that get_user_pages() took a reference to the page, in
+	 * get_pfn()?  We have to put it back now. */
+	if (pte.flags & _PAGE_PRESENT)
+		put_page(pfn_to_page(pte.pfn));
+}
+/*:*/
+
+static void check_gpte(struct lguest *lg, gpte_t gpte)
+{
+	if ((gpte.flags & (_PAGE_PWT|_PAGE_PSE)) || gpte.pfn >= lg->pfn_limit)
+		kill_guest(lg, "bad page table entry");
+}
+
+static void check_gpgd(struct lguest *lg, gpgd_t gpgd)
+{
+	if ((gpgd.flags & ~_PAGE_TABLE) || gpgd.pfn >= lg->pfn_limit)
+		kill_guest(lg, "bad page directory entry");
+}
+
+/*H:330
+ * (i) Setting up a page table entry for the Guest when it faults
+ *
+ * We saw this call in run_guest(): when we see a page fault in the Guest, we
+ * come here.  That's because we only set up the shadow page tables lazily as
+ * they're needed, so we get page faults all the time and quietly fix them up
+ * and return to the Guest without it knowing.
+ *
+ * If we fixed up the fault (ie. we mapped the address), this routine returns
+ * true. */
+int demand_page(struct lguest *lg, unsigned long vaddr, int errcode)
+{
+	gpgd_t gpgd;
+	spgd_t *spgd;
+	unsigned long gpte_ptr;
+	gpte_t gpte;
+	spte_t *spte;
+
+	/* First step: get the top-level Guest page table entry. */
+	gpgd = mkgpgd(lgread_u32(lg, gpgd_addr(lg, vaddr)));
+	/* Toplevel not present?  We can't map it in. */
+	if (!(gpgd.flags & _PAGE_PRESENT))
+		return 0;
+
+	/* Now look at the matching shadow entry. */
+	spgd = spgd_addr(lg, lg->pgdidx, vaddr);
+	if (!(spgd->flags & _PAGE_PRESENT)) {
+		/* No shadow entry: allocate a new shadow PTE page. */
+		unsigned long ptepage = get_zeroed_page(GFP_KERNEL);
+		/* This is not really the Guest's fault, but killing it is
+		 * simple for this corner case. */
+		if (!ptepage) {
+			kill_guest(lg, "out of memory allocating pte page");
+			return 0;
+		}
+		/* We check that the Guest pgd is OK. */
+		check_gpgd(lg, gpgd);
+		/* And we copy the flags to the shadow PGD entry.  The page
+		 * number in the shadow PGD is the page we just allocated. */
+		spgd->raw.val = (__pa(ptepage) | gpgd.flags);
+	}
+
+	/* OK, now we look at the lower level in the Guest page table: keep its
+	 * address, because we might update it later. */
+	gpte_ptr = gpte_addr(lg, gpgd, vaddr);
+	gpte = mkgpte(lgread_u32(lg, gpte_ptr));
+
+	/* If this page isn't in the Guest page tables, we can't page it in. */
+	if (!(gpte.flags & _PAGE_PRESENT))
+		return 0;
+
+	/* Check they're not trying to write to a page the Guest wants
+	 * read-only (bit 2 of errcode == write). */
+	if ((errcode & 2) && !(gpte.flags & _PAGE_RW))
+		return 0;
+
+	/* User access to a kernel page? (bit 3 == user access) */
+	if ((errcode & 4) && !(gpte.flags & _PAGE_USER))
+		return 0;
+
+	/* Check that the Guest PTE flags are OK, and the page number is below
+	 * the pfn_limit (ie. not mapping the Launcher binary). */
+	check_gpte(lg, gpte);
+	/* Add the _PAGE_ACCESSED and (for a write) _PAGE_DIRTY flag */
+	gpte.flags |= _PAGE_ACCESSED;
+	if (errcode & 2)
+		gpte.flags |= _PAGE_DIRTY;
+
+	/* Get the pointer to the shadow PTE entry we're going to set. */
+	spte = spte_addr(lg, *spgd, vaddr);
+	/* If there was a valid shadow PTE entry here before, we release it.
+	 * This can happen with a write to a previously read-only entry. */
+	release_pte(*spte);
+
+	/* If this is a write, we insist that the Guest page is writable (the
+	 * final arg to gpte_to_spte()). */
+	if (gpte.flags & _PAGE_DIRTY)
+		*spte = gpte_to_spte(lg, gpte, 1);
+	else {
+		/* If this is a read, don't set the "writable" bit in the page
+		 * table entry, even if the Guest says it's writable.  That way
+		 * we come back here when a write does actually ocur, so we can
+		 * update the Guest's _PAGE_DIRTY flag. */
+		gpte_t ro_gpte = gpte;
+		ro_gpte.flags &= ~_PAGE_RW;
+		*spte = gpte_to_spte(lg, ro_gpte, 0);
+	}
+
+	/* Finally, we write the Guest PTE entry back: we've set the
+	 * _PAGE_ACCESSED and maybe the _PAGE_DIRTY flags. */
+	lgwrite_u32(lg, gpte_ptr, gpte.raw.val);
+
+	/* We succeeded in mapping the page! */
+	return 1;
+}
+
+/*H:360 (ii) Setting up the page table entry for the Guest stack.
+ *
+ * Remember pin_stack_pages() which makes sure the stack is mapped?  It could
+ * simply call demand_page(), but as we've seen that logic is quite long, and
+ * usually the stack pages are already mapped anyway, so it's not required.
+ *
+ * This is a quick version which answers the question: is this virtual address
+ * mapped by the shadow page tables, and is it writable? */
+static int page_writable(struct lguest *lg, unsigned long vaddr)
+{
+	spgd_t *spgd;
+	unsigned long flags;
+
+	/* Look at the top level entry: is it present? */
+	spgd = spgd_addr(lg, lg->pgdidx, vaddr);
+	if (!(spgd->flags & _PAGE_PRESENT))
+		return 0;
+
+	/* Check the flags on the pte entry itself: it must be present and
+	 * writable. */
+	flags = spte_addr(lg, *spgd, vaddr)->flags;
+	return (flags & (_PAGE_PRESENT|_PAGE_RW)) == (_PAGE_PRESENT|_PAGE_RW);
+}
+
+/* So, when pin_stack_pages() asks us to pin a page, we check if it's already
+ * in the page tables, and if not, we call demand_page() with error code 2
+ * (meaning "write"). */
+void pin_page(struct lguest *lg, unsigned long vaddr)
+{
+	if (!page_writable(lg, vaddr) && !demand_page(lg, vaddr, 2))
+		kill_guest(lg, "bad stack page %#lx", vaddr);
+}
+
+/*H:450 If we chase down the release_pgd() code, it looks like this: */
+static void release_pgd(struct lguest *lg, spgd_t *spgd)
+{
+	/* If the entry's not present, there's nothing to release. */
+	if (spgd->flags & _PAGE_PRESENT) {
+		unsigned int i;
+		/* Converting the pfn to find the actual PTE page is easy: turn
+		 * the page number into a physical address, then convert to a
+		 * virtual address (easy for kernel pages like this one). */
+		spte_t *ptepage = __va(spgd->pfn << PAGE_SHIFT);
+		/* For each entry in the page, we might need to release it. */
+		for (i = 0; i < PTES_PER_PAGE; i++)
+			release_pte(ptepage[i]);
+		/* Now we can free the page of PTEs */
+		free_page((long)ptepage);
+		/* And zero out the PGD entry we we never release it twice. */
+		spgd->raw.val = 0;
+	}
+}
+
+/*H:440 (v) Flushing (thowing away) page tables,
+ *
+ * We saw flush_user_mappings() called when we re-used a top-level pgdir page.
+ * It simply releases every PTE page from 0 up to the kernel address. */
+static void flush_user_mappings(struct lguest *lg, int idx)
+{
+	unsigned int i;
+	/* Release every pgd entry up to the kernel's address. */
+	for (i = 0; i < vaddr_to_pgd_index(lg->page_offset); i++)
+		release_pgd(lg, lg->pgdirs[idx].pgdir + i);
+}
+
+/* The Guest also has a hypercall to do this manually: it's used when a large
+ * number of mappings have been changed. */
+void guest_pagetable_flush_user(struct lguest *lg)
+{
+	/* Drop the userspace part of the current page table. */
+	flush_user_mappings(lg, lg->pgdidx);
+}
+/*:*/
+
+/* We keep several page tables.  This is a simple routine to find the page
+ * table (if any) corresponding to this top-level address the Guest has given
+ * us. */
+static unsigned int find_pgdir(struct lguest *lg, unsigned long pgtable)
+{
+	unsigned int i;
+	for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
+		if (lg->pgdirs[i].cr3 == pgtable)
+			break;
+	return i;
+}
+
+/*H:435 And this is us, creating the new page directory.  If we really do
+ * allocate a new one (and so the kernel parts are not there), we set
+ * blank_pgdir. */
+static unsigned int new_pgdir(struct lguest *lg,
+			      unsigned long cr3,
+			      int *blank_pgdir)
+{
+	unsigned int next;
+
+	/* We pick one entry at random to throw out.  Choosing the Least
+	 * Recently Used might be better, but this is easy. */
+	next = random32() % ARRAY_SIZE(lg->pgdirs);
+	/* If it's never been allocated at all before, try now. */
+	if (!lg->pgdirs[next].pgdir) {
+		lg->pgdirs[next].pgdir = (spgd_t *)get_zeroed_page(GFP_KERNEL);
+		/* If the allocation fails, just keep using the one we have */
+		if (!lg->pgdirs[next].pgdir)
+			next = lg->pgdidx;
+		else
+			/* This is a blank page, so there are no kernel
+			 * mappings: caller must map the stack! */
+			*blank_pgdir = 1;
+	}
+	/* Record which Guest toplevel this shadows. */
+	lg->pgdirs[next].cr3 = cr3;
+	/* Release all the non-kernel mappings. */
+	flush_user_mappings(lg, next);
+
+	return next;
+}
+
+/*H:430 (iv) Switching page tables
+ *
+ * This is what happens when the Guest changes page tables (ie. changes the
+ * top-level pgdir).  This happens on almost every context switch. */
+void guest_new_pagetable(struct lguest *lg, unsigned long pgtable)
+{
+	int newpgdir, repin = 0;
+
+	/* Look to see if we have this one already. */
+	newpgdir = find_pgdir(lg, pgtable);
+	/* If not, we allocate or mug an existing one: if it's a fresh one,
+	 * repin gets set to 1. */
+	if (newpgdir == ARRAY_SIZE(lg->pgdirs))
+		newpgdir = new_pgdir(lg, pgtable, &repin);
+	/* Change the current pgd index to the new one. */
+	lg->pgdidx = newpgdir;
+	/* If it was completely blank, we map in the Guest kernel stack */
+	if (repin)
+		pin_stack_pages(lg);
+}
+
+/*H:470 Finally, a routine which throws away everything: all PGD entries in all
+ * the shadow page tables.  This is used when we destroy the Guest. */
+static void release_all_pagetables(struct lguest *lg)
+{
+	unsigned int i, j;
+
+	/* Every shadow pagetable this Guest has */
+	for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
+		if (lg->pgdirs[i].pgdir)
+			/* Every PGD entry except the Switcher at the top */
+			for (j = 0; j < SWITCHER_PGD_INDEX; j++)
+				release_pgd(lg, lg->pgdirs[i].pgdir + j);
+}
+
+/* We also throw away everything when a Guest tells us it's changed a kernel
+ * mapping.  Since kernel mappings are in every page table, it's easiest to
+ * throw them all away.  This is amazingly slow, but thankfully rare. */
+void guest_pagetable_clear_all(struct lguest *lg)
+{
+	release_all_pagetables(lg);
+	/* We need the Guest kernel stack mapped again. */
+	pin_stack_pages(lg);
+}
+
+/*H:420 This is the routine which actually sets the page table entry for then
+ * "idx"'th shadow page table.
+ *
+ * Normally, we can just throw out the old entry and replace it with 0: if they
+ * use it demand_page() will put the new entry in.  We need to do this anyway:
+ * The Guest expects _PAGE_ACCESSED to be set on its PTE the first time a page
+ * is read from, and _PAGE_DIRTY when it's written to.
+ *
+ * But Avi Kivity pointed out that most Operating Systems (Linux included) set
+ * these bits on PTEs immediately anyway.  This is done to save the CPU from
+ * having to update them, but it helps us the same way: if they set
+ * _PAGE_ACCESSED then we can put a read-only PTE entry in immediately, and if
+ * they set _PAGE_DIRTY then we can put a writable PTE entry in immediately.
+ */
+static void do_set_pte(struct lguest *lg, int idx,
+		       unsigned long vaddr, gpte_t gpte)
+{
+	/* Look up the matching shadow page directot entry. */
+	spgd_t *spgd = spgd_addr(lg, idx, vaddr);
+
+	/* If the top level isn't present, there's no entry to update. */
+	if (spgd->flags & _PAGE_PRESENT) {
+		/* Otherwise, we start by releasing the existing entry. */
+		spte_t *spte = spte_addr(lg, *spgd, vaddr);
+		release_pte(*spte);
+
+		/* If they're setting this entry as dirty or accessed, we might
+		 * as well put that entry they've given us in now.  This shaves
+		 * 10% off a copy-on-write micro-benchmark. */
+		if (gpte.flags & (_PAGE_DIRTY | _PAGE_ACCESSED)) {
+			check_gpte(lg, gpte);
+			*spte = gpte_to_spte(lg, gpte, gpte.flags&_PAGE_DIRTY);
+		} else
+			/* Otherwise we can demand_page() it in later. */
+			spte->raw.val = 0;
+	}
+}
+
+/*H:410 Updating a PTE entry is a little trickier.
+ *
+ * We keep track of several different page tables (the Guest uses one for each
+ * process, so it makes sense to cache at least a few).  Each of these have
+ * identical kernel parts: ie. every mapping above PAGE_OFFSET is the same for
+ * all processes.  So when the page table above that address changes, we update
+ * all the page tables, not just the current one.  This is rare.
+ *
+ * The benefit is that when we have to track a new page table, we can copy keep
+ * all the kernel mappings.  This speeds up context switch immensely. */
+void guest_set_pte(struct lguest *lg,
+		   unsigned long cr3, unsigned long vaddr, gpte_t gpte)
+{
+	/* Kernel mappings must be changed on all top levels.  Slow, but
+	 * doesn't happen often. */
+	if (vaddr >= lg->page_offset) {
+		unsigned int i;
+		for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
+			if (lg->pgdirs[i].pgdir)
+				do_set_pte(lg, i, vaddr, gpte);
+	} else {
+		/* Is this page table one we have a shadow for? */
+		int pgdir = find_pgdir(lg, cr3);
+		if (pgdir != ARRAY_SIZE(lg->pgdirs))
+			/* If so, do the update. */
+			do_set_pte(lg, pgdir, vaddr, gpte);
+	}
+}
+
+/*H:400
+ * (iii) Setting up a page table entry when the Guest tells us it has changed.
+ *
+ * Just like we did in interrupts_and_traps.c, it makes sense for us to deal
+ * with the other side of page tables while we're here: what happens when the
+ * Guest asks for a page table to be updated?
+ *
+ * We already saw that demand_page() will fill in the shadow page tables when
+ * needed, so we can simply remove shadow page table entries whenever the Guest
+ * tells us they've changed.  When the Guest tries to use the new entry it will
+ * fault and demand_page() will fix it up.
+ *
+ * So with that in mind here's our code to to update a (top-level) PGD entry:
+ */
+void guest_set_pmd(struct lguest *lg, unsigned long cr3, u32 idx)
+{
+	int pgdir;
+
+	/* The kernel seems to try to initialize this early on: we ignore its
+	 * attempts to map over the Switcher. */
+	if (idx >= SWITCHER_PGD_INDEX)
+		return;
+
+	/* If they're talking about a page table we have a shadow for... */
+	pgdir = find_pgdir(lg, cr3);
+	if (pgdir < ARRAY_SIZE(lg->pgdirs))
+		/* ... throw it away. */
+		release_pgd(lg, lg->pgdirs[pgdir].pgdir + idx);
+}
+
+/*H:500 (vii) Setting up the page tables initially.
+ *
+ * When a Guest is first created, the Launcher tells us where the toplevel of
+ * its first page table is.  We set some things up here: */
+int init_guest_pagetable(struct lguest *lg, unsigned long pgtable)
+{
+	/* In flush_user_mappings() we loop from 0 to
+	 * "vaddr_to_pgd_index(lg->page_offset)".  This assumes it won't hit
+	 * the Switcher mappings, so check that now. */
+	if (vaddr_to_pgd_index(lg->page_offset) >= SWITCHER_PGD_INDEX)
+		return -EINVAL;
+	/* We start on the first shadow page table, and give it a blank PGD
+	 * page. */
+	lg->pgdidx = 0;
+	lg->pgdirs[lg->pgdidx].cr3 = pgtable;
+	lg->pgdirs[lg->pgdidx].pgdir = (spgd_t*)get_zeroed_page(GFP_KERNEL);
+	if (!lg->pgdirs[lg->pgdidx].pgdir)
+		return -ENOMEM;
+	return 0;
+}
+
+/* When a Guest dies, our cleanup is fairly simple. */
+void free_guest_pagetable(struct lguest *lg)
+{
+	unsigned int i;
+
+	/* Throw away all page table pages. */
+	release_all_pagetables(lg);
+	/* Now free the top levels: free_page() can handle 0 just fine. */
+	for (i = 0; i < ARRAY_SIZE(lg->pgdirs); i++)
+		free_page((long)lg->pgdirs[i].pgdir);
+}
+
+/*H:480 (vi) Mapping the Switcher when the Guest is about to run.
+ *
+ * The Switcher and the two pages for this CPU need to be available to the
+ * Guest (and not the pages for other CPUs).  We have the appropriate PTE pages
+ * for each CPU already set up, we just need to hook them in. */
+void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages)
+{
+	spte_t *switcher_pte_page = __get_cpu_var(switcher_pte_pages);
+	spgd_t switcher_pgd;
+	spte_t regs_pte;
+
+	/* Make the last PGD entry for this Guest point to the Switcher's PTE
+	 * page for this CPU (with appropriate flags). */
+	switcher_pgd.pfn = __pa(switcher_pte_page) >> PAGE_SHIFT;
+	switcher_pgd.flags = _PAGE_KERNEL;
+	lg->pgdirs[lg->pgdidx].pgdir[SWITCHER_PGD_INDEX] = switcher_pgd;
+
+	/* We also change the Switcher PTE page.  When we're running the Guest,
+	 * we want the Guest's "regs" page to appear where the first Switcher
+	 * page for this CPU is.  This is an optimization: when the Switcher
+	 * saves the Guest registers, it saves them into the first page of this
+	 * CPU's "struct lguest_pages": if we make sure the Guest's register
+	 * page is already mapped there, we don't have to copy them out
+	 * again. */
+	regs_pte.pfn = __pa(lg->regs_page) >> PAGE_SHIFT;
+	regs_pte.flags = _PAGE_KERNEL;
+	switcher_pte_page[(unsigned long)pages/PAGE_SIZE%PTES_PER_PAGE]
+		= regs_pte;
+}
+/*:*/
+
+static void free_switcher_pte_pages(void)
+{
+	unsigned int i;
+
+	for_each_possible_cpu(i)
+		free_page((long)switcher_pte_page(i));
+}
+
+/*H:520 Setting up the Switcher PTE page for given CPU is fairly easy, given
+ * the CPU number and the "struct page"s for the Switcher code itself.
+ *
+ * Currently the Switcher is less than a page long, so "pages" is always 1. */
+static __init void populate_switcher_pte_page(unsigned int cpu,
+					      struct page *switcher_page[],
+					      unsigned int pages)
+{
+	unsigned int i;
+	spte_t *pte = switcher_pte_page(cpu);
+
+	/* The first entries are easy: they map the Switcher code. */
+	for (i = 0; i < pages; i++) {
+		pte[i].pfn = page_to_pfn(switcher_page[i]);
+		pte[i].flags = _PAGE_PRESENT|_PAGE_ACCESSED;
+	}
+
+	/* The only other thing we map is this CPU's pair of pages. */
+	i = pages + cpu*2;
+
+	/* First page (Guest registers) is writable from the Guest */
+	pte[i].pfn = page_to_pfn(switcher_page[i]);
+	pte[i].flags = _PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_RW;
+	/* The second page contains the "struct lguest_ro_state", and is
+	 * read-only. */
+	pte[i+1].pfn = page_to_pfn(switcher_page[i+1]);
+	pte[i+1].flags = _PAGE_PRESENT|_PAGE_ACCESSED;
+}
+
+/*H:510 At boot or module load time, init_pagetables() allocates and populates
+ * the Switcher PTE page for each CPU. */
+__init int init_pagetables(struct page **switcher_page, unsigned int pages)
+{
+	unsigned int i;
+
+	for_each_possible_cpu(i) {
+		switcher_pte_page(i) = (spte_t *)get_zeroed_page(GFP_KERNEL);
+		if (!switcher_pte_page(i)) {
+			free_switcher_pte_pages();
+			return -ENOMEM;
+		}
+		populate_switcher_pte_page(i, switcher_page, pages);
+	}
+	return 0;
+}
+/*:*/
+
+/* Cleaning up simply involves freeing the PTE page for each CPU. */
+void free_pagetables(void)
+{
+	free_switcher_pte_pages();
+}
diff --git a/drivers/lguest/segments.c b/drivers/lguest/segments.c
new file mode 100644
index 0000000..9b81119
--- /dev/null
+++ b/drivers/lguest/segments.c
@@ -0,0 +1,177 @@
+/*P:600 The x86 architecture has segments, which involve a table of descriptors
+ * which can be used to do funky things with virtual address interpretation.
+ * We originally used to use segments so the Guest couldn't alter the
+ * Guest<->Host Switcher, and then we had to trim Guest segments, and restore
+ * for userspace per-thread segments, but trim again for on userspace->kernel
+ * transitions...  This nightmarish creation was contained within this file,
+ * where we knew not to tread without heavy armament and a change of underwear.
+ *
+ * In these modern times, the segment handling code consists of simple sanity
+ * checks, and the worst you'll experience reading this code is butterfly-rash
+ * from frolicking through its parklike serenity. :*/
+#include "lg.h"
+
+/*H:600
+ * We've almost completed the Host; there's just one file to go!
+ *
+ * Segments & The Global Descriptor Table
+ *
+ * (That title sounds like a bad Nerdcore group.  Not to suggest that there are
+ * any good Nerdcore groups, but in high school a friend of mine had a band
+ * called Joe Fish and the Chips, so there are definitely worse band names).
+ *
+ * To refresh: the GDT is a table of 8-byte values describing segments.  Once
+ * set up, these segments can be loaded into one of the 6 "segment registers".
+ *
+ * GDT entries are passed around as "struct desc_struct"s, which like IDT
+ * entries are split into two 32-bit members, "a" and "b".  One day, someone
+ * will clean that up, and be declared a Hero.  (No pressure, I'm just saying).
+ *
+ * Anyway, the GDT entry contains a base (the start address of the segment), a
+ * limit (the size of the segment - 1), and some flags.  Sounds simple, and it
+ * would be, except those zany Intel engineers decided that it was too boring
+ * to put the base at one end, the limit at the other, and the flags in
+ * between.  They decided to shotgun the bits at random throughout the 8 bytes,
+ * like so:
+ *
+ * 0               16                     40       48  52  56     63
+ * [ limit part 1 ][     base part 1     ][ flags ][li][fl][base ]
+ *                                                  mit ags part 2
+ *                                                part 2
+ *
+ * As a result, this file contains a certain amount of magic numeracy.  Let's
+ * begin.
+ */
+
+/* There are several entries we don't let the Guest set.  The TSS entry is the
+ * "Task State Segment" which controls all kinds of delicate things.  The
+ * LGUEST_CS and LGUEST_DS entries are reserved for the Switcher, and the
+ * the Guest can't be trusted to deal with double faults. */
+static int ignored_gdt(unsigned int num)
+{
+	return (num == GDT_ENTRY_TSS
+		|| num == GDT_ENTRY_LGUEST_CS
+		|| num == GDT_ENTRY_LGUEST_DS
+		|| num == GDT_ENTRY_DOUBLEFAULT_TSS);
+}
+
+/*H:610 Once the GDT has been changed, we fix the new entries up a little.  We
+ * don't care if they're invalid: the worst that can happen is a General
+ * Protection Fault in the Switcher when it restores a Guest segment register
+ * which tries to use that entry.  Then we kill the Guest for causing such a
+ * mess: the message will be "unhandled trap 256". */
+static void fixup_gdt_table(struct lguest *lg, unsigned start, unsigned end)
+{
+	unsigned int i;
+
+	for (i = start; i < end; i++) {
+		/* We never copy these ones to real GDT, so we don't care what
+		 * they say */
+		if (ignored_gdt(i))
+			continue;
+
+		/* Segment descriptors contain a privilege level: the Guest is
+		 * sometimes careless and leaves this as 0, even though it's
+		 * running at privilege level 1.  If so, we fix it here. */
+		if ((lg->gdt[i].b & 0x00006000) == 0)
+			lg->gdt[i].b |= (GUEST_PL << 13);
+
+		/* Each descriptor has an "accessed" bit.  If we don't set it
+		 * now, the CPU will try to set it when the Guest first loads
+		 * that entry into a segment register.  But the GDT isn't
+		 * writable by the Guest, so bad things can happen. */
+		lg->gdt[i].b |= 0x00000100;
+	}
+}
+
+/* This routine is called at boot or modprobe time for each CPU to set up the
+ * "constant" GDT entries for Guests running on that CPU. */
+void setup_default_gdt_entries(struct lguest_ro_state *state)
+{
+	struct desc_struct *gdt = state->guest_gdt;
+	unsigned long tss = (unsigned long)&state->guest_tss;
+
+	/* The hypervisor segments are full 0-4G segments, privilege level 0 */
+	gdt[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
+	gdt[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
+
+	/* The TSS segment refers to the TSS entry for this CPU, so we cannot
+	 * copy it from the Guest.  Forgive the magic flags */
+	gdt[GDT_ENTRY_TSS].a = 0x00000067 | (tss << 16);
+	gdt[GDT_ENTRY_TSS].b = 0x00008900 | (tss & 0xFF000000)
+		| ((tss >> 16) & 0x000000FF);
+}
+
+/* This routine is called before the Guest is run for the first time. */
+void setup_guest_gdt(struct lguest *lg)
+{
+	/* Start with full 0-4G segments... */
+	lg->gdt[GDT_ENTRY_KERNEL_CS] = FULL_EXEC_SEGMENT;
+	lg->gdt[GDT_ENTRY_KERNEL_DS] = FULL_SEGMENT;
+	/* ...except the Guest is allowed to use them, so set the privilege
+	 * level appropriately in the flags. */
+	lg->gdt[GDT_ENTRY_KERNEL_CS].b |= (GUEST_PL << 13);
+	lg->gdt[GDT_ENTRY_KERNEL_DS].b |= (GUEST_PL << 13);
+}
+
+/* Like the IDT, we never simply use the GDT the Guest gives us.  We set up the
+ * GDTs for each CPU, then we copy across the entries each time we want to run
+ * a different Guest on that CPU. */
+
+/* A partial GDT load, for the three "thead-local storage" entries.  Otherwise
+ * it's just like load_guest_gdt().  So much, in fact, it would probably be
+ * neater to have a single hypercall to cover both. */
+void copy_gdt_tls(const struct lguest *lg, struct desc_struct *gdt)
+{
+	unsigned int i;
+
+	for (i = GDT_ENTRY_TLS_MIN; i <= GDT_ENTRY_TLS_MAX; i++)
+		gdt[i] = lg->gdt[i];
+}
+
+/* This is the full version */
+void copy_gdt(const struct lguest *lg, struct desc_struct *gdt)
+{
+	unsigned int i;
+
+	/* The default entries from setup_default_gdt_entries() are not
+	 * replaced.  See ignored_gdt() above. */
+	for (i = 0; i < GDT_ENTRIES; i++)
+		if (!ignored_gdt(i))
+			gdt[i] = lg->gdt[i];
+}
+
+/* This is where the Guest asks us to load a new GDT (LHCALL_LOAD_GDT). */
+void load_guest_gdt(struct lguest *lg, unsigned long table, u32 num)
+{
+	/* We assume the Guest has the same number of GDT entries as the
+	 * Host, otherwise we'd have to dynamically allocate the Guest GDT. */
+	if (num > ARRAY_SIZE(lg->gdt))
+		kill_guest(lg, "too many gdt entries %i", num);
+
+	/* We read the whole thing in, then fix it up. */
+	lgread(lg, lg->gdt, table, num * sizeof(lg->gdt[0]));
+	fixup_gdt_table(lg, 0, ARRAY_SIZE(lg->gdt));
+	/* Mark that the GDT changed so the core knows it has to copy it again,
+	 * even if the Guest is run on the same CPU. */
+	lg->changed |= CHANGED_GDT;
+}
+
+void guest_load_tls(struct lguest *lg, unsigned long gtls)
+{
+	struct desc_struct *tls = &lg->gdt[GDT_ENTRY_TLS_MIN];
+
+	lgread(lg, tls, gtls, sizeof(*tls)*GDT_ENTRY_TLS_ENTRIES);
+	fixup_gdt_table(lg, GDT_ENTRY_TLS_MIN, GDT_ENTRY_TLS_MAX+1);
+	lg->changed |= CHANGED_GDT_TLS;
+}
+
+/*
+ * With this, we have finished the Host.
+ *
+ * Five of the seven parts of our task are complete.  You have made it through
+ * the Bit of Despair (I think that's somewhere in the page table code,
+ * myself).
+ *
+ * Next, we examine "make Switcher".  It's short, but intense.
+ */
diff --git a/drivers/lguest/switcher.S b/drivers/lguest/switcher.S
new file mode 100644
index 0000000..7c9c230
--- /dev/null
+++ b/drivers/lguest/switcher.S
@@ -0,0 +1,350 @@
+/*P:900 This is the Switcher: code which sits at 0xFFC00000 to do the low-level
+ * Guest<->Host switch.  It is as simple as it can be made, but it's naturally
+ * very specific to x86.
+ *
+ * You have now completed Preparation.  If this has whet your appetite; if you
+ * are feeling invigorated and refreshed then the next, more challenging stage
+ * can be found in "make Guest". :*/
+
+/*S:100
+ * Welcome to the Switcher itself!
+ *
+ * This file contains the low-level code which changes the CPU to run the Guest
+ * code, and returns to the Host when something happens.  Understand this, and
+ * you understand the heart of our journey.
+ *
+ * Because this is in assembler rather than C, our tale switches from prose to
+ * verse.  First I tried limericks:
+ *
+ *	There once was an eax reg,
+ *	To which our pointer was fed,
+ *	It needed an add,
+ *	Which asm-offsets.h had
+ *	But this limerick is hurting my head.
+ *
+ * Next I tried haikus, but fitting the required reference to the seasons in
+ * every stanza was quickly becoming tiresome:
+ *
+ *	The %eax reg
+ *	Holds "struct lguest_pages" now:
+ *	Cherry blossoms fall.
+ *
+ * Then I started with Heroic Verse, but the rhyming requirement leeched away
+ * the content density and led to some uniquely awful oblique rhymes:
+ *
+ *	These constants are coming from struct offsets
+ *	For use within the asm switcher text.
+ *
+ * Finally, I settled for something between heroic hexameter, and normal prose
+ * with inappropriate linebreaks.  Anyway, it aint no Shakespeare.
+ */
+
+// Not all kernel headers work from assembler
+// But these ones are needed: the ENTRY() define
+// And constants extracted from struct offsets
+// To avoid magic numbers and breakage:
+// Should they change the compiler can't save us
+// Down here in the depths of assembler code.
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/page.h>
+#include "lg.h"
+
+// We mark the start of the code to copy
+// It's placed in .text tho it's never run here
+// You'll see the trick macro at the end
+// Which interleaves data and text to effect.
+.text
+ENTRY(start_switcher_text)
+
+// When we reach switch_to_guest we have just left
+// The safe and comforting shores of C code
+// %eax has the "struct lguest_pages" to use
+// Where we save state and still see it from the Guest
+// And %ebx holds the Guest shadow pagetable:
+// Once set we have truly left Host behind.
+ENTRY(switch_to_guest)
+	// We told gcc all its regs could fade,
+	// Clobbered by our journey into the Guest
+	// We could have saved them, if we tried
+	// But time is our master and cycles count.
+
+	// Segment registers must be saved for the Host
+	// We push them on the Host stack for later
+	pushl	%es
+	pushl	%ds
+	pushl	%gs
+	pushl	%fs
+	// But the compiler is fickle, and heeds
+	// No warning of %ebp clobbers
+	// When frame pointers are used.  That register
+	// Must be saved and restored or chaos strikes.
+	pushl	%ebp
+	// The Host's stack is done, now save it away
+	// In our "struct lguest_pages" at offset
+	// Distilled into asm-offsets.h
+	movl	%esp, LGUEST_PAGES_host_sp(%eax)
+
+	// All saved and there's now five steps before us:
+	// Stack, GDT, IDT, TSS
+	// And last of all the page tables are flipped.
+
+	// Yet beware that our stack pointer must be
+	// Always valid lest an NMI hits
+	// %edx does the duty here as we juggle
+	// %eax is lguest_pages: our stack lies within.
+	movl	%eax, %edx
+	addl	$LGUEST_PAGES_regs, %edx
+	movl	%edx, %esp
+
+	// The Guest's GDT we so carefully
+	// Placed in the "struct lguest_pages" before
+	lgdt	LGUEST_PAGES_guest_gdt_desc(%eax)
+
+	// The Guest's IDT we did partially
+	// Move to the "struct lguest_pages" as well.
+	lidt	LGUEST_PAGES_guest_idt_desc(%eax)
+
+	// The TSS entry which controls traps
+	// Must be loaded up with "ltr" now:
+	// For after we switch over our page tables
+	// It (as the rest) will be writable no more.
+	// (The GDT entry TSS needs
+	// Changes type when we load it: damn Intel!)
+	movl	$(GDT_ENTRY_TSS*8), %edx
+	ltr	%dx
+
+	// Look back now, before we take this last step!
+	// The Host's TSS entry was also marked used;
+	// Let's clear it again, ere we return.
+	// The GDT descriptor of the Host
+	// Points to the table after two "size" bytes
+	movl	(LGUEST_PAGES_host_gdt_desc+2)(%eax), %edx
+	// Clear the type field of "used" (byte 5, bit 2)
+	andb	$0xFD, (GDT_ENTRY_TSS*8 + 5)(%edx)
+
+	// Once our page table's switched, the Guest is live!
+	// The Host fades as we run this final step.
+	// Our "struct lguest_pages" is now read-only.
+	movl	%ebx, %cr3
+
+	// The page table change did one tricky thing:
+	// The Guest's register page has been mapped
+	// Writable onto our %esp (stack) --
+	// We can simply pop off all Guest regs.
+	popl	%ebx
+	popl	%ecx
+	popl	%edx
+	popl	%esi
+	popl	%edi
+	popl	%ebp
+	popl	%gs
+	popl	%eax
+	popl	%fs
+	popl	%ds
+	popl	%es
+
+	// Near the base of the stack lurk two strange fields
+	// Which we fill as we exit the Guest
+	// These are the trap number and its error
+	// We can simply step past them on our way.
+	addl	$8, %esp
+
+	// The last five stack slots hold return address
+	// And everything needed to change privilege
+	// Into the Guest privilege level of 1,
+	// And the stack where the Guest had last left it.
+	// Interrupts are turned back on: we are Guest.
+	iret
+
+// There are two paths where we switch to the Host
+// So we put the routine in a macro.
+// We are on our way home, back to the Host
+// Interrupted out of the Guest, we come here.
+#define SWITCH_TO_HOST							\
+	/* We save the Guest state: all registers first			\
+	 * Laid out just as "struct lguest_regs" defines */		\
+	pushl	%es;							\
+	pushl	%ds;							\
+	pushl	%fs;							\
+	pushl	%eax;							\
+	pushl	%gs;							\
+	pushl	%ebp;							\
+	pushl	%edi;							\
+	pushl	%esi;							\
+	pushl	%edx;							\
+	pushl	%ecx;							\
+	pushl	%ebx;							\
+	/* Our stack and our code are using segments			\
+	 * Set in the TSS and IDT					\
+	 * Yet if we were to touch data we'd use			\
+	 * Whatever data segment the Guest had.				\
+	 * Load the lguest ds segment for now. */			\
+	movl	$(LGUEST_DS), %eax;					\
+	movl	%eax, %ds;						\
+	/* So where are we?  Which CPU, which struct?			\
+	 * The stack is our clue: our TSS starts			\
+	 * It at the end of "struct lguest_pages".			\
+	 * Or we may have stumbled while restoring			\
+	 * Our Guest segment regs while in switch_to_guest,		\
+	 * The fault pushed atop that part-unwound stack.		\
+	 * If we round the stack down to the page start			\
+	 * We're at the start of "struct lguest_pages". */		\
+	movl	%esp, %eax;						\
+	andl	$(~(1 << PAGE_SHIFT - 1)), %eax;			\
+	/* Save our trap number: the switch will obscure it		\
+	 * (The Guest regs are not mapped here in the Host)		\
+	 * %ebx holds it safe for deliver_to_host */			\
+	movl	LGUEST_PAGES_regs_trapnum(%eax), %ebx;			\
+	/* The Host GDT, IDT and stack!					\
+	 * All these lie safely hidden from the Guest:			\
+	 * We must return to the Host page tables			\
+	 * (Hence that was saved in struct lguest_pages) */		\
+	movl	LGUEST_PAGES_host_cr3(%eax), %edx;			\
+	movl	%edx, %cr3;						\
+	/* As before, when we looked back at the Host			\
+	 * As we left and marked TSS unused				\
+	 * So must we now for the Guest left behind. */			\
+	andb	$0xFD, (LGUEST_PAGES_guest_gdt+GDT_ENTRY_TSS*8+5)(%eax); \
+	/* Switch to Host's GDT, IDT. */				\
+	lgdt	LGUEST_PAGES_host_gdt_desc(%eax);			\
+	lidt	LGUEST_PAGES_host_idt_desc(%eax);			\
+	/* Restore the Host's stack where it's saved regs lie */	\
+	movl	LGUEST_PAGES_host_sp(%eax), %esp;			\
+	/* Last the TSS: our Host is complete */			\
+	movl	$(GDT_ENTRY_TSS*8), %edx;				\
+	ltr	%dx;							\
+	/* Restore now the regs saved right at the first. */		\
+	popl	%ebp;							\
+	popl	%fs;							\
+	popl	%gs;							\
+	popl	%ds;							\
+	popl	%es
+
+// Here's where we come when the Guest has just trapped:
+// (Which trap we'll see has been pushed on the stack).
+// We need only switch back, and the Host will decode
+// Why we came home, and what needs to be done.
+return_to_host:
+	SWITCH_TO_HOST
+	iret
+
+// An interrupt, with some cause external
+// Has ajerked us rudely from the Guest's code
+// Again we must return home to the Host
+deliver_to_host:
+	SWITCH_TO_HOST
+	// But now we must go home via that place
+	// Where that interrupt was supposed to go
+	// Had we not been ensconced, running the Guest.
+	// Here we see the cleverness of our stack:
+	// The Host stack is formed like an interrupt
+	// With EIP, CS and EFLAGS layered.
+	// Interrupt handlers end with "iret"
+	// And that will take us home at long long last.
+
+	// But first we must find the handler to call!
+	// The IDT descriptor for the Host
+	// Has two bytes for size, and four for address:
+	// %edx will hold it for us for now.
+	movl	(LGUEST_PAGES_host_idt_desc+2)(%eax), %edx
+	// We now know the table address we need,
+	// And saved the trap's number inside %ebx.
+	// Yet the pointer to the handler is smeared
+	// Across the bits of the table entry.
+	// What oracle can tell us how to extract
+	// From such a convoluted encoding?
+	// I consulted gcc, and it gave
+	// These instructions, which I gladly credit:
+	leal	(%edx,%ebx,8), %eax
+	movzwl	(%eax),%edx
+	movl	4(%eax), %eax
+	xorw	%ax, %ax
+	orl	%eax, %edx
+	// Now the address of the handler's in %edx
+	// We call it now: its "iret" takes us home.
+	jmp	*%edx
+
+// Every interrupt can come to us here
+// But we must truly tell each apart.
+// They number two hundred and fifty six
+// And each must land in a different spot,
+// Push its number on stack, and join the stream.
+
+// And worse, a mere six of the traps stand apart
+// And push on their stack an addition:
+// An error number, thirty two bits long
+// So we punish the other two fifty
+// And make them push a zero so they match.
+
+// Yet two fifty six entries is long
+// And all will look most the same as the last
+// So we create a macro which can make
+// As many entries as we need to fill.
+
+// Note the change to .data then .text:
+// We plant the address of each entry
+// Into a (data) table for the Host
+// To know where each Guest interrupt should go.
+.macro IRQ_STUB N TARGET
+	.data; .long 1f; .text; 1:
+ // Trap eight, ten through fourteen and seventeen
+ // Supply an error number.  Else zero.
+ .if (\N <> 8) && (\N < 10 || \N > 14) && (\N <> 17)
+	pushl	$0
+ .endif
+	pushl	$\N
+	jmp	\TARGET
+	ALIGN
+.endm
+
+// This macro creates numerous entries
+// Using GAS macros which out-power C's.
+.macro IRQ_STUBS FIRST LAST TARGET
+ irq=\FIRST
+ .rept \LAST-\FIRST+1
+	IRQ_STUB irq \TARGET
+  irq=irq+1
+ .endr
+.endm
+
+// Here's the marker for our pointer table
+// Laid in the data section just before
+// Each macro places the address of code
+// Forming an array: each one points to text
+// Which handles interrupt in its turn.
+.data
+.global default_idt_entries
+default_idt_entries:
+.text
+	// The first two traps go straight back to the Host
+	IRQ_STUBS 0 1 return_to_host
+	// We'll say nothing, yet, about NMI
+	IRQ_STUB 2 handle_nmi
+	// Other traps also return to the Host
+	IRQ_STUBS 3 31 return_to_host
+	// All interrupts go via their handlers
+	IRQ_STUBS 32 127 deliver_to_host
+	// 'Cept system calls coming from userspace
+	// Are to go to the Guest, never the Host.
+	IRQ_STUB 128 return_to_host
+	IRQ_STUBS 129 255 deliver_to_host
+
+// The NMI, what a fabulous beast
+// Which swoops in and stops us no matter that
+// We're suspended between heaven and hell,
+// (Or more likely between the Host and Guest)
+// When in it comes!  We are dazed and confused
+// So we do the simplest thing which one can.
+// Though we've pushed the trap number and zero
+// We discard them, return, and hope we live.
+handle_nmi:
+	addl	$8, %esp
+	iret
+
+// We are done; all that's left is Mastery
+// And "make Mastery" is a journey long
+// Designed to make your fingers itch to code.
+
+// Here ends the text, the file and poem.
+ENTRY(end_switcher_text)
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 20da011..77f50b6 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -3,6 +3,11 @@
 	bool "Macintosh device drivers"
 	depends on PPC || MAC || X86
 	default y if (PPC_PMAC || MAC)
+	---help---
+	  Say Y here to get to see options for devices used with Macintosh
+	  computers. This option alone does not add any kernel code.
+
+	  If you say N, all options in this submenu will be skipped and disabled.
 
 if MACINTOSH_DRIVERS
 
diff --git a/drivers/macintosh/adb-iop.c b/drivers/macintosh/adb-iop.c
index 17ef5d3..4446966 100644
--- a/drivers/macintosh/adb-iop.c
+++ b/drivers/macintosh/adb-iop.c
@@ -19,7 +19,6 @@
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 
-#include <asm/bootinfo.h> 
 #include <asm/macintosh.h> 
 #include <asm/macints.h> 
 #include <asm/mac_iop.h>
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index bc77c5e..5c742a5 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -89,7 +89,7 @@
 static int autopoll_devs;
 int __adb_probe_sync;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static void adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
 static struct pmu_sleep_notifier adb_sleep_notifier = {
 	adb_notify_sleep,
@@ -313,7 +313,7 @@
 		printk(KERN_WARNING "Warning: no ADB interface detected\n");
 		adb_controller = NULL;
 	} else {
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 		pmu_register_sleep_notifier(&adb_sleep_notifier);
 #endif /* CONFIG_PM */
 #ifdef CONFIG_PPC
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
index 9ff2189..8cce016 100644
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -75,7 +75,7 @@
 #define ADB_KEY_POWER_OLD	0x7e
 #define ADB_KEY_POWER		0x7f
 
-u8 adb_to_linux_keycodes[128] = {
+u16 adb_to_linux_keycodes[128] = {
 	/* 0x00 */ KEY_A, 		/*  30 */
 	/* 0x01 */ KEY_S, 		/*  31 */
 	/* 0x02 */ KEY_D,		/*  32 */
@@ -139,7 +139,7 @@
 	/* 0x3c */ KEY_RIGHT,		/* 106 */
 	/* 0x3d */ KEY_DOWN,		/* 108 */
 	/* 0x3e */ KEY_UP,		/* 103 */
-	/* 0x3f */ 0,
+	/* 0x3f */ KEY_FN,		/* 0x1d0 */
 	/* 0x40 */ 0,
 	/* 0x41 */ KEY_KPDOT,		/*  83 */
 	/* 0x42 */ 0,
@@ -213,7 +213,7 @@
 	int original_handler_id;
 	int current_handler_id;
 	int mouse_kind;
-	unsigned char *keycode;
+	u16 *keycode;
 	char name[64];
 	char phys[32];
 	int flags;
@@ -334,7 +334,7 @@
 			keycode = ADB_KEY_POWER;
 		}
 		break;
-	case ADB_KEY_POWER: 
+	case ADB_KEY_POWER:
 		/* Fn + Command will produce a bogus "power" keycode */
 		if (ahid->flags & FLAG_FN_KEY_PRESSED) {
 			keycode = ADB_KEY_CMD;
@@ -359,8 +359,7 @@
 			}
 		} else
 			ahid->flags |= FLAG_FN_KEY_PRESSED;
-		/* Swallow the key press */
-		return;
+		break;
 	case ADB_KEY_DEL:
 		/* Emulate Fn+delete = forward delete */
 		if (ahid->flags & FLAG_FN_KEY_PRESSED) {
@@ -374,9 +373,9 @@
 #endif /* CONFIG_PPC_PMAC */
 	}
 
-	if (adbhid[id]->keycode[keycode]) {
-		input_report_key(adbhid[id]->input,
-				 adbhid[id]->keycode[keycode], !up_flag);
+	key = adbhid[id]->keycode[keycode];
+	if (key) {
+		input_report_key(adbhid[id]->input, key, !up_flag);
 		input_sync(adbhid[id]->input);
 	} else
 		printk(KERN_INFO "Unhandled ADB key (scancode %#02x) %s.\n", keycode,
@@ -795,8 +794,8 @@
 		input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
 		input_dev->ledbit[0] = BIT(LED_SCROLLL) | BIT(LED_CAPSL) | BIT(LED_NUML);
 		input_dev->event = adbhid_kbd_event;
-		input_dev->keycodemax = 127;
-		input_dev->keycodesize = 1;
+		input_dev->keycodemax = KEY_FN;
+		input_dev->keycodesize = sizeof(hid->keycode[0]);
 		break;
 
 	case ADB_MOUSE:
diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c
index e54c4d9..73c50bc 100644
--- a/drivers/macintosh/ans-lcd.c
+++ b/drivers/macintosh/ans-lcd.c
@@ -14,9 +14,10 @@
 #include <asm/uaccess.h>
 #include <asm/sections.h>
 #include <asm/prom.h>
-#include <asm/ans-lcd.h>
 #include <asm/io.h>
 
+#include "ans-lcd.h"
+
 #define ANSLCD_ADDR		0xf301c000
 #define ANSLCD_CTRL_IX 0x00
 #define ANSLCD_DATA_IX 0x10
diff --git a/drivers/macintosh/ans-lcd.h b/drivers/macintosh/ans-lcd.h
new file mode 100644
index 0000000..d795b9f
--- /dev/null
+++ b/drivers/macintosh/ans-lcd.h
@@ -0,0 +1,11 @@
+#ifndef _PPC_ANS_LCD_H
+#define _PPC_ANS_LCD_H
+
+#define ANSLCD_MINOR		156
+
+#define ANSLCD_CLEAR		0x01
+#define ANSLCD_SENDCTRL		0x02
+#define ANSLCD_SETSHORTDELAY	0x03
+#define ANSLCD_SETLONGDELAY	0x04
+
+#endif
diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
index 76c1e8e..33dee3a 100644
--- a/drivers/macintosh/mac_hid.c
+++ b/drivers/macintosh/mac_hid.c
@@ -13,6 +13,7 @@
 #include <linux/sysctl.h>
 #include <linux/input.h>
 #include <linux/module.h>
+#include <linux/kbd_kern.h>
 
 
 static struct input_dev *emumousebtn;
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index c96b7fe..ec9e5f3 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -365,10 +365,9 @@
 	if (np == NULL)
 		return NULL;
 
-	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev)
 		return NULL;
-	memset(dev, 0, sizeof(*dev));
 
 	dev->bus = &chip->lbus;
 	dev->media_bay = in_bay;
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c
index 4177ff0..2c21d4f 100644
--- a/drivers/macintosh/rack-meter.c
+++ b/drivers/macintosh/rack-meter.c
@@ -30,7 +30,6 @@
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
 #include <asm/dbdma.h>
-#include <asm/dbdma.h>
 #include <asm/macio.h>
 #include <asm/keylargo.h>
 
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index f8e1a13..d409f67 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -1053,10 +1053,9 @@
 	struct smu_private *pp;
 	unsigned long flags;
 
-	pp = kmalloc(sizeof(struct smu_private), GFP_KERNEL);
+	pp = kzalloc(sizeof(struct smu_private), GFP_KERNEL);
 	if (pp == 0)
 		return -ENOMEM;
-	memset(pp, 0, sizeof(struct smu_private));
 	spin_lock_init(&pp->lock);
 	pp->mode = smu_file_commands;
 	init_waitqueue_head(&pp->wait);
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index f25685b..276945d 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -379,13 +379,10 @@
 	if (thermostat)
 		return 0;
 
-	th = (struct thermostat *)
-		kmalloc(sizeof(struct thermostat), GFP_KERNEL);
-
+	th = kzalloc(sizeof(struct thermostat), GFP_KERNEL);
 	if (!th)
 		return -ENOMEM;
 
-	memset(th, 0, sizeof(*th));
 	th->clt.addr = addr;
 	th->clt.adapter = adapter;
 	th->clt.driver = &thermostat_driver;
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index dbb22403..e43554e 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -318,10 +318,9 @@
 	if (adap == NULL)
 		return NULL;
 
-	clt = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	clt = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
 	if (clt == NULL)
 		return NULL;
-	memset(clt, 0, sizeof(struct i2c_client));
 
 	clt->addr = (id >> 1) & 0x7f;
 	clt->adapter = adap;
@@ -1770,7 +1769,8 @@
 				"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
 				NULL };
 
-	return call_usermodehelper(critical_overtemp_path, argv, envp, 0);
+	return call_usermodehelper(critical_overtemp_path,
+				   argv, envp, UMH_WAIT_EXEC);
 }
 
 
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
index 3d0354e..5452da1 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -431,9 +431,8 @@
 				     | I2C_FUNC_SMBUS_WRITE_BYTE) )
 		return 0;
 
-	if( !(cl=kmalloc(sizeof(*cl), GFP_KERNEL)) )
+	if( !(cl=kzalloc(sizeof(*cl), GFP_KERNEL)) )
 		return -ENOMEM;
-	memset( cl, 0, sizeof(struct i2c_client) );
 
 	cl->addr = addr;
 	cl->adapter = adapter;
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 157080b..f7c509b 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -152,10 +152,10 @@
 static u8 pmu_intr_mask;
 static int pmu_version;
 static int drop_interrupts;
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
 static int option_lid_wakeup = 1;
-#endif /* CONFIG_PM && CONFIG_PPC32 */
-#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT_LEGACY)
+#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
+#if (defined(CONFIG_PM_SLEEP)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT_LEGACY)
 static int sleep_in_progress;
 #endif
 static unsigned long async_req_locks;
@@ -410,7 +410,7 @@
 
 	irq = irq_of_parse_and_map(vias, 0);
 	if (irq == NO_IRQ) {
-		printk(KERN_ERR "via-pmu: can't map interruptn");
+		printk(KERN_ERR "via-pmu: can't map interrupt\n");
 		return -ENODEV;
 	}
 	if (request_irq(irq, via_pmu_interrupt, 0, "VIA-PMU", (void *)0)) {
@@ -875,7 +875,7 @@
 {
 	char *p = page;
 
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
 	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);
@@ -916,7 +916,7 @@
 	*(val++) = 0;
 	while(*val == ' ')
 		val++;
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
 	if (pmu_kind == PMU_KEYLARGO_BASED &&
 	    pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
 		if (!strcmp(label, "lid_wakeup"))
@@ -1738,7 +1738,7 @@
 	return via != 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
 static LIST_HEAD(sleep_notifiers);
 
@@ -1769,9 +1769,9 @@
 	return 0;
 }
 EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
 
 /* Sleep is broadcast last-to-first */
 static void broadcast_sleep(int when)
@@ -2390,7 +2390,7 @@
 	return 0;
 }
 
-#endif /* CONFIG_PM && CONFIG_PPC32 */
+#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
 
 /*
  * Support for /dev/pmu device
@@ -2573,7 +2573,7 @@
 	int error = -EINVAL;
 
 	switch (cmd) {
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
 	case PMU_IOC_SLEEP:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EACCES;
@@ -2601,7 +2601,7 @@
 			return put_user(0, argp);
 		else
 			return put_user(1, argp);
-#endif /* CONFIG_PM && CONFIG_PPC32 */
+#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
 
 #ifdef CONFIG_PMAC_BACKLIGHT_LEGACY
 	/* Compatibility ioctl's for backlight */
@@ -2757,7 +2757,7 @@
  * to do suspend-to-disk.
  */
 
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
 
 int pmu_sys_suspended;
 
@@ -2792,7 +2792,7 @@
 	return 0;
 }
 
-#endif /* CONFIG_PM && CONFIG_PPC32 */
+#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
 
 static struct sysdev_class pmu_sysclass = {
 	set_kset_name("pmu"),
@@ -2803,10 +2803,10 @@
 };
 
 static struct sysdev_driver driver_pmu = {
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
 	.suspend	= &pmu_sys_suspend,
 	.resume		= &pmu_sys_resume,
-#endif /* CONFIG_PM && CONFIG_PPC32 */
+#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
 };
 
 static int __init init_pmu_sysfs(void)
@@ -2841,10 +2841,10 @@
 EXPORT_SYMBOL(pmu_suspend);
 EXPORT_SYMBOL(pmu_resume);
 EXPORT_SYMBOL(pmu_unlock);
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PPC32)
 EXPORT_SYMBOL(pmu_enable_irled);
 EXPORT_SYMBOL(pmu_battery_count);
 EXPORT_SYMBOL(pmu_batteries);
 EXPORT_SYMBOL(pmu_power_flags);
-#endif /* CONFIG_PM && CONFIG_PPC32 */
+#endif /* CONFIG_PM_SLEEP && CONFIG_PPC32 */
 
diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c
index dfdf11c..e2f84da 100644
--- a/drivers/macintosh/via-pmu68k.c
+++ b/drivers/macintosh/via-pmu68k.c
@@ -818,243 +818,3 @@
 {
 	return (pmu_kind != PMU_UNKNOWN);
 }
-
-#if 0 /* needs some work for 68K */
-
-/*
- * This struct is used to store config register values for
- * PCI devices which may get powered off when we sleep.
- */
-static struct pci_save {
-	u16	command;
-	u16	cache_lat;
-	u16	intr;
-} *pbook_pci_saves;
-static int n_pbook_pci_saves;
-
-static inline void
-pbook_pci_save(void)
-{
-	int npci;
-	struct pci_dev *pd = NULL;
-	struct pci_save *ps;
-
-	npci = 0;
-	while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL)
-		++npci;
-	n_pbook_pci_saves = npci;
-	if (npci == 0)
-		return;
-	ps = kmalloc(npci * sizeof(*ps), GFP_KERNEL);
-	pbook_pci_saves = ps;
-	if (ps == NULL)
-		return;
-
-	pd = NULL;
-	while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
-		pci_read_config_word(pd, PCI_COMMAND, &ps->command);
-		pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
-		pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr);
-		++ps;
-		--npci;
-	}
-}
-
-static inline void
-pbook_pci_restore(void)
-{
-	u16 cmd;
-	struct pci_save *ps = pbook_pci_saves;
-	struct pci_dev *pd = NULL;
-	int j;
-
-	while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
-		if (ps->command == 0)
-			continue;
-		pci_read_config_word(pd, PCI_COMMAND, &cmd);
-		if ((ps->command & ~cmd) == 0)
-			continue;
-		switch (pd->hdr_type) {
-		case PCI_HEADER_TYPE_NORMAL:
-			for (j = 0; j < 6; ++j)
-				pci_write_config_dword(pd,
-					PCI_BASE_ADDRESS_0 + j*4,
-					pd->resource[j].start);
-			pci_write_config_dword(pd, PCI_ROM_ADDRESS,
-			       pd->resource[PCI_ROM_RESOURCE].start);
-			pci_write_config_word(pd, PCI_CACHE_LINE_SIZE,
-				ps->cache_lat);
-			pci_write_config_word(pd, PCI_INTERRUPT_LINE,
-				ps->intr);
-			pci_write_config_word(pd, PCI_COMMAND, ps->command);
-			break;
-			/* other header types not restored at present */
-		}
-	}
-}
-
-/*
- * Put the powerbook to sleep.
- */
-#define IRQ_ENABLE	((unsigned int *)0xf3000024)
-#define MEM_CTRL	((unsigned int *)0xf8000070)
-
-int powerbook_sleep(void)
-{
-	int ret, i, x;
-	static int save_backlight;
-	static unsigned int save_irqen;
-	unsigned long msr;
-	unsigned int hid0;
-	unsigned long p, wait;
-	struct adb_request sleep_req;
-
-	/* Notify device drivers */
-	ret = blocking_notifier_call_chain(&sleep_notifier_list,
-			PBOOK_SLEEP, NULL);
-	if (ret & NOTIFY_STOP_MASK)
-		return -EBUSY;
-
-	/* Sync the disks. */
-	/* XXX It would be nice to have some way to ensure that
-	 * nobody is dirtying any new buffers while we wait. */
-	sys_sync();
-
-	/* Turn off the display backlight */
-	save_backlight = backlight_enabled;
-	if (save_backlight)
-		pmu_enable_backlight(0);
-
-	/* Give the disks a little time to actually finish writing */
-	for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
-		mb();
-
-	/* Disable all interrupts except pmu */
-	save_irqen = in_le32(IRQ_ENABLE);
-	for (i = 0; i < 32; ++i)
-		if (i != vias->intrs[0].line && (save_irqen & (1 << i)))
-			disable_irq(i);
-	asm volatile("mtdec %0" : : "r" (0x7fffffff));
-
-	/* Save the state of PCI config space for some slots */
-	pbook_pci_save();
-
-	/* Set the memory controller to keep the memory refreshed
-	   while we're asleep */
-	for (i = 0x403f; i >= 0x4000; --i) {
-		out_be32(MEM_CTRL, i);
-		do {
-			x = (in_be32(MEM_CTRL) >> 16) & 0x3ff;
-		} while (x == 0);
-		if (x >= 0x100)
-			break;
-	}
-
-	/* Ask the PMU to put us to sleep */
-	pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
-	while (!sleep_req.complete)
-		mb();
-	/* displacement-flush the L2 cache - necessary? */
-	for (p = KERNELBASE; p < KERNELBASE + 0x100000; p += 0x1000)
-		i = *(volatile int *)p;
-	asleep = 1;
-
-	/* Put the CPU into sleep mode */
-	asm volatile("mfspr %0,1008" : "=r" (hid0) :);
-	hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;
-	asm volatile("mtspr 1008,%0" : : "r" (hid0));
-	local_save_flags(msr);
-	msr |= MSR_POW | MSR_EE;
-	local_irq_restore(msr);
-	udelay(10);
-
-	/* OK, we're awake again, start restoring things */
-	out_be32(MEM_CTRL, 0x3f);
-	pbook_pci_restore();
-
-	/* wait for the PMU interrupt sequence to complete */
-	while (asleep)
-		mb();
-
-	/* reenable interrupts */
-	for (i = 0; i < 32; ++i)
-		if (i != vias->intrs[0].line && (save_irqen & (1 << i)))
-			enable_irq(i);
-
-	/* Notify drivers */
-	blocking_notifier_call_chain(&sleep_notifier_list, PBOOK_WAKE, NULL);
-
-	/* reenable ADB autopoll */
-	pmu_adb_autopoll(adb_dev_map);
-
-	/* Turn on the screen backlight, if it was on before */
-	if (save_backlight)
-		pmu_enable_backlight(1);
-
-	/* Wait for the hard disk to spin up */
-
-	return 0;
-}
-
-/*
- * Support for /dev/pmu device
- */
-static int pmu_open(struct inode *inode, struct file *file)
-{
-	return 0;
-}
-
-static ssize_t pmu_read(struct file *file, char *buf,
-			size_t count, loff_t *ppos)
-{
-	return 0;
-}
-
-static ssize_t pmu_write(struct file *file, const char *buf,
-			 size_t count, loff_t *ppos)
-{
-	return 0;
-}
-
-static int pmu_ioctl(struct inode * inode, struct file *filp,
-		     u_int cmd, u_long arg)
-{
-	int error;
-	__u32 value;
-
-	switch (cmd) {
-	    case PMU_IOC_SLEEP:
-	    	return -ENOSYS;
-	    case PMU_IOC_GET_BACKLIGHT:
-		return put_user(backlight_level, (__u32 *)arg);
-	    case PMU_IOC_SET_BACKLIGHT:
-		error = get_user(value, (__u32 *)arg);
-		if (!error)
-			pmu_set_brightness(value);
-		return error;
-	    case PMU_IOC_GET_MODEL:
-	    	return put_user(pmu_kind, (__u32 *)arg);
-	}
-	return -EINVAL;
-}
-
-static const struct file_operations pmu_device_fops = {
-	.read		= pmu_read,
-	.write		= pmu_write,
-	.ioctl		= pmu_ioctl,
-	.open		= pmu_open,
-};
-
-static struct miscdevice pmu_device = {
-	PMU_MINOR, "pmu", &pmu_device_fops
-};
-
-void pmu_device_init(void)
-{
-	if (!via)
-		return;
-	if (misc_register(&pmu_device) < 0)
-		printk(KERN_ERR "via-pmu68k: cannot register misc device.\n");
-}
-#endif /* CONFIG_PMAC_PBOOK */
-
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
index e18d265..516d943 100644
--- a/drivers/macintosh/windfarm_core.c
+++ b/drivers/macintosh/windfarm_core.c
@@ -80,7 +80,8 @@
 				"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
 				NULL };
 
-	return call_usermodehelper(critical_overtemp_path, argv, envp, 0);
+	return call_usermodehelper(critical_overtemp_path,
+				   argv, envp, UMH_WAIT_EXEC);
 }
 EXPORT_SYMBOL_GPL(wf_critical_overtemp);
 
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index a0fabf3..7e10c3a 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -117,10 +117,9 @@
 	DBG("wf_lm75: creating  %s device at address 0x%02x\n",
 	    ds1775 ? "ds1775" : "lm75", addr);
 
-	lm = kmalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
+	lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
 	if (lm == NULL)
 		return NULL;
-	memset(lm, 0, sizeof(struct wf_lm75_sensor));
 
 	/* Usual rant about sensor names not beeing very consistent in
 	 * the device-tree, oh well ...
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index 351982b..f449d77 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -380,10 +380,12 @@
 	return i2c_add_driver(&wf_sat_driver);
 }
 
+#if 0	/* uncomment when module_exit() below is uncommented */
 static void __exit sat_sensors_exit(void)
 {
 	i2c_del_driver(&wf_sat_driver);
 }
+#endif
 
 module_init(sat_sensors_init);
 /*module_exit(sat_sensors_exit); Uncomment when cleanup is implemented */
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 531d4d1..34a8c60 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -263,7 +263,7 @@
 
 config DM_MULTIPATH_RDAC
 	tristate "LSI/Engenio RDAC multipath support (EXPERIMENTAL)"
-	depends on DM_MULTIPATH && BLK_DEV_DM && EXPERIMENTAL
+	depends on DM_MULTIPATH && BLK_DEV_DM && SCSI && EXPERIMENTAL
 	---help---
 	  Multipath support for LSI/Engenio RDAC.
 
diff --git a/drivers/md/dm-bio-list.h b/drivers/md/dm-bio-list.h
index 16ee3b0..3f7b827 100644
--- a/drivers/md/dm-bio-list.h
+++ b/drivers/md/dm-bio-list.h
@@ -9,6 +9,8 @@
 
 #include <linux/bio.h>
 
+#ifdef CONFIG_BLOCK
+
 struct bio_list {
 	struct bio *head;
 	struct bio *tail;
@@ -106,4 +108,5 @@
 	return bio;
 }
 
+#endif /* CONFIG_BLOCK */
 #endif
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index ba952a0..8216a6f 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -489,7 +489,7 @@
 	if (!atomic_dec_and_test(&io->pending))
 		return;
 
-	bio_endio(io->base_bio, io->base_bio->bi_size, io->error);
+	bio_endio(io->base_bio, io->error);
 
 	mempool_free(io, cc->io_pool);
 }
@@ -509,25 +509,19 @@
 	queue_work(_kcryptd_workqueue, &io->work);
 }
 
-static int crypt_endio(struct bio *clone, unsigned int done, int error)
+static void crypt_endio(struct bio *clone, int error)
 {
 	struct dm_crypt_io *io = clone->bi_private;
 	struct crypt_config *cc = io->target->private;
 	unsigned read_io = bio_data_dir(clone) == READ;
 
 	/*
-	 * free the processed pages, even if
-	 * it's only a partially completed write
+	 * free the processed pages
 	 */
-	if (!read_io)
-		crypt_free_buffer_pages(cc, clone, done);
-
-	/* keep going - not finished yet */
-	if (unlikely(clone->bi_size))
-		return 1;
-
-	if (!read_io)
+	if (!read_io) {
+		crypt_free_buffer_pages(cc, clone, clone->bi_size);
 		goto out;
+	}
 
 	if (unlikely(!bio_flagged(clone, BIO_UPTODATE))) {
 		error = -EIO;
@@ -537,12 +531,11 @@
 	bio_put(clone);
 	io->post_process = 1;
 	kcryptd_queue_io(io);
-	return 0;
+	return;
 
 out:
 	bio_put(clone);
 	dec_pending(io, error);
-	return error;
 }
 
 static void clone_init(struct dm_crypt_io *io, struct bio *clone)
@@ -920,6 +913,8 @@
 {
 	struct crypt_config *cc = (struct crypt_config *) ti->private;
 
+	flush_workqueue(_kcryptd_workqueue);
+
 	bioset_free(cc->bs);
 	mempool_destroy(cc->page_pool);
 	mempool_destroy(cc->io_pool);
diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c
index 265c467..a2191a4 100644
--- a/drivers/md/dm-emc.c
+++ b/drivers/md/dm-emc.c
@@ -38,13 +38,10 @@
 	bio_put(bio);
 }
 
-static int emc_endio(struct bio *bio, unsigned int bytes_done, int error)
+static void emc_endio(struct bio *bio, int error)
 {
 	struct dm_path *path = bio->bi_private;
 
-	if (bio->bi_size)
-		return 1;
-
 	/* We also need to look at the sense keys here whether or not to
 	 * switch to the next PG etc.
 	 *
@@ -109,15 +106,7 @@
 		return NULL;
 	}
 
-	rq->bio = rq->biotail = bio;
-	blk_rq_bio_prep(q, rq, bio);
-
-	rq->rq_disk = bdev->bd_contains->bd_disk;
-
-	/* bio backed don't set data */
-	rq->buffer = rq->data = NULL;
-	/* rq data_len used for pc cmd's request_bufflen */
-	rq->data_len = bio->bi_size;
+	blk_rq_append_bio(q, rq, bio);
 
 	rq->sense = h->sense;
 	memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 3d65917..8fe81e1 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -623,6 +623,7 @@
 
 	ps->metadata_wq = create_singlethread_workqueue("ksnaphd");
 	if (!ps->metadata_wq) {
+		kfree(ps);
 		DMERR("couldn't start header metadata update thread");
 		return -ENOMEM;
 	}
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index f3a7724..b8e342f 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -124,15 +124,11 @@
 	}
 }
 
-static int endio(struct bio *bio, unsigned int done, int error)
+static void endio(struct bio *bio, int error)
 {
 	struct io *io;
 	unsigned region;
 
-	/* keep going until we've finished */
-	if (bio->bi_size)
-		return 1;
-
 	if (error && bio_data_dir(bio) == READ)
 		zero_fill_bio(bio);
 
@@ -146,8 +142,6 @@
 	bio_put(bio);
 
 	dec_count(io, region, error);
-
-	return 0;
 }
 
 /*-----------------------------------------------------------------
diff --git a/drivers/md/dm-mpath-rdac.c b/drivers/md/dm-mpath-rdac.c
index 8b776b8..16b1613 100644
--- a/drivers/md/dm-mpath-rdac.c
+++ b/drivers/md/dm-mpath-rdac.c
@@ -292,7 +292,7 @@
 	rq->end_io_data = h;
 	rq->timeout = h->timeout;
 	rq->cmd_type = REQ_TYPE_BLOCK_PC;
-	rq->cmd_flags = REQ_FAILFAST | REQ_NOMERGE;
+	rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
 	return rq;
 }
 
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index d6ca9d0..31056ab 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -390,11 +390,11 @@
 
 		r = map_io(m, bio, mpio, 1);
 		if (r < 0)
-			bio_endio(bio, bio->bi_size, r);
+			bio_endio(bio, r);
 		else if (r == DM_MAPIO_REMAPPED)
 			generic_make_request(bio);
 		else if (r == DM_MAPIO_REQUEUE)
-			bio_endio(bio, bio->bi_size, -EIO);
+			bio_endio(bio, -EIO);
 
 		bio = next;
 	}
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 1a876f9..d09ff15 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -820,7 +820,7 @@
 				break;
 			}
 	}
-	bio_endio(bio, bio->bi_size, 0);
+	bio_endio(bio, 0);
 }
 
 static void do_write(struct mirror_set *ms, struct bio *bio)
@@ -900,7 +900,7 @@
 	 */
 	if (unlikely(ms->log_failure))
 		while ((bio = bio_list_pop(&sync)))
-			bio_endio(bio, bio->bi_size, -EIO);
+			bio_endio(bio, -EIO);
 	else while ((bio = bio_list_pop(&sync)))
 		do_write(ms, bio);
 
@@ -951,13 +951,12 @@
 
 	len = sizeof(*ms) + (sizeof(ms->mirror[0]) * nr_mirrors);
 
-	ms = kmalloc(len, GFP_KERNEL);
+	ms = kzalloc(len, GFP_KERNEL);
 	if (!ms) {
 		ti->error = "Cannot allocate mirror context";
 		return NULL;
 	}
 
-	memset(ms, 0, len);
 	spin_lock_init(&ms->lock);
 
 	ms->ti = ti;
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 83ddbfe..98a633f 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -636,7 +636,7 @@
 	while (bio) {
 		n = bio->bi_next;
 		bio->bi_next = NULL;
-		bio_io_error(bio, bio->bi_size);
+		bio_io_error(bio);
 		bio = n;
 	}
 }
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 2fc199b..2bcde57 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -526,7 +526,7 @@
 
 void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev)
 {
-	request_queue_t *q = bdev_get_queue(bdev);
+	struct request_queue *q = bdev_get_queue(bdev);
 	struct io_restrictions *rs = &ti->limits;
 
 	/*
@@ -979,7 +979,7 @@
 	devices = dm_table_get_devices(t);
 	for (d = devices->next; d != devices; d = d->next) {
 		struct dm_dev *dd = list_entry(d, struct dm_dev, list);
-		request_queue_t *q = bdev_get_queue(dd->bdev);
+		struct request_queue *q = bdev_get_queue(dd->bdev);
 		r |= bdi_congested(&q->backing_dev_info, bdi_bits);
 	}
 
@@ -992,7 +992,7 @@
 
 	for (d = devices->next; d != devices; d = d->next) {
 		struct dm_dev *dd = list_entry(d, struct dm_dev, list);
-		request_queue_t *q = bdev_get_queue(dd->bdev);
+		struct request_queue *q = bdev_get_queue(dd->bdev);
 
 		if (q->unplug_fn)
 			q->unplug_fn(q);
@@ -1011,7 +1011,7 @@
 
 	for (d = devices->next; d != devices; d = d->next) {
 		struct dm_dev *dd = list_entry(d, struct dm_dev, list);
-		request_queue_t *q = bdev_get_queue(dd->bdev);
+		struct request_queue *q = bdev_get_queue(dd->bdev);
 		int err;
 
 		if (!q->issue_flush_fn)
diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c
index f314d7d..bdec206 100644
--- a/drivers/md/dm-zero.c
+++ b/drivers/md/dm-zero.c
@@ -43,7 +43,7 @@
 		break;
 	}
 
-	bio_endio(bio, bio->bi_size, 0);
+	bio_endio(bio, 0);
 
 	/* accepted bio, don't make new request */
 	return DM_MAPIO_SUBMITTED;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 846614e..167765c 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -80,7 +80,7 @@
 
 	unsigned long flags;
 
-	request_queue_t *queue;
+	struct request_queue *queue;
 	struct gendisk *disk;
 	char name[16];
 
@@ -484,23 +484,20 @@
 			blk_add_trace_bio(io->md->queue, io->bio,
 					  BLK_TA_COMPLETE);
 
-			bio_endio(io->bio, io->bio->bi_size, io->error);
+			bio_endio(io->bio, io->error);
 		}
 
 		free_io(io->md, io);
 	}
 }
 
-static int clone_endio(struct bio *bio, unsigned int done, int error)
+static void clone_endio(struct bio *bio, int error)
 {
 	int r = 0;
 	struct dm_target_io *tio = bio->bi_private;
 	struct mapped_device *md = tio->io->md;
 	dm_endio_fn endio = tio->ti->type->end_io;
 
-	if (bio->bi_size)
-		return 1;
-
 	if (!bio_flagged(bio, BIO_UPTODATE) && !error)
 		error = -EIO;
 
@@ -514,7 +511,7 @@
 			error = r;
 		else if (r == DM_ENDIO_INCOMPLETE)
 			/* The target will handle the io */
-			return 1;
+			return;
 		else if (r) {
 			DMWARN("unimplemented target endio return value: %d", r);
 			BUG();
@@ -530,7 +527,6 @@
 
 	bio_put(bio);
 	free_tio(md, tio);
-	return r;
 }
 
 static sector_t max_io_len(struct mapped_device *md,
@@ -580,8 +576,8 @@
 		/* the bio has been remapped so dispatch it */
 
 		blk_add_trace_remap(bdev_get_queue(clone->bi_bdev), clone,
-				    tio->io->bio->bi_bdev->bd_dev, sector,
-				    clone->bi_sector);
+				    tio->io->bio->bi_bdev->bd_dev,
+				    clone->bi_sector, sector);
 
 		generic_make_request(clone);
 	} else if (r < 0 || r == DM_MAPIO_REQUEUE) {
@@ -761,7 +757,7 @@
 
 	ci.map = dm_get_table(md);
 	if (!ci.map) {
-		bio_io_error(bio, bio->bi_size);
+		bio_io_error(bio);
 		return;
 	}
 
@@ -792,7 +788,7 @@
  * The request function that just remaps the bio built up by
  * dm_merge_bvec.
  */
-static int dm_request(request_queue_t *q, struct bio *bio)
+static int dm_request(struct request_queue *q, struct bio *bio)
 {
 	int r;
 	int rw = bio_data_dir(bio);
@@ -803,7 +799,7 @@
 	 * guarantee it is (or can be) handled by the targets correctly.
 	 */
 	if (unlikely(bio_barrier(bio))) {
-		bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+		bio_endio(bio, -EOPNOTSUPP);
 		return 0;
 	}
 
@@ -820,13 +816,13 @@
 		up_read(&md->io_lock);
 
 		if (bio_rw(bio) == READA) {
-			bio_io_error(bio, bio->bi_size);
+			bio_io_error(bio);
 			return 0;
 		}
 
 		r = queue_io(md, bio);
 		if (r < 0) {
-			bio_io_error(bio, bio->bi_size);
+			bio_io_error(bio);
 			return 0;
 
 		} else if (r == 0)
@@ -844,7 +840,7 @@
 	return 0;
 }
 
-static int dm_flush_all(request_queue_t *q, struct gendisk *disk,
+static int dm_flush_all(struct request_queue *q, struct gendisk *disk,
 			sector_t *error_sector)
 {
 	struct mapped_device *md = q->queuedata;
@@ -859,7 +855,7 @@
 	return ret;
 }
 
-static void dm_unplug_all(request_queue_t *q)
+static void dm_unplug_all(struct request_queue *q)
 {
 	struct mapped_device *md = q->queuedata;
 	struct dm_table *map = dm_get_table(md);
@@ -1110,7 +1106,7 @@
 
 static int __bind(struct mapped_device *md, struct dm_table *t)
 {
-	request_queue_t *q = md->queue;
+	struct request_queue *q = md->queue;
 	sector_t size;
 
 	size = dm_table_get_size(t);
diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c
index 4ebd0f2..cf2ddce 100644
--- a/drivers/md/faulty.c
+++ b/drivers/md/faulty.c
@@ -65,18 +65,16 @@
 #include <linux/raid/md.h>
 
 
-static int faulty_fail(struct bio *bio, unsigned int bytes_done, int error)
+static void faulty_fail(struct bio *bio, int error)
 {
 	struct bio *b = bio->bi_private;
 
 	b->bi_size = bio->bi_size;
 	b->bi_sector = bio->bi_sector;
 
-	if (bio->bi_size == 0)
-		bio_put(bio);
+	bio_put(bio);
 
-	clear_bit(BIO_UPTODATE, &b->bi_flags);
-	return (b->bi_end_io)(b, bytes_done, -EIO);
+	bio_io_error(b);
 }
 
 typedef struct faulty_conf {
@@ -167,7 +165,7 @@
 		conf->nfaults = n+1;
 }
 
-static int make_request(request_queue_t *q, struct bio *bio)
+static int make_request(struct request_queue *q, struct bio *bio)
 {
 	mddev_t *mddev = q->queuedata;
 	conf_t *conf = (conf_t*)mddev->private;
@@ -179,7 +177,7 @@
 			/* special case - don't decrement, don't generic_make_request,
 			 * just fail immediately
 			 */
-			bio_endio(bio, bio->bi_size, -EIO);
+			bio_endio(bio, -EIO);
 			return 0;
 		}
 
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 1927410..5501487 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -55,7 +55,7 @@
  *
  *	Return amount of bytes we can take at this offset
  */
-static int linear_mergeable_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *biovec)
+static int linear_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec)
 {
 	mddev_t *mddev = q->queuedata;
 	dev_info_t *dev0;
@@ -79,20 +79,20 @@
 	return maxsectors << 9;
 }
 
-static void linear_unplug(request_queue_t *q)
+static void linear_unplug(struct request_queue *q)
 {
 	mddev_t *mddev = q->queuedata;
 	linear_conf_t *conf = mddev_to_conf(mddev);
 	int i;
 
 	for (i=0; i < mddev->raid_disks; i++) {
-		request_queue_t *r_queue = bdev_get_queue(conf->disks[i].rdev->bdev);
+		struct request_queue *r_queue = bdev_get_queue(conf->disks[i].rdev->bdev);
 		if (r_queue->unplug_fn)
 			r_queue->unplug_fn(r_queue);
 	}
 }
 
-static int linear_issue_flush(request_queue_t *q, struct gendisk *disk,
+static int linear_issue_flush(struct request_queue *q, struct gendisk *disk,
 			      sector_t *error_sector)
 {
 	mddev_t *mddev = q->queuedata;
@@ -101,7 +101,7 @@
 
 	for (i=0; i < mddev->raid_disks && ret == 0; i++) {
 		struct block_device *bdev = conf->disks[i].rdev->bdev;
-		request_queue_t *r_queue = bdev_get_queue(bdev);
+		struct request_queue *r_queue = bdev_get_queue(bdev);
 
 		if (!r_queue->issue_flush_fn)
 			ret = -EOPNOTSUPP;
@@ -118,7 +118,7 @@
 	int i, ret = 0;
 
 	for (i = 0; i < mddev->raid_disks && !ret ; i++) {
-		request_queue_t *q = bdev_get_queue(conf->disks[i].rdev->bdev);
+		struct request_queue *q = bdev_get_queue(conf->disks[i].rdev->bdev);
 		ret |= bdi_congested(&q->backing_dev_info, bits);
 	}
 	return ret;
@@ -330,7 +330,7 @@
 	return 0;
 }
 
-static int linear_make_request (request_queue_t *q, struct bio *bio)
+static int linear_make_request (struct request_queue *q, struct bio *bio)
 {
 	const int rw = bio_data_dir(bio);
 	mddev_t *mddev = q->queuedata;
@@ -338,7 +338,7 @@
 	sector_t block;
 
 	if (unlikely(bio_barrier(bio))) {
-		bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+		bio_endio(bio, -EOPNOTSUPP);
 		return 0;
 	}
 
@@ -358,7 +358,7 @@
 			bdevname(tmp_dev->rdev->bdev, b),
 			(unsigned long long)tmp_dev->size,
 		        (unsigned long long)tmp_dev->offset);
-		bio_io_error(bio, bio->bi_size);
+		bio_io_error(bio);
 		return 0;
 	}
 	if (unlikely(bio->bi_sector + (bio->bi_size >> 9) >
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 65ddc88..acf1b81 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -211,9 +211,9 @@
 		)
 
 
-static int md_fail_request (request_queue_t *q, struct bio *bio)
+static int md_fail_request (struct request_queue *q, struct bio *bio)
 {
-	bio_io_error(bio, bio->bi_size);
+	bio_io_error(bio);
 	return 0;
 }
 
@@ -384,12 +384,10 @@
 }
 
 
-static int super_written(struct bio *bio, unsigned int bytes_done, int error)
+static void super_written(struct bio *bio, int error)
 {
 	mdk_rdev_t *rdev = bio->bi_private;
 	mddev_t *mddev = rdev->mddev;
-	if (bio->bi_size)
-		return 1;
 
 	if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags)) {
 		printk("md: super_written gets error=%d, uptodate=%d\n",
@@ -401,16 +399,13 @@
 	if (atomic_dec_and_test(&mddev->pending_writes))
 		wake_up(&mddev->sb_wait);
 	bio_put(bio);
-	return 0;
 }
 
-static int super_written_barrier(struct bio *bio, unsigned int bytes_done, int error)
+static void super_written_barrier(struct bio *bio, int error)
 {
 	struct bio *bio2 = bio->bi_private;
 	mdk_rdev_t *rdev = bio2->bi_private;
 	mddev_t *mddev = rdev->mddev;
-	if (bio->bi_size)
-		return 1;
 
 	if (!test_bit(BIO_UPTODATE, &bio->bi_flags) &&
 	    error == -EOPNOTSUPP) {
@@ -424,11 +419,11 @@
 		spin_unlock_irqrestore(&mddev->write_lock, flags);
 		wake_up(&mddev->sb_wait);
 		bio_put(bio);
-		return 0;
+	} else {
+		bio_put(bio2);
+		bio->bi_private = rdev;
+		super_written(bio, error);
 	}
-	bio_put(bio2);
-	bio->bi_private = rdev;
-	return super_written(bio, bytes_done, error);
 }
 
 void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
@@ -489,13 +484,9 @@
 	finish_wait(&mddev->sb_wait, &wq);
 }
 
-static int bi_complete(struct bio *bio, unsigned int bytes_done, int error)
+static void bi_complete(struct bio *bio, int error)
 {
-	if (bio->bi_size)
-		return 1;
-
 	complete((struct completion*)bio->bi_private);
-	return 0;
 }
 
 int sync_page_io(struct block_device *bdev, sector_t sector, int size,
@@ -3085,8 +3076,7 @@
 	mddev->gendisk = disk;
 	mutex_unlock(&disks_mutex);
 	mddev->kobj.parent = &disk->kobj;
-	mddev->kobj.k_name = NULL;
-	snprintf(mddev->kobj.name, KOBJ_NAME_LEN, "%s", "md");
+	kobject_set_name(&mddev->kobj, "%s", "md");
 	mddev->kobj.ktype = &md_ktype;
 	if (kobject_register(&mddev->kobj))
 		printk(KERN_WARNING "md: cannot register %s/md - name in use\n",
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 14da37f..f2a63f3 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -82,21 +82,17 @@
 	struct bio *bio = mp_bh->master_bio;
 	multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev);
 
-	bio_endio(bio, bio->bi_size, err);
+	bio_endio(bio, err);
 	mempool_free(mp_bh, conf->pool);
 }
 
-static int multipath_end_request(struct bio *bio, unsigned int bytes_done,
-				 int error)
+static void multipath_end_request(struct bio *bio, int error)
 {
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	struct multipath_bh * mp_bh = (struct multipath_bh *)(bio->bi_private);
 	multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev);
 	mdk_rdev_t *rdev = conf->multipaths[mp_bh->path].rdev;
 
-	if (bio->bi_size)
-		return 1;
-
 	if (uptodate)
 		multipath_end_bh_io(mp_bh, 0);
 	else if (!bio_rw_ahead(bio)) {
@@ -112,7 +108,6 @@
 	} else
 		multipath_end_bh_io(mp_bh, error);
 	rdev_dec_pending(rdev, conf->mddev);
-	return 0;
 }
 
 static void unplug_slaves(mddev_t *mddev)
@@ -125,7 +120,7 @@
 		mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
 		if (rdev && !test_bit(Faulty, &rdev->flags)
 		    && atomic_read(&rdev->nr_pending)) {
-			request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
+			struct request_queue *r_queue = bdev_get_queue(rdev->bdev);
 
 			atomic_inc(&rdev->nr_pending);
 			rcu_read_unlock();
@@ -140,13 +135,13 @@
 	rcu_read_unlock();
 }
 
-static void multipath_unplug(request_queue_t *q)
+static void multipath_unplug(struct request_queue *q)
 {
 	unplug_slaves(q->queuedata);
 }
 
 
-static int multipath_make_request (request_queue_t *q, struct bio * bio)
+static int multipath_make_request (struct request_queue *q, struct bio * bio)
 {
 	mddev_t *mddev = q->queuedata;
 	multipath_conf_t *conf = mddev_to_conf(mddev);
@@ -155,7 +150,7 @@
 	const int rw = bio_data_dir(bio);
 
 	if (unlikely(bio_barrier(bio))) {
-		bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+		bio_endio(bio, -EOPNOTSUPP);
 		return 0;
 	}
 
@@ -169,7 +164,7 @@
 
 	mp_bh->path = multipath_map(conf);
 	if (mp_bh->path < 0) {
-		bio_endio(bio, bio->bi_size, -EIO);
+		bio_endio(bio, -EIO);
 		mempool_free(mp_bh, conf->pool);
 		return 0;
 	}
@@ -199,7 +194,7 @@
 	seq_printf (seq, "]");
 }
 
-static int multipath_issue_flush(request_queue_t *q, struct gendisk *disk,
+static int multipath_issue_flush(struct request_queue *q, struct gendisk *disk,
 				 sector_t *error_sector)
 {
 	mddev_t *mddev = q->queuedata;
@@ -211,7 +206,7 @@
 		mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
 		if (rdev && !test_bit(Faulty, &rdev->flags)) {
 			struct block_device *bdev = rdev->bdev;
-			request_queue_t *r_queue = bdev_get_queue(bdev);
+			struct request_queue *r_queue = bdev_get_queue(bdev);
 
 			if (!r_queue->issue_flush_fn)
 				ret = -EOPNOTSUPP;
@@ -238,7 +233,7 @@
 	for (i = 0; i < mddev->raid_disks ; i++) {
 		mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
 		if (rdev && !test_bit(Faulty, &rdev->flags)) {
-			request_queue_t *q = bdev_get_queue(rdev->bdev);
+			struct request_queue *q = bdev_get_queue(rdev->bdev);
 
 			ret |= bdi_congested(&q->backing_dev_info, bits);
 			/* Just like multipath_map, we just check the
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 2c404f7..ef0da2d 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -25,7 +25,7 @@
 #define MD_DRIVER
 #define MD_PERSONALITY
 
-static void raid0_unplug(request_queue_t *q)
+static void raid0_unplug(struct request_queue *q)
 {
 	mddev_t *mddev = q->queuedata;
 	raid0_conf_t *conf = mddev_to_conf(mddev);
@@ -33,14 +33,14 @@
 	int i;
 
 	for (i=0; i<mddev->raid_disks; i++) {
-		request_queue_t *r_queue = bdev_get_queue(devlist[i]->bdev);
+		struct request_queue *r_queue = bdev_get_queue(devlist[i]->bdev);
 
 		if (r_queue->unplug_fn)
 			r_queue->unplug_fn(r_queue);
 	}
 }
 
-static int raid0_issue_flush(request_queue_t *q, struct gendisk *disk,
+static int raid0_issue_flush(struct request_queue *q, struct gendisk *disk,
 			     sector_t *error_sector)
 {
 	mddev_t *mddev = q->queuedata;
@@ -50,7 +50,7 @@
 
 	for (i=0; i<mddev->raid_disks && ret == 0; i++) {
 		struct block_device *bdev = devlist[i]->bdev;
-		request_queue_t *r_queue = bdev_get_queue(bdev);
+		struct request_queue *r_queue = bdev_get_queue(bdev);
 
 		if (!r_queue->issue_flush_fn)
 			ret = -EOPNOTSUPP;
@@ -68,7 +68,7 @@
 	int i, ret = 0;
 
 	for (i = 0; i < mddev->raid_disks && !ret ; i++) {
-		request_queue_t *q = bdev_get_queue(devlist[i]->bdev);
+		struct request_queue *q = bdev_get_queue(devlist[i]->bdev);
 
 		ret |= bdi_congested(&q->backing_dev_info, bits);
 	}
@@ -268,7 +268,7 @@
  *
  *	Return amount of bytes we can accept at this offset
  */
-static int raid0_mergeable_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *biovec)
+static int raid0_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec)
 {
 	mddev_t *mddev = q->queuedata;
 	sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev);
@@ -408,7 +408,7 @@
 	return 0;
 }
 
-static int raid0_make_request (request_queue_t *q, struct bio *bio)
+static int raid0_make_request (struct request_queue *q, struct bio *bio)
 {
 	mddev_t *mddev = q->queuedata;
 	unsigned int sect_in_chunk, chunksize_bits,  chunk_size, chunk_sects;
@@ -420,7 +420,7 @@
 	const int rw = bio_data_dir(bio);
 
 	if (unlikely(bio_barrier(bio))) {
-		bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+		bio_endio(bio, -EOPNOTSUPP);
 		return 0;
 	}
 
@@ -490,7 +490,7 @@
 		" or bigger than %dk %llu %d\n", chunk_size, 
 		(unsigned long long)bio->bi_sector, bio->bi_size >> 10);
 
-	bio_io_error(bio, bio->bi_size);
+	bio_io_error(bio);
 	return 0;
 }
 			   
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 00c78b7..6d03bea 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -238,7 +238,7 @@
 			(unsigned long long) bio->bi_sector +
 				(bio->bi_size >> 9) - 1);
 
-		bio_endio(bio, bio->bi_size,
+		bio_endio(bio,
 			test_bit(R1BIO_Uptodate, &r1_bio->state) ? 0 : -EIO);
 	}
 	free_r1bio(r1_bio);
@@ -255,16 +255,13 @@
 		r1_bio->sector + (r1_bio->sectors);
 }
 
-static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int error)
+static void raid1_end_read_request(struct bio *bio, int error)
 {
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
 	int mirror;
 	conf_t *conf = mddev_to_conf(r1_bio->mddev);
 
-	if (bio->bi_size)
-		return 1;
-	
 	mirror = r1_bio->read_disk;
 	/*
 	 * this branch is our 'one mirror IO has finished' event handler:
@@ -301,10 +298,9 @@
 	}
 
 	rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev);
-	return 0;
 }
 
-static int raid1_end_write_request(struct bio *bio, unsigned int bytes_done, int error)
+static void raid1_end_write_request(struct bio *bio, int error)
 {
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
@@ -312,8 +308,6 @@
 	conf_t *conf = mddev_to_conf(r1_bio->mddev);
 	struct bio *to_put = NULL;
 
-	if (bio->bi_size)
-		return 1;
 
 	for (mirror = 0; mirror < conf->raid_disks; mirror++)
 		if (r1_bio->bios[mirror] == bio)
@@ -366,7 +360,7 @@
 					       (unsigned long long) mbio->bi_sector,
 					       (unsigned long long) mbio->bi_sector +
 					       (mbio->bi_size >> 9) - 1);
-					bio_endio(mbio, mbio->bi_size, 0);
+					bio_endio(mbio, 0);
 				}
 			}
 		}
@@ -400,8 +394,6 @@
 
 	if (to_put)
 		bio_put(to_put);
-
-	return 0;
 }
 
 
@@ -552,7 +544,7 @@
 	for (i=0; i<mddev->raid_disks; i++) {
 		mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
 		if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
-			request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
+			struct request_queue *r_queue = bdev_get_queue(rdev->bdev);
 
 			atomic_inc(&rdev->nr_pending);
 			rcu_read_unlock();
@@ -567,7 +559,7 @@
 	rcu_read_unlock();
 }
 
-static void raid1_unplug(request_queue_t *q)
+static void raid1_unplug(struct request_queue *q)
 {
 	mddev_t *mddev = q->queuedata;
 
@@ -575,7 +567,7 @@
 	md_wakeup_thread(mddev->thread);
 }
 
-static int raid1_issue_flush(request_queue_t *q, struct gendisk *disk,
+static int raid1_issue_flush(struct request_queue *q, struct gendisk *disk,
 			     sector_t *error_sector)
 {
 	mddev_t *mddev = q->queuedata;
@@ -587,7 +579,7 @@
 		mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
 		if (rdev && !test_bit(Faulty, &rdev->flags)) {
 			struct block_device *bdev = rdev->bdev;
-			request_queue_t *r_queue = bdev_get_queue(bdev);
+			struct request_queue *r_queue = bdev_get_queue(bdev);
 
 			if (!r_queue->issue_flush_fn)
 				ret = -EOPNOTSUPP;
@@ -615,7 +607,7 @@
 	for (i = 0; i < mddev->raid_disks; i++) {
 		mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
 		if (rdev && !test_bit(Faulty, &rdev->flags)) {
-			request_queue_t *q = bdev_get_queue(rdev->bdev);
+			struct request_queue *q = bdev_get_queue(rdev->bdev);
 
 			/* Note the '|| 1' - when read_balance prefers
 			 * non-congested targets, it can be removed
@@ -765,7 +757,7 @@
 	return NULL;
 }
 
-static int make_request(request_queue_t *q, struct bio * bio)
+static int make_request(struct request_queue *q, struct bio * bio)
 {
 	mddev_t *mddev = q->queuedata;
 	conf_t *conf = mddev_to_conf(mddev);
@@ -796,7 +788,7 @@
 	if (unlikely(!mddev->barriers_work && bio_barrier(bio))) {
 		if (rw == WRITE)
 			md_write_end(mddev);
-		bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+		bio_endio(bio, -EOPNOTSUPP);
 		return 0;
 	}
 
@@ -1137,14 +1129,11 @@
 }
 
 
-static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
+static void end_sync_read(struct bio *bio, int error)
 {
 	r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
 	int i;
 
-	if (bio->bi_size)
-		return 1;
-
 	for (i=r1_bio->mddev->raid_disks; i--; )
 		if (r1_bio->bios[i] == bio)
 			break;
@@ -1160,10 +1149,9 @@
 
 	if (atomic_dec_and_test(&r1_bio->remaining))
 		reschedule_retry(r1_bio);
-	return 0;
 }
 
-static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
+static void end_sync_write(struct bio *bio, int error)
 {
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private);
@@ -1172,9 +1160,6 @@
 	int i;
 	int mirror=0;
 
-	if (bio->bi_size)
-		return 1;
-
 	for (i = 0; i < conf->raid_disks; i++)
 		if (r1_bio->bios[i] == bio) {
 			mirror = i;
@@ -1200,7 +1185,6 @@
 		md_done_sync(mddev, r1_bio->sectors, uptodate);
 		put_buf(r1_bio);
 	}
-	return 0;
 }
 
 static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
@@ -1972,7 +1956,8 @@
 		    !test_bit(In_sync, &disk->rdev->flags)) {
 			disk->head_position = 0;
 			mddev->degraded++;
-			conf->fullsync = 1;
+			if (disk->rdev)
+				conf->fullsync = 1;
 		}
 	}
 	if (mddev->degraded == conf->raid_disks) {
@@ -2153,11 +2138,25 @@
 	oldpool = conf->r1bio_pool;
 	conf->r1bio_pool = newpool;
 
-	for (d=d2=0; d < conf->raid_disks; d++)
-		if (conf->mirrors[d].rdev) {
-			conf->mirrors[d].rdev->raid_disk = d2;
-			newmirrors[d2++].rdev = conf->mirrors[d].rdev;
+	for (d = d2 = 0; d < conf->raid_disks; d++) {
+		mdk_rdev_t *rdev = conf->mirrors[d].rdev;
+		if (rdev && rdev->raid_disk != d2) {
+			char nm[20];
+			sprintf(nm, "rd%d", rdev->raid_disk);
+			sysfs_remove_link(&mddev->kobj, nm);
+			rdev->raid_disk = d2;
+			sprintf(nm, "rd%d", rdev->raid_disk);
+			sysfs_remove_link(&mddev->kobj, nm);
+			if (sysfs_create_link(&mddev->kobj,
+					      &rdev->kobj, nm))
+				printk(KERN_WARNING
+				       "md/raid1: cannot register "
+				       "%s for %s\n",
+				       nm, mdname(mddev));
 		}
+		if (rdev)
+			newmirrors[d2++].rdev = rdev;
+	}
 	kfree(conf->mirrors);
 	conf->mirrors = newmirrors;
 	kfree(conf->poolinfo);
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index a95ada1..25a96c4 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -227,7 +227,7 @@
 {
 	struct bio *bio = r10_bio->master_bio;
 
-	bio_endio(bio, bio->bi_size,
+	bio_endio(bio,
 		test_bit(R10BIO_Uptodate, &r10_bio->state) ? 0 : -EIO);
 	free_r10bio(r10_bio);
 }
@@ -243,15 +243,13 @@
 		r10_bio->devs[slot].addr + (r10_bio->sectors);
 }
 
-static int raid10_end_read_request(struct bio *bio, unsigned int bytes_done, int error)
+static void raid10_end_read_request(struct bio *bio, int error)
 {
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
 	int slot, dev;
 	conf_t *conf = mddev_to_conf(r10_bio->mddev);
 
-	if (bio->bi_size)
-		return 1;
 
 	slot = r10_bio->read_slot;
 	dev = r10_bio->devs[slot].devnum;
@@ -284,19 +282,15 @@
 	}
 
 	rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev);
-	return 0;
 }
 
-static int raid10_end_write_request(struct bio *bio, unsigned int bytes_done, int error)
+static void raid10_end_write_request(struct bio *bio, int error)
 {
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
 	int slot, dev;
 	conf_t *conf = mddev_to_conf(r10_bio->mddev);
 
-	if (bio->bi_size)
-		return 1;
-
 	for (slot = 0; slot < conf->copies; slot++)
 		if (r10_bio->devs[slot].bio == bio)
 			break;
@@ -339,7 +333,6 @@
 	}
 
 	rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev);
-	return 0;
 }
 
 
@@ -453,7 +446,7 @@
  *      If near_copies == raid_disk, there are no striping issues,
  *      but in that case, the function isn't called at all.
  */
-static int raid10_mergeable_bvec(request_queue_t *q, struct bio *bio,
+static int raid10_mergeable_bvec(struct request_queue *q, struct bio *bio,
 				struct bio_vec *bio_vec)
 {
 	mddev_t *mddev = q->queuedata;
@@ -595,7 +588,7 @@
 	for (i=0; i<mddev->raid_disks; i++) {
 		mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
 		if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
-			request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
+			struct request_queue *r_queue = bdev_get_queue(rdev->bdev);
 
 			atomic_inc(&rdev->nr_pending);
 			rcu_read_unlock();
@@ -610,7 +603,7 @@
 	rcu_read_unlock();
 }
 
-static void raid10_unplug(request_queue_t *q)
+static void raid10_unplug(struct request_queue *q)
 {
 	mddev_t *mddev = q->queuedata;
 
@@ -618,7 +611,7 @@
 	md_wakeup_thread(mddev->thread);
 }
 
-static int raid10_issue_flush(request_queue_t *q, struct gendisk *disk,
+static int raid10_issue_flush(struct request_queue *q, struct gendisk *disk,
 			     sector_t *error_sector)
 {
 	mddev_t *mddev = q->queuedata;
@@ -630,7 +623,7 @@
 		mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
 		if (rdev && !test_bit(Faulty, &rdev->flags)) {
 			struct block_device *bdev = rdev->bdev;
-			request_queue_t *r_queue = bdev_get_queue(bdev);
+			struct request_queue *r_queue = bdev_get_queue(bdev);
 
 			if (!r_queue->issue_flush_fn)
 				ret = -EOPNOTSUPP;
@@ -658,7 +651,7 @@
 	for (i = 0; i < mddev->raid_disks && ret == 0; i++) {
 		mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
 		if (rdev && !test_bit(Faulty, &rdev->flags)) {
-			request_queue_t *q = bdev_get_queue(rdev->bdev);
+			struct request_queue *q = bdev_get_queue(rdev->bdev);
 
 			ret |= bdi_congested(&q->backing_dev_info, bits);
 		}
@@ -772,7 +765,7 @@
 	spin_unlock_irq(&conf->resync_lock);
 }
 
-static int make_request(request_queue_t *q, struct bio * bio)
+static int make_request(struct request_queue *q, struct bio * bio)
 {
 	mddev_t *mddev = q->queuedata;
 	conf_t *conf = mddev_to_conf(mddev);
@@ -787,7 +780,7 @@
 	unsigned long flags;
 
 	if (unlikely(bio_barrier(bio))) {
-		bio_endio(bio, bio->bi_size, -EOPNOTSUPP);
+		bio_endio(bio, -EOPNOTSUPP);
 		return 0;
 	}
 
@@ -819,7 +812,7 @@
 		       " or bigger than %dk %llu %d\n", chunk_sects/2,
 		       (unsigned long long)bio->bi_sector, bio->bi_size >> 10);
 
-		bio_io_error(bio, bio->bi_size);
+		bio_io_error(bio);
 		return 0;
 	}
 
@@ -917,6 +910,13 @@
 		bio_list_add(&bl, mbio);
 	}
 
+	if (unlikely(!atomic_read(&r10_bio->remaining))) {
+		/* the array is dead */
+		md_write_end(mddev);
+		raid_end_bio_io(r10_bio);
+		return 0;
+	}
+
 	bitmap_startwrite(mddev->bitmap, bio->bi_sector, r10_bio->sectors, 0);
 	spin_lock_irqsave(&conf->device_lock, flags);
 	bio_list_merge(&conf->pending_bio_list, &bl);
@@ -1148,15 +1148,12 @@
 }
 
 
-static int end_sync_read(struct bio *bio, unsigned int bytes_done, int error)
+static void end_sync_read(struct bio *bio, int error)
 {
 	r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
 	conf_t *conf = mddev_to_conf(r10_bio->mddev);
 	int i,d;
 
-	if (bio->bi_size)
-		return 1;
-
 	for (i=0; i<conf->copies; i++)
 		if (r10_bio->devs[i].bio == bio)
 			break;
@@ -1185,10 +1182,9 @@
 		reschedule_retry(r10_bio);
 	}
 	rdev_dec_pending(conf->mirrors[d].rdev, conf->mddev);
-	return 0;
 }
 
-static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
+static void end_sync_write(struct bio *bio, int error)
 {
 	int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
 	r10bio_t * r10_bio = (r10bio_t *)(bio->bi_private);
@@ -1196,9 +1192,6 @@
 	conf_t *conf = mddev_to_conf(mddev);
 	int i,d;
 
-	if (bio->bi_size)
-		return 1;
-
 	for (i = 0; i < conf->copies; i++)
 		if (r10_bio->devs[i].bio == bio)
 			break;
@@ -1221,7 +1214,6 @@
 		}
 	}
 	rdev_dec_pending(conf->mirrors[d].rdev, mddev);
-	return 0;
 }
 
 /*
@@ -1367,7 +1359,7 @@
 	if (test_bit(R10BIO_Uptodate, &r10_bio->state))
 		generic_make_request(wbio);
 	else
-		bio_endio(wbio, wbio->bi_size, -EIO);
+		bio_endio(wbio, -EIO);
 }
 
 
@@ -1557,7 +1549,6 @@
 			bio = r10_bio->devs[r10_bio->read_slot].bio;
 			r10_bio->devs[r10_bio->read_slot].bio =
 				mddev->ro ? IO_BLOCKED : NULL;
-			bio_put(bio);
 			mirror = read_balance(conf, r10_bio);
 			if (mirror == -1) {
 				printk(KERN_ALERT "raid10: %s: unrecoverable I/O"
@@ -1565,8 +1556,10 @@
 				       bdevname(bio->bi_bdev,b),
 				       (unsigned long long)r10_bio->sector);
 				raid_end_bio_io(r10_bio);
+				bio_put(bio);
 			} else {
 				const int do_sync = bio_sync(r10_bio->master_bio);
+				bio_put(bio);
 				rdev = conf->mirrors[mirror].rdev;
 				if (printk_ratelimit())
 					printk(KERN_ERR "raid10: %s: redirecting sector %llu to"
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 0b66afe..caaca9e 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -108,12 +108,11 @@
 {
 	struct bio *bi = return_bi;
 	while (bi) {
-		int bytes = bi->bi_size;
 
 		return_bi = bi->bi_next;
 		bi->bi_next = NULL;
 		bi->bi_size = 0;
-		bi->bi_end_io(bi, bytes,
+		bi->bi_end_io(bi,
 			      test_bit(BIO_UPTODATE, &bi->bi_flags)
 			        ? 0 : -EIO);
 		bi = return_bi;
@@ -289,7 +288,7 @@
 }
 
 static void unplug_slaves(mddev_t *mddev);
-static void raid5_unplug_device(request_queue_t *q);
+static void raid5_unplug_device(struct request_queue *q);
 
 static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector, int disks,
 					     int pd_idx, int noblock)
@@ -382,10 +381,10 @@
 	return pending;
 }
 
-static int
-raid5_end_read_request(struct bio *bi, unsigned int bytes_done, int error);
-static int
-raid5_end_write_request (struct bio *bi, unsigned int bytes_done, int error);
+static void
+raid5_end_read_request(struct bio *bi, int error);
+static void
+raid5_end_write_request(struct bio *bi, int error);
 
 static void ops_run_io(struct stripe_head *sh)
 {
@@ -493,12 +492,12 @@
 			if (frombio)
 				tx = async_memcpy(page, bio_page, page_offset,
 					b_offset, clen,
-					ASYNC_TX_DEP_ACK | ASYNC_TX_KMAP_SRC,
+					ASYNC_TX_DEP_ACK,
 					tx, NULL, NULL);
 			else
 				tx = async_memcpy(bio_page, page, b_offset,
 					page_offset, clen,
-					ASYNC_TX_DEP_ACK | ASYNC_TX_KMAP_DST,
+					ASYNC_TX_DEP_ACK,
 					tx, NULL, NULL);
 		}
 		if (clen < len) /* hit end of page */
@@ -514,7 +513,7 @@
 	struct stripe_head *sh = stripe_head_ref;
 	struct bio *return_bi = NULL;
 	raid5_conf_t *conf = sh->raid_conf;
-	int i, more_to_read = 0;
+	int i;
 
 	pr_debug("%s: stripe %llu\n", __FUNCTION__,
 		(unsigned long long)sh->sector);
@@ -522,16 +521,14 @@
 	/* clear completed biofills */
 	for (i = sh->disks; i--; ) {
 		struct r5dev *dev = &sh->dev[i];
-		/* check if this stripe has new incoming reads */
-		if (dev->toread)
-			more_to_read++;
 
 		/* acknowledge completion of a biofill operation */
-		/* and check if we need to reply to a read request
-		*/
-		if (test_bit(R5_Wantfill, &dev->flags) && !dev->toread) {
+		/* and check if we need to reply to a read request,
+		 * new R5_Wantfill requests are held off until
+		 * !test_bit(STRIPE_OP_BIOFILL, &sh->ops.pending)
+		 */
+		if (test_and_clear_bit(R5_Wantfill, &dev->flags)) {
 			struct bio *rbi, *rbi2;
-			clear_bit(R5_Wantfill, &dev->flags);
 
 			/* The access to dev->read is outside of the
 			 * spin_lock_irq(&conf->device_lock), but is protected
@@ -558,8 +555,7 @@
 
 	return_io(return_bi);
 
-	if (more_to_read)
-		set_bit(STRIPE_HANDLE, &sh->state);
+	set_bit(STRIPE_HANDLE, &sh->state);
 	release_stripe(sh);
 }
 
@@ -951,7 +947,7 @@
 	conf->active_name = 0;
 	sc = kmem_cache_create(conf->cache_name[conf->active_name],
 			       sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
-			       0, 0, NULL, NULL);
+			       0, 0, NULL);
 	if (!sc)
 		return 1;
 	conf->slab_cache = sc;
@@ -1003,7 +999,7 @@
 	/* Step 1 */
 	sc = kmem_cache_create(conf->cache_name[1-conf->active_name],
 			       sizeof(struct stripe_head)+(newsize-1)*sizeof(struct r5dev),
-			       0, 0, NULL, NULL);
+			       0, 0, NULL);
 	if (!sc)
 		return -ENOMEM;
 
@@ -1113,8 +1109,7 @@
 	conf->slab_cache = NULL;
 }
 
-static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
-				   int error)
+static void raid5_end_read_request(struct bio * bi, int error)
 {
  	struct stripe_head *sh = bi->bi_private;
 	raid5_conf_t *conf = sh->raid_conf;
@@ -1123,8 +1118,6 @@
 	char b[BDEVNAME_SIZE];
 	mdk_rdev_t *rdev;
 
-	if (bi->bi_size)
-		return 1;
 
 	for (i=0 ; i<disks; i++)
 		if (bi == &sh->dev[i].req)
@@ -1135,7 +1128,7 @@
 		uptodate);
 	if (i == disks) {
 		BUG();
-		return 0;
+		return;
 	}
 
 	if (uptodate) {
@@ -1188,20 +1181,15 @@
 	clear_bit(R5_LOCKED, &sh->dev[i].flags);
 	set_bit(STRIPE_HANDLE, &sh->state);
 	release_stripe(sh);
-	return 0;
 }
 
-static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done,
-				    int error)
+static void raid5_end_write_request (struct bio *bi, int error)
 {
  	struct stripe_head *sh = bi->bi_private;
 	raid5_conf_t *conf = sh->raid_conf;
 	int disks = sh->disks, i;
 	int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
 
-	if (bi->bi_size)
-		return 1;
-
 	for (i=0 ; i<disks; i++)
 		if (bi == &sh->dev[i].req)
 			break;
@@ -1211,7 +1199,7 @@
 		uptodate);
 	if (i == disks) {
 		BUG();
-		return 0;
+		return;
 	}
 
 	if (!uptodate)
@@ -1222,7 +1210,6 @@
 	clear_bit(R5_LOCKED, &sh->dev[i].flags);
 	set_bit(STRIPE_HANDLE, &sh->state);
 	release_stripe(sh);
-	return 0;
 }
 
 
@@ -2541,7 +2528,7 @@
 	struct dma_async_tx_descriptor *tx = NULL;
 	clear_bit(STRIPE_EXPAND_SOURCE, &sh->state);
 	for (i = 0; i < sh->disks; i++)
-		if (i != sh->pd_idx && (r6s && i != r6s->qd_idx)) {
+		if (i != sh->pd_idx && (!r6s || i != r6s->qd_idx)) {
 			int dd_idx, pd_idx, j;
 			struct stripe_head *sh2;
 
@@ -2574,7 +2561,8 @@
 			set_bit(R5_UPTODATE, &sh2->dev[dd_idx].flags);
 			for (j = 0; j < conf->raid_disks; j++)
 				if (j != sh2->pd_idx &&
-				    (r6s && j != r6s->qd_idx) &&
+				    (!r6s || j != raid6_next_disk(sh2->pd_idx,
+								 sh2->disks)) &&
 				    !test_bit(R5_Expanded, &sh2->dev[j].flags))
 					break;
 			if (j == conf->raid_disks) {
@@ -2583,12 +2571,12 @@
 			}
 			release_stripe(sh2);
 
-			/* done submitting copies, wait for them to complete */
-			if (i + 1 >= sh->disks) {
-				async_tx_ack(tx);
-				dma_wait_for_async_tx(tx);
-			}
 		}
+	/* done submitting copies, wait for them to complete */
+	if (tx) {
+		async_tx_ack(tx);
+		dma_wait_for_async_tx(tx);
+	}
 }
 
 /*
@@ -2855,7 +2843,7 @@
 		sh->disks = conf->raid_disks;
 		sh->pd_idx = stripe_to_pdidx(sh->sector, conf,
 			conf->raid_disks);
-		s.locked += handle_write_operations5(sh, 0, 1);
+		s.locked += handle_write_operations5(sh, 1, 1);
 	} else if (s.expanded &&
 		!test_bit(STRIPE_OP_POSTXOR, &sh->ops.pending)) {
 		clear_bit(STRIPE_EXPAND_READY, &sh->state);
@@ -3182,7 +3170,7 @@
 	for (i=0; i<mddev->raid_disks; i++) {
 		mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
 		if (rdev && !test_bit(Faulty, &rdev->flags) && atomic_read(&rdev->nr_pending)) {
-			request_queue_t *r_queue = bdev_get_queue(rdev->bdev);
+			struct request_queue *r_queue = bdev_get_queue(rdev->bdev);
 
 			atomic_inc(&rdev->nr_pending);
 			rcu_read_unlock();
@@ -3197,7 +3185,7 @@
 	rcu_read_unlock();
 }
 
-static void raid5_unplug_device(request_queue_t *q)
+static void raid5_unplug_device(struct request_queue *q)
 {
 	mddev_t *mddev = q->queuedata;
 	raid5_conf_t *conf = mddev_to_conf(mddev);
@@ -3216,7 +3204,7 @@
 	unplug_slaves(mddev);
 }
 
-static int raid5_issue_flush(request_queue_t *q, struct gendisk *disk,
+static int raid5_issue_flush(struct request_queue *q, struct gendisk *disk,
 			     sector_t *error_sector)
 {
 	mddev_t *mddev = q->queuedata;
@@ -3228,7 +3216,7 @@
 		mdk_rdev_t *rdev = rcu_dereference(conf->disks[i].rdev);
 		if (rdev && !test_bit(Faulty, &rdev->flags)) {
 			struct block_device *bdev = rdev->bdev;
-			request_queue_t *r_queue = bdev_get_queue(bdev);
+			struct request_queue *r_queue = bdev_get_queue(bdev);
 
 			if (!r_queue->issue_flush_fn)
 				ret = -EOPNOTSUPP;
@@ -3267,7 +3255,7 @@
 /* We want read requests to align with chunks where possible,
  * but write requests don't need to.
  */
-static int raid5_mergeable_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *biovec)
+static int raid5_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec)
 {
 	mddev_t *mddev = q->queuedata;
 	sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev);
@@ -3342,7 +3330,7 @@
  *  first).
  *  If the read failed..
  */
-static int raid5_align_endio(struct bio *bi, unsigned int bytes, int error)
+static void raid5_align_endio(struct bio *bi, int error)
 {
 	struct bio* raid_bi  = bi->bi_private;
 	mddev_t *mddev;
@@ -3350,8 +3338,6 @@
 	int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
 	mdk_rdev_t *rdev;
 
-	if (bi->bi_size)
-		return 1;
 	bio_put(bi);
 
 	mddev = raid_bi->bi_bdev->bd_disk->queue->queuedata;
@@ -3362,22 +3348,21 @@
 	rdev_dec_pending(rdev, conf->mddev);
 
 	if (!error && uptodate) {
-		bio_endio(raid_bi, bytes, 0);
+		bio_endio(raid_bi, 0);
 		if (atomic_dec_and_test(&conf->active_aligned_reads))
 			wake_up(&conf->wait_for_stripe);
-		return 0;
+		return;
 	}
 
 
 	pr_debug("raid5_align_endio : io error...handing IO for a retry\n");
 
 	add_bio_to_retry(raid_bi, conf);
-	return 0;
 }
 
 static int bio_fits_rdev(struct bio *bi)
 {
-	request_queue_t *q = bdev_get_queue(bi->bi_bdev);
+	struct request_queue *q = bdev_get_queue(bi->bi_bdev);
 
 	if ((bi->bi_size>>9) > q->max_sectors)
 		return 0;
@@ -3396,7 +3381,7 @@
 }
 
 
-static int chunk_aligned_read(request_queue_t *q, struct bio * raid_bio)
+static int chunk_aligned_read(struct request_queue *q, struct bio * raid_bio)
 {
 	mddev_t *mddev = q->queuedata;
 	raid5_conf_t *conf = mddev_to_conf(mddev);
@@ -3466,7 +3451,7 @@
 }
 
 
-static int make_request(request_queue_t *q, struct bio * bi)
+static int make_request(struct request_queue *q, struct bio * bi)
 {
 	mddev_t *mddev = q->queuedata;
 	raid5_conf_t *conf = mddev_to_conf(mddev);
@@ -3478,7 +3463,7 @@
 	int remaining;
 
 	if (unlikely(bio_barrier(bi))) {
-		bio_endio(bi, bi->bi_size, -EOPNOTSUPP);
+		bio_endio(bi, -EOPNOTSUPP);
 		return 0;
 	}
 
@@ -3594,12 +3579,11 @@
 	remaining = --bi->bi_phys_segments;
 	spin_unlock_irq(&conf->device_lock);
 	if (remaining == 0) {
-		int bytes = bi->bi_size;
 
 		if ( rw == WRITE )
 			md_write_end(mddev);
-		bi->bi_size = 0;
-		bi->bi_end_io(bi, bytes,
+
+		bi->bi_end_io(bi,
 			      test_bit(BIO_UPTODATE, &bi->bi_flags)
 			        ? 0 : -EIO);
 	}
@@ -3877,10 +3861,8 @@
 	remaining = --raid_bio->bi_phys_segments;
 	spin_unlock_irq(&conf->device_lock);
 	if (remaining == 0) {
-		int bytes = raid_bio->bi_size;
 
-		raid_bio->bi_size = 0;
-		raid_bio->bi_end_io(raid_bio, bytes,
+		raid_bio->bi_end_io(raid_bio,
 			      test_bit(BIO_UPTODATE, &raid_bio->bi_flags)
 			        ? 0 : -EIO);
 	}
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 624b21c..dd9bd43 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -69,19 +69,89 @@
 config VIDEO_TUNER
 	tristate
 	depends on I2C
+	select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE
+	select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE
+	select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE
+	select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE
+	select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE
 
-config VIDEO_BUF
+menuconfig VIDEO_TUNER_CUSTOMIZE
+	bool "Customize analog tuner modules to build"
+	depends on VIDEO_TUNER
+	help
+	  This allows the user to deselect tuner drivers unnecessary
+	  for their hardware from the build. Use this option with care
+	  as deselecting tuner drivers which are in fact necessary will
+	  result in V4L devices which cannot be tuned due to lack of
+	  driver support
+
+	  If unsure say N.
+
+if VIDEO_TUNER_CUSTOMIZE
+
+config TUNER_MT20XX
+	tristate "Microtune 2032 / 2050 tuners"
+	depends on I2C
+	default m if VIDEO_TUNER_CUSTOMIZE
+	help
+	  Say Y here to include support for the MT2032 / MT2050 tuner.
+
+config TUNER_TDA8290
+	tristate "TDA 8290+8275(a) tuner combo"
+	depends on I2C
+	default m if VIDEO_TUNER_CUSTOMIZE
+	help
+	  Say Y here to include support for Philips TDA8290+8275(a) tuner.
+
+config TUNER_TEA5761
+	tristate "TEA 5761 radio tuner (EXPERIMENTAL)"
+	depends on I2C && EXPERIMENTAL
+	default m if VIDEO_TUNER_CUSTOMIZE
+	help
+	  Say Y here to include support for the Philips TEA5761 radio tuner.
+
+config TUNER_TEA5767
+	tristate "TEA 5767 radio tuner"
+	depends on I2C
+	default m if VIDEO_TUNER_CUSTOMIZE
+	help
+	  Say Y here to include support for the Philips TEA5767 radio tuner.
+
+config TUNER_SIMPLE
+	tristate "Simple tuner support"
+	depends on I2C
+	default m if VIDEO_TUNER_CUSTOMIZE
+	help
+	  Say Y here to include support for various simple tuners.
+
+endif # VIDEO_TUNER_CUSTOMIZE
+
+config VIDEOBUF_GEN
+	tristate
+
+config VIDEOBUF_DMA_SG
 	depends on PCI
+	select VIDEOBUF_GEN
 	tristate
 
-config VIDEO_BUF_DVB
+config VIDEOBUF_VMALLOC
+	select VIDEOBUF_GEN
 	tristate
 
+config VIDEOBUF_DVB
+	tristate
+	select VIDEOBUF_GEN
+	select VIDEOBUF_DMA_SG
+
 config VIDEO_BTCX
 	tristate
 
+config VIDEO_IR_I2C
+	tristate
+
 config VIDEO_IR
 	tristate
+	select VIDEO_IR_I2C if I2C
 
 config VIDEO_TVEEPROM
 	tristate
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index 5c63c8e..c5092ef 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -5,5 +5,5 @@
 config VIDEO_SAA7146_VV
 	tristate
 	depends on VIDEO_DEV
-	select VIDEO_BUF
+	select VIDEOBUF_DMA_SG
 	select VIDEO_SAA7146
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index fcb1941..e7c3ab9 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -21,7 +21,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/jiffies.h>
 #include <media/ir-common.h>
@@ -107,21 +106,20 @@
 }
 
 /* -------------------------------------------------------------------------- */
-
+/* extract mask bits out of data and pack them into the result */
 u32 ir_extract_bits(u32 data, u32 mask)
 {
-	int mbit, vbit;
-	u32 value;
+	u32 vbit = 1, value = 0;
 
-	value = 0;
-	vbit  = 0;
-	for (mbit = 0; mbit < 32; mbit++) {
-		if (!(mask & ((u32)1 << mbit)))
-			continue;
-		if (data & ((u32)1 << mbit))
-			value |= (1 << vbit);
-		vbit++;
-	}
+	do {
+	    if (mask&1) {
+		if (data&1)
+			value |= vbit;
+		vbit<<=1;
+	    }
+	    data>>=1;
+	} while (mask>>=1);
+
 	return value;
 }
 
@@ -346,8 +344,8 @@
 			}
 
 			/* Set/reset key-up timer */
-			timeout = current_jiffies + (500 + ir->rc5_key_timeout
-						     * HZ) / 1000;
+			timeout = current_jiffies +
+				  msecs_to_jiffies(ir->rc5_key_timeout);
 			mod_timer(&ir->timer_keyup, timeout);
 
 			/* Save code for repeat test */
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index cbd1184..aefcf28 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -20,7 +20,6 @@
 
  */
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 
 #include <linux/input.h>
 #include <media/ir-common.h>
@@ -1783,3 +1782,64 @@
 };
 
 EXPORT_SYMBOL_GPL(ir_codes_tt_1500);
+
+/* DViCO FUSION HDTV MCE remote */
+IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE] = {
+
+	[ 0x0b ] = KEY_1,
+	[ 0x17 ] = KEY_2,
+	[ 0x1b ] = KEY_3,
+	[ 0x07 ] = KEY_4,
+	[ 0x50 ] = KEY_5,
+	[ 0x54 ] = KEY_6,
+	[ 0x48 ] = KEY_7,
+	[ 0x4c ] = KEY_8,
+	[ 0x58 ] = KEY_9,
+	[ 0x03 ] = KEY_0,
+
+	[ 0x5e ] = KEY_OK,
+	[ 0x51 ] = KEY_UP,
+	[ 0x53 ] = KEY_DOWN,
+	[ 0x5b ] = KEY_LEFT,
+	[ 0x5f ] = KEY_RIGHT,
+
+	[ 0x02 ] = KEY_TV,		/* Labeled DTV on remote */
+	[ 0x0e ] = KEY_MP3,
+	[ 0x1a ] = KEY_DVD,
+	[ 0x1e ] = KEY_FAVORITES,	/* Labeled CPF on remote */
+	[ 0x16 ] = KEY_SETUP,
+	[ 0x46 ] = KEY_POWER2,		/* TV On/Off button on remote */
+	[ 0x0a ] = KEY_EPG,		/* Labeled Guide on remote */
+
+	[ 0x49 ] = KEY_BACK,
+	[ 0x59 ] = KEY_INFO,		/* Labeled MORE on remote */
+	[ 0x4d ] = KEY_MENU,		/* Labeled DVDMENU on remote */
+	[ 0x55 ] = KEY_CYCLEWINDOWS,	/* Labeled ALT-TAB on remote */
+
+	[ 0x0f ] = KEY_PREVIOUSSONG,	/* Labeled |<< REPLAY on remote */
+	[ 0x12 ] = KEY_NEXTSONG,	/* Labeled >>| SKIP on remote */
+	[ 0x42 ] = KEY_ENTER, 		/* Labeled START with a green
+					 * MS windows logo on remote */
+
+	[ 0x15 ] = KEY_VOLUMEUP,
+	[ 0x05 ] = KEY_VOLUMEDOWN,
+	[ 0x11 ] = KEY_CHANNELUP,
+	[ 0x09 ] = KEY_CHANNELDOWN,
+
+	[ 0x52 ] = KEY_CAMERA,
+	[ 0x5a ] = KEY_TUNER,
+	[ 0x19 ] = KEY_OPEN,
+
+	[ 0x13 ] = KEY_MODE,		/* 4:3 16:9 select */
+	[ 0x1f ] = KEY_ZOOM,
+
+	[ 0x43 ] = KEY_REWIND,
+	[ 0x47 ] = KEY_PLAYPAUSE,
+	[ 0x4f ] = KEY_FASTFORWARD,
+	[ 0x57 ] = KEY_MUTE,
+	[ 0x0d ] = KEY_STOP,
+	[ 0x01 ] = KEY_RECORD,
+	[ 0x4e ] = KEY_POWER,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_fusionhdtv_mce);
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index ef3e54c..365a221 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -27,7 +27,7 @@
 
 unsigned int saa7146_debug;
 
-module_param(saa7146_debug, int, 0644);
+module_param(saa7146_debug, uint, 0644);
 MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)");
 
 #if 0
@@ -100,7 +100,7 @@
  * general helper functions
  ****************************************************************************/
 
-/* this is videobuf_vmalloc_to_sg() from video-buf.c
+/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.c
    make sure virt has been allocated with vmalloc_32(), otherwise the BUG()
    may be triggered on highmem machines */
 static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
@@ -130,10 +130,10 @@
 /********************************************************************************/
 /* common page table functions */
 
-char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
+void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt)
 {
 	int pages = (length+PAGE_SIZE-1)/PAGE_SIZE;
-	char *mem = vmalloc_32(length);
+	void *mem = vmalloc_32(length);
 	int slen = 0;
 
 	if (NULL == mem)
@@ -168,7 +168,7 @@
 	return NULL;
 }
 
-void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, char *mem, struct saa7146_pgtable *pt)
+void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt)
 {
 	pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE);
 	saa7146_pgtable_free(pci, pt);
@@ -248,10 +248,11 @@
 static irqreturn_t interrupt_hw(int irq, void *dev_id)
 {
 	struct saa7146_dev *dev = dev_id;
-	u32 isr = 0;
+	u32 isr;
+	u32 ack_isr;
 
 	/* read out the interrupt status register */
-	isr = saa7146_read(dev, ISR);
+	ack_isr = isr = saa7146_read(dev, ISR);
 
 	/* is this our interrupt? */
 	if ( 0 == isr ) {
@@ -259,8 +260,6 @@
 		return IRQ_NONE;
 	}
 
-	saa7146_write(dev, ISR, isr);
-
 	if( 0 != (dev->ext)) {
 		if( 0 != (dev->ext->irq_mask & isr )) {
 			if( 0 != dev->ext->irq_func ) {
@@ -283,21 +282,16 @@
 		isr &= ~MASK_28;
 	}
 	if (0 != (isr & (MASK_16|MASK_17))) {
-		u32 status = saa7146_read(dev, I2C_STATUS);
-		if( (0x3 == (status & 0x3)) || (0 == (status & 0x1)) ) {
-			SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
-			/* only wake up if we expect something */
-			if( 0 != dev->i2c_op ) {
-				u32 psr = (saa7146_read(dev, PSR) >> 16) & 0x2;
-				u32 ssr = (saa7146_read(dev, SSR) >> 17) & 0x1f;
-				DEB_I2C(("irq: i2c, status: 0x%08x, psr:0x%02x, ssr:0x%02x).\n",status,psr,ssr));
-				dev->i2c_op = 0;
-				wake_up(&dev->i2c_wq);
-			} else {
-				DEB_I2C(("unexpected irq: i2c, status: 0x%08x, isr %#x\n",status, isr));
-			}
+		SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);
+		/* only wake up if we expect something */
+		if (0 != dev->i2c_op) {
+			dev->i2c_op = 0;
+			wake_up(&dev->i2c_wq);
 		} else {
-			DEB_I2C(("unhandled irq: i2c, status: 0x%08x, isr %#x\n",status, isr));
+			u32 psr = saa7146_read(dev, PSR);
+			u32 ssr = saa7146_read(dev, SSR);
+			printk(KERN_WARNING "%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",
+			       dev->name, isr, psr, ssr);
 		}
 		isr &= ~(MASK_16|MASK_17);
 	}
@@ -306,6 +300,7 @@
 		ERR(("disabling interrupt source(s)!\n"));
 		SAA7146_IER_DISABLE(dev,isr);
 	}
+	saa7146_write(dev, ISR, ack_isr);
 	return IRQ_HANDLED;
 }
 
@@ -548,7 +543,6 @@
 
 EXPORT_SYMBOL_GPL(saa7146_setgpio);
 
-EXPORT_SYMBOL_GPL(saa7146_i2c_transfer);
 EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare);
 
 EXPORT_SYMBOL_GPL(saa7146_debug);
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index b4770ae..67d1b1b 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -53,13 +53,14 @@
 void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
 						struct saa7146_buf *buf)
 {
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 	DEB_EE(("dev:%p, buf:%p\n",dev,buf));
 
 	BUG_ON(in_interrupt());
 
 	videobuf_waiton(&buf->vb,0,0);
-	videobuf_dma_unmap(q, &buf->vb.dma);
-	videobuf_dma_free(&buf->vb.dma);
+	videobuf_dma_unmap(q, dma);
+	videobuf_dma_free(dma);
 	buf->vb.state = STATE_NEEDS_INIT;
 }
 
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c
index 8c85efc..7e7689a 100644
--- a/drivers/media/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146_i2c.c
@@ -202,7 +202,8 @@
 				/* a signal arrived */
 				return -ERESTARTSYS;
 
-			printk(KERN_WARNING "saa7146_i2c_writeout: timed out waiting for end of xfer\n");
+			printk(KERN_WARNING "%s %s [irq]: timed out waiting for end of xfer\n",
+				dev->name, __FUNCTION__);
 			return -EIO;
 		}
 		status = saa7146_read(dev, I2C_STATUS);
@@ -219,7 +220,8 @@
 				break;
 			}
 			if (time_after(jiffies,timeout)) {
-				printk(KERN_WARNING "saa7146_i2c_writeout: timed out waiting for MC2\n");
+				printk(KERN_WARNING "%s %s: timed out waiting for MC2\n",
+					dev->name, __FUNCTION__);
 				return -EIO;
 			}
 		}
@@ -235,7 +237,8 @@
 				/* this is normal when probing the bus
 				 * (no answer from nonexisistant device...)
 				 */
-				DEB_I2C(("saa7146_i2c_writeout: timed out waiting for end of xfer\n"));
+				printk(KERN_WARNING "%s %s [poll]: timed out waiting for end of xfer\n",
+					dev->name, __FUNCTION__);
 				return -EIO;
 			}
 			if (++trial < 50 && short_delay)
@@ -246,8 +249,16 @@
 	}
 
 	/* give a detailed status report */
-	if ( 0 != (status & SAA7146_I2C_ERR)) {
+	if ( 0 != (status & (SAA7146_I2C_SPERR | SAA7146_I2C_APERR |
+			     SAA7146_I2C_DTERR | SAA7146_I2C_DRERR |
+			     SAA7146_I2C_AL    | SAA7146_I2C_ERR   |
+			     SAA7146_I2C_BUSY)) ) {
 
+		if ( 0 == (status & SAA7146_I2C_ERR) ||
+		     0 == (status & SAA7146_I2C_BUSY) ) {
+			/* it may take some time until ERR goes high - ignore */
+			DEB_I2C(("unexpected i2c status %04x\n", status));
+		}
 		if( 0 != (status & SAA7146_I2C_SPERR) ) {
 			DEB_I2C(("error due to invalid start/stop condition.\n"));
 		}
@@ -277,7 +288,7 @@
 	return 0;
 }
 
-int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
+static int saa7146_i2c_transfer(struct saa7146_dev *dev, const struct i2c_msg *msgs, int num, int retries)
 {
 	int i = 0, count = 0;
 	u32* buffer = dev->d_i2c.cpu_addr;
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index 0636084..6103484e 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -165,7 +165,7 @@
 	/* we don't wait here for the first field anymore. this is different from the video
 	   capture and might cause that the first buffer is only half filled (with only
 	   one field). but since this is some sort of streaming data, this is not that negative.
-	   but by doing this, we can use the whole engine from video-buf.c... */
+	   but by doing this, we can use the whole engine from videobuf-dma-sg.c... */
 
 /*
 	WRITE_RPS1(CMD_PAUSE | CMD_OAN | CMD_SIG1 | e_wait);
@@ -239,6 +239,8 @@
 		saa7146_dma_free(dev,q,buf);
 
 	if (STATE_NEEDS_INIT == buf->vb.state) {
+		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
 		buf->vb.width  = llength;
 		buf->vb.height = lines;
 		buf->vb.size   = size;
@@ -250,7 +252,8 @@
 		err = videobuf_iolock(q,&buf->vb, NULL);
 		if (err)
 			goto oops;
-		err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2], buf->vb.dma.sglist, buf->vb.dma.sglen);
+		err = saa7146_pgtable_build_single(dev->pci, &buf->pt[2],
+						 dma->sglist, dma->sglen);
 		if (0 != err)
 			return err;
 	}
@@ -404,7 +407,7 @@
 	fh->vbi_fmt.start[1] = 312;
 	fh->vbi_fmt.count[1] = 16;
 
-	videobuf_queue_init(&fh->vbi_q, &vbi_qops,
+	videobuf_queue_pci_init(&fh->vbi_q, &vbi_qops,
 			    dev->pci, &dev->slock,
 			    V4L2_BUF_TYPE_VBI_CAPTURE,
 			    V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index e3d04a4..f245a3b 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -594,8 +594,9 @@
 static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *buf)
 {
 	struct pci_dev *pci = dev->pci;
-	struct scatterlist *list = buf->vb.dma.sglist;
-	int length = buf->vb.dma.sglen;
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+	struct scatterlist *list = dma->sglist;
+	int length = dma->sglen;
 	struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
 
 	DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length));
@@ -655,7 +656,7 @@
 
 		/* if we have a user buffer, the first page may not be
 		   aligned to a page boundary. */
-		pt1->offset = buf->vb.dma.sglist->offset;
+		pt1->offset = list->offset;
 		pt2->offset = pt1->offset+o1;
 		pt3->offset = pt1->offset+o2;
 
@@ -889,9 +890,9 @@
 
 		DEB_EE(("VIDIOC_QUERYCAP\n"));
 
-		strcpy(cap->driver, "saa7146 v4l2");
-		strlcpy(cap->card, dev->ext->name, sizeof(cap->card));
-		sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
+		strcpy((char *)cap->driver, "saa7146 v4l2");
+		strlcpy((char *)cap->card, dev->ext->name, sizeof(cap->card));
+		sprintf((char *)cap->bus_info,"PCI:%s", pci_name(dev->pci));
 		cap->version = SAA7146_VERSION_CODE;
 		cap->capabilities =
 			V4L2_CAP_VIDEO_CAPTURE |
@@ -968,7 +969,7 @@
 			}
 			memset(f,0,sizeof(*f));
 			f->index = index;
-			strlcpy(f->description,formats[index].name,sizeof(f->description));
+			strlcpy((char *)f->description,formats[index].name,sizeof(f->description));
 			f->pixelformat = formats[index].pixelformat;
 			break;
 		}
@@ -1211,6 +1212,8 @@
 			mutex_unlock(&q->lock);
 			return err;
 		}
+
+		gbuffers = err;
 		memset(mbuf,0,sizeof(*mbuf));
 		mbuf->frames = gbuffers;
 		mbuf->size   = gbuffers * gbufsize;
@@ -1411,7 +1414,7 @@
 	sfmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
 	fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8;
 
-	videobuf_queue_init(&fh->video_q, &video_qops,
+	videobuf_queue_pci_init(&fh->video_q, &video_qops,
 			    dev->pci, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_INTERLACED,
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index a0dcd59..3197aeb 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -1,7 +1,7 @@
 config DVB_B2C2_FLEXCOP
 	tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
 	depends on DVB_CORE && I2C
-	select DVB_PLL
+	select DVB_PLL if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
 	select DVB_MT312 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile
index bff00b5..e97ff60 100644
--- a/drivers/media/dvb/b2c2/Makefile
+++ b/drivers/media/dvb/b2c2/Makefile
@@ -12,4 +12,4 @@
 b2c2-flexcop-usb-objs = flexcop-usb.o
 obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index b02c2fd..0378fd6 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -500,13 +500,13 @@
 	/* try the air atsc 2nd generation (nxt2002) */
 	if ((fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
 		fc->dev_type          = FC_AIR_ATSC2;
-		dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, &dvb_pll_samsung_tbmv);
+		dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV);
 		info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
 	} else
 	/* try the air atsc 3nd generation (lgdt3303) */
 	if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
 		fc->dev_type          = FC_AIR_ATSC3;
-		dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_lg_tdvs_h06xf);
+		dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, DVB_PLL_LG_TDVS_H06XF);
 		info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
 	} else
 	/* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
index 02a0ea6..6bf858a 100644
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -135,6 +135,13 @@
 	struct flexcop_device *fc = i2c_get_adapdata(i2c_adap);
 	int i, ret = 0;
 
+	/* Some drivers use 1 byte or 0 byte reads as probes, which this
+	 * driver doesn't support.  These probes will always fail, so this
+	 * hack makes them always succeed.  If one knew how, it would of
+	 * course be better to actually do the read.  */
+	if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1)
+		return 1;
+
 	if (mutex_lock_interruptible(&fc->i2c_mutex))
 		return -ERESTARTSYS;
 
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index cfd6fb7..ea66617 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -7,7 +7,7 @@
 	select DVB_CX24110 if !DVB_FE_CUSTOMISE
 	select DVB_OR51211 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
-	select DVB_PLL
+	select DVB_PLL if !DVB_FE_CUSTOMISE
 	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
 	select FW_LOADER
 	help
diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile
index 9d197ef..84cf705 100644
--- a/drivers/media/dvb/bt8xx/Makefile
+++ b/drivers/media/dvb/bt8xx/Makefile
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index df72b4b..eca602d 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -28,7 +28,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <asm/io.h>
diff --git a/drivers/media/dvb/bt8xx/bt878.h b/drivers/media/dvb/bt8xx/bt878.h
index f685bc1..d593bc1 100644
--- a/drivers/media/dvb/bt8xx/bt878.h
+++ b/drivers/media/dvb/bt8xx/bt878.h
@@ -149,11 +149,10 @@
 void bt878_stop(struct bt878 *bt);
 
 #if defined(__powerpc__)	/* big-endian */
-extern __inline__ void io_st_le32(volatile unsigned __iomem *addr, unsigned val)
+static inline void io_st_le32(volatile unsigned __iomem *addr, unsigned val)
 {
-	__asm__ __volatile__("stwbrx %1,0,%2":"=m"(*addr):"r"(val),
-			     "r"(addr));
-	__asm__ __volatile__("eieio":::"memory");
+	st_le32(addr, val);
+	eieio();
 }
 
 #define bmtwrite(dat,adr)  io_st_le32((adr),(dat))
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index e908e3c..b7a17e6 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1652,7 +1652,7 @@
 static int dst_tune_frontend(struct dvb_frontend* fe,
 			    struct dvb_frontend_parameters* p,
 			    unsigned int mode_flags,
-			    int *delay,
+			    unsigned int *delay,
 			    fe_status_t *status)
 {
 	struct dst_state *state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index 4f1c09b..dedd30a 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -21,7 +21,6 @@
 
 #include <linux/bitops.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/device.h>
@@ -611,7 +610,7 @@
 		card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
 		if (card->fe != NULL) {
 			dvb_attach(dvb_pll_attach, card->fe, 0x61,
-				   card->i2c_adapter, &dvb_pll_lg_tdvs_h06xf);
+				   card->i2c_adapter, DVB_PLL_LG_TDVS_H06XF);
 			dprintk ("dvb_bt8xx: lgdt330x detected\n");
 		}
 		break;
@@ -692,6 +691,9 @@
 
 	case BTTV_BOARD_PC_HDTV:
 		card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter);
+		if (card->fe != NULL)
+			dvb_attach(dvb_pll_attach, card->fe, 0x61,
+				   card->i2c_adapter, DVB_PLL_FCV1236D);
 		break;
 	}
 
diff --git a/drivers/media/dvb/cinergyT2/Makefile b/drivers/media/dvb/cinergyT2/Makefile
index c51aece..d762d8c 100644
--- a/drivers/media/dvb/cinergyT2/Makefile
+++ b/drivers/media/dvb/cinergyT2/Makefile
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_CINERGYT2) += cinergyT2.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index b40af48..5a12b56 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -548,19 +548,19 @@
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct cinergyt2 *cinergyt2 = dvbdev->priv;
-       unsigned int mask = 0;
+	unsigned int mask = 0;
 
 	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
 		return -ERESTARTSYS;
 
 	poll_wait(file, &cinergyt2->poll_wq, wait);
 
-       if (cinergyt2->pending_fe_events != 0)
+	if (cinergyt2->pending_fe_events != 0)
 		mask |= (POLLIN | POLLRDNORM | POLLPRI);
 
 	mutex_unlock(&cinergyt2->sem);
 
-       return mask;
+	return mask;
 }
 
 
@@ -829,7 +829,7 @@
 	input_dev->id.vendor = cinergyt2->udev->descriptor.idVendor;
 	input_dev->id.product = cinergyt2->udev->descriptor.idProduct;
 	input_dev->id.version = 1;
-	input_dev->cdev.dev = &cinergyt2->udev->dev;
+	input_dev->dev.parent = &cinergyt2->udev->dev;
 
 	err = input_register_device(input_dev);
 	if (err) {
@@ -905,12 +905,11 @@
 	struct cinergyt2 *cinergyt2;
 	int err;
 
-	if (!(cinergyt2 = kmalloc (sizeof(struct cinergyt2), GFP_KERNEL))) {
+	if (!(cinergyt2 = kzalloc (sizeof(struct cinergyt2), GFP_KERNEL))) {
 		dprintk(1, "out of memory?!?\n");
 		return -ENOMEM;
 	}
 
-	memset (cinergyt2, 0, sizeof (struct cinergyt2));
 	usb_set_intfdata (intf, (void *) cinergyt2);
 
 	mutex_init(&cinergyt2->sem);
@@ -1000,18 +999,17 @@
 	if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->wq_sem))
 		return -ERESTARTSYS;
 
-	if (1) {
-		cinergyt2_suspend_rc(cinergyt2);
-		cancel_rearming_delayed_work(&cinergyt2->query_work);
+	cinergyt2_suspend_rc(cinergyt2);
+	cancel_rearming_delayed_work(&cinergyt2->query_work);
 
-		mutex_lock(&cinergyt2->sem);
-		if (cinergyt2->streaming)
-			cinergyt2_stop_stream_xfer(cinergyt2);
-		cinergyt2_sleep(cinergyt2, 1);
-		mutex_unlock(&cinergyt2->sem);
-	}
+	mutex_lock(&cinergyt2->sem);
+	if (cinergyt2->streaming)
+		cinergyt2_stop_stream_xfer(cinergyt2);
+	cinergyt2_sleep(cinergyt2, 1);
+	mutex_unlock(&cinergyt2->sem);
 
 	mutex_unlock(&cinergyt2->wq_sem);
+
 	return 0;
 }
 
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 275df65..f94bc31 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -24,7 +24,6 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/poll.h>
 #include <linux/ioctl.h>
 #include <linux/wait.h>
@@ -97,7 +96,7 @@
 		if (avail > todo)
 			avail = todo;
 
-		ret = dvb_ringbuffer_read(src, buf, avail, 1);
+		ret = dvb_ringbuffer_read(src, (u8 *)buf, avail, 1);
 		if (ret < 0)
 			break;
 
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 2a03bf5..084a508 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -32,11 +32,11 @@
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/vmalloc.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/sched.h>
+#include <linux/kthread.h>
 
 #include "dvb_ca_en50221.h"
 #include "dvb_ringbuffer.h"
@@ -140,13 +140,7 @@
 	wait_queue_head_t wait_queue;
 
 	/* PID of the monitoring thread */
-	pid_t thread_pid;
-
-	/* Wait queue used when shutting thread down */
-	wait_queue_head_t thread_queue;
-
-	/* Flag indicating when thread should exit */
-	unsigned int exit:1;
+	struct task_struct *thread;
 
 	/* Flag indicating if the CA device is open */
 	unsigned int open:1;
@@ -175,7 +169,7 @@
  * @param nlen Number of bytes in needle.
  * @return Pointer into haystack needle was found at, or NULL if not found.
  */
-static u8 *findstr(u8 * haystack, int hlen, u8 * needle, int nlen)
+static char *findstr(char * haystack, int hlen, char * needle, int nlen)
 {
 	int i;
 
@@ -482,7 +476,7 @@
 	}
 
 	/* check it contains the correct DVB string */
-	dvb_str = findstr(tuple, tupleLength, "DVB_CI_V", 8);
+	dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8);
 	if (dvb_str == NULL)
 		return -EINVAL;
 	if (tupleLength < ((dvb_str - (char *) tuple) + 12))
@@ -513,8 +507,8 @@
 			ca->slot_info[slot].config_option = tuple[0] & 0x3f;
 
 			/* OK, check it contains the correct strings */
-			if ((findstr(tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
-			    (findstr(tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
+			if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
+			    (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
 				break;
 
 			got_cftableentry = 1;
@@ -902,28 +896,10 @@
 
 	ca->wakeup = 1;
 	mb();
-	wake_up_interruptible(&ca->thread_queue);
+	wake_up_process(ca->thread);
 }
 
 /**
- * Used by the CA thread to determine if an early wakeup is necessary
- *
- * @param ca CA instance.
- */
-static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private *ca)
-{
-	if (ca->wakeup) {
-		ca->wakeup = 0;
-		return 1;
-	}
-	if (ca->exit)
-		return 1;
-
-	return 0;
-}
-
-
-/**
  * Update the delay used by the thread.
  *
  * @param ca CA instance.
@@ -982,7 +958,6 @@
 static int dvb_ca_en50221_thread(void *data)
 {
 	struct dvb_ca_private *ca = data;
-	char name[15];
 	int slot;
 	int flags;
 	int status;
@@ -991,28 +966,17 @@
 
 	dprintk("%s\n", __FUNCTION__);
 
-	/* setup kernel thread */
-	snprintf(name, sizeof(name), "kdvb-ca-%i:%i", ca->dvbdev->adapter->num, ca->dvbdev->id);
-
-	lock_kernel();
-	daemonize(name);
-	sigfillset(&current->blocked);
-	unlock_kernel();
-
 	/* choose the correct initial delay */
 	dvb_ca_en50221_thread_update_delay(ca);
 
 	/* main loop */
-	while (!ca->exit) {
+	while (!kthread_should_stop()) {
 		/* sleep for a bit */
-		if (!ca->wakeup) {
-			flags = wait_event_interruptible_timeout(ca->thread_queue,
-								 dvb_ca_en50221_thread_should_wakeup(ca),
-								 ca->delay);
-			if ((flags == -ERESTARTSYS) || ca->exit) {
-				/* got signal or quitting */
-				break;
-			}
+		while (!ca->wakeup) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(ca->delay);
+			if (kthread_should_stop())
+				return 0;
 		}
 		ca->wakeup = 0;
 
@@ -1181,10 +1145,6 @@
 		}
 	}
 
-	/* completed */
-	ca->thread_pid = 0;
-	mb();
-	wake_up_interruptible(&ca->thread_queue);
 	return 0;
 }
 
@@ -1300,7 +1260,7 @@
 	struct dvb_ca_private *ca = dvbdev->priv;
 	u8 slot, connection_id;
 	int status;
-	char fragbuf[HOST_LINK_BUF_SIZE];
+	u8 fragbuf[HOST_LINK_BUF_SIZE];
 	int fragpos = 0;
 	int fraglen;
 	unsigned long timeout;
@@ -1486,7 +1446,7 @@
 				}
 
 				if ((status = dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 2,
-								      buf + pktlen, fraglen, 1)) < 0) {
+								      (u8 *)buf + pktlen, fraglen, 1)) < 0) {
 					goto exit;
 				}
 				pktlen += fraglen;
@@ -1536,8 +1496,10 @@
 		return -EIO;
 
 	err = dvb_generic_open(inode, file);
-	if (err < 0)
+	if (err < 0) {
+		module_put(ca->pub->owner);
 		return err;
+	}
 
 	for (i = 0; i < ca->slot_count; i++) {
 
@@ -1570,7 +1532,7 @@
 {
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_ca_private *ca = dvbdev->priv;
-	int err = 0;
+	int err;
 
 	dprintk("%s\n", __FUNCTION__);
 
@@ -1582,7 +1544,7 @@
 
 	module_put(ca->pub->owner);
 
-	return 0;
+	return err;
 }
 
 
@@ -1682,9 +1644,6 @@
 		goto error;
 	}
 	init_waitqueue_head(&ca->wait_queue);
-	ca->thread_pid = 0;
-	init_waitqueue_head(&ca->thread_queue);
-	ca->exit = 0;
 	ca->open = 0;
 	ca->wakeup = 0;
 	ca->next_read_slot = 0;
@@ -1710,14 +1669,14 @@
 	mb();
 
 	/* create a kthread for monitoring this CA device */
-
-	ret = kernel_thread(dvb_ca_en50221_thread, ca, 0);
-
-	if (ret < 0) {
-		printk("dvb_ca_init: failed to start kernel_thread (%d)\n", ret);
+	ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i",
+				 ca->dvbdev->adapter->num, ca->dvbdev->id);
+	if (IS_ERR(ca->thread)) {
+		ret = PTR_ERR(ca->thread);
+		printk("dvb_ca_init: failed to start kernel_thread (%d)\n",
+			ret);
 		goto error;
 	}
-	ca->thread_pid = ret;
 	return 0;
 
 error:
@@ -1748,17 +1707,7 @@
 	dprintk("%s\n", __FUNCTION__);
 
 	/* shutdown the thread if there was one */
-	if (ca->thread_pid) {
-		if (kill_proc(ca->thread_pid, 0, 1) == -ESRCH) {
-			printk("dvb_ca_release adapter %d: thread PID %d already died\n",
-			       ca->dvbdev->adapter->num, ca->thread_pid);
-		} else {
-			ca->exit = 1;
-			mb();
-			dvb_ca_en50221_thread_wakeup(ca);
-			wait_event_interruptible(ca->thread_queue, ca->thread_pid == 0);
-		}
-	}
+	kthread_stop(ca->thread);
 
 	for (i = 0; i < ca->slot_count; i++) {
 		dvb_ca_en50221_slot_shutdown(ca, i);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 6d8d1c3d..7959020 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -373,13 +373,10 @@
 static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
 {
 	struct dvb_demux_feed *feed;
-	struct list_head *pos, *head = &demux->feed_list;
 	u16 pid = ts_pid(buf);
 	int dvr_done = 0;
 
-	list_for_each(pos, head) {
-		feed = list_entry(pos, struct dvb_demux_feed, list_head);
-
+	list_for_each_entry(feed, &demux->feed_list, list_head) {
 		if ((feed->pid != pid) && (feed->pid != 0x2000))
 			continue;
 
@@ -1068,7 +1065,7 @@
 
 	if (mutex_lock_interruptible(&dvbdemux->mutex))
 		return -ERESTARTSYS;
-	dvb_dmx_swfilter(dvbdemux, buf, count);
+	dvb_dmx_swfilter(dvbdemux, (u8 *)buf, count);
 	mutex_unlock(&dvbdemux->mutex);
 
 	if (signal_pending(current))
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index b6c7f66..b203640 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -32,7 +32,6 @@
 #include <linux/slab.h>
 #include <linux/poll.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/list.h>
 #include <linux/freezer.h>
 #include <linux/jiffies.h>
@@ -43,7 +42,7 @@
 #include "dvbdev.h"
 
 static int dvb_frontend_debug;
-static int dvb_shutdown_timeout = 5;
+static int dvb_shutdown_timeout;
 static int dvb_force_auto_inversion;
 static int dvb_override_tune_delay;
 static int dvb_powerdown_on_sleep = 1;
@@ -138,7 +137,7 @@
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	if (down_interruptible (&events->sem))
+	if (mutex_lock_interruptible (&events->mtx))
 		return;
 
 	wp = (events->eventw + 1) % MAX_EVENT;
@@ -159,7 +158,7 @@
 
 	events->eventw = wp;
 
-	up (&events->sem);
+	mutex_unlock(&events->mtx);
 
 	e->status = status;
 
@@ -197,7 +196,7 @@
 			return ret;
 	}
 
-	if (down_interruptible (&events->sem))
+	if (mutex_lock_interruptible (&events->mtx))
 		return -ERESTARTSYS;
 
 	memcpy (event, &events->events[events->eventr],
@@ -205,7 +204,7 @@
 
 	events->eventr = (events->eventr + 1) % MAX_EVENT;
 
-	up (&events->sem);
+	mutex_unlock(&events->mtx);
 
 	return 0;
 }
@@ -574,10 +573,9 @@
 			dvb_frontend_swzigzag(fe);
 	}
 
-	if (dvb_shutdown_timeout) {
-		if (dvb_powerdown_on_sleep)
-			if (fe->ops.set_voltage)
-				fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
+	if (dvb_powerdown_on_sleep) {
+		if (fe->ops.set_voltage)
+			fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
 		if (fe->ops.tuner_ops.sleep) {
 			fe->ops.tuner_ops.sleep(fe);
 			if (fe->ops.i2c_gate_ctrl)
@@ -697,6 +695,65 @@
 	return 0;
 }
 
+static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe,
+					u32 *freq_min, u32 *freq_max)
+{
+	*freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min);
+
+	if (fe->ops.info.frequency_max == 0)
+		*freq_max = fe->ops.tuner_ops.info.frequency_max;
+	else if (fe->ops.tuner_ops.info.frequency_max == 0)
+		*freq_max = fe->ops.info.frequency_max;
+	else
+		*freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);
+
+	if (*freq_min == 0 || *freq_max == 0)
+		printk(KERN_WARNING "DVB: frontend %u frequency limits undefined - fix the driver\n",
+		       fe->dvb->num);
+}
+
+static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
+				struct dvb_frontend_parameters *parms)
+{
+	u32 freq_min;
+	u32 freq_max;
+
+	/* range check: frequency */
+	dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max);
+	if ((freq_min && parms->frequency < freq_min) ||
+	    (freq_max && parms->frequency > freq_max)) {
+		printk(KERN_WARNING "DVB: frontend %u frequency %u out of range (%u..%u)\n",
+		       fe->dvb->num, parms->frequency, freq_min, freq_max);
+		return -EINVAL;
+	}
+
+	/* range check: symbol rate */
+	if (fe->ops.info.type == FE_QPSK) {
+		if ((fe->ops.info.symbol_rate_min &&
+		     parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) ||
+		    (fe->ops.info.symbol_rate_max &&
+		     parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) {
+			printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
+			       fe->dvb->num, parms->u.qpsk.symbol_rate,
+			       fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
+			return -EINVAL;
+		}
+
+	} else if (fe->ops.info.type == FE_QAM) {
+		if ((fe->ops.info.symbol_rate_min &&
+		     parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) ||
+		    (fe->ops.info.symbol_rate_max &&
+		     parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) {
+			printk(KERN_WARNING "DVB: frontend %u symbol rate %u out of range (%u..%u)\n",
+			       fe->dvb->num, parms->u.qam.symbol_rate,
+			       fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
 			unsigned int cmd, void *parg)
 {
@@ -707,7 +764,7 @@
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	if (!fe || fepriv->exit)
+	if (fepriv->exit)
 		return -ENODEV;
 
 	if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
@@ -722,6 +779,7 @@
 	case FE_GET_INFO: {
 		struct dvb_frontend_info* info = parg;
 		memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
+		dvb_frontend_get_frequeny_limits(fe, &info->frequency_min, &info->frequency_max);
 
 		/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
 		 * do it, it is done for it. */
@@ -883,6 +941,11 @@
 	case FE_SET_FRONTEND: {
 		struct dvb_frontend_tune_settings fetunesettings;
 
+		if (dvb_frontend_check_parameters(fe, parg) < 0) {
+			err = -EINVAL;
+			break;
+		}
+
 		memcpy (&fepriv->parameters, parg,
 			sizeof (struct dvb_frontend_parameters));
 
@@ -992,18 +1055,15 @@
 
 	dprintk ("%s\n", __FUNCTION__);
 
-	if ((ret = dvb_generic_open (inode, file)) < 0)
-		return ret;
-
-	if (fe->ops.ts_bus_ctrl) {
-		if ((ret = fe->ops.ts_bus_ctrl (fe, 1)) < 0) {
-			dvb_generic_release (inode, file);
+	if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
+		if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
 			return ret;
-		}
 	}
 
-	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+	if ((ret = dvb_generic_open (inode, file)) < 0)
+		goto err1;
 
+	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
 		/* normal tune mode when opened R/W */
 		fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
 		fepriv->tone = -1;
@@ -1011,13 +1071,20 @@
 
 		ret = dvb_frontend_start (fe);
 		if (ret)
-			dvb_generic_release (inode, file);
+			goto err2;
 
 		/*  empty event queue */
 		fepriv->events.eventr = fepriv->events.eventw = 0;
 	}
 
 	return ret;
+
+err2:
+	dvb_generic_release(inode, file);
+err1:
+	if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
+		fe->ops.ts_bus_ctrl(fe, 0);
+	return ret;
 }
 
 static int dvb_frontend_release(struct inode *inode, struct file *file)
@@ -1032,16 +1099,18 @@
 	if ((file->f_flags & O_ACCMODE) != O_RDONLY)
 		fepriv->release_jiffies = jiffies;
 
-	if (fe->ops.ts_bus_ctrl)
-		fe->ops.ts_bus_ctrl (fe, 0);
-
 	ret = dvb_generic_release (inode, file);
 
-	if (dvbdev->users==-1 && fepriv->exit==1) {
-		fops_put(file->f_op);
-		file->f_op = NULL;
-		wake_up(&dvbdev->wait_queue);
+	if (dvbdev->users == -1) {
+		if (fepriv->exit == 1) {
+			fops_put(file->f_op);
+			file->f_op = NULL;
+			wake_up(&dvbdev->wait_queue);
+		}
+		if (fe->ops.ts_bus_ctrl)
+			fe->ops.ts_bus_ctrl(fe, 0);
 	}
+
 	return ret;
 }
 
@@ -1080,7 +1149,7 @@
 	init_MUTEX (&fepriv->sem);
 	init_waitqueue_head (&fepriv->wait_queue);
 	init_waitqueue_head (&fepriv->events.wait_queue);
-	init_MUTEX (&fepriv->events.sem);
+	mutex_init(&fepriv->events.mtx);
 	fe->dvb = dvb;
 	fepriv->inversion = INVERSION_OFF;
 
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index f233d78..a5262e8 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -35,6 +35,7 @@
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/delay.h>
+#include <linux/mutex.h>
 
 #include <linux/dvb/frontend.h>
 
@@ -61,6 +62,13 @@
 	u32 bandwidth_step;
 };
 
+struct analog_parameters {
+	unsigned int frequency;
+	unsigned int mode;
+	unsigned int audmode;
+	u64 std;
+};
+
 struct dvb_tuner_ops {
 
 	struct dvb_tuner_info info;
@@ -71,6 +79,7 @@
 
 	/** This is for simple PLLs - set all parameters in one go. */
 	int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+	int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p);
 
 	/** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
 	int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
@@ -79,7 +88,9 @@
 	int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
 
 #define TUNER_STATUS_LOCKED 1
+#define TUNER_STATUS_STEREO 2
 	int (*get_status)(struct dvb_frontend *fe, u32 *status);
+	int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
 
 	/** These are provided seperately from set_params in order to facilitate silicon
 	 * tuners which require sophisticated tuning loops, controlling each parameter seperately. */
@@ -103,7 +114,7 @@
 	int (*tune)(struct dvb_frontend* fe,
 		    struct dvb_frontend_parameters* params,
 		    unsigned int mode_flags,
-		    int *delay,
+		    unsigned int *delay,
 		    fe_status_t *status);
 	/* get frontend tuning algorithm from the module */
 	int (*get_frontend_algo)(struct dvb_frontend *fe);
@@ -142,7 +153,7 @@
 	int			  eventr;
 	int			  overflow;
 	wait_queue_head_t	  wait_queue;
-	struct semaphore	  sem;
+	struct mutex		  mtx;
 };
 
 struct dvb_frontend {
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 4ebf33a5..a33eb59 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -347,7 +347,8 @@
 {
 	struct dvb_net_priv *priv = dev->priv;
 	unsigned long skipped = 0L;
-	u8 *ts, *ts_end, *from_where = NULL, ts_remain = 0, how_much = 0, new_ts = 1;
+	const u8 *ts, *ts_end, *from_where = NULL;
+	u8 ts_remain = 0, how_much = 0, new_ts = 1;
 	struct ethhdr *ethh = NULL;
 
 #ifdef ULE_DEBUG
@@ -356,15 +357,10 @@
 	static unsigned char *ule_where = ule_hist, ule_dump = 0;
 #endif
 
-	if (dev == NULL) {
-		printk( KERN_ERR "NO netdev struct!\n" );
-		return;
-	}
-
 	/* For all TS cells in current buffer.
 	 * Appearently, we are called for every single TS cell.
 	 */
-	for (ts = (char *)buf, ts_end = (char *)buf + buf_len; ts < ts_end; /* no default incr. */ ) {
+	for (ts = buf, ts_end = buf + buf_len; ts < ts_end; /* no default incr. */ ) {
 
 		if (new_ts) {
 			/* We are about to process a new TS cell. */
@@ -799,7 +795,8 @@
 }
 
 
-static void dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len)
+static void dvb_net_sec(struct net_device *dev,
+			const u8 *pkt, int pkt_len)
 {
 	u8 *eth;
 	struct sk_buff *skb;
@@ -901,7 +898,7 @@
 	 * we rely on the DVB API definition where exactly one complete
 	 * section is delivered in buffer1
 	 */
-	dvb_net_sec (dev, (u8*) buffer1, buffer1_len);
+	dvb_net_sec (dev, buffer1, buffer1_len);
 	return 0;
 }
 
@@ -1223,10 +1220,17 @@
 	return &((struct dvb_net_priv*) dev->priv)->stats;
 }
 
+static const struct header_ops dvb_header_ops = {
+	.create		= eth_header,
+	.parse		= eth_header_parse,
+	.rebuild	= eth_rebuild_header,
+};
+
 static void dvb_net_setup(struct net_device *dev)
 {
 	ether_setup(dev);
 
+	dev->header_ops		= &dvb_header_ops;
 	dev->open		= dvb_net_open;
 	dev->stop		= dvb_net_stop;
 	dev->hard_start_xmit	= dvb_net_tx;
@@ -1235,7 +1239,7 @@
 	dev->set_mac_address    = dvb_net_set_mac;
 	dev->mtu		= 4096;
 	dev->mc_count           = 0;
-	dev->hard_header_cache  = NULL;
+
 	dev->flags |= IFF_NOARP;
 }
 
@@ -1444,18 +1448,9 @@
 	struct dvb_device *dvbdev = file->private_data;
 	struct dvb_net *dvbnet = dvbdev->priv;
 
-	if (!dvbdev)
-		return -ENODEV;
+	dvb_generic_release(inode, file);
 
-	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
-		dvbdev->readers++;
-	} else {
-		dvbdev->writers++;
-	}
-
-	dvbdev->users++;
-
-	if(dvbdev->users == 1 && dvbnet->exit==1) {
+	if(dvbdev->users == 1 && dvbnet->exit == 1) {
 		fops_put(file->f_op);
 		file->f_op = NULL;
 		wake_up(&dvbdev->wait_queue);
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index a9fa333..18738fa 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -25,7 +25,6 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/slab.h>
@@ -59,18 +58,13 @@
 
 static struct dvb_device* dvbdev_find_device (int minor)
 {
-	struct list_head *entry;
+	struct dvb_adapter *adap;
 
-	list_for_each (entry, &dvb_adapter_list) {
-		struct list_head *entry0;
-		struct dvb_adapter *adap;
-		adap = list_entry (entry, struct dvb_adapter, list_head);
-		list_for_each (entry0, &adap->device_list) {
-			struct dvb_device *dev;
-			dev = list_entry (entry0, struct dvb_device, list_head);
+	list_for_each_entry(adap, &dvb_adapter_list, list_head) {
+		struct dvb_device *dev;
+		list_for_each_entry(dev, &adap->device_list, list_head)
 			if (nums2minor(adap->num, dev->type, dev->id) == minor)
 				return dev;
-		}
 	}
 
 	return NULL;
@@ -109,10 +103,7 @@
 	.open =		dvb_device_open,
 };
 
-static struct cdev dvb_device_cdev = {
-	.kobj   = {.name = "dvb", },
-	.owner  =       THIS_MODULE,
-};
+static struct cdev dvb_device_cdev;
 
 int dvb_generic_open(struct inode *inode, struct file *file)
 {
@@ -180,13 +171,10 @@
 	u32 id = 0;
 
 	while (id < DVB_MAX_IDS) {
-		struct list_head *entry;
-		list_for_each (entry, &adap->device_list) {
-			struct dvb_device *dev;
-			dev = list_entry (entry, struct dvb_device, list_head);
+		struct dvb_device *dev;
+		list_for_each_entry(dev, &adap->device_list, list_head)
 			if (dev->type == type && dev->id == id)
 				goto skip;
-		}
 		return id;
 skip:
 		id++;
@@ -200,7 +188,7 @@
 {
 	struct dvb_device *dvbdev;
 	struct file_operations *dvbdevfops;
-	struct class_device *clsdev;
+	struct device *clsdev;
 	int id;
 
 	mutex_lock(&dvbdev_register_lock);
@@ -208,7 +196,7 @@
 	if ((id = dvbdev_get_free_id (adap, type)) < 0){
 		mutex_unlock(&dvbdev_register_lock);
 		*pdvbdev = NULL;
-		printk ("%s: could get find free device id...\n", __FUNCTION__);
+		printk(KERN_ERR "%s: couldn't find free device id\n", __FUNCTION__);
 		return -ENFILE;
 	}
 
@@ -242,17 +230,16 @@
 
 	mutex_unlock(&dvbdev_register_lock);
 
-	clsdev = class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR,
-				     nums2minor(adap->num, type, id)),
-				     adap->device, "dvb%d.%s%d", adap->num,
-				     dnames[type], id);
+	clsdev = device_create(dvb_class, adap->device,
+			       MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
+			       "dvb%d.%s%d", adap->num, dnames[type], id);
 	if (IS_ERR(clsdev)) {
 		printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
 		       __FUNCTION__, adap->num, dnames[type], id, PTR_ERR(clsdev));
 		return PTR_ERR(clsdev);
 	}
 
-	dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
+	dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
 		adap->num, dnames[type], id, nums2minor(adap->num, type, id),
 		nums2minor(adap->num, type, id));
 
@@ -266,8 +253,8 @@
 	if (!dvbdev)
 		return;
 
-	class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
-					dvbdev->type, dvbdev->id)));
+	device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
+		       dvbdev->type, dvbdev->id)));
 
 	list_del (&dvbdev->list_head);
 	kfree (dvbdev->fops);
@@ -281,13 +268,10 @@
 	int num = 0;
 
 	while (num < DVB_MAX_ADAPTERS) {
-		struct list_head *entry;
-		list_for_each (entry, &dvb_adapter_list) {
-			struct dvb_adapter *adap;
-			adap = list_entry (entry, struct dvb_adapter, list_head);
+		struct dvb_adapter *adap;
+		list_for_each_entry(adap, &dvb_adapter_list, list_head)
 			if (adap->num == num)
 				goto skip;
-		}
 		return num;
 skip:
 		num++;
@@ -311,7 +295,7 @@
 	memset (adap, 0, sizeof(struct dvb_adapter));
 	INIT_LIST_HEAD (&adap->device_list);
 
-	printk ("DVB: registering new adapter (%s).\n", name);
+	printk(KERN_INFO "DVB: registering new adapter (%s)\n", name);
 
 	adap->num = num;
 	adap->name = name;
@@ -407,13 +391,13 @@
 	dev_t dev = MKDEV(DVB_MAJOR, 0);
 
 	if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
-		printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
+		printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR);
 		return retval;
 	}
 
 	cdev_init(&dvb_device_cdev, &dvb_device_fops);
 	if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
-		printk("dvb-core: unable to get major %d\n", DVB_MAJOR);
+		printk(KERN_ERR "dvb-core: unable register character device\n");
 		goto error;
 	}
 
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 5448873..d73934d 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -2,7 +2,6 @@
 	tristate "Support for various USB DVB devices"
 	depends on DVB_CORE && USB && I2C
 	select FW_LOADER
-	select DVB_PLL
 	help
 	  By enabling this you will be able to choose the various supported
 	  USB1.1 and USB2.0 DVB devices.
@@ -27,13 +26,14 @@
 	depends on DVB_USB
 	select DVB_DIB3000MC
 	select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+	select DVB_PLL if !DVB_FE_CUSTOMISE
 	help
 	  Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
 
 config DVB_USB_DIBUSB_MB
 	tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
 	depends on DVB_USB
-	select DVB_PLL
+	select DVB_PLL if !DVB_FE_CUSTOMISE
 	select DVB_DIB3000MB
 	select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
 	help
@@ -74,6 +74,8 @@
 	select DVB_DIB7000M
 	select DVB_DIB3000MC
 	select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+	select DVB_TUNER_MT2266 if !DVB_FE_CUSTOMISE
+	select DVB_TUNER_DIB0070
 	help
 	  Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
 	  USB bridge is also present in devices having the DiB7700 DVB-T-USB
@@ -89,7 +91,7 @@
 config DVB_USB_UMT_010
 	tristate "HanfTek UMT-010 DVB-T USB2.0 support"
 	depends on DVB_USB
-	select DVB_PLL
+	select DVB_PLL if !DVB_FE_CUSTOMISE
 	select DVB_DIB3000MC
 	select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
 	help
@@ -98,7 +100,7 @@
 config DVB_USB_CXUSB
 	tristate "Conexant USB2.0 hybrid reference design support"
 	depends on DVB_USB
-	select DVB_PLL
+	select DVB_PLL if !DVB_FE_CUSTOMISE
 	select DVB_CX22702 if !DVB_FE_CUSTOMISE
 	select DVB_LGDT330X if !DVB_FE_CUSTOMISE
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
@@ -142,7 +144,7 @@
 config DVB_USB_DIGITV
 	tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
 	depends on DVB_USB
-	select DVB_PLL
+	select DVB_PLL if !DVB_FE_CUSTOMISE
 	select DVB_NXT6000 if !DVB_FE_CUSTOMISE
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
 	help
@@ -188,6 +190,7 @@
 	depends on DVB_USB
 	select DVB_DIB3000MC
 	select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+	select DVB_PLL if !DVB_FE_CUSTOMISE
 	help
 	  Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
 
@@ -216,5 +219,23 @@
 	tristate "Opera1 DVB-S USB2.0 receiver"
 	depends on DVB_USB
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
+	select DVB_PLL if !DVB_FE_CUSTOMISE
 	help
 	  Say Y here to support the Opera DVB-S USB2.0 receiver.
+
+config DVB_USB_AF9005
+	tristate "Afatech AF9005 DVB-T USB1.1 support"
+	depends on DVB_USB && EXPERIMENTAL
+	select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+	select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+	help
+	  Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
+	  and the TerraTec Cinergy T USB XE (Rev.1)
+
+config DVB_USB_AF9005_REMOTE
+	tristate "Afatech AF9005 default remote control support"
+	depends on DVB_USB_AF9005
+	help
+	  Say Y here to support the default remote control decoding for the
+	  Afatech AF9005 based receiver.
+
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 976f840..73ac0a9 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -55,4 +55,10 @@
 obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o
 
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+dvb-usb-af9005-objs = af9005.o af9005-fe.o
+obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o
+
+dvb-usb-af9005-remote-objs = af9005-remote.o
+obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/dvb-usb/af9005-fe.c b/drivers/media/dvb/dvb-usb/af9005-fe.c
new file mode 100644
index 0000000..b1a9c4c
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005-fe.c
@@ -0,0 +1,1488 @@
+/* Frontend part of the Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided 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.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "af9005.h"
+#include "af9005-script.h"
+#include "mt2060.h"
+#include "qt1010.h"
+#include <asm/div64.h>
+
+struct af9005_fe_state {
+	struct dvb_usb_device *d;
+	fe_status_t stat;
+
+	/* retraining parameters */
+	u32 original_fcw;
+	u16 original_rf_top;
+	u16 original_if_top;
+	u16 original_if_min;
+	u16 original_aci0_if_top;
+	u16 original_aci1_if_top;
+	u16 original_aci0_if_min;
+	u8 original_if_unplug_th;
+	u8 original_rf_unplug_th;
+	u8 original_dtop_if_unplug_th;
+	u8 original_dtop_rf_unplug_th;
+
+	/* statistics */
+	u32 pre_vit_error_count;
+	u32 pre_vit_bit_count;
+	u32 ber;
+	u32 post_vit_error_count;
+	u32 post_vit_bit_count;
+	u32 unc;
+	u16 abort_count;
+
+	int opened;
+	int strong;
+	unsigned long next_status_check;
+	struct dvb_frontend frontend;
+};
+
+static int af9005_write_word_agc(struct dvb_usb_device *d, u16 reghi,
+				 u16 reglo, u8 pos, u8 len, u16 value)
+{
+	int ret;
+	u8 temp;
+
+	if ((ret = af9005_write_ofdm_register(d, reglo, (u8) (value & 0xff))))
+		return ret;
+	temp = (u8) ((value & 0x0300) >> 8);
+	return af9005_write_register_bits(d, reghi, pos, len,
+					  (u8) ((value & 0x300) >> 8));
+}
+
+static int af9005_read_word_agc(struct dvb_usb_device *d, u16 reghi,
+				u16 reglo, u8 pos, u8 len, u16 * value)
+{
+	int ret;
+	u8 temp0, temp1;
+
+	if ((ret = af9005_read_ofdm_register(d, reglo, &temp0)))
+		return ret;
+	if ((ret = af9005_read_ofdm_register(d, reghi, &temp1)))
+		return ret;
+	switch (pos) {
+	case 0:
+		*value = ((u16) (temp1 & 0x03) << 8) + (u16) temp0;
+		break;
+	case 2:
+		*value = ((u16) (temp1 & 0x0C) << 6) + (u16) temp0;
+		break;
+	case 4:
+		*value = ((u16) (temp1 & 0x30) << 4) + (u16) temp0;
+		break;
+	case 6:
+		*value = ((u16) (temp1 & 0xC0) << 2) + (u16) temp0;
+		break;
+	default:
+		err("invalid pos in read word agc");
+		return -EINVAL;
+	}
+	return 0;
+
+}
+
+static int af9005_is_fecmon_available(struct dvb_frontend *fe, int *available)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	int ret;
+	u8 temp;
+
+	*available = false;
+
+	ret = af9005_read_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en,
+					fec_vtb_rsd_mon_en_pos,
+					fec_vtb_rsd_mon_en_len, &temp);
+	if (ret)
+		return ret;
+	if (temp & 1) {
+		ret =
+		    af9005_read_register_bits(state->d,
+					      xd_p_reg_ofsm_read_rbc_en,
+					      reg_ofsm_read_rbc_en_pos,
+					      reg_ofsm_read_rbc_en_len, &temp);
+		if (ret)
+			return ret;
+		if ((temp & 1) == 0)
+			*available = true;
+
+	}
+	return 0;
+}
+
+static int af9005_get_post_vit_err_cw_count(struct dvb_frontend *fe,
+					    u32 * post_err_count,
+					    u32 * post_cw_count,
+					    u16 * abort_count)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	int ret;
+	u32 err_count;
+	u32 cw_count;
+	u8 temp, temp0, temp1, temp2;
+	u16 loc_abort_count;
+
+	*post_err_count = 0;
+	*post_cw_count = 0;
+
+	/* check if error bit count is ready */
+	ret =
+	    af9005_read_register_bits(state->d, xd_r_fec_rsd_ber_rdy,
+				      fec_rsd_ber_rdy_pos, fec_rsd_ber_rdy_len,
+				      &temp);
+	if (ret)
+		return ret;
+	if (!temp) {
+		deb_info("rsd counter not ready\n");
+		return 100;
+	}
+	/* get abort count */
+	ret =
+	    af9005_read_ofdm_register(state->d,
+				      xd_r_fec_rsd_abort_packet_cnt_7_0,
+				      &temp0);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_read_ofdm_register(state->d,
+				      xd_r_fec_rsd_abort_packet_cnt_15_8,
+				      &temp1);
+	if (ret)
+		return ret;
+	loc_abort_count = ((u16) temp1 << 8) + temp0;
+
+	/* get error count */
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_7_0,
+				      &temp0);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_15_8,
+				      &temp1);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_r_fec_rsd_bit_err_cnt_23_16,
+				      &temp2);
+	if (ret)
+		return ret;
+	err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0;
+	*post_err_count = err_count - (u32) loc_abort_count *8 * 8;
+
+	/* get RSD packet number */
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0,
+				      &temp0);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8,
+				      &temp1);
+	if (ret)
+		return ret;
+	cw_count = ((u32) temp1 << 8) + temp0;
+	if (cw_count == 0) {
+		err("wrong RSD packet count");
+		return -EIO;
+	}
+	deb_info("POST abort count %d err count %d rsd packets %d\n",
+		 loc_abort_count, err_count, cw_count);
+	*post_cw_count = cw_count - (u32) loc_abort_count;
+	*abort_count = loc_abort_count;
+	return 0;
+
+}
+
+static int af9005_get_post_vit_ber(struct dvb_frontend *fe,
+				   u32 * post_err_count, u32 * post_cw_count,
+				   u16 * abort_count)
+{
+	u32 loc_cw_count = 0, loc_err_count;
+	u16 loc_abort_count;
+	int ret;
+
+	ret =
+	    af9005_get_post_vit_err_cw_count(fe, &loc_err_count, &loc_cw_count,
+					     &loc_abort_count);
+	if (ret)
+		return ret;
+	*post_err_count = loc_err_count;
+	*post_cw_count = loc_cw_count * 204 * 8;
+	*abort_count = loc_abort_count;
+
+	return 0;
+}
+
+static int af9005_get_pre_vit_err_bit_count(struct dvb_frontend *fe,
+					    u32 * pre_err_count,
+					    u32 * pre_bit_count)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	u8 temp, temp0, temp1, temp2;
+	u32 super_frame_count, x, bits;
+	int ret;
+
+	ret =
+	    af9005_read_register_bits(state->d, xd_r_fec_vtb_ber_rdy,
+				      fec_vtb_ber_rdy_pos, fec_vtb_ber_rdy_len,
+				      &temp);
+	if (ret)
+		return ret;
+	if (!temp) {
+		deb_info("viterbi counter not ready\n");
+		return 101;	/* ERR_APO_VTB_COUNTER_NOT_READY; */
+	}
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_7_0,
+				      &temp0);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_15_8,
+				      &temp1);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_r_fec_vtb_err_bit_cnt_23_16,
+				      &temp2);
+	if (ret)
+		return ret;
+	*pre_err_count = ((u32) temp2 << 16) + ((u32) temp1 << 8) + temp0;
+
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0,
+				      &temp0);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8,
+				      &temp1);
+	if (ret)
+		return ret;
+	super_frame_count = ((u32) temp1 << 8) + temp0;
+	if (super_frame_count == 0) {
+		deb_info("super frame count 0\n");
+		return 102;
+	}
+
+	/* read fft mode */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod,
+				      reg_tpsd_txmod_pos, reg_tpsd_txmod_len,
+				      &temp);
+	if (ret)
+		return ret;
+	if (temp == 0) {
+		/* 2K */
+		x = 1512;
+	} else if (temp == 1) {
+		/* 8k */
+		x = 6048;
+	} else {
+		err("Invalid fft mode");
+		return -EINVAL;
+	}
+
+	/* read constellation mode */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
+				      reg_tpsd_const_pos, reg_tpsd_const_len,
+				      &temp);
+	if (ret)
+		return ret;
+	switch (temp) {
+	case 0:		/* QPSK */
+		bits = 2;
+		break;
+	case 1:		/* QAM_16 */
+		bits = 4;
+		break;
+	case 2:		/* QAM_64 */
+		bits = 6;
+		break;
+	default:
+		err("invalid constellation mode");
+		return -EINVAL;
+	}
+	*pre_bit_count = super_frame_count * 68 * 4 * x * bits;
+	deb_info("PRE err count %d frame count %d bit count %d\n",
+		 *pre_err_count, super_frame_count, *pre_bit_count);
+	return 0;
+}
+
+static int af9005_reset_pre_viterbi(struct dvb_frontend *fe)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	int ret;
+
+	/* set super frame count to 1 */
+	ret =
+	    af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_7_0,
+				       1 & 0xff);
+	if (ret)
+		return ret;
+	ret = af9005_write_ofdm_register(state->d, xd_p_fec_super_frm_unit_15_8,
+					 1 >> 8);
+	if (ret)
+		return ret;
+	/* reset pre viterbi error count */
+	ret =
+	    af9005_write_register_bits(state->d, xd_p_fec_vtb_ber_rst,
+				       fec_vtb_ber_rst_pos, fec_vtb_ber_rst_len,
+				       1);
+
+	return ret;
+}
+
+static int af9005_reset_post_viterbi(struct dvb_frontend *fe)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	int ret;
+
+	/* set packet unit */
+	ret =
+	    af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_7_0,
+				       10000 & 0xff);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_write_ofdm_register(state->d, xd_p_fec_rsd_packet_unit_15_8,
+				       10000 >> 8);
+	if (ret)
+		return ret;
+	/* reset post viterbi error count */
+	ret =
+	    af9005_write_register_bits(state->d, xd_p_fec_rsd_ber_rst,
+				       fec_rsd_ber_rst_pos, fec_rsd_ber_rst_len,
+				       1);
+
+	return ret;
+}
+
+static int af9005_get_statistic(struct dvb_frontend *fe)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	int ret, fecavailable;
+	u64 numerator, denominator;
+
+	deb_info("GET STATISTIC\n");
+	ret = af9005_is_fecmon_available(fe, &fecavailable);
+	if (ret)
+		return ret;
+	if (!fecavailable) {
+		deb_info("fecmon not available\n");
+		return 0;
+	}
+
+	ret = af9005_get_pre_vit_err_bit_count(fe, &state->pre_vit_error_count,
+					       &state->pre_vit_bit_count);
+	if (ret == 0) {
+		af9005_reset_pre_viterbi(fe);
+		if (state->pre_vit_bit_count > 0) {
+			/* according to v 0.0.4 of the dvb api ber should be a multiple
+			   of 10E-9 so we have to multiply the error count by
+			   10E9=1000000000 */
+			numerator =
+			    (u64) state->pre_vit_error_count * (u64) 1000000000;
+			denominator = (u64) state->pre_vit_bit_count;
+			state->ber = do_div(numerator, denominator);
+		} else {
+			state->ber = 0xffffffff;
+		}
+	}
+
+	ret = af9005_get_post_vit_ber(fe, &state->post_vit_error_count,
+				      &state->post_vit_bit_count,
+				      &state->abort_count);
+	if (ret == 0) {
+		ret = af9005_reset_post_viterbi(fe);
+		state->unc += state->abort_count;
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+static int af9005_fe_refresh_state(struct dvb_frontend *fe)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	if (time_after(jiffies, state->next_status_check)) {
+		deb_info("REFRESH STATE\n");
+
+		/* statistics */
+		if (af9005_get_statistic(fe))
+			err("get_statistic_failed");
+		state->next_status_check = jiffies + 250 * HZ / 1000;
+	}
+	return 0;
+}
+
+static int af9005_fe_read_status(struct dvb_frontend *fe, fe_status_t * stat)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	u8 temp;
+	int ret;
+
+	if (fe->ops.tuner_ops.release == NULL)
+		return -ENODEV;
+
+	*stat = 0;
+	ret = af9005_read_register_bits(state->d, xd_p_agc_lock,
+					agc_lock_pos, agc_lock_len, &temp);
+	if (ret)
+		return ret;
+	if (temp)
+		*stat |= FE_HAS_SIGNAL;
+
+	ret = af9005_read_register_bits(state->d, xd_p_fd_tpsd_lock,
+					fd_tpsd_lock_pos, fd_tpsd_lock_len,
+					&temp);
+	if (ret)
+		return ret;
+	if (temp)
+		*stat |= FE_HAS_CARRIER;
+
+	ret = af9005_read_register_bits(state->d,
+					xd_r_mp2if_sync_byte_locked,
+					mp2if_sync_byte_locked_pos,
+					mp2if_sync_byte_locked_pos, &temp);
+	if (ret)
+		return ret;
+	if (temp)
+		*stat |= FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_LOCK;
+	if (state->opened)
+		af9005_led_control(state->d, *stat & FE_HAS_LOCK);
+
+	ret =
+	    af9005_read_register_bits(state->d, xd_p_reg_strong_sginal_detected,
+				      reg_strong_sginal_detected_pos,
+				      reg_strong_sginal_detected_len, &temp);
+	if (ret)
+		return ret;
+	if (temp != state->strong) {
+		deb_info("adjust for strong signal %d\n", temp);
+			state->strong = temp;
+	}
+	return 0;
+}
+
+static int af9005_fe_read_ber(struct dvb_frontend *fe, u32 * ber)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	if (fe->ops.tuner_ops.release  == NULL)
+		return -ENODEV;
+	af9005_fe_refresh_state(fe);
+	*ber = state->ber;
+	return 0;
+}
+
+static int af9005_fe_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	if (fe->ops.tuner_ops.release == NULL)
+		return -ENODEV;
+	af9005_fe_refresh_state(fe);
+	*unc = state->unc;
+	return 0;
+}
+
+static int af9005_fe_read_signal_strength(struct dvb_frontend *fe,
+					  u16 * strength)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	int ret;
+	u8 if_gain, rf_gain;
+
+	if (fe->ops.tuner_ops.release == NULL)
+		return -ENODEV;
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_r_reg_aagc_rf_gain,
+				      &rf_gain);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_read_ofdm_register(state->d, xd_r_reg_aagc_if_gain,
+				      &if_gain);
+	if (ret)
+		return ret;
+	/* this value has no real meaning, but i don't have the tables that relate
+	   the rf and if gain with the dbm, so I just scale the value */
+	*strength = (512 - rf_gain - if_gain) << 7;
+	return 0;
+}
+
+static int af9005_fe_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+	/* the snr can be derived from the ber and the constellation
+	   but I don't think this kind of complex calculations belong
+	   in the driver. I may be wrong.... */
+	return -ENOSYS;
+}
+
+static int af9005_fe_program_cfoe(struct dvb_usb_device *d, fe_bandwidth_t bw)
+{
+	u8 temp0, temp1, temp2, temp3, buf[4];
+	int ret;
+	u32 NS_coeff1_2048Nu;
+	u32 NS_coeff1_8191Nu;
+	u32 NS_coeff1_8192Nu;
+	u32 NS_coeff1_8193Nu;
+	u32 NS_coeff2_2k;
+	u32 NS_coeff2_8k;
+
+	switch (bw) {
+	case BANDWIDTH_6_MHZ:
+		NS_coeff1_2048Nu = 0x2ADB6DC;
+		NS_coeff1_8191Nu = 0xAB7313;
+		NS_coeff1_8192Nu = 0xAB6DB7;
+		NS_coeff1_8193Nu = 0xAB685C;
+		NS_coeff2_2k = 0x156DB6E;
+		NS_coeff2_8k = 0x55B6DC;
+		break;
+
+	case BANDWIDTH_7_MHZ:
+		NS_coeff1_2048Nu = 0x3200001;
+		NS_coeff1_8191Nu = 0xC80640;
+		NS_coeff1_8192Nu = 0xC80000;
+		NS_coeff1_8193Nu = 0xC7F9C0;
+		NS_coeff2_2k = 0x1900000;
+		NS_coeff2_8k = 0x640000;
+		break;
+
+	case BANDWIDTH_8_MHZ:
+		NS_coeff1_2048Nu = 0x3924926;
+		NS_coeff1_8191Nu = 0xE4996E;
+		NS_coeff1_8192Nu = 0xE49249;
+		NS_coeff1_8193Nu = 0xE48B25;
+		NS_coeff2_2k = 0x1C92493;
+		NS_coeff2_8k = 0x724925;
+		break;
+	default:
+		err("Invalid bandwith %d.", bw);
+		return -EINVAL;
+	}
+
+	/*
+	 *  write NS_coeff1_2048Nu
+	 */
+
+	temp0 = (u8) (NS_coeff1_2048Nu & 0x000000FF);
+	temp1 = (u8) ((NS_coeff1_2048Nu & 0x0000FF00) >> 8);
+	temp2 = (u8) ((NS_coeff1_2048Nu & 0x00FF0000) >> 16);
+	temp3 = (u8) ((NS_coeff1_2048Nu & 0x03000000) >> 24);
+
+	/*  big endian to make 8051 happy */
+	buf[0] = temp3;
+	buf[1] = temp2;
+	buf[2] = temp1;
+	buf[3] = temp0;
+
+	/*  cfoe_NS_2k_coeff1_25_24 */
+	ret = af9005_write_ofdm_register(d, 0xAE00, buf[0]);
+	if (ret)
+		return ret;
+
+	/*  cfoe_NS_2k_coeff1_23_16 */
+	ret = af9005_write_ofdm_register(d, 0xAE01, buf[1]);
+	if (ret)
+		return ret;
+
+	/*  cfoe_NS_2k_coeff1_15_8 */
+	ret = af9005_write_ofdm_register(d, 0xAE02, buf[2]);
+	if (ret)
+		return ret;
+
+	/*  cfoe_NS_2k_coeff1_7_0 */
+	ret = af9005_write_ofdm_register(d, 0xAE03, buf[3]);
+	if (ret)
+		return ret;
+
+	/*
+	 *  write NS_coeff2_2k
+	 */
+
+	temp0 = (u8) ((NS_coeff2_2k & 0x0000003F));
+	temp1 = (u8) ((NS_coeff2_2k & 0x00003FC0) >> 6);
+	temp2 = (u8) ((NS_coeff2_2k & 0x003FC000) >> 14);
+	temp3 = (u8) ((NS_coeff2_2k & 0x01C00000) >> 22);
+
+	/*  big endian to make 8051 happy */
+	buf[0] = temp3;
+	buf[1] = temp2;
+	buf[2] = temp1;
+	buf[3] = temp0;
+
+	ret = af9005_write_ofdm_register(d, 0xAE04, buf[0]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE05, buf[1]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE06, buf[2]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE07, buf[3]);
+	if (ret)
+		return ret;
+
+	/*
+	 *  write NS_coeff1_8191Nu
+	 */
+
+	temp0 = (u8) ((NS_coeff1_8191Nu & 0x000000FF));
+	temp1 = (u8) ((NS_coeff1_8191Nu & 0x0000FF00) >> 8);
+	temp2 = (u8) ((NS_coeff1_8191Nu & 0x00FFC000) >> 16);
+	temp3 = (u8) ((NS_coeff1_8191Nu & 0x03000000) >> 24);
+
+	/*  big endian to make 8051 happy */
+	buf[0] = temp3;
+	buf[1] = temp2;
+	buf[2] = temp1;
+	buf[3] = temp0;
+
+	ret = af9005_write_ofdm_register(d, 0xAE08, buf[0]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE09, buf[1]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE0A, buf[2]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE0B, buf[3]);
+	if (ret)
+		return ret;
+
+	/*
+	 *  write NS_coeff1_8192Nu
+	 */
+
+	temp0 = (u8) (NS_coeff1_8192Nu & 0x000000FF);
+	temp1 = (u8) ((NS_coeff1_8192Nu & 0x0000FF00) >> 8);
+	temp2 = (u8) ((NS_coeff1_8192Nu & 0x00FFC000) >> 16);
+	temp3 = (u8) ((NS_coeff1_8192Nu & 0x03000000) >> 24);
+
+	/*  big endian to make 8051 happy */
+	buf[0] = temp3;
+	buf[1] = temp2;
+	buf[2] = temp1;
+	buf[3] = temp0;
+
+	ret = af9005_write_ofdm_register(d, 0xAE0C, buf[0]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE0D, buf[1]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE0E, buf[2]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE0F, buf[3]);
+	if (ret)
+		return ret;
+
+	/*
+	 *  write NS_coeff1_8193Nu
+	 */
+
+	temp0 = (u8) ((NS_coeff1_8193Nu & 0x000000FF));
+	temp1 = (u8) ((NS_coeff1_8193Nu & 0x0000FF00) >> 8);
+	temp2 = (u8) ((NS_coeff1_8193Nu & 0x00FFC000) >> 16);
+	temp3 = (u8) ((NS_coeff1_8193Nu & 0x03000000) >> 24);
+
+	/*  big endian to make 8051 happy */
+	buf[0] = temp3;
+	buf[1] = temp2;
+	buf[2] = temp1;
+	buf[3] = temp0;
+
+	ret = af9005_write_ofdm_register(d, 0xAE10, buf[0]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE11, buf[1]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE12, buf[2]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE13, buf[3]);
+	if (ret)
+		return ret;
+
+	/*
+	 *  write NS_coeff2_8k
+	 */
+
+	temp0 = (u8) ((NS_coeff2_8k & 0x0000003F));
+	temp1 = (u8) ((NS_coeff2_8k & 0x00003FC0) >> 6);
+	temp2 = (u8) ((NS_coeff2_8k & 0x003FC000) >> 14);
+	temp3 = (u8) ((NS_coeff2_8k & 0x01C00000) >> 22);
+
+	/*  big endian to make 8051 happy */
+	buf[0] = temp3;
+	buf[1] = temp2;
+	buf[2] = temp1;
+	buf[3] = temp0;
+
+	ret = af9005_write_ofdm_register(d, 0xAE14, buf[0]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE15, buf[1]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE16, buf[2]);
+	if (ret)
+		return ret;
+
+	ret = af9005_write_ofdm_register(d, 0xAE17, buf[3]);
+	return ret;
+
+}
+
+static int af9005_fe_select_bw(struct dvb_usb_device *d, fe_bandwidth_t bw)
+{
+	u8 temp;
+	switch (bw) {
+	case BANDWIDTH_6_MHZ:
+		temp = 0;
+		break;
+	case BANDWIDTH_7_MHZ:
+		temp = 1;
+		break;
+	case BANDWIDTH_8_MHZ:
+		temp = 2;
+		break;
+	default:
+		err("Invalid bandwith %d.", bw);
+		return -EINVAL;
+	}
+	return af9005_write_register_bits(d, xd_g_reg_bw, reg_bw_pos,
+					  reg_bw_len, temp);
+}
+
+static int af9005_fe_power(struct dvb_frontend *fe, int on)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	u8 temp = on;
+	int ret;
+	deb_info("power %s tuner\n", on ? "on" : "off");
+	ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0);
+	return ret;
+}
+
+static struct mt2060_config af9005_mt2060_config = {
+	0xC0
+};
+
+static struct qt1010_config af9005_qt1010_config = {
+	0xC4
+};
+
+static int af9005_fe_init(struct dvb_frontend *fe)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	int ret, i, scriptlen;
+	u8 temp, temp0 = 0, temp1 = 0, temp2 = 0;
+	u8 buf[2];
+	u16 if1;
+
+	deb_info("in af9005_fe_init\n");
+
+	/* reset */
+	deb_info("reset\n");
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst_en,
+					4, 1, 0x01)))
+		return ret;
+	if ((ret = af9005_write_ofdm_register(state->d, APO_REG_RESET, 0)))
+		return ret;
+	/* clear ofdm reset */
+	deb_info("clear ofdm reset\n");
+	for (i = 0; i < 150; i++) {
+		if ((ret =
+		     af9005_read_ofdm_register(state->d,
+					       xd_I2C_reg_ofdm_rst, &temp)))
+			return ret;
+		if (temp & (regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos))
+			break;
+		msleep(10);
+	}
+	if (i == 150)
+		return -ETIMEDOUT;
+
+	/*FIXME in the dump
+	   write B200 A9
+	   write xd_g_reg_ofsm_clk 7
+	   read eepr c6 (2)
+	   read eepr c7 (2)
+	   misc ctrl 3 -> 1
+	   read eepr ca (6)
+	   write xd_g_reg_ofsm_clk 0
+	   write B200 a1
+	 */
+	ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa9);
+	if (ret)
+		return ret;
+	ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x07);
+	if (ret)
+		return ret;
+	temp = 0x01;
+	ret = af9005_send_command(state->d, 0x03, &temp, 1, NULL, 0);
+	if (ret)
+		return ret;
+	ret = af9005_write_ofdm_register(state->d, xd_g_reg_ofsm_clk, 0x00);
+	if (ret)
+		return ret;
+	ret = af9005_write_ofdm_register(state->d, 0xb200, 0xa1);
+	if (ret)
+		return ret;
+
+	temp = regmask[reg_ofdm_rst_len - 1] << reg_ofdm_rst_pos;
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst,
+					reg_ofdm_rst_pos, reg_ofdm_rst_len, 1)))
+		return ret;
+	ret = af9005_write_register_bits(state->d, xd_I2C_reg_ofdm_rst,
+					 reg_ofdm_rst_pos, reg_ofdm_rst_len, 0);
+
+	if (ret)
+		return ret;
+	/* don't know what register aefc is, but this is what the windows driver does */
+	ret = af9005_write_ofdm_register(state->d, 0xaefc, 0);
+	if (ret)
+		return ret;
+
+	/* set stand alone chip */
+	deb_info("set stand alone chip\n");
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_p_reg_dca_stand_alone,
+					reg_dca_stand_alone_pos,
+					reg_dca_stand_alone_len, 1)))
+		return ret;
+
+	/* set dca upper & lower chip */
+	deb_info("set dca upper & lower chip\n");
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_p_reg_dca_upper_chip,
+					reg_dca_upper_chip_pos,
+					reg_dca_upper_chip_len, 0)))
+		return ret;
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_p_reg_dca_lower_chip,
+					reg_dca_lower_chip_pos,
+					reg_dca_lower_chip_len, 0)))
+		return ret;
+
+	/* set 2wire master clock to 0x14 (for 60KHz) */
+	deb_info("set 2wire master clock to 0x14 (for 60KHz)\n");
+	if ((ret =
+	     af9005_write_ofdm_register(state->d, xd_I2C_i2c_m_period, 0x14)))
+		return ret;
+
+	/* clear dca enable chip */
+	deb_info("clear dca enable chip\n");
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_p_reg_dca_en,
+					reg_dca_en_pos, reg_dca_en_len, 0)))
+		return ret;
+	/* FIXME these are register bits, but I don't know which ones */
+	ret = af9005_write_ofdm_register(state->d, 0xa16c, 1);
+	if (ret)
+		return ret;
+	ret = af9005_write_ofdm_register(state->d, 0xa3c1, 0);
+	if (ret)
+		return ret;
+
+	/* init other parameters: program cfoe and select bandwith */
+	deb_info("program cfoe\n");
+	if ((ret = af9005_fe_program_cfoe(state->d, BANDWIDTH_6_MHZ)))
+		return ret;
+	/* set read-update bit for constellation */
+	deb_info("set read-update bit for constellation\n");
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_p_reg_feq_read_update,
+					reg_feq_read_update_pos,
+					reg_feq_read_update_len, 1)))
+		return ret;
+
+	/* sample code has a set MPEG TS code here
+	   but sniffing reveals that it doesn't do it */
+
+	/* set read-update bit to 1 for DCA constellation */
+	deb_info("set read-update bit 1 for DCA constellation\n");
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_p_reg_dca_read_update,
+					reg_dca_read_update_pos,
+					reg_dca_read_update_len, 1)))
+		return ret;
+
+	/* enable fec monitor */
+	deb_info("enable fec monitor\n");
+	if ((ret =
+	     af9005_write_register_bits(state->d, xd_p_fec_vtb_rsd_mon_en,
+					fec_vtb_rsd_mon_en_pos,
+					fec_vtb_rsd_mon_en_len, 1)))
+		return ret;
+
+	/* FIXME should be register bits, I don't know which ones */
+	ret = af9005_write_ofdm_register(state->d, 0xa601, 0);
+
+	/* set api_retrain_never_freeze */
+	deb_info("set api_retrain_never_freeze\n");
+	if ((ret = af9005_write_ofdm_register(state->d, 0xaefb, 0x01)))
+		return ret;
+
+	/* load init script */
+	deb_info("load init script\n");
+	scriptlen = sizeof(script) / sizeof(RegDesc);
+	for (i = 0; i < scriptlen; i++) {
+		if ((ret =
+		     af9005_write_register_bits(state->d, script[i].reg,
+						script[i].pos,
+						script[i].len, script[i].val)))
+			return ret;
+		/* save 3 bytes of original fcw */
+		if (script[i].reg == 0xae18)
+			temp2 = script[i].val;
+		if (script[i].reg == 0xae19)
+			temp1 = script[i].val;
+		if (script[i].reg == 0xae1a)
+			temp0 = script[i].val;
+
+		/* save original unplug threshold */
+		if (script[i].reg == xd_p_reg_unplug_th)
+			state->original_if_unplug_th = script[i].val;
+		if (script[i].reg == xd_p_reg_unplug_rf_gain_th)
+			state->original_rf_unplug_th = script[i].val;
+		if (script[i].reg == xd_p_reg_unplug_dtop_if_gain_th)
+			state->original_dtop_if_unplug_th = script[i].val;
+		if (script[i].reg == xd_p_reg_unplug_dtop_rf_gain_th)
+			state->original_dtop_rf_unplug_th = script[i].val;
+
+	}
+	state->original_fcw =
+	    ((u32) temp2 << 16) + ((u32) temp1 << 8) + (u32) temp0;
+
+
+	/* save original TOPs */
+	deb_info("save original TOPs\n");
+
+	/*  RF TOP */
+	ret =
+	    af9005_read_word_agc(state->d,
+				 xd_p_reg_aagc_rf_top_numerator_9_8,
+				 xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2,
+				 &state->original_rf_top);
+	if (ret)
+		return ret;
+
+	/*  IF TOP */
+	ret =
+	    af9005_read_word_agc(state->d,
+				 xd_p_reg_aagc_if_top_numerator_9_8,
+				 xd_p_reg_aagc_if_top_numerator_7_0, 0, 2,
+				 &state->original_if_top);
+	if (ret)
+		return ret;
+
+	/*  ACI 0 IF TOP */
+	ret =
+	    af9005_read_word_agc(state->d, 0xA60E, 0xA60A, 4, 2,
+				 &state->original_aci0_if_top);
+	if (ret)
+		return ret;
+
+	/*  ACI 1 IF TOP */
+	ret =
+	    af9005_read_word_agc(state->d, 0xA60E, 0xA60B, 6, 2,
+				 &state->original_aci1_if_top);
+	if (ret)
+		return ret;
+
+	/* attach tuner and init */
+	if (fe->ops.tuner_ops.release == NULL) {
+		/* read tuner and board id from eeprom */
+		ret = af9005_read_eeprom(adap->dev, 0xc6, buf, 2);
+		if (ret) {
+			err("Impossible to read EEPROM\n");
+			return ret;
+		}
+		deb_info("Tuner id %d, board id %d\n", buf[0], buf[1]);
+		switch (buf[0]) {
+		case 2:	/* MT2060 */
+			/* read if1 from eeprom */
+			ret = af9005_read_eeprom(adap->dev, 0xc8, buf, 2);
+			if (ret) {
+				err("Impossible to read EEPROM\n");
+				return ret;
+			}
+			if1 = (u16) (buf[0] << 8) + buf[1];
+			if (dvb_attach(mt2060_attach, fe, &adap->dev->i2c_adap,
+					 &af9005_mt2060_config, if1) == NULL) {
+				deb_info("MT2060 attach failed\n");
+				return -ENODEV;
+			}
+			break;
+		case 3:	/* QT1010 */
+		case 9:	/* QT1010B */
+			if (dvb_attach(qt1010_attach, fe, &adap->dev->i2c_adap,
+					&af9005_qt1010_config) ==NULL) {
+				deb_info("QT1010 attach failed\n");
+				return -ENODEV;
+			}
+			break;
+		default:
+			err("Unsupported tuner type %d", buf[0]);
+			return -ENODEV;
+		}
+		ret = fe->ops.tuner_ops.init(fe);
+		if (ret)
+			return ret;
+	}
+
+	deb_info("profit!\n");
+	return 0;
+}
+
+static int af9005_fe_sleep(struct dvb_frontend *fe)
+{
+	return af9005_fe_power(fe, 0);
+}
+
+static int af9005_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+
+	if (acquire) {
+		state->opened++;
+	} else {
+
+		state->opened--;
+		if (!state->opened)
+			af9005_led_control(state->d, 0);
+	}
+	return 0;
+}
+
+static int af9005_fe_set_frontend(struct dvb_frontend *fe,
+				  struct dvb_frontend_parameters *fep)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	int ret;
+	u8 temp, temp0, temp1, temp2;
+
+	deb_info("af9005_fe_set_frontend freq %d bw %d\n", fep->frequency,
+		 fep->u.ofdm.bandwidth);
+	if (fe->ops.tuner_ops.release == NULL) {
+		err("Tuner not attached");
+		return -ENODEV;
+	}
+
+	deb_info("turn off led\n");
+	/* not in the log */
+	ret = af9005_led_control(state->d, 0);
+	if (ret)
+		return ret;
+	/* not sure about the bits */
+	ret = af9005_write_register_bits(state->d, XD_MP2IF_MISC, 2, 1, 0);
+	if (ret)
+		return ret;
+
+	/* set FCW to default value */
+	deb_info("set FCW to default value\n");
+	temp0 = (u8) (state->original_fcw & 0x000000ff);
+	temp1 = (u8) ((state->original_fcw & 0x0000ff00) >> 8);
+	temp2 = (u8) ((state->original_fcw & 0x00ff0000) >> 16);
+	ret = af9005_write_ofdm_register(state->d, 0xae1a, temp0);
+	if (ret)
+		return ret;
+	ret = af9005_write_ofdm_register(state->d, 0xae19, temp1);
+	if (ret)
+		return ret;
+	ret = af9005_write_ofdm_register(state->d, 0xae18, temp2);
+	if (ret)
+		return ret;
+
+	/* restore original TOPs */
+	deb_info("restore original TOPs\n");
+	ret =
+	    af9005_write_word_agc(state->d,
+				  xd_p_reg_aagc_rf_top_numerator_9_8,
+				  xd_p_reg_aagc_rf_top_numerator_7_0, 0, 2,
+				  state->original_rf_top);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_write_word_agc(state->d,
+				  xd_p_reg_aagc_if_top_numerator_9_8,
+				  xd_p_reg_aagc_if_top_numerator_7_0, 0, 2,
+				  state->original_if_top);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_write_word_agc(state->d, 0xA60E, 0xA60A, 4, 2,
+				  state->original_aci0_if_top);
+	if (ret)
+		return ret;
+	ret =
+	    af9005_write_word_agc(state->d, 0xA60E, 0xA60B, 6, 2,
+				  state->original_aci1_if_top);
+	if (ret)
+		return ret;
+
+	/* select bandwith */
+	deb_info("select bandwidth");
+	ret = af9005_fe_select_bw(state->d, fep->u.ofdm.bandwidth);
+	if (ret)
+		return ret;
+	ret = af9005_fe_program_cfoe(state->d, fep->u.ofdm.bandwidth);
+	if (ret)
+		return ret;
+
+	/* clear easy mode flag */
+	deb_info("clear easy mode flag\n");
+	ret = af9005_write_ofdm_register(state->d, 0xaefd, 0);
+	if (ret)
+		return ret;
+
+	/* set unplug threshold to original value */
+	deb_info("set unplug threshold to original value\n");
+	ret =
+	    af9005_write_ofdm_register(state->d, xd_p_reg_unplug_th,
+				       state->original_if_unplug_th);
+	if (ret)
+		return ret;
+	/* set tuner */
+	deb_info("set tuner\n");
+	ret = fe->ops.tuner_ops.set_params(fe, fep);
+	if (ret)
+		return ret;
+
+	/* trigger ofsm */
+	deb_info("trigger ofsm\n");
+	temp = 0;
+	ret = af9005_write_tuner_registers(state->d, 0xffff, &temp, 1);
+	if (ret)
+		return ret;
+
+	/* clear retrain and freeze flag */
+	deb_info("clear retrain and freeze flag\n");
+	ret =
+	    af9005_write_register_bits(state->d,
+				       xd_p_reg_api_retrain_request,
+				       reg_api_retrain_request_pos, 2, 0);
+	if (ret)
+		return ret;
+
+	/* reset pre viterbi and post viterbi registers and statistics */
+	af9005_reset_pre_viterbi(fe);
+	af9005_reset_post_viterbi(fe);
+	state->pre_vit_error_count = 0;
+	state->pre_vit_bit_count = 0;
+	state->ber = 0;
+	state->post_vit_error_count = 0;
+	/* state->unc = 0; commented out since it should be ever increasing */
+	state->abort_count = 0;
+
+	state->next_status_check = jiffies;
+	state->strong = -1;
+
+	return 0;
+}
+
+static int af9005_fe_get_frontend(struct dvb_frontend *fe,
+				  struct dvb_frontend_parameters *fep)
+{
+	struct af9005_fe_state *state = fe->demodulator_priv;
+	int ret;
+	u8 temp;
+
+	/* mode */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_const,
+				      reg_tpsd_const_pos, reg_tpsd_const_len,
+				      &temp);
+	if (ret)
+		return ret;
+	deb_info("===== fe_get_frontend ==============\n");
+	deb_info("CONSTELLATION ");
+	switch (temp) {
+	case 0:
+		fep->u.ofdm.constellation = QPSK;
+		deb_info("QPSK\n");
+		break;
+	case 1:
+		fep->u.ofdm.constellation = QAM_16;
+		deb_info("QAM_16\n");
+		break;
+	case 2:
+		fep->u.ofdm.constellation = QAM_64;
+		deb_info("QAM_64\n");
+		break;
+	}
+
+	/* tps hierarchy and alpha value */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_hier,
+				      reg_tpsd_hier_pos, reg_tpsd_hier_len,
+				      &temp);
+	if (ret)
+		return ret;
+	deb_info("HIERARCHY ");
+	switch (temp) {
+	case 0:
+		fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+		deb_info("NONE\n");
+		break;
+	case 1:
+		fep->u.ofdm.hierarchy_information = HIERARCHY_1;
+		deb_info("1\n");
+		break;
+	case 2:
+		fep->u.ofdm.hierarchy_information = HIERARCHY_2;
+		deb_info("2\n");
+		break;
+	case 3:
+		fep->u.ofdm.hierarchy_information = HIERARCHY_4;
+		deb_info("4\n");
+		break;
+	}
+
+	/*  high/low priority     */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_dec_pri,
+				      reg_dec_pri_pos, reg_dec_pri_len, &temp);
+	if (ret)
+		return ret;
+	/* if temp is set = high priority */
+	deb_info("PRIORITY %s\n", temp ? "high" : "low");
+
+	/* high coderate */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_hpcr,
+				      reg_tpsd_hpcr_pos, reg_tpsd_hpcr_len,
+				      &temp);
+	if (ret)
+		return ret;
+	deb_info("CODERATE HP ");
+	switch (temp) {
+	case 0:
+		fep->u.ofdm.code_rate_HP = FEC_1_2;
+		deb_info("FEC_1_2\n");
+		break;
+	case 1:
+		fep->u.ofdm.code_rate_HP = FEC_2_3;
+		deb_info("FEC_2_3\n");
+		break;
+	case 2:
+		fep->u.ofdm.code_rate_HP = FEC_3_4;
+		deb_info("FEC_3_4\n");
+		break;
+	case 3:
+		fep->u.ofdm.code_rate_HP = FEC_5_6;
+		deb_info("FEC_5_6\n");
+		break;
+	case 4:
+		fep->u.ofdm.code_rate_HP = FEC_7_8;
+		deb_info("FEC_7_8\n");
+		break;
+	}
+
+	/* low coderate */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_lpcr,
+				      reg_tpsd_lpcr_pos, reg_tpsd_lpcr_len,
+				      &temp);
+	if (ret)
+		return ret;
+	deb_info("CODERATE LP ");
+	switch (temp) {
+	case 0:
+		fep->u.ofdm.code_rate_LP = FEC_1_2;
+		deb_info("FEC_1_2\n");
+		break;
+	case 1:
+		fep->u.ofdm.code_rate_LP = FEC_2_3;
+		deb_info("FEC_2_3\n");
+		break;
+	case 2:
+		fep->u.ofdm.code_rate_LP = FEC_3_4;
+		deb_info("FEC_3_4\n");
+		break;
+	case 3:
+		fep->u.ofdm.code_rate_LP = FEC_5_6;
+		deb_info("FEC_5_6\n");
+		break;
+	case 4:
+		fep->u.ofdm.code_rate_LP = FEC_7_8;
+		deb_info("FEC_7_8\n");
+		break;
+	}
+
+	/* guard interval */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_gi,
+				      reg_tpsd_gi_pos, reg_tpsd_gi_len, &temp);
+	if (ret)
+		return ret;
+	deb_info("GUARD INTERVAL ");
+	switch (temp) {
+	case 0:
+		fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+		deb_info("1_32\n");
+		break;
+	case 1:
+		fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16;
+		deb_info("1_16\n");
+		break;
+	case 2:
+		fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8;
+		deb_info("1_8\n");
+		break;
+	case 3:
+		fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4;
+		deb_info("1_4\n");
+		break;
+	}
+
+	/* fft */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_tpsd_txmod,
+				      reg_tpsd_txmod_pos, reg_tpsd_txmod_len,
+				      &temp);
+	if (ret)
+		return ret;
+	deb_info("TRANSMISSION MODE ");
+	switch (temp) {
+	case 0:
+		fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
+		deb_info("2K\n");
+		break;
+	case 1:
+		fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+		deb_info("8K\n");
+		break;
+	}
+
+	/* bandwidth      */
+	ret =
+	    af9005_read_register_bits(state->d, xd_g_reg_bw, reg_bw_pos,
+				      reg_bw_len, &temp);
+	deb_info("BANDWIDTH ");
+	switch (temp) {
+	case 0:
+		fep->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+		deb_info("6\n");
+		break;
+	case 1:
+		fep->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+		deb_info("7\n");
+		break;
+	case 2:
+		fep->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+		deb_info("8\n");
+		break;
+	}
+	return 0;
+}
+
+static void af9005_fe_release(struct dvb_frontend *fe)
+{
+	struct af9005_fe_state *state =
+	    (struct af9005_fe_state *)fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops af9005_fe_ops;
+
+struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d)
+{
+	struct af9005_fe_state *state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kzalloc(sizeof(struct af9005_fe_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	deb_info("attaching frontend af9005\n");
+
+	state->d = d;
+	state->opened = 0;
+
+	memcpy(&state->frontend.ops, &af9005_fe_ops,
+	       sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	return &state->frontend;
+      error:
+	return NULL;
+}
+
+static struct dvb_frontend_ops af9005_fe_ops = {
+	.info = {
+		 .name = "AF9005 USB DVB-T",
+		 .type = FE_OFDM,
+		 .frequency_min = 44250000,
+		 .frequency_max = 867250000,
+		 .frequency_stepsize = 250000,
+		 .caps = FE_CAN_INVERSION_AUTO |
+		 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+		 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+		 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+		 FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+		 FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER |
+		 FE_CAN_HIERARCHY_AUTO,
+		 },
+
+	.release = af9005_fe_release,
+
+	.init = af9005_fe_init,
+	.sleep = af9005_fe_sleep,
+	.ts_bus_ctrl = af9005_ts_bus_ctrl,
+
+	.set_frontend = af9005_fe_set_frontend,
+	.get_frontend = af9005_fe_get_frontend,
+
+	.read_status = af9005_fe_read_status,
+	.read_ber = af9005_fe_read_ber,
+	.read_signal_strength = af9005_fe_read_signal_strength,
+	.read_snr = af9005_fe_read_snr,
+	.read_ucblocks = af9005_fe_read_unc_blocks,
+};
diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c
new file mode 100644
index 0000000..ff00c0e
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005-remote.c
@@ -0,0 +1,157 @@
+/* DVB USB compliant Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Standard remote decode function
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided 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.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/REDME.dvb-usb for more information
+ */
+#include "af9005.h"
+/* debug */
+int dvb_usb_af9005_remote_debug;
+module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+		 "enable (1) or disable (0) debug messages."
+		 DVB_USB_DEBUG_STATUS);
+
+#define deb_decode(args...)   dprintk(dvb_usb_af9005_remote_debug,0x01,args)
+
+struct dvb_usb_rc_key af9005_rc_keys[] = {
+
+	{0x01, 0xb7, KEY_POWER},
+	{0x01, 0xa7, KEY_VOLUMEUP},
+	{0x01, 0x87, KEY_CHANNELUP},
+	{0x01, 0x7f, KEY_MUTE},
+	{0x01, 0xbf, KEY_VOLUMEDOWN},
+	{0x01, 0x3f, KEY_CHANNELDOWN},
+	{0x01, 0xdf, KEY_1},
+	{0x01, 0x5f, KEY_2},
+	{0x01, 0x9f, KEY_3},
+	{0x01, 0x1f, KEY_4},
+	{0x01, 0xef, KEY_5},
+	{0x01, 0x6f, KEY_6},
+	{0x01, 0xaf, KEY_7},
+	{0x01, 0x27, KEY_8},
+	{0x01, 0x07, KEY_9},
+	{0x01, 0xcf, KEY_ZOOM},
+	{0x01, 0x4f, KEY_0},
+	{0x01, 0x8f, KEY_GOTO},	/* marked jump on the remote */
+
+	{0x00, 0xbd, KEY_POWER},
+	{0x00, 0x7d, KEY_VOLUMEUP},
+	{0x00, 0xfd, KEY_CHANNELUP},
+	{0x00, 0x9d, KEY_MUTE},
+	{0x00, 0x5d, KEY_VOLUMEDOWN},
+	{0x00, 0xdd, KEY_CHANNELDOWN},
+	{0x00, 0xad, KEY_1},
+	{0x00, 0x6d, KEY_2},
+	{0x00, 0xed, KEY_3},
+	{0x00, 0x8d, KEY_4},
+	{0x00, 0x4d, KEY_5},
+	{0x00, 0xcd, KEY_6},
+	{0x00, 0xb5, KEY_7},
+	{0x00, 0x75, KEY_8},
+	{0x00, 0xf5, KEY_9},
+	{0x00, 0x95, KEY_ZOOM},
+	{0x00, 0x55, KEY_0},
+	{0x00, 0xd5, KEY_GOTO},	/* marked jump on the remote */
+};
+
+int af9005_rc_keys_size = ARRAY_SIZE(af9005_rc_keys);
+
+static int repeatable_keys[] = {
+	KEY_VOLUMEUP,
+	KEY_VOLUMEDOWN,
+	KEY_CHANNELUP,
+	KEY_CHANNELDOWN
+};
+
+int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
+		     int *state)
+{
+	u16 mark, space;
+	u32 result;
+	u8 cust, dat, invdat;
+	int i;
+
+	if (len >= 6) {
+		mark = (u16) (data[0] << 8) + data[1];
+		space = (u16) (data[2] << 8) + data[3];
+		if (space * 3 < mark) {
+			for (i = 0; i < ARRAY_SIZE(repeatable_keys); i++) {
+				if (d->last_event == repeatable_keys[i]) {
+					*state = REMOTE_KEY_REPEAT;
+					*event = d->last_event;
+					deb_decode("repeat key, event %x\n",
+						   *event);
+					return 0;
+				}
+			}
+			deb_decode("repeated key ignored (non repeatable)\n");
+			return 0;
+		} else if (len >= 33 * 4) {	/*32 bits + start code */
+			result = 0;
+			for (i = 4; i < 4 + 32 * 4; i += 4) {
+				result <<= 1;
+				mark = (u16) (data[i] << 8) + data[i + 1];
+				mark >>= 1;
+				space = (u16) (data[i + 2] << 8) + data[i + 3];
+				space >>= 1;
+				if (mark * 2 > space)
+					result += 1;
+			}
+			deb_decode("key pressed, raw value %x\n", result);
+			if ((result & 0xff000000) != 0xfe000000) {
+				deb_decode
+				    ("doesn't start with 0xfe, ignored\n");
+				return 0;
+			}
+			cust = (result >> 16) & 0xff;
+			dat = (result >> 8) & 0xff;
+			invdat = (~result) & 0xff;
+			if (dat != invdat) {
+				deb_decode("code != inverted code\n");
+				return 0;
+			}
+			for (i = 0; i < af9005_rc_keys_size; i++) {
+				if (af9005_rc_keys[i].custom == cust
+				    && af9005_rc_keys[i].data == dat) {
+					*event = af9005_rc_keys[i].event;
+					*state = REMOTE_KEY_PRESSED;
+					deb_decode
+					    ("key pressed, event %x\n", *event);
+					return 0;
+				}
+			}
+			deb_decode("not found in table\n");
+		}
+	}
+	return 0;
+}
+
+EXPORT_SYMBOL(af9005_rc_keys);
+EXPORT_SYMBOL(af9005_rc_keys_size);
+EXPORT_SYMBOL(af9005_rc_decode);
+
+MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
+MODULE_DESCRIPTION
+    ("Standard remote control decoder for Afatech 9005 DVB-T USB1.1 stick");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9005-script.h b/drivers/media/dvb/dvb-usb/af9005-script.h
new file mode 100644
index 0000000..6eeaae5
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005-script.h
@@ -0,0 +1,203 @@
+/*
+File automatically generated by createinit.py using data
+extracted from AF05BDA.sys (windows driver):
+
+dd if=AF05BDA.sys of=initsequence bs=1 skip=88316 count=1110
+python createinit.py > af9005-script.h
+
+*/
+
+typedef struct {
+	u16 reg;
+	u8 pos;
+	u8 len;
+	u8 val;
+} RegDesc;
+
+RegDesc script[] = {
+	{0xa180, 0x0, 0x8, 0xa},
+	{0xa181, 0x0, 0x8, 0xd7},
+	{0xa182, 0x0, 0x8, 0xa3},
+	{0xa0a0, 0x0, 0x8, 0x0},
+	{0xa0a1, 0x0, 0x5, 0x0},
+	{0xa0a1, 0x5, 0x1, 0x1},
+	{0xa0c0, 0x0, 0x4, 0x1},
+	{0xa20e, 0x4, 0x4, 0xa},
+	{0xa20f, 0x0, 0x8, 0x40},
+	{0xa210, 0x0, 0x8, 0x8},
+	{0xa32a, 0x0, 0x4, 0xa},
+	{0xa32c, 0x0, 0x8, 0x20},
+	{0xa32b, 0x0, 0x8, 0x15},
+	{0xa1a0, 0x1, 0x1, 0x1},
+	{0xa000, 0x0, 0x1, 0x1},
+	{0xa000, 0x1, 0x1, 0x0},
+	{0xa001, 0x1, 0x1, 0x1},
+	{0xa001, 0x0, 0x1, 0x0},
+	{0xa001, 0x5, 0x1, 0x0},
+	{0xa00e, 0x0, 0x5, 0x10},
+	{0xa00f, 0x0, 0x3, 0x4},
+	{0xa00f, 0x3, 0x3, 0x5},
+	{0xa010, 0x0, 0x3, 0x4},
+	{0xa010, 0x3, 0x3, 0x5},
+	{0xa016, 0x4, 0x4, 0x3},
+	{0xa01f, 0x0, 0x6, 0xa},
+	{0xa020, 0x0, 0x6, 0xa},
+	{0xa2bc, 0x0, 0x1, 0x1},
+	{0xa2bc, 0x5, 0x1, 0x1},
+	{0xa015, 0x0, 0x8, 0x50},
+	{0xa016, 0x0, 0x1, 0x0},
+	{0xa02a, 0x0, 0x8, 0x50},
+	{0xa029, 0x0, 0x8, 0x4b},
+	{0xa614, 0x0, 0x8, 0x46},
+	{0xa002, 0x0, 0x5, 0x19},
+	{0xa003, 0x0, 0x5, 0x1a},
+	{0xa004, 0x0, 0x5, 0x19},
+	{0xa005, 0x0, 0x5, 0x1a},
+	{0xa008, 0x0, 0x8, 0x69},
+	{0xa009, 0x0, 0x2, 0x2},
+	{0xae1b, 0x0, 0x8, 0x69},
+	{0xae1c, 0x0, 0x8, 0x2},
+	{0xae1d, 0x0, 0x8, 0x2a},
+	{0xa022, 0x0, 0x8, 0xaa},
+	{0xa006, 0x0, 0x8, 0xc8},
+	{0xa007, 0x0, 0x2, 0x0},
+	{0xa00c, 0x0, 0x8, 0xba},
+	{0xa00d, 0x0, 0x2, 0x2},
+	{0xa608, 0x0, 0x8, 0xba},
+	{0xa60e, 0x0, 0x2, 0x2},
+	{0xa609, 0x0, 0x8, 0x80},
+	{0xa60e, 0x2, 0x2, 0x3},
+	{0xa00a, 0x0, 0x8, 0xb6},
+	{0xa00b, 0x0, 0x2, 0x0},
+	{0xa011, 0x0, 0x8, 0xb9},
+	{0xa012, 0x0, 0x2, 0x0},
+	{0xa013, 0x0, 0x8, 0xbd},
+	{0xa014, 0x0, 0x2, 0x2},
+	{0xa366, 0x0, 0x1, 0x1},
+	{0xa2bc, 0x3, 0x1, 0x0},
+	{0xa2bd, 0x0, 0x8, 0xa},
+	{0xa2be, 0x0, 0x8, 0x14},
+	{0xa2bf, 0x0, 0x8, 0x8},
+	{0xa60a, 0x0, 0x8, 0xbd},
+	{0xa60e, 0x4, 0x2, 0x2},
+	{0xa60b, 0x0, 0x8, 0x86},
+	{0xa60e, 0x6, 0x2, 0x3},
+	{0xa001, 0x2, 0x2, 0x1},
+	{0xa1c7, 0x0, 0x8, 0xf5},
+	{0xa03d, 0x0, 0x8, 0xb1},
+	{0xa616, 0x0, 0x8, 0xff},
+	{0xa617, 0x0, 0x8, 0xad},
+	{0xa618, 0x0, 0x8, 0xad},
+	{0xa61e, 0x3, 0x1, 0x1},
+	{0xae1a, 0x0, 0x8, 0x0},
+	{0xae19, 0x0, 0x8, 0xc8},
+	{0xae18, 0x0, 0x8, 0x61},
+	{0xa140, 0x0, 0x8, 0x0},
+	{0xa141, 0x0, 0x8, 0xc8},
+	{0xa142, 0x0, 0x7, 0x61},
+	{0xa023, 0x0, 0x8, 0xff},
+	{0xa021, 0x0, 0x8, 0xad},
+	{0xa026, 0x0, 0x1, 0x0},
+	{0xa024, 0x0, 0x8, 0xff},
+	{0xa025, 0x0, 0x8, 0xff},
+	{0xa1c8, 0x0, 0x8, 0xf},
+	{0xa2bc, 0x1, 0x1, 0x0},
+	{0xa60c, 0x0, 0x4, 0x5},
+	{0xa60c, 0x4, 0x4, 0x6},
+	{0xa60d, 0x0, 0x8, 0xa},
+	{0xa371, 0x0, 0x1, 0x1},
+	{0xa366, 0x1, 0x3, 0x7},
+	{0xa338, 0x0, 0x8, 0x10},
+	{0xa339, 0x0, 0x6, 0x7},
+	{0xa33a, 0x0, 0x6, 0x1f},
+	{0xa33b, 0x0, 0x8, 0xf6},
+	{0xa33c, 0x3, 0x5, 0x4},
+	{0xa33d, 0x4, 0x4, 0x0},
+	{0xa33d, 0x1, 0x1, 0x1},
+	{0xa33d, 0x2, 0x1, 0x1},
+	{0xa33d, 0x3, 0x1, 0x1},
+	{0xa16d, 0x0, 0x4, 0xf},
+	{0xa161, 0x0, 0x5, 0x5},
+	{0xa162, 0x0, 0x4, 0x5},
+	{0xa165, 0x0, 0x8, 0xff},
+	{0xa166, 0x0, 0x8, 0x9c},
+	{0xa2c3, 0x0, 0x4, 0x5},
+	{0xa61a, 0x0, 0x6, 0xf},
+	{0xb200, 0x0, 0x8, 0xa1},
+	{0xb201, 0x0, 0x8, 0x7},
+	{0xa093, 0x0, 0x1, 0x0},
+	{0xa093, 0x1, 0x5, 0xf},
+	{0xa094, 0x0, 0x8, 0xff},
+	{0xa095, 0x0, 0x8, 0xf},
+	{0xa080, 0x2, 0x5, 0x3},
+	{0xa081, 0x0, 0x4, 0x0},
+	{0xa081, 0x4, 0x4, 0x9},
+	{0xa082, 0x0, 0x5, 0x1f},
+	{0xa08d, 0x0, 0x8, 0x1},
+	{0xa083, 0x0, 0x8, 0x32},
+	{0xa084, 0x0, 0x1, 0x0},
+	{0xa08e, 0x0, 0x8, 0x3},
+	{0xa085, 0x0, 0x8, 0x32},
+	{0xa086, 0x0, 0x3, 0x0},
+	{0xa087, 0x0, 0x8, 0x6e},
+	{0xa088, 0x0, 0x5, 0x15},
+	{0xa089, 0x0, 0x8, 0x0},
+	{0xa08a, 0x0, 0x5, 0x19},
+	{0xa08b, 0x0, 0x8, 0x92},
+	{0xa08c, 0x0, 0x5, 0x1c},
+	{0xa120, 0x0, 0x8, 0x0},
+	{0xa121, 0x0, 0x5, 0x10},
+	{0xa122, 0x0, 0x8, 0x0},
+	{0xa123, 0x0, 0x7, 0x40},
+	{0xa123, 0x7, 0x1, 0x0},
+	{0xa124, 0x0, 0x8, 0x13},
+	{0xa125, 0x0, 0x7, 0x10},
+	{0xa1c0, 0x0, 0x8, 0x0},
+	{0xa1c1, 0x0, 0x5, 0x4},
+	{0xa1c2, 0x0, 0x8, 0x0},
+	{0xa1c3, 0x0, 0x5, 0x10},
+	{0xa1c3, 0x5, 0x3, 0x0},
+	{0xa1c4, 0x0, 0x6, 0x0},
+	{0xa1c5, 0x0, 0x7, 0x10},
+	{0xa100, 0x0, 0x8, 0x0},
+	{0xa101, 0x0, 0x5, 0x10},
+	{0xa102, 0x0, 0x8, 0x0},
+	{0xa103, 0x0, 0x7, 0x40},
+	{0xa103, 0x7, 0x1, 0x0},
+	{0xa104, 0x0, 0x8, 0x18},
+	{0xa105, 0x0, 0x7, 0xa},
+	{0xa106, 0x0, 0x8, 0x20},
+	{0xa107, 0x0, 0x8, 0x40},
+	{0xa108, 0x0, 0x4, 0x0},
+	{0xa38c, 0x0, 0x8, 0xfc},
+	{0xa38d, 0x0, 0x8, 0x0},
+	{0xa38e, 0x0, 0x8, 0x7e},
+	{0xa38f, 0x0, 0x8, 0x0},
+	{0xa390, 0x0, 0x8, 0x2f},
+	{0xa60f, 0x5, 0x1, 0x1},
+	{0xa170, 0x0, 0x8, 0xdc},
+	{0xa171, 0x0, 0x2, 0x0},
+	{0xa2ae, 0x0, 0x1, 0x1},
+	{0xa2ae, 0x1, 0x1, 0x1},
+	{0xa392, 0x0, 0x1, 0x1},
+	{0xa391, 0x2, 0x1, 0x0},
+	{0xabc1, 0x0, 0x8, 0xff},
+	{0xabc2, 0x0, 0x8, 0x0},
+	{0xabc8, 0x0, 0x8, 0x8},
+	{0xabca, 0x0, 0x8, 0x10},
+	{0xabcb, 0x0, 0x1, 0x0},
+	{0xabc3, 0x5, 0x3, 0x7},
+	{0xabc0, 0x6, 0x1, 0x0},
+	{0xabc0, 0x4, 0x2, 0x0},
+	{0xa344, 0x4, 0x4, 0x1},
+	{0xabc0, 0x7, 0x1, 0x1},
+	{0xabc0, 0x2, 0x1, 0x1},
+	{0xa345, 0x0, 0x8, 0x66},
+	{0xa346, 0x0, 0x8, 0x66},
+	{0xa347, 0x0, 0x4, 0x0},
+	{0xa343, 0x0, 0x4, 0xa},
+	{0xa347, 0x4, 0x4, 0x2},
+	{0xa348, 0x0, 0x4, 0xc},
+	{0xa348, 0x4, 0x4, 0x7},
+	{0xa349, 0x0, 0x6, 0x2},
+};
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
new file mode 100644
index 0000000..7db6eee
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005.c
@@ -0,0 +1,1141 @@
+/* DVB USB compliant Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided 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.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/REDME.dvb-usb for more information
+ */
+#include "af9005.h"
+
+/* debug */
+int dvb_usb_af9005_debug;
+module_param_named(debug, dvb_usb_af9005_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+		 "set debugging level (1=info,xfer=2,rc=4,reg=8,i2c=16,fw=32 (or-able))."
+		 DVB_USB_DEBUG_STATUS);
+/* enable obnoxious led */
+int dvb_usb_af9005_led = 1;
+module_param_named(led, dvb_usb_af9005_led, bool, 0644);
+MODULE_PARM_DESC(led, "enable led (default: 1).");
+
+/* eeprom dump */
+int dvb_usb_af9005_dump_eeprom = 0;
+module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0);
+MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom.");
+
+/* remote control decoder */
+int (*rc_decode) (struct dvb_usb_device * d, u8 * data, int len, u32 * event,
+		  int *state);
+void *rc_keys;
+int *rc_keys_size;
+
+u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff };
+
+struct af9005_device_state {
+	u8 sequence;
+	int led_state;
+};
+
+int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen,
+			  u8 * rbuf, u16 rlen, int delay_ms)
+{
+	int actlen, ret = -ENOMEM;
+
+	if (wbuf == NULL || wlen == 0)
+		return -EINVAL;
+
+	if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+		return ret;
+
+	deb_xfer(">>> ");
+	debug_dump(wbuf, wlen, deb_xfer);
+
+	ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev,
+						    2), wbuf, wlen,
+			   &actlen, 2000);
+
+	if (ret)
+		err("bulk message failed: %d (%d/%d)", ret, wlen, actlen);
+	else
+		ret = actlen != wlen ? -1 : 0;
+
+	/* an answer is expected, and no error before */
+	if (!ret && rbuf && rlen) {
+		if (delay_ms)
+			msleep(delay_ms);
+
+		ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
+							    0x01), rbuf,
+				   rlen, &actlen, 2000);
+
+		if (ret)
+			err("recv bulk message failed: %d", ret);
+		else {
+			deb_xfer("<<< ");
+			debug_dump(rbuf, actlen, deb_xfer);
+		}
+	}
+
+	mutex_unlock(&d->usb_mutex);
+	return ret;
+}
+
+int af9005_usb_generic_write(struct dvb_usb_device *d, u8 * buf, u16 len)
+{
+	return af9005_usb_generic_rw(d, buf, len, NULL, 0, 0);
+}
+
+int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
+			      int readwrite, int type, u8 * values, int len)
+{
+	struct af9005_device_state *st = d->priv;
+	u8 obuf[16] = { 0 };
+	u8 ibuf[17] = { 0 };
+	u8 command;
+	int i;
+	int ret;
+
+	if (len < 1) {
+		err("generic read/write, less than 1 byte. Makes no sense.");
+		return -EINVAL;
+	}
+	if (len > 8) {
+		err("generic read/write, more than 8 bytes. Not supported.");
+		return -EINVAL;
+	}
+
+	obuf[0] = 14;		/* rest of buffer length low */
+	obuf[1] = 0;		/* rest of buffer length high */
+
+	obuf[2] = AF9005_REGISTER_RW;	/* register operation */
+	obuf[3] = 12;		/* rest of buffer length */
+
+	obuf[4] = st->sequence++;	/* sequence number */
+
+	obuf[5] = (u8) (reg >> 8);	/* register address */
+	obuf[6] = (u8) (reg & 0xff);
+
+	if (type == AF9005_OFDM_REG) {
+		command = AF9005_CMD_OFDM_REG;
+	} else {
+		command = AF9005_CMD_TUNER;
+	}
+
+	if (len > 1)
+		command |=
+		    AF9005_CMD_BURST | AF9005_CMD_AUTOINC | (len - 1) << 3;
+	command |= readwrite;
+	if (readwrite == AF9005_CMD_WRITE)
+		for (i = 0; i < len; i++)
+			obuf[8 + i] = values[i];
+	else if (type == AF9005_TUNER_REG)
+		/* read command for tuner, the first byte contains the i2c address */
+		obuf[8] = values[0];
+	obuf[7] = command;
+
+	ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
+	if (ret)
+		return ret;
+
+	/* sanity check */
+	if (ibuf[2] != AF9005_REGISTER_RW_ACK) {
+		err("generic read/write, wrong reply code.");
+		return -EIO;
+	}
+	if (ibuf[3] != 0x0d) {
+		err("generic read/write, wrong length in reply.");
+		return -EIO;
+	}
+	if (ibuf[4] != obuf[4]) {
+		err("generic read/write, wrong sequence in reply.");
+		return -EIO;
+	}
+	/*
+	   Windows driver doesn't check these fields, in fact sometimes
+	   the register in the reply is different that what has been sent
+
+	   if (ibuf[5] != obuf[5] || ibuf[6] != obuf[6]) {
+	   err("generic read/write, wrong register in reply.");
+	   return -EIO;
+	   }
+	   if (ibuf[7] != command) {
+	   err("generic read/write wrong command in reply.");
+	   return -EIO;
+	   }
+	 */
+	if (ibuf[16] != 0x01) {
+		err("generic read/write wrong status code in reply.");
+		return -EIO;
+	}
+	if (readwrite == AF9005_CMD_READ)
+		for (i = 0; i < len; i++)
+			values[i] = ibuf[8 + i];
+
+	return 0;
+
+}
+
+int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 * value)
+{
+	int ret;
+	deb_reg("read register %x ", reg);
+	ret = af9005_generic_read_write(d, reg,
+					AF9005_CMD_READ, AF9005_OFDM_REG,
+					value, 1);
+	if (ret)
+		deb_reg("failed\n");
+	else
+		deb_reg("value %x\n", *value);
+	return ret;
+}
+
+int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+			       u8 * values, int len)
+{
+	int ret;
+	deb_reg("read %d registers %x ", len, reg);
+	ret = af9005_generic_read_write(d, reg,
+					AF9005_CMD_READ, AF9005_OFDM_REG,
+					values, len);
+	if (ret)
+		deb_reg("failed\n");
+	else
+		debug_dump(values, len, deb_reg);
+	return ret;
+}
+
+int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg, u8 value)
+{
+	int ret;
+	u8 temp = value;
+	deb_reg("write register %x value %x ", reg, value);
+	ret = af9005_generic_read_write(d, reg,
+					AF9005_CMD_WRITE, AF9005_OFDM_REG,
+					&temp, 1);
+	if (ret)
+		deb_reg("failed\n");
+	else
+		deb_reg("ok\n");
+	return ret;
+}
+
+int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+				u8 * values, int len)
+{
+	int ret;
+	deb_reg("write %d registers %x values ", len, reg);
+	debug_dump(values, len, deb_reg);
+
+	ret = af9005_generic_read_write(d, reg,
+					AF9005_CMD_WRITE, AF9005_OFDM_REG,
+					values, len);
+	if (ret)
+		deb_reg("failed\n");
+	else
+		deb_reg("ok\n");
+	return ret;
+}
+
+int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
+			      u8 len, u8 * value)
+{
+	u8 temp;
+	int ret;
+	deb_reg("read bits %x %x %x", reg, pos, len);
+	ret = af9005_read_ofdm_register(d, reg, &temp);
+	if (ret) {
+		deb_reg(" failed\n");
+		return ret;
+	}
+	*value = (temp >> pos) & regmask[len - 1];
+	deb_reg(" value %x\n", *value);
+	return 0;
+
+}
+
+int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg, u8 pos,
+			       u8 len, u8 value)
+{
+	u8 temp, mask;
+	int ret;
+	deb_reg("write bits %x %x %x value %x\n", reg, pos, len, value);
+	if (pos == 0 && len == 8)
+		return af9005_write_ofdm_register(d, reg, value);
+	ret = af9005_read_ofdm_register(d, reg, &temp);
+	if (ret)
+		return ret;
+	mask = regmask[len - 1] << pos;
+	temp = (temp & ~mask) | ((value << pos) & mask);
+	return af9005_write_ofdm_register(d, reg, temp);
+
+}
+
+static int af9005_usb_read_tuner_registers(struct dvb_usb_device *d,
+					   u16 reg, u8 * values, int len)
+{
+	return af9005_generic_read_write(d, reg,
+					 AF9005_CMD_READ, AF9005_TUNER_REG,
+					 values, len);
+}
+
+static int af9005_usb_write_tuner_registers(struct dvb_usb_device *d,
+					    u16 reg, u8 * values, int len)
+{
+	return af9005_generic_read_write(d, reg,
+					 AF9005_CMD_WRITE,
+					 AF9005_TUNER_REG, values, len);
+}
+
+int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,
+				 u8 * values, int len)
+{
+	/* don't let the name of this function mislead you: it's just used
+	   as an interface from the firmware to the i2c bus. The actual
+	   i2c addresses are contained in the data */
+	int ret, i, done = 0, fail = 0;
+	u8 temp;
+	ret = af9005_usb_write_tuner_registers(d, reg, values, len);
+	if (ret)
+		return ret;
+	if (reg != 0xffff) {
+		/* check if write done (0xa40d bit 1) or fail (0xa40d bit 2) */
+		for (i = 0; i < 200; i++) {
+			ret =
+			    af9005_read_ofdm_register(d,
+						      xd_I2C_i2c_m_status_wdat_done,
+						      &temp);
+			if (ret)
+				return ret;
+			done = temp & (regmask[i2c_m_status_wdat_done_len - 1]
+				       << i2c_m_status_wdat_done_pos);
+			if (done)
+				break;
+			fail = temp & (regmask[i2c_m_status_wdat_fail_len - 1]
+				       << i2c_m_status_wdat_fail_pos);
+			if (fail)
+				break;
+			msleep(50);
+		}
+		if (i == 200)
+			return -ETIMEDOUT;
+		if (fail) {
+			/* clear write fail bit */
+			af9005_write_register_bits(d,
+						   xd_I2C_i2c_m_status_wdat_fail,
+						   i2c_m_status_wdat_fail_pos,
+						   i2c_m_status_wdat_fail_len,
+						   1);
+			return -EIO;
+		}
+		/* clear write done bit */
+		ret =
+		    af9005_write_register_bits(d,
+					       xd_I2C_i2c_m_status_wdat_fail,
+					       i2c_m_status_wdat_done_pos,
+					       i2c_m_status_wdat_done_len, 1);
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg, u8 addr,
+				u8 * values, int len)
+{
+	/* don't let the name of this function mislead you: it's just used
+	   as an interface from the firmware to the i2c bus. The actual
+	   i2c addresses are contained in the data */
+	int ret, i;
+	u8 temp, buf[2];
+
+	buf[0] = addr;		/* tuner i2c address */
+	buf[1] = values[0];	/* tuner register */
+
+	values[0] = addr + 0x01;	/* i2c read address */
+
+	if (reg == APO_REG_I2C_RW_SILICON_TUNER) {
+		/* write tuner i2c address to tuner, 0c00c0 undocumented, found by sniffing */
+		ret = af9005_write_tuner_registers(d, 0x00c0, buf, 2);
+		if (ret)
+			return ret;
+	}
+
+	/* send read command to ofsm */
+	ret = af9005_usb_read_tuner_registers(d, reg, values, 1);
+	if (ret)
+		return ret;
+
+	/* check if read done */
+	for (i = 0; i < 200; i++) {
+		ret = af9005_read_ofdm_register(d, 0xa408, &temp);
+		if (ret)
+			return ret;
+		if (temp & 0x01)
+			break;
+		msleep(50);
+	}
+	if (i == 200)
+		return -ETIMEDOUT;
+
+	/* clear read done bit (by writing 1) */
+	ret = af9005_write_ofdm_register(d, xd_I2C_i2c_m_data8, 1);
+	if (ret)
+		return ret;
+
+	/* get read data (available from 0xa400) */
+	for (i = 0; i < len; i++) {
+		ret = af9005_read_ofdm_register(d, 0xa400 + i, &temp);
+		if (ret)
+			return ret;
+		values[i] = temp;
+	}
+	return 0;
+}
+
+static int af9005_i2c_write(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
+			    u8 * data, int len)
+{
+	int ret, i;
+	u8 buf[3];
+	deb_i2c("i2c_write i2caddr %x, reg %x, len %d data ", i2caddr,
+		reg, len);
+	debug_dump(data, len, deb_i2c);
+
+	for (i = 0; i < len; i++) {
+		buf[0] = i2caddr;
+		buf[1] = reg + (u8) i;
+		buf[2] = data[i];
+		ret =
+		    af9005_write_tuner_registers(d,
+						 APO_REG_I2C_RW_SILICON_TUNER,
+						 buf, 3);
+		if (ret) {
+			deb_i2c("i2c_write failed\n");
+			return ret;
+		}
+	}
+	deb_i2c("i2c_write ok\n");
+	return 0;
+}
+
+static int af9005_i2c_read(struct dvb_usb_device *d, u8 i2caddr, u8 reg,
+			   u8 * data, int len)
+{
+	int ret, i;
+	u8 temp;
+	deb_i2c("i2c_read i2caddr %x, reg %x, len %d\n ", i2caddr, reg, len);
+	for (i = 0; i < len; i++) {
+		temp = reg + i;
+		ret =
+		    af9005_read_tuner_registers(d,
+						APO_REG_I2C_RW_SILICON_TUNER,
+						i2caddr, &temp, 1);
+		if (ret) {
+			deb_i2c("i2c_read failed\n");
+			return ret;
+		}
+		data[i] = temp;
+	}
+	deb_i2c("i2c data read: ");
+	debug_dump(data, len, deb_i2c);
+	return 0;
+}
+
+static int af9005_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+			   int num)
+{
+	/* only implements what the mt2060 module does, don't know how
+	   to make it really generic */
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+	int ret;
+	u8 reg, addr;
+	u8 *value;
+
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+		return -EAGAIN;
+
+	if (num > 2)
+		warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+	if (num == 2) {
+		/* reads a single register */
+		reg = *msg[0].buf;
+		addr = msg[0].addr;
+		value = msg[1].buf;
+		ret = af9005_i2c_read(d, addr, reg, value, 1);
+		if (ret == 0)
+			ret = 2;
+	} else {
+		/* write one or more registers */
+		reg = msg[0].buf[0];
+		addr = msg[0].addr;
+		value = &msg[0].buf[1];
+		ret = af9005_i2c_write(d, addr, reg, value, msg[0].len - 1);
+		if (ret == 0)
+			ret = 1;
+	}
+
+	mutex_unlock(&d->i2c_mutex);
+	return ret;
+}
+
+static u32 af9005_i2c_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm af9005_i2c_algo = {
+	.master_xfer = af9005_i2c_xfer,
+	.functionality = af9005_i2c_func,
+};
+
+int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,
+			int wlen, u8 * rbuf, int rlen)
+{
+	struct af9005_device_state *st = d->priv;
+
+	int ret, i, packet_len;
+	u8 buf[64];
+	u8 ibuf[64];
+
+	if (wlen < 0) {
+		err("send command, wlen less than 0 bytes. Makes no sense.");
+		return -EINVAL;
+	}
+	if (wlen > 54) {
+		err("send command, wlen more than 54 bytes. Not supported.");
+		return -EINVAL;
+	}
+	if (rlen > 54) {
+		err("send command, rlen more than 54 bytes. Not supported.");
+		return -EINVAL;
+	}
+	packet_len = wlen + 5;
+	buf[0] = (u8) (packet_len & 0xff);
+	buf[1] = (u8) ((packet_len & 0xff00) >> 8);
+
+	buf[2] = 0x26;		/* packet type */
+	buf[3] = wlen + 3;
+	buf[4] = st->sequence++;
+	buf[5] = command;
+	buf[6] = wlen;
+	for (i = 0; i < wlen; i++)
+		buf[7 + i] = wbuf[i];
+	ret = af9005_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);
+	if (ret)
+		return ret;
+	if (ibuf[2] != 0x27) {
+		err("send command, wrong reply code.");
+		return -EIO;
+	}
+	if (ibuf[4] != buf[4]) {
+		err("send command, wrong sequence in reply.");
+		return -EIO;
+	}
+	if (ibuf[5] != 0x01) {
+		err("send command, wrong status code in reply.");
+		return -EIO;
+	}
+	if (ibuf[6] != rlen) {
+		err("send command, invalid data length in reply.");
+		return -EIO;
+	}
+	for (i = 0; i < rlen; i++)
+		rbuf[i] = ibuf[i + 7];
+	return 0;
+}
+
+int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values,
+		       int len)
+{
+	struct af9005_device_state *st = d->priv;
+	u8 obuf[16], ibuf[14];
+	int ret, i;
+
+	memset(obuf, 0, sizeof(obuf));
+	memset(ibuf, 0, sizeof(ibuf));
+
+	obuf[0] = 14;		/* length of rest of packet low */
+	obuf[1] = 0;		/* length of rest of packer high */
+
+	obuf[2] = 0x2a;		/* read/write eeprom */
+
+	obuf[3] = 12;		/* size */
+
+	obuf[4] = st->sequence++;
+
+	obuf[5] = 0;		/* read */
+
+	obuf[6] = len;
+	obuf[7] = address;
+	ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
+	if (ret)
+		return ret;
+	if (ibuf[2] != 0x2b) {
+		err("Read eeprom, invalid reply code");
+		return -EIO;
+	}
+	if (ibuf[3] != 10) {
+		err("Read eeprom, invalid reply length");
+		return -EIO;
+	}
+	if (ibuf[4] != obuf[4]) {
+		err("Read eeprom, wrong sequence in reply ");
+		return -EIO;
+	}
+	if (ibuf[5] != 1) {
+		err("Read eeprom, wrong status in reply ");
+		return -EIO;
+	}
+	for (i = 0; i < len; i++) {
+		values[i] = ibuf[6 + i];
+	}
+	return 0;
+}
+
+static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply)
+{
+	u8 buf[FW_BULKOUT_SIZE + 2];
+	u16 checksum;
+	int act_len, i, ret;
+	memset(buf, 0, sizeof(buf));
+	buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
+	buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
+	switch (type) {
+	case FW_CONFIG:
+		buf[2] = 0x11;
+		buf[3] = 0x04;
+		buf[4] = 0x00;	/* sequence number, original driver doesn't increment it here */
+		buf[5] = 0x03;
+		checksum = buf[4] + buf[5];
+		buf[6] = (u8) ((checksum >> 8) & 0xff);
+		buf[7] = (u8) (checksum & 0xff);
+		break;
+	case FW_CONFIRM:
+		buf[2] = 0x11;
+		buf[3] = 0x04;
+		buf[4] = 0x00;	/* sequence number, original driver doesn't increment it here */
+		buf[5] = 0x01;
+		checksum = buf[4] + buf[5];
+		buf[6] = (u8) ((checksum >> 8) & 0xff);
+		buf[7] = (u8) (checksum & 0xff);
+		break;
+	case FW_BOOT:
+		buf[2] = 0x10;
+		buf[3] = 0x08;
+		buf[4] = 0x00;	/* sequence number, original driver doesn't increment it here */
+		buf[5] = 0x97;
+		buf[6] = 0xaa;
+		buf[7] = 0x55;
+		buf[8] = 0xa5;
+		buf[9] = 0x5a;
+		checksum = 0;
+		for (i = 4; i <= 9; i++)
+			checksum += buf[i];
+		buf[10] = (u8) ((checksum >> 8) & 0xff);
+		buf[11] = (u8) (checksum & 0xff);
+		break;
+	default:
+		err("boot packet invalid boot packet type");
+		return -EINVAL;
+	}
+	deb_fw(">>> ");
+	debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
+
+	ret = usb_bulk_msg(udev,
+			   usb_sndbulkpipe(udev, 0x02),
+			   buf, FW_BULKOUT_SIZE + 2, &act_len, 2000);
+	if (ret)
+		err("boot packet bulk message failed: %d (%d/%d)", ret,
+		    FW_BULKOUT_SIZE + 2, act_len);
+	else
+		ret = act_len != FW_BULKOUT_SIZE + 2 ? -1 : 0;
+	if (ret)
+		return ret;
+	memset(buf, 0, 9);
+	ret = usb_bulk_msg(udev,
+			   usb_rcvbulkpipe(udev, 0x01), buf, 9, &act_len, 2000);
+	if (ret) {
+		err("boot packet recv bulk message failed: %d", ret);
+		return ret;
+	}
+	deb_fw("<<< ");
+	debug_dump(buf, act_len, deb_fw);
+	checksum = 0;
+	switch (type) {
+	case FW_CONFIG:
+		if (buf[2] != 0x11) {
+			err("boot bad config header.");
+			return -EIO;
+		}
+		if (buf[3] != 0x05) {
+			err("boot bad config size.");
+			return -EIO;
+		}
+		if (buf[4] != 0x00) {
+			err("boot bad config sequence.");
+			return -EIO;
+		}
+		if (buf[5] != 0x04) {
+			err("boot bad config subtype.");
+			return -EIO;
+		}
+		for (i = 4; i <= 6; i++)
+			checksum += buf[i];
+		if (buf[7] * 256 + buf[8] != checksum) {
+			err("boot bad config checksum.");
+			return -EIO;
+		}
+		*reply = buf[6];
+		break;
+	case FW_CONFIRM:
+		if (buf[2] != 0x11) {
+			err("boot bad confirm header.");
+			return -EIO;
+		}
+		if (buf[3] != 0x05) {
+			err("boot bad confirm size.");
+			return -EIO;
+		}
+		if (buf[4] != 0x00) {
+			err("boot bad confirm sequence.");
+			return -EIO;
+		}
+		if (buf[5] != 0x02) {
+			err("boot bad confirm subtype.");
+			return -EIO;
+		}
+		for (i = 4; i <= 6; i++)
+			checksum += buf[i];
+		if (buf[7] * 256 + buf[8] != checksum) {
+			err("boot bad confirm checksum.");
+			return -EIO;
+		}
+		*reply = buf[6];
+		break;
+	case FW_BOOT:
+		if (buf[2] != 0x10) {
+			err("boot bad boot header.");
+			return -EIO;
+		}
+		if (buf[3] != 0x05) {
+			err("boot bad boot size.");
+			return -EIO;
+		}
+		if (buf[4] != 0x00) {
+			err("boot bad boot sequence.");
+			return -EIO;
+		}
+		if (buf[5] != 0x01) {
+			err("boot bad boot pattern 01.");
+			return -EIO;
+		}
+		if (buf[6] != 0x10) {
+			err("boot bad boot pattern 10.");
+			return -EIO;
+		}
+		for (i = 4; i <= 6; i++)
+			checksum += buf[i];
+		if (buf[7] * 256 + buf[8] != checksum) {
+			err("boot bad boot checksum.");
+			return -EIO;
+		}
+		break;
+
+	}
+
+	return 0;
+}
+
+int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw)
+{
+	int i, packets, ret, act_len;
+
+	u8 buf[FW_BULKOUT_SIZE + 2];
+	u8 reply;
+
+	ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+	if (ret)
+		return ret;
+	if (reply != 0x01) {
+		err("before downloading firmware, FW_CONFIG expected 0x01, received 0x%x", reply);
+		return -EIO;
+	}
+	packets = fw->size / FW_BULKOUT_SIZE;
+	buf[0] = (u8) (FW_BULKOUT_SIZE & 0xff);
+	buf[1] = (u8) ((FW_BULKOUT_SIZE >> 8) & 0xff);
+	for (i = 0; i < packets; i++) {
+		memcpy(&buf[2], fw->data + i * FW_BULKOUT_SIZE,
+		       FW_BULKOUT_SIZE);
+		deb_fw(">>> ");
+		debug_dump(buf, FW_BULKOUT_SIZE + 2, deb_fw);
+		ret = usb_bulk_msg(udev,
+				   usb_sndbulkpipe(udev, 0x02),
+				   buf, FW_BULKOUT_SIZE + 2, &act_len, 1000);
+		if (ret) {
+			err("firmware download failed at packet %d with code %d", i, ret);
+			return ret;
+		}
+	}
+	ret = af9005_boot_packet(udev, FW_CONFIRM, &reply);
+	if (ret)
+		return ret;
+	if (reply != (u8) (packets & 0xff)) {
+		err("after downloading firmware, FW_CONFIRM expected 0x%x, received 0x%x", packets & 0xff, reply);
+		return -EIO;
+	}
+	ret = af9005_boot_packet(udev, FW_BOOT, &reply);
+	if (ret)
+		return ret;
+	ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+	if (ret)
+		return ret;
+	if (reply != 0x02) {
+		err("after downloading firmware, FW_CONFIG expected 0x02, received 0x%x", reply);
+		return -EIO;
+	}
+
+	return 0;
+
+}
+
+int af9005_led_control(struct dvb_usb_device *d, int onoff)
+{
+	struct af9005_device_state *st = d->priv;
+	int temp, ret;
+
+	if (onoff && dvb_usb_af9005_led)
+		temp = 1;
+	else
+		temp = 0;
+	if (st->led_state != temp) {
+		ret =
+		    af9005_write_register_bits(d, xd_p_reg_top_locken1,
+					       reg_top_locken1_pos,
+					       reg_top_locken1_len, temp);
+		if (ret)
+			return ret;
+		ret =
+		    af9005_write_register_bits(d, xd_p_reg_top_lock1,
+					       reg_top_lock1_pos,
+					       reg_top_lock1_len, temp);
+		if (ret)
+			return ret;
+		st->led_state = temp;
+	}
+	return 0;
+}
+
+static int af9005_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	u8 buf[8];
+	int i;
+
+	/* without these calls the first commands after downloading
+	   the firmware fail. I put these calls here to simulate
+	   what it is done in dvb-usb-init.c.
+	 */
+	struct usb_device *udev = adap->dev->udev;
+	usb_clear_halt(udev, usb_sndbulkpipe(udev, 2));
+	usb_clear_halt(udev, usb_rcvbulkpipe(udev, 1));
+	if (dvb_usb_af9005_dump_eeprom) {
+		printk("EEPROM DUMP\n");
+		for (i = 0; i < 255; i += 8) {
+			af9005_read_eeprom(adap->dev, i, buf, 8);
+			printk("ADDR %x ", i);
+			debug_dump(buf, 8, printk);
+		}
+	}
+	adap->fe = af9005_fe_attach(adap->dev);
+	return 0;
+}
+
+static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state)
+{
+	struct af9005_device_state *st = d->priv;
+	int ret, len;
+
+	u8 obuf[5];
+	u8 ibuf[256];
+
+	*state = REMOTE_NO_KEY_PRESSED;
+	if (rc_decode == NULL) {
+		/* it shouldn't never come here */
+		return 0;
+	}
+	/* deb_info("rc_query\n"); */
+	obuf[0] = 3;		/* rest of packet length low */
+	obuf[1] = 0;		/* rest of packet lentgh high */
+	obuf[2] = 0x40;		/* read remote */
+	obuf[3] = 1;		/* rest of packet length */
+	obuf[4] = st->sequence++;	/* sequence number */
+	ret = af9005_usb_generic_rw(d, obuf, 5, ibuf, 256, 0);
+	if (ret) {
+		err("rc query failed");
+		return ret;
+	}
+	if (ibuf[2] != 0x41) {
+		err("rc query bad header.");
+		return -EIO;
+	}
+	if (ibuf[4] != obuf[4]) {
+		err("rc query bad sequence.");
+		return -EIO;
+	}
+	len = ibuf[5];
+	if (len > 246) {
+		err("rc query invalid length");
+		return -EIO;
+	}
+	if (len > 0) {
+		deb_rc("rc data (%d) ", len);
+		debug_dump((ibuf + 6), len, deb_rc);
+		ret = rc_decode(d, &ibuf[6], len, event, state);
+		if (ret) {
+			err("rc_decode failed");
+			return ret;
+		} else {
+			deb_rc("rc_decode state %x event %x\n", *state, *event);
+			if (*state == REMOTE_KEY_REPEAT)
+				*event = d->last_event;
+		}
+	}
+	return 0;
+}
+
+static int af9005_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+
+	return 0;
+}
+
+static int af9005_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
+{
+	int ret;
+	deb_info("pid filter control  onoff %d\n", onoff);
+	if (onoff) {
+		ret =
+		    af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
+		if (ret)
+			return ret;
+		ret =
+		    af9005_write_register_bits(adap->dev,
+					       XD_MP2IF_DMX_CTRL, 1, 1, 1);
+		if (ret)
+			return ret;
+		ret =
+		    af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 1);
+	} else
+		ret =
+		    af9005_write_ofdm_register(adap->dev, XD_MP2IF_DMX_CTRL, 0);
+	if (ret)
+		return ret;
+	deb_info("pid filter control ok\n");
+	return 0;
+}
+
+static int af9005_pid_filter(struct dvb_usb_adapter *adap, int index,
+			     u16 pid, int onoff)
+{
+	u8 cmd = index & 0x1f;
+	int ret;
+	deb_info("set pid filter, index %d, pid %x, onoff %d\n", index,
+		 pid, onoff);
+	if (onoff) {
+		/* cannot use it as pid_filter_ctrl since it has to be done
+		   before setting the first pid */
+		if (adap->feedcount == 1) {
+			deb_info("first pid set, enable pid table\n");
+			ret = af9005_pid_filter_control(adap, onoff);
+			if (ret)
+				return ret;
+		}
+		ret =
+		    af9005_write_ofdm_register(adap->dev,
+					       XD_MP2IF_PID_DATA_L,
+					       (u8) (pid & 0xff));
+		if (ret)
+			return ret;
+		ret =
+		    af9005_write_ofdm_register(adap->dev,
+					       XD_MP2IF_PID_DATA_H,
+					       (u8) (pid >> 8));
+		if (ret)
+			return ret;
+		cmd |= 0x20 | 0x40;
+	} else {
+		if (adap->feedcount == 0) {
+			deb_info("last pid unset, disable pid table\n");
+			ret = af9005_pid_filter_control(adap, onoff);
+			if (ret)
+				return ret;
+		}
+	}
+	ret = af9005_write_ofdm_register(adap->dev, XD_MP2IF_PID_IDX, cmd);
+	if (ret)
+		return ret;
+	deb_info("set pid ok\n");
+	return 0;
+}
+
+static int af9005_identify_state(struct usb_device *udev,
+				 struct dvb_usb_device_properties *props,
+				 struct dvb_usb_device_description **desc,
+				 int *cold)
+{
+	int ret;
+	u8 reply;
+	ret = af9005_boot_packet(udev, FW_CONFIG, &reply);
+	if (ret)
+		return ret;
+	deb_info("result of FW_CONFIG in identify state %d\n", reply);
+	if (reply == 0x01)
+		*cold = 1;
+	else if (reply == 0x02)
+		*cold = 0;
+	else
+		return -EIO;
+	deb_info("Identify state cold = %d\n", *cold);
+	return 0;
+}
+
+static struct dvb_usb_device_properties af9005_properties;
+
+static int af9005_usb_probe(struct usb_interface *intf,
+			    const struct usb_device_id *id)
+{
+	return dvb_usb_device_init(intf, &af9005_properties, THIS_MODULE, NULL);
+}
+
+static struct usb_device_id af9005_usb_table[] = {
+	{USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9005)},
+	{USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE)},
+	{0},
+};
+
+MODULE_DEVICE_TABLE(usb, af9005_usb_table);
+
+static struct dvb_usb_device_properties af9005_properties = {
+	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+	.usb_ctrl = DEVICE_SPECIFIC,
+	.firmware = "af9005.fw",
+	.download_firmware = af9005_download_firmware,
+	.no_reconnect = 1,
+
+	.size_of_priv = sizeof(struct af9005_device_state),
+
+	.num_adapters = 1,
+	.adapter = {
+		    {
+		     .caps =
+		     DVB_USB_ADAP_HAS_PID_FILTER |
+		     DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+		     .pid_filter_count = 32,
+		     .pid_filter = af9005_pid_filter,
+		     /* .pid_filter_ctrl = af9005_pid_filter_control, */
+		     .frontend_attach = af9005_frontend_attach,
+		     /* .tuner_attach     = af9005_tuner_attach, */
+		     /* parameter for the MPEG2-data transfer */
+		     .stream = {
+				.type = USB_BULK,
+				.count = 10,
+				.endpoint = 0x04,
+				.u = {
+				      .bulk = {
+					       .buffersize = 4096,	/* actual size seen is 3948 */
+					       }
+				      }
+				},
+		     }
+		    },
+	.power_ctrl = af9005_power_ctrl,
+	.identify_state = af9005_identify_state,
+
+	.i2c_algo = &af9005_i2c_algo,
+
+	.rc_interval = 200,
+	.rc_key_map = NULL,
+	.rc_key_map_size = 0,
+	.rc_query = af9005_rc_query,
+
+	.num_device_descs = 2,
+	.devices = {
+		    {.name = "Afatech DVB-T USB1.1 stick",
+		     .cold_ids = {&af9005_usb_table[0], NULL},
+		     .warm_ids = {NULL},
+		     },
+		    {.name = "TerraTec Cinergy T USB XE",
+		     .cold_ids = {&af9005_usb_table[1], NULL},
+		     .warm_ids = {NULL},
+		     },
+		    {NULL},
+		    }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver af9005_usb_driver = {
+	.name = "dvb_usb_af9005",
+	.probe = af9005_usb_probe,
+	.disconnect = dvb_usb_device_exit,
+	.id_table = af9005_usb_table,
+};
+
+/* module stuff */
+static int __init af9005_usb_module_init(void)
+{
+	int result;
+	if ((result = usb_register(&af9005_usb_driver))) {
+		err("usb_register failed. (%d)", result);
+		return result;
+	}
+	rc_decode = symbol_request(af9005_rc_decode);
+	rc_keys = symbol_request(af9005_rc_keys);
+	rc_keys_size = symbol_request(af9005_rc_keys_size);
+	if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) {
+		err("af9005_rc_decode function not found, disabling remote");
+		af9005_properties.rc_query = NULL;
+	} else {
+		af9005_properties.rc_key_map = rc_keys;
+		af9005_properties.rc_key_map_size = *rc_keys_size;
+	}
+
+	return 0;
+}
+
+static void __exit af9005_usb_module_exit(void)
+{
+	/* release rc decode symbols */
+	if (rc_decode != NULL)
+		symbol_put(af9005_rc_decode);
+	if (rc_keys != NULL)
+		symbol_put(af9005_rc_keys);
+	if (rc_keys_size != NULL)
+		symbol_put(af9005_rc_keys_size);
+	/* deregister this driver from the USB subsystem */
+	usb_deregister(&af9005_usb_driver);
+}
+
+module_init(af9005_usb_module_init);
+module_exit(af9005_usb_module_exit);
+
+MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
+MODULE_DESCRIPTION("Driver for Afatech 9005 DVB-T USB1.1 stick");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/dvb/dvb-usb/af9005.h
new file mode 100644
index 0000000..0bc48a0
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/af9005.h
@@ -0,0 +1,3496 @@
+/* Common header-file of the Linux driver for the Afatech 9005
+ * USB1.1 DVB-T receiver.
+ *
+ * Copyright (C) 2007 Luca Olivetti (luca@ventoso.org)
+ *
+ * Thanks to Afatech who kindly provided 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.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_AF9005_H_
+#define _DVB_USB_AF9005_H_
+
+#define DVB_USB_LOG_PREFIX "af9005"
+#include "dvb-usb.h"
+
+extern int dvb_usb_af9005_debug;
+#define deb_info(args...) dprintk(dvb_usb_af9005_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_af9005_debug,0x02,args)
+#define deb_rc(args...)   dprintk(dvb_usb_af9005_debug,0x04,args)
+#define deb_reg(args...)  dprintk(dvb_usb_af9005_debug,0x08,args)
+#define deb_i2c(args...)  dprintk(dvb_usb_af9005_debug,0x10,args)
+#define deb_fw(args...)   dprintk(dvb_usb_af9005_debug,0x20,args)
+
+extern int dvb_usb_af9005_led;
+
+/* firmware */
+#define FW_BULKOUT_SIZE 250
+enum {
+	FW_CONFIG,
+	FW_CONFIRM,
+	FW_BOOT
+};
+
+/* af9005 commands */
+#define AF9005_OFDM_REG  0
+#define AF9005_TUNER_REG 1
+
+#define AF9005_REGISTER_RW     0x20
+#define AF9005_REGISTER_RW_ACK 0x21
+
+#define AF9005_CMD_OFDM_REG 0x00
+#define AF9005_CMD_TUNER    0x80
+#define AF9005_CMD_BURST    0x02
+#define AF9005_CMD_AUTOINC  0x04
+#define AF9005_CMD_READ     0x00
+#define AF9005_CMD_WRITE    0x01
+
+/* af9005 registers */
+#define APO_REG_RESET					0xAEFF
+
+#define APO_REG_I2C_RW_CAN_TUNER            0xF000
+#define APO_REG_I2C_RW_SILICON_TUNER        0xF001
+#define APO_REG_GPIO_RW_SILICON_TUNER       0xFFFE	/*  also for OFSM */
+#define APO_REG_TRIGGER_OFSM                0xFFFF	/*  also for OFSM */
+
+/***********************************************************************
+ *  Apollo Registers from VLSI					       *
+ ***********************************************************************/
+#define xd_p_reg_aagc_inverted_agc	0xA000
+#define	reg_aagc_inverted_agc_pos 0
+#define	reg_aagc_inverted_agc_len 1
+#define	reg_aagc_inverted_agc_lsb 0
+#define xd_p_reg_aagc_sign_only	0xA000
+#define	reg_aagc_sign_only_pos 1
+#define	reg_aagc_sign_only_len 1
+#define	reg_aagc_sign_only_lsb 0
+#define xd_p_reg_aagc_slow_adc_en	0xA000
+#define	reg_aagc_slow_adc_en_pos 2
+#define	reg_aagc_slow_adc_en_len 1
+#define	reg_aagc_slow_adc_en_lsb 0
+#define xd_p_reg_aagc_slow_adc_scale	0xA000
+#define	reg_aagc_slow_adc_scale_pos 3
+#define	reg_aagc_slow_adc_scale_len 5
+#define	reg_aagc_slow_adc_scale_lsb 0
+#define xd_p_reg_aagc_check_slow_adc_lock	0xA001
+#define	reg_aagc_check_slow_adc_lock_pos 0
+#define	reg_aagc_check_slow_adc_lock_len 1
+#define	reg_aagc_check_slow_adc_lock_lsb 0
+#define xd_p_reg_aagc_init_control	0xA001
+#define	reg_aagc_init_control_pos 1
+#define	reg_aagc_init_control_len 1
+#define	reg_aagc_init_control_lsb 0
+#define xd_p_reg_aagc_total_gain_sel	0xA001
+#define	reg_aagc_total_gain_sel_pos 2
+#define	reg_aagc_total_gain_sel_len 2
+#define	reg_aagc_total_gain_sel_lsb 0
+#define xd_p_reg_aagc_out_inv	0xA001
+#define	reg_aagc_out_inv_pos 5
+#define	reg_aagc_out_inv_len 1
+#define	reg_aagc_out_inv_lsb 0
+#define xd_p_reg_aagc_int_en	0xA001
+#define	reg_aagc_int_en_pos 6
+#define	reg_aagc_int_en_len 1
+#define	reg_aagc_int_en_lsb 0
+#define xd_p_reg_aagc_lock_change_flag	0xA001
+#define	reg_aagc_lock_change_flag_pos 7
+#define	reg_aagc_lock_change_flag_len 1
+#define	reg_aagc_lock_change_flag_lsb 0
+#define xd_p_reg_aagc_rf_loop_bw_scale_acquire	0xA002
+#define	reg_aagc_rf_loop_bw_scale_acquire_pos 0
+#define	reg_aagc_rf_loop_bw_scale_acquire_len 5
+#define	reg_aagc_rf_loop_bw_scale_acquire_lsb 0
+#define xd_p_reg_aagc_rf_loop_bw_scale_track	0xA003
+#define	reg_aagc_rf_loop_bw_scale_track_pos 0
+#define	reg_aagc_rf_loop_bw_scale_track_len 5
+#define	reg_aagc_rf_loop_bw_scale_track_lsb 0
+#define xd_p_reg_aagc_if_loop_bw_scale_acquire	0xA004
+#define	reg_aagc_if_loop_bw_scale_acquire_pos 0
+#define	reg_aagc_if_loop_bw_scale_acquire_len 5
+#define	reg_aagc_if_loop_bw_scale_acquire_lsb 0
+#define xd_p_reg_aagc_if_loop_bw_scale_track	0xA005
+#define	reg_aagc_if_loop_bw_scale_track_pos 0
+#define	reg_aagc_if_loop_bw_scale_track_len 5
+#define	reg_aagc_if_loop_bw_scale_track_lsb 0
+#define xd_p_reg_aagc_max_rf_agc_7_0	0xA006
+#define	reg_aagc_max_rf_agc_7_0_pos 0
+#define	reg_aagc_max_rf_agc_7_0_len 8
+#define	reg_aagc_max_rf_agc_7_0_lsb 0
+#define xd_p_reg_aagc_max_rf_agc_9_8	0xA007
+#define	reg_aagc_max_rf_agc_9_8_pos 0
+#define	reg_aagc_max_rf_agc_9_8_len 2
+#define	reg_aagc_max_rf_agc_9_8_lsb 8
+#define xd_p_reg_aagc_min_rf_agc_7_0	0xA008
+#define	reg_aagc_min_rf_agc_7_0_pos 0
+#define	reg_aagc_min_rf_agc_7_0_len 8
+#define	reg_aagc_min_rf_agc_7_0_lsb 0
+#define xd_p_reg_aagc_min_rf_agc_9_8	0xA009
+#define	reg_aagc_min_rf_agc_9_8_pos 0
+#define	reg_aagc_min_rf_agc_9_8_len 2
+#define	reg_aagc_min_rf_agc_9_8_lsb 8
+#define xd_p_reg_aagc_max_if_agc_7_0	0xA00A
+#define	reg_aagc_max_if_agc_7_0_pos 0
+#define	reg_aagc_max_if_agc_7_0_len 8
+#define	reg_aagc_max_if_agc_7_0_lsb 0
+#define xd_p_reg_aagc_max_if_agc_9_8	0xA00B
+#define	reg_aagc_max_if_agc_9_8_pos 0
+#define	reg_aagc_max_if_agc_9_8_len 2
+#define	reg_aagc_max_if_agc_9_8_lsb 8
+#define xd_p_reg_aagc_min_if_agc_7_0	0xA00C
+#define	reg_aagc_min_if_agc_7_0_pos 0
+#define	reg_aagc_min_if_agc_7_0_len 8
+#define	reg_aagc_min_if_agc_7_0_lsb 0
+#define xd_p_reg_aagc_min_if_agc_9_8	0xA00D
+#define	reg_aagc_min_if_agc_9_8_pos 0
+#define	reg_aagc_min_if_agc_9_8_len 2
+#define	reg_aagc_min_if_agc_9_8_lsb 8
+#define xd_p_reg_aagc_lock_sample_scale	0xA00E
+#define	reg_aagc_lock_sample_scale_pos 0
+#define	reg_aagc_lock_sample_scale_len 5
+#define	reg_aagc_lock_sample_scale_lsb 0
+#define xd_p_reg_aagc_rf_agc_lock_scale_acquire	0xA00F
+#define	reg_aagc_rf_agc_lock_scale_acquire_pos 0
+#define	reg_aagc_rf_agc_lock_scale_acquire_len 3
+#define	reg_aagc_rf_agc_lock_scale_acquire_lsb 0
+#define xd_p_reg_aagc_rf_agc_lock_scale_track	0xA00F
+#define	reg_aagc_rf_agc_lock_scale_track_pos 3
+#define	reg_aagc_rf_agc_lock_scale_track_len 3
+#define	reg_aagc_rf_agc_lock_scale_track_lsb 0
+#define xd_p_reg_aagc_if_agc_lock_scale_acquire	0xA010
+#define	reg_aagc_if_agc_lock_scale_acquire_pos 0
+#define	reg_aagc_if_agc_lock_scale_acquire_len 3
+#define	reg_aagc_if_agc_lock_scale_acquire_lsb 0
+#define xd_p_reg_aagc_if_agc_lock_scale_track	0xA010
+#define	reg_aagc_if_agc_lock_scale_track_pos 3
+#define	reg_aagc_if_agc_lock_scale_track_len 3
+#define	reg_aagc_if_agc_lock_scale_track_lsb 0
+#define xd_p_reg_aagc_rf_top_numerator_7_0	0xA011
+#define	reg_aagc_rf_top_numerator_7_0_pos 0
+#define	reg_aagc_rf_top_numerator_7_0_len 8
+#define	reg_aagc_rf_top_numerator_7_0_lsb 0
+#define xd_p_reg_aagc_rf_top_numerator_9_8	0xA012
+#define	reg_aagc_rf_top_numerator_9_8_pos 0
+#define	reg_aagc_rf_top_numerator_9_8_len 2
+#define	reg_aagc_rf_top_numerator_9_8_lsb 8
+#define xd_p_reg_aagc_if_top_numerator_7_0	0xA013
+#define	reg_aagc_if_top_numerator_7_0_pos 0
+#define	reg_aagc_if_top_numerator_7_0_len 8
+#define	reg_aagc_if_top_numerator_7_0_lsb 0
+#define xd_p_reg_aagc_if_top_numerator_9_8	0xA014
+#define	reg_aagc_if_top_numerator_9_8_pos 0
+#define	reg_aagc_if_top_numerator_9_8_len 2
+#define	reg_aagc_if_top_numerator_9_8_lsb 8
+#define xd_p_reg_aagc_adc_out_desired_7_0	0xA015
+#define	reg_aagc_adc_out_desired_7_0_pos 0
+#define	reg_aagc_adc_out_desired_7_0_len 8
+#define	reg_aagc_adc_out_desired_7_0_lsb 0
+#define xd_p_reg_aagc_adc_out_desired_8	0xA016
+#define	reg_aagc_adc_out_desired_8_pos 0
+#define	reg_aagc_adc_out_desired_8_len 1
+#define	reg_aagc_adc_out_desired_8_lsb 0
+#define xd_p_reg_aagc_fixed_gain	0xA016
+#define	reg_aagc_fixed_gain_pos 3
+#define	reg_aagc_fixed_gain_len 1
+#define	reg_aagc_fixed_gain_lsb 0
+#define xd_p_reg_aagc_lock_count_th	0xA016
+#define	reg_aagc_lock_count_th_pos 4
+#define	reg_aagc_lock_count_th_len 4
+#define	reg_aagc_lock_count_th_lsb 0
+#define xd_p_reg_aagc_fixed_rf_agc_control_7_0	0xA017
+#define	reg_aagc_fixed_rf_agc_control_7_0_pos 0
+#define	reg_aagc_fixed_rf_agc_control_7_0_len 8
+#define	reg_aagc_fixed_rf_agc_control_7_0_lsb 0
+#define xd_p_reg_aagc_fixed_rf_agc_control_15_8	0xA018
+#define	reg_aagc_fixed_rf_agc_control_15_8_pos 0
+#define	reg_aagc_fixed_rf_agc_control_15_8_len 8
+#define	reg_aagc_fixed_rf_agc_control_15_8_lsb 8
+#define xd_p_reg_aagc_fixed_rf_agc_control_23_16	0xA019
+#define	reg_aagc_fixed_rf_agc_control_23_16_pos 0
+#define	reg_aagc_fixed_rf_agc_control_23_16_len 8
+#define	reg_aagc_fixed_rf_agc_control_23_16_lsb 16
+#define xd_p_reg_aagc_fixed_rf_agc_control_30_24	0xA01A
+#define	reg_aagc_fixed_rf_agc_control_30_24_pos 0
+#define	reg_aagc_fixed_rf_agc_control_30_24_len 7
+#define	reg_aagc_fixed_rf_agc_control_30_24_lsb 24
+#define xd_p_reg_aagc_fixed_if_agc_control_7_0	0xA01B
+#define	reg_aagc_fixed_if_agc_control_7_0_pos 0
+#define	reg_aagc_fixed_if_agc_control_7_0_len 8
+#define	reg_aagc_fixed_if_agc_control_7_0_lsb 0
+#define xd_p_reg_aagc_fixed_if_agc_control_15_8	0xA01C
+#define	reg_aagc_fixed_if_agc_control_15_8_pos 0
+#define	reg_aagc_fixed_if_agc_control_15_8_len 8
+#define	reg_aagc_fixed_if_agc_control_15_8_lsb 8
+#define xd_p_reg_aagc_fixed_if_agc_control_23_16	0xA01D
+#define	reg_aagc_fixed_if_agc_control_23_16_pos 0
+#define	reg_aagc_fixed_if_agc_control_23_16_len 8
+#define	reg_aagc_fixed_if_agc_control_23_16_lsb 16
+#define xd_p_reg_aagc_fixed_if_agc_control_30_24	0xA01E
+#define	reg_aagc_fixed_if_agc_control_30_24_pos 0
+#define	reg_aagc_fixed_if_agc_control_30_24_len 7
+#define	reg_aagc_fixed_if_agc_control_30_24_lsb 24
+#define xd_p_reg_aagc_rf_agc_unlock_numerator	0xA01F
+#define	reg_aagc_rf_agc_unlock_numerator_pos 0
+#define	reg_aagc_rf_agc_unlock_numerator_len 6
+#define	reg_aagc_rf_agc_unlock_numerator_lsb 0
+#define xd_p_reg_aagc_if_agc_unlock_numerator	0xA020
+#define	reg_aagc_if_agc_unlock_numerator_pos 0
+#define	reg_aagc_if_agc_unlock_numerator_len 6
+#define	reg_aagc_if_agc_unlock_numerator_lsb 0
+#define xd_p_reg_unplug_th	0xA021
+#define	reg_unplug_th_pos 0
+#define	reg_unplug_th_len 8
+#define	reg_aagc_rf_x0_lsb 0
+#define xd_p_reg_weak_signal_rfagc_thr 0xA022
+#define	reg_weak_signal_rfagc_thr_pos 0
+#define	reg_weak_signal_rfagc_thr_len 8
+#define	reg_weak_signal_rfagc_thr_lsb 0
+#define xd_p_reg_unplug_rf_gain_th 0xA023
+#define	reg_unplug_rf_gain_th_pos 0
+#define	reg_unplug_rf_gain_th_len 8
+#define	reg_unplug_rf_gain_th_lsb 0
+#define xd_p_reg_unplug_dtop_rf_gain_th 0xA024
+#define	reg_unplug_dtop_rf_gain_th_pos 0
+#define	reg_unplug_dtop_rf_gain_th_len 8
+#define	reg_unplug_dtop_rf_gain_th_lsb 0
+#define xd_p_reg_unplug_dtop_if_gain_th 0xA025
+#define	reg_unplug_dtop_if_gain_th_pos 0
+#define	reg_unplug_dtop_if_gain_th_len 8
+#define	reg_unplug_dtop_if_gain_th_lsb 0
+#define xd_p_reg_top_recover_at_unplug_en 0xA026
+#define	reg_top_recover_at_unplug_en_pos 0
+#define	reg_top_recover_at_unplug_en_len 1
+#define	reg_top_recover_at_unplug_en_lsb 0
+#define xd_p_reg_aagc_rf_x6	0xA027
+#define	reg_aagc_rf_x6_pos 0
+#define	reg_aagc_rf_x6_len 8
+#define	reg_aagc_rf_x6_lsb 0
+#define xd_p_reg_aagc_rf_x7	0xA028
+#define	reg_aagc_rf_x7_pos 0
+#define	reg_aagc_rf_x7_len 8
+#define	reg_aagc_rf_x7_lsb 0
+#define xd_p_reg_aagc_rf_x8	0xA029
+#define	reg_aagc_rf_x8_pos 0
+#define	reg_aagc_rf_x8_len 8
+#define	reg_aagc_rf_x8_lsb 0
+#define xd_p_reg_aagc_rf_x9	0xA02A
+#define	reg_aagc_rf_x9_pos 0
+#define	reg_aagc_rf_x9_len 8
+#define	reg_aagc_rf_x9_lsb 0
+#define xd_p_reg_aagc_rf_x10	0xA02B
+#define	reg_aagc_rf_x10_pos 0
+#define	reg_aagc_rf_x10_len 8
+#define	reg_aagc_rf_x10_lsb 0
+#define xd_p_reg_aagc_rf_x11	0xA02C
+#define	reg_aagc_rf_x11_pos 0
+#define	reg_aagc_rf_x11_len 8
+#define	reg_aagc_rf_x11_lsb 0
+#define xd_p_reg_aagc_rf_x12	0xA02D
+#define	reg_aagc_rf_x12_pos 0
+#define	reg_aagc_rf_x12_len 8
+#define	reg_aagc_rf_x12_lsb 0
+#define xd_p_reg_aagc_rf_x13	0xA02E
+#define	reg_aagc_rf_x13_pos 0
+#define	reg_aagc_rf_x13_len 8
+#define	reg_aagc_rf_x13_lsb 0
+#define xd_p_reg_aagc_if_x0	0xA02F
+#define	reg_aagc_if_x0_pos 0
+#define	reg_aagc_if_x0_len 8
+#define	reg_aagc_if_x0_lsb 0
+#define xd_p_reg_aagc_if_x1	0xA030
+#define	reg_aagc_if_x1_pos 0
+#define	reg_aagc_if_x1_len 8
+#define	reg_aagc_if_x1_lsb 0
+#define xd_p_reg_aagc_if_x2	0xA031
+#define	reg_aagc_if_x2_pos 0
+#define	reg_aagc_if_x2_len 8
+#define	reg_aagc_if_x2_lsb 0
+#define xd_p_reg_aagc_if_x3	0xA032
+#define	reg_aagc_if_x3_pos 0
+#define	reg_aagc_if_x3_len 8
+#define	reg_aagc_if_x3_lsb 0
+#define xd_p_reg_aagc_if_x4	0xA033
+#define	reg_aagc_if_x4_pos 0
+#define	reg_aagc_if_x4_len 8
+#define	reg_aagc_if_x4_lsb 0
+#define xd_p_reg_aagc_if_x5	0xA034
+#define	reg_aagc_if_x5_pos 0
+#define	reg_aagc_if_x5_len 8
+#define	reg_aagc_if_x5_lsb 0
+#define xd_p_reg_aagc_if_x6	0xA035
+#define	reg_aagc_if_x6_pos 0
+#define	reg_aagc_if_x6_len 8
+#define	reg_aagc_if_x6_lsb 0
+#define xd_p_reg_aagc_if_x7	0xA036
+#define	reg_aagc_if_x7_pos 0
+#define	reg_aagc_if_x7_len 8
+#define	reg_aagc_if_x7_lsb 0
+#define xd_p_reg_aagc_if_x8	0xA037
+#define	reg_aagc_if_x8_pos 0
+#define	reg_aagc_if_x8_len 8
+#define	reg_aagc_if_x8_lsb 0
+#define xd_p_reg_aagc_if_x9	0xA038
+#define	reg_aagc_if_x9_pos 0
+#define	reg_aagc_if_x9_len 8
+#define	reg_aagc_if_x9_lsb 0
+#define xd_p_reg_aagc_if_x10	0xA039
+#define	reg_aagc_if_x10_pos 0
+#define	reg_aagc_if_x10_len 8
+#define	reg_aagc_if_x10_lsb 0
+#define xd_p_reg_aagc_if_x11	0xA03A
+#define	reg_aagc_if_x11_pos 0
+#define	reg_aagc_if_x11_len 8
+#define	reg_aagc_if_x11_lsb 0
+#define xd_p_reg_aagc_if_x12	0xA03B
+#define	reg_aagc_if_x12_pos 0
+#define	reg_aagc_if_x12_len 8
+#define	reg_aagc_if_x12_lsb 0
+#define xd_p_reg_aagc_if_x13	0xA03C
+#define	reg_aagc_if_x13_pos 0
+#define	reg_aagc_if_x13_len 8
+#define	reg_aagc_if_x13_lsb 0
+#define xd_p_reg_aagc_min_rf_ctl_8bit_for_dca	0xA03D
+#define	reg_aagc_min_rf_ctl_8bit_for_dca_pos 0
+#define	reg_aagc_min_rf_ctl_8bit_for_dca_len 8
+#define	reg_aagc_min_rf_ctl_8bit_for_dca_lsb 0
+#define xd_p_reg_aagc_min_if_ctl_8bit_for_dca	0xA03E
+#define	reg_aagc_min_if_ctl_8bit_for_dca_pos 0
+#define	reg_aagc_min_if_ctl_8bit_for_dca_len 8
+#define	reg_aagc_min_if_ctl_8bit_for_dca_lsb 0
+#define xd_r_reg_aagc_total_gain_7_0	0xA070
+#define	reg_aagc_total_gain_7_0_pos 0
+#define	reg_aagc_total_gain_7_0_len 8
+#define	reg_aagc_total_gain_7_0_lsb 0
+#define xd_r_reg_aagc_total_gain_15_8	0xA071
+#define	reg_aagc_total_gain_15_8_pos 0
+#define	reg_aagc_total_gain_15_8_len 8
+#define	reg_aagc_total_gain_15_8_lsb 8
+#define xd_p_reg_aagc_in_sat_cnt_7_0	0xA074
+#define	reg_aagc_in_sat_cnt_7_0_pos 0
+#define	reg_aagc_in_sat_cnt_7_0_len 8
+#define	reg_aagc_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_aagc_in_sat_cnt_15_8	0xA075
+#define	reg_aagc_in_sat_cnt_15_8_pos 0
+#define	reg_aagc_in_sat_cnt_15_8_len 8
+#define	reg_aagc_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_aagc_in_sat_cnt_23_16	0xA076
+#define	reg_aagc_in_sat_cnt_23_16_pos 0
+#define	reg_aagc_in_sat_cnt_23_16_len 8
+#define	reg_aagc_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_aagc_in_sat_cnt_31_24	0xA077
+#define	reg_aagc_in_sat_cnt_31_24_pos 0
+#define	reg_aagc_in_sat_cnt_31_24_len 8
+#define	reg_aagc_in_sat_cnt_31_24_lsb 24
+#define xd_r_reg_aagc_digital_rf_volt_7_0	0xA078
+#define	reg_aagc_digital_rf_volt_7_0_pos 0
+#define	reg_aagc_digital_rf_volt_7_0_len 8
+#define	reg_aagc_digital_rf_volt_7_0_lsb 0
+#define xd_r_reg_aagc_digital_rf_volt_9_8	0xA079
+#define	reg_aagc_digital_rf_volt_9_8_pos 0
+#define	reg_aagc_digital_rf_volt_9_8_len 2
+#define	reg_aagc_digital_rf_volt_9_8_lsb 8
+#define xd_r_reg_aagc_digital_if_volt_7_0	0xA07A
+#define	reg_aagc_digital_if_volt_7_0_pos 0
+#define	reg_aagc_digital_if_volt_7_0_len 8
+#define	reg_aagc_digital_if_volt_7_0_lsb 0
+#define xd_r_reg_aagc_digital_if_volt_9_8	0xA07B
+#define	reg_aagc_digital_if_volt_9_8_pos 0
+#define	reg_aagc_digital_if_volt_9_8_len 2
+#define	reg_aagc_digital_if_volt_9_8_lsb 8
+#define xd_r_reg_aagc_rf_gain	0xA07C
+#define	reg_aagc_rf_gain_pos 0
+#define	reg_aagc_rf_gain_len 8
+#define	reg_aagc_rf_gain_lsb 0
+#define xd_r_reg_aagc_if_gain	0xA07D
+#define	reg_aagc_if_gain_pos 0
+#define	reg_aagc_if_gain_len 8
+#define	reg_aagc_if_gain_lsb 0
+#define xd_p_tinr_imp_indicator	0xA080
+#define	tinr_imp_indicator_pos 0
+#define	tinr_imp_indicator_len 2
+#define	tinr_imp_indicator_lsb 0
+#define xd_p_reg_tinr_fifo_size	0xA080
+#define	reg_tinr_fifo_size_pos 2
+#define	reg_tinr_fifo_size_len 5
+#define	reg_tinr_fifo_size_lsb 0
+#define xd_p_reg_tinr_saturation_cnt_th	0xA081
+#define	reg_tinr_saturation_cnt_th_pos 0
+#define	reg_tinr_saturation_cnt_th_len 4
+#define	reg_tinr_saturation_cnt_th_lsb 0
+#define xd_p_reg_tinr_saturation_th_3_0	0xA081
+#define	reg_tinr_saturation_th_3_0_pos 4
+#define	reg_tinr_saturation_th_3_0_len 4
+#define	reg_tinr_saturation_th_3_0_lsb 0
+#define xd_p_reg_tinr_saturation_th_8_4	0xA082
+#define	reg_tinr_saturation_th_8_4_pos 0
+#define	reg_tinr_saturation_th_8_4_len 5
+#define	reg_tinr_saturation_th_8_4_lsb 4
+#define xd_p_reg_tinr_imp_duration_th_2k_7_0	0xA083
+#define	reg_tinr_imp_duration_th_2k_7_0_pos 0
+#define	reg_tinr_imp_duration_th_2k_7_0_len 8
+#define	reg_tinr_imp_duration_th_2k_7_0_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_2k_8	0xA084
+#define	reg_tinr_imp_duration_th_2k_8_pos 0
+#define	reg_tinr_imp_duration_th_2k_8_len 1
+#define	reg_tinr_imp_duration_th_2k_8_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_8k_7_0	0xA085
+#define	reg_tinr_imp_duration_th_8k_7_0_pos 0
+#define	reg_tinr_imp_duration_th_8k_7_0_len 8
+#define	reg_tinr_imp_duration_th_8k_7_0_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_8k_10_8	0xA086
+#define	reg_tinr_imp_duration_th_8k_10_8_pos 0
+#define	reg_tinr_imp_duration_th_8k_10_8_len 3
+#define	reg_tinr_imp_duration_th_8k_10_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_6m_7_0	0xA087
+#define	reg_tinr_freq_ratio_6m_7_0_pos 0
+#define	reg_tinr_freq_ratio_6m_7_0_len 8
+#define	reg_tinr_freq_ratio_6m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_6m_12_8	0xA088
+#define	reg_tinr_freq_ratio_6m_12_8_pos 0
+#define	reg_tinr_freq_ratio_6m_12_8_len 5
+#define	reg_tinr_freq_ratio_6m_12_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_7m_7_0	0xA089
+#define	reg_tinr_freq_ratio_7m_7_0_pos 0
+#define	reg_tinr_freq_ratio_7m_7_0_len 8
+#define	reg_tinr_freq_ratio_7m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_7m_12_8	0xA08A
+#define	reg_tinr_freq_ratio_7m_12_8_pos 0
+#define	reg_tinr_freq_ratio_7m_12_8_len 5
+#define	reg_tinr_freq_ratio_7m_12_8_lsb 8
+#define xd_p_reg_tinr_freq_ratio_8m_7_0	0xA08B
+#define	reg_tinr_freq_ratio_8m_7_0_pos 0
+#define	reg_tinr_freq_ratio_8m_7_0_len 8
+#define	reg_tinr_freq_ratio_8m_7_0_lsb 0
+#define xd_p_reg_tinr_freq_ratio_8m_12_8	0xA08C
+#define	reg_tinr_freq_ratio_8m_12_8_pos 0
+#define	reg_tinr_freq_ratio_8m_12_8_len 5
+#define	reg_tinr_freq_ratio_8m_12_8_lsb 8
+#define xd_p_reg_tinr_imp_duration_th_low_2k	0xA08D
+#define	reg_tinr_imp_duration_th_low_2k_pos 0
+#define	reg_tinr_imp_duration_th_low_2k_len 8
+#define	reg_tinr_imp_duration_th_low_2k_lsb 0
+#define xd_p_reg_tinr_imp_duration_th_low_8k	0xA08E
+#define	reg_tinr_imp_duration_th_low_8k_pos 0
+#define	reg_tinr_imp_duration_th_low_8k_len 8
+#define	reg_tinr_imp_duration_th_low_8k_lsb 0
+#define xd_r_reg_tinr_counter_7_0	0xA090
+#define	reg_tinr_counter_7_0_pos 0
+#define	reg_tinr_counter_7_0_len 8
+#define	reg_tinr_counter_7_0_lsb 0
+#define xd_r_reg_tinr_counter_15_8	0xA091
+#define	reg_tinr_counter_15_8_pos 0
+#define	reg_tinr_counter_15_8_len 8
+#define	reg_tinr_counter_15_8_lsb 8
+#define xd_p_reg_tinr_adative_tinr_en	0xA093
+#define	reg_tinr_adative_tinr_en_pos 0
+#define	reg_tinr_adative_tinr_en_len 1
+#define	reg_tinr_adative_tinr_en_lsb 0
+#define xd_p_reg_tinr_peak_fifo_size	0xA093
+#define	reg_tinr_peak_fifo_size_pos 1
+#define	reg_tinr_peak_fifo_size_len 5
+#define	reg_tinr_peak_fifo_size_lsb 0
+#define xd_p_reg_tinr_counter_rst	0xA093
+#define	reg_tinr_counter_rst_pos 6
+#define	reg_tinr_counter_rst_len 1
+#define	reg_tinr_counter_rst_lsb 0
+#define xd_p_reg_tinr_search_period_7_0	0xA094
+#define	reg_tinr_search_period_7_0_pos 0
+#define	reg_tinr_search_period_7_0_len 8
+#define	reg_tinr_search_period_7_0_lsb 0
+#define xd_p_reg_tinr_search_period_15_8	0xA095
+#define	reg_tinr_search_period_15_8_pos 0
+#define	reg_tinr_search_period_15_8_len 8
+#define	reg_tinr_search_period_15_8_lsb 8
+#define xd_p_reg_ccifs_fcw_7_0	0xA0A0
+#define	reg_ccifs_fcw_7_0_pos 0
+#define	reg_ccifs_fcw_7_0_len 8
+#define	reg_ccifs_fcw_7_0_lsb 0
+#define xd_p_reg_ccifs_fcw_12_8	0xA0A1
+#define	reg_ccifs_fcw_12_8_pos 0
+#define	reg_ccifs_fcw_12_8_len 5
+#define	reg_ccifs_fcw_12_8_lsb 8
+#define xd_p_reg_ccifs_spec_inv	0xA0A1
+#define	reg_ccifs_spec_inv_pos 5
+#define	reg_ccifs_spec_inv_len 1
+#define	reg_ccifs_spec_inv_lsb 0
+#define xd_p_reg_gp_trigger	0xA0A2
+#define	reg_gp_trigger_pos 0
+#define	reg_gp_trigger_len 1
+#define	reg_gp_trigger_lsb 0
+#define xd_p_reg_trigger_sel	0xA0A2
+#define	reg_trigger_sel_pos 1
+#define	reg_trigger_sel_len 2
+#define	reg_trigger_sel_lsb 0
+#define xd_p_reg_debug_ofdm	0xA0A2
+#define	reg_debug_ofdm_pos 3
+#define	reg_debug_ofdm_len 2
+#define	reg_debug_ofdm_lsb 0
+#define xd_p_reg_trigger_module_sel	0xA0A3
+#define	reg_trigger_module_sel_pos 0
+#define	reg_trigger_module_sel_len 6
+#define	reg_trigger_module_sel_lsb 0
+#define xd_p_reg_trigger_set_sel	0xA0A4
+#define	reg_trigger_set_sel_pos 0
+#define	reg_trigger_set_sel_len 6
+#define	reg_trigger_set_sel_lsb 0
+#define xd_p_reg_fw_int_mask_n	0xA0A4
+#define	reg_fw_int_mask_n_pos 6
+#define	reg_fw_int_mask_n_len 1
+#define	reg_fw_int_mask_n_lsb 0
+#define xd_p_reg_debug_group	0xA0A5
+#define	reg_debug_group_pos 0
+#define	reg_debug_group_len 4
+#define	reg_debug_group_lsb 0
+#define xd_p_reg_odbg_clk_sel	0xA0A5
+#define	reg_odbg_clk_sel_pos 4
+#define	reg_odbg_clk_sel_len 2
+#define	reg_odbg_clk_sel_lsb 0
+#define xd_p_reg_ccif_sc	0xA0C0
+#define	reg_ccif_sc_pos 0
+#define	reg_ccif_sc_len 4
+#define	reg_ccif_sc_lsb 0
+#define xd_r_reg_ccif_saturate	0xA0C1
+#define	reg_ccif_saturate_pos 0
+#define	reg_ccif_saturate_len 2
+#define	reg_ccif_saturate_lsb 0
+#define xd_r_reg_antif_saturate	0xA0C1
+#define	reg_antif_saturate_pos 2
+#define	reg_antif_saturate_len 4
+#define	reg_antif_saturate_lsb 0
+#define xd_r_reg_acif_saturate	0xA0C2
+#define	reg_acif_saturate_pos 0
+#define	reg_acif_saturate_len 8
+#define	reg_acif_saturate_lsb 0
+#define xd_p_reg_tmr_timer0_threshold_7_0	0xA0C8
+#define	reg_tmr_timer0_threshold_7_0_pos 0
+#define	reg_tmr_timer0_threshold_7_0_len 8
+#define	reg_tmr_timer0_threshold_7_0_lsb 0
+#define xd_p_reg_tmr_timer0_threshold_15_8	0xA0C9
+#define	reg_tmr_timer0_threshold_15_8_pos 0
+#define	reg_tmr_timer0_threshold_15_8_len 8
+#define	reg_tmr_timer0_threshold_15_8_lsb 8
+#define xd_p_reg_tmr_timer0_enable	0xA0CA
+#define	reg_tmr_timer0_enable_pos 0
+#define	reg_tmr_timer0_enable_len 1
+#define	reg_tmr_timer0_enable_lsb 0
+#define xd_p_reg_tmr_timer0_clk_sel	0xA0CA
+#define	reg_tmr_timer0_clk_sel_pos 1
+#define	reg_tmr_timer0_clk_sel_len 1
+#define	reg_tmr_timer0_clk_sel_lsb 0
+#define xd_p_reg_tmr_timer0_int	0xA0CA
+#define	reg_tmr_timer0_int_pos 2
+#define	reg_tmr_timer0_int_len 1
+#define	reg_tmr_timer0_int_lsb 0
+#define xd_p_reg_tmr_timer0_rst	0xA0CA
+#define	reg_tmr_timer0_rst_pos 3
+#define	reg_tmr_timer0_rst_len 1
+#define	reg_tmr_timer0_rst_lsb 0
+#define xd_r_reg_tmr_timer0_count_7_0	0xA0CB
+#define	reg_tmr_timer0_count_7_0_pos 0
+#define	reg_tmr_timer0_count_7_0_len 8
+#define	reg_tmr_timer0_count_7_0_lsb 0
+#define xd_r_reg_tmr_timer0_count_15_8	0xA0CC
+#define	reg_tmr_timer0_count_15_8_pos 0
+#define	reg_tmr_timer0_count_15_8_len 8
+#define	reg_tmr_timer0_count_15_8_lsb 8
+#define xd_p_reg_suspend	0xA0CD
+#define	reg_suspend_pos 0
+#define	reg_suspend_len 1
+#define	reg_suspend_lsb 0
+#define xd_p_reg_suspend_rdy	0xA0CD
+#define	reg_suspend_rdy_pos 1
+#define	reg_suspend_rdy_len 1
+#define	reg_suspend_rdy_lsb 0
+#define xd_p_reg_resume	0xA0CD
+#define	reg_resume_pos 2
+#define	reg_resume_len 1
+#define	reg_resume_lsb 0
+#define xd_p_reg_resume_rdy	0xA0CD
+#define	reg_resume_rdy_pos 3
+#define	reg_resume_rdy_len 1
+#define	reg_resume_rdy_lsb 0
+#define xd_p_reg_fmf	0xA0CE
+#define	reg_fmf_pos 0
+#define	reg_fmf_len 8
+#define	reg_fmf_lsb 0
+#define xd_p_ccid_accumulate_num_2k_7_0	0xA100
+#define	ccid_accumulate_num_2k_7_0_pos 0
+#define	ccid_accumulate_num_2k_7_0_len 8
+#define	ccid_accumulate_num_2k_7_0_lsb 0
+#define xd_p_ccid_accumulate_num_2k_12_8	0xA101
+#define	ccid_accumulate_num_2k_12_8_pos 0
+#define	ccid_accumulate_num_2k_12_8_len 5
+#define	ccid_accumulate_num_2k_12_8_lsb 8
+#define xd_p_ccid_accumulate_num_8k_7_0	0xA102
+#define	ccid_accumulate_num_8k_7_0_pos 0
+#define	ccid_accumulate_num_8k_7_0_len 8
+#define	ccid_accumulate_num_8k_7_0_lsb 0
+#define xd_p_ccid_accumulate_num_8k_14_8	0xA103
+#define	ccid_accumulate_num_8k_14_8_pos 0
+#define	ccid_accumulate_num_8k_14_8_len 7
+#define	ccid_accumulate_num_8k_14_8_lsb 8
+#define xd_p_ccid_desired_level_0	0xA103
+#define	ccid_desired_level_0_pos 7
+#define	ccid_desired_level_0_len 1
+#define	ccid_desired_level_0_lsb 0
+#define xd_p_ccid_desired_level_8_1	0xA104
+#define	ccid_desired_level_8_1_pos 0
+#define	ccid_desired_level_8_1_len 8
+#define	ccid_desired_level_8_1_lsb 1
+#define xd_p_ccid_apply_delay	0xA105
+#define	ccid_apply_delay_pos 0
+#define	ccid_apply_delay_len 7
+#define	ccid_apply_delay_lsb 0
+#define xd_p_ccid_CCID_Threshold1	0xA106
+#define	ccid_CCID_Threshold1_pos 0
+#define	ccid_CCID_Threshold1_len 8
+#define	ccid_CCID_Threshold1_lsb 0
+#define xd_p_ccid_CCID_Threshold2	0xA107
+#define	ccid_CCID_Threshold2_pos 0
+#define	ccid_CCID_Threshold2_len 8
+#define	ccid_CCID_Threshold2_lsb 0
+#define xd_p_reg_ccid_gain_scale	0xA108
+#define	reg_ccid_gain_scale_pos 0
+#define	reg_ccid_gain_scale_len 4
+#define	reg_ccid_gain_scale_lsb 0
+#define xd_p_reg_ccid2_passband_gain_set	0xA108
+#define	reg_ccid2_passband_gain_set_pos 4
+#define	reg_ccid2_passband_gain_set_len 4
+#define	reg_ccid2_passband_gain_set_lsb 0
+#define xd_r_ccid_multiplier_7_0	0xA109
+#define	ccid_multiplier_7_0_pos 0
+#define	ccid_multiplier_7_0_len 8
+#define	ccid_multiplier_7_0_lsb 0
+#define xd_r_ccid_multiplier_15_8	0xA10A
+#define	ccid_multiplier_15_8_pos 0
+#define	ccid_multiplier_15_8_len 8
+#define	ccid_multiplier_15_8_lsb 8
+#define xd_r_ccid_right_shift_bits	0xA10B
+#define	ccid_right_shift_bits_pos 0
+#define	ccid_right_shift_bits_len 4
+#define	ccid_right_shift_bits_lsb 0
+#define xd_r_reg_ccid_sx_7_0	0xA10C
+#define	reg_ccid_sx_7_0_pos 0
+#define	reg_ccid_sx_7_0_len 8
+#define	reg_ccid_sx_7_0_lsb 0
+#define xd_r_reg_ccid_sx_15_8	0xA10D
+#define	reg_ccid_sx_15_8_pos 0
+#define	reg_ccid_sx_15_8_len 8
+#define	reg_ccid_sx_15_8_lsb 8
+#define xd_r_reg_ccid_sx_21_16	0xA10E
+#define	reg_ccid_sx_21_16_pos 0
+#define	reg_ccid_sx_21_16_len 6
+#define	reg_ccid_sx_21_16_lsb 16
+#define xd_r_reg_ccid_sy_7_0	0xA110
+#define	reg_ccid_sy_7_0_pos 0
+#define	reg_ccid_sy_7_0_len 8
+#define	reg_ccid_sy_7_0_lsb 0
+#define xd_r_reg_ccid_sy_15_8	0xA111
+#define	reg_ccid_sy_15_8_pos 0
+#define	reg_ccid_sy_15_8_len 8
+#define	reg_ccid_sy_15_8_lsb 8
+#define xd_r_reg_ccid_sy_23_16	0xA112
+#define	reg_ccid_sy_23_16_pos 0
+#define	reg_ccid_sy_23_16_len 8
+#define	reg_ccid_sy_23_16_lsb 16
+#define xd_r_reg_ccid2_sz_7_0	0xA114
+#define	reg_ccid2_sz_7_0_pos 0
+#define	reg_ccid2_sz_7_0_len 8
+#define	reg_ccid2_sz_7_0_lsb 0
+#define xd_r_reg_ccid2_sz_15_8	0xA115
+#define	reg_ccid2_sz_15_8_pos 0
+#define	reg_ccid2_sz_15_8_len 8
+#define	reg_ccid2_sz_15_8_lsb 8
+#define xd_r_reg_ccid2_sz_23_16	0xA116
+#define	reg_ccid2_sz_23_16_pos 0
+#define	reg_ccid2_sz_23_16_len 8
+#define	reg_ccid2_sz_23_16_lsb 16
+#define xd_r_reg_ccid2_sz_25_24	0xA117
+#define	reg_ccid2_sz_25_24_pos 0
+#define	reg_ccid2_sz_25_24_len 2
+#define	reg_ccid2_sz_25_24_lsb 24
+#define xd_r_reg_ccid2_sy_7_0	0xA118
+#define	reg_ccid2_sy_7_0_pos 0
+#define	reg_ccid2_sy_7_0_len 8
+#define	reg_ccid2_sy_7_0_lsb 0
+#define xd_r_reg_ccid2_sy_15_8	0xA119
+#define	reg_ccid2_sy_15_8_pos 0
+#define	reg_ccid2_sy_15_8_len 8
+#define	reg_ccid2_sy_15_8_lsb 8
+#define xd_r_reg_ccid2_sy_23_16	0xA11A
+#define	reg_ccid2_sy_23_16_pos 0
+#define	reg_ccid2_sy_23_16_len 8
+#define	reg_ccid2_sy_23_16_lsb 16
+#define xd_r_reg_ccid2_sy_25_24	0xA11B
+#define	reg_ccid2_sy_25_24_pos 0
+#define	reg_ccid2_sy_25_24_len 2
+#define	reg_ccid2_sy_25_24_lsb 24
+#define xd_p_dagc1_accumulate_num_2k_7_0	0xA120
+#define	dagc1_accumulate_num_2k_7_0_pos 0
+#define	dagc1_accumulate_num_2k_7_0_len 8
+#define	dagc1_accumulate_num_2k_7_0_lsb 0
+#define xd_p_dagc1_accumulate_num_2k_12_8	0xA121
+#define	dagc1_accumulate_num_2k_12_8_pos 0
+#define	dagc1_accumulate_num_2k_12_8_len 5
+#define	dagc1_accumulate_num_2k_12_8_lsb 8
+#define xd_p_dagc1_accumulate_num_8k_7_0	0xA122
+#define	dagc1_accumulate_num_8k_7_0_pos 0
+#define	dagc1_accumulate_num_8k_7_0_len 8
+#define	dagc1_accumulate_num_8k_7_0_lsb 0
+#define xd_p_dagc1_accumulate_num_8k_14_8	0xA123
+#define	dagc1_accumulate_num_8k_14_8_pos 0
+#define	dagc1_accumulate_num_8k_14_8_len 7
+#define	dagc1_accumulate_num_8k_14_8_lsb 8
+#define xd_p_dagc1_desired_level_0	0xA123
+#define	dagc1_desired_level_0_pos 7
+#define	dagc1_desired_level_0_len 1
+#define	dagc1_desired_level_0_lsb 0
+#define xd_p_dagc1_desired_level_8_1	0xA124
+#define	dagc1_desired_level_8_1_pos 0
+#define	dagc1_desired_level_8_1_len 8
+#define	dagc1_desired_level_8_1_lsb 1
+#define xd_p_dagc1_apply_delay	0xA125
+#define	dagc1_apply_delay_pos 0
+#define	dagc1_apply_delay_len 7
+#define	dagc1_apply_delay_lsb 0
+#define xd_p_dagc1_bypass_scale_ctl	0xA126
+#define	dagc1_bypass_scale_ctl_pos 0
+#define	dagc1_bypass_scale_ctl_len 2
+#define	dagc1_bypass_scale_ctl_lsb 0
+#define xd_p_reg_dagc1_in_sat_cnt_7_0	0xA127
+#define	reg_dagc1_in_sat_cnt_7_0_pos 0
+#define	reg_dagc1_in_sat_cnt_7_0_len 8
+#define	reg_dagc1_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc1_in_sat_cnt_15_8	0xA128
+#define	reg_dagc1_in_sat_cnt_15_8_pos 0
+#define	reg_dagc1_in_sat_cnt_15_8_len 8
+#define	reg_dagc1_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc1_in_sat_cnt_23_16	0xA129
+#define	reg_dagc1_in_sat_cnt_23_16_pos 0
+#define	reg_dagc1_in_sat_cnt_23_16_len 8
+#define	reg_dagc1_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc1_in_sat_cnt_31_24	0xA12A
+#define	reg_dagc1_in_sat_cnt_31_24_pos 0
+#define	reg_dagc1_in_sat_cnt_31_24_len 8
+#define	reg_dagc1_in_sat_cnt_31_24_lsb 24
+#define xd_p_reg_dagc1_out_sat_cnt_7_0	0xA12B
+#define	reg_dagc1_out_sat_cnt_7_0_pos 0
+#define	reg_dagc1_out_sat_cnt_7_0_len 8
+#define	reg_dagc1_out_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc1_out_sat_cnt_15_8	0xA12C
+#define	reg_dagc1_out_sat_cnt_15_8_pos 0
+#define	reg_dagc1_out_sat_cnt_15_8_len 8
+#define	reg_dagc1_out_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc1_out_sat_cnt_23_16	0xA12D
+#define	reg_dagc1_out_sat_cnt_23_16_pos 0
+#define	reg_dagc1_out_sat_cnt_23_16_len 8
+#define	reg_dagc1_out_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc1_out_sat_cnt_31_24	0xA12E
+#define	reg_dagc1_out_sat_cnt_31_24_pos 0
+#define	reg_dagc1_out_sat_cnt_31_24_len 8
+#define	reg_dagc1_out_sat_cnt_31_24_lsb 24
+#define xd_r_dagc1_multiplier_7_0	0xA136
+#define	dagc1_multiplier_7_0_pos 0
+#define	dagc1_multiplier_7_0_len 8
+#define	dagc1_multiplier_7_0_lsb 0
+#define xd_r_dagc1_multiplier_15_8	0xA137
+#define	dagc1_multiplier_15_8_pos 0
+#define	dagc1_multiplier_15_8_len 8
+#define	dagc1_multiplier_15_8_lsb 8
+#define xd_r_dagc1_right_shift_bits	0xA138
+#define	dagc1_right_shift_bits_pos 0
+#define	dagc1_right_shift_bits_len 4
+#define	dagc1_right_shift_bits_lsb 0
+#define xd_p_reg_bfs_fcw_7_0	0xA140
+#define	reg_bfs_fcw_7_0_pos 0
+#define	reg_bfs_fcw_7_0_len 8
+#define	reg_bfs_fcw_7_0_lsb 0
+#define xd_p_reg_bfs_fcw_15_8	0xA141
+#define	reg_bfs_fcw_15_8_pos 0
+#define	reg_bfs_fcw_15_8_len 8
+#define	reg_bfs_fcw_15_8_lsb 8
+#define xd_p_reg_bfs_fcw_22_16	0xA142
+#define	reg_bfs_fcw_22_16_pos 0
+#define	reg_bfs_fcw_22_16_len 7
+#define	reg_bfs_fcw_22_16_lsb 16
+#define xd_p_reg_antif_sf_7_0	0xA144
+#define	reg_antif_sf_7_0_pos 0
+#define	reg_antif_sf_7_0_len 8
+#define	reg_antif_sf_7_0_lsb 0
+#define xd_p_reg_antif_sf_11_8	0xA145
+#define	reg_antif_sf_11_8_pos 0
+#define	reg_antif_sf_11_8_len 4
+#define	reg_antif_sf_11_8_lsb 8
+#define xd_r_bfs_fcw_q_7_0	0xA150
+#define	bfs_fcw_q_7_0_pos 0
+#define	bfs_fcw_q_7_0_len 8
+#define	bfs_fcw_q_7_0_lsb 0
+#define xd_r_bfs_fcw_q_15_8	0xA151
+#define	bfs_fcw_q_15_8_pos 0
+#define	bfs_fcw_q_15_8_len 8
+#define	bfs_fcw_q_15_8_lsb 8
+#define xd_r_bfs_fcw_q_22_16	0xA152
+#define	bfs_fcw_q_22_16_pos 0
+#define	bfs_fcw_q_22_16_len 7
+#define	bfs_fcw_q_22_16_lsb 16
+#define xd_p_reg_dca_enu	0xA160
+#define	reg_dca_enu_pos 0
+#define	reg_dca_enu_len 1
+#define	reg_dca_enu_lsb 0
+#define xd_p_reg_dca_enl	0xA160
+#define	reg_dca_enl_pos 1
+#define	reg_dca_enl_len 1
+#define	reg_dca_enl_lsb 0
+#define xd_p_reg_dca_lower_chip	0xA160
+#define	reg_dca_lower_chip_pos 2
+#define	reg_dca_lower_chip_len 1
+#define	reg_dca_lower_chip_lsb 0
+#define xd_p_reg_dca_upper_chip	0xA160
+#define	reg_dca_upper_chip_pos 3
+#define	reg_dca_upper_chip_len 1
+#define	reg_dca_upper_chip_lsb 0
+#define xd_p_reg_dca_platch	0xA160
+#define	reg_dca_platch_pos 4
+#define	reg_dca_platch_len 1
+#define	reg_dca_platch_lsb 0
+#define xd_p_reg_dca_th	0xA161
+#define	reg_dca_th_pos 0
+#define	reg_dca_th_len 5
+#define	reg_dca_th_lsb 0
+#define xd_p_reg_dca_scale	0xA162
+#define	reg_dca_scale_pos 0
+#define	reg_dca_scale_len 4
+#define	reg_dca_scale_lsb 0
+#define xd_p_reg_dca_tone_7_0	0xA163
+#define	reg_dca_tone_7_0_pos 0
+#define	reg_dca_tone_7_0_len 8
+#define	reg_dca_tone_7_0_lsb 0
+#define xd_p_reg_dca_tone_12_8	0xA164
+#define	reg_dca_tone_12_8_pos 0
+#define	reg_dca_tone_12_8_len 5
+#define	reg_dca_tone_12_8_lsb 8
+#define xd_p_reg_dca_time_7_0	0xA165
+#define	reg_dca_time_7_0_pos 0
+#define	reg_dca_time_7_0_len 8
+#define	reg_dca_time_7_0_lsb 0
+#define xd_p_reg_dca_time_15_8	0xA166
+#define	reg_dca_time_15_8_pos 0
+#define	reg_dca_time_15_8_len 8
+#define	reg_dca_time_15_8_lsb 8
+#define xd_r_dcasm	0xA167
+#define	dcasm_pos 0
+#define	dcasm_len 3
+#define	dcasm_lsb 0
+#define xd_p_reg_qnt_valuew_7_0	0xA168
+#define	reg_qnt_valuew_7_0_pos 0
+#define	reg_qnt_valuew_7_0_len 8
+#define	reg_qnt_valuew_7_0_lsb 0
+#define xd_p_reg_qnt_valuew_10_8	0xA169
+#define	reg_qnt_valuew_10_8_pos 0
+#define	reg_qnt_valuew_10_8_len 3
+#define	reg_qnt_valuew_10_8_lsb 8
+#define xd_p_dca_sbx_gain_diff_7_0	0xA16A
+#define	dca_sbx_gain_diff_7_0_pos 0
+#define	dca_sbx_gain_diff_7_0_len 8
+#define	dca_sbx_gain_diff_7_0_lsb 0
+#define xd_p_dca_sbx_gain_diff_9_8	0xA16B
+#define	dca_sbx_gain_diff_9_8_pos 0
+#define	dca_sbx_gain_diff_9_8_len 2
+#define	dca_sbx_gain_diff_9_8_lsb 8
+#define xd_p_reg_dca_stand_alone	0xA16C
+#define	reg_dca_stand_alone_pos 0
+#define	reg_dca_stand_alone_len 1
+#define	reg_dca_stand_alone_lsb 0
+#define xd_p_reg_dca_upper_out_en	0xA16C
+#define	reg_dca_upper_out_en_pos 1
+#define	reg_dca_upper_out_en_len 1
+#define	reg_dca_upper_out_en_lsb 0
+#define xd_p_reg_dca_rc_en	0xA16C
+#define	reg_dca_rc_en_pos 2
+#define	reg_dca_rc_en_len 1
+#define	reg_dca_rc_en_lsb 0
+#define xd_p_reg_dca_retrain_send	0xA16C
+#define	reg_dca_retrain_send_pos 3
+#define	reg_dca_retrain_send_len 1
+#define	reg_dca_retrain_send_lsb 0
+#define xd_p_reg_dca_retrain_rec	0xA16C
+#define	reg_dca_retrain_rec_pos 4
+#define	reg_dca_retrain_rec_len 1
+#define	reg_dca_retrain_rec_lsb 0
+#define xd_p_reg_dca_api_tpsrdy	0xA16C
+#define	reg_dca_api_tpsrdy_pos 5
+#define	reg_dca_api_tpsrdy_len 1
+#define	reg_dca_api_tpsrdy_lsb 0
+#define xd_p_reg_dca_symbol_gap	0xA16D
+#define	reg_dca_symbol_gap_pos 0
+#define	reg_dca_symbol_gap_len 4
+#define	reg_dca_symbol_gap_lsb 0
+#define xd_p_reg_qnt_nfvaluew_7_0	0xA16E
+#define	reg_qnt_nfvaluew_7_0_pos 0
+#define	reg_qnt_nfvaluew_7_0_len 8
+#define	reg_qnt_nfvaluew_7_0_lsb 0
+#define xd_p_reg_qnt_nfvaluew_10_8	0xA16F
+#define	reg_qnt_nfvaluew_10_8_pos 0
+#define	reg_qnt_nfvaluew_10_8_len 3
+#define	reg_qnt_nfvaluew_10_8_lsb 8
+#define xd_p_reg_qnt_flatness_thr_7_0	0xA170
+#define	reg_qnt_flatness_thr_7_0_pos 0
+#define	reg_qnt_flatness_thr_7_0_len 8
+#define	reg_qnt_flatness_thr_7_0_lsb 0
+#define xd_p_reg_qnt_flatness_thr_9_8	0xA171
+#define	reg_qnt_flatness_thr_9_8_pos 0
+#define	reg_qnt_flatness_thr_9_8_len 2
+#define	reg_qnt_flatness_thr_9_8_lsb 8
+#define xd_p_reg_dca_tone_idx_5_0	0xA171
+#define	reg_dca_tone_idx_5_0_pos 2
+#define	reg_dca_tone_idx_5_0_len 6
+#define	reg_dca_tone_idx_5_0_lsb 0
+#define xd_p_reg_dca_tone_idx_12_6	0xA172
+#define	reg_dca_tone_idx_12_6_pos 0
+#define	reg_dca_tone_idx_12_6_len 7
+#define	reg_dca_tone_idx_12_6_lsb 6
+#define xd_p_reg_dca_data_vld	0xA173
+#define	reg_dca_data_vld_pos 0
+#define	reg_dca_data_vld_len 1
+#define	reg_dca_data_vld_lsb 0
+#define xd_p_reg_dca_read_update	0xA173
+#define	reg_dca_read_update_pos 1
+#define	reg_dca_read_update_len 1
+#define	reg_dca_read_update_lsb 0
+#define xd_r_reg_dca_data_re_5_0	0xA173
+#define	reg_dca_data_re_5_0_pos 2
+#define	reg_dca_data_re_5_0_len 6
+#define	reg_dca_data_re_5_0_lsb 0
+#define xd_r_reg_dca_data_re_10_6	0xA174
+#define	reg_dca_data_re_10_6_pos 0
+#define	reg_dca_data_re_10_6_len 5
+#define	reg_dca_data_re_10_6_lsb 6
+#define xd_r_reg_dca_data_im_7_0	0xA175
+#define	reg_dca_data_im_7_0_pos 0
+#define	reg_dca_data_im_7_0_len 8
+#define	reg_dca_data_im_7_0_lsb 0
+#define xd_r_reg_dca_data_im_10_8	0xA176
+#define	reg_dca_data_im_10_8_pos 0
+#define	reg_dca_data_im_10_8_len 3
+#define	reg_dca_data_im_10_8_lsb 8
+#define xd_r_reg_dca_data_h2_7_0	0xA178
+#define	reg_dca_data_h2_7_0_pos 0
+#define	reg_dca_data_h2_7_0_len 8
+#define	reg_dca_data_h2_7_0_lsb 0
+#define xd_r_reg_dca_data_h2_9_8	0xA179
+#define	reg_dca_data_h2_9_8_pos 0
+#define	reg_dca_data_h2_9_8_len 2
+#define	reg_dca_data_h2_9_8_lsb 8
+#define xd_p_reg_f_adc_7_0	0xA180
+#define	reg_f_adc_7_0_pos 0
+#define	reg_f_adc_7_0_len 8
+#define	reg_f_adc_7_0_lsb 0
+#define xd_p_reg_f_adc_15_8	0xA181
+#define	reg_f_adc_15_8_pos 0
+#define	reg_f_adc_15_8_len 8
+#define	reg_f_adc_15_8_lsb 8
+#define xd_p_reg_f_adc_23_16	0xA182
+#define	reg_f_adc_23_16_pos 0
+#define	reg_f_adc_23_16_len 8
+#define	reg_f_adc_23_16_lsb 16
+#define xd_r_intp_mu_7_0	0xA190
+#define	intp_mu_7_0_pos 0
+#define	intp_mu_7_0_len 8
+#define	intp_mu_7_0_lsb 0
+#define xd_r_intp_mu_15_8	0xA191
+#define	intp_mu_15_8_pos 0
+#define	intp_mu_15_8_len 8
+#define	intp_mu_15_8_lsb 8
+#define xd_r_intp_mu_19_16	0xA192
+#define	intp_mu_19_16_pos 0
+#define	intp_mu_19_16_len 4
+#define	intp_mu_19_16_lsb 16
+#define xd_p_reg_agc_rst	0xA1A0
+#define	reg_agc_rst_pos 0
+#define	reg_agc_rst_len 1
+#define	reg_agc_rst_lsb 0
+#define xd_p_rf_agc_en	0xA1A0
+#define	rf_agc_en_pos 1
+#define	rf_agc_en_len 1
+#define	rf_agc_en_lsb 0
+#define xd_p_rf_agc_dis	0xA1A0
+#define	rf_agc_dis_pos 2
+#define	rf_agc_dis_len 1
+#define	rf_agc_dis_lsb 0
+#define xd_p_if_agc_rst	0xA1A0
+#define	if_agc_rst_pos 3
+#define	if_agc_rst_len 1
+#define	if_agc_rst_lsb 0
+#define xd_p_if_agc_en	0xA1A0
+#define	if_agc_en_pos 4
+#define	if_agc_en_len 1
+#define	if_agc_en_lsb 0
+#define xd_p_if_agc_dis	0xA1A0
+#define	if_agc_dis_pos 5
+#define	if_agc_dis_len 1
+#define	if_agc_dis_lsb 0
+#define xd_p_agc_lock	0xA1A0
+#define	agc_lock_pos 6
+#define	agc_lock_len 1
+#define	agc_lock_lsb 0
+#define xd_p_reg_tinr_rst	0xA1A1
+#define	reg_tinr_rst_pos 0
+#define	reg_tinr_rst_len 1
+#define	reg_tinr_rst_lsb 0
+#define xd_p_reg_tinr_en	0xA1A1
+#define	reg_tinr_en_pos 1
+#define	reg_tinr_en_len 1
+#define	reg_tinr_en_lsb 0
+#define xd_p_reg_ccifs_en	0xA1A2
+#define	reg_ccifs_en_pos 0
+#define	reg_ccifs_en_len 1
+#define	reg_ccifs_en_lsb 0
+#define xd_p_reg_ccifs_dis	0xA1A2
+#define	reg_ccifs_dis_pos 1
+#define	reg_ccifs_dis_len 1
+#define	reg_ccifs_dis_lsb 0
+#define xd_p_reg_ccifs_rst	0xA1A2
+#define	reg_ccifs_rst_pos 2
+#define	reg_ccifs_rst_len 1
+#define	reg_ccifs_rst_lsb 0
+#define xd_p_reg_ccifs_byp	0xA1A2
+#define	reg_ccifs_byp_pos 3
+#define	reg_ccifs_byp_len 1
+#define	reg_ccifs_byp_lsb 0
+#define xd_p_reg_ccif_en	0xA1A3
+#define	reg_ccif_en_pos 0
+#define	reg_ccif_en_len 1
+#define	reg_ccif_en_lsb 0
+#define xd_p_reg_ccif_dis	0xA1A3
+#define	reg_ccif_dis_pos 1
+#define	reg_ccif_dis_len 1
+#define	reg_ccif_dis_lsb 0
+#define xd_p_reg_ccif_rst	0xA1A3
+#define	reg_ccif_rst_pos 2
+#define	reg_ccif_rst_len 1
+#define	reg_ccif_rst_lsb 0
+#define xd_p_reg_ccif_byp	0xA1A3
+#define	reg_ccif_byp_pos 3
+#define	reg_ccif_byp_len 1
+#define	reg_ccif_byp_lsb 0
+#define xd_p_dagc1_rst	0xA1A4
+#define	dagc1_rst_pos 0
+#define	dagc1_rst_len 1
+#define	dagc1_rst_lsb 0
+#define xd_p_dagc1_en	0xA1A4
+#define	dagc1_en_pos 1
+#define	dagc1_en_len 1
+#define	dagc1_en_lsb 0
+#define xd_p_dagc1_mode	0xA1A4
+#define	dagc1_mode_pos 2
+#define	dagc1_mode_len 2
+#define	dagc1_mode_lsb 0
+#define xd_p_dagc1_done	0xA1A4
+#define	dagc1_done_pos 4
+#define	dagc1_done_len 1
+#define	dagc1_done_lsb 0
+#define xd_p_ccid_rst	0xA1A5
+#define	ccid_rst_pos 0
+#define	ccid_rst_len 1
+#define	ccid_rst_lsb 0
+#define xd_p_ccid_en	0xA1A5
+#define	ccid_en_pos 1
+#define	ccid_en_len 1
+#define	ccid_en_lsb 0
+#define xd_p_ccid_mode	0xA1A5
+#define	ccid_mode_pos 2
+#define	ccid_mode_len 2
+#define	ccid_mode_lsb 0
+#define xd_p_ccid_done	0xA1A5
+#define	ccid_done_pos 4
+#define	ccid_done_len 1
+#define	ccid_done_lsb 0
+#define xd_r_ccid_deted	0xA1A5
+#define	ccid_deted_pos 5
+#define	ccid_deted_len 1
+#define	ccid_deted_lsb 0
+#define xd_p_ccid2_en	0xA1A5
+#define	ccid2_en_pos 6
+#define	ccid2_en_len 1
+#define	ccid2_en_lsb 0
+#define xd_p_ccid2_done	0xA1A5
+#define	ccid2_done_pos 7
+#define	ccid2_done_len 1
+#define	ccid2_done_lsb 0
+#define xd_p_reg_bfs_en	0xA1A6
+#define	reg_bfs_en_pos 0
+#define	reg_bfs_en_len 1
+#define	reg_bfs_en_lsb 0
+#define xd_p_reg_bfs_dis	0xA1A6
+#define	reg_bfs_dis_pos 1
+#define	reg_bfs_dis_len 1
+#define	reg_bfs_dis_lsb 0
+#define xd_p_reg_bfs_rst	0xA1A6
+#define	reg_bfs_rst_pos 2
+#define	reg_bfs_rst_len 1
+#define	reg_bfs_rst_lsb 0
+#define xd_p_reg_bfs_byp	0xA1A6
+#define	reg_bfs_byp_pos 3
+#define	reg_bfs_byp_len 1
+#define	reg_bfs_byp_lsb 0
+#define xd_p_reg_antif_en	0xA1A7
+#define	reg_antif_en_pos 0
+#define	reg_antif_en_len 1
+#define	reg_antif_en_lsb 0
+#define xd_p_reg_antif_dis	0xA1A7
+#define	reg_antif_dis_pos 1
+#define	reg_antif_dis_len 1
+#define	reg_antif_dis_lsb 0
+#define xd_p_reg_antif_rst	0xA1A7
+#define	reg_antif_rst_pos 2
+#define	reg_antif_rst_len 1
+#define	reg_antif_rst_lsb 0
+#define xd_p_reg_antif_byp	0xA1A7
+#define	reg_antif_byp_pos 3
+#define	reg_antif_byp_len 1
+#define	reg_antif_byp_lsb 0
+#define xd_p_intp_en	0xA1A8
+#define	intp_en_pos 0
+#define	intp_en_len 1
+#define	intp_en_lsb 0
+#define xd_p_intp_dis	0xA1A8
+#define	intp_dis_pos 1
+#define	intp_dis_len 1
+#define	intp_dis_lsb 0
+#define xd_p_intp_rst	0xA1A8
+#define	intp_rst_pos 2
+#define	intp_rst_len 1
+#define	intp_rst_lsb 0
+#define xd_p_intp_byp	0xA1A8
+#define	intp_byp_pos 3
+#define	intp_byp_len 1
+#define	intp_byp_lsb 0
+#define xd_p_reg_acif_en	0xA1A9
+#define	reg_acif_en_pos 0
+#define	reg_acif_en_len 1
+#define	reg_acif_en_lsb 0
+#define xd_p_reg_acif_dis	0xA1A9
+#define	reg_acif_dis_pos 1
+#define	reg_acif_dis_len 1
+#define	reg_acif_dis_lsb 0
+#define xd_p_reg_acif_rst	0xA1A9
+#define	reg_acif_rst_pos 2
+#define	reg_acif_rst_len 1
+#define	reg_acif_rst_lsb 0
+#define xd_p_reg_acif_byp	0xA1A9
+#define	reg_acif_byp_pos 3
+#define	reg_acif_byp_len 1
+#define	reg_acif_byp_lsb 0
+#define xd_p_reg_acif_sync_mode	0xA1A9
+#define	reg_acif_sync_mode_pos 4
+#define	reg_acif_sync_mode_len 1
+#define	reg_acif_sync_mode_lsb 0
+#define xd_p_dagc2_rst	0xA1AA
+#define	dagc2_rst_pos 0
+#define	dagc2_rst_len 1
+#define	dagc2_rst_lsb 0
+#define xd_p_dagc2_en	0xA1AA
+#define	dagc2_en_pos 1
+#define	dagc2_en_len 1
+#define	dagc2_en_lsb 0
+#define xd_p_dagc2_mode	0xA1AA
+#define	dagc2_mode_pos 2
+#define	dagc2_mode_len 2
+#define	dagc2_mode_lsb 0
+#define xd_p_dagc2_done	0xA1AA
+#define	dagc2_done_pos 4
+#define	dagc2_done_len 1
+#define	dagc2_done_lsb 0
+#define xd_p_reg_dca_en	0xA1AB
+#define	reg_dca_en_pos 0
+#define	reg_dca_en_len 1
+#define	reg_dca_en_lsb 0
+#define xd_p_dagc2_accumulate_num_2k_7_0	0xA1C0
+#define	dagc2_accumulate_num_2k_7_0_pos 0
+#define	dagc2_accumulate_num_2k_7_0_len 8
+#define	dagc2_accumulate_num_2k_7_0_lsb 0
+#define xd_p_dagc2_accumulate_num_2k_12_8	0xA1C1
+#define	dagc2_accumulate_num_2k_12_8_pos 0
+#define	dagc2_accumulate_num_2k_12_8_len 5
+#define	dagc2_accumulate_num_2k_12_8_lsb 8
+#define xd_p_dagc2_accumulate_num_8k_7_0	0xA1C2
+#define	dagc2_accumulate_num_8k_7_0_pos 0
+#define	dagc2_accumulate_num_8k_7_0_len 8
+#define	dagc2_accumulate_num_8k_7_0_lsb 0
+#define xd_p_dagc2_accumulate_num_8k_12_8	0xA1C3
+#define	dagc2_accumulate_num_8k_12_8_pos 0
+#define	dagc2_accumulate_num_8k_12_8_len 5
+#define	dagc2_accumulate_num_8k_12_8_lsb 8
+#define xd_p_dagc2_desired_level_2_0	0xA1C3
+#define	dagc2_desired_level_2_0_pos 5
+#define	dagc2_desired_level_2_0_len 3
+#define	dagc2_desired_level_2_0_lsb 0
+#define xd_p_dagc2_desired_level_8_3	0xA1C4
+#define	dagc2_desired_level_8_3_pos 0
+#define	dagc2_desired_level_8_3_len 6
+#define	dagc2_desired_level_8_3_lsb 3
+#define xd_p_dagc2_apply_delay	0xA1C5
+#define	dagc2_apply_delay_pos 0
+#define	dagc2_apply_delay_len 7
+#define	dagc2_apply_delay_lsb 0
+#define xd_p_dagc2_bypass_scale_ctl	0xA1C6
+#define	dagc2_bypass_scale_ctl_pos 0
+#define	dagc2_bypass_scale_ctl_len 3
+#define	dagc2_bypass_scale_ctl_lsb 0
+#define xd_p_dagc2_programmable_shift1	0xA1C7
+#define	dagc2_programmable_shift1_pos 0
+#define	dagc2_programmable_shift1_len 8
+#define	dagc2_programmable_shift1_lsb 0
+#define xd_p_dagc2_programmable_shift2	0xA1C8
+#define	dagc2_programmable_shift2_pos 0
+#define	dagc2_programmable_shift2_len 8
+#define	dagc2_programmable_shift2_lsb 0
+#define xd_p_reg_dagc2_in_sat_cnt_7_0	0xA1C9
+#define	reg_dagc2_in_sat_cnt_7_0_pos 0
+#define	reg_dagc2_in_sat_cnt_7_0_len 8
+#define	reg_dagc2_in_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc2_in_sat_cnt_15_8	0xA1CA
+#define	reg_dagc2_in_sat_cnt_15_8_pos 0
+#define	reg_dagc2_in_sat_cnt_15_8_len 8
+#define	reg_dagc2_in_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc2_in_sat_cnt_23_16	0xA1CB
+#define	reg_dagc2_in_sat_cnt_23_16_pos 0
+#define	reg_dagc2_in_sat_cnt_23_16_len 8
+#define	reg_dagc2_in_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc2_in_sat_cnt_31_24	0xA1CC
+#define	reg_dagc2_in_sat_cnt_31_24_pos 0
+#define	reg_dagc2_in_sat_cnt_31_24_len 8
+#define	reg_dagc2_in_sat_cnt_31_24_lsb 24
+#define xd_p_reg_dagc2_out_sat_cnt_7_0	0xA1CD
+#define	reg_dagc2_out_sat_cnt_7_0_pos 0
+#define	reg_dagc2_out_sat_cnt_7_0_len 8
+#define	reg_dagc2_out_sat_cnt_7_0_lsb 0
+#define xd_p_reg_dagc2_out_sat_cnt_15_8	0xA1CE
+#define	reg_dagc2_out_sat_cnt_15_8_pos 0
+#define	reg_dagc2_out_sat_cnt_15_8_len 8
+#define	reg_dagc2_out_sat_cnt_15_8_lsb 8
+#define xd_p_reg_dagc2_out_sat_cnt_23_16	0xA1CF
+#define	reg_dagc2_out_sat_cnt_23_16_pos 0
+#define	reg_dagc2_out_sat_cnt_23_16_len 8
+#define	reg_dagc2_out_sat_cnt_23_16_lsb 16
+#define xd_p_reg_dagc2_out_sat_cnt_31_24	0xA1D0
+#define	reg_dagc2_out_sat_cnt_31_24_pos 0
+#define	reg_dagc2_out_sat_cnt_31_24_len 8
+#define	reg_dagc2_out_sat_cnt_31_24_lsb 24
+#define xd_r_dagc2_multiplier_7_0	0xA1D6
+#define	dagc2_multiplier_7_0_pos 0
+#define	dagc2_multiplier_7_0_len 8
+#define	dagc2_multiplier_7_0_lsb 0
+#define xd_r_dagc2_multiplier_15_8	0xA1D7
+#define	dagc2_multiplier_15_8_pos 0
+#define	dagc2_multiplier_15_8_len 8
+#define	dagc2_multiplier_15_8_lsb 8
+#define xd_r_dagc2_right_shift_bits	0xA1D8
+#define	dagc2_right_shift_bits_pos 0
+#define	dagc2_right_shift_bits_len 4
+#define	dagc2_right_shift_bits_lsb 0
+#define xd_p_cfoe_NS_coeff1_7_0	0xA200
+#define	cfoe_NS_coeff1_7_0_pos 0
+#define	cfoe_NS_coeff1_7_0_len 8
+#define	cfoe_NS_coeff1_7_0_lsb 0
+#define xd_p_cfoe_NS_coeff1_15_8	0xA201
+#define	cfoe_NS_coeff1_15_8_pos 0
+#define	cfoe_NS_coeff1_15_8_len 8
+#define	cfoe_NS_coeff1_15_8_lsb 8
+#define xd_p_cfoe_NS_coeff1_23_16	0xA202
+#define	cfoe_NS_coeff1_23_16_pos 0
+#define	cfoe_NS_coeff1_23_16_len 8
+#define	cfoe_NS_coeff1_23_16_lsb 16
+#define xd_p_cfoe_NS_coeff1_25_24	0xA203
+#define	cfoe_NS_coeff1_25_24_pos 0
+#define	cfoe_NS_coeff1_25_24_len 2
+#define	cfoe_NS_coeff1_25_24_lsb 24
+#define xd_p_cfoe_NS_coeff2_5_0	0xA203
+#define	cfoe_NS_coeff2_5_0_pos 2
+#define	cfoe_NS_coeff2_5_0_len 6
+#define	cfoe_NS_coeff2_5_0_lsb 0
+#define xd_p_cfoe_NS_coeff2_13_6	0xA204
+#define	cfoe_NS_coeff2_13_6_pos 0
+#define	cfoe_NS_coeff2_13_6_len 8
+#define	cfoe_NS_coeff2_13_6_lsb 6
+#define xd_p_cfoe_NS_coeff2_21_14	0xA205
+#define	cfoe_NS_coeff2_21_14_pos 0
+#define	cfoe_NS_coeff2_21_14_len 8
+#define	cfoe_NS_coeff2_21_14_lsb 14
+#define xd_p_cfoe_NS_coeff2_24_22	0xA206
+#define	cfoe_NS_coeff2_24_22_pos 0
+#define	cfoe_NS_coeff2_24_22_len 3
+#define	cfoe_NS_coeff2_24_22_lsb 22
+#define xd_p_cfoe_lf_c1_4_0	0xA206
+#define	cfoe_lf_c1_4_0_pos 3
+#define	cfoe_lf_c1_4_0_len 5
+#define	cfoe_lf_c1_4_0_lsb 0
+#define xd_p_cfoe_lf_c1_12_5	0xA207
+#define	cfoe_lf_c1_12_5_pos 0
+#define	cfoe_lf_c1_12_5_len 8
+#define	cfoe_lf_c1_12_5_lsb 5
+#define xd_p_cfoe_lf_c1_20_13	0xA208
+#define	cfoe_lf_c1_20_13_pos 0
+#define	cfoe_lf_c1_20_13_len 8
+#define	cfoe_lf_c1_20_13_lsb 13
+#define xd_p_cfoe_lf_c1_25_21	0xA209
+#define	cfoe_lf_c1_25_21_pos 0
+#define	cfoe_lf_c1_25_21_len 5
+#define	cfoe_lf_c1_25_21_lsb 21
+#define xd_p_cfoe_lf_c2_2_0	0xA209
+#define	cfoe_lf_c2_2_0_pos 5
+#define	cfoe_lf_c2_2_0_len 3
+#define	cfoe_lf_c2_2_0_lsb 0
+#define xd_p_cfoe_lf_c2_10_3	0xA20A
+#define	cfoe_lf_c2_10_3_pos 0
+#define	cfoe_lf_c2_10_3_len 8
+#define	cfoe_lf_c2_10_3_lsb 3
+#define xd_p_cfoe_lf_c2_18_11	0xA20B
+#define	cfoe_lf_c2_18_11_pos 0
+#define	cfoe_lf_c2_18_11_len 8
+#define	cfoe_lf_c2_18_11_lsb 11
+#define xd_p_cfoe_lf_c2_25_19	0xA20C
+#define	cfoe_lf_c2_25_19_pos 0
+#define	cfoe_lf_c2_25_19_len 7
+#define	cfoe_lf_c2_25_19_lsb 19
+#define xd_p_cfoe_ifod_7_0	0xA20D
+#define	cfoe_ifod_7_0_pos 0
+#define	cfoe_ifod_7_0_len 8
+#define	cfoe_ifod_7_0_lsb 0
+#define xd_p_cfoe_ifod_10_8	0xA20E
+#define	cfoe_ifod_10_8_pos 0
+#define	cfoe_ifod_10_8_len 3
+#define	cfoe_ifod_10_8_lsb 8
+#define xd_p_cfoe_Divg_ctr_th	0xA20E
+#define	cfoe_Divg_ctr_th_pos 4
+#define	cfoe_Divg_ctr_th_len 4
+#define	cfoe_Divg_ctr_th_lsb 0
+#define xd_p_cfoe_FOT_divg_th	0xA20F
+#define	cfoe_FOT_divg_th_pos 0
+#define	cfoe_FOT_divg_th_len 8
+#define	cfoe_FOT_divg_th_lsb 0
+#define xd_p_cfoe_FOT_cnvg_th	0xA210
+#define	cfoe_FOT_cnvg_th_pos 0
+#define	cfoe_FOT_cnvg_th_len 8
+#define	cfoe_FOT_cnvg_th_lsb 0
+#define xd_p_reg_cfoe_offset_7_0	0xA211
+#define	reg_cfoe_offset_7_0_pos 0
+#define	reg_cfoe_offset_7_0_len 8
+#define	reg_cfoe_offset_7_0_lsb 0
+#define xd_p_reg_cfoe_offset_9_8	0xA212
+#define	reg_cfoe_offset_9_8_pos 0
+#define	reg_cfoe_offset_9_8_len 2
+#define	reg_cfoe_offset_9_8_lsb 8
+#define xd_p_reg_cfoe_ifoe_sign_corr	0xA212
+#define	reg_cfoe_ifoe_sign_corr_pos 2
+#define	reg_cfoe_ifoe_sign_corr_len 1
+#define	reg_cfoe_ifoe_sign_corr_lsb 0
+#define xd_r_cfoe_fot_LF_output_7_0	0xA218
+#define	cfoe_fot_LF_output_7_0_pos 0
+#define	cfoe_fot_LF_output_7_0_len 8
+#define	cfoe_fot_LF_output_7_0_lsb 0
+#define xd_r_cfoe_fot_LF_output_15_8	0xA219
+#define	cfoe_fot_LF_output_15_8_pos 0
+#define	cfoe_fot_LF_output_15_8_len 8
+#define	cfoe_fot_LF_output_15_8_lsb 8
+#define xd_r_cfoe_ifo_metric_7_0	0xA21A
+#define	cfoe_ifo_metric_7_0_pos 0
+#define	cfoe_ifo_metric_7_0_len 8
+#define	cfoe_ifo_metric_7_0_lsb 0
+#define xd_r_cfoe_ifo_metric_15_8	0xA21B
+#define	cfoe_ifo_metric_15_8_pos 0
+#define	cfoe_ifo_metric_15_8_len 8
+#define	cfoe_ifo_metric_15_8_lsb 8
+#define xd_r_cfoe_ifo_metric_23_16	0xA21C
+#define	cfoe_ifo_metric_23_16_pos 0
+#define	cfoe_ifo_metric_23_16_len 8
+#define	cfoe_ifo_metric_23_16_lsb 16
+#define xd_p_ste_Nu	0xA220
+#define	ste_Nu_pos 0
+#define	ste_Nu_len 2
+#define	ste_Nu_lsb 0
+#define xd_p_ste_GI	0xA220
+#define	ste_GI_pos 2
+#define	ste_GI_len 3
+#define	ste_GI_lsb 0
+#define xd_p_ste_symbol_num	0xA221
+#define	ste_symbol_num_pos 0
+#define	ste_symbol_num_len 2
+#define	ste_symbol_num_lsb 0
+#define xd_p_ste_sample_num	0xA221
+#define	ste_sample_num_pos 2
+#define	ste_sample_num_len 2
+#define	ste_sample_num_lsb 0
+#define xd_p_reg_ste_buf_en	0xA221
+#define	reg_ste_buf_en_pos 7
+#define	reg_ste_buf_en_len 1
+#define	reg_ste_buf_en_lsb 0
+#define xd_p_ste_FFT_offset_7_0	0xA222
+#define	ste_FFT_offset_7_0_pos 0
+#define	ste_FFT_offset_7_0_len 8
+#define	ste_FFT_offset_7_0_lsb 0
+#define xd_p_ste_FFT_offset_11_8	0xA223
+#define	ste_FFT_offset_11_8_pos 0
+#define	ste_FFT_offset_11_8_len 4
+#define	ste_FFT_offset_11_8_lsb 8
+#define xd_p_reg_ste_tstmod	0xA223
+#define	reg_ste_tstmod_pos 5
+#define	reg_ste_tstmod_len 1
+#define	reg_ste_tstmod_lsb 0
+#define xd_p_ste_adv_start_7_0	0xA224
+#define	ste_adv_start_7_0_pos 0
+#define	ste_adv_start_7_0_len 8
+#define	ste_adv_start_7_0_lsb 0
+#define xd_p_ste_adv_start_10_8	0xA225
+#define	ste_adv_start_10_8_pos 0
+#define	ste_adv_start_10_8_len 3
+#define	ste_adv_start_10_8_lsb 8
+#define xd_p_ste_adv_stop	0xA226
+#define	ste_adv_stop_pos 0
+#define	ste_adv_stop_len 8
+#define	ste_adv_stop_lsb 0
+#define xd_r_ste_P_value_7_0	0xA228
+#define	ste_P_value_7_0_pos 0
+#define	ste_P_value_7_0_len 8
+#define	ste_P_value_7_0_lsb 0
+#define xd_r_ste_P_value_10_8	0xA229
+#define	ste_P_value_10_8_pos 0
+#define	ste_P_value_10_8_len 3
+#define	ste_P_value_10_8_lsb 8
+#define xd_r_ste_M_value_7_0	0xA22A
+#define	ste_M_value_7_0_pos 0
+#define	ste_M_value_7_0_len 8
+#define	ste_M_value_7_0_lsb 0
+#define xd_r_ste_M_value_10_8	0xA22B
+#define	ste_M_value_10_8_pos 0
+#define	ste_M_value_10_8_len 3
+#define	ste_M_value_10_8_lsb 8
+#define xd_r_ste_H1	0xA22C
+#define	ste_H1_pos 0
+#define	ste_H1_len 7
+#define	ste_H1_lsb 0
+#define xd_r_ste_H2	0xA22D
+#define	ste_H2_pos 0
+#define	ste_H2_len 7
+#define	ste_H2_lsb 0
+#define xd_r_ste_H3	0xA22E
+#define	ste_H3_pos 0
+#define	ste_H3_len 7
+#define	ste_H3_lsb 0
+#define xd_r_ste_H4	0xA22F
+#define	ste_H4_pos 0
+#define	ste_H4_len 7
+#define	ste_H4_lsb 0
+#define xd_r_ste_Corr_value_I_7_0	0xA230
+#define	ste_Corr_value_I_7_0_pos 0
+#define	ste_Corr_value_I_7_0_len 8
+#define	ste_Corr_value_I_7_0_lsb 0
+#define xd_r_ste_Corr_value_I_15_8	0xA231
+#define	ste_Corr_value_I_15_8_pos 0
+#define	ste_Corr_value_I_15_8_len 8
+#define	ste_Corr_value_I_15_8_lsb 8
+#define xd_r_ste_Corr_value_I_23_16	0xA232
+#define	ste_Corr_value_I_23_16_pos 0
+#define	ste_Corr_value_I_23_16_len 8
+#define	ste_Corr_value_I_23_16_lsb 16
+#define xd_r_ste_Corr_value_I_27_24	0xA233
+#define	ste_Corr_value_I_27_24_pos 0
+#define	ste_Corr_value_I_27_24_len 4
+#define	ste_Corr_value_I_27_24_lsb 24
+#define xd_r_ste_Corr_value_Q_7_0	0xA234
+#define	ste_Corr_value_Q_7_0_pos 0
+#define	ste_Corr_value_Q_7_0_len 8
+#define	ste_Corr_value_Q_7_0_lsb 0
+#define xd_r_ste_Corr_value_Q_15_8	0xA235
+#define	ste_Corr_value_Q_15_8_pos 0
+#define	ste_Corr_value_Q_15_8_len 8
+#define	ste_Corr_value_Q_15_8_lsb 8
+#define xd_r_ste_Corr_value_Q_23_16	0xA236
+#define	ste_Corr_value_Q_23_16_pos 0
+#define	ste_Corr_value_Q_23_16_len 8
+#define	ste_Corr_value_Q_23_16_lsb 16
+#define xd_r_ste_Corr_value_Q_27_24	0xA237
+#define	ste_Corr_value_Q_27_24_pos 0
+#define	ste_Corr_value_Q_27_24_len 4
+#define	ste_Corr_value_Q_27_24_lsb 24
+#define xd_r_ste_J_num_7_0	0xA238
+#define	ste_J_num_7_0_pos 0
+#define	ste_J_num_7_0_len 8
+#define	ste_J_num_7_0_lsb 0
+#define xd_r_ste_J_num_15_8	0xA239
+#define	ste_J_num_15_8_pos 0
+#define	ste_J_num_15_8_len 8
+#define	ste_J_num_15_8_lsb 8
+#define xd_r_ste_J_num_23_16	0xA23A
+#define	ste_J_num_23_16_pos 0
+#define	ste_J_num_23_16_len 8
+#define	ste_J_num_23_16_lsb 16
+#define xd_r_ste_J_num_31_24	0xA23B
+#define	ste_J_num_31_24_pos 0
+#define	ste_J_num_31_24_len 8
+#define	ste_J_num_31_24_lsb 24
+#define xd_r_ste_J_den_7_0	0xA23C
+#define	ste_J_den_7_0_pos 0
+#define	ste_J_den_7_0_len 8
+#define	ste_J_den_7_0_lsb 0
+#define xd_r_ste_J_den_15_8	0xA23D
+#define	ste_J_den_15_8_pos 0
+#define	ste_J_den_15_8_len 8
+#define	ste_J_den_15_8_lsb 8
+#define xd_r_ste_J_den_18_16	0xA23E
+#define	ste_J_den_18_16_pos 0
+#define	ste_J_den_18_16_len 3
+#define	ste_J_den_18_16_lsb 16
+#define xd_r_ste_Beacon_Indicator	0xA23E
+#define	ste_Beacon_Indicator_pos 4
+#define	ste_Beacon_Indicator_len 1
+#define	ste_Beacon_Indicator_lsb 0
+#define xd_r_tpsd_Frame_Num	0xA250
+#define	tpsd_Frame_Num_pos 0
+#define	tpsd_Frame_Num_len 2
+#define	tpsd_Frame_Num_lsb 0
+#define xd_r_tpsd_Constel	0xA250
+#define	tpsd_Constel_pos 2
+#define	tpsd_Constel_len 2
+#define	tpsd_Constel_lsb 0
+#define xd_r_tpsd_GI	0xA250
+#define	tpsd_GI_pos 4
+#define	tpsd_GI_len 2
+#define	tpsd_GI_lsb 0
+#define xd_r_tpsd_Mode	0xA250
+#define	tpsd_Mode_pos 6
+#define	tpsd_Mode_len 2
+#define	tpsd_Mode_lsb 0
+#define xd_r_tpsd_CR_HP	0xA251
+#define	tpsd_CR_HP_pos 0
+#define	tpsd_CR_HP_len 3
+#define	tpsd_CR_HP_lsb 0
+#define xd_r_tpsd_CR_LP	0xA251
+#define	tpsd_CR_LP_pos 3
+#define	tpsd_CR_LP_len 3
+#define	tpsd_CR_LP_lsb 0
+#define xd_r_tpsd_Hie	0xA252
+#define	tpsd_Hie_pos 0
+#define	tpsd_Hie_len 3
+#define	tpsd_Hie_lsb 0
+#define xd_r_tpsd_Res_Bits	0xA252
+#define	tpsd_Res_Bits_pos 3
+#define	tpsd_Res_Bits_len 5
+#define	tpsd_Res_Bits_lsb 0
+#define xd_r_tpsd_Res_Bits_0	0xA253
+#define	tpsd_Res_Bits_0_pos 0
+#define	tpsd_Res_Bits_0_len 1
+#define	tpsd_Res_Bits_0_lsb 0
+#define xd_r_tpsd_LengthInd	0xA253
+#define	tpsd_LengthInd_pos 1
+#define	tpsd_LengthInd_len 6
+#define	tpsd_LengthInd_lsb 0
+#define xd_r_tpsd_Cell_Id_7_0	0xA254
+#define	tpsd_Cell_Id_7_0_pos 0
+#define	tpsd_Cell_Id_7_0_len 8
+#define	tpsd_Cell_Id_7_0_lsb 0
+#define xd_r_tpsd_Cell_Id_15_8	0xA255
+#define	tpsd_Cell_Id_15_8_pos 0
+#define	tpsd_Cell_Id_15_8_len 8
+#define	tpsd_Cell_Id_15_8_lsb 0
+#define xd_p_reg_fft_mask_tone0_7_0	0xA260
+#define	reg_fft_mask_tone0_7_0_pos 0
+#define	reg_fft_mask_tone0_7_0_len 8
+#define	reg_fft_mask_tone0_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone0_12_8	0xA261
+#define	reg_fft_mask_tone0_12_8_pos 0
+#define	reg_fft_mask_tone0_12_8_len 5
+#define	reg_fft_mask_tone0_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone1_7_0	0xA262
+#define	reg_fft_mask_tone1_7_0_pos 0
+#define	reg_fft_mask_tone1_7_0_len 8
+#define	reg_fft_mask_tone1_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone1_12_8	0xA263
+#define	reg_fft_mask_tone1_12_8_pos 0
+#define	reg_fft_mask_tone1_12_8_len 5
+#define	reg_fft_mask_tone1_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone2_7_0	0xA264
+#define	reg_fft_mask_tone2_7_0_pos 0
+#define	reg_fft_mask_tone2_7_0_len 8
+#define	reg_fft_mask_tone2_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone2_12_8	0xA265
+#define	reg_fft_mask_tone2_12_8_pos 0
+#define	reg_fft_mask_tone2_12_8_len 5
+#define	reg_fft_mask_tone2_12_8_lsb 8
+#define xd_p_reg_fft_mask_tone3_7_0	0xA266
+#define	reg_fft_mask_tone3_7_0_pos 0
+#define	reg_fft_mask_tone3_7_0_len 8
+#define	reg_fft_mask_tone3_7_0_lsb 0
+#define xd_p_reg_fft_mask_tone3_12_8	0xA267
+#define	reg_fft_mask_tone3_12_8_pos 0
+#define	reg_fft_mask_tone3_12_8_len 5
+#define	reg_fft_mask_tone3_12_8_lsb 8
+#define xd_p_reg_fft_mask_from0_7_0	0xA268
+#define	reg_fft_mask_from0_7_0_pos 0
+#define	reg_fft_mask_from0_7_0_len 8
+#define	reg_fft_mask_from0_7_0_lsb 0
+#define xd_p_reg_fft_mask_from0_12_8	0xA269
+#define	reg_fft_mask_from0_12_8_pos 0
+#define	reg_fft_mask_from0_12_8_len 5
+#define	reg_fft_mask_from0_12_8_lsb 8
+#define xd_p_reg_fft_mask_to0_7_0	0xA26A
+#define	reg_fft_mask_to0_7_0_pos 0
+#define	reg_fft_mask_to0_7_0_len 8
+#define	reg_fft_mask_to0_7_0_lsb 0
+#define xd_p_reg_fft_mask_to0_12_8	0xA26B
+#define	reg_fft_mask_to0_12_8_pos 0
+#define	reg_fft_mask_to0_12_8_len 5
+#define	reg_fft_mask_to0_12_8_lsb 8
+#define xd_p_reg_fft_mask_from1_7_0	0xA26C
+#define	reg_fft_mask_from1_7_0_pos 0
+#define	reg_fft_mask_from1_7_0_len 8
+#define	reg_fft_mask_from1_7_0_lsb 0
+#define xd_p_reg_fft_mask_from1_12_8	0xA26D
+#define	reg_fft_mask_from1_12_8_pos 0
+#define	reg_fft_mask_from1_12_8_len 5
+#define	reg_fft_mask_from1_12_8_lsb 8
+#define xd_p_reg_fft_mask_to1_7_0	0xA26E
+#define	reg_fft_mask_to1_7_0_pos 0
+#define	reg_fft_mask_to1_7_0_len 8
+#define	reg_fft_mask_to1_7_0_lsb 0
+#define xd_p_reg_fft_mask_to1_12_8	0xA26F
+#define	reg_fft_mask_to1_12_8_pos 0
+#define	reg_fft_mask_to1_12_8_len 5
+#define	reg_fft_mask_to1_12_8_lsb 8
+#define xd_p_reg_cge_idx0_7_0	0xA280
+#define	reg_cge_idx0_7_0_pos 0
+#define	reg_cge_idx0_7_0_len 8
+#define	reg_cge_idx0_7_0_lsb 0
+#define xd_p_reg_cge_idx0_12_8	0xA281
+#define	reg_cge_idx0_12_8_pos 0
+#define	reg_cge_idx0_12_8_len 5
+#define	reg_cge_idx0_12_8_lsb 8
+#define xd_p_reg_cge_idx1_7_0	0xA282
+#define	reg_cge_idx1_7_0_pos 0
+#define	reg_cge_idx1_7_0_len 8
+#define	reg_cge_idx1_7_0_lsb 0
+#define xd_p_reg_cge_idx1_12_8	0xA283
+#define	reg_cge_idx1_12_8_pos 0
+#define	reg_cge_idx1_12_8_len 5
+#define	reg_cge_idx1_12_8_lsb 8
+#define xd_p_reg_cge_idx2_7_0	0xA284
+#define	reg_cge_idx2_7_0_pos 0
+#define	reg_cge_idx2_7_0_len 8
+#define	reg_cge_idx2_7_0_lsb 0
+#define xd_p_reg_cge_idx2_12_8	0xA285
+#define	reg_cge_idx2_12_8_pos 0
+#define	reg_cge_idx2_12_8_len 5
+#define	reg_cge_idx2_12_8_lsb 8
+#define xd_p_reg_cge_idx3_7_0	0xA286
+#define	reg_cge_idx3_7_0_pos 0
+#define	reg_cge_idx3_7_0_len 8
+#define	reg_cge_idx3_7_0_lsb 0
+#define xd_p_reg_cge_idx3_12_8	0xA287
+#define	reg_cge_idx3_12_8_pos 0
+#define	reg_cge_idx3_12_8_len 5
+#define	reg_cge_idx3_12_8_lsb 8
+#define xd_p_reg_cge_idx4_7_0	0xA288
+#define	reg_cge_idx4_7_0_pos 0
+#define	reg_cge_idx4_7_0_len 8
+#define	reg_cge_idx4_7_0_lsb 0
+#define xd_p_reg_cge_idx4_12_8	0xA289
+#define	reg_cge_idx4_12_8_pos 0
+#define	reg_cge_idx4_12_8_len 5
+#define	reg_cge_idx4_12_8_lsb 8
+#define xd_p_reg_cge_idx5_7_0	0xA28A
+#define	reg_cge_idx5_7_0_pos 0
+#define	reg_cge_idx5_7_0_len 8
+#define	reg_cge_idx5_7_0_lsb 0
+#define xd_p_reg_cge_idx5_12_8	0xA28B
+#define	reg_cge_idx5_12_8_pos 0
+#define	reg_cge_idx5_12_8_len 5
+#define	reg_cge_idx5_12_8_lsb 8
+#define xd_p_reg_cge_idx6_7_0	0xA28C
+#define	reg_cge_idx6_7_0_pos 0
+#define	reg_cge_idx6_7_0_len 8
+#define	reg_cge_idx6_7_0_lsb 0
+#define xd_p_reg_cge_idx6_12_8	0xA28D
+#define	reg_cge_idx6_12_8_pos 0
+#define	reg_cge_idx6_12_8_len 5
+#define	reg_cge_idx6_12_8_lsb 8
+#define xd_p_reg_cge_idx7_7_0	0xA28E
+#define	reg_cge_idx7_7_0_pos 0
+#define	reg_cge_idx7_7_0_len 8
+#define	reg_cge_idx7_7_0_lsb 0
+#define xd_p_reg_cge_idx7_12_8	0xA28F
+#define	reg_cge_idx7_12_8_pos 0
+#define	reg_cge_idx7_12_8_len 5
+#define	reg_cge_idx7_12_8_lsb 8
+#define xd_p_reg_cge_idx8_7_0	0xA290
+#define	reg_cge_idx8_7_0_pos 0
+#define	reg_cge_idx8_7_0_len 8
+#define	reg_cge_idx8_7_0_lsb 0
+#define xd_p_reg_cge_idx8_12_8	0xA291
+#define	reg_cge_idx8_12_8_pos 0
+#define	reg_cge_idx8_12_8_len 5
+#define	reg_cge_idx8_12_8_lsb 8
+#define xd_p_reg_cge_idx9_7_0	0xA292
+#define	reg_cge_idx9_7_0_pos 0
+#define	reg_cge_idx9_7_0_len 8
+#define	reg_cge_idx9_7_0_lsb 0
+#define xd_p_reg_cge_idx9_12_8	0xA293
+#define	reg_cge_idx9_12_8_pos 0
+#define	reg_cge_idx9_12_8_len 5
+#define	reg_cge_idx9_12_8_lsb 8
+#define xd_p_reg_cge_idx10_7_0	0xA294
+#define	reg_cge_idx10_7_0_pos 0
+#define	reg_cge_idx10_7_0_len 8
+#define	reg_cge_idx10_7_0_lsb 0
+#define xd_p_reg_cge_idx10_12_8	0xA295
+#define	reg_cge_idx10_12_8_pos 0
+#define	reg_cge_idx10_12_8_len 5
+#define	reg_cge_idx10_12_8_lsb 8
+#define xd_p_reg_cge_idx11_7_0	0xA296
+#define	reg_cge_idx11_7_0_pos 0
+#define	reg_cge_idx11_7_0_len 8
+#define	reg_cge_idx11_7_0_lsb 0
+#define xd_p_reg_cge_idx11_12_8	0xA297
+#define	reg_cge_idx11_12_8_pos 0
+#define	reg_cge_idx11_12_8_len 5
+#define	reg_cge_idx11_12_8_lsb 8
+#define xd_p_reg_cge_idx12_7_0	0xA298
+#define	reg_cge_idx12_7_0_pos 0
+#define	reg_cge_idx12_7_0_len 8
+#define	reg_cge_idx12_7_0_lsb 0
+#define xd_p_reg_cge_idx12_12_8	0xA299
+#define	reg_cge_idx12_12_8_pos 0
+#define	reg_cge_idx12_12_8_len 5
+#define	reg_cge_idx12_12_8_lsb 8
+#define xd_p_reg_cge_idx13_7_0	0xA29A
+#define	reg_cge_idx13_7_0_pos 0
+#define	reg_cge_idx13_7_0_len 8
+#define	reg_cge_idx13_7_0_lsb 0
+#define xd_p_reg_cge_idx13_12_8	0xA29B
+#define	reg_cge_idx13_12_8_pos 0
+#define	reg_cge_idx13_12_8_len 5
+#define	reg_cge_idx13_12_8_lsb 8
+#define xd_p_reg_cge_idx14_7_0	0xA29C
+#define	reg_cge_idx14_7_0_pos 0
+#define	reg_cge_idx14_7_0_len 8
+#define	reg_cge_idx14_7_0_lsb 0
+#define xd_p_reg_cge_idx14_12_8	0xA29D
+#define	reg_cge_idx14_12_8_pos 0
+#define	reg_cge_idx14_12_8_len 5
+#define	reg_cge_idx14_12_8_lsb 8
+#define xd_p_reg_cge_idx15_7_0	0xA29E
+#define	reg_cge_idx15_7_0_pos 0
+#define	reg_cge_idx15_7_0_len 8
+#define	reg_cge_idx15_7_0_lsb 0
+#define xd_p_reg_cge_idx15_12_8	0xA29F
+#define	reg_cge_idx15_12_8_pos 0
+#define	reg_cge_idx15_12_8_len 5
+#define	reg_cge_idx15_12_8_lsb 8
+#define xd_r_reg_fft_crc	0xA2A8
+#define	reg_fft_crc_pos 0
+#define	reg_fft_crc_len 8
+#define	reg_fft_crc_lsb 0
+#define xd_p_fd_fft_shift_max	0xA2A9
+#define	fd_fft_shift_max_pos 0
+#define	fd_fft_shift_max_len 4
+#define	fd_fft_shift_max_lsb 0
+#define xd_r_fd_fft_shift	0xA2A9
+#define	fd_fft_shift_pos 4
+#define	fd_fft_shift_len 4
+#define	fd_fft_shift_lsb 0
+#define xd_r_fd_fft_frame_num	0xA2AA
+#define	fd_fft_frame_num_pos 0
+#define	fd_fft_frame_num_len 2
+#define	fd_fft_frame_num_lsb 0
+#define xd_r_fd_fft_symbol_count	0xA2AB
+#define	fd_fft_symbol_count_pos 0
+#define	fd_fft_symbol_count_len 7
+#define	fd_fft_symbol_count_lsb 0
+#define xd_r_reg_fft_idx_max_7_0	0xA2AC
+#define	reg_fft_idx_max_7_0_pos 0
+#define	reg_fft_idx_max_7_0_len 8
+#define	reg_fft_idx_max_7_0_lsb 0
+#define xd_r_reg_fft_idx_max_12_8	0xA2AD
+#define	reg_fft_idx_max_12_8_pos 0
+#define	reg_fft_idx_max_12_8_len 5
+#define	reg_fft_idx_max_12_8_lsb 8
+#define xd_p_reg_cge_program	0xA2AE
+#define	reg_cge_program_pos 0
+#define	reg_cge_program_len 1
+#define	reg_cge_program_lsb 0
+#define xd_p_reg_cge_fixed	0xA2AE
+#define	reg_cge_fixed_pos 1
+#define	reg_cge_fixed_len 1
+#define	reg_cge_fixed_lsb 0
+#define xd_p_reg_fft_rotate_en	0xA2AE
+#define	reg_fft_rotate_en_pos 2
+#define	reg_fft_rotate_en_len 1
+#define	reg_fft_rotate_en_lsb 0
+#define xd_p_reg_fft_rotate_base_4_0	0xA2AE
+#define	reg_fft_rotate_base_4_0_pos 3
+#define	reg_fft_rotate_base_4_0_len 5
+#define	reg_fft_rotate_base_4_0_lsb 0
+#define xd_p_reg_fft_rotate_base_12_5	0xA2AF
+#define	reg_fft_rotate_base_12_5_pos 0
+#define	reg_fft_rotate_base_12_5_len 8
+#define	reg_fft_rotate_base_12_5_lsb 5
+#define xd_p_reg_gp_trigger_fd	0xA2B8
+#define	reg_gp_trigger_fd_pos 0
+#define	reg_gp_trigger_fd_len 1
+#define	reg_gp_trigger_fd_lsb 0
+#define xd_p_reg_trigger_sel_fd	0xA2B8
+#define	reg_trigger_sel_fd_pos 1
+#define	reg_trigger_sel_fd_len 2
+#define	reg_trigger_sel_fd_lsb 0
+#define xd_p_reg_trigger_module_sel_fd	0xA2B9
+#define	reg_trigger_module_sel_fd_pos 0
+#define	reg_trigger_module_sel_fd_len 6
+#define	reg_trigger_module_sel_fd_lsb 0
+#define xd_p_reg_trigger_set_sel_fd	0xA2BA
+#define	reg_trigger_set_sel_fd_pos 0
+#define	reg_trigger_set_sel_fd_len 6
+#define	reg_trigger_set_sel_fd_lsb 0
+#define xd_p_reg_fd_noname_7_0	0xA2BC
+#define	reg_fd_noname_7_0_pos 0
+#define	reg_fd_noname_7_0_len 8
+#define	reg_fd_noname_7_0_lsb 0
+#define xd_p_reg_fd_noname_15_8	0xA2BD
+#define	reg_fd_noname_15_8_pos 0
+#define	reg_fd_noname_15_8_len 8
+#define	reg_fd_noname_15_8_lsb 8
+#define xd_p_reg_fd_noname_23_16	0xA2BE
+#define	reg_fd_noname_23_16_pos 0
+#define	reg_fd_noname_23_16_len 8
+#define	reg_fd_noname_23_16_lsb 16
+#define xd_p_reg_fd_noname_31_24	0xA2BF
+#define	reg_fd_noname_31_24_pos 0
+#define	reg_fd_noname_31_24_len 8
+#define	reg_fd_noname_31_24_lsb 24
+#define xd_r_fd_fpcc_cp_corr_signn	0xA2C0
+#define	fd_fpcc_cp_corr_signn_pos 0
+#define	fd_fpcc_cp_corr_signn_len 8
+#define	fd_fpcc_cp_corr_signn_lsb 0
+#define xd_p_reg_feq_s1	0xA2C1
+#define	reg_feq_s1_pos 0
+#define	reg_feq_s1_len 5
+#define	reg_feq_s1_lsb 0
+#define xd_p_fd_fpcc_cp_corr_tone_th	0xA2C2
+#define	fd_fpcc_cp_corr_tone_th_pos 0
+#define	fd_fpcc_cp_corr_tone_th_len 6
+#define	fd_fpcc_cp_corr_tone_th_lsb 0
+#define xd_p_fd_fpcc_cp_corr_symbol_log_th	0xA2C3
+#define	fd_fpcc_cp_corr_symbol_log_th_pos 0
+#define	fd_fpcc_cp_corr_symbol_log_th_len 4
+#define	fd_fpcc_cp_corr_symbol_log_th_lsb 0
+#define xd_p_fd_fpcc_cp_corr_int	0xA2C4
+#define	fd_fpcc_cp_corr_int_pos 0
+#define	fd_fpcc_cp_corr_int_len 1
+#define	fd_fpcc_cp_corr_int_lsb 0
+#define xd_p_reg_sfoe_ns_7_0	0xA320
+#define	reg_sfoe_ns_7_0_pos 0
+#define	reg_sfoe_ns_7_0_len 8
+#define	reg_sfoe_ns_7_0_lsb 0
+#define xd_p_reg_sfoe_ns_14_8	0xA321
+#define	reg_sfoe_ns_14_8_pos 0
+#define	reg_sfoe_ns_14_8_len 7
+#define	reg_sfoe_ns_14_8_lsb 8
+#define xd_p_reg_sfoe_c1_7_0	0xA322
+#define	reg_sfoe_c1_7_0_pos 0
+#define	reg_sfoe_c1_7_0_len 8
+#define	reg_sfoe_c1_7_0_lsb 0
+#define xd_p_reg_sfoe_c1_15_8	0xA323
+#define	reg_sfoe_c1_15_8_pos 0
+#define	reg_sfoe_c1_15_8_len 8
+#define	reg_sfoe_c1_15_8_lsb 8
+#define xd_p_reg_sfoe_c1_17_16	0xA324
+#define	reg_sfoe_c1_17_16_pos 0
+#define	reg_sfoe_c1_17_16_len 2
+#define	reg_sfoe_c1_17_16_lsb 16
+#define xd_p_reg_sfoe_c2_7_0	0xA325
+#define	reg_sfoe_c2_7_0_pos 0
+#define	reg_sfoe_c2_7_0_len 8
+#define	reg_sfoe_c2_7_0_lsb 0
+#define xd_p_reg_sfoe_c2_15_8	0xA326
+#define	reg_sfoe_c2_15_8_pos 0
+#define	reg_sfoe_c2_15_8_len 8
+#define	reg_sfoe_c2_15_8_lsb 8
+#define xd_p_reg_sfoe_c2_17_16	0xA327
+#define	reg_sfoe_c2_17_16_pos 0
+#define	reg_sfoe_c2_17_16_len 2
+#define	reg_sfoe_c2_17_16_lsb 16
+#define xd_r_reg_sfoe_out_9_2	0xA328
+#define	reg_sfoe_out_9_2_pos 0
+#define	reg_sfoe_out_9_2_len 8
+#define	reg_sfoe_out_9_2_lsb 0
+#define xd_r_reg_sfoe_out_1_0	0xA329
+#define	reg_sfoe_out_1_0_pos 0
+#define	reg_sfoe_out_1_0_len 2
+#define	reg_sfoe_out_1_0_lsb 0
+#define xd_p_reg_sfoe_lm_counter_th	0xA32A
+#define	reg_sfoe_lm_counter_th_pos 0
+#define	reg_sfoe_lm_counter_th_len 4
+#define	reg_sfoe_lm_counter_th_lsb 0
+#define xd_p_reg_sfoe_convg_th	0xA32B
+#define	reg_sfoe_convg_th_pos 0
+#define	reg_sfoe_convg_th_len 8
+#define	reg_sfoe_convg_th_lsb 0
+#define xd_p_reg_sfoe_divg_th	0xA32C
+#define	reg_sfoe_divg_th_pos 0
+#define	reg_sfoe_divg_th_len 8
+#define	reg_sfoe_divg_th_lsb 0
+#define xd_p_fd_tpsd_en	0xA330
+#define	fd_tpsd_en_pos 0
+#define	fd_tpsd_en_len 1
+#define	fd_tpsd_en_lsb 0
+#define xd_p_fd_tpsd_dis	0xA330
+#define	fd_tpsd_dis_pos 1
+#define	fd_tpsd_dis_len 1
+#define	fd_tpsd_dis_lsb 0
+#define xd_p_fd_tpsd_rst	0xA330
+#define	fd_tpsd_rst_pos 2
+#define	fd_tpsd_rst_len 1
+#define	fd_tpsd_rst_lsb 0
+#define xd_p_fd_tpsd_lock	0xA330
+#define	fd_tpsd_lock_pos 3
+#define	fd_tpsd_lock_len 1
+#define	fd_tpsd_lock_lsb 0
+#define xd_r_fd_tpsd_s19	0xA330
+#define	fd_tpsd_s19_pos 4
+#define	fd_tpsd_s19_len 1
+#define	fd_tpsd_s19_lsb 0
+#define xd_r_fd_tpsd_s17	0xA330
+#define	fd_tpsd_s17_pos 5
+#define	fd_tpsd_s17_len 1
+#define	fd_tpsd_s17_lsb 0
+#define xd_p_fd_sfr_ste_en	0xA331
+#define	fd_sfr_ste_en_pos 0
+#define	fd_sfr_ste_en_len 1
+#define	fd_sfr_ste_en_lsb 0
+#define xd_p_fd_sfr_ste_dis	0xA331
+#define	fd_sfr_ste_dis_pos 1
+#define	fd_sfr_ste_dis_len 1
+#define	fd_sfr_ste_dis_lsb 0
+#define xd_p_fd_sfr_ste_rst	0xA331
+#define	fd_sfr_ste_rst_pos 2
+#define	fd_sfr_ste_rst_len 1
+#define	fd_sfr_ste_rst_lsb 0
+#define xd_p_fd_sfr_ste_mode	0xA331
+#define	fd_sfr_ste_mode_pos 3
+#define	fd_sfr_ste_mode_len 1
+#define	fd_sfr_ste_mode_lsb 0
+#define xd_p_fd_sfr_ste_done	0xA331
+#define	fd_sfr_ste_done_pos 4
+#define	fd_sfr_ste_done_len 1
+#define	fd_sfr_ste_done_lsb 0
+#define xd_p_reg_cfoe_ffoe_en	0xA332
+#define	reg_cfoe_ffoe_en_pos 0
+#define	reg_cfoe_ffoe_en_len 1
+#define	reg_cfoe_ffoe_en_lsb 0
+#define xd_p_reg_cfoe_ffoe_dis	0xA332
+#define	reg_cfoe_ffoe_dis_pos 1
+#define	reg_cfoe_ffoe_dis_len 1
+#define	reg_cfoe_ffoe_dis_lsb 0
+#define xd_p_reg_cfoe_ffoe_rst	0xA332
+#define	reg_cfoe_ffoe_rst_pos 2
+#define	reg_cfoe_ffoe_rst_len 1
+#define	reg_cfoe_ffoe_rst_lsb 0
+#define xd_p_reg_cfoe_ifoe_en	0xA332
+#define	reg_cfoe_ifoe_en_pos 3
+#define	reg_cfoe_ifoe_en_len 1
+#define	reg_cfoe_ifoe_en_lsb 0
+#define xd_p_reg_cfoe_ifoe_dis	0xA332
+#define	reg_cfoe_ifoe_dis_pos 4
+#define	reg_cfoe_ifoe_dis_len 1
+#define	reg_cfoe_ifoe_dis_lsb 0
+#define xd_p_reg_cfoe_ifoe_rst	0xA332
+#define	reg_cfoe_ifoe_rst_pos 5
+#define	reg_cfoe_ifoe_rst_len 1
+#define	reg_cfoe_ifoe_rst_lsb 0
+#define xd_p_reg_cfoe_fot_en	0xA332
+#define	reg_cfoe_fot_en_pos 6
+#define	reg_cfoe_fot_en_len 1
+#define	reg_cfoe_fot_en_lsb 0
+#define xd_p_reg_cfoe_fot_lm_en	0xA332
+#define	reg_cfoe_fot_lm_en_pos 7
+#define	reg_cfoe_fot_lm_en_len 1
+#define	reg_cfoe_fot_lm_en_lsb 0
+#define xd_p_reg_cfoe_fot_rst	0xA333
+#define	reg_cfoe_fot_rst_pos 0
+#define	reg_cfoe_fot_rst_len 1
+#define	reg_cfoe_fot_rst_lsb 0
+#define xd_r_fd_cfoe_ffoe_done	0xA333
+#define	fd_cfoe_ffoe_done_pos 1
+#define	fd_cfoe_ffoe_done_len 1
+#define	fd_cfoe_ffoe_done_lsb 0
+#define xd_p_fd_cfoe_metric_vld	0xA333
+#define	fd_cfoe_metric_vld_pos 2
+#define	fd_cfoe_metric_vld_len 1
+#define	fd_cfoe_metric_vld_lsb 0
+#define xd_p_reg_cfoe_ifod_vld	0xA333
+#define	reg_cfoe_ifod_vld_pos 3
+#define	reg_cfoe_ifod_vld_len 1
+#define	reg_cfoe_ifod_vld_lsb 0
+#define xd_r_fd_cfoe_ifoe_done	0xA333
+#define	fd_cfoe_ifoe_done_pos 4
+#define	fd_cfoe_ifoe_done_len 1
+#define	fd_cfoe_ifoe_done_lsb 0
+#define xd_r_fd_cfoe_fot_valid	0xA333
+#define	fd_cfoe_fot_valid_pos 5
+#define	fd_cfoe_fot_valid_len 1
+#define	fd_cfoe_fot_valid_lsb 0
+#define xd_p_reg_cfoe_divg_int	0xA333
+#define	reg_cfoe_divg_int_pos 6
+#define	reg_cfoe_divg_int_len 1
+#define	reg_cfoe_divg_int_lsb 0
+#define xd_r_reg_cfoe_divg_flag	0xA333
+#define	reg_cfoe_divg_flag_pos 7
+#define	reg_cfoe_divg_flag_len 1
+#define	reg_cfoe_divg_flag_lsb 0
+#define xd_p_reg_sfoe_en	0xA334
+#define	reg_sfoe_en_pos 0
+#define	reg_sfoe_en_len 1
+#define	reg_sfoe_en_lsb 0
+#define xd_p_reg_sfoe_dis	0xA334
+#define	reg_sfoe_dis_pos 1
+#define	reg_sfoe_dis_len 1
+#define	reg_sfoe_dis_lsb 0
+#define xd_p_reg_sfoe_rst	0xA334
+#define	reg_sfoe_rst_pos 2
+#define	reg_sfoe_rst_len 1
+#define	reg_sfoe_rst_lsb 0
+#define xd_p_reg_sfoe_vld_int	0xA334
+#define	reg_sfoe_vld_int_pos 3
+#define	reg_sfoe_vld_int_len 1
+#define	reg_sfoe_vld_int_lsb 0
+#define xd_p_reg_sfoe_lm_en	0xA334
+#define	reg_sfoe_lm_en_pos 4
+#define	reg_sfoe_lm_en_len 1
+#define	reg_sfoe_lm_en_lsb 0
+#define xd_p_reg_sfoe_divg_int	0xA334
+#define	reg_sfoe_divg_int_pos 5
+#define	reg_sfoe_divg_int_len 1
+#define	reg_sfoe_divg_int_lsb 0
+#define xd_r_reg_sfoe_divg_flag	0xA334
+#define	reg_sfoe_divg_flag_pos 6
+#define	reg_sfoe_divg_flag_len 1
+#define	reg_sfoe_divg_flag_lsb 0
+#define xd_p_reg_fft_rst	0xA335
+#define	reg_fft_rst_pos 0
+#define	reg_fft_rst_len 1
+#define	reg_fft_rst_lsb 0
+#define xd_p_reg_fft_fast_beacon	0xA335
+#define	reg_fft_fast_beacon_pos 1
+#define	reg_fft_fast_beacon_len 1
+#define	reg_fft_fast_beacon_lsb 0
+#define xd_p_reg_fft_fast_valid	0xA335
+#define	reg_fft_fast_valid_pos 2
+#define	reg_fft_fast_valid_len 1
+#define	reg_fft_fast_valid_lsb 0
+#define xd_p_reg_fft_mask_en	0xA335
+#define	reg_fft_mask_en_pos 3
+#define	reg_fft_mask_en_len 1
+#define	reg_fft_mask_en_lsb 0
+#define xd_p_reg_fft_crc_en	0xA335
+#define	reg_fft_crc_en_pos 4
+#define	reg_fft_crc_en_len 1
+#define	reg_fft_crc_en_lsb 0
+#define xd_p_reg_finr_en	0xA336
+#define	reg_finr_en_pos 0
+#define	reg_finr_en_len 1
+#define	reg_finr_en_lsb 0
+#define xd_p_fd_fste_en	0xA337
+#define	fd_fste_en_pos 1
+#define	fd_fste_en_len 1
+#define	fd_fste_en_lsb 0
+#define xd_p_fd_sqi_tps_level_shift	0xA338
+#define	fd_sqi_tps_level_shift_pos 0
+#define	fd_sqi_tps_level_shift_len 8
+#define	fd_sqi_tps_level_shift_lsb 0
+#define xd_p_fd_pilot_ma_len	0xA339
+#define	fd_pilot_ma_len_pos 0
+#define	fd_pilot_ma_len_len 6
+#define	fd_pilot_ma_len_lsb 0
+#define xd_p_fd_tps_ma_len	0xA33A
+#define	fd_tps_ma_len_pos 0
+#define	fd_tps_ma_len_len 6
+#define	fd_tps_ma_len_lsb 0
+#define xd_p_fd_sqi_s3	0xA33B
+#define	fd_sqi_s3_pos 0
+#define	fd_sqi_s3_len 8
+#define	fd_sqi_s3_lsb 0
+#define xd_p_fd_sqi_dummy_reg_0	0xA33C
+#define	fd_sqi_dummy_reg_0_pos 0
+#define	fd_sqi_dummy_reg_0_len 1
+#define	fd_sqi_dummy_reg_0_lsb 0
+#define xd_p_fd_sqi_debug_sel	0xA33C
+#define	fd_sqi_debug_sel_pos 1
+#define	fd_sqi_debug_sel_len 2
+#define	fd_sqi_debug_sel_lsb 0
+#define xd_p_fd_sqi_s2	0xA33C
+#define	fd_sqi_s2_pos 3
+#define	fd_sqi_s2_len 5
+#define	fd_sqi_s2_lsb 0
+#define xd_p_fd_sqi_dummy_reg_1	0xA33D
+#define	fd_sqi_dummy_reg_1_pos 0
+#define	fd_sqi_dummy_reg_1_len 1
+#define	fd_sqi_dummy_reg_1_lsb 0
+#define xd_p_fd_inr_ignore	0xA33D
+#define	fd_inr_ignore_pos 1
+#define	fd_inr_ignore_len 1
+#define	fd_inr_ignore_lsb 0
+#define xd_p_fd_pilot_ignore	0xA33D
+#define	fd_pilot_ignore_pos 2
+#define	fd_pilot_ignore_len 1
+#define	fd_pilot_ignore_lsb 0
+#define xd_p_fd_etps_ignore	0xA33D
+#define	fd_etps_ignore_pos 3
+#define	fd_etps_ignore_len 1
+#define	fd_etps_ignore_lsb 0
+#define xd_p_fd_sqi_s1	0xA33D
+#define	fd_sqi_s1_pos 4
+#define	fd_sqi_s1_len 4
+#define	fd_sqi_s1_lsb 0
+#define xd_p_reg_fste_ehw_7_0	0xA33E
+#define	reg_fste_ehw_7_0_pos 0
+#define	reg_fste_ehw_7_0_len 8
+#define	reg_fste_ehw_7_0_lsb 0
+#define xd_p_reg_fste_ehw_9_8	0xA33F
+#define	reg_fste_ehw_9_8_pos 0
+#define	reg_fste_ehw_9_8_len 2
+#define	reg_fste_ehw_9_8_lsb 8
+#define xd_p_reg_fste_i_adj_vld	0xA33F
+#define	reg_fste_i_adj_vld_pos 2
+#define	reg_fste_i_adj_vld_len 1
+#define	reg_fste_i_adj_vld_lsb 0
+#define xd_p_reg_fste_phase_ini_7_0	0xA340
+#define	reg_fste_phase_ini_7_0_pos 0
+#define	reg_fste_phase_ini_7_0_len 8
+#define	reg_fste_phase_ini_7_0_lsb 0
+#define xd_p_reg_fste_phase_ini_11_8	0xA341
+#define	reg_fste_phase_ini_11_8_pos 0
+#define	reg_fste_phase_ini_11_8_len 4
+#define	reg_fste_phase_ini_11_8_lsb 8
+#define xd_p_reg_fste_phase_inc_3_0	0xA341
+#define	reg_fste_phase_inc_3_0_pos 4
+#define	reg_fste_phase_inc_3_0_len 4
+#define	reg_fste_phase_inc_3_0_lsb 0
+#define xd_p_reg_fste_phase_inc_11_4	0xA342
+#define	reg_fste_phase_inc_11_4_pos 0
+#define	reg_fste_phase_inc_11_4_len 8
+#define	reg_fste_phase_inc_11_4_lsb 4
+#define xd_p_reg_fste_acum_cost_cnt_max	0xA343
+#define	reg_fste_acum_cost_cnt_max_pos 0
+#define	reg_fste_acum_cost_cnt_max_len 4
+#define	reg_fste_acum_cost_cnt_max_lsb 0
+#define xd_p_reg_fste_step_size_std	0xA343
+#define	reg_fste_step_size_std_pos 4
+#define	reg_fste_step_size_std_len 4
+#define	reg_fste_step_size_std_lsb 0
+#define xd_p_reg_fste_step_size_max	0xA344
+#define	reg_fste_step_size_max_pos 0
+#define	reg_fste_step_size_max_len 4
+#define	reg_fste_step_size_max_lsb 0
+#define xd_p_reg_fste_step_size_min	0xA344
+#define	reg_fste_step_size_min_pos 4
+#define	reg_fste_step_size_min_len 4
+#define	reg_fste_step_size_min_lsb 0
+#define xd_p_reg_fste_frac_step_size_7_0	0xA345
+#define	reg_fste_frac_step_size_7_0_pos 0
+#define	reg_fste_frac_step_size_7_0_len 8
+#define	reg_fste_frac_step_size_7_0_lsb 0
+#define xd_p_reg_fste_frac_step_size_15_8	0xA346
+#define	reg_fste_frac_step_size_15_8_pos 0
+#define	reg_fste_frac_step_size_15_8_len 8
+#define	reg_fste_frac_step_size_15_8_lsb 8
+#define xd_p_reg_fste_frac_step_size_19_16	0xA347
+#define	reg_fste_frac_step_size_19_16_pos 0
+#define	reg_fste_frac_step_size_19_16_len 4
+#define	reg_fste_frac_step_size_19_16_lsb 16
+#define xd_p_reg_fste_rpd_dir_cnt_max	0xA347
+#define	reg_fste_rpd_dir_cnt_max_pos 4
+#define	reg_fste_rpd_dir_cnt_max_len 4
+#define	reg_fste_rpd_dir_cnt_max_lsb 0
+#define xd_p_reg_fste_ehs	0xA348
+#define	reg_fste_ehs_pos 0
+#define	reg_fste_ehs_len 4
+#define	reg_fste_ehs_lsb 0
+#define xd_p_reg_fste_frac_cost_cnt_max_3_0	0xA348
+#define	reg_fste_frac_cost_cnt_max_3_0_pos 4
+#define	reg_fste_frac_cost_cnt_max_3_0_len 4
+#define	reg_fste_frac_cost_cnt_max_3_0_lsb 0
+#define xd_p_reg_fste_frac_cost_cnt_max_9_4	0xA349
+#define	reg_fste_frac_cost_cnt_max_9_4_pos 0
+#define	reg_fste_frac_cost_cnt_max_9_4_len 6
+#define	reg_fste_frac_cost_cnt_max_9_4_lsb 4
+#define xd_p_reg_fste_w0_7_0	0xA34A
+#define	reg_fste_w0_7_0_pos 0
+#define	reg_fste_w0_7_0_len 8
+#define	reg_fste_w0_7_0_lsb 0
+#define xd_p_reg_fste_w0_11_8	0xA34B
+#define	reg_fste_w0_11_8_pos 0
+#define	reg_fste_w0_11_8_len 4
+#define	reg_fste_w0_11_8_lsb 8
+#define xd_p_reg_fste_w1_3_0	0xA34B
+#define	reg_fste_w1_3_0_pos 4
+#define	reg_fste_w1_3_0_len 4
+#define	reg_fste_w1_3_0_lsb 0
+#define xd_p_reg_fste_w1_11_4	0xA34C
+#define	reg_fste_w1_11_4_pos 0
+#define	reg_fste_w1_11_4_len 8
+#define	reg_fste_w1_11_4_lsb 4
+#define xd_p_reg_fste_w2_7_0	0xA34D
+#define	reg_fste_w2_7_0_pos 0
+#define	reg_fste_w2_7_0_len 8
+#define	reg_fste_w2_7_0_lsb 0
+#define xd_p_reg_fste_w2_11_8	0xA34E
+#define	reg_fste_w2_11_8_pos 0
+#define	reg_fste_w2_11_8_len 4
+#define	reg_fste_w2_11_8_lsb 8
+#define xd_p_reg_fste_w3_3_0	0xA34E
+#define	reg_fste_w3_3_0_pos 4
+#define	reg_fste_w3_3_0_len 4
+#define	reg_fste_w3_3_0_lsb 0
+#define xd_p_reg_fste_w3_11_4	0xA34F
+#define	reg_fste_w3_11_4_pos 0
+#define	reg_fste_w3_11_4_len 8
+#define	reg_fste_w3_11_4_lsb 4
+#define xd_p_reg_fste_w4_7_0	0xA350
+#define	reg_fste_w4_7_0_pos 0
+#define	reg_fste_w4_7_0_len 8
+#define	reg_fste_w4_7_0_lsb 0
+#define xd_p_reg_fste_w4_11_8	0xA351
+#define	reg_fste_w4_11_8_pos 0
+#define	reg_fste_w4_11_8_len 4
+#define	reg_fste_w4_11_8_lsb 8
+#define xd_p_reg_fste_w5_3_0	0xA351
+#define	reg_fste_w5_3_0_pos 4
+#define	reg_fste_w5_3_0_len 4
+#define	reg_fste_w5_3_0_lsb 0
+#define xd_p_reg_fste_w5_11_4	0xA352
+#define	reg_fste_w5_11_4_pos 0
+#define	reg_fste_w5_11_4_len 8
+#define	reg_fste_w5_11_4_lsb 4
+#define xd_p_reg_fste_w6_7_0	0xA353
+#define	reg_fste_w6_7_0_pos 0
+#define	reg_fste_w6_7_0_len 8
+#define	reg_fste_w6_7_0_lsb 0
+#define xd_p_reg_fste_w6_11_8	0xA354
+#define	reg_fste_w6_11_8_pos 0
+#define	reg_fste_w6_11_8_len 4
+#define	reg_fste_w6_11_8_lsb 8
+#define xd_p_reg_fste_w7_3_0	0xA354
+#define	reg_fste_w7_3_0_pos 4
+#define	reg_fste_w7_3_0_len 4
+#define	reg_fste_w7_3_0_lsb 0
+#define xd_p_reg_fste_w7_11_4	0xA355
+#define	reg_fste_w7_11_4_pos 0
+#define	reg_fste_w7_11_4_len 8
+#define	reg_fste_w7_11_4_lsb 4
+#define xd_p_reg_fste_w8_7_0	0xA356
+#define	reg_fste_w8_7_0_pos 0
+#define	reg_fste_w8_7_0_len 8
+#define	reg_fste_w8_7_0_lsb 0
+#define xd_p_reg_fste_w8_11_8	0xA357
+#define	reg_fste_w8_11_8_pos 0
+#define	reg_fste_w8_11_8_len 4
+#define	reg_fste_w8_11_8_lsb 8
+#define xd_p_reg_fste_w9_3_0	0xA357
+#define	reg_fste_w9_3_0_pos 4
+#define	reg_fste_w9_3_0_len 4
+#define	reg_fste_w9_3_0_lsb 0
+#define xd_p_reg_fste_w9_11_4	0xA358
+#define	reg_fste_w9_11_4_pos 0
+#define	reg_fste_w9_11_4_len 8
+#define	reg_fste_w9_11_4_lsb 4
+#define xd_p_reg_fste_wa_7_0	0xA359
+#define	reg_fste_wa_7_0_pos 0
+#define	reg_fste_wa_7_0_len 8
+#define	reg_fste_wa_7_0_lsb 0
+#define xd_p_reg_fste_wa_11_8	0xA35A
+#define	reg_fste_wa_11_8_pos 0
+#define	reg_fste_wa_11_8_len 4
+#define	reg_fste_wa_11_8_lsb 8
+#define xd_p_reg_fste_wb_3_0	0xA35A
+#define	reg_fste_wb_3_0_pos 4
+#define	reg_fste_wb_3_0_len 4
+#define	reg_fste_wb_3_0_lsb 0
+#define xd_p_reg_fste_wb_11_4	0xA35B
+#define	reg_fste_wb_11_4_pos 0
+#define	reg_fste_wb_11_4_len 8
+#define	reg_fste_wb_11_4_lsb 4
+#define xd_r_fd_fste_i_adj	0xA35C
+#define	fd_fste_i_adj_pos 0
+#define	fd_fste_i_adj_len 5
+#define	fd_fste_i_adj_lsb 0
+#define xd_r_fd_fste_f_adj_7_0	0xA35D
+#define	fd_fste_f_adj_7_0_pos 0
+#define	fd_fste_f_adj_7_0_len 8
+#define	fd_fste_f_adj_7_0_lsb 0
+#define xd_r_fd_fste_f_adj_15_8	0xA35E
+#define	fd_fste_f_adj_15_8_pos 0
+#define	fd_fste_f_adj_15_8_len 8
+#define	fd_fste_f_adj_15_8_lsb 8
+#define xd_r_fd_fste_f_adj_19_16	0xA35F
+#define	fd_fste_f_adj_19_16_pos 0
+#define	fd_fste_f_adj_19_16_len 4
+#define	fd_fste_f_adj_19_16_lsb 16
+#define xd_p_reg_feq_Leak_Bypass	0xA366
+#define	reg_feq_Leak_Bypass_pos 0
+#define	reg_feq_Leak_Bypass_len 1
+#define	reg_feq_Leak_Bypass_lsb 0
+#define xd_p_reg_feq_Leak_Mneg1	0xA366
+#define	reg_feq_Leak_Mneg1_pos 1
+#define	reg_feq_Leak_Mneg1_len 3
+#define	reg_feq_Leak_Mneg1_lsb 0
+#define xd_p_reg_feq_Leak_B_ShiftQ	0xA366
+#define	reg_feq_Leak_B_ShiftQ_pos 4
+#define	reg_feq_Leak_B_ShiftQ_len 4
+#define	reg_feq_Leak_B_ShiftQ_lsb 0
+#define xd_p_reg_feq_Leak_B_Float0	0xA367
+#define	reg_feq_Leak_B_Float0_pos 0
+#define	reg_feq_Leak_B_Float0_len 8
+#define	reg_feq_Leak_B_Float0_lsb 0
+#define xd_p_reg_feq_Leak_B_Float1	0xA368
+#define	reg_feq_Leak_B_Float1_pos 0
+#define	reg_feq_Leak_B_Float1_len 8
+#define	reg_feq_Leak_B_Float1_lsb 0
+#define xd_p_reg_feq_Leak_B_Float2	0xA369
+#define	reg_feq_Leak_B_Float2_pos 0
+#define	reg_feq_Leak_B_Float2_len 8
+#define	reg_feq_Leak_B_Float2_lsb 0
+#define xd_p_reg_feq_Leak_B_Float3	0xA36A
+#define	reg_feq_Leak_B_Float3_pos 0
+#define	reg_feq_Leak_B_Float3_len 8
+#define	reg_feq_Leak_B_Float3_lsb 0
+#define xd_p_reg_feq_Leak_B_Float4	0xA36B
+#define	reg_feq_Leak_B_Float4_pos 0
+#define	reg_feq_Leak_B_Float4_len 8
+#define	reg_feq_Leak_B_Float4_lsb 0
+#define xd_p_reg_feq_Leak_B_Float5	0xA36C
+#define	reg_feq_Leak_B_Float5_pos 0
+#define	reg_feq_Leak_B_Float5_len 8
+#define	reg_feq_Leak_B_Float5_lsb 0
+#define xd_p_reg_feq_Leak_B_Float6	0xA36D
+#define	reg_feq_Leak_B_Float6_pos 0
+#define	reg_feq_Leak_B_Float6_len 8
+#define	reg_feq_Leak_B_Float6_lsb 0
+#define xd_p_reg_feq_Leak_B_Float7	0xA36E
+#define	reg_feq_Leak_B_Float7_pos 0
+#define	reg_feq_Leak_B_Float7_len 8
+#define	reg_feq_Leak_B_Float7_lsb 0
+#define xd_r_reg_feq_data_h2_7_0	0xA36F
+#define	reg_feq_data_h2_7_0_pos 0
+#define	reg_feq_data_h2_7_0_len 8
+#define	reg_feq_data_h2_7_0_lsb 0
+#define xd_r_reg_feq_data_h2_9_8	0xA370
+#define	reg_feq_data_h2_9_8_pos 0
+#define	reg_feq_data_h2_9_8_len 2
+#define	reg_feq_data_h2_9_8_lsb 8
+#define xd_p_reg_feq_leak_use_slice_tps	0xA371
+#define	reg_feq_leak_use_slice_tps_pos 0
+#define	reg_feq_leak_use_slice_tps_len 1
+#define	reg_feq_leak_use_slice_tps_lsb 0
+#define xd_p_reg_feq_read_update	0xA371
+#define	reg_feq_read_update_pos 1
+#define	reg_feq_read_update_len 1
+#define	reg_feq_read_update_lsb 0
+#define xd_p_reg_feq_data_vld	0xA371
+#define	reg_feq_data_vld_pos 2
+#define	reg_feq_data_vld_len 1
+#define	reg_feq_data_vld_lsb 0
+#define xd_p_reg_feq_tone_idx_4_0	0xA371
+#define	reg_feq_tone_idx_4_0_pos 3
+#define	reg_feq_tone_idx_4_0_len 5
+#define	reg_feq_tone_idx_4_0_lsb 0
+#define xd_p_reg_feq_tone_idx_12_5	0xA372
+#define	reg_feq_tone_idx_12_5_pos 0
+#define	reg_feq_tone_idx_12_5_len 8
+#define	reg_feq_tone_idx_12_5_lsb 5
+#define xd_r_reg_feq_data_re_7_0	0xA373
+#define	reg_feq_data_re_7_0_pos 0
+#define	reg_feq_data_re_7_0_len 8
+#define	reg_feq_data_re_7_0_lsb 0
+#define xd_r_reg_feq_data_re_10_8	0xA374
+#define	reg_feq_data_re_10_8_pos 0
+#define	reg_feq_data_re_10_8_len 3
+#define	reg_feq_data_re_10_8_lsb 8
+#define xd_r_reg_feq_data_im_7_0	0xA375
+#define	reg_feq_data_im_7_0_pos 0
+#define	reg_feq_data_im_7_0_len 8
+#define	reg_feq_data_im_7_0_lsb 0
+#define xd_r_reg_feq_data_im_10_8	0xA376
+#define	reg_feq_data_im_10_8_pos 0
+#define	reg_feq_data_im_10_8_len 3
+#define	reg_feq_data_im_10_8_lsb 8
+#define xd_r_reg_feq_y_re	0xA377
+#define	reg_feq_y_re_pos 0
+#define	reg_feq_y_re_len 8
+#define	reg_feq_y_re_lsb 0
+#define xd_r_reg_feq_y_im	0xA378
+#define	reg_feq_y_im_pos 0
+#define	reg_feq_y_im_len 8
+#define	reg_feq_y_im_lsb 0
+#define xd_r_reg_feq_h_re_7_0	0xA379
+#define	reg_feq_h_re_7_0_pos 0
+#define	reg_feq_h_re_7_0_len 8
+#define	reg_feq_h_re_7_0_lsb 0
+#define xd_r_reg_feq_h_re_8	0xA37A
+#define	reg_feq_h_re_8_pos 0
+#define	reg_feq_h_re_8_len 1
+#define	reg_feq_h_re_8_lsb 0
+#define xd_r_reg_feq_h_im_7_0	0xA37B
+#define	reg_feq_h_im_7_0_pos 0
+#define	reg_feq_h_im_7_0_len 8
+#define	reg_feq_h_im_7_0_lsb 0
+#define xd_r_reg_feq_h_im_8	0xA37C
+#define	reg_feq_h_im_8_pos 0
+#define	reg_feq_h_im_8_len 1
+#define	reg_feq_h_im_8_lsb 0
+#define xd_p_fec_super_frm_unit_7_0	0xA380
+#define	fec_super_frm_unit_7_0_pos 0
+#define	fec_super_frm_unit_7_0_len 8
+#define	fec_super_frm_unit_7_0_lsb 0
+#define xd_p_fec_super_frm_unit_15_8	0xA381
+#define	fec_super_frm_unit_15_8_pos 0
+#define	fec_super_frm_unit_15_8_len 8
+#define	fec_super_frm_unit_15_8_lsb 8
+#define xd_r_fec_vtb_err_bit_cnt_7_0	0xA382
+#define	fec_vtb_err_bit_cnt_7_0_pos 0
+#define	fec_vtb_err_bit_cnt_7_0_len 8
+#define	fec_vtb_err_bit_cnt_7_0_lsb 0
+#define xd_r_fec_vtb_err_bit_cnt_15_8	0xA383
+#define	fec_vtb_err_bit_cnt_15_8_pos 0
+#define	fec_vtb_err_bit_cnt_15_8_len 8
+#define	fec_vtb_err_bit_cnt_15_8_lsb 8
+#define xd_r_fec_vtb_err_bit_cnt_23_16	0xA384
+#define	fec_vtb_err_bit_cnt_23_16_pos 0
+#define	fec_vtb_err_bit_cnt_23_16_len 8
+#define	fec_vtb_err_bit_cnt_23_16_lsb 16
+#define xd_p_fec_rsd_packet_unit_7_0	0xA385
+#define	fec_rsd_packet_unit_7_0_pos 0
+#define	fec_rsd_packet_unit_7_0_len 8
+#define	fec_rsd_packet_unit_7_0_lsb 0
+#define xd_p_fec_rsd_packet_unit_15_8	0xA386
+#define	fec_rsd_packet_unit_15_8_pos 0
+#define	fec_rsd_packet_unit_15_8_len 8
+#define	fec_rsd_packet_unit_15_8_lsb 8
+#define xd_r_fec_rsd_bit_err_cnt_7_0	0xA387
+#define	fec_rsd_bit_err_cnt_7_0_pos 0
+#define	fec_rsd_bit_err_cnt_7_0_len 8
+#define	fec_rsd_bit_err_cnt_7_0_lsb 0
+#define xd_r_fec_rsd_bit_err_cnt_15_8	0xA388
+#define	fec_rsd_bit_err_cnt_15_8_pos 0
+#define	fec_rsd_bit_err_cnt_15_8_len 8
+#define	fec_rsd_bit_err_cnt_15_8_lsb 8
+#define xd_r_fec_rsd_bit_err_cnt_23_16	0xA389
+#define	fec_rsd_bit_err_cnt_23_16_pos 0
+#define	fec_rsd_bit_err_cnt_23_16_len 8
+#define	fec_rsd_bit_err_cnt_23_16_lsb 16
+#define xd_r_fec_rsd_abort_packet_cnt_7_0	0xA38A
+#define	fec_rsd_abort_packet_cnt_7_0_pos 0
+#define	fec_rsd_abort_packet_cnt_7_0_len 8
+#define	fec_rsd_abort_packet_cnt_7_0_lsb 0
+#define xd_r_fec_rsd_abort_packet_cnt_15_8	0xA38B
+#define	fec_rsd_abort_packet_cnt_15_8_pos 0
+#define	fec_rsd_abort_packet_cnt_15_8_len 8
+#define	fec_rsd_abort_packet_cnt_15_8_lsb 8
+#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_7_0	0xA38C
+#define	fec_RSD_PKT_NUM_PER_UNIT_7_0_pos 0
+#define	fec_RSD_PKT_NUM_PER_UNIT_7_0_len 8
+#define	fec_RSD_PKT_NUM_PER_UNIT_7_0_lsb 0
+#define xd_p_fec_RSD_PKT_NUM_PER_UNIT_15_8	0xA38D
+#define	fec_RSD_PKT_NUM_PER_UNIT_15_8_pos 0
+#define	fec_RSD_PKT_NUM_PER_UNIT_15_8_len 8
+#define	fec_RSD_PKT_NUM_PER_UNIT_15_8_lsb 8
+#define xd_p_fec_RS_TH_1_7_0	0xA38E
+#define	fec_RS_TH_1_7_0_pos 0
+#define	fec_RS_TH_1_7_0_len 8
+#define	fec_RS_TH_1_7_0_lsb 0
+#define xd_p_fec_RS_TH_1_15_8	0xA38F
+#define	fec_RS_TH_1_15_8_pos 0
+#define	fec_RS_TH_1_15_8_len 8
+#define	fec_RS_TH_1_15_8_lsb 8
+#define xd_p_fec_RS_TH_2	0xA390
+#define	fec_RS_TH_2_pos 0
+#define	fec_RS_TH_2_len 8
+#define	fec_RS_TH_2_lsb 0
+#define xd_p_fec_mon_en	0xA391
+#define	fec_mon_en_pos 0
+#define	fec_mon_en_len 1
+#define	fec_mon_en_lsb 0
+#define xd_p_reg_b8to47	0xA391
+#define	reg_b8to47_pos 1
+#define	reg_b8to47_len 1
+#define	reg_b8to47_lsb 0
+#define xd_p_reg_rsd_sync_rep	0xA391
+#define	reg_rsd_sync_rep_pos 2
+#define	reg_rsd_sync_rep_len 1
+#define	reg_rsd_sync_rep_lsb 0
+#define xd_p_fec_rsd_retrain_rst	0xA391
+#define	fec_rsd_retrain_rst_pos 3
+#define	fec_rsd_retrain_rst_len 1
+#define	fec_rsd_retrain_rst_lsb 0
+#define xd_r_fec_rsd_ber_rdy	0xA391
+#define	fec_rsd_ber_rdy_pos 4
+#define	fec_rsd_ber_rdy_len 1
+#define	fec_rsd_ber_rdy_lsb 0
+#define xd_p_fec_rsd_ber_rst	0xA391
+#define	fec_rsd_ber_rst_pos 5
+#define	fec_rsd_ber_rst_len 1
+#define	fec_rsd_ber_rst_lsb 0
+#define xd_r_fec_vtb_ber_rdy	0xA391
+#define	fec_vtb_ber_rdy_pos 6
+#define	fec_vtb_ber_rdy_len 1
+#define	fec_vtb_ber_rdy_lsb 0
+#define xd_p_fec_vtb_ber_rst	0xA391
+#define	fec_vtb_ber_rst_pos 7
+#define	fec_vtb_ber_rst_len 1
+#define	fec_vtb_ber_rst_lsb 0
+#define xd_p_reg_vtb_clk40en	0xA392
+#define	reg_vtb_clk40en_pos 0
+#define	reg_vtb_clk40en_len 1
+#define	reg_vtb_clk40en_lsb 0
+#define xd_p_fec_vtb_rsd_mon_en	0xA392
+#define	fec_vtb_rsd_mon_en_pos 1
+#define	fec_vtb_rsd_mon_en_len 1
+#define	fec_vtb_rsd_mon_en_lsb 0
+#define xd_p_reg_fec_data_en	0xA392
+#define	reg_fec_data_en_pos 2
+#define	reg_fec_data_en_len 1
+#define	reg_fec_data_en_lsb 0
+#define xd_p_fec_dummy_reg_2	0xA392
+#define	fec_dummy_reg_2_pos 3
+#define	fec_dummy_reg_2_len 3
+#define	fec_dummy_reg_2_lsb 0
+#define xd_p_reg_sync_chk	0xA392
+#define	reg_sync_chk_pos 6
+#define	reg_sync_chk_len 1
+#define	reg_sync_chk_lsb 0
+#define xd_p_fec_rsd_bypass	0xA392
+#define	fec_rsd_bypass_pos 7
+#define	fec_rsd_bypass_len 1
+#define	fec_rsd_bypass_lsb 0
+#define xd_p_fec_sw_rst	0xA393
+#define	fec_sw_rst_pos 0
+#define	fec_sw_rst_len 1
+#define	fec_sw_rst_lsb 0
+#define xd_r_fec_vtb_pm_crc	0xA394
+#define	fec_vtb_pm_crc_pos 0
+#define	fec_vtb_pm_crc_len 8
+#define	fec_vtb_pm_crc_lsb 0
+#define xd_r_fec_vtb_tb_7_crc	0xA395
+#define	fec_vtb_tb_7_crc_pos 0
+#define	fec_vtb_tb_7_crc_len 8
+#define	fec_vtb_tb_7_crc_lsb 0
+#define xd_r_fec_vtb_tb_6_crc	0xA396
+#define	fec_vtb_tb_6_crc_pos 0
+#define	fec_vtb_tb_6_crc_len 8
+#define	fec_vtb_tb_6_crc_lsb 0
+#define xd_r_fec_vtb_tb_5_crc	0xA397
+#define	fec_vtb_tb_5_crc_pos 0
+#define	fec_vtb_tb_5_crc_len 8
+#define	fec_vtb_tb_5_crc_lsb 0
+#define xd_r_fec_vtb_tb_4_crc	0xA398
+#define	fec_vtb_tb_4_crc_pos 0
+#define	fec_vtb_tb_4_crc_len 8
+#define	fec_vtb_tb_4_crc_lsb 0
+#define xd_r_fec_vtb_tb_3_crc	0xA399
+#define	fec_vtb_tb_3_crc_pos 0
+#define	fec_vtb_tb_3_crc_len 8
+#define	fec_vtb_tb_3_crc_lsb 0
+#define xd_r_fec_vtb_tb_2_crc	0xA39A
+#define	fec_vtb_tb_2_crc_pos 0
+#define	fec_vtb_tb_2_crc_len 8
+#define	fec_vtb_tb_2_crc_lsb 0
+#define xd_r_fec_vtb_tb_1_crc	0xA39B
+#define	fec_vtb_tb_1_crc_pos 0
+#define	fec_vtb_tb_1_crc_len 8
+#define	fec_vtb_tb_1_crc_lsb 0
+#define xd_r_fec_vtb_tb_0_crc	0xA39C
+#define	fec_vtb_tb_0_crc_pos 0
+#define	fec_vtb_tb_0_crc_len 8
+#define	fec_vtb_tb_0_crc_lsb 0
+#define xd_r_fec_rsd_bank0_crc	0xA39D
+#define	fec_rsd_bank0_crc_pos 0
+#define	fec_rsd_bank0_crc_len 8
+#define	fec_rsd_bank0_crc_lsb 0
+#define xd_r_fec_rsd_bank1_crc	0xA39E
+#define	fec_rsd_bank1_crc_pos 0
+#define	fec_rsd_bank1_crc_len 8
+#define	fec_rsd_bank1_crc_lsb 0
+#define xd_r_fec_idi_vtb_crc	0xA39F
+#define	fec_idi_vtb_crc_pos 0
+#define	fec_idi_vtb_crc_len 8
+#define	fec_idi_vtb_crc_lsb 0
+#define xd_g_reg_tpsd_txmod	0xA3C0
+#define	reg_tpsd_txmod_pos 0
+#define	reg_tpsd_txmod_len 2
+#define	reg_tpsd_txmod_lsb 0
+#define xd_g_reg_tpsd_gi	0xA3C0
+#define	reg_tpsd_gi_pos 2
+#define	reg_tpsd_gi_len 2
+#define	reg_tpsd_gi_lsb 0
+#define xd_g_reg_tpsd_hier	0xA3C0
+#define	reg_tpsd_hier_pos 4
+#define	reg_tpsd_hier_len 3
+#define	reg_tpsd_hier_lsb 0
+#define xd_g_reg_bw	0xA3C1
+#define	reg_bw_pos 2
+#define	reg_bw_len 2
+#define	reg_bw_lsb 0
+#define xd_g_reg_dec_pri	0xA3C1
+#define	reg_dec_pri_pos 4
+#define	reg_dec_pri_len 1
+#define	reg_dec_pri_lsb 0
+#define xd_g_reg_tpsd_const	0xA3C1
+#define	reg_tpsd_const_pos 6
+#define	reg_tpsd_const_len 2
+#define	reg_tpsd_const_lsb 0
+#define xd_g_reg_tpsd_hpcr	0xA3C2
+#define	reg_tpsd_hpcr_pos 0
+#define	reg_tpsd_hpcr_len 3
+#define	reg_tpsd_hpcr_lsb 0
+#define xd_g_reg_tpsd_lpcr	0xA3C2
+#define	reg_tpsd_lpcr_pos 3
+#define	reg_tpsd_lpcr_len 3
+#define	reg_tpsd_lpcr_lsb 0
+#define xd_g_reg_ofsm_clk	0xA3D0
+#define	reg_ofsm_clk_pos 0
+#define	reg_ofsm_clk_len 3
+#define	reg_ofsm_clk_lsb 0
+#define xd_g_reg_fclk_cfg	0xA3D1
+#define	reg_fclk_cfg_pos 0
+#define	reg_fclk_cfg_len 1
+#define	reg_fclk_cfg_lsb 0
+#define xd_g_reg_fclk_idi	0xA3D1
+#define	reg_fclk_idi_pos 1
+#define	reg_fclk_idi_len 1
+#define	reg_fclk_idi_lsb 0
+#define xd_g_reg_fclk_odi	0xA3D1
+#define	reg_fclk_odi_pos 2
+#define	reg_fclk_odi_len 1
+#define	reg_fclk_odi_lsb 0
+#define xd_g_reg_fclk_rsd	0xA3D1
+#define	reg_fclk_rsd_pos 3
+#define	reg_fclk_rsd_len 1
+#define	reg_fclk_rsd_lsb 0
+#define xd_g_reg_fclk_vtb	0xA3D1
+#define	reg_fclk_vtb_pos 4
+#define	reg_fclk_vtb_len 1
+#define	reg_fclk_vtb_lsb 0
+#define xd_g_reg_fclk_cste	0xA3D1
+#define	reg_fclk_cste_pos 5
+#define	reg_fclk_cste_len 1
+#define	reg_fclk_cste_lsb 0
+#define xd_g_reg_fclk_mp2if	0xA3D1
+#define	reg_fclk_mp2if_pos 6
+#define	reg_fclk_mp2if_len 1
+#define	reg_fclk_mp2if_lsb 0
+#define xd_I2C_i2c_m_slave_addr	0xA400
+#define	i2c_m_slave_addr_pos 0
+#define	i2c_m_slave_addr_len 8
+#define	i2c_m_slave_addr_lsb 0
+#define xd_I2C_i2c_m_data1	0xA401
+#define	i2c_m_data1_pos 0
+#define	i2c_m_data1_len 8
+#define	i2c_m_data1_lsb 0
+#define xd_I2C_i2c_m_data2	0xA402
+#define	i2c_m_data2_pos 0
+#define	i2c_m_data2_len 8
+#define	i2c_m_data2_lsb 0
+#define xd_I2C_i2c_m_data3	0xA403
+#define	i2c_m_data3_pos 0
+#define	i2c_m_data3_len 8
+#define	i2c_m_data3_lsb 0
+#define xd_I2C_i2c_m_data4	0xA404
+#define	i2c_m_data4_pos 0
+#define	i2c_m_data4_len 8
+#define	i2c_m_data4_lsb 0
+#define xd_I2C_i2c_m_data5	0xA405
+#define	i2c_m_data5_pos 0
+#define	i2c_m_data5_len 8
+#define	i2c_m_data5_lsb 0
+#define xd_I2C_i2c_m_data6	0xA406
+#define	i2c_m_data6_pos 0
+#define	i2c_m_data6_len 8
+#define	i2c_m_data6_lsb 0
+#define xd_I2C_i2c_m_data7	0xA407
+#define	i2c_m_data7_pos 0
+#define	i2c_m_data7_len 8
+#define	i2c_m_data7_lsb 0
+#define xd_I2C_i2c_m_data8	0xA408
+#define	i2c_m_data8_pos 0
+#define	i2c_m_data8_len 8
+#define	i2c_m_data8_lsb 0
+#define xd_I2C_i2c_m_data9	0xA409
+#define	i2c_m_data9_pos 0
+#define	i2c_m_data9_len 8
+#define	i2c_m_data9_lsb 0
+#define xd_I2C_i2c_m_data10	0xA40A
+#define	i2c_m_data10_pos 0
+#define	i2c_m_data10_len 8
+#define	i2c_m_data10_lsb 0
+#define xd_I2C_i2c_m_data11	0xA40B
+#define	i2c_m_data11_pos 0
+#define	i2c_m_data11_len 8
+#define	i2c_m_data11_lsb 0
+#define xd_I2C_i2c_m_cmd_rw	0xA40C
+#define	i2c_m_cmd_rw_pos 0
+#define	i2c_m_cmd_rw_len 1
+#define	i2c_m_cmd_rw_lsb 0
+#define xd_I2C_i2c_m_cmd_rwlen	0xA40C
+#define	i2c_m_cmd_rwlen_pos 3
+#define	i2c_m_cmd_rwlen_len 4
+#define	i2c_m_cmd_rwlen_lsb 0
+#define xd_I2C_i2c_m_status_cmd_exe	0xA40D
+#define	i2c_m_status_cmd_exe_pos 0
+#define	i2c_m_status_cmd_exe_len 1
+#define	i2c_m_status_cmd_exe_lsb 0
+#define xd_I2C_i2c_m_status_wdat_done	0xA40D
+#define	i2c_m_status_wdat_done_pos 1
+#define	i2c_m_status_wdat_done_len 1
+#define	i2c_m_status_wdat_done_lsb 0
+#define xd_I2C_i2c_m_status_wdat_fail	0xA40D
+#define	i2c_m_status_wdat_fail_pos 2
+#define	i2c_m_status_wdat_fail_len 1
+#define	i2c_m_status_wdat_fail_lsb 0
+#define xd_I2C_i2c_m_period	0xA40E
+#define	i2c_m_period_pos 0
+#define	i2c_m_period_len 8
+#define	i2c_m_period_lsb 0
+#define xd_I2C_i2c_m_reg_msb_lsb	0xA40F
+#define	i2c_m_reg_msb_lsb_pos 0
+#define	i2c_m_reg_msb_lsb_len 1
+#define	i2c_m_reg_msb_lsb_lsb 0
+#define xd_I2C_reg_ofdm_rst	0xA40F
+#define	reg_ofdm_rst_pos 1
+#define	reg_ofdm_rst_len 1
+#define	reg_ofdm_rst_lsb 0
+#define xd_I2C_reg_sample_period_on_tuner	0xA40F
+#define	reg_sample_period_on_tuner_pos 2
+#define	reg_sample_period_on_tuner_len 1
+#define	reg_sample_period_on_tuner_lsb 0
+#define xd_I2C_reg_rst_i2c	0xA40F
+#define	reg_rst_i2c_pos 3
+#define	reg_rst_i2c_len 1
+#define	reg_rst_i2c_lsb 0
+#define xd_I2C_reg_ofdm_rst_en	0xA40F
+#define	reg_ofdm_rst_en_pos 4
+#define	reg_ofdm_rst_en_len 1
+#define	reg_ofdm_rst_en_lsb 0
+#define xd_I2C_reg_tuner_sda_sync_on	0xA40F
+#define	reg_tuner_sda_sync_on_pos 5
+#define	reg_tuner_sda_sync_on_len 1
+#define	reg_tuner_sda_sync_on_lsb 0
+#define xd_p_mp2if_data_access_disable_ofsm	0xA500
+#define	mp2if_data_access_disable_ofsm_pos 0
+#define	mp2if_data_access_disable_ofsm_len 1
+#define	mp2if_data_access_disable_ofsm_lsb 0
+#define xd_p_reg_mp2_sw_rst_ofsm	0xA500
+#define	reg_mp2_sw_rst_ofsm_pos 1
+#define	reg_mp2_sw_rst_ofsm_len 1
+#define	reg_mp2_sw_rst_ofsm_lsb 0
+#define xd_p_reg_mp2if_clk_en_ofsm	0xA500
+#define	reg_mp2if_clk_en_ofsm_pos 2
+#define	reg_mp2if_clk_en_ofsm_len 1
+#define	reg_mp2if_clk_en_ofsm_lsb 0
+#define xd_r_mp2if_sync_byte_locked	0xA500
+#define	mp2if_sync_byte_locked_pos 3
+#define	mp2if_sync_byte_locked_len 1
+#define	mp2if_sync_byte_locked_lsb 0
+#define xd_r_mp2if_ts_not_188	0xA500
+#define	mp2if_ts_not_188_pos 4
+#define	mp2if_ts_not_188_len 1
+#define	mp2if_ts_not_188_lsb 0
+#define xd_r_mp2if_psb_empty	0xA500
+#define	mp2if_psb_empty_pos 5
+#define	mp2if_psb_empty_len 1
+#define	mp2if_psb_empty_lsb 0
+#define xd_r_mp2if_psb_overflow	0xA500
+#define	mp2if_psb_overflow_pos 6
+#define	mp2if_psb_overflow_len 1
+#define	mp2if_psb_overflow_lsb 0
+#define xd_p_mp2if_keep_sf_sync_byte_ofsm	0xA500
+#define	mp2if_keep_sf_sync_byte_ofsm_pos 7
+#define	mp2if_keep_sf_sync_byte_ofsm_len 1
+#define	mp2if_keep_sf_sync_byte_ofsm_lsb 0
+#define xd_r_mp2if_psb_mp2if_num_pkt	0xA501
+#define	mp2if_psb_mp2if_num_pkt_pos 0
+#define	mp2if_psb_mp2if_num_pkt_len 6
+#define	mp2if_psb_mp2if_num_pkt_lsb 0
+#define xd_p_reg_mpeg_full_speed_ofsm	0xA501
+#define	reg_mpeg_full_speed_ofsm_pos 6
+#define	reg_mpeg_full_speed_ofsm_len 1
+#define	reg_mpeg_full_speed_ofsm_lsb 0
+#define xd_p_mp2if_mpeg_ser_mode_ofsm	0xA501
+#define	mp2if_mpeg_ser_mode_ofsm_pos 7
+#define	mp2if_mpeg_ser_mode_ofsm_len 1
+#define	mp2if_mpeg_ser_mode_ofsm_lsb 0
+#define xd_p_reg_sw_mon51	0xA600
+#define	reg_sw_mon51_pos 0
+#define	reg_sw_mon51_len 8
+#define	reg_sw_mon51_lsb 0
+#define xd_p_reg_top_pcsel	0xA601
+#define	reg_top_pcsel_pos 0
+#define	reg_top_pcsel_len 1
+#define	reg_top_pcsel_lsb 0
+#define xd_p_reg_top_rs232	0xA601
+#define	reg_top_rs232_pos 1
+#define	reg_top_rs232_len 1
+#define	reg_top_rs232_lsb 0
+#define xd_p_reg_top_pcout	0xA601
+#define	reg_top_pcout_pos 2
+#define	reg_top_pcout_len 1
+#define	reg_top_pcout_lsb 0
+#define xd_p_reg_top_debug	0xA601
+#define	reg_top_debug_pos 3
+#define	reg_top_debug_len 1
+#define	reg_top_debug_lsb 0
+#define xd_p_reg_top_adcdly	0xA601
+#define	reg_top_adcdly_pos 4
+#define	reg_top_adcdly_len 2
+#define	reg_top_adcdly_lsb 0
+#define xd_p_reg_top_pwrdw	0xA601
+#define	reg_top_pwrdw_pos 6
+#define	reg_top_pwrdw_len 1
+#define	reg_top_pwrdw_lsb 0
+#define xd_p_reg_top_pwrdw_inv	0xA601
+#define	reg_top_pwrdw_inv_pos 7
+#define	reg_top_pwrdw_inv_len 1
+#define	reg_top_pwrdw_inv_lsb 0
+#define xd_p_reg_top_int_inv	0xA602
+#define	reg_top_int_inv_pos 0
+#define	reg_top_int_inv_len 1
+#define	reg_top_int_inv_lsb 0
+#define xd_p_reg_top_dio_sel	0xA602
+#define	reg_top_dio_sel_pos 1
+#define	reg_top_dio_sel_len 1
+#define	reg_top_dio_sel_lsb 0
+#define xd_p_reg_top_gpioon0	0xA603
+#define	reg_top_gpioon0_pos 0
+#define	reg_top_gpioon0_len 1
+#define	reg_top_gpioon0_lsb 0
+#define xd_p_reg_top_gpioon1	0xA603
+#define	reg_top_gpioon1_pos 1
+#define	reg_top_gpioon1_len 1
+#define	reg_top_gpioon1_lsb 0
+#define xd_p_reg_top_gpioon2	0xA603
+#define	reg_top_gpioon2_pos 2
+#define	reg_top_gpioon2_len 1
+#define	reg_top_gpioon2_lsb 0
+#define xd_p_reg_top_gpioon3	0xA603
+#define	reg_top_gpioon3_pos 3
+#define	reg_top_gpioon3_len 1
+#define	reg_top_gpioon3_lsb 0
+#define xd_p_reg_top_lockon1	0xA603
+#define	reg_top_lockon1_pos 4
+#define	reg_top_lockon1_len 1
+#define	reg_top_lockon1_lsb 0
+#define xd_p_reg_top_lockon2	0xA603
+#define	reg_top_lockon2_pos 5
+#define	reg_top_lockon2_len 1
+#define	reg_top_lockon2_lsb 0
+#define xd_p_reg_top_gpioo0	0xA604
+#define	reg_top_gpioo0_pos 0
+#define	reg_top_gpioo0_len 1
+#define	reg_top_gpioo0_lsb 0
+#define xd_p_reg_top_gpioo1	0xA604
+#define	reg_top_gpioo1_pos 1
+#define	reg_top_gpioo1_len 1
+#define	reg_top_gpioo1_lsb 0
+#define xd_p_reg_top_gpioo2	0xA604
+#define	reg_top_gpioo2_pos 2
+#define	reg_top_gpioo2_len 1
+#define	reg_top_gpioo2_lsb 0
+#define xd_p_reg_top_gpioo3	0xA604
+#define	reg_top_gpioo3_pos 3
+#define	reg_top_gpioo3_len 1
+#define	reg_top_gpioo3_lsb 0
+#define xd_p_reg_top_lock1	0xA604
+#define	reg_top_lock1_pos 4
+#define	reg_top_lock1_len 1
+#define	reg_top_lock1_lsb 0
+#define xd_p_reg_top_lock2	0xA604
+#define	reg_top_lock2_pos 5
+#define	reg_top_lock2_len 1
+#define	reg_top_lock2_lsb 0
+#define xd_p_reg_top_gpioen0	0xA605
+#define	reg_top_gpioen0_pos 0
+#define	reg_top_gpioen0_len 1
+#define	reg_top_gpioen0_lsb 0
+#define xd_p_reg_top_gpioen1	0xA605
+#define	reg_top_gpioen1_pos 1
+#define	reg_top_gpioen1_len 1
+#define	reg_top_gpioen1_lsb 0
+#define xd_p_reg_top_gpioen2	0xA605
+#define	reg_top_gpioen2_pos 2
+#define	reg_top_gpioen2_len 1
+#define	reg_top_gpioen2_lsb 0
+#define xd_p_reg_top_gpioen3	0xA605
+#define	reg_top_gpioen3_pos 3
+#define	reg_top_gpioen3_len 1
+#define	reg_top_gpioen3_lsb 0
+#define xd_p_reg_top_locken1	0xA605
+#define	reg_top_locken1_pos 4
+#define	reg_top_locken1_len 1
+#define	reg_top_locken1_lsb 0
+#define xd_p_reg_top_locken2	0xA605
+#define	reg_top_locken2_pos 5
+#define	reg_top_locken2_len 1
+#define	reg_top_locken2_lsb 0
+#define xd_r_reg_top_gpioi0	0xA606
+#define	reg_top_gpioi0_pos 0
+#define	reg_top_gpioi0_len 1
+#define	reg_top_gpioi0_lsb 0
+#define xd_r_reg_top_gpioi1	0xA606
+#define	reg_top_gpioi1_pos 1
+#define	reg_top_gpioi1_len 1
+#define	reg_top_gpioi1_lsb 0
+#define xd_r_reg_top_gpioi2	0xA606
+#define	reg_top_gpioi2_pos 2
+#define	reg_top_gpioi2_len 1
+#define	reg_top_gpioi2_lsb 0
+#define xd_r_reg_top_gpioi3	0xA606
+#define	reg_top_gpioi3_pos 3
+#define	reg_top_gpioi3_len 1
+#define	reg_top_gpioi3_lsb 0
+#define xd_r_reg_top_locki1	0xA606
+#define	reg_top_locki1_pos 4
+#define	reg_top_locki1_len 1
+#define	reg_top_locki1_lsb 0
+#define xd_r_reg_top_locki2	0xA606
+#define	reg_top_locki2_pos 5
+#define	reg_top_locki2_len 1
+#define	reg_top_locki2_lsb 0
+#define xd_p_reg_dummy_7_0	0xA608
+#define	reg_dummy_7_0_pos 0
+#define	reg_dummy_7_0_len 8
+#define	reg_dummy_7_0_lsb 0
+#define xd_p_reg_dummy_15_8	0xA609
+#define	reg_dummy_15_8_pos 0
+#define	reg_dummy_15_8_len 8
+#define	reg_dummy_15_8_lsb 8
+#define xd_p_reg_dummy_23_16	0xA60A
+#define	reg_dummy_23_16_pos 0
+#define	reg_dummy_23_16_len 8
+#define	reg_dummy_23_16_lsb 16
+#define xd_p_reg_dummy_31_24	0xA60B
+#define	reg_dummy_31_24_pos 0
+#define	reg_dummy_31_24_len 8
+#define	reg_dummy_31_24_lsb 24
+#define xd_p_reg_dummy_39_32	0xA60C
+#define	reg_dummy_39_32_pos 0
+#define	reg_dummy_39_32_len 8
+#define	reg_dummy_39_32_lsb 32
+#define xd_p_reg_dummy_47_40	0xA60D
+#define	reg_dummy_47_40_pos 0
+#define	reg_dummy_47_40_len 8
+#define	reg_dummy_47_40_lsb 40
+#define xd_p_reg_dummy_55_48	0xA60E
+#define	reg_dummy_55_48_pos 0
+#define	reg_dummy_55_48_len 8
+#define	reg_dummy_55_48_lsb 48
+#define xd_p_reg_dummy_63_56	0xA60F
+#define	reg_dummy_63_56_pos 0
+#define	reg_dummy_63_56_len 8
+#define	reg_dummy_63_56_lsb 56
+#define xd_p_reg_dummy_71_64	0xA610
+#define	reg_dummy_71_64_pos 0
+#define	reg_dummy_71_64_len 8
+#define	reg_dummy_71_64_lsb 64
+#define xd_p_reg_dummy_79_72	0xA611
+#define	reg_dummy_79_72_pos 0
+#define	reg_dummy_79_72_len 8
+#define	reg_dummy_79_72_lsb 72
+#define xd_p_reg_dummy_87_80	0xA612
+#define	reg_dummy_87_80_pos 0
+#define	reg_dummy_87_80_len 8
+#define	reg_dummy_87_80_lsb 80
+#define xd_p_reg_dummy_95_88	0xA613
+#define	reg_dummy_95_88_pos 0
+#define	reg_dummy_95_88_len 8
+#define	reg_dummy_95_88_lsb 88
+#define xd_p_reg_dummy_103_96	0xA614
+#define	reg_dummy_103_96_pos 0
+#define	reg_dummy_103_96_len 8
+#define	reg_dummy_103_96_lsb 96
+
+#define xd_p_reg_unplug_flag	0xA615
+#define	reg_unplug_flag_pos 0
+#define	reg_unplug_flag_len 1
+#define	reg_unplug_flag_lsb 104
+
+#define xd_p_reg_api_dca_stes_request   0xA615
+#define reg_api_dca_stes_request_pos 1
+#define reg_api_dca_stes_request_len 1
+#define reg_api_dca_stes_request_lsb 0
+
+#define xd_p_reg_back_to_dca_flag	0xA615
+#define	reg_back_to_dca_flag_pos 2
+#define	reg_back_to_dca_flag_len 1
+#define	reg_back_to_dca_flag_lsb 106
+
+#define xd_p_reg_api_retrain_request    0xA615
+#define reg_api_retrain_request_pos 3
+#define reg_api_retrain_request_len 1
+#define reg_api_retrain_request_lsb 0
+
+#define xd_p_reg_Dyn_Top_Try_flag	0xA615
+#define	reg_Dyn_Top_Try_flag_pos 3
+#define	reg_Dyn_Top_Try_flag_len 1
+#define	reg_Dyn_Top_Try_flag_lsb 107
+
+#define xd_p_reg_API_retrain_freeze_flag	0xA615
+#define	reg_API_retrain_freeze_flag_pos 4
+#define	reg_API_retrain_freeze_flag_len 1
+#define	reg_API_retrain_freeze_flag_lsb 108
+
+#define xd_p_reg_dummy_111_104	0xA615
+#define	reg_dummy_111_104_pos 0
+#define	reg_dummy_111_104_len 8
+#define	reg_dummy_111_104_lsb 104
+#define xd_p_reg_dummy_119_112	0xA616
+#define	reg_dummy_119_112_pos 0
+#define	reg_dummy_119_112_len 8
+#define	reg_dummy_119_112_lsb 112
+#define xd_p_reg_dummy_127_120	0xA617
+#define	reg_dummy_127_120_pos 0
+#define	reg_dummy_127_120_len 8
+#define	reg_dummy_127_120_lsb 120
+#define xd_p_reg_dummy_135_128	0xA618
+#define	reg_dummy_135_128_pos 0
+#define	reg_dummy_135_128_len 8
+#define	reg_dummy_135_128_lsb 128
+
+#define xd_p_reg_dummy_143_136	0xA619
+#define	reg_dummy_143_136_pos 0
+#define	reg_dummy_143_136_len 8
+#define	reg_dummy_143_136_lsb 136
+
+#define xd_p_reg_CCIR_dis	0xA619
+#define	reg_CCIR_dis_pos 0
+#define	reg_CCIR_dis_len 1
+#define	reg_CCIR_dis_lsb 0
+
+#define xd_p_reg_dummy_151_144	0xA61A
+#define	reg_dummy_151_144_pos 0
+#define	reg_dummy_151_144_len 8
+#define	reg_dummy_151_144_lsb 144
+
+#define xd_p_reg_dummy_159_152	0xA61B
+#define	reg_dummy_159_152_pos 0
+#define	reg_dummy_159_152_len 8
+#define	reg_dummy_159_152_lsb 152
+
+#define xd_p_reg_dummy_167_160	0xA61C
+#define	reg_dummy_167_160_pos 0
+#define	reg_dummy_167_160_len 8
+#define	reg_dummy_167_160_lsb 160
+
+#define xd_p_reg_dummy_175_168	0xA61D
+#define	reg_dummy_175_168_pos 0
+#define	reg_dummy_175_168_len 8
+#define	reg_dummy_175_168_lsb 168
+
+#define xd_p_reg_dummy_183_176	0xA61E
+#define	reg_dummy_183_176_pos 0
+#define	reg_dummy_183_176_len 8
+#define	reg_dummy_183_176_lsb 176
+
+#define xd_p_reg_ofsm_read_rbc_en  0xA61E
+#define reg_ofsm_read_rbc_en_pos 2
+#define reg_ofsm_read_rbc_en_len 1
+#define reg_ofsm_read_rbc_en_lsb 0
+
+#define xd_p_reg_ce_filter_selection_dis  0xA61E
+#define reg_ce_filter_selection_dis_pos 1
+#define reg_ce_filter_selection_dis_len 1
+#define reg_ce_filter_selection_dis_lsb 0
+
+#define xd_p_reg_OFSM_version_control_7_0  0xA611
+#define reg_OFSM_version_control_7_0_pos 0
+#define reg_OFSM_version_control_7_0_len 8
+#define reg_OFSM_version_control_7_0_lsb 0
+
+#define xd_p_reg_OFSM_version_control_15_8  0xA61F
+#define reg_OFSM_version_control_15_8_pos 0
+#define reg_OFSM_version_control_15_8_len 8
+#define reg_OFSM_version_control_15_8_lsb 0
+
+#define xd_p_reg_OFSM_version_control_23_16  0xA620
+#define reg_OFSM_version_control_23_16_pos 0
+#define reg_OFSM_version_control_23_16_len 8
+#define reg_OFSM_version_control_23_16_lsb 0
+
+#define xd_p_reg_dummy_191_184	0xA61F
+#define	reg_dummy_191_184_pos 0
+#define	reg_dummy_191_184_len 8
+#define	reg_dummy_191_184_lsb 184
+
+#define xd_p_reg_dummy_199_192	0xA620
+#define	reg_dummy_199_192_pos 0
+#define	reg_dummy_199_192_len 8
+#define	reg_dummy_199_192_lsb 192
+
+#define xd_p_reg_ce_en	0xABC0
+#define	reg_ce_en_pos 0
+#define	reg_ce_en_len 1
+#define	reg_ce_en_lsb 0
+#define xd_p_reg_ce_fctrl_en	0xABC0
+#define	reg_ce_fctrl_en_pos 1
+#define	reg_ce_fctrl_en_len 1
+#define	reg_ce_fctrl_en_lsb 0
+#define xd_p_reg_ce_fste_tdi	0xABC0
+#define	reg_ce_fste_tdi_pos 2
+#define	reg_ce_fste_tdi_len 1
+#define	reg_ce_fste_tdi_lsb 0
+#define xd_p_reg_ce_dynamic	0xABC0
+#define	reg_ce_dynamic_pos 3
+#define	reg_ce_dynamic_len 1
+#define	reg_ce_dynamic_lsb 0
+#define xd_p_reg_ce_conf	0xABC0
+#define	reg_ce_conf_pos 4
+#define	reg_ce_conf_len 2
+#define	reg_ce_conf_lsb 0
+#define xd_p_reg_ce_dyn12	0xABC0
+#define	reg_ce_dyn12_pos 6
+#define	reg_ce_dyn12_len 1
+#define	reg_ce_dyn12_lsb 0
+#define xd_p_reg_ce_derot_en	0xABC0
+#define	reg_ce_derot_en_pos 7
+#define	reg_ce_derot_en_len 1
+#define	reg_ce_derot_en_lsb 0
+#define xd_p_reg_ce_dynamic_th_7_0	0xABC1
+#define	reg_ce_dynamic_th_7_0_pos 0
+#define	reg_ce_dynamic_th_7_0_len 8
+#define	reg_ce_dynamic_th_7_0_lsb 0
+#define xd_p_reg_ce_dynamic_th_15_8	0xABC2
+#define	reg_ce_dynamic_th_15_8_pos 0
+#define	reg_ce_dynamic_th_15_8_len 8
+#define	reg_ce_dynamic_th_15_8_lsb 8
+#define xd_p_reg_ce_s1	0xABC3
+#define	reg_ce_s1_pos 0
+#define	reg_ce_s1_len 5
+#define	reg_ce_s1_lsb 0
+#define xd_p_reg_ce_var_forced_value	0xABC3
+#define	reg_ce_var_forced_value_pos 5
+#define	reg_ce_var_forced_value_len 3
+#define	reg_ce_var_forced_value_lsb 0
+#define xd_p_reg_ce_data_im_7_0	0xABC4
+#define	reg_ce_data_im_7_0_pos 0
+#define	reg_ce_data_im_7_0_len 8
+#define	reg_ce_data_im_7_0_lsb 0
+#define xd_p_reg_ce_data_im_8	0xABC5
+#define	reg_ce_data_im_8_pos 0
+#define	reg_ce_data_im_8_len 1
+#define	reg_ce_data_im_8_lsb 0
+#define xd_p_reg_ce_data_re_6_0	0xABC5
+#define	reg_ce_data_re_6_0_pos 1
+#define	reg_ce_data_re_6_0_len 7
+#define	reg_ce_data_re_6_0_lsb 0
+#define xd_p_reg_ce_data_re_8_7	0xABC6
+#define	reg_ce_data_re_8_7_pos 0
+#define	reg_ce_data_re_8_7_len 2
+#define	reg_ce_data_re_8_7_lsb 7
+#define xd_p_reg_ce_tone_5_0	0xABC6
+#define	reg_ce_tone_5_0_pos 2
+#define	reg_ce_tone_5_0_len 6
+#define	reg_ce_tone_5_0_lsb 0
+#define xd_p_reg_ce_tone_12_6	0xABC7
+#define	reg_ce_tone_12_6_pos 0
+#define	reg_ce_tone_12_6_len 7
+#define	reg_ce_tone_12_6_lsb 6
+#define xd_p_reg_ce_centroid_drift_th	0xABC8
+#define	reg_ce_centroid_drift_th_pos 0
+#define	reg_ce_centroid_drift_th_len 8
+#define	reg_ce_centroid_drift_th_lsb 0
+#define xd_p_reg_ce_centroid_count_max	0xABC9
+#define	reg_ce_centroid_count_max_pos 0
+#define	reg_ce_centroid_count_max_len 4
+#define	reg_ce_centroid_count_max_lsb 0
+#define xd_p_reg_ce_centroid_bias_inc_7_0	0xABCA
+#define	reg_ce_centroid_bias_inc_7_0_pos 0
+#define	reg_ce_centroid_bias_inc_7_0_len 8
+#define	reg_ce_centroid_bias_inc_7_0_lsb 0
+#define xd_p_reg_ce_centroid_bias_inc_8	0xABCB
+#define	reg_ce_centroid_bias_inc_8_pos 0
+#define	reg_ce_centroid_bias_inc_8_len 1
+#define	reg_ce_centroid_bias_inc_8_lsb 0
+#define xd_p_reg_ce_var_th0_7_0	0xABCC
+#define	reg_ce_var_th0_7_0_pos 0
+#define	reg_ce_var_th0_7_0_len 8
+#define	reg_ce_var_th0_7_0_lsb 0
+#define xd_p_reg_ce_var_th0_15_8	0xABCD
+#define	reg_ce_var_th0_15_8_pos 0
+#define	reg_ce_var_th0_15_8_len 8
+#define	reg_ce_var_th0_15_8_lsb 8
+#define xd_p_reg_ce_var_th1_7_0	0xABCE
+#define	reg_ce_var_th1_7_0_pos 0
+#define	reg_ce_var_th1_7_0_len 8
+#define	reg_ce_var_th1_7_0_lsb 0
+#define xd_p_reg_ce_var_th1_15_8	0xABCF
+#define	reg_ce_var_th1_15_8_pos 0
+#define	reg_ce_var_th1_15_8_len 8
+#define	reg_ce_var_th1_15_8_lsb 8
+#define xd_p_reg_ce_var_th2_7_0	0xABD0
+#define	reg_ce_var_th2_7_0_pos 0
+#define	reg_ce_var_th2_7_0_len 8
+#define	reg_ce_var_th2_7_0_lsb 0
+#define xd_p_reg_ce_var_th2_15_8	0xABD1
+#define	reg_ce_var_th2_15_8_pos 0
+#define	reg_ce_var_th2_15_8_len 8
+#define	reg_ce_var_th2_15_8_lsb 8
+#define xd_p_reg_ce_var_th3_7_0	0xABD2
+#define	reg_ce_var_th3_7_0_pos 0
+#define	reg_ce_var_th3_7_0_len 8
+#define	reg_ce_var_th3_7_0_lsb 0
+#define xd_p_reg_ce_var_th3_15_8	0xABD3
+#define	reg_ce_var_th3_15_8_pos 0
+#define	reg_ce_var_th3_15_8_len 8
+#define	reg_ce_var_th3_15_8_lsb 8
+#define xd_p_reg_ce_var_th4_7_0	0xABD4
+#define	reg_ce_var_th4_7_0_pos 0
+#define	reg_ce_var_th4_7_0_len 8
+#define	reg_ce_var_th4_7_0_lsb 0
+#define xd_p_reg_ce_var_th4_15_8	0xABD5
+#define	reg_ce_var_th4_15_8_pos 0
+#define	reg_ce_var_th4_15_8_len 8
+#define	reg_ce_var_th4_15_8_lsb 8
+#define xd_p_reg_ce_var_th5_7_0	0xABD6
+#define	reg_ce_var_th5_7_0_pos 0
+#define	reg_ce_var_th5_7_0_len 8
+#define	reg_ce_var_th5_7_0_lsb 0
+#define xd_p_reg_ce_var_th5_15_8	0xABD7
+#define	reg_ce_var_th5_15_8_pos 0
+#define	reg_ce_var_th5_15_8_len 8
+#define	reg_ce_var_th5_15_8_lsb 8
+#define xd_p_reg_ce_var_th6_7_0	0xABD8
+#define	reg_ce_var_th6_7_0_pos 0
+#define	reg_ce_var_th6_7_0_len 8
+#define	reg_ce_var_th6_7_0_lsb 0
+#define xd_p_reg_ce_var_th6_15_8	0xABD9
+#define	reg_ce_var_th6_15_8_pos 0
+#define	reg_ce_var_th6_15_8_len 8
+#define	reg_ce_var_th6_15_8_lsb 8
+#define xd_p_reg_ce_fctrl_reset	0xABDA
+#define	reg_ce_fctrl_reset_pos 0
+#define	reg_ce_fctrl_reset_len 1
+#define	reg_ce_fctrl_reset_lsb 0
+#define xd_p_reg_ce_cent_auto_clr_en	0xABDA
+#define	reg_ce_cent_auto_clr_en_pos 1
+#define	reg_ce_cent_auto_clr_en_len 1
+#define	reg_ce_cent_auto_clr_en_lsb 0
+#define xd_p_reg_ce_fctrl_auto_reset_en	0xABDA
+#define	reg_ce_fctrl_auto_reset_en_pos 2
+#define	reg_ce_fctrl_auto_reset_en_len 1
+#define	reg_ce_fctrl_auto_reset_en_lsb 0
+#define xd_p_reg_ce_var_forced_en	0xABDA
+#define	reg_ce_var_forced_en_pos 3
+#define	reg_ce_var_forced_en_len 1
+#define	reg_ce_var_forced_en_lsb 0
+#define xd_p_reg_ce_cent_forced_en	0xABDA
+#define	reg_ce_cent_forced_en_pos 4
+#define	reg_ce_cent_forced_en_len 1
+#define	reg_ce_cent_forced_en_lsb 0
+#define xd_p_reg_ce_var_max	0xABDA
+#define	reg_ce_var_max_pos 5
+#define	reg_ce_var_max_len 3
+#define	reg_ce_var_max_lsb 0
+#define xd_p_reg_ce_cent_forced_value_7_0	0xABDB
+#define	reg_ce_cent_forced_value_7_0_pos 0
+#define	reg_ce_cent_forced_value_7_0_len 8
+#define	reg_ce_cent_forced_value_7_0_lsb 0
+#define xd_p_reg_ce_cent_forced_value_11_8	0xABDC
+#define	reg_ce_cent_forced_value_11_8_pos 0
+#define	reg_ce_cent_forced_value_11_8_len 4
+#define	reg_ce_cent_forced_value_11_8_lsb 8
+#define xd_p_reg_ce_fctrl_rd	0xABDD
+#define	reg_ce_fctrl_rd_pos 0
+#define	reg_ce_fctrl_rd_len 1
+#define	reg_ce_fctrl_rd_lsb 0
+#define xd_p_reg_ce_centroid_max_6_0	0xABDD
+#define	reg_ce_centroid_max_6_0_pos 1
+#define	reg_ce_centroid_max_6_0_len 7
+#define	reg_ce_centroid_max_6_0_lsb 0
+#define xd_p_reg_ce_centroid_max_11_7	0xABDE
+#define	reg_ce_centroid_max_11_7_pos 0
+#define	reg_ce_centroid_max_11_7_len 5
+#define	reg_ce_centroid_max_11_7_lsb 7
+#define xd_p_reg_ce_var	0xABDF
+#define	reg_ce_var_pos 0
+#define	reg_ce_var_len 3
+#define	reg_ce_var_lsb 0
+#define xd_p_reg_ce_fctrl_rdy	0xABDF
+#define	reg_ce_fctrl_rdy_pos 3
+#define	reg_ce_fctrl_rdy_len 1
+#define	reg_ce_fctrl_rdy_lsb 0
+#define xd_p_reg_ce_centroid_out_3_0	0xABDF
+#define	reg_ce_centroid_out_3_0_pos 4
+#define	reg_ce_centroid_out_3_0_len 4
+#define	reg_ce_centroid_out_3_0_lsb 0
+#define xd_p_reg_ce_centroid_out_11_4	0xABE0
+#define	reg_ce_centroid_out_11_4_pos 0
+#define	reg_ce_centroid_out_11_4_len 8
+#define	reg_ce_centroid_out_11_4_lsb 4
+#define xd_p_reg_ce_bias_7_0	0xABE1
+#define	reg_ce_bias_7_0_pos 0
+#define	reg_ce_bias_7_0_len 8
+#define	reg_ce_bias_7_0_lsb 0
+#define xd_p_reg_ce_bias_11_8	0xABE2
+#define	reg_ce_bias_11_8_pos 0
+#define	reg_ce_bias_11_8_len 4
+#define	reg_ce_bias_11_8_lsb 8
+#define xd_p_reg_ce_m1_3_0	0xABE2
+#define	reg_ce_m1_3_0_pos 4
+#define	reg_ce_m1_3_0_len 4
+#define	reg_ce_m1_3_0_lsb 0
+#define xd_p_reg_ce_m1_11_4	0xABE3
+#define	reg_ce_m1_11_4_pos 0
+#define	reg_ce_m1_11_4_len 8
+#define	reg_ce_m1_11_4_lsb 4
+#define xd_p_reg_ce_rh0_7_0	0xABE4
+#define	reg_ce_rh0_7_0_pos 0
+#define	reg_ce_rh0_7_0_len 8
+#define	reg_ce_rh0_7_0_lsb 0
+#define xd_p_reg_ce_rh0_15_8	0xABE5
+#define	reg_ce_rh0_15_8_pos 0
+#define	reg_ce_rh0_15_8_len 8
+#define	reg_ce_rh0_15_8_lsb 8
+#define xd_p_reg_ce_rh0_23_16	0xABE6
+#define	reg_ce_rh0_23_16_pos 0
+#define	reg_ce_rh0_23_16_len 8
+#define	reg_ce_rh0_23_16_lsb 16
+#define xd_p_reg_ce_rh0_31_24	0xABE7
+#define	reg_ce_rh0_31_24_pos 0
+#define	reg_ce_rh0_31_24_len 8
+#define	reg_ce_rh0_31_24_lsb 24
+#define xd_p_reg_ce_rh3_real_7_0	0xABE8
+#define	reg_ce_rh3_real_7_0_pos 0
+#define	reg_ce_rh3_real_7_0_len 8
+#define	reg_ce_rh3_real_7_0_lsb 0
+#define xd_p_reg_ce_rh3_real_15_8	0xABE9
+#define	reg_ce_rh3_real_15_8_pos 0
+#define	reg_ce_rh3_real_15_8_len 8
+#define	reg_ce_rh3_real_15_8_lsb 8
+#define xd_p_reg_ce_rh3_real_23_16	0xABEA
+#define	reg_ce_rh3_real_23_16_pos 0
+#define	reg_ce_rh3_real_23_16_len 8
+#define	reg_ce_rh3_real_23_16_lsb 16
+#define xd_p_reg_ce_rh3_real_31_24	0xABEB
+#define	reg_ce_rh3_real_31_24_pos 0
+#define	reg_ce_rh3_real_31_24_len 8
+#define	reg_ce_rh3_real_31_24_lsb 24
+#define xd_p_reg_ce_rh3_imag_7_0	0xABEC
+#define	reg_ce_rh3_imag_7_0_pos 0
+#define	reg_ce_rh3_imag_7_0_len 8
+#define	reg_ce_rh3_imag_7_0_lsb 0
+#define xd_p_reg_ce_rh3_imag_15_8	0xABED
+#define	reg_ce_rh3_imag_15_8_pos 0
+#define	reg_ce_rh3_imag_15_8_len 8
+#define	reg_ce_rh3_imag_15_8_lsb 8
+#define xd_p_reg_ce_rh3_imag_23_16	0xABEE
+#define	reg_ce_rh3_imag_23_16_pos 0
+#define	reg_ce_rh3_imag_23_16_len 8
+#define	reg_ce_rh3_imag_23_16_lsb 16
+#define xd_p_reg_ce_rh3_imag_31_24	0xABEF
+#define	reg_ce_rh3_imag_31_24_pos 0
+#define	reg_ce_rh3_imag_31_24_len 8
+#define	reg_ce_rh3_imag_31_24_lsb 24
+#define xd_p_reg_feq_fix_eh2_7_0	0xABF0
+#define	reg_feq_fix_eh2_7_0_pos 0
+#define	reg_feq_fix_eh2_7_0_len 8
+#define	reg_feq_fix_eh2_7_0_lsb 0
+#define xd_p_reg_feq_fix_eh2_15_8	0xABF1
+#define	reg_feq_fix_eh2_15_8_pos 0
+#define	reg_feq_fix_eh2_15_8_len 8
+#define	reg_feq_fix_eh2_15_8_lsb 8
+#define xd_p_reg_feq_fix_eh2_23_16	0xABF2
+#define	reg_feq_fix_eh2_23_16_pos 0
+#define	reg_feq_fix_eh2_23_16_len 8
+#define	reg_feq_fix_eh2_23_16_lsb 16
+#define xd_p_reg_feq_fix_eh2_31_24	0xABF3
+#define	reg_feq_fix_eh2_31_24_pos 0
+#define	reg_feq_fix_eh2_31_24_len 8
+#define	reg_feq_fix_eh2_31_24_lsb 24
+#define xd_p_reg_ce_m2_central_7_0	0xABF4
+#define	reg_ce_m2_central_7_0_pos 0
+#define	reg_ce_m2_central_7_0_len 8
+#define	reg_ce_m2_central_7_0_lsb 0
+#define xd_p_reg_ce_m2_central_15_8	0xABF5
+#define	reg_ce_m2_central_15_8_pos 0
+#define	reg_ce_m2_central_15_8_len 8
+#define	reg_ce_m2_central_15_8_lsb 8
+#define xd_p_reg_ce_fftshift	0xABF6
+#define	reg_ce_fftshift_pos 0
+#define	reg_ce_fftshift_len 4
+#define	reg_ce_fftshift_lsb 0
+#define xd_p_reg_ce_fftshift1	0xABF6
+#define	reg_ce_fftshift1_pos 4
+#define	reg_ce_fftshift1_len 4
+#define	reg_ce_fftshift1_lsb 0
+#define xd_p_reg_ce_fftshift2	0xABF7
+#define	reg_ce_fftshift2_pos 0
+#define	reg_ce_fftshift2_len 4
+#define	reg_ce_fftshift2_lsb 0
+#define xd_p_reg_ce_top_mobile	0xABF7
+#define	reg_ce_top_mobile_pos 4
+#define	reg_ce_top_mobile_len 1
+#define	reg_ce_top_mobile_lsb 0
+#define xd_p_reg_strong_sginal_detected 0xA2BC
+#define reg_strong_sginal_detected_pos 2
+#define reg_strong_sginal_detected_len 1
+#define reg_strong_sginal_detected_lsb 0
+
+#define XD_MP2IF_BASE                           0xB000
+#define XD_MP2IF_CSR                        (0x00 + XD_MP2IF_BASE)
+#define XD_MP2IF_DMX_CTRL                       (0x03 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_IDX                        (0x04 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_DATA_L                     (0x05 + XD_MP2IF_BASE)
+#define XD_MP2IF_PID_DATA_H                     (0x06 + XD_MP2IF_BASE)
+#define XD_MP2IF_MISC                       (0x07 + XD_MP2IF_BASE)
+
+extern struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d);
+extern int af9005_read_ofdm_register(struct dvb_usb_device *d, u16 reg,
+				     u8 * value);
+extern int af9005_read_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+				      u8 * values, int len);
+extern int af9005_write_ofdm_register(struct dvb_usb_device *d, u16 reg,
+				      u8 value);
+extern int af9005_write_ofdm_registers(struct dvb_usb_device *d, u16 reg,
+				       u8 * values, int len);
+extern int af9005_read_tuner_registers(struct dvb_usb_device *d, u16 reg,
+				       u8 addr, u8 * values, int len);
+extern int af9005_write_tuner_registers(struct dvb_usb_device *d, u16 reg,
+					u8 * values, int len);
+extern int af9005_read_register_bits(struct dvb_usb_device *d, u16 reg,
+				     u8 pos, u8 len, u8 * value);
+extern int af9005_write_register_bits(struct dvb_usb_device *d, u16 reg,
+				      u8 pos, u8 len, u8 value);
+extern int af9005_send_command(struct dvb_usb_device *d, u8 command,
+			       u8 * wbuf, int wlen, u8 * rbuf, int rlen);
+extern int af9005_read_eeprom(struct dvb_usb_device *d, u8 address,
+			      u8 * values, int len);
+extern int af9005_tuner_attach(struct dvb_usb_adapter *adap);
+extern int af9005_led_control(struct dvb_usb_device *d, int onoff);
+
+extern u8 regmask[8];
+
+/* remote control decoder */
+extern int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len,
+			    u32 * event, int *state);
+extern struct dvb_usb_rc_key af9005_rc_keys[];
+extern int af9005_rc_keys_size;
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index bac2ae3..04e31cf 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -354,41 +354,35 @@
 /* Callbacks for DVB USB */
 static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
 {
-	u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
-	adap->pll_addr = 0x61;
-	memcpy(adap->pll_init, bpll, 4);
-	adap->pll_desc = &dvb_pll_fmd1216me;
-
-	adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
-	adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
-
+	dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
+		   DVB_PLL_FMD1216ME);
 	return 0;
 }
 
 static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap)
 {
 	dvb_attach(dvb_pll_attach, adap->fe, 0x61,
-		   NULL, &dvb_pll_thomson_dtt7579);
+		   NULL, DVB_PLL_THOMSON_DTT7579);
 	return 0;
 }
 
 static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap)
 {
-	dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, &dvb_pll_lg_z201);
+	dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_LG_Z201);
 	return 0;
 }
 
 static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
 {
 	dvb_attach(dvb_pll_attach, adap->fe, 0x60,
-		   NULL, &dvb_pll_thomson_dtt7579);
+		   NULL, DVB_PLL_THOMSON_DTT7579);
 	return 0;
 }
 
 static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
 {
 	dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
-		   &dvb_pll_lg_tdvs_h06xf);
+		   DVB_PLL_LG_TDVS_H06XF);
 	return 0;
 }
 
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
index cda3ade..4a903ea 100644
--- a/drivers/media/dvb/dvb-usb/dib0700.h
+++ b/drivers/media/dvb/dvb-usb/dib0700.h
@@ -30,17 +30,19 @@
 	// 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog)
 	// 2 Byte: MPEG2 mode:  4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1)
 	// 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines)    4LSB(     "                "           )
+#define REQUEST_SET_RC       0x11
 #define REQUEST_GET_VERSION  0x15
 
 struct dib0700_state {
 	u8 channel_state;
 	u16 mt2060_if1[2];
-
+	u8 rc_toggle;
 	u8 is_dib7000pc;
 };
 
 extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val);
 extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3);
+extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen);
 extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw);
 extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
 extern struct i2c_algorithm dib0700_i2c_algo;
@@ -50,5 +52,4 @@
 extern int dib0700_device_count;
 extern struct dvb_usb_device_properties dib0700_devices[];
 extern struct usb_device_id dib0700_usb_id_table[];
-
 #endif
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index dddf164..3ea294e 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -13,6 +13,10 @@
 module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
 
+static int dvb_usb_dib0700_ir_proto = 1;
+module_param(dvb_usb_dib0700_ir_proto, int, 0644);
+MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6).");
+
 /* expecting rx buffer: request data[0] data[1] ... data[2] */
 static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
 {
@@ -32,7 +36,7 @@
 }
 
 /* expecting tx buffer: request data[0] ... data[n] (n <= 4) */
-static int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
+int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
 {
 	u16 index, value;
 	int status;
@@ -260,14 +264,29 @@
 	return dib0700_ctrl_wr(adap->dev, b, 4);
 }
 
+static int dib0700_rc_setup(struct dvb_usb_device *d)
+{
+	u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0};
+	int i = dib0700_ctrl_wr(d, rc_setup, 3);
+	if (i<0) {
+		err("ir protocol setup failed");
+		return -1;
+	}
+	return 0;
+}
+
 static int dib0700_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
 	int i;
+	struct dvb_usb_device *dev;
 
 	for (i = 0; i < dib0700_device_count; i++)
-		if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, NULL) == 0)
+		if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, &dev) == 0)
+		{
+			dib0700_rc_setup(dev);
 			return 0;
+		}
 
 	return -ENODEV;
 }
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 2208757..e8c4a86 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -4,7 +4,7 @@
  *	under the terms of the GNU General Public License as published by the Free
  *	Software Foundation, version 2.
  *
- *  Copyright (C) 2005-6 DiBcom, SA
+ *  Copyright (C) 2005-7 DiBcom, SA
  */
 #include "dib0700.h"
 
@@ -12,13 +12,19 @@
 #include "dib7000m.h"
 #include "dib7000p.h"
 #include "mt2060.h"
+#include "mt2266.h"
+#include "dib0070.h"
 
 static int force_lna_activation;
 module_param(force_lna_activation, int, 0644);
 MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), "
 		"if applicable for the device (default: 0=automatic/off).");
 
-/* Hauppauge Nova-T 500
+struct dib0700_adapter_state {
+	int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *);
+};
+
+/* Hauppauge Nova-T 500 (aka Bristol)
  *  has a LNA on GPIO0 which is enabled by setting 1 */
 static struct mt2060_config bristol_mt2060_config[2] = {
 	{
@@ -96,6 +102,321 @@
 		st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0;
 }
 
+/* STK7700D: Pinnacle/Terratec/Hauppauge Dual DVB-T Diversity */
+
+/* MT226x */
+static struct dibx000_agc_config stk7700d_7000p_mt2266_agc_config[2] = {
+	{
+		BAND_UHF, // band_caps
+
+		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
+		* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+		(0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup
+
+		1130,  // inv_gain
+		21,  // time_stabiliz
+
+		0,  // alpha_level
+		118,  // thlock
+
+		0,     // wbd_inv
+		3530,  // wbd_ref
+		1,     // wbd_sel
+		0,     // wbd_alpha
+
+		65535,  // agc1_max
+		33770,  // agc1_min
+		65535,  // agc2_max
+		23592,  // agc2_min
+
+		0,    // agc1_pt1
+		62,   // agc1_pt2
+		255,  // agc1_pt3
+		64,   // agc1_slope1
+		64,   // agc1_slope2
+		132,  // agc2_pt1
+		192,  // agc2_pt2
+		80,   // agc2_slope1
+		80,   // agc2_slope2
+
+		17,  // alpha_mant
+		27,  // alpha_exp
+		23,  // beta_mant
+		51,  // beta_exp
+
+		1,  // perform_agc_softsplit
+	}, {
+		BAND_VHF | BAND_LBAND, // band_caps
+
+		/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=1, P_agc_inv_pwm2=1,
+		* P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+		(0 << 15) | (0 << 14) | (1 << 11) | (1 << 10) | (1 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup
+
+		2372, // inv_gain
+		21,   // time_stabiliz
+
+		0,    // alpha_level
+		118,  // thlock
+
+		0,    // wbd_inv
+		3530, // wbd_ref
+		1,     // wbd_sel
+		0,    // wbd_alpha
+
+		65535, // agc1_max
+		0,     // agc1_min
+		65535, // agc2_max
+		23592, // agc2_min
+
+		0,    // agc1_pt1
+		128,  // agc1_pt2
+		128,  // agc1_pt3
+		128,  // agc1_slope1
+		0,    // agc1_slope2
+		128,  // agc2_pt1
+		253,  // agc2_pt2
+		81,   // agc2_slope1
+		0,    // agc2_slope2
+
+		17,  // alpha_mant
+		27,  // alpha_exp
+		23,  // beta_mant
+		51,  // beta_exp
+
+		1,  // perform_agc_softsplit
+	}
+};
+
+static struct dibx000_bandwidth_config stk7700d_mt2266_pll_config = {
+	60000, 30000, // internal, sampling
+	1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass
+	0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo
+	(3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
+	0, // ifreq
+	20452225, // timf
+};
+
+static struct dib7000p_config stk7700d_dib7000p_mt2266_config[] = {
+	{	.output_mpeg2_in_188_bytes = 1,
+		.hostbus_diversity = 1,
+		.tuner_is_baseband = 1,
+
+		.agc_config_count = 2,
+		.agc = stk7700d_7000p_mt2266_agc_config,
+		.bw  = &stk7700d_mt2266_pll_config,
+
+		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+		.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+	},
+	{	.output_mpeg2_in_188_bytes = 1,
+		.hostbus_diversity = 1,
+		.tuner_is_baseband = 1,
+
+		.agc_config_count = 2,
+		.agc = stk7700d_7000p_mt2266_agc_config,
+		.bw  = &stk7700d_mt2266_pll_config,
+
+		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+		.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+	}
+};
+
+static struct mt2266_config stk7700d_mt2266_config[2] = {
+	{	.i2c_address = 0x60
+	},
+	{	.i2c_address = 0x60
+	}
+};
+
+static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	if (adap->id == 0) {
+		dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+		msleep(10);
+		dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+		dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+		dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+		msleep(10);
+		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+		msleep(10);
+		dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+		dib7000p_i2c_enumeration(&adap->dev->i2c_adap,2,18,stk7700d_dib7000p_mt2266_config);
+	}
+
+	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,0x80+(adap->id << 1),
+				&stk7700d_dib7000p_mt2266_config[adap->id]);
+
+	return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct i2c_adapter *tun_i2c;
+	tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+	return dvb_attach(mt2266_attach, adap->fe, tun_i2c,
+		&stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;;
+}
+
+#define DEFAULT_RC_INTERVAL 150
+
+static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
+
+static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+	u8 key[4];
+	int i;
+	struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+	struct dib0700_state *st = d->priv;
+	*event = 0;
+	*state = REMOTE_NO_KEY_PRESSED;
+	i=dib0700_ctrl_rd(d,rc_request,2,key,4);
+	if (i<=0) {
+		err("RC Query Failed");
+		return -1;
+	}
+	if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0;
+	if (key[3-1]!=st->rc_toggle) {
+		for (i=0;i<d->props.rc_key_map_size; i++) {
+			if (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) {
+				*event = keymap[i].event;
+				*state = REMOTE_KEY_PRESSED;
+				st->rc_toggle=key[3-1];
+				return 0;
+			}
+		}
+		err("Unknown remote controller key : %2X %2X",(int)key[3-2],(int)key[3-3]);
+	}
+	return 0;
+}
+
+static struct dvb_usb_rc_key dib0700_rc_keys[] = {
+	/* Key codes for the tiny Pinnacle remote*/
+	{ 0x07, 0x00, KEY_MUTE },
+	{ 0x07, 0x01, KEY_MENU }, // Pinnacle logo
+	{ 0x07, 0x39, KEY_POWER },
+	{ 0x07, 0x03, KEY_VOLUMEUP },
+	{ 0x07, 0x09, KEY_VOLUMEDOWN },
+	{ 0x07, 0x06, KEY_CHANNELUP },
+	{ 0x07, 0x0c, KEY_CHANNELDOWN },
+	{ 0x07, 0x0f, KEY_1 },
+	{ 0x07, 0x15, KEY_2 },
+	{ 0x07, 0x10, KEY_3 },
+	{ 0x07, 0x18, KEY_4 },
+	{ 0x07, 0x1b, KEY_5 },
+	{ 0x07, 0x1e, KEY_6 },
+	{ 0x07, 0x11, KEY_7 },
+	{ 0x07, 0x21, KEY_8 },
+	{ 0x07, 0x12, KEY_9 },
+	{ 0x07, 0x27, KEY_0 },
+	{ 0x07, 0x24, KEY_SCREEN }, // 'Square' key
+	{ 0x07, 0x2a, KEY_TEXT },   // 'T' key
+	{ 0x07, 0x2d, KEY_REWIND },
+	{ 0x07, 0x30, KEY_PLAY },
+	{ 0x07, 0x33, KEY_FASTFORWARD },
+	{ 0x07, 0x36, KEY_RECORD },
+	{ 0x07, 0x3c, KEY_STOP },
+	{ 0x07, 0x3f, KEY_CANCEL }, // '?' key
+	/* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */
+	{ 0xeb, 0x01, KEY_POWER },
+	{ 0xeb, 0x02, KEY_1 },
+	{ 0xeb, 0x03, KEY_2 },
+	{ 0xeb, 0x04, KEY_3 },
+	{ 0xeb, 0x05, KEY_4 },
+	{ 0xeb, 0x06, KEY_5 },
+	{ 0xeb, 0x07, KEY_6 },
+	{ 0xeb, 0x08, KEY_7 },
+	{ 0xeb, 0x09, KEY_8 },
+	{ 0xeb, 0x0a, KEY_9 },
+	{ 0xeb, 0x0b, KEY_VIDEO },
+	{ 0xeb, 0x0c, KEY_0 },
+	{ 0xeb, 0x0d, KEY_REFRESH },
+	{ 0xeb, 0x0f, KEY_EPG },
+	{ 0xeb, 0x10, KEY_UP },
+	{ 0xeb, 0x11, KEY_LEFT },
+	{ 0xeb, 0x12, KEY_OK },
+	{ 0xeb, 0x13, KEY_RIGHT },
+	{ 0xeb, 0x14, KEY_DOWN },
+	{ 0xeb, 0x16, KEY_INFO },
+	{ 0xeb, 0x17, KEY_RED },
+	{ 0xeb, 0x18, KEY_GREEN },
+	{ 0xeb, 0x19, KEY_YELLOW },
+	{ 0xeb, 0x1a, KEY_BLUE },
+	{ 0xeb, 0x1b, KEY_CHANNELUP },
+	{ 0xeb, 0x1c, KEY_VOLUMEUP },
+	{ 0xeb, 0x1d, KEY_MUTE },
+	{ 0xeb, 0x1e, KEY_VOLUMEDOWN },
+	{ 0xeb, 0x1f, KEY_CHANNELDOWN },
+	{ 0xeb, 0x40, KEY_PAUSE },
+	{ 0xeb, 0x41, KEY_HOME },
+	{ 0xeb, 0x42, KEY_MENU }, /* DVD Menu */
+	{ 0xeb, 0x43, KEY_SUBTITLE },
+	{ 0xeb, 0x44, KEY_TEXT }, /* Teletext */
+	{ 0xeb, 0x45, KEY_DELETE },
+	{ 0xeb, 0x46, KEY_TV },
+	{ 0xeb, 0x47, KEY_DVD },
+	{ 0xeb, 0x48, KEY_STOP },
+	{ 0xeb, 0x49, KEY_VIDEO },
+	{ 0xeb, 0x4a, KEY_AUDIO }, /* Music */
+	{ 0xeb, 0x4b, KEY_SCREEN }, /* Pic */
+	{ 0xeb, 0x4c, KEY_PLAY },
+	{ 0xeb, 0x4d, KEY_BACK },
+	{ 0xeb, 0x4e, KEY_REWIND },
+	{ 0xeb, 0x4f, KEY_FASTFORWARD },
+	{ 0xeb, 0x54, KEY_PREVIOUS },
+	{ 0xeb, 0x58, KEY_RECORD },
+	{ 0xeb, 0x5c, KEY_NEXT },
+
+	/* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */
+	{ 0x1e, 0x00, KEY_0 },
+	{ 0x1e, 0x01, KEY_1 },
+	{ 0x1e, 0x02, KEY_2 },
+	{ 0x1e, 0x03, KEY_3 },
+	{ 0x1e, 0x04, KEY_4 },
+	{ 0x1e, 0x05, KEY_5 },
+	{ 0x1e, 0x06, KEY_6 },
+	{ 0x1e, 0x07, KEY_7 },
+	{ 0x1e, 0x08, KEY_8 },
+	{ 0x1e, 0x09, KEY_9 },
+	{ 0x1e, 0x0a, KEY_KPASTERISK },
+	{ 0x1e, 0x0b, KEY_RED },
+	{ 0x1e, 0x0c, KEY_RADIO },
+	{ 0x1e, 0x0d, KEY_MENU },
+	{ 0x1e, 0x0e, KEY_GRAVE }, /* # */
+	{ 0x1e, 0x0f, KEY_MUTE },
+	{ 0x1e, 0x10, KEY_VOLUMEUP },
+	{ 0x1e, 0x11, KEY_VOLUMEDOWN },
+	{ 0x1e, 0x12, KEY_CHANNEL },
+	{ 0x1e, 0x14, KEY_UP },
+	{ 0x1e, 0x15, KEY_DOWN },
+	{ 0x1e, 0x16, KEY_LEFT },
+	{ 0x1e, 0x17, KEY_RIGHT },
+	{ 0x1e, 0x18, KEY_VIDEO },
+	{ 0x1e, 0x19, KEY_AUDIO },
+	{ 0x1e, 0x1a, KEY_MEDIA },
+	{ 0x1e, 0x1b, KEY_EPG },
+	{ 0x1e, 0x1c, KEY_TV },
+	{ 0x1e, 0x1e, KEY_NEXT },
+	{ 0x1e, 0x1f, KEY_BACK },
+	{ 0x1e, 0x20, KEY_CHANNELUP },
+	{ 0x1e, 0x21, KEY_CHANNELDOWN },
+	{ 0x1e, 0x24, KEY_LAST }, /* Skip backwards */
+	{ 0x1e, 0x25, KEY_OK },
+	{ 0x1e, 0x29, KEY_BLUE},
+	{ 0x1e, 0x2e, KEY_GREEN },
+	{ 0x1e, 0x30, KEY_PAUSE },
+	{ 0x1e, 0x32, KEY_REWIND },
+	{ 0x1e, 0x34, KEY_FASTFORWARD },
+	{ 0x1e, 0x35, KEY_PLAY },
+	{ 0x1e, 0x36, KEY_STOP },
+	{ 0x1e, 0x37, KEY_RECORD },
+	{ 0x1e, 0x38, KEY_YELLOW },
+	{ 0x1e, 0x3b, KEY_GOTO },
+	{ 0x1e, 0x3d, KEY_POWER },
+};
+
 /* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
 static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
 	BAND_UHF | BAND_VHF,       // band_caps
@@ -194,6 +515,7 @@
 	(3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
 	60258167, // ifreq
 	20452225, // timf
+	30000000, // xtal
 };
 
 static struct dib7000m_config stk7700p_dib7000m_config = {
@@ -213,6 +535,7 @@
 static struct dib7000p_config stk7700p_dib7000p_config = {
 	.output_mpeg2_in_188_bytes = 1,
 
+	.agc_config_count = 1,
 	.agc = &stk7700p_7000p_mt2060_agc_config,
 	.bw  = &stk7700p_pll_config,
 
@@ -267,27 +590,245 @@
 		st->mt2060_if1[0]) == NULL ? -ENODEV : 0;
 }
 
+/* DIB7070 generic */
+static struct dibx000_agc_config dib7070_agc_config = {
+	BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
+	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+	 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup
+
+	600, // inv_gain
+	10,  // time_stabiliz
+
+	0,  // alpha_level
+	118,  // thlock
+
+	0,     // wbd_inv
+	3530,  // wbd_ref
+	1,     // wbd_sel
+	5,     // wbd_alpha
+
+	65535,  // agc1_max
+		0,  // agc1_min
+
+	65535,  // agc2_max
+	0,      // agc2_min
+
+	0,      // agc1_pt1
+	40,     // agc1_pt2
+	183,    // agc1_pt3
+	206,    // agc1_slope1
+	255,    // agc1_slope2
+	72,     // agc2_pt1
+	152,    // agc2_pt2
+	88,     // agc2_slope1
+	90,     // agc2_slope2
+
+	17,  // alpha_mant
+	27,  // alpha_exp
+	23,  // beta_mant
+	51,  // beta_exp
+
+	0,  // perform_agc_softsplit
+};
+
+static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
+{
+	return dib7000p_set_gpio(fe, 8, 0, !onoff);
+}
+
+static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+	return dib7000p_set_gpio(fe, 9, 0, onoff);
+}
+
+static struct dib0070_config dib7070p_dib0070_config[2] = {
+	{
+		.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+		.reset = dib7070_tuner_reset,
+		.sleep = dib7070_tuner_sleep,
+		.clock_khz = 12000,
+		.clock_pad_drive = 4
+	}, {
+		.i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+		.reset = dib7070_tuner_reset,
+		.sleep = dib7070_tuner_sleep,
+		.clock_khz = 12000,
+
+	}
+};
+
+static int dib7070_set_param_override(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dib0700_adapter_state *state = adap->priv;
+
+	u16 offset;
+	u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+	switch (band) {
+		case BAND_VHF: offset = 950; break;
+		case BAND_UHF:
+		default: offset = 550; break;
+	}
+	deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
+	dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
+	return state->set_param_save(fe, fep);
+}
+
+static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dib0700_adapter_state *st = adap->priv;
+	struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+
+	if (adap->id == 0) {
+		if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL)
+			return -ENODEV;
+	} else {
+		if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, &dib7070p_dib0070_config[1]) == NULL)
+			return -ENODEV;
+	}
+
+	st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+	adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override;
+	return 0;
+}
+
+static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
+	60000, 15000, // internal, sampling
+	1, 20, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass
+	0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo
+	(3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
+	(0 << 25) | 0, // ifreq = 0.000000 MHz
+	20452225, // timf
+	12000000, // xtal_hz
+};
+
+static struct dib7000p_config dib7070p_dib7000p_config = {
+	.output_mpeg2_in_188_bytes = 1,
+
+	.agc_config_count = 1,
+	.agc = &dib7070_agc_config,
+	.bw  = &dib7070_bw_config_12_mhz,
+
+	.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+	.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+	.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+	.hostbus_diversity = 1,
+};
+
+/* STK7070P */
+static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+	dib0700_ctrl_clock(adap->dev, 72, 1);
+
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, &dib7070p_dib7000p_config);
+
+	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &dib7070p_dib7000p_config);
+	return adap->fe == NULL ? -ENODEV : 0;
+}
+
+/* STK7070PD */
+static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
+	{
+		.output_mpeg2_in_188_bytes = 1,
+
+		.agc_config_count = 1,
+		.agc = &dib7070_agc_config,
+		.bw  = &dib7070_bw_config_12_mhz,
+
+		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+		.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+		.hostbus_diversity = 1,
+	}, {
+		.output_mpeg2_in_188_bytes = 1,
+
+		.agc_config_count = 1,
+		.agc = &dib7070_agc_config,
+		.bw  = &dib7070_bw_config_12_mhz,
+
+		.gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+		.gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+		.gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+		.hostbus_diversity = 1,
+	}
+};
+
+static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap)
+{
+	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+	dib0700_ctrl_clock(adap->dev, 72, 1);
+
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, stk7070pd_dib7000p_config);
+
+	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]);
+	return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap)
+{
+	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]);
+	return adap->fe == NULL ? -ENODEV : 0;
+}
+
+/* DVB-USB and USB stuff follows */
 struct usb_device_id dib0700_usb_id_table[] = {
-		{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P) },
+/* 0 */	{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P) },
 		{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P_PC) },
 
 		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) },
 		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) },
 		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) },
-		{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
+/* 5 */	{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
 		{ USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500) },
 		{ USB_DEVICE(USB_VID_UNIWILL,   USB_PID_UNIWILL_STK7700P) },
 		{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P) },
 		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) },
-		{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
-		{ }		/* Terminating entry */
+/* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
+		{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV2000E) },
+		{ USB_DEVICE(USB_VID_TERRATEC,  USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) },
+		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) },
+		{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700D) },
+/* 15 */{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7070P) },
+		{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV_DVB_T_FLASH) },
+		{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7070PD) },
+		{ USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) },
+		{ USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500_PC) },
+/* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) },
+		{ 0 }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
 
 #define DIB0700_DEFAULT_DEVICE_PROPERTIES \
 	.caps              = DVB_USB_IS_AN_I2C_ADAPTER, \
 	.usb_ctrl          = DEVICE_SPECIFIC, \
-	.firmware          = "dvb-usb-dib0700-01.fw", \
+	.firmware          = "dvb-usb-dib0700-03-pre1.fw", \
 	.download_firmware = dib0700_download_firmware, \
 	.no_reconnect      = 1, \
 	.size_of_priv      = sizeof(struct dib0700_state), \
@@ -321,7 +862,7 @@
 			},
 		},
 
-		.num_device_descs = 6,
+		.num_device_descs = 7,
 		.devices = {
 			{   "DiBcom STK7700P reference design",
 				{ &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] },
@@ -336,7 +877,7 @@
 				{ NULL },
 			},
 			{   "Compro Videomate U500",
-				{ &dib0700_usb_id_table[6], NULL },
+				{ &dib0700_usb_id_table[6], &dib0700_usb_id_table[19] },
 				{ NULL },
 			},
 			{   "Uniwill STK7700P based (Hama and others)",
@@ -346,8 +887,17 @@
 			{   "Leadtek Winfast DTV Dongle (STK7700P based)",
 				{ &dib0700_usb_id_table[8], NULL },
 				{ NULL },
+			},
+			{   "AVerMedia AVerTV DVB-T Express",
+				{ &dib0700_usb_id_table[20] },
+				{ NULL },
 			}
-		}
+		},
+
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_key_map       = dib0700_rc_keys,
+		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_query         = dib0700_rc_query
 	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 
 		.num_adapters = 2,
@@ -371,8 +921,112 @@
 				{ &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL },
 				{ NULL },
 			},
+		},
+
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_key_map       = dib0700_rc_keys,
+		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_query         = dib0700_rc_query
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 2,
+		.adapter = {
+			{
+				.frontend_attach  = stk7700d_frontend_attach,
+				.tuner_attach     = stk7700d_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+			}, {
+				.frontend_attach  = stk7700d_frontend_attach,
+				.tuner_attach     = stk7700d_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+			}
+		},
+
+		.num_device_descs = 4,
+		.devices = {
+			{   "Pinnacle PCTV 2000e",
+				{ &dib0700_usb_id_table[11], NULL },
+				{ NULL },
+			},
+			{   "Terratec Cinergy DT XS Diversity",
+				{ &dib0700_usb_id_table[12], NULL },
+				{ NULL },
+			},
+			{   "Hauppauge Nova-TD Stick/Elgato Eye-TV Diversity",
+				{ &dib0700_usb_id_table[13], NULL },
+				{ NULL },
+			},
+			{   "DiBcom STK7700D reference design",
+				{ &dib0700_usb_id_table[14], NULL },
+				{ NULL },
+			},
+		},
+
+		.rc_interval      = DEFAULT_RC_INTERVAL,
+		.rc_key_map       = dib0700_rc_keys,
+		.rc_key_map_size  = ARRAY_SIZE(dib0700_rc_keys),
+		.rc_query         = dib0700_rc_query
+
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 1,
+		.adapter = {
+			{
+				.frontend_attach  = stk7070p_frontend_attach,
+				.tuner_attach     = dib7070p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+				.size_of_priv     = sizeof(struct dib0700_adapter_state),
+			},
+		},
+
+		.num_device_descs = 2,
+		.devices = {
+			{   "DiBcom STK7070P reference design",
+				{ &dib0700_usb_id_table[15], NULL },
+				{ NULL },
+			},
+			{   "Pinnacle PCTV DVB-T Flash Stick",
+				{ &dib0700_usb_id_table[16], NULL },
+				{ NULL },
+			},
 		}
-	}
+	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+		.num_adapters = 2,
+		.adapter = {
+			{
+				.frontend_attach  = stk7070pd_frontend_attach0,
+				.tuner_attach     = dib7070p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+				.size_of_priv     = sizeof(struct dib0700_adapter_state),
+			}, {
+				.frontend_attach  = stk7070pd_frontend_attach1,
+				.tuner_attach     = dib7070p_tuner_attach,
+
+				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+
+				.size_of_priv     = sizeof(struct dib0700_adapter_state),
+			}
+		},
+
+		.num_device_descs = 2,
+		.devices = {
+			{   "DiBcom STK7070PD reference design",
+				{ &dib0700_usb_id_table[17], NULL },
+				{ NULL },
+			},
+			{   "Pinnacle PCTV Dual DVB-T Diversity Stick",
+				{ &dib0700_usb_id_table[18], NULL },
+				{ NULL },
+			},
+		}
+	},
 };
 
 int dib0700_device_count = ARRAY_SIZE(dib0700_devices);
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index 5143e42..9a184da 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -295,7 +295,7 @@
 	tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
 	if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) {
 		/* not found - use panasonic pll parameters */
-		if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, &dvb_pll_env57h1xd5) == NULL)
+		if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, DVB_PLL_ENV57H1XD5) == NULL)
 			return -ENOMEM;
 	} else {
 		st->mt2060_present = 1;
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index 7a6ae8f..043cada 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -14,6 +14,14 @@
  */
 #include "dibusb.h"
 
+static int dib3000mb_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct dibusb_state *st = adap->priv;
+
+	return st->ops.tuner_pass_ctrl(fe, enable, st->tuner_addr);
+}
+
 static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	struct dib3000_config demod_cfg;
@@ -21,21 +29,34 @@
 
 	demod_cfg.demod_address = 0x8;
 
-	if ((adap->fe = dib3000mb_attach(&demod_cfg,&adap->dev->i2c_adap,&st->ops)) == NULL)
+	if ((adap->fe = dvb_attach(dib3000mb_attach, &demod_cfg,
+				   &adap->dev->i2c_adap, &st->ops)) == NULL)
 		return -ENODEV;
 
-	adap->fe->ops.tuner_ops.init       = dvb_usb_tuner_init_i2c;
-	adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
-
-	adap->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
+	adap->fe->ops.i2c_gate_ctrl = dib3000mb_i2c_gate_ctrl;
 
 	return 0;
 }
 
 static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap)
 {
-	adap->pll_addr = 0x61;
-	adap->pll_desc = &dvb_pll_tua6010xs;
+	struct dibusb_state *st = adap->priv;
+
+	st->tuner_addr = 0x61;
+
+	dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
+		   DVB_PLL_TUA6010XS);
+	return 0;
+}
+
+static int dibusb_panasonic_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct dibusb_state *st = adap->priv;
+
+	st->tuner_addr = 0x60;
+
+	dvb_attach(dvb_pll_attach, adap->fe, 0x60, &adap->dev->i2c_adap,
+		   DVB_PLL_TDA665X);
 	return 0;
 }
 
@@ -50,30 +71,28 @@
 		{ .flags = 0,        .buf = b,  .len = 2 },
 		{ .flags = I2C_M_RD, .buf = b2, .len = 1 },
 	};
+	struct dibusb_state *st = adap->priv;
 
 	/* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */
-	msg[0].addr = msg[1].addr = 0x60;
+	msg[0].addr = msg[1].addr = st->tuner_addr = 0x60;
 
-	if (adap->tuner_pass_ctrl)
-		adap->tuner_pass_ctrl(adap->fe,1,msg[0].addr);
+	if (adap->fe->ops.i2c_gate_ctrl)
+		adap->fe->ops.i2c_gate_ctrl(adap->fe,1);
 
 	if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) {
 		err("tuner i2c write failed.");
 		ret = -EREMOTEIO;
 	}
 
-	if (adap->tuner_pass_ctrl)
-		adap->tuner_pass_ctrl(adap->fe,0,msg[0].addr);
+	if (adap->fe->ops.i2c_gate_ctrl)
+		adap->fe->ops.i2c_gate_ctrl(adap->fe,0);
 
 	if (b2[0] == 0xfe) {
 		info("This device has the Thomson Cable onboard. Which is default.");
-		dibusb_thomson_tuner_attach(adap);
+		ret = dibusb_thomson_tuner_attach(adap);
 	} else {
-		u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
 		info("This device has the Panasonic ENV77H11D5 onboard.");
-		adap->pll_addr = 0x60;
-		memcpy(adap->pll_init,bpll,4);
-		adap->pll_desc = &dvb_pll_tda665x;
+		ret = dibusb_panasonic_tuner_attach(adap);
 	}
 
 	return ret;
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h
index b607810..8e847aa 100644
--- a/drivers/media/dvb/dvb-usb/dibusb.h
+++ b/drivers/media/dvb/dvb-usb/dibusb.h
@@ -99,6 +99,7 @@
 struct dibusb_state {
 	struct dib_fe_xfer_ops ops;
 	int mt2060_present;
+	u8 tuner_addr;
 };
 
 struct dibusb_device_state {
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index b5acb11..bca1e09 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -118,7 +118,8 @@
 {
 	struct dvb_usb_adapter *adap = fe->dvb->priv;
 	u8 b[5];
-	dvb_usb_tuner_calc_regs(fe,fep,b, 5);
+
+	fe->ops.tuner_ops.calc_regs(fe, fep, b, sizeof(b));
 	if (fe->ops.i2c_gate_ctrl)
 		fe->ops.i2c_gate_ctrl(fe, 1);
 	return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0);
@@ -130,12 +131,14 @@
 
 static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
 {
+	struct digitv_state *st = adap->dev->priv;
+
 	if ((adap->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) {
-		adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+		st->is_nxt6000 = 0;
 		return 0;
 	}
 	if ((adap->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) {
-		adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+		st->is_nxt6000 = 1;
 		return 0;
 	}
 	return -EIO;
@@ -143,8 +146,14 @@
 
 static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
 {
-	adap->pll_addr = 0x60;
-	adap->pll_desc = &dvb_pll_tded4;
+	struct digitv_state *st = adap->dev->priv;
+
+	if (!dvb_attach(dvb_pll_attach, adap->fe, 0x60, NULL, DVB_PLL_TDED4))
+		return -ENODEV;
+
+	if (st->is_nxt6000)
+		adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+
 	return 0;
 }
 
@@ -273,6 +282,8 @@
 	.usb_ctrl = CYPRESS_FX2,
 	.firmware = "dvb-usb-digitv-02.fw",
 
+	.size_of_priv = sizeof(struct digitv_state),
+
 	.num_adapters = 1,
 	.adapter = {
 		{
diff --git a/drivers/media/dvb/dvb-usb/digitv.h b/drivers/media/dvb/dvb-usb/digitv.h
index 477ee42..8b43e3d 100644
--- a/drivers/media/dvb/dvb-usb/digitv.h
+++ b/drivers/media/dvb/dvb-usb/digitv.h
@@ -4,6 +4,10 @@
 #define DVB_USB_LOG_PREFIX "digitv"
 #include "dvb-usb.h"
 
+struct digitv_state {
+    int is_nxt6000;
+};
+
 extern int dvb_usb_digitv_debug;
 #define deb_rc(args...)   dprintk(dvb_usb_digitv_debug,0x01,args)
 
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
index 7dbe143..d86cf9b 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -1,5 +1,5 @@
 /* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/
- * Typhoon/ Yuan DVB-T USB2.0 receiver.
+ * Typhoon/ Yuan/ Miglia DVB-T USB2.0 receiver.
  *
  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
  *
@@ -96,6 +96,7 @@
 static struct dvb_usb_device_properties wt220u_fc_properties;
 static struct dvb_usb_device_properties wt220u_properties;
 static struct dvb_usb_device_properties wt220u_zl0353_properties;
+static struct dvb_usb_device_properties wt220u_miglia_properties;
 
 static int dtt200u_usb_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
@@ -103,7 +104,8 @@
 	if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE,NULL) == 0 ||
 		dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0 ||
 		dvb_usb_device_init(intf,&wt220u_fc_properties,THIS_MODULE,NULL) == 0 ||
-		dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0)
+		dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0 ||
+		dvb_usb_device_init(intf,&wt220u_miglia_properties,THIS_MODULE,NULL) == 0)
 		return 0;
 
 	return -ENODEV;
@@ -119,6 +121,7 @@
 	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD)  },
 	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM)  },
 	{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD)  },
+	{ USB_DEVICE(USB_VID_MIGLIA, USB_PID_WT220U_ZAP250_COLD)  },
 	{ 0 },
 };
 MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
@@ -303,6 +306,25 @@
 	}
 };
 
+static struct dvb_usb_device_properties wt220u_miglia_properties = {
+	.usb_ctrl = CYPRESS_FX2,
+	.firmware = "dvb-usb-wt220u-miglia-01.fw",
+
+	.num_adapters = 1,
+	.generic_bulk_ctrl_endpoint = 0x01,
+
+	.num_device_descs = 1,
+	.devices = {
+		{ .name = "WideView WT-220U PenType Receiver (Miglia)",
+		  .cold_ids = { &dtt200u_usb_table[9], NULL },
+		  /* This device turns into WT220U_ZL0353_WARM when fw
+		     has been uploaded */
+		  .warm_ids = { NULL },
+		},
+		{ NULL },
+	}
+};
+
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver dtt200u_usb_driver = {
 	.name		= "dvb_usb_dtt200u",
@@ -333,6 +355,6 @@
 module_exit(dtt200u_usb_module_exit);
 
 MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D DVB-T USB2.0 devices");
+MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D/Miglia DVB-T USB2.0 devices");
 MODULE_VERSION("1.0");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index 088b6de..23428cd3 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -46,82 +46,3 @@
 	d->state &= ~DVB_USB_STATE_I2C;
 	return 0;
 }
-
-int dvb_usb_tuner_init_i2c(struct dvb_frontend *fe)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = adap->pll_init, .len = 4 };
-	int ret = 0;
-
-	/* if pll_desc is not used */
-	if (adap->pll_desc == NULL)
-		return 0;
-
-	if (adap->tuner_pass_ctrl)
-		adap->tuner_pass_ctrl(fe, 1, adap->pll_addr);
-
-	deb_pll("pll init: %x\n",adap->pll_addr);
-	deb_pll("pll-buf: %x %x %x %x\n",adap->pll_init[0], adap->pll_init[1],
-			adap->pll_init[2], adap->pll_init[3]);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer (&adap->dev->i2c_adap, &msg, 1) != 1) {
-		err("tuner i2c write failed for pll_init.");
-		ret = -EREMOTEIO;
-	}
-	msleep(1);
-
-	if (adap->tuner_pass_ctrl)
-		adap->tuner_pass_ctrl(fe,0,adap->pll_addr);
-	return ret;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_init_i2c);
-
-int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-
-	if (buf_len != 5)
-		return -EINVAL;
-	if (adap->pll_desc == NULL)
-		return 0;
-
-	deb_pll("pll addr: %x, freq: %d %p\n",adap->pll_addr, fep->frequency, adap->pll_desc);
-
-	b[0] = adap->pll_addr;
-	dvb_pll_configure(adap->pll_desc, &b[1], fep->frequency, fep->u.ofdm.bandwidth);
-
-	deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]);
-
-	return 5;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_calc_regs);
-
-int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
-{
-	struct dvb_usb_adapter *adap = fe->dvb->priv;
-	int ret = 0;
-	u8 b[5];
-	struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
-
-	dvb_usb_tuner_calc_regs(fe,fep,b,5);
-
-	if (adap->tuner_pass_ctrl)
-		adap->tuner_pass_ctrl(fe, 1, adap->pll_addr);
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-
-	if (i2c_transfer(&adap->dev->i2c_adap, &msg, 1) != 1) {
-		err("tuner i2c write failed for pll_set.");
-		ret = -EREMOTEIO;
-	}
-	msleep(1);
-
-	if (adap->tuner_pass_ctrl)
-		adap->tuner_pass_ctrl(fe, 0, adap->pll_addr);
-
-	return ret;
-}
-EXPORT_SYMBOL(dvb_usb_tuner_set_params_i2c);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 4030816..4fa3e89 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -11,7 +11,9 @@
 
 /* Vendor IDs */
 #define USB_VID_ADSTECH				0x06e1
-#define USB_VID_ALCOR_MICRO		0x058f
+#define USB_VID_AFATECH				0x15a4
+#define USB_VID_ALCOR_MICRO			0x058f
+#define USB_VID_ALINK				0x05e3
 #define USB_VID_ANCHOR				0x0547
 #define USB_VID_ANUBIS_ELECTRONIC		0x10fd
 #define USB_VID_AVERMEDIA			0x07ca
@@ -32,9 +34,11 @@
 #define USB_VID_LEADTEK				0x0413
 #define USB_VID_LITEON				0x04ca
 #define USB_VID_MEDION				0x1660
+#define USB_VID_MIGLIA				0x18f3
 #define USB_VID_MSI				0x0db0
 #define USB_VID_OPERA1				0x695c
 #define USB_VID_PINNACLE			0x2304
+#define USB_VID_TERRATEC			0x0ccd
 #define USB_VID_VISIONPLUS			0x13d3
 #define USB_VID_TWINHAN				0x1822
 #define USB_VID_ULTIMA_ELECTRONIC		0x05d8
@@ -44,6 +48,8 @@
 /* Product IDs */
 #define USB_PID_ADSTECH_USB2_COLD			0xa333
 #define USB_PID_ADSTECH_USB2_WARM			0xa334
+#define USB_PID_AFATECH_AF9005				0x9020
+#define USB_VID_ALINK_DTU				0xf170
 #define USB_PID_AVERMEDIA_DVBT_USB_COLD			0x0001
 #define USB_PID_AVERMEDIA_DVBT_USB_WARM			0x0002
 #define USB_PID_AVERMEDIA_DVBT_USB2_COLD		0xa800
@@ -53,6 +59,7 @@
 #define USB_PID_COMPRO_DVBU2000_UNK_COLD		0x010c
 #define USB_PID_COMPRO_DVBU2000_UNK_WARM		0x010d
 #define USB_PID_COMPRO_VIDEOMATE_U500			0x1e78
+#define USB_PID_COMPRO_VIDEOMATE_U500_PC		0x1e80
 #define USB_PID_DIBCOM_HOOK_DEFAULT			0x0064
 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM		0x0065
 #define USB_PID_DIBCOM_MOD3000_COLD			0x0bb8
@@ -61,6 +68,9 @@
 #define USB_PID_DIBCOM_MOD3001_WARM			0x0bc7
 #define USB_PID_DIBCOM_STK7700P				0x1e14
 #define USB_PID_DIBCOM_STK7700P_PC			0x1e78
+#define USB_PID_DIBCOM_STK7700D				0x1ef0
+#define USB_PID_DIBCOM_STK7070P				0x1ebc
+#define USB_PID_DIBCOM_STK7070PD			0x1ebe
 #define USB_PID_DIBCOM_ANCHOR_2135_COLD			0x2131
 #define USB_PID_DPOSH_M9206_COLD			0x9206
 #define USB_PID_DPOSH_M9206_WARM			0xa090
@@ -69,6 +79,7 @@
 #define USB_PID_GRANDTEC_DVBT_USB_WARM			0x0fa1
 #define USB_PID_KWORLD_VSTREAM_COLD			0x17de
 #define USB_PID_KWORLD_VSTREAM_WARM			0x17df
+#define USB_PID_TERRATEC_CINERGY_T_USB_XE		0x0055
 #define USB_PID_TWINHAN_VP7041_COLD			0x3201
 #define USB_PID_TWINHAN_VP7041_WARM			0x3202
 #define USB_PID_TWINHAN_VP7020_COLD			0x3203
@@ -109,8 +120,17 @@
 #define USB_PID_HAUPPAUGE_NOVA_T_500_2			0x9950
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK			0x7050
 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2		0x7060
+#define USB_PID_HAUPPAUGE_NOVA_TD_STICK			0x9580
+#define USB_PID_AVERMEDIA_EXPRESS			0xb568
 #define USB_PID_AVERMEDIA_VOLAR				0xa807
 #define USB_PID_AVERMEDIA_VOLAR_2			0xb808
+#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY	0x005a
+#define USB_PID_PINNACLE_PCTV2000E			0x022c
+#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH		0x0228
+#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T	0x0229
+#define USB_PID_PCTV_200E				0x020e
+#define USB_PID_PCTV_400E				0x020f
+#define USB_PID_PCTV_450E				0x0222
 #define USB_PID_NEBULA_DIGITV				0x0201
 #define USB_PID_DVICO_BLUEBIRD_LGDT			0xd820
 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD		0xd500
@@ -130,9 +150,6 @@
 #define USB_PID_MSI_MEGASKY580_55801			0x5581
 #define USB_PID_KYE_DVB_T_COLD				0x701e
 #define USB_PID_KYE_DVB_T_WARM				0x701f
-#define USB_PID_PCTV_200E				0x020e
-#define USB_PID_PCTV_400E				0x020f
-#define USB_PID_PCTV_450E				0x0222
 #define USB_PID_LITEON_DVB_T_COLD			0xf000
 #define USB_PID_LITEON_DVB_T_WARM			0xf001
 #define USB_PID_DIGIVOX_MINI_SL_COLD			0xe360
@@ -142,8 +159,11 @@
 #define USB_PID_WINFAST_DTV_DONGLE_COLD			0x6025
 #define USB_PID_WINFAST_DTV_DONGLE_WARM			0x6026
 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P		0x6f00
-#define USB_PID_GENPIX_8PSK_COLD			0x0200
-#define USB_PID_GENPIX_8PSK_WARM			0x0201
+#define USB_PID_GENPIX_8PSK_REV_1_COLD			0x0200
+#define USB_PID_GENPIX_8PSK_REV_1_WARM			0x0201
+#define USB_PID_GENPIX_8PSK_REV_2			0x0202
+#define USB_PID_GENPIX_SKYWALKER_1			0x0203
+#define USB_PID_GENPIX_SKYWALKER_CW3K			0x0204
 #define USB_PID_SIGMATEK_DVB_110			0x6610
 #define USB_PID_MSI_DIGI_VOX_MINI_II			0x1513
 #define USB_PID_OPERA1_COLD				0x2830
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
index ffdde83..cdd717c 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
@@ -24,7 +24,7 @@
 
 static int dvb_usb_force_pid_filter_usage;
 module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444);
-MODULE_PARM_DESC(disable_rc_polling, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
+MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
 
 static int dvb_usb_adapter_init(struct dvb_usb_device *d)
 {
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 9200a30..7b9f35b 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -110,7 +110,7 @@
 	input_dev->name = "IR-receiver inside an USB DVB receiver";
 	input_dev->phys = d->rc_phys;
 	usb_to_input_id(d->udev, &input_dev->id);
-	input_dev->cdev.dev = &d->udev->dev;
+	input_dev->dev.parent = &d->udev->dev;
 
 	/* set the bits for the keys */
 	deb_rc("key map size: %d\n", d->props.rc_key_map_size);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index 6f824a5..d1b3c7b 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -297,12 +297,6 @@
 	int feedcount;
 	int pid_filtering;
 
-	/* tuner programming information */
-	u8 pll_addr;
-	u8 pll_init[4];
-	struct dvb_pll_desc *pll_desc;
-	int (*tuner_pass_ctrl) (struct dvb_frontend *, int, u8);
-
 	/* dvb */
 	struct dvb_adapter   dvb_adap;
 	struct dmxdev        dmxdev;
@@ -388,11 +382,6 @@
 /* commonly used remote control parsing */
 extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
 
-/* commonly used pll init and set functions */
-extern int dvb_usb_tuner_init_i2c(struct dvb_frontend *);
-extern int dvb_usb_tuner_calc_regs(struct dvb_frontend *, struct dvb_frontend_parameters *, u8 *buf, int buf_len);
-extern int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
-
 /* commonly used firmware download types and function */
 struct hexline {
 	u8 len;
diff --git a/drivers/media/dvb/dvb-usb/gl861.c b/drivers/media/dvb/dvb-usb/gl861.c
index e0587e6..f01d99c 100644
--- a/drivers/media/dvb/dvb-usb/gl861.c
+++ b/drivers/media/dvb/dvb-usb/gl861.c
@@ -157,6 +157,7 @@
 
 static struct usb_device_id gl861_table [] = {
 		{ USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) },
+		{ USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) },
 		{ }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, gl861_table);
@@ -187,12 +188,16 @@
 	}},
 	.i2c_algo         = &gl861_i2c_algo,
 
-	.num_device_descs = 1,
+	.num_device_descs = 2,
 	.devices = {
 		{   "MSI Mega Sky 55801 DVB-T USB2.0",
 			{ &gl861_table[0], NULL },
 			{ NULL },
 		},
+		{   "A-LINK DTU DVB-T USB2.0",
+			{ &gl861_table[1], NULL },
+			{ NULL },
+		},
 	}
 };
 
diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
index 6ccbdc9..e37142d 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
@@ -1,7 +1,8 @@
 /* DVB USB compliant Linux driver for the
- *  - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *  - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
  *
- * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com)
  *
  * Thanks to GENPIX for the sample code used to implement this module.
  *
@@ -17,27 +18,39 @@
 
 struct gp8psk_fe_state {
 	struct dvb_frontend fe;
-
 	struct dvb_usb_device *d;
-
+	u8 lock;
 	u16 snr;
-
-	unsigned long next_snr_check;
+	unsigned long next_status_check;
+	unsigned long status_check_interval;
 };
 
+static int gp8psk_fe_update_status(struct gp8psk_fe_state *st)
+{
+	u8 buf[6];
+	if (time_after(jiffies,st->next_status_check)) {
+		gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1);
+		gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6);
+		st->snr = (buf[1]) << 8 | buf[0];
+		st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
+	}
+	return 0;
+}
+
 static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
 {
 	struct gp8psk_fe_state *st = fe->demodulator_priv;
-	u8 lock;
+	gp8psk_fe_update_status(st);
 
-	if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1))
-		return -EINVAL;
-
-	if (lock)
+	if (st->lock)
 		*status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
 	else
 		*status = 0;
 
+	if (*status & FE_HAS_LOCK)
+		st->status_check_interval = 1000;
+	else
+		st->status_check_interval = 100;
 	return 0;
 }
 
@@ -60,33 +73,29 @@
 static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
 {
 	struct gp8psk_fe_state *st = fe->demodulator_priv;
-	u8 buf[2];
-
-	if (time_after(jiffies,st->next_snr_check)) {
-		gp8psk_usb_in_op(st->d,GET_SIGNAL_STRENGTH,0,0,buf,2);
-		*snr = (int)(buf[1]) << 8 | buf[0];
-		/* snr is reported in dBu*256 */
-		/* snr / 38.4 ~= 100% strength */
-		/* snr * 17 returns 100% strength as 65535 */
-		if (*snr <= 3855)
-			*snr = (*snr<<4) + *snr; // snr * 17
-		else
-			*snr = 65535;
-		st->next_snr_check = jiffies + (10*HZ)/1000;
-	} else {
-		*snr = st->snr;
-	}
+	gp8psk_fe_update_status(st);
+	/* snr is reported in dBu*256 */
+	*snr = st->snr;
 	return 0;
 }
 
 static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
 {
-	return gp8psk_fe_read_snr(fe, strength);
+	struct gp8psk_fe_state *st = fe->demodulator_priv;
+	gp8psk_fe_update_status(st);
+	/* snr is reported in dBu*256 */
+	/* snr / 38.4 ~= 100% strength */
+	/* snr * 17 returns 100% strength as 65535 */
+	if (st->snr > 0xf00)
+		*strength = 0xffff;
+	else
+		*strength = (st->snr << 4) + st->snr; /* snr*17 */
+	return 0;
 }
 
 static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
 {
-	tune->min_delay_ms = 800;
+	tune->min_delay_ms = 200;
 	return 0;
 }
 
@@ -124,7 +133,9 @@
 
 	gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
 
-	state->next_snr_check = jiffies;
+	state->lock = 0;
+	state->next_status_check = jiffies;
+	state->status_check_interval = 200;
 
 	return 0;
 }
@@ -190,6 +201,12 @@
 	return 0;
 }
 
+static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff)
+{
+	struct gp8psk_fe_state* state = fe->demodulator_priv;
+	return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0);
+}
+
 static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd)
 {
 	struct gp8psk_fe_state* state = fe->demodulator_priv;
@@ -235,10 +252,10 @@
 
 static struct dvb_frontend_ops gp8psk_fe_ops = {
 	.info = {
-		.name			= "Genpix 8psk-USB DVB-S",
+		.name			= "Genpix 8psk-to-USB2 DVB-S",
 		.type			= FE_QPSK,
-		.frequency_min		= 950000,
-		.frequency_max		= 2150000,
+		.frequency_min		= 800000,
+		.frequency_max		= 2250000,
 		.frequency_stepsize	= 100,
 		.symbol_rate_min        = 1000000,
 		.symbol_rate_max        = 45000000,
@@ -269,4 +286,5 @@
 	.set_tone = gp8psk_fe_set_tone,
 	.set_voltage = gp8psk_fe_set_voltage,
 	.dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd,
+	.enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage
 };
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
index 518d67f..92147ee 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -1,7 +1,8 @@
 /* DVB USB compliant Linux driver for the
- *  - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *  - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
  *
- * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com)
  *
  * Thanks to GENPIX for the sample code used to implement this module.
  *
@@ -40,7 +41,7 @@
 	}
 
 	if (ret < 0 || ret != blen) {
-		warn("usb in operation failed.");
+		warn("usb in %d operation failed.", req);
 		ret = -EIO;
 	} else
 		ret = 0;
@@ -97,10 +98,10 @@
 	if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0))
 		goto out_rel_fw;
 
-	info("downloaidng bcm4500 firmware from file '%s'",bcm4500_firmware);
+	info("downloading bcm4500 firmware from file '%s'",bcm4500_firmware);
 
 	ptr = fw->data;
-	buf = kmalloc(512, GFP_KERNEL | GFP_DMA);
+	buf = kmalloc(64, GFP_KERNEL | GFP_DMA);
 
 	while (ptr[0] != 0xff) {
 		u16 buflen = ptr[0] + 4;
@@ -129,25 +130,34 @@
 static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
 {
 	u8 status, buf;
+	int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
+
 	if (onoff) {
 		gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
-		if (! (status & 0x01))  /* started */
+		if (! (status & bm8pskStarted)) {  /* started */
+			if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)
+				gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0);
 			if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
 				return -EINVAL;
+		}
 
-		if (! (status & 0x02)) /* BCM4500 firmware loaded */
-			if(gp8psk_load_bcm4500fw(d))
-				return EINVAL;
+		if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+			if (! (status & bm8pskFW_Loaded)) /* BCM4500 firmware loaded */
+				if(gp8psk_load_bcm4500fw(d))
+					return EINVAL;
 
-		if (! (status & 0x04)) /* LNB Power */
+		if (! (status & bmIntersilOn)) /* LNB Power */
 			if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0,
 					&buf, 1))
 				return EINVAL;
 
-		/* Set DVB mode */
-		if(gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
-			return -EINVAL;
-		gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
+		/* Set DVB mode to 1 */
+		if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+			if (gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
+				return EINVAL;
+		/* Abort possible TS (if previous tune crashed) */
+		if (gp8psk_usb_out_op(d, ARM_TRANSFER, 0, 0, NULL, 0))
+			return EINVAL;
 	} else {
 		/* Turn off LNB power */
 		if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1))
@@ -155,11 +165,28 @@
 		/* Turn off 8psk power */
 		if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
 			return -EINVAL;
-
+		if(gp_product_id == USB_PID_GENPIX_SKYWALKER_CW3K)
+			gp8psk_usb_out_op(d, CW3K_INIT, 0, 0, NULL, 0);
 	}
 	return 0;
 }
 
+int gp8psk_bcm4500_reload(struct dvb_usb_device *d)
+{
+	u8 buf;
+	int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct);
+	/* Turn off 8psk power */
+	if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
+		return -EINVAL;
+	/* Turn On 8psk power */
+	if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
+		return -EINVAL;
+	/* load BCM4500 firmware */
+	if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
+		if (gp8psk_load_bcm4500fw(d))
+			return EINVAL;
+	return 0;
+}
 
 static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
@@ -177,12 +204,22 @@
 static int gp8psk_usb_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
-	return dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL);
+	int ret;
+	struct usb_device *udev = interface_to_usbdev(intf);
+	ret =  dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL);
+	if (ret == 0) {
+		info("found Genpix USB device pID = %x (hex)",
+			le16_to_cpu(udev->descriptor.idProduct));
+	}
+	return ret;
 }
 
 static struct usb_device_id gp8psk_usb_table [] = {
-	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_COLD) },
-	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_WARM) },
+	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_COLD) },
+	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
+	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
+	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
+	    { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) },
 	    { 0 },
 };
 MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
@@ -213,12 +250,24 @@
 
 	.generic_bulk_ctrl_endpoint = 0x01,
 
-	.num_device_descs = 1,
+	.num_device_descs = 4,
 	.devices = {
-		{ .name = "Genpix 8PSK-USB DVB-S USB2.0 receiver",
+		{ .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
 		  .cold_ids = { &gp8psk_usb_table[0], NULL },
 		  .warm_ids = { &gp8psk_usb_table[1], NULL },
 		},
+		{ .name = "Genpix 8PSK-to-USB2 Rev.2 DVB-S receiver",
+		  .cold_ids = { NULL },
+		  .warm_ids = { &gp8psk_usb_table[2], NULL },
+		},
+		{ .name = "Genpix SkyWalker-1 DVB-S receiver",
+		  .cold_ids = { NULL },
+		  .warm_ids = { &gp8psk_usb_table[3], NULL },
+		},
+		{ .name = "Genpix SkyWalker-CW3K DVB-S receiver",
+		  .cold_ids = { NULL },
+		  .warm_ids = { &gp8psk_usb_table[4], NULL },
+		},
 		{ NULL },
 	}
 };
@@ -253,6 +302,6 @@
 module_exit(gp8psk_usb_module_exit);
 
 MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");
-MODULE_DESCRIPTION("Driver for Genpix 8psk-USB DVB-S USB2.0");
-MODULE_VERSION("1.0");
+MODULE_DESCRIPTION("Driver for Genpix 8psk-to-USB2 DVB-S");
+MODULE_VERSION("1.1");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h
index 3eba706..e83a575 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.h
+++ b/drivers/media/dvb/dvb-usb/gp8psk.h
@@ -1,7 +1,8 @@
 /* DVB USB compliant Linux driver for the
- *  - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *  - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module
  *
  * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com)
  *
  * Thanks to GENPIX for the sample code used to implement this module.
  *
@@ -30,21 +31,37 @@
 #define TH_COMMAND_IN                     0xC0
 #define TH_COMMAND_OUT                    0xC1
 
-/* command bytes */
-#define GET_8PSK_CONFIG                 0x80
+/* gp8psk commands */
+
+#define GET_8PSK_CONFIG                 0x80    /* in */
 #define SET_8PSK_CONFIG                 0x81
+#define I2C_WRITE			0x83
+#define I2C_READ			0x84
 #define ARM_TRANSFER                    0x85
 #define TUNE_8PSK                       0x86
-#define GET_SIGNAL_STRENGTH             0x87
+#define GET_SIGNAL_STRENGTH             0x87    /* in */
 #define LOAD_BCM4500                    0x88
-#define BOOT_8PSK                       0x89
-#define START_INTERSIL                  0x8A
+#define BOOT_8PSK                       0x89    /* in */
+#define START_INTERSIL                  0x8A    /* in */
 #define SET_LNB_VOLTAGE                 0x8B
 #define SET_22KHZ_TONE                  0x8C
 #define SEND_DISEQC_COMMAND             0x8D
 #define SET_DVB_MODE                    0x8E
 #define SET_DN_SWITCH                   0x8F
-#define GET_SIGNAL_LOCK                 0x90
+#define GET_SIGNAL_LOCK                 0x90    /* in */
+#define GET_SERIAL_NUMBER               0x93    /* in */
+#define USE_EXTRA_VOLT                  0x94
+#define CW3K_INIT			0x9d
+
+/* PSK_configuration bits */
+#define bm8pskStarted                   0x01
+#define bm8pskFW_Loaded                 0x02
+#define bmIntersilOn                    0x04
+#define bmDVBmode                       0x08
+#define bm22kHz                         0x10
+#define bmSEL18V                        0x20
+#define bmDCtuned                       0x40
+#define bmArmed                         0x80
 
 /* Satellite modulation modes */
 #define ADV_MOD_DVB_QPSK 0     /* DVB-S QPSK */
@@ -75,5 +92,6 @@
 extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
 extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
 			     u16 index, u8 *b, int blen);
+extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d);
 
 #endif
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
index c546dde..a956bc5 100644
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -22,6 +22,8 @@
 module_param_named(debug,dvb_usb_m920x_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
 
+static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid);
+
 static inline int m920x_read(struct usb_device *udev, u8 request, u16 value,
 			     u16 index, void *data, int size)
 {
@@ -57,7 +59,8 @@
 
 static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
 {
-	int ret = 0;
+	int ret = 0, i, epi, flags = 0;
+	int adap_enabled[M9206_MAX_ADAPTERS] = { 0 };
 
 	/* Remote controller init. */
 	if (d->props.rc_query) {
@@ -76,9 +79,51 @@
 		deb("Initialising remote control success\n");
 	}
 
+	for (i = 0; i < d->props.num_adapters; i++)
+		flags |= d->adapter[i].props.caps;
+
+	/* Some devices(Dposh) might crash if we attempt touch at all. */
+	if (flags & DVB_USB_ADAP_HAS_PID_FILTER) {
+		for (i = 0; i < d->props.num_adapters; i++) {
+			epi = d->adapter[i].props.stream.endpoint - 0x81;
+
+			if (epi < 0 || epi >= M9206_MAX_ADAPTERS) {
+				printk(KERN_INFO "m920x: Unexpected adapter endpoint!\n");
+				return -EINVAL;
+			}
+
+			adap_enabled[epi] = 1;
+		}
+
+		for (i = 0; i < M9206_MAX_ADAPTERS; i++) {
+			if (adap_enabled[i])
+				continue;
+
+			if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x0)) != 0)
+				return ret;
+
+			if ((ret = m920x_set_filter(d, 0x81 + i, 0, 0x02f5)) != 0)
+				return ret;
+		}
+	}
+
 	return ret;
 }
 
+static int m920x_init_ep(struct usb_interface *intf)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct usb_host_interface *alt;
+
+	if ((alt = usb_altnum_to_altsetting(intf, 1)) == NULL) {
+		deb("No alt found!\n");
+		return -ENODEV;
+	}
+
+	return usb_set_interface(udev, alt->desc.bInterfaceNumber,
+				 alt->desc.bAlternateSetting);
+}
+
 static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
 {
 	struct m920x_state *m = d->priv;
@@ -211,8 +256,7 @@
 };
 
 /* pid filter */
-static int m920x_set_filter(struct dvb_usb_adapter *adap,
-			    int type, int idx, int pid)
+static int m920x_set_filter(struct dvb_usb_device *d, int type, int idx, int pid)
 {
 	int ret = 0;
 
@@ -221,10 +265,10 @@
 
 	pid |= 0x8000;
 
-	if ((ret = m920x_write(adap->dev->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
+	if ((ret = m920x_write(d->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
 		return ret;
 
-	if ((ret = m920x_write(adap->dev->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
+	if ((ret = m920x_write(d->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
 		return ret;
 
 	return ret;
@@ -233,40 +277,35 @@
 static int m920x_update_filters(struct dvb_usb_adapter *adap)
 {
 	struct m920x_state *m = adap->dev->priv;
-	int enabled = m->filtering_enabled;
+	int enabled = m->filtering_enabled[adap->id];
 	int i, ret = 0, filter = 0;
+	int ep = adap->props.stream.endpoint;
 
 	for (i = 0; i < M9206_MAX_FILTERS; i++)
-		if (m->filters[i] == 8192)
+		if (m->filters[adap->id][i] == 8192)
 			enabled = 0;
 
 	/* Disable all filters */
-	if ((ret = m920x_set_filter(adap, 0x81, 1, enabled)) != 0)
+	if ((ret = m920x_set_filter(adap->dev, ep, 1, enabled)) != 0)
 		return ret;
 
 	for (i = 0; i < M9206_MAX_FILTERS; i++)
-		if ((ret = m920x_set_filter(adap, 0x81, i + 2, 0)) != 0)
+		if ((ret = m920x_set_filter(adap->dev, ep, i + 2, 0)) != 0)
 			return ret;
 
-	if ((ret = m920x_set_filter(adap, 0x82, 0, 0x0)) != 0)
-		return ret;
-
 	/* Set */
 	if (enabled) {
 		for (i = 0; i < M9206_MAX_FILTERS; i++) {
-			if (m->filters[i] == 0)
+			if (m->filters[adap->id][i] == 0)
 				continue;
 
-			if ((ret = m920x_set_filter(adap, 0x81, filter + 2, m->filters[i])) != 0)
+			if ((ret = m920x_set_filter(adap->dev, ep, filter + 2, m->filters[adap->id][i])) != 0)
 				return ret;
 
 			filter++;
 		}
 	}
 
-	if ((ret = m920x_set_filter(adap, 0x82, 0, 0x02f5)) != 0)
-		return ret;
-
 	return ret;
 }
 
@@ -274,7 +313,7 @@
 {
 	struct m920x_state *m = adap->dev->priv;
 
-	m->filtering_enabled = onoff ? 1 : 0;
+	m->filtering_enabled[adap->id] = onoff ? 1 : 0;
 
 	return m920x_update_filters(adap);
 }
@@ -283,7 +322,7 @@
 {
 	struct m920x_state *m = adap->dev->priv;
 
-	m->filters[index] = onoff ? pid : 0;
+	m->filters[adap->id][index] = onoff ? pid : 0;
 
 	return m920x_update_filters(adap);
 }
@@ -368,6 +407,7 @@
 /* demod configurations */
 static int m920x_mt352_demod_init(struct dvb_frontend *fe)
 {
+	int ret;
 	u8 config[] = { CONFIG, 0x3d };
 	u8 clock[] = { CLOCK_CTL, 0x30 };
 	u8 reset[] = { RESET, 0x80 };
@@ -377,17 +417,25 @@
 	u8 unk1[] = { 0x93, 0x1a };
 	u8 unk2[] = { 0xb5, 0x7a };
 
-	mt352_write(fe, config, ARRAY_SIZE(config));
-	mt352_write(fe, clock, ARRAY_SIZE(clock));
-	mt352_write(fe, reset, ARRAY_SIZE(reset));
-	mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl));
-	mt352_write(fe, agc, ARRAY_SIZE(agc));
-	mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc));
-	mt352_write(fe, unk1, ARRAY_SIZE(unk1));
-	mt352_write(fe, unk2, ARRAY_SIZE(unk2));
-
 	deb("Demod init!\n");
 
+	if ((ret = mt352_write(fe, config, ARRAY_SIZE(config))) != 0)
+		return ret;
+	if ((ret = mt352_write(fe, clock, ARRAY_SIZE(clock))) != 0)
+		return ret;
+	if ((ret = mt352_write(fe, reset, ARRAY_SIZE(reset))) != 0)
+		return ret;
+	if ((ret = mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl))) != 0)
+		return ret;
+	if ((ret = mt352_write(fe, agc, ARRAY_SIZE(agc))) != 0)
+		return ret;
+	if ((ret = mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc))) != 0)
+		return ret;
+	if ((ret = mt352_write(fe, unk1, ARRAY_SIZE(unk1))) != 0)
+		return ret;
+	if ((ret = mt352_write(fe, unk2, ARRAY_SIZE(unk2))) != 0)
+		return ret;
+
 	return 0;
 }
 
@@ -558,8 +606,7 @@
 static int m920x_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
 {
-	struct dvb_usb_device *d;
-	struct usb_host_interface *alt;
+	struct dvb_usb_device *d = NULL;
 	int ret;
 	struct m920x_inits *rc_init_seq = NULL;
 	int bInterfaceNumber = intf->cur_altsetting->desc.bInterfaceNumber;
@@ -604,23 +651,13 @@
 		 * tvwalkertwin_properties already configured both
 		 * tuners, so there is nothing for us to do here
 		 */
-
-		return -ENODEV;
 	}
 
  found:
-	alt = usb_altnum_to_altsetting(intf, 1);
-	if (alt == NULL) {
-		deb("No alt found!\n");
-		return -ENODEV;
-	}
-
-	ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
-				alt->desc.bAlternateSetting);
-	if (ret < 0)
+	if ((ret = m920x_init_ep(intf)) < 0)
 		return ret;
 
-	if ((ret = m920x_init(d, rc_init_seq)) != 0)
+	if (d && (ret = m920x_init(d, rc_init_seq)) != 0)
 		return ret;
 
 	return ret;
@@ -737,9 +774,9 @@
  *
  * LifeView TV Walker Twin has 1 x M9206, 2 x TDA10046, 2 x TDA8275A
  * TDA10046 #0 is located at i2c address 0x08
- * TDA10046 #1 is located at i2c address 0x0b (presently disabled - not yet working)
+ * TDA10046 #1 is located at i2c address 0x0b
  * TDA8275A #0 is located at i2c address 0x60
- * TDA8275A #1 is located at i2c address 0x61 (presently disabled - not yet working)
+ * TDA8275A #1 is located at i2c address 0x61
  */
 static struct dvb_usb_device_properties tvwalkertwin_properties = {
 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
@@ -756,7 +793,7 @@
 	.size_of_priv     = sizeof(struct m920x_state),
 
 	.identify_state   = m920x_identify_state,
-	.num_adapters = 1,
+	.num_adapters = 2,
 	.adapter = {{
 		.caps = DVB_USB_ADAP_HAS_PID_FILTER |
 			DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
diff --git a/drivers/media/dvb/dvb-usb/m920x.h b/drivers/media/dvb/dvb-usb/m920x.h
index 2c8942d..3753289 100644
--- a/drivers/media/dvb/dvb-usb/m920x.h
+++ b/drivers/media/dvb/dvb-usb/m920x.h
@@ -18,6 +18,7 @@
 #define M9206_FW	0x30
 
 #define M9206_MAX_FILTERS 8
+#define M9206_MAX_ADAPTERS 2
 
 /*
 sequences found in logs:
@@ -60,8 +61,8 @@
 */
 
 struct m920x_state {
-	u16 filters[M9206_MAX_FILTERS];
-	int filtering_enabled;
+	u16 filters[M9206_MAX_ADAPTERS][M9206_MAX_FILTERS];
+	int filtering_enabled[M9206_MAX_ADAPTERS];
 	int rep_count;
 };
 
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
index 518d7ad..d7c0495 100644
--- a/drivers/media/dvb/dvb-usb/opera1.c
+++ b/drivers/media/dvb/dvb-usb/opera1.c
@@ -263,7 +263,7 @@
 {
 	dvb_attach(
 		dvb_pll_attach, adap->fe, 0xc0>>1,
-		&adap->dev->i2c_adap, &dvb_pll_opera1
+		&adap->dev->i2c_adap, DVB_PLL_OPERA1
 	);
 	return 0;
 }
@@ -435,9 +435,9 @@
 {
 	const struct firmware *fw = NULL;
 	u8 *b, *p;
-	int ret = 0, i;
+	int ret = 0, i,fpgasize=40;
 	u8 testval;
-	info("start downloading fpga firmware");
+	info("start downloading fpga firmware %s",filename);
 
 	if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) {
 		err("did not find the firmware file. (%s) "
@@ -454,17 +454,20 @@
 			/* clear fpga ? */
 			opera1_xilinx_rw(dev, 0xbc, 0xaa, &fpga_command, 1,
 					 OPERA_WRITE_MSG);
-			for (i = 0; p[i] != 0 && i < fw->size;) {
+			for (i = 0; i < fw->size;) {
+				if ( (fw->size - i) <fpgasize){
+				    fpgasize=fw->size-i;
+				}
 				b = (u8 *) p + i;
 				if (opera1_xilinx_rw
-					(dev, OPERA_WRITE_FX2, 0x0, b + 1, b[0],
-						OPERA_WRITE_MSG) != b[0]
+					(dev, OPERA_WRITE_FX2, 0x0, b , fpgasize,
+						OPERA_WRITE_MSG) != fpgasize
 					) {
 					err("error while transferring firmware");
 					ret = -EINVAL;
 					break;
 				}
-				i = i + 1 + b[0];
+				i = i + fpgasize;
 			}
 			/* restart the CPU */
 			if (ret || opera1_xilinx_rw
@@ -534,18 +537,16 @@
 static int opera1_probe(struct usb_interface *intf,
 			const struct usb_device_id *id)
 {
-	struct dvb_usb_device *d;
 	struct usb_device *udev = interface_to_usbdev(intf);
 
 	if (udev->descriptor.idProduct == USB_PID_OPERA1_WARM &&
 		udev->descriptor.idVendor == USB_VID_OPERA1 &&
-		(d == NULL
-			|| opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga.fw") != 0)
-		) {
+		opera1_xilinx_load_firmware(udev, "dvb-usb-opera1-fpga-01.fw") != 0
+	    ) {
 		return -EINVAL;
 	}
 
-	if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, &d) != 0)
+	if (dvb_usb_device_init(intf, &opera1_properties, THIS_MODULE, NULL) != 0)
 		return -EINVAL;
 	return 0;
 }
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
index f77b48f..0dcab3d 100644
--- a/drivers/media/dvb/dvb-usb/umt-010.c
+++ b/drivers/media/dvb/dvb-usb/umt-010.c
@@ -65,9 +65,7 @@
 
 static int umt_tuner_attach (struct dvb_usb_adapter *adap)
 {
-	adap->pll_addr = 0x61;
-	adap->pll_desc = &dvb_pll_tua6034;
-	adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+	dvb_attach(dvb_pll_attach, adap->fe, 0x61, NULL, DVB_PLL_TUA6034);
 	return 0;
 }
 
@@ -84,8 +82,8 @@
 
 /* do not change the order of the ID table */
 static struct usb_device_id umt_table [] = {
-/* 00 */	{ USB_DEVICE(USB_VID_HANFTEK,		USB_PID_HANFTEK_UMT_010_COLD) },
-/* 01 */	{ USB_DEVICE(USB_VID_HANFTEK,		USB_PID_HANFTEK_UMT_010_WARM) },
+/* 00 */	{ USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) },
+/* 01 */	{ USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) },
 			{ }		/* Terminating entry */
 };
 MODULE_DEVICE_TABLE (usb, umt_table);
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index 69a46b3..5bbd2d5 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -159,7 +159,7 @@
 		return 0;
 	}
 
-	for (i = 0; i < sizeof(vp7045_rc_keys)/sizeof(struct dvb_usb_rc_key); i++)
+	for (i = 0; i < ARRAY_SIZE(vp7045_rc_keys); i++)
 		if (vp7045_rc_keys[i].data == key) {
 			*state = REMOTE_KEY_PRESSED;
 			*event = vp7045_rc_keys[i].event;
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index ff44876..59b9ed1 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -283,6 +283,14 @@
 	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
 	  to support this frontend.
 
+config DVB_S5H1409
+	tristate "Samsung S5H1409 based"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+	  to support this frontend.
+
 comment "Tuners/PLL support"
 	depends on DVB_CORE
 
@@ -291,7 +299,7 @@
 	depends on DVB_CORE && I2C
 	default m if DVB_FE_CUSTOMISE
 	help
-	  This module driver a number of tuners based on PLL chips with a
+	  This module drives a number of tuners based on PLL chips with a
 	  common I2C interface. Say Y when you want to support these tuners.
 
 config DVB_TDA826X
@@ -322,6 +330,29 @@
 	help
 	  A driver for the silicon IF tuner MT2060 from Microtune.
 
+config DVB_TUNER_MT2266
+	tristate "Microtune MT2266 silicon tuner"
+	depends on I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A driver for the silicon baseband tuner MT2266 from Microtune.
+
+config DVB_TUNER_MT2131
+	tristate "Microtune MT2131 silicon tuner"
+	depends on I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A driver for the silicon baseband tuner MT2131 from Microtune.
+
+config DVB_TUNER_DIB0070
+	tristate "DiBcom DiB0070 silicon base-band tuner"
+	depends on I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  A driver for the silicon baseband tuner DiB0070 from DiBcom.
+	  This device is only used inside a SiP called togther with a
+	  demodulator for now.
+
 comment "Miscellaneous devices"
 	depends on DVB_CORE
 
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 27f3865..4b8ad1f 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -2,7 +2,7 @@
 # Makefile for the kernel DVB frontend device drivers.
 #
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
 
 obj-$(CONFIG_DVB_PLL) += dvb-pll.o
 obj-$(CONFIG_DVB_STV0299) += stv0299.o
@@ -40,5 +40,9 @@
 obj-$(CONFIG_DVB_TDA826X) += tda826x.o
 obj-$(CONFIG_DVB_TDA827X) += tda827x.o
 obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
+obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o
+obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
 obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
 obj-$(CONFIG_DVB_TUA6100) += tua6100.o
+obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o
+obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c
index baeb311d..a913f49 100644
--- a/drivers/media/dvb/frontends/bcm3510.c
+++ b/drivers/media/dvb/frontends/bcm3510.c
@@ -33,7 +33,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/jiffies.h>
diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c
index 13ad1bf..11a4968 100644
--- a/drivers/media/dvb/frontends/cx22700.c
+++ b/drivers/media/dvb/frontends/cx22700.c
@@ -23,7 +23,6 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include "dvb_frontend.h"
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 335219e..1dc164d 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -32,7 +32,6 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include "dvb_frontend.h"
-#include "dvb-pll.h"
 #include "cx22702.h"
 
 
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index 10fc0c8..b03d828 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -25,7 +25,6 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 
 #include "dvb_frontend.h"
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index 732e94a..d74fdbd 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -23,7 +23,6 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 
 #include "dvb_frontend.h"
@@ -917,7 +916,7 @@
 static int cx24123_tune(struct dvb_frontend* fe,
 			struct dvb_frontend_parameters* params,
 			unsigned int mode_flags,
-			int *delay,
+			unsigned int *delay,
 			fe_status_t *status)
 {
 	int retval = 0;
diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c
new file mode 100644
index 0000000..481eaa6
--- /dev/null
+++ b/drivers/media/dvb/frontends/dib0070.c
@@ -0,0 +1,580 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
+ *
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
+ *
+ * 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, version 2.
+ */
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "dib0070.h"
+#include "dibx000_common.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB0070: "); printk(args); printk("\n"); } } while (0)
+
+#define DIB0070_P1D  0x00
+#define DIB0070_P1F  0x01
+#define DIB0070_P1G  0x03
+#define DIB0070S_P1A 0x02
+
+struct dib0070_state {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend *fe;
+	const struct dib0070_config *cfg;
+	u16 wbd_ff_offset;
+	u8 revision;
+};
+
+static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
+{
+	u8 b[2];
+	struct i2c_msg msg[2] = {
+		{ .addr = state->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
+		{ .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b,  .len = 2 },
+	};
+	if (i2c_transfer(state->i2c, msg, 2) != 2) {
+		printk(KERN_WARNING "DiB0070 I2C read failed\n");
+		return 0;
+	}
+	return (b[0] << 8) | b[1];
+}
+
+static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
+{
+	u8 b[3] = { reg, val >> 8, val & 0xff };
+	struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 };
+	if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "DiB0070 I2C write failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+#define HARD_RESET(state) do { if (state->cfg->reset) { state->cfg->reset(state->fe,1); msleep(10); state->cfg->reset(state->fe,0); msleep(10); } } while (0)
+
+static int dib0070_set_bandwidth(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
+{
+	struct dib0070_state *st = fe->tuner_priv;
+	u16 tmp = 0;
+	tmp = dib0070_read_reg(st, 0x02) & 0x3fff;
+
+    switch(BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth)) {
+		case  8000:
+			tmp |= (0 << 14);
+			break;
+		case  7000:
+			tmp |= (1 << 14);
+			break;
+	case  6000:
+			tmp |= (2 << 14);
+			break;
+	case 5000:
+		default:
+			tmp |= (3 << 14);
+			break;
+	}
+	dib0070_write_reg(st, 0x02, tmp);
+	return 0;
+}
+
+static void dib0070_captrim(struct dib0070_state *st, u16 LO4)
+{
+	int8_t captrim, fcaptrim, step_sign, step;
+	u16 adc, adc_diff = 3000;
+
+
+
+	dib0070_write_reg(st, 0x0f, 0xed10);
+	dib0070_write_reg(st, 0x17,    0x0034);
+
+	dib0070_write_reg(st, 0x18, 0x0032);
+	msleep(2);
+
+	step = captrim = fcaptrim = 64;
+
+	do {
+		step /= 2;
+		dib0070_write_reg(st, 0x14, LO4 | captrim);
+		msleep(1);
+		adc = dib0070_read_reg(st, 0x19);
+
+		dprintk( "CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", captrim, adc, (u32) adc*(u32)1800/(u32)1024);
+
+		if (adc >= 400) {
+			adc -= 400;
+			step_sign = -1;
+		} else {
+			adc = 400 - adc;
+			step_sign = 1;
+		}
+
+		if (adc < adc_diff) {
+			dprintk( "CAPTRIM=%hd is closer to target (%hd/%hd)", captrim, adc, adc_diff);
+			adc_diff = adc;
+			fcaptrim = captrim;
+
+
+
+		}
+		captrim += (step_sign * step);
+	} while (step >= 1);
+
+	dib0070_write_reg(st, 0x14, LO4 | fcaptrim);
+	dib0070_write_reg(st, 0x18, 0x07ff);
+}
+
+#define LPF	100                       // define for the loop filter 100kHz by default 16-07-06
+#define LO4_SET_VCO_HFDIV(l, v, h)   l |= ((v) << 11) | ((h) << 7)
+#define LO4_SET_SD(l, s)             l |= ((s) << 14) | ((s) << 12)
+#define LO4_SET_CTRIM(l, c)          l |=  (c) << 10
+static int dib0070_tune_digital(struct dvb_frontend *fe, struct dvb_frontend_parameters *ch)
+{
+	struct dib0070_state *st = fe->tuner_priv;
+	u32 freq = ch->frequency/1000 + (BAND_OF_FREQUENCY(ch->frequency/1000) == BAND_VHF ? st->cfg->freq_offset_khz_vhf : st->cfg->freq_offset_khz_uhf);
+
+	u8 band = BAND_OF_FREQUENCY(freq), c;
+
+	/*******************VCO***********************************/
+	u16 lo4 = 0;
+
+	u8 REFDIV, PRESC = 2;
+	u32 FBDiv, Rest, FREF, VCOF_kHz;
+	u16 Num, Den;
+	/*******************FrontEnd******************************/
+	u16 value = 0;
+
+	dprintk( "Tuning for Band: %hd (%d kHz)", band, freq);
+
+
+	dib0070_write_reg(st, 0x17, 0x30);
+
+	dib0070_set_bandwidth(fe, ch);	/* c is used as HF */
+	switch (st->revision) {
+		case DIB0070S_P1A:
+			switch (band) {
+				case BAND_LBAND:
+					LO4_SET_VCO_HFDIV(lo4, 1, 1);
+					c = 2;
+					break;
+				case BAND_SBAND:
+					LO4_SET_VCO_HFDIV(lo4, 0, 0);
+					LO4_SET_CTRIM(lo4, 1);;
+					c = 1;
+					break;
+				case BAND_UHF:
+				default:
+					if (freq < 570000) {
+						LO4_SET_VCO_HFDIV(lo4, 1, 3);
+						PRESC = 6; c = 6;
+					} else if (freq < 680000) {
+						LO4_SET_VCO_HFDIV(lo4, 0, 2);
+						c = 4;
+					} else {
+						LO4_SET_VCO_HFDIV(lo4, 1, 2);
+						c = 4;
+					}
+					break;
+			} break;
+
+		case DIB0070_P1G:
+		case DIB0070_P1F:
+		default:
+			switch (band) {
+				case BAND_FM:
+						LO4_SET_VCO_HFDIV(lo4, 0, 7);
+						c = 24;
+					break;
+				case BAND_LBAND:
+						LO4_SET_VCO_HFDIV(lo4, 1, 0);
+						c = 2;
+					break;
+				case BAND_VHF:
+					if (freq < 180000) {
+						LO4_SET_VCO_HFDIV(lo4, 0, 3);
+						c = 16;
+					} else if (freq < 190000) {
+						LO4_SET_VCO_HFDIV(lo4, 1, 3);
+						c = 16;
+					} else {
+						LO4_SET_VCO_HFDIV(lo4, 0, 6);
+						c = 12;
+					}
+					break;
+
+				case BAND_UHF:
+				default:
+					if (freq < 570000) {
+						LO4_SET_VCO_HFDIV(lo4, 1, 5);
+						c = 6;
+					} else if (freq < 700000) {
+						LO4_SET_VCO_HFDIV(lo4, 0, 1);
+						c = 4;
+					} else {
+						LO4_SET_VCO_HFDIV(lo4, 1, 1);
+						c = 4;
+					}
+					break;
+			}
+		break;
+	}
+
+	dprintk( "HFDIV code: %hd", (lo4 >> 7) & 0xf);
+	dprintk( "VCO = %hd", (lo4 >> 11) & 0x3);
+
+
+	VCOF_kHz = (c * freq) * 2;
+	dprintk( "VCOF in kHz: %d ((%hd*%d) << 1))",VCOF_kHz, c, freq);
+
+	switch (band) {
+		case BAND_VHF:
+			REFDIV = (u8) ((st->cfg->clock_khz + 9999) / 10000);
+			break;
+		case BAND_FM:
+			REFDIV = (u8) ((st->cfg->clock_khz) / 1000);
+			break;
+		default:
+			REFDIV = (u8) ( st->cfg->clock_khz  / 10000);
+			break;
+	}
+	FREF = st->cfg->clock_khz / REFDIV;
+
+	dprintk( "REFDIV: %hd, FREF: %d", REFDIV, FREF);
+
+
+
+	switch (st->revision) {
+		case DIB0070S_P1A:
+			FBDiv = (VCOF_kHz / PRESC / FREF);
+			Rest  = (VCOF_kHz / PRESC) - FBDiv * FREF;
+			break;
+
+		case DIB0070_P1G:
+		case DIB0070_P1F:
+		default:
+			FBDiv = (freq / (FREF / 2));
+			Rest  = 2 * freq - FBDiv * FREF;
+			break;
+	}
+
+
+	     if (Rest < LPF)              Rest = 0;
+	else if (Rest < 2 * LPF)          Rest = 2 * LPF;
+	else if (Rest > (FREF - LPF))   { Rest = 0 ; FBDiv += 1; }
+	else if (Rest > (FREF - 2 * LPF)) Rest = FREF - 2 * LPF;
+	Rest = (Rest * 6528) / (FREF / 10);
+	dprintk( "FBDIV: %d, Rest: %d", FBDiv, Rest);
+
+	Num = 0;
+	Den = 1;
+
+	if (Rest > 0) {
+		LO4_SET_SD(lo4, 1);
+		Den = 255;
+		Num = (u16)Rest;
+	}
+	dprintk( "Num: %hd, Den: %hd, SD: %hd",Num, Den, (lo4 >> 12) & 0x1);
+
+
+
+	dib0070_write_reg(st, 0x11, (u16)FBDiv);
+
+
+	dib0070_write_reg(st, 0x12, (Den << 8) | REFDIV);
+
+
+	dib0070_write_reg(st, 0x13, Num);
+
+
+	value = 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001;
+
+	switch (band) {
+		case BAND_UHF:   value |= 0x4000 | 0x0800; break;
+		case BAND_LBAND: value |= 0x2000 | 0x0400; break;
+		default:         value |= 0x8000 | 0x1000; break;
+	}
+	dib0070_write_reg(st, 0x20, value);
+
+	dib0070_captrim(st, lo4);
+	if (st->revision == DIB0070S_P1A) {
+		if (band == BAND_SBAND)
+			dib0070_write_reg(st, 0x15, 0x16e2);
+		else
+			dib0070_write_reg(st, 0x15, 0x56e5);
+	}
+
+
+
+	switch (band) {
+		case BAND_UHF:   value = 0x7c82; break;
+		case BAND_LBAND: value = 0x7c84; break;
+		default:         value = 0x7c81; break;
+	}
+	dib0070_write_reg(st, 0x0f, value);
+	dib0070_write_reg(st, 0x06, 0x3fff);
+
+	/* Front End */
+	/* c == TUNE, value = SWITCH */
+	c = 0;
+	value = 0;
+	switch (band) {
+		case BAND_FM:
+			c = 0; value = 1;
+		break;
+
+		case BAND_VHF:
+			if (freq <= 180000) c = 0;
+			else if (freq <= 188200) c = 1;
+			else if (freq <= 196400) c = 2;
+			else c = 3;
+			value = 1;
+		break;
+
+		case BAND_LBAND:
+			if (freq <= 1500000) c = 0;
+			else if (freq <= 1600000) c = 1;
+			else c = 3;
+		break;
+
+		case BAND_SBAND:
+			c = 7;
+			dib0070_write_reg(st, 0x1d,0xFFFF);
+		break;
+
+		case BAND_UHF:
+		default:
+			if (st->cfg->flip_chip) {
+				if (freq <= 550000) c = 0;
+				else if (freq <= 590000) c = 1;
+				else if (freq <= 666000) c = 3;
+				else c = 5;
+			} else {
+				if (freq <= 550000) c = 2;
+				else if (freq <= 650000) c = 3;
+				else if (freq <= 750000) c = 5;
+				else if (freq <= 850000) c = 6;
+				else c = 7;
+			}
+			value = 2;
+		break;
+	}
+
+	/* default: LNA_MATCH=7, BIAS=3 */
+	dib0070_write_reg(st, 0x07, (value << 11) | (7 << 8) | (c << 3) | (3 << 0));
+	dib0070_write_reg(st, 0x08, (c << 10) | (3 << 7) | (127));
+	dib0070_write_reg(st, 0x0d, 0x0d80);
+
+
+	dib0070_write_reg(st, 0x18,   0x07ff);
+	dib0070_write_reg(st, 0x17, 0x0033);
+
+	return 0;
+}
+
+static int dib0070_wakeup(struct dvb_frontend *fe)
+{
+	struct dib0070_state *st = fe->tuner_priv;
+	if (st->cfg->sleep)
+		st->cfg->sleep(fe, 0);
+	return 0;
+}
+
+static int dib0070_sleep(struct dvb_frontend *fe)
+{
+	struct dib0070_state *st = fe->tuner_priv;
+	if (st->cfg->sleep)
+		st->cfg->sleep(fe, 1);
+	return 0;
+}
+
+static u16 dib0070_p1f_defaults[] =
+
+{
+	7, 0x02,
+		0x0008,
+		0x0000,
+		0x0000,
+		0x0000,
+		0x0000,
+		0x0002,
+		0x0100,
+
+	3, 0x0d,
+		0x0d80,
+		0x0001,
+		0x0000,
+
+	4, 0x11,
+		0x0000,
+		0x0103,
+		0x0000,
+		0x0000,
+
+	3, 0x16,
+		0x0004 | 0x0040,
+		0x0030,
+		0x07ff,
+
+	6, 0x1b,
+		0x4112,
+		0xff00,
+		0xc07f,
+		0x0000,
+		0x0180,
+		0x4000 | 0x0800 | 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001,
+
+	0,
+};
+
+static void dib0070_wbd_calibration(struct dib0070_state *state)
+{
+	u16 wbd_offs;
+	dib0070_write_reg(state, 0x0f, 0x6d81);
+	dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001);
+	msleep(9);
+	wbd_offs = dib0070_read_reg(state, 0x19);
+	dib0070_write_reg(state, 0x20, 0);
+	state->wbd_ff_offset = ((wbd_offs * 8 * 18 / 33 + 1) / 2);
+	dprintk( "WBDStart = %d (Vargen) - FF = %hd", (u32) wbd_offs * 1800/1024, state->wbd_ff_offset);
+}
+
+u16 dib0070_wbd_offset(struct dvb_frontend *fe)
+{
+	struct dib0070_state *st = fe->tuner_priv;
+	return st->wbd_ff_offset;
+}
+
+EXPORT_SYMBOL(dib0070_wbd_offset);
+static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf_div_trim, u8 cp_current, u8 third_order_filt)
+{
+	struct dib0070_state *state = fe->tuner_priv;
+    u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0);
+	dprintk( "CTRL_LO5: 0x%x", lo5);
+	return dib0070_write_reg(state, 0x15, lo5);
+}
+
+#define pgm_read_word(w) (*w)
+static int dib0070_reset(struct dib0070_state *state)
+{
+	u16 l, r, *n;
+
+	HARD_RESET(state);
+
+
+#ifndef FORCE_SBAND_TUNER
+	if ((dib0070_read_reg(state, 0x22) >> 9) & 0x1)
+		state->revision = (dib0070_read_reg(state, 0x1f) >> 8) & 0xff;
+	else
+#endif
+		state->revision = DIB0070S_P1A;
+
+	/* P1F or not */
+	dprintk( "Revision: %x", state->revision);
+
+	if (state->revision == DIB0070_P1D) {
+		dprintk( "Error: this driver is not to be used meant for P1D or earlier");
+		return -EINVAL;
+	}
+
+	n = (u16 *) dib0070_p1f_defaults;
+	l = pgm_read_word(n++);
+	while (l) {
+		r = pgm_read_word(n++);
+		do {
+			dib0070_write_reg(state, (u8)r, pgm_read_word(n++));
+			r++;
+		} while (--l);
+		l = pgm_read_word(n++);
+	}
+
+	if (state->cfg->force_crystal_mode != 0)
+		r = state->cfg->force_crystal_mode;
+	else if (state->cfg->clock_khz >= 24000)
+		r = 1;
+	else
+		r = 2;
+
+	r |= state->cfg->osc_buffer_state << 3;
+
+	dib0070_write_reg(state, 0x10, r);
+	dib0070_write_reg(state, 0x1f, (1 << 8) | ((state->cfg->clock_pad_drive & 0xf) << 4));
+
+	if (state->cfg->invert_iq) {
+		r = dib0070_read_reg(state, 0x02) & 0xffdf;
+		dib0070_write_reg(state, 0x02, r | (1 << 5));
+	}
+
+
+	if (state->revision == DIB0070S_P1A)
+		dib0070_set_ctrl_lo5(state->fe, 4, 7, 3, 1);
+	else
+		dib0070_set_ctrl_lo5(state->fe, 4, 4, 2, 0);
+
+	dib0070_write_reg(state, 0x01, (54 << 9) | 0xc8);
+	return 0;
+}
+
+
+static int dib0070_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static struct dvb_tuner_ops dib0070_ops = {
+	.info = {
+		.name           = "DiBcom DiB0070",
+		.frequency_min  =  45000000,
+		.frequency_max  = 860000000,
+		.frequency_step =      1000,
+	},
+	.release       = dib0070_release,
+
+	.init          = dib0070_wakeup,
+	.sleep         = dib0070_sleep,
+	.set_params    = dib0070_tune_digital,
+//	.get_frequency = dib0070_get_frequency,
+//	.get_bandwidth = dib0070_get_bandwidth
+};
+
+struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg)
+{
+	struct dib0070_state *state = kzalloc(sizeof(struct dib0070_state), GFP_KERNEL);
+	if (state == NULL)
+		return NULL;
+
+	state->cfg = cfg;
+	state->i2c = i2c;
+	state->fe  = fe;
+	fe->tuner_priv = state;
+
+	if (dib0070_reset(state) != 0)
+		goto free_mem;
+
+	dib0070_wbd_calibration(state);
+
+	printk(KERN_INFO "DiB0070: successfully identified\n");
+	memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = state;
+	return fe;
+
+free_mem:
+	kfree(state);
+	fe->tuner_priv = NULL;
+	return NULL;
+}
+EXPORT_SYMBOL(dib0070_attach);
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 0070 base-band RF Tuner");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dib0070.h b/drivers/media/dvb/frontends/dib0070.h
new file mode 100644
index 0000000..786e37d
--- /dev/null
+++ b/drivers/media/dvb/frontends/dib0070.h
@@ -0,0 +1,44 @@
+/*
+ * Linux-DVB Driver for DiBcom's DiB0070 base-band RF Tuner.
+ *
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
+ *
+ * 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, version 2.
+ */
+#ifndef DIB0070_H
+#define DIB0070_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+#define DEFAULT_DIB0070_I2C_ADDRESS 0x60
+
+struct dib0070_config {
+	u8 i2c_address;
+
+	/* tuner pins controlled externally */
+	int (*reset) (struct dvb_frontend *, int);
+	int (*sleep) (struct dvb_frontend *, int);
+
+	/*  offset in kHz */
+	int freq_offset_khz_uhf;
+	int freq_offset_khz_vhf;
+
+	u8 osc_buffer_state; /* 0= normal, 1= tri-state */
+	u32  clock_khz;
+	u8 clock_pad_drive; /* (Drive + 1) * 2mA */
+
+	u8 invert_iq; /* invert Q - in case I or Q is inverted on the board */
+
+	u8 force_crystal_mode; /* if == 0 -> decision is made in the driver default: <24 -> 2, >=24 -> 1 */
+
+	u8 flip_chip;
+};
+
+extern struct dvb_frontend * dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg);
+extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open);
+extern u16 dib0070_wbd_offset(struct dvb_frontend *);
+
+#endif
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index b6adea5..136b9d2 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -23,7 +23,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index 054d7e6..edae0be 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -1,7 +1,7 @@
 /*
  * Driver for DiBcom DiB3000MC/P-demodulator.
  *
- * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2004-7 DiBcom (http://www.dibcom.fr/)
  * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
  *
  * This code is partially based on the previous dib3000mc.c .
@@ -13,10 +13,6 @@
 
 #include <linux/kernel.h>
 #include <linux/i2c.h>
-//#include <linux/init.h>
-//#include <linux/delay.h>
-//#include <linux/string.h>
-//#include <linux/slab.h>
 
 #include "dvb_frontend.h"
 
@@ -26,7 +22,11 @@
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
 
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); } } while (0)
+static int buggy_sfn_workaround;
+module_param(buggy_sfn_workaround, int, 0644);
+MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0)
 
 struct dib3000mc_state {
 	struct dvb_frontend demod;
@@ -42,6 +42,8 @@
 	fe_bandwidth_t current_bandwidth;
 
 	u16 dev_id;
+
+	u8 sfn_workaround_active :1;
 };
 
 static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg)
@@ -71,7 +73,6 @@
 	return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
 }
 
-
 static int dib3000mc_identify(struct dib3000mc_state *state)
 {
 	u16 value;
@@ -92,7 +93,7 @@
 	return 0;
 }
 
-static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, u8 update_offset)
+static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u32 bw, u8 update_offset)
 {
 	u32 timf;
 
@@ -103,7 +104,7 @@
 	} else
 		timf = state->timf;
 
-	timf *= (BW_INDEX_TO_KHZ(bw) / 1000);
+	timf *= (bw / 1000);
 
 	if (update_offset) {
 		s16 tim_offs = dib3000mc_read_word(state, 416);
@@ -111,17 +112,17 @@
 		if (tim_offs &  0x2000)
 			tim_offs -= 0x4000;
 
-		if (nfft == 0)
+		if (nfft == TRANSMISSION_MODE_2K)
 			tim_offs *= 4;
 
 		timf += tim_offs;
-		state->timf = timf / (BW_INDEX_TO_KHZ(bw) / 1000);
+		state->timf = timf / (bw / 1000);
 	}
 
 	dprintk("timf: %d\n", timf);
 
-	dib3000mc_write_word(state, 23, timf >> 16);
-	dib3000mc_write_word(state, 24, timf & 0xffff);
+	dib3000mc_write_word(state, 23, (u16) (timf >> 16));
+	dib3000mc_write_word(state, 24, (u16) (timf      ) & 0xffff);
 
 	return 0;
 }
@@ -209,31 +210,30 @@
 	return ret;
 }
 
-static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw)
+static int dib3000mc_set_bandwidth(struct dib3000mc_state *state, u32 bw)
 {
-	struct dib3000mc_state *state = demod->demodulator_priv;
 	u16 bw_cfg[6] = { 0 };
 	u16 imp_bw_cfg[3] = { 0 };
 	u16 reg;
 
 /* settings here are for 27.7MHz */
 	switch (bw) {
-		case BANDWIDTH_8_MHZ:
+		case 8000:
 			bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20;
 			imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7;
 			break;
 
-		case BANDWIDTH_7_MHZ:
+		case 7000:
 			bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7;
 			imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0;
 			break;
 
-		case BANDWIDTH_6_MHZ:
+		case 6000:
 			bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5;
 			imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089;
 			break;
 
-		case 255 /* BANDWIDTH_5_MHZ */:
+		case 5000:
 			bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500;
 			imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072;
 			break;
@@ -257,7 +257,7 @@
 		dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]);
 
 	// Timing configuration
-	dib3000mc_set_timing(state, 0, bw, 0);
+	dib3000mc_set_timing(state, TRANSMISSION_MODE_2K, bw, 0);
 
 	return 0;
 }
@@ -276,7 +276,7 @@
 	for (i = 58; i < 87; i++)
 		dib3000mc_write_word(state, i, impulse_noise_val[i-58]);
 
-	if (nfft == 1) {
+	if (nfft == TRANSMISSION_MODE_8K) {
 		dib3000mc_write_word(state, 58, 0x3b);
 		dib3000mc_write_word(state, 84, 0x00);
 		dib3000mc_write_word(state, 85, 0x8200);
@@ -376,7 +376,7 @@
 	// P_search_maxtrial=1
 	dib3000mc_write_word(state, 5, 1);
 
-	dib3000mc_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
+	dib3000mc_set_bandwidth(state, 8000);
 
 	// div_lock_mask
 	dib3000mc_write_word(state,  4, 0x814);
@@ -397,7 +397,7 @@
 	dib3000mc_write_word(state, 180, 0x2FF0);
 
 	// Impulse noise configuration
-	dib3000mc_set_impulse_noise(state, 0, 1);
+	dib3000mc_set_impulse_noise(state, 0, TRANSMISSION_MODE_8K);
 
 	// output mode set-up
 	dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
@@ -423,13 +423,13 @@
 {
 	u16 cfg[4] = { 0 },reg;
 	switch (qam) {
-		case 0:
+		case QPSK:
 			cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0;
 			break;
-		case 1:
+		case QAM_16:
 			cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0;
 			break;
-		case 2:
+		case QAM_64:
 			cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8;
 			break;
 	}
@@ -437,11 +437,11 @@
 		dib3000mc_write_word(state, reg, cfg[reg - 129]);
 }
 
-static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx000_ofdm_channel *chan, u16 seq)
+static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dvb_frontend_parameters *ch, u16 seq)
 {
-	u16 tmp;
-
-	dib3000mc_set_timing(state, chan->nfft, chan->Bw, 0);
+	u16 value;
+    dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+	dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 0);
 
 //	if (boost)
 //		dib3000mc_write_word(state, 100, (11 << 6) + 6);
@@ -455,7 +455,7 @@
 	dib3000mc_write_word(state, 26,  0x6680);
 	dib3000mc_write_word(state, 29,  0x1273);
 	dib3000mc_write_word(state, 33,       5);
-	dib3000mc_set_adp_cfg(state, 1);
+	dib3000mc_set_adp_cfg(state, QAM_16);
 	dib3000mc_write_word(state, 133,  15564);
 
 	dib3000mc_write_word(state, 12 , 0x0);
@@ -470,52 +470,98 @@
 	dib3000mc_write_word(state, 97,0);
 	dib3000mc_write_word(state, 98,0);
 
-	dib3000mc_set_impulse_noise(state, 0, chan->nfft);
+	dib3000mc_set_impulse_noise(state, 0, ch->u.ofdm.transmission_mode);
 
-	tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha;
-	dib3000mc_write_word(state, 0, tmp);
-
+	value = 0;
+	switch (ch->u.ofdm.transmission_mode) {
+		case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
+		default:
+		case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
+	}
+	switch (ch->u.ofdm.guard_interval) {
+		case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
+		case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
+		case GUARD_INTERVAL_1_4:  value |= (3 << 5); break;
+		default:
+		case GUARD_INTERVAL_1_8:  value |= (2 << 5); break;
+	}
+	switch (ch->u.ofdm.constellation) {
+		case QPSK:  value |= (0 << 3); break;
+		case QAM_16: value |= (1 << 3); break;
+		default:
+		case QAM_64: value |= (2 << 3); break;
+	}
+	switch (HIERARCHY_1) {
+		case HIERARCHY_2: value |= 2; break;
+		case HIERARCHY_4: value |= 4; break;
+		default:
+		case HIERARCHY_1: value |= 1; break;
+	}
+	dib3000mc_write_word(state, 0, value);
 	dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4));
 
-	tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp);
-	if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp))
-		tmp |= chan->vit_code_rate_hp << 1;
-	else
-		tmp |= chan->vit_code_rate_lp << 1;
-	dib3000mc_write_word(state, 181, tmp);
+	value = 0;
+	if (ch->u.ofdm.hierarchy_information == 1)
+		value |= (1 << 4);
+	if (1 == 1)
+		value |= 1;
+	switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+		case FEC_2_3: value |= (2 << 1); break;
+		case FEC_3_4: value |= (3 << 1); break;
+		case FEC_5_6: value |= (5 << 1); break;
+		case FEC_7_8: value |= (7 << 1); break;
+		default:
+		case FEC_1_2: value |= (1 << 1); break;
+	}
+	dib3000mc_write_word(state, 181, value);
 
-	// diversity synchro delay
-	tmp = dib3000mc_read_word(state, 180) & 0x000f;
-	tmp |= ((chan->nfft == 0) ? 64 : 256) * ((1 << (chan->guard)) * 3 / 2) << 4; // add 50% SFN margin
-	dib3000mc_write_word(state, 180, tmp);
+	// diversity synchro delay add 50% SFN margin
+	switch (ch->u.ofdm.transmission_mode) {
+		case TRANSMISSION_MODE_8K: value = 256; break;
+		case TRANSMISSION_MODE_2K:
+		default: value = 64; break;
+	}
+	switch (ch->u.ofdm.guard_interval) {
+		case GUARD_INTERVAL_1_16: value *= 2; break;
+		case GUARD_INTERVAL_1_8:  value *= 4; break;
+		case GUARD_INTERVAL_1_4:  value *= 8; break;
+		default:
+		case GUARD_INTERVAL_1_32: value *= 1; break;
+	}
+	value <<= 4;
+	value |= dib3000mc_read_word(state, 180) & 0x000f;
+	dib3000mc_write_word(state, 180, value);
 
 	// restart demod
-	tmp = dib3000mc_read_word(state, 0);
-	dib3000mc_write_word(state, 0, tmp | (1 << 9));
-	dib3000mc_write_word(state, 0, tmp);
+	value = dib3000mc_read_word(state, 0);
+	dib3000mc_write_word(state, 0, value | (1 << 9));
+	dib3000mc_write_word(state, 0, value);
 
 	msleep(30);
 
-	dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, chan->nfft);
+	dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, ch->u.ofdm.transmission_mode);
 }
 
-static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *chan)
+static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *chan)
 {
 	struct dib3000mc_state *state = demod->demodulator_priv;
 	u16 reg;
 //	u32 val;
-	struct dibx000_ofdm_channel fchan;
+	struct dvb_frontend_parameters schan;
 
-	INIT_OFDM_CHANNEL(&fchan);
-	fchan = *chan;
+	schan = *chan;
 
+	/* TODO what is that ? */
 
 	/* a channel for autosearch */
-	fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2;
-	fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2;
-	fchan.vit_hrch = 0; fchan.vit_select_hp = 1;
+	schan.u.ofdm.transmission_mode = TRANSMISSION_MODE_8K;
+	schan.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
+	schan.u.ofdm.constellation = QAM_64;
+	schan.u.ofdm.code_rate_HP = FEC_2_3;
+	schan.u.ofdm.code_rate_LP = FEC_2_3;
+	schan.u.ofdm.hierarchy_information = 0;
 
-	dib3000mc_set_channel_cfg(state, &fchan, 11);
+	dib3000mc_set_channel_cfg(state, &schan, 11);
 
 	reg = dib3000mc_read_word(state, 0);
 	dib3000mc_write_word(state, 0, reg | (1 << 8));
@@ -539,7 +585,7 @@
 	return 0; // still pending
 }
 
-static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static int dib3000mc_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
 {
 	struct dib3000mc_state *state = demod->demodulator_priv;
 
@@ -547,11 +593,17 @@
 	dib3000mc_set_channel_cfg(state, ch, 0);
 
 	// activates isi
-	dib3000mc_write_word(state, 29, 0x1073);
+	if (state->sfn_workaround_active) {
+		dprintk("SFN workaround is active\n");
+		dib3000mc_write_word(state, 29, 0x1273);
+		dib3000mc_write_word(state, 108, 0x4000); // P_pha3_force_pha_shift
+	} else {
+		dib3000mc_write_word(state, 29, 0x1073);
+		dib3000mc_write_word(state, 108, 0x0000); // P_pha3_force_pha_shift
+	}
 
-	dib3000mc_set_adp_cfg(state, (u8)ch->nqam);
-
-	if (ch->nfft == 1) {
+	dib3000mc_set_adp_cfg(state, (u8)ch->u.ofdm.constellation);
+	if (ch->u.ofdm.transmission_mode == TRANSMISSION_MODE_8K) {
 		dib3000mc_write_word(state, 26, 38528);
 		dib3000mc_write_word(state, 33, 8);
 	} else {
@@ -560,7 +612,7 @@
 	}
 
 	if (dib3000mc_read_word(state, 509) & 0x80)
-		dib3000mc_set_timing(state, ch->nfft, ch->Bw, 1);
+		dib3000mc_set_timing(state, ch->u.ofdm.transmission_mode, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth), 1);
 
 	return 0;
 }
@@ -632,13 +684,12 @@
 				struct dvb_frontend_parameters *fep)
 {
 	struct dib3000mc_state *state = fe->demodulator_priv;
-	struct dibx000_ofdm_channel ch;
-
-	INIT_OFDM_CHANNEL(&ch);
-	FEP2DIB(fep,&ch);
 
 	state->current_bandwidth = fep->u.ofdm.bandwidth;
-	dib3000mc_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+	dib3000mc_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+
+	/* maybe the parameter has been changed */
+	state->sfn_workaround_active = buggy_sfn_workaround;
 
 	if (fe->ops.tuner_ops.set_params) {
 		fe->ops.tuner_ops.set_params(fe, fep);
@@ -651,7 +702,7 @@
 		fep->u.ofdm.code_rate_HP      == FEC_AUTO) {
 		int i = 100, found;
 
-		dib3000mc_autosearch_start(fe, &ch);
+		dib3000mc_autosearch_start(fe, fep);
 		do {
 			msleep(1);
 			found = dib3000mc_autosearch_is_irq(fe);
@@ -662,13 +713,12 @@
 			return 0; // no channel found
 
 		dib3000mc_get_frontend(fe, fep);
-		FEP2DIB(fep,&ch);
 	}
 
 	/* make this a config parameter */
 	dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
 
-	return dib3000mc_tune(fe, &ch);
+	return dib3000mc_tune(fe, fep);
 }
 
 static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
index f64546c..fb18441 100644
--- a/drivers/media/dvb/frontends/dib7000m.c
+++ b/drivers/media/dvb/frontends/dib7000m.c
@@ -2,7 +2,7 @@
  * Linux-DVB Driver for DiBcom's DiB7000M and
  *              first generation DiB7000P-demodulator-family.
  *
- * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
  *
  * This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License as
@@ -19,7 +19,7 @@
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
 
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M:"); printk(args); } } while (0)
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M: "); printk(args); printk("\n"); } } while (0)
 
 struct dib7000m_state {
 	struct dvb_frontend demod;
@@ -39,8 +39,16 @@
 	fe_bandwidth_t current_bandwidth;
 	struct dibx000_agc_config *current_agc;
 	u32 timf;
+	u32 timf_default;
+	u32 internal_clk;
+
+	u8 div_force_off : 1;
+	u8 div_state : 1;
+	u16 div_sync_wait;
 
 	u16 revision;
+
+	u8 agc_state;
 };
 
 enum dib7000m_power_mode {
@@ -63,7 +71,7 @@
 	};
 
 	if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
-		dprintk("i2c read error on %d\n",reg);
+		dprintk("i2c read error on %d",reg);
 
 	return (rb[0] << 8) | rb[1];
 }
@@ -79,6 +87,25 @@
 	};
 	return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
 }
+static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
+{
+	u16 l = 0, r, *n;
+	n = buf;
+	l = *n++;
+	while (l) {
+		r = *n++;
+
+		if (state->reg_offs && (r >= 112 && r <= 331)) // compensate for 7000MC
+			r++;
+
+		do {
+			dib7000m_write_word(state, r, *n++);
+			r++;
+		} while (--l);
+		l = *n++;
+	}
+}
+
 static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode)
 {
 	int    ret = 0;
@@ -89,8 +116,7 @@
 	fifo_threshold = 1792;
 	smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1);
 
-	dprintk("-I-  Setting output mode for demod %p to %d\n",
-			&state->demod, mode);
+	dprintk( "setting output mode for demod %p to %d", &state->demod, mode);
 
 	switch (mode) {
 		case OUTMODE_MPEG2_PAR_GATED_CLK:   // STBs with parallel gated clock
@@ -117,7 +143,7 @@
 			outreg = 0;
 			break;
 		default:
-			dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
+			dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod);
 			break;
 	}
 
@@ -129,13 +155,20 @@
 	ret |= dib7000m_write_word(state, 1795, outreg);
 	ret |= dib7000m_write_word(state, 1805, sram);
 
+	if (state->revision == 0x4003) {
+		u16 clk_cfg1 = dib7000m_read_word(state, 909) & 0xfffd;
+		if (mode == OUTMODE_DIVERSITY)
+			clk_cfg1 |= (1 << 1); // P_O_CLK_en
+		dib7000m_write_word(state, 909, clk_cfg1);
+	}
 	return ret;
 }
 
-static int dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode)
+static void dib7000m_set_power_mode(struct dib7000m_state *state, enum dib7000m_power_mode mode)
 {
 	/* by default everything is going to be powered off */
 	u16 reg_903 = 0xffff, reg_904 = 0xffff, reg_905 = 0xffff, reg_906  = 0x3fff;
+	u8  offset = 0;
 
 	/* now, depending on the requested mode, we power on */
 	switch (mode) {
@@ -170,16 +203,17 @@
 	if (!state->cfg.mobile_mode)
 		reg_904 |= (1 << 7) | (1 << 6) | (1 << 4) | (1 << 2) | (1 << 1);
 
-	/* P_sdio_select_clk = 0 on MC */
+	/* P_sdio_select_clk = 0 on MC and after*/
 	if (state->revision != 0x4000)
 		reg_906 <<= 1;
 
-	dib7000m_write_word(state,  903,  reg_903);
-	dib7000m_write_word(state,  904,  reg_904);
-	dib7000m_write_word(state,  905,  reg_905);
-	dib7000m_write_word(state,  906,  reg_906);
+	if (state->revision == 0x4003)
+		offset = 1;
 
-	return 0;
+	dib7000m_write_word(state, 903 + offset, reg_903);
+	dib7000m_write_word(state, 904 + offset, reg_904);
+	dib7000m_write_word(state, 905 + offset, reg_905);
+	dib7000m_write_word(state, 906 + offset, reg_906);
 }
 
 static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc_states no)
@@ -230,34 +264,55 @@
 			break;
 	}
 
-//	dprintk("-D-  913: %x, 914: %x\n", reg_913, reg_914);
-
+//	dprintk( "913: %x, 914: %x", reg_913, reg_914);
 	ret |= dib7000m_write_word(state, 913, reg_913);
 	ret |= dib7000m_write_word(state, 914, reg_914);
 
 	return ret;
 }
 
-static int dib7000m_set_bandwidth(struct dvb_frontend *demod, u8 bw_idx)
+static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw)
 {
-	struct dib7000m_state *state = demod->demodulator_priv;
 	u32 timf;
 
 	// store the current bandwidth for later use
-	state->current_bandwidth = bw_idx;
+	state->current_bandwidth = bw;
 
 	if (state->timf == 0) {
-		dprintk("-D-  Using default timf\n");
-		timf = state->cfg.bw->timf;
+		dprintk( "using default timf");
+		timf = state->timf_default;
 	} else {
-		dprintk("-D-  Using updated timf\n");
+		dprintk( "using updated timf");
 		timf = state->timf;
 	}
 
-	timf = timf * (BW_INDEX_TO_KHZ(bw_idx) / 100) / 80;
+	timf = timf * (bw / 50) / 160;
 
-	dib7000m_write_word(state, 23, (timf >> 16) & 0xffff);
-	dib7000m_write_word(state, 24, (timf      ) & 0xffff);
+	dib7000m_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
+	dib7000m_write_word(state, 24, (u16) ((timf      ) & 0xffff));
+
+	return 0;
+}
+
+static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff)
+{
+	struct dib7000m_state *state = demod->demodulator_priv;
+
+	if (state->div_force_off) {
+		dprintk( "diversity combination deactivated - forced by COFDM parameters");
+		onoff = 0;
+	}
+	state->div_state = (u8)onoff;
+
+	if (onoff) {
+		dib7000m_write_word(state, 263 + state->reg_offs, 6);
+		dib7000m_write_word(state, 264 + state->reg_offs, 6);
+		dib7000m_write_word(state, 266 + state->reg_offs, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
+	} else {
+		dib7000m_write_word(state, 263 + state->reg_offs, 1);
+		dib7000m_write_word(state, 264 + state->reg_offs, 0);
+		dib7000m_write_word(state, 266 + state->reg_offs, 0);
+	}
 
 	return 0;
 }
@@ -266,7 +321,7 @@
 {
 
 /* internal */
-//	dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth
+//	dib7000m_write_word(state, 928, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
 	dib7000m_write_word(state, 929, (0 << 1) | (0 << 0));
 	dib7000m_write_word(state, 930, 776); // 0.625*3.3 / 4096
 
@@ -281,10 +336,10 @@
 
 static void dib7000m_reset_pll_common(struct dib7000m_state *state, const struct dibx000_bandwidth_config *bw)
 {
-	dib7000m_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff);
-	dib7000m_write_word(state, 19,  (bw->internal*1000)        & 0xffff);
-	dib7000m_write_word(state, 21,  (bw->ifreq          >> 16) & 0xffff);
-	dib7000m_write_word(state, 22,   bw->ifreq                 & 0xffff);
+	dib7000m_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
+	dib7000m_write_word(state, 19, (u16) ( (bw->internal*1000)        & 0xffff));
+	dib7000m_write_word(state, 21, (u16) ( (bw->ifreq          >> 16) & 0xffff));
+	dib7000m_write_word(state, 22, (u16) (  bw->ifreq                 & 0xffff));
 
 	dib7000m_write_word(state, 928, bw->sad_cfg);
 }
@@ -325,15 +380,19 @@
 static void dib7000mc_reset_pll(struct dib7000m_state *state)
 {
 	const struct dibx000_bandwidth_config *bw = state->cfg.bw;
+	u16 clk_cfg1;
 
 	// clk_cfg0
 	dib7000m_write_word(state, 907, (bw->pll_prediv << 8) | (bw->pll_ratio << 0));
 
 	// clk_cfg1
 	//dib7000m_write_word(state, 908, (1 << 14) | (3 << 12) |(0 << 11) |
-	dib7000m_write_word(state, 908, (0 << 14) | (3 << 12) |(0 << 11) |
+	clk_cfg1 = (0 << 14) | (3 << 12) |(0 << 11) |
 			(bw->IO_CLK_en_core << 10) | (bw->bypclk_div << 5) | (bw->enable_refdiv << 4) |
-			(bw->pll_bypass << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0));
+			(1 << 3) | (bw->pll_range << 1) | (bw->pll_reset << 0);
+	dib7000m_write_word(state, 908, clk_cfg1);
+	clk_cfg1 = (clk_cfg1 & 0xfff7) | (bw->pll_bypass << 3);
+	dib7000m_write_word(state, 908, clk_cfg1);
 
 	// smpl_cfg
 	dib7000m_write_word(state, 910, (1 << 12) | (2 << 10) | (bw->modulo << 8) | (bw->ADClkSrc << 7));
@@ -344,9 +403,6 @@
 static int dib7000m_reset_gpio(struct dib7000m_state *st)
 {
 	/* reset the GPIOs */
-	dprintk("-D-  gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n",
-		st->cfg.gpio_dir, st->cfg.gpio_val,st->cfg.gpio_pwm_pos);
-
 	dib7000m_write_word(st, 773, st->cfg.gpio_dir);
 	dib7000m_write_word(st, 774, st->cfg.gpio_val);
 
@@ -358,6 +414,107 @@
 	return 0;
 }
 
+static u16 dib7000m_defaults_common[] =
+
+{
+	// auto search configuration
+	3, 2,
+		0x0004,
+		0x1000,
+		0x0814,
+
+	12, 6,
+		0x001b,
+		0x7740,
+		0x005b,
+		0x8d80,
+		0x01c9,
+		0xc380,
+		0x0000,
+		0x0080,
+		0x0000,
+		0x0090,
+		0x0001,
+		0xd4c0,
+
+	1, 26,
+		0x6680, // P_corm_thres Lock algorithms configuration
+
+	1, 170,
+		0x0410, // P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on
+
+	8, 173,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+
+	1, 182,
+		8192, // P_fft_nb_to_cut
+
+	2, 195,
+		0x0ccd, // P_pha3_thres
+		0,      // P_cti_use_cpe, P_cti_use_prog
+
+	1, 205,
+		0x200f, // P_cspu_regul, P_cspu_win_cut
+
+	5, 214,
+		0x023d, // P_adp_regul_cnt
+		0x00a4, // P_adp_noise_cnt
+		0x00a4, // P_adp_regul_ext
+		0x7ff0, // P_adp_noise_ext
+		0x3ccc, // P_adp_fil
+
+	1, 226,
+		0, // P_2d_byp_ti_num
+
+	1, 255,
+		0x800, // P_equal_thres_wgn
+
+	1, 263,
+		0x0001,
+
+	1, 281,
+		0x0010, // P_fec_*
+
+	1, 294,
+		0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
+
+	0
+};
+
+static u16 dib7000m_defaults[] =
+
+{
+	/* set ADC level to -16 */
+	11, 76,
+		(1 << 13) - 825 - 117,
+		(1 << 13) - 837 - 117,
+		(1 << 13) - 811 - 117,
+		(1 << 13) - 766 - 117,
+		(1 << 13) - 737 - 117,
+		(1 << 13) - 693 - 117,
+		(1 << 13) - 648 - 117,
+		(1 << 13) - 619 - 117,
+		(1 << 13) - 575 - 117,
+		(1 << 13) - 531 - 117,
+		(1 << 13) - 501 - 117,
+
+	// Tuner IO bank: max drive (14mA)
+	1, 912,
+		0x2c8a,
+
+	1, 1817,
+		1,
+
+	0,
+};
+
 static int dib7000m_demod_reset(struct dib7000m_state *state)
 {
 	dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
@@ -382,22 +539,47 @@
 		dib7000mc_reset_pll(state);
 
 	if (dib7000m_reset_gpio(state) != 0)
-		dprintk("-E-  GPIO reset was not successful.\n");
+		dprintk( "GPIO reset was not successful.");
 
 	if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
-		dprintk("-E-  OUTPUT_MODE could not be resetted.\n");
+		dprintk( "OUTPUT_MODE could not be reset.");
 
 	/* unforce divstr regardless whether i2c enumeration was done or not */
 	dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) );
 
-	dib7000m_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
+	dib7000m_set_bandwidth(state, 8000);
 
 	dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON);
 	dib7000m_sad_calib(state);
 	dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
 
+	if (state->cfg.dvbt_mode)
+		dib7000m_write_word(state, 1796, 0x0); // select DVB-T output
+
+	if (state->cfg.mobile_mode)
+		dib7000m_write_word(state, 261 + state->reg_offs, 2);
+	else
+		dib7000m_write_word(state, 224 + state->reg_offs, 1);
+
+	// P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
+	if(state->cfg.tuner_is_baseband)
+		dib7000m_write_word(state, 36, 0x0755);
+	else
+		dib7000m_write_word(state, 36, 0x1f55);
+
+	// P_divclksel=3 P_divbitsel=1
+	if (state->revision == 0x4000)
+		dib7000m_write_word(state, 909, (3 << 10) | (1 << 6));
+	else
+		dib7000m_write_word(state, 909, (3 << 4) | 1);
+
+	dib7000m_write_tab(state, dib7000m_defaults_common);
+	dib7000m_write_tab(state, dib7000m_defaults);
+
 	dib7000m_set_power_mode(state, DIB7000M_POWER_INTERFACE_ONLY);
 
+	state->internal_clk = state->cfg.bw->internal;
+
 	return 0;
 }
 
@@ -427,7 +609,7 @@
 			(agc - state->current_agc->split.min_thres) /
 			(state->current_agc->split.max_thres - state->current_agc->split.min_thres);
 
-	dprintk("AGC split_offset: %d\n",split_offset);
+	dprintk( "AGC split_offset: %d",split_offset);
 
 	// P_agc_force_split and P_agc_split_offset
 	return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset);
@@ -435,35 +617,26 @@
 
 static int dib7000m_update_lna(struct dib7000m_state *state)
 {
-	int i;
 	u16 dyn_gain;
 
-	// when there is no LNA to program return immediatly
-	if (state->cfg.update_lna == NULL)
-		return 0;
-
-	msleep(60);
-	for (i = 0; i < 20; i++) {
-		// read dyn_gain here (because it is demod-dependent and not tuner)
+	if (state->cfg.update_lna) {
+		// read dyn_gain here (because it is demod-dependent and not fe)
 		dyn_gain = dib7000m_read_word(state, 390);
 
-		dprintk("agc global: %d\n", dyn_gain);
-
 		if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
 			dib7000m_restart_agc(state);
-			msleep(60);
-		} else
-			break;
+			return 1;
+		}
 	}
 	return 0;
 }
 
-static void dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
+static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band)
 {
 	struct dibx000_agc_config *agc = NULL;
 	int i;
-	if (state->current_band == band)
-		return;
+	if (state->current_band == band && state->current_agc != NULL)
+		return 0;
 	state->current_band = band;
 
 	for (i = 0; i < state->cfg.agc_config_count; i++)
@@ -473,8 +646,8 @@
 		}
 
 	if (agc == NULL) {
-		dprintk("-E-  No valid AGC configuration found for band 0x%02x\n",band);
-		return;
+		dprintk( "no valid AGC configuration found for band 0x%02x",band);
+		return -EINVAL;
 	}
 
 	state->current_agc = agc;
@@ -489,7 +662,7 @@
 	dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp);
 	dib7000m_write_word(state, 99, (agc->beta_mant  << 6) | agc->beta_exp);
 
-	dprintk("-D-  WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
+	dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",
 		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
 
 	/* AGC continued */
@@ -510,7 +683,7 @@
 
 	if (state->revision > 0x4000) { // settings for the MC
 		dib7000m_write_word(state, 71,   agc->agc1_pt3);
-//		dprintk("-D-  929: %x %d %d\n",
+//		dprintk( "929: %x %d %d",
 //			(dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel);
 		dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2));
 	} else {
@@ -519,33 +692,160 @@
 		for (i = 0; i < 9; i++)
 			dib7000m_write_word(state, 88 + i, b[i]);
 	}
+	return 0;
 }
 
-static void dib7000m_update_timf_freq(struct dib7000m_state *state)
+static void dib7000m_update_timf(struct dib7000m_state *state)
 {
 	u32 timf = (dib7000m_read_word(state, 436) << 16) | dib7000m_read_word(state, 437);
-	state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100);
+	state->timf = timf * 160 / (state->current_bandwidth / 50);
 	dib7000m_write_word(state, 23, (u16) (timf >> 16));
 	dib7000m_write_word(state, 24, (u16) (timf & 0xffff));
-	dprintk("-D-  Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf);
+	dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default);
 }
 
-static void dib7000m_set_channel(struct dib7000m_state *state, struct dibx000_ofdm_channel *ch, u8 seq)
+static int dib7000m_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+{
+	struct dib7000m_state *state = demod->demodulator_priv;
+	u16 cfg_72 = dib7000m_read_word(state, 72);
+	int ret = -1;
+	u8 *agc_state = &state->agc_state;
+	u8 agc_split;
+
+	switch (state->agc_state) {
+		case 0:
+			// set power-up level: interf+analog+AGC
+			dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC);
+			dib7000m_set_adc_state(state, DIBX000_ADC_ON);
+
+			if (dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
+				return -1;
+
+			ret = 7; /* ADC power up */
+			(*agc_state)++;
+			break;
+
+		case 1:
+			/* AGC initialization */
+			if (state->cfg.agc_control)
+				state->cfg.agc_control(&state->demod, 1);
+
+			dib7000m_write_word(state, 75, 32768);
+			if (!state->current_agc->perform_agc_softsplit) {
+				/* we are using the wbd - so slow AGC startup */
+				dib7000m_write_word(state, 103, 1 << 8); /* force 0 split on WBD and restart AGC */
+				(*agc_state)++;
+				ret = 5;
+			} else {
+				/* default AGC startup */
+				(*agc_state) = 4;
+				/* wait AGC rough lock time */
+				ret = 7;
+			}
+
+			dib7000m_restart_agc(state);
+			break;
+
+		case 2: /* fast split search path after 5sec */
+			dib7000m_write_word(state,  72, cfg_72 | (1 << 4)); /* freeze AGC loop */
+			dib7000m_write_word(state, 103, 2 << 9);            /* fast split search 0.25kHz */
+			(*agc_state)++;
+			ret = 14;
+			break;
+
+	case 3: /* split search ended */
+			agc_split = (u8)dib7000m_read_word(state, 392); /* store the split value for the next time */
+			dib7000m_write_word(state, 75, dib7000m_read_word(state, 390)); /* set AGC gain start value */
+
+			dib7000m_write_word(state, 72,  cfg_72 & ~(1 << 4));   /* std AGC loop */
+			dib7000m_write_word(state, 103, (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
+
+			dib7000m_restart_agc(state);
+
+			dprintk( "SPLIT %p: %hd", demod, agc_split);
+
+			(*agc_state)++;
+			ret = 5;
+			break;
+
+		case 4: /* LNA startup */
+			/* wait AGC accurate lock time */
+			ret = 7;
+
+			if (dib7000m_update_lna(state))
+				// wait only AGC rough lock time
+				ret = 5;
+			else
+				(*agc_state)++;
+			break;
+
+		case 5:
+			dib7000m_agc_soft_split(state);
+
+			if (state->cfg.agc_control)
+				state->cfg.agc_control(&state->demod, 0);
+
+			(*agc_state)++;
+			break;
+
+		default:
+			break;
+	}
+	return ret;
+}
+
+static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_frontend_parameters *ch, u8 seq)
 {
 	u16 value, est[4];
 
-	dib7000m_set_agc_config(state, BAND_OF_FREQUENCY(ch->RF_kHz));
+	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
 
 	/* nfft, guard, qam, alpha */
-	dib7000m_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha));
+	value = 0;
+	switch (ch->u.ofdm.transmission_mode) {
+		case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
+		case /* 4K MODE */ 255: value |= (2 << 7); break;
+		default:
+		case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
+	}
+	switch (ch->u.ofdm.guard_interval) {
+		case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
+		case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
+		case GUARD_INTERVAL_1_4:  value |= (3 << 5); break;
+		default:
+		case GUARD_INTERVAL_1_8:  value |= (2 << 5); break;
+	}
+	switch (ch->u.ofdm.constellation) {
+		case QPSK:  value |= (0 << 3); break;
+		case QAM_16: value |= (1 << 3); break;
+		default:
+		case QAM_64: value |= (2 << 3); break;
+	}
+	switch (HIERARCHY_1) {
+		case HIERARCHY_2: value |= 2; break;
+		case HIERARCHY_4: value |= 4; break;
+		default:
+		case HIERARCHY_1: value |= 1; break;
+	}
+	dib7000m_write_word(state, 0, value);
 	dib7000m_write_word(state, 5, (seq << 4));
 
-	/* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */
-	value = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1);
-	if (ch->vit_hrch == 0 || ch->vit_select_hp == 1)
-		value |= (ch->vit_code_rate_hp << 1);
-	else
-		value |= (ch->vit_code_rate_lp << 1);
+	/* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
+	value = 0;
+	if (1 != 0)
+		value |= (1 << 6);
+	if (ch->u.ofdm.hierarchy_information == 1)
+		value |= (1 << 4);
+	if (1 == 1)
+		value |= 1;
+	switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+		case FEC_2_3: value |= (2 << 1); break;
+		case FEC_3_4: value |= (3 << 1); break;
+		case FEC_5_6: value |= (5 << 1); break;
+		case FEC_7_8: value |= (7 << 1); break;
+		default:
+		case FEC_1_2: value |= (1 << 1); break;
+	}
 	dib7000m_write_word(state, 267 + state->reg_offs, value);
 
 	/* offset loop parameters */
@@ -563,32 +863,38 @@
 	dib7000m_write_word(state, 33, (0 << 4) | 0x5);
 
 	/* P_dvsy_sync_wait */
-	switch (ch->nfft) {
-		case 1: value = 256; break;
-		case 2: value = 128; break;
-		case 0:
+	switch (ch->u.ofdm.transmission_mode) {
+		case TRANSMISSION_MODE_8K: value = 256; break;
+		case /* 4K MODE */ 255: value = 128; break;
+		case TRANSMISSION_MODE_2K:
 		default: value = 64; break;
 	}
-	value *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin
-	value <<= 4;
+	switch (ch->u.ofdm.guard_interval) {
+		case GUARD_INTERVAL_1_16: value *= 2; break;
+		case GUARD_INTERVAL_1_8:  value *= 4; break;
+		case GUARD_INTERVAL_1_4:  value *= 8; break;
+		default:
+		case GUARD_INTERVAL_1_32: value *= 1; break;
+	}
+	state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO
 
 	/* deactive the possibility of diversity reception if extended interleave - not for 7000MC */
 	/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
-	if (ch->intlv_native || state->revision > 0x4000)
-		value |= (1 << 2) | (2 << 0);
+	if (1 == 1 || state->revision > 0x4000)
+		state->div_force_off = 0;
 	else
-		value |= 0;
-	dib7000m_write_word(state, 266 + state->reg_offs, value);
+		state->div_force_off = 1;
+	dib7000m_set_diversity_in(&state->demod, state->div_state);
 
 	/* channel estimation fine configuration */
-	switch (ch->nqam) {
-		case 2:
+	switch (ch->u.ofdm.constellation) {
+		case QAM_64:
 			est[0] = 0x0148;       /* P_adp_regul_cnt 0.04 */
 			est[1] = 0xfff0;       /* P_adp_noise_cnt -0.002 */
 			est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
 			est[3] = 0xfff8;       /* P_adp_noise_ext -0.001 */
 			break;
-		case 1:
+		case QAM_16:
 			est[0] = 0x023d;       /* P_adp_regul_cnt 0.07 */
 			est[1] = 0xffdf;       /* P_adp_noise_cnt -0.004 */
 			est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
@@ -604,70 +910,48 @@
 	for (value = 0; value < 4; value++)
 		dib7000m_write_word(state, 214 + value + state->reg_offs, est[value]);
 
-	// set power-up level: interf+analog+AGC
-	dib7000m_set_power_mode(state, DIB7000M_POWER_INTERF_ANALOG_AGC);
-	dib7000m_set_adc_state(state, DIBX000_ADC_ON);
-
-	msleep(7);
-
-	//AGC initialization
-	if (state->cfg.agc_control)
-		state->cfg.agc_control(&state->demod, 1);
-
-	dib7000m_restart_agc(state);
-
-	// wait AGC rough lock time
-	msleep(5);
-
-	dib7000m_update_lna(state);
-	dib7000m_agc_soft_split(state);
-
-	// wait AGC accurate lock time
-	msleep(7);
-
-	if (state->cfg.agc_control)
-		state->cfg.agc_control(&state->demod, 0);
-
 	// set power-up level: autosearch
 	dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_DINTLV_ICIRM_EQUAL_CFROD);
 }
 
-static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static int dib7000m_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
 {
 	struct dib7000m_state *state = demod->demodulator_priv;
-	struct dibx000_ofdm_channel auto_ch;
+	struct dvb_frontend_parameters schan;
 	int ret = 0;
-	u32 value;
+	u32 value, factor;
 
-	INIT_OFDM_CHANNEL(&auto_ch);
-	auto_ch.RF_kHz           = ch->RF_kHz;
-	auto_ch.Bw               = ch->Bw;
-	auto_ch.nqam             = 2;
-	auto_ch.guard            = 0;
-	auto_ch.nfft             = 1;
-	auto_ch.vit_alpha        = 1;
-	auto_ch.vit_select_hp    = 1;
-	auto_ch.vit_code_rate_hp = 2;
-	auto_ch.vit_code_rate_lp = 3;
-	auto_ch.vit_hrch         = 0;
-	auto_ch.intlv_native     = 1;
+	schan = *ch;
 
-	dib7000m_set_channel(state, &auto_ch, 7);
+	schan.u.ofdm.constellation = QAM_64;
+	schan.u.ofdm.guard_interval        = GUARD_INTERVAL_1_32;
+	schan.u.ofdm.transmission_mode         = TRANSMISSION_MODE_8K;
+	schan.u.ofdm.code_rate_HP = FEC_2_3;
+	schan.u.ofdm.code_rate_LP = FEC_3_4;
+	schan.u.ofdm.hierarchy_information         = 0;
+
+	dib7000m_set_channel(state, &schan, 7);
+
+	factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
+	if (factor >= 5000)
+		factor = 1;
+	else
+		factor = 6;
 
 	// always use the setting for 8MHz here lock_time for 7,6 MHz are longer
-	value = 30 * state->cfg.bw->internal;
+	value = 30 * state->internal_clk * factor;
 	ret |= dib7000m_write_word(state, 6,  (u16) ((value >> 16) & 0xffff)); // lock0 wait time
 	ret |= dib7000m_write_word(state, 7,  (u16)  (value        & 0xffff)); // lock0 wait time
-	value = 100 * state->cfg.bw->internal;
+	value = 100 * state->internal_clk * factor;
 	ret |= dib7000m_write_word(state, 8,  (u16) ((value >> 16) & 0xffff)); // lock1 wait time
 	ret |= dib7000m_write_word(state, 9,  (u16)  (value        & 0xffff)); // lock1 wait time
-	value = 500 * state->cfg.bw->internal;
+	value = 500 * state->internal_clk * factor;
 	ret |= dib7000m_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
 	ret |= dib7000m_write_word(state, 11, (u16)  (value        & 0xffff)); // lock2 wait time
 
 	// start search
 	value = dib7000m_read_word(state, 0);
-	ret |= dib7000m_write_word(state, 0, value | (1 << 9));
+	ret |= dib7000m_write_word(state, 0, (u16) (value | (1 << 9)));
 
 	/* clear n_irq_pending */
 	if (state->revision == 0x4000)
@@ -685,12 +969,12 @@
 	u16 irq_pending = dib7000m_read_word(state, reg);
 
 	if (irq_pending & 0x1) { // failed
-		dprintk("#\n");
+		dprintk( "autosearch failed");
 		return 1;
 	}
 
 	if (irq_pending & 0x2) { // succeeded
-		dprintk("!\n");
+		dprintk( "autosearch succeeded");
 		return 2;
 	}
 	return 0; // still pending
@@ -705,7 +989,7 @@
 		return dib7000m_autosearch_irq(state, 537);
 }
 
-static int dib7000m_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
 {
 	struct dib7000m_state *state = demod->demodulator_priv;
 	int ret = 0;
@@ -722,182 +1006,103 @@
 	ret |= dib7000m_write_word(state, 898, 0x0000);
 	msleep(45);
 
-	ret |= dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD);
+	dib7000m_set_power_mode(state, DIB7000M_POWER_COR4_CRY_ESRAM_MOUT_NUD);
 	/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
 	ret |= dib7000m_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
 
-	// never achieved a lock with that bandwidth so far - wait for timfreq to update
+	// never achieved a lock before - wait for timfreq to update
 	if (state->timf == 0)
 		msleep(200);
 
 	//dump_reg(state);
 	/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
 	value = (6 << 8) | 0x80;
-	switch (ch->nfft) {
-		case 0: value |= (7 << 12); break;
-		case 1: value |= (9 << 12); break;
-		case 2: value |= (8 << 12); break;
+	switch (ch->u.ofdm.transmission_mode) {
+		case TRANSMISSION_MODE_2K: value |= (7 << 12); break;
+		case /* 4K MODE */ 255: value |= (8 << 12); break;
+		default:
+		case TRANSMISSION_MODE_8K: value |= (9 << 12); break;
 	}
 	ret |= dib7000m_write_word(state, 26, value);
 
 	/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
 	value = (0 << 4);
-	switch (ch->nfft) {
-		case 0: value |= 0x6; break;
-		case 1: value |= 0x8; break;
-		case 2: value |= 0x7; break;
+	switch (ch->u.ofdm.transmission_mode) {
+		case TRANSMISSION_MODE_2K: value |= 0x6; break;
+		case /* 4K MODE */ 255: value |= 0x7; break;
+		default:
+		case TRANSMISSION_MODE_8K: value |= 0x8; break;
 	}
 	ret |= dib7000m_write_word(state, 32, value);
 
 	/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
 	value = (0 << 4);
-	switch (ch->nfft) {
-		case 0: value |= 0x6; break;
-		case 1: value |= 0x8; break;
-		case 2: value |= 0x7; break;
+	switch (ch->u.ofdm.transmission_mode) {
+		case TRANSMISSION_MODE_2K: value |= 0x6; break;
+		case /* 4K MODE */ 255: value |= 0x7; break;
+		default:
+		case TRANSMISSION_MODE_8K: value |= 0x8; break;
 	}
 	ret |= dib7000m_write_word(state, 33,  value);
 
-	// we achieved a lock - it's time to update the osc freq
+	// we achieved a lock - it's time to update the timf freq
 	if ((dib7000m_read_word(state, 535) >> 6)  & 0x1)
-		dib7000m_update_timf_freq(state);
+		dib7000m_update_timf(state);
 
+    dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
 	return ret;
 }
 
-static int dib7000m_init(struct dvb_frontend *demod)
+static int dib7000m_wakeup(struct dvb_frontend *demod)
 {
 	struct dib7000m_state *state = demod->demodulator_priv;
-	int ret = 0;
-	u8 o = state->reg_offs;
 
 	dib7000m_set_power_mode(state, DIB7000M_POWER_ALL);
 
 	if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0)
-		dprintk("-E-  could not start Slow ADC\n");
+		dprintk( "could not start Slow ADC");
 
-	if (state->cfg.dvbt_mode)
-		dib7000m_write_word(state, 1796, 0x0); // select DVB-T output
-
-	if (state->cfg.mobile_mode)
-		ret |= dib7000m_write_word(state, 261 + o, 2);
-	else
-		ret |= dib7000m_write_word(state, 224 + o, 1);
-
-	ret |= dib7000m_write_word(state, 173 + o, 0);
-	ret |= dib7000m_write_word(state, 174 + o, 0);
-	ret |= dib7000m_write_word(state, 175 + o, 0);
-	ret |= dib7000m_write_word(state, 176 + o, 0);
-	ret |= dib7000m_write_word(state, 177 + o, 0);
-	ret |= dib7000m_write_word(state, 178 + o, 0);
-	ret |= dib7000m_write_word(state, 179 + o, 0);
-	ret |= dib7000m_write_word(state, 180 + o, 0);
-
-	// P_corm_thres Lock algorithms configuration
-	ret |= dib7000m_write_word(state, 26, 0x6680);
-
-	// P_palf_alpha_regul, P_palf_filter_freeze, P_palf_filter_on
-	ret |= dib7000m_write_word(state, 170 + o, 0x0410);
-	// P_fft_nb_to_cut
-	ret |= dib7000m_write_word(state, 182 + o, 8192);
-	// P_pha3_thres
-	ret |= dib7000m_write_word(state, 195 + o, 0x0ccd);
-	// P_cti_use_cpe, P_cti_use_prog
-	ret |= dib7000m_write_word(state, 196 + o,     0);
-	// P_cspu_regul, P_cspu_win_cut
-	ret |= dib7000m_write_word(state, 205 + o, 0x200f);
-	// P_adp_regul_cnt
-	ret |= dib7000m_write_word(state, 214 + o, 0x023d);
-	// P_adp_noise_cnt
-	ret |= dib7000m_write_word(state, 215 + o, 0x00a4);
-	// P_adp_regul_ext
-	ret |= dib7000m_write_word(state, 216 + o, 0x00a4);
-	// P_adp_noise_ext
-	ret |= dib7000m_write_word(state, 217 + o, 0x7ff0);
-	// P_adp_fil
-	ret |= dib7000m_write_word(state, 218 + o, 0x3ccc);
-
-	// P_2d_byp_ti_num
-	ret |= dib7000m_write_word(state, 226 + o, 0);
-
-	// P_fec_*
-	ret |= dib7000m_write_word(state, 281 + o, 0x0010);
-	// P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
-	ret |= dib7000m_write_word(state, 294 + o,0x0062);
-
-	// P_iqc_alpha_pha, P_iqc_alpha_amp, P_iqc_dcc_alpha, ...
-	if(state->cfg.tuner_is_baseband)
-		ret |= dib7000m_write_word(state, 36, 0x0755);
-	else
-		ret |= dib7000m_write_word(state, 36, 0x1f55);
-
-	// auto search configuration
-	ret |= dib7000m_write_word(state, 2,  0x0004);
-	ret |= dib7000m_write_word(state, 3,  0x1000);
-	ret |= dib7000m_write_word(state, 4,  0x0814);
-	ret |= dib7000m_write_word(state, 6,  0x001b);
-	ret |= dib7000m_write_word(state, 7,  0x7740);
-	ret |= dib7000m_write_word(state, 8,  0x005b);
-	ret |= dib7000m_write_word(state, 9,  0x8d80);
-	ret |= dib7000m_write_word(state, 10, 0x01c9);
-	ret |= dib7000m_write_word(state, 11, 0xc380);
-	ret |= dib7000m_write_word(state, 12, 0x0000);
-	ret |= dib7000m_write_word(state, 13, 0x0080);
-	ret |= dib7000m_write_word(state, 14, 0x0000);
-	ret |= dib7000m_write_word(state, 15, 0x0090);
-	ret |= dib7000m_write_word(state, 16, 0x0001);
-	ret |= dib7000m_write_word(state, 17, 0xd4c0);
-	ret |= dib7000m_write_word(state, 263 + o,0x0001);
-
-	// P_divclksel=3 P_divbitsel=1
-	if (state->revision == 0x4000)
-		dib7000m_write_word(state, 909, (3 << 10) | (1 << 6));
-	else
-		dib7000m_write_word(state, 909, (3 << 4) | 1);
-
-	// Tuner IO bank: max drive (14mA)
-	ret |= dib7000m_write_word(state, 912 ,0x2c8a);
-
-	ret |= dib7000m_write_word(state, 1817, 1);
-
-	return ret;
+	return 0;
 }
 
 static int dib7000m_sleep(struct dvb_frontend *demod)
 {
 	struct dib7000m_state *st = demod->demodulator_priv;
 	dib7000m_set_output_mode(st, OUTMODE_HIGH_Z);
-	return dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY) |
-		dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) |
+	dib7000m_set_power_mode(st, DIB7000M_POWER_INTERFACE_ONLY);
+	return dib7000m_set_adc_state(st, DIBX000_SLOW_ADC_OFF) |
 		dib7000m_set_adc_state(st, DIBX000_ADC_OFF);
 }
 
 static int dib7000m_identify(struct dib7000m_state *state)
 {
 	u16 value;
+
 	if ((value = dib7000m_read_word(state, 896)) != 0x01b3) {
-		dprintk("-E-  DiB7000M: wrong Vendor ID (read=0x%x)\n",value);
+		dprintk( "wrong Vendor ID (0x%x)",value);
 		return -EREMOTEIO;
 	}
 
 	state->revision = dib7000m_read_word(state, 897);
 	if (state->revision != 0x4000 &&
 		state->revision != 0x4001 &&
-		state->revision != 0x4002) {
-		dprintk("-E-  DiB7000M: wrong Device ID (%x)\n",value);
+		state->revision != 0x4002 &&
+		state->revision != 0x4003) {
+		dprintk( "wrong Device ID (0x%x)",value);
 		return -EREMOTEIO;
 	}
 
 	/* protect this driver to be used with 7000PC */
 	if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) {
-		dprintk("-E-  DiB7000M: this driver does not work with DiB7000PC\n");
+		dprintk( "this driver does not work with DiB7000PC");
 		return -EREMOTEIO;
 	}
 
 	switch (state->revision) {
-		case 0x4000: dprintk("-I-  found DiB7000MA/PA/MB/PB\n"); break;
-		case 0x4001: state->reg_offs = 1; dprintk("-I-  found DiB7000HC\n"); break;
-		case 0x4002: state->reg_offs = 1; dprintk("-I-  found DiB7000MC\n"); break;
+		case 0x4000: dprintk( "found DiB7000MA/PA/MB/PB"); break;
+		case 0x4001: state->reg_offs = 1; dprintk( "found DiB7000HC"); break;
+		case 0x4002: state->reg_offs = 1; dprintk( "found DiB7000MC"); break;
+		case 0x4003: state->reg_offs = 1; dprintk( "found DiB9000"); break;
 	}
 
 	return 0;
@@ -966,41 +1171,45 @@
 				struct dvb_frontend_parameters *fep)
 {
 	struct dib7000m_state *state = fe->demodulator_priv;
-	struct dibx000_ofdm_channel ch;
-
-	INIT_OFDM_CHANNEL(&ch);
-	FEP2DIB(fep,&ch);
+	int time;
 
 	state->current_bandwidth = fep->u.ofdm.bandwidth;
-	dib7000m_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+	dib7000m_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
 
 	if (fe->ops.tuner_ops.set_params)
 		fe->ops.tuner_ops.set_params(fe, fep);
 
+	/* start up the AGC */
+	state->agc_state = 0;
+	do {
+		time = dib7000m_agc_startup(fe, fep);
+		if (time != -1)
+			msleep(time);
+	} while (time != -1);
+
 	if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
 		fep->u.ofdm.guard_interval    == GUARD_INTERVAL_AUTO ||
 		fep->u.ofdm.constellation     == QAM_AUTO ||
 		fep->u.ofdm.code_rate_HP      == FEC_AUTO) {
 		int i = 800, found;
 
-		dib7000m_autosearch_start(fe, &ch);
+		dib7000m_autosearch_start(fe, fep);
 		do {
 			msleep(1);
 			found = dib7000m_autosearch_is_irq(fe);
 		} while (found == 0 && i--);
 
-		dprintk("autosearch returns: %d\n",found);
+		dprintk("autosearch returns: %d",found);
 		if (found == 0 || found == 1)
 			return 0; // no channel found
 
 		dib7000m_get_frontend(fe, fep);
-		FEP2DIB(fep, &ch);
 	}
 
 	/* make this a config parameter */
 	dib7000m_set_output_mode(state, OUTMODE_MPEG2_FIFO);
 
-	return dib7000m_tune(fe, &ch);
+	return dib7000m_tune(fe, fep);
 }
 
 static int dib7000m_read_status(struct dvb_frontend *fe, fe_status_t *stat)
@@ -1087,7 +1296,7 @@
 		if (dib7000m_identify(&st) != 0) {
 			st.i2c_addr = default_addr;
 			if (dib7000m_identify(&st) != 0) {
-				dprintk("DiB7000M #%d: not identified\n", k);
+				dprintk("DiB7000M #%d: not identified", k);
 				return -EIO;
 			}
 		}
@@ -1100,7 +1309,7 @@
 		/* set new i2c address and force divstart */
 		dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2);
 
-		dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
+		dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
 	}
 
 	for (k = 0; k < no_of_demods; k++) {
@@ -1135,6 +1344,8 @@
 	demod->demodulator_priv = st;
 	memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
 
+	st->timf_default = cfg->bw->timf;
+
 	if (dib7000m_identify(st) != 0)
 		goto error;
 
@@ -1172,7 +1383,7 @@
 
 	.release              = dib7000m_release,
 
-	.init                 = dib7000m_init,
+	.init                 = dib7000m_wakeup,
 	.sleep                = dib7000m_sleep,
 
 	.set_frontend         = dib7000m_set_frontend,
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index aece458..f45bcfc 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -1,7 +1,7 @@
 /*
  * Linux-DVB Driver for DiBcom's second generation DiB7000P (PC).
  *
- * Copyright (C) 2005-6 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2005-7 DiBcom (http://www.dibcom.fr/)
  *
  * This program is free software; you can redistribute it and/or
  *	modify it under the terms of the GNU General Public License as
@@ -18,7 +18,11 @@
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
 
-#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P:"); printk(args); } } while (0)
+static int buggy_sfn_workaround;
+module_param(buggy_sfn_workaround, int, 0644);
+MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0)
 
 struct dib7000p_state {
 	struct dvb_frontend demod;
@@ -36,12 +40,21 @@
 	struct dibx000_agc_config *current_agc;
 	u32 timf;
 
+	u8 div_force_off : 1;
+	u8 div_state : 1;
+	u16 div_sync_wait;
+
+	u8 agc_state;
+
 	u16 gpio_dir;
 	u16 gpio_val;
+
+	u8 sfn_workaround_active :1;
 };
 
 enum dib7000p_power_mode {
 	DIB7000P_POWER_ALL = 0,
+	DIB7000P_POWER_ANALOG_ADC,
 	DIB7000P_POWER_INTERFACE_ONLY,
 };
 
@@ -55,7 +68,7 @@
 	};
 
 	if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
-		dprintk("i2c read error on %d\n",reg);
+		dprintk("i2c read error on %d",reg);
 
 	return (rb[0] << 8) | rb[1];
 }
@@ -71,6 +84,22 @@
 	};
 	return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
 }
+static void dib7000p_write_tab(struct dib7000p_state *state, u16 *buf)
+{
+	u16 l = 0, r, *n;
+	n = buf;
+	l = *n++;
+	while (l) {
+		r = *n++;
+
+		do {
+			dib7000p_write_word(state, r, *n++);
+			r++;
+		} while (--l);
+		l = *n++;
+	}
+}
+
 static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode)
 {
 	int    ret = 0;
@@ -80,7 +109,7 @@
 	fifo_threshold = 1792;
 	smo_mode = (dib7000p_read_word(state, 235) & 0x0010) | (1 << 1);
 
-	dprintk("-I-  Setting output mode for demod %p to %d\n",
+	dprintk( "setting output mode for demod %p to %d",
 			&state->demod, mode);
 
 	switch (mode) {
@@ -104,11 +133,14 @@
 			fifo_threshold = 512;
 			outreg = (1 << 10) | (5 << 6);
 			break;
+		case OUTMODE_ANALOG_ADC:
+			outreg = (1 << 10) | (3 << 6);
+			break;
 		case OUTMODE_HIGH_Z:  // disable
 			outreg = 0;
 			break;
 		default:
-			dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
+			dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod);
 			break;
 	}
 
@@ -122,6 +154,30 @@
 	return ret;
 }
 
+static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff)
+{
+	struct dib7000p_state *state = demod->demodulator_priv;
+
+	if (state->div_force_off) {
+		dprintk( "diversity combination deactivated - forced by COFDM parameters");
+		onoff = 0;
+	}
+	state->div_state = (u8)onoff;
+
+	if (onoff) {
+		dib7000p_write_word(state, 204, 6);
+		dib7000p_write_word(state, 205, 16);
+		/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
+		dib7000p_write_word(state, 207, (state->div_sync_wait << 4) | (1 << 2) | (2 << 0));
+	} else {
+		dib7000p_write_word(state, 204, 1);
+		dib7000p_write_word(state, 205, 0);
+		dib7000p_write_word(state, 207, 0);
+	}
+
+	return 0;
+}
+
 static int dib7000p_set_power_mode(struct dib7000p_state *state, enum dib7000p_power_mode mode)
 {
 	/* by default everything is powered off */
@@ -134,10 +190,21 @@
 		case DIB7000P_POWER_ALL:
 			reg_774 = 0x0000; reg_775 = 0x0000; reg_776 = 0x0; reg_899 = 0x0; reg_1280 &= 0x01ff;
 			break;
+
+		case DIB7000P_POWER_ANALOG_ADC:
+			/* dem, cfg, iqc, sad, agc */
+			reg_774 &= ~((1 << 15) | (1 << 14) | (1 << 11) | (1 << 10) | (1 << 9));
+			/* nud */
+			reg_776 &= ~((1 << 0));
+			/* Dout */
+			reg_1280 &= ~((1 << 11));
+			/* fall through wanted to enable the interfaces */
+
 		/* just leave power on the control-interfaces: GPIO and (I2C or SDIO) */
 		case DIB7000P_POWER_INTERFACE_ONLY: /* TODO power up either SDIO or I2C */
 			reg_1280 &= ~((1 << 14) | (1 << 13) | (1 << 12) | (1 << 10));
 			break;
+
 /* TODO following stuff is just converted from the dib7000-driver - check when is used what */
 	}
 
@@ -188,34 +255,31 @@
 			break;
 	}
 
-//	dprintk("908: %x, 909: %x\n", reg_908, reg_909);
+//	dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
 
 	dib7000p_write_word(state, 908, reg_908);
 	dib7000p_write_word(state, 909, reg_909);
 }
 
-static int dib7000p_set_bandwidth(struct dvb_frontend *demod, u8 BW_Idx)
+static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw)
 {
-	struct dib7000p_state *state = demod->demodulator_priv;
 	u32 timf;
 
 	// store the current bandwidth for later use
-	state->current_bandwidth = BW_Idx;
+	state->current_bandwidth = bw;
 
 	if (state->timf == 0) {
-		dprintk("-D-  Using default timf\n");
+		dprintk( "using default timf");
 		timf = state->cfg.bw->timf;
 	} else {
-		dprintk("-D-  Using updated timf\n");
+		dprintk( "using updated timf");
 		timf = state->timf;
 	}
 
-	timf = timf * (BW_INDEX_TO_KHZ(BW_Idx) / 100) / 80;
+	timf = timf * (bw / 50) / 160;
 
-	dprintk("timf: %d\n",timf);
-
-	dib7000p_write_word(state, 23, (timf >> 16) & 0xffff);
-	dib7000p_write_word(state, 24, (timf      ) & 0xffff);
+	dib7000p_write_word(state, 23, (u16) ((timf >> 16) & 0xffff));
+	dib7000p_write_word(state, 24, (u16) ((timf      ) & 0xffff));
 
 	return 0;
 }
@@ -223,7 +287,7 @@
 static int dib7000p_sad_calib(struct dib7000p_state *state)
 {
 /* internal */
-//	dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is written in set_bandwidth
+//	dib7000p_write_word(state, 72, (3 << 14) | (1 << 12) | (524 << 0)); // sampling clock of the SAD is writting in set_bandwidth
 	dib7000p_write_word(state, 73, (0 << 1) | (0 << 0));
 	dib7000p_write_word(state, 74, 776); // 0.625*3.3 / 4096
 
@@ -236,18 +300,37 @@
 	return 0;
 }
 
+int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
+{
+	struct dib7000p_state *state = demod->demodulator_priv;
+	if (value > 4095)
+		value = 4095;
+	state->wbd_ref = value;
+	return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
+}
+
+EXPORT_SYMBOL(dib7000p_set_wbd_ref);
 static void dib7000p_reset_pll(struct dib7000p_state *state)
 {
 	struct dibx000_bandwidth_config *bw = &state->cfg.bw[0];
+	u16 clk_cfg0;
 
+	/* force PLL bypass */
+	clk_cfg0 = (1 << 15) | ((bw->pll_ratio & 0x3f) << 9) |
+		(bw->modulo << 7) | (bw->ADClkSrc << 6) | (bw->IO_CLK_en_core << 5) |
+		(bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0);
+
+	dib7000p_write_word(state, 900, clk_cfg0);
+
+	/* P_pll_cfg */
 	dib7000p_write_word(state, 903, (bw->pll_prediv << 5) | (((bw->pll_ratio >> 6) & 0x3) << 3) | (bw->pll_range << 1) | bw->pll_reset);
-	dib7000p_write_word(state, 900, ((bw->pll_ratio & 0x3f) << 9) | (bw->pll_bypass << 15) | (bw->modulo << 7) | (bw->ADClkSrc << 6) |
-		(bw->IO_CLK_en_core << 5) | (bw->bypclk_div << 2) | (bw->enable_refdiv << 1) | (0 << 0));
+	clk_cfg0 = (bw->pll_bypass << 15) | (clk_cfg0 & 0x7fff);
+	dib7000p_write_word(state, 900, clk_cfg0);
 
-	dib7000p_write_word(state, 18, ((bw->internal*1000) >> 16) & 0xffff);
-	dib7000p_write_word(state, 19,  (bw->internal*1000       ) & 0xffff);
-	dib7000p_write_word(state, 21,  (bw->ifreq          >> 16) & 0xffff);
-	dib7000p_write_word(state, 22,  (bw->ifreq               ) & 0xffff);
+	dib7000p_write_word(state, 18, (u16) (((bw->internal*1000) >> 16) & 0xffff));
+	dib7000p_write_word(state, 19, (u16) ( (bw->internal*1000       ) & 0xffff));
+	dib7000p_write_word(state, 21, (u16) ( (bw->ifreq          >> 16) & 0xffff));
+	dib7000p_write_word(state, 22, (u16) ( (bw->ifreq               ) & 0xffff));
 
 	dib7000p_write_word(state, 72, bw->sad_cfg);
 }
@@ -255,7 +338,7 @@
 static int dib7000p_reset_gpio(struct dib7000p_state *st)
 {
 	/* reset the GPIOs */
-	dprintk("-D-  gpio dir: %x: gpio val: %x, gpio pwm pos: %x\n",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos);
+	dprintk( "gpio dir: %x: val: %x, pwm_pos: %x",st->gpio_dir, st->gpio_val,st->cfg.gpio_pwm_pos);
 
 	dib7000p_write_word(st, 1029, st->gpio_dir);
 	dib7000p_write_word(st, 1030, st->gpio_val);
@@ -268,6 +351,120 @@
 	return 0;
 }
 
+static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
+{
+	st->gpio_dir = dib7000p_read_word(st, 1029);
+	st->gpio_dir &= ~(1 << num);         /* reset the direction bit */
+	st->gpio_dir |=  (dir & 0x1) << num; /* set the new direction */
+	dib7000p_write_word(st, 1029, st->gpio_dir);
+
+	st->gpio_val = dib7000p_read_word(st, 1030);
+	st->gpio_val &= ~(1 << num);          /* reset the direction bit */
+	st->gpio_val |=  (val & 0x01) << num; /* set the new value */
+	dib7000p_write_word(st, 1030, st->gpio_val);
+
+	return 0;
+}
+
+int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
+{
+	struct dib7000p_state *state = demod->demodulator_priv;
+	return dib7000p_cfg_gpio(state, num, dir, val);
+}
+
+EXPORT_SYMBOL(dib7000p_set_gpio);
+static u16 dib7000p_defaults[] =
+
+{
+	// auto search configuration
+	3, 2,
+		0x0004,
+		0x1000,
+		0x0814, /* Equal Lock */
+
+	12, 6,
+		0x001b,
+		0x7740,
+		0x005b,
+		0x8d80,
+		0x01c9,
+		0xc380,
+		0x0000,
+		0x0080,
+		0x0000,
+		0x0090,
+		0x0001,
+		0xd4c0,
+
+	1, 26,
+		0x6680, // P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26
+
+	/* set ADC level to -16 */
+	11, 79,
+		(1 << 13) - 825 - 117,
+		(1 << 13) - 837 - 117,
+		(1 << 13) - 811 - 117,
+		(1 << 13) - 766 - 117,
+		(1 << 13) - 737 - 117,
+		(1 << 13) - 693 - 117,
+		(1 << 13) - 648 - 117,
+		(1 << 13) - 619 - 117,
+		(1 << 13) - 575 - 117,
+		(1 << 13) - 531 - 117,
+		(1 << 13) - 501 - 117,
+
+	1, 142,
+		0x0410, // P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16
+
+	/* disable power smoothing */
+	8, 145,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+
+	1, 154,
+		1 << 13, // P_fft_freq_dir=1, P_fft_nb_to_cut=0
+
+	1, 168,
+		0x0ccd, // P_pha3_thres, default 0x3000
+
+//	1, 169,
+//		0x0010, // P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010
+
+	1, 183,
+		0x200f, // P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005
+
+	5, 187,
+		0x023d, // P_adp_regul_cnt=573, default: 410
+		0x00a4, // P_adp_noise_cnt=
+		0x00a4, // P_adp_regul_ext
+		0x7ff0, // P_adp_noise_ext
+		0x3ccc, // P_adp_fil
+
+	1, 198,
+		0x800, // P_equal_thres_wgn
+
+	1, 222,
+		0x0010, // P_fec_ber_rs_len=2
+
+	1, 235,
+		0x0062, // P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
+
+	2, 901,
+		0x0006, // P_clk_cfg1
+		(3 << 10) | (1 << 6), // P_divclksel=3 P_divbitsel=1
+
+	1, 905,
+		0x2c8e, // Tuner IO bank: max drive (14mA) + divout pads max drive
+
+	0,
+};
+
 static int dib7000p_demod_reset(struct dib7000p_state *state)
 {
 	dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
@@ -292,47 +489,34 @@
 	dib7000p_reset_pll(state);
 
 	if (dib7000p_reset_gpio(state) != 0)
-		dprintk("-E-  GPIO reset was not successful.\n");
+		dprintk( "GPIO reset was not successful.");
 
 	if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0)
-		dprintk("-E-  OUTPUT_MODE could not be resetted.\n");
+		dprintk( "OUTPUT_MODE could not be reset.");
 
 	/* unforce divstr regardless whether i2c enumeration was done or not */
 	dib7000p_write_word(state, 1285, dib7000p_read_word(state, 1285) & ~(1 << 1) );
 
+	dib7000p_set_bandwidth(state, 8000);
+
+	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
+	dib7000p_sad_calib(state);
+	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_OFF);
+
+	// P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ...
+	if(state->cfg.tuner_is_baseband)
+		dib7000p_write_word(state, 36,0x0755);
+	else
+		dib7000p_write_word(state, 36,0x1f55);
+
+	dib7000p_write_tab(state, dib7000p_defaults);
+
 	dib7000p_set_power_mode(state, DIB7000P_POWER_INTERFACE_ONLY);
 
+
 	return 0;
 }
 
-static void dib7000p_restart_agc(struct dib7000p_state *state)
-{
-	// P_restart_iqc & P_restart_agc
-	dib7000p_write_word(state, 770, 0x0c00);
-	dib7000p_write_word(state, 770, 0x0000);
-}
-
-static void dib7000p_update_lna(struct dib7000p_state *state)
-{
-	int i;
-	u16 dyn_gain;
-
-	// when there is no LNA to program return immediatly
-	if (state->cfg.update_lna == NULL)
-		return;
-
-	for (i = 0; i < 5; i++) {
-		// read dyn_gain here (because it is demod-dependent and not tuner)
-		dyn_gain = dib7000p_read_word(state, 394);
-
-		if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
-			dib7000p_restart_agc(state);
-			msleep(5);
-		} else
-			break;
-	}
-}
-
 static void dib7000p_pll_clk_cfg(struct dib7000p_state *state)
 {
 	u16 tmp = 0;
@@ -342,61 +526,270 @@
 	dib7000p_write_word(state, 900, (tmp & 0x7fff) | (1 << 6));     //use High freq clock
 }
 
-static void dib7000p_update_timf_freq(struct dib7000p_state *state)
+static void dib7000p_restart_agc(struct dib7000p_state *state)
 {
-	u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
-	state->timf = timf * 80 / (BW_INDEX_TO_KHZ(state->current_bandwidth) / 100);
-	dib7000p_write_word(state, 23, (u16) (timf >> 16));
-	dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
-	dprintk("-D-  Updated timf_frequency: %d (default: %d)\n",state->timf, state->cfg.bw->timf);
+	// P_restart_iqc & P_restart_agc
+	dib7000p_write_word(state, 770, (1 << 11) | (1 << 9));
+	dib7000p_write_word(state, 770, 0x0000);
 }
 
-static void dib7000p_set_channel(struct dib7000p_state *state, struct dibx000_ofdm_channel *ch, u8 seq)
+static int dib7000p_update_lna(struct dib7000p_state *state)
 {
-	u16 tmp, est[4]; // reg_26, reg_32, reg_33, reg_187, reg_188, reg_189, reg_190, reg_207, reg_208;
+	u16 dyn_gain;
+
+	// when there is no LNA to program return immediatly
+	if (state->cfg.update_lna) {
+		// read dyn_gain here (because it is demod-dependent and not fe)
+		dyn_gain = dib7000p_read_word(state, 394);
+		if (state->cfg.update_lna(&state->demod,dyn_gain)) { // LNA has changed
+			dib7000p_restart_agc(state);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band)
+{
+	struct dibx000_agc_config *agc = NULL;
+	int i;
+	if (state->current_band == band && state->current_agc != NULL)
+		return 0;
+	state->current_band = band;
+
+	for (i = 0; i < state->cfg.agc_config_count; i++)
+		if (state->cfg.agc[i].band_caps & band) {
+			agc = &state->cfg.agc[i];
+			break;
+		}
+
+	if (agc == NULL) {
+		dprintk( "no valid AGC configuration found for band 0x%02x",band);
+		return -EINVAL;
+	}
+
+	state->current_agc = agc;
+
+	/* AGC */
+	dib7000p_write_word(state, 75 ,  agc->setup );
+	dib7000p_write_word(state, 76 ,  agc->inv_gain );
+	dib7000p_write_word(state, 77 ,  agc->time_stabiliz );
+	dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
+
+	// Demod AGC loop configuration
+	dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
+	dib7000p_write_word(state, 102, (agc->beta_mant << 6)  | agc->beta_exp);
+
+	/* AGC continued */
+	dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d",
+		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
+
+	if (state->wbd_ref != 0)
+		dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
+	else
+		dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
+
+	dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8));
+
+	dib7000p_write_word(state, 107,  agc->agc1_max);
+	dib7000p_write_word(state, 108,  agc->agc1_min);
+	dib7000p_write_word(state, 109,  agc->agc2_max);
+	dib7000p_write_word(state, 110,  agc->agc2_min);
+	dib7000p_write_word(state, 111, (agc->agc1_pt1    << 8) | agc->agc1_pt2);
+	dib7000p_write_word(state, 112,  agc->agc1_pt3);
+	dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
+	dib7000p_write_word(state, 114, (agc->agc2_pt1    << 8) | agc->agc2_pt2);
+	dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
+	return 0;
+}
+
+static int dib7000p_agc_startup(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
+{
+	struct dib7000p_state *state = demod->demodulator_priv;
+	int ret = -1;
+	u8 *agc_state = &state->agc_state;
+	u8 agc_split;
+
+	switch (state->agc_state) {
+		case 0:
+			// set power-up level: interf+analog+AGC
+			dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
+			dib7000p_set_adc_state(state, DIBX000_ADC_ON);
+			dib7000p_pll_clk_cfg(state);
+
+			if (dib7000p_set_agc_config(state, BAND_OF_FREQUENCY(ch->frequency/1000)) != 0)
+				return -1;
+
+			ret = 7;
+			(*agc_state)++;
+			break;
+
+		case 1:
+			// AGC initialization
+			if (state->cfg.agc_control)
+				state->cfg.agc_control(&state->demod, 1);
+
+			dib7000p_write_word(state, 78, 32768);
+			if (!state->current_agc->perform_agc_softsplit) {
+				/* we are using the wbd - so slow AGC startup */
+				/* force 0 split on WBD and restart AGC */
+				dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | (1 << 8));
+				(*agc_state)++;
+				ret = 5;
+			} else {
+				/* default AGC startup */
+				(*agc_state) = 4;
+				/* wait AGC rough lock time */
+				ret = 7;
+			}
+
+			dib7000p_restart_agc(state);
+			break;
+
+		case 2: /* fast split search path after 5sec */
+			dib7000p_write_word(state,  75, state->current_agc->setup | (1 << 4)); /* freeze AGC loop */
+			dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (2 << 9) | (0 << 8)); /* fast split search 0.25kHz */
+			(*agc_state)++;
+			ret = 14;
+			break;
+
+	case 3: /* split search ended */
+			agc_split = (u8)dib7000p_read_word(state, 396); /* store the split value for the next time */
+			dib7000p_write_word(state, 78, dib7000p_read_word(state, 394)); /* set AGC gain start value */
+
+			dib7000p_write_word(state, 75,  state->current_agc->setup);   /* std AGC loop */
+			dib7000p_write_word(state, 106, (state->current_agc->wbd_sel << 13) | (state->current_agc->wbd_alpha << 9) | agc_split); /* standard split search */
+
+			dib7000p_restart_agc(state);
+
+			dprintk( "SPLIT %p: %hd", demod, agc_split);
+
+			(*agc_state)++;
+			ret = 5;
+			break;
+
+		case 4: /* LNA startup */
+			// wait AGC accurate lock time
+			ret = 7;
+
+			if (dib7000p_update_lna(state))
+				// wait only AGC rough lock time
+				ret = 5;
+			else // nothing was done, go to the next state
+				(*agc_state)++;
+			break;
+
+		case 5:
+			if (state->cfg.agc_control)
+				state->cfg.agc_control(&state->demod, 0);
+			(*agc_state)++;
+			break;
+		default:
+			break;
+	}
+	return ret;
+}
+
+static void dib7000p_update_timf(struct dib7000p_state *state)
+{
+	u32 timf = (dib7000p_read_word(state, 427) << 16) | dib7000p_read_word(state, 428);
+	state->timf = timf * 160 / (state->current_bandwidth / 50);
+	dib7000p_write_word(state, 23, (u16) (timf >> 16));
+	dib7000p_write_word(state, 24, (u16) (timf & 0xffff));
+	dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->cfg.bw->timf);
+
+}
+
+static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_frontend_parameters *ch, u8 seq)
+{
+	u16 value, est[4];
+
+    dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
 
 	/* nfft, guard, qam, alpha */
-	dib7000p_write_word(state, 0, (ch->nfft << 7) | (ch->guard << 5) | (ch->nqam << 3) | (ch->vit_alpha));
+	value = 0;
+	switch (ch->u.ofdm.transmission_mode) {
+		case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
+		case /* 4K MODE */ 255: value |= (2 << 7); break;
+		default:
+		case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
+	}
+	switch (ch->u.ofdm.guard_interval) {
+		case GUARD_INTERVAL_1_32: value |= (0 << 5); break;
+		case GUARD_INTERVAL_1_16: value |= (1 << 5); break;
+		case GUARD_INTERVAL_1_4:  value |= (3 << 5); break;
+		default:
+		case GUARD_INTERVAL_1_8:  value |= (2 << 5); break;
+	}
+	switch (ch->u.ofdm.constellation) {
+		case QPSK:  value |= (0 << 3); break;
+		case QAM_16: value |= (1 << 3); break;
+		default:
+		case QAM_64: value |= (2 << 3); break;
+	}
+	switch (HIERARCHY_1) {
+		case HIERARCHY_2: value |= 2; break;
+		case HIERARCHY_4: value |= 4; break;
+		default:
+		case HIERARCHY_1: value |= 1; break;
+	}
+	dib7000p_write_word(state, 0, value);
 	dib7000p_write_word(state, 5, (seq << 4) | 1); /* do not force tps, search list 0 */
 
-	/* P_dintl_native, P_dintlv_inv, P_vit_hrch, P_vit_code_rate, P_vit_select_hp */
-	tmp = (ch->intlv_native << 6) | (ch->vit_hrch << 4) | (ch->vit_select_hp & 0x1);
-	if (ch->vit_hrch == 0 || ch->vit_select_hp == 1)
-		tmp |= (ch->vit_code_rate_hp << 1);
-	else
-		tmp |= (ch->vit_code_rate_lp << 1);
-	dib7000p_write_word(state, 208, tmp);
+	/* P_dintl_native, P_dintlv_inv, P_hrch, P_code_rate, P_select_hp */
+	value = 0;
+	if (1 != 0)
+		value |= (1 << 6);
+	if (ch->u.ofdm.hierarchy_information == 1)
+		value |= (1 << 4);
+	if (1 == 1)
+		value |= 1;
+	switch ((ch->u.ofdm.hierarchy_information == 0 || 1 == 1) ? ch->u.ofdm.code_rate_HP : ch->u.ofdm.code_rate_LP) {
+		case FEC_2_3: value |= (2 << 1); break;
+		case FEC_3_4: value |= (3 << 1); break;
+		case FEC_5_6: value |= (5 << 1); break;
+		case FEC_7_8: value |= (7 << 1); break;
+		default:
+		case FEC_1_2: value |= (1 << 1); break;
+	}
+	dib7000p_write_word(state, 208, value);
+
+	/* offset loop parameters */
+	dib7000p_write_word(state, 26, 0x6680); // timf(6xxx)
+	dib7000p_write_word(state, 32, 0x0003); // pha_off_max(xxx3)
+	dib7000p_write_word(state, 29, 0x1273); // isi
+	dib7000p_write_word(state, 33, 0x0005); // sfreq(xxx5)
 
 	/* P_dvsy_sync_wait */
-	switch (ch->nfft) {
-		case 1: tmp = 256; break;
-		case 2: tmp = 128; break;
-		case 0:
-		default: tmp = 64; break;
+	switch (ch->u.ofdm.transmission_mode) {
+		case TRANSMISSION_MODE_8K: value = 256; break;
+		case /* 4K MODE */ 255: value = 128; break;
+		case TRANSMISSION_MODE_2K:
+		default: value = 64; break;
 	}
-	tmp *= ((1 << (ch->guard)) * 3 / 2); // add 50% SFN margin
-	tmp <<= 4;
+	switch (ch->u.ofdm.guard_interval) {
+		case GUARD_INTERVAL_1_16: value *= 2; break;
+		case GUARD_INTERVAL_1_8:  value *= 4; break;
+		case GUARD_INTERVAL_1_4:  value *= 8; break;
+		default:
+		case GUARD_INTERVAL_1_32: value *= 1; break;
+	}
+	state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO
 
-	/* deactive the possibility of diversity reception if extended interleave */
-	/* P_dvsy_sync_mode = 0, P_dvsy_sync_enable=1, P_dvcb_comb_mode=2 */
-	if (ch->intlv_native || ch->nfft == 1)
-		tmp |= (1 << 2) | (2 << 0);
-	dib7000p_write_word(state, 207, tmp);
-
-	dib7000p_write_word(state, 26, 0x6680);   // timf(6xxx)
-	dib7000p_write_word(state, 29, 0x1273);   // isi inh1273 on1073
-	dib7000p_write_word(state, 32, 0x0003);   // pha_off_max(xxx3)
-	dib7000p_write_word(state, 33, 0x0005);   // sfreq(xxx5)
+	/* deactive the possibility of diversity reception if extended interleaver */
+	state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
+	dib7000p_set_diversity_in(&state->demod, state->div_state);
 
 	/* channel estimation fine configuration */
-	switch (ch->nqam) {
-		case 2:
+	switch (ch->u.ofdm.constellation) {
+		case QAM_64:
 			est[0] = 0x0148;       /* P_adp_regul_cnt 0.04 */
 			est[1] = 0xfff0;       /* P_adp_noise_cnt -0.002 */
 			est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
 			est[3] = 0xfff8;       /* P_adp_noise_ext -0.001 */
 			break;
-		case 1:
+		case QAM_16:
 			est[0] = 0x023d;       /* P_adp_regul_cnt 0.07 */
 			est[1] = 0xffdf;       /* P_adp_noise_cnt -0.004 */
 			est[2] = 0x00a4;       /* P_adp_regul_ext 0.02 */
@@ -409,66 +802,45 @@
 			est[3] = 0xfff8;       /* P_adp_noise_ext -0.002 */
 			break;
 	}
-	for (tmp = 0; tmp < 4; tmp++)
-		dib7000p_write_word(state, 187 + tmp, est[tmp]);
-
-	// set power-up level: interf+analog+AGC
-	dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
-	dib7000p_set_adc_state(state, DIBX000_ADC_ON);
-	dib7000p_pll_clk_cfg(state);
-	msleep(7);
-
-	// AGC initialization
-	if (state->cfg.agc_control)
-		state->cfg.agc_control(&state->demod, 1);
-
-	dib7000p_restart_agc(state);
-
-	// wait AGC rough lock time
-	msleep(5);
-
-	dib7000p_update_lna(state);
-
-	// wait AGC accurate lock time
-	msleep(7);
-	if (state->cfg.agc_control)
-		state->cfg.agc_control(&state->demod, 0);
+	for (value = 0; value < 4; value++)
+		dib7000p_write_word(state, 187 + value, est[value]);
 }
 
-static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static int dib7000p_autosearch_start(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
 {
 	struct dib7000p_state *state = demod->demodulator_priv;
-	struct dibx000_ofdm_channel auto_ch;
-	u32 value;
+	struct dvb_frontend_parameters schan;
+	u32 value, factor;
 
-	INIT_OFDM_CHANNEL(&auto_ch);
-	auto_ch.RF_kHz           = ch->RF_kHz;
-	auto_ch.Bw               = ch->Bw;
-	auto_ch.nqam             = 2;
-	auto_ch.guard            = 0;
-	auto_ch.nfft             = 1;
-	auto_ch.vit_alpha        = 1;
-	auto_ch.vit_select_hp    = 1;
-	auto_ch.vit_code_rate_hp = 2;
-	auto_ch.vit_code_rate_lp = 3;
-	auto_ch.vit_hrch         = 0;
-	auto_ch.intlv_native     = 1;
+	schan = *ch;
+	schan.u.ofdm.constellation = QAM_64;
+	schan.u.ofdm.guard_interval         = GUARD_INTERVAL_1_32;
+	schan.u.ofdm.transmission_mode          = TRANSMISSION_MODE_8K;
+	schan.u.ofdm.code_rate_HP  = FEC_2_3;
+	schan.u.ofdm.code_rate_LP  = FEC_3_4;
+	schan.u.ofdm.hierarchy_information          = 0;
 
-	dib7000p_set_channel(state, &auto_ch, 7);
+	dib7000p_set_channel(state, &schan, 7);
+
+	factor = BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth);
+	if (factor >= 5000)
+		factor = 1;
+	else
+		factor = 6;
 
 	// always use the setting for 8MHz here lock_time for 7,6 MHz are longer
-	value = 30 * state->cfg.bw->internal;
+	value = 30 * state->cfg.bw->internal * factor;
 	dib7000p_write_word(state, 6,  (u16) ((value >> 16) & 0xffff)); // lock0 wait time
 	dib7000p_write_word(state, 7,  (u16)  (value        & 0xffff)); // lock0 wait time
-	value = 100 * state->cfg.bw->internal;
+	value = 100 * state->cfg.bw->internal * factor;
 	dib7000p_write_word(state, 8,  (u16) ((value >> 16) & 0xffff)); // lock1 wait time
 	dib7000p_write_word(state, 9,  (u16)  (value        & 0xffff)); // lock1 wait time
-	value = 500 * state->cfg.bw->internal;
+	value = 500 * state->cfg.bw->internal * factor;
 	dib7000p_write_word(state, 10, (u16) ((value >> 16) & 0xffff)); // lock2 wait time
 	dib7000p_write_word(state, 11, (u16)  (value        & 0xffff)); // lock2 wait time
 
 	value = dib7000p_read_word(state, 0);
-	dib7000p_write_word(state, 0, (1 << 9) | value);
+	dib7000p_write_word(state, 0, (u16) ((1 << 9) | value));
 	dib7000p_read_word(state, 1284);
 	dib7000p_write_word(state, 0, (u16) value);
 
@@ -489,7 +861,95 @@
 	return 0; // still pending
 }
 
-static int dib7000p_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 bw)
+{
+	static s16 notch[]={16143, 14402, 12238, 9713, 6902, 3888, 759, -2392};
+	static u8 sine [] ={0, 2, 3, 5, 6, 8, 9, 11, 13, 14, 16, 17, 19, 20, 22,
+	24, 25, 27, 28, 30, 31, 33, 34, 36, 38, 39, 41, 42, 44, 45, 47, 48, 50, 51,
+	53, 55, 56, 58, 59, 61, 62, 64, 65, 67, 68, 70, 71, 73, 74, 76, 77, 79, 80,
+	82, 83, 85, 86, 88, 89, 91, 92, 94, 95, 97, 98, 99, 101, 102, 104, 105,
+	107, 108, 109, 111, 112, 114, 115, 117, 118, 119, 121, 122, 123, 125, 126,
+	128, 129, 130, 132, 133, 134, 136, 137, 138, 140, 141, 142, 144, 145, 146,
+	147, 149, 150, 151, 152, 154, 155, 156, 157, 159, 160, 161, 162, 164, 165,
+	166, 167, 168, 170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 181, 182,
+	183, 184, 185, 186, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
+	199, 200, 201, 202, 203, 204, 205, 206, 207, 207, 208, 209, 210, 211, 212,
+	213, 214, 215, 215, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
+	225, 226, 227, 227, 228, 229, 229, 230, 231, 231, 232, 233, 233, 234, 235,
+	235, 236, 237, 237, 238, 238, 239, 239, 240, 241, 241, 242, 242, 243, 243,
+	244, 244, 245, 245, 245, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
+	250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 254,
+	254, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+	255, 255, 255, 255, 255, 255};
+
+	u32 xtal = state->cfg.bw->xtal_hz / 1000;
+	int f_rel = ( (rf_khz + xtal/2) / xtal) * xtal - rf_khz;
+	int k;
+	int coef_re[8],coef_im[8];
+	int bw_khz = bw;
+	u32 pha;
+
+	dprintk( "relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal);
+
+
+	if (f_rel < -bw_khz/2 || f_rel > bw_khz/2)
+		return;
+
+	bw_khz /= 100;
+
+	dib7000p_write_word(state, 142 ,0x0610);
+
+	for (k = 0; k < 8; k++) {
+		pha = ((f_rel * (k+1) * 112 * 80/bw_khz) /1000) & 0x3ff;
+
+		if (pha==0) {
+			coef_re[k] = 256;
+			coef_im[k] = 0;
+		} else if(pha < 256) {
+			coef_re[k] = sine[256-(pha&0xff)];
+			coef_im[k] = sine[pha&0xff];
+		} else if (pha == 256) {
+			coef_re[k] = 0;
+			coef_im[k] = 256;
+		} else if (pha < 512) {
+			coef_re[k] = -sine[pha&0xff];
+			coef_im[k] = sine[256 - (pha&0xff)];
+		} else if (pha == 512) {
+			coef_re[k] = -256;
+			coef_im[k] = 0;
+		} else if (pha < 768) {
+			coef_re[k] = -sine[256-(pha&0xff)];
+			coef_im[k] = -sine[pha&0xff];
+		} else if (pha == 768) {
+			coef_re[k] = 0;
+			coef_im[k] = -256;
+		} else {
+			coef_re[k] = sine[pha&0xff];
+			coef_im[k] = -sine[256 - (pha&0xff)];
+		}
+
+		coef_re[k] *= notch[k];
+		coef_re[k] += (1<<14);
+		if (coef_re[k] >= (1<<24))
+			coef_re[k]  = (1<<24) - 1;
+		coef_re[k] /= (1<<15);
+
+		coef_im[k] *= notch[k];
+		coef_im[k] += (1<<14);
+		if (coef_im[k] >= (1<<24))
+			coef_im[k]  = (1<<24)-1;
+		coef_im[k] /= (1<<15);
+
+		dprintk( "PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]);
+
+		dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
+		dib7000p_write_word(state, 144, coef_im[k] & 0x3ff);
+		dib7000p_write_word(state, 143, (1 << 14) | (k << 10) | (coef_re[k] & 0x3ff));
+	}
+	dib7000p_write_word(state,143 ,0);
+}
+
+static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_parameters *ch)
 {
 	struct dib7000p_state *state = demod->demodulator_priv;
 	u16 tmp = 0;
@@ -505,7 +965,15 @@
 	msleep(45);
 
 	/* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */
-	dib7000p_write_word(state, 29, (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3));
+	tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3);
+	if (state->sfn_workaround_active) {
+		dprintk( "SFN workaround is active");
+		tmp |= (1 << 9);
+		dib7000p_write_word(state, 166, 0x4000); // P_pha3_force_pha_shift
+	} else {
+		dib7000p_write_word(state, 166, 0x0000); // P_pha3_force_pha_shift
+	}
+	dib7000p_write_word(state, 29, tmp);
 
 	// never achieved a lock with that bandwidth so far - wait for osc-freq to update
 	if (state->timf == 0)
@@ -515,28 +983,31 @@
 
 	/* P_timf_alpha, P_corm_alpha=6, P_corm_thres=0x80 */
 	tmp = (6 << 8) | 0x80;
-	switch (ch->nfft) {
-		case 0: tmp |= (7 << 12); break;
-		case 1: tmp |= (9 << 12); break;
-		case 2: tmp |= (8 << 12); break;
+	switch (ch->u.ofdm.transmission_mode) {
+		case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break;
+		case /* 4K MODE */ 255: tmp |= (8 << 12); break;
+		default:
+		case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break;
 	}
 	dib7000p_write_word(state, 26, tmp);  /* timf_a(6xxx) */
 
 	/* P_ctrl_freeze_pha_shift=0, P_ctrl_pha_off_max */
 	tmp = (0 << 4);
-	switch (ch->nfft) {
-		case 0: tmp |= 0x6; break;
-		case 1: tmp |= 0x8; break;
-		case 2: tmp |= 0x7; break;
+	switch (ch->u.ofdm.transmission_mode) {
+		case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
+		case /* 4K MODE */ 255: tmp |= 0x7; break;
+		default:
+		case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
 	}
 	dib7000p_write_word(state, 32,  tmp);
 
 	/* P_ctrl_sfreq_inh=0, P_ctrl_sfreq_step */
 	tmp = (0 << 4);
-	switch (ch->nfft) {
-		case 0: tmp |= 0x6; break;
-		case 1: tmp |= 0x8; break;
-		case 2: tmp |= 0x7; break;
+	switch (ch->u.ofdm.transmission_mode) {
+		case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
+		case /* 4K MODE */ 255: tmp |= 0x7; break;
+		default:
+		case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
 	}
 	dib7000p_write_word(state, 33,  tmp);
 
@@ -552,131 +1023,21 @@
 
 	// we achieved a lock - it's time to update the osc freq
 	if ((tmp >> 6) & 0x1)
-		dib7000p_update_timf_freq(state);
+		dib7000p_update_timf(state);
 
+	if (state->cfg.spur_protect)
+		dib7000p_spur_protect(state, ch->frequency/1000, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
+
+    dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->u.ofdm.bandwidth));
 	return 0;
 }
 
-static int dib7000p_init(struct dvb_frontend *demod)
+static int dib7000p_wakeup(struct dvb_frontend *demod)
 {
-	struct dibx000_agc_config *agc;
 	struct dib7000p_state *state = demod->demodulator_priv;
-	int ret = 0;
-
-	// Demodulator default configuration
-	agc = state->cfg.agc;
-
 	dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
 	dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON);
-
-	/* AGC */
-	ret |= dib7000p_write_word(state, 75 ,  agc->setup );
-	ret |= dib7000p_write_word(state, 76 ,  agc->inv_gain );
-	ret |= dib7000p_write_word(state, 77 ,  agc->time_stabiliz );
-	ret |= dib7000p_write_word(state, 100, (agc->alpha_level << 12) | agc->thlock);
-
-	// Demod AGC loop configuration
-	ret |= dib7000p_write_word(state, 101, (agc->alpha_mant << 5) | agc->alpha_exp);
-	ret |= dib7000p_write_word(state, 102, (agc->beta_mant << 6)  | agc->beta_exp);
-
-	/* AGC continued */
-	dprintk("-D-  WBD: ref: %d, sel: %d, active: %d, alpha: %d\n",
-		state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel);
-
-	if (state->wbd_ref != 0)
-		ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | state->wbd_ref);
-	else
-		ret |= dib7000p_write_word(state, 105, (agc->wbd_inv << 12) | agc->wbd_ref);
-
-	ret |= dib7000p_write_word(state, 106, (agc->wbd_sel << 13) | (agc->wbd_alpha << 9) | (agc->perform_agc_softsplit << 8) );
-
-	ret |= dib7000p_write_word(state, 107,  agc->agc1_max);
-	ret |= dib7000p_write_word(state, 108,  agc->agc1_min);
-	ret |= dib7000p_write_word(state, 109,  agc->agc2_max);
-	ret |= dib7000p_write_word(state, 110,  agc->agc2_min);
-	ret |= dib7000p_write_word(state, 111, (agc->agc1_pt1 << 8) | agc->agc1_pt2 );
-	ret |= dib7000p_write_word(state, 112,  agc->agc1_pt3);
-	ret |= dib7000p_write_word(state, 113, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
-	ret |= dib7000p_write_word(state, 114, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
-	ret |= dib7000p_write_word(state, 115, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
-
-	/* disable power smoothing */
-	ret |= dib7000p_write_word(state, 145, 0);
-	ret |= dib7000p_write_word(state, 146, 0);
-	ret |= dib7000p_write_word(state, 147, 0);
-	ret |= dib7000p_write_word(state, 148, 0);
-	ret |= dib7000p_write_word(state, 149, 0);
-	ret |= dib7000p_write_word(state, 150, 0);
-	ret |= dib7000p_write_word(state, 151, 0);
-	ret |= dib7000p_write_word(state, 152, 0);
-
-	// P_timf_alpha=6, P_corm_alpha=6, P_corm_thres=128 default: 6,4,26
-	ret |= dib7000p_write_word(state, 26 ,0x6680);
-
-	// P_palf_filter_on=1, P_palf_filter_freeze=0, P_palf_alpha_regul=16
-	ret |= dib7000p_write_word(state, 142,0x0410);
-	// P_fft_freq_dir=1, P_fft_nb_to_cut=0
-	ret |= dib7000p_write_word(state, 154,1 << 13);
-	// P_pha3_thres, default 0x3000
-	ret |= dib7000p_write_word(state, 168,0x0ccd);
-	// P_cti_use_cpe=0, P_cti_use_prog=0, P_cti_win_len=16, default: 0x0010
-	//ret |= dib7000p_write_word(state, 169,0x0010);
-	// P_cspu_regul=512, P_cspu_win_cut=15, default: 0x2005
-	ret |= dib7000p_write_word(state, 183,0x200f);
-	// P_adp_regul_cnt=573, default: 410
-	ret |= dib7000p_write_word(state, 187,0x023d);
-	// P_adp_noise_cnt=
-	ret |= dib7000p_write_word(state, 188,0x00a4);
-	// P_adp_regul_ext
-	ret |= dib7000p_write_word(state, 189,0x00a4);
-	// P_adp_noise_ext
-	ret |= dib7000p_write_word(state, 190,0x7ff0);
-	// P_adp_fil
-	ret |= dib7000p_write_word(state, 191,0x3ccc);
-
-	ret |= dib7000p_write_word(state, 222,0x0010);
-	// P_smo_mode, P_smo_rs_discard, P_smo_fifo_flush, P_smo_pid_parse, P_smo_error_discard
-	ret |= dib7000p_write_word(state, 235,0x0062);
-
-	// P_iqc_alpha_pha, P_iqc_alpha_amp_dcc_alpha, ...
-	if(state->cfg.tuner_is_baseband)
-		ret |= dib7000p_write_word(state, 36,0x0755);
-	else
-		ret |= dib7000p_write_word(state, 36,0x1f55);
-
-	// auto search configuration
-	ret |= dib7000p_write_word(state, 2  ,0x0004);
-	ret |= dib7000p_write_word(state, 3  ,0x1000);
-
-	/* Equal Lock */
-	ret |= dib7000p_write_word(state, 4   ,0x0814);
-
-	ret |= dib7000p_write_word(state, 6  ,0x001b);
-	ret |= dib7000p_write_word(state, 7  ,0x7740);
-	ret |= dib7000p_write_word(state, 8  ,0x005b);
-	ret |= dib7000p_write_word(state, 9  ,0x8d80);
-	ret |= dib7000p_write_word(state, 10 ,0x01c9);
-	ret |= dib7000p_write_word(state, 11 ,0xc380);
-	ret |= dib7000p_write_word(state, 12 ,0x0000);
-	ret |= dib7000p_write_word(state, 13 ,0x0080);
-	ret |= dib7000p_write_word(state, 14 ,0x0000);
-	ret |= dib7000p_write_word(state, 15 ,0x0090);
-	ret |= dib7000p_write_word(state, 16 ,0x0001);
-	ret |= dib7000p_write_word(state, 17 ,0xd4c0);
-
-	// P_clk_cfg1
-	ret |= dib7000p_write_word(state, 901, 0x0006);
-
-	// P_divclksel=3 P_divbitsel=1
-	ret |= dib7000p_write_word(state, 902, (3 << 10) | (1 << 6));
-
-	// Tuner IO bank: max drive (14mA) + divout pads max drive
-	ret |= dib7000p_write_word(state, 905, 0x2c8e);
-
-	ret |= dib7000p_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
-	dib7000p_sad_calib(state);
-
-	return ret;
+	return 0;
 }
 
 static int dib7000p_sleep(struct dvb_frontend *demod)
@@ -688,16 +1049,16 @@
 static int dib7000p_identify(struct dib7000p_state *st)
 {
 	u16 value;
-	dprintk("-I-  DiB7000PC: checking demod on I2C address: %d (%x)\n",
+	dprintk( "checking demod on I2C address: %d (%x)",
 		st->i2c_addr, st->i2c_addr);
 
 	if ((value = dib7000p_read_word(st, 768)) != 0x01b3) {
-		dprintk("-E-  DiB7000PC: wrong Vendor ID (read=0x%x)\n",value);
+		dprintk( "wrong Vendor ID (read=0x%x)",value);
 		return -EREMOTEIO;
 	}
 
 	if ((value = dib7000p_read_word(st, 769)) != 0x4000) {
-		dprintk("-E-  DiB7000PC: wrong Device ID (%x)\n",value);
+		dprintk( "wrong Device ID (%x)",value);
 		return -EREMOTEIO;
 	}
 
@@ -767,41 +1128,48 @@
 				struct dvb_frontend_parameters *fep)
 {
 	struct dib7000p_state *state = fe->demodulator_priv;
-	struct dibx000_ofdm_channel ch;
-
-	INIT_OFDM_CHANNEL(&ch);
-	FEP2DIB(fep,&ch);
+	int time;
 
 	state->current_bandwidth = fep->u.ofdm.bandwidth;
-	dib7000p_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+	dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(fep->u.ofdm.bandwidth));
+
+	/* maybe the parameter has been changed */
+	state->sfn_workaround_active = buggy_sfn_workaround;
 
 	if (fe->ops.tuner_ops.set_params)
 		fe->ops.tuner_ops.set_params(fe, fep);
 
+	/* start up the AGC */
+	state->agc_state = 0;
+	do {
+		time = dib7000p_agc_startup(fe, fep);
+		if (time != -1)
+			msleep(time);
+	} while (time != -1);
+
 	if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
 		fep->u.ofdm.guard_interval    == GUARD_INTERVAL_AUTO ||
 		fep->u.ofdm.constellation     == QAM_AUTO ||
 		fep->u.ofdm.code_rate_HP      == FEC_AUTO) {
 		int i = 800, found;
 
-		dib7000p_autosearch_start(fe, &ch);
+		dib7000p_autosearch_start(fe, fep);
 		do {
 			msleep(1);
 			found = dib7000p_autosearch_is_irq(fe);
 		} while (found == 0 && i--);
 
-		dprintk("autosearch returns: %d\n",found);
+		dprintk("autosearch returns: %d",found);
 		if (found == 0 || found == 1)
 			return 0; // no channel found
 
 		dib7000p_get_frontend(fe, fep);
-		FEP2DIB(fep, &ch);
 	}
 
 	/* make this a config parameter */
 	dib7000p_set_output_mode(state, OUTMODE_MPEG2_FIFO);
 
-	return dib7000p_tune(fe, &ch);
+	return dib7000p_tune(fe, fep);
 }
 
 static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t *stat)
@@ -879,7 +1247,7 @@
 
 	if (i2c_transfer(i2c_adap, msg, 2) == 2)
 		if (rx[0] == 0x01 && rx[1] == 0xb3) {
-			dprintk("-D-  DiB7000PC detected\n");
+			dprintk("-D-  DiB7000PC detected");
 			return 1;
 		}
 
@@ -887,11 +1255,11 @@
 
 	if (i2c_transfer(i2c_adap, msg, 2) == 2)
 		if (rx[0] == 0x01 && rx[1] == 0xb3) {
-			dprintk("-D-  DiB7000PC detected\n");
+			dprintk("-D-  DiB7000PC detected");
 			return 1;
 		}
 
-	dprintk("-D-  DiB7000PC not detected\n");
+	dprintk("-D-  DiB7000PC not detected");
 	return 0;
 }
 EXPORT_SYMBOL(dib7000pc_detection);
@@ -929,7 +1297,7 @@
 		/* set new i2c address and force divstart */
 		dib7000p_write_word(&st, 1285, (new_addr << 2) | 0x2);
 
-		dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr);
+		dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr);
 	}
 
 	for (k = 0; k < no_of_demods; k++) {
@@ -1000,7 +1368,7 @@
 
 	.release              = dib7000p_release,
 
-	.init                 = dib7000p_init,
+	.init                 = dib7000p_wakeup,
 	.sleep                = dib7000p_sleep,
 
 	.set_frontend         = dib7000p_set_frontend,
diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h
index 79465cf..eefcac8 100644
--- a/drivers/media/dvb/frontends/dib7000p.h
+++ b/drivers/media/dvb/frontends/dib7000p.h
@@ -9,6 +9,7 @@
 	u8 tuner_is_baseband;
 	int (*update_lna) (struct dvb_frontend *, u16 agc_global);
 
+	u8 agc_config_count;
 	struct dibx000_agc_config *agc;
 	struct dibx000_bandwidth_config *bw;
 
@@ -27,20 +28,19 @@
 
 	u8 quartz_direct;
 
+	u8 spur_protect;
+
 	int (*agc_control) (struct dvb_frontend *, u8 before);
 };
 
 #define DEFAULT_DIB7000P_I2C_ADDRESS 18
 
 extern struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg);
+extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
+
 extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
 extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
-
-/* TODO
-extern INT dib7000p_set_gpio(struct dibDemod *demod, UCHAR num, UCHAR dir, UCHAR val);
-extern INT dib7000p_enable_vbg_voltage(struct dibDemod *demod);
-extern void dib7000p_set_hostbus_diversity(struct dibDemod *demod, UCHAR onoff);
-extern USHORT dib7000p_get_current_agc_global(struct dibDemod *demod);
-*/
+extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
+extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
 
 #endif
diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h
index a1df604..5e17275 100644
--- a/drivers/media/dvb/frontends/dibx000_common.h
+++ b/drivers/media/dvb/frontends/dibx000_common.h
@@ -111,6 +111,8 @@
 
 	u32 ifreq;
 	u32 timf;
+
+	u32 xtal_hz;
 };
 
 enum dibx000_adc_states {
@@ -122,56 +124,17 @@
 	DIBX000_VBG_DISABLE,
 };
 
-#define BW_INDEX_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ  ? 8000 : \
+#define BANDWIDTH_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ  ? 8000 : \
 			     (v) == BANDWIDTH_7_MHZ  ? 7000 : \
 			     (v) == BANDWIDTH_6_MHZ  ? 6000 : 8000 )
 
 /* Chip output mode. */
-#define OUTMODE_HIGH_Z                      0
-#define OUTMODE_MPEG2_PAR_GATED_CLK         1
-#define OUTMODE_MPEG2_PAR_CONT_CLK          2
-#define OUTMODE_MPEG2_SERIAL                7
-#define OUTMODE_DIVERSITY                   4
-#define OUTMODE_MPEG2_FIFO                  5
-
-/* I hope I can get rid of the following kludge in the near future */
-struct dibx000_ofdm_channel {
-	u32 RF_kHz;
-	u8  Bw;
-	s16 nfft;
-	s16 guard;
-	s16 nqam;
-	s16 vit_hrch;
-	s16 vit_select_hp;
-	s16 vit_alpha;
-	s16 vit_code_rate_hp;
-	s16 vit_code_rate_lp;
-	u8  intlv_native;
-};
-
-#define FEP2DIB(fep,ch) \
-	(ch)->RF_kHz           = (fep)->frequency / 1000; \
-	(ch)->Bw               = (fep)->u.ofdm.bandwidth; \
-	(ch)->nfft             = (fep)->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ? -1 : (fep)->u.ofdm.transmission_mode; \
-	(ch)->guard            = (fep)->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ? -1 : (fep)->u.ofdm.guard_interval; \
-	(ch)->nqam             = (fep)->u.ofdm.constellation == QAM_AUTO ? -1 : (fep)->u.ofdm.constellation == QAM_64 ? 2 : (fep)->u.ofdm.constellation; \
-	(ch)->vit_hrch         = 0; /* linux-dvb is not prepared for HIERARCHICAL TRANSMISSION */ \
-	(ch)->vit_select_hp    = 1; \
-	(ch)->vit_alpha        = 1; \
-	(ch)->vit_code_rate_hp = (fep)->u.ofdm.code_rate_HP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_HP; \
-	(ch)->vit_code_rate_lp = (fep)->u.ofdm.code_rate_LP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_LP; \
-	(ch)->intlv_native     = 1;
-
-#define INIT_OFDM_CHANNEL(ch) do {\
-	(ch)->Bw               = 0;  \
-	(ch)->nfft             = -1; \
-	(ch)->guard            = -1; \
-	(ch)->nqam             = -1; \
-	(ch)->vit_hrch         = -1; \
-	(ch)->vit_select_hp    = -1; \
-	(ch)->vit_alpha        = -1; \
-	(ch)->vit_code_rate_hp = -1; \
-	(ch)->vit_code_rate_lp = -1; \
-} while (0)
+#define OUTMODE_HIGH_Z              0
+#define OUTMODE_MPEG2_PAR_GATED_CLK 1
+#define OUTMODE_MPEG2_PAR_CONT_CLK  2
+#define OUTMODE_MPEG2_SERIAL        7
+#define OUTMODE_DIVERSITY           4
+#define OUTMODE_MPEG2_FIFO          5
+#define OUTMODE_ANALOG_ADC          6
 
 #endif
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 5f96ffd..8c8d734 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -24,6 +24,59 @@
 
 #include "dvb-pll.h"
 
+struct dvb_pll_priv {
+	/* pll number */
+	int nr;
+
+	/* i2c details */
+	int pll_i2c_address;
+	struct i2c_adapter *i2c;
+
+	/* the PLL descriptor */
+	struct dvb_pll_desc *pll_desc;
+
+	/* cached frequency/bandwidth */
+	u32 frequency;
+	u32 bandwidth;
+};
+
+#define DVB_PLL_MAX 64
+
+static unsigned int dvb_pll_devcount;
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+static unsigned int input[DVB_PLL_MAX] = { [ 0 ... (DVB_PLL_MAX-1) ] = 0 };
+module_param_array(input, int, NULL, 0644);
+MODULE_PARM_DESC(input,"specify rf input choice, 0 for autoselect (default)");
+
+static unsigned int id[DVB_PLL_MAX] =
+	{ [ 0 ... (DVB_PLL_MAX-1) ] = DVB_PLL_UNDEFINED };
+module_param_array(id, int, NULL, 0644);
+MODULE_PARM_DESC(id, "force pll id to use (DEBUG ONLY)");
+
+/* ----------------------------------------------------------- */
+
+struct dvb_pll_desc {
+	char *name;
+	u32  min;
+	u32  max;
+	u32  iffreq;
+	void (*set)(struct dvb_frontend *fe, u8 *buf,
+		    const struct dvb_frontend_parameters *params);
+	u8   *initdata;
+	u8   *sleepdata;
+	int  count;
+	struct {
+		u32 limit;
+		u32 stepsize;
+		u8  config;
+		u8  cb;
+	} entries[12];
+};
+
 /* ----------------------------------------------------------- */
 /* descriptions                                                */
 
@@ -38,7 +91,13 @@
 	0x50 = AGC Take over point = 103 dBuV */
 static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 };
 
-struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
+/*	0x04 = 166.67 kHz divider
+
+	0x80 = AGC Time constant 50ms Iagc = 9 uA
+	0x20 = AGC Take over point = 112 dBuV */
+static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 };
+
+static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
 	.name  = "Thomson dtt7579",
 	.min   = 177000000,
 	.max   = 858000000,
@@ -52,9 +111,8 @@
 		{  999999999, 166667, 0xf4, 0x08 },
 	},
 };
-EXPORT_SYMBOL(dvb_pll_thomson_dtt7579);
 
-struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
 	.name  = "Thomson dtt7610",
 	.min   =  44000000,
 	.max   = 958000000,
@@ -66,19 +124,19 @@
 		{ 999999999, 62500, 0x8e, 0x3c },
 	},
 };
-EXPORT_SYMBOL(dvb_pll_thomson_dtt7610);
 
-static void thomson_dtt759x_bw(u8 *buf, u32 freq, int bandwidth)
+static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf,
+			       const struct dvb_frontend_parameters *params)
 {
-	if (BANDWIDTH_7_MHZ == bandwidth)
+	if (BANDWIDTH_7_MHZ == params->u.ofdm.bandwidth)
 		buf[3] |= 0x10;
 }
 
-struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
 	.name  = "Thomson dtt759x",
 	.min   = 177000000,
 	.max   = 896000000,
-	.setbw = thomson_dtt759x_bw,
+	.set   = thomson_dtt759x_bw,
 	.iffreq= 36166667,
 	.sleepdata = (u8[]){ 2, 0x84, 0x03 },
 	.count = 5,
@@ -90,9 +148,8 @@
 		{  999999999, 166667, 0xfc, 0x08 },
 	},
 };
-EXPORT_SYMBOL(dvb_pll_thomson_dtt759x);
 
-struct dvb_pll_desc dvb_pll_lg_z201 = {
+static struct dvb_pll_desc dvb_pll_lg_z201 = {
 	.name  = "LG z201",
 	.min   = 174000000,
 	.max   = 862000000,
@@ -107,9 +164,8 @@
 		{  999999999, 166667, 0xfc, 0x04 },
 	},
 };
-EXPORT_SYMBOL(dvb_pll_lg_z201);
 
-struct dvb_pll_desc dvb_pll_microtune_4042 = {
+static struct dvb_pll_desc dvb_pll_microtune_4042 = {
 	.name  = "Microtune 4042 FI5",
 	.min   =  57000000,
 	.max   = 858000000,
@@ -121,9 +177,8 @@
 		{ 999999999, 62500, 0x8e, 0x31 },
 	},
 };
-EXPORT_SYMBOL(dvb_pll_microtune_4042);
 
-struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
+static struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
 	/* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
 	.name  = "Thomson dtt761x",
 	.min   =  57000000,
@@ -137,9 +192,8 @@
 		{ 999999999, 62500, 0x8e, 0x3c },
 	},
 };
-EXPORT_SYMBOL(dvb_pll_thomson_dtt761x);
 
-struct dvb_pll_desc dvb_pll_unknown_1 = {
+static struct dvb_pll_desc dvb_pll_unknown_1 = {
 	.name  = "unknown 1", /* used by dntv live dvb-t */
 	.min   = 174000000,
 	.max   = 862000000,
@@ -157,12 +211,11 @@
 		{  999999999, 166667, 0xfc, 0x08 },
 	},
 };
-EXPORT_SYMBOL(dvb_pll_unknown_1);
 
 /* Infineon TUA6010XS
  * used in Thomson Cable Tuner
  */
-struct dvb_pll_desc dvb_pll_tua6010xs = {
+static struct dvb_pll_desc dvb_pll_tua6010xs = {
 	.name  = "Infineon TUA6010XS",
 	.min   =  44250000,
 	.max   = 858000000,
@@ -174,10 +227,9 @@
 		{  999999999, 62500, 0x8e, 0x85 },
 	},
 };
-EXPORT_SYMBOL(dvb_pll_tua6010xs);
 
 /* Panasonic env57h1xd5 (some Philips PLL ?) */
-struct dvb_pll_desc dvb_pll_env57h1xd5 = {
+static struct dvb_pll_desc dvb_pll_env57h1xd5 = {
 	.name  = "Panasonic ENV57H1XD5",
 	.min   =  44250000,
 	.max   = 858000000,
@@ -190,23 +242,24 @@
 		{  999999999, 166667, 0xc2, 0xa4 },
 	},
 };
-EXPORT_SYMBOL(dvb_pll_env57h1xd5);
 
 /* Philips TDA6650/TDA6651
  * used in Panasonic ENV77H11D5
  */
-static void tda665x_bw(u8 *buf, u32 freq, int bandwidth)
+static void tda665x_bw(struct dvb_frontend *fe, u8 *buf,
+		       const struct dvb_frontend_parameters *params)
 {
-	if (bandwidth == BANDWIDTH_8_MHZ)
+	if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
 		buf[3] |= 0x08;
 }
 
-struct dvb_pll_desc dvb_pll_tda665x = {
+static struct dvb_pll_desc dvb_pll_tda665x = {
 	.name  = "Philips TDA6650/TDA6651",
 	.min   =  44250000,
 	.max   = 858000000,
-	.setbw = tda665x_bw,
+	.set   = tda665x_bw,
 	.iffreq= 36166667,
+	.initdata = (u8[]){ 4, 0x0b, 0xf5, 0x85, 0xab },
 	.count = 12,
 	.entries = {
 		{   93834000, 166667, 0xca, 0x61 /* 011 0 0 0  01 */ },
@@ -223,36 +276,35 @@
 		{  861000000, 166667, 0xca, 0xe4 /* 111 0 0 1  00 */ },
 	}
 };
-EXPORT_SYMBOL(dvb_pll_tda665x);
 
 /* Infineon TUA6034
  * used in LG TDTP E102P
  */
-static void tua6034_bw(u8 *buf, u32 freq, int bandwidth)
+static void tua6034_bw(struct dvb_frontend *fe, u8 *buf,
+		       const struct dvb_frontend_parameters *params)
 {
-	if (BANDWIDTH_7_MHZ != bandwidth)
+	if (BANDWIDTH_7_MHZ != params->u.ofdm.bandwidth)
 		buf[3] |= 0x08;
 }
 
-struct dvb_pll_desc dvb_pll_tua6034 = {
+static struct dvb_pll_desc dvb_pll_tua6034 = {
 	.name  = "Infineon TUA6034",
 	.min   =  44250000,
 	.max   = 858000000,
 	.iffreq= 36166667,
 	.count = 3,
-	.setbw = tua6034_bw,
+	.set   = tua6034_bw,
 	.entries = {
 		{  174500000, 62500, 0xce, 0x01 },
 		{  230000000, 62500, 0xce, 0x02 },
 		{  999999999, 62500, 0xce, 0x04 },
 	},
 };
-EXPORT_SYMBOL(dvb_pll_tua6034);
 
 /* Infineon TUA6034
  * used in LG TDVS-H061F, LG TDVS-H062F and LG TDVS-H064F
  */
-struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
+static struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
 	.name  = "LG TDVS-H06xF",
 	.min   =  54000000,
 	.max   = 863000000,
@@ -265,23 +317,26 @@
 		{  999999999, 62500, 0xce, 0x04 },
 	},
 };
-EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf);
 
 /* Philips FMD1216ME
  * used in Medion Hybrid PCMCIA card and USB Box
  */
-static void fmd1216me_bw(u8 *buf, u32 freq, int bandwidth)
+static void fmd1216me_bw(struct dvb_frontend *fe, u8 *buf,
+			 const struct dvb_frontend_parameters *params)
 {
-	if (bandwidth == BANDWIDTH_8_MHZ && freq >= 158870000)
+	if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
+	    params->frequency >= 158870000)
 		buf[3] |= 0x08;
 }
 
-struct dvb_pll_desc dvb_pll_fmd1216me = {
+static struct dvb_pll_desc dvb_pll_fmd1216me = {
 	.name = "Philips FMD1216ME",
 	.min = 50870000,
 	.max = 858000000,
 	.iffreq= 36125000,
-	.setbw = fmd1216me_bw,
+	.set   = fmd1216me_bw,
+	.initdata = tua603x_agc112,
+	.sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
 	.count = 7,
 	.entries = {
 		{ 143870000, 166667, 0xbc, 0x41 },
@@ -293,23 +348,23 @@
 		{ 999999999, 166667, 0xfc, 0x44 },
 	}
 };
-EXPORT_SYMBOL(dvb_pll_fmd1216me);
 
 /* ALPS TDED4
  * used in Nebula-Cards and USB boxes
  */
-static void tded4_bw(u8 *buf, u32 freq, int bandwidth)
+static void tded4_bw(struct dvb_frontend *fe, u8 *buf,
+		     const struct dvb_frontend_parameters *params)
 {
-	if (bandwidth == BANDWIDTH_8_MHZ)
+	if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
 		buf[3] |= 0x04;
 }
 
-struct dvb_pll_desc dvb_pll_tded4 = {
+static struct dvb_pll_desc dvb_pll_tded4 = {
 	.name = "ALPS TDED4",
 	.min = 47000000,
 	.max = 863000000,
 	.iffreq= 36166667,
-	.setbw = tded4_bw,
+	.set   = tded4_bw,
 	.count = 4,
 	.entries = {
 		{ 153000000, 166667, 0x85, 0x01 },
@@ -318,12 +373,11 @@
 		{ 999999999, 166667, 0x85, 0x88 },
 	}
 };
-EXPORT_SYMBOL(dvb_pll_tded4);
 
 /* ALPS TDHU2
  * used in AverTVHD MCE A180
  */
-struct dvb_pll_desc dvb_pll_tdhu2 = {
+static struct dvb_pll_desc dvb_pll_tdhu2 = {
 	.name = "ALPS TDHU2",
 	.min = 54000000,
 	.max = 864000000,
@@ -336,16 +390,48 @@
 		{ 999999999, 62500, 0x85, 0x88 },
 	}
 };
-EXPORT_SYMBOL(dvb_pll_tdhu2);
 
 /* Philips TUV1236D
  * used in ATI HDTV Wonder
  */
-struct dvb_pll_desc dvb_pll_tuv1236d = {
+static void tuv1236d_rf(struct dvb_frontend *fe, u8 *buf,
+			const struct dvb_frontend_parameters *params)
+{
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	unsigned int new_rf = input[priv->nr];
+
+	if ((new_rf == 0) || (new_rf > 2)) {
+		switch (params->u.vsb.modulation) {
+			case QAM_64:
+			case QAM_256:
+				new_rf = 1;
+				break;
+			case VSB_8:
+			default:
+				new_rf = 2;
+		}
+	}
+
+	switch (new_rf) {
+		case 1:
+			buf[3] |= 0x08;
+			break;
+		case 2:
+			buf[3] &= ~0x08;
+			break;
+		default:
+			printk(KERN_WARNING
+			       "%s: unhandled rf input selection: %d",
+			       __FUNCTION__, new_rf);
+	}
+}
+
+static struct dvb_pll_desc dvb_pll_tuv1236d = {
 	.name  = "Philips TUV1236D",
 	.min   =  54000000,
 	.max   = 864000000,
 	.iffreq= 44000000,
+	.set   = tuv1236d_rf,
 	.count = 3,
 	.entries = {
 		{ 157250000, 62500, 0xc6, 0x41 },
@@ -353,12 +439,11 @@
 		{ 999999999, 62500, 0xc6, 0x44 },
 	},
 };
-EXPORT_SYMBOL(dvb_pll_tuv1236d);
 
 /* Samsung TBMV30111IN / TBMV30712IN1
  * used in Air2PC ATSC - 2nd generation (nxt2002)
  */
-struct dvb_pll_desc dvb_pll_samsung_tbmv = {
+static struct dvb_pll_desc dvb_pll_samsung_tbmv = {
 	.name = "Samsung TBMV30111IN / TBMV30712IN1",
 	.min = 54000000,
 	.max = 860000000,
@@ -373,12 +458,11 @@
 		{ 999999999, 166667, 0xfc, 0x02 },
 	}
 };
-EXPORT_SYMBOL(dvb_pll_samsung_tbmv);
 
 /*
  * Philips SD1878 Tuner.
  */
-struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
+static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
 	.name  = "Philips SD1878",
 	.min   =  950000,
 	.max   = 2150000,
@@ -391,19 +475,19 @@
 		{ 2150000, 500, 0xc4, 0xc0},
 	},
 };
-EXPORT_SYMBOL(dvb_pll_philips_sd1878_tda8261);
 
 /*
  * Philips TD1316 Tuner.
  */
-static void td1316_bw(u8 *buf, u32 freq, int bandwidth)
+static void td1316_bw(struct dvb_frontend *fe, u8 *buf,
+		      const struct dvb_frontend_parameters *params)
 {
 	u8 band;
 
 	/* determine band */
-	if (freq < 161000000)
+	if (params->frequency < 161000000)
 		band = 1;
-	else if (freq < 444000000)
+	else if (params->frequency < 444000000)
 		band = 2;
 	else
 		band = 4;
@@ -411,16 +495,16 @@
 	buf[3] |= band;
 
 	/* setup PLL filter */
-	if (bandwidth == BANDWIDTH_8_MHZ)
+	if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
 		buf[3] |= 1 << 3;
 }
 
-struct dvb_pll_desc dvb_pll_philips_td1316 = {
+static struct dvb_pll_desc dvb_pll_philips_td1316 = {
 	.name  = "Philips TD1316",
 	.min   =  87000000,
 	.max   = 895000000,
 	.iffreq= 36166667,
-	.setbw = td1316_bw,
+	.set   = td1316_bw,
 	.count = 9,
 	.entries = {
 		{  93834000, 166667, 0xca, 0x60},
@@ -434,10 +518,9 @@
 		{ 858834000, 166667, 0xca, 0xe0},
 	},
 };
-EXPORT_SYMBOL(dvb_pll_philips_td1316);
 
 /* FE6600 used on DViCO Hybrid */
-struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
+static struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
 	.name = "Thomson FE6600",
 	.min =  44250000,
 	.max = 858000000,
@@ -450,19 +533,20 @@
 		{ 999999999, 166667, 0xf4, 0x18 },
 	}
 };
-EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
-static void opera1_bw(u8 *buf, u32 freq, int bandwidth)
+
+static void opera1_bw(struct dvb_frontend *fe, u8 *buf,
+		      const struct dvb_frontend_parameters *params)
 {
-	if (bandwidth == BANDWIDTH_8_MHZ)
+	if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
 		buf[2] |= 0x08;
 }
 
-struct dvb_pll_desc dvb_pll_opera1 = {
+static struct dvb_pll_desc dvb_pll_opera1 = {
 	.name  = "Opera Tuner",
 	.min   =  900000,
 	.max   = 2250000,
 	.iffreq= 0,
-	.setbw = opera1_bw,
+	.set   = opera1_bw,
 	.count = 8,
 	.entries = {
 		{ 1064000, 500, 0xe5, 0xc6 },
@@ -475,57 +559,89 @@
 		{ 2250000, 500, 0xe5, 0xc4 },
 	}
 };
-EXPORT_SYMBOL(dvb_pll_opera1);
 
-struct dvb_pll_priv {
-	/* i2c details */
-	int pll_i2c_address;
-	struct i2c_adapter *i2c;
+/* Philips FCV1236D
+ */
+static struct dvb_pll_desc dvb_pll_fcv1236d = {
+/* Bit_0: RF Input select
+ * Bit_1: 0=digital, 1=analog
+ */
+	.name  = "Philips FCV1236D",
+	.min   =  53000000,
+	.max   = 803000000,
+	.iffreq= 44000000,
+	.count = 3,
+	.entries = {
+		{ 159000000, 62500, 0x8e, 0xa0 },
+		{ 453000000, 62500, 0x8e, 0x90 },
+		{ 999999999, 62500, 0x8e, 0x30 },
+	},
+};
 
-	/* the PLL descriptor */
-	struct dvb_pll_desc *pll_desc;
+/* ----------------------------------------------------------- */
 
-	/* cached frequency/bandwidth */
-	u32 frequency;
-	u32 bandwidth;
+static struct dvb_pll_desc *pll_list[] = {
+	[DVB_PLL_UNDEFINED]              = NULL,
+	[DVB_PLL_THOMSON_DTT7579]        = &dvb_pll_thomson_dtt7579,
+	[DVB_PLL_THOMSON_DTT759X]        = &dvb_pll_thomson_dtt759x,
+	[DVB_PLL_THOMSON_DTT7610]        = &dvb_pll_thomson_dtt7610,
+	[DVB_PLL_LG_Z201]                = &dvb_pll_lg_z201,
+	[DVB_PLL_MICROTUNE_4042]         = &dvb_pll_microtune_4042,
+	[DVB_PLL_THOMSON_DTT761X]        = &dvb_pll_thomson_dtt761x,
+	[DVB_PLL_UNKNOWN_1]              = &dvb_pll_unknown_1,
+	[DVB_PLL_TUA6010XS]              = &dvb_pll_tua6010xs,
+	[DVB_PLL_ENV57H1XD5]             = &dvb_pll_env57h1xd5,
+	[DVB_PLL_TUA6034]                = &dvb_pll_tua6034,
+	[DVB_PLL_LG_TDVS_H06XF]          = &dvb_pll_lg_tdvs_h06xf,
+	[DVB_PLL_TDA665X]                = &dvb_pll_tda665x,
+	[DVB_PLL_FMD1216ME]              = &dvb_pll_fmd1216me,
+	[DVB_PLL_TDED4]                  = &dvb_pll_tded4,
+	[DVB_PLL_TUV1236D]               = &dvb_pll_tuv1236d,
+	[DVB_PLL_TDHU2]                  = &dvb_pll_tdhu2,
+	[DVB_PLL_SAMSUNG_TBMV]           = &dvb_pll_samsung_tbmv,
+	[DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
+	[DVB_PLL_PHILIPS_TD1316]         = &dvb_pll_philips_td1316,
+	[DVB_PLL_THOMSON_FE6600]         = &dvb_pll_thomson_fe6600,
+	[DVB_PLL_OPERA1]                 = &dvb_pll_opera1,
+	[DVB_PLL_FCV1236D]               = &dvb_pll_fcv1236d,
 };
 
 /* ----------------------------------------------------------- */
 /* code                                                        */
 
-static int debug = 0;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable verbose debug messages");
-
-int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
-		      u32 freq, int bandwidth)
+static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf,
+			     const struct dvb_frontend_parameters *params)
 {
+	struct dvb_pll_priv *priv = fe->tuner_priv;
+	struct dvb_pll_desc *desc = priv->pll_desc;
 	u32 div;
 	int i;
 
-	if (freq != 0 && (freq < desc->min || freq > desc->max))
-	    return -EINVAL;
+	if (params->frequency != 0 && (params->frequency < desc->min ||
+				       params->frequency > desc->max))
+		return -EINVAL;
 
 	for (i = 0; i < desc->count; i++) {
-		if (freq > desc->entries[i].limit)
+		if (params->frequency > desc->entries[i].limit)
 			continue;
 		break;
 	}
+
 	if (debug)
-		printk("pll: %s: freq=%d bw=%d | i=%d/%d\n",
-		       desc->name, freq, bandwidth, i, desc->count);
+		printk("pll: %s: freq=%d | i=%d/%d\n", desc->name,
+		       params->frequency, i, desc->count);
 	if (i == desc->count)
 		return -EINVAL;
 
-	div = (freq + desc->iffreq + desc->entries[i].stepsize/2) /
-	      desc->entries[i].stepsize;
+	div = (params->frequency + desc->iffreq +
+	       desc->entries[i].stepsize/2) / desc->entries[i].stepsize;
 	buf[0] = div >> 8;
 	buf[1] = div & 0xff;
 	buf[2] = desc->entries[i].config;
 	buf[3] = desc->entries[i].cb;
 
-	if (desc->setbw)
-		desc->setbw(buf, freq, bandwidth);
+	if (desc->set)
+		desc->set(fe, buf, params);
 
 	if (debug)
 		printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
@@ -534,7 +650,6 @@
 	// calculate the frequency we set it to
 	return (div * desc->entries[i].stepsize) - desc->iffreq;
 }
-EXPORT_SYMBOL(dvb_pll_configure);
 
 static int dvb_pll_release(struct dvb_frontend *fe)
 {
@@ -578,18 +693,12 @@
 		{ .addr = priv->pll_i2c_address, .flags = 0,
 		  .buf = buf, .len = sizeof(buf) };
 	int result;
-	u32 bandwidth = 0, frequency = 0;
+	u32 frequency = 0;
 
 	if (priv->i2c == NULL)
 		return -EINVAL;
 
-	// DVBT bandwidth only just now
-	if (fe->ops.info.type == FE_OFDM) {
-		bandwidth = params->u.ofdm.bandwidth;
-	}
-
-	if ((result = dvb_pll_configure(priv->pll_desc, buf,
-					params->frequency, bandwidth)) < 0)
+	if ((result = dvb_pll_configure(fe, buf, params)) < 0)
 		return result;
 	else
 		frequency = result;
@@ -601,7 +710,7 @@
 	}
 
 	priv->frequency = frequency;
-	priv->bandwidth = bandwidth;
+	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
 
 	return 0;
 }
@@ -612,18 +721,12 @@
 {
 	struct dvb_pll_priv *priv = fe->tuner_priv;
 	int result;
-	u32 bandwidth = 0, frequency = 0;
+	u32 frequency = 0;
 
 	if (buf_len < 5)
 		return -EINVAL;
 
-	// DVBT bandwidth only just now
-	if (fe->ops.info.type == FE_OFDM) {
-		bandwidth = params->u.ofdm.bandwidth;
-	}
-
-	if ((result = dvb_pll_configure(priv->pll_desc, buf+1,
-					params->frequency, bandwidth)) < 0)
+	if ((result = dvb_pll_configure(fe, buf+1, params)) < 0)
 		return result;
 	else
 		frequency = result;
@@ -631,7 +734,7 @@
 	buf[0] = priv->pll_i2c_address;
 
 	priv->frequency = frequency;
-	priv->bandwidth = bandwidth;
+	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
 
 	return 5;
 }
@@ -687,13 +790,22 @@
 
 struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
 				    struct i2c_adapter *i2c,
-				    struct dvb_pll_desc *desc)
+				    unsigned int pll_desc_id)
 {
 	u8 b1 [] = { 0 };
 	struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD,
 			       .buf = b1, .len = 1 };
 	struct dvb_pll_priv *priv = NULL;
 	int ret;
+	struct dvb_pll_desc *desc;
+
+	if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) &&
+	    (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list)))
+		pll_desc_id = id[dvb_pll_devcount];
+
+	BUG_ON(pll_desc_id < 1 || pll_desc_id >= ARRAY_SIZE(pll_list));
+
+	desc = pll_list[pll_desc_id];
 
 	if (i2c != NULL) {
 		if (fe->ops.i2c_gate_ctrl)
@@ -713,6 +825,7 @@
 	priv->pll_i2c_address = pll_addr;
 	priv->i2c = i2c;
 	priv->pll_desc = desc;
+	priv->nr = dvb_pll_devcount++;
 
 	memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops,
 	       sizeof(struct dvb_tuner_ops));
@@ -720,13 +833,37 @@
 	strncpy(fe->ops.tuner_ops.info.name, desc->name,
 		sizeof(fe->ops.tuner_ops.info.name));
 	fe->ops.tuner_ops.info.frequency_min = desc->min;
-	fe->ops.tuner_ops.info.frequency_min = desc->max;
+	fe->ops.tuner_ops.info.frequency_max = desc->max;
 	if (!desc->initdata)
 		fe->ops.tuner_ops.init = NULL;
 	if (!desc->sleepdata)
 		fe->ops.tuner_ops.sleep = NULL;
 
 	fe->tuner_priv = priv;
+
+	if ((debug) || (id[priv->nr] == pll_desc_id)) {
+		printk("dvb-pll[%d]", priv->nr);
+		if (i2c != NULL)
+			printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr);
+		printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name,
+		       id[priv->nr] == pll_desc_id ?
+				"insmod option" : "autodetected");
+	}
+	if ((debug) || (input[priv->nr] > 0)) {
+		printk("dvb-pll[%d]", priv->nr);
+		if (i2c != NULL)
+			printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr);
+		printk(": tuner rf input will be ");
+		switch (input[priv->nr]) {
+		case 0:
+			printk("autoselected\n");
+			break;
+		default:
+			printk("set to input %d (insmod option)\n",
+			       input[priv->nr]);
+		}
+	}
+
 	return fe;
 }
 EXPORT_SYMBOL(dvb_pll_attach);
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 5209f46..e93a810 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -8,50 +8,29 @@
 #include <linux/i2c.h>
 #include "dvb_frontend.h"
 
-struct dvb_pll_desc {
-	char *name;
-	u32  min;
-	u32  max;
-	u32  iffreq;
-	void (*setbw)(u8 *buf, u32 freq, int bandwidth);
-	u8   *initdata;
-	u8   *sleepdata;
-	int  count;
-	struct {
-		u32 limit;
-		u32 stepsize;
-		u8  config;
-		u8  cb;
-	} entries[12];
-};
-
-extern struct dvb_pll_desc dvb_pll_thomson_dtt7579;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt759x;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt7610;
-extern struct dvb_pll_desc dvb_pll_lg_z201;
-extern struct dvb_pll_desc dvb_pll_microtune_4042;
-extern struct dvb_pll_desc dvb_pll_thomson_dtt761x;
-extern struct dvb_pll_desc dvb_pll_unknown_1;
-
-extern struct dvb_pll_desc dvb_pll_tua6010xs;
-extern struct dvb_pll_desc dvb_pll_env57h1xd5;
-extern struct dvb_pll_desc dvb_pll_tua6034;
-extern struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf;
-extern struct dvb_pll_desc dvb_pll_tda665x;
-extern struct dvb_pll_desc dvb_pll_fmd1216me;
-extern struct dvb_pll_desc dvb_pll_tded4;
-
-extern struct dvb_pll_desc dvb_pll_tuv1236d;
-extern struct dvb_pll_desc dvb_pll_tdhu2;
-extern struct dvb_pll_desc dvb_pll_samsung_tbmv;
-extern struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261;
-extern struct dvb_pll_desc dvb_pll_philips_td1316;
-
-extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
-extern struct dvb_pll_desc dvb_pll_opera1;
-
-extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
-			     u32 freq, int bandwidth);
+#define DVB_PLL_UNDEFINED               0
+#define DVB_PLL_THOMSON_DTT7579         1
+#define DVB_PLL_THOMSON_DTT759X         2
+#define DVB_PLL_THOMSON_DTT7610         3
+#define DVB_PLL_LG_Z201                 4
+#define DVB_PLL_MICROTUNE_4042          5
+#define DVB_PLL_THOMSON_DTT761X         6
+#define DVB_PLL_UNKNOWN_1               7
+#define DVB_PLL_TUA6010XS               8
+#define DVB_PLL_ENV57H1XD5              9
+#define DVB_PLL_TUA6034                10
+#define DVB_PLL_LG_TDVS_H06XF          11
+#define DVB_PLL_TDA665X                12
+#define DVB_PLL_FMD1216ME              13
+#define DVB_PLL_TDED4                  14
+#define DVB_PLL_TUV1236D               15
+#define DVB_PLL_TDHU2                  16
+#define DVB_PLL_SAMSUNG_TBMV           17
+#define DVB_PLL_PHILIPS_SD1878_TDA8261 18
+#define DVB_PLL_PHILIPS_TD1316         19
+#define DVB_PLL_THOMSON_FE6600         20
+#define DVB_PLL_OPERA1                 21
+#define DVB_PLL_FCV1236D               22
 
 /**
  * Attach a dvb-pll to the supplied frontend structure.
@@ -59,19 +38,19 @@
  * @param fe Frontend to attach to.
  * @param pll_addr i2c address of the PLL (if used).
  * @param i2c i2c adapter to use (set to NULL if not used).
- * @param desc dvb_pll_desc to use.
+ * @param pll_desc_id dvb_pll_desc to use.
  * @return Frontend pointer on success, NULL on failure
  */
 #if defined(CONFIG_DVB_PLL) || (defined(CONFIG_DVB_PLL_MODULE) && defined(MODULE))
 extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
 					   int pll_addr,
 					   struct i2c_adapter *i2c,
-					   struct dvb_pll_desc *desc);
+					   unsigned int pll_desc_id);
 #else
 static inline struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe,
 					   int pll_addr,
 					   struct i2c_adapter *i2c,
-					   struct dvb_pll_desc *desc)
+					   unsigned int pll_desc_id)
 {
 	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
 	return NULL;
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c
index 6271b1e..fed09df 100644
--- a/drivers/media/dvb/frontends/dvb_dummy_fe.c
+++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c
@@ -20,7 +20,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/slab.h>
diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb/frontends/isl6421.c
index c967148..684c8ec 100644
--- a/drivers/media/dvb/frontends/isl6421.c
+++ b/drivers/media/dvb/frontends/isl6421.c
@@ -29,7 +29,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c
index 1aeacb1..443d904 100644
--- a/drivers/media/dvb/frontends/l64781.c
+++ b/drivers/media/dvb/frontends/l64781.c
@@ -23,7 +23,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include "dvb_frontend.h"
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index e25286e..bdc9fa8 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -35,7 +35,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c
index 2d2f58c..76f935d 100644
--- a/drivers/media/dvb/frontends/lnbp21.c
+++ b/drivers/media/dvb/frontends/lnbp21.c
@@ -28,7 +28,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 
diff --git a/drivers/media/dvb/frontends/mt2060.c b/drivers/media/dvb/frontends/mt2060.c
index 450fad8..1305b0e6 100644
--- a/drivers/media/dvb/frontends/mt2060.c
+++ b/drivers/media/dvb/frontends/mt2060.c
@@ -22,7 +22,6 @@
 /* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/delay.h>
 #include <linux/dvb/frontend.h>
 #include <linux/i2c.h>
diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/dvb/frontends/mt2131.c
new file mode 100644
index 0000000..4b93931
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2131.c
@@ -0,0 +1,314 @@
+/*
+ *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "mt2131.h"
+#include "mt2131_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(level,fmt, arg...) if (debug >= level) \
+	printk(KERN_INFO "%s: " fmt, "mt2131", ## arg)
+
+static u8 mt2131_config1[] = {
+	0x01,
+	0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88,
+	0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32,
+	0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80,
+	0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00
+};
+
+static u8 mt2131_config2[] = {
+	0x10,
+	0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04
+};
+
+static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->cfg->i2c_address, .flags = 0,
+		  .buf = &reg, .len = 1 },
+		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD,
+		  .buf = val,  .len = 1 },
+	};
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		printk(KERN_WARNING "mt2131 I2C read failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val)
+{
+	u8 buf[2] = { reg, val };
+	struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0,
+			       .buf = buf, .len = 2 };
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "mt2131 I2C write failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len)
+{
+	struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
+			       .flags = 0, .buf = buf, .len = len };
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n",
+		       (int)len);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int mt2131_set_params(struct dvb_frontend *fe,
+			     struct dvb_frontend_parameters *params)
+{
+	struct mt2131_priv *priv;
+	int ret=0, i;
+	u32 freq;
+	u8  if_band_center;
+	u32 f_lo1, f_lo2;
+	u32 div1, num1, div2, num2;
+	u8  b[8];
+	u8 lockval = 0;
+
+	priv = fe->tuner_priv;
+	if (fe->ops.info.type == FE_OFDM)
+		priv->bandwidth = params->u.ofdm.bandwidth;
+	else
+		priv->bandwidth = 0;
+
+	freq = params->frequency / 1000;  // Hz -> kHz
+	dprintk(1, "%s() freq=%d\n", __FUNCTION__, freq);
+
+	f_lo1 = freq + MT2131_IF1 * 1000;
+	f_lo1 = (f_lo1 / 250) * 250;
+	f_lo2 = f_lo1 - freq - MT2131_IF2;
+
+	priv->frequency =  (f_lo1 - f_lo2 - MT2131_IF2) * 1000,
+
+	/* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */
+	num1 = f_lo1 * 64 / (MT2131_FREF / 128);
+	div1 = num1 / 8192;
+	num1 &= 0x1fff;
+
+	/* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */
+	num2 = f_lo2 * 64 / (MT2131_FREF / 128);
+	div2 = num2 / 8192;
+	num2 &= 0x1fff;
+
+	if (freq <=   82500) if_band_center = 0x00; else
+	if (freq <=  137500) if_band_center = 0x01; else
+	if (freq <=  192500) if_band_center = 0x02; else
+	if (freq <=  247500) if_band_center = 0x03; else
+	if (freq <=  302500) if_band_center = 0x04; else
+	if (freq <=  357500) if_band_center = 0x05; else
+	if (freq <=  412500) if_band_center = 0x06; else
+	if (freq <=  467500) if_band_center = 0x07; else
+	if (freq <=  522500) if_band_center = 0x08; else
+	if (freq <=  577500) if_band_center = 0x09; else
+	if (freq <=  632500) if_band_center = 0x0A; else
+	if (freq <=  687500) if_band_center = 0x0B; else
+	if (freq <=  742500) if_band_center = 0x0C; else
+	if (freq <=  797500) if_band_center = 0x0D; else
+	if (freq <=  852500) if_band_center = 0x0E; else
+	if (freq <=  907500) if_band_center = 0x0F; else
+	if (freq <=  962500) if_band_center = 0x10; else
+	if (freq <= 1017500) if_band_center = 0x11; else
+	if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13;
+
+	b[0] = 1;
+	b[1] = (num1 >> 5) & 0xFF;
+	b[2] = (num1 & 0x1F);
+	b[3] = div1;
+	b[4] = (num2 >> 5) & 0xFF;
+	b[5] = num2 & 0x1F;
+	b[6] = div2;
+
+	dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2);
+	dprintk(1, "PLL freq=%dkHz  band=%d\n", (int)freq, (int)if_band_center);
+	dprintk(1, "PLL f_lo1=%dkHz  f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2);
+	dprintk(1, "PLL div1=%d  num1=%d  div2=%d  num2=%d\n",
+		(int)div1, (int)num1, (int)div2, (int)num2);
+	dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n",
+		(int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5],
+		(int)b[6]);
+
+	ret = mt2131_writeregs(priv,b,7);
+	if (ret < 0)
+		return ret;
+
+	mt2131_writereg(priv, 0x0b, if_band_center);
+
+	/* Wait for lock */
+	i = 0;
+	do {
+		mt2131_readreg(priv, 0x08, &lockval);
+		if ((lockval & 0x88) == 0x88)
+			break;
+		msleep(4);
+		i++;
+	} while (i < 10);
+
+	return ret;
+}
+
+static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct mt2131_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __FUNCTION__);
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int mt2131_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct mt2131_priv *priv = fe->tuner_priv;
+	dprintk(1, "%s()\n", __FUNCTION__);
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+static int mt2131_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct mt2131_priv *priv = fe->tuner_priv;
+	u8 lock_status = 0;
+	u8 afc_status = 0;
+
+	*status = 0;
+
+	mt2131_readreg(priv, 0x08, &lock_status);
+	if ((lock_status & 0x88) == 0x88)
+		*status = TUNER_STATUS_LOCKED;
+
+	mt2131_readreg(priv, 0x09, &afc_status);
+	dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n",
+		__FUNCTION__, lock_status, afc_status);
+
+	return 0;
+}
+
+static int mt2131_init(struct dvb_frontend *fe)
+{
+	struct mt2131_priv *priv = fe->tuner_priv;
+	int ret;
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	if ((ret = mt2131_writeregs(priv, mt2131_config1,
+				    sizeof(mt2131_config1))) < 0)
+		return ret;
+
+	mt2131_writereg(priv, 0x0b, 0x09);
+	mt2131_writereg(priv, 0x15, 0x47);
+	mt2131_writereg(priv, 0x07, 0xf2);
+	mt2131_writereg(priv, 0x0b, 0x01);
+
+	if ((ret = mt2131_writeregs(priv, mt2131_config2,
+				    sizeof(mt2131_config2))) < 0)
+		return ret;
+
+	return ret;
+}
+
+static int mt2131_release(struct dvb_frontend *fe)
+{
+	dprintk(1, "%s()\n", __FUNCTION__);
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static const struct dvb_tuner_ops mt2131_tuner_ops = {
+	.info = {
+		.name           = "Microtune MT2131",
+		.frequency_min  =  48000000,
+		.frequency_max  = 860000000,
+		.frequency_step =     50000,
+	},
+
+	.release       = mt2131_release,
+	.init          = mt2131_init,
+
+	.set_params    = mt2131_set_params,
+	.get_frequency = mt2131_get_frequency,
+	.get_bandwidth = mt2131_get_bandwidth,
+	.get_status    = mt2131_get_status
+};
+
+struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe,
+				    struct i2c_adapter *i2c,
+				    struct mt2131_config *cfg, u16 if1)
+{
+	struct mt2131_priv *priv = NULL;
+	u8 id = 0;
+
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->cfg = cfg;
+	priv->bandwidth = 6000000; /* 6MHz */
+	priv->i2c = i2c;
+
+	if (mt2131_readreg(priv, 0, &id) != 0) {
+		kfree(priv);
+		return NULL;
+	}
+	if ( (id != 0x3E) && (id != 0x3F) ) {
+		printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n",
+		       cfg->i2c_address);
+		kfree(priv);
+		return NULL;
+	}
+
+	printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n",
+	       cfg->i2c_address);
+	memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+	return fe;
+}
+EXPORT_SYMBOL(mt2131_attach);
+
+MODULE_AUTHOR("Steven Toth");
+MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/dvb/frontends/mt2131.h
new file mode 100644
index 0000000..1e4ffe7
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2131.h
@@ -0,0 +1,54 @@
+/*
+ *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MT2131_H__
+#define __MT2131_H__
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct mt2131_config {
+	u8 i2c_address;
+	u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
+};
+
+#if defined(CONFIG_DVB_TUNER_MT2131) || (defined(CONFIG_DVB_TUNER_MT2131_MODULE) && defined(MODULE))
+extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
+					  struct i2c_adapter *i2c,
+					  struct mt2131_config *cfg,
+					  u16 if1);
+#else
+static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
+						 struct i2c_adapter *i2c,
+						 struct mt2131_config *cfg,
+						 u16 if1)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_TUNER_MT2131 */
+
+#endif /* __MT2131_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/mt2131_priv.h b/drivers/media/dvb/frontends/mt2131_priv.h
new file mode 100644
index 0000000..e930759
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2131_priv.h
@@ -0,0 +1,49 @@
+/*
+ *  Driver for Microtune MT2131 "QAM/8VSB single chip tuner"
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __MT2131_PRIV_H__
+#define __MT2131_PRIV_H__
+
+/* Regs */
+#define MT2131_PWR              0x07
+#define MT2131_UPC_1            0x0b
+#define MT2131_AGC_RL           0x10
+#define MT2131_MISC_2           0x15
+
+/* frequency values in KHz */
+#define MT2131_IF1              1220
+#define MT2131_IF2              44000
+#define MT2131_FREF             16000
+
+struct mt2131_priv {
+	struct mt2131_config *cfg;
+	struct i2c_adapter   *i2c;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+#endif /* __MT2131_PRIV_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/dvb/frontends/mt2266.c
new file mode 100644
index 0000000..03fe826
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2266.c
@@ -0,0 +1,287 @@
+/*
+ *  Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
+ *
+ *  Copyright (c) 2007 Olivier DANET <odanet@caramail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+#include "mt2266.h"
+
+#define I2C_ADDRESS 0x60
+
+#define REG_PART_REV   0
+#define REG_TUNE       1
+#define REG_BAND       6
+#define REG_BANDWIDTH  8
+#define REG_LOCK       0x12
+
+#define PART_REV 0x85
+
+struct mt2266_priv {
+	struct mt2266_config *cfg;
+	struct i2c_adapter   *i2c;
+
+	u32 frequency;
+	u32 bandwidth;
+};
+
+/* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0)
+
+// Reads a single register
+static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
+		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val,  .len = 1 },
+	};
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		printk(KERN_WARNING "MT2266 I2C read failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+// Writes a single register
+static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val)
+{
+	u8 buf[2] = { reg, val };
+	struct i2c_msg msg = {
+		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
+	};
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "MT2266 I2C write failed\n");
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+// Writes a set of consecutive registers
+static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len)
+{
+	struct i2c_msg msg = {
+		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len
+	};
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+// Initialisation sequences
+static u8 mt2266_init1[] = {
+	REG_TUNE,
+	0x00, 0x00, 0x28, 0x00, 0x52, 0x99, 0x3f };
+
+static u8 mt2266_init2[] = {
+	0x17,                                     0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a,
+	0xd4, 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, 0x01, 0x01, 0x01, 0x01,
+	0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, 0xff, 0x00, 0x77, 0x0f, 0x2d };
+
+static u8 mt2266_init_8mhz[] = {
+	REG_BANDWIDTH,
+	0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 };
+
+static u8 mt2266_init_7mhz[] = {
+	REG_BANDWIDTH,
+	0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 };
+
+static u8 mt2266_init_6mhz[] = {
+	REG_BANDWIDTH,
+	0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7 };
+
+#define FREF 30000       // Quartz oscillator 30 MHz
+
+static int mt2266_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+	struct mt2266_priv *priv;
+	int ret=0;
+	u32 freq;
+	u32 tune;
+	u8  lnaband;
+	u8  b[10];
+	int i;
+
+	priv = fe->tuner_priv;
+
+	mt2266_writereg(priv,0x17,0x6d);
+	mt2266_writereg(priv,0x1c,0xff);
+
+	freq = params->frequency / 1000; // Hz -> kHz
+	priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+	priv->frequency = freq * 1000;
+	tune=2 * freq * (8192/16) / (FREF/16);
+
+	if (freq <= 495000) lnaband = 0xEE; else
+	if (freq <= 525000) lnaband = 0xDD; else
+	if (freq <= 550000) lnaband = 0xCC; else
+	if (freq <= 580000) lnaband = 0xBB; else
+	if (freq <= 605000) lnaband = 0xAA; else
+	if (freq <= 630000) lnaband = 0x99; else
+	if (freq <= 655000) lnaband = 0x88; else
+	if (freq <= 685000) lnaband = 0x77; else
+	if (freq <= 710000) lnaband = 0x66; else
+	if (freq <= 735000) lnaband = 0x55; else
+	if (freq <= 765000) lnaband = 0x44; else
+	if (freq <= 802000) lnaband = 0x33; else
+	if (freq <= 840000) lnaband = 0x22; else lnaband = 0x11;
+
+	msleep(100);
+	mt2266_writeregs(priv,(params->u.ofdm.bandwidth==BANDWIDTH_6_MHZ)?mt2266_init_6mhz:
+				(params->u.ofdm.bandwidth==BANDWIDTH_7_MHZ)?mt2266_init_7mhz:
+				mt2266_init_8mhz,sizeof(mt2266_init_8mhz));
+
+	b[0] = REG_TUNE;
+	b[1] = (tune >> 8) & 0x1F;
+	b[2] = tune & 0xFF;
+	b[3] = tune >> 13;
+	mt2266_writeregs(priv,b,4);
+
+	dprintk("set_parms: tune=%d band=%d",(int)tune,(int)lnaband);
+	dprintk("set_parms: [1..3]: %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3]);
+
+	b[0] = 0x05;
+	b[1] = 0x62;
+	b[2] = lnaband;
+	mt2266_writeregs(priv,b,3);
+
+	//Waits for pll lock or timeout
+	i = 0;
+	do {
+		mt2266_readreg(priv,REG_LOCK,b);
+		if ((b[0] & 0x40)==0x40)
+			break;
+		msleep(10);
+		i++;
+	} while (i<10);
+	dprintk("Lock when i=%i",(int)i);
+	return ret;
+}
+
+static void mt2266_calibrate(struct mt2266_priv *priv)
+{
+	mt2266_writereg(priv,0x11,0x03);
+	mt2266_writereg(priv,0x11,0x01);
+
+	mt2266_writeregs(priv,mt2266_init1,sizeof(mt2266_init1));
+	mt2266_writeregs(priv,mt2266_init2,sizeof(mt2266_init2));
+
+	mt2266_writereg(priv,0x33,0x5e);
+	mt2266_writereg(priv,0x10,0x10);
+	mt2266_writereg(priv,0x10,0x00);
+
+	mt2266_writeregs(priv,mt2266_init_8mhz,sizeof(mt2266_init_8mhz));
+
+	msleep(25);
+	mt2266_writereg(priv,0x17,0x6d);
+	mt2266_writereg(priv,0x1c,0x00);
+	msleep(75);
+	mt2266_writereg(priv,0x17,0x6d);
+	mt2266_writereg(priv,0x1c,0xff);
+}
+
+static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct mt2266_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+	struct mt2266_priv *priv = fe->tuner_priv;
+	*bandwidth = priv->bandwidth;
+	return 0;
+}
+
+static int mt2266_init(struct dvb_frontend *fe)
+{
+	struct mt2266_priv *priv = fe->tuner_priv;
+	mt2266_writereg(priv,0x17,0x6d);
+	mt2266_writereg(priv,0x1c,0xff);
+	return 0;
+}
+
+static int mt2266_sleep(struct dvb_frontend *fe)
+{
+	struct mt2266_priv *priv = fe->tuner_priv;
+	mt2266_writereg(priv,0x17,0x6d);
+	mt2266_writereg(priv,0x1c,0x00);
+	return 0;
+}
+
+static int mt2266_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static const struct dvb_tuner_ops mt2266_tuner_ops = {
+	.info = {
+		.name           = "Microtune MT2266",
+		.frequency_min  = 470000000,
+		.frequency_max  = 860000000,
+		.frequency_step =     50000,
+	},
+	.release       = mt2266_release,
+	.init          = mt2266_init,
+	.sleep         = mt2266_sleep,
+	.set_params    = mt2266_set_params,
+	.get_frequency = mt2266_get_frequency,
+	.get_bandwidth = mt2266_get_bandwidth
+};
+
+struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
+{
+	struct mt2266_priv *priv = NULL;
+	u8 id = 0;
+
+	priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+
+	priv->cfg      = cfg;
+	priv->i2c      = i2c;
+
+	if (mt2266_readreg(priv,0,&id) != 0) {
+		kfree(priv);
+		return NULL;
+	}
+	if (id != PART_REV) {
+		kfree(priv);
+		return NULL;
+	}
+	printk(KERN_INFO "MT2266: successfully identified\n");
+	memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+	fe->tuner_priv = priv;
+	mt2266_calibrate(priv);
+	return fe;
+}
+EXPORT_SYMBOL(mt2266_attach);
+
+MODULE_AUTHOR("Olivier DANET");
+MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/mt2266.h b/drivers/media/dvb/frontends/mt2266.h
new file mode 100644
index 0000000..f31dd61
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2266.h
@@ -0,0 +1,37 @@
+/*
+ *  Driver for Microtune MT2266 "Direct conversion low power broadband tuner"
+ *
+ *  Copyright (c) 2007 Olivier DANET <odanet@caramail.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ */
+
+#ifndef MT2266_H
+#define MT2266_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct mt2266_config {
+	u8 i2c_address;
+};
+
+#if defined(CONFIG_DVB_TUNER_MT2266) || (defined(CONFIG_DVB_TUNER_MT2266_MODULE) && defined(MODULE))
+extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg);
+#else
+static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif // CONFIG_DVB_TUNER_MT2266
+
+#endif
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
index 1ef8218..0606b9a 100644
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb/frontends/mt312.c
@@ -28,7 +28,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
index 87e31ca..5dd9b73 100644
--- a/drivers/media/dvb/frontends/mt352.c
+++ b/drivers/media/dvb/frontends/mt352.c
@@ -32,7 +32,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
index b809f83..fcf964f 100644
--- a/drivers/media/dvb/frontends/nxt200x.c
+++ b/drivers/media/dvb/frontends/nxt200x.c
@@ -44,12 +44,10 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 
 #include "dvb_frontend.h"
-#include "dvb-pll.h"
 #include "nxt200x.h"
 
 struct nxt200x_state {
@@ -546,11 +544,6 @@
 		nxt200x_writebytes(state, 0x17, buf, 1);
 	}
 
-	/* get tuning information */
-	if (fe->ops.tuner_ops.calc_regs) {
-		fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
-	}
-
 	/* set additional params */
 	switch (p->u.vsb.modulation) {
 		case QAM_64:
@@ -559,27 +552,24 @@
 			/* This is just a guess since I am unable to test it */
 			if (state->config->set_ts_params)
 				state->config->set_ts_params(fe, 1);
-
-			/* set input */
-			if (state->config->set_pll_input)
-				state->config->set_pll_input(buf+1, 1);
 			break;
 		case VSB_8:
 			/* Set non-punctured clock for VSB */
 			if (state->config->set_ts_params)
 				state->config->set_ts_params(fe, 0);
-
-			/* set input */
-			if (state->config->set_pll_input)
-				state->config->set_pll_input(buf+1, 0);
 			break;
 		default:
 			return -EINVAL;
 			break;
 	}
 
-	/* write frequency information */
-	nxt200x_writetuner(state, buf);
+	if (fe->ops.tuner_ops.calc_regs) {
+		/* get tuning information */
+		fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
+
+		/* write frequency information */
+		nxt200x_writetuner(state, buf);
+	}
 
 	/* reset the agc now that tuning has been completed */
 	nxt200x_agc_reset(state);
diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h
index 28bc559..bb0ef58 100644
--- a/drivers/media/dvb/frontends/nxt200x.h
+++ b/drivers/media/dvb/frontends/nxt200x.h
@@ -38,9 +38,6 @@
 	/* the demodulator's i2c address */
 	u8 demod_address;
 
-	/* used to set pll input */
-	int (*set_pll_input)(u8* buf, int input);
-
 	/* need to set device param for start_dma */
 	int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
 };
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index 4e0aca7..b314a1f 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -36,7 +36,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/string.h>
@@ -45,7 +44,6 @@
 
 #include "dvb_math.h"
 #include "dvb_frontend.h"
-#include "dvb-pll.h"
 #include "or51132.h"
 
 static int debug;
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index 048d7cf..f02bd94 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -32,7 +32,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/string.h>
@@ -223,38 +222,13 @@
 				  struct dvb_frontend_parameters *param)
 {
 	struct or51211_state* state = fe->demodulator_priv;
-	u32 freq = 0;
-	u16 tunerfreq = 0;
-	u8 buf[4];
 
 	/* Change only if we are actually changing the channel */
 	if (state->current_frequency != param->frequency) {
-		freq = 44000 + (param->frequency/1000);
-		tunerfreq = freq * 16/1000;
-
-		dprintk("set_parameters frequency = %d (tunerfreq = %d)\n",
-			param->frequency,tunerfreq);
-
-		buf[0] = (tunerfreq >> 8) & 0x7F;
-		buf[1] = (tunerfreq & 0xFF);
-		buf[2] = 0x8E;
-
-		if (param->frequency < 157250000) {
-			buf[3] = 0xA0;
-			dprintk("set_parameters VHF low range\n");
-		} else if (param->frequency < 454000000) {
-			buf[3] = 0x90;
-			dprintk("set_parameters VHF high range\n");
-		} else {
-			buf[3] = 0x30;
-			dprintk("set_parameters UHF range\n");
+		if (fe->ops.tuner_ops.set_params) {
+			fe->ops.tuner_ops.set_params(fe, param);
+			if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
 		}
-		dprintk("set_parameters tuner bytes: 0x%02x 0x%02x "
-			"0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]);
-
-		if (i2c_writebytes(state,0xC2>>1,buf,4))
-			printk(KERN_WARNING "or51211:set_parameters error "
-			       "writing to tuner\n");
 
 		/* Set to ATSC mode */
 		or51211_setmode(fe,0);
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
new file mode 100644
index 0000000..30e8a70
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1409.c
@@ -0,0 +1,729 @@
+/*
+    Samsung S5H1409 VSB/QAM demodulator driver
+
+    Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "dvb-pll.h"
+#include "s5h1409.h"
+
+struct s5h1409_state {
+
+	struct i2c_adapter* i2c;
+
+	/* configuration settings */
+	const struct s5h1409_config* config;
+
+	struct dvb_frontend frontend;
+
+	/* previous uncorrected block counter */
+	fe_modulation_t current_modulation;
+
+	u32 current_frequency;
+};
+
+static int debug = 0;
+#define dprintk	if (debug) printk
+
+/* Register values to initialise the demod, this will set VSB by default */
+static struct init_tab {
+	u8	reg;
+	u16	data;
+} init_tab[] = {
+	{ 0x00, 0x0071, },
+	{ 0x01, 0x3213, },
+	{ 0x09, 0x0025, },
+	{ 0x1c, 0x001d, },
+	{ 0x1f, 0x002d, },
+	{ 0x20, 0x001d, },
+	{ 0x22, 0x0022, },
+	{ 0x23, 0x0020, },
+	{ 0x29, 0x110f, },
+	{ 0x2a, 0x10b4, },
+	{ 0x2b, 0x10ae, },
+	{ 0x2c, 0x0031, },
+	{ 0x31, 0x010d, },
+	{ 0x32, 0x0100, },
+	{ 0x44, 0x0510, },
+	{ 0x54, 0x0104, },
+	{ 0x58, 0x2222, },
+	{ 0x59, 0x1162, },
+	{ 0x5a, 0x3211, },
+	{ 0x5d, 0x0370, },
+	{ 0x5e, 0x0296, },
+	{ 0x61, 0x0010, },
+	{ 0x63, 0x4a00, },
+	{ 0x65, 0x0800, },
+	{ 0x71, 0x0003, },
+	{ 0x72, 0x0470, },
+	{ 0x81, 0x0002, },
+	{ 0x82, 0x0600, },
+	{ 0x86, 0x0002, },
+	{ 0x8a, 0x2c38, },
+	{ 0x8b, 0x2a37, },
+	{ 0x92, 0x302f, },
+	{ 0x93, 0x3332, },
+	{ 0x96, 0x000c, },
+	{ 0x99, 0x0101, },
+	{ 0x9c, 0x2e37, },
+	{ 0x9d, 0x2c37, },
+	{ 0x9e, 0x2c37, },
+	{ 0xab, 0x0100, },
+	{ 0xac, 0x1003, },
+	{ 0xad, 0x103f, },
+	{ 0xe2, 0x0100, },
+	{ 0x28, 0x1010, },
+	{ 0xb1, 0x000e, },
+};
+
+/* VSB SNR lookup table */
+static struct vsb_snr_tab {
+	u16	val;
+	u16	data;
+} vsb_snr_tab[] = {
+	{ 1023, 770, },
+	{  923, 300, },
+	{  918, 295, },
+	{  915, 290, },
+	{  911, 285, },
+	{  906, 280, },
+	{  901, 275, },
+	{  896, 270, },
+	{  891, 265, },
+	{  885, 260, },
+	{  879, 255, },
+	{  873, 250, },
+	{  864, 245, },
+	{  858, 240, },
+	{  850, 235, },
+	{  841, 230, },
+	{  832, 225, },
+	{  823, 220, },
+	{  812, 215, },
+	{  802, 210, },
+	{  788, 205, },
+	{  778, 200, },
+	{  767, 195, },
+	{  753, 190, },
+	{  740, 185, },
+	{  725, 180, },
+	{  707, 175, },
+	{  689, 170, },
+	{  671, 165, },
+	{  656, 160, },
+	{  637, 155, },
+	{  616, 150, },
+	{  542, 145, },
+	{  519, 140, },
+	{  507, 135, },
+	{  497, 130, },
+	{  492, 125, },
+	{  474, 120, },
+	{  300, 111, },
+	{    0,   0, },
+};
+
+/* QAM64 SNR lookup table */
+static struct qam64_snr_tab {
+	u16	val;
+	u16	data;
+} qam64_snr_tab[] = {
+	{   12, 300, },
+	{   15, 290, },
+	{   18, 280, },
+	{   22, 270, },
+	{   23, 268, },
+	{   24, 266, },
+	{   25, 264, },
+	{   27, 262, },
+	{   28, 260, },
+	{   29, 258, },
+	{   30, 256, },
+	{   32, 254, },
+	{   33, 252, },
+	{   34, 250, },
+	{   35, 249, },
+	{   36, 248, },
+	{   37, 247, },
+	{   38, 246, },
+	{   39, 245, },
+	{   40, 244, },
+	{   41, 243, },
+	{   42, 241, },
+	{   43, 240, },
+	{   44, 239, },
+	{   45, 238, },
+	{   46, 237, },
+	{   47, 236, },
+	{   48, 235, },
+	{   49, 234, },
+	{   50, 233, },
+	{   51, 232, },
+	{   52, 231, },
+	{   53, 230, },
+	{   55, 229, },
+	{   56, 228, },
+	{   57, 227, },
+	{   58, 226, },
+	{   59, 225, },
+	{   60, 224, },
+	{   62, 223, },
+	{   63, 222, },
+	{   65, 221, },
+	{   66, 220, },
+	{   68, 219, },
+	{   69, 218, },
+	{   70, 217, },
+	{   72, 216, },
+	{   73, 215, },
+	{   75, 214, },
+	{   76, 213, },
+	{   78, 212, },
+	{   80, 211, },
+	{   81, 210, },
+	{   83, 209, },
+	{   84, 208, },
+	{   85, 207, },
+	{   87, 206, },
+	{   89, 205, },
+	{   91, 204, },
+	{   93, 203, },
+	{   95, 202, },
+	{   96, 201, },
+	{  104, 200, },
+};
+
+/* QAM256 SNR lookup table */
+static struct qam256_snr_tab {
+	u16	val;
+	u16	data;
+} qam256_snr_tab[] = {
+	{   12, 400, },
+	{   13, 390, },
+	{   15, 380, },
+	{   17, 360, },
+	{   19, 350, },
+	{   22, 348, },
+	{   23, 346, },
+	{   24, 344, },
+	{   25, 342, },
+	{   26, 340, },
+	{   27, 336, },
+	{   28, 334, },
+	{   29, 332, },
+	{   30, 330, },
+	{   31, 328, },
+	{   32, 326, },
+	{   33, 325, },
+	{   34, 322, },
+	{   35, 320, },
+	{   37, 318, },
+	{   39, 316, },
+	{   40, 314, },
+	{   41, 312, },
+	{   42, 310, },
+	{   43, 308, },
+	{   46, 306, },
+	{   47, 304, },
+	{   49, 302, },
+	{   51, 300, },
+	{   53, 298, },
+	{   54, 297, },
+	{   55, 296, },
+	{   56, 295, },
+	{   57, 294, },
+	{   59, 293, },
+	{   60, 292, },
+	{   61, 291, },
+	{   63, 290, },
+	{   64, 289, },
+	{   65, 288, },
+	{   66, 287, },
+	{   68, 286, },
+	{   69, 285, },
+	{   71, 284, },
+	{   72, 283, },
+	{   74, 282, },
+	{   75, 281, },
+	{   76, 280, },
+	{   77, 279, },
+	{   78, 278, },
+	{   81, 277, },
+	{   83, 276, },
+	{   84, 275, },
+	{   86, 274, },
+	{   87, 273, },
+	{   89, 272, },
+	{   90, 271, },
+	{   92, 270, },
+	{   93, 269, },
+	{   95, 268, },
+	{   96, 267, },
+	{   98, 266, },
+	{  100, 265, },
+	{  102, 264, },
+	{  104, 263, },
+	{  105, 262, },
+	{  106, 261, },
+	{  110, 260, },
+};
+
+/* 8 bit registers, 16 bit values */
+static int s5h1409_writereg(struct s5h1409_state* state, u8 reg, u16 data)
+{
+	int ret;
+	u8 buf [] = { reg, data >> 8,  data & 0xff };
+
+	struct i2c_msg msg = { .addr = state->config->demod_address,
+			       .flags = 0, .buf = buf, .len = 3 };
+
+	ret = i2c_transfer(state->i2c, &msg, 1);
+
+	if (ret != 1)
+		printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
+		       "ret == %i)\n", __FUNCTION__, reg, data, ret);
+
+	return (ret != 1) ? -1 : 0;
+}
+
+static u16 s5h1409_readreg(struct s5h1409_state* state, u8 reg)
+{
+	int ret;
+	u8 b0 [] = { reg };
+	u8 b1 [] = { 0, 0 };
+
+	struct i2c_msg msg [] = {
+		{ .addr = state->config->demod_address, .flags = 0,
+		  .buf = b0, .len = 1 },
+		{ .addr = state->config->demod_address, .flags = I2C_M_RD,
+		  .buf = b1, .len = 2 } };
+
+	ret = i2c_transfer(state->i2c, msg, 2);
+
+	if (ret != 2)
+		printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
+	return (b1[0] << 8) | b1[1];
+}
+
+static int s5h1409_softreset(struct dvb_frontend* fe)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __FUNCTION__);
+
+	s5h1409_writereg(state, 0xf5, 0);
+	s5h1409_writereg(state, 0xf5, 1);
+	return 0;
+}
+
+static int s5h1409_set_if_freq(struct dvb_frontend* fe, int KHz)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+	int ret = 0;
+
+	dprintk("%s(%d KHz)\n", __FUNCTION__, KHz);
+
+	if( (KHz == 44000) || (KHz == 5380) ) {
+		s5h1409_writereg(state, 0x87, 0x01be);
+		s5h1409_writereg(state, 0x88, 0x0436);
+		s5h1409_writereg(state, 0x89, 0x054d);
+	} else {
+		printk("%s() Invalid arg = %d KHz\n", __FUNCTION__, KHz);
+		ret = -1;
+	}
+
+	return ret;
+}
+
+static int s5h1409_set_spectralinversion(struct dvb_frontend* fe, int inverted)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __FUNCTION__);
+
+	if(inverted == 1)
+		return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */
+	else
+		return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */
+}
+
+static int s5h1409_enable_modulation(struct dvb_frontend* fe,
+				     fe_modulation_t m)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	dprintk("%s(0x%08x)\n", __FUNCTION__, m);
+
+	switch(m) {
+	case VSB_8:
+		dprintk("%s() VSB_8\n", __FUNCTION__);
+		s5h1409_writereg(state, 0xf4, 0);
+		break;
+	case QAM_64:
+		dprintk("%s() QAM_64\n", __FUNCTION__);
+		s5h1409_writereg(state, 0xf4, 1);
+		s5h1409_writereg(state, 0x85, 0x100);
+		break;
+	case QAM_256:
+		dprintk("%s() QAM_256\n", __FUNCTION__);
+		s5h1409_writereg(state, 0xf4, 1);
+		s5h1409_writereg(state, 0x85, 0x101);
+		break;
+	default:
+		dprintk("%s() Invalid modulation\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	state->current_modulation = m;
+	s5h1409_softreset(fe);
+
+	return 0;
+}
+
+static int s5h1409_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __FUNCTION__, enable);
+
+	if (enable)
+		return s5h1409_writereg(state, 0xf3, 1);
+	else
+		return s5h1409_writereg(state, 0xf3, 0);
+}
+
+static int s5h1409_set_gpio(struct dvb_frontend* fe, int enable)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __FUNCTION__, enable);
+
+	if (enable)
+		return s5h1409_writereg(state, 0xe3, 0x1100);
+	else
+		return s5h1409_writereg(state, 0xe3, 0);
+}
+
+static int s5h1409_sleep(struct dvb_frontend* fe, int enable)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	dprintk("%s(%d)\n", __FUNCTION__, enable);
+
+	return s5h1409_writereg(state, 0xf2, enable);
+}
+
+static int s5h1409_register_reset(struct dvb_frontend* fe)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	dprintk("%s()\n", __FUNCTION__);
+
+	return s5h1409_writereg(state, 0xfa, 0);
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int s5h1409_set_frontend (struct dvb_frontend* fe,
+				 struct dvb_frontend_parameters *p)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	dprintk("%s(frequency=%d)\n", __FUNCTION__, p->frequency);
+
+	s5h1409_softreset(fe);
+
+	state->current_frequency = p->frequency;
+
+	s5h1409_enable_modulation(fe, p->u.vsb.modulation);
+
+	if (fe->ops.tuner_ops.set_params) {
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 1);
+		fe->ops.tuner_ops.set_params(fe, p);
+		if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	return 0;
+}
+
+/* Reset the demod hardware and reset all of the configuration registers
+   to a default state. */
+static int s5h1409_init (struct dvb_frontend* fe)
+{
+	int i;
+
+	struct s5h1409_state* state = fe->demodulator_priv;
+	dprintk("%s()\n", __FUNCTION__);
+
+	s5h1409_sleep(fe, 0);
+	s5h1409_register_reset(fe);
+
+	for (i=0; i < ARRAY_SIZE(init_tab); i++)
+		s5h1409_writereg(state, init_tab[i].reg, init_tab[i].data);
+
+	/* The datasheet says that after initialisation, VSB is default */
+	state->current_modulation = VSB_8;
+
+	if (state->config->output_mode == S5H1409_SERIAL_OUTPUT)
+		s5h1409_writereg(state, 0xab, 0x100); /* Serial */
+	else
+		s5h1409_writereg(state, 0xab, 0x0); /* Parallel */
+
+	s5h1409_set_spectralinversion(fe, state->config->inversion);
+	s5h1409_set_if_freq(fe, state->config->if_freq);
+	s5h1409_set_gpio(fe, state->config->gpio);
+	s5h1409_softreset(fe);
+
+	/* Note: Leaving the I2C gate open here. */
+	s5h1409_i2c_gate_ctrl(fe, 1);
+
+	return 0;
+}
+
+static int s5h1409_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+	u16 reg;
+	u32 tuner_status = 0;
+
+	*status = 0;
+
+	/* Get the demodulator status */
+	reg = s5h1409_readreg(state, 0xf1);
+	if(reg & 0x1000)
+		*status |= FE_HAS_VITERBI;
+	if(reg & 0x8000)
+		*status |= FE_HAS_LOCK | FE_HAS_SYNC;
+
+	switch(state->config->status_mode) {
+	case S5H1409_DEMODLOCKING:
+		if (*status & FE_HAS_VITERBI)
+			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+		break;
+	case S5H1409_TUNERLOCKING:
+		/* Get the tuner status */
+		if (fe->ops.tuner_ops.get_status) {
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 1);
+
+			fe->ops.tuner_ops.get_status(fe, &tuner_status);
+
+			if (fe->ops.i2c_gate_ctrl)
+				fe->ops.i2c_gate_ctrl(fe, 0);
+		}
+		if (tuner_status)
+			*status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+		break;
+	}
+
+	dprintk("%s() status 0x%08x\n", __FUNCTION__, *status);
+
+	return 0;
+}
+
+static int s5h1409_qam256_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __FUNCTION__);
+
+	for (i=0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
+		if (v < qam256_snr_tab[i].val) {
+			*snr = qam256_snr_tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	return ret;
+}
+
+static int s5h1409_qam64_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __FUNCTION__);
+
+	for (i=0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
+		if (v < qam64_snr_tab[i].val) {
+			*snr = qam64_snr_tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	return ret;
+}
+
+static int s5h1409_vsb_lookup_snr(struct dvb_frontend* fe, u16* snr, u16 v)
+{
+	int i, ret = -EINVAL;
+	dprintk("%s()\n", __FUNCTION__);
+
+	for (i=0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
+		if (v > vsb_snr_tab[i].val) {
+			*snr = vsb_snr_tab[i].data;
+			ret = 0;
+			break;
+		}
+	}
+	dprintk("%s() snr=%d\n", __FUNCTION__, *snr);
+	return ret;
+}
+
+static int s5h1409_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+	u16 reg;
+	dprintk("%s()\n", __FUNCTION__);
+
+	reg = s5h1409_readreg(state, 0xf1) & 0x1ff;
+
+	switch(state->current_modulation) {
+	case QAM_64:
+		return s5h1409_qam64_lookup_snr(fe, snr, reg);
+	case QAM_256:
+		return s5h1409_qam256_lookup_snr(fe, snr, reg);
+	case VSB_8:
+		return s5h1409_vsb_lookup_snr(fe, snr, reg);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+static int s5h1409_read_signal_strength(struct dvb_frontend* fe,
+					u16* signal_strength)
+{
+	return s5h1409_read_snr(fe, signal_strength);
+}
+
+static int s5h1409_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	*ucblocks = s5h1409_readreg(state, 0xb5);
+
+	return 0;
+}
+
+static int s5h1409_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	return s5h1409_read_ucblocks(fe, ber);
+}
+
+static int s5h1409_get_frontend(struct dvb_frontend* fe,
+				struct dvb_frontend_parameters *p)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+
+	p->frequency = state->current_frequency;
+	p->u.vsb.modulation = state->current_modulation;
+
+	return 0;
+}
+
+static int s5h1409_get_tune_settings(struct dvb_frontend* fe,
+				     struct dvb_frontend_tune_settings *tune)
+{
+	tune->min_delay_ms = 1000;
+	return 0;
+}
+
+static void s5h1409_release(struct dvb_frontend* fe)
+{
+	struct s5h1409_state* state = fe->demodulator_priv;
+	kfree(state);
+}
+
+static struct dvb_frontend_ops s5h1409_ops;
+
+struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
+				    struct i2c_adapter* i2c)
+{
+	struct s5h1409_state* state = NULL;
+
+	/* allocate memory for the internal state */
+	state = kmalloc(sizeof(struct s5h1409_state), GFP_KERNEL);
+	if (state == NULL)
+		goto error;
+
+	/* setup the state */
+	state->config = config;
+	state->i2c = i2c;
+	state->current_modulation = 0;
+
+	/* check if the demod exists */
+	if (s5h1409_readreg(state, 0x04) != 0x0066)
+		goto error;
+
+	/* create dvb_frontend */
+	memcpy(&state->frontend.ops, &s5h1409_ops,
+	       sizeof(struct dvb_frontend_ops));
+	state->frontend.demodulator_priv = state;
+
+	/* Note: Leaving the I2C gate open here. */
+	s5h1409_writereg(state, 0xf3, 1);
+
+	return &state->frontend;
+
+error:
+	kfree(state);
+	return NULL;
+}
+
+static struct dvb_frontend_ops s5h1409_ops = {
+
+	.info = {
+		.name			= "Samsung S5H1409 QAM/8VSB Frontend",
+		.type			= FE_ATSC,
+		.frequency_min		= 54000000,
+		.frequency_max		= 858000000,
+		.frequency_stepsize	= 62500,
+		.caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+	},
+
+	.init                 = s5h1409_init,
+	.i2c_gate_ctrl        = s5h1409_i2c_gate_ctrl,
+	.set_frontend         = s5h1409_set_frontend,
+	.get_frontend         = s5h1409_get_frontend,
+	.get_tune_settings    = s5h1409_get_tune_settings,
+	.read_status          = s5h1409_read_status,
+	.read_ber             = s5h1409_read_ber,
+	.read_signal_strength = s5h1409_read_signal_strength,
+	.read_snr             = s5h1409_read_snr,
+	.read_ucblocks        = s5h1409_read_ucblocks,
+	.release              = s5h1409_release,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(s5h1409_attach);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/s5h1409.h b/drivers/media/dvb/frontends/s5h1409.h
new file mode 100644
index 0000000..20f9af1
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1409.h
@@ -0,0 +1,73 @@
+/*
+    Samsung S5H1409 VSB/QAM demodulator driver
+
+    Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __S5H1409_H__
+#define __S5H1409_H__
+
+#include <linux/dvb/frontend.h>
+
+struct s5h1409_config
+{
+	/* the demodulator's i2c address */
+	u8 demod_address;
+
+	/* serial/parallel output */
+#define S5H1409_PARALLEL_OUTPUT 0
+#define S5H1409_SERIAL_OUTPUT   1
+	u8 output_mode;
+
+	/* GPIO Setting */
+#define S5H1409_GPIO_OFF 0
+#define S5H1409_GPIO_ON  1
+	u8 gpio;
+
+	/* IF Freq in KHz */
+	u16 if_freq;
+
+	/* Spectral Inversion */
+#define S5H1409_INVERSION_OFF 0
+#define S5H1409_INVERSION_ON  1
+	u8 inversion;
+
+	/* Return lock status based on tuner lock, or demod lock */
+#define S5H1409_TUNERLOCKING 0
+#define S5H1409_DEMODLOCKING 1
+	u8 status_mode;
+};
+
+#if defined(CONFIG_DVB_S5H1409) || (defined(CONFIG_DVB_S5H1409_MODULE) && defined(MODULE))
+extern struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
+					   struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* s5h1409_attach(const struct s5h1409_config* config,
+						  struct i2c_adapter* i2c)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif /* CONFIG_DVB_S5H1409 */
+
+#endif /* __S5H1409_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c
index d98fd5c..da876f7 100644
--- a/drivers/media/dvb/frontends/sp8870.c
+++ b/drivers/media/dvb/frontends/sp8870.c
@@ -29,7 +29,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/delay.h>
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
index 5c2f8f4..1aa2539f 100644
--- a/drivers/media/dvb/frontends/sp887x.c
+++ b/drivers/media/dvb/frontends/sp887x.c
@@ -12,7 +12,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/firmware.h>
 #include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
index 9a34397..17e5cb5 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -680,8 +680,8 @@
 	.info = {
 		 .name = "ST STV0297 DVB-C",
 		 .type = FE_QAM,
-		 .frequency_min = 64000000,
-		 .frequency_max = 1300000000,
+		 .frequency_min = 47000000,
+		 .frequency_max = 862000000,
 		 .frequency_stepsize = 62500,
 		 .symbol_rate_min = 870000,
 		 .symbol_rate_max = 11700000,
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 18768d2..035dd7b 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -45,7 +45,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
@@ -249,7 +248,7 @@
 	dprintk ("%s\n", __FUNCTION__);
 
 	stv0299_readregs (state, 0x1f, sfr, 3);
-	stv0299_readregs (state, 0x1a, &rtf, 1);
+	stv0299_readregs (state, 0x1a, (u8 *)&rtf, 1);
 
 	srate = (sfr[0] << 8) | sfr[1];
 	srate *= Mclk;
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index e725f61..4cd9e82 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -439,8 +439,8 @@
 		.name = "Philips TDA10021 DVB-C",
 		.type = FE_QAM,
 		.frequency_stepsize = 62500,
-		.frequency_min = 51000000,
-		.frequency_max = 858000000,
+		.frequency_min = 47000000,
+		.frequency_max = 862000000,
 		.symbol_rate_min = (XIN/2)/64,     /* SACLK/64 == (XIN/2)/64 */
 		.symbol_rate_max = (XIN/2)/4,      /* SACLK/4 */
 	#if 0
diff --git a/drivers/media/dvb/frontends/tda10023.c b/drivers/media/dvb/frontends/tda10023.c
index da796e7..364bc01 100644
--- a/drivers/media/dvb/frontends/tda10023.c
+++ b/drivers/media/dvb/frontends/tda10023.c
@@ -215,12 +215,6 @@
 	s16 SFIL=0;
 	u16 NDEC = 0;
 
-	if (sr > (SYSCLK/(2*4)))
-		sr=SYSCLK/(2*4);
-
-	if (sr<870000)
-		sr=870000;
-
 	if (sr < (u32)(SYSCLK/98.40)) {
 		NDEC=3;
 		SFIL=1;
@@ -478,7 +472,7 @@
 	state->i2c = i2c;
 	memcpy(&state->frontend.ops, &tda10023_ops, sizeof(struct dvb_frontend_ops));
 	state->pwm = pwm;
-	for (i=0; i < sizeof(tda10023_inittab)/sizeof(*tda10023_inittab);i+=3) {
+	for (i=0; i < ARRAY_SIZE(tda10023_inittab);i+=3) {
 		if (tda10023_inittab[i] == 0x00) {
 			state->reg0 = tda10023_inittab[i+2];
 			break;
@@ -506,8 +500,8 @@
 		.name = "Philips TDA10023 DVB-C",
 		.type = FE_QAM,
 		.frequency_stepsize = 62500,
-		.frequency_min = 51000000,
-		.frequency_max = 858000000,
+		.frequency_min = 47000000,
+		.frequency_max = 862000000,
 		.symbol_rate_min = (SYSCLK/2)/64,     /* SACLK/64 == (SYSCLK/2)/64 */
 		.symbol_rate_max = (SYSCLK/2)/4,      /* SACLK/4 */
 		.caps = 0x400 | //FE_CAN_QAM_4
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index 33a8437..8415a8a 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -31,7 +31,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/jiffies.h>
 #include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c
index 0f2d4b4..9a8ddc5 100644
--- a/drivers/media/dvb/frontends/tda10086.c
+++ b/drivers/media/dvb/frontends/tda10086.c
@@ -22,7 +22,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/jiffies.h>
 #include <linux/string.h>
diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c
index 67415c9..011b74f 100644
--- a/drivers/media/dvb/frontends/tda8083.c
+++ b/drivers/media/dvb/frontends/tda8083.c
@@ -27,7 +27,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
@@ -443,12 +442,12 @@
 	.info = {
 		.name			= "Philips TDA8083 DVB-S",
 		.type			= FE_QPSK,
-		.frequency_min		= 950000,     /* FIXME: guessed! */
-		.frequency_max		= 1400000,    /* FIXME: guessed! */
+		.frequency_min		= 920000,     /* TDA8060 */
+		.frequency_max		= 2200000,    /* TDA8060 */
 		.frequency_stepsize	= 125,   /* kHz for QPSK frontends */
 	/*      .frequency_tolerance	= ???,*/
-		.symbol_rate_min	= 1000000,   /* FIXME: guessed! */
-		.symbol_rate_max	= 45000000,  /* FIXME: guessed! */
+		.symbol_rate_min	= 12000000,
+		.symbol_rate_max	= 30000000,
 	/*      .symbol_rate_tolerance	= ???,*/
 		.caps = FE_CAN_INVERSION_AUTO |
 			FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c
index 9b57576..066b73b 100644
--- a/drivers/media/dvb/frontends/ves1820.c
+++ b/drivers/media/dvb/frontends/ves1820.c
@@ -410,8 +410,8 @@
 		.name = "VLSI VES1820 DVB-C",
 		.type = FE_QAM,
 		.frequency_stepsize = 62500,
-		.frequency_min = 51000000,
-		.frequency_max = 858000000,
+		.frequency_min = 47000000,
+		.frequency_max = 862000000,
 		.caps = FE_CAN_QAM_16 |
 			FE_CAN_QAM_32 |
 			FE_CAN_QAM_64 |
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index 245f9b7..a97a7fd 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -21,7 +21,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/string.h>
diff --git a/drivers/media/dvb/pluto2/Makefile b/drivers/media/dvb/pluto2/Makefile
index ce6a9aa..7ac1287 100644
--- a/drivers/media/dvb/pluto2/Makefile
+++ b/drivers/media/dvb/pluto2/Makefile
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_PLUTO2) += pluto2.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 7751628..6d53289 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -108,7 +108,7 @@
 	tristate "Budget cards with analog video inputs"
 	depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
 	select VIDEO_SAA7146_VV
-	select DVB_PLL
+	select DVB_PLL if !DVB_FE_CUSTOMISE
 	select DVB_STV0299 if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
 	select DVB_TDA10021 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile
index aa85ecd..2c11452 100644
--- a/drivers/media/dvb/ttpci/Makefile
+++ b/drivers/media/dvb/ttpci/Makefile
@@ -11,7 +11,7 @@
 obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-core.o budget-patch.o ttpci-eeprom.o
 obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o ttpci-eeprom.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
 
 hostprogs-y	:= fdump
 
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index ef1108c..8b8144f 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -40,7 +40,6 @@
 #include <linux/smp_lock.h>
 
 #include <linux/kernel.h>
-#include <linux/moduleparam.h>
 #include <linux/sched.h>
 #include <linux/types.h>
 #include <linux/fcntl.h>
@@ -137,6 +136,15 @@
 	if (ret < 0)
 		printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret);
 
+	ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType,
+			    1, (u16) av7110->display_ar);
+	if (ret < 0)
+		printk("dvb-ttpci: unable to set aspect ratio\n");
+	ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
+			    1, av7110->display_panscan);
+	if (ret < 0)
+		printk("dvb-ttpci: unable to set pan scan\n");
+
 	ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 2, wss_cfg_4_3);
 	if (ret < 0)
 		printk("dvb-ttpci: unable to configure 4:3 wss\n");
@@ -1534,7 +1542,7 @@
 	}
 
 	/* check if the firmware is available */
-	av7110->bin_fw = (unsigned char *) vmalloc(fw->size);
+	av7110->bin_fw = vmalloc(fw->size);
 	if (NULL == av7110->bin_fw) {
 		dprintk(1, "out of memory\n");
 		release_firmware(fw);
@@ -2258,7 +2266,7 @@
 		FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
 		FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
 		FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
-		FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
+		FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage);
 		FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
 		FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
 
@@ -2639,12 +2647,12 @@
 	av7110->mixer.volume_left  = volume;
 	av7110->mixer.volume_right = volume;
 
-	init_av7110_av(av7110);
-
 	ret = av7110_register(av7110);
 	if (ret < 0)
 		goto err_arm_thread_stop_10;
 
+	init_av7110_av(av7110);
+
 	/* special case DVB-C: these cards have an analog tuner
 	   plus need some special handling, so we have separate
 	   saa7146_ext_vv data for these... */
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index 115002b..0cb4395 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -194,6 +194,7 @@
 
 	int			video_blank;
 	struct video_status	videostate;
+	u16			display_panscan;
 	int			display_ar;
 	int			trickmode;
 #define TRICK_NONE   0
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 58678c0..d75e7e4 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -391,7 +391,7 @@
  ****************************************************************************/
 
 static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf,
-					 const char *buf, unsigned long count)
+					 const u8 *buf, unsigned long count)
 {
 	unsigned long todo = count;
 	int free;
@@ -436,7 +436,7 @@
 #define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
 		   dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
 
-static ssize_t dvb_play(struct av7110 *av7110, const u8 __user *buf,
+static ssize_t dvb_play(struct av7110 *av7110, const char __user *buf,
 			unsigned long count, int nonblock, int type)
 {
 	unsigned long todo = count, n;
@@ -499,7 +499,7 @@
 	return count - todo;
 }
 
-static ssize_t dvb_aplay(struct av7110 *av7110, const u8 __user *buf,
+static ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf,
 			 unsigned long count, int nonblock, int type)
 {
 	unsigned long todo = count, n;
@@ -959,7 +959,7 @@
 
 #define MIN_IFRAME 400000
 
-static int play_iframe(struct av7110 *av7110, u8 __user *buf, unsigned int len, int nonblock)
+static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock)
 {
 	int i, n;
 
@@ -1082,19 +1082,18 @@
 	case VIDEO_SET_DISPLAY_FORMAT:
 	{
 		video_displayformat_t format = (video_displayformat_t) arg;
-		u16 val = 0;
 
 		switch (format) {
 		case VIDEO_PAN_SCAN:
-			val = VID_PAN_SCAN_PREF;
+			av7110->display_panscan = VID_PAN_SCAN_PREF;
 			break;
 
 		case VIDEO_LETTER_BOX:
-			val = VID_VC_AND_PS_PREF;
+			av7110->display_panscan = VID_VC_AND_PS_PREF;
 			break;
 
 		case VIDEO_CENTER_CUT_OUT:
-			val = VID_CENTRE_CUT_PREF;
+			av7110->display_panscan = VID_CENTRE_CUT_PREF;
 			break;
 
 		default:
@@ -1104,7 +1103,7 @@
 			break;
 		av7110->videostate.display_format = format;
 		ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
-				    1, (u16) val);
+				    1, av7110->display_panscan);
 		break;
 	}
 
@@ -1466,8 +1465,9 @@
 	av7110->videostate.play_state = VIDEO_STOPPED;
 	av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX;
 	av7110->videostate.video_format = VIDEO_FORMAT_4_3;
-	av7110->videostate.display_format = VIDEO_CENTER_CUT_OUT;
+	av7110->videostate.display_format = VIDEO_LETTER_BOX;
 	av7110->display_ar = VIDEO_FORMAT_4_3;
+	av7110->display_panscan = VID_VC_AND_PS_PREF;
 
 	init_waitqueue_head(&av7110->video_events.wait_queue);
 	spin_lock_init(&av7110->video_events.lock);
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
index e1c1294..c58e3fc 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
@@ -151,7 +151,7 @@
 {
 	int free;
 	int non_blocking = file->f_flags & O_NONBLOCK;
-	char *page = (char *)__get_free_page(GFP_USER);
+	u8 *page = (u8 *)__get_free_page(GFP_USER);
 	int res;
 
 	if (!page)
@@ -208,7 +208,7 @@
 		return -EINVAL;
 	DVB_RINGBUFFER_SKIP(cibuf, 2);
 
-	return dvb_ringbuffer_read(cibuf, buf, len, 1);
+	return dvb_ringbuffer_read(cibuf, (u8 *)buf, len, 1);
 }
 
 static int dvb_ca_open(struct inode *inode, struct file *file)
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 70aee4e..a468aa2 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -158,7 +158,7 @@
 		}
 		dprintk(4, "writing DRAM block %d\n", i);
 		mwdebi(av7110, DEBISWAB, bootblock,
-		       ((char*)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
+		       ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, AV7110_BOOT_MAX_SIZE);
 		bootblock ^= 0x1400;
 		iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
 		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, AV7110_BOOT_MAX_SIZE, 2);
@@ -173,10 +173,10 @@
 		}
 		if (rest > 4)
 			mwdebi(av7110, DEBISWAB, bootblock,
-			       ((char*)data) + i * AV7110_BOOT_MAX_SIZE, rest);
+			       ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE, rest);
 		else
 			mwdebi(av7110, DEBISWAB, bootblock,
-			       ((char*)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
+			       ((u8 *)data) + i * AV7110_BOOT_MAX_SIZE - 4, rest + 4);
 
 		iwdebi(av7110, DEBISWAB, AV7110_BOOT_BASE, swab32(base), 4);
 		iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, rest, 2);
@@ -751,7 +751,7 @@
 	return 0;
 }
 
-static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
+static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf)
 {
 	int i, ret;
 	unsigned long start;
@@ -978,24 +978,24 @@
 
 static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
 {
-       int i;
-       int length = last - first + 1;
+	int i;
+	int length = last - first + 1;
 
-       if (length * 4 > DATA_BUFF3_SIZE)
-	       return -EINVAL;
+	if (length * 4 > DATA_BUFF3_SIZE)
+		return -EINVAL;
 
-       for (i = 0; i < length; i++) {
-	       u32 color, blend, yuv;
+	for (i = 0; i < length; i++) {
+		u32 color, blend, yuv;
 
-	       if (get_user(color, colors + i))
-		       return -EFAULT;
-	       blend = (color & 0xF0000000) >> 4;
-	       yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
+		if (get_user(color, colors + i))
+			return -EFAULT;
+		blend = (color & 0xF0000000) >> 4;
+		yuv = blend ? RGB2YUV(color & 0xFF, (color >> 8) & 0xFF,
 				     (color >> 16) & 0xFF) | blend : 0;
-	       yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
-	       wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
-       }
-       return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
+		yuv = ((yuv & 0xFFFF0000) >> 16) | ((yuv & 0x0000FFFF) << 16);
+		wdebi(av7110, DEBINOSWAP, DATA_BUFF3_BASE + i * 4, yuv, 4);
+	}
+	return av7110_fw_cmd(av7110, COMTYPE_OSD, Set_Palette, 4,
 			    av7110->osdwin,
 			    bpp2pal[av7110->osdbpp[av7110->osdwin]],
 			    first, last);
diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h
index 673d9b3..74d940f 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.h
+++ b/drivers/media/dvb/ttpci/av7110_hw.h
@@ -393,7 +393,7 @@
 }
 
 /* buffer writes */
-static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, char *val, int count)
+static inline void mwdebi(struct av7110 *av7110, u32 config, int addr, u8 *val, int count)
 {
 	memcpy(av7110->debi_virt, val, count);
 	av7110_debiwrite(av7110, config, addr, 0, count);
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
index a97f166..5d19c40 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -25,7 +25,6 @@
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/proc_fs.h>
 #include <linux/kernel.h>
 #include <asm/bitops.h>
@@ -280,7 +279,7 @@
 	if (count < size)
 		return -EINVAL;
 
-	page = (char *) vmalloc(size);
+	page = vmalloc(size);
 	if (!page)
 		return -ENOMEM;
 
@@ -356,7 +355,7 @@
 		input_dev->id.vendor = av7110->dev->pci->vendor;
 		input_dev->id.product = av7110->dev->pci->device;
 	}
-	input_dev->cdev.dev = &av7110->dev->pci->dev;
+	input_dev->dev.parent = &av7110->dev->pci->dev;
 	/* initial keymap */
 	memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map);
 	input_register_keys(&av7110->ir);
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index fcd9994..76cca00 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -129,23 +129,25 @@
 
 static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
 {
+	struct av7110 *av7110 = dev->ext_priv;
 	u8 buf[] = { 0x00, reg, data };
 	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 3 };
 
 	dprintk(4, "dev: %p\n", dev);
 
-	if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
+	if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
 		return -1;
 	return 0;
 }
 
 static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4])
 {
+	struct av7110 *av7110 = dev->ext_priv;
 	struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
 
 	dprintk(4, "dev: %p\n", dev);
 
-	if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
+	if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
 		return -1;
 	return 0;
 }
@@ -333,7 +335,7 @@
 			return -EINVAL;
 
 		memset(t, 0, sizeof(*t));
-		strcpy(t->name, "Television");
+		strcpy((char *)t->name, "Television");
 
 		t->type = V4L2_TUNER_ANALOG_TV;
 		t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 0e817d6..3439c98 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -828,29 +828,6 @@
 	0xff, 0xff
 };
 
-static int philips_sd1878_tda8261_tuner_set_params(struct dvb_frontend *fe,
-						   struct dvb_frontend_parameters *params)
-{
-	u8              buf[4];
-	int             rc;
-	struct i2c_msg  tuner_msg = {.addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf)};
-	struct budget *budget = (struct budget *) fe->dvb->priv;
-
-	if((params->frequency < 950000) || (params->frequency > 2150000))
-		return -EINVAL;
-
-	rc=dvb_pll_configure(&dvb_pll_philips_sd1878_tda8261, buf,
-			     params->frequency, 0);
-	if(rc < 0) return rc;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if(i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
-		return -EIO;
-
-    return 0;
-}
-
 static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe,
 		u32 srate, u32 ratio)
 {
@@ -921,6 +898,7 @@
 #define SUBID_DVBS_TV_STAR		0x0014
 #define SUBID_DVBS_TV_STAR_CI		0x0016
 #define SUBID_DVBS_EASYWATCH_1  	0x001a
+#define SUBID_DVBS_EASYWATCH_2  	0x001b
 #define SUBID_DVBS_EASYWATCH		0x001e
 
 #define SUBID_DVBC_EASYWATCH		0x002a
@@ -982,10 +960,13 @@
 	case SUBID_DVBS_TV_STAR_CI:
 	case SUBID_DVBS_CYNERGY1200N:
 	case SUBID_DVBS_EASYWATCH:
+	case SUBID_DVBS_EASYWATCH_2:
 		fe = dvb_attach(stv0299_attach, &philips_sd1878_config,
 				&budget_av->budget.i2c_adap);
 		if (fe) {
-			fe->ops.tuner_ops.set_params = philips_sd1878_tda8261_tuner_set_params;
+			dvb_attach(dvb_pll_attach, fe, 0x60,
+				   &budget_av->budget.i2c_adap,
+				   DVB_PLL_PHILIPS_SD1878_TDA8261);
 		}
 		break;
 
@@ -1251,7 +1232,7 @@
 	.capabilities = 0,	// perhaps later: V4L2_CAP_VBI_CAPTURE, but that need tweaking with the saa7113
 	.flags = 0,
 	.stds = &standard[0],
-	.num_stds = sizeof(standard) / sizeof(struct saa7146_standard),
+	.num_stds = ARRAY_SIZE(standard),
 	.ioctls = &ioctls[0],
 	.ioctl = av_ioctl,
 };
@@ -1264,6 +1245,7 @@
 MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
 MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
 MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
+MAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S);
 MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP);
 MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3);
 MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
@@ -1287,6 +1269,7 @@
 	MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
 	MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
 	MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
+	MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b),
 	MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a),
 	MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c),
 	MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 9d42f88..5093492 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -206,7 +206,7 @@
 		input_dev->id.vendor = saa->pci->vendor;
 		input_dev->id.product = saa->pci->device;
 	}
-	input_dev->cdev.dev = &saa->pci->dev;
+	input_dev->dev.parent = &saa->pci->dev;
 
 	/* Select keymap and address */
 	switch (budget_ci->budget.dev->pci->subsystem_device) {
@@ -214,7 +214,6 @@
 	case 0x100f:
 	case 0x1011:
 	case 0x1012:
-	case 0x1017:
 		/* The hauppauge keymap is a superset of these remotes */
 		ir_input_init(input_dev, &budget_ci->ir.state,
 			      IR_TYPE_RC5, ir_codes_hauppauge_new);
@@ -225,6 +224,7 @@
 			budget_ci->ir.rc5_device = rc5_device;
 		break;
 	case 0x1010:
+	case 0x1017:
 		/* for the Technotrend 1500 bundled remote */
 		ir_input_init(input_dev, &budget_ci->ir.state,
 			      IR_TYPE_RC5, ir_codes_tt_1500);
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index b611f2b..0252081 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -34,7 +34,6 @@
  * the project's page is at http://www.linuxtv.org/dvb/
  */
 
-#include <linux/moduleparam.h>
 
 #include "budget.h"
 #include "ttpci-eeprom.h"
diff --git a/drivers/media/dvb/ttusb-budget/Makefile b/drivers/media/dvb/ttusb-budget/Makefile
index 6ab97f6..fbe2b95 100644
--- a/drivers/media/dvb/ttusb-budget/Makefile
+++ b/drivers/media/dvb/ttusb-budget/Makefile
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index b60cdc9..288e79f 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -13,7 +13,6 @@
 #include <linux/slab.h>
 #include <linux/wait.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/usb.h>
 #include <linux/delay.h>
 #include <linux/time.h>
diff --git a/drivers/media/dvb/ttusb-dec/Makefile b/drivers/media/dvb/ttusb-dec/Makefile
index b41bf1f..2d70a82 100644
--- a/drivers/media/dvb/ttusb-dec/Makefile
+++ b/drivers/media/dvb/ttusb-dec/Makefile
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o
 
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 78c98b0..5e691fd 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -22,7 +22,6 @@
 
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 194b102..11e962f 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -111,11 +111,16 @@
 	  jumper sets the card to 0x358.
 
 config RADIO_GEMTEK
-	tristate "GemTek Radio Card support"
+	tristate "GemTek Radio card (or compatible) support"
 	depends on ISA && VIDEO_V4L2
 	---help---
 	  Choose Y here if you have this FM radio card, and then fill in the
-	  port address below.
+	  I/O port address and settings below. The following cards either have
+	  GemTek Radio tuner or are rebranded GemTek Radio cards:
+
+	  - Sound Vision 16 Gold with FM Radio
+	  - Typhoon Radio card (some models)
+	  - Hama Radio card
 
 	  In order to control your radio card, you will need to use programs
 	  that are compatible with the Video For Linux API.  Information on
@@ -126,14 +131,25 @@
 	  module will be called radio-gemtek.
 
 config RADIO_GEMTEK_PORT
-	hex "GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)"
+	hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0c24c or 0x28c)"
 	depends on RADIO_GEMTEK=y
 	default "34c"
 	help
 	  Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is
 	  0x34c, if you haven't changed the jumper setting on the card. On
 	  Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O
-	  port is 0x28c.
+	  port is 0x20c, 0x248 or 0x28c.
+	  If automatic I/O port probing is enabled this port will be used only
+	  in case of automatic probing failure, ie. as a fallback.
+
+config RADIO_GEMTEK_PROBE
+	bool "Automatic I/O port probing"
+	depends on RADIO_GEMTEK=y
+	default y
+	help
+	  Say Y here to enable automatic probing for GemTek Radio card. The
+	  following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and
+	  0x28c.
 
 config RADIO_GEMTEK_PCI
 	tristate "GemTek PCI Radio Card support"
@@ -324,8 +340,8 @@
 	  Enter the I/O port of your Zoltrix radio card.
 
 config USB_DSBR
-	tristate "D-Link USB FM radio support (EXPERIMENTAL)"
-	depends on USB && VIDEO_V4L2 && EXPERIMENTAL
+	tristate "D-Link/GemTek USB FM radio support"
+	depends on USB && VIDEO_V4L2
 	---help---
 	  Say Y here if you want to connect this type of radio to your
 	  computer's USB port. Note that the audio is not digital, and
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 5adc27c..f0a67e9 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -63,7 +63,7 @@
 static void sleep_delay(long n)
 {
 	/* Sleep nicely for 'n' uS */
-	int d=n/(1000000/HZ);
+	int d=n/msecs_to_jiffies(1000);
 	if(!d)
 		udelay(n);
 	else
@@ -392,7 +392,6 @@
 	.owner		= THIS_MODULE,
 	.name		= "RadioTrack radio",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= 0,
 	.fops           = &rtrack_fops,
 	.vidioc_querycap    = vidioc_querycap,
 	.vidioc_g_tuner     = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 9f1adda..9b1f7a9 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -355,7 +355,6 @@
 	.owner		    = THIS_MODULE,
 	.name		    = "Aztech radio",
 	.type		    = VID_TYPE_TUNER,
-	.hardware	    = 0,
 	.fops               = &aztech_fops,
 	.vidioc_querycap    = vidioc_querycap,
 	.vidioc_g_tuner     = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 8cf2e9d..34e317c 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -329,7 +329,7 @@
 	init_timer(&readtimer);
 	readtimer.function=cadet_handler;
 	readtimer.data=(unsigned long)0;
-	readtimer.expires=jiffies+(HZ/20);
+	readtimer.expires=jiffies+msecs_to_jiffies(50);
 	add_timer(&readtimer);
 }
 
@@ -349,7 +349,7 @@
 		init_timer(&readtimer);
 		readtimer.function=cadet_handler;
 		readtimer.data=(unsigned long)0;
-		readtimer.expires=jiffies+(HZ/20);
+		readtimer.expires=jiffies+msecs_to_jiffies(50);
 		add_timer(&readtimer);
 	}
 	if(rdsin==rdsout) {
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 5e6f17d..99a3231 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -94,7 +94,6 @@
 
 	u32 iobase;
 	u32 length;
-	u16 model;
 
 	u32 current_frequency;
 	u8  mute;
@@ -377,7 +376,6 @@
 	.owner         = THIS_MODULE,
 	.name          = "Gemtek PCI Radio",
 	.type          = VID_TYPE_TUNER,
-	.hardware      = 0,
 	.fops          = &gemtek_pci_fops,
 	.vidioc_querycap    = vidioc_querycap,
 	.vidioc_g_tuner     = vidioc_g_tuner,
@@ -414,8 +412,6 @@
 		goto err_pci;
 	}
 
-	pci_read_config_word( pci_dev, PCI_SUBSYSTEM_ID, &card->model );
-
 	pci_set_drvdata( pci_dev, card );
 
 	if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index b04b6a7..0c963db 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -26,143 +26,383 @@
 #include <media/v4l2-common.h>
 #include <linux/spinlock.h>
 
-#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
-#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+#include <linux/version.h>	/* for KERNEL_VERSION MACRO	*/
+#define RADIO_VERSION KERNEL_VERSION(0,0,3)
+#define RADIO_BANNER "GemTek Radio card driver: v0.0.3"
 
-static struct v4l2_queryctrl radio_qctrl[] = {
-	{
-		.id            = V4L2_CID_AUDIO_MUTE,
-		.name          = "Mute",
-		.minimum       = 0,
-		.maximum       = 1,
-		.default_value = 1,
-		.type          = V4L2_CTRL_TYPE_BOOLEAN,
-	},{
-		.id            = V4L2_CID_AUDIO_VOLUME,
-		.name          = "Volume",
-		.minimum       = 0,
-		.maximum       = 65535,
-		.step          = 65535,
-		.default_value = 0xff,
-		.type          = V4L2_CTRL_TYPE_INTEGER,
-	}
-};
+/*
+ * Module info.
+ */
+
+MODULE_AUTHOR("Jonas Munsin, Pekka Seppänen <pexu@kapsi.fi>");
+MODULE_DESCRIPTION("A driver for the GemTek Radio card.");
+MODULE_LICENSE("GPL");
+
+/*
+ * Module params.
+ */
 
 #ifndef CONFIG_RADIO_GEMTEK_PORT
 #define CONFIG_RADIO_GEMTEK_PORT -1
 #endif
+#ifndef CONFIG_RADIO_GEMTEK_PROBE
+#define CONFIG_RADIO_GEMTEK_PROBE 1
+#endif
 
-static int io = CONFIG_RADIO_GEMTEK_PORT;
-static int radio_nr = -1;
-static spinlock_t lock;
+static int io		= CONFIG_RADIO_GEMTEK_PORT;
+static int probe	= CONFIG_RADIO_GEMTEK_PROBE;
+static int hardmute;
+static int shutdown	= 1;
+static int keepmuted	= 1;
+static int initmute	= 1;
+static int radio_nr	= -1;
 
-struct gemtek_device
-{
-	int port;
-	unsigned long curfreq;
+module_param(io, int, 0444);
+MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic"
+	 "probing is disabled or fails. The most common I/O ports are: 0x20c "
+	 "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to "
+	 " work for the combined sound/radiocard).");
+
+module_param(probe, bool, 0444);
+MODULE_PARM_DESC(probe, "Enable automatic device probing. Note: only the most "
+	"common I/O ports used by the card are probed.");
+
+module_param(hardmute, bool, 0644);
+MODULE_PARM_DESC(hardmute, "Enable `hard muting' by shutting down PLL, may "
+	 "reduce static noise.");
+
+module_param(shutdown, bool, 0644);
+MODULE_PARM_DESC(shutdown, "Enable shutting down PLL and muting line when "
+	 "module is unloaded.");
+
+module_param(keepmuted, bool, 0644);
+MODULE_PARM_DESC(keepmuted, "Keep card muted even when frequency is changed.");
+
+module_param(initmute, bool, 0444);
+MODULE_PARM_DESC(initmute, "Mute card when module is loaded.");
+
+module_param(radio_nr, int, 0444);
+
+/*
+ * Functions for controlling the card.
+ */
+#define GEMTEK_LOWFREQ	(87*16000)
+#define GEMTEK_HIGHFREQ	(108*16000)
+
+/*
+ * Frequency calculation constants.  Intermediate frequency 10.52 MHz (nominal
+ * value 10.7 MHz), reference divisor 6.39 kHz (nominal 6.25 kHz).
+ */
+#define FSCALE		8
+#define IF_OFFSET	((unsigned int)(10.52 * 16000 * (1<<FSCALE)))
+#define REF_FREQ	((unsigned int)(6.39 * 16 * (1<<FSCALE)))
+
+#define GEMTEK_CK		0x01	/* Clock signal			*/
+#define GEMTEK_DA		0x02	/* Serial data			*/
+#define GEMTEK_CE		0x04	/* Chip enable			*/
+#define GEMTEK_NS		0x08	/* No signal			*/
+#define GEMTEK_MT		0x10	/* Line mute			*/
+#define GEMTEK_STDF_3_125_KHZ	0x01	/* Standard frequency 3.125 kHz	*/
+#define GEMTEK_PLL_OFF		0x07	/* PLL off			*/
+
+#define BU2614_BUS_SIZE	32	/* BU2614 / BU2614FS bus size		*/
+
+#define SHORT_DELAY 5		/* usec */
+#define LONG_DELAY 75		/* usec */
+
+struct gemtek_device {
+	unsigned long lastfreq;
 	int muted;
+	u32 bu2614data;
 };
 
+#define BU2614_FREQ_BITS 	16 /* D0..D15, Frequency data		*/
+#define BU2614_PORT_BITS	3 /* P0..P2, Output port control data	*/
+#define BU2614_VOID_BITS	4 /* unused 				*/
+#define BU2614_FMES_BITS	1 /* CT, Frequency measurement beginning data */
+#define BU2614_STDF_BITS	3 /* R0..R2, Standard frequency data	*/
+#define BU2614_SWIN_BITS	1 /* S, Switch between FMIN / AMIN	*/
+#define BU2614_SWAL_BITS        1 /* PS, Swallow counter division (AMIN only)*/
+#define BU2614_VOID2_BITS	1 /* unused				*/
+#define BU2614_FMUN_BITS	1 /* GT, Frequency measurement time & unlock */
+#define BU2614_TEST_BITS	1 /* TS, Test data is input		*/
 
-/* local things */
+#define BU2614_FREQ_SHIFT 	0
+#define BU2614_PORT_SHIFT	(BU2614_FREQ_BITS + BU2614_FREQ_SHIFT)
+#define BU2614_VOID_SHIFT	(BU2614_PORT_BITS + BU2614_PORT_SHIFT)
+#define BU2614_FMES_SHIFT	(BU2614_VOID_BITS + BU2614_VOID_SHIFT)
+#define BU2614_STDF_SHIFT	(BU2614_FMES_BITS + BU2614_FMES_SHIFT)
+#define BU2614_SWIN_SHIFT	(BU2614_STDF_BITS + BU2614_STDF_SHIFT)
+#define BU2614_SWAL_SHIFT	(BU2614_SWIN_BITS + BU2614_SWIN_SHIFT)
+#define BU2614_VOID2_SHIFT	(BU2614_SWAL_BITS + BU2614_SWAL_SHIFT)
+#define BU2614_FMUN_SHIFT	(BU2614_VOID2_BITS + BU2614_VOID2_SHIFT)
+#define BU2614_TEST_SHIFT	(BU2614_FMUN_BITS + BU2614_FMUN_SHIFT)
 
-/* the correct way to mute the gemtek may be to write the last written
- * frequency || 0x10, but just writing 0x10 once seems to do it as well
+#define MKMASK(field)	(((1<<BU2614_##field##_BITS) - 1) << \
+			BU2614_##field##_SHIFT)
+#define BU2614_PORT_MASK	MKMASK(PORT)
+#define BU2614_FREQ_MASK	MKMASK(FREQ)
+#define BU2614_VOID_MASK	MKMASK(VOID)
+#define BU2614_FMES_MASK	MKMASK(FMES)
+#define BU2614_STDF_MASK	MKMASK(STDF)
+#define BU2614_SWIN_MASK	MKMASK(SWIN)
+#define BU2614_SWAL_MASK	MKMASK(SWAL)
+#define BU2614_VOID2_MASK	MKMASK(VOID2)
+#define BU2614_FMUN_MASK	MKMASK(FMUN)
+#define BU2614_TEST_MASK	MKMASK(TEST)
+
+static struct gemtek_device gemtek_unit;
+
+static spinlock_t lock;
+
+/*
+ * Set data which will be sent to BU2614FS.
+ */
+#define gemtek_bu2614_set(dev, field, data) ((dev)->bu2614data = \
+	((dev)->bu2614data & ~field##_MASK) | ((data) << field##_SHIFT))
+
+/*
+ * Transmit settings to BU2614FS over GemTek IC.
+ */
+static void gemtek_bu2614_transmit(struct gemtek_device *dev)
+{
+	int i, bit, q, mute;
+
+	spin_lock(&lock);
+
+	mute = dev->muted ? GEMTEK_MT : 0x00;
+
+	outb_p(mute | GEMTEK_DA | GEMTEK_CK, io);
+	udelay(SHORT_DELAY);
+	outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io);
+	udelay(LONG_DELAY);
+
+	for (i = 0, q = dev->bu2614data; i < 32; i++, q >>= 1) {
+	    bit = (q & 1) ? GEMTEK_DA : 0;
+	    outb_p(mute | GEMTEK_CE | bit, io);
+	    udelay(SHORT_DELAY);
+	    outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, io);
+	    udelay(SHORT_DELAY);
+	}
+
+	outb_p(mute | GEMTEK_DA | GEMTEK_CK, io);
+	udelay(SHORT_DELAY);
+	outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io);
+	udelay(LONG_DELAY);
+
+	spin_unlock(&lock);
+}
+
+/*
+ * Calculate divisor from FM-frequency for BU2614FS (3.125 KHz STDF expected).
+ */
+static unsigned long gemtek_convfreq(unsigned long freq)
+{
+	return ((freq<<FSCALE) + IF_OFFSET + REF_FREQ/2) / REF_FREQ;
+}
+
+/*
+ * Set FM-frequency.
+ */
+static void gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
+{
+
+	if (keepmuted && hardmute && dev->muted)
+		return;
+
+	if (freq < GEMTEK_LOWFREQ)
+		freq = GEMTEK_LOWFREQ;
+	else if (freq > GEMTEK_HIGHFREQ)
+		freq = GEMTEK_HIGHFREQ;
+
+	dev->lastfreq = freq;
+	dev->muted = 0;
+
+	gemtek_bu2614_set(dev, BU2614_PORT, 0);
+	gemtek_bu2614_set(dev, BU2614_FMES, 0);
+	gemtek_bu2614_set(dev, BU2614_SWIN, 0);	/* FM-mode	*/
+	gemtek_bu2614_set(dev, BU2614_SWAL, 0);
+	gemtek_bu2614_set(dev, BU2614_FMUN, 1);	/* GT bit set	*/
+	gemtek_bu2614_set(dev, BU2614_TEST, 0);
+
+	gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_STDF_3_125_KHZ);
+	gemtek_bu2614_set(dev, BU2614_FREQ, gemtek_convfreq(freq));
+
+	gemtek_bu2614_transmit(dev);
+}
+
+/*
+ * Set mute flag.
  */
 static void gemtek_mute(struct gemtek_device *dev)
 {
-	if(dev->muted)
-		return;
-	spin_lock(&lock);
-	outb(0x10, io);
-	spin_unlock(&lock);
+	int i;
 	dev->muted = 1;
+
+	if (hardmute) {
+		/* Turn off PLL, disable data output */
+		gemtek_bu2614_set(dev, BU2614_PORT, 0);
+		gemtek_bu2614_set(dev, BU2614_FMES, 0);	/* CT bit off	*/
+		gemtek_bu2614_set(dev, BU2614_SWIN, 0);	/* FM-mode	*/
+		gemtek_bu2614_set(dev, BU2614_SWAL, 0);
+		gemtek_bu2614_set(dev, BU2614_FMUN, 0);	/* GT bit off	*/
+		gemtek_bu2614_set(dev, BU2614_TEST, 0);
+		gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_PLL_OFF);
+		gemtek_bu2614_set(dev, BU2614_FREQ, 0);
+		gemtek_bu2614_transmit(dev);
+	} else {
+		spin_lock(&lock);
+
+		/* Read bus contents (CE, CK and DA). */
+		i = inb_p(io);
+		/* Write it back with mute flag set. */
+		outb_p((i >> 5) | GEMTEK_MT, io);
+		udelay(SHORT_DELAY);
+
+		spin_unlock(&lock);
+	}
 }
 
+/*
+ * Unset mute flag.
+ */
 static void gemtek_unmute(struct gemtek_device *dev)
 {
-	if(dev->muted == 0)
-		return;
-	spin_lock(&lock);
-	outb(0x20, io);
-	spin_unlock(&lock);
+	int i;
 	dev->muted = 0;
+
+	if (hardmute) {
+		/* Turn PLL back on. */
+		gemtek_setfreq(dev, dev->lastfreq);
+	} else {
+		spin_lock(&lock);
+
+		i = inb_p(io);
+		outb_p(i >> 5, io);
+		udelay(SHORT_DELAY);
+
+		spin_unlock(&lock);
+	}
 }
 
-static void zero(void)
+/*
+ * Get signal strength (= stereo status).
+ */
+static inline int gemtek_getsigstr(void)
 {
-	outb_p(0x04, io);
-	udelay(5);
-	outb_p(0x05, io);
-	udelay(5);
+	return inb_p(io) & GEMTEK_NS ? 0 : 1;
 }
 
-static void one(void)
+/*
+ * Check if requested card acts like GemTek Radio card.
+ */
+static int gemtek_verify(int port)
 {
-	outb_p(0x06, io);
-	udelay(5);
-	outb_p(0x07, io);
-	udelay(5);
+	static int verified = -1;
+	int i, q;
+
+	if (verified == port)
+		return 1;
+
+	spin_lock(&lock);
+
+	q = inb_p(port);	/* Read bus contents before probing. */
+	/* Try to turn on CE, CK and DA respectively and check if card responds
+	   properly. */
+	for (i = 0; i < 3; ++i) {
+		outb_p(1 << i, port);
+		udelay(SHORT_DELAY);
+
+		if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) {
+			spin_unlock(&lock);
+			return 0;
+		}
+	}
+	outb_p(q >> 5, port);	/* Write bus contents back. */
+	udelay(SHORT_DELAY);
+
+	spin_unlock(&lock);
+	verified = port;
+
+	return 1;
 }
 
-static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
+/*
+ * Automatic probing for card.
+ */
+static int gemtek_probe(void)
 {
+	int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c };
 	int i;
 
-/*        freq = 78.25*((float)freq/16000.0 + 10.52); */
+	if (!probe) {
+		printk(KERN_INFO "Automatic device probing disabled.\n");
+		return -1;
+	}
 
-	freq /= 16;
-	freq += 10520;
-	freq *= 7825;
-	freq /= 100000;
+	printk(KERN_INFO "Automatic device probing enabled.\n");
 
-	spin_lock(&lock);
+	for (i = 0; i < ARRAY_SIZE(ioports); ++i) {
+		printk(KERN_INFO "Trying I/O port 0x%x...\n", ioports[i]);
 
-	/* 2 start bits */
-	outb_p(0x03, io);
-	udelay(5);
-	outb_p(0x07, io);
-	udelay(5);
+		if (!request_region(ioports[i], 1, "gemtek-probe")) {
+			printk(KERN_WARNING "I/O port 0x%x busy!\n",
+			       ioports[i]);
+			continue;
+		}
 
-	/* 28 frequency bits (lsb first) */
-	for (i = 0; i < 14; i++)
-		if (freq & (1 << i))
-			one();
-		else
-			zero();
-	/* 36 unknown bits */
-	for (i = 0; i < 11; i++)
-		zero();
-	one();
-	for (i = 0; i < 4; i++)
-		zero();
-	one();
-	zero();
+		if (gemtek_verify(ioports[i])) {
+			printk(KERN_INFO "Card found from I/O port "
+			       "0x%x!\n", ioports[i]);
 
-	/* 2 end bits */
-	outb_p(0x03, io);
-	udelay(5);
-	outb_p(0x07, io);
-	udelay(5);
+			release_region(ioports[i], 1);
 
-	spin_unlock(&lock);
+			io = ioports[i];
+			return io;
+		}
 
-	return 0;
+		release_region(ioports[i], 1);
+	}
+
+	printk(KERN_ERR "Automatic probing failed!\n");
+
+	return -1;
 }
 
-static int gemtek_getsigstr(struct gemtek_device *dev)
-{
-	spin_lock(&lock);
-	inb(io);
-	udelay(5);
-	spin_unlock(&lock);
-	if (inb(io) & 8)		/* bit set = no signal present */
-		return 0;
-	return 1;		/* signal present */
-}
+/*
+ * Video 4 Linux stuff.
+ */
 
-static int vidioc_querycap(struct file *file, void  *priv,
-					struct v4l2_capability *v)
+static struct v4l2_queryctrl radio_qctrl[] = {
+	{
+		.id = V4L2_CID_AUDIO_MUTE,
+		.name = "Mute",
+		.minimum = 0,
+		.maximum = 1,
+		.default_value = 1,
+		.type = V4L2_CTRL_TYPE_BOOLEAN,
+	}, {
+		.id = V4L2_CID_AUDIO_VOLUME,
+		.name = "Volume",
+		.minimum = 0,
+		.maximum = 65535,
+		.step = 65535,
+		.default_value = 0xff,
+		.type = V4L2_CTRL_TYPE_INTEGER,
+	}
+};
+
+static struct file_operations gemtek_fops = {
+	.owner		= THIS_MODULE,
+	.open		= video_exclusive_open,
+	.release	= video_exclusive_release,
+	.ioctl		= video_ioctl2,
+	.compat_ioctl	= v4l_compat_ioctl32,
+	.llseek		= no_llseek
+};
+
+static int vidioc_querycap(struct file *file, void *priv,
+			   struct v4l2_capability *v)
 {
 	strlcpy(v->driver, "radio-gemtek", sizeof(v->driver));
 	strlcpy(v->card, "GemTek", sizeof(v->card));
@@ -172,28 +412,29 @@
 	return 0;
 }
 
-static int vidioc_g_tuner(struct file *file, void *priv,
-					struct v4l2_tuner *v)
+static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
 {
-	struct video_device *dev = video_devdata(file);
-	struct gemtek_device *rt = dev->priv;
-
 	if (v->index > 0)
 		return -EINVAL;
 
 	strcpy(v->name, "FM");
 	v->type = V4L2_TUNER_RADIO;
-	v->rangelow = (87*16000);
-	v->rangehigh = (108*16000);
-	v->rxsubchans = V4L2_TUNER_SUB_MONO;
-	v->capability = V4L2_TUNER_CAP_LOW;
-	v->audmode = V4L2_TUNER_MODE_MONO;
-	v->signal = 0xffff*gemtek_getsigstr(rt);
+	v->rangelow = GEMTEK_LOWFREQ;
+	v->rangehigh = GEMTEK_HIGHFREQ;
+	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+	v->signal = 0xffff * gemtek_getsigstr();
+	if (v->signal) {
+		v->audmode = V4L2_TUNER_MODE_STEREO;
+		v->rxsubchans = V4L2_TUNER_SUB_STEREO;
+	} else {
+		v->audmode = V4L2_TUNER_MODE_MONO;
+		v->rxsubchans = V4L2_TUNER_SUB_MONO;
+	}
+
 	return 0;
 }
 
-static int vidioc_s_tuner(struct file *file, void *priv,
-					struct v4l2_tuner *v)
+static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
 {
 	if (v->index > 0)
 		return -EINVAL;
@@ -201,38 +442,35 @@
 }
 
 static int vidioc_s_frequency(struct file *file, void *priv,
-					struct v4l2_frequency *f)
+			      struct v4l2_frequency *f)
 {
 	struct video_device *dev = video_devdata(file);
 	struct gemtek_device *rt = dev->priv;
 
-	rt->curfreq = f->frequency;
-	/* needs to be called twice in order for getsigstr to work */
-	gemtek_setfreq(rt, rt->curfreq);
-	gemtek_setfreq(rt, rt->curfreq);
+	gemtek_setfreq(rt, f->frequency);
+
 	return 0;
 }
 
 static int vidioc_g_frequency(struct file *file, void *priv,
-					struct v4l2_frequency *f)
+			      struct v4l2_frequency *f)
 {
 	struct video_device *dev = video_devdata(file);
 	struct gemtek_device *rt = dev->priv;
 
 	f->type = V4L2_TUNER_RADIO;
-	f->frequency = rt->curfreq;
+	f->frequency = rt->lastfreq;
 	return 0;
 }
 
 static int vidioc_queryctrl(struct file *file, void *priv,
-					struct v4l2_queryctrl *qc)
+			    struct v4l2_queryctrl *qc)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+	for (i = 0; i < ARRAY_SIZE(radio_qctrl); ++i) {
 		if (qc->id && qc->id == radio_qctrl[i].id) {
-			memcpy(qc, &(radio_qctrl[i]),
-						sizeof(*qc));
+			memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
 			return 0;
 		}
 	}
@@ -240,7 +478,7 @@
 }
 
 static int vidioc_g_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
+			 struct v4l2_control *ctrl)
 {
 	struct video_device *dev = video_devdata(file);
 	struct gemtek_device *rt = dev->priv;
@@ -260,7 +498,7 @@
 }
 
 static int vidioc_s_ctrl(struct file *file, void *priv,
-					struct v4l2_control *ctrl)
+			 struct v4l2_control *ctrl)
 {
 	struct video_device *dev = video_devdata(file);
 	struct gemtek_device *rt = dev->priv;
@@ -282,8 +520,7 @@
 	return -EINVAL;
 }
 
-static int vidioc_g_audio (struct file *file, void *priv,
-					struct v4l2_audio *a)
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
 {
 	if (a->index > 1)
 		return -EINVAL;
@@ -306,100 +543,102 @@
 	return 0;
 }
 
-static int vidioc_s_audio(struct file *file, void *priv,
-					struct v4l2_audio *a)
+static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
 {
 	if (a->index != 0)
 		return -EINVAL;
 	return 0;
 }
 
-static struct gemtek_device gemtek_unit;
-
-static const struct file_operations gemtek_fops = {
-	.owner		= THIS_MODULE,
-	.open           = video_exclusive_open,
-	.release        = video_exclusive_release,
-	.ioctl		= video_ioctl2,
-	.compat_ioctl	= v4l_compat_ioctl32,
-	.llseek         = no_llseek,
+static struct video_device gemtek_radio = {
+	.owner			= THIS_MODULE,
+	.name			= "GemTek Radio card",
+	.type			= VID_TYPE_TUNER,
+	.hardware		= VID_HARDWARE_GEMTEK,
+	.fops			= &gemtek_fops,
+	.vidioc_querycap	= vidioc_querycap,
+	.vidioc_g_tuner		= vidioc_g_tuner,
+	.vidioc_s_tuner		= vidioc_s_tuner,
+	.vidioc_g_audio		= vidioc_g_audio,
+	.vidioc_s_audio		= vidioc_s_audio,
+	.vidioc_g_input		= vidioc_g_input,
+	.vidioc_s_input		= vidioc_s_input,
+	.vidioc_g_frequency	= vidioc_g_frequency,
+	.vidioc_s_frequency	= vidioc_s_frequency,
+	.vidioc_queryctrl	= vidioc_queryctrl,
+	.vidioc_g_ctrl		= vidioc_g_ctrl,
+	.vidioc_s_ctrl		= vidioc_s_ctrl
 };
 
-static struct video_device gemtek_radio=
-{
-	.owner		= THIS_MODULE,
-	.name		= "GemTek radio",
-	.type		= VID_TYPE_TUNER,
-	.hardware	= 0,
-	.fops           = &gemtek_fops,
-	.vidioc_querycap    = vidioc_querycap,
-	.vidioc_g_tuner     = vidioc_g_tuner,
-	.vidioc_s_tuner     = vidioc_s_tuner,
-	.vidioc_g_audio     = vidioc_g_audio,
-	.vidioc_s_audio     = vidioc_s_audio,
-	.vidioc_g_input     = vidioc_g_input,
-	.vidioc_s_input     = vidioc_s_input,
-	.vidioc_g_frequency = vidioc_g_frequency,
-	.vidioc_s_frequency = vidioc_s_frequency,
-	.vidioc_queryctrl   = vidioc_queryctrl,
-	.vidioc_g_ctrl      = vidioc_g_ctrl,
-	.vidioc_s_ctrl      = vidioc_s_ctrl,
-};
+/*
+ * Initialization / cleanup related stuff.
+ */
 
+/*
+ * Initilize card.
+ */
 static int __init gemtek_init(void)
 {
-	if(io==-1)
-	{
-		printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (io=0x020c or io=0x248 for the combined sound/radiocard)\n");
-		return -EINVAL;
-	}
-
-	if (!request_region(io, 4, "gemtek"))
-	{
-		printk(KERN_ERR "gemtek: port 0x%x already in use\n", io);
-		return -EBUSY;
-	}
-
-	gemtek_radio.priv=&gemtek_unit;
-
-	if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr)==-1)
-	{
-		release_region(io, 4);
-		return -EINVAL;
-	}
-	printk(KERN_INFO "GemTek Radio Card driver.\n");
+	printk(KERN_INFO RADIO_BANNER "\n");
 
 	spin_lock_init(&lock);
 
-	/* this is _maybe_ unnecessary */
-	outb(0x01, io);
+	gemtek_probe();
+	if (io) {
+		if (!request_region(io, 1, "gemtek")) {
+			printk(KERN_ERR "I/O port 0x%x already in use.\n", io);
+			return -EBUSY;
+		}
 
-	/* mute card - prevents noisy bootups */
-	gemtek_unit.muted = 0;
-	gemtek_mute(&gemtek_unit);
+		if (!gemtek_verify(io))
+			printk(KERN_WARNING "Card at I/O port 0x%x does not "
+			       "respond properly, check your "
+			       "configuration.\n", io);
+		else
+			printk(KERN_INFO "Using I/O port 0x%x.\n", io);
+	} else if (probe) {
+		printk(KERN_ERR "Automatic probing failed and no "
+		       "fixed I/O port defined.\n");
+		return -ENODEV;
+	} else {
+		printk(KERN_ERR "Automatic probing disabled but no fixed "
+		       "I/O port defined.");
+		return -EINVAL;
+	}
+
+	gemtek_radio.priv = &gemtek_unit;
+
+	if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO,
+		radio_nr) == -1) {
+		release_region(io, 1);
+		return -EBUSY;
+	}
+
+	/* Set defaults */
+	gemtek_unit.lastfreq = GEMTEK_LOWFREQ;
+	gemtek_unit.bu2614data = 0;
+
+	if (initmute)
+		gemtek_mute(&gemtek_unit);
 
 	return 0;
 }
 
-MODULE_AUTHOR("Jonas Munsin");
-MODULE_DESCRIPTION("A driver for the GemTek Radio Card");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (0x20c or 0x248 have been reported to work for the combined sound/radiocard)).");
-module_param(radio_nr, int, 0);
-
-static void __exit gemtek_cleanup(void)
+/*
+ * Module cleanup
+ */
+static void __exit gemtek_exit(void)
 {
+	if (shutdown) {
+		hardmute = 1;	/* Turn off PLL */
+		gemtek_mute(&gemtek_unit);
+	} else {
+		printk(KERN_INFO "Module unloaded but card not muted!\n");
+	}
+
 	video_unregister_device(&gemtek_radio);
-	release_region(io,4);
+	release_region(io, 1);
 }
 
 module_init(gemtek_init);
-module_exit(gemtek_cleanup);
-
-/*
-  Local variables:
-  compile-command: "gcc -c -DMODVERSIONS -D__KERNEL__ -DMODULE -O6 -Wall -Wstrict-prototypes -I /home/blp/tmp/linux-2.1.111-rtrack/include radio-rtrack2.c"
-  End:
-*/
+module_exit(gemtek_exit);
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index 9b493b3..82aedfc 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -297,7 +297,6 @@
 	.owner		= THIS_MODULE,
 	.name		= "RadioTrack II radio",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= 0,
 	.fops           = &rtrack2_fops,
 	.vidioc_querycap    = vidioc_querycap,
 	.vidioc_g_tuner     = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index dc33f19..3951653 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -297,7 +297,6 @@
 	.owner		= THIS_MODULE,
 	.name		= "SF16FMx radio",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= 0,
 	.fops           = &fmi_fops,
 	.vidioc_querycap    = vidioc_querycap,
 	.vidioc_g_tuner     = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index e6c125d..c432c44 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -442,7 +442,6 @@
 	.owner		= THIS_MODULE,
 	.name		= "SF16FMR2 radio",
 	. type		= VID_TYPE_TUNER,
-	.hardware	= 0,
 	.fops		= &fmr2_fops,
 	.vidioc_querycap    = vidioc_querycap,
 	.vidioc_g_tuner     = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index e43acfd..535ffe8 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -173,7 +173,7 @@
 		i--;
 		p--;
 		temp = temp/2;
-       }
+	}
 
 	spin_lock(&lock);
 
@@ -369,7 +369,6 @@
 	.owner		= THIS_MODULE,
 	.name		= "TerraTec ActiveRadio",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= 0,
 	.fops           = &terratec_fops,
 	.vidioc_querycap    = vidioc_querycap,
 	.vidioc_g_tuner     = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index c27c629..c11981f 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -349,7 +349,6 @@
 	.owner		= THIS_MODULE,
 	.name		= "Trust FM Radio",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= 0,
 	.fops           = &trust_fops,
 	.vidioc_querycap    = vidioc_querycap,
 	.vidioc_g_tuner     = vidioc_g_tuner,
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index 8ff5a23..1366326 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -349,7 +349,6 @@
 	.owner		= THIS_MODULE,
 	.name		= "Typhoon Radio",
 	.type		= VID_TYPE_TUNER,
-	.hardware	= 0,
 	.fops           = &typhoon_fops,
 	.vidioc_querycap    = vidioc_querycap,
 	.vidioc_g_tuner     = vidioc_g_tuner,
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 4d45a40..2e571eb 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -148,6 +148,15 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called wm8739.
 
+config VIDEO_VP27SMPX
+	tristate "Panasonic VP27s internal MPX"
+	depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+	---help---
+	  Support for the internal MPX of the Panasonic VP27s tuner.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called vp27smpx.
+
 comment "Video decoders"
 
 config VIDEO_BT819
@@ -197,6 +206,13 @@
 	  OV7670 VGA camera.  It currently only works with the M88ALP01
 	  controller.
 
+config VIDEO_TCM825X
+	tristate "TCM825x camera sensor support"
+	depends on I2C && VIDEO_V4L2
+	---help---
+	  This is a driver for the Toshiba TCM825x VGA camera sensor.
+	  It is used for example in Nokia N800.
+
 config VIDEO_SAA7110
 	tristate "Philips SAA7110 video decoder"
 	depends on VIDEO_V4L1 && I2C
@@ -348,7 +364,7 @@
 config VIDEO_VIVI
 	tristate "Virtual Video Driver"
 	depends on VIDEO_V4L2 && !SPARC32 && !SPARC64 && PCI
-	select VIDEO_BUF
+	select VIDEOBUF_VMALLOC
 	default n
 	---help---
 	  Enables a virtual video driver. This device shows a color bar
@@ -500,7 +516,7 @@
 
 config VIDEO_STRADIS
 	tristate "Stradis 4:2:2 MPEG-2 video driver  (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && !PPC64
+	depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && VIRT_TO_BUS
 	help
 	  Say Y here to enable support for the Stradis 4:2:2 MPEG-2 video
 	  driver for PCI.  There is a product page at
@@ -511,7 +527,7 @@
 
 config VIDEO_ZORAN
 	tristate "Zoran ZR36057/36067 Video For Linux"
-	depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && !PPC64
+	depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && VIRT_TO_BUS
 	help
 	  Say Y for support for MJPEG capture cards based on the Zoran
 	  36057/36067 PCI controller chipset. This includes the Iomega
@@ -652,6 +668,8 @@
 
 source "drivers/media/video/cx88/Kconfig"
 
+source "drivers/media/video/cx23885/Kconfig"
+
 source "drivers/media/video/ivtv/Kconfig"
 
 config VIDEO_M32R_AR
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 9c2de50..b5a0641 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -4,19 +4,19 @@
 
 zr36067-objs	:=	zoran_procfs.o zoran_device.o \
 			zoran_driver.o zoran_card.o
-tuner-objs	:=	tuner-core.o tuner-types.o tuner-simple.o \
-			mt20xx.o tda8290.o tea5767.o tda9887.o
+tuner-objs	:=	tuner-core.o tuner-types.o tda9887.o
 
 msp3400-objs	:=	msp3400-driver.o msp3400-kthreads.o
 
-obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o
+obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \
+			   v4l2-int-device.o
 
 ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
   obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
 endif
 
 obj-$(CONFIG_VIDEO_BT848) += bt8xx/
-obj-$(CONFIG_VIDEO_BT848) += ir-kbd-i2c.o
+obj-$(CONFIG_VIDEO_IR_I2C)  += ir-kbd-i2c.o
 obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
 obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
 obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
@@ -59,9 +59,8 @@
 obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
 obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
 obj-$(CONFIG_VIDEO_MEYE) += meye.o
-obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
+obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
 obj-$(CONFIG_VIDEO_CX88) += cx88/
-obj-$(CONFIG_VIDEO_IVTV) += ivtv/
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
 obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
 obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
@@ -71,6 +70,7 @@
 obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
 obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
 obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
+obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
 obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
 obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
 obj-$(CONFIG_VIDEO_MXB) += mxb.o
@@ -80,8 +80,17 @@
 obj-$(CONFIG_TUNER_3036) += tuner-3036.o
 
 obj-$(CONFIG_VIDEO_TUNER) += tuner.o
-obj-$(CONFIG_VIDEO_BUF)   += video-buf.o
-obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o
+
+obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o
+obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o
+obj-$(CONFIG_TUNER_TDA8290) += tda8290.o
+obj-$(CONFIG_TUNER_TEA5767) += tea5767.o
+obj-$(CONFIG_TUNER_TEA5761) += tea5761.o
+
+obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
+obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
+obj-$(CONFIG_VIDEOBUF_VMALLOC) += videobuf-vmalloc.o
+obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
 obj-$(CONFIG_VIDEO_BTCX)  += btcx-risc.o
 obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
 
@@ -95,6 +104,8 @@
 obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
 obj-$(CONFIG_VIDEO_OV7670) 	+= ov7670.o
 
+obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
+
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
 obj-$(CONFIG_USB_OV511)         += ov511.o
 obj-$(CONFIG_USB_SE401)         += se401.o
@@ -112,6 +123,9 @@
 obj-$(CONFIG_USB_VICAM)         += usbvideo/
 obj-$(CONFIG_USB_QUICKCAM_MESSENGER)	+= usbvideo/
 
+obj-$(CONFIG_VIDEO_IVTV) += ivtv/
+
 obj-$(CONFIG_VIDEO_VIVI) += vivi.o
+obj-$(CONFIG_VIDEO_CX23885) += cx23885/
 
 EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index 823cd6c..cbab53f 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -38,23 +38,23 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
 
 MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
 MODULE_AUTHOR("Maxim Yevtyushkin");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(x) (x)->name
 
-#include <linux/video_encoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index 05c7820..0d0c554 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -34,23 +34,23 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
 
 MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
 MODULE_AUTHOR("Dave Perks");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(s) (s)->name
 
-#include <linux/video_encoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index 649f52f..19e9929 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -23,7 +23,6 @@
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
@@ -442,7 +441,7 @@
 	{
 		struct video_window *w = arg;
 		DEBUG(1, "VIDIOCGWIN:\n");
-		memset(w, 0, sizeof(w));
+		memset(w, 0, sizeof(*w));
 		w->width = ar->width;
 		w->height = ar->height;
 		return 0;
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index 59a4360..12d1b92 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -38,23 +38,24 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
+
 
 MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
 MODULE_AUTHOR("Mike Bernson & Dave Perks");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(s) (s)->name
 
-#include <linux/video_decoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
index 853b1a3..e1028a7 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -38,23 +38,23 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/video_encoder.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
 
 MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
 MODULE_AUTHOR("Mike Bernson & Dave Perks");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(s) (s)->name
 
-#include <linux/video_encoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
index 2e4cf1e..b767b09 100644
--- a/drivers/media/video/bt866.c
+++ b/drivers/media/video/bt866.c
@@ -257,7 +257,7 @@
 		printk(KERN_WARNING "%s: I/O error #%d "
 		       "(write 0x%02x/0x%02x)\n",
 		       encoder->i2c->name, err, encoder->addr, subaddr);
-		schedule_timeout_interruptible(HZ/10);
+		schedule_timeout_interruptible(msecs_to_jiffies(100));
 	}
 	if (err == 3) {
 		printk(KERN_WARNING "%s: giving up\n",
diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
index 58eae88..2ca162b 100644
--- a/drivers/media/video/bt8xx/Kconfig
+++ b/drivers/media/video/bt8xx/Kconfig
@@ -4,7 +4,7 @@
 	select I2C_ALGOBIT
 	select FW_LOADER
 	select VIDEO_BTCX
-	select VIDEO_BUF
+	select VIDEOBUF_DMA_SG
 	select VIDEO_IR
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 6b31e50..dd6a7d6 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -27,12 +27,12 @@
 
 #include <linux/delay.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kmod.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 #include <linux/firmware.h>
+#include <net/checksum.h>
 
 #include <asm/io.h>
 
@@ -45,7 +45,7 @@
 static void boot_bt832(struct bttv *btv);
 static void hauppauge_eeprom(struct bttv *btv);
 static void avermedia_eeprom(struct bttv *btv);
-static void osprey_eeprom(struct bttv *btv);
+static void osprey_eeprom(struct bttv *btv, const u8 ee[256]);
 static void modtec_eeprom(struct bttv *btv);
 static void init_PXC200(struct bttv *btv);
 static void init_RTV24(struct bttv *btv);
@@ -178,8 +178,8 @@
 	/* this seems to happen as well ... */
 	{ 0xff1211bd, BTTV_BOARD_PINNACLE,      "Pinnacle PCTV" },
 
-	{ 0x3000121a, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
-	{ 0x263710b4, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM/ VoodooTV 200" },
+	{ 0x3000121a, BTTV_BOARD_VOODOOTV_200,  "3Dfx VoodooTV 200" },
+	{ 0x263710b4, BTTV_BOARD_VOODOOTV_FM,   "3Dfx VoodooTV FM" },
 	{ 0x3060121a, BTTV_BOARD_STB2,	  "3Dfx VoodooTV 100/ STB OEM" },
 
 	{ 0x3000144f, BTTV_BOARD_MAGICTVIEW063, "(Askey Magic/others) TView99 CPH06x" },
@@ -313,6 +313,7 @@
 	{ 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE,    "Ultraview DVB-T Lite" },
 	{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE,    "DViCO FusionHDTV 5 Lite" },
 	{ 0x00261822, BTTV_BOARD_TWINHAN_DST,	"DNTV Live! Mini "},
+	{ 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2,	"DViCO FusionHDTV 2" },
 
 	{ 0, -1, NULL }
 };
@@ -329,7 +330,7 @@
 		.tuner		= 0,
 		.svhs		= 2,
 		.muxsel		= { 2, 3, 1, 0 },
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -344,7 +345,7 @@
 		.gpiomux 	= { 2, 0, 0, 0 },
 		.gpiomute 	= 10,
 		.needs_tvaudio	= 1,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -359,7 +360,7 @@
 		.gpiomux 	= { 0, 1, 2, 3 },
 		.gpiomute 	= 4,
 		.needs_tvaudio	= 1,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -387,13 +388,13 @@
 		.name		= "Intel Create and Share PCI/ Smart Video Recorder III",
 		.video_inputs	= 4,
 		.audio_inputs	= 0,
-		.tuner		= -1,
+		.tuner		= UNSET,
 		.svhs		= 2,
 		.gpiomask	= 0,
 		.muxsel		= { 2, 3, 1, 1 },
 		.gpiomux 	= { 0 },
 		.needs_tvaudio	= 0,
-		.tuner_type	= 4,
+		.tuner_type	= TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -408,7 +409,7 @@
 		.gpiomux 	= { 0, 1, 0, 1 },
 		.gpiomute 	= 3,
 		.needs_tvaudio	= 1,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -423,7 +424,7 @@
 		.gpiomux 	= { 0x0c, 0x04, 0x08, 0x04 },
 		/*                0x04 for some cards ?? */
 		.needs_tvaudio	= 1,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.audio_hook	= avermedia_tvphone_audio,
@@ -433,13 +434,13 @@
 		.name		= "MATRIX-Vision MV-Delta",
 		.video_inputs	= 5,
 		.audio_inputs	= 1,
-		.tuner		= -1,
+		.tuner		= UNSET,
 		.svhs		= 3,
 		.gpiomask	= 0,
 		.muxsel		= { 2, 3, 1, 0, 0 },
 		.gpiomux 	= { 0 },
 		.needs_tvaudio	= 1,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -457,7 +458,7 @@
 		.gpiomute 	= 0xc00,
 		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -488,7 +489,7 @@
 		.gpiomute 	= 4,
 		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -503,7 +504,7 @@
 		.gpiomux 	= { 0x20001,0x10001, 0, 0 },
 		.gpiomute 	= 10,
 		.needs_tvaudio	= 1,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -519,7 +520,7 @@
 		.muxsel		= { 2, 3, 1, 1 },
 		.gpiomux 	= { 13, 14, 11, 7 },
 		.needs_tvaudio	= 1,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -553,7 +554,7 @@
 		.gpiomute 	= 4,
 		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -568,7 +569,7 @@
 		.gpiomux 	= { 0, 0, 1, 0 },
 		.gpiomute 	= 10,
 		.needs_tvaudio	= 1,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -587,7 +588,7 @@
 		.gpiomute 	= 0x002000,
 		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 	},
 	[BTTV_BOARD_WINVIEW_601] = {
 		.name		= "Leadtek WinView 601",
@@ -600,7 +601,7 @@
 		.gpiomux 	= { 0x4fa007,0xcfa007,0xcfa007,0xcfa007 },
 		.gpiomute 	= 0xcfa007,
 		.needs_tvaudio	= 1,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.audio_hook	= winview_audio,
@@ -616,7 +617,7 @@
 		.muxsel		= { 2, 3, 1, 1 },
 		.gpiomux 	= { 1, 0, 0, 0 },
 		.needs_tvaudio	= 1,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -624,13 +625,13 @@
 		.name		= "Lifeview FlyVideo II EZ /FlyKit LR38 Bt848 (capture only)",
 		.video_inputs	= 4,
 		.audio_inputs	= 1,
-		.tuner		= -1,
-		.svhs		= -1,
+		.tuner		= UNSET,
+		.svhs		= UNSET,
 		.gpiomask	= 0x8dff00,
 		.muxsel		= { 2, 3, 1, 1 },
 		.gpiomux 	= { 0 },
 		.no_msp34xx	= 1,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -643,7 +644,7 @@
 		.tuner		= 0,
 		.svhs		= 2,
 		.muxsel		= { 2, 3, 1, 1 },
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -674,7 +675,7 @@
 		.gpiomute 	= 0xc00,
 		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -683,7 +684,7 @@
 		.video_inputs	= 3,
 		.audio_inputs	= 1,
 		.tuner		= 0,
-		.svhs		= -1,
+		.svhs		= UNSET,
 		.gpiomask	= 7,
 		.muxsel		= { 2, 3, -1 },
 		.digital_mode   = DIGITAL_MODE_CAMERA,
@@ -708,7 +709,7 @@
 		.gpiomute 	= 0xc00,
 		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.has_remote     = 1,
@@ -740,7 +741,7 @@
 		.gpiomux 	= { 0, 1, 2, 3 },
 		.gpiomute 	= 4,
 		.needs_tvaudio	= 1,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -813,13 +814,13 @@
 		.name		= "Imagenation PXC200",
 		.video_inputs	= 5,
 		.audio_inputs	= 1,
-		.tuner		= -1,
+		.tuner		= UNSET,
 		.svhs		= 1, /* was: 4 */
 		.gpiomask	= 0,
 		.muxsel		= { 2, 3, 1, 0, 0},
 		.gpiomux 	= { 0 },
 		.needs_tvaudio	= 1,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.muxsel_hook    = PXC200_muxsel,
@@ -836,7 +837,7 @@
 		.gpiomux 	= { 0, 0x0800, 0x1000, 0x1000 },
 		.gpiomute 	= 0x1800,
 		.pll            = PLL_28,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -860,13 +861,13 @@
 		.name		= "Intel Create and Share PCI/ Smart Video Recorder III",
 		.video_inputs	= 4,
 		.audio_inputs	= 0,
-		.tuner		= -1,
+		.tuner		= UNSET,
 		.svhs		= 2,
 		.gpiomask	= 0,
 		.muxsel		= { 2, 3, 1, 1 },
 		.gpiomux 	= { 0 },
 		.needs_tvaudio	= 0,
-		.tuner_type	= 4,
+		.tuner_type	= TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -911,7 +912,7 @@
 		.needs_tvaudio	= 0,
 		.pll		= PLL_28,
 		.has_radio	= 1,
-		.tuner_type	= 5, /* default for now, gpio reads BFFF06 for Pal bg+dk */
+		.tuner_type	= TUNER_PHILIPS_PAL, /* default for now, gpio reads BFFF06 for Pal bg+dk */
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.audio_hook	= winfast2000_audio,
@@ -928,7 +929,7 @@
 		.gpiomux 	= { 0, 0x800, 0x1000, 0x1000 },
 		.gpiomute 	= 0x1800,
 		.pll		= PLL_28,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -945,7 +946,7 @@
 		.gpiomux 	= { 0, 0x800, 0x1000, 0x1000 },
 		.gpiomute 	= 0x1800,
 		.pll		= PLL_28,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.has_radio	= 1,
@@ -962,7 +963,7 @@
 		.gpiomute 	= 0x29,
 		.no_msp34xx	= 1,
 		.pll		= PLL_28,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -978,7 +979,7 @@
 		.gpiomute 	= 0x551c00,
 		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
-		.tuner_type	= 1,
+		.tuner_type	= TUNER_PHILIPS_PAL_I,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.has_remote     = 1,
@@ -995,7 +996,7 @@
 		.gpiomute 	= 1,
 		.needs_tvaudio	= 0,
 		.pll		= PLL_28,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1030,7 +1031,7 @@
 		.gpiomux 	= { 13, 4, 11, 7 },
 		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.has_radio	= 1,
@@ -1048,7 +1049,7 @@
 		.needs_tvaudio	= 1,
 		.no_msp34xx	= 1,
 		.pll		= PLL_28,
-		.tuner_type	= 1,
+		.tuner_type	= TUNER_PHILIPS_PAL_I,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1063,7 +1064,7 @@
 		.gpiomux 	= { 0xff9ff6, 0xff9ff6, 0xff1ff7, 0 },
 		.gpiomute 	= 0xff3ffc,
 		.no_msp34xx	= 1,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1074,14 +1075,14 @@
 		.video_inputs	= 2,
 		.audio_inputs	= 1,
 		.tuner		= 0,
-		.svhs		= -1,
+		.svhs		= UNSET,
 		.gpiomask	= 3,
 		.muxsel		= { 2, 3, 1, 1 },
 		.gpiomux 	= { 1, 1, 0, 2 },
 		.gpiomute 	= 3,
 		.no_msp34xx	= 1,
 		.pll		= PLL_NONE,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1089,14 +1090,14 @@
 		.name		= "MATRIX-Vision MV-Delta 2",
 		.video_inputs	= 5,
 		.audio_inputs	= 1,
-		.tuner		= -1,
+		.tuner		= UNSET,
 		.svhs		= 3,
 		.gpiomask	= 0,
 		.muxsel		= { 2, 3, 1, 0, 0 },
 		.gpiomux 	= { 0 },
 		.no_msp34xx	= 1,
 		.pll		= PLL_28,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1112,7 +1113,7 @@
 		.gpiomute 	= 0xbcb03f,
 		.no_msp34xx	= 1,
 		.pll		= PLL_28,
-		.tuner_type	= 21,
+		.tuner_type	= TUNER_TEMIC_4039FR5_NTSC,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1129,7 +1130,7 @@
 		.needs_tvaudio	= 1,
 		.no_msp34xx	= 1,
 		.pll		= PLL_35,
-		.tuner_type	= 1,
+		.tuner_type	= TUNER_PHILIPS_PAL_I,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.has_radio	= 1,
@@ -1148,7 +1149,7 @@
 		.gpiomute 	= 1,
 		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1206,7 +1207,7 @@
 		.gpiomux        = { 0, 1, 2, 3 },
 		.gpiomute 	= 4,
 		.pll            = PLL_28,
-		.tuner_type     = -1 /* TUNER_ALPS_TMDH2_NTSC */,
+		.tuner_type     = UNSET /* TUNER_ALPS_TMDH2_NTSC */,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1234,7 +1235,7 @@
 					1= FM stereo Radio from Tuner */
 		.needs_tvaudio  = 0,
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1277,7 +1278,7 @@
 				0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
 				0x0880: Tuner A2 stereo */
 		.pll		= PLL_28,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1313,7 +1314,7 @@
 		.gpiomux        = { 0, 0x800, 0x1000, 0x1000 },
 		.gpiomute 	= 0x1800,
 		.pll            = PLL_28,
-		.tuner_type     = 5,
+		.tuner_type     = TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1324,7 +1325,7 @@
 		.name           = "GrandTec 'Grand Video Capture' (Bt848)",
 		.video_inputs   = 2,
 		.audio_inputs   = 0,
-		.tuner          = -1,
+		.tuner          = UNSET,
 		.svhs           = 1,
 		.gpiomask       = 0,
 		.muxsel         = { 3, 1 },
@@ -1332,7 +1333,7 @@
 		.needs_tvaudio  = 0,
 		.no_msp34xx     = 1,
 		.pll            = PLL_35,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1365,7 +1366,7 @@
 		.gpiomux        = { 2, 0, 0, 0 },
 		.gpiomute 	= 1,
 		.pll            = PLL_28,
-		.tuner_type	= 0,
+		.tuner_type	= TUNER_TEMIC_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1377,7 +1378,7 @@
 		.video_inputs   = 2,
 		.audio_inputs   = 2,
 		.tuner		= 0,
-		.svhs		= -1,
+		.svhs		= UNSET,
 		.gpiomask       = 11,
 		.muxsel         = { 2, 3, 1, 1 },
 		.gpiomux        = { 2, 0, 0, 1 },
@@ -1392,7 +1393,7 @@
 		.name		= "AG Electronics GMV1",
 		.video_inputs   = 2,
 		.audio_inputs   = 0,
-		.tuner		= -1,
+		.tuner		= UNSET,
 		.svhs		= 1,
 		.gpiomask       = 0xF,
 		.muxsel		= { 2, 2 },
@@ -1400,7 +1401,7 @@
 		.no_msp34xx     = 1,
 		.needs_tvaudio  = 0,
 		.pll		= PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1447,7 +1448,7 @@
 		.video_inputs	= 2,
 		.audio_inputs	= 1,
 		.tuner		= 0,
-		.svhs		= -1,
+		.svhs		= UNSET,
 		.gpiomask	= 1,
 		.muxsel		= { 2, 3, 0, 1 },
 		.gpiomux 	= { 0, 0, 1, 0 },
@@ -1476,7 +1477,7 @@
 		.no_tda9875	= 1,
 		.needs_tvaudio  = 1,
 		.pll            = PLL_28,
-		.tuner_type     = 5,
+		.tuner_type     = TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1517,13 +1518,35 @@
 
 	/* ---- card 0x44 ---------------------------------- */
 	[BTTV_BOARD_VOODOOTV_FM] = {
-		.name           = "3Dfx VoodooTV FM (Euro), VoodooTV 200 (USA)",
+		.name           = "3Dfx VoodooTV FM (Euro)",
 		/* try "insmod msp3400 simple=0" if you have
 		* sound problems with this card. */
 		.video_inputs   = 4,
 		.audio_inputs   = 1,
 		.tuner          = 0,
-		.svhs           = -1,
+		.svhs           = UNSET,
+		.gpiomask       = 0x4f8a00,
+		/* 0x100000: 1=MSP enabled (0=disable again)
+		* 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
+		.gpiomux        = {0x947fff, 0x987fff,0x947fff,0x947fff },
+		.gpiomute 	= 0x947fff,
+		/* tvtuner, radio,   external,internal, mute,  stereo
+		* tuner, Composit, SVid, Composit-on-Svid-adapter */
+		.muxsel         = { 2, 3 ,0 ,1 },
+		.tuner_type     = TUNER_MT2032,
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.pll		= PLL_28,
+		.has_radio	= 1,
+	},
+	[BTTV_BOARD_VOODOOTV_200] = {
+		.name           = "VoodooTV 200 (USA)",
+		/* try "insmod msp3400 simple=0" if you have
+		* sound problems with this card. */
+		.video_inputs   = 4,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = UNSET,
 		.gpiomask       = 0x4f8a00,
 		/* 0x100000: 1=MSP enabled (0=disable again)
 		* 0x010000: Connected to "S0" on tda9880 (0=Pal/BG, 1=NTSC) */
@@ -1543,8 +1566,8 @@
 		.name           = "Active Imaging AIMMS",
 		.video_inputs   = 1,
 		.audio_inputs   = 0,
-		.tuner          = -1,
-		.tuner_type     = -1,
+		.tuner          = UNSET,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.pll            = PLL_28,
@@ -1564,7 +1587,7 @@
 		.gpiomute 	= 13,
 		.needs_tvaudio  = 1,
 		.pll            = PLL_28,
-		.tuner_type     = 25,
+		.tuner_type     = TUNER_LG_PAL_I_FM,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.has_remote     = 1,
@@ -1580,7 +1603,7 @@
 		.name		= "Lifeview FlyVideo 98EZ (capture only) LR51",
 		.video_inputs	= 4,
 		.audio_inputs   = 0,
-		.tuner		= -1,
+		.tuner		= UNSET,
 		.svhs		= 2,
 		.muxsel		= { 2, 3, 1, 1 }, /* AV1, AV2, SVHS, CVid adapter on SVHS */
 		.pll		= PLL_28,
@@ -1606,7 +1629,7 @@
 		.no_msp34xx	= 1,
 		.no_tda9875	= 1,
 		.pll		= PLL_28,
-		.tuner_type	= 5,
+		.tuner_type	= TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.audio_hook	= pvbt878p9b_audio, /* Note: not all cards have stereo */
@@ -1626,13 +1649,13 @@
 		.name           = "Sensoray 311",
 		.video_inputs   = 5,
 		.audio_inputs   = 0,
-		.tuner          = -1,
+		.tuner          = UNSET,
 		.svhs           = 4,
 		.gpiomask       = 0,
 		.muxsel         = { 2, 3, 1, 0, 0 },
 		.gpiomux        = { 0 },
 		.needs_tvaudio  = 0,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1641,15 +1664,15 @@
 		.name           = "RemoteVision MX (RV605)",
 		.video_inputs   = 16,
 		.audio_inputs   = 0,
-		.tuner          = -1,
-		.svhs           = -1,
+		.tuner          = UNSET,
+		.svhs           = UNSET,
 		.gpiomask       = 0x00,
 		.gpiomask2      = 0x07ff,
 		.muxsel         = { 0x33, 0x13, 0x23, 0x43, 0xf3, 0x73, 0xe3, 0x03,
 				0xd3, 0xb3, 0xc3, 0x63, 0x93, 0x53, 0x83, 0xa3 },
 		.no_msp34xx     = 1,
 		.no_tda9875     = 1,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.muxsel_hook    = rv605_muxsel,
@@ -1693,15 +1716,15 @@
 		.name           = "GrandTec Multi Capture Card (Bt878)",
 		.video_inputs   = 4,
 		.audio_inputs   = 0,
-		.tuner          = -1,
-		.svhs           = -1,
+		.tuner          = UNSET,
+		.svhs           = UNSET,
 		.gpiomask       = 0,
 		.muxsel         = { 2, 3, 1, 0 },
 		.gpiomux        = { 0 },
 		.needs_tvaudio  = 0,
 		.no_msp34xx     = 1,
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1724,7 +1747,7 @@
 		.needs_tvaudio  = 0,
 		.no_msp34xx     = 1,
 		.pll            = PLL_28,
-		.tuner_type     = 5,
+		.tuner_type     = TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		/* Samsung TCPA9095PC27A (BG+DK), philips compatible, w/FM, stereo and
@@ -1744,10 +1767,10 @@
 		/* Arthur Tetzlaff-Deas, DSP Design Ltd <software@dspdesign.com> */
 		.name           = "DSP Design TCVIDEO",
 		.video_inputs   = 4,
-		.svhs           = -1,
+		.svhs           = UNSET,
 		.muxsel         = { 2, 3, 1, 0 },
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -1762,7 +1785,7 @@
 		.muxsel         = { 2, 0, 1, 1 },
 		.needs_tvaudio  = 1,
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 
@@ -1791,11 +1814,11 @@
 		.name           = "Osprey 100/150 (878)", /* 0x1(2|3)-45C6-C1 */
 		.video_inputs   = 4,                  /* id-inputs-clock */
 		.audio_inputs   = 0,
-		.tuner          = -1,
+		.tuner          = UNSET,
 		.svhs           = 3,
 		.muxsel         = { 3, 2, 0, 1 },
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.no_msp34xx     = 1,
@@ -1806,11 +1829,11 @@
 		.name           = "Osprey 100/150 (848)", /* 0x04-54C0-C1 & older boards */
 		.video_inputs   = 3,
 		.audio_inputs   = 0,
-		.tuner          = -1,
+		.tuner          = UNSET,
 		.svhs           = 2,
 		.muxsel         = { 2, 3, 1 },
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.no_msp34xx     = 1,
@@ -1823,11 +1846,11 @@
 		.name           = "Osprey 101 (848)", /* 0x05-40C0-C1 */
 		.video_inputs   = 2,
 		.audio_inputs   = 0,
-		.tuner          = -1,
+		.tuner          = UNSET,
 		.svhs           = 1,
 		.muxsel         = { 3, 1 },
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.no_msp34xx     = 1,
@@ -1838,11 +1861,11 @@
 		.name           = "Osprey 101/151",       /* 0x1(4|5)-0004-C4 */
 		.video_inputs   = 1,
 		.audio_inputs   = 0,
-		.tuner          = -1,
-		.svhs           = -1,
+		.tuner          = UNSET,
+		.svhs           = UNSET,
 		.muxsel         = { 0 },
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.no_msp34xx     = 1,
@@ -1853,11 +1876,11 @@
 		.name           = "Osprey 101/151 w/ svid",  /* 0x(16|17|20)-00C4-C1 */
 		.video_inputs   = 2,
 		.audio_inputs   = 0,
-		.tuner          = -1,
+		.tuner          = UNSET,
 		.svhs           = 1,
 		.muxsel         = { 0, 1 },
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.no_msp34xx     = 1,
@@ -1868,8 +1891,8 @@
 		.name           = "Osprey 200/201/250/251",  /* 0x1(8|9|E|F)-0004-C4 */
 		.video_inputs   = 1,
 		.audio_inputs   = 1,
-		.tuner          = -1,
-		.svhs           = -1,
+		.tuner          = UNSET,
+		.svhs           = UNSET,
 		.muxsel         = { 0 },
 		.pll            = PLL_28,
 		.tuner_type	= UNSET,
@@ -1885,7 +1908,7 @@
 		.name           = "Osprey 200/250",   /* 0x1(A|B)-00C4-C1 */
 		.video_inputs   = 2,
 		.audio_inputs   = 1,
-		.tuner          = -1,
+		.tuner          = UNSET,
 		.svhs           = 1,
 		.muxsel         = { 0, 1 },
 		.pll            = PLL_28,
@@ -1900,7 +1923,7 @@
 		.name           = "Osprey 210/220/230",   /* 0x1(A|B)-04C0-C1 */
 		.video_inputs   = 2,
 		.audio_inputs   = 1,
-		.tuner          = -1,
+		.tuner          = UNSET,
 		.svhs           = 1,
 		.muxsel         = { 2, 3 },
 		.pll            = PLL_28,
@@ -1915,11 +1938,11 @@
 		.name           = "Osprey 500",   /* 500 */
 		.video_inputs   = 2,
 		.audio_inputs   = 1,
-		.tuner          = -1,
+		.tuner          = UNSET,
 		.svhs           = 1,
 		.muxsel         = { 2, 3 },
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.no_msp34xx     = 1,
@@ -1930,9 +1953,9 @@
 		.name           = "Osprey 540",   /* 540 */
 		.video_inputs   = 4,
 		.audio_inputs   = 1,
-		.tuner          = -1,
+		.tuner          = UNSET,
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.no_msp34xx     = 1,
@@ -1945,7 +1968,7 @@
 		.name           = "Osprey 2000",  /* 2000 */
 		.video_inputs   = 2,
 		.audio_inputs   = 1,
-		.tuner          = -1,
+		.tuner          = UNSET,
 		.svhs           = 1,
 		.muxsel         = { 2, 3 },
 		.pll            = PLL_28,
@@ -1961,11 +1984,11 @@
 		.name           = "IDS Eagle",
 		.video_inputs   = 4,
 		.audio_inputs   = 0,
-		.tuner          = -1,
-		.tuner_type     = -1,
+		.tuner          = UNSET,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.svhs           = -1,
+		.svhs           = UNSET,
 		.gpiomask       = 0,
 		.muxsel         = { 0, 1, 2, 3 },
 		.muxsel_hook    = eagle_muxsel,
@@ -1978,8 +2001,8 @@
 		.video_inputs   = 2,
 		.audio_inputs   = 0,
 		.svhs           = 1,
-		.tuner          = -1,
-		.tuner_type     = -1,
+		.tuner          = UNSET,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.no_msp34xx     = 1,
@@ -2020,13 +2043,13 @@
 		.video_inputs   = 3,
 		.audio_inputs   = 1,
 		.tuner          = 0,
-		.svhs           = -1,
+		.svhs           = UNSET,
 		.gpiomask       = 7,
 		.muxsel         = { 2, 3, 1, 1},
 		.gpiomux        = { 0, 1, 2, 3},
 		.gpiomute 	= 4,
 		.needs_tvaudio  = 1,
-		.tuner_type     = 5,
+		.tuner_type     = TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.pll            = PLL_28,
@@ -2035,7 +2058,7 @@
 		.name           = "Euresys Picolo",
 		.video_inputs   = 3,
 		.audio_inputs   = 0,
-		.tuner          = -1,
+		.tuner          = UNSET,
 		.svhs           = 2,
 		.gpiomask       = 0,
 		.no_msp34xx     = 1,
@@ -2052,8 +2075,8 @@
 		.name           = "ProVideo PV150", /* 0x4f */
 		.video_inputs   = 2,
 		.audio_inputs   = 0,
-		.tuner          = -1,
-		.svhs           = -1,
+		.tuner          = UNSET,
+		.svhs           = UNSET,
 		.gpiomask       = 0,
 		.muxsel         = { 2, 3 },
 		.gpiomux        = { 0 },
@@ -2080,7 +2103,7 @@
 		.needs_tvaudio  = 0,
 		.no_msp34xx     = 1,
 		.pll            = PLL_28,
-		.tuner_type     = 2,
+		.tuner_type     = TUNER_PHILIPS_NTSC,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.audio_hook	= adtvk503_audio,
@@ -2098,7 +2121,7 @@
 		.needs_tvaudio  = 1,
 		.no_msp34xx     = 1,
 		.pll            = PLL_28,
-		.tuner_type     = 5,
+		.tuner_type     = TUNER_PHILIPS_PAL,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		/* Notes:
@@ -2121,7 +2144,7 @@
 		.gpiomask       = 0,
 		.no_tda9875     = 1,
 		.no_tda7432     = 1,
-		.tuner_type     = 1,
+		.tuner_type     = TUNER_PHILIPS_PAL_I,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.has_radio      = 1,
@@ -2138,11 +2161,11 @@
 		.name           = "IVC-200",
 		.video_inputs   = 1,
 		.audio_inputs   = 0,
-		.tuner          = -1,
-		.tuner_type     = -1,
+		.tuner          = UNSET,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.svhs           = -1,
+		.svhs           = UNSET,
 		.gpiomask       = 0xdf,
 		.muxsel         = { 2 },
 		.pll            = PLL_28,
@@ -2151,9 +2174,9 @@
 		.name           = "Grand X-Guard / Trust 814PCI",
 		.video_inputs   = 16,
 		.audio_inputs   = 0,
-		.tuner          = -1,
-		.svhs           = -1,
-		.tuner_type     = 4,
+		.tuner          = UNSET,
+		.svhs           = UNSET,
+		.tuner_type     = TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.gpiomask2      = 0xff,
@@ -2169,14 +2192,14 @@
 	[BTTV_BOARD_NEBULA_DIGITV] = {
 		.name           = "Nebula Electronics DigiTV",
 		.video_inputs   = 1,
-		.tuner          = -1,
-		.svhs           = -1,
+		.tuner          = UNSET,
+		.svhs           = UNSET,
 		.muxsel         = { 2, 3, 1, 0 },
 		.no_msp34xx     = 1,
 		.no_tda9875     = 1,
 		.no_tda7432     = 1,
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.has_dvb        = 1,
@@ -2189,15 +2212,15 @@
 		.name           = "ProVideo PV143",
 		.video_inputs   = 4,
 		.audio_inputs   = 0,
-		.tuner          = -1,
-		.svhs           = -1,
+		.tuner          = UNSET,
+		.svhs           = UNSET,
 		.gpiomask       = 0,
 		.muxsel         = { 2, 3, 1, 0 },
 		.gpiomux        = { 0 },
 		.needs_tvaudio  = 0,
 		.no_msp34xx     = 1,
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -2206,14 +2229,14 @@
 		.name           = "PHYTEC VD-009-X1 MiniDIN (bt878)",
 		.video_inputs   = 4,
 		.audio_inputs   = 0,
-		.tuner          = -1, /* card has no tuner */
+		.tuner          = UNSET, /* card has no tuner */
 		.svhs           = 3,
 		.gpiomask       = 0x00,
 		.muxsel         = { 2, 3, 1, 0 },
 		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
 		.needs_tvaudio  = 1,
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -2221,14 +2244,14 @@
 		.name           = "PHYTEC VD-009-X1 Combi (bt878)",
 		.video_inputs   = 4,
 		.audio_inputs   = 0,
-		.tuner          = -1, /* card has no tuner */
+		.tuner          = UNSET, /* card has no tuner */
 		.svhs           = 3,
 		.gpiomask       = 0x00,
 		.muxsel         = { 2, 3, 1, 1 },
 		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
 		.needs_tvaudio  = 1,
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -2238,7 +2261,7 @@
 		.name           = "PHYTEC VD-009 MiniDIN (bt878)",
 		.video_inputs   = 10,
 		.audio_inputs   = 0,
-		.tuner          = -1, /* card has no tuner */
+		.tuner          = UNSET, /* card has no tuner */
 		.svhs           = 9,
 		.gpiomask       = 0x00,
 		.gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
@@ -2248,7 +2271,7 @@
 		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
 		.needs_tvaudio  = 1,
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -2256,7 +2279,7 @@
 		.name           = "PHYTEC VD-009 Combi (bt878)",
 		.video_inputs   = 10,
 		.audio_inputs   = 0,
-		.tuner          = -1, /* card has no tuner */
+		.tuner          = UNSET, /* card has no tuner */
 		.svhs           = 9,
 		.gpiomask       = 0x00,
 		.gpiomask2      = 0x03, /* gpiomask2 defines the bits used to switch audio
@@ -2266,7 +2289,7 @@
 		.gpiomux        = { 0, 0, 0, 0 }, /* card has no audio */
 		.needs_tvaudio  = 1,
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -2274,11 +2297,11 @@
 		.name           = "IVC-100",
 		.video_inputs   = 4,
 		.audio_inputs   = 0,
-		.tuner          = -1,
-		.tuner_type     = -1,
+		.tuner          = UNSET,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.svhs           = -1,
+		.svhs           = UNSET,
 		.gpiomask       = 0xdf,
 		.muxsel         = { 2, 3, 1, 0 },
 		.pll            = PLL_28,
@@ -2288,11 +2311,11 @@
 		.name           = "IVC-120G",
 		.video_inputs   = 16,
 		.audio_inputs   = 0,    /* card has no audio */
-		.tuner          = -1,   /* card has no tuner */
-		.tuner_type     = -1,
+		.tuner          = UNSET,   /* card has no tuner */
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.svhs           = -1,   /* card has no svhs */
+		.svhs           = UNSET,   /* card has no svhs */
 		.needs_tvaudio  = 0,
 		.no_msp34xx     = 1,
 		.no_tda9875     = 1,
@@ -2333,7 +2356,7 @@
 		.video_inputs   = 3,
 		.audio_inputs   = 0,
 		.svhs           = 1,
-		.tuner          = -1,
+		.tuner          = UNSET,
 		.muxsel         = { 3, 1, 1, 3 }, /* Vid In, SVid In, Vid over SVid in connector */
 		.no_msp34xx     = 1,
 		.no_tda9875     = 1,
@@ -2364,9 +2387,9 @@
 		.name           = "SIMUS GVC1100",
 		.video_inputs   = 4,
 		.audio_inputs   = 0,
-		.tuner          = -1,
-		.svhs           = -1,
-		.tuner_type     = -1,
+		.tuner          = UNSET,
+		.svhs           = UNSET,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.pll            = PLL_28,
@@ -2395,14 +2418,14 @@
 		.name           = "LMLBT4",
 		.video_inputs   = 4, /* IN1,IN2,IN3,IN4 */
 		.audio_inputs   = 0,
-		.tuner          = -1,
-		.svhs           = -1,
+		.tuner          = UNSET,
+		.svhs           = UNSET,
 		.muxsel         = { 2, 3, 1, 0 },
 		.no_msp34xx     = 1,
 		.no_tda9875     = 1,
 		.no_tda7432     = 1,
 		.needs_tvaudio  = 0,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -2452,8 +2475,8 @@
 		.name           = "Euresys Picolo Tetra",
 		.video_inputs   = 4,
 		.audio_inputs   = 0,
-		.tuner          = -1,
-		.svhs           = -1,
+		.tuner          = UNSET,
+		.svhs           = UNSET,
 		.gpiomask       = 0,
 		.gpiomask2      = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
 		.no_msp34xx     = 1,
@@ -2464,7 +2487,7 @@
 		.pll            = PLL_28,
 		.needs_tvaudio  = 0,
 		.muxsel_hook    = picolo_tetra_muxsel,/*Required as it doesn't follow the classic input selection policy*/
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -2490,7 +2513,7 @@
 		.name           = "AVerMedia AVerTV DVB-T 771",
 		.video_inputs   = 2,
 		.svhs           = 1,
-		.tuner          = -1,
+		.tuner          = UNSET,
 		.tuner_type     = TUNER_ABSENT,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
@@ -2509,14 +2532,14 @@
 		/* Based on the Nebula card data - added remote and new card number - BTTV_BOARD_AVDVBT_761, see also ir-kbd-gpio.c */
 		.name           = "AverMedia AverTV DVB-T 761",
 		.video_inputs   = 2,
-		.tuner          = -1,
+		.tuner          = UNSET,
 		.svhs           = 1,
 		.muxsel         = { 3, 1, 2, 0 }, /* Comp0, S-Video, ?, ? */
 		.no_msp34xx     = 1,
 		.no_tda9875     = 1,
 		.no_tda7432     = 1,
 		.pll            = PLL_28,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.has_dvb        = 1,
@@ -2528,8 +2551,8 @@
 		.name             = "MATRIX Vision Sigma-SQ",
 		.video_inputs     = 16,
 		.audio_inputs     = 0,
-		.tuner            = -1,
-		.svhs             = -1,
+		.tuner            = UNSET,
+		.svhs             = UNSET,
 		.gpiomask         = 0x0,
 		.muxsel           = { 2, 2, 2, 2, 2, 2, 2, 2,
 				3, 3, 3, 3, 3, 3, 3, 3 },
@@ -2537,7 +2560,7 @@
 		.gpiomux          = { 0 },
 		.no_msp34xx       = 1,
 		.pll              = PLL_28,
-		.tuner_type       = -1,
+		.tuner_type       = UNSET,
 		.tuner_addr	  = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -2546,15 +2569,15 @@
 		.name             = "MATRIX Vision Sigma-SLC",
 		.video_inputs     = 4,
 		.audio_inputs     = 0,
-		.tuner            = -1,
-		.svhs             = -1,
+		.tuner            = UNSET,
+		.svhs             = UNSET,
 		.gpiomask         = 0x0,
 		.muxsel           = { 2, 2, 2, 2 },
 		.muxsel_hook      = sigmaSLC_muxsel,
 		.gpiomux          = { 0 },
 		.no_msp34xx       = 1,
 		.pll              = PLL_28,
-		.tuner_type       = -1,
+		.tuner_type       = UNSET,
 		.tuner_addr	  = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -2566,7 +2589,7 @@
 		.video_inputs   = 2,
 		.audio_inputs   = 1,
 		.tuner          = 0,
-		.svhs           = -1,
+		.svhs           = UNSET,
 		.gpiomask       = 0xFF,
 		.muxsel         = { 2, 3, 1, 1 },
 		.gpiomux        = { 2, 0, 0, 0 },
@@ -2584,14 +2607,14 @@
 	[BTTV_BOARD_DVICO_DVBT_LITE] = {
 		/* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
 		.name           = "DViCO FusionHDTV DVB-T Lite",
-		.tuner          = -1,
+		.tuner          = UNSET,
 		.no_msp34xx     = 1,
 		.no_tda9875     = 1,
 		.no_tda7432     = 1,
 		.pll            = PLL_28,
 		.no_video       = 1,
 		.has_dvb        = 1,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -2634,14 +2657,14 @@
 		.name           = "Tibet Systems 'Progress DVR' CS16",
 		.video_inputs   = 16,
 		.audio_inputs   = 0,
-		.tuner          = -1,
-		.svhs           = -1,
+		.tuner          = UNSET,
+		.svhs           = UNSET,
 		.muxsel         = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
 		.pll		= PLL_28,
 		.no_msp34xx     = 1,
 		.no_tda9875     = 1,
 		.no_tda7432	= 1,
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.muxsel_hook    = tibetCS16_muxsel,
@@ -2661,11 +2684,11 @@
 		.name           = "Kodicom 4400R (master)",
 		.video_inputs	= 16,
 		.audio_inputs	= 0,
-		.tuner		= -1,
-		.tuner_type	= -1,
+		.tuner		= UNSET,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.svhs		= -1,
+		.svhs		= UNSET,
 		/* GPIO bits 0-9 used for analog switch:
 		*   00 - 03:	camera selector
 		*   04 - 06:	channel (controller) selector
@@ -2693,11 +2716,11 @@
 		.name		= "Kodicom 4400R (slave)",
 		.video_inputs	= 16,
 		.audio_inputs	= 0,
-		.tuner		= -1,
-		.tuner_type	= -1,
+		.tuner		= UNSET,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
-		.svhs		= -1,
+		.svhs		= UNSET,
 		.gpiomask	= 0x010000,
 		.no_gpioirq     = 1,
 		.muxsel		= { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
@@ -2717,7 +2740,7 @@
 		.tuner          = 0,
 		.svhs           = 2,
 		.muxsel         = { 2, 3, 1, 0 },
-		.tuner_type     = -1,
+		.tuner_type     = UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.pll            = PLL_28,
@@ -2820,13 +2843,28 @@
 		.has_remote     = 1,
 	},
 		/* ---- card 0x8c ---------------------------------- */
+	/* Has four Bt878 chips behind a PCI bridge, each chip has:
+	     one external BNC composite input (mux 2)
+	     three internal composite inputs (unknown muxes)
+	     an 18-bit stereo A/D (CS5331A), which has:
+	       one external stereo unblanced (RCA) audio connection
+	       one (or 3?) internal stereo balanced (XLR) audio connection
+	       input is selected via gpio to a 14052B mux
+		 (mask=0x300, unbal=0x000, bal=0x100, ??=0x200,0x300)
+	       gain is controlled via an X9221A chip on the I2C bus @0x28
+	       sample rate is controlled via gpio to an MK1413S
+		 (mask=0x3, 32kHz=0x0, 44.1kHz=0x1, 48kHz=0x2, ??=0x3)
+	     There is neither a tuner nor an svideo input. */
 	[BTTV_BOARD_OSPREY440]  = {
 		.name           = "Osprey 440",
-		.video_inputs   = 1,
-		.audio_inputs   = 1,
-		.tuner          = -1,
-		.svhs           = 1,
-		.muxsel         = { 2 },
+		.video_inputs   = 4,
+		.audio_inputs   = 2, /* this is meaningless */
+		.tuner          = UNSET,
+		.svhs           = UNSET,
+		.muxsel         = { 2, 3, 0, 1 }, /* 3,0,1 are guesses */
+		.gpiomask	= 0x303,
+		.gpiomute	= 0x000, /* int + 32kHz */
+		.gpiomux	= { 0, 0, 0x000, 0x100},
 		.pll            = PLL_28,
 		.tuner_type     = UNSET,
 		.tuner_addr     = ADDR_UNSET,
@@ -2848,7 +2886,7 @@
 		.gpiomute 	= 1,
 		.needs_tvaudio	= 1,
 		.pll		= PLL_28,
-		.tuner_type	= 2,
+		.tuner_type	= TUNER_PHILIPS_NTSC,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -2875,14 +2913,14 @@
 		.name		= "Hauppauge ImpactVCB (bt878)",
 		.video_inputs	= 4,
 		.audio_inputs	= 0,
-		.tuner		= -1,
-		.svhs		= -1,
+		.tuner		= UNSET,
+		.svhs		= UNSET,
 		.gpiomask	= 0x0f, /* old: 7 */
 		.muxsel		= { 0, 1, 3, 2 }, /* Composite 0-3 */
 		.no_msp34xx	= 1,
 		.no_tda9875     = 1,
 		.no_tda7432     = 1,
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -2914,10 +2952,10 @@
 		.name		= "SSAI Security Video Interface",
 		.video_inputs	= 4,
 		.audio_inputs	= 0,
-		.tuner		= -1,
-		.svhs		= -1,
+		.tuner		= UNSET,
+		.svhs		= UNSET,
 		.muxsel		= { 0, 1, 2, 3 },
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
@@ -2925,13 +2963,48 @@
 		.name		= "SSAI Ultrasound Video Interface",
 		.video_inputs	= 2,
 		.audio_inputs	= 0,
-		.tuner		= -1,
+		.tuner		= UNSET,
 		.svhs		= 1,
 		.muxsel		= { 2, 0, 1, 3 },
-		.tuner_type	= -1,
+		.tuner_type	= UNSET,
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 	},
+	/* ---- card 0x94---------------------------------- */
+	[BTTV_BOARD_DVICO_FUSIONHDTV_2] = {
+		.name           = "DViCO FusionHDTV 2",
+		.tuner          = 0,
+		.tuner_type     = TUNER_PHILIPS_ATSC, /* FCV1236D */
+		.tuner_addr	= ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.svhs           = 2,
+		.muxsel		= { 2, 3, 1 },
+		.gpiomask       = 0x00e00007,
+		.gpiomux        = { 0x00400005, 0, 0x00000001, 0 },
+		.gpiomute 	= 0x00c00007,
+		.no_msp34xx     = 1,
+		.no_tda9875     = 1,
+		.no_tda7432     = 1,
+	},
+	/* ---- card 0x95---------------------------------- */
+	[BTTV_BOARD_TYPHOON_TVTUNERPCI] = {
+		.name           = "Typhoon TV-Tuner PCI (50684)",
+		.video_inputs   = 3,
+		.audio_inputs   = 1,
+		.tuner          = 0,
+		.svhs           = 2,
+		.gpiomask       = 0x3014f,
+		.muxsel         = { 2, 3, 1, 1 },
+		.gpiomux        = { 0x20001,0x10001, 0, 0 },
+		.gpiomute       = 10,
+		.needs_tvaudio  = 1,
+		.pll            = PLL_28,
+		.tuner_type     = TUNER_PHILIPS_PAL_I,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+	},
 };
 
 static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3040,7 +3113,7 @@
 static void flyvideo_gpio(struct bttv *btv)
 {
 	int gpio,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821;
-	int tuner=-1,ttype;
+	int tuner=UNSET,ttype;
 
 	gpio_inout(0xffffff, 0);
 	udelay(8);  /* without this we would see the 0x1800 mask */
@@ -3085,7 +3158,7 @@
 	 * gpio & 0x001000    output bit for audio routing */
 
 	if(is_capture_only)
-		tuner=4; /* No tuner present */
+		tuner = TUNER_ABSENT; /* No tuner present */
 
 	printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n",
 	       btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio);
@@ -3093,7 +3166,7 @@
 		btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ",
 		is_capture_only?"yes":"no ");
 
-	if(tuner!= -1) /* only set if known tuner autodetected, else let insmod option through */
+	if (tuner != UNSET) /* only set if known tuner autodetected, else let insmod option through */
 		btv->tuner_type = tuner;
 	btv->has_radio = has_radio;
 
@@ -3219,15 +3292,15 @@
 	btaor((2)<<5, ~(3<<5), BT848_IFORM);
 	gpio_bits(3,bttv_tvcards[btv->c.type].muxsel[input&7]);
 
-       /* composite */
-       /* set chroma ADC to sleep */
-       btor(BT848_ADC_C_SLEEP, BT848_ADC);
-       /* set to composite video */
-       btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
-       btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
+	/* composite */
+	/* set chroma ADC to sleep */
+	btor(BT848_ADC_C_SLEEP, BT848_ADC);
+	/* set to composite video */
+	btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
+	btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
 
-       /* switch sync drive off */
-       gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE);
+	/* switch sync drive off */
+	gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE);
 }
 
 static void gvc1100_muxsel(struct bttv *btv, unsigned int input)
@@ -3302,6 +3375,7 @@
 	case BTTV_BOARD_HAUPPAUGE878:
 		boot_msp34xx(btv,5);
 		break;
+	case BTTV_BOARD_VOODOOTV_200:
 	case BTTV_BOARD_VOODOOTV_FM:
 		boot_msp34xx(btv,20);
 		break;
@@ -3328,10 +3402,9 @@
 /* initialization part two -- after registering i2c bus */
 void __devinit bttv_init_card2(struct bttv *btv)
 {
-	int tda9887;
 	int addr=ADDR_UNSET;
 
-	btv->tuner_type = -1;
+	btv->tuner_type = UNSET;
 
 	if (BTTV_BOARD_UNKNOWN == btv->c.type) {
 		bttv_readee(btv,eeprom_data,0xa0);
@@ -3396,7 +3469,7 @@
 			printk("bttv%d: radio detected by subsystem id (CPH05x)\n",btv->c.nr);
 		}
 		break;
-       case BTTV_BOARD_STB2:
+	case BTTV_BOARD_STB2:
 		if (btv->cardid == 0x3060121a) {
 			/* Fix up entry for 3DFX VoodooTV 100,
 			   which is an OEM STB card variant. */
@@ -3412,11 +3485,12 @@
 	case BTTV_BOARD_OSPREY2xx:
 	case BTTV_BOARD_OSPREY2x0_SVID:
 	case BTTV_BOARD_OSPREY2x0:
+	case BTTV_BOARD_OSPREY440:
 	case BTTV_BOARD_OSPREY500:
 	case BTTV_BOARD_OSPREY540:
 	case BTTV_BOARD_OSPREY2000:
 		bttv_readee(btv,eeprom_data,0xa0);
-		osprey_eeprom(btv);
+		osprey_eeprom(btv, eeprom_data);
 		break;
 	case BTTV_BOARD_IDS_EAGLE:
 		init_ids_eagle(btv);
@@ -3479,7 +3553,15 @@
 			btv->tuner_type = bttv_tvcards[btv->c.type].tuner_type;
 	if (UNSET != tuner[btv->c.nr])
 		btv->tuner_type = tuner[btv->c.nr];
-	printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type);
+
+	if (btv->tuner_type == TUNER_ABSENT ||
+	    bttv_tvcards[btv->c.type].tuner == UNSET)
+		printk(KERN_INFO "bttv%d: tuner absent\n", btv->c.nr);
+	else if(btv->tuner_type == UNSET)
+		printk(KERN_WARNING "bttv%d: tuner type unset\n", btv->c.nr);
+	else
+		printk(KERN_INFO "bttv%d: tuner type=%d\n", btv->c.nr,
+		       btv->tuner_type);
 
 	if (btv->tuner_type != UNSET) {
 		struct tuner_setup tun_setup;
@@ -3521,6 +3603,9 @@
 	if (!autoload)
 		return;
 
+	if (bttv_tvcards[btv->c.type].tuner == UNSET)
+		return;  /* no tuner or related drivers to load */
+
 	/* try to detect audio/fader chips */
 	if (!bttv_tvcards[btv->c.type].no_msp34xx &&
 	    bttv_I2CRead(btv, I2C_ADDR_MSP3400, "MSP34xx") >=0)
@@ -3541,17 +3626,7 @@
 	if (bttv_tvcards[btv->c.type].needs_tvaudio)
 		request_module("tvaudio");
 
-	/* tuner modules */
-	tda9887 = 0;
-	if (btv->tda9887_conf)
-		tda9887 = 1;
-	if (0 == tda9887 && 0 == bttv_tvcards[btv->c.type].has_dvb &&
-	    bttv_I2CRead(btv, I2C_ADDR_TDA9887, "TDA9887") >=0)
-		tda9887 = 1;
-	/* Hybrid DVB card, DOES have a tda9887 */
-	if (btv->c.type == BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE)
-		tda9887 = 1;
-	if (btv->tuner_type != UNSET)
+	if (btv->tuner_type != UNSET && btv->tuner_type != TUNER_ABSENT)
 		request_module("tuner");
 }
 
@@ -3706,106 +3781,119 @@
 /* ----------------------------------------------------------------------- */
 /* some osprey specific stuff                                              */
 
-static void __devinit osprey_eeprom(struct bttv *btv)
+static void __devinit osprey_eeprom(struct bttv *btv, const u8 ee[256])
 {
-       int i = 0;
-       unsigned char *ee = eeprom_data;
-       unsigned long serial = 0;
+	int i;
+	u32 serial = 0;
+	int cardid = -1;
 
-       if (btv->c.type == 0) {
-	       /* this might be an antique... check for MMAC label in eeprom */
-	       if ((ee[0]=='M') && (ee[1]=='M') && (ee[2]=='A') && (ee[3]=='C')) {
-		       unsigned char checksum = 0;
-		       for (i = 0; i < 21; i++)
-			       checksum += ee[i];
-		       if (checksum != ee[21])
-			       return;
-		       btv->c.type = BTTV_BOARD_OSPREY1x0_848;
-		       for (i = 12; i < 21; i++)
-			       serial *= 10, serial += ee[i] - '0';
-	       }
-       } else {
-	       unsigned short type;
-	       int offset = 4*16;
+	/* This code will nevery actually get called in this case.... */
+	if (btv->c.type == BTTV_BOARD_UNKNOWN) {
+		/* this might be an antique... check for MMAC label in eeprom */
+		if (!strncmp(ee, "MMAC", 4)) {
+			u8 checksum = 0;
+			for (i = 0; i < 21; i++)
+				checksum += ee[i];
+			if (checksum != ee[21])
+				return;
+			cardid = BTTV_BOARD_OSPREY1x0_848;
+			for (i = 12; i < 21; i++)
+				serial *= 10, serial += ee[i] - '0';
+		}
+	} else {
+		unsigned short type;
 
-	       for (; offset < 8*16; offset += 16) {
-		       unsigned short checksum = 0;
-		       /* verify the checksum */
-		       for (i = 0; i < 14; i++)
-				checksum += ee[i+offset];
-			checksum = ~checksum;  /* no idea why */
-			if ((((checksum>>8)&0x0FF) == ee[offset+14]) &&
-				   ((checksum & 0x0FF) == ee[offset+15])) {
-			       break;
-		       }
-	       }
+		for (i = 4*16; i < 8*16; i += 16) {
+			u16 checksum = ip_compute_csum(ee + i, 16);
 
-	       if (offset >= 8*16)
-		       return;
+			if ((checksum&0xff) + (checksum>>8) == 0xff)
+				break;
+		}
+		if (i >= 8*16)
+			return;
+		ee += i;
 
-	       /* found a valid descriptor */
-	       type = (ee[offset+4]<<8) | (ee[offset+5]);
+		/* found a valid descriptor */
+		type = be16_to_cpup((u16*)(ee+4));
 
-	       switch(type) {
-	       /* 848 based */
-	       case 0x0004:
-		       btv->c.type = BTTV_BOARD_OSPREY1x0_848;
-		       break;
-	       case 0x0005:
-		       btv->c.type = BTTV_BOARD_OSPREY101_848;
-		       break;
+		switch(type) {
+		/* 848 based */
+		case 0x0004:
+			cardid = BTTV_BOARD_OSPREY1x0_848;
+			break;
+		case 0x0005:
+			cardid = BTTV_BOARD_OSPREY101_848;
+			break;
 
-	       /* 878 based */
-	       case 0x0012:
-	       case 0x0013:
-		       btv->c.type = BTTV_BOARD_OSPREY1x0;
-		       break;
-	       case 0x0014:
-	       case 0x0015:
-		       btv->c.type = BTTV_BOARD_OSPREY1x1;
-		       break;
-	       case 0x0016:
-	       case 0x0017:
-	       case 0x0020:
-		       btv->c.type = BTTV_BOARD_OSPREY1x1_SVID;
-		       break;
-	       case 0x0018:
-	       case 0x0019:
-	       case 0x001E:
-	       case 0x001F:
-		       btv->c.type = BTTV_BOARD_OSPREY2xx;
-		       break;
-	       case 0x001A:
-	       case 0x001B:
-		       btv->c.type = BTTV_BOARD_OSPREY2x0_SVID;
-		       break;
-	       case 0x0040:
-		       btv->c.type = BTTV_BOARD_OSPREY500;
-		       break;
-	       case 0x0050:
-	       case 0x0056:
-		       btv->c.type = BTTV_BOARD_OSPREY540;
-		       /* bttv_osprey_540_init(btv); */
-		       break;
-	       case 0x0060:
-	       case 0x0070:
-	       case 0x00A0:
-		       btv->c.type = BTTV_BOARD_OSPREY2x0;
-		       /* enable output on select control lines */
-		       gpio_inout(0xffffff,0x000303);
-		       break;
-	       default:
-		       /* unknown...leave generic, but get serial # */
-		       break;
-	       }
-	       serial =  (ee[offset+6] << 24)
-		       | (ee[offset+7] << 16)
-		       | (ee[offset+8] <<  8)
-		       | (ee[offset+9]);
-       }
+		/* 878 based */
+		case 0x0012:
+		case 0x0013:
+			cardid = BTTV_BOARD_OSPREY1x0;
+			break;
+		case 0x0014:
+		case 0x0015:
+			cardid = BTTV_BOARD_OSPREY1x1;
+			break;
+		case 0x0016:
+		case 0x0017:
+		case 0x0020:
+			cardid = BTTV_BOARD_OSPREY1x1_SVID;
+			break;
+		case 0x0018:
+		case 0x0019:
+		case 0x001E:
+		case 0x001F:
+			cardid = BTTV_BOARD_OSPREY2xx;
+			break;
+		case 0x001A:
+		case 0x001B:
+			cardid = BTTV_BOARD_OSPREY2x0_SVID;
+			break;
+		case 0x0040:
+			cardid = BTTV_BOARD_OSPREY500;
+			break;
+		case 0x0050:
+		case 0x0056:
+			cardid = BTTV_BOARD_OSPREY540;
+			/* bttv_osprey_540_init(btv); */
+			break;
+		case 0x0060:
+		case 0x0070:
+		case 0x00A0:
+			cardid = BTTV_BOARD_OSPREY2x0;
+			/* enable output on select control lines */
+			gpio_inout(0xffffff,0x000303);
+			break;
+		case 0x00D8:
+			cardid = BTTV_BOARD_OSPREY440;
+			break;
+		default:
+			/* unknown...leave generic, but get serial # */
+			printk(KERN_INFO "bttv%d: "
+			       "osprey eeprom: unknown card type 0x%04x\n",
+			       btv->c.nr, type);
+			break;
+		}
+		serial = be32_to_cpup((u32*)(ee+6));
+	}
 
-       printk(KERN_INFO "bttv%d: osprey eeprom: card=%d name=%s serial=%ld\n",
-	      btv->c.nr, btv->c.type, bttv_tvcards[btv->c.type].name,serial);
+	printk(KERN_INFO "bttv%d: osprey eeprom: card=%d '%s' serial=%u\n",
+	       btv->c.nr, cardid,
+	       cardid>0 ? bttv_tvcards[cardid].name : "Unknown", serial);
+
+	if (cardid<0 || btv->c.type == cardid)
+		return;
+
+	/* card type isn't set correctly */
+	if (card[btv->c.nr] < bttv_num_tvcards) {
+		printk(KERN_WARNING "bttv%d: osprey eeprom: "
+		       "Not overriding user specified card type\n", btv->c.nr);
+	} else {
+		printk(KERN_INFO "bttv%d: osprey eeprom: "
+		       "Changing card type from %d to %d\n", btv->c.nr,
+		       btv->c.type, cardid);
+		btv->c.type = cardid;
+	}
 }
 
 /* ----------------------------------------------------------------------- */
@@ -3865,11 +3953,15 @@
 	if(norm==VIDEO_MODE_NTSC) {
 		bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
 		bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x957fff;
+		bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x957fff;
+		bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x957fff;
 		dprintk("bttv_tda9880_setnorm to NTSC\n");
 	}
 	else {
 		bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff;
 		bttv_tvcards[BTTV_BOARD_VOODOOTV_FM].gpiomute=0x947fff;
+		bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomux[TVAUDIO_INPUT_TUNER]=0x947fff;
+		bttv_tvcards[BTTV_BOARD_VOODOOTV_200].gpiomute=0x947fff;
 		dprintk("bttv_tda9880_setnorm to PAL\n");
 	}
 	/* set GPIO according */
@@ -4163,7 +4255,7 @@
 	bus_low(btv,btv->mbox_clk);
 
 	udelay(10);
-	timeout= jiffies + HZ;
+	timeout= jiffies + msecs_to_jiffies(1000);
 
 	/* wait for DATA line to go low; error if it doesn't */
 	while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout))
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index b1fedb0..7a332b3 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -30,7 +30,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
@@ -155,13 +154,14 @@
 /* ----------------------------------------------------------------------- */
 /* sysfs                                                                   */
 
-static ssize_t show_card(struct class_device *cd, char *buf)
+static ssize_t show_card(struct device *cd,
+			 struct device_attribute *attr, char *buf)
 {
 	struct video_device *vfd = to_video_device(cd);
 	struct bttv *btv = dev_get_drvdata(vfd->dev);
 	return sprintf(buf, "%d\n", btv ? btv->c.type : UNSET);
 }
-static CLASS_DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
+static DEVICE_ATTR(card, S_IRUGO, show_card, NULL);
 
 /* ----------------------------------------------------------------------- */
 /* dvb auto-load setup                                                     */
@@ -1218,7 +1218,14 @@
 			break;
 		case TVAUDIO_INPUT_TUNER:
 		default:
-			route.input = MSP_INPUT_DEFAULT;
+			/* This is the only card that uses TUNER2, and afaik,
+			   is the only difference between the VOODOOTV_FM
+			   and VOODOOTV_200 */
+			if (btv->c.type == BTTV_BOARD_VOODOOTV_200)
+				route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER2, \
+					MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER);
+			else
+				route.input = MSP_INPUT_DEFAULT;
 			break;
 		}
 		route.output = MSP_OUTPUT_DEFAULT;
@@ -1253,7 +1260,7 @@
 	v4l2_std_id std = bttv_tvnorms[btv->tvnorm].v4l2_id;
 
 	bttv_call_i2c_clients(btv, VIDIOC_S_STD, &std);
-	if (btv->c.type == BTTV_BOARD_VOODOOTV_FM)
+	if (btv->c.type == BTTV_BOARD_VOODOOTV_FM || btv->c.type == BTTV_BOARD_VOODOOTV_200)
 		bttv_tda9880_setnorm(btv,btv->tvnorm);
 }
 
@@ -1323,6 +1330,7 @@
 
 	switch (btv->c.type) {
 	case BTTV_BOARD_VOODOOTV_FM:
+	case BTTV_BOARD_VOODOOTV_200:
 		bttv_tda9880_setnorm(btv,norm);
 		break;
 	}
@@ -2251,6 +2259,24 @@
 		printk(KERN_INFO "bttv%d: ==================  END STATUS CARD #%d  ==================\n", btv->c.nr, btv->c.nr);
 		return 0;
 	}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	case VIDIOC_DBG_G_REGISTER:
+	case VIDIOC_DBG_S_REGISTER:
+	{
+		struct v4l2_register *reg = arg;
+		if (!capable(CAP_SYS_ADMIN))
+			return -EPERM;
+		if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+			return -EINVAL;
+		/* bt848 has a 12-bit register space */
+		reg->reg &= 0xfff;
+		if (cmd == VIDIOC_DBG_G_REGISTER)
+			reg->val = btread(reg->reg);
+		else
+			btwrite(reg->val, reg->reg);
+		return 0;
+	}
+#endif
 
 	default:
 		return -ENOIOCTLCMD;
@@ -2557,7 +2583,7 @@
 	if (check_btres(fh, RESOURCE_OVERLAY)) {
 		struct bttv_buffer *new;
 
-		new = videobuf_alloc(sizeof(*new));
+		new = videobuf_pci_alloc(sizeof(*new));
 		new->crop = btv->crop[!!fh->do_crop].rect;
 		bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
 		retval = bttv_switch_overlay(btv,fh,new);
@@ -3023,7 +3049,7 @@
 		mutex_lock(&fh->cap.lock);
 		if (*on) {
 			fh->ov.tvnorm = btv->tvnorm;
-			new = videobuf_alloc(sizeof(*new));
+			new = videobuf_pci_alloc(sizeof(*new));
 			new->crop = btv->crop[!!fh->do_crop].rect;
 			bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
 		} else {
@@ -3046,6 +3072,8 @@
 					     V4L2_MEMORY_MMAP);
 		if (retval < 0)
 			goto fh_unlock_and_return;
+
+		gbuffers = retval;
 		memset(mbuf,0,sizeof(*mbuf));
 		mbuf->frames = gbuffers;
 		mbuf->size   = gbuffers * gbufsize;
@@ -3116,9 +3144,12 @@
 			retval = -EIO;
 			/* fall through */
 		case STATE_DONE:
-			videobuf_dma_sync(&fh->cap,&buf->vb.dma);
+		{
+			struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+			videobuf_dma_sync(&fh->cap,dma);
 			bttv_dma_free(&fh->cap,btv,buf);
 			break;
+		}
 		default:
 			retval = -EINVAL;
 			break;
@@ -3312,7 +3343,7 @@
 			if (check_btres(fh, RESOURCE_OVERLAY)) {
 				struct bttv_buffer *new;
 
-				new = videobuf_alloc(sizeof(*new));
+				new = videobuf_pci_alloc(sizeof(*new));
 				new->crop = btv->crop[!!fh->do_crop].rect;
 				bttv_overlay_risc(btv,&fh->ov,fh->ovfmt,new);
 				retval = bttv_switch_overlay(btv,fh,new);
@@ -3561,6 +3592,8 @@
 	case VIDIOC_G_FREQUENCY:
 	case VIDIOC_S_FREQUENCY:
 	case VIDIOC_LOG_STATUS:
+	case VIDIOC_DBG_G_REGISTER:
+	case VIDIOC_DBG_S_REGISTER:
 		return bttv_common_ioctls(btv,cmd,arg);
 
 	default:
@@ -3669,7 +3702,7 @@
 				mutex_unlock(&fh->cap.lock);
 				return POLLERR;
 			}
-			fh->cap.read_buf = videobuf_alloc(fh->cap.msize);
+			fh->cap.read_buf = videobuf_pci_alloc(fh->cap.msize);
 			if (NULL == fh->cap.read_buf) {
 				mutex_unlock(&fh->cap.lock);
 				return POLLERR;
@@ -3736,13 +3769,13 @@
 	fh->ov.setup_ok = 0;
 	v4l2_prio_open(&btv->prio,&fh->prio);
 
-	videobuf_queue_init(&fh->cap, &bttv_video_qops,
+	videobuf_queue_pci_init(&fh->cap, &bttv_video_qops,
 			    btv->c.pci, &btv->s_lock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_INTERLACED,
 			    sizeof(struct bttv_buffer),
 			    fh);
-	videobuf_queue_init(&fh->vbi, &bttv_vbi_qops,
+	videobuf_queue_pci_init(&fh->vbi, &bttv_vbi_qops,
 			    btv->c.pci, &btv->s_lock,
 			    V4L2_BUF_TYPE_VBI_CAPTURE,
 			    V4L2_FIELD_SEQ_TB,
@@ -3943,6 +3976,8 @@
 	case VIDIOCGAUDIO:
 	case VIDIOCSAUDIO:
 	case VIDIOC_LOG_STATUS:
+	case VIDIOC_DBG_G_REGISTER:
+	case VIDIOC_DBG_S_REGISTER:
 		return bttv_common_ioctls(btv,cmd,arg);
 
 	default:
@@ -4583,9 +4618,9 @@
 		goto err;
 	printk(KERN_INFO "bttv%d: registered device video%d\n",
 	       btv->c.nr,btv->video_dev->minor & 0x1f);
-	if (class_device_create_file(&btv->video_dev->class_dev,
-				     &class_device_attr_card)<0) {
-		printk(KERN_ERR "bttv%d: class_device_create_file 'card' "
+	if (device_create_file(&btv->video_dev->class_dev,
+				     &dev_attr_card)<0) {
+		printk(KERN_ERR "bttv%d: device_create_file 'card' "
 		       "failed\n", btv->c.nr);
 		goto err;
 	}
diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c
index 84154c2..dce6dae 100644
--- a/drivers/media/video/bt8xx/bttv-gpio.c
+++ b/drivers/media/video/bt8xx/bttv-gpio.c
@@ -106,11 +106,9 @@
 
 int bttv_sub_del_devices(struct bttv_core *core)
 {
-	struct bttv_sub_device *sub;
-	struct list_head *item,*save;
+	struct bttv_sub_device *sub, *save;
 
-	list_for_each_safe(item,save,&core->subs) {
-		sub = list_entry(item,struct bttv_sub_device,list);
+	list_for_each_entry_safe(sub, save, &core->subs, list) {
 		list_del(&sub->list);
 		device_unregister(&sub->dev);
 	}
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
index 0dfa49b..844f176 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/video/bt8xx/bttv-i2c.c
@@ -28,7 +28,6 @@
 */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index 6f74c80..e7c521b 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -19,7 +19,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -153,7 +152,7 @@
 {
 	if (ir->polling) {
 		setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv);
-		ir->timer.expires  = jiffies + HZ;
+		ir->timer.expires  = jiffies + msecs_to_jiffies(1000);
 		add_timer(&ir->timer);
 	} else if (ir->rc5_gpio) {
 		/* set timer_end for code completion */
@@ -313,7 +312,7 @@
 		input_dev->id.vendor  = btv->c.pci->vendor;
 		input_dev->id.product = btv->c.pci->device;
 	}
-	input_dev->cdev.dev = &btv->c.pci->dev;
+	input_dev->dev.parent = &btv->c.pci->dev;
 
 	btv->remote = ir;
 	bttv_ir_start(btv, ir);
diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
index e7104d9..58986f1 100644
--- a/drivers/media/video/bt8xx/bttv-risc.c
+++ b/drivers/media/video/bt8xx/bttv-risc.c
@@ -574,10 +574,12 @@
 void
 bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf)
 {
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
 	BUG_ON(in_interrupt());
 	videobuf_waiton(&buf->vb,0,0);
-	videobuf_dma_unmap(q, &buf->vb.dma);
-	videobuf_dma_free(&buf->vb.dma);
+	videobuf_dma_unmap(q, dma);
+	videobuf_dma_free(dma);
 	btcx_riscmem_free(btv->c.pci,&buf->bottom);
 	btcx_riscmem_free(btv->c.pci,&buf->top);
 	buf->vb.state = STATE_NEEDS_INIT;
@@ -699,6 +701,7 @@
 bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
 {
 	const struct bttv_tvnorm *tvnorm = bttv_tvnorms + buf->tvnorm;
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
 	dprintk(KERN_DEBUG
 		"bttv%d: buffer field: %s  format: %s  size: %dx%d\n",
@@ -716,25 +719,25 @@
 
 		switch (buf->vb.field) {
 		case V4L2_FIELD_TOP:
-			bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
+			bttv_risc_packed(btv,&buf->top,dma->sglist,
 					 /* offset */ 0,bpl,
 					 /* padding */ 0,/* skip_lines */ 0,
 					 buf->vb.height);
 			break;
 		case V4L2_FIELD_BOTTOM:
-			bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
+			bttv_risc_packed(btv,&buf->bottom,dma->sglist,
 					 0,bpl,0,0,buf->vb.height);
 			break;
 		case V4L2_FIELD_INTERLACED:
-			bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
+			bttv_risc_packed(btv,&buf->top,dma->sglist,
 					 0,bpl,bpl,0,buf->vb.height >> 1);
-			bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
+			bttv_risc_packed(btv,&buf->bottom,dma->sglist,
 					 bpl,bpl,bpl,0,buf->vb.height >> 1);
 			break;
 		case V4L2_FIELD_SEQ_TB:
-			bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
+			bttv_risc_packed(btv,&buf->top,dma->sglist,
 					 0,bpl,0,0,buf->vb.height >> 1);
-			bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
+			bttv_risc_packed(btv,&buf->bottom,dma->sglist,
 					 bpf,bpl,0,0,buf->vb.height >> 1);
 			break;
 		default:
@@ -767,7 +770,7 @@
 			bttv_calc_geo(btv,&buf->geo,buf->vb.width,
 				      buf->vb.height,/* both_fields */ 0,
 				      tvnorm,&buf->crop);
-			bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist,
+			bttv_risc_planar(btv, &buf->top, dma->sglist,
 					 0,buf->vb.width,0,buf->vb.height,
 					 uoffset,voffset,buf->fmt->hshift,
 					 buf->fmt->vshift,0);
@@ -776,7 +779,7 @@
 			bttv_calc_geo(btv,&buf->geo,buf->vb.width,
 				      buf->vb.height,0,
 				      tvnorm,&buf->crop);
-			bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist,
+			bttv_risc_planar(btv, &buf->bottom, dma->sglist,
 					 0,buf->vb.width,0,buf->vb.height,
 					 uoffset,voffset,buf->fmt->hshift,
 					 buf->fmt->vshift,0);
@@ -789,14 +792,14 @@
 			ypadding = buf->vb.width;
 			cpadding = buf->vb.width >> buf->fmt->hshift;
 			bttv_risc_planar(btv,&buf->top,
-					 buf->vb.dma.sglist,
+					 dma->sglist,
 					 0,buf->vb.width,ypadding,lines,
 					 uoffset,voffset,
 					 buf->fmt->hshift,
 					 buf->fmt->vshift,
 					 cpadding);
 			bttv_risc_planar(btv,&buf->bottom,
-					 buf->vb.dma.sglist,
+					 dma->sglist,
 					 ypadding,buf->vb.width,ypadding,lines,
 					 uoffset+cpadding,
 					 voffset+cpadding,
@@ -812,7 +815,7 @@
 			ypadding = buf->vb.width;
 			cpadding = buf->vb.width >> buf->fmt->hshift;
 			bttv_risc_planar(btv,&buf->top,
-					 buf->vb.dma.sglist,
+					 dma->sglist,
 					 0,buf->vb.width,0,lines,
 					 uoffset >> 1,
 					 voffset >> 1,
@@ -820,7 +823,7 @@
 					 buf->fmt->vshift,
 					 0);
 			bttv_risc_planar(btv,&buf->bottom,
-					 buf->vb.dma.sglist,
+					 dma->sglist,
 					 lines * ypadding,buf->vb.width,0,lines,
 					 lines * ypadding + (uoffset >> 1),
 					 lines * ypadding + (voffset >> 1),
@@ -839,10 +842,10 @@
 		buf->vb.field = V4L2_FIELD_SEQ_TB;
 		bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
 			      1,tvnorm,&buf->crop);
-		bttv_risc_packed(btv, &buf->top,  buf->vb.dma.sglist,
+		bttv_risc_packed(btv, &buf->top,  dma->sglist,
 				 /* offset */ 0, RAW_BPL, /* padding */ 0,
 				 /* skip_lines */ 0, RAW_LINES);
-		bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
+		bttv_risc_packed(btv, &buf->bottom, dma->sglist,
 				 buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
 	}
 
diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c
index 93e35de..346ce01 100644
--- a/drivers/media/video/bt8xx/bttv-vbi.c
+++ b/drivers/media/video/bt8xx/bttv-vbi.c
@@ -24,7 +24,6 @@
 */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
@@ -151,13 +150,14 @@
 
 	if (redo_dma_risc) {
 		unsigned int bpl, padding, offset;
+		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
 		bpl = 2044; /* max. vbipack */
 		padding = VBI_BPL - bpl;
 
 		if (fh->vbi_fmt.fmt.count[0] > 0) {
 			rc = bttv_risc_packed(btv, &buf->top,
-					      buf->vb.dma.sglist,
+					      dma->sglist,
 					      /* offset */ 0, bpl,
 					      padding, skip_lines0,
 					      fh->vbi_fmt.fmt.count[0]);
@@ -169,7 +169,7 @@
 			offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL;
 
 			rc = bttv_risc_packed(btv, &buf->bottom,
-					      buf->vb.dma.sglist,
+					      dma->sglist,
 					      offset, bpl,
 					      padding, skip_lines1,
 					      fh->vbi_fmt.fmt.count[1]);
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index f821ba6..19e75d5 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -170,6 +170,10 @@
 #define BTTV_BOARD_MACHTV_MAGICTV          0x90
 #define BTTV_BOARD_SSAI_SECURITY	   0x91
 #define BTTV_BOARD_SSAI_ULTRASOUND	   0x92
+#define BTTV_BOARD_VOODOOTV_200		   0x93
+#define BTTV_BOARD_DVICO_FUSIONHDTV_2	   0x94
+#define BTTV_BOARD_TYPHOON_TVTUNERPCI	   0x95
+
 
 /* more card-specific defines */
 #define PT2254_L_CHANNEL 0x10
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index 8f44f02..0b92c35 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -33,15 +33,15 @@
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/videodev.h>
-#include <media/v4l2-common.h>
 #include <linux/pci.h>
 #include <linux/input.h>
 #include <linux/mutex.h>
 #include <asm/scatterlist.h>
 #include <asm/io.h>
+#include <media/v4l2-common.h>
 
 #include <linux/device.h>
-#include <media/video-buf.h>
+#include <media/videobuf-dma-sg.h>
 #include <media/tuner.h>
 #include <media/tveeprom.h>
 #include <media/ir-common.h>
@@ -284,8 +284,8 @@
 #define d2printk if (bttv_debug >= 2) printk
 
 #define BTTV_MAX_FBUF   0x208000
-#define BTTV_TIMEOUT    (HZ/2) /* 0.5 seconds */
-#define BTTV_FREE_IDLE  (HZ)   /* one second */
+#define BTTV_TIMEOUT    msecs_to_jiffies(500)    /* 0.5 seconds */
+#define BTTV_FREE_IDLE  msecs_to_jiffies(1000)   /* one second */
 
 
 struct bttv_pll_info {
diff --git a/drivers/media/video/btcx-risc.c b/drivers/media/video/btcx-risc.c
index b4aca72..ce0840c 100644
--- a/drivers/media/video/btcx-risc.c
+++ b/drivers/media/video/btcx-risc.c
@@ -23,7 +23,6 @@
 */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 7d47cbe..7f7e3d3 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -104,6 +104,17 @@
 
 static inline void write_lpcontrol(struct qcam_device *q, int d)
 {
+	if (d & 0x20) {
+		/* Set bidirectional mode to reverse (data in) */
+		parport_data_reverse(q->pport);
+	} else {
+		/* Set bidirectional mode to forward (data out) */
+		parport_data_forward(q->pport);
+	}
+
+	/* Now issue the regular port command, but strip out the
+	 * direction flag */
+	d &= ~0x20;
 	parport_write_control(q->pport, d);
 }
 
@@ -344,10 +355,13 @@
 	/* Be (even more) liberal in what you accept...  */
 
 /*	if (count > 30 && count < 200) */
-	if (count > 20 && count < 300)
+	if (count > 20 && count < 400) {
 		return 1;	/* found */
-	else
+	} else {
+		printk(KERN_ERR "No Quickcam found on port %s\n",
+			q->pport->name);
 		return 0;	/* not found */
+	}
 }
 
 
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 925ff17..f76c6a6 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -95,7 +95,7 @@
 	unsigned long oldjiffies = jiffies;
 	unsigned int i;
 
-	for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )
+	for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
 		if (qcam_ready1(qcam) == value)
 			return 0;
 
@@ -120,7 +120,7 @@
 	unsigned long oldjiffies = jiffies;
 	unsigned int i;
 
-	for (oldjiffies = jiffies; (jiffies - oldjiffies) < (HZ/25); )
+	for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
 		if (qcam_ready2(qcam) == value)
 			return 0;
 
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index c08f650..b63cab3 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -14,7 +14,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/pci.h>
@@ -63,13 +62,13 @@
  */
 
 #define MAX_DMA_BUFS 3
-static int alloc_bufs_at_load = 0;
-module_param(alloc_bufs_at_load, bool, 0444);
-MODULE_PARM_DESC(alloc_bufs_at_load,
-		"Non-zero value causes DMA buffers to be allocated at module "
-		"load time.  This increases the chances of successfully getting "
-		"those buffers, but at the cost of nailing down the memory from "
-		"the outset.");
+static int alloc_bufs_at_read = 0;
+module_param(alloc_bufs_at_read, bool, 0444);
+MODULE_PARM_DESC(alloc_bufs_at_read,
+		"Non-zero value causes DMA buffers to be allocated when the "
+		"video capture device is read, rather than at module load "
+		"time.  This saves memory, but decreases the chances of "
+		"successfully getting those buffers.");
 
 static int n_dma_bufs = 3;
 module_param(n_dma_bufs, uint, 0644);
@@ -356,6 +355,7 @@
 {
 	unsigned int rval;
 	unsigned long flags;
+	DEFINE_WAIT(the_wait);
 
 	spin_lock_irqsave(&cam->dev_lock, flags);
 	rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
@@ -369,10 +369,29 @@
 	rval = value | ((command << TWSIC1_ADDR_SHIFT) & TWSIC1_ADDR);
 	cafe_reg_write(cam, REG_TWSIC1, rval);
 	spin_unlock_irqrestore(&cam->dev_lock, flags);
-	msleep(2); /* Required or things flake */
 
+	/*
+	 * Time to wait for the write to complete.  THIS IS A RACY
+	 * WAY TO DO IT, but the sad fact is that reading the TWSIC1
+	 * register too quickly after starting the operation sends
+	 * the device into a place that may be kinder and better, but
+	 * which is absolutely useless for controlling the sensor.  In
+	 * practice we have plenty of time to get into our sleep state
+	 * before the interrupt hits, and the worst case is that we
+	 * time out and then see that things completed, so this seems
+	 * the best way for now.
+	 */
+	do {
+		prepare_to_wait(&cam->smbus_wait, &the_wait,
+				TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1); /* even 1 jiffy is too long */
+		finish_wait(&cam->smbus_wait, &the_wait);
+	} while (!cafe_smbus_write_done(cam));
+
+#ifdef IF_THE_CAFE_HARDWARE_WORKED_RIGHT
 	wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam),
 			CAFE_SMBUS_TIMEOUT);
+#endif
 	spin_lock_irqsave(&cam->dev_lock, flags);
 	rval = cafe_reg_read(cam, REG_TWSIC1);
 	spin_unlock_irqrestore(&cam->dev_lock, flags);
@@ -710,7 +729,7 @@
 	 * Here we must wait a bit for the controller to come around.
 	 */
 	spin_unlock_irqrestore(&cam->dev_lock, flags);
-	mdelay(5);	/* FIXME revisit this */
+	msleep(5);
 	spin_lock_irqsave(&cam->dev_lock, flags);
 
 	cafe_reg_write(cam, REG_GL_CSR, GCSR_CCIC_EN|GCSR_SRC|GCSR_MRC);
@@ -1178,7 +1197,7 @@
 	buf->v4lbuf.field = V4L2_FIELD_NONE;
 	buf->v4lbuf.memory = V4L2_MEMORY_MMAP;
 	/*
-	 * Offset: must be 32-bit even on a 64-bit system.  video-buf
+	 * Offset: must be 32-bit even on a 64-bit system.  videobuf-dma-sg
 	 * just uses the length times the index, but the spec warns
 	 * against doing just that - vma merging problems.  So we
 	 * leave a gap between each pair of buffers.
@@ -1483,7 +1502,7 @@
 	}
 	if (cam->users == 0) {
 		cafe_ctlr_power_down(cam);
-		if (! alloc_bufs_at_load)
+		if (alloc_bufs_at_read)
 			cafe_free_dma_bufs(cam);
 	}
 	mutex_unlock(&cam->s_mutex);
@@ -2142,7 +2161,7 @@
 	/*
 	 * If so requested, try to get our DMA buffers now.
 	 */
-	if (alloc_bufs_at_load) {
+	if (!alloc_bufs_at_read) {
 		if (cafe_alloc_dma_bufs(cam, 1))
 			cam_warn(cam, "Unable to alloc DMA buffers at load"
 					" will try again later.");
@@ -2233,12 +2252,21 @@
 	if (ret)
 		return ret;
 	ret = pci_enable_device(pdev);
+
 	if (ret) {
 		cam_warn(cam, "Unable to re-enable device on resume!\n");
 		return ret;
 	}
 	cafe_ctlr_init(cam);
-	cafe_ctlr_power_up(cam);
+	cafe_ctlr_power_down(cam);
+
+	mutex_lock(&cam->s_mutex);
+	if (cam->users > 0) {
+		cafe_ctlr_power_up(cam);
+		__cafe_cam_reset(cam);
+	}
+	mutex_unlock(&cam->s_mutex);
+
 	set_bit(CF_CONFIG_NEEDED, &cam->flags);
 	if (cam->state == S_SPECREAD)
 		cam->state = S_IDLE;  /* Don't bother restarting */
diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c
index f065ad1..cefd138 100644
--- a/drivers/media/video/compat_ioctl32.c
+++ b/drivers/media/video/compat_ioctl32.c
@@ -848,6 +848,8 @@
 	case VIDIOCSFREQ32:
 	case VIDIOCGAUDIO:
 	case VIDIOCSAUDIO:
+	case VIDIOCGVBIFMT:
+	case VIDIOCSVBIFMT:
 #endif
 	case VIDIOC_QUERYCAP:
 	case VIDIOC_ENUM_FMT:
@@ -874,7 +876,10 @@
 	case VIDIOC_ENUMINPUT:
 	case VIDIOC_ENUMINPUT32:
 	case VIDIOC_G_CTRL:
+	case VIDIOC_S_CTRL:
 	case VIDIOC_S_CTRL32:
+	case VIDIOC_S_FREQUENCY:
+	case VIDIOC_G_FREQUENCY:
 	case VIDIOC_QUERYCTRL:
 	case VIDIOC_G_INPUT32:
 	case VIDIOC_S_INPUT32:
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index 78c9699..a1d02e5 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -28,7 +28,6 @@
 
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/vmalloc.h>
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c
index fd771c7..a76bd78 100644
--- a/drivers/media/video/cpia2/cpia2_core.c
+++ b/drivers/media/video/cpia2/cpia2_core.c
@@ -663,15 +663,13 @@
 		cpia2_send_command(cam, &cmd);
 	}
 
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(100 * HZ / 1000);	/* wait for 100 msecs */
+	schedule_timeout_interruptible(msecs_to_jiffies(100));
 
 	if (cam->params.pnp_id.device_type == DEVICE_STV_672)
 		retval = apply_vp_patch(cam);
 
 	/* wait for vp to go to sleep */
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(100 * HZ / 1000);	/* wait for 100 msecs */
+	schedule_timeout_interruptible(msecs_to_jiffies(100));
 
 	/***
 	 * If this is a 676, apply VP5 fixes before we start streaming
@@ -720,8 +718,7 @@
 	set_default_user_mode(cam);
 
 	/* Give VP time to wake up */
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(100 * HZ / 1000);	/* wait for 100 msecs */
+	schedule_timeout_interruptible(msecs_to_jiffies(100));
 
 	set_all_properties(cam);
 
@@ -2227,15 +2224,13 @@
 {
 	struct camera_data *cam;
 
-	cam = kmalloc(sizeof(*cam), GFP_KERNEL);
+	cam = kzalloc(sizeof(*cam), GFP_KERNEL);
 
 	if (!cam) {
 		ERR("couldn't kmalloc cpia2 struct\n");
 		return NULL;
 	}
 
-	/* Default everything to 0 */
-	memset(cam, 0, sizeof(struct camera_data));
 
 	cam->present = 1;
 	mutex_init(&cam->busy_lock);
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 1bda7ad..e3aaba1 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -37,7 +37,6 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/init.h>
-#include <linux/moduleparam.h>
 
 #include "cpia2.h"
 #include "cpia2dev.h"
@@ -105,7 +104,7 @@
 	{ CPIA2_VP_FRAMERATE_25,   "25 fps"   },
 	{ CPIA2_VP_FRAMERATE_30,   "30 fps"   },
 };
-#define NUM_FRAMERATE_CONTROLS (sizeof(framerate_controls)/sizeof(framerate_controls[0]))
+#define NUM_FRAMERATE_CONTROLS (ARRAY_SIZE(framerate_controls))
 
 static struct control_menu_info flicker_controls[] =
 {
@@ -113,7 +112,7 @@
 	{ FLICKER_50,    "50 Hz" },
 	{ FLICKER_60,    "60 Hz"  },
 };
-#define NUM_FLICKER_CONTROLS (sizeof(flicker_controls)/sizeof(flicker_controls[0]))
+#define NUM_FLICKER_CONTROLS (ARRAY_SIZE(flicker_controls))
 
 static struct control_menu_info lights_controls[] =
 {
@@ -122,7 +121,7 @@
 	{ 128, "Bottom"  },
 	{ 192, "Both"  },
 };
-#define NUM_LIGHTS_CONTROLS (sizeof(lights_controls)/sizeof(lights_controls[0]))
+#define NUM_LIGHTS_CONTROLS (ARRAY_SIZE(lights_controls))
 #define GPIO_LIGHTS_MASK 192
 
 static struct v4l2_queryctrl controls[] = {
@@ -235,7 +234,7 @@
 		.default_value = 0,
 	},
 };
-#define NUM_CONTROLS (sizeof(controls)/sizeof(controls[0]))
+#define NUM_CONTROLS (ARRAY_SIZE(controls))
 
 
 /******************************************************************************
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
index d73c86a..6230425 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/video/cx2341x.c
@@ -20,7 +20,6 @@
 
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -191,17 +190,21 @@
 
 /* Map the control ID to the correct field in the cx2341x_mpeg_params
    struct. Return -EINVAL if the ID is unknown, else return 0. */
-static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
+static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params, int busy,
 		struct v4l2_ext_control *ctrl)
 {
 	switch (ctrl->id) {
 	case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+		if (busy)
+			return -EBUSY;
 		params->audio_sampling_freq = ctrl->value;
 		break;
 	case V4L2_CID_MPEG_AUDIO_ENCODING:
 		params->audio_encoding = ctrl->value;
 		break;
 	case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+		if (busy)
+			return -EBUSY;
 		params->audio_l2_bitrate = ctrl->value;
 		break;
 	case V4L2_CID_MPEG_AUDIO_MODE:
@@ -246,6 +249,8 @@
 		params->video_gop_closure = ctrl->value;
 		break;
 	case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+		if (busy)
+			return -EBUSY;
 		/* MPEG-1 only allows CBR */
 		if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
 		    ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
@@ -253,9 +258,13 @@
 		params->video_bitrate_mode = ctrl->value;
 		break;
 	case V4L2_CID_MPEG_VIDEO_BITRATE:
+		if (busy)
+			return -EBUSY;
 		params->video_bitrate = ctrl->value;
 		break;
 	case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+		if (busy)
+			return -EBUSY;
 		params->video_bitrate_peak = ctrl->value;
 		break;
 	case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
@@ -268,6 +277,8 @@
 		params->video_mute_yuv = ctrl->value;
 		break;
 	case V4L2_CID_MPEG_STREAM_TYPE:
+		if (busy)
+			return -EBUSY;
 		params->stream_type = ctrl->value;
 		params->video_encoding =
 			(params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
@@ -632,7 +643,7 @@
 		(params->audio_crc << 14);
 }
 
-int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
+int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
 		  struct v4l2_ext_controls *ctrls, unsigned int cmd)
 {
 	int err = 0;
@@ -664,7 +675,7 @@
 		err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
 		if (err)
 			break;
-		err = cx2341x_set_ctrl(params, ctrl);
+		err = cx2341x_set_ctrl(params, busy, ctrl);
 		if (err)
 			break;
 	}
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
new file mode 100644
index 0000000..72004a0
--- /dev/null
+++ b/drivers/media/video/cx23885/Kconfig
@@ -0,0 +1,20 @@
+config VIDEO_CX23885
+	tristate "Conexant cx23885 (2388x successor) support"
+	depends on DVB_CORE && VIDEO_DEV && PCI && I2C
+	select I2C_ALGOBIT
+	select FW_LOADER
+	select VIDEO_BTCX
+	select VIDEO_TUNER
+	select VIDEO_TVEEPROM
+	select VIDEO_IR
+	select VIDEOBUF_DVB
+	select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE
+	select DVB_S5H1409 if !DVB_FE_CUSTOMISE
+	select DVB_PLL if !DVB_FE_CUSTOMISE
+	---help---
+	  This is a video4linux driver for Conexant 23885 based
+	  TV cards.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called cx23885
+
diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile
new file mode 100644
index 0000000..6650670
--- /dev/null
+++ b/drivers/media/video/cx23885/Makefile
@@ -0,0 +1,9 @@
+cx23885-objs	:= cx23885-cards.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o
+
+obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+
+EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
new file mode 100644
index 0000000..b9012ac
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -0,0 +1,280 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "cx23885.h"
+
+/* ------------------------------------------------------------------ */
+/* board config info                                                  */
+
+struct cx23885_board cx23885_boards[] = {
+	[CX23885_BOARD_UNKNOWN] = {
+		.name		= "UNKNOWN/GENERIC",
+		.input          = {{
+			.type   = CX23885_VMUX_COMPOSITE1,
+			.vmux   = 0,
+		},{
+			.type   = CX23885_VMUX_COMPOSITE2,
+			.vmux   = 1,
+		},{
+			.type   = CX23885_VMUX_COMPOSITE3,
+			.vmux   = 2,
+		},{
+			.type   = CX23885_VMUX_COMPOSITE4,
+			.vmux   = 3,
+		}},
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1800lp] = {
+		.name		= "Hauppauge WinTV-HVR1800lp",
+		.portc		= CX23885_MPEG_DVB,
+		.input          = {{
+			.type   = CX23885_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0xff00,
+		},{
+			.type   = CX23885_VMUX_DEBUG,
+			.vmux   = 0,
+			.gpio0  = 0xff01,
+		},{
+			.type   = CX23885_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0xff02,
+		},{
+			.type   = CX23885_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0xff02,
+		}},
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1800] = {
+		.name		= "Hauppauge WinTV-HVR1800",
+		.portc		= CX23885_MPEG_DVB,
+		.input          = {{
+			.type   = CX23885_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0xff00,
+		},{
+			.type   = CX23885_VMUX_DEBUG,
+			.vmux   = 0,
+			.gpio0  = 0xff01,
+		},{
+			.type   = CX23885_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0xff02,
+		},{
+			.type   = CX23885_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0xff02,
+		}},
+	},
+	[CX23885_BOARD_HAUPPAUGE_HVR1250] = {
+		.name		= "Hauppauge WinTV-HVR1250",
+		.portc		= CX23885_MPEG_DVB,
+		.input          = {{
+			.type   = CX23885_VMUX_TELEVISION,
+			.vmux   = 0,
+			.gpio0  = 0xff00,
+		},{
+			.type   = CX23885_VMUX_DEBUG,
+			.vmux   = 0,
+			.gpio0  = 0xff01,
+		},{
+			.type   = CX23885_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0xff02,
+		},{
+			.type   = CX23885_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0xff02,
+		}},
+	},
+	[CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP] = {
+		.name		= "DViCO FusionHDTV5 Express",
+		.portb		= CX23885_MPEG_DVB,
+	},
+};
+const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
+
+/* ------------------------------------------------------------------ */
+/* PCI subsystem IDs                                                  */
+
+struct cx23885_subid cx23885_subids[] = {
+	{
+		.subvendor = 0x0070,
+		.subdevice = 0x3400,
+		.card      = CX23885_BOARD_UNKNOWN,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x7600,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1800lp,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x7800,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1800,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x7801,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1800,
+	},{
+		.subvendor = 0x0070,
+		.subdevice = 0x7911,
+		.card      = CX23885_BOARD_HAUPPAUGE_HVR1250,
+	},{
+		.subvendor = 0x18ac,
+		.subdevice = 0xd500,
+		.card      = CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP,
+	},
+};
+const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
+
+void cx23885_card_list(struct cx23885_dev *dev)
+{
+	int i;
+
+	if (0 == dev->pci->subsystem_vendor &&
+	    0 == dev->pci->subsystem_device) {
+		printk("%s: Your board has no valid PCIe Subsystem ID and thus can't\n"
+		       "%s: be autodetected.  Please pass card=<n> insmod option to\n"
+		       "%s: workaround that.  Redirect complaints to the vendor of\n"
+		       "%s: the TV card.  Best regards,\n"
+		       "%s:         -- tux\n",
+		       dev->name, dev->name, dev->name, dev->name, dev->name);
+	} else {
+		printk("%s: Your board isn't known (yet) to the driver.  You can\n"
+		       "%s: try to pick one of the existing card configs via\n"
+		       "%s: card=<n> insmod option.  Updating to the latest\n"
+		       "%s: version might help as well.\n",
+		       dev->name, dev->name, dev->name, dev->name);
+	}
+	printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
+	       dev->name);
+	for (i = 0; i < cx23885_bcount; i++)
+		printk("%s:    card=%d -> %s\n",
+		       dev->name, i, cx23885_boards[i].name);
+}
+
+static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
+{
+	struct tveeprom tv;
+
+	tveeprom_hauppauge_analog(&dev->i2c_bus[0].i2c_client, &tv, eeprom_data);
+
+	/* Make sure we support the board model */
+	switch (tv.model)
+	{
+	case 76601: /* WinTV-HVR1800lp (PCIe, Retail, No IR, Dual channel ATSC and MPEG2 HW Encoder */
+	case 77001: /* WinTV-HVR1500 (Express Card, Retail, No IR, ATSC and Basic analog */
+	case 78501: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */
+	case 78521: /* WinTV-HVR1800 (PCIe, Retail, IR, Dual channel ATSC and MPEG2 HW Encoder */
+		break;
+	default:
+		printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model);
+		break;
+	}
+
+	printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+			dev->name, tv.model);
+}
+
+void cx23885_gpio_setup(struct cx23885_dev *dev)
+{
+	switch(dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+		/* GPIO-0 cx24227 demodulator reset */
+		cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+		/* GPIO-0 656_CLK */
+		/* GPIO-1 656_D0 */
+		/* GPIO-2 8295A Reset */
+		/* GPIO-3-10 cx23417 data0-7 */
+		/* GPIO-11-14 cx23417 addr0-3 */
+		/* GPIO-15-18 cx23417 READY, CS, RD, WR */
+		/* GPIO-19 IR_RX */
+		// FIXME: Analog requires the tuner is brought out of reset
+		break;
+	}
+}
+
+int cx23885_ir_init(struct cx23885_dev *dev)
+{
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+		/* FIXME: Implement me */
+		break;
+	}
+
+	return 0;
+}
+
+void cx23885_card_setup(struct cx23885_dev *dev)
+{
+	struct cx23885_tsport *ts1 = &dev->ts1;
+	struct cx23885_tsport *ts2 = &dev->ts2;
+
+	static u8 eeprom[256];
+
+	if (dev->i2c_bus[0].i2c_rc == 0) {
+		dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
+		tveeprom_read(&dev->i2c_bus[0].i2c_client,
+			      eeprom, sizeof(eeprom));
+	}
+
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+		if (dev->i2c_bus[0].i2c_rc == 0)
+			hauppauge_eeprom(dev, eeprom+0x80);
+		break;
+	}
+
+	switch (dev->board) {
+	case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
+		ts1->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+		ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts1->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+	default:
+		ts2->gen_ctrl_val  = 0xc; /* Serial bus + punctured clock */
+		ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+		ts2->src_sel_val   = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+	}
+
+}
+
+/* ------------------------------------------------------------------ */
+
+EXPORT_SYMBOL(cx23885_boards);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
+ */
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
new file mode 100644
index 0000000..af16505
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -0,0 +1,1530 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kmod.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/div64.h>
+
+#include "cx23885.h"
+
+MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
+MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug = 0;
+module_param(debug,int,0644);
+MODULE_PARM_DESC(debug,"enable debug messages");
+
+static unsigned int card[]  = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET };
+module_param_array(card,  int, NULL, 0444);
+MODULE_PARM_DESC(card,"card type");
+
+#define dprintk(level,fmt, arg...)	if (debug >= level) \
+	printk(KERN_DEBUG "%s/0: " fmt, dev->name , ## arg)
+
+static unsigned int cx23885_devcount;
+
+static DEFINE_MUTEX(devlist);
+static LIST_HEAD(cx23885_devlist);
+
+#define NO_SYNC_LINE (-1U)
+
+/*
+ * CX23885 Assumptions
+ * 1 line = 16 bytes of CDT
+ * cmds size = 80
+ * cdt size = 16 * linesize
+ * iqsize = 64
+ * maxlines = 6
+ *
+ * Address Space:
+ * 0x00000000 0x00008fff FIFO clusters
+ * 0x00010000 0x000104af Channel Management Data Structures
+ * 0x000104b0 0x000104ff Free
+ * 0x00010500 0x000108bf 15 channels * iqsize
+ * 0x000108c0 0x000108ff Free
+ * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables
+ *                       15 channels * (iqsize + (maxlines * linesize))
+ * 0x00010ea0 0x00010xxx Free
+ */
+
+struct sram_channel cx23885_sram_channels[] = {
+	[SRAM_CH01] = {
+		.name		= "test ch1",
+		.cmds_start	= 0x10000,
+		.ctrl_start	= 0x10500,
+		.cdt		= 0x10900,
+		.fifo_start	= 0x3000,
+		.fifo_size	= 0x1000,
+		.ptr1_reg	= DMA1_PTR1,
+		.ptr2_reg	= DMA1_PTR2,
+		.cnt1_reg	= DMA1_CNT1,
+		.cnt2_reg	= DMA1_CNT2,
+		.jumponly	= 1,
+	},
+	[SRAM_CH02] = {
+		.name		= "ch2",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA2_PTR1,
+		.ptr2_reg	= DMA2_PTR2,
+		.cnt1_reg	= DMA2_CNT1,
+		.cnt2_reg	= DMA2_CNT2,
+	},
+	[SRAM_CH03] = {
+		.name		= "TS1 B",
+		.cmds_start	= 0x100A0,
+		.ctrl_start	= 0x10780,
+		.cdt		= 0x10400,
+		.fifo_start	= 0x5000,
+		.fifo_size	= 0x1000,
+		.ptr1_reg	= DMA3_PTR1,
+		.ptr2_reg	= DMA3_PTR2,
+		.cnt1_reg	= DMA3_CNT1,
+		.cnt2_reg	= DMA3_CNT2,
+	},
+	[SRAM_CH04] = {
+		.name		= "ch4",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA4_PTR1,
+		.ptr2_reg	= DMA4_PTR2,
+		.cnt1_reg	= DMA4_CNT1,
+		.cnt2_reg	= DMA4_CNT2,
+	},
+	[SRAM_CH05] = {
+		.name		= "ch5",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA5_PTR1,
+		.ptr2_reg	= DMA5_PTR2,
+		.cnt1_reg	= DMA5_CNT1,
+		.cnt2_reg	= DMA5_CNT2,
+	},
+	[SRAM_CH06] = {
+		.name		= "TS2 C",
+		.cmds_start	= 0x10140,
+		.ctrl_start	= 0x10680,
+		.cdt		= 0x10480,
+		.fifo_start	= 0x6000,
+		.fifo_size	= 0x1000,
+		.ptr1_reg	= DMA5_PTR1,
+		.ptr2_reg	= DMA5_PTR2,
+		.cnt1_reg	= DMA5_CNT1,
+		.cnt2_reg	= DMA5_CNT2,
+	},
+	[SRAM_CH07] = {
+		.name		= "ch7",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA6_PTR1,
+		.ptr2_reg	= DMA6_PTR2,
+		.cnt1_reg	= DMA6_CNT1,
+		.cnt2_reg	= DMA6_CNT2,
+	},
+	[SRAM_CH08] = {
+		.name		= "ch8",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA7_PTR1,
+		.ptr2_reg	= DMA7_PTR2,
+		.cnt1_reg	= DMA7_CNT1,
+		.cnt2_reg	= DMA7_CNT2,
+	},
+	[SRAM_CH09] = {
+		.name		= "ch9",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA8_PTR1,
+		.ptr2_reg	= DMA8_PTR2,
+		.cnt1_reg	= DMA8_CNT1,
+		.cnt2_reg	= DMA8_CNT2,
+	},
+};
+
+/* FIXME, these allocations will change when
+ * analog arrives. The be reviewed.
+ * CX23887 Assumptions
+ * 1 line = 16 bytes of CDT
+ * cmds size = 80
+ * cdt size = 16 * linesize
+ * iqsize = 64
+ * maxlines = 6
+ *
+ * Address Space:
+ * 0x00000000 0x00008fff FIFO clusters
+ * 0x00010000 0x000104af Channel Management Data Structures
+ * 0x000104b0 0x000104ff Free
+ * 0x00010500 0x000108bf 15 channels * iqsize
+ * 0x000108c0 0x000108ff Free
+ * 0x00010900 0x00010e9f IQ's + Cluster Descriptor Tables
+ *                       15 channels * (iqsize + (maxlines * linesize))
+ * 0x00010ea0 0x00010xxx Free
+ */
+
+struct sram_channel cx23887_sram_channels[] = {
+	[SRAM_CH01] = {
+		.name		= "test ch1",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA1_PTR1,
+		.ptr2_reg	= DMA1_PTR2,
+		.cnt1_reg	= DMA1_CNT1,
+		.cnt2_reg	= DMA1_CNT2,
+	},
+	[SRAM_CH02] = {
+		.name		= "ch2",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA2_PTR1,
+		.ptr2_reg	= DMA2_PTR2,
+		.cnt1_reg	= DMA2_CNT1,
+		.cnt2_reg	= DMA2_CNT2,
+	},
+	[SRAM_CH03] = {
+		.name		= "ch3",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA3_PTR1,
+		.ptr2_reg	= DMA3_PTR2,
+		.cnt1_reg	= DMA3_CNT1,
+		.cnt2_reg	= DMA3_CNT2,
+	},
+	[SRAM_CH04] = {
+		.name		= "ch4",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA4_PTR1,
+		.ptr2_reg	= DMA4_PTR2,
+		.cnt1_reg	= DMA4_CNT1,
+		.cnt2_reg	= DMA4_CNT2,
+	},
+	[SRAM_CH05] = {
+		.name		= "ch5",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA5_PTR1,
+		.ptr2_reg	= DMA5_PTR2,
+		.cnt1_reg	= DMA5_CNT1,
+		.cnt2_reg	= DMA5_CNT2,
+	},
+	[SRAM_CH06] = {
+		.name		= "TS2 C",
+		.cmds_start	= 0x10140,
+		.ctrl_start	= 0x10680,
+		.cdt		= 0x108d0,
+		.fifo_start	= 0x6000,
+		.fifo_size	= 0x1000,
+		.ptr1_reg	= DMA5_PTR1,
+		.ptr2_reg	= DMA5_PTR2,
+		.cnt1_reg	= DMA5_CNT1,
+		.cnt2_reg	= DMA5_CNT2,
+	},
+	[SRAM_CH07] = {
+		.name		= "ch7",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA6_PTR1,
+		.ptr2_reg	= DMA6_PTR2,
+		.cnt1_reg	= DMA6_CNT1,
+		.cnt2_reg	= DMA6_CNT2,
+	},
+	[SRAM_CH08] = {
+		.name		= "ch8",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA7_PTR1,
+		.ptr2_reg	= DMA7_PTR2,
+		.cnt1_reg	= DMA7_CNT1,
+		.cnt2_reg	= DMA7_CNT2,
+	},
+	[SRAM_CH09] = {
+		.name		= "ch9",
+		.cmds_start	= 0x0,
+		.ctrl_start	= 0x0,
+		.cdt		= 0x0,
+		.fifo_start	= 0x0,
+		.fifo_size	= 0x0,
+		.ptr1_reg	= DMA8_PTR1,
+		.ptr2_reg	= DMA8_PTR2,
+		.cnt1_reg	= DMA8_CNT1,
+		.cnt2_reg	= DMA8_CNT2,
+	},
+};
+
+static int cx23885_risc_decode(u32 risc)
+{
+	static char *instr[16] = {
+		[ RISC_SYNC    >> 28 ] = "sync",
+		[ RISC_WRITE   >> 28 ] = "write",
+		[ RISC_WRITEC  >> 28 ] = "writec",
+		[ RISC_READ    >> 28 ] = "read",
+		[ RISC_READC   >> 28 ] = "readc",
+		[ RISC_JUMP    >> 28 ] = "jump",
+		[ RISC_SKIP    >> 28 ] = "skip",
+		[ RISC_WRITERM >> 28 ] = "writerm",
+		[ RISC_WRITECM >> 28 ] = "writecm",
+		[ RISC_WRITECR >> 28 ] = "writecr",
+	};
+	static int incr[16] = {
+		[ RISC_WRITE   >> 28 ] = 3,
+		[ RISC_JUMP    >> 28 ] = 3,
+		[ RISC_SKIP    >> 28 ] = 1,
+		[ RISC_SYNC    >> 28 ] = 1,
+		[ RISC_WRITERM >> 28 ] = 3,
+		[ RISC_WRITECM >> 28 ] = 3,
+		[ RISC_WRITECR >> 28 ] = 4,
+	};
+	static char *bits[] = {
+		"12",   "13",   "14",   "resync",
+		"cnt0", "cnt1", "18",   "19",
+		"20",   "21",   "22",   "23",
+		"irq1", "irq2", "eol",  "sol",
+	};
+	int i;
+
+	printk("0x%08x [ %s", risc,
+	       instr[risc >> 28] ? instr[risc >> 28] : "INVALID");
+	for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--)
+		if (risc & (1 << (i + 12)))
+			printk(" %s", bits[i]);
+	printk(" count=%d ]\n", risc & 0xfff);
+	return incr[risc >> 28] ? incr[risc >> 28] : 1;
+}
+
+void cx23885_wakeup(struct cx23885_tsport *port,
+		    struct cx23885_dmaqueue *q, u32 count)
+{
+	struct cx23885_dev *dev = port->dev;
+	struct cx23885_buffer *buf;
+	int bc;
+
+	for (bc = 0;; bc++) {
+		if (list_empty(&q->active))
+			break;
+		buf = list_entry(q->active.next,
+				 struct cx23885_buffer, vb.queue);
+
+		/* count comes from the hw and is is 16bit wide --
+		 * this trick handles wrap-arounds correctly for
+		 * up to 32767 buffers in flight... */
+		if ((s16) (count - buf->count) < 0)
+			break;
+
+		do_gettimeofday(&buf->vb.ts);
+		dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i,
+			count, buf->count);
+		buf->vb.state = STATE_DONE;
+		list_del(&buf->vb.queue);
+		wake_up(&buf->vb.done);
+	}
+	if (list_empty(&q->active)) {
+		del_timer(&q->timeout);
+	} else {
+		mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
+	}
+	if (bc != 1)
+		printk("%s: %d buffers handled (should be 1)\n",
+		       __FUNCTION__, bc);
+}
+void cx23885_sram_channel_dump(struct cx23885_dev *dev,
+			       struct sram_channel *ch);
+
+int cx23885_sram_channel_setup(struct cx23885_dev *dev,
+			       struct sram_channel *ch,
+			       unsigned int bpl, u32 risc)
+{
+	unsigned int i, lines;
+	u32 cdt;
+
+	if (ch->cmds_start == 0)
+	{
+		dprintk(1, "%s() Erasing channel [%s]\n", __FUNCTION__,
+			ch->name);
+		cx_write(ch->ptr1_reg, 0);
+		cx_write(ch->ptr2_reg, 0);
+		cx_write(ch->cnt2_reg, 0);
+		cx_write(ch->cnt1_reg, 0);
+		return 0;
+	} else {
+		dprintk(1, "%s() Configuring channel [%s]\n", __FUNCTION__,
+			ch->name);
+	}
+
+	bpl   = (bpl + 7) & ~7; /* alignment */
+	cdt   = ch->cdt;
+	lines = ch->fifo_size / bpl;
+	if (lines > 6)
+		lines = 6;
+	BUG_ON(lines < 2);
+
+	cx_write(8 + 0, cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC) );
+	cx_write(8 + 4, cpu_to_le32(8) );
+	cx_write(8 + 8, cpu_to_le32(0) );
+
+	/* write CDT */
+	for (i = 0; i < lines; i++) {
+		dprintk(2, "%s() 0x%08x <- 0x%08x\n", __FUNCTION__, cdt + 16*i,
+			ch->fifo_start + bpl*i);
+		cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
+		cx_write(cdt + 16*i +  4, 0);
+		cx_write(cdt + 16*i +  8, 0);
+		cx_write(cdt + 16*i + 12, 0);
+	}
+
+	/* write CMDS */
+	if (ch->jumponly)
+		cx_write(ch->cmds_start +  0, 8);
+	else
+		cx_write(ch->cmds_start +  0, risc);
+	cx_write(ch->cmds_start +  4, 0); /* 64 bits 63-32 */
+	cx_write(ch->cmds_start +  8, cdt);
+	cx_write(ch->cmds_start + 12, (lines*16) >> 3);
+	cx_write(ch->cmds_start + 16, ch->ctrl_start);
+	if (ch->jumponly)
+		cx_write(ch->cmds_start + 20, 0x80000000 | (64 >> 2) );
+	else
+		cx_write(ch->cmds_start + 20, 64 >> 2);
+	for (i = 24; i < 80; i += 4)
+		cx_write(ch->cmds_start + i, 0);
+
+	/* fill registers */
+	cx_write(ch->ptr1_reg, ch->fifo_start);
+	cx_write(ch->ptr2_reg, cdt);
+	cx_write(ch->cnt2_reg, (lines*16) >> 3);
+	cx_write(ch->cnt1_reg, (bpl >> 3) -1);
+
+	dprintk(2,"[bridge %d] sram setup %s: bpl=%d lines=%d\n",
+		dev->bridge,
+		ch->name,
+		bpl,
+		lines);
+
+	return 0;
+}
+
+void cx23885_sram_channel_dump(struct cx23885_dev *dev,
+			       struct sram_channel *ch)
+{
+	static char *name[] = {
+		"init risc lo",
+		"init risc hi",
+		"cdt base",
+		"cdt size",
+		"iq base",
+		"iq size",
+		"risc pc lo",
+		"risc pc hi",
+		"iq wr ptr",
+		"iq rd ptr",
+		"cdt current",
+		"pci target lo",
+		"pci target hi",
+		"line / byte",
+	};
+	u32 risc;
+	unsigned int i, j, n;
+
+	printk("%s: %s - dma channel status dump\n",
+	       dev->name, ch->name);
+	for (i = 0; i < ARRAY_SIZE(name); i++)
+		printk("%s:   cmds: %-15s: 0x%08x\n",
+		       dev->name, name[i],
+		       cx_read(ch->cmds_start + 4*i));
+
+	for (i = 0; i < 4; i++) {
+		risc = cx_read(ch->cmds_start + 4 * (i + 14));
+		printk("%s:   risc%d: ", dev->name, i);
+		cx23885_risc_decode(risc);
+	}
+	for (i = 0; i < (64 >> 2); i += n) {
+		risc = cx_read(ch->ctrl_start + 4 * i);
+		/* No consideration for bits 63-32 */
+
+		printk("%s:   (0x%08x) iq %x: ", dev->name,
+		       ch->ctrl_start + 4 * i, i);
+		n = cx23885_risc_decode(risc);
+		for (j = 1; j < n; j++) {
+			risc = cx_read(ch->ctrl_start + 4 * (i + j));
+			printk("%s:   iq %x: 0x%08x [ arg #%d ]\n",
+			       dev->name, i+j, risc, j);
+		}
+	}
+
+	printk("%s: fifo: 0x%08x -> 0x%x\n",
+	       dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size);
+	printk("%s: ctrl: 0x%08x -> 0x%x\n",
+	       dev->name, ch->ctrl_start, ch->ctrl_start + 6*16);
+	printk("%s:   ptr1_reg: 0x%08x\n",
+	       dev->name, cx_read(ch->ptr1_reg));
+	printk("%s:   ptr2_reg: 0x%08x\n",
+	       dev->name, cx_read(ch->ptr2_reg));
+	printk("%s:   cnt1_reg: 0x%08x\n",
+	       dev->name, cx_read(ch->cnt1_reg));
+	printk("%s:   cnt2_reg: 0x%08x\n",
+	       dev->name, cx_read(ch->cnt2_reg));
+}
+
+void cx23885_risc_disasm(struct cx23885_tsport *port,
+			 struct btcx_riscmem *risc)
+{
+	struct cx23885_dev *dev = port->dev;
+	unsigned int i, j, n;
+
+	printk("%s: risc disasm: %p [dma=0x%08lx]\n",
+	       dev->name, risc->cpu, (unsigned long)risc->dma);
+	for (i = 0; i < (risc->size >> 2); i += n) {
+		printk("%s:   %04d: ", dev->name, i);
+		n = cx23885_risc_decode(risc->cpu[i]);
+		for (j = 1; j < n; j++)
+			printk("%s:   %04d: 0x%08x [ arg #%d ]\n",
+			       dev->name, i + j, risc->cpu[i + j], j);
+		if (risc->cpu[i] == RISC_JUMP)
+			break;
+	}
+}
+
+void cx23885_shutdown(struct cx23885_dev *dev)
+{
+	/* disable RISC controller */
+	cx_write(DEV_CNTRL2, 0);
+
+	/* Disable all IR activity */
+	cx_write(IR_CNTRL_REG, 0);
+
+	/* Disable Video A/B activity */
+	cx_write(VID_A_DMA_CTL, 0);
+	cx_write(VID_B_DMA_CTL, 0);
+	cx_write(VID_C_DMA_CTL, 0);
+
+	/* Disable Audio activity */
+	cx_write(AUD_INT_DMA_CTL, 0);
+	cx_write(AUD_EXT_DMA_CTL, 0);
+
+	/* Disable Serial port */
+	cx_write(UART_CTL, 0);
+
+	/* Disable Interrupts */
+	cx_write(PCI_INT_MSK, 0);
+	cx_write(VID_A_INT_MSK, 0);
+	cx_write(VID_B_INT_MSK, 0);
+	cx_write(VID_C_INT_MSK, 0);
+	cx_write(AUDIO_INT_INT_MSK, 0);
+	cx_write(AUDIO_EXT_INT_MSK, 0);
+
+}
+
+void cx23885_reset(struct cx23885_dev *dev)
+{
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	cx23885_shutdown(dev);
+
+	cx_write(PCI_INT_STAT, 0xffffffff);
+	cx_write(VID_A_INT_STAT, 0xffffffff);
+	cx_write(VID_B_INT_STAT, 0xffffffff);
+	cx_write(VID_C_INT_STAT, 0xffffffff);
+	cx_write(AUDIO_INT_INT_STAT, 0xffffffff);
+	cx_write(AUDIO_EXT_INT_STAT, 0xffffffff);
+	cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000);
+
+	mdelay(100);
+
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH01 ], 188*4, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH02 ], 128, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH03 ], 188*4, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH04 ], 128, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH05 ], 128, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH06 ], 188*4, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH07 ], 128, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH08 ], 128, 0);
+	cx23885_sram_channel_setup(dev, &dev->sram_channels[ SRAM_CH09 ], 128, 0);
+
+	cx23885_gpio_setup(dev);
+}
+
+
+static int cx23885_pci_quirks(struct cx23885_dev *dev)
+{
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	/* The cx23885 bridge has a weird bug which causes NMI to be asserted
+	 * when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not
+	 * occur on the cx23887 bridge.
+	 */
+	if(dev->bridge == CX23885_BRIDGE_885)
+		cx_clear(RDR_TLCTL0, 1 << 4);
+
+	return 0;
+}
+
+static int get_resources(struct cx23885_dev *dev)
+{
+	if (request_mem_region(pci_resource_start(dev->pci,0),
+			       pci_resource_len(dev->pci,0),
+			       dev->name))
+		return 0;
+
+	printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
+		dev->name, (unsigned long long)pci_resource_start(dev->pci,0));
+
+	return -EBUSY;
+}
+
+static void cx23885_timeout(unsigned long data);
+int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+			 u32 reg, u32 mask, u32 value);
+
+static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno)
+{
+	dprintk(1, "%s(portno=%d)\n", __FUNCTION__, portno);
+
+	/* Transport bus init dma queue  - Common settings */
+	port->dma_ctl_val        = 0x11; /* Enable RISC controller and Fifo */
+	port->ts_int_msk_val     = 0x1111; /* TS port bits for RISC */
+
+	spin_lock_init(&port->slock);
+	port->dev = dev;
+	port->nr = portno;
+
+	INIT_LIST_HEAD(&port->mpegq.active);
+	INIT_LIST_HEAD(&port->mpegq.queued);
+	port->mpegq.timeout.function = cx23885_timeout;
+	port->mpegq.timeout.data = (unsigned long)port;
+	init_timer(&port->mpegq.timeout);
+
+	switch(portno) {
+	case 1:
+		port->reg_gpcnt          = VID_B_GPCNT;
+		port->reg_gpcnt_ctl      = VID_B_GPCNT_CTL;
+		port->reg_dma_ctl        = VID_B_DMA_CTL;
+		port->reg_lngth          = VID_B_LNGTH;
+		port->reg_hw_sop_ctrl    = VID_B_HW_SOP_CTL;
+		port->reg_gen_ctrl       = VID_B_GEN_CTL;
+		port->reg_bd_pkt_status  = VID_B_BD_PKT_STATUS;
+		port->reg_sop_status     = VID_B_SOP_STATUS;
+		port->reg_fifo_ovfl_stat = VID_B_FIFO_OVFL_STAT;
+		port->reg_vld_misc       = VID_B_VLD_MISC;
+		port->reg_ts_clk_en      = VID_B_TS_CLK_EN;
+		port->reg_src_sel        = VID_B_SRC_SEL;
+		port->reg_ts_int_msk     = VID_B_INT_MSK;
+		port->reg_ts_int_stat   = VID_B_INT_STAT;
+		port->sram_chno          = SRAM_CH03; /* VID_B */
+		port->pci_irqmask        = 0x02; /* VID_B bit1 */
+		break;
+	case 2:
+		port->reg_gpcnt          = VID_C_GPCNT;
+		port->reg_gpcnt_ctl      = VID_C_GPCNT_CTL;
+		port->reg_dma_ctl        = VID_C_DMA_CTL;
+		port->reg_lngth          = VID_C_LNGTH;
+		port->reg_hw_sop_ctrl    = VID_C_HW_SOP_CTL;
+		port->reg_gen_ctrl       = VID_C_GEN_CTL;
+		port->reg_bd_pkt_status  = VID_C_BD_PKT_STATUS;
+		port->reg_sop_status     = VID_C_SOP_STATUS;
+		port->reg_fifo_ovfl_stat = VID_C_FIFO_OVFL_STAT;
+		port->reg_vld_misc       = VID_C_VLD_MISC;
+		port->reg_ts_clk_en      = VID_C_TS_CLK_EN;
+		port->reg_src_sel        = 0;
+		port->reg_ts_int_msk     = VID_C_INT_MSK;
+		port->reg_ts_int_stat    = VID_C_INT_STAT;
+		port->sram_chno          = SRAM_CH06; /* VID_C */
+		port->pci_irqmask        = 0x04; /* VID_C bit2 */
+		break;
+	default:
+		BUG();
+	}
+
+	cx23885_risc_stopper(dev->pci, &port->mpegq.stopper,
+		     port->reg_dma_ctl, port->dma_ctl_val, 0x00);
+
+	return 0;
+}
+
+static int cx23885_dev_setup(struct cx23885_dev *dev)
+{
+	int i;
+
+	mutex_init(&dev->lock);
+
+	atomic_inc(&dev->refcount);
+
+	dev->nr = cx23885_devcount++;
+	sprintf(dev->name, "cx23885[%d]", dev->nr);
+
+	mutex_lock(&devlist);
+	list_add_tail(&dev->devlist, &cx23885_devlist);
+	mutex_unlock(&devlist);
+
+	/* Configure the internal memory */
+	if(dev->pci->device == 0x8880) {
+		dev->bridge = CX23885_BRIDGE_887;
+		dev->sram_channels = cx23887_sram_channels;
+	} else
+	if(dev->pci->device == 0x8852) {
+		dev->bridge = CX23885_BRIDGE_885;
+		dev->sram_channels = cx23885_sram_channels;
+	} else
+		BUG();
+
+	dprintk(1, "%s() Memory configured for PCIe bridge type %d\n",
+		__FUNCTION__, dev->bridge);
+
+	/* board config */
+	dev->board = UNSET;
+	if (card[dev->nr] < cx23885_bcount)
+		dev->board = card[dev->nr];
+	for (i = 0; UNSET == dev->board  &&  i < cx23885_idcount; i++)
+		if (dev->pci->subsystem_vendor == cx23885_subids[i].subvendor &&
+		    dev->pci->subsystem_device == cx23885_subids[i].subdevice)
+			dev->board = cx23885_subids[i].card;
+	if (UNSET == dev->board) {
+		dev->board = CX23885_BOARD_UNKNOWN;
+		cx23885_card_list(dev);
+	}
+
+	dev->pci_bus  = dev->pci->bus->number;
+	dev->pci_slot = PCI_SLOT(dev->pci->devfn);
+	dev->pci_irqmask = 0x001f00;
+
+	/* External Master 1 Bus */
+	dev->i2c_bus[0].nr = 0;
+	dev->i2c_bus[0].dev = dev;
+	dev->i2c_bus[0].reg_stat  = I2C1_STAT;
+	dev->i2c_bus[0].reg_ctrl  = I2C1_CTRL;
+	dev->i2c_bus[0].reg_addr  = I2C1_ADDR;
+	dev->i2c_bus[0].reg_rdata = I2C1_RDATA;
+	dev->i2c_bus[0].reg_wdata = I2C1_WDATA;
+	dev->i2c_bus[0].i2c_period = (0x9d << 24); /* 100kHz */
+
+	/* External Master 2 Bus */
+	dev->i2c_bus[1].nr = 1;
+	dev->i2c_bus[1].dev = dev;
+	dev->i2c_bus[1].reg_stat  = I2C2_STAT;
+	dev->i2c_bus[1].reg_ctrl  = I2C2_CTRL;
+	dev->i2c_bus[1].reg_addr  = I2C2_ADDR;
+	dev->i2c_bus[1].reg_rdata = I2C2_RDATA;
+	dev->i2c_bus[1].reg_wdata = I2C2_WDATA;
+	dev->i2c_bus[1].i2c_period = (0x9d << 24); /* 100kHz */
+
+	/* Internal Master 3 Bus */
+	dev->i2c_bus[2].nr = 2;
+	dev->i2c_bus[2].dev = dev;
+	dev->i2c_bus[2].reg_stat  = I2C3_STAT;
+	dev->i2c_bus[2].reg_ctrl  = I2C3_CTRL;
+	dev->i2c_bus[2].reg_addr  = I2C3_ADDR;
+	dev->i2c_bus[2].reg_rdata = I2C3_RDATA;
+	dev->i2c_bus[2].reg_wdata = I2C3_WDATA;
+	dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */
+
+	if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+		cx23885_init_tsport(dev, &dev->ts1, 1);
+
+	if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
+		cx23885_init_tsport(dev, &dev->ts2, 2);
+
+	if (get_resources(dev) < 0) {
+		printk(KERN_ERR "CORE %s No more PCIe resources for "
+		       "subsystem: %04x:%04x\n",
+		       dev->name, dev->pci->subsystem_vendor,
+		       dev->pci->subsystem_device);
+
+		cx23885_devcount--;
+		goto fail_free;
+	}
+
+	/* PCIe stuff */
+	dev->lmmio = ioremap(pci_resource_start(dev->pci,0),
+			     pci_resource_len(dev->pci,0));
+
+	dev->bmmio = (u8 __iomem *)dev->lmmio;
+
+	printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+	       dev->name, dev->pci->subsystem_vendor,
+	       dev->pci->subsystem_device, cx23885_boards[dev->board].name,
+	       dev->board, card[dev->nr] == dev->board ?
+	       "insmod option" : "autodetected");
+
+	cx23885_pci_quirks(dev);
+
+	/* init hardware */
+	cx23885_reset(dev);
+
+	cx23885_i2c_register(&dev->i2c_bus[0]);
+	cx23885_i2c_register(&dev->i2c_bus[1]);
+	cx23885_i2c_register(&dev->i2c_bus[2]);
+	cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL);
+	cx23885_card_setup(dev);
+	cx23885_ir_init(dev);
+
+	if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
+		if (cx23885_dvb_register(&dev->ts1) < 0) {
+			printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n",
+			       __FUNCTION__);
+		}
+	}
+
+	if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
+		if (cx23885_dvb_register(&dev->ts2) < 0) {
+			printk(KERN_ERR "%s() Failed to register dvb adapters on VID_C\n",
+			       __FUNCTION__);
+		}
+	}
+
+	return 0;
+
+fail_free:
+	kfree(dev);
+	return -ENODEV;
+}
+
+void cx23885_dev_unregister(struct cx23885_dev *dev)
+{
+	release_mem_region(pci_resource_start(dev->pci,0),
+			   pci_resource_len(dev->pci,0));
+
+	if (!atomic_dec_and_test(&dev->refcount))
+		return;
+
+	if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+		cx23885_dvb_unregister(&dev->ts1);
+
+	if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
+		cx23885_dvb_unregister(&dev->ts2);
+
+	cx23885_i2c_unregister(&dev->i2c_bus[2]);
+	cx23885_i2c_unregister(&dev->i2c_bus[1]);
+	cx23885_i2c_unregister(&dev->i2c_bus[0]);
+
+	iounmap(dev->lmmio);
+}
+
+static u32* cx23885_risc_field(u32 *rp, struct scatterlist *sglist,
+			       unsigned int offset, u32 sync_line,
+			       unsigned int bpl, unsigned int padding,
+			       unsigned int lines)
+{
+	struct scatterlist *sg;
+	unsigned int line, todo;
+
+	/* sync instruction */
+	if (sync_line != NO_SYNC_LINE)
+		*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
+
+	/* scan lines */
+	sg = sglist;
+	for (line = 0; line < lines; line++) {
+		while (offset && offset >= sg_dma_len(sg)) {
+			offset -= sg_dma_len(sg);
+			sg++;
+		}
+		if (bpl <= sg_dma_len(sg)-offset) {
+			/* fits into current chunk */
+			*(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
+			*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+			*(rp++)=cpu_to_le32(0); /* bits 63-32 */
+			offset+=bpl;
+		} else {
+			/* scanline needs to be split */
+			todo = bpl;
+			*(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
+					    (sg_dma_len(sg)-offset));
+			*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
+			*(rp++)=cpu_to_le32(0); /* bits 63-32 */
+			todo -= (sg_dma_len(sg)-offset);
+			offset = 0;
+			sg++;
+			while (todo > sg_dma_len(sg)) {
+				*(rp++)=cpu_to_le32(RISC_WRITE|
+						    sg_dma_len(sg));
+				*(rp++)=cpu_to_le32(sg_dma_address(sg));
+				*(rp++)=cpu_to_le32(0); /* bits 63-32 */
+				todo -= sg_dma_len(sg);
+				sg++;
+			}
+			*(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
+			*(rp++)=cpu_to_le32(sg_dma_address(sg));
+			*(rp++)=cpu_to_le32(0); /* bits 63-32 */
+			offset += todo;
+		}
+		offset += padding;
+	}
+
+	return rp;
+}
+
+int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+			struct scatterlist *sglist, unsigned int top_offset,
+			unsigned int bottom_offset, unsigned int bpl,
+			unsigned int padding, unsigned int lines)
+{
+	u32 instructions, fields;
+	u32 *rp;
+	int rc;
+
+	fields = 0;
+	if (UNSET != top_offset)
+		fields++;
+	if (UNSET != bottom_offset)
+		fields++;
+
+	/* estimate risc mem: worst case is one write per page border +
+	   one write per scan line + syncs + jump (all 2 dwords).  Padding
+	   can cause next bpl to start close to a page border.  First DMA
+	   region may be smaller than PAGE_SIZE */
+	/* write and jump need and extra dword */
+	instructions  = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines);
+	instructions += 2;
+	if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0)
+		return rc;
+
+	/* write risc instructions */
+	rp = risc->cpu;
+	if (UNSET != top_offset)
+		rp = cx23885_risc_field(rp, sglist, top_offset, 0,
+					bpl, padding, lines);
+	if (UNSET != bottom_offset)
+		rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200,
+					bpl, padding, lines);
+
+	/* save pointer to jmp instruction address */
+	risc->jmp = rp;
+	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
+	return 0;
+}
+
+int cx23885_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+			    struct scatterlist *sglist, unsigned int bpl,
+			    unsigned int lines)
+{
+	u32 instructions;
+	u32 *rp;
+	int rc;
+
+	/* estimate risc mem: worst case is one write per page border +
+	   one write per scan line + syncs + jump (all 2 dwords).  Here
+	   there is no padding and no sync.  First DMA region may be smaller
+	   than PAGE_SIZE */
+	/* Jump and write need an extra dword */
+	instructions  = 1 + (bpl * lines) / PAGE_SIZE + lines;
+	instructions += 1;
+
+	if ((rc = btcx_riscmem_alloc(pci,risc,instructions*12)) < 0)
+		return rc;
+
+	/* write risc instructions */
+	rp = risc->cpu;
+	rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines);
+
+	/* save pointer to jmp instruction address */
+	risc->jmp = rp;
+	BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size);
+	return 0;
+}
+
+int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
+			 u32 reg, u32 mask, u32 value)
+{
+	u32 *rp;
+	int rc;
+
+	if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
+		return rc;
+
+	/* write risc instructions */
+	rp = risc->cpu;
+	*(rp++) = cpu_to_le32(RISC_WRITECR  | RISC_IRQ2);
+	*(rp++) = cpu_to_le32(reg);
+	*(rp++) = cpu_to_le32(value);
+	*(rp++) = cpu_to_le32(mask);
+	*(rp++) = cpu_to_le32(RISC_JUMP);
+	*(rp++) = cpu_to_le32(risc->dma);
+	*(rp++) = cpu_to_le32(0); /* bits 63-32 */
+	return 0;
+}
+
+void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
+{
+	struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+
+	BUG_ON(in_interrupt());
+	videobuf_waiton(&buf->vb, 0, 0);
+	videobuf_dma_unmap(q, dma);
+	videobuf_dma_free(dma);
+	btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
+	buf->vb.state = STATE_NEEDS_INIT;
+}
+
+static int cx23885_start_dma(struct cx23885_tsport *port,
+			     struct cx23885_dmaqueue *q,
+			     struct cx23885_buffer   *buf)
+{
+	struct cx23885_dev *dev = port->dev;
+
+	dprintk(1, "%s() w: %d, h: %d, f: %d\n", __FUNCTION__,
+		buf->vb.width, buf->vb.height, buf->vb.field);
+
+	/* setup fifo + format */
+	cx23885_sram_channel_setup(dev,
+				   &dev->sram_channels[ port->sram_chno ],
+				   port->ts_packet_size, buf->risc.dma);
+	if(debug > 5) {
+		cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ] );
+		cx23885_risc_disasm(port, &buf->risc);
+	}
+
+	/* write TS length to chip */
+	cx_write(port->reg_lngth, buf->vb.width);
+
+	if ( (!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
+		(!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) ) {
+		printk( "%s() Failed. Unsupported value in .portb/c (0x%08x)/(0x%08x)\n",
+			__FUNCTION__,
+			cx23885_boards[dev->board].portb,
+			cx23885_boards[dev->board].portc );
+		return -EINVAL;
+	}
+
+	udelay(100);
+
+	/* If the port supports SRC SELECT, configure it */
+	if(port->reg_src_sel)
+		cx_write(port->reg_src_sel, port->src_sel_val);
+
+	cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4);
+	cx_write(port->reg_ts_clk_en, port->ts_clk_en_val);
+	cx_write(port->reg_vld_misc, 0x00);
+	cx_write(port->reg_gen_ctrl, port->gen_ctrl_val);
+	udelay(100);
+
+	// NOTE: this is 2 (reserved) for portb, does it matter?
+	/* reset counter to zero */
+	cx_write(port->reg_gpcnt_ctl, 3);
+	q->count = 1;
+
+	switch(dev->bridge) {
+	case CX23885_BRIDGE_885:
+	case CX23885_BRIDGE_887:
+		/* enable irqs */
+		dprintk(1, "%s() enabling TS int's and DMA\n", __FUNCTION__ );
+		cx_set(port->reg_ts_int_msk,  port->ts_int_msk_val);
+		cx_set(port->reg_dma_ctl, port->dma_ctl_val);
+		cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask);
+		break;
+	default:
+		BUG();
+	}
+
+	cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */
+
+	return 0;
+}
+
+static int cx23885_stop_dma(struct cx23885_tsport *port)
+{
+	struct cx23885_dev *dev = port->dev;
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	/* Stop interrupts and DMA */
+	cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val);
+	cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
+
+	return 0;
+}
+
+static int cx23885_restart_queue(struct cx23885_tsport *port,
+				struct cx23885_dmaqueue *q)
+{
+	struct cx23885_dev *dev = port->dev;
+	struct cx23885_buffer *buf;
+
+	dprintk(5, "%s()\n", __FUNCTION__);
+	if (list_empty(&q->active))
+	{
+		struct cx23885_buffer *prev;
+		prev = NULL;
+
+		dprintk(5, "%s() queue is empty\n", __FUNCTION__);
+
+		for (;;) {
+			if (list_empty(&q->queued))
+				return 0;
+			buf = list_entry(q->queued.next, struct cx23885_buffer,
+					 vb.queue);
+			if (NULL == prev) {
+				list_del(&buf->vb.queue);
+				list_add_tail(&buf->vb.queue, &q->active);
+				cx23885_start_dma(port, q, buf);
+				buf->vb.state = STATE_ACTIVE;
+				buf->count    = q->count++;
+				mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+				dprintk(5, "[%p/%d] restart_queue - first active\n",
+					buf, buf->vb.i);
+
+			} else if (prev->vb.width  == buf->vb.width  &&
+				   prev->vb.height == buf->vb.height &&
+				   prev->fmt       == buf->fmt) {
+				list_del(&buf->vb.queue);
+				list_add_tail(&buf->vb.queue, &q->active);
+				buf->vb.state = STATE_ACTIVE;
+				buf->count    = q->count++;
+				prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+				prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
+				dprintk(5,"[%p/%d] restart_queue - move to active\n",
+					buf, buf->vb.i);
+			} else {
+				return 0;
+			}
+			prev = buf;
+		}
+		return 0;
+	}
+
+	buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue);
+	dprintk(2, "restart_queue [%p/%d]: restart dma\n",
+		buf, buf->vb.i);
+	cx23885_start_dma(port, q, buf);
+	list_for_each_entry(buf, &q->active, vb.queue)
+		buf->count = q->count++;
+	mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
+			struct cx23885_buffer *buf, enum v4l2_field field)
+{
+	struct cx23885_dev *dev = port->dev;
+	int size = port->ts_packet_size * port->ts_packet_count;
+	int rc;
+
+	dprintk(1, "%s: %p\n", __FUNCTION__, buf);
+	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
+		return -EINVAL;
+
+	if (STATE_NEEDS_INIT == buf->vb.state) {
+		buf->vb.width  = port->ts_packet_size;
+		buf->vb.height = port->ts_packet_count;
+		buf->vb.size   = size;
+		buf->vb.field  = field /*V4L2_FIELD_TOP*/;
+
+		if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
+			goto fail;
+		cx23885_risc_databuffer(dev->pci, &buf->risc,
+					videobuf_to_dma(&buf->vb)->sglist,
+					buf->vb.width, buf->vb.height);
+	}
+	buf->vb.state = STATE_PREPARED;
+	return 0;
+
+ fail:
+	cx23885_free_buffer(q, buf);
+	return rc;
+}
+
+void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
+{
+	struct cx23885_buffer    *prev;
+	struct cx23885_dev *dev = port->dev;
+	struct cx23885_dmaqueue  *cx88q = &port->mpegq;
+
+	/* add jump to stopper */
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+	buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma);
+	buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
+
+	if (list_empty(&cx88q->active)) {
+		dprintk( 1, "queue is empty - first active\n" );
+		list_add_tail(&buf->vb.queue, &cx88q->active);
+		cx23885_start_dma(port, cx88q, buf);
+		buf->vb.state = STATE_ACTIVE;
+		buf->count    = cx88q->count++;
+		mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT);
+		dprintk(1, "[%p/%d] %s - first active\n",
+			buf, buf->vb.i, __FUNCTION__);
+	} else {
+		dprintk( 1, "queue is not empty - append to active\n" );
+		prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
+				  vb.queue);
+		list_add_tail(&buf->vb.queue, &cx88q->active);
+		buf->vb.state = STATE_ACTIVE;
+		buf->count    = cx88q->count++;
+		prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+		prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
+		dprintk( 1, "[%p/%d] %s - append to active\n",
+			 buf, buf->vb.i, __FUNCTION__);
+	}
+}
+
+/* ----------------------------------------------------------- */
+
+static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
+			      int restart)
+{
+	struct cx23885_dev *dev = port->dev;
+	struct cx23885_dmaqueue *q = &port->mpegq;
+	struct cx23885_buffer *buf;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->slock, flags);
+	while (!list_empty(&q->active)) {
+		buf = list_entry(q->active.next, struct cx23885_buffer,
+				 vb.queue);
+		list_del(&buf->vb.queue);
+		buf->vb.state = STATE_ERROR;
+		wake_up(&buf->vb.done);
+		dprintk(1, "[%p/%d] %s - dma=0x%08lx\n",
+			buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
+	}
+	if (restart) {
+		dprintk(1, "restarting queue\n" );
+		cx23885_restart_queue(port, q);
+	}
+	spin_unlock_irqrestore(&port->slock, flags);
+}
+
+void cx23885_cancel_buffers(struct cx23885_tsport *port)
+{
+	struct cx23885_dev *dev = port->dev;
+	struct cx23885_dmaqueue *q = &port->mpegq;
+
+	dprintk(1, "%s()\n", __FUNCTION__);
+	del_timer_sync(&q->timeout);
+	cx23885_stop_dma(port);
+	do_cancel_buffers(port, "cancel", 0);
+}
+
+static void cx23885_timeout(unsigned long data)
+{
+	struct cx23885_tsport *port = (struct cx23885_tsport *)data;
+	struct cx23885_dev *dev = port->dev;
+
+	dprintk(1, "%s()\n",__FUNCTION__);
+
+	if (debug > 5)
+		cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]);
+
+	cx23885_stop_dma(port);
+	do_cancel_buffers(port, "timeout", 1);
+}
+
+static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status)
+{
+	struct cx23885_dev *dev = port->dev;
+	int handled = 0;
+	u32 count;
+
+	if ( (status & VID_BC_MSK_OPC_ERR) ||
+	     (status & VID_BC_MSK_BAD_PKT) ||
+	     (status & VID_BC_MSK_SYNC) ||
+	     (status & VID_BC_MSK_OF))
+	{
+		if (status & VID_BC_MSK_OPC_ERR)
+			dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", VID_BC_MSK_OPC_ERR);
+		if (status & VID_BC_MSK_BAD_PKT)
+			dprintk(7, " (VID_BC_MSK_BAD_PKT 0x%08x)\n", VID_BC_MSK_BAD_PKT);
+		if (status & VID_BC_MSK_SYNC)
+			dprintk(7, " (VID_BC_MSK_SYNC    0x%08x)\n", VID_BC_MSK_SYNC);
+		if (status & VID_BC_MSK_OF)
+			dprintk(7, " (VID_BC_MSK_OF      0x%08x)\n", VID_BC_MSK_OF);
+
+		printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name);
+
+		cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
+		cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]);
+
+	} else if (status & VID_BC_MSK_RISCI1) {
+
+		dprintk(7, " (RISCI1            0x%08x)\n", VID_BC_MSK_RISCI1);
+
+		spin_lock(&port->slock);
+		count = cx_read(port->reg_gpcnt);
+		cx23885_wakeup(port, &port->mpegq, count);
+		spin_unlock(&port->slock);
+
+	} else if (status & VID_BC_MSK_RISCI2) {
+
+		dprintk(7, " (RISCI2            0x%08x)\n", VID_BC_MSK_RISCI2);
+
+		spin_lock(&port->slock);
+		cx23885_restart_queue(port, &port->mpegq);
+		spin_unlock(&port->slock);
+
+	}
+	if (status) {
+		cx_write(port->reg_ts_int_stat, status);
+		handled = 1;
+	}
+
+	return handled;
+}
+
+static irqreturn_t cx23885_irq(int irq, void *dev_id)
+{
+	struct cx23885_dev *dev = dev_id;
+	struct cx23885_tsport *ts1 = &dev->ts1;
+	struct cx23885_tsport *ts2 = &dev->ts2;
+	u32 pci_status, pci_mask;
+	u32 ts1_status, ts1_mask;
+	u32 ts2_status, ts2_mask;
+	int ts1_count = 0, ts2_count = 0, handled = 0;
+
+	pci_status = cx_read(PCI_INT_STAT);
+	pci_mask = cx_read(PCI_INT_MSK);
+	ts1_status = cx_read(VID_B_INT_STAT);
+	ts1_mask = cx_read(VID_B_INT_MSK);
+	ts2_status = cx_read(VID_C_INT_STAT);
+	ts2_mask = cx_read(VID_C_INT_MSK);
+
+	if ( (pci_status == 0) && (ts2_status == 0) && (ts1_status == 0) )
+		goto out;
+
+	ts1_count = cx_read(ts1->reg_gpcnt);
+	ts2_count = cx_read(ts2->reg_gpcnt);
+	dprintk(7, "pci_status: 0x%08x  pci_mask: 0x%08x\n", pci_status, pci_mask );
+	dprintk(7, "ts1_status: 0x%08x  ts1_mask: 0x%08x count: 0x%x\n", ts1_status, ts1_mask, ts1_count );
+	dprintk(7, "ts2_status: 0x%08x  ts2_mask: 0x%08x count: 0x%x\n", ts2_status, ts2_mask, ts2_count );
+
+	if ( (pci_status & PCI_MSK_RISC_RD) ||
+	     (pci_status & PCI_MSK_RISC_WR) ||
+	     (pci_status & PCI_MSK_AL_RD) ||
+	     (pci_status & PCI_MSK_AL_WR) ||
+	     (pci_status & PCI_MSK_APB_DMA) ||
+	     (pci_status & PCI_MSK_VID_C) ||
+	     (pci_status & PCI_MSK_VID_B) ||
+	     (pci_status & PCI_MSK_VID_A) ||
+	     (pci_status & PCI_MSK_AUD_INT) ||
+	     (pci_status & PCI_MSK_AUD_EXT) )
+	{
+
+		if (pci_status & PCI_MSK_RISC_RD)
+			dprintk(7, " (PCI_MSK_RISC_RD   0x%08x)\n", PCI_MSK_RISC_RD);
+		if (pci_status & PCI_MSK_RISC_WR)
+			dprintk(7, " (PCI_MSK_RISC_WR   0x%08x)\n", PCI_MSK_RISC_WR);
+		if (pci_status & PCI_MSK_AL_RD)
+			dprintk(7, " (PCI_MSK_AL_RD     0x%08x)\n", PCI_MSK_AL_RD);
+		if (pci_status & PCI_MSK_AL_WR)
+			dprintk(7, " (PCI_MSK_AL_WR     0x%08x)\n", PCI_MSK_AL_WR);
+		if (pci_status & PCI_MSK_APB_DMA)
+			dprintk(7, " (PCI_MSK_APB_DMA   0x%08x)\n", PCI_MSK_APB_DMA);
+		if (pci_status & PCI_MSK_VID_C)
+			dprintk(7, " (PCI_MSK_VID_C     0x%08x)\n", PCI_MSK_VID_C);
+		if (pci_status & PCI_MSK_VID_B)
+			dprintk(7, " (PCI_MSK_VID_B     0x%08x)\n", PCI_MSK_VID_B);
+		if (pci_status & PCI_MSK_VID_A)
+			dprintk(7, " (PCI_MSK_VID_A     0x%08x)\n", PCI_MSK_VID_A);
+		if (pci_status & PCI_MSK_AUD_INT)
+			dprintk(7, " (PCI_MSK_AUD_INT   0x%08x)\n", PCI_MSK_AUD_INT);
+		if (pci_status & PCI_MSK_AUD_EXT)
+			dprintk(7, " (PCI_MSK_AUD_EXT   0x%08x)\n", PCI_MSK_AUD_EXT);
+
+	}
+
+	if (ts1_status)
+		handled += cx23885_irq_ts(ts1, ts1_status);
+
+	if (ts2_status)
+		handled += cx23885_irq_ts(ts2, ts2_status);
+
+	if (handled)
+		cx_write(PCI_INT_STAT, pci_status);
+out:
+	return IRQ_RETVAL(handled);
+}
+
+static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
+				     const struct pci_device_id *pci_id)
+{
+	struct cx23885_dev *dev;
+	int err;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (NULL == dev)
+		return -ENOMEM;
+
+	/* pci init */
+	dev->pci = pci_dev;
+	if (pci_enable_device(pci_dev)) {
+		err = -EIO;
+		goto fail_free;
+	}
+
+	if (cx23885_dev_setup(dev) < 0) {
+		err = -EINVAL;
+		goto fail_free;
+	}
+
+	/* print pci info */
+	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+	pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
+	printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
+	       "latency: %d, mmio: 0x%llx\n", dev->name,
+	       pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
+	       dev->pci_lat, (unsigned long long)pci_resource_start(pci_dev,0));
+
+	pci_set_master(pci_dev);
+	if (!pci_dma_supported(pci_dev, 0xffffffff)) {
+		printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
+		err = -EIO;
+		goto fail_irq;
+	}
+
+	err = request_irq(pci_dev->irq, cx23885_irq,
+			  IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+	if (err < 0) {
+		printk(KERN_ERR "%s: can't get IRQ %d\n",
+		       dev->name, pci_dev->irq);
+		goto fail_irq;
+	}
+
+	pci_set_drvdata(pci_dev, dev);
+	return 0;
+
+fail_irq:
+	cx23885_dev_unregister(dev);
+fail_free:
+	kfree(dev);
+	return err;
+}
+
+static void __devexit cx23885_finidev(struct pci_dev *pci_dev)
+{
+	struct cx23885_dev *dev = pci_get_drvdata(pci_dev);
+
+	cx23885_shutdown(dev);
+
+	pci_disable_device(pci_dev);
+
+	/* unregister stuff */
+	free_irq(pci_dev->irq, dev);
+	pci_set_drvdata(pci_dev, NULL);
+
+	mutex_lock(&devlist);
+	list_del(&dev->devlist);
+	mutex_unlock(&devlist);
+
+	cx23885_dev_unregister(dev);
+	kfree(dev);
+}
+
+static struct pci_device_id cx23885_pci_tbl[] = {
+	{
+		/* CX23885 */
+		.vendor       = 0x14f1,
+		.device       = 0x8852,
+		.subvendor    = PCI_ANY_ID,
+		.subdevice    = PCI_ANY_ID,
+	},{
+		/* CX23887 Rev 2 */
+		.vendor       = 0x14f1,
+		.device       = 0x8880,
+		.subvendor    = PCI_ANY_ID,
+		.subdevice    = PCI_ANY_ID,
+	},{
+		/* --- end of list --- */
+	}
+};
+MODULE_DEVICE_TABLE(pci, cx23885_pci_tbl);
+
+static struct pci_driver cx23885_pci_driver = {
+	.name     = "cx23885",
+	.id_table = cx23885_pci_tbl,
+	.probe    = cx23885_initdev,
+	.remove   = __devexit_p(cx23885_finidev),
+	/* TODO */
+	.suspend  = NULL,
+	.resume   = NULL,
+};
+
+static int cx23885_init(void)
+{
+	printk(KERN_INFO "cx23885 driver version %d.%d.%d loaded\n",
+	       (CX23885_VERSION_CODE >> 16) & 0xff,
+	       (CX23885_VERSION_CODE >>  8) & 0xff,
+	       CX23885_VERSION_CODE & 0xff);
+#ifdef SNAPSHOT
+	printk(KERN_INFO "cx23885: snapshot date %04d-%02d-%02d\n",
+	       SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
+#endif
+	return pci_register_driver(&cx23885_pci_driver);
+}
+
+static void cx23885_fini(void)
+{
+	pci_unregister_driver(&cx23885_pci_driver);
+}
+
+module_init(cx23885_init);
+module_exit(cx23885_fini);
+
+/* ----------------------------------------------------------- */
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
+ */
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
new file mode 100644
index 0000000..eda8c05
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -0,0 +1,213 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/kthread.h>
+#include <linux/file.h>
+#include <linux/suspend.h>
+
+#include "cx23885.h"
+#include <media/v4l2-common.h>
+
+#include "s5h1409.h"
+#include "mt2131.h"
+#include "lgdt330x.h"
+#include "dvb-pll.h"
+
+static unsigned int debug = 0;
+
+#define dprintk(level,fmt, arg...)	if (debug >= level) \
+	printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg)
+
+/* ------------------------------------------------------------------ */
+
+static int dvb_buf_setup(struct videobuf_queue *q,
+			 unsigned int *count, unsigned int *size)
+{
+	struct cx23885_tsport *port = q->priv_data;
+
+	port->ts_packet_size  = 188 * 4;
+	port->ts_packet_count = 32;
+
+	*size  = port->ts_packet_size * port->ts_packet_count;
+	*count = 32;
+	return 0;
+}
+
+static int dvb_buf_prepare(struct videobuf_queue *q,
+			   struct videobuf_buffer *vb, enum v4l2_field field)
+{
+	struct cx23885_tsport *port = q->priv_data;
+	return cx23885_buf_prepare(q, port, (struct cx23885_buffer*)vb, field);
+}
+
+static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+	struct cx23885_tsport *port = q->priv_data;
+	cx23885_buf_queue(port, (struct cx23885_buffer*)vb);
+}
+
+static void dvb_buf_release(struct videobuf_queue *q,
+			    struct videobuf_buffer *vb)
+{
+	cx23885_free_buffer(q, (struct cx23885_buffer*)vb);
+}
+
+static struct videobuf_queue_ops dvb_qops = {
+	.buf_setup    = dvb_buf_setup,
+	.buf_prepare  = dvb_buf_prepare,
+	.buf_queue    = dvb_buf_queue,
+	.buf_release  = dvb_buf_release,
+};
+
+static struct s5h1409_config hauppauge_generic_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_SERIAL_OUTPUT,
+	.gpio          = S5H1409_GPIO_ON,
+	.if_freq       = 44000,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING
+};
+
+static struct s5h1409_config hauppauge_hvr1800lp_config = {
+	.demod_address = 0x32 >> 1,
+	.output_mode   = S5H1409_SERIAL_OUTPUT,
+	.gpio          = S5H1409_GPIO_OFF,
+	.if_freq       = 44000,
+	.inversion     = S5H1409_INVERSION_OFF,
+	.status_mode   = S5H1409_DEMODLOCKING
+};
+
+static struct mt2131_config hauppauge_generic_tunerconfig = {
+	0x61
+};
+
+static struct lgdt330x_config fusionhdtv_5_express = {
+	.demod_address = 0x0e,
+	.demod_chip = LGDT3303,
+	.serial_mpeg = 0x40,
+};
+
+static int dvb_register(struct cx23885_tsport *port)
+{
+	struct cx23885_dev *dev = port->dev;
+	struct cx23885_i2c *i2c_bus = NULL;
+
+	/* init struct videobuf_dvb */
+	port->dvb.name = dev->name;
+
+	/* init frontend */
+	switch (dev->board) {
+	case CX23885_BOARD_HAUPPAUGE_HVR1250:
+	case CX23885_BOARD_HAUPPAUGE_HVR1800:
+		i2c_bus = &dev->i2c_bus[0];
+		port->dvb.frontend = dvb_attach(s5h1409_attach,
+						&hauppauge_generic_config,
+						&i2c_bus->i2c_adap);
+		if (port->dvb.frontend != NULL) {
+			dvb_attach(mt2131_attach, port->dvb.frontend,
+				   &i2c_bus->i2c_adap,
+				   &hauppauge_generic_tunerconfig, 0);
+		}
+		break;
+	case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+		i2c_bus = &dev->i2c_bus[0];
+		port->dvb.frontend = dvb_attach(s5h1409_attach,
+						&hauppauge_hvr1800lp_config,
+						&i2c_bus->i2c_adap);
+		if (port->dvb.frontend != NULL) {
+			dvb_attach(mt2131_attach, port->dvb.frontend,
+				   &i2c_bus->i2c_adap,
+				   &hauppauge_generic_tunerconfig, 0);
+		}
+		break;
+	case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
+		i2c_bus = &dev->i2c_bus[0];
+		port->dvb.frontend = dvb_attach(lgdt330x_attach,
+						&fusionhdtv_5_express,
+						&i2c_bus->i2c_adap);
+		if (port->dvb.frontend != NULL) {
+			dvb_attach(dvb_pll_attach, port->dvb.frontend, 0x61,
+				   &i2c_bus->i2c_adap, DVB_PLL_LG_TDVS_H06XF);
+		}
+		break;
+	default:
+		printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
+		       dev->name);
+		break;
+	}
+	if (NULL == port->dvb.frontend) {
+		printk("%s: frontend initialization failed\n", dev->name);
+		return -1;
+	}
+
+	/* Put the analog decoder in standby to keep it quiet */
+	cx23885_call_i2c_clients(i2c_bus, TUNER_SET_STANDBY, NULL);
+
+	/* register everything */
+	return videobuf_dvb_register(&port->dvb, THIS_MODULE, port,
+				     &dev->pci->dev);
+}
+
+int cx23885_dvb_register(struct cx23885_tsport *port)
+{
+	struct cx23885_dev *dev = port->dev;
+	int err;
+
+	dprintk(1, "%s\n", __FUNCTION__);
+	dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
+		dev->board,
+		dev->name,
+		dev->pci_bus,
+		dev->pci_slot);
+
+	err = -ENODEV;
+
+	/* dvb stuff */
+	printk("%s: cx23885 based dvb card\n", dev->name);
+	videobuf_queue_pci_init(&port->dvb.dvbq, &dvb_qops, dev->pci, &port->slock,
+			    V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
+			    sizeof(struct cx23885_buffer), port);
+	err = dvb_register(port);
+	if (err != 0)
+		printk("%s() dvb_register failed err = %d\n", __FUNCTION__, err);
+
+	return err;
+}
+
+int cx23885_dvb_unregister(struct cx23885_tsport *port)
+{
+	/* dvb */
+	if(port->dvb.frontend)
+		videobuf_dvb_unregister(&port->dvb);
+
+	return 0;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
+*/
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
new file mode 100644
index 0000000..b517c8b
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-i2c.c
@@ -0,0 +1,382 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include "cx23885.h"
+
+#include <media/v4l2-common.h>
+
+static unsigned int i2c_debug = 0;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+static unsigned int i2c_scan = 0;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+#define dprintk(level,fmt, arg...)	if (i2c_debug >= level) \
+	printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg)
+
+#define I2C_WAIT_DELAY 32
+#define I2C_WAIT_RETRY 64
+
+#define I2C_EXTEND  (1 << 3)
+#define I2C_NOSTOP  (1 << 4)
+
+static inline int i2c_slave_did_ack(struct i2c_adapter *i2c_adap)
+{
+	struct cx23885_i2c *bus = i2c_adap->algo_data;
+	struct cx23885_dev *dev = bus->dev;
+	return cx_read(bus->reg_stat) & 0x01;
+}
+
+static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)
+{
+	struct cx23885_i2c *bus = i2c_adap->algo_data;
+	struct cx23885_dev *dev = bus->dev;
+	return cx_read(bus->reg_stat) & 0x02 ? 1 : 0;
+}
+
+static int i2c_wait_done(struct i2c_adapter *i2c_adap)
+{
+	int count;
+
+	for (count = 0; count < I2C_WAIT_RETRY; count++) {
+		if (!i2c_is_busy(i2c_adap))
+			break;
+		udelay(I2C_WAIT_DELAY);
+	}
+
+	if (I2C_WAIT_RETRY == count)
+		return 0;
+
+	return 1;
+}
+
+static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
+			 const struct i2c_msg *msg, int last)
+{
+	struct cx23885_i2c *bus = i2c_adap->algo_data;
+	struct cx23885_dev *dev = bus->dev;
+	u32 wdata, addr, ctrl;
+	int retval, cnt;
+
+	dprintk(1, "%s()\n", __FUNCTION__);
+	/* Deal with i2c probe functions with zero payload */
+	if (msg->len == 0) {
+		cx_write(bus->reg_addr, msg->addr << 25);
+		cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2));
+		if (!i2c_wait_done(i2c_adap))
+			return -EIO;
+		if (!i2c_slave_did_ack(i2c_adap))
+			return -EIO;
+
+		dprintk(1, "%s() returns 0\n", __FUNCTION__);
+		return 0;
+	}
+
+
+	/* dev, reg + first byte */
+	addr = (msg->addr << 25) | msg->buf[0];
+	wdata = msg->buf[0];
+	ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
+
+	if (msg->len > 1)
+		ctrl |= I2C_NOSTOP | I2C_EXTEND;
+
+	cx_write(bus->reg_addr, addr);
+	cx_write(bus->reg_wdata, wdata);
+	cx_write(bus->reg_ctrl, ctrl);
+
+	retval = i2c_wait_done(i2c_adap);
+	if (retval < 0)
+		goto err;
+	if (retval == 0)
+		goto eio;
+	if (i2c_debug) {
+		printk(" <W %02x %02x", msg->addr << 1, msg->buf[0]);
+		if (!(ctrl & I2C_NOSTOP))
+			printk(" >\n");
+	}
+
+	for (cnt = 1; cnt < msg->len; cnt++ ) {
+		/* following bytes */
+		wdata = msg->buf[cnt];
+		ctrl = bus->i2c_period | (1 << 12) | (1 << 2);
+
+		if (cnt < msg->len-1 || !last)
+			ctrl |= I2C_NOSTOP | I2C_EXTEND;
+
+		cx_write(bus->reg_addr, addr);
+		cx_write(bus->reg_wdata, wdata);
+		cx_write(bus->reg_ctrl, ctrl);
+
+		retval = i2c_wait_done(i2c_adap);
+		if (retval < 0)
+			goto err;
+		if (retval == 0)
+			goto eio;
+		if (i2c_debug) {
+			printk(" %02x", msg->buf[cnt]);
+			if (!(ctrl & I2C_NOSTOP))
+				printk(" >\n");
+		}
+	}
+	return msg->len;
+
+ eio:
+	retval = -EIO;
+ err:
+	printk(" ERR: %d\n", retval);
+	return retval;
+}
+
+static int i2c_readbytes(struct i2c_adapter *i2c_adap,
+			 const struct i2c_msg *msg, int last)
+{
+	struct cx23885_i2c *bus = i2c_adap->algo_data;
+	struct cx23885_dev *dev = bus->dev;
+	u32 ctrl, cnt;
+	int retval;
+
+	dprintk(1, "%s()\n", __FUNCTION__);
+
+	/* Deal with i2c probe functions with zero payload */
+	if (msg->len == 0) {
+		cx_write(bus->reg_addr, msg->addr << 25);
+		cx_write(bus->reg_ctrl, bus->i2c_period | (1 << 2) | 1);
+		if (!i2c_wait_done(i2c_adap))
+			return -EIO;
+		if (!i2c_slave_did_ack(i2c_adap))
+			return -EIO;
+
+
+		dprintk(1, "%s() returns 0\n", __FUNCTION__);
+		return 0;
+	}
+
+	for(cnt = 0; cnt < msg->len; cnt++) {
+
+		ctrl = bus->i2c_period | (1 << 12) | (1 << 2) | 1;
+
+		if (cnt < msg->len-1 || !last)
+			ctrl |= I2C_NOSTOP | I2C_EXTEND;
+
+		cx_write(bus->reg_addr, msg->addr << 25);
+		cx_write(bus->reg_ctrl, ctrl);
+
+		retval = i2c_wait_done(i2c_adap);
+		if (retval < 0)
+			goto err;
+		if (retval == 0)
+			goto eio;
+		msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff;
+		if (i2c_debug) {
+			if (!(ctrl & I2C_NOSTOP))
+				printk(" <R %02x", (msg->addr << 1) +1);
+			printk(" =%02x", msg->buf[cnt]);
+			if (!(ctrl & I2C_NOSTOP))
+				printk(" >\n");
+		}
+	}
+	return msg->len;
+
+ eio:
+	retval = -EIO;
+ err:
+	printk(" ERR: %d\n", retval);
+	return retval;
+}
+
+static int i2c_xfer(struct i2c_adapter *i2c_adap,
+		    struct i2c_msg *msgs, int num)
+{
+	struct cx23885_i2c *bus = i2c_adap->algo_data;
+	struct cx23885_dev *dev = bus->dev;
+	int i, retval = 0;
+
+	dprintk(1, "%s(num = %d)\n", __FUNCTION__, num);
+
+	for (i = 0 ; i < num; i++) {
+		dprintk(1, "%s(num = %d) addr = 0x%02x  len = 0x%x\n",
+			__FUNCTION__, num, msgs[i].addr, msgs[i].len);
+		if (msgs[i].flags & I2C_M_RD) {
+			/* read */
+			retval = i2c_readbytes(i2c_adap, &msgs[i], i+1 == num);
+			if (retval < 0)
+				goto err;
+		} else {
+			/* write */
+			retval = i2c_sendbytes(i2c_adap, &msgs[i], i+1 == num);
+			if (retval < 0)
+				goto err;
+		}
+	}
+	return num;
+
+ err:
+	return retval;
+}
+
+static int attach_inform(struct i2c_client *client)
+{
+	struct cx23885_dev *dev = i2c_get_adapdata(client->adapter);
+
+	dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
+		client->driver->driver.name, client->addr, client->name);
+
+	if (!client->driver->command)
+		return 0;
+
+	return 0;
+}
+
+static int detach_inform(struct i2c_client *client)
+{
+	struct cx23885_dev *dev = i2c_get_adapdata(client->adapter);
+
+	dprintk(1, "i2c detach [client=%s]\n", client->name);
+
+	return 0;
+}
+
+void cx23885_call_i2c_clients(struct cx23885_i2c *bus,
+			      unsigned int cmd, void *arg)
+{
+	if (bus->i2c_rc != 0)
+		return;
+
+	i2c_clients_command(&bus->i2c_adap, cmd, arg);
+}
+
+static int cx23885_algo_control(struct i2c_adapter *adap,
+				unsigned int cmd, unsigned long arg)
+{
+	return 0;
+}
+
+static u32 cx23885_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm cx23885_i2c_algo_template = {
+	.master_xfer	= i2c_xfer,
+	.algo_control	= cx23885_algo_control,
+	.functionality	= cx23885_functionality,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_adapter cx23885_i2c_adap_template = {
+	.name              = "cx23885",
+	.owner             = THIS_MODULE,
+	.id                = I2C_HW_B_CX23885,
+	.algo              = &cx23885_i2c_algo_template,
+	.client_register   = attach_inform,
+	.client_unregister = detach_inform,
+};
+
+static struct i2c_client cx23885_i2c_client_template = {
+	.name	= "cx23885 internal",
+};
+
+static char *i2c_devs[128] = {
+	[ 0x1c >> 1 ] = "lgdt3303",
+	[ 0x86 >> 1 ] = "tda9887",
+	[ 0x32 >> 1 ] = "cx24227",
+	[ 0x88 >> 1 ] = "cx25837",
+	[ 0x84 >> 1 ] = "tda8295",
+	[ 0xa0 >> 1 ] = "eeprom",
+	[ 0xc0 >> 1 ] = "tuner/mt2131/tda8275",
+	[ 0xc2 >> 1 ] = "tuner/mt2131/tda8275",
+};
+
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+	unsigned char buf;
+	int i, rc;
+
+	for (i = 0; i < 128; i++) {
+		c->addr = i;
+		rc = i2c_master_recv(c, &buf, 0);
+		if (rc < 0)
+			continue;
+		printk("%s: i2c scan: found device @ 0x%x  [%s]\n",
+		       name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+	}
+}
+
+/* init + register i2c algo-bit adapter */
+int cx23885_i2c_register(struct cx23885_i2c *bus)
+{
+	struct cx23885_dev *dev = bus->dev;
+
+	dprintk(1, "%s(bus = %d)\n", __FUNCTION__, bus->nr);
+
+	memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template,
+	       sizeof(bus->i2c_adap));
+	memcpy(&bus->i2c_algo, &cx23885_i2c_algo_template,
+	       sizeof(bus->i2c_algo));
+	memcpy(&bus->i2c_client, &cx23885_i2c_client_template,
+	       sizeof(bus->i2c_client));
+
+	bus->i2c_adap.dev.parent = &dev->pci->dev;
+
+	strlcpy(bus->i2c_adap.name, bus->dev->name,
+		sizeof(bus->i2c_adap.name));
+
+	bus->i2c_algo.data = bus;
+	bus->i2c_adap.algo_data = bus;
+	i2c_add_adapter(&bus->i2c_adap);
+
+	bus->i2c_client.adapter = &bus->i2c_adap;
+
+	if (0 == bus->i2c_rc) {
+		printk("%s: i2c bus %d registered\n", dev->name, bus->nr);
+		if (i2c_scan)
+			do_i2c_scan(dev->name, &bus->i2c_client);
+	} else
+		printk("%s: i2c bus %d register FAILED\n", dev->name, bus->nr);
+
+	return bus->i2c_rc;
+}
+
+int cx23885_i2c_unregister(struct cx23885_i2c *bus)
+{
+	i2c_del_adapter(&bus->i2c_adap);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+EXPORT_SYMBOL(cx23885_call_i2c_clients);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h
new file mode 100644
index 0000000..162169f
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-reg.h
@@ -0,0 +1,431 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _CX23885_REG_H_
+#define _CX23885_REG_H_
+
+/*
+Address Map
+0x00000000 -> 0x00009000   TX SRAM  (Fifos)
+0x00010000 -> 0x00013c00   RX SRAM  CMDS + CDT
+
+EACH CMDS struct is 0x80 bytes long
+
+DMAx_PTR1 = 0x03040 address of first cluster
+DMAx_PTR2 = 0x10600 address of the CDT
+DMAx_CNT1 = cluster size in (bytes >> 4) -1
+DMAx_CNT2 = total cdt size for all entries >> 3
+
+Cluster Descriptor entry = 4 DWORDS
+ DWORD 0 -> ptr to cluster
+ DWORD 1 Reserved
+ DWORD 2 Reserved
+ DWORD 3 Reserved
+
+Channel manager Data Structure entry = 20 DWORD
+  0  IntialProgramCounterLow
+  1  IntialProgramCounterHigh
+  2  ClusterDescriptorTableBase
+  3  ClusterDescriptorTableSize
+  4  InstructionQueueBase
+  5  InstructionQueueSize
+...  Reserved
+ 19  Reserved
+*/
+
+/* Risc Instructions */
+#define RISC_CNT_INC		 0x00010000
+#define RISC_CNT_RESET		 0x00030000
+#define RISC_IRQ1		 0x01000000
+#define RISC_IRQ2		 0x02000000
+#define RISC_EOL		 0x04000000
+#define RISC_SOL		 0x08000000
+#define RISC_WRITE		 0x10000000
+#define RISC_SKIP		 0x20000000
+#define RISC_JUMP		 0x70000000
+#define RISC_SYNC		 0x80000000
+#define RISC_RESYNC		 0x80008000
+#define RISC_READ		 0x90000000
+#define RISC_WRITERM		 0xB0000000
+#define RISC_WRITECM		 0xC0000000
+#define RISC_WRITECR		 0xD0000000
+#define RISC_WRITEC		 0x50000000
+#define RISC_READC		 0xA0000000
+
+
+/* Audio and Video Core */
+#define HOST_REG1		0x00000000
+#define HOST_REG2		0x00000001
+#define HOST_REG3		0x00000002
+
+/* Chip Configuration Registers */
+#define CHIP_CTRL		0x00000100
+#define AFE_CTRL		0x00000104
+#define VID_PLL_INT_POST	0x00000108
+#define VID_PLL_FRAC		0x0000010C
+#define AUX_PLL_INT_POST	0x00000110
+#define AUX_PLL_FRAC		0x00000114
+#define SYS_PLL_INT_POST	0x00000118
+#define SYS_PLL_FRAC		0x0000011C
+#define PIN_CTRL		0x00000120
+#define AUD_IO_CTRL		0x00000124
+#define AUD_LOCK1		0x00000128
+#define AUD_LOCK2		0x0000012C
+#define POWER_CTRL		0x00000130
+#define AFE_DIAG_CTRL1		0x00000134
+#define AFE_DIAG_CTRL3		0x0000013C
+#define PLL_DIAG_CTRL		0x00000140
+#define AFE_CLK_OUT_CTRL	0x00000144
+#define DLL1_DIAG_CTRL		0x0000015C
+
+/* GPIO[23:19] Output Enable */
+#define GPIO2_OUT_EN_REG	0x00000160
+/* GPIO[23:19] Data Registers */
+#define GPIO2			0x00000164
+
+#define IFADC_CTRL		0x00000180
+
+/* Infrared Remote Registers */
+#define IR_CNTRL_REG	0x00000200
+#define IR_TXCLK_REG	0x00000204
+#define IR_RXCLK_REG	0x00000208
+#define IR_CDUTY_REG	0x0000020C
+#define IR_STAT_REG	0x00000210
+#define IR_IRQEN_REG	0x00000214
+#define IR_FILTR_REG	0x00000218
+#define IR_FIFO_REG	0x0000023C
+
+/* Video Decoder Registers */
+#define MODE_CTRL		0x00000400
+#define OUT_CTRL1		0x00000404
+#define OUT_CTRL2		0x00000408
+#define GEN_STAT		0x0000040C
+#define INT_STAT_MASK		0x00000410
+#define LUMA_CTRL		0x00000414
+#define HSCALE_CTRL		0x00000418
+#define VSCALE_CTRL		0x0000041C
+#define CHROMA_CTRL		0x00000420
+#define VBI_LINE_CTRL1		0x00000424
+#define VBI_LINE_CTRL2		0x00000428
+#define VBI_LINE_CTRL3		0x0000042C
+#define VBI_LINE_CTRL4		0x00000430
+#define VBI_LINE_CTRL5		0x00000434
+#define VBI_FC_CFG		0x00000438
+#define VBI_MISC_CFG1		0x0000043C
+#define VBI_MISC_CFG2		0x00000440
+#define VBI_PAY1		0x00000444
+#define VBI_PAY2		0x00000448
+#define VBI_CUST1_CFG1		0x0000044C
+#define VBI_CUST1_CFG2		0x00000450
+#define VBI_CUST1_CFG3		0x00000454
+#define VBI_CUST2_CFG1		0x00000458
+#define VBI_CUST2_CFG2		0x0000045C
+#define VBI_CUST2_CFG3		0x00000460
+#define VBI_CUST3_CFG1		0x00000464
+#define VBI_CUST3_CFG2		0x00000468
+#define VBI_CUST3_CFG3		0x0000046C
+#define HORIZ_TIM_CTRL		0x00000470
+#define VERT_TIM_CTRL		0x00000474
+#define SRC_COMB_CFG		0x00000478
+#define CHROMA_VBIOFF_CFG	0x0000047C
+#define FIELD_COUNT		0x00000480
+#define MISC_TIM_CTRL		0x00000484
+#define DFE_CTRL1		0x00000488
+#define DFE_CTRL2		0x0000048C
+#define DFE_CTRL3		0x00000490
+#define PLL_CTRL		0x00000494
+#define HTL_CTRL		0x00000498
+#define COMB_CTRL		0x0000049C
+#define CRUSH_CTRL		0x000004A0
+#define SOFT_RST_CTRL		0x000004A4
+#define CX885_VERSION		0x000004B4
+#define VBI_PASS_CTRL		0x000004BC
+
+/* Audio Decoder Registers */
+/* 8051 Configuration */
+#define DL_CTL		0x00000800
+#define STD_DET_STATUS	0x00000804
+#define STD_DET_CTL	0x00000808
+#define DW8051_INT	0x0000080C
+#define GENERAL_CTL	0x00000810
+#define AAGC_CTL	0x00000814
+#define DEMATRIX_CTL	0x000008CC
+#define PATH1_CTL1	0x000008D0
+#define PATH1_VOL_CTL	0x000008D4
+#define PATH1_EQ_CTL	0x000008D8
+#define PATH1_SC_CTL	0x000008DC
+#define PATH2_CTL1	0x000008E0
+#define PATH2_VOL_CTL	0x000008E4
+#define PATH2_EQ_CTL	0x000008E8
+#define PATH2_SC_CTL	0x000008EC
+
+/* Sample Rate Converter */
+#define SRC_CTL		0x000008F0
+#define SRC_LF_COEF	0x000008F4
+#define SRC1_CTL	0x000008F8
+#define SRC2_CTL	0x000008FC
+#define SRC3_CTL	0x00000900
+#define SRC4_CTL	0x00000904
+#define SRC5_CTL	0x00000908
+#define SRC6_CTL	0x0000090C
+#define BAND_OUT_SEL	0x00000910
+#define I2S_N_CTL	0x00000914
+#define I2S_OUT_CTL	0x00000918
+#define AUTOCONFIG_REG	0x000009C4
+
+/* Audio ADC Registers */
+#define DSM_CTRL1	0x00000000
+#define DSM_CTRL2	0x00000001
+#define CHP_EN_CTRL	0x00000002
+#define CHP_CLK_CTRL1	0x00000004
+#define CHP_CLK_CTRL2	0x00000005
+#define BG_REF_CTRL	0x00000006
+#define SD2_SW_CTRL1	0x00000008
+#define SD2_SW_CTRL2	0x00000009
+#define SD2_BIAS_CTRL	0x0000000A
+#define AMP_BIAS_CTRL	0x0000000C
+#define CH_PWR_CTRL1	0x0000000E
+#define CH_PWR_CTRL2	0x0000000F
+#define DSM_STATUS1	0x00000010
+#define DSM_STATUS2	0x00000011
+#define DIG_CTL1	0x00000012
+#define DIG_CTL2	0x00000013
+#define I2S_TX_CFG	0x0000001A
+
+#define DEV_CNTRL2	0x00040000
+
+#define PCI_MSK_APB_DMA   (1 << 12)
+#define PCI_MSK_AL_WR     (1 << 11)
+#define PCI_MSK_AL_RD     (1 << 10)
+#define PCI_MSK_RISC_WR   (1 <<  9)
+#define PCI_MSK_RISC_RD   (1 <<  8)
+#define PCI_MSK_AUD_EXT   (1 <<  4)
+#define PCI_MSK_AUD_INT   (1 <<  3)
+#define PCI_MSK_VID_C     (1 <<  2)
+#define PCI_MSK_VID_B     (1 <<  1)
+#define PCI_MSK_VID_A      1
+#define PCI_INT_MSK	0x00040010
+
+#define PCI_INT_STAT	0x00040014
+#define PCI_INT_MSTAT	0x00040018
+
+#define VID_A_INT_MSK	0x00040020
+#define VID_A_INT_STAT	0x00040024
+#define VID_A_INT_MSTAT	0x00040028
+#define VID_A_INT_SSTAT	0x0004002C
+
+#define VID_B_INT_MSK	0x00040030
+#define VID_B_INT_STAT	0x00040034
+#define VID_B_INT_MSTAT	0x00040038
+#define VID_B_INT_SSTAT	0x0004003C
+
+#define VID_B_MSK_BAD_PKT (1 << 20)
+#define VID_B_MSK_OPC_ERR (1 << 16)
+#define VID_B_MSK_SYNC    (1 << 12)
+#define VID_B_MSK_OF      (1 <<  8)
+#define VID_B_MSK_RISCI2  (1 <<  4)
+#define VID_B_MSK_RISCI1   1
+
+#define VID_C_MSK_BAD_PKT (1 << 20)
+#define VID_C_MSK_OPC_ERR (1 << 16)
+#define VID_C_MSK_SYNC    (1 << 12)
+#define VID_C_MSK_OF      (1 <<  8)
+#define VID_C_MSK_RISCI2  (1 <<  4)
+#define VID_C_MSK_RISCI1   1
+
+/* A superset for testing purposes */
+#define VID_BC_MSK_BAD_PKT (1 << 20)
+#define VID_BC_MSK_OPC_ERR (1 << 16)
+#define VID_BC_MSK_SYNC    (1 << 12)
+#define VID_BC_MSK_OF      (1 <<  8)
+#define VID_BC_MSK_RISCI2  (1 <<  4)
+#define VID_BC_MSK_RISCI1   1
+
+#define VID_C_INT_MSK	0x00040040
+#define VID_C_INT_STAT	0x00040044
+#define VID_C_INT_MSTAT	0x00040048
+#define VID_C_INT_SSTAT	0x0004004C
+
+#define AUDIO_INT_INT_MSK	0x00040050
+#define AUDIO_INT_INT_STAT	0x00040054
+#define AUDIO_INT_INT_MSTAT	0x00040058
+#define AUDIO_INT_INT_SSTAT	0x0004005C
+
+#define AUDIO_EXT_INT_MSK	0x00040060
+#define AUDIO_EXT_INT_STAT	0x00040064
+#define AUDIO_EXT_INT_MSTAT	0x00040068
+#define AUDIO_EXT_INT_SSTAT	0x0004006C
+
+#define RDR_CFG0	0x00050000
+#define RDR_CFG1	0x00050004
+#define RDR_TLCTL0	0x00050318
+
+/* APB DMAC Current Buffer Pointer */
+#define DMA1_PTR1	0x00100000
+#define DMA2_PTR1	0x00100004
+#define DMA3_PTR1	0x00100008
+#define DMA4_PTR1	0x0010000C
+#define DMA5_PTR1	0x00100010
+#define DMA6_PTR1	0x00100014
+#define DMA7_PTR1	0x00100018
+#define DMA8_PTR1	0x0010001C
+
+/* APB DMAC Current Table Pointer */
+#define DMA1_PTR2	0x00100040
+#define DMA2_PTR2	0x00100044
+#define DMA3_PTR2	0x00100048
+#define DMA4_PTR2	0x0010004C
+#define DMA5_PTR2	0x00100050
+#define DMA6_PTR2	0x00100054
+#define DMA7_PTR2	0x00100058
+#define DMA8_PTR2	0x0010005C
+
+/* APB DMAC Buffer Limit */
+#define DMA1_CNT1	0x00100080
+#define DMA2_CNT1	0x00100084
+#define DMA3_CNT1	0x00100088
+#define DMA4_CNT1	0x0010008C
+#define DMA5_CNT1	0x00100090
+#define DMA6_CNT1	0x00100094
+#define DMA7_CNT1	0x00100098
+#define DMA8_CNT1	0x0010009C
+
+/* APB DMAC Table Size */
+#define DMA1_CNT2	0x001000C0
+#define DMA2_CNT2	0x001000C4
+#define DMA3_CNT2	0x001000C8
+#define DMA4_CNT2	0x001000CC
+#define DMA5_CNT2	0x001000D0
+#define DMA6_CNT2	0x001000D4
+#define DMA7_CNT2	0x001000D8
+#define DMA8_CNT2	0x001000DC
+
+/* Timer Counters */
+#define TM_CNT_LDW	0x00110000
+#define TM_CNT_UW	0x00110004
+#define TM_LMT_LDW	0x00110008
+#define TM_LMT_UW	0x0011000C
+
+/* GPIO */
+#define GP0_IO		0x00110010
+#define GPIO_ISM	0x00110014
+#define SOFT_RESET	0x0011001C
+
+/* GPIO (417 Microsoftcontroller) RW Data */
+#define MC417_RWD	0x00110020
+
+/* GPIO (417 Microsoftcontroller) Output Enable, Low Active */
+#define MC417_OEN	0x00110024
+#define MC417_CTL	0x00110028
+#define CLK_DELAY	0x00110048
+#define PAD_CTRL	0x0011004C
+
+/* Video A Interface */
+#define VID_A_GPCNT		0x00130020
+#define VBI_A_GPCNT		0x00130024
+#define VID_A_GPCNT_CTL		0x00130030
+#define VBI_A_GPCNT_CTL		0x00130034
+#define VID_A_DMA_CTL		0x00130040
+#define VID_A_VIP_CTRL		0x00130080
+#define VID_A_PIXEL_FRMT	0x00130084
+#define VID_A_VBI_CTRL		0x00130088
+
+/* Video B Interface */
+#define VID_B_DMA		0x00130100
+#define VBI_B_DMA		0x00130108
+#define VID_B_GPCNT		0x00130120
+#define VBI_B_GPCNT		0x00130124
+#define VID_B_GPCNT_CTL		0x00130134
+#define VBI_B_GPCNT_CTL		0x00130138
+#define VID_B_DMA_CTL		0x00130140
+#define VID_B_SRC_SEL		0x00130144
+#define VID_B_LNGTH		0x00130150
+#define VID_B_HW_SOP_CTL	0x00130154
+#define VID_B_GEN_CTL		0x00130158
+#define VID_B_BD_PKT_STATUS	0x0013015C
+#define VID_B_SOP_STATUS	0x00130160
+#define VID_B_FIFO_OVFL_STAT	0x00130164
+#define VID_B_VLD_MISC		0x00130168
+#define VID_B_TS_CLK_EN		0x0013016C
+#define VID_B_VIP_CTRL		0x00130180
+#define VID_B_PIXEL_FRMT	0x00130184
+
+/* Video C Interface */
+#define VID_C_GPCNT		0x00130220
+#define VID_C_GPCNT_CTL		0x00130230
+#define VBI_C_GPCNT_CTL		0x00130234
+#define VID_C_DMA_CTL		0x00130240
+#define VID_C_LNGTH		0x00130250
+#define VID_C_HW_SOP_CTL	0x00130254
+#define VID_C_GEN_CTL		0x00130258
+#define VID_C_BD_PKT_STATUS	0x0013025C
+#define VID_C_SOP_STATUS	0x00130260
+#define VID_C_FIFO_OVFL_STAT	0x00130264
+#define VID_C_VLD_MISC		0x00130268
+#define VID_C_TS_CLK_EN		0x0013026C
+
+/* Internal Audio Interface */
+#define AUD_INT_A_GPCNT		0x00140020
+#define AUD_INT_B_GPCNT		0x00140024
+#define AUD_INT_A_GPCNT_CTL	0x00140030
+#define AUD_INT_B_GPCNT_CTL	0x00140034
+#define AUD_INT_DMA_CTL		0x00140040
+#define AUD_INT_A_LNGTH		0x00140050
+#define AUD_INT_B_LNGTH		0x00140054
+#define AUD_INT_A_MODE		0x00140058
+#define AUD_INT_B_MODE		0x0014005C
+
+/* External Audio Interface */
+#define AUD_EXT_DMA		0x00140100
+#define AUD_EXT_GPCNT		0x00140120
+#define AUD_EXT_GPCNT_CTL	0x00140130
+#define AUD_EXT_DMA_CTL		0x00140140
+#define AUD_EXT_LNGTH		0x00140150
+#define AUD_EXT_A_MODE		0x00140158
+
+/* I2C Bus 1 */
+#define I2C1_ADDR	0x00180000
+#define I2C1_WDATA	0x00180004
+#define I2C1_CTRL	0x00180008
+#define I2C1_RDATA	0x0018000C
+#define I2C1_STAT	0x00180010
+
+/* I2C Bus 2 */
+#define I2C2_ADDR	0x00190000
+#define I2C2_WDATA	0x00190004
+#define I2C2_CTRL	0x00190008
+#define I2C2_RDATA	0x0019000C
+#define I2C2_STAT	0x00190010
+
+/* I2C Bus 3 */
+#define I2C3_ADDR	0x001A0000
+#define I2C3_WDATA	0x001A0004
+#define I2C3_CTRL	0x001A0008
+#define I2C3_RDATA	0x001A000C
+#define I2C3_STAT	0x001A0010
+
+/* UART */
+#define UART_CTL	0x001B0000
+#define UART_BRD	0x001B0004
+#define UART_ISR	0x001B000C
+#define UART_CNT	0x001B0010
+
+#endif /* _CX23885_REG_H_ */
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
new file mode 100644
index 0000000..dec4dc2
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -0,0 +1,301 @@
+/*
+ *  Driver for the Conexant CX23885 PCIe bridge
+ *
+ *  Copyright (c) 2006 Steven Toth <stoth@hauppauge.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/pci.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/kdev_t.h>
+
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include <media/tveeprom.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/videobuf-dvb.h>
+
+#include "btcx-risc.h"
+#include "cx23885-reg.h"
+
+#include <linux/version.h>
+#include <linux/mutex.h>
+
+#define CX23885_VERSION_CODE KERNEL_VERSION(0,0,1)
+
+#define UNSET (-1U)
+
+#define CX23885_MAXBOARDS 8
+
+/* Max number of inputs by card */
+#define MAX_CX23885_INPUT 8
+
+#define BUFFER_TIMEOUT     (HZ)  /* 0.5 seconds */
+
+#define CX23885_BOARD_NOAUTO               UNSET
+#define CX23885_BOARD_UNKNOWN                  0
+#define CX23885_BOARD_HAUPPAUGE_HVR1800lp      1
+#define CX23885_BOARD_HAUPPAUGE_HVR1800        2
+#define CX23885_BOARD_HAUPPAUGE_HVR1250        3
+#define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP   4
+
+enum cx23885_itype {
+	CX23885_VMUX_COMPOSITE1 = 1,
+	CX23885_VMUX_COMPOSITE2,
+	CX23885_VMUX_COMPOSITE3,
+	CX23885_VMUX_COMPOSITE4,
+	CX23885_VMUX_SVIDEO,
+	CX23885_VMUX_TELEVISION,
+	CX23885_VMUX_CABLE,
+	CX23885_VMUX_DVB,
+	CX23885_VMUX_DEBUG,
+	CX23885_RADIO,
+};
+
+enum cx23885_src_sel_type {
+	CX23885_SRC_SEL_EXT_656_VIDEO = 0,
+	CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO
+};
+
+/* buffer for one video frame */
+struct cx23885_buffer {
+	/* common v4l buffer stuff -- must be first */
+	struct videobuf_buffer vb;
+
+	/* cx23885 specific */
+	unsigned int           bpl;
+	struct btcx_riscmem    risc;
+	struct cx23885_fmt     *fmt;
+	u32                    count;
+};
+
+struct cx23885_input {
+	enum cx23885_itype type;
+	unsigned int    vmux;
+	u32             gpio0, gpio1, gpio2, gpio3;
+};
+
+typedef enum {
+	CX23885_MPEG_UNDEFINED = 0,
+	CX23885_MPEG_DVB
+} port_t;
+
+struct cx23885_board {
+	char                    *name;
+	port_t			portb, portc;
+	struct cx23885_input    input[MAX_CX23885_INPUT];
+};
+
+struct cx23885_subid {
+	u16     subvendor;
+	u16     subdevice;
+	u32     card;
+};
+
+struct cx23885_i2c {
+	struct cx23885_dev *dev;
+
+	int                        nr;
+
+	/* i2c i/o */
+	struct i2c_adapter         i2c_adap;
+	struct i2c_algo_bit_data   i2c_algo;
+	struct i2c_client          i2c_client;
+	u32                        i2c_rc;
+
+	/* 885 registers used for raw addess */
+	u32                        i2c_period;
+	u32                        reg_ctrl;
+	u32                        reg_stat;
+	u32                        reg_addr;
+	u32                        reg_rdata;
+	u32                        reg_wdata;
+};
+
+struct cx23885_dmaqueue {
+	struct list_head       active;
+	struct list_head       queued;
+	struct timer_list      timeout;
+	struct btcx_riscmem    stopper;
+	u32                    count;
+};
+
+struct cx23885_tsport {
+	struct cx23885_dev *dev;
+
+	int                        nr;
+	int                        sram_chno;
+
+	struct videobuf_dvb        dvb;
+
+	/* dma queues */
+	struct cx23885_dmaqueue    mpegq;
+	u32                        ts_packet_size;
+	u32                        ts_packet_count;
+
+	int                        width;
+	int                        height;
+
+	spinlock_t                 slock;
+
+	/* registers */
+	u32                        reg_gpcnt;
+	u32                        reg_gpcnt_ctl;
+	u32                        reg_dma_ctl;
+	u32                        reg_lngth;
+	u32                        reg_hw_sop_ctrl;
+	u32                        reg_gen_ctrl;
+	u32                        reg_bd_pkt_status;
+	u32                        reg_sop_status;
+	u32                        reg_fifo_ovfl_stat;
+	u32                        reg_vld_misc;
+	u32                        reg_ts_clk_en;
+	u32                        reg_ts_int_msk;
+	u32                        reg_ts_int_stat;
+	u32                        reg_src_sel;
+
+	/* Default register vals */
+	int                        pci_irqmask;
+	u32                        dma_ctl_val;
+	u32                        ts_int_msk_val;
+	u32                        gen_ctrl_val;
+	u32                        ts_clk_en_val;
+	u32                        src_sel_val;
+};
+
+struct cx23885_dev {
+	struct list_head           devlist;
+	atomic_t                   refcount;
+
+	/* pci stuff */
+	struct pci_dev             *pci;
+	unsigned char              pci_rev, pci_lat;
+	int                        pci_bus, pci_slot;
+	u32                        __iomem *lmmio;
+	u8                         __iomem *bmmio;
+	int                        pci_irqmask;
+
+	/* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
+	struct cx23885_i2c         i2c_bus[3];
+
+	int                        nr;
+	struct mutex               lock;
+
+	/* board details */
+	unsigned int               board;
+	char                       name[32];
+
+	struct cx23885_tsport      ts1, ts2;
+
+	/* sram configuration */
+	struct sram_channel        *sram_channels;
+
+	enum {
+		CX23885_BRIDGE_UNDEFINED = 0,
+		CX23885_BRIDGE_885 = 885,
+		CX23885_BRIDGE_887 = 887,
+	} bridge;
+};
+
+#define SRAM_CH01  0 /* Video A */
+#define SRAM_CH02  1 /* VBI A */
+#define SRAM_CH03  2 /* Video B */
+#define SRAM_CH04  3 /* Transport via B */
+#define SRAM_CH05  4 /* VBI B */
+#define SRAM_CH06  5 /* Video C */
+#define SRAM_CH07  6 /* Transport via C */
+#define SRAM_CH08  7 /* Audio Internal A */
+#define SRAM_CH09  8 /* Audio Internal B */
+#define SRAM_CH10  9 /* Audio External */
+#define SRAM_CH11 10 /* COMB_3D_N */
+#define SRAM_CH12 11 /* Comb 3D N1 */
+#define SRAM_CH13 12 /* Comb 3D N2 */
+#define SRAM_CH14 13 /* MOE Vid */
+#define SRAM_CH15 14 /* MOE RSLT */
+
+struct sram_channel {
+	char *name;
+	u32  cmds_start;
+	u32  ctrl_start;
+	u32  cdt;
+	u32  fifo_start;;
+	u32  fifo_size;
+	u32  ptr1_reg;
+	u32  ptr2_reg;
+	u32  cnt1_reg;
+	u32  cnt2_reg;
+	u32  jumponly;
+};
+
+/* ----------------------------------------------------------- */
+
+#define cx_read(reg)             readl(dev->lmmio + ((reg)>>2))
+#define cx_write(reg,value)      writel((value), dev->lmmio + ((reg)>>2))
+
+#define cx_andor(reg,mask,value) \
+  writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\
+  ((value) & (mask)), dev->lmmio+((reg)>>2))
+
+#define cx_set(reg,bit)          cx_andor((reg),(bit),(bit))
+#define cx_clear(reg,bit)        cx_andor((reg),(bit),0)
+
+extern int cx23885_sram_channel_setup(struct cx23885_dev *dev,
+	struct sram_channel *ch,
+	unsigned int bpl, u32 risc);
+
+/* ----------------------------------------------------------- */
+/* cx23885-cards.c                                                */
+
+extern struct cx23885_board cx23885_boards[];
+extern const unsigned int cx23885_bcount;
+
+extern struct cx23885_subid cx23885_subids[];
+extern const unsigned int cx23885_idcount;
+
+extern void cx23885_card_list(struct cx23885_dev *dev);
+extern int  cx23885_ir_init(struct cx23885_dev *dev);
+extern void cx23885_gpio_setup(struct cx23885_dev *dev);
+extern void cx23885_card_setup(struct cx23885_dev *dev);
+extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev);
+
+extern int cx23885_dvb_register(struct cx23885_tsport *port);
+extern int cx23885_dvb_unregister(struct cx23885_tsport *port);
+
+extern int cx23885_buf_prepare(struct videobuf_queue *q,
+			       struct cx23885_tsport *port,
+			       struct cx23885_buffer *buf,
+			       enum v4l2_field field);
+
+extern void cx23885_buf_queue(struct cx23885_tsport *port,
+			      struct cx23885_buffer *buf);
+extern void cx23885_free_buffer(struct videobuf_queue *q,
+				struct cx23885_buffer *buf);
+
+/* ----------------------------------------------------------- */
+/* cx23885-i2c.c                                                */
+extern int cx23885_i2c_register(struct cx23885_i2c *bus);
+extern int cx23885_i2c_unregister(struct cx23885_i2c *bus);
+extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd,
+				     void *arg);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
+ */
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
index f897c1e..3d46a77 100644
--- a/drivers/media/video/cx25840/cx25840-audio.c
+++ b/drivers/media/video/cx25840/cx25840-audio.c
@@ -157,13 +157,12 @@
 {
 	struct cx25840_state *state = i2c_get_clientdata(client);
 
+	/* assert soft reset */
+	cx25840_and_or(client, 0x810, ~0x1, 0x01);
+
 	/* stop microcontroller */
 	cx25840_and_or(client, 0x803, ~0x10, 0);
 
-	/* assert soft reset */
-	if (!state->is_cx25836)
-		cx25840_and_or(client, 0x810, ~0x1, 0x01);
-
 	/* Mute everything to prevent the PFFT! */
 	cx25840_write(client, 0x8d3, 0x1f);
 
@@ -181,32 +180,46 @@
 
 	set_audclk_freq(client, state->audclk_freq);
 
-	/* deassert soft reset */
-	if (!state->is_cx25836)
-		cx25840_and_or(client, 0x810, ~0x1, 0x00);
-
 	if (state->aud_input != CX25840_AUDIO_SERIAL) {
 		/* When the microcontroller detects the
 		 * audio format, it will unmute the lines */
 		cx25840_and_or(client, 0x803, ~0x10, 0x10);
 	}
+
+	/* deassert soft reset */
+	cx25840_and_or(client, 0x810, ~0x1, 0x00);
 }
 
 static int get_volume(struct i2c_client *client)
 {
+	struct cx25840_state *state = i2c_get_clientdata(client);
+	int vol;
+
+	if (state->unmute_volume >= 0)
+		return state->unmute_volume;
+
 	/* Volume runs +18dB to -96dB in 1/2dB steps
 	 * change to fit the msp3400 -114dB to +12dB range */
 
 	/* check PATH1_VOLUME */
-	int vol = 228 - cx25840_read(client, 0x8d4);
+	vol = 228 - cx25840_read(client, 0x8d4);
 	vol = (vol / 2) + 23;
 	return vol << 9;
 }
 
 static void set_volume(struct i2c_client *client, int volume)
 {
-	/* First convert the volume to msp3400 values (0-127) */
-	int vol = volume >> 9;
+	struct cx25840_state *state = i2c_get_clientdata(client);
+	int vol;
+
+	if (state->unmute_volume >= 0) {
+		state->unmute_volume = volume;
+		return;
+	}
+
+	/* Convert the volume to msp3400 values (0-127) */
+	vol = volume >> 9;
+
 	/* now scale it up to cx25840 values
 	 * -114dB to -96dB maps to 0
 	 * this should be 19, but in my testing that was 4dB too loud */
@@ -284,30 +297,26 @@
 
 static int get_mute(struct i2c_client *client)
 {
-	/* check SRC1_MUTE_EN */
-	return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0;
+	struct cx25840_state *state = i2c_get_clientdata(client);
+
+	return state->unmute_volume >= 0;
 }
 
 static void set_mute(struct i2c_client *client, int mute)
 {
 	struct cx25840_state *state = i2c_get_clientdata(client);
 
-	if (state->aud_input != CX25840_AUDIO_SERIAL) {
-		/* Must turn off microcontroller in order to mute sound.
-		 * Not sure if this is the best method, but it does work.
-		 * If the microcontroller is running, then it will undo any
-		 * changes to the mute register. */
-		if (mute) {
-			/* disable microcontroller */
-			cx25840_and_or(client, 0x803, ~0x10, 0x00);
-			cx25840_write(client, 0x8d3, 0x1f);
-		} else {
-			/* enable microcontroller */
-			cx25840_and_or(client, 0x803, ~0x10, 0x10);
-		}
-	} else {
-		/* SRC1_MUTE_EN */
-		cx25840_and_or(client, 0x8d3, ~0x2, mute ? 0x02 : 0x00);
+	if (mute && state->unmute_volume == -1) {
+		int vol = get_volume(client);
+
+		set_volume(client, 0);
+		state->unmute_volume = vol;
+	}
+	else if (!mute && state->unmute_volume != -1) {
+		int vol = state->unmute_volume;
+
+		state->unmute_volume = -1;
+		set_volume(client, vol);
 	}
 }
 
@@ -319,18 +328,18 @@
 
 	switch (cmd) {
 	case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+		if (!state->is_cx25836)
+			cx25840_and_or(client, 0x810, ~0x1, 1);
 		if (state->aud_input != CX25840_AUDIO_SERIAL) {
 			cx25840_and_or(client, 0x803, ~0x10, 0);
 			cx25840_write(client, 0x8d3, 0x1f);
 		}
-		if (!state->is_cx25836)
-			cx25840_and_or(client, 0x810, ~0x1, 1);
 		retval = set_audclk_freq(client, *(u32 *)arg);
-		if (!state->is_cx25836)
-			cx25840_and_or(client, 0x810, ~0x1, 0);
 		if (state->aud_input != CX25840_AUDIO_SERIAL) {
 			cx25840_and_or(client, 0x803, ~0x10, 0x10);
 		}
+		if (!state->is_cx25836)
+			cx25840_and_or(client, 0x810, ~0x1, 0);
 		return retval;
 
 	case VIDIOC_G_CTRL:
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 67bda9f..15f191e 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -34,6 +34,7 @@
 #include <linux/slab.h>
 #include <linux/videodev2.h>
 #include <linux/i2c.h>
+#include <linux/delay.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/cx25840.h>
@@ -133,7 +134,9 @@
 	cx25840_write(client, 0x159, 0x23);
 	cx25840_write(client, 0x15a, 0x87);
 	cx25840_write(client, 0x15b, 0x06);
+	udelay(10);
 	cx25840_write(client, 0x159, 0xe1);
+	udelay(10);
 	cx25840_write(client, 0x15a, 0x86);
 	cx25840_write(client, 0x159, 0xe0);
 	cx25840_write(client, 0x159, 0xe1);
@@ -147,6 +150,7 @@
 	cx25840_write(client, 0x15d, 0xe3);
 	cx25840_write(client, 0x15e, 0x86);
 	cx25840_write(client, 0x15f, 0x06);
+	udelay(10);
 	cx25840_write(client, 0x15d, 0xe1);
 	cx25840_write(client, 0x15d, 0xe0);
 	cx25840_write(client, 0x15d, 0xe1);
@@ -165,9 +169,7 @@
 	/* 3c. */
 	cx25840_and_or(client, 0x159, ~0x02, 0x02);
 	/* 3d. */
-	/* There should be a 10-us delay here, but since the
-	   i2c bus already has a 10-us delay we don't need to do
-	   anything */
+	udelay(10);
 	/* 3e. */
 	cx25840_and_or(client, 0x159, ~0x02, 0x00);
 	/* 3f. */
@@ -179,9 +181,18 @@
 	cx25840_and_or(client, 0x15b, ~0x1e, 0x10);
 }
 
-static void cx25840_initialize(struct i2c_client *client, int loadfw)
+static void cx25840_work_handler(struct work_struct *work)
 {
+	struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work);
+	cx25840_loadfw(state->c);
+	wake_up(&state->fw_wait);
+}
+
+static void cx25840_initialize(struct i2c_client *client)
+{
+	DEFINE_WAIT(wait);
 	struct cx25840_state *state = i2c_get_clientdata(client);
+	struct workqueue_struct *q;
 
 	/* datasheet startup in numbered steps, refer to page 3-77 */
 	/* 2. */
@@ -197,8 +208,19 @@
 	cx25840_write(client, 0x13c, 0x01);
 	cx25840_write(client, 0x13c, 0x00);
 	/* 5. */
-	if (loadfw)
-		cx25840_loadfw(client);
+	/* Do the firmware load in a work handler to prevent.
+	   Otherwise the kernel is blocked waiting for the
+	   bit-banging i2c interface to finish uploading the
+	   firmware. */
+	INIT_WORK(&state->fw_work, cx25840_work_handler);
+	init_waitqueue_head(&state->fw_wait);
+	q = create_singlethread_workqueue("cx25840_fw");
+	prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+	queue_work(q, &state->fw_work);
+	schedule();
+	finish_wait(&state->fw_wait, &wait);
+	destroy_workqueue(q);
+
 	/* 6. */
 	cx25840_write(client, 0x115, 0x8c);
 	cx25840_write(client, 0x116, 0x07);
@@ -251,8 +273,13 @@
 	}
 	cx25840_and_or(client, 0x401, ~0x60, 0);
 	cx25840_and_or(client, 0x401, ~0x60, 0x60);
+	cx25840_and_or(client, 0x810, ~0x01, 1);
 
-	if (std & V4L2_STD_525_60) {
+	if (state->radio) {
+		cx25840_write(client, 0x808, 0xf9);
+		cx25840_write(client, 0x80b, 0x00);
+	}
+	else if (std & V4L2_STD_525_60) {
 		/* Certain Hauppauge PVR150 models have a hardware bug
 		   that causes audio to drop out. For these models the
 		   audio standard must be set explicitly.
@@ -281,11 +308,7 @@
 		cx25840_write(client, 0x80b, 0x10);
 	}
 
-	if (cx25840_read(client, 0x803) & 0x10) {
-		/* restart audio decoder microcontroller */
-		cx25840_and_or(client, 0x803, ~0x10, 0x00);
-		cx25840_and_or(client, 0x803, ~0x10, 0x10);
-	}
+	cx25840_and_or(client, 0x810, ~0x01, 0);
 }
 
 static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
@@ -625,6 +648,22 @@
 	struct v4l2_tuner *vt = arg;
 	struct v4l2_routing *route = arg;
 
+	/* ignore these commands */
+	switch (cmd) {
+		case TUNER_SET_TYPE_ADDR:
+			return 0;
+	}
+
+	if (!state->is_initialized) {
+		v4l_dbg(1, cx25840_debug, client, "cmd %08x triggered fw load\n", cmd);
+		/* initialize on first use */
+		state->is_initialized = 1;
+		if (state->is_cx25836)
+			cx25836_initialize(client);
+		else
+			cx25840_initialize(client);
+	}
+
 	switch (cmd) {
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	/* ioctls to allow direct access to the
@@ -825,7 +864,7 @@
 		if (state->is_cx25836)
 			cx25836_initialize(client);
 		else
-			cx25840_initialize(client, 0);
+			cx25840_initialize(client);
 		break;
 
 	case VIDIOC_G_CHIP_IDENT:
@@ -856,17 +895,16 @@
 	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
 		return 0;
 
-	state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
-	if (state == 0)
+	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (client == 0)
 		return -ENOMEM;
 
-	client = &state->c;
 	client->addr = address;
 	client->adapter = adapter;
 	client->driver = &i2c_driver_cx25840;
 	snprintf(client->name, sizeof(client->name) - 1, "cx25840");
 
-	v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", address << 1);
+	v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1);
 
 	device_id = cx25840_read(client, 0x101) << 8;
 	device_id |= cx25840_read(client, 0x100);
@@ -875,42 +913,44 @@
 	 * 0x83 for the cx2583x and 0x84 for the cx2584x */
 	if ((device_id & 0xff00) == 0x8300) {
 		id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
-		state->is_cx25836 = 1;
 	}
 	else if ((device_id & 0xff00) == 0x8400) {
 		id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
-		state->is_cx25836 = 0;
 	}
 	else {
 		v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
-		kfree(state);
+		kfree(client);
 		return 0;
 	}
 
+	state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
+	if (state == NULL) {
+		kfree(client);
+		return -ENOMEM;
+	}
+
 	/* Note: revision '(device_id & 0x0f) == 2' was never built. The
 	   marking skips from 0x1 == 22 to 0x3 == 23. */
 	v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
 		    (device_id & 0xfff0) >> 4,
 		    (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f),
-		    address << 1, adapter->name);
+		    client->addr << 1, client->adapter->name);
 
 	i2c_set_clientdata(client, state);
+	state->c = client;
+	state->is_cx25836 = ((device_id & 0xff00) == 0x8300);
 	state->vid_input = CX25840_COMPOSITE7;
 	state->aud_input = CX25840_AUDIO8;
 	state->audclk_freq = 48000;
 	state->pvr150_workaround = 0;
 	state->audmode = V4L2_TUNER_MODE_LANG1;
+	state->unmute_volume = -1;
 	state->vbi_line_offset = 8;
 	state->id = id;
 	state->rev = device_id;
 
 	i2c_attach_client(client);
 
-	if (state->is_cx25836)
-		cx25836_initialize(client);
-	else
-		cx25840_initialize(client, 1);
-
 	return 0;
 }
 
@@ -932,6 +972,7 @@
 	}
 
 	kfree(state);
+	kfree(client);
 
 	return 0;
 }
@@ -1056,9 +1097,10 @@
 	}
 	v4l_info(client, "Detected audio standard:   %s\n", p);
 	v4l_info(client, "Audio muted:               %s\n",
-		    (mute_ctl & 0x2) ? "yes" : "no");
+		    (state->unmute_volume >= 0) ? "yes" : "no");
 	v4l_info(client, "Audio microcontroller:     %s\n",
-		    (download_ctl & 0x10) ? "running" : "stopped");
+		    (download_ctl & 0x10) ?
+				((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
 
 	switch (audio_config >> 4) {
 	case 0x00: p = "undefined"; break;
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index f4b56d2..ea669b1 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/video/cx25840/cx25840-core.h
@@ -35,17 +35,21 @@
 #define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0)
 
 struct cx25840_state {
-	struct i2c_client c;
+	struct i2c_client *c;
 	int pvr150_workaround;
 	int radio;
 	enum cx25840_video_input vid_input;
 	enum cx25840_audio_input aud_input;
 	u32 audclk_freq;
 	int audmode;
+	int unmute_volume; /* -1 if not muted */
 	int vbi_line_offset;
 	u32 id;
 	u32 rev;
 	int is_cx25836;
+	int is_initialized;
+	wait_queue_head_t fw_wait;    /* wake up when the fw load is finished */
+	struct work_struct fw_work;   /* work entry for fw load */
 };
 
 /* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 0f9d969..eeb5224 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -4,7 +4,7 @@
 	select I2C_ALGOBIT
 	select FW_LOADER
 	select VIDEO_BTCX
-	select VIDEO_BUF
+	select VIDEOBUF_DMA_SG
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
 	select VIDEO_IR
@@ -46,8 +46,8 @@
 config VIDEO_CX88_DVB
 	tristate "DVB/ATSC Support for cx2388x based TV cards"
 	depends on VIDEO_CX88 && DVB_CORE
-	select VIDEO_BUF_DVB
-	select DVB_PLL
+	select VIDEOBUF_DVB
+	select DVB_PLL if !DVB_FE_CUSTOMISE
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
 	select DVB_ZL10353 if !DVB_FE_CUSTOMISE
 	select DVB_OR51132 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 2d666b5..90c36c5 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -3,6 +3,7 @@
  *  Support for audio capture
  *  PCI function #1 of the cx2388x.
  *
+ *    (c) 2007 Trent Piepho <xyzzy@speakeasy.org>
  *    (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>
  *    (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
  *    Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
@@ -27,7 +28,9 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
+#include <linux/vmalloc.h>
 #include <linux/dma-mapping.h>
+#include <linux/pci.h>
 
 #include <asm/delay.h>
 #include <sound/driver.h>
@@ -46,21 +49,16 @@
 #define dprintk_core(level,fmt, arg...)	if (debug >= level) \
 	printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg)
 
-
 /****************************************************************************
 	Data type declarations - Can be moded to a header file later
  ****************************************************************************/
 
-/* These can be replaced after done */
-#define MIXER_ADDR_LAST MAX_CX88_INPUT
-
 struct cx88_audio_dev {
 	struct cx88_core           *core;
 	struct cx88_dmaqueue       q;
 
 	/* pci i/o */
 	struct pci_dev             *pci;
-	unsigned char              pci_rev,pci_lat;
 
 	/* audio controls */
 	int                        irq;
@@ -68,24 +66,17 @@
 	struct snd_card            *card;
 
 	spinlock_t                 reg_lock;
+	atomic_t		   count;
 
 	unsigned int               dma_size;
 	unsigned int               period_size;
 	unsigned int               num_periods;
 
-	struct videobuf_dmabuf dma_risc;
+	struct videobuf_dmabuf     *dma_risc;
 
-	int                        mixer_volume[MIXER_ADDR_LAST+1][2];
-	int                        capture_source[MIXER_ADDR_LAST+1][2];
+	struct cx88_buffer	   *buf;
 
-	long int read_count;
-	long int read_offset;
-
-	struct cx88_buffer   *buf;
-
-	long opened;
-	struct snd_pcm_substream *substream;
-
+	struct snd_pcm_substream   *substream;
 };
 typedef struct cx88_audio_dev snd_cx88_card_t;
 
@@ -98,7 +89,6 @@
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
 static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
-static struct snd_card *snd_cx88_cards[SNDRV_CARDS];
 
 module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled.");
@@ -136,38 +126,39 @@
 	struct cx88_core *core=chip->core;
 	struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
 
-
-	dprintk(1, "Starting audio DMA for %i bytes/line and %i (%i) lines at address %08x\n",buf->bpl, chip->num_periods, audio_ch->fifo_size / buf->bpl, audio_ch->fifo_start);
+	/* Make sure RISC/FIFO are off before changing FIFO/RISC settings */
+	cx_clear(MO_AUD_DMACNTRL, 0x11);
 
 	/* setup fifo + format - out channel */
-	cx88_sram_channel_setup(chip->core, &cx88_sram_channels[SRAM_CH25],
-				buf->bpl, buf->risc.dma);
+	cx88_sram_channel_setup(chip->core, audio_ch, buf->bpl, buf->risc.dma);
 
 	/* sets bpl size */
 	cx_write(MO_AUDD_LNGTH, buf->bpl);
 
 	/* reset counter */
-	cx_write(MO_AUDD_GPCNTRL,GP_COUNT_CONTROL_RESET);
+	cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);
+	atomic_set(&chip->count, 0);
 
-	dprintk(1,"Enabling IRQ, setting mask from 0x%x to 0x%x\n",chip->core->pci_irqmask,(chip->core->pci_irqmask | 0x02));
-	/* enable irqs */
-	cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | 0x02);
-
+	dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d "
+		"byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1,
+		chip->num_periods, buf->bpl * chip->num_periods);
 
 	/* Enables corresponding bits at AUD_INT_STAT */
-	cx_write(MO_AUD_INTMSK,
-			(1<<16)|
-			(1<<12)|
-			(1<<4)|
-			(1<<0)
-			);
+	cx_write(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+				AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
+
+	/* Clean any pending interrupt bits already set */
+	cx_write(MO_AUD_INTSTAT, ~0);
+
+	/* enable audio irqs */
+	cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT);
 
 	/* start dma */
 	cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */
 	cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */
 
 	if (debug)
-		cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
+		cx88_sram_channel_dump(chip->core, audio_ch);
 
 	return 0;
 }
@@ -184,13 +175,9 @@
 	cx_clear(MO_AUD_DMACNTRL, 0x11);
 
 	/* disable irqs */
-	cx_clear(MO_PCI_INTMSK, 0x02);
-	cx_clear(MO_AUD_INTMSK,
-			(1<<16)|
-			(1<<12)|
-			(1<<4)|
-			(1<<0)
-			);
+	cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT);
+	cx_clear(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |
+				AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);
 
 	if (debug)
 		cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]);
@@ -198,7 +185,7 @@
 	return 0;
 }
 
-#define MAX_IRQ_LOOP 10
+#define MAX_IRQ_LOOP 50
 
 /*
  * BOARD Specific: IRQ dma bits
@@ -223,42 +210,32 @@
 {
 	struct cx88_core *core = chip->core;
 	u32 status, mask;
-	u32 count;
 
 	status = cx_read(MO_AUD_INTSTAT);
 	mask   = cx_read(MO_AUD_INTMSK);
-	if (0 == (status & mask)) {
-		spin_unlock(&chip->reg_lock);
+	if (0 == (status & mask))
 		return;
-	}
 	cx_write(MO_AUD_INTSTAT, status);
 	if (debug > 1  ||  (status & mask & ~0xff))
 		cx88_print_irqbits(core->name, "irq aud",
 				   cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs),
 				   status, mask);
 	/* risc op code error */
-	if (status & (1 << 16)) {
-		printk(KERN_WARNING "%s/0: audio risc op code error\n",core->name);
+	if (status & AUD_INT_OPC_ERR) {
+		printk(KERN_WARNING "%s/1: Audio risc op code error\n",core->name);
 		cx_clear(MO_AUD_DMACNTRL, 0x11);
 		cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]);
 	}
-
-	/* risc1 downstream */
-	if (status & 0x01) {
-		spin_lock(&chip->reg_lock);
-		count = cx_read(MO_AUDD_GPCNT);
-		spin_unlock(&chip->reg_lock);
-		if (chip->read_count == 0)
-			chip->read_count += chip->dma_size;
+	if (status & AUD_INT_DN_SYNC) {
+		dprintk(1, "Downstream sync error\n");
+		cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);
+		return;
 	}
-
-	if  (chip->read_count >= chip->period_size) {
-		dprintk(2, "Elapsing period\n");
+	/* risc1 downstream */
+	if (status & AUD_INT_DN_RISCI1) {
+		atomic_set(&chip->count, cx_read(MO_AUDD_GPCNT));
 		snd_pcm_period_elapsed(chip->substream);
 	}
-
-	dprintk(3,"Leaving audio IRQ handler...\n");
-
 	/* FIXME: Any other status should deserve a special handling? */
 }
 
@@ -273,27 +250,26 @@
 	int loop, handled = 0;
 
 	for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
-		status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x02);
+		status = cx_read(MO_PCI_INTSTAT) &
+			(core->pci_irqmask | PCI_INT_AUDINT);
 		if (0 == status)
 			goto out;
-		dprintk( 3, "cx8801_irq\n" );
-		dprintk( 3, "    loop: %d/%d\n", loop, MAX_IRQ_LOOP );
-		dprintk( 3, "    status: %d\n", status );
+		dprintk(3, "cx8801_irq loop %d/%d, status %x\n",
+			loop, MAX_IRQ_LOOP, status);
 		handled = 1;
 		cx_write(MO_PCI_INTSTAT, status);
 
-		if (status & 0x02)
-		{
-			dprintk( 2, "    ALSA IRQ handling\n" );
+		if (status & core->pci_irqmask)
+			cx88_core_irq(core, status);
+		if (status & PCI_INT_AUDINT)
 			cx8801_aud_irq(chip);
-		}
-	};
+	}
 
 	if (MAX_IRQ_LOOP == loop) {
-		dprintk( 0, "clearing mask\n" );
-		dprintk(1,"%s/0: irq loop -- clearing mask\n",
+		printk(KERN_ERR
+		       "%s/1: IRQ loop detected, disabling interrupts\n",
 		       core->name);
-		cx_clear(MO_PCI_INTMSK,0x02);
+		cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT);
 	}
 
  out:
@@ -306,14 +282,15 @@
 	BUG_ON(!chip->dma_size);
 
 	dprintk(2,"Freeing buffer\n");
-	videobuf_pci_dma_unmap(chip->pci, &chip->dma_risc);
-	videobuf_dma_free(&chip->dma_risc);
+	videobuf_pci_dma_unmap(chip->pci, chip->dma_risc);
+	videobuf_dma_free(chip->dma_risc);
 	btcx_riscmem_free(chip->pci,&chip->buf->risc);
 	kfree(chip->buf);
 
+	chip->dma_risc = NULL;
 	chip->dma_size = 0;
 
-       return 0;
+	return 0;
 }
 
 /****************************************************************************
@@ -323,6 +300,7 @@
 /*
  * Digital hardware definition
  */
+#define DEFAULT_FIFO_SIZE	4096
 static struct snd_pcm_hardware snd_cx88_digital_hw = {
 	.info = SNDRV_PCM_INFO_MMAP |
 		SNDRV_PCM_INFO_INTERLEAVED |
@@ -333,22 +311,18 @@
 	.rates =		SNDRV_PCM_RATE_48000,
 	.rate_min =		48000,
 	.rate_max =		48000,
-	.channels_min = 1,
+	.channels_min = 2,
 	.channels_max = 2,
-	.buffer_bytes_max = (2*2048),
-	.period_bytes_min = 2048,
-	.period_bytes_max = 2048,
-	.periods_min = 2,
-	.periods_max = 2,
+	/* Analog audio output will be full of clicks and pops if there
+	   are not exactly four lines in the SRAM FIFO buffer.  */
+	.period_bytes_min = DEFAULT_FIFO_SIZE/4,
+	.period_bytes_max = DEFAULT_FIFO_SIZE/4,
+	.periods_min = 1,
+	.periods_max = 1024,
+	.buffer_bytes_max = (1024*1024),
 };
 
 /*
- * audio pcm capture runtime free
- */
-static void snd_card_cx88_runtime_free(struct snd_pcm_runtime *runtime)
-{
-}
-/*
  * audio pcm capture open callback
  */
 static int snd_cx88_pcm_open(struct snd_pcm_substream *substream)
@@ -357,26 +331,24 @@
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	int err;
 
-	if (test_and_set_bit(0, &chip->opened))
-		return -EBUSY;
-
-	err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+	err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS);
 	if (err < 0)
 		goto _error;
 
 	chip->substream = substream;
 
-	chip->read_count = 0;
-	chip->read_offset = 0;
-
-	runtime->private_free = snd_card_cx88_runtime_free;
 	runtime->hw = snd_cx88_digital_hw;
 
+	if (cx88_sram_channels[SRAM_CH25].fifo_size != DEFAULT_FIFO_SIZE) {
+		unsigned int bpl = cx88_sram_channels[SRAM_CH25].fifo_size / 4;
+		bpl &= ~7; /* must be multiple of 8 */
+		runtime->hw.period_bytes_min = bpl;
+		runtime->hw.period_bytes_max = bpl;
+	}
+
 	return 0;
 _error:
 	dprintk(1,"Error opening PCM!\n");
-	clear_bit(0, &chip->opened);
-	smp_mb__after_clear_bit();
 	return err;
 }
 
@@ -385,11 +357,6 @@
  */
 static int snd_cx88_close(struct snd_pcm_substream *substream)
 {
-	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
-
-	clear_bit(0, &chip->opened);
-	smp_mb__after_clear_bit();
-
 	return 0;
 }
 
@@ -400,55 +367,67 @@
 			      struct snd_pcm_hw_params * hw_params)
 {
 	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+	struct videobuf_dmabuf *dma;
+
 	struct cx88_buffer *buf;
+	int ret;
 
 	if (substream->runtime->dma_area) {
 		dsp_buffer_free(chip);
 		substream->runtime->dma_area = NULL;
 	}
 
-
 	chip->period_size = params_period_bytes(hw_params);
 	chip->num_periods = params_periods(hw_params);
 	chip->dma_size = chip->period_size * params_periods(hw_params);
 
 	BUG_ON(!chip->dma_size);
+	BUG_ON(chip->num_periods & (chip->num_periods-1));
 
-	dprintk(1,"Setting buffer\n");
-
-	buf = kzalloc(sizeof(*buf),GFP_KERNEL);
+	buf = videobuf_pci_alloc(sizeof(*buf));
 	if (NULL == buf)
 		return -ENOMEM;
 
 	buf->vb.memory = V4L2_MEMORY_MMAP;
+	buf->vb.field  = V4L2_FIELD_NONE;
 	buf->vb.width  = chip->period_size;
+	buf->bpl       = chip->period_size;
 	buf->vb.height = chip->num_periods;
 	buf->vb.size   = chip->dma_size;
-	buf->vb.field  = V4L2_FIELD_NONE;
 
-	videobuf_dma_init(&buf->vb.dma);
-	videobuf_dma_init_kernel(&buf->vb.dma,PCI_DMA_FROMDEVICE,
+	dma=videobuf_to_dma(&buf->vb);
+	videobuf_dma_init(dma);
+	ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
 			(PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT));
+	if (ret < 0)
+		goto error;
 
-	videobuf_pci_dma_map(chip->pci,&buf->vb.dma);
+	ret = videobuf_pci_dma_map(chip->pci,dma);
+	if (ret < 0)
+		goto error;
 
+	ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
+				   buf->vb.width, buf->vb.height, 1);
+	if (ret < 0)
+		goto error;
 
-	cx88_risc_databuffer(chip->pci, &buf->risc,
-			buf->vb.dma.sglist,
-			buf->vb.width, buf->vb.height);
-
-	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
+	/* Loop back to start of program */
+	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
 	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
 
 	buf->vb.state = STATE_PREPARED;
 
-	buf->bpl = chip->period_size;
 	chip->buf = buf;
-	chip->dma_risc = buf->vb.dma;
+	chip->dma_risc = dma;
 
-	dprintk(1,"Buffer ready at %u\n",chip->dma_risc.nr_pages);
-	substream->runtime->dma_area = chip->dma_risc.vmalloc;
+	substream->runtime->dma_area = chip->dma_risc->vmalloc;
+	substream->runtime->dma_bytes = chip->dma_size;
+	substream->runtime->dma_addr = 0;
 	return 0;
+
+error:
+	kfree(buf);
+	return ret;
 }
 
 /*
@@ -475,7 +454,6 @@
 	return 0;
 }
 
-
 /*
  * trigger callback
  */
@@ -484,6 +462,7 @@
 	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
 	int err;
 
+	/* Local interrupts are already disabled by ALSA */
 	spin_lock(&chip->reg_lock);
 
 	switch (cmd) {
@@ -510,17 +489,24 @@
 {
 	snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	u16 count;
 
-	if (chip->read_count) {
-		chip->read_count -= snd_pcm_lib_period_bytes(substream);
-		chip->read_offset += snd_pcm_lib_period_bytes(substream);
-		if (chip->read_offset == chip->dma_size)
-			chip->read_offset = 0;
-	}
+	count = atomic_read(&chip->count);
 
-	dprintk(2, "Pointer time, will return %li, read %li\n",chip->read_offset,chip->read_count);
-	return bytes_to_frames(runtime, chip->read_offset);
+//	dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __FUNCTION__,
+//		count, new, count & (runtime->periods-1),
+//		runtime->period_size * (count & (runtime->periods-1)));
+	return runtime->period_size * (count & (runtime->periods-1));
+}
 
+/*
+ * page callback (needed for mmap)
+ */
+static struct page *snd_cx88_page(struct snd_pcm_substream *substream,
+				unsigned long offset)
+{
+	void *pageptr = substream->runtime->dma_area + offset;
+	return vmalloc_to_page(pageptr);
 }
 
 /*
@@ -535,6 +521,7 @@
 	.prepare = snd_cx88_prepare,
 	.trigger = snd_cx88_card_trigger,
 	.pointer = snd_cx88_pointer,
+	.page = snd_cx88_page,
 };
 
 /*
@@ -562,7 +549,7 @@
 					struct snd_ctl_elem_info *info)
 {
 	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-	info->count = 1;
+	info->count = 2;
 	info->value.integer.min = 0;
 	info->value.integer.max = 0x3f;
 
@@ -575,8 +562,12 @@
 {
 	snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
 	struct cx88_core *core=chip->core;
+	int vol = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f),
+	    bal = cx_read(AUD_BAL_CTL);
 
-	value->value.integer.value[0] = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f);
+	value->value.integer.value[(bal & 0x40) ? 0 : 1] = vol;
+	vol -= (bal & 0x3f);
+	value->value.integer.value[(bal & 0x40) ? 1 : 0] = vol < 0 ? 0 : vol;
 
 	return 0;
 }
@@ -587,16 +578,31 @@
 {
 	snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
 	struct cx88_core *core=chip->core;
-	int v;
-	u32 old_control;
+	int v, b;
+	int changed = 0;
+	u32 old;
 
+	b = value->value.integer.value[1] - value->value.integer.value[0];
+	if (b < 0) {
+	    v = 0x3f - value->value.integer.value[0];
+	    b = (-b) | 0x40;
+	} else {
+	    v = 0x3f - value->value.integer.value[1];
+	}
+	/* Do we really know this will always be called with IRQs on? */
 	spin_lock_irq(&chip->reg_lock);
-	old_control = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f);
-	v = 0x3f - (value->value.integer.value[0] & 0x3f);
-	cx_andor(AUD_VOL_CTL, 0x3f, v);
+	old = cx_read(AUD_VOL_CTL);
+	if (v != (old & 0x3f)) {
+	    cx_write(AUD_VOL_CTL, (old & ~0x3f) | v);
+	    changed = 1;
+	}
+	if (cx_read(AUD_BAL_CTL) != b) {
+	    cx_write(AUD_BAL_CTL, b);
+	    changed = 1;
+	}
 	spin_unlock_irq(&chip->reg_lock);
 
-	return v != old_control;
+	return changed;
 }
 
 static struct snd_kcontrol_new snd_cx88_capture_volume = {
@@ -665,6 +671,7 @@
 	snd_cx88_card_t   *chip;
 	struct cx88_core  *core;
 	int               err;
+	unsigned char     pci_lat;
 
 	*rchip = NULL;
 
@@ -709,13 +716,12 @@
 	}
 
 	/* print pci info */
-	pci_read_config_byte(pci, PCI_CLASS_REVISION, &chip->pci_rev);
-	pci_read_config_byte(pci, PCI_LATENCY_TIMER,  &chip->pci_lat);
+	pci_read_config_byte(pci, PCI_LATENCY_TIMER, &pci_lat);
 
 	dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, "
 	       "latency: %d, mmio: 0x%llx\n", core->name, devno,
-	       pci_name(pci), chip->pci_rev, pci->irq,
-	       chip->pci_lat,(unsigned long long)pci_resource_start(pci,0));
+	       pci_name(pci), pci->revision, pci->irq,
+	       pci_lat, (unsigned long long)pci_resource_start(pci,0));
 
 	chip->irq = pci->irq;
 	synchronize_irq(chip->irq);
@@ -753,17 +759,12 @@
 		return (err);
 
 	err = snd_cx88_pcm(chip, 0, "CX88 Digital");
-
-	if (err < 0) {
-		snd_card_free(card);
-		return (err);
-	}
+	if (err < 0)
+		goto error;
 
 	err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_capture_volume, chip));
-	if (err < 0) {
-		snd_card_free(card);
-		return (err);
-	}
+	if (err < 0)
+		goto error;
 
 	strcpy (card->driver, "CX88x");
 	sprintf(card->shortname, "Conexant CX%x", pci->device);
@@ -775,16 +776,16 @@
 	       card->driver,devno);
 
 	err = snd_card_register(card);
-	if (err < 0) {
-		snd_card_free(card);
-		return (err);
-	}
-	snd_cx88_cards[devno] = card;
-
+	if (err < 0)
+		goto error;
 	pci_set_drvdata(pci,card);
 
 	devno++;
 	return 0;
+
+error:
+	snd_card_free(card);
+	return err;
 }
 /*
  * ALSA destructor
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index a80b1cb..6d6f504 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -27,7 +27,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/delay.h>
@@ -56,8 +55,7 @@
 
 /* ------------------------------------------------------------------ */
 
-#define OLD_BLACKBIRD_FIRM_IMAGE_SIZE 262144
-#define     BLACKBIRD_FIRM_IMAGE_SIZE 376836
+#define BLACKBIRD_FIRM_IMAGE_SIZE 376836
 
 /* defines below are from ivtv-driver.h */
 
@@ -405,7 +403,7 @@
 	u32 value;
 	int i;
 
-	for (i = 0; i < dev->fw_size; i++) {
+	for (i = 0; i < BLACKBIRD_FIRM_IMAGE_SIZE; i++) {
 		memory_read(dev->core, i, &value);
 		if (value == signature[signaturecnt])
 			signaturecnt++;
@@ -453,15 +451,12 @@
 		return -1;
 	}
 
-	if ((firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) &&
-	    (firmware->size != OLD_BLACKBIRD_FIRM_IMAGE_SIZE)) {
-		dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d or %d)\n",
-			firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE,
-			OLD_BLACKBIRD_FIRM_IMAGE_SIZE);
+	if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) {
+		dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d)\n",
+			firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE);
 		release_firmware(firmware);
 		return -1;
 	}
-	dev->fw_size = firmware->size;
 
 	if (0 != memcmp(firmware->data, magic, 8)) {
 		dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\n");
@@ -738,14 +733,14 @@
 	struct cx88_core  *core = dev->core;
 
 	strcpy(cap->driver, "cx88_blackbird");
-	strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card));
+	strlcpy(cap->card, core->board.name, sizeof(cap->card));
 	sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
 	cap->version = CX88_VERSION_CODE;
 	cap->capabilities =
 		V4L2_CAP_VIDEO_CAPTURE |
 		V4L2_CAP_READWRITE     |
 		V4L2_CAP_STREAMING;
-	if (UNSET != core->tuner_type)
+	if (UNSET != core->board.tuner_type)
 		cap->capabilities |= V4L2_CAP_TUNER;
 	return 0;
 }
@@ -881,7 +876,7 @@
 
 	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
 		return -EINVAL;
-	return cx2341x_ext_ctrls(&dev->params, f, VIDIOC_G_EXT_CTRLS);
+	return cx2341x_ext_ctrls(&dev->params, 0, f, VIDIOC_G_EXT_CTRLS);
 }
 
 static int vidioc_s_ext_ctrls (struct file *file, void *priv,
@@ -894,7 +889,7 @@
 	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
 		return -EINVAL;
 	p = dev->params;
-	err = cx2341x_ext_ctrls(&p, f, VIDIOC_S_EXT_CTRLS);
+	err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS);
 	if (!err) {
 		err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p);
 		dev->params = p;
@@ -912,7 +907,7 @@
 	if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
 		return -EINVAL;
 	p = dev->params;
-	err = cx2341x_ext_ctrls(&p, f, VIDIOC_TRY_EXT_CTRLS);
+	err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
 
 	return err;
 }
@@ -994,7 +989,7 @@
 	struct cx8802_fh  *fh   = priv;
 	struct cx88_core  *core = fh->dev->core;
 
-	if (unlikely(UNSET == core->tuner_type))
+	if (unlikely(UNSET == core->board.tuner_type))
 		return -EINVAL;
 
 	f->type = V4L2_TUNER_ANALOG_TV;
@@ -1032,7 +1027,7 @@
 	struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
 	u32 reg;
 
-	if (unlikely(UNSET == core->tuner_type))
+	if (unlikely(UNSET == core->board.tuner_type))
 		return -EINVAL;
 	if (0 != t->index)
 		return -EINVAL;
@@ -1053,7 +1048,7 @@
 {
 	struct cx88_core  *core = ((struct cx8802_fh *)priv)->dev->core;
 
-	if (UNSET == core->tuner_type)
+	if (UNSET == core->board.tuner_type)
 		return -EINVAL;
 	if (0 != t->index)
 		return -EINVAL;
@@ -1082,7 +1077,7 @@
 	struct cx8802_driver *drv = NULL;
 	int err;
 
-       dev = cx8802_get_device(inode);
+	dev = cx8802_get_device(inode);
 
 	dprintk( 1, "%s\n", __FUNCTION__);
 
@@ -1116,7 +1111,7 @@
 	file->private_data = fh;
 	fh->dev      = dev;
 
-	videobuf_queue_init(&fh->mpegq, &blackbird_qops,
+	videobuf_queue_pci_init(&fh->mpegq, &blackbird_qops,
 			    dev->pci, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_INTERLACED,
@@ -1239,7 +1234,7 @@
 	.vidioc_s_tuner       = vidioc_s_tuner,
 	.vidioc_s_std         = vidioc_s_std,
 	.tvnorms              = CX88_NORMS,
-       .current_norm         = V4L2_STD_NTSC_M,
+	.current_norm         = V4L2_STD_NTSC_M,
 };
 
 /* ------------------------------------------------------------------ */
@@ -1250,7 +1245,7 @@
 	struct cx88_core *core = drv->core;
 	int err = 0;
 
-	switch (core->board) {
+	switch (core->boardnr) {
 	case CX88_BOARD_HAUPPAUGE_HVR1300:
 		/* By default, core setup will leave the cx22702 out of reset, on the bus.
 		 * We left the hardware on power up with the cx22702 active.
@@ -1272,7 +1267,7 @@
 	struct cx88_core *core = drv->core;
 	int err = 0;
 
-	switch (core->board) {
+	switch (core->boardnr) {
 	case CX88_BOARD_HAUPPAUGE_HVR1300:
 		/* Exit leaving the cx23416 on the bus */
 		break;
@@ -1320,13 +1315,13 @@
 
 	dprintk( 1, "%s\n", __FUNCTION__);
 	dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
-		core->board,
+		core->boardnr,
 		core->name,
 		core->pci_bus,
 		core->pci_slot);
 
 	err = -ENODEV;
-	if (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD))
+	if (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))
 		goto fail_core;
 
 	dev->width = 720;
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index e61102d..a4eb6a8 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -27,10 +27,26 @@
 
 #include "cx88.h"
 
+static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+static unsigned int card[]  = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+
+module_param_array(tuner, int, NULL, 0444);
+module_param_array(radio, int, NULL, 0444);
+module_param_array(card,  int, NULL, 0444);
+
+MODULE_PARM_DESC(tuner,"tuner type");
+MODULE_PARM_DESC(radio,"radio tuner type");
+MODULE_PARM_DESC(card,"card type");
+
+static unsigned int latency = UNSET;
+module_param(latency,int,0444);
+MODULE_PARM_DESC(latency,"pci latency timer");
+
 /* ------------------------------------------------------------------ */
 /* board config info                                                  */
 
-struct cx88_board cx88_boards[] = {
+static const struct cx88_board cx88_boards[] = {
 	[CX88_BOARD_UNKNOWN] = {
 		.name		= "UNKNOWN/GENERIC",
 		.tuner_type     = UNSET,
@@ -575,35 +591,34 @@
 		.tuner_addr	= ADDR_UNSET,
 		.radio_addr	= ADDR_UNSET,
 		.tda9887_conf   = TDA9887_PRESENT,
+		/* GPIO[2] = audio source for analog audio out connector
+		 *  0 = analog audio input connector
+		 *  1 = CX88 audio DACs
+		 *
+		 * GPIO[7] = input to CX88's audio/chroma ADC
+		 *  0 = FM 10.7 MHz IF
+		 *  1 = Sound 4.5 MHz IF
+		 *
+		 * GPIO[1,5,6] = Oren 51132 pins 27,35,28 respectively
+		 *
+		 * GPIO[16] = Remote control input
+		 */
 		.input          = {{
 			.type   = CX88_VMUX_TELEVISION,
 			.vmux   = 0,
 			.gpio0  = 0x00008484,
-			.gpio1  = 0x00000000,
-			.gpio2  = 0x00000000,
-			.gpio3  = 0x00000000,
 		},{
 			.type   = CX88_VMUX_COMPOSITE1,
 			.vmux   = 1,
 			.gpio0  = 0x00008400,
-			.gpio1  = 0x00000000,
-			.gpio2  = 0x00000000,
-			.gpio3  = 0x00000000,
 		},{
 			.type   = CX88_VMUX_SVIDEO,
 			.vmux   = 2,
 			.gpio0  = 0x00008400,
-			.gpio1  = 0x00000000,
-			.gpio2  = 0x00000000,
-			.gpio3  = 0x00000000,
 		}},
 		.radio = {
 			.type   = CX88_RADIO,
-			.vmux   = 2,
-			.gpio0  = 0x00008400,
-			.gpio1  = 0x00000000,
-			.gpio2  = 0x00000000,
-			.gpio3  = 0x00000000,
+			.gpio0  = 0x00008404,
 		},
 		.mpeg           = CX88_MPEG_DVB,
 	},
@@ -1335,13 +1350,32 @@
 		/* fixme: Add radio support */
 		.mpeg           = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
 	},
+	[CX88_BOARD_ADSTECH_PTV_390] = {
+		.name           = "ADS Tech Instant Video PCI",
+		.tuner_type     = TUNER_ABSENT,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.input          = {{
+			.type   = CX88_VMUX_DEBUG,
+			.vmux   = 3,
+			.gpio0  = 0x04ff,
+		},{
+			.type   = CX88_VMUX_COMPOSITE1,
+			.vmux   = 1,
+			.gpio0  = 0x07fa,
+		},{
+			.type   = CX88_VMUX_SVIDEO,
+			.vmux   = 2,
+			.gpio0  = 0x07fa,
+		}},
+	},
 };
-const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
 
 /* ------------------------------------------------------------------ */
 /* PCI subsystem IDs                                                  */
 
-struct cx88_subid cx88_subids[] = {
+static const struct cx88_subid cx88_subids[] = {
 	{
 		.subvendor = 0x0070,
 		.subdevice = 0x3400,
@@ -1641,9 +1675,12 @@
 		.subvendor = 0x1421,
 		.subdevice = 0x0341, /* ADS Tech InstantTV DVB-S */
 		.card      = CX88_BOARD_KWORLD_DVBS_100,
+	},{
+		.subvendor = 0x1421,
+		.subdevice = 0x0390,
+		.card      = CX88_BOARD_ADSTECH_PTV_390,
 	},
 };
-const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
 
 /* ----------------------------------------------------------------------- */
 /* some leadtek specific stuff                                             */
@@ -1664,12 +1701,12 @@
 		return;
 	}
 
-	core->has_radio  = 1;
-	core->tuner_type = (eeprom_data[6] == 0x13) ? 43 : 38;
+	core->board.tuner_type = (eeprom_data[6] == 0x13) ?
+		TUNER_PHILIPS_FM1236_MK3 : TUNER_PHILIPS_FM1216ME_MK3;
 
 	printk(KERN_INFO "%s: Leadtek Winfast 2000XP Expert config: "
 	       "tuner=%d, eeprom[0]=0x%02x\n",
-	       core->name, core->tuner_type, eeprom_data[0]);
+	       core->name, core->board.tuner_type, eeprom_data[0]);
 }
 
 static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
@@ -1677,9 +1714,9 @@
 	struct tveeprom tv;
 
 	tveeprom_hauppauge_analog(&core->i2c_client, &tv, eeprom_data);
-	core->tuner_type = tv.tuner_type;
+	core->board.tuner_type = tv.tuner_type;
 	core->tuner_formats = tv.tuner_formats;
-	core->has_radio  = tv.has_radio;
+	core->board.radio.type = tv.has_radio ? CX88_RADIO : 0;
 
 	/* Make sure we support the board model */
 	switch (tv.model)
@@ -1769,8 +1806,9 @@
 	       name ? name : "unknown");
 	if (NULL == name)
 		return;
-	core->tuner_type = gdi_tuner[eeprom_data[0x0d]].id;
-	core->has_radio  = gdi_tuner[eeprom_data[0x0d]].fm;
+	core->board.tuner_type = gdi_tuner[eeprom_data[0x0d]].id;
+	core->board.radio.type = gdi_tuner[eeprom_data[0x0d]].fm ?
+		CX88_RADIO : 0;
 }
 
 /* ----------------------------------------------------------------------- */
@@ -1809,7 +1847,7 @@
 
 /* ----------------------------------------------------------------------- */
 
-void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
+static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
 {
 	int i;
 
@@ -1830,14 +1868,14 @@
 	}
 	printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
 	       core->name);
-	for (i = 0; i < cx88_bcount; i++)
+	for (i = 0; i < ARRAY_SIZE(cx88_boards); i++)
 		printk("%s:    card=%d -> %s\n",
 		       core->name, i, cx88_boards[i].name);
 }
 
-void cx88_card_setup_pre_i2c(struct cx88_core *core)
+static void cx88_card_setup_pre_i2c(struct cx88_core *core)
 {
-	switch (core->board) {
+	switch (core->boardnr) {
 	case CX88_BOARD_HAUPPAUGE_HVR1300:
 		/* Bring the 702 demod up before i2c scanning/attach or devices are hidden */
 		/* We leave here with the 702 on the bus */
@@ -1851,7 +1889,7 @@
 	}
 }
 
-void cx88_card_setup(struct cx88_core *core)
+static void cx88_card_setup(struct cx88_core *core)
 {
 	static u8 eeprom[256];
 
@@ -1860,7 +1898,7 @@
 		tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom));
 	}
 
-	switch (core->board) {
+	switch (core->boardnr) {
 	case CX88_BOARD_HAUPPAUGE:
 	case CX88_BOARD_HAUPPAUGE_ROSLYN:
 		if (0 == core->i2c_rc)
@@ -1904,7 +1942,7 @@
 		msleep(1);
 		cx_set(MO_GP0_IO, 0x00000101);
 		if (0 == core->i2c_rc &&
-		    core->board == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID)
+		    core->boardnr == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID)
 			dvico_fusionhdtv_hybrid_init(core);
 		break;
 	case CX88_BOARD_KWORLD_DVB_T:
@@ -1942,13 +1980,148 @@
 		}
 		break;
 	}
-	if (cx88_boards[core->board].radio.type == CX88_RADIO)
-		core->has_radio = 1;
 }
 
 /* ------------------------------------------------------------------ */
 
-EXPORT_SYMBOL(cx88_boards);
+static int cx88_pci_quirks(const char *name, struct pci_dev *pci)
+{
+	unsigned int lat = UNSET;
+	u8 ctrl = 0;
+	u8 value;
+
+	/* check pci quirks */
+	if (pci_pci_problems & PCIPCI_TRITON) {
+		printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n",
+		       name);
+		ctrl |= CX88X_EN_TBFX;
+	}
+	if (pci_pci_problems & PCIPCI_NATOMA) {
+		printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n",
+		       name);
+		ctrl |= CX88X_EN_TBFX;
+	}
+	if (pci_pci_problems & PCIPCI_VIAETBF) {
+		printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n",
+		       name);
+		ctrl |= CX88X_EN_TBFX;
+	}
+	if (pci_pci_problems & PCIPCI_VSFX) {
+		printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n",
+		       name);
+		ctrl |= CX88X_EN_VSFX;
+	}
+#ifdef PCIPCI_ALIMAGIK
+	if (pci_pci_problems & PCIPCI_ALIMAGIK) {
+		printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
+		       name);
+		lat = 0x0A;
+	}
+#endif
+
+	/* check insmod options */
+	if (UNSET != latency)
+		lat = latency;
+
+	/* apply stuff */
+	if (ctrl) {
+		pci_read_config_byte(pci, CX88X_DEVCTRL, &value);
+		value |= ctrl;
+		pci_write_config_byte(pci, CX88X_DEVCTRL, value);
+	}
+	if (UNSET != lat) {
+		printk(KERN_INFO "%s: setting pci latency timer to %d\n",
+		       name, latency);
+		pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency);
+	}
+	return 0;
+}
+
+int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci)
+{
+	if (request_mem_region(pci_resource_start(pci,0),
+			       pci_resource_len(pci,0),
+			       core->name))
+		return 0;
+	printk(KERN_ERR
+	       "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n",
+	       core->name, PCI_FUNC(pci->devfn),
+	       (unsigned long long)pci_resource_start(pci, 0),
+	       pci->subsystem_vendor, pci->subsystem_device);
+	return -EBUSY;
+}
+
+/* Allocate and initialize the cx88 core struct.  One should hold the
+ * devlist mutex before calling this.  */
+struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
+{
+	struct cx88_core *core;
+	int i;
+
+	core = kzalloc(sizeof(*core), GFP_KERNEL);
+
+	atomic_inc(&core->refcount);
+	core->pci_bus  = pci->bus->number;
+	core->pci_slot = PCI_SLOT(pci->devfn);
+	core->pci_irqmask = PCI_INT_RISC_RD_BERRINT | PCI_INT_RISC_WR_BERRINT |
+			    PCI_INT_BRDG_BERRINT | PCI_INT_SRC_DMA_BERRINT |
+			    PCI_INT_DST_DMA_BERRINT | PCI_INT_IPB_DMA_BERRINT;
+	mutex_init(&core->lock);
+
+	core->nr = nr;
+	sprintf(core->name, "cx88[%d]", core->nr);
+	if (0 != cx88_get_resources(core, pci)) {
+		kfree(core);
+		return NULL;
+	}
+
+	/* PCI stuff */
+	cx88_pci_quirks(core->name, pci);
+	core->lmmio = ioremap(pci_resource_start(pci, 0),
+			      pci_resource_len(pci, 0));
+	core->bmmio = (u8 __iomem *)core->lmmio;
+
+	/* board config */
+	core->boardnr = UNSET;
+	if (card[core->nr] < ARRAY_SIZE(cx88_boards))
+		core->boardnr = card[core->nr];
+	for (i = 0; UNSET == core->boardnr && i < ARRAY_SIZE(cx88_subids); i++)
+		if (pci->subsystem_vendor == cx88_subids[i].subvendor &&
+		    pci->subsystem_device == cx88_subids[i].subdevice)
+			core->boardnr = cx88_subids[i].card;
+	if (UNSET == core->boardnr) {
+		core->boardnr = CX88_BOARD_UNKNOWN;
+		cx88_card_list(core, pci);
+	}
+
+	memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board));
+
+	printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+		core->name,pci->subsystem_vendor,
+		pci->subsystem_device, core->board.name,
+		core->boardnr, card[core->nr] == core->boardnr ?
+		"insmod option" : "autodetected");
+
+	if (tuner[core->nr] != UNSET)
+		core->board.tuner_type = tuner[core->nr];
+	if (radio[core->nr] != UNSET)
+		core->board.radio_type = radio[core->nr];
+
+	printk(KERN_INFO "%s: TV tuner type %d, Radio tuner type %d\n",
+	       core->name, core->board.tuner_type, core->board.radio_type);
+
+	/* init hardware */
+	cx88_reset(core);
+	cx88_card_setup_pre_i2c(core);
+	cx88_i2c_init(core, pci);
+	cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
+	cx88_card_setup(core);
+	cx88_ir_init(core, pci);
+
+	return core;
+}
+
+/* ------------------------------------------------------------------ */
 
 /*
  * Local variables:
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index f31ec96..62e8dd2 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -28,7 +28,6 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/kmod.h>
@@ -52,22 +51,6 @@
 module_param(core_debug,int,0644);
 MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
 
-static unsigned int latency = UNSET;
-module_param(latency,int,0444);
-MODULE_PARM_DESC(latency,"pci latency timer");
-
-static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
-static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
-static unsigned int card[]  = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
-
-module_param_array(tuner, int, NULL, 0444);
-module_param_array(radio, int, NULL, 0444);
-module_param_array(card,  int, NULL, 0444);
-
-MODULE_PARM_DESC(tuner,"tuner type");
-MODULE_PARM_DESC(radio,"radio tuner type");
-MODULE_PARM_DESC(card,"card type");
-
 static unsigned int nicam = 0;
 module_param(nicam,int,0644);
 MODULE_PARM_DESC(nicam,"tv audio is nicam");
@@ -85,13 +68,15 @@
 
 #define NO_SYNC_LINE (-1U)
 
+/* @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be
+	 generated _after_ lpi lines are transferred. */
 static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
 			    unsigned int offset, u32 sync_line,
 			    unsigned int bpl, unsigned int padding,
-			    unsigned int lines)
+			    unsigned int lines, unsigned int lpi)
 {
 	struct scatterlist *sg;
-	unsigned int line,todo;
+	unsigned int line,todo,sol;
 
 	/* sync instruction */
 	if (sync_line != NO_SYNC_LINE)
@@ -104,15 +89,19 @@
 			offset -= sg_dma_len(sg);
 			sg++;
 		}
+		if (lpi && line>0 && !(line % lpi))
+			sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC;
+		else
+			sol = RISC_SOL;
 		if (bpl <= sg_dma_len(sg)-offset) {
 			/* fits into current chunk */
-			*(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|RISC_EOL|bpl);
+			*(rp++)=cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl);
 			*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
 			offset+=bpl;
 		} else {
 			/* scanline needs to be split */
 			todo = bpl;
-			*(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
+			*(rp++)=cpu_to_le32(RISC_WRITE|sol|
 					    (sg_dma_len(sg)-offset));
 			*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
 			todo -= (sg_dma_len(sg)-offset);
@@ -163,10 +152,10 @@
 	rp = risc->cpu;
 	if (UNSET != top_offset)
 		rp = cx88_risc_field(rp, sglist, top_offset, 0,
-				     bpl, padding, lines);
+				     bpl, padding, lines, 0);
 	if (UNSET != bottom_offset)
 		rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200,
-				     bpl, padding, lines);
+				     bpl, padding, lines, 0);
 
 	/* save pointer to jmp instruction address */
 	risc->jmp = rp;
@@ -176,7 +165,7 @@
 
 int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
 			 struct scatterlist *sglist, unsigned int bpl,
-			 unsigned int lines)
+			 unsigned int lines, unsigned int lpi)
 {
 	u32 instructions;
 	u32 *rp;
@@ -193,7 +182,7 @@
 
 	/* write risc instructions */
 	rp = risc->cpu;
-	rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines);
+	rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines, lpi);
 
 	/* save pointer to jmp instruction address */
 	risc->jmp = rp;
@@ -224,10 +213,12 @@
 void
 cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
 {
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
 	BUG_ON(in_interrupt());
 	videobuf_waiton(&buf->vb,0,0);
-	videobuf_dma_unmap(q, &buf->vb.dma);
-	videobuf_dma_free(&buf->vb.dma);
+	videobuf_dma_unmap(q, dma);
+	videobuf_dma_free(dma);
 	btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
 	buf->vb.state = STATE_NEEDS_INIT;
 }
@@ -451,10 +442,13 @@
 		printk("%s:   cmds: %-12s: 0x%08x\n",
 		       core->name,name[i],
 		       cx_read(ch->cmds_start + 4*i));
-	for (i = 0; i < 4; i++) {
+	for (n = 1, i = 0; i < 4; i++) {
 		risc = cx_read(ch->cmds_start + 4 * (i+11));
 		printk("%s:   risc%d: ", core->name, i);
-		cx88_risc_decode(risc);
+		if (--n)
+			printk("0x%08x [ arg #%d ]\n", risc, n);
+		else
+			n = cx88_risc_decode(risc);
 	}
 	for (i = 0; i < 16; i += n) {
 		risc = cx_read(ch->ctrl_start + 4 * i);
@@ -514,7 +508,7 @@
 {
 	int handled = 0;
 
-	if (status & (1<<18)) {
+	if (status & PCI_INT_IR_SMPINT) {
 		cx88_ir_irq(core);
 		handled++;
 	}
@@ -738,7 +732,7 @@
 		value |= (1 << 15);
 		value |= (1 << 16);
 	}
-	if (INPUT(core->input)->type == CX88_VMUX_SVIDEO)
+	if (INPUT(core->input).type == CX88_VMUX_SVIDEO)
 		value |= (1 << 13) | (1 << 5);
 	if (V4L2_FIELD_INTERLACED == field)
 		value |= (1 << 3); // VINT (interlaced vertical scaling)
@@ -833,7 +827,7 @@
 {
 	v4l2_std_id norm = core->tvnorm;
 
-	if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
+	if (CX88_VMUX_TELEVISION != INPUT(core->input).type)
 		return 0;
 
 	if (V4L2_STD_PAL_BG & norm) {
@@ -997,61 +991,6 @@
 
 /* ------------------------------------------------------------------ */
 
-static int cx88_pci_quirks(char *name, struct pci_dev *pci)
-{
-	unsigned int lat = UNSET;
-	u8 ctrl = 0;
-	u8 value;
-
-	/* check pci quirks */
-	if (pci_pci_problems & PCIPCI_TRITON) {
-		printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n",
-		       name);
-		ctrl |= CX88X_EN_TBFX;
-	}
-	if (pci_pci_problems & PCIPCI_NATOMA) {
-		printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n",
-		       name);
-		ctrl |= CX88X_EN_TBFX;
-	}
-	if (pci_pci_problems & PCIPCI_VIAETBF) {
-		printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n",
-		       name);
-		ctrl |= CX88X_EN_TBFX;
-	}
-	if (pci_pci_problems & PCIPCI_VSFX) {
-		printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n",
-		       name);
-		ctrl |= CX88X_EN_VSFX;
-	}
-#ifdef PCIPCI_ALIMAGIK
-	if (pci_pci_problems & PCIPCI_ALIMAGIK) {
-		printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
-		       name);
-		lat = 0x0A;
-	}
-#endif
-
-	/* check insmod options */
-	if (UNSET != latency)
-		lat = latency;
-
-	/* apply stuff */
-	if (ctrl) {
-		pci_read_config_byte(pci, CX88X_DEVCTRL, &value);
-		value |= ctrl;
-		pci_write_config_byte(pci, CX88X_DEVCTRL, value);
-	}
-	if (UNSET != lat) {
-		printk(KERN_INFO "%s: setting pci latency timer to %d\n",
-		       name, latency);
-		pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency);
-	}
-	return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
 struct video_device *cx88_vdev_init(struct cx88_core *core,
 				    struct pci_dev *pci,
 				    struct video_device *template,
@@ -1067,122 +1006,38 @@
 	vfd->dev     = &pci->dev;
 	vfd->release = video_device_release;
 	snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
-		 core->name, type, cx88_boards[core->board].name);
+		 core->name, type, core->board.name);
 	return vfd;
 }
 
-static int get_ressources(struct cx88_core *core, struct pci_dev *pci)
-{
-	if (request_mem_region(pci_resource_start(pci,0),
-			       pci_resource_len(pci,0),
-			       core->name))
-		return 0;
-	printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
-	       core->name,(unsigned long long)pci_resource_start(pci,0));
-	return -EBUSY;
-}
-
 struct cx88_core* cx88_core_get(struct pci_dev *pci)
 {
 	struct cx88_core *core;
-	struct list_head *item;
-	int i;
 
 	mutex_lock(&devlist);
-	list_for_each(item,&cx88_devlist) {
-		core = list_entry(item, struct cx88_core, devlist);
+	list_for_each_entry(core, &cx88_devlist, devlist) {
 		if (pci->bus->number != core->pci_bus)
 			continue;
 		if (PCI_SLOT(pci->devfn) != core->pci_slot)
 			continue;
 
-		if (0 != get_ressources(core,pci))
-			goto fail_unlock;
+		if (0 != cx88_get_resources(core, pci)) {
+			mutex_unlock(&devlist);
+			return NULL;
+		}
 		atomic_inc(&core->refcount);
 		mutex_unlock(&devlist);
 		return core;
 	}
-	core = kzalloc(sizeof(*core),GFP_KERNEL);
-	if (NULL == core)
-		goto fail_unlock;
 
-	atomic_inc(&core->refcount);
-	core->pci_bus  = pci->bus->number;
-	core->pci_slot = PCI_SLOT(pci->devfn);
-	core->pci_irqmask = 0x00fc00;
-	mutex_init(&core->lock);
-
-	core->nr = cx88_devcount++;
-	sprintf(core->name,"cx88[%d]",core->nr);
-	if (0 != get_ressources(core,pci)) {
-		printk(KERN_ERR "CORE %s No more PCI ressources for "
-			"subsystem: %04x:%04x, board: %s\n",
-			core->name,pci->subsystem_vendor,
-			pci->subsystem_device,
-			cx88_boards[core->board].name);
-
-		cx88_devcount--;
-		goto fail_free;
+	core = cx88_core_create(pci, cx88_devcount);
+	if (NULL != core) {
+		cx88_devcount++;
+		list_add_tail(&core->devlist, &cx88_devlist);
 	}
-	list_add_tail(&core->devlist,&cx88_devlist);
-
-	/* PCI stuff */
-	cx88_pci_quirks(core->name, pci);
-	core->lmmio = ioremap(pci_resource_start(pci,0),
-			      pci_resource_len(pci,0));
-	core->bmmio = (u8 __iomem *)core->lmmio;
-
-	/* board config */
-	core->board = UNSET;
-	if (card[core->nr] < cx88_bcount)
-		core->board = card[core->nr];
-	for (i = 0; UNSET == core->board  &&  i < cx88_idcount; i++)
-		if (pci->subsystem_vendor == cx88_subids[i].subvendor &&
-		    pci->subsystem_device == cx88_subids[i].subdevice)
-			core->board = cx88_subids[i].card;
-	if (UNSET == core->board) {
-		core->board = CX88_BOARD_UNKNOWN;
-		cx88_card_list(core,pci);
-	}
-	printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
-		core->name,pci->subsystem_vendor,
-		pci->subsystem_device,cx88_boards[core->board].name,
-		core->board, card[core->nr] == core->board ?
-		"insmod option" : "autodetected");
-
-	core->tuner_type = tuner[core->nr];
-	core->radio_type = radio[core->nr];
-	if (UNSET == core->tuner_type)
-		core->tuner_type = cx88_boards[core->board].tuner_type;
-	if (UNSET == core->radio_type)
-		core->radio_type = cx88_boards[core->board].radio_type;
-	if (!core->tuner_addr)
-		core->tuner_addr = cx88_boards[core->board].tuner_addr;
-	if (!core->radio_addr)
-		core->radio_addr = cx88_boards[core->board].radio_addr;
-
-	printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
-		core->tuner_type, core->tuner_addr<<1,
-		core->radio_type, core->radio_addr<<1);
-
-	core->tda9887_conf = cx88_boards[core->board].tda9887_conf;
-
-	/* init hardware */
-	cx88_reset(core);
-	cx88_card_setup_pre_i2c(core);
-	cx88_i2c_init(core,pci);
-	cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
-	cx88_card_setup(core);
-	cx88_ir_init(core,pci);
 
 	mutex_unlock(&devlist);
 	return core;
-
-fail_free:
-	kfree(core);
-fail_unlock:
-	mutex_unlock(&devlist);
-	return NULL;
 }
 
 void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
@@ -1229,6 +1084,9 @@
 EXPORT_SYMBOL(cx88_core_get);
 EXPORT_SYMBOL(cx88_core_put);
 
+EXPORT_SYMBOL(cx88_ir_start);
+EXPORT_SYMBOL(cx88_ir_stop);
+
 /*
  * Local variables:
  * c-basic-offset: 8
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index dbfe4dc..d16e5c6 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -35,9 +35,7 @@
 
 #include "mt352.h"
 #include "mt352_priv.h"
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
-# include "cx88-vp3054-i2c.h"
-#endif
+#include "cx88-vp3054-i2c.h"
 #include "zl10353.h"
 #include "cx22702.h"
 #include "or51132.h"
@@ -199,7 +197,7 @@
 	.demod_init    = dvico_dual_demod_init,
 };
 
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
 static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
 {
 	static u8 clock_config []  = { 0x89, 0x38, 0x38 };
@@ -223,64 +221,6 @@
 	return 0;
 }
 
-static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
-{
-	struct cx8802_dev *dev= fe->dvb->priv;
-
-	/* this message is to set up ATC and ALC */
-	static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
-	struct i2c_msg msg =
-		{ .addr = dev->core->pll_addr, .flags = 0,
-		  .buf = fmd1216_init, .len = sizeof(fmd1216_init) };
-	int err;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
-		if (err < 0)
-			return err;
-		else
-			return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
-static int dntv_live_dvbt_pro_tuner_set_params(struct dvb_frontend* fe,
-					       struct dvb_frontend_parameters* params)
-{
-	struct cx8802_dev *dev= fe->dvb->priv;
-	u8 buf[4];
-	struct i2c_msg msg =
-		{ .addr = dev->core->pll_addr, .flags = 0,
-		  .buf = buf, .len = 4 };
-	int err;
-
-	/* Switch PLL to DVB mode */
-	err = philips_fmd1216_pll_init(fe);
-	if (err)
-		return err;
-
-	/* Tune PLL */
-	dvb_pll_configure(dev->core->pll_desc, buf,
-			  params->frequency,
-			  params->u.ofdm.bandwidth);
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
-
-		printk(KERN_WARNING "cx88-dvb: %s error "
-		       "(addr %02x <- %02x, err = %i)\n",
-		       __FUNCTION__, dev->core->pll_addr, buf[0], err);
-		if (err < 0)
-			return err;
-		else
-			return -EREMOTEIO;
-	}
-
-	return 0;
-}
-
 static struct mt352_config dntv_live_dvbt_pro_config = {
 	.demod_address = 0x0f,
 	.no_tuner      = 1,
@@ -370,18 +310,8 @@
 	return 0;
 }
 
-static int nxt200x_set_pll_input(u8* buf, int input)
-{
-	if (input)
-		buf[3] |= 0x08;
-	else
-		buf[3] &= ~0x08;
-	return 0;
-}
-
 static struct nxt200x_config ati_hdtvwonder = {
 	.demod_address = 0x0a,
-	.set_pll_input = nxt200x_set_pll_input,
 	.set_ts_params = nxt200x_set_ts_param,
 };
 
@@ -448,7 +378,7 @@
 	dev->ts_gen_cntrl = 0x0c;
 
 	/* init frontend */
-	switch (dev->core->board) {
+	switch (dev->core->boardnr) {
 	case CX88_BOARD_HAUPPAUGE_DVB_T1:
 		dev->dvb.frontend = dvb_attach(cx22702_attach,
 					       &connexant_refboard_config,
@@ -456,7 +386,7 @@
 		if (dev->dvb.frontend != NULL) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
 				   &dev->core->i2c_adap,
-				   &dvb_pll_thomson_dtt759x);
+				   DVB_PLL_THOMSON_DTT759X);
 		}
 		break;
 	case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
@@ -469,7 +399,7 @@
 		if (dev->dvb.frontend != NULL) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
 				   &dev->core->i2c_adap,
-				   &dvb_pll_thomson_dtt7579);
+				   DVB_PLL_THOMSON_DTT7579);
 		}
 		break;
 	case CX88_BOARD_WINFAST_DTV2000H:
@@ -482,7 +412,7 @@
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   &dev->core->i2c_adap, &dvb_pll_fmd1216me);
+				   &dev->core->i2c_adap, DVB_PLL_FMD1216ME);
 		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
@@ -491,7 +421,7 @@
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
-				   NULL, &dvb_pll_thomson_dtt7579);
+				   NULL, DVB_PLL_THOMSON_DTT7579);
 			break;
 		}
 		/* ZL10353 replaces MT352 on later cards */
@@ -500,7 +430,7 @@
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
-				   NULL, &dvb_pll_thomson_dtt7579);
+				   NULL, DVB_PLL_THOMSON_DTT7579);
 		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
@@ -511,7 +441,7 @@
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   NULL, &dvb_pll_thomson_dtt7579);
+				   NULL, DVB_PLL_THOMSON_DTT7579);
 			break;
 		}
 		/* ZL10353 replaces MT352 on later cards */
@@ -520,7 +450,7 @@
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   NULL, &dvb_pll_thomson_dtt7579);
+				   NULL, DVB_PLL_THOMSON_DTT7579);
 		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
@@ -529,7 +459,7 @@
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   NULL, &dvb_pll_lg_z201);
+				   NULL, DVB_PLL_LG_Z201);
 		}
 		break;
 	case CX88_BOARD_KWORLD_DVB_T:
@@ -540,20 +470,19 @@
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   NULL, &dvb_pll_unknown_1);
+				   NULL, DVB_PLL_UNKNOWN_1);
 		}
 		break;
 	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
-		dev->core->pll_addr = 0x61;
-		dev->core->pll_desc = &dvb_pll_fmd1216me;
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
 		dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
 			&((struct vp3054_i2c_state *)dev->card_priv)->adap);
 		if (dev->dvb.frontend != NULL) {
-			dev->dvb.frontend->ops.tuner_ops.set_params = dntv_live_dvbt_pro_tuner_set_params;
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+				   &dev->core->i2c_adap, DVB_PLL_FMD1216ME);
 		}
 #else
-		printk("%s: built without vp3054 support\n", dev->core->name);
+		printk(KERN_ERR "%s/2: built without vp3054 support\n", dev->core->name);
 #endif
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
@@ -563,7 +492,7 @@
 		if (dev->dvb.frontend != NULL) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
 				   &dev->core->i2c_adap,
-				   &dvb_pll_thomson_fe6600);
+				   DVB_PLL_THOMSON_FE6600);
 		}
 		break;
 	case CX88_BOARD_PCHDTV_HD3000:
@@ -572,7 +501,7 @@
 		if (dev->dvb.frontend != NULL) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
 				   &dev->core->i2c_adap,
-				   &dvb_pll_thomson_dtt761x);
+				   DVB_PLL_THOMSON_DTT761X);
 		}
 		break;
 	case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
@@ -594,7 +523,7 @@
 		if (dev->dvb.frontend != NULL) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
 				   &dev->core->i2c_adap,
-				   &dvb_pll_microtune_4042);
+				   DVB_PLL_MICROTUNE_4042);
 		}
 		}
 		break;
@@ -614,7 +543,7 @@
 		if (dev->dvb.frontend != NULL) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
 				   &dev->core->i2c_adap,
-				   &dvb_pll_thomson_dtt761x);
+				   DVB_PLL_THOMSON_DTT761X);
 		}
 		}
 		break;
@@ -634,7 +563,7 @@
 		if (dev->dvb.frontend != NULL) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
 				   &dev->core->i2c_adap,
-				   &dvb_pll_lg_tdvs_h06xf);
+				   DVB_PLL_LG_TDVS_H06XF);
 		}
 		}
 		break;
@@ -654,7 +583,7 @@
 		if (dev->dvb.frontend != NULL) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
 				   &dev->core->i2c_adap,
-				   &dvb_pll_lg_tdvs_h06xf);
+				   DVB_PLL_LG_TDVS_H06XF);
 		}
 		}
 		break;
@@ -664,7 +593,7 @@
 					       &dev->core->i2c_adap);
 		if (dev->dvb.frontend != NULL) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   NULL, &dvb_pll_tuv1236d);
+				   NULL, DVB_PLL_TUV1236D);
 		}
 		break;
 	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
@@ -696,19 +625,15 @@
 		}
 		break;
 	default:
-		printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
+		printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
 		       dev->core->name);
 		break;
 	}
 	if (NULL == dev->dvb.frontend) {
-		printk("%s: frontend initialization failed\n",dev->core->name);
+		printk(KERN_ERR "%s/2: frontend initialization failed\n", dev->core->name);
 		return -1;
 	}
 
-	if (dev->core->pll_desc) {
-		dev->dvb.frontend->ops.info.frequency_min = dev->core->pll_desc->min;
-		dev->dvb.frontend->ops.info.frequency_max = dev->core->pll_desc->max;
-	}
 	/* Ensure all frontends negotiate bus access */
 	dev->dvb.frontend->ops.ts_bus_ctrl = cx88_dvb_bus_ctrl;
 
@@ -728,7 +653,7 @@
 	int err = 0;
 	dprintk( 1, "%s\n", __FUNCTION__);
 
-	switch (core->board) {
+	switch (core->boardnr) {
 	case CX88_BOARD_HAUPPAUGE_HVR1300:
 		/* We arrive here with either the cx23416 or the cx22702
 		 * on the bus. Take the bus from the cx23416 and enable the
@@ -751,7 +676,7 @@
 	int err = 0;
 	dprintk( 1, "%s\n", __FUNCTION__);
 
-	switch (core->board) {
+	switch (core->boardnr) {
 	case CX88_BOARD_HAUPPAUGE_HVR1300:
 		/* Do Nothing, leave the cx22702 on the bus. */
 		break;
@@ -769,24 +694,23 @@
 
 	dprintk( 1, "%s\n", __FUNCTION__);
 	dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
-		core->board,
+		core->boardnr,
 		core->name,
 		core->pci_bus,
 		core->pci_slot);
 
 	err = -ENODEV;
-	if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB))
+	if (!(core->board.mpeg & CX88_MPEG_DVB))
 		goto fail_core;
 
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
+	/* If vp3054 isn't enabled, a stub will just return 0 */
 	err = vp3054_i2c_probe(dev);
 	if (0 != err)
 		goto fail_core;
-#endif
 
 	/* dvb stuff */
-	printk("%s/2: cx2388x based dvb card\n", core->name);
-	videobuf_queue_init(&dev->dvb.dvbq, &dvb_qops,
+	printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name);
+	videobuf_queue_pci_init(&dev->dvb.dvbq, &dvb_qops,
 			    dev->pci, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_TOP,
@@ -794,7 +718,8 @@
 			    dev);
 	err = dvb_register(dev);
 	if (err != 0)
-		printk("%s dvb_register failed err = %d\n", __FUNCTION__, err);
+		printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n",
+		       core->name, err);
 
  fail_core:
 	return err;
@@ -807,9 +732,7 @@
 	/* dvb */
 	videobuf_dvb_unregister(&dev->dvb);
 
-#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
 	vp3054_i2c_remove(dev);
-#endif
 
 	return 0;
 }
@@ -825,7 +748,7 @@
 
 static int dvb_init(void)
 {
-	printk(KERN_INFO "cx2388x dvb driver version %d.%d.%d loaded\n",
+	printk(KERN_INFO "cx88/2: cx2388x dvb driver version %d.%d.%d loaded\n",
 	       (CX88_VERSION_CODE >> 16) & 0xff,
 	       (CX88_VERSION_CODE >>  8) & 0xff,
 	       CX88_VERSION_CODE & 0xff);
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 7919a1f..c8b1c50 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -28,7 +28,6 @@
 */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 
 #include <asm/io.h>
@@ -108,28 +107,28 @@
 	if (!client->driver->command)
 		return 0;
 
-	if (core->radio_type != UNSET) {
-		if ((core->radio_addr==ADDR_UNSET)||(core->radio_addr==client->addr)) {
+	if (core->board.radio_type != UNSET) {
+		if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) {
 			tun_setup.mode_mask = T_RADIO;
-			tun_setup.type = core->radio_type;
-			tun_setup.addr = core->radio_addr;
+			tun_setup.type = core->board.radio_type;
+			tun_setup.addr = core->board.radio_addr;
 
 			client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
 		}
 	}
-	if (core->tuner_type != UNSET) {
-		if ((core->tuner_addr==ADDR_UNSET)||(core->tuner_addr==client->addr)) {
+	if (core->board.tuner_type != UNSET) {
+		if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) {
 
 			tun_setup.mode_mask = T_ANALOG_TV;
-			tun_setup.type = core->tuner_type;
-			tun_setup.addr = core->tuner_addr;
+			tun_setup.type = core->board.tuner_type;
+			tun_setup.addr = core->board.tuner_addr;
 
 			client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup);
 		}
 	}
 
-	if (core->tda9887_conf)
-		client->driver->command(client, TDA9887_SET_CONFIG, &core->tda9887_conf);
+	if (core->board.tda9887_conf)
+		client->driver->command(client, TDA9887_SET_CONFIG, &core->board.tda9887_conf);
 	return 0;
 }
 
@@ -146,7 +145,7 @@
 	if (0 != core->i2c_rc)
 		return;
 
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
+#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
 	if ( (core->dvbdev) && (core->dvbdev->dvb.frontend) ) {
 		if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
 			core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
@@ -160,7 +159,7 @@
 		i2c_clients_command(&core->i2c_adap, cmd, arg);
 }
 
-static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
+static const struct i2c_algo_bit_data cx8800_i2c_algo_template = {
 	.setsda  = cx8800_bit_setsda,
 	.setscl  = cx8800_bit_setscl,
 	.getsda  = cx8800_bit_getsda,
@@ -171,18 +170,6 @@
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_adapter cx8800_i2c_adap_template = {
-	.name              = "cx2388x",
-	.owner             = THIS_MODULE,
-	.id                = I2C_HW_B_CX2388x,
-	.client_register   = attach_inform,
-	.client_unregister = detach_inform,
-};
-
-static struct i2c_client cx8800_i2c_client_template = {
-	.name	= "cx88xx internal",
-};
-
 static char *i2c_devs[128] = {
 	[ 0x1c >> 1 ] = "lgdt330x",
 	[ 0x86 >> 1 ] = "tda9887/cx22702",
@@ -212,26 +199,27 @@
 	/* Prevents usage of invalid delay values */
 	if (i2c_udelay<5)
 		i2c_udelay=5;
-	cx8800_i2c_algo_template.udelay=i2c_udelay;
 
-	memcpy(&core->i2c_adap, &cx8800_i2c_adap_template,
-	       sizeof(core->i2c_adap));
 	memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
 	       sizeof(core->i2c_algo));
-	memcpy(&core->i2c_client, &cx8800_i2c_client_template,
-	       sizeof(core->i2c_client));
 
-	if (core->tuner_type != TUNER_ABSENT)
+	if (core->board.tuner_type != TUNER_ABSENT)
 		core->i2c_adap.class |= I2C_CLASS_TV_ANALOG;
-	if (cx88_boards[core->board].mpeg & CX88_MPEG_DVB)
+	if (core->board.mpeg & CX88_MPEG_DVB)
 		core->i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
 
 	core->i2c_adap.dev.parent = &pci->dev;
 	strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
+	core->i2c_adap.owner = THIS_MODULE;
+	core->i2c_adap.id = I2C_HW_B_CX2388x;
+	core->i2c_adap.client_register = attach_inform;
+	core->i2c_adap.client_unregister = detach_inform;
+	core->i2c_algo.udelay = i2c_udelay;
 	core->i2c_algo.data = core;
 	i2c_set_adapdata(&core->i2c_adap,core);
 	core->i2c_adap.algo_data = &core->i2c_algo;
 	core->i2c_client.adapter = &core->i2c_adap;
+	strlcpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE);
 
 	cx8800_bit_setscl(core,1);
 	cx8800_bit_setsda(core,1);
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index 8136673..e52de39 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -27,7 +27,6 @@
 #include <linux/input.h>
 #include <linux/pci.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 
 #include "cx88.h"
 #include <media/ir-common.h>
@@ -74,7 +73,8 @@
 
 	/* read gpio value */
 	gpio = cx_read(ir->gpio_addr);
-	if (core->board == CX88_BOARD_NPGTECH_REALTV_TOP10FM) {
+	switch (core->boardnr) {
+	case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
 		/* This board apparently uses a combination of 2 GPIO
 		   to represent the keys. Additionally, the second GPIO
 		   can be used for parity.
@@ -90,9 +90,14 @@
 		auxgpio = cx_read(MO_GP1_IO);
 		/* Take out the parity part */
 		gpio=(gpio & 0x7fd) + (auxgpio & 0xef);
-	} else
+		break;
+	case CX88_BOARD_WINFAST_DTV1000:
+		gpio = (gpio & 0x6ff) | ((cx_read(MO_GP1_IO) << 8) & 0x900);
 		auxgpio = gpio;
-
+		break;
+	default:
+		auxgpio = gpio;
+	}
 	if (ir->polling) {
 		if (ir->last_gpio == auxgpio)
 			return;
@@ -107,7 +112,7 @@
 		   (gpio & ir->mask_keydown) ? " down" : "",
 		   (gpio & ir->mask_keyup) ? " up" : "");
 
-	if (ir->core->board == CX88_BOARD_NORWOOD_MICRO) {
+	if (ir->core->boardnr == CX88_BOARD_NORWOOD_MICRO) {
 		u32 gpio_key = cx_read(MO_GP0_IO);
 
 		data = (data << 4) | ((gpio_key & 0xf0) >> 4);
@@ -148,34 +153,30 @@
 static void cx88_ir_work(struct work_struct *work)
 {
 	struct cx88_IR *ir = container_of(work, struct cx88_IR, work);
-	unsigned long timeout;
 
 	cx88_ir_handle_key(ir);
-	timeout = jiffies + (ir->polling * HZ / 1000);
-	mod_timer(&ir->timer, timeout);
+	mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
 }
 
-static void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
+void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir)
 {
 	if (ir->polling) {
+		setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
 		INIT_WORK(&ir->work, cx88_ir_work);
-		init_timer(&ir->timer);
-		ir->timer.function = ir_timer;
-		ir->timer.data = (unsigned long)ir;
 		schedule_work(&ir->work);
 	}
 	if (ir->sampling) {
-		core->pci_irqmask |= (1 << 18);	/* IR_SMP_INT */
+		core->pci_irqmask |= PCI_INT_IR_SMPINT;
 		cx_write(MO_DDS_IO, 0xa80a80);	/* 4 kHz sample rate */
 		cx_write(MO_DDSCFG_IO, 0x5);	/* enable */
 	}
 }
 
-static void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir)
+void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir)
 {
 	if (ir->sampling) {
 		cx_write(MO_DDSCFG_IO, 0x0);
-		core->pci_irqmask &= ~(1 << 18);
+		core->pci_irqmask &= ~PCI_INT_IR_SMPINT;
 	}
 
 	if (ir->polling) {
@@ -202,7 +203,7 @@
 	ir->input = input_dev;
 
 	/* detect & configure */
-	switch (core->board) {
+	switch (core->boardnr) {
 	case CX88_BOARD_DNTV_LIVE_DVB_T:
 	case CX88_BOARD_KWORLD_DVB_T:
 	case CX88_BOARD_KWORLD_DVB_T_CX22702:
@@ -222,7 +223,6 @@
 	case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
 	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
 	case CX88_BOARD_HAUPPAUGE_HVR1100:
-	case CX88_BOARD_HAUPPAUGE_HVR1300:
 	case CX88_BOARD_HAUPPAUGE_HVR3000:
 		ir_codes = ir_codes_hauppauge_new;
 		ir_type = IR_TYPE_RC5;
@@ -236,6 +236,7 @@
 		ir->polling = 50; /* ms */
 		break;
 	case CX88_BOARD_WINFAST2000XP_EXPERT:
+	case CX88_BOARD_WINFAST_DTV1000:
 		ir_codes = ir_codes_winfast;
 		ir->gpio_addr = MO_GP0_IO;
 		ir->mask_keycode = 0x8f8;
@@ -312,8 +313,7 @@
 	}
 
 	/* init input device */
-	snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)",
-		 cx88_boards[core->board].name);
+	snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name);
 	snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci));
 
 	ir_input_init(input_dev, &ir->ir, ir_type, ir_codes);
@@ -328,7 +328,7 @@
 		input_dev->id.vendor = pci->vendor;
 		input_dev->id.product = pci->device;
 	}
-	input_dev->cdev.dev = &pci->dev;
+	input_dev->dev.parent = &pci->dev;
 	/* record handles to ourself */
 	ir->core = core;
 	core->ir = ir;
@@ -404,7 +404,7 @@
 		ir_dump_samples(ir->samples, ir->scount);
 
 	/* decode it */
-	switch (core->board) {
+	switch (core->boardnr) {
 	case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
 	case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
 		ircode = ir_decode_pulsedistance(ir->samples, ir->scount, 1, 4);
@@ -442,7 +442,6 @@
 	case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
 	case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
 	case CX88_BOARD_HAUPPAUGE_HVR1100:
-	case CX88_BOARD_HAUPPAUGE_HVR1300:
 	case CX88_BOARD_HAUPPAUGE_HVR3000:
 		ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
 		ir_dprintk("biphase decoded: %x\n", ircode);
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 543b05e..a652f29 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -23,12 +23,10 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
 #include <asm/delay.h>
 
 #include "cx88.h"
@@ -56,9 +54,9 @@
 {
 	struct cx8802_dev *dev=container_of(work, struct cx8802_dev, request_module_wk);
 
-	if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_DVB)
+	if (dev->core->board.mpeg & CX88_MPEG_DVB)
 		request_module("cx88-dvb");
-	if (cx88_boards[dev->core->board].mpeg & CX88_MPEG_BLACKBIRD)
+	if (dev->core->board.mpeg & CX88_MPEG_BLACKBIRD)
 		request_module("cx88-blackbird");
 }
 
@@ -96,7 +94,7 @@
 	dprintk( 1, "core->active_type_id = 0x%08x\n", core->active_type_id);
 
 	if ( (core->active_type_id == CX88_MPEG_DVB) &&
-		(cx88_boards[core->board].mpeg & CX88_MPEG_DVB) ) {
+		(core->board.mpeg & CX88_MPEG_DVB) ) {
 
 		dprintk( 1, "cx8802_start_dma doing .dvb\n");
 		/* negedge driven & software reset */
@@ -104,7 +102,7 @@
 		udelay(100);
 		cx_write(MO_PINMUX_IO, 0x00);
 		cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01);
-		switch (core->board) {
+		switch (core->boardnr) {
 		case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
 		case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
 		case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
@@ -125,7 +123,7 @@
 		cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl);
 		udelay(100);
 	} else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) &&
-		(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) ) {
+		(core->board.mpeg & CX88_MPEG_BLACKBIRD) ) {
 		dprintk( 1, "cx8802_start_dma doing .blackbird\n");
 		cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */
 
@@ -139,7 +137,7 @@
 		udelay(100);
 	} else {
 		printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __FUNCTION__,
-			cx88_boards[core->board].mpeg );
+			core->board.mpeg );
 		return -EINVAL;
 	}
 
@@ -149,7 +147,7 @@
 
 	/* enable irqs */
 	dprintk( 1, "setting the interrupt mask\n" );
-	cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04);
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_TSINT);
 	cx_set(MO_TS_INTMSK,  0x1f0011);
 
 	/* start dma */
@@ -167,7 +165,7 @@
 	cx_clear(MO_TS_DMACNTRL, 0x11);
 
 	/* disable irqs */
-	cx_clear(MO_PCI_INTMSK, 0x000004);
+	cx_clear(MO_PCI_INTMSK, PCI_INT_TSINT);
 	cx_clear(MO_TS_INTMSK, 0x1f0011);
 
 	/* Reset the controller */
@@ -181,43 +179,43 @@
 	struct cx88_buffer *buf;
 	struct list_head *item;
 
-       dprintk( 1, "cx8802_restart_queue\n" );
+	dprintk( 1, "cx8802_restart_queue\n" );
 	if (list_empty(&q->active))
 	{
-	       struct cx88_buffer *prev;
-	       prev = NULL;
+		struct cx88_buffer *prev;
+		prev = NULL;
 
-	       dprintk(1, "cx8802_restart_queue: queue is empty\n" );
+		dprintk(1, "cx8802_restart_queue: queue is empty\n" );
 
-	       for (;;) {
-		       if (list_empty(&q->queued))
-			       return 0;
-		       buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
-		       if (NULL == prev) {
-			       list_del(&buf->vb.queue);
-			       list_add_tail(&buf->vb.queue,&q->active);
-			       cx8802_start_dma(dev, q, buf);
-			       buf->vb.state = STATE_ACTIVE;
-			       buf->count    = q->count++;
-			       mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
-			       dprintk(1,"[%p/%d] restart_queue - first active\n",
-				       buf,buf->vb.i);
+		for (;;) {
+			if (list_empty(&q->queued))
+				return 0;
+			buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
+			if (NULL == prev) {
+				list_del(&buf->vb.queue);
+				list_add_tail(&buf->vb.queue,&q->active);
+				cx8802_start_dma(dev, q, buf);
+				buf->vb.state = STATE_ACTIVE;
+				buf->count    = q->count++;
+				mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+				dprintk(1,"[%p/%d] restart_queue - first active\n",
+					buf,buf->vb.i);
 
-		       } else if (prev->vb.width  == buf->vb.width  &&
-				  prev->vb.height == buf->vb.height &&
-				  prev->fmt       == buf->fmt) {
-			       list_del(&buf->vb.queue);
-			       list_add_tail(&buf->vb.queue,&q->active);
-			       buf->vb.state = STATE_ACTIVE;
-			       buf->count    = q->count++;
-			       prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
-			       dprintk(1,"[%p/%d] restart_queue - move to active\n",
-				       buf,buf->vb.i);
-		       } else {
-			       return 0;
-		       }
-		       prev = buf;
-	       }
+			} else if (prev->vb.width  == buf->vb.width  &&
+				   prev->vb.height == buf->vb.height &&
+				   prev->fmt       == buf->fmt) {
+				list_del(&buf->vb.queue);
+				list_add_tail(&buf->vb.queue,&q->active);
+				buf->vb.state = STATE_ACTIVE;
+				buf->count    = q->count++;
+				prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+				dprintk(1,"[%p/%d] restart_queue - move to active\n",
+					buf,buf->vb.i);
+			} else {
+				return 0;
+			}
+			prev = buf;
+		}
 		return 0;
 	}
 
@@ -239,6 +237,7 @@
 			struct cx88_buffer *buf, enum v4l2_field field)
 {
 	int size = dev->ts_packet_size * dev->ts_packet_count;
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 	int rc;
 
 	dprintk(1, "%s: %p\n", __FUNCTION__, buf);
@@ -254,8 +253,8 @@
 		if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
 			goto fail;
 		cx88_risc_databuffer(dev->pci, &buf->risc,
-				     buf->vb.dma.sglist,
-				     buf->vb.width, buf->vb.height);
+				     dma->sglist,
+				     buf->vb.width, buf->vb.height, 0);
 	}
 	buf->vb.state = STATE_PREPARED;
 	return 0;
@@ -336,7 +335,7 @@
 {
 	struct cx8802_dev *dev = (struct cx8802_dev*)data;
 
-	dprintk(0, "%s\n",__FUNCTION__);
+	dprintk(1, "%s\n",__FUNCTION__);
 
 	if (debug)
 		cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
@@ -414,7 +413,8 @@
 	int loop, handled = 0;
 
 	for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
-		status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x04);
+		status = cx_read(MO_PCI_INTSTAT) &
+			(core->pci_irqmask | PCI_INT_TSINT);
 		if (0 == status)
 			goto out;
 		dprintk( 1, "cx8802_irq\n" );
@@ -425,7 +425,7 @@
 
 		if (status & core->pci_irqmask)
 			cx88_core_irq(core,status);
-		if (status & 0x04)
+		if (status & PCI_INT_TSINT)
 			cx8802_mpeg_irq(dev);
 	};
 	if (MAX_IRQ_LOOP == loop) {
@@ -580,7 +580,7 @@
 
 	list_for_each(list,&cx8802_devlist) {
 		h = list_entry(list, struct cx8802_dev, devlist);
-		if (h->mpeg_dev->minor == minor)
+		if (h->mpeg_dev && h->mpeg_dev->minor == minor)
 			return h;
 	}
 
@@ -676,22 +676,24 @@
 	struct list_head *list;
 	int err = 0, i = 0;
 
-	printk(KERN_INFO "%s() ->registering driver type=%s access=%s\n", __FUNCTION__ ,
-		drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
-		drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
+	printk(KERN_INFO
+	       "cx88/2: registering cx8802 driver, type: %s access: %s\n",
+	       drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
+	       drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
 
 	if ((err = cx8802_check_driver(drv)) != 0) {
-		printk(KERN_INFO "%s() cx8802_driver is invalid\n", __FUNCTION__ );
+		printk(KERN_ERR "cx88/2: cx8802_driver is invalid\n");
 		return err;
 	}
 
 	list_for_each(list,&cx8802_devlist) {
 		h = list_entry(list, struct cx8802_dev, devlist);
 
-		printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n",
-			h->core->name,h->pci->subsystem_vendor,
-			h->pci->subsystem_device,cx88_boards[h->core->board].name,
-			h->core->board);
+		printk(KERN_INFO
+		       "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
+		       h->core->name, h->pci->subsystem_vendor,
+		       h->pci->subsystem_device, h->core->board.name,
+		       h->core->boardnr);
 
 		/* Bring up a new struct for each driver instance */
 		driver = kzalloc(sizeof(*drv),GFP_KERNEL);
@@ -713,7 +715,9 @@
 			list_add_tail(&driver->devlist,&h->drvlist.devlist);
 			mutex_unlock(&drv->core->lock);
 		} else {
-			printk(KERN_ERR "%s() ->probe failed err = %d\n", __FUNCTION__, err);
+			printk(KERN_ERR
+			       "%s/2: cx8802 probe failed, err = %d\n",
+			       h->core->name, err);
 		}
 
 	}
@@ -733,17 +737,20 @@
 	struct list_head *list2, *q;
 	int err = 0, i = 0;
 
-	printk(KERN_INFO "%s() ->unregistering driver type=%s\n", __FUNCTION__ ,
-		drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird");
+	printk(KERN_INFO
+	       "cx88/2: unregistering cx8802 driver, type: %s access: %s\n",
+	       drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
+	       drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
 
 	list_for_each(list,&cx8802_devlist) {
 		i++;
 		h = list_entry(list, struct cx8802_dev, devlist);
 
-		printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d]\n",
-			h->core->name,h->pci->subsystem_vendor,
-			h->pci->subsystem_device,cx88_boards[h->core->board].name,
-			h->core->board);
+		printk(KERN_INFO
+		       "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
+		       h->core->name, h->pci->subsystem_vendor,
+		       h->pci->subsystem_device, h->core->board.name,
+		       h->core->boardnr);
 
 		list_for_each_safe(list2, q, &h->drvlist.devlist) {
 			d = list_entry(list2, struct cx8802_driver, devlist);
@@ -758,7 +765,8 @@
 				list_del(list2);
 				mutex_unlock(&drv->core->lock);
 			} else
-				printk(KERN_ERR "%s() ->remove failed err = %d\n", __FUNCTION__, err);
+				printk(KERN_ERR "%s/2: cx8802 driver remove "
+				       "failed (%d)\n", h->core->name, err);
 
 		}
 
@@ -783,7 +791,7 @@
 	printk("%s/2: cx2388x 8802 Driver Manager\n", core->name);
 
 	err = -ENODEV;
-	if (!cx88_boards[core->board].mpeg)
+	if (!core->board.mpeg)
 		goto fail_core;
 
 	err = -ENOMEM;
@@ -866,7 +874,7 @@
 
 static int cx8802_init(void)
 {
-	printk(KERN_INFO "cx2388x cx88-mpeg Driver Manager version %d.%d.%d loaded\n",
+	printk(KERN_INFO "cx88/2: cx2388x MPEG-TS Driver Manager version %d.%d.%d loaded\n",
 	       (CX88_VERSION_CODE >> 16) & 0xff,
 	       (CX88_VERSION_CODE >>  8) & 0xff,
 	       CX88_VERSION_CODE & 0xff);
diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/video/cx88/cx88-reg.h
index d3bf5b1..2ec52d1 100644
--- a/drivers/media/video/cx88/cx88-reg.h
+++ b/drivers/media/video/cx88/cx88-reg.h
@@ -582,6 +582,28 @@
 /* ---------------------------------------------------------------------- */
 /* various constants                                                      */
 
+// DMA
+/* Interrupt mask/status */
+#define PCI_INT_VIDINT		(1 <<  0)
+#define PCI_INT_AUDINT		(1 <<  1)
+#define PCI_INT_TSINT		(1 <<  2)
+#define PCI_INT_VIPINT		(1 <<  3)
+#define PCI_INT_HSTINT		(1 <<  4)
+#define PCI_INT_TM1INT		(1 <<  5)
+#define PCI_INT_SRCDMAINT	(1 <<  6)
+#define PCI_INT_DSTDMAINT	(1 <<  7)
+#define PCI_INT_RISC_RD_BERRINT	(1 << 10)
+#define PCI_INT_RISC_WR_BERRINT	(1 << 11)
+#define PCI_INT_BRDG_BERRINT	(1 << 12)
+#define PCI_INT_SRC_DMA_BERRINT	(1 << 13)
+#define PCI_INT_DST_DMA_BERRINT	(1 << 14)
+#define PCI_INT_IPB_DMA_BERRINT	(1 << 15)
+#define PCI_INT_I2CDONE		(1 << 16)
+#define PCI_INT_I2CRACK		(1 << 17)
+#define PCI_INT_IR_SMPINT	(1 << 18)
+#define PCI_INT_GPIO_INT0	(1 << 19)
+#define PCI_INT_GPIO_INT1	(1 << 20)
+
 #define SEL_BTSC     0x01
 #define SEL_EIAJ     0x02
 #define SEL_A2       0x04
@@ -590,6 +612,19 @@
 #define SEL_FMRADIO  0x20
 
 // AUD_CTL
+#define AUD_INT_DN_RISCI1	(1 <<  0)
+#define AUD_INT_UP_RISCI1	(1 <<  1)
+#define AUD_INT_RDS_DN_RISCI1	(1 <<  2)
+#define AUD_INT_DN_RISCI2	(1 <<  4) /* yes, 3 is skipped */
+#define AUD_INT_UP_RISCI2	(1 <<  5)
+#define AUD_INT_RDS_DN_RISCI2	(1 <<  6)
+#define AUD_INT_DN_SYNC		(1 << 12)
+#define AUD_INT_UP_SYNC		(1 << 13)
+#define AUD_INT_RDS_DN_SYNC	(1 << 14)
+#define AUD_INT_OPC_ERR		(1 << 16)
+#define AUD_INT_BER_IRQ		(1 << 20)
+#define AUD_INT_MCHG_IRQ	(1 << 21)
+
 #define EN_BTSC_FORCE_MONO      0
 #define EN_BTSC_FORCE_STEREO    1
 #define EN_BTSC_FORCE_SAP       2
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 1cc2d28..76e5c78 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -36,7 +36,6 @@
 */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/errno.h>
 #include <linux/freezer.h>
 #include <linux/kernel.h>
@@ -62,6 +61,10 @@
 module_param(always_analog,int,0644);
 MODULE_PARM_DESC(always_analog,"force analog audio out");
 
+static unsigned int radio_deemphasis = 0;
+module_param(radio_deemphasis,int,0644);
+MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, "
+		 "0=None, 1=50us (elsewhere), 2=75us (USA)");
 
 #define dprintk(fmt, arg...)	if (audio_debug) \
 	printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
@@ -140,7 +143,7 @@
 	cx_write(AUD_RATE_THRES_DMD, 0x000000C0);
 	cx88_start_audio_dma(core);
 
-	if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) {
+	if (core->board.mpeg & CX88_MPEG_BLACKBIRD) {
 		cx_write(AUD_I2SINPUTCNTL, 4);
 		cx_write(AUD_BAUDRATE, 1);
 		/* 'pass-thru mode': this enables the i2s output to the mpeg encoder */
@@ -149,7 +152,7 @@
 		cx_write(AUD_I2SCNTL, 0);
 		/* cx_write(AUD_APB_IN_RATE_ADJ, 0); */
 	}
-	if ((always_analog) || (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD))) {
+	if ((always_analog) || (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))) {
 		ctl |= EN_DAC_ENABLE;
 		cx_write(AUD_CTL, ctl);
 	}
@@ -678,6 +681,10 @@
 	};
 
 	/* It is enough to leave default values? */
+	/* No, it's not!  The deemphasis registers are reset to the 75us
+	 * values by default.  Analyzing the spectrum of the decoded audio
+	 * reveals that "no deemphasis" is the same as 75 us, while the 50 us
+	 * setting results in less deemphasis.  */
 	static const struct rlist fm_no_deemph[] = {
 
 		{AUD_POLYPH80SCALEFAC, 0x0003},
@@ -688,6 +695,7 @@
 	set_audio_start(core, SEL_FMRADIO);
 
 	switch (deemph) {
+	default:
 	case FM_NO_DEEMPH:
 		set_audio_registers(core, fm_no_deemph);
 		break;
@@ -757,7 +765,7 @@
 		set_audio_standard_EIAJ(core);
 		break;
 	case WW_FM:
-		set_audio_standard_FM(core, FM_NO_DEEMPH);
+		set_audio_standard_FM(core, radio_deemphasis);
 		break;
 	case WW_NONE:
 	default:
@@ -790,9 +798,9 @@
 	core->astat = reg;
 
 /* TODO
-       Reading from AUD_STATUS is not enough
-       for auto-detecting sap/dual-fm/nicam.
-       Add some code here later.
+	Reading from AUD_STATUS is not enough
+	for auto-detecting sap/dual-fm/nicam.
+	Add some code here later.
 */
 
 	return;
diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c
index 86c1cf8..babb085 100644
--- a/drivers/media/video/cx88/cx88-vbi.c
+++ b/drivers/media/video/cx88/cx88-vbi.c
@@ -2,7 +2,6 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 
@@ -67,7 +66,7 @@
 	q->count = 1;
 
 	/* enable irqs */
-	cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01);
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT);
 	cx_set(MO_VID_INTMSK, 0x0f0088);
 
 	/* enable capture */
@@ -91,7 +90,7 @@
 	cx_clear(VID_CAPTURE_CONTROL,0x18);
 
 	/* disable irqs */
-	cx_clear(MO_PCI_INTMSK, 0x000001);
+	cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT);
 	cx_clear(MO_VID_INTMSK, 0x0f0088);
 	return 0;
 }
@@ -100,7 +99,6 @@
 			     struct cx88_dmaqueue *q)
 {
 	struct cx88_buffer *buf;
-	struct list_head *item;
 
 	if (list_empty(&q->active))
 		return 0;
@@ -109,10 +107,8 @@
 	dprintk(2,"restart_queue [%p/%d]: restart dma\n",
 		buf, buf->vb.i);
 	cx8800_start_vbi_dma(dev, q, buf);
-	list_for_each(item,&q->active) {
-		buf = list_entry(item, struct cx88_buffer, vb.queue);
+	list_for_each_entry(buf, &q->active, vb.queue)
 		buf->count = q->count++;
-	}
 	mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
 	return 0;
 }
@@ -173,6 +169,7 @@
 		return -EINVAL;
 
 	if (STATE_NEEDS_INIT == buf->vb.state) {
+		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 		buf->vb.width  = VBI_LINE_LENGTH;
 		buf->vb.height = VBI_LINE_COUNT;
 		buf->vb.size   = size;
@@ -181,7 +178,7 @@
 		if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
 			goto fail;
 		cx88_risc_buffer(dev->pci, &buf->risc,
-				 buf->vb.dma.sglist,
+				 dma->sglist,
 				 0, buf->vb.width * buf->vb.height,
 				 buf->vb.width, 0,
 				 buf->vb.height);
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 98fa354..231ae6c 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -28,7 +28,6 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kmod.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -36,7 +35,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
 #include <linux/kthread.h>
-#include <linux/dma-mapping.h>
 #include <asm/div64.h>
 
 #include "cx88.h"
@@ -369,17 +367,17 @@
 	/* struct cx88_core *core = dev->core; */
 
 	dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n",
-		input, INPUT(input)->vmux,
-		INPUT(input)->gpio0,INPUT(input)->gpio1,
-		INPUT(input)->gpio2,INPUT(input)->gpio3);
+		input, INPUT(input).vmux,
+		INPUT(input).gpio0,INPUT(input).gpio1,
+		INPUT(input).gpio2,INPUT(input).gpio3);
 	core->input = input;
-	cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input)->vmux << 14);
-	cx_write(MO_GP3_IO, INPUT(input)->gpio3);
-	cx_write(MO_GP0_IO, INPUT(input)->gpio0);
-	cx_write(MO_GP1_IO, INPUT(input)->gpio1);
-	cx_write(MO_GP2_IO, INPUT(input)->gpio2);
+	cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input).vmux << 14);
+	cx_write(MO_GP3_IO, INPUT(input).gpio3);
+	cx_write(MO_GP0_IO, INPUT(input).gpio0);
+	cx_write(MO_GP1_IO, INPUT(input).gpio1);
+	cx_write(MO_GP2_IO, INPUT(input).gpio2);
 
-	switch (INPUT(input)->type) {
+	switch (INPUT(input).type) {
 	case CX88_VMUX_SVIDEO:
 		cx_set(MO_AFECFG_IO,    0x00000001);
 		cx_set(MO_INPUT_FORMAT, 0x00010010);
@@ -394,9 +392,9 @@
 		break;
 	}
 
-	if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) {
+	if (core->board.mpeg & CX88_MPEG_BLACKBIRD) {
 		/* sets sound input from external adc */
-		if (INPUT(input)->extadc)
+		if (INPUT(input).extadc)
 			cx_set(AUD_CTL, EN_I2SIN_ENABLE);
 		else
 			cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
@@ -424,7 +422,7 @@
 	q->count = 1;
 
 	/* enable irqs */
-	cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01);
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT);
 
 	/* Enables corresponding bits at PCI_INT_STAT:
 		bits 0 to 4: video, audio, transport stream, VIP, Host
@@ -457,7 +455,7 @@
 	cx_clear(VID_CAPTURE_CONTROL,0x06);
 
 	/* disable irqs */
-	cx_clear(MO_PCI_INTMSK, 0x000001);
+	cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT);
 	cx_clear(MO_VID_INTMSK, 0x0f0011);
 	return 0;
 }
@@ -468,17 +466,14 @@
 {
 	struct cx88_core *core = dev->core;
 	struct cx88_buffer *buf, *prev;
-	struct list_head *item;
 
 	if (!list_empty(&q->active)) {
 		buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
 		dprintk(2,"restart_queue [%p/%d]: restart dma\n",
 			buf, buf->vb.i);
 		start_video_dma(dev, q, buf);
-		list_for_each(item,&q->active) {
-			buf = list_entry(item, struct cx88_buffer, vb.queue);
-			buf->count    = q->count++;
-		}
+		list_for_each_entry(buf, &q->active, vb.queue)
+			buf->count = q->count++;
 		mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
 		return 0;
 	}
@@ -536,6 +531,7 @@
 	struct cx8800_dev  *dev = fh->dev;
 	struct cx88_core *core = dev->core;
 	struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 	int rc, init_buffer = 0;
 
 	BUG_ON(NULL == fh->fmt);
@@ -568,30 +564,30 @@
 		switch (buf->vb.field) {
 		case V4L2_FIELD_TOP:
 			cx88_risc_buffer(dev->pci, &buf->risc,
-					 buf->vb.dma.sglist, 0, UNSET,
+					 dma->sglist, 0, UNSET,
 					 buf->bpl, 0, buf->vb.height);
 			break;
 		case V4L2_FIELD_BOTTOM:
 			cx88_risc_buffer(dev->pci, &buf->risc,
-					 buf->vb.dma.sglist, UNSET, 0,
+					 dma->sglist, UNSET, 0,
 					 buf->bpl, 0, buf->vb.height);
 			break;
 		case V4L2_FIELD_INTERLACED:
 			cx88_risc_buffer(dev->pci, &buf->risc,
-					 buf->vb.dma.sglist, 0, buf->bpl,
+					 dma->sglist, 0, buf->bpl,
 					 buf->bpl, buf->bpl,
 					 buf->vb.height >> 1);
 			break;
 		case V4L2_FIELD_SEQ_TB:
 			cx88_risc_buffer(dev->pci, &buf->risc,
-					 buf->vb.dma.sglist,
+					 dma->sglist,
 					 0, buf->bpl * (buf->vb.height >> 1),
 					 buf->bpl, 0,
 					 buf->vb.height >> 1);
 			break;
 		case V4L2_FIELD_SEQ_BT:
 			cx88_risc_buffer(dev->pci, &buf->risc,
-					 buf->vb.dma.sglist,
+					 dma->sglist,
 					 buf->bpl * (buf->vb.height >> 1), 0,
 					 buf->bpl, 0,
 					 buf->vb.height >> 1);
@@ -714,12 +710,10 @@
 	struct cx8800_dev *h,*dev = NULL;
 	struct cx88_core *core;
 	struct cx8800_fh *fh;
-	struct list_head *list;
 	enum v4l2_buf_type type = 0;
 	int radio = 0;
 
-	list_for_each(list,&cx8800_devlist) {
-		h = list_entry(list, struct cx8800_dev, devlist);
+	list_for_each_entry(h, &cx8800_devlist, devlist) {
 		if (h->video_dev->minor == minor) {
 			dev  = h;
 			type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -754,13 +748,13 @@
 	fh->height   = 240;
 	fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
 
-	videobuf_queue_init(&fh->vidq, &cx8800_video_qops,
+	videobuf_queue_pci_init(&fh->vidq, &cx8800_video_qops,
 			    dev->pci, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_INTERLACED,
 			    sizeof(struct cx88_buffer),
 			    fh);
-	videobuf_queue_init(&fh->vbiq, &cx8800_vbi_qops,
+	videobuf_queue_pci_init(&fh->vbiq, &cx8800_vbi_qops,
 			    dev->pci, &dev->slock,
 			    V4L2_BUF_TYPE_VBI_CAPTURE,
 			    V4L2_FIELD_SEQ_TB,
@@ -768,12 +762,11 @@
 			    fh);
 
 	if (fh->radio) {
-		int board = core->board;
 		dprintk(1,"video_open: setting radio device\n");
-		cx_write(MO_GP3_IO, cx88_boards[board].radio.gpio3);
-		cx_write(MO_GP0_IO, cx88_boards[board].radio.gpio0);
-		cx_write(MO_GP1_IO, cx88_boards[board].radio.gpio1);
-		cx_write(MO_GP2_IO, cx88_boards[board].radio.gpio2);
+		cx_write(MO_GP3_IO, core->board.radio.gpio3);
+		cx_write(MO_GP0_IO, core->board.radio.gpio0);
+		cx_write(MO_GP1_IO, core->board.radio.gpio1);
+		cx_write(MO_GP2_IO, core->board.radio.gpio2);
 		core->tvaudio = WW_FM;
 		cx88_set_tvaudio(core);
 		cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1);
@@ -1079,8 +1072,7 @@
 	struct cx88_core  *core = dev->core;
 
 	strcpy(cap->driver, "cx8800");
-	strlcpy(cap->card, cx88_boards[core->board].name,
-		sizeof(cap->card));
+	strlcpy(cap->card, core->board.name, sizeof(cap->card));
 	sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
 	cap->version = CX88_VERSION_CODE;
 	cap->capabilities =
@@ -1088,7 +1080,7 @@
 		V4L2_CAP_READWRITE     |
 		V4L2_CAP_STREAMING     |
 		V4L2_CAP_VBI_CAPTURE;
-	if (UNSET != core->tuner_type)
+	if (UNSET != core->board.tuner_type)
 		cap->capabilities |= V4L2_CAP_TUNER;
 	return 0;
 }
@@ -1108,28 +1100,9 @@
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
 {
-	struct cx8800_fh           *fh   = priv;
-	struct videobuf_queue      *q;
-	struct v4l2_requestbuffers req;
-	unsigned int i;
-	int err;
+	struct cx8800_fh           *fh  = priv;
 
-	q = get_queue(fh);
-	memset(&req,0,sizeof(req));
-	req.type   = q->type;
-	req.count  = 8;
-	req.memory = V4L2_MEMORY_MMAP;
-	err = videobuf_reqbufs(q,&req);
-	if (err < 0)
-		return err;
-
-	mbuf->frames = req.count;
-	mbuf->size   = 0;
-	for (i = 0; i < mbuf->frames; i++) {
-		mbuf->offsets[i]  = q->bufs[i]->boff;
-		mbuf->size       += q->bufs[i]->bsize;
-	}
-	return 0;
+	return videobuf_cgmbuf (get_queue(fh), mbuf, 8);
 }
 #endif
 
@@ -1222,14 +1195,14 @@
 	n = i->index;
 	if (n >= 4)
 		return -EINVAL;
-	if (0 == INPUT(n)->type)
+	if (0 == INPUT(n).type)
 		return -EINVAL;
 	memset(i,0,sizeof(*i));
 	i->index = n;
 	i->type  = V4L2_INPUT_TYPE_CAMERA;
-	strcpy(i->name,iname[INPUT(n)->type]);
-	if ((CX88_VMUX_TELEVISION == INPUT(n)->type) ||
-		(CX88_VMUX_CABLE      == INPUT(n)->type))
+	strcpy(i->name,iname[INPUT(n).type]);
+	if ((CX88_VMUX_TELEVISION == INPUT(n).type) ||
+	    (CX88_VMUX_CABLE      == INPUT(n).type))
 		i->type = V4L2_INPUT_TYPE_TUNER;
 		i->std = CX88_NORMS;
 	return 0;
@@ -1298,7 +1271,7 @@
 	struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
 	u32 reg;
 
-	if (unlikely(UNSET == core->tuner_type))
+	if (unlikely(UNSET == core->board.tuner_type))
 		return -EINVAL;
 	if (0 != t->index)
 		return -EINVAL;
@@ -1319,7 +1292,7 @@
 {
 	struct cx88_core  *core = ((struct cx8800_fh *)priv)->dev->core;
 
-	if (UNSET == core->tuner_type)
+	if (UNSET == core->board.tuner_type)
 		return -EINVAL;
 	if (0 != t->index)
 		return -EINVAL;
@@ -1334,7 +1307,7 @@
 	struct cx8800_fh  *fh   = priv;
 	struct cx88_core  *core = fh->dev->core;
 
-	if (unlikely(UNSET == core->tuner_type))
+	if (unlikely(UNSET == core->board.tuner_type))
 		return -EINVAL;
 
 	/* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
@@ -1349,7 +1322,7 @@
 int cx88_set_freq (struct cx88_core  *core,
 				struct v4l2_frequency *f)
 {
-	if (unlikely(UNSET == core->tuner_type))
+	if (unlikely(UNSET == core->board.tuner_type))
 		return -EINVAL;
 	if (unlikely(f->tuner != 0))
 		return -EINVAL;
@@ -1420,8 +1393,7 @@
 	struct cx88_core  *core = dev->core;
 
 	strcpy(cap->driver, "cx8800");
-	strlcpy(cap->card, cx88_boards[core->board].name,
-		sizeof(cap->card));
+	strlcpy(cap->card, core->board.name, sizeof(cap->card));
 	sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci));
 	cap->version = CX88_VERSION_CODE;
 	cap->capabilities = V4L2_CAP_TUNER;
@@ -1608,7 +1580,8 @@
 	int loop, handled = 0;
 
 	for (loop = 0; loop < 10; loop++) {
-		status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x01);
+		status = cx_read(MO_PCI_INTSTAT) &
+			(core->pci_irqmask | PCI_INT_VIDINT);
 		if (0 == status)
 			goto out;
 		cx_write(MO_PCI_INTSTAT, status);
@@ -1616,7 +1589,7 @@
 
 		if (status & core->pci_irqmask)
 			cx88_core_irq(core,status);
-		if (status & 0x01)
+		if (status & PCI_INT_VIDINT)
 			cx8800_vid_irq(dev);
 	};
 	if (10 == loop) {
@@ -1717,6 +1690,10 @@
 	.vidioc_s_ctrl        = vidioc_s_ctrl,
 	.vidioc_g_frequency   = vidioc_g_frequency,
 	.vidioc_s_frequency   = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register    = vidioc_g_register,
+	.vidioc_s_register    = vidioc_s_register,
+#endif
 };
 
 /* ----------------------------------------------------------- */
@@ -1818,26 +1795,32 @@
 	err = request_irq(pci_dev->irq, cx8800_irq,
 			  IRQF_SHARED | IRQF_DISABLED, core->name, dev);
 	if (err < 0) {
-		printk(KERN_ERR "%s: can't get IRQ %d\n",
+		printk(KERN_ERR "%s/0: can't get IRQ %d\n",
 		       core->name,pci_dev->irq);
 		goto fail_core;
 	}
 	cx_set(MO_PCI_INTMSK, core->pci_irqmask);
 
 	/* load and configure helper modules */
-	if (TUNER_ABSENT != core->tuner_type)
+	if (TUNER_ABSENT != core->board.tuner_type)
 		request_module("tuner");
 
-	if (cx88_boards[ core->board ].audio_chip == AUDIO_CHIP_WM8775)
+	if (core->board.audio_chip == AUDIO_CHIP_WM8775)
 		request_module("wm8775");
 
+	switch (core->boardnr) {
+	case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
+		request_module("ir-kbd-i2c");
+		request_module("rtc-isl1208");
+	}
+
 	/* register v4l devices */
 	dev->video_dev = cx88_vdev_init(core,dev->pci,
 					&cx8800_video_template,"video");
 	err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
 				    video_nr[core->nr]);
 	if (err < 0) {
-		printk(KERN_INFO "%s: can't register video device\n",
+		printk(KERN_ERR "%s/0: can't register video device\n",
 		       core->name);
 		goto fail_unreg;
 	}
@@ -1848,20 +1831,20 @@
 	err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
 				    vbi_nr[core->nr]);
 	if (err < 0) {
-		printk(KERN_INFO "%s/0: can't register vbi device\n",
+		printk(KERN_ERR "%s/0: can't register vbi device\n",
 		       core->name);
 		goto fail_unreg;
 	}
 	printk(KERN_INFO "%s/0: registered device vbi%d\n",
 	       core->name,dev->vbi_dev->minor & 0x1f);
 
-	if (core->has_radio) {
+	if (core->board.radio.type == CX88_RADIO) {
 		dev->radio_dev = cx88_vdev_init(core,dev->pci,
 						&cx8800_radio_template,"radio");
 		err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
 					    radio_nr[core->nr]);
 		if (err < 0) {
-			printk(KERN_INFO "%s/0: can't register radio device\n",
+			printk(KERN_ERR "%s/0: can't register radio device\n",
 			       core->name);
 			goto fail_unreg;
 		}
@@ -1881,8 +1864,14 @@
 	mutex_unlock(&core->lock);
 
 	/* start tvaudio thread */
-	if (core->tuner_type != TUNER_ABSENT)
+	if (core->board.tuner_type != TUNER_ABSENT) {
 		core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio");
+		if (IS_ERR(core->kthread)) {
+			err = PTR_ERR(core->kthread);
+			printk(KERN_ERR "%s/0: failed to create cx88 audio thread, err=%d\n",
+			       core->name, err);
+		}
+	}
 	return 0;
 
 fail_unreg:
@@ -1931,17 +1920,19 @@
 	/* stop video+vbi capture */
 	spin_lock(&dev->slock);
 	if (!list_empty(&dev->vidq.active)) {
-		printk("%s: suspend video\n", core->name);
+		printk("%s/0: suspend video\n", core->name);
 		stop_video_dma(dev);
 		del_timer(&dev->vidq.timeout);
 	}
 	if (!list_empty(&dev->vbiq.active)) {
-		printk("%s: suspend vbi\n", core->name);
+		printk("%s/0: suspend vbi\n", core->name);
 		cx8800_stop_vbi_dma(dev);
 		del_timer(&dev->vbiq.timeout);
 	}
 	spin_unlock(&dev->slock);
 
+	if (core->ir)
+		cx88_ir_stop(core, core->ir);
 	/* FIXME -- shutdown device */
 	cx88_shutdown(core);
 
@@ -1962,8 +1953,8 @@
 	if (dev->state.disabled) {
 		err=pci_enable_device(pci_dev);
 		if (err) {
-			printk(KERN_ERR "%s: can't enable device\n",
-						       core->name);
+			printk(KERN_ERR "%s/0: can't enable device\n",
+			       core->name);
 			return err;
 		}
 
@@ -1971,9 +1962,7 @@
 	}
 	err= pci_set_power_state(pci_dev, PCI_D0);
 	if (err) {
-		printk(KERN_ERR "%s: can't enable device\n",
-				       core->name);
-
+		printk(KERN_ERR "%s/0: can't set power state\n", core->name);
 		pci_disable_device(pci_dev);
 		dev->state.disabled = 1;
 
@@ -1983,15 +1972,19 @@
 
 	/* FIXME: re-initialize hardware */
 	cx88_reset(core);
+	if (core->ir)
+		cx88_ir_start(core, core->ir);
+
+	cx_set(MO_PCI_INTMSK, core->pci_irqmask);
 
 	/* restart video+vbi capture */
 	spin_lock(&dev->slock);
 	if (!list_empty(&dev->vidq.active)) {
-		printk("%s: resume video\n", core->name);
+		printk("%s/0: resume video\n", core->name);
 		restart_video_queue(dev,&dev->vidq);
 	}
 	if (!list_empty(&dev->vbiq.active)) {
-		printk("%s: resume vbi\n", core->name);
+		printk("%s/0: resume vbi\n", core->name);
 		cx8800_restart_vbi_queue(dev,&dev->vbiq);
 	}
 	spin_unlock(&dev->slock);
@@ -2027,7 +2020,7 @@
 
 static int cx8800_init(void)
 {
-	printk(KERN_INFO "cx2388x v4l2 driver version %d.%d.%d loaded\n",
+	printk(KERN_INFO "cx88/0: cx2388x v4l2 driver version %d.%d.%d loaded\n",
 	       (CX88_VERSION_CODE >> 16) & 0xff,
 	       (CX88_VERSION_CODE >>  8) & 0xff,
 	       CX88_VERSION_CODE & 0xff);
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c
index 82bc3a2..77c3788 100644
--- a/drivers/media/video/cx88/cx88-vp3054-i2c.c
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c
@@ -23,7 +23,6 @@
 */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 
 #include <asm/io.h>
@@ -94,7 +93,7 @@
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_algo_bit_data vp3054_i2c_algo_template = {
+static const struct i2c_algo_bit_data vp3054_i2c_algo_template = {
 	.setsda  = vp3054_bit_setsda,
 	.setscl  = vp3054_bit_setscl,
 	.getsda  = vp3054_bit_getsda,
@@ -105,19 +104,13 @@
 
 /* ----------------------------------------------------------------------- */
 
-static struct i2c_adapter vp3054_i2c_adap_template = {
-	.name              = "cx2388x",
-	.owner             = THIS_MODULE,
-	.id                = I2C_HW_B_CX2388x,
-};
-
 int vp3054_i2c_probe(struct cx8802_dev *dev)
 {
 	struct cx88_core *core = dev->core;
 	struct vp3054_i2c_state *vp3054_i2c;
 	int rc;
 
-	if (core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
+	if (core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
 		return 0;
 
 	dev->card_priv = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL);
@@ -125,8 +118,6 @@
 		return -ENOMEM;
 	vp3054_i2c = dev->card_priv;
 
-	memcpy(&vp3054_i2c->adap, &vp3054_i2c_adap_template,
-	       sizeof(vp3054_i2c->adap));
 	memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template,
 	       sizeof(vp3054_i2c->algo));
 
@@ -135,6 +126,8 @@
 	vp3054_i2c->adap.dev.parent = &dev->pci->dev;
 	strlcpy(vp3054_i2c->adap.name, core->name,
 		sizeof(vp3054_i2c->adap.name));
+	vp3054_i2c->adap.owner = THIS_MODULE;
+	vp3054_i2c->adap.id = I2C_HW_B_CX2388x;
 	vp3054_i2c->algo.data = dev;
 	i2c_set_adapdata(&vp3054_i2c->adap, dev);
 	vp3054_i2c->adap.algo_data = &vp3054_i2c->algo;
@@ -158,7 +151,7 @@
 	struct vp3054_i2c_state *vp3054_i2c = dev->card_priv;
 
 	if (vp3054_i2c == NULL ||
-	    dev->core->board != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
+	    dev->core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO)
 		return;
 
 	i2c_del_adapter(&vp3054_i2c->adap);
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.h b/drivers/media/video/cx88/cx88-vp3054-i2c.h
index 637a7d2..be99c93 100644
--- a/drivers/media/video/cx88/cx88-vp3054-i2c.h
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.h
@@ -30,5 +30,12 @@
 };
 
 /* ----------------------------------------------------------------------- */
+#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
 int  vp3054_i2c_probe(struct cx8802_dev *dev);
 void vp3054_i2c_remove(struct cx8802_dev *dev);
+#else
+static inline int  vp3054_i2c_probe(struct cx8802_dev *dev)
+{ return 0; }
+static inline void vp3054_i2c_remove(struct cx8802_dev *dev)
+{ }
+#endif
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 738d4f2..42e0a9b 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -28,11 +28,11 @@
 #include <media/v4l2-common.h>
 #include <media/tuner.h>
 #include <media/tveeprom.h>
-#include <media/video-buf.h>
+#include <media/videobuf-dma-sg.h>
 #include <media/cx2341x.h>
 #include <media/audiochip.h>
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
-#include <media/video-buf-dvb.h>
+#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
+#include <media/videobuf-dvb.h>
 #endif
 
 #include "btcx-risc.h"
@@ -209,6 +209,7 @@
 #define CX88_BOARD_NORWOOD_MICRO           54
 #define CX88_BOARD_TE_DTV_250_OEM_SWANN    55
 #define CX88_BOARD_HAUPPAUGE_HVR1300       56
+#define CX88_BOARD_ADSTECH_PTV_390         57
 
 enum cx88_itype {
 	CX88_VMUX_COMPOSITE1 = 1,
@@ -225,8 +226,8 @@
 
 struct cx88_input {
 	enum cx88_itype type;
-	unsigned int    vmux;
 	u32             gpio0, gpio1, gpio2, gpio3;
+	unsigned int    vmux:2;
 	unsigned int    extadc:1;
 };
 
@@ -249,7 +250,7 @@
 	u32     card;
 };
 
-#define INPUT(nr) (&cx88_boards[core->board].input[nr])
+#define INPUT(nr) (core->board.input[nr])
 
 /* ----------------------------------------------------------- */
 /* device / file handle status                                 */
@@ -258,7 +259,7 @@
 #define RESOURCE_VIDEO         2
 #define RESOURCE_VBI           4
 
-#define BUFFER_TIMEOUT     (HZ/2)  /* 0.5 seconds */
+#define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
 
 /* buffer for one video frame */
 struct cx88_buffer {
@@ -303,21 +304,14 @@
 	u32                        i2c_state, i2c_rc;
 
 	/* config info -- analog */
-	unsigned int               board;
-	unsigned int               tuner_type;
-	unsigned int               radio_type;
-	unsigned char              tuner_addr;
-	unsigned char              radio_addr;
-	unsigned int               tda9887_conf;
-	unsigned int               has_radio;
+	unsigned int               boardnr;
+	struct cx88_board	   board;
 
 	/* Supported V4L _STD_ tuner formats */
 	unsigned int               tuner_formats;
 
 	/* config info -- dvb */
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
-	struct dvb_pll_desc        *pll_desc;
-	unsigned int               pll_addr;
+#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
 	int 			   (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
 #endif
 
@@ -463,13 +457,10 @@
 	u32                        mailbox;
 	int                        width;
 	int                        height;
-	int                        fw_size;
 
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
+#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
 	/* for dvb only */
 	struct videobuf_dvb        dvb;
-	void*                      fe_handle;
-	int                        (*fe_release)(void *handle);
 
 	void			   *card_priv;
 #endif
@@ -528,7 +519,7 @@
 extern int
 cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
 		     struct scatterlist *sglist, unsigned int bpl,
-		     unsigned int lines);
+		     unsigned int lines, unsigned int lpi);
 extern int
 cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
 		  u32 reg, u32 mask, u32 value);
@@ -589,15 +580,9 @@
 /* ----------------------------------------------------------- */
 /* cx88-cards.c                                                */
 
-extern struct cx88_board cx88_boards[];
-extern const unsigned int cx88_bcount;
-
-extern struct cx88_subid cx88_subids[];
-extern const unsigned int cx88_idcount;
-
-extern void cx88_card_list(struct cx88_core *core, struct pci_dev *pci);
-extern void cx88_card_setup(struct cx88_core *core);
-extern void cx88_card_setup_pre_i2c(struct cx88_core *core);
+extern int cx88_get_resources(const struct cx88_core *core,
+			      struct pci_dev *pci);
+extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr);
 
 /* ----------------------------------------------------------- */
 /* cx88-tvaudio.c                                              */
@@ -629,6 +614,8 @@
 int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci);
 int cx88_ir_fini(struct cx88_core *core);
 void cx88_ir_irq(struct cx88_core *core);
+void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir);
+void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir);
 
 /* ----------------------------------------------------------- */
 /* cx88-mpeg.c                                                 */
diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c
index 0fcc935..255dae3 100644
--- a/drivers/media/video/dpc7146.c
+++ b/drivers/media/video/dpc7146.c
@@ -92,7 +92,6 @@
 {
 	struct dpc* dpc = NULL;
 	struct i2c_client *client;
-	struct list_head *item;
 
 	dpc = kzalloc(sizeof(struct dpc), GFP_KERNEL);
 	if( NULL == dpc ) {
@@ -116,11 +115,9 @@
 	}
 
 	/* loop through all i2c-devices on the bus and look who is there */
-	list_for_each(item,&dpc->i2c_adapter.clients) {
-		client = list_entry(item, struct i2c_client, list);
+	list_for_each_entry(client, &dpc->i2c_adapter.clients, list)
 		if( I2C_SAA7111A == client->addr )
 			dpc->saa7111a = client;
-	}
 
 	/* check if all devices are present */
 	if( 0 == dpc->saa7111a ) {
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 255a47d..d3282ec 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -24,7 +24,6 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/usb.h>
 #include <linux/vmalloc.h>
 
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 55d45b0..e3894b6 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -22,7 +22,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 2c7b158..b8d5327 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -252,10 +252,8 @@
 	int minor = iminor(inode);
 	int errCode = 0;
 	struct em28xx *h,*dev = NULL;
-	struct list_head *list;
 
-	list_for_each(list,&em28xx_devlist) {
-		h = list_entry(list, struct em28xx, devlist);
+	list_for_each_entry(h, &em28xx_devlist, devlist) {
 		if (h->vdev->minor == minor) {
 			dev  = h;
 			dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -268,8 +266,6 @@
 	if (NULL == dev)
 		return -ENODEV;
 
-	filp->private_data=dev;
-
 	em28xx_videodbg("open minor=%d type=%s users=%d\n",
 				minor,v4l2_type_names[dev->type],dev->users);
 
@@ -1772,6 +1768,7 @@
 	if (dev->alt_max_pkt_size == NULL) {
 		em28xx_errdev("out of memory!\n");
 		em28xx_devused&=~(1<<nr);
+		kfree(dev);
 		return -ENOMEM;
 	}
 
diff --git a/drivers/media/video/et61x251/Kconfig b/drivers/media/video/et61x251/Kconfig
index 664676f..dcc1a03 100644
--- a/drivers/media/video/et61x251/Kconfig
+++ b/drivers/media/video/et61x251/Kconfig
@@ -1,6 +1,6 @@
 config USB_ET61X251
 	tristate "USB ET61X[12]51 PC Camera Controller support"
-	depends on VIDEO_V4L1
+	depends on VIDEO_V4L2
 	---help---
 	  Say Y here if you want support for cameras based on Etoms ET61X151
 	  or ET61X251 PC Camera Controllers.
diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h
index 262f98e..02c741d 100644
--- a/drivers/media/video/et61x251/et61x251.h
+++ b/drivers/media/video/et61x251/et61x251.h
@@ -36,6 +36,7 @@
 #include <linux/mutex.h>
 #include <linux/stddef.h>
 #include <linux/string.h>
+#include <linux/kref.h>
 
 #include "et61x251_sensor.h"
 
@@ -134,7 +135,7 @@
 };
 
 static DEFINE_MUTEX(et61x251_sysfs_lock);
-static DECLARE_RWSEM(et61x251_disconnect);
+static DECLARE_RWSEM(et61x251_dev_lock);
 
 struct et61x251_device {
 	struct video_device* v4ldev;
@@ -158,12 +159,14 @@
 	struct et61x251_sysfs_attr sysfs;
 	struct et61x251_module_param module_param;
 
+	struct kref kref;
 	enum et61x251_dev_state state;
 	u8 users;
 
-	struct mutex dev_mutex, fileop_mutex;
+	struct completion probe;
+	struct mutex open_mutex, fileop_mutex;
 	spinlock_t queue_lock;
-	wait_queue_head_t open, wait_frame, wait_stream;
+	wait_queue_head_t wait_open, wait_frame, wait_stream;
 };
 
 /*****************************************************************************/
@@ -177,7 +180,7 @@
 
 void
 et61x251_attach_sensor(struct et61x251_device* cam,
-		       struct et61x251_sensor* sensor)
+		       const struct et61x251_sensor* sensor)
 {
 	memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
 }
@@ -195,8 +198,8 @@
 		else if ((level) == 2)                                        \
 			dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
 		else if ((level) >= 3)                                        \
-			dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
-				 __FUNCTION__, __LINE__ , ## args);           \
+			dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n",   \
+				 __FILE__, __FUNCTION__, __LINE__ , ## args); \
 	}                                                                     \
 } while (0)
 #	define KDBG(level, fmt, args...)                                      \
@@ -205,8 +208,8 @@
 		if ((level) == 1 || (level) == 2)                             \
 			pr_info("et61x251: " fmt "\n", ## args);              \
 		else if ((level) == 3)                                        \
-			pr_debug("et61x251: [%s:%d] " fmt "\n", __FUNCTION__, \
-				 __LINE__ , ## args);                         \
+			pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__,   \
+				 __FUNCTION__, __LINE__ , ## args);           \
 	}                                                                     \
 } while (0)
 #	define V4LDBG(level, name, cmd)                                       \
@@ -222,8 +225,8 @@
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
-	 __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__,   \
+	 __LINE__ , ## args)
 
 #undef PDBGG
 #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index a652551..d5fef4c0 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -22,7 +22,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
-#include <linux/moduleparam.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/device.h>
@@ -45,11 +44,11 @@
 
 #define ET61X251_MODULE_NAME    "V4L2 driver for ET61X[12]51 "                \
 				"PC Camera Controllers"
-#define ET61X251_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
+#define ET61X251_MODULE_AUTHOR  "(C) 2006-2007 Luca Risolia"
 #define ET61X251_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
 #define ET61X251_MODULE_LICENSE "GPL"
-#define ET61X251_MODULE_VERSION "1:1.04"
-#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 4)
+#define ET61X251_MODULE_VERSION "1:1.09"
+#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 9)
 
 /*****************************************************************************/
 
@@ -245,7 +244,8 @@
 
 
 static int
-et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor)
+et61x251_i2c_wait(struct et61x251_device* cam,
+		  const struct et61x251_sensor* sensor)
 {
 	int i, r;
 
@@ -270,7 +270,7 @@
 
 int
 et61x251_i2c_try_read(struct et61x251_device* cam,
-		      struct et61x251_sensor* sensor, u8 address)
+		      const struct et61x251_sensor* sensor, u8 address)
 {
 	struct usb_device* udev = cam->usbdev;
 	u8* data = cam->control_buffer;
@@ -303,7 +303,8 @@
 
 int
 et61x251_i2c_try_write(struct et61x251_device* cam,
-		       struct et61x251_sensor* sensor, u8 address, u8 value)
+		       const struct et61x251_sensor* sensor, u8 address,
+		       u8 value)
 {
 	struct usb_device* udev = cam->usbdev;
 	u8* data = cam->control_buffer;
@@ -615,7 +616,7 @@
 	return 0;
 
 free_urbs:
-	for (i = 0; (i < ET61X251_URBS) &&  cam->urb[i]; i++)
+	for (i = 0; (i < ET61X251_URBS) && cam->urb[i]; i++)
 		usb_free_urb(cam->urb[i]);
 
 free_buffers:
@@ -682,7 +683,7 @@
 
 	if (len < 4) {
 		strncpy(str, buff, len);
-		str[len+1] = '\0';
+		str[len] = '\0';
 	} else {
 		strncpy(str, buff, 4);
 		str[4] = '\0';
@@ -705,7 +706,8 @@
    NOTE 2: buffers are PAGE_SIZE long
 */
 
-static ssize_t et61x251_show_reg(struct class_device* cd, char* buf)
+static ssize_t et61x251_show_reg(struct device* cd,
+				 struct device_attribute *attr, char* buf)
 {
 	struct et61x251_device* cam;
 	ssize_t count;
@@ -728,7 +730,8 @@
 
 
 static ssize_t
-et61x251_store_reg(struct class_device* cd, const char* buf, size_t len)
+et61x251_store_reg(struct device* cd,
+		   struct device_attribute *attr, const char* buf, size_t len)
 {
 	struct et61x251_device* cam;
 	u8 index;
@@ -760,7 +763,8 @@
 }
 
 
-static ssize_t et61x251_show_val(struct class_device* cd, char* buf)
+static ssize_t et61x251_show_val(struct device* cd,
+				 struct device_attribute *attr, char* buf)
 {
 	struct et61x251_device* cam;
 	ssize_t count;
@@ -791,7 +795,8 @@
 
 
 static ssize_t
-et61x251_store_val(struct class_device* cd, const char* buf, size_t len)
+et61x251_store_val(struct device* cd, struct device_attribute *attr,
+		   const char* buf, size_t len)
 {
 	struct et61x251_device* cam;
 	u8 value;
@@ -829,7 +834,8 @@
 }
 
 
-static ssize_t et61x251_show_i2c_reg(struct class_device* cd, char* buf)
+static ssize_t et61x251_show_i2c_reg(struct device* cd,
+				     struct device_attribute *attr, char* buf)
 {
 	struct et61x251_device* cam;
 	ssize_t count;
@@ -854,7 +860,8 @@
 
 
 static ssize_t
-et61x251_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
+et61x251_store_i2c_reg(struct device* cd, struct device_attribute *attr,
+		       const char* buf, size_t len)
 {
 	struct et61x251_device* cam;
 	u8 index;
@@ -886,7 +893,8 @@
 }
 
 
-static ssize_t et61x251_show_i2c_val(struct class_device* cd, char* buf)
+static ssize_t et61x251_show_i2c_val(struct device* cd,
+				     struct device_attribute *attr, char* buf)
 {
 	struct et61x251_device* cam;
 	ssize_t count;
@@ -922,7 +930,8 @@
 
 
 static ssize_t
-et61x251_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
+et61x251_store_i2c_val(struct device* cd, struct device_attribute *attr,
+		       const char* buf, size_t len)
 {
 	struct et61x251_device* cam;
 	u8 value;
@@ -965,42 +974,40 @@
 }
 
 
-static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
-			 et61x251_show_reg, et61x251_store_reg);
-static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
-			 et61x251_show_val, et61x251_store_val);
-static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
-			 et61x251_show_i2c_reg, et61x251_store_i2c_reg);
-static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
-			 et61x251_show_i2c_val, et61x251_store_i2c_val);
+static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
+		   et61x251_show_reg, et61x251_store_reg);
+static DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
+		   et61x251_show_val, et61x251_store_val);
+static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
+		   et61x251_show_i2c_reg, et61x251_store_i2c_reg);
+static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
+		   et61x251_show_i2c_val, et61x251_store_i2c_val);
 
 
 static int et61x251_create_sysfs(struct et61x251_device* cam)
 {
-	struct video_device *v4ldev = cam->v4ldev;
+	struct device *classdev = &(cam->v4ldev->class_dev);
 	int err = 0;
 
-	if ((err = video_device_create_file(v4ldev, &class_device_attr_reg)))
+	if ((err = device_create_file(classdev, &dev_attr_reg)))
 		goto err_out;
-	if ((err = video_device_create_file(v4ldev, &class_device_attr_val)))
+	if ((err = device_create_file(classdev, &dev_attr_val)))
 		goto err_reg;
 
 	if (cam->sensor.sysfs_ops) {
-		if ((err = video_device_create_file(v4ldev,
-						  &class_device_attr_i2c_reg)))
+		if ((err = device_create_file(classdev, &dev_attr_i2c_reg)))
 			goto err_val;
-		if ((err = video_device_create_file(v4ldev,
-						  &class_device_attr_i2c_val)))
+		if ((err = device_create_file(classdev, &dev_attr_i2c_val)))
 			goto err_i2c_reg;
 	}
 
 err_i2c_reg:
 	if (cam->sensor.sysfs_ops)
-	video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
+		device_remove_file(classdev, &dev_attr_i2c_reg);
 err_val:
-	video_device_remove_file(v4ldev, &class_device_attr_val);
+	device_remove_file(classdev, &dev_attr_val);
 err_reg:
-	video_device_remove_file(v4ldev, &class_device_attr_reg);
+	device_remove_file(classdev, &dev_attr_reg);
 err_out:
 	return err;
 }
@@ -1103,7 +1110,8 @@
 	int err = 0;
 
 	if (!(cam->state & DEV_INITIALIZED)) {
-		init_waitqueue_head(&cam->open);
+		mutex_init(&cam->open_mutex);
+		init_waitqueue_head(&cam->wait_open);
 		qctrl = s->qctrl;
 		rect = &(s->cropcap.defrect);
 		cam->compression.quality = ET61X251_COMPRESSION_QUALITY;
@@ -1177,64 +1185,80 @@
 	return 0;
 }
 
+/*****************************************************************************/
 
-static void et61x251_release_resources(struct et61x251_device* cam)
+static void et61x251_release_resources(struct kref *kref)
 {
+	struct et61x251_device *cam;
+
 	mutex_lock(&et61x251_sysfs_lock);
 
+	cam = container_of(kref, struct et61x251_device, kref);
+
 	DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
 	video_set_drvdata(cam->v4ldev, NULL);
 	video_unregister_device(cam->v4ldev);
+	usb_put_dev(cam->usbdev);
+	kfree(cam->control_buffer);
+	kfree(cam);
 
 	mutex_unlock(&et61x251_sysfs_lock);
-
-	kfree(cam->control_buffer);
 }
 
-/*****************************************************************************/
 
 static int et61x251_open(struct inode* inode, struct file* filp)
 {
 	struct et61x251_device* cam;
 	int err = 0;
 
-	/*
-	   This is the only safe way to prevent race conditions with
-	   disconnect
-	*/
-	if (!down_read_trylock(&et61x251_disconnect))
+	if (!down_read_trylock(&et61x251_dev_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(video_devdata(filp));
 
-	if (mutex_lock_interruptible(&cam->dev_mutex)) {
-		up_read(&et61x251_disconnect);
+	if (wait_for_completion_interruptible(&cam->probe)) {
+		up_read(&et61x251_dev_lock);
 		return -ERESTARTSYS;
 	}
 
+	kref_get(&cam->kref);
+
+	if (mutex_lock_interruptible(&cam->open_mutex)) {
+		kref_put(&cam->kref, et61x251_release_resources);
+		up_read(&et61x251_dev_lock);
+		return -ERESTARTSYS;
+	}
+
+	if (cam->state & DEV_DISCONNECTED) {
+		DBG(1, "Device not present");
+		err = -ENODEV;
+		goto out;
+	}
+
 	if (cam->users) {
-		DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+		DBG(2, "Device /dev/video%d is already in use",
+		       cam->v4ldev->minor);
+		DBG(3, "Simultaneous opens are not supported");
 		if ((filp->f_flags & O_NONBLOCK) ||
 		    (filp->f_flags & O_NDELAY)) {
 			err = -EWOULDBLOCK;
 			goto out;
 		}
-		mutex_unlock(&cam->dev_mutex);
-		err = wait_event_interruptible_exclusive(cam->open,
-						  cam->state & DEV_DISCONNECTED
+		DBG(2, "A blocking open() has been requested. Wait for the "
+		       "device to be released...");
+		up_read(&et61x251_dev_lock);
+		err = wait_event_interruptible_exclusive(cam->wait_open,
+						(cam->state & DEV_DISCONNECTED)
 							 || !cam->users);
-		if (err) {
-			up_read(&et61x251_disconnect);
-			return err;
-		}
+		down_read(&et61x251_dev_lock);
+		if (err)
+			goto out;
 		if (cam->state & DEV_DISCONNECTED) {
-			up_read(&et61x251_disconnect);
-			return -ENODEV;
+			err = -ENODEV;
+			goto out;
 		}
-		mutex_lock(&cam->dev_mutex);
 	}
 
-
 	if (cam->state & DEV_MISCONFIGURED) {
 		err = et61x251_init(cam);
 		if (err) {
@@ -1259,36 +1283,32 @@
 	DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
 
 out:
-	mutex_unlock(&cam->dev_mutex);
-	up_read(&et61x251_disconnect);
+	mutex_unlock(&cam->open_mutex);
+	if (err)
+		kref_put(&cam->kref, et61x251_release_resources);
+	up_read(&et61x251_dev_lock);
 	return err;
 }
 
 
 static int et61x251_release(struct inode* inode, struct file* filp)
 {
-	struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
+	struct et61x251_device* cam;
 
-	mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+	down_write(&et61x251_dev_lock);
+
+	cam = video_get_drvdata(video_devdata(filp));
 
 	et61x251_stop_transfer(cam);
-
 	et61x251_release_buffers(cam);
-
-	if (cam->state & DEV_DISCONNECTED) {
-		et61x251_release_resources(cam);
-		usb_put_dev(cam->usbdev);
-		mutex_unlock(&cam->dev_mutex);
-		kfree(cam);
-		return 0;
-	}
-
 	cam->users--;
-	wake_up_interruptible_nr(&cam->open, 1);
+	wake_up_interruptible_nr(&cam->wait_open, 1);
 
 	DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
 
-	mutex_unlock(&cam->dev_mutex);
+	kref_put(&cam->kref, et61x251_release_resources);
+
+	up_write(&et61x251_dev_lock);
 
 	return 0;
 }
@@ -1324,7 +1344,7 @@
 		DBG(3, "Close and open the device again to choose the read "
 		       "method");
 		mutex_unlock(&cam->fileop_mutex);
-		return -EINVAL;
+		return -EBUSY;
 	}
 
 	if (cam->io == IO_NONE) {
@@ -1504,7 +1524,12 @@
 		return -EIO;
 	}
 
-	if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+	if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
+		mutex_unlock(&cam->fileop_mutex);
+		return -EACCES;
+	}
+
+	if (cam->io != IO_MMAP ||
 	    size != PAGE_ALIGN(cam->frame[0].buf.length)) {
 		mutex_unlock(&cam->fileop_mutex);
 		return -EINVAL;
@@ -1535,7 +1560,6 @@
 
 	vma->vm_ops = &et61x251_vm_ops;
 	vma->vm_private_data = &cam->frame[i];
-
 	et61x251_vm_open(vma);
 
 	mutex_unlock(&cam->fileop_mutex);
@@ -1764,7 +1788,7 @@
 			if (cam->frame[i].vma_use_count) {
 				DBG(3, "VIDIOC_S_CROP failed. "
 				       "Unmap the buffers first.");
-				return -EINVAL;
+				return -EBUSY;
 			}
 
 	/* Preserve R,G or B origin */
@@ -1921,6 +1945,8 @@
 	if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 
+	pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_ET61X251) ?
+			   0 : V4L2_COLORSPACE_SRGB;
 	pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251)
 			     ? 0 : (pfmt->width * pfmt->priv) / 8;
 	pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
@@ -1996,6 +2022,8 @@
 	    pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
 		pix->pixelformat = pfmt->pixelformat;
 	pix->priv = pfmt->priv; /* bpp */
+	pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) ?
+			  0 : V4L2_COLORSPACE_SRGB;
 	pix->colorspace = pfmt->colorspace;
 	pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
 			    ? 0 : (pix->width * pix->priv) / 8;
@@ -2013,7 +2041,7 @@
 			if (cam->frame[i].vma_use_count) {
 				DBG(3, "VIDIOC_S_FMT failed. "
 				       "Unmap the buffers first.");
-				return -EINVAL;
+				return -EBUSY;
 			}
 
 	if (cam->stream == STREAM_ON)
@@ -2129,14 +2157,14 @@
 	if (cam->io == IO_READ) {
 		DBG(3, "Close and open the device again to choose the mmap "
 		       "I/O method");
-		return -EINVAL;
+		return -EBUSY;
 	}
 
 	for (i = 0; i < cam->nbuffers; i++)
 		if (cam->frame[i].vma_use_count) {
 			DBG(3, "VIDIOC_REQBUFS failed. "
 			       "Previous buffers are still mapped.");
-			return -EINVAL;
+			return -EBUSY;
 		}
 
 	if (cam->stream == STREAM_ON)
@@ -2284,9 +2312,6 @@
 	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
 		return -EINVAL;
 
-	if (list_empty(&cam->inqueue))
-		return -EINVAL;
-
 	cam->stream = STREAM_ON;
 
 	DBG(3, "Stream on");
@@ -2535,8 +2560,6 @@
 		goto fail;
 	}
 
-	mutex_init(&cam->dev_mutex);
-
 	DBG(2, "ET61X[12]51 PC Camera Controller detected "
 	       "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
 
@@ -2568,7 +2591,7 @@
 	cam->v4ldev->release = video_device_release;
 	video_set_drvdata(cam->v4ldev, cam);
 
-	mutex_lock(&cam->dev_mutex);
+	init_completion(&cam->probe);
 
 	err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
 				    video_nr[dev_nr]);
@@ -2578,7 +2601,7 @@
 			DBG(1, "Free /dev/videoX node not found");
 		video_nr[dev_nr] = -1;
 		dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
-		mutex_unlock(&cam->dev_mutex);
+		complete_all(&cam->probe);
 		goto fail;
 	}
 
@@ -2599,11 +2622,15 @@
 		       "device controlling. Error #%d", err);
 #else
 	DBG(2, "Optional device control through 'sysfs' interface disabled");
+	DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' "
+	       "configuration option to enable it.");
 #endif
 
 	usb_set_intfdata(intf, cam);
+	kref_init(&cam->kref);
+	usb_get_dev(cam->usbdev);
 
-	mutex_unlock(&cam->dev_mutex);
+	complete_all(&cam->probe);
 
 	return 0;
 
@@ -2620,40 +2647,31 @@
 
 static void et61x251_usb_disconnect(struct usb_interface* intf)
 {
-	struct et61x251_device* cam = usb_get_intfdata(intf);
+	struct et61x251_device* cam;
 
-	if (!cam)
-		return;
+	down_write(&et61x251_dev_lock);
 
-	down_write(&et61x251_disconnect);
-
-	mutex_lock(&cam->dev_mutex);
+	cam = usb_get_intfdata(intf);
 
 	DBG(2, "Disconnecting %s...", cam->v4ldev->name);
 
-	wake_up_interruptible_all(&cam->open);
-
 	if (cam->users) {
 		DBG(2, "Device /dev/video%d is open! Deregistration and "
-		       "memory deallocation are deferred on close.",
+		       "memory deallocation are deferred.",
 		    cam->v4ldev->minor);
 		cam->state |= DEV_MISCONFIGURED;
 		et61x251_stop_transfer(cam);
 		cam->state |= DEV_DISCONNECTED;
 		wake_up_interruptible(&cam->wait_frame);
 		wake_up(&cam->wait_stream);
-		usb_get_dev(cam->usbdev);
-	} else {
+	} else
 		cam->state |= DEV_DISCONNECTED;
-		et61x251_release_resources(cam);
-	}
 
-	mutex_unlock(&cam->dev_mutex);
+	wake_up_interruptible_all(&cam->wait_open);
 
-	if (!cam->users)
-		kfree(cam);
+	kref_put(&cam->kref, et61x251_release_resources);
 
-	up_write(&et61x251_disconnect);
+	up_write(&et61x251_dev_lock);
 }
 
 
diff --git a/drivers/media/video/et61x251/et61x251_sensor.h b/drivers/media/video/et61x251/et61x251_sensor.h
index 5fadb5d..e145863 100644
--- a/drivers/media/video/et61x251/et61x251_sensor.h
+++ b/drivers/media/video/et61x251/et61x251_sensor.h
@@ -22,7 +22,7 @@
 #define _ET61X251_SENSOR_H_
 
 #include <linux/usb.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <linux/device.h>
 #include <linux/stddef.h>
 #include <linux/errno.h>
@@ -47,7 +47,7 @@
 
 extern void
 et61x251_attach_sensor(struct et61x251_device* cam,
-		       struct et61x251_sensor* sensor);
+		       const struct et61x251_sensor* sensor);
 
 /*****************************************************************************/
 
@@ -56,10 +56,10 @@
 extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value);
 extern int et61x251_i2c_read(struct et61x251_device*, u8 address);
 extern int et61x251_i2c_try_write(struct et61x251_device*,
-				  struct et61x251_sensor*, u8 address,
+				  const struct et61x251_sensor*, u8 address,
 				  u8 value);
 extern int et61x251_i2c_try_read(struct et61x251_device*,
-				 struct et61x251_sensor*, u8 address);
+				 const struct et61x251_sensor*, u8 address);
 extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
 				  u8 data2, u8 data3, u8 data4, u8 data5,
 				  u8 data6, u8 data7, u8 data8, u8 address);
diff --git a/drivers/media/video/et61x251/et61x251_tas5130d1b.c b/drivers/media/video/et61x251/et61x251_tas5130d1b.c
index b066434..04b7fbb 100644
--- a/drivers/media/video/et61x251/et61x251_tas5130d1b.c
+++ b/drivers/media/video/et61x251/et61x251_tas5130d1b.c
@@ -69,7 +69,7 @@
 }
 
 
-static struct et61x251_sensor tas5130d1b = {
+static const struct et61x251_sensor tas5130d1b = {
 	.name = "TAS5130D1B",
 	.interface = ET61X251_I2C_3WIRES,
 	.rsta = ET61X251_I2C_RSTA_STOP,
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index ed92b6f..d98dd0d 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -10,6 +10,8 @@
  *      Ulrich Mueller <ulrich.mueller42@web.de>
  * modified for em2820 based USB TV tuners by
  *      Markus Rechberger <mrechberger@gmail.com>
+ * modified for DViCO Fusion HDTV 5 RT GOLD by
+ *      Chaogui Zhang <czhang1974@gmail.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
@@ -28,7 +30,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -37,6 +38,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
+#include <linux/i2c-id.h>
 #include <linux/workqueue.h>
 #include <asm/semaphore.h>
 
@@ -60,21 +62,22 @@
 
 /* ----------------------------------------------------------------------- */
 
-static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
+			       int size, int offset)
 {
-	unsigned char buf[3];
+	unsigned char buf[6];
 	int start, range, toggle, dev, code;
 
 	/* poll IR chip */
-	if (3 != i2c_master_recv(&ir->c,buf,3))
+	if (size != i2c_master_recv(&ir->c,buf,size))
 		return -EIO;
 
 	/* split rc5 data block ... */
-	start  = (buf[0] >> 7) &    1;
-	range  = (buf[0] >> 6) &    1;
-	toggle = (buf[0] >> 5) &    1;
-	dev    =  buf[0]       & 0x1f;
-	code   = (buf[1] >> 2) & 0x3f;
+	start  = (buf[offset] >> 7) &    1;
+	range  = (buf[offset] >> 6) &    1;
+	toggle = (buf[offset] >> 5) &    1;
+	dev    =  buf[offset]       & 0x1f;
+	code   = (buf[offset+1] >> 2) & 0x3f;
 
 	/* rc5 has two start bits
 	 * the first bit must be one
@@ -96,6 +99,16 @@
 	return 1;
 }
 
+static inline int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	return get_key_haup_common (ir, ir_key, ir_raw, 3, 0);
+}
+
+static inline int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	return get_key_haup_common (ir, ir_key, ir_raw, 6, 3);
+}
+
 static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
 	unsigned char b;
@@ -130,6 +143,30 @@
 	return 1;
 }
 
+static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+	unsigned char buf[4];
+
+	/* poll IR chip */
+	if (4 != i2c_master_recv(&ir->c,buf,4)) {
+		dprintk(1,"read error\n");
+		return -EIO;
+	}
+
+	if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0)
+		dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __FUNCTION__,
+			buf[0], buf[1], buf[2], buf[3]);
+
+	/* no key pressed or signal from other ir remote */
+	if(buf[0] != 0x1 ||  buf[1] != 0xfe)
+		return 0;
+
+	*ir_key = buf[2];
+	*ir_raw = (buf[2] << 8) | buf[3];
+
+	return 1;
+}
+
 static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
 {
 	unsigned char b;
@@ -270,8 +307,9 @@
 static void ir_work(struct work_struct *work)
 {
 	struct IR_i2c *ir = container_of(work, struct IR_i2c, work);
+
 	ir_key_poll(ir);
-	mod_timer(&ir->timer, jiffies+HZ/10);
+	mod_timer(&ir->timer, jiffies + msecs_to_jiffies(100));
 }
 
 /* ----------------------------------------------------------------------- */
@@ -351,12 +389,30 @@
 		ir_type     = IR_TYPE_OTHER;
 		ir_codes    = ir_codes_empty;
 		break;
+	case 0x6b:
+		name        = "FusionHDTV";
+		ir->get_key = get_key_fusionhdtv;
+		ir_type     = IR_TYPE_RC5;
+		ir_codes    = ir_codes_fusionhdtv_mce;
+		break;
 	case 0x7a:
 	case 0x47:
 	case 0x71:
-		/* Handled by saa7134-input */
-		name        = "SAA713x remote";
-		ir_type     = IR_TYPE_OTHER;
+		if (adap->id == I2C_HW_B_CX2388x) {
+			/* Handled by cx88-input */
+			name        = "CX2388x remote";
+			ir_type     = IR_TYPE_RC5;
+			ir->get_key = get_key_haup_xvr;
+			if (hauppauge == 1) {
+				ir_codes    = ir_codes_hauppauge_new;
+			} else {
+				ir_codes    = ir_codes_rc5_tv;
+			}
+		} else {
+			/* Handled by saa7134-input */
+			name        = "SAA713x remote";
+			ir_type     = IR_TYPE_OTHER;
+		}
 		break;
 	default:
 		/* shouldn't happen */
@@ -450,6 +506,8 @@
 	static const int probe_bttv[] = { 0x1a, 0x18, 0x4b, 0x64, 0x30, -1};
 	static const int probe_saa7134[] = { 0x7a, 0x47, 0x71, -1 };
 	static const int probe_em28XX[] = { 0x30, 0x47, -1 };
+	static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 };
+	static const int probe_cx23885[] = { 0x6b, -1 };
 	const int *probe = NULL;
 	struct i2c_client c;
 	unsigned char buf;
@@ -468,6 +526,11 @@
 	case I2C_HW_B_EM28XX:
 		probe = probe_em28XX;
 		break;
+	case I2C_HW_B_CX2388x:
+		probe = probe_cx88;
+	case I2C_HW_B_CX23885:
+		probe = probe_cx23885;
+		break;
 	}
 	if (NULL == probe)
 		return 0;
diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig
index 1aaeaa0..854cc9c 100644
--- a/drivers/media/video/ivtv/Kconfig
+++ b/drivers/media/video/ivtv/Kconfig
@@ -1,6 +1,7 @@
 config VIDEO_IVTV
 	tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support"
 	depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL
+	select I2C_ALGOBIT
 	select FW_LOADER
 	select VIDEO_TUNER
 	select VIDEO_TVEEPROM
@@ -13,14 +14,31 @@
 	select VIDEO_CS53L32A
 	select VIDEO_WM8775
 	select VIDEO_WM8739
+	select VIDEO_VP27SMPX
 	select VIDEO_UPD64031A
 	select VIDEO_UPD64083
 	---help---
-	  This is a video4linux driver for Conexant cx23416 or cx23416 based
+	  This is a video4linux driver for Conexant cx23416 or cx23415 based
 	  PCI personal video recorder devices.
 
 	  This is used in devices such as the Hauppauge PVR-150/250/350/500
-	  cards.
+	  cards. There is a driver homepage at <http://www.ivtvdriver.org>.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called ivtv.
+
+config VIDEO_FB_IVTV
+	tristate "Conexant cx23415 framebuffer support"
+	depends on VIDEO_IVTV && FB && EXPERIMENTAL
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	---help---
+	  This is a framebuffer driver for the Conexant cx23415 MPEG
+	  encoder/decoder.
+
+	  This is used in the Hauppauge PVR-350 card. There is a driver
+	  homepage at <http://www.ivtvdriver.org>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ivtvfb.
diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile
index 7e95148..e8eefd9 100644
--- a/drivers/media/video/ivtv/Makefile
+++ b/drivers/media/video/ivtv/Makefile
@@ -1,7 +1,8 @@
-ivtv-objs	:= ivtv-audio.o ivtv-cards.o ivtv-controls.o \
+ivtv-objs	:= ivtv-routing.o ivtv-cards.o ivtv-controls.o \
 		   ivtv-driver.o ivtv-fileops.o ivtv-firmware.o \
 		   ivtv-gpio.o ivtv-i2c.o ivtv-ioctl.o ivtv-irq.o \
 		   ivtv-mailbox.o ivtv-queue.o ivtv-streams.o ivtv-udma.o \
-		   ivtv-vbi.o ivtv-video.o ivtv-yuv.o
+		   ivtv-vbi.o ivtv-yuv.o
 
 obj-$(CONFIG_VIDEO_IVTV) += ivtv.o
+obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
diff --git a/drivers/media/video/ivtv/ivtv-audio.c b/drivers/media/video/ivtv/ivtv-audio.c
deleted file mode 100644
index d702b8b..0000000
--- a/drivers/media/video/ivtv/ivtv-audio.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
-    Audio-related ivtv functions.
-    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
-    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
-
-    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 "ivtv-driver.h"
-#include "ivtv-mailbox.h"
-#include "ivtv-i2c.h"
-#include "ivtv-gpio.h"
-#include "ivtv-cards.h"
-#include "ivtv-audio.h"
-#include <media/msp3400.h>
-#include <linux/videodev.h>
-
-/* Selects the audio input and output according to the current
-   settings. */
-int ivtv_audio_set_io(struct ivtv *itv)
-{
-	struct v4l2_routing route;
-	u32 audio_input;
-	int mux_input;
-
-	/* Determine which input to use */
-	if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
-		audio_input = itv->card->radio_input.audio_input;
-		mux_input = itv->card->radio_input.muxer_input;
-	} else {
-		audio_input = itv->card->audio_inputs[itv->audio_input].audio_input;
-		mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input;
-	}
-
-	/* handle muxer chips */
-	route.input = mux_input;
-	route.output = 0;
-	ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
-
-	route.input = audio_input;
-	if (itv->card->hw_audio & IVTV_HW_MSP34XX) {
-		route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
-	}
-	return ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route);
-}
-
-void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route)
-{
-	ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
-}
-
-void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq)
-{
-	static u32 freqs[3] = { 44100, 48000, 32000 };
-
-	/* The audio clock of the digitizer must match the codec sample
-	   rate otherwise you get some very strange effects. */
-	if (freq > 2)
-		return;
-	ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]);
-}
-
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index 8eab0208..b6a8be6 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -616,7 +616,7 @@
 	.hw_video = IVTV_HW_SAA7115 | IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
 	.hw_audio = IVTV_HW_GPIO,
 	.hw_audio_ctrl = IVTV_HW_WM8739,
-	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TVAUDIO |
+	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_VP27SMPX |
 		  IVTV_HW_TUNER | IVTV_HW_WM8739 |
 		  IVTV_HW_UPD64031A | IVTV_HW_UPD6408X,
 	.video_inputs = {
@@ -654,7 +654,7 @@
 	.hw_audio = IVTV_HW_GPIO,
 	.hw_audio_ctrl = IVTV_HW_WM8739,
 	.hw_all = IVTV_HW_GPIO | IVTV_HW_SAA7115 | IVTV_HW_TUNER |
-		  IVTV_HW_TVAUDIO | IVTV_HW_WM8739,
+		  IVTV_HW_VP27SMPX | IVTV_HW_WM8739,
 	.video_inputs = {
 		{ IVTV_CARD_INPUT_VID_TUNER,  0, IVTV_SAA71XX_COMPOSITE4 },
 		{ IVTV_CARD_INPUT_SVIDEO1,    1, IVTV_SAA71XX_SVIDEO0    },
@@ -823,9 +823,7 @@
 
 /* ------------------------------------------------------------------------- */
 
-#ifdef HAVE_XC3028
-
-/* Yuan PG600-2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 cards */
+/* Yuan PG600-2/GotView PCI DVD Lite cards */
 
 static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = {
 	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3,     0x0600 },
@@ -835,29 +833,87 @@
 
 static const struct ivtv_card ivtv_card_pg600v2 = {
 	.type = IVTV_CARD_PG600V2,
-	.name = "Yuan PG600-2, GotView PCI DVD Lite, Club3D ZAP-TV1x01",
+	.name = "Yuan PG600-2, GotView PCI DVD Lite",
 	.v4l2_capabilities = IVTV_CAP_ENCODER,
 	.hw_video = IVTV_HW_CX25840,
 	.hw_audio = IVTV_HW_CX25840,
 	.hw_audio_ctrl = IVTV_HW_CX25840,
 	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
 	.video_inputs = {
-		{ IVTV_CARD_INPUT_VID_TUNER,  0, CX25840_COMPOSITE2 },
-		{ IVTV_CARD_INPUT_SVIDEO1,    1,
+		{ IVTV_CARD_INPUT_SVIDEO1,    0,
 		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
 	},
 	.audio_inputs = {
-		{ IVTV_CARD_INPUT_AUD_TUNER,  CX25840_AUDIO5       },
 		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
 	},
-	.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
 	.tuners = {
 		{ .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
 	},
-	.gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */
 	.pci_list = ivtv_pci_pg600v2,
 };
-#endif
+
+/* ------------------------------------------------------------------------- */
+
+/* Club3D ZAP-TV1x01 cards */
+
+static const struct ivtv_card_pci_info ivtv_pci_club3d[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_YUAN3,     0x0600 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_club3d = {
+	.type = IVTV_CARD_CLUB3D,
+	.name = "Club3D ZAP-TV1x01",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_SVIDEO1,    0,
+		  CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE3 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL },
+	},
+	.tuners = {
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
+	},
+	.pci_list = ivtv_pci_club3d,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* AVerTV MCE 116 Plus (M116) card */
+
+static const struct ivtv_card_pci_info ivtv_pci_avertv_mce116[] = {
+	{ PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc439 },
+	{ 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_avertv_mce116 = {
+	.type = IVTV_CARD_AVERTV_MCE116,
+	.name = "AVerTV MCE 116 Plus",
+	.v4l2_capabilities = IVTV_CAP_ENCODER,
+	.hw_video = IVTV_HW_CX25840,
+	.hw_audio = IVTV_HW_CX25840,
+	.hw_audio_ctrl = IVTV_HW_CX25840,
+	.hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739,
+	.video_inputs = {
+		{ IVTV_CARD_INPUT_SVIDEO1,    0, CX25840_SVIDEO3    },
+		{ IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
+	},
+	.audio_inputs = {
+		{ IVTV_CARD_INPUT_LINE_IN1,   CX25840_AUDIO_SERIAL, 1 },
+	},
+	.gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */
+	.tuners = {
+		{ .std = V4L2_STD_ALL, .tuner = TUNER_XCEIVE_XC3028 },
+	},
+	.pci_list = ivtv_pci_avertv_mce116,
+};
 
 static const struct ivtv_card *ivtv_card_list[] = {
 	&ivtv_card_pvr250,
@@ -878,9 +934,9 @@
 	&ivtv_card_gotview_pci_dvd2,
 	&ivtv_card_yuan_mpc622,
 	&ivtv_card_dctmvtvp1,
-#ifdef HAVE_XC3028
 	&ivtv_card_pg600v2,
-#endif
+	&ivtv_card_club3d,
+	&ivtv_card_avertv_mce116,
 
 	/* Variations of standard cards but with the same PCI IDs.
 	   These cards must come last in this list. */
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
index 91e9e90..ff46e5a 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -18,6 +18,68 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#ifndef IVTV_CARDS_H
+#define IVTV_CARDS_H
+
+/* Supported cards */
+#define IVTV_CARD_PVR_250 	      0	/* WinTV PVR 250 */
+#define IVTV_CARD_PVR_350 	      1	/* encoder, decoder, tv-out */
+#define IVTV_CARD_PVR_150 	      2	/* WinTV PVR 150 and PVR 500 (really just two
+					   PVR150s on one PCI board) */
+#define IVTV_CARD_M179    	      3	/* AVerMedia M179 (encoder only) */
+#define IVTV_CARD_MPG600  	      4	/* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */
+#define IVTV_CARD_MPG160  	      5	/* Kuroutoshikou ITVC15-STVLP/YUAN MPG160
+					   cx23415 based, but does not have tv-out */
+#define IVTV_CARD_PG600 	      6	/* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */
+#define IVTV_CARD_AVC2410 	      7	/* Adaptec AVC-2410 */
+#define IVTV_CARD_AVC2010 	      8	/* Adaptec AVD-2010 (No Tuner) */
+#define IVTV_CARD_TG5000TV   	      9 /* NAGASE TRANSGEAR 5000TV, encoder only */
+#define IVTV_CARD_VA2000MAX_SNT6     10 /* VA2000MAX-STN6 */
+#define IVTV_CARD_CX23416GYC 	     11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */
+#define IVTV_CARD_GV_MVPRX   	     12 /* I/O Data GV-MVP/RX, RX2, RX2W */
+#define IVTV_CARD_GV_MVPRX2E 	     13 /* I/O Data GV-MVP/RX2E */
+#define IVTV_CARD_GOTVIEW_PCI_DVD    14	/* GotView PCI DVD */
+#define IVTV_CARD_GOTVIEW_PCI_DVD2   15	/* GotView PCI DVD2 */
+#define IVTV_CARD_YUAN_MPC622        16	/* Yuan MPC622 miniPCI */
+#define IVTV_CARD_DCTMTVP1 	     17 /* DIGITAL COWBOY DCT-MTVP1 */
+#define IVTV_CARD_PG600V2	     18 /* Yuan PG600V2/GotView PCI DVD Lite */
+#define IVTV_CARD_CLUB3D	     19 /* Club3D ZAP-TV1x01 */
+#define IVTV_CARD_AVERTV_MCE116	     20 /* AVerTV MCE 116 Plus */
+#define IVTV_CARD_LAST 		     20
+
+/* Variants of existing cards but with the same PCI IDs. The driver
+   detects these based on other device information.
+   These cards must always come last.
+   New cards must be inserted above, and the indices of the cards below
+   must be adjusted accordingly. */
+
+/* PVR-350 V1 (uses saa7114) */
+#define IVTV_CARD_PVR_350_V1 	     (IVTV_CARD_LAST+1)
+/* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */
+#define IVTV_CARD_CX23416GYC_NOGR    (IVTV_CARD_LAST+2)
+#define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3)
+
+/* system vendor and device IDs */
+#define PCI_VENDOR_ID_ICOMP  0x4444
+#define PCI_DEVICE_ID_IVTV15 0x0803
+#define PCI_DEVICE_ID_IVTV16 0x0016
+
+/* subsystem vendor ID */
+#define IVTV_PCI_ID_HAUPPAUGE 		0x0070
+#define IVTV_PCI_ID_HAUPPAUGE_ALT1 	0x0270
+#define IVTV_PCI_ID_HAUPPAUGE_ALT2 	0x4070
+#define IVTV_PCI_ID_ADAPTEC 		0x9005
+#define IVTV_PCI_ID_AVERMEDIA 		0x1461
+#define IVTV_PCI_ID_YUAN1		0x12ab
+#define IVTV_PCI_ID_YUAN2 		0xff01
+#define IVTV_PCI_ID_YUAN3 		0xffab
+#define IVTV_PCI_ID_YUAN4 		0xfbab
+#define IVTV_PCI_ID_DIAMONDMM 		0xff92
+#define IVTV_PCI_ID_IODATA 		0x10fc
+#define IVTV_PCI_ID_MELCO 		0x1154
+#define IVTV_PCI_ID_GOTVIEW1		0xffac
+#define IVTV_PCI_ID_GOTVIEW2 		0xffad
+
 /* hardware flags */
 #define IVTV_HW_CX25840   (1 << 0)
 #define IVTV_HW_SAA7115   (1 << 1)
@@ -33,7 +95,8 @@
 #define IVTV_HW_UPD6408X  (1 << 11)
 #define IVTV_HW_SAA717X   (1 << 12)
 #define IVTV_HW_WM8739    (1 << 13)
-#define IVTV_HW_GPIO      (1 << 14)
+#define IVTV_HW_VP27SMPX  (1 << 14)
+#define IVTV_HW_GPIO      (1 << 15)
 
 #define IVTV_HW_SAA711X   (IVTV_HW_SAA7115 | IVTV_HW_SAA7114)
 
@@ -205,3 +268,5 @@
 int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *input);
 int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *output);
 const struct ivtv_card *ivtv_get_card(u16 index);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c
index 7a876c3..8c02fa6 100644
--- a/drivers/media/video/ivtv/ivtv-controls.c
+++ b/drivers/media/video/ivtv/ivtv-controls.c
@@ -21,7 +21,7 @@
 #include "ivtv-driver.h"
 #include "ivtv-cards.h"
 #include "ivtv-ioctl.h"
-#include "ivtv-audio.h"
+#include "ivtv-routing.h"
 #include "ivtv-i2c.h"
 #include "ivtv-mailbox.h"
 #include "ivtv-controls.h"
@@ -231,8 +231,10 @@
 		}
 		IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
 		if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+			static u32 freqs[3] = { 44100, 48000, 32000 };
 			struct cx2341x_mpeg_params p = itv->params;
-			int err = cx2341x_ext_ctrls(&p, arg, cmd);
+			int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), arg, cmd);
+			unsigned idx;
 
 			if (err)
 				return err;
@@ -254,7 +256,11 @@
 			}
 			itv->params = p;
 			itv->dualwatch_stereo_mode = p.audio_properties & 0x0300;
-			ivtv_audio_set_audio_clock_freq(itv, p.audio_properties & 0x03);
+			idx = p.audio_properties & 0x03;
+			/* The audio clock of the digitizer must match the codec sample
+			   rate otherwise you get some very strange effects. */
+			if (idx < sizeof(freqs))
+			    ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]);
 			return err;
 		}
 		return -EINVAL;
@@ -282,7 +288,7 @@
 		}
 		IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n");
 		if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
-			return cx2341x_ext_ctrls(&itv->params, arg, cmd);
+			return cx2341x_ext_ctrls(&itv->params, 0, arg, cmd);
 		return -EINVAL;
 	}
 
@@ -292,7 +298,7 @@
 
 		IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
 		if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
-			return cx2341x_ext_ctrls(&itv->params, arg, cmd);
+			return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), arg, cmd);
 		return -EINVAL;
 	}
 
diff --git a/drivers/media/video/ivtv/ivtv-controls.h b/drivers/media/video/ivtv/ivtv-controls.h
index 5a11149..bb8a6a5 100644
--- a/drivers/media/video/ivtv/ivtv-controls.h
+++ b/drivers/media/video/ivtv/ivtv-controls.h
@@ -18,4 +18,9 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#ifndef IVTV_CONTROLS_H
+#define IVTV_CONTROLS_H
+
 int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index efc6635..511a662 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -52,12 +52,12 @@
 #include "ivtv-ioctl.h"
 #include "ivtv-cards.h"
 #include "ivtv-vbi.h"
-#include "ivtv-audio.h"
+#include "ivtv-routing.h"
 #include "ivtv-gpio.h"
 #include "ivtv-yuv.h"
 
-#include <linux/vermagic.h>
 #include <media/tveeprom.h>
+#include <media/saa7115.h>
 #include <media/v4l2-chip-ident.h>
 
 /* var to keep track of the number of array elements in use */
@@ -87,17 +87,16 @@
 
 MODULE_DEVICE_TABLE(pci,ivtv_pci_tbl);
 
-const u32 yuv_offset[4] = {
-	IVTV_YUV_BUFFER_OFFSET,
-	IVTV_YUV_BUFFER_OFFSET_1,
-	IVTV_YUV_BUFFER_OFFSET_2,
-	IVTV_YUV_BUFFER_OFFSET_3
-};
-
 /* Parameter declarations */
 static int cardtype[IVTV_MAX_CARDS];
-static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
-static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
+static int tuner[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1 };
+static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1,
+				     -1, -1, -1, -1, -1, -1, -1, -1 };
 
 static int cardtype_c = 1;
 static int tuner_c = 1;
@@ -107,6 +106,18 @@
 static char ntsc[] = "-";
 
 /* Buffers */
+
+/* DMA Buffers, Default size in MB allocated */
+#define IVTV_DEFAULT_ENC_MPG_BUFFERS 4
+#define IVTV_DEFAULT_ENC_YUV_BUFFERS 2
+#define IVTV_DEFAULT_ENC_VBI_BUFFERS 1
+/* Exception: size in kB for this stream (MB is overkill) */
+#define IVTV_DEFAULT_ENC_PCM_BUFFERS 320
+#define IVTV_DEFAULT_DEC_MPG_BUFFERS 1
+#define IVTV_DEFAULT_DEC_YUV_BUFFERS 1
+/* Exception: size in kB for this stream (MB is way overkill) */
+#define IVTV_DEFAULT_DEC_VBI_BUFFERS 64
+
 static int enc_mpg_buffers = IVTV_DEFAULT_ENC_MPG_BUFFERS;
 static int enc_yuv_buffers = IVTV_DEFAULT_ENC_YUV_BUFFERS;
 static int enc_vbi_buffers = IVTV_DEFAULT_ENC_VBI_BUFFERS;
@@ -171,17 +182,27 @@
 		 "\t\t\t16 = GOTVIEW PCI DVD2 Deluxe\n"
 		 "\t\t\t17 = Yuan MPC622\n"
 		 "\t\t\t18 = Digital Cowboy DCT-MTVP1\n"
-#ifdef HAVE_XC3028
-		 "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01\n"
-#endif
+		 "\t\t\t19 = Yuan PG600V2/GotView PCI DVD Lite\n"
+		 "\t\t\t20 = Club3D ZAP-TV1x01\n"
+		 "\t\t\t21 = AverTV MCE 116 Plus\n"
 		 "\t\t\t 0 = Autodetect (default)\n"
 		 "\t\t\t-1 = Ignore this card\n\t\t");
 MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
 MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC");
 MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K");
 MODULE_PARM_DESC(debug,
-		 "Debug level (bitmask). Default: errors only\n"
-		 "\t\t\t(debug = 511 gives full debugging)");
+		 "Debug level (bitmask). Default: 0\n"
+		 "\t\t\t   1/0x0001: warning\n"
+		 "\t\t\t   2/0x0002: info\n"
+		 "\t\t\t   4/0x0004: mailbox\n"
+		 "\t\t\t   8/0x0008: ioctl\n"
+		 "\t\t\t  16/0x0010: file\n"
+		 "\t\t\t  32/0x0020: dma\n"
+		 "\t\t\t  64/0x0040: irq\n"
+		 "\t\t\t 128/0x0080: decoder\n"
+		 "\t\t\t 256/0x0100: yuv\n"
+		 "\t\t\t 512/0x0200: i2c\n"
+		 "\t\t\t1024/0x0400: high volume\n");
 MODULE_PARM_DESC(ivtv_pci_latency,
 		 "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
 		 "\t\t\tDefault: Yes");
@@ -202,7 +223,7 @@
 		 "Encoder VBI Buffers (in MB)\n"
 		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_VBI_BUFFERS));
 MODULE_PARM_DESC(enc_pcm_buffers,
-		 "Encoder PCM buffers (in MB)\n"
+		 "Encoder PCM buffers (in kB)\n"
 		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_ENC_PCM_BUFFERS));
 MODULE_PARM_DESC(dec_mpg_buffers,
 		 "Decoder MPG buffers (in MB)\n"
@@ -211,7 +232,7 @@
 		 "Decoder YUV buffers (in MB)\n"
 		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_YUV_BUFFERS));
 MODULE_PARM_DESC(dec_vbi_buffers,
-		 "Decoder VBI buffers (in MB)\n"
+		 "Decoder VBI buffers (in kB)\n"
 		 "\t\t\tDefault: " __stringify(IVTV_DEFAULT_DEC_VBI_BUFFERS));
 MODULE_PARM_DESC(newi2c,
 		 "Use new I2C implementation\n"
@@ -276,9 +297,10 @@
 }
 
 /* Generic utility functions */
-int ivtv_sleep_timeout(int timeout, int intr)
+int ivtv_msleep_timeout(unsigned int msecs, int intr)
 {
 	int ret;
+	int timeout = msecs_to_jiffies(msecs);
 
 	do {
 		set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
@@ -339,6 +361,7 @@
 		/* In a few cases the PCI subsystem IDs do not correctly
 		   identify the card. A better method is to check the
 		   model number from the eeprom instead. */
+		case 30012 ... 30039:  /* Low profile PVR250 */
 		case 32000 ... 32999:
 		case 48000 ... 48099:  /* 48??? range are PVR250s with a cx23415 */
 		case 48400 ... 48599:
@@ -426,7 +449,7 @@
 	if (itv->options.newi2c == -1 && tv.has_ir != -1 && tv.has_ir != 2) {
 		itv->options.newi2c = (tv.has_ir & 2) ? 1 : 0;
 		if (itv->options.newi2c) {
-		    IVTV_INFO("reopen i2c bus for IR-blaster support\n");
+		    IVTV_INFO("Reopen i2c bus for IR-blaster support\n");
 		    exit_ivtv_i2c(itv);
 		    init_ivtv_i2c(itv);
 		}
@@ -539,13 +562,13 @@
 	const char *chipname;
 	int i, j;
 
-	itv->options.megabytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
-	itv->options.megabytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers;
-	itv->options.megabytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers;
-	itv->options.megabytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
-	itv->options.megabytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers;
-	itv->options.megabytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers;
-	itv->options.megabytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers;
+	itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers * 1024;
+	itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers * 1024;
+	itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers * 1024;
+	itv->options.kilobytes[IVTV_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
+	itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_MPG] = dec_mpg_buffers * 1024;
+	itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_YUV] = dec_yuv_buffers * 1024;
+	itv->options.kilobytes[IVTV_DEC_STREAM_TYPE_VBI] = dec_vbi_buffers;
 	itv->options.cardtype = cardtype[itv->num];
 	itv->options.tuner = tuner[itv->num];
 	itv->options.radio = radio[itv->num];
@@ -622,6 +645,7 @@
 	itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */
 	itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */
 
+	mutex_init(&itv->serialize_lock);
 	mutex_init(&itv->i2c_bus_lock);
 	mutex_init(&itv->udma.lock);
 
@@ -643,7 +667,7 @@
 	cx2341x_fill_defaults(&itv->params);
 	itv->params.port = CX2341X_PORT_MEMORY;
 	itv->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
-	init_waitqueue_head(&itv->cap_w);
+	init_waitqueue_head(&itv->eos_waitq);
 	init_waitqueue_head(&itv->event_waitq);
 	init_waitqueue_head(&itv->vsync_waitq);
 	init_waitqueue_head(&itv->dma_waitq);
@@ -689,14 +713,6 @@
 			break;
 	itv->nof_audio_inputs = i;
 
-	/* 0x00EF = saa7114(239) 0x00F0 = saa7115(240) 0x0106 = micro */
-	if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X))
-		itv->digitizer = 0xF1;
-	else if (itv->card->hw_all & IVTV_HW_SAA7114)
-		itv->digitizer = 0xEF;
-	else /* cx25840 */
-		itv->digitizer = 0x140;
-
 	if (itv->card->hw_all & IVTV_HW_CX25840) {
 		itv->vbi.sliced_size = 288;  /* multiple of 16, real size = 284 */
 	} else {
@@ -725,6 +741,7 @@
 			  const struct pci_device_id *pci_id)
 {
 	u16 cmd;
+	u8 card_rev;
 	unsigned char pci_latency;
 
 	IVTV_DEBUG_INFO("Enabling pci device\n");
@@ -771,7 +788,7 @@
 	}
 	IVTV_DEBUG_INFO("Bus Mastering Enabled.\n");
 
-	pci_read_config_byte(dev, PCI_CLASS_REVISION, &itv->card_rev);
+	pci_read_config_byte(dev, PCI_CLASS_REVISION, &card_rev);
 	pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
 
 	if (pci_latency < 64 && ivtv_pci_latency) {
@@ -788,7 +805,7 @@
 
 	IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, "
 		   "irq: %d, latency: %d, memory: 0x%lx\n",
-		   itv->dev->device, itv->card_rev, dev->bus->number,
+		   itv->dev->device, card_rev, dev->bus->number,
 		   PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
 		   itv->dev->irq, pci_latency, (unsigned long)itv->base_addr);
 
@@ -806,18 +823,19 @@
 
 static void ivtv_load_and_init_modules(struct ivtv *itv)
 {
-	struct v4l2_control ctrl;
 	u32 hw = itv->card->hw_all;
 	int i;
 
 	/* load modules */
 #ifndef CONFIG_VIDEO_TUNER
 	if (hw & IVTV_HW_TUNER) {
-		ivtv_request_module(itv, "tuner");
-#ifdef HAVE_XC3028
-		if (itv->options.tuner == TUNER_XCEIVE_XC3028)
-			ivtv_request_module(itv, "xc3028-tuner");
-#endif
+		if (itv->options.tuner == TUNER_XCEIVE_XC3028) {
+			IVTV_INFO("Xceive tuner not yet supported, only composite and S-Video inputs will be available\n");
+			itv->tunerid = 1;
+		}
+		else {
+			ivtv_request_module(itv, "tuner");
+		}
 	}
 #endif
 #ifndef CONFIG_VIDEO_CX25840
@@ -846,6 +864,10 @@
 	if (hw & IVTV_HW_MSP34XX)
 		ivtv_request_module(itv, "msp3400");
 #endif
+#ifndef CONFIG_VIDEO_VP27SMPX
+	if (hw & IVTV_HW_VP27SMPX)
+		ivtv_request_module(itv, "vp27smpx");
+#endif
 	if (hw & IVTV_HW_TVAUDIO)
 		ivtv_request_module(itv, "tvaudio");
 #ifndef CONFIG_VIDEO_WM8775
@@ -886,13 +908,17 @@
 		else if ((hw & IVTV_HW_UPD64031A) == 0)
 			itv->card = ivtv_get_card(IVTV_CARD_CX23416GYC_NOGR);
 	}
+	else if (itv->card->type == IVTV_CARD_GV_MVPRX ||
+		 itv->card->type == IVTV_CARD_GV_MVPRX2E) {
+		struct v4l2_crystal_freq crystal_freq;
+
+		/* The crystal frequency of GVMVPRX is 24.576MHz */
+		crystal_freq.freq = SAA7115_FREQ_24_576_MHZ;
+		crystal_freq.flags = SAA7115_FREQ_FL_UCGC;
+		itv->video_dec_func(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);
+	}
 
 	if (hw & IVTV_HW_CX25840) {
-		/* CX25840_CID_ENABLE_PVR150_WORKAROUND */
-		ctrl.id = V4L2_CID_PRIVATE_BASE;
-		ctrl.value = itv->pvr150_workaround;
-		itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl);
-
 		itv->vbi.raw_decoder_line_size = 1444;
 		itv->vbi.raw_decoder_sav_odd_field = 0x20;
 		itv->vbi.raw_decoder_sav_even_field = 0x60;
@@ -938,18 +964,15 @@
 				const struct pci_device_id *pci_id)
 {
 	int retval = 0;
-	int video_input;
 	int yuv_buf_size;
 	int vbi_buf_size;
-	int fw_retry_count = 3;
 	struct ivtv *itv;
-	struct v4l2_frequency vf;
 
 	spin_lock(&ivtv_cards_lock);
 
 	/* Make sure we've got a place for this card */
 	if (ivtv_cards_active == IVTV_MAX_CARDS) {
-		printk(KERN_ERR "ivtv:  Maximum number of cards detected (%d).\n",
+		printk(KERN_ERR "ivtv:  Maximum number of cards detected (%d)\n",
 			      ivtv_cards_active);
 		spin_unlock(&ivtv_cards_lock);
 		return -ENOMEM;
@@ -964,9 +987,7 @@
 	itv->dev = dev;
 	itv->num = ivtv_cards_active++;
 	snprintf(itv->name, sizeof(itv->name) - 1, "ivtv%d", itv->num);
-	if (itv->num) {
-		printk(KERN_INFO "ivtv:  ======================  NEXT CARD  ======================\n");
-	}
+	IVTV_INFO("Initializing card #%d\n", itv->num);
 
 	spin_unlock(&ivtv_cards_lock);
 
@@ -982,6 +1003,8 @@
 
 	IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr);
 
+	mutex_lock(&itv->serialize_lock);
+
 	/* PCI Device Setup */
 	if ((retval = ivtv_setup_pci(itv, dev, pci_id)) != 0) {
 		if (retval == -EIO)
@@ -1032,22 +1055,6 @@
 		goto free_io;
 	}
 
-	while (--fw_retry_count > 0) {
-		/* load firmware */
-		if (ivtv_firmware_init(itv) == 0)
-			break;
-		if (fw_retry_count > 1)
-			IVTV_WARN("Retry loading firmware\n");
-	}
-	if (fw_retry_count == 0) {
-		IVTV_ERR("Error initializing firmware\n");
-		goto free_i2c;
-	}
-
-	/* Try and get firmware versions */
-	IVTV_DEBUG_INFO("Getting firmware version..\n");
-	ivtv_firmware_versions(itv);
-
 	/* Check yuv output filter table */
 	if (itv->has_cx23415) ivtv_yuv_filter_check(itv);
 
@@ -1135,43 +1142,22 @@
 	if (itv->options.radio > 0)
 		itv->v4l2_cap |= V4L2_CAP_RADIO;
 
-	if (itv->options.tuner > -1) {
+	if (itv->options.tuner > -1 && itv->tunerid == 0) {
 		struct tuner_setup setup;
 
 		setup.addr = ADDR_UNSET;
 		setup.type = itv->options.tuner;
 		setup.mode_mask = T_ANALOG_TV;  /* matches TV tuners */
-#ifdef HAVE_XC3028
-		setup.initmode = V4L2_TUNER_ANALOG_TV;
-		if (itv->options.tuner == TUNER_XCEIVE_XC3028) {
-			setup.gpio_write = ivtv_reset_tuner_gpio;
-			setup.gpio_priv = itv;
-		}
-#endif
 		ivtv_call_i2c_clients(itv, TUNER_SET_TYPE_ADDR, &setup);
 	}
 
-	vf.tuner = 0;
-	vf.type = V4L2_TUNER_ANALOG_TV;
-	vf.frequency = 6400; /* the tuner 'baseline' frequency */
-	if (itv->std & V4L2_STD_NTSC_M) {
-		/* Why on earth? */
-		vf.frequency = 1076;	/* ch. 4 67250*16/1000 */
-	}
-
 	/* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
 	   are not. */
 	itv->tuner_std = itv->std;
 
-	video_input = itv->active_input;
-	itv->active_input++;	/* Force update of input */
-	ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input);
-
-	/* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
-	   in one place. */
-	itv->std++;		/* Force full standard initialization */
-	itv->std_out = itv->std;
-	ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf);
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+		ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std);
+	}
 
 	retval = ivtv_streams_setup(itv);
 	if (retval) {
@@ -1179,11 +1165,6 @@
 		goto free_i2c;
 	}
 
-	if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) {
-		ivtv_init_mpeg_decoder(itv);
-	}
-	ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std);
-
 	IVTV_DEBUG_IRQ("Masking interrupts\n");
 	/* clear interrupt mask, effectively disabling interrupts */
 	ivtv_set_irq_mask(itv, 0xffffffff);
@@ -1195,26 +1176,8 @@
 		IVTV_ERR("Failed to register irq %d\n", retval);
 		goto free_streams;
 	}
-
-	/* On a cx23416 this seems to be able to enable DMA to the chip? */
-	if (!itv->has_cx23415)
-		write_reg_sync(0x03, IVTV_REG_DMACONTROL);
-
-	/* Default interrupts enabled. For the PVR350 this includes the
-	   decoder VSYNC interrupt, which is always on. It is not only used
-	   during decoding but also by the OSD.
-	   Some old PVR250 cards had a cx23415, so testing for that is too
-	   general. Instead test if the card has video output capability. */
-	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
-		ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC);
-	else
-		ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT);
-
-	if (itv->has_cx23415)
-		ivtv_set_osd_alpha(itv);
-
-	IVTV_INFO("Initialized %s, card #%d\n", itv->card_name, itv->num);
-
+	mutex_unlock(&itv->serialize_lock);
+	IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name);
 	return 0;
 
       free_irq:
@@ -1232,68 +1195,146 @@
 		release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
       free_workqueue:
 	destroy_workqueue(itv->irq_work_queues);
+	mutex_unlock(&itv->serialize_lock);
       err:
 	if (retval == 0)
 		retval = -ENODEV;
 	IVTV_ERR("Error %d on initialization\n", retval);
 
+	spin_lock(&ivtv_cards_lock);
 	kfree(ivtv_cards[ivtv_cards_active]);
 	ivtv_cards[ivtv_cards_active] = NULL;
+	spin_unlock(&ivtv_cards_lock);
 	return retval;
 }
 
+int ivtv_init_on_first_open(struct ivtv *itv)
+{
+	struct v4l2_frequency vf;
+	int fw_retry_count = 3;
+	int video_input;
+
+	if (test_bit(IVTV_F_I_FAILED, &itv->i_flags))
+		return -ENXIO;
+
+	if (test_and_set_bit(IVTV_F_I_INITED, &itv->i_flags))
+		return 0;
+
+	while (--fw_retry_count > 0) {
+		/* load firmware */
+		if (ivtv_firmware_init(itv) == 0)
+			break;
+		if (fw_retry_count > 1)
+			IVTV_WARN("Retry loading firmware\n");
+	}
+
+	if (fw_retry_count == 0) {
+		set_bit(IVTV_F_I_FAILED, &itv->i_flags);
+		return -ENXIO;
+	}
+
+	/* Try and get firmware versions */
+	IVTV_DEBUG_INFO("Getting firmware version..\n");
+	ivtv_firmware_versions(itv);
+
+	if (itv->card->hw_all & IVTV_HW_CX25840) {
+		struct v4l2_control ctrl;
+
+		/* CX25840_CID_ENABLE_PVR150_WORKAROUND */
+		ctrl.id = V4L2_CID_PRIVATE_BASE;
+		ctrl.value = itv->pvr150_workaround;
+		itv->video_dec_func(itv, VIDIOC_S_CTRL, &ctrl);
+	}
+
+	vf.tuner = 0;
+	vf.type = V4L2_TUNER_ANALOG_TV;
+	vf.frequency = 6400; /* the tuner 'baseline' frequency */
+
+	/* Set initial frequency. For PAL/SECAM broadcasts no
+	   'default' channel exists AFAIK. */
+	if (itv->std == V4L2_STD_NTSC_M_JP) {
+		vf.frequency = 1460;	/* ch. 1 91250*16/1000 */
+	}
+	else if (itv->std & V4L2_STD_NTSC_M) {
+		vf.frequency = 1076;	/* ch. 4 67250*16/1000 */
+	}
+
+	video_input = itv->active_input;
+	itv->active_input++;	/* Force update of input */
+	ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input);
+
+	/* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
+	   in one place. */
+	itv->std++;		/* Force full standard initialization */
+	itv->std_out = itv->std;
+	ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf);
+
+	if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) {
+		ivtv_init_mpeg_decoder(itv);
+	}
+	ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std);
+
+	/* On a cx23416 this seems to be able to enable DMA to the chip? */
+	if (!itv->has_cx23415)
+		write_reg_sync(0x03, IVTV_REG_DMACONTROL);
+
+	/* Default interrupts enabled. For the PVR350 this includes the
+	   decoder VSYNC interrupt, which is always on. It is not only used
+	   during decoding but also by the OSD.
+	   Some old PVR250 cards had a cx23415, so testing for that is too
+	   general. Instead test if the card has video output capability. */
+	if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+		ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT | IVTV_IRQ_DEC_VSYNC);
+		ivtv_set_osd_alpha(itv);
+	}
+	else
+		ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_INIT);
+	return 0;
+}
+
 static void ivtv_remove(struct pci_dev *pci_dev)
 {
 	struct ivtv *itv = pci_get_drvdata(pci_dev);
 
-	IVTV_DEBUG_INFO("Removing Card #%d.\n", itv->num);
+	IVTV_DEBUG_INFO("Removing Card #%d\n", itv->num);
 
-	/* Stop all captures */
-	IVTV_DEBUG_INFO(" Stopping all streams.\n");
-	if (atomic_read(&itv->capturing) > 0)
-		ivtv_stop_all_captures(itv);
+	if (test_bit(IVTV_F_I_INITED, &itv->i_flags)) {
+		/* Stop all captures */
+		IVTV_DEBUG_INFO("Stopping all streams\n");
+		if (atomic_read(&itv->capturing) > 0)
+			ivtv_stop_all_captures(itv);
 
-	/* Stop all decoding */
-	IVTV_DEBUG_INFO(" Stopping decoding.\n");
-	if (atomic_read(&itv->decoding) > 0) {
-		int type;
+		/* Stop all decoding */
+		IVTV_DEBUG_INFO("Stopping decoding\n");
+		if (atomic_read(&itv->decoding) > 0) {
+			int type;
 
-		if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
-			type = IVTV_DEC_STREAM_TYPE_YUV;
-		else
-			type = IVTV_DEC_STREAM_TYPE_MPG;
-		ivtv_stop_v4l2_decode_stream(&itv->streams[type],
-			VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
+			if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
+				type = IVTV_DEC_STREAM_TYPE_YUV;
+			else
+				type = IVTV_DEC_STREAM_TYPE_MPG;
+			ivtv_stop_v4l2_decode_stream(&itv->streams[type],
+				VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
+		}
+		ivtv_halt_firmware(itv);
 	}
 
 	/* Interrupts */
-	IVTV_DEBUG_INFO(" Disabling interrupts.\n");
 	ivtv_set_irq_mask(itv, 0xffffffff);
 	del_timer_sync(&itv->dma_timer);
 
 	/* Stop all Work Queues */
-	IVTV_DEBUG_INFO(" Stop Work Queues.\n");
 	flush_workqueue(itv->irq_work_queues);
 	destroy_workqueue(itv->irq_work_queues);
 
-	IVTV_DEBUG_INFO(" Stopping Firmware.\n");
-	ivtv_halt_firmware(itv);
-
-	IVTV_DEBUG_INFO(" Unregistering v4l devices.\n");
 	ivtv_streams_cleanup(itv);
-	IVTV_DEBUG_INFO(" Freeing dma resources.\n");
 	ivtv_udma_free(itv);
 
 	exit_ivtv_i2c(itv);
 
-	IVTV_DEBUG_INFO(" Releasing irq.\n");
 	free_irq(itv->dev->irq, (void *)itv);
+	ivtv_iounmap(itv);
 
-	if (itv->dev) {
-		ivtv_iounmap(itv);
-	}
-
-	IVTV_DEBUG_INFO(" Releasing mem.\n");
 	release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
 	release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
 	if (itv->has_cx23415)
@@ -1314,28 +1355,27 @@
 
 static int module_start(void)
 {
-	printk(KERN_INFO "ivtv:  ==================== START INIT IVTV ====================\n");
-	printk(KERN_INFO "ivtv:  version %s (" VERMAGIC_STRING ") loading\n", IVTV_VERSION);
+	printk(KERN_INFO "ivtv:  Start initialization, version %s\n", IVTV_VERSION);
 
 	memset(ivtv_cards, 0, sizeof(ivtv_cards));
 
 	/* Validate parameters */
 	if (ivtv_first_minor < 0 || ivtv_first_minor >= IVTV_MAX_CARDS) {
-		printk(KERN_ERR "ivtv:  ivtv_first_minor must be between 0 and %d. Exiting...\n",
+		printk(KERN_ERR "ivtv:  Exiting, ivtv_first_minor must be between 0 and %d\n",
 		     IVTV_MAX_CARDS - 1);
 		return -1;
 	}
 
-	if (ivtv_debug < 0 || ivtv_debug > 511) {
+	if (ivtv_debug < 0 || ivtv_debug > 2047) {
 		ivtv_debug = 0;
-		printk(KERN_INFO "ivtv:  debug value must be >= 0 and <= 511!\n");
+		printk(KERN_INFO "ivtv:  Debug value must be >= 0 and <= 2047\n");
 	}
 
 	if (pci_register_driver(&ivtv_pci_driver)) {
 		printk(KERN_ERR "ivtv:  Error detecting PCI card\n");
 		return -ENODEV;
 	}
-	printk(KERN_INFO "ivtv:  ====================  END INIT IVTV  ====================\n");
+	printk(KERN_INFO "ivtv:  End initialization\n");
 	return 0;
 }
 
@@ -1345,6 +1385,7 @@
 
 	pci_unregister_driver(&ivtv_pci_driver);
 
+	spin_lock(&ivtv_cards_lock);
 	for (i = 0; i < ivtv_cards_active; i++) {
 		if (ivtv_cards[i] == NULL)
 			continue;
@@ -1353,13 +1394,15 @@
 		}
 		kfree(ivtv_cards[i]);
 	}
+	spin_unlock(&ivtv_cards_lock);
 }
 
-/* Note: These symbols are exported because they are used by the ivtv-fb
+/* Note: These symbols are exported because they are used by the ivtvfb
    framebuffer module and an infrared module for the IR-blaster. */
 EXPORT_SYMBOL(ivtv_set_irq_mask);
 EXPORT_SYMBOL(ivtv_cards_active);
 EXPORT_SYMBOL(ivtv_cards);
+EXPORT_SYMBOL(ivtv_cards_lock);
 EXPORT_SYMBOL(ivtv_api);
 EXPORT_SYMBOL(ivtv_vapi);
 EXPORT_SYMBOL(ivtv_vapi_result);
@@ -1370,6 +1413,7 @@
 EXPORT_SYMBOL(ivtv_udma_unmap);
 EXPORT_SYMBOL(ivtv_udma_alloc);
 EXPORT_SYMBOL(ivtv_udma_prepare);
+EXPORT_SYMBOL(ivtv_init_on_first_open);
 
 module_init(module_start);
 module_exit(module_cleanup);
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index e6e56f1..3bda1df 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -38,7 +38,6 @@
 
 #include <linux/version.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
@@ -63,77 +62,20 @@
 #include <media/tuner.h>
 #include <media/cx2341x.h>
 
-/* #define HAVE_XC3028 1 */
+#include <linux/ivtv.h>
 
-#include <media/ivtv.h>
 
+/* Memory layout */
 #define IVTV_ENCODER_OFFSET	0x00000000
-#define IVTV_ENCODER_SIZE	0x00800000	/* Last half isn't needed 0x01000000 */
-
+#define IVTV_ENCODER_SIZE	0x00800000	/* Total size is 0x01000000, but only first half is used */
 #define IVTV_DECODER_OFFSET	0x01000000
-#define IVTV_DECODER_SIZE	0x00800000	/* Last half isn't needed 0x01000000 */
-
+#define IVTV_DECODER_SIZE	0x00800000	/* Total size is 0x01000000, but only first half is used */
 #define IVTV_REG_OFFSET 	0x02000000
 #define IVTV_REG_SIZE		0x00010000
 
-/* Buffers on hardware offsets */
-#define IVTV_YUV_BUFFER_OFFSET    0x001a8600	/* First YUV Buffer */
-#define IVTV_YUV_BUFFER_OFFSET_1  0x00240400	/* Second YUV Buffer */
-#define IVTV_YUV_BUFFER_OFFSET_2  0x002d8200	/* Third YUV Buffer */
-#define IVTV_YUV_BUFFER_OFFSET_3  0x00370000	/* Fourth YUV Buffer */
-#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400	/* Offset to UV Buffer */
-
-/* Offset to filter table in firmware */
-#define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8
-#define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358
-
-extern const u32 yuv_offset[4];
-
-/* Maximum ivtv driver instances.
-   Based on 6 PVR500s each with two PVR15s...
-   TODO: make this dynamic. I believe it is only a global in order to support
-    ivtv-fb. There must be a better way to do that. */
-#define IVTV_MAX_CARDS 12
-
-/* Supported cards */
-#define IVTV_CARD_PVR_250 	      0	/* WinTV PVR 250 */
-#define IVTV_CARD_PVR_350 	      1	/* encoder, decoder, tv-out */
-#define IVTV_CARD_PVR_150 	      2	/* WinTV PVR 150 and PVR 500 (really just two
-					   PVR150s on one PCI board) */
-#define IVTV_CARD_M179    	      3	/* AVerMedia M179 (encoder only) */
-#define IVTV_CARD_MPG600  	      4	/* Kuroutoshikou ITVC16-STVLP/YUAN MPG600, encoder only */
-#define IVTV_CARD_MPG160  	      5	/* Kuroutoshikou ITVC15-STVLP/YUAN MPG160
-					   cx23415 based, but does not have tv-out */
-#define IVTV_CARD_PG600 	      6	/* YUAN PG600/DIAMONDMM PVR-550 based on the CX Falcon 2 */
-#define IVTV_CARD_AVC2410 	      7	/* Adaptec AVC-2410 */
-#define IVTV_CARD_AVC2010 	      8	/* Adaptec AVD-2010 (No Tuner) */
-#define IVTV_CARD_TG5000TV   	      9 /* NAGASE TRANSGEAR 5000TV, encoder only */
-#define IVTV_CARD_VA2000MAX_SNT6     10 /* VA2000MAX-STN6 */
-#define IVTV_CARD_CX23416GYC 	     11 /* Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */
-#define IVTV_CARD_GV_MVPRX   	     12 /* I/O Data GV-MVP/RX, RX2, RX2W */
-#define IVTV_CARD_GV_MVPRX2E 	     13 /* I/O Data GV-MVP/RX2E */
-#define IVTV_CARD_GOTVIEW_PCI_DVD    14	/* GotView PCI DVD */
-#define IVTV_CARD_GOTVIEW_PCI_DVD2   15	/* GotView PCI DVD2 */
-#define IVTV_CARD_YUAN_MPC622        16	/* Yuan MPC622 miniPCI */
-#define IVTV_CARD_DCTMTVP1 	     17 /* DIGITAL COWBOY DCT-MTVP1 */
-#ifdef HAVE_XC3028
-#define IVTV_CARD_PG600V2	     18 /* Yuan PG600V2/GotView PCI DVD Lite/Club3D ZAP-TV1x01 */
-#define IVTV_CARD_LAST 		     18
-#else
-#define IVTV_CARD_LAST 		     17
-#endif
-
-/* Variants of existing cards but with the same PCI IDs. The driver
-   detects these based on other device information.
-   These cards must always come last.
-   New cards must be inserted above, and the indices of the cards below
-   must be adjusted accordingly. */
-
-/* PVR-350 V1 (uses saa7114) */
-#define IVTV_CARD_PVR_350_V1 	     (IVTV_CARD_LAST+1)
-/* 2 variants of Kuroutoshikou CX23416GYC-STVLP (Yuan MPG600GR OEM) */
-#define IVTV_CARD_CX23416GYC_NOGR    (IVTV_CARD_LAST+2)
-#define IVTV_CARD_CX23416GYC_NOGRYCS (IVTV_CARD_LAST+3)
+/* Maximum ivtv driver instances. Some people have a huge number of
+   capture cards, so set this to a high value. */
+#define IVTV_MAX_CARDS 32
 
 #define IVTV_ENC_STREAM_TYPE_MPG  0
 #define IVTV_ENC_STREAM_TYPE_YUV  1
@@ -146,70 +88,8 @@
 #define IVTV_DEC_STREAM_TYPE_YUV  8
 #define IVTV_MAX_STREAMS	  9
 
-#define IVTV_V4L2_DEC_MPG_OFFSET  16	/* offset from 0 to register decoder mpg v4l2 minors on */
-#define IVTV_V4L2_ENC_PCM_OFFSET  24	/* offset from 0 to register pcm v4l2 minors on */
-#define IVTV_V4L2_ENC_YUV_OFFSET  32	/* offset from 0 to register yuv v4l2 minors on */
-#define IVTV_V4L2_DEC_YUV_OFFSET  48	/* offset from 0 to register decoder yuv v4l2 minors on */
-#define IVTV_V4L2_DEC_VBI_OFFSET   8	/* offset from 0 to register decoder vbi input v4l2 minors on */
-#define IVTV_V4L2_DEC_VOUT_OFFSET 16	/* offset from 0 to register vbi output v4l2 minors on */
-
-#define IVTV_ENC_MEM_START 0x00000000
-#define IVTV_DEC_MEM_START 0x01000000
-
-/* system vendor and device IDs */
-#define PCI_VENDOR_ID_ICOMP  0x4444
-#define PCI_DEVICE_ID_IVTV15 0x0803
-#define PCI_DEVICE_ID_IVTV16 0x0016
-
-/* subsystem vendor ID */
-#define IVTV_PCI_ID_HAUPPAUGE 		0x0070
-#define IVTV_PCI_ID_HAUPPAUGE_ALT1 	0x0270
-#define IVTV_PCI_ID_HAUPPAUGE_ALT2 	0x4070
-#define IVTV_PCI_ID_ADAPTEC 		0x9005
-#define IVTV_PCI_ID_AVERMEDIA 		0x1461
-#define IVTV_PCI_ID_YUAN1		0x12ab
-#define IVTV_PCI_ID_YUAN2 		0xff01
-#define IVTV_PCI_ID_YUAN3 		0xffab
-#define IVTV_PCI_ID_YUAN4 		0xfbab
-#define IVTV_PCI_ID_DIAMONDMM 		0xff92
-#define IVTV_PCI_ID_IODATA 		0x10fc
-#define IVTV_PCI_ID_MELCO 		0x1154
-#define IVTV_PCI_ID_GOTVIEW1		0xffac
-#define IVTV_PCI_ID_GOTVIEW2 		0xffad
-
-/* Decoder Buffer hardware size on Chip */
-#define IVTV_DEC_MAX_BUF        0x00100000	/* max bytes in decoder buffer */
-#define IVTV_DEC_MIN_BUF        0x00010000	/* min bytes in dec buffer */
-
-/* ======================================================================== */
-/* ========================== START USER SETTABLE DMA VARIABLES =========== */
-/* ======================================================================== */
-
 #define IVTV_DMA_SG_OSD_ENT	(2883584/PAGE_SIZE)	/* sg entities */
 
-/* DMA Buffers, Default size in MB allocated */
-#define IVTV_DEFAULT_ENC_MPG_BUFFERS 4
-#define IVTV_DEFAULT_ENC_YUV_BUFFERS 2
-#define IVTV_DEFAULT_ENC_VBI_BUFFERS 1
-#define IVTV_DEFAULT_ENC_PCM_BUFFERS 1
-#define IVTV_DEFAULT_DEC_MPG_BUFFERS 1
-#define IVTV_DEFAULT_DEC_YUV_BUFFERS 1
-#define IVTV_DEFAULT_DEC_VBI_BUFFERS 1
-
-/* ======================================================================== */
-/* ========================== END USER SETTABLE DMA VARIABLES ============= */
-/* ======================================================================== */
-
-/* Decoder Status Register */
-#define IVTV_DMA_ERR_LIST 	0x00000010
-#define IVTV_DMA_ERR_WRITE 	0x00000008
-#define IVTV_DMA_ERR_READ 	0x00000004
-#define IVTV_DMA_SUCCESS_WRITE 	0x00000002
-#define IVTV_DMA_SUCCESS_READ 	0x00000001
-#define IVTV_DMA_READ_ERR 	(IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_READ)
-#define IVTV_DMA_WRITE_ERR 	(IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE)
-#define IVTV_DMA_ERR 		(IVTV_DMA_ERR_LIST | IVTV_DMA_ERR_WRITE | IVTV_DMA_ERR_READ)
-
 /* DMA Registers */
 #define IVTV_REG_DMAXFER 	(0x0000)
 #define IVTV_REG_DMASTATUS 	(0x0004)
@@ -232,42 +112,24 @@
 #define IVTV_REG_VPU 			(0x9058)
 #define IVTV_REG_APU 			(0xA064)
 
-#define IVTV_IRQ_ENC_START_CAP		(0x1 << 31)
-#define IVTV_IRQ_ENC_EOS		(0x1 << 30)
-#define IVTV_IRQ_ENC_VBI_CAP		(0x1 << 29)
-#define IVTV_IRQ_ENC_VIM_RST		(0x1 << 28)
-#define IVTV_IRQ_ENC_DMA_COMPLETE	(0x1 << 27)
-#define IVTV_IRQ_ENC_PIO_COMPLETE	(0x1 << 25)
-#define IVTV_IRQ_DEC_AUD_MODE_CHG	(0x1 << 24)
-#define IVTV_IRQ_DEC_DATA_REQ		(0x1 << 22)
-#define IVTV_IRQ_DEC_DMA_COMPLETE	(0x1 << 20)
-#define IVTV_IRQ_DEC_VBI_RE_INSERT	(0x1 << 19)
-#define IVTV_IRQ_DMA_ERR		(0x1 << 18)
-#define IVTV_IRQ_DMA_WRITE		(0x1 << 17)
-#define IVTV_IRQ_DMA_READ		(0x1 << 16)
-#define IVTV_IRQ_DEC_VSYNC		(0x1 << 10)
-
-/* IRQ Masks */
-#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\
-		IVTV_IRQ_DMA_READ|IVTV_IRQ_ENC_PIO_COMPLETE)
-
-#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS)
-#define IVTV_IRQ_MASK_DECODE  (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG)
-
 /* i2c stuff */
 #define I2C_CLIENTS_MAX 16
 
 /* debugging */
+extern int ivtv_debug;
 
-#define IVTV_DBGFLG_WARN  (1 << 0)
-#define IVTV_DBGFLG_INFO  (1 << 1)
-#define IVTV_DBGFLG_API   (1 << 2)
-#define IVTV_DBGFLG_DMA   (1 << 3)
-#define IVTV_DBGFLG_IOCTL (1 << 4)
-#define IVTV_DBGFLG_I2C   (1 << 5)
-#define IVTV_DBGFLG_IRQ   (1 << 6)
-#define IVTV_DBGFLG_DEC   (1 << 7)
-#define IVTV_DBGFLG_YUV   (1 << 8)
+#define IVTV_DBGFLG_WARN    (1 << 0)
+#define IVTV_DBGFLG_INFO    (1 << 1)
+#define IVTV_DBGFLG_MB      (1 << 2)
+#define IVTV_DBGFLG_IOCTL   (1 << 3)
+#define IVTV_DBGFLG_FILE    (1 << 4)
+#define IVTV_DBGFLG_DMA     (1 << 5)
+#define IVTV_DBGFLG_IRQ     (1 << 6)
+#define IVTV_DBGFLG_DEC     (1 << 7)
+#define IVTV_DBGFLG_YUV     (1 << 8)
+#define IVTV_DBGFLG_I2C     (1 << 9)
+/* Flag to turn on high volume debugging */
+#define IVTV_DBGFLG_HIGHVOL (1 << 10)
 
 /* NOTE: extra space before comma in 'itv->num , ## args' is required for
    gcc-2.95, otherwise it won't compile. */
@@ -276,43 +138,37 @@
 		if ((x) & ivtv_debug) \
 			printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \
 	} while (0)
-#define IVTV_DEBUG_WARN(fmt, args...)  IVTV_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args)
-#define IVTV_DEBUG_INFO(fmt, args...)  IVTV_DEBUG(IVTV_DBGFLG_INFO, "info",fmt , ## args)
-#define IVTV_DEBUG_API(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args)
-#define IVTV_DEBUG_DMA(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args)
+#define IVTV_DEBUG_WARN(fmt, args...)  IVTV_DEBUG(IVTV_DBGFLG_WARN,  "warn",  fmt , ## args)
+#define IVTV_DEBUG_INFO(fmt, args...)  IVTV_DEBUG(IVTV_DBGFLG_INFO,  "info",  fmt , ## args)
+#define IVTV_DEBUG_MB(fmt, args...)    IVTV_DEBUG(IVTV_DBGFLG_MB,    "mb",    fmt , ## args)
+#define IVTV_DEBUG_DMA(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_DMA,   "dma",   fmt , ## args)
 #define IVTV_DEBUG_IOCTL(fmt, args...) IVTV_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args)
-#define IVTV_DEBUG_I2C(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args)
-#define IVTV_DEBUG_IRQ(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args)
-#define IVTV_DEBUG_DEC(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
-#define IVTV_DEBUG_YUV(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
+#define IVTV_DEBUG_FILE(fmt, args...)  IVTV_DEBUG(IVTV_DBGFLG_FILE,  "file",  fmt , ## args)
+#define IVTV_DEBUG_I2C(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_I2C,   "i2c",   fmt , ## args)
+#define IVTV_DEBUG_IRQ(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_IRQ,   "irq",   fmt , ## args)
+#define IVTV_DEBUG_DEC(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_DEC,   "dec",   fmt , ## args)
+#define IVTV_DEBUG_YUV(fmt, args...)   IVTV_DEBUG(IVTV_DBGFLG_YUV,   "yuv",   fmt , ## args)
 
-#define IVTV_FB_DEBUG(x, type, fmt, args...) \
+#define IVTV_DEBUG_HIGH_VOL(x, type, fmt, args...) \
 	do { \
-		if ((x) & ivtv_debug) \
-			printk(KERN_INFO "ivtv%d-fb " type ": " fmt, itv->num , ## args); \
+		if (((x) & ivtv_debug) && (ivtv_debug & IVTV_DBGFLG_HIGHVOL)) \
+			printk(KERN_INFO "ivtv%d " type ": " fmt, itv->num , ## args); \
 	} while (0)
-#define IVTV_FB_DEBUG_WARN(fmt, args...)  IVTV_FB_DEBUG(IVTV_DBGFLG_WARN, "warning", fmt , ## args)
-#define IVTV_FB_DEBUG_INFO(fmt, args...)  IVTV_FB_DEBUG(IVTV_DBGFLG_INFO, "info", fmt , ## args)
-#define IVTV_FB_DEBUG_API(fmt, args...)   IVTV_FB_DEBUG(IVTV_DBGFLG_API, "api", fmt , ## args)
-#define IVTV_FB_DEBUG_DMA(fmt, args...)   IVTV_FB_DEBUG(IVTV_DBGFLG_DMA, "dma", fmt , ## args)
-#define IVTV_FB_DEBUG_IOCTL(fmt, args...) IVTV_FB_DEBUG(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args)
-#define IVTV_FB_DEBUG_I2C(fmt, args...)   IVTV_FB_DEBUG(IVTV_DBGFLG_I2C, "i2c", fmt , ## args)
-#define IVTV_FB_DEBUG_IRQ(fmt, args...)   IVTV_FB_DEBUG(IVTV_DBGFLG_IRQ, "irq", fmt , ## args)
-#define IVTV_FB_DEBUG_DEC(fmt, args...)   IVTV_FB_DEBUG(IVTV_DBGFLG_DEC, "dec", fmt , ## args)
-#define IVTV_FB_DEBUG_YUV(fmt, args...)   IVTV_FB_DEBUG(IVTV_DBGFLG_YUV, "yuv", fmt , ## args)
+#define IVTV_DEBUG_HI_WARN(fmt, args...)  IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_WARN,  "warn",  fmt , ## args)
+#define IVTV_DEBUG_HI_INFO(fmt, args...)  IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_INFO,  "info",  fmt , ## args)
+#define IVTV_DEBUG_HI_MB(fmt, args...)    IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_MB,    "mb",    fmt , ## args)
+#define IVTV_DEBUG_HI_DMA(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DMA,   "dma",   fmt , ## args)
+#define IVTV_DEBUG_HI_IOCTL(fmt, args...) IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define IVTV_DEBUG_HI_FILE(fmt, args...)  IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_FILE,  "file",  fmt , ## args)
+#define IVTV_DEBUG_HI_I2C(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_I2C,   "i2c",   fmt , ## args)
+#define IVTV_DEBUG_HI_IRQ(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_IRQ,   "irq",   fmt , ## args)
+#define IVTV_DEBUG_HI_DEC(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_DEC,   "dec",   fmt , ## args)
+#define IVTV_DEBUG_HI_YUV(fmt, args...)   IVTV_DEBUG_HIGH_VOL(IVTV_DBGFLG_YUV,   "yuv",   fmt , ## args)
 
 /* Standard kernel messages */
 #define IVTV_ERR(fmt, args...)      printk(KERN_ERR  "ivtv%d: " fmt, itv->num , ## args)
 #define IVTV_WARN(fmt, args...)     printk(KERN_WARNING "ivtv%d: " fmt, itv->num , ## args)
 #define IVTV_INFO(fmt, args...)     printk(KERN_INFO "ivtv%d: " fmt, itv->num , ## args)
-#define IVTV_FB_ERR(fmt, args...)   printk(KERN_ERR  "ivtv%d-fb: " fmt, itv->num , ## args)
-#define IVTV_FB_WARN(fmt, args...)  printk(KERN_WARNING  "ivtv%d-fb: " fmt, itv->num , ## args)
-#define IVTV_FB_INFO(fmt, args...)  printk(KERN_INFO "ivtv%d-fb: " fmt, itv->num , ## args)
-
-/* Values for IVTV_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */
-#define MPEG_FRAME_TYPE_IFRAME 1
-#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3
-#define MPEG_FRAME_TYPE_ALL 7
 
 /* output modes (cx23415 only) */
 #define OUT_NONE        0
@@ -323,22 +179,14 @@
 
 #define IVTV_MAX_PGM_INDEX (400)
 
-extern int ivtv_debug;
-
-
 struct ivtv_options {
-	int megabytes[IVTV_MAX_STREAMS]; /* Size in megabytes of each stream */
-	int cardtype;		/* force card type on load */
-	int tuner;		/* set tuner on load */
-	int radio;		/* enable/disable radio */
-	int newi2c;		/* New I2C algorithm */
+	int kilobytes[IVTV_MAX_STREAMS];        /* size in kilobytes of each stream */
+	int cardtype;				/* force card type on load */
+	int tuner;				/* set tuner on load */
+	int radio;				/* enable/disable radio */
+	int newi2c;				/* new I2C algorithm */
 };
 
-#define IVTV_MBOX_DMA_START 6
-#define IVTV_MBOX_DMA_END 8
-#define IVTV_MBOX_DMA 9
-#define IVTV_MBOX_FIELD_DISPLAYED 8
-
 /* ivtv-specific mailbox template */
 struct ivtv_mailbox {
 	u32 flags;
@@ -362,7 +210,7 @@
 };
 
 /* per-buffer bit flags */
-#define IVTV_F_B_NEED_BUF_SWAP  0	/* this buffer should be byte swapped */
+#define IVTV_F_B_NEED_BUF_SWAP  (1 << 0)	/* this buffer should be byte swapped */
 
 /* per-stream, s_flags */
 #define IVTV_F_S_DMA_PENDING	0	/* this stream has pending DMA */
@@ -383,23 +231,25 @@
 #define IVTV_F_I_DMA		   0 	/* DMA in progress */
 #define IVTV_F_I_UDMA		   1 	/* UDMA in progress */
 #define IVTV_F_I_UDMA_PENDING	   2 	/* UDMA pending */
-#define IVTV_F_I_SPEED_CHANGE	   3 	/* A speed change is in progress */
-#define IVTV_F_I_EOS		   4 	/* End of encoder stream reached */
-#define IVTV_F_I_RADIO_USER	   5 	/* The radio tuner is selected */
-#define IVTV_F_I_DIG_RST	   6 	/* Reset digitizer */
+#define IVTV_F_I_SPEED_CHANGE	   3 	/* a speed change is in progress */
+#define IVTV_F_I_EOS		   4 	/* end of encoder stream reached */
+#define IVTV_F_I_RADIO_USER	   5 	/* the radio tuner is selected */
+#define IVTV_F_I_DIG_RST	   6 	/* reset digitizer */
 #define IVTV_F_I_DEC_YUV	   7 	/* YUV instead of MPG is being decoded */
-#define IVTV_F_I_ENC_VBI	   8 	/* VBI DMA */
 #define IVTV_F_I_UPDATE_CC	   9  	/* CC should be updated */
 #define IVTV_F_I_UPDATE_WSS	   10 	/* WSS should be updated */
 #define IVTV_F_I_UPDATE_VPS	   11 	/* VPS should be updated */
 #define IVTV_F_I_DECODING_YUV	   12 	/* this stream is YUV frame decoding */
 #define IVTV_F_I_ENC_PAUSED	   13 	/* the encoder is paused */
 #define IVTV_F_I_VALID_DEC_TIMINGS 14 	/* last_dec_timing is valid */
-#define IVTV_F_I_HAVE_WORK  	   15	/* Used in the interrupt handler: there is work to be done */
+#define IVTV_F_I_HAVE_WORK  	   15	/* used in the interrupt handler: there is work to be done */
 #define IVTV_F_I_WORK_HANDLER_VBI  16	/* there is work to be done for VBI */
 #define IVTV_F_I_WORK_HANDLER_YUV  17	/* there is work to be done for YUV */
 #define IVTV_F_I_WORK_HANDLER_PIO  18	/* there is work to be done for PIO */
 #define IVTV_F_I_PIO		   19	/* PIO in progress */
+#define IVTV_F_I_DEC_PAUSED	   20 	/* the decoder is paused */
+#define IVTV_F_I_INITED		   21 	/* set after first open */
+#define IVTV_F_I_FAILED		   22 	/* set if first open failed */
 
 /* Event notifications */
 #define IVTV_F_I_EV_DEC_STOPPED	   28	/* decoder stopped event */
@@ -408,7 +258,7 @@
 #define IVTV_F_I_EV_VSYNC_ENABLED  31 	/* VSYNC event enabled */
 
 /* Scatter-Gather array element, used in DMA transfers */
-struct ivtv_SG_element {
+struct ivtv_sg_element {
 	u32 src;
 	u32 dst;
 	u32 size;
@@ -418,9 +268,11 @@
 	struct mutex lock;
 	int page_count;
 	struct page *map[IVTV_DMA_SG_OSD_ENT];
+	/* Needed when dealing with highmem userspace buffers */
+	struct page *bouncemap[IVTV_DMA_SG_OSD_ENT];
 
 	/* Base Dev SG Array for cx23415/6 */
-	struct ivtv_SG_element SGarray[IVTV_DMA_SG_OSD_ENT];
+	struct ivtv_sg_element SGarray[IVTV_DMA_SG_OSD_ENT];
 	dma_addr_t SG_handle;
 	int SG_length;
 
@@ -440,21 +292,21 @@
 struct ivtv_buffer {
 	struct list_head list;
 	dma_addr_t dma_handle;
-	unsigned long b_flags;
+	unsigned short b_flags;
+	unsigned short dma_xfer_cnt;
 	char *buf;
-
 	u32 bytesused;
 	u32 readpos;
 };
 
 struct ivtv_queue {
-	struct list_head list;
-	u32 buffers;
-	u32 length;
-	u32 bytesused;
+	struct list_head list;          /* the list of buffers in this queue */
+	u32 buffers;                    /* number of buffers in this queue */
+	u32 length;                     /* total number of bytes of available buffer space */
+	u32 bytesused;                  /* total number of bytes used in this queue */
 };
 
-struct ivtv;	/* forward reference */
+struct ivtv;				/* forward reference */
 
 struct ivtv_stream {
 	/* These first four fields are always set, even if the stream
@@ -465,11 +317,13 @@
 	int type;			/* stream type */
 
 	u32 id;
-	spinlock_t qlock; 	/* locks access to the queues */
-	unsigned long s_flags;	/* status flags, see above */
-	int dma;		/* can be PCI_DMA_TODEVICE,
-				   PCI_DMA_FROMDEVICE or
-				   PCI_DMA_NONE */
+	spinlock_t qlock; 		/* locks access to the queues */
+	unsigned long s_flags;		/* status flags, see above */
+	int dma;			/* can be PCI_DMA_TODEVICE, PCI_DMA_FROMDEVICE or PCI_DMA_NONE */
+	u32 pending_offset;
+	u32 pending_backup;
+	u64 pending_pts;
+
 	u32 dma_offset;
 	u32 dma_backup;
 	u64 dma_pts;
@@ -490,47 +344,53 @@
 	struct ivtv_queue q_dma;	/* waiting for DMA */
 	struct ivtv_queue q_predma;	/* waiting for DMA */
 
+	/* DMA xfer counter, buffers belonging to the same DMA
+	   xfer will have the same dma_xfer_cnt. */
+	u16 dma_xfer_cnt;
+
 	/* Base Dev SG Array for cx23415/6 */
-	struct ivtv_SG_element *SGarray;
-	struct ivtv_SG_element *PIOarray;
-	dma_addr_t SG_handle;
-	int SG_length;
+	struct ivtv_sg_element *sg_pending;
+	struct ivtv_sg_element *sg_processing;
+	struct ivtv_sg_element *sg_dma;
+	dma_addr_t sg_handle;
+	int sg_pending_size;
+	int sg_processing_size;
+	int sg_processed;
 
 	/* SG List of Buffers */
 	struct scatterlist *SGlist;
 };
 
 struct ivtv_open_id {
-	u32 open_id;
-	int type;
-	enum v4l2_priority prio;
+	u32 open_id;                    /* unique ID for this file descriptor */
+	int type;                       /* stream type */
+	int yuv_frames;                 /* 1: started OUT_UDMA_YUV output mode */
+	enum v4l2_priority prio;        /* priority */
 	struct ivtv *itv;
 };
 
-#define IVTV_YUV_UPDATE_HORIZONTAL  0x01
-#define IVTV_YUV_UPDATE_VERTICAL    0x02
-
 struct yuv_frame_info
 {
 	u32 update;
-	int src_x;
-	int src_y;
-	unsigned int src_w;
-	unsigned int src_h;
-	int dst_x;
-	int dst_y;
-	unsigned int dst_w;
-	unsigned int dst_h;
-	int pan_x;
-	int pan_y;
+	s32 src_x;
+	s32 src_y;
+	u32 src_w;
+	u32 src_h;
+	s32 dst_x;
+	s32 dst_y;
+	u32 dst_w;
+	u32 dst_h;
+	s32 pan_x;
+	s32 pan_y;
 	u32 vis_w;
 	u32 vis_h;
 	u32 interlaced_y;
 	u32 interlaced_uv;
-	int tru_x;
+	s32 tru_x;
 	u32 tru_w;
 	u32 tru_h;
 	u32 offset_y;
+	s32 lace_mode;
 };
 
 #define IVTV_YUV_MODE_INTERLACED	0x00
@@ -603,7 +463,6 @@
 	int decode_height;
 
 	int frame_interlaced;
-	int frame_interlaced_last;
 
 	int lace_mode;
 	int lace_threshold;
@@ -614,6 +473,11 @@
 
 	u32 yuv_forced_update;
 	int update_frame;
+
+	int sync_field[4];  /* Field to sync on */
+	int field_delay[4]; /* Flag to extend duration of previous frame */
+	u8 fields_lapsed;   /* Counter used when delaying a frame */
+
 	struct yuv_frame_info new_frame_info[4];
 	struct yuv_frame_info old_frame_info;
 	struct yuv_frame_info old_frame_info_args;
@@ -625,38 +489,61 @@
 #define IVTV_VBI_FRAMES 32
 
 /* VBI data */
-struct vbi_info {
-	u32 dec_start;
-	u32 enc_start, enc_size;
-	int fpi;
-	u32 frame;
-	u32 dma_offset;
-	u8 cc_data_odd[256];
-	u8 cc_data_even[256];
-	int cc_pos;
-	u8 cc_no_update;
-	u8 vps[5];
-	u8 vps_found;
-	int wss;
-	u8 wss_found;
-	u8 wss_no_update;
-	u32 raw_decoder_line_size;
-	u8 raw_decoder_sav_odd_field;
-	u8 raw_decoder_sav_even_field;
-	u32 sliced_decoder_line_size;
-	u8 sliced_decoder_sav_odd_field;
-	u8 sliced_decoder_sav_even_field;
-	struct v4l2_format in;
-	/* convenience pointer to sliced struct in vbi_in union */
-	struct v4l2_sliced_vbi_format *sliced_in;
-	u32 service_set_in;
-	u32 service_set_out;
-	int insert_mpeg;
+struct vbi_cc {
+	u8 odd[2];	/* two-byte payload of odd field */
+	u8 even[2];	/* two-byte payload of even field */;
+};
 
-	/* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
-	   One for /dev/vbi0 and one for /dev/vbi8 */
-	struct v4l2_sliced_vbi_data sliced_data[36];
-	struct v4l2_sliced_vbi_data sliced_dec_data[36];
+struct vbi_vps {
+	u8 data[5];	/* five-byte VPS payload */
+};
+
+struct vbi_info {
+	/* VBI general data, does not change during streaming */
+
+	u32 raw_decoder_line_size;              /* raw VBI line size from digitizer */
+	u8 raw_decoder_sav_odd_field;           /* raw VBI Start Active Video digitizer code of odd field */
+	u8 raw_decoder_sav_even_field;          /* raw VBI Start Active Video digitizer code of even field */
+	u32 sliced_decoder_line_size;           /* sliced VBI line size from digitizer */
+	u8 sliced_decoder_sav_odd_field;        /* sliced VBI Start Active Video digitizer code of odd field */
+	u8 sliced_decoder_sav_even_field;       /* sliced VBI Start Active Video digitizer code of even field */
+
+	u32 start[2];				/* start of first VBI line in the odd/even fields */
+	u32 count;				/* number of VBI lines per field */
+	u32 raw_size;				/* size of raw VBI line from the digitizer */
+	u32 sliced_size;			/* size of sliced VBI line from the digitizer */
+
+	u32 dec_start;				/* start in decoder memory of VBI re-insertion buffers */
+	u32 enc_start;				/* start in encoder memory of VBI capture buffers */
+	u32 enc_size;				/* size of VBI capture area */
+	int fpi;				/* number of VBI frames per interrupt */
+
+	struct v4l2_format in;			/* current VBI capture format */
+	struct v4l2_sliced_vbi_format *sliced_in; /* convenience pointer to sliced struct in vbi.in union */
+	int insert_mpeg;			/* if non-zero, then embed VBI data in MPEG stream */
+
+	/* Raw VBI compatibility hack */
+
+	u32 frame; 				/* frame counter hack needed for backwards compatibility
+						   of old VBI software */
+
+	/* Sliced VBI output data */
+
+	struct vbi_cc cc_payload[256];		/* sliced VBI CC payload array: it is an array to
+						   prevent dropping CC data if they couldn't be
+						   processed fast enough */
+	int cc_payload_idx;			/* index in cc_payload */
+	u8 cc_missing_cnt;			/* counts number of frames without CC for passthrough mode */
+	int wss_payload;			/* sliced VBI WSS payload */
+	u8 wss_missing_cnt;			/* counts number of frames without WSS for passthrough mode */
+	struct vbi_vps vps_payload;		/* sliced VBI VPS payload */
+
+	/* Sliced VBI capture data */
+
+	struct v4l2_sliced_vbi_data sliced_data[36];	/* sliced VBI storage for VBI encoder stream */
+	struct v4l2_sliced_vbi_data sliced_dec_data[36];/* sliced VBI storage for VBI decoder stream */
+
+	/* VBI Embedding data */
 
 	/* Buffer for VBI data inserted into MPEG stream.
 	   The first byte is a dummy byte that's never used.
@@ -673,12 +560,9 @@
 	   This pointer array will allocate 2049 bytes to store each VBI frame. */
 	u8 *sliced_mpeg_data[IVTV_VBI_FRAMES];
 	u32 sliced_mpeg_size[IVTV_VBI_FRAMES];
-	struct ivtv_buffer sliced_mpeg_buf;
-	u32 inserted_frame;
-
-	u32 start[2], count;
-	u32 raw_size;
-	u32 sliced_size;
+	struct ivtv_buffer sliced_mpeg_buf;	/* temporary buffer holding data from sliced_mpeg_data */
+	u32 inserted_frame;			/* index in sliced_mpeg_size of next sliced data
+						   to be inserted in the MPEG stream */
 };
 
 /* forward declaration of struct defined in ivtv-cards.h */
@@ -686,130 +570,132 @@
 
 /* Struct to hold info about ivtv cards */
 struct ivtv {
-	int num;		/* board number, -1 during init! */
-	char name[8];		/* board name for printk and interrupts (e.g. 'ivtv0') */
-	struct pci_dev *dev;	/* PCI device */
+	/* General fixed card data */
+	int num;			/* board number, -1 during init! */
+	char name[8];			/* board name for printk and interrupts (e.g. 'ivtv0') */
+	struct pci_dev *dev;		/* PCI device */
 	const struct ivtv_card *card;	/* card information */
-	const char *card_name;  /* full name of the card */
-	u8 has_cx23415;		/* 1 if it is a cx23415 based card, 0 for cx23416 */
-	u8 is_50hz;
-	u8 is_60hz;
-	u8 is_out_50hz;
-	u8 is_out_60hz;
-	u8 pvr150_workaround;   /* 1 if the cx25840 needs to workaround a PVR150 bug */
-	u8 nof_inputs;		/* number of video inputs */
-	u8 nof_audio_inputs;	/* number of audio inputs */
-	u32 v4l2_cap;		/* V4L2 capabilities of card */
-	u32 hw_flags; 		/* Hardware description of the board */
-
-	/* controlling Video decoder function */
+	const char *card_name;          /* full name of the card */
+	u8 has_cx23415;			/* 1 if it is a cx23415 based card, 0 for cx23416 */
+	u8 pvr150_workaround;           /* 1 if the cx25840 needs to workaround a PVR150 bug */
+	u8 nof_inputs;			/* number of video inputs */
+	u8 nof_audio_inputs;		/* number of audio inputs */
+	u32 v4l2_cap;			/* V4L2 capabilities of card */
+	u32 hw_flags; 			/* hardware description of the board */
+	int tunerid;			/* userspace tuner ID for experimental Xceive tuner support */
+	v4l2_std_id tuner_std;		/* the norm of the card's tuner (fixed) */
+					/* controlling video decoder function */
 	int (*video_dec_func)(struct ivtv *, unsigned int, void *);
+	u32 base_addr;                  /* PCI resource base address */
+	volatile void __iomem *enc_mem; /* pointer to mapped encoder memory */
+	volatile void __iomem *dec_mem; /* pointer to mapped decoder memory */
+	volatile void __iomem *reg_mem; /* pointer to mapped registers */
+	struct ivtv_options options; 	/* user options */
 
-	struct ivtv_options options; 	/* User options */
-	int stream_buf_size[IVTV_MAX_STREAMS]; /* Stream buffer size */
-	struct ivtv_stream streams[IVTV_MAX_STREAMS]; 	/* Stream data */
-	int speed;
-	u8 speed_mute_audio;
-	unsigned long i_flags;  /* global ivtv flags */
-	atomic_t capturing;	/* count number of active capture streams */
-	atomic_t decoding;	/* count number of active decoding streams */
-	u32 irq_rr_idx; /* Round-robin stream index */
-	int cur_dma_stream;	/* index of stream doing DMA */
-	int cur_pio_stream;	/* index of stream doing PIO */
-	u32 dma_data_req_offset;
-	u32 dma_data_req_size;
-	int output_mode;        /* NONE, MPG, YUV, UDMA YUV, passthrough */
-	spinlock_t lock;        /* lock access to this struct */
-	int search_pack_header;
 
-	spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
+	/* High-level state info */
+	unsigned long i_flags;          /* global ivtv flags */
+	u8 is_50hz;                     /* 1 if the current capture standard is 50 Hz */
+	u8 is_60hz                      /* 1 if the current capture standard is 60 Hz */;
+	u8 is_out_50hz                  /* 1 if the current TV output standard is 50 Hz */;
+	u8 is_out_60hz                  /* 1 if the current TV output standard is 60 Hz */;
+	int output_mode;                /* decoder output mode: NONE, MPG, YUV, UDMA YUV, passthrough */
+	u32 audio_input;                /* current audio input */
+	u32 active_input;               /* current video input */
+	u32 active_output;              /* current video output */
+	v4l2_std_id std;                /* current capture TV standard */
+	v4l2_std_id std_out;            /* current TV output standard */
+	u8 audio_stereo_mode;           /* decoder setting how to handle stereo MPEG audio */
+	u8 audio_bilingual_mode;        /* decoder setting how to handle bilingual MPEG audio */
+	struct cx2341x_mpeg_params params;              /* current encoder parameters */
 
-	/* User based DMA for OSD */
-	struct ivtv_user_dma udma;
 
-	int open_id;		/* incremented each time an open occurs, used as unique ID.
-				   starts at 1, so 0 can be used as uninitialized value
-				   in the stream->id. */
+	/* Locking */
+	spinlock_t lock;                /* lock access to this struct */
+	struct mutex serialize_lock;    /* mutex used to serialize open/close/start/stop/ioctl operations */
 
-	u32 base_addr;
-	u32 irqmask;
 
-	struct v4l2_prio_state prio;
-	struct workqueue_struct *irq_work_queues;
-	struct work_struct irq_work_queue;
-	struct timer_list dma_timer; /* Timer used to catch unfinished DMAs */
+	/* Streams */
+	int stream_buf_size[IVTV_MAX_STREAMS];          /* stream buffer size */
+	struct ivtv_stream streams[IVTV_MAX_STREAMS]; 	/* stream data */
+	atomic_t capturing;		/* count number of active capture streams */
+	atomic_t decoding;		/* count number of active decoding streams */
 
-	struct vbi_info vbi;
 
-	struct ivtv_mailbox_data enc_mbox;
-	struct ivtv_mailbox_data dec_mbox;
-	struct ivtv_api_cache api_cache[256]; 	/* Cached API Commands */
+	/* Interrupts & DMA */
+	u32 irqmask;                    /* active interrupts */
+	u32 irq_rr_idx;                 /* round-robin stream index */
+	struct workqueue_struct *irq_work_queues;       /* workqueue for PIO/YUV/VBI actions */
+	struct work_struct irq_work_queue;              /* work entry */
+	spinlock_t dma_reg_lock;        /* lock access to DMA engine registers */
+	int cur_dma_stream;		/* index of current stream doing DMA (-1 if none) */
+	int cur_pio_stream;		/* index of current stream doing PIO (-1 if none) */
+	u32 dma_data_req_offset;        /* store offset in decoder memory of current DMA request */
+	u32 dma_data_req_size;          /* store size of current DMA request */
+	int dma_retries;                /* current DMA retry attempt */
+	struct ivtv_user_dma udma;      /* user based DMA for OSD */
+	struct timer_list dma_timer;    /* timer used to catch unfinished DMAs */
+	u32 last_vsync_field;           /* last seen vsync field */
+	wait_queue_head_t dma_waitq;    /* wake up when the current DMA is finished */
+	wait_queue_head_t eos_waitq;    /* wake up when EOS arrives */
+	wait_queue_head_t event_waitq;  /* wake up when the next decoder event arrives */
+	wait_queue_head_t vsync_waitq;  /* wake up when the next decoder vsync arrives */
 
-	u8 card_rev;
-	volatile void __iomem *enc_mem, *dec_mem, *reg_mem;
 
-	u32 pgm_info_offset;
-	u32 pgm_info_num;
-	u32 pgm_info_write_idx;
-	u32 pgm_info_read_idx;
-	struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX];
+	/* Mailbox */
+	struct ivtv_mailbox_data enc_mbox;              /* encoder mailboxes */
+	struct ivtv_mailbox_data dec_mbox;              /* decoder mailboxes */
+	struct ivtv_api_cache api_cache[256]; 		/* cached API commands */
 
-	u64 mpg_data_received;
-	u64 vbi_data_inserted;
 
-	wait_queue_head_t cap_w;
-	/* when the next decoder event arrives this queue is woken up */
-	wait_queue_head_t event_waitq;
-	/* when the next decoder vsync arrives this queue is woken up */
-	wait_queue_head_t vsync_waitq;
-	/* when the current DMA is finished this queue is woken up */
-	wait_queue_head_t dma_waitq;
-
-	/* OSD support */
-	unsigned long osd_video_pbase;
-	int osd_global_alpha_state; /* 0=off : 1=on */
-	int osd_local_alpha_state;  /* 0=off : 1=on */
-	int osd_color_key_state;    /* 0=off : 1=on */
-	u8  osd_global_alpha;       /* Current global alpha */
-	u32 osd_color_key;          /* Current color key */
-	u32 osd_pixelformat; 	    /* Current pixel format */
-	struct v4l2_rect osd_rect;  /* Current OSD position and size */
-	struct v4l2_rect main_rect; /* Current Main window position and size */
-
-	u32 last_dec_timing[3];     /* Store last retrieved pts/scr/frame values */
-
-	/* i2c */
+	/* I2C */
 	struct i2c_adapter i2c_adap;
 	struct i2c_algo_bit_data i2c_algo;
 	struct i2c_client i2c_client;
-	struct mutex i2c_bus_lock;
-	int i2c_state;
-	struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];
+	struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];/* pointers to all I2C clients */
+	int i2c_state;                  /* i2c bit state */
+	struct mutex i2c_bus_lock;      /* lock i2c bus */
 
-	/* v4l2 and User settings */
 
-	/* codec settings */
-	struct cx2341x_mpeg_params params;
-	u32 audio_input;
-	u32 active_input;
-	u32 active_output;
-	v4l2_std_id std;
-	v4l2_std_id std_out;
-	v4l2_std_id tuner_std;	/* The norm of the tuner (fixed) */
-	u8 audio_stereo_mode;
-	u8 audio_bilingual_mode;
+	/* Program Index information */
+	u32 pgm_info_offset;            /* start of pgm info in encoder memory */
+	u32 pgm_info_num;               /* number of elements in the pgm cyclic buffer in encoder memory */
+	u32 pgm_info_write_idx;         /* last index written by the card that was transferred to pgm_info[] */
+	u32 pgm_info_read_idx;          /* last index in pgm_info read by the application */
+	struct v4l2_enc_idx_entry pgm_info[IVTV_MAX_PGM_INDEX]; /* filled from the pgm cyclic buffer on the card */
 
-	/* dualwatch */
-	unsigned long dualwatch_jiffies;
-	u16 dualwatch_stereo_mode;
 
-	/* Digitizer type */
-	int digitizer;		/* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */
+	/* Miscellaneous */
+	u32 open_id;			/* incremented each time an open occurs, is >= 1 */
+	struct v4l2_prio_state prio;    /* priority state */
+	int search_pack_header;         /* 1 if ivtv_copy_buf_to_user() is scanning for a pack header (0xba) */
+	int speed;                      /* current playback speed setting */
+	u8 speed_mute_audio;            /* 1 if audio should be muted when fast forward */
+	u64 mpg_data_received;          /* number of bytes received from the MPEG stream */
+	u64 vbi_data_inserted;          /* number of VBI bytes inserted into the MPEG stream */
+	u32 last_dec_timing[3];         /* cache last retrieved pts/scr/frame values */
+	unsigned long dualwatch_jiffies;/* jiffies value of the previous dualwatch check */
+	u16 dualwatch_stereo_mode;      /* current detected dualwatch stereo mode */
 
-	u32 lastVsyncFrame;
 
-	struct yuv_playback_info yuv_info;
-	struct osd_info *osd_info;
+	/* VBI state info */
+	struct vbi_info vbi;            /* VBI-specific data */
+
+
+	/* YUV playback */
+	struct yuv_playback_info yuv_info;              /* YUV playback data */
+
+
+	/* OSD support */
+	unsigned long osd_video_pbase;
+	int osd_global_alpha_state;     /* 1 = global alpha is on */
+	int osd_local_alpha_state;      /* 1 = local alpha is on */
+	int osd_chroma_key_state;       /* 1 = chroma-keying is on */
+	u8  osd_global_alpha;           /* current global alpha */
+	u32 osd_chroma_key;             /* current chroma key */
+	struct v4l2_rect osd_rect;      /* current OSD position and size */
+	struct v4l2_rect main_rect;     /* current Main window position and size */
+	struct osd_info *osd_info;      /* ivtvfb private OSD info */
 };
 
 /* Globals */
@@ -831,7 +717,7 @@
 struct ivtv_stream *ivtv_get_output_stream(struct ivtv *itv);
 
 /* Return non-zero if a signal is pending */
-int ivtv_sleep_timeout(int timeout, int intr);
+int ivtv_msleep_timeout(unsigned int msecs, int intr);
 
 /* Wait on queue, returns -EINTR if interrupted */
 int ivtv_waitq(wait_queue_head_t *waitq);
@@ -840,6 +726,9 @@
 struct tveeprom; /* forward reference */
 void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv);
 
+/* First-open initialization: load firmware, init cx25840, etc. */
+int ivtv_init_on_first_open(struct ivtv *itv);
+
 /* This is a PCI post thing, where if the pci register is not read, then
    the write doesn't always take effect right away. By reading back the
    register any pending PCI writes will be performed (in order), and so
@@ -867,4 +756,4 @@
 #define write_dec_sync(val, addr) \
 	do { write_dec(val, addr); read_dec(addr); } while (0)
 
-#endif /* IVTV_DRIVER_H */
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 555d5e6..da50fa4 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -27,10 +27,9 @@
 #include "ivtv-irq.h"
 #include "ivtv-vbi.h"
 #include "ivtv-mailbox.h"
-#include "ivtv-audio.h"
+#include "ivtv-routing.h"
 #include "ivtv-streams.h"
 #include "ivtv-yuv.h"
-#include "ivtv-controls.h"
 #include "ivtv-ioctl.h"
 #include "ivtv-cards.h"
 #include <media/saa7115.h>
@@ -190,7 +189,9 @@
 		int idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
 		struct v4l2_enc_idx_entry *e = itv->pgm_info + idx;
 		u32 addr = itv->pgm_info_offset + 4 + idx * 24;
-		const int mapping[] = { V4L2_ENC_IDX_FRAME_P, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_B, 0 };
+		const int mapping[8] = { -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, -1,
+			V4L2_ENC_IDX_FRAME_B, -1, -1, -1 };
+					// 1=I, 2=P, 4=B
 
 		e->offset = read_enc(addr + 4) + ((u64)read_enc(addr + 8) << 32);
 		if (e->offset > itv->mpg_data_received) {
@@ -199,7 +200,7 @@
 		e->offset += itv->vbi_data_inserted;
 		e->length = read_enc(addr);
 		e->pts = read_enc(addr + 16) + ((u64)(read_enc(addr + 20) & 1) << 32);
-		e->flags = mapping[read_enc(addr + 12) & 3];
+		e->flags = mapping[read_enc(addr + 12) & 7];
 		i++;
 	}
 	itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
@@ -218,7 +219,7 @@
 			/* Process pending program info updates and pending VBI data */
 			ivtv_update_pgm_info(itv);
 
-			if (jiffies - itv->dualwatch_jiffies > HZ) {
+			if (jiffies - itv->dualwatch_jiffies > msecs_to_jiffies(1000)) {
 				itv->dualwatch_jiffies = jiffies;
 				ivtv_dualwatch(itv);
 			}
@@ -245,8 +246,9 @@
 		/* do we have new data? */
 		buf = ivtv_dequeue(s, &s->q_full);
 		if (buf) {
-			if (!test_and_clear_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags))
+			if ((buf->b_flags & IVTV_F_B_NEED_BUF_SWAP) == 0)
 				return buf;
+			buf->b_flags &= ~IVTV_F_B_NEED_BUF_SWAP;
 			if (s->type == IVTV_ENC_STREAM_TYPE_MPG)
 				/* byteswap MPG data */
 				ivtv_buf_swap(buf);
@@ -256,19 +258,19 @@
 			}
 			return buf;
 		}
-		/* return if file was opened with O_NONBLOCK */
-		if (non_block) {
-			*err = -EAGAIN;
-			return NULL;
-		}
 
 		/* return if end of stream */
 		if (s->type != IVTV_DEC_STREAM_TYPE_VBI && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
-			clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
 			IVTV_DEBUG_INFO("EOS %s\n", s->name);
 			return NULL;
 		}
 
+		/* return if file was opened with O_NONBLOCK */
+		if (non_block) {
+			*err = -EAGAIN;
+			return NULL;
+		}
+
 		/* wait for more data to arrive */
 		prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
 		/* New buffers might have become available before we were added to the waitqueue */
@@ -376,10 +378,20 @@
 		int rc;
 
 		buf = ivtv_get_buffer(s, non_block, &rc);
-		if (buf == NULL && rc == -EAGAIN && tot_written)
-			break;
-		if (buf == NULL)
+		/* if there is no data available... */
+		if (buf == NULL) {
+			/* if we got data, then return that regardless */
+			if (tot_written)
+				break;
+			/* EOS condition */
+			if (rc == 0) {
+				clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+				clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+				ivtv_release_stream(s);
+			}
+			/* set errno */
 			return rc;
+		}
 		rc = ivtv_copy_buf_to_user(s, buf, ubuf + tot_written, tot_count - tot_written);
 		if (buf != &itv->vbi.sliced_mpeg_buf) {
 			ivtv_enqueue(s, buf, (buf->readpos == buf->bytesused) ? &s->q_free : &s->q_io);
@@ -406,7 +418,7 @@
 	ssize_t rc = count ? ivtv_read(s, ubuf, count, non_block) : 0;
 	struct ivtv *itv = s->itv;
 
-	IVTV_DEBUG_INFO("read %zd from %s, got %zd\n", count, s->name, rc);
+	IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc);
 	if (rc > 0)
 		pos += rc;
 	return rc;
@@ -497,9 +509,11 @@
 	struct ivtv_stream *s = &itv->streams[id->type];
 	int rc;
 
-	IVTV_DEBUG_IOCTL("read %zd bytes from %s\n", count, s->name);
+	IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);
 
+	mutex_lock(&itv->serialize_lock);
 	rc = ivtv_start_capture(id);
+	mutex_unlock(&itv->serialize_lock);
 	if (rc)
 		return rc;
 	return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
@@ -535,7 +549,7 @@
 	int rc;
 	DEFINE_WAIT(wait);
 
-	IVTV_DEBUG_IOCTL("write %zd bytes to %s\n", count, s->name);
+	IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name);
 
 	if (s->type != IVTV_DEC_STREAM_TYPE_MPG &&
 	    s->type != IVTV_DEC_STREAM_TYPE_YUV &&
@@ -549,8 +563,11 @@
 
 	/* This stream does not need to start any decoding */
 	if (s->type == IVTV_DEC_STREAM_TYPE_VOUT) {
+		int elems = count / sizeof(struct v4l2_sliced_vbi_data);
+
 		set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
-		return ivtv_write_vbi(itv, user_buf, count);
+		ivtv_write_vbi(itv, (const struct v4l2_sliced_vbi_data *)user_buf, elems);
+		return elems * sizeof(struct v4l2_sliced_vbi_data);
 	}
 
 	mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV;
@@ -610,7 +627,9 @@
 	}
 
 	/* Start decoder (returns 0 if already started) */
+	mutex_lock(&itv->serialize_lock);
 	rc = ivtv_start_decoding(id, itv->speed);
+	mutex_unlock(&itv->serialize_lock);
 	if (rc) {
 		IVTV_DEBUG_WARN("Failed start decode stream %s\n", s->name);
 
@@ -643,7 +662,7 @@
 	   to transfer the rest. */
 	if (count && !(filp->f_flags & O_NONBLOCK))
 		goto retry;
-	IVTV_DEBUG_INFO("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
+	IVTV_DEBUG_HI_FILE("Wrote %d bytes to %s (%d)\n", bytes_written, s->name, s->q_full.bytesused);
 	return bytes_written;
 }
 
@@ -655,6 +674,7 @@
 	int res = 0;
 
 	/* add stream's waitq to the poll list */
+	IVTV_DEBUG_HI_FILE("Decoder poll\n");
 	poll_wait(filp, &s->waitq, wait);
 
 	set_bit(IVTV_F_I_EV_VSYNC_ENABLED, &itv->i_flags);
@@ -677,16 +697,21 @@
 
 	/* Start a capture if there is none */
 	if (!eof && !test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
-		int rc = ivtv_start_capture(id);
+		int rc;
 
+		mutex_lock(&itv->serialize_lock);
+		rc = ivtv_start_capture(id);
+		mutex_unlock(&itv->serialize_lock);
 		if (rc) {
 			IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n",
 					s->name, rc);
 			return POLLERR;
 		}
+		IVTV_DEBUG_FILE("Encoder poll started capture\n");
 	}
 
 	/* add stream's waitq to the poll list */
+	IVTV_DEBUG_HI_FILE("Encoder poll\n");
 	poll_wait(filp, &s->waitq, wait);
 
 	if (eof || s->q_full.length)
@@ -699,7 +724,7 @@
 	struct ivtv *itv = id->itv;
 	struct ivtv_stream *s = &itv->streams[id->type];
 
-	IVTV_DEBUG_IOCTL("close() of %s\n", s->name);
+	IVTV_DEBUG_FILE("close() of %s\n", s->name);
 
 	/* 'Unclaim' this stream */
 
@@ -726,10 +751,11 @@
 			ivtv_stop_v4l2_encode_stream(s, gop_end);
 		}
 	}
-	clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
-	clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
-
-	ivtv_release_stream(s);
+	if (!gop_end) {
+		clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
+		clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
+		ivtv_release_stream(s);
+	}
 }
 
 static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts)
@@ -737,13 +763,14 @@
 	struct ivtv *itv = id->itv;
 	struct ivtv_stream *s = &itv->streams[id->type];
 
-	IVTV_DEBUG_IOCTL("close() of %s\n", s->name);
+	IVTV_DEBUG_FILE("close() of %s\n", s->name);
 
 	/* Stop decoding */
 	if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
 		IVTV_DEBUG_INFO("close stopping decode\n");
 
 		ivtv_stop_v4l2_decode_stream(s, flags, pts);
+		itv->output_mode = OUT_NONE;
 	}
 	clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
 	clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
@@ -751,12 +778,11 @@
 		/* Restore registers we've changed & clean up any mess we've made */
 		ivtv_yuv_close(itv);
 	}
-	if (s->type == IVTV_DEC_STREAM_TYPE_YUV && itv->output_mode == OUT_YUV)
-	    itv->output_mode = OUT_NONE;
-	else if (s->type == IVTV_DEC_STREAM_TYPE_MPG && itv->output_mode == OUT_MPG)
-	    itv->output_mode = OUT_NONE;
+	if (itv->output_mode == OUT_UDMA_YUV && id->yuv_frames)
+		itv->output_mode = OUT_NONE;
 
 	itv->speed = 0;
+	clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags);
 	ivtv_release_stream(s);
 }
 
@@ -766,7 +792,7 @@
 	struct ivtv *itv = id->itv;
 	struct ivtv_stream *s = &itv->streams[id->type];
 
-	IVTV_DEBUG_IOCTL("close() of %s\n", s->name);
+	IVTV_DEBUG_FILE("close %s\n", s->name);
 
 	v4l2_prio_close(&itv->prio, &id->prio);
 
@@ -779,6 +805,7 @@
 	/* 'Unclaim' this stream */
 
 	/* Stop radio */
+	mutex_lock(&itv->serialize_lock);
 	if (id->type == IVTV_ENC_STREAM_TYPE_RAD) {
 		/* Closing radio device, return to TV mode */
 		ivtv_mute(itv);
@@ -799,18 +826,106 @@
 		ivtv_unmute(itv);
 		ivtv_release_stream(s);
 	} else if (s->type >= IVTV_DEC_STREAM_TYPE_MPG) {
+		struct ivtv_stream *s_vout = &itv->streams[IVTV_DEC_STREAM_TYPE_VOUT];
+
 		ivtv_stop_decoding(id, VIDEO_CMD_STOP_TO_BLACK | VIDEO_CMD_STOP_IMMEDIATELY, 0);
+
+		/* If all output streams are closed, and if the user doesn't have
+		   IVTV_DEC_STREAM_TYPE_VOUT open, then disable CC on TV-out. */
+		if (itv->output_mode == OUT_NONE && !test_bit(IVTV_F_S_APPL_IO, &s_vout->s_flags)) {
+			/* disable CC on TV-out */
+			ivtv_disable_cc(itv);
+		}
 	} else {
 		ivtv_stop_capture(id, 0);
 	}
 	kfree(id);
+	mutex_unlock(&itv->serialize_lock);
+	return 0;
+}
+
+static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
+{
+	struct ivtv *itv = s->itv;
+	struct ivtv_open_id *item;
+
+	IVTV_DEBUG_FILE("open %s\n", s->name);
+
+	if (s->type == IVTV_DEC_STREAM_TYPE_MPG &&
+		test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
+		return -EBUSY;
+
+	if (s->type == IVTV_DEC_STREAM_TYPE_YUV &&
+		test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags))
+		return -EBUSY;
+
+	if (s->type == IVTV_DEC_STREAM_TYPE_YUV) {
+		if (read_reg(0x82c) == 0) {
+			IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n");
+			/* return -ENODEV; */
+		}
+		ivtv_udma_alloc(itv);
+	}
+
+	/* Allocate memory */
+	item = kmalloc(sizeof(struct ivtv_open_id), GFP_KERNEL);
+	if (NULL == item) {
+		IVTV_DEBUG_WARN("nomem on v4l2 open\n");
+		return -ENOMEM;
+	}
+	item->itv = itv;
+	item->type = s->type;
+	v4l2_prio_open(&itv->prio, &item->prio);
+
+	item->open_id = itv->open_id++;
+	filp->private_data = item;
+
+	if (item->type == IVTV_ENC_STREAM_TYPE_RAD) {
+		/* Try to claim this stream */
+		if (ivtv_claim_stream(item, item->type)) {
+			/* No, it's already in use */
+			kfree(item);
+			return -EBUSY;
+		}
+
+		if (!test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
+			if (atomic_read(&itv->capturing) > 0) {
+				/* switching to radio while capture is
+				   in progress is not polite */
+				kfree(item);
+				return -EBUSY;
+			}
+		}
+		/* Mark that the radio is being used. */
+		set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
+		/* We have the radio */
+		ivtv_mute(itv);
+		/* Switch tuner to radio */
+		ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL);
+		/* Select the correct audio input (i.e. radio tuner) */
+		ivtv_audio_set_io(itv);
+		if (itv->hw_flags & IVTV_HW_SAA711X)
+		{
+			struct v4l2_crystal_freq crystal_freq;
+			crystal_freq.freq = SAA7115_FREQ_32_11_MHZ;
+			crystal_freq.flags = SAA7115_FREQ_FL_APLL;
+			ivtv_saa7115(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);
+		}
+		/* Done! Unmute and continue. */
+		ivtv_unmute(itv);
+	}
+
+	/* YUV or MPG Decoding Mode? */
+	if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
+		clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
+	else if (s->type == IVTV_DEC_STREAM_TYPE_YUV)
+		set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
 	return 0;
 }
 
 int ivtv_v4l2_open(struct inode *inode, struct file *filp)
 {
-	int x, y = 0;
-	struct ivtv_open_id *item;
+	int res, x, y = 0;
 	struct ivtv *itv = NULL;
 	struct ivtv_stream *s = NULL;
 	int minor = iminor(inode);
@@ -832,106 +947,34 @@
 	if (itv == NULL) {
 		/* Couldn't find a device registered
 		   on that minor, shouldn't happen! */
-		printk(KERN_WARNING "ivtv: no ivtv device found on minor %d\n", minor);
+		IVTV_WARN("No ivtv device found on minor %d\n", minor);
 		return -ENXIO;
 	}
 
-	if (y == IVTV_DEC_STREAM_TYPE_MPG &&
-		test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
-		return -EBUSY;
-
-	if (y == IVTV_DEC_STREAM_TYPE_YUV &&
-		test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_MPG].s_flags))
-		return -EBUSY;
-
-	if (y == IVTV_DEC_STREAM_TYPE_YUV) {
-		if (read_reg(0x82c) == 0) {
-			IVTV_ERR("Tried to open YUV output device but need to send data to mpeg decoder before it can be used\n");
-			/* return -ENODEV; */
-		}
-		ivtv_udma_alloc(itv);
+	mutex_lock(&itv->serialize_lock);
+	if (ivtv_init_on_first_open(itv)) {
+		IVTV_ERR("Failed to initialize on minor %d\n", minor);
+		mutex_unlock(&itv->serialize_lock);
+		return -ENXIO;
 	}
-
-	/* Allocate memory */
-	item = kmalloc(sizeof(struct ivtv_open_id), GFP_KERNEL);
-	if (NULL == item) {
-		IVTV_DEBUG_WARN("nomem on v4l2 open\n");
-		return -ENOMEM;
-	}
-	item->itv = itv;
-	item->type = y;
-	v4l2_prio_open(&itv->prio, &item->prio);
-
-	item->open_id = itv->open_id++;
-	filp->private_data = item;
-
-	if (item->type == IVTV_ENC_STREAM_TYPE_RAD) {
-		/* Try to claim this stream */
-		if (ivtv_claim_stream(item, item->type)) {
-			/* No, it's already in use */
-			kfree(item);
-			return -EBUSY;
-		}
-
-		/* We have the radio */
-		ivtv_mute(itv);
-		/* Switch tuner to radio */
-		ivtv_call_i2c_clients(itv, AUDC_SET_RADIO, NULL);
-		/* Mark that the radio is being used. */
-		set_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
-		/* Select the correct audio input (i.e. radio tuner) */
-		ivtv_audio_set_io(itv);
-		if (itv->hw_flags & IVTV_HW_SAA711X)
-		{
-			struct v4l2_crystal_freq crystal_freq;
-			crystal_freq.freq = SAA7115_FREQ_32_11_MHZ;
-			crystal_freq.flags = SAA7115_FREQ_FL_APLL;
-			ivtv_saa7115(itv, VIDIOC_INT_S_CRYSTAL_FREQ, &crystal_freq);
-		}
-		/* Done! Unmute and continue. */
-		ivtv_unmute(itv);
-	}
-
-	/* YUV or MPG Decoding Mode? */
-	if (y == IVTV_DEC_STREAM_TYPE_MPG)
-		clear_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
-	else if (y == IVTV_DEC_STREAM_TYPE_YUV)
-	{
-		set_bit(IVTV_F_I_DEC_YUV, &itv->i_flags);
-	}
-
-	return 0;
+	res = ivtv_serialized_open(s, filp);
+	mutex_unlock(&itv->serialize_lock);
+	return res;
 }
 
 void ivtv_mute(struct ivtv *itv)
 {
-	struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 1 };
-
-	/* Mute sound to avoid pop */
-	ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl);
-
 	if (atomic_read(&itv->capturing))
 		ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 1);
-
 	IVTV_DEBUG_INFO("Mute\n");
 }
 
 void ivtv_unmute(struct ivtv *itv)
 {
-	struct v4l2_control ctrl = { V4L2_CID_AUDIO_MUTE, 0 };
-
-	/* initialize or refresh input */
-	if (atomic_read(&itv->capturing) == 0)
-		ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
-
-	ivtv_sleep_timeout(HZ / 10, 0);
-
 	if (atomic_read(&itv->capturing)) {
+		ivtv_msleep_timeout(100, 0);
 		ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12);
 		ivtv_vapi(itv, CX2341X_ENC_MUTE_AUDIO, 1, 0);
 	}
-
-	/* Unmute */
-	ivtv_control_ioctls(itv, VIDIOC_S_CTRL, &ctrl);
 	IVTV_DEBUG_INFO("Unmute\n");
 }
diff --git a/drivers/media/video/ivtv/ivtv-fileops.h b/drivers/media/video/ivtv/ivtv-fileops.h
index 74a1745..2c8d518 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.h
+++ b/drivers/media/video/ivtv/ivtv-fileops.h
@@ -18,6 +18,9 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#ifndef IVTV_FILEOPS_H
+#define IVTV_FILEOPS_H
+
 /* Testing/Debugging */
 int ivtv_v4l2_open(struct inode *inode, struct file *filp);
 ssize_t ivtv_v4l2_read(struct file *filp, char __user *buf, size_t count,
@@ -42,3 +45,5 @@
 
 /* Release a previously claimed stream. */
 void ivtv_release_stream(struct ivtv_stream *s);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c
index d4c910b..425eb10 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.c
+++ b/drivers/media/video/ivtv/ivtv-firmware.c
@@ -36,7 +36,7 @@
 #define IVTV_CMD_SPU_STOP 		0x00000001
 #define IVTV_CMD_SDRAM_PRECHARGE_INIT 	0x0000001A
 #define IVTV_CMD_SDRAM_REFRESH_INIT 	0x80000640
-#define IVTV_SDRAM_SLEEPTIME 		(60 * HZ / 100)	/* 600 ms */
+#define IVTV_SDRAM_SLEEPTIME 		600
 
 #define IVTV_DECODE_INIT_MPEG_FILENAME 	"v4l-cx2341x-init.mpg"
 #define IVTV_DECODE_INIT_MPEG_SIZE 	(152*1024)
@@ -56,14 +56,12 @@
 		volatile u32 __iomem *dst = (volatile u32 __iomem *)mem;
 		const u32 *src = (const u32 *)fw->data;
 
-		/* temporarily allow 256 KB encoding firmwares as well for
-		   compatibility with blackbird cards */
-		if (fw->size != size && fw->size != 256 * 1024) {
+		if (fw->size != size) {
 			/* Due to race conditions in firmware loading (esp. with udev <0.95)
 			   the wrong file was sometimes loaded. So we check filesizes to
 			   see if at least the right-sized file was loaded. If not, then we
 			   retry. */
-			IVTV_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
+			IVTV_INFO("Retry: file loaded was not %s (expected size %ld, got %zd)\n", fn, size, fw->size);
 			release_firmware(fw);
 			retries--;
 			goto retry;
@@ -74,12 +72,12 @@
 			dst++;
 			src++;
 		}
+		IVTV_INFO("Loaded %s firmware (%zd bytes)\n", fn, fw->size);
 		release_firmware(fw);
-		IVTV_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
 		return size;
 	}
-	IVTV_ERR("unable to open firmware %s (must be %ld bytes)\n", fn, size);
-	IVTV_ERR("did you put the firmware in the hotplug firmware directory?\n");
+	IVTV_ERR("Unable to open firmware %s (must be %ld bytes)\n", fn, size);
+	IVTV_ERR("Did you put the firmware in the hotplug firmware directory?\n");
 	return -ENOMEM;
 }
 
@@ -91,7 +89,7 @@
 	if (itv->enc_mbox.mbox)
 		ivtv_vapi(itv, CX2341X_ENC_HALT_FW, 0);
 
-	ivtv_sleep_timeout(HZ / 100, 0);
+	ivtv_msleep_timeout(10, 0);
 	itv->enc_mbox.mbox = itv->dec_mbox.mbox = NULL;
 
 	IVTV_DEBUG_INFO("Stopping VDM\n");
@@ -115,7 +113,7 @@
 	IVTV_DEBUG_INFO("Stopping SPU\n");
 	write_reg(IVTV_CMD_SPU_STOP, IVTV_REG_SPU);
 
-	ivtv_sleep_timeout(HZ / 100, 0);
+	ivtv_msleep_timeout(10, 0);
 
 	IVTV_DEBUG_INFO("init Encoder SDRAM pre-charge\n");
 	write_reg(IVTV_CMD_SDRAM_PRECHARGE_INIT, IVTV_REG_ENC_SDRAM_PRECHARGE);
@@ -131,9 +129,8 @@
 		write_reg(IVTV_CMD_SDRAM_REFRESH_INIT, IVTV_REG_DEC_SDRAM_REFRESH);
 	}
 
-	IVTV_DEBUG_INFO("Sleeping for %dms (600 recommended)\n",
-		   (int)(IVTV_SDRAM_SLEEPTIME * 1000 / HZ));
-	ivtv_sleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
+	IVTV_DEBUG_INFO("Sleeping for %dms\n", IVTV_SDRAM_SLEEPTIME);
+	ivtv_msleep_timeout(IVTV_SDRAM_SLEEPTIME, 0);
 }
 
 void ivtv_firmware_versions(struct ivtv *itv)
@@ -206,12 +203,12 @@
 
 	/* start firmware */
 	write_reg(read_reg(IVTV_REG_SPU) & IVTV_MASK_SPU_ENABLE, IVTV_REG_SPU);
-	ivtv_sleep_timeout(HZ / 10, 0);
+	ivtv_msleep_timeout(100, 0);
 	if (itv->has_cx23415)
 		write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE15, IVTV_REG_VPU);
 	else
 		write_reg(read_reg(IVTV_REG_VPU) & IVTV_MASK_VPU_ENABLE16, IVTV_REG_VPU);
-	ivtv_sleep_timeout(HZ / 10, 0);
+	ivtv_msleep_timeout(100, 0);
 
 	/* find mailboxes and ping firmware */
 	itv->enc_mbox.mbox = ivtv_search_mailbox(itv->enc_mem, IVTV_ENCODER_SIZE);
@@ -266,7 +263,7 @@
 				IVTV_DECODE_INIT_MPEG_FILENAME);
 	} else {
 		ivtv_vapi(itv, CX2341X_DEC_SCHED_DMA_FROM_HOST, 3, 0, readbytes, 0);
-		ivtv_sleep_timeout(HZ / 10, 0);
+		ivtv_msleep_timeout(100, 0);
 	}
 	ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
 }
diff --git a/drivers/media/video/ivtv/ivtv-firmware.h b/drivers/media/video/ivtv/ivtv-firmware.h
index 8b2ffe6..041ba94 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.h
+++ b/drivers/media/video/ivtv/ivtv-firmware.h
@@ -19,7 +19,12 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#ifndef IVTV_FIRMWARE_H
+#define IVTV_FIRMWARE_H
+
 int ivtv_firmware_init(struct ivtv *itv);
 void ivtv_firmware_versions(struct ivtv *itv);
 void ivtv_halt_firmware(struct ivtv *itv);
 void ivtv_init_mpeg_decoder(struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
index bc8f8ca..132fb5f 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/drivers/media/video/ivtv/ivtv-gpio.c
@@ -115,40 +115,13 @@
 	curout = (curout & ~0xF) | 1;
 	write_reg(curout, IVTV_REG_GPIO_OUT);
 	/* We could use something else for smaller time */
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(1);
+	schedule_timeout_interruptible(msecs_to_jiffies(1));
 	curout |= 2;
 	write_reg(curout, IVTV_REG_GPIO_OUT);
 	curdir &= ~0x80;
 	write_reg(curdir, IVTV_REG_GPIO_DIR);
 }
 
-#ifdef HAVE_XC3028
-int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr)
-{
-	int curdir, curout;
-	struct ivtv *itv = (struct ivtv *) priv;
-
-	if (itv->card->type != IVTV_CARD_PG600V2 || itv->options.tuner != TUNER_XCEIVE_XC3028)
-		return -EINVAL;
-	IVTV_INFO("Resetting tuner.\n");
-	curout = read_reg(IVTV_REG_GPIO_OUT);
-	curdir = read_reg(IVTV_REG_GPIO_DIR);
-	curdir |= (1 << 12);  /* GPIO bit 12 */
-
-	curout &= ~(1 << 12);
-	write_reg(curout, IVTV_REG_GPIO_OUT);
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(1);
-
-	curout |= (1 << 12);
-	write_reg(curout, IVTV_REG_GPIO_OUT);
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(1);
-
-	return 0;
-}
-#endif
 
 void ivtv_gpio_init(struct ivtv *itv)
 {
diff --git a/drivers/media/video/ivtv/ivtv-gpio.h b/drivers/media/video/ivtv/ivtv-gpio.h
index c301d2a..964a265 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.h
+++ b/drivers/media/video/ivtv/ivtv-gpio.h
@@ -18,8 +18,13 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#ifndef IVTV_GPIO_H
+#define IVTV_GPIO_H
+
 /* GPIO stuff */
 void ivtv_gpio_init(struct ivtv *itv);
 void ivtv_reset_ir_gpio(struct ivtv *itv);
-int ivtv_reset_tuner_gpio(enum v4l2_tuner_type mode, void *priv, int ptr);
+int ivtv_reset_tuner_gpio(void *dev, int cmd, int value);
 int ivtv_gpio(struct ivtv *itv, unsigned int command, void *arg);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index 50624c6..285fca6 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -109,6 +109,7 @@
 	I2C_DRIVERID_UPD64083,
 	I2C_DRIVERID_SAA717X,
 	I2C_DRIVERID_WM8739,
+	I2C_DRIVERID_VP27SMPX,
 	0 		/* IVTV_HW_GPIO dummy driver ID */
 };
 
@@ -128,6 +129,7 @@
 	"upd64083",
 	"saa717x",
 	"wm8739",
+	"vp27smpx",
 	"gpio",
 };
 
@@ -144,7 +146,7 @@
 		}
 	}
 	if (i == I2C_CLIENTS_MAX) {
-		IVTV_ERR("insufficient room for new I2C client!\n");
+		IVTV_ERR("Insufficient room for new I2C client\n");
 	}
 	return 0;
 }
@@ -236,7 +238,7 @@
 	int ret = 0;
 
 	if (ivtv_getscl(itv) == 1) {
-		IVTV_DEBUG_I2C("SCL was high starting an ack\n");
+		IVTV_DEBUG_HI_I2C("SCL was high starting an ack\n");
 		ivtv_setscl(itv, 0);
 		if (!ivtv_waitscl(itv, 0)) {
 			IVTV_DEBUG_I2C("Could not set SCL low starting an ack\n");
@@ -263,7 +265,7 @@
 {
 	int i, bit;
 
-	IVTV_DEBUG_I2C("write %x\n",byte);
+	IVTV_DEBUG_HI_I2C("write %x\n",byte);
 	for (i = 0; i < 8; ++i, byte<<=1) {
 		ivtv_setscl(itv, 0);
 		if (!ivtv_waitscl(itv, 0)) {
@@ -318,7 +320,7 @@
 	ivtv_scldelay(itv);
 	ivtv_setscl(itv, 0);
 	ivtv_scldelay(itv);
-	IVTV_DEBUG_I2C("read %x\n",*byte);
+	IVTV_DEBUG_HI_I2C("read %x\n",*byte);
 	return 0;
 }
 
@@ -330,7 +332,7 @@
 
 	sda = ivtv_getsda(itv);
 	if (sda != 1) {
-		IVTV_DEBUG_I2C("SDA was low at start\n");
+		IVTV_DEBUG_HI_I2C("SDA was low at start\n");
 		ivtv_setsda(itv, 1);
 		if (!ivtv_waitsda(itv, 1)) {
 			IVTV_DEBUG_I2C("SDA stuck low\n");
@@ -355,7 +357,7 @@
 	int i;
 
 	if (ivtv_getscl(itv) != 0) {
-		IVTV_DEBUG_I2C("SCL not low when stopping\n");
+		IVTV_DEBUG_HI_I2C("SCL not low when stopping\n");
 		ivtv_setscl(itv, 0);
 		if (!ivtv_waitscl(itv, 0)) {
 			IVTV_DEBUG_I2C("SCL could not be set low\n");
@@ -534,14 +536,13 @@
 #endif
 };
 
-static struct i2c_algo_bit_data ivtv_i2c_algo_template = {
-	NULL,                   /* ?? */
-	ivtv_setsda_old,        /* setsda function */
-	ivtv_setscl_old,        /* " */
-	ivtv_getsda_old,        /* " */
-	ivtv_getscl_old,        /* " */
-	10,                     /* udelay */
-	200                     /* timeout */
+static const struct i2c_algo_bit_data ivtv_i2c_algo_template = {
+	.setsda		= ivtv_setsda_old,
+	.setscl		= ivtv_setscl_old,
+	.getsda		= ivtv_getsda_old,
+	.getscl		= ivtv_getscl_old,
+	.udelay		= 5,
+	.timeout	= 200,
 };
 
 static struct i2c_client ivtv_i2c_client_template = {
@@ -569,7 +570,7 @@
 		}
 	}
 	if (cmd != VIDIOC_G_CHIP_IDENT)
-		IVTV_ERR("i2c addr 0x%02x not found for command 0x%x!\n", addr, cmd);
+		IVTV_ERR("i2c addr 0x%02x not found for command 0x%x\n", addr, cmd);
 	return -ENODEV;
 }
 
@@ -640,7 +641,7 @@
 
 	addr = ivtv_i2c_hw_addr(itv, hw);
 	if (addr < 0) {
-		IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x!\n",
+		IVTV_ERR("i2c hardware 0x%08x (%s) not found for command 0x%x\n",
 			       hw, ivtv_i2c_hw_name(hw), cmd);
 		return addr;
 	}
@@ -655,7 +656,7 @@
 	addr = ivtv_i2c_id_addr(itv, id);
 	if (addr < 0) {
 		if (cmd != VIDIOC_G_CHIP_IDENT)
-			IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x!\n",
+			IVTV_ERR("i2c ID 0x%08x (%s) not found for command 0x%x\n",
 				id, ivtv_i2c_id_name(id), cmd);
 		return addr;
 	}
@@ -696,7 +697,7 @@
 void ivtv_call_i2c_clients(struct ivtv *itv, unsigned int cmd, void *arg)
 {
 	if (itv->i2c_adap.algo == NULL) {
-		IVTV_ERR("adapter is not set");
+		IVTV_ERR("Adapter is not set");
 		return;
 	}
 	i2c_clients_command(&itv->i2c_adap, cmd, arg);
diff --git a/drivers/media/video/ivtv/ivtv-i2c.h b/drivers/media/video/ivtv/ivtv-i2c.h
index 5d210ad..677c329 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.h
+++ b/drivers/media/video/ivtv/ivtv-i2c.h
@@ -18,6 +18,9 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#ifndef IVTV_I2C_H
+#define IVTV_I2C_H
+
 int ivtv_cx25840(struct ivtv *itv, unsigned int cmd, void *arg);
 int ivtv_saa7115(struct ivtv *itv, unsigned int cmd, void *arg);
 int ivtv_saa7127(struct ivtv *itv, unsigned int cmd, void *arg);
@@ -34,3 +37,5 @@
 /* init + register i2c algo-bit adapter */
 int __devinit init_ivtv_i2c(struct ivtv *itv);
 void __devexit exit_ivtv_i2c(struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index 57af176..206eee7 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -25,8 +25,7 @@
 #include "ivtv-queue.h"
 #include "ivtv-fileops.h"
 #include "ivtv-vbi.h"
-#include "ivtv-audio.h"
-#include "ivtv-video.h"
+#include "ivtv-routing.h"
 #include "ivtv-streams.h"
 #include "ivtv-yuv.h"
 #include "ivtv-ioctl.h"
@@ -164,7 +163,7 @@
 {
 	ivtv_vapi(itv, CX2341X_OSD_SET_GLOBAL_ALPHA, 3,
 		itv->osd_global_alpha_state, itv->osd_global_alpha, !itv->osd_local_alpha_state);
-	ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_color_key_state, itv->osd_color_key);
+	ivtv_vapi(itv, CX2341X_OSD_SET_CHROMA_KEY, 2, itv->osd_chroma_key_state, itv->osd_chroma_key);
 }
 
 int ivtv_set_speed(struct ivtv *itv, int speed)
@@ -285,6 +284,10 @@
 
 		if (ivtv_set_output_mode(itv, OUT_MPG) != OUT_MPG)
 			return -EBUSY;
+		if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) {
+			/* forces ivtv_set_speed to be called */
+			itv->speed = 0;
+		}
 		return ivtv_start_decoding(id, vc->play.speed);
 	}
 
@@ -309,6 +312,7 @@
 		if (atomic_read(&itv->decoding) > 0) {
 			ivtv_vapi(itv, CX2341X_DEC_PAUSE_PLAYBACK, 1,
 				(vc->flags & VIDEO_CMD_FREEZE_TO_BLACK) ? 1 : 0);
+			set_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags);
 		}
 		break;
 
@@ -317,8 +321,10 @@
 		if (try) break;
 		if (itv->output_mode != OUT_MPG)
 			return -EBUSY;
-		if (atomic_read(&itv->decoding) > 0) {
-			ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, 0, 0);
+		if (test_and_clear_bit(IVTV_F_I_DEC_PAUSED, &itv->i_flags)) {
+			int speed = itv->speed;
+			itv->speed = 0;
+			return ivtv_start_decoding(id, speed);
 		}
 		break;
 
@@ -420,7 +426,7 @@
 	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
 			return -EINVAL;
-		fmt->fmt.win.chromakey = itv->osd_color_key;
+		fmt->fmt.win.chromakey = itv->osd_chroma_key;
 		fmt->fmt.win.global_alpha = itv->osd_global_alpha;
 		break;
 
@@ -540,7 +546,7 @@
 		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
 			return -EINVAL;
 		if (set_fmt) {
-			itv->osd_color_key = fmt->fmt.win.chromakey;
+			itv->osd_chroma_key = fmt->fmt.win.chromakey;
 			itv->osd_global_alpha = fmt->fmt.win.global_alpha;
 			ivtv_set_osd_alpha(itv);
 		}
@@ -577,9 +583,7 @@
 
 	/* set raw VBI format */
 	if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-		if (set_fmt && streamtype == IVTV_ENC_STREAM_TYPE_VBI &&
-		    itv->vbi.sliced_in->service_set &&
-		    atomic_read(&itv->capturing) > 0) {
+		if (set_fmt && atomic_read(&itv->capturing) > 0) {
 			return -EBUSY;
 		}
 		if (set_fmt) {
@@ -617,7 +621,7 @@
 		return 0;
 	if (set == 0)
 		return -EINVAL;
-	if (atomic_read(&itv->capturing) > 0 && itv->vbi.sliced_in->service_set == 0) {
+	if (atomic_read(&itv->capturing) > 0) {
 		return -EBUSY;
 	}
 	itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
@@ -670,13 +674,21 @@
 	case VIDIOC_INT_S_AUDIO_ROUTING: {
 		struct v4l2_routing *route = arg;
 
-		ivtv_audio_set_route(itv, route);
+		ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
 		break;
 	}
 
-	case VIDIOC_INT_RESET:
-		ivtv_reset_ir_gpio(itv);
+	case VIDIOC_INT_RESET: {
+		u32 val = *(u32 *)arg;
+
+		if ((val == 0 && itv->options.newi2c) || (val & 0x01)) {
+			ivtv_reset_ir_gpio(itv);
+		}
+		if (val & 0x02) {
+			itv->video_dec_func(itv, cmd, 0);
+		}
 		break;
+	}
 
 	default:
 		return -EINVAL;
@@ -687,6 +699,7 @@
 int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg)
 {
 	struct ivtv_open_id *id = NULL;
+	u32 data[CX2341X_MBOX_MAX_DATA];
 
 	if (filp) id = (struct ivtv_open_id *)filp->private_data;
 
@@ -891,6 +904,9 @@
 			IVTV_DEBUG_INFO("Input unchanged\n");
 			break;
 		}
+		if (atomic_read(&itv->capturing) > 0) {
+			return -EBUSY;
+		}
 		IVTV_DEBUG_INFO("Changing input from %d to %d\n",
 				itv->active_input, inp);
 
@@ -1092,14 +1108,21 @@
 
 	case VIDIOC_G_ENC_INDEX: {
 		struct v4l2_enc_idx *idx = arg;
+		struct v4l2_enc_idx_entry *e = idx->entry;
+		int entries;
 		int i;
 
-		idx->entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
+		entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
 					IVTV_MAX_PGM_INDEX;
-		if (idx->entries > V4L2_ENC_IDX_ENTRIES)
-			idx->entries = V4L2_ENC_IDX_ENTRIES;
-		for (i = 0; i < idx->entries; i++) {
-			idx->entry[i] = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
+		if (entries > V4L2_ENC_IDX_ENTRIES)
+			entries = V4L2_ENC_IDX_ENTRIES;
+		idx->entries = 0;
+		for (i = 0; i < entries; i++) {
+			*e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
+			if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) {
+				idx->entries++;
+				e++;
+			}
 		}
 		itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX;
 		break;
@@ -1113,12 +1136,14 @@
 		memset(&enc->raw, 0, sizeof(enc->raw));
 		switch (enc->cmd) {
 		case V4L2_ENC_CMD_START:
+			IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
 			enc->flags = 0;
 			if (try)
 				return 0;
 			return ivtv_start_capture(id);
 
 		case V4L2_ENC_CMD_STOP:
+			IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
 			enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
 			if (try)
 				return 0;
@@ -1126,6 +1151,7 @@
 			return 0;
 
 		case V4L2_ENC_CMD_PAUSE:
+			IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
 			enc->flags = 0;
 			if (try)
 				return 0;
@@ -1138,6 +1164,7 @@
 			break;
 
 		case V4L2_ENC_CMD_RESUME:
+			IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
 			enc->flags = 0;
 			if (try)
 				return 0;
@@ -1149,6 +1176,7 @@
 			ivtv_unmute(itv);
 			break;
 		default:
+			IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
 			return -EINVAL;
 		}
 		break;
@@ -1156,22 +1184,58 @@
 
 	case VIDIOC_G_FBUF: {
 		struct v4l2_framebuffer *fb = arg;
+		int pixfmt;
+		static u32 pixel_format[16] = {
+			V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */
+			V4L2_PIX_FMT_RGB565,
+			V4L2_PIX_FMT_RGB555,
+			V4L2_PIX_FMT_RGB444,
+			V4L2_PIX_FMT_RGB32,
+			0,
+			0,
+			0,
+			V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */
+			V4L2_PIX_FMT_YUV565,
+			V4L2_PIX_FMT_YUV555,
+			V4L2_PIX_FMT_YUV444,
+			V4L2_PIX_FMT_YUV32,
+			0,
+			0,
+			0,
+		};
 
 		memset(fb, 0, sizeof(*fb));
 		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
-			break;
+			return -EINVAL;
 		fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
-			V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_GLOBAL_ALPHA;
-		fb->fmt.pixelformat = itv->osd_pixelformat;
+			V4L2_FBUF_CAP_GLOBAL_ALPHA;
+		ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
+		data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
+		pixfmt = (data[0] >> 3) & 0xf;
+		fb->fmt.pixelformat = pixel_format[pixfmt];
 		fb->fmt.width = itv->osd_rect.width;
 		fb->fmt.height = itv->osd_rect.height;
 		fb->base = (void *)itv->osd_video_pbase;
+		if (itv->osd_chroma_key_state)
+			fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
 		if (itv->osd_global_alpha_state)
 			fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
-		if (itv->osd_local_alpha_state)
-			fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
-		if (itv->osd_color_key_state)
-			fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+		pixfmt &= 7;
+		/* no local alpha for RGB565 or unknown formats */
+		if (pixfmt == 1 || pixfmt > 4)
+			break;
+		/* 16-bit formats have inverted local alpha */
+		if (pixfmt == 2 || pixfmt == 3)
+			fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA;
+		else
+			fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA;
+		if (itv->osd_local_alpha_state) {
+			/* 16-bit formats have inverted local alpha */
+			if (pixfmt == 2 || pixfmt == 3)
+				fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA;
+			else
+				fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
+		}
 		break;
 	}
 
@@ -1179,10 +1243,21 @@
 		struct v4l2_framebuffer *fb = arg;
 
 		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
-			break;
+			return -EINVAL;
 		itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
-		itv->osd_local_alpha_state = (fb->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) != 0;
-		itv->osd_color_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
+		itv->osd_local_alpha_state =
+			(fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0;
+		itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
+		ivtv_set_osd_alpha(itv);
+		break;
+	}
+
+	case VIDIOC_OVERLAY: {
+		int *on = arg;
+
+		if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
+			return -EINVAL;
+		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, *on != 0);
 		break;
 	}
 
@@ -1194,6 +1269,7 @@
 		int i;
 
 		IVTV_INFO("=================  START STATUS CARD #%d  =================\n", itv->num);
+		IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
 		if (itv->hw_flags & IVTV_HW_TVEEPROM) {
 			struct tveeprom tv;
 
@@ -1202,32 +1278,72 @@
 		ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL);
 		ivtv_get_input(itv, itv->active_input, &vidin);
 		ivtv_get_audio_input(itv, itv->audio_input, &audin);
-		IVTV_INFO("Video Input: %s\n", vidin.name);
-		IVTV_INFO("Audio Input: %s\n", audin.name);
+		IVTV_INFO("Video Input:  %s\n", vidin.name);
+		IVTV_INFO("Audio Input:  %s%s\n", audin.name,
+			(itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : "");
 		if (has_output) {
 			struct v4l2_output vidout;
 			struct v4l2_audioout audout;
 			int mode = itv->output_mode;
-			static const char * const output_modes[] = {
+			static const char * const output_modes[5] = {
 				"None",
 				"MPEG Streaming",
 				"YUV Streaming",
 				"YUV Frames",
 				"Passthrough",
 			};
+			static const char * const audio_modes[5] = {
+				"Stereo",
+				"Left",
+				"Right",
+				"Mono",
+				"Swapped"
+			};
+			static const char * const alpha_mode[4] = {
+				"None",
+				"Global",
+				"Local",
+				"Global and Local"
+			};
+			static const char * const pixel_format[16] = {
+				"ARGB Indexed",
+				"RGB 5:6:5",
+				"ARGB 1:5:5:5",
+				"ARGB 1:4:4:4",
+				"ARGB 8:8:8:8",
+				"5",
+				"6",
+				"7",
+				"AYUV Indexed",
+				"YUV 5:6:5",
+				"AYUV 1:5:5:5",
+				"AYUV 1:4:4:4",
+				"AYUV 8:8:8:8",
+				"13",
+				"14",
+				"15",
+			};
 
 			ivtv_get_output(itv, itv->active_output, &vidout);
 			ivtv_get_audio_output(itv, 0, &audout);
 			IVTV_INFO("Video Output: %s\n", vidout.name);
-			IVTV_INFO("Audio Output: %s\n", audout.name);
+			IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name,
+				audio_modes[itv->audio_stereo_mode],
+				audio_modes[itv->audio_bilingual_mode]);
 			if (mode < 0 || mode > OUT_PASSTHROUGH)
 				mode = OUT_NONE;
-			IVTV_INFO("Output Mode: %s\n", output_modes[mode]);
+			IVTV_INFO("Output Mode:  %s\n", output_modes[mode]);
+			ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
+			data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
+			IVTV_INFO("Overlay:      %s, Alpha: %s, Pixel Format: %s\n",
+				data[0] & 1 ? "On" : "Off",
+				alpha_mode[(data[0] >> 1) & 0x3],
+				pixel_format[(data[0] >> 3) & 0xf]);
 		}
-		IVTV_INFO("Tuner: %s\n",
+		IVTV_INFO("Tuner:  %s\n",
 			test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
 		cx2341x_log_status(&itv->params, itv->name);
-		IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags);
+		IVTV_INFO("Status flags:    0x%08lx\n", itv->i_flags);
 		for (i = 0; i < IVTV_MAX_STREAMS; i++) {
 			struct ivtv_stream *s = &itv->streams[i];
 
@@ -1237,7 +1353,7 @@
 					(s->buffers - s->q_free.buffers) * 100 / s->buffers,
 					(s->buffers * s->buf_size) / 1024, s->buffers);
 		}
-		IVTV_INFO("Read MPEG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted);
+		IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted);
 		IVTV_INFO("==================  END STATUS CARD #%d  ==================\n", itv->num);
 		break;
 	}
@@ -1273,6 +1389,8 @@
 			ivtv_release_stream(s);
 			return -EBUSY;
 		}
+		/* Mark that this file handle started the UDMA_YUV mode */
+		id->yuv_frames = 1;
 		if (args->y_source == NULL)
 			return 0;
 		return ivtv_yuv_prep_frame(itv, args);
@@ -1381,9 +1499,9 @@
 		int try = (cmd == VIDEO_TRY_COMMAND);
 
 		if (try)
-			IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND\n");
+			IVTV_DEBUG_IOCTL("VIDEO_TRY_COMMAND %d\n", vc->cmd);
 		else
-			IVTV_DEBUG_IOCTL("VIDEO_COMMAND\n");
+			IVTV_DEBUG_IOCTL("VIDEO_COMMAND %d\n", vc->cmd);
 		return ivtv_video_command(itv, id, vc, try);
 	}
 
@@ -1414,11 +1532,15 @@
 				return 0;
 			if (nonblocking)
 				return -EAGAIN;
-			/* wait for event */
+			/* Wait for event. Note that serialize_lock is locked,
+			   so to allow other processes to access the driver while
+			   we are waiting unlock first and later lock again. */
+			mutex_unlock(&itv->serialize_lock);
 			prepare_to_wait(&itv->event_waitq, &wait, TASK_INTERRUPTIBLE);
 			if ((itv->i_flags & (IVTV_F_I_EV_DEC_STOPPED|IVTV_F_I_EV_VSYNC)) == 0)
 				schedule();
 			finish_wait(&itv->event_waitq, &wait);
+			mutex_lock(&itv->serialize_lock);
 			if (signal_pending(current)) {
 				/* return if a signal was received */
 				IVTV_DEBUG_INFO("User stopped wait for event\n");
@@ -1455,6 +1577,7 @@
 	case VIDIOC_S_AUDOUT:
 	case VIDIOC_S_EXT_CTRLS:
 	case VIDIOC_S_FBUF:
+	case VIDIOC_OVERLAY:
 		ret = v4l2_prio_check(&itv->prio, &id->prio);
 		if (ret)
 			return ret;
@@ -1508,6 +1631,7 @@
 	case VIDIOC_TRY_ENCODER_CMD:
 	case VIDIOC_G_FBUF:
 	case VIDIOC_S_FBUF:
+	case VIDIOC_OVERLAY:
 		if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
 			printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
 			v4l_printk_ioctl(cmd);
@@ -1548,12 +1672,9 @@
 	return 0;
 }
 
-int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
-		    unsigned long arg)
+static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct file *filp,
+		unsigned int cmd, unsigned long arg)
 {
-	struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
-	struct ivtv *itv = id->itv;
-
 	/* Filter dvb ioctls that cannot be handled by video_usercopy */
 	switch (cmd) {
 	case VIDEO_SELECT_SOURCE:
@@ -1588,3 +1709,16 @@
 	}
 	return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl);
 }
+
+int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+		    unsigned long arg)
+{
+	struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
+	struct ivtv *itv = id->itv;
+	int res;
+
+	mutex_lock(&itv->serialize_lock);
+	res = ivtv_serialized_ioctl(itv, inode, filp, cmd, arg);
+	mutex_unlock(&itv->serialize_lock);
+	return res;
+}
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.h b/drivers/media/video/ivtv/ivtv-ioctl.h
index cbccf7a..a03351b 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.h
+++ b/drivers/media/video/ivtv/ivtv-ioctl.h
@@ -18,6 +18,9 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#ifndef IVTV_IOCTL_H
+#define IVTV_IOCTL_H
+
 u16 service2vbi(int type);
 void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
 u16 get_service_set(struct v4l2_sliced_vbi_format *fmt);
@@ -26,3 +29,5 @@
 int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg);
 void ivtv_set_osd_alpha(struct ivtv *itv);
 int ivtv_set_speed(struct ivtv *itv, int speed);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index ba98bf0..fd1688e4 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -19,12 +19,9 @@
  */
 
 #include "ivtv-driver.h"
-#include "ivtv-firmware.h"
-#include "ivtv-fileops.h"
 #include "ivtv-queue.h"
 #include "ivtv-udma.h"
 #include "ivtv-irq.h"
-#include "ivtv-ioctl.h"
 #include "ivtv-mailbox.h"
 #include "ivtv-vbi.h"
 #include "ivtv-yuv.h"
@@ -45,10 +42,9 @@
 {
 	struct ivtv_stream *s = &itv->streams[itv->cur_pio_stream];
 	struct ivtv_buffer *buf;
-	struct list_head *p;
 	int i = 0;
 
-	IVTV_DEBUG_DMA("ivtv_pio_work_handler\n");
+	IVTV_DEBUG_HI_DMA("ivtv_pio_work_handler\n");
 	if (itv->cur_pio_stream < 0 || itv->cur_pio_stream >= IVTV_MAX_STREAMS ||
 			s->v4l2dev == NULL || !ivtv_use_pio(s)) {
 		itv->cur_pio_stream = -1;
@@ -56,22 +52,20 @@
 		write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
 		return;
 	}
-	IVTV_DEBUG_DMA("Process PIO %s\n", s->name);
-	buf = list_entry(s->q_dma.list.next, struct ivtv_buffer, list);
-	list_for_each(p, &s->q_dma.list) {
-		struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
-		u32 size = s->PIOarray[i].size & 0x3ffff;
+	IVTV_DEBUG_HI_DMA("Process PIO %s\n", s->name);
+	list_for_each_entry(buf, &s->q_dma.list, list) {
+		u32 size = s->sg_processing[i].size & 0x3ffff;
 
 		/* Copy the data from the card to the buffer */
 		if (s->type == IVTV_DEC_STREAM_TYPE_VBI) {
-			memcpy_fromio(buf->buf, itv->dec_mem + s->PIOarray[i].src - IVTV_DECODER_OFFSET, size);
+			memcpy_fromio(buf->buf, itv->dec_mem + s->sg_processing[i].src - IVTV_DECODER_OFFSET, size);
 		}
 		else {
-			memcpy_fromio(buf->buf, itv->enc_mem + s->PIOarray[i].src, size);
+			memcpy_fromio(buf->buf, itv->enc_mem + s->sg_processing[i].src, size);
 		}
-		if (s->PIOarray[i].size & 0x80000000)
-			break;
 		i++;
+		if (i == s->sg_processing_size)
+			break;
 	}
 	write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
 }
@@ -100,12 +94,11 @@
 {
 	struct ivtv *itv = s->itv;
 	struct ivtv_buffer *buf;
-	struct list_head *p;
 	u32 bytes_needed = 0;
 	u32 offset, size;
 	u32 UVoffset = 0, UVsize = 0;
 	int skip_bufs = s->q_predma.buffers;
-	int idx = s->SG_length;
+	int idx = s->sg_pending_size;
 	int rc;
 
 	/* sanity checks */
@@ -123,7 +116,7 @@
 		case IVTV_ENC_STREAM_TYPE_MPG:
 			offset = data[1];
 			size = data[2];
-			s->dma_pts = 0;
+			s->pending_pts = 0;
 			break;
 
 		case IVTV_ENC_STREAM_TYPE_YUV:
@@ -131,13 +124,13 @@
 			size = data[2];
 			UVoffset = data[3];
 			UVsize = data[4];
-			s->dma_pts = ((u64) data[5] << 32) | data[6];
+			s->pending_pts = ((u64) data[5] << 32) | data[6];
 			break;
 
 		case IVTV_ENC_STREAM_TYPE_PCM:
 			offset = data[1] + 12;
 			size = data[2] - 12;
-			s->dma_pts = read_dec(offset - 8) |
+			s->pending_pts = read_dec(offset - 8) |
 				((u64)(read_dec(offset - 12)) << 32);
 			if (itv->has_cx23415)
 				offset += IVTV_DECODER_OFFSET;
@@ -150,13 +143,13 @@
 				IVTV_DEBUG_INFO("VBI offset == 0\n");
 				return -1;
 			}
-			s->dma_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32);
+			s->pending_pts = read_enc(offset - 4) | ((u64)read_enc(offset - 8) << 32);
 			break;
 
 		case IVTV_DEC_STREAM_TYPE_VBI:
 			size = read_dec(itv->vbi.dec_start + 4) + 8;
 			offset = read_dec(itv->vbi.dec_start) + itv->vbi.dec_start;
-			s->dma_pts = 0;
+			s->pending_pts = 0;
 			offset += IVTV_DECODER_OFFSET;
 			break;
 		default:
@@ -165,17 +158,17 @@
 	}
 
 	/* if this is the start of the DMA then fill in the magic cookie */
-	if (s->SG_length == 0) {
+	if (s->sg_pending_size == 0 && ivtv_use_dma(s)) {
 		if (itv->has_cx23415 && (s->type == IVTV_ENC_STREAM_TYPE_PCM ||
 		    s->type == IVTV_DEC_STREAM_TYPE_VBI)) {
-			s->dma_backup = read_dec(offset - IVTV_DECODER_OFFSET);
+			s->pending_backup = read_dec(offset - IVTV_DECODER_OFFSET);
 			write_dec_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset - IVTV_DECODER_OFFSET);
 		}
 		else {
-			s->dma_backup = read_enc(offset);
+			s->pending_backup = read_enc(offset);
 			write_enc_sync(cpu_to_le32(DMA_MAGIC_COOKIE), offset);
 		}
-		s->dma_offset = offset;
+		s->pending_offset = offset;
 	}
 
 	bytes_needed = size;
@@ -187,7 +180,7 @@
 		bytes_needed += UVsize;
 	}
 
-	IVTV_DEBUG_DMA("%s %s: 0x%08x bytes at 0x%08x\n",
+	IVTV_DEBUG_HI_DMA("%s %s: 0x%08x bytes at 0x%08x\n",
 		ivtv_use_pio(s) ? "PIO" : "DMA", s->name, bytes_needed, offset);
 
 	rc = ivtv_queue_move(s, &s->q_free, &s->q_full, &s->q_predma, bytes_needed);
@@ -202,18 +195,17 @@
 	}
 	s->buffers_stolen = rc;
 
-	/* got the buffers, now fill in SGarray (DMA) */
+	/* got the buffers, now fill in sg_pending */
 	buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list);
 	memset(buf->buf, 0, 128);
-	list_for_each(p, &s->q_predma.list) {
-		struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
-
+	list_for_each_entry(buf, &s->q_predma.list, list) {
 		if (skip_bufs-- > 0)
 			continue;
-		s->SGarray[idx].dst = cpu_to_le32(buf->dma_handle);
-		s->SGarray[idx].src = cpu_to_le32(offset);
-		s->SGarray[idx].size = cpu_to_le32(s->buf_size);
+		s->sg_pending[idx].dst = buf->dma_handle;
+		s->sg_pending[idx].src = offset;
+		s->sg_pending[idx].size = s->buf_size;
 		buf->bytesused = (size < s->buf_size) ? size : s->buf_size;
+		buf->dma_xfer_cnt = s->dma_xfer_cnt;
 
 		s->q_predma.bytesused += buf->bytesused;
 		size -= buf->bytesused;
@@ -229,7 +221,7 @@
 		}
 		idx++;
 	}
-	s->SG_length = idx;
+	s->sg_pending_size = idx;
 	return 0;
 }
 
@@ -242,7 +234,7 @@
 	u32 *u32buf;
 	int x = 0;
 
-	IVTV_DEBUG_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
+	IVTV_DEBUG_HI_DMA("%s %s completed (%x)\n", ivtv_use_pio(s) ? "PIO" : "DMA",
 			s->name, s->dma_offset);
 	list_for_each(p, &s->q_dma.list) {
 		buf = list_entry(p, struct ivtv_buffer, list);
@@ -251,7 +243,7 @@
 		/* Sync Buffer */
 		ivtv_buf_sync_for_cpu(s, buf);
 
-		if (x == 0) {
+		if (x == 0 && ivtv_use_dma(s)) {
 			offset = s->dma_last_offset;
 			if (u32buf[offset / 4] != DMA_MAGIC_COOKIE)
 			{
@@ -286,14 +278,12 @@
 		/* flag byteswap ABCD -> DCBA for MPG & VBI data outside irq */
 		if (s->type == IVTV_ENC_STREAM_TYPE_MPG ||
 		    s->type == IVTV_ENC_STREAM_TYPE_VBI)
-			set_bit(IVTV_F_B_NEED_BUF_SWAP, &buf->b_flags);
+			buf->b_flags |= IVTV_F_B_NEED_BUF_SWAP;
 	}
 	if (buf)
 		buf->bytesused += s->dma_last_offset;
 	if (buf && s->type == IVTV_DEC_STREAM_TYPE_VBI) {
-		list_for_each(p, &s->q_dma.list) {
-			buf = list_entry(p, struct ivtv_buffer, list);
-
+		list_for_each_entry(buf, &s->q_dma.list, list) {
 			/* Parse and Groom VBI Data */
 			s->q_dma.bytesused -= buf->bytesused;
 			ivtv_process_vbi_data(itv, buf, 0, s->type);
@@ -313,7 +303,6 @@
 {
 	struct ivtv *itv = s->itv;
 	struct ivtv_buffer *buf;
-	struct list_head *p;
 	u32 y_size = itv->params.height * itv->params.width;
 	u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET;
 	int y_done = 0;
@@ -321,19 +310,16 @@
 	unsigned long flags = 0;
 	int idx = 0;
 
-	IVTV_DEBUG_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
-	buf = list_entry(s->q_predma.list.next, struct ivtv_buffer, list);
-	list_for_each(p, &s->q_predma.list) {
-		struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
-
+	IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
+	list_for_each_entry(buf, &s->q_predma.list, list) {
 		/* YUV UV Offset from Y Buffer */
 		if (s->type == IVTV_DEC_STREAM_TYPE_YUV && !y_done && bytes_written >= y_size) {
 			offset = uv_offset;
 			y_done = 1;
 		}
-		s->SGarray[idx].src = cpu_to_le32(buf->dma_handle);
-		s->SGarray[idx].dst = cpu_to_le32(offset);
-		s->SGarray[idx].size = cpu_to_le32(buf->bytesused);
+		s->sg_pending[idx].src = buf->dma_handle;
+		s->sg_pending[idx].dst = offset;
+		s->sg_pending[idx].size = buf->bytesused;
 
 		offset += buf->bytesused;
 		bytes_written += buf->bytesused;
@@ -342,10 +328,7 @@
 		ivtv_buf_sync_for_device(s, buf);
 		idx++;
 	}
-	s->SG_length = idx;
-
-	/* Mark last buffer size for Interrupt flag */
-	s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000);
+	s->sg_pending_size = idx;
 
 	/* Sync Hardware SG List of buffers */
 	ivtv_stream_sync_for_device(s);
@@ -361,6 +344,34 @@
 		spin_unlock_irqrestore(&itv->dma_reg_lock, flags);
 }
 
+static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s)
+{
+	struct ivtv *itv = s->itv;
+
+	s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src);
+	s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst);
+	s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000);
+	s->sg_processed++;
+	/* Sync Hardware SG List of buffers */
+	ivtv_stream_sync_for_device(s);
+	write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR);
+	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
+}
+
+static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s)
+{
+	struct ivtv *itv = s->itv;
+
+	s->sg_dma->src = cpu_to_le32(s->sg_processing[s->sg_processed].src);
+	s->sg_dma->dst = cpu_to_le32(s->sg_processing[s->sg_processed].dst);
+	s->sg_dma->size = cpu_to_le32(s->sg_processing[s->sg_processed].size | 0x80000000);
+	s->sg_processed++;
+	/* Sync Hardware SG List of buffers */
+	ivtv_stream_sync_for_device(s);
+	write_reg(s->sg_handle, IVTV_REG_DECDMAADDR);
+	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
+}
+
 /* start the encoder DMA */
 static void ivtv_dma_enc_start(struct ivtv_stream *s)
 {
@@ -368,14 +379,13 @@
 	struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
 	int i;
 
-	IVTV_DEBUG_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name);
+	IVTV_DEBUG_HI_DMA("start %s for %s\n", ivtv_use_dma(s) ? "DMA" : "PIO", s->name);
 
 	if (s->q_predma.bytesused)
 		ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
 
 	if (ivtv_use_dma(s))
-		s->SGarray[s->SG_length - 1].size =
-			cpu_to_le32(le32_to_cpu(s->SGarray[s->SG_length - 1].size) + 256);
+		s->sg_pending[s->sg_pending_size - 1].size += 256;
 
 	/* If this is an MPEG stream, and VBI data is also pending, then append the
 	   VBI DMA to the MPEG DMA and transfer both sets of data at once.
@@ -386,41 +396,42 @@
 	   sure we only use the MPEG DMA to transfer the VBI DMA if both are in
 	   use. This way no conflicts occur. */
 	clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
-	if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->SG_length &&
-			s->SG_length + s_vbi->SG_length <= s->buffers) {
+	if (s->type == IVTV_ENC_STREAM_TYPE_MPG && s_vbi->sg_pending_size &&
+			s->sg_pending_size + s_vbi->sg_pending_size <= s->buffers) {
 		ivtv_queue_move(s_vbi, &s_vbi->q_predma, NULL, &s_vbi->q_dma, s_vbi->q_predma.bytesused);
 		if (ivtv_use_dma(s_vbi))
-			s_vbi->SGarray[s_vbi->SG_length - 1].size = cpu_to_le32(le32_to_cpu(s_vbi->SGarray[s->SG_length - 1].size) + 256);
-		for (i = 0; i < s_vbi->SG_length; i++) {
-			s->SGarray[s->SG_length++] = s_vbi->SGarray[i];
+			s_vbi->sg_pending[s_vbi->sg_pending_size - 1].size += 256;
+		for (i = 0; i < s_vbi->sg_pending_size; i++) {
+			s->sg_pending[s->sg_pending_size++] = s_vbi->sg_pending[i];
 		}
-		itv->vbi.dma_offset = s_vbi->dma_offset;
-		s_vbi->SG_length = 0;
+		s_vbi->dma_offset = s_vbi->pending_offset;
+		s_vbi->sg_pending_size = 0;
+		s_vbi->dma_xfer_cnt++;
 		set_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags);
-		IVTV_DEBUG_DMA("include DMA for %s\n", s->name);
+		IVTV_DEBUG_HI_DMA("include DMA for %s\n", s->name);
 	}
 
-	/* Mark last buffer size for Interrupt flag */
-	s->SGarray[s->SG_length - 1].size |= cpu_to_le32(0x80000000);
+	s->dma_xfer_cnt++;
+	memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size);
+	s->sg_processing_size = s->sg_pending_size;
+	s->sg_pending_size = 0;
+	s->sg_processed = 0;
+	s->dma_offset = s->pending_offset;
+	s->dma_backup = s->pending_backup;
+	s->dma_pts = s->pending_pts;
 
 	if (ivtv_use_pio(s)) {
-		for (i = 0; i < s->SG_length; i++) {
-			s->PIOarray[i].src = le32_to_cpu(s->SGarray[i].src);
-			s->PIOarray[i].size = le32_to_cpu(s->SGarray[i].size);
-		}
 		set_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags);
 		set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
 		set_bit(IVTV_F_I_PIO, &itv->i_flags);
 		itv->cur_pio_stream = s->type;
 	}
 	else {
-		/* Sync Hardware SG List of buffers */
-		ivtv_stream_sync_for_device(s);
-		write_reg(s->SG_handle, IVTV_REG_ENCDMAADDR);
-		write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
+		itv->dma_retries = 0;
+		ivtv_dma_enc_start_xfer(s);
 		set_bit(IVTV_F_I_DMA, &itv->i_flags);
 		itv->cur_dma_stream = s->type;
-		itv->dma_timer.expires = jiffies + HZ / 10;
+		itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
 		add_timer(&itv->dma_timer);
 	}
 }
@@ -431,13 +442,18 @@
 
 	if (s->q_predma.bytesused)
 		ivtv_queue_move(s, &s->q_predma, NULL, &s->q_dma, s->q_predma.bytesused);
-	IVTV_DEBUG_DMA("start DMA for %s\n", s->name);
-	/* put SG Handle into register 0x0c */
-	write_reg(s->SG_handle, IVTV_REG_DECDMAADDR);
-	write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
+	s->dma_xfer_cnt++;
+	memcpy(s->sg_processing, s->sg_pending, sizeof(struct ivtv_sg_element) * s->sg_pending_size);
+	s->sg_processing_size = s->sg_pending_size;
+	s->sg_pending_size = 0;
+	s->sg_processed = 0;
+
+	IVTV_DEBUG_HI_DMA("start DMA for %s\n", s->name);
+	itv->dma_retries = 0;
+	ivtv_dma_dec_start_xfer(s);
 	set_bit(IVTV_F_I_DMA, &itv->i_flags);
 	itv->cur_dma_stream = s->type;
-	itv->dma_timer.expires = jiffies + HZ / 10;
+	itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
 	add_timer(&itv->dma_timer);
 }
 
@@ -445,27 +461,44 @@
 {
 	struct ivtv_stream *s = NULL;
 	struct ivtv_buffer *buf;
-	int hw_stream_type;
+	int hw_stream_type = 0;
 
-	IVTV_DEBUG_IRQ("DEC DMA READ\n");
-	del_timer(&itv->dma_timer);
-	if (read_reg(IVTV_REG_DMASTATUS) & 0x14) {
-		IVTV_DEBUG_WARN("DEC DMA ERROR %x\n", read_reg(IVTV_REG_DMASTATUS));
-		write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
+	IVTV_DEBUG_HI_IRQ("DEC DMA READ\n");
+	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0) {
+		del_timer(&itv->dma_timer);
+		return;
 	}
-	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
-		if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags)) {
-			s = &itv->streams[IVTV_DEC_STREAM_TYPE_YUV];
-			hw_stream_type = 2;
-		}
-		else {
-			s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
-			hw_stream_type = 0;
-		}
-		IVTV_DEBUG_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
 
+	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
+		s = &itv->streams[itv->cur_dma_stream];
 		ivtv_stream_sync_for_cpu(s);
 
+		if (read_reg(IVTV_REG_DMASTATUS) & 0x14) {
+			IVTV_DEBUG_WARN("DEC DMA ERROR %x (xfer %d of %d, retry %d)\n",
+					read_reg(IVTV_REG_DMASTATUS),
+					s->sg_processed, s->sg_processing_size, itv->dma_retries);
+			write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
+			if (itv->dma_retries == 3) {
+				/* Too many retries, give up on this frame */
+				itv->dma_retries = 0;
+				s->sg_processed = s->sg_processing_size;
+			}
+			else {
+				/* Retry, starting with the first xfer segment.
+				   Just retrying the current segment is not sufficient. */
+				s->sg_processed = 0;
+				itv->dma_retries++;
+			}
+		}
+		if (s->sg_processed < s->sg_processing_size) {
+			/* DMA next buffer */
+			ivtv_dma_dec_start_xfer(s);
+			return;
+		}
+		if (s->type == IVTV_DEC_STREAM_TYPE_YUV)
+			hw_stream_type = 2;
+		IVTV_DEBUG_HI_DMA("DEC DATA READ %s: %d\n", s->name, s->q_dma.bytesused);
+
 		/* For some reason must kick the firmware, like PIO mode,
 		   I think this tells the firmware we are done and the size
 		   of the xfer so it can calculate what we need next.
@@ -482,6 +515,7 @@
 		}
 		wake_up(&s->waitq);
 	}
+	del_timer(&itv->dma_timer);
 	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
 	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
 	itv->cur_dma_stream = -1;
@@ -493,33 +527,46 @@
 	u32 data[CX2341X_MBOX_MAX_DATA];
 	struct ivtv_stream *s;
 
-	del_timer(&itv->dma_timer);
 	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data);
-	IVTV_DEBUG_IRQ("ENC DMA COMPLETE %x %d\n", data[0], data[1]);
-	if (test_and_clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags))
-		data[1] = 3;
-	else if (data[1] > 2)
+	IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream);
+	if (itv->cur_dma_stream < 0) {
+		del_timer(&itv->dma_timer);
 		return;
-	s = &itv->streams[ivtv_stream_map[data[1]]];
-	if (data[0] & 0x18) {
-		IVTV_DEBUG_WARN("ENC DMA ERROR %x\n", data[0]);
-		write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
-		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, data[1]);
 	}
-	s->SG_length = 0;
+	s = &itv->streams[itv->cur_dma_stream];
+	ivtv_stream_sync_for_cpu(s);
+
+	if (data[0] & 0x18) {
+		IVTV_DEBUG_WARN("ENC DMA ERROR %x (offset %08x, xfer %d of %d, retry %d)\n", data[0],
+			s->dma_offset, s->sg_processed, s->sg_processing_size, itv->dma_retries);
+		write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
+		if (itv->dma_retries == 3) {
+			/* Too many retries, give up on this frame */
+			itv->dma_retries = 0;
+			s->sg_processed = s->sg_processing_size;
+		}
+		else {
+			/* Retry, starting with the first xfer segment.
+			   Just retrying the current segment is not sufficient. */
+			s->sg_processed = 0;
+			itv->dma_retries++;
+		}
+	}
+	if (s->sg_processed < s->sg_processing_size) {
+		/* DMA next buffer */
+		ivtv_dma_enc_start_xfer(s);
+		return;
+	}
+	del_timer(&itv->dma_timer);
 	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
 	itv->cur_dma_stream = -1;
 	dma_post(s);
-	ivtv_stream_sync_for_cpu(s);
 	if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) {
-		u32 tmp;
-
 		s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
-		tmp = s->dma_offset;
-		s->dma_offset = itv->vbi.dma_offset;
 		dma_post(s);
-		s->dma_offset = tmp;
 	}
+	s->sg_processing_size = 0;
+	s->sg_processed = 0;
 	wake_up(&itv->dma_waitq);
 }
 
@@ -532,9 +579,7 @@
 		return;
 	}
 	s = &itv->streams[itv->cur_pio_stream];
-	IVTV_DEBUG_IRQ("ENC PIO COMPLETE %s\n", s->name);
-	s->SG_length = 0;
-	clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
+	IVTV_DEBUG_HI_IRQ("ENC PIO COMPLETE %s\n", s->name);
 	clear_bit(IVTV_F_I_PIO, &itv->i_flags);
 	itv->cur_pio_stream = -1;
 	dma_post(s);
@@ -546,13 +591,8 @@
 		ivtv_vapi(itv, CX2341X_ENC_SCHED_DMA_TO_HOST, 3, 0, 0, 2);
 	clear_bit(IVTV_F_I_PIO, &itv->i_flags);
 	if (test_and_clear_bit(IVTV_F_S_DMA_HAS_VBI, &s->s_flags)) {
-		u32 tmp;
-
 		s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
-		tmp = s->dma_offset;
-		s->dma_offset = itv->vbi.dma_offset;
 		dma_post(s);
-		s->dma_offset = tmp;
 	}
 	wake_up(&itv->dma_waitq);
 }
@@ -564,19 +604,23 @@
 	del_timer(&itv->dma_timer);
 	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data);
 	IVTV_DEBUG_WARN("DMA ERROR %08x %08x %08x %d\n", data[0], data[1],
-					read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream);
+				read_reg(IVTV_REG_DMASTATUS), itv->cur_dma_stream);
+	write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
 	if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) &&
 	    itv->cur_dma_stream >= 0 && itv->cur_dma_stream < IVTV_MAX_STREAMS) {
 		struct ivtv_stream *s = &itv->streams[itv->cur_dma_stream];
 
 		/* retry */
-		write_reg(read_reg(IVTV_REG_DMASTATUS) & 3, IVTV_REG_DMASTATUS);
 		if (s->type >= IVTV_DEC_STREAM_TYPE_MPG)
 			ivtv_dma_dec_start(s);
 		else
 			ivtv_dma_enc_start(s);
 		return;
 	}
+	if (test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
+		ivtv_udma_start(itv);
+		return;
+	}
 	clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
 	clear_bit(IVTV_F_I_DMA, &itv->i_flags);
 	itv->cur_dma_stream = -1;
@@ -590,14 +634,13 @@
 
 	/* Get DMA destination and size arguments from card */
 	ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA, data);
-	IVTV_DEBUG_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
+	IVTV_DEBUG_HI_IRQ("ENC START CAP %d: %08x %08x\n", data[0], data[1], data[2]);
 
 	if (data[0] > 2 || data[1] == 0 || data[2] == 0) {
 		IVTV_DEBUG_WARN("Unknown input: %08x %08x %08x\n",
 				data[0], data[1], data[2]);
 		return;
 	}
-	clear_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
 	s = &itv->streams[ivtv_stream_map[data[0]]];
 	if (!stream_enc_dma_append(s, data)) {
 		set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
@@ -610,7 +653,7 @@
 	u32 data[CX2341X_MBOX_MAX_DATA];
 	struct ivtv_stream *s;
 
-	IVTV_DEBUG_IRQ("ENC START VBI CAP\n");
+	IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n");
 	s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
 
 	/* If more than two VBI buffers are pending, then
@@ -621,20 +664,17 @@
 	   DMA the data. Since at most four VBI DMA buffers are available,
 	   we just drop the old requests when there are already three
 	   requests queued. */
-	if (s->SG_length > 2) {
-		struct list_head *p;
-		list_for_each(p, &s->q_predma.list) {
-			struct ivtv_buffer *buf = list_entry(p, struct ivtv_buffer, list);
+	if (s->sg_pending_size > 2) {
+		struct ivtv_buffer *buf;
+		list_for_each_entry(buf, &s->q_predma.list, list)
 			ivtv_buf_sync_for_cpu(s, buf);
-		}
 		ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0);
-		s->SG_length = 0;
+		s->sg_pending_size = 0;
 	}
 	/* if we can append the data, and the MPEG stream isn't capturing,
 	   then start a DMA request for just the VBI data. */
 	if (!stream_enc_dma_append(s, data) &&
 			!test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) {
-		set_bit(IVTV_F_I_ENC_VBI, &itv->i_flags);
 		set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags);
 	}
 }
@@ -644,7 +684,7 @@
 	u32 data[CX2341X_MBOX_MAX_DATA];
 	struct ivtv_stream *s = &itv->streams[IVTV_DEC_STREAM_TYPE_VBI];
 
-	IVTV_DEBUG_IRQ("DEC VBI REINSERT\n");
+	IVTV_DEBUG_HI_IRQ("DEC VBI REINSERT\n");
 	if (test_bit(IVTV_F_S_CLAIMED, &s->s_flags) &&
 			!stream_enc_dma_append(s, data)) {
 		set_bit(IVTV_F_S_PIO_PENDING, &s->s_flags);
@@ -669,7 +709,7 @@
 		itv->dma_data_req_offset = data[1];
 		s = &itv->streams[IVTV_DEC_STREAM_TYPE_MPG];
 	}
-	IVTV_DEBUG_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused,
+	IVTV_DEBUG_HI_IRQ("DEC DATA REQ %s: %d %08x %u\n", s->name, s->q_full.bytesused,
 		       itv->dma_data_req_offset, itv->dma_data_req_size);
 	if (itv->dma_data_req_size == 0 || s->q_full.bytesused < itv->dma_data_req_size) {
 		set_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
@@ -695,23 +735,27 @@
 
 	if (0) IVTV_DEBUG_IRQ("DEC VSYNC\n");
 
-	if (((frame ^ itv->yuv_info.lace_sync_field) == 0 && ((itv->lastVsyncFrame & 1) ^ itv->yuv_info.lace_sync_field)) ||
-			(frame != (itv->lastVsyncFrame & 1) && !itv->yuv_info.frame_interlaced)) {
+	if (((frame ^ itv->yuv_info.sync_field[last_dma_frame]) == 0 &&
+		((itv->last_vsync_field & 1) ^ itv->yuv_info.sync_field[last_dma_frame])) ||
+			(frame != (itv->last_vsync_field & 1) && !itv->yuv_info.frame_interlaced)) {
 		int next_dma_frame = last_dma_frame;
 
-		if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) {
-			write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
-			write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
-			write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
-			write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
-			next_dma_frame = (next_dma_frame + 1) & 0x3;
-			atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame);
+		if (!(itv->yuv_info.frame_interlaced && itv->yuv_info.field_delay[next_dma_frame] && itv->yuv_info.fields_lapsed < 1)) {
+			if (next_dma_frame >= 0 && next_dma_frame != atomic_read(&itv->yuv_info.next_fill_frame)) {
+				write_reg(yuv_offset[next_dma_frame] >> 4, 0x82c);
+				write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x830);
+				write_reg(yuv_offset[next_dma_frame] >> 4, 0x834);
+				write_reg((yuv_offset[next_dma_frame] + IVTV_YUV_BUFFER_UV_OFFSET) >> 4, 0x838);
+				next_dma_frame = (next_dma_frame + 1) & 0x3;
+				atomic_set(&itv->yuv_info.next_dma_frame, next_dma_frame);
+				itv->yuv_info.fields_lapsed = -1;
+			}
 		}
 	}
-	if (frame != (itv->lastVsyncFrame & 1)) {
+	if (frame != (itv->last_vsync_field & 1)) {
 		struct ivtv_stream *s = ivtv_get_output_stream(itv);
 
-		itv->lastVsyncFrame += 1;
+		itv->last_vsync_field += 1;
 		if (frame == 0) {
 			clear_bit(IVTV_F_I_VALID_DEC_TIMINGS, &itv->i_flags);
 			clear_bit(IVTV_F_I_EV_VSYNC_FIELD, &itv->i_flags);
@@ -728,7 +772,10 @@
 			wake_up(&s->waitq);
 
 		/* Send VBI to saa7127 */
-		if (frame) {
+		if (frame && (itv->output_mode == OUT_PASSTHROUGH ||
+			test_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags) ||
+			test_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags) ||
+			test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags))) {
 			set_bit(IVTV_F_I_WORK_HANDLER_VBI, &itv->i_flags);
 			set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
 		}
@@ -746,10 +793,12 @@
 				set_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags);
 			}
 		}
+
+		itv->yuv_info.fields_lapsed ++;
 	}
 }
 
-#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ)
+#define IVTV_IRQ_DMA (IVTV_IRQ_DMA_READ | IVTV_IRQ_ENC_DMA_COMPLETE | IVTV_IRQ_DMA_ERR | IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_VBI_CAP | IVTV_IRQ_DEC_DATA_REQ | IVTV_IRQ_DEC_VBI_RE_INSERT)
 
 irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
 {
@@ -774,7 +823,7 @@
 		 */
 		if (~itv->irqmask & IVTV_IRQ_DEC_VSYNC) {
 			/* vsync is enabled, see if we're in a new field */
-			if ((itv->lastVsyncFrame & 1) != (read_reg(0x28c0) & 1)) {
+			if ((itv->last_vsync_field & 1) != (read_reg(0x28c0) & 1)) {
 				/* New field, looks like we missed it */
 				IVTV_DEBUG_YUV("VSync interrupt missed %d\n",read_reg(0x28c0)>>16);
 				vsync_force = 1;
@@ -791,10 +840,10 @@
 	/* Exclude interrupts noted below from the output, otherwise the log is flooded with
 	   these messages */
 	if (combo & ~0xff6d0400)
-		IVTV_DEBUG_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo);
+		IVTV_DEBUG_HI_IRQ("======= valid IRQ bits: 0x%08x ======\n", combo);
 
 	if (combo & IVTV_IRQ_DEC_DMA_COMPLETE) {
-		IVTV_DEBUG_IRQ("DEC DMA COMPLETE\n");
+		IVTV_DEBUG_HI_IRQ("DEC DMA COMPLETE\n");
 	}
 
 	if (combo & IVTV_IRQ_DMA_READ) {
@@ -828,7 +877,7 @@
 	if (combo & IVTV_IRQ_ENC_EOS) {
 		IVTV_DEBUG_IRQ("ENC EOS\n");
 		set_bit(IVTV_F_I_EOS, &itv->i_flags);
-		wake_up(&itv->cap_w);
+		wake_up(&itv->eos_waitq);
 	}
 
 	if (combo & IVTV_IRQ_DEC_DATA_REQ) {
@@ -850,8 +899,9 @@
 	}
 
 	if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_DMA, &itv->i_flags)) {
+		itv->irq_rr_idx++;
 		for (i = 0; i < IVTV_MAX_STREAMS; i++) {
-			int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS;
+			int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS;
 			struct ivtv_stream *s = &itv->streams[idx];
 
 			if (!test_and_clear_bit(IVTV_F_S_DMA_PENDING, &s->s_flags))
@@ -868,8 +918,9 @@
 	}
 
 	if ((combo & IVTV_IRQ_DMA) && !test_bit(IVTV_F_I_PIO, &itv->i_flags)) {
+		itv->irq_rr_idx++;
 		for (i = 0; i < IVTV_MAX_STREAMS; i++) {
-			int idx = (i + itv->irq_rr_idx++) % IVTV_MAX_STREAMS;
+			int idx = (i + itv->irq_rr_idx) % IVTV_MAX_STREAMS;
 			struct ivtv_stream *s = &itv->streams[idx];
 
 			if (!test_and_clear_bit(IVTV_F_S_PIO_PENDING, &s->s_flags))
@@ -880,8 +931,9 @@
 		}
 	}
 
-	if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags))
+	if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) {
 		queue_work(itv->irq_work_queues, &itv->irq_work_queue);
+	}
 
 	spin_unlock(&itv->dma_reg_lock);
 
diff --git a/drivers/media/video/ivtv/ivtv-irq.h b/drivers/media/video/ivtv/ivtv-irq.h
index a43348a..f879a58 100644
--- a/drivers/media/video/ivtv/ivtv-irq.h
+++ b/drivers/media/video/ivtv/ivtv-irq.h
@@ -19,8 +19,35 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#ifndef IVTV_IRQ_H
+#define IVTV_IRQ_H
+
+#define IVTV_IRQ_ENC_START_CAP		(0x1 << 31)
+#define IVTV_IRQ_ENC_EOS		(0x1 << 30)
+#define IVTV_IRQ_ENC_VBI_CAP		(0x1 << 29)
+#define IVTV_IRQ_ENC_VIM_RST		(0x1 << 28)
+#define IVTV_IRQ_ENC_DMA_COMPLETE	(0x1 << 27)
+#define IVTV_IRQ_ENC_PIO_COMPLETE	(0x1 << 25)
+#define IVTV_IRQ_DEC_AUD_MODE_CHG	(0x1 << 24)
+#define IVTV_IRQ_DEC_DATA_REQ		(0x1 << 22)
+#define IVTV_IRQ_DEC_DMA_COMPLETE	(0x1 << 20)
+#define IVTV_IRQ_DEC_VBI_RE_INSERT	(0x1 << 19)
+#define IVTV_IRQ_DMA_ERR		(0x1 << 18)
+#define IVTV_IRQ_DMA_WRITE		(0x1 << 17)
+#define IVTV_IRQ_DMA_READ		(0x1 << 16)
+#define IVTV_IRQ_DEC_VSYNC		(0x1 << 10)
+
+/* IRQ Masks */
+#define IVTV_IRQ_MASK_INIT (IVTV_IRQ_DMA_ERR|IVTV_IRQ_ENC_DMA_COMPLETE|\
+		IVTV_IRQ_DMA_READ|IVTV_IRQ_ENC_PIO_COMPLETE)
+
+#define IVTV_IRQ_MASK_CAPTURE (IVTV_IRQ_ENC_START_CAP | IVTV_IRQ_ENC_EOS)
+#define IVTV_IRQ_MASK_DECODE  (IVTV_IRQ_DEC_DATA_REQ|IVTV_IRQ_DEC_AUD_MODE_CHG)
+
 irqreturn_t ivtv_irq_handler(int irq, void *dev_id);
 
 void ivtv_irq_work_handler(struct work_struct *work);
 void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock);
 void ivtv_unfinished_dma(unsigned long arg);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c
index 6ae42a3..b05436d 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.c
+++ b/drivers/media/video/ivtv/ivtv-mailbox.c
@@ -37,8 +37,10 @@
 #define API_RESULT	 (1 << 1) 	/* Allow 1 second for this cmd to end */
 #define API_FAST_RESULT	 (3 << 1)	/* Allow 0.1 second for this cmd to end */
 #define API_DMA 	 (1 << 3)	/* DMA mailbox, has special handling */
+#define API_HIGH_VOL 	 (1 << 5)	/* High volume command (i.e. called during encoding or decoding) */
 #define API_NO_WAIT_MB 	 (1 << 4)	/* Command may not wait for a free mailbox */
 #define API_NO_WAIT_RES	 (1 << 5)	/* Command may not wait for the result */
+#define API_NO_POLL	 (1 << 6)	/* Avoid pointless polling */
 
 struct ivtv_api_info {
 	int flags;		/* Flags, see above */
@@ -50,7 +52,7 @@
 static const struct ivtv_api_info api_info[256] = {
 	/* MPEG encoder API */
 	API_ENTRY(CX2341X_ENC_PING_FW, 			API_FAST_RESULT),
-	API_ENTRY(CX2341X_ENC_START_CAPTURE, 		API_RESULT),
+	API_ENTRY(CX2341X_ENC_START_CAPTURE, 		API_RESULT | API_NO_POLL),
 	API_ENTRY(CX2341X_ENC_STOP_CAPTURE, 		API_RESULT),
 	API_ENTRY(CX2341X_ENC_SET_AUDIO_ID, 		API_CACHE),
 	API_ENTRY(CX2341X_ENC_SET_VIDEO_ID, 		API_CACHE),
@@ -77,11 +79,11 @@
 	API_ENTRY(CX2341X_ENC_SET_DMA_BLOCK_SIZE, 	API_CACHE),
 	API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_10, 	API_FAST_RESULT),
 	API_ENTRY(CX2341X_ENC_GET_PREV_DMA_INFO_MB_9, 	API_FAST_RESULT),
-	API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, 	API_DMA),
+	API_ENTRY(CX2341X_ENC_SCHED_DMA_TO_HOST, 	API_DMA | API_HIGH_VOL),
 	API_ENTRY(CX2341X_ENC_INITIALIZE_INPUT, 	API_RESULT),
 	API_ENTRY(CX2341X_ENC_SET_FRAME_DROP_RATE, 	API_CACHE),
 	API_ENTRY(CX2341X_ENC_PAUSE_ENCODER, 		API_RESULT),
-	API_ENTRY(CX2341X_ENC_REFRESH_INPUT, 		API_NO_WAIT_MB),
+	API_ENTRY(CX2341X_ENC_REFRESH_INPUT, 		API_NO_WAIT_MB | API_HIGH_VOL),
 	API_ENTRY(CX2341X_ENC_SET_COPYRIGHT, 		API_CACHE),
 	API_ENTRY(CX2341X_ENC_SET_EVENT_NOTIFICATION, 	API_RESULT),
 	API_ENTRY(CX2341X_ENC_SET_NUM_VSYNC_LINES, 	API_CACHE),
@@ -95,14 +97,14 @@
 
 	/* MPEG decoder API */
 	API_ENTRY(CX2341X_DEC_PING_FW, 			API_FAST_RESULT),
-	API_ENTRY(CX2341X_DEC_START_PLAYBACK, 		API_RESULT),
+	API_ENTRY(CX2341X_DEC_START_PLAYBACK, 		API_RESULT | API_NO_POLL),
 	API_ENTRY(CX2341X_DEC_STOP_PLAYBACK, 		API_RESULT),
 	API_ENTRY(CX2341X_DEC_SET_PLAYBACK_SPEED, 	API_RESULT),
 	API_ENTRY(CX2341X_DEC_STEP_VIDEO, 		API_RESULT),
 	API_ENTRY(CX2341X_DEC_SET_DMA_BLOCK_SIZE, 	API_CACHE),
 	API_ENTRY(CX2341X_DEC_GET_XFER_INFO, 		API_FAST_RESULT),
 	API_ENTRY(CX2341X_DEC_GET_DMA_STATUS, 		API_FAST_RESULT),
-	API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, 	API_DMA),
+	API_ENTRY(CX2341X_DEC_SCHED_DMA_FROM_HOST, 	API_DMA | API_HIGH_VOL),
 	API_ENTRY(CX2341X_DEC_PAUSE_PLAYBACK, 		API_RESULT),
 	API_ENTRY(CX2341X_DEC_HALT_FW, 			API_FAST_RESULT),
 	API_ENTRY(CX2341X_DEC_SET_STANDARD, 		API_CACHE),
@@ -175,9 +177,9 @@
 
 		/* Sleep before a retry, if not atomic */
 		if (!(flags & API_NO_WAIT_MB)) {
-			if (jiffies - then > retries * HZ / 100)
+			if (jiffies - then > msecs_to_jiffies(10*retries))
 			       break;
-			ivtv_sleep_timeout(HZ / 100, 0);
+			ivtv_msleep_timeout(10, 0);
 		}
 	}
 	return -ENODEV;
@@ -212,7 +214,7 @@
 {
 	struct ivtv_mailbox_data *mbdata = (cmd >= 128) ? &itv->enc_mbox : &itv->dec_mbox;
 	volatile struct ivtv_mailbox __iomem *mbox;
-	int api_timeout = HZ;
+	int api_timeout = msecs_to_jiffies(1000);
 	int flags, mb, i;
 	unsigned long then;
 
@@ -223,11 +225,16 @@
 	}
 	if (args < 0 || args > CX2341X_MBOX_MAX_DATA ||
 	    cmd < 0 || cmd > 255 || api_info[cmd].name == NULL) {
-		IVTV_ERR("Invalid API call: cmd = 0x%02x, args = %d\n", cmd, args);
+		IVTV_ERR("Invalid MB call: cmd = 0x%02x, args = %d\n", cmd, args);
 		return -EINVAL;
 	}
 
-	IVTV_DEBUG_API("API Call: %s\n", api_info[cmd].name);
+	if (api_info[cmd].flags & API_HIGH_VOL) {
+	    IVTV_DEBUG_HI_MB("MB Call: %s\n", api_info[cmd].name);
+	}
+	else {
+	    IVTV_DEBUG_MB("MB Call: %s\n", api_info[cmd].name);
+	}
 
 	/* clear possibly uninitialized part of data array */
 	for (i = args; i < CX2341X_MBOX_MAX_DATA; i++)
@@ -237,7 +244,7 @@
 	   data, then just return 0 as there is no need to issue this command again.
 	   Just an optimization to prevent unnecessary use of mailboxes. */
 	if (itv->api_cache[cmd].last_jiffies &&
-	    jiffies - itv->api_cache[cmd].last_jiffies < HZ * 1800 &&
+	    jiffies - itv->api_cache[cmd].last_jiffies < msecs_to_jiffies(1800000) &&
 	    !memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) {
 		itv->api_cache[cmd].last_jiffies = jiffies;
 		return 0;
@@ -262,7 +269,7 @@
 	}
 
 	if ((flags & API_FAST_RESULT) == API_FAST_RESULT)
-		api_timeout = HZ / 10;
+		api_timeout = msecs_to_jiffies(100);
 
 	mb = get_mailbox(itv, mbdata, flags);
 	if (mb < 0) {
@@ -284,6 +291,13 @@
 	/* Get results */
 	then = jiffies;
 
+	if (!(flags & API_NO_POLL)) {
+		/* First try to poll, then switch to delays */
+		for (i = 0; i < 100; i++) {
+			if (readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)
+				break;
+		}
+	}
 	while (!(readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)) {
 		if (jiffies - then > api_timeout) {
 			IVTV_DEBUG_WARN("Could not get result (%s)\n", api_info[cmd].name);
@@ -295,11 +309,12 @@
 		if (flags & API_NO_WAIT_RES)
 			mdelay(1);
 		else
-			ivtv_sleep_timeout(HZ / 100, 0);
+			ivtv_msleep_timeout(1, 0);
 	}
-	if (jiffies - then > HZ / 10)
-		IVTV_DEBUG_WARN("%s took %lu jiffies (%d per HZ)\n",
-				api_info[cmd].name, jiffies - then, HZ);
+	if (jiffies - then > msecs_to_jiffies(100))
+		IVTV_DEBUG_WARN("%s took %u jiffies\n",
+				api_info[cmd].name,
+				jiffies_to_msecs(jiffies - then));
 
 	for (i = 0; i < CX2341X_MBOX_MAX_DATA; i++)
 		data[i] = readl(&mbox->data[i]);
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h
index 79b8aec..71a54ee 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.h
+++ b/drivers/media/video/ivtv/ivtv-mailbox.h
@@ -18,8 +18,16 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#ifndef IVTV_MAILBOX_H
+#define IVTV_MAILBOX_H
+
+#define IVTV_MBOX_DMA_END         8
+#define IVTV_MBOX_DMA             9
+
 void ivtv_api_get_data(struct ivtv_mailbox_data *mbox, int mb, u32 data[]);
 int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]);
 int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...);
 int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...);
 int ivtv_api_func(void *priv, int cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c
index a04f938..39a2167 100644
--- a/drivers/media/video/ivtv/ivtv-queue.c
+++ b/drivers/media/video/ivtv/ivtv-queue.c
@@ -20,9 +20,7 @@
  */
 
 #include "ivtv-driver.h"
-#include "ivtv-streams.h"
 #include "ivtv-queue.h"
-#include "ivtv-mailbox.h"
 
 int ivtv_buf_copy_from_user(struct ivtv_stream *s, struct ivtv_buffer *buf, const char __user *src, int copybytes)
 {
@@ -60,6 +58,7 @@
 		buf->bytesused = 0;
 		buf->readpos = 0;
 		buf->b_flags = 0;
+		buf->dma_xfer_cnt = 0;
 	}
 	spin_lock_irqsave(&s->qlock, flags);
 	list_add_tail(&buf->list, &q->list);
@@ -87,7 +86,7 @@
 }
 
 static void ivtv_queue_move_buf(struct ivtv_stream *s, struct ivtv_queue *from,
-		struct ivtv_queue *to, int clear, int full)
+		struct ivtv_queue *to, int clear)
 {
 	struct ivtv_buffer *buf = list_entry(from->list.next, struct ivtv_buffer, list);
 
@@ -97,13 +96,7 @@
 	from->bytesused -= buf->bytesused - buf->readpos;
 	/* special handling for q_free */
 	if (clear)
-		buf->bytesused = buf->readpos = buf->b_flags = 0;
-	else if (full) {
-		/* special handling for stolen buffers, assume
-		   all bytes are used. */
-		buf->bytesused = s->buf_size;
-		buf->readpos = buf->b_flags = 0;
-	}
+		buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0;
 	to->buffers++;
 	to->length += s->buf_size;
 	to->bytesused += buf->bytesused - buf->readpos;
@@ -112,7 +105,7 @@
 /* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'.
    If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'.
    If 'steal' != NULL, then buffers may also taken from that queue if
-   needed.
+   needed, but only if 'from' is the free queue.
 
    The buffer is automatically cleared if it goes to the free queue. It is
    also cleared if buffers need to be taken from the 'steal' queue and
@@ -133,7 +126,7 @@
 	int rc = 0;
 	int from_free = from == &s->q_free;
 	int to_free = to == &s->q_free;
-	int bytes_available;
+	int bytes_available, bytes_steal;
 
 	spin_lock_irqsave(&s->qlock, flags);
 	if (needed_bytes == 0) {
@@ -142,32 +135,47 @@
 	}
 
 	bytes_available = from_free ? from->length : from->bytesused;
-	bytes_available += steal ? steal->length : 0;
+	bytes_steal = (from_free && steal) ? steal->length : 0;
 
-	if (bytes_available < needed_bytes) {
+	if (bytes_available + bytes_steal < needed_bytes) {
 		spin_unlock_irqrestore(&s->qlock, flags);
 		return -ENOMEM;
 	}
+	while (bytes_available < needed_bytes) {
+		struct ivtv_buffer *buf = list_entry(steal->list.prev, struct ivtv_buffer, list);
+		u16 dma_xfer_cnt = buf->dma_xfer_cnt;
+
+		/* move buffers from the tail of the 'steal' queue to the tail of the
+		   'from' queue. Always copy all the buffers with the same dma_xfer_cnt
+		   value, this ensures that you do not end up with partial frame data
+		   if one frame is stored in multiple buffers. */
+		while (dma_xfer_cnt == buf->dma_xfer_cnt) {
+			list_move_tail(steal->list.prev, &from->list);
+			rc++;
+			steal->buffers--;
+			steal->length -= s->buf_size;
+			steal->bytesused -= buf->bytesused - buf->readpos;
+			buf->bytesused = buf->readpos = buf->b_flags = buf->dma_xfer_cnt = 0;
+			from->buffers++;
+			from->length += s->buf_size;
+			bytes_available += s->buf_size;
+			if (list_empty(&steal->list))
+				break;
+			buf = list_entry(steal->list.prev, struct ivtv_buffer, list);
+		}
+	}
 	if (from_free) {
 		u32 old_length = to->length;
 
 		while (to->length - old_length < needed_bytes) {
-			if (list_empty(&from->list))
-				from = steal;
-			if (from == steal)
-				rc++; 		/* keep track of 'stolen' buffers */
-			ivtv_queue_move_buf(s, from, to, 1, 0);
+			ivtv_queue_move_buf(s, from, to, 1);
 		}
 	}
 	else {
 		u32 old_bytesused = to->bytesused;
 
 		while (to->bytesused - old_bytesused < needed_bytes) {
-			if (list_empty(&from->list))
-				from = steal;
-			if (from == steal)
-				rc++; 		/* keep track of 'stolen' buffers */
-			ivtv_queue_move_buf(s, from, to, to_free, rc);
+			ivtv_queue_move_buf(s, from, to, to_free);
 		}
 	}
 	spin_unlock_irqrestore(&s->qlock, flags);
@@ -185,7 +193,7 @@
 int ivtv_stream_alloc(struct ivtv_stream *s)
 {
 	struct ivtv *itv = s->itv;
-	int SGsize = sizeof(struct ivtv_SG_element) * s->buffers;
+	int SGsize = sizeof(struct ivtv_sg_element) * s->buffers;
 	int i;
 
 	if (s->buffers == 0)
@@ -195,27 +203,33 @@
 		s->dma != PCI_DMA_NONE ? "DMA " : "",
 		s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024);
 
-	if (ivtv_might_use_pio(s)) {
-		s->PIOarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL);
-		if (s->PIOarray == NULL) {
-			IVTV_ERR("Could not allocate PIOarray for %s stream\n", s->name);
-			return -ENOMEM;
-		}
-	}
-
-	/* Allocate DMA SG Arrays */
-	s->SGarray = (struct ivtv_SG_element *)kzalloc(SGsize, GFP_KERNEL);
-	if (s->SGarray == NULL) {
-		IVTV_ERR("Could not allocate SGarray for %s stream\n", s->name);
-		if (ivtv_might_use_pio(s)) {
-			kfree(s->PIOarray);
-			s->PIOarray = NULL;
-		}
+	s->sg_pending = kzalloc(SGsize, GFP_KERNEL);
+	if (s->sg_pending == NULL) {
+		IVTV_ERR("Could not allocate sg_pending for %s stream\n", s->name);
 		return -ENOMEM;
 	}
-	s->SG_length = 0;
+	s->sg_pending_size = 0;
+
+	s->sg_processing = kzalloc(SGsize, GFP_KERNEL);
+	if (s->sg_processing == NULL) {
+		IVTV_ERR("Could not allocate sg_processing for %s stream\n", s->name);
+		kfree(s->sg_pending);
+		s->sg_pending = NULL;
+		return -ENOMEM;
+	}
+	s->sg_processing_size = 0;
+
+	s->sg_dma = kzalloc(sizeof(struct ivtv_sg_element), GFP_KERNEL);
+	if (s->sg_dma == NULL) {
+		IVTV_ERR("Could not allocate sg_dma for %s stream\n", s->name);
+		kfree(s->sg_pending);
+		s->sg_pending = NULL;
+		kfree(s->sg_processing);
+		s->sg_processing = NULL;
+		return -ENOMEM;
+	}
 	if (ivtv_might_use_dma(s)) {
-		s->SG_handle = pci_map_single(itv->dev, s->SGarray, SGsize, s->dma);
+		s->sg_handle = pci_map_single(itv->dev, s->sg_dma, sizeof(struct ivtv_sg_element), s->dma);
 		ivtv_stream_sync_for_cpu(s);
 	}
 
@@ -262,16 +276,19 @@
 	}
 
 	/* Free SG Array/Lists */
-	if (s->SGarray != NULL) {
-		if (s->SG_handle != IVTV_DMA_UNMAPPED) {
-			pci_unmap_single(s->itv->dev, s->SG_handle,
-				 sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
-			s->SG_handle = IVTV_DMA_UNMAPPED;
+	if (s->sg_dma != NULL) {
+		if (s->sg_handle != IVTV_DMA_UNMAPPED) {
+			pci_unmap_single(s->itv->dev, s->sg_handle,
+				 sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
+			s->sg_handle = IVTV_DMA_UNMAPPED;
 		}
-		kfree(s->SGarray);
-		kfree(s->PIOarray);
-		s->PIOarray = NULL;
-		s->SGarray = NULL;
-		s->SG_length = 0;
+		kfree(s->sg_pending);
+		kfree(s->sg_processing);
+		kfree(s->sg_dma);
+		s->sg_pending = NULL;
+		s->sg_processing = NULL;
+		s->sg_dma = NULL;
+		s->sg_pending_size = 0;
+		s->sg_processing_size = 0;
 	}
 }
diff --git a/drivers/media/video/ivtv/ivtv-queue.h b/drivers/media/video/ivtv/ivtv-queue.h
index 2ed8d54..7cfc0c9 100644
--- a/drivers/media/video/ivtv/ivtv-queue.h
+++ b/drivers/media/video/ivtv/ivtv-queue.h
@@ -19,6 +19,9 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#ifndef IVTV_QUEUE_H
+#define IVTV_QUEUE_H
+
 #define IVTV_DMA_UNMAPPED	((u32) -1)
 #define SLICED_VBI_PIO 1
 
@@ -79,13 +82,15 @@
 static inline void ivtv_stream_sync_for_cpu(struct ivtv_stream *s)
 {
 	if (ivtv_use_dma(s))
-		pci_dma_sync_single_for_cpu(s->itv->dev, s->SG_handle,
-			sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
+		pci_dma_sync_single_for_cpu(s->itv->dev, s->sg_handle,
+			sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
 }
 
 static inline void ivtv_stream_sync_for_device(struct ivtv_stream *s)
 {
 	if (ivtv_use_dma(s))
-		pci_dma_sync_single_for_device(s->itv->dev, s->SG_handle,
-			sizeof(struct ivtv_SG_element) * s->buffers, PCI_DMA_TODEVICE);
+		pci_dma_sync_single_for_device(s->itv->dev, s->sg_handle,
+			sizeof(struct ivtv_sg_element), PCI_DMA_TODEVICE);
 }
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-routing.c b/drivers/media/video/ivtv/ivtv-routing.c
new file mode 100644
index 0000000..398bd33
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtv-routing.c
@@ -0,0 +1,116 @@
+/*
+    Audio/video-routing-related ivtv functions.
+    Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
+    Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
+
+    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 "ivtv-driver.h"
+#include "ivtv-i2c.h"
+#include "ivtv-cards.h"
+#include "ivtv-gpio.h"
+#include "ivtv-routing.h"
+
+#include <media/msp3400.h>
+#include <media/upd64031a.h>
+#include <media/upd64083.h>
+
+/* Selects the audio input and output according to the current
+   settings. */
+void ivtv_audio_set_io(struct ivtv *itv)
+{
+	struct v4l2_routing route;
+	u32 audio_input;
+	int mux_input;
+
+	/* Determine which input to use */
+	if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
+		audio_input = itv->card->radio_input.audio_input;
+		mux_input = itv->card->radio_input.muxer_input;
+	} else {
+		audio_input = itv->card->audio_inputs[itv->audio_input].audio_input;
+		mux_input = itv->card->audio_inputs[itv->audio_input].muxer_input;
+	}
+
+	/* handle muxer chips */
+	route.input = mux_input;
+	route.output = 0;
+	ivtv_i2c_hw(itv, itv->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+
+	route.input = audio_input;
+	if (itv->card->hw_audio & IVTV_HW_MSP34XX) {
+		route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
+	}
+	ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+}
+
+/* Selects the video input and output according to the current
+   settings. */
+void ivtv_video_set_io(struct ivtv *itv)
+{
+	struct v4l2_routing route;
+	int inp = itv->active_input;
+	u32 type;
+
+	route.input = itv->card->video_inputs[inp].video_input;
+	route.output = 0;
+	itv->video_dec_func(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+
+	type = itv->card->video_inputs[inp].video_type;
+
+	if (type == IVTV_CARD_INPUT_VID_TUNER) {
+		route.input = 0;  /* Tuner */
+	} else if (type < IVTV_CARD_INPUT_COMPOSITE1) {
+		route.input = 2;  /* S-Video */
+	} else {
+		route.input = 1;  /* Composite */
+	}
+
+	if (itv->card->hw_video & IVTV_HW_GPIO)
+		ivtv_gpio(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+
+	if (itv->card->hw_video & IVTV_HW_UPD64031A) {
+		if (type == IVTV_CARD_INPUT_VID_TUNER ||
+		    type >= IVTV_CARD_INPUT_COMPOSITE1) {
+			/* Composite: GR on, connect to 3DYCS */
+			route.input = UPD64031A_GR_ON | UPD64031A_3DYCS_COMPOSITE;
+		} else {
+			/* S-Video: GR bypassed, turn it off */
+			route.input = UPD64031A_GR_OFF | UPD64031A_3DYCS_DISABLE;
+		}
+		route.input |= itv->card->gr_config;
+
+		ivtv_upd64031a(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+	}
+
+	if (itv->card->hw_video & IVTV_HW_UPD6408X) {
+		route.input = UPD64083_YCS_MODE;
+		if (type > IVTV_CARD_INPUT_VID_TUNER &&
+		    type < IVTV_CARD_INPUT_COMPOSITE1) {
+			/* S-Video uses YCNR mode and internal Y-ADC, the upd64031a
+			   is not used. */
+			route.input |= UPD64083_YCNR_MODE;
+		}
+		else if (itv->card->hw_video & IVTV_HW_UPD64031A) {
+		  /* Use upd64031a output for tuner and composite(CX23416GYC only) inputs */
+		  if ((type == IVTV_CARD_INPUT_VID_TUNER)||
+		      (itv->card->type == IVTV_CARD_CX23416GYC)) {
+		    route.input |= UPD64083_EXT_Y_ADC;
+		  }
+		}
+		ivtv_upd64083(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+	}
+}
diff --git a/drivers/media/video/ivtv/ivtv-audio.h b/drivers/media/video/ivtv/ivtv-routing.h
similarity index 79%
rename from drivers/media/video/ivtv/ivtv-audio.h
rename to drivers/media/video/ivtv/ivtv-routing.h
index 9c42846..c72a973 100644
--- a/drivers/media/video/ivtv/ivtv-audio.h
+++ b/drivers/media/video/ivtv/ivtv-routing.h
@@ -1,5 +1,5 @@
 /*
-    Audio-related ivtv functions.
+    Audio/video-routing-related ivtv functions.
     Copyright (C) 2003-2004  Kevin Thayer <nufan_wfk at yahoo.com>
     Copyright (C) 2005-2007  Hans Verkuil <hverkuil@xs4all.nl>
 
@@ -18,6 +18,10 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-int ivtv_audio_set_io(struct ivtv *itv);
-void ivtv_audio_set_route(struct ivtv *itv, struct v4l2_routing *route);
-void ivtv_audio_set_audio_clock_freq(struct ivtv *itv, u8 freq);
+#ifndef IVTV_ROUTING_H
+#define IVTV_ROUTING_H
+
+void ivtv_audio_set_io(struct ivtv *itv);
+void ivtv_video_set_io(struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 6af88ae..fd13598 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -35,16 +35,13 @@
 
 #include "ivtv-driver.h"
 #include "ivtv-fileops.h"
-#include "ivtv-i2c.h"
 #include "ivtv-queue.h"
 #include "ivtv-mailbox.h"
-#include "ivtv-audio.h"
-#include "ivtv-video.h"
-#include "ivtv-vbi.h"
 #include "ivtv-ioctl.h"
 #include "ivtv-irq.h"
-#include "ivtv-streams.h"
+#include "ivtv-yuv.h"
 #include "ivtv-cards.h"
+#include "ivtv-streams.h"
 
 static struct file_operations ivtv_v4l2_enc_fops = {
       .owner = THIS_MODULE,
@@ -66,6 +63,13 @@
       .poll = ivtv_v4l2_dec_poll,
 };
 
+#define IVTV_V4L2_DEC_MPG_OFFSET  16	/* offset from 0 to register decoder mpg v4l2 minors on */
+#define IVTV_V4L2_ENC_PCM_OFFSET  24	/* offset from 0 to register pcm v4l2 minors on */
+#define IVTV_V4L2_ENC_YUV_OFFSET  32	/* offset from 0 to register yuv v4l2 minors on */
+#define IVTV_V4L2_DEC_YUV_OFFSET  48	/* offset from 0 to register decoder yuv v4l2 minors on */
+#define IVTV_V4L2_DEC_VBI_OFFSET   8	/* offset from 0 to register decoder vbi input v4l2 minors on */
+#define IVTV_V4L2_DEC_VOUT_OFFSET 16	/* offset from 0 to register vbi output v4l2 minors on */
+
 static struct {
 	const char *name;
 	int vfl_type;
@@ -75,7 +79,7 @@
 	struct file_operations *fops;
 } ivtv_stream_info[] = {
 	{	/* IVTV_ENC_STREAM_TYPE_MPG */
-		"encoder MPEG",
+		"encoder MPG",
 		VFL_TYPE_GRABBER, 0,
 		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_VIDEO_CAPTURE,
 		&ivtv_v4l2_enc_fops
@@ -93,7 +97,7 @@
 		&ivtv_v4l2_enc_fops
 	},
 	{	/* IVTV_ENC_STREAM_TYPE_PCM */
-		"encoder PCM audio",
+		"encoder PCM",
 		VFL_TYPE_GRABBER, IVTV_V4L2_ENC_PCM_OFFSET,
 		PCI_DMA_FROMDEVICE, 0, V4L2_BUF_TYPE_PRIVATE,
 		&ivtv_v4l2_enc_fops
@@ -105,7 +109,7 @@
 		&ivtv_v4l2_enc_fops
 	},
 	{	/* IVTV_DEC_STREAM_TYPE_MPG */
-		"decoder MPEG",
+		"decoder MPG",
 		VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET,
 		PCI_DMA_TODEVICE, 0, V4L2_BUF_TYPE_VIDEO_OUTPUT,
 		&ivtv_v4l2_dec_fops
@@ -150,11 +154,11 @@
 		s->dma = ivtv_stream_info[type].dma;
 	s->buf_size = itv->stream_buf_size[type];
 	if (s->buf_size)
-		s->buffers = itv->options.megabytes[type] * 1024 * 1024 / s->buf_size;
+		s->buffers = (itv->options.kilobytes[type] * 1024 + s->buf_size - 1) / s->buf_size;
 	spin_lock_init(&s->qlock);
 	init_waitqueue_head(&s->waitq);
 	s->id = -1;
-	s->SG_handle = IVTV_DMA_UNMAPPED;
+	s->sg_handle = IVTV_DMA_UNMAPPED;
 	ivtv_queue_init(&s->q_free);
 	ivtv_queue_init(&s->q_full);
 	ivtv_queue_init(&s->q_dma);
@@ -192,7 +196,7 @@
 	/* User explicitly selected 0 buffers for these streams, so don't
 	   create them. */
 	if (minor >= 0 && ivtv_stream_info[type].dma != PCI_DMA_NONE &&
-	    itv->options.megabytes[type] == 0) {
+	    itv->options.kilobytes[type] == 0) {
 		IVTV_INFO("Disabled %s device\n", ivtv_stream_info[type].name);
 		return 0;
 	}
@@ -238,18 +242,18 @@
 
 	switch (vfl_type) {
 	case VFL_TYPE_GRABBER:
-		IVTV_INFO("Registered device video%d for %s (%d MB)\n",
-			s->v4l2dev->minor, s->name, itv->options.megabytes[type]);
+		IVTV_INFO("Registered device video%d for %s (%d kB)\n",
+			s->v4l2dev->minor, s->name, itv->options.kilobytes[type]);
 		break;
 	case VFL_TYPE_RADIO:
 		IVTV_INFO("Registered device radio%d for %s\n",
 			s->v4l2dev->minor - MINOR_VFL_TYPE_RADIO_MIN, s->name);
 		break;
 	case VFL_TYPE_VBI:
-		if (itv->options.megabytes[type])
-			IVTV_INFO("Registered device vbi%d for %s (%d MB)\n",
+		if (itv->options.kilobytes[type])
+			IVTV_INFO("Registered device vbi%d for %s (%d kB)\n",
 				s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN,
-				s->name, itv->options.megabytes[type]);
+				s->name, itv->options.kilobytes[type]);
 		else
 			IVTV_INFO("Registered device vbi%d for %s\n",
 				s->v4l2dev->minor - MINOR_VFL_TYPE_VBI_MIN, s->name);
@@ -314,28 +318,9 @@
 	int lines;
 	int i;
 
-	/* If Embed then streamtype must be Program */
-	/* TODO: should we really do this? */
-	if (0 && !raw && itv->vbi.insert_mpeg) {
-		itv->params.stream_type = 0;
-
-		/* assign stream type */
-		ivtv_vapi(itv, CX2341X_ENC_SET_STREAM_TYPE, 1, itv->params.stream_type);
-	}
-
 	/* Reset VBI */
 	ivtv_vapi(itv, CX2341X_ENC_SET_VBI_LINE, 5, 0xffff , 0, 0, 0, 0);
 
-	if (itv->is_60hz) {
-		itv->vbi.count = 12;
-		itv->vbi.start[0] = 10;
-		itv->vbi.start[1] = 273;
-	} else {        /* PAL/SECAM */
-		itv->vbi.count = 18;
-		itv->vbi.start[0] = 6;
-		itv->vbi.start[1] = 318;
-	}
-
 	/* setup VBI registers */
 	itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
 
@@ -409,8 +394,8 @@
 	if (!itv->vbi.fpi)
 		itv->vbi.fpi = 1;
 
-	IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d lines 0x%08x\n",
-		itv->vbi.enc_start, data[1], itv->vbi.fpi, itv->digitizer);
+	IVTV_DEBUG_INFO("Setup VBI start 0x%08x frames %d fpi %d\n",
+		itv->vbi.enc_start, data[1], itv->vbi.fpi);
 
 	/* select VBI lines.
 	   Note that the sliced argument seems to have no effect. */
@@ -499,6 +484,8 @@
 	clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
 
 	if (atomic_read(&itv->capturing) == 0) {
+		int digitizer;
+
 		/* Always use frame based mode. Experiments have demonstrated that byte
 		   stream based mode results in dropped frames and corruption. Not often,
 		   but occasionally. Many thanks go to Leonard Orb who spent a lot of
@@ -524,7 +511,14 @@
 		ivtv_vapi(itv, CX2341X_ENC_SET_PLACEHOLDER, 12,
 			0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
 
-		ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, itv->digitizer, itv->digitizer);
+		if (itv->card->hw_all & (IVTV_HW_SAA7115 | IVTV_HW_SAA717X))
+		    digitizer = 0xF1;
+		else if (itv->card->hw_all & IVTV_HW_SAA7114)
+		    digitizer = 0xEF;
+		else /* cx25840 */
+		    digitizer = 0x140;
+
+		ivtv_vapi(itv, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, digitizer, digitizer);
 
 		/* Setup VBI */
 		if (itv->v4l2_cap & V4L2_CAP_VBI_CAPTURE) {
@@ -559,9 +553,10 @@
 		clear_bit(IVTV_F_I_EOS, &itv->i_flags);
 
 		/* Initialize Digitizer for Capture */
+		itv->video_dec_func(itv, VIDIOC_STREAMOFF, 0);
+		ivtv_msleep_timeout(300, 1);
 		ivtv_vapi(itv, CX2341X_ENC_INITIALIZE_INPUT, 0);
-
-		ivtv_sleep_timeout(HZ / 10, 0);
+		itv->video_dec_func(itv, VIDIOC_STREAMON, 0);
 	}
 
 	/* begin_capture */
@@ -597,10 +592,6 @@
 
 	IVTV_DEBUG_INFO("Setting some initial decoder settings\n");
 
-	/* disable VBI signals, if the MPEG stream contains VBI data,
-	   then that data will be processed automatically for you. */
-	ivtv_disable_vbi(itv);
-
 	/* set audio mode to left/stereo  for dual/stereo mode. */
 	ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
 
@@ -633,7 +624,7 @@
 	}
 	if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype,
 			itv->params.width, itv->params.height, itv->params.audio_properties)) {
-		IVTV_DEBUG_WARN("COULDN'T INITIALIZE DECODER SOURCE\n");
+		IVTV_DEBUG_WARN("Couldn't initialize decoder source\n");
 	}
 	return 0;
 }
@@ -674,10 +665,10 @@
 	clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
 
 	/* Zero out decoder counters */
-	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[0]);
-	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[1]);
-	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[2]);
-	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_FIELD_DISPLAYED].data[3]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[0]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[1]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[2]);
+	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA_END].data[3]);
 	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[0]);
 	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[1]);
 	writel(0, &itv->dec_mbox.mbox[IVTV_MBOX_DMA].data[2]);
@@ -718,9 +709,7 @@
 	struct ivtv *itv = s->itv;
 	DECLARE_WAITQUEUE(wait, current);
 	int cap_type;
-	unsigned long then;
 	int stopmode;
-	u32 data[CX2341X_MBOX_MAX_DATA];
 
 	if (s->v4l2dev == NULL)
 		return -EINVAL;
@@ -762,32 +751,20 @@
 	/* when: 0 =  end of GOP  1 = NOW!, type: 0 = mpeg, subtype: 3 = video+audio */
 	ivtv_vapi(itv, CX2341X_ENC_STOP_CAPTURE, 3, stopmode, cap_type, s->subtype);
 
-	/* only run these if we're shutting down the last cap */
-	if (atomic_read(&itv->capturing) - 1 == 0) {
-		/* event notification (off) */
-		if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
-			/* type: 0 = refresh */
-			/* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
-			ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
-			ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
-		}
-	}
-
-	then = jiffies;
-
 	if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) {
 		if (s->type == IVTV_ENC_STREAM_TYPE_MPG && gop_end) {
 			/* only run these if we're shutting down the last cap */
 			unsigned long duration;
+			unsigned long then = jiffies;
 
-			then = jiffies;
-			add_wait_queue(&itv->cap_w, &wait);
+			add_wait_queue(&itv->eos_waitq, &wait);
 
 			set_current_state(TASK_INTERRUPTIBLE);
 
 			/* wait 2s for EOS interrupt */
-			while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) && jiffies < then + 2 * HZ) {
-				schedule_timeout(HZ / 100);
+			while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) &&
+				jiffies < then + msecs_to_jiffies (2000)) {
+				schedule_timeout(msecs_to_jiffies(10));
 			}
 
 			/* To convert jiffies to ms, we must multiply by 1000
@@ -806,33 +783,12 @@
 				IVTV_DEBUG_INFO("%s: EOS took %lu ms to occur.\n", s->name, duration);
 			}
 			set_current_state(TASK_RUNNING);
-			remove_wait_queue(&itv->cap_w, &wait);
+			remove_wait_queue(&itv->eos_waitq, &wait);
+			set_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
 		}
 
-		then = jiffies;
-		/* Make sure DMA is complete */
-		add_wait_queue(&s->waitq, &wait);
-		set_current_state(TASK_INTERRUPTIBLE);
-		do {
-			/* check if DMA is pending */
-			if ((s->type == IVTV_ENC_STREAM_TYPE_MPG) &&	/* MPG Only */
-			    (read_reg(IVTV_REG_DMASTATUS) & 0x02)) {
-				/* Check for last DMA */
-				ivtv_vapi_result(itv, data, CX2341X_ENC_GET_SEQ_END, 2, 0, 0);
-
-				if (data[0] == 1) {
-					IVTV_DEBUG_DMA("%s: Last DMA of size 0x%08x\n", s->name, data[1]);
-					break;
-				}
-			} else if (read_reg(IVTV_REG_DMASTATUS) & 0x02) {
-				break;
-			}
-
-			ivtv_sleep_timeout(HZ / 100, 1);
-		} while (then + HZ * 2 > jiffies);
-
-		set_current_state(TASK_RUNNING);
-		remove_wait_queue(&s->waitq, &wait);
+		/* Handle any pending interrupts */
+		ivtv_msleep_timeout(100, 1);
 	}
 
 	atomic_dec(&itv->capturing);
@@ -849,6 +805,15 @@
 
 	/* Set the following Interrupt mask bits for capture */
 	ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
+	del_timer(&itv->dma_timer);
+
+	/* event notification (off) */
+	if (test_and_clear_bit(IVTV_F_I_DIG_RST, &itv->i_flags)) {
+		/* type: 0 = refresh */
+		/* on/off: 0 = off, intr: 0x10000000, mbox_id: -1: none */
+		ivtv_vapi(itv, CX2341X_ENC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_ENC_VIM_RST, -1);
+		ivtv_set_irq_mask(itv, IVTV_IRQ_ENC_VIM_RST);
+	}
 
 	wake_up(&s->waitq);
 
@@ -887,7 +852,7 @@
 					break;
 				tmp = data[3];
 			}
-			if (ivtv_sleep_timeout(HZ/10, 1))
+			if (ivtv_msleep_timeout(100, 1))
 				break;
 		}
 	}
@@ -897,16 +862,12 @@
 	ivtv_vapi(itv, CX2341X_DEC_SET_EVENT_NOTIFICATION, 4, 0, 0, IVTV_IRQ_DEC_AUD_MODE_CHG, -1);
 
 	ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
+	del_timer(&itv->dma_timer);
 
 	clear_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags);
 	clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
 	ivtv_flush_queues(s);
 
-	if (!test_bit(IVTV_F_S_PASSTHROUGH, &s->s_flags)) {
-		/* disable VBI on TV-out */
-		ivtv_disable_vbi(itv);
-	}
-
 	/* decrement decoding */
 	atomic_dec(&itv->decoding);
 
diff --git a/drivers/media/video/ivtv/ivtv-streams.h b/drivers/media/video/ivtv/ivtv-streams.h
index 8597b75..8f5f5b1 100644
--- a/drivers/media/video/ivtv/ivtv-streams.h
+++ b/drivers/media/video/ivtv/ivtv-streams.h
@@ -18,6 +18,9 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#ifndef IVTV_STREAMS_H
+#define IVTV_STREAMS_H
+
 int ivtv_streams_setup(struct ivtv *itv);
 void ivtv_streams_cleanup(struct ivtv *itv);
 
@@ -29,3 +32,5 @@
 
 void ivtv_stop_all_captures(struct ivtv *itv);
 int ivtv_passthrough_mode(struct ivtv *itv, int enable);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-udma.c b/drivers/media/video/ivtv/ivtv-udma.c
index bd642e1..c4626d1 100644
--- a/drivers/media/video/ivtv/ivtv-udma.c
+++ b/drivers/media/video/ivtv/ivtv-udma.c
@@ -21,7 +21,6 @@
  */
 
 #include "ivtv-driver.h"
-#include "ivtv-streams.h"
 #include "ivtv-udma.h"
 
 void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size)
@@ -38,19 +37,37 @@
 int ivtv_udma_fill_sg_list (struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset)
 {
 	int i, offset;
+	unsigned long flags;
+
+	if (map_offset < 0)
+		return map_offset;
 
 	offset = dma_page->offset;
 
 	/* Fill SG Array with new values */
 	for (i = 0; i < dma_page->page_count; i++) {
-		if (i == dma_page->page_count - 1) {
-			dma->SGlist[map_offset].length = dma_page->tail;
+		unsigned int len = (i == dma_page->page_count - 1) ?
+			dma_page->tail : PAGE_SIZE - offset;
+
+		dma->SGlist[map_offset].length = len;
+		dma->SGlist[map_offset].offset = offset;
+		if (PageHighMem(dma->map[map_offset])) {
+			void *src;
+
+			if (dma->bouncemap[map_offset] == NULL)
+				dma->bouncemap[map_offset] = alloc_page(GFP_KERNEL);
+			if (dma->bouncemap[map_offset] == NULL)
+				return -1;
+			local_irq_save(flags);
+			src = kmap_atomic(dma->map[map_offset], KM_BOUNCE_READ) + offset;
+			memcpy(page_address(dma->bouncemap[map_offset]) + offset, src, len);
+			kunmap_atomic(src, KM_BOUNCE_READ);
+			local_irq_restore(flags);
+			dma->SGlist[map_offset].page = dma->bouncemap[map_offset];
 		}
 		else {
-			dma->SGlist[map_offset].length = PAGE_SIZE - offset;
+			dma->SGlist[map_offset].page = dma->map[map_offset];
 		}
-		dma->SGlist[map_offset].offset = offset;
-		dma->SGlist[map_offset].page = dma->map[map_offset];
 		offset = 0;
 		map_offset++;
 	}
@@ -89,7 +106,7 @@
 {
 	struct ivtv_dma_page_info user_dma;
 	struct ivtv_user_dma *dma = &itv->udma;
-	int err;
+	int i, err;
 
 	IVTV_DEBUG_DMA("ivtv_udma_setup, dst: 0x%08x\n", (unsigned int)ivtv_dest_addr);
 
@@ -123,7 +140,13 @@
 	dma->page_count = user_dma.page_count;
 
 	/* Fill SG List with new values */
-	ivtv_udma_fill_sg_list(dma, &user_dma, 0);
+	if (ivtv_udma_fill_sg_list(dma, &user_dma, 0) < 0) {
+		for (i = 0; i < dma->page_count; i++) {
+			put_page(dma->map[i]);
+		}
+		dma->page_count = 0;
+		return -ENOMEM;
+	}
 
 	/* Map SG List */
 	dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
@@ -166,6 +189,8 @@
 
 void ivtv_udma_free(struct ivtv *itv)
 {
+	int i;
+
 	/* Unmap SG Array */
 	if (itv->udma.SG_handle) {
 		pci_unmap_single(itv->dev, itv->udma.SG_handle,
@@ -176,6 +201,11 @@
 	if (itv->udma.SG_length) {
 		pci_unmap_sg(itv->dev, itv->udma.SGlist, itv->udma.page_count, PCI_DMA_TODEVICE);
 	}
+
+	for (i = 0; i < IVTV_DMA_SG_OSD_ENT; i++) {
+		if (itv->udma.bouncemap[i])
+			__free_page(itv->udma.bouncemap[i]);
+	}
 }
 
 void ivtv_udma_start(struct ivtv *itv)
diff --git a/drivers/media/video/ivtv/ivtv-udma.h b/drivers/media/video/ivtv/ivtv-udma.h
index e131bcc..df727e2 100644
--- a/drivers/media/video/ivtv/ivtv-udma.h
+++ b/drivers/media/video/ivtv/ivtv-udma.h
@@ -18,6 +18,9 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#ifndef IVTV_UDMA_H
+#define IVTV_UDMA_H
+
 /* User DMA functions */
 void ivtv_udma_get_page_info(struct ivtv_dma_page_info *dma_page, unsigned long first, unsigned long size);
 int ivtv_udma_fill_sg_list(struct ivtv_user_dma *dma, struct ivtv_dma_page_info *dma_page, int map_offset);
@@ -41,3 +44,5 @@
 	pci_dma_sync_single_for_cpu((struct pci_dev *)itv->dev, itv->udma.SG_handle,
 		sizeof(itv->udma.SGarray), PCI_DMA_TODEVICE);
 }
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index 3ba46e0..c151bcf 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -18,10 +18,69 @@
  */
 
 #include "ivtv-driver.h"
-#include "ivtv-video.h"
-#include "ivtv-vbi.h"
+#include "ivtv-i2c.h"
 #include "ivtv-ioctl.h"
 #include "ivtv-queue.h"
+#include "ivtv-vbi.h"
+
+static void ivtv_set_vps(struct ivtv *itv, int enabled)
+{
+	struct v4l2_sliced_vbi_data data;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return;
+	data.id = V4L2_SLICED_VPS;
+	data.field = 0;
+	data.line = enabled ? 16 : 0;
+	data.data[2] = itv->vbi.vps_payload.data[0];
+	data.data[8] = itv->vbi.vps_payload.data[1];
+	data.data[9] = itv->vbi.vps_payload.data[2];
+	data.data[10] = itv->vbi.vps_payload.data[3];
+	data.data[11] = itv->vbi.vps_payload.data[4];
+	ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+}
+
+static void ivtv_set_cc(struct ivtv *itv, int mode, const struct vbi_cc *cc)
+{
+	struct v4l2_sliced_vbi_data data;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return;
+	data.id = V4L2_SLICED_CAPTION_525;
+	data.field = 0;
+	data.line = (mode & 1) ? 21 : 0;
+	data.data[0] = cc->odd[0];
+	data.data[1] = cc->odd[1];
+	ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+	data.field = 1;
+	data.line = (mode & 2) ? 21 : 0;
+	data.data[0] = cc->even[0];
+	data.data[1] = cc->even[1];
+	ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+}
+
+static void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
+{
+	struct v4l2_sliced_vbi_data data;
+
+	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
+		return;
+	/* When using a 50 Hz system, always turn on the
+	   wide screen signal with 4x3 ratio as the default.
+	   Turning this signal on and off can confuse certain
+	   TVs. As far as I can tell there is no reason not to
+	   transmit this signal. */
+	if ((itv->std & V4L2_STD_625_50) && !enabled) {
+		enabled = 1;
+		mode = 0x08;  /* 4x3 full format */
+	}
+	data.id = V4L2_SLICED_WSS_625;
+	data.field = 0;
+	data.line = enabled ? 23 : 0;
+	data.data[0] = mode & 0xff;
+	data.data[1] = (mode >> 8) & 0xff;
+	ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
+}
 
 static int odd_parity(u8 c)
 {
@@ -32,62 +91,50 @@
 	return c & 1;
 }
 
-static void passthrough_vbi_data(struct ivtv *itv, int cnt)
+void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t cnt)
 {
-	int wss = 0;
-	u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 };
-	u8 vps[13];
+	struct vbi_info *vi = &itv->vbi;
+	struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
 	int found_cc = 0;
-	int found_wss = 0;
-	int found_vps = 0;
-	int cc_pos = itv->vbi.cc_pos;
-	int i;
+	size_t i;
 
 	for (i = 0; i < cnt; i++) {
-		struct v4l2_sliced_vbi_data *d = itv->vbi.sliced_dec_data + i;
+		const struct v4l2_sliced_vbi_data *d = sliced + i;
 
 		if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) {
-			found_cc = 1;
 			if (d->field) {
-				cc[2] = d->data[0];
-				cc[3] = d->data[1];
+				cc.even[0] = d->data[0];
+				cc.even[1] = d->data[1];
 			} else {
-				cc[0] = d->data[0];
-				cc[1] = d->data[1];
+				cc.odd[0] = d->data[0];
+				cc.odd[1] = d->data[1];
 			}
+			found_cc = 1;
 		}
 		else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) {
-			memcpy(vps, d->data, sizeof(vps));
-			found_vps = 1;
+			struct vbi_vps vps;
+
+			vps.data[0] = d->data[2];
+			vps.data[1] = d->data[8];
+			vps.data[2] = d->data[9];
+			vps.data[3] = d->data[10];
+			vps.data[4] = d->data[11];
+			if (memcmp(&vps, &vi->vps_payload, sizeof(vps))) {
+				vi->vps_payload = vps;
+				set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
+			}
 		}
 		else if (d->id == V4L2_SLICED_WSS_625 && d->line == 23 && d->field == 0) {
-			wss = d->data[0] | d->data[1] << 8;
-			found_wss = 1;
+			int wss = d->data[0] | d->data[1] << 8;
+
+			if (vi->wss_payload != wss) {
+				vi->wss_payload = wss;
+				set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
+			}
 		}
 	}
-
-	if (itv->vbi.wss_found != found_wss || itv->vbi.wss != wss) {
-		itv->vbi.wss = wss;
-		itv->vbi.wss_found = found_wss;
-		set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
-	}
-
-	if (found_vps || itv->vbi.vps_found) {
-		itv->vbi.vps[0] = vps[2];
-		itv->vbi.vps[1] = vps[8];
-		itv->vbi.vps[2] = vps[9];
-		itv->vbi.vps[3] = vps[10];
-		itv->vbi.vps[4] = vps[11];
-		itv->vbi.vps_found = found_vps;
-		set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
-	}
-
-	if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) {
-		itv->vbi.cc_data_odd[cc_pos] = cc[0];
-		itv->vbi.cc_data_odd[cc_pos + 1] = cc[1];
-		itv->vbi.cc_data_even[cc_pos] = cc[2];
-		itv->vbi.cc_data_even[cc_pos + 1] = cc[3];
-		itv->vbi.cc_pos = cc_pos + 2;
+	if (found_cc && vi->cc_payload_idx < sizeof(vi->cc_payload)) {
+		vi->cc_payload[vi->cc_payload_idx++] = cc;
 		set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
 	}
 }
@@ -163,8 +210,8 @@
 		linemask[1] = 0xf;
 		p += 4;
 	} else {
-		/* unknown VBI data stream */
-		return 0;
+		/* unknown VBI data, convert to empty VBI frame */
+		linemask[0] = linemask[1] = 0;
 	}
 	for (i = 0; i < 36; i++) {
 		int err = 0;
@@ -211,78 +258,6 @@
 	return line * sizeof(itv->vbi.sliced_dec_data[0]);
 }
 
-ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count)
-{
-	/* Should be a __user pointer, but sparse doesn't parse this bit correctly. */
-	const struct v4l2_sliced_vbi_data *p = (const struct v4l2_sliced_vbi_data *)ubuf;
-	u8 cc[4] = { 0x80, 0x80, 0x80, 0x80 };
-	int found_cc = 0;
-	int cc_pos = itv->vbi.cc_pos;
-
-	if (itv->vbi.service_set_out == 0)
-		return -EPERM;
-
-	while (count >= sizeof(struct v4l2_sliced_vbi_data)) {
-		switch (p->id) {
-		case V4L2_SLICED_CAPTION_525:
-			if (p->id == V4L2_SLICED_CAPTION_525 &&
-			    p->line == 21 &&
-			    (itv->vbi.service_set_out &
-				V4L2_SLICED_CAPTION_525) == 0) {
-				break;
-			}
-			found_cc = 1;
-			if (p->field) {
-				cc[2] = p->data[0];
-				cc[3] = p->data[1];
-			} else {
-				cc[0] = p->data[0];
-				cc[1] = p->data[1];
-			}
-			break;
-
-		case V4L2_SLICED_VPS:
-			if (p->line == 16 && p->field == 0 &&
-			    (itv->vbi.service_set_out & V4L2_SLICED_VPS)) {
-				itv->vbi.vps[0] = p->data[2];
-				itv->vbi.vps[1] = p->data[8];
-				itv->vbi.vps[2] = p->data[9];
-				itv->vbi.vps[3] = p->data[10];
-				itv->vbi.vps[4] = p->data[11];
-				itv->vbi.vps_found = 1;
-				set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
-			}
-			break;
-
-		case V4L2_SLICED_WSS_625:
-			if (p->line == 23 && p->field == 0 &&
-			    (itv->vbi.service_set_out & V4L2_SLICED_WSS_625)) {
-				/* No lock needed for WSS */
-				itv->vbi.wss = p->data[0] | (p->data[1] << 8);
-				itv->vbi.wss_found = 1;
-				set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
-			}
-			break;
-
-		default:
-			break;
-		}
-		count -= sizeof(*p);
-		p++;
-	}
-
-	if (found_cc && cc_pos < sizeof(itv->vbi.cc_data_even)) {
-		itv->vbi.cc_data_odd[cc_pos] = cc[0];
-		itv->vbi.cc_data_odd[cc_pos + 1] = cc[1];
-		itv->vbi.cc_data_even[cc_pos] = cc[2];
-		itv->vbi.cc_data_even[cc_pos + 1] = cc[3];
-		itv->vbi.cc_pos = cc_pos + 2;
-		set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
-	}
-
-	return (const char __user *)p - ubuf;
-}
-
 /* Compress raw VBI format, removes leading SAV codes and surplus space after the
    field.
    Returns new compressed size. */
@@ -431,108 +406,95 @@
 		memcpy(buf->buf, itv->vbi.sliced_dec_data, cnt);
 		buf->bytesused = cnt;
 
-		passthrough_vbi_data(itv, cnt / sizeof(itv->vbi.sliced_dec_data[0]));
+		ivtv_write_vbi(itv, itv->vbi.sliced_dec_data,
+			       cnt / sizeof(itv->vbi.sliced_dec_data[0]));
 		return;
 	}
 }
 
-void ivtv_disable_vbi(struct ivtv *itv)
+void ivtv_disable_cc(struct ivtv *itv)
 {
-	clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
-	clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
+	struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
+
 	clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
-	ivtv_set_wss(itv, 0, 0);
-	ivtv_set_cc(itv, 0, 0, 0, 0, 0);
-	ivtv_set_vps(itv, 0, 0, 0, 0, 0, 0);
-	itv->vbi.vps_found = itv->vbi.wss_found = 0;
-	itv->vbi.wss = 0;
-	itv->vbi.cc_pos = 0;
+	ivtv_set_cc(itv, 0, &cc);
+	itv->vbi.cc_payload_idx = 0;
 }
 
 
 void ivtv_vbi_work_handler(struct ivtv *itv)
 {
+	struct vbi_info *vi = &itv->vbi;
 	struct v4l2_sliced_vbi_data data;
+	struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
 
 	/* Lock */
 	if (itv->output_mode == OUT_PASSTHROUGH) {
-		/* Note: currently only the saa7115 is used in a PVR350,
-		   so these commands are for now saa7115 specific. */
 		if (itv->is_50hz) {
 			data.id = V4L2_SLICED_WSS_625;
 			data.field = 0;
 
 			if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
 				ivtv_set_wss(itv, 1, data.data[0] & 0xf);
-				itv->vbi.wss_no_update = 0;
-			} else if (itv->vbi.wss_no_update == 4) {
+				vi->wss_missing_cnt = 0;
+			} else if (vi->wss_missing_cnt == 4) {
 				ivtv_set_wss(itv, 1, 0x8);  /* 4x3 full format */
 			} else {
-				itv->vbi.wss_no_update++;
+				vi->wss_missing_cnt++;
 			}
 		}
 		else {
-			u8 c1 = 0, c2 = 0, c3 = 0, c4 = 0;
 			int mode = 0;
 
 			data.id = V4L2_SLICED_CAPTION_525;
 			data.field = 0;
 			if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
 				mode |= 1;
-				c1 = data.data[0];
-				c2 = data.data[1];
+				cc.odd[0] = data.data[0];
+				cc.odd[1] = data.data[1];
 			}
 			data.field = 1;
 			if (itv->video_dec_func(itv, VIDIOC_INT_G_VBI_DATA, &data) == 0) {
 				mode |= 2;
-				c3 = data.data[0];
-				c4 = data.data[1];
+				cc.even[0] = data.data[0];
+				cc.even[1] = data.data[1];
 			}
 			if (mode) {
-				itv->vbi.cc_no_update = 0;
-				ivtv_set_cc(itv, mode, c1, c2, c3, c4);
-			} else if (itv->vbi.cc_no_update == 4) {
-				ivtv_set_cc(itv, 0, 0, 0, 0, 0);
+				vi->cc_missing_cnt = 0;
+				ivtv_set_cc(itv, mode, &cc);
+			} else if (vi->cc_missing_cnt == 4) {
+				ivtv_set_cc(itv, 0, &cc);
 			} else {
-				itv->vbi.cc_no_update++;
+				vi->cc_missing_cnt++;
 			}
 		}
 		return;
 	}
 
 	if (test_and_clear_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags)) {
-		/* Lock */
-		ivtv_set_wss(itv, itv->vbi.wss_found, itv->vbi.wss & 0xf);
+		ivtv_set_wss(itv, 1, vi->wss_payload & 0xf);
 	}
 
-	if (test_and_clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) {
-		if (itv->vbi.cc_pos == 0) {
-			ivtv_set_cc(itv, 3, 0x80, 0x80, 0x80, 0x80);
+	if (test_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags)) {
+		if (vi->cc_payload_idx == 0) {
+			clear_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
+			ivtv_set_cc(itv, 3, &cc);
 		}
-		while (itv->vbi.cc_pos) {
-			u8 cc_odd0 = itv->vbi.cc_data_odd[0];
-			u8 cc_odd1 = itv->vbi.cc_data_odd[1];
-			u8 cc_even0 = itv->vbi.cc_data_even[0];
-			u8 cc_even1 = itv->vbi.cc_data_even[1];
+		while (vi->cc_payload_idx) {
+			cc = vi->cc_payload[0];
 
-			memcpy(itv->vbi.cc_data_odd, itv->vbi.cc_data_odd + 2, sizeof(itv->vbi.cc_data_odd) - 2);
-			memcpy(itv->vbi.cc_data_even, itv->vbi.cc_data_even + 2, sizeof(itv->vbi.cc_data_even) - 2);
-			itv->vbi.cc_pos -= 2;
-			if (itv->vbi.cc_pos && cc_odd0 == 0x80 && cc_odd1 == 0x80)
+			memcpy(vi->cc_payload, vi->cc_payload + 1,
+					sizeof(vi->cc_payload) - sizeof(vi->cc_payload[0]));
+			vi->cc_payload_idx--;
+			if (vi->cc_payload_idx && cc.odd[0] == 0x80 && cc.odd[1] == 0x80)
 				continue;
 
-			/* Send to Saa7127 */
-			ivtv_set_cc(itv, 3, cc_odd0, cc_odd1, cc_even0, cc_even1);
-			if (itv->vbi.cc_pos == 0)
-				set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
+			ivtv_set_cc(itv, 3, &cc);
 			break;
 		}
 	}
 
 	if (test_and_clear_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags)) {
-		/* Lock */
-		ivtv_set_vps(itv, itv->vbi.vps_found,
-			itv->vbi.vps[0], itv->vbi.vps[1],
-			itv->vbi.vps[2], itv->vbi.vps[3], itv->vbi.vps[4]);
+		ivtv_set_vps(itv, 1);
 	}
 }
diff --git a/drivers/media/video/ivtv/ivtv-vbi.h b/drivers/media/video/ivtv/ivtv-vbi.h
index ec211b4..970567b 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.h
+++ b/drivers/media/video/ivtv/ivtv-vbi.h
@@ -17,10 +17,15 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-ssize_t ivtv_write_vbi(struct ivtv *itv, const char __user *ubuf, size_t count);
+#ifndef IVTV_VBI_H
+#define IVTV_VBI_H
+
+void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t count);
 void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf,
 			   u64 pts_stamp, int streamtype);
 int ivtv_used_line(struct ivtv *itv, int line, int field);
-void ivtv_disable_vbi(struct ivtv *itv);
+void ivtv_disable_cc(struct ivtv *itv);
 void ivtv_set_vbi(unsigned long arg);
 void ivtv_vbi_work_handler(struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h
index 85530a3..d050de2 100644
--- a/drivers/media/video/ivtv/ivtv-version.h
+++ b/drivers/media/video/ivtv/ivtv-version.h
@@ -17,10 +17,15 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#ifndef IVTV_VERSION_H
+#define IVTV_VERSION_H
+
 #define IVTV_DRIVER_NAME "ivtv"
 #define IVTV_DRIVER_VERSION_MAJOR 1
-#define IVTV_DRIVER_VERSION_MINOR 0
+#define IVTV_DRIVER_VERSION_MINOR 1
 #define IVTV_DRIVER_VERSION_PATCHLEVEL 0
 
 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
 #define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL)
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtv-video.c b/drivers/media/video/ivtv/ivtv-video.c
deleted file mode 100644
index 5858b19..0000000
--- a/drivers/media/video/ivtv/ivtv-video.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
-    saa7127 interface functions
-    Copyright (C) 2004-2007  Hans Verkuil <hverkuil@xs4all.nl>
-
-    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 "ivtv-driver.h"
-#include "ivtv-video.h"
-#include "ivtv-i2c.h"
-#include "ivtv-gpio.h"
-#include "ivtv-cards.h"
-#include <media/upd64031a.h>
-#include <media/upd64083.h>
-
-void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3,
-		  u8 vps4, u8 vps5)
-{
-	struct v4l2_sliced_vbi_data data;
-
-	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-		return;
-	data.id = V4L2_SLICED_VPS;
-	data.field = 0;
-	data.line = enabled ? 16 : 0;
-	data.data[4] = vps1;
-	data.data[10] = vps2;
-	data.data[11] = vps3;
-	data.data[12] = vps4;
-	data.data[13] = vps5;
-	ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
-}
-
-void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4)
-{
-	struct v4l2_sliced_vbi_data data;
-
-	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-		return;
-	data.id = V4L2_SLICED_CAPTION_525;
-	data.field = 0;
-	data.line = (mode & 1) ? 21 : 0;
-	data.data[0] = cc1;
-	data.data[1] = cc2;
-	ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
-	data.field = 1;
-	data.line = (mode & 2) ? 21 : 0;
-	data.data[0] = cc3;
-	data.data[1] = cc4;
-	ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
-}
-
-void ivtv_set_wss(struct ivtv *itv, int enabled, int mode)
-{
-	struct v4l2_sliced_vbi_data data;
-
-	if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
-		return;
-	/* When using a 50 Hz system, always turn on the
-	   wide screen signal with 4x3 ratio as the default.
-	   Turning this signal on and off can confuse certain
-	   TVs. As far as I can tell there is no reason not to
-	   transmit this signal. */
-	if ((itv->std & V4L2_STD_625_50) && !enabled) {
-		enabled = 1;
-		mode = 0x08;  /* 4x3 full format */
-	}
-	data.id = V4L2_SLICED_WSS_625;
-	data.field = 0;
-	data.line = enabled ? 23 : 0;
-	data.data[0] = mode & 0xff;
-	data.data[1] = (mode >> 8) & 0xff;
-	ivtv_saa7127(itv, VIDIOC_INT_S_VBI_DATA, &data);
-}
-
-void ivtv_video_set_io(struct ivtv *itv)
-{
-	struct v4l2_routing route;
-	int inp = itv->active_input;
-	u32 type;
-
-	route.input = itv->card->video_inputs[inp].video_input;
-	route.output = 0;
-	itv->video_dec_func(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
-
-	type = itv->card->video_inputs[inp].video_type;
-
-	if (type == IVTV_CARD_INPUT_VID_TUNER) {
-		route.input = 0;  /* Tuner */
-	} else if (type < IVTV_CARD_INPUT_COMPOSITE1) {
-		route.input = 2;  /* S-Video */
-	} else {
-		route.input = 1;  /* Composite */
-	}
-
-	if (itv->card->hw_video & IVTV_HW_GPIO)
-		ivtv_gpio(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
-
-	if (itv->card->hw_video & IVTV_HW_UPD64031A) {
-		if (type == IVTV_CARD_INPUT_VID_TUNER ||
-		    type >= IVTV_CARD_INPUT_COMPOSITE1) {
-			/* Composite: GR on, connect to 3DYCS */
-			route.input = UPD64031A_GR_ON | UPD64031A_3DYCS_COMPOSITE;
-		} else {
-			/* S-Video: GR bypassed, turn it off */
-			route.input = UPD64031A_GR_OFF | UPD64031A_3DYCS_DISABLE;
-		}
-		route.input |= itv->card->gr_config;
-
-		ivtv_upd64031a(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
-	}
-
-	if (itv->card->hw_video & IVTV_HW_UPD6408X) {
-		route.input = UPD64083_YCS_MODE;
-		if (type > IVTV_CARD_INPUT_VID_TUNER &&
-		    type < IVTV_CARD_INPUT_COMPOSITE1) {
-			/* S-Video uses YCNR mode and internal Y-ADC, the upd64031a
-			   is not used. */
-			route.input |= UPD64083_YCNR_MODE;
-		}
-		else if (itv->card->hw_video & IVTV_HW_UPD64031A) {
-		  /* Use upd64031a output for tuner and composite(CX23416GYC only) inputs */
-		  if ((type == IVTV_CARD_INPUT_VID_TUNER)||
-		      (itv->card->type == IVTV_CARD_CX23416GYC)) {
-		    route.input |= UPD64083_EXT_Y_ADC;
-		  }
-		}
-		ivtv_upd64083(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
-	}
-}
diff --git a/drivers/media/video/ivtv/ivtv-video.h b/drivers/media/video/ivtv/ivtv-video.h
deleted file mode 100644
index c8ade5d..0000000
--- a/drivers/media/video/ivtv/ivtv-video.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
-    saa7127 interface functions
-    Copyright (C) 2004-2007  Hans Verkuil <hverkuil@xs4all.nl>
-
-    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
- */
-
-void ivtv_set_wss(struct ivtv *itv, int enabled, int mode);
-void ivtv_set_cc(struct ivtv *itv, int mode, u8 cc1, u8 cc2, u8 cc3, u8 cc4);
-void ivtv_set_vps(struct ivtv *itv, int enabled, u8 vps1, u8 vps2, u8 vps3,
-		  u8 vps4, u8 vps5);
-void ivtv_video_set_io(struct ivtv *itv);
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
index bcea0954..e2288f2 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/drivers/media/video/ivtv/ivtv-yuv.c
@@ -19,11 +19,16 @@
  */
 
 #include "ivtv-driver.h"
-#include "ivtv-queue.h"
 #include "ivtv-udma.h"
-#include "ivtv-irq.h"
 #include "ivtv-yuv.h"
 
+const u32 yuv_offset[4] = {
+	IVTV_YUV_BUFFER_OFFSET,
+	IVTV_YUV_BUFFER_OFFSET_1,
+	IVTV_YUV_BUFFER_OFFSET_2,
+	IVTV_YUV_BUFFER_OFFSET_3
+};
+
 static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
 				 struct ivtv_dma_frame *args)
 {
@@ -37,7 +42,7 @@
 	int y_decode_height, uv_decode_height, y_size;
 	int frame = atomic_read(&itv->yuv_info.next_fill_frame);
 
-	y_buffer_offset = IVTV_DEC_MEM_START + yuv_offset[frame];
+	y_buffer_offset = IVTV_DECODER_OFFSET + yuv_offset[frame];
 	uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
 
 	y_decode_height = uv_decode_height = args->src.height + args->src.top;
@@ -83,7 +88,14 @@
 	}
 
 	/* Fill & map SG List */
-	ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0));
+	if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
+		IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
+		for (i = 0; i < dma->page_count; i++) {
+			put_page(dma->map[i]);
+		}
+		dma->page_count = 0;
+		return -ENOMEM;
+	}
 	dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
 
 	/* Fill SG Array with new values */
@@ -94,7 +106,7 @@
 		if (itv->yuv_info.blanking_dmaptr) {
 			dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
 			dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr);
-			dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DEC_MEM_START + yuv_offset[frame]);
+			dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DECODER_OFFSET + yuv_offset[frame]);
 			dma->SG_length++;
 		}
 	}
@@ -612,7 +624,6 @@
 		itv->yuv_info.v_filter_2 = v_filter_2;
 	}
 
-	itv->yuv_info.frame_interlaced_last = itv->yuv_info.frame_interlaced;
 }
 
 /* Modify the supplied coordinate information to fit the visible osd area */
@@ -799,6 +810,7 @@
 	    (itv->yuv_info.old_frame_info.src_y != window->src_y) ||
 	    (itv->yuv_info.old_frame_info.pan_y != window->pan_y) ||
 	    (itv->yuv_info.old_frame_info.vis_h != window->vis_h) ||
+	    (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) ||
 	    (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) ||
 	    (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) {
 		yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
@@ -898,8 +910,21 @@
 		itv->yuv_info.decode_height = 480;
 
 	/* If no visible size set, assume full size */
-	if (!itv->yuv_info.osd_vis_w) itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset;
-	if (!itv->yuv_info.osd_vis_h) itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
+	if (!itv->yuv_info.osd_vis_w)
+		itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset;
+
+	if (!itv->yuv_info.osd_vis_h) {
+		itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
+	} else {
+		/* If output video standard has changed, requested height may
+		not be legal */
+		if (itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset > itv->yuv_info.decode_height) {
+			IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
+					itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset,
+					itv->yuv_info.decode_height);
+			itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
+		}
+	}
 
 	/* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
 	itv->yuv_info.blanking_ptr = kzalloc(720*16,GFP_KERNEL);
@@ -927,6 +952,7 @@
 	int rc = 0;
 	int got_sig = 0;
 	int frame, next_fill_frame, last_fill_frame;
+	int register_update = 0;
 
 	IVTV_DEBUG_INFO("yuv_prep_frame\n");
 
@@ -940,6 +966,7 @@
 		/* Buffers are full - Overwrite the last frame */
 		next_fill_frame = frame;
 		frame = (frame - 1) & 3;
+		register_update = itv->yuv_info.new_frame_info[frame].update;
 	}
 
 	/* Take a snapshot of the yuv coordinate information */
@@ -955,6 +982,9 @@
 	itv->yuv_info.new_frame_info[frame].tru_w = args->src_width;
 	itv->yuv_info.new_frame_info[frame].tru_h = args->src_height;
 
+	/* Snapshot field order */
+	itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field;
+
 	/* Are we going to offset the Y plane */
 	if (args->src.height + args->src.top < 512-16)
 		itv->yuv_info.new_frame_info[frame].offset_y = 1;
@@ -970,6 +1000,7 @@
 	itv->yuv_info.new_frame_info[frame].update = 0;
 	itv->yuv_info.new_frame_info[frame].interlaced_y = 0;
 	itv->yuv_info.new_frame_info[frame].interlaced_uv = 0;
+	itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode;
 
 	if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame],
 	    sizeof (itv->yuv_info.new_frame_info[frame]))) {
@@ -978,6 +1009,14 @@
 /*		IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */
 	}
 
+	itv->yuv_info.new_frame_info[frame].update |= register_update;
+
+	/* Should this frame be delayed ? */
+	if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3])
+		itv->yuv_info.field_delay[frame] = 1;
+	else
+		itv->yuv_info.field_delay[frame] = 0;
+
 	/* DMA the frame */
 	mutex_lock(&itv->udma.lock);
 
diff --git a/drivers/media/video/ivtv/ivtv-yuv.h b/drivers/media/video/ivtv/ivtv-yuv.h
index 88972d3..f7215ee 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.h
+++ b/drivers/media/video/ivtv/ivtv-yuv.h
@@ -18,7 +18,28 @@
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#ifndef IVTV_YUV_H
+#define IVTV_YUV_H
+
+/* Buffers on hardware offsets */
+#define IVTV_YUV_BUFFER_OFFSET    0x001a8600	/* First YUV Buffer */
+#define IVTV_YUV_BUFFER_OFFSET_1  0x00240400	/* Second YUV Buffer */
+#define IVTV_YUV_BUFFER_OFFSET_2  0x002d8200	/* Third YUV Buffer */
+#define IVTV_YUV_BUFFER_OFFSET_3  0x00370000	/* Fourth YUV Buffer */
+#define IVTV_YUV_BUFFER_UV_OFFSET 0x65400	/* Offset to UV Buffer */
+
+/* Offset to filter table in firmware */
+#define IVTV_YUV_HORIZONTAL_FILTER_OFFSET 0x025d8
+#define IVTV_YUV_VERTICAL_FILTER_OFFSET 0x03358
+
+#define IVTV_YUV_UPDATE_HORIZONTAL  0x01
+#define IVTV_YUV_UPDATE_VERTICAL    0x02
+
+extern const u32 yuv_offset[4];
+
 int ivtv_yuv_filter_check(struct ivtv *itv);
 int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args);
 void ivtv_yuv_close(struct ivtv *itv);
 void ivtv_yuv_work_handler (struct ivtv *itv);
+
+#endif
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
new file mode 100644
index 0000000..9684048
--- /dev/null
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -0,0 +1,1190 @@
+/*
+    On Screen Display cx23415 Framebuffer driver
+
+    This module presents the cx23415 OSD (onscreen display) framebuffer memory
+    as a standard Linux /dev/fb style framebuffer device. The framebuffer has
+    support for 8, 16 & 32 bpp packed pixel formats with alpha channel. In 16bpp
+    mode, there is a choice of a three color depths (12, 15 or 16 bits), but no
+    local alpha. The colorspace is selectable between rgb & yuv.
+    Depending on the TV standard configured in the ivtv module at load time,
+    the initial resolution is either 640x400 (NTSC) or 640x480 (PAL) at 8bpp.
+    Video timings are locked to ensure a vertical refresh rate of 50Hz (PAL)
+    or 59.94 (NTSC)
+
+    Copyright (c) 2003 Matt T. Yourst <yourst@yourst.com>
+
+    Derived from drivers/video/vesafb.c
+    Portions (c) 1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+
+    2.6 kernel port:
+    Copyright (C) 2004 Matthias Badaire
+
+    Copyright (C) 2004  Chris Kennedy <c@groovy.org>
+
+    Copyright (C) 2006  Ian Armstrong <ian@iarmst.demon.co.uk>
+
+    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/module.h>
+#include <linux/kernel.h>
+#include <linux/fb.h>
+#include <linux/ivtvfb.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "ivtv-driver.h"
+#include "ivtv-udma.h"
+#include "ivtv-mailbox.h"
+
+/* card parameters */
+static int ivtvfb_card_id = -1;
+static int ivtvfb_debug = 0;
+static int osd_laced;
+static int osd_compat;
+static int osd_depth;
+static int osd_upper;
+static int osd_left;
+static int osd_yres;
+static int osd_xres;
+
+module_param(ivtvfb_card_id, int, 0444);
+module_param_named(debug,ivtvfb_debug, int, 0644);
+module_param(osd_laced, bool, 0444);
+module_param(osd_compat, bool, 0444);
+module_param(osd_depth, int, 0444);
+module_param(osd_upper, int, 0444);
+module_param(osd_left, int, 0444);
+module_param(osd_yres, int, 0444);
+module_param(osd_xres, int, 0444);
+
+MODULE_PARM_DESC(ivtvfb_card_id,
+		 "Only use framebuffer of the specified ivtv card (0-31)\n"
+		 "\t\t\tdefault -1: initialize all available framebuffers");
+
+MODULE_PARM_DESC(debug,
+		 "Debug level (bitmask). Default: errors only\n"
+		 "\t\t\t(debug = 3 gives full debugging)");
+
+MODULE_PARM_DESC(osd_compat,
+		 "Compatibility mode - Display size is locked (use for old X drivers)\n"
+		 "\t\t\t0=off\n"
+		 "\t\t\t1=on\n"
+		 "\t\t\tdefault off");
+
+/* Why upper, left, xres, yres, depth, laced ? To match terminology used
+   by fbset.
+   Why start at 1 for left & upper coordinate ? Because X doesn't allow 0 */
+
+MODULE_PARM_DESC(osd_laced,
+		 "Interlaced mode\n"
+		 "\t\t\t0=off\n"
+		 "\t\t\t1=on\n"
+		 "\t\t\tdefault off");
+
+MODULE_PARM_DESC(osd_depth,
+		 "Bits per pixel - 8, 16, 32\n"
+		 "\t\t\tdefault 8");
+
+MODULE_PARM_DESC(osd_upper,
+		 "Vertical start position\n"
+		 "\t\t\tdefault 0 (Centered)");
+
+MODULE_PARM_DESC(osd_left,
+		 "Horizontal start position\n"
+		 "\t\t\tdefault 0 (Centered)");
+
+MODULE_PARM_DESC(osd_yres,
+		 "Display height\n"
+		 "\t\t\tdefault 480 (PAL)\n"
+		 "\t\t\t        400 (NTSC)");
+
+MODULE_PARM_DESC(osd_xres,
+		 "Display width\n"
+		 "\t\t\tdefault 640");
+
+MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
+MODULE_LICENSE("GPL");
+
+/* --------------------------------------------------------------------- */
+
+#define IVTVFB_DBGFLG_WARN  (1 << 0)
+#define IVTVFB_DBGFLG_INFO  (1 << 1)
+
+#define IVTVFB_DEBUG(x, type, fmt, args...) \
+	do { \
+		if ((x) & ivtvfb_debug) \
+			printk(KERN_INFO "ivtvfb%d " type ": " fmt, itv->num , ## args); \
+	} while (0)
+#define IVTVFB_DEBUG_WARN(fmt, args...)  IVTVFB_DEBUG(IVTVFB_DBGFLG_WARN, "warning", fmt , ## args)
+#define IVTVFB_DEBUG_INFO(fmt, args...)  IVTVFB_DEBUG(IVTVFB_DBGFLG_INFO, "info", fmt , ## args)
+
+/* Standard kernel messages */
+#define IVTVFB_ERR(fmt, args...)   printk(KERN_ERR  "ivtvfb%d: " fmt, itv->num , ## args)
+#define IVTVFB_WARN(fmt, args...)  printk(KERN_WARNING  "ivtvfb%d: " fmt, itv->num , ## args)
+#define IVTVFB_INFO(fmt, args...)  printk(KERN_INFO "ivtvfb%d: " fmt, itv->num , ## args)
+
+/* --------------------------------------------------------------------- */
+
+#define IVTV_OSD_MAX_WIDTH  720
+#define IVTV_OSD_MAX_HEIGHT 576
+
+#define IVTV_OSD_BPP_8      0x00
+#define IVTV_OSD_BPP_16_444 0x03
+#define IVTV_OSD_BPP_16_555 0x02
+#define IVTV_OSD_BPP_16_565 0x01
+#define IVTV_OSD_BPP_32     0x04
+
+struct osd_info {
+	/* Physical base address */
+	unsigned long video_pbase;
+	/* Relative base address (relative to start of decoder memory) */
+	u32 video_rbase;
+	/* Mapped base address */
+	volatile char __iomem *video_vbase;
+	/* Buffer size */
+	u32 video_buffer_size;
+
+#ifdef CONFIG_MTRR
+	/* video_base rounded down as required by hardware MTRRs */
+	unsigned long fb_start_aligned_physaddr;
+	/* video_base rounded up as required by hardware MTRRs */
+	unsigned long fb_end_aligned_physaddr;
+#endif
+
+	/* Current osd mode */
+	int osd_mode;
+
+	/* Store the buffer offset */
+	int set_osd_coords_x;
+	int set_osd_coords_y;
+
+	/* Current dimensions (NOT VISIBLE SIZE!) */
+	int display_width;
+	int display_height;
+	int display_byte_stride;
+
+	/* Current bits per pixel */
+	int bits_per_pixel;
+	int bytes_per_pixel;
+
+	/* Frame buffer stuff */
+	struct fb_info ivtvfb_info;
+	struct fb_var_screeninfo ivtvfb_defined;
+	struct fb_fix_screeninfo ivtvfb_fix;
+};
+
+struct ivtv_osd_coords {
+	unsigned long offset;
+	unsigned long max_offset;
+	int pixel_stride;
+	int lines;
+	int x;
+	int y;
+};
+
+/* --------------------------------------------------------------------- */
+
+/* ivtv API calls for framebuffer related support */
+
+static int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
+				       u32 *fblength)
+{
+	u32 data[CX2341X_MBOX_MAX_DATA];
+	int rc;
+
+	rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
+	*fbbase = data[0];
+	*fblength = data[1];
+	return rc;
+}
+
+static int ivtvfb_get_osd_coords(struct ivtv *itv,
+				      struct ivtv_osd_coords *osd)
+{
+	struct osd_info *oi = itv->osd_info;
+	u32 data[CX2341X_MBOX_MAX_DATA];
+
+	ivtv_vapi_result(itv, data, CX2341X_OSD_GET_OSD_COORDS, 0);
+
+	osd->offset = data[0] - oi->video_rbase;
+	osd->max_offset = oi->display_width * oi->display_height * 4;
+	osd->pixel_stride = data[1];
+	osd->lines = data[2];
+	osd->x = data[3];
+	osd->y = data[4];
+	return 0;
+}
+
+static int ivtvfb_set_osd_coords(struct ivtv *itv, const struct ivtv_osd_coords *osd)
+{
+	struct osd_info *oi = itv->osd_info;
+
+	oi->display_width = osd->pixel_stride;
+	oi->display_byte_stride = osd->pixel_stride * oi->bytes_per_pixel;
+	oi->set_osd_coords_x += osd->x;
+	oi->set_osd_coords_y = osd->y;
+
+	return ivtv_vapi(itv, CX2341X_OSD_SET_OSD_COORDS, 5,
+			osd->offset + oi->video_rbase,
+			osd->pixel_stride,
+			osd->lines, osd->x, osd->y);
+}
+
+static int ivtvfb_set_display_window(struct ivtv *itv, struct v4l2_rect *ivtv_window)
+{
+	int osd_height_limit = itv->is_50hz ? 576 : 480;
+
+	/* Only fail if resolution too high, otherwise fudge the start coords. */
+	if ((ivtv_window->height > osd_height_limit) || (ivtv_window->width > IVTV_OSD_MAX_WIDTH))
+		return -EINVAL;
+
+	/* Ensure we don't exceed display limits */
+	if (ivtv_window->top + ivtv_window->height > osd_height_limit) {
+		IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid height setting (%d, %d)\n",
+			ivtv_window->top, ivtv_window->height);
+		ivtv_window->top = osd_height_limit - ivtv_window->height;
+	}
+
+	if (ivtv_window->left + ivtv_window->width > IVTV_OSD_MAX_WIDTH) {
+		IVTVFB_DEBUG_WARN("ivtv_ioctl_fb_set_display_window - Invalid width setting (%d, %d)\n",
+			ivtv_window->left, ivtv_window->width);
+		ivtv_window->left = IVTV_OSD_MAX_WIDTH - ivtv_window->width;
+	}
+
+	/* Set the OSD origin */
+	write_reg((ivtv_window->top << 16) | ivtv_window->left, 0x02a04);
+
+	/* How much to display */
+	write_reg(((ivtv_window->top+ivtv_window->height) << 16) | (ivtv_window->left+ivtv_window->width), 0x02a08);
+
+	/* Pass this info back the yuv handler */
+	itv->yuv_info.osd_vis_w = ivtv_window->width;
+	itv->yuv_info.osd_vis_h = ivtv_window->height;
+	itv->yuv_info.osd_x_offset = ivtv_window->left;
+	itv->yuv_info.osd_y_offset = ivtv_window->top;
+
+	return 0;
+}
+
+static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
+				  unsigned long ivtv_dest_addr, void __user *userbuf,
+				  int size_in_bytes)
+{
+	DEFINE_WAIT(wait);
+	int ret = 0;
+	int got_sig = 0;
+
+	mutex_lock(&itv->udma.lock);
+	/* Map User DMA */
+	if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
+		mutex_unlock(&itv->udma.lock);
+		IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, "
+			       "Error with get_user_pages: %d bytes, %d pages returned\n",
+			       size_in_bytes, itv->udma.page_count);
+
+		/* get_user_pages must have failed completely */
+		return -EIO;
+	}
+
+	IVTVFB_DEBUG_INFO("ivtvfb_prep_dec_dma_to_device, %d bytes, %d pages\n",
+		       size_in_bytes, itv->udma.page_count);
+
+	ivtv_udma_prepare(itv);
+	prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
+	/* if no UDMA is pending and no UDMA is in progress, then the DMA
+	   is finished */
+	while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
+		/* don't interrupt if the DMA is in progress but break off
+		   a still pending DMA. */
+		got_sig = signal_pending(current);
+		if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
+			break;
+		got_sig = 0;
+		schedule();
+	}
+	finish_wait(&itv->dma_waitq, &wait);
+
+	/* Unmap Last DMA Xfer */
+	ivtv_udma_unmap(itv);
+	mutex_unlock(&itv->udma.lock);
+	if (got_sig) {
+		IVTV_DEBUG_INFO("User stopped OSD\n");
+		return -EINTR;
+	}
+
+	return ret;
+}
+
+static int ivtvfb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
+			      unsigned long dest_offset, int count)
+{
+	DEFINE_WAIT(wait);
+	struct osd_info *oi = itv->osd_info;
+
+	/* Nothing to do */
+	if (count == 0) {
+		IVTVFB_DEBUG_WARN("ivtvfb_prep_frame: Nothing to do. count = 0\n");
+		return -EINVAL;
+	}
+
+	/* Check Total FB Size */
+	if ((dest_offset + count) > oi->video_buffer_size) {
+		IVTVFB_WARN("ivtvfb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
+			dest_offset + count, oi->video_buffer_size);
+		return -E2BIG;
+	}
+
+	/* Not fatal, but will have undesirable results */
+	if ((unsigned long)source & 3)
+		IVTVFB_WARN("ivtvfb_prep_frame: Source address not 32 bit aligned (0x%08lx)\n",
+			(unsigned long)source);
+
+	if (dest_offset & 3)
+		IVTVFB_WARN("ivtvfb_prep_frame: Dest offset not 32 bit aligned (%ld)\n", dest_offset);
+
+	if (count & 3)
+		IVTVFB_WARN("ivtvfb_prep_frame: Count not a multiple of 4 (%d)\n", count);
+
+	/* Check Source */
+	if (!access_ok(VERIFY_READ, source + dest_offset, count)) {
+		IVTVFB_WARN("Invalid userspace pointer 0x%08lx\n",
+			(unsigned long)source);
+
+		IVTVFB_DEBUG_WARN("access_ok() failed for offset 0x%08lx source 0x%08lx count %d\n",
+			dest_offset, (unsigned long)source,
+			count);
+		return -EINVAL;
+	}
+
+	/* OSD Address to send DMA to */
+	dest_offset += IVTV_DECODER_OFFSET + oi->video_rbase;
+
+	/* Fill Buffers */
+	return ivtvfb_prep_dec_dma_to_device(itv, dest_offset, source, count);
+}
+
+static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
+{
+	DEFINE_WAIT(wait);
+	struct ivtv *itv = (struct ivtv *)info->par;
+	int rc = 0;
+
+	switch (cmd) {
+		case FBIOGET_VBLANK: {
+			struct fb_vblank vblank;
+			u32 trace;
+
+			vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
+					FB_VBLANK_HAVE_VSYNC;
+			trace = read_reg(0x028c0) >> 16;
+			if (itv->is_50hz && trace > 312) trace -= 312;
+			else if (itv->is_60hz && trace > 262) trace -= 262;
+			if (trace == 1) vblank.flags |= FB_VBLANK_VSYNCING;
+			vblank.count = itv->last_vsync_field;
+			vblank.vcount = trace;
+			vblank.hcount = 0;
+			if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank)))
+				return -EFAULT;
+			return 0;
+		}
+
+		case FBIO_WAITFORVSYNC:
+			prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
+			if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT;
+			finish_wait(&itv->vsync_waitq, &wait);
+			return rc;
+
+		case IVTVFB_IOC_DMA_FRAME: {
+			struct ivtvfb_dma_frame args;
+
+			IVTVFB_DEBUG_INFO("IVTVFB_IOC_DMA_FRAME\n");
+			if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
+				return -EFAULT;
+
+			return ivtvfb_prep_frame(itv, cmd, args.source, args.dest_offset, args.count);
+		}
+
+		default:
+			IVTVFB_DEBUG_INFO("Unknown ioctl %08x\n", cmd);
+			return -EINVAL;
+	}
+	return 0;
+}
+
+/* Framebuffer device handling */
+
+static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
+{
+	struct osd_info *oi = itv->osd_info;
+	struct ivtv_osd_coords ivtv_osd;
+	struct v4l2_rect ivtv_window;
+	int osd_mode = -1;
+
+	IVTVFB_DEBUG_INFO("ivtvfb_set_var\n");
+
+	/* Select color space */
+	if (var->nonstd) /* YUV */
+		write_reg(read_reg(0x02a00) | 0x0002000, 0x02a00);
+	else /* RGB  */
+		write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
+
+	/* Set the color mode */
+	switch (var->bits_per_pixel) {
+		case 8:
+			osd_mode = IVTV_OSD_BPP_8;
+			break;
+		case 32:
+			osd_mode = IVTV_OSD_BPP_32;
+			break;
+		case 16:
+			switch (var->green.length) {
+			case 4:
+				osd_mode = IVTV_OSD_BPP_16_444;
+				break;
+			case 5:
+				osd_mode = IVTV_OSD_BPP_16_555;
+				break;
+			case 6:
+				osd_mode = IVTV_OSD_BPP_16_565;
+				break;
+			default:
+				IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
+			}
+			break;
+		default:
+			IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
+	}
+
+	/* Change osd mode if needed.
+	   Although rare, things can go wrong. The extra mode
+	   change seems to help... */
+	if (osd_mode != -1 && osd_mode != oi->osd_mode) {
+		ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
+		ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
+		oi->osd_mode = osd_mode;
+	}
+
+	oi->bits_per_pixel = var->bits_per_pixel;
+	oi->bytes_per_pixel = var->bits_per_pixel / 8;
+
+	/* Set the flicker filter */
+	switch (var->vmode & FB_VMODE_MASK) {
+		case FB_VMODE_NONINTERLACED: /* Filter on */
+			ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 1);
+			break;
+		case FB_VMODE_INTERLACED: /* Filter off */
+			ivtv_vapi(itv, CX2341X_OSD_SET_FLICKER_STATE, 1, 0);
+			break;
+		default:
+			IVTVFB_DEBUG_WARN("ivtvfb_set_var - Invalid video mode\n");
+	}
+
+	/* Read the current osd info */
+	ivtvfb_get_osd_coords(itv, &ivtv_osd);
+
+	/* Now set the OSD to the size we want */
+	ivtv_osd.pixel_stride = var->xres_virtual;
+	ivtv_osd.lines = var->yres_virtual;
+	ivtv_osd.x = 0;
+	ivtv_osd.y = 0;
+	ivtvfb_set_osd_coords(itv, &ivtv_osd);
+
+	/* Can't seem to find the right API combo for this.
+	   Use another function which does what we need through direct register access. */
+	ivtv_window.width = var->xres;
+	ivtv_window.height = var->yres;
+
+	/* Minimum margin cannot be 0, as X won't allow such a mode */
+	if (!var->upper_margin) var->upper_margin++;
+	if (!var->left_margin) var->left_margin++;
+	ivtv_window.top = var->upper_margin - 1;
+	ivtv_window.left = var->left_margin - 1;
+
+	ivtvfb_set_display_window(itv, &ivtv_window);
+
+	/* Force update of yuv registers */
+	itv->yuv_info.yuv_forced_update = 1;
+
+	IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
+		      var->xres, var->yres,
+		      var->xres_virtual, var->yres_virtual,
+		      var->bits_per_pixel);
+
+	IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
+		      var->left_margin, var->upper_margin);
+
+	IVTVFB_DEBUG_INFO("Display filter: %s\n",
+			(var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
+	IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
+
+	return 0;
+}
+
+static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
+{
+	struct osd_info *oi = itv->osd_info;
+
+	IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n");
+	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+	strcpy(fix->id, "cx23415 TV out");
+	fix->smem_start = oi->video_pbase;
+	fix->smem_len = oi->video_buffer_size;
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->visual = (oi->bits_per_pixel == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+	fix->xpanstep = 1;
+	fix->ypanstep = 1;
+	fix->ywrapstep = 0;
+	fix->line_length = oi->display_byte_stride;
+	fix->accel = FB_ACCEL_NONE;
+	return 0;
+}
+
+/* Check the requested display mode, returning -EINVAL if we can't
+   handle it. */
+
+static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
+{
+	struct osd_info *oi = itv->osd_info;
+	int osd_height_limit;
+	u32 pixclock, hlimit, vlimit;
+
+	IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
+
+	/* Set base references for mode calcs. */
+	if (itv->is_50hz) {
+		pixclock = 84316;
+		hlimit = 776;
+		vlimit = 591;
+		osd_height_limit = 576;
+	}
+	else {
+		pixclock = 83926;
+		hlimit = 776;
+		vlimit = 495;
+		osd_height_limit = 480;
+	}
+
+	/* Check the bits per pixel */
+	if (osd_compat) {
+		if (var->bits_per_pixel != 32) {
+			IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
+			return -EINVAL;
+		}
+	}
+
+	if (var->bits_per_pixel == 8 || var->bits_per_pixel == 32) {
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+	}
+	else if (var->bits_per_pixel == 16) {
+		/* To find out the true mode, check green length */
+		switch (var->green.length) {
+			case 4:
+				var->red.offset = 8;
+				var->red.length = 4;
+				var->green.offset = 4;
+				var->green.length = 4;
+				var->blue.offset = 0;
+				var->blue.length = 4;
+				var->transp.offset = 12;
+				var->transp.length = 1;
+				break;
+			case 5:
+				var->red.offset = 10;
+				var->red.length = 5;
+				var->green.offset = 5;
+				var->green.length = 5;
+				var->blue.offset = 0;
+				var->blue.length = 5;
+				var->transp.offset = 15;
+				var->transp.length = 1;
+				break;
+			default:
+				var->red.offset = 11;
+				var->red.length = 5;
+				var->green.offset = 5;
+				var->green.length = 6;
+				var->blue.offset = 0;
+				var->blue.length = 5;
+				var->transp.offset = 0;
+				var->transp.length = 0;
+				break;
+		}
+	}
+	else {
+		IVTVFB_DEBUG_WARN("Invalid colour mode: %d\n", var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	/* Check the resolution */
+	if (osd_compat) {
+		if (var->xres != oi->ivtvfb_defined.xres ||
+		    var->yres != oi->ivtvfb_defined.yres ||
+		    var->xres_virtual != oi->ivtvfb_defined.xres_virtual ||
+		    var->yres_virtual != oi->ivtvfb_defined.yres_virtual) {
+			IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d (virtual %dx%d)\n",
+				var->xres, var->yres, var->xres_virtual, var->yres_virtual);
+			return -EINVAL;
+		}
+	}
+	else {
+		if (var->xres > IVTV_OSD_MAX_WIDTH || var->yres > osd_height_limit) {
+			IVTVFB_DEBUG_WARN("Invalid resolution: %dx%d\n",
+					var->xres, var->yres);
+			return -EINVAL;
+		}
+
+		/* Max horizontal size is 1023 @ 32bpp, 2046 & 16bpp, 4092 @ 8bpp */
+		if (var->xres_virtual > 4095 / (var->bits_per_pixel / 8) ||
+		    var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8) > oi->video_buffer_size ||
+		    var->xres_virtual < var->xres ||
+		    var->yres_virtual < var->yres) {
+			IVTVFB_DEBUG_WARN("Invalid virtual resolution: %dx%d\n",
+				var->xres_virtual, var->yres_virtual);
+			return -EINVAL;
+		}
+	}
+
+	/* Some extra checks if in 8 bit mode */
+	if (var->bits_per_pixel == 8) {
+		/* Width must be a multiple of 4 */
+		if (var->xres & 3) {
+			IVTVFB_DEBUG_WARN("Invalid resolution for 8bpp: %d\n", var->xres);
+			return -EINVAL;
+		}
+		if (var->xres_virtual & 3) {
+			IVTVFB_DEBUG_WARN("Invalid virtual resolution for 8bpp: %d)\n", var->xres_virtual);
+			return -EINVAL;
+		}
+	}
+	else if (var->bits_per_pixel == 16) {
+		/* Width must be a multiple of 2 */
+		if (var->xres & 1) {
+			IVTVFB_DEBUG_WARN("Invalid resolution for 16bpp: %d\n", var->xres);
+			return -EINVAL;
+		}
+		if (var->xres_virtual & 1) {
+			IVTVFB_DEBUG_WARN("Invalid virtual resolution for 16bpp: %d)\n", var->xres_virtual);
+			return -EINVAL;
+		}
+	}
+
+	/* Now check the offsets */
+	if (var->xoffset >= var->xres_virtual || var->yoffset >= var->yres_virtual) {
+		IVTVFB_DEBUG_WARN("Invalid offset: %d (%d) %d (%d)\n",
+			var->xoffset, var->xres_virtual, var->yoffset, var->yres_virtual);
+		return -EINVAL;
+	}
+
+	/* Check pixel format */
+	if (var->nonstd > 1) {
+		IVTVFB_DEBUG_WARN("Invalid nonstd % d\n", var->nonstd);
+		return -EINVAL;
+	}
+
+	/* Check video mode */
+	if (((var->vmode & FB_VMODE_MASK) != FB_VMODE_NONINTERLACED) &&
+		((var->vmode & FB_VMODE_MASK) != FB_VMODE_INTERLACED)) {
+		IVTVFB_DEBUG_WARN("Invalid video mode: %d\n", var->vmode & FB_VMODE_MASK);
+		return -EINVAL;
+	}
+
+	/* Check the left & upper margins
+	   If the margins are too large, just center the screen
+	   (enforcing margins causes too many problems) */
+
+	if (var->left_margin + var->xres > IVTV_OSD_MAX_WIDTH + 1) {
+		var->left_margin = 1 + ((IVTV_OSD_MAX_WIDTH - var->xres) / 2);
+	}
+	if (var->upper_margin + var->yres > (itv->is_50hz ? 577 : 481)) {
+		var->upper_margin = 1 + (((itv->is_50hz ? 576 : 480) - var->yres) / 2);
+	}
+
+	/* Maintain overall 'size' for a constant refresh rate */
+	var->right_margin = hlimit - var->left_margin - var->xres;
+	var->lower_margin = vlimit - var->upper_margin - var->yres;
+
+	/* Fixed sync times */
+	var->hsync_len = 24;
+	var->vsync_len = 2;
+
+	/* Non-interlaced / interlaced mode is used to switch the OSD filter
+	   on or off. Adjust the clock timings to maintain a constant
+	   vertical refresh rate. */
+	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
+		var->pixclock = pixclock / 2;
+	else
+		var->pixclock = pixclock;
+
+	IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
+		      var->xres, var->yres,
+		      var->xres_virtual, var->yres_virtual,
+		      var->bits_per_pixel);
+
+	IVTVFB_DEBUG_INFO("Display position: %d, %d\n",
+		      var->left_margin, var->upper_margin);
+
+	IVTVFB_DEBUG_INFO("Display filter: %s\n",
+			(var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED ? "on" : "off");
+	IVTVFB_DEBUG_INFO("Color space: %s\n", var->nonstd ? "YUV" : "RGB");
+	return 0;
+}
+
+static int ivtvfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct ivtv *itv = (struct ivtv *) info->par;
+	IVTVFB_DEBUG_INFO("ivtvfb_check_var\n");
+	return _ivtvfb_check_var(var, itv);
+}
+
+static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	u32 osd_pan_index;
+	struct ivtv *itv = (struct ivtv *) info->par;
+
+	osd_pan_index = (var->xoffset + (var->yoffset * var->xres_virtual))*var->bits_per_pixel/8;
+	write_reg(osd_pan_index, 0x02A0C);
+
+	/* Pass this info back the yuv handler */
+	itv->yuv_info.osd_x_pan = var->xoffset;
+	itv->yuv_info.osd_y_pan = var->yoffset;
+	/* Force update of yuv registers */
+	itv->yuv_info.yuv_forced_update = 1;
+	return 0;
+}
+
+static int ivtvfb_set_par(struct fb_info *info)
+{
+	int rc = 0;
+	struct ivtv *itv = (struct ivtv *) info->par;
+
+	IVTVFB_DEBUG_INFO("ivtvfb_set_par\n");
+
+	rc = ivtvfb_set_var(itv, &info->var);
+	ivtvfb_pan_display(&info->var, info);
+	ivtvfb_get_fix(itv, &info->fix);
+	return rc;
+}
+
+static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+				unsigned blue, unsigned transp,
+				struct fb_info *info)
+{
+	u32 color, *palette;
+	struct ivtv *itv = (struct ivtv *)info->par;
+
+	if (regno >= info->cmap.len)
+		return -EINVAL;
+
+	color = ((transp & 0xFF00) << 16) |((red & 0xFF00) << 8) | (green & 0xFF00) | ((blue & 0xFF00) >> 8);
+	if (info->var.bits_per_pixel <= 8) {
+		write_reg(regno, 0x02a30);
+		write_reg(color, 0x02a34);
+		return 0;
+	}
+	if (regno >= 16)
+		return -EINVAL;
+
+	palette = info->pseudo_palette;
+	if (info->var.bits_per_pixel == 16) {
+		switch (info->var.green.length) {
+			case 4:
+				color = ((red & 0xf000) >> 4) |
+					((green & 0xf000) >> 8) |
+					((blue & 0xf000) >> 12);
+				break;
+			case 5:
+				color = ((red & 0xf800) >> 1) |
+					((green & 0xf800) >> 6) |
+					((blue & 0xf800) >> 11);
+				break;
+			case 6:
+				color = (red & 0xf800 ) |
+					((green & 0xfc00) >> 5) |
+					((blue & 0xf800) >> 11);
+				break;
+		}
+	}
+	palette[regno] = color;
+	return 0;
+}
+
+/* We don't really support blanking. All this does is enable or
+   disable the OSD. */
+static int ivtvfb_blank(int blank_mode, struct fb_info *info)
+{
+	struct ivtv *itv = (struct ivtv *)info->par;
+
+	IVTVFB_DEBUG_INFO("Set blanking mode : %d\n", blank_mode);
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 1);
+		break;
+	case FB_BLANK_NORMAL:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_POWERDOWN:
+		ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
+		break;
+	}
+	return 0;
+}
+
+static struct fb_ops ivtvfb_ops = {
+	.owner = THIS_MODULE,
+	.fb_check_var   = ivtvfb_check_var,
+	.fb_set_par     = ivtvfb_set_par,
+	.fb_setcolreg   = ivtvfb_setcolreg,
+	.fb_fillrect    = cfb_fillrect,
+	.fb_copyarea    = cfb_copyarea,
+	.fb_imageblit   = cfb_imageblit,
+	.fb_cursor      = NULL,
+	.fb_ioctl       = ivtvfb_ioctl,
+	.fb_pan_display = ivtvfb_pan_display,
+	.fb_blank       = ivtvfb_blank,
+};
+
+/* Initialization */
+
+
+/* Setup our initial video mode */
+static int ivtvfb_init_vidmode(struct ivtv *itv)
+{
+	struct osd_info *oi = itv->osd_info;
+	struct v4l2_rect start_window;
+	int max_height;
+
+	/* Color mode */
+
+	if (osd_compat) osd_depth = 32;
+	if (osd_depth != 8 && osd_depth != 16 && osd_depth != 32) osd_depth = 8;
+	oi->bits_per_pixel = osd_depth;
+	oi->bytes_per_pixel = oi->bits_per_pixel / 8;
+
+	/* Invalidate current osd mode to force a mode switch later */
+	oi->osd_mode = -1;
+
+	/* Horizontal size & position */
+
+	if (osd_xres > 720) osd_xres = 720;
+
+	/* Must be a multiple of 4 for 8bpp & 2 for 16bpp */
+	if (osd_depth == 8)
+		osd_xres &= ~3;
+	else if (osd_depth == 16)
+		osd_xres &= ~1;
+
+	if (osd_xres)
+		start_window.width = osd_xres;
+	else
+		start_window.width = osd_compat ? 720: 640;
+
+	/* Check horizontal start (osd_left). */
+	if (osd_left && osd_left + start_window.width > 721) {
+		IVTVFB_ERR("Invalid osd_left - assuming default\n");
+		osd_left = 0;
+	}
+
+	/* Hardware coords start at 0, user coords start at 1. */
+	osd_left--;
+
+	start_window.left = osd_left >= 0 ? osd_left : ((IVTV_OSD_MAX_WIDTH - start_window.width) / 2);
+
+	oi->display_byte_stride =
+			start_window.width * oi->bytes_per_pixel;
+
+	/* Vertical size & position */
+
+	max_height = itv->is_50hz ? 576 : 480;
+
+	if (osd_yres > max_height)
+		osd_yres = max_height;
+
+	if (osd_yres)
+		start_window.height = osd_yres;
+	else
+		start_window.height = osd_compat ? max_height : (itv->is_50hz ? 480 : 400);
+
+	/* Check vertical start (osd_upper). */
+	if (osd_upper + start_window.height > max_height + 1) {
+		IVTVFB_ERR("Invalid osd_upper - assuming default\n");
+		osd_upper = 0;
+	}
+
+	/* Hardware coords start at 0, user coords start at 1. */
+	osd_upper--;
+
+	start_window.top = osd_upper >= 0 ? osd_upper : ((max_height - start_window.height) / 2);
+
+	oi->display_width = start_window.width;
+	oi->display_height = start_window.height;
+
+	/* Generate a valid fb_var_screeninfo */
+
+	oi->ivtvfb_defined.xres = oi->display_width;
+	oi->ivtvfb_defined.yres = oi->display_height;
+	oi->ivtvfb_defined.xres_virtual = oi->display_width;
+	oi->ivtvfb_defined.yres_virtual = oi->display_height;
+	oi->ivtvfb_defined.bits_per_pixel = oi->bits_per_pixel;
+	oi->ivtvfb_defined.vmode = (osd_laced ? FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED);
+	oi->ivtvfb_defined.left_margin = start_window.left + 1;
+	oi->ivtvfb_defined.upper_margin = start_window.top + 1;
+	oi->ivtvfb_defined.accel_flags = FB_ACCEL_NONE;
+	oi->ivtvfb_defined.nonstd = 0;
+
+	/* We've filled in the most data, let the usual mode check
+	   routine fill in the rest. */
+	_ivtvfb_check_var(&oi->ivtvfb_defined, itv);
+
+	/* Generate valid fb_fix_screeninfo */
+
+	ivtvfb_get_fix(itv, &oi->ivtvfb_fix);
+
+	/* Generate valid fb_info */
+
+	oi->ivtvfb_info.node = -1;
+	oi->ivtvfb_info.flags = FBINFO_FLAG_DEFAULT;
+	oi->ivtvfb_info.fbops = &ivtvfb_ops;
+	oi->ivtvfb_info.par = itv;
+	oi->ivtvfb_info.var = oi->ivtvfb_defined;
+	oi->ivtvfb_info.fix = oi->ivtvfb_fix;
+	oi->ivtvfb_info.screen_base = (u8 __iomem *)oi->video_vbase;
+	oi->ivtvfb_info.fbops = &ivtvfb_ops;
+
+	/* Supply some monitor specs. Bogus values will do for now */
+	oi->ivtvfb_info.monspecs.hfmin = 8000;
+	oi->ivtvfb_info.monspecs.hfmax = 70000;
+	oi->ivtvfb_info.monspecs.vfmin = 10;
+	oi->ivtvfb_info.monspecs.vfmax = 100;
+
+	/* Allocate color map */
+	if (fb_alloc_cmap(&oi->ivtvfb_info.cmap, 256, 1)) {
+		IVTVFB_ERR("abort, unable to alloc cmap\n");
+		return -ENOMEM;
+	}
+
+	/* Allocate the pseudo palette */
+	oi->ivtvfb_info.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+
+	if (!oi->ivtvfb_info.pseudo_palette) {
+		IVTVFB_ERR("abort, unable to alloc pseudo pallete\n");
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/* Find OSD buffer base & size. Add to mtrr. Zero osd buffer. */
+
+static int ivtvfb_init_io(struct ivtv *itv)
+{
+	struct osd_info *oi = itv->osd_info;
+
+	mutex_lock(&itv->serialize_lock);
+	if (ivtv_init_on_first_open(itv)) {
+		mutex_unlock(&itv->serialize_lock);
+		IVTVFB_ERR("Failed to initialize ivtv\n");
+		return -ENXIO;
+	}
+	mutex_unlock(&itv->serialize_lock);
+
+	ivtvfb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);
+
+	/* The osd buffer size depends on the number of video buffers allocated
+	   on the PVR350 itself. For now we'll hardcode the smallest osd buffer
+	   size to prevent any overlap. */
+	oi->video_buffer_size = 1704960;
+
+	oi->video_pbase = itv->base_addr + IVTV_DECODER_OFFSET + oi->video_rbase;
+	oi->video_vbase = itv->dec_mem + oi->video_rbase;
+
+	if (!oi->video_vbase) {
+		IVTVFB_ERR("abort, video memory 0x%x @ 0x%lx isn't mapped!\n",
+		     oi->video_buffer_size, oi->video_pbase);
+		return -EIO;
+	}
+
+	IVTVFB_INFO("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
+			oi->video_pbase, oi->video_vbase,
+			oi->video_buffer_size / 1024);
+
+#ifdef CONFIG_MTRR
+	{
+		/* Find the largest power of two that maps the whole buffer */
+		int size_shift = 31;
+
+		while (!(oi->video_buffer_size & (1 << size_shift))) {
+			size_shift--;
+		}
+		size_shift++;
+		oi->fb_start_aligned_physaddr = oi->video_pbase & ~((1 << size_shift) - 1);
+		oi->fb_end_aligned_physaddr = oi->video_pbase + oi->video_buffer_size;
+		oi->fb_end_aligned_physaddr += (1 << size_shift) - 1;
+		oi->fb_end_aligned_physaddr &= ~((1 << size_shift) - 1);
+		if (mtrr_add(oi->fb_start_aligned_physaddr,
+			oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr,
+			     MTRR_TYPE_WRCOMB, 1) < 0) {
+			IVTVFB_INFO("disabled mttr\n");
+			oi->fb_start_aligned_physaddr = 0;
+			oi->fb_end_aligned_physaddr = 0;
+		}
+	}
+#endif
+
+	/* Blank the entire osd. */
+	memset_io(oi->video_vbase, 0, oi->video_buffer_size);
+
+	return 0;
+}
+
+/* Release any memory we've grabbed & remove mtrr entry */
+static void ivtvfb_release_buffers (struct ivtv *itv)
+{
+	struct osd_info *oi = itv->osd_info;
+
+	/* Release cmap */
+	if (oi->ivtvfb_info.cmap.len)
+		fb_dealloc_cmap(&oi->ivtvfb_info.cmap);
+
+	/* Release pseudo palette */
+	if (oi->ivtvfb_info.pseudo_palette)
+		kfree(oi->ivtvfb_info.pseudo_palette);
+
+#ifdef CONFIG_MTRR
+	if (oi->fb_end_aligned_physaddr) {
+		mtrr_del(-1, oi->fb_start_aligned_physaddr,
+			oi->fb_end_aligned_physaddr - oi->fb_start_aligned_physaddr);
+	}
+#endif
+
+	kfree(oi);
+	itv->osd_info = NULL;
+}
+
+/* Initialize the specified card */
+
+static int ivtvfb_init_card(struct ivtv *itv)
+{
+	int rc;
+
+	if (itv->osd_info) {
+		IVTVFB_ERR("Card %d already initialised\n", ivtvfb_card_id);
+		return -EBUSY;
+	}
+
+	itv->osd_info = kzalloc(sizeof(struct osd_info), GFP_ATOMIC);
+	if (itv->osd_info == 0) {
+		IVTVFB_ERR("Failed to allocate memory for osd_info\n");
+		return -ENOMEM;
+	}
+
+	/* Find & setup the OSD buffer */
+	if ((rc = ivtvfb_init_io(itv)))
+		return rc;
+
+	/* Set the startup video mode information */
+	if ((rc = ivtvfb_init_vidmode(itv))) {
+		ivtvfb_release_buffers(itv);
+		return rc;
+	}
+
+	/* Register the framebuffer */
+	if (register_framebuffer(&itv->osd_info->ivtvfb_info) < 0) {
+		ivtvfb_release_buffers(itv);
+		return -EINVAL;
+	}
+
+	itv->osd_video_pbase = itv->osd_info->video_pbase;
+
+	/* Set the card to the requested mode */
+	ivtvfb_set_par(&itv->osd_info->ivtvfb_info);
+
+	/* Set color 0 to black */
+	write_reg(0, 0x02a30);
+	write_reg(0, 0x02a34);
+
+	/* Enable the osd */
+	ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
+
+	/* Note if we're running in compatibility mode */
+	if (osd_compat)
+		IVTVFB_INFO("Running in compatibility mode. Display resize & mode change disabled\n");
+
+	/* Allocate DMA */
+	ivtv_udma_alloc(itv);
+	return 0;
+
+}
+
+static int __init ivtvfb_init(void)
+{
+	struct ivtv *itv;
+	int i, registered = 0;
+
+	if (ivtvfb_card_id < -1 || ivtvfb_card_id >= IVTV_MAX_CARDS) {
+		printk(KERN_ERR "ivtvfb:  ivtvfb_card_id parameter is out of range (valid range: -1 - %d)\n",
+		     IVTV_MAX_CARDS - 1);
+		return -EINVAL;
+	}
+
+	/* Locate & initialise all cards supporting an OSD. */
+	for (i = 0; i < ivtv_cards_active; i++) {
+		if (ivtvfb_card_id != -1 && i != ivtvfb_card_id)
+			continue;
+		itv = ivtv_cards[i];
+		if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+			if (ivtvfb_init_card(itv) == 0) {
+				IVTVFB_INFO("Framebuffer registered on ivtv card id %d\n", i);
+				registered++;
+			}
+		}
+	}
+	if (!registered) {
+		printk(KERN_ERR "ivtvfb:  no cards found");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static void ivtvfb_cleanup(void)
+{
+	struct ivtv *itv;
+	int i;
+
+	printk(KERN_INFO "ivtvfb:  Unloading framebuffer module\n");
+
+	for (i = 0; i < ivtv_cards_active; i++) {
+		itv = ivtv_cards[i];
+		if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) && itv->osd_info) {
+			IVTVFB_DEBUG_INFO("Unregister framebuffer %d\n", i);
+			ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
+			unregister_framebuffer(&itv->osd_info->ivtvfb_info);
+			ivtvfb_release_buffers(itv);
+			itv->osd_video_pbase = 0;
+		}
+	}
+}
+
+module_init(ivtvfb_init);
+module_exit(ivtvfb_cleanup);
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index 3bb7d66..c0c87e0 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -157,8 +157,7 @@
 			break;
 		v4l_warn(client, "I/O error #%d (read 0x%02x/0x%02x)\n", err,
 		       dev, addr);
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(msecs_to_jiffies(10));
+		schedule_timeout_interruptible(msecs_to_jiffies(10));
 	}
 	if (err == 3) {
 		v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
@@ -197,8 +196,7 @@
 			break;
 		v4l_warn(client, "I/O error #%d (write 0x%02x/0x%02x)\n", err,
 		       dev, addr);
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(msecs_to_jiffies(10));
+		schedule_timeout_interruptible(msecs_to_jiffies(10));
 	}
 	if (err == 3) {
 		v4l_warn(client, "giving up, resetting chip. Sound will go off, sorry folks :-|\n");
@@ -246,17 +244,17 @@
  * ----------------------------------------------------------------------- */
 
 static int scarts[3][9] = {
-       /* MASK   IN1     IN2     IN3     IN4     IN1_DA  IN2_DA  MONO    MUTE   */
+	/* MASK   IN1     IN2     IN3     IN4     IN1_DA  IN2_DA  MONO    MUTE   */
 	/* SCART DSP Input select */
-       { 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1,     -1,     0x0100, 0x0320 },
+	{ 0x0320, 0x0000, 0x0200, 0x0300, 0x0020, -1,     -1,     0x0100, 0x0320 },
 	/* SCART1 Output select */
-       { 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 },
+	{ 0x0c40, 0x0440, 0x0400, 0x0000, 0x0840, 0x0c00, 0x0040, 0x0800, 0x0c40 },
 	/* SCART2 Output select */
-       { 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 },
+	{ 0x3080, 0x1000, 0x1080, 0x2080, 0x3080, 0x0000, 0x0080, 0x2000, 0x3000 },
 };
 
 static char *scart_names[] = {
-       "in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute"
+	"in1", "in2", "in3", "in4", "in1 da", "in2 da", "mono", "mute"
 };
 
 void msp_set_scart(struct i2c_client *client, int in, int out)
@@ -814,10 +812,10 @@
 	int msp_product, msp_prod_hi, msp_prod_lo;
 	int msp_rom;
 
-	client = kmalloc(sizeof(*client), GFP_KERNEL);
-	if (client == NULL)
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
+	if (!client)
 		return -ENOMEM;
-	memset(client, 0, sizeof(*client));
+
 	client->addr = address;
 	client->adapter = adapter;
 	client->driver = &i2c_driver;
@@ -829,14 +827,14 @@
 		return 0;
 	}
 
-	state = kmalloc(sizeof(*state), GFP_KERNEL);
-	if (state == NULL) {
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
+	if (!state) {
 		kfree(client);
 		return -ENOMEM;
 	}
+
 	i2c_set_clientdata(client, state);
 
-	memset(state, 0, sizeof(*state));
 	state->v4l2_std = V4L2_STD_NTSC;
 	state->audmode = V4L2_TUNER_MODE_STEREO;
 	state->volume = 58880;	/* 0db gain */
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
index c7c9f3f8..f49d1f4 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/video/mt20xx.c
@@ -1,13 +1,20 @@
 /*
- *
  * i2c tv tuner chip device driver
  * controls microtune tuners, mt2032 + mt2050 at the moment.
+ *
+ * This "mt20xx" module was split apart from the original "tuner" module.
  */
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/videodev.h>
-#include <linux/moduleparam.h>
-#include <media/tuner.h>
+#include "tuner-i2c.h"
+#include "mt20xx.h"
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+#define PREFIX "mt20xx "
 
 /* ---------------------------------------------------------------------- */
 
@@ -20,9 +27,6 @@
 static unsigned int radio_antenna = 0;
 module_param(radio_antenna,     int, 0644);
 
-/* from tuner-core.c */
-extern int tuner_debug;
-
 /* ---------------------------------------------------------------------- */
 
 #define MT2032 0x04
@@ -37,11 +41,35 @@
 	[ MT2050 ] = "MT2050",
 };
 
+struct microtune_priv {
+	struct tuner_i2c_props i2c_props;
+
+	unsigned int xogc;
+	//unsigned int radio_if2;
+
+	u32 frequency;
+};
+
+static int microtune_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static int microtune_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct microtune_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
 // IsSpurInBand()?
-static int mt2032_spurcheck(struct i2c_client *c,
+static int mt2032_spurcheck(struct dvb_frontend *fe,
 			    int f1, int f2, int spectrum_from,int spectrum_to)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	struct microtune_priv *priv = fe->tuner_priv;
 	int n1=1,n2,f;
 
 	f1=f1/1000; //scale to kHz to avoid 32bit overflows
@@ -69,7 +97,7 @@
 	return 1;
 }
 
-static int mt2032_compute_freq(struct i2c_client *c,
+static int mt2032_compute_freq(struct dvb_frontend *fe,
 			       unsigned int rfin,
 			       unsigned int if1, unsigned int if2,
 			       unsigned int spectrum_from,
@@ -78,7 +106,7 @@
 			       int *ret_sel,
 			       unsigned int xogc) //all in Hz
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	struct microtune_priv *priv = fe->tuner_priv;
 	unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
 		desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq;
 
@@ -128,7 +156,7 @@
 		return(-1);
 	}
 
-	mt2032_spurcheck(c, lo1freq, desired_lo2,  spectrum_from, spectrum_to);
+	mt2032_spurcheck(fe, lo1freq, desired_lo2,  spectrum_from, spectrum_to);
 	// should recalculate lo1 (one step up/down)
 
 	// set up MT2032 register map for transfer over i2c
@@ -152,16 +180,16 @@
 	return 0;
 }
 
-static int mt2032_check_lo_lock(struct i2c_client *c)
+static int mt2032_check_lo_lock(struct dvb_frontend *fe)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	struct microtune_priv *priv = fe->tuner_priv;
 	int try,lock=0;
 	unsigned char buf[2];
 
 	for(try=0;try<10;try++) {
 		buf[0]=0x0e;
-		i2c_master_send(c,buf,1);
-		i2c_master_recv(c,buf,1);
+		tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+		tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
 		tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]);
 		lock=buf[0] &0x06;
 
@@ -174,15 +202,15 @@
 	return lock;
 }
 
-static int mt2032_optimize_vco(struct i2c_client *c,int sel,int lock)
+static int mt2032_optimize_vco(struct dvb_frontend *fe,int sel,int lock)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	struct microtune_priv *priv = fe->tuner_priv;
 	unsigned char buf[2];
 	int tad1;
 
 	buf[0]=0x0f;
-	i2c_master_send(c,buf,1);
-	i2c_master_recv(c,buf,1);
+	tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+	tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
 	tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]);
 	tad1=buf[0]&0x07;
 
@@ -205,57 +233,57 @@
 
 	buf[0]=0x0f;
 	buf[1]=sel;
-	i2c_master_send(c,buf,2);
-	lock=mt2032_check_lo_lock(c);
+	tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
+	lock=mt2032_check_lo_lock(fe);
 	return lock;
 }
 
 
-static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
+static void mt2032_set_if_freq(struct dvb_frontend *fe, unsigned int rfin,
 			       unsigned int if1, unsigned int if2,
 			       unsigned int from, unsigned int to)
 {
 	unsigned char buf[21];
 	int lint_try,ret,sel,lock=0;
-	struct tuner *t = i2c_get_clientdata(c);
+	struct microtune_priv *priv = fe->tuner_priv;
 
 	tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n",
 		  rfin,if1,if2,from,to);
 
 	buf[0]=0;
-	ret=i2c_master_send(c,buf,1);
-	i2c_master_recv(c,buf,21);
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+	tuner_i2c_xfer_recv(&priv->i2c_props,buf,21);
 
 	buf[0]=0;
-	ret=mt2032_compute_freq(c,rfin,if1,if2,from,to,&buf[1],&sel,t->xogc);
+	ret=mt2032_compute_freq(fe,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc);
 	if (ret<0)
 		return;
 
 	// send only the relevant registers per Rev. 1.2
 	buf[0]=0;
-	ret=i2c_master_send(c,buf,4);
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,4);
 	buf[5]=5;
-	ret=i2c_master_send(c,buf+5,4);
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,4);
 	buf[11]=11;
-	ret=i2c_master_send(c,buf+11,3);
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+11,3);
 	if(ret!=3)
 		tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret);
 
 	// wait for PLLs to lock (per manual), retry LINT if not.
 	for(lint_try=0; lint_try<2; lint_try++) {
-		lock=mt2032_check_lo_lock(c);
+		lock=mt2032_check_lo_lock(fe);
 
 		if(optimize_vco)
-			lock=mt2032_optimize_vco(c,sel,lock);
+			lock=mt2032_optimize_vco(fe,sel,lock);
 		if(lock==6) break;
 
 		tuner_dbg("mt2032: re-init PLLs by LINT\n");
 		buf[0]=7;
-		buf[1]=0x80 +8+t->xogc; // set LINT to re-init PLLs
-		i2c_master_send(c,buf,2);
+		buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs
+		tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
 		mdelay(10);
-		buf[1]=8+t->xogc;
-		i2c_master_send(c,buf,2);
+		buf[1]=8+priv->xogc;
+		tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
 	}
 
 	if (lock!=6)
@@ -263,19 +291,19 @@
 
 	buf[0]=2;
 	buf[1]=0x20; // LOGC for optimal phase noise
-	ret=i2c_master_send(c,buf,2);
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
 	if (ret!=2)
 		tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
 }
 
 
-static void mt2032_set_tv_freq(struct i2c_client *c, unsigned int freq)
+static int mt2032_set_tv_freq(struct dvb_frontend *fe,
+			      struct analog_parameters *params)
 {
-	struct tuner *t = i2c_get_clientdata(c);
 	int if2,from,to;
 
 	// signal bandwidth and picture carrier
-	if (t->std & V4L2_STD_525_60) {
+	if (params->std & V4L2_STD_525_60) {
 		// NTSC
 		from = 40750*1000;
 		to   = 46750*1000;
@@ -287,24 +315,64 @@
 		if2  = 38900*1000;
 	}
 
-	mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
+	mt2032_set_if_freq(fe, params->frequency*62500,
 			   1090*1000*1000, if2, from, to);
+
+	return 0;
 }
 
-static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
+static int mt2032_set_radio_freq(struct dvb_frontend *fe,
+				 struct analog_parameters *params)
 {
-	struct tuner *t = i2c_get_clientdata(c);
-	int if2 = t->radio_if2;
+	struct microtune_priv *priv = fe->tuner_priv;
+	int if2;
+
+	if (params->std & V4L2_STD_525_60) {
+		tuner_dbg("pinnacle ntsc\n");
+		if2 = 41300 * 1000;
+	} else {
+		tuner_dbg("pinnacle pal\n");
+		if2 = 33300 * 1000;
+	}
 
 	// per Manual for FM tuning: first if center freq. 1085 MHz
-	mt2032_set_if_freq(c, freq * 1000 / 16,
-			      1085*1000*1000,if2,if2,if2);
+	mt2032_set_if_freq(fe, params->frequency * 125 / 2,
+			   1085*1000*1000,if2,if2,if2);
+
+	return 0;
 }
 
-// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
-static int mt2032_init(struct i2c_client *c)
+static int mt2032_set_params(struct dvb_frontend *fe,
+			     struct analog_parameters *params)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	struct microtune_priv *priv = fe->tuner_priv;
+	int ret = -EINVAL;
+
+	switch (params->mode) {
+	case V4L2_TUNER_RADIO:
+		ret = mt2032_set_radio_freq(fe, params);
+		priv->frequency = params->frequency * 125 / 2;
+		break;
+	case V4L2_TUNER_ANALOG_TV:
+	case V4L2_TUNER_DIGITAL_TV:
+		ret = mt2032_set_tv_freq(fe, params);
+		priv->frequency = params->frequency * 62500;
+		break;
+	}
+
+	return ret;
+}
+
+static struct dvb_tuner_ops mt2032_tuner_ops = {
+	.set_analog_params = mt2032_set_params,
+	.release           = microtune_release,
+	.get_frequency     = microtune_get_frequency,
+};
+
+// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
+static int mt2032_init(struct dvb_frontend *fe)
+{
+	struct microtune_priv *priv = fe->tuner_priv;
 	unsigned char buf[21];
 	int ret,xogc,xok=0;
 
@@ -313,7 +381,7 @@
 	buf[2]=0xff;
 	buf[3]=0x0f;
 	buf[4]=0x1f;
-	ret=i2c_master_send(c,buf+1,4);
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+1,4);
 
 	buf[5]=6; // Index register 6
 	buf[6]=0xe4;
@@ -321,11 +389,11 @@
 	buf[8]=0xc3;
 	buf[9]=0x4e;
 	buf[10]=0xec;
-	ret=i2c_master_send(c,buf+5,6);
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,6);
 
 	buf[12]=13;  // Index register 13
 	buf[13]=0x32;
-	ret=i2c_master_send(c,buf+12,2);
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+12,2);
 
 	// Adjust XOGC (register 7), wait for XOK
 	xogc=7;
@@ -333,8 +401,8 @@
 		tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07);
 		mdelay(10);
 		buf[0]=0x0e;
-		i2c_master_send(c,buf,1);
-		i2c_master_recv(c,buf,1);
+		tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+		tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
 		xok=buf[0]&0x01;
 		tuner_dbg("mt2032: xok = 0x%02x\n",xok);
 		if (xok == 1) break;
@@ -347,32 +415,32 @@
 		}
 		buf[0]=0x07;
 		buf[1]=0x88 + xogc;
-		ret=i2c_master_send(c,buf,2);
+		ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
 		if (ret!=2)
 			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret);
 	} while (xok != 1 );
-	t->xogc=xogc;
+	priv->xogc=xogc;
 
-	t->set_tv_freq    = mt2032_set_tv_freq;
-	t->set_radio_freq = mt2032_set_radio_freq;
+	memcpy(&fe->ops.tuner_ops, &mt2032_tuner_ops, sizeof(struct dvb_tuner_ops));
+
 	return(1);
 }
 
-static void mt2050_set_antenna(struct i2c_client *c, unsigned char antenna)
+static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna)
 {
-	struct tuner *t = i2c_get_clientdata(c);
-       unsigned char buf[2];
-       int ret;
+	struct microtune_priv *priv = fe->tuner_priv;
+	unsigned char buf[2];
+	int ret;
 
-       buf[0] = 6;
-       buf[1] = antenna ? 0x11 : 0x10;
-       ret=i2c_master_send(c,buf,2);
-       tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
+	buf[0] = 6;
+	buf[1] = antenna ? 0x11 : 0x10;
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2);
+	tuner_dbg("mt2050: enabled antenna connector %d\n", antenna);
 }
 
-static void mt2050_set_if_freq(struct i2c_client *c,unsigned int freq, unsigned int if2)
+static void mt2050_set_if_freq(struct dvb_frontend *fe,unsigned int freq, unsigned int if2)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	struct microtune_priv *priv = fe->tuner_priv;
 	unsigned int if1=1218*1000*1000;
 	unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b;
 	int ret;
@@ -404,7 +472,7 @@
 	div2a=(lo2/8)-1;
 	div2b=lo2-(div2a+1)*8;
 
-	if (tuner_debug > 1) {
+	if (debug > 1) {
 		tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2);
 		tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n",
 			  num1,num2,div1a,div1b,div2a,div2b);
@@ -420,7 +488,7 @@
 	buf[5]=div2a;
 	if(num2!=0) buf[5]=buf[5]|0x40;
 
-	if (tuner_debug > 1) {
+	if (debug > 1) {
 		int i;
 		tuner_dbg("bufs is: ");
 		for(i=0;i<6;i++)
@@ -428,87 +496,131 @@
 		printk("\n");
 	}
 
-	ret=i2c_master_send(c,buf,6);
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,6);
 	if (ret!=6)
 		tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret);
 }
 
-static void mt2050_set_tv_freq(struct i2c_client *c, unsigned int freq)
+static int mt2050_set_tv_freq(struct dvb_frontend *fe,
+			      struct analog_parameters *params)
 {
-	struct tuner *t = i2c_get_clientdata(c);
 	unsigned int if2;
 
-	if (t->std & V4L2_STD_525_60) {
+	if (params->std & V4L2_STD_525_60) {
 		// NTSC
 		if2 = 45750*1000;
 	} else {
 		// PAL
 		if2 = 38900*1000;
 	}
-	if (V4L2_TUNER_DIGITAL_TV == t->mode) {
+	if (V4L2_TUNER_DIGITAL_TV == params->mode) {
 		// DVB (pinnacle 300i)
 		if2 = 36150*1000;
 	}
-	mt2050_set_if_freq(c, freq*62500, if2);
-	mt2050_set_antenna(c, tv_antenna);
+	mt2050_set_if_freq(fe, params->frequency*62500, if2);
+	mt2050_set_antenna(fe, tv_antenna);
+
+	return 0;
 }
 
-static void mt2050_set_radio_freq(struct i2c_client *c, unsigned int freq)
+static int mt2050_set_radio_freq(struct dvb_frontend *fe,
+				 struct analog_parameters *params)
 {
-	struct tuner *t = i2c_get_clientdata(c);
-	int if2 = t->radio_if2;
+	struct microtune_priv *priv = fe->tuner_priv;
+	int if2;
 
-	mt2050_set_if_freq(c, freq * 1000 / 16, if2);
-	mt2050_set_antenna(c, radio_antenna);
+	if (params->std & V4L2_STD_525_60) {
+		tuner_dbg("pinnacle ntsc\n");
+		if2 = 41300 * 1000;
+	} else {
+		tuner_dbg("pinnacle pal\n");
+		if2 = 33300 * 1000;
+	}
+
+	mt2050_set_if_freq(fe, params->frequency * 125 / 2, if2);
+	mt2050_set_antenna(fe, radio_antenna);
+
+	return 0;
 }
 
-static int mt2050_init(struct i2c_client *c)
+static int mt2050_set_params(struct dvb_frontend *fe,
+			     struct analog_parameters *params)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	struct microtune_priv *priv = fe->tuner_priv;
+	int ret = -EINVAL;
+
+	switch (params->mode) {
+	case V4L2_TUNER_RADIO:
+		ret = mt2050_set_radio_freq(fe, params);
+		priv->frequency = params->frequency * 125 / 2;
+		break;
+	case V4L2_TUNER_ANALOG_TV:
+	case V4L2_TUNER_DIGITAL_TV:
+		ret = mt2050_set_tv_freq(fe, params);
+		priv->frequency = params->frequency * 62500;
+		break;
+	}
+
+	return ret;
+}
+
+static struct dvb_tuner_ops mt2050_tuner_ops = {
+	.set_analog_params = mt2050_set_params,
+	.release           = microtune_release,
+	.get_frequency     = microtune_get_frequency,
+};
+
+static int mt2050_init(struct dvb_frontend *fe)
+{
+	struct microtune_priv *priv = fe->tuner_priv;
 	unsigned char buf[2];
 	int ret;
 
 	buf[0]=6;
 	buf[1]=0x10;
-	ret=i2c_master_send(c,buf,2); //  power
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); //  power
 
 	buf[0]=0x0f;
 	buf[1]=0x0f;
-	ret=i2c_master_send(c,buf,2); // m1lo
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); // m1lo
 
 	buf[0]=0x0d;
-	ret=i2c_master_send(c,buf,1);
-	i2c_master_recv(c,buf,1);
+	ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+	tuner_i2c_xfer_recv(&priv->i2c_props,buf,1);
 
 	tuner_dbg("mt2050: sro is %x\n",buf[0]);
-	t->set_tv_freq    = mt2050_set_tv_freq;
-	t->set_radio_freq = mt2050_set_radio_freq;
+
+	memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops));
+
 	return 0;
 }
 
-int microtune_init(struct i2c_client *c)
+struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
+				      struct i2c_adapter* i2c_adap,
+				      u8 i2c_addr)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	struct microtune_priv *priv = NULL;
 	char *name;
 	unsigned char buf[21];
 	int company_code;
 
+	priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+	fe->tuner_priv = priv;
+
+	priv->i2c_props.addr = i2c_addr;
+	priv->i2c_props.adap = i2c_adap;
+
+	//priv->radio_if2 = 10700 * 1000;	/* 10.7MHz - FM radio */
+
 	memset(buf,0,sizeof(buf));
-	t->set_tv_freq    = NULL;
-	t->set_radio_freq = NULL;
-	t->standby    = NULL;
-	if (t->std & V4L2_STD_525_60) {
-		tuner_dbg("pinnacle ntsc\n");
-		t->radio_if2 = 41300 * 1000;
-	} else {
-		tuner_dbg("pinnacle pal\n");
-		t->radio_if2 = 33300 * 1000;
-	}
+
 	name = "unknown";
 
-	i2c_master_send(c,buf,1);
-	i2c_master_recv(c,buf,21);
-	if (tuner_debug) {
+	tuner_i2c_xfer_send(&priv->i2c_props,buf,1);
+	tuner_i2c_xfer_recv(&priv->i2c_props,buf,21);
+	if (debug) {
 		int i;
 		tuner_dbg("MT20xx hexdump:");
 		for(i=0;i<21;i++) {
@@ -527,10 +639,10 @@
 		name = microtune_part[buf[0x13]];
 	switch (buf[0x13]) {
 	case MT2032:
-		mt2032_init(c);
+		mt2032_init(fe);
 		break;
 	case MT2050:
-		mt2050_init(c);
+		mt2050_init(fe);
 		break;
 	default:
 		tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n",
@@ -538,11 +650,18 @@
 		return 0;
 	}
 
-	strlcpy(c->name, name, sizeof(c->name));
+	strlcpy(fe->ops.tuner_ops.info.name, name,
+		sizeof(fe->ops.tuner_ops.info.name));
 	tuner_info("microtune %s found, OK\n",name);
-	return 0;
+	return fe;
 }
 
+EXPORT_SYMBOL_GPL(microtune_attach);
+
+MODULE_DESCRIPTION("Microtune tuner driver");
+MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
+MODULE_LICENSE("GPL");
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * ---------------------------------------------------------------------------
diff --git a/drivers/media/video/mt20xx.h b/drivers/media/video/mt20xx.h
new file mode 100644
index 0000000..5e9c825
--- /dev/null
+++ b/drivers/media/video/mt20xx.h
@@ -0,0 +1,37 @@
+/*
+    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.
+*/
+
+#ifndef __MT20XX_H__
+#define __MT20XX_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_TUNER_MT20XX) || (defined(CONFIG_TUNER_MT20XX_MODULE) && defined(MODULE))
+extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
+					     struct i2c_adapter* i2c_adap,
+					     u8 i2c_addr);
+#else
+static inline struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
+					     struct i2c_adapter* i2c_adap,
+					     u8 i2c_addr)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif
+
+#endif /* __MT20XX_H__ */
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index 152cc6b..98ad309 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -153,7 +153,6 @@
 {
 	struct mxb* mxb = NULL;
 	struct i2c_client *client;
-	struct list_head *item;
 	int result;
 
 	if ((result = request_module("saa7111")) < 0) {
@@ -196,8 +195,7 @@
 	}
 
 	/* loop through all i2c-devices on the bus and look who is there */
-	list_for_each(item,&mxb->i2c_adapter.clients) {
-		client = list_entry(item, struct i2c_client, list);
+	list_for_each_entry(client, &mxb->i2c_adapter.clients, list) {
 		if( I2C_ADDR_TEA6420_1 == client->addr )
 			mxb->tea6420_1 = client;
 		if( I2C_ADDR_TEA6420_2 == client->addr )
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
index e5edff1..9eb2562 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -5554,41 +5554,46 @@
  *  sysfs
  ***************************************************************************/
 
-static inline struct usb_ov511 *cd_to_ov(struct class_device *cd)
+static inline struct usb_ov511 *cd_to_ov(struct device *cd)
 {
 	struct video_device *vdev = to_video_device(cd);
 	return video_get_drvdata(vdev);
 }
 
-static ssize_t show_custom_id(struct class_device *cd, char *buf)
+static ssize_t show_custom_id(struct device *cd,
+			      struct device_attribute *attr, char *buf)
 {
 	struct usb_ov511 *ov = cd_to_ov(cd);
 	return sprintf(buf, "%d\n", ov->customid);
 }
-static CLASS_DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL);
+static DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL);
 
-static ssize_t show_model(struct class_device *cd, char *buf)
+static ssize_t show_model(struct device *cd,
+			  struct device_attribute *attr, char *buf)
 {
 	struct usb_ov511 *ov = cd_to_ov(cd);
 	return sprintf(buf, "%s\n", ov->desc);
 }
-static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
+static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
 
-static ssize_t show_bridge(struct class_device *cd, char *buf)
+static ssize_t show_bridge(struct device *cd,
+			   struct device_attribute *attr, char *buf)
 {
 	struct usb_ov511 *ov = cd_to_ov(cd);
 	return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge));
 }
-static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL);
+static DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL);
 
-static ssize_t show_sensor(struct class_device *cd, char *buf)
+static ssize_t show_sensor(struct device *cd,
+			   struct device_attribute *attr, char *buf)
 {
 	struct usb_ov511 *ov = cd_to_ov(cd);
 	return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor));
 }
-static CLASS_DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL);
+static DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL);
 
-static ssize_t show_brightness(struct class_device *cd, char *buf)
+static ssize_t show_brightness(struct device *cd,
+			       struct device_attribute *attr, char *buf)
 {
 	struct usb_ov511 *ov = cd_to_ov(cd);
 	unsigned short x;
@@ -5598,9 +5603,10 @@
 	sensor_get_brightness(ov, &x);
 	return sprintf(buf, "%d\n", x >> 8);
 }
-static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
+static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
 
-static ssize_t show_saturation(struct class_device *cd, char *buf)
+static ssize_t show_saturation(struct device *cd,
+			       struct device_attribute *attr, char *buf)
 {
 	struct usb_ov511 *ov = cd_to_ov(cd);
 	unsigned short x;
@@ -5610,9 +5616,10 @@
 	sensor_get_saturation(ov, &x);
 	return sprintf(buf, "%d\n", x >> 8);
 }
-static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
+static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
 
-static ssize_t show_contrast(struct class_device *cd, char *buf)
+static ssize_t show_contrast(struct device *cd,
+			     struct device_attribute *attr, char *buf)
 {
 	struct usb_ov511 *ov = cd_to_ov(cd);
 	unsigned short x;
@@ -5622,9 +5629,10 @@
 	sensor_get_contrast(ov, &x);
 	return sprintf(buf, "%d\n", x >> 8);
 }
-static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
+static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
 
-static ssize_t show_hue(struct class_device *cd, char *buf)
+static ssize_t show_hue(struct device *cd,
+			struct device_attribute *attr, char *buf)
 {
 	struct usb_ov511 *ov = cd_to_ov(cd);
 	unsigned short x;
@@ -5634,9 +5642,10 @@
 	sensor_get_hue(ov, &x);
 	return sprintf(buf, "%d\n", x >> 8);
 }
-static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
+static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
 
-static ssize_t show_exposure(struct class_device *cd, char *buf)
+static ssize_t show_exposure(struct device *cd,
+			     struct device_attribute *attr, char *buf)
 {
 	struct usb_ov511 *ov = cd_to_ov(cd);
 	unsigned char exp = 0;
@@ -5646,49 +5655,49 @@
 	sensor_get_exposure(ov, &exp);
 	return sprintf(buf, "%d\n", exp >> 8);
 }
-static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
+static DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
 
 static int ov_create_sysfs(struct video_device *vdev)
 {
 	int rc;
 
-	rc = video_device_create_file(vdev, &class_device_attr_custom_id);
+	rc = video_device_create_file(vdev, &dev_attr_custom_id);
 	if (rc) goto err;
-	rc = video_device_create_file(vdev, &class_device_attr_model);
+	rc = video_device_create_file(vdev, &dev_attr_model);
 	if (rc) goto err_id;
-	rc = video_device_create_file(vdev, &class_device_attr_bridge);
+	rc = video_device_create_file(vdev, &dev_attr_bridge);
 	if (rc) goto err_model;
-	rc = video_device_create_file(vdev, &class_device_attr_sensor);
+	rc = video_device_create_file(vdev, &dev_attr_sensor);
 	if (rc) goto err_bridge;
-	rc = video_device_create_file(vdev, &class_device_attr_brightness);
+	rc = video_device_create_file(vdev, &dev_attr_brightness);
 	if (rc) goto err_sensor;
-	rc = video_device_create_file(vdev, &class_device_attr_saturation);
+	rc = video_device_create_file(vdev, &dev_attr_saturation);
 	if (rc) goto err_bright;
-	rc = video_device_create_file(vdev, &class_device_attr_contrast);
+	rc = video_device_create_file(vdev, &dev_attr_contrast);
 	if (rc) goto err_sat;
-	rc = video_device_create_file(vdev, &class_device_attr_hue);
+	rc = video_device_create_file(vdev, &dev_attr_hue);
 	if (rc) goto err_contrast;
-	rc = video_device_create_file(vdev, &class_device_attr_exposure);
+	rc = video_device_create_file(vdev, &dev_attr_exposure);
 	if (rc) goto err_hue;
 
 	return 0;
 
 err_hue:
-	video_device_remove_file(vdev, &class_device_attr_hue);
+	video_device_remove_file(vdev, &dev_attr_hue);
 err_contrast:
-	video_device_remove_file(vdev, &class_device_attr_contrast);
+	video_device_remove_file(vdev, &dev_attr_contrast);
 err_sat:
-	video_device_remove_file(vdev, &class_device_attr_saturation);
+	video_device_remove_file(vdev, &dev_attr_saturation);
 err_bright:
-	video_device_remove_file(vdev, &class_device_attr_brightness);
+	video_device_remove_file(vdev, &dev_attr_brightness);
 err_sensor:
-	video_device_remove_file(vdev, &class_device_attr_sensor);
+	video_device_remove_file(vdev, &dev_attr_sensor);
 err_bridge:
-	video_device_remove_file(vdev, &class_device_attr_bridge);
+	video_device_remove_file(vdev, &dev_attr_bridge);
 err_model:
-	video_device_remove_file(vdev, &class_device_attr_model);
+	video_device_remove_file(vdev, &dev_attr_model);
 err_id:
-	video_device_remove_file(vdev, &class_device_attr_custom_id);
+	video_device_remove_file(vdev, &dev_attr_custom_id);
 err:
 	return rc;
 }
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
index 3ceb8a6..2bc6bdc 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/video/ov7670.c
@@ -12,7 +12,6 @@
  */
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/videodev.h>
@@ -416,7 +415,10 @@
 static int ov7670_write(struct i2c_client *c, unsigned char reg,
 		unsigned char value)
 {
-	return i2c_smbus_write_byte_data(c, reg, value);
+	int ret = i2c_smbus_write_byte_data(c, reg, value);
+	if (reg == REG_COM7 && (value & COM7_RESET))
+		msleep(2);  /* Wait for reset to run */
+	return ret;
 }
 
 
@@ -617,7 +619,7 @@
 	},
 };
 
-#define N_WIN_SIZES (sizeof(ov7670_win_sizes)/sizeof(ov7670_win_sizes[0]))
+#define N_WIN_SIZES (ARRAY_SIZE(ov7670_win_sizes))
 
 
 /*
@@ -1183,7 +1185,7 @@
 		.query = ov7670_q_hflip,
 	},
 };
-#define N_CONTROLS (sizeof(ov7670_controls)/sizeof(ov7670_controls[0]))
+#define N_CONTROLS (ARRAY_SIZE(ov7670_controls))
 
 static struct ov7670_control *ov7670_find_control(__u32 id)
 {
diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c
index 3fe9fa0..8063e33 100644
--- a/drivers/media/video/ovcamchip/ovcamchip_core.c
+++ b/drivers/media/video/ovcamchip/ovcamchip_core.c
@@ -13,7 +13,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include "ovcamchip_priv.h"
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
index 1455a8f..0ef73d9 100644
--- a/drivers/media/video/planb.c
+++ b/drivers/media/video/planb.c
@@ -353,9 +353,8 @@
 		* PLANB_DUMMY)*sizeof(struct dbdma_cmd)
 		+(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8
 		+MAX_GBUFFERS*sizeof(unsigned int);
-	if ((pb->priv_space = kmalloc (size, GFP_KERNEL)) == 0)
+	if ((pb->priv_space = kzalloc (size, GFP_KERNEL)) == 0)
 		return -ENOMEM;
-	memset ((void *) pb->priv_space, 0, size);
 	pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *)
 						DBDMA_ALIGN (pb->priv_space);
 	pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size;
@@ -845,21 +844,21 @@
 /*********************************/
 
 static int palette2fmt[] = {
-       0,
-       PLANB_GRAY,
-       0,
-       0,
-       0,
-       PLANB_COLOUR32,
-       PLANB_COLOUR15,
-       0,
-       0,
-       0,
-       0,
-       0,
-       0,
-       0,
-       0,
+	0,
+	PLANB_GRAY,
+	0,
+	0,
+	0,
+	PLANB_COLOUR32,
+	PLANB_COLOUR15,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
+	0,
 };
 
 #define PLANB_PALETTE_MAX 15
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c
index 6bbed88..22719ba 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.c
@@ -33,8 +33,10 @@
 {
 	if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
 	pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp);
-	flush_workqueue(mp->workqueue);
-	destroy_workqueue(mp->workqueue);
+	if (mp->workqueue) {
+		flush_workqueue(mp->workqueue);
+		destroy_workqueue(mp->workqueue);
+	}
 	kfree(mp);
 }
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h
index d95a858..da6441b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debug.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h
@@ -26,32 +26,33 @@
 
 /* These are listed in *rough* order of decreasing usefulness and
    increasing noise level. */
-#define PVR2_TRACE_INFO       (1 <<  0) // Normal messages
-#define PVR2_TRACE_ERROR_LEGS (1 <<  1) // error messages
-#define PVR2_TRACE_TOLERANCE  (1 <<  2) // track tolerance-affected errors
-#define PVR2_TRACE_TRAP       (1 <<  3) // Trap & report misbehavior from app
-#define PVR2_TRACE_INIT       (1 <<  4) // misc initialization steps
-#define PVR2_TRACE_START_STOP (1 <<  5) // Streaming start / stop
-#define PVR2_TRACE_CTL        (1 <<  6) // commit of control changes
-#define PVR2_TRACE_DEBUG      (1 <<  7) // Temporary debug code
-#define PVR2_TRACE_EEPROM     (1 <<  8) // eeprom parsing / report
-#define PVR2_TRACE_STRUCT     (1 <<  9) // internal struct creation
-#define PVR2_TRACE_OPEN_CLOSE (1 << 10) // application open / close
-#define PVR2_TRACE_CREG       (1 << 11) // Main critical region entry / exit
-#define PVR2_TRACE_SYSFS      (1 << 12) // Sysfs driven I/O
-#define PVR2_TRACE_FIRMWARE   (1 << 13) // firmware upload actions
-#define PVR2_TRACE_CHIPS      (1 << 14) // chip broadcast operation
-#define PVR2_TRACE_I2C        (1 << 15) // I2C related stuff
-#define PVR2_TRACE_I2C_CMD    (1 << 16) // Software commands to I2C modules
-#define PVR2_TRACE_I2C_CORE   (1 << 17) // I2C core debugging
-#define PVR2_TRACE_I2C_TRAF   (1 << 18) // I2C traffic through the adapter
-#define PVR2_TRACE_V4LIOCTL   (1 << 19) // v4l ioctl details
-#define PVR2_TRACE_ENCODER    (1 << 20) // mpeg2 encoder operation
-#define PVR2_TRACE_BUF_POOL   (1 << 21) // Track buffer pool management
-#define PVR2_TRACE_BUF_FLOW   (1 << 22) // Track buffer flow in system
-#define PVR2_TRACE_DATA_FLOW  (1 << 23) // Track data flow
-#define PVR2_TRACE_DEBUGIFC   (1 << 24) // Debug interface actions
-#define PVR2_TRACE_GPIO       (1 << 25) // GPIO state bit changes
+#define PVR2_TRACE_INFO       (1 <<  0) /* Normal messages */
+#define PVR2_TRACE_ERROR_LEGS (1 <<  1) /* error messages */
+#define PVR2_TRACE_TOLERANCE  (1 <<  2) /* track tolerance-affected errors */
+#define PVR2_TRACE_TRAP       (1 <<  3) /* Trap & report app misbehavior */
+#define PVR2_TRACE_STD        (1 <<  4) /* Log video standard stuff */
+#define PVR2_TRACE_INIT       (1 <<  5) /* misc initialization steps */
+#define PVR2_TRACE_START_STOP (1 <<  6) /* Streaming start / stop */
+#define PVR2_TRACE_CTL        (1 <<  7) /* commit of control changes */
+#define PVR2_TRACE_DEBUG      (1 <<  8) /* Temporary debug code */
+#define PVR2_TRACE_EEPROM     (1 <<  9) /* eeprom parsing / report */
+#define PVR2_TRACE_STRUCT     (1 << 10) /* internal struct creation */
+#define PVR2_TRACE_OPEN_CLOSE (1 << 11) /* application open / close */
+#define PVR2_TRACE_CREG       (1 << 12) /* Main critical region entry / exit */
+#define PVR2_TRACE_SYSFS      (1 << 13) /* Sysfs driven I/O */
+#define PVR2_TRACE_FIRMWARE   (1 << 14) /* firmware upload actions */
+#define PVR2_TRACE_CHIPS      (1 << 15) /* chip broadcast operation */
+#define PVR2_TRACE_I2C        (1 << 16) /* I2C related stuff */
+#define PVR2_TRACE_I2C_CMD    (1 << 17) /* Software commands to I2C modules */
+#define PVR2_TRACE_I2C_CORE   (1 << 18) /* I2C core debugging */
+#define PVR2_TRACE_I2C_TRAF   (1 << 19) /* I2C traffic through the adapter */
+#define PVR2_TRACE_V4LIOCTL   (1 << 20) /* v4l ioctl details */
+#define PVR2_TRACE_ENCODER    (1 << 21) /* mpeg2 encoder operation */
+#define PVR2_TRACE_BUF_POOL   (1 << 22) /* Track buffer pool management */
+#define PVR2_TRACE_BUF_FLOW   (1 << 23) /* Track buffer flow in system */
+#define PVR2_TRACE_DATA_FLOW  (1 << 24) /* Track data flow */
+#define PVR2_TRACE_DEBUGIFC   (1 << 25) /* Debug interface actions */
+#define PVR2_TRACE_GPIO       (1 << 26) /* GPIO state bit changes */
 
 
 #endif /* __PVRUSB2_HDW_INTERNAL_H */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index e9da9bb..6f135f4 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -397,10 +397,22 @@
 		count -= scnt; buf += scnt;
 		if (!wptr) return -EINVAL;
 		if (debugifc_match_keyword(wptr,wlen,"fetch")) {
-			pvr2_hdw_cpufw_set_enabled(hdw,!0);
+			scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+			if (scnt && wptr) {
+				count -= scnt; buf += scnt;
+				if (debugifc_match_keyword(wptr,wlen,"prom")) {
+					pvr2_hdw_cpufw_set_enabled(hdw,!0,!0);
+				} else if (debugifc_match_keyword(wptr,wlen,
+								  "ram")) {
+					pvr2_hdw_cpufw_set_enabled(hdw,0,!0);
+				} else {
+					return -EINVAL;
+				}
+			}
+			pvr2_hdw_cpufw_set_enabled(hdw,0,!0);
 			return 0;
 		} else if (debugifc_match_keyword(wptr,wlen,"done")) {
-			pvr2_hdw_cpufw_set_enabled(hdw,0);
+			pvr2_hdw_cpufw_set_enabled(hdw,0,0);
 			return 0;
 		} else {
 			return -EINVAL;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index ce66ab8..985d9ae 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -238,6 +238,7 @@
 	// CPU firmware info (used to help find / save firmware data)
 	char *fw_buffer;
 	unsigned int fw_size;
+	int fw_cpu_flag; /* True if we are dealing with the CPU */
 
 	// Which subsystem pieces have been enabled / configured
 	unsigned long subsys_enabled_mask;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 1311891..27b12b4b 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -492,7 +492,7 @@
 	cs.controls = &c1;
 	cs.count = 1;
 	c1.id = cptr->info->v4l_id;
-	ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs,
+	ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs,
 				VIDIOC_G_EXT_CTRLS);
 	if (ret) return ret;
 	*vp = c1.value;
@@ -510,7 +510,7 @@
 	cs.count = 1;
 	c1.id = cptr->info->v4l_id;
 	c1.value = v;
-	ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs,
+	ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state, 0, &cs,
 				VIDIOC_S_EXT_CTRLS);
 	if (ret) return ret;
 	cptr->hdw->enc_stale = !0;
@@ -1143,6 +1143,13 @@
 			fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx)
 		},
 	};
+
+	if ((hdw->hdw_type >= ARRAY_SIZE(fw_file_defs)) ||
+	    (!fw_file_defs[hdw->hdw_type].lst)) {
+		hdw->fw1_state = FW1_STATE_OK;
+		return 0;
+	}
+
 	hdw->fw1_state = FW1_STATE_FAILED; // default result
 
 	trace_firmware("pvr2_upload_firmware1");
@@ -1224,6 +1231,11 @@
 		CX2341X_FIRM_ENC_FILENAME,
 	};
 
+	if ((hdw->hdw_type != PVR2_HDW_TYPE_29XXX) &&
+	    (hdw->hdw_type != PVR2_HDW_TYPE_24XXX)) {
+		return 0;
+	}
+
 	trace_firmware("pvr2_upload_firmware2");
 
 	ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder",
@@ -1682,6 +1694,44 @@
 	return result == 0;
 }
 
+struct pvr2_std_hack {
+	v4l2_std_id pat;  /* Pattern to match */
+	v4l2_std_id msk;  /* Which bits we care about */
+	v4l2_std_id std;  /* What additional standards or default to set */
+};
+
+/* This data structure labels specific combinations of standards from
+   tveeprom that we'll try to recognize.  If we recognize one, then assume
+   a specified default standard to use.  This is here because tveeprom only
+   tells us about available standards not the intended default standard (if
+   any) for the device in question.  We guess the default based on what has
+   been reported as available.  Note that this is only for guessing a
+   default - which can always be overridden explicitly - and if the user
+   has otherwise named a default then that default will always be used in
+   place of this table. */
+const static struct pvr2_std_hack std_eeprom_maps[] = {
+	{	/* PAL(B/G) */
+		.pat = V4L2_STD_B|V4L2_STD_GH,
+		.std = V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_PAL_G,
+	},
+	{	/* NTSC(M) */
+		.pat = V4L2_STD_MN,
+		.std = V4L2_STD_NTSC_M,
+	},
+	{	/* PAL(I) */
+		.pat = V4L2_STD_PAL_I,
+		.std = V4L2_STD_PAL_I,
+	},
+	{	/* SECAM(L/L') */
+		.pat = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC,
+		.std = V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC,
+	},
+	{	/* PAL(D/D1/K) */
+		.pat = V4L2_STD_DK,
+		.std = V4L2_STD_PAL_D/V4L2_STD_PAL_D1|V4L2_STD_PAL_K,
+	},
+};
+
 static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
 {
 	char buf[40];
@@ -1691,7 +1741,7 @@
 	std1 = get_default_standard(hdw);
 
 	bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom);
-	pvr2_trace(PVR2_TRACE_INIT,
+	pvr2_trace(PVR2_TRACE_STD,
 		   "Supported video standard(s) reported by eeprom: %.*s",
 		   bcnt,buf);
 
@@ -1700,7 +1750,7 @@
 	std2 = std1 & ~hdw->std_mask_avail;
 	if (std2) {
 		bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2);
-		pvr2_trace(PVR2_TRACE_INIT,
+		pvr2_trace(PVR2_TRACE_STD,
 			   "Expanding supported video standards"
 			   " to include: %.*s",
 			   bcnt,buf);
@@ -1711,7 +1761,7 @@
 
 	if (std1) {
 		bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std1);
-		pvr2_trace(PVR2_TRACE_INIT,
+		pvr2_trace(PVR2_TRACE_STD,
 			   "Initial video standard forced to %.*s",
 			   bcnt,buf);
 		hdw->std_mask_cur = std1;
@@ -1720,12 +1770,33 @@
 		return;
 	}
 
+	{
+		unsigned int idx;
+		for (idx = 0; idx < ARRAY_SIZE(std_eeprom_maps); idx++) {
+			if (std_eeprom_maps[idx].msk ?
+			    ((std_eeprom_maps[idx].pat ^
+			     hdw->std_mask_eeprom) &
+			     std_eeprom_maps[idx].msk) :
+			    (std_eeprom_maps[idx].pat !=
+			     hdw->std_mask_eeprom)) continue;
+			bcnt = pvr2_std_id_to_str(buf,sizeof(buf),
+						  std_eeprom_maps[idx].std);
+			pvr2_trace(PVR2_TRACE_STD,
+				   "Initial video standard guessed as %.*s",
+				   bcnt,buf);
+			hdw->std_mask_cur = std_eeprom_maps[idx].std;
+			hdw->std_dirty = !0;
+			pvr2_hdw_internal_find_stdenum(hdw);
+			return;
+		}
+	}
+
 	if (hdw->std_enum_cnt > 1) {
 		// Autoselect the first listed standard
 		hdw->std_enum_cur = 1;
 		hdw->std_mask_cur = hdw->std_defs[hdw->std_enum_cur-1].id;
 		hdw->std_dirty = !0;
-		pvr2_trace(PVR2_TRACE_INIT,
+		pvr2_trace(PVR2_TRACE_STD,
 			   "Initial video standard auto-selected to %s",
 			   hdw->std_defs[hdw->std_enum_cur-1].name);
 		return;
@@ -1742,30 +1813,36 @@
 	unsigned int idx;
 	struct pvr2_ctrl *cptr;
 	int reloadFl = 0;
-	if (!reloadFl) {
-		reloadFl = (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints
-			    == 0);
+	if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) ||
+	    (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) {
+		if (!reloadFl) {
+			reloadFl =
+				(hdw->usb_intf->cur_altsetting->desc.bNumEndpoints
+				 == 0);
+			if (reloadFl) {
+				pvr2_trace(PVR2_TRACE_INIT,
+					   "USB endpoint config looks strange"
+					   "; possibly firmware needs to be"
+					   " loaded");
+			}
+		}
+		if (!reloadFl) {
+			reloadFl = !pvr2_hdw_check_firmware(hdw);
+			if (reloadFl) {
+				pvr2_trace(PVR2_TRACE_INIT,
+					   "Check for FX2 firmware failed"
+					   "; possibly firmware needs to be"
+					   " loaded");
+			}
+		}
 		if (reloadFl) {
-			pvr2_trace(PVR2_TRACE_INIT,
-				   "USB endpoint config looks strange"
-				   "; possibly firmware needs to be loaded");
+			if (pvr2_upload_firmware1(hdw) != 0) {
+				pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+					   "Failure uploading firmware1");
+			}
+			return;
 		}
 	}
-	if (!reloadFl) {
-		reloadFl = !pvr2_hdw_check_firmware(hdw);
-		if (reloadFl) {
-			pvr2_trace(PVR2_TRACE_INIT,
-				   "Check for FX2 firmware failed"
-				   "; possibly firmware needs to be loaded");
-		}
-	}
-	if (reloadFl) {
-		if (pvr2_upload_firmware1(hdw) != 0) {
-			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
-				   "Failure uploading firmware1");
-		}
-		return;
-	}
 	hdw->fw1_state = FW1_STATE_OK;
 
 	if (initusbreset) {
@@ -1773,17 +1850,25 @@
 	}
 	if (!pvr2_hdw_dev_ok(hdw)) return;
 
-	for (idx = 0; idx < pvr2_client_lists[hdw->hdw_type].cnt; idx++) {
-		request_module(pvr2_client_lists[hdw->hdw_type].lst[idx]);
+	if (hdw->hdw_type < ARRAY_SIZE(pvr2_client_lists)) {
+		for (idx = 0;
+		     idx < pvr2_client_lists[hdw->hdw_type].cnt;
+		     idx++) {
+			request_module(
+				pvr2_client_lists[hdw->hdw_type].lst[idx]);
+		}
 	}
 
-	pvr2_hdw_cmd_powerup(hdw);
-	if (!pvr2_hdw_dev_ok(hdw)) return;
+	if ((hdw->hdw_type == PVR2_HDW_TYPE_29XXX) ||
+	    (hdw->hdw_type == PVR2_HDW_TYPE_24XXX)) {
+		pvr2_hdw_cmd_powerup(hdw);
+		if (!pvr2_hdw_dev_ok(hdw)) return;
 
-	if (pvr2_upload_firmware2(hdw)){
-		pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!");
-		pvr2_hdw_render_useless(hdw);
-		return;
+		if (pvr2_upload_firmware2(hdw)){
+			pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!");
+			pvr2_hdw_render_useless(hdw);
+			return;
+		}
 	}
 
 	// This step MUST happen after the earlier powerup step.
@@ -2172,6 +2257,7 @@
 /* Destroy hardware interaction structure */
 void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
 {
+	if (!hdw) return;
 	pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw);
 	if (hdw->fw_buffer) {
 		kfree(hdw->fw_buffer);
@@ -2478,7 +2564,7 @@
 		cs.count = 1;
 		c1.id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ;
 		c1.value = hdw->srate_val;
-		cx2341x_ext_ctrls(&hdw->enc_ctl_state,&cs,VIDIOC_S_EXT_CTRLS);
+		cx2341x_ext_ctrls(&hdw->enc_ctl_state, 0, &cs,VIDIOC_S_EXT_CTRLS);
 	}
 
 	/* Scan i2c core at this point - before we clear all the dirty
@@ -2604,7 +2690,85 @@
 	} while (0); LOCK_GIVE(hdw->big_lock);
 }
 
-void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
+
+/* Grab EEPROM contents, needed for direct method. */
+#define EEPROM_SIZE 8192
+#define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__)
+static u8 *pvr2_full_eeprom_fetch(struct pvr2_hdw *hdw)
+{
+	struct i2c_msg msg[2];
+	u8 *eeprom;
+	u8 iadd[2];
+	u8 addr;
+	u16 eepromSize;
+	unsigned int offs;
+	int ret;
+	int mode16 = 0;
+	unsigned pcnt,tcnt;
+	eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL);
+	if (!eeprom) {
+		pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+			   "Failed to allocate memory"
+			   " required to read eeprom");
+		return NULL;
+	}
+
+	trace_eeprom("Value for eeprom addr from controller was 0x%x",
+		     hdw->eeprom_addr);
+	addr = hdw->eeprom_addr;
+	/* Seems that if the high bit is set, then the *real* eeprom
+	   address is shifted right now bit position (noticed this in
+	   newer PVR USB2 hardware) */
+	if (addr & 0x80) addr >>= 1;
+
+	/* FX2 documentation states that a 16bit-addressed eeprom is
+	   expected if the I2C address is an odd number (yeah, this is
+	   strange but it's what they do) */
+	mode16 = (addr & 1);
+	eepromSize = (mode16 ? EEPROM_SIZE : 256);
+	trace_eeprom("Examining %d byte eeprom at location 0x%x"
+		     " using %d bit addressing",eepromSize,addr,
+		     mode16 ? 16 : 8);
+
+	msg[0].addr = addr;
+	msg[0].flags = 0;
+	msg[0].len = mode16 ? 2 : 1;
+	msg[0].buf = iadd;
+	msg[1].addr = addr;
+	msg[1].flags = I2C_M_RD;
+
+	/* We have to do the actual eeprom data fetch ourselves, because
+	   (1) we're only fetching part of the eeprom, and (2) if we were
+	   getting the whole thing our I2C driver can't grab it in one
+	   pass - which is what tveeprom is otherwise going to attempt */
+	memset(eeprom,0,EEPROM_SIZE);
+	for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) {
+		pcnt = 16;
+		if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt;
+		offs = tcnt + (eepromSize - EEPROM_SIZE);
+		if (mode16) {
+			iadd[0] = offs >> 8;
+			iadd[1] = offs;
+		} else {
+			iadd[0] = offs;
+		}
+		msg[1].len = pcnt;
+		msg[1].buf = eeprom+tcnt;
+		if ((ret = i2c_transfer(&hdw->i2c_adap,
+					msg,ARRAY_SIZE(msg))) != 2) {
+			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+				   "eeprom fetch set offs err=%d",ret);
+			kfree(eeprom);
+			return NULL;
+		}
+	}
+	return eeprom;
+}
+
+
+void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw,
+				int prom_flag,
+				int enable_flag)
 {
 	int ret;
 	u16 address;
@@ -2618,38 +2782,60 @@
 			kfree(hdw->fw_buffer);
 			hdw->fw_buffer = NULL;
 			hdw->fw_size = 0;
-			/* Now release the CPU.  It will disconnect and
-			   reconnect later. */
-			pvr2_hdw_cpureset_assert(hdw,0);
+			if (hdw->fw_cpu_flag) {
+				/* Now release the CPU.  It will disconnect
+				   and reconnect later. */
+				pvr2_hdw_cpureset_assert(hdw,0);
+			}
 			break;
 		}
 
-		pvr2_trace(PVR2_TRACE_FIRMWARE,
-			   "Preparing to suck out CPU firmware");
-		hdw->fw_size = 0x2000;
-		hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL);
-		if (!hdw->fw_buffer) {
-			hdw->fw_size = 0;
-			break;
+		hdw->fw_cpu_flag = (prom_flag == 0);
+		if (hdw->fw_cpu_flag) {
+			pvr2_trace(PVR2_TRACE_FIRMWARE,
+				   "Preparing to suck out CPU firmware");
+			hdw->fw_size = 0x2000;
+			hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL);
+			if (!hdw->fw_buffer) {
+				hdw->fw_size = 0;
+				break;
+			}
+
+			/* We have to hold the CPU during firmware upload. */
+			pvr2_hdw_cpureset_assert(hdw,1);
+
+			/* download the firmware from address 0000-1fff in 2048
+			   (=0x800) bytes chunk. */
+
+			pvr2_trace(PVR2_TRACE_FIRMWARE,
+				   "Grabbing CPU firmware");
+			pipe = usb_rcvctrlpipe(hdw->usb_dev, 0);
+			for(address = 0; address < hdw->fw_size;
+			    address += 0x800) {
+				ret = usb_control_msg(hdw->usb_dev,pipe,
+						      0xa0,0xc0,
+						      address,0,
+						      hdw->fw_buffer+address,
+						      0x800,HZ);
+				if (ret < 0) break;
+			}
+
+			pvr2_trace(PVR2_TRACE_FIRMWARE,
+				   "Done grabbing CPU firmware");
+		} else {
+			pvr2_trace(PVR2_TRACE_FIRMWARE,
+				   "Sucking down EEPROM contents");
+			hdw->fw_buffer = pvr2_full_eeprom_fetch(hdw);
+			if (!hdw->fw_buffer) {
+				pvr2_trace(PVR2_TRACE_FIRMWARE,
+					   "EEPROM content suck failed.");
+				break;
+			}
+			hdw->fw_size = EEPROM_SIZE;
+			pvr2_trace(PVR2_TRACE_FIRMWARE,
+				   "Done sucking down EEPROM contents");
 		}
 
-		/* We have to hold the CPU during firmware upload. */
-		pvr2_hdw_cpureset_assert(hdw,1);
-
-		/* download the firmware from address 0000-1fff in 2048
-		   (=0x800) bytes chunk. */
-
-		pvr2_trace(PVR2_TRACE_FIRMWARE,"Grabbing CPU firmware");
-		pipe = usb_rcvctrlpipe(hdw->usb_dev, 0);
-		for(address = 0; address < hdw->fw_size; address += 0x800) {
-			ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0xc0,
-					      address,0,
-					      hdw->fw_buffer+address,0x800,HZ);
-			if (ret < 0) break;
-		}
-
-		pvr2_trace(PVR2_TRACE_FIRMWARE,"Done grabbing CPU firmware");
-
 	} while (0); LOCK_GIVE(hdw->big_lock);
 }
 
@@ -3272,7 +3458,6 @@
 			     int setFl,u64 *val_ptr)
 {
 #ifdef CONFIG_VIDEO_ADV_DEBUG
-	struct list_head *item;
 	struct pvr2_i2c_client *cp;
 	struct v4l2_register req;
 	int stat = 0;
@@ -3285,8 +3470,7 @@
 	req.reg = reg_id;
 	if (setFl) req.val = *val_ptr;
 	mutex_lock(&hdw->i2c_list_lock); do {
-		list_for_each(item,&hdw->i2c_clients) {
-			cp = list_entry(item,struct pvr2_i2c_client,list);
+		list_for_each_entry(cp, &hdw->i2c_clients, list) {
 			if (!v4l2_chip_match_i2c_client(
 				    cp->client,
 				    req.match_type, req.match_chip)) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 4dba8d0..e2f9d5e 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -197,11 +197,13 @@
 unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *);
 
 
-/* Enable / disable retrieval of CPU firmware.  This must be enabled before
-   pvr2_hdw_cpufw_get() will function.  Note that doing this may prevent
-   the device from running (and leaving this mode may imply a device
-   reset). */
-void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *, int enable_flag);
+/* Enable / disable retrieval of CPU firmware or prom contents.  This must
+   be enabled before pvr2_hdw_cpufw_get() will function.  Note that doing
+   this may prevent the device from running (and leaving this mode may
+   imply a device reset). */
+void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *,
+				int prom_flag,
+				int enable_flag);
 
 /* Return true if we're in a mode for retrieval CPU firmware */
 int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 6786d3c..898c9d2 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -389,10 +389,6 @@
 		ret = -EINVAL;
 		goto done;
 	}
-	if ((msgs[0].flags & I2C_M_NOSTART)) {
-		trace_i2c("i2c refusing I2C_M_NOSTART");
-		goto done;
-	}
 	if (msgs[0].addr < PVR2_I2C_FUNC_CNT) {
 		funcp = hdw->i2c_func[msgs[0].addr];
 	}
@@ -494,14 +490,12 @@
 			cnt = msgs[idx].len;
 			printk(KERN_INFO
 			       "pvrusb2 i2c xfer %u/%u:"
-			       " addr=0x%x len=%d %s%s",
+			       " addr=0x%x len=%d %s",
 			       idx+1,num,
 			       msgs[idx].addr,
 			       cnt,
 			       (msgs[idx].flags & I2C_M_RD ?
-				"read" : "write"),
-			       (msgs[idx].flags & I2C_M_NOSTART ?
-				" nostart" : ""));
+				"read" : "write"));
 			if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) {
 				if (cnt > 8) cnt = 8;
 				printk(" [");
@@ -534,7 +528,7 @@
 
 static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
 {
-	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA;
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
 }
 
 static int pvr2_i2c_core_singleton(struct i2c_client *cp,
@@ -576,15 +570,13 @@
 
 int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg)
 {
-	struct list_head *item,*nc;
-	struct pvr2_i2c_client *cp;
+	struct pvr2_i2c_client *cp, *ncp;
 	int stat = -EINVAL;
 
 	if (!hdw) return stat;
 
 	mutex_lock(&hdw->i2c_list_lock);
-	list_for_each_safe(item,nc,&hdw->i2c_clients) {
-		cp = list_entry(item,struct pvr2_i2c_client,list);
+	list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
 		if (!cp->recv_enable) continue;
 		mutex_unlock(&hdw->i2c_list_lock);
 		stat = pvr2_i2c_client_cmd(cp,cmd,arg);
@@ -608,13 +600,11 @@
 
 void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw)
 {
-	struct list_head *item;
 	struct pvr2_i2c_client *cp;
 	mutex_lock(&hdw->i2c_list_lock); do {
 		struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
 		memset(vtp,0,sizeof(*vtp));
-		list_for_each(item,&hdw->i2c_clients) {
-			cp = list_entry(item,struct pvr2_i2c_client,list);
+		list_for_each_entry(cp, &hdw->i2c_clients, list) {
 			if (!cp->detected_flag) continue;
 			if (!cp->status_poll) continue;
 			cp->status_poll(cp);
@@ -636,8 +626,7 @@
 {
 	unsigned long msk;
 	unsigned int idx;
-	struct list_head *item,*nc;
-	struct pvr2_i2c_client *cp;
+	struct pvr2_i2c_client *cp, *ncp;
 
 	if (!hdw->i2c_linked) return;
 	if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) {
@@ -655,9 +644,7 @@
 			buf = kmalloc(BUFSIZE,GFP_KERNEL);
 			pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT");
 			hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT;
-			list_for_each(item,&hdw->i2c_clients) {
-				cp = list_entry(item,struct pvr2_i2c_client,
-						list);
+			list_for_each_entry(cp, &hdw->i2c_clients, list) {
 				if (!cp->detected_flag) {
 					cp->ctl_mask = 0;
 					pvr2_i2c_probe(hdw,cp);
@@ -693,9 +680,7 @@
 				   "i2c: PEND_STALE (0x%lx)",
 				   hdw->i2c_stale_mask);
 			hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE;
-			list_for_each(item,&hdw->i2c_clients) {
-				cp = list_entry(item,struct pvr2_i2c_client,
-						list);
+			list_for_each_entry(cp, &hdw->i2c_clients, list) {
 				m2 = hdw->i2c_stale_mask;
 				m2 &= cp->ctl_mask;
 				m2 &= ~cp->pend_mask;
@@ -716,9 +701,8 @@
 			   and update each one. */
 			pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT");
 			hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT;
-			list_for_each_safe(item,nc,&hdw->i2c_clients) {
-				cp = list_entry(item,struct pvr2_i2c_client,
-						list);
+			list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients,
+						 list) {
 				if (!cp->handler) continue;
 				if (!cp->handler->func_table->update) continue;
 				pvr2_trace(PVR2_TRACE_I2C_CORE,
@@ -750,10 +734,8 @@
 			for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
 				if (!(pm & msk)) continue;
 				pm &= ~msk;
-				list_for_each(item,&hdw->i2c_clients) {
-					cp = list_entry(item,
-							struct pvr2_i2c_client,
-							list);
+				list_for_each_entry(cp, &hdw->i2c_clients,
+						    list) {
 					if (cp->pend_mask & msk) {
 						cp->pend_mask &= ~msk;
 						cp->recv_enable = !0;
@@ -777,7 +759,6 @@
 	unsigned long msk,sm,pm;
 	unsigned int idx;
 	const struct pvr2_i2c_op *opf;
-	struct list_head *item;
 	struct pvr2_i2c_client *cp;
 	unsigned int pt = 0;
 
@@ -796,11 +777,9 @@
 	}
 	if (sm) pt |= PVR2_I2C_PEND_STALE;
 
-	list_for_each(item,&hdw->i2c_clients) {
-		cp = list_entry(item,struct pvr2_i2c_client,list);
-		if (!handler_check(cp)) continue;
-		pt |= PVR2_I2C_PEND_CLIENT;
-	}
+	list_for_each_entry(cp, &hdw->i2c_clients, list)
+		if (handler_check(cp))
+			pt |= PVR2_I2C_PEND_CLIENT;
 
 	if (pt) {
 		mutex_lock(&hdw->i2c_list_lock); do {
@@ -888,12 +867,10 @@
 			     char *buf,unsigned int maxlen)
 {
 	unsigned int ccnt,bcnt;
-	struct list_head *item;
 	struct pvr2_i2c_client *cp;
 	ccnt = 0;
 	mutex_lock(&hdw->i2c_list_lock); do {
-		list_for_each(item,&hdw->i2c_clients) {
-			cp = list_entry(item,struct pvr2_i2c_client,list);
+		list_for_each_entry(cp, &hdw->i2c_clients, list) {
 			bcnt = pvr2_i2c_client_describe(
 				cp,
 				(PVR2_I2C_DETAIL_HANDLER|
@@ -931,13 +908,11 @@
 static int pvr2_i2c_detach_inform(struct i2c_client *client)
 {
 	struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
-	struct pvr2_i2c_client *cp;
-	struct list_head *item,*nc;
+	struct pvr2_i2c_client *cp, *ncp;
 	unsigned long amask = 0;
 	int foundfl = 0;
 	mutex_lock(&hdw->i2c_list_lock); do {
-		list_for_each_safe(item,nc,&hdw->i2c_clients) {
-			cp = list_entry(item,struct pvr2_i2c_client,list);
+		list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
 			if (cp->client == client) {
 				trace_i2c("pvr2_i2c_detach"
 					  " [client=%s @ 0x%x ctxt=%p]",
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
index 9ea41c6..ca9e278 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -24,7 +24,6 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/usb.h>
 #include <linux/videodev2.h>
 
@@ -42,6 +41,7 @@
 
 #define DEFAULT_DEBUG_MASK (PVR2_TRACE_ERROR_LEGS| \
 			    PVR2_TRACE_INFO| \
+			    PVR2_TRACE_STD| \
 			    PVR2_TRACE_TOLERANCE| \
 			    PVR2_TRACE_TRAP| \
 			    0)
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
index 81de26b..63e55bb 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-std.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-std.c
@@ -298,7 +298,7 @@
 	std->id = id;
 	bcnt = pvr2_std_id_to_str(std->name,sizeof(std->name)-1,id);
 	std->name[bcnt] = 0;
-	pvr2_trace(PVR2_TRACE_INIT,"Set up standard idx=%u name=%s",
+	pvr2_trace(PVR2_TRACE_STD,"Set up standard idx=%u name=%s",
 		   std->index,std->name);
 	return !0;
 }
@@ -320,11 +320,11 @@
 	v4l2_std_id idmsk,cmsk,fmsk;
 	struct v4l2_standard *stddefs;
 
-	if (pvrusb2_debug & PVR2_TRACE_INIT) {
+	if (pvrusb2_debug & PVR2_TRACE_STD) {
 		char buf[50];
 		bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id);
 		pvr2_trace(
-			PVR2_TRACE_INIT,"Mapping standards mask=0x%x (%.*s)",
+			PVR2_TRACE_STD,"Mapping standards mask=0x%x (%.*s)",
 			(int)id,bcnt,buf);
 	}
 
@@ -355,7 +355,7 @@
 			bcnt,buf);
 	}
 
-	pvr2_trace(PVR2_TRACE_INIT,"Setting up %u unique standard(s)",
+	pvr2_trace(PVR2_TRACE_STD,"Setting up %u unique standard(s)",
 		   std_cnt);
 	if (!std_cnt) return NULL; // paranoia
 
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index 7ab79ba..2ee3c30 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -33,16 +33,16 @@
 
 struct pvr2_sysfs {
 	struct pvr2_channel channel;
-	struct class_device *class_dev;
+	struct device *class_dev;
 #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
 	struct pvr2_sysfs_debugifc *debugifc;
 #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
 	struct pvr2_sysfs_ctl_item *item_first;
 	struct pvr2_sysfs_ctl_item *item_last;
-	struct class_device_attribute attr_v4l_minor_number;
-	struct class_device_attribute attr_v4l_radio_minor_number;
-	struct class_device_attribute attr_unit_number;
-	struct class_device_attribute attr_bus_info;
+	struct device_attribute attr_v4l_minor_number;
+	struct device_attribute attr_v4l_radio_minor_number;
+	struct device_attribute attr_unit_number;
+	struct device_attribute attr_bus_info;
 	int v4l_minor_number_created_ok;
 	int v4l_radio_minor_number_created_ok;
 	int unit_number_created_ok;
@@ -51,22 +51,22 @@
 
 #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
 struct pvr2_sysfs_debugifc {
-	struct class_device_attribute attr_debugcmd;
-	struct class_device_attribute attr_debuginfo;
+	struct device_attribute attr_debugcmd;
+	struct device_attribute attr_debuginfo;
 	int debugcmd_created_ok;
 	int debuginfo_created_ok;
 };
 #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
 
 struct pvr2_sysfs_ctl_item {
-	struct class_device_attribute attr_name;
-	struct class_device_attribute attr_type;
-	struct class_device_attribute attr_min;
-	struct class_device_attribute attr_max;
-	struct class_device_attribute attr_enum;
-	struct class_device_attribute attr_bits;
-	struct class_device_attribute attr_val;
-	struct class_device_attribute attr_custom;
+	struct device_attribute attr_name;
+	struct device_attribute attr_type;
+	struct device_attribute attr_min;
+	struct device_attribute attr_max;
+	struct device_attribute attr_enum;
+	struct device_attribute attr_bits;
+	struct device_attribute attr_val;
+	struct device_attribute attr_custom;
 	struct pvr2_ctrl *cptr;
 	struct pvr2_sysfs *chptr;
 	struct pvr2_sysfs_ctl_item *item_next;
@@ -80,13 +80,13 @@
 	struct class class;
 };
 
-static ssize_t show_name(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_name(int id,struct device *class_dev,char *buf)
 {
 	struct pvr2_ctrl *cptr;
 	struct pvr2_sysfs *sfp;
 	const char *name;
 
-	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
 	if (!sfp) return -EINVAL;
 	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
 	if (!cptr) return -EINVAL;
@@ -99,14 +99,14 @@
 	return scnprintf(buf,PAGE_SIZE,"%s\n",name);
 }
 
-static ssize_t show_type(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_type(int id,struct device *class_dev,char *buf)
 {
 	struct pvr2_ctrl *cptr;
 	struct pvr2_sysfs *sfp;
 	const char *name;
 	enum pvr2_ctl_type tp;
 
-	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
 	if (!sfp) return -EINVAL;
 	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
 	if (!cptr) return -EINVAL;
@@ -126,13 +126,13 @@
 	return scnprintf(buf,PAGE_SIZE,"%s\n",name);
 }
 
-static ssize_t show_min(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_min(int id,struct device *class_dev,char *buf)
 {
 	struct pvr2_ctrl *cptr;
 	struct pvr2_sysfs *sfp;
 	long val;
 
-	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
 	if (!sfp) return -EINVAL;
 	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
 	if (!cptr) return -EINVAL;
@@ -143,13 +143,13 @@
 	return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
 }
 
-static ssize_t show_max(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_max(int id,struct device *class_dev,char *buf)
 {
 	struct pvr2_ctrl *cptr;
 	struct pvr2_sysfs *sfp;
 	long val;
 
-	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
 	if (!sfp) return -EINVAL;
 	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
 	if (!cptr) return -EINVAL;
@@ -160,14 +160,14 @@
 	return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
 }
 
-static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_val_norm(int id,struct device *class_dev,char *buf)
 {
 	struct pvr2_ctrl *cptr;
 	struct pvr2_sysfs *sfp;
 	int val,ret;
 	unsigned int cnt = 0;
 
-	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
 	if (!sfp) return -EINVAL;
 	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
 	if (!cptr) return -EINVAL;
@@ -184,14 +184,14 @@
 	return cnt+1;
 }
 
-static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_val_custom(int id,struct device *class_dev,char *buf)
 {
 	struct pvr2_ctrl *cptr;
 	struct pvr2_sysfs *sfp;
 	int val,ret;
 	unsigned int cnt = 0;
 
-	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
 	if (!sfp) return -EINVAL;
 	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
 	if (!cptr) return -EINVAL;
@@ -208,14 +208,14 @@
 	return cnt+1;
 }
 
-static ssize_t show_enum(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_enum(int id,struct device *class_dev,char *buf)
 {
 	struct pvr2_ctrl *cptr;
 	struct pvr2_sysfs *sfp;
 	long val;
 	unsigned int bcnt,ccnt,ecnt;
 
-	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
 	if (!sfp) return -EINVAL;
 	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
 	if (!cptr) return -EINVAL;
@@ -233,14 +233,14 @@
 	return bcnt;
 }
 
-static ssize_t show_bits(int id,struct class_device *class_dev,char *buf)
+static ssize_t show_bits(int id,struct device *class_dev,char *buf)
 {
 	struct pvr2_ctrl *cptr;
 	struct pvr2_sysfs *sfp;
 	int valid_bits,msk;
 	unsigned int bcnt,ccnt;
 
-	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
 	if (!sfp) return -EINVAL;
 	cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
 	if (!cptr) return -EINVAL;
@@ -278,23 +278,23 @@
 	return ret;
 }
 
-static ssize_t store_val_norm(int id,struct class_device *class_dev,
+static ssize_t store_val_norm(int id,struct device *class_dev,
 			     const char *buf,size_t count)
 {
 	struct pvr2_sysfs *sfp;
 	int ret;
-	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
 	ret = store_val_any(id,0,sfp,buf,count);
 	if (!ret) ret = count;
 	return ret;
 }
 
-static ssize_t store_val_custom(int id,struct class_device *class_dev,
+static ssize_t store_val_custom(int id,struct device *class_dev,
 				const char *buf,size_t count)
 {
 	struct pvr2_sysfs *sfp;
 	int ret;
-	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
 	ret = store_val_any(id,1,sfp,buf,count);
 	if (!ret) ret = count;
 	return ret;
@@ -304,7 +304,7 @@
   Mike Isely <isely@pobox.com> 30-April-2005
 
   This next batch of horrible preprocessor hackery is needed because the
-  kernel's class_device_attribute mechanism fails to pass the actual
+  kernel's device_attribute mechanism fails to pass the actual
   attribute through to the show / store functions, which means we have no
   way to package up any attribute-specific parameters, like for example the
   control id.  So we work around this brain-damage by encoding the control
@@ -314,11 +314,13 @@
 */
 
 #define CREATE_SHOW_INSTANCE(sf_name,ctl_id) \
-static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,char *buf) \
+static ssize_t sf_name##_##ctl_id(struct device *class_dev, \
+struct device_attribute *attr, char *buf) \
 { return sf_name(ctl_id,class_dev,buf); }
 
 #define CREATE_STORE_INSTANCE(sf_name,ctl_id) \
-static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,const char *buf,size_t count) \
+static ssize_t sf_name##_##ctl_id(struct device *class_dev, \
+struct device_attribute *attr, const char *buf, size_t count) \
 { return sf_name(ctl_id,class_dev,buf,count); }
 
 #define CREATE_BATCH(ctl_id) \
@@ -395,17 +397,27 @@
 CREATE_BATCH(59)
 
 struct pvr2_sysfs_func_set {
-	ssize_t (*show_name)(struct class_device *,char *);
-	ssize_t (*show_type)(struct class_device *,char *);
-	ssize_t (*show_min)(struct class_device *,char *);
-	ssize_t (*show_max)(struct class_device *,char *);
-	ssize_t (*show_enum)(struct class_device *,char *);
-	ssize_t (*show_bits)(struct class_device *,char *);
-	ssize_t (*show_val_norm)(struct class_device *,char *);
-	ssize_t (*store_val_norm)(struct class_device *,
+	ssize_t (*show_name)(struct device *,
+			     struct device_attribute *attr, char *);
+	ssize_t (*show_type)(struct device *,
+			     struct device_attribute *attr, char *);
+	ssize_t (*show_min)(struct device *,
+			    struct device_attribute *attr, char *);
+	ssize_t (*show_max)(struct device *,
+			    struct device_attribute *attr, char *);
+	ssize_t (*show_enum)(struct device *,
+			     struct device_attribute *attr, char *);
+	ssize_t (*show_bits)(struct device *,
+			     struct device_attribute *attr, char *);
+	ssize_t (*show_val_norm)(struct device *,
+				 struct device_attribute *attr, char *);
+	ssize_t (*store_val_norm)(struct device *,
+				  struct device_attribute *attr,
 				  const char *,size_t);
-	ssize_t (*show_val_custom)(struct class_device *,char *);
-	ssize_t (*store_val_custom)(struct class_device *,
+	ssize_t (*show_val_custom)(struct device *,
+				   struct device_attribute *attr, char *);
+	ssize_t (*store_val_custom)(struct device *,
+				    struct device_attribute *attr,
 				    const char *,size_t);
 };
 
@@ -597,9 +609,12 @@
 }
 
 #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
-static ssize_t debuginfo_show(struct class_device *,char *);
-static ssize_t debugcmd_show(struct class_device *,char *);
-static ssize_t debugcmd_store(struct class_device *,const char *,size_t count);
+static ssize_t debuginfo_show(struct device *, struct device_attribute *,
+			      char *);
+static ssize_t debugcmd_show(struct device *, struct device_attribute *,
+			     char *);
+static ssize_t debugcmd_store(struct device *, struct device_attribute *,
+			      const char *, size_t count);
 
 static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
 {
@@ -616,16 +631,16 @@
 	dip->attr_debuginfo.attr.mode = S_IRUGO;
 	dip->attr_debuginfo.show = debuginfo_show;
 	sfp->debugifc = dip;
-	ret = class_device_create_file(sfp->class_dev,&dip->attr_debugcmd);
+	ret = device_create_file(sfp->class_dev,&dip->attr_debugcmd);
 	if (ret < 0) {
-		printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+		printk(KERN_WARNING "%s: device_create_file error: %d\n",
 		       __FUNCTION__, ret);
 	} else {
 		dip->debugcmd_created_ok = !0;
 	}
-	ret = class_device_create_file(sfp->class_dev,&dip->attr_debuginfo);
+	ret = device_create_file(sfp->class_dev,&dip->attr_debuginfo);
 	if (ret < 0) {
-		printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+		printk(KERN_WARNING "%s: device_create_file error: %d\n",
 		       __FUNCTION__, ret);
 	} else {
 		dip->debuginfo_created_ok = !0;
@@ -637,11 +652,11 @@
 {
 	if (!sfp->debugifc) return;
 	if (sfp->debugifc->debuginfo_created_ok) {
-		class_device_remove_file(sfp->class_dev,
+		device_remove_file(sfp->class_dev,
 					 &sfp->debugifc->attr_debuginfo);
 	}
 	if (sfp->debugifc->debugcmd_created_ok) {
-		class_device_remove_file(sfp->class_dev,
+		device_remove_file(sfp->class_dev,
 					 &sfp->debugifc->attr_debugcmd);
 	}
 	kfree(sfp->debugifc);
@@ -683,7 +698,7 @@
 }
 
 
-static void pvr2_sysfs_release(struct class_device *class_dev)
+static void pvr2_sysfs_release(struct device *class_dev)
 {
 	pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev);
 	kfree(class_dev);
@@ -698,32 +713,33 @@
 #endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
 	pvr2_sysfs_tear_down_controls(sfp);
 	if (sfp->bus_info_created_ok) {
-		class_device_remove_file(sfp->class_dev,
+		device_remove_file(sfp->class_dev,
 					 &sfp->attr_bus_info);
 	}
 	if (sfp->v4l_minor_number_created_ok) {
-		class_device_remove_file(sfp->class_dev,
+		device_remove_file(sfp->class_dev,
 					 &sfp->attr_v4l_minor_number);
 	}
 	if (sfp->v4l_radio_minor_number_created_ok) {
-		class_device_remove_file(sfp->class_dev,
+		device_remove_file(sfp->class_dev,
 					 &sfp->attr_v4l_radio_minor_number);
 	}
 	if (sfp->unit_number_created_ok) {
-		class_device_remove_file(sfp->class_dev,
+		device_remove_file(sfp->class_dev,
 					 &sfp->attr_unit_number);
 	}
 	pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev);
-	sfp->class_dev->class_data = NULL;
-	class_device_unregister(sfp->class_dev);
+	sfp->class_dev->driver_data = NULL;
+	device_unregister(sfp->class_dev);
 	sfp->class_dev = NULL;
 }
 
 
-static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf)
+static ssize_t v4l_minor_number_show(struct device *class_dev,
+				     struct device_attribute *attr, char *buf)
 {
 	struct pvr2_sysfs *sfp;
-	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
 	if (!sfp) return -EINVAL;
 	return scnprintf(buf,PAGE_SIZE,"%d\n",
 			 pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
@@ -731,21 +747,23 @@
 }
 
 
-static ssize_t bus_info_show(struct class_device *class_dev,char *buf)
+static ssize_t bus_info_show(struct device *class_dev,
+			     struct device_attribute *attr, char *buf)
 {
 	struct pvr2_sysfs *sfp;
-	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
 	if (!sfp) return -EINVAL;
 	return scnprintf(buf,PAGE_SIZE,"%s\n",
 			 pvr2_hdw_get_bus_info(sfp->channel.hdw));
 }
 
 
-static ssize_t v4l_radio_minor_number_show(struct class_device *class_dev,
+static ssize_t v4l_radio_minor_number_show(struct device *class_dev,
+					   struct device_attribute *attr,
 					   char *buf)
 {
 	struct pvr2_sysfs *sfp;
-	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
 	if (!sfp) return -EINVAL;
 	return scnprintf(buf,PAGE_SIZE,"%d\n",
 			 pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw,
@@ -753,10 +771,11 @@
 }
 
 
-static ssize_t unit_number_show(struct class_device *class_dev,char *buf)
+static ssize_t unit_number_show(struct device *class_dev,
+				struct device_attribute *attr, char *buf)
 {
 	struct pvr2_sysfs *sfp;
-	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
 	if (!sfp) return -EINVAL;
 	return scnprintf(buf,PAGE_SIZE,"%d\n",
 			 pvr2_hdw_get_unit_number(sfp->channel.hdw));
@@ -767,7 +786,7 @@
 			     struct pvr2_sysfs_class *class_ptr)
 {
 	struct usb_device *usb_dev;
-	struct class_device *class_dev;
+	struct device *class_dev;
 	int ret;
 
 	usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw);
@@ -779,23 +798,23 @@
 
 	class_dev->class = &class_ptr->class;
 	if (pvr2_hdw_get_sn(sfp->channel.hdw)) {
-		snprintf(class_dev->class_id,BUS_ID_SIZE,"sn-%lu",
+		snprintf(class_dev->bus_id, BUS_ID_SIZE, "sn-%lu",
 			 pvr2_hdw_get_sn(sfp->channel.hdw));
 	} else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) {
-		snprintf(class_dev->class_id,BUS_ID_SIZE,"unit-%c",
+		snprintf(class_dev->bus_id, BUS_ID_SIZE, "unit-%c",
 			 pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a');
 	} else {
 		kfree(class_dev);
 		return;
 	}
 
-	class_dev->dev = &usb_dev->dev;
+	class_dev->parent = &usb_dev->dev;
 
 	sfp->class_dev = class_dev;
-	class_dev->class_data = sfp;
-	ret = class_device_register(class_dev);
+	class_dev->driver_data = sfp;
+	ret = device_register(class_dev);
 	if (ret) {
-		printk(KERN_ERR "%s: class_device_register failed\n",
+		printk(KERN_ERR "%s: device_register failed\n",
 		       __FUNCTION__);
 		kfree(class_dev);
 		return;
@@ -805,10 +824,10 @@
 	sfp->attr_v4l_minor_number.attr.mode = S_IRUGO;
 	sfp->attr_v4l_minor_number.show = v4l_minor_number_show;
 	sfp->attr_v4l_minor_number.store = NULL;
-	ret = class_device_create_file(sfp->class_dev,
+	ret = device_create_file(sfp->class_dev,
 				       &sfp->attr_v4l_minor_number);
 	if (ret < 0) {
-		printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+		printk(KERN_WARNING "%s: device_create_file error: %d\n",
 		       __FUNCTION__, ret);
 	} else {
 		sfp->v4l_minor_number_created_ok = !0;
@@ -818,10 +837,10 @@
 	sfp->attr_v4l_radio_minor_number.attr.mode = S_IRUGO;
 	sfp->attr_v4l_radio_minor_number.show = v4l_radio_minor_number_show;
 	sfp->attr_v4l_radio_minor_number.store = NULL;
-	ret = class_device_create_file(sfp->class_dev,
+	ret = device_create_file(sfp->class_dev,
 				       &sfp->attr_v4l_radio_minor_number);
 	if (ret < 0) {
-		printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+		printk(KERN_WARNING "%s: device_create_file error: %d\n",
 		       __FUNCTION__, ret);
 	} else {
 		sfp->v4l_radio_minor_number_created_ok = !0;
@@ -831,9 +850,9 @@
 	sfp->attr_unit_number.attr.mode = S_IRUGO;
 	sfp->attr_unit_number.show = unit_number_show;
 	sfp->attr_unit_number.store = NULL;
-	ret = class_device_create_file(sfp->class_dev,&sfp->attr_unit_number);
+	ret = device_create_file(sfp->class_dev,&sfp->attr_unit_number);
 	if (ret < 0) {
-		printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+		printk(KERN_WARNING "%s: device_create_file error: %d\n",
 		       __FUNCTION__, ret);
 	} else {
 		sfp->unit_number_created_ok = !0;
@@ -843,10 +862,10 @@
 	sfp->attr_bus_info.attr.mode = S_IRUGO;
 	sfp->attr_bus_info.show = bus_info_show;
 	sfp->attr_bus_info.store = NULL;
-	ret = class_device_create_file(sfp->class_dev,
+	ret = device_create_file(sfp->class_dev,
 				       &sfp->attr_bus_info);
 	if (ret < 0) {
-		printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+		printk(KERN_WARNING "%s: device_create_file error: %d\n",
 		       __FUNCTION__, ret);
 	} else {
 		sfp->bus_info_created_ok = !0;
@@ -886,8 +905,8 @@
 }
 
 
-static int pvr2_sysfs_hotplug(struct class_device *cd,char **envp,
-			      int numenvp,char *buf,int size)
+static int pvr2_sysfs_hotplug(struct device *d,
+			      struct kobj_uevent_env *env)
 {
 	/* Even though we don't do anything here, we still need this function
 	   because sysfs will still try to call it. */
@@ -902,8 +921,8 @@
 	pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp);
 	clp->class.name = "pvrusb2";
 	clp->class.class_release = pvr2_sysfs_class_release;
-	clp->class.release = pvr2_sysfs_release;
-	clp->class.uevent = pvr2_sysfs_hotplug;
+	clp->class.dev_release = pvr2_sysfs_release;
+	clp->class.dev_uevent = pvr2_sysfs_hotplug;
 	if (class_register(&clp->class)) {
 		pvr2_sysfs_trace(
 			"Registration failed for pvr2_sysfs_class id=%p",clp);
@@ -921,32 +940,35 @@
 
 
 #ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
-static ssize_t debuginfo_show(struct class_device *class_dev,char *buf)
+static ssize_t debuginfo_show(struct device *class_dev,
+			      struct device_attribute *attr, char *buf)
 {
 	struct pvr2_sysfs *sfp;
-	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
 	if (!sfp) return -EINVAL;
 	pvr2_hdw_trigger_module_log(sfp->channel.hdw);
 	return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE);
 }
 
 
-static ssize_t debugcmd_show(struct class_device *class_dev,char *buf)
+static ssize_t debugcmd_show(struct device *class_dev,
+			     struct device_attribute *attr, char *buf)
 {
 	struct pvr2_sysfs *sfp;
-	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
 	if (!sfp) return -EINVAL;
 	return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE);
 }
 
 
-static ssize_t debugcmd_store(struct class_device *class_dev,
-			      const char *buf,size_t count)
+static ssize_t debugcmd_store(struct device *class_dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
 {
 	struct pvr2_sysfs *sfp;
 	int ret;
 
-	sfp = (struct pvr2_sysfs *)class_dev->class_data;
+	sfp = (struct pvr2_sysfs *)class_dev->driver_data;
 	if (!sfp) return -EINVAL;
 
 	ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count);
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index 338ced7..ea53316 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -1648,7 +1648,7 @@
 		ARG_OUT(cmd)
 		break;
 	}
-       /*
+	/*
 	case VIDIOCPWCGVIDTABLE:
 	{
 		ARG_DEF(struct pwc_table_init_buffer, table);
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 085332a..0b67d4e 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -64,7 +64,6 @@
 #include <linux/vmalloc.h>
 #include <linux/version.h>
 #include <asm/io.h>
-#include <linux/moduleparam.h>
 
 #include "pwc.h"
 #include "pwc-kiara.h"
@@ -127,9 +126,9 @@
 static int default_size = PSZ_QCIF;
 static int default_fps = 10;
 static int default_fbufs = 3;   /* Default number of frame buffers */
-       int pwc_mbufs = 2;	/* Default number of mmap() buffers */
+	int pwc_mbufs = 2;	/* Default number of mmap() buffers */
 #ifdef CONFIG_USB_PWC_DEBUG
-       int pwc_trace = PWC_DEBUG_LEVEL;
+	int pwc_trace = PWC_DEBUG_LEVEL;
 #endif
 static int power_save = 0;
 static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
@@ -908,31 +907,49 @@
 	return 0;
 }
 
-void pwc_isoc_cleanup(struct pwc_device *pdev)
+static void pwc_iso_stop(struct pwc_device *pdev)
 {
 	int i;
 
-	PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
-	if (pdev == NULL)
-		return;
-	if (pdev->iso_init == 0)
-		return;
-
 	/* Unlinking ISOC buffers one by one */
 	for (i = 0; i < MAX_ISO_BUFS; i++) {
 		struct urb *urb;
 
 		urb = pdev->sbuf[i].urb;
 		if (urb != 0) {
-			if (pdev->iso_init) {
-				PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
-				usb_kill_urb(urb);
-			}
+			PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
+			usb_kill_urb(urb);
+		}
+	}
+}
+
+static void pwc_iso_free(struct pwc_device *pdev)
+{
+	int i;
+
+	/* Freeing ISOC buffers one by one */
+	for (i = 0; i < MAX_ISO_BUFS; i++) {
+		struct urb *urb;
+
+		urb = pdev->sbuf[i].urb;
+		if (urb != 0) {
 			PWC_DEBUG_MEMORY("Freeing URB\n");
 			usb_free_urb(urb);
 			pdev->sbuf[i].urb = NULL;
 		}
 	}
+}
+
+void pwc_isoc_cleanup(struct pwc_device *pdev)
+{
+	PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
+	if (pdev == NULL)
+		return;
+	if (pdev->iso_init == 0)
+		return;
+
+	pwc_iso_stop(pdev);
+	pwc_iso_free(pdev);
 
 	/* Stop camera, but only if we are sure the camera is still there (unplug
 	   is signalled by EPIPE)
@@ -979,20 +996,22 @@
 /*********
  * sysfs
  *********/
-static struct pwc_device *cd_to_pwc(struct class_device *cd)
+static struct pwc_device *cd_to_pwc(struct device *cd)
 {
 	struct video_device *vdev = to_video_device(cd);
 	return video_get_drvdata(vdev);
 }
 
-static ssize_t show_pan_tilt(struct class_device *class_dev, char *buf)
+static ssize_t show_pan_tilt(struct device *class_dev,
+			     struct device_attribute *attr, char *buf)
 {
 	struct pwc_device *pdev = cd_to_pwc(class_dev);
 	return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);
 }
 
-static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf,
-			 size_t count)
+static ssize_t store_pan_tilt(struct device *class_dev,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
 {
 	struct pwc_device *pdev = cd_to_pwc(class_dev);
 	int pan, tilt;
@@ -1008,10 +1027,11 @@
 		return ret;
 	return strlen(buf);
 }
-static CLASS_DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
-			 store_pan_tilt);
+static DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
+		   store_pan_tilt);
 
-static ssize_t show_snapshot_button_status(struct class_device *class_dev, char *buf)
+static ssize_t show_snapshot_button_status(struct device *class_dev,
+					   struct device_attribute *attr, char *buf)
 {
 	struct pwc_device *pdev = cd_to_pwc(class_dev);
 	int status = pdev->snapshot_button_status;
@@ -1019,26 +1039,26 @@
 	return sprintf(buf, "%d\n", status);
 }
 
-static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
-			 NULL);
+static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
+		   NULL);
 
 static int pwc_create_sysfs_files(struct video_device *vdev)
 {
 	struct pwc_device *pdev = video_get_drvdata(vdev);
 	int rc;
 
-	rc = video_device_create_file(vdev, &class_device_attr_button);
+	rc = video_device_create_file(vdev, &dev_attr_button);
 	if (rc)
 		goto err;
 	if (pdev->features & FEATURE_MOTOR_PANTILT) {
-		rc = video_device_create_file(vdev,&class_device_attr_pan_tilt);
+		rc = video_device_create_file(vdev, &dev_attr_pan_tilt);
 		if (rc) goto err_button;
 	}
 
 	return 0;
 
 err_button:
-	video_device_remove_file(vdev, &class_device_attr_button);
+	video_device_remove_file(vdev, &dev_attr_button);
 err:
 	return rc;
 }
@@ -1047,8 +1067,8 @@
 {
 	struct pwc_device *pdev = video_get_drvdata(vdev);
 	if (pdev->features & FEATURE_MOTOR_PANTILT)
-		video_device_remove_file(vdev, &class_device_attr_pan_tilt);
-	video_device_remove_file(vdev, &class_device_attr_button);
+		video_device_remove_file(vdev, &dev_attr_pan_tilt);
+	video_device_remove_file(vdev, &dev_attr_button);
 }
 
 #ifdef CONFIG_USB_PWC_DEBUG
@@ -1099,7 +1119,7 @@
 		return -EBUSY;
 	}
 
-	down(&pdev->modlock);
+	mutex_lock(&pdev->modlock);
 	if (!pdev->usb_init) {
 		PWC_DEBUG_OPEN("Doing first time initialization.\n");
 		pdev->usb_init = 1;
@@ -1131,7 +1151,7 @@
 	if (i < 0) {
 		PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
 		pwc_free_buffers(pdev);
-		up(&pdev->modlock);
+		mutex_unlock(&pdev->modlock);
 		return i;
 	}
 
@@ -1172,7 +1192,7 @@
 	if (i) {
 		PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
 		pwc_free_buffers(pdev);
-		up(&pdev->modlock);
+		mutex_unlock(&pdev->modlock);
 		return i;
 	}
 
@@ -1181,7 +1201,7 @@
 		PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
 		pwc_isoc_cleanup(pdev);
 		pwc_free_buffers(pdev);
-		up(&pdev->modlock);
+		mutex_unlock(&pdev->modlock);
 		return i;
 	}
 
@@ -1191,20 +1211,28 @@
 
 	pdev->vopen++;
 	file->private_data = vdev;
-	up(&pdev->modlock);
+	mutex_unlock(&pdev->modlock);
 	PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
 	return 0;
 }
 
+
+static void pwc_cleanup(struct pwc_device *pdev)
+{
+	pwc_remove_sysfs_files(pdev->vdev);
+	video_unregister_device(pdev->vdev);
+}
+
 /* Note that all cleanup is done in the reverse order as in _open */
 static int pwc_video_close(struct inode *inode, struct file *file)
 {
 	struct video_device *vdev = file->private_data;
 	struct pwc_device *pdev;
-	int i;
+	int i, hint;
 
 	PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
 
+	lock_kernel();
 	pdev = (struct pwc_device *)vdev->priv;
 	if (pdev->vopen == 0)
 		PWC_DEBUG_MODULE("video_close() called on closed device?\n");
@@ -1225,7 +1253,7 @@
 	pwc_free_buffers(pdev);
 
 	/* Turn off LEDS and power down camera, but only when not unplugged */
-	if (pdev->error_status != EPIPE) {
+	if (!pdev->unplugged) {
 		/* Turn LEDs off */
 		if (pwc_set_leds(pdev, 0, 0) < 0)
 			PWC_DEBUG_MODULE("Failed to set LED on/off time.\n");
@@ -1234,9 +1262,19 @@
 			if (i < 0)
 				PWC_ERROR("Failed to power down camera (%d)\n", i);
 		}
+		pdev->vopen--;
+		PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
+	} else {
+		pwc_cleanup(pdev);
+		/* Free memory (don't set pdev to 0 just yet) */
+		kfree(pdev);
+		/* search device_hint[] table if we occupy a slot, by any chance */
+		for (hint = 0; hint < MAX_DEV_HINTS; hint++)
+			if (device_hint[hint].pdev == pdev)
+				device_hint[hint].pdev = NULL;
 	}
-	pdev->vopen--;
-	PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
+	unlock_kernel();
+
 	return 0;
 }
 
@@ -1259,7 +1297,7 @@
 	struct pwc_device *pdev;
 	int noblock = file->f_flags & O_NONBLOCK;
 	DECLARE_WAITQUEUE(wait, current);
-	int bytes_to_read;
+	int bytes_to_read, rv = 0;
 	void *image_buffer_addr;
 
 	PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n",
@@ -1269,8 +1307,12 @@
 	pdev = vdev->priv;
 	if (pdev == NULL)
 		return -EFAULT;
-	if (pdev->error_status)
-		return -pdev->error_status; /* Something happened, report what. */
+
+	mutex_lock(&pdev->modlock);
+	if (pdev->error_status) {
+		rv = -pdev->error_status; /* Something happened, report what. */
+		goto err_out;
+	}
 
 	/* In case we're doing partial reads, we don't have to wait for a frame */
 	if (pdev->image_read_pos == 0) {
@@ -1281,17 +1323,20 @@
 			if (pdev->error_status) {
 				remove_wait_queue(&pdev->frameq, &wait);
 				set_current_state(TASK_RUNNING);
-				return -pdev->error_status ;
+				rv = -pdev->error_status ;
+				goto err_out;
 			}
 			if (noblock) {
 				remove_wait_queue(&pdev->frameq, &wait);
 				set_current_state(TASK_RUNNING);
-				return -EWOULDBLOCK;
+				rv = -EWOULDBLOCK;
+				goto err_out;
 			}
 			if (signal_pending(current)) {
 				remove_wait_queue(&pdev->frameq, &wait);
 				set_current_state(TASK_RUNNING);
-				return -ERESTARTSYS;
+				rv = -ERESTARTSYS;
+				goto err_out;
 			}
 			schedule();
 			set_current_state(TASK_INTERRUPTIBLE);
@@ -1300,8 +1345,10 @@
 		set_current_state(TASK_RUNNING);
 
 		/* Decompress and release frame */
-		if (pwc_handle_frame(pdev))
-			return -EFAULT;
+		if (pwc_handle_frame(pdev)) {
+			rv = -EFAULT;
+			goto err_out;
+		}
 	}
 
 	PWC_DEBUG_READ("Copying data to user space.\n");
@@ -1316,14 +1363,20 @@
 	image_buffer_addr = pdev->image_data;
 	image_buffer_addr += pdev->images[pdev->fill_image].offset;
 	image_buffer_addr += pdev->image_read_pos;
-	if (copy_to_user(buf, image_buffer_addr, count))
-		return -EFAULT;
+	if (copy_to_user(buf, image_buffer_addr, count)) {
+		rv = -EFAULT;
+		goto err_out;
+	}
 	pdev->image_read_pos += count;
 	if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
 		pdev->image_read_pos = 0;
 		pwc_next_image(pdev);
 	}
+	mutex_unlock(&pdev->modlock);
 	return count;
+err_out:
+	mutex_unlock(&pdev->modlock);
+	return rv;
 }
 
 static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
@@ -1349,7 +1402,20 @@
 static int pwc_video_ioctl(struct inode *inode, struct file *file,
 			   unsigned int cmd, unsigned long arg)
 {
-	return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
+	struct video_device *vdev = file->private_data;
+	struct pwc_device *pdev;
+	int r = -ENODEV;
+
+	if (!vdev)
+		goto out;
+	pdev = vdev->priv;
+
+	mutex_lock(&pdev->modlock);
+	if (!pdev->unplugged)
+		r = video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
+	mutex_unlock(&pdev->modlock);
+out:
+	return r;
 }
 
 static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
@@ -1685,7 +1751,7 @@
 		pdev->angle_range.tilt_max =  2500;
 	}
 
-	init_MUTEX(&pdev->modlock);
+	mutex_init(&pdev->modlock);
 	spin_lock_init(&pdev->ptrlock);
 
 	pdev->udev = udev;
@@ -1791,26 +1857,28 @@
 	/* Alert waiting processes */
 	wake_up_interruptible(&pdev->frameq);
 	/* Wait until device is closed */
-	while (pdev->vopen)
-		schedule();
-	/* Device is now closed, so we can safely unregister it */
-	PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
-	pwc_remove_sysfs_files(pdev->vdev);
-	video_unregister_device(pdev->vdev);
-
-	/* Free memory (don't set pdev to 0 just yet) */
-	kfree(pdev);
+	if(pdev->vopen) {
+		mutex_lock(&pdev->modlock);
+		pdev->unplugged = 1;
+		mutex_unlock(&pdev->modlock);
+		pwc_iso_stop(pdev);
+	} else {
+		/* Device is closed, so we can safely unregister it */
+		PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
+		pwc_cleanup(pdev);
+		/* Free memory (don't set pdev to 0 just yet) */
+		kfree(pdev);
 
 disconnect_out:
-	/* search device_hint[] table if we occupy a slot, by any chance */
-	for (hint = 0; hint < MAX_DEV_HINTS; hint++)
-		if (device_hint[hint].pdev == pdev)
-			device_hint[hint].pdev = NULL;
+		/* search device_hint[] table if we occupy a slot, by any chance */
+		for (hint = 0; hint < MAX_DEV_HINTS; hint++)
+			if (device_hint[hint].pdev == pdev)
+				device_hint[hint].pdev = NULL;
+	}
 
 	unlock_kernel();
 }
 
-
 /* *grunt* We have to do atoi ourselves :-( */
 static int pwc_atoi(const char *s)
 {
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index acbb931..8e8e5b27 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -31,7 +31,7 @@
 #include <linux/wait.h>
 #include <linux/smp_lock.h>
 #include <linux/version.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
 #include <asm/errno.h>
 #include <linux/videodev.h>
 #include <media/v4l2-common.h>
@@ -193,6 +193,7 @@
    char vsnapshot;		/* snapshot mode */
    char vsync;			/* used by isoc handler */
    char vmirror;		/* for ToUCaM series */
+	char unplugged;
 
    int cmd_len;
    unsigned char cmd_buf[13];
@@ -244,7 +245,7 @@
    int image_read_pos;			/* In case we read data in pieces, keep track of were we are in the imagebuffer */
    int image_used[MAX_IMAGES];		/* For MCAPTURE and SYNC */
 
-   struct semaphore modlock;		/* to prevent races in video_open(), etc */
+   struct mutex modlock;		/* to prevent races in video_open(), etc */
    spinlock_t ptrlock;			/* for manipulating the buffer pointers */
 
    /*** motorized pan/tilt feature */
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index f2a2f34..17f1e2e 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -86,9 +86,9 @@
 
 
 
-#define PAGE_WAIT (300*HZ/1000)			/* Time between requesting page and */
+#define PAGE_WAIT    msecs_to_jiffies(300)	/* Time between requesting page and */
 						/* checking status bits */
-#define PGBUF_EXPIRE (15*HZ)			/* Time to wait before retransmitting */
+#define PGBUF_EXPIRE msecs_to_jiffies(15000)	/* Time to wait before retransmitting */
 						/* page regardless of infobits */
 typedef struct {
 	u8 pgbuf[VTX_VIRTUALSIZE];		/* Page-buffer */
@@ -115,8 +115,8 @@
 #define CCTWR 34		/* I²C write/read-address of vtx-chip */
 #define CCTRD 35
 #define NOACK_REPEAT 10		/* Retry access this many times on failure */
-#define CLEAR_DELAY (HZ/20)	/* Time required to clear a page */
-#define READY_TIMEOUT (30*HZ/1000)	/* Time to wait for ready signal of I²C-bus interface */
+#define CLEAR_DELAY   msecs_to_jiffies(50)	/* Time required to clear a page */
+#define READY_TIMEOUT msecs_to_jiffies(30)	/* Time to wait for ready signal of I2C-bus interface */
 #define INIT_DELAY 500		/* Time in usec to wait at initialization of CEA interface */
 #define START_DELAY 10		/* Time in usec to wait before starting write-cycle (CEA) */
 
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
index 92eabf8..72e344a 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -406,6 +406,7 @@
 		kfree(s);
 		return -ENOMEM;
 	}
+	spin_lock_init(&s->lock);
 	s->client = client_template;
 	s->block_count = 0;
 	s->wr_index = 0;
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
index 676b997..061134a 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -208,7 +208,7 @@
 	saa7110_write_block(client, initseq, sizeof(initseq));
 	saa7110_selmux(client, decoder->input);
 	prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ/4);
+	schedule_timeout(msecs_to_jiffies(250));
 	finish_wait(&decoder->wq, &wait);
 	status = saa7110_read(client);
 	if (status & 0x40) {
@@ -249,7 +249,7 @@
 	//saa7110_write(client,0x2E,0x9A);
 
 	prepare_to_wait(&decoder->wq, &wait, TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ/4);
+	schedule_timeout(msecs_to_jiffies(250));
 	finish_wait(&decoder->wq, &wait);
 
 	status = saa7110_read(client);
diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c
index c1a392e..7ae2d64 100644
--- a/drivers/media/video/saa7111.c
+++ b/drivers/media/video/saa7111.c
@@ -37,23 +37,23 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
 
 MODULE_DESCRIPTION("Philips SAA7111 video decoder driver");
 MODULE_AUTHOR("Dave Perks");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(s) (s)->name
 
-#include <linux/video_decoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0644);
diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c
index 87c3144..677df51 100644
--- a/drivers/media/video/saa7114.c
+++ b/drivers/media/video/saa7114.c
@@ -35,28 +35,26 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
-
 #include <linux/slab.h>
-
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_decoder.h>
 
 MODULE_DESCRIPTION("Philips SAA7114H video decoder driver");
 MODULE_AUTHOR("Maxim Yevtyushkin");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(x) (x)->name
 
-#include <linux/video_decoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index 9f98693..e35ef32 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -332,11 +332,11 @@
 	if (!enable)
 		return 0;
 
-	state->vps_data[0] = data->data[4];
-	state->vps_data[1] = data->data[10];
-	state->vps_data[2] = data->data[11];
-	state->vps_data[3] = data->data[12];
-	state->vps_data[4] = data->data[13];
+	state->vps_data[0] = data->data[2];
+	state->vps_data[1] = data->data[8];
+	state->vps_data[2] = data->data[9];
+	state->vps_data[3] = data->data[10];
+	state->vps_data[4] = data->data[11];
 	v4l_dbg(1, debug, client, "Set VPS data %02x %02x %02x %02x %02x\n",
 		state->vps_data[0], state->vps_data[1],
 		state->vps_data[2], state->vps_data[3],
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index 309dca3..d6d8d66 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -1,7 +1,7 @@
 config VIDEO_SAA7134
 	tristate "Philips SAA7134 support"
 	depends on VIDEO_DEV && PCI && I2C
-	select VIDEO_BUF
+	select VIDEOBUF_DMA_SG
 	select VIDEO_IR
 	select VIDEO_TUNER
 	select CRC32
@@ -38,9 +38,9 @@
 config VIDEO_SAA7134_DVB
 	tristate "DVB/ATSC Support for saa7134 based TV cards"
 	depends on VIDEO_SAA7134 && DVB_CORE
-	select VIDEO_BUF_DVB
+	select VIDEOBUF_DVB
 	select FW_LOADER
-	select DVB_PLL
+	select DVB_PLL if !DVB_FE_CUSTOMISE
 	select DVB_MT352 if !DVB_FE_CUSTOMISE
 	select DVB_TDA1004X if !DVB_FE_CUSTOMISE
 	select DVB_NXT200X if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index ffb0f64..c6f7279 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -20,7 +20,6 @@
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/wait.h>
-#include <linux/moduleparam.h>
 #include <linux/module.h>
 #include <sound/driver.h>
 #include <sound/core.h>
@@ -75,7 +74,8 @@
 	struct saa7134_dev *dev;
 
 	unsigned long iobase;
-	int irq;
+	s16 irq;
+	u16 mute_was_on;
 
 	spinlock_t lock;
 } snd_card_saa7134_t;
@@ -312,7 +312,7 @@
 	dev->dmasound.blksize = 0;
 	dev->dmasound.bufsize = 0;
 
-       return 0;
+	return 0;
 }
 
 
@@ -589,8 +589,10 @@
 	snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
 	struct saa7134_dev *dev = saa7134->dev;
 
-	dev->ctl_mute = 1;
-	saa7134_tvaudio_setmute(dev);
+	if (saa7134->mute_was_on) {
+		dev->ctl_mute = 1;
+		saa7134_tvaudio_setmute(dev);
+	}
 	return 0;
 }
 
@@ -637,8 +639,11 @@
 	runtime->private_free = snd_card_saa7134_runtime_free;
 	runtime->hw = snd_card_saa7134_capture;
 
-	dev->ctl_mute = 0;
-	saa7134_tvaudio_setmute(dev);
+	if (dev->ctl_mute != 0) {
+		saa7134->mute_was_on = 1;
+		dev->ctl_mute = 0;
+		saa7134_tvaudio_setmute(dev);
+	}
 
 	if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
 		return err;
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 50f15ad..a4c192f 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -32,6 +32,7 @@
 static char name_radio[]   = "Radio";
 static char name_tv[]      = "Television";
 static char name_tv_mono[] = "TV (mono only)";
+static char name_comp[]    = "Composite";
 static char name_comp1[]   = "Composite1";
 static char name_comp2[]   = "Composite2";
 static char name_comp3[]   = "Composite3";
@@ -400,7 +401,7 @@
 		.inputs		= {{
 			.name = name_tv,
 			.vmux = 1,
-			.amux = LINE2,
+			.amux = TV,
 			.tv   = 1,
 			.gpio = 0x20000,
 		},{
@@ -1535,20 +1536,15 @@
 			.tv   = 1,
 			.gpio = 0x00,
 		},{
-			.name = name_comp1,
-			.vmux = 0,
-			.amux = LINE2,
-			.gpio = 0x00,
-		},{
-			.name = name_comp2,
+			.name = name_comp,
 			.vmux = 3,
-			.amux = LINE2,
-			.gpio = 0x00,
+			.amux = LINE1,
+			.gpio = 0x02,
 		},{
 			.name = name_svideo,
 			.vmux = 8,
-			.amux = LINE2,
-			.gpio = 0x00,
+			.amux = LINE1,
+			.gpio = 0x02,
 		}},
 		.radio = {
 			.name = name_radio,
@@ -2771,6 +2767,7 @@
 		.tuner_addr     = ADDR_UNSET,
 		.radio_addr     = ADDR_UNSET,
 		.mpeg           = SAA7134_MPEG_DVB,
+		.gpiomask       = 1 << 21,
 		.inputs = {{
 			.name   = name_tv,
 			.vmux   = 1,
@@ -2781,13 +2778,18 @@
 			.vmux   = 3,
 			.amux   = LINE1,
 		},{
-			.name   = name_svideo,
+			.name   = name_comp2,
 			.vmux   = 0,
 			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
 		}},
 		.radio = {
 			.name   = name_radio,
-			.amux   = LINE1,
+			.amux   = TV,
+			.gpio   = 0x0200000,
 		},
 	},
 	[SAA7134_BOARD_KWORLD_DVBT_210] = {
@@ -2820,7 +2822,7 @@
 		},
 	},
 	[SAA7134_BOARD_KWORLD_ATSC110] = {
-		.name           = "Kworld ATSC110",
+		.name           = "Kworld ATSC110/115",
 		.audio_clock    = 0x00187de7,
 		.tuner_type     = TUNER_PHILIPS_TUV1236D,
 		.radio_type     = UNSET,
@@ -2896,7 +2898,7 @@
 		.radio_addr	= ADDR_UNSET,
 	},
 	[SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS] = {
-		.name		= "LifeView FlyDVB-T Hybrid Cardbus",
+		.name		= "LifeView FlyDVB-T Hybrid Cardbus/MSI TV @nywhere A/D NB",
 		.audio_clock    = 0x00200000,
 		.tuner_type     = TUNER_PHILIPS_TDA8290,
 		.radio_type     = UNSET,
@@ -3502,6 +3504,54 @@
 			.amux = TV,
 		},
 	},
+	[SAA7134_BOARD_10MOONSTVMASTER3] = {
+		/* Tony Wan <aloha_cn@hotmail.com> */
+		.name           = "10MOONS TM300 TV Card",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_LG_PAL_NEW_TAPC,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.gpiomask       = 0x7000,
+		.inputs         = {{
+			.name = name_tv,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x0000,
+			.tv   = 1,
+		},{
+			.name = name_comp1,
+			.vmux = 3,
+			.amux = LINE1,
+			.gpio = 0x2000,
+		},{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+			.gpio = 0x2000,
+		}},
+		.mute = {
+			.name = name_mute,
+			.amux = LINE2,
+			.gpio = 0x3000,
+		},
+	},
+	[SAA7134_BOARD_AVERMEDIA_SUPER_007] = {
+		.name           = "Avermedia Super 007",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_PHILIPS_TDA8290,
+		.radio_type     = UNSET,
+		.tuner_addr     = ADDR_UNSET,
+		.radio_addr     = ADDR_UNSET,
+		.tuner_config   = 0,
+		.mpeg           = SAA7134_MPEG_DVB,
+		.inputs = {{
+			.name   = name_tv, /* FIXME: analog tv untested */
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		}},
+	},
 };
 
 const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4034,6 +4084,12 @@
 		.driver_data  = SAA7134_BOARD_KWORLD_ATSC110,
 	},{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */
+		.subvendor    = 0x17de,
+		.subdevice    = 0x7352,
+		.driver_data  = SAA7134_BOARD_KWORLD_ATSC110, /* ATSC 115 */
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
 		.subvendor    = 0x1461,
 		.subdevice    = 0x7360,
@@ -4219,6 +4275,24 @@
 		.subdevice    = 0x2003, /* OEM cardbus */
 		.driver_data  = SAA7134_BOARD_SABRENT_TV_PCB05,
 	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0x2304,
+		.driver_data  = SAA7134_BOARD_10MOONSTVMASTER3,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x1461, /* Avermedia Technologies Inc */
+		.subdevice    = 0xf01d, /* AVerTV DVB-T Super 007 */
+		.driver_data  = SAA7134_BOARD_AVERMEDIA_SUPER_007,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = 0x4e42,
+		.subdevice    = 0x3502,
+		.driver_data  = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS
+	},{
 		/* --- boards without eeprom + subsystem ID --- */
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -4330,6 +4404,7 @@
 	case SAA7134_BOARD_AVERMEDIA_A16AR:
 	case SAA7134_BOARD_ENCORE_ENLTV:
 	case SAA7134_BOARD_ENCORE_ENLTV_FM:
+	case SAA7134_BOARD_10MOONSTVMASTER3:
 		dev->has_remote = SAA7134_REMOTE_GPIO;
 		break;
 	case SAA7134_BOARD_FLYDVBS_LR300:
@@ -4525,6 +4600,7 @@
 		break;
 	case SAA7134_BOARD_PHILIPS_TIGER:
 	case SAA7134_BOARD_PHILIPS_TIGER_S:
+	case SAA7134_BOARD_AVERMEDIA_SUPER_007:
 		{
 		u8 data[] = { 0x3c, 0x33, 0x60};
 		struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 25f8470..1a4a244 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -23,7 +23,6 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/kmod.h>
@@ -32,6 +31,7 @@
 #include <linux/delay.h>
 #include <linux/mutex.h>
 #include <linux/dma-mapping.h>
+#include <linux/pm.h>
 
 #include "saa7134-reg.h"
 #include "saa7134.h"
@@ -237,9 +237,10 @@
 unsigned long saa7134_buffer_base(struct saa7134_buf *buf)
 {
 	unsigned long base;
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 
 	base  = saa7134_buffer_startpage(buf) * 4096;
-	base += buf->vb.dma.sglist[0].offset;
+	base += dma->sglist[0].offset;
 	return base;
 }
 
@@ -287,11 +288,12 @@
 
 void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf)
 {
+	struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
 	BUG_ON(in_interrupt());
 
 	videobuf_waiton(&buf->vb,0,0);
-	videobuf_dma_unmap(q, &buf->vb.dma);
-	videobuf_dma_free(&buf->vb.dma);
+	videobuf_dma_unmap(q, dma);
+	videobuf_dma_free(dma);
 	buf->vb.state = STATE_NEEDS_INIT;
 }
 
@@ -391,6 +393,32 @@
 	spin_unlock_irqrestore(&dev->slock,flags);
 }
 
+/* resends a current buffer in queue after resume */
+
+int saa7134_buffer_requeue(struct saa7134_dev *dev,
+			 struct saa7134_dmaqueue *q)
+{
+	struct saa7134_buf *buf, *next;
+
+	assert_spin_locked(&dev->slock);
+
+	buf  = q->curr;
+	next = buf;
+	dprintk("buffer_requeue\n");
+
+	if (!buf)
+		return 0;
+
+	dprintk("buffer_requeue : resending active buffers \n");
+
+	if (!list_empty(&q->queue))
+		next = list_entry(q->queue.next, struct saa7134_buf,
+					  vb.queue);
+	buf->activate(dev, buf, next);
+
+	return 0;
+}
+
 /* ------------------------------------------------------------------ */
 
 int saa7134_set_dmabits(struct saa7134_dev *dev)
@@ -401,6 +429,9 @@
 
 	assert_spin_locked(&dev->slock);
 
+	if (dev->inresume)
+		return 0;
+
 	/* video capture -- dma 0 + video task A */
 	if (dev->video_q.curr) {
 		task |= 0x01;
@@ -560,8 +591,10 @@
 			print_irqstatus(dev,loop,report,status);
 
 
-		if (report & SAA7134_IRQ_REPORT_RDCAP /* _INTL */)
-			saa7134_irq_video_intl(dev);
+		if ((report & SAA7134_IRQ_REPORT_RDCAP) ||
+			(report & SAA7134_IRQ_REPORT_INTL))
+				saa7134_irq_video_signalchange(dev);
+
 
 		if ((report & SAA7134_IRQ_REPORT_DONE_RA0) &&
 		    (status & 0x60) == 0)
@@ -646,6 +679,39 @@
 /* ------------------------------------------------------------------ */
 
 /* early init (no i2c, no irq) */
+
+static int saa7134_hw_enable1(struct saa7134_dev *dev)
+{
+	/* RAM FIFO config */
+	saa_writel(SAA7134_FIFO_SIZE, 0x08070503);
+	saa_writel(SAA7134_THRESHOULD, 0x02020202);
+
+	/* enable audio + video processing */
+	saa_writel(SAA7134_MAIN_CTRL,
+			SAA7134_MAIN_CTRL_VPLLE |
+			SAA7134_MAIN_CTRL_APLLE |
+			SAA7134_MAIN_CTRL_EXOSC |
+			SAA7134_MAIN_CTRL_EVFE1 |
+			SAA7134_MAIN_CTRL_EVFE2 |
+			SAA7134_MAIN_CTRL_ESFE  |
+			SAA7134_MAIN_CTRL_EBDAC);
+
+	/*
+	* Initialize OSS _after_ enabling audio clock PLL and audio processing.
+	* OSS initialization writes to registers via the audio DSP; these
+	* writes will fail unless the audio clock has been started.  At worst,
+	* audio will not work.
+	*/
+
+	/* enable peripheral devices */
+	saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+
+	/* set vertical line numbering start (vbi needs this) */
+	saa_writeb(SAA7134_SOURCE_TIMING2, 0x20);
+
+	return 0;
+}
+
 static int saa7134_hwinit1(struct saa7134_dev *dev)
 {
 	dprintk("hwinit1\n");
@@ -662,44 +728,16 @@
 		saa7134_ts_init1(dev);
 	saa7134_input_init1(dev);
 
-	/* RAM FIFO config */
-	saa_writel(SAA7134_FIFO_SIZE, 0x08070503);
-	saa_writel(SAA7134_THRESHOULD,0x02020202);
-
-	/* enable audio + video processing */
-	saa_writel(SAA7134_MAIN_CTRL,
-		   SAA7134_MAIN_CTRL_VPLLE |
-		   SAA7134_MAIN_CTRL_APLLE |
-		   SAA7134_MAIN_CTRL_EXOSC |
-		   SAA7134_MAIN_CTRL_EVFE1 |
-		   SAA7134_MAIN_CTRL_EVFE2 |
-		   SAA7134_MAIN_CTRL_ESFE  |
-		   SAA7134_MAIN_CTRL_EBDAC);
-
-	/*
-	 * Initialize OSS _after_ enabling audio clock PLL and audio processing.
-	 * OSS initialization writes to registers via the audio DSP; these
-	 * writes will fail unless the audio clock has been started.  At worst,
-	 * audio will not work.
-	 */
-
-	/* enable peripheral devices */
-	saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
-
-	/* set vertical line numbering start (vbi needs this) */
-	saa_writeb(SAA7134_SOURCE_TIMING2, 0x20);
+	saa7134_hw_enable1(dev);
 
 	return 0;
 }
 
 /* late init (with i2c + irq) */
-static int saa7134_hwinit2(struct saa7134_dev *dev)
+static int saa7134_hw_enable2(struct saa7134_dev *dev)
 {
-	unsigned int irq2_mask;
-	dprintk("hwinit2\n");
 
-	saa7134_video_init2(dev);
-	saa7134_tvaudio_init2(dev);
+	unsigned int irq2_mask;
 
 	/* enable IRQ's */
 	irq2_mask =
@@ -725,6 +763,20 @@
 	return 0;
 }
 
+static int saa7134_hwinit2(struct saa7134_dev *dev)
+{
+
+	dprintk("hwinit2\n");
+
+	saa7134_video_init2(dev);
+	saa7134_tvaudio_init2(dev);
+
+	saa7134_hw_enable2(dev);
+
+	return 0;
+}
+
+
 /* shutdown */
 static int saa7134_hwfini(struct saa7134_dev *dev)
 {
@@ -838,7 +890,6 @@
 				     const struct pci_device_id *pci_id)
 {
 	struct saa7134_dev *dev;
-	struct list_head *item;
 	struct saa7134_mpeg_ops *mops;
 	int err;
 
@@ -1020,15 +1071,13 @@
 	saa7134_devcount++;
 
 	mutex_lock(&devlist_lock);
-	list_for_each(item,&mops_list) {
-		mops = list_entry(item, struct saa7134_mpeg_ops, next);
+	list_for_each_entry(mops, &mops_list, next)
 		mpeg_ops_attach(mops, dev);
-	}
 	list_add_tail(&dev->devlist,&saa7134_devlist);
 	mutex_unlock(&devlist_lock);
 
 	/* check for signal */
-	saa7134_irq_video_intl(dev);
+	saa7134_irq_video_signalchange(dev);
 
 	if (saa7134_dmasound_init && !dev->dmasound.priv_data) {
 		saa7134_dmasound_init(dev);
@@ -1057,7 +1106,6 @@
 static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
 {
 	struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
-	struct list_head *item;
 	struct saa7134_mpeg_ops *mops;
 
 	/* Release DMA sound modules if present */
@@ -1086,10 +1134,8 @@
 	/* unregister */
 	mutex_lock(&devlist_lock);
 	list_del(&dev->devlist);
-	list_for_each(item,&mops_list) {
-		mops = list_entry(item, struct saa7134_mpeg_ops, next);
+	list_for_each_entry(mops, &mops_list, next)
 		mpeg_ops_detach(mops, dev);
-	}
 	mutex_unlock(&devlist_lock);
 	saa7134_devcount--;
 
@@ -1117,18 +1163,79 @@
 	kfree(dev);
 }
 
+static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
+{
+
+	struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
+
+	/* disable overlay - apps should enable it explicitly on resume*/
+	dev->ovenable = 0;
+
+	/* Disable interrupts, DMA, and rest of the chip*/
+	saa_writel(SAA7134_IRQ1, 0);
+	saa_writel(SAA7134_IRQ2, 0);
+	saa_writel(SAA7134_MAIN_CTRL, 0);
+
+	pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
+	pci_save_state(pci_dev);
+
+    return 0;
+}
+
+static int saa7134_resume(struct pci_dev *pci_dev)
+{
+
+	struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
+	unsigned int flags;
+
+	pci_restore_state(pci_dev);
+	pci_set_power_state(pci_dev, PCI_D0);
+
+	/* Do things that are done in saa7134_initdev ,
+		except of initializing memory structures.*/
+
+	dev->inresume = 1;
+	saa7134_board_init1(dev);
+
+	if (saa7134_boards[dev->board].video_out)
+		saa7134_videoport_init(dev);
+
+	if (card_has_mpeg(dev))
+		saa7134_ts_init_hw(dev);
+
+	saa7134_hw_enable1(dev);
+	saa7134_set_decoder(dev);
+	saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id);
+	saa7134_board_init2(dev);
+	saa7134_hw_enable2(dev);
+
+	saa7134_tvaudio_setmute(dev);
+	saa7134_tvaudio_setvolume(dev, dev->ctl_volume);
+	saa7134_enable_i2s(dev);
+
+	/*resume unfinished buffer(s)*/
+	spin_lock_irqsave(&dev->slock, flags);
+	saa7134_buffer_requeue(dev, &dev->video_q);
+	saa7134_buffer_requeue(dev, &dev->vbi_q);
+	saa7134_buffer_requeue(dev, &dev->ts_q);
+
+	/* start DMA now*/
+	dev->inresume = 0;
+	saa7134_set_dmabits(dev);
+	spin_unlock_irqrestore(&dev->slock, flags);
+
+	return 0;
+}
+
 /* ----------------------------------------------------------- */
 
 int saa7134_ts_register(struct saa7134_mpeg_ops *ops)
 {
-	struct list_head *item;
 	struct saa7134_dev *dev;
 
 	mutex_lock(&devlist_lock);
-	list_for_each(item,&saa7134_devlist) {
-		dev = list_entry(item, struct saa7134_dev, devlist);
+	list_for_each_entry(dev, &saa7134_devlist, devlist)
 		mpeg_ops_attach(ops, dev);
-	}
 	list_add_tail(&ops->next,&mops_list);
 	mutex_unlock(&devlist_lock);
 	return 0;
@@ -1136,15 +1243,12 @@
 
 void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops)
 {
-	struct list_head *item;
 	struct saa7134_dev *dev;
 
 	mutex_lock(&devlist_lock);
 	list_del(&ops->next);
-	list_for_each(item,&saa7134_devlist) {
-		dev = list_entry(item, struct saa7134_dev, devlist);
+	list_for_each_entry(dev, &saa7134_devlist, devlist)
 		mpeg_ops_detach(ops, dev);
-	}
 	mutex_unlock(&devlist_lock);
 }
 
@@ -1158,6 +1262,8 @@
 	.id_table = saa7134_pci_tbl,
 	.probe    = saa7134_initdev,
 	.remove   = __devexit_p(saa7134_finidev),
+	.suspend  = saa7134_suspend,
+	.resume   = saa7134_resume
 };
 
 static int saa7134_init(void)
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index e0eec80..38d8733 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -175,18 +175,6 @@
 	return mt352_pinnacle_init(fe);
 }
 
-static int mt352_aver777_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
-{
-	if (buf_len < 5)
-		return -EINVAL;
-
-	pllbuf[0] = 0x61;
-	dvb_pll_configure(&dvb_pll_philips_td1316, pllbuf+1,
-			  params->frequency,
-			  params->u.ofdm.bandwidth);
-	return 5;
-}
-
 static struct mt352_config pinnacle_300i = {
 	.demod_address = 0x3c >> 1,
 	.adc_clock     = 20333,
@@ -444,135 +432,6 @@
 
 /* ------------------------------------------------------------------ */
 
-static int philips_fmd1216_tuner_init(struct dvb_frontend *fe)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	struct tda1004x_state *state = fe->demodulator_priv;
-	u8 addr = state->config->tuner_address;
-	/* this message is to set up ATC and ALC */
-	static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
-	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
-		return -EIO;
-	msleep(1);
-
-	return 0;
-}
-
-static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	struct tda1004x_state *state = fe->demodulator_priv;
-	u8 addr = state->config->tuner_address;
-	/* this message actually turns the tuner back to analog mode */
-	u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 };
-	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
-	msleep(1);
-	fmd1216_init[2] = 0x86;
-	fmd1216_init[3] = 0x54;
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
-	msleep(1);
-	return 0;
-}
-
-static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
-{
-	struct saa7134_dev *dev = fe->dvb->priv;
-	struct tda1004x_state *state = fe->demodulator_priv;
-	u8 addr = state->config->tuner_address;
-	u8 tuner_buf[4];
-	struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tuner_buf,.len =
-			sizeof(tuner_buf) };
-	int tuner_frequency = 0;
-	int divider = 0;
-	u8 band, mode, cp;
-
-	/* determine charge pump */
-	tuner_frequency = params->frequency + 36130000;
-	if (tuner_frequency < 87000000)
-		return -EINVAL;
-	/* low band */
-	else if (tuner_frequency < 180000000) {
-		band = 1;
-		mode = 7;
-		cp   = 0;
-	} else if (tuner_frequency < 195000000) {
-		band = 1;
-		mode = 6;
-		cp   = 1;
-	/* mid band	*/
-	} else if (tuner_frequency < 366000000) {
-		if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
-			band = 10;
-		} else {
-			band = 2;
-		}
-		mode = 7;
-		cp   = 0;
-	} else if (tuner_frequency < 478000000) {
-		if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
-			band = 10;
-		} else {
-			band = 2;
-		}
-		mode = 6;
-		cp   = 1;
-	/* high band */
-	} else if (tuner_frequency < 662000000) {
-		if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
-			band = 12;
-		} else {
-			band = 4;
-		}
-		mode = 7;
-		cp   = 0;
-	} else if (tuner_frequency < 840000000) {
-		if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
-			band = 12;
-		} else {
-			band = 4;
-		}
-		mode = 6;
-		cp   = 1;
-	} else {
-		if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
-			band = 12;
-		} else {
-			band = 4;
-		}
-		mode = 7;
-		cp   = 1;
-
-	}
-	/* calculate divisor */
-	/* ((36166000 + Finput) / 166666) rounded! */
-	divider = (tuner_frequency + 83333) / 166667;
-
-	/* setup tuner buffer */
-	tuner_buf[0] = (divider >> 8) & 0x7f;
-	tuner_buf[1] = divider & 0xff;
-	tuner_buf[2] = 0x80 | (cp << 6) | (mode  << 3) | 4;
-	tuner_buf[3] = 0x40 | band;
-
-	if (fe->ops.i2c_gate_ctrl)
-		fe->ops.i2c_gate_ctrl(fe, 1);
-	if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1) {
-		wprintk("could not write to tuner at addr: 0x%02x\n",
-			addr << 1);
-		return -EIO;
-	}
-	return 0;
-}
-
 static struct tda1004x_config medion_cardbus = {
 	.demod_address = 0x08,
 	.invert        = 1,
@@ -708,6 +567,7 @@
 }
 
 /* ------------------------------------------------------------------ */
+
 static struct tda1004x_config tda827x_lifeview_config = {
 	.demod_address = 0x08,
 	.invert        = 1,
@@ -887,6 +747,7 @@
 	.antenna_switch= 2,
 	.request_firmware = philips_tda1004x_request_firmware
 };
+
 static struct tda1004x_config kworld_dvb_t_210_config = {
 	.demod_address = 0x08,
 	.invert        = 1,
@@ -901,6 +762,22 @@
 	.antenna_switch= 1,
 	.request_firmware = philips_tda1004x_request_firmware
 };
+
+static struct tda1004x_config avermedia_super_007_config = {
+	.demod_address = 0x08,
+	.invert        = 1,
+	.invert_oclk   = 0,
+	.xtal_freq     = TDA10046_XTAL_16M,
+	.agc_config    = TDA10046_AGC_TDA827X,
+	.gpio_config   = TDA10046_GP01_I,
+	.if_freq       = TDA10046_FREQ_045,
+	.i2c_gate      = 0x4b,
+	.tuner_address = 0x60,
+	.tuner_config  = 0,
+	.antenna_switch= 1,
+	.request_firmware = philips_tda1004x_request_firmware
+};
+
 /* ------------------------------------------------------------------
  * special case: this card uses saa713x GPIO22 for the mode switch
  */
@@ -958,18 +835,8 @@
 	.demod_address    = 0x0a,
 };
 
-static int nxt200x_set_pll_input(u8 *buf, int input)
-{
-	if (input)
-		buf[3] |= 0x08;
-	else
-		buf[3] &= ~0x08;
-	return 0;
-}
-
 static struct nxt200x_config kworldatsc110 = {
 	.demod_address    = 0x0a,
-	.set_pll_input    = nxt200x_set_pll_input,
 };
 
 /* ==================================================================
@@ -983,7 +850,7 @@
 	dev->ts.nr_bufs    = 32;
 	dev->ts.nr_packets = 32*4;
 	dev->dvb.name = dev->name;
-	videobuf_queue_init(&dev->dvb.dvbq, &saa7134_ts_qops,
+	videobuf_queue_pci_init(&dev->dvb.dvbq, &saa7134_ts_qops,
 			    dev->pci, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_ALTERNATE,
@@ -1005,7 +872,8 @@
 		dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
 					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.tuner_ops.calc_regs = mt352_aver777_tuner_calc_regs;
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+				   NULL, DVB_PLL_PHILIPS_TD1316);
 		}
 		break;
 	case SAA7134_BOARD_MD7134:
@@ -1013,9 +881,8 @@
 					       &medion_cardbus,
 					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
-			dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
-			dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
-			dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address,
+				   &dev->i2c_adap, DVB_PLL_FMD1216ME);
 		}
 		break;
 	case SAA7134_BOARD_PHILIPS_TOUGH:
@@ -1113,7 +980,7 @@
 					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   NULL, &dvb_pll_tdhu2);
+				   NULL, DVB_PLL_TDHU2);
 		}
 		break;
 	case SAA7134_BOARD_KWORLD_ATSC110:
@@ -1121,7 +988,7 @@
 					       &dev->i2c_adap);
 		if (dev->dvb.frontend) {
 			dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
-				   NULL, &dvb_pll_tuv1236d);
+				   NULL, DVB_PLL_TUV1236D);
 		}
 		break;
 	case SAA7134_BOARD_FLYDVBS_LR300:
@@ -1144,9 +1011,9 @@
 		if (dev->dvb.frontend) {
 			dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
 			dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
-			dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
-			dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
-			dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+
+			dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address,
+				   &dev->i2c_adap, DVB_PLL_FMD1216ME);
 		}
 		break;
 	case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
@@ -1173,6 +1040,9 @@
 	case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
 		configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config);
 		break;
+	case SAA7134_BOARD_AVERMEDIA_SUPER_007:
+		configure_tda827x_fe(dev, &avermedia_super_007_config);
+		break;
 	default:
 		wprintk("Huh? unknown DVB card?\n");
 		break;
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index f521603..34ca874d 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -20,7 +20,6 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
@@ -77,17 +76,14 @@
 static int ts_open(struct inode *inode, struct file *file)
 {
 	int minor = iminor(inode);
-	struct saa7134_dev *h,*dev = NULL;
-	struct list_head *list;
+	struct saa7134_dev *dev;
 	int err;
 
-	list_for_each(list,&saa7134_devlist) {
-		h = list_entry(list, struct saa7134_dev, devlist);
-		if (h->empress_dev && h->empress_dev->minor == minor)
-			dev = h;
-	}
-	if (NULL == dev)
-		return -ENODEV;
+	list_for_each_entry(dev, &saa7134_devlist, devlist)
+		if (dev->empress_dev && dev->empress_dev->minor == minor)
+			goto found;
+	return -ENODEV;
+ found:
 
 	dprintk("open minor=%d\n",minor);
 	err = -EBUSY;
@@ -96,6 +92,10 @@
 	if (dev->empress_users)
 		goto done_up;
 
+	/* Unmute audio */
+	saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+		saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
+
 	dev->empress_users++;
 	file->private_data = dev;
 	err = 0;
@@ -121,6 +121,10 @@
 	/* stop the encoder */
 	ts_reset_encoder(dev);
 
+	/* Mute audio */
+	saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+		saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
+
 	mutex_unlock(&dev->empress_tsq.lock);
 	return 0;
 }
@@ -393,7 +397,7 @@
 	printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
 	       dev->name,dev->empress_dev->minor & 0x1f);
 
-	videobuf_queue_init(&dev->empress_tsq, &saa7134_ts_qops,
+	videobuf_queue_pci_init(&dev->empress_tsq, &saa7134_ts_qops,
 			    dev->pci, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_ALTERNATE,
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 1cb8c70..cc87f58 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -23,7 +23,6 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index c0de37e..80d2644 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -19,7 +19,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -153,21 +152,18 @@
 
 static void saa7134_input_timer(unsigned long data)
 {
-	struct saa7134_dev *dev = (struct saa7134_dev*)data;
+	struct saa7134_dev *dev = (struct saa7134_dev *)data;
 	struct card_ir *ir = dev->remote;
-	unsigned long timeout;
 
 	build_key(dev);
-	timeout = jiffies + (ir->polling * HZ / 1000);
-	mod_timer(&ir->timer, timeout);
+	mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
 }
 
 static void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir)
 {
 	if (ir->polling) {
-		init_timer(&ir->timer);
-		ir->timer.function = saa7134_input_timer;
-		ir->timer.data     = (unsigned long)dev;
+		setup_timer(&ir->timer, saa7134_input_timer,
+			    (unsigned long)dev);
 		ir->timer.expires  = jiffies + HZ;
 		add_timer(&ir->timer);
 	} else if (ir->rc5_gpio) {
@@ -314,6 +310,7 @@
 		mask_keycode = 0x003F00;
 		mask_keyup   = 0x040000;
 		break;
+	case SAA7134_BOARD_FLYDVBS_LR300:
 	case SAA7134_BOARD_FLYDVBT_LR301:
 	case SAA7134_BOARD_FLYDVBTDUO:
 		ir_codes     = ir_codes_flydvb;
@@ -333,6 +330,12 @@
 		mask_keyup   = 0x040000;
 		polling      = 50; // ms
 		break;
+	case SAA7134_BOARD_10MOONSTVMASTER3:
+		ir_codes     = ir_codes_encore_enltv;
+		mask_keycode = 0x5f80000;
+		mask_keyup   = 0x8000000;
+		polling      = 50; //ms
+		break;
 	}
 	if (NULL == ir_codes) {
 		printk("%s: Oops: IR config error [card=%d]\n",
@@ -374,7 +377,7 @@
 		input_dev->id.vendor  = dev->pci->vendor;
 		input_dev->id.product = dev->pci->device;
 	}
-	input_dev->cdev.dev = &dev->pci->dev;
+	input_dev->dev.parent = &dev->pci->dev;
 
 	dev->remote = ir;
 	saa7134_ir_start(dev, ir);
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
index 72444f0..aedf046 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -25,7 +25,6 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
@@ -240,17 +239,14 @@
 static int dsp_open(struct inode *inode, struct file *file)
 {
 	int minor = iminor(inode);
-	struct saa7134_dev *h,*dev = NULL;
-	struct list_head *list;
+	struct saa7134_dev *dev;
 	int err;
 
-	list_for_each(list,&saa7134_devlist) {
-		h = list_entry(list, struct saa7134_dev, devlist);
-		if (h->dmasound.minor_dsp == minor)
-			dev = h;
-	}
-	if (NULL == dev)
-		return -ENODEV;
+	list_for_each_entry(dev, &saa7134_devlist, devlist)
+		if (dev->dmasound.minor_dsp == minor)
+			goto found;
+	return -ENODEV;
+ found:
 
 	mutex_lock(&dev->dmasound.lock);
 	err = -EBUSY;
@@ -681,19 +677,14 @@
 static int mixer_open(struct inode *inode, struct file *file)
 {
 	int minor = iminor(inode);
-	struct saa7134_dev *h,*dev = NULL;
-	struct list_head *list;
+	struct saa7134_dev *dev;
 
-	list_for_each(list,&saa7134_devlist) {
-		h = list_entry(list, struct saa7134_dev, devlist);
-		if (h->dmasound.minor_mixer == minor)
-			dev = h;
-	}
-	if (NULL == dev)
-		return -ENODEV;
-
-	file->private_data = dev;
-	return 0;
+	list_for_each_entry(dev, &saa7134_devlist, devlist)
+		if (dev->dmasound.minor_mixer == minor) {
+			file->private_data = dev;
+			return 0;
+		}
+	return -ENODEV;
 }
 
 static int mixer_release(struct inode *inode, struct file *file)
@@ -1023,18 +1014,14 @@
 
 static void saa7134_oss_exit(void)
 {
-	struct saa7134_dev *dev = NULL;
-	struct list_head *list;
+	struct saa7134_dev *dev;
 
-	list_for_each(list,&saa7134_devlist) {
-		dev = list_entry(list, struct saa7134_dev, devlist);
-
+	list_for_each_entry(dev, &saa7134_devlist, devlist) {
 		/* Device isn't registered by OSS, probably ALSA's */
 		if (!dev->dmasound.minor_dsp)
 			continue;
 
 		oss_device_exit(dev);
-
 	}
 
 	saa7134_dmasound_init = NULL;
diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
index 60a90a2..4b63ad3 100644
--- a/drivers/media/video/saa7134/saa7134-ts.c
+++ b/drivers/media/video/saa7134/saa7134-ts.c
@@ -23,7 +23,6 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
@@ -93,6 +92,8 @@
 	}
 
 	if (STATE_NEEDS_INIT == buf->vb.state) {
+		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
 		buf->vb.width  = llength;
 		buf->vb.height = lines;
 		buf->vb.size   = size;
@@ -102,8 +103,8 @@
 		if (err)
 			goto oops;
 		err = saa7134_pgtable_build(dev->pci,buf->pt,
-					    buf->vb.dma.sglist,
-					    buf->vb.dma.sglen,
+					    dma->sglist,
+					    dma->sglen,
 					    saa7134_buffer_startpage(buf));
 		if (err)
 			goto oops;
@@ -176,6 +177,22 @@
 module_param(ts_nr_packets, int, 0444);
 MODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)");
 
+int saa7134_ts_init_hw(struct saa7134_dev *dev)
+{
+	/* deactivate TS softreset */
+	saa_writeb(SAA7134_TS_SERIAL1, 0x00);
+	/* TSSOP high active, TSVAL high active, TSLOCK ignored */
+	saa_writeb(SAA7134_TS_PARALLEL, 0xec);
+	saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1));
+	saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff));
+	saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff));
+	/* TSNOPIT=0, TSCOLAP=0 */
+	saa_writeb(SAA7134_TS_DMA2,
+		((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00));
+
+	return 0;
+}
+
 int saa7134_ts_init1(struct saa7134_dev *dev)
 {
 	/* sanitycheck insmod options */
@@ -199,12 +216,7 @@
 	saa7134_pgtable_alloc(dev->pci,&dev->ts.pt_ts);
 
 	/* init TS hw */
-	saa_writeb(SAA7134_TS_SERIAL1, 0x00);  /* deactivate TS softreset */
-	saa_writeb(SAA7134_TS_PARALLEL, 0xec); /* TSSOP high active, TSVAL high active, TSLOCK ignored */
-	saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1));
-	saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff));
-	saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff));
-	saa_writeb(SAA7134_TS_DMA2, ((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */
+	saa7134_ts_init_hw(dev);
 
 	return 0;
 }
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index 30395d6..1b9e39a 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -23,8 +23,8 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
+#include <linux/kthread.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <asm/div64.h>
@@ -231,7 +231,7 @@
 	}
 
 	if (dev->hw_mute  == mute &&
-		dev->hw_input == in) {
+		dev->hw_input == in && !dev->inresume) {
 		dprintk("mute/input: nothing to do [mute=%d,input=%s]\n",
 			mute,in->name);
 		return;
@@ -341,10 +341,8 @@
 
 static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
 {
-	DECLARE_WAITQUEUE(wait, current);
-
-	add_wait_queue(&dev->thread.wq, &wait);
-	if (dev->thread.scan1 == dev->thread.scan2 && !dev->thread.shutdown) {
+	if (dev->thread.scan1 == dev->thread.scan2 &&
+	    !kthread_should_stop()) {
 		if (timeout < 0) {
 			set_current_state(TASK_INTERRUPTIBLE);
 			schedule();
@@ -353,7 +351,6 @@
 						(msecs_to_jiffies(timeout));
 		}
 	}
-	remove_wait_queue(&dev->thread.wq, &wait);
 	return dev->thread.scan1 != dev->thread.scan2;
 }
 
@@ -505,11 +502,10 @@
 	unsigned int i, audio, nscan;
 	int max1,max2,carrier,rx,mode,lastmode,default_carrier;
 
-	daemonize("%s", dev->name);
 	allow_signal(SIGTERM);
 	for (;;) {
 		tvaudio_sleep(dev,-1);
-		if (dev->thread.shutdown || signal_pending(current))
+		if (kthread_should_stop() || signal_pending(current))
 			goto done;
 
 	restart:
@@ -618,7 +614,7 @@
 		for (;;) {
 			if (tvaudio_sleep(dev,5000))
 				goto restart;
-			if (dev->thread.shutdown || signal_pending(current))
+			if (kthread_should_stop() || signal_pending(current))
 				break;
 			if (UNSET == dev->thread.mode) {
 				rx = tvaudio_getstereo(dev,&tvaudio[i]);
@@ -634,7 +630,6 @@
 	}
 
  done:
-	complete_and_exit(&dev->thread.exit, 0);
 	return 0;
 }
 
@@ -782,7 +777,6 @@
 	struct saa7134_dev *dev = data;
 	u32 value, norms, clock;
 
-	daemonize("%s", dev->name);
 	allow_signal(SIGTERM);
 
 	clock = saa7134_boards[dev->board].audio_clock;
@@ -796,7 +790,7 @@
 
 	for (;;) {
 		tvaudio_sleep(dev,-1);
-		if (dev->thread.shutdown || signal_pending(current))
+		if (kthread_should_stop() || signal_pending(current))
 			goto done;
 
 	restart:
@@ -876,14 +870,13 @@
 	}
 
  done:
-	complete_and_exit(&dev->thread.exit, 0);
 	return 0;
 }
 
 /* ------------------------------------------------------------------ */
 /* common stuff + external entry points                               */
 
-static void saa7134_enable_i2s(struct saa7134_dev *dev)
+void saa7134_enable_i2s(struct saa7134_dev *dev)
 {
 	int i2s_format;
 
@@ -973,7 +966,6 @@
 
 int saa7134_tvaudio_init2(struct saa7134_dev *dev)
 {
-	DECLARE_MUTEX_LOCKED(sem);
 	int (*my_thread)(void *data) = NULL;
 
 	switch (dev->pci->device) {
@@ -986,15 +978,15 @@
 		break;
 	}
 
-	dev->thread.pid = -1;
+	dev->thread.thread = NULL;
 	if (my_thread) {
 		/* start tvaudio thread */
-		init_waitqueue_head(&dev->thread.wq);
-		init_completion(&dev->thread.exit);
-		dev->thread.pid = kernel_thread(my_thread,dev,0);
-		if (dev->thread.pid < 0)
+		dev->thread.thread = kthread_run(my_thread, dev, "%s", dev->name);
+		if (IS_ERR(dev->thread.thread)) {
 			printk(KERN_WARNING "%s: kernel_thread() failed\n",
 			       dev->name);
+			/* XXX: missing error handling here */
+		}
 		saa7134_tvaudio_do_scan(dev);
 	}
 
@@ -1005,11 +997,9 @@
 int saa7134_tvaudio_fini(struct saa7134_dev *dev)
 {
 	/* shutdown tvaudio thread */
-	if (dev->thread.pid > 0) {
-		dev->thread.shutdown = 1;
-		wake_up_interruptible(&dev->thread.wq);
-		wait_for_completion(&dev->thread.exit);
-	}
+	if (dev->thread.thread)
+		kthread_stop(dev->thread.thread);
+
 	saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */
 	return 0;
 }
@@ -1020,10 +1010,10 @@
 		dprintk("sound IF not in use, skipping scan\n");
 		dev->automute = 0;
 		saa7134_tvaudio_setmute(dev);
-	} else if (dev->thread.pid >= 0) {
+	} else if (dev->thread.thread) {
 		dev->thread.mode = UNSET;
 		dev->thread.scan2++;
-		wake_up_interruptible(&dev->thread.wq);
+		wake_up_process(dev->thread.thread);
 	} else {
 		dev->automute = 0;
 		saa7134_tvaudio_setmute(dev);
@@ -1040,4 +1030,3 @@
  * c-basic-offset: 8
  * End:
  */
-
diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c
index f38366a..81a2aed 100644
--- a/drivers/media/video/saa7134/saa7134-vbi.c
+++ b/drivers/media/video/saa7134/saa7134-vbi.c
@@ -23,7 +23,6 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 
@@ -138,6 +137,8 @@
 		saa7134_dma_free(q,buf);
 
 	if (STATE_NEEDS_INIT == buf->vb.state) {
+		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
 		buf->vb.width  = llength;
 		buf->vb.height = lines;
 		buf->vb.size   = size;
@@ -147,8 +148,8 @@
 		if (err)
 			goto oops;
 		err = saa7134_pgtable_build(dev->pci,buf->pt,
-					    buf->vb.dma.sglist,
-					    buf->vb.dma.sglen,
+					    dma->sglist,
+					    dma->sglen,
 					    saa7134_buffer_startpage(buf));
 		if (err)
 			goto oops;
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 9985ded..471b927 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -23,7 +23,6 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/sort.h>
@@ -41,7 +40,7 @@
 
 static unsigned int video_debug   = 0;
 static unsigned int gbuffers      = 8;
-static unsigned int noninterlaced = 1;
+static unsigned int noninterlaced = 0;
 static unsigned int gbufsize      = 720*576*4;
 static unsigned int gbufsize_max  = 720*576*4;
 static char secam[] = "--";
@@ -541,22 +540,12 @@
 
 /* ------------------------------------------------------------------ */
 
-static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
+void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
 {
-	int luma_control,sync_control,mux;
 
 	dprintk("set tv norm = %s\n",norm->name);
 	dev->tvnorm = norm;
 
-	mux = card_in(dev,dev->ctl_input).vmux;
-	luma_control = norm->luma_control;
-	sync_control = norm->sync_control;
-
-	if (mux > 5)
-		luma_control |= 0x80; /* svideo */
-	if (noninterlaced || dev->nosignal)
-		sync_control |= 0x20;
-
 	/* setup cropping */
 	dev->crop_bounds.left    = norm->h_start;
 	dev->crop_defrect.left   = norm->h_start;
@@ -571,6 +560,40 @@
 
 	dev->crop_current = dev->crop_defrect;
 
+	saa7134_set_decoder(dev);
+
+	if (card_in(dev, dev->ctl_input).tv) {
+		if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290)
+				&& ((card(dev).tuner_config == 1)
+				||  (card(dev).tuner_config == 2)))
+			saa7134_set_gpio(dev, 22, 5);
+		saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &norm->id);
+	}
+}
+
+static void video_mux(struct saa7134_dev *dev, int input)
+{
+	dprintk("video input = %d [%s]\n", input, card_in(dev, input).name);
+	dev->ctl_input = input;
+	set_tvnorm(dev, dev->tvnorm);
+	saa7134_tvaudio_setinput(dev, &card_in(dev, input));
+}
+
+void saa7134_set_decoder(struct saa7134_dev *dev)
+{
+	int luma_control, sync_control, mux;
+
+	struct saa7134_tvnorm *norm = dev->tvnorm;
+	mux = card_in(dev, dev->ctl_input).vmux;
+
+	luma_control = norm->luma_control;
+	sync_control = norm->sync_control;
+
+	if (mux > 5)
+		luma_control |= 0x80; /* svideo */
+	if (noninterlaced || dev->nosignal)
+		sync_control |= 0x20;
+
 	/* setup video decoder */
 	saa_writeb(SAA7134_INCR_DELAY,            0x08);
 	saa_writeb(SAA7134_ANALOG_IN_CTRL1,       0xc0 | mux);
@@ -585,9 +608,13 @@
 	saa_writeb(SAA7134_SYNC_CTRL,             sync_control);
 	saa_writeb(SAA7134_LUMA_CTRL,             luma_control);
 	saa_writeb(SAA7134_DEC_LUMA_BRIGHT,       dev->ctl_bright);
-	saa_writeb(SAA7134_DEC_LUMA_CONTRAST,     dev->ctl_contrast);
 
-	saa_writeb(SAA7134_DEC_CHROMA_SATURATION, dev->ctl_saturation);
+	saa_writeb(SAA7134_DEC_LUMA_CONTRAST,
+		dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);
+
+	saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
+		dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
+
 	saa_writeb(SAA7134_DEC_CHROMA_HUE,        dev->ctl_hue);
 	saa_writeb(SAA7134_CHROMA_CTRL1,          norm->chroma_ctrl1);
 	saa_writeb(SAA7134_CHROMA_GAIN,           norm->chroma_gain);
@@ -601,23 +628,6 @@
 	saa_writeb(SAA7134_MISC_VGATE_MSB,        norm->vgate_misc);
 	saa_writeb(SAA7134_RAW_DATA_GAIN,         0x40);
 	saa_writeb(SAA7134_RAW_DATA_OFFSET,       0x80);
-
-	/* only tell the tuner if this is a tv input */
-	if (card_in(dev,dev->ctl_input).tv) {
-		if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290)
-				&& ((card(dev).tuner_config == 1)
-				||  (card(dev).tuner_config == 2)))
-			saa7134_set_gpio(dev, 22, 5);
-		saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id);
-	}
-}
-
-static void video_mux(struct saa7134_dev *dev, int input)
-{
-	dprintk("video input = %d [%s]\n",input,card_in(dev,input).name);
-	dev->ctl_input = input;
-	set_tvnorm(dev,dev->tvnorm);
-	saa7134_tvaudio_setinput(dev,&card_in(dev,input));
 }
 
 static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
@@ -1038,6 +1048,8 @@
 	}
 
 	if (STATE_NEEDS_INIT == buf->vb.state) {
+		struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+
 		buf->vb.width  = fh->width;
 		buf->vb.height = fh->height;
 		buf->vb.size   = size;
@@ -1049,8 +1061,8 @@
 		if (err)
 			goto oops;
 		err = saa7134_pgtable_build(dev->pci,buf->pt,
-					    buf->vb.dma.sglist,
-					    buf->vb.dma.sglen,
+					    dma->sglist,
+					    dma->sglen,
 					    saa7134_buffer_startpage(buf));
 		if (err)
 			goto oops;
@@ -1273,26 +1285,24 @@
 static int video_open(struct inode *inode, struct file *file)
 {
 	int minor = iminor(inode);
-	struct saa7134_dev *h,*dev = NULL;
+	struct saa7134_dev *dev;
 	struct saa7134_fh *fh;
-	struct list_head *list;
 	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	int radio = 0;
-	list_for_each(list,&saa7134_devlist) {
-		h = list_entry(list, struct saa7134_dev, devlist);
-		if (h->video_dev && (h->video_dev->minor == minor))
-			dev = h;
-		if (h->radio_dev && (h->radio_dev->minor == minor)) {
+	list_for_each_entry(dev, &saa7134_devlist, devlist) {
+		if (dev->video_dev && (dev->video_dev->minor == minor))
+			goto found;
+		if (dev->radio_dev && (dev->radio_dev->minor == minor)) {
 			radio = 1;
-			dev = h;
+			goto found;
 		}
-		if (h->vbi_dev && (h->vbi_dev->minor == minor)) {
+		if (dev->vbi_dev && (dev->vbi_dev->minor == minor)) {
 			type = V4L2_BUF_TYPE_VBI_CAPTURE;
-			dev = h;
+			goto found;
 		}
 	}
-	if (NULL == dev)
-		return -ENODEV;
+	return -ENODEV;
+ found:
 
 	dprintk("open minor=%d radio=%d type=%s\n",minor,radio,
 		v4l2_type_names[type]);
@@ -1310,13 +1320,13 @@
 	fh->height   = 576;
 	v4l2_prio_open(&dev->prio,&fh->prio);
 
-	videobuf_queue_init(&fh->cap, &video_qops,
+	videobuf_queue_pci_init(&fh->cap, &video_qops,
 			    dev->pci, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_INTERLACED,
 			    sizeof(struct saa7134_buf),
 			    fh);
-	videobuf_queue_init(&fh->vbi, &saa7134_vbi_qops,
+	videobuf_queue_pci_init(&fh->vbi, &saa7134_vbi_qops,
 			    dev->pci, &dev->slock,
 			    V4L2_BUF_TYPE_VBI_CAPTURE,
 			    V4L2_FIELD_SEQ_TB,
@@ -1833,7 +1843,11 @@
 		if (res_check(fh, RESOURCE_OVERLAY)) {
 			spin_lock_irqsave(&dev->slock,flags);
 			stop_preview(dev,fh);
+			spin_unlock_irqrestore(&dev->slock, flags);
+
 			set_tvnorm(dev,&tvnorms[i]);
+
+			spin_lock_irqsave(&dev->slock, flags);
 			start_preview(dev,fh);
 			spin_unlock_irqrestore(&dev->slock,flags);
 		} else
@@ -2138,29 +2152,7 @@
 	}
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 	case VIDIOCGMBUF:
-	{
-		struct video_mbuf *mbuf = arg;
-		struct videobuf_queue *q;
-		struct v4l2_requestbuffers req;
-		unsigned int i;
-
-		q = saa7134_queue(fh);
-		memset(&req,0,sizeof(req));
-		req.type   = q->type;
-		req.count  = gbuffers;
-		req.memory = V4L2_MEMORY_MMAP;
-		err = videobuf_reqbufs(q,&req);
-		if (err < 0)
-			return err;
-		memset(mbuf,0,sizeof(*mbuf));
-		mbuf->frames = req.count;
-		mbuf->size   = 0;
-		for (i = 0; i < mbuf->frames; i++) {
-			mbuf->offsets[i]  = q->bufs[i]->boff;
-			mbuf->size       += q->bufs[i]->bsize;
-		}
-		return 0;
-	}
+		return videobuf_cgmbuf(saa7134_queue(fh), arg, gbuffers);
 #endif
 	case VIDIOC_REQBUFS:
 		return videobuf_reqbufs(saa7134_queue(fh),arg);
@@ -2412,34 +2404,40 @@
 	dev->video_q.timeout.data     = (unsigned long)(&dev->video_q);
 	dev->video_q.dev              = dev;
 
-	if (saa7134_boards[dev->board].video_out) {
-		/* enable video output */
-		int vo = saa7134_boards[dev->board].video_out;
-		int video_reg;
-		unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
-		saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
-		video_reg = video_out[vo][1];
-		if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
-			video_reg &= ~VP_T_CODE_P_INVERTED;
-		saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
-		saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
-		saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
-		saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
-		video_reg = video_out[vo][5];
-		if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
-			video_reg &= ~VP_CLK_CTRL2_DELAYED;
-		if (vid_port_opts & SET_CLOCK_INVERTED)
-			video_reg |= VP_CLK_CTRL1_INVERTED;
-		saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg);
-		video_reg = video_out[vo][6];
-		if (vid_port_opts & SET_VSYNC_OFF) {
-			video_reg &= ~VP_VS_TYPE_MASK;
-			video_reg |= VP_VS_TYPE_OFF;
-		}
-		saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg);
-		saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
-		saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
+	if (saa7134_boards[dev->board].video_out)
+		saa7134_videoport_init(dev);
+
+	return 0;
+}
+
+int saa7134_videoport_init(struct saa7134_dev *dev)
+{
+	/* enable video output */
+	int vo = saa7134_boards[dev->board].video_out;
+	int video_reg;
+	unsigned int vid_port_opts = saa7134_boards[dev->board].vid_port_opts;
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]);
+	video_reg = video_out[vo][1];
+	if (vid_port_opts & SET_T_CODE_POLARITY_NON_INVERTED)
+		video_reg &= ~VP_T_CODE_P_INVERTED;
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_reg);
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]);
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]);
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]);
+	video_reg = video_out[vo][5];
+	if (vid_port_opts & SET_CLOCK_NOT_DELAYED)
+		video_reg &= ~VP_CLK_CTRL2_DELAYED;
+	if (vid_port_opts & SET_CLOCK_INVERTED)
+		video_reg |= VP_CLK_CTRL1_INVERTED;
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_reg);
+	video_reg = video_out[vo][6];
+	if (vid_port_opts & SET_VSYNC_OFF) {
+		video_reg &= ~VP_VS_TYPE_MASK;
+		video_reg |= VP_VS_TYPE_OFF;
 	}
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_reg);
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]);
+	saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]);
 
 	return 0;
 }
@@ -2454,7 +2452,7 @@
 	return 0;
 }
 
-void saa7134_irq_video_intl(struct saa7134_dev *dev)
+void saa7134_irq_video_signalchange(struct saa7134_dev *dev)
 {
 	static const char *st[] = {
 		"(no signal)", "NTSC", "PAL", "SECAM" };
@@ -2466,24 +2464,28 @@
 		(st1 & 0x40) ? "not locked" : "locked",
 		(st2 & 0x40) ? "no"         : "yes",
 		st[st1 & 0x03]);
-	dev->nosignal = (st1 & 0x40) || (st2 & 0x40);
+	dev->nosignal = (st1 & 0x40) || (st2 & 0x40)  || !(st2 & 0x1);
 
 	if (dev->nosignal) {
 		/* no video signal -> mute audio */
 		if (dev->ctl_automute)
 			dev->automute = 1;
 		saa7134_tvaudio_setmute(dev);
-		saa_setb(SAA7134_SYNC_CTRL, 0x20);
 	} else {
 		/* wake up tvaudio audio carrier scan thread */
 		saa7134_tvaudio_do_scan(dev);
-		if (!noninterlaced)
-			saa_clearb(SAA7134_SYNC_CTRL, 0x20);
 	}
+
+	if ((st2 & 0x80) && !noninterlaced && !dev->nosignal)
+		saa_clearb(SAA7134_SYNC_CTRL, 0x20);
+	else
+		saa_setb(SAA7134_SYNC_CTRL, 0x20);
+
 	if (dev->mops && dev->mops->signal_change)
 		dev->mops->signal_change(dev);
 }
 
+
 void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
 {
 	enum v4l2_field field;
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 15623b2..28ec680 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -37,12 +37,12 @@
 #include <media/tuner.h>
 #include <media/ir-common.h>
 #include <media/ir-kbd-i2c.h>
-#include <media/video-buf.h>
+#include <media/videobuf-dma-sg.h>
 #include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
-#include <media/video-buf-dvb.h>
+#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
+#include <media/videobuf-dvb.h>
 #endif
 
 #define UNSET (-1U)
@@ -238,6 +238,8 @@
 #define SAA7134_BOARD_ECS_TVP3XP_4CB6  113
 #define SAA7134_BOARD_KWORLD_DVBT_210 114
 #define SAA7134_BOARD_SABRENT_TV_PCB05     115
+#define SAA7134_BOARD_10MOONSTVMASTER3     116
+#define SAA7134_BOARD_AVERMEDIA_SUPER_007  117
 
 #define SAA7134_MAXBOARDS 8
 #define SAA7134_INPUT_MAX 8
@@ -313,7 +315,7 @@
 #define INTERLACE_ON           1
 #define INTERLACE_OFF          2
 
-#define BUFFER_TIMEOUT     (HZ/2)  /* 0.5 seconds */
+#define BUFFER_TIMEOUT     msecs_to_jiffies(500)  /* 0.5 seconds */
 
 struct saa7134_dev;
 struct saa7134_dma;
@@ -327,10 +329,7 @@
 
 /* tvaudio thread status */
 struct saa7134_thread {
-	pid_t                      pid;
-	struct completion          exit;
-	wait_queue_head_t          wq;
-	unsigned int               shutdown;
+	struct task_struct         *thread;
 	unsigned int               scan1;
 	unsigned int               scan2;
 	unsigned int               mode;
@@ -525,6 +524,7 @@
 	unsigned int               hw_mute;
 	int                        last_carrier;
 	int                        nosignal;
+	unsigned int               inresume;
 
 	/* SAA7134_MPEG_* */
 	struct saa7134_ts          ts;
@@ -538,7 +538,7 @@
 	struct work_struct         empress_workqueue;
 	int                        empress_started;
 
-#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
+#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
 	/* SAA7134_MPEG_DVB only */
 	struct videobuf_dvb        dvb;
 	int (*original_demod_sleep)(struct dvb_frontend* fe);
@@ -595,6 +595,9 @@
 void saa7134_buffer_timeout(unsigned long data);
 void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf);
 
+int saa7134_buffer_requeue(struct saa7134_dev *dev,
+			 struct saa7134_dmaqueue *q);
+
 int saa7134_set_dmabits(struct saa7134_dev *dev);
 
 extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
@@ -627,12 +630,16 @@
 extern struct video_device saa7134_video_template;
 extern struct video_device saa7134_radio_template;
 
+void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm);
+int saa7134_videoport_init(struct saa7134_dev *dev);
+void saa7134_set_decoder(struct saa7134_dev *dev);
+
 int saa7134_common_ioctl(struct saa7134_dev *dev,
 			 unsigned int cmd, void *arg);
 
 int saa7134_video_init1(struct saa7134_dev *dev);
 int saa7134_video_init2(struct saa7134_dev *dev);
-void saa7134_irq_video_intl(struct saa7134_dev *dev);
+void saa7134_irq_video_signalchange(struct saa7134_dev *dev);
 void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status);
 
 
@@ -650,6 +657,8 @@
 int saa7134_ts_register(struct saa7134_mpeg_ops *ops);
 void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops);
 
+int saa7134_ts_init_hw(struct saa7134_dev *dev);
+
 /* ----------------------------------------------------------- */
 /* saa7134-vbi.c                                               */
 
@@ -678,6 +687,8 @@
 
 int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value);
 
+void saa7134_enable_i2s(struct saa7134_dev *dev);
+
 /* ----------------------------------------------------------- */
 /* saa7134-oss.c                                               */
 
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
index 339592e..66cc92c 100644
--- a/drivers/media/video/saa7185.c
+++ b/drivers/media/video/saa7185.c
@@ -34,23 +34,23 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/signal.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
-#include <linux/types.h>
+#include <asm/uaccess.h>
 
 #include <linux/videodev.h>
-#include <asm/uaccess.h>
+#include <linux/video_encoder.h>
 
 MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
 MODULE_AUTHOR("Dave Perks");
 MODULE_LICENSE("GPL");
 
-#include <linux/i2c.h>
 
 #define I2C_NAME(s) (s)->name
 
-#include <linux/video_encoder.h>
 
 static int debug = 0;
 module_param(debug, int, 0);
diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c
index 8615a60..b4018cc 100644
--- a/drivers/media/video/saa7191.c
+++ b/drivers/media/video/saa7191.c
@@ -130,7 +130,7 @@
 
 /* the first byte of data must be the first subaddress number (register) */
 static int saa7191_write_block(struct i2c_client *client,
-			       u8 length, u8 *data)
+			       u8 length, const u8 *data)
 {
 	int i;
 	int ret;
@@ -592,7 +592,7 @@
 	if (err)
 		goto out_free_decoder;
 
-	err = saa7191_write_block(client, sizeof(initseq), (u8 *)initseq);
+	err = saa7191_write_block(client, sizeof(initseq), initseq);
 	if (err) {
 		printk(KERN_ERR "SAA7191 initialization failed\n");
 		goto out_detach_client;
diff --git a/drivers/media/video/sn9c102/sn9c102.h b/drivers/media/video/sn9c102/sn9c102.h
index 11fcb49..2e3c3de 100644
--- a/drivers/media/video/sn9c102/sn9c102.h
+++ b/drivers/media/video/sn9c102/sn9c102.h
@@ -36,6 +36,7 @@
 #include <linux/mutex.h>
 #include <linux/string.h>
 #include <linux/stddef.h>
+#include <linux/kref.h>
 
 #include "sn9c102_config.h"
 #include "sn9c102_sensor.h"
@@ -94,7 +95,7 @@
 };
 
 static DEFINE_MUTEX(sn9c102_sysfs_lock);
-static DECLARE_RWSEM(sn9c102_disconnect);
+static DECLARE_RWSEM(sn9c102_dev_lock);
 
 struct sn9c102_device {
 	struct video_device* v4ldev;
@@ -122,12 +123,14 @@
 
 	struct sn9c102_module_param module_param;
 
+	struct kref kref;
 	enum sn9c102_dev_state state;
 	u8 users;
 
-	struct mutex dev_mutex, fileop_mutex;
+	struct completion probe;
+	struct mutex open_mutex, fileop_mutex;
 	spinlock_t queue_lock;
-	wait_queue_head_t open, wait_frame, wait_stream;
+	wait_queue_head_t wait_open, wait_frame, wait_stream;
 };
 
 /*****************************************************************************/
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index 74a204f..6991e06 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -22,7 +22,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
-#include <linux/moduleparam.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/device.h>
@@ -48,8 +47,8 @@
 #define SN9C102_MODULE_AUTHOR   "(C) 2004-2007 Luca Risolia"
 #define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
 #define SN9C102_MODULE_LICENSE  "GPL"
-#define SN9C102_MODULE_VERSION  "1:1.44"
-#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 44)
+#define SN9C102_MODULE_VERSION  "1:1.47"
+#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 47)
 
 /*****************************************************************************/
 
@@ -64,9 +63,10 @@
 static short video_nr[] = {[0 ... SN9C102_MAX_DEVICES-1] = -1};
 module_param_array(video_nr, short, NULL, 0444);
 MODULE_PARM_DESC(video_nr,
-		 "\n<-1|n[,...]> Specify V4L2 minor mode number."
-		 "\n -1 = use next available (default)"
-		 "\n  n = use minor number n (integer >= 0)"
+		 " <-1|n[,...]>"
+		 "\nSpecify V4L2 minor mode number."
+		 "\n-1 = use next available (default)"
+		 "\n n = use minor number n (integer >= 0)"
 		 "\nYou can specify up to "__MODULE_STRING(SN9C102_MAX_DEVICES)
 		 " cameras this way."
 		 "\nFor example:"
@@ -79,13 +79,14 @@
 			       SN9C102_FORCE_MUNMAP};
 module_param_array(force_munmap, bool, NULL, 0444);
 MODULE_PARM_DESC(force_munmap,
-		 "\n<0|1[,...]> Force the application to unmap previously"
+		 " <0|1[,...]>"
+		 "\nForce the application to unmap previously"
 		 "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
 		 "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
 		 "\nthis feature. This parameter is specific for each"
 		 "\ndetected camera."
-		 "\n 0 = do not force memory unmapping"
-		 "\n 1 = force memory unmapping (save memory)"
+		 "\n0 = do not force memory unmapping"
+		 "\n1 = force memory unmapping (save memory)"
 		 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
 		 "\n");
 
@@ -93,7 +94,8 @@
 				       SN9C102_FRAME_TIMEOUT};
 module_param_array(frame_timeout, uint, NULL, 0644);
 MODULE_PARM_DESC(frame_timeout,
-		 "\n<0|n[,...]> Timeout for a video frame in seconds before"
+		 " <0|n[,...]>"
+		 "\nTimeout for a video frame in seconds before"
 		 "\nreturning an I/O error; 0 for infinity."
 		 "\nThis parameter is specific for each detected camera."
 		 "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
@@ -103,7 +105,8 @@
 static unsigned short debug = SN9C102_DEBUG_LEVEL;
 module_param(debug, ushort, 0644);
 MODULE_PARM_DESC(debug,
-		 "\n<n> Debugging information level, from 0 to 3:"
+		 " <n>"
+		 "\nDebugging information level, from 0 to 3:"
 		 "\n0 = none (use carefully)"
 		 "\n1 = critical errors"
 		 "\n2 = significant informations"
@@ -1026,7 +1029,8 @@
    NOTE 2: buffers are PAGE_SIZE long
 */
 
-static ssize_t sn9c102_show_reg(struct class_device* cd, char* buf)
+static ssize_t sn9c102_show_reg(struct device* cd,
+				struct device_attribute *attr, char* buf)
 {
 	struct sn9c102_device* cam;
 	ssize_t count;
@@ -1050,7 +1054,8 @@
 
 
 static ssize_t
-sn9c102_store_reg(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_reg(struct device* cd, struct device_attribute *attr,
+		  const char* buf, size_t len)
 {
 	struct sn9c102_device* cam;
 	u16 index;
@@ -1083,7 +1088,8 @@
 }
 
 
-static ssize_t sn9c102_show_val(struct class_device* cd, char* buf)
+static ssize_t sn9c102_show_val(struct device* cd,
+				struct device_attribute *attr, char* buf)
 {
 	struct sn9c102_device* cam;
 	ssize_t count;
@@ -1115,7 +1121,8 @@
 
 
 static ssize_t
-sn9c102_store_val(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_val(struct device* cd, struct device_attribute *attr,
+		  const char* buf, size_t len)
 {
 	struct sn9c102_device* cam;
 	u16 value;
@@ -1154,7 +1161,8 @@
 }
 
 
-static ssize_t sn9c102_show_i2c_reg(struct class_device* cd, char* buf)
+static ssize_t sn9c102_show_i2c_reg(struct device* cd,
+				    struct device_attribute *attr, char* buf)
 {
 	struct sn9c102_device* cam;
 	ssize_t count;
@@ -1180,7 +1188,8 @@
 
 
 static ssize_t
-sn9c102_store_i2c_reg(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_i2c_reg(struct device* cd, struct device_attribute *attr,
+		      const char* buf, size_t len)
 {
 	struct sn9c102_device* cam;
 	u16 index;
@@ -1213,7 +1222,8 @@
 }
 
 
-static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
+static ssize_t sn9c102_show_i2c_val(struct device* cd,
+				    struct device_attribute *attr, char* buf)
 {
 	struct sn9c102_device* cam;
 	ssize_t count;
@@ -1250,7 +1260,8 @@
 
 
 static ssize_t
-sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_i2c_val(struct device* cd, struct device_attribute *attr,
+		      const char* buf, size_t len)
 {
 	struct sn9c102_device* cam;
 	u16 value;
@@ -1295,7 +1306,8 @@
 
 
 static ssize_t
-sn9c102_store_green(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_green(struct device* cd, struct device_attribute *attr,
+		    const char* buf, size_t len)
 {
 	struct sn9c102_device* cam;
 	enum sn9c102_bridge bridge;
@@ -1326,16 +1338,16 @@
 	case BRIDGE_SN9C102:
 		if (value > 0x0f)
 			return -EINVAL;
-		if ((res = sn9c102_store_reg(cd, "0x11", 4)) >= 0)
-			res = sn9c102_store_val(cd, buf, len);
+		if ((res = sn9c102_store_reg(cd, attr, "0x11", 4)) >= 0)
+			res = sn9c102_store_val(cd, attr, buf, len);
 		break;
 	case BRIDGE_SN9C103:
 	case BRIDGE_SN9C105:
 	case BRIDGE_SN9C120:
 		if (value > 0x7f)
 			return -EINVAL;
-		if ((res = sn9c102_store_reg(cd, "0x07", 4)) >= 0)
-			res = sn9c102_store_val(cd, buf, len);
+		if ((res = sn9c102_store_reg(cd, attr, "0x07", 4)) >= 0)
+			res = sn9c102_store_val(cd, attr, buf, len);
 		break;
 	}
 
@@ -1344,7 +1356,8 @@
 
 
 static ssize_t
-sn9c102_store_blue(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_blue(struct device* cd, struct device_attribute *attr,
+		   const char* buf, size_t len)
 {
 	ssize_t res = 0;
 	u16 value;
@@ -1354,15 +1367,16 @@
 	if (!count || value > 0x7f)
 		return -EINVAL;
 
-	if ((res = sn9c102_store_reg(cd, "0x06", 4)) >= 0)
-		res = sn9c102_store_val(cd, buf, len);
+	if ((res = sn9c102_store_reg(cd, attr, "0x06", 4)) >= 0)
+		res = sn9c102_store_val(cd, attr, buf, len);
 
 	return res;
 }
 
 
 static ssize_t
-sn9c102_store_red(struct class_device* cd, const char* buf, size_t len)
+sn9c102_store_red(struct device* cd, struct device_attribute *attr,
+		  const char* buf, size_t len)
 {
 	ssize_t res = 0;
 	u16 value;
@@ -1372,14 +1386,16 @@
 	if (!count || value > 0x7f)
 		return -EINVAL;
 
-	if ((res = sn9c102_store_reg(cd, "0x05", 4)) >= 0)
-		res = sn9c102_store_val(cd, buf, len);
+	if ((res = sn9c102_store_reg(cd, attr, "0x05", 4)) >= 0)
+		res = sn9c102_store_val(cd, attr, buf, len);
 
 	return res;
 }
 
 
-static ssize_t sn9c102_show_frame_header(struct class_device* cd, char* buf)
+static ssize_t sn9c102_show_frame_header(struct device* cd,
+					 struct device_attribute *attr,
+					 char* buf)
 {
 	struct sn9c102_device* cam;
 	ssize_t count;
@@ -1398,72 +1414,63 @@
 }
 
 
-static CLASS_DEVICE_ATTR(reg, S_IRUGO | S_IWUSR,
-			 sn9c102_show_reg, sn9c102_store_reg);
-static CLASS_DEVICE_ATTR(val, S_IRUGO | S_IWUSR,
-			 sn9c102_show_val, sn9c102_store_val);
-static CLASS_DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
-			 sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);
-static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
-			 sn9c102_show_i2c_val, sn9c102_store_i2c_val);
-static CLASS_DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);
-static CLASS_DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue);
-static CLASS_DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red);
-static CLASS_DEVICE_ATTR(frame_header, S_IRUGO,
-			 sn9c102_show_frame_header, NULL);
+static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, sn9c102_show_reg, sn9c102_store_reg);
+static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, sn9c102_show_val, sn9c102_store_val);
+static DEVICE_ATTR(i2c_reg, S_IRUGO | S_IWUSR,
+		   sn9c102_show_i2c_reg, sn9c102_store_i2c_reg);
+static DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
+		   sn9c102_show_i2c_val, sn9c102_store_i2c_val);
+static DEVICE_ATTR(green, S_IWUGO, NULL, sn9c102_store_green);
+static DEVICE_ATTR(blue, S_IWUGO, NULL, sn9c102_store_blue);
+static DEVICE_ATTR(red, S_IWUGO, NULL, sn9c102_store_red);
+static DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL);
 
 
 static int sn9c102_create_sysfs(struct sn9c102_device* cam)
 {
-	struct class_device *classdev = &(cam->v4ldev->class_dev);
+	struct device *classdev = &(cam->v4ldev->class_dev);
 	int err = 0;
 
-	if ((err = class_device_create_file(classdev, &class_device_attr_reg)))
+	if ((err = device_create_file(classdev, &dev_attr_reg)))
 		goto err_out;
-	if ((err = class_device_create_file(classdev, &class_device_attr_val)))
+	if ((err = device_create_file(classdev, &dev_attr_val)))
 		goto err_reg;
-	if ((err = class_device_create_file(classdev,
-					    &class_device_attr_frame_header)))
+	if ((err = device_create_file(classdev, &dev_attr_frame_header)))
 		goto err_val;
 
 	if (cam->sensor.sysfs_ops) {
-		if ((err = class_device_create_file(classdev,
-						  &class_device_attr_i2c_reg)))
+		if ((err = device_create_file(classdev, &dev_attr_i2c_reg)))
 			goto err_frame_header;
-		if ((err = class_device_create_file(classdev,
-						  &class_device_attr_i2c_val)))
+		if ((err = device_create_file(classdev, &dev_attr_i2c_val)))
 			goto err_i2c_reg;
 	}
 
 	if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
-		if ((err = class_device_create_file(classdev,
-						    &class_device_attr_green)))
+		if ((err = device_create_file(classdev, &dev_attr_green)))
 			goto err_i2c_val;
 	} else {
-		if ((err = class_device_create_file(classdev,
-						    &class_device_attr_blue)))
+		if ((err = device_create_file(classdev, &dev_attr_blue)))
 			goto err_i2c_val;
-		if ((err = class_device_create_file(classdev,
-						    &class_device_attr_red)))
+		if ((err = device_create_file(classdev, &dev_attr_red)))
 			goto err_blue;
 	}
 
 	return 0;
 
 err_blue:
-	class_device_remove_file(classdev, &class_device_attr_blue);
+	device_remove_file(classdev, &dev_attr_blue);
 err_i2c_val:
 	if (cam->sensor.sysfs_ops)
-		class_device_remove_file(classdev, &class_device_attr_i2c_val);
+		device_remove_file(classdev, &dev_attr_i2c_val);
 err_i2c_reg:
 	if (cam->sensor.sysfs_ops)
-		class_device_remove_file(classdev, &class_device_attr_i2c_reg);
+		device_remove_file(classdev, &dev_attr_i2c_reg);
 err_frame_header:
-	class_device_remove_file(classdev, &class_device_attr_frame_header);
+	device_remove_file(classdev, &dev_attr_frame_header);
 err_val:
-	class_device_remove_file(classdev, &class_device_attr_val);
+	device_remove_file(classdev, &dev_attr_val);
 err_reg:
-	class_device_remove_file(classdev, &class_device_attr_reg);
+	device_remove_file(classdev, &dev_attr_reg);
 err_out:
 	return err;
 }
@@ -1616,7 +1623,8 @@
 	int err = 0;
 
 	if (!(cam->state & DEV_INITIALIZED)) {
-		init_waitqueue_head(&cam->open);
+		mutex_init(&cam->open_mutex);
+		init_waitqueue_head(&cam->wait_open);
 		qctrl = s->qctrl;
 		rect = &(s->cropcap.defrect);
 	} else { /* use current values */
@@ -1706,21 +1714,27 @@
 	return 0;
 }
 
+/*****************************************************************************/
 
-static void sn9c102_release_resources(struct sn9c102_device* cam)
+static void sn9c102_release_resources(struct kref *kref)
 {
+	struct sn9c102_device *cam;
+
 	mutex_lock(&sn9c102_sysfs_lock);
 
+	cam = container_of(kref, struct sn9c102_device, kref);
+
 	DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
 	video_set_drvdata(cam->v4ldev, NULL);
 	video_unregister_device(cam->v4ldev);
+	usb_put_dev(cam->usbdev);
+	kfree(cam->control_buffer);
+	kfree(cam);
 
 	mutex_unlock(&sn9c102_sysfs_lock);
 
-	kfree(cam->control_buffer);
 }
 
-/*****************************************************************************/
 
 static int sn9c102_open(struct inode* inode, struct file* filp)
 {
@@ -1728,43 +1742,78 @@
 	int err = 0;
 
 	/*
-	   This is the only safe way to prevent race conditions with
-	   disconnect
+	   A read_trylock() in open() is the only safe way to prevent race
+	   conditions with disconnect(), one close() and multiple (not
+	   necessarily simultaneous) attempts to open(). For example, it
+	   prevents from waiting for a second access, while the device
+	   structure is being deallocated, after a possible disconnect() and
+	   during a following close() holding the write lock: given that, after
+	   this deallocation, no access will be possible anymore, using the
+	   non-trylock version would have let open() gain the access to the
+	   device structure improperly.
+	   For this reason the lock must also not be per-device.
 	*/
-	if (!down_read_trylock(&sn9c102_disconnect))
+	if (!down_read_trylock(&sn9c102_dev_lock))
 		return -ERESTARTSYS;
 
 	cam = video_get_drvdata(video_devdata(filp));
 
-	if (mutex_lock_interruptible(&cam->dev_mutex)) {
-		up_read(&sn9c102_disconnect);
+	if (wait_for_completion_interruptible(&cam->probe)) {
+		up_read(&sn9c102_dev_lock);
 		return -ERESTARTSYS;
 	}
 
+	kref_get(&cam->kref);
+
+	/*
+	    Make sure to isolate all the simultaneous opens.
+	*/
+	if (mutex_lock_interruptible(&cam->open_mutex)) {
+		kref_put(&cam->kref, sn9c102_release_resources);
+		up_read(&sn9c102_dev_lock);
+		return -ERESTARTSYS;
+	}
+
+	if (cam->state & DEV_DISCONNECTED) {
+		DBG(1, "Device not present");
+		err = -ENODEV;
+		goto out;
+	}
+
 	if (cam->users) {
-		DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+		DBG(2, "Device /dev/video%d is already in use",
+		       cam->v4ldev->minor);
 		DBG(3, "Simultaneous opens are not supported");
+		/*
+		   open() must follow the open flags and should block
+		   eventually while the device is in use.
+		*/
 		if ((filp->f_flags & O_NONBLOCK) ||
 		    (filp->f_flags & O_NDELAY)) {
 			err = -EWOULDBLOCK;
 			goto out;
 		}
-		mutex_unlock(&cam->dev_mutex);
-		err = wait_event_interruptible_exclusive(cam->open,
-						  cam->state & DEV_DISCONNECTED
+		DBG(2, "A blocking open() has been requested. Wait for the "
+		       "device to be released...");
+		up_read(&sn9c102_dev_lock);
+		/*
+		   We will not release the "open_mutex" lock, so that only one
+		   process can be in the wait queue below. This way the process
+		   will be sleeping while holding the lock, without loosing its
+		   priority after any wake_up().
+		*/
+		err = wait_event_interruptible_exclusive(cam->wait_open,
+						(cam->state & DEV_DISCONNECTED)
 							 || !cam->users);
-		if (err) {
-			up_read(&sn9c102_disconnect);
-			return err;
-		}
+		down_read(&sn9c102_dev_lock);
+		if (err)
+			goto out;
 		if (cam->state & DEV_DISCONNECTED) {
-			up_read(&sn9c102_disconnect);
-			return -ENODEV;
+			err = -ENODEV;
+			goto out;
 		}
-		mutex_lock(&cam->dev_mutex);
 	}
 
-
 	if (cam->state & DEV_MISCONFIGURED) {
 		err = sn9c102_init(cam);
 		if (err) {
@@ -1789,36 +1838,33 @@
 	DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
 
 out:
-	mutex_unlock(&cam->dev_mutex);
-	up_read(&sn9c102_disconnect);
+	mutex_unlock(&cam->open_mutex);
+	if (err)
+		kref_put(&cam->kref, sn9c102_release_resources);
+
+	up_read(&sn9c102_dev_lock);
 	return err;
 }
 
 
 static int sn9c102_release(struct inode* inode, struct file* filp)
 {
-	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
+	struct sn9c102_device* cam;
 
-	mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+	down_write(&sn9c102_dev_lock);
+
+	cam = video_get_drvdata(video_devdata(filp));
 
 	sn9c102_stop_transfer(cam);
-
 	sn9c102_release_buffers(cam);
-
-	if (cam->state & DEV_DISCONNECTED) {
-		sn9c102_release_resources(cam);
-		usb_put_dev(cam->usbdev);
-		mutex_unlock(&cam->dev_mutex);
-		kfree(cam);
-		return 0;
-	}
-
 	cam->users--;
-	wake_up_interruptible_nr(&cam->open, 1);
+	wake_up_interruptible_nr(&cam->wait_open, 1);
 
 	DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
 
-	mutex_unlock(&cam->dev_mutex);
+	kref_put(&cam->kref, sn9c102_release_resources);
+
+	up_write(&sn9c102_dev_lock);
 
 	return 0;
 }
@@ -2085,7 +2131,6 @@
 
 	vma->vm_ops = &sn9c102_vm_ops;
 	vma->vm_private_data = &cam->frame[i];
-
 	sn9c102_vm_open(vma);
 
 	mutex_unlock(&cam->fileop_mutex);
@@ -3215,8 +3260,6 @@
 		goto fail;
 	}
 
-	mutex_init(&cam->dev_mutex);
-
 	r = sn9c102_read_reg(cam, 0x00);
 	if (r < 0 || (r != 0x10 && r != 0x11 && r != 0x12)) {
 		DBG(1, "Sorry, this is not a SN9C1xx-based camera "
@@ -3282,7 +3325,7 @@
 	cam->v4ldev->release = video_device_release;
 	video_set_drvdata(cam->v4ldev, cam);
 
-	mutex_lock(&cam->dev_mutex);
+	init_completion(&cam->probe);
 
 	err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
 				    video_nr[dev_nr]);
@@ -3292,7 +3335,7 @@
 			DBG(1, "Free /dev/videoX node not found");
 		video_nr[dev_nr] = -1;
 		dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
-		mutex_unlock(&cam->dev_mutex);
+		complete_all(&cam->probe);
 		goto fail;
 	}
 
@@ -3318,8 +3361,10 @@
 #endif
 
 	usb_set_intfdata(intf, cam);
+	kref_init(&cam->kref);
+	usb_get_dev(cam->usbdev);
 
-	mutex_unlock(&cam->dev_mutex);
+	complete_all(&cam->probe);
 
 	return 0;
 
@@ -3336,40 +3381,31 @@
 
 static void sn9c102_usb_disconnect(struct usb_interface* intf)
 {
-	struct sn9c102_device* cam = usb_get_intfdata(intf);
+	struct sn9c102_device* cam;
 
-	if (!cam)
-		return;
+	down_write(&sn9c102_dev_lock);
 
-	down_write(&sn9c102_disconnect);
-
-	mutex_lock(&cam->dev_mutex);
+	cam = usb_get_intfdata(intf);
 
 	DBG(2, "Disconnecting %s...", cam->v4ldev->name);
 
-	wake_up_interruptible_all(&cam->open);
-
 	if (cam->users) {
 		DBG(2, "Device /dev/video%d is open! Deregistration and "
-		       "memory deallocation are deferred on close.",
+		       "memory deallocation are deferred.",
 		    cam->v4ldev->minor);
 		cam->state |= DEV_MISCONFIGURED;
 		sn9c102_stop_transfer(cam);
 		cam->state |= DEV_DISCONNECTED;
 		wake_up_interruptible(&cam->wait_frame);
 		wake_up(&cam->wait_stream);
-		usb_get_dev(cam->usbdev);
-	} else {
+	} else
 		cam->state |= DEV_DISCONNECTED;
-		sn9c102_release_resources(cam);
-	}
 
-	mutex_unlock(&cam->dev_mutex);
+	wake_up_interruptible_all(&cam->wait_open);
 
-	if (!cam->users)
-		kfree(cam);
+	kref_put(&cam->kref, sn9c102_release_resources);
 
-	up_write(&sn9c102_disconnect);
+	up_write(&sn9c102_dev_lock);
 }
 
 
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7630.c b/drivers/media/video/sn9c102/sn9c102_ov7630.c
index e683234..e4856fd 100644
--- a/drivers/media/video/sn9c102/sn9c102_ov7630.c
+++ b/drivers/media/video/sn9c102/sn9c102_ov7630.c
@@ -104,6 +104,145 @@
 		err += sn9c102_i2c_write(cam, 0x74, 0x21);
 		err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
 		break;
+	case BRIDGE_SN9C105:
+	case BRIDGE_SN9C120:
+	err = sn9c102_write_const_regs(cam, {0x40, 0x02}, {0x00, 0x03},
+				       {0x1a, 0x04}, {0x03, 0x10},
+				       {0x0a, 0x14}, {0xe2, 0x17},
+				       {0x0b, 0x18}, {0x00, 0x19},
+				       {0x1d, 0x1a}, {0x10, 0x1b},
+				       {0x02, 0x1c}, {0x03, 0x1d},
+				       {0x0f, 0x1e}, {0x0c, 0x1f},
+				       {0x00, 0x20}, {0x24, 0x21},
+				       {0x3b, 0x22}, {0x47, 0x23},
+				       {0x60, 0x24}, {0x71, 0x25},
+				       {0x80, 0x26}, {0x8f, 0x27},
+				       {0x9d, 0x28}, {0xaa, 0x29},
+				       {0xb8, 0x2a}, {0xc4, 0x2b},
+				       {0xd1, 0x2c}, {0xdd, 0x2d},
+				       {0xe8, 0x2e}, {0xf4, 0x2f},
+				       {0xff, 0x30}, {0x00, 0x3f},
+				       {0xc7, 0x40}, {0x01, 0x41},
+				       {0x44, 0x42}, {0x00, 0x43},
+				       {0x44, 0x44}, {0x00, 0x45},
+				       {0x44, 0x46}, {0x00, 0x47},
+				       {0xc7, 0x48}, {0x01, 0x49},
+				       {0xc7, 0x4a}, {0x01, 0x4b},
+				       {0xc7, 0x4c}, {0x01, 0x4d},
+				       {0x44, 0x4e}, {0x00, 0x4f},
+				       {0x44, 0x50}, {0x00, 0x51},
+				       {0x44, 0x52}, {0x00, 0x53},
+				       {0xc7, 0x54}, {0x01, 0x55},
+				       {0xc7, 0x56}, {0x01, 0x57},
+				       {0xc7, 0x58}, {0x01, 0x59},
+				       {0x44, 0x5a}, {0x00, 0x5b},
+				       {0x44, 0x5c}, {0x00, 0x5d},
+				       {0x44, 0x5e}, {0x00, 0x5f},
+				       {0xc7, 0x60}, {0x01, 0x61},
+				       {0xc7, 0x62}, {0x01, 0x63},
+				       {0xc7, 0x64}, {0x01, 0x65},
+				       {0x44, 0x66}, {0x00, 0x67},
+				       {0x44, 0x68}, {0x00, 0x69},
+				       {0x44, 0x6a}, {0x00, 0x6b},
+				       {0xc7, 0x6c}, {0x01, 0x6d},
+				       {0xc7, 0x6e}, {0x01, 0x6f},
+				       {0xc7, 0x70}, {0x01, 0x71},
+				       {0x44, 0x72}, {0x00, 0x73},
+				       {0x44, 0x74}, {0x00, 0x75},
+				       {0x44, 0x76}, {0x00, 0x77},
+				       {0xc7, 0x78}, {0x01, 0x79},
+				       {0xc7, 0x7a}, {0x01, 0x7b},
+				       {0xc7, 0x7c}, {0x01, 0x7d},
+				       {0x44, 0x7e}, {0x00, 0x7f},
+				       {0x17, 0x84}, {0x00, 0x85},
+				       {0x2e, 0x86}, {0x00, 0x87},
+				       {0x09, 0x88}, {0x00, 0x89},
+				       {0xe8, 0x8a}, {0x0f, 0x8b},
+				       {0xda, 0x8c}, {0x0f, 0x8d},
+				       {0x40, 0x8e}, {0x00, 0x8f},
+				       {0x37, 0x90}, {0x00, 0x91},
+				       {0xcf, 0x92}, {0x0f, 0x93},
+				       {0xfa, 0x94}, {0x0f, 0x95},
+				       {0x00, 0x96}, {0x00, 0x97},
+				       {0x00, 0x98}, {0x66, 0x99},
+				       {0x00, 0x9a}, {0x40, 0x9b},
+				       {0x20, 0x9c}, {0x00, 0x9d},
+				       {0x00, 0x9e}, {0x00, 0x9f},
+				       {0x2d, 0xc0}, {0x2d, 0xc1},
+				       {0x3a, 0xc2}, {0x00, 0xc3},
+				       {0x04, 0xc4}, {0x3f, 0xc5},
+				       {0x00, 0xc6}, {0x00, 0xc7},
+				       {0x50, 0xc8}, {0x3c, 0xc9},
+				       {0x28, 0xca}, {0xd8, 0xcb},
+				       {0x14, 0xcc}, {0xec, 0xcd},
+				       {0x32, 0xce}, {0xdd, 0xcf},
+				       {0x32, 0xd0}, {0xdd, 0xd1},
+				       {0x6a, 0xd2}, {0x50, 0xd3},
+				       {0x60, 0xd4}, {0x00, 0xd5},
+				       {0x00, 0xd6});
+
+		err += sn9c102_i2c_write(cam, 0x12, 0x80);
+		err += sn9c102_i2c_write(cam, 0x12, 0x48);
+		err += sn9c102_i2c_write(cam, 0x01, 0x80);
+		err += sn9c102_i2c_write(cam, 0x02, 0x80);
+		err += sn9c102_i2c_write(cam, 0x03, 0x80);
+		err += sn9c102_i2c_write(cam, 0x04, 0x10);
+		err += sn9c102_i2c_write(cam, 0x05, 0x20);
+		err += sn9c102_i2c_write(cam, 0x06, 0x80);
+		err += sn9c102_i2c_write(cam, 0x11, 0x00);
+		err += sn9c102_i2c_write(cam, 0x0c, 0x20);
+		err += sn9c102_i2c_write(cam, 0x0d, 0x20);
+		err += sn9c102_i2c_write(cam, 0x15, 0x80);
+		err += sn9c102_i2c_write(cam, 0x16, 0x03);
+		err += sn9c102_i2c_write(cam, 0x17, 0x1b);
+		err += sn9c102_i2c_write(cam, 0x18, 0xbd);
+		err += sn9c102_i2c_write(cam, 0x19, 0x05);
+		err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
+		err += sn9c102_i2c_write(cam, 0x1b, 0x04);
+		err += sn9c102_i2c_write(cam, 0x21, 0x1b);
+		err += sn9c102_i2c_write(cam, 0x22, 0x00);
+		err += sn9c102_i2c_write(cam, 0x23, 0xde);
+		err += sn9c102_i2c_write(cam, 0x24, 0x10);
+		err += sn9c102_i2c_write(cam, 0x25, 0x8a);
+		err += sn9c102_i2c_write(cam, 0x26, 0xa0);
+		err += sn9c102_i2c_write(cam, 0x27, 0xca);
+		err += sn9c102_i2c_write(cam, 0x28, 0xa2);
+		err += sn9c102_i2c_write(cam, 0x29, 0x74);
+		err += sn9c102_i2c_write(cam, 0x2a, 0x88);
+		err += sn9c102_i2c_write(cam, 0x2b, 0x34);
+		err += sn9c102_i2c_write(cam, 0x2c, 0x88);
+		err += sn9c102_i2c_write(cam, 0x2e, 0x00);
+		err += sn9c102_i2c_write(cam, 0x2f, 0x00);
+		err += sn9c102_i2c_write(cam, 0x30, 0x00);
+		err += sn9c102_i2c_write(cam, 0x32, 0xc2);
+		err += sn9c102_i2c_write(cam, 0x33, 0x08);
+		err += sn9c102_i2c_write(cam, 0x4c, 0x40);
+		err += sn9c102_i2c_write(cam, 0x4d, 0xf3);
+		err += sn9c102_i2c_write(cam, 0x60, 0x05);
+		err += sn9c102_i2c_write(cam, 0x61, 0x40);
+		err += sn9c102_i2c_write(cam, 0x62, 0x12);
+		err += sn9c102_i2c_write(cam, 0x63, 0x57);
+		err += sn9c102_i2c_write(cam, 0x64, 0x73);
+		err += sn9c102_i2c_write(cam, 0x65, 0x00);
+		err += sn9c102_i2c_write(cam, 0x66, 0x55);
+		err += sn9c102_i2c_write(cam, 0x67, 0x01);
+		err += sn9c102_i2c_write(cam, 0x68, 0xac);
+		err += sn9c102_i2c_write(cam, 0x69, 0x38);
+		err += sn9c102_i2c_write(cam, 0x6f, 0x1f);
+		err += sn9c102_i2c_write(cam, 0x70, 0x01);
+		err += sn9c102_i2c_write(cam, 0x71, 0x00);
+		err += sn9c102_i2c_write(cam, 0x72, 0x10);
+		err += sn9c102_i2c_write(cam, 0x73, 0x50);
+		err += sn9c102_i2c_write(cam, 0x74, 0x20);
+		err += sn9c102_i2c_write(cam, 0x76, 0x01);
+		err += sn9c102_i2c_write(cam, 0x77, 0xf3);
+		err += sn9c102_i2c_write(cam, 0x78, 0x90);
+		err += sn9c102_i2c_write(cam, 0x79, 0x98);
+		err += sn9c102_i2c_write(cam, 0x7a, 0x98);
+		err += sn9c102_i2c_write(cam, 0x7b, 0x00);
+		err += sn9c102_i2c_write(cam, 0x7c, 0x38);
+		err += sn9c102_i2c_write(cam, 0x7d, 0xff);
+		break;
 	default:
 		break;
 	}
@@ -115,6 +254,7 @@
 static int ov7630_get_ctrl(struct sn9c102_device* cam,
 			   struct v4l2_control* ctrl)
 {
+	enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
 	int err = 0;
 
 	switch (ctrl->id) {
@@ -123,13 +263,20 @@
 			return -EIO;
 		break;
 	case V4L2_CID_RED_BALANCE:
-		ctrl->value = sn9c102_pread_reg(cam, 0x07);
+		if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+			ctrl->value = sn9c102_pread_reg(cam, 0x05);
+		else
+			ctrl->value = sn9c102_pread_reg(cam, 0x07);
 		break;
 	case V4L2_CID_BLUE_BALANCE:
 		ctrl->value = sn9c102_pread_reg(cam, 0x06);
 		break;
 	case SN9C102_V4L2_CID_GREEN_BALANCE:
-		ctrl->value = sn9c102_pread_reg(cam, 0x05);
+		if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+			ctrl->value = sn9c102_pread_reg(cam, 0x07);
+		else
+			ctrl->value = sn9c102_pread_reg(cam, 0x05);
+		break;
 		break;
 	case V4L2_CID_GAIN:
 		if ((ctrl->value = sn9c102_i2c_read(cam, 0x00)) < 0)
@@ -177,6 +324,7 @@
 static int ov7630_set_ctrl(struct sn9c102_device* cam,
 			   const struct v4l2_control* ctrl)
 {
+	enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
 	int err = 0;
 
 	switch (ctrl->id) {
@@ -184,13 +332,19 @@
 		err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
 		break;
 	case V4L2_CID_RED_BALANCE:
-		err += sn9c102_write_reg(cam, ctrl->value, 0x07);
+		if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+			err += sn9c102_write_reg(cam, ctrl->value, 0x05);
+		else
+			err += sn9c102_write_reg(cam, ctrl->value, 0x07);
 		break;
 	case V4L2_CID_BLUE_BALANCE:
 		err += sn9c102_write_reg(cam, ctrl->value, 0x06);
 		break;
 	case SN9C102_V4L2_CID_GREEN_BALANCE:
-		err += sn9c102_write_reg(cam, ctrl->value, 0x05);
+		if (bridge == BRIDGE_SN9C105 || bridge == BRIDGE_SN9C120)
+			err += sn9c102_write_reg(cam, ctrl->value, 0x07);
+		else
+			err += sn9c102_write_reg(cam, ctrl->value, 0x05);
 		break;
 	case V4L2_CID_GAIN:
 		err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
@@ -227,8 +381,21 @@
 {
 	struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
 	int err = 0;
-	u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
-	   v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+	u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+
+	switch (sn9c102_get_bridge(cam)) {
+	case BRIDGE_SN9C101:
+	case BRIDGE_SN9C102:
+	case BRIDGE_SN9C103:
+		h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1;
+		break;
+	case BRIDGE_SN9C105:
+	case BRIDGE_SN9C120:
+		h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4;
+		break;
+	default:
+		break;
+	}
 
 	err += sn9c102_write_reg(cam, h_start, 0x12);
 	err += sn9c102_write_reg(cam, v_start, 0x13);
@@ -242,10 +409,28 @@
 {
 	int err = 0;
 
-	if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
-		err += sn9c102_write_reg(cam, 0x20, 0x19);
-	else
-		err += sn9c102_write_reg(cam, 0x50, 0x19);
+	switch (sn9c102_get_bridge(cam)) {
+	case BRIDGE_SN9C101:
+	case BRIDGE_SN9C102:
+	case BRIDGE_SN9C103:
+		if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8)
+			err += sn9c102_write_reg(cam, 0x50, 0x19);
+		else
+			err += sn9c102_write_reg(cam, 0x20, 0x19);
+		break;
+	case BRIDGE_SN9C105:
+	case BRIDGE_SN9C120:
+		if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
+			err += sn9c102_write_reg(cam, 0xe5, 0x17);
+			err += sn9c102_i2c_write(cam, 0x11, 0x04);
+		} else {
+			err += sn9c102_write_reg(cam, 0xe2, 0x17);
+			err += sn9c102_i2c_write(cam, 0x11, 0x02);
+		}
+		break;
+	default:
+		break;
+	}
 
 	return err;
 }
@@ -254,7 +439,8 @@
 static const struct sn9c102_sensor ov7630 = {
 	.name = "OV7630",
 	.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
-	.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103,
+	.supported_bridge = BRIDGE_SN9C101 | BRIDGE_SN9C102 | BRIDGE_SN9C103 |
+			    BRIDGE_SN9C105 | BRIDGE_SN9C120,
 	.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
 	.frequency = SN9C102_I2C_100KHZ,
 	.interface = SN9C102_I2C_2WIRES,
@@ -417,6 +603,12 @@
 			err += sn9c102_write_const_regs(cam, {0x01, 0x01},
 							{0x00, 0x01});
 		break;
+	case BRIDGE_SN9C105:
+	case BRIDGE_SN9C120:
+		err = sn9c102_write_const_regs(cam, {0x01, 0xf1}, {0x00, 0xf1},
+					       {0x29, 0x01}, {0x74, 0x02},
+					       {0x0e, 0x01}, {0x44, 0x01});
+		break;
 	default:
 		break;
 	}
diff --git a/drivers/media/video/sn9c102/sn9c102_ov7660.c b/drivers/media/video/sn9c102/sn9c102_ov7660.c
index 4b64740..8aae416 100644
--- a/drivers/media/video/sn9c102/sn9c102_ov7660.c
+++ b/drivers/media/video/sn9c102/sn9c102_ov7660.c
@@ -41,65 +41,65 @@
 				       {0xbb, 0x2a}, {0xc7, 0x2b},
 				       {0xd3, 0x2c}, {0xde, 0x2d},
 				       {0xea, 0x2e}, {0xf4, 0x2f},
-				       {0xff, 0x30}, {0x00, 0x3F},
-				       {0xC7, 0x40}, {0x01, 0x41},
+				       {0xff, 0x30}, {0x00, 0x3f},
+				       {0xc7, 0x40}, {0x01, 0x41},
 				       {0x44, 0x42}, {0x00, 0x43},
 				       {0x44, 0x44}, {0x00, 0x45},
 				       {0x44, 0x46}, {0x00, 0x47},
-				       {0xC7, 0x48}, {0x01, 0x49},
-				       {0xC7, 0x4A}, {0x01, 0x4B},
-				       {0xC7, 0x4C}, {0x01, 0x4D},
-				       {0x44, 0x4E}, {0x00, 0x4F},
+				       {0xc7, 0x48}, {0x01, 0x49},
+				       {0xc7, 0x4a}, {0x01, 0x4b},
+				       {0xc7, 0x4c}, {0x01, 0x4d},
+				       {0x44, 0x4e}, {0x00, 0x4f},
 				       {0x44, 0x50}, {0x00, 0x51},
 				       {0x44, 0x52}, {0x00, 0x53},
-				       {0xC7, 0x54}, {0x01, 0x55},
-				       {0xC7, 0x56}, {0x01, 0x57},
-				       {0xC7, 0x58}, {0x01, 0x59},
-				       {0x44, 0x5A}, {0x00, 0x5B},
-				       {0x44, 0x5C}, {0x00, 0x5D},
-				       {0x44, 0x5E}, {0x00, 0x5F},
-				       {0xC7, 0x60}, {0x01, 0x61},
-				       {0xC7, 0x62}, {0x01, 0x63},
-				       {0xC7, 0x64}, {0x01, 0x65},
+				       {0xc7, 0x54}, {0x01, 0x55},
+				       {0xc7, 0x56}, {0x01, 0x57},
+				       {0xc7, 0x58}, {0x01, 0x59},
+				       {0x44, 0x5a}, {0x00, 0x5b},
+				       {0x44, 0x5c}, {0x00, 0x5d},
+				       {0x44, 0x5e}, {0x00, 0x5f},
+				       {0xc7, 0x60}, {0x01, 0x61},
+				       {0xc7, 0x62}, {0x01, 0x63},
+				       {0xc7, 0x64}, {0x01, 0x65},
 				       {0x44, 0x66}, {0x00, 0x67},
 				       {0x44, 0x68}, {0x00, 0x69},
-				       {0x44, 0x6A}, {0x00, 0x6B},
-				       {0xC7, 0x6C}, {0x01, 0x6D},
-				       {0xC7, 0x6E}, {0x01, 0x6F},
-				       {0xC7, 0x70}, {0x01, 0x71},
+				       {0x44, 0x6a}, {0x00, 0x6b},
+				       {0xc7, 0x6c}, {0x01, 0x6d},
+				       {0xc7, 0x6e}, {0x01, 0x6f},
+				       {0xc7, 0x70}, {0x01, 0x71},
 				       {0x44, 0x72}, {0x00, 0x73},
 				       {0x44, 0x74}, {0x00, 0x75},
 				       {0x44, 0x76}, {0x00, 0x77},
-				       {0xC7, 0x78}, {0x01, 0x79},
-				       {0xC7, 0x7A}, {0x01, 0x7B},
-				       {0xC7, 0x7C}, {0x01, 0x7D},
-				       {0x44, 0x7E}, {0x00, 0x7F},
+				       {0xc7, 0x78}, {0x01, 0x79},
+				       {0xc7, 0x7a}, {0x01, 0x7b},
+				       {0xc7, 0x7c}, {0x01, 0x7d},
+				       {0x44, 0x7e}, {0x00, 0x7f},
 				       {0x14, 0x84}, {0x00, 0x85},
 				       {0x27, 0x86}, {0x00, 0x87},
 				       {0x07, 0x88}, {0x00, 0x89},
-				       {0xEC, 0x8A}, {0x0f, 0x8B},
-				       {0xD8, 0x8C}, {0x0f, 0x8D},
-				       {0x3D, 0x8E}, {0x00, 0x8F},
-				       {0x3D, 0x90}, {0x00, 0x91},
-				       {0xCD, 0x92}, {0x0f, 0x93},
+				       {0xec, 0x8a}, {0x0f, 0x8b},
+				       {0xd8, 0x8c}, {0x0f, 0x8d},
+				       {0x3d, 0x8e}, {0x00, 0x8f},
+				       {0x3d, 0x90}, {0x00, 0x91},
+				       {0xcd, 0x92}, {0x0f, 0x93},
 				       {0xf7, 0x94}, {0x0f, 0x95},
-				       {0x0C, 0x96}, {0x00, 0x97},
+				       {0x0c, 0x96}, {0x00, 0x97},
 				       {0x00, 0x98}, {0x66, 0x99},
-				       {0x05, 0x9A}, {0x00, 0x9B},
-				       {0x04, 0x9C}, {0x00, 0x9D},
-				       {0x08, 0x9E}, {0x00, 0x9F},
-				       {0x2D, 0xC0}, {0x2D, 0xC1},
-				       {0x3A, 0xC2}, {0x05, 0xC3},
-				       {0x04, 0xC4}, {0x3F, 0xC5},
-				       {0x00, 0xC6}, {0x00, 0xC7},
-				       {0x50, 0xC8}, {0x3C, 0xC9},
-				       {0x28, 0xCA}, {0xD8, 0xCB},
-				       {0x14, 0xCC}, {0xEC, 0xCD},
-				       {0x32, 0xCE}, {0xDD, 0xCF},
-				       {0x32, 0xD0}, {0xDD, 0xD1},
-				       {0x6A, 0xD2}, {0x50, 0xD3},
-				       {0x00, 0xD4}, {0x00, 0xD5},
-				       {0x00, 0xD6});
+				       {0x05, 0x9a}, {0x00, 0x9b},
+				       {0x04, 0x9c}, {0x00, 0x9d},
+				       {0x08, 0x9e}, {0x00, 0x9f},
+				       {0x2d, 0xc0}, {0x2d, 0xc1},
+				       {0x3a, 0xc2}, {0x05, 0xc3},
+				       {0x04, 0xc4}, {0x3f, 0xc5},
+				       {0x00, 0xc6}, {0x00, 0xc7},
+				       {0x50, 0xc8}, {0x3C, 0xc9},
+				       {0x28, 0xca}, {0xd8, 0xcb},
+				       {0x14, 0xcc}, {0xec, 0xcd},
+				       {0x32, 0xce}, {0xdd, 0xcf},
+				       {0x32, 0xd0}, {0xdd, 0xd1},
+				       {0x6a, 0xd2}, {0x50, 0xd3},
+				       {0x00, 0xd4}, {0x00, 0xd5},
+				       {0x00, 0xd6});
 
 	err += sn9c102_i2c_write(cam, 0x12, 0x80);
 	err += sn9c102_i2c_write(cam, 0x11, 0x09);
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
index 3e736be..eb22046 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -1321,7 +1321,7 @@
 			u32 format;
 			if (copy_from_user(&p, arg, sizeof(p)))
 				return -EFAULT;
-			if (p.palette < sizeof(palette2fmt) / sizeof(u32)) {
+			if (p.palette < ARRAY_SIZE(palette2fmt)) {
 				format = palette2fmt[p.palette];
 				saa->win.color_fmt = format;
 				saawrite(format | 0x60,
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index bf3aa8d..9e009a7 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -499,13 +499,14 @@
  *  sysfs
  ***************************************************************************/
 #define stv680_file(name, variable, field)				\
-static ssize_t show_##name(struct class_device *class_dev, char *buf)	\
+static ssize_t show_##name(struct device *class_dev,			\
+			   struct device_attribute *attr, char *buf)	\
 {									\
 	struct video_device *vdev = to_video_device(class_dev);		\
 	struct usb_stv *stv = video_get_drvdata(vdev);			\
 	return sprintf(buf, field, stv->variable);			\
 }									\
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
 
 stv680_file(model, camera_name, "%s\n");
 stv680_file(in_use, user, "%d\n");
@@ -520,53 +521,53 @@
 {
 	int rc;
 
-	rc = video_device_create_file(vdev, &class_device_attr_model);
+	rc = video_device_create_file(vdev, &dev_attr_model);
 	if (rc) goto err;
-	rc = video_device_create_file(vdev, &class_device_attr_in_use);
+	rc = video_device_create_file(vdev, &dev_attr_in_use);
 	if (rc) goto err_model;
-	rc = video_device_create_file(vdev, &class_device_attr_streaming);
+	rc = video_device_create_file(vdev, &dev_attr_streaming);
 	if (rc) goto err_inuse;
-	rc = video_device_create_file(vdev, &class_device_attr_palette);
+	rc = video_device_create_file(vdev, &dev_attr_palette);
 	if (rc) goto err_stream;
-	rc = video_device_create_file(vdev, &class_device_attr_frames_total);
+	rc = video_device_create_file(vdev, &dev_attr_frames_total);
 	if (rc) goto err_pal;
-	rc = video_device_create_file(vdev, &class_device_attr_frames_read);
+	rc = video_device_create_file(vdev, &dev_attr_frames_read);
 	if (rc) goto err_framtot;
-	rc = video_device_create_file(vdev, &class_device_attr_packets_dropped);
+	rc = video_device_create_file(vdev, &dev_attr_packets_dropped);
 	if (rc) goto err_framread;
-	rc = video_device_create_file(vdev, &class_device_attr_decoding_errors);
+	rc = video_device_create_file(vdev, &dev_attr_decoding_errors);
 	if (rc) goto err_dropped;
 
 	return 0;
 
 err_dropped:
-	video_device_remove_file(vdev, &class_device_attr_packets_dropped);
+	video_device_remove_file(vdev, &dev_attr_packets_dropped);
 err_framread:
-	video_device_remove_file(vdev, &class_device_attr_frames_read);
+	video_device_remove_file(vdev, &dev_attr_frames_read);
 err_framtot:
-	video_device_remove_file(vdev, &class_device_attr_frames_total);
+	video_device_remove_file(vdev, &dev_attr_frames_total);
 err_pal:
-	video_device_remove_file(vdev, &class_device_attr_palette);
+	video_device_remove_file(vdev, &dev_attr_palette);
 err_stream:
-	video_device_remove_file(vdev, &class_device_attr_streaming);
+	video_device_remove_file(vdev, &dev_attr_streaming);
 err_inuse:
-	video_device_remove_file(vdev, &class_device_attr_in_use);
+	video_device_remove_file(vdev, &dev_attr_in_use);
 err_model:
-	video_device_remove_file(vdev, &class_device_attr_model);
+	video_device_remove_file(vdev, &dev_attr_model);
 err:
 	return rc;
 }
 
 static void stv680_remove_sysfs_files(struct video_device *vdev)
 {
-	video_device_remove_file(vdev, &class_device_attr_model);
-	video_device_remove_file(vdev, &class_device_attr_in_use);
-	video_device_remove_file(vdev, &class_device_attr_streaming);
-	video_device_remove_file(vdev, &class_device_attr_palette);
-	video_device_remove_file(vdev, &class_device_attr_frames_total);
-	video_device_remove_file(vdev, &class_device_attr_frames_read);
-	video_device_remove_file(vdev, &class_device_attr_packets_dropped);
-	video_device_remove_file(vdev, &class_device_attr_decoding_errors);
+	video_device_remove_file(vdev, &dev_attr_model);
+	video_device_remove_file(vdev, &dev_attr_in_use);
+	video_device_remove_file(vdev, &dev_attr_streaming);
+	video_device_remove_file(vdev, &dev_attr_palette);
+	video_device_remove_file(vdev, &dev_attr_frames_total);
+	video_device_remove_file(vdev, &dev_attr_frames_read);
+	video_device_remove_file(vdev, &dev_attr_packets_dropped);
+	video_device_remove_file(vdev, &dev_attr_decoding_errors);
 }
 
 /********************************************************************
@@ -715,8 +716,11 @@
 				   stv680_video_irq, stv680);
 		stv680->urb[i] = urb;
 		err = usb_submit_urb (stv680->urb[i], GFP_KERNEL);
-		if (err)
-			PDEBUG (0, "STV(e): urb burned down in start stream");
+		if (err) {
+			PDEBUG (0, "STV(e): urb burned down with err "
+				   "%d in start stream %d", err, i);
+			goto nomem_err;
+		}
 	}			/* i STV680_NUMSBUF */
 
 	stv680->framecount = 0;
diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c
new file mode 100644
index 0000000..41cd6a0
--- /dev/null
+++ b/drivers/media/video/tcm825x.c
@@ -0,0 +1,928 @@
+/*
+ * drivers/media/video/tcm825x.c
+ *
+ * TCM825X camera sensor driver.
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * Based on code from David Cohen <david.cohen@indt.org.br>
+ *
+ * This driver was based on ov9640 sensor driver from MontaVista
+ *
+ * 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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/i2c.h>
+#include <media/v4l2-int-device.h>
+
+#include "tcm825x.h"
+
+/*
+ * The sensor has two fps modes: the lower one just gives half the fps
+ * at the same xclk than the high one.
+ */
+#define MAX_FPS 30
+#define MIN_FPS 8
+#define MAX_HALF_FPS (MAX_FPS / 2)
+#define HIGH_FPS_MODE_LOWER_LIMIT 14
+#define DEFAULT_FPS MAX_HALF_FPS
+
+struct tcm825x_sensor {
+	const struct tcm825x_platform_data *platform_data;
+	struct v4l2_int_device *v4l2_int_device;
+	struct i2c_client *i2c_client;
+	struct v4l2_pix_format pix;
+	struct v4l2_fract timeperframe;
+};
+
+/* list of image formats supported by TCM825X sensor */
+const static struct v4l2_fmtdesc tcm825x_formats[] = {
+	{
+		.description = "YUYV (YUV 4:2:2), packed",
+		.pixelformat = V4L2_PIX_FMT_UYVY,
+	}, {
+		/* Note:  V4L2 defines RGB565 as:
+		 *
+		 *      Byte 0                    Byte 1
+		 *      g2 g1 g0 r4 r3 r2 r1 r0   b4 b3 b2 b1 b0 g5 g4 g3
+		 *
+		 * We interpret RGB565 as:
+		 *
+		 *      Byte 0                    Byte 1
+		 *      g2 g1 g0 b4 b3 b2 b1 b0   r4 r3 r2 r1 r0 g5 g4 g3
+		 */
+		.description = "RGB565, le",
+		.pixelformat = V4L2_PIX_FMT_RGB565,
+	},
+};
+
+#define TCM825X_NUM_CAPTURE_FORMATS	ARRAY_SIZE(tcm825x_formats)
+
+/*
+ * TCM825X register configuration for all combinations of pixel format and
+ * image size
+ */
+const static struct tcm825x_reg subqcif	=	{ 0x20, TCM825X_PICSIZ };
+const static struct tcm825x_reg qcif	=	{ 0x18, TCM825X_PICSIZ };
+const static struct tcm825x_reg cif	=	{ 0x14, TCM825X_PICSIZ };
+const static struct tcm825x_reg qqvga	=	{ 0x0c, TCM825X_PICSIZ };
+const static struct tcm825x_reg qvga	=	{ 0x04, TCM825X_PICSIZ };
+const static struct tcm825x_reg vga	=	{ 0x00, TCM825X_PICSIZ };
+
+const static struct tcm825x_reg yuv422	=	{ 0x00, TCM825X_PICFMT };
+const static struct tcm825x_reg rgb565	=	{ 0x02, TCM825X_PICFMT };
+
+/* Our own specific controls */
+#define V4L2_CID_ALC				V4L2_CID_PRIVATE_BASE
+#define V4L2_CID_H_EDGE_EN			V4L2_CID_PRIVATE_BASE + 1
+#define V4L2_CID_V_EDGE_EN			V4L2_CID_PRIVATE_BASE + 2
+#define V4L2_CID_LENS				V4L2_CID_PRIVATE_BASE + 3
+#define V4L2_CID_MAX_EXPOSURE_TIME		V4L2_CID_PRIVATE_BASE + 4
+#define V4L2_CID_LAST_PRIV			V4L2_CID_MAX_EXPOSURE_TIME
+
+/*  Video controls  */
+static struct vcontrol {
+	struct v4l2_queryctrl qc;
+	u16 reg;
+	u16 start_bit;
+} video_control[] = {
+	{
+		{
+			.id = V4L2_CID_GAIN,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Gain",
+			.minimum = 0,
+			.maximum = 63,
+			.step = 1,
+		},
+		.reg = TCM825X_AG,
+		.start_bit = 0,
+	},
+	{
+		{
+			.id = V4L2_CID_RED_BALANCE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Red Balance",
+			.minimum = 0,
+			.maximum = 255,
+			.step = 1,
+		},
+		.reg = TCM825X_MRG,
+		.start_bit = 0,
+	},
+	{
+		{
+			.id = V4L2_CID_BLUE_BALANCE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Blue Balance",
+			.minimum = 0,
+			.maximum = 255,
+			.step = 1,
+		},
+		.reg = TCM825X_MBG,
+		.start_bit = 0,
+	},
+	{
+		{
+			.id = V4L2_CID_AUTO_WHITE_BALANCE,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+			.name = "Auto White Balance",
+			.minimum = 0,
+			.maximum = 1,
+			.step = 0,
+		},
+		.reg = TCM825X_AWBSW,
+		.start_bit = 7,
+	},
+	{
+		{
+			.id = V4L2_CID_EXPOSURE,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Exposure Time",
+			.minimum = 0,
+			.maximum = 0x1fff,
+			.step = 1,
+		},
+		.reg = TCM825X_ESRSPD_U,
+		.start_bit = 0,
+	},
+	{
+		{
+			.id = V4L2_CID_HFLIP,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+			.name = "Mirror Image",
+			.minimum = 0,
+			.maximum = 1,
+			.step = 0,
+		},
+		.reg = TCM825X_H_INV,
+		.start_bit = 6,
+	},
+	{
+		{
+			.id = V4L2_CID_VFLIP,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+			.name = "Vertical Flip",
+			.minimum = 0,
+			.maximum = 1,
+			.step = 0,
+		},
+		.reg = TCM825X_V_INV,
+		.start_bit = 7,
+	},
+	/* Private controls */
+	{
+		{
+			.id = V4L2_CID_ALC,
+			.type = V4L2_CTRL_TYPE_BOOLEAN,
+			.name = "Auto Luminance Control",
+			.minimum = 0,
+			.maximum = 1,
+			.step = 0,
+		},
+		.reg = TCM825X_ALCSW,
+		.start_bit = 7,
+	},
+	{
+		{
+			.id = V4L2_CID_H_EDGE_EN,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Horizontal Edge Enhancement",
+			.minimum = 0,
+			.maximum = 0xff,
+			.step = 1,
+		},
+		.reg = TCM825X_HDTG,
+		.start_bit = 0,
+	},
+	{
+		{
+			.id = V4L2_CID_V_EDGE_EN,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Vertical Edge Enhancement",
+			.minimum = 0,
+			.maximum = 0xff,
+			.step = 1,
+		},
+		.reg = TCM825X_VDTG,
+		.start_bit = 0,
+	},
+	{
+		{
+			.id = V4L2_CID_LENS,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Lens Shading Compensation",
+			.minimum = 0,
+			.maximum = 0x3f,
+			.step = 1,
+		},
+		.reg = TCM825X_LENS,
+		.start_bit = 0,
+	},
+	{
+		{
+			.id = V4L2_CID_MAX_EXPOSURE_TIME,
+			.type = V4L2_CTRL_TYPE_INTEGER,
+			.name = "Maximum Exposure Time",
+			.minimum = 0,
+			.maximum = 0x3,
+			.step = 1,
+		},
+		.reg = TCM825X_ESRLIM,
+		.start_bit = 5,
+	},
+};
+
+
+const static struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] =
+{ &subqcif, &qqvga, &qcif, &qvga, &cif, &vga };
+
+const static struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] =
+{ &yuv422, &rgb565 };
+
+/*
+ * Read a value from a register in an TCM825X sensor device.  The value is
+ * returned in 'val'.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tcm825x_read_reg(struct i2c_client *client, int reg)
+{
+	int err;
+	struct i2c_msg msg[2];
+	u8 reg_buf, data_buf = 0;
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	msg[0].addr = client->addr;
+	msg[0].flags = 0;
+	msg[0].len = 1;
+	msg[0].buf = &reg_buf;
+	msg[1].addr = client->addr;
+	msg[1].flags = I2C_M_RD;
+	msg[1].len = 1;
+	msg[1].buf = &data_buf;
+
+	reg_buf = reg;
+
+	err = i2c_transfer(client->adapter, msg, 2);
+	if (err < 0)
+		return err;
+	return data_buf;
+}
+
+/*
+ * Write a value to a register in an TCM825X sensor device.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tcm825x_write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+	int err;
+	struct i2c_msg msg[1];
+	unsigned char data[2];
+
+	if (!client->adapter)
+		return -ENODEV;
+
+	msg->addr = client->addr;
+	msg->flags = 0;
+	msg->len = 2;
+	msg->buf = data;
+	data[0] = reg;
+	data[1] = val;
+	err = i2c_transfer(client->adapter, msg, 1);
+	if (err >= 0)
+		return 0;
+	return err;
+}
+
+static int __tcm825x_write_reg_mask(struct i2c_client *client,
+				    u8 reg, u8 val, u8 mask)
+{
+	int rc;
+
+	/* need to do read - modify - write */
+	rc = tcm825x_read_reg(client, reg);
+	if (rc < 0)
+		return rc;
+
+	rc &= (~mask);	/* Clear the masked bits */
+	val &= mask;	/* Enforce mask on value */
+	val |= rc;
+
+	/* write the new value to the register */
+	rc = tcm825x_write_reg(client, reg, val);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+#define tcm825x_write_reg_mask(client, regmask, val)			\
+	__tcm825x_write_reg_mask(client, TCM825X_ADDR((regmask)), val,	\
+				 TCM825X_MASK((regmask)))
+
+
+/*
+ * Initialize a list of TCM825X registers.
+ * The list of registers is terminated by the pair of values
+ * { TCM825X_REG_TERM, TCM825X_VAL_TERM }.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+static int tcm825x_write_default_regs(struct i2c_client *client,
+				      const struct tcm825x_reg *reglist)
+{
+	int err;
+	const struct tcm825x_reg *next = reglist;
+
+	while (!((next->reg == TCM825X_REG_TERM)
+		 && (next->val == TCM825X_VAL_TERM))) {
+		err = tcm825x_write_reg(client, next->reg, next->val);
+		if (err) {
+			dev_err(&client->dev, "register writing failed\n");
+			return err;
+		}
+		next++;
+	}
+
+	return 0;
+}
+
+static struct vcontrol *find_vctrl(int id)
+{
+	int i;
+
+	if (id < V4L2_CID_BASE)
+		return NULL;
+
+	for (i = 0; i < ARRAY_SIZE(video_control); i++)
+		if (video_control[i].qc.id == id)
+			return &video_control[i];
+
+	return NULL;
+}
+
+/*
+ * Find the best match for a requested image capture size.  The best match
+ * is chosen as the nearest match that has the same number or fewer pixels
+ * as the requested size, or the smallest image size if the requested size
+ * has fewer pixels than the smallest image.
+ */
+static enum image_size tcm825x_find_size(struct v4l2_int_device *s,
+					 unsigned int width,
+					 unsigned int height)
+{
+	enum image_size isize;
+	unsigned long pixels = width * height;
+	struct tcm825x_sensor *sensor = s->priv;
+
+	for (isize = subQCIF; isize < VGA; isize++) {
+		if (tcm825x_sizes[isize + 1].height
+		    * tcm825x_sizes[isize + 1].width > pixels) {
+			dev_dbg(&sensor->i2c_client->dev, "size %d\n", isize);
+
+			return isize;
+		}
+	}
+
+	dev_dbg(&sensor->i2c_client->dev, "format default VGA\n");
+
+	return VGA;
+}
+
+/*
+ * Configure the TCM825X for current image size, pixel format, and
+ * frame period. fper is the frame period (in seconds) expressed as a
+ * fraction. Returns zero if successful, or non-zero otherwise. The
+ * actual frame period is returned in fper.
+ */
+static int tcm825x_configure(struct v4l2_int_device *s)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	struct v4l2_pix_format *pix = &sensor->pix;
+	enum image_size isize = tcm825x_find_size(s, pix->width, pix->height);
+	struct v4l2_fract *fper = &sensor->timeperframe;
+	enum pixel_format pfmt;
+	int err;
+	u32 tgt_fps;
+	u8 val;
+
+	/* common register initialization */
+	err = tcm825x_write_default_regs(
+		sensor->i2c_client, sensor->platform_data->default_regs());
+	if (err)
+		return err;
+
+	/* configure image size */
+	val = tcm825x_siz_reg[isize]->val;
+	dev_dbg(&sensor->i2c_client->dev,
+		"configuring image size %d\n", isize);
+	err = tcm825x_write_reg_mask(sensor->i2c_client,
+				     tcm825x_siz_reg[isize]->reg, val);
+	if (err)
+		return err;
+
+	/* configure pixel format */
+	switch (pix->pixelformat) {
+	default:
+	case V4L2_PIX_FMT_RGB565:
+		pfmt = RGB565;
+		break;
+	case V4L2_PIX_FMT_UYVY:
+		pfmt = YUV422;
+		break;
+	}
+
+	dev_dbg(&sensor->i2c_client->dev,
+		"configuring pixel format %d\n", pfmt);
+	val = tcm825x_fmt_reg[pfmt]->val;
+
+	err = tcm825x_write_reg_mask(sensor->i2c_client,
+				     tcm825x_fmt_reg[pfmt]->reg, val);
+	if (err)
+		return err;
+
+	/*
+	 * For frame rate < 15, the FPS reg (addr 0x02, bit 7) must be
+	 * set. Frame rate will be halved from the normal.
+	 */
+	tgt_fps = fper->denominator / fper->numerator;
+	if (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) {
+		val = tcm825x_read_reg(sensor->i2c_client, 0x02);
+		val |= 0x80;
+		tcm825x_write_reg(sensor->i2c_client, 0x02, val);
+	}
+
+	return 0;
+}
+
+static int ioctl_queryctrl(struct v4l2_int_device *s,
+				struct v4l2_queryctrl *qc)
+{
+	struct vcontrol *control;
+
+	control = find_vctrl(qc->id);
+
+	if (control == NULL)
+		return -EINVAL;
+
+	*qc = control->qc;
+
+	return 0;
+}
+
+static int ioctl_g_ctrl(struct v4l2_int_device *s,
+			     struct v4l2_control *vc)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	struct i2c_client *client = sensor->i2c_client;
+	int val, r;
+	struct vcontrol *lvc;
+
+	/* exposure time is special, spread accross 2 registers */
+	if (vc->id == V4L2_CID_EXPOSURE) {
+		int val_lower, val_upper;
+
+		val_upper = tcm825x_read_reg(client,
+					     TCM825X_ADDR(TCM825X_ESRSPD_U));
+		if (val_upper < 0)
+			return val_upper;
+		val_lower = tcm825x_read_reg(client,
+					     TCM825X_ADDR(TCM825X_ESRSPD_L));
+		if (val_lower < 0)
+			return val_lower;
+
+		vc->value = ((val_upper & 0x1f) << 8) | (val_lower);
+		return 0;
+	}
+
+	lvc = find_vctrl(vc->id);
+	if (lvc == NULL)
+		return -EINVAL;
+
+	r = tcm825x_read_reg(client, TCM825X_ADDR(lvc->reg));
+	if (r < 0)
+		return r;
+	val = r & TCM825X_MASK(lvc->reg);
+	val >>= lvc->start_bit;
+
+	if (val < 0)
+		return val;
+
+	vc->value = val;
+	return 0;
+}
+
+static int ioctl_s_ctrl(struct v4l2_int_device *s,
+			     struct v4l2_control *vc)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	struct i2c_client *client = sensor->i2c_client;
+	struct vcontrol *lvc;
+	int val = vc->value;
+
+	/* exposure time is special, spread accross 2 registers */
+	if (vc->id == V4L2_CID_EXPOSURE) {
+		int val_lower, val_upper;
+		val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L);
+		val_upper = (val >> 8) & TCM825X_MASK(TCM825X_ESRSPD_U);
+
+		if (tcm825x_write_reg_mask(client,
+					   TCM825X_ESRSPD_U, val_upper))
+			return -EIO;
+
+		if (tcm825x_write_reg_mask(client,
+					   TCM825X_ESRSPD_L, val_lower))
+			return -EIO;
+
+		return 0;
+	}
+
+	lvc = find_vctrl(vc->id);
+	if (lvc == NULL)
+		return -EINVAL;
+
+	val = val << lvc->start_bit;
+	if (tcm825x_write_reg_mask(client, lvc->reg, val))
+		return -EIO;
+
+	return 0;
+}
+
+static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
+				   struct v4l2_fmtdesc *fmt)
+{
+	int index = fmt->index;
+
+	switch (fmt->type) {
+	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+		if (index >= TCM825X_NUM_CAPTURE_FORMATS)
+			return -EINVAL;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	fmt->flags = tcm825x_formats[index].flags;
+	strlcpy(fmt->description, tcm825x_formats[index].description,
+		sizeof(fmt->description));
+	fmt->pixelformat = tcm825x_formats[index].pixelformat;
+
+	return 0;
+}
+
+static int ioctl_try_fmt_cap(struct v4l2_int_device *s,
+			     struct v4l2_format *f)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	enum image_size isize;
+	int ifmt;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+
+	isize = tcm825x_find_size(s, pix->width, pix->height);
+	dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %lu\n",
+		isize, (unsigned long)TCM825X_NUM_CAPTURE_FORMATS);
+
+	pix->width = tcm825x_sizes[isize].width;
+	pix->height = tcm825x_sizes[isize].height;
+
+	for (ifmt = 0; ifmt < TCM825X_NUM_CAPTURE_FORMATS; ifmt++)
+		if (pix->pixelformat == tcm825x_formats[ifmt].pixelformat)
+			break;
+
+	if (ifmt == TCM825X_NUM_CAPTURE_FORMATS)
+		ifmt = 0;	/* Default = YUV 4:2:2 */
+
+	pix->pixelformat = tcm825x_formats[ifmt].pixelformat;
+	pix->field = V4L2_FIELD_NONE;
+	pix->bytesperline = pix->width * TCM825X_BYTES_PER_PIXEL;
+	pix->sizeimage = pix->bytesperline * pix->height;
+	pix->priv = 0;
+	dev_dbg(&sensor->i2c_client->dev, "format = 0x%08x\n",
+		pix->pixelformat);
+
+	switch (pix->pixelformat) {
+	case V4L2_PIX_FMT_UYVY:
+	default:
+		pix->colorspace = V4L2_COLORSPACE_JPEG;
+		break;
+	case V4L2_PIX_FMT_RGB565:
+		pix->colorspace = V4L2_COLORSPACE_SRGB;
+		break;
+	}
+
+	return 0;
+}
+
+static int ioctl_s_fmt_cap(struct v4l2_int_device *s,
+				struct v4l2_format *f)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	int rval;
+
+	rval = ioctl_try_fmt_cap(s, f);
+	if (rval)
+		return rval;
+
+	rval = tcm825x_configure(s);
+
+	sensor->pix = *pix;
+
+	return rval;
+}
+
+static int ioctl_g_fmt_cap(struct v4l2_int_device *s,
+				struct v4l2_format *f)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+
+	f->fmt.pix = sensor->pix;
+
+	return 0;
+}
+
+static int ioctl_g_parm(struct v4l2_int_device *s,
+			     struct v4l2_streamparm *a)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	struct v4l2_captureparm *cparm = &a->parm.capture;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	memset(a, 0, sizeof(*a));
+	a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	cparm->capability = V4L2_CAP_TIMEPERFRAME;
+	cparm->timeperframe = sensor->timeperframe;
+
+	return 0;
+}
+
+static int ioctl_s_parm(struct v4l2_int_device *s,
+			     struct v4l2_streamparm *a)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+	u32 tgt_fps;	/* target frames per secound */
+	int rval;
+
+	if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if ((timeperframe->numerator == 0)
+	    || (timeperframe->denominator == 0)) {
+		timeperframe->denominator = DEFAULT_FPS;
+		timeperframe->numerator = 1;
+	}
+
+	tgt_fps = timeperframe->denominator / timeperframe->numerator;
+
+	if (tgt_fps > MAX_FPS) {
+		timeperframe->denominator = MAX_FPS;
+		timeperframe->numerator = 1;
+	} else if (tgt_fps < MIN_FPS) {
+		timeperframe->denominator = MIN_FPS;
+		timeperframe->numerator = 1;
+	}
+
+	sensor->timeperframe = *timeperframe;
+
+	rval = tcm825x_configure(s);
+
+	return rval;
+}
+
+static int ioctl_s_power(struct v4l2_int_device *s, int on)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+
+	return sensor->platform_data->power_set(on);
+}
+
+/*
+ * Given the image capture format in pix, the nominal frame period in
+ * timeperframe, calculate the required xclk frequency.
+ *
+ * TCM825X input frequency characteristics are:
+ *     Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz
+ */
+
+static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	struct v4l2_fract *timeperframe = &sensor->timeperframe;
+	u32 tgt_xclk;	/* target xclk */
+	u32 tgt_fps;	/* target frames per secound */
+	int rval;
+
+	rval = sensor->platform_data->ifparm(p);
+	if (rval)
+		return rval;
+
+	tgt_fps = timeperframe->denominator / timeperframe->numerator;
+
+	tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ?
+		(2457 * tgt_fps) / MAX_HALF_FPS :
+		(2457 * tgt_fps) / MAX_FPS;
+	tgt_xclk *= 10000;
+
+	tgt_xclk = min(tgt_xclk, (u32)TCM825X_XCLK_MAX);
+	tgt_xclk = max(tgt_xclk, (u32)TCM825X_XCLK_MIN);
+
+	p->u.bt656.clock_curr = tgt_xclk;
+
+	return 0;
+}
+
+static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+
+	return sensor->platform_data->needs_reset(s, buf, &sensor->pix);
+}
+
+static int ioctl_reset(struct v4l2_int_device *s)
+{
+	return -EBUSY;
+}
+
+static int ioctl_init(struct v4l2_int_device *s)
+{
+	return tcm825x_configure(s);
+}
+
+static int ioctl_dev_exit(struct v4l2_int_device *s)
+{
+	return 0;
+}
+
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+	struct tcm825x_sensor *sensor = s->priv;
+	int r;
+
+	r = tcm825x_read_reg(sensor->i2c_client, 0x01);
+	if (r < 0)
+		return r;
+	if (r == 0) {
+		dev_err(&sensor->i2c_client->dev, "device not detected\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[] = {
+	{ vidioc_int_dev_init_num,
+	  (v4l2_int_ioctl_func *)ioctl_dev_init },
+	{ vidioc_int_dev_exit_num,
+	  (v4l2_int_ioctl_func *)ioctl_dev_exit },
+	{ vidioc_int_s_power_num,
+	  (v4l2_int_ioctl_func *)ioctl_s_power },
+	{ vidioc_int_g_ifparm_num,
+	  (v4l2_int_ioctl_func *)ioctl_g_ifparm },
+	{ vidioc_int_g_needs_reset_num,
+	  (v4l2_int_ioctl_func *)ioctl_g_needs_reset },
+	{ vidioc_int_reset_num,
+	  (v4l2_int_ioctl_func *)ioctl_reset },
+	{ vidioc_int_init_num,
+	  (v4l2_int_ioctl_func *)ioctl_init },
+	{ vidioc_int_enum_fmt_cap_num,
+	  (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap },
+	{ vidioc_int_try_fmt_cap_num,
+	  (v4l2_int_ioctl_func *)ioctl_try_fmt_cap },
+	{ vidioc_int_g_fmt_cap_num,
+	  (v4l2_int_ioctl_func *)ioctl_g_fmt_cap },
+	{ vidioc_int_s_fmt_cap_num,
+	  (v4l2_int_ioctl_func *)ioctl_s_fmt_cap },
+	{ vidioc_int_g_parm_num,
+	  (v4l2_int_ioctl_func *)ioctl_g_parm },
+	{ vidioc_int_s_parm_num,
+	  (v4l2_int_ioctl_func *)ioctl_s_parm },
+	{ vidioc_int_queryctrl_num,
+	  (v4l2_int_ioctl_func *)ioctl_queryctrl },
+	{ vidioc_int_g_ctrl_num,
+	  (v4l2_int_ioctl_func *)ioctl_g_ctrl },
+	{ vidioc_int_s_ctrl_num,
+	  (v4l2_int_ioctl_func *)ioctl_s_ctrl },
+};
+
+static struct v4l2_int_slave tcm825x_slave = {
+	.ioctls = tcm825x_ioctl_desc,
+	.num_ioctls = ARRAY_SIZE(tcm825x_ioctl_desc),
+};
+
+static struct tcm825x_sensor tcm825x;
+
+static struct v4l2_int_device tcm825x_int_device = {
+	.module = THIS_MODULE,
+	.name = TCM825X_NAME,
+	.priv = &tcm825x,
+	.type = v4l2_int_type_slave,
+	.u = {
+		.slave = &tcm825x_slave,
+	},
+};
+
+static int tcm825x_probe(struct i2c_client *client)
+{
+	struct tcm825x_sensor *sensor = &tcm825x;
+	int rval;
+
+	if (i2c_get_clientdata(client))
+		return -EBUSY;
+
+	sensor->platform_data = client->dev.platform_data;
+
+	if (sensor->platform_data == NULL
+	    && !sensor->platform_data->is_okay())
+		return -ENODEV;
+
+	sensor->v4l2_int_device = &tcm825x_int_device;
+
+	sensor->i2c_client = client;
+	i2c_set_clientdata(client, sensor);
+
+	/* Make the default capture format QVGA RGB565 */
+	sensor->pix.width = tcm825x_sizes[QVGA].width;
+	sensor->pix.height = tcm825x_sizes[QVGA].height;
+	sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565;
+
+	rval = v4l2_int_device_register(sensor->v4l2_int_device);
+	if (rval)
+		i2c_set_clientdata(client, NULL);
+
+	return rval;
+}
+
+static int __exit tcm825x_remove(struct i2c_client *client)
+{
+	struct tcm825x_sensor *sensor = i2c_get_clientdata(client);
+
+	if (!client->adapter)
+		return -ENODEV;	/* our client isn't attached */
+
+	v4l2_int_device_unregister(sensor->v4l2_int_device);
+	i2c_set_clientdata(client, NULL);
+
+	return 0;
+}
+
+static struct i2c_driver tcm825x_i2c_driver = {
+	.driver	= {
+		.name = TCM825X_NAME,
+	},
+	.probe	= tcm825x_probe,
+	.remove	= __exit_p(tcm825x_remove),
+};
+
+static struct tcm825x_sensor tcm825x = {
+	.timeperframe = {
+		.numerator   = 1,
+		.denominator = DEFAULT_FPS,
+	},
+};
+
+static int __init tcm825x_init(void)
+{
+	int rval;
+
+	rval = i2c_add_driver(&tcm825x_i2c_driver);
+	if (rval)
+		printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n",
+		       __FUNCTION__);
+
+	return rval;
+}
+
+static void __exit tcm825x_exit(void)
+{
+	i2c_del_driver(&tcm825x_i2c_driver);
+}
+
+/*
+ * FIXME: Menelaus isn't ready (?) at module_init stage, so use
+ * late_initcall for now.
+ */
+late_initcall(tcm825x_init);
+module_exit(tcm825x_exit);
+
+MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
+MODULE_DESCRIPTION("TCM825x camera sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tcm825x.h b/drivers/media/video/tcm825x.h
new file mode 100644
index 0000000..966765b
--- /dev/null
+++ b/drivers/media/video/tcm825x.h
@@ -0,0 +1,199 @@
+/*
+ * drivers/media/video/tcm825x.h
+ *
+ * Register definitions for the TCM825X CameraChip.
+ *
+ * Author: David Cohen (david.cohen@indt.org.br)
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * This file was based on ov9640.h from MontaVista
+ */
+
+#ifndef TCM825X_H
+#define TCM825X_H
+
+#include <linux/videodev2.h>
+
+#include <media/v4l2-int-device.h>
+
+#define TCM825X_NAME "tcm825x"
+
+#define TCM825X_MASK(x)  x & 0x00ff
+#define TCM825X_ADDR(x) (x & 0xff00) >> 8
+
+/* The TCM825X I2C sensor chip has a fixed slave address of 0x3d. */
+#define TCM825X_I2C_ADDR	0x3d
+
+/*
+ * define register offsets for the TCM825X sensor chip
+ * OFFSET(8 bits) + MASK(8 bits)
+ * MASK bit 4 and 3 are used when the register uses more than one address
+ */
+#define TCM825X_FPS		0x0280
+#define TCM825X_ACF		0x0240
+#define TCM825X_DOUTBUF		0x020C
+#define TCM825X_DCLKP		0x0202
+#define TCM825X_ACFDET		0x0201
+#define TCM825X_DOUTSW		0x0380
+#define TCM825X_DATAHZ		0x0340
+#define TCM825X_PICSIZ		0x033c
+#define TCM825X_PICFMT		0x0302
+#define TCM825X_V_INV		0x0480
+#define TCM825X_H_INV		0x0440
+#define TCM825X_ESRLSW		0x0430
+#define TCM825X_V_LENGTH	0x040F
+#define TCM825X_ALCSW		0x0580
+#define TCM825X_ESRLIM		0x0560
+#define TCM825X_ESRSPD_U        0x051F
+#define TCM825X_ESRSPD_L        0x06FF
+#define TCM825X_AG		0x07FF
+#define TCM825X_ESRSPD2         0x06FF
+#define TCM825X_ALCMODE         0x0830
+#define TCM825X_ALCH            0x080F
+#define TCM825X_ALCL            0x09FF
+#define TCM825X_AWBSW           0x0A80
+#define TCM825X_MRG             0x0BFF
+#define TCM825X_MBG             0x0CFF
+#define TCM825X_GAMSW           0x0D80
+#define TCM825X_HDTG            0x0EFF
+#define TCM825X_VDTG            0x0FFF
+#define TCM825X_HDTCORE         0x10F0
+#define TCM825X_VDTCORE         0x100F
+#define TCM825X_CONT            0x11FF
+#define TCM825X_BRIGHT          0x12FF
+#define TCM825X_VHUE            0x137F
+#define TCM825X_UHUE            0x147F
+#define TCM825X_VGAIN           0x153F
+#define TCM825X_UGAIN           0x163F
+#define TCM825X_UVCORE          0x170F
+#define TCM825X_SATU            0x187F
+#define TCM825X_MHMODE          0x1980
+#define TCM825X_MHLPFSEL        0x1940
+#define TCM825X_YMODE           0x1930
+#define TCM825X_MIXHG           0x1907
+#define TCM825X_LENS            0x1A3F
+#define TCM825X_AGLIM           0x1BE0
+#define TCM825X_LENSRPOL        0x1B10
+#define TCM825X_LENSRGAIN       0x1B0F
+#define TCM825X_ES100S          0x1CFF
+#define TCM825X_ES120S          0x1DFF
+#define TCM825X_DMASK           0x1EC0
+#define TCM825X_CODESW          0x1E20
+#define TCM825X_CODESEL         0x1E10
+#define TCM825X_TESPIC          0x1E04
+#define TCM825X_PICSEL          0x1E03
+#define TCM825X_HNUM            0x20FF
+#define TCM825X_VOUTPH          0x287F
+#define TCM825X_ESROUT          0x327F
+#define TCM825X_ESROUT2         0x33FF
+#define TCM825X_AGOUT           0x34FF
+#define TCM825X_DGOUT           0x353F
+#define TCM825X_AGSLOW1         0x39C0
+#define TCM825X_FLLSMODE        0x3930
+#define TCM825X_FLLSLIM         0x390F
+#define TCM825X_DETSEL          0x3AF0
+#define TCM825X_ACDETNC         0x3A0F
+#define TCM825X_AGSLOW2         0x3BC0
+#define TCM825X_DG              0x3B3F
+#define TCM825X_REJHLEV         0x3CFF
+#define TCM825X_ALCLOCK         0x3D80
+#define TCM825X_FPSLNKSW        0x3D40
+#define TCM825X_ALCSPD          0x3D30
+#define TCM825X_REJH            0x3D03
+#define TCM825X_SHESRSW         0x3E80
+#define TCM825X_ESLIMSEL        0x3E40
+#define TCM825X_SHESRSPD        0x3E30
+#define TCM825X_ELSTEP          0x3E0C
+#define TCM825X_ELSTART         0x3E03
+#define TCM825X_AGMIN           0x3FFF
+#define TCM825X_PREGRG          0x423F
+#define TCM825X_PREGBG          0x433F
+#define TCM825X_PRERG           0x443F
+#define TCM825X_PREBG           0x453F
+#define TCM825X_MSKBR           0x477F
+#define TCM825X_MSKGR           0x487F
+#define TCM825X_MSKRB           0x497F
+#define TCM825X_MSKGB           0x4A7F
+#define TCM825X_MSKRG           0x4B7F
+#define TCM825X_MSKBG           0x4C7F
+#define TCM825X_HDTCSW          0x4D80
+#define TCM825X_VDTCSW          0x4D40
+#define TCM825X_DTCYL           0x4D3F
+#define TCM825X_HDTPSW          0x4E80
+#define TCM825X_VDTPSW          0x4E40
+#define TCM825X_DTCGAIN         0x4E3F
+#define TCM825X_DTLLIMSW        0x4F10
+#define TCM825X_DTLYLIM         0x4F0F
+#define TCM825X_YLCUTLMSK       0x5080
+#define TCM825X_YLCUTL          0x503F
+#define TCM825X_YLCUTHMSK       0x5180
+#define TCM825X_YLCUTH          0x513F
+#define TCM825X_UVSKNC          0x527F
+#define TCM825X_UVLJ            0x537F
+#define TCM825X_WBGMIN          0x54FF
+#define TCM825X_WBGMAX          0x55FF
+#define TCM825X_WBSPDUP         0x5603
+#define TCM825X_ALLAREA         0x5820
+#define TCM825X_WBLOCK          0x5810
+#define TCM825X_WB2SP           0x580F
+#define TCM825X_KIZUSW          0x5920
+#define TCM825X_PBRSW           0x5910
+#define TCM825X_ABCSW           0x5903
+#define TCM825X_PBDLV           0x5AFF
+#define TCM825X_PBC1LV          0x5BFF
+
+#define TCM825X_NUM_REGS	(TCM825X_ADDR(TCM825X_PBC1LV) + 1)
+
+#define TCM825X_BYTES_PER_PIXEL 2
+
+#define TCM825X_REG_TERM 0xff		/* terminating list entry for reg */
+#define TCM825X_VAL_TERM 0xff		/* terminating list entry for val */
+
+/* define a structure for tcm825x register initialization values */
+struct tcm825x_reg {
+	u8 val;
+	u16 reg;
+};
+
+enum image_size { subQCIF = 0, QQVGA, QCIF, QVGA, CIF, VGA };
+enum pixel_format { YUV422 = 0, RGB565 };
+#define NUM_IMAGE_SIZES 6
+#define NUM_PIXEL_FORMATS 2
+
+#define TCM825X_XCLK_MIN	11900000
+#define TCM825X_XCLK_MAX	25000000
+
+struct capture_size {
+	unsigned long width;
+	unsigned long height;
+};
+
+struct tcm825x_platform_data {
+	/* Is the sensor usable? Doesn't yet mean it's there, but you
+	 * can try! */
+	int (*is_okay)(void);
+	/* Set power state, zero is off, non-zero is on. */
+	int (*power_set)(int power);
+	/* Default registers written after power-on or reset. */
+	const struct tcm825x_reg *(*default_regs)(void);
+	int (*needs_reset)(struct v4l2_int_device *s, void *buf,
+			   struct v4l2_pix_format *fmt);
+	int (*ifparm)(struct v4l2_ifparm *p);
+};
+
+/* Array of image sizes supported by TCM825X.  These must be ordered from
+ * smallest image size to largest.
+ */
+const static struct capture_size tcm825x_sizes[] = {
+	{ 128,  96 }, /* subQCIF */
+	{ 160, 120 }, /* QQVGA */
+	{ 176, 144 }, /* QCIF */
+	{ 320, 240 }, /* QVGA */
+	{ 352, 288 }, /* CIF */
+	{ 640, 480 }, /* VGA */
+};
+
+#endif /* ifndef TCM825X_H */
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index 1a1bef0..0e5cf45 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -16,12 +16,38 @@
    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.
+
+   This "tda8290" module was split apart from the original "tuner" module.
 */
 
 #include <linux/i2c.h>
-#include <linux/videodev.h>
 #include <linux/delay.h>
-#include <media/tuner.h>
+#include <linux/videodev.h>
+#include "tuner-i2c.h"
+#include "tda8290.h"
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+#define PREFIX "tda8290 "
+
+/* ---------------------------------------------------------------------- */
+
+struct tda8290_priv {
+	struct tuner_i2c_props i2c_props;
+
+	unsigned char tda8290_easy_mode;
+	unsigned char tda827x_lpsel;
+	unsigned char tda827x_addr;
+	unsigned char tda827x_ver;
+	unsigned int sgIF;
+
+	u32 frequency;
+
+	unsigned int *lna_cfg;
+	int (*tuner_callback) (void *dev, int command,int arg);
+};
 
 /* ---------------------------------------------------------------------- */
 
@@ -69,19 +95,21 @@
 	{ .lomax =     0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}  /* End      */
 };
 
-static void tda827x_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
+static void tda827x_set_analog_params(struct dvb_frontend *fe,
+				      struct analog_parameters *params)
 {
 	unsigned char tuner_reg[8];
 	unsigned char reg2[2];
 	u32 N;
 	int i;
-	struct tuner *t = i2c_get_clientdata(c);
-	struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0};
+	struct tda8290_priv *priv = fe->tuner_priv;
+	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0};
+	unsigned int freq = params->frequency;
 
-	if (t->mode == V4L2_TUNER_RADIO)
+	if (params->mode == V4L2_TUNER_RADIO)
 		freq = freq / 1000;
 
-	N = freq + ifc;
+	N = freq + priv->sgIF;
 	i = 0;
 	while (tda827x_analog[i].lomax < N) {
 		if(tda827x_analog[i + 1].lomax == 0)
@@ -95,7 +123,7 @@
 	tuner_reg[1] = (unsigned char)(N>>8);
 	tuner_reg[2] = (unsigned char) N;
 	tuner_reg[3] = 0x40;
-	tuner_reg[4] = 0x52 + (t->tda827x_lpsel << 5);
+	tuner_reg[4] = 0x52 + (priv->tda827x_lpsel << 5);
 	tuner_reg[5] = (tda827x_analog[i].spd   << 6) + (tda827x_analog[i].div1p5 <<5) +
 		       (tda827x_analog[i].bs     <<3) +  tda827x_analog[i].bp;
 	tuner_reg[6] = 0x8f + (tda827x_analog[i].gc3 << 4);
@@ -103,53 +131,53 @@
 
 	msg.buf = tuner_reg;
 	msg.len = 8;
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 
 	msg.buf= reg2;
 	msg.len = 2;
 	reg2[0] = 0x80;
 	reg2[1] = 0;
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 
 	reg2[0] = 0x60;
 	reg2[1] = 0xbf;
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 
 	reg2[0] = 0x30;
 	reg2[1] = tuner_reg[4] + 0x80;
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 
 	msleep(1);
 	reg2[0] = 0x30;
 	reg2[1] = tuner_reg[4] + 4;
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 
 	msleep(1);
 	reg2[0] = 0x30;
 	reg2[1] = tuner_reg[4];
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 
 	msleep(550);
 	reg2[0] = 0x30;
 	reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_analog[i].cp ;
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 
 	reg2[0] = 0x60;
 	reg2[1] = 0x3f;
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 
 	reg2[0] = 0x80;
 	reg2[1] = 0x08;   // Vsync en
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 }
 
-static void tda827x_agcf(struct i2c_client *c)
+static void tda827x_agcf(struct dvb_frontend *fe)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	struct tda8290_priv *priv = fe->tuner_priv;
 	unsigned char data[] = {0x80, 0x0c};
-	struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+	struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
 			      .flags = 0, .len = 2};
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 }
 
 /* ---------------------------------------------------------------------- */
@@ -192,57 +220,64 @@
 	{ .lomax =     0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}   /* End */
 };
 
-static void tda827xa_lna_gain(struct i2c_client *c, int high)
+static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
+			      struct analog_parameters *params)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	struct tda8290_priv *priv = fe->tuner_priv;
 	unsigned char buf[] = {0x22, 0x01};
 	int arg;
-	struct i2c_msg msg = {.addr = c->addr, .flags = 0, .buf = buf, .len = sizeof(buf)};
-	if (t->config) {
+	struct i2c_msg msg = {.addr = priv->i2c_props.addr, .flags = 0, .buf = buf, .len = sizeof(buf)};
+
+	if ((priv->lna_cfg == NULL)  || (priv->tuner_callback == NULL))
+	    return;
+
+	if (*priv->lna_cfg) {
 		if (high)
 			tuner_dbg("setting LNA to high gain\n");
 		else
 			tuner_dbg("setting LNA to low gain\n");
 	}
-	switch (t->config) {
+	switch (*priv->lna_cfg) {
 	case 0: /* no LNA */
 		break;
 	case 1: /* switch is GPIO 0 of tda8290 */
 	case 2:
 		/* turn Vsync on */
-		if (t->std & V4L2_STD_MN)
+		if (params->std & V4L2_STD_MN)
 			arg = 1;
 		else
 			arg = 0;
-		if (t->tuner_callback)
-			t->tuner_callback(c->adapter->algo_data, 1, arg);
+		if (priv->tuner_callback)
+			priv->tuner_callback(priv->i2c_props.adap->algo_data, 1, arg);
 		buf[1] = high ? 0 : 1;
-		if (t->config == 2)
+		if (*priv->lna_cfg == 2)
 			buf[1] = high ? 1 : 0;
-		i2c_transfer(c->adapter, &msg, 1);
+		i2c_transfer(priv->i2c_props.adap, &msg, 1);
 		break;
 	case 3: /* switch with GPIO of saa713x */
-		if (t->tuner_callback)
-			t->tuner_callback(c->adapter->algo_data, 0, high);
+		if (priv->tuner_callback)
+			priv->tuner_callback(priv->i2c_props.adap->algo_data, 0, high);
 		break;
 	}
 }
 
-static void tda827xa_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
+static void tda827xa_set_analog_params(struct dvb_frontend *fe,
+				       struct analog_parameters *params)
 {
 	unsigned char tuner_reg[11];
 	u32 N;
 	int i;
-	struct tuner *t = i2c_get_clientdata(c);
-	struct i2c_msg msg = {.addr = t->tda827x_addr, .flags = 0, .buf = tuner_reg};
+	struct tda8290_priv *priv = fe->tuner_priv;
+	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags = 0, .buf = tuner_reg};
+	unsigned int freq = params->frequency;
 
-	tda827xa_lna_gain( c, 1);
+	tda827xa_lna_gain(fe, 1, params);
 	msleep(10);
 
-	if (t->mode == V4L2_TUNER_RADIO)
+	if (params->mode == V4L2_TUNER_RADIO)
 		freq = freq / 1000;
 
-	N = freq + ifc;
+	N = freq + priv->sgIF;
 	i = 0;
 	while (tda827xa_analog[i].lomax < N) {
 		if(tda827xa_analog[i + 1].lomax == 0)
@@ -265,90 +300,141 @@
 	tuner_reg[9] = 0x20;
 	tuner_reg[10] = 0x00;
 	msg.len = 11;
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 
 	tuner_reg[0] = 0x90;
 	tuner_reg[1] = 0xff;
 	tuner_reg[2] = 0xe0;
 	tuner_reg[3] = 0;
-	tuner_reg[4] = 0x99 + (t->tda827x_lpsel << 1);
+	tuner_reg[4] = 0x99 + (priv->tda827x_lpsel << 1);
 	msg.len = 5;
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 
 	tuner_reg[0] = 0xa0;
 	tuner_reg[1] = 0xc0;
 	msg.len = 2;
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 
 	tuner_reg[0] = 0x30;
 	tuner_reg[1] = 0x10 + tda827xa_analog[i].scr;
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 
 	msg.flags = I2C_M_RD;
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 	msg.flags = 0;
 	tuner_reg[1] >>= 4;
 	tuner_dbg("AGC2 gain is: %d\n", tuner_reg[1]);
 	if (tuner_reg[1] < 1)
-		tda827xa_lna_gain( c, 0);
+		tda827xa_lna_gain(fe, 0, params);
 
 	msleep(100);
 	tuner_reg[0] = 0x60;
 	tuner_reg[1] = 0x3c;
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 
 	msleep(163);
 	tuner_reg[0] = 0x50;
 	tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4);
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 
 	tuner_reg[0] = 0x80;
 	tuner_reg[1] = 0x28;
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 
 	tuner_reg[0] = 0xb0;
 	tuner_reg[1] = 0x01;
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 
 	tuner_reg[0] = 0xc0;
-	tuner_reg[1] = 0x19 + (t->tda827x_lpsel << 1);
-	i2c_transfer(c->adapter, &msg, 1);
+	tuner_reg[1] = 0x19 + (priv->tda827x_lpsel << 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 }
 
-static void tda827xa_agcf(struct i2c_client *c)
+static void tda827xa_agcf(struct dvb_frontend *fe)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	struct tda8290_priv *priv = fe->tuner_priv;
 	unsigned char data[] = {0x80, 0x2c};
-	struct i2c_msg msg = {.addr = t->tda827x_addr, .buf = data,
+	struct i2c_msg msg = {.addr = priv->tda827x_addr, .buf = data,
 			      .flags = 0, .len = 2};
-	i2c_transfer(c->adapter, &msg, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
 }
 
 /*---------------------------------------------------------------------*/
 
-static void tda8290_i2c_bridge(struct i2c_client *c, int close)
+static void tda8290_i2c_bridge(struct dvb_frontend *fe, int close)
 {
+	struct tda8290_priv *priv = fe->tuner_priv;
+
 	unsigned char  enable[2] = { 0x21, 0xC0 };
 	unsigned char disable[2] = { 0x21, 0x00 };
 	unsigned char *msg;
 	if(close) {
 		msg = enable;
-		i2c_master_send(c, msg, 2);
+		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
 		/* let the bridge stabilize */
 		msleep(20);
 	} else {
 		msg = disable;
-		i2c_master_send(c, msg, 2);
+		tuner_i2c_xfer_send(&priv->i2c_props, msg, 2);
 	}
 }
 
 /*---------------------------------------------------------------------*/
 
-static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq)
+static void set_audio(struct dvb_frontend *fe,
+		      struct analog_parameters *params)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	struct tda8290_priv *priv = fe->tuner_priv;
+	char* mode;
+
+	priv->tda827x_lpsel = 0;
+	if (params->std & V4L2_STD_MN) {
+		priv->sgIF = 92;
+		priv->tda8290_easy_mode = 0x01;
+		priv->tda827x_lpsel = 1;
+		mode = "MN";
+	} else if (params->std & V4L2_STD_B) {
+		priv->sgIF = 108;
+		priv->tda8290_easy_mode = 0x02;
+		mode = "B";
+	} else if (params->std & V4L2_STD_GH) {
+		priv->sgIF = 124;
+		priv->tda8290_easy_mode = 0x04;
+		mode = "GH";
+	} else if (params->std & V4L2_STD_PAL_I) {
+		priv->sgIF = 124;
+		priv->tda8290_easy_mode = 0x08;
+		mode = "I";
+	} else if (params->std & V4L2_STD_DK) {
+		priv->sgIF = 124;
+		priv->tda8290_easy_mode = 0x10;
+		mode = "DK";
+	} else if (params->std & V4L2_STD_SECAM_L) {
+		priv->sgIF = 124;
+		priv->tda8290_easy_mode = 0x20;
+		mode = "L";
+	} else if (params->std & V4L2_STD_SECAM_LC) {
+		priv->sgIF = 20;
+		priv->tda8290_easy_mode = 0x40;
+		mode = "LC";
+	} else {
+		priv->sgIF = 124;
+		priv->tda8290_easy_mode = 0x10;
+		mode = "xx";
+	}
+
+	if (params->mode == V4L2_TUNER_RADIO)
+		priv->sgIF = 88; /* if frequency is 5.5 MHz */
+
+	tuner_dbg("setting tda8290 to system %s\n", mode);
+}
+
+static int tda8290_set_params(struct dvb_frontend *fe,
+			      struct analog_parameters *params)
+{
+	struct tda8290_priv *priv = fe->tuner_priv;
 	unsigned char soft_reset[]  = { 0x00, 0x00 };
-	unsigned char easy_mode[]   = { 0x01, t->tda8290_easy_mode };
+	unsigned char easy_mode[]   = { 0x01, priv->tda8290_easy_mode };
 	unsigned char expert_mode[] = { 0x01, 0x80 };
 	unsigned char agc_out_on[]  = { 0x02, 0x00 };
 	unsigned char gainset_off[] = { 0x28, 0x14 };
@@ -369,35 +455,38 @@
 		      pll_stat;
 	int i;
 
-	tuner_dbg("tda827xa config is 0x%02x\n", t->config);
-	i2c_master_send(c, easy_mode, 2);
-	i2c_master_send(c, agc_out_on, 2);
-	i2c_master_send(c, soft_reset, 2);
+	set_audio(fe, params);
+
+	if (priv->lna_cfg)
+		tuner_dbg("tda827xa config is 0x%02x\n", *priv->lna_cfg);
+	tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
 	msleep(1);
 
-	expert_mode[1] = t->tda8290_easy_mode + 0x80;
-	i2c_master_send(c, expert_mode, 2);
-	i2c_master_send(c, gainset_off, 2);
-	i2c_master_send(c, if_agc_spd, 2);
-	if (t->tda8290_easy_mode & 0x60)
-		i2c_master_send(c, adc_head_9, 2);
+	expert_mode[1] = priv->tda8290_easy_mode + 0x80;
+	tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2);
+	if (priv->tda8290_easy_mode & 0x60)
+		tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2);
 	else
-		i2c_master_send(c, adc_head_6, 2);
-	i2c_master_send(c, pll_bw_nom, 2);
+		tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
 
-	tda8290_i2c_bridge(c, 1);
-	if (t->tda827x_ver != 0)
-		tda827xa_tune(c, ifc, freq);
+	tda8290_i2c_bridge(fe, 1);
+	if (priv->tda827x_ver != 0)
+		tda827xa_set_analog_params(fe, params);
 	else
-		tda827x_tune(c, ifc, freq);
+		tda827x_set_analog_params(fe, params);
 	for (i = 0; i < 3; i++) {
-		i2c_master_send(c, &addr_pll_stat, 1);
-		i2c_master_recv(c, &pll_stat, 1);
+		tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
+		tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
 		if (pll_stat & 0x80) {
-			i2c_master_send(c, &addr_adc_sat, 1);
-			i2c_master_recv(c, &adc_sat, 1);
-			i2c_master_send(c, &addr_agc_stat, 1);
-			i2c_master_recv(c, &agc_stat, 1);
+			tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1);
+			tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1);
+			tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
+			tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
 			tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat);
 			break;
 		} else {
@@ -409,188 +498,205 @@
 	if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) {
 		tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n",
 			   agc_stat, adc_sat, pll_stat & 0x80);
-		i2c_master_send(c, gainset_2, 2);
+		tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2);
 		msleep(100);
-		i2c_master_send(c, &addr_agc_stat, 1);
-		i2c_master_recv(c, &agc_stat, 1);
-		i2c_master_send(c, &addr_pll_stat, 1);
-		i2c_master_recv(c, &pll_stat, 1);
+		tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
+		tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
+		tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
+		tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
 		if ((agc_stat > 115) || !(pll_stat & 0x80)) {
 			tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
 				   agc_stat, pll_stat & 0x80);
-			if (t->tda827x_ver != 0)
-				tda827xa_agcf(c);
+			if (priv->tda827x_ver != 0)
+				tda827xa_agcf(fe);
 			else
-				tda827x_agcf(c);
+				tda827x_agcf(fe);
 			msleep(100);
-			i2c_master_send(c, &addr_agc_stat, 1);
-			i2c_master_recv(c, &agc_stat, 1);
-			i2c_master_send(c, &addr_pll_stat, 1);
-			i2c_master_recv(c, &pll_stat, 1);
+			tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
+			tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
+			tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
+			tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
 			if((agc_stat > 115) || !(pll_stat & 0x80)) {
 				tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat);
-				i2c_master_send(c, adc_head_12, 2);
-				i2c_master_send(c, pll_bw_low, 2);
+				tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2);
+				tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_low, 2);
 				msleep(100);
 			}
 		}
 	}
 
 	/* l/ l' deadlock? */
-	if(t->tda8290_easy_mode & 0x60) {
-		i2c_master_send(c, &addr_adc_sat, 1);
-		i2c_master_recv(c, &adc_sat, 1);
-		i2c_master_send(c, &addr_pll_stat, 1);
-		i2c_master_recv(c, &pll_stat, 1);
+	if(priv->tda8290_easy_mode & 0x60) {
+		tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1);
+		tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1);
+		tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
+		tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
 		if ((adc_sat > 20) || !(pll_stat & 0x80)) {
 			tuner_dbg("trying to resolve SECAM L deadlock\n");
-			i2c_master_send(c, agc_rst_on, 2);
+			tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2);
 			msleep(40);
-			i2c_master_send(c, agc_rst_off, 2);
+			tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_off, 2);
 		}
 	}
 
-	tda8290_i2c_bridge(c, 0);
-	i2c_master_send(c, if_agc_set, 2);
+	tda8290_i2c_bridge(fe, 0);
+	tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2);
+
+	priv->frequency = (V4L2_TUNER_RADIO == params->mode) ?
+		params->frequency * 125 / 2 : params->frequency * 62500;
+
 	return 0;
 }
 
 /*---------------------------------------------------------------------*/
 
-static void set_audio(struct tuner *t)
+static int tda8290_has_signal(struct dvb_frontend *fe)
 {
-	char* mode;
+	struct tda8290_priv *priv = fe->tuner_priv;
+	int ret;
 
-	t->tda827x_lpsel = 0;
-	if (t->std & V4L2_STD_MN) {
-		t->sgIF = 92;
-		t->tda8290_easy_mode = 0x01;
-		t->tda827x_lpsel = 1;
-		mode = "MN";
-	} else if (t->std & V4L2_STD_B) {
-		t->sgIF = 108;
-		t->tda8290_easy_mode = 0x02;
-		mode = "B";
-	} else if (t->std & V4L2_STD_GH) {
-		t->sgIF = 124;
-		t->tda8290_easy_mode = 0x04;
-		mode = "GH";
-	} else if (t->std & V4L2_STD_PAL_I) {
-		t->sgIF = 124;
-		t->tda8290_easy_mode = 0x08;
-		mode = "I";
-	} else if (t->std & V4L2_STD_DK) {
-		t->sgIF = 124;
-		t->tda8290_easy_mode = 0x10;
-		mode = "DK";
-	} else if (t->std & V4L2_STD_SECAM_L) {
-		t->sgIF = 124;
-		t->tda8290_easy_mode = 0x20;
-		mode = "L";
-	} else if (t->std & V4L2_STD_SECAM_LC) {
-		t->sgIF = 20;
-		t->tda8290_easy_mode = 0x40;
-		mode = "LC";
-	} else {
-		t->sgIF = 124;
-		t->tda8290_easy_mode = 0x10;
-		mode = "xx";
-	}
-	tuner_dbg("setting tda8290 to system %s\n", mode);
-}
-
-static void set_tv_freq(struct i2c_client *c, unsigned int freq)
-{
-	struct tuner *t = i2c_get_clientdata(c);
-
-	set_audio(t);
-	tda8290_tune(c, t->sgIF, freq);
-}
-
-static void set_radio_freq(struct i2c_client *c, unsigned int freq)
-{
-	/* if frequency is 5.5 MHz */
-	tda8290_tune(c, 88, freq);
-}
-
-static int has_signal(struct i2c_client *c)
-{
 	unsigned char i2c_get_afc[1] = { 0x1B };
 	unsigned char afc = 0;
 
-	i2c_master_send(c, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
-	i2c_master_recv(c, &afc, 1);
-	return (afc & 0x80)? 65535:0;
+	/* for now, report based on afc status */
+	tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
+	tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1);
+
+	ret = (afc & 0x80) ? 65535 : 0;
+
+	tuner_dbg("AFC status: %d\n", ret);
+
+	return ret;
+}
+
+static int tda8290_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	*status = 0;
+
+	if (tda8290_has_signal(fe))
+		*status = TUNER_STATUS_LOCKED;
+
+	return 0;
+}
+
+static int tda8290_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	*strength = tda8290_has_signal(fe);
+
+	return 0;
 }
 
 /*---------------------------------------------------------------------*/
 
-static void standby(struct i2c_client *c)
+static int tda8290_standby(struct dvb_frontend *fe)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	struct tda8290_priv *priv = fe->tuner_priv;
 	unsigned char cb1[] = { 0x30, 0xD0 };
 	unsigned char tda8290_standby[] = { 0x00, 0x02 };
 	unsigned char tda8290_agc_tri[] = { 0x02, 0x20 };
-	struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
+	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2};
 
-	tda8290_i2c_bridge(c, 1);
-	if (t->tda827x_ver != 0)
+	tda8290_i2c_bridge(fe, 1);
+	if (priv->tda827x_ver != 0)
 		cb1[1] = 0x90;
-	i2c_transfer(c->adapter, &msg, 1);
-	tda8290_i2c_bridge(c, 0);
-	i2c_master_send(c, tda8290_agc_tri, 2);
-	i2c_master_send(c, tda8290_standby, 2);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
+	tda8290_i2c_bridge(fe, 0);
+	tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2);
+
+	return 0;
 }
 
 
-static void tda8290_init_if(struct i2c_client *c)
+static void tda8290_init_if(struct dvb_frontend *fe)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	struct tda8290_priv *priv = fe->tuner_priv;
+
 	unsigned char set_VS[] = { 0x30, 0x6F };
 	unsigned char set_GP00_CF[] = { 0x20, 0x01 };
 	unsigned char set_GP01_CF[] = { 0x20, 0x0B };
 
-	if ((t->config == 1) || (t->config == 2))
-		i2c_master_send(c, set_GP00_CF, 2);
+	if ((priv->lna_cfg) &&
+	    ((*priv->lna_cfg == 1) || (*priv->lna_cfg == 2)))
+		tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2);
 	else
-		i2c_master_send(c, set_GP01_CF, 2);
-	i2c_master_send(c, set_VS, 2);
+		tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2);
+	tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2);
 }
 
-static void tda8290_init_tuner(struct i2c_client *c)
+static void tda8290_init_tuner(struct dvb_frontend *fe)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	struct tda8290_priv *priv = fe->tuner_priv;
 	unsigned char tda8275_init[]  = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf,
 					  0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 };
 	unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b,
 					  0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b };
-	struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0,
+	struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0,
 			      .buf=tda8275_init, .len = 14};
-	if (t->tda827x_ver != 0)
+	if (priv->tda827x_ver != 0)
 		msg.buf = tda8275a_init;
 
-	tda8290_i2c_bridge(c, 1);
-	i2c_transfer(c->adapter, &msg, 1);
-	tda8290_i2c_bridge(c, 0);
+	tda8290_i2c_bridge(fe, 1);
+	i2c_transfer(priv->i2c_props.adap, &msg, 1);
+	tda8290_i2c_bridge(fe, 0);
 }
 
 /*---------------------------------------------------------------------*/
 
-int tda8290_init(struct i2c_client *c)
+static int tda8290_release(struct dvb_frontend *fe)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static int tda8290_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tda8290_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static struct dvb_tuner_ops tda8290_tuner_ops = {
+	.sleep             = tda8290_standby,
+	.set_analog_params = tda8290_set_params,
+	.release           = tda8290_release,
+	.get_frequency     = tda8290_get_frequency,
+	.get_status        = tda8290_get_status,
+	.get_rf_strength   = tda8290_get_rf_strength,
+};
+
+struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
+				    struct i2c_adapter* i2c_adap,
+				    u8 i2c_addr,
+				    struct tda8290_config *cfg)
+{
+	struct tda8290_priv *priv = NULL;
 	u8 data;
 	int i, ret, tuners_found;
 	u32 tuner_addrs;
 	struct i2c_msg msg = {.flags=I2C_M_RD, .buf=&data, .len = 1};
 
-	tda8290_i2c_bridge(c, 1);
+	priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+	fe->tuner_priv = priv;
+
+	priv->i2c_props.addr = i2c_addr;
+	priv->i2c_props.adap = i2c_adap;
+	if (cfg) {
+		priv->lna_cfg        = cfg->lna_cfg;
+		priv->tuner_callback = cfg->tuner_callback;
+	}
+
+	tda8290_i2c_bridge(fe, 1);
 	/* probe for tuner chip */
 	tuners_found = 0;
 	tuner_addrs = 0;
 	for (i=0x60; i<= 0x63; i++) {
 		msg.addr = i;
-		ret = i2c_transfer(c->adapter, &msg, 1);
+		ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
 		if (ret == 1) {
 			tuners_found++;
 			tuner_addrs = (tuner_addrs << 8) + i;
@@ -600,11 +706,11 @@
 	   behind the bridge and we choose the highest address that doesn't
 	   give a response now
 	 */
-	tda8290_i2c_bridge(c, 0);
+	tda8290_i2c_bridge(fe, 0);
 	if(tuners_found > 1)
 		for (i = 0; i < tuners_found; i++) {
 			msg.addr = tuner_addrs  & 0xff;
-			ret = i2c_transfer(c->adapter, &msg, 1);
+			ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
 			if(ret == 1)
 				tuner_addrs = tuner_addrs >> 8;
 			else
@@ -612,42 +718,53 @@
 		}
 	if (tuner_addrs == 0) {
 		tuner_addrs = 0x61;
-		tuner_info ("could not clearly identify tuner address, defaulting to %x\n",
+		tuner_info("could not clearly identify tuner address, defaulting to %x\n",
 			     tuner_addrs);
 	} else {
 		tuner_addrs = tuner_addrs & 0xff;
-		tuner_info ("setting tuner address to %x\n", tuner_addrs);
+		tuner_info("setting tuner address to %x\n", tuner_addrs);
 	}
-	t->tda827x_addr = tuner_addrs;
+	priv->tda827x_addr = tuner_addrs;
 	msg.addr = tuner_addrs;
 
-	tda8290_i2c_bridge(c, 1);
-	ret = i2c_transfer(c->adapter, &msg, 1);
+	tda8290_i2c_bridge(fe, 1);
+	ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
 	if( ret != 1)
-		tuner_warn ("TDA827x access failed!\n");
+		tuner_warn("TDA827x access failed!\n");
+
+	memcpy(&fe->ops.tuner_ops, &tda8290_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
 	if ((data & 0x3c) == 0) {
-		strlcpy(c->name, "tda8290+75", sizeof(c->name));
-		t->tda827x_ver = 0;
+		strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75",
+			sizeof(fe->ops.tuner_ops.info.name));
+		fe->ops.tuner_ops.info.frequency_min  =  55000000;
+		fe->ops.tuner_ops.info.frequency_max  = 860000000;
+		fe->ops.tuner_ops.info.frequency_step =    250000;
+		priv->tda827x_ver = 0;
 	} else {
-		strlcpy(c->name, "tda8290+75a", sizeof(c->name));
-		t->tda827x_ver = 2;
+		strlcpy(fe->ops.tuner_ops.info.name, "tda8290+75a",
+			sizeof(fe->ops.tuner_ops.info.name));
+		fe->ops.tuner_ops.info.frequency_min  =  44000000;
+		fe->ops.tuner_ops.info.frequency_max  = 906000000;
+		fe->ops.tuner_ops.info.frequency_step =     62500;
+		priv->tda827x_ver = 2;
 	}
-	tuner_info("type set to %s\n", c->name);
 
-	t->set_tv_freq    = set_tv_freq;
-	t->set_radio_freq = set_radio_freq;
-	t->has_signal = has_signal;
-	t->standby = standby;
-	t->tda827x_lpsel = 0;
-	t->mode = V4L2_TUNER_ANALOG_TV;
+	priv->tda827x_lpsel = 0;
 
-	tda8290_init_tuner(c);
-	tda8290_init_if(c);
-	return 0;
+	tda8290_init_tuner(fe);
+	tda8290_init_if(fe);
+	return fe;
 }
 
-int tda8290_probe(struct i2c_client *c)
+int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
 {
+	struct tuner_i2c_props i2c_props = {
+		.adap = i2c_adap,
+		.addr = i2c_addr
+	};
+
 	unsigned char soft_reset[]   = { 0x00, 0x00 };
 	unsigned char easy_mode_b[]  = { 0x01, 0x02 };
 	unsigned char easy_mode_g[]  = { 0x01, 0x04 };
@@ -655,23 +772,30 @@
 	unsigned char addr_dto_lsb = 0x07;
 	unsigned char data;
 
-	i2c_master_send(c, easy_mode_b, 2);
-	i2c_master_send(c, soft_reset, 2);
-	i2c_master_send(c, &addr_dto_lsb, 1);
-	i2c_master_recv(c, &data, 1);
+	tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2);
+	tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
+	tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
+	tuner_i2c_xfer_recv(&i2c_props, &data, 1);
 	if (data == 0) {
-		i2c_master_send(c, easy_mode_g, 2);
-		i2c_master_send(c, soft_reset, 2);
-		i2c_master_send(c, &addr_dto_lsb, 1);
-		i2c_master_recv(c, &data, 1);
+		tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2);
+		tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
+		tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
+		tuner_i2c_xfer_recv(&i2c_props, &data, 1);
 		if (data == 0x7b) {
 			return 0;
 		}
 	}
-	i2c_master_send(c, restore_9886, 3);
+	tuner_i2c_xfer_send(&i2c_props, restore_9886, 3);
 	return -1;
 }
 
+EXPORT_SYMBOL_GPL(tda8290_probe);
+EXPORT_SYMBOL_GPL(tda8290_attach);
+
+MODULE_DESCRIPTION("Philips TDA8290 + TDA8275 / TDA8275a tuner driver");
+MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann");
+MODULE_LICENSE("GPL");
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * ---------------------------------------------------------------------------
diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h
new file mode 100644
index 0000000..107b24b
--- /dev/null
+++ b/drivers/media/video/tda8290.h
@@ -0,0 +1,54 @@
+/*
+    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.
+*/
+
+#ifndef __TDA8290_H__
+#define __TDA8290_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+struct tda8290_config
+{
+	unsigned int *lna_cfg;
+	int (*tuner_callback) (void *dev, int command,int arg);
+};
+
+#if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE))
+extern int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr);
+
+extern struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
+					   struct i2c_adapter* i2c_adap,
+					   u8 i2c_addr,
+					   struct tda8290_config *cfg);
+#else
+static inline int tda8290_probe(struct i2c_adapter* i2c_adap, u8 i2c_addr)
+{
+	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+	       __FUNCTION__);
+	return -EINVAL;
+}
+
+static inline struct dvb_frontend *tda8290_attach(struct dvb_frontend *fe,
+						  struct i2c_adapter* i2c_adap,
+						  u8 i2c_addr,
+						  struct tda8290_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif
+
+#endif /* __TDA8290_H__ */
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index fde576f..be5387f 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -1,16 +1,15 @@
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/i2c.h>
 #include <linux/types.h>
-#include <linux/videodev.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
-
+#include <linux/videodev.h>
 #include <media/v4l2-common.h>
 #include <media/tuner.h>
+#include "tuner-driver.h"
 
 
 /* Chips:
@@ -29,6 +28,11 @@
 		printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
 			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
 
+struct tda9887_priv {
+	struct tuner_i2c_props i2c_props;
+
+	unsigned char 	   data[4];
+};
 
 /* ---------------------------------------------------------------------- */
 
@@ -93,6 +97,8 @@
 #define cAudioIF_6_5             0x03    // bit e0:1
 
 
+#define cVideoIFMask		0x1c	// bit e2:4
+/* Video IF selection in TV Mode (bit B3=0) */
 #define cVideoIF_58_75           0x00    // bit e2:4
 #define cVideoIF_45_75           0x04    // bit e2:4
 #define cVideoIF_38_90           0x08    // bit e2:4
@@ -102,6 +108,13 @@
 #define cRadioIF_45_75           0x18    // bit e2:4
 #define cRadioIF_38_90           0x1C    // bit e2:4
 
+/* IF1 selection in Radio Mode (bit B3=1) */
+#define cRadioIF_33_30		0x00	// bit e2,4 (also 0x10,0x14)
+#define cRadioIF_41_30		0x04	// bit e2,4
+
+/* Output of AFC pin in radio mode when bit E7=1 */
+#define cRadioAGC_SIF		0x00	// bit e3
+#define cRadioAGC_FM		0x08	// bit e3
 
 #define cTunerGainNormal         0x00    // bit e5
 #define cTunerGainLow            0x20    // bit e5
@@ -483,9 +496,13 @@
 	if (t->tda9887_config & TDA9887_GATING_18)
 		buf[3] &= ~cGating_36;
 
-	if (t->tda9887_config & TDA9887_GAIN_NORMAL) {
-		radio_stereo.e &= ~cTunerGainLow;
-		radio_mono.e &= ~cTunerGainLow;
+	if (t->mode == V4L2_TUNER_RADIO) {
+		if (t->tda9887_config & TDA9887_RIF_41_3) {
+			buf[3] &= ~cVideoIFMask;
+			buf[3] |= cRadioIF_41_30;
+		}
+		if (t->tda9887_config & TDA9887_GAIN_NORMAL)
+			buf[3] &= ~cTunerGainLow;
 	}
 
 	return 0;
@@ -495,23 +512,24 @@
 
 static int tda9887_status(struct tuner *t)
 {
+	struct tda9887_priv *priv = t->priv;
 	unsigned char buf[1];
 	int rc;
 
 	memset(buf,0,sizeof(buf));
-	if (1 != (rc = i2c_master_recv(&t->i2c,buf,1)))
+	if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1)))
 		tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
 	dump_read_message(t, buf);
 	return 0;
 }
 
-static void tda9887_configure(struct i2c_client *client)
+static void tda9887_configure(struct tuner *t)
 {
-	struct tuner *t = i2c_get_clientdata(client);
+	struct tda9887_priv *priv = t->priv;
 	int rc;
 
-	memset(t->tda9887_data,0,sizeof(t->tda9887_data));
-	tda9887_set_tvnorm(t,t->tda9887_data);
+	memset(priv->data,0,sizeof(priv->data));
+	tda9887_set_tvnorm(t,priv->data);
 
 	/* A note on the port settings:
 	   These settings tend to depend on the specifics of the board.
@@ -526,22 +544,22 @@
 	   the ports should be set to active (0), but, again, that may
 	   differ depending on the precise hardware configuration.
 	 */
-	t->tda9887_data[1] |= cOutputPort1Inactive;
-	t->tda9887_data[1] |= cOutputPort2Inactive;
+	priv->data[1] |= cOutputPort1Inactive;
+	priv->data[1] |= cOutputPort2Inactive;
 
-	tda9887_set_config(t,t->tda9887_data);
-	tda9887_set_insmod(t,t->tda9887_data);
+	tda9887_set_config(t,priv->data);
+	tda9887_set_insmod(t,priv->data);
 
 	if (t->mode == T_STANDBY) {
-		t->tda9887_data[1] |= cForcedMuteAudioON;
+		priv->data[1] |= cForcedMuteAudioON;
 	}
 
 	tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
-		t->tda9887_data[1],t->tda9887_data[2],t->tda9887_data[3]);
+		priv->data[1],priv->data[2],priv->data[3]);
 	if (tuner_debug > 1)
-		dump_write_message(t, t->tda9887_data);
+		dump_write_message(t, priv->data);
 
-	if (4 != (rc = i2c_master_send(&t->i2c,t->tda9887_data,4)))
+	if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4)))
 		tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
 
 	if (tuner_debug > 2) {
@@ -552,15 +570,15 @@
 
 /* ---------------------------------------------------------------------- */
 
-static void tda9887_tuner_status(struct i2c_client *client)
+static void tda9887_tuner_status(struct tuner *t)
 {
-	struct tuner *t = i2c_get_clientdata(client);
-	tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->tda9887_data[1], t->tda9887_data[2], t->tda9887_data[3]);
+	struct tda9887_priv *priv = t->priv;
+	tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", priv->data[1], priv->data[2], priv->data[3]);
 }
 
-static int tda9887_get_afc(struct i2c_client *client)
+static int tda9887_get_afc(struct tuner *t)
 {
-	struct tuner *t = i2c_get_clientdata(client);
+	struct tda9887_priv *priv = t->priv;
 	static int AFC_BITS_2_kHz[] = {
 		-12500,  -37500,  -62500,  -97500,
 		-112500, -137500, -162500, -187500,
@@ -570,36 +588,55 @@
 	int afc=0;
 	__u8 reg = 0;
 
-	if (1 == i2c_master_recv(&t->i2c,&reg,1))
+	if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,&reg,1))
 		afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
 
 	return afc;
 }
 
-static void tda9887_standby(struct i2c_client *client)
+static void tda9887_standby(struct tuner *t)
 {
-	tda9887_configure(client);
+	tda9887_configure(t);
 }
 
-static void tda9887_set_freq(struct i2c_client *client, unsigned int freq)
+static void tda9887_set_freq(struct tuner *t, unsigned int freq)
 {
-	tda9887_configure(client);
+	tda9887_configure(t);
 }
 
-int tda9887_tuner_init(struct i2c_client *c)
+static void tda9887_release(struct tuner *t)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	kfree(t->priv);
+	t->priv = NULL;
+}
 
-	strlcpy(c->name, "tda9887", sizeof(c->name));
+static struct tuner_operations tda9887_tuner_ops = {
+	.set_tv_freq    = tda9887_set_freq,
+	.set_radio_freq = tda9887_set_freq,
+	.standby        = tda9887_standby,
+	.tuner_status   = tda9887_tuner_status,
+	.get_afc        = tda9887_get_afc,
+	.release        = tda9887_release,
+};
+
+int tda9887_tuner_init(struct tuner *t)
+{
+	struct tda9887_priv *priv = NULL;
+
+	priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return -ENOMEM;
+	t->priv = priv;
+
+	priv->i2c_props.addr = t->i2c.addr;
+	priv->i2c_props.adap = t->i2c.adapter;
+
+	strlcpy(t->i2c.name, "tda9887", sizeof(t->i2c.name));
 
 	tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
 						t->i2c.driver->driver.name);
 
-	t->set_tv_freq = tda9887_set_freq;
-	t->set_radio_freq = tda9887_set_freq;
-	t->standby = tda9887_standby;
-	t->tuner_status = tda9887_tuner_status;
-	t->get_afc = tda9887_get_afc;
+	memcpy(&t->ops, &tda9887_tuner_ops, sizeof(struct tuner_operations));
 
 	return 0;
 }
diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c
new file mode 100644
index 0000000..2150222
--- /dev/null
+++ b/drivers/media/video/tea5761.c
@@ -0,0 +1,320 @@
+/*
+ * For Philips TEA5761 FM Chip
+ * I2C address is allways 0x20 (0x10 at 7-bit mode).
+ *
+ * Copyright (c) 2005-2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This code is placed under the terms of the GNUv2 General Public License
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/videodev.h>
+#include <media/tuner.h>
+#include "tuner-i2c.h"
+#include "tea5761.h"
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+#define PREFIX "tea5761 "
+
+struct tea5761_priv {
+	struct tuner_i2c_props i2c_props;
+
+	u32 frequency;
+};
+
+/*****************************************************************************/
+
+/***************************
+ * TEA5761HN I2C registers *
+ ***************************/
+
+/* INTREG - Read: bytes 0 and 1 / Write: byte 0 */
+
+	/* first byte for reading */
+#define TEA5761_INTREG_IFFLAG		0x10
+#define TEA5761_INTREG_LEVFLAG		0x8
+#define TEA5761_INTREG_FRRFLAG		0x2
+#define TEA5761_INTREG_BLFLAG		0x1
+
+	/* second byte for reading / byte for writing */
+#define TEA5761_INTREG_IFMSK		0x10
+#define TEA5761_INTREG_LEVMSK		0x8
+#define TEA5761_INTREG_FRMSK		0x2
+#define TEA5761_INTREG_BLMSK		0x1
+
+/* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */
+
+	/* First byte */
+#define TEA5761_FRQSET_SEARCH_UP 0x80		/* 1=Station search from botton to up */
+#define TEA5761_FRQSET_SEARCH_MODE 0x40		/* 1=Search mode */
+
+	/* Bits 0-5 for divider MSB */
+
+	/* Second byte */
+	/* Bits 0-7 for divider LSB */
+
+/* TNCTRL - Read: bytes 4 and 5 / Write: Bytes 3 and 4 */
+
+	/* first byte */
+
+#define TEA5761_TNCTRL_PUPD_0	0x40	/* Power UP/Power Down MSB */
+#define TEA5761_TNCTRL_BLIM	0X20	/* 1= Japan Frequencies, 0= European frequencies */
+#define TEA5761_TNCTRL_SWPM	0x10	/* 1= software port is FRRFLAG */
+#define TEA5761_TNCTRL_IFCTC	0x08	/* 1= IF count time 15.02 ms, 0= IF count time 2.02 ms */
+#define TEA5761_TNCTRL_AFM	0x04
+#define TEA5761_TNCTRL_SMUTE	0x02	/* 1= Soft mute */
+#define TEA5761_TNCTRL_SNC	0x01
+
+	/* second byte */
+
+#define TEA5761_TNCTRL_MU	0x80	/* 1=Hard mute */
+#define TEA5761_TNCTRL_SSL_1	0x40
+#define TEA5761_TNCTRL_SSL_0	0x20
+#define TEA5761_TNCTRL_HLSI	0x10
+#define TEA5761_TNCTRL_MST	0x08	/* 1 = mono */
+#define TEA5761_TNCTRL_SWP	0x04
+#define TEA5761_TNCTRL_DTC	0x02	/* 1 = deemphasis 50 us, 0 = deemphasis 75 us */
+#define TEA5761_TNCTRL_AHLSI	0x01
+
+/* FRQCHECK - Read: bytes 6 and 7  */
+	/* First byte */
+
+	/* Bits 0-5 for divider MSB */
+
+	/* Second byte */
+	/* Bits 0-7 for divider LSB */
+
+/* TUNCHECK - Read: bytes 8 and 9  */
+
+	/* First byte */
+#define TEA5761_TUNCHECK_IF_MASK	0x7e	/* IF count */
+#define TEA5761_TUNCHECK_TUNTO		0x01
+
+	/* Second byte */
+#define TEA5761_TUNCHECK_LEV_MASK	0xf0	/* Level Count */
+#define TEA5761_TUNCHECK_LD		0x08
+#define TEA5761_TUNCHECK_STEREO		0x04
+
+/* TESTREG - Read: bytes 10 and 11 / Write: bytes 5 and 6 */
+
+	/* All zero = no test mode */
+
+/* MANID - Read: bytes 12 and 13 */
+
+	/* First byte - should be 0x10 */
+#define TEA5767_MANID_VERSION_MASK	0xf0	/* Version = 1 */
+#define TEA5767_MANID_ID_MSB_MASK	0x0f	/* Manufacurer ID - should be 0 */
+
+	/* Second byte - Should be 0x2b */
+
+#define TEA5767_MANID_ID_LSB_MASK	0xfe	/* Manufacturer ID - should be 0x15 */
+#define TEA5767_MANID_IDAV		0x01	/* 1 = Chip has ID, 0 = Chip has no ID */
+
+/* Chip ID - Read: bytes 14 and 15 */
+
+	/* First byte - should be 0x57 */
+
+	/* Second byte - should be 0x61 */
+
+/*****************************************************************************/
+
+#define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */
+static void tea5761_status_dump(unsigned char *buffer)
+{
+	unsigned int div, frq;
+
+	div = ((buffer[2] & 0x3f) << 8) | buffer[3];
+
+	frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4;	/* Freq in KHz */
+
+	printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n",
+	       frq / 1000, frq % 1000, div);
+}
+
+/* Freq should be specifyed at 62.5 Hz */
+static int set_radio_freq(struct dvb_frontend *fe,
+			  struct analog_parameters *params)
+{
+	struct tea5761_priv *priv = fe->tuner_priv;
+	unsigned int frq = params->frequency;
+	unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 };
+	unsigned div;
+	int rc;
+
+	tuner_dbg("radio freq counter %d\n", frq);
+
+	if (params->mode == T_STANDBY) {
+		tuner_dbg("TEA5761 set to standby mode\n");
+		buffer[5] |= TEA5761_TNCTRL_MU;
+	} else {
+		buffer[4] |= TEA5761_TNCTRL_PUPD_0;
+	}
+
+
+	if (params->audmode == V4L2_TUNER_MODE_MONO) {
+		tuner_dbg("TEA5761 set to mono\n");
+		buffer[5] |= TEA5761_TNCTRL_MST;
+	} else {
+		tuner_dbg("TEA5761 set to stereo\n");
+	}
+
+	div = (1000 * (frq * 4 / 16 + 700 + 225) ) >> 15;
+	buffer[1] = (div >> 8) & 0x3f;
+	buffer[2] = div & 0xff;
+
+	if (debug)
+		tea5761_status_dump(buffer);
+
+	if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7)))
+		tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+	priv->frequency = frq * 125 / 2;
+
+	return 0;
+}
+
+static int tea5761_read_status(struct dvb_frontend *fe, char *buffer)
+{
+	struct tea5761_priv *priv = fe->tuner_priv;
+	int rc;
+
+	memset(buffer, 0, 16);
+	if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) {
+		tuner_warn("i2c i/o error: rc == %d (should be 16)\n", rc);
+		return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static inline int tea5761_signal(struct dvb_frontend *fe, const char *buffer)
+{
+	struct tea5761_priv *priv = fe->tuner_priv;
+
+	int signal = ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4));
+
+	tuner_dbg("Signal strength: %d\n", signal);
+
+	return signal;
+}
+
+static inline int tea5761_stereo(struct dvb_frontend *fe, const char *buffer)
+{
+	struct tea5761_priv *priv = fe->tuner_priv;
+
+	int stereo = buffer[9] & TEA5761_TUNCHECK_STEREO;
+
+	tuner_dbg("Radio ST GET = %02x\n", stereo);
+
+	return (stereo ? V4L2_TUNER_SUB_STEREO : 0);
+}
+
+static int tea5761_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	unsigned char buffer[16];
+
+	*status = 0;
+
+	if (0 == tea5761_read_status(fe, buffer)) {
+		if (tea5761_signal(fe, buffer))
+			*status = TUNER_STATUS_LOCKED;
+		if (tea5761_stereo(fe, buffer))
+			*status |= TUNER_STATUS_STEREO;
+	}
+
+	return 0;
+}
+
+static int tea5761_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	unsigned char buffer[16];
+
+	*strength = 0;
+
+	if (0 == tea5761_read_status(fe, buffer))
+		*strength = tea5761_signal(fe, buffer);
+
+	return 0;
+}
+
+int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
+{
+	unsigned char buffer[16];
+	int rc;
+	struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr };
+
+	if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) {
+		printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc);
+		return EINVAL;
+	}
+
+	if (!((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061))) {
+		printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]);
+		return EINVAL;
+	}
+	printk(KERN_WARNING "TEA5761 detected.\n");
+	return 0;
+}
+
+static int tea5761_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tea5761_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static struct dvb_tuner_ops tea5761_tuner_ops = {
+	.info = {
+		.name           = "tea5761", // Philips TEA5761HN FM Radio
+	},
+	.set_analog_params = set_radio_freq,
+	.release           = tea5761_release,
+	.get_frequency     = tea5761_get_frequency,
+	.get_status        = tea5761_get_status,
+	.get_rf_strength   = tea5761_get_rf_strength,
+};
+
+struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
+				    struct i2c_adapter* i2c_adap,
+				    u8 i2c_addr)
+{
+	struct tea5761_priv *priv = NULL;
+
+	if (tea5761_autodetection(i2c_adap, i2c_addr) == EINVAL)
+		return NULL;
+
+	priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+	fe->tuner_priv = priv;
+
+	priv->i2c_props.addr = i2c_addr;
+	priv->i2c_props.adap = i2c_adap;
+
+	memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+	tuner_info("type set to %s\n", "Philips TEA5761HN FM Radio");
+
+	return fe;
+}
+
+
+EXPORT_SYMBOL_GPL(tea5761_attach);
+EXPORT_SYMBOL_GPL(tea5761_autodetection);
+
+MODULE_DESCRIPTION("Philips TEA5761 FM tuner driver");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tea5761.h b/drivers/media/video/tea5761.h
new file mode 100644
index 0000000..73a03b4
--- /dev/null
+++ b/drivers/media/video/tea5761.h
@@ -0,0 +1,47 @@
+/*
+    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.
+*/
+
+#ifndef __TEA5761_H__
+#define __TEA5761_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
+extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
+
+extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
+					   struct i2c_adapter* i2c_adap,
+					   u8 i2c_addr);
+#else
+static inline int tea5761_autodetection(struct i2c_adapter* i2c_adap,
+					u8 i2c_addr)
+{
+	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+	       __FUNCTION__);
+	return -EINVAL;
+}
+
+static inline struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
+						   struct i2c_adapter* i2c_adap,
+						   u8 i2c_addr)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif
+
+#endif /* __TEA5761_H__ */
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index d1c4178..71df419 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/video/tea5767.c
@@ -11,14 +11,22 @@
  */
 
 #include <linux/i2c.h>
-#include <linux/videodev.h>
 #include <linux/delay.h>
-#include <media/tuner.h>
+#include <linux/videodev.h>
+#include "tuner-i2c.h"
+#include "tea5767.h"
 
-#define PREFIX "TEA5767 "
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
 
-/* from tuner-core.c */
-extern int tuner_debug;
+#define PREFIX "tea5767 "
+
+struct tea5767_priv {
+	struct tuner_i2c_props i2c_props;
+
+	u32 frequency;
+};
 
 /*****************************************************************************/
 
@@ -129,13 +137,6 @@
 
 /*****************************************************************************/
 
-static void set_tv_freq(struct i2c_client *c, unsigned int freq)
-{
-	struct tuner *t = i2c_get_clientdata(c);
-
-	tuner_warn("This tuner doesn't support TV freq.\n");
-}
-
 static void tea5767_status_dump(unsigned char *buffer)
 {
 	unsigned int div, frq;
@@ -190,14 +191,16 @@
 }
 
 /* Freq should be specifyed at 62.5 Hz */
-static void set_radio_freq(struct i2c_client *c, unsigned int frq)
+static int set_radio_freq(struct dvb_frontend *fe,
+			  struct analog_parameters *params)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	struct tea5767_priv *priv = fe->tuner_priv;
+	unsigned int frq = params->frequency;
 	unsigned char buffer[5];
 	unsigned div;
 	int rc;
 
-	tuner_dbg (PREFIX "radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000);
+	tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000);
 
 	/* Rounds freq to next decimal value - for 62.5 KHz step */
 	/* frq = 20*(frq/16)+radio_frq[frq%16]; */
@@ -207,7 +210,7 @@
 		    TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND;
 	buffer[4] = 0;
 
-	if (t->audmode == V4L2_TUNER_MODE_MONO) {
+	if (params->audmode == V4L2_TUNER_MODE_MONO) {
 		tuner_dbg("TEA5767 set to mono\n");
 		buffer[2] |= TEA5767_MONO;
 	} else {
@@ -217,26 +220,26 @@
 	/* Should be replaced */
 	switch (TEA5767_HIGH_LO_32768) {
 	case TEA5767_HIGH_LO_13MHz:
-		tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n");
+		tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n");
 		buffer[2] |= TEA5767_HIGH_LO_INJECT;
 		buffer[4] |= TEA5767_PLLREF_ENABLE;
 		div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000;
 		break;
 	case TEA5767_LOW_LO_13MHz:
-		tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 13 MHz\n");
+		tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n");
 
 		buffer[4] |= TEA5767_PLLREF_ENABLE;
 		div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000;
 		break;
 	case TEA5767_LOW_LO_32768:
-		tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n");
+		tuner_dbg("radio LOW LO inject xtal @ 32,768 MHz\n");
 		buffer[3] |= TEA5767_XTAL_32768;
 		/* const 700=4000*175 Khz - to adjust freq to right value */
 		div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15;
 		break;
 	case TEA5767_HIGH_LO_32768:
 	default:
-		tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 32,768 MHz\n");
+		tuner_dbg("radio HIGH LO inject xtal @ 32,768 MHz\n");
 
 		buffer[2] |= TEA5767_HIGH_LO_INJECT;
 		buffer[3] |= TEA5767_XTAL_32768;
@@ -246,51 +249,89 @@
 	buffer[0] = (div >> 8) & 0x3f;
 	buffer[1] = div & 0xff;
 
-	if (5 != (rc = i2c_master_send(c, buffer, 5)))
+	if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5)))
 		tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
 
-	if (tuner_debug) {
-		if (5 != (rc = i2c_master_recv(c, buffer, 5)))
+	if (debug) {
+		if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5)))
 			tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
 		else
 			tea5767_status_dump(buffer);
 	}
+
+	priv->frequency = frq * 125 / 2;
+
+	return 0;
 }
 
-static int tea5767_signal(struct i2c_client *c)
+static int tea5767_read_status(struct dvb_frontend *fe, char *buffer)
 {
-	unsigned char buffer[5];
+	struct tea5767_priv *priv = fe->tuner_priv;
 	int rc;
-	struct tuner *t = i2c_get_clientdata(c);
 
-	memset(buffer, 0, sizeof(buffer));
-	if (5 != (rc = i2c_master_recv(c, buffer, 5)))
+	memset(buffer, 0, 5);
+	if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) {
 		tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+		return -EREMOTEIO;
+	}
 
-	return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8);
+	return 0;
 }
 
-static int tea5767_stereo(struct i2c_client *c)
+static inline int tea5767_signal(struct dvb_frontend *fe, const char *buffer)
 {
-	unsigned char buffer[5];
-	int rc;
-	struct tuner *t = i2c_get_clientdata(c);
+	struct tea5767_priv *priv = fe->tuner_priv;
 
-	memset(buffer, 0, sizeof(buffer));
-	if (5 != (rc = i2c_master_recv(c, buffer, 5)))
-		tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+	int signal = ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8);
 
-	rc = buffer[2] & TEA5767_STEREO_MASK;
+	tuner_dbg("Signal strength: %d\n", signal);
 
-	tuner_dbg("TEA5767 radio ST GET = %02x\n", rc);
-
-	return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0);
+	return signal;
 }
 
-static void tea5767_standby(struct i2c_client *c)
+static inline int tea5767_stereo(struct dvb_frontend *fe, const char *buffer)
+{
+	struct tea5767_priv *priv = fe->tuner_priv;
+
+	int stereo = buffer[2] & TEA5767_STEREO_MASK;
+
+	tuner_dbg("Radio ST GET = %02x\n", stereo);
+
+	return (stereo ? V4L2_TUNER_SUB_STEREO : 0);
+}
+
+static int tea5767_get_status(struct dvb_frontend *fe, u32 *status)
 {
 	unsigned char buffer[5];
-	struct tuner *t = i2c_get_clientdata(c);
+
+	*status = 0;
+
+	if (0 == tea5767_read_status(fe, buffer)) {
+		if (tea5767_signal(fe, buffer))
+			*status = TUNER_STATUS_LOCKED;
+		if (tea5767_stereo(fe, buffer))
+			*status |= TUNER_STATUS_STEREO;
+	}
+
+	return 0;
+}
+
+static int tea5767_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	unsigned char buffer[5];
+
+	*strength = 0;
+
+	if (0 == tea5767_read_status(fe, buffer))
+		*strength = tea5767_signal(fe, buffer);
+
+	return 0;
+}
+
+static int tea5767_standby(struct dvb_frontend *fe)
+{
+	unsigned char buffer[5];
+	struct tea5767_priv *priv = fe->tuner_priv;
 	unsigned div, rc;
 
 	div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */
@@ -301,25 +342,27 @@
 		    TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY;
 	buffer[4] = 0;
 
-	if (5 != (rc = i2c_master_send(c, buffer, 5)))
+	if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5)))
 		tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+	return 0;
 }
 
-int tea5767_autodetection(struct i2c_client *c)
+int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
 {
+	struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr };
 	unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 	int rc;
-	struct tuner *t = i2c_get_clientdata(c);
 
-	if ((rc = i2c_master_recv(c, buffer, 7))< 5) {
-		tuner_warn("It is not a TEA5767. Received %i bytes.\n", rc);
+	if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) {
+		printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc);
 		return EINVAL;
 	}
 
 	/* If all bytes are the same then it's a TV tuner and not a tea5767 */
 	if (buffer[0] == buffer[1] && buffer[0] == buffer[2] &&
 	    buffer[0] == buffer[3] && buffer[0] == buffer[4]) {
-		tuner_warn("All bytes are equal. It is not a TEA5767\n");
+		printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n");
 		return EINVAL;
 	}
 
@@ -329,32 +372,74 @@
 	 *  Byte 5: bit 7:0 : == 0
 	 */
 	if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) {
-		tuner_warn("Chip ID is not zero. It is not a TEA5767\n");
+		printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n");
 		return EINVAL;
 	}
 
 	/* It seems that tea5767 returns 0xff after the 5th byte */
 	if ((buffer[5] != 0xff) || (buffer[6] != 0xff)) {
-		tuner_warn("Returned more than 5 bytes. It is not a TEA5767\n");
+		printk(KERN_WARNING "Returned more than 5 bytes. It is not a TEA5767\n");
 		return EINVAL;
 	}
 
-	tuner_warn("TEA5767 detected.\n");
+	printk(KERN_WARNING "TEA5767 detected.\n");
 	return 0;
 }
 
-int tea5767_tuner_init(struct i2c_client *c)
+static int tea5767_release(struct dvb_frontend *fe)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
 
-	tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio");
-	strlcpy(c->name, "tea5767", sizeof(c->name));
-
-	t->set_tv_freq = set_tv_freq;
-	t->set_radio_freq = set_radio_freq;
-	t->has_signal = tea5767_signal;
-	t->is_stereo = tea5767_stereo;
-	t->standby = tea5767_standby;
-
-	return (0);
+	return 0;
 }
+
+static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tea5767_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static struct dvb_tuner_ops tea5767_tuner_ops = {
+	.info = {
+		.name           = "tea5767", // Philips TEA5767HN FM Radio
+	},
+
+	.set_analog_params = set_radio_freq,
+	.sleep             = tea5767_standby,
+	.release           = tea5767_release,
+	.get_frequency     = tea5767_get_frequency,
+	.get_status        = tea5767_get_status,
+	.get_rf_strength   = tea5767_get_rf_strength,
+};
+
+struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
+				    struct i2c_adapter* i2c_adap,
+				    u8 i2c_addr)
+{
+	struct tea5767_priv *priv = NULL;
+
+	priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+	fe->tuner_priv = priv;
+
+	priv->i2c_props.addr = i2c_addr;
+	priv->i2c_props.adap = i2c_adap;
+
+	memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+	tuner_info("type set to %s\n", "Philips TEA5767HN FM Radio");
+
+	return fe;
+}
+
+
+EXPORT_SYMBOL_GPL(tea5767_attach);
+EXPORT_SYMBOL_GPL(tea5767_autodetection);
+
+MODULE_DESCRIPTION("Philips TEA5767 FM tuner driver");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tea5767.h b/drivers/media/video/tea5767.h
new file mode 100644
index 0000000..5d78281
--- /dev/null
+++ b/drivers/media/video/tea5767.h
@@ -0,0 +1,47 @@
+/*
+    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.
+*/
+
+#ifndef __TEA5767_H__
+#define __TEA5767_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE))
+extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
+
+extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
+					   struct i2c_adapter* i2c_adap,
+					   u8 i2c_addr);
+#else
+static inline int tea5767_autodetection(struct i2c_adapter* i2c_adap,
+					u8 i2c_addr)
+{
+	printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
+	       __FUNCTION__);
+	return -EINVAL;
+}
+
+static inline struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
+						   struct i2c_adapter* i2c_adap,
+						   u8 i2c_addr)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif
+
+#endif /* __TEA5767_H__ */
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 505591a..9484308 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -5,7 +5,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/timer.h>
@@ -15,16 +14,25 @@
 #include <linux/poll.h>
 #include <linux/i2c.h>
 #include <linux/types.h>
-#include <linux/videodev.h>
 #include <linux/init.h>
-
+#include <linux/videodev.h>
 #include <media/tuner.h>
+#include <media/tuner-types.h>
 #include <media/v4l2-common.h>
+#include "tuner-driver.h"
+#include "mt20xx.h"
+#include "tda8290.h"
+#include "tea5761.h"
+#include "tea5767.h"
+#include "tuner-simple.h"
 
 #define UNSET (-1U)
 
 /* standard i2c insmod options */
 static unsigned short normal_i2c[] = {
+#ifdef CONFIG_TUNER_TEA5761
+	0x10,
+#endif
 	0x42, 0x43, 0x4a, 0x4b,			/* tda8290 */
 	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
 	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
@@ -68,6 +76,51 @@
 
 /* ---------------------------------------------------------------------- */
 
+static void fe_set_freq(struct tuner *t, unsigned int freq)
+{
+	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+
+	struct analog_parameters params = {
+		.frequency = freq,
+		.mode      = t->mode,
+		.audmode   = t->audmode,
+		.std       = t->std
+	};
+
+	if (NULL == fe_tuner_ops->set_analog_params) {
+		tuner_warn("Tuner frontend module has no way to set freq\n");
+		return;
+	}
+	fe_tuner_ops->set_analog_params(&t->fe, &params);
+}
+
+static void fe_release(struct tuner *t)
+{
+	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+
+	if (fe_tuner_ops->release)
+		fe_tuner_ops->release(&t->fe);
+}
+
+static void fe_standby(struct tuner *t)
+{
+	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+
+	if (fe_tuner_ops->sleep)
+		fe_tuner_ops->sleep(&t->fe);
+}
+
+static int fe_has_signal(struct tuner *t)
+{
+	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
+	u16 strength;
+
+	if (fe_tuner_ops->get_rf_strength)
+		fe_tuner_ops->get_rf_strength(&t->fe, &strength);
+
+	return strength;
+}
+
 /* Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz */
 static void set_tv_freq(struct i2c_client *c, unsigned int freq)
 {
@@ -77,7 +130,7 @@
 		tuner_warn ("tuner type not set\n");
 		return;
 	}
-	if (NULL == t->set_tv_freq) {
+	if (NULL == t->ops.set_tv_freq) {
 		tuner_warn ("Tuner has no way to set tv freq\n");
 		return;
 	}
@@ -92,7 +145,7 @@
 		else
 			freq = tv_range[1] * 16;
 	}
-	t->set_tv_freq(c, freq);
+	t->ops.set_tv_freq(t, freq);
 }
 
 static void set_radio_freq(struct i2c_client *c, unsigned int freq)
@@ -103,7 +156,7 @@
 		tuner_warn ("tuner type not set\n");
 		return;
 	}
-	if (NULL == t->set_radio_freq) {
+	if (NULL == t->ops.set_radio_freq) {
 		tuner_warn ("tuner has no way to set radio frequency\n");
 		return;
 	}
@@ -119,7 +172,7 @@
 			freq = radio_range[1] * 16000;
 	}
 
-	t->set_radio_freq(c, freq);
+	t->ops.set_radio_freq(t, freq);
 }
 
 static void set_freq(struct i2c_client *c, unsigned long freq)
@@ -143,11 +196,51 @@
 	}
 }
 
+static void tuner_i2c_address_check(struct tuner *t)
+{
+	if ((t->type == UNSET || t->type == TUNER_ABSENT) ||
+	    ((t->i2c.addr < 0x64) || (t->i2c.addr > 0x6f)))
+		return;
+
+	tuner_warn("====================== WARNING! ======================\n");
+	tuner_warn("Support for tuners in i2c address range 0x64 thru 0x6f\n");
+	tuner_warn("will soon be dropped. This message indicates that your\n");
+	tuner_warn("hardware has a %s tuner at i2c address 0x%02x.\n",
+		   t->i2c.name, t->i2c.addr);
+	tuner_warn("To ensure continued support for your device, please\n");
+	tuner_warn("send a copy of this message, along with full dmesg\n");
+	tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
+	tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
+	tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
+		   t->i2c.adapter->name, t->i2c.addr, t->type,
+		   tuners[t->type].name);
+	tuner_warn("====================== WARNING! ======================\n");
+}
+
+static void attach_tda8290(struct tuner *t)
+{
+	struct tda8290_config cfg = {
+		.lna_cfg        = &t->config,
+		.tuner_callback = t->tuner_callback
+	};
+	tda8290_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg);
+}
+
+static void attach_simple_tuner(struct tuner *t)
+{
+	struct simple_tuner_config cfg = {
+		.type = t->type,
+		.tun  = &tuners[t->type]
+	};
+	simple_tuner_attach(&t->fe, t->i2c.adapter, t->i2c.addr, &cfg);
+}
+
 static void set_type(struct i2c_client *c, unsigned int type,
 		     unsigned int new_mode_mask, unsigned int new_config,
 		     int (*tuner_callback) (void *dev, int command,int arg))
 {
 	struct tuner *t = i2c_get_clientdata(c);
+	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
 	unsigned char buffer[4];
 
 	if (type == UNSET || type == TUNER_ABSENT) {
@@ -174,21 +267,41 @@
 		return;
 	}
 
+	/* discard private data, in case set_type() was previously called */
+	if (t->ops.release)
+		t->ops.release(t);
+	else {
+		kfree(t->priv);
+		t->priv = NULL;
+	}
+
 	switch (t->type) {
 	case TUNER_MT2032:
-		microtune_init(c);
+		microtune_attach(&t->fe, t->i2c.adapter, t->i2c.addr);
 		break;
 	case TUNER_PHILIPS_TDA8290:
-		tda8290_init(c);
+	{
+		attach_tda8290(t);
 		break;
+	}
 	case TUNER_TEA5767:
-		if (tea5767_tuner_init(c) == EINVAL) {
+		if (tea5767_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) {
 			t->type = TUNER_ABSENT;
 			t->mode_mask = T_UNINITIALIZED;
 			return;
 		}
 		t->mode_mask = T_RADIO;
 		break;
+#ifdef CONFIG_TUNER_TEA5761
+	case TUNER_TEA5761:
+		if (tea5761_attach(&t->fe, t->i2c.adapter, t->i2c.addr) == NULL) {
+			t->type = TUNER_ABSENT;
+			t->mode_mask = T_UNINITIALIZED;
+			return;
+		}
+		t->mode_mask = T_RADIO;
+		break;
+#endif
 	case TUNER_PHILIPS_FMD1216ME_MK3:
 		buffer[0] = 0x0b;
 		buffer[1] = 0xdc;
@@ -199,7 +312,7 @@
 		buffer[2] = 0x86;
 		buffer[3] = 0x54;
 		i2c_master_send(c, buffer, 4);
-		default_tuner_init(c);
+		attach_simple_tuner(t);
 		break;
 	case TUNER_PHILIPS_TD1316:
 		buffer[0] = 0x0b;
@@ -207,16 +320,28 @@
 		buffer[2] = 0x86;
 		buffer[3] = 0xa4;
 		i2c_master_send(c,buffer,4);
-		default_tuner_init(c);
+		attach_simple_tuner(t);
 		break;
 	case TUNER_TDA9887:
-		tda9887_tuner_init(c);
+		tda9887_tuner_init(t);
 		break;
 	default:
-		default_tuner_init(c);
+		attach_simple_tuner(t);
 		break;
 	}
 
+	if (fe_tuner_ops->set_analog_params) {
+		strlcpy(t->i2c.name, fe_tuner_ops->info.name, sizeof(t->i2c.name));
+
+		t->ops.set_tv_freq    = fe_set_freq;
+		t->ops.set_radio_freq = fe_set_freq;
+		t->ops.standby        = fe_standby;
+		t->ops.release        = fe_release;
+		t->ops.has_signal     = fe_has_signal;
+	}
+
+	tuner_info("type set to %s\n", t->i2c.name);
+
 	if (t->mode_mask == T_UNINITIALIZED)
 		t->mode_mask = new_mode_mask;
 
@@ -224,6 +349,7 @@
 	tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
 		  c->adapter->name, c->driver->driver.name, c->addr << 1, type,
 		  t->mode_mask);
+	tuner_i2c_address_check(t);
 }
 
 /*
@@ -384,10 +510,10 @@
 	return 0;
 }
 
-static void tuner_status(struct i2c_client *client)
+static void tuner_status(struct tuner *t)
 {
-	struct tuner *t = i2c_get_clientdata(client);
 	unsigned long freq, freq_fraction;
+	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
 	const char *p;
 
 	switch (t->mode) {
@@ -408,11 +534,20 @@
 	tuner_info("Standard:        0x%08lx\n", (unsigned long)t->std);
 	if (t->mode != V4L2_TUNER_RADIO)
 	       return;
-	if (t->has_signal) {
-		tuner_info("Signal strength: %d\n", t->has_signal(client));
+	if (fe_tuner_ops->get_status) {
+		u32 tuner_status;
+
+		fe_tuner_ops->get_status(&t->fe, &tuner_status);
+		if (tuner_status & TUNER_STATUS_LOCKED)
+			tuner_info("Tuner is locked.\n");
+		if (tuner_status & TUNER_STATUS_STEREO)
+			tuner_info("Stereo:          yes\n");
 	}
-	if (t->is_stereo) {
-		tuner_info("Stereo:          %s\n", t->is_stereo(client) ? "yes" : "no");
+	if (t->ops.has_signal) {
+		tuner_info("Signal strength: %d\n", t->ops.has_signal(t));
+	}
+	if (t->ops.is_stereo) {
+		tuner_info("Stereo:          %s\n", t->ops.is_stereo(t) ? "yes" : "no");
 	}
 }
 
@@ -437,10 +572,9 @@
 	memcpy(&t->i2c, &client_template, sizeof(struct i2c_client));
 	i2c_set_clientdata(&t->i2c, t);
 	t->type = UNSET;
-	t->radio_if2 = 10700 * 1000;	/* 10.7MHz - FM radio */
 	t->audmode = V4L2_TUNER_MODE_STEREO;
 	t->mode_mask = T_UNINITIALIZED;
-	t->tuner_status = tuner_status;
+	t->ops.tuner_status = tuner_status;
 
 	if (show_i2c) {
 		unsigned char buffer[16];
@@ -460,13 +594,26 @@
 	/* autodetection code based on the i2c addr */
 	if (!no_autodetect) {
 		switch (addr) {
+#ifdef CONFIG_TUNER_TEA5761
+		case 0x10:
+			if (tea5761_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) {
+				t->type = TUNER_TEA5761;
+				t->mode_mask = T_RADIO;
+				t->mode = T_STANDBY;
+				t->radio_freq = 87.5 * 16000; /* Sets freq to FM range */
+				default_mode_mask &= ~T_RADIO;
+
+				goto register_client;
+			}
+			break;
+#endif
 		case 0x42:
 		case 0x43:
 		case 0x4a:
 		case 0x4b:
 			/* If chip is not tda8290, don't register.
 			   since it can be tda9887*/
-			if (tda8290_probe(&t->i2c) == 0) {
+			if (tda8290_probe(t->i2c.adapter, t->i2c.addr) == 0) {
 				tuner_dbg("chip at addr %x is a tda8290\n", addr);
 			} else {
 				/* Default is being tda9887 */
@@ -477,7 +624,7 @@
 			}
 			break;
 		case 0x60:
-			if (tea5767_autodetection(&t->i2c) != EINVAL) {
+			if (tea5767_autodetection(t->i2c.adapter, t->i2c.addr) != EINVAL) {
 				t->type = TUNER_TEA5767;
 				t->mode_mask = T_RADIO;
 				t->mode = T_STANDBY;
@@ -514,6 +661,28 @@
 		normal_i2c[1] = I2C_CLIENT_END;
 	}
 
+	/* HACK: Ignore 0x6b and 0x6f on cx88 boards.
+	 * FusionHDTV5 RT Gold has an ir receiver at 0x6b
+	 * and an RTC at 0x6f which can get corrupted if probed.
+	 */
+	if ((adap->id == I2C_HW_B_CX2388x) ||
+	    (adap->id == I2C_HW_B_CX23885)) {
+		unsigned int i = 0;
+
+		while (i < I2C_CLIENT_MAX_OPTS && ignore[i] != I2C_CLIENT_END)
+			i += 2;
+		if (i + 4 < I2C_CLIENT_MAX_OPTS) {
+			ignore[i+0] = adap->nr;
+			ignore[i+1] = 0x6b;
+			ignore[i+2] = adap->nr;
+			ignore[i+3] = 0x6f;
+			ignore[i+4] = I2C_CLIENT_END;
+		} else
+			printk(KERN_WARNING "tuner: "
+			       "too many options specified "
+			       "in i2c probe ignore list!\n");
+	}
+
 	default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
 
 	if (adap->class & I2C_CLASS_TV_ANALOG)
@@ -533,6 +702,11 @@
 		return err;
 	}
 
+	if (t->ops.release)
+		t->ops.release(t);
+	else {
+		kfree(t->priv);
+	}
 	kfree(t);
 	return 0;
 }
@@ -553,8 +727,8 @@
 
 	if (check_mode(t, cmd) == EINVAL) {
 		t->mode = T_STANDBY;
-		if (t->standby)
-			t->standby (client);
+		if (t->ops.standby)
+			t->ops.standby(t);
 		return EINVAL;
 	}
 	return 0;
@@ -576,6 +750,7 @@
 static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
 	struct tuner *t = i2c_get_clientdata(client);
+	struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
 
 	if (tuner_debug>1)
 		v4l_i2c_print_ioctl(&(t->i2c),cmd);
@@ -602,8 +777,8 @@
 		if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
 			return 0;
 		t->mode = T_STANDBY;
-		if (t->standby)
-			t->standby (client);
+		if (t->ops.standby)
+			t->ops.standby(t);
 		break;
 #ifdef CONFIG_VIDEO_V4L1
 	case VIDIOCSAUDIO:
@@ -662,16 +837,27 @@
 				return 0;
 
 			if (V4L2_TUNER_RADIO == t->mode) {
-				if (t->has_signal)
-					vt->signal = t->has_signal(client);
-				if (t->is_stereo) {
-					if (t->is_stereo(client))
-						vt->flags |=
-						    VIDEO_TUNER_STEREO_ON;
+				if (fe_tuner_ops->get_status) {
+					u32 tuner_status;
+
+					fe_tuner_ops->get_status(&t->fe, &tuner_status);
+					if (tuner_status & TUNER_STATUS_STEREO)
+						vt->flags |= VIDEO_TUNER_STEREO_ON;
 					else
-						vt->flags &=
-						    ~VIDEO_TUNER_STEREO_ON;
+						vt->flags &= ~VIDEO_TUNER_STEREO_ON;
+				} else {
+					if (t->ops.is_stereo) {
+						if (t->ops.is_stereo(t))
+							vt->flags |=
+								VIDEO_TUNER_STEREO_ON;
+						else
+							vt->flags &=
+								~VIDEO_TUNER_STEREO_ON;
+					}
 				}
+				if (t->ops.has_signal)
+					vt->signal = t->ops.has_signal(t);
+
 				vt->flags |= VIDEO_TUNER_LOW;	/* Allow freqs at 62.5 Hz */
 
 				vt->rangelow = radio_range[0] * 16000;
@@ -693,9 +879,17 @@
 			if (check_v4l2(t) == EINVAL)
 				return 0;
 
-			if (V4L2_TUNER_RADIO == t->mode && t->is_stereo)
-				va->mode = t->is_stereo(client)
-				    ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+			if (V4L2_TUNER_RADIO == t->mode) {
+				if (fe_tuner_ops->get_status) {
+					u32 tuner_status;
+
+					fe_tuner_ops->get_status(&t->fe, &tuner_status);
+					va->mode = (tuner_status & TUNER_STATUS_STEREO)
+					    ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+				} else if (t->ops.is_stereo)
+					va->mode = t->ops.is_stereo(t)
+					    ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+			}
 			return 0;
 		}
 #endif
@@ -746,6 +940,15 @@
 				return 0;
 			switch_v4l2();
 			f->type = t->mode;
+			if (fe_tuner_ops->get_frequency) {
+				u32 abs_freq;
+
+				fe_tuner_ops->get_frequency(&t->fe, &abs_freq);
+				f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
+					(abs_freq * 2 + 125/2) / 125 :
+					(abs_freq + 62500/2) / 62500;
+				break;
+			}
 			f->frequency = (V4L2_TUNER_RADIO == t->mode) ?
 				t->radio_freq : t->tv_freq;
 			break;
@@ -759,8 +962,8 @@
 			switch_v4l2();
 
 			tuner->type = t->mode;
-			if (t->get_afc)
-				tuner->afc=t->get_afc(client);
+			if (t->ops.get_afc)
+				tuner->afc=t->ops.get_afc(t);
 			if (t->mode == V4L2_TUNER_ANALOG_TV)
 				tuner->capability |= V4L2_TUNER_CAP_NORM;
 			if (t->mode != V4L2_TUNER_RADIO) {
@@ -770,16 +973,22 @@
 			}
 
 			/* radio mode */
-			if (t->has_signal)
-				tuner->signal = t->has_signal(client);
-
 			tuner->rxsubchans =
 				V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-			if (t->is_stereo) {
-				tuner->rxsubchans = t->is_stereo(client) ?
-					V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
-			}
+			if (fe_tuner_ops->get_status) {
+				u32 tuner_status;
 
+				fe_tuner_ops->get_status(&t->fe, &tuner_status);
+				tuner->rxsubchans = (tuner_status & TUNER_STATUS_STEREO) ?
+					V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+			} else {
+				if (t->ops.is_stereo) {
+					tuner->rxsubchans = t->ops.is_stereo(t) ?
+						V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+				}
+			}
+			if (t->ops.has_signal)
+				tuner->signal = t->ops.has_signal(t);
 			tuner->capability |=
 			    V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
 			tuner->audmode = t->audmode;
@@ -804,8 +1013,8 @@
 			break;
 		}
 	case VIDIOC_LOG_STATUS:
-		if (t->tuner_status)
-			t->tuner_status(client);
+		if (t->ops.tuner_status)
+			t->ops.tuner_status(t);
 		break;
 	}
 
diff --git a/drivers/media/video/tuner-driver.h b/drivers/media/video/tuner-driver.h
new file mode 100644
index 0000000..28a10da
--- /dev/null
+++ b/drivers/media/video/tuner-driver.h
@@ -0,0 +1,99 @@
+/*
+    tuner-driver.h - interface for different tuners
+
+    Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de)
+    minor modifications by Ralph Metzler (rjkm@thp.uni-koeln.de)
+
+    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.
+*/
+
+#ifndef __TUNER_DRIVER_H__
+#define __TUNER_DRIVER_H__
+
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include "tuner-i2c.h"
+#include "dvb_frontend.h"
+
+extern unsigned const int tuner_count;
+
+struct tuner;
+
+struct tuner_operations {
+	void (*set_tv_freq)(struct tuner *t, unsigned int freq);
+	void (*set_radio_freq)(struct tuner *t, unsigned int freq);
+	int  (*has_signal)(struct tuner *t);
+	int  (*is_stereo)(struct tuner *t);
+	int  (*get_afc)(struct tuner *t);
+	void (*tuner_status)(struct tuner *t);
+	void (*standby)(struct tuner *t);
+	void (*release)(struct tuner *t);
+};
+
+struct tuner {
+	/* device */
+	struct i2c_client i2c;
+
+	unsigned int type;	/* chip type */
+
+	unsigned int mode;
+	unsigned int mode_mask;	/* Combination of allowable modes */
+
+	unsigned int tv_freq;	/* keep track of the current settings */
+	unsigned int radio_freq;
+	unsigned int audmode;
+	v4l2_std_id  std;
+
+	int          using_v4l2;
+	void *priv;
+
+	struct dvb_frontend fe;
+
+	/* used by tda9887 */
+	unsigned int       tda9887_config;
+
+	unsigned int config;
+	int (*tuner_callback) (void *dev, int command,int arg);
+
+	struct tuner_operations ops;
+};
+
+/* ------------------------------------------------------------------------ */
+
+extern int tda9887_tuner_init(struct tuner *t);
+
+/* ------------------------------------------------------------------------ */
+
+#define tuner_warn(fmt, arg...) do {\
+	printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+#define tuner_info(fmt, arg...) do {\
+	printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+#define tuner_dbg(fmt, arg...) do {\
+	extern int tuner_debug; \
+	if (tuner_debug) \
+		printk(KERN_DEBUG "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
+			i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+
+#endif /* __TUNER_DRIVER_H__ */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h
new file mode 100644
index 0000000..159019e
--- /dev/null
+++ b/drivers/media/video/tuner-i2c.h
@@ -0,0 +1,70 @@
+/*
+    tuner-i2c.h - i2c interface for different tuners
+
+    Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org)
+
+    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.
+*/
+
+#ifndef __TUNER_I2C_H__
+#define __TUNER_I2C_H__
+
+#include <linux/i2c.h>
+
+struct tuner_i2c_props {
+	u8 addr;
+	struct i2c_adapter *adap;
+};
+
+static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len)
+{
+	struct i2c_msg msg = { .addr = props->addr, .flags = 0,
+			       .buf = buf, .len = len };
+	int ret = i2c_transfer(props->adap, &msg, 1);
+
+	return (ret == 1) ? len : ret;
+}
+
+static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, int len)
+{
+	struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD,
+			       .buf = buf, .len = len };
+	int ret = i2c_transfer(props->adap, &msg, 1);
+
+	return (ret == 1) ? len : ret;
+}
+
+#ifndef __TUNER_DRIVER_H__
+#define tuner_warn(fmt, arg...) do {\
+	printk(KERN_WARNING PREFIX "%d-%04x: " fmt, \
+			i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
+#define tuner_info(fmt, arg...) do {\
+	printk(KERN_INFO PREFIX "%d-%04x: " fmt, \
+			i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
+#define tuner_dbg(fmt, arg...) do {\
+	if ((debug)) \
+		printk(KERN_DEBUG PREFIX "%d-%04x: " fmt, \
+			i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr , ##arg); } while (0)
+#endif /* __TUNER_DRIVER_H__ */
+
+#endif /* __TUNER_I2C_H__ */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index c40b92c..7b93d3b 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -1,13 +1,23 @@
 /*
- *
  * i2c tv tuner chip device driver
  * controls all those simple 4-control-bytes style tuners.
+ *
+ * This "tuner-simple" module was split apart from the original "tuner" module.
  */
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/videodev.h>
 #include <media/tuner.h>
 #include <media/v4l2-common.h>
+#include <media/tuner-types.h>
+#include "tuner-i2c.h"
+#include "tuner-simple.h"
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable verbose debug messages");
+
+#define PREFIX "tuner-simple "
 
 static int offset = 0;
 module_param(offset, int, 0664);
@@ -54,9 +64,9 @@
     sound 2          33.16  -      -
     NICAM            33.05  33.05  39.80
  */
-#define PHILIPS_MF_SET_BG	0x01 /* Bit 2 must be zero, Bit 3 is system output */
-#define PHILIPS_MF_SET_PAL_L	0x03 // France
-#define PHILIPS_MF_SET_PAL_L2	0x02 // L'
+#define PHILIPS_MF_SET_STD_BG	0x01 /* Bit 2 must be zero, Bit 3 is system output */
+#define PHILIPS_MF_SET_STD_L	0x03 /* Used on Secam France */
+#define PHILIPS_MF_SET_STD_LC	0x02 /* Used on SECAM L' */
 
 /* Control byte */
 
@@ -80,59 +90,102 @@
 #define TUNER_PLL_LOCKED   0x40
 #define TUNER_STEREO_MK3   0x04
 
+struct tuner_simple_priv {
+	u16 last_div;
+	struct tuner_i2c_props i2c_props;
+
+	unsigned int type;
+	struct tunertype *tun;
+
+	u32 frequency;
+};
+
 /* ---------------------------------------------------------------------- */
 
-static int tuner_getstatus(struct i2c_client *c)
+static int tuner_read_status(struct dvb_frontend *fe)
 {
+	struct tuner_simple_priv *priv = fe->tuner_priv;
 	unsigned char byte;
 
-	if (1 != i2c_master_recv(c,&byte,1))
+	if (1 != tuner_i2c_xfer_recv(&priv->i2c_props,&byte,1))
 		return 0;
 
 	return byte;
 }
 
-static int tuner_signal(struct i2c_client *c)
+static inline int tuner_signal(const int status)
 {
-	return (tuner_getstatus(c) & TUNER_SIGNAL) << 13;
+	return (status & TUNER_SIGNAL) << 13;
 }
 
-static int tuner_stereo(struct i2c_client *c)
+static inline int tuner_stereo(const int type, const int status)
 {
-	int stereo, status;
-	struct tuner *t = i2c_get_clientdata(c);
-
-	status = tuner_getstatus (c);
-
-	switch (t->type) {
+	switch (type) {
 		case TUNER_PHILIPS_FM1216ME_MK3:
 		case TUNER_PHILIPS_FM1236_MK3:
 		case TUNER_PHILIPS_FM1256_IH3:
 		case TUNER_LG_NTSC_TAPE:
-			stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
-			break;
+			return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
 		default:
-			stereo = status & TUNER_STEREO;
+			return status & TUNER_STEREO;
 	}
+}
 
-	return stereo;
+static inline int tuner_islocked(const int status)
+{
+	return (status & TUNER_FL);
+}
+
+static inline int tuner_afcstatus(const int status)
+{
+	return (status & TUNER_AFC) - 2;
 }
 
 
+static int simple_get_status(struct dvb_frontend *fe, u32 *status)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	int tuner_status = tuner_read_status(fe);
+
+	*status = 0;
+
+	if (tuner_islocked(tuner_status))
+		*status = TUNER_STATUS_LOCKED;
+	if (tuner_stereo(priv->type, tuner_status))
+		*status |= TUNER_STATUS_STEREO;
+
+	tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status));
+
+	return 0;
+}
+
+static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	int signal = tuner_signal(tuner_read_status(fe));
+
+	*strength = signal;
+
+	tuner_dbg("Signal strength: %d\n", signal);
+
+	return 0;
+}
+
 /* ---------------------------------------------------------------------- */
 
-static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
+static int simple_set_tv_freq(struct dvb_frontend *fe,
+			      struct analog_parameters *params)
 {
-	struct tuner *t = i2c_get_clientdata(c);
+	struct tuner_simple_priv *priv = fe->tuner_priv;
 	u8 config, cb, tuneraddr;
 	u16 div;
 	struct tunertype *tun;
 	u8 buffer[4];
 	int rc, IFPCoff, i, j;
 	enum param_type desired_type;
-	struct tuner_params *params;
+	struct tuner_params *t_params;
 
-	tun = &tuners[t->type];
+	tun = priv->tun;
 
 	/* IFPCoff = Video Intermediate Frequency - Vif:
 		940  =16*58.75  NTSC/J (Japan)
@@ -146,14 +199,14 @@
 		171.2=16*10.70  FM Radio (at set_radio_freq)
 	*/
 
-	if (t->std == V4L2_STD_NTSC_M_JP) {
+	if (params->std == V4L2_STD_NTSC_M_JP) {
 		IFPCoff      = 940;
 		desired_type = TUNER_PARAM_TYPE_NTSC;
-	} else if ((t->std & V4L2_STD_MN) &&
-		  !(t->std & ~V4L2_STD_MN)) {
+	} else if ((params->std & V4L2_STD_MN) &&
+		  !(params->std & ~V4L2_STD_MN)) {
 		IFPCoff      = 732;
 		desired_type = TUNER_PARAM_TYPE_NTSC;
-	} else if (t->std == V4L2_STD_SECAM_LC) {
+	} else if (params->std == V4L2_STD_SECAM_LC) {
 		IFPCoff      = 543;
 		desired_type = TUNER_PARAM_TYPE_SECAM;
 	} else {
@@ -166,67 +219,67 @@
 			continue;
 		break;
 	}
-	/* use default tuner_params if desired_type not available */
+	/* use default tuner_t_params if desired_type not available */
 	if (desired_type != tun->params[j].type) {
-		tuner_dbg("IFPCoff = %d: tuner_params undefined for tuner %d\n",
-			  IFPCoff,t->type);
+		tuner_dbg("IFPCoff = %d: tuner_t_params undefined for tuner %d\n",
+			  IFPCoff, priv->type);
 		j = 0;
 	}
-	params = &tun->params[j];
+	t_params = &tun->params[j];
 
-	for (i = 0; i < params->count; i++) {
-		if (freq > params->ranges[i].limit)
+	for (i = 0; i < t_params->count; i++) {
+		if (params->frequency > t_params->ranges[i].limit)
 			continue;
 		break;
 	}
-	if (i == params->count) {
+	if (i == t_params->count) {
 		tuner_dbg("TV frequency out of range (%d > %d)",
-				freq, params->ranges[i - 1].limit);
-		freq = params->ranges[--i].limit;
+				params->frequency, t_params->ranges[i - 1].limit);
+		params->frequency = t_params->ranges[--i].limit;
 	}
-	config = params->ranges[i].config;
-	cb     = params->ranges[i].cb;
+	config = t_params->ranges[i].config;
+	cb     = t_params->ranges[i].cb;
 	/*  i == 0 -> VHF_LO
 	 *  i == 1 -> VHF_HI
 	 *  i == 2 -> UHF     */
 	tuner_dbg("tv: param %d, range %d\n",j,i);
 
-	div=freq + IFPCoff + offset;
+	div=params->frequency + IFPCoff + offset;
 
 	tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n",
-					freq / 16, freq % 16 * 100 / 16,
+					params->frequency / 16, params->frequency % 16 * 100 / 16,
 					IFPCoff / 16, IFPCoff % 16 * 100 / 16,
 					offset / 16, offset % 16 * 100 / 16,
 					div);
 
 	/* tv norm specific stuff for multi-norm tuners */
-	switch (t->type) {
+	switch (priv->type) {
 	case TUNER_PHILIPS_SECAM: // FI1216MF
 		/* 0x01 -> ??? no change ??? */
 		/* 0x02 -> PAL BDGHI / SECAM L */
 		/* 0x04 -> ??? PAL others / SECAM others ??? */
 		cb &= ~0x03;
-		if (t->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM
-			cb |= PHILIPS_MF_SET_PAL_L;
-		else if (t->std & V4L2_STD_SECAM_LC)
-			cb |= PHILIPS_MF_SET_PAL_L2;
+		if (params->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM
+			cb |= PHILIPS_MF_SET_STD_L;
+		else if (params->std & V4L2_STD_SECAM_LC)
+			cb |= PHILIPS_MF_SET_STD_LC;
 		else /* V4L2_STD_B|V4L2_STD_GH */
-			cb |= PHILIPS_MF_SET_BG;
+			cb |= PHILIPS_MF_SET_STD_BG;
 		break;
 
 	case TUNER_TEMIC_4046FM5:
 		cb &= ~0x0f;
 
-		if (t->std & V4L2_STD_PAL_BG) {
+		if (params->std & V4L2_STD_PAL_BG) {
 			cb |= TEMIC_SET_PAL_BG;
 
-		} else if (t->std & V4L2_STD_PAL_I) {
+		} else if (params->std & V4L2_STD_PAL_I) {
 			cb |= TEMIC_SET_PAL_I;
 
-		} else if (t->std & V4L2_STD_PAL_DK) {
+		} else if (params->std & V4L2_STD_PAL_DK) {
 			cb |= TEMIC_SET_PAL_DK;
 
-		} else if (t->std & V4L2_STD_SECAM_L) {
+		} else if (params->std & V4L2_STD_SECAM_L) {
 			cb |= TEMIC_SET_PAL_L;
 
 		}
@@ -235,13 +288,13 @@
 	case TUNER_PHILIPS_FQ1216ME:
 		cb &= ~0x0f;
 
-		if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
+		if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
 			cb |= PHILIPS_SET_PAL_BGDK;
 
-		} else if (t->std & V4L2_STD_PAL_I) {
+		} else if (params->std & V4L2_STD_PAL_I) {
 			cb |= PHILIPS_SET_PAL_I;
 
-		} else if (t->std & V4L2_STD_SECAM_L) {
+		} else if (params->std & V4L2_STD_SECAM_L) {
 			cb |= PHILIPS_SET_PAL_L;
 
 		}
@@ -253,7 +306,7 @@
 		/* 0x02 -> NTSC antenna input 1 */
 		/* 0x03 -> NTSC antenna input 2 */
 		cb &= ~0x03;
-		if (!(t->std & V4L2_STD_ATSC))
+		if (!(params->std & V4L2_STD_ATSC))
 			cb |= 2;
 		/* FIXME: input */
 		break;
@@ -273,23 +326,23 @@
 		buffer[2] = 0x17;
 		buffer[3] = 0x00;
 		cb &= ~0x40;
-		if (t->std & V4L2_STD_ATSC) {
+		if (params->std & V4L2_STD_ATSC) {
 			cb |= 0x40;
 			buffer[1] = 0x04;
 		}
 		/* set to the correct mode (analog or digital) */
-		tuneraddr = c->addr;
-		c->addr = 0x0a;
-		if (2 != (rc = i2c_master_send(c,&buffer[0],2)))
+		tuneraddr = priv->i2c_props.addr;
+		priv->i2c_props.addr = 0x0a;
+		if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[0],2)))
 			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
-		if (2 != (rc = i2c_master_send(c,&buffer[2],2)))
+		if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[2],2)))
 			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
-		c->addr = tuneraddr;
+		priv->i2c_props.addr = tuneraddr;
 		/* FIXME: input */
 		break;
 	}
 
-	if (params->cb_first_if_lower_freq && div < t->last_div) {
+	if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
 		buffer[0] = config;
 		buffer[1] = cb;
 		buffer[2] = (div>>8) & 0x7f;
@@ -300,53 +353,53 @@
 		buffer[2] = config;
 		buffer[3] = cb;
 	}
-	t->last_div = div;
-	if (params->has_tda9887) {
+	priv->last_div = div;
+	if (t_params->has_tda9887) {
 		int config = 0;
-		int is_secam_l = (t->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) &&
-			!(t->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC));
+		int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) &&
+			!(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC));
 
-		if (t->std == V4L2_STD_SECAM_LC) {
-			if (params->port1_active ^ params->port1_invert_for_secam_lc)
+		if (params->std == V4L2_STD_SECAM_LC) {
+			if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc)
 				config |= TDA9887_PORT1_ACTIVE;
-			if (params->port2_active ^ params->port2_invert_for_secam_lc)
+			if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)
 				config |= TDA9887_PORT2_ACTIVE;
 		}
 		else {
-			if (params->port1_active)
+			if (t_params->port1_active)
 				config |= TDA9887_PORT1_ACTIVE;
-			if (params->port2_active)
+			if (t_params->port2_active)
 				config |= TDA9887_PORT2_ACTIVE;
 		}
-		if (params->intercarrier_mode)
+		if (t_params->intercarrier_mode)
 			config |= TDA9887_INTERCARRIER;
 		if (is_secam_l) {
-			if (i == 0 && params->default_top_secam_low)
-				config |= TDA9887_TOP(params->default_top_secam_low);
-			else if (i == 1 && params->default_top_secam_mid)
-				config |= TDA9887_TOP(params->default_top_secam_mid);
-			else if (params->default_top_secam_high)
-				config |= TDA9887_TOP(params->default_top_secam_high);
+			if (i == 0 && t_params->default_top_secam_low)
+				config |= TDA9887_TOP(t_params->default_top_secam_low);
+			else if (i == 1 && t_params->default_top_secam_mid)
+				config |= TDA9887_TOP(t_params->default_top_secam_mid);
+			else if (t_params->default_top_secam_high)
+				config |= TDA9887_TOP(t_params->default_top_secam_high);
 		}
 		else {
-			if (i == 0 && params->default_top_low)
-				config |= TDA9887_TOP(params->default_top_low);
-			else if (i == 1 && params->default_top_mid)
-				config |= TDA9887_TOP(params->default_top_mid);
-			else if (params->default_top_high)
-				config |= TDA9887_TOP(params->default_top_high);
+			if (i == 0 && t_params->default_top_low)
+				config |= TDA9887_TOP(t_params->default_top_low);
+			else if (i == 1 && t_params->default_top_mid)
+				config |= TDA9887_TOP(t_params->default_top_mid);
+			else if (t_params->default_top_high)
+				config |= TDA9887_TOP(t_params->default_top_high);
 		}
-		if (params->default_pll_gating_18)
+		if (t_params->default_pll_gating_18)
 			config |= TDA9887_GATING_18;
-		i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config);
+		i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config);
 	}
 	tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
 		  buffer[0],buffer[1],buffer[2],buffer[3]);
 
-	if (4 != (rc = i2c_master_send(c,buffer,4)))
+	if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
 		tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
 
-	switch (t->type) {
+	switch (priv->type) {
 	case TUNER_LG_TDVS_H06XF:
 		/* Set the Auxiliary Byte. */
 		buffer[0] = buffer[2];
@@ -355,7 +408,7 @@
 		buffer[1] = 0x20;
 		tuner_dbg("tv 0x%02x 0x%02x\n",buffer[0],buffer[1]);
 
-		if (2 != (rc = i2c_master_send(c,buffer,2)))
+		if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,2)))
 			tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
 		break;
 	case TUNER_MICROTUNE_4042FI5:
@@ -367,8 +420,8 @@
 		/* Wait until the PLL locks */
 		for (;;) {
 			if (time_after(jiffies,timeout))
-				return;
-			if (1 != (rc = i2c_master_recv(c,&status_byte,1))) {
+				return 0;
+			if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,&status_byte,1))) {
 				tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc);
 				break;
 			}
@@ -386,68 +439,86 @@
 		tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
 			  buffer[0],buffer[1],buffer[2],buffer[3]);
 
-		if (4 != (rc = i2c_master_send(c,buffer,4)))
+		if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
 			tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
 		break;
 	}
 	}
+	return 0;
 }
 
-static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
+static int simple_set_radio_freq(struct dvb_frontend *fe,
+				 struct analog_parameters *params)
 {
 	struct tunertype *tun;
-	struct tuner *t = i2c_get_clientdata(c);
+	struct tuner_simple_priv *priv = fe->tuner_priv;
 	u8 buffer[4];
 	u16 div;
 	int rc, j;
-	enum param_type desired_type = TUNER_PARAM_TYPE_RADIO;
-	struct tuner_params *params;
+	struct tuner_params *t_params;
+	unsigned int freq = params->frequency;
 
-	tun = &tuners[t->type];
+	tun = priv->tun;
 
-	for (j = 0; j < tun->count-1; j++) {
-		if (desired_type != tun->params[j].type)
-			continue;
+	for (j = tun->count-1; j > 0; j--)
+		if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO)
+			break;
+	/* default t_params (j=0) will be used if desired type wasn't found */
+	t_params = &tun->params[j];
+
+	/* Select Radio 1st IF used */
+	switch (t_params->radio_if) {
+	case 0: /* 10.7 MHz */
+		freq += (unsigned int)(10.7*16000);
 		break;
+	case 1: /* 33.3 MHz */
+		freq += (unsigned int)(33.3*16000);
+		break;
+	case 2: /* 41.3 MHz */
+		freq += (unsigned int)(41.3*16000);
+		break;
+	default:
+		tuner_warn("Unsupported radio_if value %d\n", t_params->radio_if);
+		return 0;
 	}
-	/* use default tuner_params if desired_type not available */
-	if (desired_type != tun->params[j].type)
-		j = 0;
 
-	div = (20 * freq / 16000) + (int)(20*10.7); /* IF 10.7 MHz */
-	params = &tun->params[j];
-	buffer[2] = (params->ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */
-
-	switch (t->type) {
+	/* Bandswitch byte */
+	switch (priv->type) {
 	case TUNER_TENA_9533_DI:
 	case TUNER_YMEC_TVF_5533MF:
-		tuner_dbg ("This tuner doesn't have FM. Most cards has a TEA5767 for FM\n");
-		return;
+		tuner_dbg("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n");
+		return 0;
 	case TUNER_PHILIPS_FM1216ME_MK3:
 	case TUNER_PHILIPS_FM1236_MK3:
 	case TUNER_PHILIPS_FMD1216ME_MK3:
 	case TUNER_LG_NTSC_TAPE:
+	case TUNER_PHILIPS_FM1256_IH3:
 		buffer[3] = 0x19;
 		break;
 	case TUNER_TNF_5335MF:
 		buffer[3] = 0x11;
 		break;
-	case TUNER_PHILIPS_FM1256_IH3:
-		div = (20 * freq) / 16000 + (int)(33.3 * 20);  /* IF 33.3 MHz */
-		buffer[3] = 0x19;
-		break;
 	case TUNER_LG_PAL_FM:
 		buffer[3] = 0xa5;
 		break;
-	case TUNER_MICROTUNE_4049FM5:
-		div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */
-		buffer[3] = 0xa4;
+	case TUNER_THOMSON_DTT761X:
+		buffer[3] = 0x39;
 		break;
+	case TUNER_MICROTUNE_4049FM5:
 	default:
 		buffer[3] = 0xa4;
 		break;
 	}
-	if (params->cb_first_if_lower_freq && div < t->last_div) {
+
+	buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
+		    TUNER_RATIO_SELECT_50; /* 50 kHz step */
+
+	/* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
+	   freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
+	   freq * (1/800) */
+	div = (freq + 400) / 800;
+
+	if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
 		buffer[0] = buffer[2];
 		buffer[1] = buffer[3];
 		buffer[2] = (div>>8) & 0x7f;
@@ -459,43 +530,108 @@
 
 	tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
 	       buffer[0],buffer[1],buffer[2],buffer[3]);
-	t->last_div = div;
+	priv->last_div = div;
 
-	if (params->has_tda9887) {
+	if (t_params->has_tda9887) {
 		int config = 0;
-		if (params->port1_active && !params->port1_fm_high_sensitivity)
+		if (t_params->port1_active && !t_params->port1_fm_high_sensitivity)
 			config |= TDA9887_PORT1_ACTIVE;
-		if (params->port2_active && !params->port2_fm_high_sensitivity)
+		if (t_params->port2_active && !t_params->port2_fm_high_sensitivity)
 			config |= TDA9887_PORT2_ACTIVE;
-		if (params->intercarrier_mode)
+		if (t_params->intercarrier_mode)
 			config |= TDA9887_INTERCARRIER;
-/*		if (params->port1_set_for_fm_mono)
+/*		if (t_params->port1_set_for_fm_mono)
 			config &= ~TDA9887_PORT1_ACTIVE;*/
-		if (params->fm_gain_normal)
+		if (t_params->fm_gain_normal)
 			config |= TDA9887_GAIN_NORMAL;
-		i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config);
+		if (t_params->radio_if == 2)
+			config |= TDA9887_RIF_41_3;
+		i2c_clients_command(priv->i2c_props.adap, TDA9887_SET_CONFIG, &config);
 	}
-	if (4 != (rc = i2c_master_send(c,buffer,4)))
+	if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
 		tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
-}
-
-int default_tuner_init(struct i2c_client *c)
-{
-	struct tuner *t = i2c_get_clientdata(c);
-
-	tuner_info("type set to %d (%s)\n",
-		   t->type, tuners[t->type].name);
-	strlcpy(c->name, tuners[t->type].name, sizeof(c->name));
-
-	t->set_tv_freq = default_set_tv_freq;
-	t->set_radio_freq = default_set_radio_freq;
-	t->has_signal = tuner_signal;
-	t->is_stereo = tuner_stereo;
-	t->standby = NULL;
 
 	return 0;
 }
 
+static int simple_set_params(struct dvb_frontend *fe,
+			     struct analog_parameters *params)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	int ret = -EINVAL;
+
+	switch (params->mode) {
+	case V4L2_TUNER_RADIO:
+		ret = simple_set_radio_freq(fe, params);
+		priv->frequency = params->frequency * 125 / 2;
+		break;
+	case V4L2_TUNER_ANALOG_TV:
+	case V4L2_TUNER_DIGITAL_TV:
+		ret = simple_set_tv_freq(fe, params);
+		priv->frequency = params->frequency * 62500;
+		break;
+	}
+
+	return ret;
+}
+
+
+static int simple_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+
+	return 0;
+}
+
+static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+	struct tuner_simple_priv *priv = fe->tuner_priv;
+	*frequency = priv->frequency;
+	return 0;
+}
+
+static struct dvb_tuner_ops simple_tuner_ops = {
+	.set_analog_params = simple_set_params,
+	.release           = simple_release,
+	.get_frequency     = simple_get_frequency,
+	.get_status        = simple_get_status,
+	.get_rf_strength   = simple_get_rf_strength,
+};
+
+struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
+					 struct i2c_adapter *i2c_adap,
+					 u8 i2c_addr,
+					 struct simple_tuner_config *cfg)
+{
+	struct tuner_simple_priv *priv = NULL;
+
+	priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL);
+	if (priv == NULL)
+		return NULL;
+	fe->tuner_priv = priv;
+
+	priv->i2c_props.addr = i2c_addr;
+	priv->i2c_props.adap = i2c_adap;
+	priv->type = cfg->type;
+	priv->tun  = cfg->tun;
+
+	memcpy(&fe->ops.tuner_ops, &simple_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+	tuner_info("type set to %d (%s)\n", cfg->type, cfg->tun->name);
+
+	strlcpy(fe->ops.tuner_ops.info.name, cfg->tun->name, sizeof(fe->ops.tuner_ops.info.name));
+
+	return fe;
+}
+
+
+EXPORT_SYMBOL_GPL(simple_tuner_attach);
+
+MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver");
+MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
+MODULE_LICENSE("GPL");
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * ---------------------------------------------------------------------------
diff --git a/drivers/media/video/tuner-simple.h b/drivers/media/video/tuner-simple.h
new file mode 100644
index 0000000..9089939
--- /dev/null
+++ b/drivers/media/video/tuner-simple.h
@@ -0,0 +1,46 @@
+/*
+    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.
+*/
+
+#ifndef __TUNER_SIMPLE_H__
+#define __TUNER_SIMPLE_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+struct simple_tuner_config
+{
+	/* chip type */
+	unsigned int type;
+	struct tunertype *tun;
+};
+
+#if defined(CONFIG_TUNER_SIMPLE) || (defined(CONFIG_TUNER_SIMPLE_MODULE) && defined(MODULE))
+extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
+						struct i2c_adapter *i2c_adap,
+						u8 i2c_addr,
+						struct simple_tuner_config *cfg);
+#else
+static inline struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
+						       struct i2c_adapter *i2c_adap,
+						       u8 i2c_addr,
+						       struct simple_tuner_config *cfg)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+	return NULL;
+}
+#endif
+
+#endif /* __TUNER_SIMPLE_H__ */
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index 74c3e6f..c6a7934 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -594,19 +594,19 @@
 	},
 };
 
-/* ------------ TUNER_PHILIPS_ATSC - Philips ATSC ------------ */
+/* ---- TUNER_PHILIPS_ATSC - Philips FCV1236D (ATSC/NTSC) ---- */
 
-static struct tuner_range tuner_philips_atsc_ranges[] = {
+static struct tuner_range tuner_philips_fcv1236d_ranges[] = {
 	{ 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
-	{ 16 * 454.00 /*MHz*/, 0x8e, 0x90, },
+	{ 16 * 451.25 /*MHz*/, 0x8e, 0x90, },
 	{ 16 * 999.99        , 0x8e, 0x30, },
 };
 
-static struct tuner_params tuner_philips_atsc_params[] = {
+static struct tuner_params tuner_philips_fcv1236d_params[] = {
 	{
 		.type   = TUNER_PARAM_TYPE_NTSC,
-		.ranges = tuner_philips_atsc_ranges,
-		.count  = ARRAY_SIZE(tuner_philips_atsc_ranges),
+		.ranges = tuner_philips_fcv1236d_ranges,
+		.count  = ARRAY_SIZE(tuner_philips_fcv1236d_ranges),
 	},
 };
 
@@ -652,6 +652,7 @@
 		.port1_invert_for_secam_lc = 1,
 		.default_pll_gating_18 = 1,
 		.fm_gain_normal=1,
+		.radio_if = 1, /* 33.3 MHz */
 	},
 };
 
@@ -670,6 +671,9 @@
 		.count  = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges),
 		.has_tda9887 = 1,
 		.intercarrier_mode = 1,
+		.default_top_low = -3,
+		.default_top_mid = -3,
+		.default_top_high = -3,
 	},
 };
 
@@ -730,6 +734,7 @@
 		.type   = TUNER_PARAM_TYPE_PAL,
 		.ranges = tuner_fm1236_mk3_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
+		.radio_if = 1, /* 33.3 MHz */
 	},
 };
 
@@ -856,6 +861,9 @@
 		.type   = TUNER_PARAM_TYPE_NTSC,
 		.ranges = tuner_thomson_dtt761x_ntsc_ranges,
 		.count  = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges),
+		.has_tda9887 = 1,
+		.fm_gain_normal = 1,
+		.radio_if = 2, /* 41.3 MHz */
 	},
 };
 
@@ -1296,9 +1304,9 @@
 		.count  = ARRAY_SIZE(tuner_philips_pal_mk_params),
 	},
 	[TUNER_PHILIPS_ATSC] = { /* Philips ATSC */
-		.name   = "Philips 1236D ATSC/NTSC dual in",
-		.params = tuner_philips_atsc_params,
-		.count  = ARRAY_SIZE(tuner_philips_atsc_params),
+		.name   = "Philips FCV1236D ATSC/NTSC dual in",
+		.params = tuner_philips_fcv1236d_params,
+		.count  = ARRAY_SIZE(tuner_philips_fcv1236d_params),
 	},
 	[TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */
 		.name   = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)",
@@ -1463,6 +1471,10 @@
 		.name   = "Philips TDA988[5,6,7] IF PLL Demodulator",
 		/* see tda9887.c for details */
 	},
+	[TUNER_TEA5761] = { /* Philips RADIO */
+		.name   = "Philips TEA5761 FM Radio",
+		/* see tea5767.c for details */
+	},
 };
 
 unsigned const int tuner_count = ARRAY_SIZE(tuners);
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 9da338d..a19cdcc 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -15,7 +15,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -290,7 +289,7 @@
 		desc->checkmode(chip);
 
 		/* schedule next check */
-		mod_timer(&chip->wt, jiffies+2*HZ);
+		mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
 	}
 
 	v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name);
@@ -1770,7 +1769,7 @@
 			desc->setmode(chip,VIDEO_SOUND_MONO);
 			if (chip->prevmode != VIDEO_SOUND_MONO)
 				chip->prevmode = -1; /* reset previous mode */
-			mod_timer(&chip->wt, jiffies+2*HZ);
+			mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
 			/* the thread will call checkmode() later */
 		}
 		break;
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index a1136da..4b2c403 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -30,7 +30,6 @@
 
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
@@ -183,7 +182,7 @@
 	{ TUNER_ABSENT,        "Silicon TDA8275C1 8290 FM"},
 	{ TUNER_ABSENT,        "Thompson DTT757"},
 	/* 80-89 */
-	{ TUNER_ABSENT,        "Philips FQ1216LME MK3"},
+	{ TUNER_PHILIPS_FM1216ME_MK3, "Philips FQ1216LME MK3"},
 	{ TUNER_LG_PAL_NEW_TAPC, "LG TAPC G701D"},
 	{ TUNER_LG_NTSC_NEW_TAPC, "LG TAPC H791F"},
 	{ TUNER_LG_PAL_NEW_TAPC, "TCL 2002MB 3"},
@@ -490,7 +489,7 @@
 			to indicate 4052 mux was removed in favor of using MSP
 			inputs directly. */
 			audioic = eeprom_data[i+2] & 0x7f;
-			if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+			if (audioic < ARRAY_SIZE(audioIC))
 				tvee->audio_processor = audioIC[audioic].id;
 			else
 				tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
@@ -523,7 +522,7 @@
 			to indicate 4052 mux was removed in favor of using MSP
 			inputs directly. */
 			audioic = eeprom_data[i+1] & 0x7f;
-			if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+			if (audioic < ARRAY_SIZE(audioIC))
 				tvee->audio_processor = audioIC[audioic].id;
 			else
 				tvee->audio_processor = AUDIO_CHIP_UNKNOWN;
@@ -678,7 +677,7 @@
 		tveeprom_info("audio processor is unknown (no idx)\n");
 		tvee->audio_processor=AUDIO_CHIP_UNKNOWN;
 	} else {
-		if (audioic < sizeof(audioIC)/sizeof(*audioIC))
+		if (audioic < ARRAY_SIZE(audioIC))
 			tveeprom_info("audio processor is %s (idx %d)\n",
 					audioIC[audioic].name,audioic);
 		else
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
index 3ae5a9c..9fa5b70 100644
--- a/drivers/media/video/tvmixer.c
+++ b/drivers/media/video/tvmixer.c
@@ -2,7 +2,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/timer.h>
@@ -238,13 +237,10 @@
 
 static int tvmixer_adapters(struct i2c_adapter *adap)
 {
-	struct list_head  *item;
 	struct i2c_client *client;
 
-	list_for_each(item,&adap->clients) {
-		client = list_entry(item, struct i2c_client, list);
+	list_for_each_entry(client, &adap->clients, list)
 		tvmixer_clients(client);
-	}
 	return 0;
 }
 
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index d5ec05f..e2f1c97 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -1006,7 +1006,7 @@
 		{
 			struct v4l2_control *ctrl = arg;
 			u8 i, n;
-			n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
+			n = ARRAY_SIZE(tvp5150_qctrl);
 			for (i = 0; i < n; i++)
 				if (ctrl->id == tvp5150_qctrl[i].id) {
 					if (ctrl->value <
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
index abe2146..491505d 100644
--- a/drivers/media/video/usbvideo/konicawc.c
+++ b/drivers/media/video/usbvideo/konicawc.c
@@ -236,7 +236,7 @@
 	input_dev->name = "Konicawc snapshot button";
 	input_dev->phys = cam->input_physname;
 	usb_to_input_id(dev, &input_dev->id);
-	input_dev->cdev.dev = &dev->dev;
+	input_dev->dev.parent = &dev->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY);
 	input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
index ec0ff22..dd1a6d6 100644
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -100,7 +100,7 @@
 	input_dev->name = "QCM button";
 	input_dev->phys = cam->input_physname;
 	usb_to_input_id(dev, &input_dev->id);
-	input_dev->cdev.dev = &dev->dev;
+	input_dev->dev.parent = &dev->dev;
 
 	input_dev->evbit[0] = BIT(EV_KEY);
 	input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
@@ -439,7 +439,7 @@
 	int ret;
 	int i;
 
-	for (i=0; i < sizeof(regval_table)/sizeof(regval_table[0]) ; i++) {
+	for (i=0; i < ARRAY_SIZE(regval_table) ; i++) {
 		CHECK_RET(ret, qcm_stv_setb(uvd->dev,
 					regval_table[i].reg,
 					regval_table[i].val));
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index 982b115..ff55512 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -42,7 +42,6 @@
 #include <linux/usb.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
-#include <linux/proc_fs.h>
 #include <linux/mutex.h>
 #include "usbvideo.h"
 
@@ -417,11 +416,6 @@
 	u8 open_count;
 	u8 bulkEndpoint;
 	int needsDummyRead;
-
-#if defined(CONFIG_VIDEO_PROC_FS)
-	struct proc_dir_entry *proc_dir;
-#endif
-
 };
 
 static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
@@ -1065,175 +1059,6 @@
 	return 0;
 }
 
-#if defined(CONFIG_VIDEO_PROC_FS)
-
-static struct proc_dir_entry *vicam_proc_root = NULL;
-
-static int vicam_read_helper(char *page, char **start, off_t off,
-				int count, int *eof, int value)
-{
-	char *out = page;
-	int len;
-
-	out += sprintf(out, "%d",value);
-
-	len = out - page;
-	len -= off;
-	if (len < count) {
-		*eof = 1;
-		if (len <= 0)
-			return 0;
-	} else
-		len = count;
-
-	*start = page + off;
-	return len;
-}
-
-static int vicam_read_proc_shutter(char *page, char **start, off_t off,
-				int count, int *eof, void *data)
-{
-	return vicam_read_helper(page,start,off,count,eof,
-				((struct vicam_camera *)data)->shutter_speed);
-}
-
-static int vicam_read_proc_gain(char *page, char **start, off_t off,
-				int count, int *eof, void *data)
-{
-	return vicam_read_helper(page,start,off,count,eof,
-				((struct vicam_camera *)data)->gain);
-}
-
-static int
-vicam_write_proc_shutter(struct file *file, const char *buffer,
-			 unsigned long count, void *data)
-{
-	u16 stmp;
-	char kbuf[8];
-	struct vicam_camera *cam = (struct vicam_camera *) data;
-
-	if (count > 6)
-		return -EINVAL;
-
-	if (copy_from_user(kbuf, buffer, count))
-		return -EFAULT;
-
-	stmp = (u16) simple_strtoul(kbuf, NULL, 10);
-	if (stmp < 4 || stmp > 32000)
-		return -EINVAL;
-
-	cam->shutter_speed = stmp;
-
-	return count;
-}
-
-static int
-vicam_write_proc_gain(struct file *file, const char *buffer,
-		      unsigned long count, void *data)
-{
-	u16 gtmp;
-	char kbuf[8];
-
-	struct vicam_camera *cam = (struct vicam_camera *) data;
-
-	if (count > 4)
-		return -EINVAL;
-
-	if (copy_from_user(kbuf, buffer, count))
-		return -EFAULT;
-
-	gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
-	if (gtmp > 255)
-		return -EINVAL;
-	cam->gain = gtmp;
-
-	return count;
-}
-
-static void
-vicam_create_proc_root(void)
-{
-	vicam_proc_root = proc_mkdir("video/vicam", NULL);
-
-	if (vicam_proc_root)
-		vicam_proc_root->owner = THIS_MODULE;
-	else
-		printk(KERN_ERR
-		       "could not create /proc entry for vicam!");
-}
-
-static void
-vicam_destroy_proc_root(void)
-{
-	if (vicam_proc_root)
-		remove_proc_entry("video/vicam", 0);
-}
-
-static void
-vicam_create_proc_entry(struct vicam_camera *cam)
-{
-	char name[64];
-	struct proc_dir_entry *ent;
-
-	DBG(KERN_INFO "vicam: creating proc entry\n");
-
-	if (!vicam_proc_root || !cam) {
-		printk(KERN_INFO
-		       "vicam: could not create proc entry, %s pointer is null.\n",
-		       (!cam ? "camera" : "root"));
-		return;
-	}
-
-	sprintf(name, "video%d", cam->vdev.minor);
-
-	cam->proc_dir = proc_mkdir(name, vicam_proc_root);
-
-	if ( !cam->proc_dir )
-		return; // FIXME: We should probably return an error here
-
-	ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
-				cam->proc_dir);
-	if (ent) {
-		ent->data = cam;
-		ent->read_proc = vicam_read_proc_shutter;
-		ent->write_proc = vicam_write_proc_shutter;
-		ent->size = 64;
-	}
-
-	ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
-				cam->proc_dir);
-	if (ent) {
-		ent->data = cam;
-		ent->read_proc = vicam_read_proc_gain;
-		ent->write_proc = vicam_write_proc_gain;
-		ent->size = 64;
-	}
-}
-
-static void
-vicam_destroy_proc_entry(void *ptr)
-{
-	struct vicam_camera *cam = (struct vicam_camera *) ptr;
-	char name[16];
-
-	if ( !cam->proc_dir )
-		return;
-
-	sprintf(name, "video%d", cam->vdev.minor);
-	remove_proc_entry("shutter", cam->proc_dir);
-	remove_proc_entry("gain", cam->proc_dir);
-	remove_proc_entry(name,vicam_proc_root);
-	cam->proc_dir = NULL;
-
-}
-
-#else
-static inline void vicam_create_proc_root(void) { }
-static inline void vicam_destroy_proc_root(void) { }
-static inline void vicam_create_proc_entry(struct vicam_camera *cam) { }
-static inline void vicam_destroy_proc_entry(void *ptr) { }
-#endif
-
 static const struct file_operations vicam_fops = {
 	.owner		= THIS_MODULE,
 	.open		= vicam_open,
@@ -1305,13 +1130,12 @@
 	}
 
 	if ((cam =
-	     kmalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
+	     kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
 		printk(KERN_WARNING
 		       "could not allocate kernel memory for vicam_camera struct\n");
 		return -ENOMEM;
 	}
 
-	memset(cam, 0, sizeof (struct vicam_camera));
 
 	cam->shutter_speed = 15;
 
@@ -1330,8 +1154,6 @@
 		return -EIO;
 	}
 
-	vicam_create_proc_entry(cam);
-
 	printk(KERN_INFO "ViCam webcam driver now controlling video device %d\n",cam->vdev.minor);
 
 	usb_set_intfdata (intf, cam);
@@ -1363,8 +1185,6 @@
 
 	cam->udev = NULL;
 
-	vicam_destroy_proc_entry(cam);
-
 	/* the only thing left to do is synchronize with
 	 * our close/release function on who should release
 	 * the camera memory. if there are any users using the
@@ -1390,7 +1210,6 @@
 {
 	int retval;
 	DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
-	vicam_create_proc_root();
 	retval = usb_register(&vicam_driver);
 	if (retval)
 		printk(KERN_WARNING "usb_register failed!\n");
@@ -1404,7 +1223,6 @@
 	       "ViCam-based WebCam driver shutdown\n");
 
 	usb_deregister(&vicam_driver);
-	vicam_destroy_proc_root();
 }
 
 module_init(usb_vicam_init);
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c
index 51ab265..f09eb10 100644
--- a/drivers/media/video/usbvision/usbvision-cards.c
+++ b/drivers/media/video/usbvision/usbvision-cards.c
@@ -79,7 +79,7 @@
 		.Interface     = -1,
 		.Codec         = CODEC_SAA7113,
 		.VideoChannels = 2,
-		.VideoNorm     = V4L2_STD_PAL,
+		.VideoNorm     = V4L2_STD_NTSC,
 		.AudioChannels = 1,
 		.Radio         = 0,
 		.vbi           = 1,
@@ -311,8 +311,8 @@
 		.vbi           = 1,
 		.Tuner         = 1,
 		.TunerType     = TUNER_PHILIPS_SECAM,
-		.X_Offset      = -1,
-		.Y_Offset      = -1,
+		.X_Offset      = 0x80,
+		.Y_Offset      = 0x16,
 		.ModelString   = "Hauppauge WinTV USB (PAL/SECAM L)",
 	},
 	[HPG_WINTV_PAL_D_K] = {
@@ -586,7 +586,7 @@
 		.Radio         = 0,
 		.vbi           = 1,
 		.Tuner         = 1,
-		.TunerType     = TUNER_PHILIPS_PAL,
+		.TunerType     = TUNER_LG_PAL_NEW_TAPC,
 		.X_Offset      = 0,
 		.Y_Offset      = 3,
 		.Dvi_yuv_override = 1,
@@ -1081,6 +1081,7 @@
 	{ USB_DEVICE(0x2304, 0x0301), .driver_info=PINNA_LINX_VD_IN_CAB_PAL },
 	{ USB_DEVICE(0x2304, 0x0419), .driver_info=PINNA_PCTV_BUNGEE_PAL_FM },
 	{ USB_DEVICE(0x2400, 0x4200), .driver_info=HPG_WINTV },
+	{ },    /* terminate list */
 };
 
 MODULE_DEVICE_TABLE (usb, usbvision_table);
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index 7df071eb..c7d5f9e 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -45,7 +45,6 @@
 #include <media/tuner.h>
 #include <media/audiochip.h>
 
-#include <linux/moduleparam.h>
 #include <linux/workqueue.h>
 
 #ifdef CONFIG_KMOD
@@ -1742,7 +1741,7 @@
 		format = ISOC_MODE_YUV420;
 	}
 	value[0] = 0x0A;  //TODO: See the effect of the filter
-	value[1] = format;
+	value[1] = format; // Sets the VO_MODE register which follows FILT_CONT
 	rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
 			     USBVISION_OP_CODE,
 			     USB_DIR_OUT | USB_TYPE_VENDOR |
@@ -1831,10 +1830,10 @@
 		frameRate = FRAMERATE_MAX;
 	}
 
-	if (usbvision->tvnorm->id & V4L2_STD_625_50) {
+	if (usbvision->tvnormId & V4L2_STD_625_50) {
 		frameDrop = frameRate * 32 / 25 - 1;
 	}
-	else if (usbvision->tvnorm->id & V4L2_STD_525_60) {
+	else if (usbvision->tvnormId & V4L2_STD_525_60) {
 		frameDrop = frameRate * 32 / 30 - 1;
 	}
 
@@ -2067,7 +2066,7 @@
 	}
 
 
-	if (usbvision->tvnorm->id & V4L2_STD_PAL) {
+	if (usbvision->tvnormId & V4L2_STD_PAL) {
 		value[0] = 0xC0;
 		value[1] = 0x02;	//0x02C0 -> 704 Input video line length
 		value[2] = 0x20;
@@ -2076,7 +2075,7 @@
 		value[5] = 0x00;	//0x0060 -> 96 Input video h offset
 		value[6] = 0x16;
 		value[7] = 0x00;	//0x0016 -> 22 Input video v offset
-	} else if (usbvision->tvnorm->id & V4L2_STD_SECAM) {
+	} else if (usbvision->tvnormId & V4L2_STD_SECAM) {
 		value[0] = 0xC0;
 		value[1] = 0x02;	//0x02C0 -> 704 Input video line length
 		value[2] = 0x20;
@@ -2537,7 +2536,9 @@
 
 int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
 {
-	int mode[4];
+	/* inputs #0 and #3 are constant for every SAA711x. */
+	/* inputs #1 and #2 are variable for SAA7111 and SAA7113 */
+	int mode[4]= {SAA7115_COMPOSITE0, 0, 0, SAA7115_COMPOSITE3};
 	int audio[]= {1, 0, 0, 0};
 	struct v4l2_routing route;
 	//channel 0 is TV with audiochannel 1 (tuner mono)
@@ -2547,10 +2548,6 @@
 
 	RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs);
 	usbvision->ctl_input = channel;
-	  route.input = SAA7115_COMPOSITE1;
-	  route.output = 0;
-	  call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
-	  call_i2c_clients(usbvision, VIDIOC_S_INPUT, &usbvision->ctl_input);
 
 	// set the new channel
 	// Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video
@@ -2558,28 +2555,27 @@
 
 	switch (usbvision_device_data[usbvision->DevModel].Codec) {
 		case CODEC_SAA7113:
-			if (SwitchSVideoInput) { // To handle problems with S-Video Input for some devices.  Use SwitchSVideoInput parameter when loading the module.
-				mode[2] = 1;
+			mode[1] = SAA7115_COMPOSITE2;
+			if (SwitchSVideoInput) {
+				/* To handle problems with S-Video Input for
+				 * some devices.  Use SwitchSVideoInput
+				 * parameter when loading the module.*/
+				mode[2] = SAA7115_COMPOSITE1;
 			}
 			else {
-				mode[2] = 7;
-			}
-			if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
-				mode[0] = 0; mode[1] = 2; mode[3] = 3;  // Special for four input devices
-			}
-			else {
-				mode[0] = 0; mode[1] = 2; //modes for regular saa7113 devices
+				mode[2] = SAA7115_SVIDEO1;
 			}
 			break;
 		case CODEC_SAA7111:
-			mode[0] = 0; mode[1] = 1; mode[2] = 7; //modes for saa7111
-			break;
 		default:
-			mode[0] = 0; mode[1] = 1; mode[2] = 7; //default modes
+			/* modes for saa7111 */
+			mode[1] = SAA7115_COMPOSITE1;
+			mode[2] = SAA7115_SVIDEO1;
+			break;
 	}
 	route.input = mode[channel];
+	route.output = 0;
 	call_i2c_clients(usbvision, VIDIOC_INT_S_VIDEO_ROUTING,&route);
-	usbvision->channel = channel;
 	usbvision_set_audio(usbvision, audio[channel]);
 	return 0;
 }
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index 025be55..c66aef6 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -134,8 +134,6 @@
 		addr = (msg->addr << 1);
 		if (flags & I2C_M_RD)
 			addr |= 1;
-		if (flags & I2C_M_REV_DIR_ADDR)
-			addr ^= 1;
 
 		add[0] = addr;
 		if (flags & I2C_M_RD)
@@ -192,7 +190,7 @@
 
 static u32 functionality(struct i2c_adapter *adap)
 {
-	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING;
+	return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
 }
 
 
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index aa3258b..e2f3c01 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -36,7 +36,8 @@
  *     - use submit_urb for all setup packets
  *     - Fix memory settings for nt1004. It is 4 times as big as the
  *       nt1003 memory.
- *     - Add audio on endpoint 3 for nt1004 chip.  Seems impossible, needs a codec interface.  Which one?
+ *     - Add audio on endpoint 3 for nt1004 chip.
+ *         Seems impossible, needs a codec interface.  Which one?
  *     - Clean up the driver.
  *     - optimization for performance.
  *     - Add Videotext capability (VBI).  Working on it.....
@@ -67,7 +68,6 @@
 #include <media/tuner.h>
 #include <media/audiochip.h>
 
-#include <linux/moduleparam.h>
 #include <linux/workqueue.h>
 
 #ifdef CONFIG_KMOD
@@ -77,7 +77,8 @@
 #include "usbvision.h"
 #include "usbvision-cards.h"
 
-#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>, Dwaine Garden <DwaineGarden@rogers.com>"
+#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>,\
+ Dwaine Garden <DwaineGarden@rogers.com>"
 #define DRIVER_NAME "usbvision"
 #define DRIVER_ALIAS "USBVision"
 #define DRIVER_DESC "USBVision USB Video Device Driver for Linux"
@@ -85,20 +86,25 @@
 #define USBVISION_DRIVER_VERSION_MAJOR 0
 #define USBVISION_DRIVER_VERSION_MINOR 9
 #define USBVISION_DRIVER_VERSION_PATCHLEVEL 9
-#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,USBVISION_DRIVER_VERSION_MINOR,USBVISION_DRIVER_VERSION_PATCHLEVEL)
-#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR) "." __stringify(USBVISION_DRIVER_VERSION_MINOR) "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
+#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,\
+USBVISION_DRIVER_VERSION_MINOR,\
+USBVISION_DRIVER_VERSION_PATCHLEVEL)
+#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR)\
+ "." __stringify(USBVISION_DRIVER_VERSION_MINOR)\
+ "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
 
 #define	ENABLE_HEXDUMP	0	/* Enable if you need it */
 
 
 #ifdef USBVISION_DEBUG
 	#define PDEBUG(level, fmt, args...) \
-		if (video_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
+		if (video_debug & (level)) \
+			info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ ,\
+				## args)
 #else
 	#define PDEBUG(level, fmt, args...) do {} while(0)
 #endif
 
-#define DBG_IOCTL	1<<0
 #define DBG_IO		1<<1
 #define DBG_PROBE	1<<2
 #define DBG_MMAP	1<<3
@@ -108,7 +114,8 @@
 #define goto2next(str)	while(*str!=' ') str++; while(*str==' ') str++;
 
 
-static int usbvision_nr = 0;			// sequential number of usbvision device
+/* sequential number of usbvision device */
+static int usbvision_nr = 0;
 
 static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
 	{ 1, 1,  8, V4L2_PIX_FMT_GREY    , "GREY" },
@@ -121,55 +128,32 @@
 	{ 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" }
 };
 
-/* supported tv norms */
-static struct usbvision_tvnorm tvnorms[] = {
-	{
-		.name = "PAL",
-		.id = V4L2_STD_PAL,
-	}, {
-		.name = "NTSC",
-		.id = V4L2_STD_NTSC,
-	}, {
-		 .name = "SECAM",
-		 .id = V4L2_STD_SECAM,
-	}, {
-		.name = "PAL-M",
-		.id = V4L2_STD_PAL_M,
-	}
-};
-
-#define TVNORMS ARRAY_SIZE(tvnorms)
-
-// Function prototypes
+/* Function prototypes */
 static void usbvision_release(struct usb_usbvision *usbvision);
 
-// Default initalization of device driver parameters
-static int isocMode = ISOC_MODE_COMPRESS;		// Set the default format for ISOC endpoint
-static int video_debug = 0;				// Set the default Debug Mode of the device driver
-static int PowerOnAtOpen = 1;				// Set the default device to power on at startup
-static int video_nr = -1;				// Sequential Number of Video Device
-static int radio_nr = -1;				// Sequential Number of Radio Device
-static int vbi_nr = -1;					// Sequential Number of VBI Device
+/* Default initalization of device driver parameters */
+/* Set the default format for ISOC endpoint */
+static int isocMode = ISOC_MODE_COMPRESS;
+/* Set the default Debug Mode of the device driver */
+static int video_debug = 0;
+/* Set the default device to power on at startup */
+static int PowerOnAtOpen = 1;
+/* Sequential Number of Video Device */
+static int video_nr = -1;
+/* Sequential Number of Radio Device */
+static int radio_nr = -1;
+/* Sequential Number of VBI Device */
+static int vbi_nr = -1;
 
-// Grab parameters for the device driver
+/* Grab parameters for the device driver */
 
-#if defined(module_param)                               // Showing parameters under SYSFS
+/* Showing parameters under SYSFS */
 module_param(isocMode, int, 0444);
 module_param(video_debug, int, 0444);
 module_param(PowerOnAtOpen, int, 0444);
 module_param(video_nr, int, 0444);
 module_param(radio_nr, int, 0444);
 module_param(vbi_nr, int, 0444);
-#else							// Old Style
-MODULE_PARAM(isocMode, "i");
-MODULE_PARM(video_debug, "i");				// Grab the Debug Mode of the device driver
-MODULE_PARM(adjustCompression, "i");			// Grab the compression to be adaptive
-MODULE_PARM(PowerOnAtOpen, "i");			// Grab the device to power on at startup
-MODULE_PARM(SwitchSVideoInput, "i");			// To help people with Black and White output with using s-video input.  Some cables and input device are wired differently.
-MODULE_PARM(video_nr, "i");				// video_nr option allows to specify a certain /dev/videoX device (like /dev/video0 or /dev/video1 ...)
-MODULE_PARM(radio_nr, "i");				// radio_nr option allows to specify a certain /dev/radioX device (like /dev/radio0 or /dev/radio1 ...)
-MODULE_PARM(vbi_nr, "i");				// vbi_nr option allows to specify a certain /dev/vbiX device (like /dev/vbi0 or /dev/vbi1 ...)
-#endif
 
 MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint.  Default: 0x60 (Compression On)");
 MODULE_PARM_DESC(video_debug, " Set the default Debug Mode of the device driver.  Default: 0 (Off)");
@@ -187,39 +171,47 @@
 MODULE_ALIAS(DRIVER_ALIAS);
 
 
-/****************************************************************************************/
-/* SYSFS Code - Copied from the stv680.c usb module.					*/
-/* Device information is located at /sys/class/video4linux/video0			*/
-/* Device parameters information is located at /sys/module/usbvision                    */
-/* Device USB Information is located at /sys/bus/usb/drivers/USBVision Video Grabber    */
-/****************************************************************************************/
+/*****************************************************************************/
+/* SYSFS Code - Copied from the stv680.c usb module.			     */
+/* Device information is located at /sys/class/video4linux/video0            */
+/* Device parameters information is located at /sys/module/usbvision         */
+/* Device USB Information is located at                                      */
+/*   /sys/bus/usb/drivers/USBVision Video Grabber                            */
+/*****************************************************************************/
 
 
 #define YES_NO(x) ((x) ? "Yes" : "No")
 
-static inline struct usb_usbvision *cd_to_usbvision(struct class_device *cd)
+static inline struct usb_usbvision *cd_to_usbvision(struct device *cd)
 {
-	struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+	struct video_device *vdev =
+		container_of(cd, struct video_device, class_dev);
 	return video_get_drvdata(vdev);
 }
 
-static ssize_t show_version(struct class_device *cd, char *buf)
+static ssize_t show_version(struct device *cd,
+			    struct device_attribute *attr, char *buf)
 {
 	return sprintf(buf, "%s\n", USBVISION_VERSION_STRING);
 }
-static CLASS_DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
+static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
 
-static ssize_t show_model(struct class_device *cd, char *buf)
+static ssize_t show_model(struct device *cd,
+			  struct device_attribute *attr, char *buf)
 {
-	struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+	struct video_device *vdev =
+		container_of(cd, struct video_device, class_dev);
 	struct usb_usbvision *usbvision = video_get_drvdata(vdev);
-	return sprintf(buf, "%s\n", usbvision_device_data[usbvision->DevModel].ModelString);
+	return sprintf(buf, "%s\n",
+		       usbvision_device_data[usbvision->DevModel].ModelString);
 }
-static CLASS_DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
+static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
 
-static ssize_t show_hue(struct class_device *cd, char *buf)
+static ssize_t show_hue(struct device *cd,
+			struct device_attribute *attr, char *buf)
 {
-	struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+	struct video_device *vdev =
+		container_of(cd, struct video_device, class_dev);
 	struct usb_usbvision *usbvision = video_get_drvdata(vdev);
 	struct v4l2_control ctrl;
 	ctrl.id = V4L2_CID_HUE;
@@ -228,11 +220,13 @@
 		call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
 	return sprintf(buf, "%d\n", ctrl.value);
 }
-static CLASS_DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
+static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
 
-static ssize_t show_contrast(struct class_device *cd, char *buf)
+static ssize_t show_contrast(struct device *cd,
+			     struct device_attribute *attr, char *buf)
 {
-	struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+	struct video_device *vdev =
+		container_of(cd, struct video_device, class_dev);
 	struct usb_usbvision *usbvision = video_get_drvdata(vdev);
 	struct v4l2_control ctrl;
 	ctrl.id = V4L2_CID_CONTRAST;
@@ -241,11 +235,13 @@
 		call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
 	return sprintf(buf, "%d\n", ctrl.value);
 }
-static CLASS_DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
+static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
 
-static ssize_t show_brightness(struct class_device *cd, char *buf)
+static ssize_t show_brightness(struct device *cd,
+			       struct device_attribute *attr, char *buf)
 {
-	struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+	struct video_device *vdev =
+		container_of(cd, struct video_device, class_dev);
 	struct usb_usbvision *usbvision = video_get_drvdata(vdev);
 	struct v4l2_control ctrl;
 	ctrl.id = V4L2_CID_BRIGHTNESS;
@@ -254,11 +250,13 @@
 		call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
 	return sprintf(buf, "%d\n", ctrl.value);
 }
-static CLASS_DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
+static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
 
-static ssize_t show_saturation(struct class_device *cd, char *buf)
+static ssize_t show_saturation(struct device *cd,
+			       struct device_attribute *attr, char *buf)
 {
-	struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+	struct video_device *vdev =
+		container_of(cd, struct video_device, class_dev);
 	struct usb_usbvision *usbvision = video_get_drvdata(vdev);
 	struct v4l2_control ctrl;
 	ctrl.id = V4L2_CID_SATURATION;
@@ -267,31 +265,39 @@
 		call_i2c_clients(usbvision, VIDIOC_G_CTRL, &ctrl);
 	return sprintf(buf, "%d\n", ctrl.value);
 }
-static CLASS_DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
+static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
 
-static ssize_t show_streaming(struct class_device *cd, char *buf)
+static ssize_t show_streaming(struct device *cd,
+			      struct device_attribute *attr, char *buf)
 {
-	struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+	struct video_device *vdev =
+		container_of(cd, struct video_device, class_dev);
 	struct usb_usbvision *usbvision = video_get_drvdata(vdev);
-	return sprintf(buf, "%s\n", YES_NO(usbvision->streaming==Stream_On?1:0));
+	return sprintf(buf, "%s\n",
+		       YES_NO(usbvision->streaming==Stream_On?1:0));
 }
-static CLASS_DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);
+static DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);
 
-static ssize_t show_compression(struct class_device *cd, char *buf)
+static ssize_t show_compression(struct device *cd,
+				struct device_attribute *attr, char *buf)
 {
-	struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+	struct video_device *vdev =
+		container_of(cd, struct video_device, class_dev);
 	struct usb_usbvision *usbvision = video_get_drvdata(vdev);
-	return sprintf(buf, "%s\n", YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));
+	return sprintf(buf, "%s\n",
+		       YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));
 }
-static CLASS_DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);
+static DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);
 
-static ssize_t show_device_bridge(struct class_device *cd, char *buf)
+static ssize_t show_device_bridge(struct device *cd,
+				  struct device_attribute *attr, char *buf)
 {
-	struct video_device *vdev = container_of(cd, struct video_device, class_dev);
+	struct video_device *vdev =
+		container_of(cd, struct video_device, class_dev);
 	struct usb_usbvision *usbvision = video_get_drvdata(vdev);
 	return sprintf(buf, "%d\n", usbvision->bridgeType);
 }
-static CLASS_DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL);
+static DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL);
 
 static void usbvision_create_sysfs(struct video_device *vdev)
 {
@@ -299,40 +305,40 @@
 	if (!vdev)
 		return;
 	do {
-		res=class_device_create_file(&vdev->class_dev,
-					     &class_device_attr_version);
+		res = device_create_file(&vdev->class_dev,
+					 &dev_attr_version);
 		if (res<0)
 			break;
-		res=class_device_create_file(&vdev->class_dev,
-					     &class_device_attr_model);
+		res = device_create_file(&vdev->class_dev,
+					 &dev_attr_model);
 		if (res<0)
 			break;
-		res=class_device_create_file(&vdev->class_dev,
-					     &class_device_attr_hue);
+		res = device_create_file(&vdev->class_dev,
+					 &dev_attr_hue);
 		if (res<0)
 			break;
-		res=class_device_create_file(&vdev->class_dev,
-					     &class_device_attr_contrast);
+		res = device_create_file(&vdev->class_dev,
+					 &dev_attr_contrast);
 		if (res<0)
 			break;
-		res=class_device_create_file(&vdev->class_dev,
-					     &class_device_attr_brightness);
+		res = device_create_file(&vdev->class_dev,
+					 &dev_attr_brightness);
 		if (res<0)
 			break;
-		res=class_device_create_file(&vdev->class_dev,
-					     &class_device_attr_saturation);
+		res = device_create_file(&vdev->class_dev,
+					 &dev_attr_saturation);
 		if (res<0)
 			break;
-		res=class_device_create_file(&vdev->class_dev,
-					     &class_device_attr_streaming);
+		res = device_create_file(&vdev->class_dev,
+					 &dev_attr_streaming);
 		if (res<0)
 			break;
-		res=class_device_create_file(&vdev->class_dev,
-					     &class_device_attr_compression);
+		res = device_create_file(&vdev->class_dev,
+					 &dev_attr_compression);
 		if (res<0)
 			break;
-		res=class_device_create_file(&vdev->class_dev,
-					     &class_device_attr_bridge);
+		res = device_create_file(&vdev->class_dev,
+					 &dev_attr_bridge);
 		if (res>=0)
 			return;
 	} while (0);
@@ -343,24 +349,24 @@
 static void usbvision_remove_sysfs(struct video_device *vdev)
 {
 	if (vdev) {
-		class_device_remove_file(&vdev->class_dev,
-					 &class_device_attr_version);
-		class_device_remove_file(&vdev->class_dev,
-					 &class_device_attr_model);
-		class_device_remove_file(&vdev->class_dev,
-					 &class_device_attr_hue);
-		class_device_remove_file(&vdev->class_dev,
-					 &class_device_attr_contrast);
-		class_device_remove_file(&vdev->class_dev,
-					 &class_device_attr_brightness);
-		class_device_remove_file(&vdev->class_dev,
-					 &class_device_attr_saturation);
-		class_device_remove_file(&vdev->class_dev,
-					 &class_device_attr_streaming);
-		class_device_remove_file(&vdev->class_dev,
-					 &class_device_attr_compression);
-		class_device_remove_file(&vdev->class_dev,
-					 &class_device_attr_bridge);
+		device_remove_file(&vdev->class_dev,
+					 &dev_attr_version);
+		device_remove_file(&vdev->class_dev,
+					 &dev_attr_model);
+		device_remove_file(&vdev->class_dev,
+					 &dev_attr_hue);
+		device_remove_file(&vdev->class_dev,
+					 &dev_attr_contrast);
+		device_remove_file(&vdev->class_dev,
+					 &dev_attr_brightness);
+		device_remove_file(&vdev->class_dev,
+					 &dev_attr_saturation);
+		device_remove_file(&vdev->class_dev,
+					 &dev_attr_streaming);
+		device_remove_file(&vdev->class_dev,
+					 &dev_attr_compression);
+		device_remove_file(&vdev->class_dev,
+					 &dev_attr_bridge);
 	}
 }
 
@@ -376,7 +382,8 @@
 static int usbvision_v4l2_open(struct inode *inode, struct file *file)
 {
 	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
 	int errCode = 0;
 
 	PDEBUG(DBG_IO, "open");
@@ -390,7 +397,8 @@
 		/* Allocate memory for the scratch ring buffer */
 		errCode = usbvision_scratch_alloc(usbvision);
 		if (isocMode==ISOC_MODE_COMPRESS) {
-			/* Allocate intermediate decompression buffers only if needed */
+			/* Allocate intermediate decompression buffers
+			   only if needed */
 			errCode = usbvision_decompress_alloc(usbvision);
 		}
 		if (errCode) {
@@ -421,11 +429,10 @@
 		if (!errCode) {
 			usbvision_begin_streaming(usbvision);
 			errCode = usbvision_init_isoc(usbvision);
-			/* device needs to be initialized before isoc transfer */
+			/* device must be initialized before isoc transfer */
 			usbvision_muxsel(usbvision,0);
 			usbvision->user++;
-		}
-		else {
+		} else {
 			if (PowerOnAtOpen) {
 				usbvision_i2c_unregister(usbvision);
 				usbvision_power_off(usbvision);
@@ -456,7 +463,8 @@
 static int usbvision_v4l2_close(struct inode *inode, struct file *file)
 {
 	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
 
 	PDEBUG(DBG_IO, "close");
 	down(&usbvision->lock);
@@ -473,7 +481,8 @@
 	usbvision->user--;
 
 	if (PowerOnAtOpen) {
-		/* power off in a little while to avoid off/on every close/open short sequences */
+		/* power off in a little while
+		   to avoid off/on every close/open short sequences */
 		usbvision_set_powerOffTimer(usbvision);
 		usbvision->initialized = 0;
 	}
@@ -498,583 +507,613 @@
  * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
  *
  */
-static int usbvision_v4l2_do_ioctl(struct inode *inode, struct file *file,
-				 unsigned int cmd, void *arg)
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register (struct file *file, void *priv,
+				struct v4l2_register *reg)
 {
 	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+	int errCode;
 
-	if (!USBVISION_IS_OPERATIONAL(usbvision))
-		return -EFAULT;
+	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+		return -EINVAL;
+	/* NT100x has a 8-bit register space */
+	errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
+	if (errCode < 0) {
+		err("%s: VIDIOC_DBG_G_REGISTER failed: error %d",
+		    __FUNCTION__, errCode);
+		return errCode;
+	}
+	reg->val = errCode;
+	return 0;
+}
 
-	switch (cmd) {
+static int vidioc_s_register (struct file *file, void *priv,
+				struct v4l2_register *reg)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+	int errCode;
 
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-		/* ioctls to allow direct acces to the NT100x registers */
-		case VIDIOC_DBG_G_REGISTER:
-		case VIDIOC_DBG_S_REGISTER:
-		{
-			struct v4l2_register *reg = arg;
-			int errCode;
-
-			if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
-				return -EINVAL;
-			if (!capable(CAP_SYS_ADMIN))
-				return -EPERM;
-			/* NT100x has a 8-bit register space */
-			if (cmd == VIDIOC_DBG_G_REGISTER)
-				errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
-			else
-				errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
-			if (errCode < 0) {
-				err("%s: VIDIOC_DBG_%c_REGISTER failed: error %d", __FUNCTION__,
-				    cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S', errCode);
-				return errCode;
-			}
-			if (cmd == VIDIOC_DBG_S_REGISTER)
-				reg->val = (u8)errCode;
-
-			PDEBUG(DBG_IOCTL, "VIDIOC_DBG_%c_REGISTER reg=0x%02X, value=0x%02X",
-			       cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S',
-			       (unsigned int)reg->reg, (unsigned int)reg->val);
-			return 0;
-		}
+	if (!v4l2_chip_match_host(reg->match_type, reg->match_chip))
+		return -EINVAL;
+	/* NT100x has a 8-bit register space */
+	errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
+	if (errCode < 0) {
+		err("%s: VIDIOC_DBG_S_REGISTER failed: error %d",
+		    __FUNCTION__, errCode);
+		return errCode;
+	}
+	return 0;
+}
 #endif
-		case VIDIOC_QUERYCAP:
-		{
-			struct v4l2_capability *vc=arg;
 
-			memset(vc, 0, sizeof(*vc));
-			strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
-			strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString,
-				sizeof(vc->card));
-			strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
-				sizeof(vc->bus_info));
-			vc->version = USBVISION_DRIVER_VERSION;
-			vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
-				V4L2_CAP_AUDIO |
-				V4L2_CAP_READWRITE |
-				V4L2_CAP_STREAMING |
-				(usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
-			PDEBUG(DBG_IOCTL, "VIDIOC_QUERYCAP");
-			return 0;
+static int vidioc_querycap (struct file *file, void  *priv,
+					struct v4l2_capability *vc)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+
+	strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
+	strlcpy(vc->card,
+		usbvision_device_data[usbvision->DevModel].ModelString,
+		sizeof(vc->card));
+	strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
+		sizeof(vc->bus_info));
+	vc->version = USBVISION_DRIVER_VERSION;
+	vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+		V4L2_CAP_AUDIO |
+		V4L2_CAP_READWRITE |
+		V4L2_CAP_STREAMING |
+		(usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
+	return 0;
+}
+
+static int vidioc_enum_input (struct file *file, void *priv,
+				struct v4l2_input *vi)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+	int chan;
+
+	if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
+		return -EINVAL;
+	if (usbvision->have_tuner) {
+		chan = vi->index;
+	} else {
+		chan = vi->index + 1; /*skip Television string*/
+	}
+	/* Determine the requested input characteristics
+	   specific for each usbvision card model */
+	switch(chan) {
+	case 0:
+		if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+			strcpy(vi->name, "White Video Input");
+		} else {
+			strcpy(vi->name, "Television");
+			vi->type = V4L2_INPUT_TYPE_TUNER;
+			vi->audioset = 1;
+			vi->tuner = chan;
+			vi->std = USBVISION_NORMS;
 		}
-		case VIDIOC_ENUMINPUT:
-		{
-			struct v4l2_input *vi = arg;
-			int chan;
-
-			if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) )
-				return -EINVAL;
-			if (usbvision->have_tuner) {
-				chan = vi->index;
-			}
-			else {
-				chan = vi->index + 1; //skip Television string
-			}
-			switch(chan) {
-				case 0:
-					if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
-						strcpy(vi->name, "White Video Input");
-					}
-					else {
-						strcpy(vi->name, "Television");
-						vi->type = V4L2_INPUT_TYPE_TUNER;
-						vi->audioset = 1;
-						vi->tuner = chan;
-						vi->std = V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM;
-					}
-					break;
-				case 1:
-					vi->type = V4L2_INPUT_TYPE_CAMERA;
-					if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
-						strcpy(vi->name, "Green Video Input");
-					}
-					else {
-						strcpy(vi->name, "Composite Video Input");
-					}
-					vi->std = V4L2_STD_PAL;
-					break;
-				case 2:
-					vi->type = V4L2_INPUT_TYPE_CAMERA;
-					if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
-						strcpy(vi->name, "Yellow Video Input");
-					}
-					else {
-					strcpy(vi->name, "S-Video Input");
-					}
-					vi->std = V4L2_STD_PAL;
-					break;
-				case 3:
-					vi->type = V4L2_INPUT_TYPE_CAMERA;
-					strcpy(vi->name, "Red Video Input");
-					vi->std = V4L2_STD_PAL;
-					break;
-			}
-			PDEBUG(DBG_IOCTL, "VIDIOC_ENUMINPUT name=%s:%d tuners=%d type=%d norm=%x",
-			       vi->name, vi->index, vi->tuner,vi->type,(int)vi->std);
-			return 0;
+		break;
+	case 1:
+		vi->type = V4L2_INPUT_TYPE_CAMERA;
+		if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+			strcpy(vi->name, "Green Video Input");
+		} else {
+			strcpy(vi->name, "Composite Video Input");
 		}
-		case VIDIOC_ENUMSTD:
-		{
-			struct v4l2_standard *e = arg;
-			unsigned int i;
-			int ret;
-
-			i = e->index;
-			if (i >= TVNORMS)
-				return -EINVAL;
-			ret = v4l2_video_std_construct(e, tvnorms[e->index].id,
-						       tvnorms[e->index].name);
-			e->index = i;
-			if (ret < 0)
-				return ret;
-			return 0;
+		vi->std = V4L2_STD_PAL;
+		break;
+	case 2:
+		vi->type = V4L2_INPUT_TYPE_CAMERA;
+		if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+			strcpy(vi->name, "Yellow Video Input");
+		} else {
+			strcpy(vi->name, "S-Video Input");
 		}
-		case VIDIOC_G_INPUT:
-		{
-			int *input = arg;
-			*input = usbvision->ctl_input;
-			return 0;
-		}
-		case VIDIOC_S_INPUT:
-		{
-			int *input = arg;
-			if ((*input >= usbvision->video_inputs) || (*input < 0) )
-				return -EINVAL;
-			usbvision->ctl_input = *input;
-
-			down(&usbvision->lock);
-			usbvision_muxsel(usbvision, usbvision->ctl_input);
-			usbvision_set_input(usbvision);
-			usbvision_set_output(usbvision, usbvision->curwidth, usbvision->curheight);
-			up(&usbvision->lock);
-			return 0;
-		}
-		case VIDIOC_G_STD:
-		{
-			v4l2_std_id *id = arg;
-
-			*id = usbvision->tvnorm->id;
-
-			PDEBUG(DBG_IOCTL, "VIDIOC_G_STD std_id=%s", usbvision->tvnorm->name);
-			return 0;
-		}
-		case VIDIOC_S_STD:
-		{
-			v4l2_std_id *id = arg;
-			unsigned int i;
-
-			for (i = 0; i < TVNORMS; i++)
-				if (*id == tvnorms[i].id)
-					break;
-			if (i == TVNORMS)
-				for (i = 0; i < TVNORMS; i++)
-					if (*id & tvnorms[i].id)
-						break;
-			if (i == TVNORMS)
-				return -EINVAL;
-
-			down(&usbvision->lock);
-			usbvision->tvnorm = &tvnorms[i];
-
-			call_i2c_clients(usbvision, VIDIOC_S_STD,
-					 &usbvision->tvnorm->id);
-
-			up(&usbvision->lock);
-
-			PDEBUG(DBG_IOCTL, "VIDIOC_S_STD std_id=%s", usbvision->tvnorm->name);
-			return 0;
-		}
-		case VIDIOC_G_TUNER:
-		{
-			struct v4l2_tuner *vt = arg;
-
-			if (!usbvision->have_tuner || vt->index)	// Only tuner 0
-				return -EINVAL;
-			strcpy(vt->name, "Television");
-			/* Let clients fill in the remainder of this struct */
-			call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
-
-			PDEBUG(DBG_IOCTL, "VIDIOC_G_TUNER signal=%x, afc=%x",vt->signal,vt->afc);
-			return 0;
-		}
-		case VIDIOC_S_TUNER:
-		{
-			struct v4l2_tuner *vt = arg;
-
-			// Only no or one tuner for now
-			if (!usbvision->have_tuner || vt->index)
-				return -EINVAL;
-			/* let clients handle this */
-			call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
-
-			PDEBUG(DBG_IOCTL, "VIDIOC_S_TUNER");
-			return 0;
-		}
-		case VIDIOC_G_FREQUENCY:
-		{
-			struct v4l2_frequency *freq = arg;
-
-			freq->tuner = 0; // Only one tuner
-			freq->type = V4L2_TUNER_ANALOG_TV;
-			freq->frequency = usbvision->freq;
-			PDEBUG(DBG_IOCTL, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)freq->frequency);
-			return 0;
-		}
-		case VIDIOC_S_FREQUENCY:
-		{
-			struct v4l2_frequency *freq = arg;
-
-			// Only no or one tuner for now
-			if (!usbvision->have_tuner || freq->tuner)
-				return -EINVAL;
-
-			usbvision->freq = freq->frequency;
-			call_i2c_clients(usbvision, cmd, freq);
-			PDEBUG(DBG_IOCTL, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)freq->frequency);
-			return 0;
-		}
-		case VIDIOC_G_AUDIO:
-		{
-			struct v4l2_audio *v = arg;
-			memset(v,0, sizeof(v));
-			strcpy(v->name, "TV");
-			PDEBUG(DBG_IOCTL, "VIDIOC_G_AUDIO");
-			return 0;
-		}
-		case VIDIOC_S_AUDIO:
-		{
-			struct v4l2_audio *v = arg;
-			if(v->index) {
-				return -EINVAL;
-			}
-			PDEBUG(DBG_IOCTL, "VIDIOC_S_AUDIO");
-			return 0;
-		}
-		case VIDIOC_QUERYCTRL:
-		{
-			struct v4l2_queryctrl *ctrl = arg;
-			int id=ctrl->id;
-
-			memset(ctrl,0,sizeof(*ctrl));
-			ctrl->id=id;
-
-			call_i2c_clients(usbvision, cmd, arg);
-
-			if (ctrl->type)
-				return 0;
-			else
-				return -EINVAL;
-
-			PDEBUG(DBG_IOCTL,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type);
-		}
-		case VIDIOC_G_CTRL:
-		{
-			struct v4l2_control *ctrl = arg;
-			call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
-			PDEBUG(DBG_IOCTL,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
-			return 0;
-		}
-		case VIDIOC_S_CTRL:
-		{
-			struct v4l2_control *ctrl = arg;
-
-			PDEBUG(DBG_IOCTL, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value);
-			call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
-			return 0;
-		}
-		case VIDIOC_REQBUFS:
-		{
-			struct v4l2_requestbuffers *vr = arg;
-			int ret;
-
-			RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
-
-			// Check input validity : the user must do a VIDEO CAPTURE and MMAP method.
-			if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
-			   (vr->memory != V4L2_MEMORY_MMAP))
-				return -EINVAL;
-
-			if(usbvision->streaming == Stream_On) {
-				if ((ret = usbvision_stream_interrupt(usbvision)))
-				    return ret;
-			}
-
-			usbvision_frames_free(usbvision);
-			usbvision_empty_framequeues(usbvision);
-			vr->count = usbvision_frames_alloc(usbvision,vr->count);
-
-			usbvision->curFrame = NULL;
-
-			PDEBUG(DBG_IOCTL, "VIDIOC_REQBUFS count=%d",vr->count);
-			return 0;
-		}
-		case VIDIOC_QUERYBUF:
-		{
-			struct v4l2_buffer *vb = arg;
-			struct usbvision_frame *frame;
-
-			// FIXME : must control that buffers are mapped (VIDIOC_REQBUFS has been called)
-
-			if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
-				return -EINVAL;
-			}
-			if(vb->index>=usbvision->num_frames)  {
-				return -EINVAL;
-			}
-			// Updating the corresponding frame state
-			vb->flags = 0;
-			frame = &usbvision->frame[vb->index];
-			if(frame->grabstate >= FrameState_Ready)
-				vb->flags |= V4L2_BUF_FLAG_QUEUED;
-			if(frame->grabstate >= FrameState_Done)
-				vb->flags |= V4L2_BUF_FLAG_DONE;
-			if(frame->grabstate == FrameState_Unused)
-				vb->flags |= V4L2_BUF_FLAG_MAPPED;
-			vb->memory = V4L2_MEMORY_MMAP;
-
-			vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
-
-			vb->memory = V4L2_MEMORY_MMAP;
-			vb->field = V4L2_FIELD_NONE;
-			vb->length = usbvision->curwidth*usbvision->curheight*usbvision->palette.bytes_per_pixel;
-			vb->timestamp = usbvision->frame[vb->index].timestamp;
-			vb->sequence = usbvision->frame[vb->index].sequence;
-			return 0;
-		}
-		case VIDIOC_QBUF:
-		{
-			struct v4l2_buffer *vb = arg;
-			struct usbvision_frame *frame;
-			unsigned long lock_flags;
-
-			// FIXME : works only on VIDEO_CAPTURE MODE, MMAP.
-			if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
-				return -EINVAL;
-			}
-			if(vb->index>=usbvision->num_frames)  {
-				return -EINVAL;
-			}
-
-			frame = &usbvision->frame[vb->index];
-
-			if (frame->grabstate != FrameState_Unused) {
-				return -EAGAIN;
-			}
-
-			/* Mark it as ready and enqueue frame */
-			frame->grabstate = FrameState_Ready;
-			frame->scanstate = ScanState_Scanning;
-			frame->scanlength = 0;	/* Accumulated in usbvision_parse_data() */
-
-			vb->flags &= ~V4L2_BUF_FLAG_DONE;
-
-			/* set v4l2_format index */
-			frame->v4l2_format = usbvision->palette;
-
-			spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
-			list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue);
-			spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
-
-			PDEBUG(DBG_IOCTL, "VIDIOC_QBUF frame #%d",vb->index);
-			return 0;
-		}
-		case VIDIOC_DQBUF:
-		{
-			struct v4l2_buffer *vb = arg;
-			int ret;
-			struct usbvision_frame *f;
-			unsigned long lock_flags;
-
-			if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-				return -EINVAL;
-
-			if (list_empty(&(usbvision->outqueue))) {
-				if (usbvision->streaming == Stream_Idle)
-					return -EINVAL;
-				ret = wait_event_interruptible
-					(usbvision->wait_frame,
-					 !list_empty(&(usbvision->outqueue)));
-				if (ret)
-					return ret;
-			}
-
-			spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
-			f = list_entry(usbvision->outqueue.next,
-				       struct usbvision_frame, frame);
-			list_del(usbvision->outqueue.next);
-			spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
-
-			f->grabstate = FrameState_Unused;
-
-			vb->memory = V4L2_MEMORY_MMAP;
-			vb->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE;
-			vb->index = f->index;
-			vb->sequence = f->sequence;
-			vb->timestamp = f->timestamp;
-			vb->field = V4L2_FIELD_NONE;
-			vb->bytesused = f->scanlength;
-
-			return 0;
-		}
-		case VIDIOC_STREAMON:
-		{
-			int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-			usbvision->streaming = Stream_On;
-
-			call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
-
-			PDEBUG(DBG_IOCTL, "VIDIOC_STREAMON");
-
-			return 0;
-		}
-		case VIDIOC_STREAMOFF:
-		{
-			int *type = arg;
-			int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-			if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-				return -EINVAL;
-
-			if(usbvision->streaming == Stream_On) {
-				usbvision_stream_interrupt(usbvision);
-				// Stop all video streamings
-				call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
-			}
-			usbvision_empty_framequeues(usbvision);
-
-			PDEBUG(DBG_IOCTL, "VIDIOC_STREAMOFF");
-			return 0;
-		}
-		case VIDIOC_ENUM_FMT:
-		{
-			struct v4l2_fmtdesc *vfd = arg;
-
-			if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
-				return -EINVAL;
-			}
-			vfd->flags = 0;
-			vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-			strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
-			vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
-			memset(vfd->reserved, 0, sizeof(vfd->reserved));
-			return 0;
-		}
-		case VIDIOC_G_FMT:
-		{
-			struct v4l2_format *vf = arg;
-
-			switch (vf->type) {
-				case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-				{
-					vf->fmt.pix.width = usbvision->curwidth;
-					vf->fmt.pix.height = usbvision->curheight;
-					vf->fmt.pix.pixelformat = usbvision->palette.format;
-					vf->fmt.pix.bytesperline =  usbvision->curwidth*usbvision->palette.bytes_per_pixel;
-					vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight;
-					vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
-					vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */
-					PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT w=%d, h=%d, format=%s",
-					       vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
-					return 0;
-				}
-				default:
-					PDEBUG(DBG_IOCTL, "VIDIOC_G_FMT invalid type %d",vf->type);
-					return -EINVAL;
-			}
-			return 0;
-		}
-		case VIDIOC_TRY_FMT:
-		case VIDIOC_S_FMT:
-		{
-			struct v4l2_format *vf = arg;
-			int formatIdx,ret;
-
-			switch(vf->type) {
-				case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-				{
-					/* Find requested format in available ones */
-					for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) {
-						if(vf->fmt.pix.pixelformat == usbvision_v4l2_format[formatIdx].format) {
-							usbvision->palette = usbvision_v4l2_format[formatIdx];
-							break;
-						}
-					}
-					/* robustness */
-					if(formatIdx == USBVISION_SUPPORTED_PALETTES) {
-						return -EINVAL;
-					}
-					RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
-					RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
-
-					vf->fmt.pix.bytesperline = vf->fmt.pix.width*usbvision->palette.bytes_per_pixel;
-					vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height;
-
-					if(cmd == VIDIOC_TRY_FMT) {
-						PDEBUG(DBG_IOCTL, "VIDIOC_TRY_FMT grabdisplay w=%d, h=%d, format=%s",
-					       vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
-						return 0;
-					}
-
-					/* stop io in case it is already in progress */
-					if(usbvision->streaming == Stream_On) {
-						if ((ret = usbvision_stream_interrupt(usbvision)))
-							return ret;
-					}
-					usbvision_frames_free(usbvision);
-					usbvision_empty_framequeues(usbvision);
-
-					usbvision->curFrame = NULL;
-
-					// by now we are committed to the new data...
-					down(&usbvision->lock);
-					usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
-					up(&usbvision->lock);
-
-					PDEBUG(DBG_IOCTL, "VIDIOC_S_FMT grabdisplay w=%d, h=%d, format=%s",
-					       vf->fmt.pix.width, vf->fmt.pix.height,usbvision->palette.desc);
-					return 0;
-				}
-				default:
-					return -EINVAL;
-			}
-		}
-		default:
-			return -ENOIOCTLCMD;
+		vi->std = V4L2_STD_PAL;
+		break;
+	case 3:
+		vi->type = V4L2_INPUT_TYPE_CAMERA;
+		strcpy(vi->name, "Red Video Input");
+		vi->std = V4L2_STD_PAL;
+		break;
 	}
 	return 0;
 }
 
-static int usbvision_v4l2_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg)
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *input)
 {
-	return video_usercopy(inode, file, cmd, arg, usbvision_v4l2_do_ioctl);
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+
+	*input = usbvision->ctl_input;
+	return 0;
 }
 
+static int vidioc_s_input (struct file *file, void *priv, unsigned int input)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+
+	if ((input >= usbvision->video_inputs) || (input < 0) )
+		return -EINVAL;
+
+	down(&usbvision->lock);
+	usbvision_muxsel(usbvision, input);
+	usbvision_set_input(usbvision);
+	usbvision_set_output(usbvision,
+			     usbvision->curwidth,
+			     usbvision->curheight);
+	up(&usbvision->lock);
+	return 0;
+}
+
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+	usbvision->tvnormId=*id;
+
+	down(&usbvision->lock);
+	call_i2c_clients(usbvision, VIDIOC_S_STD,
+			 &usbvision->tvnormId);
+	up(&usbvision->lock);
+	/* propagate the change to the decoder */
+	usbvision_muxsel(usbvision, usbvision->ctl_input);
+
+	return 0;
+}
+
+static int vidioc_g_tuner (struct file *file, void *priv,
+				struct v4l2_tuner *vt)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+
+	if (!usbvision->have_tuner || vt->index)	// Only tuner 0
+		return -EINVAL;
+	if(usbvision->radio) {
+		strcpy(vt->name, "Radio");
+		vt->type = V4L2_TUNER_RADIO;
+	} else {
+		strcpy(vt->name, "Television");
+	}
+	/* Let clients fill in the remainder of this struct */
+	call_i2c_clients(usbvision,VIDIOC_G_TUNER,vt);
+
+	return 0;
+}
+
+static int vidioc_s_tuner (struct file *file, void *priv,
+				struct v4l2_tuner *vt)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+
+	// Only no or one tuner for now
+	if (!usbvision->have_tuner || vt->index)
+		return -EINVAL;
+	/* let clients handle this */
+	call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
+
+	return 0;
+}
+
+static int vidioc_g_frequency (struct file *file, void *priv,
+				struct v4l2_frequency *freq)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+
+	freq->tuner = 0; // Only one tuner
+	if(usbvision->radio) {
+		freq->type = V4L2_TUNER_RADIO;
+	} else {
+		freq->type = V4L2_TUNER_ANALOG_TV;
+	}
+	freq->frequency = usbvision->freq;
+
+	return 0;
+}
+
+static int vidioc_s_frequency (struct file *file, void *priv,
+				struct v4l2_frequency *freq)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+
+	// Only no or one tuner for now
+	if (!usbvision->have_tuner || freq->tuner)
+		return -EINVAL;
+
+	usbvision->freq = freq->frequency;
+	call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, freq);
+
+	return 0;
+}
+
+static int vidioc_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+
+	memset(a,0,sizeof(*a));
+	if(usbvision->radio) {
+		strcpy(a->name,"Radio");
+	} else {
+		strcpy(a->name, "TV");
+	}
+
+	return 0;
+}
+
+static int vidioc_s_audio (struct file *file, void *fh,
+			  struct v4l2_audio *a)
+{
+	if(a->index) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int vidioc_queryctrl (struct file *file, void *priv,
+			    struct v4l2_queryctrl *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+	int id=ctrl->id;
+
+	memset(ctrl,0,sizeof(*ctrl));
+	ctrl->id=id;
+
+	call_i2c_clients(usbvision, VIDIOC_QUERYCTRL, ctrl);
+
+	if (!ctrl->type)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int vidioc_g_ctrl (struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+	call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
+
+	return 0;
+}
+
+static int vidioc_s_ctrl (struct file *file, void *priv,
+				struct v4l2_control *ctrl)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+	call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
+
+	return 0;
+}
+
+static int vidioc_reqbufs (struct file *file,
+			   void *priv, struct v4l2_requestbuffers *vr)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+	int ret;
+
+	RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
+
+	/* Check input validity:
+	   the user must do a VIDEO CAPTURE and MMAP method. */
+	if((vr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
+	   (vr->memory != V4L2_MEMORY_MMAP))
+		return -EINVAL;
+
+	if(usbvision->streaming == Stream_On) {
+		if ((ret = usbvision_stream_interrupt(usbvision)))
+			return ret;
+	}
+
+	usbvision_frames_free(usbvision);
+	usbvision_empty_framequeues(usbvision);
+	vr->count = usbvision_frames_alloc(usbvision,vr->count);
+
+	usbvision->curFrame = NULL;
+
+	return 0;
+}
+
+static int vidioc_querybuf (struct file *file,
+			    void *priv, struct v4l2_buffer *vb)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usbvision_frame *frame;
+
+	/* FIXME : must control
+	   that buffers are mapped (VIDIOC_REQBUFS has been called) */
+	if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
+		return -EINVAL;
+	}
+	if(vb->index>=usbvision->num_frames)  {
+		return -EINVAL;
+	}
+	/* Updating the corresponding frame state */
+	vb->flags = 0;
+	frame = &usbvision->frame[vb->index];
+	if(frame->grabstate >= FrameState_Ready)
+		vb->flags |= V4L2_BUF_FLAG_QUEUED;
+	if(frame->grabstate >= FrameState_Done)
+		vb->flags |= V4L2_BUF_FLAG_DONE;
+	if(frame->grabstate == FrameState_Unused)
+		vb->flags |= V4L2_BUF_FLAG_MAPPED;
+	vb->memory = V4L2_MEMORY_MMAP;
+
+	vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
+
+	vb->memory = V4L2_MEMORY_MMAP;
+	vb->field = V4L2_FIELD_NONE;
+	vb->length = usbvision->curwidth*
+		usbvision->curheight*
+		usbvision->palette.bytes_per_pixel;
+	vb->timestamp = usbvision->frame[vb->index].timestamp;
+	vb->sequence = usbvision->frame[vb->index].sequence;
+	return 0;
+}
+
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+	struct usbvision_frame *frame;
+	unsigned long lock_flags;
+
+	/* FIXME : works only on VIDEO_CAPTURE MODE, MMAP. */
+	if(vb->type != V4L2_CAP_VIDEO_CAPTURE) {
+		return -EINVAL;
+	}
+	if(vb->index>=usbvision->num_frames)  {
+		return -EINVAL;
+	}
+
+	frame = &usbvision->frame[vb->index];
+
+	if (frame->grabstate != FrameState_Unused) {
+		return -EAGAIN;
+	}
+
+	/* Mark it as ready and enqueue frame */
+	frame->grabstate = FrameState_Ready;
+	frame->scanstate = ScanState_Scanning;
+	frame->scanlength = 0;	/* Accumulated in usbvision_parse_data() */
+
+	vb->flags &= ~V4L2_BUF_FLAG_DONE;
+
+	/* set v4l2_format index */
+	frame->v4l2_format = usbvision->palette;
+
+	spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+	list_add_tail(&usbvision->frame[vb->index].frame, &usbvision->inqueue);
+	spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+	return 0;
+}
+
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+	int ret;
+	struct usbvision_frame *f;
+	unsigned long lock_flags;
+
+	if (vb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if (list_empty(&(usbvision->outqueue))) {
+		if (usbvision->streaming == Stream_Idle)
+			return -EINVAL;
+		ret = wait_event_interruptible
+			(usbvision->wait_frame,
+			 !list_empty(&(usbvision->outqueue)));
+		if (ret)
+			return ret;
+	}
+
+	spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
+	f = list_entry(usbvision->outqueue.next,
+		       struct usbvision_frame, frame);
+	list_del(usbvision->outqueue.next);
+	spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+
+	f->grabstate = FrameState_Unused;
+
+	vb->memory = V4L2_MEMORY_MMAP;
+	vb->flags = V4L2_BUF_FLAG_MAPPED |
+		V4L2_BUF_FLAG_QUEUED |
+		V4L2_BUF_FLAG_DONE;
+	vb->index = f->index;
+	vb->sequence = f->sequence;
+	vb->timestamp = f->timestamp;
+	vb->field = V4L2_FIELD_NONE;
+	vb->bytesused = f->scanlength;
+
+	return 0;
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+	int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	usbvision->streaming = Stream_On;
+	call_i2c_clients(usbvision,VIDIOC_STREAMON , &b);
+
+	return 0;
+}
+
+static int vidioc_streamoff(struct file *file,
+			    void *priv, enum v4l2_buf_type type)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+	int b=V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	if(usbvision->streaming == Stream_On) {
+		usbvision_stream_interrupt(usbvision);
+		/* Stop all video streamings */
+		call_i2c_clients(usbvision,VIDIOC_STREAMOFF , &b);
+	}
+	usbvision_empty_framequeues(usbvision);
+
+	return 0;
+}
+
+static int vidioc_enum_fmt_cap (struct file *file, void  *priv,
+					struct v4l2_fmtdesc *vfd)
+{
+	if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
+		return -EINVAL;
+	}
+	vfd->flags = 0;
+	vfd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+	strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
+	vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
+	memset(vfd->reserved, 0, sizeof(vfd->reserved));
+	return 0;
+}
+
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+					struct v4l2_format *vf)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+	vf->fmt.pix.width = usbvision->curwidth;
+	vf->fmt.pix.height = usbvision->curheight;
+	vf->fmt.pix.pixelformat = usbvision->palette.format;
+	vf->fmt.pix.bytesperline =
+		usbvision->curwidth*usbvision->palette.bytes_per_pixel;
+	vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight;
+	vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+	vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */
+
+	return 0;
+}
+
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
+			       struct v4l2_format *vf)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+	int formatIdx;
+
+	/* Find requested format in available ones */
+	for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) {
+		if(vf->fmt.pix.pixelformat ==
+		   usbvision_v4l2_format[formatIdx].format) {
+			usbvision->palette = usbvision_v4l2_format[formatIdx];
+			break;
+		}
+	}
+	/* robustness */
+	if(formatIdx == USBVISION_SUPPORTED_PALETTES) {
+		return -EINVAL;
+	}
+	RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
+	RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
+
+	vf->fmt.pix.bytesperline = vf->fmt.pix.width*
+		usbvision->palette.bytes_per_pixel;
+	vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height;
+
+	return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+			       struct v4l2_format *vf)
+{
+	struct video_device *dev = video_devdata(file);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
+	int ret;
+
+	if( 0 != (ret=vidioc_try_fmt_cap (file, priv, vf)) ) {
+		return ret;
+	}
+
+	/* stop io in case it is already in progress */
+	if(usbvision->streaming == Stream_On) {
+		if ((ret = usbvision_stream_interrupt(usbvision)))
+			return ret;
+	}
+	usbvision_frames_free(usbvision);
+	usbvision_empty_framequeues(usbvision);
+
+	usbvision->curFrame = NULL;
+
+	/* by now we are committed to the new data... */
+	down(&usbvision->lock);
+	usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
+	up(&usbvision->lock);
+
+	return 0;
+}
 
 static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
 		      size_t count, loff_t *ppos)
 {
 	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
 	int noblock = file->f_flags & O_NONBLOCK;
 	unsigned long lock_flags;
 
 	int ret,i;
 	struct usbvision_frame *frame;
 
-	PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__, (unsigned long)count, noblock);
+	PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__,
+	       (unsigned long)count, noblock);
 
 	if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL))
 		return -EFAULT;
 
-	/* This entry point is compatible with the mmap routines so that a user can do either
-	   VIDIOC_QBUF/VIDIOC_DQBUF to get frames or call read on the device. */
+	/* This entry point is compatible with the mmap routines
+	   so that a user can do either VIDIOC_QBUF/VIDIOC_DQBUF
+	   to get frames or call read on the device. */
 	if(!usbvision->num_frames) {
-		/* First, allocate some frames to work with if this has not been done with
-		 VIDIOC_REQBUF */
+		/* First, allocate some frames to work with
+		   if this has not been done with VIDIOC_REQBUF */
 		usbvision_frames_free(usbvision);
 		usbvision_empty_framequeues(usbvision);
 		usbvision_frames_alloc(usbvision,USBVISION_NUMFRAMES);
@@ -1086,21 +1125,24 @@
 		call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL);
 	}
 
-	/* Then, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */
+	/* Then, enqueue as many frames as possible
+	   (like a user of VIDIOC_QBUF would do) */
 	for(i=0;i<usbvision->num_frames;i++) {
 		frame = &usbvision->frame[i];
 		if(frame->grabstate == FrameState_Unused) {
 			/* Mark it as ready and enqueue frame */
 			frame->grabstate = FrameState_Ready;
 			frame->scanstate = ScanState_Scanning;
-			frame->scanlength = 0;	/* Accumulated in usbvision_parse_data() */
+			/* Accumulated in usbvision_parse_data() */
+			frame->scanlength = 0;
 
 			/* set v4l2_format index */
 			frame->v4l2_format = usbvision->palette;
 
 			spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
 			list_add_tail(&frame->frame, &usbvision->inqueue);
-			spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
+			spin_unlock_irqrestore(&usbvision->queue_lock,
+					       lock_flags);
 		}
 	}
 
@@ -1128,8 +1170,9 @@
 		return 0;
 	}
 
-	PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", __FUNCTION__,
-		       frame->index, frame->bytes_read, frame->scanlength);
+	PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld",
+	       __FUNCTION__,
+	       frame->index, frame->bytes_read, frame->scanlength);
 
 	/* copy bytes to user space; we allow for partials reads */
 	if ((count + frame->bytes_read) > (unsigned long)frame->scanlength)
@@ -1140,10 +1183,11 @@
 	}
 
 	frame->bytes_read += count;
-	PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", __FUNCTION__,
-		       (unsigned long)count, frame->bytes_read);
+	PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld",
+	       __FUNCTION__,
+	       (unsigned long)count, frame->bytes_read);
 
-	// For now, forget the frame if it has not been read in one shot.
+	/* For now, forget the frame if it has not been read in one shot. */
 /* 	if (frame->bytes_read >= frame->scanlength) {// All data has been read */
 		frame->bytes_read = 0;
 
@@ -1162,7 +1206,8 @@
 	u32 i;
 
 	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
 
 	PDEBUG(DBG_MMAP, "mmap");
 
@@ -1180,11 +1225,13 @@
 	}
 
 	for (i = 0; i < usbvision->num_frames; i++) {
-		if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) == vma->vm_pgoff)
+		if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) ==
+		    vma->vm_pgoff)
 			break;
 	}
 	if (i == usbvision->num_frames) {
-		PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range");
+		PDEBUG(DBG_MMAP,
+		       "mmap: user supplied mapping address is out of range");
 		up(&usbvision->lock);
 		return -EINVAL;
 	}
@@ -1218,8 +1265,8 @@
 static int usbvision_radio_open(struct inode *inode, struct file *file)
 {
 	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
-	struct v4l2_frequency freq;
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
 	int errCode = 0;
 
 	PDEBUG(DBG_IO, "%s:", __FUNCTION__);
@@ -1249,8 +1296,6 @@
 		// If so far no errors then we shall start the radio
 		usbvision->radio = 1;
 		call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type);
-		freq.frequency = 1517; //SWR3 @ 94.8MHz
-		call_i2c_clients(usbvision, VIDIOC_S_FREQUENCY, &freq);
 		usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO);
 		usbvision->user++;
 	}
@@ -1270,7 +1315,8 @@
 static int usbvision_radio_close(struct inode *inode, struct file *file)
 {
 	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
+	struct usb_usbvision *usbvision =
+		(struct usb_usbvision *) video_get_drvdata(dev);
 	int errCode = 0;
 
 	PDEBUG(DBG_IO, "");
@@ -1304,149 +1350,6 @@
 	return errCode;
 }
 
-static int usbvision_do_radio_ioctl(struct inode *inode, struct file *file,
-				 unsigned int cmd, void *arg)
-{
-	struct video_device *dev = video_devdata(file);
-	struct usb_usbvision *usbvision = (struct usb_usbvision *) video_get_drvdata(dev);
-
-	if (!USBVISION_IS_OPERATIONAL(usbvision))
-		return -EIO;
-
-	switch (cmd) {
-		case VIDIOC_QUERYCAP:
-		{
-			struct v4l2_capability *vc=arg;
-
-			memset(vc, 0, sizeof(*vc));
-			strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
-			strlcpy(vc->card, usbvision_device_data[usbvision->DevModel].ModelString,
-				sizeof(vc->card));
-			strlcpy(vc->bus_info, usbvision->dev->dev.bus_id,
-				sizeof(vc->bus_info));
-			vc->version = USBVISION_DRIVER_VERSION;
-			vc->capabilities = (usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
-			PDEBUG(DBG_IO, "VIDIOC_QUERYCAP");
-			return 0;
-		}
-		case VIDIOC_QUERYCTRL:
-		{
-			struct v4l2_queryctrl *ctrl = arg;
-			int id=ctrl->id;
-
-			memset(ctrl,0,sizeof(*ctrl));
-			ctrl->id=id;
-
-			call_i2c_clients(usbvision, cmd, arg);
-			PDEBUG(DBG_IO,"VIDIOC_QUERYCTRL id=%x value=%x",ctrl->id,ctrl->type);
-
-			if (ctrl->type)
-				return 0;
-			else
-				return -EINVAL;
-
-		}
-		case VIDIOC_G_CTRL:
-		{
-			struct v4l2_control *ctrl = arg;
-
-			call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl);
-			PDEBUG(DBG_IO,"VIDIOC_G_CTRL id=%x value=%x",ctrl->id,ctrl->value);
-			return 0;
-		}
-		case VIDIOC_S_CTRL:
-		{
-			struct v4l2_control *ctrl = arg;
-
-			call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl);
-			PDEBUG(DBG_IO, "VIDIOC_S_CTRL id=%x value=%x",ctrl->id,ctrl->value);
-			return 0;
-		}
-		case VIDIOC_G_TUNER:
-		{
-			struct v4l2_tuner *t = arg;
-
-			if (t->index > 0)
-				return -EINVAL;
-
-			memset(t,0,sizeof(*t));
-			strcpy(t->name, "Radio");
-			t->type = V4L2_TUNER_RADIO;
-
-			/* Let clients fill in the remainder of this struct */
-			call_i2c_clients(usbvision,VIDIOC_G_TUNER,t);
-			PDEBUG(DBG_IO, "VIDIOC_G_TUNER signal=%x, afc=%x",t->signal,t->afc);
-			return 0;
-		}
-		case VIDIOC_S_TUNER:
-		{
-			struct v4l2_tuner *vt = arg;
-
-			// Only no or one tuner for now
-			if (!usbvision->have_tuner || vt->index)
-				return -EINVAL;
-			/* let clients handle this */
-			call_i2c_clients(usbvision,VIDIOC_S_TUNER,vt);
-
-			PDEBUG(DBG_IO, "VIDIOC_S_TUNER");
-			return 0;
-		}
-		case VIDIOC_G_AUDIO:
-		{
-			struct v4l2_audio *a = arg;
-
-			memset(a,0,sizeof(*a));
-			strcpy(a->name,"Radio");
-			PDEBUG(DBG_IO, "VIDIOC_G_AUDIO");
-			return 0;
-		}
-		case VIDIOC_S_AUDIO:
-		case VIDIOC_S_INPUT:
-		case VIDIOC_S_STD:
-		return 0;
-
-		case VIDIOC_G_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
-
-			memset(f,0,sizeof(*f));
-
-			f->type = V4L2_TUNER_RADIO;
-			f->frequency = usbvision->freq;
-			call_i2c_clients(usbvision, cmd, f);
-			PDEBUG(DBG_IO, "VIDIOC_G_FREQUENCY freq=0x%X", (unsigned)f->frequency);
-
-			return 0;
-		}
-		case VIDIOC_S_FREQUENCY:
-		{
-			struct v4l2_frequency *f = arg;
-
-			if (f->tuner != 0)
-				return -EINVAL;
-			usbvision->freq = f->frequency;
-			call_i2c_clients(usbvision, cmd, f);
-			PDEBUG(DBG_IO, "VIDIOC_S_FREQUENCY freq=0x%X", (unsigned)f->frequency);
-
-			return 0;
-		}
-		default:
-		{
-			PDEBUG(DBG_IO, "%s: Unknown command %x", __FUNCTION__, cmd);
-			return -ENOIOCTLCMD;
-		}
-	}
-	return 0;
-}
-
-
-static int usbvision_radio_ioctl(struct inode *inode, struct file *file,
-		       unsigned int cmd, unsigned long arg)
-{
-	return video_usercopy(inode, file, cmd, arg, usbvision_do_radio_ioctl);
-}
-
-
 /*
  * Here comes the stuff for vbi on usbvision based devices
  *
@@ -1454,21 +1357,21 @@
 static int usbvision_vbi_open(struct inode *inode, struct file *file)
 {
 	/* TODO */
-	return -EINVAL;
+	return -ENODEV;
 
 }
 
 static int usbvision_vbi_close(struct inode *inode, struct file *file)
 {
 	/* TODO */
-	return -EINVAL;
+	return -ENODEV;
 }
 
 static int usbvision_do_vbi_ioctl(struct inode *inode, struct file *file,
 				 unsigned int cmd, void *arg)
 {
 	/* TODO */
-	return -EINVAL;
+	return -ENOIOCTLCMD;
 }
 
 static int usbvision_vbi_ioctl(struct inode *inode, struct file *file,
@@ -1489,8 +1392,10 @@
 	.release	= usbvision_v4l2_close,
 	.read		= usbvision_v4l2_read,
 	.mmap		= usbvision_v4l2_mmap,
-	.ioctl		= usbvision_v4l2_ioctl,
+	.ioctl		= video_ioctl2,
 	.llseek		= no_llseek,
+/* 	.poll          = video_poll, */
+	.compat_ioctl  = v4l_compat_ioctl32,
 };
 static struct video_device usbvision_video_template = {
 	.owner             = THIS_MODULE,
@@ -1500,6 +1405,39 @@
 	.name           = "usbvision-video",
 	.release	= video_device_release,
 	.minor		= -1,
+	.vidioc_querycap      = vidioc_querycap,
+	.vidioc_enum_fmt_cap  = vidioc_enum_fmt_cap,
+	.vidioc_g_fmt_cap     = vidioc_g_fmt_cap,
+	.vidioc_try_fmt_cap   = vidioc_try_fmt_cap,
+	.vidioc_s_fmt_cap     = vidioc_s_fmt_cap,
+	.vidioc_reqbufs       = vidioc_reqbufs,
+	.vidioc_querybuf      = vidioc_querybuf,
+	.vidioc_qbuf          = vidioc_qbuf,
+	.vidioc_dqbuf         = vidioc_dqbuf,
+	.vidioc_s_std         = vidioc_s_std,
+	.vidioc_enum_input    = vidioc_enum_input,
+	.vidioc_g_input       = vidioc_g_input,
+	.vidioc_s_input       = vidioc_s_input,
+	.vidioc_queryctrl     = vidioc_queryctrl,
+	.vidioc_g_audio       = vidioc_g_audio,
+	.vidioc_s_audio       = vidioc_s_audio,
+	.vidioc_g_ctrl        = vidioc_g_ctrl,
+	.vidioc_s_ctrl        = vidioc_s_ctrl,
+	.vidioc_streamon      = vidioc_streamon,
+	.vidioc_streamoff     = vidioc_streamoff,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+/*  	.vidiocgmbuf          = vidiocgmbuf, */
+#endif
+	.vidioc_g_tuner       = vidioc_g_tuner,
+	.vidioc_s_tuner       = vidioc_s_tuner,
+	.vidioc_g_frequency   = vidioc_g_frequency,
+	.vidioc_s_frequency   = vidioc_s_frequency,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.vidioc_g_register    = vidioc_g_register,
+	.vidioc_s_register    = vidioc_s_register,
+#endif
+	.tvnorms              = USBVISION_NORMS,
+	.current_norm         = V4L2_STD_PAL
 };
 
 
@@ -1508,8 +1446,9 @@
 	.owner             = THIS_MODULE,
 	.open		= usbvision_radio_open,
 	.release	= usbvision_radio_close,
-	.ioctl		= usbvision_radio_ioctl,
+	.ioctl		= video_ioctl2,
 	.llseek		= no_llseek,
+	.compat_ioctl  = v4l_compat_ioctl32,
 };
 
 static struct video_device usbvision_radio_template=
@@ -1518,11 +1457,26 @@
 	.type		= VID_TYPE_TUNER,
 	.hardware	= VID_HARDWARE_USBVISION,
 	.fops		= &usbvision_radio_fops,
-	.release	= video_device_release,
 	.name           = "usbvision-radio",
+	.release	= video_device_release,
 	.minor		= -1,
-};
+	.vidioc_querycap      = vidioc_querycap,
+	.vidioc_enum_input    = vidioc_enum_input,
+	.vidioc_g_input       = vidioc_g_input,
+	.vidioc_s_input       = vidioc_s_input,
+	.vidioc_queryctrl     = vidioc_queryctrl,
+	.vidioc_g_audio       = vidioc_g_audio,
+	.vidioc_s_audio       = vidioc_s_audio,
+	.vidioc_g_ctrl        = vidioc_g_ctrl,
+	.vidioc_s_ctrl        = vidioc_s_ctrl,
+	.vidioc_g_tuner       = vidioc_g_tuner,
+	.vidioc_s_tuner       = vidioc_s_tuner,
+	.vidioc_g_frequency   = vidioc_g_frequency,
+	.vidioc_s_frequency   = vidioc_s_frequency,
 
+	.tvnorms              = USBVISION_NORMS,
+	.current_norm         = V4L2_STD_PAL
+};
 
 // vbi template
 static const struct file_operations usbvision_vbi_fops = {
@@ -1531,6 +1485,7 @@
 	.release	= usbvision_vbi_close,
 	.ioctl		= usbvision_vbi_ioctl,
 	.llseek		= no_llseek,
+	.compat_ioctl  = v4l_compat_ioctl32,
 };
 
 static struct video_device usbvision_vbi_template=
@@ -1574,11 +1529,11 @@
 {
 	// vbi Device:
 	if (usbvision->vbi) {
-		PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]", usbvision->vbi->minor & 0x1f);
+		PDEBUG(DBG_PROBE, "unregister /dev/vbi%d [v4l2]",
+		       usbvision->vbi->minor & 0x1f);
 		if (usbvision->vbi->minor != -1) {
 			video_unregister_device(usbvision->vbi);
-		}
-		else {
+		} else {
 			video_device_release(usbvision->vbi);
 		}
 		usbvision->vbi = NULL;
@@ -1586,11 +1541,11 @@
 
 	// Radio Device:
 	if (usbvision->rdev) {
-		PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]", usbvision->rdev->minor & 0x1f);
+		PDEBUG(DBG_PROBE, "unregister /dev/radio%d [v4l2]",
+		       usbvision->rdev->minor & 0x1f);
 		if (usbvision->rdev->minor != -1) {
 			video_unregister_device(usbvision->rdev);
-		}
-		else {
+		} else {
 			video_device_release(usbvision->rdev);
 		}
 		usbvision->rdev = NULL;
@@ -1598,11 +1553,11 @@
 
 	// Video Device:
 	if (usbvision->vdev) {
-		PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]", usbvision->vdev->minor & 0x1f);
+		PDEBUG(DBG_PROBE, "unregister /dev/video%d [v4l2]",
+		       usbvision->vdev->minor & 0x1f);
 		if (usbvision->vdev->minor != -1) {
 			video_unregister_device(usbvision->vdev);
-		}
-		else {
+		} else {
 			video_device_release(usbvision->vdev);
 		}
 		usbvision->vdev = NULL;
@@ -1613,37 +1568,52 @@
 static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
 {
 	// Video Device:
-	usbvision->vdev = usbvision_vdev_init(usbvision, &usbvision_video_template, "USBVision Video");
+	usbvision->vdev = usbvision_vdev_init(usbvision,
+					      &usbvision_video_template,
+					      "USBVision Video");
 	if (usbvision->vdev == NULL) {
 		goto err_exit;
 	}
-	if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr)<0) {
+	if (video_register_device(usbvision->vdev,
+				  VFL_TYPE_GRABBER,
+				  video_nr)<0) {
 		goto err_exit;
 	}
-	printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n", usbvision->nr,usbvision->vdev->minor & 0x1f);
+	printk(KERN_INFO "USBVision[%d]: registered USBVision Video device /dev/video%d [v4l2]\n",
+	       usbvision->nr,usbvision->vdev->minor & 0x1f);
 
 	// Radio Device:
 	if (usbvision_device_data[usbvision->DevModel].Radio) {
 		// usbvision has radio
-		usbvision->rdev = usbvision_vdev_init(usbvision, &usbvision_radio_template, "USBVision Radio");
+		usbvision->rdev = usbvision_vdev_init(usbvision,
+						      &usbvision_radio_template,
+						      "USBVision Radio");
 		if (usbvision->rdev == NULL) {
 			goto err_exit;
 		}
-		if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr)<0) {
+		if (video_register_device(usbvision->rdev,
+					  VFL_TYPE_RADIO,
+					  radio_nr)<0) {
 			goto err_exit;
 		}
-		printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n", usbvision->nr, usbvision->rdev->minor & 0x1f);
+		printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device /dev/radio%d [v4l2]\n",
+		       usbvision->nr, usbvision->rdev->minor & 0x1f);
 	}
 	// vbi Device:
 	if (usbvision_device_data[usbvision->DevModel].vbi) {
-		usbvision->vbi = usbvision_vdev_init(usbvision, &usbvision_vbi_template, "USBVision VBI");
+		usbvision->vbi = usbvision_vdev_init(usbvision,
+						     &usbvision_vbi_template,
+						     "USBVision VBI");
 		if (usbvision->vdev == NULL) {
 			goto err_exit;
 		}
-		if (video_register_device(usbvision->vbi, VFL_TYPE_VBI, vbi_nr)<0) {
+		if (video_register_device(usbvision->vbi,
+					  VFL_TYPE_VBI,
+					  vbi_nr)<0) {
 			goto err_exit;
 		}
-		printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n", usbvision->nr,usbvision->vbi->minor & 0x1f);
+		printk(KERN_INFO "USBVision[%d]: registered USBVision VBI device /dev/vbi%d [v4l2] (Not Working Yet!)\n",
+		       usbvision->nr,usbvision->vbi->minor & 0x1f);
 	}
 	// all done
 	return 0;
@@ -1657,7 +1627,8 @@
 /*
  * usbvision_alloc()
  *
- * This code allocates the struct usb_usbvision. It is filled with default values.
+ * This code allocates the struct usb_usbvision.
+ * It is filled with default values.
  *
  * Returns NULL on error, a pointer to usb_usbvision else.
  *
@@ -1666,7 +1637,8 @@
 {
 	struct usb_usbvision *usbvision;
 
-	if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) == NULL) {
+	if ((usbvision = kzalloc(sizeof(struct usb_usbvision), GFP_KERNEL)) ==
+	    NULL) {
 		goto err_exit;
 	}
 
@@ -1728,11 +1700,11 @@
 }
 
 
-/******************************** usb interface *****************************************/
+/*********************** usb interface **********************************/
 
 static void usbvision_configure_video(struct usb_usbvision *usbvision)
 {
-	int model,i;
+	int model;
 
 	if (usbvision == NULL)
 		return;
@@ -1741,25 +1713,23 @@
 	usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24;
 
 	if (usbvision_device_data[usbvision->DevModel].Vin_Reg2_override) {
-		usbvision->Vin_Reg2_Preset = usbvision_device_data[usbvision->DevModel].Vin_Reg2;
+		usbvision->Vin_Reg2_Preset =
+			usbvision_device_data[usbvision->DevModel].Vin_Reg2;
 	} else {
 		usbvision->Vin_Reg2_Preset = 0;
 	}
 
-	for (i = 0; i < TVNORMS; i++)
-		if (usbvision_device_data[model].VideoNorm == tvnorms[i].mode)
-			break;
-	if (i == TVNORMS)
-		i = 0;
-	usbvision->tvnorm = &tvnorms[i];        /* set default norm */
+	usbvision->tvnormId = usbvision_device_data[model].VideoNorm;
 
 	usbvision->video_inputs = usbvision_device_data[model].VideoChannels;
 	usbvision->ctl_input = 0;
 
 	/* This should be here to make i2c clients to be able to register */
-	usbvision_audio_off(usbvision);	//first switch off audio
+	/* first switch off audio */
+	usbvision_audio_off(usbvision);
 	if (!PowerOnAtOpen) {
-		usbvision_power_on(usbvision);	//and then power up the noisy tuner
+		/* and then power up the noisy tuner */
+		usbvision_power_on(usbvision);
 		usbvision_i2c_register(usbvision);
 	}
 }
@@ -1796,18 +1766,22 @@
 
 	if (usbvision_device_data[model].Interface >= 0) {
 		interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0];
-	}
-	else {
+	} else {
 		interface = &dev->actconfig->interface[ifnum]->altsetting[0];
 	}
 	endpoint = &interface->endpoint[1].desc;
-	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC) {
-		err("%s: interface %d. has non-ISO endpoint!", __FUNCTION__, ifnum);
-		err("%s: Endpoint attributes %d", __FUNCTION__, endpoint->bmAttributes);
+	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+	    USB_ENDPOINT_XFER_ISOC) {
+		err("%s: interface %d. has non-ISO endpoint!",
+		    __FUNCTION__, ifnum);
+		err("%s: Endpoint attributes %d",
+		    __FUNCTION__, endpoint->bmAttributes);
 		return -ENODEV;
 	}
-	if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
-		err("%s: interface %d. has ISO OUT endpoint!", __FUNCTION__, ifnum);
+	if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
+	    USB_DIR_OUT) {
+		err("%s: interface %d. has ISO OUT endpoint!",
+		    __FUNCTION__, ifnum);
 		return -ENODEV;
 	}
 
@@ -1818,11 +1792,9 @@
 
 	if (dev->descriptor.bNumConfigurations > 1) {
 		usbvision->bridgeType = BRIDGE_NT1004;
-	}
-	else if (model == DAZZLE_DVC_90_REV_1_SECAM) {
+	} else if (model == DAZZLE_DVC_90_REV_1_SECAM) {
 		usbvision->bridgeType = BRIDGE_NT1005;
-	}
-	else {
+	} else {
 		usbvision->bridgeType = BRIDGE_NT1003;
 	}
 	PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType);
@@ -1919,11 +1891,11 @@
 	up(&usbvision->lock);
 
 	if (usbvision->user) {
-		printk(KERN_INFO "%s: In use, disconnect pending\n", __FUNCTION__);
+		printk(KERN_INFO "%s: In use, disconnect pending\n",
+		       __FUNCTION__);
 		wake_up_interruptible(&usbvision->wait_frame);
 		wake_up_interruptible(&usbvision->wait_stream);
-	}
-	else {
+	} else {
 		usbvision_release(usbvision);
 	}
 
@@ -1950,7 +1922,6 @@
 
 	PDEBUG(DBG_PROBE, "");
 
-	PDEBUG(DBG_IOCTL, "IOCTL   debugging is enabled [video]");
 	PDEBUG(DBG_IO,  "IO      debugging is enabled [video]");
 	PDEBUG(DBG_PROBE, "PROBE   debugging is enabled [video]");
 	PDEBUG(DBG_MMAP, "MMAP    debugging is enabled [video]");
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
index c759d00..c5b6c50 100644
--- a/drivers/media/video/usbvision/usbvision.h
+++ b/drivers/media/video/usbvision/usbvision.h
@@ -221,6 +221,8 @@
 
 #define I2C_USB_ADAP_MAX	16
 
+#define USBVISION_NORMS (V4L2_STD_PAL | V4L2_STD_NTSC | V4L2_STD_SECAM | V4L2_STD_PAL_M)
+
 /* ----------------------------------------------------------------- */
 /* usbvision video structures                                        */
 /* ----------------------------------------------------------------- */
@@ -301,14 +303,6 @@
 	__u16 frameHeight;				/* 10 - 11 after endian correction*/
 };
 
-/* tvnorms */
-struct usbvision_tvnorm {
-	char *name;
-	v4l2_std_id id;
-	/* mode for saa7113h */
-	int mode;
-};
-
 struct usbvision_frame {
 	char *data;					/* Frame buffer */
 	struct usbvision_frame_header isocHeader;	/* Header from stream */
@@ -386,7 +380,6 @@
 	int tuner_type;
 	int tuner_addr;
 	int bridgeType;							// NT1003, NT1004, NT1005
-	int channel;
 	int radio;
 	int video_inputs;						// # of inputs
 	unsigned long freq;
@@ -441,7 +434,7 @@
 
 	struct v4l2_capability vcap;					/* Video capabilities */
 	unsigned int ctl_input;						/* selected input */
-	struct usbvision_tvnorm *tvnorm;				/* selected tv norm */
+	v4l2_std_id tvnormId;						/* selected tv norm */
 	unsigned char video_endp;					/* 0x82 for USBVISION devices based */
 
 	// Decompression stuff:
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index ede8543..9eac65f 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -19,7 +19,6 @@
 
 #include <linux/init.h>
 #include <linux/module.h>
-#include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 13ee550..c3440b2 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -65,11 +65,6 @@
 #include <linux/kmod.h>
 #endif
 
-#if defined(CONFIG_UST) || defined(CONFIG_UST_MODULE)
-#include <linux/ust.h>
-#endif
-
-
 #include <linux/videodev.h>
 
 MODULE_AUTHOR("Bill Dirks, Justin Schoeman, Gerd Knorr");
@@ -716,6 +711,7 @@
 	case V4L2_CID_AUDIO_MUTE:
 	case V4L2_CID_AUDIO_LOUDNESS:
 	case V4L2_CID_MPEG_AUDIO_MUTE:
+	case V4L2_CID_MPEG_VIDEO_MUTE:
 	case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
 	case V4L2_CID_MPEG_VIDEO_PULLDOWN:
 		qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
@@ -939,16 +935,25 @@
    When no more controls are available 0 is returned. */
 u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
 {
-	u32 ctrl_class;
+	u32 ctrl_class = V4L2_CTRL_ID2CLASS(id);
 	const u32 *pctrl;
 
-	/* if no query is desired, then just return the control ID */
-	if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0)
-		return id;
 	if (ctrl_classes == NULL)
 		return 0;
+
+	/* if no query is desired, then check if the ID is part of ctrl_classes */
+	if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0) {
+		/* find class */
+		while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) != ctrl_class)
+			ctrl_classes++;
+		if (*ctrl_classes == NULL)
+			return 0;
+		pctrl = *ctrl_classes;
+		/* find control ID */
+		while (*pctrl && *pctrl != id) pctrl++;
+		return *pctrl ? id : 0;
+	}
 	id &= V4L2_CTRL_ID_MASK;
-	ctrl_class = V4L2_CTRL_ID2CLASS(id);
 	id++;	/* select next control */
 	/* find first class that matches (or is greater than) the class of
 	   the ID */
diff --git a/drivers/media/video/v4l2-int-device.c b/drivers/media/video/v4l2-int-device.c
new file mode 100644
index 0000000..8b4ef53
--- /dev/null
+++ b/drivers/media/video/v4l2-int-device.c
@@ -0,0 +1,158 @@
+/*
+ * drivers/media/video/v4l2-int-device.c
+ *
+ * V4L2 internal ioctl interface.
+ *
+ * Copyright (C) 2007 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * 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.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/sort.h>
+#include <linux/string.h>
+
+#include <media/v4l2-int-device.h>
+
+static DEFINE_MUTEX(mutex);
+static LIST_HEAD(int_list);
+
+static void v4l2_int_device_try_attach_all(void)
+{
+	struct v4l2_int_device *m, *s;
+
+	list_for_each_entry(m, &int_list, head) {
+		if (m->type != v4l2_int_type_master)
+			continue;
+
+		list_for_each_entry(s, &int_list, head) {
+			if (s->type != v4l2_int_type_slave)
+				continue;
+
+			/* Slave is connected? */
+			if (s->u.slave->master)
+				continue;
+
+			/* Slave wants to attach to master? */
+			if (s->u.slave->attach_to[0] != 0
+			    && strncmp(m->name, s->u.slave->attach_to,
+				       V4L2NAMESIZE))
+				continue;
+
+			if (!try_module_get(m->module))
+				continue;
+
+			if (m->u.master->attach(m, s)) {
+				module_put(m->module);
+				continue;
+			}
+
+			s->u.slave->master = m;
+		}
+	}
+}
+
+static int ioctl_sort_cmp(const void *a, const void *b)
+{
+	const struct v4l2_int_ioctl_desc *d1 = a, *d2 = b;
+
+	if (d1->num > d2->num)
+		return 1;
+
+	if (d1->num < d2->num)
+		return -1;
+
+	return 0;
+}
+
+int v4l2_int_device_register(struct v4l2_int_device *d)
+{
+	if (d->type == v4l2_int_type_slave)
+		sort(d->u.slave->ioctls, d->u.slave->num_ioctls,
+		     sizeof(struct v4l2_int_ioctl_desc),
+		     &ioctl_sort_cmp, NULL);
+	mutex_lock(&mutex);
+	list_add(&d->head, &int_list);
+	v4l2_int_device_try_attach_all();
+	mutex_unlock(&mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_int_device_register);
+
+void v4l2_int_device_unregister(struct v4l2_int_device *d)
+{
+	mutex_lock(&mutex);
+	list_del(&d->head);
+	if (d->type == v4l2_int_type_slave
+	    && d->u.slave->master != NULL) {
+		d->u.slave->master->u.master->detach(d);
+		module_put(d->u.slave->master->module);
+		d->u.slave->master = NULL;
+	}
+	mutex_unlock(&mutex);
+}
+EXPORT_SYMBOL_GPL(v4l2_int_device_unregister);
+
+/* Adapted from search_extable in extable.c. */
+static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd,
+				       v4l2_int_ioctl_func *no_such_ioctl)
+{
+	const struct v4l2_int_ioctl_desc *first = slave->ioctls;
+	const struct v4l2_int_ioctl_desc *last =
+		first + slave->num_ioctls - 1;
+
+	while (first <= last) {
+		const struct v4l2_int_ioctl_desc *mid;
+
+		mid = (last - first) / 2 + first;
+
+		if (mid->num < cmd)
+			first = mid + 1;
+		else if (mid->num > cmd)
+			last = mid - 1;
+		else
+			return mid->func;
+	}
+
+	return no_such_ioctl;
+}
+
+static int no_such_ioctl_0(struct v4l2_int_device *d)
+{
+	return -ENOIOCTLCMD;
+}
+
+int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd)
+{
+	return ((v4l2_int_ioctl_func_0 *)
+		find_ioctl(d->u.slave, cmd,
+			   (v4l2_int_ioctl_func *)no_such_ioctl_0))(d);
+}
+
+static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg)
+{
+	return -ENOIOCTLCMD;
+}
+
+int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg)
+{
+	return ((v4l2_int_ioctl_func_1 *)
+		find_ioctl(d->u.slave, cmd,
+			   (v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg);
+}
diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
deleted file mode 100644
index a32dfbe..0000000
--- a/drivers/media/video/video-buf.c
+++ /dev/null
@@ -1,1425 +0,0 @@
-/*
- *
- * generic helper functions for video4linux capture buffers, to handle
- * memory management and PCI DMA.
- * Right now, bttv, saa7134, saa7146 and cx88 use it.
- *
- * The functions expect the hardware being able to scatter gatter
- * (i.e. the buffers are not linear in physical memory, but fragmented
- * into PAGE_SIZE chunks).  They also assume the driver does not need
- * to touch the video data.
- *
- * device specific map/unmap/sync stuff now are mapped as operations
- * to allow its usage by USB and virtual devices.
- *
- * (c) 2001-2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs]
- * (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
- * (c) 2006 Ted Walther and John Sokol
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/vmalloc.h>
-#include <linux/pagemap.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-
-#include <media/video-buf.h>
-
-#define MAGIC_DMABUF 0x19721112
-#define MAGIC_BUFFER 0x20040302
-#define MAGIC_CHECK(is,should)	if (unlikely((is) != (should))) \
-	{ printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
-
-static int debug = 0;
-module_param(debug, int, 0644);
-
-MODULE_DESCRIPTION("helper module to manage video4linux pci dma buffers");
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-MODULE_LICENSE("GPL");
-
-#define dprintk(level, fmt, arg...)	if (debug >= level) \
-	printk(KERN_DEBUG "vbuf: " fmt , ## arg)
-
-struct scatterlist*
-videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
-{
-	struct scatterlist *sglist;
-	struct page *pg;
-	int i;
-
-	sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
-	if (NULL == sglist)
-		return NULL;
-	for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
-		pg = vmalloc_to_page(virt);
-		if (NULL == pg)
-			goto err;
-		BUG_ON(PageHighMem(pg));
-		sglist[i].page   = pg;
-		sglist[i].length = PAGE_SIZE;
-	}
-	return sglist;
-
- err:
-	kfree(sglist);
-	return NULL;
-}
-
-struct scatterlist*
-videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
-{
-	struct scatterlist *sglist;
-	int i = 0;
-
-	if (NULL == pages[0])
-		return NULL;
-	sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL);
-	if (NULL == sglist)
-		return NULL;
-
-	if (NULL == pages[0])
-		goto nopage;
-	if (PageHighMem(pages[0]))
-		/* DMA to highmem pages might not work */
-		goto highmem;
-	sglist[0].page   = pages[0];
-	sglist[0].offset = offset;
-	sglist[0].length = PAGE_SIZE - offset;
-	for (i = 1; i < nr_pages; i++) {
-		if (NULL == pages[i])
-			goto nopage;
-		if (PageHighMem(pages[i]))
-			goto highmem;
-		sglist[i].page   = pages[i];
-		sglist[i].length = PAGE_SIZE;
-	}
-	return sglist;
-
- nopage:
-	dprintk(2,"sgl: oops - no page\n");
-	kfree(sglist);
-	return NULL;
-
- highmem:
-	dprintk(2,"sgl: oops - highmem page\n");
-	kfree(sglist);
-	return NULL;
-}
-
-/* --------------------------------------------------------------------- */
-
-void videobuf_dma_init(struct videobuf_dmabuf *dma)
-{
-	memset(dma,0,sizeof(*dma));
-	dma->magic = MAGIC_DMABUF;
-}
-
-int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
-			   unsigned long data, unsigned long size)
-{
-	unsigned long first,last;
-	int err, rw = 0;
-
-	dma->direction = direction;
-	switch (dma->direction) {
-	case PCI_DMA_FROMDEVICE: rw = READ;  break;
-	case PCI_DMA_TODEVICE:   rw = WRITE; break;
-	default:                 BUG();
-	}
-
-	first = (data          & PAGE_MASK) >> PAGE_SHIFT;
-	last  = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT;
-	dma->offset   = data & ~PAGE_MASK;
-	dma->nr_pages = last-first+1;
-	dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*),
-			     GFP_KERNEL);
-	if (NULL == dma->pages)
-		return -ENOMEM;
-	dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n",
-		data,size,dma->nr_pages);
-
-	dma->varea = (void *) data;
-
-	down_read(&current->mm->mmap_sem);
-	err = get_user_pages(current,current->mm,
-			     data & PAGE_MASK, dma->nr_pages,
-			     rw == READ, 1, /* force */
-			     dma->pages, NULL);
-	up_read(&current->mm->mmap_sem);
-	if (err != dma->nr_pages) {
-		dma->nr_pages = (err >= 0) ? err : 0;
-		dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages);
-		return err < 0 ? err : -EINVAL;
-	}
-	return 0;
-}
-
-int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
-			     int nr_pages)
-{
-	dprintk(1,"init kernel [%d pages]\n",nr_pages);
-	dma->direction = direction;
-	dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT);
-	if (NULL == dma->vmalloc) {
-		dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages);
-		return -ENOMEM;
-	}
-	dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n",
-				(unsigned long)dma->vmalloc,
-				nr_pages << PAGE_SHIFT);
-	memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT);
-	dma->nr_pages = nr_pages;
-	return 0;
-}
-
-int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
-			      dma_addr_t addr, int nr_pages)
-{
-	dprintk(1,"init overlay [%d pages @ bus 0x%lx]\n",
-		nr_pages,(unsigned long)addr);
-	dma->direction = direction;
-	if (0 == addr)
-		return -EINVAL;
-
-	dma->bus_addr = addr;
-	dma->nr_pages = nr_pages;
-	return 0;
-}
-
-int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
-{
-	void                   *dev=q->dev;
-
-	MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
-	BUG_ON(0 == dma->nr_pages);
-
-	if (dma->pages) {
-		dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages,
-						   dma->offset);
-	}
-	if (dma->vmalloc) {
-		dma->sglist = videobuf_vmalloc_to_sg
-						(dma->vmalloc,dma->nr_pages);
-	}
-	if (dma->bus_addr) {
-		dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL);
-		if (NULL != dma->sglist) {
-			dma->sglen  = 1;
-			sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK;
-			dma->sglist[0].offset           = dma->bus_addr & ~PAGE_MASK;
-			sg_dma_len(&dma->sglist[0])     = dma->nr_pages * PAGE_SIZE;
-		}
-	}
-	if (NULL == dma->sglist) {
-		dprintk(1,"scatterlist is NULL\n");
-		return -ENOMEM;
-	}
-	if (!dma->bus_addr) {
-		if (q->ops->vb_map_sg) {
-			dma->sglen = q->ops->vb_map_sg(dev,dma->sglist,
-					dma->nr_pages, dma->direction);
-		}
-		if (0 == dma->sglen) {
-			printk(KERN_WARNING
-			       "%s: videobuf_map_sg failed\n",__FUNCTION__);
-			kfree(dma->sglist);
-			dma->sglist = NULL;
-			dma->sglen = 0;
-			return -EIO;
-		}
-	}
-	return 0;
-}
-
-int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
-{
-	void                   *dev=q->dev;
-
-	MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
-	BUG_ON(!dma->sglen);
-
-	if (!dma->bus_addr && q->ops->vb_dma_sync_sg)
-		q->ops->vb_dma_sync_sg(dev,dma->sglist,dma->nr_pages,
-							dma->direction);
-
-	return 0;
-}
-
-int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
-{
-	void                   *dev=q->dev;
-
-	MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
-	if (!dma->sglen)
-		return 0;
-
-	if (!dma->bus_addr && q->ops->vb_unmap_sg)
-			q->ops->vb_unmap_sg(dev,dma->sglist,dma->nr_pages,
-							dma->direction);
-	kfree(dma->sglist);
-	dma->sglist = NULL;
-	dma->sglen = 0;
-	return 0;
-}
-
-int videobuf_dma_free(struct videobuf_dmabuf *dma)
-{
-	MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
-	BUG_ON(dma->sglen);
-
-	if (dma->pages) {
-		int i;
-		for (i=0; i < dma->nr_pages; i++)
-			page_cache_release(dma->pages[i]);
-		kfree(dma->pages);
-		dma->pages = NULL;
-	}
-
-	vfree(dma->vmalloc);
-	dma->vmalloc = NULL;
-	dma->varea = NULL;
-
-	if (dma->bus_addr) {
-		dma->bus_addr = 0;
-	}
-	dma->direction = PCI_DMA_NONE;
-	return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-void* videobuf_alloc(unsigned int size)
-{
-	struct videobuf_buffer *vb;
-
-	vb = kzalloc(size,GFP_KERNEL);
-	if (NULL != vb) {
-		videobuf_dma_init(&vb->dma);
-		init_waitqueue_head(&vb->done);
-		vb->magic     = MAGIC_BUFFER;
-	}
-	return vb;
-}
-
-int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
-{
-	int retval = 0;
-	DECLARE_WAITQUEUE(wait, current);
-
-	MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
-	add_wait_queue(&vb->done, &wait);
-	while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) {
-		if (non_blocking) {
-			retval = -EAGAIN;
-			break;
-		}
-		set_current_state(intr  ? TASK_INTERRUPTIBLE
-					: TASK_UNINTERRUPTIBLE);
-		if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED)
-			schedule();
-		set_current_state(TASK_RUNNING);
-		if (intr && signal_pending(current)) {
-			dprintk(1,"buffer waiton: -EINTR\n");
-			retval = -EINTR;
-			break;
-		}
-	}
-	remove_wait_queue(&vb->done, &wait);
-	return retval;
-}
-
-int
-videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb,
-		struct v4l2_framebuffer *fbuf)
-{
-	int err,pages;
-	dma_addr_t bus;
-
-	MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
-	switch (vb->memory) {
-	case V4L2_MEMORY_MMAP:
-	case V4L2_MEMORY_USERPTR:
-		if (0 == vb->baddr) {
-			/* no userspace addr -- kernel bounce buffer */
-			pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
-			err = videobuf_dma_init_kernel(&vb->dma,PCI_DMA_FROMDEVICE,
-						       pages);
-			if (0 != err)
-				return err;
-		} else {
-			/* dma directly to userspace */
-			err = videobuf_dma_init_user(&vb->dma,PCI_DMA_FROMDEVICE,
-						     vb->baddr,vb->bsize);
-			if (0 != err)
-				return err;
-		}
-		break;
-	case V4L2_MEMORY_OVERLAY:
-		if (NULL == fbuf)
-			return -EINVAL;
-		/* FIXME: need sanity checks for vb->boff */
-		/*
-		 * Using a double cast to avoid compiler warnings when
-		 * building for PAE. Compiler doesn't like direct casting
-		 * of a 32 bit ptr to 64 bit integer.
-		 */
-		bus   = (dma_addr_t)(unsigned long)fbuf->base + vb->boff;
-		pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
-		err = videobuf_dma_init_overlay(&vb->dma,PCI_DMA_FROMDEVICE,
-						bus, pages);
-		if (0 != err)
-			return err;
-		break;
-	default:
-		BUG();
-	}
-	err = videobuf_dma_map(q,&vb->dma);
-	if (0 != err)
-		return err;
-
-	return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-void videobuf_queue_pci(struct videobuf_queue* q)
-{
-	/* If not specified, defaults to PCI map sg */
-	if (!q->ops->vb_map_sg)
-		q->ops->vb_map_sg=(vb_map_sg_t *)pci_map_sg;
-
-	if (!q->ops->vb_dma_sync_sg)
-		q->ops->vb_dma_sync_sg=(vb_map_sg_t *)pci_dma_sync_sg_for_cpu;
-	if (!q->ops->vb_unmap_sg)
-		q->ops->vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg;
-}
-
-int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma)
-{
-	struct videobuf_queue q;
-	struct videobuf_queue_ops qops;
-
-	q.dev=pci;
-	qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg;
-	qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg;
-	q.ops = &qops;
-
-	return (videobuf_dma_map(&q,dma));
-}
-
-int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma)
-{
-	struct videobuf_queue q;
-	struct videobuf_queue_ops qops;
-
-	q.dev=pci;
-	qops.vb_map_sg=(vb_map_sg_t *)pci_map_sg;
-	qops.vb_unmap_sg=(vb_map_sg_t *)pci_unmap_sg;
-	q.ops = &qops;
-
-	return (videobuf_dma_unmap(&q,dma));
-}
-
-void videobuf_queue_init(struct videobuf_queue* q,
-			 struct videobuf_queue_ops *ops,
-			 void *dev,
-			 spinlock_t *irqlock,
-			 enum v4l2_buf_type type,
-			 enum v4l2_field field,
-			 unsigned int msize,
-			 void *priv)
-{
-	memset(q,0,sizeof(*q));
-	q->irqlock = irqlock;
-	q->dev     = dev;
-	q->type    = type;
-	q->field   = field;
-	q->msize   = msize;
-	q->ops     = ops;
-	q->priv_data = priv;
-
-	videobuf_queue_pci(q);
-
-	mutex_init(&q->lock);
-	INIT_LIST_HEAD(&q->stream);
-}
-
-int
-videobuf_queue_is_busy(struct videobuf_queue *q)
-{
-	int i;
-
-	if (q->streaming) {
-		dprintk(1,"busy: streaming active\n");
-		return 1;
-	}
-	if (q->reading) {
-		dprintk(1,"busy: pending read #1\n");
-		return 1;
-	}
-	if (q->read_buf) {
-		dprintk(1,"busy: pending read #2\n");
-		return 1;
-	}
-	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-		if (NULL == q->bufs[i])
-			continue;
-		if (q->bufs[i]->map) {
-			dprintk(1,"busy: buffer #%d mapped\n",i);
-			return 1;
-		}
-		if (q->bufs[i]->state == STATE_QUEUED) {
-			dprintk(1,"busy: buffer #%d queued\n",i);
-			return 1;
-		}
-		if (q->bufs[i]->state == STATE_ACTIVE) {
-			dprintk(1,"busy: buffer #%d avtive\n",i);
-			return 1;
-		}
-	}
-	return 0;
-}
-
-void
-videobuf_queue_cancel(struct videobuf_queue *q)
-{
-	unsigned long flags=0;
-	int i;
-
-	/* remove queued buffers from list */
-	if (q->irqlock)
-		spin_lock_irqsave(q->irqlock,flags);
-	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-		if (NULL == q->bufs[i])
-			continue;
-		if (q->bufs[i]->state == STATE_QUEUED) {
-			list_del(&q->bufs[i]->queue);
-			q->bufs[i]->state = STATE_ERROR;
-		}
-	}
-	if (q->irqlock)
-		spin_unlock_irqrestore(q->irqlock,flags);
-
-	/* free all buffers + clear queue */
-	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-		if (NULL == q->bufs[i])
-			continue;
-		q->ops->buf_release(q,q->bufs[i]);
-	}
-	INIT_LIST_HEAD(&q->stream);
-}
-
-/* --------------------------------------------------------------------- */
-
-enum v4l2_field
-videobuf_next_field(struct videobuf_queue *q)
-{
-	enum v4l2_field field = q->field;
-
-	BUG_ON(V4L2_FIELD_ANY == field);
-
-	if (V4L2_FIELD_ALTERNATE == field) {
-		if (V4L2_FIELD_TOP == q->last) {
-			field   = V4L2_FIELD_BOTTOM;
-			q->last = V4L2_FIELD_BOTTOM;
-		} else {
-			field   = V4L2_FIELD_TOP;
-			q->last = V4L2_FIELD_TOP;
-		}
-	}
-	return field;
-}
-
-void
-videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb,
-		enum v4l2_buf_type type)
-{
-	MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
-
-	b->index    = vb->i;
-	b->type     = type;
-
-	b->memory   = vb->memory;
-	switch (b->memory) {
-	case V4L2_MEMORY_MMAP:
-		b->m.offset  = vb->boff;
-		b->length    = vb->bsize;
-		break;
-	case V4L2_MEMORY_USERPTR:
-		b->m.userptr = vb->baddr;
-		b->length    = vb->bsize;
-		break;
-	case V4L2_MEMORY_OVERLAY:
-		b->m.offset  = vb->boff;
-		break;
-	}
-
-	b->flags    = 0;
-	if (vb->map)
-		b->flags |= V4L2_BUF_FLAG_MAPPED;
-
-	switch (vb->state) {
-	case STATE_PREPARED:
-	case STATE_QUEUED:
-	case STATE_ACTIVE:
-		b->flags |= V4L2_BUF_FLAG_QUEUED;
-		break;
-	case STATE_DONE:
-	case STATE_ERROR:
-		b->flags |= V4L2_BUF_FLAG_DONE;
-		break;
-	case STATE_NEEDS_INIT:
-	case STATE_IDLE:
-		/* nothing */
-		break;
-	}
-
-	if (vb->input != UNSET) {
-		b->flags |= V4L2_BUF_FLAG_INPUT;
-		b->input  = vb->input;
-	}
-
-	b->field     = vb->field;
-	b->timestamp = vb->ts;
-	b->bytesused = vb->size;
-	b->sequence  = vb->field_count >> 1;
-}
-
-int
-videobuf_reqbufs(struct videobuf_queue *q,
-		 struct v4l2_requestbuffers *req)
-{
-	unsigned int size,count;
-	int retval;
-
-	if (req->type != q->type) {
-		dprintk(1,"reqbufs: queue type invalid\n");
-		return -EINVAL;
-	}
-	if (req->count < 1) {
-		dprintk(1,"reqbufs: count invalid (%d)\n",req->count);
-		return -EINVAL;
-	}
-	if (req->memory != V4L2_MEMORY_MMAP     &&
-	    req->memory != V4L2_MEMORY_USERPTR  &&
-	    req->memory != V4L2_MEMORY_OVERLAY) {
-		dprintk(1,"reqbufs: memory type invalid\n");
-		return -EINVAL;
-	}
-
-	if (q->streaming) {
-		dprintk(1,"reqbufs: streaming already exists\n");
-		return -EBUSY;
-	}
-	if (!list_empty(&q->stream)) {
-		dprintk(1,"reqbufs: stream running\n");
-		return -EBUSY;
-	}
-
-	mutex_lock(&q->lock);
-	count = req->count;
-	if (count > VIDEO_MAX_FRAME)
-		count = VIDEO_MAX_FRAME;
-	size = 0;
-	q->ops->buf_setup(q,&count,&size);
-	size = PAGE_ALIGN(size);
-	dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n",
-		count, size, (count*size)>>PAGE_SHIFT);
-
-	retval = videobuf_mmap_setup(q,count,size,req->memory);
-	if (retval < 0) {
-		dprintk(1,"reqbufs: mmap setup returned %d\n",retval);
-		goto done;
-	}
-
-	req->count = count;
-
- done:
-	mutex_unlock(&q->lock);
-	return retval;
-}
-
-int
-videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
-{
-	if (unlikely(b->type != q->type)) {
-		dprintk(1,"querybuf: Wrong type.\n");
-		return -EINVAL;
-	}
-	if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) {
-		dprintk(1,"querybuf: index out of range.\n");
-		return -EINVAL;
-	}
-	if (unlikely(NULL == q->bufs[b->index])) {
-		dprintk(1,"querybuf: buffer is null.\n");
-		return -EINVAL;
-	}
-	videobuf_status(b,q->bufs[b->index],q->type);
-	return 0;
-}
-
-int
-videobuf_qbuf(struct videobuf_queue *q,
-	      struct v4l2_buffer *b)
-{
-	struct videobuf_buffer *buf;
-	enum v4l2_field field;
-	unsigned long flags=0;
-	int retval;
-
-	mutex_lock(&q->lock);
-	retval = -EBUSY;
-	if (q->reading) {
-		dprintk(1,"qbuf: Reading running...\n");
-		goto done;
-	}
-	retval = -EINVAL;
-	if (b->type != q->type) {
-		dprintk(1,"qbuf: Wrong type.\n");
-		goto done;
-	}
-	if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) {
-		dprintk(1,"qbuf: index out of range.\n");
-		goto done;
-	}
-	buf = q->bufs[b->index];
-	if (NULL == buf) {
-		dprintk(1,"qbuf: buffer is null.\n");
-		goto done;
-	}
-	MAGIC_CHECK(buf->magic,MAGIC_BUFFER);
-	if (buf->memory != b->memory) {
-		dprintk(1,"qbuf: memory type is wrong.\n");
-		goto done;
-	}
-	if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) {
-		dprintk(1,"qbuf: buffer is already queued or active.\n");
-		goto done;
-	}
-
-	if (b->flags & V4L2_BUF_FLAG_INPUT) {
-		if (b->input >= q->inputs) {
-			dprintk(1,"qbuf: wrong input.\n");
-			goto done;
-		}
-		buf->input = b->input;
-	} else {
-		buf->input = UNSET;
-	}
-
-	switch (b->memory) {
-	case V4L2_MEMORY_MMAP:
-		if (0 == buf->baddr) {
-			dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n");
-			goto done;
-		}
-		break;
-	case V4L2_MEMORY_USERPTR:
-		if (b->length < buf->bsize) {
-			dprintk(1,"qbuf: buffer length is not enough\n");
-			goto done;
-		}
-		if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr)
-			q->ops->buf_release(q,buf);
-		buf->baddr = b->m.userptr;
-		break;
-	case V4L2_MEMORY_OVERLAY:
-		buf->boff = b->m.offset;
-		break;
-	default:
-		dprintk(1,"qbuf: wrong memory type\n");
-		goto done;
-	}
-
-	dprintk(1,"qbuf: requesting next field\n");
-	field = videobuf_next_field(q);
-	retval = q->ops->buf_prepare(q,buf,field);
-	if (0 != retval) {
-		dprintk(1,"qbuf: buffer_prepare returned %d\n",retval);
-		goto done;
-	}
-
-	list_add_tail(&buf->stream,&q->stream);
-	if (q->streaming) {
-		if (q->irqlock)
-			spin_lock_irqsave(q->irqlock,flags);
-		q->ops->buf_queue(q,buf);
-		if (q->irqlock)
-			spin_unlock_irqrestore(q->irqlock,flags);
-	}
-	dprintk(1,"qbuf: succeded\n");
-	retval = 0;
-
- done:
-	mutex_unlock(&q->lock);
-	return retval;
-}
-
-int
-videobuf_dqbuf(struct videobuf_queue *q,
-	       struct v4l2_buffer *b, int nonblocking)
-{
-	struct videobuf_buffer *buf;
-	int retval;
-
-	mutex_lock(&q->lock);
-	retval = -EBUSY;
-	if (q->reading) {
-		dprintk(1,"dqbuf: Reading running...\n");
-		goto done;
-	}
-	retval = -EINVAL;
-	if (b->type != q->type) {
-		dprintk(1,"dqbuf: Wrong type.\n");
-		goto done;
-	}
-	if (list_empty(&q->stream)) {
-		dprintk(1,"dqbuf: stream running\n");
-		goto done;
-	}
-	buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
-	retval = videobuf_waiton(buf, nonblocking, 1);
-	if (retval < 0) {
-		dprintk(1,"dqbuf: waiton returned %d\n",retval);
-		goto done;
-	}
-	switch (buf->state) {
-	case STATE_ERROR:
-		dprintk(1,"dqbuf: state is error\n");
-		retval = -EIO;
-		videobuf_dma_sync(q,&buf->dma);
-		buf->state = STATE_IDLE;
-		break;
-	case STATE_DONE:
-		dprintk(1,"dqbuf: state is done\n");
-		videobuf_dma_sync(q,&buf->dma);
-		buf->state = STATE_IDLE;
-		break;
-	default:
-		dprintk(1,"dqbuf: state invalid\n");
-		retval = -EINVAL;
-		goto done;
-	}
-	list_del(&buf->stream);
-	memset(b,0,sizeof(*b));
-	videobuf_status(b,buf,q->type);
-
- done:
-	mutex_unlock(&q->lock);
-	return retval;
-}
-
-int videobuf_streamon(struct videobuf_queue *q)
-{
-	struct videobuf_buffer *buf;
-	struct list_head *list;
-	unsigned long flags=0;
-	int retval;
-
-	mutex_lock(&q->lock);
-	retval = -EBUSY;
-	if (q->reading)
-		goto done;
-	retval = 0;
-	if (q->streaming)
-		goto done;
-	q->streaming = 1;
-	if (q->irqlock)
-		spin_lock_irqsave(q->irqlock,flags);
-	list_for_each(list,&q->stream) {
-		buf = list_entry(list, struct videobuf_buffer, stream);
-		if (buf->state == STATE_PREPARED)
-			q->ops->buf_queue(q,buf);
-	}
-	if (q->irqlock)
-		spin_unlock_irqrestore(q->irqlock,flags);
-
- done:
-	mutex_unlock(&q->lock);
-	return retval;
-}
-
-int videobuf_streamoff(struct videobuf_queue *q)
-{
-	int retval = -EINVAL;
-
-	mutex_lock(&q->lock);
-	if (!q->streaming)
-		goto done;
-	videobuf_queue_cancel(q);
-	q->streaming = 0;
-	retval = 0;
-
- done:
-	mutex_unlock(&q->lock);
-	return retval;
-}
-
-static ssize_t
-videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data,
-		       size_t count, loff_t *ppos)
-{
-	enum v4l2_field field;
-	unsigned long flags=0;
-	int retval;
-
-	/* setup stuff */
-	q->read_buf = videobuf_alloc(q->msize);
-	if (NULL == q->read_buf)
-		return -ENOMEM;
-
-	q->read_buf->memory = V4L2_MEMORY_USERPTR;
-	q->read_buf->baddr  = (unsigned long)data;
-	q->read_buf->bsize  = count;
-	field = videobuf_next_field(q);
-	retval = q->ops->buf_prepare(q,q->read_buf,field);
-	if (0 != retval)
-		goto done;
-
-	/* start capture & wait */
-	if (q->irqlock)
-		spin_lock_irqsave(q->irqlock,flags);
-	q->ops->buf_queue(q,q->read_buf);
-	if (q->irqlock)
-		spin_unlock_irqrestore(q->irqlock,flags);
-	retval = videobuf_waiton(q->read_buf,0,0);
-	if (0 == retval) {
-		videobuf_dma_sync(q,&q->read_buf->dma);
-		if (STATE_ERROR == q->read_buf->state)
-			retval = -EIO;
-		else
-			retval = q->read_buf->size;
-	}
-
- done:
-	/* cleanup */
-	q->ops->buf_release(q,q->read_buf);
-	kfree(q->read_buf);
-	q->read_buf = NULL;
-	return retval;
-}
-
-ssize_t videobuf_read_one(struct videobuf_queue *q,
-			  char __user *data, size_t count, loff_t *ppos,
-			  int nonblocking)
-{
-	enum v4l2_field field;
-	unsigned long flags=0;
-	unsigned size, nbufs, bytes;
-	int retval;
-
-	mutex_lock(&q->lock);
-
-	nbufs = 1; size = 0;
-	q->ops->buf_setup(q,&nbufs,&size);
-	if (NULL == q->read_buf  &&
-	    count >= size        &&
-	    !nonblocking) {
-		retval = videobuf_read_zerocopy(q,data,count,ppos);
-		if (retval >= 0  ||  retval == -EIO)
-			/* ok, all done */
-			goto done;
-		/* fallback to kernel bounce buffer on failures */
-	}
-
-	if (NULL == q->read_buf) {
-		/* need to capture a new frame */
-		retval = -ENOMEM;
-		q->read_buf = videobuf_alloc(q->msize);
-		dprintk(1,"video alloc=0x%p\n", q->read_buf);
-		if (NULL == q->read_buf)
-			goto done;
-		q->read_buf->memory = V4L2_MEMORY_USERPTR;
-		q->read_buf->bsize = count; /* preferred size */
-		field = videobuf_next_field(q);
-		retval = q->ops->buf_prepare(q,q->read_buf,field);
-		if (0 != retval) {
-			kfree (q->read_buf);
-			q->read_buf = NULL;
-			goto done;
-		}
-		if (q->irqlock)
-			spin_lock_irqsave(q->irqlock,flags);
-		q->ops->buf_queue(q,q->read_buf);
-		if (q->irqlock)
-			spin_unlock_irqrestore(q->irqlock,flags);
-		q->read_off = 0;
-	}
-
-	/* wait until capture is done */
-	retval = videobuf_waiton(q->read_buf, nonblocking, 1);
-	if (0 != retval)
-		goto done;
-	videobuf_dma_sync(q,&q->read_buf->dma);
-
-	if (STATE_ERROR == q->read_buf->state) {
-		/* catch I/O errors */
-		q->ops->buf_release(q,q->read_buf);
-		kfree(q->read_buf);
-		q->read_buf = NULL;
-		retval = -EIO;
-		goto done;
-	}
-
-	/* copy to userspace */
-	bytes = count;
-	if (bytes > q->read_buf->size - q->read_off)
-		bytes = q->read_buf->size - q->read_off;
-	retval = -EFAULT;
-	if (copy_to_user(data, q->read_buf->dma.vmalloc+q->read_off, bytes))
-		goto done;
-
-	retval = bytes;
-	q->read_off += bytes;
-	if (q->read_off == q->read_buf->size) {
-		/* all data copied, cleanup */
-		q->ops->buf_release(q,q->read_buf);
-		kfree(q->read_buf);
-		q->read_buf = NULL;
-	}
-
- done:
-	mutex_unlock(&q->lock);
-	return retval;
-}
-
-int videobuf_read_start(struct videobuf_queue *q)
-{
-	enum v4l2_field field;
-	unsigned long flags=0;
-	int count = 0, size = 0;
-	int err, i;
-
-	q->ops->buf_setup(q,&count,&size);
-	if (count < 2)
-		count = 2;
-	if (count > VIDEO_MAX_FRAME)
-		count = VIDEO_MAX_FRAME;
-	size = PAGE_ALIGN(size);
-
-	err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR);
-	if (err)
-		return err;
-	for (i = 0; i < count; i++) {
-		field = videobuf_next_field(q);
-		err = q->ops->buf_prepare(q,q->bufs[i],field);
-		if (err)
-			return err;
-		list_add_tail(&q->bufs[i]->stream, &q->stream);
-	}
-	if (q->irqlock)
-		spin_lock_irqsave(q->irqlock,flags);
-	for (i = 0; i < count; i++)
-		q->ops->buf_queue(q,q->bufs[i]);
-	if (q->irqlock)
-		spin_unlock_irqrestore(q->irqlock,flags);
-	q->reading = 1;
-	return 0;
-}
-
-void videobuf_read_stop(struct videobuf_queue *q)
-{
-	int i;
-
-	videobuf_queue_cancel(q);
-	videobuf_mmap_free(q);
-	INIT_LIST_HEAD(&q->stream);
-	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-		if (NULL == q->bufs[i])
-			continue;
-		kfree(q->bufs[i]);
-		q->bufs[i] = NULL;
-	}
-	q->read_buf = NULL;
-	q->reading  = 0;
-}
-
-ssize_t videobuf_read_stream(struct videobuf_queue *q,
-			     char __user *data, size_t count, loff_t *ppos,
-			     int vbihack, int nonblocking)
-{
-	unsigned int *fc, bytes;
-	int err, retval;
-	unsigned long flags=0;
-
-	dprintk(2,"%s\n",__FUNCTION__);
-	mutex_lock(&q->lock);
-	retval = -EBUSY;
-	if (q->streaming)
-		goto done;
-	if (!q->reading) {
-		retval = videobuf_read_start(q);
-		if (retval < 0)
-			goto done;
-	}
-
-	retval = 0;
-	while (count > 0) {
-		/* get / wait for data */
-		if (NULL == q->read_buf) {
-			q->read_buf = list_entry(q->stream.next,
-						 struct videobuf_buffer,
-						 stream);
-			list_del(&q->read_buf->stream);
-			q->read_off = 0;
-		}
-		err = videobuf_waiton(q->read_buf, nonblocking, 1);
-		if (err < 0) {
-			if (0 == retval)
-				retval = err;
-			break;
-		}
-
-		if (q->read_buf->state == STATE_DONE) {
-			if (vbihack) {
-				/* dirty, undocumented hack -- pass the frame counter
-				 * within the last four bytes of each vbi data block.
-				 * We need that one to maintain backward compatibility
-				 * to all vbi decoding software out there ... */
-				fc  = (unsigned int*)q->read_buf->dma.vmalloc;
-				fc += (q->read_buf->size>>2) -1;
-				*fc = q->read_buf->field_count >> 1;
-				dprintk(1,"vbihack: %d\n",*fc);
-			}
-
-			/* copy stuff */
-			bytes = count;
-			if (bytes > q->read_buf->size - q->read_off)
-				bytes = q->read_buf->size - q->read_off;
-			if (copy_to_user(data + retval,
-					 q->read_buf->dma.vmalloc + q->read_off,
-					 bytes)) {
-				if (0 == retval)
-					retval = -EFAULT;
-				break;
-			}
-			count       -= bytes;
-			retval      += bytes;
-			q->read_off += bytes;
-		} else {
-			/* some error */
-			q->read_off = q->read_buf->size;
-			if (0 == retval)
-				retval = -EIO;
-		}
-
-		/* requeue buffer when done with copying */
-		if (q->read_off == q->read_buf->size) {
-			list_add_tail(&q->read_buf->stream,
-				      &q->stream);
-			if (q->irqlock)
-				spin_lock_irqsave(q->irqlock,flags);
-			q->ops->buf_queue(q,q->read_buf);
-			if (q->irqlock)
-				spin_unlock_irqrestore(q->irqlock,flags);
-			q->read_buf = NULL;
-		}
-		if (retval < 0)
-			break;
-	}
-
- done:
-	mutex_unlock(&q->lock);
-	return retval;
-}
-
-unsigned int videobuf_poll_stream(struct file *file,
-				  struct videobuf_queue *q,
-				  poll_table *wait)
-{
-	struct videobuf_buffer *buf = NULL;
-	unsigned int rc = 0;
-
-	mutex_lock(&q->lock);
-	if (q->streaming) {
-		if (!list_empty(&q->stream))
-			buf = list_entry(q->stream.next,
-					 struct videobuf_buffer, stream);
-	} else {
-		if (!q->reading)
-			videobuf_read_start(q);
-		if (!q->reading) {
-			rc = POLLERR;
-		} else if (NULL == q->read_buf) {
-			q->read_buf = list_entry(q->stream.next,
-						 struct videobuf_buffer,
-						 stream);
-			list_del(&q->read_buf->stream);
-			q->read_off = 0;
-		}
-		buf = q->read_buf;
-	}
-	if (!buf)
-		rc = POLLERR;
-
-	if (0 == rc) {
-		poll_wait(file, &buf->done, wait);
-		if (buf->state == STATE_DONE ||
-		    buf->state == STATE_ERROR)
-			rc = POLLIN|POLLRDNORM;
-	}
-	mutex_unlock(&q->lock);
-	return rc;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void
-videobuf_vm_open(struct vm_area_struct *vma)
-{
-	struct videobuf_mapping *map = vma->vm_private_data;
-
-	dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map,
-		map->count,vma->vm_start,vma->vm_end);
-	map->count++;
-}
-
-static void
-videobuf_vm_close(struct vm_area_struct *vma)
-{
-	struct videobuf_mapping *map = vma->vm_private_data;
-	struct videobuf_queue *q = map->q;
-	int i;
-
-	dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map,
-		map->count,vma->vm_start,vma->vm_end);
-
-	map->count--;
-	if (0 == map->count) {
-		dprintk(1,"munmap %p q=%p\n",map,q);
-		mutex_lock(&q->lock);
-		for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-			if (NULL == q->bufs[i])
-				continue;
-			if (q->bufs[i])
-				;
-			if (q->bufs[i]->map != map)
-				continue;
-			q->bufs[i]->map   = NULL;
-			q->bufs[i]->baddr = 0;
-			q->ops->buf_release(q,q->bufs[i]);
-		}
-		mutex_unlock(&q->lock);
-		kfree(map);
-	}
-	return;
-}
-
-/*
- * Get a anonymous page for the mapping.  Make sure we can DMA to that
- * memory location with 32bit PCI devices (i.e. don't use highmem for
- * now ...).  Bounce buffers don't work very well for the data rates
- * video capture has.
- */
-static struct page*
-videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
-		   int *type)
-{
-	struct page *page;
-
-	dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n",
-		vaddr,vma->vm_start,vma->vm_end);
-	if (vaddr > vma->vm_end)
-		return NOPAGE_SIGBUS;
-	page = alloc_page(GFP_USER | __GFP_DMA32);
-	if (!page)
-		return NOPAGE_OOM;
-	clear_user_page(page_address(page), vaddr, page);
-	if (type)
-		*type = VM_FAULT_MINOR;
-	return page;
-}
-
-static struct vm_operations_struct videobuf_vm_ops =
-{
-	.open     = videobuf_vm_open,
-	.close    = videobuf_vm_close,
-	.nopage   = videobuf_vm_nopage,
-};
-
-int videobuf_mmap_setup(struct videobuf_queue *q,
-			unsigned int bcount, unsigned int bsize,
-			enum v4l2_memory memory)
-{
-	unsigned int i;
-	int err;
-
-	err = videobuf_mmap_free(q);
-	if (0 != err)
-		return err;
-
-	for (i = 0; i < bcount; i++) {
-		q->bufs[i] = videobuf_alloc(q->msize);
-		q->bufs[i]->i      = i;
-		q->bufs[i]->input  = UNSET;
-		q->bufs[i]->memory = memory;
-		q->bufs[i]->bsize  = bsize;
-		switch (memory) {
-		case V4L2_MEMORY_MMAP:
-			q->bufs[i]->boff  = bsize * i;
-			break;
-		case V4L2_MEMORY_USERPTR:
-		case V4L2_MEMORY_OVERLAY:
-			/* nothing */
-			break;
-		}
-	}
-	dprintk(1,"mmap setup: %d buffers, %d bytes each\n",
-		bcount,bsize);
-	return 0;
-}
-
-int videobuf_mmap_free(struct videobuf_queue *q)
-{
-	int i;
-
-	for (i = 0; i < VIDEO_MAX_FRAME; i++)
-		if (q->bufs[i] && q->bufs[i]->map)
-			return -EBUSY;
-	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
-		if (NULL == q->bufs[i])
-			continue;
-		q->ops->buf_release(q,q->bufs[i]);
-		kfree(q->bufs[i]);
-		q->bufs[i] = NULL;
-	}
-	return 0;
-}
-
-int videobuf_mmap_mapper(struct videobuf_queue *q,
-			 struct vm_area_struct *vma)
-{
-	struct videobuf_mapping *map;
-	unsigned int first,last,size,i;
-	int retval;
-
-	mutex_lock(&q->lock);
-	retval = -EINVAL;
-	if (!(vma->vm_flags & VM_WRITE)) {
-		dprintk(1,"mmap app bug: PROT_WRITE please\n");
-		goto done;
-	}
-	if (!(vma->vm_flags & VM_SHARED)) {
-		dprintk(1,"mmap app bug: MAP_SHARED please\n");
-		goto done;
-	}
-
-	/* look for first buffer to map */
-	for (first = 0; first < VIDEO_MAX_FRAME; first++) {
-		if (NULL == q->bufs[first])
-			continue;
-		if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
-			continue;
-		if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))
-			break;
-	}
-	if (VIDEO_MAX_FRAME == first) {
-		dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n",
-			(vma->vm_pgoff << PAGE_SHIFT));
-		goto done;
-	}
-
-	/* look for last buffer to map */
-	for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {
-		if (NULL == q->bufs[last])
-			continue;
-		if (V4L2_MEMORY_MMAP != q->bufs[last]->memory)
-			continue;
-		if (q->bufs[last]->map) {
-			retval = -EBUSY;
-			goto done;
-		}
-		size += q->bufs[last]->bsize;
-		if (size == (vma->vm_end - vma->vm_start))
-			break;
-	}
-	if (VIDEO_MAX_FRAME == last) {
-		dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n",
-			(vma->vm_end - vma->vm_start));
-		goto done;
-	}
-
-	/* create mapping + update buffer list */
-	retval = -ENOMEM;
-	map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);
-	if (NULL == map)
-		goto done;
-	for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) {
-		q->bufs[i]->map   = map;
-		q->bufs[i]->baddr = vma->vm_start + size;
-	}
-	map->count    = 1;
-	map->start    = vma->vm_start;
-	map->end      = vma->vm_end;
-	map->q        = q;
-	vma->vm_ops   = &videobuf_vm_ops;
-	vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
-	vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
-	vma->vm_private_data = map;
-	dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n",
-		map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last);
-	retval = 0;
-
- done:
-	mutex_unlock(&q->lock);
-	return retval;
-}
-
-/* --------------------------------------------------------------------- */
-
-EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);
-
-EXPORT_SYMBOL_GPL(videobuf_dma_init);
-EXPORT_SYMBOL_GPL(videobuf_dma_init_user);
-EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel);
-EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay);
-EXPORT_SYMBOL_GPL(videobuf_dma_map);
-EXPORT_SYMBOL_GPL(videobuf_dma_sync);
-EXPORT_SYMBOL_GPL(videobuf_dma_unmap);
-EXPORT_SYMBOL_GPL(videobuf_dma_free);
-
-EXPORT_SYMBOL_GPL(videobuf_pci_dma_map);
-EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap);
-
-EXPORT_SYMBOL_GPL(videobuf_alloc);
-EXPORT_SYMBOL_GPL(videobuf_waiton);
-EXPORT_SYMBOL_GPL(videobuf_iolock);
-
-EXPORT_SYMBOL_GPL(videobuf_queue_init);
-EXPORT_SYMBOL_GPL(videobuf_queue_cancel);
-EXPORT_SYMBOL_GPL(videobuf_queue_is_busy);
-
-EXPORT_SYMBOL_GPL(videobuf_next_field);
-EXPORT_SYMBOL_GPL(videobuf_status);
-EXPORT_SYMBOL_GPL(videobuf_reqbufs);
-EXPORT_SYMBOL_GPL(videobuf_querybuf);
-EXPORT_SYMBOL_GPL(videobuf_qbuf);
-EXPORT_SYMBOL_GPL(videobuf_dqbuf);
-EXPORT_SYMBOL_GPL(videobuf_streamon);
-EXPORT_SYMBOL_GPL(videobuf_streamoff);
-
-EXPORT_SYMBOL_GPL(videobuf_read_start);
-EXPORT_SYMBOL_GPL(videobuf_read_stop);
-EXPORT_SYMBOL_GPL(videobuf_read_stream);
-EXPORT_SYMBOL_GPL(videobuf_read_one);
-EXPORT_SYMBOL_GPL(videobuf_poll_stream);
-
-EXPORT_SYMBOL_GPL(videobuf_mmap_setup);
-EXPORT_SYMBOL_GPL(videobuf_mmap_free);
-EXPORT_SYMBOL_GPL(videobuf_mmap_mapper);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
new file mode 100644
index 0000000..c606332
--- /dev/null
+++ b/drivers/media/video/videobuf-core.c
@@ -0,0 +1,1006 @@
+/*
+ * generic helper functions for handling video4linux capture buffers
+ *
+ * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
+ *
+ * Highly based on video-buf written originally by:
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
+ * (c) 2006 Mauro Carvalho Chehab, <mchehab@infradead.org>
+ * (c) 2006 Ted Walther and John Sokol
+ *
+ * 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
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+
+#include <media/videobuf-core.h>
+
+#define MAGIC_BUFFER 0x20070728
+#define MAGIC_CHECK(is,should)	if (unlikely((is) != (should))) \
+	{ printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
+
+static int debug = 0;
+module_param(debug, int, 0644);
+
+MODULE_DESCRIPTION("helper module to manage video4linux buffers");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
+
+#define dprintk(level, fmt, arg...)	if (debug >= level) \
+	printk(KERN_DEBUG "vbuf: " fmt , ## arg)
+
+/* --------------------------------------------------------------------- */
+
+#define CALL(q, f, arg...)						\
+	( (q->int_ops->f)? q->int_ops->f(arg) : 0)
+
+void* videobuf_alloc(struct videobuf_queue* q)
+{
+	struct videobuf_buffer *vb;
+
+	BUG_ON (q->msize<sizeof(*vb));
+
+	if (!q->int_ops || !q->int_ops->alloc) {
+		printk(KERN_ERR "No specific ops defined!\n");
+		BUG();
+	}
+
+	vb = q->int_ops->alloc(q->msize);
+
+	if (NULL != vb) {
+		init_waitqueue_head(&vb->done);
+		vb->magic     = MAGIC_BUFFER;
+	}
+
+	return vb;
+}
+
+int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
+{
+	int retval = 0;
+	DECLARE_WAITQUEUE(wait, current);
+
+	MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
+	add_wait_queue(&vb->done, &wait);
+	while (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED) {
+		if (non_blocking) {
+			retval = -EAGAIN;
+			break;
+		}
+		set_current_state(intr  ? TASK_INTERRUPTIBLE
+					: TASK_UNINTERRUPTIBLE);
+		if (vb->state == STATE_ACTIVE || vb->state == STATE_QUEUED)
+			schedule();
+		set_current_state(TASK_RUNNING);
+		if (intr && signal_pending(current)) {
+			dprintk(1,"buffer waiton: -EINTR\n");
+			retval = -EINTR;
+			break;
+		}
+	}
+	remove_wait_queue(&vb->done, &wait);
+	return retval;
+}
+
+int videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb,
+		    struct v4l2_framebuffer *fbuf)
+{
+	MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
+	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+	/* FIXME: This is required to avoid OOPS on some cases, since mmap_mapper()
+	   method should be called before _iolock.
+	   On some cases, the mmap_mapper() is called only after scheduling.
+
+	   However, this way is just too dirty! Better to wait for some event.
+	 */
+	schedule_timeout(HZ);
+
+	return CALL(q,iolock,q,vb,fbuf);
+}
+
+/* --------------------------------------------------------------------- */
+
+
+void videobuf_queue_core_init(struct videobuf_queue* q,
+			 struct videobuf_queue_ops *ops,
+			 void *dev,
+			 spinlock_t *irqlock,
+			 enum v4l2_buf_type type,
+			 enum v4l2_field field,
+			 unsigned int msize,
+			 void *priv,
+			 struct videobuf_qtype_ops *int_ops)
+{
+	memset(q,0,sizeof(*q));
+	q->irqlock   = irqlock;
+	q->dev       = dev;
+	q->type      = type;
+	q->field     = field;
+	q->msize     = msize;
+	q->ops       = ops;
+	q->priv_data = priv;
+	q->int_ops   = int_ops;
+
+	/* All buffer operations are mandatory */
+	BUG_ON (!q->ops->buf_setup);
+	BUG_ON (!q->ops->buf_prepare);
+	BUG_ON (!q->ops->buf_queue);
+	BUG_ON (!q->ops->buf_release);
+
+	/* Having implementations for abstract methods are mandatory */
+	BUG_ON (!q->int_ops);
+
+	mutex_init(&q->lock);
+	INIT_LIST_HEAD(&q->stream);
+}
+
+int videobuf_queue_is_busy(struct videobuf_queue *q)
+{
+	int i;
+
+	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+	if (q->streaming) {
+		dprintk(1,"busy: streaming active\n");
+		return 1;
+	}
+	if (q->reading) {
+		dprintk(1,"busy: pending read #1\n");
+		return 1;
+	}
+	if (q->read_buf) {
+		dprintk(1,"busy: pending read #2\n");
+		return 1;
+	}
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (NULL == q->bufs[i])
+			continue;
+		if (q->bufs[i]->map) {
+			dprintk(1,"busy: buffer #%d mapped\n",i);
+			return 1;
+		}
+		if (q->bufs[i]->state == STATE_QUEUED) {
+			dprintk(1,"busy: buffer #%d queued\n",i);
+			return 1;
+		}
+		if (q->bufs[i]->state == STATE_ACTIVE) {
+			dprintk(1,"busy: buffer #%d avtive\n",i);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+void videobuf_queue_cancel(struct videobuf_queue *q)
+{
+	unsigned long flags=0;
+	int i;
+
+	/* remove queued buffers from list */
+	if (q->irqlock)
+		spin_lock_irqsave(q->irqlock,flags);
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (NULL == q->bufs[i])
+			continue;
+		if (q->bufs[i]->state == STATE_QUEUED) {
+			list_del(&q->bufs[i]->queue);
+			q->bufs[i]->state = STATE_ERROR;
+		}
+	}
+	if (q->irqlock)
+		spin_unlock_irqrestore(q->irqlock,flags);
+
+	/* free all buffers + clear queue */
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (NULL == q->bufs[i])
+			continue;
+		q->ops->buf_release(q,q->bufs[i]);
+	}
+	INIT_LIST_HEAD(&q->stream);
+}
+
+/* --------------------------------------------------------------------- */
+
+enum v4l2_field videobuf_next_field(struct videobuf_queue *q)
+{
+	enum v4l2_field field = q->field;
+
+	BUG_ON(V4L2_FIELD_ANY == field);
+
+	if (V4L2_FIELD_ALTERNATE == field) {
+		if (V4L2_FIELD_TOP == q->last) {
+			field   = V4L2_FIELD_BOTTOM;
+			q->last = V4L2_FIELD_BOTTOM;
+		} else {
+			field   = V4L2_FIELD_TOP;
+			q->last = V4L2_FIELD_TOP;
+		}
+	}
+	return field;
+}
+
+static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
+			    struct videobuf_buffer *vb, enum v4l2_buf_type type)
+{
+	MAGIC_CHECK(vb->magic,MAGIC_BUFFER);
+	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+	b->index    = vb->i;
+	b->type     = type;
+
+	b->memory   = vb->memory;
+	switch (b->memory) {
+	case V4L2_MEMORY_MMAP:
+		b->m.offset  = vb->boff;
+		b->length    = vb->bsize;
+		break;
+	case V4L2_MEMORY_USERPTR:
+		b->m.userptr = vb->baddr;
+		b->length    = vb->bsize;
+		break;
+	case V4L2_MEMORY_OVERLAY:
+		b->m.offset  = vb->boff;
+		break;
+	}
+
+	b->flags    = 0;
+	if (vb->map)
+		b->flags |= V4L2_BUF_FLAG_MAPPED;
+
+	switch (vb->state) {
+	case STATE_PREPARED:
+	case STATE_QUEUED:
+	case STATE_ACTIVE:
+		b->flags |= V4L2_BUF_FLAG_QUEUED;
+		break;
+	case STATE_DONE:
+	case STATE_ERROR:
+		b->flags |= V4L2_BUF_FLAG_DONE;
+		break;
+	case STATE_NEEDS_INIT:
+	case STATE_IDLE:
+		/* nothing */
+		break;
+	}
+
+	if (vb->input != UNSET) {
+		b->flags |= V4L2_BUF_FLAG_INPUT;
+		b->input  = vb->input;
+	}
+
+	b->field     = vb->field;
+	b->timestamp = vb->ts;
+	b->bytesused = vb->size;
+	b->sequence  = vb->field_count >> 1;
+}
+
+int videobuf_reqbufs(struct videobuf_queue *q,
+		 struct v4l2_requestbuffers *req)
+{
+	unsigned int size,count;
+	int retval;
+
+	if (req->type != q->type) {
+		dprintk(1,"reqbufs: queue type invalid\n");
+		return -EINVAL;
+	}
+	if (req->count < 1) {
+		dprintk(1,"reqbufs: count invalid (%d)\n",req->count);
+		return -EINVAL;
+	}
+	if (req->memory != V4L2_MEMORY_MMAP     &&
+	    req->memory != V4L2_MEMORY_USERPTR  &&
+	    req->memory != V4L2_MEMORY_OVERLAY) {
+		dprintk(1,"reqbufs: memory type invalid\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&q->lock);
+	if (q->streaming) {
+		dprintk(1,"reqbufs: streaming already exists\n");
+		retval = -EBUSY;
+		goto done;
+	}
+	if (!list_empty(&q->stream)) {
+		dprintk(1,"reqbufs: stream running\n");
+		retval = -EBUSY;
+		goto done;
+	}
+
+	count = req->count;
+	if (count > VIDEO_MAX_FRAME)
+		count = VIDEO_MAX_FRAME;
+	size = 0;
+	q->ops->buf_setup(q,&count,&size);
+	size = PAGE_ALIGN(size);
+	dprintk(1,"reqbufs: bufs=%d, size=0x%x [%d pages total]\n",
+		count, size, (count*size)>>PAGE_SHIFT);
+
+	retval = videobuf_mmap_setup(q,count,size,req->memory);
+	if (retval < 0) {
+		dprintk(1,"reqbufs: mmap setup returned %d\n",retval);
+		goto done;
+	}
+
+	req->count = retval;
+
+ done:
+	mutex_unlock(&q->lock);
+	return retval;
+}
+
+int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
+{
+	if (unlikely(b->type != q->type)) {
+		dprintk(1,"querybuf: Wrong type.\n");
+		return -EINVAL;
+	}
+	if (unlikely(b->index < 0 || b->index >= VIDEO_MAX_FRAME)) {
+		dprintk(1,"querybuf: index out of range.\n");
+		return -EINVAL;
+	}
+	if (unlikely(NULL == q->bufs[b->index])) {
+		dprintk(1,"querybuf: buffer is null.\n");
+		return -EINVAL;
+	}
+	videobuf_status(q,b,q->bufs[b->index],q->type);
+	return 0;
+}
+
+int videobuf_qbuf(struct videobuf_queue *q,
+	      struct v4l2_buffer *b)
+{
+	struct videobuf_buffer *buf;
+	enum v4l2_field field;
+	unsigned long flags=0;
+	int retval;
+
+	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+	if (b->memory == V4L2_MEMORY_MMAP)
+		down_read(&current->mm->mmap_sem);
+
+	mutex_lock(&q->lock);
+	retval = -EBUSY;
+	if (q->reading) {
+		dprintk(1,"qbuf: Reading running...\n");
+		goto done;
+	}
+	retval = -EINVAL;
+	if (b->type != q->type) {
+		dprintk(1,"qbuf: Wrong type.\n");
+		goto done;
+	}
+	if (b->index < 0 || b->index >= VIDEO_MAX_FRAME) {
+		dprintk(1,"qbuf: index out of range.\n");
+		goto done;
+	}
+	buf = q->bufs[b->index];
+	if (NULL == buf) {
+		dprintk(1,"qbuf: buffer is null.\n");
+		goto done;
+	}
+	MAGIC_CHECK(buf->magic,MAGIC_BUFFER);
+	if (buf->memory != b->memory) {
+		dprintk(1,"qbuf: memory type is wrong.\n");
+		goto done;
+	}
+	if (buf->state != STATE_NEEDS_INIT && buf->state != STATE_IDLE) {
+		dprintk(1,"qbuf: buffer is already queued or active.\n");
+		goto done;
+	}
+
+	if (b->flags & V4L2_BUF_FLAG_INPUT) {
+		if (b->input >= q->inputs) {
+			dprintk(1,"qbuf: wrong input.\n");
+			goto done;
+		}
+		buf->input = b->input;
+	} else {
+		buf->input = UNSET;
+	}
+
+	switch (b->memory) {
+	case V4L2_MEMORY_MMAP:
+		if (0 == buf->baddr) {
+			dprintk(1,"qbuf: mmap requested but buffer addr is zero!\n");
+			goto done;
+		}
+		break;
+	case V4L2_MEMORY_USERPTR:
+		if (b->length < buf->bsize) {
+			dprintk(1,"qbuf: buffer length is not enough\n");
+			goto done;
+		}
+		if (STATE_NEEDS_INIT != buf->state && buf->baddr != b->m.userptr)
+			q->ops->buf_release(q,buf);
+		buf->baddr = b->m.userptr;
+		break;
+	case V4L2_MEMORY_OVERLAY:
+		buf->boff = b->m.offset;
+		break;
+	default:
+		dprintk(1,"qbuf: wrong memory type\n");
+		goto done;
+	}
+
+	dprintk(1,"qbuf: requesting next field\n");
+	field = videobuf_next_field(q);
+	retval = q->ops->buf_prepare(q,buf,field);
+	if (0 != retval) {
+		dprintk(1,"qbuf: buffer_prepare returned %d\n",retval);
+		goto done;
+	}
+
+	list_add_tail(&buf->stream,&q->stream);
+	if (q->streaming) {
+		if (q->irqlock)
+			spin_lock_irqsave(q->irqlock,flags);
+		q->ops->buf_queue(q,buf);
+		if (q->irqlock)
+			spin_unlock_irqrestore(q->irqlock,flags);
+	}
+	dprintk(1,"qbuf: succeded\n");
+	retval = 0;
+
+ done:
+	mutex_unlock(&q->lock);
+
+	if (b->memory == V4L2_MEMORY_MMAP)
+		up_read(&current->mm->mmap_sem);
+
+	return retval;
+}
+
+int videobuf_dqbuf(struct videobuf_queue *q,
+	       struct v4l2_buffer *b, int nonblocking)
+{
+	struct videobuf_buffer *buf;
+	int retval;
+
+	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+	mutex_lock(&q->lock);
+	retval = -EBUSY;
+	if (q->reading) {
+		dprintk(1,"dqbuf: Reading running...\n");
+		goto done;
+	}
+	retval = -EINVAL;
+	if (b->type != q->type) {
+		dprintk(1,"dqbuf: Wrong type.\n");
+		goto done;
+	}
+	if (list_empty(&q->stream)) {
+		dprintk(1,"dqbuf: stream running\n");
+		goto done;
+	}
+	buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
+	retval = videobuf_waiton(buf, nonblocking, 1);
+	if (retval < 0) {
+		dprintk(1,"dqbuf: waiton returned %d\n",retval);
+		goto done;
+	}
+	switch (buf->state) {
+	case STATE_ERROR:
+		dprintk(1,"dqbuf: state is error\n");
+		retval = -EIO;
+		CALL(q,sync,q, buf);
+		buf->state = STATE_IDLE;
+		break;
+	case STATE_DONE:
+		dprintk(1,"dqbuf: state is done\n");
+		CALL(q,sync,q, buf);
+		buf->state = STATE_IDLE;
+		break;
+	default:
+		dprintk(1,"dqbuf: state invalid\n");
+		retval = -EINVAL;
+		goto done;
+	}
+	list_del(&buf->stream);
+	memset(b,0,sizeof(*b));
+	videobuf_status(q,b,buf,q->type);
+
+ done:
+	mutex_unlock(&q->lock);
+	return retval;
+}
+
+int videobuf_streamon(struct videobuf_queue *q)
+{
+	struct videobuf_buffer *buf;
+	unsigned long flags=0;
+	int retval;
+
+	mutex_lock(&q->lock);
+	retval = -EBUSY;
+	if (q->reading)
+		goto done;
+	retval = 0;
+	if (q->streaming)
+		goto done;
+	q->streaming = 1;
+	if (q->irqlock)
+		spin_lock_irqsave(q->irqlock,flags);
+	list_for_each_entry(buf, &q->stream, stream)
+		if (buf->state == STATE_PREPARED)
+			q->ops->buf_queue(q,buf);
+	if (q->irqlock)
+		spin_unlock_irqrestore(q->irqlock,flags);
+
+ done:
+	mutex_unlock(&q->lock);
+	return retval;
+}
+
+int videobuf_streamoff(struct videobuf_queue *q)
+{
+	int retval = -EINVAL;
+
+	mutex_lock(&q->lock);
+	if (!q->streaming)
+		goto done;
+	videobuf_queue_cancel(q);
+	q->streaming = 0;
+	retval = 0;
+
+ done:
+	mutex_unlock(&q->lock);
+	return retval;
+}
+
+static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
+				      char __user *data,
+				      size_t count, loff_t *ppos)
+{
+	enum v4l2_field field;
+	unsigned long flags=0;
+	int retval;
+
+	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+	/* setup stuff */
+	q->read_buf = videobuf_alloc(q);
+	if (NULL == q->read_buf)
+		return -ENOMEM;
+
+	q->read_buf->memory = V4L2_MEMORY_USERPTR;
+	q->read_buf->baddr  = (unsigned long)data;
+	q->read_buf->bsize  = count;
+
+	field = videobuf_next_field(q);
+	retval = q->ops->buf_prepare(q,q->read_buf,field);
+	if (0 != retval)
+		goto done;
+
+	/* start capture & wait */
+	if (q->irqlock)
+		spin_lock_irqsave(q->irqlock,flags);
+	q->ops->buf_queue(q,q->read_buf);
+	if (q->irqlock)
+		spin_unlock_irqrestore(q->irqlock,flags);
+	retval = videobuf_waiton(q->read_buf,0,0);
+	if (0 == retval) {
+		CALL(q,sync,q,q->read_buf);
+		if (STATE_ERROR == q->read_buf->state)
+			retval = -EIO;
+		else
+			retval = q->read_buf->size;
+	}
+
+ done:
+	/* cleanup */
+	q->ops->buf_release(q,q->read_buf);
+	kfree(q->read_buf);
+	q->read_buf = NULL;
+	return retval;
+}
+
+ssize_t videobuf_read_one(struct videobuf_queue *q,
+			  char __user *data, size_t count, loff_t *ppos,
+			  int nonblocking)
+{
+	enum v4l2_field field;
+	unsigned long flags=0;
+	unsigned size, nbufs;
+	int retval;
+
+	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+	mutex_lock(&q->lock);
+
+	nbufs = 1; size = 0;
+	q->ops->buf_setup(q,&nbufs,&size);
+
+	if (NULL == q->read_buf  &&
+	    count >= size        &&
+	    !nonblocking) {
+		retval = videobuf_read_zerocopy(q,data,count,ppos);
+		if (retval >= 0  ||  retval == -EIO)
+			/* ok, all done */
+			goto done;
+		/* fallback to kernel bounce buffer on failures */
+	}
+
+	if (NULL == q->read_buf) {
+		/* need to capture a new frame */
+		retval = -ENOMEM;
+		q->read_buf = videobuf_alloc(q);
+
+		dprintk(1,"video alloc=0x%p\n", q->read_buf);
+		if (NULL == q->read_buf)
+			goto done;
+		q->read_buf->memory = V4L2_MEMORY_USERPTR;
+		q->read_buf->bsize = count; /* preferred size */
+		field = videobuf_next_field(q);
+		retval = q->ops->buf_prepare(q,q->read_buf,field);
+
+		if (0 != retval) {
+			kfree (q->read_buf);
+			q->read_buf = NULL;
+			goto done;
+		}
+		if (q->irqlock)
+			spin_lock_irqsave(q->irqlock,flags);
+
+		q->ops->buf_queue(q,q->read_buf);
+		if (q->irqlock)
+			spin_unlock_irqrestore(q->irqlock,flags);
+		q->read_off = 0;
+	}
+
+	/* wait until capture is done */
+	retval = videobuf_waiton(q->read_buf, nonblocking, 1);
+	if (0 != retval)
+		goto done;
+
+	CALL(q,sync,q,q->read_buf);
+
+	if (STATE_ERROR == q->read_buf->state) {
+		/* catch I/O errors */
+		q->ops->buf_release(q,q->read_buf);
+		kfree(q->read_buf);
+		q->read_buf = NULL;
+		retval = -EIO;
+		goto done;
+	}
+
+	/* Copy to userspace */
+	retval=CALL(q,copy_to_user,q,data,count,nonblocking);
+	if (retval<0)
+		goto done;
+
+	q->read_off += retval;
+	if (q->read_off == q->read_buf->size) {
+		/* all data copied, cleanup */
+		q->ops->buf_release(q,q->read_buf);
+		kfree(q->read_buf);
+		q->read_buf = NULL;
+	}
+
+ done:
+	mutex_unlock(&q->lock);
+	return retval;
+}
+
+int videobuf_read_start(struct videobuf_queue *q)
+{
+	enum v4l2_field field;
+	unsigned long flags=0;
+	unsigned int count = 0, size = 0;
+	int err, i;
+
+	q->ops->buf_setup(q,&count,&size);
+	if (count < 2)
+		count = 2;
+	if (count > VIDEO_MAX_FRAME)
+		count = VIDEO_MAX_FRAME;
+	size = PAGE_ALIGN(size);
+
+	err = videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR);
+	if (err < 0)
+		return err;
+
+	count = err;
+
+	for (i = 0; i < count; i++) {
+		field = videobuf_next_field(q);
+		err = q->ops->buf_prepare(q,q->bufs[i],field);
+		if (err)
+			return err;
+		list_add_tail(&q->bufs[i]->stream, &q->stream);
+	}
+	if (q->irqlock)
+		spin_lock_irqsave(q->irqlock,flags);
+	for (i = 0; i < count; i++)
+		q->ops->buf_queue(q,q->bufs[i]);
+	if (q->irqlock)
+		spin_unlock_irqrestore(q->irqlock,flags);
+	q->reading = 1;
+	return 0;
+}
+
+void videobuf_read_stop(struct videobuf_queue *q)
+{
+	int i;
+
+	videobuf_queue_cancel(q);
+	videobuf_mmap_free(q);
+	INIT_LIST_HEAD(&q->stream);
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (NULL == q->bufs[i])
+			continue;
+		kfree(q->bufs[i]);
+		q->bufs[i] = NULL;
+	}
+	q->read_buf = NULL;
+	q->reading  = 0;
+}
+
+ssize_t videobuf_read_stream(struct videobuf_queue *q,
+			     char __user *data, size_t count, loff_t *ppos,
+			     int vbihack, int nonblocking)
+{
+	int rc, retval;
+	unsigned long flags=0;
+
+	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+	dprintk(2,"%s\n",__FUNCTION__);
+	mutex_lock(&q->lock);
+	retval = -EBUSY;
+	if (q->streaming)
+		goto done;
+	if (!q->reading) {
+		retval = videobuf_read_start(q);
+		if (retval < 0)
+			goto done;
+	}
+
+	retval = 0;
+	while (count > 0) {
+		/* get / wait for data */
+		if (NULL == q->read_buf) {
+			q->read_buf = list_entry(q->stream.next,
+						 struct videobuf_buffer,
+						 stream);
+			list_del(&q->read_buf->stream);
+			q->read_off = 0;
+		}
+		rc = videobuf_waiton(q->read_buf, nonblocking, 1);
+		if (rc < 0) {
+			if (0 == retval)
+				retval = rc;
+			break;
+		}
+
+		if (q->read_buf->state == STATE_DONE) {
+			rc = CALL (q,copy_stream, q, data + retval, count,
+					retval, vbihack, nonblocking);
+			if (rc < 0) {
+				retval = rc;
+				break;
+			}
+			retval      += rc;
+			count       -= rc;
+			q->read_off += rc;
+		} else {
+			/* some error */
+			q->read_off = q->read_buf->size;
+			if (0 == retval)
+				retval = -EIO;
+		}
+
+		/* requeue buffer when done with copying */
+		if (q->read_off == q->read_buf->size) {
+			list_add_tail(&q->read_buf->stream,
+				      &q->stream);
+			if (q->irqlock)
+				spin_lock_irqsave(q->irqlock,flags);
+			q->ops->buf_queue(q,q->read_buf);
+			if (q->irqlock)
+				spin_unlock_irqrestore(q->irqlock,flags);
+			q->read_buf = NULL;
+		}
+		if (retval < 0)
+			break;
+	}
+
+ done:
+	mutex_unlock(&q->lock);
+	return retval;
+}
+
+unsigned int videobuf_poll_stream(struct file *file,
+				  struct videobuf_queue *q,
+				  poll_table *wait)
+{
+	struct videobuf_buffer *buf = NULL;
+	unsigned int rc = 0;
+
+	mutex_lock(&q->lock);
+	if (q->streaming) {
+		if (!list_empty(&q->stream))
+			buf = list_entry(q->stream.next,
+					 struct videobuf_buffer, stream);
+	} else {
+		if (!q->reading)
+			videobuf_read_start(q);
+		if (!q->reading) {
+			rc = POLLERR;
+		} else if (NULL == q->read_buf) {
+			q->read_buf = list_entry(q->stream.next,
+						 struct videobuf_buffer,
+						 stream);
+			list_del(&q->read_buf->stream);
+			q->read_off = 0;
+		}
+		buf = q->read_buf;
+	}
+	if (!buf)
+		rc = POLLERR;
+
+	if (0 == rc) {
+		poll_wait(file, &buf->done, wait);
+		if (buf->state == STATE_DONE ||
+		    buf->state == STATE_ERROR)
+			rc = POLLIN|POLLRDNORM;
+	}
+	mutex_unlock(&q->lock);
+	return rc;
+}
+
+int videobuf_mmap_setup(struct videobuf_queue *q,
+			unsigned int bcount, unsigned int bsize,
+			enum v4l2_memory memory)
+{
+	unsigned int i;
+	int err;
+
+	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+	err = videobuf_mmap_free(q);
+	if (0 != err)
+		return err;
+
+	/* Allocate and initialize buffers */
+	for (i = 0; i < bcount; i++) {
+		q->bufs[i] = videobuf_alloc(q);
+
+		if (q->bufs[i] == NULL)
+			break;
+
+		q->bufs[i]->i      = i;
+		q->bufs[i]->input  = UNSET;
+		q->bufs[i]->memory = memory;
+		q->bufs[i]->bsize  = bsize;
+		switch (memory) {
+		case V4L2_MEMORY_MMAP:
+			q->bufs[i]->boff  = bsize * i;
+			break;
+		case V4L2_MEMORY_USERPTR:
+		case V4L2_MEMORY_OVERLAY:
+			/* nothing */
+			break;
+		}
+	}
+
+	if (!i)
+		return -ENOMEM;
+
+	dprintk(1,"mmap setup: %d buffers, %d bytes each\n",
+		i, bsize);
+
+	return i;
+}
+
+int videobuf_mmap_free(struct videobuf_queue *q)
+{
+	int i;
+	int rc;
+
+	if (!q)
+		return 0;
+
+	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+	rc  = CALL(q,mmap_free,q);
+	if (rc<0)
+		return rc;
+
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (NULL == q->bufs[i])
+			continue;
+		q->ops->buf_release(q,q->bufs[i]);
+		kfree(q->bufs[i]);
+		q->bufs[i] = NULL;
+	}
+
+	return rc;
+}
+
+int videobuf_mmap_mapper(struct videobuf_queue *q,
+			 struct vm_area_struct *vma)
+{
+	int retval;
+
+	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+	mutex_lock(&q->lock);
+	retval=CALL(q,mmap_mapper,q,vma);
+	mutex_unlock(&q->lock);
+
+	return retval;
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+int videobuf_cgmbuf(struct videobuf_queue *q,
+		    struct video_mbuf *mbuf, int count)
+{
+	struct v4l2_requestbuffers req;
+	int rc,i;
+
+	MAGIC_CHECK(q->int_ops->magic,MAGIC_QTYPE_OPS);
+
+	memset(&req,0,sizeof(req));
+	req.type   = q->type;
+	req.count  = count;
+	req.memory = V4L2_MEMORY_MMAP;
+	rc = videobuf_reqbufs(q,&req);
+	if (rc < 0)
+		return rc;
+
+	mbuf->frames = req.count;
+	mbuf->size   = 0;
+	for (i = 0; i < mbuf->frames; i++) {
+		mbuf->offsets[i]  = q->bufs[i]->boff;
+		mbuf->size       += q->bufs[i]->bsize;
+	}
+
+	return 0;
+}
+#endif
+
+/* --------------------------------------------------------------------- */
+
+EXPORT_SYMBOL_GPL(videobuf_waiton);
+EXPORT_SYMBOL_GPL(videobuf_iolock);
+
+EXPORT_SYMBOL_GPL(videobuf_alloc);
+
+EXPORT_SYMBOL_GPL(videobuf_queue_core_init);
+EXPORT_SYMBOL_GPL(videobuf_queue_cancel);
+EXPORT_SYMBOL_GPL(videobuf_queue_is_busy);
+
+EXPORT_SYMBOL_GPL(videobuf_next_field);
+EXPORT_SYMBOL_GPL(videobuf_reqbufs);
+EXPORT_SYMBOL_GPL(videobuf_querybuf);
+EXPORT_SYMBOL_GPL(videobuf_qbuf);
+EXPORT_SYMBOL_GPL(videobuf_dqbuf);
+EXPORT_SYMBOL_GPL(videobuf_cgmbuf);
+EXPORT_SYMBOL_GPL(videobuf_streamon);
+EXPORT_SYMBOL_GPL(videobuf_streamoff);
+
+EXPORT_SYMBOL_GPL(videobuf_read_start);
+EXPORT_SYMBOL_GPL(videobuf_read_stop);
+EXPORT_SYMBOL_GPL(videobuf_read_stream);
+EXPORT_SYMBOL_GPL(videobuf_read_one);
+EXPORT_SYMBOL_GPL(videobuf_poll_stream);
+
+EXPORT_SYMBOL_GPL(videobuf_mmap_setup);
+EXPORT_SYMBOL_GPL(videobuf_mmap_free);
+EXPORT_SYMBOL_GPL(videobuf_mmap_mapper);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
new file mode 100644
index 0000000..8bb7fdd
--- /dev/null
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -0,0 +1,726 @@
+/*
+ * helper functions for PCI DMA video4linux capture buffers
+ *
+ * The functions expect the hardware being able to scatter gatter
+ * (i.e. the buffers are not linear in physical memory, but fragmented
+ * into PAGE_SIZE chunks).  They also assume the driver does not need
+ * to touch the video data.
+ *
+ * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
+ *
+ * Highly based on video-buf written originally by:
+ * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org>
+ * (c) 2006 Mauro Carvalho Chehab, <mchehab@infradead.org>
+ * (c) 2006 Ted Walther and John Sokol
+ *
+ * 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
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include <media/videobuf-dma-sg.h>
+
+#define MAGIC_DMABUF 0x19721112
+#define MAGIC_SG_MEM 0x17890714
+
+#define MAGIC_CHECK(is,should)	if (unlikely((is) != (should))) \
+	{ printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
+
+static int debug = 0;
+module_param(debug, int, 0644);
+
+MODULE_DESCRIPTION("helper module to manage video4linux pci dma sg buffers");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
+
+#define dprintk(level, fmt, arg...)	if (debug >= level) \
+	printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg)
+
+/* --------------------------------------------------------------------- */
+
+struct scatterlist*
+videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
+{
+	struct scatterlist *sglist;
+	struct page *pg;
+	int i;
+
+	sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
+	if (NULL == sglist)
+		return NULL;
+	for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
+		pg = vmalloc_to_page(virt);
+		if (NULL == pg)
+			goto err;
+		BUG_ON(PageHighMem(pg));
+		sglist[i].page   = pg;
+		sglist[i].length = PAGE_SIZE;
+	}
+	return sglist;
+
+ err:
+	kfree(sglist);
+	return NULL;
+}
+
+struct scatterlist*
+videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
+{
+	struct scatterlist *sglist;
+	int i = 0;
+
+	if (NULL == pages[0])
+		return NULL;
+	sglist = kcalloc(nr_pages, sizeof(*sglist), GFP_KERNEL);
+	if (NULL == sglist)
+		return NULL;
+
+	if (NULL == pages[0])
+		goto nopage;
+	if (PageHighMem(pages[0]))
+		/* DMA to highmem pages might not work */
+		goto highmem;
+	sglist[0].page   = pages[0];
+	sglist[0].offset = offset;
+	sglist[0].length = PAGE_SIZE - offset;
+	for (i = 1; i < nr_pages; i++) {
+		if (NULL == pages[i])
+			goto nopage;
+		if (PageHighMem(pages[i]))
+			goto highmem;
+		sglist[i].page   = pages[i];
+		sglist[i].length = PAGE_SIZE;
+	}
+	return sglist;
+
+ nopage:
+	dprintk(2,"sgl: oops - no page\n");
+	kfree(sglist);
+	return NULL;
+
+ highmem:
+	dprintk(2,"sgl: oops - highmem page\n");
+	kfree(sglist);
+	return NULL;
+}
+
+/* --------------------------------------------------------------------- */
+
+struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf)
+{
+	struct videbuf_pci_sg_memory *mem=buf->priv;
+	BUG_ON (!mem);
+
+	MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+	return &mem->dma;
+}
+
+void videobuf_dma_init(struct videobuf_dmabuf *dma)
+{
+	memset(dma,0,sizeof(*dma));
+	dma->magic = MAGIC_DMABUF;
+}
+
+static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
+			int direction, unsigned long data, unsigned long size)
+{
+	unsigned long first,last;
+	int err, rw = 0;
+
+	dma->direction = direction;
+	switch (dma->direction) {
+	case PCI_DMA_FROMDEVICE: rw = READ;  break;
+	case PCI_DMA_TODEVICE:   rw = WRITE; break;
+	default:                 BUG();
+	}
+
+	first = (data          & PAGE_MASK) >> PAGE_SHIFT;
+	last  = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT;
+	dma->offset   = data & ~PAGE_MASK;
+	dma->nr_pages = last-first+1;
+	dma->pages = kmalloc(dma->nr_pages * sizeof(struct page*),
+			     GFP_KERNEL);
+	if (NULL == dma->pages)
+		return -ENOMEM;
+	dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n",
+		data,size,dma->nr_pages);
+
+	dma->varea = (void *) data;
+
+
+	err = get_user_pages(current,current->mm,
+			     data & PAGE_MASK, dma->nr_pages,
+			     rw == READ, 1, /* force */
+			     dma->pages, NULL);
+
+	if (err != dma->nr_pages) {
+		dma->nr_pages = (err >= 0) ? err : 0;
+		dprintk(1,"get_user_pages: err=%d [%d]\n",err,dma->nr_pages);
+		return err < 0 ? err : -EINVAL;
+	}
+	return 0;
+}
+
+int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
+			   unsigned long data, unsigned long size)
+{
+	int ret;
+	down_read(&current->mm->mmap_sem);
+	ret = videobuf_dma_init_user_locked(dma, direction, data, size);
+	up_read(&current->mm->mmap_sem);
+
+	return ret;
+}
+
+int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
+			     int nr_pages)
+{
+	dprintk(1,"init kernel [%d pages]\n",nr_pages);
+	dma->direction = direction;
+	dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT);
+	if (NULL == dma->vmalloc) {
+		dprintk(1,"vmalloc_32(%d pages) failed\n",nr_pages);
+		return -ENOMEM;
+	}
+	dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n",
+				(unsigned long)dma->vmalloc,
+				nr_pages << PAGE_SHIFT);
+	memset(dma->vmalloc,0,nr_pages << PAGE_SHIFT);
+	dma->nr_pages = nr_pages;
+	return 0;
+}
+
+int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
+			      dma_addr_t addr, int nr_pages)
+{
+	dprintk(1,"init overlay [%d pages @ bus 0x%lx]\n",
+		nr_pages,(unsigned long)addr);
+	dma->direction = direction;
+	if (0 == addr)
+		return -EINVAL;
+
+	dma->bus_addr = addr;
+	dma->nr_pages = nr_pages;
+	return 0;
+}
+
+int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
+{
+	void                   *dev=q->dev;
+
+	MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+	BUG_ON(0 == dma->nr_pages);
+
+	if (dma->pages) {
+		dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages,
+						   dma->offset);
+	}
+	if (dma->vmalloc) {
+		dma->sglist = videobuf_vmalloc_to_sg
+						(dma->vmalloc,dma->nr_pages);
+	}
+	if (dma->bus_addr) {
+		dma->sglist = kmalloc(sizeof(struct scatterlist), GFP_KERNEL);
+		if (NULL != dma->sglist) {
+			dma->sglen  = 1;
+			sg_dma_address(&dma->sglist[0]) = dma->bus_addr & PAGE_MASK;
+			dma->sglist[0].offset           = dma->bus_addr & ~PAGE_MASK;
+			sg_dma_len(&dma->sglist[0])     = dma->nr_pages * PAGE_SIZE;
+		}
+	}
+	if (NULL == dma->sglist) {
+		dprintk(1,"scatterlist is NULL\n");
+		return -ENOMEM;
+	}
+	if (!dma->bus_addr) {
+		dma->sglen = pci_map_sg(dev,dma->sglist,
+					dma->nr_pages, dma->direction);
+		if (0 == dma->sglen) {
+			printk(KERN_WARNING
+			       "%s: videobuf_map_sg failed\n",__FUNCTION__);
+			kfree(dma->sglist);
+			dma->sglist = NULL;
+			dma->sglen = 0;
+			return -EIO;
+		}
+	}
+	return 0;
+}
+
+int videobuf_dma_sync(struct videobuf_queue *q,struct videobuf_dmabuf *dma)
+{
+	void                   *dev=q->dev;
+
+	MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+	BUG_ON(!dma->sglen);
+
+	pci_dma_sync_sg_for_cpu (dev,dma->sglist,dma->nr_pages,dma->direction);
+	return 0;
+}
+
+int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
+{
+	void                   *dev=q->dev;
+
+	MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+	if (!dma->sglen)
+		return 0;
+
+	pci_unmap_sg (dev,dma->sglist,dma->nr_pages,dma->direction);
+
+	kfree(dma->sglist);
+	dma->sglist = NULL;
+	dma->sglen = 0;
+	return 0;
+}
+
+int videobuf_dma_free(struct videobuf_dmabuf *dma)
+{
+	MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+	BUG_ON(dma->sglen);
+
+	if (dma->pages) {
+		int i;
+		for (i=0; i < dma->nr_pages; i++)
+			page_cache_release(dma->pages[i]);
+		kfree(dma->pages);
+		dma->pages = NULL;
+	}
+
+	vfree(dma->vmalloc);
+	dma->vmalloc = NULL;
+	dma->varea = NULL;
+
+	if (dma->bus_addr) {
+		dma->bus_addr = 0;
+	}
+	dma->direction = PCI_DMA_NONE;
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma)
+{
+	struct videobuf_queue q;
+
+	q.dev=pci;
+
+	return (videobuf_dma_map(&q,dma));
+}
+
+int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma)
+{
+	struct videobuf_queue q;
+
+	q.dev=pci;
+
+	return (videobuf_dma_unmap(&q,dma));
+}
+
+/* --------------------------------------------------------------------- */
+
+static void
+videobuf_vm_open(struct vm_area_struct *vma)
+{
+	struct videobuf_mapping *map = vma->vm_private_data;
+
+	dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map,
+		map->count,vma->vm_start,vma->vm_end);
+	map->count++;
+}
+
+static void
+videobuf_vm_close(struct vm_area_struct *vma)
+{
+	struct videobuf_mapping *map = vma->vm_private_data;
+	struct videobuf_queue *q = map->q;
+	struct videbuf_pci_sg_memory *mem;
+	int i;
+
+	dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map,
+		map->count,vma->vm_start,vma->vm_end);
+
+	map->count--;
+	if (0 == map->count) {
+		dprintk(1,"munmap %p q=%p\n",map,q);
+		mutex_lock(&q->lock);
+		for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+			if (NULL == q->bufs[i])
+				continue;
+			mem=q->bufs[i]->priv;
+
+			if (!mem)
+				continue;
+
+			MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+			if (q->bufs[i]->map != map)
+				continue;
+			q->bufs[i]->map   = NULL;
+			q->bufs[i]->baddr = 0;
+			q->ops->buf_release(q,q->bufs[i]);
+		}
+		mutex_unlock(&q->lock);
+		kfree(map);
+	}
+	return;
+}
+
+/*
+ * Get a anonymous page for the mapping.  Make sure we can DMA to that
+ * memory location with 32bit PCI devices (i.e. don't use highmem for
+ * now ...).  Bounce buffers don't work very well for the data rates
+ * video capture has.
+ */
+static struct page*
+videobuf_vm_nopage(struct vm_area_struct *vma, unsigned long vaddr,
+		   int *type)
+{
+	struct page *page;
+
+	dprintk(3,"nopage: fault @ %08lx [vma %08lx-%08lx]\n",
+		vaddr,vma->vm_start,vma->vm_end);
+	if (vaddr > vma->vm_end)
+		return NOPAGE_SIGBUS;
+	page = alloc_page(GFP_USER | __GFP_DMA32);
+	if (!page)
+		return NOPAGE_OOM;
+	clear_user_page(page_address(page), vaddr, page);
+	if (type)
+		*type = VM_FAULT_MINOR;
+	return page;
+}
+
+static struct vm_operations_struct videobuf_vm_ops =
+{
+	.open     = videobuf_vm_open,
+	.close    = videobuf_vm_close,
+	.nopage   = videobuf_vm_nopage,
+};
+
+/* ---------------------------------------------------------------------
+ * PCI handlers for the generic methods
+ */
+
+/* Allocated area consists on 3 parts:
+	struct video_buffer
+	struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
+	struct videobuf_pci_sg_memory
+ */
+
+static void *__videobuf_alloc(size_t size)
+{
+	struct videbuf_pci_sg_memory *mem;
+	struct videobuf_buffer *vb;
+
+	vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
+
+	mem = vb->priv = ((char *)vb)+size;
+	mem->magic=MAGIC_SG_MEM;
+
+	videobuf_dma_init(&mem->dma);
+
+	dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
+		__FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
+		mem,(long)sizeof(*mem));
+
+	return vb;
+}
+
+static int __videobuf_iolock (struct videobuf_queue* q,
+			      struct videobuf_buffer *vb,
+			      struct v4l2_framebuffer *fbuf)
+{
+	int err,pages;
+	dma_addr_t bus;
+	struct videbuf_pci_sg_memory *mem=vb->priv;
+	BUG_ON(!mem);
+
+	MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+	switch (vb->memory) {
+	case V4L2_MEMORY_MMAP:
+	case V4L2_MEMORY_USERPTR:
+		if (0 == vb->baddr) {
+			/* no userspace addr -- kernel bounce buffer */
+			pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
+			err = videobuf_dma_init_kernel( &mem->dma,
+							PCI_DMA_FROMDEVICE,
+							pages );
+			if (0 != err)
+				return err;
+		} else if (vb->memory == V4L2_MEMORY_USERPTR) {
+			/* dma directly to userspace */
+			err = videobuf_dma_init_user( &mem->dma,
+						      PCI_DMA_FROMDEVICE,
+						      vb->baddr,vb->bsize );
+			if (0 != err)
+				return err;
+		} else {
+			/* NOTE: HACK: videobuf_iolock on V4L2_MEMORY_MMAP
+			buffers can only be called from videobuf_qbuf
+			we take current->mm->mmap_sem there, to prevent
+			locking inversion, so don't take it here */
+
+			err = videobuf_dma_init_user_locked(&mem->dma,
+						      PCI_DMA_FROMDEVICE,
+						      vb->baddr, vb->bsize);
+			if (0 != err)
+				return err;
+		}
+		break;
+	case V4L2_MEMORY_OVERLAY:
+		if (NULL == fbuf)
+			return -EINVAL;
+		/* FIXME: need sanity checks for vb->boff */
+		/*
+		 * Using a double cast to avoid compiler warnings when
+		 * building for PAE. Compiler doesn't like direct casting
+		 * of a 32 bit ptr to 64 bit integer.
+		 */
+		bus   = (dma_addr_t)(unsigned long)fbuf->base + vb->boff;
+		pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
+		err = videobuf_dma_init_overlay(&mem->dma,PCI_DMA_FROMDEVICE,
+						bus, pages);
+		if (0 != err)
+			return err;
+		break;
+	default:
+		BUG();
+	}
+	err = videobuf_dma_map(q,&mem->dma);
+	if (0 != err)
+		return err;
+
+	return 0;
+}
+
+static int __videobuf_sync(struct videobuf_queue *q,
+			   struct videobuf_buffer *buf)
+{
+	struct videbuf_pci_sg_memory *mem=buf->priv;
+	BUG_ON (!mem);
+	MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+	return	videobuf_dma_sync(q,&mem->dma);
+}
+
+static int __videobuf_mmap_free(struct videobuf_queue *q)
+{
+	int i;
+
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (q->bufs[i]) {
+			if (q->bufs[i]->map)
+				return -EBUSY;
+		}
+	}
+
+	return 0;
+}
+
+static int __videobuf_mmap_mapper(struct videobuf_queue *q,
+			 struct vm_area_struct *vma)
+{
+	struct videbuf_pci_sg_memory *mem;
+	struct videobuf_mapping *map;
+	unsigned int first,last,size,i;
+	int retval;
+
+	retval = -EINVAL;
+	if (!(vma->vm_flags & VM_WRITE)) {
+		dprintk(1,"mmap app bug: PROT_WRITE please\n");
+		goto done;
+	}
+	if (!(vma->vm_flags & VM_SHARED)) {
+		dprintk(1,"mmap app bug: MAP_SHARED please\n");
+		goto done;
+	}
+
+	/* look for first buffer to map */
+	for (first = 0; first < VIDEO_MAX_FRAME; first++) {
+		if (NULL == q->bufs[first])
+			continue;
+		mem=q->bufs[first]->priv;
+		BUG_ON (!mem);
+		MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+		if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
+			continue;
+		if (q->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))
+			break;
+	}
+	if (VIDEO_MAX_FRAME == first) {
+		dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n",
+			(vma->vm_pgoff << PAGE_SHIFT));
+		goto done;
+	}
+
+	/* look for last buffer to map */
+	for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {
+		if (NULL == q->bufs[last])
+			continue;
+		if (V4L2_MEMORY_MMAP != q->bufs[last]->memory)
+			continue;
+		if (q->bufs[last]->map) {
+			retval = -EBUSY;
+			goto done;
+		}
+		size += q->bufs[last]->bsize;
+		if (size == (vma->vm_end - vma->vm_start))
+			break;
+	}
+	if (VIDEO_MAX_FRAME == last) {
+		dprintk(1,"mmap app bug: size invalid [size=0x%lx]\n",
+			(vma->vm_end - vma->vm_start));
+		goto done;
+	}
+
+	/* create mapping + update buffer list */
+	retval = -ENOMEM;
+	map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);
+	if (NULL == map)
+		goto done;
+	for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) {
+		q->bufs[i]->map   = map;
+		q->bufs[i]->baddr = vma->vm_start + size;
+	}
+	map->count    = 1;
+	map->start    = vma->vm_start;
+	map->end      = vma->vm_end;
+	map->q        = q;
+	vma->vm_ops   = &videobuf_vm_ops;
+	vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
+	vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
+	vma->vm_private_data = map;
+	dprintk(1,"mmap %p: q=%p %08lx-%08lx pgoff %08lx bufs %d-%d\n",
+		map,q,vma->vm_start,vma->vm_end,vma->vm_pgoff,first,last);
+	retval = 0;
+
+ done:
+	return retval;
+}
+
+static int __videobuf_copy_to_user ( struct videobuf_queue *q,
+				char __user *data, size_t count,
+				int nonblocking )
+{
+	struct videbuf_pci_sg_memory *mem=q->read_buf->priv;
+	BUG_ON (!mem);
+	MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+	/* copy to userspace */
+	if (count > q->read_buf->size - q->read_off)
+		count = q->read_buf->size - q->read_off;
+
+	if (copy_to_user(data, mem->dma.vmalloc+q->read_off, count))
+		return -EFAULT;
+
+	return count;
+}
+
+static int __videobuf_copy_stream ( struct videobuf_queue *q,
+				char __user *data, size_t count, size_t pos,
+				int vbihack, int nonblocking )
+{
+	unsigned int  *fc;
+	struct videbuf_pci_sg_memory *mem=q->read_buf->priv;
+	BUG_ON (!mem);
+	MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+
+	if (vbihack) {
+		/* dirty, undocumented hack -- pass the frame counter
+			* within the last four bytes of each vbi data block.
+			* We need that one to maintain backward compatibility
+			* to all vbi decoding software out there ... */
+		fc  = (unsigned int*)mem->dma.vmalloc;
+		fc += (q->read_buf->size>>2) -1;
+		*fc = q->read_buf->field_count >> 1;
+		dprintk(1,"vbihack: %d\n",*fc);
+	}
+
+	/* copy stuff using the common method */
+	count = __videobuf_copy_to_user (q,data,count,nonblocking);
+
+	if ( (count==-EFAULT) && (0 == pos) )
+		return -EFAULT;
+
+	return count;
+}
+
+static struct videobuf_qtype_ops pci_ops = {
+	.magic        = MAGIC_QTYPE_OPS,
+
+	.alloc        = __videobuf_alloc,
+	.iolock       = __videobuf_iolock,
+	.sync         = __videobuf_sync,
+	.mmap_free    = __videobuf_mmap_free,
+	.mmap_mapper  = __videobuf_mmap_mapper,
+	.copy_to_user = __videobuf_copy_to_user,
+	.copy_stream  = __videobuf_copy_stream,
+};
+
+void *videobuf_pci_alloc (size_t size)
+{
+	struct videobuf_queue q;
+
+	/* Required to make generic handler to call __videobuf_alloc */
+	q.int_ops=&pci_ops;
+
+	q.msize=size;
+
+	return videobuf_alloc (&q);
+}
+
+void videobuf_queue_pci_init(struct videobuf_queue* q,
+			 struct videobuf_queue_ops *ops,
+			 void *dev,
+			 spinlock_t *irqlock,
+			 enum v4l2_buf_type type,
+			 enum v4l2_field field,
+			 unsigned int msize,
+			 void *priv)
+{
+	videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
+				 priv, &pci_ops);
+}
+
+/* --------------------------------------------------------------------- */
+
+EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);
+
+EXPORT_SYMBOL_GPL(videobuf_to_dma);
+EXPORT_SYMBOL_GPL(videobuf_dma_init);
+EXPORT_SYMBOL_GPL(videobuf_dma_init_user);
+EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel);
+EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay);
+EXPORT_SYMBOL_GPL(videobuf_dma_map);
+EXPORT_SYMBOL_GPL(videobuf_dma_sync);
+EXPORT_SYMBOL_GPL(videobuf_dma_unmap);
+EXPORT_SYMBOL_GPL(videobuf_dma_free);
+
+EXPORT_SYMBOL_GPL(videobuf_pci_dma_map);
+EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap);
+EXPORT_SYMBOL_GPL(videobuf_pci_alloc);
+
+EXPORT_SYMBOL_GPL(videobuf_queue_pci_init);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/videobuf-dvb.c
similarity index 97%
rename from drivers/media/video/video-buf-dvb.c
rename to drivers/media/video/videobuf-dvb.c
index e617925..880317e 100644
--- a/drivers/media/video/video-buf-dvb.c
+++ b/drivers/media/video/videobuf-dvb.c
@@ -22,8 +22,8 @@
 #include <linux/file.h>
 #include <linux/freezer.h>
 
-#include <media/video-buf.h>
-#include <media/video-buf-dvb.h>
+#include <media/videobuf-dma-sg.h>
+#include <media/videobuf-dvb.h>
 
 /* ------------------------------------------------------------------ */
 
@@ -45,6 +45,7 @@
 	struct videobuf_buffer *buf;
 	unsigned long flags;
 	int err;
+	struct videobuf_dmabuf *dma;
 
 	dprintk("dvb thread started\n");
 	set_freezable();
@@ -56,7 +57,6 @@
 				 struct videobuf_buffer, stream);
 		list_del(&buf->stream);
 		err = videobuf_waiton(buf,0,1);
-		BUG_ON(0 != err);
 
 		/* no more feeds left or stop_feed() asked us to quit */
 		if (0 == dvb->nfeeds)
@@ -66,8 +66,9 @@
 		try_to_freeze();
 
 		/* feed buffer data to demux */
+		dma=videobuf_to_dma(buf);
 		if (buf->state == STATE_DONE)
-			dvb_dmx_swfilter(&dvb->demux, buf->dma.vmalloc,
+			dvb_dmx_swfilter(&dvb->demux, dma->vmalloc,
 					 buf->size);
 
 		/* requeue buffer */
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
new file mode 100644
index 0000000..2e3689a
--- /dev/null
+++ b/drivers/media/video/videobuf-vmalloc.c
@@ -0,0 +1,370 @@
+/*
+ * helper functions for vmalloc video4linux capture buffers
+ *
+ * The functions expect the hardware being able to scatter gatter
+ * (i.e. the buffers are not linear in physical memory, but fragmented
+ * into PAGE_SIZE chunks).  They also assume the driver does not need
+ * to touch the video data.
+ *
+ * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org>
+ *
+ * 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
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include <media/videobuf-vmalloc.h>
+
+#define MAGIC_DMABUF   0x17760309
+#define MAGIC_VMAL_MEM 0x18221223
+
+#define MAGIC_CHECK(is,should)	if (unlikely((is) != (should))) \
+	{ printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
+
+static int debug = 0;
+module_param(debug, int, 0644);
+
+MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
+
+#define dprintk(level, fmt, arg...)	if (debug >= level) \
+	printk(KERN_DEBUG "vbuf-sg: " fmt , ## arg)
+
+
+/***************************************************************************/
+
+static void
+videobuf_vm_open(struct vm_area_struct *vma)
+{
+	struct videobuf_mapping *map = vma->vm_private_data;
+
+	dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map,
+		map->count,vma->vm_start,vma->vm_end);
+
+	map->count++;
+}
+
+static void
+videobuf_vm_close(struct vm_area_struct *vma)
+{
+	struct videobuf_mapping *map = vma->vm_private_data;
+	struct videobuf_queue *q = map->q;
+	int i;
+
+	dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map,
+		map->count,vma->vm_start,vma->vm_end);
+
+	map->count--;
+	if (0 == map->count) {
+		dprintk(1,"munmap %p q=%p\n",map,q);
+		mutex_lock(&q->lock);
+		for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+			if (NULL == q->bufs[i])
+				continue;
+
+			if (q->bufs[i]->map != map)
+				continue;
+
+			q->ops->buf_release(q,q->bufs[i]);
+
+			q->bufs[i]->map   = NULL;
+			q->bufs[i]->baddr = 0;
+		}
+		mutex_unlock(&q->lock);
+		kfree(map);
+	}
+	return;
+}
+
+static struct vm_operations_struct videobuf_vm_ops =
+{
+	.open     = videobuf_vm_open,
+	.close    = videobuf_vm_close,
+};
+
+/* ---------------------------------------------------------------------
+ * vmalloc handlers for the generic methods
+ */
+
+/* Allocated area consists on 3 parts:
+	struct video_buffer
+	struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
+	struct videobuf_pci_sg_memory
+ */
+
+static void *__videobuf_alloc(size_t size)
+{
+	struct videbuf_vmalloc_memory *mem;
+	struct videobuf_buffer *vb;
+
+	vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
+
+	mem = vb->priv = ((char *)vb)+size;
+	mem->magic=MAGIC_VMAL_MEM;
+
+	dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
+		__FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
+		mem,(long)sizeof(*mem));
+
+	return vb;
+}
+
+static int __videobuf_iolock (struct videobuf_queue* q,
+			      struct videobuf_buffer *vb,
+			      struct v4l2_framebuffer *fbuf)
+{
+	int pages;
+
+	struct videbuf_vmalloc_memory *mem=vb->priv;
+
+
+	BUG_ON(!mem);
+
+	MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+	pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
+
+	/* Currently, doesn't support V4L2_MEMORY_OVERLAY */
+	if ((vb->memory != V4L2_MEMORY_MMAP) &&
+				(vb->memory != V4L2_MEMORY_USERPTR) ) {
+		printk(KERN_ERR "Method currently unsupported.\n");
+		return -EINVAL;
+	}
+
+	/* FIXME: should be tested with kernel mmap mem */
+	mem->vmalloc=vmalloc_user (PAGE_ALIGN(vb->size));
+	if (NULL == mem->vmalloc) {
+		printk(KERN_ERR "vmalloc (%d pages) failed\n",pages);
+		return -ENOMEM;
+	}
+
+	dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n",
+				(unsigned long)mem->vmalloc,
+				pages << PAGE_SHIFT);
+
+	/* It seems that some kernel versions need to do remap *after*
+	   the mmap() call
+	 */
+	if (mem->vma) {
+		int retval=remap_vmalloc_range(mem->vma, mem->vmalloc,0);
+		kfree(mem->vma);
+		mem->vma=NULL;
+		if (retval<0) {
+			dprintk(1,"mmap app bug: remap_vmalloc_range area %p error %d\n",
+				mem->vmalloc,retval);
+			return retval;
+		}
+	}
+
+	return 0;
+}
+
+static int __videobuf_sync(struct videobuf_queue *q,
+			   struct videobuf_buffer *buf)
+{
+	return 0;
+}
+
+static int __videobuf_mmap_free(struct videobuf_queue *q)
+{
+	unsigned int i;
+
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (q->bufs[i]) {
+			if (q->bufs[i]->map)
+				return -EBUSY;
+		}
+	}
+
+	return 0;
+}
+
+static int __videobuf_mmap_mapper(struct videobuf_queue *q,
+			 struct vm_area_struct *vma)
+{
+	struct videbuf_vmalloc_memory *mem;
+	struct videobuf_mapping *map;
+	unsigned int first;
+	int retval;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+	if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED))
+		return -EINVAL;
+
+	/* look for first buffer to map */
+	for (first = 0; first < VIDEO_MAX_FRAME; first++) {
+		if (NULL == q->bufs[first])
+			continue;
+
+		if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
+			continue;
+		if (q->bufs[first]->boff == offset)
+			break;
+	}
+	if (VIDEO_MAX_FRAME == first) {
+		dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n",
+			(vma->vm_pgoff << PAGE_SHIFT));
+		return -EINVAL;
+	}
+
+	/* create mapping + update buffer list */
+	map = q->bufs[first]->map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);
+	if (NULL == map)
+		return -ENOMEM;
+
+	map->start = vma->vm_start;
+	map->end   = vma->vm_end;
+	map->q     = q;
+
+	q->bufs[first]->baddr = vma->vm_start;
+
+	vma->vm_ops          = &videobuf_vm_ops;
+	vma->vm_flags       |= VM_DONTEXPAND | VM_RESERVED;
+	vma->vm_private_data = map;
+
+	mem=q->bufs[first]->priv;
+	BUG_ON (!mem);
+	MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+	/* Try to remap memory */
+	retval=remap_vmalloc_range(vma, mem->vmalloc,0);
+	if (retval<0) {
+		dprintk(1,"mmap: postponing remap_vmalloc_range\n");
+
+		mem->vma=kmalloc(sizeof(*vma),GFP_KERNEL);
+		if (!mem->vma) {
+			kfree(map);
+			q->bufs[first]->map=NULL;
+			return -ENOMEM;
+		}
+		memcpy(mem->vma,vma,sizeof(*vma));
+	}
+
+	dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
+		map,q,vma->vm_start,vma->vm_end,
+		(long int) q->bufs[first]->bsize,
+		vma->vm_pgoff,first);
+
+	videobuf_vm_open(vma);
+
+	return (0);
+}
+
+static int __videobuf_copy_to_user ( struct videobuf_queue *q,
+				char __user *data, size_t count,
+				int nonblocking )
+{
+	struct videbuf_vmalloc_memory *mem=q->read_buf->priv;
+	BUG_ON (!mem);
+	MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+	BUG_ON (!mem->vmalloc);
+
+	/* copy to userspace */
+	if (count > q->read_buf->size - q->read_off)
+		count = q->read_buf->size - q->read_off;
+
+	if (copy_to_user(data, mem->vmalloc+q->read_off, count))
+		return -EFAULT;
+
+	return count;
+}
+
+static int __videobuf_copy_stream ( struct videobuf_queue *q,
+				char __user *data, size_t count, size_t pos,
+				int vbihack, int nonblocking )
+{
+	unsigned int  *fc;
+	struct videbuf_vmalloc_memory *mem=q->read_buf->priv;
+	BUG_ON (!mem);
+	MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+	if (vbihack) {
+		/* dirty, undocumented hack -- pass the frame counter
+			* within the last four bytes of each vbi data block.
+			* We need that one to maintain backward compatibility
+			* to all vbi decoding software out there ... */
+		fc  = (unsigned int*)mem->vmalloc;
+		fc += (q->read_buf->size>>2) -1;
+		*fc = q->read_buf->field_count >> 1;
+		dprintk(1,"vbihack: %d\n",*fc);
+	}
+
+	/* copy stuff using the common method */
+	count = __videobuf_copy_to_user (q,data,count,nonblocking);
+
+	if ( (count==-EFAULT) && (0 == pos) )
+		return -EFAULT;
+
+	return count;
+}
+
+static struct videobuf_qtype_ops qops = {
+	.magic        = MAGIC_QTYPE_OPS,
+
+	.alloc        = __videobuf_alloc,
+	.iolock       = __videobuf_iolock,
+	.sync         = __videobuf_sync,
+	.mmap_free    = __videobuf_mmap_free,
+	.mmap_mapper  = __videobuf_mmap_mapper,
+	.copy_to_user = __videobuf_copy_to_user,
+	.copy_stream  = __videobuf_copy_stream,
+};
+
+void videobuf_queue_vmalloc_init(struct videobuf_queue* q,
+			 struct videobuf_queue_ops *ops,
+			 void *dev,
+			 spinlock_t *irqlock,
+			 enum v4l2_buf_type type,
+			 enum v4l2_field field,
+			 unsigned int msize,
+			 void *priv)
+{
+	videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
+				 priv, &qops);
+}
+
+EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
+
+void *videobuf_to_vmalloc (struct videobuf_buffer *buf)
+{
+	struct videbuf_vmalloc_memory *mem=buf->priv;
+	BUG_ON (!mem);
+	MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+	return mem->vmalloc;
+}
+EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
+
+void videobuf_vmalloc_free (struct videobuf_buffer *buf)
+{
+	struct videbuf_vmalloc_memory *mem=buf->priv;
+	BUG_ON (!mem);
+
+	MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+
+	vfree(mem->vmalloc);
+	mem->vmalloc=NULL;
+
+	return;
+}
+EXPORT_SYMBOL_GPL(videobuf_vmalloc_free);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index b876aca6..8d8e517 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -54,15 +54,14 @@
  *	sysfs stuff
  */
 
-static ssize_t show_name(struct class_device *cd, char *buf)
+static ssize_t show_name(struct device *cd,
+			 struct device_attribute *attr, char *buf)
 {
 	struct video_device *vfd = container_of(cd, struct video_device,
-								class_dev);
-	return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name);
+						class_dev);
+	return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name);
 }
 
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
-
 struct video_device *video_device_alloc(void)
 {
 	struct video_device *vfd;
@@ -76,7 +75,7 @@
 	kfree(vfd);
 }
 
-static void video_release(struct class_device *cd)
+static void video_release(struct device *cd)
 {
 	struct video_device *vfd = container_of(cd, struct video_device,
 								class_dev);
@@ -89,9 +88,15 @@
 	vfd->release(vfd);
 }
 
+static struct device_attribute video_device_attrs[] = {
+	__ATTR(name, S_IRUGO, show_name, NULL),
+	__ATTR_NULL
+};
+
 static struct class video_class = {
 	.name    = VIDEO_NAME,
-	.release = video_release,
+	.dev_attrs = video_device_attrs,
+	.dev_release = video_release,
 };
 
 /*
@@ -448,7 +453,7 @@
 	if (cmd == VIDIOCGMBUF) {
 		struct video_mbuf *p=arg;
 
-		memset(p,0,sizeof(p));
+		memset(p, 0, sizeof(*p));
 
 		if (!vfd->vidiocgmbuf)
 			return ret;
@@ -1753,22 +1758,16 @@
 	/* sysfs class */
 	memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev));
 	if (vfd->dev)
-		vfd->class_dev.dev = vfd->dev;
+		vfd->class_dev.parent = vfd->dev;
 	vfd->class_dev.class       = &video_class;
 	vfd->class_dev.devt        = MKDEV(VIDEO_MAJOR, vfd->minor);
-	sprintf(vfd->class_dev.class_id, "%s%d", name_base, i - base);
-	ret = class_device_register(&vfd->class_dev);
+	sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base);
+	ret = device_register(&vfd->class_dev);
 	if (ret < 0) {
-		printk(KERN_ERR "%s: class_device_register failed\n",
+		printk(KERN_ERR "%s: device_register failed\n",
 		       __FUNCTION__);
 		goto fail_minor;
 	}
-	ret = class_device_create_file(&vfd->class_dev, &class_device_attr_name);
-	if (ret < 0) {
-		printk(KERN_ERR "%s: class_device_create_file 'name' failed\n",
-		       __FUNCTION__);
-		goto fail_classdev;
-	}
 
 #if 1
 	/* needed until all drivers are fixed */
@@ -1779,8 +1778,6 @@
 #endif
 	return 0;
 
-fail_classdev:
-	class_device_unregister(&vfd->class_dev);
 fail_minor:
 	mutex_lock(&videodev_lock);
 	video_device[vfd->minor] = NULL;
@@ -1804,7 +1801,7 @@
 		panic("videodev: bad unregister");
 
 	video_device[vfd->minor]=NULL;
-	class_device_unregister(&vfd->class_dev);
+	device_unregister(&vfd->class_dev);
 	mutex_unlock(&videodev_lock);
 }
 
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 0c658b7..9a03dc8 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -28,7 +28,6 @@
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/moduleparam.h>
 #include <linux/time.h>
 #include <linux/version.h>
 
@@ -2077,12 +2076,10 @@
 	init_waitqueue_entry(&wait, current);
 	/* add ourselves into wait queue */
 	add_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait);
-	/* and set current state */
-	set_current_state(TASK_INTERRUPTIBLE);
 
 	/* to ensure that schedule_timeout will return immediately
-	 * if VINO interrupt was triggred meanwhile */
-	schedule_timeout(HZ / 10);
+	 * if VINO interrupt was triggered meanwhile */
+	schedule_timeout_interruptible(msecs_to_jiffies(100));
 
 	if (signal_pending(current))
 		err = -EINTR;
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 3ef4d01..b532aa2 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -25,6 +25,7 @@
 #include <linux/pci.h>
 #include <linux/random.h>
 #include <linux/version.h>
+#include <linux/mutex.h>
 #include <linux/videodev2.h>
 #include <linux/dma-mapping.h>
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -32,7 +33,7 @@
 #include <linux/videodev.h>
 #endif
 #include <linux/interrupt.h>
-#include <media/video-buf.h>
+#include <media/videobuf-vmalloc.h>
 #include <media/v4l2-common.h>
 #include <linux/kthread.h>
 #include <linux/highmem.h>
@@ -144,10 +145,6 @@
 	struct videobuf_buffer vb;
 
 	struct vivi_fmt        *fmt;
-
-#ifdef CONFIG_VIVI_SCATTER
-	struct sg_to_addr      *to_addr;
-#endif
 };
 
 struct vivi_dmaqueue {
@@ -168,12 +165,11 @@
 struct vivi_dev {
 	struct list_head           vivi_devlist;
 
-	struct semaphore           lock;
+	struct mutex               lock;
 
 	int                        users;
 
 	/* various device info */
-	unsigned int               resources;
 	struct video_device        vfd;
 
 	struct vivi_dmaqueue       vidq;
@@ -232,91 +228,25 @@
 #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
 #define TSTAMP_MIN_X 64
 
-#ifdef CONFIG_VIVI_SCATTER
-static void prep_to_addr(struct sg_to_addr to_addr[],
-			 struct videobuf_buffer *vb)
-{
-	int i, pos=0;
-
-	for (i=0;i<vb->dma.nr_pages;i++) {
-		to_addr[i].sg=&vb->dma.sglist[i];
-		to_addr[i].pos=pos;
-		pos += vb->dma.sglist[i].length;
-	}
-}
-
-static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
-{
-	int p1=0,p2=pages-1,p3=pages/2;
-
-	/* Sanity test */
-	BUG_ON (pos>=to_addr[p2].pos+to_addr[p2].sg->length);
-
-	while (p1+1<p2) {
-		if (pos < to_addr[p3].pos) {
-			p2=p3;
-		} else {
-			p1=p3;
-		}
-		p3=(p1+p2)/2;
-	}
-	if (pos >= to_addr[p2].pos)
-		p1=p2;
-
-	return (p1);
-}
-#endif
-
-#ifdef CONFIG_VIVI_SCATTER
-static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
-		     int hmax, int line, char *timestr)
-#else
 static void gen_line(char *basep,int inipos,int wmax,
-		     int hmax, int line, char *timestr)
-#endif
+		     int hmax, int line, int count, char *timestr)
 {
 	int  w,i,j,pos=inipos,y;
 	char *p,*s;
 	u8   chr,r,g,b,color;
-#ifdef CONFIG_VIVI_SCATTER
-	int pgpos,oldpg;
-	char *basep;
-	struct page *pg;
-
-	unsigned long flags;
-	spinlock_t spinlock;
-
-	spin_lock_init(&spinlock);
-
-	/* Get first addr pointed to pixel position */
-	oldpg=get_addr_pos(pos,pages,to_addr);
-	pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT);
-	spin_lock_irqsave(&spinlock,flags);
-	basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset;
-#endif
 
 	/* We will just duplicate the second pixel at the packet */
 	wmax/=2;
 
 	/* Generate a standard color bar pattern */
 	for (w=0;w<wmax;w++) {
-		r=bars[w*7/wmax][0];
-		g=bars[w*7/wmax][1];
-		b=bars[w*7/wmax][2];
+		int colorpos=((w+count)*8/(wmax+1)) % 8;
+		r=bars[colorpos][0];
+		g=bars[colorpos][1];
+		b=bars[colorpos][2];
 
 		for (color=0;color<4;color++) {
-#ifdef CONFIG_VIVI_SCATTER
-			pgpos=get_addr_pos(pos,pages,to_addr);
-			if (pgpos!=oldpg) {
-				pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT);
-				kunmap_atomic(basep, KM_BOUNCE_READ);
-				basep= kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[pgpos].sg->offset;
-				oldpg=pgpos;
-			}
-			p=basep+pos-to_addr[pgpos].pos;
-#else
 			p=basep+pos;
-#endif
 
 			switch (color) {
 				case 0:
@@ -361,23 +291,7 @@
 
 				pos=inipos+j*2;
 				for (color=0;color<4;color++) {
-#ifdef CONFIG_VIVI_SCATTER
-					pgpos=get_addr_pos(pos,pages,to_addr);
-					if (pgpos!=oldpg) {
-						pg=pfn_to_page(sg_dma_address(
-								to_addr[pgpos].sg)
-								>> PAGE_SHIFT);
-						kunmap_atomic(basep,
-								KM_BOUNCE_READ);
-						basep= kmap_atomic(pg,
-							KM_BOUNCE_READ)+
-							to_addr[pgpos].sg->offset;
-						oldpg=pgpos;
-					}
-					p=basep+pos-to_addr[pgpos].pos;
-#else
 					p=basep+pos;
-#endif
 
 					y=TO_Y(r,g,b);
 
@@ -402,12 +316,7 @@
 
 
 end:
-#ifdef CONFIG_VIVI_SCATTER
-	kunmap_atomic(basep, KM_BOUNCE_READ);
-	spin_unlock_irqrestore(&spinlock,flags);
-#else
 	return;
-#endif
 }
 static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
 {
@@ -415,47 +324,27 @@
 	int hmax  = buf->vb.height;
 	int wmax  = buf->vb.width;
 	struct timeval ts;
-#ifdef CONFIG_VIVI_SCATTER
-	struct sg_to_addr *to_addr=buf->to_addr;
-	struct videobuf_buffer *vb=&buf->vb;
-#else
-	char *tmpbuf;
-#endif
+	char *tmpbuf = kmalloc(wmax*2,GFP_KERNEL);
+	void *vbuf=videobuf_to_vmalloc (&buf->vb);
+	/* FIXME: move to dev struct */
+	static int mv_count=0;
 
-#ifdef CONFIG_VIVI_SCATTER
-	/* Test if DMA mapping is ready */
-	if (!sg_dma_address(&vb->dma.sglist[0]))
+	if (!tmpbuf)
 		return;
 
-	prep_to_addr(to_addr,vb);
-
-	/* Check if there is enough memory */
-	BUG_ON(buf->vb.dma.nr_pages << PAGE_SHIFT < (buf->vb.width*buf->vb.height)*2);
-#else
-	if (buf->vb.dma.varea) {
-		tmpbuf=kmalloc (wmax*2, GFP_KERNEL);
-	} else {
-		tmpbuf=buf->vb.dma.vmalloc;
-	}
-
-#endif
-
 	for (h=0;h<hmax;h++) {
-#ifdef CONFIG_VIVI_SCATTER
-		gen_line(to_addr,pos,vb->dma.nr_pages,wmax,hmax,h,dev->timestr);
-#else
-		if (buf->vb.dma.varea) {
-			gen_line(tmpbuf,0,wmax,hmax,h,dev->timestr);
-			/* FIXME: replacing to __copy_to_user */
-			if (copy_to_user(buf->vb.dma.varea+pos,tmpbuf,wmax*2)!=0)
-				dprintk(2,"vivifill copy_to_user failed.\n");
-		} else {
-			gen_line(tmpbuf,pos,wmax,hmax,h,dev->timestr);
-		}
-#endif
+		gen_line(tmpbuf,0,wmax,hmax,h,mv_count,
+			 dev->timestr);
+		/* FIXME: replacing to __copy_to_user */
+		if (copy_to_user(vbuf+pos,tmpbuf,wmax*2)!=0)
+			dprintk(2,"vivifill copy_to_user failed.\n");
 		pos += wmax*2;
 	}
 
+	mv_count++;
+
+	kfree(tmpbuf);
+
 	/* Updates stream time */
 
 	dev->us+=jiffies_to_usecs(jiffies-dev->jiffies);
@@ -478,7 +367,7 @@
 			dev->h,dev->m,dev->s,(dev->us+500)/1000);
 
 	dprintk(2,"vivifill at %s: Buffer 0x%08lx size= %d\n",dev->timestr,
-			(unsigned long)buf->vb.dma.varea,pos);
+			(unsigned long)tmpbuf,pos);
 
 	/* Advice that buffer was filled */
 	buf->vb.state = STATE_DONE;
@@ -618,7 +507,6 @@
 static int restart_video_queue(struct vivi_dmaqueue *dma_q)
 {
 	struct vivi_buffer *buf, *prev;
-	struct list_head *item;
 
 	dprintk(1,"%s dma_q=0x%08lx\n",__FUNCTION__,(unsigned long)dma_q);
 
@@ -632,9 +520,7 @@
 //		vivi_start_thread(dma_q);
 
 		/* cancel all outstanding capture / vbi requests */
-		list_for_each(item,&dma_q->active) {
-			buf = list_entry(item, struct vivi_buffer, vb.queue);
-
+		list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) {
 			list_del(&buf->vb.queue);
 			buf->vb.state = STATE_ERROR;
 			wake_up(&buf->vb.done);
@@ -706,8 +592,12 @@
 
 	if (0 == *count)
 		*count = 32;
+
 	while (*size * *count > vid_limit * 1024 * 1024)
 		(*count)--;
+
+	dprintk(1,"%s, count=%d, size=%d\n",__FUNCTION__,*count, *size);
+
 	return 0;
 }
 
@@ -718,15 +608,8 @@
 	if (in_interrupt())
 		BUG();
 
-#ifdef CONFIG_VIVI_SCATTER
-	/*FIXME: Maybe a spinlock is required here */
-	kfree(buf->to_addr);
-	buf->to_addr=NULL;
-#endif
-
 	videobuf_waiton(&buf->vb,0,0);
-	videobuf_dma_unmap(vq, &buf->vb.dma);
-	videobuf_dma_free(&buf->vb.dma);
+	videobuf_vmalloc_free(&buf->vb);
 	buf->vb.state = STATE_NEEDS_INIT;
 }
 
@@ -740,7 +623,7 @@
 	struct vivi_buffer *buf = container_of(vb,struct vivi_buffer,vb);
 	int rc, init_buffer = 0;
 
-//	dprintk(1,"%s, field=%d\n",__FUNCTION__,field);
+	dprintk(1,"%s, field=%d\n",__FUNCTION__,field);
 
 	BUG_ON(NULL == fh->fmt);
 	if (fh->width  < 48 || fh->width  > norm_maxw() ||
@@ -768,12 +651,6 @@
 
 	buf->vb.state = STATE_PREPARED;
 
-#ifdef CONFIG_VIVI_SCATTER
-	if (NULL == (buf->to_addr = kmalloc(sizeof(*buf->to_addr) * vb->dma.nr_pages,GFP_KERNEL))) {
-		rc=-ENOMEM;
-		goto fail;
-	}
-#endif
 	return 0;
 
 fail:
@@ -838,88 +715,14 @@
 	free_buffer(vq,buf);
 }
 
-#ifdef CONFIG_VIVI_SCATTER
-static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents,
-		       int direction)
-{
-	int i;
-
-	dprintk(1,"%s, number of pages=%d\n",__FUNCTION__,nents);
-	BUG_ON(direction == DMA_NONE);
-
-	for (i = 0; i < nents; i++ ) {
-		BUG_ON(!sg[i].page);
-
-		sg_dma_address(&sg[i]) = page_to_phys(sg[i].page) + sg[i].offset;
-	}
-
-	return nents;
-}
-
-static int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
-			 int direction)
-{
-	dprintk(1,"%s\n",__FUNCTION__);
-	return 0;
-}
-
-static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages,
-			    int direction)
-{
-//	dprintk(1,"%s\n",__FUNCTION__);
-
-//	flush_write_buffers();
-	return 0;
-}
-#endif
-
 static struct videobuf_queue_ops vivi_video_qops = {
 	.buf_setup      = buffer_setup,
 	.buf_prepare    = buffer_prepare,
 	.buf_queue      = buffer_queue,
 	.buf_release    = buffer_release,
-
-	/* Non-pci handling routines */
-//	.vb_map_sg      = vivi_map_sg,
-//	.vb_dma_sync_sg = vivi_dma_sync_sg,
-//	.vb_unmap_sg    = vivi_unmap_sg,
 };
 
 /* ------------------------------------------------------------------
-	IOCTL handling
-   ------------------------------------------------------------------*/
-
-
-static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
-{
-	/* is it free? */
-	down(&dev->lock);
-	if (dev->resources) {
-		/* no, someone else uses it */
-		up(&dev->lock);
-		return 0;
-	}
-	/* it's free, grab it */
-	dev->resources =1;
-	dprintk(1,"res: get\n");
-	up(&dev->lock);
-	return 1;
-}
-
-static int res_locked(struct vivi_dev *dev)
-{
-	return (dev->resources);
-}
-
-static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
-{
-	down(&dev->lock);
-	dev->resources = 0;
-	dprintk(1,"res: put\n");
-	up(&dev->lock);
-}
-
-/* ------------------------------------------------------------------
 	IOCTL vidioc handling
    ------------------------------------------------------------------*/
 static int vidioc_querycap (struct file *file, void  *priv,
@@ -979,8 +782,7 @@
 	field = f->fmt.pix.field;
 
 	if (field == V4L2_FIELD_ANY) {
-//		field=V4L2_FIELD_INTERLACED;
-		field=V4L2_FIELD_SEQ_TB;
+		field=V4L2_FIELD_INTERLACED;
 	} else if (V4L2_FIELD_INTERLACED != field) {
 		dprintk(1,"Field type invalid.\n");
 		return -EINVAL;
@@ -1058,57 +860,33 @@
 static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
 {
 	struct vivi_fh  *fh=priv;
-	struct videobuf_queue *q=&fh->vb_vidq;
-	struct v4l2_requestbuffers req;
-	unsigned int i;
-	int ret;
 
-	req.type   = q->type;
-	req.count  = 8;
-	req.memory = V4L2_MEMORY_MMAP;
-	ret = videobuf_reqbufs(q,&req);
-	if (ret < 0)
-		return (ret);
-
-	mbuf->frames = req.count;
-	mbuf->size   = 0;
-	for (i = 0; i < mbuf->frames; i++) {
-		mbuf->offsets[i]  = q->bufs[i]->boff;
-		mbuf->size       += q->bufs[i]->bsize;
-	}
-	return (0);
+	return videobuf_cgmbuf (&fh->vb_vidq, mbuf, 8);
 }
 #endif
 
 static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
 {
 	struct vivi_fh  *fh=priv;
-	struct vivi_dev *dev    = fh->dev;
 
 	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 	if (i != fh->type)
 		return -EINVAL;
 
-	if (!res_get(dev,fh))
-		return -EBUSY;
-	return (videobuf_streamon(&fh->vb_vidq));
+	return videobuf_streamon(&fh->vb_vidq);
 }
 
 static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
 {
 	struct vivi_fh  *fh=priv;
-	struct vivi_dev *dev    = fh->dev;
 
 	if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
 		return -EINVAL;
 	if (i != fh->type)
 		return -EINVAL;
 
-	videobuf_streamoff(&fh->vb_vidq);
-	res_free(dev,fh);
-
-	return (0);
+	return videobuf_streamoff(&fh->vb_vidq);
 }
 
 static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *i)
@@ -1201,31 +979,25 @@
 static int vivi_open(struct inode *inode, struct file *file)
 {
 	int minor = iminor(inode);
-	struct vivi_dev *h,*dev = NULL;
+	struct vivi_dev *dev;
 	struct vivi_fh *fh;
-	struct list_head *list;
-	enum v4l2_buf_type type = 0;
 	int i;
 
 	printk(KERN_DEBUG "vivi: open called (minor=%d)\n",minor);
 
-	list_for_each(list,&vivi_devlist) {
-		h = list_entry(list, struct vivi_dev, vivi_devlist);
-		if (h->vfd.minor == minor) {
-			dev  = h;
-			type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		}
-	}
-	if (NULL == dev)
-		return -ENODEV;
+	list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
+		if (dev->vfd.minor == minor)
+			goto found;
+	return -ENODEV;
+found:
 
 
 
 	/* If more than one user, mutex should be added */
 	dev->users++;
 
-	dprintk(1,"open minor=%d type=%s users=%d\n",
-				minor,v4l2_type_names[type],dev->users);
+	dprintk(1, "open minor=%d type=%s users=%d\n", minor,
+		v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
 
 	/* allocate + initialize per filehandle data */
 	fh = kzalloc(sizeof(*fh),GFP_KERNEL);
@@ -1260,19 +1032,11 @@
 	sprintf(dev->timestr,"%02d:%02d:%02d:%03d",
 			dev->h,dev->m,dev->s,(dev->us+500)/1000);
 
-#ifdef CONFIG_VIVI_SCATTER
-	videobuf_queue_init(&fh->vb_vidq,VIDEOBUF_DMA_SCATTER, &vivi_video_qops,
+	videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops,
 			NULL, NULL,
 			fh->type,
 			V4L2_FIELD_INTERLACED,
 			sizeof(struct vivi_buffer),fh);
-#else
-	videobuf_queue_init(&fh->vb_vidq, &vivi_video_qops,
-			NULL, NULL,
-			fh->type,
-			V4L2_FIELD_INTERLACED,
-			sizeof(struct vivi_buffer),fh);
-#endif
 
 	return 0;
 }
@@ -1283,9 +1047,7 @@
 	struct vivi_fh        *fh = file->private_data;
 
 	if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		if (res_locked(fh->dev))
-			return -EBUSY;
-		return videobuf_read_one(&fh->vb_vidq, data, count, ppos,
+		return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
 					file->f_flags & O_NONBLOCK);
 	}
 	return 0;
@@ -1295,31 +1057,14 @@
 vivi_poll(struct file *file, struct poll_table_struct *wait)
 {
 	struct vivi_fh        *fh = file->private_data;
-	struct vivi_buffer    *buf;
+	struct videobuf_queue *q = &fh->vb_vidq;
 
 	dprintk(1,"%s\n",__FUNCTION__);
 
 	if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
 		return POLLERR;
 
-	if (res_get(fh->dev,fh)) {
-		dprintk(1,"poll: mmap interface\n");
-		/* streaming capture */
-		if (list_empty(&fh->vb_vidq.stream))
-			return POLLERR;
-		buf = list_entry(fh->vb_vidq.stream.next,struct vivi_buffer,vb.stream);
-	} else {
-		dprintk(1,"poll: read() interface\n");
-		/* read() capture */
-		buf = (struct vivi_buffer*)fh->vb_vidq.read_buf;
-		if (NULL == buf)
-			return POLLERR;
-	}
-	poll_wait(file, &buf->vb.done, wait);
-	if (buf->vb.state == STATE_DONE ||
-	    buf->vb.state == STATE_ERROR)
-		return POLLIN|POLLRDNORM;
-	return 0;
+	return videobuf_poll_stream(file, q, wait);
 }
 
 static int vivi_release(struct inode *inode, struct file *file)
@@ -1367,7 +1112,7 @@
 	.read           = vivi_read,
 	.poll		= vivi_poll,
 	.ioctl          = video_ioctl2, /* V4L2 ioctl handler */
-	.mmap		= vivi_mmap,
+	.mmap           = vivi_mmap,
 	.llseek         = no_llseek,
 };
 
@@ -1423,7 +1168,7 @@
 	init_waitqueue_head(&dev->vidq.wq);
 
 	/* initialize locks */
-	init_MUTEX(&dev->lock);
+	mutex_init(&dev->lock);
 
 	dev->vidq.timeout.function = vivi_vid_timeout;
 	dev->vidq.timeout.data     = (unsigned long)dev;
diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c
new file mode 100644
index 0000000..63002e0
--- /dev/null
+++ b/drivers/media/video/vp27smpx.c
@@ -0,0 +1,212 @@
+/*
+ * vp27smpx - driver version 0.0.1
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Based on a tvaudio patch from Takahiro Adachi <tadachi@tadachi-net.com>
+ * and Kazuhiko Kawakami <kazz-0@mail.goo.ne.jp>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+
+MODULE_DESCRIPTION("vp27smpx driver");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static unsigned short normal_i2c[] = { 0xb6 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+struct vp27smpx_state {
+	int radio;
+	u32 audmode;
+};
+
+static void vp27smpx_set_audmode(struct i2c_client *client, u32 audmode)
+{
+	struct vp27smpx_state *state = i2c_get_clientdata(client);
+	u8 data[3] = { 0x00, 0x00, 0x04 };
+
+	switch (audmode) {
+		case V4L2_TUNER_MODE_MONO:
+		case V4L2_TUNER_MODE_LANG1:
+			break;
+		case V4L2_TUNER_MODE_STEREO:
+		case V4L2_TUNER_MODE_LANG1_LANG2:
+			data[1] = 0x01;
+			break;
+		case V4L2_TUNER_MODE_LANG2:
+			data[1] = 0x02;
+			break;
+	}
+
+	if (i2c_master_send(client, data, sizeof(data)) != sizeof(data)) {
+		v4l_err(client, "%s: I/O error setting audmode\n", client->name);
+	}
+	else {
+		state->audmode = audmode;
+	}
+}
+
+static int vp27smpx_command(struct i2c_client *client, unsigned int cmd,
+			  void *arg)
+{
+	struct vp27smpx_state *state = i2c_get_clientdata(client);
+	struct v4l2_tuner *vt = arg;
+
+	switch (cmd) {
+	case AUDC_SET_RADIO:
+		state->radio = 1;
+		break;
+
+	case VIDIOC_S_STD:
+		state->radio = 0;
+		break;
+
+	case VIDIOC_S_TUNER:
+		if (!state->radio)
+			vp27smpx_set_audmode(client, vt->audmode);
+		break;
+
+	case VIDIOC_G_TUNER:
+		if (state->radio)
+			break;
+		vt->audmode = state->audmode;
+		vt->capability = V4L2_TUNER_CAP_STEREO |
+			V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
+		vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+		break;
+
+	case VIDIOC_G_CHIP_IDENT:
+		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_VP27SMPX, 0);
+
+	case VIDIOC_LOG_STATUS:
+		v4l_info(client, "Audio Mode: %u%s\n", state->audmode,
+				state->radio ? " (Radio)" : "");
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static struct i2c_driver i2c_driver;
+
+static int vp27smpx_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *client;
+	struct vp27smpx_state *state;
+
+	/* Check if the adapter supports the needed features */
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		return 0;
+
+	client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (client == 0)
+		return -ENOMEM;
+
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &i2c_driver;
+	snprintf(client->name, sizeof(client->name) - 1, "vp27smpx");
+
+	v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+
+	state = kzalloc(sizeof(struct vp27smpx_state), GFP_KERNEL);
+	if (state == NULL) {
+		kfree(client);
+		return -ENOMEM;
+	}
+	state->audmode = V4L2_TUNER_MODE_STEREO;
+	i2c_set_clientdata(client, state);
+
+	/* initialize vp27smpx */
+	vp27smpx_set_audmode(client, state->audmode);
+	i2c_attach_client(client);
+
+	return 0;
+}
+
+static int vp27smpx_probe(struct i2c_adapter *adapter)
+{
+	if (adapter->class & I2C_CLASS_TV_ANALOG)
+		return i2c_probe(adapter, &addr_data, vp27smpx_attach);
+	return 0;
+}
+
+static int vp27smpx_detach(struct i2c_client *client)
+{
+	struct vp27smpx_state *state = i2c_get_clientdata(client);
+	int err;
+
+	err = i2c_detach_client(client);
+	if (err) {
+		return err;
+	}
+	kfree(state);
+	kfree(client);
+
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver = {
+	.driver = {
+		.name = "vp27smpx",
+	},
+	.id             = I2C_DRIVERID_VP27SMPX,
+	.attach_adapter = vp27smpx_probe,
+	.detach_client  = vp27smpx_detach,
+	.command        = vp27smpx_command,
+};
+
+
+static int __init vp27smpx_init_module(void)
+{
+	return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit vp27smpx_cleanup_module(void)
+{
+	i2c_del_driver(&i2c_driver);
+}
+
+module_init(vp27smpx_init_module);
+module_exit(vp27smpx_cleanup_module);
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
index 8f31613..5a1b5f5 100644
--- a/drivers/media/video/w9968cf.c
+++ b/drivers/media/video/w9968cf.c
@@ -42,7 +42,6 @@
 #include <asm/page.h>
 #include <asm/uaccess.h>
 #include <linux/page-flags.h>
-#include <linux/moduleparam.h>
 
 #include "w9968cf.h"
 #include "w9968cf_decoder.h"
@@ -2680,7 +2679,7 @@
 
 	/* This the only safe way to prevent race conditions with disconnect */
 	if (!down_read_trylock(&w9968cf_disconnect))
-		return -ERESTARTSYS;
+		return -EAGAIN;
 
 	cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
 
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
index 8f6741a..1bf4cbe 100644
--- a/drivers/media/video/wm8739.c
+++ b/drivers/media/video/wm8739.c
@@ -321,12 +321,14 @@
 
 static int wm8739_detach(struct i2c_client *client)
 {
+	struct wm8739_state *state = i2c_get_clientdata(client);
 	int err;
 
 	err = i2c_detach_client(client);
 	if (err)
 		return err;
 
+	kfree(state);
 	kfree(client);
 	return 0;
 }
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index 4df5d30..9f7e894 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -222,12 +222,14 @@
 
 static int wm8775_detach(struct i2c_client *client)
 {
+	struct wm8775_state *state = i2c_get_clientdata(client);
 	int err;
 
 	err = i2c_detach_client(client);
 	if (err) {
 		return err;
 	}
+	kfree(state);
 	kfree(client);
 
 	return 0;
diff --git a/drivers/media/video/zc0301/Kconfig b/drivers/media/video/zc0301/Kconfig
index 47cd93f..edb0029 100644
--- a/drivers/media/video/zc0301/Kconfig
+++ b/drivers/media/video/zc0301/Kconfig
@@ -1,6 +1,6 @@
 config USB_ZC0301
 	tristate "USB ZC0301[P] Image Processor and Control Chip support"
-	depends on VIDEO_V4L1
+	depends on VIDEO_V4L2
 	---help---
 	  Say Y here if you want support for cameras based on the ZC0301 or
 	  ZC0301P Image Processors and Control Chips.
diff --git a/drivers/media/video/zc0301/zc0301.h b/drivers/media/video/zc0301/zc0301.h
index 710f12e..a2de50e 100644
--- a/drivers/media/video/zc0301/zc0301.h
+++ b/drivers/media/video/zc0301/zc0301.h
@@ -36,6 +36,7 @@
 #include <linux/rwsem.h>
 #include <linux/stddef.h>
 #include <linux/string.h>
+#include <linux/kref.h>
 
 #include "zc0301_sensor.h"
 
@@ -98,7 +99,7 @@
 	u16 frame_timeout;
 };
 
-static DECLARE_RWSEM(zc0301_disconnect);
+static DECLARE_RWSEM(zc0301_dev_lock);
 
 struct zc0301_device {
 	struct video_device* v4ldev;
@@ -121,12 +122,14 @@
 
 	struct zc0301_module_param module_param;
 
+	struct kref kref;
 	enum zc0301_dev_state state;
 	u8 users;
 
-	struct mutex dev_mutex, fileop_mutex;
+	struct completion probe;
+	struct mutex open_mutex, fileop_mutex;
 	spinlock_t queue_lock;
-	wait_queue_head_t open, wait_frame, wait_stream;
+	wait_queue_head_t wait_open, wait_frame, wait_stream;
 };
 
 /*****************************************************************************/
@@ -156,8 +159,8 @@
 		else if ((level) == 2)                                        \
 			dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
 		else if ((level) >= 3)                                        \
-			dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
-				 __FUNCTION__, __LINE__ , ## args);           \
+			dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n",   \
+				 __FILE__, __FUNCTION__, __LINE__ , ## args); \
 	}                                                                     \
 } while (0)
 #	define KDBG(level, fmt, args...)                                      \
@@ -166,8 +169,8 @@
 		if ((level) == 1 || (level) == 2)                             \
 			pr_info("zc0301: " fmt "\n", ## args);                \
 		else if ((level) == 3)                                        \
-			pr_debug("zc0301: [%s:%d] " fmt "\n", __FUNCTION__,   \
-				 __LINE__ , ## args);                         \
+			pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__,   \
+				 __FUNCTION__, __LINE__ , ## args);           \
 	}                                                                     \
 } while (0)
 #	define V4LDBG(level, name, cmd)                                       \
@@ -183,8 +186,8 @@
 
 #undef PDBG
 #define PDBG(fmt, args...)                                                    \
-dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
-	 __FUNCTION__, __LINE__ , ## args)
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__,   \
+	 __LINE__ , ## args)
 
 #undef PDBGG
 #define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index f112055..08a93c3 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -26,7 +26,6 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
-#include <linux/moduleparam.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/device.h>
@@ -49,11 +48,11 @@
 
 #define ZC0301_MODULE_NAME    "V4L2 driver for ZC0301[P] "                    \
 			      "Image Processor and Control Chip"
-#define ZC0301_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
+#define ZC0301_MODULE_AUTHOR  "(C) 2006-2007 Luca Risolia"
 #define ZC0301_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
 #define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.07"
-#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 7)
+#define ZC0301_MODULE_VERSION "1:1.10"
+#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 10)
 
 /*****************************************************************************/
 
@@ -573,7 +572,8 @@
 	int err = 0;
 
 	if (!(cam->state & DEV_INITIALIZED)) {
-		init_waitqueue_head(&cam->open);
+		mutex_init(&cam->open_mutex);
+		init_waitqueue_head(&cam->wait_open);
 		qctrl = s->qctrl;
 		rect = &(s->cropcap.defrect);
 		cam->compression.quality = ZC0301_COMPRESSION_QUALITY;
@@ -634,59 +634,73 @@
 	return 0;
 }
 
+/*****************************************************************************/
 
-static void zc0301_release_resources(struct zc0301_device* cam)
+static void zc0301_release_resources(struct kref *kref)
 {
+	struct zc0301_device *cam = container_of(kref, struct zc0301_device,
+						 kref);
 	DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
 	video_set_drvdata(cam->v4ldev, NULL);
 	video_unregister_device(cam->v4ldev);
+	usb_put_dev(cam->usbdev);
 	kfree(cam->control_buffer);
+	kfree(cam);
 }
 
-/*****************************************************************************/
 
 static int zc0301_open(struct inode* inode, struct file* filp)
 {
 	struct zc0301_device* cam;
 	int err = 0;
 
-	/*
-	   This is the only safe way to prevent race conditions with
-	   disconnect
-	*/
-	if (!down_read_trylock(&zc0301_disconnect))
-		return -ERESTARTSYS;
+	if (!down_read_trylock(&zc0301_dev_lock))
+		return -EAGAIN;
 
 	cam = video_get_drvdata(video_devdata(filp));
 
-	if (mutex_lock_interruptible(&cam->dev_mutex)) {
-		up_read(&zc0301_disconnect);
+	if (wait_for_completion_interruptible(&cam->probe)) {
+		up_read(&zc0301_dev_lock);
 		return -ERESTARTSYS;
 	}
 
+	kref_get(&cam->kref);
+
+	if (mutex_lock_interruptible(&cam->open_mutex)) {
+		kref_put(&cam->kref, zc0301_release_resources);
+		up_read(&zc0301_dev_lock);
+		return -ERESTARTSYS;
+	}
+
+	if (cam->state & DEV_DISCONNECTED) {
+		DBG(1, "Device not present");
+		err = -ENODEV;
+		goto out;
+	}
+
 	if (cam->users) {
 		DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
+		DBG(3, "Simultaneous opens are not supported");
 		if ((filp->f_flags & O_NONBLOCK) ||
 		    (filp->f_flags & O_NDELAY)) {
 			err = -EWOULDBLOCK;
 			goto out;
 		}
-		mutex_unlock(&cam->dev_mutex);
-		err = wait_event_interruptible_exclusive(cam->open,
-						  cam->state & DEV_DISCONNECTED
+		DBG(2, "A blocking open() has been requested. Wait for the "
+		       "device to be released...");
+		up_read(&zc0301_dev_lock);
+		err = wait_event_interruptible_exclusive(cam->wait_open,
+						(cam->state & DEV_DISCONNECTED)
 							 || !cam->users);
-		if (err) {
-			up_read(&zc0301_disconnect);
-			return err;
-		}
+		down_read(&zc0301_dev_lock);
+		if (err)
+			goto out;
 		if (cam->state & DEV_DISCONNECTED) {
-			up_read(&zc0301_disconnect);
-			return -ENODEV;
+			err = -ENODEV;
+			goto out;
 		}
-		mutex_lock(&cam->dev_mutex);
 	}
 
-
 	if (cam->state & DEV_MISCONFIGURED) {
 		err = zc0301_init(cam);
 		if (err) {
@@ -711,36 +725,32 @@
 	DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
 
 out:
-	mutex_unlock(&cam->dev_mutex);
-	up_read(&zc0301_disconnect);
+	mutex_unlock(&cam->open_mutex);
+	if (err)
+		kref_put(&cam->kref, zc0301_release_resources);
+	up_read(&zc0301_dev_lock);
 	return err;
 }
 
 
 static int zc0301_release(struct inode* inode, struct file* filp)
 {
-	struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
+	struct zc0301_device* cam;
 
-	mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
+	down_write(&zc0301_dev_lock);
+
+	cam = video_get_drvdata(video_devdata(filp));
 
 	zc0301_stop_transfer(cam);
-
 	zc0301_release_buffers(cam);
-
-	if (cam->state & DEV_DISCONNECTED) {
-		zc0301_release_resources(cam);
-		usb_put_dev(cam->usbdev);
-		mutex_unlock(&cam->dev_mutex);
-		kfree(cam);
-		return 0;
-	}
-
 	cam->users--;
-	wake_up_interruptible_nr(&cam->open, 1);
+	wake_up_interruptible_nr(&cam->wait_open, 1);
 
 	DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
 
-	mutex_unlock(&cam->dev_mutex);
+	kref_put(&cam->kref, zc0301_release_resources);
+
+	up_write(&zc0301_dev_lock);
 
 	return 0;
 }
@@ -775,7 +785,7 @@
 		DBG(3, "Close and open the device again to choose the read "
 		       "method");
 		mutex_unlock(&cam->fileop_mutex);
-		return -EINVAL;
+		return -EBUSY;
 	}
 
 	if (cam->io == IO_NONE) {
@@ -953,7 +963,12 @@
 		return -EIO;
 	}
 
-	if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
+	if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
+		mutex_unlock(&cam->fileop_mutex);
+		return -EACCES;
+	}
+
+	if (cam->io != IO_MMAP ||
 	    size != PAGE_ALIGN(cam->frame[0].buf.length)) {
 		mutex_unlock(&cam->fileop_mutex);
 		return -EINVAL;
@@ -984,7 +999,6 @@
 
 	vma->vm_ops = &zc0301_vm_ops;
 	vma->vm_private_data = &cam->frame[i];
-
 	zc0301_vm_open(vma);
 
 	mutex_unlock(&cam->fileop_mutex);
@@ -1211,7 +1225,7 @@
 			if (cam->frame[i].vma_use_count) {
 				DBG(3, "VIDIOC_S_CROP failed. "
 				       "Unmap the buffers first.");
-				return -EINVAL;
+				return -EBUSY;
 			}
 
 	if (!s->set_crop) {
@@ -1434,7 +1448,7 @@
 			if (cam->frame[i].vma_use_count) {
 				DBG(3, "VIDIOC_S_FMT failed. "
 				       "Unmap the buffers first.");
-				return -EINVAL;
+				return -EBUSY;
 			}
 
 	if (cam->stream == STREAM_ON)
@@ -1544,14 +1558,14 @@
 	if (cam->io == IO_READ) {
 		DBG(3, "Close and open the device again to choose the mmap "
 		       "I/O method");
-		return -EINVAL;
+		return -EBUSY;
 	}
 
 	for (i = 0; i < cam->nbuffers; i++)
 		if (cam->frame[i].vma_use_count) {
 			DBG(3, "VIDIOC_REQBUFS failed. "
 			       "Previous buffers are still mapped.");
-			return -EINVAL;
+			return -EBUSY;
 		}
 
 	if (cam->stream == STREAM_ON)
@@ -1699,9 +1713,6 @@
 	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
 		return -EINVAL;
 
-	if (list_empty(&cam->inqueue))
-		return -EINVAL;
-
 	cam->stream = STREAM_ON;
 
 	DBG(3, "Stream on");
@@ -1949,8 +1960,6 @@
 		goto fail;
 	}
 
-	mutex_init(&cam->dev_mutex);
-
 	DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
 	       "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
 
@@ -1982,7 +1991,7 @@
 	cam->v4ldev->release = video_device_release;
 	video_set_drvdata(cam->v4ldev, cam);
 
-	mutex_lock(&cam->dev_mutex);
+	init_completion(&cam->probe);
 
 	err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
 				    video_nr[dev_nr]);
@@ -1992,7 +2001,7 @@
 			DBG(1, "Free /dev/videoX node not found");
 		video_nr[dev_nr] = -1;
 		dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
-		mutex_unlock(&cam->dev_mutex);
+		complete_all(&cam->probe);
 		goto fail;
 	}
 
@@ -2004,8 +2013,10 @@
 	dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
 
 	usb_set_intfdata(intf, cam);
+	kref_init(&cam->kref);
+	usb_get_dev(cam->usbdev);
 
-	mutex_unlock(&cam->dev_mutex);
+	complete_all(&cam->probe);
 
 	return 0;
 
@@ -2022,40 +2033,31 @@
 
 static void zc0301_usb_disconnect(struct usb_interface* intf)
 {
-	struct zc0301_device* cam = usb_get_intfdata(intf);
+	struct zc0301_device* cam;
 
-	if (!cam)
-		return;
+	down_write(&zc0301_dev_lock);
 
-	down_write(&zc0301_disconnect);
-
-	mutex_lock(&cam->dev_mutex);
+	cam = usb_get_intfdata(intf);
 
 	DBG(2, "Disconnecting %s...", cam->v4ldev->name);
 
-	wake_up_interruptible_all(&cam->open);
-
 	if (cam->users) {
 		DBG(2, "Device /dev/video%d is open! Deregistration and "
-		       "memory deallocation are deferred on close.",
+		       "memory deallocation are deferred.",
 		    cam->v4ldev->minor);
 		cam->state |= DEV_MISCONFIGURED;
 		zc0301_stop_transfer(cam);
 		cam->state |= DEV_DISCONNECTED;
 		wake_up_interruptible(&cam->wait_frame);
 		wake_up(&cam->wait_stream);
-		usb_get_dev(cam->usbdev);
-	} else {
+	} else
 		cam->state |= DEV_DISCONNECTED;
-		zc0301_release_resources(cam);
-	}
 
-	mutex_unlock(&cam->dev_mutex);
+	wake_up_interruptible_all(&cam->wait_open);
 
-	if (!cam->users)
-		kfree(cam);
+	kref_put(&cam->kref, zc0301_release_resources);
 
-	up_write(&zc0301_disconnect);
+	up_write(&zc0301_dev_lock);
 }
 
 
diff --git a/drivers/media/video/zc0301/zc0301_pas202bcb.c b/drivers/media/video/zc0301/zc0301_pas202bcb.c
index 3efb92a..24b0dfb 100644
--- a/drivers/media/video/zc0301/zc0301_pas202bcb.c
+++ b/drivers/media/video/zc0301/zc0301_pas202bcb.c
@@ -327,6 +327,7 @@
 		.height = 480,
 		.pixelformat = V4L2_PIX_FMT_JPEG,
 		.priv = 8,
+		.colorspace = V4L2_COLORSPACE_JPEG,
 	},
 };
 
diff --git a/drivers/media/video/zc0301/zc0301_pb0330.c b/drivers/media/video/zc0301/zc0301_pb0330.c
index 5784b1d..9519aba 100644
--- a/drivers/media/video/zc0301/zc0301_pb0330.c
+++ b/drivers/media/video/zc0301/zc0301_pb0330.c
@@ -157,6 +157,7 @@
 		.height = 480,
 		.pixelformat = V4L2_PIX_FMT_JPEG,
 		.priv = 8,
+		.colorspace = V4L2_COLORSPACE_JPEG,
 	},
 };
 
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
index 44e82cf..70fe6fc 100644
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ b/drivers/media/video/zc0301/zc0301_sensor.h
@@ -23,7 +23,7 @@
 #define _ZC0301_SENSOR_H_
 
 #include <linux/usb.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
 #include <linux/device.h>
 #include <linux/stddef.h>
 #include <linux/errno.h>
diff --git a/drivers/media/video/zoran.h b/drivers/media/video/zoran.h
index 8fb4a34..937c4a6 100644
--- a/drivers/media/video/zoran.h
+++ b/drivers/media/video/zoran.h
@@ -240,11 +240,16 @@
 
 struct zoran_format {
 	char *name;
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
 	int palette;
+#endif
+#ifdef CONFIG_VIDEO_V4L2
 	__u32 fourcc;
 	int colorspace;
+#endif
 	int depth;
 	__u32 flags;
+	__u32 vfespfr;
 };
 /* flags */
 #define ZORAN_FORMAT_COMPRESSED 1<<0
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index 73162a3..48da36a 100644
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -64,15 +64,15 @@
 extern const struct zoran_format zoran_formats[];
 
 static int card[BUZ_MAX] = { -1, -1, -1, -1 };
-module_param_array(card, int, NULL, 0);
+module_param_array(card, int, NULL, 0444);
 MODULE_PARM_DESC(card, "The type of card");
 
 static int encoder[BUZ_MAX] = { -1, -1, -1, -1 };
-module_param_array(encoder, int, NULL, 0);
+module_param_array(encoder, int, NULL, 0444);
 MODULE_PARM_DESC(encoder, "i2c TV encoder");
 
 static int decoder[BUZ_MAX] = { -1, -1, -1, -1 };
-module_param_array(decoder, int, NULL, 0);
+module_param_array(decoder, int, NULL, 0444);
 MODULE_PARM_DESC(decoder, "i2c TV decoder");
 
 /*
@@ -84,29 +84,31 @@
  */
 
 static unsigned long vidmem = 0;	/* Video memory base address */
-module_param(vidmem, ulong, 0);
+module_param(vidmem, ulong, 0444);
+MODULE_PARM_DESC(vidmem, "Default video memory base address");
 
 /*
    Default input and video norm at startup of the driver.
 */
 
-static int default_input = 0;	/* 0=Composite, 1=S-Video */
-module_param(default_input, int, 0);
+static unsigned int default_input = 0;	/* 0=Composite, 1=S-Video */
+module_param(default_input, uint, 0444);
 MODULE_PARM_DESC(default_input,
 		 "Default input (0=Composite, 1=S-Video, 2=Internal)");
 
 static int default_mux = 1;	/* 6 Eyes input selection */
-module_param(default_mux, int, 0);
+module_param(default_mux, int, 0644);
 MODULE_PARM_DESC(default_mux,
 		 "Default 6 Eyes mux setting (Input selection)");
 
 static int default_norm = 0;	/* 0=PAL, 1=NTSC 2=SECAM */
-module_param(default_norm, int, 0);
+module_param(default_norm, int, 0444);
 MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)");
 
-static int video_nr = -1;	/* /dev/videoN, -1 for autodetect */
-module_param(video_nr, int, 0);
-MODULE_PARM_DESC(video_nr, "video device number");
+/* /dev/videoN, -1 for autodetect */
+static int video_nr[BUZ_MAX] = {-1, -1, -1, -1};
+module_param_array(video_nr, int, NULL, 0444);
+MODULE_PARM_DESC(video_nr, "video device number (-1=Auto)");
 
 /*
    Number and size of grab buffers for Video 4 Linux
@@ -127,28 +129,27 @@
 
 int v4l_nbufs = 2;
 int v4l_bufsize = 128;		/* Everybody should be able to work with this setting */
-module_param(v4l_nbufs, int, 0);
+module_param(v4l_nbufs, int, 0644);
 MODULE_PARM_DESC(v4l_nbufs, "Maximum number of V4L buffers to use");
-module_param(v4l_bufsize, int, 0);
+module_param(v4l_bufsize, int, 0644);
 MODULE_PARM_DESC(v4l_bufsize, "Maximum size per V4L buffer (in kB)");
 
 int jpg_nbufs = 32;
 int jpg_bufsize = 512;		/* max size for 100% quality full-PAL frame */
-module_param(jpg_nbufs, int, 0);
+module_param(jpg_nbufs, int, 0644);
 MODULE_PARM_DESC(jpg_nbufs, "Maximum number of JPG buffers to use");
-module_param(jpg_bufsize, int, 0);
+module_param(jpg_bufsize, int, 0644);
 MODULE_PARM_DESC(jpg_bufsize, "Maximum size per JPG buffer (in kB)");
 
 int pass_through = 0;		/* 1=Pass through TV signal when device is not used */
 				/* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */
-module_param(pass_through, int, 0);
+module_param(pass_through, int, 0644);
 MODULE_PARM_DESC(pass_through,
 		 "Pass TV signal through to TV-out when idling");
 
-static int debug = 1;
-int *zr_debug = &debug;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "Debug level (0-4)");
+int zr36067_debug = 1;
+module_param_named(debug, zr36067_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-5)");
 
 MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver");
 MODULE_AUTHOR("Serguei Miridonov");
@@ -161,12 +162,6 @@
 };
 MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl);
 
-#define dprintk(num, format, args...) \
-	do { \
-		if (*zr_debug >= num) \
-			printk(format, ##args); \
-	} while (0)
-
 int zoran_num;			/* number of Buzs in use */
 struct zoran zoran[BUZ_MAX];
 
@@ -1075,7 +1070,7 @@
 	if (timeout) {
 		dprintk(1, ": time spent: %d\n", 1 * HZ - timeout);
 	}
-	if (*zr_debug > 1)
+	if (zr36067_debug > 1)
 		print_interrupts(zr);
 	btwrite(icr, ZR36057_ICR);
 }
@@ -1121,7 +1116,14 @@
 		zr->timing = zr->card.tvn[zr->norm];
 	}
 
-	zr->input = default_input = (default_input ? 1 : 0);
+	if (default_input > zr->card.inputs-1) {
+		dprintk(1,
+			KERN_WARNING
+			"%s: default_input value %d out of range (0-%d)\n",
+			ZR_DEVNAME(zr), default_input, zr->card.inputs-1);
+		default_input = 0;
+	}
+	zr->input = default_input;
 
 	/* Should the following be reset at every open ? */
 	zr->hue = 32768;
@@ -1153,12 +1155,12 @@
 	 */
 	memcpy(zr->video_dev, &zoran_template, sizeof(zoran_template));
 	strcpy(zr->video_dev->name, ZR_DEVNAME(zr));
-	err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr);
+	err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr[zr->id]);
 	if (err < 0)
 		goto exit_unregister;
 
 	zoran_init_hardware(zr);
-	if (*zr_debug > 2)
+	if (zr36067_debug > 2)
 		detect_guest_activity(zr);
 	test_interrupts(zr);
 	if (!pass_through) {
@@ -1620,7 +1622,7 @@
 	}
 
 	/* random nonsense */
-	dprintk(5, KERN_DEBUG "Jotti is een held!\n");
+	dprintk(6, KERN_DEBUG "Jotti is een held!\n");
 
 	/* some mainboards might not do PCI-PCI data transfer well */
 	if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL|PCIPCI_ALIMAGIK)) {
diff --git a/drivers/media/video/zoran_card.h b/drivers/media/video/zoran_card.h
index ad997c3..8444ca0 100644
--- a/drivers/media/video/zoran_card.h
+++ b/drivers/media/video/zoran_card.h
@@ -30,6 +30,14 @@
 #ifndef __ZORAN_CARD_H__
 #define __ZORAN_CARD_H__
 
+extern int zr36067_debug;
+
+#define dprintk(num, format, args...) \
+	do { \
+		if (zr36067_debug >= num) \
+			printk(format, ##args); \
+	} while (0)
+
 /* Anybody who uses more than four? */
 #define BUZ_MAX 4
 extern int zoran_num;
diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
index b075276..68c7c50 100644
--- a/drivers/media/video/zoran_device.c
+++ b/drivers/media/video/zoran_device.c
@@ -52,6 +52,7 @@
 #include "videocodec.h"
 #include "zoran.h"
 #include "zoran_device.h"
+#include "zoran_card.h"
 
 #define IRQ_MASK ( ZR36057_ISR_GIRQ0 | \
 		   ZR36057_ISR_GIRQ1 | \
@@ -59,14 +60,6 @@
 
 extern const struct zoran_format zoran_formats[];
 
-extern int *zr_debug;
-
-#define dprintk(num, format, args...) \
-	do { \
-		if (*zr_debug >= num) \
-			printk(format, ##args); \
-	} while (0)
-
 static int lml33dpath = 0;	/* 1 will use digital path in capture
 				 * mode instead of analog. It can be
 				 * used for picture adjustments using
@@ -76,7 +69,7 @@
 				 * load on Bt819 input, there will be
 				 * some image imperfections */
 
-module_param(lml33dpath, bool, 0);
+module_param(lml33dpath, bool, 0644);
 MODULE_PARM_DESC(lml33dpath,
 		 "Use digital path capture mode (on LML33 cards)");
 
@@ -174,7 +167,7 @@
 static void
 dump_guests (struct zoran *zr)
 {
-	if (*zr_debug > 2) {
+	if (zr36067_debug > 2) {
 		int i, guest[8];
 
 		for (i = 1; i < 8; i++) {	// Don't read jpeg codec here
@@ -429,8 +422,6 @@
 	reg |= (HorDcm << ZR36057_VFESPFR_HorDcm);
 	reg |= (VerDcm << ZR36057_VFESPFR_VerDcm);
 	reg |= (DispMode << ZR36057_VFESPFR_DispMode);
-	if (format->palette != VIDEO_PALETTE_YUV422 && format->palette != VIDEO_PALETTE_YUYV)
-		reg |= ZR36057_VFESPFR_LittleEndian;
 	/* RJ: I don't know, why the following has to be the opposite
 	 * of the corresponding ZR36060 setting, but only this way
 	 * we get the correct colors when uncompressing to the screen  */
@@ -439,36 +430,6 @@
 	if (zr->norm != VIDEO_MODE_NTSC)
 		reg |= ZR36057_VFESPFR_ExtFl;	// NEEDED!!!!!!! Wolfgang
 	reg |= ZR36057_VFESPFR_TopField;
-	switch (format->palette) {
-
-	case VIDEO_PALETTE_YUYV:
-	case VIDEO_PALETTE_YUV422:
-		reg |= ZR36057_VFESPFR_YUV422;
-		break;
-
-	case VIDEO_PALETTE_RGB555:
-		reg |= ZR36057_VFESPFR_RGB555 | ZR36057_VFESPFR_ErrDif;
-		break;
-
-	case VIDEO_PALETTE_RGB565:
-		reg |= ZR36057_VFESPFR_RGB565 | ZR36057_VFESPFR_ErrDif;
-		break;
-
-	case VIDEO_PALETTE_RGB24:
-		reg |= ZR36057_VFESPFR_RGB888 | ZR36057_VFESPFR_Pack24;
-		break;
-
-	case VIDEO_PALETTE_RGB32:
-		reg |= ZR36057_VFESPFR_RGB888;
-		break;
-
-	default:
-		dprintk(1,
-			KERN_INFO "%s: set_vfe() - unknown color_fmt=%x\n",
-			ZR_DEVNAME(zr), format->palette);
-		return;
-
-	}
 	if (HorDcm >= 48) {
 		reg |= 3 << ZR36057_VFESPFR_HFilter;	/* 5 tap filter */
 	} else if (HorDcm >= 32) {
@@ -476,6 +437,7 @@
 	} else if (HorDcm >= 16) {
 		reg |= 1 << ZR36057_VFESPFR_HFilter;	/* 3 tap filter */
 	}
+	reg |= format->vfespfr;
 	btwrite(reg, ZR36057_VFESPFR);
 
 	/* display configuration */
@@ -651,11 +613,17 @@
 		     int           mode)
 {
 	if (mode) {
-		if (btread(ZR36057_VSSFGR) &
-		    (ZR36057_VSSFGR_SnapShot | ZR36057_VSSFGR_FrameGrab))
+		/* We only check SnapShot and not FrameGrab here.  SnapShot==1
+		 * means a capture is already in progress, but FrameGrab==1
+		 * doesn't necessary mean that.  It's more correct to say a 1
+		 * to 0 transition indicates a capture completed.  If a
+		 * capture is pending when capturing is tuned off, FrameGrab
+		 * will be stuck at 1 until capturing is turned back on.
+		 */
+		if (btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot)
 			dprintk(1,
 				KERN_WARNING
-				"%s: zr36057_set_memgrab(1) with SnapShot or FrameGrab on!?\n",
+				"%s: zr36057_set_memgrab(1) with SnapShot on!?\n",
 				ZR_DEVNAME(zr));
 
 		/* switch on VSync interrupts */
@@ -672,11 +640,12 @@
 
 		zr->v4l_memgrab_active = 1;
 	} else {
-		zr->v4l_memgrab_active = 0;
-
 		/* switch off VSync interrupts */
 		btand(~zr->card.vsync_int, ZR36057_ICR);	// SW
 
+		zr->v4l_memgrab_active = 0;
+		zr->v4l_grab_frame = NO_GRAB_ACTIVE;
+
 		/* reenable grabbing to screen if it was running */
 		if (zr->v4l_overlay_active) {
 			zr36057_overlay(zr, 1);
@@ -1295,7 +1264,7 @@
 		zr->num_errors++;
 
 		/* Report error */
-		if (*zr_debug > 1 && zr->num_errors <= 8) {
+		if (zr36067_debug > 1 && zr->num_errors <= 8) {
 			long frame;
 			frame =
 			    zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME];
@@ -1555,7 +1524,7 @@
 
 			if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
 			    zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) {
-				if (*zr_debug > 1 &&
+				if (zr36067_debug > 1 &&
 				    (!zr->frame_num || zr->JPEG_error)) {
 					printk(KERN_INFO
 					       "%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n",
@@ -1592,7 +1561,7 @@
 						    zr->JPEG_missed;
 				}
 
-				if (*zr_debug > 2 && zr->frame_num < 6) {
+				if (zr36067_debug > 2 && zr->frame_num < 6) {
 					int i;
 					printk("%s: seq=%ld stat_com:",
 					       ZR_DEVNAME(zr), zr->jpg_seq_num);
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index cf0ed6c..1c14fa2 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -99,106 +99,106 @@
 
 #include <asm/byteorder.h>
 
+#if defined(CONFIG_VIDEO_V4L2) && defined(CONFIG_VIDEO_V4L1_COMPAT)
+#define ZFMT(pal, fcc, cs) \
+	.palette = (pal), .fourcc = (fcc), .colorspace = (cs)
+#elif defined(CONFIG_VIDEO_V4L2)
+#define ZFMT(pal, fcc, cs) \
+	.fourcc = (fcc), .colorspace = (cs)
+#else
+#define ZFMT(pal, fcc, cs) \
+	.palette = (pal)
+#endif
+
 const struct zoran_format zoran_formats[] = {
 	{
-		.name = "15-bit RGB",
-		.palette = VIDEO_PALETTE_RGB555,
-#ifdef CONFIG_VIDEO_V4L2
-#ifdef __LITTLE_ENDIAN
-		.fourcc = V4L2_PIX_FMT_RGB555,
-#else
-		.fourcc = V4L2_PIX_FMT_RGB555X,
-#endif
-		.colorspace = V4L2_COLORSPACE_SRGB,
-#endif
+		.name = "15-bit RGB LE",
+		ZFMT(VIDEO_PALETTE_RGB555,
+		     V4L2_PIX_FMT_RGB555, V4L2_COLORSPACE_SRGB),
 		.depth = 15,
 		.flags = ZORAN_FORMAT_CAPTURE |
 			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif|
+			   ZR36057_VFESPFR_LittleEndian,
 	}, {
-		.name = "16-bit RGB",
-		.palette = VIDEO_PALETTE_RGB565,
-#ifdef CONFIG_VIDEO_V4L2
-#ifdef __LITTLE_ENDIAN
-		.fourcc = V4L2_PIX_FMT_RGB565,
-#else
-		.fourcc = V4L2_PIX_FMT_RGB565X,
-#endif
-		.colorspace = V4L2_COLORSPACE_SRGB,
-#endif
+		.name = "15-bit RGB BE",
+		ZFMT(-1,
+		     V4L2_PIX_FMT_RGB555X, V4L2_COLORSPACE_SRGB),
+		.depth = 15,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif,
+	}, {
+		.name = "16-bit RGB LE",
+		ZFMT(VIDEO_PALETTE_RGB565,
+		     V4L2_PIX_FMT_RGB565, V4L2_COLORSPACE_SRGB),
 		.depth = 16,
 		.flags = ZORAN_FORMAT_CAPTURE |
 			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif|
+			   ZR36057_VFESPFR_LittleEndian,
+	}, {
+		.name = "16-bit RGB BE",
+		ZFMT(-1,
+		     V4L2_PIX_FMT_RGB565, V4L2_COLORSPACE_SRGB),
+		.depth = 16,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif,
 	}, {
 		.name = "24-bit RGB",
-		.palette = VIDEO_PALETTE_RGB24,
-#ifdef CONFIG_VIDEO_V4L2
-#ifdef __LITTLE_ENDIAN
-		.fourcc = V4L2_PIX_FMT_BGR24,
-#else
-		.fourcc = V4L2_PIX_FMT_RGB24,
-#endif
-		.colorspace = V4L2_COLORSPACE_SRGB,
-#endif
+		ZFMT(VIDEO_PALETTE_RGB24,
+		     V4L2_PIX_FMT_BGR24, V4L2_COLORSPACE_SRGB),
 		.depth = 24,
 		.flags = ZORAN_FORMAT_CAPTURE |
 			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_Pack24,
 	}, {
-		.name = "32-bit RGB",
-		.palette = VIDEO_PALETTE_RGB32,
-#ifdef CONFIG_VIDEO_V4L2
-#ifdef __LITTLE_ENDIAN
-		.fourcc = V4L2_PIX_FMT_BGR32,
-#else
-		.fourcc = V4L2_PIX_FMT_RGB32,
-#endif
-		.colorspace = V4L2_COLORSPACE_SRGB,
-#endif
+		.name = "32-bit RGB LE",
+		ZFMT(VIDEO_PALETTE_RGB32,
+		     V4L2_PIX_FMT_BGR32, V4L2_COLORSPACE_SRGB),
 		.depth = 32,
 		.flags = ZORAN_FORMAT_CAPTURE |
 			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_LittleEndian,
+	}, {
+		.name = "32-bit RGB BE",
+		ZFMT(-1,
+		     V4L2_PIX_FMT_RGB32, V4L2_COLORSPACE_SRGB),
+		.depth = 32,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_RGB888,
 	}, {
 		.name = "4:2:2, packed, YUYV",
-		.palette = VIDEO_PALETTE_YUV422,
-#ifdef CONFIG_VIDEO_V4L2
-		.fourcc = V4L2_PIX_FMT_YUYV,
-		.colorspace = V4L2_COLORSPACE_SMPTE170M,
-#endif
+		ZFMT(VIDEO_PALETTE_YUV422,
+		     V4L2_PIX_FMT_YUYV, V4L2_COLORSPACE_SMPTE170M),
 		.depth = 16,
 		.flags = ZORAN_FORMAT_CAPTURE |
 			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_YUV422,
+	}, {
+		.name = "4:2:2, packed, UYVY",
+		ZFMT(VIDEO_PALETTE_UYVY,
+		     V4L2_PIX_FMT_UYVY, V4L2_COLORSPACE_SMPTE170M),
+		.depth = 16,
+		.flags = ZORAN_FORMAT_CAPTURE |
+			 ZORAN_FORMAT_OVERLAY,
+		.vfespfr = ZR36057_VFESPFR_YUV422|ZR36057_VFESPFR_LittleEndian,
 	}, {
 		.name = "Hardware-encoded Motion-JPEG",
-		.palette = -1,
-#ifdef CONFIG_VIDEO_V4L2
-		.fourcc = V4L2_PIX_FMT_MJPEG,
-		.colorspace = V4L2_COLORSPACE_SMPTE170M,
-#endif
+		ZFMT(-1,
+		     V4L2_PIX_FMT_MJPEG, V4L2_COLORSPACE_SMPTE170M),
 		.depth = 0,
 		.flags = ZORAN_FORMAT_CAPTURE |
 			 ZORAN_FORMAT_PLAYBACK |
 			 ZORAN_FORMAT_COMPRESSED,
 	}
 };
-static const int zoran_num_formats =
-    (sizeof(zoran_formats) / sizeof(struct zoran_format));
+#define NUM_FORMATS ARRAY_SIZE(zoran_formats)
 
 // RJ: Test only - want to test BUZ_USE_HIMEM even when CONFIG_BIGPHYS_AREA is defined
-#if !defined(CONFIG_BIGPHYS_AREA)
-//#undef CONFIG_BIGPHYS_AREA
-#define BUZ_USE_HIMEM
-#endif
 
-#if defined(CONFIG_BIGPHYS_AREA)
-#   include <linux/bigphysarea.h>
-#endif
-
-extern int *zr_debug;
-
-#define dprintk(num, format, args...) \
-	do { \
-		if (*zr_debug >= num) \
-			printk(format, ##args);	\
-	} while (0)
 
 extern int v4l_nbufs;
 extern int v4l_bufsize;
@@ -207,8 +207,8 @@
 extern int pass_through;
 
 static int lock_norm = 0;	/* 1=Don't change TV standard (norm) */
-module_param(lock_norm, int, 0);
-MODULE_PARM_DESC(lock_norm, "Users can't change norm");
+module_param(lock_norm, int, 0644);
+MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)");
 
 #ifdef CONFIG_VIDEO_V4L2
 	/* small helper function for calculating buffersizes for v4l2
@@ -250,7 +250,6 @@
  *   Linux with the necessary memory left over).
  */
 
-#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA)
 static unsigned long
 get_high_mem (unsigned long size)
 {
@@ -314,7 +313,6 @@
 
 	return hi_mem_ph;
 }
-#endif
 
 static int
 v4l_fbuffer_alloc (struct file *file)
@@ -323,9 +321,7 @@
 	struct zoran *zr = fh->zr;
 	int i, off;
 	unsigned char *mem;
-#if defined(BUZ_USE_HIMEM) && !defined(CONFIG_BIGPHYS_AREA)
 	unsigned long pmem = 0;
-#endif
 
 	/* we might have old buffers lying around... */
 	if (fh->v4l_buffers.ready_to_be_freed) {
@@ -343,10 +339,7 @@
 		if (fh->v4l_buffers.buffer_size <= MAX_KMALLOC_MEM) {
 			/* Use kmalloc */
 
-			mem =
-			    (unsigned char *) kmalloc(fh->v4l_buffers.
-						      buffer_size,
-						      GFP_KERNEL);
+			mem = kmalloc(fh->v4l_buffers.buffer_size, GFP_KERNEL);
 			if (mem == 0) {
 				dprintk(1,
 					KERN_ERR
@@ -369,39 +362,6 @@
 				ZR_DEVNAME(zr), i, (unsigned long) mem,
 				virt_to_bus(mem));
 		} else {
-#if defined(CONFIG_BIGPHYS_AREA)
-			/* Use bigphysarea_alloc_pages */
-
-			int n =
-			    (fh->v4l_buffers.buffer_size + PAGE_SIZE -
-			     1) / PAGE_SIZE;
-
-			mem =
-			    (unsigned char *) bigphysarea_alloc_pages(n, 0,
-								      GFP_KERNEL);
-			if (mem == 0) {
-				dprintk(1,
-					KERN_ERR
-					"%s: v4l_fbuffer_alloc() - bigphysarea_alloc_pages for V4L buf %d failed\n",
-					ZR_DEVNAME(zr), i);
-				v4l_fbuffer_free(file);
-				return -ENOBUFS;
-			}
-			fh->v4l_buffers.buffer[i].fbuffer = mem;
-			fh->v4l_buffers.buffer[i].fbuffer_phys =
-			    virt_to_phys(mem);
-			fh->v4l_buffers.buffer[i].fbuffer_bus =
-			    virt_to_bus(mem);
-			dprintk(4,
-				KERN_INFO
-				"%s: Bigphysarea frame %d mem 0x%x (bus: 0x%x)\n",
-				ZR_DEVNAME(zr), i, (unsigned) mem,
-				(unsigned) virt_to_bus(mem));
-
-			/* Zero out the allocated memory */
-			memset(fh->v4l_buffers.buffer[i].fbuffer, 0,
-			       fh->v4l_buffers.buffer_size);
-#elif defined(BUZ_USE_HIMEM)
 
 			/* Use high memory which has been left at boot time */
 
@@ -441,20 +401,6 @@
 				fh->v4l_buffers.buffer[i].fbuffer_bus =
 				    pmem + i * fh->v4l_buffers.buffer_size;
 			}
-#else
-			/* No bigphysarea present, usage of high memory disabled,
-			 * but user wants buffers of more than MAX_KMALLOC_MEM */
-			dprintk(1,
-				KERN_ERR
-				"%s: v4l_fbuffer_alloc() - no bigphysarea_patch present, usage of high memory disabled,\n",
-				ZR_DEVNAME(zr));
-			dprintk(1,
-				KERN_ERR
-				"%s: v4l_fbuffer_alloc() - sorry, could not allocate %d V4L buffers of size %d KB.\n",
-				ZR_DEVNAME(zr), fh->v4l_buffers.num_buffers,
-				fh->v4l_buffers.buffer_size >> 10);
-			return -ENOBUFS;
-#endif
 		}
 	}
 
@@ -485,11 +431,6 @@
 				ClearPageReserved(MAP_NR(mem + off));
 			kfree((void *) fh->v4l_buffers.buffer[i].fbuffer);
 		}
-#if defined(CONFIG_BIGPHYS_AREA)
-		else
-			bigphysarea_free_pages((void *) fh->v4l_buffers.
-					       buffer[i].fbuffer);
-#endif
 		fh->v4l_buffers.buffer[i].fbuffer = NULL;
 	}
 
@@ -831,13 +772,13 @@
 	struct zoran *zr = fh->zr;
 	int res = 0, i;
 
-	for (i = 0; i < zoran_num_formats; i++) {
+	for (i = 0; i < NUM_FORMATS; i++) {
 		if (zoran_formats[i].palette == mp->format &&
 		    zoran_formats[i].flags & ZORAN_FORMAT_CAPTURE &&
 		    !(zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED))
 			break;
 	}
-	if (i == zoran_num_formats || zoran_formats[i].depth == 0) {
+	if (i == NUM_FORMATS || zoran_formats[i].depth == 0) {
 		dprintk(1,
 			KERN_ERR
 			"%s: v4l_grab() - wrong bytes-per-pixel format\n",
@@ -1154,12 +1095,10 @@
 		frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
 
 	/* buffer should now be in BUZ_STATE_DONE */
-	if (*zr_debug > 0)
-		if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE)
-			dprintk(2,
-				KERN_ERR
-				"%s: jpg_sync() - internal state error\n",
-				ZR_DEVNAME(zr));
+	if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE)
+		dprintk(2,
+			KERN_ERR "%s: jpg_sync() - internal state error\n",
+			ZR_DEVNAME(zr));
 
 	*bs = zr->jpg_buffers.buffer[frame].bs;
 	bs->frame = frame;
@@ -1236,10 +1175,14 @@
 
 	/* v4l capture */
 	if (fh->v4l_buffers.active != ZORAN_FREE) {
+		long flags;
+
+		spin_lock_irqsave(&zr->spinlock, flags);
 		zr36057_set_memgrab(zr, 0);
 		zr->v4l_buffers.allocated = 0;
 		zr->v4l_buffers.active = fh->v4l_buffers.active =
 		    ZORAN_FREE;
+		spin_unlock_irqrestore(&zr->spinlock, flags);
 	}
 
 	/* v4l buffers */
@@ -1433,7 +1376,7 @@
 		/* disable interrupts */
 		btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR);
 
-		if (*zr_debug > 1)
+		if (zr36067_debug > 1)
 			print_interrupts(zr);
 
 		/* Overlay off */
@@ -2170,7 +2113,7 @@
 			vpict->colour, vpict->contrast, vpict->depth,
 			vpict->palette);
 
-		for (i = 0; i < zoran_num_formats; i++) {
+		for (i = 0; i < NUM_FORMATS; i++) {
 			const struct zoran_format *fmt = &zoran_formats[i];
 
 			if (fmt->palette != -1 &&
@@ -2179,7 +2122,7 @@
 			    fmt->depth == vpict->depth)
 				break;
 		}
-		if (i == zoran_num_formats) {
+		if (i == NUM_FORMATS) {
 			dprintk(1,
 				KERN_ERR
 				"%s: VIDIOCSPICT - Invalid palette %d\n",
@@ -2283,10 +2226,10 @@
 			ZR_DEVNAME(zr), vbuf->base, vbuf->width,
 			vbuf->height, vbuf->depth, vbuf->bytesperline);
 
-		for (i = 0; i < zoran_num_formats; i++)
+		for (i = 0; i < NUM_FORMATS; i++)
 			if (zoran_formats[i].depth == vbuf->depth)
 				break;
-		if (i == zoran_num_formats) {
+		if (i == NUM_FORMATS) {
 			dprintk(1,
 				KERN_ERR
 				"%s: VIDIOCSFBUF - invalid fbuf depth %d\n",
@@ -2735,14 +2678,14 @@
 			return -EINVAL;
 		}
 
-		for (i = 0; i < zoran_num_formats; i++) {
+		for (i = 0; i < NUM_FORMATS; i++) {
 			if (zoran_formats[i].flags & flag)
 				num++;
 			if (num == fmt->index)
 				break;
 		}
 		if (fmt->index < 0 /* late, but not too late */  ||
-		    i == zoran_num_formats)
+		    i == NUM_FORMATS)
 			return -EINVAL;
 
 		memset(fmt, 0, sizeof(*fmt));
@@ -2800,7 +2743,8 @@
 				fmt->fmt.pix.height =
 				    fh->v4l_settings.height;
 				fmt->fmt.pix.sizeimage =
-				    fh->v4l_buffers.buffer_size;
+				    fh->v4l_settings.bytesperline *
+				    fh->v4l_settings.height;
 				fmt->fmt.pix.pixelformat =
 				    fh->v4l_settings.format->fourcc;
 				fmt->fmt.pix.colorspace =
@@ -3004,11 +2948,11 @@
 			sfmtjpg_unlock_and_return:
 				mutex_unlock(&zr->resource_lock);
 			} else {
-				for (i = 0; i < zoran_num_formats; i++)
+				for (i = 0; i < NUM_FORMATS; i++)
 					if (fmt->fmt.pix.pixelformat ==
 					    zoran_formats[i].fourcc)
 						break;
-				if (i == zoran_num_formats) {
+				if (i == NUM_FORMATS) {
 					dprintk(1,
 						KERN_ERR
 						"%s: VIDIOC_S_FMT - unknown/unsupported format 0x%x (%4.4s)\n",
@@ -3047,8 +2991,9 @@
 
 				/* tell the user the
 				 * results/missing stuff */
-				fmt->fmt.pix.sizeimage = fh->v4l_buffers.buffer_size	/*zr->gbpl * zr->gheight */
-				    ;
+				fmt->fmt.pix.sizeimage =
+					fh->v4l_settings.height *
+					fh->v4l_settings.bytesperline;
 				if (BUZ_MAX_HEIGHT <
 				    (fh->v4l_settings.height * 2))
 					fmt->fmt.pix.field =
@@ -3116,10 +3061,10 @@
 			fb->fmt.bytesperline, fb->fmt.pixelformat,
 			(char *) &printformat);
 
-		for (i = 0; i < zoran_num_formats; i++)
+		for (i = 0; i < NUM_FORMATS; i++)
 			if (zoran_formats[i].fourcc == fb->fmt.pixelformat)
 				break;
-		if (i == zoran_num_formats) {
+		if (i == NUM_FORMATS) {
 			dprintk(1,
 				KERN_ERR
 				"%s: VIDIOC_S_FBUF - format=0x%x (%4.4s) not allowed\n",
@@ -3248,7 +3193,7 @@
 			"%s: VIDIOC_QUERYBUF - index=%d, type=%d\n",
 			ZR_DEVNAME(zr), buf->index, buf->type);
 
-		memset(buf, 0, sizeof(buf));
+		memset(buf, 0, sizeof(*buf));
 		buf->type = type;
 		buf->index = index;
 
@@ -3502,8 +3447,13 @@
 				goto strmoff_unlock_and_return;
 
 			/* unload capture */
-			if (zr->v4l_memgrab_active)
+			if (zr->v4l_memgrab_active) {
+				long flags;
+
+				spin_lock_irqsave(&zr->spinlock, flags);
 				zr36057_set_memgrab(zr, 0);
+				spin_unlock_irqrestore(&zr->spinlock, flags);
+			}
 
 			for (i = 0; i < fh->v4l_buffers.num_buffers; i++)
 				zr->v4l_buffers.buffer[i].state =
@@ -3767,11 +3717,11 @@
 		dprintk(3, KERN_DEBUG "%s: VIDIOC_S_STD - norm=0x%llx\n",
 			ZR_DEVNAME(zr), (unsigned long long)*std);
 
-		if (*std == V4L2_STD_PAL)
+		if ((*std & V4L2_STD_PAL) && !(*std & ~V4L2_STD_PAL))
 			norm = VIDEO_MODE_PAL;
-		else if (*std == V4L2_STD_NTSC)
+		else if ((*std & V4L2_STD_NTSC) && !(*std & ~V4L2_STD_NTSC))
 			norm = VIDEO_MODE_NTSC;
-		else if (*std == V4L2_STD_SECAM)
+		else if ((*std & V4L2_STD_SECAM) && !(*std & ~V4L2_STD_SECAM))
 			norm = VIDEO_MODE_SECAM;
 		else if (*std == V4L2_STD_ALL)
 			norm = VIDEO_MODE_AUTO;
@@ -4212,11 +4162,11 @@
 				   V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 				int i;
 
-				for (i = 0; i < zoran_num_formats; i++)
+				for (i = 0; i < NUM_FORMATS; i++)
 					if (zoran_formats[i].fourcc ==
 					    fmt->fmt.pix.pixelformat)
 						break;
-				if (i == zoran_num_formats) {
+				if (i == NUM_FORMATS) {
 					res = -EINVAL;
 					goto tryfmt_unlock_and_return;
 				}
@@ -4276,8 +4226,8 @@
 {
 	struct zoran_fh *fh = file->private_data;
 	struct zoran *zr = fh->zr;
-	wait_queue_head_t *queue = NULL;
 	int res = 0, frame;
+	unsigned long flags;
 
 	/* we should check whether buffers are ready to be synced on
 	 * (w/o waits - O_NONBLOCK) here
@@ -4291,51 +4241,58 @@
 
 	switch (fh->map_mode) {
 	case ZORAN_MAP_MODE_RAW:
-		if (fh->v4l_buffers.active == ZORAN_FREE ||
-		    zr->v4l_pend_head == zr->v4l_pend_tail) {
-			dprintk(1,
-				"%s: zoran_poll() - no buffers queued\n",
-				ZR_DEVNAME(zr));
-			res = POLLNVAL;
-			goto poll_unlock_and_return;
-		}
-		queue = &zr->v4l_capq;
-		frame = zr->v4l_pend[zr->v4l_pend_tail & V4L_MASK_FRAME];
-		poll_wait(file, queue, wait);
-		if (fh->v4l_buffers.buffer[frame].state == BUZ_STATE_DONE)
+		poll_wait(file, &zr->v4l_capq, wait);
+		frame = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME];
+
+		spin_lock_irqsave(&zr->spinlock, flags);
+		dprintk(3,
+			KERN_DEBUG
+			"%s: %s() raw - active=%c, sync_tail=%lu/%c, pend_tail=%lu, pend_head=%lu\n",
+			ZR_DEVNAME(zr), __FUNCTION__,
+			"FAL"[fh->v4l_buffers.active], zr->v4l_sync_tail,
+			"UPMD"[zr->v4l_buffers.buffer[frame].state],
+			zr->v4l_pend_tail, zr->v4l_pend_head);
+		/* Process is the one capturing? */
+		if (fh->v4l_buffers.active != ZORAN_FREE &&
+		    /* Buffer ready to DQBUF? */
+		    zr->v4l_buffers.buffer[frame].state == BUZ_STATE_DONE)
 			res = POLLIN | POLLRDNORM;
+		spin_unlock_irqrestore(&zr->spinlock, flags);
+
 		break;
 
 	case ZORAN_MAP_MODE_JPG_REC:
 	case ZORAN_MAP_MODE_JPG_PLAY:
-		if (fh->jpg_buffers.active == ZORAN_FREE ||
-		    zr->jpg_que_head == zr->jpg_que_tail) {
-			dprintk(1,
-				"%s: zoran_poll() - no buffers queued\n",
-				ZR_DEVNAME(zr));
-			res = POLLNVAL;
-			goto poll_unlock_and_return;
-		}
-		queue = &zr->jpg_capq;
+		poll_wait(file, &zr->jpg_capq, wait);
 		frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME];
-		poll_wait(file, queue, wait);
-		if (fh->jpg_buffers.buffer[frame].state == BUZ_STATE_DONE) {
+
+		spin_lock_irqsave(&zr->spinlock, flags);
+		dprintk(3,
+			KERN_DEBUG
+			"%s: %s() jpg - active=%c, que_tail=%lu/%c, que_head=%lu, dma=%lu/%lu\n",
+			ZR_DEVNAME(zr), __FUNCTION__,
+			"FAL"[fh->jpg_buffers.active], zr->jpg_que_tail,
+			"UPMD"[zr->jpg_buffers.buffer[frame].state],
+			zr->jpg_que_head, zr->jpg_dma_tail, zr->jpg_dma_head);
+		if (fh->jpg_buffers.active != ZORAN_FREE &&
+		    zr->jpg_buffers.buffer[frame].state == BUZ_STATE_DONE) {
 			if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC)
 				res = POLLIN | POLLRDNORM;
 			else
 				res = POLLOUT | POLLWRNORM;
 		}
+		spin_unlock_irqrestore(&zr->spinlock, flags);
+
 		break;
 
 	default:
 		dprintk(1,
+			KERN_ERR
 			"%s: zoran_poll() - internal error, unknown map_mode=%d\n",
 			ZR_DEVNAME(zr), fh->map_mode);
 		res = POLLNVAL;
-		goto poll_unlock_and_return;
 	}
 
-poll_unlock_and_return:
 	mutex_unlock(&zr->resource_lock);
 
 	return res;
@@ -4431,11 +4388,15 @@
 				mutex_lock(&zr->resource_lock);
 
 				if (fh->v4l_buffers.active != ZORAN_FREE) {
+					long flags;
+
+					spin_lock_irqsave(&zr->spinlock, flags);
 					zr36057_set_memgrab(zr, 0);
 					zr->v4l_buffers.allocated = 0;
 					zr->v4l_buffers.active =
 					    fh->v4l_buffers.active =
 					    ZORAN_FREE;
+					spin_unlock_irqrestore(&zr->spinlock, flags);
 				}
 				//v4l_fbuffer_free(file);
 				fh->v4l_buffers.allocated = 0;
diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c
index 446ae8d..328ed6e 100644
--- a/drivers/media/video/zoran_procfs.c
+++ b/drivers/media/video/zoran_procfs.c
@@ -48,14 +48,7 @@
 #include "videocodec.h"
 #include "zoran.h"
 #include "zoran_procfs.h"
-
-extern int *zr_debug;
-
-#define dprintk(num, format, args...) \
-	do { \
-		if (*zr_debug >= num) \
-			printk(format, ##args); \
-	} while (0)
+#include "zoran_card.h"
 
 #ifdef CONFIG_PROC_FS
 struct procfs_params_zr36067 {
diff --git a/drivers/media/video/zr36016.c b/drivers/media/video/zr36016.c
index 62f7758..dd08455 100644
--- a/drivers/media/video/zr36016.c
+++ b/drivers/media/video/zr36016.c
@@ -38,11 +38,11 @@
    #include<linux/videodev.h> */
 
 /* I/O commands, error codes */
-#include<asm/io.h>
+#include <asm/io.h>
 //#include<errno.h>
 
 /* v4l  API */
-#include<linux/videodev.h>
+#include <linux/videodev.h>
 
 /* headerfile of this module */
 #include"zr36016.h"
diff --git a/drivers/media/video/zr36050.c b/drivers/media/video/zr36050.c
index a6bbd12..9f622e0 100644
--- a/drivers/media/video/zr36050.c
+++ b/drivers/media/video/zr36050.c
@@ -38,14 +38,14 @@
    #include<linux/videodev.h> */
 
 /* I/O commands, error codes */
-#include<asm/io.h>
+#include <asm/io.h>
 //#include<errno.h>
 
 /* headerfile of this module */
-#include"zr36050.h"
+#include "zr36050.h"
 
 /* codec io API */
-#include"videocodec.h"
+#include "videocodec.h"
 
 /* it doesn't make sense to have more than 20 or so,
   just to prevent some unwanted loops */
diff --git a/drivers/media/video/zr36060.c b/drivers/media/video/zr36060.c
index 97c8f9b..1ef14fe 100644
--- a/drivers/media/video/zr36060.c
+++ b/drivers/media/video/zr36060.c
@@ -38,14 +38,14 @@
    #include<linux/videodev.h> */
 
 /* I/O commands, error codes */
-#include<asm/io.h>
+#include <asm/io.h>
 //#include<errno.h>
 
 /* headerfile of this module */
-#include"zr36060.h"
+#include "zr36060.h"
 
 /* codec io API */
-#include"videocodec.h"
+#include "videocodec.h"
 
 /* it doesn't make sense to have more than 20 or so,
   just to prevent some unwanted loops */
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index b5d3364..6f18925 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -92,6 +92,7 @@
 	{USB_DEVICE(0x0784, 0x0040), .driver_info = METHOD1 },
 	{USB_DEVICE(0x06d6, 0x0034), .driver_info = METHOD0 },
 	{USB_DEVICE(0x0a17, 0x0062), .driver_info = METHOD2 },
+	{USB_DEVICE(0x06d6, 0x003b), .driver_info = METHOD0 },
 	{}			/* Terminating entry */
 };
 
@@ -792,6 +793,7 @@
 {
 	struct usb_device *udev = interface_to_usbdev(intf);
 	struct zr364xx_camera *cam = NULL;
+	int err;
 
 	DBG("probing...");
 
@@ -799,12 +801,11 @@
 	info("model %04x:%04x detected", udev->descriptor.idVendor,
 	     udev->descriptor.idProduct);
 
-	if ((cam =
-	     kmalloc(sizeof(struct zr364xx_camera), GFP_KERNEL)) == NULL) {
+	cam = kzalloc(sizeof(struct zr364xx_camera), GFP_KERNEL);
+	if (cam == NULL) {
 		info("cam: out of memory !");
-		return -ENODEV;
+		return -ENOMEM;
 	}
-	memset(cam, 0x00, sizeof(struct zr364xx_camera));
 	/* save the init method used by this camera */
 	cam->method = id->driver_info;
 
@@ -812,7 +813,7 @@
 	if (cam->vdev == NULL) {
 		info("cam->vdev: out of memory !");
 		kfree(cam);
-		return -ENODEV;
+		return -ENOMEM;
 	}
 	memcpy(cam->vdev, &zr364xx_template, sizeof(zr364xx_template));
 	video_set_drvdata(cam->vdev, cam);
@@ -858,12 +859,13 @@
 	cam->brightness = 64;
 	mutex_init(&cam->lock);
 
-	if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1) == -1) {
+	err = video_register_device(cam->vdev, VFL_TYPE_GRABBER, -1);
+	if (err) {
 		info("video_register_device failed");
 		video_device_release(cam->vdev);
 		kfree(cam->buffer);
 		kfree(cam);
-		return -ENODEV;
+		return err;
 	}
 
 	usb_set_intfdata(intf, cam);
@@ -905,7 +907,7 @@
 static int __init zr364xx_init(void)
 {
 	int retval;
-	retval = usb_register(&zr364xx_driver) < 0;
+	retval = usb_register(&zr364xx_driver);
 	if (retval)
 		info("usb_register failed!");
 	else
diff --git a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig
index c88cc75..f55cc03 100644
--- a/drivers/message/fusion/Kconfig
+++ b/drivers/message/fusion/Kconfig
@@ -37,6 +37,7 @@
 	  LSIFC929
 	  LSIFC929X
 	  LSIFC929XL
+	  Brocade FC 410/420
 
 config FUSION_SAS
 	tristate "Fusion MPT ScsiHost drivers for SAS"
@@ -101,4 +102,18 @@
 
 	  If unsure whether you really want or need this, say N.
 
+config FUSION_LOGGING
+	bool "Fusion MPT logging facility"
+	depends on FUSION
+	---help---
+	  This turns on a logging facility that can be used to debug a number
+	  of Fusion MPT related problems.
+
+	  The debug level can be programmed on the fly via SysFS (hex values)
+
+	  echo [level] > /sys/class/scsi_host/host#/debug_level
+
+	  There are various debug levels that an be found in the source:
+	  file:drivers/message/fusion/mptdebug.h
+
 endmenu
diff --git a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile
index 6003b46..95c9532 100644
--- a/drivers/message/fusion/Makefile
+++ b/drivers/message/fusion/Makefile
@@ -1,39 +1,8 @@
 # Fusion MPT drivers; recognized debug defines...
-#  MPT general:
-#EXTRA_CFLAGS += -DMPT_DEBUG
-#EXTRA_CFLAGS += -DMPT_DEBUG_MSG_FRAME
-#EXTRA_CFLAGS += -DMPT_DEBUG_SG
-#EXTRA_CFLAGS += -DMPT_DEBUG_EVENTS
-#EXTRA_CFLAGS += -DMPT_DEBUG_VERBOSE_EVENTS
-#EXTRA_CFLAGS += -DMPT_DEBUG_INIT
-#EXTRA_CFLAGS += -DMPT_DEBUG_EXIT
-#EXTRA_CFLAGS += -DMPT_DEBUG_FAIL
-#EXTRA_CFLAGS += -DMPT_DEBUG_DV
-#EXTRA_CFLAGS += -DMPT_DEBUG_TM
-#EXTRA_CFLAGS += -DMPT_DEBUG_REPLY
 
-#
-# driver/module specifics...
-#
-#  For mptbase:
-#CFLAGS_mptbase.o += -DMPT_DEBUG_HANDSHAKE
-#CFLAGS_mptbase.o += -DMPT_DEBUG_CONFIG
-#CFLAGS_mptbase.o += -DMPT_DEBUG_DL
-#CFLAGS_mptbase.o += -DMPT_DEBUG_IRQ
-#CFLAGS_mptbase.o += -DMPT_DEBUG_RESET
-#
-#  For mptscsih:
-#CFLAGS_mptscsih.o += -DMPT_DEBUG_SCSI
-#
-#  For mptctl:
-#CFLAGS_mptctl.o += -DMPT_DEBUG_IOCTL
-#
-#  For mptfc:
-#CFLAGS_mptfc.o += -DMPT_DEBUG_FC
-
-#  For mptsas:
-#CFLAGS_mptsas.o += -DMPT_DEBUG_SAS
-#CFLAGS_mptsas.o += -DMPT_DEBUG_SAS_WIDE
+# enable verbose logging
+# CONFIG_FUSION_LOGGING needs to be enabled in Kconfig
+#EXTRA_CFLAGS += -DMPT_DEBUG_VERBOSE
 
 
 #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 5a10c87..414c109 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -87,6 +87,12 @@
 module_param(mpt_channel_mapping, int, 0);
 MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)");
 
+static int mpt_debug_level;
+static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
+module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
+		  &mpt_debug_level, 0600);
+MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h - (default=0)");
+
 #ifdef MFCNT
 static int mfcounter = 0;
 #define PRINT_MF_COUNT 20000
@@ -161,6 +167,7 @@
 static void 	mpt_read_ioc_pg_1(MPT_ADAPTER *ioc);
 static void 	mpt_read_ioc_pg_4(MPT_ADAPTER *ioc);
 static void	mpt_timer_expired(unsigned long data);
+static void	mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc);
 static int	SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch);
 static int	SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp);
 static int	mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag);
@@ -178,9 +185,7 @@
 
 //int		mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag);
 static int	ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *evReply, int *evHandlers);
-#ifdef MPT_DEBUG_REPLY
 static void	mpt_iocstatus_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf);
-#endif
 static void	mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info);
 static void	mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info);
 static void	mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info);
@@ -217,6 +222,19 @@
 	pci_write_config_word(pdev, PCI_COMMAND, command_reg);
 }
 
+static int mpt_set_debug_level(const char *val, struct kernel_param *kp)
+{
+	int ret = param_set_int(val, kp);
+	MPT_ADAPTER *ioc;
+
+	if (ret)
+		return ret;
+
+	list_for_each_entry(ioc, &ioc_list, list)
+		ioc->debug_level = mpt_debug_level;
+	return 0;
+}
+
 /*
  *  Process turbo (context) reply...
  */
@@ -228,7 +246,7 @@
 	int req_idx = 0;
 	int cb_idx;
 
-	dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n",
+	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got TURBO reply req_idx=%08x\n",
 				ioc->name, pa));
 
 	switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) {
@@ -311,9 +329,9 @@
 	cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx;
 	mf = MPT_INDEX_2_MFPTR(ioc, req_idx);
 
-	dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
+	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n",
 			ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function));
-	DBG_DUMP_REPLY_FRAME(mr)
+	DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mr)
 
 	 /*  Check/log IOC log info
 	 */
@@ -328,10 +346,8 @@
 			mpt_sas_log_info(ioc, log_info);
 	}
 
-#ifdef MPT_DEBUG_REPLY
 	if (ioc_stat & MPI_IOCSTATUS_MASK)
 		mpt_iocstatus_info(ioc, (u32)ioc_stat, mf);
-#endif
 
 	/*  Check for (valid) IO callback!  */
 	if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS ||
@@ -413,17 +429,17 @@
 	int freereq = 1;
 	u8 func;
 
-	dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name));
-
-#if defined(MPT_DEBUG_MSG_FRAME)
-	if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
-		dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
-		DBG_DUMP_REQUEST_FRAME_HDR(mf)
+	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply() called\n", ioc->name));
+#ifdef CONFIG_FUSION_LOGGING
+	if ((ioc->debug_level & MPT_DEBUG_MSG_FRAME) &&
+			!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) {
+		dmfprintk(ioc, printk(KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf));
+		DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)mf)
 	}
 #endif
 
 	func = reply->u.hdr.Function;
-	dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n",
+	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, Function=%02Xh\n",
 			ioc->name, func));
 
 	if (func == MPI_FUNCTION_EVENT_NOTIFICATION) {
@@ -434,7 +450,7 @@
 		results = ProcessEventNotification(ioc, pEvReply, &evHandlers);
 		if (results != evHandlers) {
 			/* CHECKME! Any special handling needed here? */
-			devtverboseprintk((MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
+			devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Called %d event handlers, sum results = %d\n",
 					ioc->name, evHandlers, results));
 		}
 
@@ -445,7 +461,7 @@
 		if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
 			freereq = 0;
 		} else {
-			devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
+			devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
 				ioc->name, pEvReply));
 		}
 
@@ -454,13 +470,13 @@
 #endif
 
 	} else if (func == MPI_FUNCTION_EVENT_ACK) {
-		dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, EventAck reply received\n",
+		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_base_reply, EventAck reply received\n",
 				ioc->name));
 	} else if (func == MPI_FUNCTION_CONFIG) {
 		CONFIGPARMS *pCfg;
 		unsigned long flags;
 
-		dcprintk((MYIOC_s_INFO_FMT "config_complete (mf=%p,mr=%p)\n",
+		dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "config_complete (mf=%p,mr=%p)\n",
 				ioc->name, mf, reply));
 
 		pCfg = * ((CONFIGPARMS **)((u8 *) mf + ioc->req_sz - sizeof(void *)));
@@ -483,7 +499,7 @@
 				u16		 status;
 
 				status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
-				dcprintk((KERN_NOTICE "  IOCStatus=%04xh, IOCLogInfo=%08xh\n",
+				dcprintk(ioc, printk(KERN_NOTICE "  IOCStatus=%04xh, IOCLogInfo=%08xh\n",
 				     status, le32_to_cpu(pReply->IOCLogInfo)));
 
 				pCfg->status = status;
@@ -788,7 +804,7 @@
 		printk(KERN_INFO "MF Count 0x%x Max 0x%x \n", ioc->mfcnt, ioc->req_depth);
 #endif
 
-	dmfprintk((KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
+	dmfprintk(ioc, printk(KERN_INFO MYNAM ": %s: mpt_get_msg_frame(%d,%d), got mf=%p\n",
 			ioc->name, handle, ioc->id, mf));
 	return mf;
 }
@@ -819,27 +835,10 @@
 	mf->u.frame.hwhdr.msgctxu.fld.req_idx = cpu_to_le16(req_idx);
 	mf->u.frame.hwhdr.msgctxu.fld.rsvd = 0;
 
-#ifdef MPT_DEBUG_MSG_FRAME
-	{
-		u32	*m = mf->u.frame.hwhdr.__hdr;
-		int	 ii, n;
-
-		printk(KERN_INFO MYNAM ": %s: About to Put msg frame @ %p:\n" KERN_INFO " ",
-				ioc->name, m);
-		n = ioc->req_sz/4 - 1;
-		while (m[n] == 0)
-			n--;
-		for (ii=0; ii<=n; ii++) {
-			if (ii && ((ii%8)==0))
-				printk("\n" KERN_INFO " ");
-			printk(" %08x", le32_to_cpu(m[ii]));
-		}
-		printk("\n");
-	}
-#endif
+	DBG_DUMP_PUT_MSG_FRAME(ioc, (u32 *)mf);
 
 	mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx];
-	dsgprintk((MYIOC_s_INFO_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx]));
+	dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx]));
 	CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr);
 }
 
@@ -954,7 +953,7 @@
 	if (!(CHIPREG_READ32(&ioc->chip->Doorbell) & MPI_DOORBELL_ACTIVE))
 		return -5;
 
-	dhsprintk((KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
+	dhsprintk(ioc, printk(KERN_INFO MYNAM ": %s: mpt_send_handshake_request start, WaitCnt=%d\n",
 		ioc->name, ii));
 
 	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
@@ -1065,7 +1064,7 @@
 			    host_page_buffer_sz,
 			    &ioc->HostPageBuffer_dma)) != NULL) {
 
-				dinitprintk((MYIOC_s_INFO_FMT
+				dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 				    "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
 				    ioc->name, ioc->HostPageBuffer,
 				    (u32)ioc->HostPageBuffer_dma,
@@ -1131,6 +1130,248 @@
 	return -1;
 }
 
+/**
+ *	mpt_get_product_name - returns product string
+ *	@vendor: pci vendor id
+ *	@device: pci device id
+ *	@revision: pci revision id
+ *	@prod_name: string returned
+ *
+ *	Returns product string displayed when driver loads,
+ *	in /proc/mpt/summary and /sysfs/class/scsi_host/host<X>/version_product
+ *
+ **/
+static void
+mpt_get_product_name(u16 vendor, u16 device, u8 revision, char *prod_name)
+{
+	char *product_str = NULL;
+
+	if (vendor == PCI_VENDOR_ID_BROCADE) {
+		switch (device)
+		{
+		case MPI_MANUFACTPAGE_DEVICEID_FC949E:
+			switch (revision)
+			{
+			case 0x00:
+				product_str = "BRE040 A0";
+				break;
+			case 0x01:
+				product_str = "BRE040 A1";
+				break;
+			default:
+				product_str = "BRE040";
+				break;
+			}
+			break;
+		}
+		goto out;
+	}
+
+	switch (device)
+	{
+	case MPI_MANUFACTPAGE_DEVICEID_FC909:
+		product_str = "LSIFC909 B1";
+		break;
+	case MPI_MANUFACTPAGE_DEVICEID_FC919:
+		product_str = "LSIFC919 B0";
+		break;
+	case MPI_MANUFACTPAGE_DEVICEID_FC929:
+		product_str = "LSIFC929 B0";
+		break;
+	case MPI_MANUFACTPAGE_DEVICEID_FC919X:
+		if (revision < 0x80)
+			product_str = "LSIFC919X A0";
+		else
+			product_str = "LSIFC919XL A1";
+		break;
+	case MPI_MANUFACTPAGE_DEVICEID_FC929X:
+		if (revision < 0x80)
+			product_str = "LSIFC929X A0";
+		else
+			product_str = "LSIFC929XL A1";
+		break;
+	case MPI_MANUFACTPAGE_DEVICEID_FC939X:
+		product_str = "LSIFC939X A1";
+		break;
+	case MPI_MANUFACTPAGE_DEVICEID_FC949X:
+		product_str = "LSIFC949X A1";
+		break;
+	case MPI_MANUFACTPAGE_DEVICEID_FC949E:
+		switch (revision)
+		{
+		case 0x00:
+			product_str = "LSIFC949E A0";
+			break;
+		case 0x01:
+			product_str = "LSIFC949E A1";
+			break;
+		default:
+			product_str = "LSIFC949E";
+			break;
+		}
+		break;
+	case MPI_MANUFACTPAGE_DEVID_53C1030:
+		switch (revision)
+		{
+		case 0x00:
+			product_str = "LSI53C1030 A0";
+			break;
+		case 0x01:
+			product_str = "LSI53C1030 B0";
+			break;
+		case 0x03:
+			product_str = "LSI53C1030 B1";
+			break;
+		case 0x07:
+			product_str = "LSI53C1030 B2";
+			break;
+		case 0x08:
+			product_str = "LSI53C1030 C0";
+			break;
+		case 0x80:
+			product_str = "LSI53C1030T A0";
+			break;
+		case 0x83:
+			product_str = "LSI53C1030T A2";
+			break;
+		case 0x87:
+			product_str = "LSI53C1030T A3";
+			break;
+		case 0xc1:
+			product_str = "LSI53C1020A A1";
+			break;
+		default:
+			product_str = "LSI53C1030";
+			break;
+		}
+		break;
+	case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
+		switch (revision)
+		{
+		case 0x03:
+			product_str = "LSI53C1035 A2";
+			break;
+		case 0x04:
+			product_str = "LSI53C1035 B0";
+			break;
+		default:
+			product_str = "LSI53C1035";
+			break;
+		}
+		break;
+	case MPI_MANUFACTPAGE_DEVID_SAS1064:
+		switch (revision)
+		{
+		case 0x00:
+			product_str = "LSISAS1064 A1";
+			break;
+		case 0x01:
+			product_str = "LSISAS1064 A2";
+			break;
+		case 0x02:
+			product_str = "LSISAS1064 A3";
+			break;
+		case 0x03:
+			product_str = "LSISAS1064 A4";
+			break;
+		default:
+			product_str = "LSISAS1064";
+			break;
+		}
+		break;
+	case MPI_MANUFACTPAGE_DEVID_SAS1064E:
+		switch (revision)
+		{
+		case 0x00:
+			product_str = "LSISAS1064E A0";
+			break;
+		case 0x01:
+			product_str = "LSISAS1064E B0";
+			break;
+		case 0x02:
+			product_str = "LSISAS1064E B1";
+			break;
+		case 0x04:
+			product_str = "LSISAS1064E B2";
+			break;
+		case 0x08:
+			product_str = "LSISAS1064E B3";
+			break;
+		default:
+			product_str = "LSISAS1064E";
+			break;
+		}
+		break;
+	case MPI_MANUFACTPAGE_DEVID_SAS1068:
+		switch (revision)
+		{
+		case 0x00:
+			product_str = "LSISAS1068 A0";
+			break;
+		case 0x01:
+			product_str = "LSISAS1068 B0";
+			break;
+		case 0x02:
+			product_str = "LSISAS1068 B1";
+			break;
+		default:
+			product_str = "LSISAS1068";
+			break;
+		}
+		break;
+	case MPI_MANUFACTPAGE_DEVID_SAS1068E:
+		switch (revision)
+		{
+		case 0x00:
+			product_str = "LSISAS1068E A0";
+			break;
+		case 0x01:
+			product_str = "LSISAS1068E B0";
+			break;
+		case 0x02:
+			product_str = "LSISAS1068E B1";
+			break;
+		case 0x04:
+			product_str = "LSISAS1068E B2";
+			break;
+		case 0x08:
+			product_str = "LSISAS1068E B3";
+			break;
+		default:
+			product_str = "LSISAS1068E";
+			break;
+		}
+		break;
+	case MPI_MANUFACTPAGE_DEVID_SAS1078:
+		switch (revision)
+		{
+		case 0x00:
+			product_str = "LSISAS1078 A0";
+			break;
+		case 0x01:
+			product_str = "LSISAS1078 B0";
+			break;
+		case 0x02:
+			product_str = "LSISAS1078 C0";
+			break;
+		case 0x03:
+			product_str = "LSISAS1078 C1";
+			break;
+		case 0x04:
+			product_str = "LSISAS1078 C2";
+			break;
+		default:
+			product_str = "LSISAS1078";
+			break;
+		}
+		break;
+	}
+
+ out:
+	if (product_str)
+		sprintf(prod_name, "%s", product_str);
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *	mpt_attach - Install a PCI intelligent MPT adapter.
@@ -1167,31 +1408,37 @@
 	struct proc_dir_entry *dent, *ent;
 #endif
 
+	ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
+	if (ioc == NULL) {
+		printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
+		return -ENOMEM;
+	}
+
+	ioc->debug_level = mpt_debug_level;
+	if (mpt_debug_level)
+		printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level);
+
 	if (pci_enable_device(pdev))
 		return r;
 
-	dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n"));
+	dinitprintk(ioc, printk(KERN_WARNING MYNAM ": mpt_adapter_install\n"));
 
 	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
-		dprintk((KERN_INFO MYNAM
+		dprintk(ioc, printk(KERN_INFO MYNAM
 			": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n"));
 	} else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
 		printk(KERN_WARNING MYNAM ": 32 BIT PCI BUS DMA ADDRESSING NOT SUPPORTED\n");
 		return r;
 	}
 
-	if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
-		dprintk((KERN_INFO MYNAM
+	if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
+		dprintk(ioc, printk(KERN_INFO MYNAM
 			": Using 64 bit consistent mask\n"));
-	else
-		dprintk((KERN_INFO MYNAM
+	} else {
+		dprintk(ioc, printk(KERN_INFO MYNAM
 			": Not using 64 bit consistent mask\n"));
-
-	ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC);
-	if (ioc == NULL) {
-		printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n");
-		return -ENOMEM;
 	}
+
 	ioc->alloc_total = sizeof(MPT_ADAPTER);
 	ioc->req_sz = MPT_DEFAULT_FRAME_SIZE;		/* avoid div by zero! */
 	ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
@@ -1259,9 +1506,9 @@
 		return -EINVAL;
 	}
 	ioc->memmap = mem;
-	dinitprintk((KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
+	dinitprintk(ioc, printk(KERN_INFO MYNAM ": mem = %p, mem_phys = %lx\n", mem, mem_phys));
 
-	dinitprintk((KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
+	dinitprintk(ioc, printk(KERN_INFO MYNAM ": facts @ %p, pfacts[0] @ %p\n",
 			&ioc->facts, &ioc->pfacts[0]));
 
 	ioc->mem_phys = mem_phys;
@@ -1274,23 +1521,23 @@
 		ioc->pio_chip = (SYSIF_REGS __iomem *)pmem;
 	}
 
-	if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC909) {
-		ioc->prod_name = "LSIFC909";
+	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+	mpt_get_product_name(pdev->vendor, pdev->device, revision, ioc->prod_name);
+
+	switch (pdev->device)
+	{
+	case MPI_MANUFACTPAGE_DEVICEID_FC939X:
+	case MPI_MANUFACTPAGE_DEVICEID_FC949X:
+		ioc->errata_flag_1064 = 1;
+	case MPI_MANUFACTPAGE_DEVICEID_FC909:
+	case MPI_MANUFACTPAGE_DEVICEID_FC929:
+	case MPI_MANUFACTPAGE_DEVICEID_FC919:
+	case MPI_MANUFACTPAGE_DEVICEID_FC949E:
 		ioc->bus_type = FC;
-	}
-	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) {
-		ioc->prod_name = "LSIFC929";
-		ioc->bus_type = FC;
-	}
-	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919) {
-		ioc->prod_name = "LSIFC919";
-		ioc->bus_type = FC;
-	}
-	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929X) {
-		pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
-		ioc->bus_type = FC;
+		break;
+
+	case MPI_MANUFACTPAGE_DEVICEID_FC929X:
 		if (revision < XL_929) {
-			ioc->prod_name = "LSIFC929X";
 			/* 929X Chip Fix. Set Split transactions level
 		 	* for PCIX. Set MOST bits to zero.
 		 	*/
@@ -1298,75 +1545,46 @@
 			pcixcmd &= 0x8F;
 			pci_write_config_byte(pdev, 0x6a, pcixcmd);
 		} else {
-			ioc->prod_name = "LSIFC929XL";
 			/* 929XL Chip Fix. Set MMRBC to 0x08.
 		 	*/
 			pci_read_config_byte(pdev, 0x6a, &pcixcmd);
 			pcixcmd |= 0x08;
 			pci_write_config_byte(pdev, 0x6a, pcixcmd);
 		}
-	}
-	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC919X) {
-		ioc->prod_name = "LSIFC919X";
 		ioc->bus_type = FC;
+		break;
+
+	case MPI_MANUFACTPAGE_DEVICEID_FC919X:
 		/* 919X Chip Fix. Set Split transactions level
 		 * for PCIX. Set MOST bits to zero.
 		 */
 		pci_read_config_byte(pdev, 0x6a, &pcixcmd);
 		pcixcmd &= 0x8F;
 		pci_write_config_byte(pdev, 0x6a, pcixcmd);
-	}
-	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC939X) {
-		ioc->prod_name = "LSIFC939X";
 		ioc->bus_type = FC;
-		ioc->errata_flag_1064 = 1;
-	}
-	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949X) {
-		ioc->prod_name = "LSIFC949X";
-		ioc->bus_type = FC;
-		ioc->errata_flag_1064 = 1;
-	}
-	else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC949E) {
-		ioc->prod_name = "LSIFC949E";
-		ioc->bus_type = FC;
-	}
-	else if (pdev->device == MPI_MANUFACTPAGE_DEVID_53C1030) {
-		ioc->prod_name = "LSI53C1030";
-		ioc->bus_type = SPI;
+		break;
+
+	case MPI_MANUFACTPAGE_DEVID_53C1030:
 		/* 1030 Chip Fix. Disable Split transactions
 		 * for PCIX. Set MOST bits to zero if Rev < C0( = 8).
 		 */
-		pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
 		if (revision < C0_1030) {
 			pci_read_config_byte(pdev, 0x6a, &pcixcmd);
 			pcixcmd &= 0x8F;
 			pci_write_config_byte(pdev, 0x6a, pcixcmd);
 		}
-	}
-	else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) {
-		ioc->prod_name = "LSI53C1035";
+
+	case MPI_MANUFACTPAGE_DEVID_1030_53C1035:
 		ioc->bus_type = SPI;
-	}
-	else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) {
-		ioc->prod_name = "LSISAS1064";
-		ioc->bus_type = SAS;
+		break;
+
+	case MPI_MANUFACTPAGE_DEVID_SAS1064:
+	case MPI_MANUFACTPAGE_DEVID_SAS1068:
 		ioc->errata_flag_1064 = 1;
-	}
-	else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
-		ioc->prod_name = "LSISAS1068";
-		ioc->bus_type = SAS;
-		ioc->errata_flag_1064 = 1;
-	}
-	else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) {
-		ioc->prod_name = "LSISAS1064E";
-		ioc->bus_type = SAS;
-	}
-	else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
-		ioc->prod_name = "LSISAS1068E";
-		ioc->bus_type = SAS;
-	}
-	else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
-		ioc->prod_name = "LSISAS1078";
+
+	case MPI_MANUFACTPAGE_DEVID_SAS1064E:
+	case MPI_MANUFACTPAGE_DEVID_SAS1068E:
+	case MPI_MANUFACTPAGE_DEVID_SAS1078:
 		ioc->bus_type = SAS;
 	}
 
@@ -1616,6 +1834,7 @@
 	int	 ret = 0;
 	int	 reset_alt_ioc_active = 0;
 	int	 irq_allocated = 0;
+	u8	*a;
 
 	printk(KERN_INFO MYNAM ": Initiating %s %s\n",
 			ioc->name, reason==MPT_HOSTEVENT_IOC_BRINGUP ? "bringup" : "recovery");
@@ -1644,7 +1863,8 @@
 
 			if (reset_alt_ioc_active && ioc->alt_ioc) {
 				/* (re)Enable alt-IOC! (reply interrupt, FreeQ) */
-				dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
+				dprintk(ioc, printk(KERN_INFO MYNAM
+					": alt-%s reply irq re-enabled\n",
 						ioc->alt_ioc->name));
 				CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
 				ioc->alt_ioc->active = 1;
@@ -1677,7 +1897,7 @@
 
 
 	if (ii == 5) {
-		dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc));
 		ret = -2;
 	} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
 		MptDisplayIocCapabilities(ioc);
@@ -1685,13 +1905,15 @@
 
 	if (alt_ioc_ready) {
 		if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) {
-			dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
+			dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+				"Initial Alt IocFacts failed rc=%x\n", ioc->name, rc));
 			/* Retry - alt IOC was initialized once
 			 */
 			rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason);
 		}
 		if (rc) {
-			dinitprintk((MYIOC_s_INFO_FMT "Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
+			dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+				"Retry Alt IocFacts failed rc=%x\n", ioc->name, rc));
 			alt_ioc_ready = 0;
 			reset_alt_ioc_active = 0;
 		} else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
@@ -1724,7 +1946,7 @@
 			ioc->pci_irq = ioc->pcidev->irq;
 			pci_set_master(ioc->pcidev);		/* ?? */
 			pci_set_drvdata(ioc->pcidev, ioc);
-			dprintk((KERN_INFO MYNAM ": %s installed at interrupt "
+			dprintk(ioc, printk(KERN_INFO MYNAM ": %s installed at interrupt "
 				"%d\n", ioc->name, ioc->pcidev->irq));
 		}
 	}
@@ -1762,7 +1984,7 @@
 
 	if (reason == MPT_HOSTEVENT_IOC_BRINGUP){
 		if (ioc->upload_fw) {
-			ddlprintk((MYIOC_s_INFO_FMT
+			ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 				"firmware upload required!\n", ioc->name));
 
 			/* Controller is not operational, cannot do upload
@@ -1778,7 +2000,8 @@
 						 * chips (mpt_adapter_disable,
 						 * mpt_diag_reset)
 						 */
-						ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload:  alt_%s has cached_fw=%p \n",
+						ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+							": mpt_upload:  alt_%s has cached_fw=%p \n",
 							ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
 						ioc->alt_ioc->cached_fw = NULL;
 					}
@@ -1798,7 +2021,7 @@
 
 	if (reset_alt_ioc_active && ioc->alt_ioc) {
 		/* (re)Enable alt-IOC! (reply interrupt) */
-		dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
+		dinitprintk(ioc, printk(KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n",
 				ioc->alt_ioc->name));
 		CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, MPI_HIM_DIM);
 		ioc->alt_ioc->active = 1;
@@ -1850,13 +2073,13 @@
 				 *  (LANPage1_t stuff)
 				 */
 				(void) GetLanConfigPages(ioc);
-#ifdef MPT_DEBUG
-				{
-					u8 *a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
-					dprintk((MYIOC_s_INFO_FMT "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n",
-							ioc->name, a[5], a[4], a[3], a[2], a[1], a[0] ));
-				}
-#endif
+				a = (u8*)&ioc->lan_cnfg_page1.HardwareAddressLow;
+				dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+					"LanAddr = %02X:%02X:%02X:"
+					"%02X:%02X:%02X\n",
+					ioc->name, a[5], a[4],
+					a[3], a[2], a[1], a[0] ));
+
 			}
 		} else {
 			/* Get NVRAM and adapter maximums from SPP 0 and 2
@@ -1880,6 +2103,7 @@
 		}
 
 		GetIoUnitPage2(ioc);
+		mpt_get_manufacturing_pg_0(ioc);
 	}
 
 	/*
@@ -1892,15 +2116,17 @@
 		rc = handlers = 0;
 		for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
 			if ((ret == 0) && MptResetHandlers[ii]) {
-				dprintk((MYIOC_s_INFO_FMT "Calling IOC post_reset handler #%d\n",
-						ioc->name, ii));
+				dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+					"Calling IOC post_reset handler #%d\n",
+					ioc->name, ii));
 				rc += mpt_signal_reset(ii, ioc, MPT_IOC_POST_RESET);
 				handlers++;
 			}
 
 			if (alt_ioc_ready && MptResetHandlers[ii]) {
-				drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n",
-						ioc->name, ioc->alt_ioc->name, ii));
+				drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+					"Calling alt-%s post_reset handler #%d\n",
+					ioc->name, ioc->alt_ioc->name, ii));
 				rc += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_POST_RESET);
 				handlers++;
 			}
@@ -1938,7 +2164,7 @@
 	unsigned int func = PCI_FUNC(pdev->devfn);
 	MPT_ADAPTER *ioc_srch;
 
-	dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x,"
+	dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PCI device %s devfn=%x/%x,"
 	    " searching for devfn match on %x or %x\n",
 		ioc->name, pci_name(pdev), pdev->bus->number,
 		pdev->devfn, func-1, func+1));
@@ -1963,7 +2189,7 @@
 					ioc_srch->name, ioc_srch->alt_ioc->name);
 				break;
 			}
-			dprintk((KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
+			dprintk(ioc, printk(KERN_INFO MYNAM ": FOUND! binding %s <==> %s\n",
 				ioc->name, ioc_srch->name));
 			ioc_srch->alt_ioc = ioc;
 			ioc->alt_ioc = ioc_srch;
@@ -1984,7 +2210,7 @@
 	int ret;
 
 	if (ioc->cached_fw != NULL) {
-		ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
+		ddlprintk(ioc, printk(KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n"));
 		if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) {
 			printk(KERN_WARNING MYNAM
 				": firmware downloadboot failure (%d)!\n", ret);
@@ -1999,7 +2225,7 @@
 
 	if (ioc->alloc != NULL) {
 		sz = ioc->alloc_sz;
-		dexitprintk((KERN_INFO MYNAM ": %s.free  @ %p, sz=%d bytes\n",
+		dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s.free  @ %p, sz=%d bytes\n",
 		 	ioc->name, ioc->alloc, ioc->alloc_sz));
 		pci_free_consistent(ioc->pcidev, sz,
 				ioc->alloc, ioc->alloc_dma);
@@ -2041,7 +2267,7 @@
 
 	if (ioc->spi_data.pIocPg4 != NULL) {
 		sz = ioc->spi_data.IocPg4Sz;
-		pci_free_consistent(ioc->pcidev, sz, 
+		pci_free_consistent(ioc->pcidev, sz,
 			ioc->spi_data.pIocPg4,
 			ioc->spi_data.IocPg4_dma);
 		ioc->spi_data.pIocPg4 = NULL;
@@ -2064,7 +2290,7 @@
 			   ": %s: host page buffers free failed (%d)!\n",
 			    __FUNCTION__, ret);
 		}
-		dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free  @ %p, sz=%d bytes\n",
+		dexitprintk(ioc, printk(KERN_INFO MYNAM ": %s HostPageBuffer free  @ %p, sz=%d bytes\n",
 		 	ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz));
 		pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz,
 				ioc->HostPageBuffer,
@@ -2110,7 +2336,7 @@
 #if defined(CONFIG_MTRR) && 0
 	if (ioc->mtrr_reg > 0) {
 		mtrr_del(ioc->mtrr_reg, 0, 0);
-		dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
+		dprintk(ioc, printk(KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name));
 	}
 #endif
 
@@ -2118,7 +2344,7 @@
 	list_del(&ioc->list);
 
 	sz_last = ioc->alloc_total;
-	dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
+	dprintk(ioc, printk(KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n",
 			ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first));
 
 	if (ioc->alt_ioc)
@@ -2138,8 +2364,8 @@
 	int i = 0;
 
 	printk(KERN_INFO "%s: ", ioc->name);
-	if (ioc->prod_name && strlen(ioc->prod_name) > 3)
-		printk("%s: ", ioc->prod_name+3);
+	if (ioc->prod_name)
+		printk("%s: ", ioc->prod_name);
 	printk("Capabilities={");
 
 	if (ioc->pfacts[0].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
@@ -2198,7 +2424,7 @@
 
 	/* Get current [raw] IOC state  */
 	ioc_state = mpt_GetIocState(ioc, 0);
-	dhsprintk((KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
+	dhsprintk(ioc, printk(KERN_INFO MYNAM "::MakeIocReady, %s [raw] state=%08x\n", ioc->name, ioc_state));
 
 	/*
 	 *	Check to see if IOC got left/stuck in doorbell handshake
@@ -2229,7 +2455,7 @@
 	 *	Hmmm...  Did it get left operational?
 	 */
 	if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) {
-		dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n",
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "IOC operational unexpected\n",
 				ioc->name));
 
 		/* Check WhoInit.
@@ -2238,7 +2464,7 @@
 		 * Else, fall through to KickStart case
 		 */
 		whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT;
-		dinitprintk((KERN_INFO MYNAM
+		dinitprintk(ioc, printk(KERN_INFO MYNAM
 			": whoinit 0x%x statefault %d force %d\n",
 			whoinit, statefault, force));
 		if (whoinit == MPI_WHOINIT_PCI_PEER)
@@ -2374,7 +2600,7 @@
 	get_facts.Function = MPI_FUNCTION_IOC_FACTS;
 	/* Assert: All other get_facts fields are zero! */
 
-	dinitprintk((MYIOC_s_INFO_FMT
+	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 	    "Sending get IocFacts request req_sz=%d reply_sz=%d\n",
 	    ioc->name, req_sz, reply_sz));
 
@@ -2476,8 +2702,9 @@
 			sz = sz >> 1;
 		}
 		ioc->NBShiftFactor  = shiftFactor;
-		dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
-					ioc->name, vv, shiftFactor, r));
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+			"NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n",
+			ioc->name, vv, shiftFactor, r));
 
 		if (reason == MPT_HOSTEVENT_IOC_BRINGUP) {
 			/*
@@ -2489,9 +2716,9 @@
 			ioc->reply_sz = MPT_REPLY_FRAME_SIZE;
 			ioc->reply_depth = min_t(int, MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth);
 
-			dinitprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n",
+			dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "reply_sz=%3d, reply_depth=%4d\n",
 				ioc->name, ioc->reply_sz, ioc->reply_depth));
-			dinitprintk((MYIOC_s_INFO_FMT "req_sz  =%3d, req_depth  =%4d\n",
+			dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "req_sz  =%3d, req_depth  =%4d\n",
 				ioc->name, ioc->req_sz, ioc->req_depth));
 
 			/* Get port facts! */
@@ -2550,7 +2777,7 @@
 	get_pfacts.PortNumber = portnum;
 	/* Assert: All other get_pfacts fields are zero! */
 
-	dinitprintk((MYIOC_s_INFO_FMT "Sending get PortFacts(%d) request\n",
+	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending get PortFacts(%d) request\n",
 			ioc->name, portnum));
 
 	/* No non-zero fields in the get_pfacts request are greater than
@@ -2626,12 +2853,12 @@
 		ioc->upload_fw = 1;
 	else
 		ioc->upload_fw = 0;
-	ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n",
+	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "upload_fw %d facts.Flags=%x\n",
 		   ioc->name, ioc->upload_fw, ioc->facts.Flags));
 
 	ioc_init.MaxDevices = (U8)ioc->devices_per_bus;
 	ioc_init.MaxBuses = (U8)ioc->number_of_buses;
-	dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n",
+	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "facts.MsgVersion=%x\n",
 		   ioc->name, ioc->facts.MsgVersion));
 	if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) {
 		// set MsgVersion and HeaderVersion host driver was built with
@@ -2662,7 +2889,7 @@
 	ioc->facts.MaxDevices = ioc_init.MaxDevices;
 	ioc->facts.MaxBuses = ioc_init.MaxBuses;
 
-	dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n",
+	dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOCInit (req @ %p)\n",
 			ioc->name, &ioc_init));
 
 	r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init,
@@ -2676,7 +2903,7 @@
 	 * since we don't even look at its contents.
 	 */
 
-	dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n",
+	dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending PortEnable (req @ %p)\n",
 			ioc->name, &ioc_init));
 
 	if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) {
@@ -2707,7 +2934,7 @@
 		state = mpt_GetIocState(ioc, 1);
 		count++;
 	}
-	dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
+	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
 			ioc->name, count));
 
 	ioc->aen_event_read_flag=0;
@@ -2747,7 +2974,7 @@
 /*	port_enable.MsgFlags = 0;		*/
 /*	port_enable.MsgContext = 0;		*/
 
-	dinitprintk((MYIOC_s_INFO_FMT "Sending Port(%d)Enable (req @ %p)\n",
+	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Port(%d)Enable (req @ %p)\n",
 			ioc->name, portnum, &port_enable));
 
 	/* RAID FW may take a long time to enable
@@ -2800,7 +3027,7 @@
 	int sz;
 
 	sz = ioc->facts.FWImageSize;
-	dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image  @ %p[%p], sz=%d[%x] bytes\n",
+	dinitprintk(ioc, printk(KERN_INFO MYNAM "free_fw_memory: FW Image  @ %p[%p], sz=%d[%x] bytes\n",
 		 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
 	pci_free_consistent(ioc->pcidev, sz,
 			ioc->cached_fw, ioc->cached_fw_dma);
@@ -2844,7 +3071,7 @@
 
 	mpt_alloc_fw_memory(ioc, sz);
 
-	dinitprintk((KERN_INFO MYNAM ": FW Image  @ %p[%p], sz=%d[%x] bytes\n",
+	dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Image  @ %p[%p], sz=%d[%x] bytes\n",
 		 ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz));
 
 	if (ioc->cached_fw == NULL) {
@@ -2876,14 +3103,14 @@
 	mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma);
 
 	sgeoffset += sizeof(u32) + sizeof(dma_addr_t);
-	dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
+	dinitprintk(ioc, printk(KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n",
 			prequest, sgeoffset));
-	DBG_DUMP_FW_REQUEST_FRAME(prequest)
+	DBG_DUMP_FW_REQUEST_FRAME(ioc, (u32 *)prequest)
 
 	ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest,
 				reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag);
 
-	dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
+	dinitprintk(ioc, printk(KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii));
 
 	cmdStatus = -EFAULT;
 	if (ii == 0) {
@@ -2898,13 +3125,13 @@
 				cmdStatus = 0;
 		}
 	}
-	dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n",
+	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": do_upload cmdStatus=%d \n",
 			ioc->name, cmdStatus));
 
 
 	if (cmdStatus) {
 
-		ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n",
+		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": fw upload failed, freeing image \n",
 			ioc->name));
 		mpt_free_fw_memory(ioc);
 	}
@@ -2939,7 +3166,7 @@
 	u32			 load_addr;
 	u32 			 ioc_state=0;
 
-	ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
+	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n",
 				ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader));
 
 	CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF);
@@ -2964,7 +3191,7 @@
 	for (count = 0; count < 30; count ++) {
 		diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
 		if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
-			ddlprintk((MYIOC_s_INFO_FMT "RESET_ADAPTER cleared, count=%d\n",
+			ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RESET_ADAPTER cleared, count=%d\n",
 				ioc->name, count));
 			break;
 		}
@@ -2977,7 +3204,7 @@
 	}
 
 	if ( count == 30 ) {
-		ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! "
+		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot failed! "
 		"Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n",
 		ioc->name, diag0val));
 		return -3;
@@ -3003,10 +3230,10 @@
 		pci_enable_io_access(ioc->pcidev);
 
 	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->LoadStartAddress);
-	ddlprintk((MYIOC_s_INFO_FMT "LoadStart addr written 0x%x \n",
+	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "LoadStart addr written 0x%x \n",
 		ioc->name, pFwHeader->LoadStartAddress));
 
-	ddlprintk((MYIOC_s_INFO_FMT "Write FW Image: 0x%x bytes @ %p\n",
+	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write FW Image: 0x%x bytes @ %p\n",
 				ioc->name, fwSize*4, ptrFw));
 	while (fwSize--) {
 		CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, *ptrFw++);
@@ -3021,7 +3248,7 @@
 		fwSize = (pExtImage->ImageSize + 3) >> 2;
 		ptrFw = (u32 *)pExtImage;
 
-		ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
+		ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n",
 						ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr));
 		CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr);
 
@@ -3032,11 +3259,11 @@
 	}
 
 	/* Write the IopResetVectorRegAddr */
-	ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Addr=%x! \n", ioc->name, 	pFwHeader->IopResetRegAddr));
+	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Addr=%x! \n", ioc->name, 	pFwHeader->IopResetRegAddr));
 	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, pFwHeader->IopResetRegAddr);
 
 	/* Write the IopResetVectorValue */
-	ddlprintk((MYIOC_s_INFO_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
+	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Write IopResetVector Value=%x! \n", ioc->name, pFwHeader->IopResetVectorValue));
 	CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, pFwHeader->IopResetVectorValue);
 
 	/* Clear the internal flash bad bit - autoincrementing register,
@@ -3070,11 +3297,11 @@
 		pci_disable_io_access(ioc->pcidev);
 
 	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
-	ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, "
+	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot diag0val=%x, "
 		"turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n",
 		ioc->name, diag0val));
 	diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE);
-	ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n",
+	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "downloadboot now diag0val=%x\n",
 		ioc->name, diag0val));
 	CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val);
 
@@ -3085,7 +3312,7 @@
 		ioc_state = mpt_GetIocState(ioc, 0);
 		if ( (GetIocFacts(ioc, sleepFlag,
 				MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) {
-			ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n",
+			ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "GetIocFacts failed: IocState=%x\n",
 					ioc->name, ioc_state));
 			return -EFAULT;
 		}
@@ -3093,17 +3320,20 @@
 
 	for (count=0; count<HZ*20; count++) {
 		if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) {
-			ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n",
-					ioc->name, count, ioc_state));
+			ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+				"downloadboot successful! (count=%d) IocState=%x\n",
+				ioc->name, count, ioc_state));
 			if (ioc->bus_type == SAS) {
 				return 0;
 			}
 			if ((SendIocInit(ioc, sleepFlag)) != 0) {
-				ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n",
+				ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+					"downloadboot: SendIocInit failed\n",
 					ioc->name));
 				return -EFAULT;
 			}
-			ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit successful\n",
+			ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+					"downloadboot: SendIocInit successful\n",
 					ioc->name));
 			return 0;
 		}
@@ -3113,8 +3343,8 @@
 			mdelay (10);
 		}
 	}
-	ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! IocState=%x\n",
-		ioc->name, ioc_state));
+	ddlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		"downloadboot failed! IocState=%x\n",ioc->name, ioc_state));
 	return -EFAULT;
 }
 
@@ -3151,7 +3381,7 @@
 	u32 ioc_state=0;
 	int cnt,cntdn;
 
-	dinitprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
+	dinitprintk(ioc, printk(KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name));
 	if (ioc->bus_type == SPI) {
 		/* Always issue a Msg Unit Reset first. This will clear some
 		 * SCSI bus hang conditions.
@@ -3169,14 +3399,14 @@
 	if (hard_reset_done < 0)
 		return hard_reset_done;
 
-	dinitprintk((MYIOC_s_INFO_FMT "Diagnostic reset successful!\n",
+	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset successful!\n",
 			ioc->name));
 
 	cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 2;	/* 2 seconds */
 	for (cnt=0; cnt<cntdn; cnt++) {
 		ioc_state = mpt_GetIocState(ioc, 1);
 		if ((ioc_state == MPI_IOC_STATE_READY) || (ioc_state == MPI_IOC_STATE_OPERATIONAL)) {
-			dinitprintk((MYIOC_s_INFO_FMT "KickStart successful! (cnt=%d)\n",
+			dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "KickStart successful! (cnt=%d)\n",
  					ioc->name, cnt));
 			return hard_reset_done;
 		}
@@ -3219,15 +3449,13 @@
 	u32 doorbell;
 	int hard_reset_done = 0;
 	int count = 0;
-#ifdef MPT_DEBUG
 	u32 diag1val = 0;
-#endif
 
 	/* Clear any existing interrupts */
 	CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
 
 	if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
-		drsprintk((MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
+		drsprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
 			"address=%p\n",  ioc->name, __FUNCTION__,
 			&ioc->chip->Doorbell, &ioc->chip->Reset_1078));
 		CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
@@ -3240,7 +3468,7 @@
 			doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
 			doorbell &= MPI_IOC_STATE_MASK;
 
-			drsprintk((MYIOC_s_INFO_FMT
+			drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 				"looking for READY STATE: doorbell=%x"
 			        " count=%d\n",
 				ioc->name, doorbell, count));
@@ -3260,12 +3488,12 @@
 	/* Use "Diagnostic reset" method! (only thing available!) */
 	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
 
-#ifdef MPT_DEBUG
-	if (ioc->alt_ioc)
-		diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-	dprintk((MYIOC_s_INFO_FMT "DbG1: diag0=%08x, diag1=%08x\n",
+	if (ioc->debug_level & MPT_DEBUG) {
+		if (ioc->alt_ioc)
+			diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG1: diag0=%08x, diag1=%08x\n",
 			ioc->name, diag0val, diag1val));
-#endif
+	}
 
 	/* Do the reset if we are told to ignore the reset history
 	 * or if the reset history is 0
@@ -3299,16 +3527,16 @@
 
 			diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
 
-			dprintk((MYIOC_s_INFO_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
+			dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Wrote magic DiagWriteEn sequence (%x)\n",
 					ioc->name, diag0val));
 		}
 
-#ifdef MPT_DEBUG
-		if (ioc->alt_ioc)
-			diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-		dprintk((MYIOC_s_INFO_FMT "DbG2: diag0=%08x, diag1=%08x\n",
+		if (ioc->debug_level & MPT_DEBUG) {
+			if (ioc->alt_ioc)
+				diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+			dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG2: diag0=%08x, diag1=%08x\n",
 				ioc->name, diag0val, diag1val));
-#endif
+		}
 		/*
 		 * Disable the ARM (Bug fix)
 		 *
@@ -3322,7 +3550,7 @@
 		 */
 		CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_RESET_ADAPTER);
 		hard_reset_done = 1;
-		dprintk((MYIOC_s_INFO_FMT "Diagnostic reset performed\n",
+		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Diagnostic reset performed\n",
 				ioc->name));
 
 		/*
@@ -3337,12 +3565,14 @@
 
 			for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
 				if (MptResetHandlers[ii]) {
-					dprintk((MYIOC_s_INFO_FMT "Calling IOC pre_reset handler #%d\n",
-							ioc->name, ii));
+					dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+						"Calling IOC pre_reset handler #%d\n",
+						ioc->name, ii));
 					r += mpt_signal_reset(ii, ioc, MPT_IOC_PRE_RESET);
 					if (ioc->alt_ioc) {
-						dprintk((MYIOC_s_INFO_FMT "Calling alt-%s pre_reset handler #%d\n",
-								ioc->name, ioc->alt_ioc->name, ii));
+						dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+							"Calling alt-%s pre_reset handler #%d\n",
+							ioc->name, ioc->alt_ioc->name, ii));
 						r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_PRE_RESET);
 					}
 				}
@@ -3365,7 +3595,7 @@
 					break;
 				}
 
-				dprintk((MYIOC_s_INFO_FMT "cached_fw: diag0val=%x count=%d\n",
+				dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "cached_fw: diag0val=%x count=%d\n",
 					iocp->name, diag0val, count));
 				/* wait 1 sec */
 				if (sleepFlag == CAN_SLEEP) {
@@ -3406,12 +3636,12 @@
 	}
 
 	diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
-#ifdef MPT_DEBUG
-	if (ioc->alt_ioc)
-		diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-	dprintk((MYIOC_s_INFO_FMT "DbG3: diag0=%08x, diag1=%08x\n",
-		ioc->name, diag0val, diag1val));
-#endif
+	if (ioc->debug_level & MPT_DEBUG) {
+		if (ioc->alt_ioc)
+			diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG3: diag0=%08x, diag1=%08x\n",
+			ioc->name, diag0val, diag1val));
+	}
 
 	/* Clear RESET_HISTORY bit!  Place board in the
 	 * diagnostic mode to update the diag register.
@@ -3465,12 +3695,12 @@
 		return -3;
 	}
 
-#ifdef MPT_DEBUG
-	if (ioc->alt_ioc)
-		diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
-	dprintk((MYIOC_s_INFO_FMT "DbG4: diag0=%08x, diag1=%08x\n",
+	if (ioc->debug_level & MPT_DEBUG) {
+		if (ioc->alt_ioc)
+			diag1val = CHIPREG_READ32(&ioc->alt_ioc->chip->Diagnostic);
+		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DbG4: diag0=%08x, diag1=%08x\n",
 			ioc->name, diag0val, diag1val));
-#endif
+	}
 
 	/*
 	 * Reset flag that says we've enabled event notification
@@ -3502,7 +3732,7 @@
 	u32 state;
 	int cntdn, count;
 
-	drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n",
+	drsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending IOC reset(0x%02x)!\n",
 			ioc->name, reset_type));
 	CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<<MPI_DOORBELL_FUNCTION_SHIFT);
 	if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0)
@@ -3567,14 +3797,14 @@
 			return -1;
 
 		ioc->ReqToChain = (int *) mem;
-		dinitprintk((KERN_INFO MYNAM ": %s ReqToChain alloc  @ %p, sz=%d bytes\n",
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReqToChain alloc  @ %p, sz=%d bytes\n",
 			 	ioc->name, mem, sz));
 		mem = kmalloc(sz, GFP_ATOMIC);
 		if (mem == NULL)
 			return -1;
 
 		ioc->RequestNB = (int *) mem;
-		dinitprintk((KERN_INFO MYNAM ": %s RequestNB alloc  @ %p, sz=%d bytes\n",
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestNB alloc  @ %p, sz=%d bytes\n",
 			 	ioc->name, mem, sz));
 	}
 	for (ii = 0; ii < ioc->req_depth; ii++) {
@@ -3604,7 +3834,7 @@
 		numSGE = 1 + (scale - 1) * (ioc->facts.MaxChainDepth-1) + scale +
 			(ioc->req_sz - 64) / (sizeof(dma_addr_t) + sizeof(u32));
 	}
-	dinitprintk((KERN_INFO MYNAM ": %s num_sge=%d numSGE=%d\n",
+	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "num_sge=%d numSGE=%d\n",
 		ioc->name, num_sge, numSGE));
 
 	if ( numSGE > MPT_SCSI_SG_DEPTH	)
@@ -3617,7 +3847,7 @@
 	}
 	num_chain++;
 
-	dinitprintk((KERN_INFO MYNAM ": %s Now numSGE=%d num_sge=%d num_chain=%d\n",
+	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Now numSGE=%d num_sge=%d num_chain=%d\n",
 		ioc->name, numSGE, num_sge, num_chain));
 
 	if (ioc->bus_type == SPI)
@@ -3634,7 +3864,7 @@
 			return -1;
 
 		ioc->ChainToChain = (int *) mem;
-		dinitprintk((KERN_INFO MYNAM ": %s ChainToChain alloc @ %p, sz=%d bytes\n",
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainToChain alloc @ %p, sz=%d bytes\n",
 			 	ioc->name, mem, sz));
 	} else {
 		mem = (u8 *) ioc->ChainToChain;
@@ -3670,22 +3900,22 @@
 			return -1;
 
 		total_size = reply_sz = (ioc->reply_sz * ioc->reply_depth);
-		dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d bytes, ReplyDepth=%d\n",
 			 	ioc->name, ioc->reply_sz, ioc->reply_depth));
-		dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffer sz=%d[%x] bytes\n",
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffer sz=%d[%x] bytes\n",
 			 	ioc->name, reply_sz, reply_sz));
 
 		sz = (ioc->req_sz * ioc->req_depth);
-		dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d bytes, RequestDepth=%d\n",
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d bytes, RequestDepth=%d\n",
 			 	ioc->name, ioc->req_sz, ioc->req_depth));
-		dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffer sz=%d[%x] bytes\n",
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffer sz=%d[%x] bytes\n",
 			 	ioc->name, sz, sz));
 		total_size += sz;
 
 		sz = num_chain * ioc->req_sz; /* chain buffer pool size */
-		dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d bytes, ChainDepth=%d\n",
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d bytes, ChainDepth=%d\n",
 			 	ioc->name, ioc->req_sz, num_chain));
-		dinitprintk((KERN_INFO MYNAM ": %s.ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffer sz=%d[%x] bytes num_chain=%d\n",
 			 	ioc->name, sz, sz, num_chain));
 
 		total_size += sz;
@@ -3696,7 +3926,7 @@
 			goto out_fail;
 		}
 
-		dinitprintk((KERN_INFO MYNAM ": %s.Total alloc @ %p[%p], sz=%d[%x] bytes\n",
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Total alloc @ %p[%p], sz=%d[%x] bytes\n",
 			 	ioc->name, mem, (void *)(ulong)alloc_dma, total_size, total_size));
 
 		memset(mem, 0, total_size);
@@ -3707,7 +3937,7 @@
 		ioc->reply_frames = (MPT_FRAME_HDR *) mem;
 		ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
 
-		dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n",
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
 	 		ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
 
 		alloc_dma += reply_sz;
@@ -3718,7 +3948,7 @@
 		ioc->req_frames = (MPT_FRAME_HDR *) mem;
 		ioc->req_frames_dma = alloc_dma;
 
-		dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n",
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "RequestBuffers @ %p[%p]\n",
 			 	ioc->name, mem, (void *)(ulong)alloc_dma));
 
 		ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF);
@@ -3732,7 +3962,7 @@
 		ioc->mtrr_reg = mtrr_add(ioc->req_frames_dma,
 					 sz,
 					 MTRR_TYPE_WRCOMB, 1);
-		dprintk((MYIOC_s_INFO_FMT "MTRR region registered (base:size=%08x:%x)\n",
+		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MTRR region registered (base:size=%08x:%x)\n",
 				ioc->name, ioc->req_frames_dma, sz));
 #endif
 
@@ -3744,7 +3974,7 @@
 		ioc->ChainBuffer = mem;
 		ioc->ChainBufferDMA = alloc_dma;
 
-		dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n",
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ChainBuffers @ %p(%p)\n",
 			ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA));
 
 		/* Initialize the free chain Q.
@@ -3789,7 +4019,7 @@
 
 		ioc->sense_buf_low_dma = (u32) (ioc->sense_buf_pool_dma & 0xFFFFFFFF);
 		ioc->alloc_total += sz;
-		dinitprintk((KERN_INFO MYNAM ": %s.SenseBuffers @ %p[%p]\n",
+		dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SenseBuffers @ %p[%p]\n",
  			ioc->name, ioc->sense_buf_pool, (void *)(ulong)ioc->sense_buf_pool_dma));
 
 	}
@@ -3797,7 +4027,7 @@
 	/* Post Reply frames to FIFO
 	 */
 	alloc_dma = ioc->alloc_dma;
-	dinitprintk((KERN_INFO MYNAM ": %s.ReplyBuffers @ %p[%p]\n",
+	dinitprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ReplyBuffers @ %p[%p]\n",
 	 	ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma));
 
 	for (i = 0; i < ioc->reply_depth; i++) {
@@ -3878,7 +4108,7 @@
 	if ((t = WaitForDoorbellInt(ioc, 5, sleepFlag)) < 0)
 		failcnt++;
 
-	dhsprintk((MYIOC_s_INFO_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
+	dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request start reqBytes=%d, WaitCnt=%d%s\n",
 			ioc->name, reqBytes, t, failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
 
 	/* Read doorbell and check for active bit */
@@ -3913,10 +4143,10 @@
 				failcnt++;
 		}
 
-		dhsprintk((KERN_INFO MYNAM ": Handshake request frame (@%p) header\n", req));
-		DBG_DUMP_REQUEST_FRAME_HDR(req)
+		dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handshake request frame (@%p) header\n", ioc->name, req));
+		DBG_DUMP_REQUEST_FRAME_HDR(ioc, (u32 *)req)
 
-		dhsprintk((MYIOC_s_INFO_FMT "HandShake request post done, WaitCnt=%d%s\n",
+		dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake request post done, WaitCnt=%d%s\n",
 				ioc->name, t, failcnt ? " - MISSING DOORBELL ACK!" : ""));
 
 		/*
@@ -3925,7 +4155,7 @@
 		if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0)
 			failcnt++;
 
-		dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n",
+		dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HandShake reply count=%d%s\n",
 				ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : ""));
 
 		/*
@@ -3981,7 +4211,7 @@
 	}
 
 	if (cntdn) {
-		dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell ACK (count=%d)\n",
+		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell ACK (count=%d)\n",
 				ioc->name, count));
 		return count;
 	}
@@ -4030,7 +4260,7 @@
 	}
 
 	if (cntdn) {
-		dprintk((MYIOC_s_INFO_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
+		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell INT (cnt=%d) howlong=%d\n",
 				ioc->name, count, howlong));
 		return count;
 	}
@@ -4082,7 +4312,7 @@
 		}
 	}
 
-	dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
+	dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitCnt=%d First handshake reply word=%08x%s\n",
 			ioc->name, t, le32_to_cpu(*(u32 *)hs_reply),
 			failcnt ? " - MISSING DOORBELL HANDSHAKE!" : ""));
 
@@ -4118,10 +4348,10 @@
 	}
 #endif
 
-	dhsprintk((MYIOC_s_INFO_FMT "Got Handshake reply:\n", ioc->name));
-	DBG_DUMP_REPLY_FRAME(mptReply)
+	dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Got Handshake reply:\n", ioc->name));
+	DBG_DUMP_REPLY_FRAME(ioc, (u32 *)mptReply)
 
-	dhsprintk((MYIOC_s_INFO_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
+	dhsprintk(ioc, printk(MYIOC_s_DEBUG_FMT "WaitForDoorbell REPLY WaitCnt=%d (sz=%d)\n",
 			ioc->name, t, u16cnt/2));
 	return u16cnt/2;
 }
@@ -4546,7 +4776,7 @@
 
 		ioc->spi_data.nvram = (int *) mem;
 
-		dprintk((MYIOC_s_INFO_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
+		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SCSI device NVRAM settings @ %p, sz=%d\n",
 			ioc->name, ioc->spi_data.nvram, sz));
 	}
 
@@ -4582,7 +4812,8 @@
 				ioc->spi_data.minSyncFactor = MPT_ASYNC;
 				ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN;
 				rc = 1;
-				ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n",
+				ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+					"Unable to read PortPage0 minSyncFactor=%x\n",
 					ioc->name, ioc->spi_data.minSyncFactor));
 			} else {
 				/* Save the Port Page 0 data
@@ -4593,7 +4824,8 @@
 
 				if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) {
 					ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS;
-					ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n",
+					ddvprintk(ioc, printk(KERN_INFO MYNAM
+						" :%s noQas due to Capabilities=%x\n",
 						ioc->name, pPP0->Capabilities));
 				}
 				ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0;
@@ -4602,7 +4834,8 @@
 					ioc->spi_data.maxSyncOffset = (u8) (data >> 16);
 					data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK;
 					ioc->spi_data.minSyncFactor = (u8) (data >> 8);
-					ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n",
+					ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+						"PortPage0 minSyncFactor=%x\n",
 						ioc->name, ioc->spi_data.minSyncFactor));
 				} else {
 					ioc->spi_data.maxSyncOffset = 0;
@@ -4618,7 +4851,8 @@
 
 					if (ioc->spi_data.minSyncFactor < MPT_ULTRA) {
 						ioc->spi_data.minSyncFactor = MPT_ULTRA;
-						ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n",
+						ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+							"HVD or SE detected, minSyncFactor=%x\n",
 							ioc->name, ioc->spi_data.minSyncFactor));
 					}
 				}
@@ -4734,10 +4968,10 @@
 	ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion;
 	ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength;
 
-	dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n",
+	dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 0: version %d length %d\n",
 			ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length));
 
-	dcprintk((MYIOC_s_INFO_FMT "Headers: 1: version %d length %d\n",
+	dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Headers: 1: version %d length %d\n",
 			ioc->name, ioc->spi_data.sdp1version, ioc->spi_data.sdp1length));
 	return 0;
 }
@@ -5146,12 +5380,12 @@
 	cfg.physAddr = ioc1_dma;
 	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
 	if (mpt_config(ioc, &cfg) == 0) {
-		
+
 		tmp = le32_to_cpu(pIoc1->Flags) & MPI_IOCPAGE1_REPLY_COALESCING;
 		if (tmp == MPI_IOCPAGE1_REPLY_COALESCING) {
 			tmp = le32_to_cpu(pIoc1->CoalescingTimeout);
 
-			dprintk((MYIOC_s_INFO_FMT "Coalescing Enabled Timeout = %d\n",
+			dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Coalescing Enabled Timeout = %d\n",
 					ioc->name, tmp));
 
 			if (tmp > MPT_COALESCING_TIMEOUT) {
@@ -5162,26 +5396,29 @@
 				cfg.dir = 1;
 				cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT;
 				if (mpt_config(ioc, &cfg) == 0) {
-					dprintk((MYIOC_s_INFO_FMT "Reset Current Coalescing Timeout to = %d\n",
+					dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Reset Current Coalescing Timeout to = %d\n",
 							ioc->name, MPT_COALESCING_TIMEOUT));
 
 					cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_NVRAM;
 					if (mpt_config(ioc, &cfg) == 0) {
-						dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout to = %d\n",
+						dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+								"Reset NVRAM Coalescing Timeout to = %d\n",
 								ioc->name, MPT_COALESCING_TIMEOUT));
 					} else {
-						dprintk((MYIOC_s_INFO_FMT "Reset NVRAM Coalescing Timeout Failed\n",
-									ioc->name));
+						dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+								"Reset NVRAM Coalescing Timeout Failed\n",
+								ioc->name));
 					}
 
 				} else {
-					dprintk((MYIOC_s_WARN_FMT "Reset of Current Coalescing Timeout Failed!\n",
-								ioc->name));
+					dprintk(ioc, printk(MYIOC_s_WARN_FMT
+						"Reset of Current Coalescing Timeout Failed!\n",
+						ioc->name));
 				}
 			}
 
 		} else {
-			dprintk((MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
+			dprintk(ioc, printk(MYIOC_s_WARN_FMT "Coalescing Disabled\n", ioc->name));
 		}
 	}
 
@@ -5190,6 +5427,49 @@
 	return;
 }
 
+static void
+mpt_get_manufacturing_pg_0(MPT_ADAPTER *ioc)
+{
+	CONFIGPARMS		cfg;
+	ConfigPageHeader_t	hdr;
+	dma_addr_t		buf_dma;
+	ManufacturingPage0_t	*pbuf = NULL;
+
+	memset(&cfg, 0 , sizeof(CONFIGPARMS));
+	memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
+
+	hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING;
+	cfg.cfghdr.hdr = &hdr;
+	cfg.physAddr = -1;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.timeout = 10;
+
+	if (mpt_config(ioc, &cfg) != 0)
+		goto out;
+
+	if (!cfg.cfghdr.hdr->PageLength)
+		goto out;
+
+	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+	pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma);
+	if (!pbuf)
+		goto out;
+
+	cfg.physAddr = buf_dma;
+
+	if (mpt_config(ioc, &cfg) != 0)
+		goto out;
+
+	memcpy(ioc->board_name, pbuf->BoardName, sizeof(ioc->board_name));
+	memcpy(ioc->board_assembly, pbuf->BoardAssembly, sizeof(ioc->board_assembly));
+	memcpy(ioc->board_tracer, pbuf->BoardTracerNumber, sizeof(ioc->board_tracer));
+
+	out:
+
+	if (pbuf)
+		pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma);
+}
+
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *	SendEventNotification - Send EventNotification (on or off) request to adapter
@@ -5203,13 +5483,13 @@
 
 	evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc);
 	if (evnp == NULL) {
-		devtverboseprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
+		devtverboseprintk(ioc, printk(MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n",
 				ioc->name));
 		return 0;
 	}
 	memset(evnp, 0, sizeof(*evnp));
 
-	devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
+	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp));
 
 	evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION;
 	evnp->ChainOffset = 0;
@@ -5233,12 +5513,12 @@
 	EventAck_t	*pAck;
 
 	if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
-		dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
+		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
 		    ioc->name,__FUNCTION__));
 		return -1;
 	}
 
-	devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
+	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending EventAck\n", ioc->name));
 
 	pAck->Function     = MPI_FUNCTION_EVENT_ACK;
 	pAck->ChainOffset  = 0;
@@ -5283,7 +5563,7 @@
 	 */
 	in_isr = in_interrupt();
 	if (in_isr) {
-		dcprintk((MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
+		dcprintk(ioc, printk(MYIOC_s_WARN_FMT "Config request not allowed in ISR context!\n",
 				ioc->name));
 		return -EPERM;
 	}
@@ -5291,7 +5571,7 @@
 	/* Get and Populate a free Frame
 	 */
 	if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
-		dcprintk((MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
+		dcprintk(ioc, printk(MYIOC_s_WARN_FMT "mpt_config: no msg frames!\n",
 				ioc->name));
 		return -EAGAIN;
 	}
@@ -5336,13 +5616,13 @@
 	if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) {
 		flagsLength |= pExtHdr->ExtPageLength * 4;
 
-		dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
+		dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
 			ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action));
 	}
 	else {
 		flagsLength |= pCfg->cfghdr.hdr->PageLength * 4;
 
-		dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n",
+		dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Sending Config request type %d, page %d and action %d\n",
 			ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action));
 	}
 
@@ -5392,7 +5672,7 @@
 {
 	MPT_ADAPTER *ioc = (MPT_ADAPTER *) data;
 
-	dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired! \n", ioc->name));
+	dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired! \n", ioc->name));
 
 	/* Perform a FW reload */
 	if (mpt_HardResetHandler(ioc, NO_SLEEP) < 0)
@@ -5402,7 +5682,7 @@
 	 * Hard reset clean-up will wake up
 	 * process and free all resources.
 	 */
-	dcprintk((MYIOC_s_WARN_FMT "mpt_timer_expired complete!\n", ioc->name));
+	dcprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mpt_timer_expired complete!\n", ioc->name));
 
 	return;
 }
@@ -5421,7 +5701,7 @@
 	CONFIGPARMS *pCfg;
 	unsigned long flags;
 
-	dprintk((KERN_WARNING MYNAM
+	dprintk(ioc, printk(KERN_DEBUG MYNAM
 			": IOC %s_reset routed to MPT base driver!\n",
 			reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
 			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
@@ -5792,7 +6072,7 @@
 	int		 rc;
 	unsigned long	 flags;
 
-	dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name));
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler Entered!\n", ioc->name));
 #ifdef MFCNT
 	printk(MYIOC_s_INFO_FMT "HardResetHandler Entered!\n", ioc->name);
 	printk("MF count 0x%x !\n", ioc->mfcnt);
@@ -5824,11 +6104,11 @@
 
 		for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
 			if (MptResetHandlers[ii]) {
-				dtmprintk((MYIOC_s_INFO_FMT "Calling IOC reset_setup handler #%d\n",
+				dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling IOC reset_setup handler #%d\n",
 						ioc->name, ii));
 				r += mpt_signal_reset(ii, ioc, MPT_IOC_SETUP_RESET);
 				if (ioc->alt_ioc) {
-					dtmprintk((MYIOC_s_INFO_FMT "Calling alt-%s setup reset handler #%d\n",
+					dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Calling alt-%s setup reset handler #%d\n",
 							ioc->name, ioc->alt_ioc->name, ii));
 					r += mpt_signal_reset(ii, ioc->alt_ioc, MPT_IOC_SETUP_RESET);
 				}
@@ -5850,7 +6130,7 @@
 		ioc->alt_ioc->diagPending = 0;
 	spin_unlock_irqrestore(&ioc->diagLock, flags);
 
-	dtmprintk((MYIOC_s_INFO_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "HardResetHandler rc = %d!\n", ioc->name, rc));
 
 	return rc;
 }
@@ -6251,16 +6531,18 @@
 	}
 
 	EventDescriptionStr(event, evData0, evStr);
-	devtprintk((MYIOC_s_INFO_FMT "MPT event:(%02Xh) : %s\n",
+	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event:(%02Xh) : %s\n",
 			ioc->name,
 			event,
 			evStr));
 
-#if defined(MPT_DEBUG) || defined(MPT_DEBUG_VERBOSE_EVENTS)
-	printk(KERN_INFO MYNAM ": Event data:\n" KERN_INFO);
+#ifdef CONFIG_FUSION_LOGGING
+	devtverboseprintk(ioc, printk(KERN_DEBUG MYNAM
+	    ": Event data:\n"));
 	for (ii = 0; ii < evDataLen; ii++)
-		printk(" %08x", le32_to_cpu(pEventReply->Data[ii]));
-	printk("\n");
+		devtverboseprintk(ioc, printk(" %08x",
+		    le32_to_cpu(pEventReply->Data[ii])));
+	devtverboseprintk(ioc, printk(KERN_DEBUG "\n"));
 #endif
 
 	/*
@@ -6315,7 +6597,7 @@
 	 */
 	for (ii=MPT_MAX_PROTOCOL_DRIVERS-1; ii; ii--) {
 		if (MptEvHandlers[ii]) {
-			devtverboseprintk((MYIOC_s_INFO_FMT "Routing Event to event handler #%d\n",
+			devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Routing Event to event handler #%d\n",
 					ioc->name, ii));
 			r += (*(MptEvHandlers[ii]))(ioc, pEventReply);
 			handlers++;
@@ -6327,10 +6609,10 @@
 	 *  If needed, send (a single) EventAck.
 	 */
 	if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) {
-		devtverboseprintk((MYIOC_s_WARN_FMT
+		devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 			"EventAck required\n",ioc->name));
 		if ((ii = SendEventAck(ioc, pEventReply)) != 0) {
-			devtverboseprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n",
+			devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SendEventAck returned %d\n",
 					ioc->name, ii));
 		}
 	}
@@ -6677,7 +6959,6 @@
 			sas_loginfo.dw.code, sas_loginfo.dw.subcode);
 }
 
-#ifdef MPT_DEBUG_REPLY
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 /**
  *	mpt_iocstatus_info_config - IOCSTATUS information for config pages
@@ -6982,7 +7263,6 @@
 
 	printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s\n", ioc->name, status, desc);
 }
-#endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 EXPORT_SYMBOL(mpt_attach);
@@ -7047,11 +7327,7 @@
 
 	/* Register for hard reset handling callbacks.
 	 */
-	if (mpt_reset_register(mpt_base_index, mpt_ioc_reset) == 0) {
-		dprintk((KERN_INFO MYNAM ": Register for IOC reset notification\n"));
-	} else {
-		/* FIXME! */
-	}
+	mpt_reset_register(mpt_base_index, mpt_ioc_reset);
 
 #ifdef CONFIG_PROC_FS
 	(void) procmpt_create();
@@ -7070,8 +7346,6 @@
 fusion_exit(void)
 {
 
-	dexitprintk((KERN_INFO MYNAM ": fusion_exit() called!\n"));
-
 	mpt_reset_deregister(mpt_base_index);
 
 #ifdef CONFIG_PROC_FS
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index 05eb6e5..15ff226 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -186,6 +186,7 @@
  * MPT drivers.  NOTE: Users of these macro defs must
  * themselves define their own MYNAM.
  */
+#define MYIOC_s_DEBUG_FMT		KERN_DEBUG MYNAM ": %s: "
 #define MYIOC_s_INFO_FMT		KERN_INFO MYNAM ": %s: "
 #define MYIOC_s_NOTE_FMT		KERN_NOTICE MYNAM ": %s: "
 #define MYIOC_s_WARN_FMT		KERN_WARNING MYNAM ": %s: WARNING - "
@@ -537,7 +538,15 @@
 	int			 id;		/* Unique adapter id N {0,1,2,...} */
 	int			 pci_irq;	/* This irq           */
 	char			 name[MPT_NAME_LENGTH];	/* "iocN"             */
-	char			*prod_name;	/* "LSIFC9x9"         */
+	char			 prod_name[MPT_NAME_LENGTH];	/* "LSIFC9x9"         */
+	char			 board_name[16];
+	char			 board_assembly[16];
+	char			 board_tracer[16];
+	u16			 nvdata_version_persistent;
+	u16			 nvdata_version_default;
+	int			 debug_level;
+	u8			 io_missing_delay;
+	u8			 device_missing_delay;
 	SYSIF_REGS __iomem	*chip;		/* == c8817000 (mmap) */
 	SYSIF_REGS __iomem	*pio_chip;	/* Programmed IO (downloadboot) */
 	u8			 bus_type;
@@ -711,171 +720,7 @@
 /*
  *  Funky (private) macros...
  */
-#ifdef MPT_DEBUG
-#define dprintk(x)  printk x
-#else
-#define dprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_INIT
-#define dinitprintk(x)  printk x
-#define DBG_DUMP_FW_REQUEST_FRAME(mfp) \
-	{	int  i, n = 10;						\
-		u32 *m = (u32 *)(mfp);					\
-		printk(KERN_INFO " ");					\
-		for (i=0; i<n; i++)					\
-			printk(" %08x", le32_to_cpu(m[i]));		\
-		printk("\n");						\
-	}
-#else
-#define dinitprintk(x)
-#define DBG_DUMP_FW_REQUEST_FRAME(mfp)
-#endif
-
-#ifdef MPT_DEBUG_EXIT
-#define dexitprintk(x)  printk x
-#else
-#define dexitprintk(x)
-#endif
-
-#if defined MPT_DEBUG_FAIL || defined (MPT_DEBUG_SG)
-#define dfailprintk(x) printk x
-#else
-#define dfailprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_HANDSHAKE
-#define dhsprintk(x)  printk x
-#else
-#define dhsprintk(x)
-#endif
-
-#if defined(MPT_DEBUG_EVENTS) || defined(MPT_DEBUG_VERBOSE_EVENTS)
-#define devtprintk(x)  printk x
-#else
-#define devtprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_VERBOSE_EVENTS
-#define devtverboseprintk(x)  printk x
-#else
-#define devtverboseprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_RESET
-#define drsprintk(x)  printk x
-#else
-#define drsprintk(x)
-#endif
-
-//#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
-#if defined(MPT_DEBUG_MSG_FRAME)
-#define dmfprintk(x)  printk x
-#define DBG_DUMP_REQUEST_FRAME(mfp) \
-	{	int  i, n = 24;						\
-		u32 *m = (u32 *)(mfp);					\
-		for (i=0; i<n; i++) {					\
-			if (i && ((i%8)==0))				\
-				printk("\n");				\
-			printk("%08x ", le32_to_cpu(m[i]));		\
-		}							\
-		printk("\n");						\
-	}
-#else
-#define dmfprintk(x)
-#define DBG_DUMP_REQUEST_FRAME(mfp)
-#endif
-
-#ifdef MPT_DEBUG_IRQ
-#define dirqprintk(x)  printk x
-#else
-#define dirqprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_SG
-#define dsgprintk(x)  printk x
-#else
-#define dsgprintk(x)
-#endif
-
-#if defined(MPT_DEBUG_DL) || defined(MPT_DEBUG)
-#define ddlprintk(x)  printk x
-#else
-#define ddlprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_DV
-#define ddvprintk(x)  printk x
-#else
-#define ddvprintk(x)
-#endif
-
-#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY)
-#define ddvtprintk(x)  printk x
-#else
-#define ddvtprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_IOCTL
-#define dctlprintk(x) printk x
-#else
-#define dctlprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_REPLY
-#define dreplyprintk(x) printk x
-#else
-#define dreplyprintk(x)
-#endif
-
-#ifdef DMPT_DEBUG_FC
-#define dfcprintk(x) printk x
-#else
-#define dfcprintk(x)
-#endif
-
-#ifdef MPT_DEBUG_TM
-#define dtmprintk(x) printk x
-#define DBG_DUMP_TM_REQUEST_FRAME(mfp) \
-	{	u32 *m = (u32 *)(mfp);					\
-		int  i, n = 13;						\
-		printk("TM_REQUEST:\n");				\
-		for (i=0; i<n; i++) {					\
-			if (i && ((i%8)==0))				\
-				printk("\n");				\
-			printk("%08x ", le32_to_cpu(m[i]));		\
-		}							\
-		printk("\n");						\
-	}
-#define DBG_DUMP_TM_REPLY_FRAME(mfp) \
-	{	u32 *m = (u32 *)(mfp);					\
-		int  i, n = (le32_to_cpu(m[0]) & 0x00FF0000) >> 16;	\
-		printk("TM_REPLY MessageLength=%d:\n", n);		\
-		for (i=0; i<n; i++) {					\
-			if (i && ((i%8)==0))				\
-				printk("\n");				\
-			printk(" %08x", le32_to_cpu(m[i]));		\
-		}							\
-		printk("\n");						\
-	}
-#else
-#define dtmprintk(x)
-#define DBG_DUMP_TM_REQUEST_FRAME(mfp)
-#define DBG_DUMP_TM_REPLY_FRAME(mfp)
-#endif
-
-#if defined(MPT_DEBUG_CONFIG) || defined(MPT_DEBUG)
-#define dcprintk(x) printk x
-#else
-#define dcprintk(x)
-#endif
-
-#if defined(MPT_DEBUG_SCSI) || defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
-#define dsprintk(x) printk x
-#else
-#define dsprintk(x)
-#endif
-
+#include "mptdebug.h"
 
 #define MPT_INDEX_2_MFPTR(ioc,idx) \
 	(MPT_FRAME_HDR*)( (u8*)(ioc)->req_frames + (ioc)->req_sz * (idx) )
@@ -886,36 +731,6 @@
 #define MPT_INDEX_2_RFPTR(ioc,idx) \
 	(MPT_FRAME_HDR*)( (u8*)(ioc)->reply_frames + (ioc)->req_sz * (idx) )
 
-#if defined(MPT_DEBUG) || defined(MPT_DEBUG_MSG_FRAME)
-#define DBG_DUMP_REPLY_FRAME(mfp) \
-	{	u32 *m = (u32 *)(mfp);					\
-		int  i, n = (le32_to_cpu(m[0]) & 0x00FF0000) >> 16;	\
-		printk(KERN_INFO " ");					\
-		for (i=0; i<n; i++)					\
-			printk(" %08x", le32_to_cpu(m[i]));		\
-		printk("\n");						\
-	}
-#define DBG_DUMP_REQUEST_FRAME_HDR(mfp) \
-	{	int  i, n = 3;						\
-		u32 *m = (u32 *)(mfp);					\
-		printk(KERN_INFO " ");					\
-		for (i=0; i<n; i++)					\
-			printk(" %08x", le32_to_cpu(m[i]));		\
-		printk("\n");						\
-	}
-#else
-#define DBG_DUMP_REPLY_FRAME(mfp)
-#define DBG_DUMP_REQUEST_FRAME_HDR(mfp)
-#endif
-
-// debug sas wide ports
-#ifdef MPT_DEBUG_SAS_WIDE
-#define dsaswideprintk(x) printk x
-#else
-#define dsaswideprintk(x)
-#endif
-
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 #define SCSI_STD_SENSE_BYTES    18
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index 58e6c31..89695e7 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -181,7 +181,7 @@
 mptctl_syscall_down(MPT_ADAPTER *ioc, int nonblock)
 {
 	int rc = 0;
-	dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock));
+//	dctlprintk(ioc, printk(KERN_DEBUG MYNAM "::mptctl_syscall_down(%p,%d) called\n", ioc, nonblock));
 
 	if (nonblock) {
 		if (!mutex_trylock(&ioc->ioctl->ioctl_mutex))
@@ -190,7 +190,7 @@
 		if (mutex_lock_interruptible(&ioc->ioctl->ioctl_mutex))
 			rc = -ERESTARTSYS;
 	}
-	dctlprintk((KERN_INFO MYNAM "::mptctl_syscall_down return %d\n", rc));
+//	dctlprintk(ioc, printk(KERN_DEBUG MYNAM "::mptctl_syscall_down return %d\n", rc));
 	return rc;
 }
 
@@ -209,18 +209,19 @@
 	u16 iocStatus;
 	u8 cmd;
 
-	dctlprintk(("mptctl_reply()!\n"));
 	if (req)
 		 cmd = req->u.hdr.Function;
 	else
 		return 1;
+	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tcompleting mpi function (0x%02X), req=%p, "
+	    "reply=%p\n", ioc->name,  req->u.hdr.Function, req, reply));
 
 	if (ioc->ioctl) {
 
 		if (reply==NULL) {
 
-			dctlprintk(("mptctl_reply() NULL Reply "
-				"Function=%x!\n", cmd));
+			dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_reply() NULL Reply "
+				"Function=%x!\n", ioc->name, cmd));
 
 			ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
 			ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
@@ -233,14 +234,9 @@
 
 		}
 
-		dctlprintk(("mptctl_reply() with req=%p "
-			"reply=%p Function=%x!\n", req, reply, cmd));
-
 		/* Copy the reply frame (which much exist
 		 * for non-SCSI I/O) to the IOC structure.
 		 */
-		dctlprintk(("Copying Reply Frame @%p to ioc%d!\n",
-			reply, ioc->id));
 		memcpy(ioc->ioctl->ReplyFrame, reply,
 			min(ioc->reply_sz, 4*reply->u.reply.MsgLength));
 		ioc->ioctl->status |= MPT_IOCTL_STATUS_RF_VALID;
@@ -252,8 +248,24 @@
 		if (iocStatus  == MPI_IOCSTATUS_SUCCESS)
 			ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD;
 
+		if (iocStatus || reply->u.reply.IOCLogInfo)
+			dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\tiocstatus (0x%04X), "
+				"loginfo (0x%08X)\n", ioc->name,
+				iocStatus,
+				le32_to_cpu(reply->u.reply.IOCLogInfo)));
+
 		if ((cmd == MPI_FUNCTION_SCSI_IO_REQUEST) ||
 			(cmd == MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
+
+			if (reply->u.sreply.SCSIStatus || reply->u.sreply.SCSIState)
+				dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+					"\tscsi_status (0x%02x), scsi_state (0x%02x), "
+					"tag = (0x%04x), transfer_count (0x%08x)\n", ioc->name,
+					reply->u.sreply.SCSIStatus,
+					reply->u.sreply.SCSIState,
+					le16_to_cpu(reply->u.sreply.TaskTag),
+					le32_to_cpu(reply->u.sreply.TransferCount)));
+
 			ioc->ioctl->reset &= ~MPTCTL_RESET_OK;
 
 			if ((iocStatus == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN) ||
@@ -298,8 +310,8 @@
 {
 	int rc = 1;
 
-	dctlprintk((KERN_NOTICE MYNAM ": Timeout Expired! Host %d\n",
-				ioctl->ioc->id));
+	dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT ": Timeout Expired! Host %d\n",
+				ioctl->ioc->name, ioctl->ioc->id));
 	if (ioctl == NULL)
 		return;
 
@@ -311,7 +323,7 @@
 		/* Issue a reset for this device.
 		 * The IOC is not responding.
 		 */
-		dctlprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
+		dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
 			 ioctl->ioc->name));
 		mpt_HardResetHandler(ioctl->ioc, CAN_SLEEP);
 	}
@@ -350,14 +362,14 @@
 	/* Send request
 	 */
 	if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc)) == NULL) {
-		dctlprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n",
+		dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt, no msg frames!!\n",
 				ioctl->ioc->name));
 
 		mptctl_free_tm_flags(ioctl->ioc);
 		return -ENOMEM;
 	}
 
-	dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
+	dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
 			ioctl->ioc->name, mf));
 
 	pScsiTm = (SCSITaskMgmt_t *) mf;
@@ -377,15 +389,15 @@
 		pScsiTm->Reserved2[ii] = 0;
 
 	pScsiTm->TaskMsgContext = 0;
-	dtmprintk((MYIOC_s_INFO_FMT
+	dtmprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT
 		"mptctl_bus_reset: issued.\n", ioctl->ioc->name));
 
-	DBG_DUMP_TM_REQUEST_FRAME((u32 *)mf);
+	DBG_DUMP_TM_REQUEST_FRAME(ioctl->ioc, (u32 *)mf);
 
 	ioctl->wait_done=0;
 	if ((retval = mpt_send_handshake_request(mptctl_id, ioctl->ioc,
 	     sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
-		dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
+		dfailprintk(ioctl->ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
 			" (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
 			hd->ioc, mf));
 		goto mptctl_bus_reset_done;
@@ -456,7 +468,7 @@
 mptctl_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
 {
 	MPT_IOCTL *ioctl = ioc->ioctl;
-	dctlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to IOCTL driver!\n",
+	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": IOC %s_reset routed to IOCTL driver!\n",ioc->name,
 		reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
 		reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
 
@@ -487,7 +499,8 @@
 
 	event = le32_to_cpu(pEvReply->Event) & 0xFF;
 
-	dctlprintk(("%s() called\n", __FUNCTION__));
+	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s() called\n",
+	    ioc->name, __FUNCTION__));
 	if(async_queue == NULL)
 		return 1;
 
@@ -497,8 +510,10 @@
 	 */
 	 if (event == 0x21 ) {
 		ioc->aen_event_read_flag=1;
-		dctlprintk(("Raised SIGIO to application\n"));
-		devtverboseprintk(("Raised SIGIO to application\n"));
+		dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Raised SIGIO to application\n",
+		    ioc->name));
+		devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "Raised SIGIO to application\n", ioc->name));
 		kill_fasync(&async_queue, SIGIO, POLL_IN);
 		return 1;
 	 }
@@ -515,8 +530,10 @@
 	 */
 	if (ioc->events && (ioc->eventTypes & ( 1 << event))) {
 		ioc->aen_event_read_flag=1;
-		dctlprintk(("Raised SIGIO to application\n"));
-		devtverboseprintk(("Raised SIGIO to application\n"));
+		dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "Raised SIGIO to application\n", ioc->name));
+		devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		    "Raised SIGIO to application\n", ioc->name));
 		kill_fasync(&async_queue, SIGIO, POLL_IN);
 	}
 	return 1;
@@ -530,14 +547,12 @@
 	list_for_each_entry(ioc, &ioc_list, list)
 		ioc->aen_event_read_flag=0;
 
-	dctlprintk(("%s() called\n", __FUNCTION__));
 	return fasync_helper(fd, filep, mode, &async_queue);
 }
 
 static int
 mptctl_release(struct inode *inode, struct file *filep)
 {
-	dctlprintk(("%s() called\n", __FUNCTION__));
 	return fasync_helper(-1, filep, 0, &async_queue);
 }
 
@@ -558,8 +573,6 @@
 	int ret;
 	MPT_ADAPTER *iocp = NULL;
 
-	dctlprintk(("mptctl_ioctl() called\n"));
-
 	if (copy_from_user(&khdr, uhdr, sizeof(khdr))) {
 		printk(KERN_ERR "%s::mptctl_ioctl() @%d - "
 				"Unable to copy mpt_ioctl_header data @ %p\n",
@@ -574,13 +587,13 @@
 	iocnumX = khdr.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		dctlprintk((KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnumX));
+		printk(KERN_DEBUG "%s::mptctl_ioctl() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnumX);
 		return -ENODEV;
 	}
 
 	if (!iocp->active) {
-		printk(KERN_ERR "%s::mptctl_ioctl() @%d - Controller disabled.\n",
+		printk(KERN_DEBUG "%s::mptctl_ioctl() @%d - Controller disabled.\n",
 				__FILE__, __LINE__);
 		return -EFAULT;
 	}
@@ -612,8 +625,6 @@
 	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
 		return ret;
 
-	dctlprintk((MYIOC_s_INFO_FMT ": mptctl_ioctl()\n", iocp->name));
-
 	if (cmd == MPTFWDOWNLOAD)
 		ret = mptctl_fw_download(arg);
 	else if (cmd == MPTCOMMAND)
@@ -648,8 +659,6 @@
 	struct mpt_ioctl_diag_reset krinfo;
 	MPT_ADAPTER		*iocp;
 
-	dctlprintk((KERN_INFO "mptctl_do_reset called.\n"));
-
 	if (copy_from_user(&krinfo, urinfo, sizeof(struct mpt_ioctl_diag_reset))) {
 		printk(KERN_ERR "%s@%d::mptctl_do_reset - "
 				"Unable to copy mpt_ioctl_diag_reset struct @ %p\n",
@@ -658,11 +667,14 @@
 	}
 
 	if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) {
-		dctlprintk((KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n",
-				__FILE__, __LINE__, krinfo.hdr.iocnum));
+		printk(KERN_DEBUG "%s@%d::mptctl_do_reset - ioc%d not found!\n",
+				__FILE__, __LINE__, krinfo.hdr.iocnum);
 		return -ENODEV; /* (-6) No such device or address */
 	}
 
+	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "mptctl_do_reset called.\n",
+	    iocp->name));
+
 	if (mpt_HardResetHandler(iocp, CAN_SLEEP) != 0) {
 		printk (KERN_ERR "%s@%d::mptctl_do_reset - reset failed.\n",
 			__FILE__, __LINE__);
@@ -695,7 +707,6 @@
 	struct mpt_fw_xfer __user *ufwdl = (void __user *) arg;
 	struct mpt_fw_xfer	 kfwdl;
 
-	dctlprintk((KERN_INFO "mptctl_fwdl called. mptctl_id = %xh\n", mptctl_id)); //tc
 	if (copy_from_user(&kfwdl, ufwdl, sizeof(struct mpt_fw_xfer))) {
 		printk(KERN_ERR "%s@%d::_ioctl_fwdl - "
 				"Unable to copy mpt_fw_xfer struct @ %p\n",
@@ -744,15 +755,8 @@
 	u16			 iocstat;
 	pFWDownloadReply_t	 ReplyMsg = NULL;
 
-	dctlprintk(("mptctl_do_fwdl called. mptctl_id = %xh.\n", mptctl_id));
-
-	dctlprintk(("DbG: kfwdl.bufp  = %p\n", ufwbuf));
-	dctlprintk(("DbG: kfwdl.fwlen = %d\n", (int)fwlen));
-	dctlprintk(("DbG: kfwdl.ioc   = %04xh\n", ioc));
-
 	if (mpt_verify_adapter(ioc, &iocp) < 0) {
-		dctlprintk(("ioctl_fwdl - ioc%d not found!\n",
-				 ioc));
+		printk(KERN_DEBUG "ioctl_fwdl - ioc%d not found!\n",				 ioc);
 		return -ENODEV; /* (-6) No such device or address */
 	} else {
 
@@ -761,6 +765,16 @@
 		if ((mf = mpt_get_msg_frame(mptctl_id, iocp)) == NULL)
 			return -EAGAIN;
 	}
+
+	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT
+	    "mptctl_do_fwdl called. mptctl_id = %xh.\n", iocp->name, mptctl_id));
+	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.bufp  = %p\n",
+	    iocp->name, ufwbuf));
+	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.fwlen = %d\n",
+	    iocp->name, (int)fwlen));
+	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: kfwdl.ioc   = %04xh\n",
+	    iocp->name, ioc));
+
 	dlmsg = (FWDownload_t*) mf;
 	ptsge = (FWDownloadTCSGE_t *) &dlmsg->SGL;
 	sgOut = (char *) (ptsge + 1);
@@ -829,7 +843,8 @@
 		goto fwdl_out;
 	}
 
-	dctlprintk(("DbG: sgl buffer  = %p, sgfrags = %d\n", sgl, numfrags));
+	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "DbG: sgl buffer = %p, sgfrags = %d\n",
+	    iocp->name, sgl, numfrags));
 
 	/*
 	 * Parse SG list, copying sgl itself,
@@ -865,15 +880,7 @@
 		sgOut += (sizeof(dma_addr_t) + sizeof(u32));
 	}
 
-#ifdef MPT_DEBUG
-	{
-		u32 *m = (u32 *)mf;
-		printk(KERN_INFO MYNAM ": F/W download request:\n" KERN_INFO " ");
-		for (i=0; i < 7+numfrags*2; i++)
-			printk(" %08x", le32_to_cpu(m[i]));
-		printk("\n");
-	}
-#endif
+	DBG_DUMP_FW_DOWNLOAD(iocp, (u32 *)mf, numfrags);
 
 	/*
 	 * Finally, perform firmware download.
@@ -1049,13 +1056,11 @@
 	*frags = numfrags;
 	*blp = buflist;
 
-	dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
-			   "%d SG frags generated!\n",
-			   numfrags));
+	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: kbuf_alloc_2_sgl() - "
+	   "%d SG frags generated!\n", ioc->name, numfrags));
 
-	dctlprintk((KERN_INFO MYNAM "-SG: kbuf_alloc_2_sgl() - "
-			   "last (big) alloc_sz=%d\n",
-			   alloc_sz));
+	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: kbuf_alloc_2_sgl() - "
+	   "last (big) alloc_sz=%d\n", ioc->name, alloc_sz));
 
 	return sglbuf;
 
@@ -1139,7 +1144,8 @@
 
 	pci_free_consistent(ioc->pcidev, MAX_SGL_BYTES, sgl, sgl_dma);
 	kfree(buflist);
-	dctlprintk((KERN_INFO MYNAM "-SG: Free'd 1 SGL buf + %d kbufs!\n", n));
+	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "-SG: Free'd 1 SGL buf + %d kbufs!\n",
+	    ioc->name, n));
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1166,7 +1172,6 @@
 	struct scsi_device 	*sdev;
 	VirtDevice		*vdev;
 
-	dctlprintk((": mptctl_getiocinfo called.\n"));
 	/* Add of PCI INFO results in unaligned access for
 	 * IA64 and Sparc. Reset long to int. Return no PCI
 	 * data for obsolete format.
@@ -1199,8 +1204,8 @@
 
 	if (((iocnum = mpt_verify_adapter(karg->hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dctlprintk((KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum));
+		printk(KERN_DEBUG "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
 		kfree(karg);
 		return -ENODEV;
 	}
@@ -1214,6 +1219,9 @@
 		return -EFAULT;
 	}
 
+	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_getiocinfo called.\n",
+	    ioc->name));
+
 	/* Fill in the data and return the structure to the calling
 	 * program
 	 */
@@ -1320,7 +1328,6 @@
 	u8			port;
 	struct scsi_device 	*sdev;
 
-	dctlprintk(("mptctl_gettargetinfo called.\n"));
 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_targetinfo))) {
 		printk(KERN_ERR "%s@%d::mptctl_gettargetinfo - "
 			"Unable to read in mpt_ioctl_targetinfo struct @ %p\n",
@@ -1330,11 +1337,13 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dctlprintk((KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum));
+		printk(KERN_DEBUG "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
 		return -ENODEV;
 	}
 
+	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_gettargetinfo called.\n",
+	    ioc->name));
 	/* Get the port number and set the maximum number of bytes
 	 * in the returned structure.
 	 * Ignore the port setting.
@@ -1434,7 +1443,6 @@
 	MPT_ADAPTER *ioc;
 	int iocnum;
 
-	dctlprintk(("mptctl_readtest called.\n"));
 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_test))) {
 		printk(KERN_ERR "%s@%d::mptctl_readtest - "
 			"Unable to read in mpt_ioctl_test struct @ %p\n",
@@ -1444,11 +1452,13 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dctlprintk((KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum));
+		printk(KERN_DEBUG "%s::mptctl_readtest() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
 		return -ENODEV;
 	}
 
+	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_readtest called.\n",
+	    ioc->name));
 	/* Fill in the data and return the structure to the calling
 	 * program
 	 */
@@ -1494,7 +1504,6 @@
 	MPT_ADAPTER *ioc;
 	int iocnum;
 
-	dctlprintk(("mptctl_eventquery called.\n"));
 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventquery))) {
 		printk(KERN_ERR "%s@%d::mptctl_eventquery - "
 			"Unable to read in mpt_ioctl_eventquery struct @ %p\n",
@@ -1504,11 +1513,13 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dctlprintk((KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum));
+		printk(KERN_DEBUG "%s::mptctl_eventquery() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
 		return -ENODEV;
 	}
 
+	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventquery called.\n",
+	    ioc->name));
 	karg.eventEntries = MPTCTL_EVENT_LOG_SIZE;
 	karg.eventTypes = ioc->eventTypes;
 
@@ -1532,7 +1543,6 @@
 	MPT_ADAPTER *ioc;
 	int iocnum;
 
-	dctlprintk(("mptctl_eventenable called.\n"));
 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventenable))) {
 		printk(KERN_ERR "%s@%d::mptctl_eventenable - "
 			"Unable to read in mpt_ioctl_eventenable struct @ %p\n",
@@ -1542,11 +1552,13 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dctlprintk((KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum));
+		printk(KERN_DEBUG "%s::mptctl_eventenable() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
 		return -ENODEV;
 	}
 
+	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventenable called.\n",
+	    ioc->name));
 	if (ioc->events == NULL) {
 		/* Have not yet allocated memory - do so now.
 		 */
@@ -1579,7 +1591,6 @@
 	int			 iocnum;
 	int			 numBytes, maxEvents, max;
 
-	dctlprintk(("mptctl_eventreport called.\n"));
 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_eventreport))) {
 		printk(KERN_ERR "%s@%d::mptctl_eventreport - "
 			"Unable to read in mpt_ioctl_eventreport struct @ %p\n",
@@ -1589,10 +1600,12 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dctlprintk((KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum));
+		printk(KERN_DEBUG "%s::mptctl_eventreport() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
 		return -ENODEV;
 	}
+	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_eventreport called.\n",
+	    ioc->name));
 
 	numBytes = karg.hdr.maxDataSize - sizeof(mpt_ioctl_header);
 	maxEvents = numBytes/sizeof(MPT_IOCTL_EVENTS);
@@ -1632,7 +1645,6 @@
 	int			 iocnum;
 	int			 newFwSize;
 
-	dctlprintk(("mptctl_replace_fw called.\n"));
 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_replace_fw))) {
 		printk(KERN_ERR "%s@%d::mptctl_replace_fw - "
 			"Unable to read in mpt_ioctl_replace_fw struct @ %p\n",
@@ -1642,11 +1654,13 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dctlprintk((KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum));
+		printk(KERN_DEBUG "%s::mptctl_replace_fw() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
 		return -ENODEV;
 	}
 
+	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_replace_fw called.\n",
+	    ioc->name));
 	/* If caching FW, Free the old FW image
 	 */
 	if (ioc->cached_fw == NULL)
@@ -1704,7 +1718,6 @@
 	int		iocnum;
 	int		rc;
 
-	dctlprintk(("mptctl_command called.\n"));
 
 	if (copy_from_user(&karg, uarg, sizeof(struct mpt_ioctl_command))) {
 		printk(KERN_ERR "%s@%d::mptctl_mpt_command - "
@@ -1715,8 +1728,8 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dctlprintk((KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum));
+		printk(KERN_DEBUG "%s::mptctl_mpt_command() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
 		return -ENODEV;
 	}
 
@@ -1756,13 +1769,12 @@
 	ulong 		timeout;
 	struct scsi_device *sdev;
 
-	dctlprintk(("mptctl_do_mpt_command called.\n"));
 	bufIn.kptr = bufOut.kptr = NULL;
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dctlprintk((KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum));
+		printk(KERN_DEBUG "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
 		return -ENODEV;
 	}
 	if (!ioc->ioctl) {
@@ -1816,6 +1828,9 @@
 
 	/* Verify that this request is allowed.
 	 */
+	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sending mpi function (0x%02X), req=%p\n",
+	    ioc->name, hdr->Function, mf));
+
 	switch (hdr->Function) {
 	case MPI_FUNCTION_IOC_FACTS:
 	case MPI_FUNCTION_PORT_FACTS:
@@ -1823,6 +1838,18 @@
 		break;
 
 	case MPI_FUNCTION_CONFIG:
+	{
+		Config_t *config_frame;
+		config_frame = (Config_t *)mf;
+		dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\ttype=0x%02x ext_type=0x%02x "
+		    "number=0x%02x action=0x%02x\n", ioc->name,
+		    config_frame->Header.PageType,
+		    config_frame->ExtPageType,
+		    config_frame->Header.PageNumber,
+		    config_frame->Action));
+		break;
+	}
+
 	case MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND:
 	case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND:
 	case MPI_FUNCTION_FW_UPLOAD:
@@ -2158,12 +2185,12 @@
 	ioc->ioctl->wait_done = 0;
 	if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) {
 
-		DBG_DUMP_TM_REQUEST_FRAME((u32 *)mf);
+		DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
 
 		if (mpt_send_handshake_request(mptctl_id, ioc,
 			sizeof(SCSITaskMgmt_t), (u32*)mf,
 			CAN_SLEEP) != 0) {
-			dfailprintk((MYIOC_s_ERR_FMT "_send_handshake FAILED!"
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT "_send_handshake FAILED!"
 				" (ioc %p, mf %p) \n", ioc->name,
 				ioc, mf));
 			mptctl_free_tm_flags(ioc);
@@ -2303,7 +2330,6 @@
 	MPT_FRAME_HDR		*mf = NULL;
 	MPIHeader_t		*mpi_hdr;
 
-	dctlprintk((": mptctl_hp_hostinfo called.\n"));
 	/* Reset long to int. Should affect IA64 and SPARC only
 	 */
 	if (data_size == sizeof(hp_host_info_t))
@@ -2322,10 +2348,12 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 	    (ioc == NULL)) {
-		dctlprintk((KERN_ERR "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum));
+		printk(KERN_DEBUG "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
 		return -ENODEV;
 	}
+	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_hostinfo called.\n",
+	    ioc->name));
 
 	/* Fill in the data and return the structure to the calling
 	 * program
@@ -2441,7 +2469,7 @@
 	 * Gather ISTWI(Industry Standard Two Wire Interface) Data
 	 */
 	if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) {
-		dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
+		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
 		    ioc->name,__FUNCTION__));
 		goto out;
 	}
@@ -2474,7 +2502,7 @@
 	     HZ*MPT_IOCTL_DEFAULT_TIMEOUT /* 10 sec */);
 
 	if(rc <=0 && (ioc->ioctl->wait_done != 1 )) {
-		/* 
+		/*
 		 * Now we need to reset the board
 		 */
 		mpt_free_msg_frame(ioc, mf);
@@ -2482,7 +2510,7 @@
 		goto out;
 	}
 
-	/* 
+	/*
 	 *ISTWI Data Definition
 	 * pbuf[0] = FW_VERSION = 0x4
 	 * pbuf[1] = Bay Count = 6 or 4 or 2, depending on
@@ -2538,7 +2566,6 @@
 	ConfigPageHeader_t	hdr;
 	int			tmp, np, rc = 0;
 
-	dctlprintk((": mptctl_hp_targetinfo called.\n"));
 	if (copy_from_user(&karg, uarg, sizeof(hp_target_info_t))) {
 		printk(KERN_ERR "%s@%d::mptctl_hp_targetinfo - "
 			"Unable to read in hp_host_targetinfo struct @ %p\n",
@@ -2548,10 +2575,12 @@
 
 	if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) ||
 		(ioc == NULL)) {
-		dctlprintk((KERN_ERR "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
-				__FILE__, __LINE__, iocnum));
+		printk(KERN_DEBUG "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n",
+				__FILE__, __LINE__, iocnum);
 		return -ENODEV;
 	}
+	dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT ": mptctl_hp_targetinfo called.\n",
+	    ioc->name));
 
 	/*  There is nothing to do for FCP parts.
 	 */
@@ -2694,7 +2723,6 @@
 	int nonblock = (filp->f_flags & O_NONBLOCK);
 	int ret;
 
-	dctlprintk((KERN_INFO MYNAM "::compat_mptfwxfer_ioctl() called\n"));
 
 	if (copy_from_user(&kfw32, (char __user *)arg, sizeof(kfw32)))
 		return -EFAULT;
@@ -2703,14 +2731,16 @@
 	iocnumX = kfw32.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		dctlprintk((KERN_ERR MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n",
-				__LINE__, iocnumX));
+		printk(KERN_DEBUG MYNAM "::compat_mptfwxfer_ioctl @%d - ioc%d not found!\n",
+				__LINE__, iocnumX);
 		return -ENODEV;
 	}
 
 	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
 		return ret;
 
+	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "compat_mptfwxfer_ioctl() called\n",
+	    iocp->name));
 	kfw.iocnum = iocnum;
 	kfw.fwlen = kfw32.fwlen;
 	kfw.bufp = compat_ptr(kfw32.bufp);
@@ -2734,8 +2764,6 @@
 	int nonblock = (filp->f_flags & O_NONBLOCK);
 	int ret;
 
-	dctlprintk((KERN_INFO MYNAM "::compat_mpt_command() called\n"));
-
 	if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32)))
 		return -EFAULT;
 
@@ -2743,14 +2771,16 @@
 	iocnumX = karg32.hdr.iocnum & 0xFF;
 	if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) ||
 	    (iocp == NULL)) {
-		dctlprintk((KERN_ERR MYNAM "::compat_mpt_command @%d - ioc%d not found!\n",
-				__LINE__, iocnumX));
+		printk(KERN_DEBUG MYNAM "::compat_mpt_command @%d - ioc%d not found!\n",
+				__LINE__, iocnumX);
 		return -ENODEV;
 	}
 
 	if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0)
 		return ret;
 
+	dctlprintk(iocp, printk(MYIOC_s_DEBUG_FMT "compat_mpt_command() called\n",
+	    iocp->name));
 	/* Copy data to karg */
 	karg.hdr.iocnum = karg32.hdr.iocnum;
 	karg.hdr.port = karg32.hdr.port;
@@ -2878,11 +2908,7 @@
 
 	show_mptmod_ver(my_NAME, my_VERSION);
 
-	if(mpt_device_driver_register(&mptctl_driver,
-	  MPTCTL_DRIVER) != 0 ) {
-		dprintk((KERN_INFO MYNAM
-		": failed to register dd callbacks\n"));
-	}
+	mpt_device_driver_register(&mptctl_driver, MPTCTL_DRIVER);
 
 	/* Register this device */
 	err = misc_register(&mptctl_miscdev);
@@ -2905,16 +2931,8 @@
 		goto out_fail;
 	}
 
-	if (mpt_reset_register(mptctl_id, mptctl_ioc_reset) == 0) {
-		dprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
-	} else {
-		/* FIXME! */
-	}
-
-	if (mpt_event_register(mptctl_id, mptctl_event_process) == 0) {
-		devtverboseprintk((KERN_INFO MYNAM
-		  ": Registered for IOC event notifications\n"));
-	}
+	mpt_reset_register(mptctl_id, mptctl_ioc_reset);
+	mpt_event_register(mptctl_id, mptctl_event_process);
 
 	return 0;
 
@@ -2934,11 +2952,9 @@
 
 	/* De-register reset handler from base module */
 	mpt_reset_deregister(mptctl_id);
-	dprintk((KERN_INFO MYNAM ": Deregistered for IOC reset notifications\n"));
 
 	/* De-register callback handler from base module */
 	mpt_deregister(mptctl_id);
-	printk(KERN_INFO MYNAM ": Deregistered from Fusion MPT base driver\n");
 
         mpt_device_driver_deregister(MPTCTL_DRIVER);
 
diff --git a/drivers/message/fusion/mptdebug.h b/drivers/message/fusion/mptdebug.h
new file mode 100644
index 0000000..ffdb0a6
--- /dev/null
+++ b/drivers/message/fusion/mptdebug.h
@@ -0,0 +1,288 @@
+/*
+ *  linux/drivers/message/fusion/mptdebug.h
+ *      For use with LSI PCI chip/adapter(s)
+ *      running LSI Fusion MPT (Message Passing Technology) firmware.
+ *
+ *  Copyright (c) 1999-2007 LSI Corporation
+ *  (mailto:DL-MPTFusionLinux@lsi.com)
+ *
+ */
+/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
+
+#ifndef MPTDEBUG_H_INCLUDED
+#define MPTDEBUG_H_INCLUDED
+
+/*
+ * debug level can be programmed on the fly via SysFS (hex values)
+ *
+ * Example:  (programming for MPT_DEBUG_EVENTS on host 5)
+ *
+ * echo 8 > /sys/class/scsi_host/host5/debug_level
+ *
+ * --------------------------------------------------------
+ * mpt_debug_level - command line parameter
+ * this allow enabling debug at driver load time (for all iocs)
+ *
+ * Example  (programming for MPT_DEBUG_EVENTS)
+ *
+ * insmod mptbase.ko mpt_debug_level=8
+ *
+ * --------------------------------------------------------
+ * CONFIG_FUSION_LOGGING - enables compiling debug into driver
+ * this can be enabled in the driver Makefile
+ *
+ *
+ * --------------------------------------------------------
+ * Please note most debug prints are set to logging priority = debug
+ * This is the lowest level, and most verbose.  Please refer to manual
+ * pages for syslogd or syslogd-ng on how to configure this.
+ */
+
+#define MPT_DEBUG			0x00000001
+#define MPT_DEBUG_MSG_FRAME		0x00000002
+#define MPT_DEBUG_SG			0x00000004
+#define MPT_DEBUG_EVENTS		0x00000008
+#define MPT_DEBUG_VERBOSE_EVENTS	0x00000010
+#define MPT_DEBUG_INIT			0x00000020
+#define MPT_DEBUG_EXIT			0x00000040
+#define MPT_DEBUG_FAIL			0x00000080
+#define MPT_DEBUG_TM			0x00000100
+#define MPT_DEBUG_DV			0x00000200
+#define MPT_DEBUG_REPLY			0x00000400
+#define MPT_DEBUG_HANDSHAKE		0x00000800
+#define MPT_DEBUG_CONFIG		0x00001000
+#define MPT_DEBUG_DL			0x00002000
+#define MPT_DEBUG_RESET			0x00008000
+#define MPT_DEBUG_SCSI			0x00010000
+#define MPT_DEBUG_IOCTL			0x00020000
+#define MPT_DEBUG_FC			0x00080000
+#define MPT_DEBUG_SAS			0x00100000
+#define MPT_DEBUG_SAS_WIDE		0x00200000
+
+/*
+ * CONFIG_FUSION_LOGGING - enabled in Kconfig
+ */
+
+#ifdef CONFIG_FUSION_LOGGING
+#define MPT_CHECK_LOGGING(IOC, CMD, BITS)			\
+{								\
+	if (IOC->debug_level & BITS)				\
+		CMD;						\
+}
+#else
+#define MPT_CHECK_LOGGING(IOC, CMD, BITS)
+#endif
+
+
+/*
+ * debug macros
+ */
+
+#define dprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG)
+
+#define dsgprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SG)
+
+#define devtprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENTS)
+
+#define devtverboseprintk(IOC, CMD)		\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_VERBOSE_EVENTS)
+
+#define dinitprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_INIT)
+
+#define dexitprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EXIT)
+
+#define dfailprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_FAIL)
+
+#define dtmprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TM)
+
+#define ddvprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_DV)
+
+#define dreplyprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_REPLY)
+
+#define dhsprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_HANDSHAKE)
+
+#define dcprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CONFIG)
+
+#define ddlprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_DL)
+
+#define drsprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_RESET)
+
+#define dsprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SCSI)
+
+#define dctlprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_IOCTL)
+
+#define dfcprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_FC)
+
+#define dsasprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS)
+
+#define dsaswideprintk(IOC, CMD)		\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE)
+
+
+
+/*
+ * Verbose logging
+ */
+#if defined(MPT_DEBUG_VERBOSE) && defined(CONFIG_FUSION_LOGGING)
+static inline void
+DBG_DUMP_FW_DOWNLOAD(MPT_ADAPTER *ioc, u32  *mfp, int numfrags)
+{
+	int i;
+
+	if (!(ioc->debug_level & MPT_DEBUG))
+		return;
+	printk(KERN_DEBUG "F/W download request:\n");
+	for (i=0; i < 7+numfrags*2; i++)
+		printk(" %08x", le32_to_cpu(mfp[i]));
+	printk("\n");
+}
+
+static inline void
+DBG_DUMP_PUT_MSG_FRAME(MPT_ADAPTER *ioc, u32 *mfp)
+{
+	int	 ii, n;
+
+	if (!(ioc->debug_level & MPT_DEBUG_MSG_FRAME))
+		return;
+	printk(KERN_DEBUG "%s: About to Put msg frame @ %p:\n",
+		ioc->name, mfp);
+	n = ioc->req_sz/4 - 1;
+	while (mfp[n] == 0)
+		n--;
+	for (ii=0; ii<=n; ii++) {
+		if (ii && ((ii%8)==0))
+			printk("\n");
+		printk(" %08x", le32_to_cpu(mfp[ii]));
+	}
+	printk("\n");
+}
+
+static inline void
+DBG_DUMP_FW_REQUEST_FRAME(MPT_ADAPTER *ioc, u32 *mfp)
+{
+	int  i, n;
+
+	if (!(ioc->debug_level & MPT_DEBUG_MSG_FRAME))
+		return;
+	n = 10;
+	printk(KERN_INFO " ");
+	for (i = 0; i < n; i++)
+		printk(" %08x", le32_to_cpu(mfp[i]));
+	printk("\n");
+}
+
+static inline void
+DBG_DUMP_REQUEST_FRAME(MPT_ADAPTER *ioc, u32 *mfp)
+{
+	int  i, n;
+
+	if (!(ioc->debug_level & MPT_DEBUG_MSG_FRAME))
+		return;
+	n = 24;
+	for (i=0; i<n; i++) {
+		if (i && ((i%8)==0))
+			printk("\n");
+		printk("%08x ", le32_to_cpu(mfp[i]));
+	}
+	printk("\n");
+}
+
+static inline void
+DBG_DUMP_REPLY_FRAME(MPT_ADAPTER *ioc, u32 *mfp)
+{
+	int  i, n;
+
+	if (!(ioc->debug_level & MPT_DEBUG_MSG_FRAME))
+		return;
+	n = (le32_to_cpu(mfp[0]) & 0x00FF0000) >> 16;
+	printk(KERN_INFO " ");
+	for (i=0; i<n; i++)
+		printk(" %08x", le32_to_cpu(mfp[i]));
+	printk("\n");
+}
+
+static inline void
+DBG_DUMP_REQUEST_FRAME_HDR(MPT_ADAPTER *ioc, u32 *mfp)
+{
+	int  i, n;
+
+	if (!(ioc->debug_level & MPT_DEBUG_MSG_FRAME))
+		return;
+	n = 3;
+	printk(KERN_INFO " ");
+	for (i=0; i<n; i++)
+		printk(" %08x", le32_to_cpu(mfp[i]));
+	printk("\n");
+}
+
+static inline void
+DBG_DUMP_TM_REQUEST_FRAME(MPT_ADAPTER *ioc, u32 *mfp)
+{
+	int  i, n;
+
+	if (!(ioc->debug_level & MPT_DEBUG_TM))
+		return;
+	n = 13;
+	printk(KERN_DEBUG "TM_REQUEST:\n");
+	for (i=0; i<n; i++) {
+		if (i && ((i%8)==0))
+			printk("\n");
+		printk("%08x ", le32_to_cpu(mfp[i]));
+	}
+	printk("\n");
+}
+
+static inline void
+DBG_DUMP_TM_REPLY_FRAME(MPT_ADAPTER *ioc, u32 *mfp)
+{
+	int  i, n;
+
+	if (!(ioc->debug_level & MPT_DEBUG_TM))
+		return;
+	n = (le32_to_cpu(mfp[0]) & 0x00FF0000) >> 16;
+	printk(KERN_DEBUG "TM_REPLY MessageLength=%d:\n", n);
+	for (i=0; i<n; i++) {
+		if (i && ((i%8)==0))
+			printk("\n");
+		printk(" %08x", le32_to_cpu(mfp[i]));
+	}
+	printk("\n");
+}
+
+#define dmfprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_MSG_FRAME)
+
+# else /* ifdef MPT_DEBUG_MF */
+
+#define DBG_DUMP_FW_DOWNLOAD(IOC, mfp, numfrags)
+#define DBG_DUMP_PUT_MSG_FRAME(IOC, mfp)
+#define DBG_DUMP_FW_REQUEST_FRAME(IOC, mfp)
+#define DBG_DUMP_REQUEST_FRAME(IOC, mfp)
+#define DBG_DUMP_REPLY_FRAME(IOC, mfp)
+#define DBG_DUMP_REQUEST_FRAME_HDR(IOC, mfp)
+#define DBG_DUMP_TM_REQUEST_FRAME(IOC, mfp)
+#define DBG_DUMP_TM_REPLY_FRAME(IOC, mfp)
+
+#define dmfprintk(IOC, CMD)			\
+	MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_MSG_FRAME)
+
+#endif /* defined(MPT_DEBUG_VERBOSE) && defined(CONFIG_FUSION_LOGGING) */
+
+#endif /* ifndef MPTDEBUG_H_INCLUDED */
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index b766445..8422c25 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -130,6 +130,7 @@
 	.max_sectors			= 8192,
 	.cmd_per_lun			= 7,
 	.use_clustering			= ENABLE_CLUSTERING,
+	.shost_attrs			= mptscsih_host_attrs,
 };
 
 /****************************************************************************
@@ -153,6 +154,8 @@
 		PCI_ANY_ID, PCI_ANY_ID },
 	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949E,
 		PCI_ANY_ID, PCI_ANY_ID },
+	{ PCI_VENDOR_ID_BROCADE, MPI_MANUFACTPAGE_DEVICEID_FC949E,
+		PCI_ANY_ID, PCI_ANY_ID },
 	{0}	/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, mptfc_pci_table);
@@ -185,16 +188,18 @@
 			  int (*func)(struct scsi_cmnd *SCpnt),
 			  const char *caller)
 {
+	MPT_SCSI_HOST		*hd;
 	struct scsi_device	*sdev = SCpnt->device;
 	struct Scsi_Host	*shost = sdev->host;
 	struct fc_rport		*rport = starget_to_rport(scsi_target(sdev));
 	unsigned long		flags;
 	int			ready;
 
+	hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
 	spin_lock_irqsave(shost->host_lock, flags);
 	while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) {
 		spin_unlock_irqrestore(shost->host_lock, flags);
-		dfcprintk ((MYIOC_s_INFO_FMT
+		dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
 			"mptfc_block_error_handler.%d: %d:%d, port status is "
 			"DID_IMM_RETRY, deferring %s recovery.\n",
 			((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
@@ -206,7 +211,7 @@
 	spin_unlock_irqrestore(shost->host_lock, flags);
 
 	if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) {
-		dfcprintk ((MYIOC_s_INFO_FMT
+		dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
 			"%s.%d: %d:%d, failing recovery, "
 			"port state %d, vdev %p.\n", caller,
 			((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
@@ -215,7 +220,7 @@
 			SCpnt->device->hostdata));
 		return FAILED;
 	}
-	dfcprintk ((MYIOC_s_INFO_FMT
+	dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT
 		"%s.%d: %d:%d, executing recovery.\n", caller,
 		((MPT_SCSI_HOST *) shost->hostdata)->ioc->name,
 		((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no,
@@ -480,7 +485,7 @@
 
 			pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
 			nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
-			dfcprintk ((MYIOC_s_INFO_FMT
+			dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
 				"mptfc_reg_dev.%d: %x, %llx / %llx, tid %d, "
 				"rport tid %d, tmo %d\n",
 					ioc->name,
@@ -556,6 +561,35 @@
 
 	return rc;
 }
+/*
+ *	mptfc_dump_lun_info
+ *	@ioc
+ *	@rport
+ *	@sdev
+ *
+ */
+static void
+mptfc_dump_lun_info(MPT_ADAPTER *ioc, struct fc_rport *rport, struct scsi_device *sdev,
+		VirtTarget *vtarget)
+{
+	u64 nn, pn;
+	struct mptfc_rport_info *ri;
+
+	ri = *((struct mptfc_rport_info **)rport->dd_data);
+	pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
+	nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
+	dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
+		"mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
+		"CurrentTargetID %d, %x %llx %llx\n",
+		ioc->name,
+		sdev->host->host_no,
+		vtarget->num_luns,
+		sdev->id, ri->pg0.CurrentTargetID,
+		ri->pg0.PortIdentifier,
+		(unsigned long long)pn,
+		(unsigned long long)nn));
+}
+
 
 /*
  *	OS entry point to allow host driver to alloc memory
@@ -603,25 +637,7 @@
 	vtarget->num_luns++;
 
 
-#ifdef DMPT_DEBUG_FC
-	{
-	u64 nn, pn;
-	struct mptfc_rport_info *ri;
-	ri = *((struct mptfc_rport_info **)rport->dd_data);
-	pn = (u64)ri->pg0.WWPN.High << 32 | (u64)ri->pg0.WWPN.Low;
-	nn = (u64)ri->pg0.WWNN.High << 32 | (u64)ri->pg0.WWNN.Low;
-	dfcprintk ((MYIOC_s_INFO_FMT
-		"mptfc_slv_alloc.%d: num_luns %d, sdev.id %d, "
-	        "CurrentTargetID %d, %x %llx %llx\n",
-		hd->ioc->name,
-		sdev->host->host_no,
-		vtarget->num_luns,
-		sdev->id, ri->pg0.CurrentTargetID,
-		ri->pg0.PortIdentifier,
-		(unsigned long long)pn,
-		(unsigned long long)nn));
-	}
-#endif
+	mptfc_dump_lun_info(hd->ioc, rport, sdev, vtarget);
 
 	return 0;
 }
@@ -650,27 +666,12 @@
 	/* dd_data is null until finished adding target */
 	ri = *((struct mptfc_rport_info **)rport->dd_data);
 	if (unlikely(!ri)) {
-		dfcprintk ((MYIOC_s_INFO_FMT
-			"mptfc_qcmd.%d: %d:%d, dd_data is null.\n",
-			((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
-			((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
-			SCpnt->device->id,SCpnt->device->lun));
 		SCpnt->result = DID_IMM_RETRY << 16;
 		done(SCpnt);
 		return 0;
 	}
 
-	err = mptscsih_qcmd(SCpnt,done);
-#ifdef DMPT_DEBUG_FC
-	if (unlikely(err)) {
-		dfcprintk ((MYIOC_s_INFO_FMT
-			"mptfc_qcmd.%d: %d:%d, mptscsih_qcmd returns non-zero, (%x).\n",
-			((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->name,
-			((MPT_SCSI_HOST *) SCpnt->device->host->hostdata)->ioc->sh->host_no,
-			SCpnt->device->id,SCpnt->device->lun,err));
-	}
-#endif
-	return err;
+	return mptscsih_qcmd(SCpnt,done);
 }
 
 /*
@@ -1038,7 +1039,7 @@
 
 			pn = (u64)ri->pg0.WWPN.High << 32 |
 			     (u64)ri->pg0.WWPN.Low;
-			dfcprintk ((MYIOC_s_INFO_FMT
+			dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
 				"mptfc_setup_reset.%d: %llx deleted\n",
 				ioc->name,
 				ioc->sh->host_no,
@@ -1085,7 +1086,7 @@
 
 			pn = (u64)ri->pg0.WWPN.High << 32 |
 			     (u64)ri->pg0.WWPN.Low;
-			dfcprintk ((MYIOC_s_INFO_FMT
+			dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT
 				"mptfc_rescan.%d: %llx deleted\n",
 				ioc->name,
 				ioc->sh->host_no,
@@ -1209,7 +1210,7 @@
 
 	if (numSGE < sh->sg_tablesize) {
 		/* Reset this value */
-		dprintk((MYIOC_s_INFO_FMT
+		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		  "Resetting sg_tablesize to %d from %d\n",
 		  ioc->name, numSGE, sh->sg_tablesize));
 		sh->sg_tablesize = numSGE;
@@ -1229,7 +1230,7 @@
 		goto out_mptfc_probe;
 	}
 
-	dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
+	dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
 		 ioc->name, hd->ScsiLookup));
 
 	/* Clear the TM flags
@@ -1261,7 +1262,7 @@
 	sh->transportt = mptfc_transport_template;
 	error = scsi_add_host (sh, &ioc->pcidev->dev);
 	if(error) {
-		dprintk((KERN_ERR MYNAM
+		dprintk(ioc, printk(KERN_ERR MYNAM
 		  "scsi_add_host failed\n"));
 		goto out_mptfc_probe;
 	}
@@ -1320,7 +1321,7 @@
 	unsigned long flags;
 	int rc=1;
 
-	devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
+	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
 			ioc->name, event));
 
 	if (ioc->sh == NULL ||
@@ -1354,8 +1355,8 @@
 		return rc;
 
 
-	dtmprintk((KERN_WARNING MYNAM
-		": IOC %s_reset routed to FC host driver!\n",
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+		": IOC %s_reset routed to FC host driver!\n",ioc->name,
 		reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
 		reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
 
@@ -1410,15 +1411,8 @@
 	mptfcTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTFC_DRIVER);
 	mptfcInternalCtx = mpt_register(mptscsih_scandv_complete, MPTFC_DRIVER);
 
-	if (mpt_event_register(mptfcDoneCtx, mptfc_event_process) == 0) {
-		devtverboseprintk((KERN_INFO MYNAM
-		  ": Registered for IOC event notifications\n"));
-	}
-
-	if (mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset) == 0) {
-		dprintk((KERN_INFO MYNAM
-		  ": Registered for IOC reset notifications\n"));
-	}
+	mpt_event_register(mptfcDoneCtx, mptfc_event_process);
+	mpt_reset_register(mptfcDoneCtx, mptfc_ioc_reset);
 
 	error = pci_register_driver(&mptfc_driver);
 	if (error)
@@ -1483,12 +1477,7 @@
 	fc_release_transport(mptfc_transport_template);
 
 	mpt_reset_deregister(mptfcDoneCtx);
-	dprintk((KERN_INFO MYNAM
-	  ": Deregistered for IOC reset notifications\n"));
-
 	mpt_event_deregister(mptfcDoneCtx);
-	dprintk((KERN_INFO MYNAM
-	  ": Deregistered for IOC event notifications\n"));
 
 	mpt_deregister(mptfcInternalCtx);
 	mpt_deregister(mptfcTaskCtx);
diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c
index 7e8a90c..3da4c37 100644
--- a/drivers/message/fusion/mptlan.c
+++ b/drivers/message/fusion/mptlan.c
@@ -1427,8 +1427,6 @@
 	dlprintk((KERN_INFO MYNAM ": Finished registering dev "
 		"and setting initial values\n"));
 
-	SET_MODULE_OWNER(dev);
-
 	if (register_netdev(dev) != 0) {
 		free_netdev(dev);
 		dev = NULL;
@@ -1524,8 +1522,7 @@
 
 	dlprintk((KERN_INFO MYNAM ": Registered for IOC reset notifications\n"));
 	
-	if (mpt_device_driver_register(&mptlan_driver, MPTLAN_DRIVER))
-		dprintk((KERN_INFO MYNAM ": failed to register dd callbacks\n"));
+	mpt_device_driver_register(&mptlan_driver, MPTLAN_DRIVER);
 	return 0;
 }
 
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index 9e5424e..b9c69bf 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -201,103 +201,91 @@
 	u8	sep_channel;		/* SEP channel logical channel id */
 };
 
-#ifdef MPT_DEBUG_SAS
-static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
+static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
+					MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
 {
-	printk("---- IO UNIT PAGE 0 ------------\n");
-	printk("Handle=0x%X\n",
-		le16_to_cpu(phy_data->AttachedDeviceHandle));
-	printk("Controller Handle=0x%X\n",
-		le16_to_cpu(phy_data->ControllerDevHandle));
-	printk("Port=0x%X\n", phy_data->Port);
-	printk("Port Flags=0x%X\n", phy_data->PortFlags);
-	printk("PHY Flags=0x%X\n", phy_data->PhyFlags);
-	printk("Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate);
-	printk("Controller PHY Device Info=0x%X\n",
-		le32_to_cpu(phy_data->ControllerPhyDeviceInfo));
-	printk("DiscoveryStatus=0x%X\n",
-		le32_to_cpu(phy_data->DiscoveryStatus));
-	printk("\n");
+	dsasprintk(ioc, printk(KERN_DEBUG "---- IO UNIT PAGE 0 ------------\n"));
+	dsasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n",
+		le16_to_cpu(phy_data->AttachedDeviceHandle)));
+	dsasprintk(ioc, printk(KERN_DEBUG "Controller Handle=0x%X\n",
+		le16_to_cpu(phy_data->ControllerDevHandle)));
+	dsasprintk(ioc, printk(KERN_DEBUG "Port=0x%X\n", phy_data->Port));
+	dsasprintk(ioc, printk(KERN_DEBUG "Port Flags=0x%X\n", phy_data->PortFlags));
+	dsasprintk(ioc, printk(KERN_DEBUG "PHY Flags=0x%X\n", phy_data->PhyFlags));
+	dsasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate));
+	dsasprintk(ioc, printk(KERN_DEBUG "Controller PHY Device Info=0x%X\n",
+		le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
+	dsasprintk(ioc, printk(KERN_DEBUG "DiscoveryStatus=0x%X\n\n",
+		le32_to_cpu(phy_data->DiscoveryStatus)));
 }
 
-static void mptsas_print_phy_pg0(SasPhyPage0_t *pg0)
+static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
 {
 	__le64 sas_address;
 
 	memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
 
-	printk("---- SAS PHY PAGE 0 ------------\n");
-	printk("Attached Device Handle=0x%X\n",
-			le16_to_cpu(pg0->AttachedDevHandle));
-	printk("SAS Address=0x%llX\n",
-			(unsigned long long)le64_to_cpu(sas_address));
-	printk("Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier);
-	printk("Attached Device Info=0x%X\n",
-			le32_to_cpu(pg0->AttachedDeviceInfo));
-	printk("Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate);
-	printk("Change Count=0x%X\n", pg0->ChangeCount);
-	printk("PHY Info=0x%X\n", le32_to_cpu(pg0->PhyInfo));
-	printk("\n");
+	dsasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 0 ------------\n"));
+	dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Handle=0x%X\n",
+			le16_to_cpu(pg0->AttachedDevHandle)));
+	dsasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n",
+			(unsigned long long)le64_to_cpu(sas_address)));
+	dsasprintk(ioc, printk(KERN_DEBUG "Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier));
+	dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Info=0x%X\n",
+			le32_to_cpu(pg0->AttachedDeviceInfo)));
+	dsasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate));
+	dsasprintk(ioc, printk(KERN_DEBUG "Change Count=0x%X\n", pg0->ChangeCount));
+	dsasprintk(ioc, printk(KERN_DEBUG "PHY Info=0x%X\n\n", le32_to_cpu(pg0->PhyInfo)));
 }
 
-static void mptsas_print_phy_pg1(SasPhyPage1_t *pg1)
+static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
 {
-	printk("---- SAS PHY PAGE 1 ------------\n");
-	printk("Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount);
-	printk("Running Disparity Error Count=0x%x\n",
-			pg1->RunningDisparityErrorCount);
-	printk("Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount);
-	printk("PHY Reset Problem Count=0x%x\n", pg1->PhyResetProblemCount);
-	printk("\n");
+	dsasprintk(ioc, printk(KERN_DEBUG "---- SAS PHY PAGE 1 ------------\n"));
+	dsasprintk(ioc, printk(KERN_DEBUG "Invalid Dword Count=0x%x\n", pg1->InvalidDwordCount));
+	dsasprintk(ioc, printk(KERN_DEBUG "Running Disparity Error Count=0x%x\n",
+			pg1->RunningDisparityErrorCount));
+	dsasprintk(ioc, printk(KERN_DEBUG "Loss Dword Synch Count=0x%x\n", pg1->LossDwordSynchCount));
+	dsasprintk(ioc, printk(KERN_DEBUG "PHY Reset Problem Count=0x%x\n\n", pg1->PhyResetProblemCount));
 }
 
-static void mptsas_print_device_pg0(SasDevicePage0_t *pg0)
+static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
 {
 	__le64 sas_address;
 
 	memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
 
-	printk("---- SAS DEVICE PAGE 0 ---------\n");
-	printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle));
-	printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle));
-	printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle));
-	printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot));
-	printk("SAS Address=0x%llX\n", (unsigned long long)
-	    le64_to_cpu(sas_address));
-	printk("Target ID=0x%X\n", pg0->TargetID);
-	printk("Bus=0x%X\n", pg0->Bus);
+	dsasprintk(ioc, printk(KERN_DEBUG "---- SAS DEVICE PAGE 0 ---------\n"));
+	dsasprintk(ioc, printk(KERN_DEBUG "Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle)));
+	dsasprintk(ioc, printk(KERN_DEBUG "Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle)));
+	dsasprintk(ioc, printk(KERN_DEBUG "Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle)));
+	dsasprintk(ioc, printk(KERN_DEBUG "Slot=0x%X\n", le16_to_cpu(pg0->Slot)));
+	dsasprintk(ioc, printk(KERN_DEBUG "SAS Address=0x%llX\n", (unsigned long long)
+	    le64_to_cpu(sas_address)));
+	dsasprintk(ioc, printk(KERN_DEBUG "Target ID=0x%X\n", pg0->TargetID));
+	dsasprintk(ioc, printk(KERN_DEBUG "Bus=0x%X\n", pg0->Bus));
 	/* The PhyNum field specifies the PHY number of the parent
 	 * device this device is linked to
 	 */
-	printk("Parent Phy Num=0x%X\n", pg0->PhyNum);
-	printk("Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus));
-	printk("Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo));
-	printk("Flags=0x%X\n", le16_to_cpu(pg0->Flags));
-	printk("Physical Port=0x%X\n", pg0->PhysicalPort);
-	printk("\n");
+	dsasprintk(ioc, printk(KERN_DEBUG "Parent Phy Num=0x%X\n", pg0->PhyNum));
+	dsasprintk(ioc, printk(KERN_DEBUG "Access Status=0x%X\n", le16_to_cpu(pg0->AccessStatus)));
+	dsasprintk(ioc, printk(KERN_DEBUG "Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo)));
+	dsasprintk(ioc, printk(KERN_DEBUG "Flags=0x%X\n", le16_to_cpu(pg0->Flags)));
+	dsasprintk(ioc, printk(KERN_DEBUG "Physical Port=0x%X\n\n", pg0->PhysicalPort));
 }
 
-static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1)
+static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
 {
-	printk("---- SAS EXPANDER PAGE 1 ------------\n");
-
-	printk("Physical Port=0x%X\n", pg1->PhysicalPort);
-	printk("PHY Identifier=0x%X\n", pg1->PhyIdentifier);
-	printk("Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate);
-	printk("Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate);
-	printk("Hardware Link Rate=0x%X\n", pg1->HwLinkRate);
-	printk("Owner Device Handle=0x%X\n",
-			le16_to_cpu(pg1->OwnerDevHandle));
-	printk("Attached Device Handle=0x%X\n",
-			le16_to_cpu(pg1->AttachedDevHandle));
+	dsasprintk(ioc, printk(KERN_DEBUG "---- SAS EXPANDER PAGE 1 ------------\n"));
+	dsasprintk(ioc, printk(KERN_DEBUG "Physical Port=0x%X\n", pg1->PhysicalPort));
+	dsasprintk(ioc, printk(KERN_DEBUG "PHY Identifier=0x%X\n", pg1->PhyIdentifier));
+	dsasprintk(ioc, printk(KERN_DEBUG "Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate));
+	dsasprintk(ioc, printk(KERN_DEBUG "Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate));
+	dsasprintk(ioc, printk(KERN_DEBUG "Hardware Link Rate=0x%X\n", pg1->HwLinkRate));
+	dsasprintk(ioc, printk(KERN_DEBUG "Owner Device Handle=0x%X\n",
+			le16_to_cpu(pg1->OwnerDevHandle)));
+	dsasprintk(ioc, printk(KERN_DEBUG "Attached Device Handle=0x%X\n\n",
+			le16_to_cpu(pg1->AttachedDevHandle)));
 }
-#else
-#define mptsas_print_phy_data(phy_data)		do { } while (0)
-#define mptsas_print_phy_pg0(pg0)		do { } while (0)
-#define mptsas_print_phy_pg1(pg1)		do { } while (0)
-#define mptsas_print_device_pg0(pg0)		do { } while (0)
-#define mptsas_print_expander_pg1(pg1)		do { } while (0)
-#endif
 
 static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
 {
@@ -354,7 +342,7 @@
 
 /* no mutex */
 static void
-mptsas_port_delete(struct mptsas_portinfo_details * port_details)
+mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
 {
 	struct mptsas_portinfo *port_info;
 	struct mptsas_phyinfo *phy_info;
@@ -366,7 +354,7 @@
 	port_info = port_details->port_info;
 	phy_info = port_info->phy_info;
 
-	dsaswideprintk((KERN_DEBUG "%s: [%p]: num_phys=%02d "
+	dsaswideprintk(ioc, printk(KERN_DEBUG "%s: [%p]: num_phys=%02d "
 	    "bitmask=0x%016llX\n", __FUNCTION__, port_details,
 	    port_details->num_phys, (unsigned long long)
 	    port_details->phy_bitmask));
@@ -390,20 +378,19 @@
 }
 
 static inline void
-mptsas_set_rphy(struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
+mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
 {
 	if (phy_info->port_details) {
 		phy_info->port_details->rphy = rphy;
-		dsaswideprintk((KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy));
+		dsaswideprintk(ioc, printk(KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy));
 	}
 
-#ifdef MPT_DEBUG_SAS_WIDE
 	if (rphy) {
-		dev_printk(KERN_DEBUG, &rphy->dev, "add:");
-		printk("rphy=%p release=%p\n",
-			rphy, rphy->dev.release);
+		dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
+		    &rphy->dev, "add:"));
+		dsaswideprintk(ioc, printk(KERN_DEBUG "rphy=%p release=%p\n",
+			rphy, rphy->dev.release));
 	}
-#endif
 }
 
 static inline struct sas_port *
@@ -416,18 +403,17 @@
 }
 
 static inline void
-mptsas_set_port(struct mptsas_phyinfo *phy_info, struct sas_port *port)
+mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
 {
 	if (phy_info->port_details)
 		phy_info->port_details->port = port;
 
-#ifdef MPT_DEBUG_SAS_WIDE
 	if (port) {
-		dev_printk(KERN_DEBUG, &port->dev, "add: ");
-		printk("port=%p release=%p\n",
-			port, port->dev.release);
+		dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
+		    &port->dev, "add:"));
+		dsaswideprintk(ioc, printk(KERN_DEBUG "port=%p release=%p\n",
+			port, port->dev.release));
 	}
-#endif
 }
 
 static inline struct scsi_target *
@@ -477,7 +463,7 @@
 		 * Removing a phy from a port, letting the last
 		 * phy be removed by firmware events.
 		 */
-		dsaswideprintk((KERN_DEBUG
+		dsaswideprintk(ioc, printk(KERN_DEBUG
 			"%s: [%p]: deleting phy = %d\n",
 			__FUNCTION__, port_details, i));
 		port_details->num_phys--;
@@ -493,7 +479,7 @@
 	phy_info = port_info->phy_info;
 	for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
 		sas_address = phy_info->attached.sas_address;
-		dsaswideprintk((KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n",
+		dsaswideprintk(ioc, printk(KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n",
 		    i, (unsigned long long)sas_address));
 		if (!sas_address)
 			continue;
@@ -512,7 +498,7 @@
 				port_details->phy_bitmask |=
 				    (1 << phy_info->phy_id);
 			phy_info->sas_port_add_phy=1;
-			dsaswideprintk((KERN_DEBUG "\t\tForming port\n\t\t"
+			dsaswideprintk(ioc, printk(KERN_DEBUG "\t\tForming port\n\t\t"
 			    "phy_id=%d sas_address=0x%018llX\n",
 			    i, (unsigned long long)sas_address));
 			phy_info->port_details = port_details;
@@ -529,7 +515,7 @@
 				continue;
 			if (phy_info_cmp->port_details == port_details )
 				continue;
-			dsaswideprintk((KERN_DEBUG
+			dsaswideprintk(ioc, printk(KERN_DEBUG
 			    "\t\tphy_id=%d sas_address=0x%018llX\n",
 			    j, (unsigned long long)
 			    phy_info_cmp->attached.sas_address));
@@ -559,21 +545,19 @@
 
  out:
 
-#ifdef MPT_DEBUG_SAS_WIDE
 	for (i = 0; i < port_info->num_phys; i++) {
 		port_details = port_info->phy_info[i].port_details;
 		if (!port_details)
 			continue;
-		dsaswideprintk((KERN_DEBUG
+		dsaswideprintk(ioc, printk(KERN_DEBUG
 		    "%s: [%p]: phy_id=%02d num_phys=%02d "
 		    "bitmask=0x%016llX\n", __FUNCTION__,
 		    port_details, i, port_details->num_phys,
 		    (unsigned long long)port_details->phy_bitmask));
-		dsaswideprintk((KERN_DEBUG"\t\tport = %p rphy=%p\n",
+		dsaswideprintk(ioc, printk(KERN_DEBUG"\t\tport = %p rphy=%p\n",
 			port_details->port, port_details->rphy));
 	}
-	dsaswideprintk((KERN_DEBUG"\n"));
-#endif
+	dsaswideprintk(ioc, printk(KERN_DEBUG"\n"));
 	mutex_unlock(&ioc->sas_topology_mutex);
 }
 
@@ -622,7 +606,7 @@
 	SCSITaskMgmt_t	*pScsiTm;
 
 	if ((mf = mpt_get_msg_frame(ioc->TaskCtx, ioc)) == NULL) {
-		dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
+		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, no msg frames @%d!!\n",
 		    ioc->name,__FUNCTION__, __LINE__));
 		return 0;
 	}
@@ -637,12 +621,12 @@
 	pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
 	pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
 
-	DBG_DUMP_TM_REQUEST_FRAME(mf);
+	DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
 
 	if (mpt_send_handshake_request(ioc->TaskCtx, ioc,
 	    sizeof(SCSITaskMgmt_t), (u32 *)mf, NO_SLEEP)) {
 		mpt_free_msg_frame(ioc, mf);
-		dfailprintk((MYIOC_s_WARN_FMT "%s, tm handshake failed @%d!!\n",
+		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, tm handshake failed @%d!!\n",
 		    ioc->name,__FUNCTION__, __LINE__));
 		return 0;
 	}
@@ -681,7 +665,7 @@
 	target_reset_list = kzalloc(sizeof(*target_reset_list),
 	    GFP_ATOMIC);
 	if (!target_reset_list) {
-		dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
+		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
 		    ioc->name,__FUNCTION__, __LINE__));
 		return;
 	}
@@ -748,7 +732,7 @@
 
 	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
 	if (!ev) {
-		dfailprintk((MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
+		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s, failed to allocate mem @%d..!!\n",
 		    ioc->name,__FUNCTION__, __LINE__));
 		return;
 	}
@@ -1119,6 +1103,7 @@
 	.max_sectors			= 8192,
 	.cmd_per_lun			= 7,
 	.use_clustering			= ENABLE_CLUSTERING,
+	.shost_attrs			= mptscsih_host_attrs,
 };
 
 static int mptsas_get_linkerrors(struct sas_phy *phy)
@@ -1167,7 +1152,7 @@
 	if (error)
 		goto out_free_consistent;
 
-	mptsas_print_phy_pg1(buffer);
+	mptsas_print_phy_pg1(ioc, buffer);
 
 	phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
 	phy->running_disparity_error_count =
@@ -1327,11 +1312,137 @@
 	return rc;
 }
 
+static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
+			      struct request *req)
+{
+	MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
+	MPT_FRAME_HDR *mf;
+	SmpPassthroughRequest_t *smpreq;
+	struct request *rsp = req->next_rq;
+	int ret;
+	int flagsLength;
+	unsigned long timeleft;
+	char *psge;
+	dma_addr_t dma_addr_in = 0;
+	dma_addr_t dma_addr_out = 0;
+	u64 sas_address = 0;
+
+	if (!rsp) {
+		printk(KERN_ERR "%s: the smp response space is missing\n",
+		       __FUNCTION__);
+		return -EINVAL;
+	}
+
+	/* do we need to support multiple segments? */
+	if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
+		printk(KERN_ERR "%s: multiple segments req %u %u, rsp %u %u\n",
+		       __FUNCTION__, req->bio->bi_vcnt, req->data_len,
+		       rsp->bio->bi_vcnt, rsp->data_len);
+		return -EINVAL;
+	}
+
+	ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
+	if (ret)
+		goto out;
+
+	mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
+	if (!mf) {
+		ret = -ENOMEM;
+		goto out_unlock;
+	}
+
+	smpreq = (SmpPassthroughRequest_t *)mf;
+	memset(smpreq, 0, sizeof(*smpreq));
+
+	smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
+	smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
+
+	if (rphy)
+		sas_address = rphy->identify.sas_address;
+	else {
+		struct mptsas_portinfo *port_info;
+
+		mutex_lock(&ioc->sas_topology_mutex);
+		port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
+		if (port_info && port_info->phy_info)
+			sas_address =
+				port_info->phy_info[0].phy->identify.sas_address;
+		mutex_unlock(&ioc->sas_topology_mutex);
+	}
+
+	*((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
+
+	psge = (char *)
+		(((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
+
+	/* request */
+	flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
+		       MPI_SGE_FLAGS_END_OF_BUFFER |
+		       MPI_SGE_FLAGS_DIRECTION |
+		       mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT;
+	flagsLength |= (req->data_len - 4);
+
+	dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
+				      req->data_len, PCI_DMA_BIDIRECTIONAL);
+	if (!dma_addr_out)
+		goto put_mf;
+	mpt_add_sge(psge, flagsLength, dma_addr_out);
+	psge += (sizeof(u32) + sizeof(dma_addr_t));
+
+	/* response */
+	flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
+	flagsLength |= rsp->data_len + 4;
+	dma_addr_in =  pci_map_single(ioc->pcidev, bio_data(rsp->bio),
+				      rsp->data_len, PCI_DMA_BIDIRECTIONAL);
+	if (!dma_addr_in)
+		goto unmap;
+	mpt_add_sge(psge, flagsLength, dma_addr_in);
+
+	mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
+
+	timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
+	if (!timeleft) {
+		printk(KERN_ERR "%s: smp timeout!\n", __FUNCTION__);
+		/* On timeout reset the board */
+		mpt_HardResetHandler(ioc, CAN_SLEEP);
+		ret = -ETIMEDOUT;
+		goto unmap;
+	}
+	mf = NULL;
+
+	if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) {
+		SmpPassthroughReply_t *smprep;
+
+		smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
+		memcpy(req->sense, smprep, sizeof(*smprep));
+		req->sense_len = sizeof(*smprep);
+	} else {
+		printk(KERN_ERR "%s: smp passthru reply failed to be returned\n",
+		       __FUNCTION__);
+		ret = -ENXIO;
+	}
+unmap:
+	if (dma_addr_out)
+		pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
+				 PCI_DMA_BIDIRECTIONAL);
+	if (dma_addr_in)
+		pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
+				 PCI_DMA_BIDIRECTIONAL);
+put_mf:
+	if (mf)
+		mpt_free_msg_frame(ioc, mf);
+out_unlock:
+	mutex_unlock(&ioc->sas_mgmt.mutex);
+out:
+	return ret;
+}
+
 static struct sas_function_template mptsas_transport_functions = {
 	.get_linkerrors		= mptsas_get_linkerrors,
 	.get_enclosure_identifier = mptsas_get_enclosure_identifier,
 	.get_bay_identifier	= mptsas_get_bay_identifier,
 	.phy_reset		= mptsas_phy_reset,
+	.smp_handler		= mptsas_smp_handler,
 };
 
 static struct scsi_transport_template *mptsas_transport_template;
@@ -1390,8 +1501,13 @@
 		goto out_free_consistent;
 	}
 
+	ioc->nvdata_version_persistent =
+	    le16_to_cpu(buffer->NvdataVersionPersistent);
+	ioc->nvdata_version_default =
+	    le16_to_cpu(buffer->NvdataVersionDefault);
+
 	for (i = 0; i < port_info->num_phys; i++) {
-		mptsas_print_phy_data(&buffer->PhyData[i]);
+		mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
 		port_info->phy_info[i].phy_id = i;
 		port_info->phy_info[i].port_id =
 		    buffer->PhyData[i].Port;
@@ -1410,6 +1526,63 @@
 }
 
 static int
+mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
+{
+	ConfigExtendedPageHeader_t hdr;
+	CONFIGPARMS cfg;
+	SasIOUnitPage1_t *buffer;
+	dma_addr_t dma_handle;
+	int error;
+	u16 device_missing_delay;
+
+	memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
+	memset(&cfg, 0, sizeof(CONFIGPARMS));
+
+	cfg.cfghdr.ehdr = &hdr;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
+	cfg.timeout = 10;
+	cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
+	cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
+	cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
+	cfg.cfghdr.ehdr->PageNumber = 1;
+
+	error = mpt_config(ioc, &cfg);
+	if (error)
+		goto out;
+	if (!hdr.ExtPageLength) {
+		error = -ENXIO;
+		goto out;
+	}
+
+	buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+					    &dma_handle);
+	if (!buffer) {
+		error = -ENOMEM;
+		goto out;
+	}
+
+	cfg.physAddr = dma_handle;
+	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
+
+	error = mpt_config(ioc, &cfg);
+	if (error)
+		goto out_free_consistent;
+
+	ioc->io_missing_delay  =
+	    le16_to_cpu(buffer->IODeviceMissingDelay);
+	device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
+	ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
+	    (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
+	    device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
+
+ out_free_consistent:
+	pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
+			    buffer, dma_handle);
+ out:
+	return error;
+}
+
+static int
 mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
 		u32 form, u32 form_specific)
 {
@@ -1459,7 +1632,7 @@
 	if (error)
 		goto out_free_consistent;
 
-	mptsas_print_phy_pg0(buffer);
+	mptsas_print_phy_pg0(ioc, buffer);
 
 	phy_info->hw_link_rate = buffer->HwLinkRate;
 	phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
@@ -1526,7 +1699,7 @@
 	if (error)
 		goto out_free_consistent;
 
-	mptsas_print_device_pg0(buffer);
+	mptsas_print_device_pg0(ioc, buffer);
 
 	device_info->handle = le16_to_cpu(buffer->DevHandle);
 	device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
@@ -1674,7 +1847,7 @@
 		goto out_free_consistent;
 
 
-	mptsas_print_expander_pg1(buffer);
+	mptsas_print_expander_pg1(ioc, buffer);
 
 	/* save config data */
 	phy_info->phy_id = buffer->PhyIdentifier;
@@ -1883,17 +2056,17 @@
 			}
 			error = sas_port_add(port);
 			if (error) {
-				dfailprintk((MYIOC_s_ERR_FMT
+				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 					"%s: exit at line=%d\n", ioc->name,
 					__FUNCTION__, __LINE__));
 				goto out;
 			}
-			mptsas_set_port(phy_info, port);
-			dsaswideprintk((KERN_DEBUG
+			mptsas_set_port(ioc, phy_info, port);
+			dsaswideprintk(ioc, printk(KERN_DEBUG
 			    "sas_port_alloc: port=%p dev=%p port_id=%d\n",
 			    port, dev, port->port_identifier));
 		}
-		dsaswideprintk((KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
+		dsaswideprintk(ioc, printk(KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
 		    phy_info->phy_id));
 		sas_port_add_phy(port, phy_info->phy);
 		phy_info->sas_port_add_phy = 0;
@@ -1954,7 +2127,7 @@
 			break;
 		}
 		if (!rphy) {
-			dfailprintk((MYIOC_s_ERR_FMT
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				__FUNCTION__, __LINE__));
 			goto out;
@@ -1963,13 +2136,13 @@
 		rphy->identify = identify;
 		error = sas_rphy_add(rphy);
 		if (error) {
-			dfailprintk((MYIOC_s_ERR_FMT
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				__FUNCTION__, __LINE__));
 			sas_rphy_free(rphy);
 			goto out;
 		}
-		mptsas_set_rphy(phy_info, rphy);
+		mptsas_set_rphy(ioc, phy_info, rphy);
 	}
 
  out:
@@ -1990,6 +2163,7 @@
 	if (error)
 		goto out_free_port_info;
 
+	mptsas_sas_io_unit_pg1(ioc);
 	mutex_lock(&ioc->sas_topology_mutex);
 	ioc->handle = hba->phy_info[0].handle;
 	port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
@@ -2194,18 +2368,17 @@
 				if (phy_info->attached.sas_address !=
 					expander_sas_address)
 					continue;
-#ifdef MPT_DEBUG_SAS_WIDE
-				dev_printk(KERN_DEBUG, &port->dev,
-				    "delete port (%d)\n", port->port_identifier);
-#endif
+				dsaswideprintk(ioc,
+					dev_printk(KERN_DEBUG, &port->dev,
+					"delete port (%d)\n", port->port_identifier));
 				sas_port_delete(port);
-				mptsas_port_delete(phy_info->port_details);
+				mptsas_port_delete(ioc, phy_info->port_details);
 			}
  next_port:
 
 			phy_info = port_info->phy_info;
 			for (i = 0; i < port_info->num_phys; i++, phy_info++)
-				mptsas_port_delete(phy_info->port_details);
+				mptsas_port_delete(ioc, phy_info->port_details);
 
 			list_del(&port_info->list);
 			kfree(port_info->phy_info);
@@ -2491,7 +2664,7 @@
 				    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
 				     MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
 				    (ev->channel << 8) + ev->id)) {
-					dfailprintk((MYIOC_s_ERR_FMT
+					dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 					"%s: exit at line=%d\n", ioc->name,
 						__FUNCTION__, __LINE__));
 					break;
@@ -2511,20 +2684,20 @@
 		 * Sanity checks, for non-existing phys and remote rphys.
 		 */
 		if (!phy_info){
-			dfailprintk((MYIOC_s_ERR_FMT
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 				__FUNCTION__, __LINE__));
 			break;
 		}
 		if (!phy_info->port_details) {
-			dfailprintk((MYIOC_s_ERR_FMT
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 			       	__FUNCTION__, __LINE__));
 			break;
 		}
 		rphy = mptsas_get_rphy(phy_info);
 		if (!rphy) {
-			dfailprintk((MYIOC_s_ERR_FMT
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 			       	__FUNCTION__, __LINE__));
 			break;
@@ -2532,7 +2705,7 @@
 
 		port = mptsas_get_port(phy_info);
 		if (!port) {
-			dfailprintk((MYIOC_s_ERR_FMT
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 			       	__FUNCTION__, __LINE__));
 			break;
@@ -2543,7 +2716,7 @@
 			vtarget = starget->hostdata;
 
 			if (!vtarget) {
-				dfailprintk((MYIOC_s_ERR_FMT
+				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 					"%s: exit at line=%d\n", ioc->name,
 					__FUNCTION__, __LINE__));
 				break;
@@ -2581,12 +2754,10 @@
 		printk(MYIOC_s_INFO_FMT
 		       "removing %s device, channel %d, id %d, phy %d\n",
 		       ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
-#ifdef MPT_DEBUG_SAS_WIDE
 		dev_printk(KERN_DEBUG, &port->dev,
 		    "delete port (%d)\n", port->port_identifier);
-#endif
 		sas_port_delete(port);
-		mptsas_port_delete(phy_info->port_details);
+		mptsas_port_delete(ioc, phy_info->port_details);
 		break;
 	case MPTSAS_ADD_DEVICE:
 
@@ -2600,7 +2771,7 @@
 		    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
 		     MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
 			(ev->channel << 8) + ev->id)) {
-				dfailprintk((MYIOC_s_ERR_FMT
+				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 					"%s: exit at line=%d\n", ioc->name,
 					__FUNCTION__, __LINE__));
 			break;
@@ -2612,7 +2783,7 @@
 				sas_device.sas_address);
 
 		if (!phy_info || !phy_info->port_details) {
-			dfailprintk((MYIOC_s_ERR_FMT
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 			       	__FUNCTION__, __LINE__));
 			break;
@@ -2624,7 +2795,7 @@
 			vtarget = starget->hostdata;
 
 			if (!vtarget) {
-				dfailprintk((MYIOC_s_ERR_FMT
+				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 					"%s: exit at line=%d\n", ioc->name,
 				       	__FUNCTION__, __LINE__));
 				break;
@@ -2647,7 +2818,7 @@
 		}
 
 		if (mptsas_get_rphy(phy_info)) {
-			dfailprintk((MYIOC_s_ERR_FMT
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 			       	__FUNCTION__, __LINE__));
 			if (ev->channel) printk("%d\n", __LINE__);
@@ -2656,7 +2827,7 @@
 
 		port = mptsas_get_port(phy_info);
 		if (!port) {
-			dfailprintk((MYIOC_s_ERR_FMT
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 			       	__FUNCTION__, __LINE__));
 			break;
@@ -2681,7 +2852,7 @@
 		mptsas_parse_device_info(&identify, &phy_info->attached);
 		rphy = sas_end_device_alloc(port);
 		if (!rphy) {
-			dfailprintk((MYIOC_s_ERR_FMT
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 			       	__FUNCTION__, __LINE__));
 			break; /* non-fatal: an rphy can be added later */
@@ -2689,13 +2860,13 @@
 
 		rphy->identify = identify;
 		if (sas_rphy_add(rphy)) {
-			dfailprintk((MYIOC_s_ERR_FMT
+			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
 				"%s: exit at line=%d\n", ioc->name,
 			       	__FUNCTION__, __LINE__));
 			sas_rphy_free(rphy);
 			break;
 		}
-		mptsas_set_rphy(phy_info, rphy);
+		mptsas_set_rphy(ioc, phy_info, rphy);
 		break;
 	case MPTSAS_ADD_RAID:
 		sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
@@ -3111,7 +3282,7 @@
 
 	if (numSGE < sh->sg_tablesize) {
 		/* Reset this value */
-		dprintk((MYIOC_s_INFO_FMT
+		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		  "Resetting sg_tablesize to %d from %d\n",
 		  ioc->name, numSGE, sh->sg_tablesize));
 		sh->sg_tablesize = numSGE;
@@ -3129,7 +3300,7 @@
 		goto out_mptsas_probe;
 	}
 
-	dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
+	dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
 		 ioc->name, hd->ScsiLookup));
 
 	/* Clear the TM flags
@@ -3169,7 +3340,7 @@
 
 	error = scsi_add_host(sh, &ioc->pcidev->dev);
 	if (error) {
-		dprintk((KERN_ERR MYNAM
+		dprintk(ioc, printk(KERN_ERR MYNAM
 		  "scsi_add_host failed\n"));
 		goto out_mptsas_probe;
 	}
@@ -3197,7 +3368,7 @@
 	list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
 		list_del(&p->list);
 		for (i = 0 ; i < p->num_phys ; i++)
-			mptsas_port_delete(p->phy_info[i].port_details);
+			mptsas_port_delete(ioc, p->phy_info[i].port_details);
 		kfree(p->phy_info);
 		kfree(p);
 	}
@@ -3237,6 +3408,8 @@
 static int __init
 mptsas_init(void)
 {
+	int error;
+
 	show_mptmod_ver(my_NAME, my_VERSION);
 
 	mptsas_transport_template =
@@ -3250,17 +3423,14 @@
 		mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
 	mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
 
-	if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) {
-		devtverboseprintk((KERN_INFO MYNAM
-		  ": Registered for IOC event notifications\n"));
-	}
+	mpt_event_register(mptsasDoneCtx, mptsas_event_process);
+	mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
 
-	if (mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset) == 0) {
-		dprintk((KERN_INFO MYNAM
-		  ": Registered for IOC reset notifications\n"));
-	}
+	error = pci_register_driver(&mptsas_driver);
+	if (error)
+		sas_release_transport(mptsas_transport_template);
 
-	return pci_register_driver(&mptsas_driver);
+	return error;
 }
 
 static void __exit
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index d356173..5431529 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -191,7 +191,7 @@
 	int rc;
 	int chain_idx;
 
-	dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer called\n",
+	dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer called\n",
 			ioc->name));
 	spin_lock_irqsave(&ioc->FreeQlock, flags);
 	if (!list_empty(&ioc->FreeChainQ)) {
@@ -203,12 +203,12 @@
 		offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer;
 		chain_idx = offset / ioc->req_sz;
 		rc = SUCCESS;
-		dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
+		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n",
 			ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx));
 	} else {
 		rc = FAILED;
 		chain_idx = MPT_HOST_NO_CHAIN;
-		dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n",
+		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT "getFreeChainBuffer failed\n",
 			ioc->name));
 	}
 	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
@@ -337,7 +337,7 @@
 			 */
 			pReq->ChainOffset = 0;
 			RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor)  + 1) & 0x03;
-			dsgprintk((MYIOC_s_INFO_FMT
+			dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 			    "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
 			ioc->RequestNB[req_idx] = RequestNB;
 		}
@@ -353,7 +353,7 @@
 		 * Loop until done.
 		 */
 
-		dsgprintk((MYIOC_s_INFO_FMT "SG: Chain Required! sg done %d\n",
+		dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SG: Chain Required! sg done %d\n",
 				ioc->name, sg_done));
 
 		/* Set LAST_ELEMENT flag for last non-chain element
@@ -386,7 +386,7 @@
 			 */
 			pReq->ChainOffset = (u8) (sgeOffset >> 2);
 			RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor)  + 1) & 0x03;
-			dsgprintk((MYIOC_s_ERR_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
+			dsgprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Chain Buffer Needed, RequestNB=%x sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset));
 			ioc->RequestNB[req_idx] = RequestNB;
 		}
 
@@ -397,7 +397,7 @@
 		 * in current buffer. Get a chain buffer.
 		 */
 		if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) {
-			dfailprintk((MYIOC_s_INFO_FMT
+			dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 			    "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n",
  			    ioc->name, pReq->CDB[0], SCpnt));
 			return FAILED;
@@ -419,7 +419,7 @@
 		 *   out the Address and Flags fields.
 		 */
 		chainSge = (char *) psge;
-		dsgprintk((KERN_INFO "  Current buff @ %p (index 0x%x)",
+		dsgprintk(ioc, printk(KERN_DEBUG "  Current buff @ %p (index 0x%x)",
 				psge, req_idx));
 
 		/* Start the SGE for the next buffer
@@ -428,7 +428,7 @@
 		sgeOffset = 0;
 		sg_done = 0;
 
-		dsgprintk((KERN_INFO "  Chain buff @ %p (index 0x%x)\n",
+		dsgprintk(ioc, printk(KERN_DEBUG "  Chain buff @ %p (index 0x%x)\n",
 				psge, chain_idx));
 
 		/* Start the SGE for the next buffer
@@ -456,7 +456,7 @@
 		return;
 
 	if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
-		dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
+		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
 		    ioc->name,__FUNCTION__));
 		return;
 	}
@@ -467,93 +467,158 @@
 	SEPMsg->TargetID = vtarget->id;
 	SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
 	SEPMsg->SlotStatus = SlotStatus;
-	devtverboseprintk((MYIOC_s_WARN_FMT
+	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 	    "Sending SEP cmd=%x channel=%d id=%d\n",
 	    ioc->name, SlotStatus, SEPMsg->Bus, SEPMsg->TargetID));
 	mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
 }
 
-#ifdef MPT_DEBUG_REPLY
+#ifdef CONFIG_FUSION_LOGGING
 /**
- *	mptscsih_iocstatus_info_scsiio - IOCSTATUS information for SCSIIO
+ *	mptscsih_info_scsiio - debug print info on reply frame
  *	@ioc: Pointer to MPT_ADAPTER structure
- *	@ioc_status: U32 IOCStatus word from IOC
- *	@scsi_status: U8 sam status from target
- *	@scsi_state: U8 scsi state
  *	@sc: original scsi cmnd pointer
- *	@mf: Pointer to MPT request frame
+ *	@pScsiReply: Pointer to MPT reply frame
+ *
+ *	MPT_DEBUG_REPLY needs to be enabled to obtain this info
  *
  *	Refer to lsi/mpi.h.
  **/
 static void
-mptscsih_iocstatus_info_scsiio(MPT_ADAPTER *ioc, u32 ioc_status,
-    u8 scsi_status, u8 scsi_state, struct scsi_cmnd *sc)
+mptscsih_info_scsiio(MPT_ADAPTER *ioc, struct scsi_cmnd *sc, SCSIIOReply_t * pScsiReply)
 {
-	char extend_desc[EVENT_DESCR_STR_SZ];
-	char *desc = NULL;
+	char	*desc = NULL;
+	char	*desc1 = NULL;
+	u16	ioc_status;
+	u8	skey, asc, ascq;
+
+	ioc_status = le16_to_cpu(pScsiReply->IOCStatus) & MPI_IOCSTATUS_MASK;
 
 	switch (ioc_status) {
 
-	case MPI_IOCSTATUS_SCSI_INVALID_BUS: /* 0x0041 */
-		desc = "SCSI Invalid Bus";
+	case MPI_IOCSTATUS_SUCCESS:
+		desc = "success";
 		break;
-
-	case MPI_IOCSTATUS_SCSI_INVALID_TARGETID: /* 0x0042 */
-		desc = "SCSI Invalid TargetID";
+	case MPI_IOCSTATUS_SCSI_INVALID_BUS:
+		desc = "invalid bus";
 		break;
-
-	case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */
-		/*
-		 * Inquiry is issued for device scanning
-		 */
-		if (sc->cmnd[0] != 0x12)
-			desc = "SCSI Device Not There";
+	case MPI_IOCSTATUS_SCSI_INVALID_TARGETID:
+		desc = "invalid target_id";
 		break;
-
-	case MPI_IOCSTATUS_SCSI_DATA_OVERRUN: /* 0x0044 */
-		desc = "SCSI Data Overrun";
+	case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
+		desc = "device not there";
 		break;
-
-	case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR: /* 0x0046 */
-		desc = "SCSI I/O Data Error";
+	case MPI_IOCSTATUS_SCSI_DATA_OVERRUN:
+		desc = "data overrun";
 		break;
-
-	case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR: /* 0x0047 */
-		desc = "SCSI Protocol Error";
+	case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN:
+		desc = "data underrun";
 		break;
-
-	case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
-		desc = "SCSI Task Terminated";
+	case MPI_IOCSTATUS_SCSI_IO_DATA_ERROR:
+		desc = "I/O data error";
 		break;
-
-	case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */
-		desc = "SCSI Residual Mismatch";
+	case MPI_IOCSTATUS_SCSI_PROTOCOL_ERROR:
+		desc = "protocol error";
 		break;
-
-	case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED: /* 0x004A */
-		desc = "SCSI Task Management Failed";
+	case MPI_IOCSTATUS_SCSI_TASK_TERMINATED:
+		desc = "task terminated";
 		break;
-
-	case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
-		desc = "SCSI IOC Terminated";
+	case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
+		desc = "residual mismatch";
 		break;
-
-	case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
-		desc = "SCSI Ext Terminated";
+	case MPI_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
+		desc = "task management failed";
+		break;
+	case MPI_IOCSTATUS_SCSI_IOC_TERMINATED:
+		desc = "IOC terminated";
+		break;
+	case MPI_IOCSTATUS_SCSI_EXT_TERMINATED:
+		desc = "ext terminated";
+		break;
+	default:
+		desc = "";
 		break;
 	}
 
-	if (!desc)
-		return;
+	switch (pScsiReply->SCSIStatus)
+	{
 
-	snprintf(extend_desc, EVENT_DESCR_STR_SZ,
-	    "[%d:%d:%d:%d] cmd=%02Xh, sam_status=%02Xh state=%02Xh",
-		sc->device->host->host_no,
-		sc->device->channel, sc->device->id, sc->device->lun,
-		sc->cmnd[0], scsi_status, scsi_state);
+	case MPI_SCSI_STATUS_SUCCESS:
+		desc1 = "success";
+		break;
+	case MPI_SCSI_STATUS_CHECK_CONDITION:
+		desc1 = "check condition";
+		break;
+	case MPI_SCSI_STATUS_CONDITION_MET:
+		desc1 = "condition met";
+		break;
+	case MPI_SCSI_STATUS_BUSY:
+		desc1 = "busy";
+		break;
+	case MPI_SCSI_STATUS_INTERMEDIATE:
+		desc1 = "intermediate";
+		break;
+	case MPI_SCSI_STATUS_INTERMEDIATE_CONDMET:
+		desc1 = "intermediate condmet";
+		break;
+	case MPI_SCSI_STATUS_RESERVATION_CONFLICT:
+		desc1 = "reservation conflict";
+		break;
+	case MPI_SCSI_STATUS_COMMAND_TERMINATED:
+		desc1 = "command terminated";
+		break;
+	case MPI_SCSI_STATUS_TASK_SET_FULL:
+		desc1 = "task set full";
+		break;
+	case MPI_SCSI_STATUS_ACA_ACTIVE:
+		desc1 = "aca active";
+		break;
+	case MPI_SCSI_STATUS_FCPEXT_DEVICE_LOGGED_OUT:
+		desc1 = "fcpext device logged out";
+		break;
+	case MPI_SCSI_STATUS_FCPEXT_NO_LINK:
+		desc1 = "fcpext no link";
+		break;
+	case MPI_SCSI_STATUS_FCPEXT_UNASSIGNED:
+		desc1 = "fcpext unassigned";
+		break;
+	default:
+		desc1 = "";
+		break;
+	}
 
-	printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04X): %s: %s\n",
-	    ioc->name, ioc_status, desc, extend_desc);
+	scsi_print_command(sc);
+	printk(KERN_DEBUG "\tfw_channel = %d, fw_id = %d\n",
+	    pScsiReply->Bus, pScsiReply->TargetID);
+	printk(KERN_DEBUG "\trequest_len = %d, underflow = %d, resid = %d\n",
+	    scsi_bufflen(sc), sc->underflow, scsi_get_resid(sc));
+	printk(KERN_DEBUG "\ttag = %d, transfer_count = %d, sc->result = %08X\n",
+	    le16_to_cpu(pScsiReply->TaskTag),
+	    le32_to_cpu(pScsiReply->TransferCount), sc->result);
+
+	printk(KERN_DEBUG "\tiocstatus = %s (0x%04x), "
+	    "scsi_status = %s (0x%02x), scsi_state = (0x%02x)\n",
+	    desc, ioc_status,
+	    desc1, pScsiReply->SCSIStatus,
+	    pScsiReply->SCSIState);
+
+	if (pScsiReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_VALID) {
+		skey = sc->sense_buffer[2] & 0x0F;
+		asc = sc->sense_buffer[12];
+		ascq = sc->sense_buffer[13];
+
+		printk(KERN_DEBUG "\t[sense_key,asc,ascq]: "
+		    "[0x%02x,0x%02x,0x%02x]\n",
+		    skey, asc, ascq);
+	}
+
+	/*
+	 *  Look for + dump FCP ResponseInfo[]!
+	 */
+	if (pScsiReply->SCSIState & MPI_SCSI_STATE_RESPONSE_INFO_VALID &&
+	    pScsiReply->ResponseInfo)
+		printk(KERN_DEBUG "response_info = %08xh\n",
+		    le32_to_cpu(pScsiReply->ResponseInfo));
 }
 #endif
 
@@ -627,11 +692,11 @@
 	pScsiReply = (SCSIIOReply_t *) mr;
 
 	if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){
-		dmfprintk((MYIOC_s_INFO_FMT
+		dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 			"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n",
 			ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag));
 	}else{
-		dmfprintk((MYIOC_s_INFO_FMT
+		dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 			"ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n",
 			ioc->name, mf, mr, sc, req_idx));
 	}
@@ -759,7 +824,7 @@
 				sc->result=DID_SOFT_ERROR << 16;
 			else /* Sufficient data transfer occurred */
 				sc->result = (DID_OK << 16) | scsi_status;
-			dreplyprintk((KERN_NOTICE
+			dreplyprintk(ioc, printk(KERN_DEBUG
 			    "RESIDUAL_MISMATCH: result=%x on channel=%d id=%d\n",
 			    sc->result, sc->device->channel, sc->device->id));
 			break;
@@ -792,9 +857,11 @@
 				}
 			}
 
-			dreplyprintk((KERN_NOTICE "  sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
+
+			dreplyprintk(ioc, printk(KERN_DEBUG "  sc->underflow={report ERR if < %02xh bytes xfer'd}\n",
 					sc->underflow));
-			dreplyprintk((KERN_NOTICE "  ActBytesXferd=%02xh\n", xfer_cnt));
+			dreplyprintk(ioc, printk(KERN_DEBUG "  ActBytesXferd=%02xh\n", xfer_cnt));
+
 			/* Report Queue Full
 			 */
 			if (scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)
@@ -871,27 +938,9 @@
 
 		}	/* switch(status) */
 
-#ifdef MPT_DEBUG_REPLY
-		if (sc->result) {
-
-			mptscsih_iocstatus_info_scsiio(ioc, status,
-			    scsi_status, scsi_state, sc);
-
-			dreplyprintk(("%s: [%d:%d:%d:%d] cmd=0x%02x "
-			    "result=0x%08x\n\tiocstatus=0x%04X "
-			    "scsi_state=0x%02X scsi_status=0x%02X "
-			    "loginfo=0x%08X\n", __FUNCTION__,
-			    sc->device->host->host_no, sc->device->channel, sc->device->id,
-			    sc->device->lun, sc->cmnd[0], sc->result, status,
-			    scsi_state, scsi_status, log_info));
-
-			dreplyprintk(("%s: [%d:%d:%d:%d] resid=%d "
-				      "bufflen=%d xfer_cnt=%d\n", __FUNCTION__,
-				      sc->device->host->host_no,
-				      sc->device->channel, sc->device->id,
-				      sc->device->lun, scsi_get_resid(sc),
-				      scsi_bufflen(sc), xfer_cnt));
-		}
+#ifdef CONFIG_FUSION_LOGGING
+		if (sc->result && (ioc->debug_level & MPT_DEBUG_REPLY))
+			mptscsih_info_scsiio(ioc, sc, pScsiReply);
 #endif
 
 	} /* end of address reply case */
@@ -925,7 +974,7 @@
 	int		 ii;
 	int		 max = ioc->req_depth;
 
-	dprintk((KERN_INFO MYNAM ": flush_ScsiLookup called\n"));
+	dprintk(ioc, printk(KERN_DEBUG MYNAM ": flush_ScsiLookup called\n"));
 	for (ii= 0; ii < max; ii++) {
 		if ((SCpnt = hd->ScsiLookup[ii]) != NULL) {
 
@@ -937,7 +986,7 @@
 			hd->ScsiLookup[ii] = NULL;
 
 			mf = MPT_INDEX_2_MFPTR(ioc, ii);
-			dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
+			dmfprintk(ioc, printk(KERN_DEBUG MYNAM ": flush: ScsiDone (mf=%p,sc=%p)\n",
 					mf, SCpnt));
 
 			/* Free Chain buffers */
@@ -987,7 +1036,7 @@
 	struct scsi_cmnd *sc;
 	struct scsi_lun  lun;
 
-	dsprintk((KERN_INFO MYNAM ": search_running channel %d id %d lun %d max %d\n",
+	dsprintk(hd->ioc, printk(KERN_DEBUG MYNAM ": search_running channel %d id %d lun %d max %d\n",
 	    vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun, max));
 
 	for (ii=0; ii < max; ii++) {
@@ -1020,9 +1069,9 @@
 			scsi_dma_unmap(sc);
 			sc->host_scribble = NULL;
 			sc->result = DID_NO_CONNECT << 16;
-			dsprintk(( "search_running: found (sc=%p, mf = %p) "
-			    "channel %d id %d, lun %d \n", sc, mf,
-			    vdevice->vtarget->channel, vdevice->vtarget->id, vdevice->lun));
+			sdev_printk(KERN_INFO, sc->device, "completing cmds: fw_channel %d,"
+			   "fw_id %d, sc=%p, mf = %p, idx=%x\n", vdevice->vtarget->channel,
+			   vdevice->vtarget->id, sc, mf, ii);
 			sc->scsi_done(sc);
 		}
 	}
@@ -1057,7 +1106,7 @@
 		return;
 
 	if (time - hd->last_queue_full > 10 * HZ) {
-		dprintk((MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
+		dprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "Device (%d:%d:%d) reported QUEUE_FULL!\n",
 				hd->ioc->name, 0, sc->device->id, sc->device->lun));
 		hd->last_queue_full = time;
 	}
@@ -1098,7 +1147,7 @@
 		hd->ScsiLookup = NULL;
 	}
 
-	dprintk((MYIOC_s_INFO_FMT
+	dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
 	    "Free'd ScsiLookup (%d) memory\n",
 	    hd->ioc->name, sz1));
 
@@ -1317,17 +1366,19 @@
 	u32	 cmd_len;
 	int	 my_idx;
 	int	 ii;
+	MPT_ADAPTER *ioc;
 
 	hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
+	ioc = hd->ioc;
 	lun = SCpnt->device->lun;
 	SCpnt->scsi_done = done;
 
-	dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n",
-			(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done));
+	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
+		ioc->name, SCpnt, done));
 
 	if (hd->resetPending) {
-		dtmprintk((MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
-			(hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt));
+		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
+			ioc->name, SCpnt));
 		return SCSI_MLQUEUE_HOST_BUSY;
 	}
 
@@ -1335,8 +1386,8 @@
 	 *  Put together a MPT SCSI request...
 	 */
 	if ((mf = mpt_get_msg_frame(hd->ioc->DoneCtx, hd->ioc)) == NULL) {
-		dprintk((MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
-				hd->ioc->name));
+		dprintk(ioc, printk(MYIOC_s_WARN_FMT "QueueCmd, no msg frames!!\n",
+				ioc->name));
 		return SCSI_MLQUEUE_HOST_BUSY;
 	}
 
@@ -1422,9 +1473,9 @@
 	hd->ScsiLookup[my_idx] = SCpnt;
 
 	mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
-	dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
-			hd->ioc->name, SCpnt, mf, my_idx));
-	DBG_DUMP_REQUEST_FRAME(mf)
+	dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
+			ioc->name, SCpnt, mf, my_idx));
+	DBG_DUMP_REQUEST_FRAME(ioc, (u32 *)mf)
 	return 0;
 
  fail:
@@ -1475,7 +1526,7 @@
 		list_add_tail(&chain->u.frame.linkage.list, &ioc->FreeChainQ);
 		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
 
-		dmfprintk((MYIOC_s_INFO_FMT "FreeChainBuffers (index %d)\n",
+		dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "FreeChainBuffers (index %d)\n",
 				ioc->name, chain_idx));
 
 		/* handle next */
@@ -1519,7 +1570,7 @@
 	unsigned long	 flags;
 
 	ioc = hd->ioc;
-	dtmprintk((MYIOC_s_INFO_FMT "TMHandler Entered!\n", ioc->name));
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TMHandler Entered!\n", ioc->name));
 
 	// SJR - CHECKME - Can we avoid this here?
 	// (mpt_HardResetHandler has this check...)
@@ -1539,20 +1590,20 @@
 	 */
 	if (mptscsih_tm_pending_wait(hd) == FAILED) {
 		if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) {
-			dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: "
+			dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler abort: "
 			   "Timed out waiting for last TM (%d) to complete! \n",
-			   hd->ioc->name, hd->tmPending));
+			   ioc->name, hd->tmPending));
 			return FAILED;
 		} else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) {
-			dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target "
+			dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler target "
 				"reset: Timed out waiting for last TM (%d) "
-				"to complete! \n", hd->ioc->name,
+				"to complete! \n", ioc->name,
 				hd->tmPending));
 			return FAILED;
 		} else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) {
-			dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: "
+			dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: TMHandler bus reset: "
 			   "Timed out waiting for last TM (%d) to complete! \n",
-			   hd->ioc->name, hd->tmPending));
+			  ioc->name, hd->tmPending));
 			return FAILED;
 		}
 	} else {
@@ -1591,12 +1642,13 @@
 	    ctx2abort, timeout);
 	if (rc)
 		printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n",
-		       hd->ioc->name);
+		       ioc->name);
 	else
-		dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n",
-			   hd->ioc->name));
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Issue of TaskMgmt Successful!\n",
+			   ioc->name));
 
-	dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
+			"TMHandler rc = %d!\n", ioc->name, rc));
 
 	return rc;
 }
@@ -1632,11 +1684,11 @@
 	/* Return Fail to calling function if no message frames available.
 	 */
 	if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) {
-		dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
+		dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n",
 				hd->ioc->name));
 		return FAILED;
 	}
-	dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n",
+	dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt request @ %p\n",
 			hd->ioc->name, mf));
 
 	/* Format the Request
@@ -1660,27 +1712,27 @@
 
 	pScsiTm->TaskMsgContext = ctx2abort;
 
-	dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
+	dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "IssueTaskMgmt: ctx2abort (0x%08x) "
 		"type=%d\n", hd->ioc->name, ctx2abort, type));
 
-	DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm);
+	DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)pScsiTm);
 
 	if ((retval = mpt_send_handshake_request(hd->ioc->TaskCtx, hd->ioc,
 		sizeof(SCSITaskMgmt_t), (u32*)pScsiTm, CAN_SLEEP)) != 0) {
-		dfailprintk((MYIOC_s_ERR_FMT "send_handshake FAILED!"
+		dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "send_handshake FAILED!"
 			" (hd %p, ioc %p, mf %p, rc=%d) \n", hd->ioc->name, hd,
 			hd->ioc, mf, retval));
 		goto fail_out;
 	}
 
 	if(mptscsih_tm_wait_for_completion(hd, timeout) == FAILED) {
-		dfailprintk((MYIOC_s_ERR_FMT "task management request TIMED OUT!"
+		dfailprintk(hd->ioc, printk(MYIOC_s_ERR_FMT "task management request TIMED OUT!"
 			" (hd %p, ioc %p, mf %p) \n", hd->ioc->name, hd,
 			hd->ioc, mf));
-		dtmprintk((MYIOC_s_INFO_FMT "Calling HardReset! \n",
+		dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Calling HardReset! \n",
 			 hd->ioc->name));
 		retval = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
-		dtmprintk((MYIOC_s_INFO_FMT "rc=%d \n",
+		dtmprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "rc=%d \n",
 			 hd->ioc->name, retval));
 		goto fail_out;
 	}
@@ -1748,8 +1800,8 @@
 	if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) {
 		SCpnt->result = DID_RESET << 16;
 		SCpnt->scsi_done(SCpnt);
-		dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: Can't locate "
-		    "host! (sc=%p)\n", SCpnt));
+		printk(KERN_DEBUG MYNAM ": mptscsih_abort: Can't locate "
+		    "host! (sc=%p)\n", SCpnt);
 		return FAILED;
 	}
 
@@ -1760,7 +1812,7 @@
 
 	vdevice = SCpnt->device->hostdata;
 	if (!vdevice || !vdevice->vtarget) {
-		dtmprintk((MYIOC_s_DEBUG_FMT "task abort: device has been "
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: device has been "
 		    "deleted (sc=%p)\n", ioc->name, SCpnt));
 		SCpnt->result = DID_NO_CONNECT << 16;
 		SCpnt->scsi_done(SCpnt);
@@ -1771,7 +1823,7 @@
 	/* Task aborts are not supported for hidden raid components.
 	 */
 	if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
-		dtmprintk((MYIOC_s_DEBUG_FMT "task abort: hidden raid "
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "task abort: hidden raid "
 		    "component (sc=%p)\n", ioc->name, SCpnt));
 		SCpnt->result = DID_RESET << 16;
 		retval = FAILED;
@@ -1785,7 +1837,7 @@
 		 * Do OS callback.
 		 */
 		SCpnt->result = DID_RESET << 16;
-		dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: "
+		dtmprintk(ioc, printk(KERN_DEBUG MYNAM ": %s: mptscsih_abort: "
 		   "Command not in the active list! (sc=%p)\n", ioc->name,
 		   SCpnt));
 		retval = 0;
@@ -1850,8 +1902,8 @@
 	/* If we can't locate our host adapter structure, return FAILED status.
 	 */
 	if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
-		dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: Can't "
-		    "locate host! (sc=%p)\n", SCpnt));
+		printk(KERN_DEBUG MYNAM ": mptscsih_dev_reset: Can't "
+		    "locate host! (sc=%p)\n", SCpnt);
 		return FAILED;
 	}
 
@@ -1913,8 +1965,8 @@
 	/* If we can't locate our host adapter structure, return FAILED status.
 	 */
 	if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
-		dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: Can't "
-		    "locate host! (sc=%p)\n", SCpnt ));
+		printk(KERN_DEBUG MYNAM ": mptscsih_bus_reset: Can't "
+		    "locate host! (sc=%p)\n", SCpnt );
 		return FAILED;
 	}
 
@@ -1957,8 +2009,8 @@
 
 	/*  If we can't locate the host to reset, then we failed. */
 	if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){
-		dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: Can't "
-		    "locate host! (sc=%p)\n", SCpnt));
+		printk( KERN_DEBUG MYNAM ": mptscsih_host_reset: Can't "
+		    "locate host! (sc=%p)\n", SCpnt);
 		return FAILED;
 	}
 
@@ -2106,16 +2158,16 @@
 	u8			 tmType;
 	u32			 termination_count;
 
-	dtmprintk((MYIOC_s_WARN_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
+	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed (mf=%p,mr=%p)\n",
 	    ioc->name, mf, mr));
 	if (!ioc->sh) {
-		dtmprintk((MYIOC_s_WARN_FMT
+		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
 		    "TaskMgmt Complete: NULL Scsi Host Ptr\n", ioc->name));
 		return 1;
 	}
 
 	if (mr == NULL) {
-		dtmprintk((MYIOC_s_WARN_FMT
+		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT
 		    "ERROR! TaskMgmt Reply: NULL Request %p\n", ioc->name, mf));
 		return 1;
 	}
@@ -2131,19 +2183,21 @@
 	    pScsiTmReply->ResponseCode)
 		mptscsih_taskmgmt_response_code(ioc,
 		    pScsiTmReply->ResponseCode);
-	DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
+	DBG_DUMP_TM_REPLY_FRAME(ioc, (u32 *)pScsiTmReply);
 
-#if defined(MPT_DEBUG_REPLY) || defined(MPT_DEBUG_TM)
-	printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
-	    "iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
-	    "term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
-	    pScsiTmReply->TargetID, pScsiTmReq->TaskType,
-	    le16_to_cpu(pScsiTmReply->IOCStatus),
-	    le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
-	    le32_to_cpu(pScsiTmReply->TerminationCount));
+#ifdef CONFIG_FUSION_LOGGING
+	if ((ioc->debug_level & MPT_DEBUG_REPLY) ||
+				(ioc->debug_level & MPT_DEBUG_TM ))
+		printk("%s: ha=%d [%d:%d:0] task_type=0x%02X "
+			"iocstatus=0x%04X\n\tloginfo=0x%08X response_code=0x%02X "
+			"term_cmnds=%d\n", __FUNCTION__, ioc->id, pScsiTmReply->Bus,
+			 pScsiTmReply->TargetID, pScsiTmReq->TaskType,
+			le16_to_cpu(pScsiTmReply->IOCStatus),
+			le32_to_cpu(pScsiTmReply->IOCLogInfo),pScsiTmReply->ResponseCode,
+			le32_to_cpu(pScsiTmReply->TerminationCount));
 #endif
 	if (!iocstatus) {
-		dtmprintk((MYIOC_s_WARN_FMT " TaskMgmt SUCCESS\n", ioc->name));
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT " TaskMgmt SUCCESS\n", ioc->name));
 			hd->abortSCpnt = NULL;
 		goto out;
 	}
@@ -2224,10 +2278,6 @@
 	geom[1] = sectors;
 	geom[2] = cylinders;
 
-	dprintk((KERN_NOTICE
-		": bios_param: Id=%i Lun=%i Channel=%i CHS=%i/%i/%i\n",
-		sdev->id, sdev->lun, sdev->channel, (int)cylinders, heads, sectors));
-
 	return 0;
 }
 
@@ -2393,11 +2443,11 @@
 	vtarget = starget->hostdata;
 	vdevice = sdev->hostdata;
 
-	dsprintk((MYIOC_s_INFO_FMT
+	dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
 		"device @ %p, channel=%d, id=%d, lun=%d\n",
 		hd->ioc->name, sdev, sdev->channel, sdev->id, sdev->lun));
 	if (hd->ioc->bus_type == SPI)
-		dsprintk((MYIOC_s_INFO_FMT
+		dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
 		    "sdtr %d wdtr %d ppr %d inq length=%d\n",
 		    hd->ioc->name, sdev->sdtr, sdev->wdtr,
 		    sdev->ppr, sdev->inquiry_len));
@@ -2411,19 +2461,19 @@
 	vdevice->configured_lun = 1;
 	mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
 
-	dsprintk((MYIOC_s_INFO_FMT
+	dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
 		"Queue depth=%d, tflags=%x\n",
 		hd->ioc->name, sdev->queue_depth, vtarget->tflags));
 
 	if (hd->ioc->bus_type == SPI)
-		dsprintk((MYIOC_s_INFO_FMT
+		dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
 		    "negoFlags=%x, maxOffset=%x, SyncFactor=%x\n",
 		    hd->ioc->name, vtarget->negoFlags, vtarget->maxOffset,
 		    vtarget->minSyncFactor));
 
 slave_configure_exit:
 
-	dsprintk((MYIOC_s_INFO_FMT
+	dsprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT
 		"tagged %d, simple %d, ordered %d\n",
 		hd->ioc->name,sdev->tagged_supported, sdev->simple_tags,
 		sdev->ordered_tags));
@@ -2490,7 +2540,7 @@
 			}
 		}
 	} else {
-		dprintk((MYIOC_s_INFO_FMT "Hmmm... SenseData len=0! (?)\n",
+		dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Hmmm... SenseData len=0! (?)\n",
 				hd->ioc->name));
 	}
 }
@@ -2520,7 +2570,7 @@
 	unsigned long	 flags;
 	int 		ii;
 
-	dtmprintk((KERN_WARNING MYNAM
+	dtmprintk(ioc, printk(KERN_DEBUG MYNAM
 			": IOC %s_reset routed to SCSI host driver!\n",
 			reset_phase==MPT_IOC_SETUP_RESET ? "setup" : (
 			reset_phase==MPT_IOC_PRE_RESET ? "pre" : "post")));
@@ -2535,7 +2585,7 @@
 		hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
 
 	if (reset_phase == MPT_IOC_SETUP_RESET) {
-		dtmprintk((MYIOC_s_WARN_FMT "Setup-Diag Reset\n", ioc->name));
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Setup-Diag Reset\n", ioc->name));
 
 		/* Clean Up:
 		 * 1. Set Hard Reset Pending Flag
@@ -2544,7 +2594,7 @@
 		hd->resetPending = 1;
 
 	} else if (reset_phase == MPT_IOC_PRE_RESET) {
-		dtmprintk((MYIOC_s_WARN_FMT "Pre-Diag Reset\n", ioc->name));
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Diag Reset\n", ioc->name));
 
 		/* 2. Flush running commands
 		 *	Clean ScsiLookup (and associated memory)
@@ -2564,10 +2614,10 @@
 			mpt_free_msg_frame(ioc, hd->cmdPtr);
 		}
 
-		dtmprintk((MYIOC_s_WARN_FMT "Pre-Reset complete.\n", ioc->name));
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Pre-Reset complete.\n", ioc->name));
 
 	} else {
-		dtmprintk((MYIOC_s_WARN_FMT "Post-Diag Reset\n", ioc->name));
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Diag Reset\n", ioc->name));
 
 		/* Once a FW reload begins, all new OS commands are
 		 * redirected to the doneQ w/ a reset status.
@@ -2607,7 +2657,7 @@
 			hd->cmdPtr = NULL;
 		}
 
-		dtmprintk((MYIOC_s_WARN_FMT "Post-Reset complete.\n", ioc->name));
+		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Post-Reset complete.\n", ioc->name));
 
 	}
 
@@ -2621,7 +2671,7 @@
 	MPT_SCSI_HOST *hd;
 	u8 event = le32_to_cpu(pEvReply->Event) & 0xFF;
 
-	devtverboseprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
+	devtverboseprintk(ioc, printk(MYIOC_s_DEBUG_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n",
 			ioc->name, event));
 
 	if (ioc->sh == NULL ||
@@ -2663,7 +2713,7 @@
 	case MPI_EVENT_STATE_CHANGE:			/* 02 */
 	case MPI_EVENT_EVENT_CHANGE:			/* 0A */
 	default:
-		dprintk((KERN_INFO "  Ignoring event (=%02Xh)\n", event));
+		dprintk(ioc, printk(KERN_DEBUG MYNAM ": Ignoring event (=%02Xh)\n", event));
 		break;
 	}
 
@@ -2724,7 +2774,7 @@
 	}
 	hd->cmdPtr = NULL;
 
-	ddvprintk((MYIOC_s_INFO_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
+	ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScanDvComplete (mf=%p,mr=%p,idx=%d)\n",
 			hd->ioc->name, mf, mr, req_idx));
 
 	hd->pLocal = &hd->localReply;
@@ -2744,9 +2794,6 @@
 		status = le16_to_cpu(pReply->IOCStatus) & MPI_IOCSTATUS_MASK;
 		scsi_status = pReply->SCSIStatus;
 
-		ddvtprintk((KERN_NOTICE "  IOCStatus=%04xh, SCSIState=%02xh, SCSIStatus=%02xh, IOCLogInfo=%08xh\n",
-			     status, pReply->SCSIState, scsi_status,
-			     le32_to_cpu(pReply->IOCLogInfo)));
 
 		switch(status) {
 
@@ -2799,7 +2846,7 @@
 							SCSI_STD_SENSE_BYTES);
 				memcpy(hd->pLocal->sense, sense_data, sz);
 
-				ddvprintk((KERN_NOTICE "  Check Condition, sense ptr %p\n",
+				ddvprintk(ioc, printk(KERN_DEBUG "  Check Condition, sense ptr %p\n",
 						sense_data));
 			} else if (pReply->SCSIState & MPI_SCSI_STATE_AUTOSENSE_FAILED) {
 				if (pReq->CDB[0] == INQUIRY)
@@ -2830,8 +2877,6 @@
 
 		}	/* switch(status) */
 
-		ddvtprintk((KERN_NOTICE "  completionCode set to %08xh\n",
-				completionCode));
 	} /* end of address reply case */
 
 	hd->pLocal->completion = completionCode;
@@ -2862,7 +2907,7 @@
 {
 	MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) data;
 
-	ddvprintk((MYIOC_s_WARN_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
+	ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired! Cmd %p\n", hd->ioc->name, hd->cmdPtr));
 
 	if (hd->cmdPtr) {
 		MPIHeader_t *cmd = (MPIHeader_t *)hd->cmdPtr;
@@ -2874,7 +2919,6 @@
 			 * If new eh code, do nothing. Wait for OS cmd timeout
 			 *	for bus reset.
 			 */
-			ddvtprintk((MYIOC_s_NOTE_FMT "DV Cmd Timeout: NoOp\n", hd->ioc->name));
 		} else {
 			/* Perform a FW reload */
 			if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0) {
@@ -2891,7 +2935,7 @@
 	 * The FW will reply to all outstanding commands, callback will finish cleanup.
 	 * Hard reset clean-up will free all resources.
 	 */
-	ddvprintk((MYIOC_s_WARN_FMT "Timer Expired Complete!\n", hd->ioc->name));
+	ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Timer Expired Complete!\n", hd->ioc->name));
 
 	return;
 }
@@ -2932,7 +2976,7 @@
 
 	in_isr = in_interrupt();
 	if (in_isr) {
-		dprintk((MYIOC_s_WARN_FMT "Internal SCSI IO request not allowed in ISR context!\n",
+		dprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Internal SCSI IO request not allowed in ISR context!\n",
        				hd->ioc->name));
 		return -EPERM;
 	}
@@ -3035,7 +3079,7 @@
 	/* Get and Populate a free Frame
 	 */
 	if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
-		ddvprintk((MYIOC_s_WARN_FMT "No msg frames!\n",
+		ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "No msg frames!\n",
 					hd->ioc->name));
 		return -EBUSY;
 	}
@@ -3075,7 +3119,7 @@
 
 	if (cmd == REQUEST_SENSE) {
 		pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED);
-		ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n",
+		ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Untagged! 0x%2x\n",
 			hd->ioc->name, cmd));
 	}
 
@@ -3086,7 +3130,7 @@
 	pScsiReq->SenseBufferLowAddr = cpu_to_le32(hd->ioc->sense_buf_low_dma
 					   + (my_idx * MPT_SENSE_BUFFER_ALLOC));
 
-	ddvprintk((MYIOC_s_INFO_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
+	ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "Sending Command 0x%x for (%d:%d:%d)\n",
 			hd->ioc->name, cmd, io->channel, io->id, io->lun));
 
 	if (dir == MPI_SCSIIO_CONTROL_READ) {
@@ -3138,7 +3182,7 @@
 	} else {
 		rc = -EFAULT;
 		/* This should never happen. */
-		ddvprintk((MYIOC_s_INFO_FMT "_do_cmd: Null pLocal!!!\n",
+		ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "_do_cmd: Null pLocal!!!\n",
 				hd->ioc->name));
 	}
 
@@ -3187,6 +3231,189 @@
 	mptscsih_do_cmd(hd, &iocmd);
 }
 
+static ssize_t
+mptscsih_version_fw_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	MPT_SCSI_HOST	*hd = (MPT_SCSI_HOST *)host->hostdata;
+	MPT_ADAPTER *ioc = hd->ioc;
+
+	return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
+	    (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
+	    (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
+	    (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
+	    ioc->facts.FWVersion.Word & 0x000000FF);
+}
+static CLASS_DEVICE_ATTR(version_fw, S_IRUGO, mptscsih_version_fw_show, NULL);
+
+static ssize_t
+mptscsih_version_bios_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	MPT_SCSI_HOST	*hd = (MPT_SCSI_HOST *)host->hostdata;
+	MPT_ADAPTER *ioc = hd->ioc;
+
+	return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n",
+	    (ioc->biosVersion & 0xFF000000) >> 24,
+	    (ioc->biosVersion & 0x00FF0000) >> 16,
+	    (ioc->biosVersion & 0x0000FF00) >> 8,
+	    ioc->biosVersion & 0x000000FF);
+}
+static CLASS_DEVICE_ATTR(version_bios, S_IRUGO, mptscsih_version_bios_show, NULL);
+
+static ssize_t
+mptscsih_version_mpi_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	MPT_SCSI_HOST	*hd = (MPT_SCSI_HOST *)host->hostdata;
+	MPT_ADAPTER *ioc = hd->ioc;
+
+	return snprintf(buf, PAGE_SIZE, "%03x\n", ioc->facts.MsgVersion);
+}
+static CLASS_DEVICE_ATTR(version_mpi, S_IRUGO, mptscsih_version_mpi_show, NULL);
+
+static ssize_t
+mptscsih_version_product_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	MPT_SCSI_HOST	*hd = (MPT_SCSI_HOST *)host->hostdata;
+	MPT_ADAPTER *ioc = hd->ioc;
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->prod_name);
+}
+static CLASS_DEVICE_ATTR(version_product, S_IRUGO,
+    mptscsih_version_product_show, NULL);
+
+static ssize_t
+mptscsih_version_nvdata_persistent_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	MPT_SCSI_HOST	*hd = (MPT_SCSI_HOST *)host->hostdata;
+	MPT_ADAPTER *ioc = hd->ioc;
+
+	return snprintf(buf, PAGE_SIZE, "%02xh\n",
+	    ioc->nvdata_version_persistent);
+}
+static CLASS_DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
+    mptscsih_version_nvdata_persistent_show, NULL);
+
+static ssize_t
+mptscsih_version_nvdata_default_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	MPT_SCSI_HOST	*hd = (MPT_SCSI_HOST *)host->hostdata;
+	MPT_ADAPTER *ioc = hd->ioc;
+
+	return snprintf(buf, PAGE_SIZE, "%02xh\n",ioc->nvdata_version_default);
+}
+static CLASS_DEVICE_ATTR(version_nvdata_default, S_IRUGO,
+    mptscsih_version_nvdata_default_show, NULL);
+
+static ssize_t
+mptscsih_board_name_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	MPT_SCSI_HOST	*hd = (MPT_SCSI_HOST *)host->hostdata;
+	MPT_ADAPTER *ioc = hd->ioc;
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_name);
+}
+static CLASS_DEVICE_ATTR(board_name, S_IRUGO, mptscsih_board_name_show, NULL);
+
+static ssize_t
+mptscsih_board_assembly_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	MPT_SCSI_HOST	*hd = (MPT_SCSI_HOST *)host->hostdata;
+	MPT_ADAPTER *ioc = hd->ioc;
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_assembly);
+}
+static CLASS_DEVICE_ATTR(board_assembly, S_IRUGO,
+    mptscsih_board_assembly_show, NULL);
+
+static ssize_t
+mptscsih_board_tracer_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	MPT_SCSI_HOST	*hd = (MPT_SCSI_HOST *)host->hostdata;
+	MPT_ADAPTER *ioc = hd->ioc;
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", ioc->board_tracer);
+}
+static CLASS_DEVICE_ATTR(board_tracer, S_IRUGO,
+    mptscsih_board_tracer_show, NULL);
+
+static ssize_t
+mptscsih_io_delay_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	MPT_SCSI_HOST	*hd = (MPT_SCSI_HOST *)host->hostdata;
+	MPT_ADAPTER *ioc = hd->ioc;
+
+	return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
+}
+static CLASS_DEVICE_ATTR(io_delay, S_IRUGO,
+    mptscsih_io_delay_show, NULL);
+
+static ssize_t
+mptscsih_device_delay_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	MPT_SCSI_HOST	*hd = (MPT_SCSI_HOST *)host->hostdata;
+	MPT_ADAPTER *ioc = hd->ioc;
+
+	return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
+}
+static CLASS_DEVICE_ATTR(device_delay, S_IRUGO,
+    mptscsih_device_delay_show, NULL);
+
+static ssize_t
+mptscsih_debug_level_show(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	MPT_SCSI_HOST	*hd = (MPT_SCSI_HOST *)host->hostdata;
+	MPT_ADAPTER *ioc = hd->ioc;
+
+	return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->debug_level);
+}
+static ssize_t
+mptscsih_debug_level_store(struct class_device *cdev, const char *buf,
+								size_t count)
+{
+	struct Scsi_Host *host = class_to_shost(cdev);
+	MPT_SCSI_HOST	*hd = (MPT_SCSI_HOST *)host->hostdata;
+	MPT_ADAPTER *ioc = hd->ioc;
+	int val = 0;
+
+	if (sscanf(buf, "%x", &val) != 1)
+		return -EINVAL;
+
+	ioc->debug_level = val;
+	printk(MYIOC_s_INFO_FMT "debug_level=%08xh\n",
+				ioc->name, ioc->debug_level);
+	return strlen(buf);
+}
+static CLASS_DEVICE_ATTR(debug_level, S_IRUGO | S_IWUSR,
+    mptscsih_debug_level_show, mptscsih_debug_level_store);
+
+struct class_device_attribute *mptscsih_host_attrs[] = {
+	&class_device_attr_version_fw,
+	&class_device_attr_version_bios,
+	&class_device_attr_version_mpi,
+	&class_device_attr_version_product,
+	&class_device_attr_version_nvdata_persistent,
+	&class_device_attr_version_nvdata_default,
+	&class_device_attr_board_name,
+	&class_device_attr_board_assembly,
+	&class_device_attr_board_tracer,
+	&class_device_attr_io_delay,
+	&class_device_attr_device_delay,
+	&class_device_attr_debug_level,
+	NULL,
+};
+EXPORT_SYMBOL(mptscsih_host_attrs);
+
 EXPORT_SYMBOL(mptscsih_remove);
 EXPORT_SYMBOL(mptscsih_shutdown);
 #ifdef CONFIG_PM
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
index 8eccdfe..67b088d 100644
--- a/drivers/message/fusion/mptscsih.h
+++ b/drivers/message/fusion/mptscsih.h
@@ -129,3 +129,4 @@
 extern int mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 id, int lun, int ctx2abort, ulong timeout);
 extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id);
 extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id);
+extern struct class_device_attribute *mptscsih_host_attrs[];
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 6b3e0c0..8c98420 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -138,7 +138,9 @@
 				else {
 					factor = MPT_ULTRA320;
 					if (scsi_device_qas(sdev)) {
-						ddvprintk((KERN_INFO "Enabling QAS due to byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id));
+						ddvprintk(hd->ioc,
+						printk(KERN_DEBUG "Enabling QAS due to "
+						"byte56=%02x on id=%d!\n", scsi_device_qas(sdev), id));
 						noQas = 0;
 					}
 					if (sdev->type == TYPE_TAPE &&
@@ -225,7 +227,8 @@
 		/* Disable QAS in a mixed configuration case
 		 */
 
-		ddvprintk((KERN_INFO "Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
+		ddvprintk(hd->ioc, printk(KERN_DEBUG
+			"Disabling QAS due to noQas=%02x on id=%d!\n", noQas, id));
 	}
 }
 
@@ -256,8 +259,8 @@
 	/* Get a MF for this command.
 	 */
 	if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) {
-		dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n",
-					ioc->name));
+		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
+				"writeIOCPage4 : no msg frames!\n",ioc->name));
 		return -EAGAIN;
 	}
 
@@ -297,7 +300,7 @@
 
 	mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, dataDma);
 
-	ddvprintk((MYIOC_s_INFO_FMT
+	ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		"writeIOCPage4: MaxSEP=%d ActiveSEP=%d id=%d bus=%d\n",
 			ioc->name, IOCPage4Ptr->MaxSEP, IOCPage4Ptr->ActiveSEP, id, channel));
 
@@ -422,7 +425,7 @@
 	if (starget->channel == 0 &&
 	    mptspi_is_raid(hd, starget->id)) {
 		vtarget->raidVolume = 1;
-		ddvprintk((KERN_INFO
+		ddvprintk(hd->ioc, printk(KERN_DEBUG
 		    "RAID Volume @ channel=%d id=%d\n", starget->channel,
 		    starget->id));
 	}
@@ -462,7 +465,7 @@
 static void
 mptspi_print_write_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
 {
-	ddvprintk((MYIOC_s_INFO_FMT "id=%d Requested = 0x%08x"
+	ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Requested = 0x%08x"
 	    " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
 	    hd->ioc->name, starget->id, ii,
 	    ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
@@ -487,7 +490,7 @@
 static void
 mptspi_print_read_nego(struct _MPT_SCSI_HOST *hd, struct scsi_target *starget, u32 ii)
 {
-	ddvprintk((MYIOC_s_INFO_FMT "id=%d Read = 0x%08x"
+	ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d Read = 0x%08x"
 	    " ( %s factor = 0x%02x @ offset = 0x%02x %s%s%s%s%s%s%s%s)\n",
 	    hd->ioc->name, starget->id, ii,
 	    ii & MPI_SCSIDEVPAGE0_NP_WIDE ? "Wide ": "",
@@ -613,7 +616,7 @@
 	/* Get and Populate a free Frame
 	 */
 	if ((mf = mpt_get_msg_frame(hd->ioc->InternalCtx, hd->ioc)) == NULL) {
-		ddvprintk((MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
+		ddvprintk(hd->ioc, printk(MYIOC_s_WARN_FMT "_do_raid: no msg frames!\n",
 					hd->ioc->name));
 		return -EAGAIN;
 	}
@@ -635,7 +638,7 @@
 	mpt_add_sge((char *)&pReq->ActionDataSGE,
 		MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
 
-	ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action=%x channel=%d id=%d\n",
+	ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "RAID Volume action=%x channel=%d id=%d\n",
 			hd->ioc->name, pReq->Action, channel, id));
 
 	hd->pLocal = NULL;
@@ -735,7 +738,7 @@
 	if (ret)
 		return ret;
 
-	ddvprintk((MYIOC_s_INFO_FMT "id=%d min_period=0x%02x"
+	ddvprintk(hd->ioc, printk(MYIOC_s_DEBUG_FMT "id=%d min_period=0x%02x"
 		" max_offset=0x%02x max_width=%d\n", hd->ioc->name,
 		sdev->id, spi_min_period(scsi_target(sdev)),
 		spi_max_offset(scsi_target(sdev)),
@@ -768,10 +771,8 @@
 		return 0;
 	}
 
-#ifdef MPT_DEBUG_DV
 	if (spi_dv_pending(scsi_target(SCpnt->device)))
-		scsi_print_command(SCpnt);
-#endif
+		ddvprintk(hd->ioc, scsi_print_command(SCpnt));
 
 	return mptscsih_qcmd(SCpnt,done);
 }
@@ -821,6 +822,7 @@
 	.max_sectors			= 8192,
 	.cmd_per_lun			= 7,
 	.use_clustering			= ENABLE_CLUSTERING,
+	.shost_attrs			= mptscsih_host_attrs,
 };
 
 static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
@@ -1414,7 +1416,7 @@
 
 	if (numSGE < sh->sg_tablesize) {
 		/* Reset this value */
-		dprintk((MYIOC_s_INFO_FMT
+		dprintk(ioc, printk(MYIOC_s_INFO_FMT
 		  "Resetting sg_tablesize to %d from %d\n",
 		  ioc->name, numSGE, sh->sg_tablesize));
 		sh->sg_tablesize = numSGE;
@@ -1434,7 +1436,7 @@
 		goto out_mptspi_probe;
 	}
 
-	dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
+	dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
 		 ioc->name, hd->ScsiLookup));
 
 	/* Clear the TM flags
@@ -1462,7 +1464,7 @@
 	ioc->spi_data.Saf_Te = mpt_saf_te;
 
 	hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
-	ddvprintk((MYIOC_s_INFO_FMT
+	ddvprintk(ioc, printk(MYIOC_s_DEBUG_FMT
 		"saf_te %x\n",
 		ioc->name,
 		mpt_saf_te));
@@ -1480,7 +1482,7 @@
 
 	error = scsi_add_host (sh, &ioc->pcidev->dev);
 	if(error) {
-		dprintk((KERN_ERR MYNAM
+		dprintk(ioc, printk(KERN_ERR MYNAM
 		  "scsi_add_host failed\n"));
 		goto out_mptspi_probe;
 	}
@@ -1523,6 +1525,8 @@
 static int __init
 mptspi_init(void)
 {
+	int error;
+
 	show_mptmod_ver(my_NAME, my_VERSION);
 
 	mptspi_transport_template = spi_attach_transport(&mptspi_transport_functions);
@@ -1533,17 +1537,14 @@
 	mptspiTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSPI_DRIVER);
 	mptspiInternalCtx = mpt_register(mptscsih_scandv_complete, MPTSPI_DRIVER);
 
-	if (mpt_event_register(mptspiDoneCtx, mptspi_event_process) == 0) {
-		devtverboseprintk((KERN_INFO MYNAM
-		  ": Registered for IOC event notifications\n"));
-	}
+	mpt_event_register(mptspiDoneCtx, mptspi_event_process);
+	mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset);
 
-	if (mpt_reset_register(mptspiDoneCtx, mptspi_ioc_reset) == 0) {
-		dprintk((KERN_INFO MYNAM
-		  ": Registered for IOC reset notifications\n"));
-	}
+	error = pci_register_driver(&mptspi_driver);
+	if (error)
+		spi_release_transport(mptspi_transport_template);
 
-	return pci_register_driver(&mptspi_driver);
+	return error;
 }
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -1557,12 +1558,7 @@
 	pci_unregister_driver(&mptspi_driver);
 
 	mpt_reset_deregister(mptspiDoneCtx);
-	dprintk((KERN_INFO MYNAM
-	  ": Deregistered for IOC reset notifications\n"));
-
 	mpt_event_deregister(mptspiDoneCtx);
-	dprintk((KERN_INFO MYNAM
-	  ": Deregistered for IOC event notifications\n"));
 
 	mpt_deregister(mptspiInternalCtx);
 	mpt_deregister(mptspiTaskCtx);
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index 64a52bd..50b2c73 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -159,7 +159,7 @@
  *	Returns 0 on success or negative error code on failure.
  */
 
-static int i2o_block_issue_flush(request_queue_t * queue, struct gendisk *disk,
+static int i2o_block_issue_flush(struct request_queue * queue, struct gendisk *disk,
 				 sector_t * error_sector)
 {
 	struct i2o_block_device *i2o_blk_dev = queue->queuedata;
@@ -445,7 +445,7 @@
 {
 	struct i2o_block_request *ireq = req->special;
 	struct i2o_block_device *dev = ireq->i2o_blk_dev;
-	request_queue_t *q = req->q;
+	struct request_queue *q = req->q;
 	unsigned long flags;
 
 	if (end_that_request_chunk(req, uptodate, nr_bytes)) {
@@ -744,7 +744,7 @@
 {
 	struct i2o_block_device *dev = req->rq_disk->private_data;
 	struct i2o_controller *c;
-	int tid = dev->i2o_dev->lct_data.tid;
+	u32 tid = dev->i2o_dev->lct_data.tid;
 	struct i2o_message *msg;
 	u32 *mptr;
 	struct i2o_block_request *ireq = req->special;
@@ -1171,8 +1171,7 @@
 	/* Allocate request mempool and slab */
 	size = sizeof(struct i2o_block_request);
 	i2o_blk_req_pool.slab = kmem_cache_create("i2o_block_req", size, 0,
-						  SLAB_HWCACHE_ALIGN, NULL,
-						  NULL);
+						  SLAB_HWCACHE_ALIGN, NULL);
 	if (!i2o_blk_req_pool.slab) {
 		osm_err("can't init request slab\n");
 		rc = -ENOMEM;
diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
index 75f401d..b4ed57e 100644
--- a/drivers/mfd/mcp-core.c
+++ b/drivers/mfd/mcp-core.c
@@ -200,9 +200,8 @@
 {
 	struct mcp *mcp;
 
-	mcp = kmalloc(sizeof(struct mcp) + size, GFP_KERNEL);
+	mcp = kzalloc(sizeof(struct mcp) + size, GFP_KERNEL);
 	if (mcp) {
-		memset(mcp, 0, sizeof(struct mcp) + size);
 		spin_lock_init(&mcp->lock);
 		mcp->attached_device.parent = parent;
 		mcp->attached_device.bus = &mcp_bus_type;
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 149810a..e03f1bc 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -484,12 +484,11 @@
 		goto err_disable;
 	}
 
-	ucb = kmalloc(sizeof(struct ucb1x00), GFP_KERNEL);
+	ucb = kzalloc(sizeof(struct ucb1x00), GFP_KERNEL);
 	ret = -ENOMEM;
 	if (!ucb)
 		goto err_disable;
 
-	memset(ucb, 0, sizeof(struct ucb1x00));
 
 	ucb->cdev.class = &ucb1x00_class;
 	ucb->cdev.dev = &mcp->attached_device;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 1d516f2..73e248f 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -5,6 +5,11 @@
 menuconfig MISC_DEVICES
 	bool "Misc devices"
 	default y
+	---help---
+	  Say Y here to get to see options for device drivers from various
+	  different categories. This option alone does not add any kernel code.
+
+	  If you say N, all options in this submenu will be skipped and disabled.
 
 if MISC_DEVICES
 
@@ -150,6 +155,7 @@
 	depends on X86 && ACPI
 	select BACKLIGHT_CLASS_DEVICE
 	select HWMON
+	select NVRAM
 	---help---
 	  This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
 	  support for Fn-Fx key combinations, Bluetooth control, video
@@ -196,4 +202,5 @@
 
 	  If you are not sure, say Y here.
 
+
 endif # MISC_DEVICES
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
index 7798f590e..7dce318 100644
--- a/drivers/misc/asus-laptop.c
+++ b/drivers/misc/asus-laptop.c
@@ -53,7 +53,6 @@
 #define ASUS_HOTK_NAME          "Asus Laptop Support"
 #define ASUS_HOTK_CLASS         "hotkey"
 #define ASUS_HOTK_DEVICE_NAME   "Hotkey"
-#define ASUS_HOTK_HID           "ATK0100"
 #define ASUS_HOTK_FILE          "asus-laptop"
 #define ASUS_HOTK_PREFIX        "\\_SB.ATKD."
 
@@ -197,12 +196,18 @@
 /*
  * The hotkey driver declaration
  */
+static const struct acpi_device_id asus_device_ids[] = {
+	{"ATK0100", 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, asus_device_ids);
+
 static int asus_hotk_add(struct acpi_device *device);
 static int asus_hotk_remove(struct acpi_device *device, int type);
 static struct acpi_driver asus_hotk_driver = {
 	.name = ASUS_HOTK_NAME,
 	.class = ASUS_HOTK_CLASS,
-	.ids = ASUS_HOTK_HID,
+	.ids = asus_device_ids,
 	.ops = {
 		.add = asus_hotk_add,
 		.remove = asus_hotk_remove,
@@ -727,7 +732,7 @@
 		lcd_blank(FB_BLANK_POWERDOWN);
 	}
 
-	acpi_bus_generate_event(hotk->device, event,
+	acpi_bus_generate_proc_event(hotk->device, event,
 				hotk->event_count[event % 128]++);
 
 	return;
@@ -979,10 +984,9 @@
 	printk(ASUS_NOTICE "Asus Laptop Support version %s\n",
 	       ASUS_LAPTOP_VERSION);
 
-	hotk = kmalloc(sizeof(struct asus_hotk), GFP_KERNEL);
+	hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
 	if (!hotk)
 		return -ENOMEM;
-	memset(hotk, 0, sizeof(struct asus_hotk));
 
 	hotk->handle = device->handle;
 	strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
@@ -1068,19 +1072,17 @@
 }
 
 #define  ASUS_LED_UNREGISTER(object)				\
-	if(object##_led.class_dev				\
-	   && !IS_ERR(object##_led.class_dev))			\
+	if (object##_led.dev)					\
 		led_classdev_unregister(&object##_led)
 
 static void asus_led_exit(void)
 {
+	destroy_workqueue(led_workqueue);
 	ASUS_LED_UNREGISTER(mled);
 	ASUS_LED_UNREGISTER(tled);
 	ASUS_LED_UNREGISTER(pled);
 	ASUS_LED_UNREGISTER(rled);
 	ASUS_LED_UNREGISTER(gled);
-
-	destroy_workqueue(led_workqueue);
 }
 
 static void __exit asus_laptop_exit(void)
@@ -1136,29 +1138,42 @@
 
 	rv = ASUS_LED_REGISTER(mled, dev);
 	if (rv)
-		return rv;
+		goto out;
 
 	rv = ASUS_LED_REGISTER(tled, dev);
 	if (rv)
-		return rv;
+		goto out1;
 
 	rv = ASUS_LED_REGISTER(rled, dev);
 	if (rv)
-		return rv;
+		goto out2;
 
 	rv = ASUS_LED_REGISTER(pled, dev);
 	if (rv)
-		return rv;
+		goto out3;
 
 	rv = ASUS_LED_REGISTER(gled, dev);
 	if (rv)
-		return rv;
+		goto out4;
 
 	led_workqueue = create_singlethread_workqueue("led_workqueue");
 	if (!led_workqueue)
-		return -ENOMEM;
+		goto out5;
 
 	return 0;
+out5:
+	rv = -ENOMEM;
+	ASUS_LED_UNREGISTER(gled);
+out4:
+	ASUS_LED_UNREGISTER(pled);
+out3:
+	ASUS_LED_UNREGISTER(rled);
+out2:
+	ASUS_LED_UNREGISTER(tled);
+out1:
+	ASUS_LED_UNREGISTER(mled);
+out:
+	return rv;
 }
 
 static int __init asus_laptop_init(void)
diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c
index 276ba3c..aa8ce7ab 100644
--- a/drivers/misc/hdpuftrs/hdpu_cpustate.c
+++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c
@@ -19,16 +19,41 @@
 #include <linux/spinlock.h>
 #include <linux/miscdevice.h>
 #include <linux/proc_fs.h>
+#include <linux/hdpu_features.h>
 #include <linux/platform_device.h>
 #include <asm/uaccess.h>
-#include <linux/hdpu_features.h>
+#include <linux/seq_file.h>
+#include <asm/io.h>
 
 #define SKY_CPUSTATE_VERSION		"1.1"
 
 static int hdpu_cpustate_probe(struct platform_device *pdev);
 static int hdpu_cpustate_remove(struct platform_device *pdev);
 
-struct cpustate_t cpustate;
+static unsigned char cpustate_get_state(void);
+static int cpustate_proc_open(struct inode *inode, struct file *file);
+static int cpustate_proc_read(struct seq_file *seq, void *offset);
+
+static struct cpustate_t cpustate;
+
+static const struct file_operations proc_cpustate = {
+	.open = cpustate_proc_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+static int cpustate_proc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, cpustate_proc_read, NULL);
+}
+
+static int cpustate_proc_read(struct seq_file *seq, void *offset)
+{
+	seq_printf(seq, "CPU State: %04x\n", cpustate_get_state());
+	return 0;
+}
 
 static int cpustate_get_ref(int excl)
 {
@@ -66,13 +91,13 @@
 	return 0;
 }
 
-unsigned char cpustate_get_state(void)
+static unsigned char cpustate_get_state(void)
 {
 
 	return cpustate.cached_val;
 }
 
-void cpustate_set_state(unsigned char new_state)
+static void cpustate_set_state(unsigned char new_state)
 {
 	unsigned int state = (new_state << 21);
 
@@ -134,29 +159,6 @@
 	return cpustate_free_ref();
 }
 
-/*
- *	Info exported via "/proc/sky_cpustate".
- */
-static int cpustate_read_proc(char *page, char **start, off_t off,
-			      int count, int *eof, void *data)
-{
-	char *p = page;
-	int len = 0;
-
-	p += sprintf(p, "CPU State: %04x\n", cpustate_get_state());
-	len = p - page;
-
-	if (len <= off + count)
-		*eof = 1;
-	*start = page + off;
-	len -= off;
-	if (len > count)
-		len = count;
-	if (len < 0)
-		len = 0;
-	return len;
-}
-
 static struct platform_driver hdpu_cpustate_driver = {
 	.probe = hdpu_cpustate_probe,
 	.remove = hdpu_cpustate_remove,
@@ -169,22 +171,18 @@
  *	The various file operations we support.
  */
 static const struct file_operations cpustate_fops = {
-      owner:THIS_MODULE,
-      open:cpustate_open,
-      release:cpustate_release,
-      read:cpustate_read,
-      write:cpustate_write,
-      fasync:NULL,
-      poll:NULL,
-      ioctl:NULL,
-      llseek:no_llseek,
-
+      .owner	= THIS_MODULE,
+      .open	= cpustate_open,
+      .release	= cpustate_release,
+      .read	= cpustate_read,
+      .write	= cpustate_write,
+      .llseek	= no_llseek,
 };
 
 static struct miscdevice cpustate_dev = {
-	MISC_DYNAMIC_MINOR,
-	"sky_cpustate",
-	&cpustate_fops
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "sky_cpustate",
+	.fops	= &cpustate_fops,
 };
 
 static int hdpu_cpustate_probe(struct platform_device *pdev)
@@ -194,23 +192,31 @@
 	int ret;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		printk(KERN_ERR "sky_cpustate: "
+		       "Invalid memory resource.\n");
+		return -EINVAL;
+	}
 	cpustate.set_addr = (unsigned long *)res->start;
 	cpustate.clr_addr = (unsigned long *)res->end - 1;
 
 	ret = misc_register(&cpustate_dev);
 	if (ret) {
-		printk(KERN_WARNING "sky_cpustate: Unable to register misc "
-					"device.\n");
+		printk(KERN_WARNING "sky_cpustate: "
+		       "Unable to register misc device.\n");
 		cpustate.set_addr = NULL;
 		cpustate.clr_addr = NULL;
 		return ret;
 	}
 
-	proc_de = create_proc_read_entry("sky_cpustate", 0, 0,
-					cpustate_read_proc, NULL);
-	if (proc_de == NULL)
-		printk(KERN_WARNING "sky_cpustate: Unable to create proc "
-					"dir entry\n");
+	proc_de = create_proc_entry("sky_cpustate", 0666, &proc_root);
+	if (!proc_de) {
+		printk(KERN_WARNING "sky_cpustate: "
+		       "Unable to create proc entry\n");
+	} else {
+		proc_de->proc_fops = &proc_cpustate;
+		proc_de->owner = THIS_MODULE;
+	}
 
 	printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n");
 	return 0;
@@ -218,21 +224,18 @@
 
 static int hdpu_cpustate_remove(struct platform_device *pdev)
 {
-
 	cpustate.set_addr = NULL;
 	cpustate.clr_addr = NULL;
 
 	remove_proc_entry("sky_cpustate", NULL);
 	misc_deregister(&cpustate_dev);
-	return 0;
 
+	return 0;
 }
 
 static int __init cpustate_init(void)
 {
-	int rc;
-	rc = platform_driver_register(&hdpu_cpustate_driver);
-	return rc;
+	return platform_driver_register(&hdpu_cpustate_driver);
 }
 
 static void __exit cpustate_exit(void)
diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c
index 60c8b26..2887b21 100644
--- a/drivers/misc/hdpuftrs/hdpu_nexus.c
+++ b/drivers/misc/hdpuftrs/hdpu_nexus.c
@@ -18,17 +18,38 @@
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
 #include <linux/hdpu_features.h>
-
 #include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <asm/io.h>
 
 static int hdpu_nexus_probe(struct platform_device *pdev);
 static int hdpu_nexus_remove(struct platform_device *pdev);
+static int hdpu_slot_id_open(struct inode *inode, struct file *file);
+static int hdpu_slot_id_read(struct seq_file *seq, void *offset);
+static int hdpu_chassis_id_open(struct inode *inode, struct file *file);
+static int hdpu_chassis_id_read(struct seq_file *seq, void *offset);
 
 static struct proc_dir_entry *hdpu_slot_id;
 static struct proc_dir_entry *hdpu_chassis_id;
 static int slot_id = -1;
 static int chassis_id = -1;
 
+static const struct file_operations proc_slot_id = {
+	.open = hdpu_slot_id_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
+static const struct file_operations proc_chassis_id = {
+	.open = hdpu_chassis_id_open,
+	.read = seq_read,
+	.llseek	= seq_lseek,
+	.release = single_release,
+	.owner = THIS_MODULE,
+};
+
 static struct platform_driver hdpu_nexus_driver = {
 	.probe = hdpu_nexus_probe,
 	.remove = hdpu_nexus_remove,
@@ -37,43 +58,67 @@
 	},
 };
 
-int hdpu_slot_id_read(char *buffer, char **buffer_location, off_t offset,
-		      int buffer_length, int *zero, void *ptr)
+static int hdpu_slot_id_open(struct inode *inode, struct file *file)
 {
-
-	if (offset > 0)
-		return 0;
-	return sprintf(buffer, "%d\n", slot_id);
+	return single_open(file, hdpu_slot_id_read, NULL);
 }
 
-int hdpu_chassis_id_read(char *buffer, char **buffer_location, off_t offset,
-			 int buffer_length, int *zero, void *ptr)
+static int hdpu_slot_id_read(struct seq_file *seq, void *offset)
 {
+	seq_printf(seq, "%d\n", slot_id);
+	return 0;
+}
 
-	if (offset > 0)
-		return 0;
-	return sprintf(buffer, "%d\n", chassis_id);
+static int hdpu_chassis_id_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, hdpu_chassis_id_read, NULL);
+}
+
+static int hdpu_chassis_id_read(struct seq_file *seq, void *offset)
+{
+	seq_printf(seq, "%d\n", chassis_id);
+	return 0;
 }
 
 static int hdpu_nexus_probe(struct platform_device *pdev)
 {
 	struct resource *res;
+	int *nexus_id_addr;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	int *nexus_id_addr;
-	nexus_id_addr =
-	    ioremap(res->start, (unsigned long)(res->end - res->start));
+	if (!res) {
+		printk(KERN_ERR "sky_nexus: "
+		       "Invalid memory resource.\n");
+		return -EINVAL;
+	}
+	nexus_id_addr = ioremap(res->start,
+				(unsigned long)(res->end - res->start));
 	if (nexus_id_addr) {
 		slot_id = (*nexus_id_addr >> 8) & 0x1f;
 		chassis_id = *nexus_id_addr & 0xff;
 		iounmap(nexus_id_addr);
-	} else
-		printk("Could not map slot id\n");
+	} else {
+		printk(KERN_ERR "sky_nexus: Could not map slot id\n");
+	}
+
 	hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root);
-	hdpu_slot_id->read_proc = hdpu_slot_id_read;
+	if (!hdpu_slot_id) {
+		printk(KERN_WARNING "sky_nexus: "
+		       "Unable to create proc dir entry: sky_slot_id\n");
+	} else {
+		hdpu_slot_id->proc_fops = &proc_slot_id;
+		hdpu_slot_id->owner = THIS_MODULE;
+	}
 
 	hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root);
-	hdpu_chassis_id->read_proc = hdpu_chassis_id_read;
+	if (!hdpu_chassis_id) {
+		printk(KERN_WARNING "sky_nexus: "
+		       "Unable to create proc dir entry: sky_chassis_id\n");
+	} else {
+		hdpu_chassis_id->proc_fops = &proc_chassis_id;
+		hdpu_chassis_id->owner = THIS_MODULE;
+	}
+
 	return 0;
 }
 
@@ -81,18 +126,19 @@
 {
 	slot_id = -1;
 	chassis_id = -1;
+
 	remove_proc_entry("sky_slot_id", &proc_root);
 	remove_proc_entry("sky_chassis_id", &proc_root);
+
 	hdpu_slot_id = 0;
 	hdpu_chassis_id = 0;
+
 	return 0;
 }
 
 static int __init nexus_init(void)
 {
-	int rc;
-	rc = platform_driver_register(&hdpu_nexus_driver);
-	return rc;
+	return platform_driver_register(&hdpu_nexus_driver);
 }
 
 static void __exit nexus_exit(void)
diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c
index b5df347..6497872 100644
--- a/drivers/misc/ibmasm/command.c
+++ b/drivers/misc/ibmasm/command.c
@@ -41,18 +41,16 @@
 	if (buffer_size > IBMASM_CMD_MAX_BUFFER_SIZE)
 		return NULL;
 
-	cmd = kmalloc(sizeof(struct command), GFP_KERNEL);
+	cmd = kzalloc(sizeof(struct command), GFP_KERNEL);
 	if (cmd == NULL)
 		return NULL;
 
-	memset(cmd, 0, sizeof(*cmd));
 
-	cmd->buffer = kmalloc(buffer_size, GFP_KERNEL);
+	cmd->buffer = kzalloc(buffer_size, GFP_KERNEL);
 	if (cmd->buffer == NULL) {
 		kfree(cmd);
 		return NULL;
 	}
-	memset(cmd->buffer, 0, buffer_size);
 	cmd->buffer_size = buffer_size;
 
 	kobject_init(&cmd->kobj);
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
index eb7b073..22a7e8b 100644
--- a/drivers/misc/ibmasm/ibmasmfs.c
+++ b/drivers/misc/ibmasm/ibmasmfs.c
@@ -563,11 +563,10 @@
 	if (*offset != 0)
 		return 0;
 
-	buff = kmalloc (count + 1, GFP_KERNEL);
+	buff = kzalloc (count + 1, GFP_KERNEL);
 	if (!buff)
 		return -ENOMEM;
 
-	memset(buff, 0x0, count + 1);
 
 	if (copy_from_user(buff, ubuff, count)) {
 		kfree(buff);
diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c
index fb03a85..4f9d4a9 100644
--- a/drivers/misc/ibmasm/module.c
+++ b/drivers/misc/ibmasm/module.c
@@ -77,13 +77,12 @@
 	/* vnc client won't work without bus-mastering */
 	pci_set_master(pdev);
 
-	sp = kmalloc(sizeof(struct service_processor), GFP_KERNEL);
+	sp = kzalloc(sizeof(struct service_processor), GFP_KERNEL);
 	if (sp == NULL) {
 		dev_err(&pdev->dev, "Failed to allocate memory\n");
 		result = -ENOMEM;
 		goto error_kmalloc;
 	}
-	memset(sp, 0, sizeof(struct service_processor));
 
 	spin_lock_init(&sp->lock);
 	INIT_LIST_HEAD(&sp->command_queue);
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
index 932a415..83679c7 100644
--- a/drivers/misc/msi-laptop.c
+++ b/drivers/misc/msi-laptop.c
@@ -283,7 +283,7 @@
 
 /* Initialization */
 
-static int dmi_check_cb(struct dmi_system_id *id)
+static int dmi_check_cb(const struct dmi_system_id *id)
 {
         printk("msi-laptop: Identified laptop model '%s'.\n", id->ident);
         return 0;
@@ -353,7 +353,7 @@
 	if (IS_ERR(msibl_device))
 		return PTR_ERR(msibl_device);
 
-	msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1,
+	msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1;
 
 	ret = platform_driver_register(&msipf_driver);
 	if (ret)
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index 9623eaf..e73a71f0 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -142,43 +142,124 @@
 	int key;
 };
 
-/* Correspondance table between sonypi events and input layer events */
-static struct {
-	int sonypiev;
-	int inputev;
-} sony_laptop_inputkeys[] = {
-	{ SONYPI_EVENT_CAPTURE_PRESSED,	 	KEY_CAMERA },
-	{ SONYPI_EVENT_FNKEY_ONLY, 		KEY_FN },
-	{ SONYPI_EVENT_FNKEY_ESC, 		KEY_FN_ESC },
-	{ SONYPI_EVENT_FNKEY_F1, 		KEY_FN_F1 },
-	{ SONYPI_EVENT_FNKEY_F2, 		KEY_FN_F2 },
-	{ SONYPI_EVENT_FNKEY_F3, 		KEY_FN_F3 },
-	{ SONYPI_EVENT_FNKEY_F4, 		KEY_FN_F4 },
-	{ SONYPI_EVENT_FNKEY_F5, 		KEY_FN_F5 },
-	{ SONYPI_EVENT_FNKEY_F6, 		KEY_FN_F6 },
-	{ SONYPI_EVENT_FNKEY_F7, 		KEY_FN_F7 },
-	{ SONYPI_EVENT_FNKEY_F8, 		KEY_FN_F8 },
-	{ SONYPI_EVENT_FNKEY_F9,		KEY_FN_F9 },
-	{ SONYPI_EVENT_FNKEY_F10,		KEY_FN_F10 },
-	{ SONYPI_EVENT_FNKEY_F11, 		KEY_FN_F11 },
-	{ SONYPI_EVENT_FNKEY_F12,		KEY_FN_F12 },
-	{ SONYPI_EVENT_FNKEY_1, 		KEY_FN_1 },
-	{ SONYPI_EVENT_FNKEY_2, 		KEY_FN_2 },
-	{ SONYPI_EVENT_FNKEY_D,			KEY_FN_D },
-	{ SONYPI_EVENT_FNKEY_E,			KEY_FN_E },
-	{ SONYPI_EVENT_FNKEY_F,			KEY_FN_F },
-	{ SONYPI_EVENT_FNKEY_S,			KEY_FN_S },
-	{ SONYPI_EVENT_FNKEY_B,			KEY_FN_B },
-	{ SONYPI_EVENT_BLUETOOTH_PRESSED, 	KEY_BLUE },
-	{ SONYPI_EVENT_BLUETOOTH_ON, 		KEY_BLUE },
-	{ SONYPI_EVENT_PKEY_P1, 		KEY_PROG1 },
-	{ SONYPI_EVENT_PKEY_P2, 		KEY_PROG2 },
-	{ SONYPI_EVENT_PKEY_P3, 		KEY_PROG3 },
-	{ SONYPI_EVENT_BACK_PRESSED, 		KEY_BACK },
-	{ SONYPI_EVENT_HELP_PRESSED, 		KEY_HELP },
-	{ SONYPI_EVENT_ZOOM_PRESSED, 		KEY_ZOOM },
-	{ SONYPI_EVENT_THUMBPHRASE_PRESSED, 	BTN_THUMB },
-	{ 0, 0 },
+/* Correspondance table between sonypi events
+ * and input layer indexes in the keymap
+ */
+static int sony_laptop_input_index[] = {
+	-1,	/* no event */
+	-1,	/* SONYPI_EVENT_JOGDIAL_DOWN */
+	-1,	/* SONYPI_EVENT_JOGDIAL_UP */
+	-1,	/* SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
+	-1,	/* SONYPI_EVENT_JOGDIAL_UP_PRESSED */
+	-1,	/* SONYPI_EVENT_JOGDIAL_PRESSED */
+	-1,	/* SONYPI_EVENT_JOGDIAL_RELEASED */
+	 0,	/* SONYPI_EVENT_CAPTURE_PRESSED */
+	 1,	/* SONYPI_EVENT_CAPTURE_RELEASED */
+	 2,	/* SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
+	 3,	/* SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
+	 4,	/* SONYPI_EVENT_FNKEY_ESC */
+	 5,	/* SONYPI_EVENT_FNKEY_F1 */
+	 6,	/* SONYPI_EVENT_FNKEY_F2 */
+	 7,	/* SONYPI_EVENT_FNKEY_F3 */
+	 8,	/* SONYPI_EVENT_FNKEY_F4 */
+	 9,	/* SONYPI_EVENT_FNKEY_F5 */
+	10,	/* SONYPI_EVENT_FNKEY_F6 */
+	11,	/* SONYPI_EVENT_FNKEY_F7 */
+	12,	/* SONYPI_EVENT_FNKEY_F8 */
+	13,	/* SONYPI_EVENT_FNKEY_F9 */
+	14,	/* SONYPI_EVENT_FNKEY_F10 */
+	15,	/* SONYPI_EVENT_FNKEY_F11 */
+	16,	/* SONYPI_EVENT_FNKEY_F12 */
+	17,	/* SONYPI_EVENT_FNKEY_1 */
+	18,	/* SONYPI_EVENT_FNKEY_2 */
+	19,	/* SONYPI_EVENT_FNKEY_D */
+	20,	/* SONYPI_EVENT_FNKEY_E */
+	21,	/* SONYPI_EVENT_FNKEY_F */
+	22,	/* SONYPI_EVENT_FNKEY_S */
+	23,	/* SONYPI_EVENT_FNKEY_B */
+	24,	/* SONYPI_EVENT_BLUETOOTH_PRESSED */
+	25,	/* SONYPI_EVENT_PKEY_P1 */
+	26,	/* SONYPI_EVENT_PKEY_P2 */
+	27,	/* SONYPI_EVENT_PKEY_P3 */
+	28,	/* SONYPI_EVENT_BACK_PRESSED */
+	-1,	/* SONYPI_EVENT_LID_CLOSED */
+	-1,	/* SONYPI_EVENT_LID_OPENED */
+	29,	/* SONYPI_EVENT_BLUETOOTH_ON */
+	30,	/* SONYPI_EVENT_BLUETOOTH_OFF */
+	31,	/* SONYPI_EVENT_HELP_PRESSED */
+	32,	/* SONYPI_EVENT_FNKEY_ONLY */
+	33,	/* SONYPI_EVENT_JOGDIAL_FAST_DOWN */
+	34,	/* SONYPI_EVENT_JOGDIAL_FAST_UP */
+	35,	/* SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
+	36,	/* SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
+	37,	/* SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
+	38,	/* SONYPI_EVENT_JOGDIAL_VFAST_UP */
+	39,	/* SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
+	40,	/* SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
+	41,	/* SONYPI_EVENT_ZOOM_PRESSED */
+	42,	/* SONYPI_EVENT_THUMBPHRASE_PRESSED */
+	43,	/* SONYPI_EVENT_MEYE_FACE */
+	44,	/* SONYPI_EVENT_MEYE_OPPOSITE */
+	45,	/* SONYPI_EVENT_MEMORYSTICK_INSERT */
+	46,	/* SONYPI_EVENT_MEMORYSTICK_EJECT */
+	-1,	/* SONYPI_EVENT_ANYBUTTON_RELEASED */
+	-1,	/* SONYPI_EVENT_BATTERY_INSERT */
+	-1,	/* SONYPI_EVENT_BATTERY_REMOVE */
+	-1,	/* SONYPI_EVENT_FNKEY_RELEASED */
+	47,	/* SONYPI_EVENT_WIRELESS_ON */
+	48,	/* SONYPI_EVENT_WIRELESS_OFF */
+};
+
+static int sony_laptop_input_keycode_map[] = {
+	KEY_CAMERA,	/*  0 SONYPI_EVENT_CAPTURE_PRESSED */
+	KEY_RESERVED,	/*  1 SONYPI_EVENT_CAPTURE_RELEASED */
+	KEY_RESERVED,	/*  2 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
+	KEY_RESERVED,	/*  3 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
+	KEY_FN_ESC,	/*  4 SONYPI_EVENT_FNKEY_ESC */
+	KEY_FN_F1,	/*  5 SONYPI_EVENT_FNKEY_F1 */
+	KEY_FN_F2,	/*  6 SONYPI_EVENT_FNKEY_F2 */
+	KEY_FN_F3,	/*  7 SONYPI_EVENT_FNKEY_F3 */
+	KEY_FN_F4,	/*  8 SONYPI_EVENT_FNKEY_F4 */
+	KEY_FN_F5,	/*  9 SONYPI_EVENT_FNKEY_F5 */
+	KEY_FN_F6,	/* 10 SONYPI_EVENT_FNKEY_F6 */
+	KEY_FN_F7,	/* 11 SONYPI_EVENT_FNKEY_F7 */
+	KEY_FN_F8,	/* 12 SONYPI_EVENT_FNKEY_F8 */
+	KEY_FN_F9,	/* 13 SONYPI_EVENT_FNKEY_F9 */
+	KEY_FN_F10,	/* 14 SONYPI_EVENT_FNKEY_F10 */
+	KEY_FN_F11,	/* 15 SONYPI_EVENT_FNKEY_F11 */
+	KEY_FN_F12,	/* 16 SONYPI_EVENT_FNKEY_F12 */
+	KEY_FN_F1,	/* 17 SONYPI_EVENT_FNKEY_1 */
+	KEY_FN_F2,	/* 18 SONYPI_EVENT_FNKEY_2 */
+	KEY_FN_D,	/* 19 SONYPI_EVENT_FNKEY_D */
+	KEY_FN_E,	/* 20 SONYPI_EVENT_FNKEY_E */
+	KEY_FN_F,	/* 21 SONYPI_EVENT_FNKEY_F */
+	KEY_FN_S,	/* 22 SONYPI_EVENT_FNKEY_S */
+	KEY_FN_B,	/* 23 SONYPI_EVENT_FNKEY_B */
+	KEY_BLUETOOTH,	/* 24 SONYPI_EVENT_BLUETOOTH_PRESSED */
+	KEY_PROG1,	/* 25 SONYPI_EVENT_PKEY_P1 */
+	KEY_PROG2,	/* 26 SONYPI_EVENT_PKEY_P2 */
+	KEY_PROG3,	/* 27 SONYPI_EVENT_PKEY_P3 */
+	KEY_BACK,	/* 28 SONYPI_EVENT_BACK_PRESSED */
+	KEY_BLUETOOTH,	/* 29 SONYPI_EVENT_BLUETOOTH_ON */
+	KEY_BLUETOOTH,	/* 30 SONYPI_EVENT_BLUETOOTH_OFF */
+	KEY_HELP,	/* 31 SONYPI_EVENT_HELP_PRESSED */
+	KEY_FN,		/* 32 SONYPI_EVENT_FNKEY_ONLY */
+	KEY_RESERVED,	/* 33 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
+	KEY_RESERVED,	/* 34 SONYPI_EVENT_JOGDIAL_FAST_UP */
+	KEY_RESERVED,	/* 35 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
+	KEY_RESERVED,	/* 36 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
+	KEY_RESERVED,	/* 37 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
+	KEY_RESERVED,	/* 38 SONYPI_EVENT_JOGDIAL_VFAST_UP */
+	KEY_RESERVED,	/* 39 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
+	KEY_RESERVED,	/* 40 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
+	KEY_ZOOM,	/* 41 SONYPI_EVENT_ZOOM_PRESSED */
+	BTN_THUMB,	/* 42 SONYPI_EVENT_THUMBPHRASE_PRESSED */
+	KEY_RESERVED,	/* 43 SONYPI_EVENT_MEYE_FACE */
+	KEY_RESERVED,	/* 44 SONYPI_EVENT_MEYE_OPPOSITE */
+	KEY_RESERVED,	/* 45 SONYPI_EVENT_MEMORYSTICK_INSERT */
+	KEY_RESERVED,	/* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */
+	KEY_WLAN,	/* 47 SONYPI_EVENT_WIRELESS_ON */
+	KEY_WLAN,	/* 48 SONYPI_EVENT_WIRELESS_OFF */
 };
 
 /* release buttons after a short delay if pressed */
@@ -202,7 +283,6 @@
 	struct input_dev *jog_dev = sony_laptop_input.jog_dev;
 	struct input_dev *key_dev = sony_laptop_input.key_dev;
 	struct sony_laptop_keypress kp = { NULL };
-	int i;
 
 	if (event == SONYPI_EVENT_FNKEY_RELEASED) {
 		/* Nothing, not all VAIOs generate this event */
@@ -231,17 +311,22 @@
 		break;
 
 	default:
-		for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
-			if (event == sony_laptop_inputkeys[i].sonypiev) {
+		if (event > ARRAY_SIZE (sony_laptop_input_keycode_map)) {
+			dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
+			break;
+		}
+		if (sony_laptop_input_index[event] != -1) {
+			kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]];
+			if (kp.key != KEY_UNKNOWN)
 				kp.dev = key_dev;
-				kp.key = sony_laptop_inputkeys[i].inputev;
-				break;
-			}
+		}
 		break;
 	}
 
 	if (kp.dev) {
 		input_report_key(kp.dev, kp.key, 1);
+		/* we emit the scancode so we can always remap the key */
+		input_event(kp.dev, EV_MSC, MSC_SCAN, event);
 		input_sync(kp.dev);
 		kfifo_put(sony_laptop_input.fifo,
 			  (unsigned char *)&kp, sizeof(kp));
@@ -296,11 +381,18 @@
 	key_dev->id.vendor = PCI_VENDOR_ID_SONY;
 
 	/* Initialize the Input Drivers: special keys */
-	key_dev->evbit[0] = BIT(EV_KEY);
-	for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
-		if (sony_laptop_inputkeys[i].inputev)
-			set_bit(sony_laptop_inputkeys[i].inputev,
-					key_dev->keybit);
+	set_bit(EV_KEY, key_dev->evbit);
+	set_bit(EV_MSC, key_dev->evbit);
+	set_bit(MSC_SCAN, key_dev->mscbit);
+	key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]);
+	key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map);
+	key_dev->keycode = &sony_laptop_input_keycode_map;
+	for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) {
+		if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) {
+			set_bit(sony_laptop_input_keycode_map[i],
+				key_dev->keybit);
+		}
+	}
 
 	error = input_register_device(key_dev);
 	if (error)
@@ -487,6 +579,14 @@
 SNC_HANDLE_NAMES(lanpower_get, "GLNP");
 SNC_HANDLE_NAMES(lanpower_set, "LNPW");
 
+SNC_HANDLE_NAMES(lidstate_get, "GLID");
+
+SNC_HANDLE_NAMES(indicatorlamp_get, "GILS");
+SNC_HANDLE_NAMES(indicatorlamp_set, "SILS");
+
+SNC_HANDLE_NAMES(gainbass_get, "GMGB");
+SNC_HANDLE_NAMES(gainbass_set, "CMGB");
+
 SNC_HANDLE_NAMES(PID_get, "GPID");
 
 SNC_HANDLE_NAMES(CTR_get, "GCTR");
@@ -507,6 +607,12 @@
 			boolean_validate, 0),
 	SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
 			boolean_validate, 1),
+	SNC_HANDLE(lidstate, snc_lidstate_get, NULL,
+			boolean_validate, 0),
+	SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set,
+			boolean_validate, 0),
+	SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set,
+			boolean_validate, 0),
 	/* unknown methods */
 	SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1),
 	SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
@@ -689,13 +795,125 @@
 };
 
 /*
+ * New SNC-only Vaios event mapping to driver known keys
+ */
+struct sony_nc_event {
+	u8	data;
+	u8	event;
+};
+
+static struct sony_nc_event *sony_nc_events;
+
+/* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence
+ * for Fn keys
+ */
+static int sony_nc_C_enable(const struct dmi_system_id *id)
+{
+	int result = 0;
+
+	printk(KERN_NOTICE DRV_PFX "detected %s\n", id->ident);
+
+	sony_nc_events = id->driver_data;
+
+	if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x4, &result) < 0
+			|| acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x2, &result) < 0
+			|| acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x10, &result) < 0
+			|| acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x0, &result) < 0
+			|| acpi_callsetfunc(sony_nc_acpi_handle, "SN03", 0x2, &result) < 0
+			|| acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x101, &result) < 0) {
+		printk(KERN_WARNING DRV_PFX "failed to initialize SNC, some "
+				"functionalities may be missing\n");
+		return 1;
+	}
+	return 0;
+}
+
+static struct sony_nc_event sony_C_events[] = {
+	{ 0x81, SONYPI_EVENT_FNKEY_F1 },
+	{ 0x01, SONYPI_EVENT_FNKEY_RELEASED },
+	{ 0x85, SONYPI_EVENT_FNKEY_F5 },
+	{ 0x05, SONYPI_EVENT_FNKEY_RELEASED },
+	{ 0x86, SONYPI_EVENT_FNKEY_F6 },
+	{ 0x06, SONYPI_EVENT_FNKEY_RELEASED },
+	{ 0x87, SONYPI_EVENT_FNKEY_F7 },
+	{ 0x07, SONYPI_EVENT_FNKEY_RELEASED },
+	{ 0x8A, SONYPI_EVENT_FNKEY_F10 },
+	{ 0x0A, SONYPI_EVENT_FNKEY_RELEASED },
+	{ 0x8C, SONYPI_EVENT_FNKEY_F12 },
+	{ 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
+	{ 0, 0 },
+};
+
+/* SNC-only model map */
+static const struct dmi_system_id sony_nc_ids[] = {
+		{
+			.ident = "Sony Vaio FE Series",
+			.callback = sony_nc_C_enable,
+			.driver_data = sony_C_events,
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+				DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FE"),
+			},
+		},
+		{
+			.ident = "Sony Vaio FZ Series",
+			.callback = sony_nc_C_enable,
+			.driver_data = sony_C_events,
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+				DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ"),
+			},
+		},
+		{
+			.ident = "Sony Vaio C Series",
+			.callback = sony_nc_C_enable,
+			.driver_data = sony_C_events,
+			.matches = {
+				DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+				DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"),
+			},
+		},
+		{ }
+};
+
+/*
  * ACPI callbacks
  */
 static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
 {
-	dprintk("sony_acpi_notify, event: %d\n", event);
-	sony_laptop_report_input_event(event);
-	acpi_bus_generate_event(sony_nc_acpi_device, 1, event);
+	struct sony_nc_event *evmap;
+	u32 ev = event;
+	int result;
+
+	if (ev == 0x92) {
+		/* read the key pressed from EC.GECR
+		 * A call to SN07 with 0x0202 will do it as well respecting
+		 * the current protocol on different OSes
+		 *
+		 * Note: the path for GECR may be
+		 *   \_SB.PCI0.LPCB.EC (C, FE, AR, N and friends)
+		 *   \_SB.PCI0.PIB.EC0 (VGN-FR notifications are sent directly, no GECR)
+		 *
+		 * TODO: we may want to do the same for the older GHKE -need
+		 *       dmi list- so this snippet may become one more callback.
+		 */
+		if (acpi_callsetfunc(handle, "SN07", 0x0202, &result) < 0)
+			dprintk("sony_acpi_notify, unable to decode event 0x%.2x\n", ev);
+		else
+			ev = result & 0xFF;
+	}
+
+	if (sony_nc_events)
+		for (evmap = sony_nc_events; evmap->event; evmap++) {
+			if (evmap->data == ev) {
+				ev = evmap->event;
+				break;
+			}
+		}
+
+	dprintk("sony_acpi_notify, event: 0x%.2x\n", ev);
+	sony_laptop_report_input_event(ev);
+	acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev);
 }
 
 static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
@@ -732,6 +950,15 @@
 			break;
 		}
 	}
+
+	/* set the last requested brightness level */
+	if (sony_backlight_device &&
+			!sony_backlight_update_status(sony_backlight_device))
+		printk(KERN_WARNING DRV_PFX "unable to restore brightness level");
+
+	/* re-initialize models with specific requirements */
+	dmi_check_system(sony_nc_ids);
+
 	return 0;
 }
 
@@ -750,6 +977,15 @@
 
 	sony_nc_acpi_handle = device->handle;
 
+	/* read device status */
+	result = acpi_bus_get_status(device);
+	/* bail IFF the above call was successful and the device is not present */
+	if (!result && !device->status.present) {
+		dprintk("Device not present\n");
+		result = -ENODEV;
+		goto outwalk;
+	}
+
 	if (debug) {
 		status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle,
 					     1, sony_walk_callback, NULL, NULL);
@@ -760,6 +996,15 @@
 		}
 	}
 
+	/* try to _INI the device if such method exists (ACPI spec 3.0-6.5.1
+	 * should be respected as we already checked for the device presence above */
+	if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, METHOD_NAME__INI, &handle))) {
+		dprintk("Invoking _INI\n");
+		if (ACPI_FAILURE(acpi_evaluate_object(sony_nc_acpi_handle, METHOD_NAME__INI,
+						NULL, NULL)))
+			dprintk("_INI Method failed\n");
+	}
+
 	/* setup input devices and helper fifo */
 	result = sony_laptop_setup_input();
 	if (result) {
@@ -772,7 +1017,7 @@
 					     ACPI_DEVICE_NOTIFY,
 					     sony_acpi_notify, NULL);
 	if (ACPI_FAILURE(status)) {
-		printk(KERN_WARNING DRV_PFX "unable to install notify handler\n");
+		printk(KERN_WARNING DRV_PFX "unable to install notify handler (%u)\n", status);
 		result = -ENODEV;
 		goto outinput;
 	}
@@ -795,6 +1040,9 @@
 
 	}
 
+	/* initialize models with specific requirements */
+	dmi_check_system(sony_nc_ids);
+
 	result = sony_pf_add();
 	if (result)
 		goto outbacklight;
@@ -890,10 +1138,22 @@
 	return 0;
 }
 
+static const struct acpi_device_id sony_device_ids[] = {
+	{SONY_NC_HID, 0},
+	{SONY_PIC_HID, 0},
+	{"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, sony_device_ids);
+
+static const struct acpi_device_id sony_nc_device_ids[] = {
+	{SONY_NC_HID, 0},
+	{"", 0},
+};
+
 static struct acpi_driver sony_nc_driver = {
 	.name = SONY_NC_DRIVER_NAME,
 	.class = SONY_NC_CLASS,
-	.ids = SONY_NC_HID,
+	.ids = sony_nc_device_ids,
 	.owner = THIS_MODULE,
 	.ops = {
 		.add = sony_nc_add,
@@ -908,7 +1168,9 @@
 #define SONYPI_DEVICE_TYPE2	0x00000002
 #define SONYPI_DEVICE_TYPE3	0x00000004
 
-#define SONY_PIC_EV_MASK	0xff
+#define SONYPI_TYPE1_OFFSET	0x04
+#define SONYPI_TYPE2_OFFSET	0x12
+#define SONYPI_TYPE3_OFFSET	0x12
 
 struct sony_pic_ioport {
 	struct acpi_resource_io	io;
@@ -922,6 +1184,7 @@
 
 struct sony_pic_dev {
 	int			model;
+	u16			evport_offset;
 	u8			camera_power;
 	u8			bluetooth_power;
 	u8			wwan_power;
@@ -1999,20 +2262,17 @@
 static irqreturn_t sony_pic_irq(int irq, void *dev_id)
 {
 	int i, j;
-	u32 port_val = 0;
 	u8 ev = 0;
 	u8 data_mask = 0;
 	u8 device_event = 0;
 
 	struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
 
-	acpi_os_read_port(dev->cur_ioport->io.minimum, &port_val,
-			dev->cur_ioport->io.address_length);
-	ev = port_val & SONY_PIC_EV_MASK;
-	data_mask = 0xff & (port_val >> (dev->cur_ioport->io.address_length - 8));
+	ev = inb_p(dev->cur_ioport->io.minimum);
+	data_mask = inb_p(dev->cur_ioport->io.minimum + dev->evport_offset);
 
-	dprintk("event (0x%.8x [%.2x] [%.2x]) at port 0x%.4x\n",
-			port_val, ev, data_mask, dev->cur_ioport->io.minimum);
+	dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
+			ev, data_mask, dev->cur_ioport->io.minimum, dev->evport_offset);
 
 	if (ev == 0x00 || ev == 0xff)
 		return IRQ_HANDLED;
@@ -2041,7 +2301,7 @@
 
 found:
 	sony_laptop_report_input_event(device_event);
-	acpi_bus_generate_event(spic_dev.acpi_dev, 1, device_event);
+	acpi_bus_generate_proc_event(spic_dev.acpi_dev, 1, device_event);
 	sonypi_compat_report_event(device_event);
 
 	return IRQ_HANDLED;
@@ -2057,8 +2317,6 @@
 	struct sony_pic_ioport *io, *tmp_io;
 	struct sony_pic_irq *irq, *tmp_irq;
 
-	sonypi_compat_exit();
-
 	if (sony_pic_disable(device)) {
 		printk(KERN_ERR DRV_PFX "Couldn't disable device.\n");
 		return -ENXIO;
@@ -2068,6 +2326,8 @@
 	release_region(spic_dev.cur_ioport->io.minimum,
 			spic_dev.cur_ioport->io.address_length);
 
+	sonypi_compat_exit();
+
 	sony_laptop_remove_input();
 
 	/* pf attrs */
@@ -2103,6 +2363,20 @@
 	spic_dev.model = sony_pic_detect_device_type();
 	mutex_init(&spic_dev.lock);
 
+	/* model specific characteristics */
+	switch(spic_dev.model) {
+		case SONYPI_DEVICE_TYPE1:
+			spic_dev.evport_offset = SONYPI_TYPE1_OFFSET;
+			break;
+		case SONYPI_DEVICE_TYPE3:
+			spic_dev.evport_offset = SONYPI_TYPE3_OFFSET;
+			break;
+		case SONYPI_DEVICE_TYPE2:
+		default:
+			spic_dev.evport_offset = SONYPI_TYPE2_OFFSET;
+			break;
+	}
+
 	/* read _PRS resources */
 	result = sony_pic_possible_resources(device);
 	if (result) {
@@ -2119,6 +2393,9 @@
 		goto err_free_resources;
 	}
 
+	if (sonypi_compat_init())
+		goto err_remove_input;
+
 	/* request io port */
 	list_for_each_entry(io, &spic_dev.ioports, list) {
 		if (request_region(io->io.minimum, io->io.address_length,
@@ -2133,7 +2410,7 @@
 	if (!spic_dev.cur_ioport) {
 		printk(KERN_ERR DRV_PFX "Failed to request_region.\n");
 		result = -ENODEV;
-		goto err_remove_input;
+		goto err_remove_compat;
 	}
 
 	/* request IRQ */
@@ -2173,9 +2450,6 @@
 	if (result)
 		goto err_remove_pf;
 
-	if (sonypi_compat_init())
-		goto err_remove_pf;
-
 	return 0;
 
 err_remove_pf:
@@ -2191,6 +2465,9 @@
 	release_region(spic_dev.cur_ioport->io.minimum,
 			spic_dev.cur_ioport->io.address_length);
 
+err_remove_compat:
+	sonypi_compat_exit();
+
 err_remove_input:
 	sony_laptop_remove_input();
 
@@ -2222,10 +2499,15 @@
 	return 0;
 }
 
+static const struct acpi_device_id sony_pic_device_ids[] = {
+	{SONY_PIC_HID, 0},
+	{"", 0},
+};
+
 static struct acpi_driver sony_pic_driver = {
 	.name = SONY_PIC_DRIVER_NAME,
 	.class = SONY_PIC_CLASS,
-	.ids = SONY_PIC_HID,
+	.ids = sony_pic_device_ids,
 	.owner = THIS_MODULE,
 	.ops = {
 		.add = sony_pic_add,
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 95c0b96..6c0b2f0 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -21,8 +21,8 @@
  *  02110-1301, USA.
  */
 
-#define IBM_VERSION "0.14"
-#define TPACPI_SYSFS_VERSION 0x000100
+#define IBM_VERSION "0.16"
+#define TPACPI_SYSFS_VERSION 0x010000
 
 /*
  *  Changelog:
@@ -92,6 +92,29 @@
 /* Please remove this in year 2009 */
 MODULE_ALIAS("ibm_acpi");
 
+/*
+ * DMI matching for module autoloading
+ *
+ * See http://thinkwiki.org/wiki/List_of_DMI_IDs
+ * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
+ *
+ * Only models listed in thinkwiki will be supported, so add yours
+ * if it is not there yet.
+ */
+#define IBM_BIOS_MODULE_ALIAS(__type) \
+	MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW")
+
+/* Non-ancient thinkpads */
+MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*");
+MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*");
+
+/* Ancient thinkpad BIOSes have to be identified by
+ * BIOS type or model number, and there are far less
+ * BIOS types than model numbers... */
+IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]");
+IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]");
+IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");
+
 #define __unused __attribute__ ((unused))
 
 /****************************************************************************
@@ -106,7 +129,7 @@
  * ACPI basic handles
  */
 
-static acpi_handle root_handle = NULL;
+static acpi_handle root_handle;
 
 #define IBM_HANDLE(object, parent, paths...)			\
 	static acpi_handle  object##_handle;			\
@@ -388,12 +411,13 @@
 
 	sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name);
 	ibm->acpi->driver->ids = ibm->acpi->hid;
+
 	ibm->acpi->driver->ops.add = &tpacpi_device_add;
 
 	rc = acpi_bus_register_driver(ibm->acpi->driver);
 	if (rc < 0) {
 		printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
-		       ibm->acpi->hid, rc);
+		       ibm->name, rc);
 		kfree(ibm->acpi->driver);
 		ibm->acpi->driver = NULL;
 	} else if (!rc)
@@ -487,19 +511,36 @@
 /****************************************************************************
  ****************************************************************************
  *
- * Device model: hwmon and platform
+ * Device model: input, hwmon and platform
  *
  ****************************************************************************
  ****************************************************************************/
 
-static struct platform_device *tpacpi_pdev = NULL;
-static struct class_device *tpacpi_hwmon = NULL;
+static struct platform_device *tpacpi_pdev;
+static struct class_device *tpacpi_hwmon;
+static struct input_dev *tpacpi_inputdev;
+
+
+static int tpacpi_resume_handler(struct platform_device *pdev)
+{
+	struct ibm_struct *ibm, *itmp;
+
+	list_for_each_entry_safe(ibm, itmp,
+				 &tpacpi_all_drivers,
+				 all_drivers) {
+		if (ibm->resume)
+			(ibm->resume)();
+	}
+
+	return 0;
+}
 
 static struct platform_driver tpacpi_pdriver = {
 	.driver = {
 		.name = IBM_DRVR_NAME,
 		.owner = THIS_MODULE,
 	},
+	.resume = tpacpi_resume_handler,
 };
 
 
@@ -677,9 +718,19 @@
 	printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
 	printk(IBM_INFO "%s\n", IBM_URL);
 
-	if (ibm_thinkpad_ec_found)
-		printk(IBM_INFO "ThinkPad EC firmware %s\n",
-		       ibm_thinkpad_ec_found);
+	printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n",
+		(thinkpad_id.bios_version_str) ?
+			thinkpad_id.bios_version_str : "unknown",
+		(thinkpad_id.ec_version_str) ?
+			thinkpad_id.ec_version_str : "unknown");
+
+	if (thinkpad_id.vendor && thinkpad_id.model_str)
+		printk(IBM_INFO "%s %s\n",
+			(thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
+				"IBM" : ((thinkpad_id.vendor ==
+						PCI_VENDOR_ID_LENOVO) ?
+					"Lenovo" : "Unknown vendor"),
+			thinkpad_id.model_str);
 
 	return 0;
 }
@@ -704,16 +755,28 @@
  */
 
 static int hotkey_orig_status;
-static int hotkey_orig_mask;
+static u32 hotkey_orig_mask;
+static u32 hotkey_all_mask;
+static u32 hotkey_reserved_mask;
 
-static struct attribute_set *hotkey_dev_attributes = NULL;
+static u16 *hotkey_keycode_map;
+
+static struct attribute_set *hotkey_dev_attributes;
+
+static int hotkey_get_wlsw(int *status)
+{
+	if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
+		return -EIO;
+	return 0;
+}
 
 /* sysfs hotkey enable ------------------------------------------------- */
 static ssize_t hotkey_enable_show(struct device *dev,
 			   struct device_attribute *attr,
 			   char *buf)
 {
-	int res, status, mask;
+	int res, status;
+	u32 mask;
 
 	res = hotkey_get(&status, &mask);
 	if (res)
@@ -727,7 +790,8 @@
 			    const char *buf, size_t count)
 {
 	unsigned long t;
-	int res, status, mask;
+	int res, status;
+	u32 mask;
 
 	if (parse_strtoul(buf, 1, &t))
 		return -EINVAL;
@@ -748,13 +812,14 @@
 			   struct device_attribute *attr,
 			   char *buf)
 {
-	int res, status, mask;
+	int res, status;
+	u32 mask;
 
 	res = hotkey_get(&status, &mask);
 	if (res)
 		return res;
 
-	return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask);
+	return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask);
 }
 
 static ssize_t hotkey_mask_store(struct device *dev,
@@ -762,9 +827,10 @@
 			    const char *buf, size_t count)
 {
 	unsigned long t;
-	int res, status, mask;
+	int res, status;
+	u32 mask;
 
-	if (parse_strtoul(buf, 0xffff, &t))
+	if (parse_strtoul(buf, 0xffffffffUL, &t))
 		return -EINVAL;
 
 	res = hotkey_get(&status, &mask);
@@ -794,26 +860,140 @@
 			   struct device_attribute *attr,
 			   char *buf)
 {
-	return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask);
+	return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask);
 }
 
 static struct device_attribute dev_attr_hotkey_bios_mask =
 	__ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL);
 
+/* sysfs hotkey all_mask ----------------------------------------------- */
+static ssize_t hotkey_all_mask_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask);
+}
+
+static struct device_attribute dev_attr_hotkey_all_mask =
+	__ATTR(hotkey_all_mask, S_IRUGO, hotkey_all_mask_show, NULL);
+
+/* sysfs hotkey recommended_mask --------------------------------------- */
+static ssize_t hotkey_recommended_mask_show(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0x%08x\n",
+			hotkey_all_mask & ~hotkey_reserved_mask);
+}
+
+static struct device_attribute dev_attr_hotkey_recommended_mask =
+	__ATTR(hotkey_recommended_mask, S_IRUGO,
+		hotkey_recommended_mask_show, NULL);
+
+/* sysfs hotkey radio_sw ----------------------------------------------- */
+static ssize_t hotkey_radio_sw_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	int res, s;
+	res = hotkey_get_wlsw(&s);
+	if (res < 0)
+		return res;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", !!s);
+}
+
+static struct device_attribute dev_attr_hotkey_radio_sw =
+	__ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL);
+
+/* sysfs hotkey report_mode -------------------------------------------- */
+static ssize_t hotkey_report_mode_show(struct device *dev,
+			   struct device_attribute *attr,
+			   char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+		(hotkey_report_mode != 0) ? hotkey_report_mode : 1);
+}
+
+static struct device_attribute dev_attr_hotkey_report_mode =
+	__ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL);
+
 /* --------------------------------------------------------------------- */
 
-static struct attribute *hotkey_mask_attributes[] = {
+static struct attribute *hotkey_attributes[] __initdata = {
+	&dev_attr_hotkey_enable.attr,
+	&dev_attr_hotkey_report_mode.attr,
+};
+
+static struct attribute *hotkey_mask_attributes[] __initdata = {
 	&dev_attr_hotkey_mask.attr,
 	&dev_attr_hotkey_bios_enabled.attr,
 	&dev_attr_hotkey_bios_mask.attr,
+	&dev_attr_hotkey_all_mask.attr,
+	&dev_attr_hotkey_recommended_mask.attr,
 };
 
 static int __init hotkey_init(struct ibm_init_struct *iibm)
 {
-	int res;
+
+	static u16 ibm_keycode_map[] __initdata = {
+		/* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
+		KEY_FN_F1,	KEY_FN_F2,	KEY_COFFEE,	KEY_SLEEP,
+		KEY_WLAN,	KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
+		KEY_FN_F9,	KEY_FN_F10,	KEY_FN_F11,	KEY_SUSPEND,
+		/* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
+		KEY_UNKNOWN,	/* 0x0C: FN+BACKSPACE */
+		KEY_UNKNOWN,	/* 0x0D: FN+INSERT */
+		KEY_UNKNOWN,	/* 0x0E: FN+DELETE */
+		KEY_RESERVED,	/* 0x0F: FN+HOME (brightness up) */
+		/* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
+		KEY_RESERVED,	/* 0x10: FN+END (brightness down) */
+		KEY_RESERVED,	/* 0x11: FN+PGUP (thinklight toggle) */
+		KEY_UNKNOWN,	/* 0x12: FN+PGDOWN */
+		KEY_ZOOM,	/* 0x13: FN+SPACE (zoom) */
+		KEY_RESERVED,	/* 0x14: VOLUME UP */
+		KEY_RESERVED,	/* 0x15: VOLUME DOWN */
+		KEY_RESERVED,	/* 0x16: MUTE */
+		KEY_VENDOR,	/* 0x17: Thinkpad/AccessIBM/Lenovo */
+		/* (assignments unknown, please report if found) */
+		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+	};
+	static u16 lenovo_keycode_map[] __initdata = {
+		/* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
+		KEY_FN_F1,	KEY_COFFEE,	KEY_BATTERY,	KEY_SLEEP,
+		KEY_WLAN,	KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
+		KEY_FN_F9,	KEY_FN_F10,	KEY_FN_F11,	KEY_SUSPEND,
+		/* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
+		KEY_UNKNOWN,	/* 0x0C: FN+BACKSPACE */
+		KEY_UNKNOWN,	/* 0x0D: FN+INSERT */
+		KEY_UNKNOWN,	/* 0x0E: FN+DELETE */
+		KEY_BRIGHTNESSUP,	/* 0x0F: FN+HOME (brightness up) */
+		/* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
+		KEY_BRIGHTNESSDOWN,	/* 0x10: FN+END (brightness down) */
+		KEY_RESERVED,	/* 0x11: FN+PGUP (thinklight toggle) */
+		KEY_UNKNOWN,	/* 0x12: FN+PGDOWN */
+		KEY_ZOOM,	/* 0x13: FN+SPACE (zoom) */
+		KEY_RESERVED,	/* 0x14: VOLUME UP */
+		KEY_RESERVED,	/* 0x15: VOLUME DOWN */
+		KEY_RESERVED,	/* 0x16: MUTE */
+		KEY_VENDOR,	/* 0x17: Thinkpad/AccessIBM/Lenovo */
+		/* (assignments unknown, please report if found) */
+		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
+	};
+
+#define TPACPI_HOTKEY_MAP_LEN		ARRAY_SIZE(ibm_keycode_map)
+#define TPACPI_HOTKEY_MAP_SIZE		sizeof(ibm_keycode_map)
+#define TPACPI_HOTKEY_MAP_TYPESIZE	sizeof(ibm_keycode_map[0])
+
+	int res, i;
+	int status;
 
 	vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
 
+	BUG_ON(!tpacpi_inputdev);
+
 	IBM_ACPIHANDLE_INIT(hkey);
 	mutex_init(&hotkey_mutex);
 
@@ -824,11 +1004,12 @@
 		str_supported(tp_features.hotkey));
 
 	if (tp_features.hotkey) {
-		hotkey_dev_attributes = create_attr_set(4, NULL);
+		hotkey_dev_attributes = create_attr_set(8, NULL);
 		if (!hotkey_dev_attributes)
 			return -ENOMEM;
-		res = add_to_attr_set(hotkey_dev_attributes,
-				&dev_attr_hotkey_enable.attr);
+		res = add_many_to_attr_set(hotkey_dev_attributes,
+				hotkey_attributes,
+				ARRAY_SIZE(hotkey_attributes));
 		if (res)
 			return res;
 
@@ -840,19 +1021,90 @@
 		vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
 			str_supported(tp_features.hotkey_mask));
 
+		if (tp_features.hotkey_mask) {
+			/* MHKA available in A31, R40, R40e, T4x, X31, and later */
+			if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
+					"MHKA", "qd"))
+				hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */
+		}
+
 		res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
 		if (!res && tp_features.hotkey_mask) {
 			res = add_many_to_attr_set(hotkey_dev_attributes,
 				hotkey_mask_attributes,
 				ARRAY_SIZE(hotkey_mask_attributes));
 		}
+
+		/* Not all thinkpads have a hardware radio switch */
+		if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
+			tp_features.hotkey_wlsw = 1;
+			printk(IBM_INFO
+				"radio switch found; radios are %s\n",
+				enabled(status, 0));
+			res = add_to_attr_set(hotkey_dev_attributes,
+					&dev_attr_hotkey_radio_sw.attr);
+		}
+
 		if (!res)
 			res = register_attr_set_with_sysfs(
 					hotkey_dev_attributes,
 					&tpacpi_pdev->dev.kobj);
-
 		if (res)
 			return res;
+
+		/* Set up key map */
+
+		hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
+						GFP_KERNEL);
+		if (!hotkey_keycode_map) {
+			printk(IBM_ERR "failed to allocate memory for key map\n");
+			return -ENOMEM;
+		}
+
+		if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
+			dbg_printk(TPACPI_DBG_INIT,
+				   "using Lenovo default hot key map\n");
+			memcpy(hotkey_keycode_map, &lenovo_keycode_map,
+				TPACPI_HOTKEY_MAP_SIZE);
+		} else {
+			dbg_printk(TPACPI_DBG_INIT,
+				   "using IBM default hot key map\n");
+			memcpy(hotkey_keycode_map, &ibm_keycode_map,
+				TPACPI_HOTKEY_MAP_SIZE);
+		}
+
+		set_bit(EV_KEY, tpacpi_inputdev->evbit);
+		set_bit(EV_MSC, tpacpi_inputdev->evbit);
+		set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
+		tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;
+		tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN;
+		tpacpi_inputdev->keycode = hotkey_keycode_map;
+		for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) {
+			if (hotkey_keycode_map[i] != KEY_RESERVED) {
+				set_bit(hotkey_keycode_map[i],
+					tpacpi_inputdev->keybit);
+			} else {
+				if (i < sizeof(hotkey_reserved_mask)*8)
+					hotkey_reserved_mask |= 1 << i;
+			}
+		}
+
+		if (tp_features.hotkey_wlsw) {
+			set_bit(EV_SW, tpacpi_inputdev->evbit);
+			set_bit(SW_RADIO, tpacpi_inputdev->swbit);
+		}
+
+		dbg_printk(TPACPI_DBG_INIT,
+				"enabling hot key handling\n");
+		res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask)
+					| hotkey_orig_mask);
+		if (res)
+			return res;
+
+		dbg_printk(TPACPI_DBG_INIT,
+				"legacy hot key reporting over procfs %s\n",
+				(hotkey_report_mode < 2) ?
+					"enabled" : "disabled");
 	}
 
 	return (tp_features.hotkey)? 0 : 1;
@@ -875,22 +1127,108 @@
 	}
 }
 
+static void tpacpi_input_send_key(unsigned int scancode,
+				  unsigned int keycode)
+{
+	if (keycode != KEY_RESERVED) {
+		input_report_key(tpacpi_inputdev, keycode, 1);
+		if (keycode == KEY_UNKNOWN)
+			input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
+				    scancode);
+		input_sync(tpacpi_inputdev);
+
+		input_report_key(tpacpi_inputdev, keycode, 0);
+		if (keycode == KEY_UNKNOWN)
+			input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
+				    scancode);
+		input_sync(tpacpi_inputdev);
+	}
+}
+
+static void tpacpi_input_send_radiosw(void)
+{
+	int wlsw;
+
+	if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw))
+		input_report_switch(tpacpi_inputdev,
+				    SW_RADIO, !!wlsw);
+}
+
 static void hotkey_notify(struct ibm_struct *ibm, u32 event)
 {
-	int hkey;
+	u32 hkey;
+	unsigned int keycode, scancode;
+	int send_acpi_ev = 0;
 
-	if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
-		acpi_bus_generate_event(ibm->acpi->device, event, hkey);
-	else {
-		printk(IBM_ERR "unknown hotkey event %d\n", event);
-		acpi_bus_generate_event(ibm->acpi->device, event, 0);
+	if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
+		switch (hkey >> 12) {
+		case 1:
+			/* 0x1000-0x1FFF: key presses */
+			scancode = hkey & 0xfff;
+			if (scancode > 0 && scancode < 0x21) {
+				scancode--;
+				keycode = hotkey_keycode_map[scancode];
+				tpacpi_input_send_key(scancode, keycode);
+			} else {
+				printk(IBM_ERR
+				       "hotkey 0x%04x out of range for keyboard map\n",
+				       hkey);
+				send_acpi_ev = 1;
+			}
+			break;
+		case 5:
+			/* 0x5000-0x5FFF: LID */
+			/* we don't handle it through this path, just
+			 * eat up known LID events */
+			if (hkey != 0x5001 && hkey != 0x5002) {
+				printk(IBM_ERR
+					"unknown LID-related hotkey event: 0x%04x\n",
+					hkey);
+				send_acpi_ev = 1;
+			}
+			break;
+		case 7:
+			/* 0x7000-0x7FFF: misc */
+			if (tp_features.hotkey_wlsw && hkey == 0x7000) {
+				tpacpi_input_send_radiosw();
+				break;
+			}
+			/* fallthrough to default */
+		default:
+			/* case 2: dock-related */
+			/*	0x2305 - T43 waking up due to bay lever eject while aslept */
+			/* case 3: ultra-bay related. maybe bay in dock? */
+			/*	0x3003 - T43 after wake up by bay lever eject (0x2305) */
+			printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey);
+			send_acpi_ev = 1;
+		}
+	} else {
+		printk(IBM_ERR "unknown hotkey notification event %d\n", event);
+		hkey = 0;
+		send_acpi_ev = 1;
 	}
+
+	/* Legacy events */
+	if (send_acpi_ev || hotkey_report_mode < 2)
+		acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey);
+
+	/* netlink events */
+	if (send_acpi_ev) {
+		acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
+						ibm->acpi->device->dev.bus_id,
+						event, hkey);
+	}
+}
+
+static void hotkey_resume(void)
+{
+	tpacpi_input_send_radiosw();
 }
 
 /*
  * Call with hotkey_mutex held
  */
-static int hotkey_get(int *status, int *mask)
+static int hotkey_get(int *status, u32 *mask)
 {
 	if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
 		return -EIO;
@@ -905,7 +1243,7 @@
 /*
  * Call with hotkey_mutex held
  */
-static int hotkey_set(int status, int mask)
+static int hotkey_set(int status, u32 mask)
 {
 	int i;
 
@@ -926,7 +1264,8 @@
 /* procfs -------------------------------------------------------------- */
 static int hotkey_read(char *p)
 {
-	int res, status, mask;
+	int res, status;
+	u32 mask;
 	int len = 0;
 
 	if (!tp_features.hotkey) {
@@ -944,7 +1283,7 @@
 
 	len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
 	if (tp_features.hotkey_mask) {
-		len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
+		len += sprintf(p + len, "mask:\t\t0x%08x\n", mask);
 		len += sprintf(p + len,
 			       "commands:\tenable, disable, reset, <mask>\n");
 	} else {
@@ -957,7 +1296,8 @@
 
 static int hotkey_write(char *buf)
 {
-	int res, status, mask;
+	int res, status;
+	u32 mask;
 	char *cmd;
 	int do_cmd = 0;
 
@@ -1000,8 +1340,13 @@
 	return res;
 }
 
+static const struct acpi_device_id ibm_htk_device_ids[] = {
+	{IBM_HKEY_HID, 0},
+	{"", 0},
+};
+
 static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = {
-	.hid = IBM_HKEY_HID,
+	.hid = ibm_htk_device_ids,
 	.notify = hotkey_notify,
 	.handle = &hkey_handle,
 	.type = ACPI_DEVICE_NOTIFY,
@@ -1012,6 +1357,7 @@
 	.read = hotkey_read,
 	.write = hotkey_write,
 	.exit = hotkey_exit,
+	.resume = hotkey_resume,
 	.acpi = &ibm_hotkey_acpidriver,
 };
 
@@ -1763,6 +2109,11 @@
 /* don't list other alternatives as we install a notify handler on the 570 */
 IBM_HANDLE(pci, root, "\\_SB.PCI");	/* 570 */
 
+static const struct acpi_device_id ibm_pci_device_ids[] = {
+	{PCI_ROOT_HID_STRING, 0},
+	{"", 0},
+};
+
 static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
 	{
 	 .notify = dock_notify,
@@ -1770,7 +2121,10 @@
 	 .type = ACPI_SYSTEM_NOTIFY,
 	},
 	{
-	 .hid = IBM_PCI_HID,
+	/* THIS ONE MUST NEVER BE USED FOR DRIVER AUTOLOADING.
+	 * We just use it to get notifications of dock hotplug
+	 * in very old thinkpads */
+	 .hid = ibm_pci_device_ids,
 	 .notify = dock_notify,
 	 .handle = &pci_handle,
 	 .type = ACPI_SYSTEM_NOTIFY,
@@ -1829,23 +2183,29 @@
 static void dock_notify(struct ibm_struct *ibm, u32 event)
 {
 	int docked = dock_docked();
-	int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID);
+	int pci = ibm->acpi->hid && ibm->acpi->device &&
+		acpi_match_device_ids(ibm->acpi->device, ibm_pci_device_ids);
+	int data;
 
 	if (event == 1 && !pci)	/* 570 */
-		acpi_bus_generate_event(ibm->acpi->device, event, 1);	/* button */
+		data = 1;	/* button */
 	else if (event == 1 && pci)	/* 570 */
-		acpi_bus_generate_event(ibm->acpi->device, event, 3);	/* dock */
+		data = 3;	/* dock */
 	else if (event == 3 && docked)
-		acpi_bus_generate_event(ibm->acpi->device, event, 1);	/* button */
+		data = 1;	/* button */
 	else if (event == 3 && !docked)
-		acpi_bus_generate_event(ibm->acpi->device, event, 2);	/* undock */
+		data = 2;	/* undock */
 	else if (event == 0 && docked)
-		acpi_bus_generate_event(ibm->acpi->device, event, 3);	/* dock */
+		data = 3;	/* dock */
 	else {
 		printk(IBM_ERR "unknown dock event %d, status %d\n",
 		       event, _sta(dock_handle));
-		acpi_bus_generate_event(ibm->acpi->device, event, 0);	/* unknown */
+		data = 0;	/* unknown */
 	}
+	acpi_bus_generate_proc_event(ibm->acpi->device, event, data);
+	acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
+					  ibm->acpi->device->dev.bus_id,
+					  event, data);
 }
 
 static int dock_read(char *p)
@@ -1943,7 +2303,10 @@
 
 static void bay_notify(struct ibm_struct *ibm, u32 event)
 {
-	acpi_bus_generate_event(ibm->acpi->device, event, 0);
+	acpi_bus_generate_proc_event(ibm->acpi->device, event, 0);
+	acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
+					  ibm->acpi->device->dev.bus_id,
+					  event, 0);
 }
 
 #define bay_occupied(b) (_sta(b##_handle) & 1)
@@ -2389,7 +2752,7 @@
 
 	acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
 
-	if (ibm_thinkpad_ec_found && experimental) {
+	if (thinkpad_id.ec_model) {
 		/*
 		 * Direct EC access mode: sensors at registers
 		 * 0x78-0x7F, 0xC0-0xC7.  Registers return 0x00 for
@@ -2533,6 +2896,8 @@
 			snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
 			if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
 				return -EIO;
+			if (t > 127 || t < -127)
+				t = TP_EC_THERMAL_TMP_NA;
 			*value = t * 1000;
 			return 0;
 		}
@@ -2671,22 +3036,39 @@
  * Backlight/brightness subdriver
  */
 
-static struct backlight_device *ibm_backlight_device = NULL;
+static struct backlight_device *ibm_backlight_device;
 
 static struct backlight_ops ibm_backlight_data = {
         .get_brightness = brightness_get,
         .update_status  = brightness_update_status,
 };
 
+static struct mutex brightness_mutex;
+
 static int __init brightness_init(struct ibm_init_struct *iibm)
 {
 	int b;
 
 	vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
 
+	mutex_init(&brightness_mutex);
+
+	if (!brightness_mode) {
+		if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
+			brightness_mode = 2;
+		else
+			brightness_mode = 3;
+
+		dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n",
+			brightness_mode);
+	}
+
+	if (brightness_mode > 3)
+		return -EINVAL;
+
 	b = brightness_get(NULL);
 	if (b < 0)
-		return b;
+		return 1;
 
 	ibm_backlight_device = backlight_device_register(
 					TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
@@ -2722,34 +3104,79 @@
 				bd->props.brightness : 0);
 }
 
+/*
+ * ThinkPads can read brightness from two places: EC 0x31, or
+ * CMOS NVRAM byte 0x5E, bits 0-3.
+ */
 static int brightness_get(struct backlight_device *bd)
 {
-	u8 level;
-	if (!acpi_ec_read(brightness_offset, &level))
-		return -EIO;
+	u8 lec = 0, lcmos = 0, level = 0;
 
-	level &= 0x7;
+	if (brightness_mode & 1) {
+		if (!acpi_ec_read(brightness_offset, &lec))
+			return -EIO;
+		lec &= 7;
+		level = lec;
+	};
+	if (brightness_mode & 2) {
+		lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
+			 & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
+			>> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
+		level = lcmos;
+	}
+
+	if (brightness_mode == 3 && lec != lcmos) {
+		printk(IBM_ERR
+			"CMOS NVRAM (%u) and EC (%u) do not agree "
+			"on display brightness level\n",
+			(unsigned int) lcmos,
+			(unsigned int) lec);
+		return -EIO;
+	}
 
 	return level;
 }
 
 static int brightness_set(int value)
 {
-	int cmos_cmd, inc, i;
-	int current_value = brightness_get(NULL);
+	int cmos_cmd, inc, i, res;
+	int current_value;
 
-	value &= 7;
+	if (value > 7)
+		return -EINVAL;
 
-	cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN;
-	inc = value > current_value ? 1 : -1;
-	for (i = current_value; i != value; i += inc) {
-		if (issue_thinkpad_cmos_command(cmos_cmd))
-			return -EIO;
-		if (!acpi_ec_write(brightness_offset, i + inc))
-			return -EIO;
+	res = mutex_lock_interruptible(&brightness_mutex);
+	if (res < 0)
+		return res;
+
+	current_value = brightness_get(NULL);
+	if (current_value < 0) {
+		res = current_value;
+		goto errout;
 	}
 
-	return 0;
+	cmos_cmd = value > current_value ?
+			TP_CMOS_BRIGHTNESS_UP :
+			TP_CMOS_BRIGHTNESS_DOWN;
+	inc = value > current_value ? 1 : -1;
+
+	res = 0;
+	for (i = current_value; i != value; i += inc) {
+		if ((brightness_mode & 2) &&
+		    issue_thinkpad_cmos_command(cmos_cmd)) {
+			res = -EIO;
+			goto errout;
+		}
+		if ((brightness_mode & 1) &&
+		    !acpi_ec_write(brightness_offset, i + inc)) {
+			res = -EIO;
+			goto errout;;
+		}
+	}
+
+errout:
+	mutex_unlock(&brightness_mutex);
+	return res;
 }
 
 static int brightness_read(char *p)
@@ -3273,20 +3700,19 @@
 			 * Enable for TP-1Y (T43), TP-78 (R51e),
 			 * TP-76 (R52), TP-70 (T43, R52), which are known
 			 * to be buggy. */
-			if (fan_control_initial_status == 0x07 &&
-			    ibm_thinkpad_ec_found &&
-			    ((ibm_thinkpad_ec_found[0] == '1' &&
-			      ibm_thinkpad_ec_found[1] == 'Y') ||
-			     (ibm_thinkpad_ec_found[0] == '7' &&
-			      (ibm_thinkpad_ec_found[1] == '6' ||
-			       ibm_thinkpad_ec_found[1] == '8' ||
-			       ibm_thinkpad_ec_found[1] == '0'))
-			    )) {
-				printk(IBM_NOTICE
-				       "fan_init: initial fan status is "
-				       "unknown, assuming it is in auto "
-				       "mode\n");
-				tp_features.fan_ctrl_status_undef = 1;
+			if (fan_control_initial_status == 0x07) {
+				switch (thinkpad_id.ec_model) {
+				case 0x5931: /* TP-1Y */
+				case 0x3837: /* TP-78 */
+				case 0x3637: /* TP-76 */
+				case 0x3037: /* TP-70 */
+					printk(IBM_NOTICE
+					       "fan_init: initial fan status is "
+					       "unknown, assuming it is in auto "
+					       "mode\n");
+					tp_features.fan_ctrl_status_undef = 1;
+					;;
+				}
 			}
 		} else {
 			printk(IBM_ERR
@@ -3474,7 +3900,7 @@
 
 static void fan_watchdog_reset(void)
 {
-	static int fan_watchdog_active = 0;
+	static int fan_watchdog_active;
 
 	if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
 		return;
@@ -3877,7 +4303,7 @@
  ****************************************************************************/
 
 /* /proc support */
-static struct proc_dir_entry *proc_dir = NULL;
+static struct proc_dir_entry *proc_dir;
 
 /* Subdriver registry */
 static LIST_HEAD(tpacpi_all_drivers);
@@ -4020,13 +4446,30 @@
 
 /* Probing */
 
-static char *ibm_thinkpad_ec_found = NULL;
-
-static char* __init check_dmi_for_ec(void)
+static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
 {
-	struct dmi_device *dev = NULL;
+	const struct dmi_device *dev = NULL;
 	char ec_fw_string[18];
 
+	if (!tp)
+		return;
+
+	memset(tp, 0, sizeof(*tp));
+
+	if (dmi_name_in_vendors("IBM"))
+		tp->vendor = PCI_VENDOR_ID_IBM;
+	else if (dmi_name_in_vendors("LENOVO"))
+		tp->vendor = PCI_VENDOR_ID_LENOVO;
+	else
+		return;
+
+	tp->bios_version_str = kstrdup(dmi_get_system_info(DMI_BIOS_VERSION),
+					GFP_KERNEL);
+	if (!tp->bios_version_str)
+		return;
+	tp->bios_model = tp->bios_version_str[0]
+			 | (tp->bios_version_str[1] << 8);
+
 	/*
 	 * ThinkPad T23 or newer, A31 or newer, R50e or newer,
 	 * X32 or newer, all Z series;  Some models must have an
@@ -4040,10 +4483,20 @@
 			   ec_fw_string) == 1) {
 			ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
 			ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
-			return kstrdup(ec_fw_string, GFP_KERNEL);
+
+			tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
+			tp->ec_model = ec_fw_string[0]
+					| (ec_fw_string[1] << 8);
+			break;
 		}
 	}
-	return NULL;
+
+	tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION),
+					GFP_KERNEL);
+	if (strnicmp(tp->model_str, "ThinkPad", 8) != 0) {
+		kfree(tp->model_str);
+		tp->model_str = NULL;
+	}
 }
 
 static int __init probe_for_thinkpad(void)
@@ -4057,7 +4510,7 @@
 	 * Non-ancient models have better DMI tagging, but very old models
 	 * don't.
 	 */
-	is_thinkpad = dmi_name_in_vendors("ThinkPad");
+	is_thinkpad = (thinkpad_id.model_str != NULL);
 
 	/* ec is required because many other handles are relative to it */
 	IBM_ACPIHANDLE_INIT(ec);
@@ -4073,7 +4526,7 @@
 	 * false positives a damn great deal
 	 */
 	if (!is_thinkpad)
-		is_thinkpad = dmi_name_in_vendors("IBM");
+		is_thinkpad = (thinkpad_id.vendor == PCI_VENDOR_ID_IBM);
 
 	if (!is_thinkpad && !force_load)
 		return -ENODEV;
@@ -4185,10 +4638,16 @@
 module_param_named(debug, dbg_level, uint, 0);
 
 static int force_load;
-module_param(force_load, int, 0);
+module_param(force_load, bool, 0);
 
 static int fan_control_allowed;
-module_param_named(fan_control, fan_control_allowed, int, 0);
+module_param_named(fan_control, fan_control_allowed, bool, 0);
+
+static int brightness_mode;
+module_param_named(brightness_mode, brightness_mode, int, 0);
+
+static unsigned int hotkey_report_mode;
+module_param(hotkey_report_mode, uint, 0);
 
 #define IBM_PARAM(feature) \
 	module_param_call(feature, set_ibm_param, NULL, NULL, 0)
@@ -4215,13 +4674,21 @@
 {
 	int ret, i;
 
+	/* Parameter checking */
+	if (hotkey_report_mode > 2)
+		return -EINVAL;
+
 	/* Driver-level probe */
+
+	get_thinkpad_model_data(&thinkpad_id);
 	ret = probe_for_thinkpad();
-	if (ret)
+	if (ret) {
+		thinkpad_acpi_module_exit();
 		return ret;
+	}
 
 	/* Driver initialization */
-	ibm_thinkpad_ec_found = check_dmi_for_ec();
+
 	IBM_ACPIHANDLE_INIT(ecrd);
 	IBM_ACPIHANDLE_INIT(ecwr);
 
@@ -4239,12 +4706,15 @@
 		thinkpad_acpi_module_exit();
 		return ret;
 	}
+	tp_features.platform_drv_registered = 1;
+
 	ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver);
 	if (ret) {
 		printk(IBM_ERR "unable to create sysfs driver attributes\n");
 		thinkpad_acpi_module_exit();
 		return ret;
 	}
+	tp_features.platform_drv_attrs_registered = 1;
 
 
 	/* Device initialization */
@@ -4265,6 +4735,22 @@
 		thinkpad_acpi_module_exit();
 		return ret;
 	}
+	tpacpi_inputdev = input_allocate_device();
+	if (!tpacpi_inputdev) {
+		printk(IBM_ERR "unable to allocate input device\n");
+		thinkpad_acpi_module_exit();
+		return -ENOMEM;
+	} else {
+		/* Prepare input device, but don't register */
+		tpacpi_inputdev->name = "ThinkPad Extra Buttons";
+		tpacpi_inputdev->phys = IBM_DRVR_NAME "/input0";
+		tpacpi_inputdev->id.bustype = BUS_HOST;
+		tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ?
+						thinkpad_id.vendor :
+						PCI_VENDOR_ID_IBM;
+		tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT;
+		tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION;
+	}
 	for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
 		ret = ibm_init(&ibms_init[i]);
 		if (ret >= 0 && *ibms_init[i].param)
@@ -4274,6 +4760,14 @@
 			return ret;
 		}
 	}
+	ret = input_register_device(tpacpi_inputdev);
+	if (ret < 0) {
+		printk(IBM_ERR "unable to register input device\n");
+		thinkpad_acpi_module_exit();
+		return ret;
+	} else {
+		tp_features.input_device_registered = 1;
+	}
 
 	return 0;
 }
@@ -4290,19 +4784,31 @@
 
 	dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
 
+	if (tpacpi_inputdev) {
+		if (tp_features.input_device_registered)
+			input_unregister_device(tpacpi_inputdev);
+		else
+			input_free_device(tpacpi_inputdev);
+	}
+
 	if (tpacpi_hwmon)
 		hwmon_device_unregister(tpacpi_hwmon);
 
 	if (tpacpi_pdev)
 		platform_device_unregister(tpacpi_pdev);
 
-	tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
-	platform_driver_unregister(&tpacpi_pdriver);
+	if (tp_features.platform_drv_attrs_registered)
+		tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
+
+	if (tp_features.platform_drv_registered)
+		platform_driver_unregister(&tpacpi_pdriver);
 
 	if (proc_dir)
 		remove_proc_entry(IBM_PROC_DIR, acpi_root_dir);
 
-	kfree(ibm_thinkpad_ec_found);
+	kfree(thinkpad_id.bios_version_str);
+	kfree(thinkpad_id.ec_version_str);
+	kfree(thinkpad_id.model_str);
 }
 
 module_init(thinkpad_acpi_module_init);
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
index 72d62f2..082a1cb 100644
--- a/drivers/misc/thinkpad_acpi.h
+++ b/drivers/misc/thinkpad_acpi.h
@@ -32,6 +32,7 @@
 #include <linux/list.h>
 #include <linux/mutex.h>
 
+#include <linux/nvram.h>
 #include <linux/proc_fs.h>
 #include <linux/sysfs.h>
 #include <linux/backlight.h>
@@ -39,6 +40,7 @@
 #include <linux/platform_device.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
+#include <linux/input.h>
 #include <asm/uaccess.h>
 
 #include <linux/dmi.h>
@@ -48,6 +50,7 @@
 #include <acpi/acpi_drivers.h>
 #include <acpi/acnamesp.h>
 
+#include <linux/pci_ids.h>
 
 /****************************************************************************
  * Main driver
@@ -78,6 +81,11 @@
 #define TP_CMOS_BRIGHTNESS_UP	4
 #define TP_CMOS_BRIGHTNESS_DOWN	5
 
+/* ThinkPad CMOS NVRAM constants */
+#define TP_NVRAM_ADDR_BRIGHTNESS       0x5e
+#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x07
+#define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0
+
 #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
 #define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
 #define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
@@ -98,9 +106,13 @@
 #define vdbg_printk(a_dbg_level, format, arg...)
 #endif
 
+/* Input IDs */
+#define TPACPI_HKEY_INPUT_VENDOR	PCI_VENDOR_ID_IBM
+#define TPACPI_HKEY_INPUT_PRODUCT	0x5054 /* "TP" */
+#define TPACPI_HKEY_INPUT_VERSION	0x4101
+
 /* ACPI HIDs */
 #define IBM_HKEY_HID    "IBM0068"
-#define IBM_PCI_HID     "PNP0A03"
 
 /* ACPI helpers */
 static int __must_check acpi_evalf(acpi_handle handle,
@@ -161,6 +173,7 @@
 static struct platform_device *tpacpi_pdev;
 static struct class_device *tpacpi_hwmon;
 static struct platform_driver tpacpi_pdriver;
+static struct input_dev *tpacpi_inputdev;
 static int tpacpi_create_driver_attributes(struct device_driver *drv);
 static void tpacpi_remove_driver_attributes(struct device_driver *drv);
 
@@ -168,9 +181,8 @@
 static int experimental;
 static u32 dbg_level;
 static int force_load;
-static char *ibm_thinkpad_ec_found;
+static unsigned int hotkey_report_mode;
 
-static char* check_dmi_for_ec(void);
 static int thinkpad_acpi_module_init(void);
 static void thinkpad_acpi_module_exit(void);
 
@@ -182,7 +194,7 @@
 struct ibm_struct;
 
 struct tp_acpi_drv_struct {
-	char *hid;
+	const struct acpi_device_id *hid;
 	struct acpi_driver *driver;
 
 	void (*notify) (struct ibm_struct *, u32);
@@ -197,6 +209,7 @@
 	int (*read) (char *);
 	int (*write) (char *);
 	void (*exit) (void);
+	void (*resume) (void);
 
 	struct list_head all_drivers;
 
@@ -228,12 +241,31 @@
 	u16 bluetooth:1;
 	u16 hotkey:1;
 	u16 hotkey_mask:1;
+	u16 hotkey_wlsw:1;
 	u16 light:1;
 	u16 light_status:1;
 	u16 wan:1;
 	u16 fan_ctrl_status_undef:1;
+	u16 input_device_registered:1;
+	u16 platform_drv_registered:1;
+	u16 platform_drv_attrs_registered:1;
 } tp_features;
 
+struct thinkpad_id_data {
+	unsigned int vendor;	/* ThinkPad vendor:
+				 * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
+
+	char *bios_version_str;	/* Something like 1ZET51WW (1.03z) */
+	char *ec_version_str;	/* Something like 1ZHT51WW-1.04a */
+
+	u16 bios_model;		/* Big Endian, TP-1Y = 0x5931, 0 = unknown */
+	u16 ec_model;
+
+	char *model_str;
+};
+
+static struct thinkpad_id_data thinkpad_id;
+
 static struct list_head tpacpi_all_drivers;
 
 static struct ibm_init_struct ibms_init[];
@@ -300,6 +332,7 @@
 
 static struct backlight_device *ibm_backlight_device;
 static int brightness_offset = 0x31;
+static int brightness_mode;
 
 static int brightness_init(struct ibm_init_struct *iibm);
 static void brightness_exit(void);
@@ -415,14 +448,14 @@
  */
 
 static int hotkey_orig_status;
-static int hotkey_orig_mask;
+static u32 hotkey_orig_mask;
 
 static struct mutex hotkey_mutex;
 
 static int hotkey_init(struct ibm_init_struct *iibm);
 static void hotkey_exit(void);
-static int hotkey_get(int *status, int *mask);
-static int hotkey_set(int status, int mask);
+static int hotkey_get(int *status, u32 *mask);
+static int hotkey_set(int status, u32 mask);
 static void hotkey_notify(struct ibm_struct *ibm, u32 event);
 static int hotkey_read(char *p);
 static int hotkey_write(char *buf);
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index d195fb0..8f77949 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -57,16 +57,11 @@
 	return 0;
 }
 
-static int tifm_uevent(struct device *dev, char **envp, int num_envp,
-		       char *buffer, int buffer_size)
+static int tifm_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
-	int i = 0;
-	int length = 0;
 
-	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-			   "TIFM_CARD_TYPE=%s",
-			   tifm_media_type_name(sock->type, 1)))
+	if (add_uevent_var(env, "TIFM_CARD_TYPE=%s", tifm_media_type_name(sock->type, 1)))
 		return -ENOMEM;
 
 	return 0;
diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index a49cb97..aa8a4e4 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -32,3 +32,10 @@
 
 	  If unsure, say Y here.
 
+config SDIO_UART
+	tristate "SDIO UART/GPS class support"
+	depends on MMC
+	help
+	  SDIO function driver for SDIO cards that implements the UART
+	  class, as well as the GPS class which appears like a UART.
+
diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile
index cf8c939..fc5a784 100644
--- a/drivers/mmc/card/Makefile
+++ b/drivers/mmc/card/Makefile
@@ -9,3 +9,5 @@
 obj-$(CONFIG_MMC_BLOCK)		+= mmc_block.o
 mmc_block-objs			:= block.o queue.o
 
+obj-$(CONFIG_SDIO_UART)		+= sdio_uart.o
+
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index cbd4b6e..e38d5a3 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -151,17 +151,19 @@
 
 	cmd.opcode = MMC_APP_CMD;
 	cmd.arg = card->rca << 16;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
 
 	err = mmc_wait_for_cmd(card->host, &cmd, 0);
-	if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD))
+	if (err)
+		return (u32)-1;
+	if (!mmc_host_is_spi(card->host) && !(cmd.resp[0] & R1_APP_CMD))
 		return (u32)-1;
 
 	memset(&cmd, 0, sizeof(struct mmc_command));
 
 	cmd.opcode = SD_APP_SEND_NUM_WR_BLKS;
 	cmd.arg = 0;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
 
 	memset(&data, 0, sizeof(struct mmc_data));
 
@@ -192,7 +194,7 @@
 
 	mmc_wait_for_req(card->host, &mrq);
 
-	if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE)
+	if (cmd.error || data.error)
 		return (u32)-1;
 
 	blocks = ntohl(blocks);
@@ -220,17 +222,15 @@
 		brq.cmd.arg = req->sector;
 		if (!mmc_card_blockaddr(card))
 			brq.cmd.arg <<= 9;
-		brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+		brq.cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
 		brq.data.blksz = 1 << md->block_bits;
 		brq.stop.opcode = MMC_STOP_TRANSMISSION;
 		brq.stop.arg = 0;
-		brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+		brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
 		brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
 		if (brq.data.blocks > card->host->max_blk_count)
 			brq.data.blocks = card->host->max_blk_count;
 
-		mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
-
 		/*
 		 * If the host doesn't support multiple block writes, force
 		 * block writes to single block. SD cards are excepted from
@@ -243,8 +243,12 @@
 			brq.data.blocks = 1;
 
 		if (brq.data.blocks > 1) {
-			brq.data.flags |= MMC_DATA_MULTI;
-			brq.mrq.stop = &brq.stop;
+			/* SPI multiblock writes terminate using a special
+			 * token, not a STOP_TRANSMISSION request.
+			 */
+			if (!mmc_host_is_spi(card->host)
+					|| rq_data_dir(req) == READ)
+				brq.mrq.stop = &brq.stop;
 			readcmd = MMC_READ_MULTIPLE_BLOCK;
 			writecmd = MMC_WRITE_MULTIPLE_BLOCK;
 		} else {
@@ -261,6 +265,8 @@
 			brq.data.flags |= MMC_DATA_WRITE;
 		}
 
+		mmc_set_data_timeout(&brq.data, card);
+
 		brq.data.sg = mq->sg;
 		brq.data.sg_len = mmc_queue_map_sg(mq);
 
@@ -302,7 +308,7 @@
 			goto cmd_err;
 		}
 
-		if (rq_data_dir(req) != READ) {
+		if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
 			do {
 				int err;
 
@@ -414,13 +420,12 @@
 		return ERR_PTR(-ENOSPC);
 	__set_bit(devidx, dev_use);
 
-	md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
+	md = kzalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
 	if (!md) {
 		ret = -ENOMEM;
 		goto out;
 	}
 
-	memset(md, 0, sizeof(struct mmc_blk_data));
 
 	/*
 	 * Set the read-only status based on the supported commands
@@ -511,7 +516,7 @@
 	mmc_claim_host(card->host);
 	cmd.opcode = MMC_SET_BLOCKLEN;
 	cmd.arg = 1 << md->block_bits;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
 	err = mmc_wait_for_cmd(card->host, &cmd, 5);
 	mmc_release_host(card->host);
 
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index b53dac8..b0abc7d 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mmc/queue.c
+ *  linux/drivers/mmc/card/queue.c
  *
  *  Copyright (C) 2003 Russell King, All Rights Reserved.
  *  Copyright 2006-2007 Pierre Ossman
@@ -83,7 +83,7 @@
  * on any queue on this host, and attempt to issue it.  This may
  * not be the queue we were asked to process.
  */
-static void mmc_request(request_queue_t *q)
+static void mmc_request(struct request_queue *q)
 {
 	struct mmc_queue *mq = q->queuedata;
 	struct request *req;
@@ -117,7 +117,6 @@
 	struct mmc_host *host = card->host;
 	u64 limit = BLK_BOUNCE_HIGH;
 	int ret;
-	unsigned int bouncesz;
 
 	if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
 		limit = *mmc_dev(host)->dma_mask;
@@ -134,6 +133,8 @@
 
 #ifdef CONFIG_MMC_BLOCK_BOUNCE
 	if (host->max_hw_segs == 1) {
+		unsigned int bouncesz;
+
 		bouncesz = MMC_QUEUE_BOUNCESZ;
 
 		if (bouncesz > host->max_req_size)
@@ -156,14 +157,14 @@
 				GFP_KERNEL);
 			if (!mq->sg) {
 				ret = -ENOMEM;
-				goto free_bounce_buf;
+				goto cleanup_queue;
 			}
 
 			mq->bounce_sg = kmalloc(sizeof(struct scatterlist) *
 				bouncesz / 512, GFP_KERNEL);
 			if (!mq->bounce_sg) {
 				ret = -ENOMEM;
-				goto free_sg;
+				goto cleanup_queue;
 			}
 		}
 	}
@@ -197,21 +198,20 @@
  	if (mq->bounce_sg)
  		kfree(mq->bounce_sg);
  	mq->bounce_sg = NULL;
- free_sg:
-	kfree(mq->sg);
+ cleanup_queue:
+ 	if (mq->sg)
+		kfree(mq->sg);
 	mq->sg = NULL;
- free_bounce_buf:
 	if (mq->bounce_buf)
 		kfree(mq->bounce_buf);
 	mq->bounce_buf = NULL;
- cleanup_queue:
 	blk_cleanup_queue(mq->queue);
 	return ret;
 }
 
 void mmc_cleanup_queue(struct mmc_queue *mq)
 {
-	request_queue_t *q = mq->queue;
+	struct request_queue *q = mq->queue;
 	unsigned long flags;
 
 	/* Mark that we should start throwing out stragglers */
@@ -252,7 +252,7 @@
  */
 void mmc_queue_suspend(struct mmc_queue *mq)
 {
-	request_queue_t *q = mq->queue;
+	struct request_queue *q = mq->queue;
 	unsigned long flags;
 
 	if (!(mq->flags & MMC_QUEUE_SUSPENDED)) {
@@ -272,7 +272,7 @@
  */
 void mmc_queue_resume(struct mmc_queue *mq)
 {
-	request_queue_t *q = mq->queue;
+	struct request_queue *q = mq->queue;
 	unsigned long flags;
 
 	if (mq->flags & MMC_QUEUE_SUSPENDED) {
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c
new file mode 100644
index 0000000..d552de6
--- /dev/null
+++ b/drivers/mmc/card/sdio_uart.c
@@ -0,0 +1,1158 @@
+/*
+ * linux/drivers/mmc/card/sdio_uart.c - SDIO UART/GPS driver
+ *
+ * Based on drivers/serial/8250.c and drivers/serial/serial_core.c
+ * by Russell King.
+ *
+ * Author:	Nicolas Pitre
+ * Created:	June 15, 2007
+ * Copyright:	MontaVista Software, Inc.
+ *
+ * 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.
+ */
+
+/*
+ * Note: Although this driver assumes a 16550A-like UART implementation,
+ * it is not possible to leverage the common 8250/16550 driver, nor the
+ * core UART infrastructure, as they assumes direct access to the hardware
+ * registers, often under a spinlock.  This is not possible in the SDIO
+ * context as SDIO access functions must be able to sleep.
+ *
+ * Because we need to lock the SDIO host to ensure an exclusive access to
+ * the card, we simply rely on that lock to also prevent and serialize
+ * concurrent access to the same port.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/serial_reg.h>
+#include <linux/circ_buf.h>
+#include <linux/gfp.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+
+
+#define UART_NR		8	/* Number of UARTs this driver can handle */
+
+
+#define UART_XMIT_SIZE	PAGE_SIZE
+#define WAKEUP_CHARS	256
+
+#define circ_empty(circ)	((circ)->head == (circ)->tail)
+#define circ_clear(circ)	((circ)->head = (circ)->tail = 0)
+
+#define circ_chars_pending(circ) \
+		(CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE))
+
+#define circ_chars_free(circ) \
+		(CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE))
+
+
+struct uart_icount {
+	__u32	cts;
+	__u32	dsr;
+	__u32	rng;
+	__u32	dcd;
+	__u32	rx;
+	__u32	tx;
+	__u32	frame;
+	__u32	overrun;
+	__u32	parity;
+	__u32	brk;
+};
+
+struct sdio_uart_port {
+	struct kref		kref;
+	struct tty_struct	*tty;
+	unsigned int		index;
+	unsigned int		opened;
+	struct mutex		open_lock;
+	struct sdio_func	*func;
+	struct mutex		func_lock;
+	struct task_struct	*in_sdio_uart_irq;
+	unsigned int		regs_offset;
+	struct circ_buf		xmit;
+	spinlock_t		write_lock;
+	struct uart_icount	icount;
+	unsigned int		uartclk;
+	unsigned int		mctrl;
+	unsigned int		read_status_mask;
+	unsigned int		ignore_status_mask;
+	unsigned char		x_char;
+	unsigned char           ier;
+	unsigned char           lcr;
+};
+
+static struct sdio_uart_port *sdio_uart_table[UART_NR];
+static DEFINE_SPINLOCK(sdio_uart_table_lock);
+
+static int sdio_uart_add_port(struct sdio_uart_port *port)
+{
+	int index, ret = -EBUSY;
+
+	kref_init(&port->kref);
+	mutex_init(&port->open_lock);
+	mutex_init(&port->func_lock);
+	spin_lock_init(&port->write_lock);
+
+	spin_lock(&sdio_uart_table_lock);
+	for (index = 0; index < UART_NR; index++) {
+		if (!sdio_uart_table[index]) {
+			port->index = index;
+			sdio_uart_table[index] = port;
+			ret = 0;
+			break;
+		}
+	}
+	spin_unlock(&sdio_uart_table_lock);
+
+	return ret;
+}
+
+static struct sdio_uart_port *sdio_uart_port_get(unsigned index)
+{
+	struct sdio_uart_port *port;
+
+	if (index >= UART_NR)
+		return NULL;
+
+	spin_lock(&sdio_uart_table_lock);
+	port = sdio_uart_table[index];
+	if (port)
+		kref_get(&port->kref);
+	spin_unlock(&sdio_uart_table_lock);
+
+	return port;
+}
+
+static void sdio_uart_port_destroy(struct kref *kref)
+{
+	struct sdio_uart_port *port =
+		container_of(kref, struct sdio_uart_port, kref);
+	kfree(port);
+}
+
+static void sdio_uart_port_put(struct sdio_uart_port *port)
+{
+	kref_put(&port->kref, sdio_uart_port_destroy);
+}
+
+static void sdio_uart_port_remove(struct sdio_uart_port *port)
+{
+	struct sdio_func *func;
+
+	BUG_ON(sdio_uart_table[port->index] != port);
+
+	spin_lock(&sdio_uart_table_lock);
+	sdio_uart_table[port->index] = NULL;
+	spin_unlock(&sdio_uart_table_lock);
+
+	/*
+	 * We're killing a port that potentially still is in use by
+	 * the tty layer. Be careful to prevent any further access
+	 * to the SDIO function and arrange for the tty layer to
+	 * give up on that port ASAP.
+	 * Beware: the lock ordering is critical.
+	 */
+	mutex_lock(&port->open_lock);
+	mutex_lock(&port->func_lock);
+	func = port->func;
+	sdio_claim_host(func);
+	port->func = NULL;
+	mutex_unlock(&port->func_lock);
+	if (port->opened)
+		tty_hangup(port->tty);
+	mutex_unlock(&port->open_lock);
+	sdio_release_irq(func);
+	sdio_disable_func(func);
+	sdio_release_host(func);
+
+	sdio_uart_port_put(port);
+}
+
+static int sdio_uart_claim_func(struct sdio_uart_port *port)
+{
+	mutex_lock(&port->func_lock);
+	if (unlikely(!port->func)) {
+		mutex_unlock(&port->func_lock);
+		return -ENODEV;
+	}
+	if (likely(port->in_sdio_uart_irq != current))
+		sdio_claim_host(port->func);
+	mutex_unlock(&port->func_lock);
+	return 0;
+}
+
+static inline void sdio_uart_release_func(struct sdio_uart_port *port)
+{
+	if (likely(port->in_sdio_uart_irq != current))
+		sdio_release_host(port->func);
+}
+
+static inline unsigned int sdio_in(struct sdio_uart_port *port, int offset)
+{
+	unsigned char c;
+	c = sdio_readb(port->func, port->regs_offset + offset, NULL);
+	return c;
+}
+
+static inline void sdio_out(struct sdio_uart_port *port, int offset, int value)
+{
+	sdio_writeb(port->func, value, port->regs_offset + offset, NULL);
+}
+
+static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port)
+{
+	unsigned char status;
+	unsigned int ret;
+
+	status = sdio_in(port, UART_MSR);
+
+	ret = 0;
+	if (status & UART_MSR_DCD)
+		ret |= TIOCM_CAR;
+	if (status & UART_MSR_RI)
+		ret |= TIOCM_RNG;
+	if (status & UART_MSR_DSR)
+		ret |= TIOCM_DSR;
+	if (status & UART_MSR_CTS)
+		ret |= TIOCM_CTS;
+	return ret;
+}
+
+static void sdio_uart_write_mctrl(struct sdio_uart_port *port, unsigned int mctrl)
+{
+	unsigned char mcr = 0;
+
+	if (mctrl & TIOCM_RTS)
+		mcr |= UART_MCR_RTS;
+	if (mctrl & TIOCM_DTR)
+		mcr |= UART_MCR_DTR;
+	if (mctrl & TIOCM_OUT1)
+		mcr |= UART_MCR_OUT1;
+	if (mctrl & TIOCM_OUT2)
+		mcr |= UART_MCR_OUT2;
+	if (mctrl & TIOCM_LOOP)
+		mcr |= UART_MCR_LOOP;
+
+	sdio_out(port, UART_MCR, mcr);
+}
+
+static inline void sdio_uart_update_mctrl(struct sdio_uart_port *port,
+					  unsigned int set, unsigned int clear)
+{
+	unsigned int old;
+
+	old = port->mctrl;
+	port->mctrl = (old & ~clear) | set;
+	if (old != port->mctrl)
+		sdio_uart_write_mctrl(port, port->mctrl);
+}
+
+#define sdio_uart_set_mctrl(port, x)	sdio_uart_update_mctrl(port, x, 0)
+#define sdio_uart_clear_mctrl(port, x)	sdio_uart_update_mctrl(port, 0, x)
+
+static void sdio_uart_change_speed(struct sdio_uart_port *port,
+				   struct ktermios *termios,
+				   struct ktermios *old)
+{
+	unsigned char cval, fcr = 0;
+	unsigned int baud, quot;
+
+	switch (termios->c_cflag & CSIZE) {
+	case CS5:
+		cval = UART_LCR_WLEN5;
+		break;
+	case CS6:
+		cval = UART_LCR_WLEN6;
+		break;
+	case CS7:
+		cval = UART_LCR_WLEN7;
+		break;
+	default:
+	case CS8:
+		cval = UART_LCR_WLEN8;
+		break;
+	}
+
+	if (termios->c_cflag & CSTOPB)
+		cval |= UART_LCR_STOP;
+	if (termios->c_cflag & PARENB)
+		cval |= UART_LCR_PARITY;
+	if (!(termios->c_cflag & PARODD))
+		cval |= UART_LCR_EPAR;
+
+	for (;;) {
+		baud = tty_termios_baud_rate(termios);
+		if (baud == 0)
+			baud = 9600;  /* Special case: B0 rate. */
+		if (baud <= port->uartclk)
+			break;
+		/*
+		 * Oops, the quotient was zero.  Try again with the old
+		 * baud rate if possible, otherwise default to 9600.
+		 */
+		termios->c_cflag &= ~CBAUD;
+		if (old) {
+			termios->c_cflag |= old->c_cflag & CBAUD;
+			old = NULL;
+		} else
+			termios->c_cflag |= B9600;
+	}
+	quot = (2 * port->uartclk + baud) / (2 * baud);
+
+	if (baud < 2400)
+		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+	else
+		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10;
+
+	port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
+	if (termios->c_iflag & INPCK)
+		port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
+	if (termios->c_iflag & (BRKINT | PARMRK))
+		port->read_status_mask |= UART_LSR_BI;
+
+	/*
+	 * Characters to ignore
+	 */
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
+	if (termios->c_iflag & IGNBRK) {
+		port->ignore_status_mask |= UART_LSR_BI;
+		/*
+		 * If we're ignoring parity and break indicators,
+		 * ignore overruns too (for real raw support).
+		 */
+		if (termios->c_iflag & IGNPAR)
+			port->ignore_status_mask |= UART_LSR_OE;
+	}
+
+	/*
+	 * ignore all characters if CREAD is not set
+	 */
+	if ((termios->c_cflag & CREAD) == 0)
+		port->ignore_status_mask |= UART_LSR_DR;
+
+	/*
+	 * CTS flow control flag and modem status interrupts
+	 */
+	port->ier &= ~UART_IER_MSI;
+	if ((termios->c_cflag & CRTSCTS) || !(termios->c_cflag & CLOCAL))
+		port->ier |= UART_IER_MSI;
+
+	port->lcr = cval;
+
+	sdio_out(port, UART_IER, port->ier);
+	sdio_out(port, UART_LCR, cval | UART_LCR_DLAB);
+	sdio_out(port, UART_DLL, quot & 0xff);
+	sdio_out(port, UART_DLM, quot >> 8);
+	sdio_out(port, UART_LCR, cval);
+	sdio_out(port, UART_FCR, fcr);
+
+	sdio_uart_write_mctrl(port, port->mctrl);
+}
+
+static void sdio_uart_start_tx(struct sdio_uart_port *port)
+{
+	if (!(port->ier & UART_IER_THRI)) {
+		port->ier |= UART_IER_THRI;
+		sdio_out(port, UART_IER, port->ier);
+	}
+}
+
+static void sdio_uart_stop_tx(struct sdio_uart_port *port)
+{
+	if (port->ier & UART_IER_THRI) {
+		port->ier &= ~UART_IER_THRI;
+		sdio_out(port, UART_IER, port->ier);
+	}
+}
+
+static void sdio_uart_stop_rx(struct sdio_uart_port *port)
+{
+	port->ier &= ~UART_IER_RLSI;
+	port->read_status_mask &= ~UART_LSR_DR;
+	sdio_out(port, UART_IER, port->ier);
+}
+
+static void sdio_uart_receive_chars(struct sdio_uart_port *port, int *status)
+{
+	struct tty_struct *tty = port->tty;
+	unsigned int ch, flag;
+	int max_count = 256;
+
+	do {
+		ch = sdio_in(port, UART_RX);
+		flag = TTY_NORMAL;
+		port->icount.rx++;
+
+		if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE |
+				        UART_LSR_FE | UART_LSR_OE))) {
+			/*
+			 * For statistics only
+			 */
+			if (*status & UART_LSR_BI) {
+				*status &= ~(UART_LSR_FE | UART_LSR_PE);
+				port->icount.brk++;
+			} else if (*status & UART_LSR_PE)
+				port->icount.parity++;
+			else if (*status & UART_LSR_FE)
+				port->icount.frame++;
+			if (*status & UART_LSR_OE)
+				port->icount.overrun++;
+
+			/*
+			 * Mask off conditions which should be ignored.
+			 */
+			*status &= port->read_status_mask;
+			if (*status & UART_LSR_BI) {
+				flag = TTY_BREAK;
+			} else if (*status & UART_LSR_PE)
+				flag = TTY_PARITY;
+			else if (*status & UART_LSR_FE)
+				flag = TTY_FRAME;
+		}
+
+		if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0)
+			tty_insert_flip_char(tty, ch, flag);
+
+		/*
+		 * Overrun is special.  Since it's reported immediately,
+		 * it doesn't affect the current character.
+		 */
+		if (*status & ~port->ignore_status_mask & UART_LSR_OE)
+			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
+		*status = sdio_in(port, UART_LSR);
+	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
+	tty_flip_buffer_push(tty);
+}
+
+static void sdio_uart_transmit_chars(struct sdio_uart_port *port)
+{
+	struct circ_buf *xmit = &port->xmit;
+	int count;
+
+	if (port->x_char) {
+		sdio_out(port, UART_TX, port->x_char);
+		port->icount.tx++;
+		port->x_char = 0;
+		return;
+	}
+	if (circ_empty(xmit) || port->tty->stopped || port->tty->hw_stopped) {
+		sdio_uart_stop_tx(port);
+		return;
+	}
+
+	count = 16;
+	do {
+		sdio_out(port, UART_TX, xmit->buf[xmit->tail]);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+		if (circ_empty(xmit))
+			break;
+	} while (--count > 0);
+
+	if (circ_chars_pending(xmit) < WAKEUP_CHARS)
+		tty_wakeup(port->tty);
+
+	if (circ_empty(xmit))
+		sdio_uart_stop_tx(port);
+}
+
+static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
+{
+	int status;
+
+	status = sdio_in(port, UART_MSR);
+
+	if ((status & UART_MSR_ANY_DELTA) == 0)
+		return;
+
+	if (status & UART_MSR_TERI)
+		port->icount.rng++;
+	if (status & UART_MSR_DDSR)
+		port->icount.dsr++;
+	if (status & UART_MSR_DDCD)
+		port->icount.dcd++;
+	if (status & UART_MSR_DCTS) {
+		port->icount.cts++;
+		if (port->tty->termios->c_cflag & CRTSCTS) {
+			int cts = (status & UART_MSR_CTS);
+			if (port->tty->hw_stopped) {
+				if (cts) {
+					port->tty->hw_stopped = 0;
+					sdio_uart_start_tx(port);
+					tty_wakeup(port->tty);
+				}
+			} else {
+				if (!cts) {
+					port->tty->hw_stopped = 1;
+					sdio_uart_stop_tx(port);
+				}
+			}
+		}
+	}
+}
+
+/*
+ * This handles the interrupt from one port.
+ */
+static void sdio_uart_irq(struct sdio_func *func)
+{
+	struct sdio_uart_port *port = sdio_get_drvdata(func);
+	unsigned int iir, lsr;
+
+	/*
+	 * In a few places sdio_uart_irq() is called directly instead of
+	 * waiting for the actual interrupt to be raised and the SDIO IRQ
+	 * thread scheduled in order to reduce latency.  However, some
+	 * interaction with the tty core may end up calling us back
+	 * (serial echo, flow control, etc.) through those same places
+	 * causing undesirable effects.  Let's stop the recursion here.
+	 */
+	if (unlikely(port->in_sdio_uart_irq == current))
+		return;
+
+	iir = sdio_in(port, UART_IIR);
+	if (iir & UART_IIR_NO_INT)
+		return;
+
+	port->in_sdio_uart_irq = current;
+	lsr = sdio_in(port, UART_LSR);
+	if (lsr & UART_LSR_DR)
+		sdio_uart_receive_chars(port, &lsr);
+	sdio_uart_check_modem_status(port);
+	if (lsr & UART_LSR_THRE)
+		sdio_uart_transmit_chars(port);
+	port->in_sdio_uart_irq = NULL;
+}
+
+static int sdio_uart_startup(struct sdio_uart_port *port)
+{
+	unsigned long page;
+	int ret;
+
+	/*
+	 * Set the TTY IO error marker - we will only clear this
+	 * once we have successfully opened the port.
+	 */
+	set_bit(TTY_IO_ERROR, &port->tty->flags);
+
+	/* Initialise and allocate the transmit buffer. */
+	page = __get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+	port->xmit.buf = (unsigned char *)page;
+	circ_clear(&port->xmit);
+
+	ret = sdio_uart_claim_func(port);
+	if (ret)
+		goto err1;
+	ret = sdio_enable_func(port->func);
+	if (ret)
+		goto err2;
+	ret = sdio_claim_irq(port->func, sdio_uart_irq);
+	if (ret)
+		goto err3;
+
+	/*
+	 * Clear the FIFO buffers and disable them.
+	 * (they will be reenabled in sdio_change_speed())
+	 */
+	sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO);
+	sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO |
+			UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+	sdio_out(port, UART_FCR, 0);
+
+	/*
+	 * Clear the interrupt registers.
+	 */
+	(void) sdio_in(port, UART_LSR);
+	(void) sdio_in(port, UART_RX);
+	(void) sdio_in(port, UART_IIR);
+	(void) sdio_in(port, UART_MSR);
+
+	/*
+	 * Now, initialize the UART
+	 */
+	sdio_out(port, UART_LCR, UART_LCR_WLEN8);
+
+	port->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
+	port->mctrl = TIOCM_OUT2;
+
+	sdio_uart_change_speed(port, port->tty->termios, NULL);
+
+	if (port->tty->termios->c_cflag & CBAUD)
+		sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
+
+	if (port->tty->termios->c_cflag & CRTSCTS)
+		if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
+			port->tty->hw_stopped = 1;
+
+	clear_bit(TTY_IO_ERROR, &port->tty->flags);
+
+	/* Kick the IRQ handler once while we're still holding the host lock */
+	sdio_uart_irq(port->func);
+
+	sdio_uart_release_func(port);
+	return 0;
+
+err3:
+	sdio_disable_func(port->func);
+err2:
+	sdio_uart_release_func(port);
+err1:
+	free_page((unsigned long)port->xmit.buf);
+	return ret;
+}
+
+static void sdio_uart_shutdown(struct sdio_uart_port *port)
+{
+	int ret;
+
+	ret = sdio_uart_claim_func(port);
+	if (ret)
+		goto skip;
+
+	sdio_uart_stop_rx(port);
+
+	/* TODO: wait here for TX FIFO to drain */
+
+	/* Turn off DTR and RTS early. */
+	if (port->tty->termios->c_cflag & HUPCL)
+		sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
+
+	 /* Disable interrupts from this port */
+	sdio_release_irq(port->func);
+	port->ier = 0;
+	sdio_out(port, UART_IER, 0);
+
+	sdio_uart_clear_mctrl(port, TIOCM_OUT2);
+
+	/* Disable break condition and FIFOs. */
+	port->lcr &= ~UART_LCR_SBC;
+	sdio_out(port, UART_LCR, port->lcr);
+	sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO |
+				 UART_FCR_CLEAR_RCVR |
+				 UART_FCR_CLEAR_XMIT);
+	sdio_out(port, UART_FCR, 0);
+
+	sdio_disable_func(port->func);
+
+	sdio_uart_release_func(port);
+
+skip:
+	/* Free the transmit buffer page. */
+	free_page((unsigned long)port->xmit.buf);
+}
+
+static int sdio_uart_open (struct tty_struct *tty, struct file * filp)
+{
+	struct sdio_uart_port *port;
+	int ret;
+
+	port = sdio_uart_port_get(tty->index);
+	if (!port)
+		return -ENODEV;
+
+	mutex_lock(&port->open_lock);
+
+	/*
+	 * Make sure not to mess up with a dead port
+	 * which has not been closed yet.
+	 */
+	if (tty->driver_data && tty->driver_data != port) {
+		mutex_unlock(&port->open_lock);
+		sdio_uart_port_put(port);
+		return -EBUSY;
+	}
+
+	if (!port->opened) {
+		tty->driver_data = port;
+		port->tty = tty;
+		ret = sdio_uart_startup(port);
+		if (ret) {
+			tty->driver_data = NULL;
+			port->tty = NULL;
+			mutex_unlock(&port->open_lock);
+			sdio_uart_port_put(port);
+			return ret;
+		}
+	}
+	port->opened++;
+	mutex_unlock(&port->open_lock);
+	return 0;
+}
+
+static void sdio_uart_close(struct tty_struct *tty, struct file * filp)
+{
+	struct sdio_uart_port *port = tty->driver_data;
+
+	if (!port)
+		return;
+
+	mutex_lock(&port->open_lock);
+	BUG_ON(!port->opened);
+
+	/*
+	 * This is messy.  The tty layer calls us even when open()
+	 * returned an error.  Ignore this close request if tty->count
+	 * is larger than port->count.
+	 */
+	if (tty->count > port->opened) {
+		mutex_unlock(&port->open_lock);
+		return;
+	}
+
+	if (--port->opened == 0) {
+		tty->closing = 1;
+		sdio_uart_shutdown(port);
+		tty_ldisc_flush(tty);
+		port->tty = NULL;
+		tty->driver_data = NULL;
+		tty->closing = 0;
+	}
+	mutex_unlock(&port->open_lock);
+	sdio_uart_port_put(port);
+}
+
+static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf,
+			   int count)
+{
+	struct sdio_uart_port *port = tty->driver_data;
+	struct circ_buf *circ = &port->xmit;
+	int c, ret = 0;
+
+	if (!port->func)
+		return -ENODEV;
+
+	spin_lock(&port->write_lock);
+	while (1) {
+		c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
+		if (count < c)
+			c = count;
+		if (c <= 0)
+			break;
+		memcpy(circ->buf + circ->head, buf, c);
+		circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
+		buf += c;
+		count -= c;
+		ret += c;
+	}
+	spin_unlock(&port->write_lock);
+
+	if ( !(port->ier & UART_IER_THRI)) {
+		int err = sdio_uart_claim_func(port);
+		if (!err) {
+			sdio_uart_start_tx(port);
+			sdio_uart_irq(port->func);
+			sdio_uart_release_func(port);
+		} else
+			ret = err;
+	}
+
+	return ret;
+}
+
+static int sdio_uart_write_room(struct tty_struct *tty)
+{
+	struct sdio_uart_port *port = tty->driver_data;
+	return port ? circ_chars_free(&port->xmit) : 0;
+}
+
+static int sdio_uart_chars_in_buffer(struct tty_struct *tty)
+{
+	struct sdio_uart_port *port = tty->driver_data;
+	return port ? circ_chars_pending(&port->xmit) : 0;
+}
+
+static void sdio_uart_send_xchar(struct tty_struct *tty, char ch)
+{
+	struct sdio_uart_port *port = tty->driver_data;
+
+	port->x_char = ch;
+	if (ch && !(port->ier & UART_IER_THRI)) {
+		if (sdio_uart_claim_func(port) != 0)
+			return;
+		sdio_uart_start_tx(port);
+		sdio_uart_irq(port->func);
+		sdio_uart_release_func(port);
+	}
+}
+
+static void sdio_uart_throttle(struct tty_struct *tty)
+{
+	struct sdio_uart_port *port = tty->driver_data;
+
+	if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
+		return;
+
+	if (sdio_uart_claim_func(port) != 0)
+		return;
+
+	if (I_IXOFF(tty)) {
+		port->x_char = STOP_CHAR(tty);
+		sdio_uart_start_tx(port);
+	}
+
+	if (tty->termios->c_cflag & CRTSCTS)
+		sdio_uart_clear_mctrl(port, TIOCM_RTS);
+
+	sdio_uart_irq(port->func);
+	sdio_uart_release_func(port);
+}
+
+static void sdio_uart_unthrottle(struct tty_struct *tty)
+{
+	struct sdio_uart_port *port = tty->driver_data;
+
+	if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
+		return;
+
+	if (sdio_uart_claim_func(port) != 0)
+		return;
+
+	if (I_IXOFF(tty)) {
+		if (port->x_char) {
+			port->x_char = 0;
+		} else {
+			port->x_char = START_CHAR(tty);
+			sdio_uart_start_tx(port);
+		}
+	}
+
+	if (tty->termios->c_cflag & CRTSCTS)
+		sdio_uart_set_mctrl(port, TIOCM_RTS);
+
+	sdio_uart_irq(port->func);
+	sdio_uart_release_func(port);
+}
+
+static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
+{
+	struct sdio_uart_port *port = tty->driver_data;
+	unsigned int cflag = tty->termios->c_cflag;
+
+#define RELEVANT_IFLAG(iflag)   ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+	if ((cflag ^ old_termios->c_cflag) == 0 &&
+	    RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
+		return;
+
+	if (sdio_uart_claim_func(port) != 0)
+		return;
+
+	sdio_uart_change_speed(port, tty->termios, old_termios);
+
+	/* Handle transition to B0 status */
+	if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
+		sdio_uart_clear_mctrl(port, TIOCM_RTS | TIOCM_DTR);
+
+	/* Handle transition away from B0 status */
+	if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
+		unsigned int mask = TIOCM_DTR;
+		if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags))
+			mask |= TIOCM_RTS;
+		sdio_uart_set_mctrl(port, mask);
+	}
+
+	/* Handle turning off CRTSCTS */
+	if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		sdio_uart_start_tx(port);
+	}
+
+	/* Handle turning on CRTSCTS */
+	if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
+		if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) {
+			tty->hw_stopped = 1;
+			sdio_uart_stop_tx(port);
+		}
+	}
+
+	sdio_uart_release_func(port);
+}
+
+static void sdio_uart_break_ctl(struct tty_struct *tty, int break_state)
+{
+	struct sdio_uart_port *port = tty->driver_data;
+
+	if (sdio_uart_claim_func(port) != 0)
+		return;
+
+	if (break_state == -1)
+		port->lcr |= UART_LCR_SBC;
+	else
+		port->lcr &= ~UART_LCR_SBC;
+	sdio_out(port, UART_LCR, port->lcr);
+
+	sdio_uart_release_func(port);
+}
+
+static int sdio_uart_tiocmget(struct tty_struct *tty, struct file *file)
+{
+	struct sdio_uart_port *port = tty->driver_data;
+	int result;
+
+	result = sdio_uart_claim_func(port);
+	if (!result) {
+		result = port->mctrl | sdio_uart_get_mctrl(port);
+		sdio_uart_release_func(port);
+	}
+
+	return result;
+}
+
+static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file,
+			      unsigned int set, unsigned int clear)
+{
+	struct sdio_uart_port *port = tty->driver_data;
+	int result;
+
+	result =sdio_uart_claim_func(port);
+	if(!result) {
+		sdio_uart_update_mctrl(port, set, clear);
+		sdio_uart_release_func(port);
+	}
+
+	return result;
+}
+
+static int sdio_uart_read_proc(char *page, char **start, off_t off,
+			       int count, int *eof, void *data)
+{
+	int i, len = 0;
+	off_t begin = 0;
+
+	len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n",
+		       "", "", "");
+	for (i = 0; i < UART_NR && len < PAGE_SIZE - 96; i++) {
+		struct sdio_uart_port *port = sdio_uart_port_get(i);
+		if (port) {
+			len += sprintf(page+len, "%d: uart:SDIO", i);
+			if(capable(CAP_SYS_ADMIN)) {
+				len += sprintf(page + len, " tx:%d rx:%d",
+					       port->icount.tx, port->icount.rx);
+				if (port->icount.frame)
+					len += sprintf(page + len, " fe:%d",
+						       port->icount.frame);
+				if (port->icount.parity)
+					len += sprintf(page + len, " pe:%d",
+						       port->icount.parity);
+				if (port->icount.brk)
+					len += sprintf(page + len, " brk:%d",
+						       port->icount.brk);
+				if (port->icount.overrun)
+					len += sprintf(page + len, " oe:%d",
+						       port->icount.overrun);
+				if (port->icount.cts)
+					len += sprintf(page + len, " cts:%d",
+						       port->icount.cts);
+				if (port->icount.dsr)
+					len += sprintf(page + len, " dsr:%d",
+						       port->icount.dsr);
+				if (port->icount.rng)
+					len += sprintf(page + len, " rng:%d",
+						       port->icount.rng);
+				if (port->icount.dcd)
+					len += sprintf(page + len, " dcd:%d",
+						       port->icount.dcd);
+			}
+			strcat(page, "\n");
+			len++;
+			sdio_uart_port_put(port);
+		}
+
+		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);
+}
+
+static const struct tty_operations sdio_uart_ops = {
+	.open			= sdio_uart_open,
+	.close			= sdio_uart_close,
+	.write			= sdio_uart_write,
+	.write_room		= sdio_uart_write_room,
+	.chars_in_buffer	= sdio_uart_chars_in_buffer,
+	.send_xchar		= sdio_uart_send_xchar,
+	.throttle		= sdio_uart_throttle,
+	.unthrottle		= sdio_uart_unthrottle,
+	.set_termios		= sdio_uart_set_termios,
+	.break_ctl		= sdio_uart_break_ctl,
+	.tiocmget		= sdio_uart_tiocmget,
+	.tiocmset		= sdio_uart_tiocmset,
+	.read_proc		= sdio_uart_read_proc,
+};
+
+static struct tty_driver *sdio_uart_tty_driver;
+
+static int sdio_uart_probe(struct sdio_func *func,
+			   const struct sdio_device_id *id)
+{
+	struct sdio_uart_port *port;
+	int ret;
+
+	port = kzalloc(sizeof(struct sdio_uart_port), GFP_KERNEL);
+	if (!port)
+		return -ENOMEM;
+
+	if (func->class == SDIO_CLASS_UART) {
+		printk(KERN_WARNING "%s: need info on UART class basic setup\n",
+		       sdio_func_id(func));
+		kfree(port);
+		return -ENOSYS;
+	} else if (func->class == SDIO_CLASS_GPS) {
+		/*
+		 * We need tuple 0x91.  It contains SUBTPL_SIOREG
+		 * and SUBTPL_RCVCAPS.
+		 */
+		struct sdio_func_tuple *tpl;
+		for (tpl = func->tuples; tpl; tpl = tpl->next) {
+			if (tpl->code != 0x91)
+				continue;
+			if (tpl->size < 10)
+				continue;
+			if (tpl->data[1] == 0)  /* SUBTPL_SIOREG */
+				break;
+		}
+		if (!tpl) {
+			printk(KERN_WARNING
+			       "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n",
+			       sdio_func_id(func));
+			kfree(port);
+			return -EINVAL;
+		}
+		printk(KERN_DEBUG "%s: Register ID = 0x%02x, Exp ID = 0x%02x\n",
+		       sdio_func_id(func), tpl->data[2], tpl->data[3]);
+		port->regs_offset = (tpl->data[4] << 0) |
+				    (tpl->data[5] << 8) |
+				    (tpl->data[6] << 16);
+		printk(KERN_DEBUG "%s: regs offset = 0x%x\n",
+		       sdio_func_id(func), port->regs_offset);
+		port->uartclk = tpl->data[7] * 115200;
+		if (port->uartclk == 0)
+			port->uartclk = 115200;
+		printk(KERN_DEBUG "%s: clk %d baudcode %u 4800-div %u\n",
+		       sdio_func_id(func), port->uartclk,
+		       tpl->data[7], tpl->data[8] | (tpl->data[9] << 8));
+	} else {
+		kfree(port);
+		return -EINVAL;
+	}
+
+	port->func = func;
+	sdio_set_drvdata(func, port);
+
+	ret = sdio_uart_add_port(port);
+	if (ret) {
+		kfree(port);
+	} else {
+		struct device *dev;
+		dev = tty_register_device(sdio_uart_tty_driver, port->index, &func->dev);
+		if (IS_ERR(dev)) {
+			sdio_uart_port_remove(port);
+			ret = PTR_ERR(dev);
+		}
+	}
+
+	return ret;
+}
+
+static void sdio_uart_remove(struct sdio_func *func)
+{
+	struct sdio_uart_port *port = sdio_get_drvdata(func);
+
+	tty_unregister_device(sdio_uart_tty_driver, port->index);
+	sdio_uart_port_remove(port);
+}
+
+static const struct sdio_device_id sdio_uart_ids[] = {
+	{ SDIO_DEVICE_CLASS(SDIO_CLASS_UART)		},
+	{ SDIO_DEVICE_CLASS(SDIO_CLASS_GPS)		},
+	{ /* end: all zeroes */				},
+};
+
+MODULE_DEVICE_TABLE(sdio, sdio_uart_ids);
+
+static struct sdio_driver sdio_uart_driver = {
+	.probe		= sdio_uart_probe,
+	.remove		= sdio_uart_remove,
+	.name		= "sdio_uart",
+	.id_table	= sdio_uart_ids,
+};
+
+static int __init sdio_uart_init(void)
+{
+	int ret;
+	struct tty_driver *tty_drv;
+
+	sdio_uart_tty_driver = tty_drv = alloc_tty_driver(UART_NR);
+	if (!tty_drv)
+		return -ENOMEM;
+
+	tty_drv->owner = THIS_MODULE;
+	tty_drv->driver_name = "sdio_uart";
+	tty_drv->name =   "ttySDIO";
+	tty_drv->major = 0;  /* dynamically allocated */
+	tty_drv->minor_start = 0;
+	tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
+	tty_drv->subtype = SERIAL_TYPE_NORMAL;
+	tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+	tty_drv->init_termios = tty_std_termios;
+	tty_drv->init_termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL;
+	tty_drv->init_termios.c_ispeed = 4800;
+	tty_drv->init_termios.c_ospeed = 4800;
+	tty_set_operations(tty_drv, &sdio_uart_ops);
+
+	ret = tty_register_driver(tty_drv);
+	if (ret)
+		goto err1;
+
+	ret = sdio_register_driver(&sdio_uart_driver);
+	if (ret)
+		goto err2;
+
+	return 0;
+
+err2:
+	tty_unregister_driver(tty_drv);
+err1:
+	put_tty_driver(tty_drv);
+	return ret;
+}
+
+static void __exit sdio_uart_exit(void)
+{
+	sdio_unregister_driver(&sdio_uart_driver);
+	tty_unregister_driver(sdio_uart_tty_driver);
+	put_tty_driver(sdio_uart_tty_driver);
+}
+
+module_init(sdio_uart_init);
+module_exit(sdio_uart_exit);
+
+MODULE_AUTHOR("Nicolas Pitre");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
index 3fdd08c..4985807 100644
--- a/drivers/mmc/core/Makefile
+++ b/drivers/mmc/core/Makefile
@@ -8,5 +8,7 @@
 
 obj-$(CONFIG_MMC)		+= mmc_core.o
 mmc_core-y			:= core.o sysfs.o bus.o host.o \
-				   mmc.o mmc_ops.o sd.o sd_ops.o
+				   mmc.o mmc_ops.o sd.o sd_ops.o \
+				   sdio.o sdio_ops.o sdio_bus.o \
+				   sdio_cis.o sdio_io.o sdio_irq.o
 
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 348b566..b0c22ca 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -19,6 +19,7 @@
 
 #include "sysfs.h"
 #include "core.h"
+#include "sdio_cis.h"
 #include "bus.h"
 
 #define dev_to_mmc_card(d)	container_of(d, struct mmc_card, dev)
@@ -34,6 +35,8 @@
 		return sprintf(buf, "MMC\n");
 	case MMC_TYPE_SD:
 		return sprintf(buf, "SD\n");
+	case MMC_TYPE_SDIO:
+		return sprintf(buf, "SDIO\n");
 	default:
 		return -EFAULT;
 	}
@@ -55,36 +58,35 @@
 }
 
 static int
-mmc_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
-		int buf_size)
+mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct mmc_card *card = dev_to_mmc_card(dev);
-	int retval = 0, i = 0, length = 0;
-
-#define add_env(fmt,val) do {					\
-	retval = add_uevent_var(envp, num_envp, &i,		\
-				buf, buf_size, &length,		\
-				fmt, val);			\
-	if (retval)						\
-		return retval;					\
-} while (0);
+	const char *type;
+	int retval = 0;
 
 	switch (card->type) {
 	case MMC_TYPE_MMC:
-		add_env("MMC_TYPE=%s", "MMC");
+		type = "MMC";
 		break;
 	case MMC_TYPE_SD:
-		add_env("MMC_TYPE=%s", "SD");
+		type = "SD";
 		break;
+	case MMC_TYPE_SDIO:
+		type = "SDIO";
+		break;
+	default:
+		type = NULL;
 	}
 
-	add_env("MMC_NAME=%s", mmc_card_name(card));
+	if (type) {
+		retval = add_uevent_var(env, "MMC_TYPE=%s", type);
+		if (retval)
+			return retval;
+	}
 
-#undef add_env
+	retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card));
 
-	envp[i] = NULL;
-
-	return 0;
+	return retval;
 }
 
 static int mmc_bus_probe(struct device *dev)
@@ -176,6 +178,11 @@
 {
 	struct mmc_card *card = dev_to_mmc_card(dev);
 
+	sdio_free_common_cis(card);
+
+	if (card->info)
+		kfree(card->info);
+
 	kfree(card);
 }
 
@@ -186,12 +193,10 @@
 {
 	struct mmc_card *card;
 
-	card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL);
+	card = kzalloc(sizeof(struct mmc_card), GFP_KERNEL);
 	if (!card)
 		return ERR_PTR(-ENOMEM);
 
-	memset(card, 0, sizeof(struct mmc_card));
-
 	card->host = host;
 
 	device_initialize(&card->dev);
@@ -209,10 +214,40 @@
 int mmc_add_card(struct mmc_card *card)
 {
 	int ret;
+	const char *type;
 
 	snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
 		 "%s:%04x", mmc_hostname(card->host), card->rca);
 
+	switch (card->type) {
+	case MMC_TYPE_MMC:
+		type = "MMC";
+		break;
+	case MMC_TYPE_SD:
+		type = "SD";
+		if (mmc_card_blockaddr(card))
+			type = "SDHC";
+		break;
+	case MMC_TYPE_SDIO:
+		type = "SDIO";
+		break;
+	default:
+		type = "?";
+		break;
+	}
+
+	if (mmc_host_is_spi(card->host)) {
+		printk(KERN_INFO "%s: new %s%s card on SPI\n",
+			mmc_hostname(card->host),
+			mmc_card_highspeed(card) ? "high speed " : "",
+			type);
+	} else {
+		printk(KERN_INFO "%s: new %s%s card at address %04x\n",
+			mmc_hostname(card->host),
+			mmc_card_highspeed(card) ? "high speed " : "",
+			type, card->rca);
+	}
+
 	card->dev.uevent_suppress = 1;
 
 	ret = device_add(&card->dev);
@@ -243,6 +278,14 @@
 void mmc_remove_card(struct mmc_card *card)
 {
 	if (mmc_card_present(card)) {
+		if (mmc_host_is_spi(card->host)) {
+			printk(KERN_INFO "%s: SPI card removed\n",
+				mmc_hostname(card->host));
+		} else {
+			printk(KERN_INFO "%s: card %04x removed\n",
+				mmc_hostname(card->host), card->rca);
+		}
+
 		if (card->host->bus_ops->sysfs_remove)
 			card->host->bus_ops->sysfs_remove(card->host, card);
 		device_del(&card->dev);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index b5d8a6d..09435e0 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/pagemap.h>
 #include <linux/err.h>
+#include <linux/leds.h>
 #include <asm/scatterlist.h>
 #include <linux/scatterlist.h>
 
@@ -29,16 +30,27 @@
 #include "core.h"
 #include "bus.h"
 #include "host.h"
+#include "sdio_bus.h"
 
 #include "mmc_ops.h"
 #include "sd_ops.h"
+#include "sdio_ops.h"
 
 extern int mmc_attach_mmc(struct mmc_host *host, u32 ocr);
 extern int mmc_attach_sd(struct mmc_host *host, u32 ocr);
+extern int mmc_attach_sdio(struct mmc_host *host, u32 ocr);
 
 static struct workqueue_struct *workqueue;
 
 /*
+ * Enabling software CRCs on the data blocks can be a significant (30%)
+ * performance cost, and for other reasons may not always be desired.
+ * So we allow it it to be disabled.
+ */
+int use_spi_crc = 1;
+module_param(use_spi_crc, bool, 0);
+
+/*
  * Internal function. Schedule delayed work in the MMC work queue.
  */
 static int mmc_schedule_delayed_work(struct delayed_work *work,
@@ -68,32 +80,48 @@
 	struct mmc_command *cmd = mrq->cmd;
 	int err = cmd->error;
 
-	pr_debug("%s: req done (CMD%u): %d/%d/%d: %08x %08x %08x %08x\n",
-		 mmc_hostname(host), cmd->opcode, err,
-		 mrq->data ? mrq->data->error : 0,
-		 mrq->stop ? mrq->stop->error : 0,
-		 cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
+	if (err && cmd->retries && mmc_host_is_spi(host)) {
+		if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
+			cmd->retries = 0;
+	}
 
 	if (err && cmd->retries) {
+		pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
+			mmc_hostname(host), cmd->opcode, err);
+
 		cmd->retries--;
 		cmd->error = 0;
 		host->ops->request(host, mrq);
-	} else if (mrq->done) {
-		mrq->done(mrq);
+	} else {
+		led_trigger_event(host->led, LED_OFF);
+
+		pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
+			mmc_hostname(host), cmd->opcode, err,
+			cmd->resp[0], cmd->resp[1],
+			cmd->resp[2], cmd->resp[3]);
+
+		if (mrq->data) {
+			pr_debug("%s:     %d bytes transferred: %d\n",
+				mmc_hostname(host),
+				mrq->data->bytes_xfered, mrq->data->error);
+		}
+
+		if (mrq->stop) {
+			pr_debug("%s:     (CMD%u): %d: %08x %08x %08x %08x\n",
+				mmc_hostname(host), mrq->stop->opcode,
+				mrq->stop->error,
+				mrq->stop->resp[0], mrq->stop->resp[1],
+				mrq->stop->resp[2], mrq->stop->resp[3]);
+		}
+
+		if (mrq->done)
+			mrq->done(mrq);
 	}
 }
 
 EXPORT_SYMBOL(mmc_request_done);
 
-/**
- *	mmc_start_request - start a command on a host
- *	@host: MMC host to start command on
- *	@mrq: MMC request to start
- *
- *	Queue a command on the specified host.  We expect the
- *	caller to be holding the host lock with interrupts disabled.
- */
-void
+static void
 mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
 {
 #ifdef CONFIG_MMC_DEBUG
@@ -104,8 +132,25 @@
 		 mmc_hostname(host), mrq->cmd->opcode,
 		 mrq->cmd->arg, mrq->cmd->flags);
 
+	if (mrq->data) {
+		pr_debug("%s:     blksz %d blocks %d flags %08x "
+			"tsac %d ms nsac %d\n",
+			mmc_hostname(host), mrq->data->blksz,
+			mrq->data->blocks, mrq->data->flags,
+			mrq->data->timeout_ns / 1000000,
+			mrq->data->timeout_clks);
+	}
+
+	if (mrq->stop) {
+		pr_debug("%s:     CMD%u arg %08x flags %08x\n",
+			 mmc_hostname(host), mrq->stop->opcode,
+			 mrq->stop->arg, mrq->stop->flags);
+	}
+
 	WARN_ON(!host->claimed);
 
+	led_trigger_event(host->led, LED_FULL);
+
 	mrq->cmd->error = 0;
 	mrq->cmd->mrq = mrq;
 	if (mrq->data) {
@@ -133,14 +178,21 @@
 	host->ops->request(host, mrq);
 }
 
-EXPORT_SYMBOL(mmc_start_request);
-
 static void mmc_wait_done(struct mmc_request *mrq)
 {
 	complete(mrq->done_data);
 }
 
-int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
+/**
+ *	mmc_wait_for_req - start a request and wait for completion
+ *	@host: MMC host to start command
+ *	@mrq: MMC request to start
+ *
+ *	Start a new MMC custom command request for a host, and wait
+ *	for the command to complete. Does not attempt to parse the
+ *	response.
+ */
+void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
 {
 	DECLARE_COMPLETION_ONSTACK(complete);
 
@@ -150,8 +202,6 @@
 	mmc_start_request(host, mrq);
 
 	wait_for_completion(&complete);
-
-	return 0;
 }
 
 EXPORT_SYMBOL(mmc_wait_for_req);
@@ -170,7 +220,7 @@
 {
 	struct mmc_request mrq;
 
-	BUG_ON(!host->claimed);
+	WARN_ON(!host->claimed);
 
 	memset(&mrq, 0, sizeof(struct mmc_request));
 
@@ -191,14 +241,24 @@
  *	mmc_set_data_timeout - set the timeout for a data command
  *	@data: data phase for command
  *	@card: the MMC card associated with the data transfer
- *	@write: flag to differentiate reads from writes
+ *
+ *	Computes the data timeout parameters according to the
+ *	correct algorithm given the card type.
  */
-void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
-			  int write)
+void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
 {
 	unsigned int mult;
 
 	/*
+	 * SDIO cards only define an upper 1 s limit on access.
+	 */
+	if (mmc_card_sdio(card)) {
+		data->timeout_ns = 1000000000;
+		data->timeout_clks = 0;
+		return;
+	}
+
+	/*
 	 * SD cards use a 100 multiplier rather than 10
 	 */
 	mult = mmc_card_sd(card) ? 100 : 10;
@@ -207,7 +267,7 @@
 	 * Scale up the multiplier (and therefore the timeout) by
 	 * the r2w factor for writes.
 	 */
-	if (write)
+	if (data->flags & MMC_DATA_WRITE)
 		mult <<= card->csd.r2w_factor;
 
 	data->timeout_ns = card->csd.tacc_ns * mult;
@@ -223,7 +283,7 @@
 		timeout_us += data->timeout_clks * 1000 /
 			(card->host->ios.clock / 1000);
 
-		if (write)
+		if (data->flags & MMC_DATA_WRITE)
 			limit_us = 250000;
 		else
 			limit_us = 100000;
@@ -242,36 +302,43 @@
 /**
  *	__mmc_claim_host - exclusively claim a host
  *	@host: mmc host to claim
- *	@card: mmc card to claim host for
+ *	@abort: whether or not the operation should be aborted
  *
- *	Claim a host for a set of operations.  If a valid card
- *	is passed and this wasn't the last card selected, select
- *	the card before returning.
- *
- *	Note: you should use mmc_card_claim_host or mmc_claim_host.
+ *	Claim a host for a set of operations.  If @abort is non null and
+ *	dereference a non-zero value then this will return prematurely with
+ *	that non-zero value without acquiring the lock.  Returns zero
+ *	with the lock held otherwise.
  */
-void mmc_claim_host(struct mmc_host *host)
+int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
 {
 	DECLARE_WAITQUEUE(wait, current);
 	unsigned long flags;
+	int stop;
+
+	might_sleep();
 
 	add_wait_queue(&host->wq, &wait);
 	spin_lock_irqsave(&host->lock, flags);
 	while (1) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
-		if (!host->claimed)
+		stop = abort ? atomic_read(abort) : 0;
+		if (stop || !host->claimed)
 			break;
 		spin_unlock_irqrestore(&host->lock, flags);
 		schedule();
 		spin_lock_irqsave(&host->lock, flags);
 	}
 	set_current_state(TASK_RUNNING);
-	host->claimed = 1;
+	if (!stop)
+		host->claimed = 1;
+	else
+		wake_up(&host->wq);
 	spin_unlock_irqrestore(&host->lock, flags);
 	remove_wait_queue(&host->wq, &wait);
+	return stop;
 }
 
-EXPORT_SYMBOL(mmc_claim_host);
+EXPORT_SYMBOL(__mmc_claim_host);
 
 /**
  *	mmc_release_host - release a host
@@ -284,7 +351,7 @@
 {
 	unsigned long flags;
 
-	BUG_ON(!host->claimed);
+	WARN_ON(!host->claimed);
 
 	spin_lock_irqsave(&host->lock, flags);
 	host->claimed = 0;
@@ -404,19 +471,32 @@
 	int bit = fls(host->ocr_avail) - 1;
 
 	host->ios.vdd = bit;
-	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
-	host->ios.chip_select = MMC_CS_DONTCARE;
+	if (mmc_host_is_spi(host)) {
+		host->ios.chip_select = MMC_CS_HIGH;
+		host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
+	} else {
+		host->ios.chip_select = MMC_CS_DONTCARE;
+		host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+	}
 	host->ios.power_mode = MMC_POWER_UP;
 	host->ios.bus_width = MMC_BUS_WIDTH_1;
 	host->ios.timing = MMC_TIMING_LEGACY;
 	mmc_set_ios(host);
 
-	mmc_delay(1);
+	/*
+	 * This delay should be sufficient to allow the power supply
+	 * to reach the minimum voltage.
+	 */
+	mmc_delay(2);
 
 	host->ios.clock = host->f_min;
 	host->ios.power_mode = MMC_POWER_ON;
 	mmc_set_ios(host);
 
+	/*
+	 * This delay must be at least 74 clock sizes, or 1 ms, or the
+	 * time required to reach a stable voltage.
+	 */
 	mmc_delay(2);
 }
 
@@ -424,8 +504,10 @@
 {
 	host->ios.clock = 0;
 	host->ios.vdd = 0;
-	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
-	host->ios.chip_select = MMC_CS_DONTCARE;
+	if (!mmc_host_is_spi(host)) {
+		host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
+		host->ios.chip_select = MMC_CS_DONTCARE;
+	}
 	host->ios.power_mode = MMC_POWER_OFF;
 	host->ios.bus_width = MMC_BUS_WIDTH_1;
 	host->ios.timing = MMC_TIMING_LEGACY;
@@ -433,6 +515,45 @@
 }
 
 /*
+ * Cleanup when the last reference to the bus operator is dropped.
+ */
+void __mmc_release_bus(struct mmc_host *host)
+{
+	BUG_ON(!host);
+	BUG_ON(host->bus_refs);
+	BUG_ON(!host->bus_dead);
+
+	host->bus_ops = NULL;
+}
+
+/*
+ * Increase reference count of bus operator
+ */
+static inline void mmc_bus_get(struct mmc_host *host)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	host->bus_refs++;
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/*
+ * Decrease reference count of bus operator and free it if
+ * it is the last reference.
+ */
+static inline void mmc_bus_put(struct mmc_host *host)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->lock, flags);
+	host->bus_refs--;
+	if ((host->bus_refs == 0) && host->bus_ops)
+		__mmc_release_bus(host);
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
+/*
  * Assign a mmc bus handler to a host. Only one bus handler may control a
  * host at any given time.
  */
@@ -443,7 +564,7 @@
 	BUG_ON(!host);
 	BUG_ON(!ops);
 
-	BUG_ON(!host->claimed);
+	WARN_ON(!host->claimed);
 
 	spin_lock_irqsave(&host->lock, flags);
 
@@ -467,8 +588,8 @@
 
 	BUG_ON(!host);
 
-	BUG_ON(!host->claimed);
-	BUG_ON(!host->bus_ops);
+	WARN_ON(!host->claimed);
+	WARN_ON(!host->bus_ops);
 
 	spin_lock_irqsave(&host->lock, flags);
 
@@ -481,32 +602,22 @@
 	mmc_bus_put(host);
 }
 
-/*
- * Cleanup when the last reference to the bus operator is dropped.
- */
-void __mmc_release_bus(struct mmc_host *host)
-{
-	BUG_ON(!host);
-	BUG_ON(host->bus_refs);
-	BUG_ON(!host->bus_dead);
-
-	host->bus_ops = NULL;
-}
-
 /**
  *	mmc_detect_change - process change of state on a MMC socket
  *	@host: host which changed state.
  *	@delay: optional delay to wait before detection (jiffies)
  *
- *	All we know is that card(s) have been inserted or removed
- *	from the socket(s).  We don't know which socket or cards.
+ *	MMC drivers should call this when they detect a card has been
+ *	inserted or removed. The MMC layer will confirm that any
+ *	present card is still functional, and initialize any newly
+ *	inserted.
  */
 void mmc_detect_change(struct mmc_host *host, unsigned long delay)
 {
 #ifdef CONFIG_MMC_DEBUG
 	unsigned long flags;
 	spin_lock_irqsave(&host->lock, flags);
-	BUG_ON(host->removed);
+	WARN_ON(host->removed);
 	spin_unlock_irqrestore(&host->lock, flags);
 #endif
 
@@ -539,24 +650,38 @@
 
 		mmc_send_if_cond(host, host->ocr_avail);
 
+		/*
+		 * First we search for SDIO...
+		 */
+		err = mmc_send_io_op_cond(host, 0, &ocr);
+		if (!err) {
+			if (mmc_attach_sdio(host, ocr))
+				mmc_power_off(host);
+			return;
+		}
+
+		/*
+		 * ...then normal SD...
+		 */
 		err = mmc_send_app_op_cond(host, 0, &ocr);
-		if (err == MMC_ERR_NONE) {
+		if (!err) {
 			if (mmc_attach_sd(host, ocr))
 				mmc_power_off(host);
-		} else {
-			/*
-			 * If we fail to detect any SD cards then try
-			 * searching for MMC cards.
-			 */
-			err = mmc_send_op_cond(host, 0, &ocr);
-			if (err == MMC_ERR_NONE) {
-				if (mmc_attach_mmc(host, ocr))
-					mmc_power_off(host);
-			} else {
-				mmc_power_off(host);
-				mmc_release_host(host);
-			}
+			return;
 		}
+
+		/*
+		 * ...and finally MMC.
+		 */
+		err = mmc_send_op_cond(host, 0, &ocr);
+		if (!err) {
+			if (mmc_attach_mmc(host, ocr))
+				mmc_power_off(host);
+			return;
+		}
+
+		mmc_release_host(host);
+		mmc_power_off(host);
 	} else {
 		if (host->bus_ops->detect && !host->bus_dead)
 			host->bus_ops->detect(host);
@@ -667,22 +792,38 @@
 		return -ENOMEM;
 
 	ret = mmc_register_bus();
-	if (ret == 0) {
-		ret = mmc_register_host_class();
-		if (ret)
-			mmc_unregister_bus();
-	}
+	if (ret)
+		goto destroy_workqueue;
+
+	ret = mmc_register_host_class();
+	if (ret)
+		goto unregister_bus;
+
+	ret = sdio_register_bus();
+	if (ret)
+		goto unregister_host_class;
+
+	return 0;
+
+unregister_host_class:
+	mmc_unregister_host_class();
+unregister_bus:
+	mmc_unregister_bus();
+destroy_workqueue:
+	destroy_workqueue(workqueue);
+
 	return ret;
 }
 
 static void __exit mmc_exit(void)
 {
+	sdio_unregister_bus();
 	mmc_unregister_host_class();
 	mmc_unregister_bus();
 	destroy_workqueue(workqueue);
 }
 
-module_init(mmc_init);
+subsys_initcall(mmc_init);
 module_exit(mmc_exit);
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index ae006b3..39daf2f 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -27,28 +27,6 @@
 void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
 void mmc_detach_bus(struct mmc_host *host);
 
-void __mmc_release_bus(struct mmc_host *host);
-
-static inline void mmc_bus_get(struct mmc_host *host)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&host->lock, flags);
-	host->bus_refs++;
-	spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static inline void mmc_bus_put(struct mmc_host *host)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&host->lock, flags);
-	host->bus_refs--;
-	if ((host->bus_refs == 0) && host->bus_ops)
-		__mmc_release_bus(host);
-	spin_unlock_irqrestore(&host->lock, flags);
-}
-
 void mmc_set_chip_select(struct mmc_host *host, int mode);
 void mmc_set_clock(struct mmc_host *host, unsigned int hz);
 void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
@@ -70,5 +48,7 @@
 void mmc_start_host(struct mmc_host *host);
 void mmc_stop_host(struct mmc_host *host);
 
+extern int use_spi_crc;
+
 #endif
 
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 1433d95..c65d203 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -15,6 +15,7 @@
 #include <linux/err.h>
 #include <linux/idr.h>
 #include <linux/pagemap.h>
+#include <linux/leds.h>
 
 #include <linux/mmc/host.h>
 
@@ -58,12 +59,10 @@
 {
 	struct mmc_host *host;
 
-	host = kmalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
+	host = kzalloc(sizeof(struct mmc_host) + extra, GFP_KERNEL);
 	if (!host)
 		return NULL;
 
-	memset(host, 0, sizeof(struct mmc_host) + extra);
-
 	host->parent = dev;
 	host->class_dev.parent = dev;
 	host->class_dev.class = &mmc_host_class;
@@ -93,11 +92,18 @@
 /**
  *	mmc_add_host - initialise host hardware
  *	@host: mmc host
+ *
+ *	Register the host with the driver model. The host must be
+ *	prepared to start servicing requests before this function
+ *	completes.
  */
 int mmc_add_host(struct mmc_host *host)
 {
 	int err;
 
+	WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
+		!host->ops->enable_sdio_irq);
+
 	if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
 		return -ENOMEM;
 
@@ -110,6 +116,8 @@
 	snprintf(host->class_dev.bus_id, BUS_ID_SIZE,
 		 "mmc%d", host->index);
 
+	led_trigger_register_simple(host->class_dev.bus_id, &host->led);
+
 	err = device_add(&host->class_dev);
 	if (err)
 		return err;
@@ -126,7 +134,8 @@
  *	@host: mmc host
  *
  *	Unregister and remove all cards associated with this host,
- *	and power down the MMC bus.
+ *	and power down the MMC bus. No new requests will be issued
+ *	after this function has returned.
  */
 void mmc_remove_host(struct mmc_host *host)
 {
@@ -134,6 +143,8 @@
 
 	device_del(&host->class_dev);
 
+	led_trigger_unregister_simple(host->led);
+
 	spin_lock(&mmc_host_lock);
 	idr_remove(&mmc_host_idr, host->index);
 	spin_unlock(&mmc_host_lock);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 66f85bf..65fe288 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mmc/mmc.c
+ *  linux/drivers/mmc/core/mmc.c
  *
  *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
  *  Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
@@ -100,7 +100,7 @@
 		break;
 
 	default:
-		printk("%s: card has unknown MMCA version %d\n",
+		printk(KERN_ERR "%s: card has unknown MMCA version %d\n",
 			mmc_hostname(card->host), card->csd.mmca_vsn);
 		return -EINVAL;
 	}
@@ -123,7 +123,7 @@
 	 */
 	csd_struct = UNSTUFF_BITS(resp, 126, 2);
 	if (csd_struct != 1 && csd_struct != 2) {
-		printk("%s: unrecognised CSD structure version %d\n",
+		printk(KERN_ERR "%s: unrecognised CSD structure version %d\n",
 			mmc_hostname(card->host), csd_struct);
 		return -EINVAL;
 	}
@@ -161,13 +161,12 @@
 {
 	int err;
 	u8 *ext_csd;
+	unsigned int ext_csd_struct;
 
 	BUG_ON(!card);
 
-	err = MMC_ERR_FAILED;
-
 	if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
-		return MMC_ERR_NONE;
+		return 0;
 
 	/*
 	 * As the ext_csd is so large and mostly unused, we don't store the
@@ -176,13 +175,19 @@
 	ext_csd = kmalloc(512, GFP_KERNEL);
 	if (!ext_csd) {
 		printk(KERN_ERR "%s: could not allocate a buffer to "
-			"receive the ext_csd. mmc v4 cards will be "
-			"treated as v3.\n", mmc_hostname(card->host));
-		return MMC_ERR_FAILED;
+			"receive the ext_csd.\n", mmc_hostname(card->host));
+		return -ENOMEM;
 	}
 
 	err = mmc_send_ext_csd(card, ext_csd);
-	if (err != MMC_ERR_NONE) {
+	if (err) {
+		/*
+		 * We all hosts that cannot perform the command
+		 * to fail more gracefully
+		 */
+		if (err != -EINVAL)
+			goto out;
+
 		/*
 		 * High capacity cards should have this "magic" size
 		 * stored in their CSD.
@@ -197,18 +202,29 @@
 				"EXT_CSD, performance might "
 				"suffer.\n",
 				mmc_hostname(card->host));
-			err = MMC_ERR_NONE;
+			err = 0;
 		}
+
 		goto out;
 	}
 
-	card->ext_csd.sectors =
-		ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
-		ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
-		ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
-		ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
-	if (card->ext_csd.sectors)
-		mmc_card_set_blockaddr(card);
+	ext_csd_struct = ext_csd[EXT_CSD_REV];
+	if (ext_csd_struct > 2) {
+		printk(KERN_ERR "%s: unrecognised EXT_CSD structure "
+			"version %d\n", mmc_hostname(card->host),
+			ext_csd_struct);
+		return -EINVAL;
+	}
+
+	if (ext_csd_struct >= 2) {
+		card->ext_csd.sectors =
+			ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
+			ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
+			ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
+			ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
+		if (card->ext_csd.sectors)
+			mmc_card_set_blockaddr(card);
+	}
 
 	switch (ext_csd[EXT_CSD_CARD_TYPE]) {
 	case EXT_CSD_CARD_TYPE_52 | EXT_CSD_CARD_TYPE_26:
@@ -246,7 +262,7 @@
 	unsigned int max_dtr;
 
 	BUG_ON(!host);
-	BUG_ON(!host->claimed);
+	WARN_ON(!host->claimed);
 
 	/*
 	 * Since we're changing the OCR value, we seem to
@@ -258,19 +274,33 @@
 
 	/* The extra bit indicates that we support high capacity */
 	err = mmc_send_op_cond(host, ocr | (1 << 30), NULL);
-	if (err != MMC_ERR_NONE)
+	if (err)
 		goto err;
 
 	/*
+	 * For SPI, enable CRC as appropriate.
+	 */
+	if (mmc_host_is_spi(host)) {
+		err = mmc_spi_set_crc(host, use_spi_crc);
+		if (err)
+			goto err;
+	}
+
+	/*
 	 * Fetch CID from card.
 	 */
-	err = mmc_all_send_cid(host, cid);
-	if (err != MMC_ERR_NONE)
+	if (mmc_host_is_spi(host))
+		err = mmc_send_cid(host, cid);
+	else
+		err = mmc_all_send_cid(host, cid);
+	if (err)
 		goto err;
 
 	if (oldcard) {
-		if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
+		if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) {
+			err = -ENOENT;
 			goto err;
+		}
 
 		card = oldcard;
 	} else {
@@ -278,8 +308,10 @@
 		 * Allocate card structure.
 		 */
 		card = mmc_alloc_card(host);
-		if (IS_ERR(card))
+		if (IS_ERR(card)) {
+			err = PTR_ERR(card);
 			goto err;
+		}
 
 		card->type = MMC_TYPE_MMC;
 		card->rca = 1;
@@ -287,43 +319,47 @@
 	}
 
 	/*
-	 * Set card RCA.
+	 * For native busses:  set card RCA and quit open drain mode.
 	 */
-	err = mmc_set_relative_addr(card);
-	if (err != MMC_ERR_NONE)
-		goto free_card;
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_set_relative_addr(card);
+		if (err)
+			goto free_card;
 
-	mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+	}
 
 	if (!oldcard) {
 		/*
 		 * Fetch CSD from card.
 		 */
 		err = mmc_send_csd(card, card->raw_csd);
-		if (err != MMC_ERR_NONE)
+		if (err)
 			goto free_card;
 
 		err = mmc_decode_csd(card);
-		if (err < 0)
+		if (err)
 			goto free_card;
 		err = mmc_decode_cid(card);
-		if (err < 0)
+		if (err)
 			goto free_card;
 	}
 
 	/*
 	 * Select card, as all following commands rely on that.
 	 */
-	err = mmc_select_card(card);
-	if (err != MMC_ERR_NONE)
-		goto free_card;
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_select_card(card);
+		if (err)
+			goto free_card;
+	}
 
 	if (!oldcard) {
 		/*
-		 * Fetch and process extened CSD.
+		 * Fetch and process extended CSD.
 		 */
 		err = mmc_read_ext_csd(card);
-		if (err != MMC_ERR_NONE)
+		if (err)
 			goto free_card;
 	}
 
@@ -334,7 +370,7 @@
 		(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 			EXT_CSD_HS_TIMING, 1);
-		if (err != MMC_ERR_NONE)
+		if (err)
 			goto free_card;
 
 		mmc_card_set_highspeed(card);
@@ -363,7 +399,7 @@
 		(host->caps & MMC_CAP_4_BIT_DATA)) {
 		err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
 			EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_4);
-		if (err != MMC_ERR_NONE)
+		if (err)
 			goto free_card;
 
 		mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
@@ -372,14 +408,14 @@
 	if (!oldcard)
 		host->card = card;
 
-	return MMC_ERR_NONE;
+	return 0;
 
 free_card:
 	if (!oldcard)
 		mmc_remove_card(card);
 err:
 
-	return MMC_ERR_FAILED;
+	return err;
 }
 
 /*
@@ -413,7 +449,7 @@
 
 	mmc_release_host(host);
 
-	if (err != MMC_ERR_NONE) {
+	if (err) {
 		mmc_remove(host);
 
 		mmc_claim_host(host);
@@ -480,7 +516,8 @@
 	BUG_ON(!host->card);
 
 	mmc_claim_host(host);
-	mmc_deselect_cards(host);
+	if (!mmc_host_is_spi(host))
+		mmc_deselect_cards(host);
 	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_release_host(host);
 }
@@ -499,14 +536,17 @@
 	BUG_ON(!host->card);
 
 	mmc_claim_host(host);
-
 	err = mmc_init_card(host, host->ocr, host->card);
-	if (err != MMC_ERR_NONE) {
+	mmc_release_host(host);
+
+	if (err) {
 		mmc_remove(host);
+
+		mmc_claim_host(host);
 		mmc_detach_bus(host);
+		mmc_release_host(host);
 	}
 
-	mmc_release_host(host);
 }
 
 #else
@@ -533,11 +573,20 @@
 	int err;
 
 	BUG_ON(!host);
-	BUG_ON(!host->claimed);
+	WARN_ON(!host->claimed);
 
 	mmc_attach_bus(host, &mmc_ops);
 
 	/*
+	 * We need to get OCR a different way for SPI.
+	 */
+	if (mmc_host_is_spi(host)) {
+		err = mmc_spi_read_ocr(host, 1, &ocr);
+		if (err)
+			goto err;
+	}
+
+	/*
 	 * Sanity check the voltages that the card claims to
 	 * support.
 	 */
@@ -553,32 +602,37 @@
 	/*
 	 * Can we support the voltage of the card?
 	 */
-	if (!host->ocr)
+	if (!host->ocr) {
+		err = -EINVAL;
 		goto err;
+	}
 
 	/*
 	 * Detect and init the card.
 	 */
 	err = mmc_init_card(host, host->ocr, NULL);
-	if (err != MMC_ERR_NONE)
+	if (err)
 		goto err;
 
 	mmc_release_host(host);
 
 	err = mmc_add_card(host->card);
 	if (err)
-		goto reclaim_host;
+		goto remove_card;
 
 	return 0;
 
-reclaim_host:
-	mmc_claim_host(host);
+remove_card:
 	mmc_remove_card(host->card);
 	host->card = NULL;
+	mmc_claim_host(host);
 err:
 	mmc_detach_bus(host);
 	mmc_release_host(host);
 
-	return 0;
+	printk(KERN_ERR "%s: error %d whilst initialising MMC card\n",
+		mmc_hostname(host), err);
+
+	return err;
 }
 
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 7dd720f..bf4bc6a 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mmc/mmc_ops.h
+ *  linux/drivers/mmc/core/mmc_ops.h
  *
  *  Copyright 2006-2007 Pierre Ossman
  *
@@ -40,10 +40,10 @@
 	}
 
 	err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
-	if (err != MMC_ERR_NONE)
+	if (err)
 		return err;
 
-	return MMC_ERR_NONE;
+	return 0;
 }
 
 int mmc_select_card(struct mmc_card *card)
@@ -63,23 +63,36 @@
 	int err;
 	struct mmc_command cmd;
 
-	mmc_set_chip_select(host, MMC_CS_HIGH);
-
-	mmc_delay(1);
+	/*
+	 * Non-SPI hosts need to prevent chipselect going active during
+	 * GO_IDLE; that would put chips into SPI mode.  Remind them of
+	 * that in case of hardware that won't pull up DAT3/nCS otherwise.
+	 *
+	 * SPI hosts ignore ios.chip_select; it's managed according to
+	 * rules that must accomodate non-MMC slaves which this layer
+	 * won't even know about.
+	 */
+	if (!mmc_host_is_spi(host)) {
+		mmc_set_chip_select(host, MMC_CS_HIGH);
+		mmc_delay(1);
+	}
 
 	memset(&cmd, 0, sizeof(struct mmc_command));
 
 	cmd.opcode = MMC_GO_IDLE_STATE;
 	cmd.arg = 0;
-	cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
 
 	err = mmc_wait_for_cmd(host, &cmd, 0);
 
 	mmc_delay(1);
 
-	mmc_set_chip_select(host, MMC_CS_DONTCARE);
+	if (!mmc_host_is_spi(host)) {
+		mmc_set_chip_select(host, MMC_CS_DONTCARE);
+		mmc_delay(1);
+	}
 
-	mmc_delay(1);
+	host->use_spi_crc = 0;
 
 	return err;
 }
@@ -94,23 +107,33 @@
 	memset(&cmd, 0, sizeof(struct mmc_command));
 
 	cmd.opcode = MMC_SEND_OP_COND;
-	cmd.arg = ocr;
-	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+	cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
 
 	for (i = 100; i; i--) {
 		err = mmc_wait_for_cmd(host, &cmd, 0);
-		if (err != MMC_ERR_NONE)
+		if (err)
 			break;
 
-		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+		/* if we're just probing, do a single pass */
+		if (ocr == 0)
 			break;
 
-		err = MMC_ERR_TIMEOUT;
+		/* otherwise wait until reset completes */
+		if (mmc_host_is_spi(host)) {
+			if (!(cmd.resp[0] & R1_SPI_IDLE))
+				break;
+		} else {
+			if (cmd.resp[0] & MMC_CARD_BUSY)
+				break;
+		}
+
+		err = -ETIMEDOUT;
 
 		mmc_delay(10);
 	}
 
-	if (rocr)
+	if (rocr && !mmc_host_is_spi(host))
 		*rocr = cmd.resp[0];
 
 	return err;
@@ -131,12 +154,12 @@
 	cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
 
 	err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
-	if (err != MMC_ERR_NONE)
+	if (err)
 		return err;
 
 	memcpy(cid, cmd.resp, sizeof(u32) * 4);
 
-	return MMC_ERR_NONE;
+	return 0;
 }
 
 int mmc_set_relative_addr(struct mmc_card *card)
@@ -154,46 +177,52 @@
 	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
 
 	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
-	if (err != MMC_ERR_NONE)
+	if (err)
 		return err;
 
-	return MMC_ERR_NONE;
+	return 0;
 }
 
-int mmc_send_csd(struct mmc_card *card, u32 *csd)
+static int
+mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
 {
 	int err;
 	struct mmc_command cmd;
 
-	BUG_ON(!card);
-	BUG_ON(!card->host);
-	BUG_ON(!csd);
+	BUG_ON(!host);
+	BUG_ON(!cxd);
 
 	memset(&cmd, 0, sizeof(struct mmc_command));
 
-	cmd.opcode = MMC_SEND_CSD;
-	cmd.arg = card->rca << 16;
+	cmd.opcode = opcode;
+	cmd.arg = arg;
 	cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
 
-	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
-	if (err != MMC_ERR_NONE)
+	err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+	if (err)
 		return err;
 
-	memcpy(csd, cmd.resp, sizeof(u32) * 4);
+	memcpy(cxd, cmd.resp, sizeof(u32) * 4);
 
-	return MMC_ERR_NONE;
+	return 0;
 }
 
-int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
+static int
+mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
+		u32 opcode, void *buf, unsigned len)
 {
 	struct mmc_request mrq;
 	struct mmc_command cmd;
 	struct mmc_data data;
 	struct scatterlist sg;
+	void *data_buf;
 
-	BUG_ON(!card);
-	BUG_ON(!card->host);
-	BUG_ON(!ext_csd);
+	/* dma onto stack is unsafe/nonportable, but callers to this
+	 * routine normally provide temporary on-stack buffers ...
+	 */
+	data_buf = kmalloc(len, GFP_KERNEL);
+	if (data_buf == NULL)
+		return -ENOMEM;
 
 	memset(&mrq, 0, sizeof(struct mmc_request));
 	memset(&cmd, 0, sizeof(struct mmc_command));
@@ -202,28 +231,99 @@
 	mrq.cmd = &cmd;
 	mrq.data = &data;
 
-	cmd.opcode = MMC_SEND_EXT_CSD;
+	cmd.opcode = opcode;
 	cmd.arg = 0;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
 
-	data.blksz = 512;
+	/* NOTE HACK:  the MMC_RSP_SPI_R1 is always correct here, but we
+	 * rely on callers to never use this with "native" calls for reading
+	 * CSD or CID.  Native versions of those commands use the R2 type,
+	 * not R1 plus a data block.
+	 */
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	data.blksz = len;
 	data.blocks = 1;
 	data.flags = MMC_DATA_READ;
 	data.sg = &sg;
 	data.sg_len = 1;
 
-	sg_init_one(&sg, ext_csd, 512);
+	sg_init_one(&sg, data_buf, len);
 
-	mmc_set_data_timeout(&data, card, 0);
+	if (card)
+		mmc_set_data_timeout(&data, card);
 
-	mmc_wait_for_req(card->host, &mrq);
+	mmc_wait_for_req(host, &mrq);
 
-	if (cmd.error != MMC_ERR_NONE)
+	memcpy(buf, data_buf, len);
+	kfree(data_buf);
+
+	if (cmd.error)
 		return cmd.error;
-	if (data.error != MMC_ERR_NONE)
+	if (data.error)
 		return data.error;
 
-	return MMC_ERR_NONE;
+	return 0;
+}
+
+int mmc_send_csd(struct mmc_card *card, u32 *csd)
+{
+	if (!mmc_host_is_spi(card->host))
+		return mmc_send_cxd_native(card->host, card->rca << 16,
+				csd, MMC_SEND_CSD);
+
+	return mmc_send_cxd_data(card, card->host, MMC_SEND_CSD, csd, 16);
+}
+
+int mmc_send_cid(struct mmc_host *host, u32 *cid)
+{
+	if (!mmc_host_is_spi(host)) {
+		if (!host->card)
+			return -EINVAL;
+		return mmc_send_cxd_native(host, host->card->rca << 16,
+				cid, MMC_SEND_CID);
+	}
+
+	return mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid, 16);
+}
+
+int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+	return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD,
+			ext_csd, 512);
+}
+
+int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
+{
+	struct mmc_command cmd;
+	int err;
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SPI_READ_OCR;
+	cmd.arg = highcap ? (1 << 30) : 0;
+	cmd.flags = MMC_RSP_SPI_R3;
+
+	err = mmc_wait_for_cmd(host, &cmd, 0);
+
+	*ocrp = cmd.resp[1];
+	return err;
+}
+
+int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
+{
+	struct mmc_command cmd;
+	int err;
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SPI_CRC_ON_OFF;
+	cmd.flags = MMC_RSP_SPI_R1;
+	cmd.arg = use_crc;
+
+	err = mmc_wait_for_cmd(host, &cmd, 0);
+	if (!err)
+		host->use_spi_crc = use_crc;
+	return err;
 }
 
 int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
@@ -241,13 +341,13 @@
 		  (index << 16) |
 		  (value << 8) |
 		  set;
-	cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+	cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
 
 	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
-	if (err != MMC_ERR_NONE)
+	if (err)
 		return err;
 
-	return MMC_ERR_NONE;
+	return 0;
 }
 
 int mmc_send_status(struct mmc_card *card, u32 *status)
@@ -261,16 +361,20 @@
 	memset(&cmd, 0, sizeof(struct mmc_command));
 
 	cmd.opcode = MMC_SEND_STATUS;
-	cmd.arg = card->rca << 16;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	if (!mmc_host_is_spi(card->host))
+		cmd.arg = card->rca << 16;
+	cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
 
 	err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
-	if (err != MMC_ERR_NONE)
+	if (err)
 		return err;
 
+	/* NOTE: callers are required to understand the difference
+	 * between "native" and SPI format status words!
+	 */
 	if (status)
 		*status = cmd.resp[0];
 
-	return MMC_ERR_NONE;
+	return 0;
 }
 
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 7a481e8..17854bf 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mmc/mmc_ops.h
+ *  linux/drivers/mmc/core/mmc_ops.h
  *
  *  Copyright 2006-2007 Pierre Ossman
  *
@@ -22,6 +22,9 @@
 int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
 int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
 int mmc_send_status(struct mmc_card *card, u32 *status);
+int mmc_send_cid(struct mmc_host *host, u32 *cid);
+int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
+int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
 
 #endif
 
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 1240684..d1c1e0f5 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mmc/sd.c
+ *  linux/drivers/mmc/core/sd.c
  *
  *  Copyright (C) 2003-2004 Russell King, All Rights Reserved.
  *  SD support Copyright (C) 2004 Ian Molton, All Rights Reserved.
@@ -149,7 +149,7 @@
 		csd->write_partial = 0;
 		break;
 	default:
-		printk("%s: unrecognised CSD structure version %d\n",
+		printk(KERN_ERR "%s: unrecognised CSD structure version %d\n",
 			mmc_hostname(card->host), csd_struct);
 		return -EINVAL;
 	}
@@ -166,14 +166,12 @@
 	unsigned int scr_struct;
 	u32 resp[4];
 
-	BUG_ON(!mmc_card_sd(card));
-
 	resp[3] = card->raw_scr[1];
 	resp[2] = card->raw_scr[0];
 
 	scr_struct = UNSTUFF_BITS(resp, 60, 4);
 	if (scr_struct != 0) {
-		printk("%s: unrecognised SCR structure version %d\n",
+		printk(KERN_ERR "%s: unrecognised SCR structure version %d\n",
 			mmc_hostname(card->host), scr_struct);
 		return -EINVAL;
 	}
@@ -193,31 +191,38 @@
 	u8 *status;
 
 	if (card->scr.sda_vsn < SCR_SPEC_VER_1)
-		return MMC_ERR_NONE;
+		return 0;
 
 	if (!(card->csd.cmdclass & CCC_SWITCH)) {
 		printk(KERN_WARNING "%s: card lacks mandatory switch "
 			"function, performance might suffer.\n",
 			mmc_hostname(card->host));
-		return MMC_ERR_NONE;
+		return 0;
 	}
 
-	err = MMC_ERR_FAILED;
+	err = -EIO;
 
 	status = kmalloc(64, GFP_KERNEL);
 	if (!status) {
-		printk("%s: could not allocate a buffer for switch "
-		       "capabilities.\n",
-			mmc_hostname(card->host));
-		return err;
+		printk(KERN_ERR "%s: could not allocate a buffer for "
+			"switch capabilities.\n", mmc_hostname(card->host));
+		return -ENOMEM;
 	}
 
 	err = mmc_sd_switch(card, 0, 0, 1, status);
-	if (err != MMC_ERR_NONE) {
+	if (err) {
+		/*
+		 * We all hosts that cannot perform the command
+		 * to fail more gracefully
+		 */
+		if (err != -EINVAL)
+			goto out;
+
 		printk(KERN_WARNING "%s: problem reading switch "
 			"capabilities, performance might suffer.\n",
 			mmc_hostname(card->host));
-		err = MMC_ERR_NONE;
+		err = 0;
+
 		goto out;
 	}
 
@@ -239,29 +244,28 @@
 	u8 *status;
 
 	if (card->scr.sda_vsn < SCR_SPEC_VER_1)
-		return MMC_ERR_NONE;
+		return 0;
 
 	if (!(card->csd.cmdclass & CCC_SWITCH))
-		return MMC_ERR_NONE;
+		return 0;
 
 	if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED))
-		return MMC_ERR_NONE;
+		return 0;
 
 	if (card->sw_caps.hs_max_dtr == 0)
-		return MMC_ERR_NONE;
+		return 0;
 
-	err = MMC_ERR_FAILED;
+	err = -EIO;
 
 	status = kmalloc(64, GFP_KERNEL);
 	if (!status) {
-		printk("%s: could not allocate a buffer for switch "
-		       "capabilities.\n",
-			mmc_hostname(card->host));
-		return err;
+		printk(KERN_ERR "%s: could not allocate a buffer for "
+			"switch capabilities.\n", mmc_hostname(card->host));
+		return -ENOMEM;
 	}
 
 	err = mmc_sd_switch(card, 1, 0, 1, status);
-	if (err != MMC_ERR_NONE)
+	if (err)
 		goto out;
 
 	if ((status[16] & 0xF) != 1) {
@@ -294,7 +298,7 @@
 	unsigned int max_dtr;
 
 	BUG_ON(!host);
-	BUG_ON(!host->claimed);
+	WARN_ON(!host->claimed);
 
 	/*
 	 * Since we're changing the OCR value, we seem to
@@ -311,23 +315,37 @@
 	 * block-addressed SDHC cards.
 	 */
 	err = mmc_send_if_cond(host, ocr);
-	if (err == MMC_ERR_NONE)
+	if (!err)
 		ocr |= 1 << 30;
 
 	err = mmc_send_app_op_cond(host, ocr, NULL);
-	if (err != MMC_ERR_NONE)
+	if (err)
 		goto err;
 
 	/*
+	 * For SPI, enable CRC as appropriate.
+	 */
+	if (mmc_host_is_spi(host)) {
+		err = mmc_spi_set_crc(host, use_spi_crc);
+		if (err)
+			goto err;
+	}
+
+	/*
 	 * Fetch CID from card.
 	 */
-	err = mmc_all_send_cid(host, cid);
-	if (err != MMC_ERR_NONE)
+	if (mmc_host_is_spi(host))
+		err = mmc_send_cid(host, cid);
+	else
+		err = mmc_all_send_cid(host, cid);
+	if (err)
 		goto err;
 
 	if (oldcard) {
-		if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0)
+		if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) {
+			err = -ENOENT;
 			goto err;
+		}
 
 		card = oldcard;
 	} else {
@@ -335,32 +353,36 @@
 		 * Allocate card structure.
 		 */
 		card = mmc_alloc_card(host);
-		if (IS_ERR(card))
+		if (IS_ERR(card)) {
+			err = PTR_ERR(card);
 			goto err;
+		}
 
 		card->type = MMC_TYPE_SD;
 		memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
 	}
 
 	/*
-	 * Set card RCA.
+	 * For native busses:  get card RCA and quit open drain mode.
 	 */
-	err = mmc_send_relative_addr(host, &card->rca);
-	if (err != MMC_ERR_NONE)
-		goto free_card;
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_send_relative_addr(host, &card->rca);
+		if (err)
+			goto free_card;
 
-	mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+	}
 
 	if (!oldcard) {
 		/*
 		 * Fetch CSD from card.
 		 */
 		err = mmc_send_csd(card, card->raw_csd);
-		if (err != MMC_ERR_NONE)
+		if (err)
 			goto free_card;
 
 		err = mmc_decode_csd(card);
-		if (err < 0)
+		if (err)
 			goto free_card;
 
 		mmc_decode_cid(card);
@@ -369,16 +391,18 @@
 	/*
 	 * Select card, as all following commands rely on that.
 	 */
-	err = mmc_select_card(card);
-	if (err != MMC_ERR_NONE)
-		goto free_card;
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_select_card(card);
+		if (err)
+			goto free_card;
+	}
 
 	if (!oldcard) {
 		/*
 		 * Fetch SCR from card.
 		 */
 		err = mmc_app_send_scr(card, card->raw_scr);
-		if (err != MMC_ERR_NONE)
+		if (err)
 			goto free_card;
 
 		err = mmc_decode_scr(card);
@@ -389,7 +413,7 @@
 		 * Fetch switch information from card.
 		 */
 		err = mmc_read_switch(card);
-		if (err != MMC_ERR_NONE)
+		if (err)
 			goto free_card;
 	}
 
@@ -397,7 +421,7 @@
 	 * Attempt to change to high-speed (if supported)
 	 */
 	err = mmc_switch_hs(card);
-	if (err != MMC_ERR_NONE)
+	if (err)
 		goto free_card;
 
 	/*
@@ -420,7 +444,7 @@
 	if ((host->caps & MMC_CAP_4_BIT_DATA) &&
 		(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
 		err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
-		if (err != MMC_ERR_NONE)
+		if (err)
 			goto free_card;
 
 		mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
@@ -444,14 +468,14 @@
 	if (!oldcard)
 		host->card = card;
 
-	return MMC_ERR_NONE;
+	return 0;
 
 free_card:
 	if (!oldcard)
 		mmc_remove_card(card);
 err:
 
-	return MMC_ERR_FAILED;
+	return err;
 }
 
 /*
@@ -485,7 +509,7 @@
 
 	mmc_release_host(host);
 
-	if (err != MMC_ERR_NONE) {
+	if (err) {
 		mmc_sd_remove(host);
 
 		mmc_claim_host(host);
@@ -554,7 +578,8 @@
 	BUG_ON(!host->card);
 
 	mmc_claim_host(host);
-	mmc_deselect_cards(host);
+	if (!mmc_host_is_spi(host))
+		mmc_deselect_cards(host);
 	host->card->state &= ~MMC_STATE_HIGHSPEED;
 	mmc_release_host(host);
 }
@@ -573,14 +598,17 @@
 	BUG_ON(!host->card);
 
 	mmc_claim_host(host);
-
 	err = mmc_sd_init_card(host, host->ocr, host->card);
-	if (err != MMC_ERR_NONE) {
+	mmc_release_host(host);
+
+	if (err) {
 		mmc_sd_remove(host);
+
+		mmc_claim_host(host);
 		mmc_detach_bus(host);
+		mmc_release_host(host);
 	}
 
-	mmc_release_host(host);
 }
 
 #else
@@ -607,11 +635,22 @@
 	int err;
 
 	BUG_ON(!host);
-	BUG_ON(!host->claimed);
+	WARN_ON(!host->claimed);
 
 	mmc_attach_bus(host, &mmc_sd_ops);
 
 	/*
+	 * We need to get OCR a different way for SPI.
+	 */
+	if (mmc_host_is_spi(host)) {
+		mmc_go_idle(host);
+
+		err = mmc_spi_read_ocr(host, 0, &ocr);
+		if (err)
+			goto err;
+	}
+
+	/*
 	 * Sanity check the voltages that the card claims to
 	 * support.
 	 */
@@ -634,32 +673,37 @@
 	/*
 	 * Can we support the voltage(s) of the card(s)?
 	 */
-	if (!host->ocr)
+	if (!host->ocr) {
+		err = -EINVAL;
 		goto err;
+	}
 
 	/*
 	 * Detect and init the card.
 	 */
 	err = mmc_sd_init_card(host, host->ocr, NULL);
-	if (err != MMC_ERR_NONE)
+	if (err)
 		goto err;
 
 	mmc_release_host(host);
 
 	err = mmc_add_card(host->card);
 	if (err)
-		goto reclaim_host;
+		goto remove_card;
 
 	return 0;
 
-reclaim_host:
-	mmc_claim_host(host);
+remove_card:
 	mmc_remove_card(host->card);
 	host->card = NULL;
+	mmc_claim_host(host);
 err:
 	mmc_detach_bus(host);
 	mmc_release_host(host);
 
-	return 0;
+	printk(KERN_ERR "%s: error %d whilst initialising SD card\n",
+		mmc_hostname(host), err);
+
+	return err;
 }
 
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 9697ce5..ee4029a 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mmc/sd_ops.h
+ *  linux/drivers/mmc/core/sd_ops.h
  *
  *  Copyright 2006-2007 Pierre Ossman
  *
@@ -21,11 +21,40 @@
 #include "core.h"
 #include "sd_ops.h"
 
+static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
+{
+	int err;
+	struct mmc_command cmd;
+
+	BUG_ON(!host);
+	BUG_ON(card && (card->host != host));
+
+	cmd.opcode = MMC_APP_CMD;
+
+	if (card) {
+		cmd.arg = card->rca << 16;
+		cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+	} else {
+		cmd.arg = 0;
+		cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR;
+	}
+
+	err = mmc_wait_for_cmd(host, &cmd, 0);
+	if (err)
+		return err;
+
+	/* Check that card supported application commands */
+	if (!mmc_host_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD))
+		return -EOPNOTSUPP;
+
+	return 0;
+}
+
 /**
  *	mmc_wait_for_app_cmd - start an application command and wait for
  			       completion
  *	@host: MMC host to start command
- *	@rca: RCA to send MMC_APP_CMD to
+ *	@card: Card to send MMC_APP_CMD to
  *	@cmd: MMC command to start
  *	@retries: maximum number of retries
  *
@@ -44,7 +73,7 @@
 	BUG_ON(!cmd);
 	BUG_ON(retries < 0);
 
-	err = MMC_ERR_INVALID;
+	err = -EIO;
 
 	/*
 	 * We have to resend MMC_APP_CMD for each attempt so
@@ -54,8 +83,14 @@
 		memset(&mrq, 0, sizeof(struct mmc_request));
 
 		err = mmc_app_cmd(host, card);
-		if (err != MMC_ERR_NONE)
+		if (err) {
+			/* no point in retrying; no APP commands allowed */
+			if (mmc_host_is_spi(host)) {
+				if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
+					break;
+			}
 			continue;
+		}
 
 		memset(&mrq, 0, sizeof(struct mmc_request));
 
@@ -68,8 +103,14 @@
 		mmc_wait_for_req(host, &mrq);
 
 		err = cmd->error;
-		if (cmd->error == MMC_ERR_NONE)
+		if (!cmd->error)
 			break;
+
+		/* no point in retrying illegal APP commands */
+		if (mmc_host_is_spi(host)) {
+			if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND)
+				break;
+		}
 	}
 
 	return err;
@@ -77,35 +118,6 @@
 
 EXPORT_SYMBOL(mmc_wait_for_app_cmd);
 
-int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
-{
-	int err;
-	struct mmc_command cmd;
-
-	BUG_ON(!host);
-	BUG_ON(card && (card->host != host));
-
-	cmd.opcode = MMC_APP_CMD;
-
-	if (card) {
-		cmd.arg = card->rca << 16;
-		cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
-	} else {
-		cmd.arg = 0;
-		cmd.flags = MMC_RSP_R1 | MMC_CMD_BCR;
-	}
-
-	err = mmc_wait_for_cmd(host, &cmd, 0);
-	if (err != MMC_ERR_NONE)
-		return err;
-
-	/* Check that card supported application commands */
-	if (!(cmd.resp[0] & R1_APP_CMD))
-		return MMC_ERR_FAILED;
-
-	return MMC_ERR_NONE;
-}
-
 int mmc_app_set_bus_width(struct mmc_card *card, int width)
 {
 	int err;
@@ -127,14 +139,14 @@
 		cmd.arg = SD_BUS_WIDTH_4;
 		break;
 	default:
-		return MMC_ERR_INVALID;
+		return -EINVAL;
 	}
 
 	err = mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES);
-	if (err != MMC_ERR_NONE)
+	if (err)
 		return err;
 
-	return MMC_ERR_NONE;
+	return 0;
 }
 
 int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
@@ -147,23 +159,36 @@
 	memset(&cmd, 0, sizeof(struct mmc_command));
 
 	cmd.opcode = SD_APP_OP_COND;
-	cmd.arg = ocr;
-	cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
+	if (mmc_host_is_spi(host))
+		cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */
+	else
+		cmd.arg = ocr;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
 
 	for (i = 100; i; i--) {
 		err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES);
-		if (err != MMC_ERR_NONE)
+		if (err)
 			break;
 
-		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
+		/* if we're just probing, do a single pass */
+		if (ocr == 0)
 			break;
 
-		err = MMC_ERR_TIMEOUT;
+		/* otherwise wait until reset completes */
+		if (mmc_host_is_spi(host)) {
+			if (!(cmd.resp[0] & R1_SPI_IDLE))
+				break;
+		} else {
+			if (cmd.resp[0] & MMC_CARD_BUSY)
+				break;
+		}
+
+		err = -ETIMEDOUT;
 
 		mmc_delay(10);
 	}
 
-	if (rocr)
+	if (rocr && !mmc_host_is_spi(host))
 		*rocr = cmd.resp[0];
 
 	return err;
@@ -174,6 +199,7 @@
 	struct mmc_command cmd;
 	int err;
 	static const u8 test_pattern = 0xAA;
+	u8 result_pattern;
 
 	/*
 	 * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
@@ -182,16 +208,21 @@
 	 */
 	cmd.opcode = SD_SEND_IF_COND;
 	cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
-	cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
+	cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;
 
 	err = mmc_wait_for_cmd(host, &cmd, 0);
-	if (err != MMC_ERR_NONE)
+	if (err)
 		return err;
 
-	if ((cmd.resp[0] & 0xFF) != test_pattern)
-		return MMC_ERR_FAILED;
+	if (mmc_host_is_spi(host))
+		result_pattern = cmd.resp[1] & 0xFF;
+	else
+		result_pattern = cmd.resp[0] & 0xFF;
 
-	return MMC_ERR_NONE;
+	if (result_pattern != test_pattern)
+		return -EIO;
+
+	return 0;
 }
 
 int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
@@ -209,12 +240,12 @@
 	cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
 
 	err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
-	if (err != MMC_ERR_NONE)
+	if (err)
 		return err;
 
 	*rca = cmd.resp[0] >> 16;
 
-	return MMC_ERR_NONE;
+	return 0;
 }
 
 int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
@@ -229,8 +260,10 @@
 	BUG_ON(!card->host);
 	BUG_ON(!scr);
 
+	/* NOTE: caller guarantees scr is heap-allocated */
+
 	err = mmc_app_cmd(card->host, card);
-	if (err != MMC_ERR_NONE)
+	if (err)
 		return err;
 
 	memset(&mrq, 0, sizeof(struct mmc_request));
@@ -242,7 +275,7 @@
 
 	cmd.opcode = SD_APP_SEND_SCR;
 	cmd.arg = 0;
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
 
 	data.blksz = 8;
 	data.blocks = 1;
@@ -252,19 +285,19 @@
 
 	sg_init_one(&sg, scr, 8);
 
-	mmc_set_data_timeout(&data, card, 0);
+	mmc_set_data_timeout(&data, card);
 
 	mmc_wait_for_req(card->host, &mrq);
 
-	if (cmd.error != MMC_ERR_NONE)
+	if (cmd.error)
 		return cmd.error;
-	if (data.error != MMC_ERR_NONE)
+	if (data.error)
 		return data.error;
 
 	scr[0] = ntohl(scr[0]);
 	scr[1] = ntohl(scr[1]);
 
-	return MMC_ERR_NONE;
+	return 0;
 }
 
 int mmc_sd_switch(struct mmc_card *card, int mode, int group,
@@ -278,6 +311,8 @@
 	BUG_ON(!card);
 	BUG_ON(!card->host);
 
+	/* NOTE: caller guarantees resp is heap-allocated */
+
 	mode = !!mode;
 	value &= 0xF;
 
@@ -292,7 +327,7 @@
 	cmd.arg = mode << 31 | 0x00FFFFFF;
 	cmd.arg &= ~(0xF << (group * 4));
 	cmd.arg |= value << (group * 4);
-	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+	cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
 
 	data.blksz = 64;
 	data.blocks = 1;
@@ -302,15 +337,15 @@
 
 	sg_init_one(&sg, resp, 64);
 
-	mmc_set_data_timeout(&data, card, 0);
+	mmc_set_data_timeout(&data, card);
 
 	mmc_wait_for_req(card->host, &mrq);
 
-	if (cmd.error != MMC_ERR_NONE)
+	if (cmd.error)
 		return cmd.error;
-	if (data.error != MMC_ERR_NONE)
+	if (data.error)
 		return data.error;
 
-	return MMC_ERR_NONE;
+	return 0;
 }
 
diff --git a/drivers/mmc/core/sd_ops.h b/drivers/mmc/core/sd_ops.h
index 1240fdd..9742d8a 100644
--- a/drivers/mmc/core/sd_ops.h
+++ b/drivers/mmc/core/sd_ops.h
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mmc/sd_ops.h
+ *  linux/drivers/mmc/core/sd_ops.h
  *
  *  Copyright 2006-2007 Pierre Ossman
  *
@@ -12,7 +12,6 @@
 #ifndef _MMC_SD_OPS_H
 #define _MMC_SD_OPS_H
 
-int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card);
 int mmc_app_set_bus_width(struct mmc_card *card, int width);
 int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
 int mmc_send_if_cond(struct mmc_host *host, u32 ocr);
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
new file mode 100644
index 0000000..87a50f4
--- /dev/null
+++ b/drivers/mmc/core/sdio.c
@@ -0,0 +1,395 @@
+/*
+ *  linux/drivers/mmc/sdio.c
+ *
+ *  Copyright 2006-2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/err.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "core.h"
+#include "bus.h"
+#include "sdio_bus.h"
+#include "mmc_ops.h"
+#include "sd_ops.h"
+#include "sdio_ops.h"
+#include "sdio_cis.h"
+
+static int sdio_read_fbr(struct sdio_func *func)
+{
+	int ret;
+	unsigned char data;
+
+	ret = mmc_io_rw_direct(func->card, 0, 0,
+		SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF, 0, &data);
+	if (ret)
+		goto out;
+
+	data &= 0x0f;
+
+	if (data == 0x0f) {
+		ret = mmc_io_rw_direct(func->card, 0, 0,
+			SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF_EXT, 0, &data);
+		if (ret)
+			goto out;
+	}
+
+	func->class = data;
+
+out:
+	return ret;
+}
+
+static int sdio_init_func(struct mmc_card *card, unsigned int fn)
+{
+	int ret;
+	struct sdio_func *func;
+
+	BUG_ON(fn > SDIO_MAX_FUNCS);
+
+	func = sdio_alloc_func(card);
+	if (IS_ERR(func))
+		return PTR_ERR(func);
+
+	func->num = fn;
+
+	ret = sdio_read_fbr(func);
+	if (ret)
+		goto fail;
+
+	ret = sdio_read_func_cis(func);
+	if (ret)
+		goto fail;
+
+	card->sdio_func[fn - 1] = func;
+
+	return 0;
+
+fail:
+	/*
+	 * It is okay to remove the function here even though we hold
+	 * the host lock as we haven't registered the device yet.
+	 */
+	sdio_remove_func(func);
+	return ret;
+}
+
+static int sdio_read_cccr(struct mmc_card *card)
+{
+	int ret;
+	int cccr_vsn;
+	unsigned char data;
+
+	memset(&card->cccr, 0, sizeof(struct sdio_cccr));
+
+	ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CCCR, 0, &data);
+	if (ret)
+		goto out;
+
+	cccr_vsn = data & 0x0f;
+
+	if (cccr_vsn > SDIO_CCCR_REV_1_20) {
+		printk(KERN_ERR "%s: unrecognised CCCR structure version %d\n",
+			mmc_hostname(card->host), cccr_vsn);
+		return -EINVAL;
+	}
+
+	card->cccr.sdio_vsn = (data & 0xf0) >> 4;
+
+	ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_CAPS, 0, &data);
+	if (ret)
+		goto out;
+
+	if (data & SDIO_CCCR_CAP_SMB)
+		card->cccr.multi_block = 1;
+	if (data & SDIO_CCCR_CAP_LSC)
+		card->cccr.low_speed = 1;
+	if (data & SDIO_CCCR_CAP_4BLS)
+		card->cccr.wide_bus = 1;
+
+	if (cccr_vsn >= SDIO_CCCR_REV_1_10) {
+		ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_POWER, 0, &data);
+		if (ret)
+			goto out;
+
+		if (data & SDIO_POWER_SMPC)
+			card->cccr.high_power = 1;
+	}
+
+	if (cccr_vsn >= SDIO_CCCR_REV_1_20) {
+		ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data);
+		if (ret)
+			goto out;
+
+		if (data & SDIO_SPEED_SHS)
+			card->cccr.high_speed = 1;
+	}
+
+out:
+	return ret;
+}
+
+static int sdio_enable_wide(struct mmc_card *card)
+{
+	int ret;
+	u8 ctrl;
+
+	if (!(card->host->caps & MMC_CAP_4_BIT_DATA))
+		return 0;
+
+	if (card->cccr.low_speed && !card->cccr.wide_bus)
+		return 0;
+
+	ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl);
+	if (ret)
+		return ret;
+
+	ctrl |= SDIO_BUS_WIDTH_4BIT;
+
+	ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL);
+	if (ret)
+		return ret;
+
+	mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+
+	return 0;
+}
+
+/*
+ * Host is being removed. Free up the current card.
+ */
+static void mmc_sdio_remove(struct mmc_host *host)
+{
+	int i;
+
+	BUG_ON(!host);
+	BUG_ON(!host->card);
+
+	for (i = 0;i < host->card->sdio_funcs;i++) {
+		if (host->card->sdio_func[i]) {
+			sdio_remove_func(host->card->sdio_func[i]);
+			host->card->sdio_func[i] = NULL;
+		}
+	}
+
+	mmc_remove_card(host->card);
+	host->card = NULL;
+}
+
+/*
+ * Card detection callback from host.
+ */
+static void mmc_sdio_detect(struct mmc_host *host)
+{
+	int err;
+
+	BUG_ON(!host);
+	BUG_ON(!host->card);
+
+	mmc_claim_host(host);
+
+	/*
+	 * Just check if our card has been removed.
+	 */
+	err = mmc_select_card(host->card);
+
+	mmc_release_host(host);
+
+	if (err) {
+		mmc_sdio_remove(host);
+
+		mmc_claim_host(host);
+		mmc_detach_bus(host);
+		mmc_release_host(host);
+	}
+}
+
+
+static const struct mmc_bus_ops mmc_sdio_ops = {
+	.remove = mmc_sdio_remove,
+	.detect = mmc_sdio_detect,
+};
+
+
+/*
+ * Starting point for SDIO card init.
+ */
+int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
+{
+	int err;
+	int i, funcs;
+	struct mmc_card *card;
+
+	BUG_ON(!host);
+	WARN_ON(!host->claimed);
+
+	mmc_attach_bus(host, &mmc_sdio_ops);
+
+	/*
+	 * Sanity check the voltages that the card claims to
+	 * support.
+	 */
+	if (ocr & 0x7F) {
+		printk(KERN_WARNING "%s: card claims to support voltages "
+		       "below the defined range. These will be ignored.\n",
+		       mmc_hostname(host));
+		ocr &= ~0x7F;
+	}
+
+	if (ocr & MMC_VDD_165_195) {
+		printk(KERN_WARNING "%s: SDIO card claims to support the "
+		       "incompletely defined 'low voltage range'. This "
+		       "will be ignored.\n", mmc_hostname(host));
+		ocr &= ~MMC_VDD_165_195;
+	}
+
+	host->ocr = mmc_select_voltage(host, ocr);
+
+	/*
+	 * Can we support the voltage(s) of the card(s)?
+	 */
+	if (!host->ocr) {
+		err = -EINVAL;
+		goto err;
+	}
+
+	/*
+	 * Inform the card of the voltage
+	 */
+	err = mmc_send_io_op_cond(host, host->ocr, &ocr);
+	if (err)
+		goto err;
+
+	/*
+	 * For SPI, enable CRC as appropriate.
+	 */
+	if (mmc_host_is_spi(host)) {
+		err = mmc_spi_set_crc(host, use_spi_crc);
+		if (err)
+			goto err;
+	}
+
+	/*
+	 * The number of functions on the card is encoded inside
+	 * the ocr.
+	 */
+	funcs = (ocr & 0x70000000) >> 28;
+
+	/*
+	 * Allocate card structure.
+	 */
+	card = mmc_alloc_card(host);
+	if (IS_ERR(card)) {
+		err = PTR_ERR(card);
+		goto err;
+	}
+
+	card->type = MMC_TYPE_SDIO;
+	card->sdio_funcs = funcs;
+
+	host->card = card;
+
+	/*
+	 * For native busses:  set card RCA and quit open drain mode.
+	 */
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_send_relative_addr(host, &card->rca);
+		if (err)
+			goto remove;
+
+		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+	}
+
+	/*
+	 * Select card, as all following commands rely on that.
+	 */
+	if (!mmc_host_is_spi(host)) {
+		err = mmc_select_card(card);
+		if (err)
+			goto remove;
+	}
+
+	/*
+	 * Read the common registers.
+	 */
+	err = sdio_read_cccr(card);
+	if (err)
+		goto remove;
+
+	/*
+	 * Read the common CIS tuples.
+	 */
+	err = sdio_read_common_cis(card);
+	if (err)
+		goto remove;
+
+	/*
+	 * No support for high-speed yet, so just set
+	 * the card's maximum speed.
+	 */
+	mmc_set_clock(host, card->cis.max_dtr);
+
+	/*
+	 * Switch to wider bus (if supported).
+	 */
+	err = sdio_enable_wide(card);
+	if (err)
+		goto remove;
+
+	/*
+	 * Initialize (but don't add) all present functions.
+	 */
+	for (i = 0;i < funcs;i++) {
+		err = sdio_init_func(host->card, i + 1);
+		if (err)
+			goto remove;
+	}
+
+	mmc_release_host(host);
+
+	/*
+	 * First add the card to the driver model...
+	 */
+	err = mmc_add_card(host->card);
+	if (err)
+		goto remove_added;
+
+	/*
+	 * ...then the SDIO functions.
+	 */
+	for (i = 0;i < funcs;i++) {
+		err = sdio_add_func(host->card->sdio_func[i]);
+		if (err)
+			goto remove_added;
+	}
+
+	return 0;
+
+
+remove_added:
+	/* Remove without lock if the device has been added. */
+	mmc_sdio_remove(host);
+	mmc_claim_host(host);
+remove:
+	/* And with lock if it hasn't been added. */
+	if (host->card)
+		mmc_sdio_remove(host);
+err:
+	mmc_detach_bus(host);
+	mmc_release_host(host);
+
+	printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n",
+		mmc_hostname(host), err);
+
+	return err;
+}
+
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
new file mode 100644
index 0000000..0713a8c
--- /dev/null
+++ b/drivers/mmc/core/sdio_bus.c
@@ -0,0 +1,270 @@
+/*
+ *  linux/drivers/mmc/core/sdio_bus.c
+ *
+ *  Copyright 2007 Pierre Ossman
+ *
+ * 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.
+ *
+ * SDIO function driver model
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "sdio_cis.h"
+#include "sdio_bus.h"
+
+#define dev_to_sdio_func(d)	container_of(d, struct sdio_func, dev)
+#define to_sdio_driver(d)      container_of(d, struct sdio_driver, drv)
+
+/* show configuration fields */
+#define sdio_config_attr(field, format_string)				\
+static ssize_t								\
+field##_show(struct device *dev, struct device_attribute *attr, char *buf)				\
+{									\
+	struct sdio_func *func;						\
+									\
+	func = dev_to_sdio_func (dev);					\
+	return sprintf (buf, format_string, func->field);		\
+}
+
+sdio_config_attr(class, "0x%02x\n");
+sdio_config_attr(vendor, "0x%04x\n");
+sdio_config_attr(device, "0x%04x\n");
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct sdio_func *func = dev_to_sdio_func (dev);
+
+	return sprintf(buf, "sdio:c%02Xv%04Xd%04X\n",
+			func->class, func->vendor, func->device);
+}
+
+static struct device_attribute sdio_dev_attrs[] = {
+	__ATTR_RO(class),
+	__ATTR_RO(vendor),
+	__ATTR_RO(device),
+	__ATTR_RO(modalias),
+	__ATTR_NULL,
+};
+
+static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,
+	const struct sdio_device_id *id)
+{
+	if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class)
+		return NULL;
+	if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor)
+		return NULL;
+	if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device)
+		return NULL;
+	return id;
+}
+
+static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,
+	struct sdio_driver *sdrv)
+{
+	const struct sdio_device_id *ids;
+
+	ids = sdrv->id_table;
+
+	if (ids) {
+		while (ids->class || ids->vendor || ids->device) {
+			if (sdio_match_one(func, ids))
+				return ids;
+			ids++;
+		}
+	}
+
+	return NULL;
+}
+
+static int sdio_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct sdio_func *func = dev_to_sdio_func(dev);
+	struct sdio_driver *sdrv = to_sdio_driver(drv);
+
+	if (sdio_match_device(func, sdrv))
+		return 1;
+
+	return 0;
+}
+
+static int
+sdio_bus_uevent(struct device *dev, char **envp, int num_envp, char *buf,
+		int buf_size)
+{
+	struct sdio_func *func = dev_to_sdio_func(dev);
+	int i = 0, length = 0;
+
+	if (add_uevent_var(envp, num_envp, &i,
+			buf, buf_size, &length,
+			"SDIO_CLASS=%02X", func->class))
+		return -ENOMEM;
+
+	if (add_uevent_var(envp, num_envp, &i,
+			buf, buf_size, &length,
+			"SDIO_ID=%04X:%04X", func->vendor, func->device))
+		return -ENOMEM;
+
+	if (add_uevent_var(envp, num_envp, &i,
+			buf, buf_size, &length,
+			"MODALIAS=sdio:c%02Xv%04Xd%04X",
+			func->class, func->vendor, func->device))
+		return -ENOMEM;
+
+	envp[i] = NULL;
+
+	return 0;
+}
+
+static int sdio_bus_probe(struct device *dev)
+{
+	struct sdio_driver *drv = to_sdio_driver(dev->driver);
+	struct sdio_func *func = dev_to_sdio_func(dev);
+	const struct sdio_device_id *id;
+	int ret;
+
+	id = sdio_match_device(func, drv);
+	if (!id)
+		return -ENODEV;
+
+	/* Set the default block size so the driver is sure it's something
+	 * sensible. */
+	sdio_claim_host(func);
+	ret = sdio_set_block_size(func, 0);
+	sdio_release_host(func);
+	if (ret)
+		return ret;
+
+	return drv->probe(func, id);
+}
+
+static int sdio_bus_remove(struct device *dev)
+{
+	struct sdio_driver *drv = to_sdio_driver(dev->driver);
+	struct sdio_func *func = dev_to_sdio_func(dev);
+
+	drv->remove(func);
+
+	if (func->irq_handler) {
+		printk(KERN_WARNING "WARNING: driver %s did not remove "
+			"its interrupt handler!\n", drv->name);
+		sdio_claim_host(func);
+		sdio_release_irq(func);
+		sdio_release_host(func);
+	}
+
+	return 0;
+}
+
+static struct bus_type sdio_bus_type = {
+	.name		= "sdio",
+	.dev_attrs	= sdio_dev_attrs,
+	.match		= sdio_bus_match,
+	.uevent		= sdio_bus_uevent,
+	.probe		= sdio_bus_probe,
+	.remove		= sdio_bus_remove,
+};
+
+int sdio_register_bus(void)
+{
+	return bus_register(&sdio_bus_type);
+}
+
+void sdio_unregister_bus(void)
+{
+	bus_unregister(&sdio_bus_type);
+}
+
+/**
+ *	sdio_register_driver - register a function driver
+ *	@drv: SDIO function driver
+ */
+int sdio_register_driver(struct sdio_driver *drv)
+{
+	drv->drv.name = drv->name;
+	drv->drv.bus = &sdio_bus_type;
+	return driver_register(&drv->drv);
+}
+EXPORT_SYMBOL_GPL(sdio_register_driver);
+
+/**
+ *	sdio_unregister_driver - unregister a function driver
+ *	@drv: SDIO function driver
+ */
+void sdio_unregister_driver(struct sdio_driver *drv)
+{
+	drv->drv.bus = &sdio_bus_type;
+	driver_unregister(&drv->drv);
+}
+EXPORT_SYMBOL_GPL(sdio_unregister_driver);
+
+static void sdio_release_func(struct device *dev)
+{
+	struct sdio_func *func = dev_to_sdio_func(dev);
+
+	sdio_free_func_cis(func);
+
+	if (func->info)
+		kfree(func->info);
+
+	kfree(func);
+}
+
+/*
+ * Allocate and initialise a new SDIO function structure.
+ */
+struct sdio_func *sdio_alloc_func(struct mmc_card *card)
+{
+	struct sdio_func *func;
+
+	func = kzalloc(sizeof(struct sdio_func), GFP_KERNEL);
+	if (!func)
+		return ERR_PTR(-ENOMEM);
+
+	func->card = card;
+
+	device_initialize(&func->dev);
+
+	func->dev.parent = &card->dev;
+	func->dev.bus = &sdio_bus_type;
+	func->dev.release = sdio_release_func;
+
+	return func;
+}
+
+/*
+ * Register a new SDIO function with the driver model.
+ */
+int sdio_add_func(struct sdio_func *func)
+{
+	int ret;
+
+	snprintf(func->dev.bus_id, sizeof(func->dev.bus_id),
+		 "%s:%d", mmc_card_id(func->card), func->num);
+
+	ret = device_add(&func->dev);
+	if (ret == 0)
+		sdio_func_set_present(func);
+
+	return ret;
+}
+
+/*
+ * Unregister a SDIO function with the driver model, and
+ * (eventually) free it.
+ */
+void sdio_remove_func(struct sdio_func *func)
+{
+	if (sdio_func_present(func))
+		device_del(&func->dev);
+
+	put_device(&func->dev);
+}
+
diff --git a/drivers/mmc/core/sdio_bus.h b/drivers/mmc/core/sdio_bus.h
new file mode 100644
index 0000000..567a768
--- /dev/null
+++ b/drivers/mmc/core/sdio_bus.h
@@ -0,0 +1,22 @@
+/*
+ *  linux/drivers/mmc/core/sdio_bus.h
+ *
+ *  Copyright 2007 Pierre Ossman
+ *
+ * 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.
+ */
+#ifndef _MMC_CORE_SDIO_BUS_H
+#define _MMC_CORE_SDIO_BUS_H
+
+struct sdio_func *sdio_alloc_func(struct mmc_card *card);
+int sdio_add_func(struct sdio_func *func);
+void sdio_remove_func(struct sdio_func *func);
+
+int sdio_register_bus(void);
+void sdio_unregister_bus(void);
+
+#endif
+
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
new file mode 100644
index 0000000..d5e51b1
--- /dev/null
+++ b/drivers/mmc/core/sdio_cis.c
@@ -0,0 +1,346 @@
+/*
+ * linux/drivers/mmc/core/sdio_cis.c
+ *
+ * Author:	Nicolas Pitre
+ * Created:	June 11, 2007
+ * Copyright:	MontaVista Software Inc.
+ *
+ * Copyright 2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/kernel.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "sdio_cis.h"
+#include "sdio_ops.h"
+
+static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
+			 const unsigned char *buf, unsigned size)
+{
+	unsigned i, nr_strings;
+	char **buffer, *string;
+
+	buf += 2;
+	size -= 2;
+
+	nr_strings = 0;
+	for (i = 0; i < size; i++) {
+		if (buf[i] == 0xff)
+			break;
+		if (buf[i] == 0)
+			nr_strings++;
+	}
+
+	if (buf[i-1] != '\0') {
+		printk(KERN_WARNING "SDIO: ignoring broken CISTPL_VERS_1\n");
+		return 0;
+	}
+
+	size = i;
+
+	buffer = kzalloc(sizeof(char*) * nr_strings + size, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	string = (char*)(buffer + nr_strings);
+
+	for (i = 0; i < nr_strings; i++) {
+		buffer[i] = string;
+		strcpy(string, buf);
+		string += strlen(string) + 1;
+		buf += strlen(buf) + 1;
+	}
+
+	if (func) {
+		func->num_info = nr_strings;
+		func->info = (const char**)buffer;
+	} else {
+		card->num_info = nr_strings;
+		card->info = (const char**)buffer;
+	}
+
+	return 0;
+}
+
+static int cistpl_manfid(struct mmc_card *card, struct sdio_func *func,
+			 const unsigned char *buf, unsigned size)
+{
+	unsigned int vendor, device;
+
+	/* TPLMID_MANF */
+	vendor = buf[0] | (buf[1] << 8);
+
+	/* TPLMID_CARD */
+	device = buf[2] | (buf[3] << 8);
+
+	if (func) {
+		func->vendor = vendor;
+		func->device = device;
+	} else {
+		card->cis.vendor = vendor;
+		card->cis.device = device;
+	}
+
+	return 0;
+}
+
+static const unsigned char speed_val[16] =
+	{ 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 };
+static const unsigned int speed_unit[8] =
+	{ 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 };
+
+static int cistpl_funce_common(struct mmc_card *card,
+			       const unsigned char *buf, unsigned size)
+{
+	if (size < 0x04 || buf[0] != 0)
+		return -EINVAL;
+
+	/* TPLFE_FN0_BLK_SIZE */
+	card->cis.blksize = buf[1] | (buf[2] << 8);
+
+	/* TPLFE_MAX_TRAN_SPEED */
+	card->cis.max_dtr = speed_val[(buf[3] >> 3) & 15] *
+			    speed_unit[buf[3] & 7];
+
+	return 0;
+}
+
+static int cistpl_funce_func(struct sdio_func *func,
+			     const unsigned char *buf, unsigned size)
+{
+	unsigned vsn;
+	unsigned min_size;
+
+	vsn = func->card->cccr.sdio_vsn;
+	min_size = (vsn == SDIO_SDIO_REV_1_00) ? 28 : 42;
+
+	if (size < min_size || buf[0] != 1)
+		return -EINVAL;
+
+	/* TPLFE_MAX_BLK_SIZE */
+	func->max_blksize = buf[12] | (buf[13] << 8);
+
+	return 0;
+}
+
+static int cistpl_funce(struct mmc_card *card, struct sdio_func *func,
+			const unsigned char *buf, unsigned size)
+{
+	int ret;
+
+	/*
+	 * There should be two versions of the CISTPL_FUNCE tuple,
+	 * one for the common CIS (function 0) and a version used by
+	 * the individual function's CIS (1-7). Yet, the later has a
+	 * different length depending on the SDIO spec version.
+	 */
+	if (func)
+		ret = cistpl_funce_func(func, buf, size);
+	else
+		ret = cistpl_funce_common(card, buf, size);
+
+	if (ret) {
+		printk(KERN_ERR "%s: bad CISTPL_FUNCE size %u "
+		       "type %u\n", mmc_hostname(card->host), size, buf[0]);
+		return ret;
+	}
+
+	return 0;
+}
+
+typedef int (tpl_parse_t)(struct mmc_card *, struct sdio_func *,
+			   const unsigned char *, unsigned);
+
+struct cis_tpl {
+	unsigned char code;
+	unsigned char min_size;
+	tpl_parse_t *parse;
+};
+
+static const struct cis_tpl cis_tpl_list[] = {
+	{	0x15,	3,	cistpl_vers_1		},
+	{	0x20,	4,	cistpl_manfid		},
+	{	0x21,	2,	/* cistpl_funcid */	},
+	{	0x22,	0,	cistpl_funce		},
+};
+
+static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
+{
+	int ret;
+	struct sdio_func_tuple *this, **prev;
+	unsigned i, ptr = 0;
+
+	/*
+	 * Note that this works for the common CIS (function number 0) as
+	 * well as a function's CIS * since SDIO_CCCR_CIS and SDIO_FBR_CIS
+	 * have the same offset.
+	 */
+	for (i = 0; i < 3; i++) {
+		unsigned char x, fn;
+
+		if (func)
+			fn = func->num;
+		else
+			fn = 0;
+
+		ret = mmc_io_rw_direct(card, 0, 0,
+			SDIO_FBR_BASE(fn) + SDIO_FBR_CIS + i, 0, &x);
+		if (ret)
+			return ret;
+		ptr |= x << (i * 8);
+	}
+
+	if (func)
+		prev = &func->tuples;
+	else
+		prev = &card->tuples;
+
+	BUG_ON(*prev);
+
+	do {
+		unsigned char tpl_code, tpl_link;
+
+		ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_code);
+		if (ret)
+			break;
+
+		/* 0xff means we're done */
+		if (tpl_code == 0xff)
+			break;
+
+		ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link);
+		if (ret)
+			break;
+
+		this = kmalloc(sizeof(*this) + tpl_link, GFP_KERNEL);
+		if (!this)
+			return -ENOMEM;
+
+		for (i = 0; i < tpl_link; i++) {
+			ret = mmc_io_rw_direct(card, 0, 0,
+					       ptr + i, 0, &this->data[i]);
+			if (ret)
+				break;
+		}
+		if (ret) {
+			kfree(this);
+			break;
+		}
+
+		for (i = 0; i < ARRAY_SIZE(cis_tpl_list); i++)
+			if (cis_tpl_list[i].code == tpl_code)
+				break;
+		if (i >= ARRAY_SIZE(cis_tpl_list)) {
+			/* this tuple is unknown to the core */
+			this->next = NULL;
+			this->code = tpl_code;
+			this->size = tpl_link;
+			*prev = this;
+			prev = &this->next;
+			printk(KERN_DEBUG
+			       "%s: queuing CIS tuple 0x%02x length %u\n",
+			       mmc_hostname(card->host), tpl_code, tpl_link);
+		} else {
+			const struct cis_tpl *tpl = cis_tpl_list + i;
+			if (tpl_link < tpl->min_size) {
+				printk(KERN_ERR
+				       "%s: bad CIS tuple 0x%02x (length = %u, expected >= %u)\n",
+				       mmc_hostname(card->host),
+				       tpl_code, tpl_link, tpl->min_size);
+				ret = -EINVAL;
+			} else if (tpl->parse) {
+				ret = tpl->parse(card, func,
+						 this->data, tpl_link);
+			}
+			kfree(this);
+		}
+
+		ptr += tpl_link;
+	} while (!ret);
+
+	/*
+	 * Link in all unknown tuples found in the common CIS so that
+	 * drivers don't have to go digging in two places.
+	 */
+	if (func)
+		*prev = card->tuples;
+
+	return ret;
+}
+
+int sdio_read_common_cis(struct mmc_card *card)
+{
+	return sdio_read_cis(card, NULL);
+}
+
+void sdio_free_common_cis(struct mmc_card *card)
+{
+	struct sdio_func_tuple *tuple, *victim;
+
+	tuple = card->tuples;
+
+	while (tuple) {
+		victim = tuple;
+		tuple = tuple->next;
+		kfree(victim);
+	}
+
+	card->tuples = NULL;
+}
+
+int sdio_read_func_cis(struct sdio_func *func)
+{
+	int ret;
+
+	ret = sdio_read_cis(func->card, func);
+	if (ret)
+		return ret;
+
+	/*
+	 * Since we've linked to tuples in the card structure,
+	 * we must make sure we have a reference to it.
+	 */
+	get_device(&func->card->dev);
+
+	/*
+	 * Vendor/device id is optional for function CIS, so
+	 * copy it from the card structure as needed.
+	 */
+	if (func->vendor == 0) {
+		func->vendor = func->card->cis.vendor;
+		func->device = func->card->cis.device;
+	}
+
+	return 0;
+}
+
+void sdio_free_func_cis(struct sdio_func *func)
+{
+	struct sdio_func_tuple *tuple, *victim;
+
+	tuple = func->tuples;
+
+	while (tuple && tuple != func->card->tuples) {
+		victim = tuple;
+		tuple = tuple->next;
+		kfree(victim);
+	}
+
+	func->tuples = NULL;
+
+	/*
+	 * We have now removed the link to the tuples in the
+	 * card structure, so remove the reference.
+	 */
+	put_device(&func->card->dev);
+}
+
diff --git a/drivers/mmc/core/sdio_cis.h b/drivers/mmc/core/sdio_cis.h
new file mode 100644
index 0000000..4d903c2
--- /dev/null
+++ b/drivers/mmc/core/sdio_cis.h
@@ -0,0 +1,23 @@
+/*
+ * linux/drivers/mmc/core/sdio_cis.h
+ *
+ * Author:	Nicolas Pitre
+ * Created:	June 11, 2007
+ * Copyright:	MontaVista Software Inc.
+ *
+ * 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.
+ */
+
+#ifndef _MMC_SDIO_CIS_H
+#define _MMC_SDIO_CIS_H
+
+int sdio_read_common_cis(struct mmc_card *card);
+void sdio_free_common_cis(struct mmc_card *card);
+
+int sdio_read_func_cis(struct sdio_func *func);
+void sdio_free_func_cis(struct sdio_func *func);
+
+#endif
diff --git a/drivers/mmc/core/sdio_io.c b/drivers/mmc/core/sdio_io.c
new file mode 100644
index 0000000..625b92c
--- /dev/null
+++ b/drivers/mmc/core/sdio_io.c
@@ -0,0 +1,548 @@
+/*
+ *  linux/drivers/mmc/core/sdio_io.c
+ *
+ *  Copyright 2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "sdio_ops.h"
+
+/**
+ *	sdio_claim_host - exclusively claim a bus for a certain SDIO function
+ *	@func: SDIO function that will be accessed
+ *
+ *	Claim a bus for a set of operations. The SDIO function given
+ *	is used to figure out which bus is relevant.
+ */
+void sdio_claim_host(struct sdio_func *func)
+{
+	BUG_ON(!func);
+	BUG_ON(!func->card);
+
+	mmc_claim_host(func->card->host);
+}
+EXPORT_SYMBOL_GPL(sdio_claim_host);
+
+/**
+ *	sdio_release_host - release a bus for a certain SDIO function
+ *	@func: SDIO function that was accessed
+ *
+ *	Release a bus, allowing others to claim the bus for their
+ *	operations.
+ */
+void sdio_release_host(struct sdio_func *func)
+{
+	BUG_ON(!func);
+	BUG_ON(!func->card);
+
+	mmc_release_host(func->card->host);
+}
+EXPORT_SYMBOL_GPL(sdio_release_host);
+
+/**
+ *	sdio_enable_func - enables a SDIO function for usage
+ *	@func: SDIO function to enable
+ *
+ *	Powers up and activates a SDIO function so that register
+ *	access is possible.
+ */
+int sdio_enable_func(struct sdio_func *func)
+{
+	int ret;
+	unsigned char reg;
+	unsigned long timeout;
+
+	BUG_ON(!func);
+	BUG_ON(!func->card);
+
+	pr_debug("SDIO: Enabling device %s...\n", sdio_func_id(func));
+
+	ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IOEx, 0, &reg);
+	if (ret)
+		goto err;
+
+	reg |= 1 << func->num;
+
+	ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IOEx, reg, NULL);
+	if (ret)
+		goto err;
+
+	/*
+	 * FIXME: This should timeout based on information in the CIS,
+	 * but we don't have card to parse that yet.
+	 */
+	timeout = jiffies + HZ;
+
+	while (1) {
+		ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IORx, 0, &reg);
+		if (ret)
+			goto err;
+		if (reg & (1 << func->num))
+			break;
+		ret = -ETIME;
+		if (time_after(jiffies, timeout))
+			goto err;
+	}
+
+	pr_debug("SDIO: Enabled device %s\n", sdio_func_id(func));
+
+	return 0;
+
+err:
+	pr_debug("SDIO: Failed to enable device %s\n", sdio_func_id(func));
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sdio_enable_func);
+
+/**
+ *	sdio_disable_func - disable a SDIO function
+ *	@func: SDIO function to disable
+ *
+ *	Powers down and deactivates a SDIO function. Register access
+ *	to this function will fail until the function is reenabled.
+ */
+int sdio_disable_func(struct sdio_func *func)
+{
+	int ret;
+	unsigned char reg;
+
+	BUG_ON(!func);
+	BUG_ON(!func->card);
+
+	pr_debug("SDIO: Disabling device %s...\n", sdio_func_id(func));
+
+	ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IOEx, 0, &reg);
+	if (ret)
+		goto err;
+
+	reg &= ~(1 << func->num);
+
+	ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IOEx, reg, NULL);
+	if (ret)
+		goto err;
+
+	pr_debug("SDIO: Disabled device %s\n", sdio_func_id(func));
+
+	return 0;
+
+err:
+	pr_debug("SDIO: Failed to disable device %s\n", sdio_func_id(func));
+	return -EIO;
+}
+EXPORT_SYMBOL_GPL(sdio_disable_func);
+
+/**
+ *	sdio_set_block_size - set the block size of an SDIO function
+ *	@func: SDIO function to change
+ *	@blksz: new block size or 0 to use the default.
+ *
+ *	The default block size is the largest supported by both the function
+ *	and the host, with a maximum of 512 to ensure that arbitrarily sized
+ *	data transfer use the optimal (least) number of commands.
+ *
+ *	A driver may call this to override the default block size set by the
+ *	core. This can be used to set a block size greater than the maximum
+ *	that reported by the card; it is the driver's responsibility to ensure
+ *	it uses a value that the card supports.
+ *
+ *	Returns 0 on success, -EINVAL if the host does not support the
+ *	requested block size, or -EIO (etc.) if one of the resultant FBR block
+ *	size register writes failed.
+ *
+ */
+int sdio_set_block_size(struct sdio_func *func, unsigned blksz)
+{
+	int ret;
+
+	if (blksz > func->card->host->max_blk_size)
+		return -EINVAL;
+
+	if (blksz == 0) {
+		blksz = min(min(
+			func->max_blksize,
+			func->card->host->max_blk_size),
+			512u);
+	}
+
+	ret = mmc_io_rw_direct(func->card, 1, 0,
+		SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE,
+		blksz & 0xff, NULL);
+	if (ret)
+		return ret;
+	ret = mmc_io_rw_direct(func->card, 1, 0,
+		SDIO_FBR_BASE(func->num) + SDIO_FBR_BLKSIZE + 1,
+		(blksz >> 8) & 0xff, NULL);
+	if (ret)
+		return ret;
+	func->cur_blksize = blksz;
+	return 0;
+}
+
+EXPORT_SYMBOL_GPL(sdio_set_block_size);
+
+/* Split an arbitrarily sized data transfer into several
+ * IO_RW_EXTENDED commands. */
+static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
+	unsigned addr, int incr_addr, u8 *buf, unsigned size)
+{
+	unsigned remainder = size;
+	unsigned max_blocks;
+	int ret;
+
+	/* Do the bulk of the transfer using block mode (if supported). */
+	if (func->card->cccr.multi_block) {
+		/* Blocks per command is limited by host count, host transfer
+		 * size (we only use a single sg entry) and the maximum for
+		 * IO_RW_EXTENDED of 511 blocks. */
+		max_blocks = min(min(
+			func->card->host->max_blk_count,
+			func->card->host->max_seg_size / func->cur_blksize),
+			511u);
+
+		while (remainder > func->cur_blksize) {
+			unsigned blocks;
+
+			blocks = remainder / func->cur_blksize;
+			if (blocks > max_blocks)
+				blocks = max_blocks;
+			size = blocks * func->cur_blksize;
+
+			ret = mmc_io_rw_extended(func->card, write,
+				func->num, addr, incr_addr, buf,
+				blocks, func->cur_blksize);
+			if (ret)
+				return ret;
+
+			remainder -= size;
+			buf += size;
+			if (incr_addr)
+				addr += size;
+		}
+	}
+
+	/* Write the remainder using byte mode. */
+	while (remainder > 0) {
+		size = remainder;
+		if (size > func->cur_blksize)
+			size = func->cur_blksize;
+		if (size > 512)
+			size = 512; /* maximum size for byte mode */
+
+		ret = mmc_io_rw_extended(func->card, write, func->num, addr,
+			 incr_addr, buf, 1, size);
+		if (ret)
+			return ret;
+
+		remainder -= size;
+		buf += size;
+		if (incr_addr)
+			addr += size;
+	}
+	return 0;
+}
+
+/**
+ *	sdio_readb - read a single byte from a SDIO function
+ *	@func: SDIO function to access
+ *	@addr: address to read
+ *	@err_ret: optional status value from transfer
+ *
+ *	Reads a single byte from the address space of a given SDIO
+ *	function. If there is a problem reading the address, 0xff
+ *	is returned and @err_ret will contain the error code.
+ */
+unsigned char sdio_readb(struct sdio_func *func, unsigned int addr,
+	int *err_ret)
+{
+	int ret;
+	unsigned char val;
+
+	BUG_ON(!func);
+
+	if (err_ret)
+		*err_ret = 0;
+
+	ret = mmc_io_rw_direct(func->card, 0, func->num, addr, 0, &val);
+	if (ret) {
+		if (err_ret)
+			*err_ret = ret;
+		return 0xFF;
+	}
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(sdio_readb);
+
+/**
+ *	sdio_writeb - write a single byte to a SDIO function
+ *	@func: SDIO function to access
+ *	@b: byte to write
+ *	@addr: address to write to
+ *	@err_ret: optional status value from transfer
+ *
+ *	Writes a single byte to the address space of a given SDIO
+ *	function. @err_ret will contain the status of the actual
+ *	transfer.
+ */
+void sdio_writeb(struct sdio_func *func, unsigned char b, unsigned int addr,
+	int *err_ret)
+{
+	int ret;
+
+	BUG_ON(!func);
+
+	ret = mmc_io_rw_direct(func->card, 1, func->num, addr, b, NULL);
+	if (err_ret)
+		*err_ret = ret;
+}
+EXPORT_SYMBOL_GPL(sdio_writeb);
+
+/**
+ *	sdio_memcpy_fromio - read a chunk of memory from a SDIO function
+ *	@func: SDIO function to access
+ *	@dst: buffer to store the data
+ *	@addr: address to begin reading from
+ *	@count: number of bytes to read
+ *
+ *	Reads from the address space of a given SDIO function. Return
+ *	value indicates if the transfer succeeded or not.
+ */
+int sdio_memcpy_fromio(struct sdio_func *func, void *dst,
+	unsigned int addr, int count)
+{
+	return sdio_io_rw_ext_helper(func, 0, addr, 1, dst, count);
+}
+EXPORT_SYMBOL_GPL(sdio_memcpy_fromio);
+
+/**
+ *	sdio_memcpy_toio - write a chunk of memory to a SDIO function
+ *	@func: SDIO function to access
+ *	@addr: address to start writing to
+ *	@src: buffer that contains the data to write
+ *	@count: number of bytes to write
+ *
+ *	Writes to the address space of a given SDIO function. Return
+ *	value indicates if the transfer succeeded or not.
+ */
+int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr,
+	void *src, int count)
+{
+	return sdio_io_rw_ext_helper(func, 1, addr, 1, src, count);
+}
+EXPORT_SYMBOL_GPL(sdio_memcpy_toio);
+
+/**
+ *	sdio_readsb - read from a FIFO on a SDIO function
+ *	@func: SDIO function to access
+ *	@dst: buffer to store the data
+ *	@addr: address of (single byte) FIFO
+ *	@count: number of bytes to read
+ *
+ *	Reads from the specified FIFO of a given SDIO function. Return
+ *	value indicates if the transfer succeeded or not.
+ */
+int sdio_readsb(struct sdio_func *func, void *dst, unsigned int addr,
+	int count)
+{
+	return sdio_io_rw_ext_helper(func, 0, addr, 0, dst, count);
+}
+
+EXPORT_SYMBOL_GPL(sdio_readsb);
+
+/**
+ *	sdio_writesb - write to a FIFO of a SDIO function
+ *	@func: SDIO function to access
+ *	@addr: address of (single byte) FIFO
+ *	@src: buffer that contains the data to write
+ *	@count: number of bytes to write
+ *
+ *	Writes to the specified FIFO of a given SDIO function. Return
+ *	value indicates if the transfer succeeded or not.
+ */
+int sdio_writesb(struct sdio_func *func, unsigned int addr, void *src,
+	int count)
+{
+	return sdio_io_rw_ext_helper(func, 1, addr, 0, src, count);
+}
+EXPORT_SYMBOL_GPL(sdio_writesb);
+
+/**
+ *	sdio_readw - read a 16 bit integer from a SDIO function
+ *	@func: SDIO function to access
+ *	@addr: address to read
+ *	@err_ret: optional status value from transfer
+ *
+ *	Reads a 16 bit integer from the address space of a given SDIO
+ *	function. If there is a problem reading the address, 0xffff
+ *	is returned and @err_ret will contain the error code.
+ */
+unsigned short sdio_readw(struct sdio_func *func, unsigned int addr,
+	int *err_ret)
+{
+	int ret;
+
+	if (err_ret)
+		*err_ret = 0;
+
+	ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 2);
+	if (ret) {
+		if (err_ret)
+			*err_ret = ret;
+		return 0xFFFF;
+	}
+
+	return le16_to_cpu(*(u16*)func->tmpbuf);
+}
+EXPORT_SYMBOL_GPL(sdio_readw);
+
+/**
+ *	sdio_writew - write a 16 bit integer to a SDIO function
+ *	@func: SDIO function to access
+ *	@b: integer to write
+ *	@addr: address to write to
+ *	@err_ret: optional status value from transfer
+ *
+ *	Writes a 16 bit integer to the address space of a given SDIO
+ *	function. @err_ret will contain the status of the actual
+ *	transfer.
+ */
+void sdio_writew(struct sdio_func *func, unsigned short b, unsigned int addr,
+	int *err_ret)
+{
+	int ret;
+
+	*(u16*)func->tmpbuf = cpu_to_le16(b);
+
+	ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 2);
+	if (err_ret)
+		*err_ret = ret;
+}
+EXPORT_SYMBOL_GPL(sdio_writew);
+
+/**
+ *	sdio_readl - read a 32 bit integer from a SDIO function
+ *	@func: SDIO function to access
+ *	@addr: address to read
+ *	@err_ret: optional status value from transfer
+ *
+ *	Reads a 32 bit integer from the address space of a given SDIO
+ *	function. If there is a problem reading the address,
+ *	0xffffffff is returned and @err_ret will contain the error
+ *	code.
+ */
+unsigned long sdio_readl(struct sdio_func *func, unsigned int addr,
+	int *err_ret)
+{
+	int ret;
+
+	if (err_ret)
+		*err_ret = 0;
+
+	ret = sdio_memcpy_fromio(func, func->tmpbuf, addr, 4);
+	if (ret) {
+		if (err_ret)
+			*err_ret = ret;
+		return 0xFFFFFFFF;
+	}
+
+	return le32_to_cpu(*(u32*)func->tmpbuf);
+}
+EXPORT_SYMBOL_GPL(sdio_readl);
+
+/**
+ *	sdio_writel - write a 32 bit integer to a SDIO function
+ *	@func: SDIO function to access
+ *	@b: integer to write
+ *	@addr: address to write to
+ *	@err_ret: optional status value from transfer
+ *
+ *	Writes a 32 bit integer to the address space of a given SDIO
+ *	function. @err_ret will contain the status of the actual
+ *	transfer.
+ */
+void sdio_writel(struct sdio_func *func, unsigned long b, unsigned int addr,
+	int *err_ret)
+{
+	int ret;
+
+	*(u32*)func->tmpbuf = cpu_to_le32(b);
+
+	ret = sdio_memcpy_toio(func, addr, func->tmpbuf, 4);
+	if (err_ret)
+		*err_ret = ret;
+}
+EXPORT_SYMBOL_GPL(sdio_writel);
+
+/**
+ *	sdio_f0_readb - read a single byte from SDIO function 0
+ *	@func: an SDIO function of the card
+ *	@addr: address to read
+ *	@err_ret: optional status value from transfer
+ *
+ *	Reads a single byte from the address space of SDIO function 0.
+ *	If there is a problem reading the address, 0xff is returned
+ *	and @err_ret will contain the error code.
+ */
+unsigned char sdio_f0_readb(struct sdio_func *func, unsigned int addr,
+	int *err_ret)
+{
+	int ret;
+	unsigned char val;
+
+	BUG_ON(!func);
+
+	if (err_ret)
+		*err_ret = 0;
+
+	ret = mmc_io_rw_direct(func->card, 0, 0, addr, 0, &val);
+	if (ret) {
+		if (err_ret)
+			*err_ret = ret;
+		return 0xFF;
+	}
+
+	return val;
+}
+EXPORT_SYMBOL_GPL(sdio_f0_readb);
+
+/**
+ *	sdio_f0_writeb - write a single byte to SDIO function 0
+ *	@func: an SDIO function of the card
+ *	@b: byte to write
+ *	@addr: address to write to
+ *	@err_ret: optional status value from transfer
+ *
+ *	Writes a single byte to the address space of SDIO function 0.
+ *	@err_ret will contain the status of the actual transfer.
+ *
+ *	Only writes to the vendor specific CCCR registers (0xF0 -
+ *	0xFF) are permiited; @err_ret will be set to -EINVAL for *
+ *	writes outside this range.
+ */
+void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr,
+	int *err_ret)
+{
+	int ret;
+
+	BUG_ON(!func);
+
+	if (addr < 0xF0 || addr > 0xFF) {
+		if (err_ret)
+			*err_ret = -EINVAL;
+		return;
+	}
+
+	ret = mmc_io_rw_direct(func->card, 1, 0, addr, b, NULL);
+	if (err_ret)
+		*err_ret = ret;
+}
+EXPORT_SYMBOL_GPL(sdio_f0_writeb);
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
new file mode 100644
index 0000000..3bd3021
--- /dev/null
+++ b/drivers/mmc/core/sdio_irq.c
@@ -0,0 +1,267 @@
+/*
+ * linux/drivers/mmc/core/sdio_irq.c
+ *
+ * Author:      Nicolas Pitre
+ * Created:     June 18, 2007
+ * Copyright:   MontaVista Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+
+#include "sdio_ops.h"
+
+static int process_sdio_pending_irqs(struct mmc_card *card)
+{
+	int i, ret, count;
+	unsigned char pending;
+
+	ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending);
+	if (ret) {
+		printk(KERN_DEBUG "%s: error %d reading SDIO_CCCR_INTx\n",
+		       mmc_card_id(card), ret);
+		return ret;
+	}
+
+	count = 0;
+	for (i = 1; i <= 7; i++) {
+		if (pending & (1 << i)) {
+			struct sdio_func *func = card->sdio_func[i - 1];
+			if (!func) {
+				printk(KERN_WARNING "%s: pending IRQ for "
+					"non-existant function\n",
+					mmc_card_id(card));
+				ret = -EINVAL;
+			} else if (func->irq_handler) {
+				func->irq_handler(func);
+				count++;
+			} else {
+				printk(KERN_WARNING "%s: pending IRQ with no handler\n",
+				       sdio_func_id(func));
+				ret = -EINVAL;
+			}
+		}
+	}
+
+	if (count)
+		return count;
+
+	return ret;
+}
+
+static int sdio_irq_thread(void *_host)
+{
+	struct mmc_host *host = _host;
+	struct sched_param param = { .sched_priority = 1 };
+	unsigned long period, idle_period;
+	int ret;
+
+	sched_setscheduler(current, SCHED_FIFO, &param);
+
+	/*
+	 * We want to allow for SDIO cards to work even on non SDIO
+	 * aware hosts.  One thing that non SDIO host cannot do is
+	 * asynchronous notification of pending SDIO card interrupts
+	 * hence we poll for them in that case.
+	 */
+	idle_period = msecs_to_jiffies(10);
+	period = (host->caps & MMC_CAP_SDIO_IRQ) ?
+		MAX_SCHEDULE_TIMEOUT : idle_period;
+
+	pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n",
+		 mmc_hostname(host), period);
+
+	do {
+		/*
+		 * We claim the host here on drivers behalf for a couple
+		 * reasons:
+		 *
+		 * 1) it is already needed to retrieve the CCCR_INTx;
+		 * 2) we want the driver(s) to clear the IRQ condition ASAP;
+		 * 3) we need to control the abort condition locally.
+		 *
+		 * Just like traditional hard IRQ handlers, we expect SDIO
+		 * IRQ handlers to be quick and to the point, so that the
+		 * holding of the host lock does not cover too much work
+		 * that doesn't require that lock to be held.
+		 */
+		ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort);
+		if (ret)
+			break;
+		ret = process_sdio_pending_irqs(host->card);
+		mmc_release_host(host);
+
+		/*
+		 * Give other threads a chance to run in the presence of
+		 * errors.  FIXME: determine if due to card removal and
+		 * possibly exit this thread if so.
+		 */
+		if (ret < 0)
+			ssleep(1);
+
+		/*
+		 * Adaptive polling frequency based on the assumption
+		 * that an interrupt will be closely followed by more.
+		 * This has a substantial benefit for network devices.
+		 */
+		if (!(host->caps & MMC_CAP_SDIO_IRQ)) {
+			if (ret > 0)
+				period /= 2;
+			else {
+				period++;
+				if (period > idle_period)
+					period = idle_period;
+			}
+		}
+
+		set_task_state(current, TASK_INTERRUPTIBLE);
+		if (host->caps & MMC_CAP_SDIO_IRQ)
+			host->ops->enable_sdio_irq(host, 1);
+		if (!kthread_should_stop())
+			schedule_timeout(period);
+		set_task_state(current, TASK_RUNNING);
+	} while (!kthread_should_stop());
+
+	if (host->caps & MMC_CAP_SDIO_IRQ)
+		host->ops->enable_sdio_irq(host, 0);
+
+	pr_debug("%s: IRQ thread exiting with code %d\n",
+		 mmc_hostname(host), ret);
+
+	return ret;
+}
+
+static int sdio_card_irq_get(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+
+	WARN_ON(!host->claimed);
+
+	if (!host->sdio_irqs++) {
+		atomic_set(&host->sdio_irq_thread_abort, 0);
+		host->sdio_irq_thread =
+			kthread_run(sdio_irq_thread, host, "ksdiorqd");
+		if (IS_ERR(host->sdio_irq_thread)) {
+			int err = PTR_ERR(host->sdio_irq_thread);
+			host->sdio_irqs--;
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+static int sdio_card_irq_put(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+
+	WARN_ON(!host->claimed);
+	BUG_ON(host->sdio_irqs < 1);
+
+	if (!--host->sdio_irqs) {
+		atomic_set(&host->sdio_irq_thread_abort, 1);
+		kthread_stop(host->sdio_irq_thread);
+	}
+
+	return 0;
+}
+
+/**
+ *	sdio_claim_irq - claim the IRQ for a SDIO function
+ *	@func: SDIO function
+ *	@handler: IRQ handler callback
+ *
+ *	Claim and activate the IRQ for the given SDIO function. The provided
+ *	handler will be called when that IRQ is asserted.  The host is always
+ *	claimed already when the handler is called so the handler must not
+ *	call sdio_claim_host() nor sdio_release_host().
+ */
+int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler)
+{
+	int ret;
+	unsigned char reg;
+
+	BUG_ON(!func);
+	BUG_ON(!func->card);
+
+	pr_debug("SDIO: Enabling IRQ for %s...\n", sdio_func_id(func));
+
+	if (func->irq_handler) {
+		pr_debug("SDIO: IRQ for %s already in use.\n", sdio_func_id(func));
+		return -EBUSY;
+	}
+
+	ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
+	if (ret)
+		return ret;
+
+	reg |= 1 << func->num;
+
+	reg |= 1; /* Master interrupt enable */
+
+	ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL);
+	if (ret)
+		return ret;
+
+	func->irq_handler = handler;
+	ret = sdio_card_irq_get(func->card);
+	if (ret)
+		func->irq_handler = NULL;
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(sdio_claim_irq);
+
+/**
+ *	sdio_release_irq - release the IRQ for a SDIO function
+ *	@func: SDIO function
+ *
+ *	Disable and release the IRQ for the given SDIO function.
+ */
+int sdio_release_irq(struct sdio_func *func)
+{
+	int ret;
+	unsigned char reg;
+
+	BUG_ON(!func);
+	BUG_ON(!func->card);
+
+	pr_debug("SDIO: Disabling IRQ for %s...\n", sdio_func_id(func));
+
+	if (func->irq_handler) {
+		func->irq_handler = NULL;
+		sdio_card_irq_put(func->card);
+	}
+
+	ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
+	if (ret)
+		return ret;
+
+	reg &= ~(1 << func->num);
+
+	/* Disable master interrupt with the last function interrupt */
+	if (!(reg & 0xFE))
+		reg = 0;
+
+	ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(sdio_release_irq);
+
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
new file mode 100644
index 0000000..4d289b2
--- /dev/null
+++ b/drivers/mmc/core/sdio_ops.c
@@ -0,0 +1,176 @@
+/*
+ *  linux/drivers/mmc/sdio_ops.c
+ *
+ *  Copyright 2006-2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sdio.h>
+
+#include "core.h"
+
+int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
+{
+	struct mmc_command cmd;
+	int i, err = 0;
+
+	BUG_ON(!host);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = SD_IO_SEND_OP_COND;
+	cmd.arg = ocr;
+	cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR;
+
+	for (i = 100; i; i--) {
+		err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
+		if (err)
+			break;
+
+		/* if we're just probing, do a single pass */
+		if (ocr == 0)
+			break;
+
+		/* otherwise wait until reset completes */
+		if (mmc_host_is_spi(host)) {
+			/*
+			 * Both R1_SPI_IDLE and MMC_CARD_BUSY indicate
+			 * an initialized card under SPI, but some cards
+			 * (Marvell's) only behave when looking at this
+			 * one.
+			 */
+			if (cmd.resp[1] & MMC_CARD_BUSY)
+				break;
+		} else {
+			if (cmd.resp[0] & MMC_CARD_BUSY)
+				break;
+		}
+
+		err = -ETIMEDOUT;
+
+		mmc_delay(10);
+	}
+
+	if (rocr)
+		*rocr = cmd.resp[mmc_host_is_spi(host) ? 1 : 0];
+
+	return err;
+}
+
+int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
+	unsigned addr, u8 in, u8* out)
+{
+	struct mmc_command cmd;
+	int err;
+
+	BUG_ON(!card);
+	BUG_ON(fn > 7);
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = SD_IO_RW_DIRECT;
+	cmd.arg = write ? 0x80000000 : 0x00000000;
+	cmd.arg |= fn << 28;
+	cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;
+	cmd.arg |= addr << 9;
+	cmd.arg |= in;
+	cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
+
+	err = mmc_wait_for_cmd(card->host, &cmd, 0);
+	if (err)
+		return err;
+
+	if (mmc_host_is_spi(card->host)) {
+		/* host driver already reported errors */
+	} else {
+		if (cmd.resp[0] & R5_ERROR)
+			return -EIO;
+		if (cmd.resp[0] & R5_FUNCTION_NUMBER)
+			return -EINVAL;
+		if (cmd.resp[0] & R5_OUT_OF_RANGE)
+			return -ERANGE;
+	}
+
+	if (out) {
+		if (mmc_host_is_spi(card->host))
+			*out = (cmd.resp[0] >> 8) & 0xFF;
+		else
+			*out = cmd.resp[0] & 0xFF;
+	}
+
+	return 0;
+}
+
+int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
+	unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
+{
+	struct mmc_request mrq;
+	struct mmc_command cmd;
+	struct mmc_data data;
+	struct scatterlist sg;
+
+	BUG_ON(!card);
+	BUG_ON(fn > 7);
+	BUG_ON(blocks == 1 && blksz > 512);
+	WARN_ON(blocks == 0);
+	WARN_ON(blksz == 0);
+
+	memset(&mrq, 0, sizeof(struct mmc_request));
+	memset(&cmd, 0, sizeof(struct mmc_command));
+	memset(&data, 0, sizeof(struct mmc_data));
+
+	mrq.cmd = &cmd;
+	mrq.data = &data;
+
+	cmd.opcode = SD_IO_RW_EXTENDED;
+	cmd.arg = write ? 0x80000000 : 0x00000000;
+	cmd.arg |= fn << 28;
+	cmd.arg |= incr_addr ? 0x04000000 : 0x00000000;
+	cmd.arg |= addr << 9;
+	if (blocks == 1 && blksz <= 512)
+		cmd.arg |= (blksz == 512) ? 0 : blksz;	/* byte mode */
+	else
+		cmd.arg |= 0x08000000 | blocks;		/* block mode */
+	cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
+
+	data.blksz = blksz;
+	data.blocks = blocks;
+	data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
+	data.sg = &sg;
+	data.sg_len = 1;
+
+	sg_init_one(&sg, buf, blksz * blocks);
+
+	mmc_set_data_timeout(&data, card);
+
+	mmc_wait_for_req(card->host, &mrq);
+
+	if (cmd.error)
+		return cmd.error;
+	if (data.error)
+		return data.error;
+
+	if (mmc_host_is_spi(card->host)) {
+		/* host driver already reported errors */
+	} else {
+		if (cmd.resp[0] & R5_ERROR)
+			return -EIO;
+		if (cmd.resp[0] & R5_FUNCTION_NUMBER)
+			return -EINVAL;
+		if (cmd.resp[0] & R5_OUT_OF_RANGE)
+			return -ERANGE;
+	}
+
+	return 0;
+}
+
diff --git a/drivers/mmc/core/sdio_ops.h b/drivers/mmc/core/sdio_ops.h
new file mode 100644
index 0000000..e2e74b0
--- /dev/null
+++ b/drivers/mmc/core/sdio_ops.h
@@ -0,0 +1,22 @@
+/*
+ *  linux/drivers/mmc/sdio_ops.c
+ *
+ *  Copyright 2006-2007 Pierre Ossman
+ *
+ * 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.
+ */
+
+#ifndef _MMC_SDIO_OPS_H
+#define _MMC_SDIO_OPS_H
+
+int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
+int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
+	unsigned addr, u8 in, u8* out);
+int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
+	unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz);
+
+#endif
+
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index e23082f..5fef678 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -35,6 +35,23 @@
 
 	  If unsure, say N.
 
+config MMC_RICOH_MMC
+	tristate "Ricoh MMC Controller Disabler  (EXPERIMENTAL)"
+	depends on PCI && EXPERIMENTAL && MMC_SDHCI
+	help
+	  This selects the disabler for the Ricoh MMC Controller. This
+	  proprietary controller is unnecessary because the SDHCI driver
+	  supports MMC cards on the SD controller, but if it is not
+	  disabled, it will steal the MMC cards away - rendering them
+	  useless. It is safe to select this driver even if you don't
+	  have a Ricoh based card reader.
+
+
+	  To compile this driver as a module, choose M here:
+	  the module will be called ricoh_mmc.
+
+	  If unsure, say Y.
+
 config MMC_OMAP
 	tristate "TI OMAP Multimedia Card Interface support"
 	depends on ARCH_OMAP
@@ -100,3 +117,16 @@
           To compile this driver as a module, choose M here: the
 	  module will be called tifm_sd.
 
+config MMC_SPI
+	tristate "MMC/SD over SPI (EXPERIMENTAL)"
+	depends on MMC && SPI_MASTER && !HIGHMEM && EXPERIMENTAL
+	select CRC7
+	select CRC_ITU_T
+	help
+	  Some systems accss MMC/SD cards using a SPI controller instead of
+	  using a "native" MMC/SD controller.  This has a disadvantage of
+	  being relatively high overhead, but a compensating advantage of
+	  working on many systems without dedicated MMC/SD controllers.
+
+	  If unsure, or if your system has no SPI master driver, say N.
+
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 6685f64..3877c87 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -10,9 +10,11 @@
 obj-$(CONFIG_MMC_PXA)		+= pxamci.o
 obj-$(CONFIG_MMC_IMX)		+= imxmmc.o
 obj-$(CONFIG_MMC_SDHCI)		+= sdhci.o
+obj-$(CONFIG_MMC_RICOH_MMC)	+= ricoh_mmc.o
 obj-$(CONFIG_MMC_WBSD)		+= wbsd.o
 obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o
 obj-$(CONFIG_MMC_OMAP)		+= omap.o
 obj-$(CONFIG_MMC_AT91)		+= at91_mci.o
 obj-$(CONFIG_MMC_TIFM_SD)	+= tifm_sd.o
+obj-$(CONFIG_MMC_SPI)		+= mmc_spi.o
 
diff --git a/drivers/mmc/host/at91_mci.c b/drivers/mmc/host/at91_mci.c
index 28c8818..6ba98a4 100644
--- a/drivers/mmc/host/at91_mci.c
+++ b/drivers/mmc/host/at91_mci.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mmc/at91_mci.c - ATMEL AT91 MCI Driver
+ *  linux/drivers/mmc/host/at91_mci.c - ATMEL AT91 MCI Driver
  *
  *  Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved
  *
@@ -83,7 +83,7 @@
 
 #define AT91_MCI_ERRORS	(AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE	\
 		| AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE		\
-		| AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)			
+		| AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)
 
 #define at91_mci_read(host, reg)	__raw_readl((host)->baseaddr + (reg))
 #define at91_mci_write(host, reg, val)	__raw_writel((val), (host)->baseaddr + (reg))
@@ -328,7 +328,7 @@
 	data = cmd->data;
 	if (!data) return;
 
-	if (cmd->data->flags & MMC_DATA_MULTI) {
+	if (cmd->data->blocks > 1) {
 		pr_debug("multiple write : wait for BLKE...\n");
 		at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE);
 	} else
@@ -428,6 +428,14 @@
 	}
 
 	if (data) {
+
+		if ( data->blksz & 0x3 ) {
+			pr_debug("Unsupported block size\n");
+			cmd->error = -EINVAL;
+			mmc_request_done(host->mmc, host->request);
+			return;
+		}
+
 		block_length = data->blksz;
 		blocks = data->blocks;
 
@@ -439,7 +447,7 @@
 
 		if (data->flags & MMC_DATA_STREAM)
 			cmdr |= AT91_MCI_TRTYP_STREAM;
-		if (data->flags & MMC_DATA_MULTI)
+		if (data->blocks > 1)
 			cmdr |= AT91_MCI_TRTYP_MULTIPLE;
 	}
 	else {
@@ -577,24 +585,22 @@
 			AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE |
 			AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) {
 		if ((status & AT91_MCI_RCRCE) && !(mmc_resp_type(cmd) & MMC_RSP_CRC)) {
-			cmd->error = MMC_ERR_NONE;
+			cmd->error = 0;
 		}
 		else {
 			if (status & (AT91_MCI_RTOE | AT91_MCI_DTOE))
-				cmd->error = MMC_ERR_TIMEOUT;
+				cmd->error = -ETIMEDOUT;
 			else if (status & (AT91_MCI_RCRCE | AT91_MCI_DCRCE))
-				cmd->error = MMC_ERR_BADCRC;
-			else if (status & (AT91_MCI_OVRE | AT91_MCI_UNRE))
-				cmd->error = MMC_ERR_FIFO;
+				cmd->error = -EILSEQ;
 			else
-				cmd->error = MMC_ERR_FAILED;
+				cmd->error = -EIO;
 
 			pr_debug("Error detected and set to %d (cmd = %d, retries = %d)\n",
 				 cmd->error, cmd->opcode, cmd->retries);
 		}
 	}
 	else
-		cmd->error = MMC_ERR_NONE;
+		cmd->error = 0;
 
 	at91_mci_process_next(host);
 }
@@ -676,15 +682,15 @@
 
 	int_status = at91_mci_read(host, AT91_MCI_SR);
 	int_mask = at91_mci_read(host, AT91_MCI_IMR);
-	
+
 	pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask,
 		int_status & int_mask);
-	
+
 	int_status = int_status & int_mask;
 
 	if (int_status & AT91_MCI_ERRORS) {
 		completed = 1;
-		
+
 		if (int_status & AT91_MCI_UNRE)
 			pr_debug("MMC: Underrun error\n");
 		if (int_status & AT91_MCI_OVRE)
@@ -836,7 +842,6 @@
 	mmc->f_min = 375000;
 	mmc->f_max = 25000000;
 	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-	mmc->caps = MMC_CAP_BYTEBLOCK;
 
 	mmc->max_blk_size = 4095;
 	mmc->max_blk_count = mmc->max_req_size;
@@ -903,8 +908,10 @@
 	/*
 	 * Add host to MMC layer
 	 */
-	if (host->board->det_pin)
+	if (host->board->det_pin) {
 		host->present = !at91_get_gpio_value(host->board->det_pin);
+		device_init_wakeup(&pdev->dev, 1);
+	}
 	else
 		host->present = -1;
 
@@ -939,7 +946,8 @@
 
 	host = mmc_priv(mmc);
 
-	if (host->present != -1) {
+	if (host->board->det_pin) {
+		device_init_wakeup(&pdev->dev, 0);
 		free_irq(host->board->det_pin, host);
 		cancel_delayed_work(&host->mmc->detect);
 	}
@@ -966,8 +974,12 @@
 static int at91_mci_suspend(struct platform_device *pdev, pm_message_t state)
 {
 	struct mmc_host *mmc = platform_get_drvdata(pdev);
+	struct at91mci_host *host = mmc_priv(mmc);
 	int ret = 0;
 
+	if (host->board->det_pin && device_may_wakeup(&pdev->dev))
+		enable_irq_wake(host->board->det_pin);
+
 	if (mmc)
 		ret = mmc_suspend_host(mmc, state);
 
@@ -977,8 +989,12 @@
 static int at91_mci_resume(struct platform_device *pdev)
 {
 	struct mmc_host *mmc = platform_get_drvdata(pdev);
+	struct at91mci_host *host = mmc_priv(mmc);
 	int ret = 0;
 
+	if (host->board->det_pin && device_may_wakeup(&pdev->dev))
+		disable_irq_wake(host->board->det_pin);
+
 	if (mmc)
 		ret = mmc_resume_host(mmc);
 
diff --git a/drivers/mmc/host/au1xmmc.c b/drivers/mmc/host/au1xmmc.c
index 52b63f1..92c4d0d 100644
--- a/drivers/mmc/host/au1xmmc.c
+++ b/drivers/mmc/host/au1xmmc.c
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/mmc/au1xmmc.c - AU1XX0 MMC driver
+ * linux/drivers/mmc/host/au1xmmc.c - AU1XX0 MMC driver
  *
  *  Copyright (c) 2005, Advanced Micro Devices, Inc.
  *
@@ -186,7 +186,7 @@
 }
 
 static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
-				struct mmc_command *cmd, unsigned int flags)
+				struct mmc_command *cmd, struct mmc_data *data)
 {
 	u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
 
@@ -208,19 +208,21 @@
 	default:
 		printk(KERN_INFO "au1xmmc: unhandled response type %02x\n",
 			mmc_resp_type(cmd));
-		return MMC_ERR_INVALID;
+		return -EINVAL;
 	}
 
-	if (flags & MMC_DATA_READ) {
-		if (flags & MMC_DATA_MULTI)
-			mmccmd |= SD_CMD_CT_4;
-		else
-			mmccmd |= SD_CMD_CT_2;
-	} else if (flags & MMC_DATA_WRITE) {
-		if (flags & MMC_DATA_MULTI)
-			mmccmd |= SD_CMD_CT_3;
-		else
-			mmccmd |= SD_CMD_CT_1;
+	if (data) {
+		if (flags & MMC_DATA_READ) {
+			if (data->blocks > 1)
+				mmccmd |= SD_CMD_CT_4;
+			else
+				mmccmd |= SD_CMD_CT_2;
+		} else if (flags & MMC_DATA_WRITE) {
+			if (data->blocks > 1)
+				mmccmd |= SD_CMD_CT_3;
+			else
+				mmccmd |= SD_CMD_CT_1;
+		}
 	}
 
 	au_writel(cmd->arg, HOST_CMDARG(host));
@@ -253,7 +255,7 @@
 		IRQ_ON(host, SD_CONFIG_CR);
 	}
 
-	return MMC_ERR_NONE;
+	return 0;
 }
 
 static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status)
@@ -278,7 +280,7 @@
 	while((host->flags & HOST_F_XMIT) && (status & SD_STATUS_DB))
 		status = au_readl(HOST_STATUS(host));
 
-	data->error = MMC_ERR_NONE;
+	data->error = 0;
 	dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma.dir);
 
         /* Process any errors */
@@ -288,14 +290,14 @@
 		crc |= ((status & 0x07) == 0x02) ? 0 : 1;
 
 	if (crc)
-		data->error = MMC_ERR_BADCRC;
+		data->error = -EILSEQ;
 
 	/* Clear the CRC bits */
 	au_writel(SD_STATUS_WC | SD_STATUS_RC, HOST_STATUS(host));
 
 	data->bytes_xfered = 0;
 
-	if (data->error == MMC_ERR_NONE) {
+	if (!data->error) {
 		if (host->flags & HOST_F_DMA) {
 			u32 chan = DMA_CHANNEL(host);
 
@@ -475,7 +477,7 @@
 		return;
 
 	cmd = mrq->cmd;
-	cmd->error = MMC_ERR_NONE;
+	cmd->error = 0;
 
 	if (cmd->flags & MMC_RSP_PRESENT) {
 		if (cmd->flags & MMC_RSP_136) {
@@ -512,11 +514,11 @@
         /* Figure out errors */
 
 	if (status & (SD_STATUS_SC | SD_STATUS_WC | SD_STATUS_RC))
-		cmd->error = MMC_ERR_BADCRC;
+		cmd->error = -EILSEQ;
 
 	trans = host->flags & (HOST_F_XMIT | HOST_F_RECV);
 
-	if (!trans || cmd->error != MMC_ERR_NONE) {
+	if (!trans || cmd->error) {
 
 		IRQ_OFF(host, SD_CONFIG_TH | SD_CONFIG_RA|SD_CONFIG_RF);
 		tasklet_schedule(&host->finish_task);
@@ -589,7 +591,7 @@
 				   data->sg_len, host->dma.dir);
 
 	if (host->dma.len == 0)
-		return MMC_ERR_TIMEOUT;
+		return -ETIMEDOUT;
 
 	au_writel(data->blksz - 1, HOST_BLKSIZE(host));
 
@@ -640,11 +642,11 @@
 			//IRQ_ON(host, SD_CONFIG_RA|SD_CONFIG_RF);
 	}
 
-	return MMC_ERR_NONE;
+	return 0;
 
  dataerr:
 	dma_unmap_sg(mmc_dev(host->mmc),data->sg,data->sg_len,host->dma.dir);
-	return MMC_ERR_TIMEOUT;
+	return -ETIMEDOUT;
 }
 
 /* static void au1xmmc_request
@@ -656,7 +658,7 @@
 
 	struct au1xmmc_host *host = mmc_priv(mmc);
 	unsigned int flags = 0;
-	int ret = MMC_ERR_NONE;
+	int ret = 0;
 
 	WARN_ON(irqs_disabled());
 	WARN_ON(host->status != HOST_S_IDLE);
@@ -672,10 +674,10 @@
 		ret = au1xmmc_prepare_data(host, mrq->data);
 	}
 
-	if (ret == MMC_ERR_NONE)
-		ret = au1xmmc_send_command(host, 0, mrq->cmd, flags);
+	if (!ret)
+		ret = au1xmmc_send_command(host, 0, mrq->cmd, mrq->data);
 
-	if (ret != MMC_ERR_NONE) {
+	if (ret) {
 		mrq->cmd->error = ret;
 		au1xmmc_finish_request(host);
 	}
@@ -764,10 +766,10 @@
 
 		if (host->mrq && (status & STATUS_TIMEOUT)) {
 			if (status & SD_STATUS_RAT)
-				host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+				host->mrq->cmd->error = -ETIMEDOUT;
 
 			else if (status & SD_STATUS_DT)
-				host->mrq->data->error = MMC_ERR_TIMEOUT;
+				host->mrq->data->error = -ETIMEDOUT;
 
 			/* In PIO mode, interrupts might still be enabled */
 			IRQ_OFF(host, SD_CONFIG_NE | SD_CONFIG_TH);
diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c
index 7ee2045..6ebc41e 100644
--- a/drivers/mmc/host/imxmmc.c
+++ b/drivers/mmc/host/imxmmc.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mmc/imxmmc.c - Motorola i.MX MMCI driver
+ *  linux/drivers/mmc/host/imxmmc.c - Motorola i.MX MMCI driver
  *
  *  Copyright (C) 2004 Sascha Hauer, Pengutronix <sascha@saschahauer.de>
  *  Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
@@ -428,11 +428,11 @@
 	if ( stat & STATUS_ERR_MASK ) {
 		dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",stat);
 		if(stat & (STATUS_CRC_READ_ERR | STATUS_CRC_WRITE_ERR))
-			data->error = MMC_ERR_BADCRC;
+			data->error = -EILSEQ;
 		else if(stat & STATUS_TIME_OUT_READ)
-			data->error = MMC_ERR_TIMEOUT;
+			data->error = -ETIMEDOUT;
 		else
-			data->error = MMC_ERR_FAILED;
+			data->error = -EIO;
 	} else {
 		data->bytes_xfered = host->dma_size;
 	}
@@ -458,10 +458,10 @@
 
 	if (stat & STATUS_TIME_OUT_RESP) {
 		dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n");
-		cmd->error = MMC_ERR_TIMEOUT;
+		cmd->error = -ETIMEDOUT;
 	} else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
 		dev_dbg(mmc_dev(host->mmc), "cmd crc error\n");
-		cmd->error = MMC_ERR_BADCRC;
+		cmd->error = -EILSEQ;
 	}
 
 	if(cmd->flags & MMC_RSP_PRESENT) {
@@ -482,7 +482,7 @@
 	dev_dbg(mmc_dev(host->mmc), "RESP 0x%08x, 0x%08x, 0x%08x, 0x%08x, error %d\n",
 		cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3], cmd->error);
 
-	if (data && (cmd->error == MMC_ERR_NONE) && !(stat & STATUS_ERR_MASK)) {
+	if (data && !cmd->error && !(stat & STATUS_ERR_MASK)) {
 		if (host->req->data->flags & MMC_DATA_WRITE) {
 
 			/* Wait for FIFO to be empty before starting DMA write */
@@ -491,7 +491,7 @@
 			if(imxmci_busy_wait_for_status(host, &stat,
 				STATUS_APPL_BUFF_FE,
 				40, "imxmci_cmd_done DMA WR") < 0) {
-				cmd->error = MMC_ERR_FIFO;
+				cmd->error = -EIO;
 				imxmci_finish_data(host, stat);
 				if(host->req)
 					imxmci_finish_request(host, host->req);
@@ -884,9 +884,21 @@
 	}
 }
 
+static int imxmci_get_ro(struct mmc_host *mmc)
+{
+	struct imxmci_host *host = mmc_priv(mmc);
+
+	if (host->pdata && host->pdata->get_ro)
+		return host->pdata->get_ro(mmc_dev(mmc));
+	/* Host doesn't support read only detection so assume writeable */
+	return 0;
+}
+
+
 static const struct mmc_host_ops imxmci_ops = {
 	.request	= imxmci_request,
 	.set_ios	= imxmci_set_ios,
+	.get_ro		= imxmci_get_ro,
 };
 
 static struct resource *platform_device_resource(struct platform_device *dev, unsigned int mask, int nr)
@@ -913,7 +925,7 @@
 {
 	struct imxmci_host *host = (struct imxmci_host *)data;
 
-	if( host->pdata->card_present() != host->present ) {
+	if( host->pdata->card_present(mmc_dev(host->mmc)) != host->present ) {
 		host->present ^= 1;
 		dev_info(mmc_dev(host->mmc), "card %s\n",
 		      host->present ? "inserted" : "removed");
@@ -963,7 +975,7 @@
 	mmc->f_min = 150000;
 	mmc->f_max = CLK_RATE/2;
 	mmc->ocr_avail = MMC_VDD_32_33;
-	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_BYTEBLOCK;
+	mmc->caps = MMC_CAP_4_BIT_DATA;
 
 	/* MMC core transfer sizes tunable parameters */
 	mmc->max_hw_segs = 64;
@@ -1022,7 +1034,7 @@
 	if (ret)
 		goto out;
 
-	host->present = host->pdata->card_present();
+	host->present = host->pdata->card_present(mmc_dev(mmc));
 	init_timer(&host->timer);
 	host->timer.data = (unsigned long)host;
 	host->timer.function = imxmci_check_status;
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
new file mode 100644
index 0000000..f30327b
--- /dev/null
+++ b/drivers/mmc/host/mmc_spi.c
@@ -0,0 +1,1408 @@
+/*
+ * mmc_spi.c - Access SD/MMC cards through SPI master controllers
+ *
+ * (C) Copyright 2005, Intec Automation,
+ *		Mike Lavender (mike@steroidmicros)
+ * (C) Copyright 2006-2007, David Brownell
+ * (C) Copyright 2007, Axis Communications,
+ *		Hans-Peter Nilsson (hp@axis.com)
+ * (C) Copyright 2007, ATRON electronic GmbH,
+ *		Jan Nikitenko <jan.nikitenko@gmail.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+#include <linux/dma-mapping.h>
+#include <linux/crc7.h>
+#include <linux/crc-itu-t.h>
+
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>		/* for R1_SPI_* bit values */
+
+#include <linux/spi/spi.h>
+#include <linux/spi/mmc_spi.h>
+
+#include <asm/unaligned.h>
+
+
+/* NOTES:
+ *
+ * - For now, we won't try to interoperate with a real mmc/sd/sdio
+ *   controller, although some of them do have hardware support for
+ *   SPI protocol.  The main reason for such configs would be mmc-ish
+ *   cards like DataFlash, which don't support that "native" protocol.
+ *
+ *   We don't have a "DataFlash/MMC/SD/SDIO card slot" abstraction to
+ *   switch between driver stacks, and in any case if "native" mode
+ *   is available, it will be faster and hence preferable.
+ *
+ * - MMC depends on a different chipselect management policy than the
+ *   SPI interface currently supports for shared bus segments:  it needs
+ *   to issue multiple spi_message requests with the chipselect active,
+ *   using the results of one message to decide the next one to issue.
+ *
+ *   Pending updates to the programming interface, this driver expects
+ *   that it not share the bus with other drivers (precluding conflicts).
+ *
+ * - We tell the controller to keep the chipselect active from the
+ *   beginning of an mmc_host_ops.request until the end.  So beware
+ *   of SPI controller drivers that mis-handle the cs_change flag!
+ *
+ *   However, many cards seem OK with chipselect flapping up/down
+ *   during that time ... at least on unshared bus segments.
+ */
+
+
+/*
+ * Local protocol constants, internal to data block protocols.
+ */
+
+/* Response tokens used to ack each block written: */
+#define SPI_MMC_RESPONSE_CODE(x)	((x) & 0x1f)
+#define SPI_RESPONSE_ACCEPTED		((2 << 1)|1)
+#define SPI_RESPONSE_CRC_ERR		((5 << 1)|1)
+#define SPI_RESPONSE_WRITE_ERR		((6 << 1)|1)
+
+/* Read and write blocks start with these tokens and end with crc;
+ * on error, read tokens act like a subset of R2_SPI_* values.
+ */
+#define SPI_TOKEN_SINGLE	0xfe	/* single block r/w, multiblock read */
+#define SPI_TOKEN_MULTI_WRITE	0xfc	/* multiblock write */
+#define SPI_TOKEN_STOP_TRAN	0xfd	/* terminate multiblock write */
+
+#define MMC_SPI_BLOCKSIZE	512
+
+
+/* These fixed timeouts come from the latest SD specs, which say to ignore
+ * the CSD values.  The R1B value is for card erase (e.g. the "I forgot the
+ * card's password" scenario); it's mostly applied to STOP_TRANSMISSION after
+ * reads which takes nowhere near that long.  Older cards may be able to use
+ * shorter timeouts ... but why bother?
+ */
+#define readblock_timeout	ktime_set(0, 100 * 1000 * 1000)
+#define writeblock_timeout	ktime_set(0, 250 * 1000 * 1000)
+#define r1b_timeout		ktime_set(3, 0)
+
+
+/****************************************************************************/
+
+/*
+ * Local Data Structures
+ */
+
+/* "scratch" is per-{command,block} data exchanged with the card */
+struct scratch {
+	u8			status[29];
+	u8			data_token;
+	__be16			crc_val;
+};
+
+struct mmc_spi_host {
+	struct mmc_host		*mmc;
+	struct spi_device	*spi;
+
+	unsigned char		power_mode;
+	u16			powerup_msecs;
+
+	struct mmc_spi_platform_data	*pdata;
+
+	/* for bulk data transfers */
+	struct spi_transfer	token, t, crc, early_status;
+	struct spi_message	m;
+
+	/* for status readback */
+	struct spi_transfer	status;
+	struct spi_message	readback;
+
+	/* underlying DMA-aware controller, or null */
+	struct device		*dma_dev;
+
+	/* buffer used for commands and for message "overhead" */
+	struct scratch		*data;
+	dma_addr_t		data_dma;
+
+	/* Specs say to write ones most of the time, even when the card
+	 * has no need to read its input data; and many cards won't care.
+	 * This is our source of those ones.
+	 */
+	void			*ones;
+	dma_addr_t		ones_dma;
+};
+
+
+/****************************************************************************/
+
+/*
+ * MMC-over-SPI protocol glue, used by the MMC stack interface
+ */
+
+static inline int mmc_cs_off(struct mmc_spi_host *host)
+{
+	/* chipselect will always be inactive after setup() */
+	return spi_setup(host->spi);
+}
+
+static int
+mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len)
+{
+	int status;
+
+	if (len > sizeof(*host->data)) {
+		WARN_ON(1);
+		return -EIO;
+	}
+
+	host->status.len = len;
+
+	if (host->dma_dev)
+		dma_sync_single_for_device(host->dma_dev,
+				host->data_dma, sizeof(*host->data),
+				DMA_FROM_DEVICE);
+
+	status = spi_sync(host->spi, &host->readback);
+	if (status == 0)
+		status = host->readback.status;
+
+	if (host->dma_dev)
+		dma_sync_single_for_cpu(host->dma_dev,
+				host->data_dma, sizeof(*host->data),
+				DMA_FROM_DEVICE);
+
+	return status;
+}
+
+static int
+mmc_spi_skip(struct mmc_spi_host *host, ktime_t timeout, unsigned n, u8 byte)
+{
+	u8		*cp = host->data->status;
+
+	timeout = ktime_add(timeout, ktime_get());
+
+	while (1) {
+		int		status;
+		unsigned	i;
+
+		status = mmc_spi_readbytes(host, n);
+		if (status < 0)
+			return status;
+
+		for (i = 0; i < n; i++) {
+			if (cp[i] != byte)
+				return cp[i];
+		}
+
+		/* REVISIT investigate msleep() to avoid busy-wait I/O
+		 * in at least some cases.
+		 */
+		if (ktime_to_ns(ktime_sub(ktime_get(), timeout)) > 0)
+			break;
+	}
+	return -ETIMEDOUT;
+}
+
+static inline int
+mmc_spi_wait_unbusy(struct mmc_spi_host *host, ktime_t timeout)
+{
+	return mmc_spi_skip(host, timeout, sizeof(host->data->status), 0);
+}
+
+static int mmc_spi_readtoken(struct mmc_spi_host *host)
+{
+	return mmc_spi_skip(host, readblock_timeout, 1, 0xff);
+}
+
+
+/*
+ * Note that for SPI, cmd->resp[0] is not the same data as "native" protocol
+ * hosts return!  The low byte holds R1_SPI bits.  The next byte may hold
+ * R2_SPI bits ... for SEND_STATUS, or after data read errors.
+ *
+ * cmd->resp[1] holds any four-byte response, for R3 (READ_OCR) and on
+ * newer cards R7 (IF_COND).
+ */
+
+static char *maptype(struct mmc_command *cmd)
+{
+	switch (mmc_spi_resp_type(cmd)) {
+	case MMC_RSP_SPI_R1:	return "R1";
+	case MMC_RSP_SPI_R1B:	return "R1B";
+	case MMC_RSP_SPI_R2:	return "R2/R5";
+	case MMC_RSP_SPI_R3:	return "R3/R4/R7";
+	default:		return "?";
+	}
+}
+
+/* return zero, else negative errno after setting cmd->error */
+static int mmc_spi_response_get(struct mmc_spi_host *host,
+		struct mmc_command *cmd, int cs_on)
+{
+	u8	*cp = host->data->status;
+	u8	*end = cp + host->t.len;
+	int	value = 0;
+	char	tag[32];
+
+	snprintf(tag, sizeof(tag), "  ... CMD%d response SPI_%s",
+		cmd->opcode, maptype(cmd));
+
+	/* Except for data block reads, the whole response will already
+	 * be stored in the scratch buffer.  It's somewhere after the
+	 * command and the first byte we read after it.  We ignore that
+	 * first byte.  After STOP_TRANSMISSION command it may include
+	 * two data bits, but otherwise it's all ones.
+	 */
+	cp += 8;
+	while (cp < end && *cp == 0xff)
+		cp++;
+
+	/* Data block reads (R1 response types) may need more data... */
+	if (cp == end) {
+		unsigned	i;
+
+		cp = host->data->status;
+
+		/* Card sends N(CR) (== 1..8) bytes of all-ones then one
+		 * status byte ... and we already scanned 2 bytes.
+		 *
+		 * REVISIT block read paths use nasty byte-at-a-time I/O
+		 * so it can always DMA directly into the target buffer.
+		 * It'd probably be better to memcpy() the first chunk and
+		 * avoid extra i/o calls...
+		 */
+		for (i = 2; i < 9; i++) {
+			value = mmc_spi_readbytes(host, 1);
+			if (value < 0)
+				goto done;
+			if (*cp != 0xff)
+				goto checkstatus;
+		}
+		value = -ETIMEDOUT;
+		goto done;
+	}
+
+checkstatus:
+	if (*cp & 0x80) {
+		dev_dbg(&host->spi->dev, "%s: INVALID RESPONSE, %02x\n",
+					tag, *cp);
+		value = -EBADR;
+		goto done;
+	}
+
+	cmd->resp[0] = *cp++;
+	cmd->error = 0;
+
+	/* Status byte: the entire seven-bit R1 response.  */
+	if (cmd->resp[0] != 0) {
+		if ((R1_SPI_PARAMETER | R1_SPI_ADDRESS
+					| R1_SPI_ILLEGAL_COMMAND)
+				& cmd->resp[0])
+			value = -EINVAL;
+		else if (R1_SPI_COM_CRC & cmd->resp[0])
+			value = -EILSEQ;
+		else if ((R1_SPI_ERASE_SEQ | R1_SPI_ERASE_RESET)
+				& cmd->resp[0])
+			value = -EIO;
+		/* else R1_SPI_IDLE, "it's resetting" */
+	}
+
+	switch (mmc_spi_resp_type(cmd)) {
+
+	/* SPI R1B == R1 + busy; STOP_TRANSMISSION (for multiblock reads)
+	 * and less-common stuff like various erase operations.
+	 */
+	case MMC_RSP_SPI_R1B:
+		/* maybe we read all the busy tokens already */
+		while (cp < end && *cp == 0)
+			cp++;
+		if (cp == end)
+			mmc_spi_wait_unbusy(host, r1b_timeout);
+		break;
+
+	/* SPI R2 == R1 + second status byte; SEND_STATUS
+	 * SPI R5 == R1 + data byte; IO_RW_DIRECT
+	 */
+	case MMC_RSP_SPI_R2:
+		cmd->resp[0] |= *cp << 8;
+		break;
+
+	/* SPI R3, R4, or R7 == R1 + 4 bytes */
+	case MMC_RSP_SPI_R3:
+		cmd->resp[1] = be32_to_cpu(get_unaligned((u32 *)cp));
+		break;
+
+	/* SPI R1 == just one status byte */
+	case MMC_RSP_SPI_R1:
+		break;
+
+	default:
+		dev_dbg(&host->spi->dev, "bad response type %04x\n",
+				mmc_spi_resp_type(cmd));
+		if (value >= 0)
+			value = -EINVAL;
+		goto done;
+	}
+
+	if (value < 0)
+		dev_dbg(&host->spi->dev, "%s: resp %04x %08x\n",
+			tag, cmd->resp[0], cmd->resp[1]);
+
+	/* disable chipselect on errors and some success cases */
+	if (value >= 0 && cs_on)
+		return value;
+done:
+	if (value < 0)
+		cmd->error = value;
+	mmc_cs_off(host);
+	return value;
+}
+
+/* Issue command and read its response.
+ * Returns zero on success, negative for error.
+ *
+ * On error, caller must cope with mmc core retry mechanism.  That
+ * means immediate low-level resubmit, which affects the bus lock...
+ */
+static int
+mmc_spi_command_send(struct mmc_spi_host *host,
+		struct mmc_request *mrq,
+		struct mmc_command *cmd, int cs_on)
+{
+	struct scratch		*data = host->data;
+	u8			*cp = data->status;
+	u32			arg = cmd->arg;
+	int			status;
+	struct spi_transfer	*t;
+
+	/* We can handle most commands (except block reads) in one full
+	 * duplex I/O operation before either starting the next transfer
+	 * (data block or command) or else deselecting the card.
+	 *
+	 * First, write 7 bytes:
+	 *  - an all-ones byte to ensure the card is ready
+	 *  - opcode byte (plus start and transmission bits)
+	 *  - four bytes of big-endian argument
+	 *  - crc7 (plus end bit) ... always computed, it's cheap
+	 *
+	 * We init the whole buffer to all-ones, which is what we need
+	 * to write while we're reading (later) response data.
+	 */
+	memset(cp++, 0xff, sizeof(data->status));
+
+	*cp++ = 0x40 | cmd->opcode;
+	*cp++ = (u8)(arg >> 24);
+	*cp++ = (u8)(arg >> 16);
+	*cp++ = (u8)(arg >> 8);
+	*cp++ = (u8)arg;
+	*cp++ = (crc7(0, &data->status[1], 5) << 1) | 0x01;
+
+	/* Then, read up to 13 bytes (while writing all-ones):
+	 *  - N(CR) (== 1..8) bytes of all-ones
+	 *  - status byte (for all response types)
+	 *  - the rest of the response, either:
+	 *      + nothing, for R1 or R1B responses
+	 *	+ second status byte, for R2 responses
+	 *	+ four data bytes, for R3 and R7 responses
+	 *
+	 * Finally, read some more bytes ... in the nice cases we know in
+	 * advance how many, and reading 1 more is always OK:
+	 *  - N(EC) (== 0..N) bytes of all-ones, before deselect/finish
+	 *  - N(RC) (== 1..N) bytes of all-ones, before next command
+	 *  - N(WR) (== 1..N) bytes of all-ones, before data write
+	 *
+	 * So in those cases one full duplex I/O of at most 21 bytes will
+	 * handle the whole command, leaving the card ready to receive a
+	 * data block or new command.  We do that whenever we can, shaving
+	 * CPU and IRQ costs (especially when using DMA or FIFOs).
+	 *
+	 * There are two other cases, where it's not generally practical
+	 * to rely on a single I/O:
+	 *
+	 *  - R1B responses need at least N(EC) bytes of all-zeroes.
+	 *
+	 *    In this case we can *try* to fit it into one I/O, then
+	 *    maybe read more data later.
+	 *
+	 *  - Data block reads are more troublesome, since a variable
+	 *    number of padding bytes precede the token and data.
+	 *      + N(CX) (== 0..8) bytes of all-ones, before CSD or CID
+	 *      + N(AC) (== 1..many) bytes of all-ones
+	 *
+	 *    In this case we currently only have minimal speedups here:
+	 *    when N(CR) == 1 we can avoid I/O in response_get().
+	 */
+	if (cs_on && (mrq->data->flags & MMC_DATA_READ)) {
+		cp += 2;	/* min(N(CR)) + status */
+		/* R1 */
+	} else {
+		cp += 10;	/* max(N(CR)) + status + min(N(RC),N(WR)) */
+		if (cmd->flags & MMC_RSP_SPI_S2)	/* R2/R5 */
+			cp++;
+		else if (cmd->flags & MMC_RSP_SPI_B4)	/* R3/R4/R7 */
+			cp += 4;
+		else if (cmd->flags & MMC_RSP_BUSY)	/* R1B */
+			cp = data->status + sizeof(data->status);
+		/* else:  R1 (most commands) */
+	}
+
+	dev_dbg(&host->spi->dev, "  mmc_spi: CMD%d, resp %s\n",
+		cmd->opcode, maptype(cmd));
+
+	/* send command, leaving chipselect active */
+	spi_message_init(&host->m);
+
+	t = &host->t;
+	memset(t, 0, sizeof(*t));
+	t->tx_buf = t->rx_buf = data->status;
+	t->tx_dma = t->rx_dma = host->data_dma;
+	t->len = cp - data->status;
+	t->cs_change = 1;
+	spi_message_add_tail(t, &host->m);
+
+	if (host->dma_dev) {
+		host->m.is_dma_mapped = 1;
+		dma_sync_single_for_device(host->dma_dev,
+				host->data_dma, sizeof(*host->data),
+				DMA_BIDIRECTIONAL);
+	}
+	status = spi_sync(host->spi, &host->m);
+	if (status == 0)
+		status = host->m.status;
+
+	if (host->dma_dev)
+		dma_sync_single_for_cpu(host->dma_dev,
+				host->data_dma, sizeof(*host->data),
+				DMA_BIDIRECTIONAL);
+	if (status < 0) {
+		dev_dbg(&host->spi->dev, "  ... write returned %d\n", status);
+		cmd->error = status;
+		return status;
+	}
+
+	/* after no-data commands and STOP_TRANSMISSION, chipselect off */
+	return mmc_spi_response_get(host, cmd, cs_on);
+}
+
+/* Build data message with up to four separate transfers.  For TX, we
+ * start by writing the data token.  And in most cases, we finish with
+ * a status transfer.
+ *
+ * We always provide TX data for data and CRC.  The MMC/SD protocol
+ * requires us to write ones; but Linux defaults to writing zeroes;
+ * so we explicitly initialize it to all ones on RX paths.
+ *
+ * We also handle DMA mapping, so the underlying SPI controller does
+ * not need to (re)do it for each message.
+ */
+static void
+mmc_spi_setup_data_message(
+	struct mmc_spi_host	*host,
+	int			multiple,
+	enum dma_data_direction	direction)
+{
+	struct spi_transfer	*t;
+	struct scratch		*scratch = host->data;
+	dma_addr_t		dma = host->data_dma;
+
+	spi_message_init(&host->m);
+	if (dma)
+		host->m.is_dma_mapped = 1;
+
+	/* for reads, readblock() skips 0xff bytes before finding
+	 * the token; for writes, this transfer issues that token.
+	 */
+	if (direction == DMA_TO_DEVICE) {
+		t = &host->token;
+		memset(t, 0, sizeof(*t));
+		t->len = 1;
+		if (multiple)
+			scratch->data_token = SPI_TOKEN_MULTI_WRITE;
+		else
+			scratch->data_token = SPI_TOKEN_SINGLE;
+		t->tx_buf = &scratch->data_token;
+		if (dma)
+			t->tx_dma = dma + offsetof(struct scratch, data_token);
+		spi_message_add_tail(t, &host->m);
+	}
+
+	/* Body of transfer is buffer, then CRC ...
+	 * either TX-only, or RX with TX-ones.
+	 */
+	t = &host->t;
+	memset(t, 0, sizeof(*t));
+	t->tx_buf = host->ones;
+	t->tx_dma = host->ones_dma;
+	/* length and actual buffer info are written later */
+	spi_message_add_tail(t, &host->m);
+
+	t = &host->crc;
+	memset(t, 0, sizeof(*t));
+	t->len = 2;
+	if (direction == DMA_TO_DEVICE) {
+		/* the actual CRC may get written later */
+		t->tx_buf = &scratch->crc_val;
+		if (dma)
+			t->tx_dma = dma + offsetof(struct scratch, crc_val);
+	} else {
+		t->tx_buf = host->ones;
+		t->tx_dma = host->ones_dma;
+		t->rx_buf = &scratch->crc_val;
+		if (dma)
+			t->rx_dma = dma + offsetof(struct scratch, crc_val);
+	}
+	spi_message_add_tail(t, &host->m);
+
+	/*
+	 * A single block read is followed by N(EC) [0+] all-ones bytes
+	 * before deselect ... don't bother.
+	 *
+	 * Multiblock reads are followed by N(AC) [1+] all-ones bytes before
+	 * the next block is read, or a STOP_TRANSMISSION is issued.  We'll
+	 * collect that single byte, so readblock() doesn't need to.
+	 *
+	 * For a write, the one-byte data response follows immediately, then
+	 * come zero or more busy bytes, then N(WR) [1+] all-ones bytes.
+	 * Then single block reads may deselect, and multiblock ones issue
+	 * the next token (next data block, or STOP_TRAN).  We can try to
+	 * minimize I/O ops by using a single read to collect end-of-busy.
+	 */
+	if (multiple || direction == DMA_TO_DEVICE) {
+		t = &host->early_status;
+		memset(t, 0, sizeof(*t));
+		t->len = (direction == DMA_TO_DEVICE)
+				? sizeof(scratch->status)
+				: 1;
+		t->tx_buf = host->ones;
+		t->tx_dma = host->ones_dma;
+		t->rx_buf = scratch->status;
+		if (dma)
+			t->rx_dma = dma + offsetof(struct scratch, status);
+		t->cs_change = 1;
+		spi_message_add_tail(t, &host->m);
+	}
+}
+
+/*
+ * Write one block:
+ *  - caller handled preceding N(WR) [1+] all-ones bytes
+ *  - data block
+ *	+ token
+ *	+ data bytes
+ *	+ crc16
+ *  - an all-ones byte ... card writes a data-response byte
+ *  - followed by N(EC) [0+] all-ones bytes, card writes zero/'busy'
+ *
+ * Return negative errno, else success.
+ */
+static int
+mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t)
+{
+	struct spi_device	*spi = host->spi;
+	int			status, i;
+	struct scratch		*scratch = host->data;
+
+	if (host->mmc->use_spi_crc)
+		scratch->crc_val = cpu_to_be16(
+				crc_itu_t(0, t->tx_buf, t->len));
+	if (host->dma_dev)
+		dma_sync_single_for_device(host->dma_dev,
+				host->data_dma, sizeof(*scratch),
+				DMA_BIDIRECTIONAL);
+
+	status = spi_sync(spi, &host->m);
+	if (status == 0)
+		status = host->m.status;
+
+	if (status != 0) {
+		dev_dbg(&spi->dev, "write error (%d)\n", status);
+		return status;
+	}
+
+	if (host->dma_dev)
+		dma_sync_single_for_cpu(host->dma_dev,
+				host->data_dma, sizeof(*scratch),
+				DMA_BIDIRECTIONAL);
+
+	/*
+	 * Get the transmission data-response reply.  It must follow
+	 * immediately after the data block we transferred.  This reply
+	 * doesn't necessarily tell whether the write operation succeeded;
+	 * it just says if the transmission was ok and whether *earlier*
+	 * writes succeeded; see the standard.
+	 */
+	switch (SPI_MMC_RESPONSE_CODE(scratch->status[0])) {
+	case SPI_RESPONSE_ACCEPTED:
+		status = 0;
+		break;
+	case SPI_RESPONSE_CRC_ERR:
+		/* host shall then issue MMC_STOP_TRANSMISSION */
+		status = -EILSEQ;
+		break;
+	case SPI_RESPONSE_WRITE_ERR:
+		/* host shall then issue MMC_STOP_TRANSMISSION,
+		 * and should MMC_SEND_STATUS to sort it out
+		 */
+		status = -EIO;
+		break;
+	default:
+		status = -EPROTO;
+		break;
+	}
+	if (status != 0) {
+		dev_dbg(&spi->dev, "write error %02x (%d)\n",
+			scratch->status[0], status);
+		return status;
+	}
+
+	t->tx_buf += t->len;
+	if (host->dma_dev)
+		t->tx_dma += t->len;
+
+	/* Return when not busy.  If we didn't collect that status yet,
+	 * we'll need some more I/O.
+	 */
+	for (i = 1; i < sizeof(scratch->status); i++) {
+		if (scratch->status[i] != 0)
+			return 0;
+	}
+	return mmc_spi_wait_unbusy(host, writeblock_timeout);
+}
+
+/*
+ * Read one block:
+ *  - skip leading all-ones bytes ... either
+ *      + N(AC) [1..f(clock,CSD)] usually, else
+ *      + N(CX) [0..8] when reading CSD or CID
+ *  - data block
+ *	+ token ... if error token, no data or crc
+ *	+ data bytes
+ *	+ crc16
+ *
+ * After single block reads, we're done; N(EC) [0+] all-ones bytes follow
+ * before dropping chipselect.
+ *
+ * For multiblock reads, caller either reads the next block or issues a
+ * STOP_TRANSMISSION command.
+ */
+static int
+mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t)
+{
+	struct spi_device	*spi = host->spi;
+	int			status;
+	struct scratch		*scratch = host->data;
+
+	/* At least one SD card sends an all-zeroes byte when N(CX)
+	 * applies, before the all-ones bytes ... just cope with that.
+	 */
+	status = mmc_spi_readbytes(host, 1);
+	if (status < 0)
+		return status;
+	status = scratch->status[0];
+	if (status == 0xff || status == 0)
+		status = mmc_spi_readtoken(host);
+
+	if (status == SPI_TOKEN_SINGLE) {
+		if (host->dma_dev) {
+			dma_sync_single_for_device(host->dma_dev,
+					host->data_dma, sizeof(*scratch),
+					DMA_BIDIRECTIONAL);
+			dma_sync_single_for_device(host->dma_dev,
+					t->rx_dma, t->len,
+					DMA_FROM_DEVICE);
+		}
+
+		status = spi_sync(spi, &host->m);
+		if (status == 0)
+			status = host->m.status;
+
+		if (host->dma_dev) {
+			dma_sync_single_for_cpu(host->dma_dev,
+					host->data_dma, sizeof(*scratch),
+					DMA_BIDIRECTIONAL);
+			dma_sync_single_for_cpu(host->dma_dev,
+					t->rx_dma, t->len,
+					DMA_FROM_DEVICE);
+		}
+
+	} else {
+		dev_dbg(&spi->dev, "read error %02x (%d)\n", status, status);
+
+		/* we've read extra garbage, timed out, etc */
+		if (status < 0)
+			return status;
+
+		/* low four bits are an R2 subset, fifth seems to be
+		 * vendor specific ... map them all to generic error..
+		 */
+		return -EIO;
+	}
+
+	if (host->mmc->use_spi_crc) {
+		u16 crc = crc_itu_t(0, t->rx_buf, t->len);
+
+		be16_to_cpus(&scratch->crc_val);
+		if (scratch->crc_val != crc) {
+			dev_dbg(&spi->dev, "read - crc error: crc_val=0x%04x, "
+					"computed=0x%04x len=%d\n",
+					scratch->crc_val, crc, t->len);
+			return -EILSEQ;
+		}
+	}
+
+	t->rx_buf += t->len;
+	if (host->dma_dev)
+		t->rx_dma += t->len;
+
+	return 0;
+}
+
+/*
+ * An MMC/SD data stage includes one or more blocks, optional CRCs,
+ * and inline handshaking.  That handhaking makes it unlike most
+ * other SPI protocol stacks.
+ */
+static void
+mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd,
+		struct mmc_data *data, u32 blk_size)
+{
+	struct spi_device	*spi = host->spi;
+	struct device		*dma_dev = host->dma_dev;
+	struct spi_transfer	*t;
+	enum dma_data_direction	direction;
+	struct scatterlist	*sg;
+	unsigned		n_sg;
+	int			multiple = (data->blocks > 1);
+
+	if (data->flags & MMC_DATA_READ)
+		direction = DMA_FROM_DEVICE;
+	else
+		direction = DMA_TO_DEVICE;
+	mmc_spi_setup_data_message(host, multiple, direction);
+	t = &host->t;
+
+	/* Handle scatterlist segments one at a time, with synch for
+	 * each 512-byte block
+	 */
+	for (sg = data->sg, n_sg = data->sg_len; n_sg; n_sg--, sg++) {
+		int			status = 0;
+		dma_addr_t		dma_addr = 0;
+		void			*kmap_addr;
+		unsigned		length = sg->length;
+		enum dma_data_direction	dir = direction;
+
+		/* set up dma mapping for controller drivers that might
+		 * use DMA ... though they may fall back to PIO
+		 */
+		if (dma_dev) {
+			/* never invalidate whole *shared* pages ... */
+			if ((sg->offset != 0 || length != PAGE_SIZE)
+					&& dir == DMA_FROM_DEVICE)
+				dir = DMA_BIDIRECTIONAL;
+
+			dma_addr = dma_map_page(dma_dev, sg->page, 0,
+						PAGE_SIZE, dir);
+			if (direction == DMA_TO_DEVICE)
+				t->tx_dma = dma_addr + sg->offset;
+			else
+				t->rx_dma = dma_addr + sg->offset;
+		}
+
+		/* allow pio too; we don't allow highmem */
+		kmap_addr = kmap(sg->page);
+		if (direction == DMA_TO_DEVICE)
+			t->tx_buf = kmap_addr + sg->offset;
+		else
+			t->rx_buf = kmap_addr + sg->offset;
+
+		/* transfer each block, and update request status */
+		while (length) {
+			t->len = min(length, blk_size);
+
+			dev_dbg(&host->spi->dev,
+				"    mmc_spi: %s block, %d bytes\n",
+				(direction == DMA_TO_DEVICE)
+				? "write"
+				: "read",
+				t->len);
+
+			if (direction == DMA_TO_DEVICE)
+				status = mmc_spi_writeblock(host, t);
+			else
+				status = mmc_spi_readblock(host, t);
+			if (status < 0)
+				break;
+
+			data->bytes_xfered += t->len;
+			length -= t->len;
+
+			if (!multiple)
+				break;
+		}
+
+		/* discard mappings */
+		if (direction == DMA_FROM_DEVICE)
+			flush_kernel_dcache_page(sg->page);
+		kunmap(sg->page);
+		if (dma_dev)
+			dma_unmap_page(dma_dev, dma_addr, PAGE_SIZE, dir);
+
+		if (status < 0) {
+			data->error = status;
+			dev_dbg(&spi->dev, "%s status %d\n",
+				(direction == DMA_TO_DEVICE)
+					? "write" : "read",
+				status);
+			break;
+		}
+	}
+
+	/* NOTE some docs describe an MMC-only SET_BLOCK_COUNT (CMD23) that
+	 * can be issued before multiblock writes.  Unlike its more widely
+	 * documented analogue for SD cards (SET_WR_BLK_ERASE_COUNT, ACMD23),
+	 * that can affect the STOP_TRAN logic.   Complete (and current)
+	 * MMC specs should sort that out before Linux starts using CMD23.
+	 */
+	if (direction == DMA_TO_DEVICE && multiple) {
+		struct scratch	*scratch = host->data;
+		int		tmp;
+		const unsigned	statlen = sizeof(scratch->status);
+
+		dev_dbg(&spi->dev, "    mmc_spi: STOP_TRAN\n");
+
+		/* Tweak the per-block message we set up earlier by morphing
+		 * it to hold single buffer with the token followed by some
+		 * all-ones bytes ... skip N(BR) (0..1), scan the rest for
+		 * "not busy any longer" status, and leave chip selected.
+		 */
+		INIT_LIST_HEAD(&host->m.transfers);
+		list_add(&host->early_status.transfer_list,
+				&host->m.transfers);
+
+		memset(scratch->status, 0xff, statlen);
+		scratch->status[0] = SPI_TOKEN_STOP_TRAN;
+
+		host->early_status.tx_buf = host->early_status.rx_buf;
+		host->early_status.tx_dma = host->early_status.rx_dma;
+		host->early_status.len = statlen;
+
+		if (host->dma_dev)
+			dma_sync_single_for_device(host->dma_dev,
+					host->data_dma, sizeof(*scratch),
+					DMA_BIDIRECTIONAL);
+
+		tmp = spi_sync(spi, &host->m);
+		if (tmp == 0)
+			tmp = host->m.status;
+
+		if (host->dma_dev)
+			dma_sync_single_for_cpu(host->dma_dev,
+					host->data_dma, sizeof(*scratch),
+					DMA_BIDIRECTIONAL);
+
+		if (tmp < 0) {
+			if (!data->error)
+				data->error = tmp;
+			return;
+		}
+
+		/* Ideally we collected "not busy" status with one I/O,
+		 * avoiding wasteful byte-at-a-time scanning... but more
+		 * I/O is often needed.
+		 */
+		for (tmp = 2; tmp < statlen; tmp++) {
+			if (scratch->status[tmp] != 0)
+				return;
+		}
+		tmp = mmc_spi_wait_unbusy(host, writeblock_timeout);
+		if (tmp < 0 && !data->error)
+			data->error = tmp;
+	}
+}
+
+/****************************************************************************/
+
+/*
+ * MMC driver implementation -- the interface to the MMC stack
+ */
+
+static void mmc_spi_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct mmc_spi_host	*host = mmc_priv(mmc);
+	int			status = -EINVAL;
+
+#ifdef DEBUG
+	/* MMC core and layered drivers *MUST* issue SPI-aware commands */
+	{
+		struct mmc_command	*cmd;
+		int			invalid = 0;
+
+		cmd = mrq->cmd;
+		if (!mmc_spi_resp_type(cmd)) {
+			dev_dbg(&host->spi->dev, "bogus command\n");
+			cmd->error = -EINVAL;
+			invalid = 1;
+		}
+
+		cmd = mrq->stop;
+		if (cmd && !mmc_spi_resp_type(cmd)) {
+			dev_dbg(&host->spi->dev, "bogus STOP command\n");
+			cmd->error = -EINVAL;
+			invalid = 1;
+		}
+
+		if (invalid) {
+			dump_stack();
+			mmc_request_done(host->mmc, mrq);
+			return;
+		}
+	}
+#endif
+
+	/* issue command; then optionally data and stop */
+	status = mmc_spi_command_send(host, mrq, mrq->cmd, mrq->data != NULL);
+	if (status == 0 && mrq->data) {
+		mmc_spi_data_do(host, mrq->cmd, mrq->data, mrq->data->blksz);
+		if (mrq->stop)
+			status = mmc_spi_command_send(host, mrq, mrq->stop, 0);
+		else
+			mmc_cs_off(host);
+	}
+
+	mmc_request_done(host->mmc, mrq);
+}
+
+/* See Section 6.4.1, in SD "Simplified Physical Layer Specification 2.0"
+ *
+ * NOTE that here we can't know that the card has just been powered up;
+ * not all MMC/SD sockets support power switching.
+ *
+ * FIXME when the card is still in SPI mode, e.g. from a previous kernel,
+ * this doesn't seem to do the right thing at all...
+ */
+static void mmc_spi_initsequence(struct mmc_spi_host *host)
+{
+	/* Try to be very sure any previous command has completed;
+	 * wait till not-busy, skip debris from any old commands.
+	 */
+	mmc_spi_wait_unbusy(host, r1b_timeout);
+	mmc_spi_readbytes(host, 10);
+
+	/*
+	 * Do a burst with chipselect active-high.  We need to do this to
+	 * meet the requirement of 74 clock cycles with both chipselect
+	 * and CMD (MOSI) high before CMD0 ... after the card has been
+	 * powered up to Vdd(min), and so is ready to take commands.
+	 *
+	 * Some cards are particularly needy of this (e.g. Viking "SD256")
+	 * while most others don't seem to care.
+	 *
+	 * Note that this is one of the places MMC/SD plays games with the
+	 * SPI protocol.  Another is that when chipselect is released while
+	 * the card returns BUSY status, the clock must issue several cycles
+	 * with chipselect high before the card will stop driving its output.
+	 */
+	host->spi->mode |= SPI_CS_HIGH;
+	if (spi_setup(host->spi) != 0) {
+		/* Just warn; most cards work without it. */
+		dev_warn(&host->spi->dev,
+				"can't change chip-select polarity\n");
+		host->spi->mode &= ~SPI_CS_HIGH;
+	} else {
+		mmc_spi_readbytes(host, 18);
+
+		host->spi->mode &= ~SPI_CS_HIGH;
+		if (spi_setup(host->spi) != 0) {
+			/* Wot, we can't get the same setup we had before? */
+			dev_err(&host->spi->dev,
+					"can't restore chip-select polarity\n");
+		}
+	}
+}
+
+static char *mmc_powerstring(u8 power_mode)
+{
+	switch (power_mode) {
+	case MMC_POWER_OFF: return "off";
+	case MMC_POWER_UP:  return "up";
+	case MMC_POWER_ON:  return "on";
+	}
+	return "?";
+}
+
+static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct mmc_spi_host *host = mmc_priv(mmc);
+
+	if (host->power_mode != ios->power_mode) {
+		int		canpower;
+
+		canpower = host->pdata && host->pdata->setpower;
+
+		dev_dbg(&host->spi->dev, "mmc_spi: power %s (%d)%s\n",
+				mmc_powerstring(ios->power_mode),
+				ios->vdd,
+				canpower ? ", can switch" : "");
+
+		/* switch power on/off if possible, accounting for
+		 * max 250msec powerup time if needed.
+		 */
+		if (canpower) {
+			switch (ios->power_mode) {
+			case MMC_POWER_OFF:
+			case MMC_POWER_UP:
+				host->pdata->setpower(&host->spi->dev,
+						ios->vdd);
+				if (ios->power_mode == MMC_POWER_UP)
+					msleep(host->powerup_msecs);
+			}
+		}
+
+		/* See 6.4.1 in the simplified SD card physical spec 2.0 */
+		if (ios->power_mode == MMC_POWER_ON)
+			mmc_spi_initsequence(host);
+
+		/* If powering down, ground all card inputs to avoid power
+		 * delivery from data lines!  On a shared SPI bus, this
+		 * will probably be temporary; 6.4.2 of the simplified SD
+		 * spec says this must last at least 1msec.
+		 *
+		 *   - Clock low means CPOL 0, e.g. mode 0
+		 *   - MOSI low comes from writing zero
+		 *   - Chipselect is usually active low...
+		 */
+		if (canpower && ios->power_mode == MMC_POWER_OFF) {
+			int mres;
+
+			host->spi->mode &= ~(SPI_CPOL|SPI_CPHA);
+			mres = spi_setup(host->spi);
+			if (mres < 0)
+				dev_dbg(&host->spi->dev,
+					"switch to SPI mode 0 failed\n");
+
+			if (spi_w8r8(host->spi, 0x00) < 0)
+				dev_dbg(&host->spi->dev,
+					"put spi signals to low failed\n");
+
+			/*
+			 * Now clock should be low due to spi mode 0;
+			 * MOSI should be low because of written 0x00;
+			 * chipselect should be low (it is active low)
+			 * power supply is off, so now MMC is off too!
+			 *
+			 * FIXME no, chipselect can be high since the
+			 * device is inactive and SPI_CS_HIGH is clear...
+			 */
+			msleep(10);
+			if (mres == 0) {
+				host->spi->mode |= (SPI_CPOL|SPI_CPHA);
+				mres = spi_setup(host->spi);
+				if (mres < 0)
+					dev_dbg(&host->spi->dev,
+						"switch back to SPI mode 3"
+						" failed\n");
+			}
+		}
+
+		host->power_mode = ios->power_mode;
+	}
+
+	if (host->spi->max_speed_hz != ios->clock && ios->clock != 0) {
+		int		status;
+
+		host->spi->max_speed_hz = ios->clock;
+		status = spi_setup(host->spi);
+		dev_dbg(&host->spi->dev,
+			"mmc_spi:  clock to %d Hz, %d\n",
+			host->spi->max_speed_hz, status);
+	}
+}
+
+static int mmc_spi_get_ro(struct mmc_host *mmc)
+{
+	struct mmc_spi_host *host = mmc_priv(mmc);
+
+	if (host->pdata && host->pdata->get_ro)
+		return host->pdata->get_ro(mmc->parent);
+	/* board doesn't support read only detection; assume writeable */
+	return 0;
+}
+
+
+static const struct mmc_host_ops mmc_spi_ops = {
+	.request	= mmc_spi_request,
+	.set_ios	= mmc_spi_set_ios,
+	.get_ro		= mmc_spi_get_ro,
+};
+
+
+/****************************************************************************/
+
+/*
+ * SPI driver implementation
+ */
+
+static irqreturn_t
+mmc_spi_detect_irq(int irq, void *mmc)
+{
+	struct mmc_spi_host *host = mmc_priv(mmc);
+	u16 delay_msec = max(host->pdata->detect_delay, (u16)100);
+
+	mmc_detect_change(mmc, msecs_to_jiffies(delay_msec));
+	return IRQ_HANDLED;
+}
+
+static int mmc_spi_probe(struct spi_device *spi)
+{
+	void			*ones;
+	struct mmc_host		*mmc;
+	struct mmc_spi_host	*host;
+	int			status;
+
+	/* MMC and SD specs only seem to care that sampling is on the
+	 * rising edge ... meaning SPI modes 0 or 3.  So either SPI mode
+	 * should be legit.  We'll use mode 0 since it seems to be a
+	 * bit less troublesome on some hardware ... unclear why.
+	 */
+	spi->mode = SPI_MODE_0;
+	spi->bits_per_word = 8;
+
+	status = spi_setup(spi);
+	if (status < 0) {
+		dev_dbg(&spi->dev, "needs SPI mode %02x, %d KHz; %d\n",
+				spi->mode, spi->max_speed_hz / 1000,
+				status);
+		return status;
+	}
+
+	/* We can use the bus safely iff nobody else will interfere with
+	 * us.  That is, either we have the experimental exclusive access
+	 * primitives ... or else there's nobody to share it with.
+	 */
+	if (spi->master->num_chipselect > 1) {
+		struct device	*parent = spi->dev.parent;
+
+		/* If there are multiple devices on this bus, we
+		 * can't proceed.
+		 */
+		spin_lock(&parent->klist_children.k_lock);
+		if (parent->klist_children.k_list.next
+				!= parent->klist_children.k_list.prev)
+			status = -EMLINK;
+		else
+			status = 0;
+		spin_unlock(&parent->klist_children.k_lock);
+		if (status < 0) {
+			dev_err(&spi->dev, "can't share SPI bus\n");
+			return status;
+		}
+
+		/* REVISIT we can't guarantee another device won't
+		 * be added later.  It's uncommon though ... for now,
+		 * work as if this is safe.
+		 */
+		dev_warn(&spi->dev, "ASSUMING unshared SPI bus!\n");
+	}
+
+	/* We need a supply of ones to transmit.  This is the only time
+	 * the CPU touches these, so cache coherency isn't a concern.
+	 *
+	 * NOTE if many systems use more than one MMC-over-SPI connector
+	 * it'd save some memory to share this.  That's evidently rare.
+	 */
+	status = -ENOMEM;
+	ones = kmalloc(MMC_SPI_BLOCKSIZE, GFP_KERNEL);
+	if (!ones)
+		goto nomem;
+	memset(ones, 0xff, MMC_SPI_BLOCKSIZE);
+
+	mmc = mmc_alloc_host(sizeof(*host), &spi->dev);
+	if (!mmc)
+		goto nomem;
+
+	mmc->ops = &mmc_spi_ops;
+	mmc->max_blk_size = MMC_SPI_BLOCKSIZE;
+
+	/* As long as we keep track of the number of successfully
+	 * transmitted blocks, we're good for multiwrite.
+	 */
+	mmc->caps = MMC_CAP_SPI | MMC_CAP_MULTIWRITE;
+
+	/* SPI doesn't need the lowspeed device identification thing for
+	 * MMC or SD cards, since it never comes up in open drain mode.
+	 * That's good; some SPI masters can't handle very low speeds!
+	 *
+	 * However, low speed SDIO cards need not handle over 400 KHz;
+	 * that's the only reason not to use a few MHz for f_min (until
+	 * the upper layer reads the target frequency from the CSD).
+	 */
+	mmc->f_min = 400000;
+	mmc->f_max = spi->max_speed_hz;
+
+	host = mmc_priv(mmc);
+	host->mmc = mmc;
+	host->spi = spi;
+
+	host->ones = ones;
+
+	/* Platform data is used to hook up things like card sensing
+	 * and power switching gpios.
+	 */
+	host->pdata = spi->dev.platform_data;
+	if (host->pdata)
+		mmc->ocr_avail = host->pdata->ocr_mask;
+	if (!mmc->ocr_avail) {
+		dev_warn(&spi->dev, "ASSUMING 3.2-3.4 V slot power\n");
+		mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+	}
+	if (host->pdata && host->pdata->setpower) {
+		host->powerup_msecs = host->pdata->powerup_msecs;
+		if (!host->powerup_msecs || host->powerup_msecs > 250)
+			host->powerup_msecs = 250;
+	}
+
+	dev_set_drvdata(&spi->dev, mmc);
+
+	/* preallocate dma buffers */
+	host->data = kmalloc(sizeof(*host->data), GFP_KERNEL);
+	if (!host->data)
+		goto fail_nobuf1;
+
+	if (spi->master->cdev.dev->dma_mask) {
+		struct device	*dev = spi->master->cdev.dev;
+
+		host->dma_dev = dev;
+		host->ones_dma = dma_map_single(dev, ones,
+				MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
+		host->data_dma = dma_map_single(dev, host->data,
+				sizeof(*host->data), DMA_BIDIRECTIONAL);
+
+		/* REVISIT in theory those map operations can fail... */
+
+		dma_sync_single_for_cpu(host->dma_dev,
+				host->data_dma, sizeof(*host->data),
+				DMA_BIDIRECTIONAL);
+	}
+
+	/* setup message for status/busy readback */
+	spi_message_init(&host->readback);
+	host->readback.is_dma_mapped = (host->dma_dev != NULL);
+
+	spi_message_add_tail(&host->status, &host->readback);
+	host->status.tx_buf = host->ones;
+	host->status.tx_dma = host->ones_dma;
+	host->status.rx_buf = &host->data->status;
+	host->status.rx_dma = host->data_dma + offsetof(struct scratch, status);
+	host->status.cs_change = 1;
+
+	/* register card detect irq */
+	if (host->pdata && host->pdata->init) {
+		status = host->pdata->init(&spi->dev, mmc_spi_detect_irq, mmc);
+		if (status != 0)
+			goto fail_glue_init;
+	}
+
+	status = mmc_add_host(mmc);
+	if (status != 0)
+		goto fail_add_host;
+
+	dev_info(&spi->dev, "SD/MMC host %s%s%s%s\n",
+			mmc->class_dev.bus_id,
+			host->dma_dev ? "" : ", no DMA",
+			(host->pdata && host->pdata->get_ro)
+				? "" : ", no WP",
+			(host->pdata && host->pdata->setpower)
+				? "" : ", no poweroff");
+	return 0;
+
+fail_add_host:
+	mmc_remove_host (mmc);
+fail_glue_init:
+	if (host->dma_dev)
+		dma_unmap_single(host->dma_dev, host->data_dma,
+				sizeof(*host->data), DMA_BIDIRECTIONAL);
+	kfree(host->data);
+
+fail_nobuf1:
+	mmc_free_host(mmc);
+	dev_set_drvdata(&spi->dev, NULL);
+
+nomem:
+	kfree(ones);
+	return status;
+}
+
+
+static int __devexit mmc_spi_remove(struct spi_device *spi)
+{
+	struct mmc_host		*mmc = dev_get_drvdata(&spi->dev);
+	struct mmc_spi_host	*host;
+
+	if (mmc) {
+		host = mmc_priv(mmc);
+
+		/* prevent new mmc_detect_change() calls */
+		if (host->pdata && host->pdata->exit)
+			host->pdata->exit(&spi->dev, mmc);
+
+		mmc_remove_host(mmc);
+
+		if (host->dma_dev) {
+			dma_unmap_single(host->dma_dev, host->ones_dma,
+				MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
+			dma_unmap_single(host->dma_dev, host->data_dma,
+				sizeof(*host->data), DMA_BIDIRECTIONAL);
+		}
+
+		kfree(host->data);
+		kfree(host->ones);
+
+		spi->max_speed_hz = mmc->f_max;
+		mmc_free_host(mmc);
+		dev_set_drvdata(&spi->dev, NULL);
+	}
+	return 0;
+}
+
+
+static struct spi_driver mmc_spi_driver = {
+	.driver = {
+		.name =		"mmc_spi",
+		.bus =		&spi_bus_type,
+		.owner =	THIS_MODULE,
+	},
+	.probe =	mmc_spi_probe,
+	.remove =	__devexit_p(mmc_spi_remove),
+};
+
+
+static int __init mmc_spi_init(void)
+{
+	return spi_register_driver(&mmc_spi_driver);
+}
+module_init(mmc_spi_init);
+
+
+static void __exit mmc_spi_exit(void)
+{
+	spi_unregister_driver(&mmc_spi_driver);
+}
+module_exit(mmc_spi_exit);
+
+
+MODULE_AUTHOR("Mike Lavender, David Brownell, "
+		"Hans-Peter Nilsson, Jan Nikitenko");
+MODULE_DESCRIPTION("SPI SD/MMC host driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index d11c2d2..d0eb0a2 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mmc/mmci.c - ARM PrimeCell MMCI PL180/1 driver
+ *  linux/drivers/mmc/host/mmci.c - ARM PrimeCell MMCI PL180/1 driver
  *
  *  Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
  *
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/highmem.h>
+#include <linux/log2.h>
 #include <linux/mmc/host.h>
 #include <linux/amba/bus.h>
 #include <linux/clk.h>
@@ -154,11 +155,11 @@
 	}
 	if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
 		if (status & MCI_DATACRCFAIL)
-			data->error = MMC_ERR_BADCRC;
+			data->error = -EILSEQ;
 		else if (status & MCI_DATATIMEOUT)
-			data->error = MMC_ERR_TIMEOUT;
+			data->error = -ETIMEDOUT;
 		else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
-			data->error = MMC_ERR_FIFO;
+			data->error = -EIO;
 		status |= MCI_DATAEND;
 
 		/*
@@ -193,12 +194,12 @@
 	cmd->resp[3] = readl(base + MMCIRESPONSE3);
 
 	if (status & MCI_CMDTIMEOUT) {
-		cmd->error = MMC_ERR_TIMEOUT;
+		cmd->error = -ETIMEDOUT;
 	} else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) {
-		cmd->error = MMC_ERR_BADCRC;
+		cmd->error = -EILSEQ;
 	}
 
-	if (!cmd->data || cmd->error != MMC_ERR_NONE) {
+	if (!cmd->data || cmd->error) {
 		if (host->data)
 			mmci_stop_data(host);
 		mmci_request_end(host, cmd->mrq);
@@ -391,6 +392,14 @@
 
 	WARN_ON(host->mrq != NULL);
 
+	if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
+		printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n",
+			mmc_hostname(mmc), mrq->data->blksz);
+		mrq->cmd->error = -EINVAL;
+		mmc_request_done(mmc, mrq);
+		return;
+	}
+
 	spin_lock_irq(&host->lock);
 
 	host->mrq = mrq;
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 6d7eadc..000e6a9 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mmc/mmci.h - ARM PrimeCell MMCI PL180/1 driver
+ *  linux/drivers/mmc/host/mmci.h - ARM PrimeCell MMCI PL180/1 driver
  *
  *  Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
  *
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index b0824a3..60a67df 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/media/mmc/omap.c
+ *  linux/drivers/mmc/host/omap.c
  *
  *  Copyright (C) 2004 Nokia Corporation
  *  Written by Tuukka Tikkanen and Juha Yrjölä<juha.yrjola@nokia.com>
@@ -263,7 +263,7 @@
 		enum dma_data_direction dma_data_dir;
 
 		BUG_ON(host->dma_ch < 0);
-		if (data->error != MMC_ERR_NONE)
+		if (data->error)
 			omap_stop_dma(host->dma_ch);
 		/* Release DMA channel lazily */
 		mod_timer(&host->dma_timer, jiffies + HZ);
@@ -368,7 +368,7 @@
 		}
 	}
 
-	if (host->data == NULL || cmd->error != MMC_ERR_NONE) {
+	if (host->data == NULL || cmd->error) {
 		host->mrq = NULL;
 		clk_disable(host->fclk);
 		mmc_request_done(host->mmc, cmd->mrq);
@@ -475,14 +475,14 @@
 		if (status & OMAP_MMC_STAT_DATA_TOUT) {
 			dev_dbg(mmc_dev(host->mmc), "data timeout\n");
 			if (host->data) {
-				host->data->error |= MMC_ERR_TIMEOUT;
+				host->data->error = -ETIMEDOUT;
 				transfer_error = 1;
 			}
 		}
 
 		if (status & OMAP_MMC_STAT_DATA_CRC) {
 			if (host->data) {
-				host->data->error |= MMC_ERR_BADCRC;
+				host->data->error = -EILSEQ;
 				dev_dbg(mmc_dev(host->mmc),
 					 "data CRC error, bytes left %d\n",
 					host->total_bytes_left);
@@ -504,7 +504,7 @@
 					dev_err(mmc_dev(host->mmc),
 						"command timeout, CMD %d\n",
 						host->cmd->opcode);
-				host->cmd->error = MMC_ERR_TIMEOUT;
+				host->cmd->error = -ETIMEDOUT;
 				end_command = 1;
 			}
 		}
@@ -514,7 +514,7 @@
 				dev_err(mmc_dev(host->mmc),
 					"command CRC error (CMD%d, arg 0x%08x)\n",
 					host->cmd->opcode, host->cmd->arg);
-				host->cmd->error = MMC_ERR_BADCRC;
+				host->cmd->error = -EILSEQ;
 				end_command = 1;
 			} else
 				dev_err(mmc_dev(host->mmc),
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index f8985c5..657901e 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mmc/pxa.c - PXA MMCI driver
+ *  linux/drivers/mmc/host/pxa.c - PXA MMCI driver
  *
  *  Copyright (C) 2003 Russell King, All Rights Reserved.
  *
@@ -142,6 +142,10 @@
 				   host->dma_dir);
 
 	for (i = 0; i < host->dma_len; i++) {
+		unsigned int length = sg_dma_len(&data->sg[i]);
+		host->sg_cpu[i].dcmd = dcmd | length;
+		if (length & 31 && !(data->flags & MMC_DATA_READ))
+			host->sg_cpu[i].dcmd |= DCMD_ENDIRQEN;
 		if (data->flags & MMC_DATA_READ) {
 			host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
 			host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
@@ -149,7 +153,6 @@
 			host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
 			host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
 		}
-		host->sg_cpu[i].dcmd = dcmd | sg_dma_len(&data->sg[i]);
 		host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
 					sizeof(struct pxa_dma_desc);
 	}
@@ -226,7 +229,7 @@
 	}
 
 	if (stat & STAT_TIME_OUT_RESPONSE) {
-		cmd->error = MMC_ERR_TIMEOUT;
+		cmd->error = -ETIMEDOUT;
 	} else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
 #ifdef CONFIG_PXA27x
 		/*
@@ -239,11 +242,11 @@
 			pr_debug("ignoring CRC from command %d - *risky*\n", cmd->opcode);
 		} else
 #endif
-		cmd->error = MMC_ERR_BADCRC;
+		cmd->error = -EILSEQ;
 	}
 
 	pxamci_disable_irq(host, END_CMD_RES);
-	if (host->data && cmd->error == MMC_ERR_NONE) {
+	if (host->data && !cmd->error) {
 		pxamci_enable_irq(host, DATA_TRAN_DONE);
 	} else {
 		pxamci_finish_request(host, host->mrq);
@@ -264,9 +267,9 @@
 		     host->dma_dir);
 
 	if (stat & STAT_READ_TIME_OUT)
-		data->error = MMC_ERR_TIMEOUT;
+		data->error = -ETIMEDOUT;
 	else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
-		data->error = MMC_ERR_BADCRC;
+		data->error = -EILSEQ;
 
 	/*
 	 * There appears to be a hardware design bug here.  There seems to
@@ -274,7 +277,7 @@
 	 * This means that if there was an error on any block, we mark all
 	 * data blocks as being in error.
 	 */
-	if (data->error == MMC_ERR_NONE)
+	if (!data->error)
 		data->bytes_xfered = data->blocks * data->blksz;
 	else
 		data->bytes_xfered = 0;
@@ -284,7 +287,7 @@
 	host->data = NULL;
 	if (host->mrq->stop) {
 		pxamci_stop_clock(host);
-		pxamci_start_cmd(host, host->mrq->stop, 0);
+		pxamci_start_cmd(host, host->mrq->stop, host->cmdat);
 	} else {
 		pxamci_finish_request(host, host->mrq);
 	}
@@ -298,7 +301,7 @@
 	unsigned int ireg;
 	int handled = 0;
 
-	ireg = readl(host->base + MMC_I_REG);
+	ireg = readl(host->base + MMC_I_REG) & ~readl(host->base + MMC_I_MASK);
 
 	if (ireg) {
 		unsigned stat = readl(host->base + MMC_STAT);
@@ -309,6 +312,10 @@
 			handled |= pxamci_cmd_done(host, stat);
 		if (ireg & DATA_TRAN_DONE)
 			handled |= pxamci_data_done(host, stat);
+		if (ireg & SDIO_INT) {
+			mmc_signal_sdio_irq(host->mmc);
+			handled = 1;
+		}
 	}
 
 	return IRQ_RETVAL(handled);
@@ -382,20 +389,46 @@
 			host->cmdat |= CMDAT_INIT;
 	}
 
+	if (ios->bus_width == MMC_BUS_WIDTH_4)
+		host->cmdat |= CMDAT_SD_4DAT;
+	else
+		host->cmdat &= ~CMDAT_SD_4DAT;
+
 	pr_debug("PXAMCI: clkrt = %x cmdat = %x\n",
 		 host->clkrt, host->cmdat);
 }
 
+static void pxamci_enable_sdio_irq(struct mmc_host *host, int enable)
+{
+	struct pxamci_host *pxa_host = mmc_priv(host);
+
+	if (enable)
+		pxamci_enable_irq(pxa_host, SDIO_INT);
+	else
+		pxamci_disable_irq(pxa_host, SDIO_INT);
+}
+
 static const struct mmc_host_ops pxamci_ops = {
-	.request	= pxamci_request,
-	.get_ro		= pxamci_get_ro,
-	.set_ios	= pxamci_set_ios,
+	.request		= pxamci_request,
+	.get_ro			= pxamci_get_ro,
+	.set_ios		= pxamci_set_ios,
+	.enable_sdio_irq	= pxamci_enable_sdio_irq,
 };
 
 static void pxamci_dma_irq(int dma, void *devid)
 {
-	printk(KERN_ERR "DMA%d: IRQ???\n", dma);
-	DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
+	struct pxamci_host *host = devid;
+	int dcsr = DCSR(dma);
+	DCSR(dma) = dcsr & ~DCSR_STOPIRQEN;
+
+	if (dcsr & DCSR_ENDINTR) {
+		writel(BUF_PART_FULL, host->base + MMC_PRTBUF);
+	} else {
+		printk(KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
+		       mmc_hostname(host->mmc), dma, dcsr);
+		host->data->error = -EIO;
+		pxamci_data_done(host, 0);
+	}
 }
 
 static irqreturn_t pxamci_detect_irq(int irq, void *devid)
@@ -444,9 +477,9 @@
 	mmc->max_seg_size = PAGE_SIZE;
 
 	/*
-	 * Block length register is 10 bits.
+	 * Block length register is only 10 bits before PXA27x.
 	 */
-	mmc->max_blk_size = 1023;
+	mmc->max_blk_size = (cpu_is_pxa21x() || cpu_is_pxa25x()) ? 1023 : 2048;
 
 	/*
 	 * Block count register is 16 bits.
@@ -460,6 +493,12 @@
 	mmc->ocr_avail = host->pdata ?
 			 host->pdata->ocr_mask :
 			 MMC_VDD_32_33|MMC_VDD_33_34;
+	mmc->caps = 0;
+	host->cmdat = 0;
+	if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) {
+		mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
+		host->cmdat |= CMDAT_SDIO_INT_EN;
+	}
 
 	host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
 	if (!host->sg_cpu) {
diff --git a/drivers/mmc/host/pxamci.h b/drivers/mmc/host/pxamci.h
index df17c28..3153e77 100644
--- a/drivers/mmc/host/pxamci.h
+++ b/drivers/mmc/host/pxamci.h
@@ -25,6 +25,8 @@
 #define SPI_EN			(1 << 0)
 
 #define MMC_CMDAT	0x0010
+#define CMDAT_SDIO_INT_EN	(1 << 11)
+#define CMDAT_SD_4DAT		(1 << 8)
 #define CMDAT_DMAEN		(1 << 7)
 #define CMDAT_INIT		(1 << 6)
 #define CMDAT_BUSY		(1 << 5)
diff --git a/drivers/mmc/host/ricoh_mmc.c b/drivers/mmc/host/ricoh_mmc.c
new file mode 100644
index 0000000..1e87045
--- /dev/null
+++ b/drivers/mmc/host/ricoh_mmc.c
@@ -0,0 +1,151 @@
+/*
+ *  ricoh_mmc.c - Dummy driver to disable the Rioch MMC controller.
+ *
+ *  Copyright (C) 2007 Philip Langdale, All Rights Reserved.
+ *
+ * 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 is a conceptually ridiculous driver, but it is required by the way
+ * the Ricoh multi-function R5C832 works. This chip implements firewire
+ * and four different memory card controllers. Two of those controllers are
+ * an SDHCI controller and a proprietary MMC controller. The linux SDHCI
+ * driver supports MMC cards but the chip detects MMC cards in hardware
+ * and directs them to the MMC controller - so the SDHCI driver never sees
+ * them. To get around this, we must disable the useless MMC controller.
+ * At that point, the SDHCI controller will start seeing them. As a bonus,
+ * a detection event occurs immediately, even if the MMC card is already
+ * in the reader.
+ *
+ * The relevant registers live on the firewire function, so this is unavoidably
+ * ugly. Such is life.
+ */
+
+#include <linux/pci.h>
+
+#define DRIVER_NAME "ricoh-mmc"
+
+static const struct pci_device_id pci_ids[] __devinitdata = {
+	{
+		.vendor		= PCI_VENDOR_ID_RICOH,
+		.device		= PCI_DEVICE_ID_RICOH_R5C843,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	},
+	{ /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+static int __devinit ricoh_mmc_probe(struct pci_dev *pdev,
+				     const struct pci_device_id *ent)
+{
+	u8 rev;
+
+	struct pci_dev *fw_dev = NULL;
+
+	BUG_ON(pdev == NULL);
+	BUG_ON(ent == NULL);
+
+	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
+
+	printk(KERN_INFO DRIVER_NAME
+		": Ricoh MMC controller found at %s [%04x:%04x] (rev %x)\n",
+		pci_name(pdev), (int)pdev->vendor, (int)pdev->device,
+		(int)rev);
+
+	while ((fw_dev = pci_get_device(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, fw_dev))) {
+		if (PCI_SLOT(pdev->devfn) == PCI_SLOT(fw_dev->devfn) &&
+		    pdev->bus == fw_dev->bus) {
+			u8 write_enable;
+			u8 disable;
+
+			pci_read_config_byte(fw_dev, 0xCB, &disable);
+			if (disable & 0x02) {
+				printk(KERN_INFO DRIVER_NAME
+				       ": Controller already disabled. Nothing to do.\n");
+				return -ENODEV;
+			}
+
+			pci_read_config_byte(fw_dev, 0xCA, &write_enable);
+			pci_write_config_byte(fw_dev, 0xCA, 0x57);
+			pci_write_config_byte(fw_dev, 0xCB, disable | 0x02);
+			pci_write_config_byte(fw_dev, 0xCA, write_enable);
+
+			pci_set_drvdata(pdev, fw_dev);
+
+			printk(KERN_INFO DRIVER_NAME
+			       ": Controller is now disabled.\n");
+
+			break;
+		}
+	}
+
+	if (pci_get_drvdata(pdev) == NULL) {
+		printk(KERN_WARNING DRIVER_NAME
+		       ": Main firewire function not found. Cannot disable controller.\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void __devexit ricoh_mmc_remove(struct pci_dev *pdev)
+{
+	u8 write_enable;
+	u8 disable;
+	struct pci_dev *fw_dev = NULL;
+
+	fw_dev = pci_get_drvdata(pdev);
+	BUG_ON(fw_dev == NULL);
+
+	pci_read_config_byte(fw_dev, 0xCA, &write_enable);
+	pci_read_config_byte(fw_dev, 0xCB, &disable);
+	pci_write_config_byte(fw_dev, 0xCA, 0x57);
+	pci_write_config_byte(fw_dev, 0xCB, disable & ~0x02);
+	pci_write_config_byte(fw_dev, 0xCA, write_enable);
+
+	printk(KERN_INFO DRIVER_NAME
+	       ": Controller is now re-enabled.\n");
+
+	pci_set_drvdata(pdev, NULL);
+}
+
+static struct pci_driver ricoh_mmc_driver = {
+	.name = 	DRIVER_NAME,
+	.id_table =	pci_ids,
+	.probe = 	ricoh_mmc_probe,
+	.remove =	__devexit_p(ricoh_mmc_remove),
+};
+
+/*****************************************************************************\
+ *                                                                           *
+ * Driver init/exit                                                          *
+ *                                                                           *
+\*****************************************************************************/
+
+static int __init ricoh_mmc_drv_init(void)
+{
+	printk(KERN_INFO DRIVER_NAME
+		": Ricoh MMC Controller disabling driver\n");
+	printk(KERN_INFO DRIVER_NAME ": Copyright(c) Philip Langdale\n");
+
+	return pci_register_driver(&ricoh_mmc_driver);
+}
+
+static void __exit ricoh_mmc_drv_exit(void)
+{
+	pci_unregister_driver(&ricoh_mmc_driver);
+}
+
+module_init(ricoh_mmc_drv_init);
+module_exit(ricoh_mmc_drv_exit);
+
+MODULE_AUTHOR("Philip Langdale <philipl@alumni.utexas.net>");
+MODULE_DESCRIPTION("Ricoh MMC Controller disabling driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 10d15c3..b397121 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mmc/sdhci.c - Secure Digital Host Controller Interface driver
+ *  linux/drivers/mmc/host/sdhci.c - Secure Digital Host Controller Interface driver
  *
  *  Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
  *
@@ -25,8 +25,6 @@
 #define DBG(f, x...) \
 	pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
 
-static unsigned int debug_nodma = 0;
-static unsigned int debug_forcedma = 0;
 static unsigned int debug_quirks = 0;
 
 #define SDHCI_QUIRK_CLOCK_BEFORE_RESET			(1<<0)
@@ -34,6 +32,8 @@
 /* Controller doesn't like some resets when there is no card inserted. */
 #define SDHCI_QUIRK_NO_CARD_NO_RESET			(1<<2)
 #define SDHCI_QUIRK_SINGLE_POWER_WRITE			(1<<3)
+#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS		(1<<4)
+#define SDHCI_QUIRK_BROKEN_DMA				(1<<5)
 
 static const struct pci_device_id pci_ids[] __devinitdata = {
 	{
@@ -67,7 +67,8 @@
 		.device		= PCI_DEVICE_ID_ENE_CB712_SD,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
-		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE,
+		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE |
+				  SDHCI_QUIRK_BROKEN_DMA,
 	},
 
 	{
@@ -75,7 +76,26 @@
 		.device		= PCI_DEVICE_ID_ENE_CB712_SD_2,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
-		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE,
+		.driver_data	= SDHCI_QUIRK_SINGLE_POWER_WRITE |
+				  SDHCI_QUIRK_BROKEN_DMA,
+	},
+
+	{
+		.vendor         = PCI_VENDOR_ID_ENE,
+		.device         = PCI_DEVICE_ID_ENE_CB714_SD,
+		.subvendor      = PCI_ANY_ID,
+		.subdevice      = PCI_ANY_ID,
+		.driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE |
+				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
+	},
+
+	{
+		.vendor         = PCI_VENDOR_ID_ENE,
+		.device         = PCI_DEVICE_ID_ENE_CB714_SD_2,
+		.subvendor      = PCI_ANY_ID,
+		.subdevice      = PCI_ANY_ID,
+		.driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE |
+				  SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS,
 	},
 
 	{	/* Generic SD host controller */
@@ -113,7 +133,7 @@
 		readb(host->ioaddr + SDHCI_POWER_CONTROL),
 		readb(host->ioaddr + SDHCI_BLOCK_GAP_CONTROL));
 	printk(KERN_DEBUG DRIVER_NAME ": Wake-up:  0x%08x | Clock:    0x%08x\n",
-		readb(host->ioaddr + SDHCI_WALK_UP_CONTROL),
+		readb(host->ioaddr + SDHCI_WAKE_UP_CONTROL),
 		readw(host->ioaddr + SDHCI_CLOCK_CONTROL));
 	printk(KERN_DEBUG DRIVER_NAME ": Timeout:  0x%08x | Int stat: 0x%08x\n",
 		readb(host->ioaddr + SDHCI_TIMEOUT_CONTROL),
@@ -361,16 +381,14 @@
 	if (data == NULL)
 		return;
 
-	DBG("blksz %04x blks %04x flags %08x\n",
-		data->blksz, data->blocks, data->flags);
-	DBG("tsac %d ms nsac %d clk\n",
-		data->timeout_ns / 1000000, data->timeout_clks);
-
 	/* Sanity checks */
 	BUG_ON(data->blksz * data->blocks > 524288);
 	BUG_ON(data->blksz > host->mmc->max_blk_size);
 	BUG_ON(data->blocks > 65535);
 
+	host->data = data;
+	host->data_early = 0;
+
 	/* timeout in us */
 	target_timeout = data->timeout_ns / 1000 +
 		data->timeout_clks / host->clock;
@@ -429,11 +447,11 @@
 {
 	u16 mode;
 
-	WARN_ON(host->data);
-
 	if (data == NULL)
 		return;
 
+	WARN_ON(!host->data);
+
 	mode = SDHCI_TRNS_BLK_CNT_EN;
 	if (data->blocks > 1)
 		mode |= SDHCI_TRNS_MULTI;
@@ -463,27 +481,25 @@
 	/*
 	 * Controller doesn't count down when in single block mode.
 	 */
-	if ((data->blocks == 1) && (data->error == MMC_ERR_NONE))
-		blocks = 0;
+	if (data->blocks == 1)
+		blocks = (data->error == 0) ? 0 : 1;
 	else
 		blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT);
 	data->bytes_xfered = data->blksz * (data->blocks - blocks);
 
-	if ((data->error == MMC_ERR_NONE) && blocks) {
+	if (!data->error && blocks) {
 		printk(KERN_ERR "%s: Controller signalled completion even "
 			"though there were blocks left.\n",
 			mmc_hostname(host->mmc));
-		data->error = MMC_ERR_FAILED;
+		data->error = -EIO;
 	}
 
-	DBG("Ending data transfer (%d bytes)\n", data->bytes_xfered);
-
 	if (data->stop) {
 		/*
 		 * The controller needs a reset of internal state machines
 		 * upon error conditions.
 		 */
-		if (data->error != MMC_ERR_NONE) {
+		if (data->error) {
 			sdhci_reset(host, SDHCI_RESET_CMD);
 			sdhci_reset(host, SDHCI_RESET_DATA);
 		}
@@ -501,8 +517,6 @@
 
 	WARN_ON(host->cmd);
 
-	DBG("Sending cmd (%x)\n", cmd->opcode);
-
 	/* Wait max 10 ms */
 	timeout = 10;
 
@@ -520,7 +534,7 @@
 			printk(KERN_ERR "%s: Controller never released "
 				"inhibit bit(s).\n", mmc_hostname(host->mmc));
 			sdhci_dumpregs(host);
-			cmd->error = MMC_ERR_FAILED;
+			cmd->error = -EIO;
 			tasklet_schedule(&host->finish_tasklet);
 			return;
 		}
@@ -541,7 +555,7 @@
 	if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
 		printk(KERN_ERR "%s: Unsupported response type!\n",
 			mmc_hostname(host->mmc));
-		cmd->error = MMC_ERR_INVALID;
+		cmd->error = -EINVAL;
 		tasklet_schedule(&host->finish_tasklet);
 		return;
 	}
@@ -588,13 +602,12 @@
 		}
 	}
 
-	host->cmd->error = MMC_ERR_NONE;
+	host->cmd->error = 0;
 
-	DBG("Ending cmd (%x)\n", host->cmd->opcode);
+	if (host->data && host->data_early)
+		sdhci_finish_data(host);
 
-	if (host->cmd->data)
-		host->data = host->cmd->data;
-	else
+	if (!host->cmd->data)
 		tasklet_schedule(&host->finish_tasklet);
 
 	host->cmd = NULL;
@@ -710,7 +723,7 @@
 	host->mrq = mrq;
 
 	if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) {
-		host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+		host->mrq->cmd->error = -ENOMEDIUM;
 		tasklet_schedule(&host->finish_tasklet);
 	} else
 		sdhci_send_command(host, mrq->cmd);
@@ -759,6 +772,14 @@
 
 	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
 
+	/*
+	 * Some (ENE) controllers go apeshit on some ios operation,
+	 * signalling timeout and CRC errors even on CMD0. Resetting
+	 * it on each ios seems to solve the problem.
+	 */
+	if(host->chip->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
+		sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+
 	mmiowb();
 	spin_unlock_irqrestore(&host->lock, flags);
 }
@@ -780,10 +801,35 @@
 	return !(present & SDHCI_WRITE_PROTECT);
 }
 
+static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+	struct sdhci_host *host;
+	unsigned long flags;
+	u32 ier;
+
+	host = mmc_priv(mmc);
+
+	spin_lock_irqsave(&host->lock, flags);
+
+	ier = readl(host->ioaddr + SDHCI_INT_ENABLE);
+
+	ier &= ~SDHCI_INT_CARD_INT;
+	if (enable)
+		ier |= SDHCI_INT_CARD_INT;
+
+	writel(ier, host->ioaddr + SDHCI_INT_ENABLE);
+	writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE);
+
+	mmiowb();
+
+	spin_unlock_irqrestore(&host->lock, flags);
+}
+
 static const struct mmc_host_ops sdhci_ops = {
 	.request	= sdhci_request,
 	.set_ios	= sdhci_set_ios,
 	.get_ro		= sdhci_get_ro,
+	.enable_sdio_irq = sdhci_enable_sdio_irq,
 };
 
 /*****************************************************************************\
@@ -811,7 +857,7 @@
 			sdhci_reset(host, SDHCI_RESET_CMD);
 			sdhci_reset(host, SDHCI_RESET_DATA);
 
-			host->mrq->cmd->error = MMC_ERR_FAILED;
+			host->mrq->cmd->error = -ENOMEDIUM;
 			tasklet_schedule(&host->finish_tasklet);
 		}
 	}
@@ -835,15 +881,13 @@
 
 	mrq = host->mrq;
 
-	DBG("Ending request, cmd (%x)\n", mrq->cmd->opcode);
-
 	/*
 	 * The controller needs a reset of internal state machines
 	 * upon error conditions.
 	 */
-	if ((mrq->cmd->error != MMC_ERR_NONE) ||
-		(mrq->data && ((mrq->data->error != MMC_ERR_NONE) ||
-		(mrq->data->stop && (mrq->data->stop->error != MMC_ERR_NONE))))) {
+	if (mrq->cmd->error ||
+		(mrq->data && (mrq->data->error ||
+		(mrq->data->stop && mrq->data->stop->error)))) {
 
 		/* Some controllers need this kick or reset won't work here */
 		if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
@@ -888,13 +932,13 @@
 		sdhci_dumpregs(host);
 
 		if (host->data) {
-			host->data->error = MMC_ERR_TIMEOUT;
+			host->data->error = -ETIMEDOUT;
 			sdhci_finish_data(host);
 		} else {
 			if (host->cmd)
-				host->cmd->error = MMC_ERR_TIMEOUT;
+				host->cmd->error = -ETIMEDOUT;
 			else
-				host->mrq->cmd->error = MMC_ERR_TIMEOUT;
+				host->mrq->cmd->error = -ETIMEDOUT;
 
 			tasklet_schedule(&host->finish_tasklet);
 		}
@@ -915,27 +959,23 @@
 	BUG_ON(intmask == 0);
 
 	if (!host->cmd) {
-		printk(KERN_ERR "%s: Got command interrupt even though no "
-			"command operation was in progress.\n",
-			mmc_hostname(host->mmc));
+		printk(KERN_ERR "%s: Got command interrupt 0x%08x even "
+			"though no command operation was in progress.\n",
+			mmc_hostname(host->mmc), (unsigned)intmask);
 		sdhci_dumpregs(host);
 		return;
 	}
 
-	if (intmask & SDHCI_INT_RESPONSE)
-		sdhci_finish_command(host);
-	else {
-		if (intmask & SDHCI_INT_TIMEOUT)
-			host->cmd->error = MMC_ERR_TIMEOUT;
-		else if (intmask & SDHCI_INT_CRC)
-			host->cmd->error = MMC_ERR_BADCRC;
-		else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX))
-			host->cmd->error = MMC_ERR_FAILED;
-		else
-			host->cmd->error = MMC_ERR_INVALID;
+	if (intmask & SDHCI_INT_TIMEOUT)
+		host->cmd->error = -ETIMEDOUT;
+	else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT |
+			SDHCI_INT_INDEX))
+		host->cmd->error = -EILSEQ;
 
+	if (host->cmd->error)
 		tasklet_schedule(&host->finish_tasklet);
-	}
+	else if (intmask & SDHCI_INT_RESPONSE)
+		sdhci_finish_command(host);
 }
 
 static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
@@ -950,22 +990,20 @@
 		if (intmask & SDHCI_INT_DATA_END)
 			return;
 
-		printk(KERN_ERR "%s: Got data interrupt even though no "
-			"data operation was in progress.\n",
-			mmc_hostname(host->mmc));
+		printk(KERN_ERR "%s: Got data interrupt 0x%08x even "
+			"though no data operation was in progress.\n",
+			mmc_hostname(host->mmc), (unsigned)intmask);
 		sdhci_dumpregs(host);
 
 		return;
 	}
 
 	if (intmask & SDHCI_INT_DATA_TIMEOUT)
-		host->data->error = MMC_ERR_TIMEOUT;
-	else if (intmask & SDHCI_INT_DATA_CRC)
-		host->data->error = MMC_ERR_BADCRC;
-	else if (intmask & SDHCI_INT_DATA_END_BIT)
-		host->data->error = MMC_ERR_FAILED;
+		host->data->error = -ETIMEDOUT;
+	else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT))
+		host->data->error = -EILSEQ;
 
-	if (host->data->error != MMC_ERR_NONE)
+	if (host->data->error)
 		sdhci_finish_data(host);
 	else {
 		if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
@@ -980,8 +1018,18 @@
 			writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS),
 				host->ioaddr + SDHCI_DMA_ADDRESS);
 
-		if (intmask & SDHCI_INT_DATA_END)
-			sdhci_finish_data(host);
+		if (intmask & SDHCI_INT_DATA_END) {
+			if (host->cmd) {
+				/*
+				 * Data managed to finish before the
+				 * command completed. Make sure we do
+				 * things in the proper order.
+				 */
+				host->data_early = 1;
+			} else {
+				sdhci_finish_data(host);
+			}
+		}
 	}
 }
 
@@ -990,6 +1038,7 @@
 	irqreturn_t result;
 	struct sdhci_host* host = dev_id;
 	u32 intmask;
+	int cardint = 0;
 
 	spin_lock(&host->lock);
 
@@ -1024,6 +1073,8 @@
 
 	intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
 
+	intmask &= ~SDHCI_INT_ERROR;
+
 	if (intmask & SDHCI_INT_BUS_POWER) {
 		printk(KERN_ERR "%s: Card is consuming too much power!\n",
 			mmc_hostname(host->mmc));
@@ -1032,6 +1083,11 @@
 
 	intmask &= ~SDHCI_INT_BUS_POWER;
 
+	if (intmask & SDHCI_INT_CARD_INT)
+		cardint = 1;
+
+	intmask &= ~SDHCI_INT_CARD_INT;
+
 	if (intmask) {
 		printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n",
 			mmc_hostname(host->mmc), intmask);
@@ -1046,6 +1102,12 @@
 out:
 	spin_unlock(&host->lock);
 
+	/*
+	 * We have to delay this as it calls back into the driver.
+	 */
+	if (cardint)
+		mmc_signal_sdio_irq(host->mmc);
+
 	return result;
 }
 
@@ -1231,20 +1293,26 @@
 
 	caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
 
-	if (debug_nodma)
-		DBG("DMA forced off\n");
-	else if (debug_forcedma) {
-		DBG("DMA forced on\n");
+	if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
 		host->flags |= SDHCI_USE_DMA;
-	} else if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
-		host->flags |= SDHCI_USE_DMA;
-	else if ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA)
-		DBG("Controller doesn't have DMA interface\n");
 	else if (!(caps & SDHCI_CAN_DO_DMA))
 		DBG("Controller doesn't have DMA capability\n");
 	else
 		host->flags |= SDHCI_USE_DMA;
 
+	if ((chip->quirks & SDHCI_QUIRK_BROKEN_DMA) &&
+		(host->flags & SDHCI_USE_DMA)) {
+		DBG("Disabling DMA as it is marked broken");
+		host->flags &= ~SDHCI_USE_DMA;
+	}
+
+	if (((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) &&
+		(host->flags & SDHCI_USE_DMA)) {
+		printk(KERN_WARNING "%s: Will use DMA "
+			"mode even though HW doesn't fully "
+			"claim to support it.\n", host->slot_descr);
+	}
+
 	if (host->flags & SDHCI_USE_DMA) {
 		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
 			printk(KERN_WARNING "%s: No suitable DMA available. "
@@ -1285,7 +1353,7 @@
 	mmc->ops = &sdhci_ops;
 	mmc->f_min = host->max_clk / 256;
 	mmc->f_max = host->max_clk;
-	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
+	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_SDIO_IRQ;
 
 	if (caps & SDHCI_CAN_DO_HISPD)
 		mmc->caps |= MMC_CAP_SD_HIGHSPEED;
@@ -1334,12 +1402,11 @@
 	 */
 	mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
 	if (mmc->max_blk_size >= 3) {
-		printk(KERN_ERR "%s: Invalid maximum block size.\n",
+		printk(KERN_WARNING "%s: Invalid maximum block size, assuming 512\n",
 			host->slot_descr);
-		ret = -ENODEV;
-		goto unmap;
-	}
-	mmc->max_blk_size = 512 << mmc->max_blk_size;
+		mmc->max_blk_size = 512;
+	} else
+		mmc->max_blk_size = 512 << mmc->max_blk_size;
 
 	/*
 	 * Maximum block count.
@@ -1539,14 +1606,10 @@
 module_init(sdhci_drv_init);
 module_exit(sdhci_drv_exit);
 
-module_param(debug_nodma, uint, 0444);
-module_param(debug_forcedma, uint, 0444);
 module_param(debug_quirks, uint, 0444);
 
 MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
 MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)");
-MODULE_PARM_DESC(debug_forcedma, "Forcefully enable DMA transfers. (default 0)");
 MODULE_PARM_DESC(debug_quirks, "Force certain quirks.");
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 7400f4b..05195ea 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mmc/sdhci.h - Secure Digital Host Controller Interface driver
+ *  linux/drivers/mmc/host/sdhci.h - Secure Digital Host Controller Interface driver
  *
  *  Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
  *
@@ -81,7 +81,7 @@
 
 #define SDHCI_BLOCK_GAP_CONTROL	0x2A
 
-#define SDHCI_WALK_UP_CONTROL	0x2B
+#define SDHCI_WAKE_UP_CONTROL	0x2B
 
 #define SDHCI_CLOCK_CONTROL	0x2C
 #define  SDHCI_DIVIDER_SHIFT	8
@@ -107,6 +107,7 @@
 #define  SDHCI_INT_CARD_INSERT	0x00000040
 #define  SDHCI_INT_CARD_REMOVE	0x00000080
 #define  SDHCI_INT_CARD_INT	0x00000100
+#define  SDHCI_INT_ERROR	0x00008000
 #define  SDHCI_INT_TIMEOUT	0x00010000
 #define  SDHCI_INT_CRC		0x00020000
 #define  SDHCI_INT_END_BIT	0x00040000
@@ -181,6 +182,7 @@
 	struct mmc_request	*mrq;		/* Current request */
 	struct mmc_command	*cmd;		/* Current command */
 	struct mmc_data		*data;		/* Current data request */
+	int			data_early:1;	/* Data finished before cmd */
 
 	struct scatterlist	*cur_sg;	/* We're working on this */
 	int			num_sg;		/* Entries left */
diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c
index 8b736e9..9b90479 100644
--- a/drivers/mmc/host/tifm_sd.c
+++ b/drivers/mmc/host/tifm_sd.c
@@ -16,6 +16,7 @@
 #include <linux/mmc/host.h>
 #include <linux/highmem.h>
 #include <linux/scatterlist.h>
+#include <linux/log2.h>
 #include <asm/io.h>
 
 #define DRIVER_NAME "tifm_sd"
@@ -404,14 +405,14 @@
 	struct tifm_dev *sock = host->dev;
 	struct mmc_command *cmd = host->req->cmd;
 
-	if (cmd->error != MMC_ERR_NONE)
+	if (cmd->error)
 		goto finish_request;
 
 	if (!(host->cmd_flags & CMD_READY))
 		return;
 
 	if (cmd->data) {
-		if (cmd->data->error != MMC_ERR_NONE) {
+		if (cmd->data->error) {
 			if ((host->cmd_flags & SCMD_ACTIVE)
 			    && !(host->cmd_flags & SCMD_READY))
 				return;
@@ -504,7 +505,7 @@
 {
 	struct tifm_sd *host;
 	unsigned int host_status = 0;
-	int cmd_error = MMC_ERR_NONE;
+	int cmd_error = 0;
 	struct mmc_command *cmd = NULL;
 	unsigned long flags;
 
@@ -521,15 +522,15 @@
 			writel(host_status & TIFM_MMCSD_ERRMASK,
 			       sock->addr + SOCK_MMCSD_STATUS);
 			if (host_status & TIFM_MMCSD_CTO)
-				cmd_error = MMC_ERR_TIMEOUT;
+				cmd_error = -ETIMEDOUT;
 			else if (host_status & TIFM_MMCSD_CCRC)
-				cmd_error = MMC_ERR_BADCRC;
+				cmd_error = -EILSEQ;
 
 			if (cmd->data) {
 				if (host_status & TIFM_MMCSD_DTO)
-					cmd->data->error = MMC_ERR_TIMEOUT;
+					cmd->data->error = -ETIMEDOUT;
 				else if (host_status & TIFM_MMCSD_DCRC)
-					cmd->data->error = MMC_ERR_BADCRC;
+					cmd->data->error = -EILSEQ;
 			}
 
 			writel(TIFM_FIFO_INT_SETALL,
@@ -626,14 +627,21 @@
 
 	spin_lock_irqsave(&sock->lock, flags);
 	if (host->eject) {
-		spin_unlock_irqrestore(&sock->lock, flags);
+		mrq->cmd->error = -ENOMEDIUM;
 		goto err_out;
 	}
 
 	if (host->req) {
 		printk(KERN_ERR "%s : unfinished request detected\n",
 		       sock->dev.bus_id);
-		spin_unlock_irqrestore(&sock->lock, flags);
+		mrq->cmd->error = -ETIMEDOUT;
+		goto err_out;
+	}
+
+	if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
+		printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n",
+			sock->dev.bus_id, mrq->data->blksz);
+		mrq->cmd->error = -EINVAL;
 		goto err_out;
 	}
 
@@ -722,7 +730,7 @@
 	return;
 
 err_out:
-	mrq->cmd->error = MMC_ERR_TIMEOUT;
+	spin_unlock_irqrestore(&sock->lock, flags);
 	mmc_request_done(mmc, mrq);
 }
 
@@ -1012,9 +1020,9 @@
 		writel(TIFM_FIFO_INT_SETALL,
 		       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
 		writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
-		host->req->cmd->error = MMC_ERR_TIMEOUT;
+		host->req->cmd->error = -ENOMEDIUM;
 		if (host->req->stop)
-			host->req->stop->error = MMC_ERR_TIMEOUT;
+			host->req->stop->error = -ENOMEDIUM;
 		tasklet_schedule(&host->finish_tasklet);
 	}
 	spin_unlock_irqrestore(&sock->lock, flags);
diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c
index 867ca6a..80db11c 100644
--- a/drivers/mmc/host/wbsd.c
+++ b/drivers/mmc/host/wbsd.c
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver
+ *  linux/drivers/mmc/host/wbsd.c - Winbond W83L51xD SD/MMC driver
  *
  *  Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved.
  *
@@ -207,8 +207,6 @@
 {
 	unsigned long dmaflags;
 
-	DBGF("Ending request, cmd (%x)\n", mrq->cmd->opcode);
-
 	if (host->dma >= 0) {
 		/*
 		 * Release ISA DMA controller.
@@ -319,7 +317,7 @@
 	 * Correct response type?
 	 */
 	if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_SHORT) {
-		cmd->error = MMC_ERR_INVALID;
+		cmd->error = -EILSEQ;
 		return;
 	}
 
@@ -339,7 +337,7 @@
 	 * Correct response type?
 	 */
 	if (wbsd_read_index(host, WBSD_IDX_RSPLEN) != WBSD_RSP_LONG) {
-		cmd->error = MMC_ERR_INVALID;
+		cmd->error = -EILSEQ;
 		return;
 	}
 
@@ -360,8 +358,6 @@
 	int i;
 	u8 status, isr;
 
-	DBGF("Sending cmd (%x)\n", cmd->opcode);
-
 	/*
 	 * Clear accumulated ISR. The interrupt routine
 	 * will fill this one with events that occur during
@@ -376,7 +372,7 @@
 	for (i = 3; i >= 0; i--)
 		outb((cmd->arg >> (i * 8)) & 0xff, host->base + WBSD_CMDR);
 
-	cmd->error = MMC_ERR_NONE;
+	cmd->error = 0;
 
 	/*
 	 * Wait for the request to complete.
@@ -396,13 +392,13 @@
 
 		/* Card removed? */
 		if (isr & WBSD_INT_CARD)
-			cmd->error = MMC_ERR_TIMEOUT;
+			cmd->error = -ENOMEDIUM;
 		/* Timeout? */
 		else if (isr & WBSD_INT_TIMEOUT)
-			cmd->error = MMC_ERR_TIMEOUT;
+			cmd->error = -ETIMEDOUT;
 		/* CRC? */
 		else if ((cmd->flags & MMC_RSP_CRC) && (isr & WBSD_INT_CRC))
-			cmd->error = MMC_ERR_BADCRC;
+			cmd->error = -EILSEQ;
 		/* All ok */
 		else {
 			if (cmd->flags & MMC_RSP_136)
@@ -411,8 +407,6 @@
 				wbsd_get_short_reply(host, cmd);
 		}
 	}
-
-	DBGF("Sent cmd (%x), res %d\n", cmd->opcode, cmd->error);
 }
 
 /*
@@ -550,11 +544,6 @@
 	unsigned long dmaflags;
 	unsigned int size;
 
-	DBGF("blksz %04x blks %04x flags %08x\n",
-		data->blksz, data->blocks, data->flags);
-	DBGF("tsac %d ms nsac %d clk\n",
-		data->timeout_ns / 1000000, data->timeout_clks);
-
 	/*
 	 * Calculate size.
 	 */
@@ -596,7 +585,7 @@
 			((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH);
 		wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF);
 	} else {
-		data->error = MMC_ERR_INVALID;
+		data->error = -EINVAL;
 		return;
 	}
 
@@ -618,7 +607,7 @@
 		 */
 		BUG_ON(size > 0x10000);
 		if (size > 0x10000) {
-			data->error = MMC_ERR_INVALID;
+			data->error = -EINVAL;
 			return;
 		}
 
@@ -680,7 +669,7 @@
 		}
 	}
 
-	data->error = MMC_ERR_NONE;
+	data->error = 0;
 }
 
 static void wbsd_finish_data(struct wbsd_host *host, struct mmc_data *data)
@@ -735,8 +724,8 @@
 				"%d bytes left.\n",
 				mmc_hostname(host->mmc), count);
 
-			if (data->error == MMC_ERR_NONE)
-				data->error = MMC_ERR_FAILED;
+			if (!data->error)
+				data->error = -EIO;
 		} else {
 			/*
 			 * Transfer data from DMA buffer to
@@ -746,14 +735,12 @@
 				wbsd_dma_to_sg(host, data);
 		}
 
-		if (data->error != MMC_ERR_NONE) {
+		if (data->error) {
 			if (data->bytes_xfered)
 				data->bytes_xfered -= data->blksz;
 		}
 	}
 
-	DBGF("Ending data transfer (%d bytes)\n", data->bytes_xfered);
-
 	wbsd_request_end(host, host->mrq);
 }
 
@@ -780,11 +767,10 @@
 	host->mrq = mrq;
 
 	/*
-	 * If there is no card in the slot then
-	 * timeout immediatly.
+	 * Check that there is actually a card in the slot.
 	 */
 	if (!(host->flags & WBSD_FCARD_PRESENT)) {
-		cmd->error = MMC_ERR_TIMEOUT;
+		cmd->error = -ENOMEDIUM;
 		goto done;
 	}
 
@@ -820,7 +806,7 @@
 				"supported by this controller.\n",
 				mmc_hostname(host->mmc), cmd->opcode);
 #endif
-			cmd->error = MMC_ERR_INVALID;
+			cmd->error = -EINVAL;
 
 			goto done;
 		};
@@ -832,7 +818,7 @@
 	if (cmd->data) {
 		wbsd_prepare_data(host, cmd->data);
 
-		if (cmd->data->error != MMC_ERR_NONE)
+		if (cmd->data->error)
 			goto done;
 	}
 
@@ -843,7 +829,7 @@
 	 * will be finished after the data has
 	 * transfered.
 	 */
-	if (cmd->data && (cmd->error == MMC_ERR_NONE)) {
+	if (cmd->data && !cmd->error) {
 		/*
 		 * Dirty fix for hardware bug.
 		 */
@@ -1046,7 +1032,7 @@
 				mmc_hostname(host->mmc));
 			wbsd_reset(host);
 
-			host->mrq->cmd->error = MMC_ERR_FAILED;
+			host->mrq->cmd->error = -ENOMEDIUM;
 			tasklet_schedule(&host->finish_tasklet);
 		}
 
@@ -1110,7 +1096,7 @@
 
 	DBGF("CRC error\n");
 
-	data->error = MMC_ERR_BADCRC;
+	data->error = -EILSEQ;
 
 	tasklet_schedule(&host->finish_tasklet);
 
@@ -1134,7 +1120,7 @@
 
 	DBGF("Timeout\n");
 
-	data->error = MMC_ERR_TIMEOUT;
+	data->error = -ETIMEDOUT;
 
 	tasklet_schedule(&host->finish_tasklet);
 
@@ -1233,7 +1219,7 @@
 	mmc->f_min = 375000;
 	mmc->f_max = 24000000;
 	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
+	mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;
 
 	spin_lock_init(&host->lock);
 
@@ -1279,7 +1265,7 @@
 	return 0;
 }
 
-static void __devexit wbsd_free_mmc(struct device *dev)
+static void wbsd_free_mmc(struct device *dev)
 {
 	struct mmc_host *mmc;
 	struct wbsd_host *host;
@@ -1371,7 +1357,7 @@
 	return 0;
 }
 
-static void __devexit wbsd_release_regions(struct wbsd_host *host)
+static void wbsd_release_regions(struct wbsd_host *host)
 {
 	if (host->base)
 		release_region(host->base, 8);
@@ -1447,7 +1433,7 @@
 		"Falling back on FIFO.\n", dma);
 }
 
-static void __devexit wbsd_release_dma(struct wbsd_host *host)
+static void wbsd_release_dma(struct wbsd_host *host)
 {
 	if (host->dma_addr) {
 		dma_unmap_single(mmc_dev(host->mmc), host->dma_addr,
@@ -1497,7 +1483,7 @@
 	return 0;
 }
 
-static void __devexit wbsd_release_irq(struct wbsd_host *host)
+static void  wbsd_release_irq(struct wbsd_host *host)
 {
 	if (!host->irq)
 		return;
@@ -1548,7 +1534,7 @@
  * Release all resources for the host.
  */
 
-static void __devexit wbsd_release_resources(struct wbsd_host *host)
+static void wbsd_release_resources(struct wbsd_host *host)
 {
 	wbsd_release_dma(host);
 	wbsd_release_irq(host);
diff --git a/drivers/mmc/host/wbsd.h b/drivers/mmc/host/wbsd.h
index 873bda1..0877866 100644
--- a/drivers/mmc/host/wbsd.h
+++ b/drivers/mmc/host/wbsd.h
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/mmc/wbsd.h - Winbond W83L51xD SD/MMC driver
+ *  linux/drivers/mmc/host/wbsd.h - Winbond W83L51xD SD/MMC driver
  *
  *  Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved.
  *
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 451adcc..6d958a4 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -3,9 +3,9 @@
 #
 
 # Core functionality.
+obj-$(CONFIG_MTD)		+= mtd.o
 mtd-y				:= mtdcore.o mtdsuper.o
 mtd-$(CONFIG_MTD_PARTITIONS)	+= mtdpart.o
-obj-$(CONFIG_MTD)		+= $(mtd-y)
 
 obj-$(CONFIG_MTD_CONCAT)	+= mtdconcat.o
 obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c
index b96ac8e..54aa759 100644
--- a/drivers/mtd/devices/docprobe.c
+++ b/drivers/mtd/devices/docprobe.c
@@ -81,9 +81,6 @@
 #endif /*  CONFIG_MTD_DOCPROBE_HIGH */
 #elif defined(__PPC__)
 	0xe4000000,
-#elif defined(CONFIG_MOMENCO_OCELOT)
-	0x2f000000,
-        0xff000000,
 #elif defined(CONFIG_MOMENCO_OCELOT_G)
         0xff000000,
 ##else
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index f88ebc5..6cd132c 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -103,7 +103,7 @@
 
 config MTD_SUN_UFLASH
 	tristate "Sun Microsystems userflash support"
-	depends on SPARC && MTD_CFI
+	depends on SPARC && MTD_CFI && PCI
 	help
 	  This provides a 'mapping' driver which supports the way in
 	  which user-programmable flash chips are connected on various
@@ -362,7 +362,7 @@
 
 config MTD_EBONY
 	tristate "Flash devices mapped on IBM 440GP Ebony"
-	depends on MTD_JEDECPROBE && EBONY
+	depends on MTD_JEDECPROBE && EBONY && !PPC_MERGE
 	help
 	  This enables access routines for the flash chips on the IBM 440GP
 	  Ebony board. If you have one of these boards and would like to
diff --git a/drivers/mtd/maps/lubbock-flash.c b/drivers/mtd/maps/lubbock-flash.c
index 1aa0447..e856068 100644
--- a/drivers/mtd/maps/lubbock-flash.c
+++ b/drivers/mtd/maps/lubbock-flash.c
@@ -15,9 +15,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/slab.h>
 
-#include <linux/dma-mapping.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
@@ -26,7 +24,7 @@
 #include <asm/hardware.h>
 #include <asm/arch/pxa-regs.h>
 #include <asm/arch/lubbock.h>
-
+#include <asm/cacheflush.h>
 
 #define ROM_ADDR	0x00000000
 #define FLASH_ADDR	0x04000000
@@ -35,7 +33,7 @@
 
 static void lubbock_map_inval_cache(struct map_info *map, unsigned long from, ssize_t len)
 {
-	consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE);
+	flush_ioremap_region(map->phys, map->cached, from, len);
 }
 
 static struct map_info lubbock_maps[2] = { {
diff --git a/drivers/mtd/maps/mainstone-flash.c b/drivers/mtd/maps/mainstone-flash.c
index eaa4bbb..d76487d 100644
--- a/drivers/mtd/maps/mainstone-flash.c
+++ b/drivers/mtd/maps/mainstone-flash.c
@@ -15,8 +15,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
@@ -26,6 +24,7 @@
 #include <asm/hardware.h>
 #include <asm/arch/pxa-regs.h>
 #include <asm/arch/mainstone.h>
+#include <asm/cacheflush.h>
 
 
 #define ROM_ADDR	0x00000000
@@ -36,7 +35,7 @@
 static void mainstone_map_inval_cache(struct map_info *map, unsigned long from,
 				      ssize_t len)
 {
-	consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE);
+	flush_ioremap_region(map->phys, map->cached, from, len);
 }
 
 static struct map_info mainstone_maps[2] = { {
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index bbb42c3..cf75a56 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -1,9 +1,12 @@
 /*
- * Normal mappings of chips in physical memory for OF devices
+ * Flash mappings described by the OF (or flattened) device tree
  *
  * Copyright (C) 2006 MontaVista Software Inc.
  * Author: Vitaly Wool <vwool@ru.mvista.com>
  *
+ * Revised to handle newer style flash binding by:
+ *   Copyright (C) 2007 David Gibson, IBM Corporation.
+ *
  * 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
@@ -12,102 +15,157 @@
 
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/slab.h>
 #include <linux/device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
-#include <linux/mtd/physmap.h>
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/of_device.h>
-#include <asm/of_platform.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
-struct physmap_flash_info {
+struct of_flash {
 	struct mtd_info		*mtd;
 	struct map_info		map;
 	struct resource		*res;
 #ifdef CONFIG_MTD_PARTITIONS
-	int			nr_parts;
 	struct mtd_partition	*parts;
 #endif
 };
 
-static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
 #ifdef CONFIG_MTD_PARTITIONS
-static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
-#endif
+#define OF_FLASH_PARTS(info)	((info)->parts)
 
-#ifdef CONFIG_MTD_PARTITIONS
-static int parse_flash_partitions(struct device_node *node,
-		struct mtd_partition **parts)
+static int parse_obsolete_partitions(struct of_device *dev,
+				     struct of_flash *info,
+				     struct device_node *dp)
 {
-	int i, plen, retval = -ENOMEM;
-	const  u32  *part;
-	const  char *name;
+	int i, plen, nr_parts;
+	const struct {
+		u32 offset, len;
+	} *part;
+	const char *names;
 
-	part = of_get_property(node, "partitions", &plen);
-	if (part == NULL)
-		goto err;
+	part = of_get_property(dp, "partitions", &plen);
+	if (!part)
+		return 0; /* No partitions found */
 
-	retval = plen / (2 * sizeof(u32));
-	*parts = kzalloc(retval * sizeof(struct mtd_partition), GFP_KERNEL);
-	if (*parts == NULL) {
-		printk(KERN_ERR "Can't allocate the flash partition data!\n");
-		goto err;
-	}
+	dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n");
 
-	name = of_get_property(node, "partition-names", &plen);
+	nr_parts = plen / sizeof(part[0]);
 
-	for (i = 0; i < retval; i++) {
-		(*parts)[i].offset = *part++;
-		(*parts)[i].size   = *part & ~1;
-		if (*part++ & 1) /* bit 0 set signifies read only partition */
-			(*parts)[i].mask_flags = MTD_WRITEABLE;
+	info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL);
+	if (!info->parts)
+		return -ENOMEM;
 
-		if (name != NULL && plen > 0) {
-			int len = strlen(name) + 1;
+	names = of_get_property(dp, "partition-names", &plen);
 
-			(*parts)[i].name = (char *)name;
+	for (i = 0; i < nr_parts; i++) {
+		info->parts[i].offset = part->offset;
+		info->parts[i].size   = part->len & ~1;
+		if (part->len & 1) /* bit 0 set signifies read only partition */
+			info->parts[i].mask_flags = MTD_WRITEABLE;
+
+		if (names && (plen > 0)) {
+			int len = strlen(names) + 1;
+
+			info->parts[i].name = (char *)names;
 			plen -= len;
-			name += len;
-		} else
-			(*parts)[i].name = "unnamed";
-	}
-err:
-	return retval;
-}
-#endif
+			names += len;
+		} else {
+			info->parts[i].name = "unnamed";
+		}
 
-static int of_physmap_remove(struct of_device *dev)
+		part++;
+	}
+
+	return nr_parts;
+}
+
+static int __devinit parse_partitions(struct of_flash *info,
+				      struct of_device *dev)
 {
-	struct physmap_flash_info *info;
+	const char *partname;
+	static const char *part_probe_types[]
+		= { "cmdlinepart", "RedBoot", NULL };
+	struct device_node *dp = dev->node, *pp;
+	int nr_parts, i;
+
+	/* First look for RedBoot table or partitions on the command
+	 * line, these take precedence over device tree information */
+	nr_parts = parse_mtd_partitions(info->mtd, part_probe_types,
+					&info->parts, 0);
+	if (nr_parts > 0) {
+		add_mtd_partitions(info->mtd, info->parts, nr_parts);
+		return 0;
+	}
+
+	/* First count the subnodes */
+	nr_parts = 0;
+	for (pp = dp->child; pp; pp = pp->sibling)
+		nr_parts++;
+
+	if (nr_parts == 0)
+		return parse_obsolete_partitions(dev, info, dp);
+
+	info->parts = kzalloc(nr_parts * sizeof(*info->parts),
+			      GFP_KERNEL);
+	if (!info->parts)
+		return -ENOMEM;
+
+	for (pp = dp->child, i = 0; pp; pp = pp->sibling, i++) {
+		const u32 *reg;
+		int len;
+
+		reg = of_get_property(pp, "reg", &len);
+		if (!reg || (len != 2*sizeof(u32))) {
+			dev_err(&dev->dev, "Invalid 'reg' on %s\n",
+				dp->full_name);
+			kfree(info->parts);
+			info->parts = NULL;
+			return -EINVAL;
+		}
+		info->parts[i].offset = reg[0];
+		info->parts[i].size = reg[1];
+
+		partname = of_get_property(pp, "label", &len);
+		if (!partname)
+			partname = of_get_property(pp, "name", &len);
+		info->parts[i].name = (char *)partname;
+
+		if (of_get_property(pp, "read-only", &len))
+			info->parts[i].mask_flags = MTD_WRITEABLE;
+	}
+
+	return nr_parts;
+}
+#else /* MTD_PARTITIONS */
+#define	OF_FLASH_PARTS(info)		(0)
+#define parse_partitions(info, dev)	(0)
+#endif /* MTD_PARTITIONS */
+
+static int of_flash_remove(struct of_device *dev)
+{
+	struct of_flash *info;
 
 	info = dev_get_drvdata(&dev->dev);
-	if (info == NULL)
+	if (!info)
 		return 0;
 	dev_set_drvdata(&dev->dev, NULL);
 
-	if (info->mtd != NULL) {
-#ifdef CONFIG_MTD_PARTITIONS
-		if (info->nr_parts) {
+	if (info->mtd) {
+		if (OF_FLASH_PARTS(info)) {
 			del_mtd_partitions(info->mtd);
-			kfree(info->parts);
+			kfree(OF_FLASH_PARTS(info));
 		} else {
 			del_mtd_device(info->mtd);
 		}
-#else
-		del_mtd_device(info->mtd);
-#endif
 		map_destroy(info->mtd);
 	}
 
-	if (info->map.virt != NULL)
+	if (info->map.virt)
 		iounmap(info->map.virt);
 
-	if (info->res != NULL) {
+	if (info->res) {
 		release_resource(info->res);
 		kfree(info->res);
 	}
@@ -115,48 +173,79 @@
 	return 0;
 }
 
-static int __devinit of_physmap_probe(struct of_device *dev, const struct of_device_id *match)
+/* Helper function to handle probing of the obsolete "direct-mapped"
+ * compatible binding, which has an extra "probe-type" property
+ * describing the type of flash probe necessary. */
+static struct mtd_info * __devinit obsolete_probe(struct of_device *dev,
+						  struct map_info *map)
+{
+	struct device_node *dp = dev->node;
+	const char *of_probe;
+	struct mtd_info *mtd;
+	static const char *rom_probe_types[]
+		= { "cfi_probe", "jedec_probe", "map_rom"};
+	int i;
+
+	dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
+		 "flash binding\n");
+
+	of_probe = of_get_property(dp, "probe-type", NULL);
+	if (!of_probe) {
+		for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
+			mtd = do_map_probe(rom_probe_types[i], map);
+			if (mtd)
+				return mtd;
+		}
+		return NULL;
+	} else if (strcmp(of_probe, "CFI") == 0) {
+		return do_map_probe("cfi_probe", map);
+	} else if (strcmp(of_probe, "JEDEC") == 0) {
+		return do_map_probe("jedec_probe", map);
+	} else {
+		if (strcmp(of_probe, "ROM") != 0)
+			dev_warn(&dev->dev, "obsolete_probe: don't know probe "
+				 "type '%s', mapping as rom\n", of_probe);
+		return do_map_probe("mtd_rom", map);
+	}
+}
+
+static int __devinit of_flash_probe(struct of_device *dev,
+				    const struct of_device_id *match)
 {
 	struct device_node *dp = dev->node;
 	struct resource res;
-	struct physmap_flash_info *info;
-	const char **probe_type;
-	const char *of_probe;
+	struct of_flash *info;
+	const char *probe_type = match->data;
 	const u32 *width;
 	int err;
 
-
+	err = -ENXIO;
 	if (of_address_to_resource(dp, 0, &res)) {
-		dev_err(&dev->dev, "Can't get the flash mapping!\n");
-		err = -EINVAL;
+		dev_err(&dev->dev, "Can't get IO address from device tree\n");
 		goto err_out;
 	}
 
-       	dev_dbg(&dev->dev, "physmap flash device: %.8llx at %.8llx\n",
-	    (unsigned long long)res.end - res.start + 1,
-	    (unsigned long long)res.start);
+       	dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n",
+		(unsigned long long)res.start, (unsigned long long)res.end);
 
-	info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL);
-	if (info == NULL) {
-		err = -ENOMEM;
+	err = -ENOMEM;
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
 		goto err_out;
-	}
 	memset(info, 0, sizeof(*info));
 
 	dev_set_drvdata(&dev->dev, info);
 
+	err = -EBUSY;
 	info->res = request_mem_region(res.start, res.end - res.start + 1,
-			dev->dev.bus_id);
-	if (info->res == NULL) {
-		dev_err(&dev->dev, "Could not reserve memory region\n");
-		err = -ENOMEM;
+				       dev->dev.bus_id);
+	if (!info->res)
 		goto err_out;
-	}
 
+	err = -ENXIO;
 	width = of_get_property(dp, "bank-width", NULL);
-	if (width == NULL) {
-		dev_err(&dev->dev, "Can't get the flash bank width!\n");
-		err = -EINVAL;
+	if (!width) {
+		dev_err(&dev->dev, "Can't get bank width from device tree\n");
 		goto err_out;
 	}
 
@@ -165,91 +254,87 @@
 	info->map.size = res.end - res.start + 1;
 	info->map.bankwidth = *width;
 
+	err = -ENOMEM;
 	info->map.virt = ioremap(info->map.phys, info->map.size);
-	if (info->map.virt == NULL) {
-		dev_err(&dev->dev, "Failed to ioremap flash region\n");
-		err = EIO;
+	if (!info->map.virt) {
+		dev_err(&dev->dev, "Failed to ioremap() flash region\n");
 		goto err_out;
 	}
 
 	simple_map_init(&info->map);
 
-	of_probe = of_get_property(dp, "probe-type", NULL);
-	if (of_probe == NULL) {
-		probe_type = rom_probe_types;
-		for (; info->mtd == NULL && *probe_type != NULL; probe_type++)
-			info->mtd = do_map_probe(*probe_type, &info->map);
-	} else if (!strcmp(of_probe, "CFI"))
-		info->mtd = do_map_probe("cfi_probe", &info->map);
-	else if (!strcmp(of_probe, "JEDEC"))
-		info->mtd = do_map_probe("jedec_probe", &info->map);
-	else {
- 		if (strcmp(of_probe, "ROM"))
-			dev_dbg(&dev->dev, "map_probe: don't know probe type "
-			"'%s', mapping as rom\n", of_probe);
-		info->mtd = do_map_probe("mtd_rom", &info->map);
-	}
-	if (info->mtd == NULL) {
-		dev_err(&dev->dev, "map_probe failed\n");
-		err = -ENXIO;
+	if (probe_type)
+		info->mtd = do_map_probe(probe_type, &info->map);
+	else
+		info->mtd = obsolete_probe(dev, &info->map);
+
+	err = -ENXIO;
+	if (!info->mtd) {
+		dev_err(&dev->dev, "do_map_probe() failed\n");
 		goto err_out;
 	}
 	info->mtd->owner = THIS_MODULE;
 
-#ifdef CONFIG_MTD_PARTITIONS
-	err = parse_mtd_partitions(info->mtd, part_probe_types, &info->parts, 0);
-	if (err > 0) {
-		add_mtd_partitions(info->mtd, info->parts, err);
-	} else if ((err = parse_flash_partitions(dp, &info->parts)) > 0) {
-		dev_info(&dev->dev, "Using OF partition information\n");
-		add_mtd_partitions(info->mtd, info->parts, err);
-		info->nr_parts = err;
-	} else
-#endif
+	err = parse_partitions(info, dev);
+	if (err < 0)
+		goto err_out;
 
-	add_mtd_device(info->mtd);
+	if (err > 0)
+		add_mtd_partitions(info->mtd, OF_FLASH_PARTS(info), err);
+	else
+		add_mtd_device(info->mtd);
+
 	return 0;
 
 err_out:
-	of_physmap_remove(dev);
+	of_flash_remove(dev);
 	return err;
-
-	return 0;
-
-
 }
 
-static struct of_device_id of_physmap_match[] = {
+static struct of_device_id of_flash_match[] = {
+	{
+		.compatible	= "cfi-flash",
+		.data		= (void *)"cfi_probe",
+	},
+	{
+		/* FIXME: JEDEC chips can't be safely and reliably
+		 * probed, although the mtd code gets it right in
+		 * practice most of the time.  We should use the
+		 * vendor and device ids specified by the binding to
+		 * bypass the heuristic probe code, but the mtd layer
+		 * provides, at present, no interface for doing so
+		 * :(. */
+		.compatible	= "jedec-flash",
+		.data		= (void *)"jedec_probe",
+	},
 	{
 		.type		= "rom",
 		.compatible	= "direct-mapped"
 	},
 	{ },
 };
+MODULE_DEVICE_TABLE(of, of_flash_match);
 
-MODULE_DEVICE_TABLE(of, of_physmap_match);
-
-
-static struct of_platform_driver of_physmap_flash_driver = {
-	.name		= "physmap-flash",
-	.match_table	= of_physmap_match,
-	.probe		= of_physmap_probe,
-	.remove		= of_physmap_remove,
+static struct of_platform_driver of_flash_driver = {
+	.name		= "of-flash",
+	.match_table	= of_flash_match,
+	.probe		= of_flash_probe,
+	.remove		= of_flash_remove,
 };
 
-static int __init of_physmap_init(void)
+static int __init of_flash_init(void)
 {
-	return of_register_platform_driver(&of_physmap_flash_driver);
+	return of_register_platform_driver(&of_flash_driver);
 }
 
-static void __exit of_physmap_exit(void)
+static void __exit of_flash_exit(void)
 {
-	of_unregister_platform_driver(&of_physmap_flash_driver);
+	of_unregister_platform_driver(&of_flash_driver);
 }
 
-module_init(of_physmap_init);
-module_exit(of_physmap_exit);
+module_init(of_flash_init);
+module_exit(of_flash_exit);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
-MODULE_DESCRIPTION("Configurable MTD map driver for OF");
+MODULE_DESCRIPTION("Device tree based MTD map driver");
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 8c86b80..d091b24 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -7,6 +7,7 @@
 
 #include <linux/device.h>
 #include <linux/fs.h>
+#include <linux/mm.h>
 #include <linux/err.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 9c62368..6174a97 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -560,7 +560,3 @@
 EXPORT_SYMBOL_GPL(parse_mtd_partitions);
 EXPORT_SYMBOL_GPL(register_mtd_parser);
 EXPORT_SYMBOL_GPL(deregister_mtd_parser);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
-MODULE_DESCRIPTION("Generic support for partitioning of MTD devices");
diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c
index aca3319..9b430f2 100644
--- a/drivers/mtd/mtdsuper.c
+++ b/drivers/mtd/mtdsuper.c
@@ -70,6 +70,8 @@
 	DEBUG(1, "MTDSB: New superblock for device %d (\"%s\")\n",
 	      mtd->index, mtd->name);
 
+	sb->s_flags = flags;
+
 	ret = fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
 	if (ret < 0) {
 		up_write(&sb->s_umount);
diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c
index 512e999..b2a5672 100644
--- a/drivers/mtd/nand/at91_nand.c
+++ b/drivers/mtd/nand/at91_nand.c
@@ -128,7 +128,10 @@
 	nand_chip->IO_ADDR_R = host->io_base;
 	nand_chip->IO_ADDR_W = host->io_base;
 	nand_chip->cmd_ctrl = at91_nand_cmd_ctrl;
-	nand_chip->dev_ready = at91_nand_device_ready;
+
+	if (host->board->rdy_pin)
+		nand_chip->dev_ready = at91_nand_device_ready;
+
 	nand_chip->ecc.mode = NAND_ECC_SOFT;	/* enable ECC */
 	nand_chip->chip_delay = 20;		/* 20us command delay time */
 
diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c
index cff969d..6f32a35 100644
--- a/drivers/mtd/nand/cafe_nand.c
+++ b/drivers/mtd/nand/cafe_nand.c
@@ -816,7 +816,8 @@
 }
 
 static struct pci_device_id cafe_nand_tbl[] = {
-	{ 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 }
+	{ 0x11ab, 0x4100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MEMORY_FLASH << 8, 0xFFFF0 },
+	{ 0, }
 };
 
 MODULE_DEVICE_TABLE(pci, cafe_nand_tbl);
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index 17c8680..e96259f 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -56,9 +56,6 @@
 #endif /*  CONFIG_MTD_DOCPROBE_HIGH */
 #elif defined(__PPC__)
 	0xe4000000,
-#elif defined(CONFIG_MOMENCO_OCELOT)
-	0x2f000000,
-	0xff000000,
 #elif defined(CONFIG_MOMENCO_OCELOT_G)
 	0xff000000,
 #else
diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c
index 1daf823..0146cdc 100644
--- a/drivers/mtd/nand/edb7312.c
+++ b/drivers/mtd/nand/edb7312.c
@@ -74,7 +74,7 @@
 /*
  *	hardware specific access to control-lines
  *
- *	NAND_NCE: bit 0 -> bit 7
+ *	NAND_NCE: bit 0 -> bit 6 (bit 7 = 1)
  *	NAND_CLE: bit 1 -> bit 4
  *	NAND_ALE: bit 2 -> bit 5
  */
@@ -83,12 +83,12 @@
 	struct nand_chip *chip = mtd->priv;
 
 	if (ctrl & NAND_CTRL_CHANGE) {
-		unsigned char bits;
+		unsigned char bits = 0x80;
 
-		bits = (ctrl & (NAND_CLE | NAND_ALE)) << 3;
-		bits = (ctrl & NAND_NCE) << 7;
+		bits |= (ctrl & (NAND_CLE | NAND_ALE)) << 3;
+		bits |= (ctrl & NAND_NCE) ? 0x00 : 0x40;
 
-		clps_writeb((clps_readb(ep7312_pxdr)  & 0xB0) | 0x10,
+		clps_writeb((clps_readb(ep7312_pxdr)  & 0xF0) | bits,
 			    ep7312_pxdr);
 	}
 	if (cmd != NAND_CMD_NONE)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 7e68203..24ac677 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -24,6 +24,7 @@
  *	if we have HW ecc support.
  *	The AG-AND chips have nice features for speed improvement,
  *	which are not supported yet. Read / program 4 pages in one go.
+ *	BBT table is not serialized, has to be fixed
  *
  * 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
@@ -360,6 +361,7 @@
 		/* We write two bytes, so we dont have to mess with 16 bit
 		 * access
 		 */
+		nand_get_device(chip, mtd, FL_WRITING);
 		ofs += mtd->oobsize;
 		chip->ops.len = chip->ops.ooblen = 2;
 		chip->ops.datbuf = NULL;
@@ -367,9 +369,11 @@
 		chip->ops.ooboffs = chip->badblockpos & ~0x01;
 
 		ret = nand_do_write_oob(mtd, ofs, &chip->ops);
+		nand_release_device(mtd);
 	}
 	if (!ret)
 		mtd->ecc_stats.badblocks++;
+
 	return ret;
 }
 
@@ -768,7 +772,7 @@
 	uint8_t *p = buf;
 	uint8_t *ecc_calc = chip->buffers->ecccalc;
 	uint8_t *ecc_code = chip->buffers->ecccode;
-	int *eccpos = chip->ecc.layout->eccpos;
+	uint32_t *eccpos = chip->ecc.layout->eccpos;
 
 	chip->ecc.read_page_raw(mtd, chip, buf);
 
@@ -810,7 +814,7 @@
 	uint8_t *p = buf;
 	uint8_t *ecc_calc = chip->buffers->ecccalc;
 	uint8_t *ecc_code = chip->buffers->ecccode;
-	int *eccpos = chip->ecc.layout->eccpos;
+	uint32_t *eccpos = chip->ecc.layout->eccpos;
 
 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
 		chip->ecc.hwctl(mtd, NAND_ECC_READ);
@@ -1416,7 +1420,7 @@
 	int eccsteps = chip->ecc.steps;
 	uint8_t *ecc_calc = chip->buffers->ecccalc;
 	const uint8_t *p = buf;
-	int *eccpos = chip->ecc.layout->eccpos;
+	uint32_t *eccpos = chip->ecc.layout->eccpos;
 
 	/* Software ecc calculation */
 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
@@ -1442,7 +1446,7 @@
 	int eccsteps = chip->ecc.steps;
 	uint8_t *ecc_calc = chip->buffers->ecccalc;
 	const uint8_t *p = buf;
-	int *eccpos = chip->ecc.layout->eccpos;
+	uint32_t *eccpos = chip->ecc.layout->eccpos;
 
 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
 		chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c
index d4b1ba8..006c03a 100644
--- a/drivers/mtd/rfd_ftl.c
+++ b/drivers/mtd/rfd_ftl.c
@@ -779,6 +779,7 @@
 	else {
 		if (!mtd->erasesize) {
 			printk(KERN_WARNING PREFIX "please provide block_size");
+			kfree(part);
 			return;
 		}
 		else
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 555d594..1cb22bf 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -33,6 +33,7 @@
 #include <linux/moduleparam.h>
 #include <linux/stringify.h>
 #include <linux/stat.h>
+#include <linux/log2.h>
 #include "ubi.h"
 
 /* Maximum length of the 'mtd=' parameter */
@@ -369,7 +370,7 @@
 out_wl:
 	ubi_wl_close(ubi);
 out_vtbl:
-	kfree(ubi->vtbl);
+	vfree(ubi->vtbl);
 out_si:
 	ubi_scan_destroy_si(si);
 	return err;
@@ -422,8 +423,7 @@
 	ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft;
 
 	/* Make sure minimal I/O unit is power of 2 */
-	if (ubi->min_io_size == 0 ||
-	    (ubi->min_io_size & (ubi->min_io_size - 1))) {
+	if (!is_power_of_2(ubi->min_io_size)) {
 		ubi_err("bad min. I/O unit");
 		return -EINVAL;
 	}
@@ -593,8 +593,6 @@
 	if (err)
 		goto out_detach;
 
-	ubi_devices_cnt += 1;
-
 	ubi_msg("attached mtd%d to ubi%d", ubi->mtd->index, ubi_devices_cnt);
 	ubi_msg("MTD device name:            \"%s\"", ubi->mtd->name);
 	ubi_msg("MTD device size:            %llu MiB", ubi->flash_size >> 20);
@@ -624,12 +622,13 @@
 		wake_up_process(ubi->bgt_thread);
 	}
 
+	ubi_devices_cnt += 1;
 	return 0;
 
 out_detach:
 	ubi_eba_close(ubi);
 	ubi_wl_close(ubi);
-	kfree(ubi->vtbl);
+	vfree(ubi->vtbl);
 out_free:
 	kfree(ubi);
 out_mtd:
@@ -650,7 +649,7 @@
 	uif_close(ubi);
 	ubi_eba_close(ubi);
 	ubi_wl_close(ubi);
-	kfree(ubi->vtbl);
+	vfree(ubi->vtbl);
 	put_mtd_device(ubi->mtd);
 	kfree(ubi_devices[ubi_num]);
 	ubi_devices[ubi_num] = NULL;
@@ -686,13 +685,6 @@
 		struct mtd_dev_param *p = &mtd_dev_param[i];
 
 		cond_resched();
-
-		if (!p->name) {
-			dbg_err("empty name");
-			err = -EINVAL;
-			goto out_detach;
-		}
-
 		err = attach_mtd_dev(p->name, p->vid_hdr_offs, p->data_offs);
 		if (err)
 			goto out_detach;
@@ -799,7 +791,7 @@
 
 	/* Get rid of the final newline */
 	if (buf[len - 1] == '\n')
-		buf[len - 1] = 0;
+		buf[len - 1] = '\0';
 
 	for (i = 0; i < 3; i++)
 		tokens[i] = strsep(&pbuf, ",");
@@ -809,9 +801,6 @@
 		return -EINVAL;
 	}
 
-	if (tokens[0] == '\0')
-		return -EINVAL;
-
 	p = &mtd_dev_param[mtd_devs];
 	strcpy(&p->name[0], tokens[0]);
 
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 6612eb7..fe4da1e 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -64,6 +64,7 @@
 		if (ubi_devices[i] && ubi_devices[i]->major == major)
 			return ubi_devices[i];
 	BUG();
+	return NULL;
 }
 
 /**
@@ -153,7 +154,7 @@
 		ubi_warn("update of volume %d not finished, volume is damaged",
 			 vol->vol_id);
 		vol->updating = 0;
-		kfree(vol->upd_buf);
+		vfree(vol->upd_buf);
 	}
 
 	ubi_close_volume(desc);
@@ -232,7 +233,7 @@
 	tbuf_size = vol->usable_leb_size;
 	if (count < tbuf_size)
 		tbuf_size = ALIGN(count, ubi->min_io_size);
-	tbuf = kmalloc(tbuf_size, GFP_KERNEL);
+	tbuf = vmalloc(tbuf_size);
 	if (!tbuf)
 		return -ENOMEM;
 
@@ -271,7 +272,7 @@
 		len = count > tbuf_size ? tbuf_size : count;
 	} while (count);
 
-	kfree(tbuf);
+	vfree(tbuf);
 	return err ? err : count_save - count;
 }
 
@@ -320,7 +321,7 @@
 	tbuf_size = vol->usable_leb_size;
 	if (count < tbuf_size)
 		tbuf_size = ALIGN(count, ubi->min_io_size);
-	tbuf = kmalloc(tbuf_size, GFP_KERNEL);
+	tbuf = vmalloc(tbuf_size);
 	if (!tbuf)
 		return -ENOMEM;
 
@@ -355,7 +356,7 @@
 		len = count > tbuf_size ? tbuf_size : count;
 	}
 
-	kfree(tbuf);
+	vfree(tbuf);
 	return err ? err : count_save - count;
 }
 
@@ -397,6 +398,7 @@
 			vol->corrupted = 1;
 		}
 		vol->checked = 1;
+		ubi_gluebi_updated(vol);
 		revoke_exclusive(desc, UBI_READWRITE);
 	}
 
@@ -413,19 +415,7 @@
 	struct ubi_device *ubi = vol->ubi;
 	void __user *argp = (void __user *)arg;
 
-	if (_IOC_NR(cmd) > VOL_CDEV_IOC_MAX_SEQ ||
-	    _IOC_TYPE(cmd) != UBI_VOL_IOC_MAGIC)
-		return -ENOTTY;
-
-	if (_IOC_DIR(cmd) && _IOC_READ)
-		err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
-	else if (_IOC_DIR(cmd) && _IOC_WRITE)
-		err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
-	if (err)
-		return -EFAULT;
-
 	switch (cmd) {
-
 	/* Volume update command */
 	case UBI_IOCVOLUP:
 	{
@@ -471,7 +461,7 @@
 	{
 		int32_t lnum;
 
-		err = __get_user(lnum, (__user int32_t *)argp);
+		err = get_user(lnum, (__user int32_t *)argp);
 		if (err) {
 			err = -EFAULT;
 			break;
@@ -587,17 +577,6 @@
 	struct ubi_volume_desc *desc;
 	void __user *argp = (void __user *)arg;
 
-	if (_IOC_NR(cmd) > UBI_CDEV_IOC_MAX_SEQ ||
-	    _IOC_TYPE(cmd) != UBI_IOC_MAGIC)
-		return -ENOTTY;
-
-	if (_IOC_DIR(cmd) && _IOC_READ)
-		err = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd));
-	else if (_IOC_DIR(cmd) && _IOC_WRITE)
-		err = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd));
-	if (err)
-		return -EFAULT;
-
 	if (!capable(CAP_SYS_RESOURCE))
 		return -EPERM;
 
@@ -612,7 +591,7 @@
 		struct ubi_mkvol_req req;
 
 		dbg_msg("create volume");
-		err = __copy_from_user(&req, argp,
+		err = copy_from_user(&req, argp,
 				       sizeof(struct ubi_mkvol_req));
 		if (err) {
 			err = -EFAULT;
@@ -629,7 +608,7 @@
 		if (err)
 			break;
 
-		err = __put_user(req.vol_id, (__user int32_t *)argp);
+		err = put_user(req.vol_id, (__user int32_t *)argp);
 		if (err)
 			err = -EFAULT;
 
@@ -642,7 +621,7 @@
 		int vol_id;
 
 		dbg_msg("remove volume");
-		err = __get_user(vol_id, (__user int32_t *)argp);
+		err = get_user(vol_id, (__user int32_t *)argp);
 		if (err) {
 			err = -EFAULT;
 			break;
@@ -669,7 +648,7 @@
 		struct ubi_rsvol_req req;
 
 		dbg_msg("re-size volume");
-		err = __copy_from_user(&req, argp,
+		err = copy_from_user(&req, argp,
 				       sizeof(struct ubi_rsvol_req));
 		if (err) {
 			err = -EFAULT;
@@ -707,7 +686,7 @@
 struct file_operations ubi_cdev_operations = {
 	.owner = THIS_MODULE,
 	.ioctl = ubi_cdev_ioctl,
-	.llseek = no_llseek
+	.llseek = no_llseek,
 };
 
 /* UBI volume character device operations */
@@ -718,5 +697,5 @@
 	.llseek  = vol_cdev_llseek,
 	.read    = vol_cdev_read,
 	.write   = vol_cdev_write,
-	.ioctl   = vol_cdev_ioctl
+	.ioctl   = vol_cdev_ioctl,
 };
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index 8636422..310341e 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -35,12 +35,12 @@
 void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr)
 {
 	dbg_msg("erase counter header dump:");
-	dbg_msg("magic          %#08x", ubi32_to_cpu(ec_hdr->magic));
+	dbg_msg("magic          %#08x", be32_to_cpu(ec_hdr->magic));
 	dbg_msg("version        %d",    (int)ec_hdr->version);
-	dbg_msg("ec             %llu",  (long long)ubi64_to_cpu(ec_hdr->ec));
-	dbg_msg("vid_hdr_offset %d",    ubi32_to_cpu(ec_hdr->vid_hdr_offset));
-	dbg_msg("data_offset    %d",    ubi32_to_cpu(ec_hdr->data_offset));
-	dbg_msg("hdr_crc        %#08x", ubi32_to_cpu(ec_hdr->hdr_crc));
+	dbg_msg("ec             %llu",  (long long)be64_to_cpu(ec_hdr->ec));
+	dbg_msg("vid_hdr_offset %d",    be32_to_cpu(ec_hdr->vid_hdr_offset));
+	dbg_msg("data_offset    %d",    be32_to_cpu(ec_hdr->data_offset));
+	dbg_msg("hdr_crc        %#08x", be32_to_cpu(ec_hdr->hdr_crc));
 	dbg_msg("erase counter header hexdump:");
 	ubi_dbg_hexdump(ec_hdr, UBI_EC_HDR_SIZE);
 }
@@ -52,20 +52,20 @@
 void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
 {
 	dbg_msg("volume identifier header dump:");
-	dbg_msg("magic     %08x", ubi32_to_cpu(vid_hdr->magic));
+	dbg_msg("magic     %08x", be32_to_cpu(vid_hdr->magic));
 	dbg_msg("version   %d",   (int)vid_hdr->version);
 	dbg_msg("vol_type  %d",   (int)vid_hdr->vol_type);
 	dbg_msg("copy_flag %d",   (int)vid_hdr->copy_flag);
 	dbg_msg("compat    %d",   (int)vid_hdr->compat);
-	dbg_msg("vol_id    %d",   ubi32_to_cpu(vid_hdr->vol_id));
-	dbg_msg("lnum      %d",   ubi32_to_cpu(vid_hdr->lnum));
-	dbg_msg("leb_ver   %u",   ubi32_to_cpu(vid_hdr->leb_ver));
-	dbg_msg("data_size %d",   ubi32_to_cpu(vid_hdr->data_size));
-	dbg_msg("used_ebs  %d",   ubi32_to_cpu(vid_hdr->used_ebs));
-	dbg_msg("data_pad  %d",   ubi32_to_cpu(vid_hdr->data_pad));
+	dbg_msg("vol_id    %d",   be32_to_cpu(vid_hdr->vol_id));
+	dbg_msg("lnum      %d",   be32_to_cpu(vid_hdr->lnum));
+	dbg_msg("leb_ver   %u",   be32_to_cpu(vid_hdr->leb_ver));
+	dbg_msg("data_size %d",   be32_to_cpu(vid_hdr->data_size));
+	dbg_msg("used_ebs  %d",   be32_to_cpu(vid_hdr->used_ebs));
+	dbg_msg("data_pad  %d",   be32_to_cpu(vid_hdr->data_pad));
 	dbg_msg("sqnum     %llu",
-		(unsigned long long)ubi64_to_cpu(vid_hdr->sqnum));
-	dbg_msg("hdr_crc   %08x", ubi32_to_cpu(vid_hdr->hdr_crc));
+		(unsigned long long)be64_to_cpu(vid_hdr->sqnum));
+	dbg_msg("hdr_crc   %08x", be32_to_cpu(vid_hdr->hdr_crc));
 	dbg_msg("volume identifier header hexdump:");
 }
 
@@ -91,7 +91,7 @@
 
 	if (vol->name_len <= UBI_VOL_NAME_MAX &&
 	    strnlen(vol->name, vol->name_len + 1) == vol->name_len) {
-		dbg_msg("name          %s", vol->name);
+		dbg_msg("name            %s", vol->name);
 	} else {
 		dbg_msg("the 1st 5 characters of the name: %c%c%c%c%c",
 			vol->name[0], vol->name[1], vol->name[2],
@@ -106,30 +106,30 @@
  */
 void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx)
 {
-	int name_len = ubi16_to_cpu(r->name_len);
+	int name_len = be16_to_cpu(r->name_len);
 
 	dbg_msg("volume table record %d dump:", idx);
-	dbg_msg("reserved_pebs   %d", ubi32_to_cpu(r->reserved_pebs));
-	dbg_msg("alignment       %d", ubi32_to_cpu(r->alignment));
-	dbg_msg("data_pad        %d", ubi32_to_cpu(r->data_pad));
+	dbg_msg("reserved_pebs   %d", be32_to_cpu(r->reserved_pebs));
+	dbg_msg("alignment       %d", be32_to_cpu(r->alignment));
+	dbg_msg("data_pad        %d", be32_to_cpu(r->data_pad));
 	dbg_msg("vol_type        %d", (int)r->vol_type);
 	dbg_msg("upd_marker      %d", (int)r->upd_marker);
 	dbg_msg("name_len        %d", name_len);
 
 	if (r->name[0] == '\0') {
-		dbg_msg("name          NULL");
+		dbg_msg("name            NULL");
 		return;
 	}
 
 	if (name_len <= UBI_VOL_NAME_MAX &&
 	    strnlen(&r->name[0], name_len + 1) == name_len) {
-		dbg_msg("name          %s", &r->name[0]);
+		dbg_msg("name            %s", &r->name[0]);
 	} else {
 		dbg_msg("1st 5 characters of the name: %c%c%c%c%c",
 			r->name[0], r->name[1], r->name[2], r->name[3],
 			r->name[4]);
 	}
-	dbg_msg("crc             %#08x", ubi32_to_cpu(r->crc));
+	dbg_msg("crc             %#08x", be32_to_cpu(r->crc));
 }
 
 /**
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index f816ad9..ff8f395 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -52,7 +52,6 @@
 struct ubi_scan_leb;
 struct ubi_mkvol_req;
 
-void ubi_dbg_print(int type, const char *func, const char *fmt, ...);
 void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
 void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
 void ubi_dbg_dump_vol_info(const struct ubi_volume *vol);
@@ -66,7 +65,6 @@
 
 #define dbg_msg(fmt, ...)    ({})
 #define ubi_dbg_dump_stack() ({})
-#define ubi_dbg_print(func, fmt, ...)    ({})
 #define ubi_dbg_dump_ec_hdr(ec_hdr)      ({})
 #define ubi_dbg_dump_vid_hdr(vid_hdr)    ({})
 #define ubi_dbg_dump_vol_info(vol)       ({})
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 7c6b223..7c5e29e 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -425,10 +425,10 @@
 		} else if (err == UBI_IO_BITFLIPS)
 			scrub = 1;
 
-		ubi_assert(lnum < ubi32_to_cpu(vid_hdr->used_ebs));
-		ubi_assert(len == ubi32_to_cpu(vid_hdr->data_size));
+		ubi_assert(lnum < be32_to_cpu(vid_hdr->used_ebs));
+		ubi_assert(len == be32_to_cpu(vid_hdr->data_size));
 
-		crc = ubi32_to_cpu(vid_hdr->data_crc);
+		crc = be32_to_cpu(vid_hdr->data_crc);
 		ubi_free_vid_hdr(ubi, vid_hdr);
 	}
 
@@ -518,13 +518,13 @@
 		goto out_put;
 	}
 
-	vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+	vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
 	err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr);
 	if (err)
 		goto write_error;
 
 	data_size = offset + len;
-	new_buf = kmalloc(data_size, GFP_KERNEL);
+	new_buf = vmalloc(data_size);
 	if (!new_buf) {
 		err = -ENOMEM;
 		goto out_put;
@@ -535,7 +535,7 @@
 	if (offset > 0) {
 		err = ubi_io_read_data(ubi, new_buf, pnum, 0, offset);
 		if (err && err != UBI_IO_BITFLIPS) {
-			kfree(new_buf);
+			vfree(new_buf);
 			goto out_put;
 		}
 	}
@@ -544,11 +544,11 @@
 
 	err = ubi_io_write_data(ubi, new_buf, new_pnum, 0, data_size);
 	if (err) {
-		kfree(new_buf);
+		vfree(new_buf);
 		goto write_error;
 	}
 
-	kfree(new_buf);
+	vfree(new_buf);
 	ubi_free_vid_hdr(ubi, vid_hdr);
 
 	vol->eba_tbl[lnum] = new_pnum;
@@ -634,11 +634,11 @@
 	}
 
 	vid_hdr->vol_type = UBI_VID_DYNAMIC;
-	vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
-	vid_hdr->vol_id = cpu_to_ubi32(vol_id);
-	vid_hdr->lnum = cpu_to_ubi32(lnum);
+	vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+	vid_hdr->vol_id = cpu_to_be32(vol_id);
+	vid_hdr->lnum = cpu_to_be32(lnum);
 	vid_hdr->compat = ubi_get_compat(ubi, vol_id);
-	vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+	vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
 
 retry:
 	pnum = ubi_wl_get_peb(ubi, dtype);
@@ -692,7 +692,7 @@
 		return err;
 	}
 
-	vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+	vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
 	ubi_msg("try another PEB");
 	goto retry;
 }
@@ -748,17 +748,17 @@
 		return err;
 	}
 
-	vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
-	vid_hdr->vol_id = cpu_to_ubi32(vol_id);
-	vid_hdr->lnum = cpu_to_ubi32(lnum);
+	vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+	vid_hdr->vol_id = cpu_to_be32(vol_id);
+	vid_hdr->lnum = cpu_to_be32(lnum);
 	vid_hdr->compat = ubi_get_compat(ubi, vol_id);
-	vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+	vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
 
 	crc = crc32(UBI_CRC32_INIT, buf, data_size);
 	vid_hdr->vol_type = UBI_VID_STATIC;
-	vid_hdr->data_size = cpu_to_ubi32(data_size);
-	vid_hdr->used_ebs = cpu_to_ubi32(used_ebs);
-	vid_hdr->data_crc = cpu_to_ubi32(crc);
+	vid_hdr->data_size = cpu_to_be32(data_size);
+	vid_hdr->used_ebs = cpu_to_be32(used_ebs);
+	vid_hdr->data_crc = cpu_to_be32(crc);
 
 retry:
 	pnum = ubi_wl_get_peb(ubi, dtype);
@@ -813,7 +813,7 @@
 		return err;
 	}
 
-	vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+	vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
 	ubi_msg("try another PEB");
 	goto retry;
 }
@@ -854,17 +854,17 @@
 		return err;
 	}
 
-	vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
-	vid_hdr->vol_id = cpu_to_ubi32(vol_id);
-	vid_hdr->lnum = cpu_to_ubi32(lnum);
+	vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
+	vid_hdr->vol_id = cpu_to_be32(vol_id);
+	vid_hdr->lnum = cpu_to_be32(lnum);
 	vid_hdr->compat = ubi_get_compat(ubi, vol_id);
-	vid_hdr->data_pad = cpu_to_ubi32(vol->data_pad);
+	vid_hdr->data_pad = cpu_to_be32(vol->data_pad);
 
 	crc = crc32(UBI_CRC32_INIT, buf, len);
-	vid_hdr->vol_type = UBI_VID_STATIC;
-	vid_hdr->data_size = cpu_to_ubi32(len);
+	vid_hdr->vol_type = UBI_VID_DYNAMIC;
+	vid_hdr->data_size = cpu_to_be32(len);
 	vid_hdr->copy_flag = 1;
-	vid_hdr->data_crc = cpu_to_ubi32(crc);
+	vid_hdr->data_crc = cpu_to_be32(crc);
 
 retry:
 	pnum = ubi_wl_get_peb(ubi, dtype);
@@ -891,11 +891,13 @@
 		goto write_error;
 	}
 
-	err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
-	if (err) {
-		ubi_free_vid_hdr(ubi, vid_hdr);
-		leb_write_unlock(ubi, vol_id, lnum);
-		return err;
+	if (vol->eba_tbl[lnum] >= 0) {
+		err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1);
+		if (err) {
+			ubi_free_vid_hdr(ubi, vid_hdr);
+			leb_write_unlock(ubi, vol_id, lnum);
+			return err;
+		}
 	}
 
 	vol->eba_tbl[lnum] = pnum;
@@ -924,7 +926,7 @@
 		return err;
 	}
 
-	vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+	vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
 	ubi_msg("try another PEB");
 	goto retry;
 }
@@ -965,19 +967,19 @@
 	uint32_t crc;
 	void *buf, *buf1 = NULL;
 
-	vol_id = ubi32_to_cpu(vid_hdr->vol_id);
-	lnum = ubi32_to_cpu(vid_hdr->lnum);
+	vol_id = be32_to_cpu(vid_hdr->vol_id);
+	lnum = be32_to_cpu(vid_hdr->lnum);
 
 	dbg_eba("copy LEB %d:%d, PEB %d to PEB %d", vol_id, lnum, from, to);
 
 	if (vid_hdr->vol_type == UBI_VID_STATIC) {
-		data_size = ubi32_to_cpu(vid_hdr->data_size);
+		data_size = be32_to_cpu(vid_hdr->data_size);
 		aldata_size = ALIGN(data_size, ubi->min_io_size);
 	} else
 		data_size = aldata_size =
-			    ubi->leb_size - ubi32_to_cpu(vid_hdr->data_pad);
+			    ubi->leb_size - be32_to_cpu(vid_hdr->data_pad);
 
-	buf = kmalloc(aldata_size, GFP_KERNEL);
+	buf = vmalloc(aldata_size);
 	if (!buf)
 		return -ENOMEM;
 
@@ -987,7 +989,7 @@
 	 */
 	err = leb_write_lock(ubi, vol_id, lnum);
 	if (err) {
-		kfree(buf);
+		vfree(buf);
 		return err;
 	}
 
@@ -1054,10 +1056,10 @@
 	 */
 	if (data_size > 0) {
 		vid_hdr->copy_flag = 1;
-		vid_hdr->data_size = cpu_to_ubi32(data_size);
-		vid_hdr->data_crc = cpu_to_ubi32(crc);
+		vid_hdr->data_size = cpu_to_be32(data_size);
+		vid_hdr->data_crc = cpu_to_be32(crc);
 	}
-	vid_hdr->sqnum = cpu_to_ubi64(next_sqnum(ubi));
+	vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi));
 
 	err = ubi_io_write_vid_hdr(ubi, to, vid_hdr);
 	if (err)
@@ -1082,7 +1084,7 @@
 		 * We've written the data and are going to read it back to make
 		 * sure it was written correctly.
 		 */
-		buf1 = kmalloc(aldata_size, GFP_KERNEL);
+		buf1 = vmalloc(aldata_size);
 		if (!buf1) {
 			err = -ENOMEM;
 			goto out_unlock;
@@ -1111,15 +1113,15 @@
 	vol->eba_tbl[lnum] = to;
 
 	leb_write_unlock(ubi, vol_id, lnum);
-	kfree(buf);
-	kfree(buf1);
+	vfree(buf);
+	vfree(buf1);
 
 	return 0;
 
 out_unlock:
 	leb_write_unlock(ubi, vol_id, lnum);
-	kfree(buf);
-	kfree(buf1);
+	vfree(buf);
+	vfree(buf1);
 	return err;
 }
 
@@ -1147,7 +1149,7 @@
 	if (ubi_devices_cnt == 0) {
 		ltree_slab = kmem_cache_create("ubi_ltree_slab",
 					       sizeof(struct ltree_entry), 0,
-					       0, &ltree_entry_ctor, NULL);
+					       0, &ltree_entry_ctor);
 		if (!ltree_slab)
 			return -ENOMEM;
 	}
diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c
index fc9478d..41ff74c 100644
--- a/drivers/mtd/ubi/gluebi.c
+++ b/drivers/mtd/ubi/gluebi.c
@@ -282,7 +282,6 @@
 		mtd->flags = MTD_WRITEABLE;
 	mtd->writesize  = ubi->min_io_size;
 	mtd->owner      = THIS_MODULE;
-	mtd->size       = vol->usable_leb_size * vol->reserved_pebs;
 	mtd->erasesize  = vol->usable_leb_size;
 	mtd->read       = gluebi_read;
 	mtd->write      = gluebi_write;
@@ -290,6 +289,15 @@
 	mtd->get_device = gluebi_get_device;
 	mtd->put_device = gluebi_put_device;
 
+	/*
+	 * In case of dynamic volume, MTD device size is just volume size. In
+	 * case of a static volume the size is equivalent to the amount of data
+	 * bytes, which is zero at this moment and will be changed after volume
+	 * update.
+	 */
+	if (vol->vol_type == UBI_DYNAMIC_VOLUME)
+		mtd->size = vol->usable_leb_size * vol->reserved_pebs;
+
 	if (add_mtd_device(mtd)) {
 		ubi_err("cannot not add MTD device\n");
 		kfree(mtd->name);
@@ -321,3 +329,20 @@
 	kfree(mtd->name);
 	return 0;
 }
+
+/**
+ * ubi_gluebi_updated - UBI volume was updated notifier.
+ * @vol: volume description object
+ *
+ * This function is called every time an UBI volume is updated. This function
+ * does nothing if volume @vol is dynamic, and changes MTD device size if the
+ * volume is static. This is needed because static volumes cannot be read past
+ * data they contain.
+ */
+void ubi_gluebi_updated(struct ubi_volume *vol)
+{
+	struct mtd_info *mtd = &vol->gluebi_mtd;
+
+	if (vol->vol_type == UBI_STATIC_VOLUME)
+		mtd->size = vol->used_bytes;
+}
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 438914d..b0d8f4c 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -125,9 +125,9 @@
  * o %UBI_IO_BITFLIPS if all the requested data were successfully read, but
  *   correctable bit-flips were detected; this is harmless but may indicate
  *   that this eraseblock may become bad soon (but do not have to);
- * o %-EBADMSG if the MTD subsystem reported about data data integrity
- *   problems, for example it can me an ECC error in case of NAND; this most
- *   probably means that the data is corrupted;
+ * o %-EBADMSG if the MTD subsystem reported about data integrity problems, for
+ *   example it can be an ECC error in case of NAND; this most probably means
+ *   that the data is corrupted;
  * o %-EIO if some I/O error occurred;
  * o other negative error codes in case of other errors.
  */
@@ -298,7 +298,7 @@
 	memset(&ei, 0, sizeof(struct erase_info));
 
 	ei.mtd      = ubi->mtd;
-	ei.addr     = pnum * ubi->peb_size;
+	ei.addr     = (loff_t)pnum * ubi->peb_size;
 	ei.len      = ubi->peb_size;
 	ei.callback = erase_callback;
 	ei.priv     = (unsigned long)&wq;
@@ -382,7 +382,7 @@
 	void *buf;
 	int err, i, patt_count;
 
-	buf = kmalloc(ubi->peb_size, GFP_KERNEL);
+	buf = vmalloc(ubi->peb_size);
 	if (!buf)
 		return -ENOMEM;
 
@@ -437,7 +437,7 @@
 		 * physical eraseblock which means something is wrong with it.
 		 */
 		err = -EIO;
-	kfree(buf);
+	vfree(buf);
 	return err;
 }
 
@@ -557,9 +557,9 @@
 	long long ec;
 	int vid_hdr_offset, leb_start;
 
-	ec = ubi64_to_cpu(ec_hdr->ec);
-	vid_hdr_offset = ubi32_to_cpu(ec_hdr->vid_hdr_offset);
-	leb_start = ubi32_to_cpu(ec_hdr->data_offset);
+	ec = be64_to_cpu(ec_hdr->ec);
+	vid_hdr_offset = be32_to_cpu(ec_hdr->vid_hdr_offset);
+	leb_start = be32_to_cpu(ec_hdr->data_offset);
 
 	if (ec_hdr->version != UBI_VERSION) {
 		ubi_err("node with incompatible UBI version found: "
@@ -640,7 +640,7 @@
 		read_err = err;
 	}
 
-	magic = ubi32_to_cpu(ec_hdr->magic);
+	magic = be32_to_cpu(ec_hdr->magic);
 	if (magic != UBI_EC_HDR_MAGIC) {
 		/*
 		 * The magic field is wrong. Let's check if we have read all
@@ -684,7 +684,7 @@
 	}
 
 	crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
-	hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc);
+	hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
 
 	if (hdr_crc != crc) {
 		if (verbose) {
@@ -729,12 +729,12 @@
 	dbg_io("write EC header to PEB %d", pnum);
 	ubi_assert(pnum >= 0 &&  pnum < ubi->peb_count);
 
-	ec_hdr->magic = cpu_to_ubi32(UBI_EC_HDR_MAGIC);
+	ec_hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC);
 	ec_hdr->version = UBI_VERSION;
-	ec_hdr->vid_hdr_offset = cpu_to_ubi32(ubi->vid_hdr_offset);
-	ec_hdr->data_offset = cpu_to_ubi32(ubi->leb_start);
+	ec_hdr->vid_hdr_offset = cpu_to_be32(ubi->vid_hdr_offset);
+	ec_hdr->data_offset = cpu_to_be32(ubi->leb_start);
 	crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
-	ec_hdr->hdr_crc = cpu_to_ubi32(crc);
+	ec_hdr->hdr_crc = cpu_to_be32(crc);
 
 	err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr);
 	if (err)
@@ -757,13 +757,13 @@
 {
 	int vol_type = vid_hdr->vol_type;
 	int copy_flag = vid_hdr->copy_flag;
-	int vol_id = ubi32_to_cpu(vid_hdr->vol_id);
-	int lnum = ubi32_to_cpu(vid_hdr->lnum);
+	int vol_id = be32_to_cpu(vid_hdr->vol_id);
+	int lnum = be32_to_cpu(vid_hdr->lnum);
 	int compat = vid_hdr->compat;
-	int data_size = ubi32_to_cpu(vid_hdr->data_size);
-	int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
-	int data_pad = ubi32_to_cpu(vid_hdr->data_pad);
-	int data_crc = ubi32_to_cpu(vid_hdr->data_crc);
+	int data_size = be32_to_cpu(vid_hdr->data_size);
+	int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+	int data_pad = be32_to_cpu(vid_hdr->data_pad);
+	int data_crc = be32_to_cpu(vid_hdr->data_crc);
 	int usable_leb_size = ubi->leb_size - data_pad;
 
 	if (copy_flag != 0 && copy_flag != 1) {
@@ -914,7 +914,7 @@
 		read_err = err;
 	}
 
-	magic = ubi32_to_cpu(vid_hdr->magic);
+	magic = be32_to_cpu(vid_hdr->magic);
 	if (magic != UBI_VID_HDR_MAGIC) {
 		/*
 		 * If we have read all 0xFF bytes, the VID header probably does
@@ -957,7 +957,7 @@
 	}
 
 	crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
-	hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc);
+	hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
 
 	if (hdr_crc != crc) {
 		if (verbose) {
@@ -1007,10 +1007,10 @@
 	if (err)
 		return err > 0 ? -EINVAL: err;
 
-	vid_hdr->magic = cpu_to_ubi32(UBI_VID_HDR_MAGIC);
+	vid_hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC);
 	vid_hdr->version = UBI_VERSION;
 	crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
-	vid_hdr->hdr_crc = cpu_to_ubi32(crc);
+	vid_hdr->hdr_crc = cpu_to_be32(crc);
 
 	err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr);
 	if (err)
@@ -1060,7 +1060,7 @@
 	int err;
 	uint32_t magic;
 
-	magic = ubi32_to_cpu(ec_hdr->magic);
+	magic = be32_to_cpu(ec_hdr->magic);
 	if (magic != UBI_EC_HDR_MAGIC) {
 		ubi_err("bad magic %#08x, must be %#08x",
 			magic, UBI_EC_HDR_MAGIC);
@@ -1105,7 +1105,7 @@
 		goto exit;
 
 	crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
-	hdr_crc = ubi32_to_cpu(ec_hdr->hdr_crc);
+	hdr_crc = be32_to_cpu(ec_hdr->hdr_crc);
 	if (hdr_crc != crc) {
 		ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc);
 		ubi_err("paranoid check failed for PEB %d", pnum);
@@ -1137,7 +1137,7 @@
 	int err;
 	uint32_t magic;
 
-	magic = ubi32_to_cpu(vid_hdr->magic);
+	magic = be32_to_cpu(vid_hdr->magic);
 	if (magic != UBI_VID_HDR_MAGIC) {
 		ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x",
 			magic, pnum, UBI_VID_HDR_MAGIC);
@@ -1187,7 +1187,7 @@
 		goto exit;
 
 	crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
-	hdr_crc = ubi32_to_cpu(vid_hdr->hdr_crc);
+	hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
 	if (hdr_crc != crc) {
 		ubi_err("bad VID header CRC at PEB %d, calculated %#08x, "
 			"read %#08x", pnum, crc, hdr_crc);
@@ -1224,9 +1224,10 @@
 	void *buf;
 	loff_t addr = (loff_t)pnum * ubi->peb_size + offset;
 
-	buf = kzalloc(len, GFP_KERNEL);
+	buf = vmalloc(len);
 	if (!buf)
 		return -ENOMEM;
+	memset(buf, 0, len);
 
 	err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf);
 	if (err && err != -EUCLEAN) {
@@ -1242,7 +1243,7 @@
 		goto fail;
 	}
 
-	kfree(buf);
+	vfree(buf);
 	return 0;
 
 fail:
@@ -1252,7 +1253,7 @@
 	err = 1;
 error:
 	ubi_dbg_dump_stack();
-	kfree(buf);
+	vfree(buf);
 	return err;
 }
 
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index d352c45..4a458e8 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -37,14 +37,9 @@
 {
 	const struct ubi_device *ubi;
 
-	if (!try_module_get(THIS_MODULE))
-		return -ENODEV;
-
 	if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES ||
-	    !ubi_devices[ubi_num]) {
-		module_put(THIS_MODULE);
+	    !ubi_devices[ubi_num])
 		return -ENODEV;
-	}
 
 	ubi = ubi_devices[ubi_num];
 	di->ubi_num = ubi->ubi_num;
@@ -52,7 +47,6 @@
 	di->min_io_size = ubi->min_io_size;
 	di->ro_mode = ubi->ro_mode;
 	di->cdev = MKDEV(ubi->major, 0);
-	module_put(THIS_MODULE);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(ubi_get_device_info);
@@ -319,9 +313,14 @@
 	    offset + len > vol->usable_leb_size)
 		return -EINVAL;
 
-	if (vol->vol_type == UBI_STATIC_VOLUME && lnum == vol->used_ebs - 1 &&
-	    offset + len > vol->last_eb_bytes)
-		return -EINVAL;
+	if (vol->vol_type == UBI_STATIC_VOLUME) {
+		if (vol->used_ebs == 0)
+			/* Empty static UBI volume */
+			return 0;
+		if (lnum == vol->used_ebs - 1 &&
+		    offset + len > vol->last_eb_bytes)
+			return -EINVAL;
+	}
 
 	if (vol->upd_marker)
 		return -EBADF;
diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c
index 38d4e67..9e2338c 100644
--- a/drivers/mtd/ubi/misc.c
+++ b/drivers/mtd/ubi/misc.c
@@ -67,7 +67,7 @@
 	if (vol->vol_type != UBI_STATIC_VOLUME)
 		return 0;
 
-	buf = kmalloc(vol->usable_leb_size, GFP_KERNEL);
+	buf = vmalloc(vol->usable_leb_size);
 	if (!buf)
 		return -ENOMEM;
 
@@ -87,7 +87,7 @@
 		}
 	}
 
-	kfree(buf);
+	vfree(buf);
 	return err;
 }
 
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index 473f320..94ee549 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -24,7 +24,7 @@
  * This unit is responsible for scanning the flash media, checking UBI
  * headers and providing complete information about the UBI flash image.
  *
- * The scanning information is reoresented by a &struct ubi_scan_info' object.
+ * The scanning information is represented by a &struct ubi_scan_info' object.
  * Information about found volumes is represented by &struct ubi_scan_volume
  * objects which are kept in volume RB-tree with root at the @volumes field.
  * The RB-tree is indexed by the volume ID.
@@ -55,8 +55,19 @@
 static struct ubi_ec_hdr *ech;
 static struct ubi_vid_hdr *vidh;
 
-int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec,
-			 struct list_head *list)
+/**
+ * add_to_list - add physical eraseblock to a list.
+ * @si: scanning information
+ * @pnum: physical eraseblock number to add
+ * @ec: erase counter of the physical eraseblock
+ * @list: the list to add to
+ *
+ * This function adds physical eraseblock @pnum to free, erase, corrupted or
+ * alien lists. Returns zero in case of success and a negative error code in
+ * case of failure.
+ */
+static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
+		       struct list_head *list)
 {
 	struct ubi_scan_leb *seb;
 
@@ -121,9 +132,9 @@
 			    const struct ubi_scan_volume *sv, int pnum)
 {
 	int vol_type = vid_hdr->vol_type;
-	int vol_id = ubi32_to_cpu(vid_hdr->vol_id);
-	int used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
-	int data_pad = ubi32_to_cpu(vid_hdr->data_pad);
+	int vol_id = be32_to_cpu(vid_hdr->vol_id);
+	int used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+	int data_pad = be32_to_cpu(vid_hdr->data_pad);
 
 	if (sv->leb_count != 0) {
 		int sv_vol_type;
@@ -189,7 +200,7 @@
 	struct ubi_scan_volume *sv;
 	struct rb_node **p = &si->volumes.rb_node, *parent = NULL;
 
-	ubi_assert(vol_id == ubi32_to_cpu(vid_hdr->vol_id));
+	ubi_assert(vol_id == be32_to_cpu(vid_hdr->vol_id));
 
 	/* Walk the volume RB-tree to look if this volume is already present */
 	while (*p) {
@@ -211,11 +222,10 @@
 		return ERR_PTR(-ENOMEM);
 
 	sv->highest_lnum = sv->leb_count = 0;
-	si->max_sqnum = 0;
 	sv->vol_id = vol_id;
 	sv->root = RB_ROOT;
-	sv->used_ebs = ubi32_to_cpu(vid_hdr->used_ebs);
-	sv->data_pad = ubi32_to_cpu(vid_hdr->data_pad);
+	sv->used_ebs = be32_to_cpu(vid_hdr->used_ebs);
+	sv->data_pad = be32_to_cpu(vid_hdr->data_pad);
 	sv->compat = vid_hdr->compat;
 	sv->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME
 							    : UBI_STATIC_VOLUME;
@@ -257,10 +267,10 @@
 	int len, err, second_is_newer, bitflips = 0, corrupted = 0;
 	uint32_t data_crc, crc;
 	struct ubi_vid_hdr *vidh = NULL;
-	unsigned long long sqnum2 = ubi64_to_cpu(vid_hdr->sqnum);
+	unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum);
 
 	if (seb->sqnum == 0 && sqnum2 == 0) {
-		long long abs, v1 = seb->leb_ver, v2 = ubi32_to_cpu(vid_hdr->leb_ver);
+		long long abs, v1 = seb->leb_ver, v2 = be32_to_cpu(vid_hdr->leb_ver);
 
 		/*
 		 * UBI constantly increases the logical eraseblock version
@@ -344,8 +354,8 @@
 
 	/* Read the data of the copy and check the CRC */
 
-	len = ubi32_to_cpu(vid_hdr->data_size);
-	buf = kmalloc(len, GFP_KERNEL);
+	len = be32_to_cpu(vid_hdr->data_size);
+	buf = vmalloc(len);
 	if (!buf) {
 		err = -ENOMEM;
 		goto out_free_vidh;
@@ -355,7 +365,7 @@
 	if (err && err != UBI_IO_BITFLIPS)
 		goto out_free_buf;
 
-	data_crc = ubi32_to_cpu(vid_hdr->data_crc);
+	data_crc = be32_to_cpu(vid_hdr->data_crc);
 	crc = crc32(UBI_CRC32_INIT, buf, len);
 	if (crc != data_crc) {
 		dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x",
@@ -368,7 +378,7 @@
 		bitflips = !!err;
 	}
 
-	kfree(buf);
+	vfree(buf);
 	ubi_free_vid_hdr(ubi, vidh);
 
 	if (second_is_newer)
@@ -379,7 +389,7 @@
 	return second_is_newer | (bitflips << 1) | (corrupted << 2);
 
 out_free_buf:
-	kfree(buf);
+	vfree(buf);
 out_free_vidh:
 	ubi_free_vid_hdr(ubi, vidh);
 	ubi_assert(err < 0);
@@ -396,8 +406,12 @@
  * @vid_hdr: the volume identifier header
  * @bitflips: if bit-flips were detected when this physical eraseblock was read
  *
- * This function returns zero in case of success and a negative error code in
- * case of failure.
+ * This function adds information about a used physical eraseblock to the
+ * 'used' tree of the corresponding volume. The function is rather complex
+ * because it has to handle cases when this is not the first physical
+ * eraseblock belonging to the same logical eraseblock, and the newer one has
+ * to be picked, while the older one has to be dropped. This function returns
+ * zero in case of success and a negative error code in case of failure.
  */
 int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
 		      int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
@@ -410,10 +424,10 @@
 	struct ubi_scan_leb *seb;
 	struct rb_node **p, *parent = NULL;
 
-	vol_id = ubi32_to_cpu(vid_hdr->vol_id);
-	lnum = ubi32_to_cpu(vid_hdr->lnum);
-	sqnum = ubi64_to_cpu(vid_hdr->sqnum);
-	leb_ver = ubi32_to_cpu(vid_hdr->leb_ver);
+	vol_id = be32_to_cpu(vid_hdr->vol_id);
+	lnum = be32_to_cpu(vid_hdr->lnum);
+	sqnum = be64_to_cpu(vid_hdr->sqnum);
+	leb_ver = be32_to_cpu(vid_hdr->leb_ver);
 
 	dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, ver %u, bitflips %d",
 		pnum, vol_id, lnum, ec, sqnum, leb_ver, bitflips);
@@ -422,6 +436,9 @@
 	if (IS_ERR(sv) < 0)
 		return PTR_ERR(sv);
 
+	if (si->max_sqnum < sqnum)
+		si->max_sqnum = sqnum;
+
 	/*
 	 * Walk the RB-tree of logical eraseblocks of volume @vol_id to look
 	 * if this is the first instance of this logical eraseblock or not.
@@ -492,11 +509,11 @@
 				return err;
 
 			if (cmp_res & 4)
-				err = ubi_scan_add_to_list(si, seb->pnum,
-							   seb->ec, &si->corr);
+				err = add_to_list(si, seb->pnum, seb->ec,
+						  &si->corr);
 			else
-				err = ubi_scan_add_to_list(si, seb->pnum,
-							   seb->ec, &si->erase);
+				err = add_to_list(si, seb->pnum, seb->ec,
+						  &si->erase);
 			if (err)
 				return err;
 
@@ -508,7 +525,7 @@
 
 			if (sv->highest_lnum == lnum)
 				sv->last_data_size =
-					ubi32_to_cpu(vid_hdr->data_size);
+					be32_to_cpu(vid_hdr->data_size);
 
 			return 0;
 		} else {
@@ -517,11 +534,9 @@
 			 * previously.
 			 */
 			if (cmp_res & 4)
-				return ubi_scan_add_to_list(si, pnum, ec,
-							    &si->corr);
+				return add_to_list(si, pnum, ec, &si->corr);
 			else
-				return ubi_scan_add_to_list(si, pnum, ec,
-							    &si->erase);
+				return add_to_list(si, pnum, ec, &si->erase);
 		}
 	}
 
@@ -547,12 +562,9 @@
 
 	if (sv->highest_lnum <= lnum) {
 		sv->highest_lnum = lnum;
-		sv->last_data_size = ubi32_to_cpu(vid_hdr->data_size);
+		sv->last_data_size = be32_to_cpu(vid_hdr->data_size);
 	}
 
-	if (si->max_sqnum < sqnum)
-		si->max_sqnum = sqnum;
-
 	sv->leb_count += 1;
 	rb_link_node(&seb->u.rb, parent, p);
 	rb_insert_color(&seb->u.rb, &sv->root);
@@ -674,7 +686,7 @@
 		return -EINVAL;
 	}
 
-	ec_hdr->ec = cpu_to_ubi64(ec);
+	ec_hdr->ec = cpu_to_be64(ec);
 
 	err = ubi_io_sync_erase(ubi, pnum, 0);
 	if (err < 0)
@@ -754,7 +766,7 @@
  * @si: scanning information
  * @pnum: the physical eraseblock number
  *
- * This function returns a zero if the physical eraseblock was succesfully
+ * This function returns a zero if the physical eraseblock was successfully
  * handled and a negative error code in case of failure.
  */
 static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum)
@@ -783,8 +795,7 @@
 	else if (err == UBI_IO_BITFLIPS)
 		bitflips = 1;
 	else if (err == UBI_IO_PEB_EMPTY)
-		return ubi_scan_add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC,
-					    &si->erase);
+		return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase);
 	else if (err == UBI_IO_BAD_EC_HDR) {
 		/*
 		 * We have to also look at the VID header, possibly it is not
@@ -806,7 +817,7 @@
 			return -EINVAL;
 		}
 
-		ec = ubi64_to_cpu(ech->ec);
+		ec = be64_to_cpu(ech->ec);
 		if (ec > UBI_MAX_ERASECOUNTER) {
 			/*
 			 * Erase counter overflow. The EC headers have 64 bits
@@ -832,28 +843,28 @@
 	else if (err == UBI_IO_BAD_VID_HDR ||
 		 (err == UBI_IO_PEB_FREE && ec_corr)) {
 		/* VID header is corrupted */
-		err = ubi_scan_add_to_list(si, pnum, ec, &si->corr);
+		err = add_to_list(si, pnum, ec, &si->corr);
 		if (err)
 			return err;
 		goto adjust_mean_ec;
 	} else if (err == UBI_IO_PEB_FREE) {
 		/* No VID header - the physical eraseblock is free */
-		err = ubi_scan_add_to_list(si, pnum, ec, &si->free);
+		err = add_to_list(si, pnum, ec, &si->free);
 		if (err)
 			return err;
 		goto adjust_mean_ec;
 	}
 
-	vol_id = ubi32_to_cpu(vidh->vol_id);
+	vol_id = be32_to_cpu(vidh->vol_id);
 	if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOL_ID) {
-		int lnum = ubi32_to_cpu(vidh->lnum);
+		int lnum = be32_to_cpu(vidh->lnum);
 
 		/* Unsupported internal volume */
 		switch (vidh->compat) {
 		case UBI_COMPAT_DELETE:
 			ubi_msg("\"delete\" compatible internal volume %d:%d"
 				" found, remove it", vol_id, lnum);
-			err = ubi_scan_add_to_list(si, pnum, ec, &si->corr);
+			err = add_to_list(si, pnum, ec, &si->corr);
 			if (err)
 				return err;
 			break;
@@ -868,7 +879,7 @@
 		case UBI_COMPAT_PRESERVE:
 			ubi_msg("\"preserve\" compatible internal volume %d:%d"
 				" found", vol_id, lnum);
-			err = ubi_scan_add_to_list(si, pnum, ec, &si->alien);
+			err = add_to_list(si, pnum, ec, &si->alien);
 			if (err)
 				return err;
 			si->alien_peb_count += 1;
@@ -1109,7 +1120,7 @@
 	uint8_t *buf;
 
 	/*
-	 * At first, check that scanning information is ok.
+	 * At first, check that scanning information is OK.
 	 */
 	ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) {
 		int leb_count = 0;
@@ -1249,12 +1260,12 @@
 				goto bad_vid_hdr;
 			}
 
-			if (seb->sqnum != ubi64_to_cpu(vidh->sqnum)) {
+			if (seb->sqnum != be64_to_cpu(vidh->sqnum)) {
 				ubi_err("bad sqnum %llu", seb->sqnum);
 				goto bad_vid_hdr;
 			}
 
-			if (sv->vol_id != ubi32_to_cpu(vidh->vol_id)) {
+			if (sv->vol_id != be32_to_cpu(vidh->vol_id)) {
 				ubi_err("bad vol_id %d", sv->vol_id);
 				goto bad_vid_hdr;
 			}
@@ -1264,22 +1275,22 @@
 				goto bad_vid_hdr;
 			}
 
-			if (seb->lnum != ubi32_to_cpu(vidh->lnum)) {
+			if (seb->lnum != be32_to_cpu(vidh->lnum)) {
 				ubi_err("bad lnum %d", seb->lnum);
 				goto bad_vid_hdr;
 			}
 
-			if (sv->used_ebs != ubi32_to_cpu(vidh->used_ebs)) {
+			if (sv->used_ebs != be32_to_cpu(vidh->used_ebs)) {
 				ubi_err("bad used_ebs %d", sv->used_ebs);
 				goto bad_vid_hdr;
 			}
 
-			if (sv->data_pad != ubi32_to_cpu(vidh->data_pad)) {
+			if (sv->data_pad != be32_to_cpu(vidh->data_pad)) {
 				ubi_err("bad data_pad %d", sv->data_pad);
 				goto bad_vid_hdr;
 			}
 
-			if (seb->leb_ver != ubi32_to_cpu(vidh->leb_ver)) {
+			if (seb->leb_ver != be32_to_cpu(vidh->leb_ver)) {
 				ubi_err("bad leb_ver %u", seb->leb_ver);
 				goto bad_vid_hdr;
 			}
@@ -1288,12 +1299,12 @@
 		if (!last_seb)
 			continue;
 
-		if (sv->highest_lnum != ubi32_to_cpu(vidh->lnum)) {
+		if (sv->highest_lnum != be32_to_cpu(vidh->lnum)) {
 			ubi_err("bad highest_lnum %d", sv->highest_lnum);
 			goto bad_vid_hdr;
 		}
 
-		if (sv->last_data_size != ubi32_to_cpu(vidh->data_size)) {
+		if (sv->last_data_size != be32_to_cpu(vidh->data_size)) {
 			ubi_err("bad last_data_size %d", sv->last_data_size);
 			goto bad_vid_hdr;
 		}
@@ -1310,8 +1321,10 @@
 	memset(buf, 1, ubi->peb_count);
 	for (pnum = 0; pnum < ubi->peb_count; pnum++) {
 		err = ubi_io_is_bad(ubi, pnum);
-		if (err < 0)
+		if (err < 0) {
+			kfree(buf);
 			return err;
+		}
 		else if (err)
 			buf[pnum] = 0;
 	}
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
index 3949f61..140e82e 100644
--- a/drivers/mtd/ubi/scan.h
+++ b/drivers/mtd/ubi/scan.h
@@ -147,8 +147,6 @@
 		list_add_tail(&seb->u.list, list);
 }
 
-int ubi_scan_add_to_list(struct ubi_scan_info *si, int pnum, int ec,
-			 struct list_head *list);
 int ubi_scan_add_used(const struct ubi_device *ubi, struct ubi_scan_info *si,
 		      int pnum, int ec, const struct ubi_vid_hdr *vid_hdr,
 		      int bitflips);
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index feb647f..5959f91 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -35,6 +35,7 @@
 #include <linux/cdev.h>
 #include <linux/device.h>
 #include <linux/string.h>
+#include <linux/vmalloc.h>
 #include <linux/mtd/mtd.h>
 
 #include <mtd/ubi-header.h>
@@ -374,9 +375,11 @@
 #ifdef CONFIG_MTD_UBI_GLUEBI
 int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol);
 int ubi_destroy_gluebi(struct ubi_volume *vol);
+void ubi_gluebi_updated(struct ubi_volume *vol);
 #else
 #define ubi_create_gluebi(ubi, vol) 0
 #define ubi_destroy_gluebi(vol) 0
+#define ubi_gluebi_updated(vol)
 #endif
 
 /* eba.c */
diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c
index 8925b97..0efc586 100644
--- a/drivers/mtd/ubi/upd.c
+++ b/drivers/mtd/ubi/upd.c
@@ -150,7 +150,7 @@
 			vol->updating = 0;
 	}
 
-	vol->upd_buf = kmalloc(ubi->leb_size, GFP_KERNEL);
+	vol->upd_buf = vmalloc(ubi->leb_size);
 	if (!vol->upd_buf)
 		return -ENOMEM;
 
@@ -339,7 +339,7 @@
 		err = ubi_wl_flush(ubi);
 		if (err == 0) {
 			err = to_write;
-			kfree(vol->upd_buf);
+			vfree(vol->upd_buf);
 			vol->updating = 0;
 		}
 	}
diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c
index 622d0d1..ea0d5c8 100644
--- a/drivers/mtd/ubi/vmt.c
+++ b/drivers/mtd/ubi/vmt.c
@@ -228,7 +228,7 @@
 	for (i = 0; i < ubi->vtbl_slots; i++)
 		if (ubi->volumes[i] &&
 		    ubi->volumes[i]->name_len == req->name_len &&
-		    strcmp(ubi->volumes[i]->name, req->name) == 0) {
+		    !strcmp(ubi->volumes[i]->name, req->name)) {
 			dbg_err("volume \"%s\" exists (ID %d)", req->name, i);
 			goto out_unlock;
 		}
@@ -243,7 +243,6 @@
 	/* Reserve physical eraseblocks */
 	if (vol->reserved_pebs > ubi->avail_pebs) {
 		dbg_err("not enough PEBs, only %d available", ubi->avail_pebs);
-		spin_unlock(&ubi->volumes_lock);
 		err = -ENOSPC;
 		goto out_unlock;
 	}
@@ -281,7 +280,8 @@
 	if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
 		vol->used_ebs = vol->reserved_pebs;
 		vol->last_eb_bytes = vol->usable_leb_size;
-		vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+		vol->used_bytes =
+			(long long)vol->used_ebs * vol->usable_leb_size;
 	} else {
 		bytes = vol->used_bytes;
 		vol->last_eb_bytes = do_div(bytes, vol->usable_leb_size);
@@ -320,10 +320,10 @@
 
 	/* Fill volume table record */
 	memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record));
-	vtbl_rec.reserved_pebs = cpu_to_ubi32(vol->reserved_pebs);
-	vtbl_rec.alignment     = cpu_to_ubi32(vol->alignment);
-	vtbl_rec.data_pad      = cpu_to_ubi32(vol->data_pad);
-	vtbl_rec.name_len      = cpu_to_ubi16(vol->name_len);
+	vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs);
+	vtbl_rec.alignment     = cpu_to_be32(vol->alignment);
+	vtbl_rec.data_pad      = cpu_to_be32(vol->data_pad);
+	vtbl_rec.name_len      = cpu_to_be16(vol->name_len);
 	if (vol->vol_type == UBI_DYNAMIC_VOLUME)
 		vtbl_rec.vol_type = UBI_VID_DYNAMIC;
 	else
@@ -352,6 +352,7 @@
 	spin_lock(&ubi->volumes_lock);
 	ubi->rsvd_pebs -= vol->reserved_pebs;
 	ubi->avail_pebs += vol->reserved_pebs;
+	ubi->volumes[vol_id] = NULL;
 out_unlock:
 	spin_unlock(&ubi->volumes_lock);
 	kfree(vol);
@@ -368,6 +369,7 @@
 	spin_lock(&ubi->volumes_lock);
 	ubi->rsvd_pebs -= vol->reserved_pebs;
 	ubi->avail_pebs += vol->reserved_pebs;
+	ubi->volumes[vol_id] = NULL;
 	spin_unlock(&ubi->volumes_lock);
 	volume_sysfs_close(vol);
 	return err;
@@ -503,7 +505,7 @@
 
 	/* Change volume table record */
 	memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record));
-	vtbl_rec.reserved_pebs = cpu_to_ubi32(reserved_pebs);
+	vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs);
 	err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec);
 	if (err)
 		goto out_acc;
@@ -537,7 +539,8 @@
 	if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
 		vol->used_ebs = reserved_pebs;
 		vol->last_eb_bytes = vol->usable_leb_size;
-		vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+		vol->used_bytes =
+			(long long)vol->used_ebs * vol->usable_leb_size;
 	}
 
 	paranoid_check_volumes(ubi);
@@ -643,21 +646,33 @@
  * @ubi: UBI device description object
  * @vol_id: volume ID
  */
-static void paranoid_check_volume(const struct ubi_device *ubi, int vol_id)
+static void paranoid_check_volume(struct ubi_device *ubi, int vol_id)
 {
 	int idx = vol_id2idx(ubi, vol_id);
 	int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker;
-	const struct ubi_volume *vol = ubi->volumes[idx];
+	const struct ubi_volume *vol;
 	long long n;
 	const char *name;
 
-	reserved_pebs = ubi32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
+	spin_lock(&ubi->volumes_lock);
+	reserved_pebs = be32_to_cpu(ubi->vtbl[vol_id].reserved_pebs);
+	vol = ubi->volumes[idx];
 
 	if (!vol) {
 		if (reserved_pebs) {
 			ubi_err("no volume info, but volume exists");
 			goto fail;
 		}
+		spin_unlock(&ubi->volumes_lock);
+		return;
+	}
+
+	if (vol->exclusive) {
+		/*
+		 * The volume may be being created at the moment, do not check
+		 * it (e.g., it may be in the middle of ubi_create_volume().
+		 */
+		spin_unlock(&ubi->volumes_lock);
 		return;
 	}
 
@@ -726,7 +741,7 @@
 		goto fail;
 	}
 
-	n = vol->used_ebs * vol->usable_leb_size;
+	n = (long long)vol->used_ebs * vol->usable_leb_size;
 	if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
 		if (vol->corrupted != 0) {
 			ubi_err("corrupted dynamic volume");
@@ -765,9 +780,9 @@
 		}
 	}
 
-	alignment  = ubi32_to_cpu(ubi->vtbl[vol_id].alignment);
-	data_pad   = ubi32_to_cpu(ubi->vtbl[vol_id].data_pad);
-	name_len   = ubi16_to_cpu(ubi->vtbl[vol_id].name_len);
+	alignment  = be32_to_cpu(ubi->vtbl[vol_id].alignment);
+	data_pad   = be32_to_cpu(ubi->vtbl[vol_id].data_pad);
+	name_len   = be16_to_cpu(ubi->vtbl[vol_id].name_len);
 	upd_marker = ubi->vtbl[vol_id].upd_marker;
 	name       = &ubi->vtbl[vol_id].name[0];
 	if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC)
@@ -782,12 +797,14 @@
 		goto fail;
 	}
 
+	spin_unlock(&ubi->volumes_lock);
 	return;
 
 fail:
-	ubi_err("paranoid check failed");
+	ubi_err("paranoid check failed for volume %d", vol_id);
 	ubi_dbg_dump_vol_info(vol);
 	ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id);
+	spin_unlock(&ubi->volumes_lock);
 	BUG();
 }
 
@@ -800,10 +817,8 @@
 	int i;
 
 	mutex_lock(&ubi->vtbl_mutex);
-	spin_lock(&ubi->volumes_lock);
 	for (i = 0; i < ubi->vtbl_slots; i++)
 		paranoid_check_volume(ubi, i);
-	spin_unlock(&ubi->volumes_lock);
 	mutex_unlock(&ubi->vtbl_mutex);
 }
 #endif
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index b6fd6bb..bc5df50 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -93,12 +93,9 @@
 		vtbl_rec = &empty_vtbl_record;
 	else {
 		crc = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC);
-		vtbl_rec->crc = cpu_to_ubi32(crc);
+		vtbl_rec->crc = cpu_to_be32(crc);
 	}
 
-	dbg_msg("change record %d", idx);
-	ubi_dbg_dump_vtbl_record(vtbl_rec, idx);
-
 	mutex_lock(&ubi->vtbl_mutex);
 	memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record));
 	for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) {
@@ -141,18 +138,18 @@
 	for (i = 0; i < ubi->vtbl_slots; i++) {
 		cond_resched();
 
-		reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs);
-		alignment = ubi32_to_cpu(vtbl[i].alignment);
-		data_pad = ubi32_to_cpu(vtbl[i].data_pad);
+		reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
+		alignment = be32_to_cpu(vtbl[i].alignment);
+		data_pad = be32_to_cpu(vtbl[i].data_pad);
 		upd_marker = vtbl[i].upd_marker;
 		vol_type = vtbl[i].vol_type;
-		name_len = ubi16_to_cpu(vtbl[i].name_len);
+		name_len = be16_to_cpu(vtbl[i].name_len);
 		name = &vtbl[i].name[0];
 
 		crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC);
-		if (ubi32_to_cpu(vtbl[i].crc) != crc) {
+		if (be32_to_cpu(vtbl[i].crc) != crc) {
 			ubi_err("bad CRC at record %u: %#08x, not %#08x",
-				 i, crc, ubi32_to_cpu(vtbl[i].crc));
+				 i, crc, be32_to_cpu(vtbl[i].crc));
 			ubi_dbg_dump_vtbl_record(&vtbl[i], i);
 			return 1;
 		}
@@ -225,8 +222,8 @@
 	/* Checks that all names are unique */
 	for (i = 0; i < ubi->vtbl_slots - 1; i++) {
 		for (n = i + 1; n < ubi->vtbl_slots; n++) {
-			int len1 = ubi16_to_cpu(vtbl[i].name_len);
-			int len2 = ubi16_to_cpu(vtbl[n].name_len);
+			int len1 = be16_to_cpu(vtbl[i].name_len);
+			int len2 = be16_to_cpu(vtbl[n].name_len);
 
 			if (len1 > 0 && len1 == len2 &&
 			    !strncmp(vtbl[i].name, vtbl[n].name, len1)) {
@@ -288,13 +285,13 @@
 	}
 
 	vid_hdr->vol_type = UBI_VID_DYNAMIC;
-	vid_hdr->vol_id = cpu_to_ubi32(UBI_LAYOUT_VOL_ID);
+	vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOL_ID);
 	vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT;
 	vid_hdr->data_size = vid_hdr->used_ebs =
-			     vid_hdr->data_pad = cpu_to_ubi32(0);
-	vid_hdr->lnum = cpu_to_ubi32(copy);
-	vid_hdr->sqnum = cpu_to_ubi64(++si->max_sqnum);
-	vid_hdr->leb_ver = cpu_to_ubi32(old_seb ? old_seb->leb_ver + 1: 0);
+			     vid_hdr->data_pad = cpu_to_be32(0);
+	vid_hdr->lnum = cpu_to_be32(copy);
+	vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum);
+	vid_hdr->leb_ver = cpu_to_be32(old_seb ? old_seb->leb_ver + 1: 0);
 
 	/* The EC header is already there, write the VID header */
 	err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr);
@@ -317,14 +314,15 @@
 	return err;
 
 write_error:
-	kfree(new_seb);
-	/* May be this physical eraseblock went bad, try to pick another one */
-	if (++tries <= 5) {
-		err = ubi_scan_add_to_list(si, new_seb->pnum, new_seb->ec,
-					   &si->corr);
-		if (!err)
-			goto retry;
+	if (err == -EIO && ++tries <= 5) {
+		/*
+		 * Probably this physical eraseblock went bad, try to pick
+		 * another one.
+		 */
+		list_add_tail(&new_seb->u.list, &si->corr);
+		goto retry;
 	}
+	kfree(new_seb);
 out_free:
 	ubi_free_vid_hdr(ubi, vid_hdr);
 	return err;
@@ -380,11 +378,12 @@
 
 	/* Read both LEB 0 and LEB 1 into memory */
 	ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) {
-		leb[seb->lnum] = kzalloc(ubi->vtbl_size, GFP_KERNEL);
+		leb[seb->lnum] = vmalloc(ubi->vtbl_size);
 		if (!leb[seb->lnum]) {
 			err = -ENOMEM;
 			goto out_free;
 		}
+		memset(leb[seb->lnum], 0, ubi->vtbl_size);
 
 		err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0,
 				       ubi->vtbl_size);
@@ -415,7 +414,7 @@
 		}
 
 		/* Both LEB 1 and LEB 2 are OK and consistent */
-		kfree(leb[1]);
+		vfree(leb[1]);
 		return leb[0];
 	} else {
 		/* LEB 0 is corrupted or does not exist */
@@ -436,13 +435,13 @@
 			goto out_free;
 		ubi_msg("volume table was restored");
 
-		kfree(leb[0]);
+		vfree(leb[0]);
 		return leb[1];
 	}
 
 out_free:
-	kfree(leb[0]);
-	kfree(leb[1]);
+	vfree(leb[0]);
+	vfree(leb[1]);
 	return ERR_PTR(err);
 }
 
@@ -460,9 +459,10 @@
 	int i;
 	struct ubi_vtbl_record *vtbl;
 
-	vtbl = kzalloc(ubi->vtbl_size, GFP_KERNEL);
+	vtbl = vmalloc(ubi->vtbl_size);
 	if (!vtbl)
 		return ERR_PTR(-ENOMEM);
+	memset(vtbl, 0, ubi->vtbl_size);
 
 	for (i = 0; i < ubi->vtbl_slots; i++)
 		memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE);
@@ -472,7 +472,7 @@
 
 		err = create_vtbl(ubi, si, i, vtbl);
 		if (err) {
-			kfree(vtbl);
+			vfree(vtbl);
 			return ERR_PTR(err);
 		}
 	}
@@ -500,19 +500,19 @@
 	for (i = 0; i < ubi->vtbl_slots; i++) {
 		cond_resched();
 
-		if (ubi32_to_cpu(vtbl[i].reserved_pebs) == 0)
+		if (be32_to_cpu(vtbl[i].reserved_pebs) == 0)
 			continue; /* Empty record */
 
 		vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL);
 		if (!vol)
 			return -ENOMEM;
 
-		vol->reserved_pebs = ubi32_to_cpu(vtbl[i].reserved_pebs);
-		vol->alignment = ubi32_to_cpu(vtbl[i].alignment);
-		vol->data_pad = ubi32_to_cpu(vtbl[i].data_pad);
+		vol->reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs);
+		vol->alignment = be32_to_cpu(vtbl[i].alignment);
+		vol->data_pad = be32_to_cpu(vtbl[i].data_pad);
 		vol->vol_type = vtbl[i].vol_type == UBI_VID_DYNAMIC ?
 					UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME;
-		vol->name_len = ubi16_to_cpu(vtbl[i].name_len);
+		vol->name_len = be16_to_cpu(vtbl[i].name_len);
 		vol->usable_leb_size = ubi->leb_size - vol->data_pad;
 		memcpy(vol->name, vtbl[i].name, vol->name_len);
 		vol->name[vol->name_len] = '\0';
@@ -531,7 +531,8 @@
 		if (vol->vol_type == UBI_DYNAMIC_VOLUME) {
 			vol->used_ebs = vol->reserved_pebs;
 			vol->last_eb_bytes = vol->usable_leb_size;
-			vol->used_bytes = vol->used_ebs * vol->usable_leb_size;
+			vol->used_bytes =
+				(long long)vol->used_ebs * vol->usable_leb_size;
 			continue;
 		}
 
@@ -561,7 +562,8 @@
 		}
 
 		vol->used_ebs = sv->used_ebs;
-		vol->used_bytes = (vol->used_ebs - 1) * vol->usable_leb_size;
+		vol->used_bytes =
+			(long long)(vol->used_ebs - 1) * vol->usable_leb_size;
 		vol->used_bytes += sv->last_data_size;
 		vol->last_eb_bytes = sv->last_data_size;
 	}
@@ -578,7 +580,8 @@
 	vol->usable_leb_size = ubi->leb_size;
 	vol->used_ebs = vol->reserved_pebs;
 	vol->last_eb_bytes = vol->reserved_pebs;
-	vol->used_bytes = vol->used_ebs * (ubi->leb_size - vol->data_pad);
+	vol->used_bytes =
+		(long long)vol->used_ebs * (ubi->leb_size - vol->data_pad);
 	vol->vol_id = UBI_LAYOUT_VOL_ID;
 
 	ubi_assert(!ubi->volumes[i]);
@@ -718,7 +721,7 @@
 	int i, err;
 	struct ubi_scan_volume *sv;
 
-	empty_vtbl_record.crc = cpu_to_ubi32(0xf116c36b);
+	empty_vtbl_record.crc = cpu_to_be32(0xf116c36b);
 
 	/*
 	 * The number of supported volumes is limited by the eraseblock size
@@ -783,7 +786,7 @@
 	return 0;
 
 out_free:
-	kfree(ubi->vtbl);
+	vfree(ubi->vtbl);
 	for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++)
 		if (ubi->volumes[i]) {
 			kfree(ubi->volumes[i]);
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index ab2174a..a5a9b8d 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -667,7 +667,7 @@
 
 	dbg_wl("erased PEB %d, new EC %llu", e->pnum, ec);
 
-	ec_hdr->ec = cpu_to_ubi64(ec);
+	ec_hdr->ec = cpu_to_be64(ec);
 
 	err = ubi_io_write_ec_hdr(ubi, e->pnum, ec_hdr);
 	if (err)
@@ -1060,9 +1060,8 @@
 static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
 			int cancel)
 {
-	int err;
 	struct ubi_wl_entry *e = wl_wrk->e;
-	int pnum = e->pnum;
+	int pnum = e->pnum, err, need;
 
 	if (cancel) {
 		dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
@@ -1097,62 +1096,70 @@
 	kfree(wl_wrk);
 	kmem_cache_free(wl_entries_slab, e);
 
-	if (err != -EIO) {
+	if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
+	    err == -EBUSY) {
+		int err1;
+
+		/* Re-schedule the LEB for erasure */
+		err1 = schedule_erase(ubi, e, 0);
+		if (err1) {
+			err = err1;
+			goto out_ro;
+		}
+		return err;
+	} else if (err != -EIO) {
 		/*
 		 * If this is not %-EIO, we have no idea what to do. Scheduling
 		 * this physical eraseblock for erasure again would cause
 		 * errors again and again. Well, lets switch to RO mode.
 		 */
-		ubi_ro_mode(ubi);
-		return err;
+		goto out_ro;
 	}
 
 	/* It is %-EIO, the PEB went bad */
 
 	if (!ubi->bad_allowed) {
 		ubi_err("bad physical eraseblock %d detected", pnum);
-		ubi_ro_mode(ubi);
-		err = -EIO;
-	} else {
-		int need;
-
-		spin_lock(&ubi->volumes_lock);
-		need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
-		if (need > 0) {
-			need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
-			ubi->avail_pebs -= need;
-			ubi->rsvd_pebs += need;
-			ubi->beb_rsvd_pebs += need;
-			if (need > 0)
-				ubi_msg("reserve more %d PEBs", need);
-		}
-
-		if (ubi->beb_rsvd_pebs == 0) {
-			spin_unlock(&ubi->volumes_lock);
-			ubi_err("no reserved physical eraseblocks");
-			ubi_ro_mode(ubi);
-			return -EIO;
-		}
-
-		spin_unlock(&ubi->volumes_lock);
-		ubi_msg("mark PEB %d as bad", pnum);
-
-		err = ubi_io_mark_bad(ubi, pnum);
-		if (err) {
-			ubi_ro_mode(ubi);
-			return err;
-		}
-
-		spin_lock(&ubi->volumes_lock);
-		ubi->beb_rsvd_pebs -= 1;
-		ubi->bad_peb_count += 1;
-		ubi->good_peb_count -= 1;
-		ubi_calculate_reserved(ubi);
-		if (ubi->beb_rsvd_pebs == 0)
-			ubi_warn("last PEB from the reserved pool was used");
-		spin_unlock(&ubi->volumes_lock);
+		goto out_ro;
 	}
 
+	spin_lock(&ubi->volumes_lock);
+	need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
+	if (need > 0) {
+		need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
+		ubi->avail_pebs -= need;
+		ubi->rsvd_pebs += need;
+		ubi->beb_rsvd_pebs += need;
+		if (need > 0)
+			ubi_msg("reserve more %d PEBs", need);
+	}
+
+	if (ubi->beb_rsvd_pebs == 0) {
+		spin_unlock(&ubi->volumes_lock);
+		ubi_err("no reserved physical eraseblocks");
+		goto out_ro;
+	}
+
+	spin_unlock(&ubi->volumes_lock);
+	ubi_msg("mark PEB %d as bad", pnum);
+
+	err = ubi_io_mark_bad(ubi, pnum);
+	if (err)
+		goto out_ro;
+
+	spin_lock(&ubi->volumes_lock);
+	ubi->beb_rsvd_pebs -= 1;
+	ubi->bad_peb_count += 1;
+	ubi->good_peb_count -= 1;
+	ubi_calculate_reserved(ubi);
+	if (ubi->beb_rsvd_pebs == 0)
+		ubi_warn("last PEB from the reserved pool was used");
+	spin_unlock(&ubi->volumes_lock);
+
+	return err;
+
+out_ro:
+	ubi_ro_mode(ubi);
 	return err;
 }
 
@@ -1445,7 +1452,7 @@
 	if (ubi_devices_cnt == 0) {
 		wl_entries_slab = kmem_cache_create("ubi_wl_entry_slab",
 						    sizeof(struct ubi_wl_entry),
-						    0, 0, NULL, NULL);
+						    0, 0, NULL);
 		if (!wl_entries_slab)
 			return -ENOMEM;
 	}
@@ -1634,7 +1641,7 @@
 		goto out_free;
 	}
 
-	read_ec = ubi64_to_cpu(ec_hdr->ec);
+	read_ec = be64_to_cpu(ec_hdr->ec);
 	if (ec != read_ec) {
 		ubi_err("paranoid check failed for PEB %d", pnum);
 		ubi_err("read EC is %lld, should be %d", read_ec, ec);
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 4bee99b..be71868 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -174,8 +174,6 @@
 		mem_start = dev->mem_start & 7;
 	}
 
-	SET_MODULE_OWNER(dev);
-
 	if (io > 0x1ff) {	/* Check a single specified location. */
 		err = el1_probe1(dev, io);
 	} else if (io != 0) {
@@ -317,7 +315,6 @@
 	dev->tx_timeout = &el_timeout;
 	dev->watchdog_timeo = HZ;
 	dev->stop = &el1_close;
-	dev->get_stats = &el1_get_stats;
 	dev->set_multicast_list = &set_multicast_list;
 	dev->ethtool_ops = &netdev_ethtool_ops;
 	return 0;
@@ -376,7 +373,7 @@
 	if (el_debug)
 		printk (KERN_DEBUG "%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n",
 			dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS));
-	lp->stats.tx_errors++;
+	dev->stats.tx_errors++;
 	outb(TX_NORM, TX_CMD);
 	outb(RX_NORM, RX_CMD);
 	outb(AX_OFF, AX_CMD);	/* Just trigger a false interrupt. */
@@ -443,7 +440,7 @@
 		lp->tx_pkt_start = gp_start;
     		lp->collisions = 0;
 
-    		lp->stats.tx_bytes += skb->len;
+		dev->stats.tx_bytes += skb->len;
 
 		/*
 		 *	Command mode with status cleared should [in theory]
@@ -590,7 +587,7 @@
 				printk (KERN_DEBUG "%s: Transmit failed 16 times, Ethernet jammed?\n",dev->name);
 			outb(AX_SYS, AX_CMD);
 			lp->txing = 0;
-			lp->stats.tx_aborted_errors++;
+			dev->stats.tx_aborted_errors++;
 			netif_wake_queue(dev);
 		}
 		else if (txsr & TX_COLLISION)
@@ -608,7 +605,7 @@
 			outb(AX_SYS, AX_CMD);
 			outw(lp->tx_pkt_start, GP_LOW);
 			outb(AX_XMIT, AX_CMD);
-			lp->stats.collisions++;
+			dev->stats.collisions++;
 			spin_unlock(&lp->lock);
 			goto out;
 		}
@@ -617,7 +614,7 @@
 			/*
 			 *	It worked.. we will now fall through and receive
 			 */
-			lp->stats.tx_packets++;
+			dev->stats.tx_packets++;
 			if (el_debug > 6)
 				printk(KERN_DEBUG " Tx succeeded %s\n",
 		       			(txsr & TX_RDY) ? "." : "but tx is busy!");
@@ -642,10 +639,10 @@
 		 *	Just reading rx_status fixes most errors.
 		 */
 		if (rxsr & RX_MISSED)
-			lp->stats.rx_missed_errors++;
+			dev->stats.rx_missed_errors++;
 		else if (rxsr & RX_RUNT)
 		{	/* Handled to avoid board lock-up. */
-			lp->stats.rx_length_errors++;
+			dev->stats.rx_length_errors++;
 			if (el_debug > 5)
 				printk(KERN_DEBUG " runt.\n");
 		}
@@ -696,7 +693,6 @@
 
 static void el_receive(struct net_device *dev)
 {
-	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	int pkt_len;
 	struct sk_buff *skb;
@@ -710,7 +706,7 @@
 	{
 		if (el_debug)
 			printk(KERN_DEBUG "%s: bogus packet, length=%d\n", dev->name, pkt_len);
-		lp->stats.rx_over_errors++;
+		dev->stats.rx_over_errors++;
 		return;
 	}
 
@@ -729,7 +725,7 @@
 	if (skb == NULL)
 	{
 		printk(KERN_INFO "%s: Memory squeeze, dropping packet.\n", dev->name);
-		lp->stats.rx_dropped++;
+		dev->stats.rx_dropped++;
 		return;
 	}
 	else
@@ -744,8 +740,8 @@
 		skb->protocol=eth_type_trans(skb,dev);
 		netif_rx(skb);
 		dev->last_rx = jiffies;
-		lp->stats.rx_packets++;
-		lp->stats.rx_bytes+=pkt_len;
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes+=pkt_len;
 	}
 	return;
 }
@@ -813,23 +809,6 @@
 }
 
 /**
- * el1_get_stats:
- * @dev: The card to get the statistics for
- *
- * In smarter devices this function is needed to pull statistics off the
- * board itself. The 3c501 has no hardware statistics. We maintain them all
- * so they are by definition always up to date.
- *
- * Returns the statistics for the card from the card private data
- */
-
-static struct net_device_stats *el1_get_stats(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	return &lp->stats;
-}
-
-/**
  * set_multicast_list:
  * @dev: The device to adjust
  *
diff --git a/drivers/net/3c501.h b/drivers/net/3c501.h
index c56a2c6..cfec64e 100644
--- a/drivers/net/3c501.h
+++ b/drivers/net/3c501.h
@@ -11,7 +11,6 @@
 static void el_receive(struct net_device *dev);
 static void el_reset(struct net_device *dev);
 static int  el1_close(struct net_device *dev);
-static struct net_device_stats *el1_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
 static const struct ethtool_ops netdev_ethtool_ops;
 
@@ -29,7 +28,6 @@
 
 struct net_local
 {
-	struct net_device_stats stats;
 	int		tx_pkt_start;	/* The length of the current Tx packet. */
 	int		collisions;	/* Tx collisions this packet */
 	int		loading;	/* Spot buffer load collisions */
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index bc7e906..9c23336 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -95,8 +95,6 @@
     int base_addr = dev->base_addr;
     int irq = dev->irq;
 
-    SET_MODULE_OWNER(dev);
-
     if (base_addr > 0x1ff)	/* Check a single specified location. */
 	return el2_probe1(dev, base_addr);
     else if (base_addr != 0)		/* Don't probe at all. */
@@ -179,6 +177,7 @@
     int i, iobase_reg, membase_reg, saved_406, wordlength, retval;
     static unsigned version_printed;
     unsigned long vendor_id;
+    DECLARE_MAC_BUF(mac);
 
     if (!request_region(ioaddr, EL2_IO_EXTENT, DRV_NAME))
 	return -EBUSY;
@@ -228,7 +227,8 @@
 
     /* Retrieve and print the ethernet address. */
     for (i = 0; i < 6; i++)
-	printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+	dev->dev_addr[i] = inb(ioaddr + i);
+    printk("%s", print_mac(mac, dev->dev_addr));
 
     /* Map the 8390 back into the window. */
     outb(ECNTRL_THIN, ioaddr + 0x406);
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index e985a85..9c65734 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -169,21 +169,6 @@
 
 /*****************************************************************
  *
- * useful macros
- *
- *****************************************************************/
-
-#ifndef	TRUE
-#define	TRUE	1
-#endif
-
-#ifndef	FALSE
-#define	FALSE	0
-#endif
-
-
-/*****************************************************************
- *
  * List of I/O-addresses we try to auto-sense
  * Last element MUST BE 0!
  *****************************************************************/
@@ -270,7 +255,7 @@
 	spin_unlock_irqrestore(&adapter->lock, flags);
 }
 
-static int start_receive(struct net_device *, pcb_struct *);
+static bool start_receive(struct net_device *, pcb_struct *);
 
 static inline void adapter_reset(struct net_device *dev)
 {
@@ -328,28 +313,28 @@
 }
 
 /* Primitive functions used by send_pcb() */
-static inline unsigned int send_pcb_slow(unsigned int base_addr, unsigned char byte)
+static inline bool send_pcb_slow(unsigned int base_addr, unsigned char byte)
 {
 	unsigned long timeout;
 	outb_command(byte, base_addr);
 	for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
 		if (inb_status(base_addr) & HCRE)
-			return FALSE;
+			return false;
 	}
 	printk(KERN_WARNING "3c505: send_pcb_slow timed out\n");
-	return TRUE;
+	return true;
 }
 
-static inline unsigned int send_pcb_fast(unsigned int base_addr, unsigned char byte)
+static inline bool send_pcb_fast(unsigned int base_addr, unsigned char byte)
 {
 	unsigned int timeout;
 	outb_command(byte, base_addr);
 	for (timeout = 0; timeout < 40000; timeout++) {
 		if (inb_status(base_addr) & HCRE)
-			return FALSE;
+			return false;
 	}
 	printk(KERN_WARNING "3c505: send_pcb_fast timed out\n");
-	return TRUE;
+	return true;
 }
 
 /* Check to see if the receiver needs restarting, and kick it if so */
@@ -386,7 +371,7 @@
  * timeout is reduced to 500us).
  */
 
-static int send_pcb(struct net_device *dev, pcb_struct * pcb)
+static bool send_pcb(struct net_device *dev, pcb_struct * pcb)
 {
 	int i;
 	unsigned long timeout;
@@ -396,14 +381,14 @@
 	check_3c505_dma(dev);
 
 	if (adapter->dmaing && adapter->current_dma.direction == 0)
-		return FALSE;
+		return false;
 
 	/* Avoid contention */
 	if (test_and_set_bit(1, &adapter->send_pcb_semaphore)) {
 		if (elp_debug >= 3) {
 			printk(KERN_DEBUG "%s: send_pcb entered while threaded\n", dev->name);
 		}
-		return FALSE;
+		return false;
 	}
 	/*
 	 * load each byte into the command register and
@@ -435,7 +420,7 @@
 		switch (GET_ASF(dev->base_addr)) {
 		case ASF_PCB_ACK:
 			adapter->send_pcb_semaphore = 0;
-			return TRUE;
+			return true;
 
 		case ASF_PCB_NAK:
 #ifdef ELP_DEBUG
@@ -453,7 +438,7 @@
 	spin_unlock_irqrestore(&adapter->lock, flags);
       abort:
 	adapter->send_pcb_semaphore = 0;
-	return FALSE;
+	return false;
 }
 
 
@@ -470,7 +455,7 @@
  *
  *****************************************************************/
 
-static int receive_pcb(struct net_device *dev, pcb_struct * pcb)
+static bool receive_pcb(struct net_device *dev, pcb_struct * pcb)
 {
 	int i, j;
 	int total_length;
@@ -487,7 +472,7 @@
 	while (((stat = get_status(dev->base_addr)) & ACRF) == 0 && time_before(jiffies, timeout));
 	if (time_after_eq(jiffies, timeout)) {
 		TIMEOUT_MSG(__LINE__);
-		return FALSE;
+		return false;
 	}
 	pcb->command = inb_command(dev->base_addr);
 
@@ -497,14 +482,14 @@
 	if (time_after_eq(jiffies, timeout)) {
 		TIMEOUT_MSG(__LINE__);
 		printk(KERN_INFO "%s: status %02x\n", dev->name, stat);
-		return FALSE;
+		return false;
 	}
 	pcb->length = inb_command(dev->base_addr);
 
 	if (pcb->length > MAX_PCB_DATA) {
 		INVALID_PCB_MSG(pcb->length);
 		adapter_reset(dev);
-		return FALSE;
+		return false;
 	}
 	/* read the data */
 	spin_lock_irqsave(&adapter->lock, flags);
@@ -519,7 +504,7 @@
 	spin_unlock_irqrestore(&adapter->lock, flags);
 	if (j >= 20000) {
 		TIMEOUT_MSG(__LINE__);
-		return FALSE;
+		return false;
 	}
 	/* woops, the last "data" byte was really the length! */
 	total_length = pcb->data.raw[--i];
@@ -529,7 +514,7 @@
 		if (elp_debug >= 2)
 			printk(KERN_WARNING "%s: mangled PCB received\n", dev->name);
 		set_hsf(dev, HSF_PCB_NAK);
-		return FALSE;
+		return false;
 	}
 
 	if (pcb->command == CMD_RECEIVE_PACKET_COMPLETE) {
@@ -538,14 +523,14 @@
 				set_hsf(dev, HSF_PCB_NAK);
 				printk(KERN_WARNING "%s: PCB rejected, transfer in progress and backlog full\n", dev->name);
 				pcb->command = 0;
-				return TRUE;
+				return true;
 			} else {
 				pcb->command = 0xff;
 			}
 		}
 	}
 	set_hsf(dev, HSF_PCB_ACK);
-	return TRUE;
+	return true;
 }
 
 /******************************************************
@@ -555,9 +540,9 @@
  *
  ******************************************************/
 
-static int start_receive(struct net_device *dev, pcb_struct * tx_pcb)
+static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb)
 {
-	int status;
+	bool status;
 	elp_device *adapter = dev->priv;
 
 	if (elp_debug >= 3)
@@ -984,7 +969,7 @@
  *
  ******************************************************/
 
-static int send_packet(struct net_device *dev, struct sk_buff *skb)
+static bool send_packet(struct net_device *dev, struct sk_buff *skb)
 {
 	elp_device *adapter = dev->priv;
 	unsigned long target;
@@ -998,7 +983,7 @@
 	if (test_and_set_bit(0, (void *) &adapter->busy)) {
 		if (elp_debug >= 2)
 			printk(KERN_DEBUG "%s: transmit blocked\n", dev->name);
-		return FALSE;
+		return false;
 	}
 
 	adapter->stats.tx_bytes += nlen;
@@ -1015,7 +1000,7 @@
 
 	if (!send_pcb(dev, &adapter->tx_pcb)) {
 		adapter->busy = 0;
-		return FALSE;
+		return false;
 	}
 	/* if this happens, we die */
 	if (test_and_set_bit(0, (void *) &adapter->dmaing))
@@ -1047,7 +1032,7 @@
 	if (elp_debug >= 3)
 		printk(KERN_DEBUG "%s: DMA transfer started\n", dev->name);
 
-	return TRUE;
+	return true;
 }
 
 /*
@@ -1401,8 +1386,7 @@
 	unsigned long timeout;
 	unsigned long cookie = 0;
 	int err = -ENODEV;
-
-	SET_MODULE_OWNER(dev);
+	DECLARE_MAC_BUF(mac);
 
 	/*
 	 *  setup adapter structure
@@ -1538,11 +1522,10 @@
 	/*
 	 * print remainder of startup message
 	 */
-	printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, ",
-	       dev->name, dev->base_addr, dev->irq, dev->dma);
-	printk("addr %02x:%02x:%02x:%02x:%02x:%02x, ",
-	       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-	       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+	printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, "
+	       "addr %s, ",
+	       dev->name, dev->base_addr, dev->irq, dev->dma,
+	       print_mac(mac, dev->dev_addr));
 
 	/*
 	 * read more information from the adapter
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index eed4299..964d31a 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -118,7 +118,6 @@
 
 /* Information that need to be kept for each board. */
 struct net_local {
-	struct net_device_stats stats;
 	int last_restart;
 	ushort rx_head;
 	ushort rx_tail;
@@ -289,7 +288,6 @@
 static irqreturn_t el16_interrupt(int irq, void *dev_id);
 static void el16_rx(struct net_device *dev);
 static int	el16_close(struct net_device *dev);
-static struct net_device_stats *el16_get_stats(struct net_device *dev);
 static void el16_tx_timeout (struct net_device *dev);
 
 static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad);
@@ -327,8 +325,6 @@
 		mem_start = dev->mem_start & 15;
 	}
 
-	SET_MODULE_OWNER(dev);
-
 	if (io > 0x1ff) 	/* Check a single specified location. */
 		err = el16_probe1(dev, io);
 	else if (io != 0)
@@ -361,6 +357,7 @@
 	static unsigned char init_ID_done, version_printed;
 	int i, irq, irqval, retval;
 	struct net_local *lp;
+	DECLARE_MAC_BUF(mac);
 
 	if (init_ID_done == 0) {
 		ushort lrs_state = 0xff;
@@ -406,10 +403,9 @@
 	dev->base_addr = ioaddr;
 
 	outb(0x01, ioaddr + MISC_CTRL);
-	for (i = 0; i < 6; i++) {
+	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = inb(ioaddr + i);
-		printk(" %02x", dev->dev_addr[i]);
-	}
+	printk(" %s", print_mac(mac, dev->dev_addr));
 
 	if (mem_start)
 		net_debug = mem_start & 7;
@@ -457,7 +453,6 @@
  	dev->open = el16_open;
  	dev->stop = el16_close;
 	dev->hard_start_xmit = el16_send_packet;
-	dev->get_stats	= el16_get_stats;
 	dev->tx_timeout = el16_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	dev->ethtool_ops = &netdev_ethtool_ops;
@@ -491,7 +486,7 @@
 			readw(shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" :
 			"network cable problem");
 	/* Try to restart the adaptor. */
-	if (lp->last_restart == lp->stats.tx_packets) {
+	if (lp->last_restart == dev->stats.tx_packets) {
 		if (net_debug > 1)
 			printk ("Resetting board.\n");
 		/* Completely reset the adaptor. */
@@ -503,7 +498,7 @@
 			printk ("Kicking board.\n");
 		writew(0xf000 | CUC_START | RX_START, shmem + iSCB_CMD);
 		outb (0, ioaddr + SIGNAL_CA);	/* Issue channel-attn. */
-		lp->last_restart = lp->stats.tx_packets;
+		lp->last_restart = dev->stats.tx_packets;
 	}
 	dev->trans_start = jiffies;
 	netif_wake_queue (dev);
@@ -522,7 +517,7 @@
 
 	spin_lock_irqsave (&lp->lock, flags);
 
-	lp->stats.tx_bytes += length;
+	dev->stats.tx_bytes += length;
 	/* Disable the 82586's input to the interrupt line. */
 	outb (0x80, ioaddr + MISC_CTRL);
 
@@ -581,14 +576,14 @@
 	  }
 	  /* Tx unsuccessful or some interesting status bit set. */
 	  if (!(tx_status & 0x2000) || (tx_status & 0x0f3f)) {
-		lp->stats.tx_errors++;
-		if (tx_status & 0x0600)  lp->stats.tx_carrier_errors++;
-		if (tx_status & 0x0100)  lp->stats.tx_fifo_errors++;
-		if (!(tx_status & 0x0040))  lp->stats.tx_heartbeat_errors++;
-		if (tx_status & 0x0020)  lp->stats.tx_aborted_errors++;
-		lp->stats.collisions += tx_status & 0xf;
+		dev->stats.tx_errors++;
+		if (tx_status & 0x0600)  dev->stats.tx_carrier_errors++;
+		if (tx_status & 0x0100)  dev->stats.tx_fifo_errors++;
+		if (!(tx_status & 0x0040))  dev->stats.tx_heartbeat_errors++;
+		if (tx_status & 0x0020)  dev->stats.tx_aborted_errors++;
+		dev->stats.collisions += tx_status & 0xf;
 	  }
-	  lp->stats.tx_packets++;
+	  dev->stats.tx_packets++;
 	  if (net_debug > 5)
 		  printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
 	  lp->tx_reap += TX_BUF_SIZE;
@@ -667,17 +662,6 @@
 	return 0;
 }
 
-/* Get the current statistics.	This may be called with the card open or
-   closed. */
-static struct net_device_stats *el16_get_stats(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	/* ToDo: decide if there are any useful statistics from the SCB. */
-
-	return &lp->stats;
-}
-
 /* Initialize the Rx-block list. */
 static void init_rx_bufs(struct net_device *dev)
 {
@@ -854,12 +838,12 @@
 				   pkt_len);
 		} else if ((frame_status & 0x2000) == 0) {
 			/* Frame Rxed, but with error. */
-			lp->stats.rx_errors++;
-			if (frame_status & 0x0800) lp->stats.rx_crc_errors++;
-			if (frame_status & 0x0400) lp->stats.rx_frame_errors++;
-			if (frame_status & 0x0200) lp->stats.rx_fifo_errors++;
-			if (frame_status & 0x0100) lp->stats.rx_over_errors++;
-			if (frame_status & 0x0080) lp->stats.rx_length_errors++;
+			dev->stats.rx_errors++;
+			if (frame_status & 0x0800) dev->stats.rx_crc_errors++;
+			if (frame_status & 0x0400) dev->stats.rx_frame_errors++;
+			if (frame_status & 0x0200) dev->stats.rx_fifo_errors++;
+			if (frame_status & 0x0100) dev->stats.rx_over_errors++;
+			if (frame_status & 0x0080) dev->stats.rx_length_errors++;
 		} else {
 			/* Malloc up new buffer. */
 			struct sk_buff *skb;
@@ -868,7 +852,7 @@
 			skb = dev_alloc_skb(pkt_len+2);
 			if (skb == NULL) {
 				printk("%s: Memory squeeze, dropping packet.\n", dev->name);
-				lp->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 				break;
 			}
 
@@ -880,8 +864,8 @@
 			skb->protocol=eth_type_trans(skb,dev);
 			netif_rx(skb);
 			dev->last_rx = jiffies;
-			lp->stats.rx_packets++;
-			lp->stats.rx_bytes += pkt_len;
+			dev->stats.rx_packets++;
+			dev->stats.rx_bytes += pkt_len;
 		}
 
 		/* Clear the status word and set End-of-List on the rx frame. */
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 127f608..edda6e1 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -299,7 +299,7 @@
 	{ }	/* terminate list */
 };
 
-static u16 el3_isapnp_phys_addr[8][3];
+static __be16 el3_isapnp_phys_addr[8][3];
 static int nopnp;
 #endif /* __ISAPNP__ */
 
@@ -313,8 +313,9 @@
 static int __init el3_common_init(struct net_device *dev)
 {
 	struct el3_private *lp = netdev_priv(dev);
-	short i;
 	int err;
+	DECLARE_MAC_BUF(mac);
+	const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
 
 	spin_lock_init(&lp->lock);
 
@@ -346,17 +347,10 @@
 		return err;
 	}
 
-	{
-		const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
-		printk("%s: 3c5x9 found at %#3.3lx, %s port, address ",
-			dev->name, dev->base_addr,
-			if_names[(dev->if_port & 0x03)]);
-	}
-
-	/* Read in the station address. */
-	for (i = 0; i < 6; i++)
-		printk(" %2.2x", dev->dev_addr[i]);
-	printk(", IRQ %d.\n", dev->irq);
+	printk(KERN_INFO "%s: 3c5x9 found at %#3.3lx, %s port, "
+	       "address %s, IRQ %d.\n",
+	       dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)],
+	       print_mac(mac, dev->dev_addr), dev->irq);
 
 	if (el3_debug > 0)
 		printk(KERN_INFO "%s", version);
@@ -385,7 +379,7 @@
 	struct el3_private *lp;
 	short lrs_state = 0xff, i;
 	int ioaddr, irq, if_port;
-	u16 phys_addr[3];
+	__be16 phys_addr[3];
 	static int current_tag;
 	int err = -ENODEV;
 #if defined(__ISAPNP__)
@@ -432,7 +426,6 @@
 					return -ENOMEM;
 			}
 
-			SET_MODULE_OWNER(dev);
 			SET_NETDEV_DEV(dev, &idev->dev);
 			pnp_cards++;
 
@@ -524,8 +517,6 @@
 	if (!dev)
 		return -ENOMEM;
 
-	SET_MODULE_OWNER(dev);
-
 	netdev_boot_setup_check(dev);
 
 	/* Set passed-in IRQ or I/O Addr. */
@@ -644,7 +635,6 @@
 			return -ENOMEM;
 	}
 
-	SET_MODULE_OWNER(dev);
 	netdev_boot_setup_check(dev);
 
 	memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
@@ -704,8 +694,6 @@
 		return -ENOMEM;
 	}
 
-	SET_MODULE_OWNER(dev);
-
 	netdev_boot_setup_check(dev);
 
 	memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr));
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 290166d..275e751 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -501,8 +501,6 @@
 		netdev_boot_setup_check(dev);
 	}
 
-	SET_MODULE_OWNER(dev);
-
 #ifdef __ISAPNP__
 	if(nopnp == 1)
 		goto no_pnp;
@@ -571,6 +569,7 @@
 	unsigned int eeprom[0x40], checksum = 0;	/* EEPROM contents */
 	int i;
 	int irq;
+	DECLARE_MAC_BUF(mac);
 
 	if (idev) {
 		irq = pnp_irq(idev, 0);
@@ -632,8 +631,7 @@
 	checksum = (checksum ^ (checksum >> 8)) & 0xff;
 	if (checksum != 0x00)
 		printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
-	for (i = 0; i < 6; i++)
-		printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
+	printk(" %s", print_mac(mac, dev->dev_addr));
 	if (eeprom[16] == 0x11c7) {	/* Corkscrew */
 		if (request_dma(dev->dma, "3c515")) {
 			printk(", DMA %d allocation failed", dev->dma);
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index ab18343..239fc42 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -383,8 +383,8 @@
 static int elmc_getinfo(char *buf, int slot, void *d)
 {
 	int len = 0;
-	struct net_device *dev = (struct net_device *) d;
-	int i;
+	struct net_device *dev = d;
+	DECLARE_MAC_BUF(mac);
 
 	if (dev == NULL)
 		return len;
@@ -399,12 +399,8 @@
 	len += sprintf(buf + len, "Transceiver: %s\n", dev->if_port ?
 		       "External" : "Internal");
 	len += sprintf(buf + len, "Device: %s\n", dev->name);
-	len += sprintf(buf + len, "Hardware Address:");
-	for (i = 0; i < 6; i++) {
-		len += sprintf(buf + len, " %02x", dev->dev_addr[i]);
-	}
-	buf[len++] = '\n';
-	buf[len] = 0;
+	len += sprintf(buf + len, "Hardware Address: %s\n",
+		       print_mac(mac, dev->dev_addr));
 
 	return len;
 }				/* elmc_getinfo() */
@@ -422,8 +418,8 @@
 	unsigned int size = 0;
 	int retval;
 	struct priv *pr = dev->priv;
+	DECLARE_MAC_BUF(mac);
 
-	SET_MODULE_OWNER(dev);
 	if (MCA_bus == 0) {
 		return -ENODEV;
 	}
@@ -545,12 +541,11 @@
 
 	/* The hardware address for the 3c523 is stored in the first six
 	   bytes of the IO address. */
-	printk(KERN_INFO "%s: hardware address ", dev->name);
-	for (i = 0; i < 6; i++) {
+	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = inb(dev->base_addr + i);
-		printk(" %02x", dev->dev_addr[i]);
-	}
-	printk("\n");
+
+	printk(KERN_INFO "%s: hardware address %s\n",
+	       dev->name, print_mac(mac, dev->dev_addr));
 
 	dev->open = &elmc_open;
 	dev->stop = &elmc_close;
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index c7b571b..b72b89d 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -257,8 +257,6 @@
 	if (unit >= 0)
 		sprintf(dev->name, "eth%d", unit);
 
-	SET_MODULE_OWNER(dev);
-
 	/* Do not check any supplied i/o locations.
 	   POS registers usually don't fail :) */
 
@@ -338,6 +336,7 @@
 		"82586 initialisation failure",
 		"Adapter list configuration error"
 	};
+	DECLARE_MAC_BUF(mac);
 
 	/* Time to play MCA games */
 
@@ -398,17 +397,17 @@
 	 *	Go PROM browsing
 	 */
 
-	printk("%s: Address ", dev->name);
-
 	/* Retrieve and print the ethernet address. */
 	for (i = 0; i < 6; i++)
 	{
 		mca_write_pos(slot, 6, i+12);
 		mca_write_pos(slot, 7, 0);
 
-		printk(" %2.2x", dev->dev_addr[i] = mca_read_pos(slot,3));
+		dev->dev_addr[i] = mca_read_pos(slot,3);
 	}
 
+	printk("%s: Address %s", dev->name, print_mac(mac, dev->dev_addr));
+
 	mca_write_pos(slot, 6, 0);
 	mca_write_pos(slot, 7, 0);
 
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 6deb20f..8d3893d 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -538,10 +538,10 @@
 #define LAST_FRAG 	0x80000000			/* Last Addr/Len pair in descriptor. */
 #define DN_COMPLETE	0x00010000			/* This packet has been downloaded */
 struct boom_rx_desc {
-	u32 next;					/* Last entry points to 0.   */
-	s32 status;
-	u32 addr;					/* Up to 63 addr/len pairs possible. */
-	s32 length;					/* Set LAST_FRAG to indicate last pair. */
+	__le32 next;					/* Last entry points to 0.   */
+	__le32 status;
+	__le32 addr;					/* Up to 63 addr/len pairs possible. */
+	__le32 length;					/* Set LAST_FRAG to indicate last pair. */
 };
 /* Values for the Rx status entry. */
 enum rx_desc_status {
@@ -558,16 +558,16 @@
 #endif
 
 struct boom_tx_desc {
-	u32 next;					/* Last entry points to 0.   */
-	s32 status;					/* bits 0:12 length, others see below.  */
+	__le32 next;					/* Last entry points to 0.   */
+	__le32 status;					/* bits 0:12 length, others see below.  */
 #if DO_ZEROCOPY
 	struct {
-		u32 addr;
-		s32 length;
+		__le32 addr;
+		__le32 length;
 	} frag[1+MAX_SKB_FRAGS];
 #else
-		u32 addr;
-		s32 length;
+		__le32 addr;
+		__le32 length;
 #endif
 };
 
@@ -705,7 +705,7 @@
 
 static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
 				   int chip_idx, int card_idx);
-static void vortex_up(struct net_device *dev);
+static int vortex_up(struct net_device *dev);
 static void vortex_down(struct net_device *dev, int final);
 static int vortex_open(struct net_device *dev);
 static void mdio_sync(void __iomem *ioaddr, int bits);
@@ -841,8 +841,11 @@
 			return -EBUSY;
 		}
 		if (netif_running(dev)) {
-			vortex_up(dev);
-			netif_device_attach(dev);
+			err = vortex_up(dev);
+			if (err)
+				return err;
+			else
+				netif_device_attach(dev);
 		}
 	}
 	return 0;
@@ -1011,6 +1014,7 @@
 	char *print_name = "3c59x";
 	struct pci_dev *pdev = NULL;
 	struct eisa_device *edev = NULL;
+	DECLARE_MAC_BUF(mac);
 
 	if (!printed_version) {
 		printk (version);
@@ -1033,7 +1037,6 @@
 		printk (KERN_ERR PFX "unable to allocate etherdev, aborting\n");
 		goto out;
 	}
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, gendev);
 	vp = netdev_priv(dev);
 
@@ -1128,7 +1131,7 @@
 					   + sizeof(struct boom_tx_desc) * TX_RING_SIZE,
 					   &vp->rx_ring_dma);
 	retval = -ENOMEM;
-	if (vp->rx_ring == 0)
+	if (!vp->rx_ring)
 		goto free_region;
 
 	vp->tx_ring = (struct boom_tx_desc *)(vp->rx_ring + RX_RING_SIZE);
@@ -1201,12 +1204,10 @@
 	if ((checksum != 0x00) && !(vci->drv_flags & IS_TORNADO))
 		printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
 	for (i = 0; i < 3; i++)
-		((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
+		((__be16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
 	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-	if (print_info) {
-		for (i = 0; i < 6; i++)
-			printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
-	}
+	if (print_info)
+		printk(" %s", print_mac(mac, dev->dev_addr));
 	/* Unfortunately an all zero eeprom passes the checksum and this
 	   gets found in the wild in failure cases. Crypto is hard 8) */
 	if (!is_valid_ether_addr(dev->dev_addr)) {
@@ -1484,19 +1485,24 @@
 	}
 }
 
-static void
+static int
 vortex_up(struct net_device *dev)
 {
 	struct vortex_private *vp = netdev_priv(dev);
 	void __iomem *ioaddr = vp->ioaddr;
 	unsigned int config;
-	int i, mii_reg1, mii_reg5;
+	int i, mii_reg1, mii_reg5, err;
 
 	if (VORTEX_PCI(vp)) {
 		pci_set_power_state(VORTEX_PCI(vp), PCI_D0);	/* Go active */
 		if (vp->pm_state_valid)
 			pci_restore_state(VORTEX_PCI(vp));
-		pci_enable_device(VORTEX_PCI(vp));
+		err = pci_enable_device(VORTEX_PCI(vp));
+		if (err) {
+			printk(KERN_WARNING "%s: Could not enable device \n",
+				dev->name);
+			goto err_out;
+		}
 	}
 
 	/* Before initializing select the active media port. */
@@ -1555,6 +1561,7 @@
 		mii_reg1 = mdio_read(dev, vp->phys[0], MII_BMSR);
 		mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA);
 		vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0);
+		vp->mii.full_duplex = vp->full_duplex;
 
 		vortex_check_media(dev, 1);
 	}
@@ -1660,6 +1667,8 @@
 	if (vp->cb_fn_base)			/* The PCMCIA people are idiots.  */
 		iowrite32(0x8000, vp->cb_fn_base + 4);
 	netif_start_queue (dev);
+err_out:
+	return err;
 }
 
 static int
@@ -1673,7 +1682,7 @@
 	if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ?
 				&boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev))) {
 		printk(KERN_ERR "%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
-		goto out;
+		goto err;
 	}
 
 	if (vp->full_bus_master_rx) { /* Boomerang bus master. */
@@ -1702,20 +1711,22 @@
 				}
 			}
 			retval = -ENOMEM;
-			goto out_free_irq;
+			goto err_free_irq;
 		}
 		/* Wrap the ring. */
 		vp->rx_ring[i-1].next = cpu_to_le32(vp->rx_ring_dma);
 	}
 
-	vortex_up(dev);
-	return 0;
+	retval = vortex_up(dev);
+	if (!retval)
+		goto out;
 
-out_free_irq:
+err_free_irq:
 	free_irq(dev->irq, dev);
-out:
+err:
 	if (vortex_debug > 1)
 		printk(KERN_ERR "%s: vortex_open() fails: returning %d\n", dev->name, retval);
+out:
 	return retval;
 }
 
@@ -2489,7 +2500,7 @@
 
 			/* Check if the packet is long enough to just accept without
 			   copying to a properly sized skbuff. */
-			if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
+			if (pkt_len < rx_copybreak && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
 				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
 				pci_dma_sync_single_for_cpu(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
 				/* 'skb_put()' points to the start of sk_buff data area. */
@@ -2822,9 +2833,14 @@
 	vortex_debug = dbg;
 }
 
-static int vortex_get_stats_count(struct net_device *dev)
+static int vortex_get_sset_count(struct net_device *dev, int sset)
 {
-	return VORTEX_NUM_STATS;
+	switch (sset) {
+	case ETH_SS_STATS:
+		return VORTEX_NUM_STATS;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void vortex_get_ethtool_stats(struct net_device *dev,
@@ -2881,12 +2897,11 @@
 	.get_msglevel           = vortex_get_msglevel,
 	.set_msglevel           = vortex_set_msglevel,
 	.get_ethtool_stats      = vortex_get_ethtool_stats,
-	.get_stats_count        = vortex_get_stats_count,
+	.get_sset_count		= vortex_get_sset_count,
 	.get_settings           = vortex_get_settings,
 	.set_settings           = vortex_set_settings,
 	.get_link               = ethtool_op_get_link,
 	.nway_reset             = vortex_nway_reset,
-	.get_perm_addr		= ethtool_op_get_perm_addr,
 };
 
 #ifdef CONFIG_PCI
@@ -2899,7 +2914,7 @@
 	struct vortex_private *vp = netdev_priv(dev);
 	void __iomem *ioaddr = vp->ioaddr;
 	unsigned long flags;
-	int state = 0;
+	pci_power_t state = 0;
 
 	if(VORTEX_PCI(vp))
 		state = VORTEX_PCI(vp)->current_state;
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index e89ace1..224e0bf 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -305,18 +305,18 @@
 
                 /* We got an incomplete frame? */
                 if ((bits & LE_R1_POK) != LE_R1_POK) {
-                        lp->stats.rx_over_errors++;
-                        lp->stats.rx_errors++;
+                        dev->stats.rx_over_errors++;
+                        dev->stats.rx_errors++;
                         continue;
                 } else if (bits & LE_R1_ERR) {
                         /* Count only the end frame as a rx error,
                          * not the beginning
                          */
-                        if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
-                        if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
-                        if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
-                        if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
-                        if (bits & LE_R1_EOP) lp->stats.rx_errors++;
+                        if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++;
+                        if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++;
+                        if (bits & LE_R1_OFL) dev->stats.rx_over_errors++;
+                        if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++;
+                        if (bits & LE_R1_EOP) dev->stats.rx_errors++;
                 } else {
                         len = (rd->mblength & 0xfff) - 4;
                         skb = dev_alloc_skb (len+2);
@@ -324,7 +324,7 @@
                         if (skb == 0) {
                                 printk ("%s: Memory squeeze, deferring packet.\n",
                                         dev->name);
-                                lp->stats.rx_dropped++;
+                                dev->stats.rx_dropped++;
                                 rd->mblength = 0;
                                 rd->rmd1_bits = LE_R1_OWN;
                                 lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
@@ -339,8 +339,8 @@
                         skb->protocol = eth_type_trans (skb, dev);
 			netif_rx (skb);
 			dev->last_rx = jiffies;
-			lp->stats.rx_packets++;
-			lp->stats.rx_bytes += len;
+			dev->stats.rx_packets++;
+			dev->stats.rx_bytes += len;
                 }
 
                 /* Return the packet to the pool */
@@ -377,12 +377,12 @@
                 if (td->tmd1_bits & LE_T1_ERR) {
                         status = td->misc;
 
-                        lp->stats.tx_errors++;
-                        if (status & LE_T3_RTY)  lp->stats.tx_aborted_errors++;
-                        if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+                        dev->stats.tx_errors++;
+                        if (status & LE_T3_RTY)  dev->stats.tx_aborted_errors++;
+                        if (status & LE_T3_LCOL) dev->stats.tx_window_errors++;
 
                         if (status & LE_T3_CLOS) {
-                                lp->stats.tx_carrier_errors++;
+                                dev->stats.tx_carrier_errors++;
                                 if (lp->auto_select) {
                                         lp->tpe = 1 - lp->tpe;
                                         printk("%s: Carrier Lost, trying %s\n",
@@ -400,7 +400,7 @@
                         /* buffer errors and underflows turn off the transmitter */
                         /* Restart the adapter */
                         if (status & (LE_T3_BUF|LE_T3_UFL)) {
-                                lp->stats.tx_fifo_errors++;
+                                dev->stats.tx_fifo_errors++;
 
                                 printk ("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
                                         dev->name);
@@ -420,13 +420,13 @@
 
                         /* One collision before packet was sent. */
                         if (td->tmd1_bits & LE_T1_EONE)
-                                lp->stats.collisions++;
+                                dev->stats.collisions++;
 
                         /* More than one collision, be optimistic. */
                         if (td->tmd1_bits & LE_T1_EMORE)
-                                lp->stats.collisions += 2;
+                                dev->stats.collisions += 2;
 
-                        lp->stats.tx_packets++;
+                        dev->stats.tx_packets++;
                 }
 
                 j = (j + 1) & lp->tx_ring_mod_mask;
@@ -471,9 +471,9 @@
 
         /* Log misc errors. */
         if (csr0 & LE_C0_BABL)
-                lp->stats.tx_errors++;       /* Tx babble. */
+                dev->stats.tx_errors++;       /* Tx babble. */
         if (csr0 & LE_C0_MISS)
-                lp->stats.rx_errors++;       /* Missed a Rx frame. */
+                dev->stats.rx_errors++;       /* Missed a Rx frame. */
         if (csr0 & LE_C0_MERR) {
                 printk("%s: Bus master arbitration failure, status %4.4x.\n",
                        dev->name, csr0);
@@ -589,13 +589,6 @@
         return 0;
 }
 
-struct net_device_stats *lance_get_stats (struct net_device *dev)
-{
-        struct lance_private *lp = netdev_priv(dev);
-
-        return &lp->stats;
-}
-
 /* taken from the depca driver via a2065.c */
 static void lance_load_multicast (struct net_device *dev)
 {
diff --git a/drivers/net/7990.h b/drivers/net/7990.h
index b1212b5..0a5837b 100644
--- a/drivers/net/7990.h
+++ b/drivers/net/7990.h
@@ -111,7 +111,6 @@
         int lance_log_rx_bufs, lance_log_tx_bufs;
         int rx_ring_mod_mask, tx_ring_mod_mask;
 
-        struct net_device_stats stats;
         int tpe;                                  /* TPE is selected */
         int auto_select;                          /* cable-selection is by carrier */
         unsigned short busmaster_regval;
@@ -246,7 +245,6 @@
 extern int lance_open(struct net_device *dev);
 extern int lance_close (struct net_device *dev);
 extern int lance_start_xmit (struct sk_buff *skb, struct net_device *dev);
-extern struct net_device_stats *lance_get_stats (struct net_device *dev);
 extern void lance_set_multicast (struct net_device *dev);
 extern void lance_tx_timeout(struct net_device *dev);
 #ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index e970e64..a453eda 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -78,7 +78,7 @@
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #define CP_VLAN_TAG_USED 1
 #define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \
-	do { (tx_desc)->opts2 = (vlan_tag_value); } while (0)
+	do { (tx_desc)->opts2 = cpu_to_le32(vlan_tag_value); } while (0)
 #else
 #define CP_VLAN_TAG_USED 0
 #define CP_VLAN_TX_TAG(tx_desc,vlan_tag_value) \
@@ -303,25 +303,25 @@
 	  (RX_DMA_BURST << RxCfgDMAShift);
 
 struct cp_desc {
-	u32		opts1;
-	u32		opts2;
-	u64		addr;
+	__le32		opts1;
+	__le32		opts2;
+	__le64		addr;
 };
 
 struct cp_dma_stats {
-	u64			tx_ok;
-	u64			rx_ok;
-	u64			tx_err;
-	u32			rx_err;
-	u16			rx_fifo;
-	u16			frame_align;
-	u32			tx_ok_1col;
-	u32			tx_ok_mcol;
-	u64			rx_ok_phys;
-	u64			rx_ok_bcast;
-	u32			rx_ok_mcast;
-	u16			tx_abort;
-	u16			tx_underrun;
+	__le64			tx_ok;
+	__le64			rx_ok;
+	__le64			tx_err;
+	__le32			rx_err;
+	__le16			rx_fifo;
+	__le16			frame_align;
+	__le32			tx_ok_1col;
+	__le32			tx_ok_mcol;
+	__le64			rx_ok_phys;
+	__le64			rx_ok_bcast;
+	__le32			rx_ok_mcast;
+	__le16			tx_abort;
+	__le16			tx_underrun;
 } __attribute__((packed));
 
 struct cp_extra_stats {
@@ -334,6 +334,8 @@
 	spinlock_t		lock;
 	u32			msg_enable;
 
+	struct napi_struct	napi;
+
 	struct pci_dev		*pdev;
 	u32			rx_config;
 	u16			cpcmd;
@@ -460,9 +462,9 @@
 	cp->dev->last_rx = jiffies;
 
 #if CP_VLAN_TAG_USED
-	if (cp->vlgrp && (desc->opts2 & RxVlanTagged)) {
+	if (cp->vlgrp && (desc->opts2 & cpu_to_le32(RxVlanTagged))) {
 		vlan_hwaccel_receive_skb(skb, cp->vlgrp,
-					 be16_to_cpu(desc->opts2 & 0xffff));
+					 swab16(le32_to_cpu(desc->opts2) & 0xffff));
 	} else
 #endif
 		netif_receive_skb(skb);
@@ -501,12 +503,12 @@
 	return 0;
 }
 
-static int cp_rx_poll (struct net_device *dev, int *budget)
+static int cp_rx_poll(struct napi_struct *napi, int budget)
 {
-	struct cp_private *cp = netdev_priv(dev);
-	unsigned rx_tail = cp->rx_tail;
-	unsigned rx_work = dev->quota;
-	unsigned rx;
+	struct cp_private *cp = container_of(napi, struct cp_private, napi);
+	struct net_device *dev = cp->dev;
+	unsigned int rx_tail = cp->rx_tail;
+	int rx;
 
 rx_status_loop:
 	rx = 0;
@@ -560,7 +562,7 @@
 
 		skb_reserve(new_skb, RX_OFFSET);
 
-		pci_unmap_single(cp->pdev, mapping,
+		dma_unmap_single(&cp->pdev->dev, mapping,
 				 buflen, PCI_DMA_FROMDEVICE);
 
 		/* Handle checksum offloading for incoming packets. */
@@ -571,7 +573,7 @@
 
 		skb_put(skb, len);
 
-		mapping = pci_map_single(cp->pdev, new_skb->data, buflen,
+		mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen,
 					 PCI_DMA_FROMDEVICE);
 		cp->rx_skb[rx_tail] = new_skb;
 
@@ -588,33 +590,28 @@
 			desc->opts1 = cpu_to_le32(DescOwn | cp->rx_buf_sz);
 		rx_tail = NEXT_RX(rx_tail);
 
-		if (!rx_work--)
+		if (rx >= budget)
 			break;
 	}
 
 	cp->rx_tail = rx_tail;
 
-	dev->quota -= rx;
-	*budget -= rx;
-
 	/* if we did not reach work limit, then we're done with
 	 * this round of polling
 	 */
-	if (rx_work) {
+	if (rx < budget) {
 		unsigned long flags;
 
 		if (cpr16(IntrStatus) & cp_rx_intr_mask)
 			goto rx_status_loop;
 
-		local_irq_save(flags);
+		spin_lock_irqsave(&cp->lock, flags);
 		cpw16_f(IntrMask, cp_intr_mask);
-		__netif_rx_complete(dev);
-		local_irq_restore(flags);
-
-		return 0;	/* done */
+		__netif_rx_complete(dev, napi);
+		spin_unlock_irqrestore(&cp->lock, flags);
 	}
 
-	return 1;		/* not done */
+	return rx;
 }
 
 static irqreturn_t cp_interrupt (int irq, void *dev_instance)
@@ -647,9 +644,9 @@
 	}
 
 	if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
-		if (netif_rx_schedule_prep(dev)) {
+		if (netif_rx_schedule_prep(dev, &cp->napi)) {
 			cpw16_f(IntrMask, cp_norx_intr_mask);
-			__netif_rx_schedule(dev);
+			__netif_rx_schedule(dev, &cp->napi);
 		}
 
 	if (status & (TxOK | TxErr | TxEmpty | SWInt))
@@ -704,7 +701,7 @@
 		skb = cp->tx_skb[tx_tail];
 		BUG_ON(!skb);
 
-		pci_unmap_single(cp->pdev, le64_to_cpu(txd->addr),
+		dma_unmap_single(&cp->pdev->dev, le64_to_cpu(txd->addr),
 				 le32_to_cpu(txd->opts1) & 0xffff,
 				 PCI_DMA_TODEVICE);
 
@@ -768,7 +765,7 @@
 
 #if CP_VLAN_TAG_USED
 	if (cp->vlgrp && vlan_tx_tag_present(skb))
-		vlan_tag = TxVlanTag | cpu_to_be16(vlan_tx_tag_get(skb));
+		vlan_tag = TxVlanTag | swab16(vlan_tx_tag_get(skb));
 #endif
 
 	entry = cp->tx_head;
@@ -782,7 +779,7 @@
 		dma_addr_t mapping;
 
 		len = skb->len;
-		mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+		mapping = dma_map_single(&cp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE);
 		CP_VLAN_TX_TAG(txd, vlan_tag);
 		txd->addr = cpu_to_le64(mapping);
 		wmb();
@@ -818,7 +815,7 @@
 		 */
 		first_eor = eor;
 		first_len = skb_headlen(skb);
-		first_mapping = pci_map_single(cp->pdev, skb->data,
+		first_mapping = dma_map_single(&cp->pdev->dev, skb->data,
 					       first_len, PCI_DMA_TODEVICE);
 		cp->tx_skb[entry] = skb;
 		entry = NEXT_TX(entry);
@@ -830,7 +827,7 @@
 			dma_addr_t mapping;
 
 			len = this_frag->size;
-			mapping = pci_map_single(cp->pdev,
+			mapping = dma_map_single(&cp->pdev->dev,
 						 ((void *) page_address(this_frag->page) +
 						  this_frag->page_offset),
 						 len, PCI_DMA_TODEVICE);
@@ -1021,8 +1018,8 @@
 	cpw8_f (Cfg9346, Cfg9346_Unlock);
 
 	/* Restore our idea of the MAC address. */
-	cpw32_f (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
-	cpw32_f (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
+	cpw32_f (MAC0 + 0, le32_to_cpu (*(__le32 *) (dev->dev_addr + 0)));
+	cpw32_f (MAC0 + 4, le32_to_cpu (*(__le32 *) (dev->dev_addr + 4)));
 
 	cp_start_hw(cp);
 	cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */
@@ -1069,8 +1066,8 @@
 
 		skb_reserve(skb, RX_OFFSET);
 
-		mapping = pci_map_single(cp->pdev, skb->data, cp->rx_buf_sz,
-					 PCI_DMA_FROMDEVICE);
+		mapping = dma_map_single(&cp->pdev->dev, skb->data,
+					 cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
 		cp->rx_skb[i] = skb;
 
 		cp->rx_ring[i].opts2 = 0;
@@ -1110,7 +1107,8 @@
 {
 	void *mem;
 
-	mem = pci_alloc_consistent(cp->pdev, CP_RING_BYTES, &cp->ring_dma);
+	mem = dma_alloc_coherent(&cp->pdev->dev, CP_RING_BYTES,
+				 &cp->ring_dma, GFP_KERNEL);
 	if (!mem)
 		return -ENOMEM;
 
@@ -1128,7 +1126,7 @@
 	for (i = 0; i < CP_RX_RING_SIZE; i++) {
 		if (cp->rx_skb[i]) {
 			desc = cp->rx_ring + i;
-			pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr),
+			dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr),
 					 cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
 			dev_kfree_skb(cp->rx_skb[i]);
 		}
@@ -1139,7 +1137,7 @@
 			struct sk_buff *skb = cp->tx_skb[i];
 
 			desc = cp->tx_ring + i;
-			pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr),
+			dma_unmap_single(&cp->pdev->dev,le64_to_cpu(desc->addr),
 					 le32_to_cpu(desc->opts1) & 0xffff,
 					 PCI_DMA_TODEVICE);
 			if (le32_to_cpu(desc->opts1) & LastFrag)
@@ -1158,7 +1156,8 @@
 static void cp_free_rings (struct cp_private *cp)
 {
 	cp_clean_rings(cp);
-	pci_free_consistent(cp->pdev, CP_RING_BYTES, cp->rx_ring, cp->ring_dma);
+	dma_free_coherent(&cp->pdev->dev, CP_RING_BYTES, cp->rx_ring,
+			  cp->ring_dma);
 	cp->rx_ring = NULL;
 	cp->tx_ring = NULL;
 }
@@ -1175,6 +1174,8 @@
 	if (rc)
 		return rc;
 
+	napi_enable(&cp->napi);
+
 	cp_init_hw(cp);
 
 	rc = request_irq(dev->irq, cp_interrupt, IRQF_SHARED, dev->name, dev);
@@ -1188,6 +1189,7 @@
 	return 0;
 
 err_out_hw:
+	napi_disable(&cp->napi);
 	cp_stop_hw(cp);
 	cp_free_rings(cp);
 	return rc;
@@ -1198,6 +1200,8 @@
 	struct cp_private *cp = netdev_priv(dev);
 	unsigned long flags;
 
+	napi_disable(&cp->napi);
+
 	if (netif_msg_ifdown(cp))
 		printk(KERN_DEBUG "%s: disabling interface\n", dev->name);
 
@@ -1379,9 +1383,14 @@
 	return CP_REGS_SIZE;
 }
 
-static int cp_get_stats_count (struct net_device *dev)
+static int cp_get_sset_count (struct net_device *dev, int sset)
 {
-	return CP_NUM_STATS;
+	switch (sset) {
+	case ETH_SS_STATS:
+		return CP_NUM_STATS;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static int cp_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -1517,7 +1526,8 @@
 	dma_addr_t dma;
 	int i;
 
-	nic_stats = pci_alloc_consistent(cp->pdev, sizeof(*nic_stats), &dma);
+	nic_stats = dma_alloc_coherent(&cp->pdev->dev, sizeof(*nic_stats),
+				       &dma, GFP_KERNEL);
 	if (!nic_stats)
 		return;
 
@@ -1552,13 +1562,13 @@
 	tmp_stats[i++] = cp->cp_stats.rx_frags;
 	BUG_ON(i != CP_NUM_STATS);
 
-	pci_free_consistent(cp->pdev, sizeof(*nic_stats), nic_stats, dma);
+	dma_free_coherent(&cp->pdev->dev, sizeof(*nic_stats), nic_stats, dma);
 }
 
 static const struct ethtool_ops cp_ethtool_ops = {
 	.get_drvinfo		= cp_get_drvinfo,
 	.get_regs_len		= cp_get_regs_len,
-	.get_stats_count	= cp_get_stats_count,
+	.get_sset_count		= cp_get_sset_count,
 	.get_settings		= cp_get_settings,
 	.set_settings		= cp_set_settings,
 	.nway_reset		= cp_nway_reset,
@@ -1567,18 +1577,14 @@
 	.set_msglevel		= cp_set_msglevel,
 	.get_rx_csum		= cp_get_rx_csum,
 	.set_rx_csum		= cp_set_rx_csum,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
 	.set_tx_csum		= ethtool_op_set_tx_csum, /* local! */
-	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
-	.get_tso		= ethtool_op_get_tso,
 	.set_tso		= ethtool_op_set_tso,
 	.get_regs		= cp_get_regs,
 	.get_wol		= cp_get_wol,
 	.set_wol		= cp_set_wol,
 	.get_strings		= cp_get_strings,
 	.get_ethtool_stats	= cp_get_ethtool_stats,
-	.get_perm_addr		= ethtool_op_get_perm_addr,
 	.get_eeprom_len		= cp_get_eeprom_len,
 	.get_eeprom		= cp_get_eeprom,
 	.set_eeprom		= cp_set_eeprom,
@@ -1822,6 +1828,7 @@
 	void __iomem *regs;
 	resource_size_t pciaddr;
 	unsigned int addr_len, i, pci_using_dac;
+	DECLARE_MAC_BUF(mac);
 
 #ifndef MODULE
 	static int version_printed;
@@ -1841,7 +1848,6 @@
 	dev = alloc_etherdev(sizeof(struct cp_private));
 	if (!dev)
 		return -ENOMEM;
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	cp = netdev_priv(dev);
@@ -1924,8 +1930,8 @@
 	/* read MAC address from EEPROM */
 	addr_len = read_eeprom (regs, 0, 8) == 0x8129 ? 8 : 6;
 	for (i = 0; i < 3; i++)
-		((u16 *) (dev->dev_addr))[i] =
-		    le16_to_cpu (read_eeprom (regs, i + 7, addr_len));
+		((__le16 *) (dev->dev_addr))[i] =
+		    cpu_to_le16(read_eeprom (regs, i + 7, addr_len));
 	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
 	dev->open = cp_open;
@@ -1934,11 +1940,10 @@
 	dev->hard_start_xmit = cp_start_xmit;
 	dev->get_stats = cp_get_stats;
 	dev->do_ioctl = cp_ioctl;
-	dev->poll = cp_rx_poll;
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = cp_poll_controller;
 #endif
-	dev->weight = 16;	/* arbitrary? from NAPI_HOWTO.txt. */
+	netif_napi_add(dev, &cp->napi, cp_rx_poll, 16);
 #ifdef BROKEN
 	dev->change_mtu = cp_change_mtu;
 #endif
@@ -1965,13 +1970,10 @@
 		goto err_out_iomap;
 
 	printk (KERN_INFO "%s: RTL-8139C+ at 0x%lx, "
-		"%02x:%02x:%02x:%02x:%02x:%02x, "
-		"IRQ %d\n",
+		"%s, IRQ %d\n",
 		dev->name,
 		dev->base_addr,
-		dev->dev_addr[0], dev->dev_addr[1],
-		dev->dev_addr[2], dev->dev_addr[3],
-		dev->dev_addr[4], dev->dev_addr[5],
+		print_mac(mac, dev->dev_addr),
 		dev->irq);
 
 	pci_set_drvdata(pdev, dev);
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 327eaa7..973b684 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -291,198 +291,197 @@
 
 /* Symbolic offsets to registers. */
 enum RTL8139_registers {
-	MAC0 = 0,		/* Ethernet hardware address. */
-	MAR0 = 8,		/* Multicast filter. */
-	TxStatus0 = 0x10,	/* Transmit status (Four 32bit registers). */
-	TxAddr0 = 0x20,		/* Tx descriptors (also four 32bit). */
-	RxBuf = 0x30,
-	ChipCmd = 0x37,
-	RxBufPtr = 0x38,
-	RxBufAddr = 0x3A,
-	IntrMask = 0x3C,
-	IntrStatus = 0x3E,
-	TxConfig = 0x40,
-	RxConfig = 0x44,
-	Timer = 0x48,		/* A general-purpose counter. */
-	RxMissed = 0x4C,	/* 24 bits valid, write clears. */
-	Cfg9346 = 0x50,
-	Config0 = 0x51,
-	Config1 = 0x52,
-	FlashReg = 0x54,
-	MediaStatus = 0x58,
-	Config3 = 0x59,
-	Config4 = 0x5A,		/* absent on RTL-8139A */
-	HltClk = 0x5B,
-	MultiIntr = 0x5C,
-	TxSummary = 0x60,
-	BasicModeCtrl = 0x62,
-	BasicModeStatus = 0x64,
-	NWayAdvert = 0x66,
-	NWayLPAR = 0x68,
-	NWayExpansion = 0x6A,
+	MAC0		= 0,	 /* Ethernet hardware address. */
+	MAR0		= 8,	 /* Multicast filter. */
+	TxStatus0	= 0x10,	 /* Transmit status (Four 32bit registers). */
+	TxAddr0		= 0x20,	 /* Tx descriptors (also four 32bit). */
+	RxBuf		= 0x30,
+	ChipCmd		= 0x37,
+	RxBufPtr	= 0x38,
+	RxBufAddr	= 0x3A,
+	IntrMask	= 0x3C,
+	IntrStatus	= 0x3E,
+	TxConfig	= 0x40,
+	RxConfig	= 0x44,
+	Timer		= 0x48,	 /* A general-purpose counter. */
+	RxMissed	= 0x4C,  /* 24 bits valid, write clears. */
+	Cfg9346		= 0x50,
+	Config0		= 0x51,
+	Config1		= 0x52,
+	FlashReg	= 0x54,
+	MediaStatus	= 0x58,
+	Config3		= 0x59,
+	Config4		= 0x5A,	 /* absent on RTL-8139A */
+	HltClk		= 0x5B,
+	MultiIntr	= 0x5C,
+	TxSummary	= 0x60,
+	BasicModeCtrl	= 0x62,
+	BasicModeStatus	= 0x64,
+	NWayAdvert	= 0x66,
+	NWayLPAR	= 0x68,
+	NWayExpansion	= 0x6A,
 	/* Undocumented registers, but required for proper operation. */
-	FIFOTMS = 0x70,		/* FIFO Control and test. */
-	CSCR = 0x74,		/* Chip Status and Configuration Register. */
-	PARA78 = 0x78,
-	PARA7c = 0x7c,		/* Magic transceiver parameter register. */
-	Config5 = 0xD8,		/* absent on RTL-8139A */
+	FIFOTMS		= 0x70,	 /* FIFO Control and test. */
+	CSCR		= 0x74,	 /* Chip Status and Configuration Register. */
+	PARA78		= 0x78,
+	PARA7c		= 0x7c,	 /* Magic transceiver parameter register. */
+	Config5		= 0xD8,	 /* absent on RTL-8139A */
 };
 
 enum ClearBitMasks {
-	MultiIntrClear = 0xF000,
-	ChipCmdClear = 0xE2,
-	Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
+	MultiIntrClear	= 0xF000,
+	ChipCmdClear	= 0xE2,
+	Config1Clear	= (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
 };
 
 enum ChipCmdBits {
-	CmdReset = 0x10,
-	CmdRxEnb = 0x08,
-	CmdTxEnb = 0x04,
-	RxBufEmpty = 0x01,
+	CmdReset	= 0x10,
+	CmdRxEnb	= 0x08,
+	CmdTxEnb	= 0x04,
+	RxBufEmpty	= 0x01,
 };
 
 /* Interrupt register bits, using my own meaningful names. */
 enum IntrStatusBits {
-	PCIErr = 0x8000,
-	PCSTimeout = 0x4000,
-	RxFIFOOver = 0x40,
-	RxUnderrun = 0x20,
-	RxOverflow = 0x10,
-	TxErr = 0x08,
-	TxOK = 0x04,
-	RxErr = 0x02,
-	RxOK = 0x01,
+	PCIErr		= 0x8000,
+	PCSTimeout	= 0x4000,
+	RxFIFOOver	= 0x40,
+	RxUnderrun	= 0x20,
+	RxOverflow	= 0x10,
+	TxErr		= 0x08,
+	TxOK		= 0x04,
+	RxErr		= 0x02,
+	RxOK		= 0x01,
 
-	RxAckBits = RxFIFOOver | RxOverflow | RxOK,
+	RxAckBits	= RxFIFOOver | RxOverflow | RxOK,
 };
 
 enum TxStatusBits {
-	TxHostOwns = 0x2000,
-	TxUnderrun = 0x4000,
-	TxStatOK = 0x8000,
-	TxOutOfWindow = 0x20000000,
-	TxAborted = 0x40000000,
-	TxCarrierLost = 0x80000000,
+	TxHostOwns	= 0x2000,
+	TxUnderrun	= 0x4000,
+	TxStatOK	= 0x8000,
+	TxOutOfWindow	= 0x20000000,
+	TxAborted	= 0x40000000,
+	TxCarrierLost	= 0x80000000,
 };
 enum RxStatusBits {
-	RxMulticast = 0x8000,
-	RxPhysical = 0x4000,
-	RxBroadcast = 0x2000,
-	RxBadSymbol = 0x0020,
-	RxRunt = 0x0010,
-	RxTooLong = 0x0008,
-	RxCRCErr = 0x0004,
-	RxBadAlign = 0x0002,
-	RxStatusOK = 0x0001,
+	RxMulticast	= 0x8000,
+	RxPhysical	= 0x4000,
+	RxBroadcast	= 0x2000,
+	RxBadSymbol	= 0x0020,
+	RxRunt		= 0x0010,
+	RxTooLong	= 0x0008,
+	RxCRCErr	= 0x0004,
+	RxBadAlign	= 0x0002,
+	RxStatusOK	= 0x0001,
 };
 
 /* Bits in RxConfig. */
 enum rx_mode_bits {
-	AcceptErr = 0x20,
-	AcceptRunt = 0x10,
-	AcceptBroadcast = 0x08,
-	AcceptMulticast = 0x04,
-	AcceptMyPhys = 0x02,
-	AcceptAllPhys = 0x01,
+	AcceptErr	= 0x20,
+	AcceptRunt	= 0x10,
+	AcceptBroadcast	= 0x08,
+	AcceptMulticast	= 0x04,
+	AcceptMyPhys	= 0x02,
+	AcceptAllPhys	= 0x01,
 };
 
 /* Bits in TxConfig. */
 enum tx_config_bits {
-
         /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
-        TxIFGShift = 24,
-        TxIFG84 = (0 << TxIFGShift),    /* 8.4us / 840ns (10 / 100Mbps) */
-        TxIFG88 = (1 << TxIFGShift),    /* 8.8us / 880ns (10 / 100Mbps) */
-        TxIFG92 = (2 << TxIFGShift),    /* 9.2us / 920ns (10 / 100Mbps) */
-        TxIFG96 = (3 << TxIFGShift),    /* 9.6us / 960ns (10 / 100Mbps) */
+        TxIFGShift	= 24,
+        TxIFG84		= (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */
+        TxIFG88		= (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */
+        TxIFG92		= (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */
+        TxIFG96		= (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */
 
-	TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
-	TxCRC = (1 << 16),	/* DISABLE appending CRC to end of Tx packets */
-	TxClearAbt = (1 << 0),	/* Clear abort (WO) */
-	TxDMAShift = 8,		/* DMA burst value (0-7) is shifted this many bits */
-	TxRetryShift = 4,	/* TXRR value (0-15) is shifted this many bits */
+	TxLoopBack	= (1 << 18) | (1 << 17), /* enable loopback test mode */
+	TxCRC		= (1 << 16),	/* DISABLE Tx pkt CRC append */
+	TxClearAbt	= (1 << 0),	/* Clear abort (WO) */
+	TxDMAShift	= 8, /* DMA burst value (0-7) is shifted X many bits */
+	TxRetryShift	= 4, /* TXRR value (0-15) is shifted X many bits */
 
-	TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
+	TxVersionMask	= 0x7C800000, /* mask out version bits 30-26, 23 */
 };
 
 /* Bits in Config1 */
 enum Config1Bits {
-	Cfg1_PM_Enable = 0x01,
-	Cfg1_VPD_Enable = 0x02,
-	Cfg1_PIO = 0x04,
-	Cfg1_MMIO = 0x08,
-	LWAKE = 0x10,		/* not on 8139, 8139A */
+	Cfg1_PM_Enable	= 0x01,
+	Cfg1_VPD_Enable	= 0x02,
+	Cfg1_PIO	= 0x04,
+	Cfg1_MMIO	= 0x08,
+	LWAKE		= 0x10,		/* not on 8139, 8139A */
 	Cfg1_Driver_Load = 0x20,
-	Cfg1_LED0 = 0x40,
-	Cfg1_LED1 = 0x80,
-	SLEEP = (1 << 1),	/* only on 8139, 8139A */
-	PWRDN = (1 << 0),	/* only on 8139, 8139A */
+	Cfg1_LED0	= 0x40,
+	Cfg1_LED1	= 0x80,
+	SLEEP		= (1 << 1),	/* only on 8139, 8139A */
+	PWRDN		= (1 << 0),	/* only on 8139, 8139A */
 };
 
 /* Bits in Config3 */
 enum Config3Bits {
-	Cfg3_FBtBEn    = (1 << 0), /* 1 = Fast Back to Back */
-	Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
-	Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
-	Cfg3_CardB_En  = (1 << 3), /* 1 = enable CardBus registers */
-	Cfg3_LinkUp    = (1 << 4), /* 1 = wake up on link up */
-	Cfg3_Magic     = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
-	Cfg3_PARM_En   = (1 << 6), /* 0 = software can set twister parameters */
-	Cfg3_GNTSel    = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
+	Cfg3_FBtBEn   	= (1 << 0), /* 1	= Fast Back to Back */
+	Cfg3_FuncRegEn	= (1 << 1), /* 1	= enable CardBus Function registers */
+	Cfg3_CLKRUN_En	= (1 << 2), /* 1	= enable CLKRUN */
+	Cfg3_CardB_En 	= (1 << 3), /* 1	= enable CardBus registers */
+	Cfg3_LinkUp   	= (1 << 4), /* 1	= wake up on link up */
+	Cfg3_Magic    	= (1 << 5), /* 1	= wake up on Magic Packet (tm) */
+	Cfg3_PARM_En  	= (1 << 6), /* 0	= software can set twister parameters */
+	Cfg3_GNTSel   	= (1 << 7), /* 1	= delay 1 clock from PCI GNT signal */
 };
 
 /* Bits in Config4 */
 enum Config4Bits {
-	LWPTN = (1 << 2),	/* not on 8139, 8139A */
+	LWPTN	= (1 << 2),	/* not on 8139, 8139A */
 };
 
 /* Bits in Config5 */
 enum Config5Bits {
-	Cfg5_PME_STS     = (1 << 0), /* 1 = PCI reset resets PME_Status */
-	Cfg5_LANWake     = (1 << 1), /* 1 = enable LANWake signal */
-	Cfg5_LDPS        = (1 << 2), /* 0 = save power when link is down */
-	Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */
-	Cfg5_UWF         = (1 << 4), /* 1 = accept unicast wakeup frame */
-	Cfg5_MWF         = (1 << 5), /* 1 = accept multicast wakeup frame */
-	Cfg5_BWF         = (1 << 6), /* 1 = accept broadcast wakeup frame */
+	Cfg5_PME_STS   	= (1 << 0), /* 1	= PCI reset resets PME_Status */
+	Cfg5_LANWake   	= (1 << 1), /* 1	= enable LANWake signal */
+	Cfg5_LDPS      	= (1 << 2), /* 0	= save power when link is down */
+	Cfg5_FIFOAddrPtr= (1 << 3), /* Realtek internal SRAM testing */
+	Cfg5_UWF        = (1 << 4), /* 1 = accept unicast wakeup frame */
+	Cfg5_MWF        = (1 << 5), /* 1 = accept multicast wakeup frame */
+	Cfg5_BWF        = (1 << 6), /* 1 = accept broadcast wakeup frame */
 };
 
 enum RxConfigBits {
 	/* rx fifo threshold */
-	RxCfgFIFOShift = 13,
-	RxCfgFIFONone = (7 << RxCfgFIFOShift),
+	RxCfgFIFOShift	= 13,
+	RxCfgFIFONone	= (7 << RxCfgFIFOShift),
 
 	/* Max DMA burst */
-	RxCfgDMAShift = 8,
+	RxCfgDMAShift	= 8,
 	RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
 
 	/* rx ring buffer length */
-	RxCfgRcv8K = 0,
-	RxCfgRcv16K = (1 << 11),
-	RxCfgRcv32K = (1 << 12),
-	RxCfgRcv64K = (1 << 11) | (1 << 12),
+	RxCfgRcv8K	= 0,
+	RxCfgRcv16K	= (1 << 11),
+	RxCfgRcv32K	= (1 << 12),
+	RxCfgRcv64K	= (1 << 11) | (1 << 12),
 
 	/* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
-	RxNoWrap = (1 << 7),
+	RxNoWrap	= (1 << 7),
 };
 
 /* Twister tuning parameters from RealTek.
    Completely undocumented, but required to tune bad links on some boards. */
 enum CSCRBits {
-	CSCR_LinkOKBit = 0x0400,
-	CSCR_LinkChangeBit = 0x0800,
-	CSCR_LinkStatusBits = 0x0f000,
-	CSCR_LinkDownOffCmd = 0x003c0,
-	CSCR_LinkDownCmd = 0x0f3c0,
+	CSCR_LinkOKBit		= 0x0400,
+	CSCR_LinkChangeBit	= 0x0800,
+	CSCR_LinkStatusBits	= 0x0f000,
+	CSCR_LinkDownOffCmd	= 0x003c0,
+	CSCR_LinkDownCmd	= 0x0f3c0,
 };
 
 enum Cfg9346Bits {
-	Cfg9346_Lock = 0x00,
-	Cfg9346_Unlock = 0xC0,
+	Cfg9346_Lock	= 0x00,
+	Cfg9346_Unlock	= 0xC0,
 };
 
 typedef enum {
-	CH_8139 = 0,
+	CH_8139	= 0,
 	CH_8139_K,
 	CH_8139A,
 	CH_8139A_G,
@@ -495,8 +494,8 @@
 } chip_t;
 
 enum chip_flags {
-	HasHltClk = (1 << 0),
-	HasLWake = (1 << 1),
+	HasHltClk	= (1 << 0),
+	HasLWake	= (1 << 1),
 };
 
 #define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
@@ -569,36 +568,46 @@
 };
 
 struct rtl8139_private {
-	void __iomem *mmio_addr;
-	int drv_flags;
-	struct pci_dev *pci_dev;
-	u32 msg_enable;
-	struct net_device_stats stats;
-	unsigned char *rx_ring;
-	unsigned int cur_rx;	/* Index into the Rx buffer of next Rx pkt. */
-	unsigned int tx_flag;
-	unsigned long cur_tx;
-	unsigned long dirty_tx;
-	unsigned char *tx_buf[NUM_TX_DESC];	/* Tx bounce buffers */
-	unsigned char *tx_bufs;	/* Tx bounce buffer region. */
-	dma_addr_t rx_ring_dma;
-	dma_addr_t tx_bufs_dma;
-	signed char phys[4];		/* MII device addresses. */
-	char twistie, twist_row, twist_col;	/* Twister tune state. */
-	unsigned int watchdog_fired : 1;
-	unsigned int default_port : 4;	/* Last dev->if_port value. */
-	unsigned int have_thread : 1;
-	spinlock_t lock;
-	spinlock_t rx_lock;
-	chip_t chipset;
-	u32 rx_config;
-	struct rtl_extra_stats xstats;
+	void __iomem		*mmio_addr;
+	int			drv_flags;
+	struct pci_dev		*pci_dev;
+	u32			msg_enable;
+	struct napi_struct	napi;
+	struct net_device	*dev;
+	struct net_device_stats	stats;
 
-	struct delayed_work thread;
+	unsigned char		*rx_ring;
+	unsigned int		cur_rx;	/* RX buf index of next pkt */
+	dma_addr_t		rx_ring_dma;
 
-	struct mii_if_info mii;
-	unsigned int regs_len;
-	unsigned long fifo_copy_timeout;
+	unsigned int		tx_flag;
+	unsigned long		cur_tx;
+	unsigned long		dirty_tx;
+	unsigned char		*tx_buf[NUM_TX_DESC];	/* Tx bounce buffers */
+	unsigned char		*tx_bufs;	/* Tx bounce buffer region. */
+	dma_addr_t		tx_bufs_dma;
+
+	signed char		phys[4];	/* MII device addresses. */
+
+				/* Twister tune state. */
+	char			twistie, twist_row, twist_col;
+
+	unsigned int		watchdog_fired : 1;
+	unsigned int		default_port : 4; /* Last dev->if_port value. */
+	unsigned int		have_thread : 1;
+
+	spinlock_t		lock;
+	spinlock_t		rx_lock;
+
+	chip_t			chipset;
+	u32			rx_config;
+	struct rtl_extra_stats	xstats;
+
+	struct delayed_work	thread;
+
+	struct mii_if_info	mii;
+	unsigned int		regs_len;
+	unsigned long		fifo_copy_timeout;
 };
 
 MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>");
@@ -625,10 +634,10 @@
 static void rtl8139_init_ring (struct net_device *dev);
 static int rtl8139_start_xmit (struct sk_buff *skb,
 			       struct net_device *dev);
-static int rtl8139_poll(struct net_device *dev, int *budget);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void rtl8139_poll_controller(struct net_device *dev);
 #endif
+static int rtl8139_poll(struct napi_struct *napi, int budget);
 static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance);
 static int rtl8139_close (struct net_device *dev);
 static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
@@ -646,24 +655,11 @@
 #define RTL_W16_F(reg, val16)	do { iowrite16 ((val16), ioaddr + (reg)); ioread16 (ioaddr + (reg)); } while (0)
 #define RTL_W32_F(reg, val32)	do { iowrite32 ((val32), ioaddr + (reg)); ioread32 (ioaddr + (reg)); } while (0)
 
-
-#define MMIO_FLUSH_AUDIT_COMPLETE 1
-#if MMIO_FLUSH_AUDIT_COMPLETE
-
 /* write MMIO register */
 #define RTL_W8(reg, val8)	iowrite8 ((val8), ioaddr + (reg))
 #define RTL_W16(reg, val16)	iowrite16 ((val16), ioaddr + (reg))
 #define RTL_W32(reg, val32)	iowrite32 ((val32), ioaddr + (reg))
 
-#else
-
-/* write MMIO register, then flush */
-#define RTL_W8		RTL_W8_F
-#define RTL_W16		RTL_W16_F
-#define RTL_W32		RTL_W32_F
-
-#endif /* MMIO_FLUSH_AUDIT_COMPLETE */
-
 /* read MMIO register */
 #define RTL_R8(reg)		ioread8 (ioaddr + (reg))
 #define RTL_R16(reg)		ioread16 (ioaddr + (reg))
@@ -770,7 +766,6 @@
 		dev_err(&pdev->dev, "Unable to alloc new net device\n");
 		return -ENOMEM;
 	}
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	tp = netdev_priv(dev);
@@ -931,6 +926,7 @@
 	int i, addr_len, option;
 	void __iomem *ioaddr;
 	static int board_idx = -1;
+	DECLARE_MAC_BUF(mac);
 
 	assert (pdev != NULL);
 	assert (ent != NULL);
@@ -963,6 +959,7 @@
 
 	assert (dev != NULL);
 	tp = netdev_priv(dev);
+	tp->dev = dev;
 
 	ioaddr = tp->mmio_addr;
 	assert (ioaddr != NULL);
@@ -976,8 +973,7 @@
 	/* The Rtl8139-specific entries in the device structure. */
 	dev->open = rtl8139_open;
 	dev->hard_start_xmit = rtl8139_start_xmit;
-	dev->poll = rtl8139_poll;
-	dev->weight = 64;
+	netif_napi_add(dev, &tp->napi, rtl8139_poll, 64);
 	dev->stop = rtl8139_close;
 	dev->get_stats = rtl8139_get_stats;
 	dev->set_multicast_list = rtl8139_set_rx_mode;
@@ -1022,14 +1018,11 @@
 	pci_set_drvdata (pdev, dev);
 
 	printk (KERN_INFO "%s: %s at 0x%lx, "
-		"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
-		"IRQ %d\n",
+		"%s, IRQ %d\n",
 		dev->name,
 		board_info[ent->driver_data].name,
 		dev->base_addr,
-		dev->dev_addr[0], dev->dev_addr[1],
-		dev->dev_addr[2], dev->dev_addr[3],
-		dev->dev_addr[4], dev->dev_addr[5],
+		print_mac(mac, dev->dev_addr),
 		dev->irq);
 
 	printk (KERN_DEBUG "%s:  Identified 8139 chip type '%s'\n",
@@ -1314,24 +1307,26 @@
 	if (retval)
 		return retval;
 
-	tp->tx_bufs = pci_alloc_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
-					   &tp->tx_bufs_dma);
-	tp->rx_ring = pci_alloc_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
-					   &tp->rx_ring_dma);
+	tp->tx_bufs = dma_alloc_coherent(&tp->pci_dev->dev, TX_BUF_TOT_LEN,
+					   &tp->tx_bufs_dma, GFP_KERNEL);
+	tp->rx_ring = dma_alloc_coherent(&tp->pci_dev->dev, RX_BUF_TOT_LEN,
+					   &tp->rx_ring_dma, GFP_KERNEL);
 	if (tp->tx_bufs == NULL || tp->rx_ring == NULL) {
 		free_irq(dev->irq, dev);
 
 		if (tp->tx_bufs)
-			pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
+			dma_free_coherent(&tp->pci_dev->dev, TX_BUF_TOT_LEN,
 					    tp->tx_bufs, tp->tx_bufs_dma);
 		if (tp->rx_ring)
-			pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
+			dma_free_coherent(&tp->pci_dev->dev, RX_BUF_TOT_LEN,
 					    tp->rx_ring, tp->rx_ring_dma);
 
 		return -ENOMEM;
 
 	}
 
+	napi_enable(&tp->napi);
+
 	tp->mii.full_duplex = tp->mii.force_media;
 	tp->tx_flag = (TX_FIFO_THRESH << 11) & 0x003f0000;
 
@@ -2103,39 +2098,32 @@
 	}
 }
 
-static int rtl8139_poll(struct net_device *dev, int *budget)
+static int rtl8139_poll(struct napi_struct *napi, int budget)
 {
-	struct rtl8139_private *tp = netdev_priv(dev);
+	struct rtl8139_private *tp = container_of(napi, struct rtl8139_private, napi);
+	struct net_device *dev = tp->dev;
 	void __iomem *ioaddr = tp->mmio_addr;
-	int orig_budget = min(*budget, dev->quota);
-	int done = 1;
+	int work_done;
 
 	spin_lock(&tp->rx_lock);
-	if (likely(RTL_R16(IntrStatus) & RxAckBits)) {
-		int work_done;
+	work_done = 0;
+	if (likely(RTL_R16(IntrStatus) & RxAckBits))
+		work_done += rtl8139_rx(dev, tp, budget);
 
-		work_done = rtl8139_rx(dev, tp, orig_budget);
-		if (likely(work_done > 0)) {
-			*budget -= work_done;
-			dev->quota -= work_done;
-			done = (work_done < orig_budget);
-		}
-	}
-
-	if (done) {
+	if (work_done < budget) {
 		unsigned long flags;
 		/*
 		 * Order is important since data can get interrupted
 		 * again when we think we are done.
 		 */
-		local_irq_save(flags);
+		spin_lock_irqsave(&tp->lock, flags);
 		RTL_W16_F(IntrMask, rtl8139_intr_mask);
-		__netif_rx_complete(dev);
-		local_irq_restore(flags);
+		__netif_rx_complete(dev, napi);
+		spin_unlock_irqrestore(&tp->lock, flags);
 	}
 	spin_unlock(&tp->rx_lock);
 
-	return !done;
+	return work_done;
 }
 
 /* The interrupt handler does all of the Rx thread work and cleans up
@@ -2180,9 +2168,9 @@
 	/* Receive packets are processed by poll routine.
 	   If not running start it now. */
 	if (status & RxAckBits){
-		if (netif_rx_schedule_prep(dev)) {
+		if (netif_rx_schedule_prep(dev, &tp->napi)) {
 			RTL_W16_F (IntrMask, rtl8139_norx_intr_mask);
-			__netif_rx_schedule (dev);
+			__netif_rx_schedule(dev, &tp->napi);
 		}
 	}
 
@@ -2223,7 +2211,8 @@
 	void __iomem *ioaddr = tp->mmio_addr;
 	unsigned long flags;
 
-	netif_stop_queue (dev);
+	netif_stop_queue(dev);
+	napi_disable(&tp->napi);
 
 	if (netif_msg_ifdown(tp))
 		printk(KERN_DEBUG "%s: Shutting down ethercard, status was 0x%4.4x.\n",
@@ -2248,10 +2237,10 @@
 
 	rtl8139_tx_clear (tp);
 
-	pci_free_consistent(tp->pci_dev, RX_BUF_TOT_LEN,
-			    tp->rx_ring, tp->rx_ring_dma);
-	pci_free_consistent(tp->pci_dev, TX_BUF_TOT_LEN,
-			    tp->tx_bufs, tp->tx_bufs_dma);
+	dma_free_coherent(&tp->pci_dev->dev, RX_BUF_TOT_LEN,
+			  tp->rx_ring, tp->rx_ring_dma);
+	dma_free_coherent(&tp->pci_dev->dev, TX_BUF_TOT_LEN,
+			  tp->tx_bufs, tp->tx_bufs_dma);
 	tp->rx_ring = NULL;
 	tp->tx_bufs = NULL;
 
@@ -2417,9 +2406,14 @@
 }
 #endif /* CONFIG_8139TOO_MMIO */
 
-static int rtl8139_get_stats_count(struct net_device *dev)
+static int rtl8139_get_sset_count(struct net_device *dev, int sset)
 {
-	return RTL_NUM_STATS;
+	switch (sset) {
+	case ETH_SS_STATS:
+		return RTL_NUM_STATS;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void rtl8139_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
@@ -2450,9 +2444,8 @@
 	.get_wol		= rtl8139_get_wol,
 	.set_wol		= rtl8139_set_wol,
 	.get_strings		= rtl8139_get_strings,
-	.get_stats_count	= rtl8139_get_stats_count,
+	.get_sset_count		= rtl8139_get_sset_count,
 	.get_ethtool_stats	= rtl8139_get_ethtool_stats,
-	.get_perm_addr		= ethtool_op_get_perm_addr,
 };
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index 3ff1155..bb30d5b 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -57,6 +57,7 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/pgtable.h>
+#include <asm/cacheflush.h>
 
 static char version[] __initdata =
 	"82596.c $Revision: 1.5 $\n";
@@ -325,7 +326,6 @@
 	struct i596_cmd *cmd_head;
 	int cmd_backlog;
 	unsigned long last_cmd;
-	struct net_device_stats stats;
 	struct i596_rfd rfds[RX_RING_SIZE];
 	struct i596_rbd rbds[RX_RING_SIZE];
 	struct tx_cmd tx_cmds[TX_RING_SIZE];
@@ -359,7 +359,6 @@
 static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t i596_interrupt(int irq, void *dev_id);
 static int i596_close(struct net_device *dev);
-static struct net_device_stats *i596_get_stats(struct net_device *dev);
 static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
 static void i596_tx_timeout (struct net_device *dev);
 static void print_eth(unsigned char *buf, char *str);
@@ -827,7 +826,7 @@
 			if (skb == NULL) {
 				/* XXX tulip.c can defer packets here!! */
 				printk(KERN_WARNING "%s: i596_rx Memory squeeze, dropping packet.\n", dev->name);
-				lp->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 			}
 			else {
 				if (!rx_in_place) {
@@ -843,28 +842,28 @@
 #endif
 				netif_rx(skb);
 				dev->last_rx = jiffies;
-				lp->stats.rx_packets++;
-				lp->stats.rx_bytes+=pkt_len;
+				dev->stats.rx_packets++;
+				dev->stats.rx_bytes+=pkt_len;
 			}
 		}
 		else {
 			DEB(DEB_ERRORS, printk(KERN_DEBUG "%s: Error, rfd.stat = 0x%04x\n",
 					dev->name, rfd->stat));
-			lp->stats.rx_errors++;
+			dev->stats.rx_errors++;
 			if ((rfd->stat) & 0x0001)
-				lp->stats.collisions++;
+				dev->stats.collisions++;
 			if ((rfd->stat) & 0x0080)
-				lp->stats.rx_length_errors++;
+				dev->stats.rx_length_errors++;
 			if ((rfd->stat) & 0x0100)
-				lp->stats.rx_over_errors++;
+				dev->stats.rx_over_errors++;
 			if ((rfd->stat) & 0x0200)
-				lp->stats.rx_fifo_errors++;
+				dev->stats.rx_fifo_errors++;
 			if ((rfd->stat) & 0x0400)
-				lp->stats.rx_frame_errors++;
+				dev->stats.rx_frame_errors++;
 			if ((rfd->stat) & 0x0800)
-				lp->stats.rx_crc_errors++;
+				dev->stats.rx_crc_errors++;
 			if ((rfd->stat) & 0x1000)
-				lp->stats.rx_length_errors++;
+				dev->stats.rx_length_errors++;
 		}
 
 		/* Clear the buffer descriptor count and EOF + F flags */
@@ -915,8 +914,8 @@
 
 				dev_kfree_skb(skb);
 
-				lp->stats.tx_errors++;
-				lp->stats.tx_aborted_errors++;
+				dev->stats.tx_errors++;
+				dev->stats.tx_aborted_errors++;
 
 				ptr->v_next = ptr->b_next = I596_NULL;
 				tx_cmd->cmd.command = 0;  /* Mark as free */
@@ -1037,10 +1036,10 @@
 	DEB(DEB_ERRORS,printk(KERN_ERR "%s: transmit timed out, status resetting.\n",
 			dev->name));
 
-	lp->stats.tx_errors++;
+	dev->stats.tx_errors++;
 
 	/* Try to restart the adaptor */
-	if (lp->last_restart == lp->stats.tx_packets) {
+	if (lp->last_restart == dev->stats.tx_packets) {
 		DEB(DEB_ERRORS,printk(KERN_ERR "Resetting board.\n"));
 		/* Shutdown and restart */
 		i596_reset (dev, lp, ioaddr);
@@ -1049,7 +1048,7 @@
 		DEB(DEB_ERRORS,printk(KERN_ERR "Kicking board.\n"));
 		lp->scb.command = CUC_START | RX_START;
 		CA (dev);
-		lp->last_restart = lp->stats.tx_packets;
+		lp->last_restart = dev->stats.tx_packets;
 	}
 
 	dev->trans_start = jiffies;
@@ -1081,7 +1080,7 @@
 	if (tx_cmd->cmd.command) {
 		printk(KERN_NOTICE "%s: xmit ring full, dropping packet.\n",
 				dev->name);
-		lp->stats.tx_dropped++;
+		dev->stats.tx_dropped++;
 
 		dev_kfree_skb(skb);
 	} else {
@@ -1106,8 +1105,8 @@
 		DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued"));
 		i596_add_cmd(dev, &tx_cmd->cmd);
 
-		lp->stats.tx_packets++;
-		lp->stats.tx_bytes += length;
+		dev->stats.tx_packets++;
+		dev->stats.tx_bytes += length;
 	}
 
 	netif_start_queue(dev);
@@ -1117,15 +1116,12 @@
 
 static void print_eth(unsigned char *add, char *str)
 {
-	int i;
+	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mac2);
 
-	printk(KERN_DEBUG "i596 0x%p, ", add);
-	for (i = 0; i < 6; i++)
-		printk(" %02X", add[i + 6]);
-	printk(" -->");
-	for (i = 0; i < 6; i++)
-		printk(" %02X", add[i]);
-	printk(" %02X%02X, %s\n", add[12], add[13], str);
+	printk(KERN_DEBUG "i596 0x%p, %s --> %s %02X%02X, %s\n",
+	       add, print_mac(mac, add + 6), print_mac(mac2, add),
+	       add[12], add[13], str);
 }
 
 static int io = 0x300;
@@ -1233,11 +1229,9 @@
 	DEB(DEB_PROBE,printk(KERN_INFO "%s", version));
 
 	/* The 82596-specific entries in the device structure. */
-	SET_MODULE_OWNER(dev);
 	dev->open = i596_open;
 	dev->stop = i596_close;
 	dev->hard_start_xmit = i596_start_xmit;
-	dev->get_stats = i596_get_stats;
 	dev->set_multicast_list = set_multicast_list;
 	dev->tx_timeout = i596_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
@@ -1343,17 +1337,17 @@
 				if ((ptr->status) & STAT_OK) {
 					DEB(DEB_TXADDR,print_eth(skb->data, "tx-done"));
 				} else {
-					lp->stats.tx_errors++;
+					dev->stats.tx_errors++;
 					if ((ptr->status) & 0x0020)
-						lp->stats.collisions++;
+						dev->stats.collisions++;
 					if (!((ptr->status) & 0x0040))
-						lp->stats.tx_heartbeat_errors++;
+						dev->stats.tx_heartbeat_errors++;
 					if ((ptr->status) & 0x0400)
-						lp->stats.tx_carrier_errors++;
+						dev->stats.tx_carrier_errors++;
 					if ((ptr->status) & 0x0800)
-						lp->stats.collisions++;
+						dev->stats.collisions++;
 					if ((ptr->status) & 0x1000)
-						lp->stats.tx_aborted_errors++;
+						dev->stats.tx_aborted_errors++;
 				}
 
 				dev_kfree_skb_irq(skb);
@@ -1408,8 +1402,8 @@
 			if (netif_running(dev)) {
 				DEB(DEB_ERRORS,printk(KERN_ERR "%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status));
 				ack_cmd |= RX_START;
-				lp->stats.rx_errors++;
-				lp->stats.rx_fifo_errors++;
+				dev->stats.rx_errors++;
+				dev->stats.rx_fifo_errors++;
 				rebuild_rx_bufs(dev);
 			}
 		}
@@ -1492,14 +1486,6 @@
 	return 0;
 }
 
-static struct net_device_stats *
- i596_get_stats(struct net_device *dev)
-{
-	struct i596_private *lp = dev->priv;
-
-	return &lp->stats;
-}
-
 /*
  *    Set or clear the multicast filter for this adaptor.
  */
@@ -1550,6 +1536,7 @@
 		struct dev_mc_list *dmi;
 		unsigned char *cp;
 		struct mc_cmd *cmd;
+		DECLARE_MAC_BUF(mac);
 
 		if (wait_cfg(dev, &lp->mc_cmd.cmd, 1000, "multicast list change request timed out"))
 			return;
@@ -1560,8 +1547,8 @@
 		for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) {
 			memcpy(cp, dmi->dmi_addr, 6);
 			if (i596_debug > 1)
-				DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n",
-						dev->name, cp[0],cp[1],cp[2],cp[3],cp[4],cp[5]));
+				DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %s\n",
+						dev->name, print_mac(mac, cp)));
 		}
 		i596_add_cmd(dev, &cmd->cmd);
 	}
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 43d0317..9c635a2 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -5,6 +5,7 @@
 
 menuconfig NETDEVICES
 	default y if UML
+	depends on NET
 	bool "Network device support"
 	---help---
 	  You can say N here if you don't intend to connect your Linux box to
@@ -134,6 +135,12 @@
 
 	  If you don't know what to use this for, you don't need it.
 
+config VETH
+	tristate "Virtual ethernet device"
+	---help---
+	  The device is an ethernet tunnel. Devices are created in pairs. When
+	  one end receives the packet it appears on its pair and vice versa.
+
 config NET_SB1000
 	tristate "General Instruments Surfboard 1000"
 	depends on PNP
@@ -158,6 +165,15 @@
 
 	  If you don't have this card, of course say N.
 
+config IP1000
+       tristate "IP1000 Gigabit Ethernet support"
+       depends on PCI && EXPERIMENTAL
+       ---help---
+         This driver supports IP1000 gigabit Ethernet cards.
+
+         To compile this driver as a module, choose M here: the module
+         will be called ipg.  This is recommended.
+
 source "drivers/net/arcnet/Kconfig"
 
 source "drivers/net/phy/Kconfig"
@@ -224,6 +240,13 @@
 	  AX88796 driver, using platform bus to provide
 	  chip detection and resources
 
+config AX88796_93CX6
+	bool "ASIX AX88796 external 93CX6 eeprom support"
+	depends on AX88796
+	select EEPROM_93CX6
+	help
+	  Select this if your platform comes with an external 93CX6 eeprom.
+
 config MACE
 	tristate "MACE (Power Mac ethernet) support"
 	depends on PPC_PMAC && PPC32
@@ -465,10 +488,6 @@
 	  If you have an Alchemy Semi AU1X00 based system
 	  say Y.  Otherwise, say N.
 
-config NET_SB1250_MAC
-	tristate "SB1250 Ethernet support"
-	depends on SIBYTE_SB1xxx_SOC
-
 config SGI_IOC3_ETH
 	bool "SGI IOC3 Ethernet"
 	depends on PCI && SGI_IP27
@@ -479,26 +498,6 @@
 	  the Ethernet-HOWTO, available from
 	  <http://www.tldp.org/docs.html#howto>.
 
-config SGI_IOC3_ETH_HW_RX_CSUM
-	bool "Receive hardware checksums"
-	depends on SGI_IOC3_ETH && INET
-	default y
-	help
-	  The SGI IOC3 network adapter supports TCP and UDP checksums in
-	  hardware to offload processing of these checksums from the CPU.  At
-	  the moment only acceleration of IPv4 is supported.  This option
-	  enables offloading for checksums on receive.  If unsure, say Y.
-
-config SGI_IOC3_ETH_HW_TX_CSUM
-	bool "Transmit hardware checksums"
-	depends on SGI_IOC3_ETH && INET
-	default y
-	help
-	  The SGI IOC3 network adapter supports TCP and UDP checksums in
-	  hardware to offload processing of these checksums from the CPU.  At
-	  the moment only acceleration of IPv4 is supported.  This option
-	  enables offloading for checksums on transmit.  If unsure, say Y.
-
 config MIPS_SIM_NET
 	tristate "MIPS simulator Network device"
 	depends on MIPS_SIM
@@ -838,6 +837,52 @@
 	  <file:Documentation/networking/net-modules.txt>. The module
 	  will be called smc-ultra32.
 
+config BFIN_MAC
+	tristate "Blackfin 536/537 on-chip mac support"
+	depends on NET_ETHERNET && (BF537 || BF536) && (!BF537_PORT_H)
+	select CRC32
+	select MII
+	select PHYLIB
+	select BFIN_MAC_USE_L1 if DMA_UNCACHED_NONE
+	help
+	  This is the driver for blackfin on-chip mac device. Say Y if you want it
+	  compiled into the kernel. This driver is also available as a module
+	  ( = code which can be inserted in and removed from the running kernel
+	  whenever you want). The module will be called bfin_mac.
+
+config BFIN_MAC_USE_L1
+	bool "Use L1 memory for rx/tx packets"
+	depends on BFIN_MAC && BF537
+	default y
+	help
+	  To get maximum network performace, you should use L1 memory as rx/tx buffers.
+	  Say N here if you want to reserve L1 memory for other uses.
+
+config BFIN_TX_DESC_NUM
+	int "Number of transmit buffer packets"
+	depends on BFIN_MAC
+	range 6 10 if BFIN_MAC_USE_L1
+	range 10 100
+	default "10"
+	help
+	  Set the number of buffer packets used in driver.
+
+config BFIN_RX_DESC_NUM
+	int "Number of receive buffer packets"
+	depends on BFIN_MAC
+	range 20 100 if BFIN_MAC_USE_L1
+	range 20 800
+	default "20"
+	help
+	  Set the number of buffer packets used in driver.
+
+config BFIN_MAC_RMII
+	bool "RMII PHY Interface (EXPERIMENTAL)"
+	depends on BFIN_MAC && EXPERIMENTAL
+	default n
+	help
+	  Use Reduced PHY MII Interface
+
 config SMC9194
 	tristate "SMC 9194 support"
 	depends on NET_VENDOR_SMC && (ISA || MAC && BROKEN)
@@ -899,7 +944,7 @@
 	tristate "SMSC LAN911[5678] support"
 	select CRC32
 	select MII
-	depends on ARCH_PXA
+	depends on ARCH_PXA || SUPERH
 	help
 	  This is a driver for SMSC's LAN911x series of Ethernet chipsets
 	  including the new LAN9115, LAN9116, LAN9117, and LAN9118.
@@ -1205,75 +1250,8 @@
 	  <file:Documentation/networking/net-modules.txt>. The module will
 	  be called ibmveth.
 
-config IBM_EMAC
-	tristate "PowerPC 4xx on-chip Ethernet support"
-	depends on 4xx && !PPC_MERGE
-	help
-	  This driver supports the PowerPC 4xx EMAC family of on-chip
-          Ethernet controllers.
-
-config IBM_EMAC_RXB
-	int "Number of receive buffers"
-	depends on IBM_EMAC
-	default "128"
-
-config IBM_EMAC_TXB
-	int "Number of transmit buffers"
-	depends on IBM_EMAC
-	default "64"
-
-config IBM_EMAC_POLL_WEIGHT
-	int "MAL NAPI polling weight"
-	depends on IBM_EMAC
-	default "32"
-
-config IBM_EMAC_RX_COPY_THRESHOLD
-	int "RX skb copy threshold (bytes)"
-	depends on IBM_EMAC
-	default "256"
-
-config IBM_EMAC_RX_SKB_HEADROOM
-	int "Additional RX skb headroom (bytes)"
-	depends on IBM_EMAC
-	default "0"
-	help
-	  Additional receive skb headroom. Note, that driver
-	  will always reserve at least 2 bytes to make IP header
-	  aligned, so usually there is no need to add any additional
-	  headroom.
-	  
-	  If unsure, set to 0.
-
-config IBM_EMAC_PHY_RX_CLK_FIX
-	bool "PHY Rx clock workaround"
-	depends on IBM_EMAC && (405EP || 440GX || 440EP || 440GR)
-	help
-	  Enable this if EMAC attached to a PHY which doesn't generate
-	  RX clock if there is no link, if this is the case, you will 
-	  see "TX disable timeout" or "RX disable timeout" in the system
-	  log.
-	  
-	  If unsure, say N.
-
-config IBM_EMAC_DEBUG
-	bool "Debugging"
-	depends on IBM_EMAC
-	default n
-
-config IBM_EMAC_ZMII
-	bool
-	depends on IBM_EMAC && (NP405H || NP405L || 44x)
-	default y
-
-config IBM_EMAC_RGMII
-	bool
-	depends on IBM_EMAC && 440GX
-	default y
-		
-config IBM_EMAC_TAH
-	bool
-	depends on IBM_EMAC && 440GX
-	default y
+source "drivers/net/ibm_emac/Kconfig"
+source "drivers/net/ibm_newemac/Kconfig"
 
 config NET_PCI
 	bool "EISA, VLB, PCI and on board controllers"
@@ -1408,18 +1386,38 @@
 	  called apricot.
 
 config B44
-	tristate "Broadcom 4400 ethernet support"
-	depends on NET_PCI && PCI
+	tristate "Broadcom 440x/47xx ethernet support"
+	depends on SSB_POSSIBLE
+	select SSB
 	select MII
 	help
-	  If you have a network (Ethernet) controller of this type, say Y and
-	  read the Ethernet-HOWTO, available from
+	  If you have a network (Ethernet) controller of this type, say Y
+	  or M and read the Ethernet-HOWTO, available from
 	  <http://www.tldp.org/docs.html#howto>.
 
 	  To compile this driver as a module, choose M here and read
 	  <file:Documentation/networking/net-modules.txt>.  The module will be
 	  called b44.
 
+# Auto-select SSB PCI-HOST support, if possible
+config B44_PCI_AUTOSELECT
+	bool
+	depends on B44 && SSB_PCIHOST_POSSIBLE
+	select SSB_PCIHOST
+	default y
+
+# Auto-select SSB PCICORE driver, if possible
+config B44_PCICORE_AUTOSELECT
+	bool
+	depends on B44 && SSB_DRIVER_PCICORE_POSSIBLE
+	select SSB_DRIVER_PCICORE
+	default y
+
+config B44_PCI
+	bool
+	depends on B44_PCI_AUTOSELECT && B44_PCICORE_AUTOSELECT
+	default y
+
 config FORCEDETH
 	tristate "nForce Ethernet support"
 	depends on NET_PCI && PCI
@@ -1468,21 +1466,6 @@
 	depends on NET_PCI && PCI && MIPS
 	select MII
 
-config DGRS
-	tristate "Digi Intl. RightSwitch SE-X support"
-	depends on NET_PCI && (PCI || EISA)
-	---help---
-	  This is support for the Digi International RightSwitch series of
-	  PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6
-	  models.  If you have a network card of this type, say Y and read the
-	  Ethernet-HOWTO, available from
-	  <http://www.tldp.org/docs.html#howto>.  More specific
-	  information is contained in <file:Documentation/networking/dgrs.txt>.
-
-	  To compile this driver as a module, choose M here and read
-	  <file:Documentation/networking/net-modules.txt>.  The module
-	  will be called dgrs.
-
 config EEPRO100
 	tristate "EtherExpressPro/100 support (eepro100, original Becker driver)"
 	depends on NET_PCI && PCI
@@ -1923,6 +1906,16 @@
 	bool "Ethernet (1000 Mbit)"
 	depends on !UML
 	default y
+	---help---
+	  Ethernet (also called IEEE 802.3 or ISO 8802-2) is the most common
+	  type of Local Area Network (LAN) in universities and companies.
+
+	  Say Y here to get to see options for Gigabit Ethernet drivers.
+	  This option alone does not add any kernel code.
+	  Note that drivers supporting both 100 and 1000 MBit may be listed
+	  under "Ethernet (10 or 100MBit)" instead.
+
+	  If you say N, all options in this submenu will be skipped and disabled.
 
 if NETDEV_1000
 
@@ -1954,14 +1947,15 @@
 	  The safe and default value for this is N.
 
 config DL2K
-	tristate "D-Link DL2000-based Gigabit Ethernet support"
+	tristate "DL2000/TC902x-based Gigabit Ethernet support"
 	depends on PCI
 	select CRC32
 	help
-	  This driver supports D-Link 2000-based gigabit ethernet cards, which
-	  includes
+	  This driver supports DL2000/TC902x-based Gigabit ethernet cards,
+	  which includes
 	  D-Link DGE-550T Gigabit Ethernet Adapter.
 	  D-Link DL2000-based Gigabit Ethernet Adapter.
+	  Sundance/Tamarack TC902x Gigabit Ethernet Adapter.
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called dl2k.
@@ -2014,6 +2008,29 @@
 
 	  If in doubt, say N.
 
+config E1000E
+	tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support"
+	depends on PCI
+	---help---
+	  This driver supports the PCI-Express Intel(R) PRO/1000 gigabit
+	  ethernet family of adapters. For PCI or PCI-X e1000 adapters,
+	  use the regular e1000 driver For more information on how to
+	  identify your adapter, go to the Adapter & Driver ID Guide at:
+
+	  <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+	  For general information and support, go to the Intel support
+	  website at:
+
+	  <http://support.intel.com>
+
+	  More specific information on configuring the driver is in
+	  <file:Documentation/networking/e1000e.txt>.
+
+	  To compile this driver as a module, choose M here and read
+	  <file:Documentation/networking/net-modules.txt>.  The module
+	  will be called e1000e.
+
 source "drivers/net/ixp2000/Kconfig"
 
 config MYRI_SBUS
@@ -2098,6 +2115,19 @@
 	  
 	  If in doubt, say Y.
 
+config SB1250_MAC
+	tristate "SB1250 Gigabit Ethernet support"
+	depends on SIBYTE_SB1xxx_SOC
+	select PHYLIB
+	---help---
+	  This driver supports Gigabit Ethernet interfaces based on the
+	  Broadcom SiByte family of System-On-a-Chip parts.  They include
+	  the BCM1120, BCM1125, BCM1125H, BCM1250, BCM1255, BCM1280, BCM1455
+	  and BCM1480 chips.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called sb1250-mac.
+
 config SIS190
 	tristate "SiS190/SiS191 gigabit ethernet support"
 	depends on PCI
@@ -2122,7 +2152,7 @@
 	  with better performance and more complete ethtool support.
 
 	  It does not support the link failover and network management 
-	  features available in the hardware.
+	  features that "portable" vendor supplied sk98lin driver does.
 
 	  This driver supports adapters based on the original Yukon chipset:
 	  Marvell 88E8001, Belkin F5D5005, CNet GigaCard, DLink DGE-530T,
@@ -2160,6 +2190,93 @@
 
 	 If unsure, say N.
 
+config SK98LIN
+	tristate "Marvell Yukon Chipset / SysKonnect SK-98xx Support (DEPRECATED)"
+	depends on PCI
+	---help---
+	  Say Y here if you have a Marvell Yukon or SysKonnect SK-98xx/SK-95xx
+	  compliant Gigabit Ethernet Adapter.
+
+	  This driver supports the original Yukon chipset. This driver is
+	  deprecated and will be removed from the kernel in the near future,
+	  it has been replaced by the skge driver. skge is cleaner and
+	  seems to work better.
+
+	  This driver does not support the newer Yukon2 chipset. A separate
+	  driver, sky2, is provided to support Yukon2-based adapters.
+
+	  The following adapters are supported by this driver:
+	    - 3Com 3C940 Gigabit LOM Ethernet Adapter
+	    - 3Com 3C941 Gigabit LOM Ethernet Adapter
+	    - Allied Telesyn AT-2970LX Gigabit Ethernet Adapter
+	    - Allied Telesyn AT-2970LX/2SC Gigabit Ethernet Adapter
+	    - Allied Telesyn AT-2970SX Gigabit Ethernet Adapter
+	    - Allied Telesyn AT-2970SX/2SC Gigabit Ethernet Adapter
+	    - Allied Telesyn AT-2970TX Gigabit Ethernet Adapter
+	    - Allied Telesyn AT-2970TX/2TX Gigabit Ethernet Adapter
+	    - Allied Telesyn AT-2971SX Gigabit Ethernet Adapter
+	    - Allied Telesyn AT-2971T Gigabit Ethernet Adapter
+	    - Belkin Gigabit Desktop Card 10/100/1000Base-T Adapter, Copper RJ-45
+	    - EG1032 v2 Instant Gigabit Network Adapter
+	    - EG1064 v2 Instant Gigabit Network Adapter
+	    - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Abit)
+	    - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Albatron)
+	    - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Asus)
+	    - Marvell 88E8001 Gigabit LOM Ethernet Adapter (ECS)
+	    - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Epox)
+	    - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Foxconn)
+	    - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Gigabyte)
+	    - Marvell 88E8001 Gigabit LOM Ethernet Adapter (Iwill)
+	    - Marvell 88E8050 Gigabit LOM Ethernet Adapter (Intel)
+	    - Marvell RDK-8001 Adapter
+	    - Marvell RDK-8002 Adapter
+	    - Marvell RDK-8003 Adapter
+	    - Marvell RDK-8004 Adapter
+	    - Marvell RDK-8006 Adapter
+	    - Marvell RDK-8007 Adapter
+	    - Marvell RDK-8008 Adapter
+	    - Marvell RDK-8009 Adapter
+	    - Marvell RDK-8010 Adapter
+	    - Marvell RDK-8011 Adapter
+	    - Marvell RDK-8012 Adapter
+	    - Marvell RDK-8052 Adapter
+	    - Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (32 bit)
+	    - Marvell Yukon Gigabit Ethernet 10/100/1000Base-T Adapter (64 bit)
+	    - N-Way PCI-Bus Giga-Card 1000/100/10Mbps(L)
+	    - SK-9521 10/100/1000Base-T Adapter
+	    - SK-9521 V2.0 10/100/1000Base-T Adapter
+	    - SK-9821 Gigabit Ethernet Server Adapter (SK-NET GE-T)
+	    - SK-9821 V2.0 Gigabit Ethernet 10/100/1000Base-T Adapter
+	    - SK-9822 Gigabit Ethernet Server Adapter (SK-NET GE-T dual link)
+	    - SK-9841 Gigabit Ethernet Server Adapter (SK-NET GE-LX)
+	    - SK-9841 V2.0 Gigabit Ethernet 1000Base-LX Adapter
+	    - SK-9842 Gigabit Ethernet Server Adapter (SK-NET GE-LX dual link)
+	    - SK-9843 Gigabit Ethernet Server Adapter (SK-NET GE-SX)
+	    - SK-9843 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+	    - SK-9844 Gigabit Ethernet Server Adapter (SK-NET GE-SX dual link)
+	    - SK-9851 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+	    - SK-9861 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition)
+	    - SK-9861 V2.0 Gigabit Ethernet 1000Base-SX Adapter
+	    - SK-9862 Gigabit Ethernet Server Adapter (SK-NET GE-SX Volition dual link)
+	    - SK-9871 Gigabit Ethernet Server Adapter (SK-NET GE-ZX)
+	    - SK-9871 V2.0 Gigabit Ethernet 1000Base-ZX Adapter
+	    - SK-9872 Gigabit Ethernet Server Adapter (SK-NET GE-ZX dual link)
+	    - SMC EZ Card 1000 (SMC9452TXV.2)
+	  
+	  The adapters support Jumbo Frames.
+	  The dual link adapters support link-failover and dual port features.
+	  Both Marvell Yukon and SysKonnect SK-98xx/SK-95xx adapters support 
+	  the scatter-gather functionality with sendfile(). Please refer to 
+	  <file:Documentation/networking/sk98lin.txt> for more information about
+	  optional driver parameters.
+	  Questions concerning this driver may be addressed to:
+	      <linux@syskonnect.de>
+	  
+	  If you want to compile this driver as a module ( = code which can be
+	  inserted in and removed from the running kernel whenever you want),
+	  say M here and read <file:Documentation/kbuild/modules.txt>. The module will
+	  be called sk98lin. This is recommended.
+
 config VIA_VELOCITY
 	tristate "VIA Velocity support"
 	depends on PCI
@@ -2294,6 +2411,11 @@
 	bool "Ethernet (10000 Mbit)"
 	depends on !UML
 	default y
+	---help---
+	  Say Y here to get to see options for 10 Gigabit Ethernet drivers.
+	  This option alone does not add any kernel code.
+
+	  If you say N, all options in this submenu will be skipped and disabled.
 
 if NETDEV_10000
 
@@ -2354,18 +2476,42 @@
 config EHEA
 	tristate "eHEA Ethernet support"
 	depends on IBMEBUS
+	select INET_LRO
 	---help---
 	  This driver supports the IBM pSeries eHEA ethernet adapter.
 
 	  To compile the driver as a module, choose M here. The module
 	  will be called ehea.
 
+config IXGBE
+	tristate "Intel(R) 10GbE PCI Express adapters support"
+	depends on PCI
+	---help---
+	  This driver supports Intel(R) 10GbE PCI Express family of
+	  adapters.  For more information on how to identify your adapter, go
+	  to the Adapter & Driver ID Guide at:
+
+	  <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+	  For general information and support, go to the Intel support
+	  website at:
+
+	  <http://support.intel.com>
+
+	  More specific information on configuring the driver is in
+	  <file:Documentation/networking/ixgbe.txt>.
+
+	  To compile this driver as a module, choose M here and read
+	  <file:Documentation/networking/net-modules.txt>.  The module
+	  will be called ixgbe.
+
 config IXGB
 	tristate "Intel(R) PRO/10GbE support"
 	depends on PCI
 	---help---
-	  This driver supports Intel(R) PRO/10GbE family of
-	  adapters.  For more information on how to identify your adapter, go
+	  This driver supports Intel(R) PRO/10GbE family of adapters for
+	  PCI-X type cards. For PCI-E type cards, use the "ixgbe" driver
+	  instead. For more information on how to identify your adapter, go
 	  to the Adapter & Driver ID Guide at:
 
 	  <http://support.intel.com/support/network/adapter/pro100/21397.htm>
@@ -2429,6 +2575,7 @@
 	depends on PCI
 	select FW_LOADER
 	select CRC32
+	select INET_LRO
 	---help---
 	  This driver supports Myricom Myri-10G Dual Protocol interface in
 	  Ethernet mode. If the eeprom on your board is not recent enough,
@@ -2447,6 +2594,13 @@
 	help
 	  This enables the support for NetXen's Gigabit Ethernet card.
 
+config NIU
+	tristate "Sun Neptune 10Gbit Ethernet support"
+	depends on PCI
+	help
+	  This enables support for cards based upon Sun's
+	  Neptune chipset.
+
 config PASEMI_MAC
 	tristate "PA Semi 1/10Gbit MAC"
 	depends on PPC64 && PCI
@@ -2470,6 +2624,12 @@
 	  debug_level module parameter (which can also be set after
 	  the driver is loaded through sysfs).
 
+config TEHUTI
+	tristate "Tehuti Networks 10G Ethernet"
+	depends on PCI
+	help
+	  Tehuti Networks 10G Ethernet NIC
+
 endif # NETDEV_10000
 
 source "drivers/net/tokenring/Kconfig"
@@ -2486,6 +2646,18 @@
 
 source "drivers/s390/net/Kconfig"
 
+config XEN_NETDEV_FRONTEND
+	tristate "Xen network device frontend driver"
+	depends on XEN
+	default y
+	help
+	  The network device frontend driver allows the kernel to
+	  access network devices exported exported by a virtual
+	  machine containing a physical network device driver. The
+	  frontend driver is intended for unprivileged guest domains;
+	  if you are compiling a kernel for a Xen guest, you almost
+	  certainly want to enable this.
+
 config ISERIES_VETH
 	tristate "iSeries Virtual Ethernet driver support"
 	depends on PPC_ISERIES
@@ -2794,7 +2966,7 @@
 
 config PPPOL2TP
 	tristate "PPP over L2TP (EXPERIMENTAL)"
-	depends on EXPERIMENTAL && PPP
+	depends on EXPERIMENTAL && PPP && INET
 	help
 	  Support for PPP-over-L2TP socket family. L2TP is a protocol
 	  used by ISPs and enterprises to tunnel PPP traffic over UDP
@@ -2915,6 +3087,16 @@
 	If you want to log kernel messages over the network, enable this.
 	See <file:Documentation/networking/netconsole.txt> for details.
 
+config NETCONSOLE_DYNAMIC
+	bool "Dynamic reconfiguration of logging targets (EXPERIMENTAL)"
+	depends on NETCONSOLE && SYSFS && EXPERIMENTAL
+	select CONFIGFS_FS
+	help
+	  This option enables the ability to dynamically reconfigure target
+	  parameters (interface, IP addresses, port numbers, MAC addresses)
+	  at runtime through a userspace interface exported using configfs.
+	  See <file:Documentation/networking/netconsole.txt> for details.
+
 config NETPOLL
 	def_bool NETCONSOLE
 
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index eb41676..d2e0f35 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -3,14 +3,19 @@
 #
 
 obj-$(CONFIG_E1000) += e1000/
+obj-$(CONFIG_E1000E) += e1000e/
 obj-$(CONFIG_IBM_EMAC) += ibm_emac/
+obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac/
+obj-$(CONFIG_IXGBE) += ixgbe/
 obj-$(CONFIG_IXGB) += ixgb/
+obj-$(CONFIG_IP1000) += ipg.o
 obj-$(CONFIG_CHELSIO_T1) += chelsio/
 obj-$(CONFIG_CHELSIO_T3) += cxgb3/
 obj-$(CONFIG_EHEA) += ehea/
 obj-$(CONFIG_BONDING) += bonding/
 obj-$(CONFIG_ATL1) += atl1/
 obj-$(CONFIG_GIANFAR) += gianfar_driver.o
+obj-$(CONFIG_TEHUTI) += tehuti.o
 
 gianfar_driver-objs := gianfar.o \
 		gianfar_ethtool.o \
@@ -18,7 +23,7 @@
 		gianfar_sysfs.o
 
 obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
-ucc_geth_driver-objs := ucc_geth.o ucc_geth_mii.o
+ucc_geth_driver-objs := ucc_geth.o ucc_geth_mii.o ucc_geth_ethtool.o
 
 #
 # link order important here
@@ -39,7 +44,6 @@
 obj-$(CONFIG_MACE) += mace.o
 obj-$(CONFIG_BMAC) += bmac.o
 
-obj-$(CONFIG_DGRS) += dgrs.o
 obj-$(CONFIG_VORTEX) += 3c59x.o
 obj-$(CONFIG_TYPHOON) += typhoon.o
 obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o
@@ -66,6 +70,7 @@
 obj-$(CONFIG_TC35815) += tc35815.o
 obj-$(CONFIG_SKGE) += skge.o
 obj-$(CONFIG_SKY2) += sky2.o
+obj-$(CONFIG_SK98LIN) += sk98lin/
 obj-$(CONFIG_SKFP) += skfp/
 obj-$(CONFIG_VIA_RHINE) += via-rhine.o
 obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o
@@ -105,7 +110,7 @@
 obj-$(CONFIG_ES3210) += es3210.o 8390.o
 obj-$(CONFIG_LNE390) += lne390.o 8390.o
 obj-$(CONFIG_NE3210) += ne3210.o 8390.o
-obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o
+obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o
 obj-$(CONFIG_B44) += b44.o
 obj-$(CONFIG_FORCEDETH) += forcedeth.o
 obj-$(CONFIG_NE_H8300) += ne-h8300.o
@@ -127,6 +132,8 @@
 obj-$(CONFIG_SLIP) += slip.o
 obj-$(CONFIG_SLHC) += slhc.o
 
+obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o
+
 obj-$(CONFIG_DUMMY) += dummy.o
 obj-$(CONFIG_IFB) += ifb.o
 obj-$(CONFIG_MACVLAN) += macvlan.o
@@ -175,6 +182,7 @@
 obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
 obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
 obj-$(CONFIG_EQUALIZER) += eql.o
+obj-$(CONFIG_LGUEST_NET) += lguest_net.o
 obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
 obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
 obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o
@@ -189,6 +197,7 @@
 obj-$(CONFIG_MACMACE) += macmace.o
 obj-$(CONFIG_MAC89x0) += mac89x0.o
 obj-$(CONFIG_TUN) += tun.o
+obj-$(CONFIG_VETH) += veth.o
 obj-$(CONFIG_NET_NETX) += netx-eth.o
 obj-$(CONFIG_DL2K) += dl2k.o
 obj-$(CONFIG_R8169) += r8169.o
@@ -198,6 +207,7 @@
 obj-$(CONFIG_MYRI10GE) += myri10ge/
 obj-$(CONFIG_SMC91X) += smc91x.o
 obj-$(CONFIG_SMC911X) += smc911x.o
+obj-$(CONFIG_BFIN_MAC) += bfin_mac.o
 obj-$(CONFIG_DM9000) += dm9000.o
 obj-$(CONFIG_FEC_8XX) += fec_8xx/
 obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o
@@ -231,3 +241,4 @@
 obj-$(CONFIG_FS_ENET) += fs_enet/
 
 obj-$(CONFIG_NETXEN_NIC) += netxen/
+obj-$(CONFIG_NIU) += niu.o
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index a45de69..18f7f81 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -119,7 +119,6 @@
 	int lance_log_rx_bufs, lance_log_tx_bufs;
 	int rx_ring_mod_mask, tx_ring_mod_mask;
 
-	struct net_device_stats stats;
 	int tpe;		      /* cable-selection is TPE */
 	int auto_select;	      /* cable-selection by carrier */
 	unsigned short busmaster_regval;
@@ -294,18 +293,18 @@
 
 		/* We got an incomplete frame? */
 		if ((bits & LE_R1_POK) != LE_R1_POK) {
-			lp->stats.rx_over_errors++;
-			lp->stats.rx_errors++;
+			dev->stats.rx_over_errors++;
+			dev->stats.rx_errors++;
 			continue;
 		} else if (bits & LE_R1_ERR) {
 			/* Count only the end frame as a rx error,
 			 * not the beginning
 			 */
-			if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
-			if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
-			if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
-			if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
-			if (bits & LE_R1_EOP) lp->stats.rx_errors++;
+			if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++;
+			if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++;
+			if (bits & LE_R1_OFL) dev->stats.rx_over_errors++;
+			if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++;
+			if (bits & LE_R1_EOP) dev->stats.rx_errors++;
 		} else {
 			len = (rd->mblength & 0xfff) - 4;
 			skb = dev_alloc_skb (len+2);
@@ -313,7 +312,7 @@
 			if (skb == 0) {
 				printk(KERN_WARNING "%s: Memory squeeze, "
 				       "deferring packet.\n", dev->name);
-				lp->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 				rd->mblength = 0;
 				rd->rmd1_bits = LE_R1_OWN;
 				lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
@@ -328,8 +327,8 @@
 			skb->protocol = eth_type_trans (skb, dev);
 			netif_rx (skb);
 			dev->last_rx = jiffies;
-			lp->stats.rx_packets++;
-			lp->stats.rx_bytes += len;
+			dev->stats.rx_packets++;
+			dev->stats.rx_bytes += len;
 		}
 
 		/* Return the packet to the pool */
@@ -364,12 +363,12 @@
 		if (td->tmd1_bits & LE_T1_ERR) {
 			status = td->misc;
 
-			lp->stats.tx_errors++;
-			if (status & LE_T3_RTY)  lp->stats.tx_aborted_errors++;
-			if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+			dev->stats.tx_errors++;
+			if (status & LE_T3_RTY)  dev->stats.tx_aborted_errors++;
+			if (status & LE_T3_LCOL) dev->stats.tx_window_errors++;
 
 			if (status & LE_T3_CLOS) {
-				lp->stats.tx_carrier_errors++;
+				dev->stats.tx_carrier_errors++;
 				if (lp->auto_select) {
 					lp->tpe = 1 - lp->tpe;
 					printk(KERN_ERR "%s: Carrier Lost, "
@@ -388,7 +387,7 @@
 			/* buffer errors and underflows turn off the transmitter */
 			/* Restart the adapter */
 			if (status & (LE_T3_BUF|LE_T3_UFL)) {
-				lp->stats.tx_fifo_errors++;
+				dev->stats.tx_fifo_errors++;
 
 				printk(KERN_ERR "%s: Tx: ERR_BUF|ERR_UFL, "
 				       "restarting\n", dev->name);
@@ -408,13 +407,13 @@
 
 			/* One collision before packet was sent. */
 			if (td->tmd1_bits & LE_T1_EONE)
-				lp->stats.collisions++;
+				dev->stats.collisions++;
 
 			/* More than one collision, be optimistic. */
 			if (td->tmd1_bits & LE_T1_EMORE)
-				lp->stats.collisions += 2;
+				dev->stats.collisions += 2;
 
-			lp->stats.tx_packets++;
+			dev->stats.tx_packets++;
 		}
 
 		j = (j + 1) & lp->tx_ring_mod_mask;
@@ -459,9 +458,9 @@
 
 	/* Log misc errors. */
 	if (csr0 & LE_C0_BABL)
-		lp->stats.tx_errors++;       /* Tx babble. */
+		dev->stats.tx_errors++;       /* Tx babble. */
 	if (csr0 & LE_C0_MISS)
-		lp->stats.rx_errors++;       /* Missed a Rx frame. */
+		dev->stats.rx_errors++;       /* Missed a Rx frame. */
 	if (csr0 & LE_C0_MERR) {
 		printk(KERN_ERR "%s: Bus master arbitration failure, status "
 		       "%4.4x.\n", dev->name, csr0);
@@ -606,7 +605,7 @@
 	/* Now, give the packet to the lance */
 	ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
 	lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
-	lp->stats.tx_bytes += skblen;
+	dev->stats.tx_bytes += skblen;
 
 	if (TX_BUFFS_AVAIL <= 0)
 		netif_stop_queue(dev);
@@ -621,13 +620,6 @@
 	return status;
 }
 
-static struct net_device_stats *lance_get_stats (struct net_device *dev)
-{
-	struct lance_private *lp = netdev_priv(dev);
-
-	return &lp->stats;
-}
-
 /* taken from the depca driver */
 static void lance_load_multicast (struct net_device *dev)
 {
@@ -724,6 +716,7 @@
 	unsigned long board, base_addr, mem_start;
 	struct resource *r1, *r2;
 	int err;
+	DECLARE_MAC_BUF(mac);
 
 	board = z->resource.start;
 	base_addr = board+A2065_LANCE;
@@ -746,7 +739,6 @@
 		return -ENOMEM;
 	}
 
-	SET_MODULE_OWNER(dev);
 	priv = netdev_priv(dev);
 
 	r1->name = dev->name;
@@ -783,7 +775,6 @@
 	dev->hard_start_xmit = &lance_start_xmit;
 	dev->tx_timeout = &lance_tx_timeout;
 	dev->watchdog_timeo = 5*HZ;
-	dev->get_stats = &lance_get_stats;
 	dev->set_multicast_list = &lance_set_multicast;
 	dev->dma = 0;
 
@@ -802,9 +793,8 @@
 	zorro_set_drvdata(z, dev);
 
 	printk(KERN_INFO "%s: A2065 at 0x%08lx, Ethernet Address "
-	       "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board,
-	       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-	       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+	       "%s\n", dev->name, board,
+	       print_mac(mac, dev->dev_addr));
 
 	return 0;
 }
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index 644c408..5136d949 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -103,8 +103,6 @@
 	int irq = dev->irq;
 	int mem_start = dev->mem_start;
 
-	SET_MODULE_OWNER(dev);
-
 	if (ioaddr > 0x1ff)		/* Check a single specified location. */
 		return ac_probe1(ioaddr, dev);
 	else if (ioaddr > 0)		/* Don't probe at all. */
@@ -148,6 +146,7 @@
 static int __init ac_probe1(int ioaddr, struct net_device *dev)
 {
 	int i, retval;
+	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, AC_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -169,10 +168,11 @@
 		   inb(ioaddr + AC_ID_PORT + 2), inb(ioaddr + AC_ID_PORT + 3));
 #endif
 
-	printk("AC3200 in EISA slot %d, node", ioaddr/0x1000);
-	for(i = 0; i < 6; i++)
-		printk(" %02x", dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i));
+	for (i = 0; i < 6; i++)
+		dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i);
 
+	printk(KERN_DEBUG "AC3200 in EISA slot %d, node %s",
+	       ioaddr/0x1000, print_mac(mac, dev->dev_addr));
 #if 0
 	/* Check the vendor ID/prefix. Redundant after checking the EISA ID */
 	if (inb(ioaddr + AC_SA_PROM + 0) != AC_ADDR0
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index b78a4e5..6c19265 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -406,7 +406,7 @@
 #define DEF_STAT		(2 * TICKS_PER_SEC)
 
 
-static int link[ACE_MAX_MOD_PARMS];
+static int link_state[ACE_MAX_MOD_PARMS];
 static int trace[ACE_MAX_MOD_PARMS];
 static int tx_coal_tick[ACE_MAX_MOD_PARMS];
 static int rx_coal_tick[ACE_MAX_MOD_PARMS];
@@ -419,7 +419,7 @@
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver");
 
-module_param_array(link, int, NULL, 0);
+module_param_array_named(link, link_state, int, NULL, 0);
 module_param_array(trace, int, NULL, 0);
 module_param_array(tx_coal_tick, int, NULL, 0);
 module_param_array(max_tx_desc, int, NULL, 0);
@@ -465,7 +465,6 @@
 		return -ENOMEM;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	ap = dev->priv;
@@ -894,6 +893,7 @@
 	int board_idx, ecode = 0;
 	short i;
 	unsigned char cache_size;
+	DECLARE_MAC_BUF(mac);
 
 	ap = netdev_priv(dev);
 	regs = ap->regs;
@@ -987,36 +987,32 @@
 
 	mac1 = 0;
 	for(i = 0; i < 4; i++) {
-		int tmp;
+		int t;
 
 		mac1 = mac1 << 8;
-		tmp = read_eeprom_byte(dev, 0x8c+i);
-		if (tmp < 0) {
+		t = read_eeprom_byte(dev, 0x8c+i);
+		if (t < 0) {
 			ecode = -EIO;
 			goto init_error;
 		} else
-			mac1 |= (tmp & 0xff);
+			mac1 |= (t & 0xff);
 	}
 	mac2 = 0;
 	for(i = 4; i < 8; i++) {
-		int tmp;
+		int t;
 
 		mac2 = mac2 << 8;
-		tmp = read_eeprom_byte(dev, 0x8c+i);
-		if (tmp < 0) {
+		t = read_eeprom_byte(dev, 0x8c+i);
+		if (t < 0) {
 			ecode = -EIO;
 			goto init_error;
 		} else
-			mac2 |= (tmp & 0xff);
+			mac2 |= (t & 0xff);
 	}
 
 	writel(mac1, &regs->MacAddrHi);
 	writel(mac2, &regs->MacAddrLo);
 
-	printk("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       (mac1 >> 8) & 0xff, mac1 & 0xff, (mac2 >> 24) &0xff,
-	       (mac2 >> 16) & 0xff, (mac2 >> 8) & 0xff, mac2 & 0xff);
-
 	dev->dev_addr[0] = (mac1 >> 8) & 0xff;
 	dev->dev_addr[1] = mac1 & 0xff;
 	dev->dev_addr[2] = (mac2 >> 24) & 0xff;
@@ -1024,6 +1020,8 @@
 	dev->dev_addr[4] = (mac2 >> 8) & 0xff;
 	dev->dev_addr[5] = mac2 & 0xff;
 
+	printk("MAC: %s\n", print_mac(mac, dev->dev_addr));
+
 	/*
 	 * Looks like this is necessary to deal with on all architectures,
 	 * even this %$#%$# N440BX Intel based thing doesn't get it right.
@@ -1307,10 +1305,10 @@
 	writel(TX_RING_BASE, &regs->WinBase);
 
 	if (ACE_IS_TIGON_I(ap)) {
-		ap->tx_ring = (struct tx_desc *) regs->Window;
+		ap->tx_ring = (__force struct tx_desc *) regs->Window;
 		for (i = 0; i < (TIGON_I_TX_RING_ENTRIES
 				 * sizeof(struct tx_desc)) / sizeof(u32); i++)
-			writel(0, (void __iomem *)ap->tx_ring  + i * 4);
+			writel(0, (__force void __iomem *)ap->tx_ring  + i * 4);
 
 		set_aceaddr(&info->tx_ctrl.rngptr, TX_RING_BASE);
 	} else {
@@ -1396,8 +1394,8 @@
 	/*
 	 * Override link default parameters
 	 */
-	if ((board_idx >= 0) && link[board_idx]) {
-		int option = link[board_idx];
+	if ((board_idx >= 0) && link_state[board_idx]) {
+		int option = link_state[board_idx];
 
 		tmp = LNK_ENABLE;
 
@@ -2385,8 +2383,9 @@
 
 		if (mapping) {
 			if (ACE_IS_TIGON_I(ap)) {
-				struct tx_desc __iomem *tx
-					= (struct tx_desc __iomem *) &ap->tx_ring[i];
+				/* NB: TIGON_1 is special, tx_ring is in io space */
+				struct tx_desc __iomem *tx;
+				tx = (__force struct tx_desc __iomem *) &ap->tx_ring[i];
 				writel(0, &tx->addr.addrhi);
 				writel(0, &tx->addr.addrlo);
 				writel(0, &tx->flagsize);
@@ -2446,7 +2445,7 @@
 #endif
 
 	if (ACE_IS_TIGON_I(ap)) {
-		struct tx_desc __iomem *io = (struct tx_desc __iomem *) desc;
+		struct tx_desc __iomem *io = (__force struct tx_desc __iomem *) desc;
 		writel(addr >> 32, &io->addr.addrhi);
 		writel(addr & 0xffffffff, &io->addr.addrlo);
 		writel(flagsize, &io->flagsize);
@@ -2938,7 +2937,7 @@
  * This operation requires the NIC to be halted and is performed with
  * interrupts disabled and with the spinlock hold.
  */
-int __devinit ace_load_firmware(struct net_device *dev)
+static int __devinit ace_load_firmware(struct net_device *dev)
 {
 	struct ace_private *ap = netdev_priv(dev);
 	struct ace_regs __iomem *regs = ap->regs;
@@ -3128,12 +3127,6 @@
 	int result = 0;
 	short i;
 
-	if (!dev) {
-		printk(KERN_ERR "No device!\n");
-		result = -ENODEV;
-		goto out;
-	}
-
 	/*
 	 * Don't take interrupts on this CPU will bit banging
 	 * the %#%#@$ I2C device
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index a61b2f8..1cc74ec 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -709,7 +709,8 @@
 		lp->tx_complete_idx++;
 		/*COAL update tx coalescing parameters */
 		lp->coal_conf.tx_packets++;
-		lp->coal_conf.tx_bytes += lp->tx_ring[tx_index].buff_count;
+		lp->coal_conf.tx_bytes +=
+			le16_to_cpu(lp->tx_ring[tx_index].buff_count);
 
 		if (netif_queue_stopped(dev) &&
 			lp->tx_complete_idx > lp->tx_idx - NUM_TX_BUFFERS +2){
@@ -723,9 +724,10 @@
 
 #ifdef CONFIG_AMD8111E_NAPI
 /* This function handles the driver receive operation in polling mode */
-static int amd8111e_rx_poll(struct net_device *dev, int * budget)
+static int amd8111e_rx_poll(struct napi_struct *napi, int budget)
 {
-	struct amd8111e_priv *lp = netdev_priv(dev);
+	struct amd8111e_priv *lp = container_of(napi, struct amd8111e_priv, napi);
+	struct net_device *dev = lp->amd8111e_net_dev;
 	int rx_index = lp->rx_idx & RX_RING_DR_MOD_MASK;
 	void __iomem *mmio = lp->mmio;
 	struct sk_buff *skb,*new_skb;
@@ -737,7 +739,7 @@
 #if AMD8111E_VLAN_TAG_USED
 	short vtag;
 #endif
-	int rx_pkt_limit = dev->quota;
+	int rx_pkt_limit = budget;
 	unsigned long flags;
 
 	do{
@@ -838,21 +840,14 @@
 	} while(intr0 & RINT0);
 
 	/* Receive descriptor is empty now */
-	dev->quota -= num_rx_pkt;
-	*budget -= num_rx_pkt;
-
 	spin_lock_irqsave(&lp->lock, flags);
-	netif_rx_complete(dev);
+	__netif_rx_complete(dev, napi);
 	writel(VAL0|RINTEN0, mmio + INTEN0);
 	writel(VAL2 | RDMD0, mmio + CMD0);
 	spin_unlock_irqrestore(&lp->lock, flags);
-	return 0;
 
 rx_not_empty:
-	/* Do not call a netif_rx_complete */
-	dev->quota -= num_rx_pkt;
-	*budget -= num_rx_pkt;
-	return 1;
+	return num_rx_pkt;
 }
 
 #else
@@ -1287,11 +1282,11 @@
 	/* Check if Receive Interrupt has occurred. */
 #ifdef CONFIG_AMD8111E_NAPI
 	if(intr0 & RINT0){
-		if(netif_rx_schedule_prep(dev)){
+		if(netif_rx_schedule_prep(dev, &lp->napi)){
 			/* Disable receive interupts */
 			writel(RINTEN0, mmio + INTEN0);
 			/* Schedule a polling routine */
-			__netif_rx_schedule(dev);
+			__netif_rx_schedule(dev, &lp->napi);
 		}
 		else if (intren0 & RINTEN0) {
 			printk("************Driver bug! \
@@ -1345,6 +1340,8 @@
 	struct amd8111e_priv *lp = netdev_priv(dev);
 	netif_stop_queue(dev);
 
+	napi_disable(&lp->napi);
+
 	spin_lock_irq(&lp->lock);
 
 	amd8111e_disable_interrupt(lp);
@@ -1375,12 +1372,15 @@
 					 dev->name, dev))
 		return -EAGAIN;
 
+	napi_enable(&lp->napi);
+
 	spin_lock_irq(&lp->lock);
 
 	amd8111e_init_hw_default(lp);
 
 	if(amd8111e_restart(dev)){
 		spin_unlock_irq(&lp->lock);
+		napi_disable(&lp->napi);
 		if (dev->irq)
 			free_irq(dev->irq, dev);
 		return -ENOMEM;
@@ -1405,7 +1405,7 @@
 static int amd8111e_tx_queue_avail(struct amd8111e_priv* lp )
 {
 	int tx_index = lp->tx_idx & TX_BUFF_MOD_MASK;
-	if(lp->tx_skbuff[tx_index] != 0)
+	if (lp->tx_skbuff[tx_index])
 		return -1;
 	else
 		return 0;
@@ -1442,7 +1442,7 @@
 	lp->tx_dma_addr[tx_index] =
 	    pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
 	lp->tx_ring[tx_index].buff_phy_addr =
-	    (u32) cpu_to_le32(lp->tx_dma_addr[tx_index]);
+	    cpu_to_le32(lp->tx_dma_addr[tx_index]);
 
 	/*  Set FCS and LTINT bits */
 	wmb();
@@ -1935,6 +1935,7 @@
 	unsigned long reg_addr,reg_len;
 	struct amd8111e_priv* lp;
 	struct net_device* dev;
+	DECLARE_MAC_BUF(mac);
 
 	err = pci_enable_device(pdev);
 	if(err){
@@ -1983,7 +1984,6 @@
 		goto err_free_reg;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 #if AMD8111E_VLAN_TAG_USED
@@ -1999,7 +1999,7 @@
 	spin_lock_init(&lp->lock);
 
 	lp->mmio = ioremap(reg_addr, reg_len);
-	if (lp->mmio == 0) {
+	if (!lp->mmio) {
 		printk(KERN_ERR "amd8111e: Cannot map device registers, "
 		       "exiting\n");
 		err = -ENOMEM;
@@ -2008,7 +2008,7 @@
 
 	/* Initializing MAC address */
 	for(i = 0; i < ETH_ADDR_LEN; i++)
-			dev->dev_addr[i] =readb(lp->mmio + PADR + i);
+		dev->dev_addr[i] = readb(lp->mmio + PADR + i);
 
 	/* Setting user defined parametrs */
 	lp->ext_phy_option = speed_duplex[card_idx];
@@ -2031,8 +2031,7 @@
 	dev->tx_timeout = amd8111e_tx_timeout;
 	dev->watchdog_timeo = AMD8111E_TX_TIMEOUT;
 #ifdef CONFIG_AMD8111E_NAPI
-	dev->poll = amd8111e_rx_poll;
-	dev->weight = 32;
+	netif_napi_add(dev, &lp->napi, amd8111e_rx_poll, 32);
 #endif
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = amd8111e_poll;
@@ -2078,11 +2077,10 @@
 	/*  display driver and device information */
 
     	chip_version = (readl(lp->mmio + CHIPID) & 0xf0000000)>>28;
-    	printk(KERN_INFO "%s: AMD-8111e Driver Version: %s\n",								 dev->name,MODULE_VERS);
-    	printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet ",							dev->name, chip_version);
-    	for (i = 0; i < 6; i++)
-		printk("%2.2x%c",dev->dev_addr[i],i == 5 ? ' ' : ':');
-    	printk( "\n");
+	printk(KERN_INFO "%s: AMD-8111e Driver Version: %s\n",
+	       dev->name,MODULE_VERS);
+	printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet %s\n",
+	       dev->name, chip_version, print_mac(mac, dev->dev_addr));
 	if (lp->ext_phy_id)
 		printk(KERN_INFO "%s: Found MII PHY ID 0x%08x at address 0x%02x\n",
 		       dev->name, lp->ext_phy_id, lp->ext_phy_addr);
diff --git a/drivers/net/amd8111e.h b/drivers/net/amd8111e.h
index e65080a..28c60a7 100644
--- a/drivers/net/amd8111e.h
+++ b/drivers/net/amd8111e.h
@@ -655,32 +655,32 @@
 
 struct amd8111e_tx_dr{
 
-	u16 buff_count; /* Size of the buffer pointed by this descriptor */
+	__le16 buff_count; /* Size of the buffer pointed by this descriptor */
 
-	u16 tx_flags;
+	__le16 tx_flags;
 
-	u16 tag_ctrl_info;
+	__le16 tag_ctrl_info;
 
-	u16 tag_ctrl_cmd;
+	__le16 tag_ctrl_cmd;
 
-	u32 buff_phy_addr;
+	__le32 buff_phy_addr;
 
-	u32 reserved;
+	__le32 reserved;
 };
 
 struct amd8111e_rx_dr{
 
-	u32 reserved;
+	__le32 reserved;
 
-	u16 msg_count; /* Received message len */
+	__le16 msg_count; /* Received message len */
 
-	u16 tag_ctrl_info;
+	__le16 tag_ctrl_info;
 
-	u16 buff_count;  /* Len of the buffer pointed by descriptor. */
+	__le16 buff_count;  /* Len of the buffer pointed by descriptor. */
 
-	u16 rx_flags;
+	__le16 rx_flags;
 
-	u32 buff_phy_addr;
+	__le32 buff_phy_addr;
 
 };
 struct amd8111e_link_config{
@@ -763,6 +763,8 @@
 	/* Reg memory mapped address */
 	void __iomem *mmio;
 
+	struct napi_struct napi;
+
 	spinlock_t lock;	/* Guard lock */
 	unsigned long rx_idx, tx_idx;	/* The next free ring entry */
 	unsigned long tx_complete_idx;
diff --git a/drivers/net/apne.c b/drivers/net/apne.c
index 9541911..c12cbdf 100644
--- a/drivers/net/apne.c
+++ b/drivers/net/apne.c
@@ -148,7 +148,6 @@
 		sprintf(dev->name, "eth%d", unit);
 		netdev_boot_setup_check(dev);
 	}
-	SET_MODULE_OWNER(dev);
 
 	/* disable pcmcia irq for readtuple */
 	pcmcia_disable_irq();
@@ -205,6 +204,7 @@
     int neX000, ctron;
 #endif
     static unsigned version_printed;
+    DECLARE_MAC_BUF(mac);
 
     if (ei_debug  &&  version_printed++ == 0)
 	printk(version);
@@ -247,7 +247,7 @@
 	    {0x00,	NE_EN0_RSARHI},
 	    {E8390_RREAD+E8390_START, NE_CMD},
 	};
-	for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) {
+	for (i = 0; i < ARRAY_SIZE(program_seq); i++) {
 	    outb(program_seq[i].value, ioaddr + program_seq[i].offset);
 	}
 
@@ -317,12 +317,12 @@
     i = request_irq(dev->irq, apne_interrupt, IRQF_SHARED, DRV_NAME, dev);
     if (i) return i;
 
-    for(i = 0; i < ETHER_ADDR_LEN; i++) {
-	printk(" %2.2x", SA_prom[i]);
+    for(i = 0; i < ETHER_ADDR_LEN; i++)
 	dev->dev_addr[i] = SA_prom[i];
-    }
 
-    printk("\n%s: %s found.\n", dev->name, name);
+    printk(" %s\n", print_mac(mac, dev->dev_addr));
+
+    printk("%s: %s found.\n", dev->name, name);
 
     ei_status.name = name;
     ei_status.tx_start_page = start_page;
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index da6ffa8..92c3a4c 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -194,10 +194,6 @@
 static void cops_rx (struct net_device *dev);
 static int  cops_send_packet (struct sk_buff *skb, struct net_device *dev);
 static void set_multicast_list (struct net_device *dev);
-static int  cops_hard_header (struct sk_buff *skb, struct net_device *dev,
-			      unsigned short type, void *daddr, void *saddr, 
-			      unsigned len);
-
 static int  cops_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 static int  cops_close (struct net_device *dev);
 static struct net_device_stats *cops_get_stats (struct net_device *dev);
@@ -235,8 +231,6 @@
 		base_addr = dev->base_addr = io;
 	}
 
-	SET_MODULE_OWNER(dev);
-
 	if (base_addr > 0x1ff) {    /* Check a single specified location. */
 		err = cops_probe1(dev, base_addr);
 	} else if (base_addr != 0) { /* Don't probe at all. */
@@ -333,7 +327,6 @@
 	dev->base_addr = ioaddr;
 
         lp = netdev_priv(dev);
-        memset(lp, 0, sizeof(struct cops_local));
         spin_lock_init(&lp->lock);
 
 	/* Copy local board variable to lp struct. */
@@ -342,7 +335,7 @@
 	dev->hard_start_xmit    = cops_send_packet;
 	dev->tx_timeout		= cops_timeout;
 	dev->watchdog_timeo	= HZ * 2;
-	dev->hard_header	= cops_hard_header;
+
         dev->get_stats          = cops_get_stats;
 	dev->open               = cops_open;
         dev->stop               = cops_close;
@@ -947,19 +940,6 @@
 }
 
 /*
- *      Another Dummy function to keep the Appletalk layer happy.
- */
- 
-static int cops_hard_header(struct sk_buff *skb, struct net_device *dev,
-			    unsigned short type, void *daddr, void *saddr, 
-			    unsigned len)
-{
-        if(cops_debug >= 3)
-                printk("%s: cops_hard_header executed. Wow!\n", dev->name);
-        return 0;
-}
-
-/*
  *      System ioctls for the COPS LocalTalk card.
  */
  
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index f22e46d..1071144 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -65,7 +65,6 @@
 	if (!dev)
 		return ERR_PTR(-ENOMEM);
 
-	SET_MODULE_OWNER(dev);
 	strcpy(dev->name, "ipddp%d");
 
 	if (version_printed++ == 0)
@@ -117,7 +116,7 @@
  */
 static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	u32 paddr = ((struct rtable*)skb->dst)->rt_gateway;
+	__be32 paddr = ((struct rtable*)skb->dst)->rt_gateway;
         struct ddpehdr *ddp;
         struct ipddp_route *rt;
         struct atalk_addr *our_addr;
diff --git a/drivers/net/appletalk/ipddp.h b/drivers/net/appletalk/ipddp.h
index 52072fb..531519d 100644
--- a/drivers/net/appletalk/ipddp.h
+++ b/drivers/net/appletalk/ipddp.h
@@ -14,7 +14,7 @@
 struct ipddp_route
 {
         struct net_device *dev;             /* Carrier device */
-        __u32 ip;                       /* IP address */
+        __be32 ip;                       /* IP address */
         struct atalk_addr at;              /* Gateway appletalk address */
         int flags;
         struct ipddp_route *next;
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index 6a6cbd3..6ab2c2d 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -870,15 +870,6 @@
 	/* Actually netatalk needs fixing! */
 }
 
-static int ltpc_hard_header (struct sk_buff *skb, struct net_device *dev, 
-	unsigned short type, void *daddr, void *saddr, unsigned len)
-{
-	if(debug & DEBUG_VERBOSE)
-		printk("ltpc_hard_header called for device %s\n",
-			dev->name);
-	return 0;
-}
-
 static int ltpc_poll_counter;
 
 static void ltpc_poll(unsigned long l)
@@ -1046,8 +1037,6 @@
 	if (!dev)
 		goto out;
 
-	SET_MODULE_OWNER(dev);
-
 	/* probe for the I/O port address */
 	
 	if (io != 0x240 && request_region(0x220,8,"ltpc")) {
@@ -1143,7 +1132,6 @@
 
 	/* Fill in the fields of the device structure with ethernet-generic values. */
 	dev->hard_start_xmit = ltpc_xmit;
-	dev->hard_header = ltpc_hard_header;
 	dev->get_stats = ltpc_get_stats;
 
 	/* add the ltpc-specific things */
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index 681e20b..c59c806 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -102,8 +102,8 @@
 static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev);
 static void arcnet_timeout(struct net_device *dev);
 static int arcnet_header(struct sk_buff *skb, struct net_device *dev,
-			 unsigned short type, void *daddr, void *saddr,
-			 unsigned len);
+			 unsigned short type, const void *daddr,
+			 const void *saddr, unsigned len);
 static int arcnet_rebuild_header(struct sk_buff *skb);
 static struct net_device_stats *arcnet_get_stats(struct net_device *dev);
 static int go_tx(struct net_device *dev);
@@ -317,11 +317,17 @@
 	return mtu == 65535 ? XMTU : mtu;
 }
 
+static const struct header_ops arcnet_header_ops = {
+	.create = arcnet_header,
+	.rebuild = arcnet_rebuild_header,
+};
+
 
 /* Setup a struct device for ARCnet. */
 static void arcdev_setup(struct net_device *dev)
 {
 	dev->type = ARPHRD_ARCNET;
+	dev->header_ops = &arcnet_header_ops;
 	dev->hard_header_len = sizeof(struct archdr);
 	dev->mtu = choose_mtu();
 
@@ -342,8 +348,6 @@
 	dev->hard_start_xmit = arcnet_send_packet;
 	dev->tx_timeout = arcnet_timeout;
 	dev->get_stats = arcnet_get_stats;
-	dev->hard_header = arcnet_header;
-	dev->rebuild_header = arcnet_rebuild_header;
 }
 
 struct net_device *alloc_arcdev(char *name)
@@ -488,10 +492,10 @@
 
 
 static int arcnet_header(struct sk_buff *skb, struct net_device *dev,
-			 unsigned short type, void *daddr, void *saddr,
-			 unsigned len)
+			 unsigned short type, const void *daddr,
+			 const void *saddr, unsigned len)
 {
-	struct arcnet_local *lp = dev->priv;
+	const struct arcnet_local *lp = netdev_priv(dev);
 	uint8_t _daddr, proto_num;
 	struct ArcProto *proto;
 
diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c
index 1f03027..6599f10 100644
--- a/drivers/net/arcnet/com90io.c
+++ b/drivers/net/arcnet/com90io.c
@@ -398,8 +398,6 @@
 	if (!dev)
 		return -ENOMEM;
 
-	SET_MODULE_OWNER(dev);
-
 	dev->base_addr = io;
 	dev->irq = irq;
 	if (dev->irq == 2)
diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c
index 2de8877..dab185b 100644
--- a/drivers/net/arcnet/rfc1051.c
+++ b/drivers/net/arcnet/rfc1051.c
@@ -34,7 +34,7 @@
 #define VERSION "arcnet: RFC1051 \"simple standard\" (`s') encapsulation support loaded.\n"
 
 
-static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev);
+static __be16 type_trans(struct sk_buff *skb, struct net_device *dev);
 static void rx(struct net_device *dev, int bufnum,
 	       struct archdr *pkthdr, int length);
 static int build_header(struct sk_buff *skb, struct net_device *dev,
@@ -86,7 +86,7 @@
  * 
  * With ARCnet we have to convert everything to Ethernet-style stuff.
  */
-static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev)
+static __be16 type_trans(struct sk_buff *skb, struct net_device *dev)
 {
 	struct arcnet_local *lp = dev->priv;
 	struct archdr *pkt = (struct archdr *) skb->data;
diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c
index 460a095..6d6d95c 100644
--- a/drivers/net/arcnet/rfc1201.c
+++ b/drivers/net/arcnet/rfc1201.c
@@ -34,7 +34,7 @@
 #define VERSION "arcnet: RFC1201 \"standard\" (`a') encapsulation support loaded.\n"
 
 
-static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev);
+static __be16 type_trans(struct sk_buff *skb, struct net_device *dev);
 static void rx(struct net_device *dev, int bufnum,
 	       struct archdr *pkthdr, int length);
 static int build_header(struct sk_buff *skb, struct net_device *dev,
@@ -88,7 +88,7 @@
  * 
  * With ARCnet we have to convert everything to Ethernet-style stuff.
  */
-static unsigned short type_trans(struct sk_buff *skb, struct net_device *dev)
+static __be16 type_trans(struct sk_buff *skb, struct net_device *dev)
 {
 	struct archdr *pkt = (struct archdr *) skb->data;
 	struct arc_rfc1201 *soft = &pkt->soft.rfc1201;
@@ -456,7 +456,7 @@
 
 		excsoft.proto = soft->proto;
 		excsoft.split_flag = 0xff;
-		excsoft.sequence = 0xffff;
+		excsoft.sequence = htons(0xffff);
 
 		hard->offset[0] = 0;
 		ofs = 512 - softlen;
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index bc5a38a..3fa3bcc 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -166,6 +166,7 @@
     struct net_device *dev;
     struct ariadne_private *priv;
     int err;
+    DECLARE_MAC_BUF(mac);
 
     r1 = request_mem_region(base_addr, sizeof(struct Am79C960), "Am79C960");
     if (!r1)
@@ -183,7 +184,6 @@
 	return -ENOMEM;
     }
 
-    SET_MODULE_OWNER(dev);
     priv = netdev_priv(dev);
 
     r1->name = dev->name;
@@ -217,9 +217,8 @@
     zorro_set_drvdata(z, dev);
 
     printk(KERN_INFO "%s: Ariadne at 0x%08lx, Ethernet Address "
-	   "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, board,
-	   dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-	   dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+	   "%s\n", dev->name, board,
+	   print_mac(mac, dev->dev_addr));
 
     return 0;
 }
@@ -615,21 +614,17 @@
     /* Fill in a Tx ring entry */
 
 #if 0
-    printk(KERN_DEBUG "TX pkt type 0x%04x from ", ((u_short *)skb->data)[6]);
-    {
-	int i;
-	u_char *ptr = &((u_char *)skb->data)[6];
-	for (i = 0; i < 6; i++)
-	    printk("%02x", ptr[i]);
-    }
-    printk(" to ");
-    {
-	int i;
-	u_char *ptr = (u_char *)skb->data;
-	for (i = 0; i < 6; i++)
-	    printk("%02x", ptr[i]);
-    }
-    printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len);
+{
+    DECLARE_MAC_BUF(mac);
+    DECLARE_MAC_BUF(mac2);
+
+    printk(KERN_DEBUG "TX pkt type 0x%04x from %s to %s "
+	   " data 0x%08x len %d\n",
+	   ((u_short *)skb->data)[6],
+	   print_mac(mac, ((const u8 *)skb->data)+6),
+	   print_mac(mac, (const u8 *)skb->data),
+	   (int)skb->data, (int)skb->len);
+}
 #endif
 
     local_irq_save(flags);
@@ -749,22 +744,22 @@
 	    skb_copy_to_linear_data(skb, (char *)priv->rx_buff[entry], pkt_len);
 	    skb->protocol=eth_type_trans(skb,dev);
 #if 0
+{
+	    DECLARE_MAC_BUF(mac);
+
 	    printk(KERN_DEBUG "RX pkt type 0x%04x from ",
 		   ((u_short *)skb->data)[6]);
 	    {
-		int i;
 		u_char *ptr = &((u_char *)skb->data)[6];
-		for (i = 0; i < 6; i++)
-		    printk("%02x", ptr[i]);
+		printk("%s", print_mac(mac, ptr));
 	    }
 	    printk(" to ");
 	    {
-		int i;
 		u_char *ptr = (u_char *)skb->data;
-		for (i = 0; i < 6; i++)
-		    printk("%02x", ptr[i]);
+		printk("%s", print_mac(mac, ptr));
 	    }
 	    printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len);
+}
 #endif
 
 	    netif_rx(skb);
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index 2143eeb..ba6bd03 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -414,7 +414,7 @@
 	/*
 	 * Update the multicast hash table
 	 */
-	for (i = 0; i < sizeof(multi_hash) / sizeof(multi_hash[0]); i++)
+	for (i = 0; i < ARRAY_SIZE(multi_hash); i++)
 		write_rreg(dev->base_addr, i + LADRL, multi_hash[i]);
 
 	/*
@@ -741,12 +741,10 @@
 
 	ret = register_netdev(dev);
 	if (ret == 0) {
-		printk(KERN_INFO "%s: ether address ", dev->name);
+		DECLARE_MAC_BUF(mac);
 
-		/* Retrive and print the ethernet address. */
-		for (i = 0; i < 6; i++)
-			printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
-
+		printk(KERN_INFO "%s: ether address %s\n",
+		       dev->name, print_mac(mac, dev->dev_addr));
 		return 0;
 	}
 
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index ef2cc80..25b114a 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -485,6 +485,7 @@
 static int set_mac_address(struct net_device *dev, void* addr)
 {
 	struct sockaddr *address = addr;
+	DECLARE_MAC_BUF(mac);
 
 	if (!is_valid_ether_addr(address->sa_data))
 		return -EADDRNOTAVAIL;
@@ -492,9 +493,8 @@
 	memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
 	update_mac_address(dev);
 
-	printk("%s: Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
-		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+	printk("%s: Setting MAC address to %s\n", dev->name,
+	       print_mac(mac, dev->dev_addr));
 
 	return 0;
 }
@@ -979,6 +979,7 @@
 	struct at91_private *lp;
 	unsigned int val;
 	int res;
+	DECLARE_MAC_BUF(mac);
 
 	dev = alloc_etherdev(sizeof(struct at91_private));
 	if (!dev)
@@ -986,7 +987,6 @@
 
 	dev->base_addr = AT91_VA_BASE_EMAC;
 	dev->irq = AT91RM9200_ID_EMAC;
-	SET_MODULE_OWNER(dev);
 
 	/* Install the interrupt handler */
 	if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) {
@@ -1082,12 +1082,11 @@
 	}
 
 	/* Display ethernet banner */
-	printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n",
-		dev->name, (uint) dev->base_addr, dev->irq,
-		at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
-		at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
-		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+	printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%s)\n",
+	       dev->name, (uint) dev->base_addr, dev->irq,
+	       at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-",
+	       at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex",
+	       print_mac(mac, dev->dev_addr));
 	if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID))
 		printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
 	else if (phy_type == MII_LXT971A_ID)
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
index f6ece1d..7f016f3 100644
--- a/drivers/net/arm/ep93xx_eth.c
+++ b/drivers/net/arm/ep93xx_eth.c
@@ -169,6 +169,9 @@
 	spinlock_t		tx_pending_lock;
 	unsigned int		tx_pending;
 
+	struct net_device	*dev;
+	struct napi_struct	napi;
+
 	struct net_device_stats	stats;
 
 	struct mii_if_info	mii;
@@ -190,15 +193,11 @@
 	return &(ep->stats);
 }
 
-static int ep93xx_rx(struct net_device *dev, int *budget)
+static int ep93xx_rx(struct net_device *dev, int processed, int budget)
 {
 	struct ep93xx_priv *ep = netdev_priv(dev);
-	int rx_done;
-	int processed;
 
-	rx_done = 0;
-	processed = 0;
-	while (*budget > 0) {
+	while (processed < budget) {
 		int entry;
 		struct ep93xx_rstat *rstat;
 		u32 rstat0;
@@ -211,10 +210,8 @@
 
 		rstat0 = rstat->rstat0;
 		rstat1 = rstat->rstat1;
-		if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP)) {
-			rx_done = 1;
+		if (!(rstat0 & RSTAT0_RFP) || !(rstat1 & RSTAT1_RFP))
 			break;
-		}
 
 		rstat->rstat0 = 0;
 		rstat->rstat1 = 0;
@@ -275,8 +272,6 @@
 err:
 		ep->rx_pointer = (entry + 1) & (RX_QUEUE_ENTRIES - 1);
 		processed++;
-		dev->quota--;
-		(*budget)--;
 	}
 
 	if (processed) {
@@ -284,7 +279,7 @@
 		wrw(ep, REG_RXSTSENQ, processed);
 	}
 
-	return !rx_done;
+	return processed;
 }
 
 static int ep93xx_have_more_rx(struct ep93xx_priv *ep)
@@ -293,36 +288,32 @@
 	return !!((rstat->rstat0 & RSTAT0_RFP) && (rstat->rstat1 & RSTAT1_RFP));
 }
 
-static int ep93xx_poll(struct net_device *dev, int *budget)
+static int ep93xx_poll(struct napi_struct *napi, int budget)
 {
-	struct ep93xx_priv *ep = netdev_priv(dev);
-
-	/*
-	 * @@@ Have to stop polling if device is downed while we
-	 * are polling.
-	 */
+	struct ep93xx_priv *ep = container_of(napi, struct ep93xx_priv, napi);
+	struct net_device *dev = ep->dev;
+	int rx = 0;
 
 poll_some_more:
-	if (ep93xx_rx(dev, budget))
-		return 1;
+	rx = ep93xx_rx(dev, rx, budget);
+	if (rx < budget) {
+		int more = 0;
 
-	netif_rx_complete(dev);
-
-	spin_lock_irq(&ep->rx_lock);
-	wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX);
-	if (ep93xx_have_more_rx(ep)) {
-		wrl(ep, REG_INTEN, REG_INTEN_TX);
-		wrl(ep, REG_INTSTSP, REG_INTSTS_RX);
+		spin_lock_irq(&ep->rx_lock);
+		__netif_rx_complete(dev, napi);
+		wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX);
+		if (ep93xx_have_more_rx(ep)) {
+			wrl(ep, REG_INTEN, REG_INTEN_TX);
+			wrl(ep, REG_INTSTSP, REG_INTSTS_RX);
+			more = 1;
+		}
 		spin_unlock_irq(&ep->rx_lock);
 
-		if (netif_rx_reschedule(dev, 0))
+		if (more && netif_rx_reschedule(dev, napi))
 			goto poll_some_more;
-
-		return 0;
 	}
-	spin_unlock_irq(&ep->rx_lock);
 
-	return 0;
+	return rx;
 }
 
 static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -426,9 +417,9 @@
 
 	if (status & REG_INTSTS_RX) {
 		spin_lock(&ep->rx_lock);
-		if (likely(__netif_rx_schedule_prep(dev))) {
+		if (likely(__netif_rx_schedule_prep(dev, &ep->napi))) {
 			wrl(ep, REG_INTEN, REG_INTEN_TX);
-			__netif_rx_schedule(dev);
+			__netif_rx_schedule(dev, &ep->napi);
 		}
 		spin_unlock(&ep->rx_lock);
 	}
@@ -648,7 +639,10 @@
 			dev->dev_addr[4], dev->dev_addr[5]);
 	}
 
+	napi_enable(&ep->napi);
+
 	if (ep93xx_start_hw(dev)) {
+		napi_disable(&ep->napi);
 		ep93xx_free_buffers(ep);
 		return -EIO;
 	}
@@ -662,6 +656,7 @@
 
 	err = request_irq(ep->irq, ep93xx_irq, IRQF_SHARED, dev->name, dev);
 	if (err) {
+		napi_disable(&ep->napi);
 		ep93xx_stop_hw(dev);
 		ep93xx_free_buffers(ep);
 		return err;
@@ -678,6 +673,7 @@
 {
 	struct ep93xx_priv *ep = netdev_priv(dev);
 
+	napi_disable(&ep->napi);
 	netif_stop_queue(dev);
 
 	wrl(ep, REG_GIINTMSK, 0);
@@ -788,14 +784,12 @@
 
 	dev->get_stats = ep93xx_get_stats;
 	dev->ethtool_ops = &ep93xx_ethtool_ops;
-	dev->poll = ep93xx_poll;
 	dev->hard_start_xmit = ep93xx_xmit;
 	dev->open = ep93xx_open;
 	dev->stop = ep93xx_close;
 	dev->do_ioctl = ep93xx_ioctl;
 
 	dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
-	dev->weight = 64;
 
 	return dev;
 }
@@ -847,6 +841,8 @@
 		goto err_out;
 	}
 	ep = netdev_priv(dev);
+	ep->dev = dev;
+	netif_napi_add(dev, &ep->napi, ep93xx_poll, 64);
 
 	platform_set_drvdata(pdev, dev);
 
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
index f21148e..3bb9e29 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -36,7 +36,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
@@ -75,7 +74,7 @@
 
 /* ------------------------------------------------------------------------- */
 
-static char version[] __initdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
+static char version[] __devinitdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
 
 #define BUS_16 16
 #define BUS_8  8
@@ -997,6 +996,7 @@
 {
 	struct net_device *dev;
 	int i, ret = 0;
+	DECLARE_MAC_BUF(mac);
 
 	ether1_banner();
 
@@ -1010,7 +1010,6 @@
 		goto release;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &ec->dev);
 
 	dev->irq = ec->irq;
@@ -1045,12 +1044,9 @@
 	if (ret)
 		goto free;
 
-	printk(KERN_INFO "%s: ether1 in slot %d, ",
-		dev->name, ec->slot_no);
+	printk(KERN_INFO "%s: ether1 in slot %d, %s\n",
+		dev->name, ec->slot_no, print_mac(mac, dev->dev_addr));
     
-	for (i = 0; i < 6; i++)
-		printk ("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
-
 	ecard_set_drvdata(ec, dev);
 	return 0;
 
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
index da71350..67e96ae 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -51,7 +51,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
@@ -69,7 +68,7 @@
 #include <asm/ecard.h>
 #include <asm/io.h>
 
-static char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n";
+static char version[] __devinitdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n";
 
 #include "ether3.h"
 
@@ -464,7 +463,7 @@
 	if (dev->flags & IFF_PROMISC) {
 		/* promiscuous mode */
 		priv(dev)->regs.config1 |= CFG1_RECVPROMISC;
-	} else if (dev->flags & IFF_ALLMULTI) {
+	} else if (dev->flags & IFF_ALLMULTI || dev->mc_count) {
 		priv(dev)->regs.config1 |= CFG1_RECVSPECBRMULTI;
 	} else
 		priv(dev)->regs.config1 |= CFG1_RECVSPECBROAD;
@@ -776,7 +775,8 @@
 {
 	const struct ether3_data *data = id->data;
 	struct net_device *dev;
-	int i, bus_type, ret;
+	int bus_type, ret;
+	DECLARE_MAC_BUF(mac);
 
 	ether3_banner();
 
@@ -790,7 +790,6 @@
 		goto release;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &ec->dev);
 
 	priv(dev)->base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0);
@@ -860,9 +859,8 @@
 	if (ret)
 		goto free;
 
-	printk("%s: %s in slot %d, ", dev->name, data->name, ec->slot_no);
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+	printk("%s: %s in slot %d, %s\n",
+	       dev->name, data->name, ec->slot_no, print_mac(mac, dev->dev_addr));
 
 	ecard_set_drvdata(ec, dev);
 	return 0;
diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c
index 769ba69..00081d2 100644
--- a/drivers/net/arm/etherh.c
+++ b/drivers/net/arm/etherh.c
@@ -31,7 +31,6 @@
 #include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
-#include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
 #include <linux/slab.h>
@@ -649,6 +648,7 @@
 	struct net_device *dev;
 	struct etherh_priv *eh;
 	int i, ret;
+	DECLARE_MAC_BUF(mac);
 
 	etherh_banner();
 
@@ -662,7 +662,6 @@
 		goto release;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &ec->dev);
 
 	dev->open		= etherh_open;
@@ -747,11 +746,8 @@
 	if (ret)
 		goto free;
 
-	printk(KERN_INFO "%s: %s in slot %d, ",
-		dev->name, data->name, ec->slot_no);
-
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+	printk(KERN_INFO "%s: %s in slot %d, %s\n",
+		dev->name, data->name, ec->slot_no, print_mac(mac, dev->dev_addr));
 
 	ecard_set_drvdata(ec, dev);
 
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index bed8e0eb..b032c1b 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -109,7 +109,6 @@
 
 /* Information that need to be kept for each board. */
 struct net_local {
-	struct net_device_stats stats;
 	spinlock_t lock;
 	unsigned char mc_filter[8];
 	uint jumpered:1;			/* Set iff the board has jumper config. */
@@ -164,7 +163,6 @@
 static irqreturn_t net_interrupt(int irq, void *dev_id);
 static void net_rx(struct net_device *dev);
 static int net_close(struct net_device *dev);
-static struct net_device_stats *net_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
 static void net_tx_timeout (struct net_device *dev);
 
@@ -225,8 +223,6 @@
 		dev->irq = irq;
 	}
 
-	SET_MODULE_OWNER(dev);
-
 	if (io > 0x1ff) {	/* Check a single specified location. */
 		err = at1700_probe1(dev, io);
 	} else if (io != 0) {	/* Don't probe at all. */
@@ -269,6 +265,7 @@
 	unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0;
 	int slot, ret = -ENODEV;
 	struct net_local *lp = netdev_priv(dev);
+	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, AT1700_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -392,16 +389,15 @@
 	if (is_at1700) {
 		for(i = 0; i < 3; i++) {
 			unsigned short eeprom_val = read_eeprom(ioaddr, 4+i);
-			printk("%04x", eeprom_val);
 			((unsigned short *)dev->dev_addr)[i] = ntohs(eeprom_val);
 		}
 	} else {
 		for(i = 0; i < 6; i++) {
 			unsigned char val = inb(ioaddr + SAPROM + i);
-			printk("%02x", val);
 			dev->dev_addr[i] = val;
 		}
 	}
+	printk("%s", print_mac(mac, dev->dev_addr));
 
 	/* The EEPROM word 12 bit 0x0400 means use regular 100 ohm 10baseT signals,
 	   rather than 150 ohm shielded twisted pair compensation.
@@ -458,7 +454,6 @@
 	dev->open		= net_open;
 	dev->stop		= net_close;
 	dev->hard_start_xmit = net_send_packet;
-	dev->get_stats	= net_get_stats;
 	dev->set_multicast_list = &set_rx_mode;
 	dev->tx_timeout = net_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
@@ -573,7 +568,7 @@
 	 dev->name, inw(ioaddr + TX_STATUS), inw(ioaddr + TX_INTR), inw(ioaddr + TX_MODE),
 		inw(ioaddr + CONFIG_0), inw(ioaddr + DATAPORT), inw(ioaddr + TX_START),
 		inw(ioaddr + MODE13 - 1), inw(ioaddr + RX_CTRL));
-	lp->stats.tx_errors++;
+	dev->stats.tx_errors++;
 	/* ToDo: We should try to restart the adaptor... */
 	outw(0xffff, ioaddr + MODE24);
 	outw (0xffff, ioaddr + TX_STATUS);
@@ -693,10 +688,10 @@
 				printk("%s: 16 Collision occur during Txing.\n", dev->name);
 			/* Cancel sending a packet. */
 			outb(0x03, ioaddr + COL16CNTL);
-			lp->stats.collisions++;
+			dev->stats.collisions++;
 		}
 		if (status & 0x82) {
-			lp->stats.tx_packets++;
+			dev->stats.tx_packets++;
 			/* The Tx queue has any packets and is not being
 			   transferred a packet from the host, start
 			   transmitting. */
@@ -721,7 +716,6 @@
 static void
 net_rx(struct net_device *dev)
 {
-	struct net_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	int boguscount = 5;
 
@@ -740,11 +734,11 @@
 #endif
 
 		if ((status & 0xF0) != 0x20) {	/* There was an error. */
-			lp->stats.rx_errors++;
-			if (status & 0x08) lp->stats.rx_length_errors++;
-			if (status & 0x04) lp->stats.rx_frame_errors++;
-			if (status & 0x02) lp->stats.rx_crc_errors++;
-			if (status & 0x01) lp->stats.rx_over_errors++;
+			dev->stats.rx_errors++;
+			if (status & 0x08) dev->stats.rx_length_errors++;
+			if (status & 0x04) dev->stats.rx_frame_errors++;
+			if (status & 0x02) dev->stats.rx_crc_errors++;
+			if (status & 0x01) dev->stats.rx_over_errors++;
 		} else {
 			/* Malloc up new buffer. */
 			struct sk_buff *skb;
@@ -755,7 +749,7 @@
 				/* Prime the FIFO and then flush the packet. */
 				inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
 				outb(0x05, ioaddr + RX_CTRL);
-				lp->stats.rx_errors++;
+				dev->stats.rx_errors++;
 				break;
 			}
 			skb = dev_alloc_skb(pkt_len+3);
@@ -765,7 +759,7 @@
 				/* Prime the FIFO and then flush the packet. */
 				inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);
 				outb(0x05, ioaddr + RX_CTRL);
-				lp->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 				break;
 			}
 			skb_reserve(skb,2);
@@ -774,8 +768,8 @@
 			skb->protocol=eth_type_trans(skb, dev);
 			netif_rx(skb);
 			dev->last_rx = jiffies;
-			lp->stats.rx_packets++;
-			lp->stats.rx_bytes += pkt_len;
+			dev->stats.rx_packets++;
+			dev->stats.rx_bytes += pkt_len;
 		}
 		if (--boguscount <= 0)
 			break;
@@ -824,17 +818,6 @@
 	return 0;
 }
 
-/* Get the current statistics.
-   This may be called with the card open or closed.
-   There are no on-chip counters, so this function is trivial.
-*/
-static struct net_device_stats *
-net_get_stats(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	return &lp->stats;
-}
-
 /*
   Set the multicast/promiscuous mode for this adaptor.
 */
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index dfa8b9b..ebf1a3a 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -224,7 +224,6 @@
 	int			dirty_tx;		/* Ring entries to be freed. */
 				/* copy function */
 	void			*(*memcpy_f)( void *, const void *, size_t );
-	struct net_device_stats stats;
 /* This must be long for set_bit() */
 	long			tx_full;
 	spinlock_t		devlock;
@@ -263,7 +262,7 @@
 									   (highest byte stripped) */
 };
 
-#define	N_LANCE_ADDR	(sizeof(lance_addr_list)/sizeof(*lance_addr_list))
+#define	N_LANCE_ADDR	ARRAY_SIZE(lance_addr_list)
 
 
 /* Definitions for the Lance */
@@ -347,7 +346,6 @@
 static irqreturn_t lance_interrupt( int irq, void *dev_id );
 static int lance_rx( struct net_device *dev );
 static int lance_close( struct net_device *dev );
-static struct net_device_stats *lance_get_stats( struct net_device *dev );
 static void set_multicast_list( struct net_device *dev );
 static int lance_set_mac_address( struct net_device *dev, void *addr );
 static void lance_tx_timeout (struct net_device *dev);
@@ -390,7 +388,6 @@
 		sprintf(dev->name, "eth%d", unit);
 		netdev_boot_setup_check(dev);
 	}
-	SET_MODULE_OWNER(dev);
 
 	for( i = 0; i < N_LANCE_ADDR; ++i ) {
 		if (lance_probe1( dev, &lance_addr_list[i] )) {
@@ -470,6 +467,7 @@
 	int 					i;
 	static int 				did_version;
 	unsigned short			save1, save2;
+	DECLARE_MAC_BUF(mac);
 
 	PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n",
 				  (long)memaddr, (long)ioaddr ));
@@ -598,8 +596,7 @@
 		i = IO->mem;
 		break;
 	}
-	for( i = 0; i < 6; ++i )
-		printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" );
+	printk("%s\n", print_mac(mac, dev->dev_addr));
 	if (lp->cardtype == OLD_RIEBL) {
 		printk( "%s: Warning: This is a default ethernet address!\n",
 				dev->name );
@@ -632,7 +629,6 @@
 	dev->open = &lance_open;
 	dev->hard_start_xmit = &lance_start_xmit;
 	dev->stop = &lance_close;
-	dev->get_stats = &lance_get_stats;
 	dev->set_multicast_list = &set_multicast_list;
 	dev->set_mac_address = &lance_set_mac_address;
 
@@ -640,13 +636,6 @@
 	dev->tx_timeout = lance_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
-
-#if 0
-	dev->start = 0;
-#endif
-
-	memset( &lp->stats, 0, sizeof(lp->stats) );
-
 	return( 1 );
 }
 
@@ -754,7 +743,7 @@
 	 * little endian mode.
 	 */
 	REGA( CSR3 ) = CSR3_BSWP | (lp->cardtype == PAM_CARD ? CSR3_ACON : 0);
-	lp->stats.tx_errors++;
+	dev->stats.tx_errors++;
 #ifndef final_version
 		{	int i;
 			DPRINTK( 2, ( "Ring data: dirty_tx %d cur_tx %d%s cur_rx %d\n",
@@ -790,6 +779,8 @@
 	int entry, len;
 	struct lance_tx_head *head;
 	unsigned long flags;
+	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mac2);
 
 	DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n",
 				  dev->name, DREG ));
@@ -812,17 +803,13 @@
 
 	/* Fill in a Tx ring entry */
 	if (lance_debug >= 3) {
-		u_char *p;
-		int i;
-		printk( "%s: TX pkt type 0x%04x from ", dev->name,
-				((u_short *)skb->data)[6]);
-		for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ )
-			printk("%02x%s", *p++, i != 5 ? ":" : "" );
-		printk(" to ");
-		for( p = (u_char *)skb->data, i = 0; i < 6; i++ )
-			printk("%02x%s", *p++, i != 5 ? ":" : "" );
-		printk(" data at 0x%08x len %d\n", (int)skb->data,
-			   (int)skb->len );
+		printk( "%s: TX pkt type 0x%04x from "
+				"%s to %s"
+				" data at 0x%08x len %d\n",
+				dev->name, ((u_short *)skb->data)[6],
+				print_mac(mac, &skb->data[6]),
+				print_mac(mac2, skb->data),
+				(int)skb->data, (int)skb->len );
 	}
 
 	/* We're not prepared for the int until the last flags are set/reset. And
@@ -842,7 +829,7 @@
 	head->misc = 0;
 	lp->memcpy_f( PKTBUF_ADDR(head), (void *)skb->data, skb->len );
 	head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
-	lp->stats.tx_bytes += skb->len;
+	dev->stats.tx_bytes += skb->len;
 	dev_kfree_skb( skb );
 	lp->cur_tx++;
 	while( lp->cur_tx >= TX_RING_SIZE && lp->dirty_tx >= TX_RING_SIZE ) {
@@ -913,13 +900,13 @@
 				if (status & TMD1_ERR) {
 					/* There was an major error, log it. */
 					int err_status = MEM->tx_head[entry].misc;
-					lp->stats.tx_errors++;
-					if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
-					if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
-					if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++;
+					dev->stats.tx_errors++;
+					if (err_status & TMD3_RTRY) dev->stats.tx_aborted_errors++;
+					if (err_status & TMD3_LCAR) dev->stats.tx_carrier_errors++;
+					if (err_status & TMD3_LCOL) dev->stats.tx_window_errors++;
 					if (err_status & TMD3_UFLO) {
 						/* Ackk!  On FIFO errors the Tx unit is turned off! */
-						lp->stats.tx_fifo_errors++;
+						dev->stats.tx_fifo_errors++;
 						/* Remove this verbosity later! */
 						DPRINTK( 1, ( "%s: Tx FIFO error! Status %04x\n",
 									  dev->name, csr0 ));
@@ -928,8 +915,8 @@
 					}
 				} else {
 					if (status & (TMD1_MORE | TMD1_ONE | TMD1_DEF))
-						lp->stats.collisions++;
-					lp->stats.tx_packets++;
+						dev->stats.collisions++;
+					dev->stats.tx_packets++;
 				}
 
 				/* XXX MSch: free skb?? */
@@ -956,8 +943,8 @@
 		}
 
 		/* Log misc errors. */
-		if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */
-		if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */
+		if (csr0 & CSR0_BABL) dev->stats.tx_errors++; /* Tx babble. */
+		if (csr0 & CSR0_MISS) dev->stats.rx_errors++; /* Missed a Rx frame. */
 		if (csr0 & CSR0_MERR) {
 			DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), "
 						  "status %04x.\n", dev->name, csr0 ));
@@ -998,11 +985,11 @@
 			   buffers it's possible for a jabber packet to use two
 			   buffers, with only the last correctly noting the error. */
 			if (status & RMD1_ENP)	/* Only count a general error at the */
-				lp->stats.rx_errors++; /* end of a packet.*/
-			if (status & RMD1_FRAM) lp->stats.rx_frame_errors++;
-			if (status & RMD1_OFLO) lp->stats.rx_over_errors++;
-			if (status & RMD1_CRC) lp->stats.rx_crc_errors++;
-			if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++;
+				dev->stats.rx_errors++; /* end of a packet.*/
+			if (status & RMD1_FRAM) dev->stats.rx_frame_errors++;
+			if (status & RMD1_OFLO) dev->stats.rx_over_errors++;
+			if (status & RMD1_CRC) dev->stats.rx_crc_errors++;
+			if (status & RMD1_BUFF) dev->stats.rx_fifo_errors++;
 			head->flag &= (RMD1_ENP|RMD1_STP);
 		} else {
 			/* Malloc up new buffer, compatible with net-3. */
@@ -1011,7 +998,7 @@
 
 			if (pkt_len < 60) {
 				printk( "%s: Runt packet!\n", dev->name );
-				lp->stats.rx_errors++;
+				dev->stats.rx_errors++;
 			}
 			else {
 				skb = dev_alloc_skb( pkt_len+2 );
@@ -1024,7 +1011,7 @@
 							break;
 
 					if (i > RX_RING_SIZE - 2) {
-						lp->stats.rx_dropped++;
+						dev->stats.rx_dropped++;
 						head->flag |= RMD1_OWN_CHIP;
 						lp->cur_rx++;
 					}
@@ -1032,19 +1019,18 @@
 				}
 
 				if (lance_debug >= 3) {
-					u_char *data = PKTBUF_ADDR(head), *p;
-					printk( "%s: RX pkt type 0x%04x from ", dev->name,
-							((u_short *)data)[6]);
-					for( p = &data[6], i = 0; i < 6; i++ )
-						printk("%02x%s", *p++, i != 5 ? ":" : "" );
-					printk(" to ");
-					for( p = data, i = 0; i < 6; i++ )
-						printk("%02x%s", *p++, i != 5 ? ":" : "" );
-					printk(" data %02x %02x %02x %02x %02x %02x %02x %02x "
+					u_char *data = PKTBUF_ADDR(head);
+					DECLARE_MAC_BUF(mac);
+					DECLARE_MAC_BUF(mac2);
+
+					printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %s to %s ",
+						   "data %02x %02x %02x %02x %02x %02x %02x %02x "
 						   "len %d\n",
+						   dev->name, ((u_short *)data)[6],
+						   print_mac(mac, &data[6]), print_mac(mac2, data),
 						   data[15], data[16], data[17], data[18],
 						   data[19], data[20], data[21], data[22],
-						   pkt_len );
+						   pkt_len);
 				}
 
 				skb_reserve( skb, 2 );	/* 16 byte align */
@@ -1053,8 +1039,8 @@
 				skb->protocol = eth_type_trans( skb, dev );
 				netif_rx( skb );
 				dev->last_rx = jiffies;
-				lp->stats.rx_packets++;
-				lp->stats.rx_bytes += pkt_len;
+				dev->stats.rx_packets++;
+				dev->stats.rx_bytes += pkt_len;
 			}
 		}
 
@@ -1091,14 +1077,6 @@
 }
 
 
-static struct net_device_stats *lance_get_stats( struct net_device *dev )
-
-{	struct lance_private *lp = (struct lance_private *)dev->priv;
-
-	return &lp->stats;
-}
-
-
 /* Set or clear the multicast filter for this adaptor.
    num_addrs == -1		Promiscuous mode, receive all packets
    num_addrs == 0		Normal mode, clear multicast list
diff --git a/drivers/net/atl1/atl1_ethtool.c b/drivers/net/atl1/atl1_ethtool.c
index 1f616c5..68a83be8 100644
--- a/drivers/net/atl1/atl1_ethtool.c
+++ b/drivers/net/atl1/atl1_ethtool.c
@@ -88,9 +88,14 @@
 
 }
 
-static int atl1_get_stats_count(struct net_device *netdev)
+static int atl1_get_sset_count(struct net_device *netdev, int sset)
 {
-	return ARRAY_SIZE(atl1_gstrings_stats);
+	switch (sset) {
+	case ETH_SS_STATS:
+		return ARRAY_SIZE(atl1_gstrings_stats);
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static int atl1_get_settings(struct net_device *netdev,
@@ -489,15 +494,12 @@
 	.get_pauseparam		= atl1_get_pauseparam,
 	.set_pauseparam 	= atl1_set_pauseparam,
 	.get_rx_csum		= atl1_get_rx_csum,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
 	.set_tx_csum		= ethtool_op_set_tx_hw_csum,
 	.get_link		= ethtool_op_get_link,
-	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
 	.get_strings		= atl1_get_strings,
 	.nway_reset		= atl1_nway_reset,
 	.get_ethtool_stats	= atl1_get_ethtool_stats,
-	.get_stats_count	= atl1_get_stats_count,
-	.get_tso		= ethtool_op_get_tso,
+	.get_sset_count		= atl1_get_sset_count,
 	.set_tso		= ethtool_op_set_tso,
 };
diff --git a/drivers/net/atl1/atl1_hw.c b/drivers/net/atl1/atl1_hw.c
index ef886bd..9d3bd22 100644
--- a/drivers/net/atl1/atl1_hw.c
+++ b/drivers/net/atl1/atl1_hw.c
@@ -603,7 +603,7 @@
 
 static void atl1_init_flash_opcode(struct atl1_hw *hw)
 {
-	if (hw->flash_vendor >= sizeof(flash_table) / sizeof(flash_table[0]))
+	if (hw->flash_vendor >= ARRAY_SIZE(flash_table))
 		hw->flash_vendor = 0;	/* ATMEL */
 
 	/* Init OP table */
diff --git a/drivers/net/atl1/atl1_hw.h b/drivers/net/atl1/atl1_hw.h
index 100c09c..939aa0f 100644
--- a/drivers/net/atl1/atl1_hw.h
+++ b/drivers/net/atl1/atl1_hw.h
@@ -680,11 +680,6 @@
 #define AUTONEG_ADVERTISE_10_100_ALL	0x000F	/* All 10/100 speeds */
 #define AUTONEG_ADVERTISE_10_ALL	0x0003	/* 10Mbps Full & Half speeds */
 
-/* The size (in bytes) of a ethernet packet */
-#define ENET_HEADER_SIZE		14
-#define MAXIMUM_ETHERNET_FRAME_SIZE	1518	/* with FCS */
-#define MINIMUM_ETHERNET_FRAME_SIZE	64	/* with FCS */
-#define ETHERNET_FCS_SIZE		4
 #define MAX_JUMBO_FRAME_SIZE		0x2800
 
 #define PHY_AUTO_NEG_TIME	45	/* 4.5 Seconds */
@@ -929,8 +924,8 @@
 	atl1_dma_req_128 = 0,
 	atl1_dma_req_256 = 1,
 	atl1_dma_req_512 = 2,
-	atl1_dam_req_1024 = 3,
-	atl1_dam_req_2048 = 4,
+	atl1_dma_req_1024 = 3,
+	atl1_dma_req_2048 = 4,
 	atl1_dma_req_4096 = 5
 };
 
diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c
index fd1e156..35b0a7d 100644
--- a/drivers/net/atl1/atl1_main.c
+++ b/drivers/net/atl1/atl1_main.c
@@ -59,6 +59,7 @@
 #include <linux/skbuff.h>
 #include <linux/etherdevice.h>
 #include <linux/if_vlan.h>
+#include <linux/if_ether.h>
 #include <linux/irqreturn.h>
 #include <linux/workqueue.h>
 #include <linux/timer.h>
@@ -75,7 +76,6 @@
 #include <linux/compiler.h>
 #include <linux/delay.h>
 #include <linux/mii.h>
-#include <linux/interrupt.h>
 #include <net/checksum.h>
 
 #include <asm/atomic.h>
@@ -120,8 +120,8 @@
 	struct atl1_hw *hw = &adapter->hw;
 	struct net_device *netdev = adapter->netdev;
 
-	hw->max_frame_size = netdev->mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
-	hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
+	hw->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+	hw->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
 
 	adapter->wol = 0;
 	adapter->rx_buffer_len = (hw->max_frame_size + 7) & ~7;
@@ -314,7 +314,7 @@
 	return -ENOMEM;
 }
 
-void atl1_init_ring_ptrs(struct atl1_adapter *adapter)
+static void atl1_init_ring_ptrs(struct atl1_adapter *adapter)
 {
 	struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
 	struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
@@ -688,9 +688,9 @@
 {
 	struct atl1_adapter *adapter = netdev_priv(netdev);
 	int old_mtu = netdev->mtu;
-	int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+	int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
 
-	if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
+	if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) ||
 	    (max_frame > MAX_JUMBO_FRAME_SIZE)) {
 		dev_warn(&adapter->pdev->dev, "invalid MTU setting\n");
 		return -EINVAL;
@@ -908,8 +908,8 @@
 	/* config DMA Engine */
 	value = ((((u32) hw->dmar_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
 		<< DMA_CTRL_DMAR_BURST_LEN_SHIFT) |
-		((((u32) hw->dmaw_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
-		<< DMA_CTRL_DMAR_BURST_LEN_SHIFT) | DMA_CTRL_DMAR_EN |
+		((((u32) hw->dmaw_block) & DMA_CTRL_DMAW_BURST_LEN_MASK)
+		<< DMA_CTRL_DMAW_BURST_LEN_SHIFT) | DMA_CTRL_DMAR_EN |
 		DMA_CTRL_DMAW_EN;
 	value |= (u32) hw->dma_ord;
 	if (atl1_rcb_128 == hw->rcb_value)
@@ -917,7 +917,10 @@
 	iowrite32(value, hw->hw_addr + REG_DMA_CTRL);
 
 	/* config CMB / SMB */
-	value = hw->cmb_rrd | ((u32) hw->cmb_tpd << 16);
+	value = (hw->cmb_tpd > adapter->tpd_ring.count) ?
+		hw->cmb_tpd : adapter->tpd_ring.count;
+	value <<= 16;
+	value |= hw->cmb_rrd;
 	iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TH);
 	value = hw->cmb_rx_timer | ((u32) hw->cmb_tx_timer << 16);
 	iowrite32(value, hw->hw_addr + REG_CMB_WRITE_TIMER);
@@ -1334,7 +1337,7 @@
 		skb = buffer_info->skb;
 		length = le16_to_cpu(rrd->xsz.xsum_sz.pkt_size);
 
-		skb_put(skb, length - ETHERNET_FCS_SIZE);
+		skb_put(skb, length - ETH_FCS_LEN);
 
 		/* Receive Checksum Offload */
 		atl1_rx_checksum(adapter, rrd, skb);
@@ -1364,7 +1367,6 @@
 	if (count) {
 		u32 tpd_next_to_use;
 		u32 rfd_next_to_use;
-		u32 rrd_next_to_clean;
 
 		spin_lock(&adapter->mb_lock);
 
@@ -1422,7 +1424,7 @@
 		netif_wake_queue(adapter->netdev);
 }
 
-static u16 tpd_avail(struct atl1_tpd_ring *tpd_ring)
+static u16 atl1_tpd_avail(struct atl1_tpd_ring *tpd_ring)
 {
 	u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean);
 	u16 next_to_use = atomic_read(&tpd_ring->next_to_use);
@@ -1453,7 +1455,7 @@
 			tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
 				iph->daddr, 0, IPPROTO_TCP, 0);
 			ipofst = skb_network_offset(skb);
-			if (ipofst != ENET_HEADER_SIZE) /* 802.3 frame */
+			if (ipofst != ETH_HLEN) /* 802.3 frame */
 				tso->tsopl |= 1 << TSO_PARAM_ETHTYPE_SHIFT;
 
 			tso->tsopl |= (iph->ihl &
@@ -1509,7 +1511,7 @@
 	unsigned int f;
 	u16 tpd_next_to_use;
 	u16 proto_hdr_len;
-	u16 i, m, len12;
+	u16 len12;
 
 	first_buf_len -= skb->data_len;
 	nr_frags = skb_shinfo(skb)->nr_frags;
@@ -1533,6 +1535,8 @@
 			tpd_next_to_use = 0;
 
 		if (first_buf_len > proto_hdr_len) {
+			int i, m;
+
 			len12 = first_buf_len - proto_hdr_len;
 			m = (len12 + ATL1_MAX_TX_BUF_LEN - 1) /
 				ATL1_MAX_TX_BUF_LEN;
@@ -1700,15 +1704,13 @@
 		}
 	}
 
-	local_irq_save(flags);
-	if (!spin_trylock(&adapter->lock)) {
+	if (!spin_trylock_irqsave(&adapter->lock, flags)) {
 		/* Can't get lock - tell upper layer to requeue */
-		local_irq_restore(flags);
 		dev_printk(KERN_DEBUG, &adapter->pdev->dev, "tx locked\n");
 		return NETDEV_TX_LOCKED;
 	}
 
-	if (tpd_avail(&adapter->tpd_ring) < count) {
+	if (atl1_tpd_avail(&adapter->tpd_ring) < count) {
 		/* not enough descriptors */
 		netif_stop_queue(netdev);
 		spin_unlock_irqrestore(&adapter->lock, flags);
@@ -2201,21 +2203,26 @@
 	struct net_device *netdev;
 	struct atl1_adapter *adapter;
 	static int cards_found = 0;
-	bool pci_using_64 = true;
 	int err;
 
 	err = pci_enable_device(pdev);
 	if (err)
 		return err;
 
-	err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+	/*
+	 * The atl1 chip can DMA to 64-bit addresses, but it uses a single
+	 * shared register for the high 32 bits, so only a single, aligned,
+	 * 4 GB physical address range can be used at a time.
+	 *
+	 * Supporting 64-bit DMA on this hardware is more trouble than it's
+	 * worth.  It is far easier to limit to 32-bit DMA than update
+	 * various kernel subsystems to support the mechanics required by a
+	 * fixed-high-32-bit system.
+	 */
+	err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 	if (err) {
-		err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
-		if (err) {
-			dev_err(&pdev->dev, "no usable DMA configuration\n");
-			goto err_dma;
-		}
-		pci_using_64 = false;
+		dev_err(&pdev->dev, "no usable DMA configuration\n");
+		goto err_dma;
 	}
 	/* Mark all PCI regions associated with PCI device
 	 * pdev as being reserved by owner atl1_driver_name
@@ -2234,7 +2241,6 @@
 		err = -ENOMEM;
 		goto err_alloc_etherdev;
 	}
-	SET_MODULE_OWNER(netdev);
 	SET_NETDEV_DEV(netdev, &pdev->dev);
 
 	pci_set_drvdata(pdev, netdev);
@@ -2280,7 +2286,6 @@
 
 	netdev->ethtool_ops = &atl1_ethtool_ops;
 	adapter->bd_number = cards_found;
-	adapter->pci_using_64 = pci_using_64;
 
 	/* setup the private structure */
 	err = atl1_sw_init(adapter);
@@ -2297,9 +2302,6 @@
 	 */
 	/* netdev->features |= NETIF_F_TSO; */
 
-	if (pci_using_64)
-		netdev->features |= NETIF_F_HIGHDMA;
-
 	netdev->features |= NETIF_F_LLTX;
 
 	/*
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index 82d78ff..62f09e5 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -171,7 +171,6 @@
 struct net_local {
     spinlock_t lock;
     struct net_device *next_module;
-    struct net_device_stats stats;
     struct timer_list timer;	/* Media selection timer. */
     long last_rx_time;		/* Last Rx, in jiffies, to handle Rx hang. */
     int saved_tx_size;
@@ -205,7 +204,6 @@
 static void net_rx(struct net_device *dev);
 static void read_block(long ioaddr, int length, unsigned char *buffer, int data_mode);
 static int net_close(struct net_device *dev);
-static struct net_device_stats *net_get_stats(struct net_device *dev);
 static void set_rx_mode_8002(struct net_device *dev);
 static void set_rx_mode_8012(struct net_device *dev);
 static void tx_timeout(struct net_device *dev);
@@ -250,6 +248,7 @@
 	struct net_local *lp;
 	int saved_ctrl_reg, status, i;
 	int res;
+	DECLARE_MAC_BUF(mac);
 
 	outb(0xff, ioaddr + PAR_DATA);
 	/* Save the original value of the Control register, in case we guessed
@@ -299,7 +298,6 @@
 	dev = alloc_etherdev(sizeof(struct net_local));
 	if (!dev)
 		return -ENOMEM;
-	SET_MODULE_OWNER(dev);
 
 	/* Find the IRQ used by triggering an interrupt. */
 	write_reg_byte(ioaddr, CMR2, 0x01);			/* No accept mode, IRQ out. */
@@ -325,10 +323,9 @@
 		printk(KERN_INFO "%s", version);
 #endif
 
-	printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, SAPROM "
-		   "%02X:%02X:%02X:%02X:%02X:%02X.\n", dev->name, dev->base_addr,
-		   dev->irq, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-		   dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+	printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, "
+	       "SAPROM %s.\n",
+	       dev->name, dev->base_addr, dev->irq, print_mac(mac, dev->dev_addr));
 
 	/* Reset the ethernet hardware and activate the printer pass-through. */
 	write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX);
@@ -349,7 +346,6 @@
 	dev->open		= net_open;
 	dev->stop		= net_close;
 	dev->hard_start_xmit	= atp_send_packet;
-	dev->get_stats		= net_get_stats;
 	dev->set_multicast_list =
 	  lp->chip_type == RTL8002 ? &set_rx_mode_8002 : &set_rx_mode_8012;
 	dev->tx_timeout		= tx_timeout;
@@ -539,18 +535,17 @@
 
 static void tx_timeout(struct net_device *dev)
 {
-	struct net_local *np = netdev_priv(dev);
 	long ioaddr = dev->base_addr;
 
 	printk(KERN_WARNING "%s: Transmit timed out, %s?\n", dev->name,
 		   inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem"
 		   :  "IRQ conflict");
-	np->stats.tx_errors++;
+	dev->stats.tx_errors++;
 	/* Try to restart the adapter. */
 	hardware_init(dev);
 	dev->trans_start = jiffies;
 	netif_wake_queue(dev);
-	np->stats.tx_errors++;
+	dev->stats.tx_errors++;
 }
 
 static int atp_send_packet(struct sk_buff *skb, struct net_device *dev)
@@ -630,7 +625,7 @@
 				/* We acknowledged the normal Rx interrupt, so if the interrupt
 				   is still outstanding we must have a Rx error. */
 				if (read_status & (CMR1_IRQ << 3)) { /* Overrun. */
-					lp->stats.rx_over_errors++;
+					dev->stats.rx_over_errors++;
 					/* Set to no-accept mode long enough to remove a packet. */
 					write_reg_high(ioaddr, CMR2, CMR2h_OFF);
 					net_rx(dev);
@@ -650,9 +645,9 @@
 			   and reinitialize the adapter. */
 			write_reg(ioaddr, ISR, ISR_TxErr + ISR_TxOK);
 			if (status & (ISR_TxErr<<3)) {
-				lp->stats.collisions++;
+				dev->stats.collisions++;
 				if (++lp->re_tx > 15) {
-					lp->stats.tx_aborted_errors++;
+					dev->stats.tx_aborted_errors++;
 					hardware_init(dev);
 					break;
 				}
@@ -661,7 +656,7 @@
 				write_reg(ioaddr, CMR1, CMR1_ReXmit + CMR1_Xmit);
 			} else {
 				/* Finish up the transmit. */
-				lp->stats.tx_packets++;
+				dev->stats.tx_packets++;
 				lp->pac_cnt_in_tx_buf--;
 				if ( lp->saved_tx_size) {
 					trigger_send(ioaddr, lp->saved_tx_size);
@@ -679,7 +674,7 @@
 					   "%ld jiffies status %02x  CMR1 %02x.\n", dev->name,
 					   num_tx_since_rx, jiffies - dev->last_rx, status,
 					   (read_nibble(ioaddr, CMR1) >> 3) & 15);
-			lp->stats.rx_missed_errors++;
+			dev->stats.rx_missed_errors++;
 			hardware_init(dev);
 			num_tx_since_rx = 0;
 			break;
@@ -736,13 +731,13 @@
 			struct net_local *lp = netdev_priv(atp_timed_dev);
 			write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);
 			if (i == 2)
-			  lp->stats.tx_errors++;
+			  dev->stats.tx_errors++;
 			else if (i == 3)
-			  lp->stats.tx_dropped++;
+			  dev->stats.tx_dropped++;
 			else if (i == 4)
-			  lp->stats.collisions++;
+			  dev->stats.collisions++;
 			else
-			  lp->stats.rx_errors++;
+			  dev->stats.rx_errors++;
 		  }
 #endif
 	}
@@ -766,14 +761,14 @@
 		printk(KERN_DEBUG " rx_count %04x %04x %04x %04x..", rx_head.pad,
 			   rx_head.rx_count, rx_head.rx_status, rx_head.cur_addr);
 	if ((rx_head.rx_status & 0x77) != 0x01) {
-		lp->stats.rx_errors++;
-		if (rx_head.rx_status & 0x0004) lp->stats.rx_frame_errors++;
-		else if (rx_head.rx_status & 0x0002) lp->stats.rx_crc_errors++;
+		dev->stats.rx_errors++;
+		if (rx_head.rx_status & 0x0004) dev->stats.rx_frame_errors++;
+		else if (rx_head.rx_status & 0x0002) dev->stats.rx_crc_errors++;
 		if (net_debug > 3)
 			printk(KERN_DEBUG "%s: Unknown ATP Rx error %04x.\n",
 				   dev->name, rx_head.rx_status);
 		if  (rx_head.rx_status & 0x0020) {
-			lp->stats.rx_fifo_errors++;
+			dev->stats.rx_fifo_errors++;
 			write_reg_high(ioaddr, CMR1, CMR1h_TxENABLE);
 			write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE);
 		} else if (rx_head.rx_status & 0x0050)
@@ -788,7 +783,7 @@
 		if (skb == NULL) {
 			printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n",
 				   dev->name);
-			lp->stats.rx_dropped++;
+			dev->stats.rx_dropped++;
 			goto done;
 		}
 
@@ -797,8 +792,8 @@
 		skb->protocol = eth_type_trans(skb, dev);
 		netif_rx(skb);
 		dev->last_rx = jiffies;
-		lp->stats.rx_packets++;
-		lp->stats.rx_bytes += pkt_len;
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += pkt_len;
 	}
  done:
 	write_reg(ioaddr, CMR1, CMR1_NextPkt);
@@ -850,15 +845,6 @@
 	return 0;
 }
 
-/* Get the current statistics.	This may be called with the card open or
-   closed. */
-static struct net_device_stats *
-net_get_stats(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-	return &lp->stats;
-}
-
 /*
  *	Set or clear the multicast filter for this adapter.
  */
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index e86b369..b46c5d8 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -90,7 +90,6 @@
 static irqreturn_t au1000_interrupt(int, void *);
 static void au1000_tx_timeout(struct net_device *);
 static void set_rx_mode(struct net_device *);
-static struct net_device_stats *au1000_get_stats(struct net_device *);
 static int au1000_ioctl(struct net_device *, struct ifreq *, int);
 static int mdio_read(struct net_device *, int, int);
 static void mdio_write(struct net_device *, int, int, u16);
@@ -772,7 +771,6 @@
 	dev->open = au1000_open;
 	dev->hard_start_xmit = au1000_tx;
 	dev->stop = au1000_close;
-	dev->get_stats = au1000_get_stats;
 	dev->set_multicast_list = &set_rx_mode;
 	dev->do_ioctl = &au1000_ioctl;
 	SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops);
@@ -1038,7 +1036,7 @@
 static void update_tx_stats(struct net_device *dev, u32 status)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
-	struct net_device_stats *ps = &aup->stats;
+	struct net_device_stats *ps = &dev->stats;
 
 	if (status & TX_FRAME_ABORTED) {
 		if (!aup->phy_dev || (DUPLEX_FULL == aup->phy_dev->duplex)) {
@@ -1094,7 +1092,7 @@
 static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
-	struct net_device_stats *ps = &aup->stats;
+	struct net_device_stats *ps = &dev->stats;
 	volatile tx_dma_t *ptxd;
 	u32 buff_stat;
 	db_dest_t *pDB;
@@ -1148,7 +1146,7 @@
 static inline void update_rx_stats(struct net_device *dev, u32 status)
 {
 	struct au1000_private *aup = (struct au1000_private *) dev->priv;
-	struct net_device_stats *ps = &aup->stats;
+	struct net_device_stats *ps = &dev->stats;
 
 	ps->rx_packets++;
 	if (status & RX_MCAST_FRAME)
@@ -1201,7 +1199,7 @@
 				printk(KERN_ERR
 				       "%s: Memory squeeze, dropping packet.\n",
 				       dev->name);
-				aup->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 				continue;
 			}
 			skb_reserve(skb, 2);	/* 16 byte IP header align */
@@ -1324,18 +1322,5 @@
 	return phy_mii_ioctl(aup->phy_dev, if_mii(rq), cmd);
 }
 
-static struct net_device_stats *au1000_get_stats(struct net_device *dev)
-{
-	struct au1000_private *aup = (struct au1000_private *) dev->priv;
-
-	if (au1000_debug > 4)
-		printk("%s: au1000_get_stats: dev=%p\n", dev->name, dev);
-
-	if (netif_device_present(dev)) {
-		return &aup->stats;
-	}
-	return 0;
-}
-
 module_init(au1000_init_module);
 module_exit(au1000_cleanup_module);
diff --git a/drivers/net/au1000_eth.h b/drivers/net/au1000_eth.h
index 52fe00d..f3baeaa 100644
--- a/drivers/net/au1000_eth.h
+++ b/drivers/net/au1000_eth.h
@@ -115,6 +115,5 @@
 	u32 vaddr;                /* virtual address of rx/tx buffers   */
 	dma_addr_t dma_addr;      /* dma address of rx/tx buffers       */
 
-	struct net_device_stats stats;
 	spinlock_t lock;       /* Serialise access to device */
 };
diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c
index 1d88236..9fe0517 100644
--- a/drivers/net/ax88796.c
+++ b/drivers/net/ax88796.c
@@ -24,6 +24,7 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
+#include <linux/eeprom_93cx6.h>
 
 #include <net/ax88796.h>
 
@@ -580,9 +581,39 @@
 	.set_settings		= ax_set_settings,
 	.nway_reset		= ax_nway_reset,
 	.get_link		= ax_get_link,
-	.get_perm_addr		= ethtool_op_get_perm_addr,
 };
 
+#ifdef CONFIG_AX88796_93CX6
+static void ax_eeprom_register_read(struct eeprom_93cx6 *eeprom)
+{
+	struct ei_device *ei_local = eeprom->data;
+	u8 reg = ei_inb(ei_local->mem + AX_MEMR);
+
+	eeprom->reg_data_in = reg & AX_MEMR_EEI;
+	eeprom->reg_data_out = reg & AX_MEMR_EEO; /* Input pin */
+	eeprom->reg_data_clock = reg & AX_MEMR_EECLK;
+	eeprom->reg_chip_select = reg & AX_MEMR_EECS;
+}
+
+static void ax_eeprom_register_write(struct eeprom_93cx6 *eeprom)
+{
+	struct ei_device *ei_local = eeprom->data;
+	u8 reg = ei_inb(ei_local->mem + AX_MEMR);
+
+	reg &= ~(AX_MEMR_EEI | AX_MEMR_EECLK | AX_MEMR_EECS);
+
+	if (eeprom->reg_data_in)
+		reg |= AX_MEMR_EEI;
+	if (eeprom->reg_data_clock)
+		reg |= AX_MEMR_EECLK;
+	if (eeprom->reg_chip_select)
+		reg |= AX_MEMR_EECS;
+
+	ei_outb(reg, ei_local->mem + AX_MEMR);
+	udelay(10);
+}
+#endif
+
 /* setup code */
 
 static void ax_initial_setup(struct net_device *dev, struct ei_device *ei_local)
@@ -641,6 +672,23 @@
 		memcpy(dev->dev_addr,  SA_prom, 6);
 	}
 
+#ifdef CONFIG_AX88796_93CX6
+	if (first_init && ax->plat->flags & AXFLG_HAS_93CX6) {
+		unsigned char mac_addr[6];
+		struct eeprom_93cx6 eeprom;
+
+		eeprom.data = ei_local;
+		eeprom.register_read = ax_eeprom_register_read;
+		eeprom.register_write = ax_eeprom_register_write;
+		eeprom.width = PCI_EEPROM_WIDTH_93C56;
+
+		eeprom_93cx6_multiread(&eeprom, 0,
+				       (__le16 __force *)mac_addr,
+				       sizeof(mac_addr) >> 1);
+
+		memcpy(dev->dev_addr,  mac_addr, 6);
+	}
+#endif
 	if (ax->plat->wordlength == 2) {
 		/* We must set the 8390 for word mode. */
 		ei_outb(ax->plat->dcr_val, ei_local->mem + EN0_DCFG);
@@ -819,11 +867,12 @@
 	}
 
 	ei_status.mem = ioremap(res->start, size);
-	dev->base_addr = (long)ei_status.mem;
+	dev->base_addr = (unsigned long)ei_status.mem;
 
 	if (ei_status.mem == NULL) {
-		dev_err(&pdev->dev, "Cannot ioremap area (%08zx,%08zx)\n",
-			res->start, res->end);
+		dev_err(&pdev->dev, "Cannot ioremap area (%08llx,%08llx)\n",
+			(unsigned long long)res->start,
+			(unsigned long long)res->end);
 
  		ret = -ENXIO;
 		goto exit_req;
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 96fb0ec..3d247f3 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -1,8 +1,11 @@
-/* b44.c: Broadcom 4400 device driver.
+/* b44.c: Broadcom 44xx/47xx Fast Ethernet device driver.
  *
  * Copyright (C) 2002 David S. Miller (davem@redhat.com)
- * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
+ * Copyright (C) 2004 Pekka Pietikainen (pp@ee.oulu.fi)
+ * Copyright (C) 2004 Florian Schirmer (jolt@tuxbox.org)
+ * Copyright (C) 2006 Felix Fietkau (nbd@openwrt.org)
  * Copyright (C) 2006 Broadcom Corporation.
+ * Copyright (C) 2007 Michael Buesch <mb@bu3sch.de>
  *
  * Distribute under GPL.
  */
@@ -21,17 +24,18 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/dma-mapping.h>
+#include <linux/ssb/ssb.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
+
 #include "b44.h"
 
 #define DRV_MODULE_NAME		"b44"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"1.01"
-#define DRV_MODULE_RELDATE	"Jun 16, 2006"
+#define DRV_MODULE_VERSION	"2.0"
 
 #define B44_DEF_MSG_ENABLE	  \
 	(NETIF_MSG_DRV		| \
@@ -85,10 +89,10 @@
 #define B44_ETHIPV4UDP_HLEN	42
 
 static char version[] __devinitdata =
-	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION "\n";
 
-MODULE_AUTHOR("Florian Schirmer, Pekka Pietikainen, David S. Miller");
-MODULE_DESCRIPTION("Broadcom 4400 10/100 PCI ethernet driver");
+MODULE_AUTHOR("Felix Fietkau, Florian Schirmer, Pekka Pietikainen, David S. Miller");
+MODULE_DESCRIPTION("Broadcom 44xx/47xx 10/100 PCI ethernet driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_MODULE_VERSION);
 
@@ -96,18 +100,28 @@
 module_param(b44_debug, int, 0);
 MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value");
 
-static struct pci_device_id b44_pci_tbl[] = {
-	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
-	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
-	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
-	{ }	/* terminate list with empty entry */
-};
 
+#ifdef CONFIG_B44_PCI
+static const struct pci_device_id b44_pci_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B0) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401B1) },
+	{ 0 } /* terminate list with empty entry */
+};
 MODULE_DEVICE_TABLE(pci, b44_pci_tbl);
 
+static struct pci_driver b44_pci_driver = {
+	.name		= DRV_MODULE_NAME,
+	.id_table	= b44_pci_tbl,
+};
+#endif /* CONFIG_B44_PCI */
+
+static const struct ssb_device_id b44_ssb_tbl[] = {
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET, SSB_ANY_REV),
+	SSB_DEVTABLE_END
+};
+MODULE_DEVICE_TABLE(ssb, b44_ssb_tbl);
+
 static void b44_halt(struct b44 *);
 static void b44_init_rings(struct b44 *);
 
@@ -119,6 +133,7 @@
 
 static int dma_desc_align_mask;
 static int dma_desc_sync_size;
+static int instance;
 
 static const char b44_gstrings[][ETH_GSTRING_LEN] = {
 #define _B44(x...)	# x,
@@ -126,35 +141,35 @@
 #undef _B44
 };
 
-static inline void b44_sync_dma_desc_for_device(struct pci_dev *pdev,
-                                                dma_addr_t dma_base,
-                                                unsigned long offset,
-                                                enum dma_data_direction dir)
+static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev,
+						dma_addr_t dma_base,
+						unsigned long offset,
+						enum dma_data_direction dir)
 {
-	dma_sync_single_range_for_device(&pdev->dev, dma_base,
-	                                 offset & dma_desc_align_mask,
-	                                 dma_desc_sync_size, dir);
+	dma_sync_single_range_for_device(sdev->dev, dma_base,
+					 offset & dma_desc_align_mask,
+					 dma_desc_sync_size, dir);
 }
 
-static inline void b44_sync_dma_desc_for_cpu(struct pci_dev *pdev,
-                                             dma_addr_t dma_base,
-                                             unsigned long offset,
-                                             enum dma_data_direction dir)
+static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
+					     dma_addr_t dma_base,
+					     unsigned long offset,
+					     enum dma_data_direction dir)
 {
-	dma_sync_single_range_for_cpu(&pdev->dev, dma_base,
-	                              offset & dma_desc_align_mask,
-	                              dma_desc_sync_size, dir);
+	dma_sync_single_range_for_cpu(sdev->dev, dma_base,
+				      offset & dma_desc_align_mask,
+				      dma_desc_sync_size, dir);
 }
 
 static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
 {
-	return readl(bp->regs + reg);
+	return ssb_read32(bp->sdev, reg);
 }
 
 static inline void bw32(const struct b44 *bp,
 			unsigned long reg, unsigned long val)
 {
-	writel(val, bp->regs + reg);
+	ssb_write32(bp->sdev, reg, val);
 }
 
 static int b44_wait_bit(struct b44 *bp, unsigned long reg,
@@ -182,117 +197,29 @@
 	return 0;
 }
 
-/* Sonics SiliconBackplane support routines.  ROFL, you should see all the
- * buzz words used on this company's website :-)
- *
- * All of these routines must be invoked with bp->lock held and
- * interrupts disabled.
- */
-
-#define SB_PCI_DMA             0x40000000      /* Client Mode PCI memory access space (1 GB) */
-#define BCM4400_PCI_CORE_ADDR  0x18002000      /* Address of PCI core on BCM4400 cards */
-
-static u32 ssb_get_core_rev(struct b44 *bp)
-{
-	return (br32(bp, B44_SBIDHIGH) & SBIDHIGH_RC_MASK);
-}
-
-static u32 ssb_pci_setup(struct b44 *bp, u32 cores)
-{
-	u32 bar_orig, pci_rev, val;
-
-	pci_read_config_dword(bp->pdev, SSB_BAR0_WIN, &bar_orig);
-	pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, BCM4400_PCI_CORE_ADDR);
-	pci_rev = ssb_get_core_rev(bp);
-
-	val = br32(bp, B44_SBINTVEC);
-	val |= cores;
-	bw32(bp, B44_SBINTVEC, val);
-
-	val = br32(bp, SSB_PCI_TRANS_2);
-	val |= SSB_PCI_PREF | SSB_PCI_BURST;
-	bw32(bp, SSB_PCI_TRANS_2, val);
-
-	pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, bar_orig);
-
-	return pci_rev;
-}
-
-static void ssb_core_disable(struct b44 *bp)
-{
-	if (br32(bp, B44_SBTMSLOW) & SBTMSLOW_RESET)
-		return;
-
-	bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK));
-	b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0);
-	b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1);
-	bw32(bp, B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK |
-			    SBTMSLOW_REJECT | SBTMSLOW_RESET));
-	br32(bp, B44_SBTMSLOW);
-	udelay(1);
-	bw32(bp, B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_RESET));
-	br32(bp, B44_SBTMSLOW);
-	udelay(1);
-}
-
-static void ssb_core_reset(struct b44 *bp)
+static inline void __b44_cam_read(struct b44 *bp, unsigned char *data, int index)
 {
 	u32 val;
 
-	ssb_core_disable(bp);
-	bw32(bp, B44_SBTMSLOW, (SBTMSLOW_RESET | SBTMSLOW_CLOCK | SBTMSLOW_FGC));
-	br32(bp, B44_SBTMSLOW);
-	udelay(1);
+	bw32(bp, B44_CAM_CTRL, (CAM_CTRL_READ |
+			    (index << CAM_CTRL_INDEX_SHIFT)));
 
-	/* Clear SERR if set, this is a hw bug workaround.  */
-	if (br32(bp, B44_SBTMSHIGH) & SBTMSHIGH_SERR)
-		bw32(bp, B44_SBTMSHIGH, 0);
+	b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);
 
-	val = br32(bp, B44_SBIMSTATE);
-	if (val & (SBIMSTATE_IBE | SBIMSTATE_TO))
-		bw32(bp, B44_SBIMSTATE, val & ~(SBIMSTATE_IBE | SBIMSTATE_TO));
+	val = br32(bp, B44_CAM_DATA_LO);
 
-	bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC));
-	br32(bp, B44_SBTMSLOW);
-	udelay(1);
+	data[2] = (val >> 24) & 0xFF;
+	data[3] = (val >> 16) & 0xFF;
+	data[4] = (val >> 8) & 0xFF;
+	data[5] = (val >> 0) & 0xFF;
 
-	bw32(bp, B44_SBTMSLOW, (SBTMSLOW_CLOCK));
-	br32(bp, B44_SBTMSLOW);
-	udelay(1);
+	val = br32(bp, B44_CAM_DATA_HI);
+
+	data[0] = (val >> 8) & 0xFF;
+	data[1] = (val >> 0) & 0xFF;
 }
 
-static int ssb_core_unit(struct b44 *bp)
-{
-#if 0
-	u32 val = br32(bp, B44_SBADMATCH0);
-	u32 base;
-
-	type = val & SBADMATCH0_TYPE_MASK;
-	switch (type) {
-	case 0:
-		base = val & SBADMATCH0_BS0_MASK;
-		break;
-
-	case 1:
-		base = val & SBADMATCH0_BS1_MASK;
-		break;
-
-	case 2:
-	default:
-		base = val & SBADMATCH0_BS2_MASK;
-		break;
-	};
-#endif
-	return 0;
-}
-
-static int ssb_is_core_up(struct b44 *bp)
-{
-	return ((br32(bp, B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK))
-		== SBTMSLOW_CLOCK);
-}
-
-static void __b44_cam_write(struct b44 *bp, unsigned char *data, int index)
+static inline void __b44_cam_write(struct b44 *bp, unsigned char *data, int index)
 {
 	u32 val;
 
@@ -328,14 +255,14 @@
 	bw32(bp, B44_IMASK, bp->imask);
 }
 
-static int b44_readphy(struct b44 *bp, int reg, u32 *val)
+static int __b44_readphy(struct b44 *bp, int phy_addr, int reg, u32 *val)
 {
 	int err;
 
 	bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
 	bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
 			     (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) |
-			     (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
+			     (phy_addr << MDIO_DATA_PMD_SHIFT) |
 			     (reg << MDIO_DATA_RA_SHIFT) |
 			     (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT)));
 	err = b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
@@ -344,29 +271,40 @@
 	return err;
 }
 
-static int b44_writephy(struct b44 *bp, int reg, u32 val)
+static int __b44_writephy(struct b44 *bp, int phy_addr, int reg, u32 val)
 {
 	bw32(bp, B44_EMAC_ISTAT, EMAC_INT_MII);
 	bw32(bp, B44_MDIO_DATA, (MDIO_DATA_SB_START |
 			     (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) |
-			     (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
+			     (phy_addr << MDIO_DATA_PMD_SHIFT) |
 			     (reg << MDIO_DATA_RA_SHIFT) |
 			     (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT) |
 			     (val & MDIO_DATA_DATA)));
 	return b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
 }
 
+static inline int b44_readphy(struct b44 *bp, int reg, u32 *val)
+{
+	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+		return 0;
+
+	return __b44_readphy(bp, bp->phy_addr, reg, val);
+}
+
+static inline int b44_writephy(struct b44 *bp, int reg, u32 val)
+{
+	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+		return 0;
+
+	return __b44_writephy(bp, bp->phy_addr, reg, val);
+}
+
 /* miilib interface */
-/* FIXME FIXME: phy_id is ignored, bp->phy_addr use is unconditional
- * due to code existing before miilib use was added to this driver.
- * Someone should remove this artificial driver limitation in
- * b44_{read,write}phy.  bp->phy_addr itself is fine (and needed).
- */
 static int b44_mii_read(struct net_device *dev, int phy_id, int location)
 {
 	u32 val;
 	struct b44 *bp = netdev_priv(dev);
-	int rc = b44_readphy(bp, location, &val);
+	int rc = __b44_readphy(bp, phy_id, location, &val);
 	if (rc)
 		return 0xffffffff;
 	return val;
@@ -376,7 +314,7 @@
 			 int val)
 {
 	struct b44 *bp = netdev_priv(dev);
-	b44_writephy(bp, location, val);
+	__b44_writephy(bp, phy_id, location, val);
 }
 
 static int b44_phy_reset(struct b44 *bp)
@@ -384,6 +322,8 @@
 	u32 val;
 	int err;
 
+	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+		return 0;
 	err = b44_writephy(bp, MII_BMCR, BMCR_RESET);
 	if (err)
 		return err;
@@ -442,11 +382,52 @@
 	__b44_set_flow_ctrl(bp, pause_enab);
 }
 
+#ifdef SSB_DRIVER_MIPS
+extern char *nvram_get(char *name);
+static void b44_wap54g10_workaround(struct b44 *bp)
+{
+	const char *str;
+	u32 val;
+	int err;
+
+	/*
+	 * workaround for bad hardware design in Linksys WAP54G v1.0
+	 * see https://dev.openwrt.org/ticket/146
+	 * check and reset bit "isolate"
+	 */
+	str = nvram_get("boardnum");
+	if (!str)
+		return;
+	if (simple_strtoul(str, NULL, 0) == 2) {
+		err = __b44_readphy(bp, 0, MII_BMCR, &val);
+		if (err)
+			goto error;
+		if (!(val & BMCR_ISOLATE))
+			return;
+		val &= ~BMCR_ISOLATE;
+		err = __b44_writephy(bp, 0, MII_BMCR, val);
+		if (err)
+			goto error;
+	}
+	return;
+error:
+	printk(KERN_WARNING PFX "PHY: cannot reset MII transceiver isolate bit.\n");
+}
+#else
+static inline void b44_wap54g10_workaround(struct b44 *bp)
+{
+}
+#endif
+
 static int b44_setup_phy(struct b44 *bp)
 {
 	u32 val;
 	int err;
 
+	b44_wap54g10_workaround(bp);
+
+	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+		return 0;
 	if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0)
 		goto out;
 	if ((err = b44_writephy(bp, B44_MII_ALEDCTRL,
@@ -542,6 +523,19 @@
 {
 	u32 bmsr, aux;
 
+	if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) {
+		bp->flags |= B44_FLAG_100_BASE_T;
+		bp->flags |= B44_FLAG_FULL_DUPLEX;
+		if (!netif_carrier_ok(bp->dev)) {
+			u32 val = br32(bp, B44_TX_CTRL);
+			val |= TX_CTRL_DUPLEX;
+			bw32(bp, B44_TX_CTRL, val);
+			netif_carrier_on(bp->dev);
+			b44_link_report(bp);
+		}
+		return;
+	}
+
 	if (!b44_readphy(bp, MII_BMSR, &bmsr) &&
 	    !b44_readphy(bp, B44_MII_AUXCTRL, &aux) &&
 	    (bmsr != 0xffff)) {
@@ -617,10 +611,10 @@
 
 		BUG_ON(skb == NULL);
 
-		pci_unmap_single(bp->pdev,
-				 pci_unmap_addr(rp, mapping),
+		dma_unmap_single(bp->sdev->dev,
+				 rp->mapping,
 				 skb->len,
-				 PCI_DMA_TODEVICE);
+				 DMA_TO_DEVICE);
 		rp->skb = NULL;
 		dev_kfree_skb_irq(skb);
 	}
@@ -657,9 +651,9 @@
 	if (skb == NULL)
 		return -ENOMEM;
 
-	mapping = pci_map_single(bp->pdev, skb->data,
+	mapping = dma_map_single(bp->sdev->dev, skb->data,
 				 RX_PKT_BUF_SZ,
-				 PCI_DMA_FROMDEVICE);
+				 DMA_FROM_DEVICE);
 
 	/* Hardware bug work-around, the chip is unable to do PCI DMA
 	   to/from anything above 1GB :-( */
@@ -667,18 +661,19 @@
 		mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
 		/* Sigh... */
 		if (!dma_mapping_error(mapping))
-			pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
+			dma_unmap_single(bp->sdev->dev, mapping,
+					RX_PKT_BUF_SZ, DMA_FROM_DEVICE);
 		dev_kfree_skb_any(skb);
 		skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
 		if (skb == NULL)
 			return -ENOMEM;
-		mapping = pci_map_single(bp->pdev, skb->data,
+		mapping = dma_map_single(bp->sdev->dev, skb->data,
 					 RX_PKT_BUF_SZ,
-					 PCI_DMA_FROMDEVICE);
+					 DMA_FROM_DEVICE);
 		if (dma_mapping_error(mapping) ||
 			mapping + RX_PKT_BUF_SZ > DMA_30BIT_MASK) {
 			if (!dma_mapping_error(mapping))
-				pci_unmap_single(bp->pdev, mapping, RX_PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
+				dma_unmap_single(bp->sdev->dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
 			dev_kfree_skb_any(skb);
 			return -ENOMEM;
 		}
@@ -691,7 +686,7 @@
 	rh->flags = 0;
 
 	map->skb = skb;
-	pci_unmap_addr_set(map, mapping, mapping);
+	map->mapping = mapping;
 
 	if (src_map != NULL)
 		src_map->skb = NULL;
@@ -705,9 +700,9 @@
 	dp->addr = cpu_to_le32((u32) mapping + RX_PKT_OFFSET + bp->dma_offset);
 
 	if (bp->flags & B44_FLAG_RX_RING_HACK)
-		b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
-		                             dest_idx * sizeof(dp),
-		                             DMA_BIDIRECTIONAL);
+		b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma,
+			                    dest_idx * sizeof(dp),
+			                    DMA_BIDIRECTIONAL);
 
 	return RX_PKT_BUF_SZ;
 }
@@ -730,13 +725,12 @@
 	rh = (struct rx_header *) src_map->skb->data;
 	rh->len = 0;
 	rh->flags = 0;
-	pci_unmap_addr_set(dest_map, mapping,
-			   pci_unmap_addr(src_map, mapping));
+	dest_map->mapping = src_map->mapping;
 
 	if (bp->flags & B44_FLAG_RX_RING_HACK)
-		b44_sync_dma_desc_for_cpu(bp->pdev, bp->rx_ring_dma,
-		                          src_idx * sizeof(src_desc),
-		                          DMA_BIDIRECTIONAL);
+		b44_sync_dma_desc_for_cpu(bp->sdev, bp->rx_ring_dma,
+			                 src_idx * sizeof(src_desc),
+			                 DMA_BIDIRECTIONAL);
 
 	ctrl = src_desc->ctrl;
 	if (dest_idx == (B44_RX_RING_SIZE - 1))
@@ -750,13 +744,13 @@
 	src_map->skb = NULL;
 
 	if (bp->flags & B44_FLAG_RX_RING_HACK)
-		b44_sync_dma_desc_for_device(bp->pdev, bp->rx_ring_dma,
-		                             dest_idx * sizeof(dest_desc),
-		                             DMA_BIDIRECTIONAL);
+		b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma,
+					     dest_idx * sizeof(dest_desc),
+					     DMA_BIDIRECTIONAL);
 
-	pci_dma_sync_single_for_device(bp->pdev, le32_to_cpu(src_desc->addr),
-				       RX_PKT_BUF_SZ,
-				       PCI_DMA_FROMDEVICE);
+	dma_sync_single_for_device(bp->sdev->dev, le32_to_cpu(src_desc->addr),
+				   RX_PKT_BUF_SZ,
+				   DMA_FROM_DEVICE);
 }
 
 static int b44_rx(struct b44 *bp, int budget)
@@ -772,13 +766,13 @@
 	while (cons != prod && budget > 0) {
 		struct ring_info *rp = &bp->rx_buffers[cons];
 		struct sk_buff *skb = rp->skb;
-		dma_addr_t map = pci_unmap_addr(rp, mapping);
+		dma_addr_t map = rp->mapping;
 		struct rx_header *rh;
 		u16 len;
 
-		pci_dma_sync_single_for_cpu(bp->pdev, map,
+		dma_sync_single_for_cpu(bp->sdev->dev, map,
 					    RX_PKT_BUF_SZ,
-					    PCI_DMA_FROMDEVICE);
+					    DMA_FROM_DEVICE);
 		rh = (struct rx_header *) skb->data;
 		len = le16_to_cpu(rh->len);
 		if ((len > (RX_PKT_BUF_SZ - RX_PKT_OFFSET)) ||
@@ -810,8 +804,8 @@
 			skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
 			if (skb_size < 0)
 				goto drop_it;
-			pci_unmap_single(bp->pdev, map,
-					 skb_size, PCI_DMA_FROMDEVICE);
+			dma_unmap_single(bp->sdev->dev, map,
+					 skb_size, DMA_FROM_DEVICE);
 			/* Leave out rx_header */
                 	skb_put(skb, len + RX_PKT_OFFSET);
             	        skb_pull(skb, RX_PKT_OFFSET);
@@ -848,10 +842,11 @@
 	return received;
 }
 
-static int b44_poll(struct net_device *netdev, int *budget)
+static int b44_poll(struct napi_struct *napi, int budget)
 {
-	struct b44 *bp = netdev_priv(netdev);
-	int done;
+	struct b44 *bp = container_of(napi, struct b44, napi);
+	struct net_device *netdev = bp->dev;
+	int work_done;
 
 	spin_lock_irq(&bp->lock);
 
@@ -862,22 +857,9 @@
 	}
 	spin_unlock_irq(&bp->lock);
 
-	done = 1;
-	if (bp->istat & ISTAT_RX) {
-		int orig_budget = *budget;
-		int work_done;
-
-		if (orig_budget > netdev->quota)
-			orig_budget = netdev->quota;
-
-		work_done = b44_rx(bp, orig_budget);
-
-		*budget -= work_done;
-		netdev->quota -= work_done;
-
-		if (work_done >= orig_budget)
-			done = 0;
-	}
+	work_done = 0;
+	if (bp->istat & ISTAT_RX)
+		work_done += b44_rx(bp, budget);
 
 	if (bp->istat & ISTAT_ERRORS) {
 		unsigned long flags;
@@ -888,15 +870,15 @@
 		b44_init_hw(bp, B44_FULL_RESET_SKIP_PHY);
 		netif_wake_queue(bp->dev);
 		spin_unlock_irqrestore(&bp->lock, flags);
-		done = 1;
+		work_done = 0;
 	}
 
-	if (done) {
-		netif_rx_complete(netdev);
+	if (work_done < budget) {
+		netif_rx_complete(netdev, napi);
 		b44_enable_ints(bp);
 	}
 
-	return (done ? 0 : 1);
+	return work_done;
 }
 
 static irqreturn_t b44_interrupt(int irq, void *dev_id)
@@ -924,13 +906,13 @@
 			goto irq_ack;
 		}
 
-		if (netif_rx_schedule_prep(dev)) {
+		if (netif_rx_schedule_prep(dev, &bp->napi)) {
 			/* NOTE: These writes are posted by the readback of
 			 *       the ISTAT register below.
 			 */
 			bp->istat = istat;
 			__b44_disable_ints(bp);
-			__netif_rx_schedule(dev);
+			__netif_rx_schedule(dev, &bp->napi);
 		} else {
 			printk(KERN_ERR PFX "%s: Error, poll already scheduled\n",
 			       dev->name);
@@ -982,24 +964,25 @@
 		goto err_out;
 	}
 
-	mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+	mapping = dma_map_single(bp->sdev->dev, skb->data, len, DMA_TO_DEVICE);
 	if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
 		struct sk_buff *bounce_skb;
 
 		/* Chip can't handle DMA to/from >1GB, use bounce buffer */
 		if (!dma_mapping_error(mapping))
-			pci_unmap_single(bp->pdev, mapping, len, PCI_DMA_TODEVICE);
+			dma_unmap_single(bp->sdev->dev, mapping, len,
+					DMA_TO_DEVICE);
 
 		bounce_skb = __dev_alloc_skb(len, GFP_ATOMIC | GFP_DMA);
 		if (!bounce_skb)
 			goto err_out;
 
-		mapping = pci_map_single(bp->pdev, bounce_skb->data,
-					 len, PCI_DMA_TODEVICE);
+		mapping = dma_map_single(bp->sdev->dev, bounce_skb->data,
+					 len, DMA_TO_DEVICE);
 		if (dma_mapping_error(mapping) || mapping + len > DMA_30BIT_MASK) {
 			if (!dma_mapping_error(mapping))
-				pci_unmap_single(bp->pdev, mapping,
-						 len, PCI_DMA_TODEVICE);
+				dma_unmap_single(bp->sdev->dev, mapping,
+					 len, DMA_TO_DEVICE);
 			dev_kfree_skb_any(bounce_skb);
 			goto err_out;
 		}
@@ -1011,7 +994,7 @@
 
 	entry = bp->tx_prod;
 	bp->tx_buffers[entry].skb = skb;
-	pci_unmap_addr_set(&bp->tx_buffers[entry], mapping, mapping);
+	bp->tx_buffers[entry].mapping = mapping;
 
 	ctrl  = (len & DESC_CTRL_LEN);
 	ctrl |= DESC_CTRL_IOC | DESC_CTRL_SOF | DESC_CTRL_EOF;
@@ -1022,9 +1005,9 @@
 	bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping+bp->dma_offset);
 
 	if (bp->flags & B44_FLAG_TX_RING_HACK)
-		b44_sync_dma_desc_for_device(bp->pdev, bp->tx_ring_dma,
-		                             entry * sizeof(bp->tx_ring[0]),
-		                             DMA_TO_DEVICE);
+		b44_sync_dma_desc_for_device(bp->sdev, bp->tx_ring_dma,
+			                    entry * sizeof(bp->tx_ring[0]),
+			                    DMA_TO_DEVICE);
 
 	entry = NEXT_TX(entry);
 
@@ -1097,10 +1080,8 @@
 
 		if (rp->skb == NULL)
 			continue;
-		pci_unmap_single(bp->pdev,
-				 pci_unmap_addr(rp, mapping),
-				 RX_PKT_BUF_SZ,
-				 PCI_DMA_FROMDEVICE);
+		dma_unmap_single(bp->sdev->dev, rp->mapping, RX_PKT_BUF_SZ,
+					DMA_FROM_DEVICE);
 		dev_kfree_skb_any(rp->skb);
 		rp->skb = NULL;
 	}
@@ -1111,10 +1092,8 @@
 
 		if (rp->skb == NULL)
 			continue;
-		pci_unmap_single(bp->pdev,
-				 pci_unmap_addr(rp, mapping),
-				 rp->skb->len,
-				 PCI_DMA_TODEVICE);
+		dma_unmap_single(bp->sdev->dev, rp->mapping, rp->skb->len,
+					DMA_TO_DEVICE);
 		dev_kfree_skb_any(rp->skb);
 		rp->skb = NULL;
 	}
@@ -1136,14 +1115,14 @@
 	memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
 
 	if (bp->flags & B44_FLAG_RX_RING_HACK)
-		dma_sync_single_for_device(&bp->pdev->dev, bp->rx_ring_dma,
-		                           DMA_TABLE_BYTES,
-		                           PCI_DMA_BIDIRECTIONAL);
+		dma_sync_single_for_device(bp->sdev->dev, bp->rx_ring_dma,
+			                  DMA_TABLE_BYTES,
+			                  DMA_BIDIRECTIONAL);
 
 	if (bp->flags & B44_FLAG_TX_RING_HACK)
-		dma_sync_single_for_device(&bp->pdev->dev, bp->tx_ring_dma,
-		                           DMA_TABLE_BYTES,
-		                           PCI_DMA_TODEVICE);
+		dma_sync_single_for_device(bp->sdev->dev, bp->tx_ring_dma,
+			                  DMA_TABLE_BYTES,
+			                  DMA_TO_DEVICE);
 
 	for (i = 0; i < bp->rx_pending; i++) {
 		if (b44_alloc_rx_skb(bp, -1, i) < 0)
@@ -1163,24 +1142,24 @@
 	bp->tx_buffers = NULL;
 	if (bp->rx_ring) {
 		if (bp->flags & B44_FLAG_RX_RING_HACK) {
-			dma_unmap_single(&bp->pdev->dev, bp->rx_ring_dma,
-				         DMA_TABLE_BYTES,
-				         DMA_BIDIRECTIONAL);
+			dma_unmap_single(bp->sdev->dev, bp->rx_ring_dma,
+					DMA_TABLE_BYTES,
+					DMA_BIDIRECTIONAL);
 			kfree(bp->rx_ring);
 		} else
-			pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
+			dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES,
 					    bp->rx_ring, bp->rx_ring_dma);
 		bp->rx_ring = NULL;
 		bp->flags &= ~B44_FLAG_RX_RING_HACK;
 	}
 	if (bp->tx_ring) {
 		if (bp->flags & B44_FLAG_TX_RING_HACK) {
-			dma_unmap_single(&bp->pdev->dev, bp->tx_ring_dma,
-				         DMA_TABLE_BYTES,
-				         DMA_TO_DEVICE);
+			dma_unmap_single(bp->sdev->dev, bp->tx_ring_dma,
+					DMA_TABLE_BYTES,
+					DMA_TO_DEVICE);
 			kfree(bp->tx_ring);
 		} else
-			pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
+			dma_free_coherent(bp->sdev->dev, DMA_TABLE_BYTES,
 					    bp->tx_ring, bp->tx_ring_dma);
 		bp->tx_ring = NULL;
 		bp->flags &= ~B44_FLAG_TX_RING_HACK;
@@ -1191,22 +1170,22 @@
  * Must not be invoked with interrupt sources disabled and
  * the hardware shutdown down.  Can sleep.
  */
-static int b44_alloc_consistent(struct b44 *bp)
+static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
 {
 	int size;
 
 	size  = B44_RX_RING_SIZE * sizeof(struct ring_info);
-	bp->rx_buffers = kzalloc(size, GFP_KERNEL);
+	bp->rx_buffers = kzalloc(size, gfp);
 	if (!bp->rx_buffers)
 		goto out_err;
 
 	size = B44_TX_RING_SIZE * sizeof(struct ring_info);
-	bp->tx_buffers = kzalloc(size, GFP_KERNEL);
+	bp->tx_buffers = kzalloc(size, gfp);
 	if (!bp->tx_buffers)
 		goto out_err;
 
 	size = DMA_TABLE_BYTES;
-	bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma);
+	bp->rx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->rx_ring_dma, gfp);
 	if (!bp->rx_ring) {
 		/* Allocation may have failed due to pci_alloc_consistent
 		   insisting on use of GFP_DMA, which is more restrictive
@@ -1214,13 +1193,13 @@
 		struct dma_desc *rx_ring;
 		dma_addr_t rx_ring_dma;
 
-		rx_ring = kzalloc(size, GFP_KERNEL);
+		rx_ring = kzalloc(size, gfp);
 		if (!rx_ring)
 			goto out_err;
 
-		rx_ring_dma = dma_map_single(&bp->pdev->dev, rx_ring,
-		                             DMA_TABLE_BYTES,
-		                             DMA_BIDIRECTIONAL);
+		rx_ring_dma = dma_map_single(bp->sdev->dev, rx_ring,
+			                    DMA_TABLE_BYTES,
+			                    DMA_BIDIRECTIONAL);
 
 		if (dma_mapping_error(rx_ring_dma) ||
 			rx_ring_dma + size > DMA_30BIT_MASK) {
@@ -1233,21 +1212,21 @@
 		bp->flags |= B44_FLAG_RX_RING_HACK;
 	}
 
-	bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma);
+	bp->tx_ring = dma_alloc_coherent(bp->sdev->dev, size, &bp->tx_ring_dma, gfp);
 	if (!bp->tx_ring) {
-		/* Allocation may have failed due to pci_alloc_consistent
+		/* Allocation may have failed due to dma_alloc_coherent
 		   insisting on use of GFP_DMA, which is more restrictive
 		   than necessary...  */
 		struct dma_desc *tx_ring;
 		dma_addr_t tx_ring_dma;
 
-		tx_ring = kzalloc(size, GFP_KERNEL);
+		tx_ring = kzalloc(size, gfp);
 		if (!tx_ring)
 			goto out_err;
 
-		tx_ring_dma = dma_map_single(&bp->pdev->dev, tx_ring,
-		                             DMA_TABLE_BYTES,
-		                             DMA_TO_DEVICE);
+		tx_ring_dma = dma_map_single(bp->sdev->dev, tx_ring,
+			                    DMA_TABLE_BYTES,
+			                    DMA_TO_DEVICE);
 
 		if (dma_mapping_error(tx_ring_dma) ||
 			tx_ring_dma + size > DMA_30BIT_MASK) {
@@ -1282,7 +1261,9 @@
 /* bp->lock is held. */
 static void b44_chip_reset(struct b44 *bp)
 {
-	if (ssb_is_core_up(bp)) {
+	struct ssb_device *sdev = bp->sdev;
+
+	if (ssb_device_is_enabled(bp->sdev)) {
 		bw32(bp, B44_RCV_LAZY, 0);
 		bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE);
 		b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1);
@@ -1294,19 +1275,25 @@
 		}
 		bw32(bp, B44_DMARX_CTRL, 0);
 		bp->rx_prod = bp->rx_cons = 0;
-	} else {
-		ssb_pci_setup(bp, (bp->core_unit == 0 ?
-				   SBINTVEC_ENET0 :
-				   SBINTVEC_ENET1));
-	}
+	} else
+		ssb_pcicore_dev_irqvecs_enable(&sdev->bus->pcicore, sdev);
 
-	ssb_core_reset(bp);
-
+	ssb_device_enable(bp->sdev, 0);
 	b44_clear_stats(bp);
 
-	/* Make PHY accessible. */
-	bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
-			     (0x0d & MDIO_CTRL_MAXF_MASK)));
+	switch (sdev->bus->bustype) {
+	case SSB_BUSTYPE_SSB:
+		bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
+		     (((ssb_clockspeed(sdev->bus) + (B44_MDC_RATIO / 2)) / B44_MDC_RATIO)
+		     & MDIO_CTRL_MAXF_MASK)));
+		break;
+	case SSB_BUSTYPE_PCI:
+	case SSB_BUSTYPE_PCMCIA:
+		bw32(bp, B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
+		     (0x0d & MDIO_CTRL_MAXF_MASK)));
+		break;
+	}
+
 	br32(bp, B44_MDIO_CTRL);
 
 	if (!(br32(bp, B44_DEVCTRL) & DEVCTRL_IPP)) {
@@ -1349,6 +1336,7 @@
 {
 	struct b44 *bp = netdev_priv(dev);
 	struct sockaddr *addr = p;
+	u32 val;
 
 	if (netif_running(dev))
 		return -EBUSY;
@@ -1359,7 +1347,11 @@
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 
 	spin_lock_irq(&bp->lock);
-	__b44_set_mac_addr(bp);
+
+	val = br32(bp, B44_RXCONFIG);
+	if (!(val & RXCONFIG_CAM_ABSENT))
+		__b44_set_mac_addr(bp);
+
 	spin_unlock_irq(&bp->lock);
 
 	return 0;
@@ -1416,10 +1408,12 @@
 	struct b44 *bp = netdev_priv(dev);
 	int err;
 
-	err = b44_alloc_consistent(bp);
+	err = b44_alloc_consistent(bp, GFP_KERNEL);
 	if (err)
 		goto out;
 
+	napi_enable(&bp->napi);
+
 	b44_init_rings(bp);
 	b44_init_hw(bp, B44_FULL_RESET);
 
@@ -1427,6 +1421,7 @@
 
 	err = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev);
 	if (unlikely(err < 0)) {
+		napi_disable(&bp->napi);
 		b44_chip_reset(bp);
 		b44_free_rings(bp);
 		b44_free_consistent(bp);
@@ -1445,18 +1440,6 @@
 	return err;
 }
 
-#if 0
-/*static*/ void b44_dump_state(struct b44 *bp)
-{
-	u32 val32, val32_2, val32_3, val32_4, val32_5;
-	u16 val16;
-
-	pci_read_config_word(bp->pdev, PCI_STATUS, &val16);
-	printk("DEBUG: PCI status [%04x] \n", val16);
-
-}
-#endif
-
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /*
  * Polling receive - used by netconsole and other diagnostic tools
@@ -1519,14 +1502,13 @@
 	u8 *pwol_pattern;
 	u8 pwol_mask[B44_PMASK_SIZE];
 
-	pwol_pattern = kmalloc(B44_PATTERN_SIZE, GFP_KERNEL);
+	pwol_pattern = kzalloc(B44_PATTERN_SIZE, GFP_KERNEL);
 	if (!pwol_pattern) {
 		printk(KERN_ERR PFX "Memory not available for WOL\n");
 		return;
 	}
 
 	/* Ipv4 magic packet pattern - pattern 0.*/
-	memset(pwol_pattern, 0, B44_PATTERN_SIZE);
 	memset(pwol_mask, 0, B44_PMASK_SIZE);
 	plen0 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
 				  B44_ETHIPV4UDP_HLEN);
@@ -1568,10 +1550,24 @@
 
 }
 
+#ifdef CONFIG_B44_PCI
+static void b44_setup_wol_pci(struct b44 *bp)
+{
+	u16 val;
+
+	if (bp->sdev->bus->bustype != SSB_BUSTYPE_SSB) {
+		bw32(bp, SSB_TMSLOW, br32(bp, SSB_TMSLOW) | SSB_TMSLOW_PE);
+		pci_read_config_word(bp->sdev->bus->host_pci, SSB_PMCSR, &val);
+		pci_write_config_word(bp->sdev->bus->host_pci, SSB_PMCSR, val | SSB_PE);
+	}
+}
+#else
+static inline void b44_setup_wol_pci(struct b44 *bp) { }
+#endif /* CONFIG_B44_PCI */
+
 static void b44_setup_wol(struct b44 *bp)
 {
 	u32 val;
-	u16 pmval;
 
 	bw32(bp, B44_RXCONFIG, RXCONFIG_ALLMULTI);
 
@@ -1595,13 +1591,7 @@
  	} else {
  		b44_setup_pseudo_magicp(bp);
  	}
-
-	val = br32(bp, B44_SBTMSLOW);
-	bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE);
-
-	pci_read_config_word(bp->pdev, SSB_PMCSR, &pmval);
-	pci_write_config_word(bp->pdev, SSB_PMCSR, pmval | SSB_PE);
-
+	b44_setup_wol_pci(bp);
 }
 
 static int b44_close(struct net_device *dev)
@@ -1610,15 +1600,12 @@
 
 	netif_stop_queue(dev);
 
-	netif_poll_disable(dev);
+	napi_disable(&bp->napi);
 
 	del_timer_sync(&bp->timer);
 
 	spin_lock_irq(&bp->lock);
 
-#if 0
-	b44_dump_state(bp);
-#endif
 	b44_halt(bp);
 	b44_free_rings(bp);
 	netif_carrier_off(dev);
@@ -1627,8 +1614,6 @@
 
 	free_irq(dev->irq, dev);
 
-	netif_poll_enable(dev);
-
 	if (bp->flags & B44_FLAG_WOL_ENABLE) {
 		b44_init_hw(bp, B44_PARTIAL_RESET);
 		b44_setup_wol(bp);
@@ -1701,7 +1686,7 @@
 
 	val = br32(bp, B44_RXCONFIG);
 	val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI);
-	if (dev->flags & IFF_PROMISC) {
+	if ((dev->flags & IFF_PROMISC) || (val & RXCONFIG_CAM_ABSENT)) {
 		val |= RXCONFIG_PROMISC;
 		bw32(bp, B44_RXCONFIG, val);
 	} else {
@@ -1749,11 +1734,19 @@
 static void b44_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info)
 {
 	struct b44 *bp = netdev_priv(dev);
-	struct pci_dev *pci_dev = bp->pdev;
+	struct ssb_bus *bus = bp->sdev->bus;
 
-	strcpy (info->driver, DRV_MODULE_NAME);
-	strcpy (info->version, DRV_MODULE_VERSION);
-	strcpy (info->bus_info, pci_name(pci_dev));
+	strncpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver));
+	strncpy(info->version, DRV_MODULE_VERSION, sizeof(info->driver));
+	switch (bus->bustype) {
+	case SSB_BUSTYPE_PCI:
+		strncpy(info->bus_info, pci_name(bus->host_pci), sizeof(info->bus_info));
+		break;
+	case SSB_BUSTYPE_PCMCIA:
+	case SSB_BUSTYPE_SSB:
+		strncpy(info->bus_info, "SSB", sizeof(info->bus_info));
+		break;
+	}
 }
 
 static int b44_nway_reset(struct net_device *dev)
@@ -1969,9 +1962,14 @@
 	}
 }
 
-static int b44_get_stats_count(struct net_device *dev)
+static int b44_get_sset_count(struct net_device *dev, int sset)
 {
-	return ARRAY_SIZE(b44_gstrings);
+	switch (sset) {
+	case ETH_SS_STATS:
+		return ARRAY_SIZE(b44_gstrings);
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void b44_get_ethtool_stats(struct net_device *dev,
@@ -2032,9 +2030,8 @@
 	.get_msglevel		= b44_get_msglevel,
 	.set_msglevel		= b44_set_msglevel,
 	.get_strings		= b44_get_strings,
-	.get_stats_count	= b44_get_stats_count,
+	.get_sset_count		= b44_get_sset_count,
 	.get_ethtool_stats	= b44_get_ethtool_stats,
-	.get_perm_addr		= ethtool_op_get_perm_addr,
 };
 
 static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -2053,33 +2050,23 @@
 	return err;
 }
 
-/* Read 128-bytes of EEPROM. */
-static int b44_read_eeprom(struct b44 *bp, u8 *data)
-{
-	long i;
-	__le16 *ptr = (__le16 *) data;
-
-	for (i = 0; i < 128; i += 2)
-		ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i));
-
-	return 0;
-}
-
 static int __devinit b44_get_invariants(struct b44 *bp)
 {
-	u8 eeprom[128];
-	int err;
+	struct ssb_device *sdev = bp->sdev;
+	int err = 0;
+	u8 *addr;
 
-	err = b44_read_eeprom(bp, &eeprom[0]);
-	if (err)
-		goto out;
+	bp->dma_offset = ssb_dma_translation(sdev);
 
-	bp->dev->dev_addr[0] = eeprom[79];
-	bp->dev->dev_addr[1] = eeprom[78];
-	bp->dev->dev_addr[2] = eeprom[81];
-	bp->dev->dev_addr[3] = eeprom[80];
-	bp->dev->dev_addr[4] = eeprom[83];
-	bp->dev->dev_addr[5] = eeprom[82];
+	if (sdev->bus->bustype == SSB_BUSTYPE_SSB &&
+	    instance > 1) {
+		addr = sdev->bus->sprom.r1.et1mac;
+		bp->phy_addr = sdev->bus->sprom.r1.et1phyaddr;
+	} else {
+		addr = sdev->bus->sprom.r1.et0mac;
+		bp->phy_addr = sdev->bus->sprom.r1.et0phyaddr;
+	}
+	memcpy(bp->dev->dev_addr, addr, 6);
 
 	if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){
 		printk(KERN_ERR PFX "Invalid MAC address found in EEPROM\n");
@@ -2088,103 +2075,53 @@
 
 	memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len);
 
-	bp->phy_addr = eeprom[90] & 0x1f;
-
 	bp->imask = IMASK_DEF;
 
-	bp->core_unit = ssb_core_unit(bp);
-	bp->dma_offset = SB_PCI_DMA;
-
 	/* XXX - really required?
 	   bp->flags |= B44_FLAG_BUGGY_TXPTR;
-         */
+	*/
 
- 	if (ssb_get_core_rev(bp) >= 7)
- 		bp->flags |= B44_FLAG_B0_ANDLATER;
+	if (bp->sdev->id.revision >= 7)
+		bp->flags |= B44_FLAG_B0_ANDLATER;
 
-out:
 	return err;
 }
 
-static int __devinit b44_init_one(struct pci_dev *pdev,
-				  const struct pci_device_id *ent)
+static int __devinit b44_init_one(struct ssb_device *sdev,
+				  const struct ssb_device_id *ent)
 {
 	static int b44_version_printed = 0;
-	unsigned long b44reg_base, b44reg_len;
 	struct net_device *dev;
 	struct b44 *bp;
-	int err, i;
+	int err;
+	DECLARE_MAC_BUF(mac);
+
+	instance++;
 
 	if (b44_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
 
-	err = pci_enable_device(pdev);
-	if (err) {
-		dev_err(&pdev->dev, "Cannot enable PCI device, "
-		       "aborting.\n");
-		return err;
-	}
-
-	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
-		dev_err(&pdev->dev,
-			"Cannot find proper PCI device "
-		       "base address, aborting.\n");
-		err = -ENODEV;
-		goto err_out_disable_pdev;
-	}
-
-	err = pci_request_regions(pdev, DRV_MODULE_NAME);
-	if (err) {
-		dev_err(&pdev->dev,
-			"Cannot obtain PCI resources, aborting.\n");
-		goto err_out_disable_pdev;
-	}
-
-	pci_set_master(pdev);
-
-	err = pci_set_dma_mask(pdev, (u64) DMA_30BIT_MASK);
-	if (err) {
-		dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
-		goto err_out_free_res;
-	}
-
-	err = pci_set_consistent_dma_mask(pdev, (u64) DMA_30BIT_MASK);
-	if (err) {
-		dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
-		goto err_out_free_res;
-	}
-
-	b44reg_base = pci_resource_start(pdev, 0);
-	b44reg_len = pci_resource_len(pdev, 0);
 
 	dev = alloc_etherdev(sizeof(*bp));
 	if (!dev) {
-		dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
+		dev_err(sdev->dev, "Etherdev alloc failed, aborting.\n");
 		err = -ENOMEM;
-		goto err_out_free_res;
+		goto out;
 	}
 
-	SET_MODULE_OWNER(dev);
-	SET_NETDEV_DEV(dev,&pdev->dev);
+	SET_NETDEV_DEV(dev, sdev->dev);
 
 	/* No interesting netdevice features in this card... */
 	dev->features |= 0;
 
 	bp = netdev_priv(dev);
-	bp->pdev = pdev;
+	bp->sdev = sdev;
 	bp->dev = dev;
 
 	bp->msg_enable = netif_msg_init(b44_debug, B44_DEF_MSG_ENABLE);
 
 	spin_lock_init(&bp->lock);
 
-	bp->regs = ioremap(b44reg_base, b44reg_len);
-	if (bp->regs == 0UL) {
-		dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
-		err = -ENOMEM;
-		goto err_out_free_dev;
-	}
-
 	bp->rx_pending = B44_DEF_RX_RING_PENDING;
 	bp->tx_pending = B44_DEF_TX_RING_PENDING;
 
@@ -2196,23 +2133,34 @@
 	dev->set_mac_address = b44_set_mac_addr;
 	dev->do_ioctl = b44_ioctl;
 	dev->tx_timeout = b44_tx_timeout;
-	dev->poll = b44_poll;
-	dev->weight = 64;
+	netif_napi_add(dev, &bp->napi, b44_poll, 64);
 	dev->watchdog_timeo = B44_TX_TIMEOUT;
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = b44_poll_controller;
 #endif
 	dev->change_mtu = b44_change_mtu;
-	dev->irq = pdev->irq;
+	dev->irq = sdev->irq;
 	SET_ETHTOOL_OPS(dev, &b44_ethtool_ops);
 
 	netif_carrier_off(dev);
 
+	err = ssb_bus_powerup(sdev->bus, 0);
+	if (err) {
+		dev_err(sdev->dev,
+			"Failed to powerup the bus\n");
+		goto err_out_free_dev;
+	}
+	err = ssb_dma_set_mask(sdev, DMA_30BIT_MASK);
+	if (err) {
+		dev_err(sdev->dev,
+			"Required 30BIT DMA mask unsupported by the system.\n");
+		goto err_out_powerdown;
+	}
 	err = b44_get_invariants(bp);
 	if (err) {
-		dev_err(&pdev->dev,
+		dev_err(sdev->dev,
 			"Problem fetching invariants of chip, aborting.\n");
-		goto err_out_iounmap;
+		goto err_out_powerdown;
 	}
 
 	bp->mii_if.dev = dev;
@@ -2231,61 +2179,49 @@
 
 	err = register_netdev(dev);
 	if (err) {
-		dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
-		goto err_out_iounmap;
+		dev_err(sdev->dev, "Cannot register net device, aborting.\n");
+		goto err_out_powerdown;
 	}
 
-	pci_set_drvdata(pdev, dev);
-
-	pci_save_state(bp->pdev);
+	ssb_set_drvdata(sdev, dev);
 
 	/* Chip reset provides power to the b44 MAC & PCI cores, which
 	 * is necessary for MAC register access.
 	 */
 	b44_chip_reset(bp);
 
-	printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name);
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", dev->dev_addr[i],
-		       i == 5 ? '\n' : ':');
+	printk(KERN_INFO "%s: Broadcom 44xx/47xx 10/100BaseT Ethernet %s\n",
+	       dev->name, print_mac(mac, dev->dev_addr));
 
 	return 0;
 
-err_out_iounmap:
-	iounmap(bp->regs);
+err_out_powerdown:
+	ssb_bus_may_powerdown(sdev->bus);
 
 err_out_free_dev:
 	free_netdev(dev);
 
-err_out_free_res:
-	pci_release_regions(pdev);
-
-err_out_disable_pdev:
-	pci_disable_device(pdev);
-	pci_set_drvdata(pdev, NULL);
+out:
 	return err;
 }
 
-static void __devexit b44_remove_one(struct pci_dev *pdev)
+static void __devexit b44_remove_one(struct ssb_device *sdev)
 {
-	struct net_device *dev = pci_get_drvdata(pdev);
-	struct b44 *bp = netdev_priv(dev);
+	struct net_device *dev = ssb_get_drvdata(sdev);
 
 	unregister_netdev(dev);
-	iounmap(bp->regs);
+	ssb_bus_may_powerdown(sdev->bus);
 	free_netdev(dev);
-	pci_release_regions(pdev);
-	pci_disable_device(pdev);
-	pci_set_drvdata(pdev, NULL);
+	ssb_set_drvdata(sdev, NULL);
 }
 
-static int b44_suspend(struct pci_dev *pdev, pm_message_t state)
+static int b44_suspend(struct ssb_device *sdev, pm_message_t state)
 {
-	struct net_device *dev = pci_get_drvdata(pdev);
+	struct net_device *dev = ssb_get_drvdata(sdev);
 	struct b44 *bp = netdev_priv(dev);
 
-        if (!netif_running(dev))
-                 return 0;
+	if (!netif_running(dev))
+		return 0;
 
 	del_timer_sync(&bp->timer);
 
@@ -2303,33 +2239,29 @@
 		b44_init_hw(bp, B44_PARTIAL_RESET);
 		b44_setup_wol(bp);
 	}
-	pci_disable_device(pdev);
+
 	return 0;
 }
 
-static int b44_resume(struct pci_dev *pdev)
+static int b44_resume(struct ssb_device *sdev)
 {
-	struct net_device *dev = pci_get_drvdata(pdev);
+	struct net_device *dev = ssb_get_drvdata(sdev);
 	struct b44 *bp = netdev_priv(dev);
 	int rc = 0;
 
-	pci_restore_state(pdev);
-	rc = pci_enable_device(pdev);
+	rc = ssb_bus_powerup(sdev->bus, 0);
 	if (rc) {
-		printk(KERN_ERR PFX "%s: pci_enable_device failed\n",
-			dev->name);
+		dev_err(sdev->dev,
+			"Failed to powerup the bus\n");
 		return rc;
 	}
 
-	pci_set_master(pdev);
-
 	if (!netif_running(dev))
 		return 0;
 
 	rc = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev);
 	if (rc) {
 		printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name);
-		pci_disable_device(pdev);
 		return rc;
 	}
 
@@ -2348,29 +2280,53 @@
 	return 0;
 }
 
-static struct pci_driver b44_driver = {
+static struct ssb_driver b44_ssb_driver = {
 	.name		= DRV_MODULE_NAME,
-	.id_table	= b44_pci_tbl,
+	.id_table	= b44_ssb_tbl,
 	.probe		= b44_init_one,
 	.remove		= __devexit_p(b44_remove_one),
-        .suspend        = b44_suspend,
-        .resume         = b44_resume,
+	.suspend	= b44_suspend,
+	.resume		= b44_resume,
 };
 
+static inline int b44_pci_init(void)
+{
+	int err = 0;
+#ifdef CONFIG_B44_PCI
+	err = ssb_pcihost_register(&b44_pci_driver);
+#endif
+	return err;
+}
+
+static inline void b44_pci_exit(void)
+{
+#ifdef CONFIG_B44_PCI
+	ssb_pcihost_unregister(&b44_pci_driver);
+#endif
+}
+
 static int __init b44_init(void)
 {
 	unsigned int dma_desc_align_size = dma_get_cache_alignment();
+	int err;
 
 	/* Setup paramaters for syncing RX/TX DMA descriptors */
 	dma_desc_align_mask = ~(dma_desc_align_size - 1);
 	dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc));
 
-	return pci_register_driver(&b44_driver);
+	err = b44_pci_init();
+	if (err)
+		return err;
+	err = ssb_driver_register(&b44_ssb_driver);
+	if (err)
+		b44_pci_exit();
+	return err;
 }
 
 static void __exit b44_cleanup(void)
 {
-	pci_unregister_driver(&b44_driver);
+	ssb_driver_unregister(&b44_ssb_driver);
+	b44_pci_exit();
 }
 
 module_init(b44_init);
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index e537e63..7db0c84 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -129,6 +129,7 @@
 #define  RXCONFIG_FLOW		0x00000020 /* Flow Control Enable */
 #define  RXCONFIG_FLOW_ACCEPT	0x00000040 /* Accept Unicast Flow Control Frame */
 #define  RXCONFIG_RFILT		0x00000080 /* Reject Filter */
+#define  RXCONFIG_CAM_ABSENT	0x00000100 /* CAM Absent */
 #define B44_RXMAXLEN	0x0404UL /* EMAC RX Max Packet Length */
 #define B44_TXMAXLEN	0x0408UL /* EMAC TX Max Packet Length */
 #define B44_MDIO_CTRL	0x0410UL /* EMAC MDIO Control */
@@ -227,76 +228,6 @@
 #define B44_RX_PAUSE	0x05D4UL /* MIB RX Pause Packets */
 #define B44_RX_NPAUSE	0x05D8UL /* MIB RX Non-Pause Packets */
 
-/* Silicon backplane register definitions */
-#define B44_SBIMSTATE	0x0F90UL /* SB Initiator Agent State */
-#define  SBIMSTATE_PC		0x0000000f /* Pipe Count */
-#define  SBIMSTATE_AP_MASK	0x00000030 /* Arbitration Priority */
-#define  SBIMSTATE_AP_BOTH	0x00000000 /* Use both timeslices and token */
-#define  SBIMSTATE_AP_TS	0x00000010 /* Use timeslices only */
-#define  SBIMSTATE_AP_TK	0x00000020 /* Use token only */
-#define  SBIMSTATE_AP_RSV	0x00000030 /* Reserved */
-#define  SBIMSTATE_IBE		0x00020000 /* In Band Error */
-#define  SBIMSTATE_TO		0x00040000 /* Timeout */
-#define B44_SBINTVEC	0x0F94UL /* SB Interrupt Mask */
-#define  SBINTVEC_PCI		0x00000001 /* Enable interrupts for PCI */
-#define  SBINTVEC_ENET0		0x00000002 /* Enable interrupts for enet 0 */
-#define  SBINTVEC_ILINE20	0x00000004 /* Enable interrupts for iline20 */
-#define  SBINTVEC_CODEC		0x00000008 /* Enable interrupts for v90 codec */
-#define  SBINTVEC_USB		0x00000010 /* Enable interrupts for usb */
-#define  SBINTVEC_EXTIF		0x00000020 /* Enable interrupts for external i/f */
-#define  SBINTVEC_ENET1		0x00000040 /* Enable interrupts for enet 1 */
-#define B44_SBTMSLOW	0x0F98UL /* SB Target State Low */
-#define  SBTMSLOW_RESET		0x00000001 /* Reset */
-#define  SBTMSLOW_REJECT	0x00000002 /* Reject */
-#define  SBTMSLOW_CLOCK		0x00010000 /* Clock Enable */
-#define  SBTMSLOW_FGC		0x00020000 /* Force Gated Clocks On */
-#define  SBTMSLOW_PE		0x40000000 /* Power Management Enable */
-#define  SBTMSLOW_BE		0x80000000 /* BIST Enable */
-#define B44_SBTMSHIGH	0x0F9CUL /* SB Target State High */
-#define  SBTMSHIGH_SERR		0x00000001 /* S-error */
-#define  SBTMSHIGH_INT		0x00000002 /* Interrupt */
-#define  SBTMSHIGH_BUSY		0x00000004 /* Busy */
-#define  SBTMSHIGH_GCR		0x20000000 /* Gated Clock Request */
-#define  SBTMSHIGH_BISTF	0x40000000 /* BIST Failed */
-#define  SBTMSHIGH_BISTD	0x80000000 /* BIST Done */
-#define B44_SBIDHIGH	0x0FFCUL /* SB Identification High */
-#define  SBIDHIGH_RC_MASK	0x0000000f /* Revision Code */
-#define  SBIDHIGH_CC_MASK	0x0000fff0 /* Core Code */
-#define  SBIDHIGH_CC_SHIFT	4
-#define  SBIDHIGH_VC_MASK	0xffff0000 /* Vendor Code */
-#define  SBIDHIGH_VC_SHIFT	16
-
-/* SSB PCI config space registers.  */
-#define SSB_PMCSR		0x44
-#define  SSB_PE			0x100
-#define	SSB_BAR0_WIN		0x80
-#define	SSB_BAR1_WIN		0x84
-#define	SSB_SPROM_CONTROL	0x88
-#define	SSB_BAR1_CONTROL	0x8c
-
-/* SSB core and host control registers.  */
-#define SSB_CONTROL		0x0000UL
-#define SSB_ARBCONTROL		0x0010UL
-#define SSB_ISTAT		0x0020UL
-#define SSB_IMASK		0x0024UL
-#define SSB_MBOX		0x0028UL
-#define SSB_BCAST_ADDR		0x0050UL
-#define SSB_BCAST_DATA		0x0054UL
-#define SSB_PCI_TRANS_0		0x0100UL
-#define SSB_PCI_TRANS_1		0x0104UL
-#define SSB_PCI_TRANS_2		0x0108UL
-#define SSB_SPROM		0x0800UL
-
-#define SSB_PCI_MEM		0x00000000
-#define SSB_PCI_IO		0x00000001
-#define SSB_PCI_CFG0		0x00000002
-#define SSB_PCI_CFG1		0x00000003
-#define SSB_PCI_PREF		0x00000004
-#define SSB_PCI_BURST		0x00000008
-#define SSB_PCI_MASK0		0xfc000000
-#define SSB_PCI_MASK1		0xfc000000
-#define SSB_PCI_MASK2		0xc0000000
-
 /* 4400 PHY registers */
 #define B44_MII_AUXCTRL		24	/* Auxiliary Control */
 #define  MII_AUXCTRL_DUPLEX	0x0001  /* Full Duplex */
@@ -346,10 +277,12 @@
 
 struct ring_info {
 	struct sk_buff		*skb;
-	DECLARE_PCI_UNMAP_ADDR(mapping);
+	dma_addr_t	mapping;
 };
 
 #define B44_MCAST_TABLE_SIZE	32
+#define B44_PHY_ADDR_NO_PHY	30
+#define B44_MDC_RATIO		5000000
 
 #define	B44_STAT_REG_DECLARE		\
 	_B44(tx_good_octets)		\
@@ -410,6 +343,8 @@
 #undef _B44
 };
 
+struct ssb_device;
+
 struct b44 {
 	spinlock_t		lock;
 
@@ -423,6 +358,8 @@
 	struct ring_info	*rx_buffers;
 	struct ring_info	*tx_buffers;
 
+	struct napi_struct	napi;
+
 	u32			dma_offset;
 	u32			flags;
 #define B44_FLAG_B0_ANDLATER	0x00000001
@@ -450,8 +387,7 @@
 	struct net_device_stats	stats;
 	struct b44_hw_stats	hw_stats;
 
-	void __iomem		*regs;
-	struct pci_dev		*pdev;
+	struct ssb_device	*sdev;
 	struct net_device	*dev;
 
 	dma_addr_t		rx_ring_dma, tx_ring_dma;
@@ -459,7 +395,6 @@
 	u32			rx_pending;
 	u32			tx_pending;
 	u8			phy_addr;
-	u8			core_unit;
 
 	struct mii_if_info	mii_if;
 };
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
new file mode 100644
index 0000000..53fe7de
--- /dev/null
+++ b/drivers/net/bfin_mac.c
@@ -0,0 +1,1081 @@
+/*
+ * File:	drivers/net/bfin_mac.c
+ * Based on:
+ * Maintainer:
+ * 		Bryan Wu <bryan.wu@analog.com>
+ *
+ * Original author:
+ * 		Luke Yang <luke.yang@analog.com>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *		Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:	Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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 ;  see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/crc32.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/platform_device.h>
+
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/blackfin.h>
+#include <asm/cacheflush.h>
+#include <asm/portmux.h>
+
+#include "bfin_mac.h"
+
+#define DRV_NAME	"bfin_mac"
+#define DRV_VERSION	"1.1"
+#define DRV_AUTHOR	"Bryan Wu, Luke Yang"
+#define DRV_DESC	"Blackfin BF53[67] on-chip Ethernet MAC driver"
+
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRV_DESC);
+
+#if defined(CONFIG_BFIN_MAC_USE_L1)
+# define bfin_mac_alloc(dma_handle, size)  l1_data_sram_zalloc(size)
+# define bfin_mac_free(dma_handle, ptr)    l1_data_sram_free(ptr)
+#else
+# define bfin_mac_alloc(dma_handle, size) \
+	dma_alloc_coherent(NULL, size, dma_handle, GFP_KERNEL)
+# define bfin_mac_free(dma_handle, ptr) \
+	dma_free_coherent(NULL, sizeof(*ptr), ptr, dma_handle)
+#endif
+
+#define PKT_BUF_SZ 1580
+
+#define MAX_TIMEOUT_CNT	500
+
+/* pointers to maintain transmit list */
+static struct net_dma_desc_tx *tx_list_head;
+static struct net_dma_desc_tx *tx_list_tail;
+static struct net_dma_desc_rx *rx_list_head;
+static struct net_dma_desc_rx *rx_list_tail;
+static struct net_dma_desc_rx *current_rx_ptr;
+static struct net_dma_desc_tx *current_tx_ptr;
+static struct net_dma_desc_tx *tx_desc;
+static struct net_dma_desc_rx *rx_desc;
+
+static void bf537mac_disable(void);
+static void bf537mac_enable(void);
+
+static void desc_list_free(void)
+{
+	struct net_dma_desc_rx *r;
+	struct net_dma_desc_tx *t;
+	int i;
+#if !defined(CONFIG_BFIN_MAC_USE_L1)
+	dma_addr_t dma_handle = 0;
+#endif
+
+	if (tx_desc) {
+		t = tx_list_head;
+		for (i = 0; i < CONFIG_BFIN_TX_DESC_NUM; i++) {
+			if (t) {
+				if (t->skb) {
+					dev_kfree_skb(t->skb);
+					t->skb = NULL;
+				}
+				t = t->next;
+			}
+		}
+		bfin_mac_free(dma_handle, tx_desc);
+	}
+
+	if (rx_desc) {
+		r = rx_list_head;
+		for (i = 0; i < CONFIG_BFIN_RX_DESC_NUM; i++) {
+			if (r) {
+				if (r->skb) {
+					dev_kfree_skb(r->skb);
+					r->skb = NULL;
+				}
+				r = r->next;
+			}
+		}
+		bfin_mac_free(dma_handle, rx_desc);
+	}
+}
+
+static int desc_list_init(void)
+{
+	int i;
+	struct sk_buff *new_skb;
+#if !defined(CONFIG_BFIN_MAC_USE_L1)
+	/*
+	 * This dma_handle is useless in Blackfin dma_alloc_coherent().
+	 * The real dma handler is the return value of dma_alloc_coherent().
+	 */
+	dma_addr_t dma_handle;
+#endif
+
+	tx_desc = bfin_mac_alloc(&dma_handle,
+				sizeof(struct net_dma_desc_tx) *
+				CONFIG_BFIN_TX_DESC_NUM);
+	if (tx_desc == NULL)
+		goto init_error;
+
+	rx_desc = bfin_mac_alloc(&dma_handle,
+				sizeof(struct net_dma_desc_rx) *
+				CONFIG_BFIN_RX_DESC_NUM);
+	if (rx_desc == NULL)
+		goto init_error;
+
+	/* init tx_list */
+	tx_list_head = tx_list_tail = tx_desc;
+
+	for (i = 0; i < CONFIG_BFIN_TX_DESC_NUM; i++) {
+		struct net_dma_desc_tx *t = tx_desc + i;
+		struct dma_descriptor *a = &(t->desc_a);
+		struct dma_descriptor *b = &(t->desc_b);
+
+		/*
+		 * disable DMA
+		 * read from memory WNR = 0
+		 * wordsize is 32 bits
+		 * 6 half words is desc size
+		 * large desc flow
+		 */
+		a->config = WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE;
+		a->start_addr = (unsigned long)t->packet;
+		a->x_count = 0;
+		a->next_dma_desc = b;
+
+		/*
+		 * enabled DMA
+		 * write to memory WNR = 1
+		 * wordsize is 32 bits
+		 * disable interrupt
+		 * 6 half words is desc size
+		 * large desc flow
+		 */
+		b->config = DMAEN | WNR | WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE;
+		b->start_addr = (unsigned long)(&(t->status));
+		b->x_count = 0;
+
+		t->skb = NULL;
+		tx_list_tail->desc_b.next_dma_desc = a;
+		tx_list_tail->next = t;
+		tx_list_tail = t;
+	}
+	tx_list_tail->next = tx_list_head;	/* tx_list is a circle */
+	tx_list_tail->desc_b.next_dma_desc = &(tx_list_head->desc_a);
+	current_tx_ptr = tx_list_head;
+
+	/* init rx_list */
+	rx_list_head = rx_list_tail = rx_desc;
+
+	for (i = 0; i < CONFIG_BFIN_RX_DESC_NUM; i++) {
+		struct net_dma_desc_rx *r = rx_desc + i;
+		struct dma_descriptor *a = &(r->desc_a);
+		struct dma_descriptor *b = &(r->desc_b);
+
+		/* allocate a new skb for next time receive */
+		new_skb = dev_alloc_skb(PKT_BUF_SZ + 2);
+		if (!new_skb) {
+			printk(KERN_NOTICE DRV_NAME
+			       ": init: low on mem - packet dropped\n");
+			goto init_error;
+		}
+		skb_reserve(new_skb, 2);
+		r->skb = new_skb;
+
+		/*
+		 * enabled DMA
+		 * write to memory WNR = 1
+		 * wordsize is 32 bits
+		 * disable interrupt
+		 * 6 half words is desc size
+		 * large desc flow
+		 */
+		a->config = DMAEN | WNR | WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE;
+		/* since RXDWA is enabled */
+		a->start_addr = (unsigned long)new_skb->data - 2;
+		a->x_count = 0;
+		a->next_dma_desc = b;
+
+		/*
+		 * enabled DMA
+		 * write to memory WNR = 1
+		 * wordsize is 32 bits
+		 * enable interrupt
+		 * 6 half words is desc size
+		 * large desc flow
+		 */
+		b->config = DMAEN | WNR | WDSIZE_32 | DI_EN |
+				NDSIZE_6 | DMAFLOW_LARGE;
+		b->start_addr = (unsigned long)(&(r->status));
+		b->x_count = 0;
+
+		rx_list_tail->desc_b.next_dma_desc = a;
+		rx_list_tail->next = r;
+		rx_list_tail = r;
+	}
+	rx_list_tail->next = rx_list_head;	/* rx_list is a circle */
+	rx_list_tail->desc_b.next_dma_desc = &(rx_list_head->desc_a);
+	current_rx_ptr = rx_list_head;
+
+	return 0;
+
+init_error:
+	desc_list_free();
+	printk(KERN_ERR DRV_NAME ": kmalloc failed\n");
+	return -ENOMEM;
+}
+
+
+/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/
+
+/* Set FER regs to MUX in Ethernet pins */
+static int setup_pin_mux(int action)
+{
+#if defined(CONFIG_BFIN_MAC_RMII)
+	u16 pin_req[] = P_RMII0;
+#else
+	u16 pin_req[] = P_MII0;
+#endif
+
+	if (action) {
+		if (peripheral_request_list(pin_req, DRV_NAME)) {
+			printk(KERN_ERR DRV_NAME
+			": Requesting Peripherals failed\n");
+			return -EFAULT;
+		}
+	} else
+		peripheral_free_list(pin_req);
+
+	return 0;
+}
+
+/*
+ * MII operations
+ */
+/* Wait until the previous MDC/MDIO transaction has completed */
+static void mdio_poll(void)
+{
+	int timeout_cnt = MAX_TIMEOUT_CNT;
+
+	/* poll the STABUSY bit */
+	while ((bfin_read_EMAC_STAADD()) & STABUSY) {
+		mdelay(10);
+		if (timeout_cnt-- < 0) {
+			printk(KERN_ERR DRV_NAME
+			": wait MDC/MDIO transaction to complete timeout\n");
+			break;
+		}
+	}
+}
+
+/* Read an off-chip register in a PHY through the MDC/MDIO port */
+static int mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
+{
+	mdio_poll();
+
+	/* read mode */
+	bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) |
+				SET_REGAD((u16) regnum) |
+				STABUSY);
+
+	mdio_poll();
+
+	return (int) bfin_read_EMAC_STADAT();
+}
+
+/* Write an off-chip register in a PHY through the MDC/MDIO port */
+static int mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
+			 u16 value)
+{
+	mdio_poll();
+
+	bfin_write_EMAC_STADAT((u32) value);
+
+	/* write mode */
+	bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) |
+				SET_REGAD((u16) regnum) |
+				STAOP |
+				STABUSY);
+
+	mdio_poll();
+
+	return 0;
+}
+
+static int mdiobus_reset(struct mii_bus *bus)
+{
+	return 0;
+}
+
+static void bf537_adjust_link(struct net_device *dev)
+{
+	struct bf537mac_local *lp = netdev_priv(dev);
+	struct phy_device *phydev = lp->phydev;
+	unsigned long flags;
+	int new_state = 0;
+
+	spin_lock_irqsave(&lp->lock, flags);
+	if (phydev->link) {
+		/* Now we make sure that we can be in full duplex mode.
+		 * If not, we operate in half-duplex mode. */
+		if (phydev->duplex != lp->old_duplex) {
+			u32 opmode = bfin_read_EMAC_OPMODE();
+			new_state = 1;
+
+			if (phydev->duplex)
+				opmode |= FDMODE;
+			else
+				opmode &= ~(FDMODE);
+
+			bfin_write_EMAC_OPMODE(opmode);
+			lp->old_duplex = phydev->duplex;
+		}
+
+		if (phydev->speed != lp->old_speed) {
+#if defined(CONFIG_BFIN_MAC_RMII)
+			u32 opmode = bfin_read_EMAC_OPMODE();
+			bf537mac_disable();
+			switch (phydev->speed) {
+			case 10:
+				opmode |= RMII_10;
+				break;
+			case 100:
+				opmode &= ~(RMII_10);
+				break;
+			default:
+				printk(KERN_WARNING
+					"%s: Ack!  Speed (%d) is not 10/100!\n",
+					DRV_NAME, phydev->speed);
+				break;
+			}
+			bfin_write_EMAC_OPMODE(opmode);
+			bf537mac_enable();
+#endif
+
+			new_state = 1;
+			lp->old_speed = phydev->speed;
+		}
+
+		if (!lp->old_link) {
+			new_state = 1;
+			lp->old_link = 1;
+			netif_schedule(dev);
+		}
+	} else if (lp->old_link) {
+		new_state = 1;
+		lp->old_link = 0;
+		lp->old_speed = 0;
+		lp->old_duplex = -1;
+	}
+
+	if (new_state) {
+		u32 opmode = bfin_read_EMAC_OPMODE();
+		phy_print_status(phydev);
+		pr_debug("EMAC_OPMODE = 0x%08x\n", opmode);
+	}
+
+	spin_unlock_irqrestore(&lp->lock, flags);
+}
+
+static int mii_probe(struct net_device *dev)
+{
+	struct bf537mac_local *lp = netdev_priv(dev);
+	struct phy_device *phydev = NULL;
+	unsigned short sysctl;
+	int i;
+
+	/* Enable PHY output early */
+	if (!(bfin_read_VR_CTL() & PHYCLKOE))
+		bfin_write_VR_CTL(bfin_read_VR_CTL() | PHYCLKOE);
+
+	/* MDC  = 2.5 MHz */
+	sysctl = bfin_read_EMAC_SYSCTL();
+	sysctl |= SET_MDCDIV(24);
+	bfin_write_EMAC_SYSCTL(sysctl);
+
+	/* search for connect PHY device */
+	for (i = 0; i < PHY_MAX_ADDR; i++) {
+		struct phy_device *const tmp_phydev = lp->mii_bus.phy_map[i];
+
+		if (!tmp_phydev)
+			continue; /* no PHY here... */
+
+		phydev = tmp_phydev;
+		break; /* found it */
+	}
+
+	/* now we are supposed to have a proper phydev, to attach to... */
+	if (!phydev) {
+		printk(KERN_INFO "%s: Don't found any phy device at all\n",
+			dev->name);
+		return -ENODEV;
+	}
+
+#if defined(CONFIG_BFIN_MAC_RMII)
+	phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0,
+			PHY_INTERFACE_MODE_RMII);
+#else
+	phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0,
+			PHY_INTERFACE_MODE_MII);
+#endif
+
+	if (IS_ERR(phydev)) {
+		printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+		return PTR_ERR(phydev);
+	}
+
+	/* mask with MAC supported features */
+	phydev->supported &= (SUPPORTED_10baseT_Half
+			      | SUPPORTED_10baseT_Full
+			      | SUPPORTED_100baseT_Half
+			      | SUPPORTED_100baseT_Full
+			      | SUPPORTED_Autoneg
+			      | SUPPORTED_Pause | SUPPORTED_Asym_Pause
+			      | SUPPORTED_MII
+			      | SUPPORTED_TP);
+
+	phydev->advertising = phydev->supported;
+
+	lp->old_link = 0;
+	lp->old_speed = 0;
+	lp->old_duplex = -1;
+	lp->phydev = phydev;
+
+	printk(KERN_INFO "%s: attached PHY driver [%s] "
+	       "(mii_bus:phy_addr=%s, irq=%d)\n",
+	       DRV_NAME, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
+
+	return 0;
+}
+
+/**************************************************************************/
+void setup_system_regs(struct net_device *dev)
+{
+	unsigned short sysctl;
+
+	/*
+	 * Odd word alignment for Receive Frame DMA word
+	 * Configure checksum support and rcve frame word alignment
+	 */
+	sysctl = bfin_read_EMAC_SYSCTL();
+#if defined(BFIN_MAC_CSUM_OFFLOAD)
+	sysctl |= RXDWA | RXCKS;
+#else
+	sysctl |= RXDWA;
+#endif
+	bfin_write_EMAC_SYSCTL(sysctl);
+
+	bfin_write_EMAC_MMC_CTL(RSTC | CROLL);
+
+	/* Initialize the TX DMA channel registers */
+	bfin_write_DMA2_X_COUNT(0);
+	bfin_write_DMA2_X_MODIFY(4);
+	bfin_write_DMA2_Y_COUNT(0);
+	bfin_write_DMA2_Y_MODIFY(0);
+
+	/* Initialize the RX DMA channel registers */
+	bfin_write_DMA1_X_COUNT(0);
+	bfin_write_DMA1_X_MODIFY(4);
+	bfin_write_DMA1_Y_COUNT(0);
+	bfin_write_DMA1_Y_MODIFY(0);
+}
+
+static void setup_mac_addr(u8 *mac_addr)
+{
+	u32 addr_low = le32_to_cpu(*(__le32 *) & mac_addr[0]);
+	u16 addr_hi = le16_to_cpu(*(__le16 *) & mac_addr[4]);
+
+	/* this depends on a little-endian machine */
+	bfin_write_EMAC_ADDRLO(addr_low);
+	bfin_write_EMAC_ADDRHI(addr_hi);
+}
+
+static int bf537mac_set_mac_address(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+	if (netif_running(dev))
+		return -EBUSY;
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+	setup_mac_addr(dev->dev_addr);
+	return 0;
+}
+
+static void adjust_tx_list(void)
+{
+	int timeout_cnt = MAX_TIMEOUT_CNT;
+
+	if (tx_list_head->status.status_word != 0
+	    && current_tx_ptr != tx_list_head) {
+		goto adjust_head;	/* released something, just return; */
+	}
+
+	/*
+	 * if nothing released, check wait condition
+	 * current's next can not be the head,
+	 * otherwise the dma will not stop as we want
+	 */
+	if (current_tx_ptr->next->next == tx_list_head) {
+		while (tx_list_head->status.status_word == 0) {
+			mdelay(10);
+			if (tx_list_head->status.status_word != 0
+			    || !(bfin_read_DMA2_IRQ_STATUS() & 0x08)) {
+				goto adjust_head;
+			}
+			if (timeout_cnt-- < 0) {
+				printk(KERN_ERR DRV_NAME
+				": wait for adjust tx list head timeout\n");
+				break;
+			}
+		}
+		if (tx_list_head->status.status_word != 0) {
+			goto adjust_head;
+		}
+	}
+
+	return;
+
+adjust_head:
+	do {
+		tx_list_head->desc_a.config &= ~DMAEN;
+		tx_list_head->status.status_word = 0;
+		if (tx_list_head->skb) {
+			dev_kfree_skb(tx_list_head->skb);
+			tx_list_head->skb = NULL;
+		} else {
+			printk(KERN_ERR DRV_NAME
+			       ": no sk_buff in a transmitted frame!\n");
+		}
+		tx_list_head = tx_list_head->next;
+	} while (tx_list_head->status.status_word != 0
+		 && current_tx_ptr != tx_list_head);
+	return;
+
+}
+
+static int bf537mac_hard_start_xmit(struct sk_buff *skb,
+				struct net_device *dev)
+{
+	struct bf537mac_local *lp = netdev_priv(dev);
+	unsigned int data;
+
+	current_tx_ptr->skb = skb;
+
+	/*
+	 * Is skb->data always 16-bit aligned?
+	 * Do we need to memcpy((char *)(tail->packet + 2), skb->data, len)?
+	 */
+	if ((((unsigned int)(skb->data)) & 0x02) == 2) {
+		/* move skb->data to current_tx_ptr payload */
+		data = (unsigned int)(skb->data) - 2;
+		*((unsigned short *)data) = (unsigned short)(skb->len);
+		current_tx_ptr->desc_a.start_addr = (unsigned long)data;
+		/* this is important! */
+		blackfin_dcache_flush_range(data, (data + (skb->len)) + 2);
+
+	} else {
+		*((unsigned short *)(current_tx_ptr->packet)) =
+		    (unsigned short)(skb->len);
+		memcpy((char *)(current_tx_ptr->packet + 2), skb->data,
+		       (skb->len));
+		current_tx_ptr->desc_a.start_addr =
+		    (unsigned long)current_tx_ptr->packet;
+		if (current_tx_ptr->status.status_word != 0)
+			current_tx_ptr->status.status_word = 0;
+		blackfin_dcache_flush_range((unsigned int)current_tx_ptr->
+					    packet,
+					    (unsigned int)(current_tx_ptr->
+							   packet + skb->len) +
+					    2);
+	}
+
+	/* enable this packet's dma */
+	current_tx_ptr->desc_a.config |= DMAEN;
+
+	/* tx dma is running, just return */
+	if (bfin_read_DMA2_IRQ_STATUS() & 0x08)
+		goto out;
+
+	/* tx dma is not running */
+	bfin_write_DMA2_NEXT_DESC_PTR(&(current_tx_ptr->desc_a));
+	/* dma enabled, read from memory, size is 6 */
+	bfin_write_DMA2_CONFIG(current_tx_ptr->desc_a.config);
+	/* Turn on the EMAC tx */
+	bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE);
+
+out:
+	adjust_tx_list();
+	current_tx_ptr = current_tx_ptr->next;
+	dev->trans_start = jiffies;
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += (skb->len);
+	return 0;
+}
+
+static void bf537mac_rx(struct net_device *dev)
+{
+	struct sk_buff *skb, *new_skb;
+	struct bf537mac_local *lp = netdev_priv(dev);
+	unsigned short len;
+
+	/* allocate a new skb for next time receive */
+	skb = current_rx_ptr->skb;
+	new_skb = dev_alloc_skb(PKT_BUF_SZ + 2);
+	if (!new_skb) {
+		printk(KERN_NOTICE DRV_NAME
+		       ": rx: low on mem - packet dropped\n");
+		dev->stats.rx_dropped++;
+		goto out;
+	}
+	/* reserve 2 bytes for RXDWA padding */
+	skb_reserve(new_skb, 2);
+	current_rx_ptr->skb = new_skb;
+	current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2;
+
+	len = (unsigned short)((current_rx_ptr->status.status_word) & RX_FRLEN);
+	skb_put(skb, len);
+	blackfin_dcache_invalidate_range((unsigned long)skb->head,
+					 (unsigned long)skb->tail);
+
+	dev->last_rx = jiffies;
+	skb->dev = dev;
+	skb->protocol = eth_type_trans(skb, dev);
+#if defined(BFIN_MAC_CSUM_OFFLOAD)
+	skb->csum = current_rx_ptr->status.ip_payload_csum;
+	skb->ip_summed = CHECKSUM_PARTIAL;
+#endif
+
+	netif_rx(skb);
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += len;
+	current_rx_ptr->status.status_word = 0x00000000;
+	current_rx_ptr = current_rx_ptr->next;
+
+out:
+	return;
+}
+
+/* interrupt routine to handle rx and error signal */
+static irqreturn_t bf537mac_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	int number = 0;
+
+get_one_packet:
+	if (current_rx_ptr->status.status_word == 0) {
+		/* no more new packet received */
+		if (number == 0) {
+			if (current_rx_ptr->next->status.status_word != 0) {
+				current_rx_ptr = current_rx_ptr->next;
+				goto real_rx;
+			}
+		}
+		bfin_write_DMA1_IRQ_STATUS(bfin_read_DMA1_IRQ_STATUS() |
+					   DMA_DONE | DMA_ERR);
+		return IRQ_HANDLED;
+	}
+
+real_rx:
+	bf537mac_rx(dev);
+	number++;
+	goto get_one_packet;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void bf537mac_poll(struct net_device *dev)
+{
+	disable_irq(IRQ_MAC_RX);
+	bf537mac_interrupt(IRQ_MAC_RX, dev);
+	enable_irq(IRQ_MAC_RX);
+}
+#endif				/* CONFIG_NET_POLL_CONTROLLER */
+
+static void bf537mac_disable(void)
+{
+	unsigned int opmode;
+
+	opmode = bfin_read_EMAC_OPMODE();
+	opmode &= (~RE);
+	opmode &= (~TE);
+	/* Turn off the EMAC */
+	bfin_write_EMAC_OPMODE(opmode);
+}
+
+/*
+ * Enable Interrupts, Receive, and Transmit
+ */
+static void bf537mac_enable(void)
+{
+	u32 opmode;
+
+	pr_debug("%s: %s\n", DRV_NAME, __FUNCTION__);
+
+	/* Set RX DMA */
+	bfin_write_DMA1_NEXT_DESC_PTR(&(rx_list_head->desc_a));
+	bfin_write_DMA1_CONFIG(rx_list_head->desc_a.config);
+
+	/* Wait MII done */
+	mdio_poll();
+
+	/* We enable only RX here */
+	/* ASTP   : Enable Automatic Pad Stripping
+	   PR     : Promiscuous Mode for test
+	   PSF    : Receive frames with total length less than 64 bytes.
+	   FDMODE : Full Duplex Mode
+	   LB     : Internal Loopback for test
+	   RE     : Receiver Enable */
+	opmode = bfin_read_EMAC_OPMODE();
+	if (opmode & FDMODE)
+		opmode |= PSF;
+	else
+		opmode |= DRO | DC | PSF;
+	opmode |= RE;
+
+#if defined(CONFIG_BFIN_MAC_RMII)
+	opmode |= RMII; /* For Now only 100MBit are supported */
+#ifdef CONFIG_BF_REV_0_2
+	opmode |= TE;
+#endif
+#endif
+	/* Turn on the EMAC rx */
+	bfin_write_EMAC_OPMODE(opmode);
+}
+
+/* Our watchdog timed out. Called by the networking layer */
+static void bf537mac_timeout(struct net_device *dev)
+{
+	pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+
+	bf537mac_disable();
+
+	/* reset tx queue */
+	tx_list_tail = tx_list_head->next;
+
+	bf537mac_enable();
+
+	/* We can accept TX packets again */
+	dev->trans_start = jiffies;
+	netif_wake_queue(dev);
+}
+
+/*
+ * This routine will, depending on the values passed to it,
+ * either make it accept multicast packets, go into
+ * promiscuous mode (for TCPDUMP and cousins) or accept
+ * a select set of multicast packets
+ */
+static void bf537mac_set_multicast_list(struct net_device *dev)
+{
+	u32 sysctl;
+
+	if (dev->flags & IFF_PROMISC) {
+		printk(KERN_INFO "%s: set to promisc mode\n", dev->name);
+		sysctl = bfin_read_EMAC_OPMODE();
+		sysctl |= RAF;
+		bfin_write_EMAC_OPMODE(sysctl);
+	} else if (dev->flags & IFF_ALLMULTI || dev->mc_count) {
+		/* accept all multicast */
+		sysctl = bfin_read_EMAC_OPMODE();
+		sysctl |= PAM;
+		bfin_write_EMAC_OPMODE(sysctl);
+	} else {
+		/* clear promisc or multicast mode */
+		sysctl = bfin_read_EMAC_OPMODE();
+		sysctl &= ~(RAF | PAM);
+		bfin_write_EMAC_OPMODE(sysctl);
+	}
+}
+
+/*
+ * this puts the device in an inactive state
+ */
+static void bf537mac_shutdown(struct net_device *dev)
+{
+	/* Turn off the EMAC */
+	bfin_write_EMAC_OPMODE(0x00000000);
+	/* Turn off the EMAC RX DMA */
+	bfin_write_DMA1_CONFIG(0x0000);
+	bfin_write_DMA2_CONFIG(0x0000);
+}
+
+/*
+ * Open and Initialize the interface
+ *
+ * Set up everything, reset the card, etc..
+ */
+static int bf537mac_open(struct net_device *dev)
+{
+	struct bf537mac_local *lp = netdev_priv(dev);
+	int retval;
+	pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+
+	/*
+	 * Check that the address is valid.  If its not, refuse
+	 * to bring the device up.  The user must specify an
+	 * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx
+	 */
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		printk(KERN_WARNING DRV_NAME ": no valid ethernet hw addr\n");
+		return -EINVAL;
+	}
+
+	/* initial rx and tx list */
+	retval = desc_list_init();
+
+	if (retval)
+		return retval;
+
+	phy_start(lp->phydev);
+	setup_system_regs(dev);
+	bf537mac_disable();
+	bf537mac_enable();
+
+	pr_debug("hardware init finished\n");
+	netif_start_queue(dev);
+	netif_carrier_on(dev);
+
+	return 0;
+}
+
+/*
+ *
+ * this makes the board clean up everything that it can
+ * and not talk to the outside world.   Caused by
+ * an 'ifconfig ethX down'
+ */
+static int bf537mac_close(struct net_device *dev)
+{
+	struct bf537mac_local *lp = netdev_priv(dev);
+	pr_debug("%s: %s\n", dev->name, __FUNCTION__);
+
+	netif_stop_queue(dev);
+	netif_carrier_off(dev);
+
+	phy_stop(lp->phydev);
+
+	/* clear everything */
+	bf537mac_shutdown(dev);
+
+	/* free the rx/tx buffers */
+	desc_list_free();
+
+	return 0;
+}
+
+static int __init bf537mac_probe(struct net_device *dev)
+{
+	struct bf537mac_local *lp = netdev_priv(dev);
+	int retval;
+	int i;
+
+	/* Grab the MAC address in the MAC */
+	*(__le32 *) (&(dev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO());
+	*(__le16 *) (&(dev->dev_addr[4])) = cpu_to_le16((u16) bfin_read_EMAC_ADDRHI());
+
+	/* probe mac */
+	/*todo: how to proble? which is revision_register */
+	bfin_write_EMAC_ADDRLO(0x12345678);
+	if (bfin_read_EMAC_ADDRLO() != 0x12345678) {
+		pr_debug("can't detect bf537 mac!\n");
+		retval = -ENODEV;
+		goto err_out;
+	}
+
+	/* set the GPIO pins to Ethernet mode */
+	retval = setup_pin_mux(1);
+	if (retval)
+		return retval;
+
+	/*Is it valid? (Did bootloader initialize it?) */
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		/* Grab the MAC from the board somehow - this is done in the
+		   arch/blackfin/mach-bf537/boards/eth_mac.c */
+		get_bf537_ether_addr(dev->dev_addr);
+	}
+
+	/* If still not valid, get a random one */
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		random_ether_addr(dev->dev_addr);
+	}
+
+	setup_mac_addr(dev->dev_addr);
+
+	/* MDIO bus initial */
+	lp->mii_bus.priv = dev;
+	lp->mii_bus.read = mdiobus_read;
+	lp->mii_bus.write = mdiobus_write;
+	lp->mii_bus.reset = mdiobus_reset;
+	lp->mii_bus.name = "bfin_mac_mdio";
+	lp->mii_bus.id = 0;
+	lp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+	for (i = 0; i < PHY_MAX_ADDR; ++i)
+		lp->mii_bus.irq[i] = PHY_POLL;
+
+	mdiobus_register(&lp->mii_bus);
+
+	retval = mii_probe(dev);
+	if (retval)
+		return retval;
+
+	/* Fill in the fields of the device structure with ethernet values. */
+	ether_setup(dev);
+
+	dev->open = bf537mac_open;
+	dev->stop = bf537mac_close;
+	dev->hard_start_xmit = bf537mac_hard_start_xmit;
+	dev->set_mac_address = bf537mac_set_mac_address;
+	dev->tx_timeout = bf537mac_timeout;
+	dev->set_multicast_list = bf537mac_set_multicast_list;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = bf537mac_poll;
+#endif
+
+	spin_lock_init(&lp->lock);
+
+	/* now, enable interrupts */
+	/* register irq handler */
+	if (request_irq
+	    (IRQ_MAC_RX, bf537mac_interrupt, IRQF_DISABLED | IRQF_SHARED,
+	     "BFIN537_MAC_RX", dev)) {
+		printk(KERN_WARNING DRV_NAME
+		       ": Unable to attach BlackFin MAC RX interrupt\n");
+		return -EBUSY;
+	}
+
+
+	retval = register_netdev(dev);
+	if (retval == 0) {
+		/* now, print out the card info, in a short format.. */
+		printk(KERN_INFO "%s: Version %s, %s\n",
+			 DRV_NAME, DRV_VERSION, DRV_DESC);
+	}
+
+err_out:
+	return retval;
+}
+
+static int bfin_mac_probe(struct platform_device *pdev)
+{
+	struct net_device *ndev;
+
+	ndev = alloc_etherdev(sizeof(struct bf537mac_local));
+	if (!ndev) {
+		printk(KERN_WARNING DRV_NAME ": could not allocate device\n");
+		return -ENOMEM;
+	}
+
+	SET_NETDEV_DEV(ndev, &pdev->dev);
+
+	platform_set_drvdata(pdev, ndev);
+
+	if (bf537mac_probe(ndev) != 0) {
+		platform_set_drvdata(pdev, NULL);
+		free_netdev(ndev);
+		printk(KERN_WARNING DRV_NAME ": not found\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int bfin_mac_remove(struct platform_device *pdev)
+{
+	struct net_device *ndev = platform_get_drvdata(pdev);
+
+	platform_set_drvdata(pdev, NULL);
+
+	unregister_netdev(ndev);
+
+	free_irq(IRQ_MAC_RX, ndev);
+
+	free_netdev(ndev);
+
+	setup_pin_mux(0);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+	struct net_device *net_dev = platform_get_drvdata(pdev);
+
+	if (netif_running(net_dev))
+		bf537mac_close(net_dev);
+
+	return 0;
+}
+
+static int bfin_mac_resume(struct platform_device *pdev)
+{
+	struct net_device *net_dev = platform_get_drvdata(pdev);
+
+	if (netif_running(net_dev))
+		bf537mac_open(net_dev);
+
+	return 0;
+}
+#else
+#define bfin_mac_suspend NULL
+#define bfin_mac_resume NULL
+#endif	/* CONFIG_PM */
+
+static struct platform_driver bfin_mac_driver = {
+	.probe = bfin_mac_probe,
+	.remove = bfin_mac_remove,
+	.resume = bfin_mac_resume,
+	.suspend = bfin_mac_suspend,
+	.driver = {
+		   .name = DRV_NAME,
+		   },
+};
+
+static int __init bfin_mac_init(void)
+{
+	return platform_driver_register(&bfin_mac_driver);
+}
+
+module_init(bfin_mac_init);
+
+static void __exit bfin_mac_cleanup(void)
+{
+	platform_driver_unregister(&bfin_mac_driver);
+}
+
+module_exit(bfin_mac_cleanup);
diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h
new file mode 100644
index 0000000..3a107ad
--- /dev/null
+++ b/drivers/net/bfin_mac.h
@@ -0,0 +1,95 @@
+/*
+ * File:	drivers/net/bfin_mac.c
+ * Based on:
+ * Maintainer:
+ * 		Bryan Wu <bryan.wu@analog.com>
+ *
+ * Original author:
+ * 		Luke Yang <luke.yang@analog.com>
+ *
+ * Created:
+ * Description:
+ *
+ * Modified:
+ *		Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Bugs:	Enter bugs at http://blackfin.uclinux.org/
+ *
+ * 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, 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 ;  see the file COPYING.
+ * If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define BFIN_MAC_CSUM_OFFLOAD
+
+struct dma_descriptor {
+	struct dma_descriptor *next_dma_desc;
+	unsigned long start_addr;
+	unsigned short config;
+	unsigned short x_count;
+};
+
+struct status_area_rx {
+#if defined(BFIN_MAC_CSUM_OFFLOAD)
+	unsigned short ip_hdr_csum;	/* ip header checksum */
+	/* ip payload(udp or tcp or others) checksum */
+	unsigned short ip_payload_csum;
+#endif
+	unsigned long status_word;	/* the frame status word */
+};
+
+struct status_area_tx {
+	unsigned long status_word;	/* the frame status word */
+};
+
+/* use two descriptors for a packet */
+struct net_dma_desc_rx {
+	struct net_dma_desc_rx *next;
+	struct sk_buff *skb;
+	struct dma_descriptor desc_a;
+	struct dma_descriptor desc_b;
+	struct status_area_rx status;
+};
+
+/* use two descriptors for a packet */
+struct net_dma_desc_tx {
+	struct net_dma_desc_tx *next;
+	struct sk_buff *skb;
+	struct dma_descriptor desc_a;
+	struct dma_descriptor desc_b;
+	unsigned char packet[1560];
+	struct status_area_tx status;
+};
+
+struct bf537mac_local {
+	/*
+	 * these are things that the kernel wants me to keep, so users
+	 * can find out semi-useless statistics of how well the card is
+	 * performing
+	 */
+	struct net_device_stats stats;
+
+	unsigned char Mac[6];	/* MAC address of the board */
+	spinlock_t lock;
+
+	/* MII and PHY stuffs */
+	int old_link;          /* used by bf537_adjust_link */
+	int old_speed;
+	int old_duplex;
+
+	struct phy_device *phydev;
+	struct mii_bus mii_bus;
+};
+
+extern void get_bf537_ether_addr(char *addr);
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 9b8d7d9..a42bd19 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -19,6 +19,7 @@
 #include <linux/spinlock.h>
 #include <linux/crc32.h>
 #include <linux/bitrev.h>
+#include <linux/ethtool.h>
 #include <asm/prom.h>
 #include <asm/dbdma.h>
 #include <asm/io.h>
@@ -74,7 +75,6 @@
 	int tx_fill;
 	int tx_empty;
 	unsigned char tx_fullup;
-	struct net_device_stats stats;
 	struct timer_list tx_timeout;
 	int timeout_active;
 	int sleeping;
@@ -144,7 +144,6 @@
 static int bmac_open(struct net_device *dev);
 static int bmac_close(struct net_device *dev);
 static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *bmac_stats(struct net_device *dev);
 static void bmac_set_multicast(struct net_device *dev);
 static void bmac_reset_and_enable(struct net_device *dev);
 static void bmac_start_chip(struct net_device *dev);
@@ -667,7 +666,7 @@
 	bp->tx_bufs[bp->tx_fill] = skb;
 	bp->tx_fill = i;
 
-	bp->stats.tx_bytes += skb->len;
+	dev->stats.tx_bytes += skb->len;
 
 	dbdma_continue(td);
 
@@ -706,8 +705,8 @@
 		nb = RX_BUFLEN - residual - 2;
 		if (nb < (ETHERMINPACKET - ETHERCRC)) {
 			skb = NULL;
-			bp->stats.rx_length_errors++;
-			bp->stats.rx_errors++;
+			dev->stats.rx_length_errors++;
+			dev->stats.rx_errors++;
 		} else {
 			skb = bp->rx_bufs[i];
 			bp->rx_bufs[i] = NULL;
@@ -718,10 +717,10 @@
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
 			dev->last_rx = jiffies;
-			++bp->stats.rx_packets;
-			bp->stats.rx_bytes += nb;
+			++dev->stats.rx_packets;
+			dev->stats.rx_bytes += nb;
 		} else {
-			++bp->stats.rx_dropped;
+			++dev->stats.rx_dropped;
 		}
 		dev->last_rx = jiffies;
 		if ((skb = bp->rx_bufs[i]) == NULL) {
@@ -784,7 +783,7 @@
 		}
 
 		if (bp->tx_bufs[bp->tx_empty]) {
-			++bp->stats.tx_packets;
+			++dev->stats.tx_packets;
 			dev_kfree_skb_irq(bp->tx_bufs[bp->tx_empty]);
 		}
 		bp->tx_bufs[bp->tx_empty] = NULL;
@@ -806,13 +805,6 @@
 	return IRQ_HANDLED;
 }
 
-static struct net_device_stats *bmac_stats(struct net_device *dev)
-{
-	struct bmac_data *p = netdev_priv(dev);
-
-	return &p->stats;
-}
-
 #ifndef SUNHME_MULTICAST
 /* Real fast bit-reversal algorithm, 6-bit values */
 static int reverse6[64] = {
@@ -1079,17 +1071,17 @@
 	}
 	/* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */
 	/*     bmac_txdma_intr_inner(irq, dev_id); */
-	/*   if (status & FrameReceived) bp->stats.rx_dropped++; */
-	if (status & RxErrorMask) bp->stats.rx_errors++;
-	if (status & RxCRCCntExp) bp->stats.rx_crc_errors++;
-	if (status & RxLenCntExp) bp->stats.rx_length_errors++;
-	if (status & RxOverFlow) bp->stats.rx_over_errors++;
-	if (status & RxAlignCntExp) bp->stats.rx_frame_errors++;
+	/*   if (status & FrameReceived) dev->stats.rx_dropped++; */
+	if (status & RxErrorMask) dev->stats.rx_errors++;
+	if (status & RxCRCCntExp) dev->stats.rx_crc_errors++;
+	if (status & RxLenCntExp) dev->stats.rx_length_errors++;
+	if (status & RxOverFlow) dev->stats.rx_over_errors++;
+	if (status & RxAlignCntExp) dev->stats.rx_frame_errors++;
 
-	/*   if (status & FrameSent) bp->stats.tx_dropped++; */
-	if (status & TxErrorMask) bp->stats.tx_errors++;
-	if (status & TxUnderrun) bp->stats.tx_fifo_errors++;
-	if (status & TxNormalCollExp) bp->stats.collisions++;
+	/*   if (status & FrameSent) dev->stats.tx_dropped++; */
+	if (status & TxErrorMask) dev->stats.tx_errors++;
+	if (status & TxUnderrun) dev->stats.tx_fifo_errors++;
+	if (status & TxNormalCollExp) dev->stats.collisions++;
 	return IRQ_HANDLED;
 }
 
@@ -1246,6 +1238,17 @@
 	}
 	spin_unlock_irqrestore(&bp->lock, flags);
 }
+static void bmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	struct bmac_data *bp = netdev_priv(dev);
+	strcpy(info->driver, "bmac");
+	strcpy(info->bus_info, bp->mdev->ofdev.dev.bus_id);
+}
+
+static const struct ethtool_ops bmac_ethtool_ops = {
+	.get_drvinfo		= bmac_get_drvinfo,
+	.get_link		= ethtool_op_get_link,
+};
 
 static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_id *match)
 {
@@ -1255,6 +1258,7 @@
 	unsigned char addr[6];
 	struct net_device *dev;
 	int is_bmac_plus = ((int)match->data) != 0;
+	DECLARE_MAC_BUF(mac);
 
 	if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
 		printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n");
@@ -1279,7 +1283,6 @@
 	}
 
 	bp = netdev_priv(dev);
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
 	macio_set_drvdata(mdev, dev);
 
@@ -1311,8 +1314,8 @@
 
 	dev->open = bmac_open;
 	dev->stop = bmac_close;
+	dev->ethtool_ops = &bmac_ethtool_ops;
 	dev->hard_start_xmit = bmac_output;
-	dev->get_stats = bmac_stats;
 	dev->set_multicast_list = bmac_set_multicast;
 	dev->set_mac_address = bmac_set_address;
 
@@ -1365,9 +1368,8 @@
 		goto err_out_irq2;
 	}
 
-	printk(KERN_INFO "%s: BMAC%s at", dev->name, (is_bmac_plus? "+": ""));
-	for (j = 0; j < 6; ++j)
-		printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
+	printk(KERN_INFO "%s: BMAC%s at %s",
+	       dev->name, (is_bmac_plus ? "+" : ""), print_mac(mac, dev->dev_addr));
 	XXDEBUG((", base_addr=%#0lx", dev->base_addr));
 	printk("\n");
 
@@ -1530,7 +1532,7 @@
 	XXDEBUG((KERN_DEBUG "bmac: tx empty=%d fill=%d fullup=%d\n",
 		 bp->tx_empty, bp->tx_fill, bp->tx_fullup));
 	i = bp->tx_empty;
-	++bp->stats.tx_errors;
+	++dev->stats.tx_errors;
 	if (i != bp->tx_fill) {
 		dev_kfree_skb(bp->tx_bufs[i]);
 		bp->tx_bufs[i] = NULL;
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index d23861c..78ed633 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -52,10 +52,12 @@
 #include "bnx2_fw.h"
 #include "bnx2_fw2.h"
 
+#define FW_BUF_SIZE		0x8000
+
 #define DRV_MODULE_NAME		"bnx2"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"1.6.2"
-#define DRV_MODULE_RELDATE	"July 6, 2007"
+#define DRV_MODULE_VERSION	"1.6.7"
+#define DRV_MODULE_RELDATE	"October 10, 2007"
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -126,91 +128,102 @@
 
 static struct flash_spec flash_table[] =
 {
+#define BUFFERED_FLAGS		(BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)
+#define NONBUFFERED_FLAGS	(BNX2_NV_WREN)
 	/* Slow EEPROM */
 	{0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
-	 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
+	 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
 	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
 	 "EEPROM - slow"},
 	/* Expansion entry 0001 */
 	{0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
-	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
 	 "Entry 0001"},
 	/* Saifun SA25F010 (non-buffered flash) */
 	/* strap, cfg1, & write1 need updates */
 	{0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
-	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
 	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
 	 "Non-buffered flash (128kB)"},
 	/* Saifun SA25F020 (non-buffered flash) */
 	/* strap, cfg1, & write1 need updates */
 	{0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
-	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
 	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
 	 "Non-buffered flash (256kB)"},
 	/* Expansion entry 0100 */
 	{0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
-	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
 	 "Entry 0100"},
 	/* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
 	{0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
-	 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
+	 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
 	 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
 	 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
 	/* Entry 0110: ST M45PE20 (non-buffered flash)*/
 	{0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
-	 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
+	 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
 	 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
 	 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
 	/* Saifun SA25F005 (non-buffered flash) */
 	/* strap, cfg1, & write1 need updates */
 	{0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
-	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
 	 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
 	 "Non-buffered flash (64kB)"},
 	/* Fast EEPROM */
 	{0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
-	 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
+	 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
 	 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
 	 "EEPROM - fast"},
 	/* Expansion entry 1001 */
 	{0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
-	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
 	 "Entry 1001"},
 	/* Expansion entry 1010 */
 	{0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
-	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
 	 "Entry 1010"},
 	/* ATMEL AT45DB011B (buffered flash) */
 	{0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
-	 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
 	 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
 	 "Buffered flash (128kB)"},
 	/* Expansion entry 1100 */
 	{0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
-	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
 	 "Entry 1100"},
 	/* Expansion entry 1101 */
 	{0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
-	 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
+	 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
 	 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
 	 "Entry 1101"},
 	/* Ateml Expansion entry 1110 */
 	{0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
-	 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
 	 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
 	 "Entry 1110 (Atmel)"},
 	/* ATMEL AT45DB021B (buffered flash) */
 	{0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
-	 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
+	 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
 	 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
 	 "Buffered flash (256kB)"},
 };
 
+static struct flash_spec flash_5709 = {
+	.flags		= BNX2_NV_BUFFERED,
+	.page_bits	= BCM5709_FLASH_PAGE_BITS,
+	.page_size	= BCM5709_FLASH_PAGE_SIZE,
+	.addr_mask	= BCM5709_FLASH_BYTE_ADDR_MASK,
+	.total_size	= BUFFERED_FLASH_TOTAL_SIZE*2,
+	.name		= "5709 Buffered flash (256kB)",
+};
+
 MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
 
 static inline u32 bnx2_tx_avail(struct bnx2 *bp)
@@ -417,7 +430,7 @@
 {
 	bnx2_disable_int_sync(bp);
 	if (netif_running(bp->dev)) {
-		netif_poll_disable(bp->dev);
+		napi_disable(&bp->napi);
 		netif_tx_disable(bp->dev);
 		bp->dev->trans_start = jiffies;	/* prevent tx timeout */
 	}
@@ -429,7 +442,7 @@
 	if (atomic_dec_and_test(&bp->intr_sem)) {
 		if (netif_running(bp->dev)) {
 			netif_wake_queue(bp->dev);
-			netif_poll_enable(bp->dev);
+			napi_enable(&bp->napi);
 			bnx2_enable_int(bp);
 		}
 	}
@@ -2540,7 +2553,7 @@
 	if (unlikely(atomic_read(&bp->intr_sem) != 0))
 		return IRQ_HANDLED;
 
-	netif_rx_schedule(dev);
+	netif_rx_schedule(dev, &bp->napi);
 
 	return IRQ_HANDLED;
 }
@@ -2557,7 +2570,7 @@
 	if (unlikely(atomic_read(&bp->intr_sem) != 0))
 		return IRQ_HANDLED;
 
-	netif_rx_schedule(dev);
+	netif_rx_schedule(dev, &bp->napi);
 
 	return IRQ_HANDLED;
 }
@@ -2593,9 +2606,9 @@
 	if (unlikely(atomic_read(&bp->intr_sem) != 0))
 		return IRQ_HANDLED;
 
-	if (netif_rx_schedule_prep(dev)) {
+	if (netif_rx_schedule_prep(dev, &bp->napi)) {
 		bp->last_status_idx = sblk->status_idx;
-		__netif_rx_schedule(dev);
+		__netif_rx_schedule(dev, &bp->napi);
 	}
 
 	return IRQ_HANDLED;
@@ -2620,10 +2633,8 @@
 	return 0;
 }
 
-static int
-bnx2_poll(struct net_device *dev, int *budget)
+static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget)
 {
-	struct bnx2 *bp = netdev_priv(dev);
 	struct status_block *sblk = bp->status_blk;
 	u32 status_attn_bits = sblk->status_attn_bits;
 	u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
@@ -2641,44 +2652,54 @@
 		REG_RD(bp, BNX2_HC_COMMAND);
 	}
 
-	if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
+	if (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
 		bnx2_tx_int(bp);
 
-	if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) {
-		int orig_budget = *budget;
-		int work_done;
+	if (sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons)
+		work_done += bnx2_rx_int(bp, budget - work_done);
 
-		if (orig_budget > dev->quota)
-			orig_budget = dev->quota;
+	return work_done;
+}
 
-		work_done = bnx2_rx_int(bp, orig_budget);
-		*budget -= work_done;
-		dev->quota -= work_done;
-	}
+static int bnx2_poll(struct napi_struct *napi, int budget)
+{
+	struct bnx2 *bp = container_of(napi, struct bnx2, napi);
+	int work_done = 0;
+	struct status_block *sblk = bp->status_blk;
 
-	bp->last_status_idx = bp->status_blk->status_idx;
-	rmb();
+	while (1) {
+		work_done = bnx2_poll_work(bp, work_done, budget);
 
-	if (!bnx2_has_work(bp)) {
-		netif_rx_complete(dev);
-		if (likely(bp->flags & USING_MSI_FLAG)) {
+		if (unlikely(work_done >= budget))
+			break;
+
+		/* bp->last_status_idx is used below to tell the hw how
+		 * much work has been processed, so we must read it before
+		 * checking for more work.
+		 */
+		bp->last_status_idx = sblk->status_idx;
+		rmb();
+		if (likely(!bnx2_has_work(bp))) {
+			netif_rx_complete(bp->dev, napi);
+			if (likely(bp->flags & USING_MSI_FLAG)) {
+				REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
+				       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+				       bp->last_status_idx);
+				break;
+			}
+			REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
+			       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
+			       BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
+			       bp->last_status_idx);
+
 			REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
 			       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
 			       bp->last_status_idx);
-			return 0;
+			break;
 		}
-		REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
-		       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
-		       BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
-		       bp->last_status_idx);
-
-		REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
-		       BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
-		       bp->last_status_idx);
-		return 0;
 	}
 
-	return 1;
+	return work_done;
 }
 
 /* Called with rtnl_lock from vlan functions and also netif_tx_lock
@@ -2756,92 +2777,6 @@
 	spin_unlock_bh(&bp->phy_lock);
 }
 
-#define FW_BUF_SIZE	0x8000
-
-static int
-bnx2_gunzip_init(struct bnx2 *bp)
-{
-	if ((bp->gunzip_buf = vmalloc(FW_BUF_SIZE)) == NULL)
-		goto gunzip_nomem1;
-
-	if ((bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL)) == NULL)
-		goto gunzip_nomem2;
-
-	bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
-	if (bp->strm->workspace == NULL)
-		goto gunzip_nomem3;
-
-	return 0;
-
-gunzip_nomem3:
-	kfree(bp->strm);
-	bp->strm = NULL;
-
-gunzip_nomem2:
-	vfree(bp->gunzip_buf);
-	bp->gunzip_buf = NULL;
-
-gunzip_nomem1:
-	printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for "
-			    "uncompression.\n", bp->dev->name);
-	return -ENOMEM;
-}
-
-static void
-bnx2_gunzip_end(struct bnx2 *bp)
-{
-	kfree(bp->strm->workspace);
-
-	kfree(bp->strm);
-	bp->strm = NULL;
-
-	if (bp->gunzip_buf) {
-		vfree(bp->gunzip_buf);
-		bp->gunzip_buf = NULL;
-	}
-}
-
-static int
-bnx2_gunzip(struct bnx2 *bp, u8 *zbuf, int len, void **outbuf, int *outlen)
-{
-	int n, rc;
-
-	/* check gzip header */
-	if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED))
-		return -EINVAL;
-
-	n = 10;
-
-#define FNAME	0x8
-	if (zbuf[3] & FNAME)
-		while ((zbuf[n++] != 0) && (n < len));
-
-	bp->strm->next_in = zbuf + n;
-	bp->strm->avail_in = len - n;
-	bp->strm->next_out = bp->gunzip_buf;
-	bp->strm->avail_out = FW_BUF_SIZE;
-
-	rc = zlib_inflateInit2(bp->strm, -MAX_WBITS);
-	if (rc != Z_OK)
-		return rc;
-
-	rc = zlib_inflate(bp->strm, Z_FINISH);
-
-	*outlen = FW_BUF_SIZE - bp->strm->avail_out;
-	*outbuf = bp->gunzip_buf;
-
-	if ((rc != Z_OK) && (rc != Z_STREAM_END))
-		printk(KERN_ERR PFX "%s: Firmware decompression error: %s\n",
-		       bp->dev->name, bp->strm->msg);
-
-	zlib_inflateEnd(bp->strm);
-
-	if (rc == Z_STREAM_END)
-		return 0;
-
-	return rc;
-}
-
 static void
 load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
 	u32 rv2p_proc)
@@ -2891,19 +2826,13 @@
 	/* Load the Text area. */
 	offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
 	if (fw->gz_text) {
-		u32 text_len;
-		void *text;
-
-		rc = bnx2_gunzip(bp, fw->gz_text, fw->gz_text_len, &text,
-				 &text_len);
-		if (rc)
-			return rc;
-
-		fw->text = text;
-	}
-	if (fw->gz_text) {
 		int j;
 
+		rc = zlib_inflate_blob(fw->text, FW_BUF_SIZE, fw->gz_text,
+				       fw->gz_text_len);
+		if (rc < 0)
+			return rc;
+
 		for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
 			REG_WR_IND(bp, offset, cpu_to_le32(fw->text[j]));
 	        }
@@ -2921,21 +2850,21 @@
 
 	/* Load the SBSS area. */
 	offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base);
-	if (fw->sbss) {
+	if (fw->sbss_len) {
 		int j;
 
 		for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) {
-			REG_WR_IND(bp, offset, fw->sbss[j]);
+			REG_WR_IND(bp, offset, 0);
 		}
 	}
 
 	/* Load the BSS area. */
 	offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base);
-	if (fw->bss) {
+	if (fw->bss_len) {
 		int j;
 
 		for (j = 0; j < (fw->bss_len/4); j++, offset += 4) {
-			REG_WR_IND(bp, offset, fw->bss[j]);
+			REG_WR_IND(bp, offset, 0);
 		}
 	}
 
@@ -2968,27 +2897,24 @@
 {
 	struct cpu_reg cpu_reg;
 	struct fw_info *fw;
-	int rc = 0;
+	int rc;
 	void *text;
-	u32 text_len;
-
-	if ((rc = bnx2_gunzip_init(bp)) != 0)
-		return rc;
 
 	/* Initialize the RV2P processor. */
-	rc = bnx2_gunzip(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), &text,
-			 &text_len);
-	if (rc)
+	text = vmalloc(FW_BUF_SIZE);
+	if (!text)
+		return -ENOMEM;
+	rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1));
+	if (rc < 0)
 		goto init_cpu_err;
 
-	load_rv2p_fw(bp, text, text_len, RV2P_PROC1);
+	load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC1);
 
-	rc = bnx2_gunzip(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), &text,
-			 &text_len);
-	if (rc)
+	rc = zlib_inflate_blob(text, FW_BUF_SIZE, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2));
+	if (rc < 0)
 		goto init_cpu_err;
 
-	load_rv2p_fw(bp, text, text_len, RV2P_PROC2);
+	load_rv2p_fw(bp, text, rc /* == len */, RV2P_PROC2);
 
 	/* Initialize the RX Processor. */
 	cpu_reg.mode = BNX2_RXP_CPU_MODE;
@@ -3009,6 +2935,7 @@
 	else
 		fw = &bnx2_rxp_fw_06;
 
+	fw->text = text;
 	rc = load_cpu_fw(bp, &cpu_reg, fw);
 	if (rc)
 		goto init_cpu_err;
@@ -3032,6 +2959,7 @@
 	else
 		fw = &bnx2_txp_fw_06;
 
+	fw->text = text;
 	rc = load_cpu_fw(bp, &cpu_reg, fw);
 	if (rc)
 		goto init_cpu_err;
@@ -3055,6 +2983,7 @@
 	else
 		fw = &bnx2_tpat_fw_06;
 
+	fw->text = text;
 	rc = load_cpu_fw(bp, &cpu_reg, fw);
 	if (rc)
 		goto init_cpu_err;
@@ -3078,6 +3007,7 @@
 	else
 		fw = &bnx2_com_fw_06;
 
+	fw->text = text;
 	rc = load_cpu_fw(bp, &cpu_reg, fw);
 	if (rc)
 		goto init_cpu_err;
@@ -3099,12 +3029,13 @@
 	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
 		fw = &bnx2_cp_fw_09;
 
+		fw->text = text;
 		rc = load_cpu_fw(bp, &cpu_reg, fw);
 		if (rc)
 			goto init_cpu_err;
 	}
 init_cpu_err:
-	bnx2_gunzip_end(bp);
+	vfree(text);
 	return rc;
 }
 
@@ -3289,7 +3220,7 @@
 	val = REG_RD(bp, BNX2_MISC_CFG);
 	REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
 
-	if (!bp->flash_info->buffered) {
+	if (bp->flash_info->flags & BNX2_NV_WREN) {
 		int j;
 
 		REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
@@ -3349,7 +3280,7 @@
 	u32 cmd;
 	int j;
 
-	if (bp->flash_info->buffered)
+	if (bp->flash_info->flags & BNX2_NV_BUFFERED)
 		/* Buffered flash, no erase needed */
 		return 0;
 
@@ -3392,8 +3323,8 @@
 	/* Build the command word. */
 	cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
 
-	/* Calculate an offset of a buffered flash. */
-	if (bp->flash_info->buffered) {
+	/* Calculate an offset of a buffered flash, not needed for 5709. */
+	if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
 		offset = ((offset / bp->flash_info->page_size) <<
 			   bp->flash_info->page_bits) +
 			  (offset % bp->flash_info->page_size);
@@ -3439,8 +3370,8 @@
 	/* Build the command word. */
 	cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
 
-	/* Calculate an offset of a buffered flash. */
-	if (bp->flash_info->buffered) {
+	/* Calculate an offset of a buffered flash, not needed for 5709. */
+	if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
 		offset = ((offset / bp->flash_info->page_size) <<
 			  bp->flash_info->page_bits) +
 			 (offset % bp->flash_info->page_size);
@@ -3478,15 +3409,19 @@
 bnx2_init_nvram(struct bnx2 *bp)
 {
 	u32 val;
-	int j, entry_count, rc;
+	int j, entry_count, rc = 0;
 	struct flash_spec *flash;
 
+	if (CHIP_NUM(bp) == CHIP_NUM_5709) {
+		bp->flash_info = &flash_5709;
+		goto get_flash_size;
+	}
+
 	/* Determine the selected interface. */
 	val = REG_RD(bp, BNX2_NVM_CFG1);
 
-	entry_count = sizeof(flash_table) / sizeof(struct flash_spec);
+	entry_count = ARRAY_SIZE(flash_table);
 
-	rc = 0;
 	if (val & 0x40000000) {
 
 		/* Flash interface has been reconfigured */
@@ -3542,6 +3477,7 @@
 		return -ENODEV;
 	}
 
+get_flash_size:
 	val = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG2);
 	val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
 	if (val)
@@ -3706,7 +3642,7 @@
 		buf = align_buf;
 	}
 
-	if (bp->flash_info->buffered == 0) {
+	if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
 		flash_buffer = kmalloc(264, GFP_KERNEL);
 		if (flash_buffer == NULL) {
 			rc = -ENOMEM;
@@ -3739,7 +3675,7 @@
 		bnx2_enable_nvram_access(bp);
 
 		cmd_flags = BNX2_NVM_COMMAND_FIRST;
-		if (bp->flash_info->buffered == 0) {
+		if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
 			int j;
 
 			/* Read the whole page into the buffer
@@ -3767,7 +3703,7 @@
 		/* Loop to write back the buffer data from page_start to
 		 * data_start */
 		i = 0;
-		if (bp->flash_info->buffered == 0) {
+		if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
 			/* Erase the page */
 			if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
 				goto nvram_write_end;
@@ -3791,7 +3727,7 @@
 		/* Loop to write the new data from data_start to data_end */
 		for (addr = data_start; addr < data_end; addr += 4, i += 4) {
 			if ((addr == page_end - 4) ||
-				((bp->flash_info->buffered) &&
+				((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
 				 (addr == data_end - 4))) {
 
 				cmd_flags |= BNX2_NVM_COMMAND_LAST;
@@ -3808,7 +3744,7 @@
 
 		/* Loop to write back the buffer data from data_end
 		 * to page_end */
-		if (bp->flash_info->buffered == 0) {
+		if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
 			for (addr = data_end; addr < page_end;
 				addr += 4, i += 4) {
 
@@ -3856,12 +3792,6 @@
 		return;
 
 	if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) {
-		if (netif_running(bp->dev)) {
-			val = BNX2_DRV_ACK_CAP_SIGNATURE |
-			      BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
-			REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_ACK_CAP_MB,
-				   val);
-		}
 		bp->phy_flags |= REMOTE_PHY_CAP_FLAG;
 
 		val = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
@@ -3869,6 +3799,22 @@
 			bp->phy_port = PORT_FIBRE;
 		else
 			bp->phy_port = PORT_TP;
+
+		if (netif_running(bp->dev)) {
+			u32 sig;
+
+			if (val & BNX2_LINK_STATUS_LINK_UP) {
+				bp->link_up = 1;
+				netif_carrier_on(bp->dev);
+			} else {
+				bp->link_up = 0;
+				netif_carrier_off(bp->dev);
+			}
+			sig = BNX2_DRV_ACK_CAP_SIGNATURE |
+			      BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
+			REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_ACK_CAP_MB,
+				   sig);
+		}
 	}
 }
 
@@ -3877,6 +3823,7 @@
 {
 	u32 val;
 	int i, rc = 0;
+	u8 old_port;
 
 	/* Wait for the current PCI transaction to complete before
 	 * issuing a reset. */
@@ -3918,11 +3865,13 @@
 		/* Chip reset. */
 		REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
 
+		/* Reading back any register after chip reset will hang the
+		 * bus on 5706 A0 and A1.  The msleep below provides plenty
+		 * of margin for write posting.
+		 */
 		if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
-		    (CHIP_ID(bp) == CHIP_ID_5706_A1)) {
-			current->state = TASK_UNINTERRUPTIBLE;
-			schedule_timeout(HZ / 50);
-		}
+		    (CHIP_ID(bp) == CHIP_ID_5706_A1))
+			msleep(20);
 
 		/* Reset takes approximate 30 usec */
 		for (i = 0; i < 10; i++) {
@@ -3953,8 +3902,9 @@
 		return rc;
 
 	spin_lock_bh(&bp->phy_lock);
+	old_port = bp->phy_port;
 	bnx2_init_remote_phy(bp);
-	if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+	if ((bp->phy_flags & REMOTE_PHY_CAP_FLAG) && old_port != bp->phy_port)
 		bnx2_set_default_remote_link(bp);
 	spin_unlock_bh(&bp->phy_lock);
 
@@ -4107,7 +4057,7 @@
 	if (CHIP_NUM(bp) == CHIP_NUM_5708)
 		REG_WR(bp, BNX2_HC_STATS_TICKS, 0);
 	else
-		REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks & 0xffff00);
+		REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks);
 	REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8);  /* 3ms */
 
 	if (CHIP_ID(bp) == CHIP_ID_5706_A1)
@@ -4127,10 +4077,6 @@
 
 	REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
 
-	if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
-	    BNX2_PORT_FEATURE_ASF_ENABLED)
-		bp->flags |= ASF_ENABLE_FLAG;
-
 	/* Initialize the receive filter. */
 	bnx2_set_rx_mode(bp->dev);
 
@@ -4647,6 +4593,9 @@
 		bnx2_set_mac_loopback(bp);
 	}
 	else if (loopback_mode == BNX2_PHY_LOOPBACK) {
+		if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
+			return 0;
+
 		bp->loopback = PHY_LOOPBACK;
 		bnx2_set_phy_loopback(bp);
 	}
@@ -4815,6 +4764,11 @@
 {
 	u32 bmsr;
 
+	if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
+		if (bp->link_up)
+			return 0;
+		return -ENODEV;
+	}
 	spin_lock_bh(&bp->phy_lock);
 	bnx2_enable_bmsr1(bp);
 	bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
@@ -5025,6 +4979,8 @@
 	if (rc)
 		return rc;
 
+	napi_enable(&bp->napi);
+
 	if ((bp->flags & MSI_CAP_FLAG) && !disable_msi) {
 		if (pci_enable_msi(bp->pdev) == 0) {
 			bp->flags |= USING_MSI_FLAG;
@@ -5035,6 +4991,7 @@
 	rc = bnx2_request_irq(bp);
 
 	if (rc) {
+		napi_disable(&bp->napi);
 		bnx2_free_mem(bp);
 		return rc;
 	}
@@ -5042,6 +4999,7 @@
 	rc = bnx2_init_nic(bp);
 
 	if (rc) {
+		napi_disable(&bp->napi);
 		bnx2_free_irq(bp);
 		bnx2_free_skbs(bp);
 		bnx2_free_mem(bp);
@@ -5074,6 +5032,7 @@
 				rc = bnx2_request_irq(bp);
 
 			if (rc) {
+				napi_disable(&bp->napi);
 				bnx2_free_skbs(bp);
 				bnx2_free_mem(bp);
 				del_timer_sync(&bp->timer);
@@ -5287,7 +5246,8 @@
 	while (bp->in_reset_task)
 		msleep(1);
 
-	bnx2_netif_stop(bp);
+	bnx2_disable_int_sync(bp);
+	napi_disable(&bp->napi);
 	del_timer_sync(&bp->timer);
 	if (bp->flags & NO_WOL_FLAG)
 		reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
@@ -5786,8 +5746,9 @@
 		if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
 			bp->stats_ticks = USEC_PER_SEC;
 	}
-	if (bp->stats_ticks > 0xffff00) bp->stats_ticks = 0xffff00;
-	bp->stats_ticks &= 0xffff00;
+	if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS)
+		bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
+	bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
 
 	if (netif_running(bp->dev)) {
 		bnx2_netif_stop(bp);
@@ -6055,9 +6016,16 @@
 };
 
 static int
-bnx2_self_test_count(struct net_device *dev)
+bnx2_get_sset_count(struct net_device *dev, int sset)
 {
-	return BNX2_NUM_TESTS;
+	switch (sset) {
+	case ETH_SS_TEST:
+		return BNX2_NUM_TESTS;
+	case ETH_SS_STATS:
+		return BNX2_NUM_STATS;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void
@@ -6131,12 +6099,6 @@
 	}
 }
 
-static int
-bnx2_get_stats_count(struct net_device *dev)
-{
-	return BNX2_NUM_STATS;
-}
-
 static void
 bnx2_get_ethtool_stats(struct net_device *dev,
 		struct ethtool_stats *stats, u64 *buf)
@@ -6244,19 +6206,14 @@
 	.set_pauseparam		= bnx2_set_pauseparam,
 	.get_rx_csum		= bnx2_get_rx_csum,
 	.set_rx_csum		= bnx2_set_rx_csum,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
 	.set_tx_csum		= bnx2_set_tx_csum,
-	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
-	.get_tso		= ethtool_op_get_tso,
 	.set_tso		= bnx2_set_tso,
-	.self_test_count	= bnx2_self_test_count,
 	.self_test		= bnx2_self_test,
 	.get_strings		= bnx2_get_strings,
 	.phys_id		= bnx2_phys_id,
-	.get_stats_count	= bnx2_get_stats_count,
 	.get_ethtool_stats	= bnx2_get_ethtool_stats,
-	.get_perm_addr		= ethtool_op_get_perm_addr,
+	.get_sset_count		= bnx2_get_sset_count,
 };
 
 /* Called with rtnl_lock */
@@ -6462,7 +6419,6 @@
 	u32 reg;
 	u64 dma_mask, persist_dma_mask;
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 	bp = netdev_priv(dev);
 
@@ -6629,6 +6585,21 @@
 		if (i != 2)
 			bp->fw_version[j++] = '.';
 	}
+	reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE);
+	if (reg & BNX2_PORT_FEATURE_WOL_ENABLED)
+		bp->wol = 1;
+
+	if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) {
+		bp->flags |= ASF_ENABLE_FLAG;
+
+		for (i = 0; i < 30; i++) {
+			reg = REG_RD_IND(bp, bp->shmem_base +
+					     BNX2_BC_STATE_CONDITION);
+			if (reg & BNX2_CONDITION_MFW_RUN_MASK)
+				break;
+			msleep(10);
+		}
+	}
 	reg = REG_RD_IND(bp, bp->shmem_base + BNX2_BC_STATE_CONDITION);
 	reg &= BNX2_CONDITION_MFW_RUN_MASK;
 	if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
@@ -6672,7 +6643,7 @@
 	bp->rx_ticks_int = 18;
 	bp->rx_ticks = 18;
 
-	bp->stats_ticks = 1000000 & 0xffff00;
+	bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
 
 	bp->timer_interval =  HZ;
 	bp->current_interval =  HZ;
@@ -6688,11 +6659,14 @@
 	bp->phy_port = PORT_TP;
 	if (bp->phy_flags & PHY_SERDES_FLAG) {
 		bp->phy_port = PORT_FIBRE;
-		bp->flags |= NO_WOL_FLAG;
+		reg = REG_RD_IND(bp, bp->shmem_base +
+				     BNX2_SHARED_HW_CFG_CONFIG);
+		if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) {
+			bp->flags |= NO_WOL_FLAG;
+			bp->wol = 0;
+		}
 		if (CHIP_NUM(bp) != CHIP_NUM_5706) {
 			bp->phy_addr = 2;
-			reg = REG_RD_IND(bp, bp->shmem_base +
-					 BNX2_SHARED_HW_CFG_CONFIG);
 			if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
 				bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG;
 		}
@@ -6701,13 +6675,16 @@
 	} else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
 		   CHIP_NUM(bp) == CHIP_NUM_5708)
 		bp->phy_flags |= PHY_CRC_FIX_FLAG;
-	else if (CHIP_ID(bp) == CHIP_ID_5709_A0)
+	else if (CHIP_ID(bp) == CHIP_ID_5709_A0 ||
+		 CHIP_ID(bp) == CHIP_ID_5709_A1)
 		bp->phy_flags |= PHY_DIS_EARLY_DAC_FLAG;
 
 	if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
 	    (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
-	    (CHIP_ID(bp) == CHIP_ID_5708_B1))
+	    (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
 		bp->flags |= NO_WOL_FLAG;
+		bp->wol = 0;
+	}
 
 	if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
 		bp->tx_quick_cons_trip_int =
@@ -6800,8 +6777,9 @@
 	static int version_printed = 0;
 	struct net_device *dev = NULL;
 	struct bnx2 *bp;
-	int rc, i;
+	int rc;
 	char str[40];
+	DECLARE_MAC_BUF(mac);
 
 	if (version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
@@ -6831,11 +6809,10 @@
 #ifdef BCM_VLAN
 	dev->vlan_rx_register = bnx2_vlan_rx_register;
 #endif
-	dev->poll = bnx2_poll;
 	dev->ethtool_ops = &bnx2_ethtool_ops;
-	dev->weight = 64;
 
 	bp = netdev_priv(dev);
+	netif_napi_add(dev, &bp->napi, bnx2_poll, 64);
 
 #if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
 	dev->poll_controller = poll_bnx2;
@@ -6870,19 +6847,14 @@
 	}
 
 	printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
-		"IRQ %d, ",
+		"IRQ %d, node addr %s\n",
 		dev->name,
 		bp->name,
 		((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
 		((CHIP_ID(bp) & 0x0ff0) >> 4),
 		bnx2_bus_string(bp, str),
 		dev->base_addr,
-		bp->pdev->irq);
-
-	printk("node addr ");
-	for (i = 0; i < 6; i++)
-		printk("%2.2x", dev->dev_addr[i]);
-	printk("\n");
+		bp->pdev->irq, print_mac(mac, dev->dev_addr));
 
 	return 0;
 }
@@ -6913,6 +6885,11 @@
 	struct bnx2 *bp = netdev_priv(dev);
 	u32 reset_code;
 
+	/* PCI register 4 needs to be saved whether netif_running() or not.
+	 * MSI address and data need to be saved if using MSI and
+	 * netif_running().
+	 */
+	pci_save_state(pdev);
 	if (!netif_running(dev))
 		return 0;
 
@@ -6928,7 +6905,6 @@
 		reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
 	bnx2_reset_chip(bp, reset_code);
 	bnx2_free_skbs(bp);
-	pci_save_state(pdev);
 	bnx2_set_power_state(bp, pci_choose_state(pdev, state));
 	return 0;
 }
@@ -6939,10 +6915,10 @@
 	struct net_device *dev = pci_get_drvdata(pdev);
 	struct bnx2 *bp = netdev_priv(dev);
 
+	pci_restore_state(pdev);
 	if (!netif_running(dev))
 		return 0;
 
-	pci_restore_state(pdev);
 	bnx2_set_power_state(bp, PCI_D0);
 	netif_device_attach(dev);
 	bnx2_init_nic(bp);
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index d8cd1af..1dce0d1 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -6433,6 +6433,11 @@
 #define ST_MICRO_FLASH_PAGE_SIZE		256
 #define ST_MICRO_FLASH_BASE_TOTAL_SIZE		65536
 
+#define BCM5709_FLASH_PAGE_BITS			8
+#define BCM5709_FLASH_PHY_PAGE_SIZE		(1 << BCM5709_FLASH_PAGE_BITS)
+#define BCM5709_FLASH_BYTE_ADDR_MASK		(BCM5709_FLASH_PHY_PAGE_SIZE-1)
+#define BCM5709_FLASH_PAGE_SIZE			256
+
 #define NVRAM_TIMEOUT_COUNT			30000
 
 
@@ -6449,7 +6454,10 @@
 	u32 config2;
 	u32 config3;
 	u32 write1;
-	u32 buffered;
+	u32 flags;
+#define BNX2_NV_BUFFERED	0x00000001
+#define BNX2_NV_TRANSLATE	0x00000002
+#define BNX2_NV_WREN		0x00000004
 	u32 page_bits;
 	u32 page_size;
 	u32 addr_mask;
@@ -6465,6 +6473,8 @@
 	struct net_device	*dev;
 	struct pci_dev		*pdev;
 
+	struct napi_struct	napi;
+
 	atomic_t		intr_sem;
 
 	struct status_block	*status_blk;
@@ -6671,9 +6681,6 @@
 	u32			flash_size;
 
 	int			status_stats_size;
-
-	struct z_stream_s	*strm;
-	void			*gunzip_buf;
 };
 
 static u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset);
@@ -6745,13 +6752,11 @@
 	const u32 sbss_addr;
 	const u32 sbss_len;
 	const u32 sbss_index;
-	const u32 *sbss;
 
 	/* BSS section. */
 	const u32 bss_addr;
 	const u32 bss_len;
 	const u32 bss_index;
-	const u32 *bss;
 
 	/* Read-only section. */
 	const u32 rodata_addr;
@@ -6903,6 +6908,7 @@
 #define BNX2_SHARED_HW_CFG_LED_MODE_MAC		 0
 #define BNX2_SHARED_HW_CFG_LED_MODE_GPHY1	 0x100
 #define BNX2_SHARED_HW_CFG_LED_MODE_GPHY2	 0x200
+#define BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX	 0x8000
 
 #define BNX2_SHARED_HW_CFG_CONFIG2		0x00000040
 #define BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK	 0x00fff000
diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h
index b49f439..a6d7824 100644
--- a/drivers/net/bnx2_fw.h
+++ b/drivers/net/bnx2_fw.h
@@ -15,7 +15,8 @@
  */
 
 static u8 bnx2_COM_b06FwText[] = {
-	0x1f, 0x8b, 0x08, 0x00, 0x45, 0x30, 0xe7, 0x45, 0x00, 0x03, 0xdc, 0x5a,
+/*	0x1f, 0x8b, 0x08, 0x00, 0x45, 0x30, 0xe7, 0x45, 0x00, 0x03, */
+								    0xdc, 0x5a,
 	0x6b, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0x33, 0x3b, 0x4b, 0xae, 0xc8, 0x15,
 	0x35, 0xa2, 0xc6, 0xf4, 0x5a, 0xa2, 0xed, 0x5d, 0x72, 0x28, 0x12, 0x96,
 	0xec, 0x6e, 0x68, 0xda, 0x62, 0x8c, 0x8d, 0xb4, 0xd9, 0xa5, 0x0c, 0xa1,
@@ -1047,8 +1048,6 @@
 	0x08002bd8, 0x08002c08, 0x08002c38, 0x00000000, 0x080060cc, 0x080060cc,
 	0x080060cc, 0x080060cc, 0x080060cc, 0x08006100, 0x08006100, 0x08006140,
 	0x0800614c, 0x0800614c, 0x080060cc, 0x00000000, 0x00000000 };
-static const u32 bnx2_COM_b06FwBss[(0x88/4) + 1] = { 0x0 };
-static const u32 bnx2_COM_b06FwSbss[(0x60/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_com_fw_06 = {
 	.ver_major			= 0x3,
@@ -1071,12 +1070,10 @@
 	.sbss_addr			= 0x08007e00,
 	.sbss_len			= 0x60,
 	.sbss_index			= 0x0,
-	.sbss				= bnx2_COM_b06FwSbss,
 
 	.bss_addr			= 0x08007e60,
 	.bss_len			= 0x88,
 	.bss_index			= 0x0,
-	.bss				= bnx2_COM_b06FwBss,
 
 	.rodata_addr			= 0x08007d58,
 	.rodata_len			= 0x88,
@@ -1085,8 +1082,9 @@
 };
 
 static u8 bnx2_RXP_b06FwText[] = {
-	0x1f, 0x8b, 0x08, 0x08, 0xcb, 0xa3, 0x46, 0x45, 0x00, 0x03, 0x74, 0x65,
-	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xec, 0x5c, 0x6f, 0x6c,
+/*	0x1f, 0x8b, 0x08, 0x08, 0xcb, 0xa3, 0x46, 0x45, 0x00, 0x03, 0x74, 0x65,
+	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
+							0xec, 0x5c, 0x6f, 0x6c,
 	0x1c, 0xc7, 0x75, 0x7f, 0x3b, 0xbb, 0xa4, 0x4e, 0xd4, 0x91, 0x5c, 0x1e,
 	0x4f, 0xf4, 0x49, 0x66, 0x94, 0x5d, 0x71, 0x25, 0x5e, 0x2d, 0xc6, 0x5d,
 	0x31, 0x57, 0x9b, 0x08, 0xce, 0xf1, 0x79, 0xef, 0x64, 0xb1, 0x86, 0x0a,
@@ -1760,9 +1758,6 @@
 	0x08006030, 0x08006030, 0x08006018, 0x08006030, 0x08006030, 0x08006030,
 	0x08006024, 0x00000000, 0x00000000 };
 
-static u32 bnx2_RXP_b06FwBss[(0x13dc/4) + 1] = { 0x0 };
-static u32 bnx2_RXP_b06FwSbss[(0x2c/4) + 1] = { 0x0 };
-
 static struct fw_info bnx2_rxp_fw_06 = {
 	.ver_major			= 0x2,
 	.ver_minor			= 0x8,
@@ -1784,12 +1779,10 @@
 	.sbss_addr			= 0x080069c0,
 	.sbss_len			= 0x2c,
 	.sbss_index			= 0x0,
-	.sbss				= bnx2_RXP_b06FwSbss,
 
 	.bss_addr			= 0x080069f0,
 	.bss_len			= 0x13dc,
 	.bss_index			= 0x0,
-	.bss				= bnx2_RXP_b06FwBss,
 
 	.rodata_addr			= 0x08006728,
 	.rodata_len			= 0x278,
@@ -1798,8 +1791,9 @@
 };
 
 static u8 bnx2_rv2p_proc1[] = {
-	0x1f, 0x8b, 0x08, 0x08, 0x5e, 0xd0, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
-	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xc5, 0x56, 0xcf, 0x6b,
+/*	0x1f, 0x8b, 0x08, 0x08, 0x5e, 0xd0, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
+							0xc5, 0x56, 0xcf, 0x6b,
 	0x13, 0x51, 0x10, 0x9e, 0xec, 0x6e, 0xb2, 0xdb, 0x74, 0xbb, 0x1b, 0x2b,
 	0xda, 0xa0, 0xb1, 0x8d, 0x51, 0x6a, 0x7f, 0xa4, 0xb4, 0x11, 0x0f, 0x82,
 	0x42, 0x25, 0x3d, 0x04, 0x54, 0x44, 0x7a, 0x28, 0x22, 0x82, 0x36, 0x8a,
@@ -1877,8 +1871,9 @@
 	0x12, 0x3d, 0x80, 0x0b, 0x00, 0x00, 0x00 };
 
 static u8 bnx2_rv2p_proc2[] = {
-	0x1f, 0x8b, 0x08, 0x08, 0x7e, 0xd1, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
-	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xcd, 0x58, 0x5b, 0x6c,
+/*	0x1f, 0x8b, 0x08, 0x08, 0x7e, 0xd1, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
+							0xcd, 0x58, 0x5b, 0x6c,
 	0x54, 0x55, 0x14, 0x3d, 0xf3, 0xe8, 0xcc, 0x9d, 0xe9, 0xed, 0x9d, 0xf2,
 	0xb2, 0x03, 0xad, 0x08, 0xe5, 0xd1, 0x56, 0x29, 0xe8, 0x54, 0xab, 0x18,
 	0x15, 0x2c, 0x5a, 0x8c, 0x26, 0x68, 0xf0, 0xf9, 0x63, 0x14, 0x04, 0xda,
@@ -2057,8 +2052,9 @@
 	0x17, 0x00, 0x00, 0x00 };
 
 static u8 bnx2_TPAT_b06FwText[] = {
-	0x1f, 0x8b, 0x08, 0x08, 0x47, 0xd2, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
-	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xc5, 0x57, 0x4d, 0x68,
+/*	0x1f, 0x8b, 0x08, 0x08, 0x47, 0xd2, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
+							0xc5, 0x57, 0x4d, 0x68,
 	0x1c, 0xe7, 0x19, 0x7e, 0xe7, 0x77, 0x47, 0x62, 0x25, 0x8d, 0x93, 0x3d,
 	0xac, 0x5d, 0xa5, 0x99, 0x91, 0x46, 0x3f, 0x54, 0x26, 0x9e, 0x84, 0xa5,
 	0x56, 0x61, 0x20, 0xe3, 0x99, 0x95, 0x2c, 0x0c, 0x05, 0x07, 0x42, 0x08,
@@ -2252,8 +2248,6 @@
 
 static u32 bnx2_TPAT_b06FwData[(0x0/4) + 1] = { 0x0 };
 static u32 bnx2_TPAT_b06FwRodata[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_TPAT_b06FwBss[(0x250/4) + 1] = { 0x0 };
-static u32 bnx2_TPAT_b06FwSbss[(0x34/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_tpat_fw_06 = {
 	.ver_major			= 0x1,
@@ -2276,12 +2270,10 @@
 	.sbss_addr			= 0x08001a60,
 	.sbss_len			= 0x34,
 	.sbss_index			= 0x0,
-	.sbss				= bnx2_TPAT_b06FwSbss,
 
 	.bss_addr			= 0x08001aa0,
 	.bss_len			= 0x250,
 	.bss_index			= 0x0,
-	.bss				= bnx2_TPAT_b06FwBss,
 
 	.rodata_addr			= 0x00000000,
 	.rodata_len			= 0x0,
@@ -2290,8 +2282,9 @@
 };
 
 static u8 bnx2_TXP_b06FwText[] = {
-	0x1f, 0x8b, 0x08, 0x08, 0x21, 0xd3, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
-	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0xed, 0x5c, 0x6d, 0x6c,
+/*	0x1f, 0x8b, 0x08, 0x08, 0x21, 0xd3, 0x41, 0x44, 0x00, 0x03, 0x74, 0x65,
+	0x73, 0x74, 0x31, 0x2e, 0x62, 0x69, 0x6e, 0x00, */
+							0xed, 0x5c, 0x6d, 0x6c,
 	0x1b, 0xf7, 0x79, 0x7f, 0xee, 0x85, 0xd2, 0x51, 0x96, 0xe9, 0x93, 0xc2,
 	0x78, 0x6c, 0xc0, 0xa6, 0x77, 0xd6, 0x51, 0x66, 0x20, 0xb5, 0xa0, 0x05,
 	0x36, 0x55, 0x87, 0x43, 0x73, 0x3e, 0x52, 0x2f, 0x4e, 0x5c, 0x57, 0x71,
@@ -2708,8 +2701,6 @@
 
 static u32 bnx2_TXP_b06FwData[(0x0/4) + 1] = { 0x0 };
 static u32 bnx2_TXP_b06FwRodata[(0x0/4) + 1] = { 0x0 };
-static u32 bnx2_TXP_b06FwBss[(0x1c4/4) + 1] = { 0x0 };
-static u32 bnx2_TXP_b06FwSbss[(0x38/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_txp_fw_06 = {
 	.ver_major			= 0x1,
@@ -2732,12 +2723,10 @@
 	.sbss_addr			= 0x08005760,
 	.sbss_len			= 0x38,
 	.sbss_index			= 0x0,
-	.sbss				= bnx2_TXP_b06FwSbss,
 
 	.bss_addr			= 0x080057a0,
 	.bss_len			= 0x1c4,
 	.bss_index			= 0x0,
-	.bss				= bnx2_TXP_b06FwBss,
 
 	.rodata_addr			= 0x00000000,
 	.rodata_len			= 0x0,
diff --git a/drivers/net/bnx2_fw2.h b/drivers/net/bnx2_fw2.h
index 2c06753..5bd52be 100644
--- a/drivers/net/bnx2_fw2.h
+++ b/drivers/net/bnx2_fw2.h
@@ -15,7 +15,8 @@
  */
 
 static u8 bnx2_COM_b09FwText[] = {
-	0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xdc, 0x5b,
+/*	0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, */
+								    0xdc, 0x5b,
 	0x6d, 0x70, 0x5c, 0xd5, 0x79, 0x7e, 0xef, 0xd9, 0xbb, 0xf2, 0x5a, 0x92,
 	0xe5, 0x6b, 0x79, 0x23, 0x16, 0x4b, 0xc0, 0xae, 0x75, 0x6d, 0x69, 0xb0,
 	0x43, 0x16, 0xa1, 0x80, 0x9a, 0xd9, 0xc0, 0xb2, 0x2b, 0x33, 0x9e, 0x0c,
@@ -1045,8 +1046,6 @@
 	0x08002b3c, 0x08002b6c, 0x08002b9c, 0x00000000, 0x0800604c, 0x0800604c,
 	0x0800604c, 0x0800604c, 0x0800604c, 0x08006078, 0x08006078, 0x080060b8,
 	0x080060c4, 0x080060c4, 0x0800604c, 0x00000000, 0x00000000 };
-static const u32 bnx2_COM_b09FwBss[(0x88/4) + 1] = { 0x0 };
-static const u32 bnx2_COM_b09FwSbss[(0x60/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_com_fw_09 = {
 	.ver_major			= 0x3,
@@ -1069,12 +1068,10 @@
 	.sbss_addr			= 0x08007e60,
 	.sbss_len			= 0x60,
 	.sbss_index			= 0x0,
-	.sbss				= bnx2_COM_b09FwSbss,
 
 	.bss_addr			= 0x08007ec0,
 	.bss_len			= 0x88,
 	.bss_index			= 0x0,
-	.bss				= bnx2_COM_b09FwBss,
 
 	.rodata_addr			= 0x08007dc0,
 	.rodata_len			= 0x88,
@@ -1083,7 +1080,8 @@
 };
 
 static u8 bnx2_CP_b09FwText[] = {
-	0x1f, 0x8b, 0x08, 0x00, 0x0f, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xbd, 0x7d,
+/*	0x1f, 0x8b, 0x08, 0x00, 0x0f, 0x34, 0xe7, 0x45, 0x00, 0x03, */
+								    0xbd, 0x7d,
 	0x0d, 0x74, 0x5c, 0x57, 0x7d, 0xe7, 0xff, 0xdd, 0x19, 0x49, 0x63, 0x59,
 	0x96, 0x9f, 0xe5, 0x89, 0x32, 0x51, 0x84, 0x3d, 0x23, 0x3d, 0xd9, 0x22,
 	0x12, 0xe1, 0xc5, 0x11, 0xac, 0xda, 0x2a, 0xe9, 0x30, 0x92, 0x3f, 0x12,
@@ -2241,8 +2239,6 @@
 	0x080032e8, 0x08003300, 0x08003320, 0x08003358, 0x08003338, 0x08003338,
 	0x080050d4, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050d4, 0x080050fc,
 	0x080050fc, 0x08005124, 0x08005174, 0x08005144, 0x00000000 };
-static const u32 bnx2_CP_b09FwBss[(0x3b0/4) + 1] = { 0x0 };
-static const u32 bnx2_CP_b09FwSbss[(0xa1/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_cp_fw_09 = {
 	.ver_major			= 0x3,
@@ -2265,12 +2261,10 @@
 	.sbss_addr			= 0x08007024,
 	.sbss_len			= 0xa1,
 	.sbss_index			= 0x0,
-	.sbss				= bnx2_CP_b09FwSbss,
 
 	.bss_addr			= 0x080070d0,
 	.bss_len			= 0x3b0,
 	.bss_index			= 0x0,
-	.bss				= bnx2_CP_b09FwBss,
 
 	.rodata_addr			= 0x08006ee8,
 	.rodata_len			= 0x118,
@@ -2279,7 +2273,8 @@
 };
 
 static u8 bnx2_RXP_b09FwText[] = {
-	0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xec, 0x5c,
+/*	0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, */
+								    0xec, 0x5c,
 	0x5d, 0x6c, 0x1c, 0xd7, 0x75, 0x3e, 0xf3, 0x43, 0x6a, 0x49, 0xf1, 0x67,
 	0xb8, 0x5c, 0xb1, 0x2b, 0x99, 0x96, 0x77, 0xc9, 0x91, 0xc8, 0x58, 0x8a,
 	0x31, 0xa2, 0x09, 0x5b, 0x48, 0x17, 0xf6, 0x76, 0x76, 0x25, 0xb1, 0xb1,
@@ -2950,8 +2945,6 @@
 	0x08006058, 0x08006070, 0x08006070, 0x08006070, 0x08006058, 0x08006070,
 	0x08006070, 0x08006070, 0x08006058, 0x08006070, 0x08006070, 0x08006070,
 	0x08006064, 0x00000000, 0x00000000 };
-static const u32 bnx2_RXP_b09FwBss[(0x13dc/4) + 1] = { 0x0 };
-static const u32 bnx2_RXP_b09FwSbss[(0x20/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_rxp_fw_09 = {
 	.ver_major			= 0x3,
@@ -2974,12 +2967,10 @@
 	.sbss_addr			= 0x08006a00,
 	.sbss_len			= 0x20,
 	.sbss_index			= 0x0,
-	.sbss				= bnx2_RXP_b09FwSbss,
 
 	.bss_addr			= 0x08006a20,
 	.bss_len			= 0x13dc,
 	.bss_index			= 0x0,
-	.bss				= bnx2_RXP_b09FwBss,
 
 	.rodata_addr			= 0x08006768,
 	.rodata_len			= 0x278,
@@ -2988,7 +2979,8 @@
 };
 
 static u8 bnx2_TPAT_b09FwText[] = {
-	0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xcd, 0x58,
+/*	0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, */
+								    0xcd, 0x58,
 	0x5d, 0x68, 0x1c, 0xd7, 0x15, 0x3e, 0xf3, 0xb7, 0x3b, 0x52, 0x24, 0xeb,
 	0x5a, 0xd9, 0xa6, 0xeb, 0xa0, 0x34, 0x33, 0xda, 0x91, 0xac, 0x22, 0x13,
 	0x4f, 0x9d, 0x25, 0x16, 0x65, 0x21, 0x93, 0xd9, 0x91, 0xac, 0x98, 0x3c,
@@ -3241,8 +3233,6 @@
 
 static const u32 bnx2_TPAT_b09FwData[(0x0/4) + 1] = { 0x0 };
 static const u32 bnx2_TPAT_b09FwRodata[(0x0/4) + 1] = { 0x0 };
-static const u32 bnx2_TPAT_b09FwBss[(0x850/4) + 1] = { 0x0 };
-static const u32 bnx2_TPAT_b09FwSbss[(0x2c/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_tpat_fw_09 = {
 	.ver_major			= 0x3,
@@ -3265,12 +3255,10 @@
 	.sbss_addr			= 0x08002088,
 	.sbss_len			= 0x2c,
 	.sbss_index			= 0x0,
-	.sbss				= bnx2_TPAT_b09FwSbss,
 
 	.bss_addr			= 0x080020c0,
 	.bss_len			= 0x850,
 	.bss_index			= 0x0,
-	.bss				= bnx2_TPAT_b09FwBss,
 
 	.rodata_addr			= 0x00000000,
 	.rodata_len			= 0x0,
@@ -3279,7 +3267,8 @@
 };
 
 static u8 bnx2_TXP_b09FwText[] = {
-	0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, 0xcd, 0x7c,
+/*	0x1f, 0x8b, 0x08, 0x00, 0x0e, 0x34, 0xe7, 0x45, 0x00, 0x03, */
+								    0xcd, 0x7c,
 	0x6f, 0x70, 0x5b, 0xd7, 0x95, 0xdf, 0x79, 0xef, 0x81, 0x24, 0x48, 0xd1,
 	0xd4, 0x13, 0x17, 0x56, 0x60, 0x87, 0x71, 0x00, 0xf1, 0x81, 0x66, 0x42,
 	0xae, 0x04, 0x2b, 0x4c, 0xc2, 0x6d, 0xd1, 0xf8, 0x05, 0x00, 0x29, 0x48,
@@ -4055,8 +4044,6 @@
 	0x08004060, 0x0800408c, 0x080040d4, 0x080040d4, 0x08003f60, 0x08003f8c,
 	0x08003f8c, 0x080040d4, 0x080040d4, 0x080040d4, 0x08003ff4, 0x00000000,
 	0x00000000 };
-static const u32 bnx2_TXP_b09FwBss[(0xa20/4) + 1] = { 0x0 };
-static const u32 bnx2_TXP_b09FwSbss[(0x8c/4) + 1] = { 0x0 };
 
 static struct fw_info bnx2_txp_fw_09 = {
 	.ver_major			= 0x3,
@@ -4079,12 +4066,10 @@
 	.sbss_addr			= 0x08004750,
 	.sbss_len			= 0x8c,
 	.sbss_index			= 0x0,
-	.sbss				= bnx2_TXP_b09FwSbss,
 
 	.bss_addr			= 0x080047e0,
 	.bss_len			= 0xa20,
 	.bss_index			= 0x0,
-	.bss				= bnx2_TXP_b09FwBss,
 
 	.rodata_addr			= 0x08004638,
 	.rodata_len			= 0x30,
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index f829e4a..7a045a3 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -29,6 +29,7 @@
 #include <linux/ethtool.h>
 #include <linux/if_bonding.h>
 #include <linux/pkt_sched.h>
+#include <net/net_namespace.h>
 #include "bonding.h"
 #include "bond_3ad.h"
 
@@ -100,7 +101,6 @@
 static u8 __get_duplex(struct port *port);
 static inline void __initialize_port_locks(struct port *port);
 //conversions
-static void __htons_lacpdu(struct lacpdu *lacpdu);
 static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par);
 
 
@@ -419,26 +419,6 @@
 }
 
 //conversions
-/**
- * __htons_lacpdu - convert the contents of a LACPDU to network byte order
- * @lacpdu: the speicifed lacpdu
- *
- * For each multi-byte field in the lacpdu, convert its content
- */
-static void __htons_lacpdu(struct lacpdu *lacpdu)
-{
-	if (lacpdu) {
-		lacpdu->actor_system_priority =   htons(lacpdu->actor_system_priority);
-		lacpdu->actor_key =               htons(lacpdu->actor_key);
-		lacpdu->actor_port_priority =     htons(lacpdu->actor_port_priority);
-		lacpdu->actor_port =              htons(lacpdu->actor_port);
-		lacpdu->partner_system_priority = htons(lacpdu->partner_system_priority);
-		lacpdu->partner_key =             htons(lacpdu->partner_key);
-		lacpdu->partner_port_priority =   htons(lacpdu->partner_port_priority);
-		lacpdu->partner_port =            htons(lacpdu->partner_port);
-		lacpdu->collector_max_delay =     htons(lacpdu->collector_max_delay);
-	}
-}
 
 /**
  * __ad_timer_to_ticks - convert a given timer type to AD module ticks
@@ -826,11 +806,11 @@
 	 * lacpdu->actor_information_length  initialized
 	 */
 
-	lacpdu->actor_system_priority = port->actor_system_priority;
+	lacpdu->actor_system_priority = htons(port->actor_system_priority);
 	lacpdu->actor_system = port->actor_system;
-	lacpdu->actor_key = port->actor_oper_port_key;
-	lacpdu->actor_port_priority = port->actor_port_priority;
-	lacpdu->actor_port = port->actor_port_number;
+	lacpdu->actor_key = htons(port->actor_oper_port_key);
+	lacpdu->actor_port_priority = htons(port->actor_port_priority);
+	lacpdu->actor_port = htons(port->actor_port_number);
 	lacpdu->actor_state = port->actor_oper_port_state;
 
 	/* lacpdu->reserved_3_1              initialized
@@ -838,11 +818,11 @@
 	 * lacpdu->partner_information_length initialized
 	 */
 
-	lacpdu->partner_system_priority = port->partner_oper_system_priority;
+	lacpdu->partner_system_priority = htons(port->partner_oper_system_priority);
 	lacpdu->partner_system = port->partner_oper_system;
-	lacpdu->partner_key = port->partner_oper_key;
-	lacpdu->partner_port_priority = port->partner_oper_port_priority;
-	lacpdu->partner_port = port->partner_oper_port_number;
+	lacpdu->partner_key = htons(port->partner_oper_key);
+	lacpdu->partner_port_priority = htons(port->partner_oper_port_priority);
+	lacpdu->partner_port = htons(port->partner_oper_port_number);
 	lacpdu->partner_state = port->partner_oper_port_state;
 
 	/* lacpdu->reserved_3_2              initialized
@@ -854,9 +834,6 @@
 	 * terminator_length                 initialized
 	 * reserved_50[50]                   initialized
 	 */
-
-	/* Convert all non u8 parameters to Big Endian for transmit */
-	__htons_lacpdu(lacpdu);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////
@@ -1833,7 +1810,7 @@
 	}
 	lacpdu->tlv_type_collector_info = 0x03;
 	lacpdu->collector_information_length= 0x10;
-	lacpdu->collector_max_delay = AD_COLLECTOR_MAX_DELAY;
+	lacpdu->collector_max_delay = htons(AD_COLLECTOR_MAX_DELAY);
 	for (index=0; index<=11; index++) {
 		lacpdu->reserved_12[index]=0;
 	}
@@ -2448,6 +2425,9 @@
 	struct slave *slave = NULL;
 	int ret = NET_RX_DROP;
 
+	if (dev->nd_net != &init_net)
+		goto out;
+
 	if (!(dev->flags & IFF_MASTER))
 		goto out;
 
diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h
index 6ad5ad6..862952f 100644
--- a/drivers/net/bonding/bond_3ad.h
+++ b/drivers/net/bonding/bond_3ad.h
@@ -108,7 +108,7 @@
 typedef struct ad_header {
 	struct mac_addr destination_address;
 	struct mac_addr source_address;
-	u16 length_type;
+	__be16 length_type;
 } ad_header_t;
 
 // Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard)
@@ -117,25 +117,25 @@
 	u8 version_number;
 	u8 tlv_type_actor_info;	      // = actor information(type/length/value)
 	u8 actor_information_length; // = 20
-	u16 actor_system_priority;
+	__be16 actor_system_priority;
 	struct mac_addr actor_system;
-	u16 actor_key;
-	u16 actor_port_priority;
-	u16 actor_port;
+	__be16 actor_key;
+	__be16 actor_port_priority;
+	__be16 actor_port;
 	u8 actor_state;
 	u8 reserved_3_1[3];	     // = 0
 	u8 tlv_type_partner_info;     // = partner information
 	u8 partner_information_length;	 // = 20
-	u16 partner_system_priority;
+	__be16 partner_system_priority;
 	struct mac_addr partner_system;
-	u16 partner_key;
-	u16 partner_port_priority;
-	u16 partner_port;
+	__be16 partner_key;
+	__be16 partner_port_priority;
+	__be16 partner_port;
 	u8 partner_state;
 	u8 reserved_3_2[3];	     // = 0
 	u8 tlv_type_collector_info;	  // = collector information
 	u8 collector_information_length; // = 16
-	u16 collector_max_delay;
+	__be16 collector_max_delay;
 	u8 reserved_12[12];
 	u8 tlv_type_terminator;	     // = terminator
 	u8 terminator_length;	     // = 0
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 92c3b6f..aea2217 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -87,20 +87,20 @@
 struct learning_pkt {
 	u8 mac_dst[ETH_ALEN];
 	u8 mac_src[ETH_ALEN];
-	u16 type;
+	__be16 type;
 	u8 padding[ETH_ZLEN - ETH_HLEN];
 };
 
 struct arp_pkt {
-	u16     hw_addr_space;
-	u16     prot_addr_space;
+	__be16  hw_addr_space;
+	__be16  prot_addr_space;
 	u8      hw_addr_len;
 	u8      prot_addr_len;
-	u16     op_code;
+	__be16  op_code;
 	u8      mac_src[ETH_ALEN];	/* sender hardware address */
-	u32     ip_src;			/* sender IP address */
+	__be32  ip_src;			/* sender IP address */
 	u8      mac_dst[ETH_ALEN];	/* target hardware address */
-	u32     ip_dst;			/* target IP address */
+	__be32  ip_dst;			/* target IP address */
 };
 #pragma pack()
 
@@ -345,6 +345,9 @@
 	struct arp_pkt *arp = (struct arp_pkt *)skb->data;
 	int res = NET_RX_DROP;
 
+	if (bond_dev->nd_net != &init_net)
+		goto out;
+
 	if (!(bond_dev->flags & IFF_MASTER))
 		goto out;
 
@@ -579,7 +582,7 @@
 }
 
 /* mark all clients using src_ip to be updated */
-static void rlb_req_update_subnet_clients(struct bonding *bond, u32 src_ip)
+static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip)
 {
 	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
 	struct rlb_client_info *client_info;
@@ -1264,7 +1267,7 @@
 	struct ethhdr *eth_data;
 	struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
 	struct slave *tx_slave = NULL;
-	static const u32 ip_bcast = 0xffffffff;
+	static const __be32 ip_bcast = htonl(0xffffffff);
 	int hash_size = 0;
 	int do_tx_balance = 1;
 	u32 hash_index = 0;
@@ -1308,8 +1311,7 @@
 		hash_size = sizeof(ipv6_hdr(skb)->daddr);
 		break;
 	case ETH_P_IPX:
-		if (ipx_hdr(skb)->ipx_checksum !=
-		    __constant_htons(IPX_NO_CHECKSUM)) {
+		if (ipx_hdr(skb)->ipx_checksum != IPX_NO_CHECKSUM) {
 			/* something is wrong with this packet */
 			do_tx_balance = 0;
 			break;
diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h
index 28f2a2f..fd87264 100644
--- a/drivers/net/bonding/bond_alb.h
+++ b/drivers/net/bonding/bond_alb.h
@@ -60,8 +60,8 @@
  * -------------------------------------------------------------------------
  */
 struct rlb_client_info {
-	u32 ip_src;		/* the server IP address */
-	u32 ip_dst;		/* the client IP address */
+	__be32 ip_src;		/* the server IP address */
+	__be32 ip_dst;		/* the client IP address */
 	u8  mac_dst[ETH_ALEN];	/* the client MAC address */
 	u32 next;		/* The next Hash table entry index */
 	u32 prev;		/* The previous Hash table entry index */
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index cb9cb30..64bfec3 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -75,6 +75,7 @@
 #include <linux/if_vlan.h>
 #include <linux/if_bonding.h>
 #include <net/route.h>
+#include <net/net_namespace.h>
 #include "bonding.h"
 #include "bond_3ad.h"
 #include "bond_alb.h"
@@ -143,7 +144,7 @@
 #endif
 
 extern struct rw_semaphore bonding_rwsem;
-static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ;
+static __be32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ;
 static int arp_ip_count	= 0;
 static int bond_mode	= BOND_MODE_ROUNDROBIN;
 static int xmit_hashtype= BOND_XMIT_POLICY_LAYER2;
@@ -613,38 +614,20 @@
 static int bond_update_speed_duplex(struct slave *slave)
 {
 	struct net_device *slave_dev = slave->dev;
-	static int (* ioctl)(struct net_device *, struct ifreq *, int);
-	struct ifreq ifr;
 	struct ethtool_cmd etool;
+	int res;
 
 	/* Fake speed and duplex */
 	slave->speed = SPEED_100;
 	slave->duplex = DUPLEX_FULL;
 
-	if (slave_dev->ethtool_ops) {
-		int res;
-
-		if (!slave_dev->ethtool_ops->get_settings) {
-			return -1;
-		}
-
-		res = slave_dev->ethtool_ops->get_settings(slave_dev, &etool);
-		if (res < 0) {
-			return -1;
-		}
-
-		goto verify;
-	}
-
-	ioctl = slave_dev->do_ioctl;
-	strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ);
-	etool.cmd = ETHTOOL_GSET;
-	ifr.ifr_data = (char*)&etool;
-	if (!ioctl || (IOCTL(slave_dev, &ifr, SIOCETHTOOL) < 0)) {
+	if (!slave_dev->ethtool_ops || !slave_dev->ethtool_ops->get_settings)
 		return -1;
-	}
 
-verify:
+	res = slave_dev->ethtool_ops->get_settings(slave_dev, &etool);
+	if (res < 0)
+		return -1;
+
 	switch (etool.speed) {
 	case SPEED_10:
 	case SPEED_100:
@@ -690,7 +673,6 @@
 	static int (* ioctl)(struct net_device *, struct ifreq *, int);
 	struct ifreq ifr;
 	struct mii_ioctl_data *mii;
-	struct ethtool_value etool;
 
 	if (bond->params.use_carrier) {
 		return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0;
@@ -721,9 +703,10 @@
 		}
 	}
 
-	/* try SIOCETHTOOL ioctl, some drivers cache ETHTOOL_GLINK */
-	/* for a period of time so we attempt to get link status   */
-	/* from it last if the above MII ioctls fail...            */
+	/*
+	 * Some drivers cache ETHTOOL_GLINK for a period of time so we only
+	 * attempt to get link status from it if the above MII ioctls fail.
+	 */
 	if (slave_dev->ethtool_ops) {
 		if (slave_dev->ethtool_ops->get_link) {
 			u32 link;
@@ -734,23 +717,9 @@
 		}
 	}
 
-	if (ioctl) {
-		strncpy(ifr.ifr_name, slave_dev->name, IFNAMSIZ);
-		etool.cmd = ETHTOOL_GLINK;
-		ifr.ifr_data = (char*)&etool;
-		if (IOCTL(slave_dev, &ifr, SIOCETHTOOL) == 0) {
-			if (etool.data == 1) {
-				return BMSR_LSTATUS;
-			} else {
-				dprintk("SIOCETHTOOL shows link down\n");
-				return 0;
-			}
-		}
-	}
-
 	/*
 	 * If reporting, report that either there's no dev->do_ioctl,
-	 * or both SIOCGMIIREG and SIOCETHTOOL failed (meaning that we
+	 * or both SIOCGMIIREG and get_link failed (meaning that we
 	 * cannot report link status).  If not reporting, pretend
 	 * we're ok.
 	 */
@@ -1234,43 +1203,35 @@
 	return 0;
 }
 
-#define BOND_INTERSECT_FEATURES \
-	(NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_TSO | NETIF_F_UFO)
+#define BOND_VLAN_FEATURES \
+	(NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX | \
+	 NETIF_F_HW_VLAN_FILTER)
 
 /* 
  * Compute the common dev->feature set available to all slaves.  Some
- * feature bits are managed elsewhere, so preserve feature bits set on
- * master device that are not part of the examined set.
+ * feature bits are managed elsewhere, so preserve those feature bits
+ * on the master device.
  */
 static int bond_compute_features(struct bonding *bond)
 {
-	unsigned long features = BOND_INTERSECT_FEATURES;
 	struct slave *slave;
 	struct net_device *bond_dev = bond->dev;
+	unsigned long features = bond_dev->features;
 	unsigned short max_hard_header_len = ETH_HLEN;
 	int i;
 
+	features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES);
+	features |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
+		    NETIF_F_GSO_MASK | NETIF_F_NO_CSUM;
+
 	bond_for_each_slave(bond, slave, i) {
-		features &= (slave->dev->features & BOND_INTERSECT_FEATURES);
+		features = netdev_compute_features(features,
+						   slave->dev->features);
 		if (slave->dev->hard_header_len > max_hard_header_len)
 			max_hard_header_len = slave->dev->hard_header_len;
 	}
 
-	if ((features & NETIF_F_SG) && 
-	    !(features & NETIF_F_ALL_CSUM))
-		features &= ~NETIF_F_SG;
-
-	/* 
-	 * features will include NETIF_F_TSO (NETIF_F_UFO) iff all 
-	 * slave devices support NETIF_F_TSO (NETIF_F_UFO), which 
-	 * implies that all slaves also support scatter-gather 
-	 * (NETIF_F_SG), which implies that features also includes 
-	 * NETIF_F_SG. So no need to check whether we have an  
-	 * illegal combination of NETIF_F_{TSO,UFO} and 
-	 * !NETIF_F_SG 
-	 */
-
-	features |= (bond_dev->features & ~BOND_INTERSECT_FEATURES);
+	features |= (bond_dev->features & BOND_VLAN_FEATURES);
 	bond_dev->features = features;
 	bond_dev->hard_header_len = max_hard_header_len;
 
@@ -1643,6 +1604,7 @@
 	struct slave *slave, *oldcurrent;
 	struct sockaddr addr;
 	int mac_addr_differ;
+	DECLARE_MAC_BUF(mac);
 
 	/* slave is not a slave or master is not master of this slave */
 	if (!(slave_dev->flags & IFF_SLAVE) ||
@@ -1670,19 +1632,13 @@
 				 ETH_ALEN);
 	if (!mac_addr_differ && (bond->slave_cnt > 1)) {
 		printk(KERN_WARNING DRV_NAME
-		       ": %s: Warning: the permanent HWaddr of %s "
-		       "- %02X:%02X:%02X:%02X:%02X:%02X - is "
-		       "still in use by %s. Set the HWaddr of "
-		       "%s to a different address to avoid "
-		       "conflicts.\n",
+		       ": %s: Warning: the permanent HWaddr of %s - "
+		       "%s - is still in use by %s. "
+		       "Set the HWaddr of %s to a different address "
+		       "to avoid conflicts.\n",
 		       bond_dev->name,
 		       slave_dev->name,
-		       slave->perm_hwaddr[0],
-		       slave->perm_hwaddr[1],
-		       slave->perm_hwaddr[2],
-		       slave->perm_hwaddr[3],
-		       slave->perm_hwaddr[4],
-		       slave->perm_hwaddr[5],
+		       print_mac(mac, slave->perm_hwaddr),
 		       bond_dev->name,
 		       slave_dev->name);
 	}
@@ -2270,7 +2226,7 @@
 }
 
 
-static u32 bond_glean_dev_ip(struct net_device *dev)
+static __be32 bond_glean_dev_ip(struct net_device *dev)
 {
 	struct in_device *idev;
 	struct in_ifaddr *ifa;
@@ -2313,7 +2269,7 @@
 	return 0;
 }
 
-static int bond_has_this_ip(struct bonding *bond, u32 ip)
+static int bond_has_this_ip(struct bonding *bond, __be32 ip)
 {
 	struct vlan_entry *vlan, *vlan_next;
 
@@ -2337,7 +2293,7 @@
  * switches in VLAN mode (especially if ports are configured as
  * "native" to a VLAN) might not pass non-tagged frames.
  */
-static void bond_arp_send(struct net_device *slave_dev, int arp_op, u32 dest_ip, u32 src_ip, unsigned short vlan_id)
+static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ip, __be32 src_ip, unsigned short vlan_id)
 {
 	struct sk_buff *skb;
 
@@ -2365,7 +2321,7 @@
 static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
 {
 	int i, vlan_id, rv;
-	u32 *targets = bond->params.arp_targets;
+	__be32 *targets = bond->params.arp_targets;
 	struct vlan_entry *vlan, *vlan_next;
 	struct net_device *vlan_dev;
 	struct flowi fl;
@@ -2470,10 +2426,10 @@
 	}
 }
 
-static void bond_validate_arp(struct bonding *bond, struct slave *slave, u32 sip, u32 tip)
+static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 sip, __be32 tip)
 {
 	int i;
-	u32 *targets = bond->params.arp_targets;
+	__be32 *targets = bond->params.arp_targets;
 
 	targets = bond->params.arp_targets;
 	for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) {
@@ -2495,7 +2451,10 @@
 	struct slave *slave;
 	struct bonding *bond;
 	unsigned char *arp_ptr;
-	u32 sip, tip;
+	__be32 sip, tip;
+
+	if (dev->nd_net != &init_net)
+		goto out;
 
 	if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER))
 		goto out;
@@ -3042,6 +3001,7 @@
 
 	if (bond->params.mode == BOND_MODE_8023AD) {
 		struct ad_info ad_info;
+		DECLARE_MAC_BUF(mac);
 
 		seq_puts(seq, "\n802.3ad info\n");
 		seq_printf(seq, "LACP rate: %s\n",
@@ -3061,13 +3021,8 @@
 				   ad_info.actor_key);
 			seq_printf(seq, "\tPartner Key: %d\n",
 				   ad_info.partner_key);
-			seq_printf(seq, "\tPartner Mac Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
-				   ad_info.partner_system[0],
-				   ad_info.partner_system[1],
-				   ad_info.partner_system[2],
-				   ad_info.partner_system[3],
-				   ad_info.partner_system[4],
-				   ad_info.partner_system[5]);
+			seq_printf(seq, "\tPartner Mac Address: %s\n",
+				   print_mac(mac, ad_info.partner_system));
 		}
 	}
 }
@@ -3075,6 +3030,7 @@
 static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave)
 {
 	struct bonding *bond = seq->private;
+	DECLARE_MAC_BUF(mac);
 
 	seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name);
 	seq_printf(seq, "MII Status: %s\n",
@@ -3083,10 +3039,8 @@
 		   slave->link_failure_count);
 
 	seq_printf(seq,
-		   "Permanent HW addr: %02x:%02x:%02x:%02x:%02x:%02x\n",
-		   slave->perm_hwaddr[0], slave->perm_hwaddr[1],
-		   slave->perm_hwaddr[2], slave->perm_hwaddr[3],
-		   slave->perm_hwaddr[4], slave->perm_hwaddr[5]);
+		   "Permanent HW addr: %s\n",
+		   print_mac(mac, slave->perm_hwaddr));
 
 	if (bond->params.mode == BOND_MODE_8023AD) {
 		const struct aggregator *agg
@@ -3184,7 +3138,7 @@
 {
 	int len = strlen(DRV_NAME);
 
-	for (bond_proc_dir = proc_net->subdir; bond_proc_dir;
+	for (bond_proc_dir = init_net.proc_net->subdir; bond_proc_dir;
 	     bond_proc_dir = bond_proc_dir->next) {
 		if ((bond_proc_dir->namelen == len) &&
 		    !memcmp(bond_proc_dir->name, DRV_NAME, len)) {
@@ -3193,7 +3147,7 @@
 	}
 
 	if (!bond_proc_dir) {
-		bond_proc_dir = proc_mkdir(DRV_NAME, proc_net);
+		bond_proc_dir = proc_mkdir(DRV_NAME, init_net.proc_net);
 		if (bond_proc_dir) {
 			bond_proc_dir->owner = THIS_MODULE;
 		} else {
@@ -3228,7 +3182,7 @@
 			bond_proc_dir->owner = NULL;
 		}
 	} else {
-		remove_proc_entry(DRV_NAME, proc_net);
+		remove_proc_entry(DRV_NAME, init_net.proc_net);
 		bond_proc_dir = NULL;
 	}
 }
@@ -3335,6 +3289,9 @@
 {
 	struct net_device *event_dev = (struct net_device *)ptr;
 
+	if (event_dev->nd_net != &init_net)
+		return NOTIFY_DONE;
+
 	dprintk("event_dev: %s, event: %lx\n",
 		(event_dev ? event_dev->name : "None"),
 		event);
@@ -3470,14 +3427,14 @@
 {
 	struct ethhdr *data = (struct ethhdr *)skb->data;
 	struct iphdr *iph = ip_hdr(skb);
-	u16 *layer4hdr = (u16 *)((u32 *)iph + iph->ihl);
+	__be16 *layer4hdr = (__be16 *)((u32 *)iph + iph->ihl);
 	int layer4_xor = 0;
 
 	if (skb->protocol == __constant_htons(ETH_P_IP)) {
 		if (!(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) &&
 		    (iph->protocol == IPPROTO_TCP ||
 		     iph->protocol == IPPROTO_UDP)) {
-			layer4_xor = htons((*layer4hdr ^ *(layer4hdr + 1)));
+			layer4_xor = ntohs((*layer4hdr ^ *(layer4hdr + 1)));
 		}
 		return (layer4_xor ^
 			((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count;
@@ -3752,7 +3709,7 @@
 	}
 
 	down_write(&(bonding_rwsem));
-	slave_dev = dev_get_by_name(ifr->ifr_slave);
+	slave_dev = dev_get_by_name(&init_net, ifr->ifr_slave);
 
 	dprintk("slave_dev=%p: \n", slave_dev);
 
@@ -4235,10 +4192,6 @@
 }
 
 static const struct ethtool_ops bond_ethtool_ops = {
-	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.get_tso		= ethtool_op_get_tso,
-	.get_ufo		= ethtool_op_get_ufo,
-	.get_sg			= ethtool_op_get_sg,
 	.get_drvinfo		= bond_ethtool_get_drvinfo,
 };
 
@@ -4568,7 +4521,7 @@
 			       arp_ip_target[arp_ip_count]);
 			arp_interval = 0;
 		} else {
-			u32 ip = in_aton(arp_ip_target[arp_ip_count]);
+			__be32 ip = in_aton(arp_ip_target[arp_ip_count]);
 			arp_target[arp_ip_count] = ip;
 		}
 	}
@@ -4707,8 +4660,6 @@
 		goto out_netdev;
 	}
 
-	SET_MODULE_OWNER(bond_dev);
-
 	res = register_netdevice(bond_dev);
 	if (res < 0) {
 		goto out_bond;
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 60cccf2..6f49ca7 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -31,10 +31,10 @@
 #include <linux/inetdevice.h>
 #include <linux/in.h>
 #include <linux/sysfs.h>
-#include <linux/string.h>
 #include <linux/ctype.h>
 #include <linux/inet.h>
 #include <linux/rtnetlink.h>
+#include <net/net_namespace.h>
 
 /* #define BONDING_DEBUG 1 */
 #include "bonding.h"
@@ -299,7 +299,7 @@
 		read_unlock_bh(&bond->lock);
 		printk(KERN_INFO DRV_NAME ": %s: Adding slave %s.\n",
 		       bond->dev->name, ifname);
-		dev = dev_get_by_name(ifname);
+		dev = dev_get_by_name(&init_net, ifname);
 		if (!dev) {
 			printk(KERN_INFO DRV_NAME
 			       ": %s: Interface %s does not exist!\n",
@@ -682,16 +682,16 @@
 					 struct device_attribute *attr,
 					 const char *buf, size_t count)
 {
-	u32 newtarget;
+	__be32 newtarget;
 	int i = 0, done = 0, ret = count;
 	struct bonding *bond = to_bond(d);
-	u32 *targets;
+	__be32 *targets;
 
 	targets = bond->params.arp_targets;
 	newtarget = in_aton(buf + 1);
 	/* look for adds */
 	if (buf[0] == '+') {
-		if ((newtarget == 0) || (newtarget == INADDR_BROADCAST)) {
+		if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) {
 			printk(KERN_ERR DRV_NAME
 			       ": %s: invalid ARP target %u.%u.%u.%u specified for addition\n",
  			       bond->dev->name, NIPQUAD(newtarget));
@@ -727,7 +727,7 @@
 
 	}
 	else if (buf[0] == '-')	{
-		if ((newtarget == 0) || (newtarget == INADDR_BROADCAST)) {
+		if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) {
 			printk(KERN_ERR DRV_NAME
 			       ": %s: invalid ARP target %d.%d.%d.%d specified for removal\n",
 			       bond->dev->name, NIPQUAD(newtarget));
@@ -1361,17 +1361,14 @@
 {
 	int count = 0;
 	struct bonding *bond = to_bond(d);
+	DECLARE_MAC_BUF(mac);
 
 	if (bond->params.mode == BOND_MODE_8023AD) {
 		struct ad_info ad_info;
 		if (!bond_3ad_get_active_agg_info(bond, &ad_info)) {
-			count = sprintf(buf,"%02x:%02x:%02x:%02x:%02x:%02x\n",
-				       ad_info.partner_system[0],
-				       ad_info.partner_system[1],
-				       ad_info.partner_system[2],
-				       ad_info.partner_system[3],
-				       ad_info.partner_system[4],
-				       ad_info.partner_system[5]) + 1;
+			count = sprintf(buf,"%s\n",
+					print_mac(mac, ad_info.partner_system))
+				+ 1;
 		}
 	}
 	else
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 6dcbd25..2a6af7d 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -132,7 +132,7 @@
 	int downdelay;
 	int lacp_fast;
 	char primary[IFNAMSIZ];
-	u32 arp_targets[BOND_MAX_ARP_TARGETS];
+	__be32 arp_targets[BOND_MAX_ARP_TARGETS];
 };
 
 struct bond_parm_tbl {
@@ -142,7 +142,7 @@
 
 struct vlan_entry {
 	struct list_head vlan_list;
-	u32 vlan_ip;
+	__be32 vlan_ip;
 	unsigned short vlan_id;
 };
 
@@ -193,7 +193,7 @@
 	struct   list_head bond_list;
 	struct   dev_mc_list *mc_list;
 	int      (*xmit_hash_policy)(struct sk_buff *, struct net_device *, int);
-	u32      master_ip;
+	__be32   master_ip;
 	u16      flags;
 	struct   ad_bond_info ad_info;
 	struct   alb_bond_info alb_info;
diff --git a/drivers/net/bsd_comp.c b/drivers/net/bsd_comp.c
index 7845eaf..88edb98 100644
--- a/drivers/net/bsd_comp.c
+++ b/drivers/net/bsd_comp.c
@@ -395,20 +395,18 @@
  * Allocate the main control structure for this instance.
  */
     maxmaxcode = MAXCODE(bits);
-    db         = kmalloc(sizeof (struct bsd_db),
+    db         = kzalloc(sizeof (struct bsd_db),
 					    GFP_KERNEL);
     if (!db)
       {
 	return NULL;
       }
 
-    memset (db, 0, sizeof(struct bsd_db));
 /*
  * Allocate space for the dictionary. This may be more than one page in
  * length.
  */
-    db->dict = (struct bsd_dict *) vmalloc (hsize *
-					    sizeof (struct bsd_dict));
+    db->dict = vmalloc(hsize * sizeof(struct bsd_dict));
     if (!db->dict)
       {
 	bsd_free (db);
@@ -427,8 +425,7 @@
  */
     else
       {
-        db->lens = (unsigned short *) vmalloc ((maxmaxcode + 1) *
-					       sizeof (db->lens[0]));
+        db->lens = vmalloc((maxmaxcode + 1) * sizeof(db->lens[0]));
 	if (!db->lens)
 	  {
 	    bsd_free (db);
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index f6e4030..563bf5f 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -2485,7 +2485,7 @@
 	if (status & INTR_RX_DONE_ALT) { /* handle rx separately */
 #ifdef USE_NAPI
 		cas_mask_intr(cp);
-		netif_rx_schedule(dev);
+		netif_rx_schedule(dev, &cp->napi);
 #else
 		cas_rx_ringN(cp, ring, 0);
 #endif
@@ -2536,7 +2536,7 @@
 	if (status & INTR_RX_DONE_ALT) { /* handle rx separately */
 #ifdef USE_NAPI
 		cas_mask_intr(cp);
-		netif_rx_schedule(dev);
+		netif_rx_schedule(dev, &cp->napi);
 #else
 		cas_rx_ringN(cp, 1, 0);
 #endif
@@ -2592,7 +2592,7 @@
 	if (status & INTR_RX_DONE) {
 #ifdef USE_NAPI
 		cas_mask_intr(cp);
-		netif_rx_schedule(dev);
+		netif_rx_schedule(dev, &cp->napi);
 #else
 		cas_rx_ringN(cp, 0, 0);
 #endif
@@ -2607,9 +2607,10 @@
 
 
 #ifdef USE_NAPI
-static int cas_poll(struct net_device *dev, int *budget)
+static int cas_poll(struct napi_struct *napi, int budget)
 {
-	struct cas *cp = netdev_priv(dev);
+	struct cas *cp = container_of(napi, struct cas, napi);
+	struct net_device *dev = cp->dev;
 	int i, enable_intr, todo, credits;
 	u32 status = readl(cp->regs + REG_INTR_STATUS);
 	unsigned long flags;
@@ -2620,20 +2621,18 @@
 
 	/* NAPI rx packets. we spread the credits across all of the
 	 * rxc rings
-	 */
-	todo = min(*budget, dev->quota);
-
-	/* to make sure we're fair with the work we loop through each
+	 *
+	 * to make sure we're fair with the work we loop through each
 	 * ring N_RX_COMP_RING times with a request of
-	 * todo / N_RX_COMP_RINGS
+	 * budget / N_RX_COMP_RINGS
 	 */
 	enable_intr = 1;
 	credits = 0;
 	for (i = 0; i < N_RX_COMP_RINGS; i++) {
 		int j;
 		for (j = 0; j < N_RX_COMP_RINGS; j++) {
-			credits += cas_rx_ringN(cp, j, todo / N_RX_COMP_RINGS);
-			if (credits >= todo) {
+			credits += cas_rx_ringN(cp, j, budget / N_RX_COMP_RINGS);
+			if (credits >= budget) {
 				enable_intr = 0;
 				goto rx_comp;
 			}
@@ -2641,9 +2640,6 @@
 	}
 
 rx_comp:
-	*budget    -= credits;
-	dev->quota -= credits;
-
 	/* final rx completion */
 	spin_lock_irqsave(&cp->lock, flags);
 	if (status)
@@ -2674,11 +2670,10 @@
 #endif
 	spin_unlock_irqrestore(&cp->lock, flags);
 	if (enable_intr) {
-		netif_rx_complete(dev);
+		netif_rx_complete(dev, napi);
 		cas_unmask_intr(cp);
-		return 0;
 	}
-	return 1;
+	return credits;
 }
 #endif
 
@@ -4351,6 +4346,9 @@
 		goto err_spare;
 	}
 
+#ifdef USE_NAPI
+	napi_enable(&cp->napi);
+#endif
 	/* init hw */
 	cas_lock_all_save(cp, flags);
 	cas_clean_rings(cp);
@@ -4376,6 +4374,9 @@
 	unsigned long flags;
 	struct cas *cp = netdev_priv(dev);
 
+#ifdef USE_NAPI
+	napi_enable(&cp->napi);
+#endif
 	/* Make sure we don't get distracted by suspend/resume */
 	mutex_lock(&cp->pm_mutex);
 
@@ -4771,9 +4772,14 @@
 	cas_read_regs(cp, p, regs->len / sizeof(u32));
 }
 
-static int cas_get_stats_count(struct net_device *dev)
+static int cas_get_sset_count(struct net_device *dev, int sset)
 {
-	return CAS_NUM_STAT_KEYS;
+	switch (sset) {
+	case ETH_SS_STATS:
+		return CAS_NUM_STAT_KEYS;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void cas_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -4817,7 +4823,7 @@
 	.set_msglevel		= cas_set_msglevel,
 	.get_regs_len		= cas_get_regs_len,
 	.get_regs		= cas_get_regs,
-	.get_stats_count	= cas_get_stats_count,
+	.get_sset_count		= cas_get_sset_count,
 	.get_strings		= cas_get_strings,
 	.get_ethtool_stats	= cas_get_ethtool_stats,
 };
@@ -4876,6 +4882,7 @@
 	int i, err, pci_using_dac;
 	u16 pci_cmd;
 	u8 orig_cacheline_size = 0, cas_cacheline_size = 0;
+	DECLARE_MAC_BUF(mac);
 
 	if (cas_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
@@ -4899,7 +4906,6 @@
 		err = -ENOMEM;
 		goto err_out_disable_pdev;
 	}
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	err = pci_request_regions(pdev, dev->name);
@@ -5062,8 +5068,7 @@
 	dev->watchdog_timeo = CAS_TX_TIMEOUT;
 	dev->change_mtu = cas_change_mtu;
 #ifdef USE_NAPI
-	dev->poll = cas_poll;
-	dev->weight = 64;
+	netif_napi_add(dev, &cp->napi, cas_poll, 64);
 #endif
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = cas_netpoll;
@@ -5085,16 +5090,12 @@
 
 	i = readl(cp->regs + REG_BIM_CFG);
 	printk(KERN_INFO "%s: Sun Cassini%s (%sbit/%sMHz PCI/%s) "
-	       "Ethernet[%d] ",  dev->name,
+	       "Ethernet[%d] %s\n",  dev->name,
 	       (cp->cas_flags & CAS_FLAG_REG_PLUS) ? "+" : "",
 	       (i & BIM_CFG_32BIT) ? "32" : "64",
 	       (i & BIM_CFG_66MHZ) ? "66" : "33",
-	       (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq);
-
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", dev->dev_addr[i],
-		       i == 5 ? ' ' : ':');
-	printk("\n");
+	       (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq,
+	       print_mac(mac, dev->dev_addr));
 
 	pci_set_drvdata(pdev, dev);
 	cp->hw_running = 1;
diff --git a/drivers/net/cassini.h b/drivers/net/cassini.h
index a970804..2f93f83 100644
--- a/drivers/net/cassini.h
+++ b/drivers/net/cassini.h
@@ -4280,6 +4280,8 @@
 	int rx_cur[N_RX_COMP_RINGS], rx_new[N_RX_COMP_RINGS];
 	int rx_last[N_RX_DESC_RINGS];
 
+	struct napi_struct napi;
+
 	/* Set when chip is actually in operational state
 	 * (ie. not power managed) */
 	int hw_running;
diff --git a/drivers/net/chelsio/Makefile b/drivers/net/chelsio/Makefile
index 743ad8b..57a4b26 100644
--- a/drivers/net/chelsio/Makefile
+++ b/drivers/net/chelsio/Makefile
@@ -4,6 +4,6 @@
 
 obj-$(CONFIG_CHELSIO_T1) += cxgb.o
 
-cxgb-$(CONFIG_CHELSIO_T1_1G) += mac.o mv88e1xxx.o vsc7326.o
+cxgb-$(CONFIG_CHELSIO_T1_1G) += mv88e1xxx.o vsc7326.o
 cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \
 	     mv88x201x.o my3126.o $(cxgb-y)
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index 8ba702c..846ca53 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -278,6 +278,7 @@
 	struct peespi *espi;
 	struct petp   *tp;
 
+	struct napi_struct napi;
 	struct port_info port[MAX_NPORTS];
 	struct delayed_work stats_update_task;
 	struct timer_list stats_update_timer;
@@ -371,6 +372,7 @@
 extern void t1_interrupts_disable(adapter_t *adapter);
 extern void t1_interrupts_clear(adapter_t *adapter);
 extern int t1_elmer0_ext_intr_handler(adapter_t *adapter);
+extern void t1_elmer0_ext_intr(adapter_t *adapter);
 extern int t1_slow_intr_handler(adapter_t *adapter);
 
 extern int t1_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc);
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index 231ce43..2dbf8dc 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -255,8 +255,11 @@
 	struct adapter *adapter = dev->priv;
 	int other_ports = adapter->open_device_map & PORT_MASK;
 
-	if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
+	napi_enable(&adapter->napi);
+	if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) {
+		napi_disable(&adapter->napi);
 		return err;
+	}
 
 	__set_bit(dev->if_port, &adapter->open_device_map);
 	link_start(&adapter->port[dev->if_port]);
@@ -274,6 +277,7 @@
 	struct cmac *mac = p->mac;
 
 	netif_stop_queue(dev);
+	napi_disable(&adapter->napi);
 	mac->ops->disable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
 	netif_carrier_off(dev);
 
@@ -435,9 +439,14 @@
 	strcpy(info->bus_info, pci_name(adapter->pdev));
 }
 
-static int get_stats_count(struct net_device *dev)
+static int get_sset_count(struct net_device *dev, int sset)
 {
-	return ARRAY_SIZE(stats_strings);
+	switch (sset) {
+	case ETH_SS_STATS:
+		return ARRAY_SIZE(stats_strings);
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -790,17 +799,14 @@
 	.set_pauseparam    = set_pauseparam,
 	.get_rx_csum       = get_rx_csum,
 	.set_rx_csum       = set_rx_csum,
-	.get_tx_csum       = ethtool_op_get_tx_csum,
 	.set_tx_csum       = ethtool_op_set_tx_csum,
-	.get_sg            = ethtool_op_get_sg,
 	.set_sg            = ethtool_op_set_sg,
 	.get_link          = ethtool_op_get_link,
 	.get_strings       = get_strings,
-	.get_stats_count   = get_stats_count,
+	.get_sset_count	   = get_sset_count,
 	.get_ethtool_stats = get_stats,
 	.get_regs_len      = get_regs_len,
 	.get_regs          = get_regs,
-	.get_tso           = ethtool_op_get_tso,
 	.set_tso           = set_tso,
 };
 
@@ -1032,7 +1038,6 @@
 			goto out_free_dev;
 		}
 
-		SET_MODULE_OWNER(netdev);
 		SET_NETDEV_DEV(netdev, &pdev->dev);
 
 		if (!adapter) {
@@ -1113,8 +1118,7 @@
 		netdev->poll_controller = t1_netpoll;
 #endif
 #ifdef CONFIG_CHELSIO_T1_NAPI
-		netdev->weight = 64;
-		netdev->poll = t1_poll;
+		netif_napi_add(netdev, &adapter->napi, t1_poll, 64);
 #endif
 
 		SET_ETHTOOL_OPS(netdev, &t1_ethtool_ops);
diff --git a/drivers/net/chelsio/mac.c b/drivers/net/chelsio/mac.c
deleted file mode 100644
index 1d97282..0000000
--- a/drivers/net/chelsio/mac.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/* $Date: 2005/10/22 00:42:59 $ $RCSfile: mac.c,v $ $Revision: 1.32 $ */
-#include "gmac.h"
-#include "regs.h"
-#include "fpga_defs.h"
-
-#define MAC_CSR_INTERFACE_GMII      0x0
-#define MAC_CSR_INTERFACE_TBI       0x1
-#define MAC_CSR_INTERFACE_MII       0x2
-#define MAC_CSR_INTERFACE_RMII      0x3
-
-/* Chelsio's MAC statistics. */
-struct mac_statistics {
-
-	/* Transmit */
-	u32 TxFramesTransmittedOK;
-	u32 TxReserved1;
-	u32 TxReserved2;
-	u32 TxOctetsTransmittedOK;
-	u32 TxFramesWithDeferredXmissions;
-	u32 TxLateCollisions;
-	u32 TxFramesAbortedDueToXSCollisions;
-	u32 TxFramesLostDueToIntMACXmitError;
-	u32 TxReserved3;
-	u32 TxMulticastFrameXmittedOK;
-	u32 TxBroadcastFramesXmittedOK;
-	u32 TxFramesWithExcessiveDeferral;
-	u32 TxPAUSEMACCtrlFramesTransmitted;
-
-	/* Receive */
-	u32 RxFramesReceivedOK;
-	u32 RxFrameCheckSequenceErrors;
-	u32 RxAlignmentErrors;
-	u32 RxOctetsReceivedOK;
-	u32 RxFramesLostDueToIntMACRcvError;
-	u32 RxMulticastFramesReceivedOK;
-	u32 RxBroadcastFramesReceivedOK;
-	u32 RxInRangeLengthErrors;
-	u32 RxTxOutOfRangeLengthField;
-	u32 RxFrameTooLongErrors;
-	u32 RxPAUSEMACCtrlFramesReceived;
-};
-
-static int static_aPorts[] = {
-	FPGA_GMAC_INTERRUPT_PORT0,
-	FPGA_GMAC_INTERRUPT_PORT1,
-	FPGA_GMAC_INTERRUPT_PORT2,
-	FPGA_GMAC_INTERRUPT_PORT3
-};
-
-struct _cmac_instance {
-	u32 index;
-};
-
-static int mac_intr_enable(struct cmac *mac)
-{
-	u32 mac_intr;
-
-	if (t1_is_asic(mac->adapter)) {
-		/* ASIC */
-
-		/* We don't use the on chip MAC for ASIC products. */
-	} else {
-		/* FPGA */
-
-		/* Set parent gmac interrupt. */
-		mac_intr = readl(mac->adapter->regs + A_PL_ENABLE);
-		mac_intr |= FPGA_PCIX_INTERRUPT_GMAC;
-		writel(mac_intr, mac->adapter->regs + A_PL_ENABLE);
-
-		mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
-		mac_intr |= static_aPorts[mac->instance->index];
-		writel(mac_intr,
-		       mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
-	}
-
-	return 0;
-}
-
-static int mac_intr_disable(struct cmac *mac)
-{
-	u32 mac_intr;
-
-	if (t1_is_asic(mac->adapter)) {
-		/* ASIC */
-
-		/* We don't use the on chip MAC for ASIC products. */
-	} else {
-		/* FPGA */
-
-		/* Set parent gmac interrupt. */
-		mac_intr = readl(mac->adapter->regs + A_PL_ENABLE);
-		mac_intr &= ~FPGA_PCIX_INTERRUPT_GMAC;
-		writel(mac_intr, mac->adapter->regs + A_PL_ENABLE);
-
-		mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
-		mac_intr &= ~(static_aPorts[mac->instance->index]);
-		writel(mac_intr,
-		       mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_ENABLE);
-	}
-
-	return 0;
-}
-
-static int mac_intr_clear(struct cmac *mac)
-{
-	u32 mac_intr;
-
-	if (t1_is_asic(mac->adapter)) {
-		/* ASIC */
-
-		/* We don't use the on chip MAC for ASIC products. */
-	} else {
-		/* FPGA */
-
-		/* Set parent gmac interrupt. */
-		writel(FPGA_PCIX_INTERRUPT_GMAC,
-		       mac->adapter->regs +  A_PL_CAUSE);
-		mac_intr = readl(mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE);
-		mac_intr |= (static_aPorts[mac->instance->index]);
-		writel(mac_intr,
-		       mac->adapter->regs + FPGA_GMAC_ADDR_INTERRUPT_CAUSE);
-	}
-
-	return 0;
-}
-
-static int mac_get_address(struct cmac *mac, u8 addr[6])
-{
-	u32 data32_lo, data32_hi;
-
-	data32_lo = readl(mac->adapter->regs
-			  + MAC_REG_IDLO(mac->instance->index));
-	data32_hi = readl(mac->adapter->regs
-			  + MAC_REG_IDHI(mac->instance->index));
-
-	addr[0] = (u8) ((data32_hi >> 8) & 0xFF);
-	addr[1] = (u8) ((data32_hi) & 0xFF);
-	addr[2] = (u8) ((data32_lo >> 24) & 0xFF);
-	addr[3] = (u8) ((data32_lo >> 16) & 0xFF);
-	addr[4] = (u8) ((data32_lo >> 8) & 0xFF);
-	addr[5] = (u8) ((data32_lo) & 0xFF);
-	return 0;
-}
-
-static int mac_reset(struct cmac *mac)
-{
-	u32 data32;
-	int mac_in_reset, time_out = 100;
-	int idx = mac->instance->index;
-
-	data32 = readl(mac->adapter->regs + MAC_REG_CSR(idx));
-	writel(data32 | F_MAC_RESET,
-	       mac->adapter->regs + MAC_REG_CSR(idx));
-
-	do {
-		data32 = readl(mac->adapter->regs + MAC_REG_CSR(idx));
-
-		mac_in_reset = data32 & F_MAC_RESET;
-		if (mac_in_reset)
-			udelay(1);
-	} while (mac_in_reset && --time_out);
-
-	if (mac_in_reset) {
-		CH_ERR("%s: MAC %d reset timed out\n",
-		       mac->adapter->name, idx);
-		return 2;
-	}
-
-	return 0;
-}
-
-static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
-{
-	u32 val;
-
-	val = readl(mac->adapter->regs
-			    + MAC_REG_CSR(mac->instance->index));
-	val &= ~(F_MAC_PROMISC | F_MAC_MC_ENABLE);
-	val |= V_MAC_PROMISC(t1_rx_mode_promisc(rm) != 0);
-	val |= V_MAC_MC_ENABLE(t1_rx_mode_allmulti(rm) != 0);
-	writel(val,
-	       mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
-
-	return 0;
-}
-
-static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex,
-				   int fc)
-{
-	u32 data32;
-
-	data32 = readl(mac->adapter->regs
-			       + MAC_REG_CSR(mac->instance->index));
-	data32 &= ~(F_MAC_HALF_DUPLEX | V_MAC_SPEED(M_MAC_SPEED) |
-		V_INTERFACE(M_INTERFACE) | F_MAC_TX_PAUSE_ENABLE |
-		F_MAC_RX_PAUSE_ENABLE);
-
-	switch (speed) {
-	case SPEED_10:
-	case SPEED_100:
-		data32 |= V_INTERFACE(MAC_CSR_INTERFACE_MII);
-		data32 |= V_MAC_SPEED(speed == SPEED_10 ? 0 : 1);
-		break;
-	case SPEED_1000:
-		data32 |= V_INTERFACE(MAC_CSR_INTERFACE_GMII);
-		data32 |= V_MAC_SPEED(2);
-		break;
-	}
-
-	if (duplex >= 0)
-		data32 |= V_MAC_HALF_DUPLEX(duplex == DUPLEX_HALF);
-
-	if (fc >= 0) {
-		data32 |= V_MAC_RX_PAUSE_ENABLE((fc & PAUSE_RX) != 0);
-		data32 |= V_MAC_TX_PAUSE_ENABLE((fc & PAUSE_TX) != 0);
-	}
-
-	writel(data32,
-	       mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
-	return 0;
-}
-
-static int mac_enable(struct cmac *mac, int which)
-{
-	u32 val;
-
-	val = readl(mac->adapter->regs
-			    + MAC_REG_CSR(mac->instance->index));
-	if (which & MAC_DIRECTION_RX)
-		val |= F_MAC_RX_ENABLE;
-	if (which & MAC_DIRECTION_TX)
-		val |= F_MAC_TX_ENABLE;
-	writel(val,
-	       mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
-	return 0;
-}
-
-static int mac_disable(struct cmac *mac, int which)
-{
-	u32 val;
-
-	val = readl(mac->adapter->regs
-			    + MAC_REG_CSR(mac->instance->index));
-	if (which & MAC_DIRECTION_RX)
-		val &= ~F_MAC_RX_ENABLE;
-	if (which & MAC_DIRECTION_TX)
-		val &= ~F_MAC_TX_ENABLE;
-	writel(val,
-	       mac->adapter->regs + MAC_REG_CSR(mac->instance->index));
-	return 0;
-}
-
-#if 0
-static int mac_set_ifs(struct cmac *mac, u32 mode)
-{
-	t1_write_reg_4(mac->adapter,
-		       MAC_REG_IFS(mac->instance->index),
-		       mode);
-	return 0;
-}
-
-static int mac_enable_isl(struct cmac *mac)
-{
-	u32 data32 = readl(mac->adapter->regs
-				   + MAC_REG_CSR(mac->instance->index));
-	data32 |= F_MAC_RX_ENABLE | F_MAC_TX_ENABLE;
-	t1_write_reg_4(mac->adapter,
-		       MAC_REG_CSR(mac->instance->index),
-		       data32);
-	return 0;
-}
-#endif
-
-static int mac_set_mtu(struct cmac *mac, int mtu)
-{
-	if (mtu > 9600)
-		return -EINVAL;
-	writel(mtu + ETH_HLEN + VLAN_HLEN,
-	       mac->adapter->regs + MAC_REG_LARGEFRAMELENGTH(mac->instance->index));
-
-	return 0;
-}
-
-static const struct cmac_statistics *mac_update_statistics(struct cmac *mac,
-							   int flag)
-{
-	struct mac_statistics st;
-	u32 *p = (u32 *) & st, i;
-
-	writel(0,
-	       mac->adapter->regs + MAC_REG_RMCNT(mac->instance->index));
-
-	for (i = 0; i < sizeof(st) / sizeof(u32); i++)
-		*p++ = readl(mac->adapter->regs
-			     + MAC_REG_RMDATA(mac->instance->index));
-
-	/* XXX convert stats */
-	return &mac->stats;
-}
-
-static void mac_destroy(struct cmac *mac)
-{
-	kfree(mac);
-}
-
-static struct cmac_ops chelsio_mac_ops = {
-	.destroy                 = mac_destroy,
-	.reset                   = mac_reset,
-	.interrupt_enable        = mac_intr_enable,
-	.interrupt_disable       = mac_intr_disable,
-	.interrupt_clear         = mac_intr_clear,
-	.enable                  = mac_enable,
-	.disable                 = mac_disable,
-	.set_mtu                 = mac_set_mtu,
-	.set_rx_mode             = mac_set_rx_mode,
-	.set_speed_duplex_fc     = mac_set_speed_duplex_fc,
-	.macaddress_get          = mac_get_address,
-	.statistics_update       = mac_update_statistics,
-};
-
-static struct cmac *mac_create(adapter_t *adapter, int index)
-{
-	struct cmac *mac;
-	u32 data32;
-
-	if (index >= 4)
-		return NULL;
-
-	mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
-	if (!mac)
-		return NULL;
-
-	mac->ops = &chelsio_mac_ops;
-	mac->instance = (cmac_instance *) (mac + 1);
-
-	mac->instance->index = index;
-	mac->adapter = adapter;
-
-	data32 = readl(adapter->regs + MAC_REG_CSR(mac->instance->index));
-	data32 &= ~(F_MAC_RESET | F_MAC_PROMISC | F_MAC_PROMISC |
-		    F_MAC_LB_ENABLE | F_MAC_RX_ENABLE | F_MAC_TX_ENABLE);
-	data32 |= F_MAC_JUMBO_ENABLE;
-	writel(data32, adapter->regs + MAC_REG_CSR(mac->instance->index));
-
-	/* Initialize the random backoff seed. */
-	data32 = 0x55aa + (3 * index);
-	writel(data32,
-	       adapter->regs + MAC_REG_GMRANDBACKOFFSEED(mac->instance->index));
-
-	/* Check to see if the mac address needs to be set manually. */
-	data32 = readl(adapter->regs + MAC_REG_IDLO(mac->instance->index));
-	if (data32 == 0 || data32 == 0xffffffff) {
-		/*
-		 * Add a default MAC address if we can't read one.
-		 */
-		writel(0x43FFFFFF - index,
-		       adapter->regs + MAC_REG_IDLO(mac->instance->index));
-		writel(0x0007,
-		       adapter->regs + MAC_REG_IDHI(mac->instance->index));
-	}
-
-	(void) mac_set_mtu(mac, 1500);
-	return mac;
-}
-
-const struct gmac t1_chelsio_mac_ops = {
-	.create = mac_create
-};
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index e4f874a..ffa7e64 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -1620,23 +1620,20 @@
  * or protection from interrupts as data interrupts are off at this point and
  * other adapter interrupts do not interfere.
  */
-int t1_poll(struct net_device *dev, int *budget)
+int t1_poll(struct napi_struct *napi, int budget)
 {
-	struct adapter *adapter = dev->priv;
+	struct adapter *adapter = container_of(napi, struct adapter, napi);
+	struct net_device *dev = adapter->port[0].dev;
 	int work_done;
 
-	work_done = process_responses(adapter, min(*budget, dev->quota));
-	*budget -= work_done;
-	dev->quota -= work_done;
+	work_done = process_responses(adapter, budget);
 
-	if (unlikely(responses_pending(adapter)))
-		return 1;
-
-	netif_rx_complete(dev);
-	writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
-
-	return 0;
-
+	if (likely(!responses_pending(adapter))) {
+		netif_rx_complete(dev, napi);
+		writel(adapter->sge->respQ.cidx,
+		       adapter->regs + A_SG_SLEEPING);
+	}
+	return work_done;
 }
 
 /*
@@ -1653,13 +1650,13 @@
 
 		writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
 
-		if (__netif_rx_schedule_prep(dev)) {
+		if (napi_schedule_prep(&adapter->napi)) {
 			if (process_pure_responses(adapter))
-				__netif_rx_schedule(dev);
+				__netif_rx_schedule(dev, &adapter->napi);
 			else {
 				/* no data, no NAPI needed */
 				writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
-				netif_poll_enable(dev);	/* undo schedule_prep */
+				napi_enable(&adapter->napi);	/* undo schedule_prep */
 			}
 		}
 		return IRQ_HANDLED;
diff --git a/drivers/net/chelsio/sge.h b/drivers/net/chelsio/sge.h
index d132a0ef..713d9c5 100644
--- a/drivers/net/chelsio/sge.h
+++ b/drivers/net/chelsio/sge.h
@@ -77,7 +77,7 @@
 int t1_sge_set_coalesce_params(struct sge *, struct sge_params *);
 void t1_sge_destroy(struct sge *);
 irqreturn_t t1_interrupt(int irq, void *cookie);
-int t1_poll(struct net_device *, int *);
+int t1_poll(struct napi_struct *, int);
 
 int t1_start_xmit(struct sk_buff *skb, struct net_device *dev);
 void t1_set_vlan_accel(struct adapter *adapter, int on_off);
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index 7de9a61..dc50151 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -884,7 +884,7 @@
 	if (cause & F_PL_INTR_PCIX)
 		t1_pci_intr_handler(adapter);
 	if (cause & F_PL_INTR_EXT)
-		t1_elmer0_ext_intr_handler(adapter);
+		t1_elmer0_ext_intr(adapter);
 
 	/* Clear the interrupts just processed. */
 	writel(cause, adapter->regs + A_PL_CAUSE);
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 5bdf5ca..314b2f6 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -618,12 +618,8 @@
 
 	/* show it in the log as well */
 
-	printk(KERN_INFO "%s: changed MAC to ", dev->name);
-
-	for (i = 0; i < 5; i++)
-		printk("%02X:", dev->dev_addr[i]);
-
-	printk("%02X\n", dev->dev_addr[i]);
+	printk(KERN_INFO "%s: changed MAC to %s\n",
+	       dev->name, print_mac(mac, dev->dev_addr));
 
 	spin_unlock(&np->lock);
 
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 9774bb1..57175097 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -516,8 +516,8 @@
 	unsigned rev_type = 0;
 	int eeprom_buff[CHKSUM_LEN];
 	int retval;
+	DECLARE_MAC_BUF(mac);
 
-	SET_MODULE_OWNER(dev);
 	/* Initialize the device structure. */
 	if (!modular) {
 		memset(lp, 0, sizeof(*lp));
@@ -806,7 +806,7 @@
 		        i = cs8900_irq_map[0];
 #else
 			/* Translate the IRQ using the IRQ mapping table. */
-			if (i >= sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]))
+			if (i >= ARRAY_SIZE(cs8900_irq_map))
 				printk("\ncs89x0: invalid ISA interrupt number %d\n", i);
 			else
 				i = cs8900_irq_map[i];
@@ -841,11 +841,7 @@
 	}
 
 	/* print the ethernet address. */
-	printk(", MAC");
-	for (i = 0; i < ETH_ALEN; i++)
-	{
-		printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
-	}
+	printk(", MAC %s", print_mac(mac, dev->dev_addr));
 
 	dev->open		= net_open;
 	dev->stop		= net_close;
@@ -1247,11 +1243,11 @@
 
 	if (chip_type == CS8900) {
 		/* Search the mapping table for the corresponding IRQ pin. */
-		for (i = 0; i != sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]); i++)
+		for (i = 0; i != ARRAY_SIZE(cs8900_irq_map); i++)
 			if (cs8900_irq_map[i] == irq)
 				break;
 		/* Not found */
-		if (i == sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]))
+		if (i == ARRAY_SIZE(cs8900_irq_map))
 			i = 3;
 		writereg(dev, PP_CS8900_ISAINT, i);
 	} else {
@@ -1807,17 +1803,15 @@
 	int i;
 	struct sockaddr *addr = p;
 
-
 	if (netif_running(dev))
 		return -EBUSY;
 
 	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
 
 	if (net_debug) {
-		printk("%s: Setting MAC address to ", dev->name);
-		for (i = 0; i < dev->addr_len; i++)
-			printk(" %2.2x", dev->dev_addr[i]);
-		printk(".\n");
+		DECLARE_MAC_BUF(mac);
+		printk("%s: Setting MAC address to %s.\n",
+		       dev->name, print_mac(mac, dev->dev_addr));
 	}
 	/* set the Ethernet address */
 	for (i=0; i < ETH_ALEN/2; i++)
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index ab72563..0442617 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -49,9 +49,13 @@
 typedef irqreturn_t(*intr_handler_t) (int, void *);
 
 struct vlan_group;
+struct adapter;
+struct sge_qset;
 
 struct port_info {
+	struct adapter *adapter;
 	struct vlan_group *vlan_grp;
+	struct sge_qset *qs;
 	const struct port_type_info *port_type;
 	u8 port_id;
 	u8 rx_csum_offload;
@@ -171,10 +175,12 @@
 };
 
 struct sge_qset {		/* an SGE queue set */
+	struct adapter *adap;
+	struct napi_struct napi;
 	struct sge_rspq rspq;
 	struct sge_fl fl[SGE_RXQ_PER_SET];
 	struct sge_txq txq[SGE_TXQ_PER_SET];
-	struct net_device *netdev;	/* associated net device */
+	struct net_device *netdev;
 	unsigned long txq_stopped;	/* which Tx queues are stopped */
 	struct timer_list tx_reclaim_timer;	/* reclaims TX buffers */
 	unsigned long port_stats[SGE_PSTAT_MAX];
@@ -219,12 +225,6 @@
 	struct delayed_work adap_check_task;
 	struct work_struct ext_intr_handler_task;
 
-	/*
-	 * Dummy netdevices are needed when using multiple receive queues with
-	 * NAPI as each netdevice can service only one queue.
-	 */
-	struct net_device *dummy_netdev[SGE_QSETS - 1];
-
 	struct dentry *debugfs_root;
 
 	struct mutex mdio_lock;
@@ -251,12 +251,6 @@
 	return netdev_priv(adap->port[idx]);
 }
 
-/*
- * We use the spare atalk_ptr to map a net device to its SGE queue set.
- * This is a macro so it can be used as l-value.
- */
-#define dev2qset(netdev) ((netdev)->atalk_ptr)
-
 #define OFFLOAD_DEVMAP_BIT 15
 
 #define tdev2adap(d) container_of(d, struct adapter, tdev)
@@ -282,7 +276,7 @@
 void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p);
 int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
 		      int irq_vec_idx, const struct qset_params *p,
-		      int ntxq, struct net_device *netdev);
+		      int ntxq, struct net_device *dev);
 int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
 		unsigned char *data);
 irqreturn_t t3_sge_intr_msix(int irq, void *cookie);
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index 1637800..99c75d30 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -97,6 +97,7 @@
 	MAX_NPORTS = 2,		/* max # of ports */
 	MAX_FRAME_SIZE = 10240,	/* max MAC frame size, including header + FCS */
 	EEPROMSIZE = 8192,	/* Serial EEPROM size */
+	SERNUM_LEN     = 16,    /* Serial # length */
 	RSS_TABLE_SIZE = 64,	/* size of RSS lookup and mapping tables */
 	TCB_SIZE = 128,		/* TCB size */
 	NMTUS = 16,		/* size of MTU table */
@@ -104,7 +105,7 @@
 	PROTO_SRAM_LINES = 128, /* size of TP sram */
 };
 
-#define MAX_RX_COALESCING_LEN 16224U
+#define MAX_RX_COALESCING_LEN 12288U
 
 enum {
 	PAUSE_RX = 1 << 0,
@@ -126,8 +127,8 @@
 
 enum {
 	TP_VERSION_MAJOR	= 1,
-	TP_VERSION_MINOR	= 0,
-	TP_VERSION_MICRO	= 44
+	TP_VERSION_MINOR	= 1,
+	TP_VERSION_MICRO	= 0
 };
 
 #define S_TP_VERSION_MAJOR		16
@@ -167,8 +168,8 @@
 };
 
 struct sg_ent {			/* SGE scatter/gather entry */
-	u32 len[2];
-	u64 addr[2];
+	__be32 len[2];
+	__be64 addr[2];
 };
 
 #ifndef SGE_NUM_GENBITS
@@ -391,6 +392,7 @@
 	unsigned int uclk;
 	unsigned int mdc;
 	unsigned int mem_timing;
+	u8 sn[SERNUM_LEN + 1];
 	u8 eth_base[6];
 	u8 port_type[MAX_NPORTS];
 	unsigned short xauicfg[2];
@@ -436,6 +438,7 @@
 	T3_REV_A  = 0,
 	T3_REV_B  = 2,
 	T3_REV_B2 = 3,
+	T3_REV_C  = 4,
 };
 
 struct trace_params {
@@ -507,9 +510,11 @@
 	unsigned int tx_xcnt;
 	u64 tx_mcnt;
 	unsigned int rx_xcnt;
+	unsigned int rx_ocnt;
 	u64 rx_mcnt;
 	unsigned int toggle_cnt;
 	unsigned int txen;
+	u64 rx_pause;
 	struct mac_stats stats;
 };
 
@@ -679,14 +684,15 @@
 int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data);
 int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data);
 int t3_seeprom_wp(struct adapter *adapter, int enable);
-int t3_check_tpsram_version(struct adapter *adapter);
+int t3_get_tp_version(struct adapter *adapter, u32 *vers);
+int t3_check_tpsram_version(struct adapter *adapter, int *must_load);
 int t3_check_tpsram(struct adapter *adapter, u8 *tp_ram, unsigned int size);
 int t3_set_proto_sram(struct adapter *adap, u8 *data);
 int t3_read_flash(struct adapter *adapter, unsigned int addr,
 		  unsigned int nwords, u32 *data, int byte_oriented);
 int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size);
 int t3_get_fw_version(struct adapter *adapter, u32 *vers);
-int t3_check_fw_version(struct adapter *adapter);
+int t3_check_fw_version(struct adapter *adapter, int *must_load);
 int t3_init_hw(struct adapter *adapter, u32 fw_params);
 void mac_prep(struct cmac *mac, struct adapter *adapter, int index);
 void early_hw_init(struct adapter *adapter, const struct adapter_info *ai);
diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h
index 2095dda..6c4f320 100644
--- a/drivers/net/cxgb3/cxgb3_ctl_defs.h
+++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h
@@ -33,27 +33,29 @@
 #define _CXGB3_OFFLOAD_CTL_DEFS_H
 
 enum {
-	GET_MAX_OUTSTANDING_WR,
-	GET_TX_MAX_CHUNK,
-	GET_TID_RANGE,
-	GET_STID_RANGE,
-	GET_RTBL_RANGE,
-	GET_L2T_CAPACITY,
-	GET_MTUS,
-	GET_WR_LEN,
-	GET_IFF_FROM_MAC,
-	GET_DDP_PARAMS,
-	GET_PORTS,
+	GET_MAX_OUTSTANDING_WR 	= 0,
+	GET_TX_MAX_CHUNK	= 1,
+	GET_TID_RANGE		= 2,
+	GET_STID_RANGE		= 3,
+	GET_RTBL_RANGE		= 4,
+	GET_L2T_CAPACITY	= 5,
+	GET_MTUS		= 6,
+	GET_WR_LEN		= 7,
+	GET_IFF_FROM_MAC	= 8,
+	GET_DDP_PARAMS		= 9,
+	GET_PORTS		= 10,
 
-	ULP_ISCSI_GET_PARAMS,
-	ULP_ISCSI_SET_PARAMS,
+	ULP_ISCSI_GET_PARAMS	= 11,
+	ULP_ISCSI_SET_PARAMS	= 12,
 
-	RDMA_GET_PARAMS,
-	RDMA_CQ_OP,
-	RDMA_CQ_SETUP,
-	RDMA_CQ_DISABLE,
-	RDMA_CTRL_QP_SETUP,
-	RDMA_GET_MEM,
+	RDMA_GET_PARAMS		= 13,
+	RDMA_CQ_OP		= 14,
+	RDMA_CQ_SETUP		= 15,
+	RDMA_CQ_DISABLE		= 16,
+	RDMA_CTRL_QP_SETUP	= 17,
+	RDMA_GET_MEM		= 18,
+
+	GET_RX_PAGE_INFO	= 50,
 };
 
 /*
@@ -161,4 +163,12 @@
 	unsigned long long base_addr;
 	unsigned int size;
 };
+
+/*
+ * Offload TX/RX page information.
+ */
+struct ofld_page_info {
+	unsigned int page_size;  /* Page size, should be a power of 2 */
+	unsigned int num;        /* Number of pages */
+};
 #endif				/* _CXGB3_OFFLOAD_CTL_DEFS_H */
diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h
index 483a594..45e9216 100644
--- a/drivers/net/cxgb3/cxgb3_defs.h
+++ b/drivers/net/cxgb3/cxgb3_defs.h
@@ -79,9 +79,17 @@
 static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t,
 						unsigned int tid)
 {
+	union listen_entry *e;
+
 	if (tid < t->stid_base || tid >= t->stid_base + t->nstids)
 		return NULL;
-	return &(stid2entry(t, tid)->t3c_tid);
+
+	e = stid2entry(t, tid);
+	if ((void *)e->next >= (void *)t->tid_tab &&
+	    (void *)e->next < (void *)&t->atid_tab[t->natids])
+		return NULL;
+
+	return &e->t3c_tid;
 }
 
 /*
@@ -90,9 +98,17 @@
 static inline struct t3c_tid_entry *lookup_atid(const struct tid_info *t,
 						unsigned int tid)
 {
+	union active_open_entry *e;
+
 	if (tid < t->atid_base || tid >= t->atid_base + t->natids)
 		return NULL;
-	return &(atid2entry(t, tid)->t3c_tid);
+
+	e = atid2entry(t, tid);
+	if ((void *)e->next >= (void *)t->tid_tab &&
+	    (void *)e->next < (void *)&t->atid_tab[t->natids])
+		return NULL;
+
+	return &e->t3c_tid;
 }
 
 int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n);
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 6fd1e52..61ffc92 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -339,46 +339,17 @@
 		      V_RRCPLCPUSIZE(6), cpus, rspq_map);
 }
 
-/*
- * If we have multiple receive queues per port serviced by NAPI we need one
- * netdevice per queue as NAPI operates on netdevices.  We already have one
- * netdevice, namely the one associated with the interface, so we use dummy
- * ones for any additional queues.  Note that these netdevices exist purely
- * so that NAPI has something to work with, they do not represent network
- * ports and are not registered.
- */
-static int init_dummy_netdevs(struct adapter *adap)
+static void init_napi(struct adapter *adap)
 {
-	int i, j, dummy_idx = 0;
-	struct net_device *nd;
+	int i;
 
-	for_each_port(adap, i) {
-		struct net_device *dev = adap->port[i];
-		const struct port_info *pi = netdev_priv(dev);
+	for (i = 0; i < SGE_QSETS; i++) {
+		struct sge_qset *qs = &adap->sge.qs[i];
 
-		for (j = 0; j < pi->nqsets - 1; j++) {
-			if (!adap->dummy_netdev[dummy_idx]) {
-				nd = alloc_netdev(0, "", ether_setup);
-				if (!nd)
-					goto free_all;
-
-				nd->priv = adap;
-				nd->weight = 64;
-				set_bit(__LINK_STATE_START, &nd->state);
-				adap->dummy_netdev[dummy_idx] = nd;
-			}
-			strcpy(adap->dummy_netdev[dummy_idx]->name, dev->name);
-			dummy_idx++;
-		}
+		if (qs->adap)
+			netif_napi_add(qs->netdev, &qs->napi, qs->napi.poll,
+				       64);
 	}
-	return 0;
-
-free_all:
-	while (--dummy_idx >= 0) {
-		free_netdev(adap->dummy_netdev[dummy_idx]);
-		adap->dummy_netdev[dummy_idx] = NULL;
-	}
-	return -ENOMEM;
 }
 
 /*
@@ -389,20 +360,18 @@
 static void quiesce_rx(struct adapter *adap)
 {
 	int i;
-	struct net_device *dev;
 
-	for_each_port(adap, i) {
-		dev = adap->port[i];
-		while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
-			msleep(1);
-	}
+	for (i = 0; i < SGE_QSETS; i++)
+		if (adap->sge.qs[i].adap)
+			napi_disable(&adap->sge.qs[i].napi);
+}
 
-	for (i = 0; i < ARRAY_SIZE(adap->dummy_netdev); i++) {
-		dev = adap->dummy_netdev[i];
-		if (dev)
-			while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
-				msleep(1);
-	}
+static void enable_all_napi(struct adapter *adap)
+{
+	int i;
+	for (i = 0; i < SGE_QSETS; i++)
+		if (adap->sge.qs[i].adap)
+			napi_enable(&adap->sge.qs[i].napi);
 }
 
 /**
@@ -415,7 +384,7 @@
  */
 static int setup_sge_qsets(struct adapter *adap)
 {
-	int i, j, err, irq_idx = 0, qset_idx = 0, dummy_dev_idx = 0;
+	int i, j, err, irq_idx = 0, qset_idx = 0;
 	unsigned int ntxq = SGE_TXQ_PER_SET;
 
 	if (adap->params.rev > 0 && !(adap->flags & USING_MSI))
@@ -423,15 +392,14 @@
 
 	for_each_port(adap, i) {
 		struct net_device *dev = adap->port[i];
-		const struct port_info *pi = netdev_priv(dev);
+		struct port_info *pi = netdev_priv(dev);
 
+		pi->qs = &adap->sge.qs[pi->first_qset];
 		for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
 			err = t3_sge_alloc_qset(adap, qset_idx, 1,
 				(adap->flags & USING_MSIX) ? qset_idx + 1 :
 							     irq_idx,
-				&adap->params.sge.qset[qset_idx], ntxq,
-				j == 0 ? dev :
-					 adap-> dummy_netdev[dummy_dev_idx++]);
+				&adap->params.sge.qset[qset_idx], ntxq, dev);
 			if (err) {
 				t3_free_sge_resources(adap);
 				return err;
@@ -482,7 +450,8 @@
 #define CXGB3_SHOW(name, val_expr) \
 static ssize_t format_##name(struct net_device *dev, char *buf) \
 { \
-	struct adapter *adap = dev->priv; \
+	struct port_info *pi = netdev_priv(dev); \
+	struct adapter *adap = pi->adapter; \
 	return sprintf(buf, "%u\n", val_expr); \
 } \
 static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
@@ -493,7 +462,8 @@
 
 static ssize_t set_nfilters(struct net_device *dev, unsigned int val)
 {
-	struct adapter *adap = dev->priv;
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adap = pi->adapter;
 	int min_tids = is_offload(adap) ? MC5_MIN_TIDS : 0;
 
 	if (adap->flags & FULL_INIT_DONE)
@@ -515,7 +485,8 @@
 
 static ssize_t set_nservers(struct net_device *dev, unsigned int val)
 {
-	struct adapter *adap = dev->priv;
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adap = pi->adapter;
 
 	if (adap->flags & FULL_INIT_DONE)
 		return -EBUSY;
@@ -556,9 +527,10 @@
 static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr,
 			    char *buf, int sched)
 {
-	ssize_t len;
+	struct port_info *pi = netdev_priv(to_net_dev(d));
+	struct adapter *adap = pi->adapter;
 	unsigned int v, addr, bpt, cpt;
-	struct adapter *adap = to_net_dev(d)->priv;
+	ssize_t len;
 
 	addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
 	rtnl_lock();
@@ -581,10 +553,11 @@
 static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr,
 			     const char *buf, size_t len, int sched)
 {
+	struct port_info *pi = netdev_priv(to_net_dev(d));
+	struct adapter *adap = pi->adapter;
+	unsigned int val;
 	char *endp;
 	ssize_t ret;
-	unsigned int val;
-	struct adapter *adap = to_net_dev(d)->priv;
 
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
@@ -721,6 +694,7 @@
 }
 
 #define FW_FNAME "t3fw-%d.%d.%d.bin"
+#define TPSRAM_NAME "t3%c_protocol_sram-%d.%d.%d.bin"
 
 static int upgrade_fw(struct adapter *adap)
 {
@@ -739,6 +713,74 @@
 	}
 	ret = t3_load_fw(adap, fw->data, fw->size);
 	release_firmware(fw);
+
+	if (ret == 0)
+		dev_info(dev, "successful upgrade to firmware %d.%d.%d\n",
+			 FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
+	else
+		dev_err(dev, "failed to upgrade to firmware %d.%d.%d\n",
+			FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
+	
+	return ret;
+}
+
+static inline char t3rev2char(struct adapter *adapter)
+{
+	char rev = 0;
+
+	switch(adapter->params.rev) {
+	case T3_REV_B:
+	case T3_REV_B2:
+		rev = 'b';
+		break;
+	case T3_REV_C:
+		rev = 'c';
+		break;
+	}
+	return rev;
+}
+
+static int update_tpsram(struct adapter *adap)
+{
+	const struct firmware *tpsram;
+	char buf[64];
+	struct device *dev = &adap->pdev->dev;
+	int ret;
+	char rev;
+	
+	rev = t3rev2char(adap);
+	if (!rev)
+		return 0;
+
+	snprintf(buf, sizeof(buf), TPSRAM_NAME, rev,
+		 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
+
+	ret = request_firmware(&tpsram, buf, dev);
+	if (ret < 0) {
+		dev_err(dev, "could not load TP SRAM: unable to load %s\n",
+			buf);
+		return ret;
+	}
+	
+	ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);
+	if (ret)
+		goto release_tpsram;	
+
+	ret = t3_set_proto_sram(adap, tpsram->data);
+	if (ret == 0)
+		dev_info(dev,
+			 "successful update of protocol engine "
+			 "to %d.%d.%d\n",
+			 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
+	else
+		dev_err(dev, "failed to update of protocol engine %d.%d.%d\n",
+			TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
+	if (ret)
+		dev_err(dev, "loading protocol SRAM failed\n");
+
+release_tpsram:
+	release_firmware(tpsram);
+	
 	return ret;
 }
 
@@ -754,30 +796,36 @@
  */
 static int cxgb_up(struct adapter *adap)
 {
-	int err = 0;
+	int err;
+	int must_load;
 
 	if (!(adap->flags & FULL_INIT_DONE)) {
-		err = t3_check_fw_version(adap);
-		if (err == -EINVAL)
+		err = t3_check_fw_version(adap, &must_load);
+		if (err == -EINVAL) {
 			err = upgrade_fw(adap);
-		if (err)
-			goto out;
+			if (err && must_load)
+				goto out;
+		}
 
-		err = init_dummy_netdevs(adap);
-		if (err)
-			goto out;
+		err = t3_check_tpsram_version(adap, &must_load);
+		if (err == -EINVAL) {
+			err = update_tpsram(adap);
+			if (err && must_load)
+				goto out;
+		}
 
 		err = t3_init_hw(adap, 0);
 		if (err)
 			goto out;
 
 		t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
-		
+
 		err = setup_sge_qsets(adap);
 		if (err)
 			goto out;
 
 		setup_rss(adap);
+		init_napi(adap);
 		adap->flags |= FULL_INIT_DONE;
 	}
 
@@ -804,6 +852,7 @@
 				      adap->name, adap)))
 		goto irq_err;
 
+	enable_all_napi(adap);
 	t3_sge_start(adap);
 	t3_intr_enable(adap);
 
@@ -858,10 +907,11 @@
 
 static int offload_open(struct net_device *dev)
 {
-	struct adapter *adapter = dev->priv;
-	struct t3cdev *tdev = T3CDEV(dev);
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
+	struct t3cdev *tdev = dev2t3cdev(dev);
 	int adap_up = adapter->open_device_map & PORT_MASK;
-	int err = 0;
+	int err;
 
 	if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
 		return 0;
@@ -924,13 +974,15 @@
 
 static int cxgb_open(struct net_device *dev)
 {
-	int err;
-	struct adapter *adapter = dev->priv;
 	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
 	int other_ports = adapter->open_device_map & PORT_MASK;
+	int err;
 
-	if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
+	if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) {
+		quiesce_rx(adapter);
 		return err;
+	}
 
 	set_bit(pi->port_id, &adapter->open_device_map);
 	if (is_offload(adapter) && !ofld_disable) {
@@ -951,17 +1003,17 @@
 
 static int cxgb_close(struct net_device *dev)
 {
-	struct adapter *adapter = dev->priv;
-	struct port_info *p = netdev_priv(dev);
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
 
-	t3_port_intr_disable(adapter, p->port_id);
+	t3_port_intr_disable(adapter, pi->port_id);
 	netif_stop_queue(dev);
-	p->phy.ops->power_down(&p->phy, 1);
+	pi->phy.ops->power_down(&pi->phy, 1);
 	netif_carrier_off(dev);
-	t3_mac_disable(&p->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
+	t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
 
 	spin_lock(&adapter->work_lock);	/* sync with update task */
-	clear_bit(p->port_id, &adapter->open_device_map);
+	clear_bit(pi->port_id, &adapter->open_device_map);
 	spin_unlock(&adapter->work_lock);
 
 	if (!(adapter->open_device_map & PORT_MASK))
@@ -976,13 +1028,13 @@
 
 static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
 {
-	struct adapter *adapter = dev->priv;
-	struct port_info *p = netdev_priv(dev);
-	struct net_device_stats *ns = &p->netstats;
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
+	struct net_device_stats *ns = &pi->netstats;
 	const struct mac_stats *pstats;
 
 	spin_lock(&adapter->stats_lock);
-	pstats = t3_mac_update_stats(&p->mac);
+	pstats = t3_mac_update_stats(&pi->mac);
 	spin_unlock(&adapter->stats_lock);
 
 	ns->tx_bytes = pstats->tx_octets;
@@ -1015,14 +1067,16 @@
 
 static u32 get_msglevel(struct net_device *dev)
 {
-	struct adapter *adapter = dev->priv;
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
 
 	return adapter->msg_enable;
 }
 
 static void set_msglevel(struct net_device *dev, u32 val)
 {
-	struct adapter *adapter = dev->priv;
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
 
 	adapter->msg_enable = val;
 }
@@ -1077,9 +1131,14 @@
 
 };
 
-static int get_stats_count(struct net_device *dev)
+static int get_sset_count(struct net_device *dev, int sset)
 {
-	return ARRAY_SIZE(stats_strings);
+	switch (sset) {
+	case ETH_SS_STATS:
+		return ARRAY_SIZE(stats_strings);
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 #define T3_REGMAP_SIZE (3 * 1024)
@@ -1096,10 +1155,13 @@
 
 static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
 	u32 fw_vers = 0;
-	struct adapter *adapter = dev->priv;
+	u32 tp_vers = 0;
 
 	t3_get_fw_version(adapter, &fw_vers);
+	t3_get_tp_version(adapter, &tp_vers);
 
 	strcpy(info->driver, DRV_NAME);
 	strcpy(info->version, DRV_VERSION);
@@ -1108,11 +1170,14 @@
 		strcpy(info->fw_version, "N/A");
 	else {
 		snprintf(info->fw_version, sizeof(info->fw_version),
-			 "%s %u.%u.%u",
+			 "%s %u.%u.%u TP %u.%u.%u",
 			 G_FW_VERSION_TYPE(fw_vers) ? "T" : "N",
 			 G_FW_VERSION_MAJOR(fw_vers),
 			 G_FW_VERSION_MINOR(fw_vers),
-			 G_FW_VERSION_MICRO(fw_vers));
+			 G_FW_VERSION_MICRO(fw_vers),
+			 G_TP_VERSION_MAJOR(tp_vers),
+			 G_TP_VERSION_MINOR(tp_vers),
+			 G_TP_VERSION_MICRO(tp_vers));
 	}
 }
 
@@ -1136,8 +1201,8 @@
 static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
 		      u64 *data)
 {
-	struct adapter *adapter = dev->priv;
 	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
 	const struct mac_stats *s;
 
 	spin_lock(&adapter->stats_lock);
@@ -1205,7 +1270,8 @@
 static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
 		     void *buf)
 {
-	struct adapter *ap = dev->priv;
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *ap = pi->adapter;
 
 	/*
 	 * Version scheme:
@@ -1246,8 +1312,9 @@
 
 static int cxgb3_phys_id(struct net_device *dev, u32 data)
 {
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
 	int i;
-	struct adapter *adapter = dev->priv;
 
 	if (data == 0)
 		data = 2;
@@ -1408,8 +1475,8 @@
 
 static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
 {
-	const struct adapter *adapter = dev->priv;
-	const struct port_info *pi = netdev_priv(dev);
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
 	const struct qset_params *q = &adapter->params.sge.qset[pi->first_qset];
 
 	e->rx_max_pending = MAX_RX_BUFFERS;
@@ -1425,10 +1492,10 @@
 
 static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
 {
-	int i;
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
 	struct qset_params *q;
-	struct adapter *adapter = dev->priv;
-	const struct port_info *pi = netdev_priv(dev);
+	int i;
 
 	if (e->rx_pending > MAX_RX_BUFFERS ||
 	    e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS ||
@@ -1457,7 +1524,8 @@
 
 static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
 {
-	struct adapter *adapter = dev->priv;
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
 	struct qset_params *qsp = &adapter->params.sge.qset[0];
 	struct sge_qset *qs = &adapter->sge.qs[0];
 
@@ -1471,7 +1539,8 @@
 
 static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
 {
-	struct adapter *adapter = dev->priv;
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
 	struct qset_params *q = adapter->params.sge.qset;
 
 	c->rx_coalesce_usecs = q->coalesce_usecs;
@@ -1481,8 +1550,9 @@
 static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
 		      u8 * data)
 {
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
 	int i, err = 0;
-	struct adapter *adapter = dev->priv;
 
 	u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL);
 	if (!buf)
@@ -1501,10 +1571,11 @@
 static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 		      u8 * data)
 {
-	u8 *buf;
-	int err = 0;
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
 	u32 aligned_offset, aligned_len, *p;
-	struct adapter *adapter = dev->priv;
+	u8 *buf;
+	int err;
 
 	if (eeprom->magic != EEPROM_MAGIC)
 		return -EINVAL;
@@ -1568,22 +1639,18 @@
 	.set_pauseparam = set_pauseparam,
 	.get_rx_csum = get_rx_csum,
 	.set_rx_csum = set_rx_csum,
-	.get_tx_csum = ethtool_op_get_tx_csum,
 	.set_tx_csum = ethtool_op_set_tx_csum,
-	.get_sg = ethtool_op_get_sg,
 	.set_sg = ethtool_op_set_sg,
 	.get_link = ethtool_op_get_link,
 	.get_strings = get_strings,
 	.phys_id = cxgb3_phys_id,
 	.nway_reset = restart_autoneg,
-	.get_stats_count = get_stats_count,
+	.get_sset_count = get_sset_count,
 	.get_ethtool_stats = get_stats,
 	.get_regs_len = get_regs_len,
 	.get_regs = get_regs,
 	.get_wol = get_wol,
-	.get_tso = ethtool_op_get_tso,
 	.set_tso = ethtool_op_set_tso,
-	.get_perm_addr = ethtool_op_get_perm_addr
 };
 
 static int in_range(int val, int lo, int hi)
@@ -1593,9 +1660,10 @@
 
 static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
 {
-	int ret;
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
 	u32 cmd;
-	struct adapter *adapter = dev->priv;
+	int ret;
 
 	if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
 		return -EFAULT;
@@ -1701,7 +1769,6 @@
 	}
 	case CHELSIO_SET_QSET_NUM:{
 		struct ch_reg edata;
-		struct port_info *pi = netdev_priv(dev);
 		unsigned int i, first_qset = 0, other_qsets = 0;
 
 		if (!capable(CAP_NET_ADMIN))
@@ -1733,7 +1800,6 @@
 	}
 	case CHELSIO_GET_QSET_NUM:{
 		struct ch_reg edata;
-		struct port_info *pi = netdev_priv(dev);
 
 		edata.cmd = CHELSIO_GET_QSET_NUM;
 		edata.val = pi->nqsets;
@@ -1924,10 +1990,10 @@
 
 static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
 {
-	int ret, mmd;
-	struct adapter *adapter = dev->priv;
-	struct port_info *pi = netdev_priv(dev);
 	struct mii_ioctl_data *data = if_mii(req);
+	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
+	int ret, mmd;
 
 	switch (cmd) {
 	case SIOCGMIIPHY:
@@ -1995,9 +2061,9 @@
 
 static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
 {
-	int ret;
-	struct adapter *adapter = dev->priv;
 	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
+	int ret;
 
 	if (new_mtu < 81)	/* accommodate SACK */
 		return -EINVAL;
@@ -2014,8 +2080,8 @@
 
 static int cxgb_set_mac_addr(struct net_device *dev, void *p)
 {
-	struct adapter *adapter = dev->priv;
 	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
 	struct sockaddr *addr = p;
 
 	if (!is_valid_ether_addr(addr->sa_data))
@@ -2051,8 +2117,8 @@
 
 static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
 {
-	struct adapter *adapter = dev->priv;
 	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
 
 	pi->vlan_grp = grp;
 	if (adapter->params.rev > 0)
@@ -2071,8 +2137,8 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void cxgb_netpoll(struct net_device *dev)
 {
-	struct adapter *adapter = dev->priv;
 	struct port_info *pi = netdev_priv(dev);
+	struct adapter *adapter = pi->adapter;
 	int qidx;
 
 	for (qidx = pi->first_qset; qidx < pi->first_qset + pi->nqsets; qidx++) {
@@ -2089,42 +2155,6 @@
 }
 #endif
 
-#define TPSRAM_NAME "t3%c_protocol_sram-%d.%d.%d.bin"
-int update_tpsram(struct adapter *adap)
-{
-	const struct firmware *tpsram;
-	char buf[64];
-	struct device *dev = &adap->pdev->dev;
-	int ret;
-	char rev;
-	
-	rev = adap->params.rev == T3_REV_B2 ? 'b' : 'a';
-
-	snprintf(buf, sizeof(buf), TPSRAM_NAME, rev,
-		 TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
-
-	ret = request_firmware(&tpsram, buf, dev);
-	if (ret < 0) {
-		dev_err(dev, "could not load TP SRAM: unable to load %s\n",
-			buf);
-		return ret;
-	}
-	
-	ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);
-	if (ret)
-		goto release_tpsram;	
-
-	ret = t3_set_proto_sram(adap, tpsram->data);
-	if (ret)
-		dev_err(dev, "loading protocol SRAM failed\n");
-
-release_tpsram:
-	release_firmware(tpsram);
-	
-	return ret;
-}
-
-
 /*
  * Periodic accumulation of MAC statistics.
  */
@@ -2271,6 +2301,10 @@
 
 	if (adapter->flags & FULL_INIT_DONE) {
 		t3_sge_stop(adapter);
+		t3_write_reg(adapter, A_XGM_TX_CTRL, 0);
+		t3_write_reg(adapter, A_XGM_RX_CTRL, 0);
+		t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0);
+		t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0);
 		t3_intr_disable(adapter);
 	}
 	CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
@@ -2330,10 +2364,12 @@
 		       (adap->flags & USING_MSIX) ? " MSI-X" :
 		       (adap->flags & USING_MSI) ? " MSI" : "");
 		if (adap->name == dev->name && adap->params.vpd.mclk)
-			printk(KERN_INFO "%s: %uMB CM, %uMB PMTX, %uMB PMRX\n",
+			printk(KERN_INFO
+			       "%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n",
 			       adap->name, t3_mc7_size(&adap->cm) >> 20,
 			       t3_mc7_size(&adap->pmtx) >> 20,
-			       t3_mc7_size(&adap->pmrx) >> 20);
+			       t3_mc7_size(&adap->pmrx) >> 20,
+			       adap->params.vpd.sn);
 	}
 }
 
@@ -2429,11 +2465,11 @@
 			goto out_free_dev;
 		}
 
-		SET_MODULE_OWNER(netdev);
 		SET_NETDEV_DEV(netdev, &pdev->dev);
 
 		adapter->port[i] = netdev;
 		pi = netdev_priv(netdev);
+		pi->adapter = adapter;
 		pi->rx_csum_offload = 1;
 		pi->nqsets = 1;
 		pi->first_qset = i;
@@ -2443,7 +2479,6 @@
 		netdev->irq = pdev->irq;
 		netdev->mem_start = mmio_start;
 		netdev->mem_end = mmio_start + mmio_len - 1;
-		netdev->priv = adapter;
 		netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
 		netdev->features |= NETIF_F_LLTX;
 		if (pci_using_dac)
@@ -2463,23 +2498,15 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 		netdev->poll_controller = cxgb_netpoll;
 #endif
-		netdev->weight = 64;
 
 		SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
 	}
 
-	pci_set_drvdata(pdev, adapter->port[0]);
+	pci_set_drvdata(pdev, adapter);
 	if (t3_prep_adapter(adapter, ai, 1) < 0) {
 		err = -ENODEV;
 		goto out_free_dev;
 	}
-
-	err = t3_check_tpsram_version(adapter);
-	if (err == -EINVAL)
-		err = update_tpsram(adapter);
-
-	if (err)
-		goto out_free_dev;
 		
 	/*
 	 * The card is now ready to go.  If any errors occur during device
@@ -2548,11 +2575,10 @@
 
 static void __devexit remove_one(struct pci_dev *pdev)
 {
-	struct net_device *dev = pci_get_drvdata(pdev);
+	struct adapter *adapter = pci_get_drvdata(pdev);
 
-	if (dev) {
+	if (adapter) {
 		int i;
-		struct adapter *adapter = dev->priv;
 
 		t3_sge_stop(adapter);
 		sysfs_remove_group(&adapter->port[0]->dev.kobj,
@@ -2572,12 +2598,6 @@
 		t3_free_sge_resources(adapter);
 		cxgb_disable_msi(adapter);
 
-		for (i = 0; i < ARRAY_SIZE(adapter->dummy_netdev); i++)
-			if (adapter->dummy_netdev[i]) {
-				free_netdev(adapter->dummy_netdev[i]);
-				adapter->dummy_netdev[i] = NULL;
-			}
-
 		for_each_port(adapter, i)
 			if (adapter->port[i])
 				free_netdev(adapter->port[i]);
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
index ebcf35e..bd25421 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -57,7 +57,7 @@
 static LIST_HEAD(adapter_list);
 
 static const unsigned int MAX_ATIDS = 64 * 1024;
-static const unsigned int ATID_BASE = 0x100000;
+static const unsigned int ATID_BASE = 0x10000;
 
 static inline int offload_activated(struct t3cdev *tdev)
 {
@@ -222,32 +222,32 @@
 	int ret = 0;
 
 	switch (req) {
-	case RDMA_GET_PARAMS:{
-		struct rdma_info *req = data;
+	case RDMA_GET_PARAMS: {
+		struct rdma_info *rdma = data;
 		struct pci_dev *pdev = adapter->pdev;
 
-		req->udbell_physbase = pci_resource_start(pdev, 2);
-		req->udbell_len = pci_resource_len(pdev, 2);
-		req->tpt_base =
+		rdma->udbell_physbase = pci_resource_start(pdev, 2);
+		rdma->udbell_len = pci_resource_len(pdev, 2);
+		rdma->tpt_base =
 			t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT);
-		req->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT);
-		req->pbl_base =
+		rdma->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT);
+		rdma->pbl_base =
 			t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT);
-		req->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT);
-		req->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT);
-		req->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT);
-		req->kdb_addr = adapter->regs + A_SG_KDOORBELL;
-		req->pdev = pdev;
+		rdma->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT);
+		rdma->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT);
+		rdma->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT);
+		rdma->kdb_addr = adapter->regs + A_SG_KDOORBELL;
+		rdma->pdev = pdev;
 		break;
 	}
 	case RDMA_CQ_OP:{
 		unsigned long flags;
-		struct rdma_cq_op *req = data;
+		struct rdma_cq_op *rdma = data;
 
 		/* may be called in any context */
 		spin_lock_irqsave(&adapter->sge.reg_lock, flags);
-		ret = t3_sge_cqcntxt_op(adapter, req->id, req->op,
-					req->credits);
+		ret = t3_sge_cqcntxt_op(adapter, rdma->id, rdma->op,
+					rdma->credits);
 		spin_unlock_irqrestore(&adapter->sge.reg_lock, flags);
 		break;
 	}
@@ -274,15 +274,15 @@
 		break;
 	}
 	case RDMA_CQ_SETUP:{
-		struct rdma_cq_setup *req = data;
+		struct rdma_cq_setup *rdma = data;
 
 		spin_lock_irq(&adapter->sge.reg_lock);
 		ret =
-			t3_sge_init_cqcntxt(adapter, req->id,
-					req->base_addr, req->size,
+			t3_sge_init_cqcntxt(adapter, rdma->id,
+					rdma->base_addr, rdma->size,
 					ASYNC_NOTIF_RSPQ,
-					req->ovfl_mode, req->credits,
-					req->credit_thres);
+					rdma->ovfl_mode, rdma->credits,
+					rdma->credit_thres);
 		spin_unlock_irq(&adapter->sge.reg_lock);
 		break;
 	}
@@ -292,13 +292,13 @@
 		spin_unlock_irq(&adapter->sge.reg_lock);
 		break;
 	case RDMA_CTRL_QP_SETUP:{
-		struct rdma_ctrlqp_setup *req = data;
+		struct rdma_ctrlqp_setup *rdma = data;
 
 		spin_lock_irq(&adapter->sge.reg_lock);
 		ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0,
 						SGE_CNTXT_RDMA,
 						ASYNC_NOTIF_RSPQ,
-						req->base_addr, req->size,
+						rdma->base_addr, rdma->size,
 						FW_RI_TID_START, 1, 0);
 		spin_unlock_irq(&adapter->sge.reg_lock);
 		break;
@@ -317,6 +317,8 @@
 	struct iff_mac *iffmacp;
 	struct ddp_params *ddpp;
 	struct adap_ports *ports;
+	struct ofld_page_info *rx_page_info;
+	struct tp_params *tp = &adapter->params.tp;
 	int i;
 
 	switch (req) {
@@ -382,6 +384,11 @@
 		if (!offload_running(adapter))
 			return -EAGAIN;
 		return cxgb_rdma_ctl(adapter, req, data);
+	case GET_RX_PAGE_INFO:
+		rx_page_info = data;
+		rx_page_info->page_size = tp->rx_pg_size;
+		rx_page_info->num = tp->rx_num_pgs;
+		break;
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -593,6 +600,16 @@
 
 EXPORT_SYMBOL(cxgb3_alloc_stid);
 
+/* Get the t3cdev associated with a net_device */
+struct t3cdev *dev2t3cdev(struct net_device *dev)
+{
+	const struct port_info *pi = netdev_priv(dev);
+
+	return (struct t3cdev *)pi->adapter;
+}
+
+EXPORT_SYMBOL(dev2t3cdev);
+
 static int do_smt_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
 {
 	struct cpl_smt_write_rpl *rpl = cplhdr(skb);
@@ -677,10 +694,19 @@
 {
 	struct cpl_pass_accept_req *req = cplhdr(skb);
 	unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+	struct tid_info *t = &(T3C_DATA(dev))->tid_maps;
 	struct t3c_tid_entry *t3c_tid;
+	unsigned int tid = GET_TID(req);
 
-	t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
-	if (t3c_tid->ctx && t3c_tid->client->handlers &&
+	if (unlikely(tid >= t->ntids)) {
+		printk("%s: passive open TID %u too large\n",
+		       dev->name, tid);
+		t3_fatal_err(tdev2adap(dev));
+		return CPL_RET_BUF_DONE;
+	}
+
+	t3c_tid = lookup_stid(t, stid);
+	if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
 	    t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) {
 		return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]
 		    (dev, skb, t3c_tid->ctx);
@@ -699,7 +725,7 @@
  * the buffer.
  */
 static struct sk_buff *cxgb3_get_cpl_reply_skb(struct sk_buff *skb, size_t len,
-					       int gfp)
+					       gfp_t gfp)
 {
 	if (likely(!skb_cloned(skb))) {
 		BUG_ON(skb->len < len);
@@ -762,16 +788,25 @@
 {
 	struct cpl_act_establish *req = cplhdr(skb);
 	unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+	struct tid_info *t = &(T3C_DATA(dev))->tid_maps;
 	struct t3c_tid_entry *t3c_tid;
+	unsigned int tid = GET_TID(req);
 
-	t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
+	if (unlikely(tid >= t->ntids)) {
+		printk("%s: active establish TID %u too large\n",
+		       dev->name, tid);
+		t3_fatal_err(tdev2adap(dev));
+		return CPL_RET_BUF_DONE;
+	}
+
+	t3c_tid = lookup_atid(t, atid);
 	if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
 	    t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) {
 		return t3c_tid->client->handlers[CPL_ACT_ESTABLISH]
 		    (dev, skb, t3c_tid->ctx);
 	} else {
 		printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
-		       dev->name, CPL_PASS_ACCEPT_REQ);
+		       dev->name, CPL_ACT_ESTABLISH);
 		return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
 	}
 }
@@ -925,7 +960,7 @@
 	struct net_device *dev = neigh->dev;
 
 	if (dev && (is_offloading(dev))) {
-		struct t3cdev *tdev = T3CDEV(dev);
+		struct t3cdev *tdev = dev2t3cdev(dev);
 
 		BUG_ON(!tdev);
 		t3_l2t_update(tdev, neigh);
@@ -973,9 +1008,9 @@
 		       "device ignored.\n", __FUNCTION__);
 		return;
 	}
-	tdev = T3CDEV(olddev);
+	tdev = dev2t3cdev(olddev);
 	BUG_ON(!tdev);
-	if (tdev != T3CDEV(newdev)) {
+	if (tdev != dev2t3cdev(newdev)) {
 		printk(KERN_WARNING "%s: Redirect to different "
 		       "offload device ignored.\n", __FUNCTION__);
 		return;
diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h
index f15446a..7a37913 100644
--- a/drivers/net/cxgb3/cxgb3_offload.h
+++ b/drivers/net/cxgb3/cxgb3_offload.h
@@ -51,6 +51,8 @@
 
 void cxgb3_set_dummy_ops(struct t3cdev *dev);
 
+struct t3cdev *dev2t3cdev(struct net_device *dev);
+
 /*
  * Client registration.  Users of T3 driver must register themselves.
  * The T3 driver will call the add function of every client for each T3
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h
index aa80313..5e1bc0d 100644
--- a/drivers/net/cxgb3/regs.h
+++ b/drivers/net/cxgb3/regs.h
@@ -172,6 +172,14 @@
 
 #define A_SG_INT_CAUSE 0x5c
 
+#define S_HIPIODRBDROPERR    11
+#define V_HIPIODRBDROPERR(x) ((x) << S_HIPIODRBDROPERR)
+#define F_HIPIODRBDROPERR    V_HIPIODRBDROPERR(1U)
+
+#define S_LOPIODRBDROPERR    10
+#define V_LOPIODRBDROPERR(x) ((x) << S_LOPIODRBDROPERR)
+#define F_LOPIODRBDROPERR    V_LOPIODRBDROPERR(1U)
+
 #define S_RSPQDISABLED    3
 #define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED)
 #define F_RSPQDISABLED    V_RSPQDISABLED(1U)
@@ -1318,6 +1326,7 @@
 #define V_D0_WEIGHT(x) ((x) << S_D0_WEIGHT)
 
 #define A_PM1_RX_CFG 0x5c0
+#define A_PM1_RX_MODE 0x5c4
 
 #define A_PM1_RX_INT_ENABLE 0x5d8
 
@@ -1386,6 +1395,7 @@
 #define A_PM1_RX_INT_CAUSE 0x5dc
 
 #define A_PM1_TX_CFG 0x5e0
+#define A_PM1_TX_MODE 0x5e4
 
 #define A_PM1_TX_INT_ENABLE 0x5f8
 
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index a2cfd68..994b5d6 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -79,7 +79,7 @@
 };
 
 struct tx_desc {
-	u64 flit[TX_DESC_FLITS];
+	__be64 flit[TX_DESC_FLITS];
 };
 
 struct rx_desc {
@@ -544,7 +544,7 @@
  *	as HW contexts, packet buffers, and descriptor rings.  Traffic to the
  *	queue set must be quiesced prior to calling this.
  */
-void t3_free_qset(struct adapter *adapter, struct sge_qset *q)
+static void t3_free_qset(struct adapter *adapter, struct sge_qset *q)
 {
 	int i;
 	struct pci_dev *pdev = adapter->pdev;
@@ -591,9 +591,6 @@
 				  q->rspq.desc, q->rspq.phys_addr);
 	}
 
-	if (q->netdev)
-		q->netdev->atalk_ptr = NULL;
-
 	memset(q, 0, sizeof(*q));
 }
 
@@ -907,8 +904,8 @@
 			     const struct sge_txq *q,
 			     const struct sg_ent *sgl,
 			     unsigned int flits, unsigned int sgl_flits,
-			     unsigned int gen, unsigned int wr_hi,
-			     unsigned int wr_lo)
+			     unsigned int gen, __be32 wr_hi,
+			     __be32 wr_lo)
 {
 	struct work_request_hdr *wrp = (struct work_request_hdr *)d;
 	struct tx_sw_desc *sd = &q->sdesc[pidx];
@@ -1073,8 +1070,8 @@
 {
 	unsigned int ndesc, pidx, credits, gen, compl;
 	const struct port_info *pi = netdev_priv(dev);
-	struct adapter *adap = dev->priv;
-	struct sge_qset *qs = dev2qset(dev);
+	struct adapter *adap = pi->adapter;
+	struct sge_qset *qs = pi->qs;
 	struct sge_txq *q = &qs->txq[TXQ_ETH];
 
 	/*
@@ -1182,8 +1179,8 @@
  *
  *	Writes a packet as immediate data into a Tx descriptor.  The packet
  *	contains a work request at its beginning.  We must write the packet
- *	carefully so the SGE doesn't read accidentally before it's written in
- *	its entirety.
+ *	carefully so the SGE doesn't read it accidentally before it's written
+ *	in its entirety.
  */
 static inline void write_imm(struct tx_desc *d, struct sk_buff *skb,
 			     unsigned int len, unsigned int gen)
@@ -1191,7 +1188,11 @@
 	struct work_request_hdr *from = (struct work_request_hdr *)skb->data;
 	struct work_request_hdr *to = (struct work_request_hdr *)d;
 
-	memcpy(&to[1], &from[1], len - sizeof(*from));
+	if (likely(!skb->data_len))
+		memcpy(&to[1], &from[1], len - sizeof(*from));
+	else
+		skb_copy_bits(skb, sizeof(*from), &to[1], len - sizeof(*from));
+
 	to->wr_hi = from->wr_hi | htonl(F_WR_SOP | F_WR_EOP |
 					V_WR_BCNTLFLT(len & 7));
 	wmb();
@@ -1261,7 +1262,7 @@
 
 static inline int immediate(const struct sk_buff *skb)
 {
-	return skb->len <= WR_LEN && !skb->data_len;
+	return skb->len <= WR_LEN;
 }
 
 /**
@@ -1326,12 +1327,12 @@
 	struct sk_buff *skb;
 	struct sge_qset *qs = (struct sge_qset *)data;
 	struct sge_txq *q = &qs->txq[TXQ_CTRL];
-	struct adapter *adap = qs->netdev->priv;
 
 	spin_lock(&q->lock);
       again:reclaim_completed_tx_imm(q);
 
-	while (q->in_use < q->size && (skb = __skb_dequeue(&q->sendq)) != NULL) {
+	while (q->in_use < q->size &&
+	       (skb = __skb_dequeue(&q->sendq)) != NULL) {
 
 		write_imm(&q->desc[q->pidx], skb, skb->len, q->gen);
 
@@ -1353,7 +1354,7 @@
 	}
 
 	spin_unlock(&q->lock);
-	t3_write_reg(adap, A_SG_KDOORBELL,
+	t3_write_reg(qs->adap, A_SG_KDOORBELL,
 		     F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
 }
 
@@ -1467,12 +1468,13 @@
  */
 static inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb)
 {
-	unsigned int flits, cnt = skb_shinfo(skb)->nr_frags;
+	unsigned int flits, cnt;
 
-	if (skb->len <= WR_LEN && cnt == 0)
+	if (skb->len <= WR_LEN)
 		return 1;	/* packet fits as immediate data */
 
 	flits = skb_transport_offset(skb) / 8;	/* headers */
+	cnt = skb_shinfo(skb)->nr_frags;
 	if (skb->tail != skb->transport_header)
 		cnt++;
 	return flits_to_desc(flits + sgl_len(cnt));
@@ -1531,7 +1533,8 @@
 	struct sk_buff *skb;
 	struct sge_qset *qs = (struct sge_qset *)data;
 	struct sge_txq *q = &qs->txq[TXQ_OFLD];
-	struct adapter *adap = qs->netdev->priv;
+	const struct port_info *pi = netdev_priv(qs->netdev);
+	struct adapter *adap = pi->adapter;
 
 	spin_lock(&q->lock);
       again:reclaim_completed_tx(adap, q);
@@ -1636,8 +1639,7 @@
 	else {
 		struct sge_qset *qs = rspq_to_qset(q);
 
-		if (__netif_rx_schedule_prep(qs->netdev))
-			__netif_rx_schedule(qs->netdev);
+		napi_schedule(&qs->napi);
 		q->rx_head = skb;
 	}
 	q->rx_tail = skb;
@@ -1673,33 +1675,30 @@
  *	receive handler.  Batches need to be of modest size as we do prefetches
  *	on the packets in each.
  */
-static int ofld_poll(struct net_device *dev, int *budget)
+static int ofld_poll(struct napi_struct *napi, int budget)
 {
-	struct adapter *adapter = dev->priv;
-	struct sge_qset *qs = dev2qset(dev);
+	struct sge_qset *qs = container_of(napi, struct sge_qset, napi);
 	struct sge_rspq *q = &qs->rspq;
-	int work_done, limit = min(*budget, dev->quota), avail = limit;
+	struct adapter *adapter = qs->adap;
+	int work_done = 0;
 
-	while (avail) {
+	while (work_done < budget) {
 		struct sk_buff *head, *tail, *skbs[RX_BUNDLE_SIZE];
 		int ngathered;
 
 		spin_lock_irq(&q->lock);
 		head = q->rx_head;
 		if (!head) {
-			work_done = limit - avail;
-			*budget -= work_done;
-			dev->quota -= work_done;
-			__netif_rx_complete(dev);
+			napi_complete(napi);
 			spin_unlock_irq(&q->lock);
-			return 0;
+			return work_done;
 		}
 
 		tail = q->rx_tail;
 		q->rx_head = q->rx_tail = NULL;
 		spin_unlock_irq(&q->lock);
 
-		for (ngathered = 0; avail && head; avail--) {
+		for (ngathered = 0; work_done < budget && head; work_done++) {
 			prefetch(head->data);
 			skbs[ngathered] = head;
 			head = head->next;
@@ -1721,10 +1720,8 @@
 		}
 		deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered);
 	}
-	work_done = limit - avail;
-	*budget -= work_done;
-	dev->quota -= work_done;
-	return 1;
+
+	return work_done;
 }
 
 /**
@@ -2068,49 +2065,47 @@
 
 /**
  *	napi_rx_handler - the NAPI handler for Rx processing
- *	@dev: the net device
+ *	@napi: the napi instance
  *	@budget: how many packets we can process in this round
  *
  *	Handler for new data events when using NAPI.
  */
-static int napi_rx_handler(struct net_device *dev, int *budget)
+static int napi_rx_handler(struct napi_struct *napi, int budget)
 {
-	struct adapter *adap = dev->priv;
-	struct sge_qset *qs = dev2qset(dev);
-	int effective_budget = min(*budget, dev->quota);
+	struct sge_qset *qs = container_of(napi, struct sge_qset, napi);
+	struct adapter *adap = qs->adap;
+	int work_done = process_responses(adap, qs, budget);
 
-	int work_done = process_responses(adap, qs, effective_budget);
-	*budget -= work_done;
-	dev->quota -= work_done;
+	if (likely(work_done < budget)) {
+		napi_complete(napi);
 
-	if (work_done >= effective_budget)
-		return 1;
-
-	netif_rx_complete(dev);
-
-	/*
-	 * Because we don't atomically flush the following write it is
-	 * possible that in very rare cases it can reach the device in a way
-	 * that races with a new response being written plus an error interrupt
-	 * causing the NAPI interrupt handler below to return unhandled status
-	 * to the OS.  To protect against this would require flushing the write
-	 * and doing both the write and the flush with interrupts off.  Way too
-	 * expensive and unjustifiable given the rarity of the race.
-	 *
-	 * The race cannot happen at all with MSI-X.
-	 */
-	t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) |
-		     V_NEWTIMER(qs->rspq.next_holdoff) |
-		     V_NEWINDEX(qs->rspq.cidx));
-	return 0;
+		/*
+		 * Because we don't atomically flush the following
+		 * write it is possible that in very rare cases it can
+		 * reach the device in a way that races with a new
+		 * response being written plus an error interrupt
+		 * causing the NAPI interrupt handler below to return
+		 * unhandled status to the OS.  To protect against
+		 * this would require flushing the write and doing
+		 * both the write and the flush with interrupts off.
+		 * Way too expensive and unjustifiable given the
+		 * rarity of the race.
+		 *
+		 * The race cannot happen at all with MSI-X.
+		 */
+		t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) |
+			     V_NEWTIMER(qs->rspq.next_holdoff) |
+			     V_NEWINDEX(qs->rspq.cidx));
+	}
+	return work_done;
 }
 
 /*
  * Returns true if the device is already scheduled for polling.
  */
-static inline int napi_is_scheduled(struct net_device *dev)
+static inline int napi_is_scheduled(struct napi_struct *napi)
 {
-	return test_bit(__LINK_STATE_RX_SCHED, &dev->state);
+	return test_bit(NAPI_STATE_SCHED, &napi->state);
 }
 
 /**
@@ -2193,8 +2188,7 @@
 			     V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx));
 		return 0;
 	}
-	if (likely(__netif_rx_schedule_prep(qs->netdev)))
-		__netif_rx_schedule(qs->netdev);
+	napi_schedule(&qs->napi);
 	return 1;
 }
 
@@ -2205,7 +2199,7 @@
 irqreturn_t t3_sge_intr_msix(int irq, void *cookie)
 {
 	struct sge_qset *qs = cookie;
-	struct adapter *adap = qs->netdev->priv;
+	struct adapter *adap = qs->adap;
 	struct sge_rspq *q = &qs->rspq;
 
 	spin_lock(&q->lock);
@@ -2221,15 +2215,14 @@
  * The MSI-X interrupt handler for an SGE response queue for the NAPI case
  * (i.e., response queue serviced by NAPI polling).
  */
-irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie)
+static irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie)
 {
 	struct sge_qset *qs = cookie;
-	struct adapter *adap = qs->netdev->priv;
 	struct sge_rspq *q = &qs->rspq;
 
 	spin_lock(&q->lock);
 
-	if (handle_responses(adap, q) < 0)
+	if (handle_responses(qs->adap, q) < 0)
 		q->unhandled_irqs++;
 	spin_unlock(&q->lock);
 	return IRQ_HANDLED;
@@ -2272,11 +2265,13 @@
 	return IRQ_HANDLED;
 }
 
-static int rspq_check_napi(struct net_device *dev, struct sge_rspq *q)
+static int rspq_check_napi(struct sge_qset *qs)
 {
-	if (!napi_is_scheduled(dev) && is_new_response(&q->desc[q->cidx], q)) {
-		if (likely(__netif_rx_schedule_prep(dev)))
-			__netif_rx_schedule(dev);
+	struct sge_rspq *q = &qs->rspq;
+
+	if (!napi_is_scheduled(&qs->napi) &&
+	    is_new_response(&q->desc[q->cidx], q)) {
+		napi_schedule(&qs->napi);
 		return 1;
 	}
 	return 0;
@@ -2289,7 +2284,7 @@
  * one SGE response queue per port in this mode and protect all response
  * queues with queue 0's lock.
  */
-irqreturn_t t3_intr_msi_napi(int irq, void *cookie)
+static irqreturn_t t3_intr_msi_napi(int irq, void *cookie)
 {
 	int new_packets;
 	struct adapter *adap = cookie;
@@ -2297,10 +2292,9 @@
 
 	spin_lock(&q->lock);
 
-	new_packets = rspq_check_napi(adap->sge.qs[0].netdev, q);
+	new_packets = rspq_check_napi(&adap->sge.qs[0]);
 	if (adap->params.nports == 2)
-		new_packets += rspq_check_napi(adap->sge.qs[1].netdev,
-					       &adap->sge.qs[1].rspq);
+		new_packets += rspq_check_napi(&adap->sge.qs[1]);
 	if (!new_packets && t3_slow_intr_handler(adap) == 0)
 		q->unhandled_irqs++;
 
@@ -2403,9 +2397,9 @@
 static irqreturn_t t3b_intr_napi(int irq, void *cookie)
 {
 	u32 map;
-	struct net_device *dev;
 	struct adapter *adap = cookie;
-	struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+	struct sge_qset *qs0 = &adap->sge.qs[0];
+	struct sge_rspq *q0 = &qs0->rspq;
 
 	t3_write_reg(adap, A_PL_CLI, 0);
 	map = t3_read_reg(adap, A_SG_DATA_INTR);
@@ -2418,18 +2412,11 @@
 	if (unlikely(map & F_ERRINTR))
 		t3_slow_intr_handler(adap);
 
-	if (likely(map & 1)) {
-		dev = adap->sge.qs[0].netdev;
+	if (likely(map & 1))
+		napi_schedule(&qs0->napi);
 
-		if (likely(__netif_rx_schedule_prep(dev)))
-			__netif_rx_schedule(dev);
-	}
-	if (map & 2) {
-		dev = adap->sge.qs[1].netdev;
-
-		if (likely(__netif_rx_schedule_prep(dev)))
-			__netif_rx_schedule(dev);
-	}
+	if (map & 2)
+		napi_schedule(&adap->sge.qs[1].napi);
 
 	spin_unlock(&q0->lock);
 	return IRQ_HANDLED;
@@ -2476,6 +2463,10 @@
 			 "(0x%x)\n", (v >> S_RSPQ0DISABLED) & 0xff);
 	}
 
+	if (status & (F_HIPIODRBDROPERR | F_LOPIODRBDROPERR))
+		CH_ALERT(adapter, "SGE dropped %s priority doorbell\n",
+			 status & F_HIPIODRBDROPERR ? "high" : "lo");
+
 	t3_write_reg(adapter, A_SG_INT_CAUSE, status);
 	if (status & (F_RSPQCREDITOVERFOW | F_RSPQDISABLED))
 		t3_fatal_err(adapter);
@@ -2508,7 +2499,7 @@
 {
 	spinlock_t *lock;
 	struct sge_qset *qs = (struct sge_qset *)data;
-	struct adapter *adap = qs->netdev->priv;
+	struct adapter *adap = qs->adap;
 
 	if (spin_trylock(&qs->txq[TXQ_ETH].lock)) {
 		reclaim_completed_tx(adap, &qs->txq[TXQ_ETH]);
@@ -2519,9 +2510,9 @@
 		spin_unlock(&qs->txq[TXQ_OFLD].lock);
 	}
 	lock = (adap->flags & USING_MSIX) ? &qs->rspq.lock :
-	    &adap->sge.qs[0].rspq.lock;
+					    &adap->sge.qs[0].rspq.lock;
 	if (spin_trylock_irq(lock)) {
-		if (!napi_is_scheduled(qs->netdev)) {
+		if (!napi_is_scheduled(&qs->napi)) {
 			u32 status = t3_read_reg(adap, A_SG_RSPQ_FL_STATUS);
 
 			if (qs->fl[0].credits < qs->fl[0].size)
@@ -2555,12 +2546,9 @@
  */
 void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p)
 {
-	if (!qs->netdev)
-		return;
-
 	qs->rspq.holdoff_tmr = max(p->coalesce_usecs * 10, 1U);/* can't be 0 */
 	qs->rspq.polling = p->polling;
-	qs->netdev->poll = p->polling ? napi_rx_handler : ofld_poll;
+	qs->napi.poll = p->polling ? napi_rx_handler : ofld_poll;
 }
 
 /**
@@ -2580,7 +2568,7 @@
  */
 int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
 		      int irq_vec_idx, const struct qset_params *p,
-		      int ntxq, struct net_device *netdev)
+		      int ntxq, struct net_device *dev)
 {
 	int i, ret = -ENOMEM;
 	struct sge_qset *q = &adapter->sge.qs[id];
@@ -2701,16 +2689,10 @@
 	}
 
 	spin_unlock(&adapter->sge.reg_lock);
-	q->netdev = netdev;
-	t3_update_qset_coalesce(q, p);
 
-	/*
-	 * We use atalk_ptr as a backpointer to a qset.  In case a device is
-	 * associated with multiple queue sets only the first one sets
-	 * atalk_ptr.
-	 */
-	if (netdev->atalk_ptr == NULL)
-		netdev->atalk_ptr = q;
+	q->adap = adapter;
+	q->netdev = dev;
+	t3_update_qset_coalesce(q, p);
 
 	refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL);
 	refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL);
diff --git a/drivers/net/cxgb3/sge_defs.h b/drivers/net/cxgb3/sge_defs.h
index 514869e..29b6c80 100644
--- a/drivers/net/cxgb3/sge_defs.h
+++ b/drivers/net/cxgb3/sge_defs.h
@@ -106,6 +106,10 @@
 #define V_CQ_GEN(x) ((x) << S_CQ_GEN)
 #define F_CQ_GEN    V_CQ_GEN(1U)
 
+#define S_CQ_ERR    30
+#define V_CQ_ERR(x) ((x) << S_CQ_ERR)
+#define F_CQ_ERR    V_CQ_ERR(1U)
+
 #define S_CQ_OVERFLOW_MODE    31
 #define V_CQ_OVERFLOW_MODE(x) ((x) << S_CQ_OVERFLOW_MODE)
 #define F_CQ_OVERFLOW_MODE    V_CQ_OVERFLOW_MODE(1U)
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index dd3149d..d4ee00d 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -119,9 +119,9 @@
  *	Reads registers that are accessed indirectly through an address/data
  *	register pair.
  */
-void t3_read_indirect(struct adapter *adap, unsigned int addr_reg,
-		      unsigned int data_reg, u32 *vals, unsigned int nregs,
-		      unsigned int start_idx)
+static void t3_read_indirect(struct adapter *adap, unsigned int addr_reg,
+			     unsigned int data_reg, u32 *vals,
+			     unsigned int nregs, unsigned int start_idx)
 {
 	while (nregs--) {
 		t3_write_reg(adap, addr_reg, start_idx);
@@ -505,7 +505,7 @@
 	u8 vpdr_len[2];
 	VPD_ENTRY(pn, 16);	/* part number */
 	VPD_ENTRY(ec, 16);	/* EC level */
-	VPD_ENTRY(sn, 16);	/* serial number */
+	VPD_ENTRY(sn, SERNUM_LEN); /* serial number */
 	VPD_ENTRY(na, 12);	/* MAC address base */
 	VPD_ENTRY(cclk, 6);	/* core clock */
 	VPD_ENTRY(mclk, 6);	/* mem clock */
@@ -648,6 +648,7 @@
 	p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10);
 	p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10);
 	p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10);
+	memcpy(p->sn, vpd.sn_data, SERNUM_LEN);
 
 	/* Old eeproms didn't have port information */
 	if (adapter->params.rev == 0 && !vpd.port0_data[0]) {
@@ -848,16 +849,15 @@
 }
 
 /**
- *	t3_check_tpsram_version - read the tp sram version
+ *	t3_get_tp_version - read the tp sram version
  *	@adapter: the adapter
+ *	@vers: where to place the version
  *
- *	Reads the protocol sram version from serial eeprom.
+ *	Reads the protocol sram version from sram.
  */
-int t3_check_tpsram_version(struct adapter *adapter)
+int t3_get_tp_version(struct adapter *adapter, u32 *vers)
 {
 	int ret;
-	u32 vers;
-	unsigned int major, minor;
 
 	/* Get version loaded in SRAM */
 	t3_write_reg(adapter, A_TP_EMBED_OP_FIELD0, 0);
@@ -866,7 +866,32 @@
 	if (ret)
 		return ret;
 	
-	vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1);
+	*vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1);
+
+	return 0;
+}
+
+/**
+ *	t3_check_tpsram_version - read the tp sram version
+ *	@adapter: the adapter
+ *	@must_load: set to 1 if loading a new microcode image is required
+ *
+ *	Reads the protocol sram version from flash.
+ */
+int t3_check_tpsram_version(struct adapter *adapter, int *must_load)
+{
+	int ret;
+	u32 vers;
+	unsigned int major, minor;
+
+	if (adapter->params.rev == T3_REV_A)
+		return 0;
+
+	*must_load = 1;
+
+	ret = t3_get_tp_version(adapter, &vers);
+	if (ret)
+		return ret;
 
 	major = G_TP_VERSION_MAJOR(vers);
 	minor = G_TP_VERSION_MINOR(vers);
@@ -874,6 +899,16 @@
 	if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) 
 		return 0;
 
+	if (major != TP_VERSION_MAJOR)
+		CH_ERR(adapter, "found wrong TP version (%u.%u), "
+		       "driver needs version %d.%d\n", major, minor,
+		       TP_VERSION_MAJOR, TP_VERSION_MINOR);
+	else {
+		*must_load = 0;
+		CH_ERR(adapter, "found wrong TP version (%u.%u), "
+		       "driver compiled for version %d.%d\n", major, minor,
+		       TP_VERSION_MAJOR, TP_VERSION_MINOR);
+	}
 	return -EINVAL;
 }
 
@@ -925,16 +960,18 @@
 /**
  *	t3_check_fw_version - check if the FW is compatible with this driver
  *	@adapter: the adapter
- *
+ *	@must_load: set to 1 if loading a new FW image is required
+
  *	Checks if an adapter's FW is compatible with the driver.  Returns 0
  *	if the versions are compatible, a negative error otherwise.
  */
-int t3_check_fw_version(struct adapter *adapter)
+int t3_check_fw_version(struct adapter *adapter, int *must_load)
 {
 	int ret;
 	u32 vers;
 	unsigned int type, major, minor;
 
+	*must_load = 1;
 	ret = t3_get_fw_version(adapter, &vers);
 	if (ret)
 		return ret;
@@ -947,9 +984,17 @@
 	    minor == FW_VERSION_MINOR)
 		return 0;
 
-	CH_ERR(adapter, "found wrong FW version(%u.%u), "
-	       "driver needs version %u.%u\n", major, minor,
-	       FW_VERSION_MAJOR, FW_VERSION_MINOR);
+	if (major != FW_VERSION_MAJOR)
+		CH_ERR(adapter, "found wrong FW version(%u.%u), "
+		       "driver needs version %u.%u\n", major, minor,
+		       FW_VERSION_MAJOR, FW_VERSION_MINOR);
+	else {
+		*must_load = 0;
+		CH_WARN(adapter, "found wrong FW minor version(%u.%u), "
+		        "driver compiled for version %u.%u\n", major, minor,
+			FW_VERSION_MAJOR, FW_VERSION_MINOR);
+	}
+
 	return -EINVAL;
 }
 
@@ -1313,6 +1358,10 @@
 		{0}
 	};
 
+	if (t3_read_reg(adapter, A_PCIE_INT_CAUSE) & F_PEXERR)
+		CH_ALERT(adapter, "PEX error code 0x%x\n",
+			 t3_read_reg(adapter, A_PCIE_PEX_ERR));
+
 	if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK,
 				  pcie_intr_info, adapter->irq_stats))
 		t3_fatal_err(adapter);
@@ -1764,6 +1813,8 @@
 	for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i)
 		t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff);
 
+	if (is_pcie(adapter))
+		t3_write_reg(adapter, A_PCIE_PEX_ERR, 0xffffffff);
 	t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff);
 	t3_read_reg(adapter, A_PL_INT_CAUSE0);	/* flush */
 }
@@ -1819,6 +1870,8 @@
 	phy->ops->intr_clear(phy);
 }
 
+#define SG_CONTEXT_CMD_ATTEMPTS 100
+
 /**
  * 	t3_sge_write_context - write an SGE context
  * 	@adapter: the adapter
@@ -1838,7 +1891,7 @@
 	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
 		     V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
 	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
-			       0, 5, 1);
+			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
 }
 
 /**
@@ -1995,7 +2048,8 @@
 	base_addr >>= 32;
 	t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
 		     V_CQ_BASE_HI((u32) base_addr) | V_CQ_RSPQ(rspq) |
-		     V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode));
+		     V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode) |
+		     V_CQ_ERR(ovfl_mode));
 	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) |
 		     V_CQ_CREDIT_THRES(credit_thres));
 	return t3_sge_write_context(adapter, id, F_CQ);
@@ -2023,7 +2077,7 @@
 	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
 		     V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id));
 	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
-			       0, 5, 1);
+			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
 }
 
 /**
@@ -2047,7 +2101,7 @@
 	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
 		     V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id));
 	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
-			       0, 5, 1);
+			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
 }
 
 /**
@@ -2071,7 +2125,7 @@
 	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
 		     V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id));
 	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
-			       0, 5, 1);
+			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
 }
 
 /**
@@ -2095,7 +2149,7 @@
 	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
 		     V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id));
 	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
-			       0, 5, 1);
+			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
 }
 
 /**
@@ -2120,7 +2174,7 @@
 	t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) |
 		     V_CONTEXT(id) | F_CQ);
 	if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
-				0, 5, 1, &val))
+				0, SG_CONTEXT_CMD_ATTEMPTS, 1, &val))
 		return -EIO;
 
 	if (op >= 2 && op < 7) {
@@ -2130,7 +2184,8 @@
 		t3_write_reg(adapter, A_SG_CONTEXT_CMD,
 			     V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id));
 		if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD,
-				    F_CONTEXT_CMD_BUSY, 0, 5, 1))
+				    F_CONTEXT_CMD_BUSY, 0,
+				    SG_CONTEXT_CMD_ATTEMPTS, 1))
 			return -EIO;
 		return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0));
 	}
@@ -2156,7 +2211,7 @@
 	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
 		     V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id));
 	if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0,
-			    5, 1))
+			    SG_CONTEXT_CMD_ATTEMPTS, 1))
 		return -EIO;
 	data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0);
 	data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1);
@@ -3188,6 +3243,8 @@
 		t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN);
 
 	t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff);
+	t3_write_reg(adapter, A_PM1_RX_MODE, 0);
+	t3_write_reg(adapter, A_PM1_TX_MODE, 0);
 	init_hw_for_avail_ports(adapter, adapter->params.nports);
 	t3_sge_init(adapter, &adapter->params.sge);
 
@@ -3350,7 +3407,7 @@
  * Older PCIe cards lose their config space during reset, PCI-X
  * ones don't.
  */
-int t3_reset_adapter(struct adapter *adapter)
+static int t3_reset_adapter(struct adapter *adapter)
 {
 	int i, save_and_restore_pcie = 
 	    adapter->params.rev < T3_REV_B2 && is_pcie(adapter);
diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/cxgb3/t3cdev.h
index fa4099b..77fcc1a 100644
--- a/drivers/net/cxgb3/t3cdev.h
+++ b/drivers/net/cxgb3/t3cdev.h
@@ -42,9 +42,6 @@
 
 #define T3CNAMSIZ 16
 
-/* Get the t3cdev associated with a net_device */
-#define T3CDEV(netdev) (struct t3cdev *)(netdev->priv)
-
 struct cxgb3_client;
 
 enum t3ctype {
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index eb508bf..ef1c633 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -39,6 +39,6 @@
 
 /* Firmware version */
 #define FW_VERSION_MAJOR 4
-#define FW_VERSION_MINOR 3
+#define FW_VERSION_MINOR 6
 #define FW_VERSION_MICRO 0
 #endif				/* __CHELSIO_VERSION_H */
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
index c302b1a..eeb766a 100644
--- a/drivers/net/cxgb3/xgmac.c
+++ b/drivers/net/cxgb3/xgmac.c
@@ -142,7 +142,7 @@
 	return 0;
 }
 
-int t3b2_mac_reset(struct cmac *mac)
+static int t3b2_mac_reset(struct cmac *mac)
 {
 	struct adapter *adap = mac->adapter;
 	unsigned int oft = mac->offset;
@@ -437,12 +437,13 @@
 	struct mac_stats *s = &mac->stats;
 	
 	if (which & MAC_DIRECTION_TX) {
-		t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
 		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
 		t3_write_reg(adap, A_TP_PIO_DATA, 0xc0ede401);
 		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
 		t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
 
+		t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
+
 		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
 		mac->tx_mcnt = s->tx_frames;
 		mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
@@ -451,9 +452,11 @@
 						A_XGM_TX_SPI4_SOP_EOP_CNT +
 						oft)));
 		mac->rx_mcnt = s->rx_frames;
+		mac->rx_pause = s->rx_pause;
 		mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
 						A_XGM_RX_SPI4_SOP_EOP_CNT +
 						oft)));
+		mac->rx_ocnt = s->rx_fifo_ovfl;
 		mac->txen = F_TXEN;
 		mac->toggle_cnt = 0;
 	}
@@ -464,24 +467,19 @@
 
 int t3_mac_disable(struct cmac *mac, int which)
 {
-	int idx = macidx(mac);
 	struct adapter *adap = mac->adapter;
-	int val;
 
 	if (which & MAC_DIRECTION_TX) {
 		t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
-		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
-		t3_write_reg(adap, A_TP_PIO_DATA, 0xc000001f);
-		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
-		t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
 		mac->txen = 0;
 	}
 	if (which & MAC_DIRECTION_RX) {
+		int val = F_MAC_RESET_;
+
 		t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
 				 F_PCS_RESET_, 0);
 		msleep(100);
 		t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
-		val = F_MAC_RESET_;
 		if (is_10G(adap))
 			val |= F_PCS_RESET_;
 		else if (uses_xaui(adap))
@@ -507,7 +505,7 @@
 	tx_xcnt = 1;		/* By default tx_xcnt is making progress */
 	tx_tcnt = mac->tx_tcnt;	/* If tx_mcnt is progressing ignore tx_tcnt */
 	rx_xcnt = 1;		/* By default rx_xcnt is making progress */
-	if (tx_mcnt == mac->tx_mcnt) {
+	if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
 		tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
 						A_XGM_TX_SPI4_SOP_EOP_CNT +
 					       	mac->offset)));
@@ -524,10 +522,7 @@
 		goto rxcheck;
 	}
 
-	if (((tx_tcnt != mac->tx_tcnt) &&
-	     (tx_xcnt == 0) && (mac->tx_xcnt == 0)) ||
-	    ((mac->tx_mcnt == tx_mcnt) &&
-	     (tx_xcnt != 0) && (mac->tx_xcnt != 0))) {
+	if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0))  {
 		if (mac->toggle_cnt > 4) {
 			status = 2;
 			goto out;
@@ -541,11 +536,14 @@
 	}
 
 rxcheck:
-	if (rx_mcnt != mac->rx_mcnt)
+	if (rx_mcnt != mac->rx_mcnt) {
 		rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
 						A_XGM_RX_SPI4_SOP_EOP_CNT +
-						mac->offset)));
-	else
+						mac->offset))) +
+						(s->rx_fifo_ovfl -
+						 mac->rx_ocnt);
+		mac->rx_ocnt = s->rx_fifo_ovfl;
+	} else
 		goto out;
 
 	if (mac->rx_mcnt != s->rx_frames && rx_xcnt == 0 &&
@@ -560,6 +558,7 @@
 	mac->tx_mcnt = s->tx_frames;
 	mac->rx_xcnt = rx_xcnt;
 	mac->rx_mcnt = s->rx_frames;
+	mac->rx_pause = s->rx_pause;
 	if (status == 1) {
 		t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
 		t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
diff --git a/drivers/net/de600.c b/drivers/net/de600.c
index dae97b8..cb849b09 100644
--- a/drivers/net/de600.c
+++ b/drivers/net/de600.c
@@ -154,11 +154,6 @@
 	return 0;
 }
 
-static struct net_device_stats *get_stats(struct net_device *dev)
-{
-	return (struct net_device_stats *)(dev->priv);
-}
-
 static inline void trigger_interrupt(struct net_device *dev)
 {
 	de600_put_command(FLIP_IRQ);
@@ -308,7 +303,7 @@
 	if (!(irq_status & TX_FAILED16)) {
 		tx_fifo_out = (tx_fifo_out + 1) % TX_PAGES;
 		++free_tx_pages;
-		((struct net_device_stats *)(dev->priv))->tx_packets++;
+		dev->stats.tx_packets++;
 		netif_wake_queue(dev);
 	}
 
@@ -375,8 +370,8 @@
 
 	/* update stats */
 	dev->last_rx = jiffies;
-	((struct net_device_stats *)(dev->priv))->rx_packets++; /* count all receives */
-	((struct net_device_stats *)(dev->priv))->rx_bytes += size; /* count all received bytes */
+	dev->stats.rx_packets++; /* count all receives */
+	dev->stats.rx_bytes += size; /* count all received bytes */
 
 	/*
 	 * If any worth-while packets have been received, netif_rx()
@@ -389,12 +384,12 @@
 	int	i;
 	struct net_device *dev;
 	int err;
+	DECLARE_MAC_BUF(mac);
 
-	dev = alloc_etherdev(sizeof(struct net_device_stats));
+	dev = alloc_etherdev(0);
 	if (!dev)
 		return ERR_PTR(-ENOMEM);
 
-	SET_MODULE_OWNER(dev);
 
 	if (!request_region(DE600_IO, 3, "de600")) {
 		printk(KERN_WARNING "DE600: port 0x%x busy\n", DE600_IO);
@@ -444,12 +439,7 @@
 		goto out1;
 	}
 
-	printk(", Ethernet Address: %02X", dev->dev_addr[0]);
-	for (i = 1; i < ETH_ALEN; i++)
-		printk(":%02X",dev->dev_addr[i]);
-	printk("\n");
-
-	dev->get_stats = get_stats;
+	printk(", Ethernet Address: %s\n", print_mac(mac, dev->dev_addr));
 
 	dev->open = de600_open;
 	dev->stop = de600_close;
diff --git a/drivers/net/de600.h b/drivers/net/de600.h
index 1288e48..e80ecba 100644
--- a/drivers/net/de600.h
+++ b/drivers/net/de600.h
@@ -121,7 +121,6 @@
 /* Put in the device structure. */
 static int	de600_open(struct net_device *dev);
 static int	de600_close(struct net_device *dev);
-static struct net_device_stats *get_stats(struct net_device *dev);
 static int	de600_start_xmit(struct sk_buff *skb, struct net_device *dev);
 
 /* Dispatch from interrupts. */
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index dc48924..3f5190c 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -216,7 +216,6 @@
 /* Put in the device structure. */
 static int	de620_open(struct net_device *);
 static int	de620_close(struct net_device *);
-static struct	net_device_stats *get_stats(struct net_device *);
 static void	de620_set_multicast_list(struct net_device *);
 static int	de620_start_xmit(struct sk_buff *, struct net_device *);
 
@@ -480,16 +479,6 @@
 
 /*********************************************
  *
- * Return current statistics
- *
- */
-static struct net_device_stats *get_stats(struct net_device *dev)
-{
-	return (struct net_device_stats *)(dev->priv);
-}
-
-/*********************************************
- *
  * Set or clear the multicast filter for this adaptor.
  * (no real multicast implemented for the DE-620, but she can be promiscuous...)
  *
@@ -579,7 +568,7 @@
 	if(!(using_txbuf == (TXBF0 | TXBF1)))
 		netif_wake_queue(dev);
 
-	((struct net_device_stats *)(dev->priv))->tx_packets++;
+	dev->stats.tx_packets++;
 	spin_unlock_irqrestore(&de620_lock, flags);
 	dev_kfree_skb (skb);
 	return 0;
@@ -660,7 +649,7 @@
 		/* You win some, you lose some. And sometimes plenty... */
 		adapter_init(dev);
 		netif_wake_queue(dev);
-		((struct net_device_stats *)(dev->priv))->rx_over_errors++;
+		dev->stats.rx_over_errors++;
 		return 0;
 	}
 
@@ -680,7 +669,7 @@
 		next_rx_page = header_buf.Rx_NextPage; /* at least a try... */
 		de620_send_command(dev, W_DUMMY);
 		de620_set_register(dev, W_NPRF, next_rx_page);
-		((struct net_device_stats *)(dev->priv))->rx_over_errors++;
+		dev->stats.rx_over_errors++;
 		return 0;
 	}
 	next_rx_page = pagelink;
@@ -693,7 +682,7 @@
 		skb = dev_alloc_skb(size+2);
 		if (skb == NULL) { /* Yeah, but no place to put it... */
 			printk(KERN_WARNING "%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size);
-			((struct net_device_stats *)(dev->priv))->rx_dropped++;
+			dev->stats.rx_dropped++;
 		}
 		else { /* Yep! Go get it! */
 			skb_reserve(skb,2);	/* Align */
@@ -706,8 +695,8 @@
 			netif_rx(skb); /* deliver it "upstairs" */
 			dev->last_rx = jiffies;
 			/* count all receives */
-			((struct net_device_stats *)(dev->priv))->rx_packets++;
-			((struct net_device_stats *)(dev->priv))->rx_bytes += size;
+			dev->stats.rx_packets++;
+			dev->stats.rx_bytes += size;
 		}
 	}
 
@@ -818,13 +807,12 @@
 	struct net_device *dev;
 	int err = -ENOMEM;
 	int i;
+	DECLARE_MAC_BUF(mac);
 
-	dev = alloc_etherdev(sizeof(struct net_device_stats));
+	dev = alloc_etherdev(0);
 	if (!dev)
 		goto out;
 
-	SET_MODULE_OWNER(dev);
-
 	spin_lock_init(&de620_lock);
 
 	/*
@@ -866,13 +854,14 @@
 	}
 
 	/* else, got it! */
-	printk(", Ethernet Address: %2.2X",
-		dev->dev_addr[0] = nic_data.NodeID[0]);
+	dev->dev_addr[0] = nic_data.NodeID[0];
 	for (i = 1; i < ETH_ALEN; i++) {
-		printk(":%2.2X", dev->dev_addr[i] = nic_data.NodeID[i]);
+		dev->dev_addr[i] = nic_data.NodeID[i];
 		dev->broadcast[i] = 0xff;
 	}
 
+	printk(", Ethernet Address: %s", print_mac(mac, dev->dev_addr));
+
 	printk(" (%dk RAM,",
 		(nic_data.RAM_Size) ? (nic_data.RAM_Size >> 2) : 64);
 
@@ -881,7 +870,6 @@
 	else
 		printk(" UTP)\n");
 
-	dev->get_stats 		= get_stats;
 	dev->open 		= de620_open;
 	dev->stop 		= de620_close;
 	dev->hard_start_xmit 	= de620_start_xmit;
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index b2577f4..00e0194 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -258,8 +258,6 @@
 	int rx_new, tx_new;
 	int rx_old, tx_old;
 
-	struct net_device_stats stats;
-
 	unsigned short busmaster_regval;
 
 	struct timer_list       multicast_timer;
@@ -583,22 +581,22 @@
 
 		/* We got an incomplete frame? */
 		if ((bits & LE_R1_POK) != LE_R1_POK) {
-			lp->stats.rx_over_errors++;
-			lp->stats.rx_errors++;
+			dev->stats.rx_over_errors++;
+			dev->stats.rx_errors++;
 		} else if (bits & LE_R1_ERR) {
 			/* Count only the end frame as a rx error,
 			 * not the beginning
 			 */
 			if (bits & LE_R1_BUF)
-				lp->stats.rx_fifo_errors++;
+				dev->stats.rx_fifo_errors++;
 			if (bits & LE_R1_CRC)
-				lp->stats.rx_crc_errors++;
+				dev->stats.rx_crc_errors++;
 			if (bits & LE_R1_OFL)
-				lp->stats.rx_over_errors++;
+				dev->stats.rx_over_errors++;
 			if (bits & LE_R1_FRA)
-				lp->stats.rx_frame_errors++;
+				dev->stats.rx_frame_errors++;
 			if (bits & LE_R1_EOP)
-				lp->stats.rx_errors++;
+				dev->stats.rx_errors++;
 		} else {
 			len = (*rds_ptr(rd, mblength, lp->type) & 0xfff) - 4;
 			skb = dev_alloc_skb(len + 2);
@@ -606,7 +604,7 @@
 			if (skb == 0) {
 				printk("%s: Memory squeeze, deferring packet.\n",
 				       dev->name);
-				lp->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 				*rds_ptr(rd, mblength, lp->type) = 0;
 				*rds_ptr(rd, rmd1, lp->type) =
 					((lp->rx_buf_ptr_lnc[entry] >> 16) &
@@ -614,7 +612,7 @@
 				lp->rx_new = (entry + 1) & RX_RING_MOD_MASK;
 				return 0;
 			}
-			lp->stats.rx_bytes += len;
+			dev->stats.rx_bytes += len;
 
 			skb_reserve(skb, 2);	/* 16 byte align */
 			skb_put(skb, len);	/* make room */
@@ -625,7 +623,7 @@
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
 			dev->last_rx = jiffies;
-			lp->stats.rx_packets++;
+			dev->stats.rx_packets++;
 		}
 
 		/* Return the packet to the pool */
@@ -660,14 +658,14 @@
 		if (*tds_ptr(td, tmd1, lp->type) & LE_T1_ERR) {
 			status = *tds_ptr(td, misc, lp->type);
 
-			lp->stats.tx_errors++;
+			dev->stats.tx_errors++;
 			if (status & LE_T3_RTY)
-				lp->stats.tx_aborted_errors++;
+				dev->stats.tx_aborted_errors++;
 			if (status & LE_T3_LCOL)
-				lp->stats.tx_window_errors++;
+				dev->stats.tx_window_errors++;
 
 			if (status & LE_T3_CLOS) {
-				lp->stats.tx_carrier_errors++;
+				dev->stats.tx_carrier_errors++;
 				printk("%s: Carrier Lost\n", dev->name);
 				/* Stop the lance */
 				writereg(&ll->rap, LE_CSR0);
@@ -681,7 +679,7 @@
 			 * transmitter, restart the adapter.
 			 */
 			if (status & (LE_T3_BUF | LE_T3_UFL)) {
-				lp->stats.tx_fifo_errors++;
+				dev->stats.tx_fifo_errors++;
 
 				printk("%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
 				       dev->name);
@@ -702,13 +700,13 @@
 
 			/* One collision before packet was sent. */
 			if (*tds_ptr(td, tmd1, lp->type) & LE_T1_EONE)
-				lp->stats.collisions++;
+				dev->stats.collisions++;
 
 			/* More than one collision, be optimistic. */
 			if (*tds_ptr(td, tmd1, lp->type) & LE_T1_EMORE)
-				lp->stats.collisions += 2;
+				dev->stats.collisions += 2;
 
-			lp->stats.tx_packets++;
+			dev->stats.tx_packets++;
 		}
 		j = (j + 1) & TX_RING_MOD_MASK;
 	}
@@ -754,10 +752,10 @@
 		lance_tx(dev);
 
 	if (csr0 & LE_C0_BABL)
-		lp->stats.tx_errors++;
+		dev->stats.tx_errors++;
 
 	if (csr0 & LE_C0_MISS)
-		lp->stats.rx_errors++;
+		dev->stats.rx_errors++;
 
 	if (csr0 & LE_C0_MERR) {
 		printk("%s: Memory error, status %04x\n", dev->name, csr0);
@@ -912,7 +910,7 @@
 		len = ETH_ZLEN;
 	}
 
-	lp->stats.tx_bytes += len;
+	dev->stats.tx_bytes += len;
 
 	entry = lp->tx_new;
 	*lib_ptr(ib, btx_ring[entry].length, lp->type) = (-len);
@@ -938,13 +936,6 @@
  	return 0;
 }
 
-static struct net_device_stats *lance_get_stats(struct net_device *dev)
-{
-	struct lance_private *lp = netdev_priv(dev);
-
-	return &lp->stats;
-}
-
 static void lance_load_multicast(struct net_device *dev)
 {
 	struct lance_private *lp = netdev_priv(dev);
@@ -1036,6 +1027,7 @@
 	int i, ret;
 	unsigned long esar_base;
 	unsigned char *esar;
+	DECLARE_MAC_BUF(mac);
 
 	if (dec_lance_debug && version_printed++ == 0)
 		printk(version);
@@ -1223,28 +1215,26 @@
 	 */
 	switch (type) {
 	case ASIC_LANCE:
-		printk("%s: IOASIC onboard LANCE, addr = ", name);
+		printk("%s: IOASIC onboard LANCE", name);
 		break;
 	case PMAD_LANCE:
-		printk("%s: PMAD-AA, addr = ", name);
+		printk("%s: PMAD-AA", name);
 		break;
 	case PMAX_LANCE:
-		printk("%s: PMAX onboard LANCE, addr = ", name);
+		printk("%s: PMAX onboard LANCE", name);
 		break;
 	}
-	for (i = 0; i < 6; i++) {
+	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = esar[i * 4];
-		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ',' : ':');
-	}
 
-	printk(" irq = %d\n", dev->irq);
+	printk(", addr = %s, irq = %d\n",
+	       print_mac(mac, dev->dev_addr), dev->irq);
 
 	dev->open = &lance_open;
 	dev->stop = &lance_close;
 	dev->hard_start_xmit = &lance_start_xmit;
 	dev->tx_timeout = &lance_tx_timeout;
 	dev->watchdog_timeo = 5*HZ;
-	dev->get_stats = &lance_get_stats;
 	dev->set_multicast_list = &lance_set_multicast;
 
 	/* lp->ll is the location of the registers for lance card */
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 7df23dc..b07613e 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -200,6 +200,7 @@
 
 /* Include files */
 #include <linux/bitops.h>
+#include <linux/compiler.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/eisa.h>
@@ -240,8 +241,6 @@
  */
 #define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128)
 
-#define __unused __attribute__ ((unused))
-
 #ifdef CONFIG_PCI
 #define DFX_BUS_PCI(dev) (dev->bus == &pci_bus_type)
 #else
@@ -375,7 +374,7 @@
 
 static void dfx_port_write_long(DFX_board_t *bp, int offset, u32 data)
 {
-	struct device __unused *bdev = bp->bus_dev;
+	struct device __maybe_unused *bdev = bp->bus_dev;
 	int dfx_bus_tc = DFX_BUS_TC(bdev);
 	int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
 
@@ -399,7 +398,7 @@
 
 static void dfx_port_read_long(DFX_board_t *bp, int offset, u32 *data)
 {
-	struct device __unused *bdev = bp->bus_dev;
+	struct device __maybe_unused *bdev = bp->bus_dev;
 	int dfx_bus_tc = DFX_BUS_TC(bdev);
 	int dfx_use_mmio = DFX_MMIO || dfx_bus_tc;
 
@@ -540,7 +539,6 @@
 		goto err_out;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, bdev);
 
 	bp = netdev_priv(dev);
@@ -866,7 +864,7 @@
 
 static void __devinit dfx_bus_config_check(DFX_board_t *bp)
 {
-	struct device __unused *bdev = bp->bus_dev;
+	struct device __maybe_unused *bdev = bp->bus_dev;
 	int dfx_bus_eisa = DFX_BUS_EISA(bdev);
 	int	status;				/* return code from adapter port control call */
 	u32	host_data;			/* LW data returned from port control call */
@@ -3624,8 +3622,8 @@
 }
 
 
-static int __devinit __unused dfx_dev_register(struct device *);
-static int __devexit __unused dfx_dev_unregister(struct device *);
+static int __devinit __maybe_unused dfx_dev_register(struct device *);
+static int __devexit __maybe_unused dfx_dev_unregister(struct device *);
 
 #ifdef CONFIG_PCI
 static int __devinit dfx_pci_register(struct pci_dev *,
@@ -3699,7 +3697,7 @@
 };
 #endif /* CONFIG_TC */
 
-static int __devinit __unused dfx_dev_register(struct device *dev)
+static int __devinit __maybe_unused dfx_dev_register(struct device *dev)
 {
 	int status;
 
@@ -3709,7 +3707,7 @@
 	return status;
 }
 
-static int __devexit __unused dfx_dev_unregister(struct device *dev)
+static int __devexit __maybe_unused dfx_dev_unregister(struct device *dev)
 {
 	put_device(dev);
 	dfx_unregister(dev);
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index 1834970..ace39ec 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -485,7 +485,6 @@
 /* Kernel-only (not device) fields */
 	int rx_new, tx_new;	/* The next free ring entry               */
 	int rx_old, tx_old;	/* The ring entries to be free()ed.       */
-	struct net_device_stats stats;
 	spinlock_t lock;
 	struct {		/* Private stats counters                 */
 		u32 bins[DEPCA_PKT_STAT_SZ];
@@ -522,7 +521,6 @@
 static int depca_close(struct net_device *dev);
 static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void depca_tx_timeout(struct net_device *dev);
-static struct net_device_stats *depca_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
 
 /*
@@ -575,6 +573,7 @@
 	s16 nicsr;
 	u_long ioaddr;
 	u_long mem_start;
+	DECLARE_MAC_BUF(mac);
 
 	/*
 	 * We are now supposed to enter this function with the
@@ -634,14 +633,11 @@
 
 	printk(", h/w address ");
 	status = get_hw_addr(dev);
+	printk("%s", print_mac(mac, dev->dev_addr));
 	if (status != 0) {
 		printk("      which has an Ethernet PROM CRC error.\n");
 		return -ENXIO;
 	}
-	for (i = 0; i < ETH_ALEN - 1; i++) {	/* get the ethernet address */
-		printk("%2.2x:", dev->dev_addr[i]);
-	}
-	printk("%2.2x", dev->dev_addr[i]);
 
 	/* Set up the maximum amount of network RAM(kB) */
 	netRAM = ((lp->adapter != DEPCA) ? 64 : 48);
@@ -801,7 +797,6 @@
 	dev->open = &depca_open;
 	dev->hard_start_xmit = &depca_start_xmit;
 	dev->stop = &depca_close;
-	dev->get_stats = &depca_get_stats;
 	dev->set_multicast_list = &set_multicast_list;
 	dev->do_ioctl = &depca_ioctl;
 	dev->tx_timeout = depca_tx_timeout;
@@ -1026,15 +1021,15 @@
 		}
 		if (status & R_ENP) {	/* Valid frame status */
 			if (status & R_ERR) {	/* There was an error. */
-				lp->stats.rx_errors++;	/* Update the error stats. */
+				dev->stats.rx_errors++;	/* Update the error stats. */
 				if (status & R_FRAM)
-					lp->stats.rx_frame_errors++;
+					dev->stats.rx_frame_errors++;
 				if (status & R_OFLO)
-					lp->stats.rx_over_errors++;
+					dev->stats.rx_over_errors++;
 				if (status & R_CRC)
-					lp->stats.rx_crc_errors++;
+					dev->stats.rx_crc_errors++;
 				if (status & R_BUFF)
-					lp->stats.rx_fifo_errors++;
+					dev->stats.rx_fifo_errors++;
 			} else {
 				short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4;
 				struct sk_buff *skb;
@@ -1063,8 +1058,8 @@
 					   ** Update stats
 					 */
 					dev->last_rx = jiffies;
-					lp->stats.rx_packets++;
-					lp->stats.rx_bytes += pkt_len;
+					dev->stats.rx_packets++;
+					dev->stats.rx_bytes += pkt_len;
 					for (i = 1; i < DEPCA_PKT_STAT_SZ - 1; i++) {
 						if (pkt_len < (i * DEPCA_PKT_BIN_SZ)) {
 							lp->pktStats.bins[i]++;
@@ -1087,7 +1082,7 @@
 					}
 				} else {
 					printk("%s: Memory squeeze, deferring packet.\n", dev->name);
-					lp->stats.rx_dropped++;	/* Really, deferred. */
+					dev->stats.rx_dropped++;	/* Really, deferred. */
 					break;
 				}
 			}
@@ -1125,24 +1120,24 @@
 			break;
 		} else if (status & T_ERR) {	/* An error occurred. */
 			status = readl(&lp->tx_ring[entry].misc);
-			lp->stats.tx_errors++;
+			dev->stats.tx_errors++;
 			if (status & TMD3_RTRY)
-				lp->stats.tx_aborted_errors++;
+				dev->stats.tx_aborted_errors++;
 			if (status & TMD3_LCAR)
-				lp->stats.tx_carrier_errors++;
+				dev->stats.tx_carrier_errors++;
 			if (status & TMD3_LCOL)
-				lp->stats.tx_window_errors++;
+				dev->stats.tx_window_errors++;
 			if (status & TMD3_UFLO)
-				lp->stats.tx_fifo_errors++;
+				dev->stats.tx_fifo_errors++;
 			if (status & (TMD3_BUFF | TMD3_UFLO)) {
 				/* Trigger an immediate send demand. */
 				outw(CSR0, DEPCA_ADDR);
 				outw(INEA | TDMD, DEPCA_DATA);
 			}
 		} else if (status & (T_MORE | T_ONE)) {
-			lp->stats.collisions++;
+			dev->stats.collisions++;
 		} else {
-			lp->stats.tx_packets++;
+			dev->stats.tx_packets++;
 		}
 
 		/* Update all the pointers */
@@ -1234,15 +1229,6 @@
 	return status;
 }
 
-static struct net_device_stats *depca_get_stats(struct net_device *dev)
-{
-	struct depca_private *lp = (struct depca_private *) dev->priv;
-
-	/* Null body since there is no framing error counter */
-
-	return &lp->stats;
-}
-
 /*
 ** Set or clear the multicast filter for this adaptor.
 */
@@ -1855,6 +1841,7 @@
 	u_long ioaddr = dev->base_addr;
 	struct depca_init *p = &lp->init_block;
 	int i;
+	DECLARE_MAC_BUF(mac);
 
 	if (depca_debug > 1) {
 		/* Do not copy the shadow init block into shared memory */
@@ -1893,11 +1880,7 @@
 		printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base));
 		printk("Initialisation block at 0x%8.8lx(Phys)\n", lp->mem_start);
 		printk("        mode: 0x%4.4x\n", p->mode);
-		printk("        physical address: ");
-		for (i = 0; i < ETH_ALEN - 1; i++) {
-			printk("%2.2x:", p->phys_addr[i]);
-		}
-		printk("%2.2x\n", p->phys_addr[i]);
+		printk("        physical address: %s\n", print_mac(mac, p->phys_addr));
 		printk("        multicast hash table: ");
 		for (i = 0; i < (HASH_TABLE_LEN >> 3) - 1; i++) {
 			printk("%2.2x:", p->mcast_table[i]);
diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c
deleted file mode 100644
index df62c02..0000000
--- a/drivers/net/dgrs.c
+++ /dev/null
@@ -1,1615 +0,0 @@
-/*
- *	Digi RightSwitch SE-X loadable device driver for Linux
- *
- *	The RightSwitch is a 4 (EISA) or 6 (PCI) port etherswitch and
- *	a NIC on an internal board.
- *
- *	Author: Rick Richardson, rick@remotepoint.com
- *	Derived from the SVR4.2 (UnixWare) driver for the same card.
- *
- *	Copyright 1995-1996 Digi International Inc.
- *
- *	This software may be used and distributed according to the terms
- *	of the GNU General Public License, incorporated herein by reference.
- *
- *	For information on purchasing a RightSwitch SE-4 or SE-6
- *	board, please contact Digi's sales department at 1-612-912-3444
- *	or 1-800-DIGIBRD.  Outside the U.S., please check our Web page
- *	at http://www.dgii.com for sales offices worldwide.
- *
- *	OPERATION:
- *	When compiled as a loadable module, this driver can operate
- *	the board as either a 4/6 port switch with a 5th or 7th port
- *	that is a conventional NIC interface as far as the host is
- *	concerned, OR as 4/6 independent NICs.  To select multi-NIC
- *	mode, add "nicmode=1" on the insmod load line for the driver.
- *
- *	This driver uses the "dev" common ethernet device structure
- *	and a private "priv" (dev->priv) structure that contains
- *	mostly DGRS-specific information and statistics.  To keep
- *	the code for both the switch mode and the multi-NIC mode
- *	as similar as possible, I have introduced the concept of
- *	"dev0"/"priv0" and "devN"/"privN"  pointer pairs in subroutines
- *	where needed.  The first pair of pointers points to the
- *	"dev" and "priv" structures of the zeroth (0th) device
- *	interface associated with a board.  The second pair of
- *	pointers points to the current (Nth) device interface
- *	for the board: the one for which we are processing data.
- *
- *	In switch mode, the pairs of pointers are always the same,
- *	that is, dev0 == devN and priv0 == privN.  This is just
- *	like previous releases of this driver which did not support
- *	NIC mode.
- *
- *	In multi-NIC mode, the pairs of pointers may be different.
- *	We use the devN and privN pointers to reference just the
- *	name, port number, and statistics for the current interface.
- *	We use the dev0 and priv0 pointers to access the variables
- *	that control access to the board, such as board address
- *	and simulated 82596 variables.  This is because there is
- *	only one "fake" 82596 that serves as the interface to
- *	the board.  We do not want to try to keep the variables
- *	associated with this 82596 in sync across all devices.
- *
- *	This scheme works well.  As you will see, except for
- *	initialization, there is very little difference between
- *	the two modes as far as this driver is concerned.  On the
- *	receive side in NIC mode, the interrupt *always* comes in on
- *	the 0th interface (dev0/priv0).  We then figure out which
- *	real 82596 port it came in on from looking at the "chan"
- *	member that the board firmware adds at the end of each
- *	RBD (a.k.a. TBD). We get the channel number like this:
- *		int chan = ((I596_RBD *) S2H(cbp->xmit.tbdp))->chan;
- *
- *	On the transmit side in multi-NIC mode, we specify the
- *	output 82596 port by setting the new "dstchan" structure
- *	member that is at the end of the RFD, like this:
- *		priv0->rfdp->dstchan = privN->chan;
- *
- *	TODO:
- *	- Multi-NIC mode is not yet supported when the driver is linked
- *	  into the kernel.
- *	- Better handling of multicast addresses.
- *
- *	Fixes:
- *	Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 11/01/2001
- *	- fix dgrs_found_device wrt checking kmalloc return and
- *	rollbacking the partial steps of the whole process when
- *	one of the devices can't be allocated. Fix SET_MODULE_OWNER
- *	on the loop to use devN instead of repeated calls to dev.
- *
- *	davej <davej@suse.de> - 9/2/2001
- *	- Enable PCI device before reading ioaddr/irq
- *
- */
-
-#include <linux/module.h>
-#include <linux/eisa.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/io.h>
-#include <asm/byteorder.h>
-#include <asm/uaccess.h>
-
-static char version[] __initdata =
-	"$Id: dgrs.c,v 1.13 2000/06/06 04:07:00 rick Exp $";
-
-/*
- *	DGRS include files
- */
-typedef unsigned char uchar;
-#define vol volatile
-
-#include "dgrs.h"
-#include "dgrs_es4h.h"
-#include "dgrs_plx9060.h"
-#include "dgrs_i82596.h"
-#include "dgrs_ether.h"
-#include "dgrs_asstruct.h"
-#include "dgrs_bcomm.h"
-
-#ifdef CONFIG_PCI
-static struct pci_device_id dgrs_pci_tbl[] = {
-	{ SE6_PCI_VENDOR_ID, SE6_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, },
-	{ }			/* Terminating entry */
-};
-MODULE_DEVICE_TABLE(pci, dgrs_pci_tbl);
-#endif
-
-#ifdef CONFIG_EISA
-static struct eisa_device_id dgrs_eisa_tbl[] = {
-	{ "DBI0A01" },
-	{ }
-};
-MODULE_DEVICE_TABLE(eisa, dgrs_eisa_tbl);
-#endif
-
-MODULE_LICENSE("GPL");
-
-
-/*
- *	Firmware.  Compiled separately for local compilation,
- *	but #included for Linux distribution.
- */
-#ifndef NOFW
-	#include "dgrs_firmware.c"
-#else
-	extern int	dgrs_firmnum;
-	extern char	dgrs_firmver[];
-	extern char	dgrs_firmdate[];
-	extern uchar	dgrs_code[];
-	extern int	dgrs_ncode;
-#endif
-
-/*
- *	Linux out*() is backwards from all other operating systems
- */
-#define	OUTB(ADDR, VAL)	outb(VAL, ADDR)
-#define	OUTW(ADDR, VAL)	outw(VAL, ADDR)
-#define	OUTL(ADDR, VAL)	outl(VAL, ADDR)
-
-/*
- *	Macros to convert switch to host and host to switch addresses
- *	(assumes a local variable priv points to board dependent struct)
- */
-#define	S2H(A)	( ((unsigned long)(A)&0x00ffffff) + priv0->vmem )
-#define	S2HN(A)	( ((unsigned long)(A)&0x00ffffff) + privN->vmem )
-#define	H2S(A)	( ((char *) (A) - priv0->vmem) + 0xA3000000 )
-
-/*
- *	Convert a switch address to a "safe" address for use with the
- *	PLX 9060 DMA registers and the associated HW kludge that allows
- *	for host access of the DMA registers.
- */
-#define	S2DMA(A)	( (unsigned long)(A) & 0x00ffffff)
-
-/*
- *	"Space.c" variables, now settable from module interface
- *	Use the name below, minus the "dgrs_" prefix.  See init_module().
- */
-static int	dgrs_debug = 1;
-static int	dgrs_dma = 1;
-static int	dgrs_spantree = -1;
-static int	dgrs_hashexpire = -1;
-static uchar	dgrs_ipaddr[4] = { 0xff, 0xff, 0xff, 0xff};
-static uchar	dgrs_iptrap[4] = { 0xff, 0xff, 0xff, 0xff};
-static __u32	dgrs_ipxnet = -1;
-static int	dgrs_nicmode;
-
-/*
- *	Private per-board data structure (dev->priv)
- */
-typedef struct
-{
-	/*
-	 *	Stuff for generic ethercard I/F
-	 */
-	struct net_device_stats	stats;
-
-	/*
-	 *	DGRS specific data
-	 */
-	char		*vmem;
-
-        struct bios_comm *bcomm;        /* Firmware BIOS comm structure */
-        PORT            *port;          /* Ptr to PORT[0] struct in VM */
-        I596_SCB        *scbp;          /* Ptr to SCB struct in VM */
-        I596_RFD        *rfdp;          /* Current RFD list */
-        I596_RBD        *rbdp;          /* Current RBD list */
-
-        volatile int    intrcnt;        /* Count of interrupts */
-
-        /*
-         *      SE-4 (EISA) board variables
-         */
-        uchar		is_reg;		/* EISA: Value for ES4H_IS reg */
-
-        /*
-         *      SE-6 (PCI) board variables
-         *
-         *      The PLX "expansion rom" space is used for DMA register
-         *      access from the host on the SE-6.  These are the physical
-         *      and virtual addresses of that space.
-         */
-        ulong		plxreg;		/* Phys address of PLX chip */
-        char            *vplxreg;	/* Virtual address of PLX chip */
-        ulong		plxdma;		/* Phys addr of PLX "expansion rom" */
-        ulong volatile  *vplxdma;	/* Virtual addr of "expansion rom" */
-        int             use_dma;        /* Flag: use DMA */
-	DMACHAIN	*dmadesc_s;	/* area for DMA chains (SW addr.) */
-	DMACHAIN	*dmadesc_h;	/* area for DMA chains (Host Virtual) */
-
-	/*
-	 *	Multi-NIC mode variables
-	 *
-	 *	All entries of the devtbl[] array are valid for the 0th
-	 *	device (i.e. eth0, but not eth1...eth5).  devtbl[0] is
-	 *	valid for all devices (i.e. eth0, eth1, ..., eth5).
-	 */
-	int		nports;		/* Number of physical ports (4 or 6) */
-	int		chan;		/* Channel # (1-6) for this device */
-	struct net_device	*devtbl[6];	/* Ptrs to N device structs */
-
-} DGRS_PRIV;
-
-
-/*
- *	reset or un-reset the IDT processor
- */
-static void
-proc_reset(struct net_device *dev0, int reset)
-{
-	DGRS_PRIV	*priv0 = (DGRS_PRIV *) dev0->priv;
-
-	if (priv0->plxreg)
-	{
-		ulong		val;
-		val = inl(dev0->base_addr + PLX_MISC_CSR);
-		if (reset)
-			val |= SE6_RESET;
-		else
-			val &= ~SE6_RESET;
-		OUTL(dev0->base_addr + PLX_MISC_CSR, val);
-	}
-	else
-	{
-		OUTB(dev0->base_addr + ES4H_PC, reset ? ES4H_PC_RESET : 0);
-	}
-}
-
-/*
- *	See if the board supports bus master DMA
- */
-static int
-check_board_dma(struct net_device *dev0)
-{
-	DGRS_PRIV	*priv0 = (DGRS_PRIV *) dev0->priv;
-	ulong	x;
-
-	/*
-	 *	If Space.c says not to use DMA, or if it's not a PLX based
-	 *	PCI board, or if the expansion ROM space is not PCI
-	 *	configured, then return false.
-	 */
-	if (!dgrs_dma || !priv0->plxreg || !priv0->plxdma)
-		return (0);
-
-	/*
-	 *	Set the local address remap register of the "expansion rom"
-	 *	area to 0x80000000 so that we can use it to access the DMA
-	 *	registers from the host side.
-	 */
-	OUTL(dev0->base_addr + PLX_ROM_BASE_ADDR, 0x80000000);
-
-	/*
-	 * Set the PCI region descriptor to:
-	 *      Space 0:
-	 *              disable read-prefetch
-	 *              enable READY
-	 *              enable BURST
-	 *              0 internal wait states
-	 *      Expansion ROM: (used for host DMA register access)
-	 *              disable read-prefetch
-	 *              enable READY
-	 *              disable BURST
-	 *              0 internal wait states
-	 */
-	OUTL(dev0->base_addr + PLX_BUS_REGION, 0x49430343);
-
-	/*
-	 *	Now map the DMA registers into our virtual space
-	 */
-	priv0->vplxdma = (ulong *) ioremap (priv0->plxdma, 256);
-	if (!priv0->vplxdma)
-	{
-		printk("%s: can't *remap() the DMA regs\n", dev0->name);
-		return (0);
-	}
-
-	/*
-	 *	Now test to see if we can access the DMA registers
-	 *	If we write -1 and get back 1FFF, then we accessed the
-	 *	DMA register.  Otherwise, we probably have an old board
-	 *	and wrote into regular RAM.
-	 */
-	priv0->vplxdma[PLX_DMA0_MODE/4] = 0xFFFFFFFF;
-	x = priv0->vplxdma[PLX_DMA0_MODE/4];
-	if (x != 0x00001FFF) {
-		iounmap((void *)priv0->vplxdma);
-		return (0);
-	}
-
-	return (1);
-}
-
-/*
- *	Initiate DMA using PLX part on PCI board.  Spin the
- *	processor until completed.  All addresses are physical!
- *
- *	If pciaddr is NULL, then it's a chaining DMA, and lcladdr is
- *	the address of the first DMA descriptor in the chain.
- *
- *	If pciaddr is not NULL, then it's a single DMA.
- *
- *	In either case, "lcladdr" must have been fixed up to make
- *	sure the MSB isn't set using the S2DMA macro before passing
- *	the address to this routine.
- */
-static int
-do_plx_dma(
-	struct net_device *dev,
-	ulong pciaddr,
-	ulong lcladdr,
-	int len,
-	int to_host
-)
-{
-        int     	i;
-        ulong   	csr = 0;
-	DGRS_PRIV	*priv = (DGRS_PRIV *) dev->priv;
-
-	if (pciaddr)
-	{
-		/*
-		 *	Do a single, non-chain DMA
-		 */
-		priv->vplxdma[PLX_DMA0_PCI_ADDR/4] = pciaddr;
-		priv->vplxdma[PLX_DMA0_LCL_ADDR/4] = lcladdr;
-		priv->vplxdma[PLX_DMA0_SIZE/4] = len;
-		priv->vplxdma[PLX_DMA0_DESCRIPTOR/4] = to_host
-					? PLX_DMA_DESC_TO_HOST
-					: PLX_DMA_DESC_TO_BOARD;
-		priv->vplxdma[PLX_DMA0_MODE/4] =
-					  PLX_DMA_MODE_WIDTH32
-					| PLX_DMA_MODE_WAITSTATES(0)
-					| PLX_DMA_MODE_READY
-					| PLX_DMA_MODE_NOBTERM
-					| PLX_DMA_MODE_BURST
-					| PLX_DMA_MODE_NOCHAIN;
-	}
-	else
-	{
-		/*
-		 *	Do a chaining DMA
-		 */
-		priv->vplxdma[PLX_DMA0_MODE/4] =
-					  PLX_DMA_MODE_WIDTH32
-					| PLX_DMA_MODE_WAITSTATES(0)
-					| PLX_DMA_MODE_READY
-					| PLX_DMA_MODE_NOBTERM
-					| PLX_DMA_MODE_BURST
-					| PLX_DMA_MODE_CHAIN;
-		priv->vplxdma[PLX_DMA0_DESCRIPTOR/4] = lcladdr;
-	}
-
-	priv->vplxdma[PLX_DMA_CSR/4] =
-				PLX_DMA_CSR_0_ENABLE | PLX_DMA_CSR_0_START;
-
-        /*
-	 *	Wait for DMA to complete
-	 */
-        for (i = 0; i < 1000000; ++i)
-        {
-		/*
-		 *	Spin the host CPU for 1 usec, so we don't thrash
-		 *	the PCI bus while the PLX 9060 is doing DMA.
-		 */
-		udelay(1);
-
-		csr = (volatile unsigned long) priv->vplxdma[PLX_DMA_CSR/4];
-
-                if (csr & PLX_DMA_CSR_0_DONE)
-                        break;
-        }
-
-        if ( ! (csr & PLX_DMA_CSR_0_DONE) )
-        {
-		printk("%s: DMA done never occurred. DMA disabled.\n",
-			dev->name);
-		priv->use_dma = 0;
-                return 1;
-        }
-        return 0;
-}
-
-/*
- *	dgrs_rcv_frame()
- *
- *	Process a received frame.  This is called from the interrupt
- *	routine, and works for both switch mode and multi-NIC mode.
- *
- *	Note that when in multi-NIC mode, we want to always access the
- *	hardware using the dev and priv structures of the first port,
- *	so that we are using only one set of variables to maintain
- *	the board interface status, but we want to use the Nth port
- *	dev and priv structures to maintain statistics and to pass
- *	the packet up.
- *
- *	Only the first device structure is attached to the interrupt.
- *	We use the special "chan" variable at the end of the first RBD
- *	to select the Nth device in multi-NIC mode.
- *
- *	We currently do chained DMA on a per-packet basis when the
- *	packet is "long", and we spin the CPU a short time polling
- *	for DMA completion.  This avoids a second interrupt overhead,
- *	and gives the best performance for light traffic to the host.
- *
- *	However, a better scheme that could be implemented would be
- *	to see how many packets are outstanding for the host, and if
- *	the number is "large", create a long chain to DMA several
- *	packets into the host in one go.  In this case, we would set
- *	up some state variables to let the host CPU continue doing
- *	other things until a DMA completion interrupt comes along.
- */
-static void
-dgrs_rcv_frame(
-	struct net_device	*dev0,
-	DGRS_PRIV	*priv0,
-	I596_CB		*cbp
-)
-{
-	int		len;
-	I596_TBD	*tbdp;
-	struct sk_buff	*skb;
-	uchar		*putp;
-	uchar		*p;
-	struct net_device	*devN;
-	DGRS_PRIV	*privN;
-
-	/*
-	 *	Determine Nth priv and dev structure pointers
-	 */
-	if (dgrs_nicmode)
-	{	/* Multi-NIC mode */
-		int chan = ((I596_RBD *) S2H(cbp->xmit.tbdp))->chan;
-
-		devN = priv0->devtbl[chan-1];
-		/*
-		 * If devN is null, we got an interrupt before the I/F
-		 * has been initialized.  Pitch the packet.
-		 */
-		if (devN == NULL)
-			goto out;
-		privN = (DGRS_PRIV *) devN->priv;
-	}
-	else
-	{	/* Switch mode */
-		devN = dev0;
-		privN = priv0;
-	}
-
-	if (0) printk("%s: rcv len=%ld\n", devN->name, cbp->xmit.count);
-
-	/*
-	 *	Allocate a message block big enough to hold the whole frame
-	 */
-	len = cbp->xmit.count;
-	if ((skb = dev_alloc_skb(len+5)) == NULL)
-	{
-		printk("%s: dev_alloc_skb failed for rcv buffer\n", devN->name);
-		++privN->stats.rx_dropped;
-		/* discarding the frame */
-		goto out;
-	}
-	skb_reserve(skb, 2);	/* Align IP header */
-
-again:
-	putp = p = skb_put(skb, len);
-
-	/*
-	 *	There are three modes here for doing the packet copy.
-	 *	If we have DMA, and the packet is "long", we use the
-	 *	chaining mode of DMA.  If it's shorter, we use single
-	 *	DMA's.  Otherwise, we use memcpy().
-	 */
-	if (priv0->use_dma && priv0->dmadesc_h && len > 64)
-	{
-		/*
-		 *	If we can use DMA and it's a long frame, copy it using
-		 *	DMA chaining.
-		 */
-		DMACHAIN	*ddp_h;	/* Host virtual DMA desc. pointer */
-		DMACHAIN	*ddp_s;	/* Switch physical DMA desc. pointer */
-		uchar		*phys_p;
-
-		/*
-		 *	Get the physical address of the STREAMS buffer.
-		 *	NOTE: allocb() guarantees that the whole buffer
-		 *	is in a single page if the length < 4096.
-		 */
-		phys_p = (uchar *) virt_to_phys(putp);
-
-		ddp_h = priv0->dmadesc_h;
-		ddp_s = priv0->dmadesc_s;
-		tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp);
-		for (;;)
-		{
-			int	count;
-			int	amt;
-
-			count = tbdp->count;
-			amt = count & 0x3fff;
-			if (amt == 0)
-				break; /* For safety */
-			if ( (p-putp) >= len)
-			{
-				printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp));
-				proc_reset(dev0, 1);	/* Freeze IDT */
-				break; /* For Safety */
-			}
-
-			ddp_h->pciaddr = (ulong) phys_p;
-			ddp_h->lcladdr = S2DMA(tbdp->buf);
-			ddp_h->len = amt;
-
-			phys_p += amt;
-			p += amt;
-
-			if (count & I596_TBD_EOF)
-			{
-				ddp_h->next = PLX_DMA_DESC_TO_HOST
-						| PLX_DMA_DESC_EOC;
-				++ddp_h;
-				break;
-			}
-			else
-			{
-				++ddp_s;
-				ddp_h->next = PLX_DMA_DESC_TO_HOST
-						| (ulong) ddp_s;
-				tbdp = (I596_TBD *) S2H(tbdp->next);
-				++ddp_h;
-			}
-		}
-		if (ddp_h - priv0->dmadesc_h)
-		{
-			int	rc;
-
-			rc = do_plx_dma(dev0,
-				0, (ulong) priv0->dmadesc_s, len, 0);
-			if (rc)
-			{
-				printk("%s: Chained DMA failure\n", devN->name);
-				goto again;
-			}
-		}
-	}
-	else if (priv0->use_dma)
-	{
-		/*
-		 *	If we can use DMA and it's a shorter frame, copy it
-		 *	using single DMA transfers.
-		 */
-		uchar		*phys_p;
-
-		/*
-		 *	Get the physical address of the STREAMS buffer.
-		 *	NOTE: allocb() guarantees that the whole buffer
-		 *	is in a single page if the length < 4096.
-		 */
-		phys_p = (uchar *) virt_to_phys(putp);
-
-		tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp);
-		for (;;)
-		{
-			int	count;
-			int	amt;
-			int	rc;
-
-			count = tbdp->count;
-			amt = count & 0x3fff;
-			if (amt == 0)
-				break; /* For safety */
-			if ( (p-putp) >= len)
-			{
-				printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp));
-				proc_reset(dev0, 1);	/* Freeze IDT */
-				break; /* For Safety */
-			}
-			rc = do_plx_dma(dev0, (ulong) phys_p,
-						S2DMA(tbdp->buf), amt, 1);
-			if (rc)
-			{
-				memcpy(p, S2H(tbdp->buf), amt);
-				printk("%s: Single DMA failed\n", devN->name);
-			}
-			phys_p += amt;
-			p += amt;
-			if (count & I596_TBD_EOF)
-				break;
-			tbdp = (I596_TBD *) S2H(tbdp->next);
-		}
-	}
-	else
-	{
-		/*
-		 *	Otherwise, copy it piece by piece using memcpy()
-		 */
-		tbdp = (I596_TBD *) S2H(cbp->xmit.tbdp);
-		for (;;)
-		{
-			int	count;
-			int	amt;
-
-			count = tbdp->count;
-			amt = count & 0x3fff;
-			if (amt == 0)
-				break; /* For safety */
-			if ( (p-putp) >= len)
-			{
-				printk("%s: cbp = %lx\n", devN->name, (long) H2S(cbp));
-				proc_reset(dev0, 1);	/* Freeze IDT */
-				break; /* For Safety */
-			}
-			memcpy(p, S2H(tbdp->buf), amt);
-			p += amt;
-			if (count & I596_TBD_EOF)
-				break;
-			tbdp = (I596_TBD *) S2H(tbdp->next);
-		}
-	}
-
-	/*
-	 *	Pass the frame to upper half
-	 */
-	skb->protocol = eth_type_trans(skb, devN);
-	netif_rx(skb);
-	devN->last_rx = jiffies;
-	++privN->stats.rx_packets;
-	privN->stats.rx_bytes += len;
-
-out:
-	cbp->xmit.status = I596_CB_STATUS_C | I596_CB_STATUS_OK;
-}
-
-/*
- *	Start transmission of a frame
- *
- *	The interface to the board is simple: we pretend that we are
- *	a fifth 82596 ethernet controller 'receiving' data, and copy the
- *	data into the same structures that a real 82596 would.  This way,
- *	the board firmware handles the host 'port' the same as any other.
- *
- *	NOTE: we do not use Bus master DMA for this routine.  Turns out
- *	that it is not needed.  Slave writes over the PCI bus are about
- *	as fast as DMA, due to the fact that the PLX part can do burst
- *	writes.  The same is not true for data being read from the board.
- *
- *	For multi-NIC mode, we tell the firmware the desired 82596
- *	output port by setting the special "dstchan" member at the
- *	end of the traditional 82596 RFD structure.
- */
-
-static int dgrs_start_xmit(struct sk_buff *skb, struct net_device *devN)
-{
-	DGRS_PRIV	*privN = (DGRS_PRIV *) devN->priv;
-	struct net_device	*dev0;
-	DGRS_PRIV	*priv0;
-	I596_RBD	*rbdp;
-	int		count;
-	int		i, len, amt;
-
-	/*
-	 *	Determine 0th priv and dev structure pointers
-	 */
-	if (dgrs_nicmode)
-	{
-		dev0 = privN->devtbl[0];
-		priv0 = (DGRS_PRIV *) dev0->priv;
-	}
-	else
-	{
-		dev0 = devN;
-		priv0 = privN;
-	}
-
-	if (dgrs_debug > 1)
-		printk("%s: xmit len=%d\n", devN->name, (int) skb->len);
-
-	devN->trans_start = jiffies;
-	netif_start_queue(devN);
-
-	if (priv0->rfdp->cmd & I596_RFD_EL)
-	{	/* Out of RFD's */
-		if (0) printk("%s: NO RFD's\n", devN->name);
-		goto no_resources;
-	}
-
-	rbdp = priv0->rbdp;
-	count = 0;
-	priv0->rfdp->rbdp = (I596_RBD *) H2S(rbdp);
-
-	i = 0; len = skb->len;
-	for (;;)
-	{
-		if (rbdp->size & I596_RBD_EL)
-		{	/* Out of RBD's */
-			if (0) printk("%s: NO RBD's\n", devN->name);
-			goto no_resources;
-		}
-
-		amt = min_t(unsigned int, len, rbdp->size - count);
-		skb_copy_from_linear_data_offset(skb, i, S2H(rbdp->buf) + count, amt);
-		i += amt;
-		count += amt;
-		len -= amt;
-		if (len == 0)
-		{
-			if (skb->len < 60)
-				rbdp->count = 60 | I596_RBD_EOF;
-			else
-				rbdp->count = count | I596_RBD_EOF;
-			rbdp = (I596_RBD *) S2H(rbdp->next);
-			goto frame_done;
-		}
-		else if (count < 32)
-		{
-			/* More data to come, but we used less than 32
-			 * bytes of this RBD.  Keep filling this RBD.
-			 */
-			{}	/* Yes, we do nothing here */
-		}
-		else
-		{
-			rbdp->count = count;
-			rbdp = (I596_RBD *) S2H(rbdp->next);
-			count = 0;
-		}
-	}
-
-frame_done:
-	priv0->rbdp = rbdp;
-	if (dgrs_nicmode)
-		priv0->rfdp->dstchan = privN->chan;
-	priv0->rfdp->status = I596_RFD_C | I596_RFD_OK;
-	priv0->rfdp = (I596_RFD *) S2H(priv0->rfdp->next);
-
-	++privN->stats.tx_packets;
-
-	dev_kfree_skb (skb);
-	return (0);
-
-no_resources:
-	priv0->scbp->status |= I596_SCB_RNR;	/* simulate I82596 */
-	return (-EAGAIN);
-}
-
-/*
- *	Open the interface
- */
-static int
-dgrs_open( struct net_device *dev )
-{
-	netif_start_queue(dev);
-	return (0);
-}
-
-/*
- *	Close the interface
- */
-static int dgrs_close( struct net_device *dev )
-{
-	netif_stop_queue(dev);
-	return (0);
-}
-
-/*
- *	Get statistics
- */
-static struct net_device_stats *dgrs_get_stats( struct net_device *dev )
-{
-	DGRS_PRIV	*priv = (DGRS_PRIV *) dev->priv;
-
-	return (&priv->stats);
-}
-
-/*
- *	Set multicast list and/or promiscuous mode
- */
-
-static void dgrs_set_multicast_list( struct net_device *dev)
-{
-	DGRS_PRIV	*priv = (DGRS_PRIV *) dev->priv;
-
-	priv->port->is_promisc = (dev->flags & IFF_PROMISC) ? 1 : 0;
-}
-
-/*
- *	Unique ioctl's
- */
-static int dgrs_ioctl(struct net_device *devN, struct ifreq *ifr, int cmd)
-{
-	DGRS_PRIV	*privN = (DGRS_PRIV *) devN->priv;
-	DGRS_IOCTL	ioc;
-	int		i;
-
-	if (cmd != DGRSIOCTL)
-		return -EINVAL;
-
-	if(copy_from_user(&ioc, ifr->ifr_data, sizeof(DGRS_IOCTL)))
-		return -EFAULT;
-
-	switch (ioc.cmd)
-	{
-		case DGRS_GETMEM:
-			if (ioc.len != sizeof(ulong))
-				return -EINVAL;
-			if(copy_to_user(ioc.data, &devN->mem_start, ioc.len))
-				return -EFAULT;
-			return (0);
-		case DGRS_SETFILTER:
-			if (!capable(CAP_NET_ADMIN))
-				return -EPERM;
-			if (ioc.port > privN->bcomm->bc_nports)
-				return -EINVAL;
-			if (ioc.filter >= NFILTERS)
-				return -EINVAL;
-			if (ioc.len > privN->bcomm->bc_filter_area_len)
-				return -EINVAL;
-
-			/* Wait for old command to finish */
-			for (i = 0; i < 1000; ++i)
-			{
-				if ( (volatile long) privN->bcomm->bc_filter_cmd <= 0 )
-					break;
-				udelay(1);
-			}
-			if (i >= 1000)
-				return -EIO;
-
-			privN->bcomm->bc_filter_port = ioc.port;
-			privN->bcomm->bc_filter_num = ioc.filter;
-			privN->bcomm->bc_filter_len = ioc.len;
-
-			if (ioc.len)
-			{
-				if(copy_from_user(S2HN(privN->bcomm->bc_filter_area),
-					ioc.data, ioc.len))
-					return -EFAULT;
-				privN->bcomm->bc_filter_cmd = BC_FILTER_SET;
-			}
-			else
-				privN->bcomm->bc_filter_cmd = BC_FILTER_CLR;
-			return(0);
-		default:
-			return -EOPNOTSUPP;
-	}
-}
-
-/*
- *	Process interrupts
- *
- *	dev, priv will always refer to the 0th device in Multi-NIC mode.
- */
-
-static irqreturn_t dgrs_intr(int irq, void *dev_id)
-{
-	struct net_device	*dev0 = dev_id;
-	DGRS_PRIV	*priv0 = dev0->priv;
-	I596_CB		*cbp;
-	int		cmd;
-	int		i;
-
-	++priv0->intrcnt;
-	if (1) ++priv0->bcomm->bc_cnt[4];
-	if (0)
-	{
-		static int cnt = 100;
-		if (--cnt > 0)
-		printk("%s: interrupt: irq %d\n", dev0->name, irq);
-	}
-
-	/*
-	 *	Get 596 command
-	 */
-	cmd = priv0->scbp->cmd;
-
-	/*
-	 *	See if RU has been restarted
-	 */
-	if ( (cmd & I596_SCB_RUC) == I596_SCB_RUC_START)
-	{
-		if (0) printk("%s: RUC start\n", dev0->name);
-		priv0->rfdp = (I596_RFD *) S2H(priv0->scbp->rfdp);
-		priv0->rbdp = (I596_RBD *) S2H(priv0->rfdp->rbdp);
-		priv0->scbp->status &= ~(I596_SCB_RNR|I596_SCB_RUS);
-		/*
-		 * Tell upper half (halves)
-		 */
-		if (dgrs_nicmode)
-		{
-			for (i = 0; i < priv0->nports; ++i)
-				netif_wake_queue (priv0->devtbl[i]);
-		}
-		else
-			netif_wake_queue (dev0);
-		/* if (bd->flags & TX_QUEUED)
-			DL_sched(bd, bdd); */
-	}
-
-	/*
-	 *	See if any CU commands to process
-	 */
-	if ( (cmd & I596_SCB_CUC) != I596_SCB_CUC_START)
-	{
-		priv0->scbp->cmd = 0;	/* Ignore all other commands */
-		goto ack_intr;
-	}
-	priv0->scbp->status &= ~(I596_SCB_CNA|I596_SCB_CUS);
-
-	/*
-	 *	Process a command
-	 */
-	cbp = (I596_CB *) S2H(priv0->scbp->cbp);
-	priv0->scbp->cmd = 0;	/* Safe to clear the command */
-	for (;;)
-	{
-		switch (cbp->nop.cmd & I596_CB_CMD)
-		{
-		case I596_CB_CMD_XMIT:
-			dgrs_rcv_frame(dev0, priv0, cbp);
-			break;
-		default:
-			cbp->nop.status = I596_CB_STATUS_C | I596_CB_STATUS_OK;
-			break;
-		}
-		if (cbp->nop.cmd & I596_CB_CMD_EL)
-			break;
-		cbp = (I596_CB *) S2H(cbp->nop.next);
-	}
-	priv0->scbp->status |= I596_SCB_CNA;
-
-	/*
-	 * Ack the interrupt
-	 */
-ack_intr:
-	if (priv0->plxreg)
-		OUTL(dev0->base_addr + PLX_LCL2PCI_DOORBELL, 1);
-
-	return IRQ_HANDLED;
-}
-
-/*
- *	Download the board firmware
- */
-static int __init
-dgrs_download(struct net_device *dev0)
-{
-	DGRS_PRIV	*priv0 = (DGRS_PRIV *) dev0->priv;
-	int		is;
-	unsigned long	i;
-
-	static const int iv2is[16] = {
-				0, 0, 0, ES4H_IS_INT3,
-				0, ES4H_IS_INT5, 0, ES4H_IS_INT7,
-				0, 0, ES4H_IS_INT10, ES4H_IS_INT11,
-				ES4H_IS_INT12, 0, 0, ES4H_IS_INT15 };
-
-	/*
-	 * Map in the dual port memory
-	 */
-	priv0->vmem = ioremap(dev0->mem_start, 2048*1024);
-	if (!priv0->vmem)
-	{
-		printk("%s: cannot map in board memory\n", dev0->name);
-		return -ENXIO;
-	}
-
-	/*
-	 *	Hold the processor and configure the board addresses
-	 */
-	if (priv0->plxreg)
-	{	/* PCI bus */
-		proc_reset(dev0, 1);
-	}
-	else
-	{	/* EISA bus */
-		is = iv2is[dev0->irq & 0x0f];
-		if (!is)
-		{
-			printk("%s: Illegal IRQ %d\n", dev0->name, dev0->irq);
-			iounmap(priv0->vmem);
-			priv0->vmem = NULL;
-			return -ENXIO;
-		}
-		OUTB(dev0->base_addr + ES4H_AS_31_24,
-			(uchar) (dev0->mem_start >> 24) );
-		OUTB(dev0->base_addr + ES4H_AS_23_16,
-			(uchar) (dev0->mem_start >> 16) );
-		priv0->is_reg = ES4H_IS_LINEAR | is |
-			((uchar) (dev0->mem_start >> 8) & ES4H_IS_AS15);
-		OUTB(dev0->base_addr + ES4H_IS, priv0->is_reg);
-		OUTB(dev0->base_addr + ES4H_EC, ES4H_EC_ENABLE);
-		OUTB(dev0->base_addr + ES4H_PC, ES4H_PC_RESET);
-		OUTB(dev0->base_addr + ES4H_MW, ES4H_MW_ENABLE | 0x00);
-	}
-
-	/*
-	 *	See if we can do DMA on the SE-6
-	 */
-	priv0->use_dma = check_board_dma(dev0);
-	if (priv0->use_dma)
-		printk("%s: Bus Master DMA is enabled.\n", dev0->name);
-
-	/*
-	 * Load and verify the code at the desired address
-	 */
-	memcpy(priv0->vmem, dgrs_code, dgrs_ncode);	/* Load code */
-	if (memcmp(priv0->vmem, dgrs_code, dgrs_ncode))
-	{
-		iounmap(priv0->vmem);
-		priv0->vmem = NULL;
-		printk("%s: download compare failed\n", dev0->name);
-		return -ENXIO;
-	}
-
-	/*
-	 * Configurables
-	 */
-	priv0->bcomm = (struct bios_comm *) (priv0->vmem + 0x0100);
-	priv0->bcomm->bc_nowait = 1;	/* Tell board to make printf not wait */
-	priv0->bcomm->bc_squelch = 0;	/* Flag from Space.c */
-	priv0->bcomm->bc_150ohm = 0;	/* Flag from Space.c */
-
-	priv0->bcomm->bc_spew = 0;	/* Debug flag from Space.c */
-	priv0->bcomm->bc_maxrfd = 0;	/* Debug flag from Space.c */
-	priv0->bcomm->bc_maxrbd = 0;	/* Debug flag from Space.c */
-
-	/*
-	 * Tell board we are operating in switch mode (1) or in
-	 * multi-NIC mode (2).
-	 */
-	priv0->bcomm->bc_host = dgrs_nicmode ? BC_MULTINIC : BC_SWITCH;
-
-	/*
-	 * Request memory space on board for DMA chains
-	 */
-	if (priv0->use_dma)
-		priv0->bcomm->bc_hostarea_len = (2048/64) * 16;
-
-	/*
-	 * NVRAM configurables from Space.c
-	 */
-	priv0->bcomm->bc_spantree = dgrs_spantree;
-	priv0->bcomm->bc_hashexpire = dgrs_hashexpire;
-	memcpy(priv0->bcomm->bc_ipaddr, dgrs_ipaddr, 4);
-	memcpy(priv0->bcomm->bc_iptrap, dgrs_iptrap, 4);
-	memcpy(priv0->bcomm->bc_ipxnet, &dgrs_ipxnet, 4);
-
-	/*
-	 * Release processor, wait 8 seconds for board to initialize
-	 */
-	proc_reset(dev0, 0);
-
-	for (i = jiffies + 8 * HZ; time_after(i, jiffies); )
-	{
-		barrier();		/* Gcc 2.95 needs this */
-		if (priv0->bcomm->bc_status >= BC_RUN)
-			break;
-	}
-
-	if (priv0->bcomm->bc_status < BC_RUN)
-	{
-		printk("%s: board not operating\n", dev0->name);
-		iounmap(priv0->vmem);
-		priv0->vmem = NULL;
-		return -ENXIO;
-	}
-
-	priv0->port = (PORT *) S2H(priv0->bcomm->bc_port);
-	priv0->scbp = (I596_SCB *) S2H(priv0->port->scbp);
-	priv0->rfdp = (I596_RFD *) S2H(priv0->scbp->rfdp);
-	priv0->rbdp = (I596_RBD *) S2H(priv0->rfdp->rbdp);
-
-	priv0->scbp->status = I596_SCB_CNA;	/* CU is idle */
-
-	/*
-	 *	Get switch physical and host virtual pointers to DMA
-	 *	chaining area.  NOTE: the MSB of the switch physical
-	 *	address *must* be turned off.  Otherwise, the HW kludge
-	 *	that allows host access of the PLX DMA registers will
-	 *	erroneously select the PLX registers.
-	 */
-	priv0->dmadesc_s = (DMACHAIN *) S2DMA(priv0->bcomm->bc_hostarea);
-	if (priv0->dmadesc_s)
-		priv0->dmadesc_h = (DMACHAIN *) S2H(priv0->dmadesc_s);
-	else
-		priv0->dmadesc_h = NULL;
-
-	/*
-	 *	Enable board interrupts
-	 */
-	if (priv0->plxreg)
-	{	/* PCI bus */
-		OUTL(dev0->base_addr + PLX_INT_CSR,
-			inl(dev0->base_addr + PLX_INT_CSR)
-			| PLX_PCI_DOORBELL_IE);	/* Enable intr to host */
-		OUTL(dev0->base_addr + PLX_LCL2PCI_DOORBELL, 1);
-	}
-	else
-	{	/* EISA bus */
-	}
-
-	return (0);
-}
-
-/*
- *	Probe (init) a board
- */
-static int __init
-dgrs_probe1(struct net_device *dev)
-{
-	DGRS_PRIV	*priv = (DGRS_PRIV *) dev->priv;
-	unsigned long	i;
-	int		rc;
-
-	printk("%s: Digi RightSwitch io=%lx mem=%lx irq=%d plx=%lx dma=%lx\n",
-		dev->name, dev->base_addr, dev->mem_start, dev->irq,
-		priv->plxreg, priv->plxdma);
-
-	/*
-	 *	Download the firmware and light the processor
-	 */
-	rc = dgrs_download(dev);
-	if (rc)
-		goto err_out;
-
-	/*
-	 * Get ether address of board
-	 */
-	printk("%s: Ethernet address", dev->name);
-	memcpy(dev->dev_addr, priv->port->ethaddr, 6);
-	for (i = 0; i < 6; ++i)
-		printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
-	printk("\n");
-
-	if (dev->dev_addr[0] & 1)
-	{
-		printk("%s: Illegal Ethernet Address\n", dev->name);
-		rc = -ENXIO;
-		goto err_out;
-	}
-
-	/*
-	 *	ACK outstanding interrupts, hook the interrupt,
-	 *	and verify that we are getting interrupts from the board.
-	 */
-	if (priv->plxreg)
-		OUTL(dev->base_addr + PLX_LCL2PCI_DOORBELL, 1);
-
-	rc = request_irq(dev->irq, &dgrs_intr, IRQF_SHARED, "RightSwitch", dev);
-	if (rc)
-		goto err_out;
-
-	priv->intrcnt = 0;
-	for (i = jiffies + 2*HZ + HZ/2; time_after(i, jiffies); )
-	{
-		cpu_relax();
-		if (priv->intrcnt >= 2)
-			break;
-	}
-	if (priv->intrcnt < 2)
-	{
-		printk(KERN_ERR "%s: Not interrupting on IRQ %d (%d)\n",
-				dev->name, dev->irq, priv->intrcnt);
-		rc = -ENXIO;
-		goto err_free_irq;
-	}
-
-	/*
-	 *	Entry points...
-	 */
-	dev->open = &dgrs_open;
-	dev->stop = &dgrs_close;
-	dev->get_stats = &dgrs_get_stats;
-	dev->hard_start_xmit = &dgrs_start_xmit;
-	dev->set_multicast_list = &dgrs_set_multicast_list;
-	dev->do_ioctl = &dgrs_ioctl;
-
-	return rc;
-
-err_free_irq:
-	free_irq(dev->irq, dev);
-err_out:
-       	return rc;
-}
-
-static int __init
-dgrs_initclone(struct net_device *dev)
-{
-	DGRS_PRIV	*priv = (DGRS_PRIV *) dev->priv;
-	int		i;
-
-	printk("%s: Digi RightSwitch port %d ",
-		dev->name, priv->chan);
-	for (i = 0; i < 6; ++i)
-		printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
-	printk("\n");
-
-	return (0);
-}
-
-static struct net_device * __init
-dgrs_found_device(
-	int		io,
-	ulong		mem,
-	int		irq,
-	ulong		plxreg,
-	ulong		plxdma,
-	struct device   *pdev
-)
-{
-	DGRS_PRIV *priv;
-	struct net_device *dev;
-	int i, ret = -ENOMEM;
-
-	dev = alloc_etherdev(sizeof(DGRS_PRIV));
-	if (!dev)
-		goto err0;
-
-	priv = (DGRS_PRIV *)dev->priv;
-
-	dev->base_addr = io;
-	dev->mem_start = mem;
-	dev->mem_end = mem + 2048 * 1024 - 1;
-	dev->irq = irq;
-	priv->plxreg = plxreg;
-	priv->plxdma = plxdma;
-	priv->vplxdma = NULL;
-
-	priv->chan = 1;
-	priv->devtbl[0] = dev;
-
-	SET_MODULE_OWNER(dev);
-	SET_NETDEV_DEV(dev, pdev);
-
-	ret = dgrs_probe1(dev);
-	if (ret)
-		goto err1;
-
-	ret = register_netdev(dev);
-	if (ret)
-		goto err2;
-
-	if ( !dgrs_nicmode )
-		return dev;	/* Switch mode, we are done */
-
-	/*
-	 * Operating card as N separate NICs
-	 */
-
-	priv->nports = priv->bcomm->bc_nports;
-
-	for (i = 1; i < priv->nports; ++i)
-	{
-		struct net_device	*devN;
-		DGRS_PRIV	*privN;
-			/* Allocate new dev and priv structures */
-		devN = alloc_etherdev(sizeof(DGRS_PRIV));
-		ret = -ENOMEM;
-		if (!devN)
-			goto fail;
-
-		/* Don't copy the network device structure! */
-
-		/* copy the priv structure of dev[0] */
-		privN = (DGRS_PRIV *)devN->priv;
-		*privN = *priv;
-
-			/* ... and zero out VM areas */
-		privN->vmem = NULL;
-		privN->vplxdma = NULL;
-			/* ... and zero out IRQ */
-		devN->irq = 0;
-			/* ... and base MAC address off address of 1st port */
-		devN->dev_addr[5] += i;
-
-		ret = dgrs_initclone(devN);
-		if (ret)
-			goto fail;
-
-		SET_MODULE_OWNER(devN);
-		SET_NETDEV_DEV(dev, pdev);
-
-		ret = register_netdev(devN);
-		if (ret) {
-			free_netdev(devN);
-			goto fail;
-		}
-		privN->chan = i+1;
-		priv->devtbl[i] = devN;
-	}
-	return dev;
-
- fail:
-	while (i >= 0) {
-		struct net_device *d = priv->devtbl[i--];
-		unregister_netdev(d);
-		free_netdev(d);
-	}
-
- err2:
-	free_irq(dev->irq, dev);
- err1:
-	free_netdev(dev);
- err0:
-	return ERR_PTR(ret);
-}
-
-static void __devexit dgrs_remove(struct net_device *dev)
-{
-	DGRS_PRIV *priv = dev->priv;
-	int i;
-
-	unregister_netdev(dev);
-
-	for (i = 1; i < priv->nports; ++i) {
-		struct net_device *d = priv->devtbl[i];
-		if (d) {
-			unregister_netdev(d);
-			free_netdev(d);
-		}
-	}
-
-	proc_reset(priv->devtbl[0], 1);
-
-	if (priv->vmem)
-		iounmap(priv->vmem);
-	if (priv->vplxdma)
-		iounmap((uchar *) priv->vplxdma);
-
-	if (dev->irq)
-		free_irq(dev->irq, dev);
-
-	for (i = 1; i < priv->nports; ++i) {
-		if (priv->devtbl[i])
-			unregister_netdev(priv->devtbl[i]);
-	}
-}
-
-#ifdef CONFIG_PCI
-static int __init dgrs_pci_probe(struct pci_dev *pdev,
-				 const struct pci_device_id *ent)
-{
-	struct net_device *dev;
-	int err;
-	uint	io;
-	uint	mem;
-	uint	irq;
-	uint	plxreg;
-	uint	plxdma;
-
-	/*
-	 * Get and check the bus-master and latency values.
-	 * Some PCI BIOSes fail to set the master-enable bit,
-	 * and the latency timer must be set to the maximum
-	 * value to avoid data corruption that occurs when the
-	 * timer expires during a transfer.  Yes, it's a bug.
-	 */
-	err = pci_enable_device(pdev);
-	if (err)
-		return err;
-	err = pci_request_regions(pdev, "RightSwitch");
-	if (err)
-		return err;
-
-	pci_set_master(pdev);
-
-	plxreg = pci_resource_start (pdev, 0);
-	io = pci_resource_start (pdev, 1);
-	mem = pci_resource_start (pdev, 2);
-	pci_read_config_dword(pdev, 0x30, &plxdma);
-	irq = pdev->irq;
-	plxdma &= ~15;
-
-	/*
-	 * On some BIOSES, the PLX "expansion rom" (used for DMA)
-	 * address comes up as "0".  This is probably because
-	 * the BIOS doesn't see a valid 55 AA ROM signature at
-	 * the "ROM" start and zeroes the address.  To get
-	 * around this problem the SE-6 is configured to ask
-	 * for 4 MB of space for the dual port memory.  We then
-	 * must set its range back to 2 MB, and use the upper
-	 * half for DMA register access
-	 */
-	OUTL(io + PLX_SPACE0_RANGE, 0xFFE00000L);
-	if (plxdma == 0)
-		plxdma = mem + (2048L * 1024L);
-	pci_write_config_dword(pdev, 0x30, plxdma + 1);
-	pci_read_config_dword(pdev, 0x30, &plxdma);
-	plxdma &= ~15;
-
-	dev = dgrs_found_device(io, mem, irq, plxreg, plxdma, &pdev->dev);
-	if (IS_ERR(dev)) {
-		pci_release_regions(pdev);
-		return PTR_ERR(dev);
-	}
-
-	pci_set_drvdata(pdev, dev);
-	return 0;
-}
-
-static void __devexit dgrs_pci_remove(struct pci_dev *pdev)
-{
-	struct net_device *dev = pci_get_drvdata(pdev);
-
-	dgrs_remove(dev);
-	pci_release_regions(pdev);
-	free_netdev(dev);
-}
-
-static struct pci_driver dgrs_pci_driver = {
-	.name = "dgrs",
-	.id_table = dgrs_pci_tbl,
-	.probe = dgrs_pci_probe,
-	.remove = __devexit_p(dgrs_pci_remove),
-};
-#else
-static struct pci_driver dgrs_pci_driver = {};
-#endif
-
-
-#ifdef CONFIG_EISA
-static int is2iv[8] __initdata = { 0, 3, 5, 7, 10, 11, 12, 15 };
-
-static int __init dgrs_eisa_probe (struct device *gendev)
-{
-	struct net_device *dev;
-	struct eisa_device *edev = to_eisa_device(gendev);
-	uint	io = edev->base_addr;
-	uint	mem;
-	uint	irq;
-	int 	rc = -ENODEV; /* Not EISA configured */
-
-	if (!request_region(io, 256, "RightSwitch")) {
-		printk(KERN_ERR "dgrs: eisa io 0x%x, which is busy.\n", io);
-		return -EBUSY;
-	}
-
-	if ( ! (inb(io+ES4H_EC) & ES4H_EC_ENABLE) )
-		goto err_out;
-
-	mem = (inb(io+ES4H_AS_31_24) << 24)
-		+ (inb(io+ES4H_AS_23_16) << 16);
-
-	irq = is2iv[ inb(io+ES4H_IS) & ES4H_IS_INTMASK ];
-
-	dev = dgrs_found_device(io, mem, irq, 0L, 0L, gendev);
-	if (IS_ERR(dev)) {
-		rc = PTR_ERR(dev);
-		goto err_out;
-	}
-
-	gendev->driver_data = dev;
-	return 0;
- err_out:
-	release_region(io, 256);
-	return rc;
-}
-
-static int __devexit dgrs_eisa_remove(struct device *gendev)
-{
-	struct net_device *dev = gendev->driver_data;
-
-	dgrs_remove(dev);
-
-	release_region(dev->base_addr, 256);
-
-	free_netdev(dev);
-	return 0;
-}
-
-
-static struct eisa_driver dgrs_eisa_driver = {
-	.id_table = dgrs_eisa_tbl,
-	.driver = {
-		.name = "dgrs",
-		.probe = dgrs_eisa_probe,
-		.remove = __devexit_p(dgrs_eisa_remove),
-	}
-};
-#endif
-
-/*
- *	Variables that can be overriden from module command line
- */
-static int	debug = -1;
-static int	dma = -1;
-static int	hashexpire = -1;
-static int	spantree = -1;
-static int	ipaddr[4] = { -1 };
-static int	iptrap[4] = { -1 };
-static __u32	ipxnet = -1;
-static int	nicmode = -1;
-
-module_param(debug, int, 0);
-module_param(dma, int, 0);
-module_param(hashexpire, int, 0);
-module_param(spantree, int, 0);
-module_param_array(ipaddr, int, NULL, 0);
-module_param_array(iptrap, int, NULL, 0);
-module_param(ipxnet, int, 0);
-module_param(nicmode, int, 0);
-MODULE_PARM_DESC(debug, "Digi RightSwitch enable debugging (0-1)");
-MODULE_PARM_DESC(dma, "Digi RightSwitch enable BM DMA (0-1)");
-MODULE_PARM_DESC(nicmode, "Digi RightSwitch operating mode (1: switch, 2: multi-NIC)");
-
-static int __init dgrs_init_module (void)
-{
-	int	i;
-	int	err;
-
-	/*
-	 *	Command line variable overrides
-	 *		debug=NNN
-	 *		dma=0/1
-	 *		spantree=0/1
-	 *		hashexpire=NNN
-	 *		ipaddr=A,B,C,D
-	 *		iptrap=A,B,C,D
-	 *		ipxnet=NNN
-	 *		nicmode=NNN
-	 */
-	if (debug >= 0)
-		dgrs_debug = debug;
-	if (dma >= 0)
-		dgrs_dma = dma;
-	if (nicmode >= 0)
-		dgrs_nicmode = nicmode;
-	if (hashexpire >= 0)
-		dgrs_hashexpire = hashexpire;
-	if (spantree >= 0)
-		dgrs_spantree = spantree;
-	if (ipaddr[0] != -1)
-		for (i = 0; i < 4; ++i)
-			dgrs_ipaddr[i] = ipaddr[i];
-	if (iptrap[0] != -1)
-		for (i = 0; i < 4; ++i)
-			dgrs_iptrap[i] = iptrap[i];
-	if (ipxnet != -1)
-		dgrs_ipxnet = htonl( ipxnet );
-
-	if (dgrs_debug)
-	{
-		printk(KERN_INFO "dgrs: SW=%s FW=Build %d %s\nFW Version=%s\n",
-		       version, dgrs_firmnum, dgrs_firmdate, dgrs_firmver);
-	}
-
-	/*
-	 *	Find and configure all the cards
-	 */
-#ifdef CONFIG_EISA
-	err = eisa_driver_register(&dgrs_eisa_driver);
-	if (err)
-		return err;
-#endif
-	err = pci_register_driver(&dgrs_pci_driver);
-	if (err)
-		return err;
-	return 0;
-}
-
-static void __exit dgrs_cleanup_module (void)
-{
-#ifdef CONFIG_EISA
-	eisa_driver_unregister (&dgrs_eisa_driver);
-#endif
-#ifdef CONFIG_PCI
-	pci_unregister_driver (&dgrs_pci_driver);
-#endif
-}
-
-module_init(dgrs_init_module);
-module_exit(dgrs_cleanup_module);
diff --git a/drivers/net/dgrs.h b/drivers/net/dgrs.h
deleted file mode 100644
index 6058d53..0000000
--- a/drivers/net/dgrs.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *	ioctl's for the Digi Intl. RightSwitch
- *
- *	These network driver ioctl's are a bit obtuse compared to the usual
- *	ioctl's for a "normal" device driver.  Hey, I didn't invent it.
- *
- *	Typical use:
- *
- *	struct ifreq	ifr;
- *	DGRS_IOCTL	ioc;
- *	int		x;
- *
- *	strcpy(ifr.ifr_name, "eth1");
- *	ifr.ifr_data = (caddr_t) &ioc;
- *	ioc.cmd = DGRS_GETMEM;
- *	ioc.len = sizeof(x);
- *	ioc.data = (caddr_t) &x;
- *	rc = ioctl(fd, DGRSIOCTL, &ifr);
- *	printf("rc=%d mem=%x\n", rc, x);
- *
- */
-#include <linux/sockios.h>
-
-#define DGRSIOCTL      SIOCDEVPRIVATE
-
-typedef struct dgrs_ioctl {
-	unsigned short cmd;	/* Command to run */
-	unsigned short len;	/* Length of the data buffer */
-	unsigned char  __user *data;	/* Pointer to the data buffer */
-	unsigned short	port;	/* port number for command, if needed */
-	unsigned short	filter;	/* filter number for command, if needed */
-} DGRS_IOCTL;
-
-/*
- *	Commands for the driver
- */
-#define	DGRS_GETMEM		0x01	/* Get the dual port memory address */
-#define	DGRS_SETFILTER		0x02	/* Set a filter */
diff --git a/drivers/net/dgrs_asstruct.h b/drivers/net/dgrs_asstruct.h
deleted file mode 100644
index f0e2121..0000000
--- a/drivers/net/dgrs_asstruct.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- *	For declaring structures shared with assembly routines
- *
- *	$Id: asstruct.h,v 1.1.1.1 1994/10/23 05:08:32 rick Exp $
- */
-
-#ifdef ASSEMBLER
-
-#	define MO(t,a)		(a)
-#	define VMO(t,a)		(a)
-
-#	define	BEGIN_STRUCT(x)	_Off=0
-#	define	S1A(t,x,n)	_Off=(_Off+0)&~0; x=_Off; _Off=_Off+(1*n)
-#	define	S2A(t,x,n)	_Off=(_Off+1)&~1; x=_Off; _Off=_Off+(2*n)
-#	define	S4A(t,x,n)	_Off=(_Off+3)&~3; x=_Off; _Off=_Off+(4*n)
-#	define	WORD(x)		_Off=(_Off+3)&~3; x=_Off; _Off=_Off+4
-#	define	WORDA(x,n)	_Off=(_Off+3)&~3; x=_Off; _Off=_Off+(4*n)
-#	define	VWORD(x)	_Off=(_Off+3)&~3; x=_Off; _Off=_Off+4
-#	define	S1(t,x)		_Off=(_Off+0)&~0; x=_Off; _Off=_Off+1
-#	define	S2(t,x)		_Off=(_Off+1)&~1; x=_Off; _Off=_Off+2
-#	define	S4(t,x)		_Off=(_Off+3)&~3; x=_Off; _Off=_Off+4
-#	define	END_STRUCT(x)	_Off=(_Off+3)&~3; x=_Off
-
-#else	/* C */
-
-#define VMO(t,a)        (*(volatile t *)(a))
-
-#	define BEGIN_STRUCT(x) struct x {
-#	define S1(t,x)         t x ;
-#	define S1A(t,x,n)      t x[n] ;
-#	define S2(t,x)         t x ;
-#	define S2A(t,x,n)      t x[n] ;
-#	define S4(t,x)         t x ;
-#	define S4A(t,x,n)      t x[n] ;
-#	define END_STRUCT(x)   } ;
-
-#endif
diff --git a/drivers/net/dgrs_bcomm.h b/drivers/net/dgrs_bcomm.h
deleted file mode 100644
index 5e9c252..0000000
--- a/drivers/net/dgrs_bcomm.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * The bios low-memory structure
- *
- * Some of the variables in here can be used to set parameters that
- * are stored in NVRAM and will retain their old values the next time
- * the card is brought up.  To use the values stored in NVRAM, the
- * parameter should be set to "all ones".  This tells the firmware to
- * use the NVRAM value or a suitable default.  The value that is used
- * will be stored back into this structure by the firmware.  If the
- * value of the variable is not "all ones", then that value will be
- * used and will be stored into NVRAM if it isn't already there.
- * The variables this applies to are the following:
- *	Variable	Set to:		Gets default of:
- *	bc_hashexpire	-1		300	(5 minutes)
- *	bc_spantree	-1		1	(spanning tree on)
- *	bc_ipaddr	FF:FF:FF:FF	0	(no SNMP IP address)
- *	bc_ipxnet	FF:FF:FF:FF	0	(no SNMP IPX net)
- *	bc_iptrap	FF:FF:FF:FF	0	(no SNMP IP trap address)
- *
- * Some variables MUST have their value set after the firmware
- * is loaded onto the board, but before the processor is released.
- * These are:
- *	bc_host		0 means no host "port", run as standalone switch.
- *			1 means run as a switch, with a host port. (normal)
- *			2 means run as multiple NICs, not as a switch.
- *			-1 means run in diagnostics mode.
- *	bc_nowait
- *	bc_hostarea_len
- *	bc_filter_len
- *
- */
-BEGIN_STRUCT(bios_comm)
-	S4(ulong, bc_intflag)	/* Count of all interrupts */
-	S4(ulong, bc_lbolt)	/* Count of timer interrupts */
-	S4(ulong, bc_maincnt)	/* Count of main loops */
-	S4(ulong, bc_hashcnt)	/* Count of entries in hash table */
-	S4A(ulong, bc_cnt, 8)	/* Misc counters, for debugging */
-	S4A(ulong, bc_flag, 8)	/* Misc flags, for debugging */
-	S4(ulong, bc_memsize)	/* Size of memory */
-	S4(ulong, bc_dcache)	/* Size of working dcache */
-	S4(ulong, bc_icache)	/* Size of working icache */
-	S4(long, bc_status)	/* Firmware status */
-	S1A(char, bc_file, 8)	/* File name of assertion failure */
-	S4(ulong, bc_line)	/* Line # of assertion failure */
-	S4(uchar *, bc_ramstart)
-	S4(uchar *, bc_ramend)
-	S4(uchar *, bc_heapstart) /* Start of heap (end of loaded memory) */
-	S4(uchar *, bc_heapend)	/* End of heap */
-
-	/* Configurable Parameters */
-	S4(long, bc_host)	/* 1=Host Port, 0=No Host Port, -1=Test Mode */
-	S4(long, bc_nowait)	/* Don't wait for 2host circ buffer to empty*/
-	S4(long, bc_150ohm)	/* 0 == 100 ohm UTP, 1 == 150 ohm STP */
-	S4(long, bc_squelch)	/* 0 == normal squelch, 1 == reduced squelch */
-	S4(ulong, bc_hashexpire) /* Expiry time in seconds for hash table */
-	S4(long, bc_spantree)	/* 1 == enable IEEE spanning tree */
-
-	S2A(ushort, bc_eaddr, 3) /* New ether address */
-	S2(ushort, bc_dummy1)	/* padding for DOS compilers */
-
-	/* Various debugging aids */
-	S4(long, bc_debug)	/* Debugging is turned on */
-	S4(long, bc_spew)	/* Spew data on port 4 for bs_spew seconds */
-	S4(long, bc_spewlen)	/* Length of spewed data packets */
-	S4(long, bc_maxrfd)	/* If != 0, max number of RFD's to allocate */
-	S4(long, bc_maxrbd)	/* If != 0, max number of RBD's to allocate */
-
-	/* Circular buffers for messages to/from host */
-	S4(ulong, bc_2host_head)
-	S4(ulong, bc_2host_tail)
-	S4(ulong, bc_2host_mask)
-	S1A(char, bc_2host, 0x200)	/* Circ buff to host */
-
-	S4(ulong, bc_2idt_head)
-	S4(ulong, bc_2idt_tail)
-	S4(ulong, bc_2idt_mask)
-	S1A(char, bc_2idt, 0x200)	/* Circ buff to idt */
-
-	/* Pointers to structures for driver access */
-	S4(uchar *, bc_port)	/* pointer to Port[] structures */
-	S4(long, bc_nports)	/* Number of ports */
-	S4(long, bc_portlen)	/* sizeof(PORT) */
-	S4(uchar *, bc_hash)	/* Pointer to hash table */
-	S4(long, bc_hashlen)	/* sizeof(Table) */
-
-	/* SNMP agent addresses */
-	S1A(uchar, bc_ipaddr, 4) /* IP address for SNMP */
-	S1A(uchar, bc_ipxnet, 4) /* IPX net address for SNMP */
-
-	S4(long, bc_nohostintr) /* Do not cause periodic host interrupts */
-
-	S4(uchar *, bc_dmaaddr) /* Physical addr of host DMA buf for diags */
-	S4(ulong, bc_dmalen)	/* Length of DMA buffer 0..2048 */
-
-	/*
-	 *	Board memory allocated on startup for use by host, usually
-	 *	for the purposes of creating DMA chain descriptors.  The
-	 *	"len" must be set before the processor is released.  The
-	 *	address of the area is returned in bc_hostarea.  The area
-	 *	is guaranteed to be aligned on a 16 byte boundary.
-	 */
-	S4(ulong, bc_hostarea_len)	/* RW: Number of bytes to allocate */
-	S4(uchar *, bc_hostarea)	/* RO: Address of allocated memory */
-
-	/*
-	 *	Variables for communicating filters into the board
-	 */
-	S4(ulong *, bc_filter_area)	/* RO: Space to put filter into */
-	S4(ulong, bc_filter_area_len)	/* RO: Length of area, in bytes */
-	S4(long, bc_filter_cmd)		/* RW: Filter command, see below */
-	S4(ulong, bc_filter_len)	/* RW: Actual length of filter */
-	S4(ulong, bc_filter_port)	/* RW: Port # for filter 0..6 */
-	S4(ulong, bc_filter_num)	/* RW: Filter #, 0=input, 1=output */
-
-	/* more SNMP agent addresses */
-	S1A(uchar, bc_iptrap, 4) /* IP address for SNMP */
-
-	S4A(long, bc_spare, 2)	/* spares */
-END_STRUCT(bios_comm)
-
-#define	bc	VMO(struct bios_comm, 0xa3000100)
-
-/*
- *	bc_status values
- */
-#define	BC_INIT	0
-#define	BC_RUN	100
-
-/*
- *	bc_host values
- */
-#define	BC_DIAGS	-1
-#define BC_SASWITCH	0
-#define	BC_SWITCH	1
-#define	BC_MULTINIC	2
-
-/*
- *	Values for spew (debugging)
- */
-#define	BC_SPEW_ENABLE	0x80000000
-
-/*
- *	filter commands
- */
-#define	BC_FILTER_ERR	-1
-#define	BC_FILTER_OK	0
-#define	BC_FILTER_SET	1
-#define	BC_FILTER_CLR	2
diff --git a/drivers/net/dgrs_es4h.h b/drivers/net/dgrs_es4h.h
deleted file mode 100644
index 5518fba..0000000
--- a/drivers/net/dgrs_es4h.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/************************************************************************/
-/*									*/
-/*	es4h.h:	Hardware definition of the ES/4h Ethernet Switch, from	*/
-/*		both the host and the 3051's point of view.		*/
-/*		NOTE: this name is a misnomer now that there is a PCI	*/
-/*		board.  Everything that says "es4h" should really be	*/
-/*		"se4".  But we'll keep the old name for now.		*/
-/*									*/
-/*	$Id: es4h.h,v 1.10 1996/08/22 17:16:53 rick Exp $		*/
-/*									*/
-/************************************************************************/
-
-/************************************************************************/
-/*									*/
-/*	EISA I/O Registers.  These are located at 0x1000 * slot-number	*/
-/*	plus the indicated address.  I.E. 0x4000-0x4009 for slot 4.	*/
-/*									*/
-/************************************************************************/
-
-#define	ES4H_MANUFmsb	0x00		/* Read-only */
-#define	ES4H_MANUFlsb	0x01		/* Read-only */
-#	define ES4H_MANUF_CODE		0x1049	/* = "DBI" */
-
-#define	ES4H_PRODUCT	0x02		/* Read-only */
-#	define ES4H_PRODUCT_CODE	0x0A
-#	define EPC_PRODUCT_CODE		0x03
-
-#define	ES4H_REVISION	0x03		/* Read-only */
-#	define ES4H_REVISION_CODE	0x01
-
-#define	ES4H_EC		0x04		/* EISA Control */
-#	define ES4H_EC_RESET		0x04	/* WO, EISA reset */
-#	define ES4H_EC_ENABLE		0x01	/* RW, EISA enable - set to */
-						/* 1 before memory enable */
-#define	ES4H_PC		0x05		/* Processor Control */
-#	define ES4H_PC_RESET		0x04	/* RW, 3051 reset */
-#	define ES4H_PC_INT		0x08	/* WO, assert 3051 intr. 3 */
-
-#define	ES4H_MW		0x06		/* Memory Window select and enable */
-#	define ES4H_MW_ENABLE		0x80	/* WO, enable memory */
-#	define ES4H_MW_SELECT_MASK	0x1f	/* WO, 32k window selected */
-
-#define	ES4H_IS		0x07		/* Interrupt, addr select */
-#	define ES4H_IS_INTMASK		0x07	/* WO, interrupt select */
-#	define ES4H_IS_INTOFF		0x00		/* No IRQ */
-#	define ES4H_IS_INT3		0x03		/* IRQ 3 */
-#	define ES4H_IS_INT5		0x02		/* IRQ 5 */
-#	define ES4H_IS_INT7		0x01		/* IRQ 7 */
-#	define ES4H_IS_INT10		0x04		/* IRQ 10 */
-#	define ES4H_IS_INT11		0x05		/* IRQ 11 */
-#	define ES4H_IS_INT12		0x06		/* IRQ 12 */
-#	define ES4H_IS_INT15		0x07		/* IRQ 15 */
-#	define ES4H_IS_INTACK		0x10	/* WO, interrupt ack */
-#	define ES4H_IS_INTPEND		0x10	/* RO, interrupt pending */
-#	define ES4H_IS_LINEAR		0x40	/* WO, no memory windowing */
-#	define ES4H_IS_AS15		0x80	/* RW, address select bit 15 */
-
-#define	ES4H_AS_23_16	0x08		/* Address select bits 23-16 */
-#define	ES4H_AS_31_24	0x09		/* Address select bits 31-24 */
-
-#define ES4H_IO_MAX		0x09		/* Size of I/O space */
-
-/*
- * PCI
- */
-#define SE6_RESET		PLX_USEROUT
-
-/************************************************************************/
-/*									*/
-/*	3051 Memory Map							*/
-/*									*/
-/*	Note: 3051 has 4K I-cache, 2K D-cache.  1 cycle is 50 nsec.	*/
-/*									*/
-/************************************************************************/
-#define	SE4_NPORTS		4		/* # of ethernet ports */
-#define	SE6_NPORTS		6		/* # of ethernet ports */
-#define	SE_NPORTS		6		/* Max # of ethernet ports */
-
-#define	ES4H_RAM_BASE		0x83000000	/* Base address of RAM */
-#define	ES4H_RAM_SIZE		0x00200000	/* Size of RAM (2MB) */
-#define	ES4H_RAM_INTBASE	0x83800000	/* Base of int-on-write RAM */
-						/* a.k.a. PKT RAM */
-
-						/* Ethernet controllers */
-						/* See: i82596.h */
-#define	ES4H_ETHER0_PORT	0xA2000000
-#define	ES4H_ETHER0_CMD		0xA2000100
-#define	ES4H_ETHER1_PORT	0xA2000200
-#define	ES4H_ETHER1_CMD		0xA2000300
-#define	ES4H_ETHER2_PORT	0xA2000400
-#define	ES4H_ETHER2_CMD		0xA2000500
-#define	ES4H_ETHER3_PORT	0xA2000600
-#define	ES4H_ETHER3_CMD		0xA2000700
-#define	ES4H_ETHER4_PORT	0xA2000800	/* RS SE-6 only */
-#define	ES4H_ETHER4_CMD		0xA2000900	/* RS SE-6 only */
-#define	ES4H_ETHER5_PORT	0xA2000A00	/* RS SE-6 only */
-#define	ES4H_ETHER5_CMD		0xA2000B00	/* RS SE-6 only */
-
-#define	ES4H_I8254		0xA2040000	/* 82C54 timers */
-						/* See: i8254.h */
-
-#define	SE4_I8254_HZ		(23000000/4)	/* EISA clock input freq. */
-#define	SE4_IDT_HZ		(46000000)	/* EISA CPU freq. */
-#define	SE6_I8254_HZ		(20000000/4)	/* PCI clock input freq. */
-#define	SE6_IDT_HZ		(50000000)	/* PCI CPU freq. */
-#define	ES4H_I8254_HZ		(23000000/4)	/* EISA clock input freq. */
-
-#define	ES4H_GPP		0xA2050000	/* General purpose port */
-	/*
-	 * SE-4 (EISA) GPP bits
-	 */
-#	define ES4H_GPP_C0_100		0x0001	/* WO, Chan 0: 100 ohm TP */
-#	define ES4H_GPP_C0_SQE		0x0002	/* WO, Chan 0: normal squelch */
-#	define ES4H_GPP_C1_100		0x0004	/* WO, Chan 1: 100 ohm TP */
-#	define ES4H_GPP_C1_SQE		0x0008	/* WO, Chan 1: normal squelch */
-#	define ES4H_GPP_C2_100		0x0010	/* WO, Chan 2: 100 ohm TP */
-#	define ES4H_GPP_C2_SQE		0x0020	/* WO, Chan 2: normal squelch */
-#	define ES4H_GPP_C3_100		0x0040	/* WO, Chan 3: 100 ohm TP */
-#	define ES4H_GPP_C3_SQE		0x0080	/* WO, Chan 3: normal squelch */
-#	define ES4H_GPP_SQE		0x00AA	/* WO, All: normal squelch */
-#	define ES4H_GPP_100		0x0055	/* WO, All: 100 ohm TP */
-#	define ES4H_GPP_HOSTINT		0x0100	/* RO, cause intr. to host */
-						/* Hold high > 250 nsec */
-#	define SE4_GPP_EED		0x0200	/* RW, EEPROM data bit */
-#	define SE4_GPP_EECS		0x0400	/* RW, EEPROM chip select */
-#	define SE4_GPP_EECK		0x0800	/* RW, EEPROM clock */
-
-	/*
-	 * SE-6 (PCI) GPP bits
-	 */
-#	define SE6_GPP_EED		0x0001	/* RW, EEPROM data bit */
-#	define SE6_GPP_EECS		0x0002	/* RW, EEPROM chip select */
-#	define SE6_GPP_EECK		0x0004	/* RW, EEPROM clock */
-#	define SE6_GPP_LINK		0x00fc	/* R, Link status LEDs */
-
-#define	ES4H_INTVEC		0xA2060000	/* RO: Interrupt Vector */
-#	define ES4H_IV_DMA0		0x01	/* Chan 0 DMA interrupt */
-#	define ES4H_IV_PKT0		0x02	/* Chan 0 PKT interrupt */
-#	define ES4H_IV_DMA1		0x04	/* Chan 1 DMA interrupt */
-#	define ES4H_IV_PKT1		0x08	/* Chan 1 PKT interrupt */
-#	define ES4H_IV_DMA2		0x10	/* Chan 2 DMA interrupt */
-#	define ES4H_IV_PKT2		0x20	/* Chan 2 PKT interrupt */
-#	define ES4H_IV_DMA3		0x40	/* Chan 3 DMA interrupt */
-#	define ES4H_IV_PKT3		0x80	/* Chan 3 PKT interrupt */
-
-#define	ES4H_INTACK		0xA2060000	/* WO: Interrupt Ack */
-#	define ES4H_INTACK_8254		0x01	/* Real Time Clock (int 0) */
-#	define ES4H_INTACK_HOST		0x02	/* Host (int 1) */
-#	define ES4H_INTACK_PKT0		0x04	/* Chan 0 Pkt (int 2) */
-#	define ES4H_INTACK_PKT1		0x08	/* Chan 1 Pkt (int 3) */
-#	define ES4H_INTACK_PKT2		0x10	/* Chan 2 Pkt (int 4) */
-#	define ES4H_INTACK_PKT3		0x20	/* Chan 3 Pkt (int 5) */
-
-#define	SE6_PLX			0xA2070000	/* PLX 9060, SE-6 (PCI) only */
-						/* see plx9060.h */
-
-#define	SE6_PCI_VENDOR_ID	0x114F		/* Digi PCI vendor ID */
-#define	SE6_PCI_DEVICE_ID	0x0003		/* RS SE-6 device ID */
-#define	SE6_PCI_ID		((SE6_PCI_DEVICE_ID<<16) | SE6_PCI_VENDOR_ID)
-
-/*
- *	IDT Interrupts
- */
-#define	ES4H_INT_8254		IDT_INT0
-#define	ES4H_INT_HOST		IDT_INT1
-#define	ES4H_INT_ETHER0		IDT_INT2
-#define	ES4H_INT_ETHER1		IDT_INT3
-#define	ES4H_INT_ETHER2		IDT_INT4
-#define	ES4H_INT_ETHER3		IDT_INT5
-
-/*
- *	Because there are differences between the SE-4 and the SE-6,
- *	we assume that the following globals will be set up at init
- *	time in main.c to containt the appropriate constants from above
- */
-extern ushort	Gpp;		/* Softcopy of GPP register */
-extern ushort	EEck;		/* Clock bit */
-extern ushort	EEcs;		/* CS bit */
-extern ushort	EEd;		/* Data bit */
-extern ulong	I8254_Hz;	/* i8254 input frequency */
-extern ulong	IDT_Hz;		/* IDT CPU frequency */
-extern int	Nports;		/* Number of ethernet controllers */
-extern int	Nchan;		/* Nports+1 */
diff --git a/drivers/net/dgrs_ether.h b/drivers/net/dgrs_ether.h
deleted file mode 100644
index 7539b59..0000000
--- a/drivers/net/dgrs_ether.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- *	A filtering function.  There are two filters/port.  Filter "0"
- *	is the input filter, and filter "1" is the output filter.
- */
-typedef int (FILTER_FUNC)(uchar *pktp, int pktlen, ulong *scratch, int port);
-#define	NFILTERS	2
-
-/*
- *	The per port structure
- */
-typedef struct
-{
-	int		chan;		/* Channel number (0-3) */
-	ulong		portaddr;	/* address of 596 port register */
-	volatile ulong	*ca;		/* address of 596 chan attention */
-	ulong		intmask;	/* Interrupt mask for this port */
-	ulong		intack;		/* Ack bit for this port */
-
-	uchar		ethaddr[6];	/* Ethernet address of this port */
-	int		is_promisc;	/* Port is promiscuous */
-
-	int		debug;		/* Debugging turned on */
-
-	I596_ISCP	*iscpp;		/* Uncached ISCP pointer */
-	I596_SCP	*scpp;		/* Uncached SCP pointer */
-	I596_SCB	*scbp;		/* Uncached SCB pointer */
-
-	I596_ISCP	iscp;
-	I596_SCB	scb;
-
-	/* Command Queue */
-	I596_CB		*cb0;
-	I596_CB		*cbN;
-	I596_CB		*cb_head;
-	I596_CB		*cb_tail;
-
-	/* Receive Queue */
-	I596_RFD	*rfd0;
-	I596_RFD	*rfdN;
-	I596_RFD	*rfd_head;
-	I596_RFD	*rfd_tail;
-
-	/* Receive Buffers */
-	I596_RBD	*rbd0;
-	I596_RBD	*rbdN;
-	I596_RBD	*rbd_head;
-	I596_RBD	*rbd_tail;
-	int		buf_size;	/* Size of an RBD buffer */
-	int		buf_cnt;	/* Total RBD's allocated */
-
-	/* Rx Statistics */
-	ulong		cnt_rx_cnt;	/* Total packets rcvd, good and bad */
-	ulong		cnt_rx_good;	/* Total good packets rcvd */
-	ulong		cnt_rx_bad;	/* Total of all bad packets rcvd */
-					/* Subtotals can be gotten from SCB */
-	ulong		cnt_rx_nores;	/* No resources */
-	ulong		cnt_rx_bytes;	/* Total bytes rcvd */
-
-	/* Tx Statistics */
-	ulong		cnt_tx_queued;
-	ulong		cnt_tx_done;
-	ulong		cnt_tx_freed;
-	ulong		cnt_tx_nores;	/* No resources */
-
-	ulong		cnt_tx_bad;
-	ulong		cnt_tx_err_late;
-	ulong		cnt_tx_err_nocrs;
-	ulong		cnt_tx_err_nocts;
-	ulong		cnt_tx_err_under;
-	ulong		cnt_tx_err_maxcol;
-	ulong		cnt_tx_collisions;
-
-	/* Special stuff for host */
-#	define		rfd_freed	cnt_rx_cnt
-	ulong		rbd_freed;
-	int		host_timer;
-
-	/* Added after first beta */
-	ulong		cnt_tx_races;	/* Counts race conditions */
-	int		spanstate;
-	ulong		cnt_st_tx;	/* send span tree pkts */
-	ulong		cnt_st_fail_tx;	/* Failures to send span tree pkts */
-	ulong		cnt_st_fail_rbd;/* Failures to send span tree pkts */
-	ulong		cnt_st_rx;	/* rcv span tree pkts */
-	ulong		cnt_st_rx_bad;	/* bogus st packets rcvd */
-	ulong		cnt_rx_fwd;	/* Rcvd packets that were forwarded */
-
-	ulong		cnt_rx_mcast;	/* Multicast pkts received */
-	ulong		cnt_tx_mcast;	/* Multicast pkts transmitted */
-	ulong		cnt_tx_bytes;	/* Bytes transmitted */
-
-	/*
-	 *	Packet filtering
-	 *	Filter 0: input filter
-	 *	Filter 1: output filter
-	 */
-
-	ulong		*filter_space[NFILTERS];
-	FILTER_FUNC	*filter_func[NFILTERS];
-	ulong		filter_cnt[NFILTERS];
-	ulong		filter_len[NFILTERS];
-
-	ulong		pad[ (512-300) / 4];
-} PORT;
-
-/*
- *	Port[0]			is host interface
- *	Port[1..SE_NPORTS]	are external 10 Base T ports.  Fewer may be in
- *				use, depending on whether this is an SE-4 or
- *				an SE-6.
- *	Port[SE_NPORTS]		Pseudo-port for Spanning tree and SNMP
- */
-extern PORT	Port[1+SE_NPORTS+1];
-
-extern int	Nports;		/* Number of genuine ethernet controllers */
-extern int	Nchan;		/* ... plus one for host interface */
-
-extern int	FirstChan;	/* 0 or 1, depedning on whether host is used */
-extern int	NumChan;	/* 4 or 5 */
-
-/*
- *	A few globals
- */
-extern int	IsPromisc;
-extern int	MultiNicMode;
-
-/*
- *	Functions
- */
-extern void	eth_xmit_spew_on(PORT *p, int cnt);
-extern void	eth_xmit_spew_off(PORT *p);
-
-extern I596_RBD	*alloc_rbds(PORT *p, int num);
-
-extern I596_CB * eth_cb_alloc(PORT *p);
diff --git a/drivers/net/dgrs_firmware.c b/drivers/net/dgrs_firmware.c
deleted file mode 100644
index 8c20d4c..0000000
--- a/drivers/net/dgrs_firmware.c
+++ /dev/null
@@ -1,9966 +0,0 @@
-static const int dgrs_firmnum = 550;
-static char dgrs_firmver[] = "$Version$";
-static char dgrs_firmdate[] = "11/16/96 03:45:15";
-static unsigned char dgrs_code[] __initdata = {
-	213,5,192,8,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,64,40,35,41,
-	101,115,52,104,46,98,105,110,32,32,32,32,
-	32,32,49,46,48,32,48,48,47,48,48,47,
-	57,52,0,64,40,35,41,67,111,112,121,114,
-	105,103,104,116,32,49,57,57,53,44,32,68,
-	105,103,105,32,73,110,116,101,114,110,97,116,
-	105,111,110,97,108,46,32,32,65,108,108,32,
-	82,105,103,104,116,115,32,82,101,115,101,114,
-	118,101,100,46,0,0,0,0,97,5,192,8,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,255,255,0,16,0,0,0,0,
-	0,0,0,0,8,0,224,3,0,0,0,0,
-	148,255,189,39,16,0,161,175,20,0,162,175,
-	24,0,163,175,28,0,164,175,32,0,165,175,
-	36,0,166,175,40,0,167,175,44,0,168,175,
-	48,0,169,175,52,0,170,175,56,0,171,175,
-	60,0,172,175,64,0,173,175,68,0,174,175,
-	72,0,175,175,76,0,184,175,80,0,185,175,
-	88,0,190,175,92,0,191,175,0,112,8,64,
-	18,72,0,0,16,80,0,0,0,96,11,64,
-	84,0,168,175,96,0,169,175,100,0,170,175,
-	104,0,171,175,33,56,0,1,0,131,24,60,
-	0,1,24,39,0,0,8,143,0,0,0,0,
-	1,0,8,33,0,0,8,175,0,104,5,64,
-	0,96,6,64,124,0,168,48,212,255,0,21,
-	0,0,0,0,36,64,166,0,0,255,8,49,
-	27,0,0,17,0,0,0,0,130,65,8,0,
-	2,131,9,60,33,72,40,1,0,220,41,141,
-	66,64,8,0,2,131,10,60,33,80,72,1,
-	0,224,74,141,0,0,0,0,38,80,70,1,
-	1,255,74,49,33,40,192,0,38,48,202,0,
-	0,96,134,64,66,64,8,0,2,131,4,60,
-	33,32,136,0,0,226,132,144,9,248,32,1,
-	0,0,0,0,104,0,166,143,0,0,0,0,
-	0,96,134,64,0,104,5,64,227,255,0,16,
-	0,0,0,0,104,0,168,143,96,0,169,143,
-	100,0,170,143,0,0,0,0,0,96,136,64,
-	19,0,32,1,17,0,64,1,20,0,162,143,
-	24,0,163,143,28,0,164,143,32,0,165,143,
-	36,0,166,143,40,0,167,143,44,0,168,143,
-	48,0,169,143,52,0,170,143,56,0,171,143,
-	60,0,172,143,64,0,173,143,68,0,174,143,
-	72,0,175,143,76,0,184,143,80,0,185,143,
-	88,0,190,143,92,0,191,143,0,0,0,0,
-	84,0,186,143,16,0,161,143,108,0,189,39,
-	8,0,64,3,16,0,0,66,0,96,26,64,
-	0,0,0,0,255,255,27,60,254,0,123,55,
-	0,0,0,0,36,208,91,3,0,0,0,0,
-	0,96,154,64,0,0,0,0,0,112,26,64,
-	0,0,0,0,16,0,0,66,0,0,0,0,
-	8,0,64,3,0,0,0,0,255,255,8,36,
-	133,255,0,17,0,0,0,0,1,0,8,37,
-	130,255,0,21,0,0,0,0,255,255,8,36,
-	33,8,0,1,126,255,40,20,0,0,0,0,
-	1,0,33,36,123,255,32,20,0,0,0,0,
-	255,255,2,36,120,255,72,20,0,0,0,0,
-	1,0,66,36,117,255,64,20,0,0,0,0,
-	255,255,3,36,114,255,104,20,0,0,0,0,
-	1,0,99,36,111,255,96,20,0,0,0,0,
-	255,255,4,36,108,255,136,20,0,0,0,0,
-	1,0,132,36,105,255,128,20,0,0,0,0,
-	255,255,5,36,102,255,168,20,0,0,0,0,
-	1,0,165,36,99,255,160,20,0,0,0,0,
-	255,255,6,36,96,255,200,20,0,0,0,0,
-	1,0,198,36,93,255,192,20,0,0,0,0,
-	255,255,7,36,90,255,232,20,0,0,0,0,
-	1,0,231,36,87,255,224,20,0,0,0,0,
-	255,255,9,36,84,255,40,21,0,0,0,0,
-	1,0,41,37,81,255,32,21,0,0,0,0,
-	255,255,10,36,78,255,72,21,0,0,0,0,
-	1,0,74,37,75,255,64,21,0,0,0,0,
-	255,255,11,36,72,255,104,21,0,0,0,0,
-	1,0,107,37,69,255,96,21,0,0,0,0,
-	255,255,12,36,66,255,136,21,0,0,0,0,
-	1,0,140,37,63,255,128,21,0,0,0,0,
-	255,255,13,36,60,255,168,21,0,0,0,0,
-	1,0,173,37,57,255,160,21,0,0,0,0,
-	255,255,14,36,54,255,200,21,0,0,0,0,
-	1,0,206,37,51,255,192,21,0,0,0,0,
-	255,255,15,36,48,255,232,21,0,0,0,0,
-	1,0,239,37,45,255,224,21,0,0,0,0,
-	255,255,24,36,42,255,8,23,0,0,0,0,
-	1,0,24,39,39,255,0,23,0,0,0,0,
-	255,255,16,36,36,255,8,22,0,0,0,0,
-	1,0,16,38,33,255,0,22,0,0,0,0,
-	255,255,17,36,30,255,40,22,0,0,0,0,
-	1,0,49,38,27,255,32,22,0,0,0,0,
-	255,255,18,36,24,255,72,22,0,0,0,0,
-	1,0,82,38,21,255,64,22,0,0,0,0,
-	255,255,19,36,18,255,104,22,0,0,0,0,
-	1,0,115,38,15,255,96,22,0,0,0,0,
-	255,255,20,36,12,255,136,22,0,0,0,0,
-	1,0,148,38,9,255,128,22,0,0,0,0,
-	255,255,21,36,6,255,168,22,0,0,0,0,
-	1,0,181,38,3,255,160,22,0,0,0,0,
-	255,255,22,36,0,255,200,22,0,0,0,0,
-	1,0,214,38,253,254,192,22,0,0,0,0,
-	255,255,23,36,250,254,232,22,0,0,0,0,
-	1,0,247,38,247,254,224,22,0,0,0,0,
-	255,255,26,36,244,254,72,23,0,0,0,0,
-	1,0,90,39,241,254,64,23,0,0,0,0,
-	255,255,27,36,238,254,104,23,0,0,0,0,
-	1,0,123,39,235,254,96,23,0,0,0,0,
-	255,255,28,36,232,254,136,23,0,0,0,0,
-	1,0,156,39,229,254,128,23,0,0,0,0,
-	255,255,29,36,226,254,168,23,0,0,0,0,
-	1,0,189,39,223,254,160,23,0,0,0,0,
-	255,255,30,36,220,254,200,23,0,0,0,0,
-	1,0,222,39,217,254,192,23,0,0,0,0,
-	255,255,31,36,214,254,232,23,0,0,0,0,
-	1,0,255,39,211,254,224,23,0,0,0,0,
-	0,131,24,60,0,1,24,39,0,32,1,60,
-	37,192,1,3,0,96,8,64,0,0,0,0,
-	1,0,1,60,37,64,1,1,0,96,136,64,
-	33,16,0,0,165,165,3,60,165,165,99,52,
-	0,128,1,60,0,0,35,172,0,128,9,60,
-	0,0,41,141,0,0,0,0,0,96,10,64,
-	0,0,0,0,8,0,1,60,36,80,65,1,
-	29,0,64,21,0,0,0,0,27,0,105,20,
-	0,0,0,0,0,1,2,36,0,128,1,60,
-	33,8,34,0,0,0,32,172,64,16,2,0,
-	1,0,1,60,1,0,33,52,43,8,65,0,
-	248,255,32,20,0,0,0,0,255,255,3,36,
-	0,128,1,60,0,0,35,172,0,1,2,36,
-	0,128,3,60,33,24,98,0,0,0,99,140,
-	0,0,0,0,7,0,96,20,0,0,0,0,
-	64,16,2,0,1,0,1,60,1,0,33,52,
-	43,8,65,0,245,255,32,20,0,0,0,0,
-	0,96,128,64,0,0,0,0,84,0,2,175,
-	0,96,8,64,0,0,0,0,3,0,1,60,
-	37,64,1,1,0,96,136,64,33,16,0,0,
-	165,165,3,60,165,165,99,52,0,128,1,60,
-	0,0,35,172,0,128,9,60,0,0,41,141,
-	0,0,0,0,0,96,10,64,0,0,0,0,
-	8,0,1,60,36,80,65,1,29,0,64,21,
-	0,0,0,0,27,0,105,20,0,0,0,0,
-	0,1,2,36,0,128,1,60,33,8,34,0,
-	0,0,32,172,64,16,2,0,1,0,1,60,
-	1,0,33,52,43,8,65,0,248,255,32,20,
-	0,0,0,0,255,255,3,36,0,128,1,60,
-	0,0,35,172,0,1,2,36,0,128,3,60,
-	33,24,98,0,0,0,99,140,0,0,0,0,
-	7,0,96,20,0,0,0,0,64,16,2,0,
-	1,0,1,60,1,0,33,52,43,8,65,0,
-	245,255,32,20,0,0,0,0,0,96,128,64,
-	0,0,0,0,88,0,2,175,88,0,9,143,
-	0,0,0,0,17,0,32,17,0,0,0,0,
-	0,0,0,0,3,0,2,60,0,0,0,0,
-	0,96,130,64,0,128,8,60,37,72,40,1,
-	0,0,0,161,4,0,0,161,8,0,0,161,
-	12,0,0,161,16,0,0,161,20,0,0,161,
-	24,0,0,161,32,0,8,37,247,255,9,21,
-	252,255,0,161,84,0,9,143,0,0,0,0,
-	17,0,32,17,0,0,0,0,0,0,0,0,
-	1,0,2,60,0,0,0,0,0,96,130,64,
-	0,128,8,60,37,72,40,1,0,0,0,161,
-	4,0,0,161,8,0,0,161,12,0,0,161,
-	16,0,0,161,20,0,0,161,24,0,0,161,
-	32,0,8,37,247,255,9,21,252,255,0,161,
-	32,0,8,60,0,96,136,64,0,104,128,64,
-	0,131,2,60,152,28,66,36,255,31,9,60,
-	255,255,41,53,36,16,73,0,0,128,9,60,
-	37,16,73,0,8,0,64,0,0,0,0,0,
-	2,131,8,60,224,210,8,37,252,255,1,36,
-	36,64,1,1,3,131,9,60,124,18,41,37,
-	252,255,1,36,36,72,33,1,0,0,10,36,
-	0,0,10,173,254,255,9,21,4,0,8,37,
-	3,131,8,60,128,18,8,37,252,255,1,36,
-	36,64,1,1,31,131,9,60,252,255,41,53,
-	252,255,1,36,36,72,33,1,237,254,10,60,
-	175,222,74,53,0,0,10,173,254,255,9,21,
-	4,0,8,37,2,131,8,60,0,212,8,37,
-	252,255,1,36,36,64,1,1,2,131,9,60,
-	252,219,41,37,252,255,1,36,36,72,33,1,
-	173,222,10,60,239,190,74,53,0,0,10,173,
-	254,255,9,21,4,0,8,37,0,4,8,60,
-	0,0,0,0,0,24,136,64,0,0,0,0,
-	2,131,29,60,0,220,189,39,0,0,30,36,
-	2,131,28,60,51,8,192,12,16,78,156,39,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	232,255,189,39,16,0,191,175,8,128,132,39,
-	15,63,192,12,0,0,0,0,16,0,191,143,
-	24,0,189,39,8,0,224,3,0,0,0,0,
-	232,255,189,39,16,0,191,175,12,128,132,39,
-	15,63,192,12,0,0,0,0,16,0,191,143,
-	24,0,189,39,8,0,224,3,0,0,0,0,
-	232,255,189,39,16,0,191,175,16,128,132,39,
-	15,63,192,12,0,0,0,0,16,0,191,143,
-	24,0,189,39,8,0,224,3,0,0,0,0,
-	232,255,189,39,16,0,191,175,20,128,132,39,
-	15,63,192,12,0,0,0,0,16,0,191,143,
-	24,0,189,39,8,0,224,3,0,0,0,0,
-	232,255,189,39,24,133,131,143,6,0,2,36,
-	20,0,191,175,6,0,98,20,16,0,176,175,
-	7,162,3,60,228,0,99,52,1,0,2,36,
-	184,7,192,8,0,0,98,172,0,128,130,151,
-	5,162,16,60,0,1,66,52,120,63,192,12,
-	0,0,2,166,0,128,130,151,0,0,0,0,
-	255,254,66,48,0,0,2,166,20,0,191,143,
-	16,0,176,143,8,0,224,3,24,0,189,39,
-	232,255,189,39,33,16,128,0,3,0,64,4,
-	16,0,191,175,254,255,2,60,192,29,66,52,
-	0,163,4,60,96,1,132,52,0,163,1,60,
-	92,1,34,172,0,163,1,60,104,1,38,172,
-	204,63,192,12,8,0,6,36,228,63,192,12,
-	255,255,4,36,204,7,192,8,0,0,0,0,
-	16,0,191,143,24,0,189,39,8,0,224,3,
-	0,0,0,0,216,255,189,39,1,0,6,36,
-	3,131,2,60,143,18,66,36,240,255,3,36,
-	36,16,67,0,0,163,1,60,120,1,34,172,
-	0,163,2,60,120,1,66,140,33,56,0,0,
-	32,0,191,175,28,0,177,175,24,0,176,175,
-	16,0,160,175,0,163,1,60,116,1,34,172,
-	0,163,3,60,112,1,99,140,0,163,2,60,
-	116,1,66,140,0,163,4,60,116,1,132,140,
-	35,136,98,0,84,64,192,12,33,40,32,2,
-	13,0,64,16,0,0,0,0,1,131,4,60,
-	96,127,132,36,24,128,144,39,33,40,0,2,
-	1,131,7,60,128,127,231,36,15,63,192,12,
-	148,0,6,36,1,0,4,36,33,40,0,2,
-	188,7,192,12,148,0,6,36,2,0,33,6,
-	33,16,32,2,3,0,34,38,131,136,2,0,
-	0,163,2,60,116,1,66,140,0,0,0,0,
-	6,0,32,18,237,254,3,60,175,222,99,52,
-	0,0,67,172,255,255,49,38,253,255,32,22,
-	4,0,66,36,32,0,191,143,28,0,177,143,
-	24,0,176,143,8,0,224,3,40,0,189,39,
-	224,255,189,39,15,0,132,36,240,255,3,36,
-	20,0,177,175,0,163,17,60,120,1,49,142,
-	0,163,2,60,120,1,66,140,36,32,131,0,
-	33,16,68,0,0,163,1,60,120,1,34,172,
-	0,163,3,60,120,1,99,140,0,163,2,60,
-	112,1,66,140,24,0,191,175,43,16,67,0,
-	13,0,64,16,16,0,176,175,1,131,4,60,
-	96,127,132,36,24,128,144,39,33,40,0,2,
-	1,131,7,60,176,127,231,36,15,63,192,12,
-	171,0,6,36,1,0,4,36,33,40,0,2,
-	188,7,192,12,171,0,6,36,33,16,32,2,
-	24,0,191,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,216,255,189,39,
-	3,0,2,60,7,162,3,60,36,0,191,175,
-	32,0,176,175,0,163,1,60,92,1,32,172,
-	0,0,99,140,79,17,66,52,32,0,98,20,
-	87,0,4,60,76,0,8,60,64,75,8,53,
-	250,2,7,60,128,240,231,52,7,162,6,60,
-	152,0,198,52,67,73,3,60,67,3,99,52,
-	7,162,4,60,48,1,132,52,7,162,5,60,
-	0,1,165,52,6,0,2,36,24,133,130,175,
-	0,163,1,60,204,5,34,172,4,0,2,36,
-	50,133,130,167,2,0,2,36,48,133,130,167,
-	1,0,2,36,20,133,130,167,119,119,2,36,
-	28,133,136,175,16,133,135,175,0,0,195,172,
-	0,0,130,172,67,1,2,36,0,0,162,172,
-	109,8,192,8,31,131,4,60,240,188,132,52,
-	189,2,3,60,128,231,99,52,4,0,2,36,
-	24,133,130,175,0,163,1,60,204,5,34,172,
-	0,8,2,36,50,133,130,167,0,4,2,36,
-	48,133,130,167,0,2,2,36,20,133,130,167,
-	28,133,132,175,16,133,131,175,31,131,4,60,
-	0,240,132,52,24,133,131,143,0,131,2,60,
-	0,163,1,60,108,1,34,172,0,163,1,60,
-	112,1,36,172,1,0,99,36,32,133,131,175,
-	210,7,192,12,0,0,0,0,0,163,2,60,
-	132,1,66,140,0,128,128,167,2,0,64,20,
-	85,0,2,36,0,128,130,167,0,163,2,60,
-	136,1,66,140,0,0,0,0,5,0,64,20,
-	0,0,0,0,0,128,130,151,0,0,0,0,
-	170,0,66,52,0,128,130,167,0,128,131,151,
-	5,162,2,60,0,0,67,164,188,64,192,12,
-	1,0,16,36,2,131,4,60,0,220,132,36,
-	2,131,5,60,0,224,165,36,2,131,6,60,
-	0,226,198,36,8,0,7,36,2,131,2,60,
-	112,154,66,36,16,0,162,175,2,131,2,60,
-	144,154,66,36,20,0,162,175,2,131,2,60,
-	176,154,66,36,24,0,162,175,0,131,2,60,
-	36,30,66,36,0,163,1,60,92,1,48,172,
-	240,64,192,12,28,0,162,175,0,163,3,60,
-	124,1,99,140,40,133,128,175,2,0,98,40,
-	7,0,64,16,2,0,2,36,18,0,97,4,
-	255,255,2,36,7,0,98,16,0,0,0,0,
-	196,8,192,8,0,0,0,0,16,0,98,16,
-	0,0,0,0,196,8,192,8,0,0,0,0,
-	24,133,133,143,1,131,4,60,15,63,192,12,
-	208,127,132,36,0,163,1,60,112,25,192,12,
-	124,1,32,172,207,8,192,8,0,0,0,0,
-	211,8,192,12,0,0,0,0,207,8,192,8,
-	0,0,0,0,40,133,144,175,31,10,192,12,
-	0,0,0,0,207,8,192,8,0,0,0,0,
-	1,131,4,60,96,127,132,36,24,128,144,39,
-	33,40,0,2,32,128,135,39,15,63,192,12,
-	58,1,6,36,1,0,4,36,33,40,0,2,
-	188,7,192,12,58,1,6,36,36,0,191,143,
-	32,0,176,143,8,0,224,3,40,0,189,39,
-	192,255,189,39,56,0,191,175,52,0,181,175,
-	48,0,180,175,44,0,179,175,40,0,178,175,
-	36,0,177,175,180,10,192,12,32,0,176,175,
-	33,32,0,0,2,0,2,36,0,163,1,60,
-	244,57,192,12,92,1,34,172,3,0,2,36,
-	0,163,1,60,0,12,192,12,92,1,34,172,
-	1,0,4,36,4,0,2,36,0,163,1,60,
-	34,11,192,12,92,1,34,172,5,0,2,36,
-	0,163,1,60,92,1,34,172,0,163,19,60,
-	124,1,115,142,0,163,3,60,160,1,99,140,
-	1,0,98,46,80,133,130,175,0,128,2,60,
-	5,0,98,20,0,0,0,0,32,133,130,143,
-	0,0,0,0,252,8,192,8,255,255,66,36,
-	32,133,130,143,0,0,0,0,84,133,130,175,
-	130,11,192,12,0,0,0,0,33,32,64,0,
-	2,0,5,36,232,3,6,36,0,131,7,60,
-	196,37,231,36,156,11,192,12,16,0,160,175,
-	35,35,192,12,0,0,0,0,6,0,2,36,
-	0,163,1,60,84,35,192,12,92,1,34,172,
-	7,0,2,36,0,163,1,60,141,47,192,12,
-	92,1,34,172,8,0,2,36,0,163,1,60,
-	120,50,192,12,92,1,34,172,9,0,2,36,
-	0,163,1,60,92,1,34,172,0,163,2,60,
-	240,5,66,140,0,0,0,0,8,0,64,16,
-	10,0,2,36,0,163,4,60,240,5,132,140,
-	13,8,192,12,0,0,0,0,0,163,1,60,
-	244,5,34,172,10,0,2,36,0,163,1,60,
-	92,1,34,172,157,15,192,12,1,0,21,36,
-	2,131,2,60,192,246,66,36,33,160,64,0,
-	80,133,131,143,11,0,2,36,0,163,1,60,
-	92,1,34,172,100,0,2,36,0,163,1,60,
-	92,1,34,172,84,133,130,143,64,26,3,0,
-	33,136,116,0,64,18,2,0,33,144,84,0,
-	0,163,2,60,8,1,66,140,0,0,0,0,
-	1,0,66,36,0,163,1,60,8,1,34,172,
-	0,163,2,60,8,1,66,140,0,163,2,60,
-	124,1,66,140,0,0,0,0,14,0,83,16,
-	0,0,0,0,4,0,64,16,33,152,64,0,
-	80,133,128,175,76,9,192,8,0,0,0,0,
-	80,133,149,175,2,131,4,60,163,23,192,12,
-	192,246,132,36,80,133,130,143,0,0,0,0,
-	64,18,2,0,33,136,84,0,0,163,2,60,
-	0,6,66,140,0,0,0,0,3,0,64,24,
-	33,128,32,2,239,15,192,12,0,0,0,0,
-	43,16,18,2,11,0,64,16,33,32,0,2,
-	151,18,192,12,10,0,5,36,27,22,192,12,
-	33,32,0,2,142,22,192,12,33,32,0,2,
-	0,2,16,38,43,16,18,2,247,255,64,20,
-	33,32,0,2,184,11,192,12,0,0,0,0,
-	54,9,192,8,0,0,0,0,56,0,191,143,
-	52,0,181,143,48,0,180,143,44,0,179,143,
-	40,0,178,143,36,0,177,143,32,0,176,143,
-	8,0,224,3,64,0,189,39,4,128,130,143,
-	232,255,189,39,20,0,191,175,16,0,176,175,
-	1,0,67,36,4,128,131,175,255,255,3,36,
-	4,0,67,20,255,31,4,60,0,163,1,60,
-	8,1,32,172,255,31,4,60,255,255,132,52,
-	0,163,16,60,0,163,2,60,8,1,66,140,
-	208,132,131,143,220,5,16,54,35,16,67,0,
-	0,163,1,60,16,1,34,172,2,131,2,60,
-	192,246,66,36,36,16,68,0,0,160,3,60,
-	37,16,67,0,0,163,3,60,8,1,99,140,
-	28,0,68,140,0,0,5,142,3,131,2,60,
-	20,18,66,140,208,132,131,175,36,133,132,175,
-	18,0,162,16,0,163,4,60,99,59,192,12,
-	220,5,132,52,255,0,5,60,255,0,165,52,
-	0,255,6,60,0,0,4,142,0,255,198,52,
-	0,20,4,0,2,28,4,0,37,16,67,0,
-	2,26,2,0,36,24,101,0,0,18,2,0,
-	36,16,70,0,37,24,98,0,176,133,132,175,
-	184,133,131,175,0,163,16,60,16,6,16,54,
-	0,0,3,142,3,131,2,60,68,18,66,140,
-	0,0,0,0,18,0,98,16,0,163,4,60,
-	119,59,192,12,16,6,132,52,255,0,5,60,
-	255,0,165,52,0,255,6,60,0,0,4,142,
-	0,255,198,52,0,20,4,0,2,28,4,0,
-	37,16,67,0,2,26,2,0,36,24,101,0,
-	0,18,2,0,36,16,70,0,37,24,98,0,
-	196,133,132,175,192,133,131,175,0,163,16,60,
-	224,5,16,54,0,0,3,142,3,131,2,60,
-	24,18,66,140,0,0,0,0,18,0,98,16,
-	0,163,4,60,139,59,192,12,224,5,132,52,
-	255,0,5,60,255,0,165,52,0,255,6,60,
-	0,0,4,142,0,255,198,52,0,20,4,0,
-	2,28,4,0,37,16,67,0,2,26,2,0,
-	36,24,101,0,0,18,2,0,36,16,70,0,
-	37,24,98,0,188,133,132,175,180,133,131,175,
-	44,133,131,143,0,163,2,60,144,1,66,140,
-	0,0,0,0,5,0,98,16,0,0,0,0,
-	0,163,4,60,144,1,132,140,159,59,192,12,
-	0,0,0,0,0,163,3,60,140,1,99,140,
-	3,131,2,60,64,18,66,140,0,0,0,0,
-	5,0,98,16,0,0,0,0,0,163,4,60,
-	140,1,132,140,51,60,192,12,0,0,0,0,
-	44,133,130,143,0,0,0,0,3,0,64,16,
-	0,0,0,0,116,38,192,12,0,0,0,0,
-	164,7,192,12,0,0,0,0,36,128,130,143,
-	0,0,0,0,1,0,66,36,36,128,130,175,
-	60,0,66,40,8,0,64,20,0,0,0,0,
-	3,131,2,60,24,18,66,140,36,128,128,175,
-	3,0,64,16,0,0,0,0,222,48,192,12,
-	0,0,0,0,0,163,2,60,48,1,66,140,
-	0,0,0,0,20,0,64,16,0,0,0,0,
-	0,163,1,60,48,1,32,172,0,163,1,60,
-	16,1,32,172,0,163,1,60,20,1,32,172,
-	0,163,1,60,24,1,32,172,0,163,1,60,
-	28,1,32,172,0,163,1,60,32,1,32,172,
-	0,163,1,60,36,1,32,172,0,163,1,60,
-	40,1,32,172,0,163,1,60,201,13,192,12,
-	44,1,32,172,20,0,191,143,16,0,176,143,
-	8,0,224,3,24,0,189,39,216,255,189,39,
-	36,0,191,175,32,0,178,175,28,0,177,175,
-	180,10,192,12,24,0,176,175,33,32,0,0,
-	2,0,2,36,0,163,1,60,244,57,192,12,
-	92,1,34,172,3,0,2,36,0,163,1,60,
-	0,12,192,12,92,1,34,172,1,0,4,36,
-	4,0,2,36,0,163,1,60,34,11,192,12,
-	92,1,34,172,32,133,131,143,5,0,2,36,
-	0,163,1,60,92,1,34,172,80,133,128,175,
-	84,133,131,175,130,11,192,12,0,0,0,0,
-	33,32,64,0,2,0,5,36,232,3,6,36,
-	0,131,7,60,196,37,231,36,156,11,192,12,
-	16,0,160,175,0,163,2,60,240,5,66,140,
-	0,0,0,0,8,0,64,16,10,0,2,36,
-	0,163,4,60,240,5,132,140,13,8,192,12,
-	0,0,0,0,0,163,1,60,244,5,34,172,
-	10,0,2,36,0,163,1,60,92,1,34,172,
-	100,0,2,36,80,133,131,143,2,131,4,60,
-	192,246,132,36,0,163,1,60,92,1,34,172,
-	84,133,130,143,64,26,3,0,33,144,100,0,
-	64,18,2,0,33,136,68,0,0,163,2,60,
-	8,1,66,140,33,128,64,2,1,0,66,36,
-	0,163,1,60,8,1,34,172,0,163,2,60,
-	8,1,66,140,43,16,17,2,11,0,64,16,
-	33,32,0,2,151,18,192,12,10,0,5,36,
-	27,22,192,12,33,32,0,2,142,22,192,12,
-	33,32,0,2,0,2,16,38,43,16,17,2,
-	247,255,64,20,33,32,0,2,184,11,192,12,
-	0,0,0,0,91,10,192,8,0,0,0,0,
-	36,0,191,143,32,0,178,143,28,0,177,143,
-	24,0,176,143,8,0,224,3,40,0,189,39,
-	4,128,130,143,232,255,189,39,16,0,191,175,
-	1,0,67,36,4,128,131,175,255,255,3,36,
-	4,0,67,20,255,31,4,60,0,163,1,60,
-	8,1,32,172,255,31,4,60,0,163,2,60,
-	8,1,66,140,212,132,131,143,255,255,132,52,
-	35,16,67,0,0,163,1,60,16,1,34,172,
-	2,131,2,60,192,246,66,36,36,16,68,0,
-	0,160,3,60,37,16,67,0,0,163,3,60,
-	8,1,99,140,28,0,66,140,212,132,131,175,
-	36,133,130,175,164,7,192,12,0,0,0,0,
-	0,163,2,60,48,1,66,140,0,0,0,0,
-	20,0,64,16,0,0,0,0,0,163,1,60,
-	48,1,32,172,0,163,1,60,16,1,32,172,
-	0,163,1,60,20,1,32,172,0,163,1,60,
-	24,1,32,172,0,163,1,60,28,1,32,172,
-	0,163,1,60,32,1,32,172,0,163,1,60,
-	36,1,32,172,0,163,1,60,40,1,32,172,
-	0,163,1,60,201,13,192,12,44,1,32,172,
-	16,0,191,143,24,0,189,39,8,0,224,3,
-	0,0,0,0,224,255,189,39,24,0,191,175,
-	20,0,177,175,120,63,192,12,16,0,176,175,
-	52,0,2,36,4,162,1,60,12,0,34,160,
-	120,63,192,12,232,3,16,36,28,133,130,143,
-	0,0,0,0,27,0,80,0,2,0,0,22,
-	0,0,0,0,13,0,7,0,18,16,0,0,
-	4,162,17,60,120,63,192,12,0,0,34,162,
-	28,133,130,143,0,0,0,0,27,0,80,0,
-	2,0,0,22,0,0,0,0,13,0,7,0,
-	18,16,0,0,33,40,0,0,33,32,0,0,
-	6,162,3,60,2,18,2,0,0,0,34,162,
-	1,0,2,36,0,163,1,60,4,1,32,172,
-	0,0,98,172,2,131,1,60,33,8,36,0,
-	8,245,32,172,1,0,165,36,22,0,162,44,
-	250,255,64,20,20,0,132,36,31,131,4,60,
-	0,240,132,52,52,128,131,143,1,0,2,36,
-	68,133,128,175,48,128,130,175,64,133,128,175,
-	32,131,1,60,252,239,36,172,8,0,96,16,
-	31,131,5,60,252,239,165,52,31,131,6,60,
-	1,131,4,60,224,127,132,36,15,63,192,12,
-	0,240,198,52,52,128,128,175,24,0,191,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,232,255,189,39,16,0,176,175,
-	116,0,2,36,20,0,191,175,4,162,1,60,
-	12,0,34,160,130,63,192,12,33,128,128,0,
-	4,162,1,60,4,0,48,160,130,63,192,12,
-	3,130,16,0,4,162,1,60,130,63,192,12,
-	4,0,48,160,20,0,191,143,16,0,176,143,
-	8,0,224,3,24,0,189,39,224,255,189,39,
-	64,0,2,36,24,0,191,175,20,0,177,175,
-	16,0,176,175,4,162,1,60,130,63,192,12,
-	12,0,34,160,4,162,17,60,4,0,49,146,
-	0,0,0,0,130,63,192,12,255,0,49,50,
-	4,162,16,60,4,0,16,146,0,0,0,0,
-	130,63,192,12,255,0,16,50,0,130,16,0,
-	37,16,17,2,24,0,191,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,32,0,189,39,
-	48,128,130,143,232,255,189,39,16,0,176,175,
-	33,128,128,0,3,0,64,20,20,0,191,175,
-	180,10,192,12,0,0,0,0,5,0,0,18,
-	0,0,0,0,236,63,192,12,1,4,4,36,
-	50,11,192,8,0,0,0,0,228,63,192,12,
-	0,4,4,36,20,0,191,143,16,0,176,143,
-	8,0,224,3,24,0,189,39,216,255,189,39,
-	6,162,3,60,1,0,2,36,32,0,191,175,
-	28,0,177,175,24,0,176,175,0,0,98,172,
-	0,163,2,60,4,1,66,140,33,136,224,0,
-	1,0,66,36,0,163,1,60,4,1,34,172,
-	56,128,130,143,0,163,3,60,4,1,99,140,
-	1,0,66,36,56,128,130,175,232,3,66,40,
-	21,0,64,20,255,127,3,60,68,133,130,143,
-	254,255,99,52,56,128,128,175,1,0,66,36,
-	43,24,98,0,68,133,130,175,13,0,96,16,
-	0,0,0,0,2,131,4,60,28,128,132,36,
-	60,128,144,39,33,40,0,2,2,131,7,60,
-	60,128,231,36,15,63,192,12,144,0,6,36,
-	1,0,4,36,33,40,0,2,188,7,192,12,
-	144,0,6,36,64,133,134,143,0,0,0,0,
-	14,0,192,24,33,24,0,0,2,131,5,60,
-	0,245,165,36,33,32,0,0,2,131,2,60,
-	33,16,68,0,0,245,66,140,20,0,132,36,
-	1,0,99,36,255,255,66,36,0,0,162,172,
-	42,16,102,0,247,255,64,20,20,0,165,36,
-	31,131,4,60,252,239,132,52,31,131,2,60,
-	0,0,131,140,255,255,66,52,0,0,113,172,
-	4,0,99,36,43,16,67,0,3,0,64,16,
-	0,0,0,0,31,131,3,60,0,240,99,52,
-	0,0,131,172,32,0,191,143,28,0,177,143,
-	24,0,176,143,8,0,224,3,40,0,189,39,
-	64,133,130,143,232,255,189,39,20,0,191,175,
-	22,0,66,40,13,0,64,20,16,0,176,175,
-	2,131,4,60,28,128,132,36,60,128,144,39,
-	33,40,0,2,2,131,7,60,84,128,231,36,
-	15,63,192,12,173,0,6,36,1,0,4,36,
-	33,40,0,2,188,7,192,12,173,0,6,36,
-	64,133,130,143,0,0,0,0,1,0,67,36,
-	64,133,131,175,20,0,191,143,16,0,176,143,
-	8,0,224,3,24,0,189,39,128,16,4,0,
-	33,16,68,0,16,0,163,143,128,16,2,0,
-	2,131,1,60,33,8,34,0,4,245,38,172,
-	2,131,1,60,33,8,34,0,12,245,39,172,
-	2,131,1,60,33,8,34,0,0,245,38,172,
-	2,131,1,60,33,8,34,0,8,245,37,172,
-	2,131,1,60,33,8,34,0,16,245,35,172,
-	8,0,224,3,33,16,0,1,128,16,4,0,
-	33,16,68,0,128,16,2,0,2,131,1,60,
-	33,8,34,0,8,0,224,3,8,245,32,172,
-	64,133,130,143,192,255,189,39,40,0,180,175,
-	33,160,0,0,56,0,191,175,52,0,183,175,
-	48,0,182,175,44,0,181,175,36,0,179,175,
-	32,0,178,175,28,0,177,175,48,0,64,24,
-	24,0,176,175,1,0,23,36,2,0,22,36,
-	2,131,16,60,12,245,16,38,4,0,19,38,
-	244,255,17,38,252,255,18,38,33,168,0,0,
-	0,0,67,142,0,0,0,0,7,0,119,16,
-	2,0,98,40,25,0,64,20,0,0,0,0,
-	9,0,118,16,0,0,0,0,236,11,192,8,
-	20,0,16,38,0,0,34,142,0,0,0,0,
-	17,0,64,28,0,0,0,0,230,11,192,8,
-	0,0,64,174,0,0,34,142,0,0,0,0,
-	11,0,64,28,0,0,0,0,2,131,2,60,
-	33,16,85,0,4,245,66,140,0,0,0,0,
-	0,0,34,174,0,0,100,142,0,0,2,142,
-	0,0,0,0,9,248,64,0,0,0,0,0,
-	20,0,16,38,20,0,115,38,20,0,49,38,
-	20,0,82,38,64,133,130,143,1,0,148,38,
-	42,16,130,2,218,255,64,20,20,0,181,38,
-	56,0,191,143,52,0,183,143,48,0,182,143,
-	44,0,181,143,40,0,180,143,36,0,179,143,
-	32,0,178,143,28,0,177,143,24,0,176,143,
-	8,0,224,3,64,0,189,39,0,0,0,0,
-	2,131,3,60,192,246,99,36,0,2,2,36,
-	0,163,1,60,200,5,35,172,0,163,1,60,
-	208,5,34,172,0,163,2,60,124,1,66,140,
-	216,255,189,39,16,0,176,175,33,128,0,0,
-	28,0,179,175,255,255,19,36,24,0,178,175,
-	21,0,114,36,20,0,177,175,32,0,191,175,
-	1,0,66,44,80,133,130,175,139,14,192,12,
-	20,0,113,36,184,24,192,12,0,0,0,0,
-	27,67,192,12,33,32,0,2,6,0,83,20,
-	1,0,16,38,2,131,4,60,15,63,192,12,
-	112,128,132,36,126,12,192,8,1,0,2,36,
-	0,0,34,162,3,18,2,0,0,0,66,162,
-	2,0,82,38,3,0,2,42,241,255,64,20,
-	2,0,49,38,2,131,17,60,212,246,49,38,
-	33,32,32,2,33,40,0,0,255,127,6,60,
-	247,24,192,12,255,255,198,52,255,31,3,60,
-	255,255,99,52,236,255,48,38,36,0,34,38,
-	36,16,67,0,0,160,3,60,37,16,67,0,
-	0,32,3,36,236,255,32,174,2,131,1,60,
-	220,246,32,172,2,131,1,60,204,246,32,172,
-	2,131,1,60,236,246,34,172,0,0,67,164,
-	222,21,192,12,33,32,0,2,122,15,192,12,
-	33,32,0,2,242,21,192,12,33,32,0,2,
-	32,133,130,143,1,0,16,36,42,16,2,2,
-	12,0,64,16,255,31,3,60,236,1,49,38,
-	133,12,192,12,33,32,0,2,242,21,192,12,
-	33,32,32,2,32,133,130,143,1,0,16,38,
-	42,16,2,2,248,255,64,20,0,2,49,38,
-	255,31,3,60,255,255,99,52,2,131,16,60,
-	192,4,16,38,7,0,2,36,0,0,2,174,
-	56,0,2,38,36,16,67,0,0,160,3,60,
-	37,16,67,0,0,32,3,36,2,131,1,60,
-	220,4,32,172,2,131,1,60,204,4,32,172,
-	2,131,1,60,236,4,34,172,0,0,67,164,
-	2,131,2,60,212,246,66,140,2,131,3,60,
-	216,246,99,132,20,0,2,174,24,0,3,166,
-	2,131,2,60,217,4,66,144,0,0,0,0,
-	7,0,66,36,2,131,1,60,217,4,34,160,
-	112,15,192,12,33,32,0,2,33,32,0,2,
-	19,15,192,12,32,0,5,36,20,0,16,38,
-	33,32,0,2,7,0,5,36,255,127,6,60,
-	247,24,192,12,255,255,198,52,33,16,0,0,
-	32,0,191,143,28,0,179,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	40,0,189,39,200,255,189,39,48,0,180,175,
-	33,160,128,0,255,31,6,60,255,255,198,52,
-	64,26,20,0,2,131,2,60,192,246,66,36,
-	40,0,178,175,33,144,98,0,255,255,132,38,
-	64,18,4,0,0,162,3,60,33,16,67,0,
-	52,0,191,175,44,0,179,175,36,0,177,175,
-	32,0,176,175,4,0,66,174,0,1,66,36,
-	8,0,66,174,0,16,2,36,4,16,130,0,
-	12,0,66,174,4,0,2,36,4,16,130,0,
-	0,160,5,60,16,0,66,174,48,0,66,38,
-	36,16,70,0,37,16,69,0,36,0,66,174,
-	64,16,4,0,33,16,68,0,128,16,2,0,
-	2,131,3,60,240,231,99,36,33,16,67,0,
-	36,16,70,0,37,16,69,0,40,0,66,174,
-	56,0,66,38,36,16,70,0,37,16,69,0,
-	0,0,84,174,44,0,66,174,32,0,64,174,
-	2,131,2,60,212,246,66,140,2,131,3,60,
-	216,246,99,132,20,0,66,174,24,0,67,166,
-	25,0,66,146,0,0,0,0,33,32,84,0,
-	2,131,2,60,0,227,66,36,36,16,70,0,
-	37,128,69,0,2,131,2,60,32,227,66,36,
-	36,16,70,0,25,0,68,162,40,133,131,143,
-	0,0,0,0,3,0,96,16,37,136,69,0,
-	255,255,130,36,25,0,66,162,12,0,68,142,
-	28,0,64,174,228,63,192,12,1,0,132,52,
-	4,0,68,142,0,0,0,0,76,67,192,12,
-	33,40,0,0,76,63,192,12,0,0,0,0,
-	76,63,192,12,0,0,0,0,255,255,2,36,
-	4,0,2,174,4,0,2,142,0,0,0,0,
-	0,0,2,174,4,0,68,142,0,0,0,0,
-	76,67,192,12,1,0,5,54,4,0,4,38,
-	33,40,0,0,255,255,6,36,211,67,192,12,
-	208,7,7,36,8,0,64,20,255,255,2,52,
-	2,131,4,60,184,128,132,36,4,0,6,142,
-	0,0,0,0,15,63,192,12,33,40,128,2,
-	255,255,2,52,48,1,34,174,4,0,68,142,
-	0,0,0,0,76,67,192,12,3,0,37,54,
-	48,1,36,38,33,40,0,0,255,255,6,52,
-	211,67,192,12,208,7,7,36,7,0,64,20,
-	0,0,0,0,2,131,4,60,8,129,132,36,
-	48,1,38,142,0,0,0,0,15,63,192,12,
-	33,40,128,2,143,63,192,12,0,0,0,0,
-	40,0,69,142,4,0,68,142,0,0,0,0,
-	76,67,192,12,2,0,165,52,44,0,81,142,
-	84,128,131,143,80,128,132,143,100,0,2,36,
-	0,0,32,166,2,0,32,166,4,0,32,174,
-	8,0,32,174,12,0,32,174,16,0,32,174,
-	24,0,32,174,20,0,32,174,28,0,32,174,
-	32,0,32,174,36,0,34,166,38,0,34,166,
-	36,0,35,166,38,0,36,166,36,0,83,142,
-	1,0,2,36,0,0,98,174,44,0,66,142,
-	0,0,0,0,4,0,98,174,40,0,67,142,
-	116,0,2,60,0,0,98,172,40,0,67,142,
-	36,0,66,142,0,0,0,0,8,0,98,172,
-	8,0,66,142,0,0,0,0,0,0,64,172,
-	0,0,98,142,0,0,0,0,10,0,64,16,
-	33,128,0,0,208,7,2,42,7,0,64,16,
-	0,0,0,0,143,63,192,12,0,0,0,0,
-	0,0,98,142,0,0,0,0,248,255,64,20,
-	1,0,16,38,0,0,98,142,0,0,0,0,
-	6,0,64,16,33,32,32,2,2,131,4,60,
-	76,129,132,36,15,63,192,12,33,40,128,2,
-	33,32,32,2,8,0,5,36,0,0,34,150,
-	8,0,6,36,0,240,66,48,0,6,66,52,
-	2,0,34,166,8,0,66,142,208,7,7,36,
-	129,67,192,12,0,0,64,172,6,0,64,20,
-	2,0,36,38,2,131,4,60,160,129,132,36,
-	15,63,192,12,33,40,128,2,2,0,36,38,
-	33,40,0,0,0,0,34,150,33,48,0,0,
-	0,240,66,48,2,0,34,166,8,0,66,142,
-	208,7,7,36,129,67,192,12,0,0,64,172,
-	4,0,64,20,0,0,0,0,2,131,4,60,
-	15,63,192,12,248,129,132,36,143,63,192,12,
-	0,0,0,0,108,0,80,142,0,128,2,52,
-	0,0,0,166,2,0,2,166,44,0,66,142,
-	0,32,5,36,4,0,80,172,44,0,67,142,
-	0,241,2,52,2,0,98,164,8,0,66,142,
-	0,32,6,36,0,0,64,172,44,0,68,142,
-	0,0,0,0,129,67,192,12,208,7,7,36,
-	12,0,64,20,0,0,0,0,44,0,66,142,
-	0,0,0,0,0,0,69,148,2,131,4,60,
-	15,63,192,12,16,130,132,36,254,255,4,36,
-	2,131,5,60,44,130,165,36,188,7,192,12,
-	1,1,6,36,108,0,80,142,2,128,2,52,
-	0,0,0,166,2,0,2,166,14,0,2,36,
-	8,0,2,162,200,0,2,36,9,0,2,162,
-	65,0,2,36,10,0,2,162,46,0,2,36,
-	11,0,2,162,87,0,2,36,12,0,0,162,
-	13,0,2,162,242,0,2,36,14,0,0,162,
-	15,0,2,162,1,0,2,36,16,0,2,162,
-	8,0,2,36,17,0,2,162,88,128,130,143,
-	0,0,0,0,6,0,64,16,64,0,2,36,
-	2,131,4,60,15,63,192,12,56,130,132,36,
-	88,128,128,175,64,0,2,36,18,0,2,162,
-	255,0,2,36,19,0,2,162,63,0,2,36,
-	20,0,0,162,21,0,2,162,44,0,66,142,
-	0,32,5,36,4,0,80,172,44,0,67,142,
-	0,33,2,36,2,0,98,164,8,0,66,142,
-	0,32,6,36,0,0,64,172,44,0,68,142,
-	0,0,0,0,129,67,192,12,208,7,7,36,
-	12,0,64,20,0,0,0,0,44,0,66,142,
-	0,0,0,0,0,0,69,148,2,131,4,60,
-	15,63,192,12,16,130,132,36,253,255,4,36,
-	2,131,5,60,44,130,165,36,188,7,192,12,
-	85,1,6,36,222,21,192,12,33,32,64,2,
-	122,15,192,12,33,32,64,2,52,0,191,143,
-	48,0,180,143,44,0,179,143,40,0,178,143,
-	36,0,177,143,32,0,176,143,8,0,224,3,
-	56,0,189,39,248,255,189,39,32,133,133,143,
-	0,0,0,0,50,0,160,24,33,32,0,0,
-	2,131,3,60,192,246,99,36,44,0,98,140,
-	152,0,96,172,156,0,96,172,160,0,96,172,
-	164,0,96,172,168,0,96,172,172,0,96,172,
-	176,0,96,172,180,0,96,172,184,0,96,172,
-	188,0,96,172,192,0,96,172,196,0,96,172,
-	200,0,96,172,204,0,96,172,208,0,96,172,
-	212,0,96,172,216,0,96,172,224,0,96,172,
-	232,0,96,172,236,0,96,172,240,0,96,172,
-	244,0,96,172,248,0,96,172,252,0,96,172,
-	0,1,96,172,4,1,96,172,8,1,96,172,
-	12,0,64,172,44,0,98,140,0,0,0,0,
-	16,0,64,172,44,0,98,140,0,0,0,0,
-	24,0,64,172,44,0,98,140,0,0,0,0,
-	20,0,64,172,44,0,98,140,1,0,132,36,
-	28,0,64,172,44,0,98,140,0,2,99,36,
-	32,0,64,172,42,16,133,0,210,255,64,20,
-	0,0,0,0,33,32,0,0,0,163,3,60,
-	0,1,99,52,32,0,5,36,33,16,131,0,
-	188,0,69,160,1,0,132,36,0,2,130,44,
-	251,255,64,20,0,0,0,0,8,0,224,3,
-	8,0,189,39,0,0,0,0,124,133,130,143,
-	232,255,189,39,20,0,191,175,17,0,64,20,
-	16,0,176,175,208,7,16,36,7,0,0,26,
-	0,0,0,0,143,63,192,12,255,255,16,38,
-	124,133,130,143,0,0,0,0,249,255,64,16,
-	0,0,0,0,6,0,0,22,0,0,0,0,
-	2,131,4,60,15,63,192,12,80,130,132,36,
-	45,14,192,8,33,16,0,0,220,63,192,12,
-	33,32,0,0,33,32,64,0,124,133,144,143,
-	128,133,130,143,4,0,3,142,255,255,66,36,
-	128,133,130,175,124,133,131,175,220,63,192,12,
-	0,0,0,0,33,16,0,2,20,0,191,143,
-	16,0,176,143,8,0,224,3,24,0,189,39,
-	232,255,189,39,96,133,130,143,33,40,128,0,
-	43,16,162,0,6,0,64,20,16,0,191,175,
-	100,133,130,143,0,0,0,0,43,16,162,0,
-	6,0,64,20,0,0,0,0,2,131,4,60,
-	15,63,192,12,116,130,132,36,71,14,192,8,
-	0,0,0,0,124,133,131,143,128,133,130,143,
-	124,133,133,175,1,0,66,36,4,0,163,172,
-	128,133,130,175,16,0,191,143,24,0,189,39,
-	8,0,224,3,0,0,0,0,108,133,130,143,
-	232,255,189,39,20,0,191,175,17,0,64,20,
-	16,0,176,175,208,7,16,36,7,0,0,26,
-	0,0,0,0,143,63,192,12,255,255,16,38,
-	108,133,130,143,0,0,0,0,249,255,64,16,
-	0,0,0,0,6,0,0,22,0,0,0,0,
-	2,131,4,60,15,63,192,12,148,130,132,36,
-	108,14,192,8,33,16,0,0,220,63,192,12,
-	33,32,0,0,33,32,64,0,108,133,144,143,
-	120,133,130,143,0,0,3,142,255,255,66,36,
-	120,133,130,175,108,133,131,175,220,63,192,12,
-	0,0,0,0,33,16,0,2,20,0,191,143,
-	16,0,176,143,8,0,224,3,24,0,189,39,
-	232,255,189,39,104,133,130,143,33,40,128,0,
-	43,16,162,0,6,0,64,20,16,0,191,175,
-	112,133,130,143,0,0,0,0,43,16,162,0,
-	6,0,64,20,0,0,0,0,2,131,4,60,
-	15,63,192,12,184,130,132,36,135,14,192,8,
-	0,0,0,0,108,133,130,143,0,0,0,0,
-	0,0,162,172,120,133,130,143,108,133,133,175,
-	1,0,66,36,120,133,130,175,16,0,191,143,
-	24,0,189,39,8,0,224,3,0,0,0,0,
-	232,255,189,39,20,0,191,175,16,0,176,175,
-	124,133,128,175,13,8,192,12,0,32,4,36,
-	255,31,3,60,255,255,99,52,255,1,16,36,
-	36,16,67,0,0,160,3,60,37,16,67,0,
-	96,133,130,175,0,32,66,36,100,133,130,175,
-	0,17,16,0,96,133,132,143,255,255,16,38,
-	49,14,192,12,33,32,130,0,251,255,1,6,
-	0,17,16,0,0,2,2,36,132,133,130,175,
-	108,133,128,175,13,8,192,12,18,0,4,60,
-	255,31,3,60,255,255,99,52,255,17,16,36,
-	36,16,67,0,0,160,3,60,37,16,67,0,
-	18,0,3,60,104,133,130,175,33,16,67,0,
-	112,133,130,175,0,18,16,0,104,133,132,143,
-	255,255,16,38,112,14,192,12,33,32,130,0,
-	251,255,1,6,0,18,16,0,0,18,2,36,
-	116,133,130,175,20,0,191,143,16,0,176,143,
-	8,0,224,3,24,0,189,39,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,163,2,60,
-	168,1,66,140,216,255,189,39,28,0,177,175,
-	33,136,128,0,32,0,178,175,33,144,160,0,
-	36,0,191,175,17,0,64,16,24,0,176,175,
-	0,163,2,60,168,1,66,140,0,0,0,0,
-	42,16,82,0,12,0,64,16,128,128,18,0,
-	0,0,34,142,0,163,18,60,168,1,82,142,
-	0,0,0,0,6,0,64,20,128,128,18,0,
-	2,131,4,60,224,130,132,36,15,63,192,12,
-	33,40,64,2,128,128,18,0,33,128,18,2,
-	128,128,16,0,13,8,192,12,33,32,0,2,
-	255,31,3,60,255,255,99,52,33,32,0,0,
-	36,16,67,0,0,160,3,60,37,16,67,0,
-	112,0,34,174,112,0,35,142,33,16,80,0,
-	15,0,64,26,116,0,34,174,8,0,5,36,
-	1,0,132,36,20,0,98,36,4,0,98,172,
-	2,0,101,164,0,0,96,164,8,0,96,172,
-	14,0,96,164,12,0,96,164,33,24,64,0,
-	42,16,146,0,246,255,64,20,1,0,132,36,
-	255,255,132,36,116,0,35,142,112,0,34,142,
-	0,0,0,0,240,255,98,172,116,0,35,142,
-	0,0,0,0,218,255,98,148,0,0,0,0,
-	0,128,66,52,218,255,98,164,116,0,35,142,
-	0,0,0,0,238,255,98,148,0,0,0,0,
-	0,128,66,52,238,255,98,164,116,0,34,142,
-	112,0,35,142,216,255,66,36,120,0,35,174,
-	124,0,34,174,36,0,191,143,32,0,178,143,
-	28,0,177,143,24,0,176,143,8,0,224,3,
-	40,0,189,39,200,255,189,39,32,0,178,175,
-	33,144,128,0,0,1,2,36,48,0,191,175,
-	44,0,181,175,40,0,180,175,36,0,179,175,
-	28,0,177,175,24,0,176,175,144,0,66,174,
-	0,163,2,60,172,1,66,140,0,0,0,0,
-	17,0,64,16,33,160,160,0,0,163,2,60,
-	172,1,66,140,0,0,0,0,42,16,84,0,
-	12,0,64,16,128,128,20,0,0,0,66,142,
-	0,163,20,60,172,1,148,142,0,0,0,0,
-	6,0,64,20,128,128,20,0,2,131,4,60,
-	236,130,132,36,15,63,192,12,33,40,128,2,
-	128,128,20,0,33,128,20,2,128,128,16,0,
-	33,32,0,2,13,8,192,12,148,0,84,174,
-	255,31,3,60,255,255,99,52,33,152,0,0,
-	36,16,67,0,0,160,3,60,37,16,67,0,
-	128,0,66,174,128,0,81,142,33,16,80,0,
-	15,0,128,26,132,0,66,174,0,1,21,36,
-	20,0,48,38,4,0,48,174,75,14,192,12,
-	0,0,32,174,8,0,34,174,12,0,53,174,
-	0,0,66,142,1,0,115,38,16,0,34,162,
-	17,0,32,162,42,16,116,2,244,255,64,20,
-	33,136,0,2,132,0,67,142,128,0,66,142,
-	0,0,0,0,240,255,98,172,132,0,67,142,
-	0,0,0,0,228,255,98,140,0,0,0,0,
-	0,128,66,52,228,255,98,172,132,0,67,142,
-	0,0,0,0,248,255,98,140,0,0,0,0,
-	0,128,66,52,248,255,98,172,132,0,66,142,
-	128,0,67,142,216,255,66,36,136,0,67,174,
-	140,0,66,174,48,0,191,143,44,0,181,143,
-	40,0,180,143,36,0,179,143,32,0,178,143,
-	28,0,177,143,24,0,176,143,8,0,224,3,
-	56,0,189,39,152,0,128,172,156,0,128,172,
-	160,0,128,172,164,0,128,172,168,0,128,172,
-	252,0,128,172,0,1,128,172,152,0,128,172,
-	8,0,224,3,216,0,128,172,232,255,189,39,
-	16,0,176,175,20,0,191,175,112,15,192,12,
-	33,128,128,0,33,32,0,2,192,14,192,12,
-	0,4,5,36,33,32,0,2,19,15,192,12,
-	128,2,5,36,120,0,3,142,136,0,2,142,
-	0,0,0,0,8,0,98,172,44,0,3,142,
-	120,0,2,142,0,0,0,0,8,0,98,172,
-	0,0,2,142,0,0,0,0,255,255,66,36,
-	6,0,66,44,7,0,64,16,16,0,3,36,
-	44,0,2,142,0,0,0,0,2,0,67,164,
-	8,0,2,142,0,0,0,0,0,0,64,172,
-	20,0,191,143,16,0,176,143,8,0,224,3,
-	24,0,189,39,184,255,189,39,0,32,6,36,
-	68,0,191,175,64,0,190,175,60,0,183,175,
-	56,0,182,175,52,0,181,175,48,0,180,175,
-	44,0,179,175,40,0,178,175,36,0,177,175,
-	32,0,176,175,0,163,1,60,252,5,38,172,
-	13,8,192,12,0,32,4,36,255,31,4,60,
-	255,255,132,52,33,168,0,0,255,31,6,60,
-	255,255,198,52,2,131,3,60,212,247,99,36,
-	16,0,101,36,8,0,126,36,248,255,119,36,
-	33,176,96,0,36,16,68,0,0,160,3,60,
-	37,16,67,0,16,0,166,175,0,163,1,60,
-	248,5,34,172,0,163,1,60,0,6,32,172,
-	33,160,0,0,33,128,224,2,33,152,160,0,
-	33,144,192,3,33,136,192,2,32,133,130,143,
-	0,0,32,174,0,0,0,174,0,0,64,174,
-	42,16,162,2,10,0,64,16,0,0,96,174,
-	0,32,4,36,13,8,192,12,24,0,165,175,
-	16,0,166,143,0,128,3,60,36,16,70,0,
-	37,16,67,0,0,0,2,174,24,0,165,143,
-	4,0,16,38,4,0,115,38,4,0,82,38,
-	1,0,148,38,2,0,130,42,234,255,64,20,
-	4,0,49,38,0,2,165,36,0,2,222,39,
-	0,2,247,38,1,0,181,38,7,0,162,42,
-	222,255,64,20,0,2,214,38,68,0,191,143,
-	64,0,190,143,60,0,183,143,56,0,182,143,
-	52,0,181,143,48,0,180,143,44,0,179,143,
-	40,0,178,143,36,0,177,143,32,0,176,143,
-	8,0,224,3,72,0,189,39,0,163,4,60,
-	0,6,132,140,0,163,3,60,8,6,99,140,
-	32,133,130,143,224,255,189,39,16,0,176,175,
-	0,163,16,60,12,6,16,142,20,0,177,175,
-	0,163,17,60,4,6,49,142,43,16,98,0,
-	42,0,64,16,24,0,191,175,2,0,2,46,
-	40,0,64,16,255,255,2,36,0,163,2,60,
-	252,5,66,140,0,0,0,0,43,16,81,0,
-	34,0,64,20,255,255,2,36,64,18,3,0,
-	2,131,3,60,192,246,99,36,33,24,67,0,
-	1,0,2,36,5,0,130,16,2,0,2,36,
-	18,0,130,16,128,16,16,0,36,16,192,8,
-	0,0,0,0,128,128,16,0,33,128,3,2,
-	12,1,4,142,0,163,5,60,248,5,165,140,
-	33,48,32,2,80,68,192,12,36,1,17,174,
-	12,1,4,142,12,1,2,142,33,40,32,2,
-	114,68,192,12,20,1,2,174,36,16,192,8,
-	0,0,0,0,33,16,67,0,20,1,64,172,
-	36,1,64,172,0,163,1,60,42,16,192,8,
-	0,6,32,172,255,255,2,36,0,163,1,60,
-	0,6,34,172,24,0,191,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,32,0,189,39,
-	176,133,136,143,188,133,137,143,232,255,189,39,
-	3,0,0,21,16,0,191,175,124,0,32,17,
-	0,0,0,0,12,0,194,148,0,0,0,0,
-	0,26,2,0,2,18,2,0,37,56,98,0,
-	255,255,227,48,221,5,98,44,36,0,64,20,
-	170,170,2,52,0,8,2,36,23,0,98,20,
-	6,8,2,36,21,0,0,17,0,0,0,0,
-	32,0,194,148,30,0,195,148,0,20,2,0,
-	37,56,67,0,36,0,195,148,0,161,2,52,
-	5,0,98,16,8,0,2,36,34,0,195,148,
-	0,0,0,0,98,0,98,20,0,0,0,0,
-	3,0,232,16,255,255,2,36,94,0,226,20,
-	0,0,0,0,226,46,192,12,14,0,6,36,
-	177,16,192,8,0,0,0,0,7,0,98,20,
-	255,255,227,48,71,0,0,17,55,129,2,52,
-	108,43,192,12,14,0,6,36,177,16,192,8,
-	0,0,0,0,162,16,192,8,55,129,2,52,
-	14,0,195,148,0,0,0,0,61,0,98,20,
-	255,255,2,52,16,0,195,144,3,0,2,36,
-	55,0,98,20,255,255,2,52,20,0,194,148,
-	0,0,0,0,0,26,2,0,2,18,2,0,
-	37,56,98,0,255,255,227,48,0,8,2,36,
-	23,0,98,20,6,8,2,36,21,0,0,17,
-	0,0,0,0,40,0,194,148,38,0,195,148,
-	0,20,2,0,37,56,67,0,44,0,195,148,
-	0,161,2,52,5,0,98,16,8,0,2,36,
-	42,0,195,148,0,0,0,0,49,0,98,20,
-	0,0,0,0,3,0,232,16,255,255,2,36,
-	45,0,226,20,0,0,0,0,226,46,192,12,
-	22,0,6,36,177,16,192,8,0,0,0,0,
-	7,0,98,20,255,255,227,48,6,0,0,17,
-	55,129,2,52,108,43,192,12,22,0,6,36,
-	177,16,192,8,0,0,0,0,55,129,2,52,
-	30,0,98,20,0,0,0,0,28,0,32,17,
-	144,15,3,36,38,0,194,148,28,0,198,140,
-	24,0,67,20,0,0,0,0,3,0,201,16,
-	0,0,0,0,20,0,192,20,0,0,0,0,
-	175,16,192,8,22,0,6,36,14,0,195,148,
-	0,0,0,0,14,0,98,20,0,0,0,0,
-	12,0,32,17,144,15,3,36,30,0,194,148,
-	20,0,198,140,8,0,67,20,0,0,0,0,
-	3,0,201,16,0,0,0,0,4,0,192,20,
-	0,0,0,0,14,0,6,36,126,49,192,12,
-	0,0,0,0,16,0,191,143,24,0,189,39,
-	8,0,224,3,0,0,0,0,128,255,189,39,
-	116,0,183,175,33,184,128,0,3,0,3,36,
-	124,0,191,175,120,0,190,175,112,0,182,175,
-	108,0,181,175,104,0,180,175,100,0,179,175,
-	96,0,178,175,92,0,177,175,88,0,176,175,
-	0,0,245,142,8,0,178,140,192,17,21,0,
-	3,131,4,60,33,32,130,0,20,13,132,140,
-	8,0,84,142,0,0,0,0,59,0,131,16,
-	5,0,130,44,57,0,64,16,128,16,4,0,
-	2,131,1,60,33,8,34,0,104,131,34,140,
-	0,0,0,0,8,0,64,0,0,0,0,0,
-	44,133,130,143,0,0,0,0,48,0,64,16,
-	6,0,132,38,4,0,131,150,2,131,2,60,
-	68,207,66,148,0,0,0,0,6,0,98,20,
-	33,32,0,0,0,0,130,142,48,129,131,143,
-	0,0,0,0,38,16,67,0,1,0,68,44,
-	72,1,128,16,33,32,160,2,114,42,192,12,
-	33,40,128,2,45,18,192,8,33,32,64,2,
-	44,133,130,143,0,0,0,0,27,0,64,16,
-	6,0,132,38,4,0,131,150,2,131,2,60,
-	68,207,66,148,0,0,0,0,6,0,98,20,
-	33,32,0,0,0,0,130,142,48,129,131,143,
-	0,0,0,0,38,16,67,0,1,0,68,44,
-	5,0,128,16,33,32,160,2,114,42,192,12,
-	33,40,128,2,45,18,192,8,33,32,64,2,
-	6,0,132,38,0,163,6,60,140,1,198,140,
-	0,0,0,0,247,24,192,12,33,40,160,2,
-	45,18,192,8,33,32,64,2,6,0,132,38,
-	0,163,6,60,140,1,198,140,0,0,0,0,
-	247,24,192,12,33,40,160,2,203,24,192,12,
-	33,32,128,2,20,1,227,142,0,0,0,0,
-	14,0,96,16,33,240,64,0,33,32,128,2,
-	16,0,166,39,18,0,69,150,0,0,0,0,
-	9,248,96,0,33,56,192,3,6,0,64,16,
-	33,32,64,2,28,1,226,142,0,0,0,0,
-	1,0,66,36,45,18,192,8,28,1,226,174,
-	132,0,193,7,7,0,2,36,4,0,131,150,
-	2,131,2,60,68,207,66,148,0,0,0,0,
-	6,0,98,20,33,32,0,0,0,0,130,142,
-	48,129,131,143,0,0,0,0,38,16,67,0,
-	1,0,68,44,9,0,128,16,255,255,2,36,
-	44,133,130,143,0,0,0,0,251,0,64,16,
-	33,32,160,2,114,42,192,12,33,40,128,2,
-	45,18,192,8,33,32,64,2,10,0,194,23,
-	0,0,0,0,8,0,160,18,0,0,0,0,
-	36,133,130,143,0,0,0,0,8,0,64,16,
-	1,0,19,36,80,133,147,143,69,17,192,8,
-	0,0,0,0,0,1,226,142,80,133,147,143,
-	1,0,66,36,0,1,226,174,84,133,130,143,
-	0,0,0,0,35,16,83,0,255,255,66,36,
-	17,0,66,162,84,133,130,143,33,128,96,2,
-	42,16,2,2,15,0,64,16,64,18,16,0,
-	2,131,3,60,192,246,99,36,33,136,67,0,
-	5,0,21,18,0,0,0,0,247,22,192,12,
-	33,32,32,2,217,0,64,16,33,16,0,0,
-	84,133,130,143,1,0,16,38,42,16,2,2,
-	246,255,64,20,0,2,49,38,84,133,130,143,
-	33,128,96,2,42,16,2,2,55,0,64,16,
-	64,18,16,0,2,131,3,60,192,246,99,36,
-	33,152,67,0,33,136,64,0,192,177,16,0,
-	41,0,21,18,0,0,0,0,2,131,2,60,
-	33,16,81,0,216,247,66,140,0,0,0,0,
-	15,0,64,16,33,32,128,2,16,0,166,39,
-	18,0,69,150,0,0,0,0,9,248,64,0,
-	33,56,160,2,8,0,64,16,0,0,0,0,
-	2,131,2,60,33,16,81,0,224,247,66,140,
-	0,0,0,0,1,0,66,36,140,17,192,8,
-	32,1,98,174,44,133,130,143,0,0,0,0,
-	7,0,64,16,3,0,8,36,3,131,2,60,
-	33,16,86,0,20,13,66,140,0,0,0,0,
-	6,0,72,20,0,0,0,0,33,32,96,2,
-	6,23,192,12,33,40,64,2,146,17,192,8,
-	0,2,115,38,17,0,66,146,0,0,0,0,
-	255,255,66,36,17,0,66,162,17,0,66,146,
-	0,2,115,38,0,2,49,38,84,133,130,143,
-	1,0,16,38,42,16,2,2,208,255,64,20,
-	128,0,214,38,254,255,2,36,4,0,194,23,
-	33,32,224,2,33,40,64,2,47,16,192,12,
-	33,48,128,2,17,0,66,146,0,0,0,0,
-	140,0,64,16,33,32,64,2,36,18,192,8,
-	0,0,0,0,26,0,194,23,0,0,0,0,
-	36,133,130,143,0,0,0,0,11,0,64,16,
-	33,32,224,2,9,0,160,18,1,0,2,36,
-	17,0,66,162,2,131,4,60,192,246,132,36,
-	6,23,192,12,33,40,64,2,126,0,64,16,
-	33,16,0,0,33,32,224,2,33,40,64,2,
-	47,16,192,12,33,48,128,2,36,133,130,143,
-	0,0,0,0,115,0,64,16,33,32,64,2,
-	116,0,160,22,1,0,2,36,45,18,192,8,
-	0,0,0,0,87,0,213,19,64,130,30,0,
-	2,131,2,60,33,16,80,0,216,247,66,140,
-	0,0,0,0,18,0,64,16,33,32,128,2,
-	16,0,166,39,18,0,69,150,0,0,0,0,
-	9,248,64,0,33,56,160,2,11,0,64,16,
-	33,32,64,2,2,131,2,60,33,16,80,0,
-	224,247,66,140,0,0,0,0,1,0,66,36,
-	2,131,1,60,33,8,48,0,224,247,34,172,
-	45,18,192,8,17,0,128,160,36,133,130,143,
-	0,0,0,0,43,0,64,16,0,0,0,0,
-	41,0,192,19,0,0,0,0,39,0,160,18,
-	64,18,30,0,2,131,16,60,192,246,16,38,
-	33,136,80,0,247,22,192,12,33,32,32,2,
-	74,0,64,16,33,16,0,0,247,22,192,12,
-	33,32,0,2,63,0,64,16,2,0,2,36,
-	17,0,66,162,44,133,130,143,0,0,0,0,
-	7,0,64,16,192,17,30,0,3,131,3,60,
-	33,24,98,0,20,13,99,140,3,0,2,36,
-	6,0,98,20,0,0,0,0,33,32,32,2,
-	6,23,192,12,33,40,64,2,0,18,192,8,
-	0,0,0,0,17,0,66,146,0,0,0,0,
-	255,255,66,36,17,0,66,162,17,0,66,146,
-	2,131,4,60,192,246,132,36,6,23,192,12,
-	33,40,64,2,36,18,192,8,0,0,0,0,
-	44,133,130,143,0,0,0,0,7,0,64,16,
-	192,17,30,0,3,131,3,60,33,24,98,0,
-	20,13,99,140,3,0,2,36,28,0,98,20,
-	0,0,0,0,1,0,2,36,17,0,66,162,
-	64,18,30,0,2,131,4,60,192,246,132,36,
-	32,18,192,8,33,32,68,0,36,133,130,143,
-	0,0,0,0,17,0,64,16,0,0,0,0,
-	15,0,192,19,1,0,2,36,17,0,66,162,
-	2,131,4,60,192,246,132,36,6,23,192,12,
-	33,40,64,2,13,0,64,16,33,16,0,0,
-	252,0,226,142,0,0,0,0,1,0,66,36,
-	47,18,192,8,252,0,226,174,48,18,192,8,
-	33,16,0,0,17,0,64,162,33,32,64,2,
-	152,21,192,12,0,0,0,0,1,0,2,36,
-	124,0,191,143,120,0,190,143,116,0,183,143,
-	112,0,182,143,108,0,181,143,104,0,180,143,
-	100,0,179,143,96,0,178,143,92,0,177,143,
-	88,0,176,143,8,0,224,3,128,0,189,39,
-	216,255,189,39,24,0,178,175,33,144,128,0,
-	32,0,191,175,28,0,179,175,20,0,177,175,
-	16,0,176,175,8,0,177,140,0,0,66,142,
-	8,0,38,142,36,0,64,16,0,0,0,0,
-	28,0,66,142,0,0,0,0,18,0,64,20,
-	1,0,2,36,0,0,194,144,0,0,0,0,
-	1,0,66,48,13,0,64,20,1,0,2,36,
-	4,0,195,148,24,0,66,150,0,0,0,0,
-	6,0,98,20,33,32,0,0,0,0,194,140,
-	20,0,67,142,0,0,0,0,38,16,67,0,
-	1,0,68,44,10,0,128,16,1,0,2,36,
-	17,0,34,162,2,131,4,60,192,246,132,36,
-	6,23,192,12,33,40,32,2,45,0,64,16,
-	33,16,0,0,139,18,192,8,0,0,0,0,
-	17,0,32,162,152,21,192,12,33,32,32,2,
-	144,18,192,8,1,0,2,36,16,0,179,140,
-	0,0,0,0,6,0,96,26,0,0,0,0,
-	32,133,130,143,0,0,0,0,42,16,98,2,
-	15,0,64,20,1,0,2,36,2,131,4,60,
-	248,130,132,36,2,131,16,60,24,131,16,38,
-	33,40,0,2,2,131,7,60,36,131,231,36,
-	15,63,192,12,188,2,6,36,1,0,4,36,
-	33,40,0,2,188,7,192,12,188,2,6,36,
-	1,0,2,36,17,0,34,162,64,18,19,0,
-	2,131,4,60,192,246,132,36,33,32,68,0,
-	6,23,192,12,33,40,32,2,6,0,64,16,
-	33,16,0,0,252,0,66,142,0,0,0,0,
-	1,0,66,36,252,0,66,174,1,0,2,36,
-	32,0,191,143,28,0,179,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	40,0,189,39,72,255,189,39,164,0,181,175,
-	33,168,128,0,180,0,191,175,176,0,190,175,
-	172,0,183,175,168,0,182,175,160,0,180,175,
-	156,0,179,175,152,0,178,175,148,0,177,175,
-	144,0,176,175,88,0,165,175,120,0,160,175,
-	120,0,168,142,0,0,0,0,96,0,168,175,
-	124,0,169,142,0,0,0,0,15,2,160,24,
-	104,0,169,175,96,0,168,143,0,0,0,0,
-	0,0,4,149,0,0,0,0,0,128,130,48,
-	9,2,64,16,0,0,0,0,128,0,160,175,
-	8,0,2,141,136,0,169,142,255,255,8,36,
-	18,0,72,16,112,0,169,175,112,0,169,143,
-	0,0,0,0,0,0,35,141,4,0,40,141,
-	128,0,169,143,255,63,98,48,33,72,34,1,
-	0,128,99,48,112,0,168,175,246,255,96,16,
-	128,0,169,175,96,0,168,143,0,0,0,0,
-	8,0,2,141,128,0,169,151,0,0,0,0,
-	18,0,73,164,0,32,130,48,200,1,64,16,
-	0,0,0,0,40,133,130,143,0,0,0,0,
-	75,0,64,16,3,0,8,36,96,0,168,143,
-	0,0,0,0,8,0,16,141,0,0,162,142,
-	8,0,5,142,30,0,64,16,0,0,0,0,
-	28,0,162,142,0,0,0,0,18,0,64,20,
-	1,0,9,36,0,0,162,144,0,0,0,0,
-	1,0,66,48,13,0,64,20,0,0,0,0,
-	4,0,163,148,24,0,162,150,0,0,0,0,
-	6,0,98,20,33,32,0,0,0,0,162,140,
-	20,0,163,142,0,0,0,0,38,16,67,0,
-	1,0,68,44,6,0,128,16,1,0,9,36,
-	17,0,9,162,2,131,4,60,192,246,132,36,
-	18,19,192,8,33,40,0,2,17,0,0,162,
-	130,20,192,8,33,32,0,2,16,0,17,141,
-	0,0,0,0,6,0,32,26,0,0,0,0,
-	32,133,130,143,0,0,0,0,42,16,34,2,
-	15,0,64,20,1,0,9,36,2,131,4,60,
-	248,130,132,36,2,131,5,60,24,131,165,36,
-	2,131,7,60,36,131,231,36,15,63,192,12,
-	188,2,6,36,1,0,4,36,2,131,5,60,
-	24,131,165,36,188,7,192,12,188,2,6,36,
-	1,0,9,36,17,0,9,162,64,34,17,0,
-	2,131,8,60,192,246,8,37,33,32,136,0,
-	33,40,0,2,6,23,192,12,0,0,0,0,
-	112,1,64,16,33,16,0,0,252,0,162,142,
-	0,0,0,0,1,0,66,36,132,20,192,8,
-	252,0,162,174,0,0,182,142,96,0,169,143,
-	192,17,22,0,8,0,50,141,3,131,3,60,
-	33,24,98,0,20,13,99,140,8,0,84,142,
-	0,0,0,0,59,0,104,16,5,0,98,44,
-	57,0,64,16,128,16,3,0,2,131,1,60,
-	33,8,34,0,128,131,34,140,0,0,0,0,
-	8,0,64,0,0,0,0,0,44,133,130,143,
-	0,0,0,0,48,0,64,16,6,0,132,38,
-	4,0,131,150,2,131,2,60,68,207,66,148,
-	0,0,0,0,6,0,98,20,33,32,0,0,
-	0,0,130,142,48,129,131,143,0,0,0,0,
-	38,16,67,0,1,0,68,44,67,1,128,16,
-	33,32,192,2,114,42,192,12,33,40,128,2,
-	130,20,192,8,33,32,64,2,44,133,130,143,
-	0,0,0,0,27,0,64,16,6,0,132,38,
-	4,0,131,150,2,131,2,60,68,207,66,148,
-	0,0,0,0,6,0,98,20,33,32,0,0,
-	0,0,130,142,48,129,131,143,0,0,0,0,
-	38,16,67,0,1,0,68,44,5,0,128,16,
-	33,32,192,2,114,42,192,12,33,40,128,2,
-	130,20,192,8,33,32,64,2,6,0,132,38,
-	0,163,6,60,140,1,198,140,0,0,0,0,
-	247,24,192,12,33,40,192,2,130,20,192,8,
-	33,32,64,2,6,0,132,38,0,163,6,60,
-	140,1,198,140,0,0,0,0,247,24,192,12,
-	33,40,192,2,203,24,192,12,33,32,128,2,
-	20,1,163,142,0,0,0,0,14,0,96,16,
-	33,240,64,0,33,32,128,2,16,0,166,39,
-	18,0,69,150,0,0,0,0,9,248,96,0,
-	33,56,192,3,6,0,64,16,33,32,64,2,
-	28,1,162,142,0,0,0,0,1,0,66,36,
-	130,20,192,8,28,1,162,174,132,0,193,7,
-	7,0,2,36,4,0,131,150,2,131,2,60,
-	68,207,66,148,0,0,0,0,6,0,98,20,
-	33,32,0,0,0,0,130,142,48,129,131,143,
-	0,0,0,0,38,16,67,0,1,0,68,44,
-	9,0,128,16,255,255,9,36,44,133,130,143,
-	0,0,0,0,246,0,64,16,33,32,192,2,
-	114,42,192,12,33,40,128,2,130,20,192,8,
-	33,32,64,2,10,0,201,23,0,0,0,0,
-	8,0,192,18,0,0,0,0,36,133,130,143,
-	0,0,0,0,8,0,64,16,1,0,19,36,
-	80,133,147,143,159,19,192,8,0,0,0,0,
-	0,1,162,142,80,133,147,143,1,0,66,36,
-	0,1,162,174,84,133,130,143,0,0,0,0,
-	35,16,83,0,255,255,66,36,17,0,66,162,
-	84,133,130,143,33,136,96,2,42,16,34,2,
-	15,0,64,16,64,18,17,0,2,131,8,60,
-	192,246,8,37,33,128,72,0,5,0,54,18,
-	0,0,0,0,247,22,192,12,33,32,0,2,
-	212,0,64,16,33,16,0,0,84,133,130,143,
-	1,0,49,38,42,16,34,2,246,255,64,20,
-	0,2,16,38,84,133,130,143,33,136,96,2,
-	42,16,34,2,55,0,64,16,64,18,17,0,
-	2,131,9,60,192,246,41,37,33,152,73,0,
-	33,128,64,0,192,185,17,0,41,0,54,18,
-	0,0,0,0,2,131,2,60,33,16,80,0,
-	216,247,66,140,0,0,0,0,15,0,64,16,
-	33,32,128,2,16,0,166,39,18,0,69,150,
-	0,0,0,0,9,248,64,0,33,56,192,2,
-	8,0,64,16,0,0,0,0,2,131,2,60,
-	33,16,80,0,224,247,66,140,0,0,0,0,
-	1,0,66,36,230,19,192,8,32,1,98,174,
-	44,133,130,143,0,0,0,0,7,0,64,16,
-	3,0,8,36,3,131,2,60,33,16,87,0,
-	20,13,66,140,0,0,0,0,6,0,72,20,
-	0,0,0,0,33,32,96,2,6,23,192,12,
-	33,40,64,2,236,19,192,8,0,2,115,38,
-	17,0,66,146,0,0,0,0,255,255,66,36,
-	17,0,66,162,17,0,66,146,0,2,115,38,
-	0,2,16,38,84,133,130,143,1,0,49,38,
-	42,16,34,2,208,255,64,20,128,0,247,38,
-	254,255,2,36,4,0,194,23,33,32,160,2,
-	33,40,64,2,47,16,192,12,33,48,128,2,
-	17,0,66,146,0,0,0,0,135,0,64,16,
-	33,32,64,2,22,19,192,8,0,0,0,0,
-	26,0,194,23,0,0,0,0,36,133,130,143,
-	0,0,0,0,11,0,64,16,33,32,160,2,
-	9,0,192,18,1,0,9,36,17,0,73,162,
-	2,131,4,60,192,246,132,36,6,23,192,12,
-	33,40,64,2,121,0,64,16,33,16,0,0,
-	33,32,160,2,33,40,64,2,47,16,192,12,
-	33,48,128,2,36,133,130,143,0,0,0,0,
-	110,0,64,16,33,32,64,2,111,0,192,22,
-	1,0,2,36,130,20,192,8,0,0,0,0,
-	89,0,214,19,64,130,30,0,2,131,2,60,
-	33,16,80,0,216,247,66,140,0,0,0,0,
-	18,0,64,16,33,32,128,2,16,0,166,39,
-	18,0,69,150,0,0,0,0,9,248,64,0,
-	33,56,192,2,11,0,64,16,33,32,64,2,
-	2,131,8,60,192,246,8,37,2,131,2,60,
-	33,16,80,0,224,247,66,140,33,24,8,2,
-	1,0,66,36,32,1,98,172,130,20,192,8,
-	17,0,128,160,36,133,130,143,0,0,0,0,
-	44,0,64,16,0,0,0,0,42,0,192,19,
-	0,0,0,0,40,0,192,18,64,18,30,0,
-	2,131,9,60,192,246,41,37,33,128,73,0,
-	247,22,192,12,33,32,0,2,69,0,64,16,
-	33,16,0,0,2,131,4,60,247,22,192,12,
-	192,246,132,36,57,0,64,16,2,0,2,36,
-	17,0,66,162,44,133,130,143,0,0,0,0,
-	7,0,64,16,192,17,30,0,3,131,1,60,
-	33,8,34,0,20,13,34,140,3,0,8,36,
-	6,0,72,20,0,0,0,0,33,32,0,2,
-	6,23,192,12,33,40,64,2,91,20,192,8,
-	0,0,0,0,17,0,66,146,0,0,0,0,
-	255,255,66,36,17,0,66,162,17,0,66,146,
-	2,131,4,60,192,246,132,36,6,23,192,12,
-	33,40,64,2,22,19,192,8,0,0,0,0,
-	44,133,130,143,0,0,0,0,7,0,64,16,
-	192,17,30,0,3,131,1,60,33,8,34,0,
-	20,13,34,140,3,0,9,36,22,0,73,20,
-	0,0,0,0,1,0,8,36,17,0,72,162,
-	64,34,30,0,2,131,9,60,192,246,41,37,
-	33,32,137,0,18,19,192,8,33,40,64,2,
-	36,133,130,143,0,0,0,0,10,0,64,16,
-	0,0,0,0,8,0,192,19,1,0,8,36,
-	17,0,72,162,2,131,4,60,192,246,132,36,
-	18,19,192,8,33,40,64,2,133,20,192,8,
-	33,16,0,0,17,0,64,162,33,32,64,2,
-	152,21,192,12,0,0,0,0,1,0,2,36,
-	52,0,64,16,0,0,0,0,152,0,162,142,
-	0,0,0,0,1,0,66,36,152,0,162,174,
-	156,0,162,142,168,0,163,142,1,0,66,36,
-	156,0,162,174,128,0,169,143,0,0,0,0,
-	33,24,105,0,163,20,192,8,168,0,163,174,
-	152,0,162,142,160,0,163,142,1,0,66,36,
-	1,0,99,36,152,0,162,174,160,0,163,174,
-	96,0,168,143,0,0,0,0,8,0,2,141,
-	255,255,9,36,4,0,73,16,0,0,0,0,
-	8,0,4,141,152,21,192,12,0,0,0,0,
-	120,0,168,143,112,0,169,143,1,0,8,37,
-	120,0,168,175,136,0,169,174,96,0,168,143,
-	8,128,2,52,0,0,0,165,2,0,2,165,
-	104,0,169,143,8,0,2,36,2,0,34,165,
-	4,0,40,141,96,0,169,143,104,0,168,175,
-	4,0,41,141,120,0,168,143,96,0,169,175,
-	88,0,169,143,0,0,0,0,42,16,9,1,
-	243,253,64,20,0,0,0,0,96,0,168,143,
-	44,0,163,142,120,0,168,174,104,0,169,143,
-	0,0,0,0,124,0,169,174,0,0,98,148,
-	0,0,0,0,0,16,66,48,43,0,64,16,
-	0,0,0,0,2,0,98,148,0,0,0,0,
-	39,0,64,20,0,0,0,0,0,0,2,149,
-	0,0,0,0,35,0,64,20,0,0,0,0,
-	2,0,2,149,8,0,3,36,255,255,66,48,
-	30,0,67,20,0,0,0,0,136,0,162,142,
-	0,0,0,0,12,0,66,140,0,0,0,0,
-	0,128,66,48,23,0,64,20,0,0,0,0,
-	164,0,162,142,44,0,163,142,1,0,66,36,
-	164,0,162,174,8,0,104,172,136,0,162,142,
-	0,0,0,0,8,0,2,173,44,0,163,142,
-	16,16,2,36,2,0,98,164,0,0,162,142,
-	0,0,0,0,5,0,64,20,0,0,0,0,
-	164,7,192,12,0,0,0,0,239,20,192,8,
-	0,0,0,0,8,0,162,142,0,0,0,0,
-	0,0,64,172,180,0,191,143,176,0,190,143,
-	172,0,183,143,168,0,182,143,164,0,181,143,
-	160,0,180,143,156,0,179,143,152,0,178,143,
-	148,0,177,143,144,0,176,143,8,0,224,3,
-	184,0,189,39,216,255,189,39,28,0,177,175,
-	33,136,128,0,32,0,178,175,33,144,160,0,
-	96,128,132,39,6,0,37,38,24,0,176,175,
-	104,128,144,39,36,0,191,175,31,21,192,12,
-	33,48,0,2,108,128,132,39,33,40,32,2,
-	31,21,192,12,33,48,0,2,10,0,64,26,
-	33,128,0,0,116,128,132,39,33,16,17,2,
-	12,0,69,144,0,0,0,0,15,63,192,12,
-	1,0,16,38,42,16,18,2,248,255,64,20,
-	0,0,0,0,124,128,132,39,15,63,192,12,
-	0,0,0,0,36,0,191,143,32,0,178,143,
-	28,0,177,143,24,0,176,143,8,0,224,3,
-	40,0,189,39,208,255,189,39,40,0,191,175,
-	2,0,162,144,0,0,163,144,1,0,167,144,
-	16,0,162,175,3,0,162,144,33,64,128,0,
-	20,0,162,175,4,0,162,144,2,131,4,60,
-	68,131,132,36,24,0,162,175,5,0,162,144,
-	33,40,0,1,32,0,166,175,33,48,96,0,
-	15,63,192,12,28,0,162,175,40,0,191,143,
-	48,0,189,39,8,0,224,3,0,0,0,0,
-	248,255,189,39,136,0,135,140,255,255,163,36,
-	12,0,160,16,33,48,224,0,255,255,5,36,
-	12,0,194,140,0,0,0,0,0,128,66,48,
-	8,0,64,20,33,16,0,0,255,255,99,36,
-	0,0,192,172,4,0,198,140,247,255,101,20,
-	0,0,0,0,136,0,134,172,33,16,224,0,
-	8,0,224,3,8,0,189,39,224,255,189,39,
-	16,0,176,175,33,128,160,0,28,0,191,175,
-	24,0,178,175,33,0,128,20,20,0,177,175,
-	84,133,130,143,80,133,131,143,0,0,0,0,
-	35,16,67,0,17,0,2,162,80,133,145,143,
-	84,133,130,143,0,0,0,0,42,16,34,2,
-	19,0,64,16,64,18,17,0,2,131,3,60,
-	192,246,99,36,33,144,67,0,33,32,64,2,
-	6,23,192,12,33,40,0,2,6,0,64,20,
-	0,0,0,0,17,0,2,146,0,0,0,0,
-	255,255,66,36,17,0,2,162,17,0,2,146,
-	84,133,130,143,1,0,49,38,42,16,34,2,
-	242,255,64,20,0,2,82,38,17,0,2,146,
-	144,21,192,8,0,0,0,0,36,133,130,143,
-	0,0,0,0,25,0,64,16,1,0,2,36,
-	0,0,130,140,0,0,0,0,20,0,64,16,
-	2,0,2,36,17,0,2,162,6,23,192,12,
-	33,40,0,2,19,0,64,16,33,16,0,0,
-	2,131,4,60,192,246,132,36,6,23,192,12,
-	33,40,0,2,7,0,64,20,0,0,0,0,
-	17,0,2,146,0,0,0,0,255,255,66,36,
-	17,0,2,162,17,0,2,146,0,0,0,0,
-	144,21,192,8,1,0,2,36,1,0,2,36,
-	17,0,2,162,6,23,192,12,33,40,0,2,
-	28,0,191,143,24,0,178,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,32,0,189,39,
-	0,0,0,0,0,0,0,0,0,129,9,52,
-	16,0,130,144,2,131,3,60,192,246,99,36,
-	64,18,2,0,33,56,67,0,140,0,230,140,
-	0,1,8,36,4,0,197,140,0,0,131,140,
-	0,0,128,172,12,0,137,172,4,0,164,172,
-	12,0,200,172,33,48,160,0,216,0,226,140,
-	33,40,128,0,1,0,66,36,0,128,99,48,
-	4,0,96,20,216,0,226,172,4,0,132,140,
-	161,21,192,8,0,0,0,0,8,0,224,3,
-	140,0,230,172,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,8,0,224,3,0,0,0,0,
-	172,0,128,172,176,0,128,172,180,0,128,172,
-	184,0,128,172,188,0,128,172,192,0,128,172,
-	196,0,128,172,200,0,128,172,204,0,128,172,
-	208,0,128,172,212,0,128,172,224,0,128,172,
-	8,1,128,172,4,1,128,172,236,0,128,172,
-	240,0,128,172,232,0,128,172,244,0,128,172,
-	8,0,224,3,248,0,128,172,224,255,189,39,
-	16,0,176,175,33,128,128,0,20,0,177,175,
-	0,2,17,36,24,0,191,175,13,8,192,12,
-	0,48,4,36,255,31,3,60,255,255,99,52,
-	33,32,0,0,36,16,67,0,0,128,3,60,
-	37,40,67,0,33,24,160,0,0,128,6,52,
-	1,0,132,36,24,0,98,36,0,0,96,164,
-	2,0,102,164,4,0,98,172,33,24,64,0,
-	42,16,145,0,249,255,64,20,1,0,132,36,
-	255,255,132,36,64,16,17,0,33,16,81,0,
-	192,16,2,0,33,16,69,0,48,0,163,36,
-	236,255,69,172,108,0,3,174,104,0,3,174,
-	96,0,5,174,100,0,2,174,24,0,191,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,248,255,189,39,0,32,14,60,
-	4,0,177,175,7,0,17,60,0,0,176,175,
-	4,0,16,60,2,131,25,60,192,246,57,39,
-	0,1,15,36,108,0,152,140,104,0,137,140,
-	176,0,140,140,180,0,141,140,94,0,56,17,
-	0,0,0,0,4,0,43,141,0,0,0,0,
-	37,16,110,1,0,0,66,148,0,0,0,0,
-	0,128,66,48,86,0,64,16,37,16,46,1,
-	0,0,67,140,0,0,0,0,36,16,113,0,
-	76,0,80,20,0,32,98,48,41,0,64,20,
-	15,0,98,48,188,0,130,140,0,0,0,0,
-	1,0,66,36,188,0,130,172,0,8,98,48,
-	6,0,64,16,0,4,98,48,192,0,130,140,
-	0,0,0,0,1,0,66,36,192,0,130,172,
-	0,4,98,48,6,0,64,16,0,2,98,48,
-	196,0,130,140,0,0,0,0,1,0,66,36,
-	196,0,130,172,0,2,98,48,6,0,64,16,
-	0,1,98,48,200,0,130,140,0,0,0,0,
-	1,0,66,36,200,0,130,172,0,1,98,48,
-	6,0,64,16,32,0,98,48,204,0,130,140,
-	0,0,0,0,1,0,66,36,204,0,130,172,
-	32,0,98,48,6,0,64,16,15,0,98,48,
-	208,0,130,140,0,0,0,0,1,0,66,36,
-	208,0,130,172,15,0,98,48,212,0,131,140,
-	8,0,37,141,33,24,98,0,212,0,131,172,
-	17,0,162,144,1,0,140,37,255,255,66,36,
-	17,0,162,160,25,0,64,20,37,24,46,1,
-	16,0,162,144,1,0,173,37,64,18,2,0,
-	33,64,89,0,140,0,7,141,0,129,10,52,
-	4,0,230,140,0,0,163,140,0,0,160,172,
-	12,0,170,172,4,0,197,172,12,0,239,172,
-	33,56,192,0,216,0,2,141,33,48,160,0,
-	1,0,66,36,0,128,99,48,4,0,96,20,
-	216,0,2,173,4,0,165,140,114,22,192,8,
-	0,0,0,0,140,0,7,173,37,24,46,1,
-	0,128,2,60,0,0,98,172,40,22,192,8,
-	33,72,96,1,104,0,137,172,176,0,140,172,
-	180,0,141,172,4,0,177,143,0,0,176,143,
-	8,0,224,3,8,0,189,39,224,255,189,39,
-	16,0,176,175,33,128,128,0,24,0,191,175,
-	20,0,177,175,44,0,17,142,0,0,0,0,
-	0,0,34,150,0,0,0,0,0,32,66,48,
-	89,0,64,16,0,0,0,0,2,0,34,150,
-	0,0,0,0,0,1,66,48,84,0,64,20,
-	0,0,0,0,27,22,192,12,0,0,0,0,
-	104,0,4,142,0,0,0,0,2,0,130,148,
-	0,128,3,52,255,255,66,48,75,0,67,16,
-	0,0,0,0,224,0,2,142,0,0,0,0,
-	1,0,66,36,224,0,2,174,4,0,36,174,
-	0,0,128,164,4,0,130,140,0,0,0,0,
-	0,0,64,164,0,0,2,142,0,0,0,0,
-	51,0,64,16,0,33,2,36,2,0,34,150,
-	0,0,0,0,47,0,64,16,0,33,2,36,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	2,0,34,150,0,0,0,0,211,255,64,20,
-	0,33,2,36,2,0,34,166,0,0,2,142,
-	0,0,0,0,5,0,64,16,0,0,0,0,
-	8,0,2,142,0,0,0,0,242,22,192,8,
-	0,0,64,172,164,7,192,12,0,0,0,0,
-	24,0,191,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,108,0,133,140,
-	0,0,0,0,4,0,162,140,0,0,0,0,
-	4,0,67,140,104,0,130,140,0,0,0,0,
-	5,0,98,20,33,16,160,0,184,0,131,140,
-	33,16,0,0,1,0,99,36,184,0,131,172,
-	8,0,224,3,0,0,0,0,224,255,189,39,
-	16,0,176,175,33,128,128,0,28,0,191,175,
-	24,0,178,175,20,0,177,175,108,0,18,142,
-	8,1,6,142,44,0,17,142,4,0,66,142,
-	104,0,7,142,4,0,66,140,18,0,163,148,
-	172,0,4,142,0,0,0,0,6,0,71,20,
-	255,255,99,48,184,0,3,142,33,16,0,0,
-	1,0,99,36,157,23,192,8,184,0,3,174,
-	33,48,195,0,1,0,130,36,172,0,2,174,
-	8,1,6,174,8,0,162,140,4,1,3,142,
-	0,0,70,144,33,32,64,2,8,0,69,174,
-	12,0,64,174,1,0,194,48,2,0,64,16,
-	1,0,98,36,4,1,2,174,0,0,2,142,
-	0,0,0,0,35,0,64,20,0,0,0,0,
-	18,0,162,148,0,0,0,0,255,255,66,48,
-	12,0,66,174,0,0,34,150,0,0,0,0,
-	0,32,66,48,24,0,64,16,12,0,2,36,
-	2,0,34,150,0,0,0,0,0,1,66,48,
-	19,0,64,20,12,0,2,36,4,0,242,16,
-	0,0,0,0,27,22,192,12,33,32,0,2,
-	12,0,2,36,2,0,66,166,104,0,4,142,
-	0,0,0,0,0,0,128,164,4,0,130,140,
-	0,0,0,0,0,0,64,164,0,33,2,36,
-	4,0,36,174,164,7,192,12,2,0,34,166,
-	154,23,192,8,0,0,0,0,154,23,192,8,
-	2,0,130,164,0,0,34,150,0,0,0,0,
-	0,32,66,48,69,0,64,16,12,0,2,36,
-	4,0,242,16,0,0,0,0,27,22,192,12,
-	33,32,0,2,12,0,2,36,2,0,66,166,
-	104,0,4,142,0,0,0,0,0,0,128,164,
-	4,0,130,140,0,0,0,0,0,0,64,164,
-	4,0,36,174,2,0,34,150,0,0,0,0,
-	47,0,64,16,0,33,2,36,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,2,0,34,150,
-	0,0,0,0,211,255,64,20,0,33,2,36,
-	2,0,34,166,8,0,2,142,0,0,0,0,
-	154,23,192,8,0,0,64,172,2,0,66,166,
-	4,0,67,142,1,0,2,36,108,0,3,174,
-	28,0,191,143,24,0,178,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,32,0,189,39,
-	216,255,189,39,20,0,177,175,33,136,128,0,
-	24,0,178,175,2,131,18,60,192,131,82,38,
-	28,0,179,175,0,1,19,36,32,0,191,175,
-	16,0,176,175,104,0,48,142,108,0,34,142,
-	0,0,0,0,4,0,2,22,0,0,0,0,
-	2,0,2,150,245,23,192,8,0,0,0,0,
-	2,0,2,150,0,0,0,0,7,0,66,48,
-	11,0,64,20,33,40,64,2,2,131,4,60,
-	160,131,132,36,2,131,7,60,252,131,231,36,
-	15,63,192,12,0,2,6,36,1,0,4,36,
-	33,40,64,2,188,7,192,12,0,2,6,36,
-	2,0,2,150,4,0,3,36,7,0,66,48,
-	40,0,67,20,0,128,2,52,8,0,3,142,
-	0,0,0,0,17,0,98,144,0,0,0,0,
-	255,255,66,36,17,0,98,160,17,0,98,144,
-	0,0,0,0,30,0,64,20,0,128,2,52,
-	180,0,34,142,33,32,96,0,1,0,66,36,
-	180,0,34,174,16,0,130,144,2,131,3,60,
-	192,246,99,36,64,18,2,0,33,56,67,0,
-	140,0,230,140,0,129,8,52,4,0,197,140,
-	0,0,131,140,0,0,128,172,12,0,136,172,
-	4,0,164,172,12,0,211,172,33,48,160,0,
-	216,0,226,140,33,40,128,0,1,0,66,36,
-	0,128,99,48,4,0,96,20,216,0,226,172,
-	4,0,132,140,223,23,192,8,0,0,0,0,
-	140,0,230,172,0,128,2,52,2,0,2,166,
-	0,0,0,166,4,0,16,142,174,23,192,8,
-	0,0,0,0,44,0,35,142,104,0,48,174,
-	0,0,98,148,0,0,0,0,0,32,66,52,
-	0,0,98,164,32,0,191,143,28,0,179,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,40,0,189,39,0,163,2,60,
-	0,1,66,52,0,0,66,140,2,131,3,60,
-	192,6,99,36,255,3,66,48,60,0,66,36,
-	0,128,66,52,8,0,224,3,0,0,98,172,
-	208,255,189,39,28,0,177,175,33,136,128,0,
-	32,0,178,175,33,144,160,0,24,0,176,175,
-	0,163,16,60,0,163,2,60,164,1,66,140,
-	0,1,16,54,44,0,191,175,40,0,180,175,
-	4,0,64,20,36,0,179,175,60,0,2,36,
-	0,163,1,60,164,1,34,172,0,163,2,60,
-	164,1,66,140,0,0,0,0,221,5,66,40,
-	3,0,64,20,220,5,2,36,0,163,1,60,
-	164,1,34,172,0,163,3,60,164,1,99,140,
-	255,255,2,36,21,0,98,20,0,0,0,0,
-	128,128,130,143,0,0,0,0,5,0,67,20,
-	2,0,5,36,130,11,192,12,0,0,0,0,
-	128,128,130,175,2,0,5,36,10,0,6,36,
-	128,128,132,143,0,131,7,60,8,96,231,36,
-	156,11,192,12,16,0,160,175,0,0,2,142,
-	2,131,3,60,192,6,99,36,255,3,66,48,
-	66,24,192,8,64,0,66,36,0,163,2,60,
-	164,1,66,140,2,131,3,60,192,6,99,36,
-	0,128,66,52,0,0,98,172,255,31,4,60,
-	255,255,132,52,2,131,2,60,208,6,66,36,
-	36,16,68,0,0,160,5,60,37,16,69,0,
-	2,131,3,60,176,12,99,36,2,131,1,60,
-	196,6,32,172,2,131,1,60,200,6,34,172,
-	12,0,2,36,0,0,96,164,2,131,1,60,
-	178,12,34,164,6,0,65,6,36,16,100,0,
-	37,16,69,0,2,131,1,60,180,12,34,172,
-	99,24,192,8,255,31,18,60,2,131,2,60,
-	178,12,66,148,0,0,0,0,0,128,66,52,
-	2,131,1,60,178,12,34,164,255,31,18,60,
-	255,255,82,54,2,131,2,60,192,6,66,36,
-	36,16,82,0,0,160,20,60,37,16,84,0,
-	2,131,1,60,184,12,34,172,2,131,1,60,
-	188,12,32,172,44,0,34,142,0,0,0,0,
-	0,0,66,148,2,131,19,60,176,12,115,38,
-	0,32,66,48,15,0,64,20,33,40,0,0,
-	2,131,4,60,160,131,132,36,2,131,16,60,
-	192,131,16,38,33,40,0,2,2,131,7,60,
-	24,132,231,36,15,63,192,12,71,2,6,36,
-	1,0,4,36,33,40,0,2,188,7,192,12,
-	71,2,6,36,33,40,0,0,33,48,0,0,
-	36,16,114,2,44,0,35,142,37,16,84,0,
-	4,0,98,172,44,0,36,142,208,7,7,36,
-	129,67,192,12,2,0,132,36,12,0,64,20,
-	0,0,0,0,44,0,34,142,0,0,0,0,
-	2,0,69,148,2,131,4,60,15,63,192,12,
-	56,132,132,36,255,255,4,36,2,131,5,60,
-	192,131,165,36,188,7,192,12,79,2,6,36,
-	44,0,34,142,0,33,3,36,2,0,67,164,
-	8,0,34,142,0,0,0,0,0,0,64,172,
-	44,0,191,143,40,0,180,143,36,0,179,143,
-	32,0,178,143,28,0,177,143,24,0,176,143,
-	8,0,224,3,48,0,189,39,232,255,189,39,
-	128,128,132,143,0,128,2,52,16,0,191,175,
-	2,131,1,60,3,0,128,4,178,12,34,164,
-	177,11,192,12,0,0,0,0,16,0,191,143,
-	24,0,189,39,8,0,224,3,0,0,0,0,
-	8,0,224,3,0,0,0,0,0,0,0,0,
-	0,0,0,0,240,255,2,52,2,131,1,60,
-	33,8,34,0,208,12,32,172,240,255,66,36,
-	251,255,65,4,0,0,0,0,2,131,2,60,
-	208,12,66,36,0,163,1,60,12,1,32,172,
-	0,163,1,60,212,5,34,172,1,0,2,60,
-	148,133,128,175,144,133,128,175,0,163,1,60,
-	8,0,224,3,216,5,34,172,0,0,136,148,
-	4,0,138,148,1,0,2,49,34,0,64,20,
-	2,0,137,148,0,25,10,0,38,24,106,0,
-	38,24,105,0,240,255,99,48,2,131,15,60,
-	208,12,239,37,33,40,111,0,68,133,142,143,
-	128,0,3,36,0,0,162,140,4,0,171,148,
-	23,0,64,16,43,16,194,1,9,0,64,16,
-	6,0,172,148,7,0,11,21,8,0,173,148,
-	5,0,44,21,0,0,0,0,3,0,77,21,
-	10,0,162,148,8,0,224,3,0,0,0,0,
-	255,255,99,36,10,0,96,16,240,255,165,36,
-	43,16,175,0,238,255,64,16,0,0,162,140,
-	248,127,229,37,248,127,165,36,218,24,192,8,
-	0,0,162,140,8,0,224,3,254,255,2,36,
-	8,0,224,3,255,255,2,36,8,0,224,3,
-	0,0,0,0,0,0,136,148,68,133,142,143,
-	1,0,2,49,53,0,64,20,2,0,137,148,
-	0,131,2,60,4,0,138,148,12,1,89,140,
-	0,25,10,0,38,24,106,0,38,24,105,0,
-	240,255,99,48,2,131,15,60,208,12,239,37,
-	33,56,111,0,128,0,3,36,0,0,248,140,
-	4,0,235,148,43,16,216,1,14,0,64,16,
-	6,0,236,148,24,0,11,21,8,0,237,148,
-	22,0,44,21,255,127,2,60,20,0,77,21,
-	255,255,66,52,43,16,2,3,2,0,64,16,
-	33,16,198,1,0,0,226,172,10,0,229,164,
-	8,0,224,3,0,0,2,36,3,0,0,23,
-	1,0,57,35,0,131,2,60,12,1,89,172,
-	33,16,198,1,0,0,226,172,10,0,229,164,
-	4,0,232,164,6,0,233,164,8,0,234,164,
-	8,0,224,3,1,0,2,36,255,255,99,36,
-	11,0,96,16,0,0,0,0,240,255,231,36,
-	43,16,239,0,221,255,64,16,0,0,248,140,
-	248,127,231,37,248,127,231,36,8,25,192,8,
-	0,0,248,140,8,0,224,3,0,0,2,36,
-	144,133,130,143,0,0,0,0,1,0,66,32,
-	144,133,130,175,8,0,224,3,255,255,2,36,
-	8,0,224,3,0,0,0,0,164,128,130,143,
-	0,0,0,0,7,0,130,20,232,255,189,39,
-	160,128,130,143,2,131,3,60,208,12,99,36,
-	0,17,2,0,108,25,192,8,33,16,67,0,
-	42,16,130,0,3,0,64,16,255,255,2,36,
-	164,128,128,175,160,128,130,175,164,128,130,143,
-	160,128,131,143,35,48,130,0,1,0,101,36,
-	0,16,162,40,25,0,64,16,0,25,5,0,
-	68,133,135,143,2,131,2,60,33,16,67,0,
-	208,12,66,140,0,0,0,0,43,16,226,0,
-	4,0,64,16,0,0,0,0,255,255,198,36,
-	6,0,192,16,0,16,162,40,1,0,165,36,
-	0,16,162,40,243,255,64,20,16,0,99,36,
-	0,16,162,40,7,0,64,16,0,25,5,0,
-	2,131,2,60,208,12,66,36,160,128,133,175,
-	164,128,132,175,108,25,192,8,33,16,98,0,
-	33,16,0,0,255,255,3,36,164,128,128,175,
-	160,128,131,175,8,0,224,3,24,0,189,39,
-	0,0,0,0,0,0,0,0,24,255,189,39,
-	228,0,191,175,224,0,190,175,220,0,183,175,
-	216,0,182,175,212,0,181,175,208,0,180,175,
-	204,0,179,175,200,0,178,175,196,0,177,175,
-	192,0,176,175,44,28,192,12,0,0,0,0,
-	176,128,132,39,15,63,192,12,1,0,17,36,
-	24,0,176,39,164,68,192,12,33,32,0,2,
-	24,0,162,131,0,0,0,0,137,25,192,8,
-	32,0,8,36,0,0,2,130,32,0,8,36,
-	253,255,72,16,1,0,16,38,255,255,16,38,
-	9,0,8,36,249,255,72,16,1,0,16,38,
-	255,255,16,38,0,0,2,146,0,0,0,0,
-	208,255,66,36,10,0,66,44,27,0,64,16,
-	33,32,0,2,33,40,0,0,212,68,192,12,
-	33,48,0,0,0,0,3,146,0,0,0,0,
-	208,255,99,36,10,0,99,44,9,0,96,16,
-	33,136,64,0,1,0,16,38,0,0,2,146,
-	0,0,0,0,208,255,66,36,10,0,66,44,
-	251,255,64,20,1,0,16,38,255,255,16,38,
-	0,0,2,130,32,0,8,36,253,255,72,16,
-	1,0,16,38,255,255,16,38,9,0,8,36,
-	249,255,72,16,1,0,16,38,255,255,16,38,
-	0,0,2,130,0,0,3,146,0,0,0,0,
-	22,0,64,16,104,0,180,39,32,0,8,36,
-	19,0,72,16,9,0,8,36,17,0,72,16,
-	32,0,5,36,9,0,4,36,208,255,98,36,
-	10,0,66,44,12,0,64,20,0,0,0,0,
-	1,0,16,38,0,0,131,162,0,0,2,130,
-	0,0,3,146,0,0,0,0,5,0,64,16,
-	1,0,148,38,3,0,69,16,0,0,0,0,
-	243,255,68,20,208,255,98,36,0,0,128,162,
-	104,0,180,39,0,0,2,130,32,0,8,36,
-	253,255,72,16,1,0,16,38,255,255,16,38,
-	9,0,8,36,249,255,72,16,1,0,16,38,
-	255,255,16,38,33,240,0,2,0,0,196,131,
-	0,0,0,0,32,69,192,12,144,0,190,175,
-	11,0,64,16,33,32,192,3,33,40,0,0,
-	212,68,192,12,33,48,0,0,33,152,64,0,
-	33,32,192,3,33,40,0,0,44,69,192,12,
-	16,0,6,36,232,25,192,8,33,144,64,0,
-	255,255,18,36,255,255,19,36,0,0,3,130,
-	0,0,2,146,0,0,0,0,17,0,96,16,
-	32,0,8,36,15,0,104,16,1,0,16,38,
-	255,255,16,38,32,0,4,36,0,22,2,0,
-	3,22,2,0,9,0,8,36,8,0,72,16,
-	0,0,0,0,1,0,16,38,0,0,3,130,
-	0,0,2,146,3,0,96,16,0,0,0,0,
-	246,255,100,20,0,22,2,0,0,0,2,130,
-	32,0,8,36,253,255,72,16,1,0,16,38,
-	255,255,16,38,9,0,8,36,249,255,72,16,
-	1,0,16,38,255,255,16,38,33,184,0,2,
-	33,32,224,2,33,40,0,0,212,68,192,12,
-	33,48,0,0,33,32,224,2,33,40,0,0,
-	16,0,6,36,44,69,192,12,33,176,64,0,
-	0,0,227,130,0,0,0,0,15,0,96,16,
-	33,168,64,0,32,0,8,36,12,0,104,16,
-	32,0,3,36,0,0,2,130,9,0,8,36,
-	8,0,72,16,0,0,0,0,1,0,16,38,
-	0,0,2,130,0,0,0,0,3,0,64,16,
-	0,0,0,0,248,255,67,20,0,0,0,0,
-	0,0,131,130,0,0,0,0,121,0,98,44,
-	244,1,64,16,128,16,3,0,2,131,1,60,
-	33,8,34,0,160,138,34,140,0,0,0,0,
-	8,0,64,0,0,0,0,0,1,0,131,130,
-	104,0,2,36,26,0,98,16,105,0,98,40,
-	7,0,64,16,116,0,2,36,34,0,96,16,
-	98,0,2,36,11,0,98,16,0,0,0,0,
-	26,28,192,8,0,0,0,0,5,0,98,16,
-	119,0,8,36,27,0,104,16,33,16,32,2,
-	26,28,192,8,0,0,0,0,4,162,2,60,
-	33,144,66,2,2,0,130,130,0,0,0,0,
-	214,1,64,20,0,0,0,0,2,131,4,60,
-	108,132,132,36,0,0,70,146,82,26,192,8,
-	0,0,0,0,2,0,130,130,0,0,0,0,
-	205,1,64,20,0,0,0,0,2,131,4,60,
-	120,132,132,36,0,0,70,150,0,0,0,0,
-	15,63,192,12,33,40,64,2,125,25,192,8,
-	0,0,0,0,33,16,32,2,37,255,64,16,
-	255,255,49,38,0,0,80,142,2,131,4,60,
-	132,132,132,36,33,40,64,2,4,0,82,38,
-	15,63,192,12,33,48,0,2,33,16,32,2,
-	247,255,64,20,255,255,49,38,125,25,192,8,
-	0,0,0,0,1,0,131,130,104,0,2,36,
-	23,0,98,16,105,0,98,40,7,0,64,16,
-	116,0,2,36,25,0,96,16,98,0,2,36,
-	11,0,98,16,0,0,0,0,26,28,192,8,
-	0,0,0,0,5,0,98,16,119,0,8,36,
-	17,0,104,16,0,0,0,0,26,28,192,8,
-	0,0,0,0,4,162,2,60,33,144,66,2,
-	2,0,130,130,0,0,0,0,158,1,64,20,
-	0,0,0,0,125,25,192,8,0,0,85,162,
-	2,0,130,130,0,0,0,0,152,1,64,20,
-	0,0,0,0,125,25,192,8,0,0,85,166,
-	125,25,192,8,0,0,85,174,0,163,16,60,
-	31,163,17,60,255,255,49,54,0,0,2,142,
-	0,0,0,0,4,0,82,20,0,0,0,0,
-	180,128,132,39,15,63,192,12,33,40,0,2,
-	4,0,16,38,43,16,48,2,246,255,64,16,
-	0,0,0,0,125,25,192,8,0,0,0,0,
-	33,16,32,2,228,254,64,16,255,255,49,38,
-	33,32,96,2,164,32,192,12,33,40,192,2,
-	33,16,32,2,251,255,64,20,255,255,49,38,
-	125,25,192,8,0,0,0,0,1,0,130,130,
-	0,0,0,0,117,1,64,20,33,32,32,2,
-	133,29,192,12,33,40,96,2,125,25,192,8,
-	0,0,0,0,33,32,96,2,33,40,32,2,
-	234,31,192,12,33,48,192,2,125,25,192,8,
-	0,0,0,0,1,0,130,130,0,0,0,0,
-	103,1,64,20,33,16,32,2,200,254,64,16,
-	255,255,49,38,33,32,96,2,33,40,192,2,
-	182,29,192,12,33,48,0,2,33,16,32,2,
-	250,255,64,20,255,255,49,38,125,25,192,8,
-	0,0,0,0,33,32,32,2,33,40,96,2,
-	33,48,192,2,38,30,192,12,33,56,0,2,
-	125,25,192,8,0,0,0,0,5,162,2,60,
-	0,0,69,144,2,131,4,60,15,63,192,12,
-	144,132,132,36,125,25,192,8,0,0,0,0,
-	0,163,1,60,20,1,32,172,14,0,32,18,
-	33,128,0,0,164,7,192,12,1,0,16,38,
-	143,63,192,12,0,0,0,0,143,63,192,12,
-	0,0,0,0,143,63,192,12,0,0,0,0,
-	143,63,192,12,0,0,0,0,43,16,17,2,
-	244,255,64,20,0,0,0,0,184,63,192,12,
-	0,0,0,0,0,163,16,60,20,1,16,142,
-	0,0,0,0,7,0,17,22,33,40,32,2,
-	2,131,4,60,164,132,132,36,15,63,192,12,
-	33,40,32,2,125,25,192,8,0,0,0,0,
-	2,131,4,60,188,132,132,36,15,63,192,12,
-	33,48,0,2,125,25,192,8,0,0,0,0,
-	0,0,226,130,7,162,8,60,16,0,64,16,
-	33,144,72,2,33,16,32,2,134,254,64,16,
-	255,255,49,38,0,0,85,174,2,131,4,60,
-	132,132,132,36,33,40,64,2,15,63,192,12,
-	33,48,160,2,4,0,82,38,33,16,32,2,
-	247,255,64,20,255,255,49,38,125,25,192,8,
-	0,0,0,0,33,16,32,2,119,254,64,16,
-	255,255,49,38,0,0,80,142,2,131,4,60,
-	132,132,132,36,33,40,64,2,4,0,82,38,
-	15,63,192,12,33,48,0,2,33,16,32,2,
-	247,255,64,20,255,255,49,38,125,25,192,8,
-	0,0,0,0,7,162,16,60,64,0,17,38,
-	2,131,4,60,228,132,132,36,33,40,0,2,
-	0,0,6,142,0,0,0,0,15,63,192,12,
-	4,0,16,38,42,16,17,2,247,255,64,20,
-	7,162,8,60,128,0,16,37,176,0,17,37,
-	2,131,4,60,228,132,132,36,33,40,0,2,
-	0,0,6,142,0,0,0,0,15,63,192,12,
-	4,0,16,38,42,16,17,2,247,255,64,20,
-	7,162,8,60,192,0,16,37,240,0,17,37,
-	2,131,4,60,228,132,132,36,33,40,0,2,
-	0,0,6,142,0,0,0,0,15,63,192,12,
-	4,0,16,38,42,16,17,2,247,255,64,20,
-	0,0,0,0,125,25,192,8,0,0,0,0,
-	1,0,130,130,0,0,0,0,222,0,64,20,
-	33,16,32,2,63,254,64,16,255,255,49,38,
-	33,32,96,2,213,29,192,12,33,40,160,2,
-	33,16,32,2,251,255,64,20,255,255,49,38,
-	125,25,192,8,0,0,0,0,1,0,130,130,
-	0,0,0,0,208,0,64,20,33,16,32,2,
-	49,254,64,16,255,255,49,38,33,32,96,2,
-	161,31,192,12,33,40,192,2,33,16,32,2,
-	251,255,64,20,255,255,49,38,125,25,192,8,
-	0,0,0,0,33,16,32,2,38,254,64,16,
-	255,255,49,38,208,32,192,12,33,32,0,0,
-	33,32,0,0,164,32,192,12,33,40,0,0,
-	40,29,192,12,0,0,0,0,133,29,192,12,
-	255,255,4,36,33,16,32,2,245,255,64,20,
-	255,255,49,38,125,25,192,8,0,0,0,0,
-	1,0,131,130,87,0,2,36,27,0,98,16,
-	88,0,98,40,7,0,64,16,114,0,2,36,
-	37,0,96,16,82,0,2,36,9,0,98,16,
-	0,0,0,0,125,25,192,8,0,0,0,0,
-	5,0,98,16,119,0,8,36,15,0,104,16,
-	0,0,0,0,125,25,192,8,0,0,0,0,
-	2,0,130,130,0,0,0,0,159,0,64,20,
-	0,0,0,0,60,65,192,12,33,32,96,2,
-	184,128,132,39,33,40,96,2,15,63,192,12,
-	33,48,64,0,125,25,192,8,0,0,0,0,
-	2,0,130,130,0,0,0,0,147,0,64,20,
-	33,32,96,2,162,65,192,12,33,40,160,2,
-	242,253,64,20,33,40,160,2,2,131,4,60,
-	8,133,132,36,15,63,192,12,33,48,96,2,
-	125,25,192,8,0,0,0,0,33,16,32,2,
-	233,253,64,16,255,255,49,38,40,29,192,12,
-	0,0,0,0,33,16,32,2,252,255,64,20,
-	255,255,49,38,125,25,192,8,0,0,0,0,
-	1,0,133,130,87,0,2,36,29,0,162,16,
-	88,0,162,40,5,0,64,16,82,0,2,36,
-	11,0,162,16,33,16,32,2,125,25,192,8,
-	0,0,0,0,114,0,2,36,5,0,162,16,
-	119,0,8,36,19,0,168,16,33,32,64,2,
-	125,25,192,8,0,0,0,0,33,16,32,2,
-	206,253,64,16,255,255,49,38,168,69,192,12,
-	33,32,64,2,184,128,132,39,33,40,64,2,
-	15,63,192,12,33,48,64,0,1,0,82,38,
-	33,16,32,2,247,255,64,20,255,255,49,38,
-	125,25,192,8,0,0,0,0,33,32,64,2,
-	29,70,192,12,33,40,160,2,189,253,64,20,
-	33,40,160,2,2,131,4,60,40,133,132,36,
-	15,63,192,12,33,48,64,2,125,25,192,8,
-	0,0,0,0,144,0,164,143,122,28,192,12,
-	0,0,0,0,125,25,192,8,0,0,0,0,
-	33,16,96,2,175,253,64,16,255,255,115,38,
-	143,63,192,12,0,0,0,0,33,16,96,2,
-	252,255,64,20,255,255,115,38,125,25,192,8,
-	0,0,0,0,33,16,32,2,165,253,64,16,
-	255,255,49,38,33,32,96,2,208,32,192,12,
-	33,40,192,2,33,16,32,2,251,255,64,20,
-	255,255,49,38,125,25,192,8,0,0,0,0,
-	1,0,130,146,0,0,0,0,159,255,66,36,
-	0,22,2,0,3,30,2,0,24,0,98,44,
-	27,0,64,16,128,16,3,0,2,131,1,60,
-	33,8,34,0,136,140,34,140,0,0,0,0,
-	8,0,64,0,0,0,0,0,12,33,192,12,
-	33,32,64,2,125,25,192,8,0,0,0,0,
-	15,33,192,12,33,32,96,2,125,25,192,8,
-	0,0,0,0,18,33,192,12,33,32,96,2,
-	125,25,192,8,0,0,0,0,22,33,192,12,
-	33,32,96,2,125,25,192,8,0,0,0,0,
-	25,33,192,12,33,32,64,2,125,25,192,8,
-	0,0,0,0,33,32,64,2,7,33,192,12,
-	33,40,192,2,125,25,192,8,0,0,0,0,
-	16,0,182,175,33,32,32,2,33,40,192,3,
-	33,48,224,2,161,33,192,12,33,56,160,2,
-	125,25,192,8,0,0,0,0,33,136,0,0,
-	2,131,4,60,72,133,132,36,15,63,192,12,
-	1,0,49,38,32,0,34,46,250,255,64,20,
-	0,0,0,0,125,25,192,8,0,0,0,0,
-	2,131,4,60,92,133,132,36,15,63,192,12,
-	33,40,128,2,123,25,192,8,0,0,0,0,
-	228,0,191,143,224,0,190,143,220,0,183,143,
-	216,0,182,143,212,0,181,143,208,0,180,143,
-	204,0,179,143,200,0,178,143,196,0,177,143,
-	192,0,176,143,8,0,224,3,232,0,189,39,
-	232,255,189,39,2,131,5,60,192,154,165,36,
-	20,0,191,175,16,0,176,175,0,0,162,140,
-	0,0,0,0,9,0,64,16,33,128,160,0,
-	0,0,5,142,192,128,132,39,15,63,192,12,
-	4,0,16,38,0,0,2,142,0,0,0,0,
-	249,255,64,20,0,0,0,0,20,0,191,143,
-	16,0,176,143,8,0,224,3,24,0,189,39,
-	0,0,132,144,0,0,0,0,208,255,130,36,
-	10,0,66,44,4,0,64,16,0,22,4,0,
-	3,22,2,0,89,28,192,8,208,255,66,36,
-	159,255,130,36,6,0,66,44,4,0,64,16,
-	0,22,4,0,3,22,2,0,89,28,192,8,
-	169,255,66,36,191,255,130,36,6,0,66,44,
-	3,0,64,20,0,22,4,0,89,28,192,8,
-	255,255,2,36,3,22,2,0,201,255,66,36,
-	8,0,224,3,0,0,0,0,216,255,189,39,
-	24,0,178,175,33,144,128,0,32,0,191,175,
-	28,0,179,175,20,0,177,175,16,0,176,175,
-	0,0,81,142,0,0,0,0,65,28,192,12,
-	33,32,32,2,33,24,64,0,255,255,19,36,
-	9,0,115,16,0,129,3,0,65,28,192,12,
-	1,0,36,38,33,24,64,0,4,0,115,16,
-	2,0,34,38,0,0,66,174,115,28,192,8,
-	37,16,3,2,255,255,2,36,32,0,191,143,
-	28,0,179,143,24,0,178,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,40,0,189,39,
-	176,255,189,39,64,0,180,175,33,160,128,0,
-	72,0,191,175,68,0,181,175,60,0,179,175,
-	56,0,178,175,52,0,177,175,48,0,176,175,
-	0,0,130,130,0,0,0,0,53,0,64,20,
-	33,128,0,0,27,67,192,12,33,32,0,0,
-	1,0,4,36,27,67,192,12,33,128,64,0,
-	2,0,4,36,27,67,192,12,33,136,64,0,
-	33,24,64,0,255,255,2,36,5,0,2,18,
-	0,0,0,0,3,0,34,18,0,0,0,0,
-	6,0,98,20,255,255,2,52,2,131,4,60,
-	15,63,192,12,60,137,132,36,29,29,192,8,
-	0,0,0,0,5,0,2,18,0,0,0,0,
-	3,0,34,18,0,0,0,0,6,0,98,20,
-	1,0,2,50,2,131,4,60,15,63,192,12,
-	104,137,132,36,29,29,192,8,0,0,0,0,
-	6,0,64,16,255,0,5,50,2,131,4,60,
-	15,63,192,12,132,137,132,36,29,29,192,8,
-	0,0,0,0,2,131,4,60,176,137,132,36,
-	3,50,16,0,3,18,17,0,16,0,162,175,
-	255,0,98,48,20,0,162,175,3,18,3,0,
-	255,0,39,50,15,63,192,12,24,0,162,175,
-	29,29,192,8,0,0,0,0,40,0,180,175,
-	58,0,21,36,32,0,19,36,255,255,18,36,
-	32,0,177,39,40,0,162,143,0,0,0,0,
-	0,0,67,128,0,0,0,0,3,0,117,16,
-	0,0,0,0,3,0,115,20,0,0,0,0,
-	1,0,66,36,40,0,162,175,91,28,192,12,
-	40,0,164,39,33,24,64,0,75,0,114,16,
-	0,0,0,0,40,0,162,143,0,0,35,166,
-	0,0,67,128,0,0,0,0,3,0,117,16,
-	0,0,0,0,3,0,115,20,0,0,0,0,
-	1,0,66,36,40,0,162,175,91,28,192,12,
-	40,0,164,39,33,24,64,0,60,0,114,16,
-	1,0,16,38,0,0,34,150,0,26,3,0,
-	37,16,67,0,0,0,34,166,3,0,2,42,
-	220,255,64,20,2,0,49,38,32,0,165,151,
-	0,0,0,0,1,0,162,48,7,0,64,16,
-	0,0,0,0,2,131,4,60,208,137,132,36,
-	15,63,192,12,255,0,165,48,25,29,192,8,
-	0,0,0,0,36,0,162,151,0,0,0,0,
-	0,7,66,48,6,0,64,16,0,0,0,0,
-	2,131,4,60,15,63,192,12,0,138,132,36,
-	25,29,192,8,0,0,0,0,255,66,192,12,
-	33,32,0,0,1,0,4,36,34,0,165,151,
-	0,0,0,0,255,66,192,12,33,128,0,0,
-	36,0,165,151,0,0,0,0,255,66,192,12,
-	2,0,4,36,2,131,4,60,15,63,192,12,
-	32,138,132,36,2,131,4,60,80,138,132,36,
-	15,63,192,12,33,40,0,2,196,128,132,39,
-	200,128,134,39,31,21,192,12,32,0,165,39,
-	36,0,162,151,1,0,16,38,0,1,66,36,
-	36,0,162,167,8,0,2,42,7,0,64,16,
-	0,0,0,0,8,29,192,8,0,0,0,0,
-	2,131,4,60,116,138,132,36,15,63,192,12,
-	33,40,128,2,72,0,191,143,68,0,181,143,
-	64,0,180,143,60,0,179,143,56,0,178,143,
-	52,0,177,143,48,0,176,143,8,0,224,3,
-	80,0,189,39,0,0,0,0,0,0,0,0,
-	224,255,189,39,16,0,176,175,33,128,0,0,
-	20,0,177,175,33,136,0,0,24,0,191,175,
-	33,32,0,2,162,65,192,12,33,40,0,0,
-	43,0,64,16,0,0,0,0,1,0,16,38,
-	64,0,2,42,249,255,64,20,33,32,0,2,
-	33,128,0,0,85,85,17,36,33,32,0,2,
-	162,65,192,12,85,85,5,36,32,0,64,16,
-	0,0,0,0,1,0,16,38,64,0,2,42,
-	249,255,64,20,33,32,0,2,33,128,0,0,
-	170,170,17,52,33,32,0,2,162,65,192,12,
-	170,170,5,52,21,0,64,16,0,0,0,0,
-	1,0,16,38,64,0,2,42,249,255,64,20,
-	33,32,0,2,33,128,0,0,255,255,17,52,
-	33,32,0,2,162,65,192,12,255,255,5,52,
-	10,0,64,16,0,0,0,0,1,0,16,38,
-	64,0,2,42,249,255,64,20,33,32,0,2,
-	2,131,4,60,15,63,192,12,240,140,132,36,
-	101,29,192,8,0,0,0,0,60,65,192,12,
-	33,32,0,2,2,131,4,60,4,141,132,36,
-	33,40,32,2,33,48,0,2,15,63,192,12,
-	33,56,64,0,24,0,191,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,32,0,189,39,
-	0,0,0,0,0,0,0,0,232,255,189,39,
-	16,0,191,175,210,7,192,12,0,0,0,0,
-	139,14,192,12,0,0,0,0,180,10,192,12,
-	0,0,0,0,32,133,132,143,1,0,2,36,
-	42,16,68,0,9,0,64,16,0,2,3,36,
-	64,34,4,0,2,131,1,60,33,8,35,0,
-	196,246,32,172,0,2,99,36,42,16,100,0,
-	250,255,64,20,0,0,0,0,16,0,191,143,
-	24,0,189,39,8,0,224,3,0,0,0,0,
-	208,255,189,39,24,0,178,175,33,144,128,0,
-	32,0,180,175,33,160,160,0,44,0,191,175,
-	40,0,182,175,36,0,181,175,28,0,179,175,
-	20,0,177,175,3,0,128,26,16,0,176,175,
-	149,29,192,8,1,0,147,38,1,0,20,36,
-	32,133,147,143,255,255,82,38,255,255,2,36,
-	20,0,66,18,255,255,21,36,2,131,22,60,
-	192,246,214,38,108,29,192,12,33,128,128,2,
-	42,16,19,2,10,0,64,16,64,18,16,0,
-	33,136,86,0,242,21,192,12,33,32,32,2,
-	133,12,192,12,33,32,0,2,1,0,16,38,
-	42,16,19,2,249,255,64,20,0,2,49,38,
-	255,255,82,38,240,255,85,22,0,0,0,0,
-	44,0,191,143,40,0,182,143,36,0,181,143,
-	32,0,180,143,28,0,179,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	48,0,189,39,216,255,189,39,24,0,178,175,
-	33,144,160,0,28,0,179,175,33,152,192,0,
-	32,0,191,175,20,0,177,175,3,0,128,24,
-	16,0,176,175,195,29,192,8,1,0,145,36,
-	1,0,4,36,32,133,145,143,33,128,128,0,
-	42,16,17,2,8,0,64,16,33,32,0,2,
-	33,40,64,2,250,29,192,12,33,48,96,2,
-	1,0,16,38,42,16,17,2,250,255,64,20,
-	33,32,0,2,32,0,191,143,28,0,179,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,40,0,189,39,224,255,189,39,
-	24,0,191,175,20,0,177,175,3,0,128,24,
-	16,0,176,175,222,29,192,8,1,0,145,36,
-	1,0,4,36,32,133,145,143,33,128,128,0,
-	42,16,17,2,7,0,64,16,0,0,0,0,
-	237,29,192,12,33,32,0,2,1,0,16,38,
-	42,16,17,2,251,255,64,20,0,0,0,0,
-	24,0,191,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,64,34,4,0,
-	2,131,2,60,192,246,66,36,33,32,130,0,
-	44,0,131,140,1,0,2,36,32,0,130,172,
-	16,0,2,36,2,0,98,164,8,0,130,140,
-	0,0,0,0,8,0,224,3,0,0,64,172,
-	208,255,189,39,33,48,128,0,64,18,6,0,
-	2,131,3,60,192,246,99,36,36,0,177,175,
-	33,136,67,0,40,0,191,175,32,0,176,175,
-	4,0,34,142,0,0,0,0,4,0,64,20,
-	33,128,160,0,1,0,4,36,133,29,192,12,
-	33,40,192,0,3,0,0,30,221,5,2,42,
-	17,30,192,8,1,0,16,36,3,0,64,20,
-	33,32,32,2,220,5,16,36,33,32,32,2,
-	208,7,5,36,108,0,131,140,12,0,2,36,
-	2,0,98,164,16,0,162,39,8,0,98,172,
-	0,128,2,54,12,0,96,172,16,0,162,175,
-	255,255,2,36,20,0,162,175,2,131,2,60,
-	0,155,66,36,98,31,192,12,24,0,162,175,
-	40,0,191,143,36,0,177,143,32,0,176,143,
-	8,0,224,3,48,0,189,39,56,254,189,39,
-	160,1,176,175,33,128,192,0,48,1,164,175,
-	33,32,224,0,64,18,5,0,2,131,3,60,
-	192,246,99,36,33,16,67,0,56,1,162,175,
-	64,18,16,0,33,16,67,0,40,0,168,39,
-	196,1,191,175,192,1,190,175,188,1,183,175,
-	184,1,182,175,180,1,181,175,176,1,180,175,
-	172,1,179,175,168,1,178,175,164,1,177,175,
-	64,1,162,175,12,0,160,24,96,1,168,175,
-	32,133,131,143,0,0,0,0,42,16,163,0,
-	19,1,64,16,1,0,2,36,5,0,0,26,
-	42,16,3,2,15,1,64,16,1,0,2,36,
-	3,0,176,20,33,40,0,0,86,31,192,8,
-	1,0,2,36,212,68,192,12,33,48,0,0,
-	6,0,65,4,104,1,162,175,33,72,64,0,
-	35,72,9,0,104,1,169,175,87,30,192,8,
-	112,1,160,175,1,0,8,36,112,1,168,175,
-	1,0,4,36,133,29,192,12,33,40,0,0,
-	237,29,192,12,33,32,0,2,24,0,169,39,
-	56,1,168,143,255,0,2,36,80,1,169,175,
-	108,0,8,141,43,1,163,39,72,1,168,175,
-	0,0,98,160,255,255,66,36,253,255,65,4,
-	255,255,99,36,64,1,169,143,0,0,0,0,
-	120,0,41,141,64,1,168,143,128,1,169,175,
-	124,0,8,141,64,1,169,143,136,1,168,175,
-	44,0,34,141,0,0,0,0,12,0,64,172,
-	44,0,34,141,0,0,0,0,16,0,64,172,
-	44,0,34,141,120,1,160,175,32,0,64,172,
-	44,0,34,141,88,1,160,175,24,0,64,172,
-	48,1,168,143,0,0,0,0,168,0,0,25,
-	40,0,169,39,144,1,169,175,88,1,168,143,
-	0,0,0,0,255,0,2,49,4,0,86,36,
-	60,0,194,42,2,0,64,16,0,0,0,0,
-	60,0,22,36,104,1,169,143,0,0,0,0,
-	2,0,32,17,0,0,0,0,104,1,182,143,
-	56,1,164,143,72,1,168,143,12,0,2,36,
-	2,0,2,165,80,1,169,143,0,128,194,54,
-	8,0,9,173,12,0,0,173,0,0,34,173,
-	255,255,8,36,4,0,40,173,144,1,168,143,
-	0,0,0,0,8,0,40,173,88,1,168,143,
-	96,1,169,143,208,7,5,36,98,31,192,12,
-	0,0,40,173,0,128,5,52,0,128,6,52,
-	128,1,164,143,0,0,0,0,129,67,192,12,
-	2,0,7,36,13,0,64,20,0,0,0,0,
-	88,1,165,143,2,131,4,60,15,63,192,12,
-	64,141,132,36,120,1,169,143,0,0,0,0,
-	1,0,41,37,20,0,34,41,117,0,64,16,
-	120,1,169,175,32,31,192,8,0,0,0,0,
-	128,1,168,143,64,1,169,143,8,0,2,141,
-	255,255,8,36,136,0,53,141,0,0,0,0,
-	50,0,72,16,33,184,0,0,1,0,4,36,
-	4,0,18,36,4,0,3,36,0,0,190,142,
-	8,0,166,142,112,1,169,143,255,63,212,51,
-	30,0,32,17,33,184,244,2,42,16,116,0,
-	27,0,64,16,33,152,96,0,144,1,168,143,
-	0,0,0,0,33,136,72,2,33,128,102,0,
-	15,0,128,16,0,0,0,0,0,0,2,146,
-	0,0,35,146,0,0,0,0,10,0,67,16,
-	33,48,192,2,2,131,4,60,92,141,132,36,
-	88,1,165,143,16,0,163,175,0,0,2,146,
-	33,56,64,2,15,63,192,12,20,0,162,175,
-	33,32,0,0,1,0,115,38,1,0,16,38,
-	1,0,49,38,42,16,116,2,235,255,64,20,
-	1,0,82,38,33,24,0,0,4,0,181,142,
-	0,128,194,51,217,255,64,16,0,0,0,0,
-	128,1,169,143,0,0,0,0,8,0,34,141,
-	0,0,0,0,25,0,128,16,18,0,87,164,
-	9,0,246,18,33,48,192,2,2,131,4,60,
-	140,141,132,36,88,1,165,143,0,0,0,0,
-	15,63,192,12,33,56,224,2,5,31,192,8,
-	0,0,0,0,64,1,168,143,0,0,0,0,
-	136,0,2,141,96,1,169,143,8,0,70,140,
-	0,0,34,141,0,0,198,140,0,0,0,0,
-	7,0,194,16,0,0,0,0,88,1,165,143,
-	2,131,4,60,15,63,192,12,184,141,132,36,
-	64,1,168,143,0,0,0,0,136,0,4,141,
-	152,21,192,12,0,0,0,0,64,1,169,143,
-	0,0,0,0,136,0,53,173,128,1,168,143,
-	8,128,2,52,0,0,0,165,2,0,2,165,
-	8,0,0,173,12,0,0,165,136,1,169,143,
-	8,0,2,36,2,0,34,165,4,0,40,141,
-	128,1,169,143,136,1,168,175,4,0,41,141,
-	64,1,168,143,128,1,169,175,120,0,9,173,
-	136,1,169,143,0,0,0,0,124,0,9,173,
-	88,1,168,143,48,1,169,143,1,0,8,37,
-	42,16,9,1,91,255,64,20,88,1,168,175,
-	64,1,168,143,0,0,0,0,44,0,3,141,
-	0,0,0,0,12,0,98,140,0,0,0,0,
-	5,0,64,16,0,0,0,0,12,0,101,140,
-	2,131,4,60,15,63,192,12,212,141,132,36,
-	64,1,169,143,0,0,0,0,44,0,35,141,
-	0,0,0,0,16,0,98,140,0,0,0,0,
-	5,0,64,16,0,0,0,0,16,0,101,140,
-	2,131,4,60,15,63,192,12,240,141,132,36,
-	64,1,168,143,0,0,0,0,44,0,3,141,
-	0,0,0,0,32,0,98,140,0,0,0,0,
-	5,0,64,16,0,0,0,0,32,0,101,140,
-	2,131,4,60,15,63,192,12,16,142,132,36,
-	64,1,169,143,0,0,0,0,44,0,35,141,
-	0,0,0,0,24,0,98,140,0,0,0,0,
-	5,0,64,16,0,0,0,0,24,0,101,140,
-	2,131,4,60,15,63,192,12,48,142,132,36,
-	196,1,191,143,192,1,190,143,188,1,183,143,
-	184,1,182,143,180,1,181,143,176,1,180,143,
-	172,1,179,143,168,1,178,143,164,1,177,143,
-	160,1,176,143,8,0,224,3,200,1,189,39,
-	224,255,189,39,16,0,176,175,33,128,128,0,
-	24,0,191,175,20,0,177,175,44,0,4,142,
-	0,0,0,0,0,0,130,148,0,0,0,0,
-	0,32,66,48,7,0,64,20,33,136,160,0,
-	0,0,133,148,2,131,4,60,15,63,192,12,
-	80,142,132,36,156,31,192,8,3,0,2,36,
-	2,0,132,36,33,40,0,0,33,48,0,0,
-	129,67,192,12,33,56,32,2,13,0,64,16,
-	33,40,0,0,44,0,3,142,0,33,2,36,
-	2,0,98,164,8,0,2,142,33,48,0,0,
-	0,0,64,172,44,0,4,142,33,56,32,2,
-	129,67,192,12,2,0,132,36,9,0,64,20,
-	0,32,5,36,44,0,2,142,0,0,0,0,
-	2,0,69,148,2,131,4,60,15,63,192,12,
-	108,142,132,36,156,31,192,8,1,0,2,36,
-	44,0,4,142,0,32,6,36,129,67,192,12,
-	33,56,32,2,8,0,64,20,33,16,0,0,
-	44,0,2,142,0,0,0,0,0,0,69,148,
-	2,131,4,60,15,63,192,12,132,142,132,36,
-	2,0,2,36,24,0,191,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,32,0,189,39,
-	224,255,189,39,24,0,178,175,33,144,160,0,
-	28,0,191,175,20,0,177,175,7,0,128,4,
-	16,0,176,175,24,133,130,143,0,0,0,0,
-	255,255,66,36,42,16,68,0,4,0,64,16,
-	33,136,128,0,24,133,130,143,33,32,0,0,
-	255,255,81,36,33,128,128,0,42,16,48,2,
-	7,0,64,20,33,32,0,2,193,31,192,12,
-	33,40,64,2,1,0,16,38,42,16,48,2,
-	251,255,64,16,33,32,0,2,28,0,191,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,8,0,224,3,
-	0,0,0,0,232,255,189,39,16,0,191,175,
-	236,63,192,12,1,16,4,36,85,0,2,36,
-	131,131,1,60,128,18,34,160,16,0,191,143,
-	24,0,189,39,8,0,224,3,0,0,0,0,
-	216,255,189,39,28,0,177,175,33,136,128,0,
-	32,0,178,175,33,144,160,0,212,128,132,39,
-	36,0,191,175,15,63,192,12,24,0,176,175,
-	9,0,64,26,33,128,0,0,0,0,37,146,
-	1,0,49,38,220,128,132,39,15,63,192,12,
-	1,0,16,38,42,16,18,2,249,255,64,20,
-	0,0,0,0,228,128,132,39,15,63,192,12,
-	0,0,0,0,36,0,191,143,32,0,178,143,
-	28,0,177,143,24,0,176,143,8,0,224,3,
-	40,0,189,39,48,255,189,39,33,56,128,0,
-	192,0,178,175,33,144,160,0,200,0,180,175,
-	33,160,192,0,255,255,226,36,6,0,66,44,
-	204,0,191,175,196,0,179,175,188,0,177,175,
-	2,0,64,20,184,0,176,175,1,0,7,36,
-	2,0,64,30,0,0,0,0,1,0,18,36,
-	2,0,128,30,64,18,7,0,60,0,20,36,
-	2,131,3,60,192,246,99,36,33,136,67,0,
-	4,0,34,142,0,0,0,0,4,0,64,20,
-	33,152,64,2,1,0,4,36,133,29,192,12,
-	33,40,224,0,255,31,4,60,255,255,132,52,
-	0,128,133,54,120,0,162,39,36,16,68,0,
-	0,160,3,60,37,16,67,0,104,0,165,175,
-	108,0,160,175,112,0,162,175,12,0,2,36,
-	80,0,160,167,82,0,162,167,80,0,162,39,
-	36,16,68,0,37,128,67,0,104,0,162,39,
-	36,16,68,0,232,128,132,143,37,16,67,0,
-	84,0,176,175,88,0,162,175,92,0,160,175,
-	5,0,128,16,4,0,2,36,82,0,162,167,
-	255,255,2,36,92,0,165,175,88,0,162,175,
-	44,0,34,142,0,0,0,0,0,0,66,148,
-	0,0,0,0,0,32,66,48,7,0,64,20,
-	33,40,0,0,255,255,4,36,2,131,5,60,
-	184,142,165,36,188,7,192,12,208,1,6,36,
-	33,40,0,0,44,0,34,142,33,48,0,0,
-	4,0,80,172,44,0,36,142,208,7,7,36,
-	129,67,192,12,2,0,132,36,12,0,64,20,
-	0,0,0,0,44,0,34,142,0,0,0,0,
-	2,0,69,148,2,131,4,60,15,63,192,12,
-	108,142,132,36,255,255,4,36,2,131,5,60,
-	184,142,165,36,188,7,192,12,216,1,6,36,
-	34,11,192,12,1,0,4,36,0,163,16,60,
-	4,1,16,142,0,163,2,60,4,1,66,140,
-	0,0,0,0,252,255,2,18,0,33,3,36,
-	44,0,34,142,0,0,0,0,2,0,67,164,
-	8,0,34,142,0,0,0,0,0,0,64,172,
-	0,163,16,60,4,1,16,142,44,0,36,142,
-	0,0,0,0,4,0,130,140,0,0,0,0,
-	0,0,66,148,0,0,0,0,0,128,66,48,
-	10,0,64,20,0,0,0,0,44,0,35,142,
-	0,0,0,0,4,0,98,140,0,0,0,0,
-	0,0,66,148,0,0,0,0,0,128,66,48,
-	250,255,64,16,0,0,0,0,255,255,115,38,
-	19,0,96,18,33,40,64,2,44,0,35,142,
-	0,0,0,0,4,0,98,140,0,0,0,0,
-	0,0,66,148,0,0,0,0,0,128,66,48,
-	229,255,64,16,0,0,0,0,4,0,98,140,
-	0,0,0,0,0,0,66,148,0,0,0,0,
-	0,128,66,48,250,255,64,20,0,0,0,0,
-	89,32,192,8,0,0,0,0,2,131,4,60,
-	200,142,132,36,33,48,128,2,0,163,3,60,
-	4,1,99,140,0,128,2,52,82,0,162,167,
-	35,128,112,0,15,63,192,12,33,56,0,2,
-	19,0,0,18,64,41,18,0,35,40,178,0,
-	128,40,5,0,33,40,178,0,192,40,5,0,
-	26,0,176,0,2,0,0,22,0,0,0,0,
-	13,0,7,0,255,255,1,36,4,0,1,22,
-	0,128,1,60,2,0,161,20,0,0,0,0,
-	13,0,6,0,18,40,0,0,236,128,132,39,
-	15,63,192,12,0,0,0,0,204,0,191,143,
-	200,0,180,143,196,0,179,143,192,0,178,143,
-	188,0,177,143,184,0,176,143,8,0,224,3,
-	208,0,189,39,224,255,189,39,20,0,177,175,
-	33,136,128,0,24,0,191,175,180,10,192,12,
-	16,0,176,175,34,11,192,12,1,0,4,36,
-	16,133,132,143,0,163,16,60,4,1,16,142,
-	193,63,192,12,0,0,0,0,0,163,2,60,
-	4,1,66,140,0,0,0,0,35,40,80,0,
-	73,252,162,36,99,0,66,44,4,0,64,16,
-	0,0,0,0,2,131,4,60,196,32,192,8,
-	0,143,132,36,5,0,160,20,0,0,0,0,
-	2,131,4,60,36,143,132,36,196,32,192,8,
-	33,40,0,0,2,131,4,60,76,143,132,36,
-	15,63,192,12,1,0,16,36,3,0,48,18,
-	0,0,0,0,34,11,192,12,33,32,0,0,
-	0,129,144,175,24,0,191,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,32,0,189,39,
-	200,255,189,39,32,0,178,175,33,144,128,0,
-	33,48,64,2,44,0,181,175,1,131,21,60,
-	60,252,181,38,33,56,160,2,40,0,180,175,
-	2,131,20,60,144,143,148,38,36,0,179,175,
-	0,163,19,60,120,1,115,142,0,163,3,60,
-	120,1,99,140,32,131,2,60,48,0,191,175,
-	28,0,177,175,24,0,176,175,16,0,180,175,
-	33,32,96,2,35,136,67,0,84,64,192,12,
-	33,40,32,2,3,0,64,18,33,128,64,0,
-	10,0,0,22,0,0,0,0,16,0,180,175,
-	33,32,96,2,33,40,32,2,33,48,64,2,
-	244,63,192,12,33,56,160,2,33,128,2,2,
-	5,0,0,18,33,40,96,2,2,131,4,60,
-	168,143,132,36,252,32,192,8,33,40,96,2,
-	2,131,4,60,204,143,132,36,15,63,192,12,
-	33,48,177,0,48,0,191,143,44,0,181,143,
-	40,0,180,143,36,0,179,143,32,0,178,143,
-	28,0,177,143,24,0,176,143,8,0,224,3,
-	56,0,189,39,0,163,1,60,232,5,36,172,
-	0,163,1,60,8,0,224,3,236,5,37,172,
-	28,129,132,175,8,0,224,3,0,0,0,0,
-	16,129,132,175,8,0,224,3,0,0,0,0,
-	15,0,132,48,20,129,132,175,8,0,224,3,
-	0,0,0,0,24,129,132,175,8,0,224,3,
-	0,0,0,0,32,129,132,175,8,0,224,3,
-	0,0,0,0,33,72,128,0,33,80,160,0,
-	33,88,192,0,7,162,4,60,48,1,132,52,
-	7,162,8,60,0,1,8,53,20,129,130,143,
-	24,129,131,143,128,48,2,0,28,129,130,143,
-	3,0,197,52,2,0,96,16,0,0,130,172,
-	67,0,197,52,16,129,130,143,0,0,0,0,
-	2,0,64,16,33,24,160,0,0,1,99,52,
-	36,129,130,143,0,0,0,0,2,0,64,16,
-	0,0,0,0,0,4,99,52,32,129,130,143,
-	0,0,3,173,3,0,64,16,7,162,5,60,
-	0,0,2,173,7,162,5,60,4,1,165,52,
-	7,162,6,60,8,1,198,52,255,0,2,60,
-	255,255,66,52,7,162,3,60,12,1,99,52,
-	7,162,4,60,16,1,132,52,36,16,66,1,
-	0,0,169,172,0,0,194,172,43,16,7,0,
-	192,16,2,0,0,0,107,172,8,0,224,3,
-	0,0,130,172,7,162,3,60,40,1,99,52,
-	3,0,2,36,0,163,1,60,20,1,32,172,
-	8,0,224,3,0,0,98,172,232,255,189,39,
-	16,0,191,175,33,24,0,0,7,162,6,60,
-	40,1,198,52,15,0,4,60,63,66,132,52,
-	0,0,197,140,0,0,0,0,16,0,162,48,
-	7,0,64,20,1,0,99,36,42,16,131,0,
-	249,255,64,16,0,0,0,0,2,131,4,60,
-	122,33,192,8,240,143,132,36,36,129,130,143,
-	0,0,0,0,3,0,64,20,33,24,0,0,
-	125,33,192,8,33,16,0,0,1,0,5,36,
-	15,0,4,60,63,66,132,52,0,163,2,60,
-	20,1,66,140,0,0,0,0,247,255,69,16,
-	1,0,99,36,42,16,131,0,249,255,64,16,
-	0,0,0,0,0,163,5,60,20,1,165,140,
-	2,131,4,60,24,144,132,36,15,63,192,12,
-	0,0,0,0,1,0,2,36,16,0,191,143,
-	24,0,189,39,8,0,224,3,0,0,0,0,
-	224,255,189,39,24,0,191,175,33,72,192,0,
-	255,31,3,60,255,255,99,52,33,64,0,0,
-	36,32,131,0,0,160,2,60,37,32,130,0,
-	36,40,163,0,16,0,32,25,37,40,162,0,
-	0,0,134,144,0,0,167,144,0,0,0,0,
-	7,0,199,16,1,0,165,36,2,131,4,60,
-	72,144,132,36,15,63,192,12,33,40,0,1,
-	157,33,192,8,1,0,2,36,1,0,8,37,
-	42,16,9,1,242,255,64,20,1,0,132,36,
-	33,16,0,0,24,0,191,143,32,0,189,39,
-	8,0,224,3,0,0,0,0,0,163,2,60,
-	232,5,66,140,152,255,189,39,80,0,180,175,
-	120,0,180,143,64,0,176,175,33,128,160,0,
-	68,0,177,175,33,136,192,0,72,0,178,175,
-	33,144,224,0,100,0,191,175,96,0,190,175,
-	92,0,183,175,88,0,182,175,84,0,181,175,
-	76,0,179,175,12,0,64,16,16,0,164,175,
-	0,163,2,60,236,5,66,140,0,0,0,0,
-	7,0,64,16,0,0,0,0,0,163,2,60,
-	236,5,66,140,0,0,0,0,1,8,66,44,
-	10,0,64,20,16,0,2,60,0,163,5,60,
-	232,5,165,140,0,163,6,60,236,5,198,140,
-	2,131,4,60,15,63,192,12,124,144,132,36,
-	7,35,192,8,0,0,0,0,16,0,168,143,
-	0,0,0,0,43,16,72,0,6,0,64,16,
-	0,0,0,0,2,131,4,60,15,63,192,12,
-	172,144,132,36,7,35,192,8,0,0,0,0,
-	224,132,130,143,0,0,0,0,11,0,64,20,
-	0,0,0,0,0,163,4,60,236,5,132,140,
-	13,8,192,12,0,0,0,0,255,31,3,60,
-	255,255,99,52,36,16,67,0,0,160,3,60,
-	37,16,67,0,224,132,130,175,228,132,130,143,
-	0,0,0,0,11,0,64,20,0,0,0,0,
-	0,163,4,60,236,5,132,140,13,8,192,12,
-	0,0,0,0,255,31,3,60,255,255,99,52,
-	36,16,67,0,0,160,3,60,37,16,67,0,
-	228,132,130,175,224,132,133,143,0,163,6,60,
-	232,5,198,140,228,132,135,143,2,131,4,60,
-	15,63,192,12,208,144,132,36,16,129,133,143,
-	20,129,134,143,2,131,4,60,15,63,192,12,
-	8,145,132,36,7,162,2,60,232,0,66,52,
-	0,0,83,140,1,0,3,130,105,0,2,36,
-	7,0,98,20,251,255,2,60,1,0,2,36,
-	36,129,130,175,4,0,2,60,0,8,66,52,
-	10,34,192,8,37,152,98,2,36,129,128,175,
-	255,247,66,52,36,152,98,2,7,162,2,60,
-	232,0,66,52,0,0,83,172,0,0,5,130,
-	114,0,2,36,3,0,162,16,82,0,2,36,
-	3,0,162,20,119,0,2,36,42,34,192,8,
-	33,176,0,0,3,0,162,16,87,0,2,36,
-	3,0,162,20,108,0,2,36,42,34,192,8,
-	1,0,22,36,3,0,162,16,76,0,2,36,
-	3,0,162,20,116,0,2,36,42,34,192,8,
-	2,0,22,36,118,0,162,16,84,0,2,36,
-	116,0,162,16,0,0,0,0,2,131,4,60,
-	15,63,192,12,52,145,132,36,7,35,192,8,
-	0,0,0,0,0,0,38,130,0,0,0,0,
-	12,0,192,16,99,0,2,36,3,0,194,16,
-	67,0,2,36,4,0,194,20,33,152,0,0,
-	5,0,19,36,61,34,192,8,5,0,21,36,
-	2,131,1,60,80,155,50,160,61,34,192,8,
-	33,168,0,0,33,168,0,0,5,0,19,36,
-	2,131,1,60,80,155,32,160,16,0,168,143,
-	0,163,18,60,236,5,82,142,0,0,0,0,
-	197,0,0,17,255,255,20,37,255,255,194,38,
-	2,0,87,44,2,0,30,36,33,128,160,2,
-	42,16,112,2,73,0,64,20,0,0,0,0,
-	42,0,224,18,5,0,2,36,13,0,2,22,
-	0,0,0,0,25,0,64,26,33,136,0,0,
-	224,132,130,143,0,0,0,0,33,16,81,0,
-	0,0,81,160,1,0,49,38,42,16,50,2,
-	249,255,64,20,33,48,64,2,105,34,192,8,
-	0,0,0,0,2,131,3,60,33,24,112,0,
-	80,155,99,144,0,0,0,0,9,0,64,26,
-	33,136,0,0,224,132,130,143,0,0,0,0,
-	33,16,81,0,1,0,49,38,0,0,67,160,
-	42,16,50,2,249,255,64,20,0,0,0,0,
-	33,48,64,2,0,163,4,60,232,5,132,140,
-	224,132,133,143,0,0,0,0,28,33,192,12,
-	1,0,7,36,76,33,192,12,0,0,0,0,
-	83,33,192,12,0,0,0,0,147,0,64,20,
-	0,0,0,0,3,0,192,18,33,48,64,2,
-	22,0,222,22,0,0,0,0,0,163,4,60,
-	232,5,132,140,228,132,133,143,0,0,0,0,
-	28,33,192,12,33,56,0,0,76,33,192,12,
-	0,0,0,0,83,33,192,12,0,0,0,0,
-	131,0,64,20,0,0,0,0,8,0,222,22,
-	0,0,0,0,224,132,132,143,228,132,133,143,
-	0,0,0,0,129,33,192,12,33,48,64,2,
-	122,0,64,20,0,0,0,0,1,0,16,38,
-	42,16,112,2,185,255,64,16,0,0,0,0,
-	255,255,148,38,255,255,2,36,178,255,130,22,
-	33,128,160,2,7,35,192,8,0,0,0,0,
-	180,10,192,12,0,0,0,0,34,11,192,12,
-	1,0,4,36,0,0,34,130,0,0,0,0,
-	6,0,64,16,33,184,0,0,24,0,160,175,
-	2,131,1,60,88,155,52,164,171,34,192,8,
-	33,176,0,0,6,0,23,36,4,0,2,36,
-	24,0,160,175,2,131,1,60,88,155,34,164,
-	33,176,0,0,0,8,30,36,24,0,177,143,
-	0,0,0,0,42,16,241,2,83,0,64,20,
-	64,16,17,0,2,131,8,60,88,155,8,37,
-	33,168,72,0,0,0,178,150,0,0,0,0,
-	26,0,210,3,2,0,64,22,0,0,0,0,
-	13,0,7,0,255,255,1,36,4,0,65,22,
-	0,128,1,60,2,0,193,23,0,0,0,0,
-	13,0,6,0,18,16,0,0,16,0,168,143,
-	0,0,0,0,24,0,72,0,33,56,192,2,
-	33,128,0,0,0,163,19,60,4,1,115,142,
-	0,163,4,60,232,5,132,140,224,132,133,143,
-	18,160,0,0,0,0,0,0,0,0,0,0,
-	28,33,192,12,33,48,64,2,10,0,128,26,
-	0,0,0,0,76,33,192,12,0,0,0,0,
-	83,33,192,12,0,0,0,0,48,0,64,20,
-	1,0,16,38,42,16,20,2,248,255,64,20,
-	0,0,0,0,2,131,5,60,140,145,165,36,
-	0,163,16,60,4,1,16,142,3,0,192,18,
-	0,0,0,0,2,131,5,60,128,145,165,36,
-	2,131,4,60,96,145,132,36,15,63,192,12,
-	33,48,64,2,19,0,19,18,24,0,146,2,
-	18,24,0,0,35,16,19,2,0,0,0,0,
-	27,0,98,0,2,0,64,20,0,0,0,0,
-	13,0,7,0,18,16,0,0,2,131,4,60,
-	152,145,132,36,64,41,2,0,35,40,162,0,
-	128,40,5,0,33,40,162,0,15,63,192,12,
-	192,40,5,0,255,34,192,8,2,0,181,38,
-	2,131,4,60,168,145,132,36,15,63,192,12,
-	2,0,181,38,1,0,49,38,42,16,241,2,
-	178,255,64,16,0,0,0,0,1,0,214,38,
-	2,0,194,42,166,255,64,20,0,0,0,0,
-	100,0,191,143,96,0,190,143,92,0,183,143,
-	88,0,182,143,84,0,181,143,80,0,180,143,
-	76,0,179,143,72,0,178,143,68,0,177,143,
-	64,0,176,143,8,0,224,3,104,0,189,39,
-	0,0,0,0,43,16,134,0,0,0,164,175,
-	4,0,165,175,8,0,166,175,7,0,64,20,
-	12,0,167,175,43,16,196,0,5,0,64,20,
-	1,0,2,36,43,16,167,0,2,0,64,16,
-	43,16,229,0,255,255,2,36,8,0,224,3,
-	0,0,0,0,232,255,189,39,3,131,4,60,
-	208,12,132,36,170,0,5,36,16,0,191,175,
-	144,71,192,12,60,0,6,36,2,131,6,60,
-	112,155,198,36,2,131,2,60,212,246,66,140,
-	2,131,3,60,216,246,99,132,0,0,194,172,
-	4,0,195,164,2,131,2,60,138,155,66,148,
-	2,131,3,60,132,155,99,148,2,131,4,60,
-	134,155,132,148,2,131,5,60,136,155,165,148,
-	3,131,1,60,216,12,34,164,2,131,2,60,
-	130,155,66,148,3,131,10,60,218,12,74,37,
-	3,0,199,136,0,0,199,152,4,0,200,128,
-	5,0,201,128,3,0,71,169,0,0,71,185,
-	4,0,72,161,5,0,73,161,3,131,1,60,
-	238,12,35,164,3,131,1,60,242,12,36,164,
-	3,131,1,60,246,12,37,164,3,131,1,60,
-	240,12,34,164,16,0,191,143,24,0,189,39,
-	8,0,224,3,0,0,0,0,3,131,2,60,
-	216,12,66,140,3,131,3,60,220,12,99,140,
-	3,131,1,60,208,12,34,172,3,131,1,60,
-	212,12,35,172,3,131,2,60,238,12,66,148,
-	3,131,3,60,240,12,99,148,3,131,4,60,
-	242,12,132,148,232,255,189,39,16,0,176,175,
-	3,131,1,60,234,12,35,164,24,133,131,143,
-	20,0,191,175,3,131,1,60,224,12,32,172,
-	3,131,1,60,228,12,32,172,3,131,1,60,
-	248,12,32,172,3,131,1,60,252,12,32,172,
-	3,131,1,60,8,13,32,164,3,131,1,60,
-	4,13,32,164,3,131,1,60,232,12,34,164,
-	33,16,68,0,3,131,1,60,236,12,36,164,
-	3,131,1,60,244,12,34,164,8,0,96,24,
-	1,0,16,36,150,35,192,12,33,32,0,2,
-	24,133,130,143,1,0,16,38,42,16,80,0,
-	250,255,64,16,0,0,0,0,206,35,192,12,
-	0,0,0,0,52,36,192,12,0,0,0,0,
-	1,0,2,36,3,131,1,60,0,13,34,164,
-	3,0,2,36,3,131,1,60,2,13,32,164,
-	3,131,1,60,20,13,34,172,2,131,1,60,
-	164,247,34,172,20,0,191,143,16,0,176,143,
-	8,0,224,3,24,0,189,39,224,255,189,39,
-	20,0,177,175,33,136,128,0,16,0,176,175,
-	192,129,17,0,3,131,4,60,16,13,132,36,
-	33,32,4,2,187,0,5,36,24,0,191,175,
-	144,71,192,12,128,0,6,36,2,131,2,60,
-	140,155,66,148,100,0,3,36,3,131,1,60,
-	33,8,48,0,24,13,35,172,0,18,2,0,
-	37,16,34,2,3,131,1,60,33,8,48,0,
-	16,13,34,164,22,36,192,12,33,32,32,2,
-	4,0,2,36,64,138,17,0,3,131,1,60,
-	33,8,48,0,20,13,34,172,2,131,1,60,
-	33,8,49,0,164,247,34,172,3,131,1,60,
-	33,8,48,0,52,13,32,172,3,131,1,60,
-	33,8,48,0,56,13,32,172,3,131,1,60,
-	33,8,48,0,106,13,32,164,3,131,1,60,
-	33,8,48,0,110,13,32,164,3,131,1,60,
-	33,8,48,0,114,13,32,164,3,131,1,60,
-	33,8,48,0,120,13,32,172,24,0,191,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,24,133,130,143,216,255,189,39,
-	20,0,177,175,1,0,17,36,36,0,191,175,
-	32,0,180,175,28,0,179,175,24,0,178,175,
-	55,0,64,24,16,0,176,175,3,131,20,60,
-	228,12,148,38,3,131,2,60,56,13,66,36,
-	128,0,83,36,124,0,82,36,128,0,16,36,
-	0,0,130,142,0,0,0,0,6,0,34,22,
-	33,32,32,2,0,0,64,174,101,36,192,12,
-	0,0,96,174,8,36,192,8,128,0,115,38,
-	3,131,4,60,33,32,144,0,40,13,132,140,
-	3,131,5,60,33,40,176,0,44,13,165,140,
-	244,255,134,142,248,255,135,142,20,35,192,12,
-	0,0,0,0,17,0,64,20,33,32,32,2,
-	3,131,3,60,33,24,112,0,48,13,99,148,
-	3,131,2,60,33,16,80,0,16,13,66,148,
-	0,0,0,0,8,0,98,20,0,0,0,0,
-	3,131,1,60,33,8,48,0,106,13,32,164,
-	101,36,192,12,33,32,32,2,8,36,192,8,
-	128,0,115,38,0,0,64,174,125,36,192,12,
-	0,0,96,174,128,0,115,38,128,0,82,38,
-	24,133,130,143,1,0,49,38,42,16,81,0,
-	210,255,64,16,128,0,16,38,36,0,191,143,
-	32,0,180,143,28,0,179,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	40,0,189,39,192,33,4,0,3,131,2,60,
-	28,13,66,36,33,24,130,0,3,131,5,60,
-	208,12,165,140,3,131,6,60,212,12,198,140,
-	0,0,101,172,4,0,102,172,12,0,66,36,
-	3,131,3,60,224,12,99,140,33,16,130,0,
-	3,131,1,60,33,8,36,0,36,13,35,172,
-	3,131,3,60,216,12,99,140,3,131,5,60,
-	220,12,165,140,0,0,67,172,4,0,69,172,
-	3,131,2,60,33,16,68,0,16,13,66,148,
-	3,131,1,60,33,8,36,0,8,0,224,3,
-	48,13,34,164,24,133,130,143,224,255,189,39,
-	20,0,177,175,1,0,17,36,24,0,191,175,
-	38,0,64,24,16,0,176,175,128,0,16,36,
-	3,131,4,60,33,32,144,0,40,13,132,140,
-	3,131,5,60,33,40,176,0,44,13,165,140,
-	3,131,6,60,216,12,198,140,3,131,7,60,
-	220,12,231,140,20,35,192,12,0,0,0,0,
-	18,0,64,20,0,0,0,0,3,131,3,60,
-	33,24,112,0,48,13,99,148,3,131,2,60,
-	33,16,80,0,16,13,66,148,0,0,0,0,
-	9,0,98,20,0,0,0,0,3,131,2,60,
-	33,16,80,0,20,13,66,140,0,0,0,0,
-	3,0,64,16,0,0,0,0,203,36,192,12,
-	33,32,32,2,24,133,130,143,1,0,49,38,
-	42,16,81,0,221,255,64,16,128,0,16,38,
-	24,0,191,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,192,41,4,0,
-	3,131,3,60,33,24,101,0,20,13,99,140,
-	4,0,2,36,16,0,98,20,240,255,189,39,
-	1,0,2,36,64,26,4,0,3,131,1,60,
-	33,8,37,0,20,13,34,172,2,131,1,60,
-	33,8,35,0,164,247,34,172,1,0,2,36,
-	3,131,1,60,33,8,37,0,110,13,34,164,
-	3,131,1,60,33,8,37,0,112,13,32,164,
-	8,0,224,3,16,0,189,39,224,255,189,39,
-	24,0,178,175,33,144,128,0,16,0,176,175,
-	192,129,18,0,28,0,191,175,20,0,177,175,
-	3,131,2,60,33,16,80,0,20,13,66,140,
-	0,0,0,0,18,0,64,16,4,0,17,36,
-	16,0,81,16,254,255,66,36,2,0,66,44,
-	4,0,64,16,64,18,18,0,161,36,192,12,
-	0,0,0,0,64,18,18,0,3,131,1,60,
-	33,8,48,0,20,13,49,172,2,131,1,60,
-	33,8,34,0,164,247,49,172,3,131,1,60,
-	33,8,48,0,110,13,32,164,28,0,191,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,3,131,4,60,
-	208,12,132,140,3,131,5,60,212,12,165,140,
-	3,131,6,60,216,12,198,140,3,131,7,60,
-	220,12,231,140,232,255,189,39,16,0,191,175,
-	20,35,192,12,0,0,0,0,10,0,64,20,
-	1,0,2,36,3,131,1,60,252,12,34,172,
-	1,0,2,36,3,131,1,60,4,13,34,164,
-	3,131,1,60,6,13,32,164,197,36,192,8,
-	1,0,2,36,3,131,2,60,248,12,66,140,
-	0,0,0,0,9,0,64,20,1,0,2,36,
-	72,37,192,12,0,0,0,0,1,0,2,36,
-	3,131,1,60,8,13,34,164,3,131,1,60,
-	10,13,32,164,1,0,2,36,3,131,1,60,
-	248,12,34,172,16,0,191,143,24,0,189,39,
-	8,0,224,3,0,0,0,0,224,255,189,39,
-	20,0,177,175,33,136,128,0,16,0,176,175,
-	192,129,17,0,24,0,191,175,3,131,2,60,
-	33,16,80,0,114,13,66,132,0,0,0,0,
-	5,0,64,16,1,0,2,36,3,131,1,60,
-	33,8,48,0,67,37,192,8,56,13,34,172,
-	3,131,4,60,208,12,132,36,3,131,2,60,
-	64,13,66,36,33,24,2,2,3,131,1,60,
-	33,8,48,0,60,13,32,164,0,0,133,140,
-	4,0,134,140,0,0,101,172,4,0,102,172,
-	12,0,66,36,3,131,3,60,224,12,99,140,
-	33,16,2,2,3,131,1,60,33,8,48,0,
-	72,13,35,172,3,131,3,60,216,12,99,140,
-	3,131,5,60,220,12,165,140,0,0,67,172,
-	4,0,69,172,3,131,2,60,33,16,80,0,
-	16,13,66,148,3,131,1,60,33,8,48,0,
-	84,13,34,164,0,0,132,140,3,131,5,60,
-	212,12,165,140,3,131,6,60,216,12,198,140,
-	3,131,7,60,220,12,231,140,20,35,192,12,
-	0,0,0,0,5,0,64,20,0,0,0,0,
-	3,131,1,60,33,8,48,0,22,37,192,8,
-	86,13,32,164,3,131,2,60,228,12,66,140,
-	2,131,3,60,128,155,99,148,192,17,2,0,
-	3,131,1,60,33,8,34,0,108,13,34,148,
-	0,0,0,0,33,16,67,0,3,131,1,60,
-	33,8,48,0,86,13,34,164,3,131,2,60,
-	232,12,66,148,192,129,17,0,3,131,1,60,
-	33,8,48,0,88,13,34,164,3,131,2,60,
-	234,12,66,148,33,32,32,2,3,131,1,60,
-	33,8,48,0,90,13,34,164,3,131,3,60,
-	236,12,99,148,3,131,2,60,33,16,80,0,
-	52,13,66,140,3,131,5,60,60,13,165,36,
-	3,131,1,60,33,8,48,0,52,13,32,172,
-	3,131,1,60,33,8,48,0,96,13,34,172,
-	3,131,1,60,33,8,48,0,92,13,35,164,
-	3,131,2,60,252,12,66,140,3,131,1,60,
-	33,8,48,0,100,13,34,172,80,40,192,12,
-	33,40,5,2,1,0,2,36,3,131,1,60,
-	33,8,48,0,56,13,32,172,3,131,1,60,
-	33,8,48,0,114,13,34,164,3,131,1,60,
-	33,8,48,0,116,13,32,164,24,0,191,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,232,255,189,39,128,0,2,36,
-	3,131,4,60,228,12,132,140,3,131,5,60,
-	104,13,165,36,16,0,191,175,192,25,4,0,
-	3,131,1,60,33,8,35,0,104,13,34,164,
-	151,40,192,12,33,40,101,0,2,131,4,60,
-	15,63,192,12,12,146,132,36,16,0,191,143,
-	24,0,189,39,8,0,224,3,0,0,0,0,
-	232,255,189,39,16,0,191,175,102,37,192,12,
-	0,0,0,0,13,38,192,12,0,0,0,0,
-	16,0,191,143,24,0,189,39,8,0,224,3,
-	0,0,0,0,24,133,130,143,208,255,189,39,
-	24,0,178,175,33,144,0,0,28,0,179,175,
-	1,0,19,36,44,0,191,175,40,0,182,175,
-	36,0,181,175,32,0,180,175,20,0,177,175,
-	110,0,64,24,16,0,176,175,3,131,21,60,
-	216,12,181,38,3,131,22,60,16,13,214,38,
-	128,0,208,38,128,0,20,36,192,17,18,0,
-	3,131,4,60,33,32,148,0,40,13,132,140,
-	3,131,5,60,33,40,180,0,44,13,165,140,
-	0,0,166,142,3,131,7,60,220,12,231,140,
-	0,0,0,0,20,35,192,12,33,136,86,0,
-	10,0,64,20,0,0,0,0,3,131,3,60,
-	33,24,116,0,48,13,99,148,3,131,2,60,
-	33,16,84,0,16,13,66,148,0,0,0,0,
-	74,0,98,16,0,0,0,0,4,0,2,142,
-	0,0,0,0,70,0,64,16,0,0,0,0,
-	12,0,4,142,16,0,5,142,0,0,166,142,
-	3,131,7,60,220,12,231,140,20,35,192,12,
-	0,0,0,0,61,0,65,4,0,0,0,0,
-	58,0,64,18,0,0,0,0,12,0,4,142,
-	16,0,5,142,12,0,38,142,16,0,39,142,
-	20,35,192,12,0,0,0,0,50,0,64,4,
-	0,0,0,0,12,0,4,142,16,0,5,142,
-	12,0,38,142,16,0,39,142,20,35,192,12,
-	0,0,0,0,43,0,64,20,0,0,0,0,
-	20,0,5,142,8,0,3,142,20,0,36,142,
-	8,0,34,142,33,40,163,0,33,32,130,0,
-	43,16,164,0,33,0,64,20,0,0,0,0,
-	32,0,164,20,0,0,0,0,24,0,4,142,
-	28,0,5,142,24,0,38,142,28,0,39,142,
-	20,35,192,12,0,0,0,0,23,0,64,4,
-	0,0,0,0,24,0,4,142,28,0,5,142,
-	24,0,38,142,28,0,39,142,20,35,192,12,
-	0,0,0,0,16,0,64,20,0,0,0,0,
-	32,0,4,150,32,0,35,150,0,0,0,0,
-	43,16,131,0,9,0,64,20,0,0,0,0,
-	8,0,131,20,0,0,0,0,0,0,2,150,
-	0,0,35,150,0,0,0,0,43,16,67,0,
-	2,0,64,16,0,0,0,0,33,144,96,2,
-	128,0,16,38,24,133,130,143,1,0,115,38,
-	42,16,83,0,154,255,64,16,128,0,148,38,
-	3,131,1,60,228,12,50,172,12,0,64,22,
-	192,17,18,0,3,131,2,60,216,12,66,140,
-	3,131,3,60,220,12,99,140,3,131,1,60,
-	208,12,34,172,3,131,1,60,212,12,35,172,
-	3,131,1,60,3,38,192,8,224,12,32,172,
-	3,131,3,60,33,24,98,0,28,13,99,140,
-	3,131,4,60,33,32,130,0,32,13,132,140,
-	3,131,1,60,208,12,35,172,3,131,1,60,
-	212,12,36,172,3,131,3,60,33,24,98,0,
-	36,13,99,140,3,131,1,60,33,8,34,0,
-	24,13,34,140,0,0,0,0,33,24,98,0,
-	3,131,1,60,224,12,35,172,44,0,191,143,
-	40,0,182,143,36,0,181,143,32,0,180,143,
-	28,0,179,143,24,0,178,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,48,0,189,39,
-	24,133,130,143,208,255,189,39,36,0,181,175,
-	1,0,21,36,44,0,191,175,40,0,182,175,
-	32,0,180,175,28,0,179,175,24,0,178,175,
-	20,0,177,175,82,0,64,24,16,0,176,175,
-	3,131,22,60,216,12,214,38,3,131,2,60,
-	48,13,66,36,128,0,84,36,96,0,83,36,
-	124,0,82,36,120,0,81,36,128,0,16,36,
-	0,0,36,142,0,0,69,142,0,0,198,142,
-	3,131,7,60,220,12,231,140,20,35,192,12,
-	0,0,0,0,55,0,64,20,0,0,0,0,
-	0,0,131,150,0,0,98,150,0,0,0,0,
-	50,0,98,20,0,0,0,0,3,131,4,60,
-	33,32,144,0,28,13,132,140,3,131,5,60,
-	33,40,176,0,32,13,165,140,248,255,198,142,
-	3,131,7,60,212,12,231,140,20,35,192,12,
-	0,0,0,0,37,0,64,16,0,0,0,0,
-	8,0,196,142,3,131,3,60,33,24,112,0,
-	36,13,99,140,0,0,0,0,43,16,131,0,
-	29,0,64,20,0,0,0,0,27,0,131,20,
-	0,0,0,0,0,0,196,142,3,131,5,60,
-	220,12,165,140,0,0,38,142,0,0,71,142,
-	20,35,192,12,0,0,0,0,16,0,64,4,
-	0,0,0,0,0,0,196,142,3,131,5,60,
-	220,12,165,140,0,0,38,142,0,0,71,142,
-	20,35,192,12,0,0,0,0,9,0,64,20,
-	0,0,0,0,0,0,99,150,0,0,130,150,
-	0,0,0,0,43,16,67,0,3,0,64,20,
-	0,0,0,0,22,36,192,12,33,32,160,2,
-	128,0,148,38,128,0,115,38,128,0,82,38,
-	128,0,49,38,24,133,130,143,1,0,181,38,
-	42,16,85,0,185,255,64,16,128,0,16,38,
-	44,0,191,143,40,0,182,143,36,0,181,143,
-	32,0,180,143,28,0,179,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	48,0,189,39,216,255,189,39,3,131,4,60,
-	0,13,132,36,32,0,191,175,28,0,179,175,
-	24,0,178,175,20,0,177,175,16,0,176,175,
-	0,0,130,132,0,0,0,0,14,0,64,16,
-	0,0,0,0,3,131,2,60,2,13,66,148,
-	3,131,3,60,234,12,99,148,1,0,66,36,
-	3,131,1,60,2,13,34,164,255,255,66,48,
-	43,16,67,0,3,0,64,20,0,0,0,0,
-	11,39,192,12,0,0,128,164,3,131,4,60,
-	8,13,132,36,0,0,130,132,0,0,0,0,
-	14,0,64,16,0,0,0,0,3,131,2,60,
-	10,13,66,148,3,131,3,60,234,12,99,148,
-	1,0,66,36,3,131,1,60,10,13,34,164,
-	255,255,66,48,43,16,67,0,3,0,64,20,
-	0,0,0,0,24,39,192,12,0,0,128,164,
-	3,131,4,60,4,13,132,36,0,0,130,132,
-	0,0,0,0,14,0,64,16,0,0,0,0,
-	3,131,2,60,6,13,66,148,3,131,3,60,
-	244,12,99,148,1,0,66,36,3,131,1,60,
-	6,13,34,164,255,255,66,48,43,16,67,0,
-	3,0,64,20,0,0,0,0,37,39,192,12,
-	0,0,128,164,24,133,130,143,0,0,0,0,
-	78,0,64,24,1,0,17,36,3,131,2,60,
-	16,13,66,36,226,0,83,36,128,0,82,36,
-	128,0,16,36,3,131,2,60,33,16,80,0,
-	110,13,66,132,0,0,0,0,18,0,64,16,
-	0,0,0,0,3,131,2,60,33,16,80,0,
-	112,13,66,148,0,0,0,0,1,0,66,36,
-	96,0,66,166,3,131,3,60,236,12,99,148,
-	255,255,66,48,43,16,67,0,6,0,64,20,
-	0,0,0,0,3,131,1,60,33,8,48,0,
-	110,13,32,164,79,39,192,12,33,32,32,2,
-	3,131,2,60,33,16,80,0,106,13,66,132,
-	0,0,0,0,18,0,64,16,0,0,0,0,
-	3,131,2,60,33,16,80,0,108,13,66,148,
-	0,0,0,0,1,0,66,36,92,0,66,166,
-	3,131,3,60,232,12,99,148,255,255,66,48,
-	43,16,67,0,6,0,64,20,0,0,0,0,
-	3,131,1,60,33,8,48,0,106,13,32,164,
-	129,39,192,12,33,32,32,2,0,0,98,134,
-	0,0,0,0,16,0,64,16,0,0,0,0,
-	3,131,2,60,33,16,80,0,116,13,66,148,
-	0,0,0,0,1,0,66,36,100,0,66,166,
-	3,131,3,60,246,12,99,148,255,255,66,48,
-	43,16,67,0,4,0,64,20,0,0,0,0,
-	0,0,96,166,191,39,192,12,33,32,32,2,
-	128,0,115,38,128,0,82,38,24,133,130,143,
-	1,0,49,38,42,16,81,0,185,255,64,16,
-	128,0,16,38,32,0,191,143,28,0,179,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,40,0,189,39,232,255,189,39,
-	16,0,191,175,52,36,192,12,0,0,0,0,
-	1,0,2,36,3,131,1,60,0,13,34,164,
-	3,131,1,60,2,13,32,164,16,0,191,143,
-	24,0,189,39,8,0,224,3,0,0,0,0,
-	232,255,189,39,16,0,191,175,72,37,192,12,
-	0,0,0,0,1,0,2,36,3,131,1,60,
-	8,13,34,164,3,131,1,60,10,13,32,164,
-	16,0,191,143,24,0,189,39,8,0,224,3,
-	0,0,0,0,240,255,189,39,3,131,1,60,
-	248,12,32,172,3,131,1,60,252,12,32,172,
-	8,0,224,3,16,0,189,39,24,133,130,143,
-	224,255,189,39,20,0,177,175,1,0,17,36,
-	24,0,191,175,23,0,64,24,16,0,176,175,
-	128,0,16,36,3,131,4,60,33,32,144,0,
-	40,13,132,140,3,131,5,60,33,40,176,0,
-	44,13,165,140,3,131,6,60,216,12,198,140,
-	3,131,7,60,220,12,231,140,20,35,192,12,
-	0,0,0,0,3,0,64,20,1,0,49,38,
-	74,39,192,8,1,0,2,36,24,133,130,143,
-	0,0,0,0,42,16,81,0,236,255,64,16,
-	128,0,16,38,33,16,0,0,24,0,191,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,232,255,189,39,192,41,4,0,
-	16,0,191,175,3,131,3,60,33,24,101,0,
-	20,13,99,140,1,0,2,36,16,0,98,20,
-	2,0,2,36,64,26,4,0,3,131,1,60,
-	33,8,37,0,20,13,34,172,2,131,1,60,
-	33,8,35,0,164,247,34,172,1,0,2,36,
-	3,131,1,60,33,8,37,0,110,13,34,164,
-	3,131,1,60,33,8,37,0,125,39,192,8,
-	112,13,32,164,21,0,98,20,3,0,3,36,
-	64,18,4,0,3,131,1,60,33,8,37,0,
-	20,13,35,172,2,131,1,60,33,8,34,0,
-	164,247,35,172,3,131,2,60,33,16,69,0,
-	120,13,66,140,0,0,0,0,1,0,66,36,
-	3,131,1,60,33,8,37,0,44,39,192,12,
-	120,13,34,172,3,0,64,16,0,0,0,0,
-	161,36,192,12,0,0,0,0,16,0,191,143,
-	24,0,189,39,8,0,224,3,0,0,0,0,
-	224,255,189,39,16,0,176,175,33,128,128,0,
-	20,0,177,175,3,131,17,60,208,12,49,38,
-	24,0,191,175,0,0,36,142,3,131,5,60,
-	212,12,165,140,3,131,6,60,216,12,198,140,
-	3,131,7,60,220,12,231,140,20,35,192,12,
-	0,0,0,0,33,32,0,2,22,36,192,12,
-	1,0,80,44,92,37,192,12,0,0,0,0,
-	206,35,192,12,0,0,0,0,33,0,0,22,
-	0,0,0,0,0,0,36,142,3,131,5,60,
-	212,12,165,140,3,131,6,60,216,12,198,140,
-	3,131,7,60,220,12,231,140,20,35,192,12,
-	0,0,0,0,22,0,64,20,0,0,0,0,
-	3,131,2,60,238,12,66,148,3,131,3,60,
-	240,12,99,148,3,131,4,60,242,12,132,148,
-	3,131,1,60,232,12,34,164,3,131,1,60,
-	234,12,35,164,3,131,1,60,161,36,192,12,
-	236,12,36,164,3,131,1,60,52,36,192,12,
-	8,13,32,164,1,0,2,36,3,131,1,60,
-	0,13,34,164,3,131,1,60,2,13,32,164,
-	24,0,191,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,232,255,189,39,
-	192,17,4,0,16,0,191,175,3,131,1,60,
-	33,8,34,0,56,13,34,140,0,0,0,0,
-	3,0,64,16,0,0,0,0,203,36,192,12,
-	0,0,0,0,16,0,191,143,24,0,189,39,
-	8,0,224,3,0,0,0,0,3,131,1,60,
-	248,12,32,172,3,131,1,60,8,0,224,3,
-	8,13,32,164,232,255,189,39,192,25,4,0,
-	1,0,2,36,16,0,191,175,3,131,1,60,
-	33,8,35,0,203,36,192,12,52,13,34,172,
-	16,0,191,143,24,0,189,39,8,0,224,3,
-	0,0,0,0,192,33,4,0,3,131,2,60,
-	28,13,66,36,33,24,130,0,4,0,166,140,
-	8,0,167,140,0,0,102,172,4,0,103,172,
-	12,0,66,36,12,0,163,140,33,16,130,0,
-	3,131,1,60,33,8,36,0,36,13,35,172,
-	16,0,163,140,20,0,166,140,0,0,67,172,
-	4,0,70,172,24,0,163,148,1,0,2,36,
-	3,131,1,60,33,8,36,0,106,13,34,164,
-	3,131,1,60,33,8,36,0,48,13,35,164,
-	26,0,162,148,3,131,1,60,33,8,36,0,
-	8,0,224,3,108,13,34,164,28,0,130,148,
-	3,131,1,60,232,12,34,164,30,0,130,148,
-	3,131,1,60,234,12,34,164,32,0,130,148,
-	3,131,1,60,236,12,34,164,40,0,130,140,
-	3,131,1,60,8,0,224,3,252,12,34,172,
-	224,255,189,39,16,0,176,175,33,128,160,0,
-	192,25,4,0,3,131,2,60,16,13,66,36,
-	20,0,177,175,33,136,98,0,24,0,191,175,
-	4,0,4,142,8,0,5,142,12,0,38,142,
-	16,0,39,142,20,35,192,12,0,0,0,0,
-	48,0,64,4,1,0,2,36,4,0,4,142,
-	8,0,5,142,12,0,38,142,16,0,39,142,
-	20,35,192,12,0,0,0,0,40,0,64,20,
-	33,16,0,0,12,0,4,142,20,0,35,142,
-	0,0,0,0,43,16,131,0,34,0,64,20,
-	1,0,2,36,32,0,131,20,33,16,0,0,
-	16,0,4,142,20,0,5,142,24,0,38,142,
-	28,0,39,142,20,35,192,12,0,0,0,0,
-	24,0,64,4,1,0,2,36,16,0,4,142,
-	20,0,5,142,24,0,38,142,28,0,39,142,
-	20,35,192,12,0,0,0,0,16,0,64,20,
-	33,16,0,0,16,0,4,142,20,0,5,142,
-	3,131,6,60,216,12,198,140,3,131,7,60,
-	220,12,231,140,20,35,192,12,0,0,0,0,
-	6,0,64,20,1,0,2,36,24,0,3,150,
-	32,0,34,150,0,0,0,0,43,16,67,0,
-	1,0,66,56,24,0,191,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,32,0,189,39,
-	44,133,130,143,216,255,189,39,20,0,177,175,
-	33,136,128,0,32,0,180,175,33,160,160,0,
-	36,0,191,175,28,0,179,175,24,0,178,175,
-	53,0,64,16,16,0,176,175,2,131,19,60,
-	192,4,115,38,33,32,96,2,54,21,192,12,
-	1,0,5,36,33,128,64,0,8,0,0,22,
-	64,26,17,0,2,131,2,60,33,16,67,0,
-	176,247,66,140,33,24,99,2,1,0,66,36,
-	143,40,192,8,240,242,98,172,8,0,4,142,
-	64,146,17,0,20,242,101,38,33,40,69,2,
-	172,41,192,12,33,48,128,2,33,24,64,0,
-	60,0,98,40,2,0,64,16,0,242,98,38,
-	60,0,3,36,33,136,66,2,33,32,32,2,
-	33,40,0,2,1,0,2,36,17,0,2,162,
-	0,128,98,52,0,0,2,174,6,23,192,12,
-	18,0,3,166,10,0,64,20,33,32,0,2,
-	2,131,2,60,33,16,82,0,172,247,66,140,
-	0,0,0,0,1,0,66,36,152,21,192,12,
-	236,0,34,174,143,40,192,8,0,0,0,0,
-	2,131,2,60,33,16,82,0,168,247,66,140,
-	0,0,0,0,1,0,66,36,232,0,34,174,
-	36,0,191,143,32,0,180,143,28,0,179,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,40,0,189,39,44,133,130,143,
-	216,255,189,39,20,0,177,175,33,136,128,0,
-	32,0,180,175,33,160,160,0,36,0,191,175,
-	28,0,179,175,24,0,178,175,53,0,64,16,
-	16,0,176,175,2,131,19,60,192,4,115,38,
-	33,32,96,2,54,21,192,12,1,0,5,36,
-	33,128,64,0,8,0,0,22,64,26,17,0,
-	2,131,2,60,33,16,67,0,176,247,66,140,
-	33,24,99,2,1,0,66,36,214,40,192,8,
-	240,242,98,172,8,0,4,142,64,146,17,0,
-	20,242,101,38,33,40,69,2,74,42,192,12,
-	33,48,128,2,33,24,64,0,60,0,98,40,
-	2,0,64,16,0,242,98,38,60,0,3,36,
-	33,136,66,2,33,32,32,2,33,40,0,2,
-	1,0,2,36,17,0,2,162,0,128,98,52,
-	0,0,2,174,6,23,192,12,18,0,3,166,
-	10,0,64,20,33,32,0,2,2,131,2,60,
-	33,16,82,0,172,247,66,140,0,0,0,0,
-	1,0,66,36,152,21,192,12,236,0,34,174,
-	214,40,192,8,0,0,0,0,2,131,2,60,
-	33,16,82,0,168,247,66,140,0,0,0,0,
-	1,0,66,36,232,0,34,174,36,0,191,143,
-	32,0,180,143,28,0,179,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	40,0,189,39,216,255,189,39,24,0,178,175,
-	33,144,128,0,20,0,177,175,33,136,160,0,
-	16,0,176,175,33,128,192,0,36,0,191,175,
-	32,0,180,175,28,0,179,175,4,0,36,142,
-	8,0,37,142,160,133,134,143,2,131,7,60,
-	180,211,231,140,20,35,192,12,0,0,0,0,
-	11,0,64,20,0,0,0,0,2,131,4,60,
-	144,146,132,36,15,63,192,12,33,40,0,2,
-	100,129,132,39,108,129,134,39,31,21,192,12,
-	6,0,5,38,92,41,192,8,0,0,0,0,
-	3,131,20,60,208,12,148,38,0,0,132,142,
-	3,131,5,60,212,12,165,140,3,131,6,60,
-	216,12,198,140,3,131,7,60,220,12,231,140,
-	0,0,0,0,20,35,192,12,192,129,18,0,
-	3,131,3,60,33,24,112,0,20,13,99,140,
-	0,0,0,0,80,0,96,16,1,0,83,44,
-	33,32,64,2,11,40,192,12,33,40,32,2,
-	50,0,64,16,33,32,64,2,223,39,192,12,
-	33,40,32,2,92,37,192,12,0,0,0,0,
-	206,35,192,12,0,0,0,0,0,0,132,142,
-	3,131,5,60,212,12,165,140,3,131,6,60,
-	216,12,198,140,3,131,7,60,220,12,231,140,
-	20,35,192,12,0,0,0,0,16,0,64,16,
-	0,0,0,0,14,0,96,18,0,0,0,0,
-	3,131,2,60,248,12,66,140,3,131,1,60,
-	9,0,64,16,0,13,32,164,3,131,1,60,
-	72,37,192,12,4,13,32,164,1,0,2,36,
-	3,131,1,60,8,13,34,164,3,131,1,60,
-	10,13,32,164,3,131,2,60,228,12,66,140,
-	0,0,0,0,38,0,66,22,0,0,0,0,
-	254,39,192,12,33,32,32,2,52,36,192,12,
-	0,0,0,0,36,0,34,142,0,0,0,0,
-	30,0,64,16,0,0,0,0,206,39,192,12,
-	0,0,0,0,92,41,192,8,0,0,0,0,
-	3,131,4,60,33,32,144,0,40,13,132,140,
-	3,131,5,60,33,40,176,0,44,13,165,140,
-	3,131,6,60,216,12,198,140,3,131,7,60,
-	220,12,231,140,20,35,192,12,0,0,0,0,
-	12,0,64,20,0,0,0,0,3,131,3,60,
-	33,24,112,0,48,13,99,148,3,131,2,60,
-	33,16,80,0,16,13,66,148,0,0,0,0,
-	3,0,98,20,0,0,0,0,203,36,192,12,
-	33,32,64,2,36,0,191,143,32,0,180,143,
-	28,0,179,143,24,0,178,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,40,0,189,39,
-	224,255,189,39,20,0,177,175,33,136,128,0,
-	16,0,176,175,192,129,17,0,24,0,191,175,
-	3,131,2,60,33,16,80,0,20,13,66,140,
-	0,0,0,0,28,0,64,16,0,0,0,0,
-	3,131,4,60,33,32,144,0,40,13,132,140,
-	3,131,5,60,33,40,176,0,44,13,165,140,
-	3,131,6,60,216,12,198,140,3,131,7,60,
-	220,12,231,140,20,35,192,12,0,0,0,0,
-	14,0,64,20,0,0,0,0,3,131,3,60,
-	33,24,112,0,48,13,99,148,3,131,2,60,
-	33,16,80,0,16,13,66,148,0,0,0,0,
-	5,0,98,20,0,0,0,0,161,36,192,12,
-	0,0,0,0,211,39,192,12,33,32,32,2,
-	24,0,191,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,2,18,5,0,
-	0,0,130,160,8,0,224,3,1,0,133,160,
-	2,22,5,0,0,0,130,160,2,20,5,0,
-	1,0,130,160,2,18,5,0,2,0,130,160,
-	8,0,224,3,3,0,133,160,0,0,130,144,
-	1,0,131,144,0,18,2,0,8,0,224,3,
-	37,16,98,0,0,0,130,144,1,0,131,144,
-	2,0,133,144,0,22,2,0,0,28,3,0,
-	33,16,67,0,0,42,5,0,3,0,131,144,
-	33,16,69,0,8,0,224,3,37,16,67,0,
-	224,255,189,39,16,0,176,175,33,128,128,0,
-	24,0,191,175,20,0,177,175,48,129,135,39,
-	3,0,226,136,0,0,226,152,4,0,227,128,
-	5,0,228,128,3,0,2,170,0,0,2,186,
-	4,0,3,162,5,0,4,162,3,0,162,136,
-	0,0,162,152,4,0,163,128,5,0,164,128,
-	9,0,2,170,6,0,2,186,10,0,3,162,
-	11,0,4,162,12,0,4,38,38,0,5,36,
-	144,41,192,12,33,136,192,0,14,0,4,38,
-	144,41,192,12,66,66,5,36,17,0,4,38,
-	33,40,0,0,3,0,2,36,144,41,192,12,
-	16,0,2,162,19,0,0,162,20,0,0,162,
-	40,0,34,142,0,0,0,0,43,32,2,0,
-	36,0,34,142,0,0,0,0,3,0,64,16,
-	33,24,128,0,218,41,192,8,128,0,130,52,
-	33,16,96,0,21,0,2,162,4,0,37,150,
-	0,0,0,0,144,41,192,12,22,0,4,38,
-	9,0,34,138,6,0,34,154,10,0,35,130,
-	11,0,36,130,27,0,2,170,24,0,2,186,
-	28,0,3,162,29,0,4,162,12,0,37,142,
-	0,0,0,0,148,41,192,12,30,0,4,38,
-	16,0,37,150,0,0,0,0,144,41,192,12,
-	34,0,4,38,21,0,34,138,18,0,34,154,
-	22,0,35,130,23,0,36,130,39,0,2,170,
-	36,0,2,186,40,0,3,162,41,0,4,162,
-	24,0,37,150,0,0,0,0,144,41,192,12,
-	42,0,4,38,26,0,37,150,0,0,0,0,
-	144,41,192,12,44,0,4,38,28,0,37,150,
-	0,0,0,0,144,41,192,12,46,0,4,38,
-	30,0,37,150,0,0,0,0,144,41,192,12,
-	48,0,4,38,32,0,37,150,0,0,0,0,
-	144,41,192,12,50,0,4,38,52,0,2,36,
-	24,0,191,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,224,255,189,39,
-	16,0,176,175,33,128,160,0,24,0,191,175,
-	20,0,177,175,21,0,2,146,33,136,128,0,
-	1,0,66,48,40,0,34,174,22,0,2,146,
-	22,0,4,38,128,0,66,48,156,41,192,12,
-	36,0,34,174,4,0,34,166,27,0,2,138,
-	24,0,2,154,28,0,3,130,29,0,4,130,
-	9,0,34,170,6,0,34,186,10,0,35,162,
-	11,0,36,162,161,41,192,12,30,0,4,38,
-	34,0,4,38,156,41,192,12,12,0,34,174,
-	16,0,34,166,39,0,2,138,36,0,2,154,
-	40,0,3,130,41,0,4,130,21,0,34,170,
-	18,0,34,186,22,0,35,162,23,0,36,162,
-	156,41,192,12,42,0,4,38,44,0,4,38,
-	156,41,192,12,24,0,34,166,46,0,4,38,
-	156,41,192,12,26,0,34,166,48,0,4,38,
-	156,41,192,12,28,0,34,166,50,0,4,38,
-	156,41,192,12,30,0,34,166,32,0,34,166,
-	24,0,191,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,232,255,189,39,
-	16,0,176,175,33,128,128,0,20,0,191,175,
-	48,129,134,39,3,0,194,136,0,0,194,152,
-	4,0,195,128,5,0,196,128,3,0,2,170,
-	0,0,2,186,4,0,3,162,5,0,4,162,
-	3,0,162,136,0,0,162,152,4,0,163,128,
-	5,0,164,128,9,0,2,170,6,0,2,186,
-	10,0,3,162,11,0,4,162,12,0,4,38,
-	144,41,192,12,7,0,5,36,14,0,4,38,
-	144,41,192,12,66,66,5,36,17,0,4,38,
-	33,40,0,0,3,0,2,36,144,41,192,12,
-	16,0,2,162,21,0,2,36,128,0,3,36,
-	19,0,0,162,20,0,3,162,20,0,191,143,
-	16,0,176,143,8,0,224,3,24,0,189,39,
-	176,255,189,39,68,0,177,175,64,0,176,175,
-	33,128,160,0,72,0,191,175,14,0,3,146,
-	66,0,2,36,9,0,98,20,33,136,128,0,
-	15,0,2,146,0,0,0,0,6,0,67,20,
-	64,26,17,0,16,0,3,146,3,0,2,36,
-	11,0,98,16,0,0,0,0,64,26,17,0,
-	2,131,2,60,33,16,67,0,184,247,66,140,
-	0,0,0,0,1,0,66,36,2,131,1,60,
-	33,8,35,0,182,42,192,8,184,247,34,172,
-	20,0,3,146,0,0,0,0,5,0,96,16,
-	128,0,2,36,21,0,98,16,64,26,17,0,
-	179,42,192,8,0,0,0,0,16,0,164,39,
-	64,26,17,0,2,131,2,60,33,16,67,0,
-	180,247,66,140,0,0,0,0,1,0,66,36,
-	2,131,1,60,33,8,35,0,180,247,34,172,
-	17,42,192,12,33,40,0,2,33,32,32,2,
-	16,0,165,39,222,40,192,12,33,48,0,2,
-	182,42,192,8,0,0,0,0,2,131,2,60,
-	33,16,67,0,180,247,66,140,0,0,0,0,
-	1,0,66,36,2,131,1,60,33,8,35,0,
-	180,247,34,172,100,41,192,12,33,32,32,2,
-	182,42,192,8,0,0,0,0,112,129,132,39,
-	15,63,192,12,0,0,0,0,72,0,191,143,
-	68,0,177,143,64,0,176,143,8,0,224,3,
-	80,0,189,39,8,0,224,3,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	1,0,162,48,8,0,64,16,255,255,198,48,
-	67,40,5,0,64,16,5,0,33,16,68,0,
-	0,0,66,144,0,0,0,0,203,42,192,8,
-	33,48,194,0,67,40,5,0,255,255,165,36,
-	255,255,2,36,6,0,162,16,255,255,3,36,
-	0,0,130,148,2,0,132,36,255,255,165,36,
-	252,255,163,20,33,48,194,0,255,255,195,48,
-	2,20,6,0,33,48,98,0,255,255,195,48,
-	2,20,6,0,33,48,98,0,8,0,224,3,
-	255,255,194,48,208,255,189,39,16,0,176,175,
-	33,128,128,0,28,0,179,175,33,152,160,0,
-	24,0,178,175,33,144,192,0,36,0,181,175,
-	33,168,0,2,32,0,180,175,33,160,0,0,
-	40,0,191,175,20,0,177,175,12,0,3,142,
-	0,0,2,142,0,0,0,0,35,24,98,0,
-	42,16,114,0,2,0,64,16,33,136,64,2,
-	33,136,96,0,13,0,32,18,33,40,96,2,
-	35,144,81,2,8,0,2,142,0,0,4,142,
-	33,48,32,2,80,68,192,12,33,32,68,0,
-	8,0,2,142,0,0,2,142,0,0,2,142,
-	33,152,113,2,33,16,81,0,0,0,2,174,
-	0,0,2,142,0,0,0,0,4,0,64,18,
-	33,160,130,2,4,0,16,142,233,42,192,8,
-	0,0,0,0,18,0,180,166,33,16,0,2,
-	40,0,191,143,36,0,181,143,32,0,180,143,
-	28,0,179,143,24,0,178,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,48,0,189,39,
-	224,255,189,39,24,0,178,175,33,144,128,0,
-	2,131,4,60,192,4,132,36,36,0,165,175,
-	1,0,5,36,28,0,191,175,20,0,177,175,
-	54,21,192,12,16,0,176,175,33,136,64,0,
-	8,0,32,22,33,40,0,0,2,131,2,60,
-	176,5,66,140,0,0,0,0,1,0,66,36,
-	2,131,1,60,102,43,192,8,176,5,34,172,
-	0,1,3,36,8,0,48,142,8,0,2,36,
-	16,0,2,166,6,0,2,36,18,0,2,162,
-	4,0,2,36,14,0,3,166,19,0,2,162,
-	20,0,3,166,2,131,6,60,212,4,198,36,
-	3,0,194,136,0,0,194,152,4,0,195,132,
-	25,0,2,170,22,0,2,186,26,0,3,166,
-	2,131,1,60,195,211,34,136,176,133,130,155,
-	0,0,0,0,31,0,2,170,28,0,2,186,
-	32,0,4,38,144,71,192,12,6,0,6,36,
-	39,0,162,139,36,0,162,155,0,0,0,0,
-	41,0,2,170,38,0,2,186,132,129,133,39,
-	3,0,162,136,0,0,162,152,4,0,163,128,
-	5,0,164,128,3,0,2,170,0,0,2,186,
-	4,0,3,162,5,0,4,162,2,131,5,60,
-	212,4,165,36,3,0,162,136,0,0,162,152,
-	4,0,163,128,5,0,164,128,9,0,2,170,
-	6,0,2,186,10,0,3,162,11,0,4,162,
-	33,32,64,2,8,6,2,36,12,0,2,166,
-	60,128,2,52,0,0,34,174,60,0,2,36,
-	18,0,34,166,74,21,192,12,33,40,32,2,
-	3,0,64,20,0,0,0,0,152,21,192,12,
-	33,32,32,2,28,0,191,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,216,255,189,39,32,0,180,175,
-	33,160,128,0,16,0,176,175,33,128,160,0,
-	36,0,191,175,28,0,179,175,24,0,178,175,
-	20,0,177,175,8,0,2,142,33,152,192,0,
-	33,136,83,0,6,0,35,150,0,1,4,36,
-	5,0,100,16,0,2,2,36,113,0,98,16,
-	0,0,0,0,15,44,192,8,0,0,0,0,
-	24,0,35,150,176,133,130,151,0,0,0,0,
-	139,0,98,20,0,0,0,0,26,0,35,150,
-	2,131,2,60,194,211,66,148,0,0,0,0,
-	133,0,98,20,0,0,0,0,0,0,34,150,
-	0,0,0,0,129,0,68,20,8,0,2,36,
-	2,0,35,150,0,0,0,0,125,0,98,20,
-	6,4,2,36,4,0,35,150,0,0,0,0,
-	121,0,98,20,0,0,0,0,2,131,4,60,
-	192,4,132,36,54,21,192,12,1,0,5,36,
-	33,144,64,0,8,0,64,22,0,0,0,0,
-	2,131,2,60,176,5,66,140,0,0,0,0,
-	1,0,66,36,2,131,1,60,15,44,192,8,
-	176,5,34,172,8,0,5,142,8,0,80,142,
-	9,0,162,136,6,0,162,152,10,0,163,128,
-	11,0,164,128,3,0,2,170,0,0,2,186,
-	4,0,3,162,5,0,4,162,2,131,6,60,
-	212,4,198,36,3,0,194,136,0,0,194,152,
-	4,0,195,128,5,0,196,128,9,0,2,170,
-	6,0,2,186,10,0,3,162,11,0,4,162,
-	12,0,4,38,12,0,165,36,33,128,19,2,
-	80,68,192,12,244,255,102,38,0,1,2,36,
-	0,0,2,166,8,0,2,36,2,0,2,166,
-	6,0,2,36,4,0,2,162,4,0,2,36,
-	5,0,2,162,0,2,2,36,6,0,2,166,
-	2,131,5,60,212,4,165,36,3,0,162,136,
-	0,0,162,152,4,0,163,132,11,0,2,170,
-	8,0,2,186,12,0,3,166,2,131,1,60,
-	195,211,34,136,176,133,130,155,0,0,0,0,
-	17,0,2,170,14,0,2,186,11,0,34,138,
-	8,0,34,154,12,0,35,134,21,0,2,170,
-	18,0,2,186,22,0,3,166,17,0,34,138,
-	14,0,34,154,0,0,0,0,27,0,2,170,
-	24,0,2,186,33,32,128,2,33,40,64,2,
-	60,128,2,52,0,0,66,174,60,0,2,36,
-	74,21,192,12,18,0,66,166,38,0,64,20,
-	0,0,0,0,152,21,192,12,33,32,64,2,
-	15,44,192,8,0,0,0,0,14,0,35,150,
-	196,133,130,151,0,0,0,0,29,0,98,20,
-	0,0,0,0,16,0,35,150,2,131,2,60,
-	214,211,66,148,0,0,0,0,23,0,98,20,
-	0,0,0,0,0,0,34,150,0,0,0,0,
-	19,0,68,20,8,0,2,36,2,0,35,150,
-	0,0,0,0,15,0,98,20,6,4,2,36,
-	4,0,35,150,0,0,0,0,11,0,98,20,
-	0,0,0,0,68,133,130,143,140,129,134,39,
-	11,0,35,138,8,0,35,154,12,0,36,134,
-	3,0,195,168,0,0,195,184,4,0,196,164,
-	20,0,66,36,152,129,130,175,36,0,191,143,
-	32,0,180,143,28,0,179,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	40,0,189,39,192,255,189,39,80,0,169,143,
-	84,0,168,143,56,0,180,175,33,160,128,0,
-	44,0,177,175,88,0,177,143,16,0,164,39,
-	52,0,179,175,92,0,179,143,3,131,3,60,
-	32,17,99,36,40,0,176,175,33,128,192,0,
-	60,0,191,175,48,0,178,175,0,0,98,140,
-	8,0,50,142,1,0,66,36,0,0,98,172,
-	3,0,162,136,0,0,162,152,4,0,163,128,
-	5,0,170,128,3,0,66,170,0,0,66,186,
-	4,0,67,162,5,0,74,162,2,131,10,60,
-	212,4,74,37,3,0,66,137,0,0,66,153,
-	4,0,67,129,5,0,69,129,9,0,66,170,
-	6,0,66,186,10,0,67,162,11,0,69,162,
-	69,0,2,36,16,0,162,163,17,0,168,163,
-	18,0,34,150,240,132,131,143,33,48,0,0,
-	25,0,169,163,20,0,66,36,0,66,2,0,
-	255,255,66,48,2,18,2,0,37,64,2,1,
-	0,74,3,0,255,255,98,48,2,18,2,0,
-	37,72,34,1,3,131,2,60,0,17,66,140,
-	22,0,160,167,26,0,160,167,18,0,168,167,
-	176,133,136,143,1,0,99,36,240,132,131,175,
-	20,0,169,167,24,0,162,163,28,0,168,175,
-	3,0,226,136,0,0,226,152,0,0,0,0,
-	35,0,162,171,32,0,162,187,192,42,192,12,
-	20,0,5,36,39,16,2,0,26,0,162,167,
-	14,0,2,36,44,0,2,22,8,0,2,36,
-	12,0,66,166,19,0,162,139,16,0,162,155,
-	23,0,163,139,20,0,163,155,27,0,164,139,
-	24,0,164,155,31,0,165,139,28,0,165,155,
-	17,0,66,170,14,0,66,186,21,0,67,170,
-	18,0,67,186,25,0,68,170,22,0,68,186,
-	29,0,69,170,26,0,69,186,35,0,162,139,
-	32,0,162,155,0,0,0,0,33,0,66,170,
-	30,0,66,186,34,0,2,36,0,0,34,174,
-	0,0,35,142,18,0,34,150,0,0,0,0,
-	33,16,67,0,18,0,34,166,18,0,34,150,
-	0,0,0,0,60,0,66,44,68,0,64,16,
-	33,32,128,2,0,0,98,142,18,0,35,150,
-	60,0,66,36,35,16,67,0,0,0,98,174,
-	60,0,2,36,18,0,34,166,201,44,192,8,
-	33,32,128,2,164,129,133,39,3,0,162,136,
-	0,0,162,152,4,0,163,128,5,0,164,128,
-	17,0,66,170,14,0,66,186,18,0,67,162,
-	19,0,68,162,8,0,2,36,20,0,66,166,
-	19,0,162,139,16,0,162,155,23,0,163,139,
-	20,0,163,155,27,0,164,139,24,0,164,155,
-	31,0,165,139,28,0,165,155,25,0,66,170,
-	22,0,66,186,29,0,67,170,26,0,67,186,
-	33,0,68,170,30,0,68,186,37,0,69,170,
-	34,0,69,186,35,0,162,139,32,0,162,155,
-	0,0,0,0,41,0,66,170,38,0,66,186,
-	42,0,2,36,0,0,34,174,0,0,35,142,
-	18,0,34,150,0,0,0,0,33,16,67,0,
-	18,0,34,166,18,0,34,150,0,0,0,0,
-	60,0,66,44,8,0,64,16,0,0,0,0,
-	0,0,98,142,18,0,35,150,60,0,66,36,
-	35,16,67,0,0,0,98,174,60,0,2,36,
-	18,0,34,166,18,0,34,150,0,0,0,0,
-	0,26,2,0,2,18,2,0,37,24,98,0,
-	12,0,67,166,33,32,128,2,74,21,192,12,
-	33,40,32,2,8,0,64,20,33,32,32,2,
-	3,131,3,60,36,17,99,36,0,0,98,140,
-	0,0,0,0,1,0,66,36,152,21,192,12,
-	0,0,98,172,60,0,191,143,56,0,180,143,
-	52,0,179,143,48,0,178,143,44,0,177,143,
-	40,0,176,143,8,0,224,3,64,0,189,39,
-	176,255,189,39,56,0,180,175,112,0,180,143,
-	48,0,178,175,100,0,178,143,52,0,179,175,
-	104,0,179,143,64,0,182,175,33,176,128,0,
-	72,0,190,175,33,240,160,0,60,0,181,175,
-	33,168,224,0,68,0,183,175,108,0,183,143,
-	2,131,4,60,192,4,132,36,76,0,191,175,
-	44,0,177,175,40,0,176,175,32,0,166,175,
-	7,2,130,38,2,130,2,0,54,21,192,12,
-	33,40,0,2,33,136,64,0,8,0,32,22,
-	0,74,18,0,2,131,4,60,232,146,132,36,
-	33,40,128,2,15,63,192,12,33,48,0,2,
-	74,45,192,8,0,0,0,0,255,255,66,50,
-	2,18,2,0,37,72,34,1,0,66,19,0,
-	255,255,98,50,2,18,2,0,37,64,2,1,
-	8,0,130,38,0,58,2,0,255,255,66,48,
-	2,18,2,0,37,56,226,0,0,163,4,60,
-	220,5,132,52,4,0,5,36,4,0,34,142,
-	0,17,6,36,8,0,80,140,4,0,35,142,
-	8,0,2,36,0,0,98,172,0,0,9,166,
-	2,0,8,166,6,0,0,166,192,42,192,12,
-	4,0,7,166,33,32,160,2,4,0,5,36,
-	192,42,192,12,255,255,70,48,4,0,4,38,
-	2,0,5,36,192,42,192,12,255,255,70,48,
-	33,32,0,2,8,0,5,36,192,42,192,12,
-	255,255,70,48,33,32,224,2,33,40,128,2,
-	192,42,192,12,255,255,70,48,39,24,2,0,
-	255,255,98,48,2,0,64,20,33,40,224,2,
-	255,255,3,52,6,0,3,166,4,0,36,142,
-	0,0,0,0,220,42,192,12,33,48,128,2,
-	33,32,192,2,0,0,67,140,33,40,192,3,
-	0,128,99,52,0,0,67,172,4,0,35,142,
-	32,0,166,143,18,0,99,148,33,56,160,2,
-	18,0,35,166,96,0,170,143,17,0,3,36,
-	16,0,163,175,24,0,177,175,28,0,162,175,
-	23,44,192,12,20,0,170,175,3,131,3,60,
-	124,17,99,36,0,0,98,140,0,0,0,0,
-	1,0,66,36,0,0,98,172,76,0,191,143,
-	72,0,190,143,68,0,183,143,64,0,182,143,
-	60,0,181,143,56,0,180,143,52,0,179,143,
-	48,0,178,143,44,0,177,143,40,0,176,143,
-	8,0,224,3,80,0,189,39,128,255,189,39,
-	116,0,183,175,33,184,128,0,112,0,182,175,
-	33,176,160,0,104,0,180,175,33,160,192,0,
-	108,0,181,175,33,168,224,0,40,0,164,39,
-	96,0,178,175,144,0,178,143,33,40,0,0,
-	100,0,179,175,148,0,179,143,16,0,6,36,
-	120,0,191,175,92,0,177,175,144,71,192,12,
-	88,0,176,175,56,0,177,39,33,32,32,2,
-	33,40,0,0,2,0,16,36,40,0,176,167,
-	2,0,162,150,0,0,0,0,42,0,162,167,
-	19,0,130,138,16,0,130,154,0,0,0,0,
-	47,0,162,171,44,0,162,187,144,71,192,12,
-	16,0,6,36,33,32,64,2,33,40,96,2,
-	40,0,166,39,33,56,32,2,56,0,176,167,
-	0,0,162,150,2,131,16,60,8,239,16,38,
-	58,0,162,167,15,0,130,138,12,0,130,154,
-	0,0,0,0,63,0,162,171,60,0,162,187,
-	242,5,2,36,84,0,162,167,72,0,162,39,
-	72,0,160,167,76,0,176,175,80,0,176,175,
-	247,71,192,12,16,0,162,175,255,255,3,36,
-	22,0,67,16,12,0,145,38,33,32,224,2,
-	6,0,197,38,35,48,150,2,0,0,163,150,
-	4,0,2,36,16,0,162,175,161,0,2,36,
-	20,0,162,175,28,0,176,175,0,18,3,0,
-	2,26,3,0,37,16,67,0,255,255,66,48,
-	24,0,162,175,80,0,162,143,76,0,163,143,
-	33,56,32,2,35,16,67,0,255,255,66,48,
-	220,44,192,12,32,0,162,175,120,0,191,143,
-	116,0,183,143,112,0,182,143,108,0,181,143,
-	104,0,180,143,100,0,179,143,96,0,178,143,
-	92,0,177,143,88,0,176,143,8,0,224,3,
-	128,0,189,39,196,133,130,143,184,255,189,39,
-	64,0,191,175,60,0,177,175,109,0,64,16,
-	56,0,176,175,255,255,3,36,106,0,67,16,
-	0,0,0,0,176,133,130,143,176,133,145,39,
-	102,0,64,16,0,0,0,0,100,0,67,16,
-	0,0,0,0,2,131,2,60,8,239,66,36,
-	44,0,162,175,48,0,162,175,242,5,2,36,
-	40,0,160,167,6,0,128,16,52,0,162,167,
-	1,0,2,36,23,0,130,16,0,0,0,0,
-	36,46,192,8,0,0,0,0,2,131,16,60,
-	160,204,16,38,156,71,192,12,33,32,0,2,
-	0,163,4,60,4,1,132,140,204,204,3,60,
-	205,204,99,52,25,0,131,0,33,40,32,2,
-	33,48,0,2,33,56,64,0,40,0,164,39,
-	16,64,0,0,194,16,8,0,0,0,0,0,
-	104,56,192,12,16,0,162,175,251,45,192,8,
-	33,24,64,0,3,131,2,60,28,18,66,148,
-	0,0,0,0,2,0,66,48,61,0,64,16,
-	0,0,0,0,2,131,16,60,160,204,16,38,
-	156,71,192,12,33,32,0,2,0,163,4,60,
-	4,1,132,140,204,204,3,60,205,204,99,52,
-	25,0,131,0,33,40,32,2,33,48,0,2,
-	33,56,64,0,40,0,164,39,16,64,0,0,
-	194,16,8,0,0,0,0,0,105,57,192,12,
-	16,0,162,175,33,24,64,0,255,255,2,36,
-	39,0,98,16,0,0,0,0,140,129,130,147,
-	0,0,0,0,1,0,66,48,7,0,64,20,
-	0,0,0,0,68,133,131,143,152,129,130,143,
-	0,0,0,0,43,16,67,0,11,0,64,16,
-	33,32,0,0,68,133,131,143,148,129,130,143,
-	0,0,0,0,6,0,98,16,33,32,0,0,
-	196,133,133,143,148,129,131,175,17,43,192,12,
-	33,32,0,0,33,32,0,0,140,129,133,39,
-	14,0,6,36,4,0,2,36,16,0,162,175,
-	162,0,2,36,20,0,162,175,24,0,162,175,
-	2,131,2,60,8,239,66,36,28,0,162,175,
-	48,0,162,143,44,0,163,143,196,133,135,39,
-	35,16,67,0,255,255,66,48,220,44,192,12,
-	32,0,162,175,64,0,191,143,60,0,177,143,
-	56,0,176,143,8,0,224,3,72,0,189,39,
-	208,255,189,39,36,0,179,175,33,152,128,0,
-	40,0,180,175,33,160,160,0,32,0,178,175,
-	24,0,176,175,33,128,224,0,44,0,191,175,
-	28,0,177,175,6,0,2,150,64,0,177,143,
-	0,0,0,0,20,0,64,16,33,144,192,0,
-	12,0,68,38,8,0,5,36,192,42,192,12,
-	0,17,6,36,4,0,4,38,2,0,5,36,
-	192,42,192,12,255,255,70,48,33,32,0,2,
-	33,40,32,2,192,42,192,12,255,255,70,48,
-	255,255,66,48,255,255,3,52,4,0,67,16,
-	0,0,0,0,3,131,3,60,111,46,192,8,
-	120,17,99,36,4,0,2,150,0,0,0,0,
-	0,26,2,0,2,18,2,0,37,24,98,0,
-	255,255,99,48,4,0,113,16,8,0,7,38,
-	3,131,3,60,111,46,192,8,120,17,99,36,
-	2,0,2,150,0,0,0,0,0,26,2,0,
-	2,18,2,0,37,24,98,0,255,255,99,48,
-	161,0,2,36,15,0,98,20,248,255,40,38,
-	33,32,96,2,33,40,128,2,3,131,3,60,
-	112,17,99,36,0,0,98,140,33,48,64,2,
-	16,0,167,175,33,56,0,2,20,0,168,175,
-	1,0,66,36,86,45,192,12,0,0,98,172,
-	115,46,192,8,0,0,0,0,3,131,3,60,
-	116,17,99,36,0,0,98,140,0,0,0,0,
-	1,0,66,36,0,0,98,172,44,0,191,143,
-	40,0,180,143,36,0,179,143,32,0,178,143,
-	28,0,177,143,24,0,176,143,8,0,224,3,
-	48,0,189,39,192,255,189,39,52,0,181,175,
-	33,168,128,0,44,0,179,175,33,152,160,0,
-	48,0,180,175,33,160,192,0,32,0,176,175,
-	33,128,224,0,33,32,0,2,33,48,0,0,
-	40,0,178,175,80,0,178,143,3,131,3,60,
-	144,16,99,36,56,0,191,175,36,0,177,175,
-	0,0,98,140,33,40,64,2,1,0,66,36,
-	192,42,192,12,0,0,98,172,255,255,66,48,
-	255,255,3,52,8,0,67,16,8,0,2,36,
-	3,131,2,60,148,16,66,140,0,0,0,0,
-	1,0,66,36,3,131,1,60,217,46,192,8,
-	148,16,34,172,0,0,3,150,0,0,0,0,
-	58,0,98,20,255,1,69,38,2,131,4,60,
-	192,4,132,36,3,131,2,60,172,16,66,140,
-	3,131,3,60,196,16,99,140,1,0,66,36,
-	1,0,99,36,3,131,1,60,172,16,34,172,
-	3,131,1,60,196,16,35,172,54,21,192,12,
-	2,42,5,0,33,136,64,0,8,0,32,22,
-	33,32,0,2,3,131,2,60,200,16,66,140,
-	0,0,0,0,1,0,66,36,3,131,1,60,
-	217,46,192,8,200,16,34,172,33,40,64,2,
-	33,48,0,0,0,0,0,162,192,42,192,12,
-	2,0,0,166,33,40,0,2,39,16,2,0,
-	2,0,162,164,4,0,36,142,0,0,0,0,
-	220,42,192,12,33,48,64,2,33,32,160,2,
-	6,0,101,38,35,48,147,2,0,0,67,140,
-	12,0,135,38,0,128,99,52,0,0,67,172,
-	1,0,3,36,18,0,50,166,16,0,163,175,
-	4,0,3,36,20,0,163,175,24,0,177,175,
-	23,44,192,12,28,0,162,175,3,131,2,60,
-	228,16,66,140,0,0,0,0,1,0,66,36,
-	3,131,1,60,228,16,34,172,56,0,191,143,
-	52,0,181,143,48,0,180,143,44,0,179,143,
-	40,0,178,143,36,0,177,143,32,0,176,143,
-	8,0,224,3,64,0,189,39,200,255,189,39,
-	44,0,181,175,33,168,128,0,3,131,3,60,
-	4,17,99,36,48,0,191,175,40,0,180,175,
-	36,0,179,175,32,0,178,175,28,0,177,175,
-	24,0,176,175,0,0,98,140,33,136,160,0,
-	1,0,66,36,0,0,98,172,18,0,34,150,
-	0,0,0,0,255,255,84,48,243,5,130,46,
-	8,0,64,20,33,152,192,0,3,131,2,60,
-	8,17,66,140,0,0,0,0,1,0,66,36,
-	3,131,1,60,132,47,192,8,8,17,34,172,
-	2,131,18,60,18,233,82,38,33,32,64,2,
-	0,0,48,142,8,0,37,142,255,63,16,50,
-	80,68,192,12,33,48,0,2,0,0,34,142,
-	0,0,0,0,0,128,66,48,5,0,64,20,
-	33,144,80,2,4,0,49,142,0,0,0,0,
-	1,47,192,8,33,32,64,2,2,131,18,60,
-	18,233,82,38,33,128,114,2,16,0,17,38,
-	33,32,32,2,176,133,133,39,168,71,192,12,
-	4,0,6,36,9,0,64,16,33,32,32,2,
-	128,129,133,39,168,71,192,12,4,0,6,36,
-	4,0,64,16,0,0,0,0,3,131,3,60,
-	128,47,192,8,12,17,99,36,0,0,4,146,
-	64,0,2,36,240,0,131,48,4,0,98,16,
-	15,0,130,48,3,131,3,60,128,47,192,8,
-	8,17,99,36,128,136,2,0,20,0,34,42,
-	4,0,64,16,33,32,0,2,3,131,3,60,
-	128,47,192,8,8,17,99,36,33,40,32,2,
-	192,42,192,12,33,48,0,0,255,255,66,48,
-	255,255,3,52,4,0,67,16,0,0,0,0,
-	3,131,3,60,128,47,192,8,8,17,99,36,
-	6,0,2,150,0,0,0,0,63,255,66,48,
-	18,0,64,16,33,56,17,2,3,131,3,60,
-	48,17,99,36,0,0,98,140,0,0,0,0,
-	1,0,66,36,0,0,98,172,3,131,2,60,
-	56,17,66,140,3,131,3,60,24,17,99,140,
-	1,0,66,36,1,0,99,36,3,131,1,60,
-	56,17,34,172,3,131,1,60,132,47,192,8,
-	24,17,35,172,2,0,2,150,0,0,0,0,
-	0,26,2,0,2,18,2,0,37,24,98,0,
-	255,255,99,48,35,64,113,0,35,16,242,0,
-	35,16,130,2,42,16,72,0,4,0,64,16,
-	1,0,2,36,3,131,3,60,128,47,192,8,
-	24,17,99,36,9,0,3,146,0,0,0,0,
-	5,0,98,16,17,0,2,36,15,0,98,16,
-	33,32,160,2,126,47,192,8,0,0,0,0,
-	33,32,160,2,33,40,64,2,3,131,3,60,
-	28,17,99,36,0,0,98,140,33,48,0,2,
-	16,0,168,175,1,0,66,36,123,46,192,12,
-	0,0,98,172,132,47,192,8,0,0,0,0,
-	33,40,64,2,3,131,3,60,28,17,99,36,
-	0,0,98,140,33,48,0,2,16,0,168,175,
-	1,0,66,36,41,46,192,12,0,0,98,172,
-	132,47,192,8,0,0,0,0,3,131,3,60,
-	20,17,99,36,0,0,98,140,0,0,0,0,
-	1,0,66,36,0,0,98,172,48,0,191,143,
-	44,0,181,143,40,0,180,143,36,0,179,143,
-	32,0,178,143,28,0,177,143,24,0,176,143,
-	8,0,224,3,56,0,189,39,232,255,189,39,
-	255,0,12,60,255,0,140,53,0,255,13,60,
-	0,255,173,53,16,0,176,175,3,131,16,60,
-	0,17,16,38,33,32,0,2,33,40,0,0,
-	0,163,9,60,220,5,41,141,0,163,10,60,
-	16,6,74,141,0,163,11,60,224,5,107,141,
-	20,0,191,175,0,28,9,0,2,20,9,0,
-	37,24,98,0,0,60,10,0,2,20,10,0,
-	37,56,226,0,0,68,11,0,2,20,11,0,
-	37,64,2,1,2,18,3,0,36,16,76,0,
-	0,26,3,0,36,24,109,0,37,16,67,0,
-	184,133,130,175,2,18,7,0,36,16,76,0,
-	0,58,7,0,36,56,237,0,37,16,71,0,
-	192,133,130,175,2,18,8,0,36,16,76,0,
-	0,66,8,0,36,64,13,1,37,16,72,0,
-	176,133,137,175,196,133,138,175,188,133,139,175,
-	180,133,130,175,144,71,192,12,76,0,6,36,
-	3,131,4,60,144,16,132,36,33,40,0,0,
-	32,0,2,36,0,0,2,174,10,0,2,36,
-	3,131,1,60,44,17,34,172,144,71,192,12,
-	104,0,6,36,3,131,4,60,112,17,132,36,
-	33,40,0,0,144,71,192,12,16,0,6,36,
-	3,131,4,60,80,17,132,36,33,40,0,0,
-	144,71,192,12,32,0,6,36,20,0,191,143,
-	16,0,176,143,8,0,224,3,24,0,189,39,
-	176,255,189,39,100,0,162,143,96,0,169,143,
-	72,0,182,175,33,176,128,0,48,0,176,175,
-	104,0,176,143,34,0,164,39,60,0,179,175,
-	108,0,179,143,3,131,3,60,104,17,99,36,
-	56,0,178,175,2,131,18,60,212,4,82,38,
-	52,0,177,175,33,136,192,0,68,0,181,175,
-	112,0,181,143,4,0,6,36,76,0,191,175,
-	64,0,180,175,0,66,2,0,255,255,66,48,
-	2,18,2,0,37,64,2,1,0,0,98,140,
-	8,0,116,142,1,0,66,36,0,0,98,172,
-	3,0,162,136,0,0,162,152,4,0,163,128,
-	5,0,170,128,3,0,130,170,0,0,130,186,
-	4,0,131,162,5,0,138,162,3,0,66,138,
-	0,0,66,154,4,0,67,130,5,0,69,130,
-	9,0,130,170,6,0,130,186,10,0,131,162,
-	11,0,133,162,255,255,2,52,16,0,162,167,
-	18,0,98,150,33,40,0,0,20,0,160,163,
-	21,0,160,163,30,0,66,36,0,26,2,0,
-	255,255,66,48,2,18,2,0,37,24,98,0,
-	18,0,163,167,3,0,226,136,0,0,226,152,
-	0,0,0,0,25,0,162,171,22,0,162,187,
-	3,0,34,137,0,0,34,153,4,0,35,129,
-	5,0,39,129,29,0,162,171,26,0,162,187,
-	30,0,163,163,31,0,167,163,144,71,192,12,
-	32,0,168,167,3,0,66,138,0,0,66,154,
-	4,0,67,134,41,0,162,171,38,0,162,187,
-	42,0,163,167,33,16,0,2,0,130,16,0,
-	255,255,66,48,2,18,2,0,37,128,2,2,
-	14,0,2,36,58,0,34,22,44,0,176,167,
-	18,0,162,151,0,0,0,0,12,0,130,166,
-	19,0,162,139,16,0,162,155,23,0,163,139,
-	20,0,163,155,27,0,164,139,24,0,164,155,
-	31,0,165,139,28,0,165,155,17,0,130,170,
-	14,0,130,186,21,0,131,170,18,0,131,186,
-	25,0,132,170,22,0,132,186,29,0,133,170,
-	26,0,133,186,35,0,162,139,32,0,162,155,
-	39,0,163,139,36,0,163,155,43,0,164,139,
-	40,0,164,155,44,0,165,131,33,0,130,170,
-	30,0,130,186,37,0,131,170,34,0,131,186,
-	41,0,132,170,38,0,132,186,42,0,133,162,
-	45,0,162,131,0,0,0,0,43,0,130,162,
-	44,0,2,36,0,0,98,174,0,0,99,142,
-	18,0,98,150,0,0,0,0,33,16,67,0,
-	18,0,98,166,18,0,98,150,0,0,0,0,
-	60,0,66,44,80,0,64,16,33,32,192,2,
-	0,0,162,142,18,0,99,150,60,0,66,36,
-	35,16,67,0,0,0,162,174,60,0,2,36,
-	18,0,98,166,172,48,192,8,33,32,192,2,
-	208,129,133,39,3,0,162,136,0,0,162,152,
-	4,0,163,128,5,0,164,128,17,0,130,170,
-	14,0,130,186,18,0,131,162,19,0,132,162,
-	129,55,2,36,20,0,130,166,19,0,162,139,
-	16,0,162,155,23,0,163,139,20,0,163,155,
-	27,0,164,139,24,0,164,155,31,0,165,139,
-	28,0,165,155,25,0,130,170,22,0,130,186,
-	29,0,131,170,26,0,131,186,33,0,132,170,
-	30,0,132,186,37,0,133,170,34,0,133,186,
-	35,0,162,139,32,0,162,155,39,0,163,139,
-	36,0,163,155,43,0,164,139,40,0,164,155,
-	44,0,165,131,41,0,130,170,38,0,130,186,
-	45,0,131,170,42,0,131,186,49,0,132,170,
-	46,0,132,186,50,0,133,162,45,0,162,131,
-	0,0,0,0,51,0,130,162,52,0,2,36,
-	0,0,98,174,0,0,99,142,18,0,98,150,
-	0,0,0,0,33,16,67,0,18,0,98,166,
-	18,0,98,150,0,0,0,0,60,0,66,44,
-	8,0,64,16,0,0,0,0,0,0,162,142,
-	18,0,99,150,60,0,66,36,35,16,67,0,
-	0,0,162,174,60,0,2,36,18,0,98,166,
-	18,0,98,150,0,0,0,0,0,26,2,0,
-	2,18,2,0,37,24,98,0,12,0,131,166,
-	33,32,192,2,74,21,192,12,33,40,96,2,
-	8,0,64,20,33,32,96,2,3,131,3,60,
-	108,17,99,36,0,0,98,140,0,0,0,0,
-	1,0,66,36,152,21,192,12,0,0,98,172,
-	76,0,191,143,72,0,182,143,68,0,181,143,
-	64,0,180,143,60,0,179,143,56,0,178,143,
-	52,0,177,143,48,0,176,143,8,0,224,3,
-	80,0,189,39,33,24,0,0,5,0,7,36,
-	58,0,6,36,0,0,162,144,0,0,0,0,
-	2,17,2,0,2,131,1,60,33,8,34,0,
-	176,155,34,144,0,0,0,0,0,0,130,160,
-	0,0,162,144,1,0,132,36,15,0,66,48,
-	2,131,1,60,33,8,34,0,176,155,34,144,
-	1,0,165,36,0,0,130,160,3,0,103,16,
-	1,0,132,36,0,0,134,160,1,0,132,36,
-	1,0,99,36,6,0,98,40,233,255,64,20,
-	0,0,0,0,8,0,224,3,0,0,0,0,
-	128,255,189,39,2,101,2,36,0,2,3,36,
-	112,0,176,175,44,0,176,39,33,32,0,2,
-	33,40,0,0,48,0,6,36,120,0,191,175,
-	116,0,177,175,40,0,162,167,144,71,192,12,
-	42,0,163,167,3,131,17,60,96,18,49,38,
-	2,131,5,60,224,147,165,36,188,71,192,12,
-	33,32,32,2,18,0,64,20,33,32,0,2,
-	2,131,5,60,236,147,165,36,0,0,162,140,
-	4,0,163,140,8,0,164,140,44,0,162,175,
-	48,0,163,175,52,0,164,175,12,0,162,128,
-	0,0,0,0,56,0,162,163,2,131,5,60,
-	212,4,165,36,193,48,192,12,56,0,164,39,
-	8,49,192,8,92,0,177,39,33,40,32,2,
-	204,63,192,12,48,0,6,36,92,0,177,39,
-	33,32,32,2,33,40,0,0,144,71,192,12,
-	4,0,6,36,2,131,4,60,212,4,132,36,
-	0,0,130,140,4,0,131,132,96,0,162,175,
-	100,0,163,167,4,82,2,36,0,1,3,36,
-	236,255,132,36,2,0,5,36,102,0,162,167,
-	54,21,192,12,104,0,163,167,33,128,64,0,
-	22,0,0,18,40,0,165,39,4,0,4,142,
-	0,0,0,0,220,42,192,12,66,0,6,36,
-	33,32,0,0,0,0,67,140,132,129,133,39,
-	0,128,99,52,0,0,67,172,4,0,3,142,
-	14,0,6,36,18,0,99,148,33,56,32,2,
-	18,0,3,166,82,4,3,36,16,0,165,175,
-	20,0,163,175,24,0,163,175,28,0,176,175,
-	214,47,192,12,32,0,162,175,120,0,191,143,
-	116,0,177,143,112,0,176,143,8,0,224,3,
-	128,0,189,39,144,255,189,39,104,0,180,175,
-	33,160,128,0,100,0,179,175,33,152,160,0,
-	92,0,177,175,33,136,192,0,33,32,224,0,
-	40,0,166,39,56,0,167,39,96,0,178,175,
-	2,131,18,60,8,239,82,38,88,0,176,175,
-	128,0,176,143,242,5,2,36,84,0,162,167,
-	72,0,162,39,108,0,191,175,72,0,160,167,
-	76,0,178,175,80,0,178,175,16,0,162,175,
-	247,71,192,12,33,40,0,2,255,255,3,36,
-	37,0,67,16,255,1,5,38,2,131,4,60,
-	192,4,132,36,54,21,192,12,2,42,5,0,
-	33,128,64,0,30,0,0,18,33,40,64,2,
-	80,0,166,143,76,0,162,143,4,0,4,142,
-	35,48,194,0,220,42,192,12,255,255,198,48,
-	33,32,128,2,0,0,67,140,6,0,101,38,
-	0,128,99,52,0,0,67,172,4,0,3,142,
-	35,48,51,2,18,0,99,148,18,0,39,38,
-	18,0,3,166,28,0,40,150,22,0,35,38,
-	16,0,163,175,15,144,3,52,24,0,163,175,
-	28,0,176,175,32,0,162,175,0,18,8,0,
-	2,66,8,0,37,16,72,0,255,255,66,48,
-	214,47,192,12,20,0,162,175,108,0,191,143,
-	104,0,180,143,100,0,179,143,96,0,178,143,
-	92,0,177,143,88,0,176,143,8,0,224,3,
-	112,0,189,39,200,255,189,39,44,0,181,175,
-	33,168,128,0,28,0,177,175,33,136,160,0,
-	48,0,191,175,40,0,180,175,36,0,179,175,
-	32,0,178,175,24,0,176,175,18,0,34,150,
-	0,0,0,0,255,255,84,48,243,5,130,46,
-	4,0,64,20,33,152,192,0,3,131,3,60,
-	241,49,192,8,84,17,99,36,2,131,18,60,
-	16,233,82,38,33,32,64,2,0,0,48,142,
-	8,0,37,142,255,63,16,50,80,68,192,12,
-	33,48,0,2,0,0,34,142,0,0,0,0,
-	0,128,66,48,5,0,64,20,33,144,80,2,
-	4,0,49,142,0,0,0,0,148,49,192,8,
-	33,32,64,2,2,131,2,60,16,233,66,36,
-	33,128,98,2,6,0,17,38,33,32,32,2,
-	0,163,5,60,224,5,165,52,168,71,192,12,
-	4,0,6,36,9,0,64,16,33,32,32,2,
-	224,129,133,39,168,71,192,12,4,0,6,36,
-	5,0,64,16,10,0,17,38,3,131,3,60,
-	241,49,192,8,88,17,99,36,10,0,17,38,
-	33,32,32,2,2,131,5,60,212,4,165,36,
-	168,71,192,12,6,0,6,36,9,0,64,16,
-	33,32,32,2,228,129,133,39,168,71,192,12,
-	6,0,6,36,4,0,64,16,0,0,0,0,
-	3,131,3,60,241,49,192,8,88,17,99,36,
-	0,0,3,150,255,255,2,52,4,0,98,16,
-	30,0,7,38,3,131,3,60,241,49,192,8,
-	88,17,99,36,2,0,2,150,2,131,5,60,
-	16,233,165,36,0,26,2,0,2,18,2,0,
-	37,24,98,0,255,255,99,48,226,255,104,36,
-	35,16,229,0,35,16,130,2,42,16,72,0,
-	4,0,64,16,0,0,0,0,3,131,3,60,
-	241,49,192,8,96,17,99,36,16,0,2,150,
-	0,0,0,0,0,26,2,0,2,18,2,0,
-	37,24,98,0,255,255,99,48,15,144,2,52,
-	11,0,98,20,33,32,160,2,3,131,3,60,
-	100,17,99,36,0,0,98,140,33,48,0,2,
-	16,0,168,175,1,0,66,36,54,49,192,12,
-	0,0,98,172,245,49,192,8,0,0,0,0,
-	3,131,3,60,92,17,99,36,0,0,98,140,
-	0,0,0,0,1,0,66,36,0,0,98,172,
-	48,0,191,143,44,0,181,143,40,0,180,143,
-	36,0,179,143,32,0,178,143,28,0,177,143,
-	24,0,176,143,8,0,224,3,56,0,189,39,
-	0,0,0,0,0,0,0,0,232,255,189,39,
-	16,0,191,175,13,8,192,12,0,8,4,36,
-	8,133,130,175,16,0,191,143,24,0,189,39,
-	8,0,224,3,0,0,0,0,232,255,189,39,
-	45,0,128,16,16,0,191,175,240,129,133,143,
-	7,0,130,36,194,16,2,0,10,0,160,20,
-	1,0,70,36,8,133,133,143,0,133,130,39,
-	0,133,133,175,0,0,162,172,0,8,2,36,
-	240,129,133,175,2,131,1,60,20,211,32,172,
-	4,0,162,172,0,0,164,140,0,0,0,0,
-	4,0,131,140,0,0,0,0,43,16,102,0,
-	14,0,64,20,0,0,0,0,5,0,102,20,
-	35,16,102,0,0,0,130,140,0,0,0,0,
-	43,50,192,8,0,0,162,172,4,0,130,172,
-	192,16,2,0,33,32,130,0,4,0,134,172,
-	240,129,133,175,57,50,192,8,8,0,130,36,
-	240,129,130,143,0,0,0,0,4,0,130,16,
-	33,40,128,0,0,0,132,140,28,50,192,8,
-	0,0,0,0,2,131,4,60,15,63,192,12,
-	64,148,132,36,33,16,0,0,16,0,191,143,
-	24,0,189,39,8,0,224,3,0,0,0,0,
-	56,0,128,16,248,255,132,36,240,129,133,143,
-	0,0,0,0,78,50,192,8,43,16,164,0,
-	0,0,163,140,0,0,0,0,43,16,163,0,
-	5,0,64,20,43,16,164,0,12,0,64,20,
-	43,16,131,0,10,0,64,20,0,0,0,0,
-	33,40,96,0,43,16,164,0,244,255,64,16,
-	0,0,0,0,0,0,162,140,0,0,0,0,
-	43,16,130,0,239,255,64,16,0,0,0,0,
-	4,0,134,140,0,0,163,140,192,16,6,0,
-	33,16,130,0,11,0,67,20,0,0,0,0,
-	4,0,98,140,0,0,0,0,33,16,194,0,
-	4,0,130,172,0,0,162,140,0,0,0,0,
-	0,0,66,140,0,0,0,0,102,50,192,8,
-	0,0,130,172,0,0,131,172,4,0,163,140,
-	0,0,0,0,192,16,3,0,33,16,162,0,
-	9,0,68,20,0,0,0,0,4,0,130,140,
-	0,0,0,0,33,16,98,0,4,0,162,172,
-	0,0,130,140,0,0,0,0,117,50,192,8,
-	0,0,162,172,0,0,164,172,240,129,133,175,
-	8,0,224,3,0,0,0,0,232,255,189,39,
-	16,0,191,175,0,50,192,12,0,0,0,0,
-	178,45,192,12,33,32,0,0,16,0,191,143,
-	24,0,189,39,8,0,224,3,0,0,0,0,
-	1,0,3,36,5,0,195,20,255,255,2,36,
-	0,0,226,140,0,0,0,0,43,16,2,0,
-	35,16,2,0,8,0,224,3,0,0,0,0,
-	224,255,189,39,16,0,176,175,33,128,224,0,
-	20,0,177,175,48,0,177,143,1,0,2,36,
-	5,0,162,20,24,0,191,175,0,0,194,140,
-	0,0,0,0,8,0,64,16,0,0,0,0,
-	11,0,2,36,33,32,0,2,33,40,32,2,
-	48,72,192,12,96,0,2,174,1,0,66,36,
-	100,0,2,174,17,0,34,146,0,0,0,0,
-	1,0,66,52,17,0,34,162,24,0,191,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,8,0,224,3,0,0,0,0,
-	16,0,163,143,0,0,0,0,17,0,98,144,
-	0,0,0,0,2,0,66,52,8,0,224,3,
-	17,0,98,160,8,0,224,3,0,0,0,0,
-	224,255,189,39,16,0,176,175,33,128,128,0,
-	244,129,131,151,255,0,2,36,28,0,191,175,
-	24,0,178,175,20,0,177,175,4,0,2,174,
-	60,0,0,174,1,0,98,36,244,129,130,167,
-	10,0,3,166,3,0,162,136,0,0,162,152,
-	7,0,163,136,4,0,163,152,11,0,164,136,
-	8,0,164,152,15,0,167,136,12,0,167,152,
-	15,0,2,170,12,0,2,186,19,0,3,170,
-	16,0,3,186,23,0,4,170,20,0,4,186,
-	27,0,7,170,24,0,7,186,3,0,194,136,
-	0,0,194,152,7,0,195,136,4,0,195,152,
-	11,0,196,136,8,0,196,152,15,0,197,136,
-	12,0,197,152,31,0,2,170,28,0,2,186,
-	35,0,3,170,32,0,3,186,39,0,4,170,
-	36,0,4,186,43,0,5,170,40,0,5,186,
-	80,0,2,142,76,0,3,142,0,0,0,0,
-	35,16,67,0,255,255,81,48,88,0,3,150,
-	3,0,2,36,13,0,98,16,0,0,0,0,
-	2,131,18,60,160,204,82,38,156,71,192,12,
-	33,32,64,2,7,0,81,20,33,32,64,2,
-	76,0,5,142,0,0,0,0,168,71,192,12,
-	33,48,32,2,21,0,64,16,33,16,0,0,
-	2,131,18,60,192,204,82,38,156,71,192,12,
-	33,32,64,2,7,0,81,20,33,32,64,2,
-	76,0,5,142,0,0,0,0,168,71,192,12,
-	33,48,32,2,9,0,64,16,33,16,0,0,
-	3,131,3,60,132,17,99,36,0,0,98,140,
-	1,0,4,36,1,0,66,36,178,45,192,12,
-	0,0,98,172,1,0,2,36,28,0,191,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,0,0,0,0,
-	0,0,0,0,224,255,189,39,20,0,177,175,
-	33,136,224,0,16,0,176,175,48,0,176,143,
-	24,0,191,175,156,71,192,12,33,32,32,2,
-	0,0,2,174,33,16,32,2,24,0,191,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,8,0,224,3,33,16,224,0,
-	0,0,227,140,204,204,2,60,205,204,66,52,
-	25,0,98,0,16,32,0,0,0,0,0,0,
-	0,0,0,0,8,0,224,3,194,16,4,0,
-	224,255,189,39,16,0,176,175,33,128,224,0,
-	33,32,0,2,33,40,0,0,20,0,177,175,
-	48,0,177,143,24,0,191,175,208,71,192,12,
-	16,0,6,36,2,0,64,20,35,16,80,0,
-	16,0,2,36,0,0,34,174,33,16,0,2,
-	24,0,191,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,232,255,189,39,
-	40,0,164,143,44,0,165,143,16,0,191,175,
-	205,59,192,12,0,0,0,0,16,0,191,143,
-	24,0,189,39,8,0,224,3,0,0,0,0,
-	232,255,189,39,40,0,164,143,44,0,165,143,
-	16,0,191,175,239,59,192,12,0,0,0,0,
-	16,0,191,143,24,0,189,39,8,0,224,3,
-	0,0,0,0,232,255,189,39,40,0,164,143,
-	44,0,165,143,16,0,191,175,17,60,192,12,
-	0,0,0,0,16,0,191,143,24,0,189,39,
-	8,0,224,3,0,0,0,0,8,0,224,3,
-	33,16,224,0,0,0,226,140,8,0,224,3,
-	0,0,0,0,216,255,189,39,24,0,176,175,
-	56,0,176,143,32,0,191,175,28,0,177,175,
-	36,0,2,142,1,0,3,36,20,0,81,140,
-	187,0,163,20,0,0,0,0,0,0,195,140,
-	0,0,0,0,183,0,96,16,0,0,0,0,
-	32,133,130,143,0,0,0,0,43,16,67,0,
-	178,0,64,20,255,255,104,36,64,18,8,0,
-	2,131,3,60,192,246,99,36,33,40,67,0,
-	255,255,132,36,22,0,130,44,170,0,64,16,
-	128,16,4,0,2,131,1,60,33,8,34,0,
-	144,148,34,140,0,0,0,0,8,0,64,0,
-	0,0,0,0,2,0,2,36,16,0,2,162,
-	17,0,2,146,0,0,195,140,0,0,0,0,
-	15,52,192,8,2,0,66,52,33,32,32,2,
-	17,0,3,146,4,0,2,36,16,0,2,162,
-	40,0,0,166,44,0,17,174,2,0,99,52,
-	156,71,192,12,17,0,3,162,255,255,66,48,
-	33,16,34,2,48,0,2,174,40,52,192,8,
-	52,0,0,166,17,0,3,146,2,0,2,36,
-	16,0,2,162,243,51,192,8,40,0,17,174,
-	17,0,3,146,2,0,2,36,16,0,2,162,
-	243,51,192,8,40,0,17,174,66,0,2,36,
-	13,0,0,21,16,0,2,162,24,133,132,143,
-	0,0,0,0,64,25,4,0,35,24,100,0,
-	128,17,3,0,35,16,67,0,192,16,2,0,
-	33,16,68,0,128,24,2,0,33,16,67,0,
-	178,51,192,8,192,17,2,0,152,0,2,60,
-	128,150,66,52,40,0,2,174,17,0,2,146,
-	0,0,0,0,199,51,192,8,2,0,66,52,
-	17,0,3,146,4,0,2,36,16,0,2,162,
-	20,0,162,36,44,0,2,174,26,0,162,36,
-	40,0,0,166,48,0,2,174,243,51,192,8,
-	52,0,0,166,2,0,2,36,16,0,2,162,
-	17,0,2,146,1,0,3,36,40,0,3,174,
-	2,0,66,52,40,52,192,8,17,0,2,162,
-	17,0,3,146,0,0,0,0,241,51,192,8,
-	67,0,2,36,65,0,2,36,16,0,2,162,
-	17,0,2,146,168,0,163,140,0,0,0,0,
-	15,52,192,8,2,0,66,52,65,0,2,36,
-	16,0,2,162,156,0,162,140,0,1,164,140,
-	22,52,192,8,0,0,0,0,65,0,2,36,
-	16,0,2,162,17,0,2,146,0,1,163,140,
-	0,0,0,0,15,52,192,8,2,0,66,52,
-	65,0,2,36,16,0,2,162,17,0,2,146,
-	164,0,163,140,0,0,0,0,15,52,192,8,
-	2,0,66,52,65,0,2,36,16,0,2,162,
-	17,0,2,146,160,0,163,140,0,0,0,0,
-	15,52,192,8,2,0,66,52,17,0,3,146,
-	65,0,2,36,16,0,2,162,40,0,0,174,
-	2,0,99,52,40,52,192,8,17,0,3,162,
-	65,0,2,36,16,0,2,162,172,0,162,140,
-	4,1,164,140,22,52,192,8,0,0,0,0,
-	65,0,2,36,16,0,2,162,17,0,2,146,
-	4,1,163,140,0,0,0,0,15,52,192,8,
-	2,0,66,52,65,0,2,36,16,0,2,162,
-	17,0,2,146,184,0,163,140,0,0,0,0,
-	15,52,192,8,2,0,66,52,65,0,2,36,
-	16,0,2,162,17,0,2,146,188,0,163,140,
-	2,0,66,52,40,0,3,174,40,52,192,8,
-	17,0,2,162,66,0,2,36,16,0,2,162,
-	172,0,162,140,176,0,164,140,17,0,3,146,
-	35,16,68,0,2,0,99,52,40,0,2,174,
-	40,52,192,8,17,0,3,162,16,0,160,175,
-	33,32,224,0,33,40,0,2,2,131,7,60,
-	96,204,231,36,226,76,192,12,2,0,6,36,
-	40,52,192,8,0,0,0,0,33,32,224,0,
-	200,76,192,12,33,40,0,2,32,0,191,143,
-	28,0,177,143,24,0,176,143,8,0,224,3,
-	40,0,189,39,224,255,189,39,16,0,176,175,
-	33,128,224,0,20,0,177,175,48,0,177,143,
-	1,0,2,36,10,0,162,20,24,0,191,175,
-	0,0,198,140,0,0,0,0,6,0,192,16,
-	0,0,0,0,32,133,130,143,0,0,0,0,
-	43,16,70,0,5,0,64,16,7,0,2,36,
-	33,32,0,2,33,40,32,2,70,52,192,8,
-	11,0,2,36,7,0,130,16,33,32,0,2,
-	33,40,32,2,17,0,2,36,48,72,192,12,
-	96,0,2,174,1,0,66,36,100,0,2,174,
-	17,0,34,146,0,0,0,0,1,0,66,52,
-	17,0,34,162,24,0,191,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,32,0,189,39,
-	208,255,189,39,32,0,176,175,64,0,176,143,
-	36,0,177,175,33,136,224,0,4,0,160,20,
-	40,0,191,175,1,0,2,36,106,52,192,8,
-	24,0,162,175,0,0,198,140,32,133,130,143,
-	0,0,0,0,43,16,194,0,3,0,64,16,
-	1,0,194,36,106,52,192,8,24,0,162,175,
-	17,0,2,146,0,0,0,0,18,0,66,52,
-	116,52,192,8,17,0,2,162,16,0,176,175,
-	1,0,5,36,24,0,166,39,97,51,192,12,
-	33,56,32,2,33,32,32,2,33,40,0,2,
-	1,0,6,36,253,76,192,12,24,0,167,39,
-	40,0,191,143,36,0,177,143,32,0,176,143,
-	8,0,224,3,48,0,189,39,16,0,163,143,
-	1,0,2,36,13,0,162,20,14,0,2,36,
-	0,0,198,140,0,0,0,0,9,0,192,16,
-	0,0,0,0,32,133,130,143,0,0,0,0,
-	43,16,70,0,4,0,64,20,14,0,2,36,
-	7,0,2,36,2,0,130,16,14,0,2,36,
-	96,0,226,172,17,0,98,144,0,0,0,0,
-	2,0,66,52,8,0,224,3,17,0,98,160,
-	16,0,162,143,0,0,0,0,8,0,224,3,
-	0,0,226,172,0,0,226,140,8,0,224,3,
-	0,0,0,0,232,255,189,39,40,0,168,143,
-	1,0,2,36,61,0,162,20,16,0,191,175,
-	0,0,197,140,0,0,0,0,57,0,160,16,
-	0,0,0,0,32,133,130,143,0,0,0,0,
-	43,16,69,0,52,0,64,20,255,255,132,36,
-	5,0,130,44,49,0,64,16,128,16,4,0,
-	2,131,1,60,33,8,34,0,232,148,34,140,
-	0,0,0,0,8,0,64,0,0,0,0,0,
-	64,0,2,36,16,0,2,161,0,163,5,60,
-	220,5,165,52,3,0,162,136,0,0,162,152,
-	0,0,0,0,43,0,2,169,40,0,2,185,
-	17,0,2,145,0,0,0,0,213,52,192,8,
-	2,0,66,52,2,0,2,36,16,0,2,161,
-	17,0,2,145,0,0,195,140,0,0,0,0,
-	198,52,192,8,2,0,66,52,64,0,2,36,
-	16,0,2,161,17,0,2,145,128,132,131,143,
-	2,0,66,52,40,0,3,173,218,52,192,8,
-	17,0,2,161,2,0,2,36,16,0,2,161,
-	17,0,2,145,0,0,0,0,211,52,192,8,
-	1,0,3,36,2,0,2,36,16,0,2,161,
-	17,0,2,145,220,5,3,36,40,0,3,173,
-	2,0,66,52,218,52,192,8,17,0,2,161,
-	33,32,224,0,200,76,192,12,33,40,0,1,
-	16,0,191,143,24,0,189,39,8,0,224,3,
-	0,0,0,0,208,255,189,39,32,0,176,175,
-	64,0,176,143,36,0,177,175,33,136,224,0,
-	4,0,160,20,40,0,191,175,1,0,2,36,
-	245,52,192,8,24,0,162,175,0,0,198,140,
-	32,133,130,143,0,0,0,0,43,16,194,0,
-	3,0,64,16,1,0,194,36,245,52,192,8,
-	24,0,162,175,17,0,2,146,0,0,0,0,
-	18,0,66,52,255,52,192,8,17,0,2,162,
-	16,0,176,175,1,0,5,36,24,0,166,39,
-	150,52,192,12,33,56,32,2,33,32,32,2,
-	33,40,0,2,1,0,6,36,253,76,192,12,
-	24,0,167,39,40,0,191,143,36,0,177,143,
-	32,0,176,143,8,0,224,3,48,0,189,39,
-	232,255,189,39,40,0,165,143,16,0,191,175,
-	200,76,192,12,33,32,224,0,16,0,191,143,
-	24,0,189,39,8,0,224,3,0,0,0,0,
-	16,0,163,143,14,0,2,36,96,0,226,172,
-	17,0,98,144,0,0,0,0,2,0,66,52,
-	8,0,224,3,17,0,98,160,224,255,189,39,
-	16,0,176,175,33,128,224,0,17,0,2,36,
-	24,0,191,175,20,0,177,175,96,0,2,174,
-	48,0,177,143,33,32,0,2,48,72,192,12,
-	33,40,32,2,1,0,66,36,100,0,2,174,
-	17,0,34,146,0,0,0,0,1,0,66,52,
-	17,0,34,162,24,0,191,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,32,0,189,39,
-	16,0,163,143,0,0,0,0,17,0,98,144,
-	0,0,0,0,18,0,66,52,8,0,224,3,
-	17,0,98,160,8,0,224,3,33,16,224,0,
-	224,255,189,39,48,0,168,143,1,0,2,36,
-	114,0,162,20,24,0,191,175,0,0,195,140,
-	0,0,0,0,110,0,96,16,0,0,0,0,
-	32,133,130,143,0,0,0,0,43,16,67,0,
-	105,0,64,20,255,255,98,36,64,18,2,0,
-	2,131,3,60,192,246,99,36,33,24,67,0,
-	255,255,132,36,17,0,130,44,97,0,64,16,
-	128,16,4,0,2,131,1,60,33,8,34,0,
-	0,149,34,140,0,0,0,0,8,0,64,0,
-	0,0,0,0,2,0,2,36,16,0,2,161,
-	17,0,2,145,0,0,195,140,0,0,0,0,
-	140,53,192,8,2,0,66,52,2,0,2,36,
-	16,0,2,161,44,0,99,140,17,0,2,145,
-	16,0,99,140,0,0,0,0,101,53,192,8,
-	2,0,66,52,2,0,2,36,16,0,2,161,
-	44,0,99,140,17,0,2,145,12,0,99,140,
-	2,0,66,52,17,0,2,161,173,53,192,8,
-	40,0,3,173,2,0,2,36,16,0,2,161,
-	17,0,2,145,212,0,99,140,0,0,0,0,
-	140,53,192,8,2,0,66,52,2,0,2,36,
-	16,0,2,161,17,0,2,145,192,0,99,140,
-	0,0,0,0,140,53,192,8,2,0,66,52,
-	2,0,2,36,16,0,2,161,17,0,2,145,
-	208,0,99,140,0,0,0,0,140,53,192,8,
-	2,0,66,52,2,0,2,36,16,0,2,161,
-	204,0,98,140,184,0,100,140,17,0,3,145,
-	33,16,68,0,2,0,99,52,40,0,2,173,
-	173,53,192,8,17,0,3,161,2,0,2,36,
-	16,0,2,161,17,0,2,145,196,0,99,140,
-	2,0,66,52,40,0,3,173,173,53,192,8,
-	17,0,2,161,17,0,3,145,2,0,2,36,
-	16,0,2,161,40,0,0,173,2,0,99,52,
-	173,53,192,8,17,0,3,161,2,0,2,36,
-	16,0,2,161,44,0,100,140,17,0,2,145,
-	20,0,131,140,24,0,132,140,2,0,66,52,
-	17,0,2,161,33,24,100,0,173,53,192,8,
-	40,0,3,173,16,0,160,175,33,32,224,0,
-	33,40,0,1,2,131,7,60,104,204,231,36,
-	226,76,192,12,11,0,6,36,173,53,192,8,
-	0,0,0,0,33,32,224,0,200,76,192,12,
-	33,40,0,1,24,0,191,143,32,0,189,39,
-	8,0,224,3,0,0,0,0,208,255,189,39,
-	32,0,176,175,64,0,176,143,36,0,177,175,
-	33,136,224,0,4,0,160,20,40,0,191,175,
-	1,0,2,36,200,53,192,8,24,0,162,175,
-	0,0,198,140,32,133,130,143,0,0,0,0,
-	43,16,194,0,3,0,64,16,1,0,194,36,
-	200,53,192,8,24,0,162,175,17,0,2,146,
-	0,0,0,0,18,0,66,52,210,53,192,8,
-	17,0,2,162,16,0,176,175,1,0,5,36,
-	24,0,166,39,52,53,192,12,33,56,32,2,
-	33,32,32,2,33,40,0,2,1,0,6,36,
-	253,76,192,12,24,0,167,39,40,0,191,143,
-	36,0,177,143,32,0,176,143,8,0,224,3,
-	48,0,189,39,0,0,226,140,8,0,224,3,
-	0,0,0,0,3,131,2,60,28,18,66,148,
-	0,0,0,0,2,0,66,48,2,0,64,16,
-	2,0,3,36,1,0,3,36,8,0,224,3,
-	33,16,96,0,232,255,189,39,40,0,164,143,
-	16,0,191,175,1,0,132,56,186,59,192,12,
-	1,0,132,44,16,0,191,143,24,0,189,39,
-	8,0,224,3,0,0,0,0,16,0,163,143,
-	6,0,2,36,0,0,98,172,8,0,224,3,
-	33,16,224,0,224,255,189,39,48,0,168,143,
-	1,0,2,36,52,0,162,20,24,0,191,175,
-	0,0,197,140,0,0,0,0,48,0,160,16,
-	0,0,0,0,24,133,130,143,0,0,0,0,
-	43,16,69,0,43,0,64,20,255,255,132,36,
-	5,0,130,44,40,0,64,16,128,16,4,0,
-	2,131,1,60,33,8,34,0,72,149,34,140,
-	0,0,0,0,8,0,64,0,0,0,0,0,
-	2,0,2,36,16,0,2,161,17,0,2,145,
-	0,0,195,140,2,0,66,52,40,0,3,173,
-	45,54,192,8,17,0,2,161,2,0,2,36,
-	16,0,2,161,0,0,194,140,17,0,3,145,
-	1,0,66,36,2,0,99,52,40,0,2,173,
-	45,54,192,8,17,0,3,161,16,0,160,175,
-	33,32,224,0,33,40,0,1,2,131,7,60,
-	148,204,231,36,226,76,192,12,2,0,6,36,
-	45,54,192,8,0,0,0,0,17,0,3,145,
-	2,0,2,36,16,0,2,161,40,0,0,173,
-	2,0,99,52,45,54,192,8,17,0,3,161,
-	33,32,224,0,200,76,192,12,33,40,0,1,
-	24,0,191,143,32,0,189,39,8,0,224,3,
-	0,0,0,0,208,255,189,39,32,0,176,175,
-	64,0,176,143,36,0,177,175,33,136,224,0,
-	4,0,160,20,40,0,191,175,1,0,2,36,
-	72,54,192,8,24,0,162,175,0,0,198,140,
-	24,133,130,143,0,0,0,0,43,16,194,0,
-	3,0,64,16,1,0,194,36,72,54,192,8,
-	24,0,162,175,17,0,2,146,0,0,0,0,
-	18,0,66,52,82,54,192,8,17,0,2,162,
-	16,0,176,175,1,0,5,36,24,0,166,39,
-	242,53,192,12,33,56,32,2,33,32,32,2,
-	33,40,0,2,1,0,6,36,253,76,192,12,
-	24,0,167,39,40,0,191,143,36,0,177,143,
-	32,0,176,143,8,0,224,3,48,0,189,39,
-	0,0,226,148,8,0,224,3,0,0,0,0,
-	8,0,224,3,33,16,224,0,16,0,163,143,
-	8,0,2,36,0,0,98,172,8,0,224,3,
-	33,16,224,0,224,255,189,39,16,0,176,175,
-	48,0,176,143,1,0,2,36,24,0,191,175,
-	126,0,162,20,20,0,177,175,0,0,198,140,
-	0,0,0,0,122,0,192,16,0,0,0,0,
-	24,133,130,143,0,0,0,0,43,16,70,0,
-	117,0,64,20,192,17,6,0,3,131,3,60,
-	16,13,99,36,33,136,67,0,255,255,132,36,
-	10,0,130,44,110,0,64,16,128,16,4,0,
-	2,131,1,60,33,8,34,0,96,149,34,140,
-	0,0,0,0,8,0,64,0,0,0,0,0,
-	17,0,3,146,2,0,2,36,16,0,2,162,
-	211,54,192,8,40,0,6,174,2,0,2,36,
-	16,0,2,162,0,0,34,150,17,0,3,146,
-	0,0,0,0,143,54,192,8,2,18,2,0,
-	2,0,2,36,16,0,2,162,4,0,34,142,
-	17,0,3,146,1,0,66,36,2,0,99,52,
-	40,0,2,174,232,54,192,8,17,0,3,162,
-	2,0,2,36,16,0,2,162,4,0,34,142,
-	0,0,0,0,2,0,64,16,2,0,3,36,
-	1,0,3,36,17,0,2,146,40,0,3,174,
-	2,0,66,52,232,54,192,8,17,0,2,162,
-	2,0,2,36,16,0,2,162,17,0,2,146,
-	8,0,35,142,0,0,0,0,226,54,192,8,
-	2,0,66,52,9,50,192,12,8,0,4,36,
-	33,48,64,0,15,0,34,138,12,0,34,154,
-	19,0,35,138,16,0,35,154,3,0,194,168,
-	0,0,194,184,7,0,195,168,196,54,192,8,
-	4,0,195,184,2,0,2,36,16,0,2,162,
-	17,0,2,146,20,0,35,142,0,0,0,0,
-	226,54,192,8,2,0,66,52,9,50,192,12,
-	8,0,4,36,33,48,64,0,27,0,34,138,
-	24,0,34,154,31,0,35,138,28,0,35,154,
-	3,0,194,168,0,0,194,184,7,0,195,168,
-	4,0,195,184,0,0,194,148,0,0,0,0,
-	0,26,2,0,2,18,2,0,37,24,98,0,
-	0,0,195,164,17,0,3,146,4,0,2,36,
-	16,0,2,162,1,0,2,36,40,0,2,166,
-	8,0,194,36,44,0,6,174,48,0,2,174,
-	52,0,0,166,2,0,99,52,232,54,192,8,
-	17,0,3,162,2,0,2,36,16,0,2,162,
-	17,0,2,146,32,0,35,150,0,0,0,0,
-	226,54,192,8,2,0,66,52,2,0,2,36,
-	16,0,2,162,17,0,2,146,104,0,35,142,
-	2,0,66,52,40,0,3,174,232,54,192,8,
-	17,0,2,162,33,32,224,0,200,76,192,12,
-	33,40,0,2,24,0,191,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,32,0,189,39,
-	224,255,189,39,16,0,176,175,33,128,224,0,
-	20,0,177,175,48,0,177,143,1,0,2,36,
-	10,0,162,20,24,0,191,175,0,0,198,140,
-	0,0,0,0,6,0,192,16,0,0,0,0,
-	24,133,130,143,0,0,0,0,43,16,70,0,
-	5,0,64,16,2,0,2,36,33,32,0,2,
-	33,40,32,2,13,55,192,8,11,0,2,36,
-	14,0,130,16,2,0,130,44,5,0,64,20,
-	6,0,130,44,3,0,64,16,4,0,130,44,
-	8,0,64,16,0,0,0,0,33,32,0,2,
-	33,40,32,2,17,0,2,36,48,72,192,12,
-	96,0,2,174,1,0,66,36,100,0,2,174,
-	17,0,34,146,0,0,0,0,1,0,66,52,
-	17,0,34,162,24,0,191,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,32,0,189,39,
-	208,255,189,39,32,0,176,175,64,0,176,143,
-	36,0,177,175,33,136,224,0,4,0,160,20,
-	40,0,191,175,1,0,2,36,49,55,192,8,
-	24,0,162,175,0,0,198,140,24,133,130,143,
-	0,0,0,0,43,16,194,0,3,0,64,16,
-	1,0,194,36,49,55,192,8,24,0,162,175,
-	17,0,2,146,0,0,0,0,18,0,66,52,
-	59,55,192,8,17,0,2,162,16,0,176,175,
-	1,0,5,36,24,0,166,39,97,54,192,12,
-	33,56,32,2,33,32,32,2,33,40,0,2,
-	1,0,6,36,253,76,192,12,24,0,167,39,
-	40,0,191,143,36,0,177,143,32,0,176,143,
-	8,0,224,3,48,0,189,39,232,255,189,39,
-	33,64,128,0,16,0,176,175,40,0,176,143,
-	1,0,2,36,57,0,162,20,20,0,191,175,
-	0,0,196,140,0,0,0,0,54,0,128,16,
-	14,0,2,36,24,133,130,143,0,0,0,0,
-	43,16,68,0,49,0,64,20,14,0,2,36,
-	192,17,4,0,3,131,3,60,16,13,99,36,
-	33,48,67,0,4,0,2,36,21,0,2,17,
-	5,0,2,45,5,0,64,16,2,0,2,36,
-	8,0,2,17,14,0,2,36,129,55,192,8,
-	96,0,226,172,5,0,2,36,28,0,2,17,
-	14,0,2,36,129,55,192,8,96,0,226,172,
-	0,0,195,144,0,0,0,0,0,0,195,164,
-	40,0,2,142,0,0,0,0,0,18,2,0,
-	37,24,98,0,129,55,192,8,0,0,195,164,
-	40,0,3,142,0,0,0,0,5,0,101,16,
-	2,0,2,36,7,0,98,16,14,0,2,36,
-	129,55,192,8,96,0,226,172,187,42,192,12,
-	1,0,5,36,129,55,192,8,0,0,0,0,
-	187,42,192,12,33,40,0,0,129,55,192,8,
-	0,0,0,0,40,0,2,142,0,0,0,0,
-	129,55,192,8,8,0,194,172,14,0,2,36,
-	96,0,226,172,17,0,2,146,0,0,0,0,
-	2,0,66,52,17,0,2,162,20,0,191,143,
-	16,0,176,143,8,0,224,3,24,0,189,39,
-	216,255,189,39,20,0,177,175,33,136,128,0,
-	28,0,179,175,33,152,160,0,24,0,178,175,
-	33,144,224,0,16,0,176,175,56,0,176,143,
-	1,0,2,36,46,0,98,22,32,0,191,175,
-	0,0,196,140,0,0,0,0,42,0,128,16,
-	0,0,0,0,58,25,192,12,0,0,0,0,
-	33,32,64,0,37,0,128,16,2,0,2,36,
-	11,0,34,18,3,0,34,46,5,0,64,16,
-	3,0,2,36,15,0,51,18,4,0,2,36,
-	195,55,192,8,33,32,64,2,20,0,34,18,
-	33,32,64,2,195,55,192,8,0,0,0,0,
-	2,0,2,36,16,0,2,162,17,0,2,146,
-	10,0,131,132,2,0,66,52,40,0,3,174,
-	197,55,192,8,17,0,2,162,17,0,3,146,
-	16,0,2,162,4,0,130,36,44,0,2,174,
-	10,0,130,36,40,0,0,166,48,0,2,174,
-	191,55,192,8,52,0,0,166,17,0,3,146,
-	2,0,2,36,16,0,2,162,40,0,17,174,
-	2,0,99,52,197,55,192,8,17,0,3,162,
-	33,32,64,2,200,76,192,12,33,40,0,2,
-	32,0,191,143,28,0,179,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	40,0,189,39,208,255,189,39,32,0,176,175,
-	64,0,176,143,40,0,178,175,33,144,128,0,
-	36,0,177,175,33,136,224,0,3,0,160,20,
-	44,0,191,175,218,55,192,8,1,0,2,36,
-	0,0,194,140,0,0,0,0,1,0,66,36,
-	24,0,162,175,24,0,164,143,58,25,192,12,
-	0,0,0,0,6,0,64,20,33,32,64,2,
-	17,0,2,146,0,0,0,0,18,0,66,52,
-	239,55,192,8,17,0,2,162,16,0,176,175,
-	1,0,5,36,24,0,166,39,137,55,192,12,
-	33,56,32,2,33,32,32,2,33,40,0,2,
-	1,0,6,36,253,76,192,12,24,0,167,39,
-	44,0,191,143,40,0,178,143,36,0,177,143,
-	32,0,176,143,8,0,224,3,48,0,189,39,
-	232,255,189,39,40,0,168,143,1,0,2,36,
-	63,0,162,20,16,0,191,175,0,0,195,140,
-	0,0,0,0,59,0,96,16,0,0,0,0,
-	24,133,130,143,0,0,0,0,43,16,67,0,
-	54,0,64,20,64,18,3,0,2,131,3,60,
-	192,246,99,36,33,24,67,0,255,255,132,36,
-	5,0,130,44,47,0,64,16,128,16,4,0,
-	2,131,1,60,33,8,34,0,136,149,34,140,
-	0,0,0,0,8,0,64,0,0,0,0,0,
-	2,0,2,36,16,0,2,161,17,0,2,145,
-	0,0,195,140,0,0,0,0,43,56,192,8,
-	2,0,66,52,2,0,2,36,16,0,2,161,
-	17,0,2,145,220,5,3,36,40,0,3,173,
-	2,0,66,52,59,56,192,8,17,0,2,161,
-	65,0,2,36,16,0,2,161,17,0,2,145,
-	156,0,99,140,0,0,0,0,43,56,192,8,
-	2,0,66,52,65,0,2,36,16,0,2,161,
-	17,0,2,145,172,0,99,140,2,0,66,52,
-	40,0,3,173,59,56,192,8,17,0,2,161,
-	65,0,2,36,16,0,2,161,156,0,98,140,
-	252,0,100,140,17,0,3,145,35,16,68,0,
-	2,0,99,52,40,0,2,173,59,56,192,8,
-	17,0,3,161,33,32,224,0,200,76,192,12,
-	33,40,0,1,16,0,191,143,24,0,189,39,
-	8,0,224,3,0,0,0,0,208,255,189,39,
-	32,0,176,175,64,0,176,143,36,0,177,175,
-	33,136,224,0,4,0,160,20,40,0,191,175,
-	1,0,2,36,86,56,192,8,24,0,162,175,
-	0,0,198,140,24,133,130,143,0,0,0,0,
-	43,16,194,0,3,0,64,16,1,0,194,36,
-	86,56,192,8,24,0,162,175,17,0,2,146,
-	0,0,0,0,18,0,66,52,96,56,192,8,
-	17,0,2,162,16,0,176,175,1,0,5,36,
-	24,0,166,39,245,55,192,12,33,56,32,2,
-	33,32,32,2,33,40,0,2,1,0,6,36,
-	253,76,192,12,24,0,167,39,40,0,191,143,
-	36,0,177,143,32,0,176,143,8,0,224,3,
-	48,0,189,39,0,0,0,0,0,0,0,0,
-	0,0,0,0,200,255,189,39,72,0,163,143,
-	44,0,177,175,33,136,128,0,20,0,165,175,
-	33,40,224,0,2,131,2,60,172,210,66,140,
-	152,132,135,143,33,32,0,0,48,0,191,175,
-	40,0,176,175,24,0,160,175,28,0,160,175,
-	36,0,160,175,16,0,162,175,104,77,192,12,
-	32,0,163,175,33,128,64,0,3,0,0,22,
-	33,32,0,2,143,56,192,8,33,16,0,0,
-	197,80,192,12,33,40,32,2,255,255,3,36,
-	5,0,67,20,0,0,0,0,167,83,192,12,
-	33,32,0,2,143,56,192,8,33,16,0,0,
-	167,83,192,12,33,32,0,2,8,0,34,142,
-	4,0,35,142,0,0,0,0,35,16,67,0,
-	255,255,66,48,48,0,191,143,44,0,177,143,
-	40,0,176,143,8,0,224,3,56,0,189,39,
-	200,255,189,39,44,0,177,175,33,136,128,0,
-	72,0,168,143,33,32,0,0,20,0,165,175,
-	33,40,224,0,2,131,3,60,172,210,99,140,
-	152,132,135,143,1,0,2,36,48,0,191,175,
-	40,0,176,175,24,0,162,175,28,0,160,175,
-	36,0,160,175,16,0,163,175,104,77,192,12,
-	32,0,168,175,33,128,64,0,3,0,0,22,
-	33,32,0,2,188,56,192,8,33,16,0,0,
-	197,80,192,12,33,40,32,2,255,255,3,36,
-	5,0,67,20,0,0,0,0,167,83,192,12,
-	33,32,0,2,188,56,192,8,33,16,0,0,
-	167,83,192,12,33,32,0,2,8,0,34,142,
-	4,0,35,142,0,0,0,0,35,16,67,0,
-	255,255,66,48,48,0,191,143,44,0,177,143,
-	40,0,176,143,8,0,224,3,56,0,189,39,
-	176,255,189,39,44,0,177,175,108,0,177,143,
-	68,0,183,175,96,0,183,143,72,0,190,175,
-	100,0,190,143,48,0,178,175,33,144,128,0,
-	56,0,180,175,33,160,160,0,52,0,179,175,
-	33,152,192,0,40,0,176,175,33,128,224,0,
-	60,0,181,175,1,0,21,36,76,0,191,175,
-	3,0,53,18,64,0,182,175,9,57,192,8,
-	255,255,2,36,4,0,6,36,2,131,22,60,
-	48,205,214,38,160,132,132,143,104,0,165,143,
-	128,32,4,0,80,68,192,12,33,32,150,0,
-	33,32,0,0,33,40,0,2,152,132,135,143,
-	2,0,2,36,24,0,162,175,160,132,130,143,
-	2,131,3,60,172,210,99,140,33,48,96,2,
-	20,0,180,175,28,0,160,175,32,0,183,175,
-	36,0,181,175,1,0,81,36,104,77,192,12,
-	16,0,163,175,33,128,64,0,23,0,0,18,
-	33,40,0,0,16,0,190,175,33,32,0,2,
-	33,48,32,2,108,84,192,12,33,56,192,2,
-	255,255,17,36,13,0,81,16,33,32,0,2,
-	197,80,192,12,33,40,64,2,9,0,81,16,
-	0,0,0,0,167,83,192,12,33,32,0,2,
-	8,0,66,142,4,0,67,142,0,0,0,0,
-	35,16,67,0,9,57,192,8,255,255,66,48,
-	167,83,192,12,33,32,0,2,33,16,0,0,
-	76,0,191,143,72,0,190,143,68,0,183,143,
-	64,0,182,143,60,0,181,143,56,0,180,143,
-	52,0,179,143,48,0,178,143,44,0,177,143,
-	40,0,176,143,8,0,224,3,80,0,189,39,
-	176,255,189,39,44,0,177,175,108,0,177,143,
-	68,0,183,175,96,0,183,143,72,0,190,175,
-	100,0,190,143,48,0,178,175,33,144,128,0,
-	56,0,180,175,33,160,160,0,52,0,179,175,
-	33,152,192,0,40,0,176,175,33,128,224,0,
-	60,0,181,175,1,0,21,36,76,0,191,175,
-	3,0,53,18,64,0,182,175,93,57,192,8,
-	255,255,2,36,4,0,6,36,2,131,22,60,
-	48,205,214,38,160,132,132,143,104,0,165,143,
-	128,32,4,0,80,68,192,12,33,32,150,0,
-	33,32,0,0,33,40,0,2,152,132,135,143,
-	3,0,2,36,24,0,162,175,160,132,130,143,
-	2,131,3,60,172,210,99,140,33,48,96,2,
-	20,0,180,175,28,0,160,175,32,0,183,175,
-	36,0,181,175,1,0,81,36,104,77,192,12,
-	16,0,163,175,33,128,64,0,23,0,0,18,
-	33,40,0,0,16,0,190,175,33,32,0,2,
-	33,48,32,2,108,84,192,12,33,56,192,2,
-	255,255,17,36,13,0,81,16,33,32,0,2,
-	197,80,192,12,33,40,64,2,9,0,81,16,
-	0,0,0,0,167,83,192,12,33,32,0,2,
-	8,0,66,142,4,0,67,142,0,0,0,0,
-	35,16,67,0,93,57,192,8,255,255,66,48,
-	167,83,192,12,33,32,0,2,33,16,0,0,
-	76,0,191,143,72,0,190,143,68,0,183,143,
-	64,0,182,143,60,0,181,143,56,0,180,143,
-	52,0,179,143,48,0,178,143,44,0,177,143,
-	40,0,176,143,8,0,224,3,80,0,189,39,
-	200,255,189,39,44,0,177,175,33,136,128,0,
-	72,0,168,143,33,32,0,0,20,0,165,175,
-	33,40,224,0,2,131,3,60,172,210,99,140,
-	152,132,135,143,4,0,2,36,48,0,191,175,
-	40,0,176,175,24,0,162,175,28,0,160,175,
-	36,0,160,175,16,0,163,175,104,77,192,12,
-	32,0,168,175,33,128,64,0,3,0,0,22,
-	33,32,0,2,145,57,192,8,33,16,0,0,
-	197,80,192,12,33,40,32,2,255,255,3,36,
-	5,0,67,20,0,0,0,0,167,83,192,12,
-	33,32,0,2,145,57,192,8,33,16,0,0,
-	167,83,192,12,33,32,0,2,8,0,34,142,
-	4,0,35,142,0,0,0,0,35,16,67,0,
-	255,255,66,48,48,0,191,143,44,0,177,143,
-	40,0,176,143,8,0,224,3,56,0,189,39,
-	200,255,189,39,44,0,177,175,33,136,128,0,
-	72,0,163,143,33,32,0,0,20,0,165,175,
-	33,40,224,0,164,132,135,143,2,131,2,60,
-	92,205,66,36,16,0,162,175,6,0,2,36,
-	24,0,162,175,1,0,2,36,48,0,191,175,
-	40,0,176,175,28,0,162,175,36,0,160,175,
-	104,77,192,12,32,0,163,175,33,128,64,0,
-	3,0,0,22,33,32,0,2,191,57,192,8,
-	33,16,0,0,197,80,192,12,33,40,32,2,
-	255,255,3,36,5,0,67,20,0,0,0,0,
-	167,83,192,12,33,32,0,2,191,57,192,8,
-	33,16,0,0,167,83,192,12,33,32,0,2,
-	8,0,34,142,4,0,35,142,0,0,0,0,
-	35,16,67,0,255,255,66,48,48,0,191,143,
-	44,0,177,143,40,0,176,143,8,0,224,3,
-	56,0,189,39,200,255,189,39,44,0,177,175,
-	33,136,128,0,72,0,163,143,33,32,0,0,
-	20,0,165,175,33,40,224,0,164,132,135,143,
-	2,131,2,60,92,205,66,36,16,0,162,175,
-	6,0,2,36,24,0,162,175,2,0,2,36,
-	48,0,191,175,40,0,176,175,28,0,162,175,
-	36,0,160,175,104,77,192,12,32,0,163,175,
-	33,128,64,0,3,0,0,22,33,32,0,2,
-	237,57,192,8,33,16,0,0,197,80,192,12,
-	33,40,32,2,255,255,3,36,5,0,67,20,
-	0,0,0,0,167,83,192,12,33,32,0,2,
-	237,57,192,8,33,16,0,0,167,83,192,12,
-	33,32,0,2,8,0,34,142,4,0,35,142,
-	0,0,0,0,35,16,67,0,255,255,66,48,
-	48,0,191,143,44,0,177,143,40,0,176,143,
-	8,0,224,3,56,0,189,39,0,0,0,0,
-	0,0,0,0,224,255,189,39,24,0,178,175,
-	33,144,128,0,20,0,177,175,3,131,17,60,
-	0,18,49,38,16,0,176,175,33,128,0,0,
-	28,0,191,175,208,133,128,175,60,65,192,12,
-	33,32,0,2,0,0,34,166,1,0,16,38,
-	64,0,2,42,250,255,64,20,2,0,49,38,
-	3,131,3,60,18,18,99,144,255,0,2,36,
-	3,0,98,16,0,0,0,0,6,0,64,18,
-	0,163,4,60,75,59,192,12,32,0,4,36,
-	87,59,192,12,255,0,4,36,0,163,4,60,
-	220,5,132,52,176,132,133,39,168,71,192,12,
-	4,0,6,36,25,0,64,20,0,163,4,60,
-	3,131,16,60,20,18,16,38,33,32,0,2,
-	176,132,133,39,168,71,192,12,4,0,6,36,
-	3,0,64,16,0,163,4,60,7,0,64,18,
-	0,0,0,0,220,5,132,52,33,40,0,0,
-	144,71,192,12,4,0,6,36,47,58,192,8,
-	0,163,4,60,0,163,5,60,220,5,165,52,
-	3,0,2,138,0,0,2,154,0,0,0,0,
-	3,0,162,168,0,0,162,184,0,163,4,60,
-	99,59,192,12,220,5,132,52,0,163,4,60,
-	16,6,132,52,176,132,133,39,168,71,192,12,
-	4,0,6,36,25,0,64,20,0,163,4,60,
-	3,131,16,60,68,18,16,38,33,32,0,2,
-	176,132,133,39,168,71,192,12,4,0,6,36,
-	3,0,64,16,0,163,4,60,7,0,64,18,
-	0,0,0,0,16,6,132,52,33,40,0,0,
-	144,71,192,12,4,0,6,36,80,58,192,8,
-	0,163,4,60,0,163,5,60,16,6,165,52,
-	3,0,2,138,0,0,2,154,0,0,0,0,
-	3,0,162,168,0,0,162,184,0,163,4,60,
-	119,59,192,12,16,6,132,52,0,163,4,60,
-	224,5,132,52,176,132,133,39,168,71,192,12,
-	4,0,6,36,25,0,64,20,0,163,4,60,
-	3,131,16,60,24,18,16,38,33,32,0,2,
-	176,132,133,39,168,71,192,12,4,0,6,36,
-	3,0,64,16,0,163,4,60,7,0,64,18,
-	0,0,0,0,224,5,132,52,33,40,0,0,
-	144,71,192,12,4,0,6,36,113,58,192,8,
-	0,163,4,60,0,163,5,60,224,5,165,52,
-	3,0,2,138,0,0,2,154,0,0,0,0,
-	3,0,162,168,0,0,162,184,0,163,4,60,
-	139,59,192,12,224,5,132,52,3,131,3,60,
-	28,18,99,36,0,0,98,148,0,0,0,0,
-	0,128,66,48,3,0,64,20,1,0,2,36,
-	2,0,64,18,0,0,0,0,0,0,98,164,
-	0,163,2,60,144,1,66,140,0,0,0,0,
-	7,0,64,20,0,0,0,0,3,131,3,60,
-	28,18,99,36,0,0,98,148,0,0,0,0,
-	146,58,192,8,254,255,66,48,0,163,2,60,
-	144,1,66,140,0,0,0,0,7,0,64,24,
-	0,0,0,0,3,131,3,60,28,18,99,36,
-	0,0,98,148,0,0,0,0,1,0,66,52,
-	0,0,98,164,3,131,4,60,28,18,132,148,
-	0,0,0,0,159,59,192,12,1,0,132,48,
-	3,131,3,60,80,18,99,144,255,0,2,36,
-	3,0,98,16,0,0,0,0,5,0,64,18,
-	0,0,0,0,2,131,4,60,160,149,132,36,
-	205,59,192,12,14,0,5,36,3,131,3,60,
-	96,18,99,144,255,0,2,36,3,0,98,16,
-	0,0,0,0,5,0,64,18,0,0,0,0,
-	2,131,4,60,176,149,132,36,239,59,192,12,
-	11,0,5,36,3,131,3,60,112,18,99,144,
-	255,0,2,36,3,0,98,16,0,0,0,0,
-	5,0,64,18,0,0,0,0,2,131,4,60,
-	188,149,132,36,17,60,192,12,15,0,5,36,
-	0,163,2,60,140,1,66,140,0,0,0,0,
-	7,0,64,16,15,0,2,60,0,163,3,60,
-	140,1,99,140,64,66,66,52,43,16,67,0,
-	26,0,64,16,0,0,0,0,3,131,3,60,
-	64,18,99,140,255,255,2,36,3,0,98,16,
-	44,1,2,36,4,0,64,18,0,0,0,0,
-	0,163,1,60,221,58,192,8,140,1,34,172,
-	5,0,96,20,15,0,4,60,1,0,2,36,
-	0,163,1,60,221,58,192,8,140,1,34,172,
-	64,66,132,52,43,16,131,0,4,0,64,16,
-	0,0,0,0,0,163,1,60,221,58,192,8,
-	140,1,36,172,0,163,1,60,140,1,35,172,
-	0,163,4,60,140,1,132,140,51,60,192,12,
-	0,0,0,0,28,0,191,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,208,255,189,39,20,0,177,175,
-	33,136,128,0,36,0,181,175,33,168,160,0,
-	28,0,179,175,33,152,192,0,44,0,191,175,
-	40,0,182,175,32,0,180,175,24,0,178,175,
-	168,71,192,12,16,0,176,175,76,0,64,16,
-	0,0,0,0,3,131,22,60,0,18,214,38,
-	35,16,54,2,194,31,2,0,33,16,67,0,
-	67,144,2,0,1,0,98,38,194,31,2,0,
-	33,16,67,0,67,128,2,0,255,255,20,38,
-	64,0,130,46,14,0,64,20,64,0,66,46,
-	2,131,4,60,204,149,132,36,180,132,144,39,
-	33,40,0,2,2,131,7,60,236,149,231,36,
-	15,63,192,12,143,0,6,36,1,0,4,36,
-	33,40,0,2,188,7,192,12,143,0,6,36,
-	64,0,66,46,14,0,64,20,33,32,32,2,
-	2,131,4,60,204,149,132,36,180,132,144,39,
-	33,40,0,2,2,131,7,60,20,150,231,36,
-	15,63,192,12,144,0,6,36,1,0,4,36,
-	33,40,0,2,188,7,192,12,144,0,6,36,
-	33,32,32,2,33,40,160,2,80,68,192,12,
-	33,48,96,2,64,16,18,0,33,136,86,0,
-	33,128,128,2,255,255,2,36,25,0,2,18,
-	255,255,20,36,180,132,147,39,33,32,64,2,
-	208,133,130,143,1,0,82,38,1,0,66,36,
-	208,133,130,175,0,0,37,150,0,0,0,0,
-	162,65,192,12,2,0,49,38,10,0,64,20,
-	33,40,96,2,2,131,4,60,204,149,132,36,
-	188,132,135,39,15,63,192,12,159,0,6,36,
-	1,0,4,36,33,40,96,2,188,7,192,12,
-	159,0,6,36,255,255,16,38,235,255,20,22,
-	33,32,64,2,44,0,191,143,40,0,182,143,
-	36,0,181,143,32,0,180,143,28,0,179,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,48,0,189,39,224,255,189,39,
-	16,0,164,163,3,131,4,60,18,18,132,36,
-	16,0,165,39,24,0,191,175,231,58,192,12,
-	1,0,6,36,24,0,191,143,32,0,189,39,
-	8,0,224,3,0,0,0,0,224,255,189,39,
-	16,0,164,163,3,131,4,60,19,18,132,36,
-	16,0,165,39,24,0,191,175,231,58,192,12,
-	1,0,6,36,24,0,191,143,32,0,189,39,
-	8,0,224,3,0,0,0,0,232,255,189,39,
-	33,40,128,0,16,0,176,175,3,131,16,60,
-	20,18,16,38,33,32,0,2,20,0,191,175,
-	231,58,192,12,4,0,6,36,0,163,5,60,
-	220,5,165,52,3,0,2,138,0,0,2,154,
-	0,0,0,0,3,0,162,168,0,0,162,184,
-	20,0,191,143,16,0,176,143,8,0,224,3,
-	24,0,189,39,232,255,189,39,33,40,128,0,
-	16,0,176,175,3,131,16,60,68,18,16,38,
-	33,32,0,2,20,0,191,175,231,58,192,12,
-	4,0,6,36,0,163,5,60,16,6,165,52,
-	3,0,2,138,0,0,2,154,0,0,0,0,
-	3,0,162,168,0,0,162,184,20,0,191,143,
-	16,0,176,143,8,0,224,3,24,0,189,39,
-	232,255,189,39,33,40,128,0,16,0,176,175,
-	3,131,16,60,24,18,16,38,33,32,0,2,
-	20,0,191,175,231,58,192,12,4,0,6,36,
-	0,163,5,60,224,5,165,52,3,0,2,138,
-	0,0,2,154,0,0,0,0,3,0,162,168,
-	0,0,162,184,20,0,191,143,16,0,176,143,
-	8,0,224,3,24,0,189,39,3,131,2,60,
-	28,18,66,148,224,255,189,39,24,0,191,175,
-	8,0,128,16,16,0,162,167,1,0,66,52,
-	16,0,162,167,1,0,2,36,44,133,130,175,
-	0,163,1,60,177,59,192,8,144,1,34,172,
-	254,255,66,48,16,0,162,167,44,133,128,175,
-	0,163,1,60,144,1,32,172,3,131,4,60,
-	28,18,132,36,16,0,165,39,231,58,192,12,
-	2,0,6,36,24,0,191,143,32,0,189,39,
-	8,0,224,3,0,0,0,0,3,131,2,60,
-	28,18,66,148,224,255,189,39,24,0,191,175,
-	3,0,128,16,16,0,162,167,195,59,192,8,
-	2,0,66,52,253,255,66,48,16,0,162,167,
-	3,131,4,60,28,18,132,36,16,0,165,39,
-	231,58,192,12,2,0,6,36,24,0,191,143,
-	32,0,189,39,8,0,224,3,0,0,0,0,
-	216,255,189,39,32,0,191,175,33,56,128,0,
-	33,48,160,0,3,0,226,136,0,0,226,152,
-	7,0,227,136,4,0,227,152,11,0,228,136,
-	8,0,228,152,15,0,229,136,12,0,229,152,
-	19,0,162,171,16,0,162,187,23,0,163,171,
-	20,0,163,187,27,0,164,171,24,0,164,187,
-	31,0,165,171,28,0,165,187,16,0,194,44,
-	3,0,64,16,16,0,163,39,33,16,102,0,
-	0,0,64,160,3,131,4,60,80,18,132,36,
-	33,40,224,0,231,58,192,12,16,0,6,36,
-	32,0,191,143,40,0,189,39,8,0,224,3,
-	0,0,0,0,216,255,189,39,32,0,191,175,
-	33,56,128,0,33,48,160,0,3,0,226,136,
-	0,0,226,152,7,0,227,136,4,0,227,152,
-	11,0,228,136,8,0,228,152,15,0,229,136,
-	12,0,229,152,19,0,162,171,16,0,162,187,
-	23,0,163,171,20,0,163,187,27,0,164,171,
-	24,0,164,187,31,0,165,171,28,0,165,187,
-	16,0,194,44,3,0,64,16,16,0,163,39,
-	33,16,102,0,0,0,64,160,3,131,4,60,
-	96,18,132,36,33,40,224,0,231,58,192,12,
-	16,0,6,36,32,0,191,143,40,0,189,39,
-	8,0,224,3,0,0,0,0,216,255,189,39,
-	32,0,191,175,33,56,128,0,33,48,160,0,
-	3,0,226,136,0,0,226,152,7,0,227,136,
-	4,0,227,152,11,0,228,136,8,0,228,152,
-	15,0,229,136,12,0,229,152,19,0,162,171,
-	16,0,162,187,23,0,163,171,20,0,163,187,
-	27,0,164,171,24,0,164,187,31,0,165,171,
-	28,0,165,187,16,0,194,44,3,0,64,16,
-	16,0,163,39,33,16,102,0,0,0,64,160,
-	3,131,4,60,112,18,132,36,33,40,224,0,
-	231,58,192,12,16,0,6,36,32,0,191,143,
-	40,0,189,39,8,0,224,3,0,0,0,0,
-	232,255,189,39,15,0,2,60,54,66,66,52,
-	24,0,164,175,246,255,132,36,43,16,68,0,
-	3,0,64,16,16,0,191,175,44,1,2,36,
-	24,0,162,175,3,131,4,60,64,18,132,36,
-	24,0,165,39,231,58,192,12,4,0,6,36,
-	24,0,162,143,0,163,1,60,140,1,34,172,
-	16,0,191,143,24,0,189,39,8,0,224,3,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,232,255,189,39,16,0,191,175,
-	0,38,4,0,196,64,192,12,3,38,4,0,
-	16,0,191,143,24,0,189,39,8,0,224,3,
-	0,0,0,0,232,255,189,39,16,0,191,175,
-	0,38,4,0,196,64,192,12,3,38,4,0,
-	16,0,191,143,24,0,189,39,8,0,224,3,
-	0,0,0,0,160,255,189,39,112,0,162,143,
-	72,0,176,175,33,128,224,0,88,0,180,175,
-	33,160,0,0,84,0,179,175,33,152,192,0,
-	92,0,191,175,80,0,178,175,7,0,160,16,
-	76,0,177,175,6,0,65,4,51,0,177,39,
-	45,0,20,36,3,0,0,18,35,16,2,0,
-	255,255,16,38,51,0,177,39,51,0,160,163,
-	27,0,68,0,2,0,128,20,0,0,0,0,
-	13,0,7,0,18,24,0,0,16,16,0,0,
-	2,131,1,60,33,8,34,0,128,205,34,144,
-	255,255,49,38,2,0,0,18,0,0,34,162,
-	255,255,16,38,33,16,96,0,241,255,64,20,
-	1,0,3,36,0,22,19,0,3,22,2,0,
-	11,0,67,20,33,32,128,2,255,255,16,38,
-	255,255,2,36,7,0,2,18,0,0,0,0,
-	255,255,18,36,196,64,192,12,32,0,4,36,
-	255,255,16,38,252,255,18,22,33,32,128,2,
-	4,0,128,16,0,22,19,0,196,64,192,12,
-	0,0,0,0,0,22,19,0,3,22,2,0,
-	2,0,3,36,14,0,67,20,255,255,2,36,
-	255,255,16,38,11,0,2,18,255,255,18,36,
-	196,64,192,12,48,0,4,36,255,255,16,38,
-	6,0,18,18,0,0,0,0,156,60,192,8,
-	0,0,0,0,0,38,4,0,196,64,192,12,
-	3,38,4,0,0,0,34,130,0,0,36,146,
-	0,0,0,0,249,255,64,20,1,0,49,38,
-	255,255,49,38,0,22,19,0,3,22,2,0,
-	3,0,3,36,9,0,67,20,255,255,16,38,
-	255,255,2,36,6,0,2,18,255,255,17,36,
-	196,64,192,12,32,0,4,36,255,255,16,38,
-	252,255,17,22,0,0,0,0,92,0,191,143,
-	88,0,180,143,84,0,179,143,80,0,178,143,
-	76,0,177,143,72,0,176,143,8,0,224,3,
-	96,0,189,39,200,255,189,39,40,0,178,175,
-	33,144,128,0,32,0,176,175,33,128,160,0,
-	36,0,177,175,33,136,192,0,33,32,32,2,
-	48,0,191,175,156,71,192,12,44,0,179,175,
-	33,32,0,0,33,24,64,0,42,16,112,0,
-	2,0,64,16,33,152,64,2,35,32,3,2,
-	0,22,18,0,3,22,2,0,1,0,3,36,
-	11,0,67,20,33,128,128,0,255,255,16,38,
-	255,255,2,36,8,0,2,18,0,22,19,0,
-	255,255,18,36,196,64,192,12,32,0,4,36,
-	255,255,16,38,252,255,18,22,0,0,0,0,
-	0,22,19,0,3,22,2,0,2,0,3,36,
-	14,0,67,20,255,255,2,36,255,255,16,38,
-	11,0,2,18,255,255,18,36,196,64,192,12,
-	48,0,4,36,255,255,16,38,6,0,18,18,
-	0,0,0,0,233,60,192,8,0,0,0,0,
-	0,38,4,0,196,64,192,12,3,38,4,0,
-	0,0,34,130,0,0,36,146,0,0,0,0,
-	249,255,64,20,1,0,49,38,255,255,49,38,
-	0,22,19,0,3,22,2,0,3,0,3,36,
-	9,0,67,20,255,255,16,38,255,255,2,36,
-	6,0,2,18,255,255,17,36,196,64,192,12,
-	32,0,4,36,255,255,16,38,252,255,17,22,
-	0,0,0,0,48,0,191,143,44,0,179,143,
-	40,0,178,143,36,0,177,143,32,0,176,143,
-	8,0,224,3,56,0,189,39,32,255,189,39,
-	192,0,178,175,33,144,160,0,196,0,179,175,
-	33,152,0,0,220,0,191,175,216,0,190,175,
-	212,0,183,175,208,0,182,175,204,0,181,175,
-	200,0,180,175,188,0,177,175,184,0,176,175,
-	1,0,130,128,0,0,0,0,229,1,64,16,
-	33,136,0,0,255,255,22,36,1,0,23,36,
-	2,0,30,36,1,0,149,36,0,0,162,146,
-	0,0,0,0,219,255,66,36,0,22,2,0,
-	3,30,2,0,84,0,98,44,217,1,64,16,
-	128,16,3,0,2,131,1,60,33,8,34,0,
-	80,150,34,140,0,0,0,0,8,0,64,0,
-	0,0,0,0,209,61,192,8,37,0,4,36,
-	2,131,16,60,64,150,16,38,156,71,192,12,
-	33,32,0,2,59,61,192,8,0,0,0,0,
-	0,38,4,0,196,64,192,12,3,38,4,0,
-	0,0,2,130,0,0,4,146,0,0,0,0,
-	249,255,64,20,1,0,16,38,3,63,192,8,
-	1,0,162,38,0,38,18,0,209,61,192,8,
-	3,38,4,0,2,0,3,36,33,128,32,2,
-	33,40,64,2,33,160,0,0,51,0,177,39,
-	51,0,160,163,27,0,163,0,2,0,96,20,
-	0,0,0,0,13,0,7,0,18,40,0,0,
-	16,16,0,0,2,131,1,60,33,8,34,0,
-	128,205,34,144,255,255,49,38,2,0,0,18,
-	0,0,34,162,255,255,16,38,242,255,160,20,
-	0,0,0,0,10,0,119,22,0,22,20,0,
-	255,255,16,38,8,0,22,18,3,38,2,0,
-	255,255,18,36,196,64,192,12,32,0,4,36,
-	255,255,16,38,252,255,18,22,0,22,20,0,
-	3,38,2,0,3,0,128,16,0,0,0,0,
-	196,64,192,12,0,0,0,0,14,0,126,22,
-	0,0,0,0,255,255,16,38,11,0,22,18,
-	255,255,18,36,196,64,192,12,48,0,4,36,
-	255,255,16,38,6,0,18,18,0,0,0,0,
-	111,61,192,8,0,0,0,0,0,38,4,0,
-	196,64,192,12,3,38,4,0,0,0,34,130,
-	0,0,36,146,0,0,0,0,249,255,64,20,
-	1,0,49,38,255,255,49,38,3,0,6,36,
-	80,0,102,22,66,0,4,36,255,255,16,38,
-	77,0,22,18,255,255,17,36,196,64,192,12,
-	32,0,4,36,255,255,16,38,252,255,17,22,
-	66,0,4,36,209,61,192,8,0,0,0,0,
-	8,0,3,36,33,128,32,2,33,40,64,2,
-	33,160,0,0,51,0,177,39,51,0,160,163,
-	27,0,163,0,2,0,96,20,0,0,0,0,
-	13,0,7,0,18,40,0,0,16,16,0,0,
-	2,131,1,60,33,8,34,0,128,205,34,144,
-	255,255,49,38,2,0,0,18,0,0,34,162,
-	255,255,16,38,242,255,160,20,0,0,0,0,
-	10,0,119,22,0,22,20,0,255,255,16,38,
-	8,0,22,18,3,38,2,0,255,255,18,36,
-	196,64,192,12,32,0,4,36,255,255,16,38,
-	252,255,18,22,0,22,20,0,3,38,2,0,
-	3,0,128,16,0,0,0,0,196,64,192,12,
-	0,0,0,0,14,0,126,22,0,0,0,0,
-	255,255,16,38,11,0,22,18,255,255,18,36,
-	196,64,192,12,48,0,4,36,255,255,16,38,
-	6,0,18,18,0,0,0,0,182,61,192,8,
-	0,0,0,0,0,38,4,0,196,64,192,12,
-	3,38,4,0,0,0,34,130,0,0,36,146,
-	0,0,0,0,249,255,64,20,1,0,49,38,
-	255,255,49,38,3,0,6,36,9,0,102,22,
-	81,0,4,36,255,255,16,38,6,0,22,18,
-	255,255,17,36,196,64,192,12,32,0,4,36,
-	255,255,16,38,252,255,17,22,81,0,4,36,
-	196,64,192,12,0,0,0,0,3,63,192,8,
-	1,0,162,38,33,128,32,2,33,16,64,2,
-	33,160,0,0,5,0,65,6,10,0,4,36,
-	45,0,20,36,2,0,32,18,35,16,18,0,
-	255,255,48,38,51,0,177,39,51,0,160,163,
-	27,0,68,0,2,0,128,20,0,0,0,0,
-	13,0,7,0,18,24,0,0,16,16,0,0,
-	2,131,1,60,33,8,34,0,128,205,34,144,
-	255,255,49,38,2,0,0,18,0,0,34,162,
-	255,255,16,38,33,16,96,0,241,255,64,20,
-	0,0,0,0,10,0,119,22,33,32,128,2,
-	255,255,16,38,7,0,22,18,0,0,0,0,
-	255,255,18,36,196,64,192,12,32,0,4,36,
-	255,255,16,38,252,255,18,22,33,32,128,2,
-	3,0,128,16,0,0,0,0,196,64,192,12,
-	0,0,0,0,14,0,126,22,0,0,0,0,
-	255,255,16,38,11,0,22,18,255,255,18,36,
-	196,64,192,12,48,0,4,36,255,255,16,38,
-	6,0,18,18,0,0,0,0,4,62,192,8,
-	0,0,0,0,0,38,4,0,196,64,192,12,
-	3,38,4,0,0,0,34,130,0,0,36,146,
-	0,0,0,0,249,255,64,20,1,0,49,38,
-	255,255,49,38,3,0,6,36,237,0,102,22,
-	1,0,162,38,255,255,16,38,234,0,22,18,
-	255,255,17,36,196,64,192,12,32,0,4,36,
-	255,255,16,38,252,255,17,22,1,0,162,38,
-	3,63,192,8,0,0,0,0,10,0,3,36,
-	33,128,32,2,33,40,64,2,33,160,0,0,
-	51,0,177,39,51,0,160,163,27,0,163,0,
-	2,0,96,20,0,0,0,0,13,0,7,0,
-	18,40,0,0,16,16,0,0,2,131,1,60,
-	33,8,34,0,128,205,34,144,255,255,49,38,
-	2,0,0,18,0,0,34,162,255,255,16,38,
-	242,255,160,20,0,0,0,0,10,0,119,22,
-	0,22,20,0,255,255,16,38,8,0,22,18,
-	3,38,2,0,255,255,18,36,196,64,192,12,
-	32,0,4,36,255,255,16,38,252,255,18,22,
-	0,22,20,0,3,38,2,0,3,0,128,16,
-	0,0,0,0,196,64,192,12,0,0,0,0,
-	14,0,126,22,0,0,0,0,255,255,16,38,
-	11,0,22,18,255,255,18,36,196,64,192,12,
-	48,0,4,36,255,255,16,38,6,0,18,18,
-	0,0,0,0,75,62,192,8,0,0,0,0,
-	0,38,4,0,196,64,192,12,3,38,4,0,
-	0,0,34,130,0,0,36,146,0,0,0,0,
-	249,255,64,20,1,0,49,38,255,255,49,38,
-	3,0,6,36,166,0,102,22,1,0,162,38,
-	255,255,16,38,163,0,22,18,255,255,17,36,
-	196,64,192,12,32,0,4,36,255,255,16,38,
-	252,255,17,22,1,0,162,38,3,63,192,8,
-	0,0,0,0,192,132,144,39,156,71,192,12,
-	33,32,0,2,112,62,192,8,0,0,0,0,
-	0,38,4,0,196,64,192,12,3,38,4,0,
-	0,0,2,130,0,0,4,146,0,0,0,0,
-	249,255,64,20,1,0,16,38,16,0,3,36,
-	33,128,32,2,33,40,64,2,33,160,0,0,
-	51,0,177,39,51,0,160,163,27,0,163,0,
-	2,0,96,20,0,0,0,0,13,0,7,0,
-	18,40,0,0,16,16,0,0,2,131,1,60,
-	33,8,34,0,128,205,34,144,255,255,49,38,
-	2,0,0,18,0,0,34,162,255,255,16,38,
-	242,255,160,20,0,0,0,0,10,0,119,22,
-	0,22,20,0,255,255,16,38,8,0,22,18,
-	3,38,2,0,255,255,18,36,196,64,192,12,
-	32,0,4,36,255,255,16,38,252,255,18,22,
-	0,22,20,0,3,38,2,0,3,0,128,16,
-	0,0,0,0,196,64,192,12,0,0,0,0,
-	14,0,126,22,0,0,0,0,255,255,16,38,
-	11,0,22,18,255,255,18,36,196,64,192,12,
-	48,0,4,36,255,255,16,38,6,0,18,18,
-	0,0,0,0,159,62,192,8,0,0,0,0,
-	0,38,4,0,196,64,192,12,3,38,4,0,
-	0,0,34,130,0,0,36,146,0,0,0,0,
-	249,255,64,20,1,0,49,38,255,255,49,38,
-	3,0,6,36,82,0,102,22,1,0,162,38,
-	255,255,16,38,79,0,22,18,255,255,17,36,
-	196,64,192,12,32,0,4,36,255,255,16,38,
-	252,255,17,22,1,0,162,38,3,63,192,8,
-	0,0,0,0,156,71,192,12,33,32,64,2,
-	33,24,64,0,42,16,113,0,2,0,64,16,
-	33,32,0,0,35,32,35,2,10,0,119,22,
-	33,128,128,0,255,255,16,38,7,0,22,18,
-	0,0,0,0,255,255,17,36,196,64,192,12,
-	32,0,4,36,255,255,16,38,252,255,17,22,
-	0,0,0,0,14,0,126,22,0,0,0,0,
-	255,255,16,38,11,0,22,18,255,255,17,36,
-	196,64,192,12,48,0,4,36,255,255,16,38,
-	6,0,17,18,0,0,0,0,211,62,192,8,
-	0,0,0,0,0,38,4,0,196,64,192,12,
-	3,38,4,0,0,0,66,130,0,0,68,146,
-	0,0,0,0,249,255,64,20,1,0,82,38,
-	255,255,82,38,3,0,6,36,30,0,102,22,
-	1,0,162,38,255,255,16,38,27,0,22,18,
-	255,255,17,36,196,64,192,12,32,0,4,36,
-	255,255,16,38,252,255,17,22,1,0,162,38,
-	3,63,192,8,0,0,0,0,253,62,192,8,
-	3,0,19,36,3,0,96,22,128,16,17,0,
-	2,0,19,36,128,16,17,0,33,16,81,0,
-	64,16,2,0,0,0,163,130,208,255,66,36,
-	2,0,96,22,33,136,67,0,1,0,19,36,
-	1,0,181,38,0,0,162,130,0,0,0,0,
-	33,254,64,20,0,0,0,0,1,0,130,36,
-	220,0,191,143,216,0,190,143,212,0,183,143,
-	208,0,182,143,204,0,181,143,200,0,180,143,
-	196,0,179,143,192,0,178,143,188,0,177,143,
-	184,0,176,143,8,0,224,3,224,0,189,39,
-	0,0,164,175,4,0,165,175,8,0,166,175,
-	12,0,167,175,200,255,189,39,59,0,162,39,
-	252,255,3,36,36,16,67,0,52,0,191,175,
-	48,0,180,175,44,0,179,175,40,0,178,175,
-	36,0,177,175,32,0,176,175,56,0,164,175,
-	0,0,80,140,4,0,81,36,0,0,2,130,
-	0,0,3,146,0,0,0,0,31,0,64,16,
-	37,0,20,36,69,0,19,36,252,255,18,36,
-	0,22,3,0,3,38,2,0,18,0,148,20,
-	0,0,0,0,1,0,3,130,0,0,0,0,
-	4,0,100,16,33,32,0,2,4,0,115,20,
-	3,0,34,38,33,32,0,2,56,63,192,8,
-	33,40,0,0,36,16,82,0,4,0,81,36,
-	0,0,69,140,33,32,0,2,13,61,192,12,
-	0,0,0,0,62,63,192,8,33,128,64,0,
-	196,64,192,12,1,0,16,38,0,0,2,130,
-	0,0,3,146,0,0,0,0,230,255,64,20,
-	0,22,3,0,52,0,191,143,48,0,180,143,
-	44,0,179,143,40,0,178,143,36,0,177,143,
-	32,0,176,143,8,0,224,3,56,0,189,39,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,8,0,224,3,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,8,0,224,3,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	8,0,224,3,0,0,0,0,33,72,224,3,
-	170,3,8,36,76,63,192,12,0,0,0,0,
-	255,255,8,33,252,255,0,21,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,8,0,32,1,
-	0,0,0,0,33,88,224,3,232,3,10,36,
-	143,63,192,12,0,0,0,0,255,255,74,33,
-	252,255,64,21,0,0,0,0,8,0,96,1,
-	0,0,0,0,250,255,132,32,130,32,4,0,
-	255,255,132,32,0,0,0,0,253,255,128,20,
-	0,0,0,0,8,0,224,3,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	248,255,189,39,255,255,195,36,10,0,192,16,
-	33,56,160,0,255,255,6,36,0,0,162,144,
-	1,0,165,36,0,0,130,160,4,0,64,16,
-	1,0,132,36,255,255,99,36,249,255,102,20,
-	0,0,0,0,33,16,224,0,8,0,224,3,
-	8,0,189,39,0,96,2,64,0,0,0,0,
-	38,64,68,0,1,255,8,49,38,64,2,1,
-	0,96,136,64,8,0,224,3,1,255,66,48,
-	0,96,2,64,0,0,0,0,1,255,132,48,
-	39,32,128,0,36,64,68,0,0,96,136,64,
-	8,0,224,3,1,255,66,48,0,96,2,64,
-	0,0,0,0,0,255,132,48,37,64,68,0,
-	1,0,8,53,0,96,136,64,8,0,224,3,
-	1,255,66,48,176,255,189,39,64,0,182,175,
-	33,176,128,0,52,0,179,175,33,152,160,0,
-	72,0,190,175,33,240,192,0,68,0,183,175,
-	33,184,224,0,60,0,181,175,33,168,0,0,
-	56,0,180,175,33,160,0,0,76,0,191,175,
-	48,0,178,175,44,0,177,175,40,0,176,175,
-	2,131,6,60,33,48,212,0,160,205,198,144,
-	0,0,0,0,28,0,96,26,33,128,0,0,
-	33,24,192,2,33,32,118,2,0,0,102,160,
-	1,0,99,36,42,16,100,0,252,255,64,20,
-	0,0,0,0,19,0,96,26,33,128,0,0,
-	255,0,210,48,33,136,192,2,0,0,39,146,
-	0,0,0,0,9,0,242,16,0,0,0,0,
-	5,0,224,18,33,40,0,2,96,0,164,143,
-	0,0,0,0,9,248,224,2,33,48,64,2,
-	32,0,192,23,1,0,181,38,1,0,16,38,
-	42,16,19,2,241,255,64,20,1,0,49,38,
-	1,0,148,38,4,0,130,46,220,255,64,20,
-	0,0,0,0,7,0,96,26,33,128,0,0,
-	33,24,192,2,0,0,112,160,1,0,16,38,
-	42,16,19,2,252,255,64,20,1,0,99,36,
-	20,0,96,26,33,128,0,0,33,136,192,2,
-	0,0,39,146,255,0,6,50,11,0,230,16,
-	0,0,0,0,5,0,224,18,0,0,0,0,
-	96,0,164,143,0,0,0,0,9,248,224,2,
-	33,40,0,2,3,0,192,19,1,0,181,38,
-	72,64,192,8,1,0,2,36,1,0,16,38,
-	42,16,19,2,239,255,64,20,1,0,49,38,
-	33,16,160,2,76,0,191,143,72,0,190,143,
-	68,0,183,143,64,0,182,143,60,0,181,143,
-	56,0,180,143,52,0,179,143,48,0,178,143,
-	44,0,177,143,40,0,176,143,8,0,224,3,
-	80,0,189,39,160,255,189,39,88,0,190,175,
-	33,240,128,0,68,0,179,175,33,152,160,0,
-	76,0,181,175,33,168,224,0,72,0,180,175,
-	33,160,0,0,33,16,96,2,92,0,191,175,
-	84,0,183,175,80,0,182,175,64,0,178,175,
-	60,0,177,175,56,0,176,175,2,0,97,6,
-	16,0,166,175,3,0,98,38,131,152,2,0,
-	33,184,0,0,2,131,22,60,164,205,214,38,
-	0,0,210,142,0,0,0,0,7,0,96,18,
-	33,128,0,0,33,24,192,3,0,0,114,172,
-	1,0,16,38,43,16,19,2,252,255,64,20,
-	4,0,99,36,20,0,96,18,33,128,0,0,
-	33,136,192,3,0,0,39,142,0,0,0,0,
-	11,0,242,16,128,40,16,0,5,0,160,18,
-	0,0,0,0,112,0,164,143,0,0,0,0,
-	9,248,160,2,33,48,64,2,16,0,168,143,
-	0,0,0,0,34,0,0,21,1,0,148,38,
-	1,0,16,38,43,16,19,2,239,255,64,20,
-	4,0,49,38,1,0,247,38,4,0,226,46,
-	222,255,64,20,4,0,214,38,7,0,96,18,
-	33,128,0,0,33,24,192,3,0,0,112,172,
-	1,0,16,38,43,16,19,2,252,255,64,20,
-	4,0,99,36,22,0,96,18,33,128,0,0,
-	33,136,192,3,0,0,39,142,0,0,0,0,
-	13,0,240,16,128,40,16,0,5,0,160,18,
-	0,0,0,0,112,0,164,143,0,0,0,0,
-	9,248,160,2,33,48,0,2,16,0,168,143,
-	0,0,0,0,3,0,0,17,1,0,148,38,
-	174,64,192,8,1,0,2,36,1,0,16,38,
-	43,16,19,2,237,255,64,20,4,0,49,38,
-	33,16,128,2,92,0,191,143,88,0,190,143,
-	84,0,183,143,80,0,182,143,76,0,181,143,
-	72,0,180,143,68,0,179,143,64,0,178,143,
-	60,0,177,143,56,0,176,143,8,0,224,3,
-	96,0,189,39,0,0,0,0,0,0,0,0,
-	255,1,2,36,0,163,1,60,176,1,32,172,
-	0,163,1,60,180,1,32,172,0,163,1,60,
-	8,0,224,3,184,1,34,172,232,255,189,39,
-	16,0,176,175,33,128,128,0,20,0,191,175,
-	220,63,192,12,33,32,0,0,33,40,64,0,
-	0,163,3,60,180,1,99,140,0,163,2,60,
-	184,1,66,140,0,163,4,60,128,1,132,140,
-	1,0,99,36,11,0,128,20,36,24,98,0,
-	0,163,2,60,176,1,66,140,0,0,0,0,
-	6,0,98,20,0,0,0,0,0,163,2,60,
-	128,1,66,140,0,0,0,0,247,255,64,16,
-	0,0,0,0,0,163,2,60,180,1,66,140,
-	33,32,160,0,0,163,1,60,33,8,34,0,
-	188,1,48,160,0,163,1,60,220,63,192,12,
-	180,1,35,172,20,0,191,143,16,0,176,143,
-	8,0,224,3,24,0,189,39,8,0,224,3,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,192,255,189,39,33,80,0,0,
-	80,0,185,143,84,0,184,143,88,0,175,143,
-	1,0,2,36,60,0,177,175,92,0,177,143,
-	4,112,226,0,12,0,224,24,56,0,176,175,
-	1,0,9,36,33,64,160,3,33,24,32,3,
-	0,0,98,140,4,0,99,36,1,0,74,37,
-	4,16,73,0,0,0,2,173,42,16,71,1,
-	249,255,64,20,4,0,8,37,46,0,192,25,
-	33,80,0,0,255,0,16,36,33,72,0,0,
-	0,0,145,172,0,0,160,164,34,0,224,24,
-	0,0,208,160,33,88,128,0,33,96,160,0,
-	33,104,192,0,33,64,32,3,33,24,160,3,
-	0,0,98,140,0,0,0,0,36,16,66,1,
-	19,0,64,16,0,0,0,0,0,0,2,141,
-	0,0,0,0,128,16,2,0,33,16,88,0,
-	0,0,66,140,0,0,0,0,0,0,98,173,
-	0,0,2,141,0,0,0,0,64,16,2,0,
-	33,16,79,0,0,0,66,148,0,0,0,0,
-	0,0,130,165,0,0,2,141,0,0,0,0,
-	47,65,192,8,0,0,162,161,4,0,8,37,
-	1,0,41,37,42,16,39,1,229,255,64,20,
-	4,0,99,36,1,0,198,36,2,0,165,36,
-	1,0,74,37,42,16,78,1,213,255,64,20,
-	4,0,132,36,60,0,177,143,56,0,176,143,
-	8,0,224,3,64,0,189,39,0,0,0,0,
-	0,0,0,0,0,0,0,0,216,255,189,39,
-	63,0,132,48,28,0,179,175,128,1,147,52,
-	50,133,130,151,48,133,132,151,0,128,131,151,
-	20,0,177,175,16,0,176,175,5,162,16,60,
-	32,0,191,175,24,0,178,175,39,16,68,0,
-	36,24,98,0,0,128,131,167,0,0,3,166,
-	76,63,192,12,0,1,17,36,0,128,130,151,
-	48,133,131,151,5,162,18,60,37,16,67,0,
-	0,128,130,167,0,0,2,166,36,16,51,2,
-	6,0,64,16,0,0,0,0,0,128,131,151,
-	20,133,130,151,0,0,0,0,96,65,192,8,
-	37,24,98,0,20,133,130,151,0,128,131,151,
-	39,16,2,0,36,24,98,0,0,128,131,167,
-	0,0,67,166,76,63,192,12,66,136,17,0,
-	0,128,130,151,50,133,131,151,0,0,0,0,
-	37,16,67,0,0,128,130,167,76,63,192,12,
-	0,0,66,166,50,133,130,151,0,128,131,151,
-	39,16,2,0,36,24,98,0,255,255,34,50,
-	0,128,131,167,0,0,67,166,226,255,64,20,
-	36,16,51,2,33,136,0,0,16,0,16,36,
-	5,162,18,60,255,255,19,36,76,63,192,12,
-	0,0,0,0,0,128,131,151,50,133,130,151,
-	0,0,0,0,37,24,98,0,0,128,131,167,
-	76,63,192,12,0,0,67,166,8,0,0,18,
-	0,0,0,0,0,0,67,150,20,133,130,151,
-	0,0,0,0,36,16,67,0,2,0,64,16,
-	64,136,17,0,1,0,49,54,76,63,192,12,
-	255,255,16,38,50,133,130,151,0,128,131,151,
-	39,16,2,0,36,24,98,0,0,128,131,167,
-	230,255,19,22,0,0,67,166,48,133,130,151,
-	0,128,131,151,39,16,2,0,36,24,98,0,
-	5,162,2,60,0,128,131,167,0,0,67,164,
-	255,255,34,50,32,0,191,143,28,0,179,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,40,0,189,39,208,255,189,39,
-	36,0,181,175,33,168,160,0,32,0,180,175,
-	63,0,148,48,33,32,128,2,44,0,191,175,
-	40,0,182,175,28,0,179,175,24,0,178,175,
-	20,0,177,175,60,65,192,12,16,0,176,175,
-	33,152,64,0,255,255,163,50,255,255,98,50,
-	3,0,98,20,48,1,22,36,245,66,192,8,
-	1,0,2,36,5,162,16,60,50,133,130,151,
-	48,133,132,151,0,128,131,151,39,16,68,0,
-	36,24,98,0,0,128,131,167,0,0,3,166,
-	76,63,192,12,0,1,17,36,0,128,130,151,
-	48,133,131,151,5,162,18,60,37,16,67,0,
-	0,128,130,167,0,0,2,166,36,16,54,2,
-	6,0,64,16,0,0,0,0,0,128,131,151,
-	20,133,130,151,0,0,0,0,210,65,192,8,
-	37,24,98,0,20,133,130,151,0,128,131,151,
-	39,16,2,0,36,24,98,0,0,128,131,167,
-	0,0,67,166,76,63,192,12,66,136,17,0,
-	0,128,130,151,50,133,131,151,0,0,0,0,
-	37,16,67,0,0,128,130,167,76,63,192,12,
-	0,0,66,166,50,133,130,151,0,128,131,151,
-	39,16,2,0,36,24,98,0,255,255,34,50,
-	0,128,131,167,0,0,67,166,226,255,64,20,
-	36,16,54,2,255,255,163,50,255,255,98,50,
-	39,16,2,0,36,24,98,0,84,0,96,16,
-	192,1,147,54,5,162,16,60,50,133,130,151,
-	48,133,132,151,0,128,131,151,39,16,68,0,
-	36,24,98,0,0,128,131,167,0,0,3,166,
-	76,63,192,12,0,1,17,36,0,128,130,151,
-	48,133,131,151,5,162,18,60,37,16,67,0,
-	0,128,130,167,0,0,2,166,36,16,51,2,
-	6,0,64,16,0,0,0,0,0,128,131,151,
-	20,133,130,151,0,0,0,0,8,66,192,8,
-	37,24,98,0,20,133,130,151,0,128,131,151,
-	39,16,2,0,36,24,98,0,0,128,131,167,
-	0,0,67,166,76,63,192,12,66,136,17,0,
-	0,128,130,151,50,133,131,151,0,0,0,0,
-	37,16,67,0,0,128,130,167,76,63,192,12,
-	0,0,66,166,50,133,130,151,0,128,131,151,
-	39,16,2,0,36,24,98,0,255,255,34,50,
-	0,128,131,167,0,0,67,166,226,255,64,20,
-	36,16,51,2,5,162,16,60,50,133,130,151,
-	48,133,132,151,0,128,131,151,39,16,68,0,
-	36,24,98,0,0,128,131,167,76,63,192,12,
-	0,0,3,166,0,128,131,151,48,133,130,151,
-	0,0,0,0,37,24,98,0,0,0,3,166,
-	0,0,4,150,20,133,130,151,0,128,131,167,
-	36,16,68,0,9,0,64,20,0,0,0,0,
-	76,63,192,12,0,0,0,0,0,0,3,150,
-	20,133,130,151,0,0,0,0,36,16,67,0,
-	249,255,64,16,0,0,0,0,48,133,130,151,
-	0,128,131,151,39,16,2,0,36,24,98,0,
-	5,162,2,60,0,128,131,167,0,0,67,164,
-	255,255,163,50,255,255,2,52,125,0,98,16,
-	64,1,147,54,5,162,16,60,50,133,130,151,
-	48,133,132,151,0,128,131,151,39,16,68,0,
-	36,24,98,0,0,128,131,167,0,0,3,166,
-	76,63,192,12,0,1,17,36,0,128,130,151,
-	48,133,131,151,5,162,18,60,37,16,67,0,
-	0,128,130,167,0,0,2,166,36,16,51,2,
-	6,0,64,16,0,0,0,0,0,128,131,151,
-	20,133,130,151,0,0,0,0,95,66,192,8,
-	37,24,98,0,20,133,130,151,0,128,131,151,
-	39,16,2,0,36,24,98,0,0,128,131,167,
-	0,0,67,166,76,63,192,12,66,136,17,0,
-	0,128,130,151,50,133,131,151,0,0,0,0,
-	37,16,67,0,0,128,130,167,76,63,192,12,
-	0,0,66,166,50,133,130,151,0,128,131,151,
-	39,16,2,0,36,24,98,0,255,255,34,50,
-	0,128,131,167,0,0,67,166,226,255,64,20,
-	36,16,51,2,33,144,160,2,0,128,16,52,
-	0,128,130,151,48,133,131,151,5,162,17,60,
-	37,16,67,0,5,162,3,60,0,128,130,167,
-	0,0,98,164,36,16,18,2,6,0,64,16,
-	0,0,0,0,0,128,131,151,20,133,130,151,
-	0,0,0,0,136,66,192,8,37,24,98,0,
-	20,133,130,151,0,128,131,151,39,16,2,0,
-	36,24,98,0,0,128,131,167,0,0,35,166,
-	76,63,192,12,66,128,16,0,0,128,130,151,
-	50,133,131,151,0,0,0,0,37,16,67,0,
-	0,128,130,167,76,63,192,12,0,0,34,166,
-	50,133,130,151,0,128,131,151,39,16,2,0,
-	36,24,98,0,255,255,2,50,0,128,131,167,
-	0,0,35,166,226,255,64,20,36,16,18,2,
-	5,162,16,60,50,133,130,151,48,133,132,151,
-	0,128,131,151,39,16,68,0,36,24,98,0,
-	0,128,131,167,76,63,192,12,0,0,3,166,
-	0,128,131,151,48,133,130,151,0,0,0,0,
-	37,24,98,0,0,0,3,166,0,0,4,150,
-	20,133,130,151,0,128,131,167,36,16,68,0,
-	9,0,64,20,0,0,0,0,76,63,192,12,
-	0,0,0,0,0,0,3,150,20,133,130,151,
-	0,0,0,0,36,16,67,0,249,255,64,16,
-	0,0,0,0,48,133,130,151,0,128,131,151,
-	39,16,2,0,36,24,98,0,5,162,2,60,
-	0,128,131,167,0,0,67,164,0,1,19,36,
-	5,162,16,60,50,133,130,151,48,133,132,151,
-	0,128,131,151,39,16,68,0,36,24,98,0,
-	0,128,131,167,0,0,3,166,76,63,192,12,
-	0,1,17,36,0,128,130,151,48,133,131,151,
-	5,162,18,60,37,16,67,0,0,128,130,167,
-	0,0,2,166,36,16,113,2,6,0,64,16,
-	0,0,0,0,0,128,131,151,20,133,130,151,
-	0,0,0,0,220,66,192,8,37,24,98,0,
-	20,133,130,151,0,128,131,151,39,16,2,0,
-	36,24,98,0,0,128,131,167,0,0,67,166,
-	76,63,192,12,66,136,17,0,0,128,130,151,
-	50,133,131,151,0,0,0,0,37,16,67,0,
-	0,128,130,167,76,63,192,12,0,0,66,166,
-	50,133,130,151,0,128,131,151,39,16,2,0,
-	36,24,98,0,255,255,34,50,0,128,131,167,
-	0,0,67,166,226,255,64,20,36,16,113,2,
-	60,65,192,12,33,32,128,2,38,16,162,2,
-	255,255,66,48,1,0,66,44,44,0,191,143,
-	40,0,182,143,36,0,181,143,32,0,180,143,
-	28,0,179,143,24,0,178,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,48,0,189,39,
-	224,255,189,39,24,0,178,175,33,144,0,0,
-	64,16,4,0,16,0,176,175,33,128,68,0,
-	33,32,0,2,20,0,177,175,255,255,177,48,
-	28,0,191,175,162,65,192,12,33,40,32,2,
-	8,0,64,16,1,0,4,38,162,65,192,12,
-	33,40,32,2,4,0,64,16,2,0,4,38,
-	162,65,192,12,33,40,32,2,43,144,2,0,
-	33,16,64,2,28,0,191,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,216,255,189,39,64,16,4,0,
-	24,0,178,175,33,144,68,0,33,32,64,2,
-	36,0,191,175,32,0,180,175,28,0,179,175,
-	20,0,177,175,60,65,192,12,16,0,176,175,
-	1,0,84,38,33,32,128,2,60,65,192,12,
-	33,136,64,0,2,0,83,38,33,32,96,2,
-	60,65,192,12,33,128,64,0,255,255,35,50,
-	255,255,17,50,8,0,113,20,0,0,0,0,
-	255,255,66,48,3,0,34,18,33,32,96,2,
-	162,65,192,12,33,40,32,2,66,67,192,8,
-	33,16,32,2,255,255,80,48,4,0,112,16,
-	33,32,128,2,5,0,48,22,255,255,2,36,
-	33,32,64,2,162,65,192,12,33,40,0,2,
-	33,16,0,2,36,0,191,143,32,0,180,143,
-	28,0,179,143,24,0,178,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,40,0,189,39,
-	0,0,0,0,0,0,0,0,0,96,8,64,
-	0,0,0,0,254,255,1,36,36,72,1,1,
-	0,96,137,64,0,0,133,164,2,0,132,32,
-	2,44,5,0,0,0,133,164,0,96,136,64,
-	8,0,224,3,0,0,0,0,208,255,189,39,
-	32,0,178,175,33,144,128,0,28,0,177,175,
-	33,136,160,0,36,0,179,175,33,152,192,0,
-	40,0,180,175,33,160,224,0,44,0,191,175,
-	2,0,32,22,24,0,176,175,255,255,17,36,
-	0,0,66,142,0,0,0,0,36,16,81,0,
-	3,0,83,20,0,0,0,0,121,67,192,8,
-	1,0,2,36,11,0,128,26,33,128,0,0,
-	143,63,192,12,0,0,0,0,0,0,66,142,
-	0,0,0,0,36,16,81,0,246,255,83,16,
-	1,0,16,38,42,16,20,2,247,255,64,20,
-	0,0,0,0,33,16,0,0,44,0,191,143,
-	40,0,180,143,36,0,179,143,32,0,178,143,
-	28,0,177,143,24,0,176,143,8,0,224,3,
-	48,0,189,39,208,255,189,39,32,0,178,175,
-	33,144,128,0,28,0,177,175,33,136,160,0,
-	36,0,179,175,33,152,192,0,40,0,180,175,
-	33,160,224,0,44,0,191,175,2,0,32,22,
-	24,0,176,175,255,255,17,52,0,0,66,150,
-	0,0,0,0,36,16,81,0,3,0,83,20,
-	0,0,0,0,162,67,192,8,1,0,2,36,
-	11,0,128,26,33,128,0,0,143,63,192,12,
-	0,0,0,0,0,0,66,150,0,0,0,0,
-	36,16,81,0,246,255,83,16,1,0,16,38,
-	42,16,20,2,247,255,64,20,0,0,0,0,
-	33,16,0,0,44,0,191,143,40,0,180,143,
-	36,0,179,143,32,0,178,143,28,0,177,143,
-	24,0,176,143,8,0,224,3,48,0,189,39,
-	208,255,189,39,32,0,178,175,33,144,128,0,
-	28,0,177,175,33,136,160,0,36,0,179,175,
-	33,152,192,0,40,0,180,175,33,160,224,0,
-	44,0,191,175,2,0,32,22,24,0,176,175,
-	255,0,17,36,0,0,66,146,0,0,0,0,
-	36,16,81,0,3,0,83,20,0,0,0,0,
-	203,67,192,8,1,0,2,36,11,0,128,26,
-	33,128,0,0,143,63,192,12,0,0,0,0,
-	0,0,66,146,0,0,0,0,36,16,81,0,
-	246,255,83,16,1,0,16,38,42,16,20,2,
-	247,255,64,20,0,0,0,0,33,16,0,0,
-	44,0,191,143,40,0,180,143,36,0,179,143,
-	32,0,178,143,28,0,177,143,24,0,176,143,
-	8,0,224,3,48,0,189,39,208,255,189,39,
-	32,0,178,175,33,144,128,0,28,0,177,175,
-	33,136,160,0,36,0,179,175,33,152,192,0,
-	40,0,180,175,33,160,224,0,44,0,191,175,
-	2,0,32,22,24,0,176,175,255,255,17,36,
-	0,0,66,142,0,0,0,0,36,16,81,0,
-	3,0,83,20,0,0,0,0,244,67,192,8,
-	1,0,2,36,11,0,128,26,33,128,0,0,
-	143,63,192,12,0,0,0,0,0,0,66,142,
-	0,0,0,0,36,16,81,0,246,255,83,20,
-	1,0,16,38,42,16,20,2,247,255,64,20,
-	0,0,0,0,33,16,0,0,44,0,191,143,
-	40,0,180,143,36,0,179,143,32,0,178,143,
-	28,0,177,143,24,0,176,143,8,0,224,3,
-	48,0,189,39,208,255,189,39,32,0,178,175,
-	33,144,128,0,28,0,177,175,33,136,160,0,
-	36,0,179,175,33,152,192,0,40,0,180,175,
-	33,160,224,0,44,0,191,175,2,0,32,22,
-	24,0,176,175,255,255,17,52,0,0,66,150,
-	0,0,0,0,36,16,81,0,3,0,83,20,
-	0,0,0,0,29,68,192,8,1,0,2,36,
-	11,0,128,26,33,128,0,0,143,63,192,12,
-	0,0,0,0,0,0,66,150,0,0,0,0,
-	36,16,81,0,246,255,83,20,1,0,16,38,
-	42,16,20,2,247,255,64,20,0,0,0,0,
-	33,16,0,0,44,0,191,143,40,0,180,143,
-	36,0,179,143,32,0,178,143,28,0,177,143,
-	24,0,176,143,8,0,224,3,48,0,189,39,
-	208,255,189,39,32,0,178,175,33,144,128,0,
-	28,0,177,175,33,136,160,0,36,0,179,175,
-	33,152,192,0,40,0,180,175,33,160,224,0,
-	44,0,191,175,2,0,32,22,24,0,176,175,
-	255,0,17,36,0,0,66,146,0,0,0,0,
-	36,16,81,0,3,0,83,20,0,0,0,0,
-	70,68,192,8,1,0,2,36,11,0,128,26,
-	33,128,0,0,143,63,192,12,0,0,0,0,
-	0,0,66,146,0,0,0,0,36,16,81,0,
-	246,255,83,20,1,0,16,38,42,16,20,2,
-	247,255,64,20,0,0,0,0,33,16,0,0,
-	44,0,191,143,40,0,180,143,36,0,179,143,
-	32,0,178,143,28,0,177,143,24,0,176,143,
-	8,0,224,3,48,0,189,39,0,0,0,0,
-	0,0,0,0,248,255,189,39,255,255,195,36,
-	8,0,192,16,33,56,128,0,255,255,6,36,
-	0,0,162,144,1,0,165,36,255,255,99,36,
-	0,0,130,160,251,255,102,20,1,0,132,36,
-	33,16,224,0,8,0,224,3,8,0,189,39,
-	0,0,0,0,0,0,0,0,0,96,8,64,
-	1,0,9,60,0,96,137,64,15,0,138,48,
-	33,40,170,0,192,255,165,36,0,0,128,160,
-	16,0,128,160,32,0,128,160,251,255,160,28,
-	48,0,128,160,64,0,132,36,0,96,136,64,
-	0,0,0,0,0,0,0,0,8,0,224,3,
-	0,0,0,0,0,0,0,0,1,131,2,60,
-	224,17,66,36,0,32,9,60,37,16,73,0,
-	8,0,64,0,0,0,0,0,0,96,8,64,
-	3,0,9,60,0,96,137,64,15,0,138,48,
-	33,40,170,0,192,255,165,36,0,0,128,160,
-	16,0,128,160,32,0,128,160,251,255,160,28,
-	48,0,128,160,64,0,132,36,0,96,136,64,
-	0,0,0,0,0,0,0,0,8,0,224,3,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,163,3,60,192,3,99,140,
-	0,163,2,60,188,3,66,140,0,0,0,0,
-	16,0,98,16,255,255,2,36,0,163,2,60,
-	188,3,66,140,0,163,1,60,33,8,34,0,
-	200,3,34,144,0,163,3,60,188,3,99,140,
-	0,163,4,60,196,3,132,140,0,22,2,0,
-	3,22,2,0,1,0,99,36,36,24,100,0,
-	0,163,1,60,188,3,35,172,8,0,224,3,
-	0,0,0,0,0,163,6,60,0,1,198,52,
-	10,0,9,36,255,255,8,36,13,0,7,36,
-	0,163,3,60,192,3,99,140,0,163,2,60,
-	188,3,66,140,0,0,0,0,17,0,98,16,
-	255,255,5,36,0,163,2,60,188,3,66,140,
-	0,0,0,0,33,16,70,0,200,2,66,144,
-	0,0,0,0,0,22,2,0,3,46,2,0,
-	0,163,2,60,188,3,66,140,0,163,3,60,
-	196,3,99,140,1,0,66,36,36,16,67,0,
-	0,163,1,60,188,3,34,172,11,0,169,16,
-	11,0,162,40,5,0,64,16,0,0,0,0,
-	228,255,168,16,0,0,0,0,206,68,192,8,
-	0,0,133,160,224,255,167,16,0,0,0,0,
-	206,68,192,8,0,0,133,160,208,68,192,8,
-	0,0,128,160,169,68,192,8,1,0,132,36,
-	8,0,224,3,0,0,0,0,0,0,0,0,
-	0,0,0,0,208,255,189,39,24,0,176,175,
-	33,128,128,0,36,0,179,175,33,152,160,0,
-	28,0,177,175,33,136,0,0,32,0,178,175,
-	33,144,0,2,5,0,64,22,40,0,191,175,
-	54,0,96,22,33,16,0,0,22,69,192,8,
-	0,0,32,174,0,0,67,130,0,0,0,0,
-	233,68,192,8,32,0,2,36,0,0,3,130,
-	32,0,2,36,253,255,98,16,1,0,16,38,
-	255,255,16,38,9,0,2,36,249,255,98,16,
-	1,0,16,38,255,255,16,38,0,0,3,130,
-	45,0,2,36,4,0,98,20,43,0,2,36,
-	1,0,16,38,250,68,192,8,1,0,17,36,
-	3,0,98,20,33,32,0,2,1,0,16,38,
-	33,32,0,2,44,69,192,12,16,0,165,39,
-	7,0,96,18,33,24,64,0,16,0,162,143,
-	0,0,0,0,2,0,80,20,0,0,0,0,
-	33,16,64,2,0,0,98,174,6,0,32,18,
-	0,128,2,60,43,16,67,0,5,0,64,20,
-	255,127,2,60,19,69,192,8,33,16,96,0,
-	5,0,97,4,255,127,2,60,7,0,32,18,
-	255,255,66,52,22,69,192,8,0,128,2,60,
-	33,16,96,0,2,0,32,18,0,0,0,0,
-	35,16,2,0,40,0,191,143,36,0,179,143,
-	32,0,178,143,28,0,177,143,24,0,176,143,
-	8,0,224,3,48,0,189,39,0,0,0,0,
-	0,0,0,0,0,0,0,0,208,255,130,36,
-	10,0,66,44,7,0,64,20,1,0,2,36,
-	191,255,130,36,6,0,66,44,3,0,64,20,
-	1,0,2,36,159,255,130,36,6,0,66,44,
-	8,0,224,3,0,0,0,0,248,255,189,39,
-	0,0,176,175,33,56,0,0,33,72,0,0,
-	33,80,0,0,33,112,0,0,5,0,128,20,
-	33,200,128,0,110,0,160,20,33,16,0,0,
-	163,69,192,8,0,0,192,173,0,0,131,128,
-	32,0,2,36,253,255,98,16,1,0,132,36,
-	255,255,132,36,9,0,2,36,249,255,98,16,
-	1,0,132,36,255,255,132,36,0,0,131,128,
-	43,0,2,36,3,0,98,20,45,0,2,36,
-	75,69,192,8,1,0,132,36,3,0,98,20,
-	0,0,0,0,1,0,132,36,1,0,14,36,
-	3,0,192,16,16,0,2,36,16,0,194,20,
-	0,0,0,0,0,0,131,128,48,0,2,36,
-	9,0,98,20,10,0,2,36,1,0,131,128,
-	88,0,2,36,3,0,98,16,120,0,2,36,
-	3,0,98,20,8,0,2,36,16,0,2,36,
-	2,0,132,36,2,0,192,20,0,0,0,0,
-	33,48,64,0,0,0,131,128,255,255,2,36,
-	27,0,70,0,2,0,192,20,0,0,0,0,
-	13,0,7,0,18,64,0,0,16,192,0,0,
-	0,0,0,0,0,0,0,0,42,0,96,16,
-	48,0,98,44,48,0,207,36,11,0,205,40,
-	87,0,204,36,55,0,203,36,5,0,64,20,
-	43,16,111,0,3,0,64,16,0,0,0,0,
-	130,69,192,8,208,255,99,36,30,0,160,21,
-	97,0,98,44,6,0,64,20,65,0,98,44,
-	43,16,108,0,3,0,64,16,65,0,98,44,
-	130,69,192,8,169,255,99,36,21,0,64,20,
-	43,16,107,0,19,0,64,16,0,0,0,0,
-	201,255,99,36,43,16,7,1,6,0,64,20,
-	1,0,9,36,6,0,232,20,24,0,230,0,
-	43,16,3,3,3,0,64,16,0,0,0,0,
-	1,0,10,36,24,0,230,0,1,0,132,36,
-	18,128,0,0,33,56,3,2,0,0,131,128,
-	0,0,0,0,220,255,96,20,48,0,98,44,
-	5,0,64,17,0,0,0,0,13,0,160,16,
-	255,255,2,36,163,69,192,8,0,0,164,172,
-	6,0,160,16,0,0,0,0,3,0,32,21,
-	0,0,0,0,160,69,192,8,0,0,185,172,
-	0,0,164,172,2,0,192,17,33,16,224,0,
-	35,16,2,0,0,0,176,143,8,0,224,3,
-	8,0,189,39,0,0,0,0,0,0,0,0,
-	200,255,189,39,16,0,176,175,7,162,16,60,
-	236,0,16,54,255,240,3,60,255,255,99,52,
-	63,0,132,48,36,0,181,175,128,1,149,52,
-	24,0,178,175,0,1,18,36,20,0,177,175,
-	7,162,17,60,236,0,49,54,44,0,183,175,
-	0,4,23,60,32,0,180,175,255,251,20,60,
-	255,255,148,54,40,0,182,175,0,1,22,60,
-	28,0,179,175,255,254,19,60,48,0,191,175,
-	0,0,2,142,0,0,0,0,36,16,67,0,
-	224,133,130,175,0,0,2,174,76,63,192,12,
-	255,255,115,54,224,133,130,143,0,2,3,60,
-	37,16,67,0,224,133,130,175,0,0,2,174,
-	36,16,85,2,5,0,64,16,0,0,0,0,
-	224,133,130,143,0,0,0,0,214,69,192,8,
-	37,16,87,0,224,133,130,143,0,0,0,0,
-	36,16,84,0,224,133,130,175,76,63,192,12,
-	0,0,34,174,224,133,130,143,0,0,0,0,
-	37,16,86,0,224,133,130,175,0,0,34,174,
-	76,63,192,12,66,144,18,0,224,133,130,143,
-	0,0,0,0,36,16,83,0,224,133,130,175,
-	0,0,34,174,255,255,66,50,230,255,64,20,
-	36,16,85,2,33,136,0,0,16,0,16,36,
-	7,162,18,60,236,0,82,54,0,1,22,60,
-	0,8,21,60,255,254,19,60,255,255,115,54,
-	255,255,20,36,76,63,192,12,0,0,0,0,
-	224,133,130,143,0,0,0,0,37,16,86,0,
-	224,133,130,175,76,63,192,12,0,0,66,174,
-	7,0,0,18,0,0,0,0,0,0,66,142,
-	0,0,0,0,36,16,85,0,2,0,64,16,
-	64,136,17,0,1,0,49,54,76,63,192,12,
-	255,255,16,38,224,133,130,143,0,0,0,0,
-	36,16,83,0,224,133,130,175,0,0,66,174,
-	232,255,20,22,7,162,4,60,236,0,132,52,
-	255,253,3,60,224,133,130,143,255,255,99,52,
-	36,16,67,0,224,133,130,175,0,0,130,172,
-	255,255,34,50,48,0,191,143,44,0,183,143,
-	40,0,182,143,36,0,181,143,32,0,180,143,
-	28,0,179,143,24,0,178,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,56,0,189,39,
-	200,255,189,39,48,0,190,175,33,240,160,0,
-	40,0,182,175,63,0,150,48,33,32,192,2,
-	52,0,191,175,44,0,183,175,36,0,181,175,
-	32,0,180,175,28,0,179,175,24,0,178,175,
-	20,0,177,175,168,69,192,12,16,0,176,175,
-	33,152,64,0,255,255,195,51,255,255,98,50,
-	3,0,98,20,7,162,16,60,131,71,192,8,
-	1,0,2,36,236,0,16,54,255,252,3,60,
-	255,255,99,52,0,1,18,36,7,162,17,60,
-	236,0,49,54,255,251,21,60,255,255,181,54,
-	0,1,23,60,255,254,20,60,224,133,130,143,
-	0,0,0,0,36,16,67,0,224,133,130,175,
-	0,0,2,174,76,63,192,12,255,255,148,54,
-	224,133,130,143,0,2,3,60,37,16,67,0,
-	224,133,130,175,0,0,2,174,48,1,66,50,
-	5,0,64,16,0,4,6,60,224,133,130,143,
-	0,0,0,0,83,70,192,8,37,16,70,0,
-	224,133,130,143,0,0,0,0,36,16,85,0,
-	224,133,130,175,76,63,192,12,0,0,34,174,
-	224,133,130,143,0,0,0,0,37,16,87,0,
-	224,133,130,175,0,0,34,174,76,63,192,12,
-	66,144,18,0,224,133,130,143,0,0,0,0,
-	36,16,84,0,224,133,130,175,0,0,34,174,
-	255,255,66,50,230,255,64,20,48,1,66,50,
-	255,255,195,51,255,255,98,50,39,16,2,0,
-	36,24,98,0,88,0,96,16,192,1,213,54,
-	7,162,16,60,236,0,16,54,255,252,3,60,
-	255,255,99,52,0,1,18,36,7,162,17,60,
-	236,0,49,54,255,251,20,60,255,255,148,54,
-	0,1,23,60,255,254,19,60,224,133,130,143,
-	0,0,0,0,36,16,67,0,224,133,130,175,
-	0,0,2,174,76,63,192,12,255,255,115,54,
-	224,133,130,143,0,2,3,60,37,16,67,0,
-	224,133,130,175,0,0,2,174,36,16,85,2,
-	5,0,64,16,0,4,6,60,224,133,130,143,
-	0,0,0,0,140,70,192,8,37,16,70,0,
-	224,133,130,143,0,0,0,0,36,16,84,0,
-	224,133,130,175,76,63,192,12,0,0,34,174,
-	224,133,130,143,0,0,0,0,37,16,87,0,
-	224,133,130,175,0,0,34,174,76,63,192,12,
-	66,144,18,0,224,133,130,143,0,0,0,0,
-	36,16,83,0,224,133,130,175,0,0,34,174,
-	255,255,66,50,230,255,64,20,36,16,85,2,
-	7,162,16,60,236,0,16,54,255,252,3,60,
-	224,133,130,143,255,255,99,52,36,16,67,0,
-	224,133,130,175,76,63,192,12,0,0,2,174,
-	224,133,130,143,0,2,3,60,37,16,67,0,
-	224,133,130,175,0,0,2,174,0,0,2,142,
-	0,8,3,60,36,16,67,0,11,0,64,20,
-	7,162,4,60,7,162,16,60,236,0,16,54,
-	0,8,17,60,76,63,192,12,0,0,0,0,
-	0,0,2,142,0,0,0,0,36,16,81,0,
-	250,255,64,16,7,162,4,60,236,0,132,52,
-	255,253,3,60,224,133,130,143,255,255,99,52,
-	36,16,67,0,224,133,130,175,0,0,130,172,
-	255,255,195,51,255,255,2,52,133,0,98,16,
-	64,1,213,54,7,162,16,60,236,0,16,54,
-	255,252,3,60,255,255,99,52,0,1,18,36,
-	7,162,17,60,236,0,49,54,255,251,20,60,
-	255,255,148,54,0,1,23,60,255,254,19,60,
-	224,133,130,143,0,0,0,0,36,16,67,0,
-	224,133,130,175,0,0,2,174,76,63,192,12,
-	255,255,115,54,224,133,130,143,0,2,3,60,
-	37,16,67,0,224,133,130,175,0,0,2,174,
-	36,16,85,2,5,0,64,16,0,4,6,60,
-	224,133,130,143,0,0,0,0,231,70,192,8,
-	37,16,70,0,224,133,130,143,0,0,0,0,
-	36,16,84,0,224,133,130,175,76,63,192,12,
-	0,0,34,174,224,133,130,143,0,0,0,0,
-	37,16,87,0,224,133,130,175,0,0,34,174,
-	76,63,192,12,66,144,18,0,224,133,130,143,
-	0,0,0,0,36,16,83,0,224,133,130,175,
-	0,0,34,174,255,255,66,50,230,255,64,20,
-	36,16,85,2,33,160,192,3,7,162,2,60,
-	236,0,66,52,0,128,17,52,7,162,16,60,
-	236,0,16,54,0,4,23,60,255,251,19,60,
-	255,255,115,54,0,1,21,60,255,254,18,60,
-	255,255,82,54,224,133,131,143,0,2,4,60,
-	37,24,100,0,224,133,131,175,0,0,67,172,
-	36,16,52,2,5,0,64,16,0,0,0,0,
-	224,133,130,143,0,0,0,0,20,71,192,8,
-	37,16,87,0,224,133,130,143,0,0,0,0,
-	36,16,83,0,224,133,130,175,76,63,192,12,
-	0,0,2,174,224,133,130,143,0,0,0,0,
-	37,16,85,0,224,133,130,175,0,0,2,174,
-	76,63,192,12,66,136,17,0,224,133,130,143,
-	0,0,0,0,36,16,82,0,224,133,130,175,
-	0,0,2,174,255,255,34,50,230,255,64,20,
-	36,16,52,2,7,162,16,60,236,0,16,54,
-	255,252,3,60,224,133,130,143,255,255,99,52,
-	36,16,67,0,224,133,130,175,76,63,192,12,
-	0,0,2,174,224,133,130,143,0,2,3,60,
-	37,16,67,0,224,133,130,175,0,0,2,174,
-	0,0,2,142,0,8,3,60,36,16,67,0,
-	11,0,64,20,7,162,4,60,7,162,16,60,
-	236,0,16,54,0,8,17,60,76,63,192,12,
-	0,0,0,0,0,0,2,142,0,0,0,0,
-	36,16,81,0,250,255,64,16,7,162,4,60,
-	236,0,132,52,255,253,3,60,224,133,130,143,
-	255,255,99,52,36,16,67,0,224,133,130,175,
-	0,0,130,172,7,162,16,60,236,0,16,54,
-	255,252,3,60,255,255,99,52,0,1,18,36,
-	7,162,17,60,236,0,49,54,0,4,23,60,
-	255,251,20,60,255,255,148,54,0,1,21,60,
-	255,254,19,60,224,133,130,143,0,0,0,0,
-	36,16,67,0,224,133,130,175,0,0,2,174,
-	76,63,192,12,255,255,115,54,224,133,130,143,
-	0,2,3,60,37,16,67,0,224,133,130,175,
-	0,0,2,174,0,1,66,50,5,0,64,16,
-	0,0,0,0,224,133,130,143,0,0,0,0,
-	108,71,192,8,37,16,87,0,224,133,130,143,
-	0,0,0,0,36,16,84,0,224,133,130,175,
-	76,63,192,12,0,0,34,174,224,133,130,143,
-	0,0,0,0,37,16,85,0,224,133,130,175,
-	0,0,34,174,76,63,192,12,66,144,18,0,
-	224,133,130,143,0,0,0,0,36,16,83,0,
-	224,133,130,175,0,0,34,174,255,255,66,50,
-	230,255,64,20,0,1,66,50,168,69,192,12,
-	33,32,192,2,38,16,194,3,255,255,66,48,
-	1,0,66,44,52,0,191,143,48,0,190,143,
-	44,0,183,143,40,0,182,143,36,0,181,143,
-	32,0,180,143,28,0,179,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	56,0,189,39,0,0,0,0,248,255,189,39,
-	255,255,195,36,6,0,192,16,33,16,128,0,
-	255,255,6,36,0,0,133,160,255,255,99,36,
-	253,255,102,20,1,0,132,36,8,0,189,39,
-	8,0,224,3,0,0,0,0,159,71,192,8,
-	33,24,0,0,1,0,99,36,0,0,130,128,
-	0,0,0,0,252,255,64,20,1,0,132,36,
-	8,0,224,3,33,16,96,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,255,255,198,36,
-	10,0,192,16,0,0,0,0,0,0,131,128,
-	0,0,162,128,0,0,0,0,5,0,98,20,
-	0,0,0,0,1,0,132,36,255,255,198,36,
-	248,255,192,20,1,0,165,36,0,0,131,144,
-	0,0,162,144,0,0,0,0,8,0,224,3,
-	35,16,98,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,196,71,192,8,240,255,189,39,
-	0,0,163,128,3,22,2,0,8,0,67,20,
-	0,0,0,0,1,0,132,36,1,0,165,36,
-	0,0,130,128,0,0,131,144,0,0,0,0,
-	246,255,64,20,0,22,3,0,0,0,131,144,
-	0,0,162,144,0,0,0,0,35,16,98,0,
-	8,0,224,3,16,0,189,39,0,0,0,0,
-	255,255,198,36,9,0,192,4,33,16,0,0,
-	0,0,130,144,0,0,0,0,5,0,69,16,
-	33,16,128,0,255,255,198,36,250,255,193,4,
-	1,0,132,36,33,16,0,0,8,0,224,3,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,2,0,192,20,255,255,2,36,
-	1,0,2,36,8,0,224,3,0,0,226,172,
-	232,255,189,39,20,0,191,175,16,0,176,175,
-	40,0,176,143,33,32,192,0,4,0,5,142,
-	0,0,0,0,15,86,192,12,255,255,230,48,
-	3,0,64,16,255,255,2,36,243,71,192,8,
-	0,0,2,174,0,0,0,174,20,0,191,143,
-	16,0,176,143,8,0,224,3,24,0,189,39,
-	208,255,189,39,40,0,191,175,33,24,128,0,
-	64,0,162,143,32,0,160,175,36,0,162,175,
-	12,0,66,148,0,0,0,0,2,0,64,20,
-	33,32,160,0,120,5,2,36,255,255,66,48,
-	16,0,162,175,1,131,2,60,148,31,66,36,
-	20,0,162,175,1,131,2,60,128,31,66,36,
-	24,0,162,175,32,0,162,39,28,0,162,175,
-	166,85,192,12,33,40,96,0,32,0,162,143,
-	40,0,191,143,48,0,189,39,8,0,224,3,
-	0,0,0,0,0,0,0,0,88,0,131,148,
-	4,0,2,36,9,0,98,20,0,0,0,0,
-	33,72,192,8,116,0,132,36,33,16,69,0,
-	128,16,2,0,8,0,131,140,0,0,0,0,
-	46,72,192,8,33,16,67,0,104,0,132,36,
-	12,0,128,16,33,16,0,0,4,0,130,140,
-	0,0,0,0,42,16,162,0,243,255,64,20,
-	0,17,5,0,4,0,130,140,12,0,132,140,
-	0,0,0,0,247,255,128,20,35,40,162,0,
-	33,16,0,0,8,0,224,3,0,0,0,0,
-	88,0,131,148,4,0,2,36,3,0,98,20,
-	33,48,0,0,55,72,192,8,116,0,132,36,
-	104,0,132,36,8,0,130,140,0,0,0,0,
-	43,16,162,0,14,0,64,16,255,255,2,36,
-	92,72,192,8,0,0,0,0,35,24,163,0,
-	0,17,3,0,35,16,67,0,0,26,2,0,
-	33,16,67,0,0,28,2,0,33,16,67,0,
-	35,16,2,0,131,16,2,0,92,72,192,8,
-	33,16,194,0,18,0,128,16,0,0,0,0,
-	4,0,131,140,0,0,0,0,0,17,3,0,
-	33,16,67,0,128,16,2,0,8,0,131,140,
-	0,0,0,0,33,16,67,0,43,16,162,0,
-	233,255,64,20,0,0,0,0,4,0,130,140,
-	12,0,132,140,0,0,0,0,241,255,128,20,
-	33,48,194,0,255,255,2,36,8,0,224,3,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	8,0,130,36,144,0,163,140,120,132,135,39,
-	2,0,96,16,20,0,137,36,33,56,96,0,
-	0,0,72,140,4,0,68,140,132,72,192,8,
-	0,0,0,0,30,0,0,25,0,0,0,0,
-	4,0,227,140,0,0,0,0,4,0,98,140,
-	0,0,0,0,55,0,64,16,255,255,2,36,
-	0,0,135,140,0,0,98,140,0,0,0,0,
-	8,0,71,16,0,0,0,0,8,0,99,36,
-	4,0,98,140,0,0,0,0,248,255,64,20,
-	255,255,2,36,168,72,192,8,0,0,0,0,
-	0,0,130,140,0,0,0,0,4,0,34,173,
-	4,0,103,140,255,255,8,37,4,0,132,36,
-	0,0,226,148,0,0,0,0,1,0,66,48,
-	226,255,64,16,0,0,0,0,0,0,226,148,
-	0,0,0,0,64,0,66,48,27,0,64,20,
-	255,255,2,36,0,0,226,148,0,0,0,0,
-	1,0,66,48,17,0,64,16,0,0,0,0,
-	13,0,192,16,1,0,2,36,64,0,162,140,
-	0,0,0,0,9,0,64,20,1,0,2,36,
-	28,0,226,140,4,0,163,140,0,0,0,0,
-	36,16,67,0,3,0,64,20,1,0,2,36,
-	168,72,192,8,255,255,2,36,164,72,192,8,
-	0,0,34,165,0,0,32,165,8,0,40,173,
-	12,0,36,173,16,0,39,173,33,16,0,0,
-	8,0,224,3,0,0,0,0,200,255,189,39,
-	48,0,191,175,44,0,179,175,40,0,178,175,
-	36,0,177,175,32,0,176,175,33,152,128,0,
-	33,128,160,0,33,144,192,0,0,0,4,142,
-	0,0,0,0,48,0,130,40,2,0,64,16,
-	8,0,113,38,48,0,4,36,0,0,36,174,
-	9,50,192,12,128,32,4,0,3,0,64,20,
-	4,0,34,174,214,72,192,8,255,255,2,36,
-	144,0,66,142,120,132,132,39,2,0,64,16,
-	0,0,0,0,33,32,64,0,16,0,160,175,
-	20,0,179,175,24,0,178,175,0,0,5,142,
-	4,0,6,142,0,0,0,0,221,72,192,12,
-	33,56,32,2,33,128,64,0,4,0,0,26,
-	0,0,0,0,0,0,34,142,214,72,192,8,
-	0,0,0,0,110,86,192,12,33,32,32,2,
-	33,16,0,2,48,0,191,143,44,0,179,143,
-	40,0,178,143,36,0,177,143,32,0,176,143,
-	8,0,224,3,56,0,189,39,184,255,189,39,
-	68,0,191,175,64,0,190,175,60,0,183,175,
-	56,0,182,175,52,0,181,175,48,0,180,175,
-	44,0,179,175,40,0,178,175,36,0,177,175,
-	32,0,176,175,33,144,128,0,33,176,160,0,
-	33,136,224,0,88,0,183,143,92,0,179,143,
-	96,0,190,143,32,0,226,38,0,0,36,142,
-	0,0,0,0,42,16,130,0,22,0,64,16,
-	33,160,192,0,4,0,132,36,9,50,192,12,
-	128,32,4,0,33,128,64,0,3,0,0,22,
-	33,32,0,2,153,73,192,8,255,255,2,36,
-	0,0,38,142,4,0,37,142,0,0,0,0,
-	80,68,192,12,128,48,6,0,4,0,36,142,
-	61,50,192,12,0,0,0,0,4,0,48,174,
-	0,0,34,142,0,0,0,0,4,0,66,36,
-	0,0,34,174,0,0,66,150,0,0,0,0,
-	1,0,66,48,96,0,64,20,0,0,0,0,
-	33,0,192,30,0,0,0,0,4,0,80,142,
-	0,0,0,0,4,0,2,142,0,0,0,0,
-	108,0,64,16,128,160,23,0,1,0,242,38,
-	4,0,34,142,0,0,0,0,33,16,130,2,
-	0,0,3,142,0,0,0,0,0,0,67,172,
-	0,0,2,142,0,0,0,0,24,0,98,174,
-	16,0,178,175,20,0,179,175,24,0,190,175,
-	4,0,4,142,33,40,0,0,33,48,0,0,
-	221,72,192,12,33,56,32,2,112,0,64,20,
-	8,0,16,38,4,0,2,142,0,0,0,0,
-	234,255,64,20,33,16,0,0,153,73,192,8,
-	0,0,0,0,4,0,80,142,0,0,0,0,
-	4,0,2,142,0,0,0,0,76,0,64,16,
-	128,168,23,0,1,0,242,38,0,0,3,142,
-	0,0,132,142,0,0,0,0,43,16,100,0,
-	42,0,64,20,0,0,0,0,19,0,100,20,
-	255,255,197,38,4,0,34,142,0,0,0,0,
-	33,16,162,2,0,0,67,172,0,0,2,142,
-	0,0,0,0,24,0,98,174,16,0,178,175,
-	20,0,179,175,24,0,190,175,4,0,4,142,
-	4,0,134,38,221,72,192,12,33,56,32,2,
-	25,0,64,16,8,0,16,38,153,73,192,8,
-	0,0,0,0,0,0,130,142,0,0,0,0,
-	43,16,67,0,17,0,64,16,33,40,0,0,
-	4,0,34,142,0,0,0,0,33,16,162,2,
-	0,0,67,172,0,0,2,142,0,0,0,0,
-	24,0,98,174,16,0,178,175,20,0,179,175,
-	24,0,190,175,4,0,4,142,33,48,0,0,
-	221,72,192,12,33,56,32,2,52,0,64,20,
-	0,0,0,0,8,0,16,38,4,0,2,142,
-	0,0,0,0,205,255,64,20,33,16,0,0,
-	153,73,192,8,0,0,0,0,0,0,66,150,
-	0,0,0,0,64,0,66,48,40,0,64,20,
-	33,16,0,0,3,0,66,146,0,0,0,0,
-	1,0,66,48,11,0,64,16,33,24,64,2,
-	64,0,194,143,0,0,0,0,9,0,64,20,
-	0,0,0,0,28,0,98,140,4,0,195,143,
-	0,0,0,0,36,16,67,0,3,0,64,20,
-	0,0,0,0,153,73,192,8,33,16,0,0,
-	14,0,192,26,33,16,246,2,0,0,34,174,
-	4,0,36,142,128,128,23,0,33,32,4,2,
-	33,40,128,2,80,68,192,12,128,48,22,0,
-	28,0,118,174,4,0,34,142,0,0,0,0,
-	33,128,2,2,149,73,192,8,32,0,112,174,
-	0,0,55,174,28,0,96,174,32,0,96,174,
-	36,0,114,174,1,0,2,36,20,0,98,166,
-	1,0,2,36,68,0,191,143,64,0,190,143,
-	60,0,183,143,56,0,182,143,52,0,181,143,
-	48,0,180,143,44,0,179,143,40,0,178,143,
-	36,0,177,143,32,0,176,143,8,0,224,3,
-	72,0,189,39,3,0,160,28,33,16,0,0,
-	0,0,224,172,1,0,2,36,8,0,224,3,
-	0,0,0,0,208,255,189,39,44,0,191,175,
-	40,0,178,175,36,0,177,175,32,0,176,175,
-	33,144,128,0,33,136,224,0,64,0,176,143,
-	0,0,0,0,6,0,160,24,24,0,160,175,
-	17,0,2,146,0,0,0,0,18,0,66,52,
-	200,73,192,8,17,0,2,162,33,32,32,2,
-	33,40,0,2,1,0,6,36,253,76,192,12,
-	24,0,167,39,36,0,2,142,16,0,176,175,
-	8,0,66,140,33,32,64,2,1,0,5,36,
-	24,0,166,39,9,248,64,0,33,56,32,2,
-	44,0,191,143,40,0,178,143,36,0,177,143,
-	32,0,176,143,8,0,224,3,48,0,189,39,
-	224,255,189,39,28,0,191,175,24,0,178,175,
-	20,0,177,175,33,144,128,0,33,136,160,0,
-	31,0,81,18,16,0,176,175,4,0,80,142,
-	0,0,0,0,4,0,2,142,0,0,0,0,
-	10,0,64,16,0,0,0,0,4,0,4,142,
-	0,0,0,0,206,73,192,12,33,40,32,2,
-	8,0,16,38,4,0,2,142,0,0,0,0,
-	248,255,64,20,0,0,0,0,0,0,66,150,
-	0,0,0,0,32,0,66,48,4,0,64,16,
-	0,0,0,0,4,0,68,142,61,50,192,12,
-	0,0,0,0,0,0,66,150,0,0,0,0,
-	16,0,66,48,3,0,64,16,0,0,0,0,
-	61,50,192,12,33,32,64,2,28,0,191,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,120,132,131,39,
-	2,0,128,16,0,0,0,0,33,24,128,0,
-	0,0,167,140,4,0,165,140,26,74,192,8,
-	0,0,0,0,28,0,224,24,0,0,0,0,
-	4,0,99,140,0,0,0,0,4,0,98,140,
-	0,0,0,0,11,0,64,16,0,0,0,0,
-	0,0,164,140,0,0,98,140,0,0,0,0,
-	9,0,68,16,0,0,0,0,8,0,99,36,
-	4,0,98,140,0,0,0,0,248,255,64,20,
-	0,0,0,0,0,0,192,172,33,74,192,8,
-	2,0,2,36,4,0,99,140,255,255,231,36,
-	4,0,165,36,0,0,98,148,0,0,0,0,
-	1,0,66,48,228,255,64,16,0,0,0,0,
-	0,0,195,172,42,16,7,0,8,0,224,3,
-	0,0,0,0,208,255,189,39,44,0,191,175,
-	40,0,182,175,36,0,181,175,32,0,180,175,
-	28,0,179,175,24,0,178,175,20,0,177,175,
-	16,0,176,175,33,168,192,0,0,0,162,140,
-	0,0,0,0,3,0,64,28,33,48,0,0,
-	220,74,192,8,5,0,2,36,120,132,147,39,
-	2,0,128,16,0,0,224,172,33,152,128,0,
-	0,0,177,140,4,0,180,140,84,74,192,8,
-	0,0,0,0,29,0,32,26,0,0,0,0,
-	4,0,102,142,0,0,0,0,4,0,194,140,
-	0,0,0,0,23,0,64,16,0,0,0,0,
-	0,0,131,142,0,0,194,140,0,0,0,0,
-	6,0,67,16,0,0,0,0,8,0,198,36,
-	4,0,194,140,0,0,0,0,248,255,64,20,
-	0,0,0,0,4,0,194,140,0,0,0,0,
-	9,0,64,16,0,0,0,0,255,255,49,38,
-	4,0,148,38,33,152,64,0,0,0,98,150,
-	0,0,0,0,1,0,66,48,227,255,64,16,
-	0,0,0,0,29,0,32,22,0,0,0,0,
-	0,0,99,150,0,0,0,0,1,0,98,48,
-	11,0,64,16,4,0,98,48,123,0,64,16,
-	3,0,2,36,0,0,162,150,0,0,0,0,
-	1,0,66,48,118,0,64,16,4,0,2,36,
-	0,0,243,172,219,74,192,8,4,0,213,172,
-	0,0,98,150,0,0,0,0,4,0,66,48,
-	110,0,64,16,3,0,2,36,0,0,162,150,
-	0,0,0,0,1,0,66,48,105,0,64,20,
-	4,0,2,36,0,0,243,172,219,74,192,8,
-	4,0,213,172,0,0,98,150,0,0,0,0,
-	1,0,66,48,97,0,64,20,2,0,2,36,
-	2,0,34,42,23,0,64,20,33,144,160,2,
-	56,0,22,36,9,50,192,12,16,0,4,36,
-	33,128,64,0,40,0,0,18,128,16,17,0,
-	33,16,84,0,252,255,66,140,0,0,0,0,
-	0,0,2,174,4,0,18,174,8,0,0,174,
-	12,0,0,174,9,50,192,12,8,0,4,36,
-	33,144,64,0,24,0,64,18,255,255,49,38,
-	0,0,86,166,2,0,34,42,236,255,64,16,
-	4,0,80,174,4,0,102,142,0,0,0,0,
-	4,0,194,140,0,0,0,0,6,0,64,16,
-	1,0,17,36,8,0,198,36,4,0,194,140,
-	0,0,0,0,252,255,64,20,1,0,49,38,
-	1,0,36,38,9,50,192,12,192,32,4,0,
-	33,128,64,0,12,0,0,22,33,32,64,2,
-	173,74,192,8,0,0,0,0,0,0,18,142,
-	0,0,0,0,61,50,192,12,33,32,0,2,
-	33,32,64,2,206,73,192,12,33,40,160,2,
-	220,74,192,8,1,0,2,36,4,0,102,142,
-	0,0,0,0,192,74,192,8,33,168,0,2,
-	4,0,194,140,0,0,0,0,14,0,64,16,
-	0,0,0,0,0,0,194,140,4,0,195,140,
-	0,0,2,174,4,0,3,174,8,0,198,36,
-	8,0,16,38,255,255,49,38,0,0,194,140,
-	0,0,131,142,0,0,0,0,43,16,67,0,
-	240,255,64,20,0,0,0,0,0,0,130,142,
-	0,0,0,0,0,0,2,174,4,0,18,174,
-	8,0,4,38,33,40,192,0,80,68,192,12,
-	192,48,17,0,4,0,102,142,4,0,117,174,
-	0,0,98,150,0,0,0,0,32,0,66,48,
-	3,0,64,16,0,0,0,0,61,50,192,12,
-	33,32,192,0,0,0,98,150,0,0,0,0,
-	32,0,66,52,0,0,98,166,33,16,0,0,
-	44,0,191,143,40,0,182,143,36,0,181,143,
-	32,0,180,143,28,0,179,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	48,0,189,39,232,255,189,39,20,0,191,175,
-	16,0,176,175,0,0,162,140,0,0,0,0,
-	85,0,64,24,33,16,0,0,120,132,144,39,
-	2,0,128,16,0,0,0,0,33,128,128,0,
-	0,0,164,140,4,0,165,140,0,0,0,0,
-	0,0,168,140,0,0,2,150,0,0,0,0,
-	33,24,64,0,1,0,66,48,34,0,64,20,
-	33,56,0,2,32,0,128,24,8,0,98,48,
-	4,0,6,142,5,0,64,16,0,0,0,0,
-	12,0,194,140,0,0,0,0,3,0,64,16,
-	0,0,0,0,33,56,0,2,0,0,168,140,
-	0,0,195,140,0,0,162,140,0,0,0,0,
-	10,0,98,16,0,0,0,0,0,0,163,140,
-	4,0,194,140,0,0,0,0,20,0,64,16,
-	8,0,198,36,0,0,194,140,0,0,0,0,
-	249,255,67,20,0,0,0,0,255,255,132,36,
-	4,0,208,140,0,0,0,0,0,0,3,150,
-	0,0,0,0,1,0,98,48,224,255,64,16,
-	4,0,165,36,36,0,128,20,33,16,0,0,
-	0,0,2,150,0,0,0,0,2,0,66,48,
-	3,0,64,20,0,0,0,0,65,75,192,8,
-	33,16,0,0,4,0,230,140,0,0,0,0,
-	0,0,194,140,0,0,0,0,7,0,72,16,
-	0,0,0,0,8,0,198,36,0,0,194,140,
-	0,0,0,0,253,255,72,20,8,0,198,36,
-	248,255,198,36,4,0,199,140,0,0,0,0,
-	10,0,224,16,33,32,224,0,8,0,194,140,
-	12,0,195,140,0,0,194,172,4,0,195,172,
-	8,0,198,36,4,0,194,140,0,0,0,0,
-	248,255,64,20,33,32,224,0,206,73,192,12,
-	33,40,0,2,33,16,0,2,20,0,191,143,
-	16,0,176,143,8,0,224,3,24,0,189,39,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	192,255,189,39,56,0,191,175,52,0,181,175,
-	48,0,180,175,44,0,179,175,40,0,178,175,
-	36,0,177,175,32,0,176,175,33,136,128,0,
-	33,144,160,0,33,152,192,0,33,160,224,0,
-	80,0,181,143,0,0,0,0,36,0,162,142,
-	0,0,0,0,20,0,80,140,33,32,128,2,
-	48,72,192,12,33,40,160,2,16,0,3,142,
-	0,0,0,0,16,0,163,175,20,0,180,175,
-	24,0,162,175,0,0,2,142,1,0,4,36,
-	33,40,32,2,33,48,64,2,9,248,64,0,
-	33,56,96,2,6,0,64,20,33,32,128,2,
-	17,0,162,146,0,0,0,0,1,0,66,52,
-	113,75,192,8,17,0,162,162,33,40,160,2,
-	59,77,192,12,33,48,64,0,56,0,191,143,
-	52,0,181,143,48,0,180,143,44,0,179,143,
-	40,0,178,143,36,0,177,143,32,0,176,143,
-	8,0,224,3,64,0,189,39,192,255,189,39,
-	60,0,191,175,56,0,178,175,52,0,177,175,
-	48,0,176,175,33,136,224,0,80,0,178,143,
-	36,0,160,175,36,0,66,142,0,0,0,0,
-	20,0,67,140,2,0,80,144,0,0,0,0,
-	255,0,2,50,254,255,71,36,70,0,226,44,
-	110,0,64,16,128,16,7,0,2,131,1,60,
-	33,8,34,0,160,151,34,140,0,0,0,0,
-	8,0,64,0,0,0,0,0,16,0,177,175,
-	8,0,98,140,16,0,103,140,9,248,64,0,
-	0,0,0,0,2,0,3,36,16,0,67,162,
-	251,75,192,8,40,0,66,174,16,0,177,175,
-	8,0,98,140,16,0,103,140,9,248,64,0,
-	0,0,0,0,40,0,162,175,16,0,80,162,
-	40,0,162,143,0,0,0,0,251,75,192,8,
-	40,0,66,174,32,0,162,39,16,0,162,175,
-	20,0,177,175,36,0,162,39,24,0,162,175,
-	8,0,98,140,16,0,103,140,9,248,64,0,
-	0,0,0,0,33,48,64,0,16,0,80,162,
-	17,0,66,146,0,0,0,0,2,0,66,52,
-	17,0,66,162,36,0,162,143,0,0,0,0,
-	43,16,2,0,40,0,66,166,44,0,70,174,
-	32,0,162,151,0,0,0,0,33,16,194,0,
-	48,0,66,174,255,75,192,8,52,0,64,166,
-	16,0,177,175,36,0,162,39,20,0,162,175,
-	8,0,98,140,16,0,103,140,9,248,64,0,
-	0,0,0,0,33,128,64,0,8,0,0,22,
-	33,32,32,2,16,0,160,175,33,40,64,2,
-	33,48,0,0,226,76,192,12,33,56,0,0,
-	255,75,192,8,0,0,0,0,36,0,162,143,
-	0,0,0,0,16,0,162,175,0,0,6,142,
-	4,0,7,142,0,0,0,0,226,76,192,12,
-	33,40,64,2,36,0,162,143,0,0,0,0,
-	35,0,64,16,0,0,0,0,61,50,192,12,
-	33,32,0,2,255,75,192,8,0,0,0,0,
-	5,0,2,36,251,75,192,8,16,0,66,162,
-	16,0,177,175,40,0,162,39,20,0,162,175,
-	8,0,98,140,16,0,103,140,9,248,64,0,
-	0,0,0,0,33,48,64,0,7,0,192,16,
-	64,0,2,36,3,0,194,136,0,0,194,152,
-	0,0,0,0,43,0,162,171,40,0,162,187,
-	64,0,2,36,16,0,66,162,40,0,162,143,
-	0,0,0,0,251,75,192,8,40,0,66,174,
-	5,0,2,36,96,0,34,174,17,0,66,146,
-	0,0,0,0,2,0,66,52,17,0,66,162,
-	60,0,191,143,56,0,178,143,52,0,177,143,
-	48,0,176,143,8,0,224,3,64,0,189,39,
-	80,255,189,39,168,0,191,175,164,0,179,175,
-	160,0,178,175,156,0,177,175,152,0,176,175,
-	33,152,128,0,33,136,224,0,192,0,178,143,
-	0,0,0,0,36,0,66,142,0,0,0,0,
-	20,0,67,140,0,0,0,0,16,0,98,140,
-	0,0,0,0,16,0,162,175,20,0,177,175,
-	4,0,98,140,0,0,0,0,9,248,64,0,
-	24,0,167,39,33,128,64,0,6,0,0,22,
-	33,32,32,2,17,0,66,146,0,0,0,0,
-	18,0,66,52,45,76,192,8,17,0,66,162,
-	33,40,64,2,33,48,0,2,253,76,192,12,
-	24,0,167,39,16,0,178,175,33,32,96,2,
-	33,40,0,2,24,0,166,39,122,75,192,12,
-	33,56,32,2,168,0,191,143,164,0,179,143,
-	160,0,178,143,156,0,177,143,152,0,176,143,
-	8,0,224,3,176,0,189,39,192,255,189,39,
-	56,0,191,175,52,0,181,175,48,0,180,175,
-	44,0,179,175,40,0,178,175,36,0,177,175,
-	32,0,176,175,33,152,128,0,33,160,160,0,
-	33,168,192,0,33,136,224,0,80,0,178,143,
-	0,0,0,0,36,0,66,142,0,0,0,0,
-	20,0,80,140,33,32,32,2,48,72,192,12,
-	33,40,64,2,16,0,3,142,0,0,0,0,
-	16,0,163,175,20,0,177,175,24,0,162,175,
-	0,0,2,142,33,32,0,0,33,40,96,2,
-	33,48,128,2,9,248,64,0,33,56,160,2,
-	5,0,64,16,33,32,32,2,200,76,192,12,
-	33,40,64,2,95,76,192,8,0,0,0,0,
-	16,0,178,175,33,32,96,2,33,40,128,2,
-	33,48,160,2,122,75,192,12,33,56,32,2,
-	56,0,191,143,52,0,181,143,48,0,180,143,
-	44,0,179,143,40,0,178,143,36,0,177,143,
-	32,0,176,143,8,0,224,3,64,0,189,39,
-	192,255,189,39,56,0,191,175,52,0,181,175,
-	48,0,180,175,44,0,179,175,40,0,178,175,
-	36,0,177,175,32,0,176,175,33,152,128,0,
-	33,160,160,0,33,168,192,0,80,0,177,143,
-	0,0,0,0,36,0,34,142,0,0,0,0,
-	20,0,82,140,2,0,66,144,0,0,0,0,
-	254,255,67,36,70,0,98,44,57,0,64,16,
-	33,128,224,0,128,16,3,0,2,131,1,60,
-	33,8,34,0,184,152,34,140,0,0,0,0,
-	8,0,64,0,0,0,0,0,33,32,0,2,
-	48,72,192,12,33,40,32,2,40,0,35,142,
-	0,0,0,0,16,0,163,175,20,0,176,175,
-	173,76,192,8,24,0,162,175,33,32,0,2,
-	48,72,192,12,33,40,32,2,44,0,35,142,
-	0,0,0,0,16,0,163,175,48,0,35,142,
-	44,0,36,142,0,0,0,0,35,24,100,0,
-	170,76,192,8,255,255,99,48,33,32,0,2,
-	48,72,192,12,33,40,32,2,40,0,35,142,
-	0,0,0,0,16,0,163,175,44,0,35,142,
-	0,0,0,0,171,76,192,8,20,0,163,175,
-	33,32,0,2,48,72,192,12,33,40,32,2,
-	40,0,35,38,16,0,163,175,4,0,3,36,
-	20,0,163,175,24,0,176,175,28,0,162,175,
-	12,0,66,142,33,32,96,2,33,40,128,2,
-	16,0,71,142,0,0,0,0,9,248,64,0,
-	33,48,160,2,184,76,192,8,0,0,0,0,
-	5,0,2,36,96,0,2,174,17,0,34,146,
-	0,0,0,0,2,0,66,52,17,0,34,162,
-	56,0,191,143,52,0,181,143,48,0,180,143,
-	44,0,179,143,40,0,178,143,36,0,177,143,
-	32,0,176,143,8,0,224,3,64,0,189,39,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	224,255,189,39,24,0,191,175,20,0,177,175,
-	16,0,176,175,33,128,128,0,64,0,2,142,
-	0,0,0,0,7,0,64,20,33,136,160,0,
-	2,0,2,36,48,72,192,12,96,0,2,174,
-	1,0,66,36,217,76,192,8,100,0,2,174,
-	129,0,2,36,16,0,34,162,17,0,34,146,
-	0,0,0,0,2,0,66,52,17,0,34,162,
-	24,0,191,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,232,255,189,39,
-	20,0,191,175,16,0,176,175,33,128,128,0,
-	33,64,160,0,33,32,192,0,33,40,224,0,
-	40,0,162,143,17,0,3,145,0,0,0,0,
-	2,0,99,52,17,0,3,161,6,0,3,36,
-	4,0,64,16,16,0,3,161,40,0,4,173,
-	249,76,192,8,44,0,5,173,80,86,192,12,
-	40,0,6,37,2,0,64,16,5,0,2,36,
-	96,0,2,174,20,0,191,143,16,0,176,143,
-	8,0,224,3,24,0,189,39,200,255,189,39,
-	48,0,191,175,44,0,183,175,40,0,182,175,
-	36,0,181,175,32,0,180,175,28,0,179,175,
-	24,0,178,175,20,0,177,175,16,0,176,175,
-	33,176,128,0,33,144,160,0,33,152,192,0,
-	37,0,96,18,33,184,224,0,28,0,84,38,
-	8,0,67,142,28,0,66,142,0,0,0,0,
-	35,128,98,0,42,16,83,0,23,0,64,16,
-	33,168,19,2,9,50,192,12,128,32,21,0,
-	33,136,64,0,8,0,32,22,128,128,16,0,
-	5,0,2,36,96,0,194,174,17,0,66,146,
-	0,0,0,0,2,0,66,52,48,77,192,8,
-	17,0,66,162,33,32,32,2,12,0,69,142,
-	0,0,0,0,80,68,192,12,33,48,0,2,
-	110,86,192,12,8,0,68,38,12,0,81,174,
-	33,128,48,2,4,0,144,174,4,0,132,142,
-	33,40,224,2,80,68,192,12,128,48,19,0,
-	0,0,147,174,8,0,85,174,48,0,191,143,
-	44,0,183,143,40,0,182,143,36,0,181,143,
-	32,0,180,143,28,0,179,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	56,0,189,39,224,255,189,39,24,0,191,175,
-	20,0,177,175,16,0,176,175,33,136,128,0,
-	5,0,192,24,33,128,160,0,3,0,2,36,
-	96,0,34,174,95,77,192,8,100,0,38,174,
-	19,0,195,36,19,0,98,44,9,0,64,16,
-	128,16,3,0,2,131,1,60,33,8,34,0,
-	208,153,34,140,0,0,0,0,8,0,64,0,
-	0,0,0,0,89,77,192,8,2,0,6,36,
-	89,77,192,8,5,0,6,36,89,77,192,8,
-	3,0,6,36,89,77,192,8,1,0,6,36,
-	35,48,6,0,96,0,38,174,33,32,32,2,
-	48,72,192,12,33,40,0,2,1,0,66,36,
-	100,0,34,174,17,0,2,146,0,0,0,0,
-	1,0,66,52,17,0,2,162,24,0,191,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,200,255,189,39,52,0,191,175,
-	48,0,190,175,44,0,183,175,40,0,182,175,
-	36,0,181,175,32,0,180,175,28,0,179,175,
-	24,0,178,175,20,0,177,175,16,0,176,175,
-	33,152,128,0,33,168,160,0,33,160,192,0,
-	76,0,182,143,80,0,183,143,84,0,190,143,
-	92,0,177,143,0,0,0,0,209,83,192,12,
-	33,144,224,0,33,128,64,0,3,0,0,22,
-	4,0,2,36,168,77,192,8,33,16,0,0,
-	88,0,2,166,64,0,19,174,33,32,64,2,
-	72,0,165,143,0,0,0,0,80,86,192,12,
-	92,0,6,38,255,255,3,36,23,0,67,16,
-	0,0,0,0,3,0,194,138,0,0,194,154,
-	0,0,0,0,103,0,2,170,100,0,2,186,
-	104,0,23,174,108,0,30,174,88,0,168,143,
-	0,0,0,0,112,0,8,174,72,0,0,166,
-	76,0,20,174,255,255,162,50,33,16,130,2,
-	80,0,2,174,84,0,0,166,9,0,32,18,
-	120,0,17,174,224,83,192,12,33,32,32,2,
-	6,0,64,20,124,0,2,174,167,83,192,12,
-	33,32,0,2,168,77,192,8,33,16,0,0,
-	124,0,0,174,33,16,0,2,52,0,191,143,
-	48,0,190,143,44,0,183,143,40,0,182,143,
-	36,0,181,143,32,0,180,143,28,0,179,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,56,0,189,39,224,255,189,39,
-	28,0,191,175,24,0,178,175,20,0,177,175,
-	16,0,176,175,33,144,128,0,92,0,68,142,
-	128,86,192,12,0,0,0,0,96,0,68,142,
-	0,0,0,0,128,86,192,12,33,128,64,0,
-	100,0,68,142,0,0,0,0,128,86,192,12,
-	33,136,64,0,33,128,17,2,6,0,16,38,
-	33,16,80,0,90,0,66,166,191,79,192,12,
-	104,0,68,38,255,255,67,48,90,0,68,150,
-	128,0,98,44,5,0,64,20,2,0,130,36,
-	0,1,98,44,2,0,64,20,3,0,130,36,
-	4,0,130,36,33,16,67,0,90,0,66,166,
-	80,0,66,142,76,0,67,142,90,0,80,150,
-	64,0,68,142,0,0,0,0,128,86,192,12,
-	35,136,67,0,255,255,67,48,90,0,68,150,
-	0,0,0,0,128,0,130,44,9,0,64,20,
-	0,1,130,44,4,0,64,16,0,0,0,0,
-	33,24,112,0,237,77,192,8,6,0,99,36,
-	33,24,112,0,237,77,192,8,7,0,99,36,
-	33,24,112,0,5,0,99,36,255,255,36,50,
-	128,0,130,44,5,0,64,20,1,0,130,36,
-	0,1,130,44,2,0,64,20,2,0,130,36,
-	3,0,130,36,33,16,98,0,2,0,66,166,
-	2,0,67,150,2,0,68,150,0,0,0,0,
-	128,0,130,44,6,0,64,20,1,0,99,36,
-	0,1,130,44,4,0,64,20,2,0,98,36,
-	3,78,192,8,3,0,98,36,1,0,98,36,
-	0,0,66,166,0,0,66,150,28,0,191,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,216,255,189,39,
-	32,0,191,175,28,0,179,175,24,0,178,175,
-	20,0,177,175,16,0,176,175,33,152,128,0,
-	171,86,192,12,92,0,100,38,104,0,100,142,
-	0,0,0,0,128,86,192,12,33,144,64,0,
-	108,0,100,142,0,0,0,0,128,86,192,12,
-	33,136,64,0,112,0,100,142,0,0,0,0,
-	153,86,192,12,33,128,64,0,10,0,82,38,
-	33,136,50,2,33,128,17,2,4,0,16,38,
-	33,16,80,0,90,0,98,166,191,79,192,12,
-	116,0,100,38,255,255,67,48,90,0,100,150,
-	128,0,98,44,5,0,64,20,2,0,130,36,
-	0,1,98,44,2,0,64,20,3,0,130,36,
-	4,0,130,36,33,16,67,0,90,0,98,166,
-	80,0,98,142,76,0,99,142,90,0,113,150,
-	64,0,100,142,0,0,0,0,128,86,192,12,
-	35,128,67,0,255,255,67,48,90,0,100,150,
-	0,0,0,0,128,0,130,44,9,0,64,20,
-	0,1,130,44,4,0,64,16,0,0,0,0,
-	33,24,113,0,74,78,192,8,6,0,99,36,
-	33,24,113,0,74,78,192,8,7,0,99,36,
-	33,24,113,0,5,0,99,36,255,255,4,50,
-	128,0,130,44,5,0,64,20,1,0,130,36,
-	0,1,130,44,2,0,64,20,2,0,130,36,
-	3,0,130,36,33,16,98,0,2,0,98,166,
-	2,0,99,150,2,0,100,150,0,0,0,0,
-	128,0,130,44,6,0,64,20,1,0,99,36,
-	0,1,130,44,4,0,64,20,2,0,112,36,
-	96,78,192,8,3,0,112,36,1,0,112,36,
-	255,255,2,50,32,0,191,143,28,0,179,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,40,0,189,39,208,255,189,39,
-	40,0,191,175,36,0,179,175,32,0,178,175,
-	28,0,177,175,24,0,176,175,33,128,128,0,
-	33,152,192,0,33,144,224,0,33,136,160,0,
-	16,0,4,36,32,0,5,36,1,131,6,60,
-	56,97,198,36,242,86,192,12,33,56,0,2,
-	255,255,36,50,1,131,5,60,56,97,165,36,
-	44,87,192,12,33,48,0,2,16,0,176,175,
-	2,0,4,36,33,40,0,0,1,131,7,60,
-	56,97,231,36,94,87,192,12,33,48,96,2,
-	8,0,71,142,4,0,66,142,0,0,0,0,
-	35,56,226,0,1,131,2,60,56,97,66,36,
-	16,0,162,175,20,0,176,175,4,0,4,36,
-	33,40,0,0,4,0,70,142,0,0,0,0,
-	194,87,192,12,255,255,231,48,40,0,191,143,
-	36,0,179,143,32,0,178,143,28,0,177,143,
-	24,0,176,143,8,0,224,3,48,0,189,39,
-	216,255,189,39,36,0,191,175,32,0,178,175,
-	28,0,177,175,24,0,176,175,33,128,128,0,
-	33,136,160,0,88,0,4,150,160,0,5,36,
-	1,131,6,60,56,97,198,36,242,86,192,12,
-	33,56,32,2,90,0,4,150,1,131,5,60,
-	56,97,165,36,44,87,192,12,33,48,32,2,
-	16,0,177,175,6,0,4,36,33,40,0,0,
-	1,131,7,60,56,97,231,36,15,88,192,12,
-	92,0,6,38,1,131,18,60,56,97,82,38,
-	16,0,178,175,20,0,177,175,33,32,0,0,
-	64,0,5,36,100,0,6,38,194,87,192,12,
-	4,0,7,36,16,0,177,175,2,0,4,36,
-	33,40,0,0,104,0,6,142,0,0,0,0,
-	94,87,192,12,33,56,64,2,16,0,177,175,
-	2,0,4,36,33,40,0,0,108,0,6,142,
-	0,0,0,0,94,87,192,12,33,56,64,2,
-	16,0,177,175,3,0,4,36,64,0,5,36,
-	112,0,6,142,0,0,0,0,143,87,192,12,
-	33,56,64,2,116,0,4,38,7,79,192,12,
-	33,40,32,2,36,0,191,143,32,0,178,143,
-	28,0,177,143,24,0,176,143,8,0,224,3,
-	40,0,189,39,216,255,189,39,32,0,191,175,
-	28,0,177,175,24,0,176,175,33,128,128,0,
-	33,136,160,0,88,0,4,150,160,0,5,36,
-	1,131,6,60,56,97,198,36,242,86,192,12,
-	33,56,32,2,90,0,4,150,1,131,5,60,
-	56,97,165,36,44,87,192,12,33,48,32,2,
-	16,0,177,175,2,0,4,36,92,0,6,142,
-	1,131,7,60,56,97,231,36,94,87,192,12,
-	33,40,0,0,16,0,177,175,2,0,4,36,
-	96,0,6,142,1,131,7,60,56,97,231,36,
-	94,87,192,12,33,40,0,0,16,0,177,175,
-	2,0,4,36,100,0,6,142,1,131,7,60,
-	56,97,231,36,94,87,192,12,33,40,0,0,
-	104,0,4,38,7,79,192,12,33,40,32,2,
-	32,0,191,143,28,0,177,143,24,0,176,143,
-	8,0,224,3,40,0,189,39,200,255,189,39,
-	52,0,191,175,48,0,180,175,44,0,179,175,
-	40,0,178,175,36,0,177,175,32,0,176,175,
-	33,144,128,0,33,136,160,0,16,0,4,36,
-	32,0,5,36,1,131,6,60,56,97,198,36,
-	242,86,192,12,33,56,32,2,0,0,68,150,
-	1,131,5,60,56,97,165,36,44,87,192,12,
-	33,48,32,2,155,0,64,18,0,0,0,0,
-	1,131,20,60,56,97,148,38,8,0,80,142,
-	0,0,0,0,145,0,0,18,0,0,0,0,
-	4,0,66,142,0,0,0,0,141,0,64,24,
-	33,152,0,0,16,0,4,36,32,0,5,36,
-	33,48,128,2,242,86,192,12,33,56,32,2,
-	4,0,4,150,33,40,128,2,44,87,192,12,
-	33,48,32,2,16,0,177,175,6,0,4,36,
-	33,40,0,0,8,0,6,38,15,88,192,12,
-	33,56,128,2,16,0,3,146,65,0,2,36,
-	47,0,98,16,66,0,98,40,18,0,64,16,
-	5,0,2,36,88,0,98,16,6,0,98,40,
-	7,0,64,16,2,0,2,36,30,0,98,16,
-	4,0,2,36,51,0,98,16,4,0,4,36,
-	174,79,192,8,1,0,115,38,6,0,2,36,
-	68,0,98,16,64,0,2,36,78,0,98,16,
-	33,32,0,0,174,79,192,8,1,0,115,38,
-	68,0,2,36,47,0,98,16,69,0,98,40,
-	7,0,64,16,66,0,2,36,24,0,98,16,
-	67,0,2,36,25,0,98,16,3,0,4,36,
-	174,79,192,8,1,0,115,38,131,0,98,40,
-	83,0,64,16,128,0,98,40,68,0,64,16,
-	0,0,0,0,174,79,192,8,1,0,115,38,
-	16,0,177,175,2,0,4,36,40,0,6,142,
-	1,131,7,60,56,97,231,36,94,87,192,12,
-	33,40,0,0,174,79,192,8,1,0,115,38,
-	16,0,177,175,111,79,192,8,1,0,4,36,
-	16,0,177,175,111,79,192,8,2,0,4,36,
-	16,0,177,175,40,0,6,142,1,131,7,60,
-	56,97,231,36,143,87,192,12,64,0,5,36,
-	174,79,192,8,1,0,115,38,48,0,7,142,
-	44,0,2,142,0,0,0,0,35,56,226,0,
-	16,0,180,175,20,0,177,175,134,79,192,8,
-	33,40,0,0,48,0,7,142,44,0,2,142,
-	0,0,0,0,35,56,226,0,16,0,180,175,
-	20,0,177,175,4,0,4,36,64,0,5,36,
-	44,0,6,142,0,0,0,0,194,87,192,12,
-	255,255,231,48,174,79,192,8,1,0,115,38,
-	16,0,177,175,6,0,4,36,33,40,0,0,
-	1,131,7,60,56,97,231,36,15,88,192,12,
-	40,0,6,38,174,79,192,8,1,0,115,38,
-	5,0,4,36,164,79,192,8,33,40,0,0,
-	16,0,180,175,20,0,177,175,64,0,5,36,
-	40,0,6,38,194,87,192,12,4,0,7,36,
-	174,79,192,8,1,0,115,38,16,0,4,146,
-	16,0,5,146,31,0,132,48,224,0,165,48,
-	1,131,6,60,56,97,198,36,242,86,192,12,
-	33,56,32,2,33,32,0,0,1,131,5,60,
-	56,97,165,36,44,87,192,12,33,48,32,2,
-	1,0,115,38,4,0,66,142,0,0,0,0,
-	42,16,98,2,117,255,64,20,68,0,16,38,
-	12,0,82,142,0,0,0,0,105,255,64,22,
-	0,0,0,0,52,0,191,143,48,0,180,143,
-	44,0,179,143,40,0,178,143,36,0,177,143,
-	32,0,176,143,8,0,224,3,56,0,189,39,
-	200,255,189,39,52,0,191,175,48,0,182,175,
-	44,0,181,175,40,0,180,175,36,0,179,175,
-	32,0,178,175,28,0,177,175,24,0,176,175,
-	33,168,128,0,33,152,160,2,113,0,160,18,
-	33,144,0,0,4,0,22,36,8,0,112,142,
-	0,0,0,0,104,0,0,18,0,0,0,0,
-	4,0,98,142,0,0,0,0,100,0,64,24,
-	33,160,0,0,171,86,192,12,8,0,4,38,
-	255,255,67,48,128,0,98,44,5,0,64,20,
-	2,0,113,36,0,1,98,44,2,0,64,20,
-	3,0,113,36,4,0,113,36,16,0,3,146,
-	64,0,2,36,50,0,98,16,65,0,98,40,
-	16,0,64,16,68,0,2,36,34,0,118,16,
-	5,0,98,40,5,0,64,16,2,0,2,36,
-	20,0,98,16,255,255,36,50,22,80,192,8,
-	0,0,0,0,5,0,2,36,35,0,98,16,
-	6,0,2,36,29,0,98,16,255,255,36,50,
-	22,80,192,8,0,0,0,0,19,0,98,16,
-	68,0,98,40,12,0,64,20,131,0,98,40,
-	28,0,64,16,128,0,98,40,27,0,64,20,
-	255,255,36,50,22,80,192,8,18,0,0,166,
-	40,0,4,142,128,86,192,12,0,0,0,0,
-	21,80,192,8,18,0,2,166,40,0,4,142,
-	153,86,192,12,0,0,0,0,21,80,192,8,
-	18,0,2,166,48,0,2,142,44,0,3,142,
-	0,0,0,0,35,16,67,0,21,80,192,8,
-	18,0,2,166,171,86,192,12,40,0,4,38,
-	21,80,192,8,18,0,2,166,21,80,192,8,
-	18,0,0,166,18,0,22,166,255,255,36,50,
-	18,0,3,150,0,0,0,0,128,0,98,44,
-	6,0,64,20,1,0,132,36,0,1,98,44,
-	4,0,64,20,2,0,98,36,33,80,192,8,
-	3,0,98,36,1,0,98,36,33,16,130,0,
-	4,0,2,166,4,0,4,150,0,0,0,0,
-	1,0,132,36,4,0,3,150,0,0,0,0,
-	128,0,98,44,6,0,64,20,255,255,69,50,
-	0,1,98,44,4,0,64,20,2,0,162,36,
-	49,80,192,8,3,0,162,36,1,0,162,36,
-	33,144,68,0,1,0,148,38,4,0,98,142,
-	0,0,0,0,42,16,130,2,158,255,64,20,
-	68,0,16,38,12,0,115,142,0,0,0,0,
-	146,255,96,22,0,0,0,0,0,0,178,166,
-	255,255,66,50,52,0,191,143,48,0,182,143,
-	44,0,181,143,40,0,180,143,36,0,179,143,
-	32,0,178,143,28,0,177,143,24,0,176,143,
-	8,0,224,3,56,0,189,39,224,255,189,39,
-	24,0,191,175,20,0,177,175,16,0,176,175,
-	33,128,128,0,171,86,192,12,8,0,4,38,
-	255,255,67,48,128,0,98,44,5,0,64,20,
-	2,0,113,36,0,1,98,44,2,0,64,20,
-	3,0,113,36,4,0,113,36,16,0,3,146,
-	64,0,2,36,52,0,98,16,65,0,98,40,
-	17,0,64,16,4,0,2,36,37,0,98,16,
-	0,0,0,0,5,0,98,40,5,0,64,16,
-	2,0,2,36,22,0,98,16,255,255,36,50,
-	145,80,192,8,0,0,0,0,5,0,2,36,
-	36,0,98,16,6,0,2,36,30,0,98,16,
-	255,255,36,50,145,80,192,8,0,0,0,0,
-	68,0,2,36,20,0,98,16,0,0,0,0,
-	68,0,98,40,12,0,64,20,131,0,98,40,
-	28,0,64,16,128,0,98,40,27,0,64,20,
-	255,255,36,50,145,80,192,8,18,0,0,166,
-	40,0,4,142,128,86,192,12,0,0,0,0,
-	144,80,192,8,18,0,2,166,40,0,4,142,
-	153,86,192,12,0,0,0,0,144,80,192,8,
-	18,0,2,166,48,0,2,142,44,0,3,142,
-	0,0,0,0,143,80,192,8,35,16,67,0,
-	171,86,192,12,40,0,4,38,144,80,192,8,
-	18,0,2,166,144,80,192,8,18,0,0,166,
-	4,0,2,36,18,0,2,166,255,255,36,50,
-	18,0,3,150,0,0,0,0,128,0,98,44,
-	6,0,64,20,1,0,132,36,0,1,98,44,
-	4,0,64,20,2,0,98,36,156,80,192,8,
-	3,0,98,36,1,0,98,36,33,16,130,0,
-	4,0,2,166,4,0,3,150,4,0,4,150,
-	0,0,0,0,128,0,130,44,6,0,64,20,
-	1,0,99,36,0,1,130,44,4,0,64,20,
-	2,0,98,36,170,80,192,8,3,0,98,36,
-	1,0,98,36,255,255,66,48,24,0,191,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,232,255,189,39,16,0,191,175,
-	64,0,130,140,0,0,0,0,12,0,64,20,
-	33,16,0,0,88,0,131,148,4,0,2,36,
-	5,0,98,16,0,0,0,0,180,77,192,12,
-	0,0,0,0,193,80,192,8,255,255,66,48,
-	11,78,192,12,0,0,0,0,255,255,66,48,
-	16,0,191,143,24,0,189,39,8,0,224,3,
-	0,0,0,0,224,255,189,39,24,0,191,175,
-	20,0,177,175,16,0,176,175,33,128,128,0,
-	176,80,192,12,33,136,160,0,33,32,0,2,
-	33,40,32,2,213,80,192,12,255,255,70,48,
-	24,0,191,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,224,255,189,39,
-	28,0,191,175,24,0,178,175,20,0,177,175,
-	16,0,176,175,33,144,128,0,33,136,192,0,
-	255,255,34,50,41,0,64,16,33,128,160,0,
-	4,0,2,142,0,0,0,0,11,0,64,20,
-	255,255,35,50,9,50,192,12,255,255,36,50,
-	33,24,64,0,32,0,96,16,1,0,2,36,
-	0,0,2,166,4,0,3,174,8,0,3,174,
-	242,80,192,8,12,0,17,166,12,0,2,150,
-	0,0,0,0,43,16,67,0,23,0,64,20,
-	255,255,2,36,64,0,66,142,0,0,0,0,
-	19,0,64,20,255,255,2,36,33,32,0,2,
-	2,0,69,150,33,48,0,0,104,78,192,12,
-	72,0,71,38,88,0,67,150,4,0,2,36,
-	5,0,98,16,33,32,64,2,217,78,192,12,
-	33,40,0,2,8,81,192,8,33,16,0,0,
-	153,78,192,12,33,40,0,2,8,81,192,8,
-	33,16,0,0,255,255,2,36,28,0,191,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,0,0,0,0,
-	0,0,0,0,168,255,189,39,80,0,191,175,
-	76,0,183,175,72,0,182,175,68,0,181,175,
-	64,0,180,175,60,0,179,175,56,0,178,175,
-	52,0,177,175,48,0,176,175,33,24,128,0,
-	33,152,160,0,33,176,192,0,33,184,224,0,
-	104,0,162,143,0,0,0,0,2,0,64,20,
-	44,0,160,175,40,0,162,39,0,0,64,172,
-	24,0,164,39,33,40,96,0,156,88,192,12,
-	33,48,96,2,33,136,64,0,82,0,32,18,
-	33,16,0,0,209,83,192,12,0,0,0,0,
-	33,144,64,0,5,0,64,22,1,0,2,36,
-	183,88,192,12,33,32,32,2,124,81,192,8,
-	33,16,0,0,148,0,66,162,196,88,192,12,
-	33,32,32,2,224,0,85,48,44,0,176,39,
-	33,32,32,2,124,89,192,12,33,40,0,2,
-	33,160,64,0,33,32,32,2,198,89,192,12,
-	33,40,0,2,2,0,66,166,44,0,162,143,
-	0,0,0,0,14,0,64,20,0,0,0,0,
-	8,0,35,142,4,0,34,142,0,0,0,0,
-	35,128,98,0,2,0,66,150,0,0,0,0,
-	33,128,2,2,42,16,19,2,16,0,64,20,
-	33,32,32,2,42,16,112,2,16,0,64,16,
-	0,0,0,0,167,83,192,12,33,32,64,2,
-	183,88,192,12,33,32,32,2,3,131,3,60,
-	140,17,99,36,0,0,98,140,0,0,0,0,
-	1,0,66,36,0,0,98,172,124,81,192,8,
-	33,16,0,0,33,40,0,2,42,89,192,12,
-	33,48,0,0,255,0,162,50,255,255,131,50,
-	37,16,67,0,48,0,3,36,8,0,67,20,
-	33,32,64,2,16,0,176,175,33,40,32,2,
-	33,48,192,2,135,81,192,12,33,56,224,2,
-	117,81,192,8,33,128,64,0,3,131,3,60,
-	140,17,99,36,0,0,98,140,0,0,0,0,
-	1,0,66,36,0,0,98,172,33,128,0,0,
-	3,0,0,22,0,0,0,0,167,83,192,12,
-	33,32,64,2,183,88,192,12,33,32,32,2,
-	33,16,0,2,80,0,191,143,76,0,183,143,
-	72,0,182,143,68,0,181,143,64,0,180,143,
-	60,0,179,143,56,0,178,143,52,0,177,143,
-	48,0,176,143,8,0,224,3,88,0,189,39,
-	176,255,189,39,76,0,191,175,72,0,182,175,
-	68,0,181,175,64,0,180,175,60,0,179,175,
-	56,0,178,175,52,0,177,175,48,0,176,175,
-	33,128,128,0,33,136,160,0,33,160,192,0,
-	33,168,224,0,96,0,182,143,24,0,160,175,
-	33,32,32,2,24,0,165,39,2,0,6,36,
-	239,90,192,12,33,56,0,0,64,0,2,174,
-	24,0,162,143,0,0,0,0,155,0,64,20,
-	0,0,0,0,64,0,2,142,0,0,0,0,
-	4,0,64,16,33,32,32,2,3,131,3,60,
-	60,82,192,8,148,17,99,36,16,0,160,175,
-	72,0,5,38,24,0,166,39,110,90,192,12,
-	4,0,7,36,24,0,162,143,0,0,0,0,
-	139,0,64,20,0,0,0,0,196,88,192,12,
-	33,32,32,2,224,0,66,48,160,0,3,36,
-	133,0,67,20,33,32,32,2,124,89,192,12,
-	24,0,165,39,33,144,64,0,33,32,32,2,
-	198,89,192,12,24,0,165,39,33,152,64,0,
-	24,0,162,143,0,0,0,0,122,0,64,20,
-	0,0,0,0,255,255,66,50,5,0,66,44,
-	118,0,64,16,0,0,0,0,8,0,34,142,
-	4,0,35,142,0,0,0,0,35,16,67,0,
-	255,255,99,50,33,16,67,0,110,0,194,22,
-	33,32,0,2,88,0,18,166,90,0,19,166,
-	33,40,128,2,178,50,192,12,33,48,160,2,
-	118,0,64,20,33,16,0,0,255,255,67,50,
-	4,0,2,36,24,0,98,16,33,32,32,2,
-	24,0,165,39,2,0,6,36,239,90,192,12,
-	33,56,0,0,92,0,2,174,33,32,32,2,
-	24,0,165,39,2,0,6,36,239,90,192,12,
-	33,56,0,0,96,0,2,174,33,32,32,2,
-	24,0,165,39,2,0,6,36,239,90,192,12,
-	33,56,0,0,100,0,2,174,24,0,162,143,
-	0,0,0,0,78,0,64,20,33,32,32,2,
-	67,82,192,8,104,0,5,38,4,0,2,36,
-	88,0,2,166,90,0,19,166,124,0,0,174,
-	16,0,160,175,92,0,5,38,24,0,166,39,
-	186,91,192,12,6,0,7,36,24,0,162,143,
-	0,0,0,0,63,0,64,20,100,0,4,38,
-	33,40,0,0,144,71,192,12,4,0,6,36,
-	32,0,160,167,40,0,160,175,36,0,160,175,
-	44,0,160,167,32,0,178,39,64,0,2,36,
-	16,0,162,175,33,32,32,2,33,40,64,2,
-	24,0,166,39,110,90,192,12,33,56,0,0,
-	24,0,162,143,0,0,0,0,5,0,64,16,
-	0,0,0,0,24,92,192,12,33,32,64,2,
-	58,82,192,8,0,0,0,0,40,0,162,143,
-	36,0,163,143,0,0,0,0,35,16,67,0,
-	255,255,70,48,5,0,194,44,2,0,64,20,
-	0,0,0,0,4,0,6,36,8,0,192,16,
-	33,32,32,2,36,0,165,143,0,0,0,0,
-	80,68,192,12,100,0,4,38,24,92,192,12,
-	32,0,164,39,33,32,32,2,24,0,165,39,
-	2,0,6,36,239,90,192,12,33,56,0,0,
-	104,0,2,174,33,32,32,2,24,0,165,39,
-	2,0,6,36,239,90,192,12,33,56,0,0,
-	108,0,2,174,33,32,32,2,24,0,165,39,
-	3,0,6,36,239,90,192,12,64,0,7,36,
-	112,0,2,174,24,0,162,143,0,0,0,0,
-	9,0,64,16,33,32,32,2,3,131,3,60,
-	140,17,99,36,0,0,98,140,0,0,0,0,
-	1,0,66,36,0,0,98,172,73,82,192,8,
-	33,16,0,0,116,0,5,38,33,48,192,2,
-	163,82,192,12,33,56,0,2,255,255,3,36,
-	248,255,67,16,33,16,0,2,76,0,191,143,
-	72,0,182,143,68,0,181,143,64,0,180,143,
-	60,0,179,143,56,0,178,143,52,0,177,143,
-	48,0,176,143,8,0,224,3,80,0,189,39,
-	184,255,189,39,64,0,191,175,60,0,183,175,
-	56,0,182,175,52,0,181,175,48,0,180,175,
-	44,0,179,175,40,0,178,175,36,0,177,175,
-	32,0,176,175,33,128,128,0,16,0,160,175,
-	8,0,2,142,4,0,3,142,0,0,0,0,
-	35,184,67,0,33,144,0,0,255,255,162,48,
-	45,0,64,16,33,136,0,0,3,131,19,60,
-	140,17,115,38,255,255,22,36,255,255,181,48,
-	8,0,3,142,4,0,2,142,0,0,0,0,
-	35,160,98,0,0,0,2,146,0,0,0,0,
-	128,0,66,48,32,0,64,20,33,32,0,2,
-	124,89,192,12,16,0,165,39,33,32,0,2,
-	198,89,192,12,16,0,165,39,33,40,64,0,
-	16,0,162,143,0,0,0,0,6,0,64,20,
-	33,32,0,2,255,255,165,48,251,88,192,12,
-	1,0,6,36,7,0,86,20,0,0,0,0,
-	0,0,98,142,0,0,0,0,1,0,66,36,
-	0,0,98,174,147,82,192,8,255,255,17,36,
-	8,0,2,142,4,0,3,142,0,0,0,0,
-	35,16,67,0,33,16,66,2,35,144,84,0,
-	255,255,66,50,43,16,85,0,217,255,64,20,
-	1,0,49,38,33,32,0,2,33,40,224,2,
-	251,88,192,12,33,48,0,0,33,16,32,2,
-	64,0,191,143,60,0,183,143,56,0,182,143,
-	52,0,181,143,48,0,180,143,44,0,179,143,
-	40,0,178,143,36,0,177,143,32,0,176,143,
-	8,0,224,3,72,0,189,39,192,255,189,39,
-	56,0,191,175,52,0,181,175,48,0,180,175,
-	44,0,179,175,40,0,178,175,36,0,177,175,
-	32,0,176,175,33,144,128,0,33,152,160,0,
-	33,168,224,0,16,0,160,175,124,89,192,12,
-	16,0,165,39,33,32,64,2,198,89,192,12,
-	16,0,165,39,0,0,98,166,16,0,162,143,
-	0,0,0,0,28,0,64,20,0,0,0,0,
-	12,0,66,142,8,0,67,142,0,0,0,0,
-	35,16,67,0,0,0,99,150,255,255,66,48,
-	20,0,98,20,0,0,0,0,4,0,96,174,
-	0,0,101,150,0,0,0,0,83,82,192,12,
-	33,32,64,2,33,32,64,0,255,255,2,36,
-	46,0,130,16,0,0,0,0,3,0,128,20,
-	0,0,0,0,246,82,192,8,8,0,96,174,
-	224,83,192,12,4,0,100,174,10,0,64,20,
-	8,0,98,174,247,82,192,8,255,255,2,36,
-	3,131,3,60,140,17,99,36,0,0,98,140,
-	0,0,0,0,1,0,66,36,210,82,192,8,
-	0,0,98,172,8,0,112,142,4,0,98,142,
-	0,0,0,0,23,0,64,24,33,136,0,0,
-	255,255,20,36,33,32,64,2,124,89,192,12,
-	16,0,165,39,33,32,64,2,198,89,192,12,
-	16,0,165,39,4,0,2,166,16,0,162,143,
-	0,0,0,0,233,255,64,20,33,32,64,2,
-	33,40,0,2,0,83,192,12,33,48,160,2,
-	226,255,84,16,1,0,49,38,4,0,98,142,
-	0,0,0,0,42,16,34,2,236,255,64,20,
-	68,0,16,38,33,16,0,0,56,0,191,143,
-	52,0,181,143,48,0,180,143,44,0,179,143,
-	40,0,178,143,36,0,177,143,32,0,176,143,
-	8,0,224,3,64,0,189,39,184,255,189,39,
-	68,0,191,175,64,0,180,175,60,0,179,175,
-	56,0,178,175,52,0,177,175,48,0,176,175,
-	33,128,128,0,33,144,160,0,24,0,160,175,
-	16,0,160,175,8,0,69,38,24,0,166,39,
-	186,91,192,12,6,0,7,36,24,0,162,143,
-	0,0,0,0,103,0,64,20,0,0,0,0,
-	196,88,192,12,33,32,0,2,224,0,84,48,
-	33,32,0,2,124,89,192,12,24,0,165,39,
-	33,152,64,0,33,32,0,2,198,89,192,12,
-	24,0,165,39,33,136,64,0,24,0,162,143,
-	0,0,0,0,88,0,64,20,37,16,116,2,
-	18,0,81,166,16,0,66,162,16,0,67,146,
-	64,0,2,36,48,0,98,16,65,0,98,40,
-	16,0,64,16,4,0,2,36,31,0,98,16,
-	5,0,98,40,5,0,64,16,2,0,2,36,
-	22,0,98,16,33,32,0,2,121,83,192,8,
-	0,0,0,0,5,0,2,36,65,0,98,16,
-	6,0,2,36,27,0,98,16,33,32,0,2,
-	121,83,192,8,0,0,0,0,68,0,2,36,
-	15,0,98,16,68,0,98,40,8,0,64,20,
-	33,32,0,2,131,0,98,40,57,0,64,16,
-	128,0,98,40,51,0,64,16,0,0,0,0,
-	121,83,192,8,0,0,0,0,255,255,37,50,
-	164,90,192,12,24,0,166,39,117,83,192,8,
-	40,0,66,174,33,32,0,2,255,255,37,50,
-	40,0,70,38,19,90,192,12,24,0,167,39,
-	117,83,192,8,0,0,0,0,255,255,37,50,
-	40,0,70,38,24,91,192,12,24,0,167,39,
-	117,83,192,8,0,0,0,0,40,0,68,38,
-	33,40,0,0,144,71,192,12,4,0,6,36,
-	32,0,160,167,40,0,160,175,36,0,160,175,
-	44,0,160,167,33,32,0,2,255,255,37,50,
-	32,0,166,39,19,90,192,12,24,0,167,39,
-	40,0,162,143,36,0,163,143,0,0,0,0,
-	35,16,67,0,255,255,70,48,5,0,194,44,
-	2,0,64,20,0,0,0,0,4,0,6,36,
-	7,0,192,16,0,0,0,0,36,0,165,143,
-	0,0,0,0,80,68,192,12,40,0,68,38,
-	24,92,192,12,32,0,164,39,24,0,162,143,
-	0,0,0,0,8,0,64,16,33,16,0,0,
-	3,131,3,60,140,17,99,36,0,0,98,140,
-	0,0,0,0,1,0,66,36,0,0,98,172,
-	255,255,2,36,68,0,191,143,64,0,180,143,
-	60,0,179,143,56,0,178,143,52,0,177,143,
-	48,0,176,143,8,0,224,3,72,0,189,39,
-	232,255,189,39,20,0,191,175,16,0,176,175,
-	33,128,128,0,76,0,2,142,0,0,0,0,
-	3,0,64,16,0,0,0,0,24,92,192,12,
-	72,0,4,38,88,0,3,150,4,0,2,36,
-	5,0,98,20,0,0,0,0,110,86,192,12,
-	92,0,4,38,157,83,192,8,116,0,4,38,
-	13,84,192,12,104,0,4,38,120,0,4,38,
-	13,84,192,12,0,0,0,0,148,0,3,146,
-	0,0,0,0,248,83,192,12,33,32,0,2,
-	20,0,191,143,16,0,176,143,8,0,224,3,
-	24,0,189,39,232,255,189,39,20,0,191,175,
-	16,0,176,175,33,128,128,0,5,0,0,18,
-	0,0,0,0,136,83,192,12,0,0,0,0,
-	61,50,192,12,33,32,0,2,20,0,191,143,
-	16,0,176,143,8,0,224,3,24,0,189,39,
-	224,255,189,39,24,0,191,175,20,0,177,175,
-	16,0,176,175,33,136,128,0,9,50,192,12,
-	16,0,4,36,33,128,64,0,11,0,0,18,
-	33,32,0,2,33,40,0,0,144,71,192,12,
-	16,0,6,36,224,83,192,12,33,32,32,2,
-	4,0,64,16,8,0,2,174,4,0,17,174,
-	204,83,192,8,33,16,0,2,61,50,192,12,
-	33,32,0,2,33,16,0,0,24,0,191,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,232,255,189,39,20,0,191,175,
-	16,0,176,175,9,50,192,12,152,0,4,36,
-	33,128,64,0,4,0,0,18,33,16,0,0,
-	248,83,192,12,33,32,0,2,33,16,0,2,
-	20,0,191,143,16,0,176,143,8,0,224,3,
-	24,0,189,39,224,255,189,39,24,0,191,175,
-	20,0,177,175,0,17,4,0,33,16,68,0,
-	128,136,2,0,11,0,32,18,16,0,176,175,
-	9,50,192,12,33,32,32,2,33,128,64,0,
-	4,0,0,18,33,32,0,2,33,40,0,0,
-	144,71,192,12,33,48,32,2,243,83,192,8,
-	33,16,0,2,33,16,0,0,24,0,191,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,232,255,189,39,20,0,191,175,
-	16,0,176,175,33,128,128,0,33,40,0,0,
-	144,71,192,12,152,0,6,36,255,0,2,36,
-	88,0,2,166,120,5,2,36,58,0,2,166,
-	72,0,0,166,80,0,0,174,76,0,0,174,
-	84,0,0,166,148,0,0,162,149,0,0,162,
-	20,0,191,143,16,0,176,143,8,0,224,3,
-	24,0,189,39,208,255,189,39,40,0,191,175,
-	36,0,179,175,32,0,178,175,28,0,177,175,
-	24,0,176,175,33,128,128,0,31,0,0,18,
-	1,0,19,36,8,0,18,142,0,0,0,0,
-	16,0,64,18,0,0,0,0,4,0,2,142,
-	0,0,0,0,9,0,64,24,33,136,0,0,
-	59,84,192,12,33,32,64,2,1,0,49,38,
-	4,0,2,142,0,0,0,0,42,16,34,2,
-	249,255,64,20,68,0,82,38,8,0,4,142,
-	61,50,192,12,0,0,0,0,12,0,17,142,
-	4,0,96,18,0,0,0,0,33,152,0,0,
-	49,84,192,8,4,0,0,174,61,50,192,12,
-	33,32,0,2,33,128,32,2,227,255,0,22,
-	0,0,0,0,40,0,191,143,36,0,179,143,
-	32,0,178,143,28,0,177,143,24,0,176,143,
-	8,0,224,3,48,0,189,39,232,255,189,39,
-	20,0,191,175,16,0,176,175,33,128,128,0,
-	60,0,2,142,0,0,0,0,4,0,64,16,
-	0,0,0,0,9,248,64,0,0,0,0,0,
-	60,0,0,174,110,86,192,12,8,0,4,38,
-	78,84,192,12,33,32,0,2,20,0,191,143,
-	16,0,176,143,8,0,224,3,24,0,189,39,
-	232,255,189,39,16,0,191,175,16,0,131,144,
-	6,0,2,36,18,0,98,16,7,0,98,40,
-	5,0,64,16,4,0,2,36,6,0,98,16,
-	0,0,0,0,103,84,192,8,0,0,0,0,
-	68,0,2,36,11,0,98,20,0,0,0,0,
-	44,0,130,140,0,0,0,0,7,0,64,16,
-	0,0,0,0,24,92,192,12,40,0,132,36,
-	103,84,192,8,0,0,0,0,110,86,192,12,
-	40,0,132,36,16,0,191,143,24,0,189,39,
-	8,0,224,3,0,0,0,0,0,0,0,0,
-	216,255,189,39,32,0,191,175,28,0,179,175,
-	24,0,178,175,20,0,177,175,16,0,176,175,
-	33,136,192,0,56,0,179,143,0,0,0,0,
-	20,72,192,12,33,144,224,0,33,128,64,0,
-	11,0,0,18,33,32,32,2,33,40,64,2,
-	80,86,192,12,8,0,6,38,255,255,3,36,
-	5,0,67,16,2,0,2,36,16,0,2,162,
-	40,0,19,174,133,84,192,8,33,16,0,0,
-	255,255,2,36,32,0,191,143,28,0,179,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,40,0,189,39,216,255,189,39,
-	32,0,191,175,28,0,177,175,24,0,176,175,
-	33,128,128,0,96,0,5,174,100,0,6,174,
-	128,0,2,142,0,0,0,0,11,0,64,16,
-	0,0,0,0,13,84,192,12,104,0,4,38,
-	124,0,2,142,0,0,0,0,108,0,2,174,
-	128,0,2,142,0,0,0,0,112,0,2,174,
-	128,0,0,174,124,0,0,174,88,0,17,150,
-	2,0,2,36,88,0,2,166,176,80,192,12,
-	33,32,0,2,33,56,64,0,64,0,2,142,
-	0,0,0,0,35,0,64,20,255,255,35,50,
-	3,0,2,36,14,0,98,16,255,255,227,48,
-	58,0,2,150,0,0,0,0,43,16,67,0,
-	9,0,64,16,12,0,4,38,48,0,2,142,
-	28,0,5,38,52,0,7,142,0,0,0,0,
-	9,248,64,0,1,0,6,36,214,84,192,8,
-	0,0,0,0,96,0,2,142,0,0,0,0,
-	250,255,67,36,13,0,98,44,13,0,64,16,
-	128,16,3,0,2,131,1,60,33,8,34,0,
-	32,154,34,140,0,0,0,0,8,0,64,0,
-	0,0,0,0,204,84,192,8,2,0,2,36,
-	204,84,192,8,3,0,2,36,5,0,2,36,
-	96,0,2,174,52,0,2,142,0,0,0,0,
-	16,0,162,175,44,0,2,142,12,0,4,38,
-	28,0,5,38,33,48,0,2,9,248,64,0,
-	255,255,231,48,32,0,191,143,28,0,177,143,
-	24,0,176,143,8,0,224,3,40,0,189,39,
-	224,255,189,39,28,0,191,175,24,0,176,175,
-	33,128,128,0,96,0,5,142,0,0,0,0,
-	6,0,160,16,0,0,0,0,100,0,6,142,
-	140,84,192,12,0,0,0,0,56,85,192,8,
-	0,0,0,0,176,80,192,12,33,32,0,2,
-	33,56,64,0,88,0,2,150,0,0,0,0,
-	2,0,66,44,11,0,64,16,255,255,227,48,
-	58,0,2,150,0,0,0,0,43,16,67,0,
-	6,0,64,16,33,32,0,2,1,0,5,36,
-	140,84,192,12,33,48,0,0,56,85,192,8,
-	0,0,0,0,96,0,2,142,0,0,0,0,
-	49,0,64,20,2,0,2,36,88,0,3,150,
-	3,0,2,36,33,0,98,16,4,0,98,40,
-	7,0,64,16,2,0,98,40,41,0,64,16,
-	2,0,2,36,39,0,96,4,0,0,0,0,
-	13,85,192,8,0,0,0,0,5,0,2,36,
-	34,0,98,20,2,0,2,36,3,131,3,60,
-	236,17,99,36,0,0,98,140,0,0,0,0,
-	1,0,66,36,104,0,4,38,25,0,128,16,
-	0,0,98,172,3,131,5,60,176,17,165,36,
-	0,0,162,140,108,0,3,142,0,0,0,0,
-	33,16,67,0,0,0,162,172,12,0,132,140,
-	0,0,0,0,248,255,128,20,2,0,2,36,
-	47,85,192,8,88,0,2,166,3,131,4,60,
-	236,17,132,36,0,0,130,140,0,0,0,0,
-	1,0,66,36,0,0,130,172,200,255,130,140,
-	108,0,3,142,0,0,0,0,33,16,67,0,
-	200,255,130,172,2,0,2,36,88,0,2,166,
-	52,0,2,142,0,0,0,0,16,0,162,175,
-	44,0,2,142,12,0,4,38,28,0,5,38,
-	33,48,0,2,9,248,64,0,255,255,231,48,
-	28,0,191,143,24,0,176,143,8,0,224,3,
-	32,0,189,39,232,255,189,39,20,0,191,175,
-	16,0,176,175,33,128,128,0,88,0,3,150,
-	1,0,2,36,25,0,98,16,2,0,98,40,
-	5,0,64,16,3,0,2,36,7,0,96,16,
-	0,0,0,0,116,85,192,8,0,0,0,0,
-	37,0,98,16,0,0,0,0,116,85,192,8,
-	0,0,0,0,112,0,4,142,108,0,3,142,
-	0,0,0,0,34,0,96,16,0,0,0,0,
-	17,0,130,144,0,0,0,0,2,0,66,48,
-	33,0,64,16,255,255,99,36,250,255,96,20,
-	68,0,132,36,116,85,192,8,0,0,0,0,
-	112,0,4,142,108,0,3,142,0,0,0,0,
-	8,0,96,16,0,0,0,0,17,0,130,144,
-	0,0,0,0,2,0,66,48,19,0,64,16,
-	255,255,99,36,250,255,96,20,68,0,132,36,
-	118,93,192,12,33,32,0,2,241,255,64,28,
-	255,255,66,40,7,0,64,16,0,0,0,0,
-	92,85,192,8,0,0,0,0,120,94,192,12,
-	33,32,0,2,5,0,64,20,0,0,0,0,
-	219,84,192,12,33,32,0,2,167,83,192,12,
-	33,32,0,2,20,0,191,143,16,0,176,143,
-	8,0,224,3,24,0,189,39,232,255,189,39,
-	20,0,191,175,16,0,176,175,33,128,128,0,
-	88,0,3,150,1,0,2,36,17,0,98,16,
-	2,0,98,40,5,0,64,16,3,0,2,36,
-	9,0,96,16,0,0,0,0,156,85,192,8,
-	0,0,0,0,13,0,98,16,5,0,2,36,
-	7,0,98,16,0,0,0,0,156,85,192,8,
-	0,0,0,0,60,95,192,12,33,32,0,2,
-	154,85,192,8,0,0,0,0,0,93,192,12,
-	33,32,0,2,154,85,192,8,0,0,0,0,
-	252,93,192,12,33,32,0,2,5,0,64,20,
-	0,0,0,0,60,85,192,12,33,32,0,2,
-	162,85,192,8,0,0,0,0,167,83,192,12,
-	33,32,0,2,20,0,191,143,16,0,176,143,
-	8,0,224,3,24,0,189,39,192,255,189,39,
-	60,0,191,175,56,0,182,175,52,0,181,175,
-	48,0,180,175,44,0,179,175,40,0,178,175,
-	36,0,177,175,32,0,176,175,33,64,128,0,
-	33,136,192,0,33,152,224,0,84,0,182,143,
-	88,0,181,143,92,0,180,143,80,0,178,151,
-	3,131,3,60,128,17,99,36,0,0,98,140,
-	0,0,0,0,1,0,66,36,0,0,98,172,
-	24,0,162,39,16,0,162,175,33,32,160,0,
-	16,81,192,12,33,40,0,1,33,128,64,0,
-	57,0,0,18,255,255,66,50,58,0,3,150,
-	0,0,0,0,43,16,67,0,2,0,64,16,
-	0,0,0,0,58,0,18,166,44,0,22,174,
-	48,0,21,174,52,0,20,174,24,0,162,143,
-	0,0,0,0,7,0,64,16,1,0,2,36,
-	219,84,192,12,33,32,0,2,167,83,192,12,
-	33,32,0,2,5,86,192,8,0,0,0,0,
-	88,0,3,150,0,0,0,0,16,0,98,16,
-	2,0,98,40,5,0,64,16,3,0,2,36,
-	9,0,96,16,0,0,0,0,244,85,192,8,
-	0,0,0,0,11,0,98,16,5,0,2,36,
-	31,0,98,16,0,0,0,0,244,85,192,8,
-	0,0,0,0,3,131,3,60,239,85,192,8,
-	184,17,99,36,3,131,3,60,239,85,192,8,
-	188,17,99,36,3,131,3,60,192,17,99,36,
-	0,0,98,140,0,0,0,0,1,0,66,36,
-	3,86,192,8,0,0,98,172,3,131,3,60,
-	140,17,99,36,0,0,98,140,0,0,0,0,
-	1,0,66,36,0,0,98,172,167,83,192,12,
-	33,32,0,2,33,32,32,2,33,40,96,2,
-	1,0,6,36,9,248,160,2,33,56,128,2,
-	5,86,192,8,0,0,0,0,124,85,192,12,
-	33,32,0,2,60,0,191,143,56,0,182,143,
-	52,0,181,143,48,0,180,143,44,0,179,143,
-	40,0,178,143,36,0,177,143,32,0,176,143,
-	8,0,224,3,64,0,189,39,232,255,189,39,
-	20,0,191,175,16,0,176,175,33,128,128,0,
-	213,80,192,12,255,255,198,48,53,0,64,20,
-	255,255,2,36,3,131,3,60,144,17,99,36,
-	0,0,98,140,0,0,0,0,1,0,66,36,
-	0,0,98,172,96,0,2,142,0,0,0,0,
-	32,0,64,16,4,0,2,36,92,0,98,140,
-	0,0,0,0,1,0,66,36,92,0,98,172,
-	96,0,2,142,0,0,0,0,255,255,67,36,
-	5,0,98,44,32,0,64,16,128,16,3,0,
-	2,131,1,60,33,8,34,0,88,154,34,140,
-	0,0,0,0,8,0,64,0,0,0,0,0,
-	3,131,3,60,70,86,192,8,204,17,99,36,
-	3,131,3,60,70,86,192,8,212,17,99,36,
-	3,131,3,60,70,86,192,8,216,17,99,36,
-	3,131,3,60,70,86,192,8,208,17,99,36,
-	3,131,3,60,70,86,192,8,220,17,99,36,
-	88,0,3,150,0,0,0,0,8,0,98,20,
-	33,16,0,0,3,131,3,60,240,17,99,36,
-	0,0,98,140,0,0,0,0,1,0,66,36,
-	0,0,98,172,33,16,0,0,20,0,191,143,
-	16,0,176,143,8,0,224,3,24,0,189,39,
-	0,0,0,0,224,255,189,39,28,0,191,175,
-	24,0,178,175,20,0,177,175,16,0,176,175,
-	33,144,160,0,33,128,192,0,4,0,0,174,
-	14,0,128,16,0,0,4,174,128,136,4,0,
-	9,50,192,12,33,32,32,2,3,0,64,20,
-	4,0,2,174,104,86,192,8,255,255,2,36,
-	5,0,32,18,33,40,64,2,4,0,4,142,
-	0,0,0,0,80,68,192,12,33,48,32,2,
-	33,16,0,0,28,0,191,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,232,255,189,39,20,0,191,175,
-	16,0,176,175,33,128,128,0,4,0,4,142,
-	0,0,0,0,4,0,128,16,0,0,0,0,
-	61,50,192,12,0,0,0,0,4,0,0,174,
-	0,0,0,174,20,0,191,143,16,0,176,143,
-	8,0,224,3,24,0,189,39,0,0,0,0,
-	0,0,0,0,11,0,128,4,128,0,130,40,
-	20,0,64,20,1,0,3,36,255,127,2,36,
-	42,16,68,0,16,0,64,16,2,0,3,36,
-	127,0,2,60,255,255,66,52,148,86,192,8,
-	42,16,68,0,128,255,130,40,9,0,64,16,
-	1,0,3,36,0,128,130,40,6,0,64,16,
-	2,0,3,36,128,255,2,60,42,16,130,0,
-	2,0,64,20,4,0,3,36,3,0,3,36,
-	8,0,224,3,33,16,96,0,128,0,130,44,
-	14,0,64,20,1,0,2,36,255,127,2,36,
-	43,16,68,0,9,0,64,16,127,0,2,60,
-	255,255,66,52,43,16,68,0,6,0,64,16,
-	3,0,2,36,4,0,128,4,5,0,2,36,
-	169,86,192,8,4,0,2,36,2,0,2,36,
-	8,0,224,3,0,0,0,0,4,0,135,140,
-	0,0,130,140,0,0,0,0,65,0,64,16,
-	33,16,0,0,0,0,227,140,4,0,231,36,
-	128,16,3,0,33,16,67,0,192,16,2,0,
-	0,0,227,140,0,0,0,0,33,24,67,0,
-	128,0,98,44,17,0,64,20,4,0,231,36,
-	0,64,98,44,15,0,64,20,2,0,5,36,
-	31,0,2,60,255,255,66,52,43,16,67,0,
-	7,0,64,16,255,15,2,60,255,255,66,52,
-	43,16,67,0,6,0,64,20,5,0,5,36,
-	204,86,192,8,4,0,5,36,204,86,192,8,
-	3,0,5,36,1,0,5,36,2,0,6,36,
-	0,0,130,140,0,0,0,0,42,16,194,0,
-	31,0,64,16,255,255,162,48,31,0,9,60,
-	255,255,41,53,255,15,8,60,255,255,8,53,
-	0,0,132,140,0,0,227,140,4,0,231,36,
-	128,0,98,44,16,0,64,20,255,255,165,48,
-	0,64,98,44,11,0,64,20,43,16,35,1,
-	7,0,64,16,43,16,3,1,3,0,64,20,
-	0,0,0,0,236,86,192,8,4,0,165,36,
-	236,86,192,8,5,0,165,36,236,86,192,8,
-	3,0,165,36,236,86,192,8,2,0,165,36,
-	1,0,165,36,1,0,198,36,42,16,196,0,
-	232,255,64,20,255,255,162,48,8,0,224,3,
-	0,0,0,0,208,255,189,39,40,0,191,175,
-	33,72,192,0,224,0,165,48,255,255,130,48,
-	31,0,66,44,7,0,64,16,33,48,160,0,
-	37,16,133,0,16,0,162,163,33,32,224,0,
-	16,0,165,39,38,87,192,8,1,0,6,36,
-	32,0,163,39,33,40,0,0,31,0,194,52,
-	24,0,162,163,255,255,130,48,8,0,64,16,
-	25,0,168,39,127,0,130,48,0,0,98,160,
-	1,0,99,36,255,255,130,48,194,33,2,0,
-	250,255,128,20,1,0,165,36,1,0,166,36,
-	33,16,160,0,255,255,66,48,2,0,66,44,
-	13,0,64,20,255,255,165,36,255,255,4,52,
-	255,255,99,36,0,0,98,144,0,0,0,0,
-	128,0,66,52,0,0,2,161,1,0,8,37,
-	33,16,160,0,255,255,66,48,2,0,66,44,
-	246,255,64,16,33,40,164,0,255,255,98,144,
-	0,0,0,0,0,0,2,161,33,32,224,0,
-	24,0,165,39,255,255,198,48,9,248,32,1,
-	0,0,0,0,40,0,191,143,48,0,189,39,
-	8,0,224,3,0,0,0,0,208,255,189,39,
-	40,0,191,175,33,72,160,0,255,255,130,48,
-	128,0,66,44,6,0,64,16,33,64,192,0,
-	16,0,164,163,33,32,0,1,16,0,165,39,
-	88,87,192,8,1,0,6,36,24,0,167,39,
-	32,0,165,39,255,255,130,48,7,0,64,16,
-	33,24,0,0,0,0,164,160,1,0,165,36,
-	255,255,130,48,2,34,2,0,251,255,128,20,
-	1,0,99,36,128,0,98,52,0,0,226,160,
-	1,0,231,36,1,0,102,36,33,16,96,0,
-	255,255,66,48,11,0,64,16,255,255,99,36,
-	255,255,4,52,255,255,165,36,0,0,162,144,
-	0,0,0,0,0,0,226,160,1,0,231,36,
-	33,16,96,0,255,255,66,48,248,255,64,20,
-	33,24,100,0,33,32,0,1,24,0,165,39,
-	255,255,198,48,9,248,32,1,0,0,0,0,
-	40,0,191,143,48,0,189,39,8,0,224,3,
-	0,0,0,0,200,255,189,39,48,0,191,175,
-	44,0,181,175,40,0,180,175,36,0,179,175,
-	32,0,178,175,28,0,177,175,24,0,176,175,
-	33,136,160,0,33,144,192,0,33,152,224,0,
-	72,0,180,143,33,128,128,0,128,86,192,12,
-	33,32,64,2,33,168,64,0,255,255,4,50,
-	192,0,37,50,33,48,96,2,242,86,192,12,
-	33,56,128,2,255,255,176,50,33,32,0,2,
-	33,40,96,2,44,87,192,12,33,48,128,2,
-	16,0,162,39,33,24,80,0,255,255,99,36,
-	6,0,98,16,0,0,114,160,16,0,162,39,
-	3,146,18,0,255,255,99,36,253,255,98,20,
-	0,0,114,160,33,32,128,2,16,0,165,39,
-	9,248,96,2,255,255,166,50,48,0,191,143,
-	44,0,181,143,40,0,180,143,36,0,179,143,
-	32,0,178,143,28,0,177,143,24,0,176,143,
-	8,0,224,3,56,0,189,39,200,255,189,39,
-	48,0,191,175,44,0,181,175,40,0,180,175,
-	36,0,179,175,32,0,178,175,28,0,177,175,
-	24,0,176,175,33,136,160,0,33,144,192,0,
-	33,160,224,0,72,0,181,143,33,128,128,0,
-	153,86,192,12,33,32,64,2,33,152,64,0,
-	255,255,4,50,192,0,37,50,33,48,128,2,
-	242,86,192,12,33,56,160,2,255,255,112,50,
-	33,32,0,2,33,40,128,2,44,87,192,12,
-	33,48,160,2,16,0,162,39,33,32,80,0,
-	9,0,0,18,255,255,99,38,255,255,5,52,
-	255,255,132,36,0,0,146,160,2,146,18,0,
-	33,16,96,0,255,255,66,48,250,255,64,20,
-	33,24,101,0,33,32,160,2,16,0,165,39,
-	9,248,128,2,255,255,102,50,48,0,191,143,
-	44,0,181,143,40,0,180,143,36,0,179,143,
-	32,0,178,143,28,0,177,143,24,0,176,143,
-	8,0,224,3,56,0,189,39,216,255,189,39,
-	32,0,191,175,28,0,179,175,24,0,178,175,
-	20,0,177,175,16,0,176,175,33,152,192,0,
-	56,0,178,143,60,0,177,143,33,128,224,0,
-	255,255,132,48,192,0,165,48,33,48,64,2,
-	242,86,192,12,33,56,32,2,255,255,16,50,
-	33,32,0,2,33,40,64,2,44,87,192,12,
-	33,48,32,2,4,0,0,18,33,32,32,2,
-	33,40,96,2,9,248,64,2,33,48,0,2,
-	32,0,191,143,28,0,179,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	40,0,189,39,224,255,189,39,24,0,191,175,
-	33,72,160,0,128,0,130,44,18,0,64,20,
-	33,64,192,0,0,64,130,44,13,0,64,20,
-	31,0,2,60,255,255,66,52,43,16,68,0,
-	7,0,64,16,255,15,2,60,255,255,66,52,
-	43,16,68,0,8,0,64,20,5,0,6,36,
-	250,87,192,8,4,0,6,36,250,87,192,8,
-	3,0,6,36,250,87,192,8,2,0,6,36,
-	1,0,6,36,255,255,194,48,16,0,163,39,
-	33,40,98,0,9,0,163,16,33,56,0,0,
-	16,0,163,39,255,255,165,36,127,0,130,48,
-	37,16,226,0,0,0,162,160,194,33,4,0,
-	250,255,163,20,128,0,7,36,33,32,0,1,
-	16,0,165,39,9,248,32,1,255,255,198,48,
-	24,0,191,143,32,0,189,39,8,0,224,3,
-	0,0,0,0,208,255,189,39,44,0,191,175,
-	40,0,182,175,36,0,181,175,32,0,180,175,
-	28,0,179,175,24,0,178,175,20,0,177,175,
-	16,0,176,175,33,144,160,0,33,168,192,0,
-	33,160,224,0,64,0,182,143,33,136,128,0,
-	4,0,179,142,0,0,0,0,171,86,192,12,
-	33,32,160,2,33,128,64,0,255,255,36,50,
-	192,0,69,50,33,48,128,2,242,86,192,12,
-	33,56,192,2,255,255,16,50,33,32,0,2,
-	33,40,128,2,44,87,192,12,33,48,192,2,
-	23,0,0,18,33,40,128,2,0,0,98,142,
-	4,0,115,38,128,32,2,0,33,32,130,0,
-	192,32,4,0,0,0,98,142,4,0,115,38,
-	33,32,130,0,226,87,192,12,33,48,192,2,
-	63,88,192,8,2,0,16,36,0,0,100,142,
-	4,0,115,38,226,87,192,12,33,48,192,2,
-	1,0,16,38,0,0,162,142,0,0,0,0,
-	42,16,2,2,247,255,64,20,33,40,128,2,
-	44,0,191,143,40,0,182,143,36,0,181,143,
-	32,0,180,143,28,0,179,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	48,0,189,39,224,255,189,39,28,0,191,175,
-	24,0,178,175,20,0,177,175,16,0,176,175,
-	33,136,128,0,33,144,192,0,255,255,67,50,
-	12,0,34,150,0,0,0,0,43,16,67,0,
-	4,0,64,16,1,0,2,36,12,0,50,150,
-	0,0,0,0,255,255,67,50,11,0,98,16,
-	2,0,98,40,5,0,64,16,2,0,2,36,
-	50,0,96,16,255,255,80,50,137,88,192,8,
-	0,0,0,0,15,0,98,16,255,255,80,50,
-	137,88,192,8,0,0,0,0,8,0,35,142,
-	0,0,0,0,1,0,98,36,8,0,34,174,
-	0,0,162,144,0,0,0,0,0,0,98,160,
-	12,0,34,150,0,0,0,0,255,255,66,36,
-	149,88,192,8,12,0,34,166,8,0,35,142,
-	0,0,0,0,1,0,98,36,8,0,34,174,
-	0,0,162,144,0,0,0,0,0,0,98,160,
-	8,0,35,142,0,0,0,0,1,0,98,36,
-	8,0,34,174,1,0,162,144,0,0,0,0,
-	0,0,98,160,12,0,34,150,0,0,0,0,
-	254,255,66,36,149,88,192,8,12,0,34,166,
-	8,0,36,142,0,0,0,0,80,68,192,12,
-	33,48,0,2,12,0,34,150,0,0,0,0,
-	35,16,82,0,12,0,34,166,8,0,34,142,
-	0,0,0,0,33,128,2,2,8,0,48,174,
-	255,255,66,50,28,0,191,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,224,255,189,39,24,0,191,175,
-	20,0,177,175,16,0,176,175,33,128,160,0,
-	10,0,128,20,33,136,192,0,9,50,192,12,
-	16,0,4,36,33,32,64,0,3,0,128,20,
-	1,0,2,36,178,88,192,8,33,16,0,0,
-	173,88,192,8,0,0,130,160,0,0,128,160,
-	4,0,144,172,8,0,144,172,33,16,17,2,
-	12,0,130,172,33,16,128,0,24,0,191,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,232,255,189,39,16,0,191,175,
-	0,0,130,144,0,0,0,0,1,0,66,48,
-	3,0,64,16,0,0,0,0,61,50,192,12,
-	0,0,0,0,16,0,191,143,24,0,189,39,
-	8,0,224,3,0,0,0,0,0,0,130,144,
-	0,0,0,0,128,0,66,48,16,0,64,20,
-	255,255,2,36,8,0,130,140,12,0,131,140,
-	0,0,0,0,43,16,67,0,7,0,64,20,
-	0,0,0,0,0,0,130,144,0,0,0,0,
-	128,0,66,52,0,0,130,160,216,88,192,8,
-	255,255,2,36,8,0,130,140,0,0,0,0,
-	0,0,66,144,8,0,224,3,0,0,0,0,
-	30,0,192,24,33,56,192,0,0,0,130,144,
-	0,0,0,0,128,0,66,48,16,0,64,20,
-	255,0,3,36,8,0,131,140,12,0,130,140,
-	0,0,0,0,43,16,98,0,5,0,64,16,
-	1,0,98,36,8,0,130,172,0,0,99,144,
-	240,88,192,8,0,0,0,0,0,0,130,144,
-	0,0,0,0,128,0,66,52,0,0,130,160,
-	255,0,3,36,0,0,130,144,0,0,0,0,
-	128,0,66,48,5,0,64,20,0,0,0,0,
-	0,0,163,160,255,255,198,36,228,255,192,28,
-	1,0,165,36,8,0,224,3,35,16,230,0,
-	1,0,2,36,15,0,194,16,2,0,194,40,
-	5,0,64,16,2,0,2,36,7,0,192,16,
-	255,255,2,36,40,89,192,8,0,0,0,0,
-	11,0,194,16,255,255,2,36,40,89,192,8,
-	0,0,0,0,4,0,130,140,0,0,0,0,
-	21,89,192,8,33,40,162,0,8,0,130,140,
-	0,0,0,0,19,89,192,8,33,40,162,0,
-	12,0,130,140,0,0,0,0,35,40,69,0,
-	4,0,130,140,0,0,0,0,43,16,162,0,
-	17,0,64,20,255,255,2,36,12,0,130,140,
-	0,0,0,0,43,16,69,0,12,0,64,20,
-	255,255,2,36,12,0,130,140,0,0,0,0,
-	43,16,162,0,5,0,64,16,0,0,0,0,
-	0,0,130,144,0,0,0,0,127,0,66,48,
-	0,0,130,160,8,0,133,172,33,16,0,0,
-	8,0,224,3,0,0,0,0,12,0,130,140,
-	4,0,131,140,0,0,0,0,35,56,67,0,
-	1,0,2,36,15,0,194,16,2,0,194,40,
-	5,0,64,16,2,0,2,36,7,0,192,16,
-	255,255,2,36,87,89,192,8,0,0,0,0,
-	12,0,194,16,255,255,2,36,87,89,192,8,
-	0,0,0,0,4,0,130,140,0,0,0,0,
-	66,89,192,8,33,16,162,0,8,0,130,140,
-	0,0,0,0,33,16,162,0,72,89,192,8,
-	12,0,130,172,12,0,130,140,0,0,0,0,
-	35,16,69,0,12,0,130,172,8,0,130,140,
-	12,0,131,140,0,0,0,0,43,16,67,0,
-	5,0,64,16,0,0,0,0,0,0,130,144,
-	0,0,0,0,85,89,192,8,127,0,66,48,
-	0,0,130,144,0,0,0,0,128,0,66,52,
-	0,0,130,160,33,16,224,0,8,0,224,3,
-	0,0,0,0,232,255,189,39,20,0,191,175,
-	16,0,176,175,12,0,128,20,33,128,160,0,
-	9,50,192,12,16,0,4,36,33,32,64,0,
-	3,0,128,20,0,0,0,0,119,89,192,8,
-	33,16,0,0,0,0,2,146,0,0,0,0,
-	108,89,192,8,1,0,66,52,0,0,2,146,
-	0,0,0,0,254,0,66,48,0,0,130,160,
-	4,0,2,142,0,0,0,0,4,0,130,172,
-	8,0,2,142,0,0,0,0,8,0,130,172,
-	12,0,2,142,0,0,0,0,12,0,130,172,
-	33,16,128,0,20,0,191,143,16,0,176,143,
-	8,0,224,3,24,0,189,39,0,0,0,0,
-	0,0,130,144,0,0,0,0,128,0,66,48,
-	17,0,64,20,31,0,3,36,8,0,131,140,
-	12,0,130,140,0,0,0,0,43,16,98,0,
-	6,0,64,16,1,0,98,36,8,0,130,172,
-	0,0,98,144,0,0,0,0,145,89,192,8,
-	31,0,67,48,0,0,130,144,0,0,0,0,
-	128,0,66,52,0,0,130,160,31,0,3,36,
-	0,0,130,144,0,0,0,0,128,0,66,48,
-	4,0,64,16,1,0,2,36,0,0,162,172,
-	196,89,192,8,33,16,0,0,255,0,99,48,
-	31,0,2,36,6,0,98,16,33,16,96,0,
-	196,89,192,8,0,0,0,0,1,0,2,36,
-	195,89,192,8,0,0,162,172,33,48,0,0,
-	0,0,130,144,0,0,0,0,128,0,66,48,
-	16,0,64,20,255,0,3,36,8,0,131,140,
-	12,0,130,140,0,0,0,0,43,16,98,0,
-	5,0,64,16,1,0,98,36,8,0,130,172,
-	0,0,99,144,183,89,192,8,0,0,0,0,
-	0,0,130,144,0,0,0,0,128,0,66,52,
-	0,0,130,160,255,0,3,36,0,0,130,144,
-	0,0,0,0,128,0,66,48,228,255,64,20,
-	128,0,98,48,4,0,64,16,127,0,98,48,
-	37,16,194,0,163,89,192,8,192,49,2,0,
-	255,0,98,48,37,48,70,0,255,255,194,48,
-	8,0,224,3,0,0,0,0,0,0,130,144,
-	0,0,0,0,128,0,66,48,16,0,64,20,
-	255,0,6,36,8,0,131,140,12,0,130,140,
-	0,0,0,0,43,16,98,0,5,0,64,16,
-	1,0,98,36,8,0,130,172,0,0,102,144,
-	218,89,192,8,0,0,0,0,0,0,130,144,
-	0,0,0,0,128,0,66,52,0,0,130,160,
-	255,0,6,36,0,0,130,144,0,0,0,0,
-	128,0,66,48,13,0,64,20,1,0,2,36,
-	255,0,195,48,128,0,2,36,4,0,98,20,
-	2,0,2,36,0,0,162,172,17,90,192,8,
-	255,255,2,52,128,0,194,48,6,0,64,20,
-	33,24,0,0,17,90,192,8,255,0,194,48,
-	0,0,162,172,17,90,192,8,33,16,0,0,
-	127,0,194,48,32,0,64,16,255,255,71,36,
-	0,26,3,0,0,0,130,144,0,0,0,0,
-	128,0,66,48,16,0,64,20,255,255,102,48,
-	8,0,131,140,12,0,130,140,0,0,0,0,
-	43,16,98,0,6,0,64,16,1,0,98,36,
-	8,0,130,172,0,0,98,144,0,0,0,0,
-	7,90,192,8,37,24,194,0,0,0,130,144,
-	0,0,0,0,128,0,66,52,0,0,130,160,
-	255,0,195,52,0,0,130,144,0,0,0,0,
-	128,0,66,48,224,255,64,20,1,0,2,36,
-	33,16,224,0,255,0,66,48,226,255,64,20,
-	255,255,231,36,255,255,98,48,8,0,224,3,
-	0,0,0,0,216,255,189,39,36,0,191,175,
-	32,0,180,175,28,0,179,175,24,0,178,175,
-	20,0,177,175,16,0,176,175,33,152,128,0,
-	33,128,192,0,33,144,160,0,255,255,81,50,
-	33,0,32,18,33,160,224,0,255,255,2,52,
-	30,0,34,18,0,0,0,0,9,50,192,12,
-	33,32,32,2,33,24,64,0,29,0,96,16,
-	1,0,2,36,0,0,2,166,4,0,3,174,
-	8,0,3,174,12,0,18,166,33,32,96,2,
-	8,0,5,142,0,0,0,0,218,88,192,12,
-	33,48,32,2,33,24,64,0,255,255,100,48,
-	10,0,145,20,1,0,2,36,12,0,2,150,
-	0,0,0,0,35,16,67,0,12,0,2,166,
-	8,0,2,142,0,0,0,0,33,16,130,0,
-	68,90,192,8,8,0,2,174,68,90,192,8,
-	0,0,130,174,0,0,0,166,4,0,0,174,
-	8,0,0,174,12,0,0,166,36,0,191,143,
-	32,0,180,143,28,0,179,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	40,0,189,39,224,255,189,39,28,0,191,175,
-	24,0,178,175,20,0,177,175,16,0,176,175,
-	33,144,128,0,33,136,160,0,33,128,192,0,
-	124,89,192,12,33,40,0,2,33,32,64,2,
-	198,89,192,12,33,40,0,2,33,40,64,0,
-	0,0,2,142,0,0,0,0,7,0,64,20,
-	33,32,64,2,255,255,165,48,33,48,32,2,
-	19,90,192,12,33,56,0,2,104,90,192,8,
-	0,0,0,0,0,0,32,166,4,0,32,174,
-	8,0,32,174,12,0,32,166,28,0,191,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,216,255,189,39,
-	36,0,191,175,32,0,180,175,28,0,179,175,
-	24,0,178,175,20,0,177,175,16,0,176,175,
-	33,152,128,0,33,136,160,0,33,144,192,0,
-	56,0,176,147,0,0,0,0,196,88,192,12,
-	33,160,224,0,224,0,66,48,7,0,80,20,
-	33,32,96,2,124,89,192,12,33,40,64,2,
-	255,255,66,48,255,255,131,50,7,0,67,16,
-	33,32,96,2,0,0,66,142,0,0,0,0,
-	16,0,64,20,4,0,2,36,152,90,192,8,
-	0,0,66,174,198,89,192,12,33,40,64,2,
-	33,40,64,0,0,0,66,142,0,0,0,0,
-	7,0,64,20,33,32,96,2,255,255,165,48,
-	33,48,32,2,19,90,192,12,33,56,64,2,
-	156,90,192,8,0,0,0,0,0,0,32,166,
-	4,0,32,174,8,0,32,174,12,0,32,166,
-	36,0,191,143,32,0,180,143,28,0,179,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,40,0,189,39,33,56,0,0,
-	255,255,168,36,255,255,165,48,50,0,160,16,
-	1,0,9,36,1,0,12,36,4,0,10,36,
-	3,0,11,36,255,255,5,52,0,0,130,144,
-	0,0,0,0,128,0,66,48,16,0,64,20,
-	255,0,3,36,8,0,131,140,12,0,130,140,
-	0,0,0,0,43,16,98,0,5,0,64,16,
-	1,0,98,36,8,0,130,172,0,0,99,144,
-	193,90,192,8,0,0,0,0,0,0,130,144,
-	0,0,0,0,128,0,66,52,0,0,130,160,
-	255,0,3,36,0,0,130,144,0,0,0,0,
-	128,0,66,48,3,0,64,16,0,0,0,0,
-	218,90,192,8,0,0,204,172,11,0,32,17,
-	255,255,2,49,5,0,74,20,33,72,0,0,
-	3,0,96,16,0,0,0,0,218,90,192,8,
-	0,0,203,172,128,0,98,48,3,0,64,16,
-	0,18,7,0,255,255,7,36,0,18,7,0,
-	37,56,67,0,33,16,0,1,255,255,66,48,
-	212,255,64,20,33,64,5,1,8,0,224,3,
-	33,16,224,0,224,255,189,39,24,0,191,175,
-	20,0,177,175,16,0,176,175,33,128,128,0,
-	124,89,192,12,33,136,160,0,33,32,0,2,
-	198,89,192,12,33,40,32,2,33,32,0,2,
-	255,255,69,48,164,90,192,12,33,48,32,2,
-	24,0,191,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,32,0,189,39,216,255,189,39,
-	32,0,191,175,28,0,179,175,24,0,178,175,
-	20,0,177,175,16,0,176,175,33,144,128,0,
-	33,136,160,0,33,152,192,0,196,88,192,12,
-	33,128,224,0,224,0,66,48,255,0,16,50,
-	7,0,80,20,33,32,64,2,124,89,192,12,
-	33,40,32,2,255,255,66,48,255,255,99,50,
-	8,0,67,16,33,32,64,2,0,0,34,142,
-	0,0,0,0,2,0,64,20,4,0,2,36,
-	0,0,34,174,17,91,192,8,33,16,0,0,
-	198,89,192,12,33,40,32,2,33,32,64,2,
-	255,255,69,48,164,90,192,12,33,48,32,2,
-	32,0,191,143,28,0,179,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	40,0,189,39,208,255,189,39,44,0,191,175,
-	40,0,180,175,36,0,179,175,32,0,178,175,
-	28,0,177,175,24,0,176,175,33,128,128,0,
-	33,152,192,0,33,160,224,0,0,0,96,174,
-	4,0,96,174,8,0,3,142,4,0,2,142,
-	0,0,0,0,35,24,98,0,255,255,165,48,
-	35,0,160,24,33,144,0,0,1,0,6,36,
-	0,0,2,146,0,0,0,0,128,0,66,48,
-	16,0,64,20,255,0,4,36,8,0,4,142,
-	12,0,2,142,0,0,0,0,43,16,130,0,
-	5,0,64,16,1,0,130,36,8,0,2,174,
-	0,0,132,144,64,91,192,8,0,0,0,0,
-	0,0,2,146,0,0,0,0,128,0,66,52,
-	0,0,2,162,255,0,4,36,0,0,2,146,
-	0,0,0,0,128,0,66,48,3,0,64,16,
-	128,0,130,48,150,91,192,8,0,0,134,174,
-	2,0,64,20,0,0,0,0,1,0,82,38,
-	255,255,165,36,224,255,160,28,0,0,0,0,
-	33,32,0,2,33,40,96,0,251,88,192,12,
-	33,48,0,0,68,0,64,18,1,0,81,38,
-	9,50,192,12,128,32,17,0,33,40,64,0,
-	63,0,160,16,0,0,0,0,0,0,113,174,
-	4,0,101,174,59,0,64,26,33,56,0,0,
-	1,0,8,36,33,48,0,0,0,0,2,146,
-	0,0,0,0,128,0,66,48,16,0,64,20,
-	255,0,4,36,8,0,3,142,12,0,2,142,
-	0,0,0,0,43,16,98,0,5,0,64,16,
-	1,0,98,36,8,0,2,174,0,0,100,144,
-	114,91,192,8,0,0,0,0,0,0,2,146,
-	0,0,0,0,128,0,66,52,0,0,2,162,
-	255,0,4,36,0,0,2,146,0,0,0,0,
-	128,0,66,48,3,0,64,16,192,49,6,0,
-	150,91,192,8,0,0,136,174,127,0,130,48,
-	37,48,194,0,128,0,130,48,225,255,64,20,
-	0,0,0,0,18,0,224,20,40,0,194,44,
-	4,0,64,16,80,0,194,44,0,0,160,172,
-	145,91,192,8,4,0,165,36,5,0,64,16,
-	216,255,194,36,0,0,168,172,4,0,165,36,
-	146,91,192,8,0,0,162,172,2,0,2,36,
-	0,0,162,172,4,0,165,36,176,255,194,36,
-	146,91,192,8,0,0,162,172,0,0,166,172,
-	1,0,231,36,42,16,242,0,200,255,64,20,
-	4,0,165,36,44,0,191,143,40,0,180,143,
-	36,0,179,143,32,0,178,143,28,0,177,143,
-	24,0,176,143,8,0,224,3,48,0,189,39,
-	224,255,189,39,28,0,191,175,24,0,178,175,
-	20,0,177,175,16,0,176,175,33,136,128,0,
-	33,144,160,0,33,128,192,0,124,89,192,12,
-	33,40,0,2,33,32,32,2,198,89,192,12,
-	33,40,0,2,33,40,64,0,0,0,2,142,
-	0,0,0,0,5,0,64,20,33,32,32,2,
-	255,255,165,48,33,48,64,2,24,91,192,12,
-	33,56,0,2,28,0,191,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	32,0,189,39,216,255,189,39,36,0,191,175,
-	32,0,180,175,28,0,179,175,24,0,178,175,
-	20,0,177,175,16,0,176,175,33,144,128,0,
-	33,160,160,0,33,136,192,0,56,0,176,147,
-	0,0,0,0,196,88,192,12,33,152,224,0,
-	224,0,66,48,7,0,80,20,33,32,64,2,
-	124,89,192,12,33,40,32,2,255,255,66,48,
-	255,255,99,50,7,0,67,16,33,32,64,2,
-	0,0,34,142,0,0,0,0,14,0,64,20,
-	4,0,2,36,226,91,192,8,0,0,34,174,
-	198,89,192,12,33,40,32,2,33,40,64,0,
-	0,0,34,142,0,0,0,0,5,0,64,20,
-	33,32,64,2,255,255,165,48,33,48,128,2,
-	24,91,192,12,33,56,32,2,36,0,191,143,
-	32,0,180,143,28,0,179,143,24,0,178,143,
-	20,0,177,143,16,0,176,143,8,0,224,3,
-	40,0,189,39,0,0,0,0,0,0,0,0,
-	216,255,189,39,32,0,191,175,28,0,179,175,
-	24,0,178,175,20,0,177,175,16,0,176,175,
-	33,152,128,0,8,0,99,142,4,0,98,142,
-	0,0,0,0,35,128,98,0,255,255,4,50,
-	19,0,128,16,33,136,160,0,9,50,192,12,
-	0,0,0,0,33,144,64,0,3,0,64,22,
-	255,255,16,50,17,92,192,8,255,255,2,36,
-	33,32,64,2,4,0,101,142,0,0,0,0,
-	80,68,192,12,33,48,0,2,1,0,2,36,
-	0,0,34,166,4,0,50,174,33,128,80,2,
-	15,92,192,8,8,0,48,174,0,0,32,166,
-	4,0,32,174,8,0,32,174,12,0,32,166,
-	33,16,0,0,32,0,191,143,28,0,179,143,
-	24,0,178,143,20,0,177,143,16,0,176,143,
-	8,0,224,3,40,0,189,39,232,255,189,39,
-	20,0,191,175,16,0,176,175,33,128,128,0,
-	0,0,2,150,0,0,0,0,1,0,66,48,
-	7,0,64,16,0,0,0,0,4,0,4,142,
-	0,0,0,0,3,0,128,16,0,0,0,0,
-	61,50,192,12,0,0,0,0,0,0,0,166,
-	8,0,0,174,4,0,0,174,12,0,0,166,
-	20,0,191,143,16,0,176,143,8,0,224,3,
-	24,0,189,39,224,255,189,39,24,0,191,175,
-	20,0,177,175,16,0,176,175,33,128,128,0,
-	8,0,163,140,4,0,162,140,0,0,0,0,
-	35,136,98,0,255,255,35,50,12,0,2,150,
-	0,0,0,0,43,16,67,0,4,0,64,16,
-	255,255,38,50,12,0,17,150,0,0,0,0,
-	255,255,38,50,6,0,192,16,255,255,34,50,
-	8,0,4,142,4,0,165,140,80,68,192,12,
-	0,0,0,0,255,255,34,50,8,0,3,142,
-	0,0,0,0,33,16,67,0,8,0,2,174,
-	12,0,2,150,0,0,0,0,35,16,81,0,
-	12,0,2,166,24,0,191,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,32,0,189,39,
-	1,0,2,36,23,0,194,16,2,0,194,40,
-	5,0,64,16,2,0,2,36,7,0,192,16,
-	255,255,2,36,132,92,192,8,0,0,0,0,
-	23,0,194,16,255,255,2,36,132,92,192,8,
-	0,0,0,0,255,255,162,48,4,0,131,140,
-	0,0,0,0,33,48,67,0,8,0,130,140,
-	0,0,0,0,35,16,67,0,12,0,131,148,
-	0,0,0,0,33,16,67,0,124,92,192,8,
-	35,40,69,0,255,255,162,48,8,0,131,140,
-	0,0,0,0,33,48,67,0,12,0,130,148,
-	0,0,0,0,124,92,192,8,35,40,69,0,
-	12,0,130,148,8,0,131,140,0,0,0,0,
-	33,48,67,0,255,255,162,48,35,48,194,0,
-	4,0,130,140,0,0,0,0,43,16,194,0,
-	4,0,64,20,255,255,2,36,8,0,134,172,
-	12,0,133,164,33,16,0,0,8,0,224,3,
-	0,0,0,0,216,255,189,39,32,0,191,175,
-	28,0,179,175,24,0,178,175,20,0,177,175,
-	16,0,176,175,33,128,128,0,33,152,160,0,
-	8,0,3,142,4,0,2,142,0,0,0,0,
-	35,144,98,0,255,255,66,50,12,0,3,150,
-	0,0,0,0,33,16,67,0,255,255,99,50,
-	42,16,67,0,35,0,64,16,1,0,2,36,
-	0,0,3,150,0,0,0,0,32,0,98,20,
-	255,255,2,36,9,50,192,12,255,255,100,50,
-	33,136,64,0,3,0,32,22,255,255,70,50,
-	189,92,192,8,255,255,2,36,5,0,192,16,
-	0,0,0,0,4,0,5,142,0,0,0,0,
-	80,68,192,12,33,32,32,2,0,0,2,150,
-	0,0,0,0,1,0,66,48,7,0,64,16,
-	0,0,0,0,4,0,4,142,0,0,0,0,
-	3,0,128,16,0,0,0,0,61,50,192,12,
-	0,0,0,0,4,0,17,174,255,255,66,50,
-	33,16,34,2,8,0,2,174,35,16,114,2,
-	12,0,2,166,33,16,0,0,32,0,191,143,
-	28,0,179,143,24,0,178,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,40,0,189,39,
-	216,255,189,39,32,0,191,175,28,0,179,175,
-	24,0,178,175,20,0,177,175,16,0,176,175,
-	33,128,128,0,33,136,192,0,255,255,36,50,
-	35,0,128,16,33,152,160,0,8,0,2,142,
-	4,0,3,142,0,0,0,0,35,16,67,0,
-	255,255,66,48,12,0,3,150,0,0,0,0,
-	33,16,67,0,42,16,68,0,20,0,64,16,
-	0,0,0,0,9,50,192,12,0,0,0,0,
-	33,144,64,0,24,0,64,18,255,255,2,36,
-	0,0,2,150,0,0,0,0,1,0,66,48,
-	8,0,64,16,1,0,2,36,4,0,4,142,
-	0,0,0,0,4,0,128,16,0,0,0,0,
-	61,50,192,12,0,0,0,0,1,0,2,36,
-	0,0,2,166,4,0,18,174,4,0,4,142,
-	33,40,96,2,80,68,192,12,255,255,38,50,
-	33,32,0,2,255,255,37,50,85,92,192,12,
-	33,48,0,0,33,16,0,0,32,0,191,143,
-	28,0,179,143,24,0,178,143,20,0,177,143,
-	16,0,176,143,8,0,224,3,40,0,189,39,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	184,255,189,39,64,0,191,175,60,0,183,175,
-	56,0,182,175,52,0,181,175,48,0,180,175,
-	44,0,179,175,40,0,178,175,36,0,177,175,
-	32,0,176,175,33,144,128,0,112,0,84,142,
-	0,0,0,0,92,0,128,18,1,0,2,36,
-	108,0,81,142,0,0,0,0,88,0,32,18,
-	0,0,0,0,96,0,87,38,136,0,66,174,
-	140,0,64,174,96,0,64,174,100,0,64,174,
-	224,83,192,12,33,32,32,2,33,168,64,0,
-	25,0,160,18,33,128,160,2,108,0,66,142,
-	0,0,0,0,124,0,66,174,128,0,84,174,
-	108,0,81,174,112,0,85,174,29,0,32,26,
-	33,152,0,0,255,255,22,36,33,32,0,2,
-	8,0,133,38,33,48,64,2,170,72,192,12,
-	1,0,7,36,10,0,86,16,33,32,64,2,
-	14,0,64,20,0,0,0,0,64,0,66,142,
-	0,0,0,0,10,0,64,20,2,0,5,36,
-	56,93,192,8,1,0,102,38,33,32,64,2,
-	5,0,5,36,33,48,0,0,140,84,192,12,
-	0,0,0,0,107,93,192,8,1,0,2,36,
-	1,0,115,38,68,0,16,38,42,16,113,2,
-	230,255,64,20,68,0,148,38,40,0,32,18,
-	33,128,160,2,17,0,2,146,0,0,0,0,
-	34,0,66,48,32,0,64,20,0,0,0,0,
-	36,0,2,142,16,0,176,175,16,0,66,140,
-	24,0,4,142,28,0,5,142,32,0,6,142,
-	0,0,0,0,9,248,64,0,33,56,64,2,
-	17,0,2,146,0,0,0,0,32,0,66,52,
-	17,0,2,162,0,0,226,142,0,0,0,0,
-	15,0,64,16,0,0,0,0,255,255,49,38,
-	15,0,32,18,68,0,16,38,17,0,3,146,
-	0,0,0,0,32,0,98,48,2,0,64,20,
-	34,0,98,52,17,0,2,162,255,255,49,38,
-	248,255,32,22,68,0,16,38,107,93,192,8,
-	33,16,0,0,255,255,49,38,218,255,32,22,
-	68,0,16,38,33,16,0,0,64,0,191,143,
-	60,0,183,143,56,0,182,143,52,0,181,143,
-	48,0,180,143,44,0,179,143,40,0,178,143,
-	36,0,177,143,32,0,176,143,8,0,224,3,
-	72,0,189,39,168,255,189,39,80,0,191,175,
-	76,0,183,175,72,0,182,175,68,0,181,175,
-	64,0,180,175,60,0,179,175,56,0,178,175,
-	52,0,177,175,48,0,176,175,33,144,128,0,
-	96,0,66,142,0,0,0,0,3,0,64,16,
-	33,32,0,0,240,93,192,8,255,255,2,36,
-	116,0,66,142,0,0,0,0,7,0,64,16,
-	104,0,67,38,12,0,99,140,0,0,0,0,
-	12,0,98,140,0,0,0,0,251,255,64,20,
-	0,0,0,0,8,0,116,140,0,0,0,0,
-	92,0,128,18,33,16,0,0,4,0,115,140,
-	0,0,0,0,88,0,96,18,0,0,0,0,
-	64,0,66,142,0,0,0,0,55,0,64,20,
-	0,0,0,0,33,128,128,2,52,0,96,26,
-	33,136,0,0,255,255,23,36,2,0,22,36,
-	5,0,21,36,17,0,2,146,0,0,0,0,
-	16,0,66,48,40,0,64,16,24,0,165,39,
-	8,0,3,142,28,0,2,142,0,0,0,0,
-	35,24,98,0,24,0,163,175,12,0,2,142,
-	0,0,0,0,28,0,162,175,128,24,3,0,
-	33,24,98,0,252,255,98,140,0,0,0,0,
-	1,0,66,36,252,255,98,172,12,0,0,174,
-	8,0,0,174,33,32,0,2,33,48,64,2,
-	170,72,192,12,1,0,7,36,6,0,87,16,
-	0,0,0,0,9,0,64,20,1,0,34,38,
-	96,0,86,174,196,93,192,8,100,0,66,174,
-	96,0,85,174,110,86,192,12,24,0,164,39,
-	240,93,192,8,255,255,2,36,110,86,192,12,
-	24,0,164,39,17,0,2,146,0,0,0,0,
-	12,0,66,48,17,0,2,162,1,0,4,36,
-	1,0,49,38,42,16,51,2,209,255,64,20,
-	68,0,16,38,27,0,128,16,33,128,128,2,
-	23,0,96,26,33,136,0,0,17,0,2,146,
-	0,0,0,0,34,0,66,48,14,0,64,20,
-	0,0,0,0,36,0,2,142,16,0,176,175,
-	16,0,66,140,24,0,4,142,28,0,5,142,
-	32,0,6,142,0,0,0,0,9,248,64,0,
-	33,56,64,2,17,0,2,146,0,0,0,0,
-	32,0,66,52,17,0,2,162,1,0,49,38,
-	42,16,51,2,235,255,64,20,68,0,16,38,
-	240,93,192,8,1,0,2,36,33,16,0,0,
-	80,0,191,143,76,0,183,143,72,0,182,143,
-	68,0,181,143,64,0,180,143,60,0,179,143,
-	56,0,178,143,52,0,177,143,48,0,176,143,
-	8,0,224,3,88,0,189,39,0,0,0,0,
-	200,255,189,39,48,0,191,175,44,0,179,175,
-	40,0,178,175,36,0,177,175,32,0,176,175,
-	33,144,128,0,96,0,64,174,100,0,64,174,
-	112,0,80,142,0,0,0,0,105,0,0,18,
-	33,16,0,0,108,0,81,142,0,0,0,0,
-	101,0,32,18,0,0,0,0,64,0,66,142,
-	0,0,0,0,43,0,64,20,33,32,64,2,
-	50,0,32,26,33,152,0,0,33,32,0,2,
-	33,40,64,2,96,72,192,12,1,0,6,36,
-	13,0,64,20,33,32,64,2,20,0,2,150,
-	0,0,0,0,1,0,66,48,34,0,64,16,
-	2,0,5,36,36,0,2,142,0,0,0,0,
-	3,0,66,144,0,0,0,0,2,0,66,48,
-	3,0,64,20,0,0,0,0,63,94,192,8,
-	2,0,5,36,36,0,2,142,0,0,0,0,
-	32,0,66,140,4,0,67,142,0,0,0,0,
-	36,16,67,0,16,0,64,16,33,32,64,2,
-	36,0,2,142,16,0,3,146,2,0,66,144,
-	0,0,0,0,11,0,98,20,3,0,5,36,
-	1,0,115,38,42,16,113,2,219,255,64,20,
-	68,0,16,38,69,94,192,8,96,0,83,38,
-	5,0,5,36,64,94,192,8,33,48,0,0,
-	2,0,5,36,1,0,102,38,140,84,192,12,
-	0,0,0,0,113,94,192,8,1,0,2,36,
-	96,0,83,38,112,0,80,142,0,0,0,0,
-	41,0,32,18,33,16,0,0,17,0,2,146,
-	0,0,0,0,17,0,66,48,32,0,64,20,
-	0,0,0,0,36,0,2,142,16,0,176,175,
-	4,0,66,140,24,0,4,142,28,0,5,142,
-	32,0,6,142,0,0,0,0,9,248,64,0,
-	33,56,64,2,17,0,2,146,0,0,0,0,
-	16,0,66,52,17,0,2,162,0,0,98,142,
-	0,0,0,0,15,0,64,16,0,0,0,0,
-	255,255,49,38,15,0,32,18,68,0,16,38,
-	17,0,3,146,0,0,0,0,16,0,98,48,
-	2,0,64,20,17,0,98,52,17,0,2,162,
-	255,255,49,38,248,255,32,22,68,0,16,38,
-	113,94,192,8,33,16,0,0,255,255,49,38,
-	218,255,32,22,68,0,16,38,33,16,0,0,
-	48,0,191,143,44,0,179,143,40,0,178,143,
-	36,0,177,143,32,0,176,143,8,0,224,3,
-	56,0,189,39,192,255,189,39,56,0,191,175,
-	52,0,183,175,48,0,182,175,44,0,181,175,
-	40,0,180,175,36,0,179,175,32,0,178,175,
-	28,0,177,175,24,0,176,175,33,144,128,0,
-	112,0,84,142,0,0,0,0,171,0,128,18,
-	33,16,0,0,108,0,85,142,0,0,0,0,
-	166,0,160,18,32,0,2,36,56,0,67,146,
-	0,0,0,0,75,0,98,16,96,0,83,38,
-	33,0,98,40,5,0,64,16,64,0,2,36,
-	9,0,96,16,33,16,0,0,49,95,192,8,
-	0,0,0,0,85,0,98,16,128,0,2,36,
-	137,0,98,16,33,16,0,0,49,95,192,8,
-	0,0,0,0,33,136,160,2,8,0,32,18,
-	33,128,128,2,17,0,2,146,0,0,0,0,
-	1,0,66,48,139,0,64,16,255,255,49,38,
-	250,255,32,22,68,0,16,38,0,0,98,142,
-	0,0,0,0,136,0,64,20,33,16,0,0,
-	33,136,160,2,43,0,32,18,33,128,128,2,
-	14,0,22,36,64,0,23,36,17,0,2,146,
-	0,0,0,0,34,0,66,48,33,0,64,20,
-	0,0,0,0,36,0,2,142,16,0,176,175,
-	12,0,66,140,24,0,4,142,28,0,5,142,
-	32,0,6,142,0,0,0,0,9,248,64,0,
-	33,56,64,2,17,0,2,146,0,0,0,0,
-	32,0,66,52,17,0,2,162,0,0,98,142,
-	0,0,0,0,16,0,64,16,0,0,0,0,
-	255,255,49,38,10,0,32,18,68,0,16,38,
-	17,0,3,146,0,0,0,0,32,0,98,48,
-	2,0,64,20,192,0,98,52,17,0,2,162,
-	255,255,49,38,248,255,32,22,68,0,16,38,
-	0,0,118,174,236,94,192,8,56,0,87,162,
-	255,255,49,38,217,255,32,22,68,0,16,38,
-	32,0,2,36,56,0,66,162,0,0,98,142,
-	0,0,0,0,13,0,64,20,64,0,2,36,
-	33,136,160,2,81,0,32,18,33,128,128,2,
-	17,0,2,146,0,0,0,0,2,0,66,48,
-	74,0,64,16,255,255,49,38,250,255,32,22,
-	68,0,16,38,49,95,192,8,33,16,0,0,
-	56,0,66,162,14,0,2,36,0,0,98,174,
-	33,136,160,2,53,0,32,18,33,128,128,2,
-	2,0,23,36,15,0,22,36,17,0,2,146,
-	0,0,0,0,194,0,66,48,5,0,64,16,
-	0,0,0,0,19,0,87,16,0,0,0,0,
-	32,95,192,8,255,255,49,38,64,0,2,142,
-	0,0,0,0,34,0,64,16,0,0,0,0,
-	16,0,176,175,64,0,2,142,24,0,4,142,
-	28,0,5,142,32,0,6,142,0,0,0,0,
-	9,248,64,0,33,56,64,2,17,0,2,146,
-	0,0,0,0,30,95,192,8,64,0,66,52,
-	64,0,2,142,0,0,0,0,13,0,64,16,
-	0,0,0,0,16,0,176,175,64,0,2,142,
-	24,0,4,142,28,0,5,142,32,0,6,142,
-	0,0,0,0,9,248,64,0,33,56,64,2,
-	17,0,2,146,0,0,0,0,30,95,192,8,
-	64,0,66,52,0,0,118,174,17,0,2,146,
-	0,0,0,0,128,0,66,52,17,0,2,162,
-	255,255,49,38,208,255,32,22,68,0,16,38,
-	33,136,160,2,12,0,32,18,33,128,128,2,
-	17,0,2,146,0,0,0,0,128,0,66,48,
-	5,0,64,16,255,255,49,38,250,255,32,22,
-	68,0,16,38,49,95,192,8,33,16,0,0,
-	49,95,192,8,1,0,2,36,33,16,0,0,
-	56,0,191,143,52,0,183,143,48,0,182,143,
-	44,0,181,143,40,0,180,143,36,0,179,143,
-	32,0,178,143,28,0,177,143,24,0,176,143,
-	8,0,224,3,64,0,189,39,184,255,189,39,
-	64,0,191,175,60,0,183,175,56,0,182,175,
-	52,0,181,175,48,0,180,175,44,0,179,175,
-	40,0,178,175,36,0,177,175,32,0,176,175,
-	33,160,128,0,112,0,147,142,0,0,0,0,
-	129,0,96,18,33,16,0,0,108,0,146,142,
-	0,0,0,0,125,0,64,18,96,0,151,38,
-	96,0,128,174,100,0,128,174,224,83,192,12,
-	33,32,64,2,33,168,64,0,5,0,160,22,
-	33,136,64,2,33,32,128,2,5,0,5,36,
-	123,95,192,8,33,48,0,0,36,0,64,18,
-	33,128,160,2,5,0,22,36,16,0,22,162,
-	8,0,100,142,12,0,101,142,0,0,0,0,
-	80,86,192,12,8,0,6,38,5,0,64,20,
-	0,0,0,0,255,255,49,38,68,0,115,38,
-	245,255,32,22,68,0,16,38,21,0,32,18,
-	42,16,50,2,7,0,64,16,33,128,160,2,
-	59,84,192,12,33,32,0,2,1,0,49,38,
-	42,16,50,2,251,255,64,20,68,0,16,38,
-	61,50,192,12,33,32,160,2,33,32,128,2,
-	5,0,5,36,123,95,192,8,33,48,0,0,
-	2,0,5,36,1,0,38,38,140,84,192,12,
-	0,0,0,0,203,95,192,8,1,0,2,36,
-	124,0,146,174,112,0,130,142,0,0,0,0,
-	128,0,130,174,112,0,149,174,33,128,160,2,
-	27,0,64,26,33,136,0,0,33,32,0,2,
-	33,40,128,2,96,72,192,12,1,0,6,36,
-	13,0,64,20,0,0,0,0,20,0,2,150,
-	0,0,0,0,1,0,66,48,8,0,64,16,
-	0,0,0,0,36,0,2,142,0,0,0,0,
-	3,0,66,144,0,0,0,0,1,0,66,48,
-	5,0,64,20,0,0,0,0,64,0,130,142,
-	0,0,0,0,221,255,64,16,33,32,128,2,
-	1,0,49,38,42,16,50,2,231,255,64,20,
-	68,0,16,38,40,0,64,18,33,128,160,2,
-	17,0,2,146,0,0,0,0,34,0,66,48,
-	32,0,64,20,0,0,0,0,36,0,2,142,
-	16,0,176,175,8,0,66,140,24,0,4,142,
-	28,0,5,142,32,0,6,142,0,0,0,0,
-	9,248,64,0,33,56,128,2,17,0,2,146,
-	0,0,0,0,32,0,66,52,17,0,2,162,
-	0,0,226,142,0,0,0,0,15,0,64,16,
-	0,0,0,0,255,255,82,38,15,0,64,18,
-	68,0,16,38,17,0,3,146,0,0,0,0,
-	32,0,98,48,2,0,64,20,34,0,98,52,
-	17,0,2,162,255,255,82,38,248,255,64,22,
-	68,0,16,38,203,95,192,8,33,16,0,0,
-	255,255,82,38,218,255,64,22,68,0,16,38,
-	33,16,0,0,64,0,191,143,60,0,183,143,
-	56,0,182,143,52,0,181,143,48,0,180,143,
-	44,0,179,143,40,0,178,143,36,0,177,143,
-	32,0,176,143,8,0,224,3,72,0,189,39,
-	0,0,0,0,0,0,0,0,37,115,58,37,
-	100,58,32,102,97,105,108,101,100,32,97,115,
-	115,101,114,116,105,111,110,32,96,37,115,39,
-	10,0,0,0,114,97,109,116,101,115,116,100,
-	119,40,98,99,46,98,99,95,104,101,97,112,
-	115,116,97,114,116,44,32,108,101,110,44,32,
-	49,44,32,48,44,32,48,41,32,61,61,32,
-	48,0,0,0,98,99,46,98,99,95,104,101,
-	97,112,101,110,100,32,60,61,32,98,99,46,
-	98,99,95,114,97,109,101,110,100,0,0,0,
-	35,32,112,111,114,116,115,58,32,37,100,10,
-	0,0,0,0,42,42,42,80,114,111,102,105,
-	108,105,110,103,32,64,32,37,120,44,32,37,
-	120,10,0,0,103,111,116,32,104,101,114,101,
-	32,99,97,117,115,101,61,37,120,32,115,116,
-	97,116,117,115,61,37,120,32,118,101,99,61,
-	37,120,10,0,37,115,58,37,100,58,32,102,
-	97,105,108,101,100,32,97,115,115,101,114,116,
-	105,111,110,32,96,37,115,39,10,0,0,0,
-	83,101,99,111,110,100,115,32,60,32,48,120,
-	55,70,70,70,102,102,102,102,0,0,0,0,
-	84,105,109,101,114,115,85,115,101,100,32,60,
-	32,78,84,73,77,69,82,83,0,0,0,0,
-	0,0,0,0,69,69,80,82,79,77,32,105,
-	115,32,98,97,100,10,0,0,80,111,114,116,
-	32,37,100,32,101,116,104,101,114,32,97,100,
-	100,114,101,115,115,58,32,37,48,50,88,58,
-	37,48,50,88,58,37,48,50,88,58,37,48,
-	50,88,58,37,48,50,88,58,37,48,50,88,
-	10,0,0,0,35,35,35,32,56,50,53,57,
-	54,32,67,104,97,110,32,37,100,58,32,115,
-	101,108,102,116,101,115,116,32,102,97,105,108,
-	101,100,32,40,37,120,41,10,0,0,0,0,
-	42,42,42,32,56,50,53,57,54,32,80,111,
-	114,116,32,37,100,58,32,115,101,108,102,116,
-	101,115,116,32,112,97,115,115,101,100,10,0,
-	56,50,53,57,54,32,80,111,114,116,32,37,
-	100,58,32,100,117,109,112,32,102,97,105,108,
-	101,100,32,40,37,120,41,10,0,0,0,0,
-	42,42,42,32,56,50,53,57,54,32,80,111,
-	114,116,32,37,100,58,32,100,117,109,112,32,
-	112,97,115,115,101,100,10,0,35,35,35,32,
-	56,50,53,57,54,32,80,111,114,116,32,37,
-	100,58,32,83,67,80,32,102,101,116,99,104,
-	32,102,97,105,108,101,100,10,0,0,0,0,
-	42,42,42,32,56,50,53,57,54,32,80,111,
-	114,116,32,37,100,58,32,83,67,80,32,102,
-	101,116,99,104,32,112,97,115,115,101,100,32,
-	37,120,32,10,0,0,0,0,35,35,35,32,
-	56,50,53,57,54,32,80,111,114,116,32,37,
-	100,58,32,66,85,83,84,73,77,69,82,83,
-	32,108,111,97,100,32,102,97,105,108,101,100,
-	10,0,0,0,42,42,42,32,56,50,53,57,
-	54,32,80,111,114,116,32,37,100,58,32,66,
-	85,83,84,73,77,69,82,83,32,108,111,97,
-	100,32,112,97,115,115,101,100,10,0,0,0,
-	35,35,35,32,65,67,75,32,100,105,100,32,
-	110,111,116,32,111,99,99,117,114,10,0,0,
-	35,35,35,32,115,116,97,116,117,115,32,115,
-	116,105,108,108,32,98,117,115,121,58,32,37,
-	120,10,0,0,101,116,104,95,105,110,105,116,
-	46,99,0,0,42,42,42,76,49,87,65,10,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,35,35,35,32,84,66,68,32,
-	98,108,111,99,107,115,32,97,114,101,110,39,
-	116,32,98,101,105,110,103,32,102,114,101,101,
-	100,10,0,0,65,116,116,101,109,112,116,32,
-	116,111,32,102,114,101,101,32,98,111,103,117,
-	115,32,84,66,68,32,37,120,10,0,0,0,
-	35,35,35,32,66,85,70,32,98,108,111,99,
-	107,115,32,97,114,101,110,39,116,32,98,101,
-	105,110,103,32,102,114,101,101,100,10,0,0,
-	65,116,116,101,109,112,116,32,116,111,32,102,
-	114,101,101,32,98,111,103,117,115,32,66,85,
-	70,32,37,120,10,0,0,0,0,0,0,0,
-	0,0,0,0,82,70,68,115,32,37,100,32,
-	10,0,0,0,82,66,68,115,32,37,100,32,
-	10,0,0,0,37,115,58,37,100,58,32,102,
-	97,105,108,101,100,32,97,115,115,101,114,116,
-	105,111,110,32,96,37,115,39,10,0,0,0,
-	101,116,104,95,114,99,118,46,99,0,0,0,
-	100,115,116,99,104,97,110,32,62,61,32,49,
-	32,38,38,32,100,115,116,99,104,97,110,32,
-	60,32,78,99,104,97,110,0,37,115,37,48,
-	50,88,58,37,48,50,88,58,37,48,50,88,
-	58,37,48,50,88,58,37,48,50,88,58,37,
-	48,50,88,37,115,0,0,0,176,72,0,131,
-	80,67,0,131,164,67,0,131,24,68,0,131,
-	80,67,0,131,0,0,0,0,4,82,0,131,
-	184,76,0,131,12,77,0,131,128,77,0,131,
-	184,76,0,131,0,0,0,0,0,0,0,0,
-	0,0,0,0,37,115,58,37,100,58,32,102,
-	97,105,108,101,100,32,97,115,115,101,114,116,
-	105,111,110,32,96,37,115,39,10,0,0,0,
-	101,116,104,95,120,109,105,116,46,99,0,0,
-	99,98,112,45,62,110,111,112,46,99,109,100,
-	32,61,61,32,73,53,57,54,95,67,66,95,
-	67,77,68,95,78,79,80,124,73,53,57,54,
-	95,67,66,95,67,77,68,95,69,76,0,0,
-	99,98,112,45,62,110,111,112,46,99,109,100,
-	32,38,32,73,53,57,54,95,67,66,95,67,
-	77,68,0,0,112,45,62,115,99,98,112,45,
-	62,115,116,97,116,117,115,32,38,32,73,53,
-	57,54,95,83,67,66,95,67,78,65,0,0,
-	35,35,35,32,99,109,100,32,115,116,105,108,
-	108,32,98,117,115,121,58,32,37,120,10,0,
-	37,100,61,37,100,44,37,120,44,37,100,10,
-	0,0,0,0,39,37,115,39,32,37,120,32,
-	37,120,10,0,37,48,56,120,58,32,37,48,
-	50,120,10,0,37,48,56,120,58,32,37,48,
-	52,120,10,0,37,48,56,120,58,32,37,48,
-	56,120,10,0,108,105,110,107,32,115,116,97,
-	116,101,32,37,48,50,120,10,0,0,0,0,
-	42,42,42,32,103,111,116,32,37,100,32,105,
-	110,116,101,114,114,117,112,116,115,10,0,0,
-	35,35,35,32,69,120,112,101,99,116,101,100,
-	32,37,100,32,98,117,116,32,103,111,116,32,
-	37,100,32,105,110,116,101,114,114,117,112,116,
-	115,10,0,0,80,76,88,57,48,54,48,32,
-	65,100,100,114,101,115,115,32,61,32,37,88,
-	32,68,65,84,65,32,61,32,37,88,32,10,
-	0,0,0,0,42,42,42,32,87,114,105,116,
-	101,32,111,102,32,37,120,32,116,111,32,37,
-	100,32,102,97,105,108,101,100,10,0,0,0,
-	42,42,42,32,87,114,105,116,101,32,111,102,
-	32,37,120,32,116,111,32,37,120,32,102,97,
-	105,108,101,100,10,0,0,0,42,42,42,42,
-	42,42,42,42,42,42,42,42,42,42,42,42,
-	0,0,0,0,42,42,42,32,73,108,108,101,
-	103,97,108,32,99,111,109,109,97,110,100,32,
-	39,37,115,39,10,0,0,0,45,45,45,32,
-	99,111,109,109,97,110,100,115,32,109,44,116,
-	44,101,44,69,44,97,44,120,44,108,44,115,
-	44,112,32,99,97,110,32,98,101,32,112,114,
-	101,102,105,120,101,100,32,119,105,116,104,32,
-	97,32,114,101,112,101,97,116,32,99,111,117,
-	110,116,0,0,108,32,120,112,111,114,116,32,
-	114,112,111,114,116,32,91,108,101,110,93,32,
-	32,32,32,32,32,32,32,32,32,76,111,111,
-	112,98,97,99,107,32,116,101,115,116,32,102,
-	114,111,109,32,120,112,111,114,116,32,40,49,
-	45,54,41,32,116,111,32,114,112,111,114,116,
-	32,40,49,45,54,41,0,0,105,32,32,32,
-	32,32,32,32,32,32,73,110,116,101,114,114,
-	117,112,116,32,72,111,115,116,32,32,124,32,
-	32,115,32,91,112,111,114,116,93,32,91,108,
-	101,110,93,32,66,97,99,107,50,98,97,99,
-	107,32,120,109,105,116,32,99,110,116,32,112,
-	97,99,107,101,116,115,0,0,80,32,32,32,
-	32,32,32,32,32,32,84,101,115,116,32,80,
-	76,88,32,57,48,54,48,32,32,32,124,32,
-	32,100,32,91,114,124,119,124,108,124,116,93,
-	32,91,118,97,108,124,39,99,39,93,32,32,
-	82,101,97,100,47,87,114,105,116,101,47,76,
-	111,111,112,47,84,105,109,101,32,68,77,65,
-	0,0,0,0,76,32,32,32,32,32,32,32,
-	32,32,82,101,97,100,32,76,105,110,107,32,
-	76,69,68,115,32,32,124,32,32,112,32,114,
-	101,103,110,111,32,91,118,97,108,93,32,32,
-	82,101,97,100,47,91,119,114,105,116,101,93,
-	32,80,76,88,32,114,101,103,105,115,116,101,
-	114,0,0,0,65,32,97,100,100,114,32,32,
-	32,32,83,101,116,32,101,116,104,101,114,32,
-	97,100,100,114,32,32,124,32,32,36,32,115,
-	99,114,105,112,116,32,32,32,32,32,32,32,
-	82,101,97,100,32,99,109,100,115,32,102,114,
-	111,109,32,102,105,108,101,32,39,115,99,114,
-	105,112,116,39,0,0,0,0,120,32,91,112,
-	111,114,116,93,32,32,84,120,32,101,116,104,
-	101,114,32,32,32,32,32,32,32,32,124,32,
-	32,82,32,91,112,111,114,116,93,32,32,32,
-	32,32,32,32,82,120,32,101,116,104,101,114,
-	32,91,111,110,32,112,111,114,116,32,49,45,
-	54,93,0,0,72,32,32,32,32,32,32,32,
-	32,32,84,111,103,103,108,101,32,70,67,67,
-	32,116,101,115,116,32,124,32,32,113,44,94,
-	68,44,94,90,32,32,32,32,32,32,32,32,
-	81,117,105,116,0,0,0,0,97,32,32,32,
-	32,32,32,32,32,32,84,101,115,116,32,97,
-	108,108,32,32,32,32,32,32,32,32,124,32,
-	32,90,32,109,115,101,99,115,32,32,32,32,
-	32,32,32,32,80,97,117,115,101,32,102,111,
-	114,32,97,32,119,104,105,108,101,0,0,0,
-	69,32,32,32,32,32,32,32,32,32,84,101,
-	115,116,32,69,69,80,82,79,77,32,32,32,
-	32,32,124,32,32,83,114,32,97,100,100,114,
-	59,32,83,119,32,97,100,100,114,32,118,97,
-	108,59,32,32,82,101,97,100,47,87,114,105,
-	116,101,32,80,76,88,32,69,50,32,114,101,
-	103,0,0,0,101,32,91,112,111,114,116,93,
-	32,32,84,101,115,116,32,101,116,104,101,114,
-	110,101,116,32,32,32,124,32,32,69,114,32,
-	97,100,100,114,59,32,69,119,32,97,100,100,
-	114,32,118,97,108,59,32,32,82,101,97,100,
-	47,87,114,105,116,101,32,69,69,80,82,79,
-	77,32,114,101,103,0,0,0,116,32,32,32,
-	32,32,32,32,32,32,84,101,115,116,32,116,
-	105,109,101,114,115,32,32,32,32,32,124,32,
-	32,119,91,42,93,32,97,100,100,114,32,118,
-	97,108,32,32,87,114,105,116,101,32,109,101,
-	109,111,114,121,58,32,119,98,32,119,104,44,
-	32,119,119,44,32,119,116,0,109,32,32,32,
-	32,32,32,32,32,32,84,101,115,116,32,109,
-	101,109,111,114,121,32,32,32,32,32,124,32,
-	32,114,91,42,93,32,97,100,100,114,32,32,
-	32,32,32,32,82,101,97,100,32,109,101,109,
-	111,114,121,58,32,114,98,32,114,104,44,32,
-	114,119,44,32,114,116,0,0,42,42,42,32,
-	82,105,103,104,116,83,119,105,116,99,104,32,
-	68,105,97,103,110,111,115,116,105,99,115,32,
-	109,101,110,117,32,42,42,42,0,0,0,0,
-	45,45,45,32,84,104,114,101,101,32,99,111,
-	112,105,101,115,32,111,102,32,97,100,100,114,
-	101,115,115,32,100,111,32,110,111,116,32,97,
-	103,114,101,101,33,10,0,0,45,45,45,32,
-	69,116,104,101,114,32,65,100,100,114,101,115,
-	115,32,78,111,116,32,83,101,116,33,10,0,
-	45,45,45,32,69,116,104,101,114,32,65,100,
-	100,114,101,115,115,32,105,115,32,97,32,109,
-	117,108,116,105,99,97,115,116,32,97,100,100,
-	114,101,115,115,33,10,0,0,42,42,42,32,
-	37,48,50,88,37,48,50,88,37,48,50,88,
-	58,37,48,50,88,58,37,48,50,88,37,48,
-	50,88,10,0,45,45,45,32,70,105,114,115,
-	116,32,98,121,116,101,32,40,37,48,50,88,
-	41,32,105,115,32,97,32,98,114,111,97,100,
-	99,97,115,116,32,97,100,100,114,101,115,115,
-	10,0,0,0,45,45,45,32,76,97,115,116,
-	32,100,105,103,105,116,32,109,117,115,116,32,
-	98,101,32,48,32,111,114,32,56,10,0,0,
-	42,42,42,32,69,105,103,104,116,32,101,116,
-	104,101,114,110,101,116,32,97,100,100,114,101,
-	115,115,101,115,32,104,97,118,101,32,98,101,
-	101,110,32,117,115,101,100,58,10,0,0,0,
-	42,42,42,32,80,111,114,116,32,37,100,32,
-	101,116,104,101,114,110,101,116,32,97,100,100,
-	114,101,115,115,32,105,115,32,0,0,0,0,
-	45,45,45,32,66,97,100,32,101,116,104,101,
-	114,32,97,100,100,114,101,115,115,32,39,37,
-	115,39,32,115,112,101,99,105,102,105,101,100,
-	10,0,0,0,0,0,0,0,244,101,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,244,101,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,64,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,28,111,0,131,104,112,0,131,
-	104,112,0,131,132,111,0,131,152,109,0,131,
-	104,112,0,131,104,112,0,131,244,101,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	24,107,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,76,108,0,131,104,112,0,131,
-	228,108,0,131,112,110,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	28,109,0,131,104,112,0,131,48,111,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	104,112,0,131,104,112,0,131,104,112,0,131,
-	84,109,0,131,104,112,0,131,104,112,0,131,
-	32,112,0,131,136,106,0,131,28,106,0,131,
-	104,112,0,131,104,112,0,131,52,107,0,131,
-	104,112,0,131,104,112,0,131,252,106,0,131,
-	88,111,0,131,104,112,0,131,104,112,0,131,
-	196,107,0,131,104,112,0,131,180,104,0,131,
-	168,106,0,131,92,106,0,131,104,112,0,131,
-	104,112,0,131,148,105,0,131,192,106,0,131,
-	0,0,0,0,188,111,0,131,204,111,0,131,
-	12,112,0,131,12,112,0,131,12,112,0,131,
-	12,112,0,131,12,112,0,131,12,112,0,131,
-	12,112,0,131,12,112,0,131,12,112,0,131,
-	12,112,0,131,252,111,0,131,12,112,0,131,
-	12,112,0,131,12,112,0,131,12,112,0,131,
-	236,111,0,131,12,112,0,131,12,112,0,131,
-	12,112,0,131,12,112,0,131,220,111,0,131,
-	252,111,0,131,0,0,0,0,0,0,0,0,
-	42,42,42,32,69,69,80,82,79,77,32,80,
-	97,115,115,101,100,10,0,0,33,33,33,32,
-	69,69,80,82,79,77,32,70,97,105,108,117,
-	114,101,58,32,87,114,111,116,101,32,37,48,
-	52,120,32,97,116,32,37,100,44,32,103,111,
-	116,32,37,48,52,120,10,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,35,35,35,70,
-	114,97,109,101,32,37,100,32,100,105,100,32,
-	110,111,116,32,97,114,114,105,118,101,10,0,
-	35,35,35,32,70,114,97,109,101,32,37,100,
-	44,32,108,101,110,32,37,100,44,32,98,121,
-	116,101,32,37,100,44,32,119,97,110,116,32,
-	37,120,32,103,111,116,32,37,120,10,0,0,
-	35,35,35,70,114,97,109,101,32,37,100,32,
-	119,114,111,110,103,32,108,101,110,103,116,104,
-	32,40,119,97,110,116,32,37,100,32,103,111,
-	116,32,37,100,41,10,0,0,35,35,35,70,
-	114,97,109,101,32,37,100,58,32,103,111,116,
-	32,115,101,113,32,37,100,10,0,0,0,0,
-	35,35,35,32,37,100,32,67,82,67,32,101,
-	114,114,111,114,115,32,111,99,99,117,114,101,
-	100,10,0,0,35,35,35,32,37,100,32,65,
-	108,105,103,110,32,101,114,114,111,114,115,32,
-	111,99,99,117,114,101,100,10,0,0,0,0,
-	35,35,35,32,37,100,32,83,104,111,114,116,
-	32,101,114,114,111,114,115,32,111,99,99,117,
-	114,101,100,10,0,0,0,0,35,35,35,32,
-	37,100,32,79,118,101,114,114,117,110,32,101,
-	114,114,111,114,115,32,111,99,99,117,114,101,
-	100,10,0,0,35,35,35,32,67,85,32,115,
-	116,105,108,108,32,114,117,110,110,105,110,103,
-	58,32,37,120,10,0,0,0,35,35,35,32,
-	99,109,100,32,115,116,105,108,108,32,98,117,
-	115,121,58,32,37,120,10,0,35,35,35,32,
-	115,116,97,116,117,115,32,115,116,105,108,108,
-	32,98,117,115,121,58,32,37,120,10,0,0,
-	67,66,61,37,120,44,32,84,66,68,61,37,
-	120,44,32,66,85,70,61,37,120,10,0,0,
-	116,101,115,116,95,101,116,104,101,114,46,99,
-	0,0,0,0,37,100,32,102,114,97,109,101,
-	115,32,111,102,32,108,101,110,103,116,104,32,
-	37,100,32,115,101,110,116,32,105,110,32,37,
-	100,32,109,115,101,99,115,10,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	42,42,42,32,56,50,53,52,32,84,105,109,
-	101,114,32,48,32,79,75,44,32,99,111,117,
-	110,116,32,119,97,115,32,37,100,10,0,0,
-	42,42,42,32,56,50,53,52,32,84,105,109,
-	101,114,32,48,32,110,111,116,32,105,110,116,
-	101,114,114,117,112,116,105,110,103,32,37,100,
-	10,0,0,0,42,42,42,32,56,50,53,52,
-	32,84,105,109,101,114,32,48,32,115,112,101,
-	101,100,32,119,114,111,110,103,44,32,103,111,
-	116,32,37,100,32,115,104,111,117,108,100,32,
-	98,101,32,49,48,48,48,10,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	9,37,120,58,32,119,97,110,116,32,37,120,
-	32,103,111,116,32,37,120,10,0,0,0,0,
-	45,45,45,32,82,65,77,32,84,101,115,116,
-	32,111,102,32,37,120,32,116,111,32,37,120,
-	32,102,97,105,108,101,100,10,0,0,0,0,
-	42,42,42,32,82,65,77,32,84,101,115,116,
-	32,111,102,32,37,120,32,116,111,32,37,120,
-	32,112,97,115,115,101,100,10,0,0,0,0,
-	35,35,35,32,68,77,65,32,68,79,78,69,
-	32,110,101,118,101,114,32,111,99,99,117,114,
-	114,101,100,46,32,32,99,115,114,32,61,32,
-	37,120,10,0,35,35,35,32,72,111,115,116,
-	32,110,101,118,101,114,32,103,111,116,32,68,
-	77,65,32,105,110,116,101,114,114,117,112,116,
-	46,32,98,99,95,99,110,116,32,61,32,37,
-	100,10,0,0,35,35,35,32,68,77,65,32,
-	101,114,114,111,114,32,97,116,32,105,110,100,
-	101,120,32,37,100,58,32,119,97,110,116,101,
-	100,32,37,48,50,120,32,103,111,116,32,37,
-	48,50,120,10,0,0,0,0,35,35,35,32,
-	73,108,108,101,103,97,108,32,72,111,115,116,
-	32,97,100,100,114,32,40,61,37,120,41,32,
-	111,114,32,108,101,110,103,116,104,32,40,61,
-	37,100,41,10,0,0,0,0,35,35,35,32,
-	67,111,117,110,116,32,99,97,110,110,111,116,
-	32,98,101,32,62,32,49,48,50,52,42,49,
-	48,50,52,10,0,0,0,0,42,42,42,32,
-	108,99,108,46,66,117,102,49,32,61,32,37,
-	120,32,45,45,62,32,104,111,115,116,46,66,
-	117,102,32,61,32,37,120,32,45,45,62,32,
-	108,99,108,46,66,117,102,50,32,61,32,37,
-	120,10,0,0,42,42,42,32,62,32,68,98,
-	32,37,100,32,40,98,117,114,115,116,41,59,
-	32,62,32,68,119,32,37,100,32,40,119,97,
-	105,116,115,116,97,116,101,115,41,10,0,0,
-	35,35,35,32,83,101,99,111,110,100,32,97,
-	114,103,32,109,117,115,116,32,98,101,32,39,
-	114,39,32,111,114,32,39,119,39,32,111,114,
-	32,39,108,39,10,0,0,0,42,42,42,32,
-	68,77,65,32,37,115,32,105,110,32,37,52,
-	100,32,98,121,116,101,32,99,104,117,110,107,
-	115,58,32,0,32,32,116,111,32,104,111,115,
-	116,0,0,0,102,114,111,109,32,104,111,115,
-	116,0,0,0,37,56,100,32,98,121,116,101,
-	115,47,115,101,99,46,10,0,116,105,109,101,
-	32,116,111,111,32,115,104,111,114,116,32,116,
-	111,32,109,101,97,115,117,114,101,10,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	80,37,100,45,62,37,115,32,10,0,0,0,
-	116,114,97,110,115,109,105,116,32,112,101,110,
-	100,105,110,103,32,111,110,32,37,100,10,0,
-	116,114,97,110,115,109,105,116,32,99,111,110,
-	102,105,103,32,111,110,32,37,100,10,0,0,
-	116,114,97,110,115,109,105,116,32,116,99,110,
-	10,0,0,0,116,99,110,32,101,120,112,10,
-	0,0,0,0,102,111,114,119,97,114,100,95,
-	100,101,108,97,121,32,101,120,112,32,37,100,
-	10,0,0,0,109,101,115,115,97,103,101,95,
-	97,103,101,32,101,120,112,32,37,100,10,0,
-	104,111,108,100,32,101,120,112,32,37,100,10,
-	0,0,0,0,84,120,67,79,78,70,73,71,
-	37,100,10,0,84,120,84,67,78,37,100,10,
-	0,0,0,0,114,99,118,32,99,111,110,102,
-	105,103,32,111,110,32,37,100,10,0,0,0,
-	90,69,82,79,32,114,111,111,116,33,32,97,
-	116,32,37,120,32,0,0,0,115,117,112,101,
-	114,99,101,100,101,115,32,37,100,10,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	65,82,80,82,69,81,32,37,120,33,10,0,
-	65,82,80,82,69,80,32,37,120,33,10,0,
-	83,101,110,100,32,85,68,80,32,37,100,10,
-	0,0,0,0,78,111,32,82,66,68,39,115,
-	32,105,110,32,85,68,80,32,40,37,100,32,
-	37,100,41,10,0,0,0,0,83,101,110,116,
-	32,85,68,80,32,37,100,10,0,0,0,0,
-	83,78,77,80,32,39,37,99,39,32,108,101,
-	110,32,37,100,10,0,0,0,69,110,118,111,
-	121,32,114,99,61,37,100,10,0,0,0,0,
-	71,101,110,32,116,114,97,112,32,37,100,32,
-	114,99,61,37,100,10,0,0,66,97,100,32,
-	85,68,80,32,99,104,101,99,107,115,117,109,
-	32,37,120,32,108,101,110,32,37,100,10,0,
-	66,97,100,32,85,68,80,32,108,101,110,103,
-	116,104,32,119,97,110,116,32,37,100,32,103,
-	111,116,32,37,100,10,0,0,66,97,100,32,
-	73,67,77,80,32,99,104,101,99,107,115,117,
-	109,10,0,0,78,111,32,82,66,68,39,115,
-	32,105,110,32,73,67,77,80,10,0,0,0,
-	66,97,100,32,73,80,32,99,104,101,99,107,
-	115,117,109,10,0,0,0,0,84,114,117,110,
-	99,97,116,101,100,32,73,80,10,0,0,0,
-	83,69,78,84,32,73,80,88,33,10,0,0,
-	110,111,32,115,121,115,78,97,109,101,0,0,
-	114,105,103,104,116,115,119,105,116,99,104,45,
-	0,0,0,0,78,111,32,82,66,68,39,115,
-	32,105,110,32,115,101,110,100,95,115,97,112,
-	10,0,0,0,78,111,32,82,66,68,39,115,
-	32,105,110,32,73,80,88,10,0,0,0,0,
-	84,114,117,110,99,97,116,101,100,32,73,80,
-	88,10,0,0,0,0,0,0,0,0,0,0,
-	77,97,108,108,111,99,32,114,101,116,117,114,
-	110,115,32,78,85,76,76,33,0,0,0,0,
-	0,0,0,0,0,0,0,0,68,105,103,105,
-	32,73,110,116,108,46,32,82,105,103,104,116,
-	83,119,105,116,99,104,32,83,69,45,88,0,
-	73,110,116,101,108,32,56,50,53,57,54,0,
-	0,0,0,0,0,0,0,0,8,206,0,131,
-	36,206,0,131,92,206,0,131,112,206,0,131,
-	132,206,0,131,220,206,0,131,4,207,0,131,
-	4,207,0,131,36,207,0,131,52,207,0,131,
-	80,207,0,131,104,207,0,131,132,207,0,131,
-	160,207,0,131,188,207,0,131,188,207,0,131,
-	216,207,0,131,240,207,0,131,12,208,0,131,
-	40,208,0,131,72,208,0,131,112,208,0,131,
-	180,210,0,131,232,210,0,131,4,211,0,131,
-	36,211,0,131,60,211,0,131,0,0,0,0,
-	64,213,0,131,92,213,0,131,124,213,0,131,
-	160,213,0,131,60,214,0,131,60,214,0,131,
-	60,214,0,131,188,213,0,131,216,213,0,131,
-	244,213,0,131,28,214,0,131,168,214,0,131,
-	60,214,0,131,168,214,0,131,168,214,0,131,
-	88,214,0,131,132,214,0,131,0,0,0,0,
-	36,216,0,131,68,216,0,131,104,216,0,131,
-	140,216,0,131,140,216,0,131,0,0,0,0,
-	248,217,0,131,12,218,0,131,40,218,0,131,
-	76,218,0,131,124,218,0,131,152,218,0,131,
-	200,218,0,131,228,218,0,131,88,219,0,131,
-	116,219,0,131,64,224,0,131,92,224,0,131,
-	124,224,0,131,152,224,0,131,184,224,0,131,
-	0,0,0,0,110,111,32,115,121,115,67,111,
-	110,116,97,99,116,0,0,0,110,111,32,115,
-	121,115,78,97,109,101,0,0,110,111,32,115,
-	121,115,76,111,99,97,116,105,111,110,0,0,
-	37,115,58,37,100,58,32,102,97,105,108,101,
-	100,32,97,115,115,101,114,116,105,111,110,32,
-	96,37,115,39,10,0,0,0,110,117,109,114,
-	101,103,115,32,60,61,32,78,86,82,65,77,
-	95,78,82,69,71,83,32,38,38,32,110,117,
-	109,114,101,103,115,32,62,32,48,0,0,0,
-	102,105,114,115,116,114,101,103,32,60,32,78,
-	86,82,65,77,95,78,82,69,71,83,32,38,
-	38,32,102,105,114,115,116,114,101,103,32,62,
-	61,32,48,0,0,0,0,0,10,13,69,82,
-	82,79,82,32,45,0,0,0,0,0,0,0,
-	192,244,0,131,8,252,0,131,8,252,0,131,
-	8,252,0,131,8,252,0,131,8,252,0,131,
-	8,252,0,131,8,252,0,131,192,251,0,131,
-	8,252,0,131,8,252,0,131,200,251,0,131,
-	212,251,0,131,212,251,0,131,212,251,0,131,
-	212,251,0,131,212,251,0,131,212,251,0,131,
-	212,251,0,131,212,251,0,131,212,251,0,131,
-	8,252,0,131,8,252,0,131,8,252,0,131,
-	8,252,0,131,8,252,0,131,8,252,0,131,
-	8,252,0,131,8,252,0,131,8,252,0,131,
-	8,252,0,131,8,252,0,131,200,244,0,131,
-	8,252,0,131,8,252,0,131,8,252,0,131,
-	8,252,0,131,8,252,0,131,8,252,0,131,
-	8,252,0,131,8,252,0,131,8,252,0,131,
-	8,252,0,131,8,252,0,131,8,252,0,131,
-	8,252,0,131,8,252,0,131,8,252,0,131,
-	8,252,0,131,8,252,0,131,8,252,0,131,
-	212,249,0,131,8,252,0,131,8,252,0,131,
-	8,252,0,131,8,252,0,131,8,252,0,131,
-	8,252,0,131,8,252,0,131,8,252,0,131,
-	8,252,0,131,20,245,0,131,8,245,0,131,
-	84,247,0,131,8,252,0,131,8,252,0,131,
-	8,252,0,131,8,252,0,131,8,252,0,131,
-	8,252,0,131,8,252,0,131,244,251,0,131,
-	8,252,0,131,8,252,0,131,48,246,0,131,
-	8,252,0,131,8,252,0,131,8,252,0,131,
-	240,250,0,131,8,252,0,131,132,248,0,131,
-	8,252,0,131,8,252,0,131,160,249,0,131,
-	72,46,1,131,228,47,1,131,152,46,1,131,
-	132,47,1,131,0,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,228,47,1,131,
-	228,47,1,131,228,47,1,131,144,47,1,131,
-	108,46,1,131,108,46,1,131,108,46,1,131,
-	152,46,1,131,152,46,1,131,228,47,1,131,
-	108,46,1,131,20,50,1,131,216,50,1,131,
-	56,50,1,131,224,50,1,131,104,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	216,50,1,131,216,50,1,131,216,50,1,131,
-	144,50,1,131,20,50,1,131,20,50,1,131,
-	20,50,1,131,56,50,1,131,56,50,1,131,
-	216,50,1,131,20,50,1,131,124,53,1,131,
-	96,53,1,131,96,53,1,131,96,53,1,131,
-	96,53,1,131,96,53,1,131,96,53,1,131,
-	96,53,1,131,96,53,1,131,96,53,1,131,
-	96,53,1,131,96,53,1,131,96,53,1,131,
-	96,53,1,131,88,53,1,131,64,53,1,131,
-	80,53,1,131,72,53,1,131,64,53,1,131,
-	0,0,0,0,28,83,1,131,36,83,1,131,
-	36,83,1,131,36,83,1,131,36,83,1,131,
-	28,83,1,131,44,83,1,131,44,83,1,131,
-	44,83,1,131,44,83,1,131,44,83,1,131,
-	28,83,1,131,44,83,1,131,0,0,0,0,
-	196,88,1,131,232,88,1,131,208,88,1,131,
-	220,88,1,131,244,88,1,131,0,0,0,0,
-	4,0,0,0,5,0,0,0,6,0,0,0,
-	7,0,0,0,2,0,0,0,3,0,0,0,
-	0,0,0,0,1,0,0,0,72,30,0,131,
-	72,30,0,131,216,44,0,131,0,30,0,131,
-	108,30,0,131,108,30,0,131,108,30,0,131,
-	108,30,0,131,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,20,137,1,131,
-	204,136,1,131,132,136,1,131,56,136,1,131,
-	236,135,1,131,172,135,1,131,120,135,1,131,
-	52,135,1,131,232,134,1,131,160,134,1,131,
-	80,134,1,131,8,134,1,131,188,133,1,131,
-	120,133,1,131,0,0,0,0,0,0,0,0,
-	72,72,72,72,72,72,72,72,72,72,72,72,
-	72,72,72,72,72,72,72,72,72,72,72,72,
-	72,72,72,72,72,72,72,72,72,72,72,72,
-	72,72,72,72,72,72,72,72,72,72,72,72,
-	72,72,72,72,72,72,72,72,72,72,72,72,
-	72,72,72,72,72,72,72,72,72,72,72,72,
-	72,72,72,72,72,0,0,0,0,255,85,170,
-	0,0,0,0,4,0,8,0,16,0,32,0,
-	64,0,0,1,0,8,0,0,0,0,0,0,
-	0,0,0,0,0,4,3,2,1,0,0,0,
-	7,0,0,0,1,0,1,0,1,0,2,0,
-	20,0,15,0,1,0,0,128,128,0,0,0,
-	100,0,0,0,96,207,1,131,92,207,1,131,
-	88,207,1,131,84,207,1,131,80,207,1,131,
-	0,0,0,0,0,0,0,0,48,49,50,51,
-	52,53,54,55,56,57,65,66,67,68,69,70,
-	0,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,64,204,0,131,156,202,0,131,
-	96,148,1,131,1,0,4,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	200,155,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,124,204,0,131,156,202,0,131,
-	168,210,1,131,1,0,6,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	4,156,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,132,204,0,131,156,202,0,131,
-	4,1,0,163,1,0,67,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	64,156,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,168,204,0,131,248,204,0,131,
-	80,18,3,131,1,0,4,3,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	124,156,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,168,204,0,131,32,205,0,131,
-	96,18,3,131,1,0,4,3,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	184,156,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,168,204,0,131,72,205,0,131,
-	112,18,3,131,1,0,4,3,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	244,156,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,112,205,0,131,156,202,0,131,
-	2,0,0,0,1,0,2,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	48,157,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,0,0,
-	220,155,1,131,2,0,0,0,24,156,1,131,
-	3,0,0,0,84,156,1,131,4,0,0,0,
-	144,156,1,131,5,0,0,0,204,156,1,131,
-	6,0,0,0,8,157,1,131,7,0,0,0,
-	68,157,1,131,0,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,120,205,0,131,
-	156,202,0,131,48,211,1,131,1,0,2,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,172,157,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,2,1,180,208,0,131,132,205,0,131,
-	164,202,0,131,76,209,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,4,1,180,208,0,131,
-	132,205,0,131,164,202,0,131,76,209,0,131,
-	124,148,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,2,1,
-	180,208,0,131,132,205,0,131,164,202,0,131,
-	76,209,0,131,6,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,2,1,180,208,0,131,132,205,0,131,
-	164,202,0,131,76,209,0,131,220,5,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,66,1,180,208,0,131,
-	132,205,0,131,164,202,0,131,76,209,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,4,1,
-	180,208,0,131,132,205,0,131,164,202,0,131,
-	76,209,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,2,3,180,208,0,131,132,205,0,131,
-	228,209,0,131,76,209,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,2,1,180,208,0,131,
-	132,205,0,131,164,202,0,131,76,209,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,67,1,
-	180,208,0,131,132,205,0,131,164,202,0,131,
-	76,209,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,65,1,180,208,0,131,132,205,0,131,
-	164,202,0,131,76,209,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,65,1,180,208,0,131,
-	132,205,0,131,164,202,0,131,76,209,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,65,1,
-	180,208,0,131,132,205,0,131,164,202,0,131,
-	76,209,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,65,1,180,208,0,131,132,205,0,131,
-	164,202,0,131,76,209,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,65,1,180,208,0,131,
-	132,205,0,131,164,202,0,131,76,209,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,65,1,
-	180,208,0,131,132,205,0,131,164,202,0,131,
-	76,209,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,65,1,180,208,0,131,132,205,0,131,
-	164,202,0,131,76,209,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,65,1,180,208,0,131,
-	132,205,0,131,164,202,0,131,76,209,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,65,1,
-	180,208,0,131,132,205,0,131,164,202,0,131,
-	76,209,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,65,1,180,208,0,131,132,205,0,131,
-	164,202,0,131,76,209,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,65,1,180,208,0,131,
-	132,205,0,131,164,202,0,131,76,209,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,66,1,
-	180,208,0,131,132,205,0,131,164,202,0,131,
-	76,209,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,6,1,180,208,0,131,132,205,0,131,
-	164,202,0,131,76,209,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,0,0,232,157,1,131,
-	2,0,0,0,16,158,1,131,3,0,0,0,
-	56,158,1,131,4,0,0,0,96,158,1,131,
-	5,0,0,0,136,158,1,131,6,0,0,0,
-	176,158,1,131,7,0,0,0,216,158,1,131,
-	8,0,0,0,0,159,1,131,9,0,0,0,
-	40,159,1,131,10,0,0,0,80,159,1,131,
-	11,0,0,0,120,159,1,131,12,0,0,0,
-	160,159,1,131,13,0,0,0,200,159,1,131,
-	14,0,0,0,240,159,1,131,15,0,0,0,
-	24,160,1,131,16,0,0,0,64,160,1,131,
-	17,0,0,0,104,160,1,131,18,0,0,0,
-	144,160,1,131,19,0,0,0,184,160,1,131,
-	20,0,0,0,224,160,1,131,21,0,0,0,
-	8,161,1,131,22,0,0,0,48,161,1,131,
-	0,0,0,0,0,0,0,0,1,0,0,0,
-	32,208,1,131,0,0,0,0,0,0,0,0,
-	1,0,0,0,192,157,1,131,2,0,0,0,
-	40,208,1,131,0,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,112,205,0,131,
-	60,210,0,131,2,0,0,0,1,0,2,3,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,56,162,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,120,205,0,131,
-	60,210,0,131,0,17,3,131,1,0,2,3,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,116,162,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,4,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,176,162,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,8,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,236,162,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,12,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,40,163,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,16,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,100,163,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,20,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,160,163,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,24,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,220,163,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,28,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,24,164,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,32,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,84,164,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,36,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,144,164,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,40,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,204,164,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,120,205,0,131,
-	156,202,0,131,44,17,3,131,1,0,2,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,8,165,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,48,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,68,165,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,52,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,128,165,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,56,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,188,165,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,60,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,248,165,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,64,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,52,166,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,68,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,112,166,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,64,1,44,202,0,131,88,210,0,131,
-	164,202,0,131,120,211,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,2,1,44,202,0,131,
-	88,210,0,131,164,202,0,131,120,211,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,64,1,
-	44,202,0,131,88,210,0,131,164,202,0,131,
-	120,211,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,2,1,44,202,0,131,88,210,0,131,
-	164,202,0,131,120,211,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,2,1,44,202,0,131,
-	88,210,0,131,164,202,0,131,120,211,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,0,0,
-	172,166,1,131,2,0,0,0,212,166,1,131,
-	3,0,0,0,252,166,1,131,4,0,0,0,
-	36,167,1,131,5,0,0,0,76,167,1,131,
-	0,0,0,0,0,0,0,0,1,0,0,0,
-	56,208,1,131,0,0,0,0,0,0,0,0,
-	1,0,64,3,84,212,0,131,16,212,0,131,
-	52,212,0,131,172,212,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,2,3,84,212,0,131,
-	16,212,0,131,52,212,0,131,172,212,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,2,3,
-	84,212,0,131,16,212,0,131,52,212,0,131,
-	172,212,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,2,3,84,212,0,131,16,212,0,131,
-	52,212,0,131,172,212,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,2,3,84,212,0,131,
-	16,212,0,131,52,212,0,131,172,212,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,2,3,
-	84,212,0,131,16,212,0,131,52,212,0,131,
-	172,212,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,64,3,84,212,0,131,16,212,0,131,
-	52,212,0,131,172,212,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,2,3,84,212,0,131,
-	16,212,0,131,52,212,0,131,172,212,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,2,1,
-	84,212,0,131,16,212,0,131,164,202,0,131,
-	172,212,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,2,3,84,212,0,131,16,212,0,131,
-	52,212,0,131,172,212,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,64,3,84,212,0,131,
-	16,212,0,131,52,212,0,131,172,212,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,2,3,
-	84,212,0,131,16,212,0,131,52,212,0,131,
-	172,212,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,6,1,84,212,0,131,16,212,0,131,
-	164,202,0,131,172,212,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,0,0,180,167,1,131,
-	2,0,0,0,220,167,1,131,3,0,0,0,
-	4,168,1,131,4,0,0,0,44,168,1,131,
-	5,0,0,0,84,168,1,131,6,0,0,0,
-	124,168,1,131,7,0,0,0,164,168,1,131,
-	8,0,0,0,204,168,1,131,9,0,0,0,
-	244,168,1,131,10,0,0,0,28,169,1,131,
-	11,0,0,0,68,169,1,131,12,0,0,0,
-	108,169,1,131,13,0,0,0,148,169,1,131,
-	0,0,0,0,0,0,0,0,1,0,0,0,
-	72,208,1,131,0,0,0,0,0,0,0,0,
-	1,0,2,3,84,212,0,131,16,212,0,131,
-	52,212,0,131,172,212,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,4,3,84,212,0,131,
-	16,212,0,131,52,212,0,131,172,212,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,64,3,
-	84,212,0,131,16,212,0,131,52,212,0,131,
-	172,212,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,2,3,84,212,0,131,16,212,0,131,
-	52,212,0,131,172,212,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,0,0,60,170,1,131,
-	2,0,0,0,100,170,1,131,3,0,0,0,
-	140,170,1,131,4,0,0,0,180,170,1,131,
-	0,0,0,0,0,0,0,0,1,0,0,0,
-	88,208,1,131,0,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,72,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,20,171,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,0,0,76,162,1,131,2,0,0,0,
-	136,162,1,131,3,0,0,0,196,162,1,131,
-	4,0,0,0,0,163,1,131,5,0,0,0,
-	60,163,1,131,6,0,0,0,120,163,1,131,
-	7,0,0,0,180,163,1,131,8,0,0,0,
-	240,163,1,131,9,0,0,0,44,164,1,131,
-	10,0,0,0,104,164,1,131,11,0,0,0,
-	164,164,1,131,12,0,0,0,224,164,1,131,
-	13,0,0,0,28,165,1,131,14,0,0,0,
-	88,165,1,131,15,0,0,0,148,165,1,131,
-	16,0,0,0,208,165,1,131,17,0,0,0,
-	12,166,1,131,18,0,0,0,72,166,1,131,
-	19,0,0,0,132,166,1,131,20,0,0,0,
-	64,208,1,131,21,0,0,0,80,208,1,131,
-	22,0,0,0,96,208,1,131,23,0,0,0,
-	40,171,1,131,0,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,144,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,16,172,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,148,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,76,172,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,152,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,136,172,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,156,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,196,172,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,160,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,0,173,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,164,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,60,173,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,168,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,120,173,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,172,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,180,173,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,176,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,240,173,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,180,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,44,174,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,184,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,104,174,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,188,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,164,174,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,192,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,224,174,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,196,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,28,175,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,200,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,88,175,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,204,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,148,175,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,208,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,208,175,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,212,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,12,176,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,216,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,72,176,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,220,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,132,176,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,224,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,192,176,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,228,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,252,176,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,232,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,56,177,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,236,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,116,177,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,240,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,176,177,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,244,16,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,236,177,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,0,0,36,172,1,131,2,0,0,0,
-	96,172,1,131,3,0,0,0,156,172,1,131,
-	4,0,0,0,216,172,1,131,5,0,0,0,
-	20,173,1,131,6,0,0,0,80,173,1,131,
-	7,0,0,0,140,173,1,131,8,0,0,0,
-	200,173,1,131,9,0,0,0,4,174,1,131,
-	10,0,0,0,64,174,1,131,11,0,0,0,
-	124,174,1,131,12,0,0,0,184,174,1,131,
-	13,0,0,0,244,174,1,131,14,0,0,0,
-	48,175,1,131,15,0,0,0,108,175,1,131,
-	16,0,0,0,168,175,1,131,17,0,0,0,
-	228,175,1,131,18,0,0,0,32,176,1,131,
-	19,0,0,0,92,176,1,131,20,0,0,0,
-	152,176,1,131,21,0,0,0,212,176,1,131,
-	22,0,0,0,16,177,1,131,23,0,0,0,
-	76,177,1,131,24,0,0,0,136,177,1,131,
-	25,0,0,0,196,177,1,131,26,0,0,0,
-	0,178,1,131,0,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,112,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,0,179,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,116,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,60,179,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,120,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,120,179,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,76,210,0,131,
-	156,202,0,131,124,17,3,131,1,0,65,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,180,179,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,200,212,0,131,
-	156,202,0,131,220,5,0,163,1,0,64,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,240,179,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,112,205,0,131,
-	156,202,0,131,161,0,0,0,1,0,2,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,44,180,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,0,0,4,180,1,131,2,0,0,0,
-	64,180,1,131,0,0,0,0,0,0,0,0,
-	1,0,0,0,120,208,1,131,0,0,0,0,
-	0,0,0,0,1,0,0,0,20,179,1,131,
-	2,0,0,0,80,179,1,131,3,0,0,0,
-	140,179,1,131,4,0,0,0,200,179,1,131,
-	5,0,0,0,128,208,1,131,0,0,0,0,
-	0,0,0,0,1,0,2,1,44,202,0,131,
-	208,212,0,131,164,202,0,131,196,214,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,65,1,
-	44,202,0,131,208,212,0,131,164,202,0,131,
-	196,214,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,65,1,44,202,0,131,208,212,0,131,
-	164,202,0,131,196,214,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,65,1,44,202,0,131,
-	208,212,0,131,164,202,0,131,196,214,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,65,1,
-	44,202,0,131,208,212,0,131,164,202,0,131,
-	196,214,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,65,1,44,202,0,131,208,212,0,131,
-	164,202,0,131,196,214,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,65,1,44,202,0,131,
-	208,212,0,131,164,202,0,131,196,214,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,65,1,
-	44,202,0,131,208,212,0,131,164,202,0,131,
-	196,214,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,65,1,44,202,0,131,208,212,0,131,
-	164,202,0,131,196,214,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,65,1,44,202,0,131,
-	208,212,0,131,164,202,0,131,196,214,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,65,1,
-	44,202,0,131,208,212,0,131,164,202,0,131,
-	196,214,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,65,1,44,202,0,131,208,212,0,131,
-	164,202,0,131,196,214,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,65,1,44,202,0,131,
-	208,212,0,131,164,202,0,131,196,214,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,6,1,
-	44,202,0,131,208,212,0,131,164,202,0,131,
-	196,214,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,0,0,192,180,1,131,2,0,0,0,
-	232,180,1,131,3,0,0,0,16,181,1,131,
-	4,0,0,0,56,181,1,131,5,0,0,0,
-	96,181,1,131,6,0,0,0,136,181,1,131,
-	7,0,0,0,176,181,1,131,8,0,0,0,
-	216,181,1,131,9,0,0,0,0,182,1,131,
-	10,0,0,0,40,182,1,131,11,0,0,0,
-	80,182,1,131,13,0,0,0,120,182,1,131,
-	16,0,0,0,160,182,1,131,17,0,0,0,
-	200,182,1,131,0,0,0,0,0,0,0,0,
-	1,0,0,0,144,208,1,131,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,1,0,0,0,
-	160,208,1,131,2,0,0,0,168,208,1,131,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	1,0,0,0,184,208,1,131,2,0,0,0,
-	192,208,1,131,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	1,0,0,0,208,208,1,131,2,0,0,0,
-	216,208,1,131,3,0,0,0,224,208,1,131,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	1,0,0,0,240,208,1,131,2,0,0,0,
-	248,208,1,131,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,1,0,0,0,
-	8,209,1,131,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,1,0,0,0,24,209,1,131,
-	2,0,0,0,32,209,1,131,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	1,0,0,0,48,209,1,131,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	1,0,0,0,64,209,1,131,0,0,0,0,
-	0,0,0,0,1,0,0,0,232,208,1,131,
-	2,0,0,0,0,209,1,131,3,0,0,0,
-	16,209,1,131,4,0,0,0,40,209,1,131,
-	5,0,0,0,56,209,1,131,6,0,0,0,
-	72,209,1,131,0,0,0,0,0,0,0,0,
-	2,0,0,0,152,208,1,131,6,0,0,0,
-	176,208,1,131,7,0,0,0,200,208,1,131,
-	8,0,0,0,80,209,1,131,0,0,0,0,
-	0,0,0,0,7,0,0,0,88,209,1,131,
-	0,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	128,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	8,185,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	144,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	68,185,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	148,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	128,185,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	132,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	188,185,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	136,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	248,185,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	140,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	52,186,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	156,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	112,186,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	160,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	172,186,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	164,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	232,186,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	168,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	36,187,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	172,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	96,187,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	176,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	156,187,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	180,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	216,187,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	184,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	20,188,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	188,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	80,188,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	192,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	140,188,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	196,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	200,188,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	200,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	4,189,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	204,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	64,189,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	208,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	124,189,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	212,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	184,189,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	220,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	244,189,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	224,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	48,190,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	228,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	108,190,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	232,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	168,190,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	236,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	228,190,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,92,215,0,131,156,202,0,131,
-	240,17,3,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	32,191,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,104,215,0,131,140,215,0,131,
-	0,0,0,0,1,0,2,3,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	92,191,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,0,0,
-	28,185,1,131,2,0,0,0,88,185,1,131,
-	3,0,0,0,148,185,1,131,4,0,0,0,
-	208,185,1,131,5,0,0,0,12,186,1,131,
-	6,0,0,0,72,186,1,131,8,0,0,0,
-	132,186,1,131,9,0,0,0,192,186,1,131,
-	10,0,0,0,252,186,1,131,11,0,0,0,
-	56,187,1,131,12,0,0,0,116,187,1,131,
-	13,0,0,0,176,187,1,131,14,0,0,0,
-	236,187,1,131,15,0,0,0,40,188,1,131,
-	16,0,0,0,100,188,1,131,17,0,0,0,
-	160,188,1,131,18,0,0,0,220,188,1,131,
-	19,0,0,0,24,189,1,131,20,0,0,0,
-	84,189,1,131,21,0,0,0,144,189,1,131,
-	22,0,0,0,204,189,1,131,24,0,0,0,
-	8,190,1,131,25,0,0,0,68,190,1,131,
-	26,0,0,0,128,190,1,131,27,0,0,0,
-	188,190,1,131,28,0,0,0,248,190,1,131,
-	29,0,0,0,52,191,1,131,30,0,0,0,
-	112,191,1,131,0,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,180,215,0,131,
-	156,202,0,131,218,12,3,131,1,0,4,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,128,192,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,120,205,0,131,
-	156,202,0,131,40,211,1,131,1,0,2,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,188,192,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	8,202,0,131,148,38,1,131,112,205,0,131,
-	156,202,0,131,2,0,0,0,1,0,2,1,
-	32,45,1,131,208,48,1,131,160,49,1,131,
-	20,48,1,131,248,192,1,131,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,2,1,44,202,0,131,200,215,0,131,
-	164,202,0,131,196,216,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,2,1,44,202,0,131,
-	200,215,0,131,164,202,0,131,196,216,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,6,1,
-	44,202,0,131,200,215,0,131,164,202,0,131,
-	196,216,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,65,1,44,202,0,131,200,215,0,131,
-	164,202,0,131,196,216,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,65,1,44,202,0,131,
-	200,215,0,131,164,202,0,131,196,216,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,0,0,
-	52,193,1,131,2,0,0,0,92,193,1,131,
-	3,0,0,0,132,193,1,131,4,0,0,0,
-	172,193,1,131,5,0,0,0,212,193,1,131,
-	0,0,0,0,0,0,0,0,1,0,0,0,
-	112,209,1,131,0,0,0,0,0,0,0,0,
-	1,0,0,0,148,192,1,131,2,0,0,0,
-	208,192,1,131,3,0,0,0,12,193,1,131,
-	4,0,0,0,120,209,1,131,0,0,0,0,
-	0,0,0,0,8,202,0,131,148,38,1,131,
-	112,205,0,131,156,202,0,131,3,0,0,0,
-	1,0,2,1,32,45,1,131,208,48,1,131,
-	160,49,1,131,20,48,1,131,100,194,1,131,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,8,202,0,131,148,38,1,131,
-	92,217,0,131,60,210,0,131,216,12,3,131,
-	1,0,2,3,32,45,1,131,208,48,1,131,
-	160,49,1,131,20,48,1,131,160,194,1,131,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,8,202,0,131,148,38,1,131,
-	104,217,0,131,156,202,0,131,0,0,0,0,
-	1,0,67,1,32,45,1,131,208,48,1,131,
-	160,49,1,131,20,48,1,131,220,194,1,131,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,8,202,0,131,148,38,1,131,
-	104,217,0,131,156,202,0,131,0,0,0,0,
-	1,0,65,1,32,45,1,131,208,48,1,131,
-	160,49,1,131,20,48,1,131,24,195,1,131,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,8,202,0,131,148,38,1,131,
-	112,217,0,131,156,202,0,131,216,12,3,131,
-	1,0,4,1,32,45,1,131,208,48,1,131,
-	160,49,1,131,20,48,1,131,84,195,1,131,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,8,202,0,131,148,38,1,131,
-	120,205,0,131,156,202,0,131,224,12,3,131,
-	1,0,2,1,32,45,1,131,208,48,1,131,
-	160,49,1,131,20,48,1,131,144,195,1,131,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,8,202,0,131,148,38,1,131,
-	120,205,0,131,156,202,0,131,228,12,3,131,
-	1,0,2,1,32,45,1,131,208,48,1,131,
-	160,49,1,131,20,48,1,131,204,195,1,131,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,8,202,0,131,148,38,1,131,
-	92,217,0,131,156,202,0,131,232,12,3,131,
-	1,0,2,1,32,45,1,131,208,48,1,131,
-	160,49,1,131,20,48,1,131,8,196,1,131,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,8,202,0,131,148,38,1,131,
-	92,217,0,131,156,202,0,131,234,12,3,131,
-	1,0,2,1,32,45,1,131,208,48,1,131,
-	160,49,1,131,20,48,1,131,68,196,1,131,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,8,202,0,131,148,38,1,131,
-	92,217,0,131,156,202,0,131,246,12,3,131,
-	1,0,2,1,32,45,1,131,208,48,1,131,
-	160,49,1,131,20,48,1,131,128,196,1,131,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,8,202,0,131,148,38,1,131,
-	92,217,0,131,156,202,0,131,236,12,3,131,
-	1,0,2,1,32,45,1,131,208,48,1,131,
-	160,49,1,131,20,48,1,131,188,196,1,131,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,8,202,0,131,148,38,1,131,
-	92,217,0,131,60,210,0,131,238,12,3,131,
-	1,0,2,3,32,45,1,131,208,48,1,131,
-	160,49,1,131,20,48,1,131,248,196,1,131,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,8,202,0,131,148,38,1,131,
-	92,217,0,131,60,210,0,131,240,12,3,131,
-	1,0,2,3,32,45,1,131,208,48,1,131,
-	160,49,1,131,20,48,1,131,52,197,1,131,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,8,202,0,131,148,38,1,131,
-	92,217,0,131,60,210,0,131,242,12,3,131,
-	1,0,2,3,32,45,1,131,208,48,1,131,
-	160,49,1,131,20,48,1,131,112,197,1,131,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,2,1,180,219,0,131,
-	132,217,0,131,164,202,0,131,104,220,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,2,3,
-	180,219,0,131,132,217,0,131,0,221,0,131,
-	104,220,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,2,1,180,219,0,131,132,217,0,131,
-	164,202,0,131,104,220,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,2,3,180,219,0,131,
-	132,217,0,131,0,221,0,131,104,220,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,2,3,
-	180,219,0,131,132,217,0,131,0,221,0,131,
-	104,220,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,4,1,180,219,0,131,132,217,0,131,
-	164,202,0,131,104,220,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,2,1,180,219,0,131,
-	132,217,0,131,164,202,0,131,104,220,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,4,1,
-	180,219,0,131,132,217,0,131,164,202,0,131,
-	104,220,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,4,1,180,219,0,131,132,217,0,131,
-	164,202,0,131,104,220,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,65,1,180,219,0,131,
-	132,217,0,131,164,202,0,131,104,220,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,0,0,
-	172,197,1,131,2,0,0,0,212,197,1,131,
-	3,0,0,0,252,197,1,131,4,0,0,0,
-	36,198,1,131,5,0,0,0,76,198,1,131,
-	6,0,0,0,116,198,1,131,7,0,0,0,
-	156,198,1,131,8,0,0,0,196,198,1,131,
-	9,0,0,0,236,198,1,131,10,0,0,0,
-	20,199,1,131,0,0,0,0,0,0,0,0,
-	1,0,0,0,136,209,1,131,0,0,0,0,
-	0,0,0,0,1,0,0,0,120,194,1,131,
-	2,0,0,0,180,194,1,131,3,0,0,0,
-	240,194,1,131,4,0,0,0,44,195,1,131,
-	5,0,0,0,104,195,1,131,6,0,0,0,
-	164,195,1,131,7,0,0,0,224,195,1,131,
-	8,0,0,0,28,196,1,131,9,0,0,0,
-	88,196,1,131,10,0,0,0,148,196,1,131,
-	11,0,0,0,208,196,1,131,12,0,0,0,
-	12,197,1,131,13,0,0,0,72,197,1,131,
-	14,0,0,0,132,197,1,131,15,0,0,0,
-	144,209,1,131,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,76,210,0,131,156,202,0,131,
-	160,211,1,131,1,0,65,1,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	44,200,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,8,202,0,131,
-	148,38,1,131,120,205,0,131,60,210,0,131,
-	140,1,0,163,1,0,2,3,32,45,1,131,
-	208,48,1,131,160,49,1,131,20,48,1,131,
-	104,200,1,131,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,4,1,
-	44,202,0,131,36,222,0,131,164,202,0,131,
-	48,223,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,2,1,44,202,0,131,36,222,0,131,
-	164,202,0,131,48,223,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,2,1,44,202,0,131,
-	36,222,0,131,164,202,0,131,48,223,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,0,0,
-	164,200,1,131,2,0,0,0,204,200,1,131,
-	3,0,0,0,244,200,1,131,0,0,0,0,
-	0,0,0,0,1,0,0,0,168,209,1,131,
-	0,0,0,0,0,0,0,0,1,0,2,1,
-	44,202,0,131,212,223,0,131,164,202,0,131,
-	252,224,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,2,1,44,202,0,131,212,223,0,131,
-	164,202,0,131,252,224,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,65,1,44,202,0,131,
-	212,223,0,131,164,202,0,131,252,224,0,131,
-	0,0,0,0,0,0,0,0,255,0,0,0,
-	255,0,0,0,0,0,0,0,1,0,65,1,
-	44,202,0,131,212,223,0,131,164,202,0,131,
-	252,224,0,131,0,0,0,0,0,0,0,0,
-	255,0,0,0,255,0,0,0,0,0,0,0,
-	1,0,65,1,44,202,0,131,212,223,0,131,
-	164,202,0,131,252,224,0,131,0,0,0,0,
-	0,0,0,0,255,0,0,0,255,0,0,0,
-	0,0,0,0,1,0,0,0,76,201,1,131,
-	2,0,0,0,116,201,1,131,3,0,0,0,
-	156,201,1,131,4,0,0,0,196,201,1,131,
-	5,0,0,0,236,201,1,131,0,0,0,0,
-	0,0,0,0,1,0,0,0,184,209,1,131,
-	0,0,0,0,0,0,0,0,1,0,0,0,
-	64,200,1,131,2,0,0,0,124,200,1,131,
-	3,0,0,0,176,209,1,131,4,0,0,0,
-	192,209,1,131,0,0,0,0,0,0,0,0,
-	1,0,0,0,128,209,1,131,2,0,0,0,
-	152,209,1,131,3,0,0,0,160,209,1,131,
-	4,0,0,0,200,209,1,131,0,0,0,0,
-	0,0,0,0,1,0,0,0,24,208,1,131,
-	2,0,0,0,48,208,1,131,4,0,0,0,
-	104,208,1,131,5,0,0,0,112,208,1,131,
-	7,0,0,0,136,208,1,131,10,0,0,0,
-	96,209,1,131,11,0,0,0,104,209,1,131,
-	17,0,0,0,208,209,1,131,0,0,0,0,
-	0,0,0,0,1,0,0,0,216,209,1,131,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	1,0,0,0,240,209,1,131,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,1,0,0,0,8,210,1,131,
-	2,0,0,0,16,210,1,131,3,0,0,0,
-	24,210,1,131,4,0,0,0,32,210,1,131,
-	5,0,0,0,40,210,1,131,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,1,0,0,0,
-	56,210,1,131,2,0,0,0,64,210,1,131,
-	0,0,0,0,0,0,0,0,1,0,0,0,
-	72,210,1,131,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,1,0,0,0,
-	48,210,1,131,2,0,0,0,80,210,1,131,
-	3,0,0,0,88,210,1,131,0,0,0,0,
-	0,0,0,0,1,0,0,0,16,208,1,131,
-	2,0,0,0,224,209,1,131,3,0,0,0,
-	232,209,1,131,4,0,0,0,248,209,1,131,
-	5,0,0,0,0,210,1,131,6,0,0,0,
-	96,210,1,131,0,0,0,0,0,0,0,0,
-	1,0,0,0,104,210,1,131,0,0,0,0,
-	0,0,0,0,6,0,0,0,112,210,1,131,
-	0,0,0,0,0,0,0,0,3,0,0,0,
-	120,210,1,131,0,0,0,0,0,0,0,0,
-	1,0,0,0,128,210,1,131,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	1,0,0,0,3,0,0,0,6,0,0,0,
-	1,0,0,0,2,0,0,0,1,0,0,0,
-	10,0,0,0,7,0,0,0,8,0,0,0,
-	2,0,0,0,2,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,112,117,98,108,
-	105,99,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,112,114,105,118,97,116,101,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	83,78,77,80,95,116,114,97,112,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,1,0,0,0,
-	3,0,0,0,6,0,0,0,1,0,0,0,
-	4,0,0,0,1,0,0,0,76,1,0,0,
-	5,0,0,0,1,0,0,0,1,0,0,0,
-	0,0,0,0,0,0,0,0,1,0,0,0,
-	3,0,0,0,6,0,0,0,1,0,0,0,
-	2,0,0,0,1,0,0,0,2,0,0,0,
-	2,0,0,0,1,0,0,0,1,0,0,0,
-	0,0,0,0,1,0,0,0,3,0,0,0,
-	6,0,0,0,1,0,0,0,2,0,0,0,
-	1,0,0,0,17,0,0,0,0,0,0,0,
-	0,0,0,0,48,49,50,51,52,53,54,55,
-	56,57,65,66,67,68,69,70,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	255,85,170,0,255,255,255,255,85,85,85,85,
-	170,170,170,170,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,64,40,35,41,
-	32,67,111,112,121,114,105,103,104,116,32,40,
-	99,41,32,49,57,56,54,32,45,32,49,57,
-	57,53,32,32,69,112,105,108,111,103,117,101,
-	32,84,101,99,104,110,111,108,111,103,121,32,
-	67,111,114,112,111,114,97,116,105,111,110,10,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,255,255,255,255,
-	72,10,0,0,78,10,0,0,83,10,0,0,
-	69,10,0,0,109,97,105,110,46,99,0,0,
-	48,0,0,0,55,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,1,0,0,0,
-	0,0,0,0,116,105,109,101,114,46,99,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	100,0,0,0,100,0,0,0,1,0,0,0,
-	0,0,0,0,115,114,99,32,0,0,0,0,
-	32,0,0,0,100,115,116,32,0,0,0,0,
-	32,37,48,50,88,0,0,0,10,0,0,0,
-	255,255,255,255,48,48,48,48,48,48,0,0,
-	48,48,48,48,48,49,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,255,255,255,255,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	62,32,0,0,37,120,10,0,37,120,58,9,
-	37,120,10,0,37,115,10,0,0,0,0,0,
-	10,0,0,0,0,0,0,0,0,0,0,0,
-	68,85,77,80,10,0,0,0,37,48,50,120,
-	32,0,0,0,10,0,0,0,0,0,0,0,
-	37,100,32,112,112,115,10,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	1,0,0,0,0,0,0,0,1,0,0,0,
-	119,119,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,1,128,194,0,
-	0,0,0,0,1,128,194,0,0,16,0,0,
-	66,76,75,0,70,87,68,0,76,82,78,0,
-	76,73,83,0,68,73,83,0,72,69,76,76,
-	79,10,0,0,116,99,32,101,120,112,10,0,
-	102,114,111,109,32,0,0,0,10,0,0,0,
-	87,101,105,114,100,0,0,0,0,0,0,0,
-	0,0,0,0,255,255,255,255,255,255,255,255,
-	255,255,0,0,255,255,255,255,255,255,0,0,
-	0,0,0,0,0,0,0,0,80,65,68,37,
-	100,10,0,0,170,170,3,0,0,0,0,0,
-	83,69,78,84,33,10,0,0,85,68,80,10,
-	0,0,0,0,73,67,77,80,10,0,0,0,
-	69,67,72,79,10,0,0,0,73,80,10,0,
-	170,170,3,0,0,0,0,0,73,80,88,33,
-	10,0,0,0,0,0,0,0,255,255,255,255,
-	255,255,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0,
-	0,0,0,0,192,155,1,131,0,0,0,0,
-	108,157,1,131,0,0,0,0,88,161,1,131,
-	0,0,0,0,16,162,1,131,0,0,0,0,
-	32,162,1,131,0,0,0,0,116,167,1,131,
-	0,0,0,0,164,167,1,131,0,0,0,0,
-	188,169,1,131,0,0,0,0,44,170,1,131,
-	0,0,0,0,220,170,1,131,0,0,0,0,
-	4,171,1,131,0,0,0,0,80,171,1,131,
-	0,0,0,0,40,178,1,131,0,0,0,0,
-	104,180,1,131,0,0,0,0,128,180,1,131,
-	0,0,0,0,144,180,1,131,0,0,0,0,
-	240,182,1,131,0,0,0,0,104,183,1,131,
-	0,0,0,0,120,183,1,131,0,0,0,0,
-	128,183,1,131,0,0,0,0,136,183,1,131,
-	0,0,0,0,160,183,1,131,0,0,0,0,
-	168,183,1,131,0,0,0,0,176,183,1,131,
-	0,0,0,0,200,183,1,131,0,0,0,0,
-	208,183,1,131,0,0,0,0,216,183,1,131,
-	0,0,0,0,224,183,1,131,0,0,0,0,
-	0,184,1,131,0,0,0,0,8,184,1,131,
-	0,0,0,0,16,184,1,131,0,0,0,0,
-	40,184,1,131,0,0,0,0,48,184,1,131,
-	0,0,0,0,64,184,1,131,0,0,0,0,
-	72,184,1,131,0,0,0,0,80,184,1,131,
-	0,0,0,0,104,184,1,131,0,0,0,0,
-	112,184,1,131,0,0,0,0,128,184,1,131,
-	0,0,0,0,136,184,1,131,0,0,0,0,
-	152,184,1,131,0,0,0,0,208,184,1,131,
-	0,0,0,0,248,184,1,131,0,0,0,0,
-	152,191,1,131,0,0,0,0,252,193,1,131,
-	0,0,0,0,44,194,1,131,0,0,0,0,
-	60,194,1,131,0,0,0,0,60,199,1,131,
-	0,0,0,0,148,199,1,131,0,0,0,0,
-	164,199,1,131,0,0,0,0,36,200,1,131,
-	0,0,0,0,28,201,1,131,0,0,0,0,
-	60,201,1,131,0,0,0,0,20,202,1,131,
-	0,0,0,0,68,202,1,131,0,0,0,0,
-	84,202,1,131,0,0,0,0,124,202,1,131,
-	0,0,0,0,164,202,1,131,0,0,0,0,
-	236,202,1,131,0,0,0,0,252,202,1,131,
-	0,0,0,0,4,203,1,131,0,0,0,0,
-	12,203,1,131,0,0,0,0,28,203,1,131,
-	0,0,0,0,36,203,1,131,0,0,0,0,
-	44,203,1,131,0,0,0,0,52,203,1,131,
-	0,0,0,0,60,203,1,131,0,0,0,0,
-	68,203,1,131,0,0,0,0,76,203,1,131,
-	0,0,0,0,124,203,1,131,0,0,0,0,
-	132,203,1,131,0,0,0,0,140,203,1,131,
-	0,0,0,0,164,203,1,131,0,0,0,0,
-	180,203,1,131,0,0,0,0,188,203,1,131,
-	0,0,0,0,220,203,1,131,0,0,0,0,
-	20,204,1,131,0,0,0,0,36,204,1,131,
-	0,0,0,0,52,204,1,131,0,0,0,0,
-	68,204,1,131,255,255,255,0,0,0,0,0,
-	0,0,0,0,0,0,0,0,1,0,0,0,
-	10,0,0,0,10,0,0,0,0,205,1,131,
-	10,0,0,0,7,0,0,0,0,0,0,0,
-	0,0,0,0,255,255,255,255,110,118,114,97,
-	109,46,99,0,114,99,0,0,48,120,0,0,
-	0,0,0,0,0,0,0,0,0,0,0,0
-	} ;
-static const int dgrs_ncode = 119520 ;
diff --git a/drivers/net/dgrs_i82596.h b/drivers/net/dgrs_i82596.h
deleted file mode 100644
index ac9217a..0000000
--- a/drivers/net/dgrs_i82596.h
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- *	i82596 ethernet controller bits and structures (little endian)
- *
- *	$Id: i82596.h,v 1.8 1996/09/03 11:19:03 rick Exp $
- */
-
-/************************************************************************/
-/*									*/
-/*	PORT commands (p. 4-20).  The least significant nibble is one	*/
-/*	of these commands, the rest of the command is a memory address	*/
-/*	aligned on a 16 byte boundary.  Note that port commands must	*/
-/*	be written to the PORT address and the PORT address+2 with two	*/
-/*	halfword writes.  Write the LSH first to PORT, then the MSH to	*/
-/*	PORT+2.  Blame Intel.						*/
-/*									*/
-/************************************************************************/
-#define	I596_PORT_RESET		0x0	/* Reset. Wait 5 SysClks & 10 TxClks */
-#define	I596_PORT_SELFTEST	0x1	/* Do a selftest */
-#define	I596_PORT_SCP_ADDR	0x2	/* Set new SCP address */
-#define	I596_PORT_DUMP		0x3	/* Dump internal data structures */
-
-/*
- *	I596_ST:	Selftest results (p. 4-21)
- */
-typedef volatile struct
-{
-	ulong	signature;	/* ROM checksum */
-	ulong	result;		/* Selftest results: non-zero is a failure */
-} I596_ST;
-
-#define	I596_ST_SELFTEST_FAIL	0x1000	/* Selftest Failed */
-#define	I596_ST_DIAGNOSE_FAIL	0x0020	/* Diagnose Failed */
-#define	I596_ST_BUSTIMER_FAIL	0x0010	/* Bus Timer Failed */
-#define	I596_ST_REGISTER_FAIL	0x0008	/* Register Failed */
-#define	I596_ST_ROM_FAIL	0x0004	/* ROM Failed */
-
-/*
- *	I596_DUMP:	Dump results
- */
-typedef volatile struct
-{
-	ulong	dump[77];
-} I596_DUMP;
-
-/************************************************************************/
-/*									*/
-/*	I596_TBD:	Transmit Buffer Descriptor (p. 4-59)		*/
-/*									*/
-/************************************************************************/
-typedef volatile struct _I596_TBD
-{
-	ulong			count;
-	vol struct _I596_TBD	*next;
-	uchar			*buf;
-	ushort			unused1;
-	ushort			unused2;
-} I596_TBD;
-
-#define	I596_TBD_NOLINK		((I596_TBD *) 0xffffffff)
-#define	I596_TBD_EOF		0x8000
-#define I596_TBD_COUNT_MASK	0x3fff
-
-/************************************************************************/
-/*									*/
-/*	I596_TFD:	Transmit Frame Descriptor (p. 4-56)		*/
-/*			a.k.a. I596_CB_XMIT				*/
-/*									*/
-/************************************************************************/
-typedef volatile struct
-{
-	ushort			status;
-	ushort			cmd;
-	union _I596_CB		*next;
-	I596_TBD		*tbdp;
-	ulong			count;	/* for speed */
-
-	/* Application defined data follows structure... */
-
-#if 0	/* We don't use these intel defined ones */
-		uchar			addr[6];
-		ushort			len;
-		uchar			data[1];
-#else
-		ulong		dstchan;/* Used by multi-NIC mode */
-#endif
-} I596_TFD;
-
-#define	I596_TFD_NOCRC	0x0010	/* cmd: No CRC insertion */
-#define	I596_TFD_FLEX	0x0008	/* cmd: Flexible mode */
-
-/************************************************************************/
-/*									*/
-/*	I596_RBD:	Receive Buffer Descriptor (p. 4-84)		*/
-/*									*/
-/************************************************************************/
-typedef volatile struct _I596_RBD
-{
-#ifdef INTEL_RETENTIVE
-	ushort			count;	/* Length of data in buf */
-	ushort			offset;
-#else
-	ulong			count;	/* Length of data in buf */
-#endif
-	vol struct _I596_RBD	*next;	/* Next buffer descriptor in list */
-	uchar			*buf;	/* Data buffer */
-#ifdef INTEL_RETENTIVE
-	ushort			size;	/* Size of buf (constant) */
-	ushort			zero;
-#else
-	ulong			size;	/* Size of buf (constant) */
-#endif
-
-	/* Application defined data follows structure... */
-
-	uchar			chan;
-	uchar			refcnt;
-	ushort			len;
-} I596_RBD;
-
-#define	I596_RBD_NOLINK		((I596_RBD *) 0xffffffff)
-#define	I596_RBD_EOF		0x8000	/* This is last buffer in a frame */
-#define	I596_RBD_F		0x4000	/* The actual count is valid */
-
-#define	I596_RBD_EL		0x8000	/* Last buffer in list */
-
-/************************************************************************/
-/*									*/
-/*	I596_RFD:	Receive Frame Descriptor (p. 4-79)		*/
-/*									*/
-/************************************************************************/
-typedef volatile struct _I596_RFD
-{
-	ushort			status;
-	ushort			cmd;
-	vol struct _I596_RFD	*next;
-	vol struct _I596_RBD	*rbdp;
-	ushort			count;	/* Len of data in RFD: always 0 */
-	ushort			size;	/* Size of RFD buffer: always 0 */
-
-	/* Application defined data follows structure... */
-
-#	if 0	/* We don't use these intel defined ones */
-		uchar		addr[6];
-		ushort		len;
-		uchar		data[1];
-#	else
-		ulong		dstchan;/* Used by multi-nic mode */
-#	endif
-} I596_RFD;
-
-#define	I596_RFD_C		0x8000	/* status: frame complete */
-#define	I596_RFD_B		0x4000	/* status: frame busy or waiting */
-#define	I596_RFD_OK		0x2000	/* status: frame OK */
-#define	I596_RFD_ERR_LENGTH	0x1000	/* status: length error */
-#define	I596_RFD_ERR_CRC	0x0800	/* status: CRC error */
-#define	I596_RFD_ERR_ALIGN	0x0400	/* status: alignment error */
-#define	I596_RFD_ERR_NOBUFS	0x0200	/* status: resource error */
-#define	I596_RFD_ERR_DMA	0x0100	/* status: DMA error */
-#define	I596_RFD_ERR_SHORT	0x0080	/* status: too short error */
-#define	I596_RFD_NOMATCH	0x0002	/* status: IA was not matched */
-#define	I596_RFD_COLLISION	0x0001	/* status: collision during receive */
-
-#define	I596_RFD_EL		0x8000	/* cmd: end of RFD list */
-#define	I596_RFD_FLEX		0x0008	/* cmd: Flexible mode */
-#define	I596_RFD_EOF		0x8000	/* count: last buffer in the frame */
-#define	I596_RFD_F		0x4000	/* count: The actual count is valid */
-
-/************************************************************************/
-/*									*/
-/*	Commands							*/
-/*									*/
-/************************************************************************/
-
-	/* values for cmd halfword in all the structs below */
-#define I596_CB_CMD		0x07	/* CB COMMANDS */
-#define I596_CB_CMD_NOP		0
-#define I596_CB_CMD_IA		1
-#define I596_CB_CMD_CONF	2
-#define I596_CB_CMD_MCAST	3
-#define I596_CB_CMD_XMIT	4
-#define I596_CB_CMD_TDR		5
-#define I596_CB_CMD_DUMP	6
-#define I596_CB_CMD_DIAG	7
-
-#define	I596_CB_CMD_EL		0x8000	/* CB is last in linked list */
-#define	I596_CB_CMD_S		0x4000	/* Suspend after execution */
-#define	I596_CB_CMD_I		0x2000	/* cause interrupt */
-
-	/* values for the status halfword in all the struct below */
-#define	I596_CB_STATUS		0xF000	/* All four status bits */
-#define	I596_CB_STATUS_C	0x8000	/* Command complete */
-#define	I596_CB_STATUS_B	0x4000	/* Command busy executing */
-#define	I596_CB_STATUS_C_OR_B	0xC000	/* Command complete or busy */
-#define	I596_CB_STATUS_OK	0x2000	/* Command complete, no errors */
-#define	I596_CB_STATUS_A	0x1000	/* Command busy executing */
-
-#define	I596_CB_NOLINK		((I596_CB *) 0xffffffff)
-
-/*
- *	I596_CB_NOP:	NOP Command (p. 4-34)
- */
-typedef volatile struct
-{
-	ushort			status;
-	ushort			cmd;
-	union _I596_CB		*next;
-} I596_CB_NOP;
-
-/*
- *	Same as above, but command and status in one ulong for speed
- */
-typedef volatile struct
-{
-	ulong			csr;
-	union _I596_CB		*next;
-} I596_CB_FAST;
-#define	FASTs(X)	(X)
-#define	FASTc(X)	((X)<<16)
-
-/*
- *	I596_CB_IA:	Individual (MAC) Address Command (p. 4-35)
- */
-typedef volatile struct
-{
-	ushort			status;
-	ushort			cmd;
-	union _I596_CB		*next;
-	uchar			addr[6];
-} I596_CB_IA;
-
-/*
- *	I596_CB_CONF:	Configure Command (p. 4-37)
- */
-typedef volatile struct
-{
-	ushort			status;
-	ushort			cmd;
-	union _I596_CB		*next;
-	uchar			conf[14];
-} I596_CB_CONF;
-
-#define	I596_CONF0_P		0x80	/* Enable RBD Prefetch Bit */
-#define	I596_CONF0_COUNT	14	/* Count of configuration bytes */
-
-#define	I596_CONF1_MON_OFF	0xC0	/* Monitor mode: Monitor off */
-#define	I596_CONF1_MON_ON	0x80	/* Monitor mode: Monitor on */
-#define	I596_CONF1_TxFIFO(W)	(W)	/* TxFIFO trigger, in words */
-
-#define	I596_CONF2_SAVEBF	0x80	/* Save bad frames */
-
-#define	I596_CONF3_ADDRLEN(B)	(B)	/* Address length */
-#define	I596_CONF3_NOSRCINSERT	0x08	/* Do not insert source address */
-#define	I596_CONF3_PREAMBLE8	0x20	/* 8 byte preamble */
-#define	I596_CONF3_LOOPOFF	0x00	/* Loopback: Off */
-#define	I596_CONF3_LOOPINT	0x40	/* Loopback: internal */
-#define	I596_CONF3_LOOPEXT	0xC0	/* Loopback: external */
-
-#define	I596_CONF4_LINPRI(ST)	(ST)	/* Linear priority: slot times */
-#define	I596_CONF4_EXPPRI(ST)	(ST)	/* Exponential priority: slot times */
-#define	I596_CONF4_IEEE_BOM	0	/* IEEE 802.3 backoff method */
-
-#define	I596_CONF5_IFS(X)	(X)	/* Interframe spacing in clocks */
-
-#define	I596_CONF6_ST_LOW(X)	(X&255)	/* Slot time, low byte */
-
-#define	I596_CONF7_ST_HI(X)	(X>>8)	/* Slot time, high bits */
-#define	I596_CONF7_RETRY(X)	(X<<4)	/* Max retry number */
-
-#define	I596_CONF8_PROMISC	0x01	/* Rcv all frames */
-#define	I596_CONF8_NOBROAD	0x02
-#define	I596_CONF8_MANCHESTER	0x04
-#define	I596_CONF8_TxNOCRS	0x08
-#define	I596_CONF8_NOCRC	0x10
-#define	I596_CONF8_CRC_CCITT	0x20
-#define	I596_CONF8_BITSTUFFING	0x40
-#define	I596_CONF8_PADDING	0x80
-
-#define	I596_CONF9_CSFILTER(X)	(X)
-#define	I596_CONF9_CSINT(X)	0x08
-#define	I596_CONF9_CDFILTER(X)	(X<<4)
-#define	I596_CONF9_CDINT(X)	0x80
-
-#define	I596_CONF10_MINLEN(X)	(X)	/* Minimum frame length */
-
-#define	I596_CONF11_PRECRS_	0x01	/* Preamble before carrier sense */
-#define	I596_CONF11_LNGFLD_	0x02	/* Padding in End of Carrier */
-#define	I596_CONF11_CRCINM_	0x04	/* CRC in memory */
-#define	I596_CONF11_AUTOTX	0x08	/* Auto retransmit */
-#define	I596_CONF11_CSBSAC_	0x10	/* Collision detect by src addr cmp. */
-#define	I596_CONF11_MCALL_	0x20	/* Multicast all */
-
-#define I596_CONF13_RESERVED	0x3f	/* Reserved: must be ones */
-#define I596_CONF13_MULTIA	0x40	/* Enable multiple addr. reception */
-#define I596_CONF13_DISBOF	0x80	/* Disable backoff algorithm */
-/*
- *	I596_CB_MCAST:	Multicast-Setup Command (p. 4-54)
- */
-typedef volatile struct
-{
-	ushort			status;
-	ushort			cmd;
-	union _I596_CB		*next;
-	ushort			count;		/* Number of 6-byte addrs that follow */
-	uchar			addr[6][1];
-} I596_CB_MCAST;
-
-/*
- *	I596_CB_XMIT:	Transmit Command (p. 4-56)
- */
-typedef	I596_TFD	I596_CB_XMIT;
-
-#define	I596_CB_XMIT_NOCRC	0x0010	/* cmd: No CRC insertion */
-#define	I596_CB_XMIT_FLEX	0x0008	/* cmd: Flexible memory mode */
-
-#define	I596_CB_XMIT_ERR_LATE	0x0800	/* status: error: late collision */
-#define	I596_CB_XMIT_ERR_NOCRS	0x0400	/* status: error: no carriers sense */
-#define	I596_CB_XMIT_ERR_NOCTS	0x0200	/* status: error: loss of CTS */
-#define	I596_CB_XMIT_ERR_UNDER	0x0100	/* status: error: DMA underrun */
-#define	I596_CB_XMIT_ERR_MAXCOL	0x0020	/* status: error: maximum collisions */
-#define	I596_CB_XMIT_COLLISIONS	0x000f	/* status: number of collisions */
-
-/*
- *	I596_CB_TDR:	Time Domain Reflectometry Command (p. 4-63)
- */
-typedef volatile struct
-{
-	ushort			status;
-	ushort			cmd;
-	union _I596_CB		*next;
-	ushort			time;
-} I596_CB_TDR;
-
-/*
- *	I596_CB_DUMP:	Dump Command (p. 4-65)
- */
-typedef volatile struct
-{
-	ushort			status;
-	ushort			cmd;
-	union _I596_CB		*next;
-	uchar			*buf;
-} I596_CB_DUMP;
-
-/*
- *	I596_CB_DIAG:	Diagnose Command (p. 4-77)
- */
-typedef volatile struct
-{
-	ushort			status;
-	ushort			cmd;
-	union _I596_CB		*next;
-} I596_CB_DIAG;
-
-/*
- *	I596_CB:	Command Block
- */
-typedef union _I596_CB
-{
-	I596_CB_NOP		nop;
-	I596_CB_IA		ia;
-	I596_CB_CONF		conf;
-	I596_CB_MCAST		mcast;
-	I596_CB_XMIT		xmit;
-	I596_CB_TDR		tdr;
-	I596_CB_DUMP		dump;
-	I596_CB_DIAG		diag;
-
-	/* command and status in one ulong for speed... */
-	I596_CB_FAST		fast;
-} I596_CB;
-
-/************************************************************************/
-/*									*/
-/*	I596_SCB:	System Configuration Block (p. 4-26)		*/
-/*									*/
-/************************************************************************/
-typedef volatile struct
-{
-	volatile ushort		status;		/* Status word */
-	volatile ushort		cmd;		/* Command word */
-	I596_CB		*cbp;
-	I596_RFD	*rfdp;
-	ulong		crc_errs;
-	ulong		align_errs;
-	ulong		resource_errs;
-	ulong		overrun_errs;
-	ulong		rcvcdt_errs;
-	ulong		short_errs;
-	ushort		toff;
-	ushort		ton;
-} I596_SCB;
-
-	/* cmd halfword values */
-#define	I596_SCB_ACK		0xF000	/* ACKNOWLEDGMENTS */
-#define	I596_SCB_ACK_CX		0x8000	/* Ack command completion */
-#define	I596_SCB_ACK_FR		0x4000	/* Ack received frame */
-#define	I596_SCB_ACK_CNA	0x2000	/* Ack command unit not active */
-#define	I596_SCB_ACK_RNR	0x1000	/* Ack rcv unit not ready */
-#define	I596_SCB_ACK_ALL	0xF000	/* Ack everything */
-
-#define	I596_SCB_CUC		0x0700	/* COMMAND UNIT COMMANDS */
-#define	I596_SCB_CUC_NOP	0x0000	/* No operation */
-#define	I596_SCB_CUC_START	0x0100	/* Start execution of first CB */
-#define	I596_SCB_CUC_RESUME	0x0200	/* Resume execution */
-#define	I596_SCB_CUC_SUSPEND	0x0300	/* Suspend after current CB */
-#define	I596_SCB_CUC_ABORT	0x0400	/* Abort current CB immediately */
-#define	I596_SCB_CUC_LOAD	0x0500	/* Load Bus throttle timers */
-#define	I596_SCB_CUC_LOADIMM	0x0600	/* Load Bus throttle timers, now */
-
-#define	I596_SCB_RUC		0x0070	/* RECEIVE UNIT COMMANDS */
-#define	I596_SCB_RUC_NOP	0x0000	/* No operation */
-#define	I596_SCB_RUC_START	0x0010	/* Start reception */
-#define	I596_SCB_RUC_RESUME	0x0020	/* Resume reception */
-#define	I596_SCB_RUC_SUSPEND	0x0030	/* Suspend reception */
-#define	I596_SCB_RUC_ABORT	0x0040	/* Abort reception */
-
-#define	I596_SCB_RESET		0x0080	/* Hard reset chip */
-
-	/* status halfword values */
-#define	I596_SCB_STAT		0xF000	/* STATUS */
-#define	I596_SCB_CX		0x8000	/* command completion */
-#define	I596_SCB_FR		0x4000	/* received frame */
-#define	I596_SCB_CNA		0x2000	/* command unit not active */
-#define	I596_SCB_RNR		0x1000	/* rcv unit not ready */
-
-#define	I596_SCB_CUS		0x0700	/* COMMAND UNIT STATUS */
-#define	I596_SCB_CUS_IDLE	0x0000	/* Idle */
-#define	I596_SCB_CUS_SUSPENDED	0x0100	/* Suspended */
-#define	I596_SCB_CUS_ACTIVE	0x0200	/* Active */
-
-#define	I596_SCB_RUS		0x00F0	/* RECEIVE UNIT STATUS */
-#define	I596_SCB_RUS_IDLE	0x0000	/* Idle */
-#define	I596_SCB_RUS_SUSPENDED	0x0010	/* Suspended */
-#define	I596_SCB_RUS_NORES	0x0020	/* No Resources */
-#define	I596_SCB_RUS_READY	0x0040	/* Ready */
-#define	I596_SCB_RUS_NORBDS	0x0080	/* No more RBDs modifier */
-
-#define	I596_SCB_LOADED		0x0008	/* Bus timers loaded */
-
-/************************************************************************/
-/*									*/
-/*	I596_ISCP:	Intermediate System Configuration Ptr (p 4-26)	*/
-/*									*/
-/************************************************************************/
-typedef volatile struct
-{
-	ulong		busy;	/* Set to 1; I596 clears it when scbp is read */
-	I596_SCB	*scbp;
-} I596_ISCP;
-
-/************************************************************************/
-/*									*/
-/*	I596_SCP:	System Configuration Pointer (p. 4-23)		*/
-/*									*/
-/************************************************************************/
-typedef volatile struct
-{
-	ulong		sysbus;
-	ulong		dummy;
-	I596_ISCP	*iscpp;
-} I596_SCP;
-
-	/* .sysbus values */
-#define I596_SCP_RESERVED	0x400000	/* Reserved bits must be set */
-#define I596_SCP_INTLOW		0x200000	/* Intr. Polarity active low */
-#define I596_SCP_INTHIGH	0		/* Intr. Polarity active high */
-#define I596_SCP_LOCKDIS	0x100000	/* Lock Function disabled */
-#define I596_SCP_LOCKEN		0		/* Lock Function enabled */
-#define I596_SCP_ETHROTTLE	0x080000	/* External Bus Throttle */
-#define I596_SCP_ITHROTTLE	0		/* Internal Bus Throttle */
-#define I596_SCP_LINEAR		0x040000	/* Linear Mode */
-#define I596_SCP_SEGMENTED	0x020000	/* Segmented Mode */
-#define I596_SCP_82586		0x000000	/* 82586 Mode */
diff --git a/drivers/net/dgrs_plx9060.h b/drivers/net/dgrs_plx9060.h
deleted file mode 100644
index 6888ae0..0000000
--- a/drivers/net/dgrs_plx9060.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- *	PLX 9060 PCI Interface chip
- */
-
-/*
- *	PCI configuration registers, same offset on local and PCI sides,
- *	but on PCI side, must use PCI BIOS calls to read/write.
- */
-#define	PCI_PLXREGS_BASE_ADDR	0x10
-
-#define	PCI_PLXREGS_IO_ADDR	0x14
-
-#define	PCI_SPACE0_BASE_ADDR	0x18
-
-#define	PCI_ROM_BASE_ADDR	0x30
-#	define PCI_ROM_ENABLED		0x00000001
-
-#define	PCI_INT_LINE		0x3C
-
-/*
- *	Registers accessible directly from PCI and local side.
- *	Offset is from PCI side.  Add PLX_LCL_OFFSET for local address.
- */
-#define	PLX_LCL_OFFSET	0x80	/* Offset of regs from local side */
-
-/*
- *	Local Configuration Registers
- */
-#define	PLX_SPACE0_RANGE	0x00	/* Range for PCI to Lcl Addr Space 0 */
-#define	PLX_SPACE0_BASE_ADDR	0x04	/* Lcl Base address remap */
-
-#define	PLX_ROM_RANGE		0x10	/* Range for expansion ROM (DMA) */
-#define	PLX_ROM_BASE_ADDR	0x14	/* Lcl base address remap for ROM */
-
-#define	PLX_BUS_REGION		0x18	/* Bus Region Descriptors */
-
-/*
- *	Shared Run Time Registers
- */
-#define	PLX_MBOX0		0x40
-#define	PLX_MBOX1		0x44
-#define	PLX_MBOX2		0x48
-#define	PLX_MBOX3		0x4C
-#define	PLX_MBOX4		0x50
-#define	PLX_MBOX5		0x54
-#define	PLX_MBOX6		0x58
-#define	PLX_MBOX7		0x5C
-
-#define	PLX_PCI2LCL_DOORBELL	0x60
-
-#define	PLX_LCL2PCI_DOORBELL	0x64
-
-#define	PLX_INT_CSR		0x68	/* Interrupt Control/Status */
-#	define	PLX_LSERR_ENABLE	0x00000001
-#	define	PLX_LSERR_PE		0x00000002
-#	define	PLX_SERR		0x00000004
-#	undef  PLX_UNUSED /*		0x00000008			*/
-#	undef  PLX_UNUSED /*		0x00000010			*/
-#	undef  PLX_UNUSED /*		0x00000020			*/
-#	undef  PLX_UNUSED /*		0x00000040			*/
-#	undef  PLX_UNUSED /*		0x00000080			*/
-#	define PLX_PCI_IE		0x00000100
-#	define	PLX_PCI_DOORBELL_IE	0x00000200
-#	define	PLX_PCI_ABORT_IE	0x00000400
-#	define	PLX_PCI_LOCAL_IE	0x00000800
-#	define	PLX_RETRY_ABORT_ENABLE	0x00001000
-#	define	PLX_PCI_DOORBELL_INT	0x00002000
-#	define	PLX_PCI_ABORT_INT	0x00004000
-#	define	PLX_PCI_LOCAL_INT	0x00008000
-#	define	PLX_LCL_IE		0x00010000
-#	define	PLX_LCL_DOORBELL_IE	0x00020000
-#	define	PLX_LCL_DMA0_IE		0x00040000
-#	define	PLX_LCL_DMA1_IE		0x00080000
-#	define	PLX_LCL_DOORBELL_INT	0x00100000
-#	define	PLX_LCL_DMA0_INT	0x00200000
-#	define	PLX_LCL_DMA1_INT	0x00400000
-#	define	PLX_LCL_BIST_INT	0x00800000
-#	define	PLX_BM_DIRECT_		0x01000000
-#	define	PLX_BM_DMA0_		0x02000000
-#	define	PLX_BM_DMA1_		0x04000000
-#	define	PLX_BM_ABORT_		0x08000000
-#	undef  PLX_UNUSED /*		0x10000000			*/
-#	undef  PLX_UNUSED /*		0x20000000			*/
-#	undef  PLX_UNUSED /*		0x40000000			*/
-#	undef  PLX_UNUSED /*		0x80000000			*/
-
-#define	PLX_MISC_CSR		0x6c	/* EEPROM,PCI,User,Init Control/Status*/
-#	define PLX_USEROUT		0x00010000
-#	define PLX_USERIN		0x00020000
-#	define PLX_EECK			0x01000000
-#	define PLX_EECS			0x02000000
-#	define PLX_EEWD			0x04000000
-#	define PLX_EERD			0x08000000
-
-/*
- *	DMA registers.  Offset is from local side
- */
-#define	PLX_DMA0_MODE		0x100
-#	define PLX_DMA_MODE_WIDTH32	0x00000003
-#	define PLX_DMA_MODE_WAITSTATES(X)	((X)<<2)
-#	define PLX_DMA_MODE_NOREADY	0x00000000
-#	define PLX_DMA_MODE_READY	0x00000040
-#	define PLX_DMA_MODE_NOBTERM	0x00000000
-#	define PLX_DMA_MODE_BTERM	0x00000080
-#	define PLX_DMA_MODE_NOBURST	0x00000000
-#	define PLX_DMA_MODE_BURST	0x00000100
-#	define PLX_DMA_MODE_NOCHAIN	0x00000000
-#	define PLX_DMA_MODE_CHAIN	0x00000200
-#	define PLX_DMA_MODE_DONE_IE	0x00000400
-#	define PLX_DMA_MODE_ADDR_HOLD	0x00000800
-
-#define	PLX_DMA0_PCI_ADDR	0x104
-					/* non-chaining mode PCI address */
-
-#define	PLX_DMA0_LCL_ADDR	0x108
-					/* non-chaining mode local address */
-
-#define	PLX_DMA0_SIZE		0x10C
-					/* non-chaining mode length */
-
-#define	PLX_DMA0_DESCRIPTOR	0x110
-#	define	PLX_DMA_DESC_EOC	0x00000002
-#	define	PLX_DMA_DESC_TC_IE	0x00000004
-#	define	PLX_DMA_DESC_TO_HOST	0x00000008
-#	define	PLX_DMA_DESC_TO_BOARD	0x00000000
-#	define	PLX_DMA_DESC_NEXTADDR	0xFFFFfff0
-
-#define	PLX_DMA1_MODE		0x114
-#define	PLX_DMA1_PCI_ADDR	0x118
-#define	PLX_DMA1_LCL_ADDR	0x11C
-#define	PLX_DMA1_SIZE		0x110
-#define	PLX_DMA1_DESCRIPTOR	0x124
-
-#define	PLX_DMA_CSR		0x128
-#	define PLX_DMA_CSR_0_ENABLE	0x00000001
-#	define PLX_DMA_CSR_0_START	0x00000002
-#	define PLX_DMA_CSR_0_ABORT	0x00000004
-#	define PLX_DMA_CSR_0_CLR_INTR	0x00000008
-#	define PLX_DMA_CSR_0_DONE	0x00000010
-#	define PLX_DMA_CSR_1_ENABLE	0x00000100
-#	define PLX_DMA_CSR_1_START	0x00000200
-#	define PLX_DMA_CSR_1_ABORT	0x00000400
-#	define PLX_DMA_CSR_1_CLR_INTR	0x00000800
-#	define PLX_DMA_CSR_1_DONE	0x00001000
-
-#define	PLX_DMA_ARB0		0x12C
-#	define PLX_DMA_ARB0_LATENCY_T	0x000000FF
-#	define PLX_DMA_ARB0_PAUSE_T	0x0000FF00
-#	define PLX_DMA_ARB0_LATENCY_EN	0x00010000
-#	define PLX_DMA_ARB0_PAUSE_EN	0x00020000
-#	define PLX_DMA_ARB0_BREQ_EN	0x00040000
-#	define PLX_DMA_ARB0_PRI		0x00180000
-#	define PLX_DMA_ARB0_PRI_ROUND	0x00000000
-#	define PLX_DMA_ARB0_PRI_0	0x00080000
-#	define PLX_DMA_ARB0_PRI_1	0x00100000
-
-#define	PLX_DMA_ARB1		0x130
-						/* Chan 0: FIFO DEPTH=16 */
-#	define PLX_DMA_ARB1_0_P2L_LW_TRIG(X)	( ((X)&15) <<  0 )
-#	define PLX_DMA_ARB1_0_L2P_LR_TRIG(X)	( ((X)&15) <<  4 )
-#	define PLX_DMA_ARB1_0_L2P_PW_TRIG(X)	( ((X)&15) <<  8 )
-#	define PLX_DMA_ARB1_0_P2L_PR_TRIG(X)	( ((X)&15) << 12 )
-						/* Chan 1: FIFO DEPTH=8 */
-#	define PLX_DMA_ARB1_1_P2L_LW_TRIG(X)	( ((X)& 7) << 16 )
-#	define PLX_DMA_ARB1_1_L2P_LR_TRIG(X)	( ((X)& 7) << 20 )
-#	define PLX_DMA_ARB1_1_L2P_PW_TRIG(X)	( ((X)& 7) << 24 )
-#	define PLX_DMA_ARB1_1_P2L_PR_TRIG(X)	( ((X)& 7) << 28 )
-
-typedef struct _dmachain
-{
-	ulong		pciaddr;
-	ulong		lcladdr;
-	ulong		len;
-	ulong		next;
-} DMACHAIN;
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 04e3710..5066beb 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -10,9 +10,9 @@
     (at your option) any later version.
 */
 
-#define DRV_NAME	"D-Link DL2000-based linux driver"
-#define DRV_VERSION	"v1.18"
-#define DRV_RELDATE	"2006/06/27"
+#define DRV_NAME	"DL2000/TC902x-based linux driver"
+#define DRV_VERSION	"v1.19"
+#define DRV_RELDATE	"2007/08/12"
 #include "dl2k.h"
 #include <linux/dma-mapping.h>
 
@@ -97,6 +97,7 @@
 	static int version_printed;
 	void *ring_space;
 	dma_addr_t ring_dma;
+	DECLARE_MAC_BUF(mac);
 
 	if (!version_printed++)
 		printk ("%s", version);
@@ -116,7 +117,6 @@
 		err = -ENOMEM;
 		goto err_out_res;
 	}
-	SET_MODULE_OWNER (dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 #ifdef MEM_MAPPING
@@ -257,10 +257,8 @@
 
 	card_idx++;
 
-	printk (KERN_INFO "%s: %s, %02x:%02x:%02x:%02x:%02x:%02x, IRQ %d\n",
-		dev->name, np->name,
-		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], irq);
+	printk (KERN_INFO "%s: %s, %s, IRQ %d\n",
+		dev->name, np->name, print_mac(mac, dev->dev_addr), irq);
 	if (tx_coalesce > 1)
 		printk(KERN_INFO "tx_coalesce:\t%d packets\n",
 				tx_coalesce);
@@ -292,7 +290,7 @@
 	return err;
 }
 
-int
+static int
 find_miiphy (struct net_device *dev)
 {
 	int i, phy_found = 0;
@@ -316,7 +314,7 @@
 	return 0;
 }
 
-int
+static int
 parse_eeprom (struct net_device *dev)
 {
 	int i, j;
@@ -339,17 +337,24 @@
 #ifdef	MEM_MAPPING
 	ioaddr = dev->base_addr;
 #endif
-	/* Check CRC */
-	crc = ~ether_crc_le (256 - 4, sromdata);
-	if (psrom->crc != crc) {
-		printk (KERN_ERR "%s: EEPROM data CRC error.\n", dev->name);
-		return -1;
+	if (np->pdev->vendor == PCI_VENDOR_ID_DLINK) {	/* D-Link Only */
+		/* Check CRC */
+		crc = ~ether_crc_le (256 - 4, sromdata);
+		if (psrom->crc != crc) {
+			printk (KERN_ERR "%s: EEPROM data CRC error.\n",
+					dev->name);
+			return -1;
+		}
 	}
 
 	/* Set MAC address */
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = psrom->mac_addr[i];
 
+	if (np->pdev->vendor != PCI_VENDOR_ID_DLINK) {
+		return 0;
+	}
+
 	/* Parse Software Information Block */
 	i = 0x30;
 	psib = (u8 *) sromdata;
@@ -1091,7 +1096,7 @@
 }
 
 
-int
+static int
 change_mtu (struct net_device *dev, int new_mtu)
 {
 	struct netdev_private *np = netdev_priv(dev);
@@ -1326,7 +1331,7 @@
 #define EEP_BUSY 0x8000
 /* Read the EEPROM word */
 /* We use I/O instruction to read/write eeprom to avoid fail on some machines */
-int
+static int
 read_eeprom (long ioaddr, int eep_addr)
 {
 	int i = 1000;
diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h
index e443065..5b80177 100644
--- a/drivers/net/dl2k.h
+++ b/drivers/net/dl2k.h
@@ -692,6 +692,7 @@
 
 static const struct pci_device_id rio_pci_tbl[] = {
 	{0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, },
+	{0x13f0, 0x1021, PCI_ANY_ID, PCI_ANY_ID, },
 	{ }
 };
 MODULE_DEVICE_TABLE (pci, rio_pci_tbl);
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index c3de81b..27ac010 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -148,7 +148,6 @@
 	struct resource *irq_res;
 
 	struct timer_list timer;
-	struct net_device_stats stats;
 	unsigned char srom[128];
 	spinlock_t lock;
 
@@ -166,8 +165,6 @@
 static void dm9000_timer(unsigned long);
 static void dm9000_init_dm9000(struct net_device *);
 
-static struct net_device_stats *dm9000_get_stats(struct net_device *);
-
 static irqreturn_t dm9000_interrupt(int, void *);
 
 static int dm9000_phy_read(struct net_device *dev, int phyaddr_unsused, int reg);
@@ -416,7 +413,6 @@
 		return -ENOMEM;
 	}
 
-	SET_MODULE_OWNER(ndev);
 	SET_NETDEV_DEV(ndev, &pdev->dev);
 
 	PRINTK2("dm9000_probe()");
@@ -559,7 +555,6 @@
 	ndev->tx_timeout         = &dm9000_timeout;
 	ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
 	ndev->stop		 = &dm9000_stop;
-	ndev->get_stats		 = &dm9000_get_stats;
 	ndev->set_multicast_list = &dm9000_hash_table;
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	ndev->poll_controller	 = &dm9000_poll_controller;
@@ -600,11 +595,10 @@
 	ret = register_netdev(ndev);
 
 	if (ret == 0) {
-		printk("%s: dm9000 at %p,%p IRQ %d MAC: ",
-		       ndev->name,  db->io_addr, db->io_data, ndev->irq);
-		for (i = 0; i < 5; i++)
-			printk("%02x:", ndev->dev_addr[i]);
-		printk("%02x\n", ndev->dev_addr[5]);
+		DECLARE_MAC_BUF(mac);
+		printk("%s: dm9000 at %p,%p IRQ %d MAC: %s\n",
+		       ndev->name,  db->io_addr, db->io_data, ndev->irq,
+		       print_mac(mac, ndev->dev_addr));
 	}
 	return 0;
 
@@ -700,6 +694,7 @@
 static int
 dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
+	unsigned long flags;
 	board_info_t *db = (board_info_t *) dev->priv;
 
 	PRINTK3("dm9000_start_xmit\n");
@@ -707,23 +702,17 @@
 	if (db->tx_pkt_cnt > 1)
 		return 1;
 
-	netif_stop_queue(dev);
-
-	/* Disable all interrupts */
-	iow(db, DM9000_IMR, IMR_PAR);
+	spin_lock_irqsave(&db->lock, flags);
 
 	/* Move data to DM9000 TX RAM */
 	writeb(DM9000_MWCMD, db->io_addr);
 
 	(db->outblk)(db->io_data, skb->data, skb->len);
-	db->stats.tx_bytes += skb->len;
+	dev->stats.tx_bytes += skb->len;
 
+	db->tx_pkt_cnt++;
 	/* TX control: First packet immediately send, second packet queue */
-	if (db->tx_pkt_cnt == 0) {
-
-		/* First Packet */
-		db->tx_pkt_cnt++;
-
+	if (db->tx_pkt_cnt == 1) {
 		/* Set TX length to DM9000 */
 		iow(db, DM9000_TXPLL, skb->len & 0xff);
 		iow(db, DM9000_TXPLH, (skb->len >> 8) & 0xff);
@@ -732,23 +721,17 @@
 		iow(db, DM9000_TCR, TCR_TXREQ);	/* Cleared after TX complete */
 
 		dev->trans_start = jiffies;	/* save the time stamp */
-
 	} else {
 		/* Second packet */
-		db->tx_pkt_cnt++;
 		db->queue_pkt_len = skb->len;
+		netif_stop_queue(dev);
 	}
 
+	spin_unlock_irqrestore(&db->lock, flags);
+
 	/* free this SKB */
 	dev_kfree_skb(skb);
 
-	/* Re-enable resource check */
-	if (db->tx_pkt_cnt == 1)
-		netif_wake_queue(dev);
-
-	/* Re-enable interrupt */
-	iow(db, DM9000_IMR, IMR_PAR | IMR_PTM | IMR_PRM);
-
 	return 0;
 }
 
@@ -802,7 +785,7 @@
 	if (tx_status & (NSR_TX2END | NSR_TX1END)) {
 		/* One packet sent complete */
 		db->tx_pkt_cnt--;
-		db->stats.tx_packets++;
+		dev->stats.tx_packets++;
 
 		/* Queue packet check & send */
 		if (db->tx_pkt_cnt > 0) {
@@ -864,17 +847,6 @@
 }
 
 /*
- *  Get statistics from driver.
- */
-static struct net_device_stats *
-dm9000_get_stats(struct net_device *dev)
-{
-	board_info_t *db = (board_info_t *) dev->priv;
-	return &db->stats;
-}
-
-
-/*
  *  A periodic timer routine
  *  Dynamic media sense, allocated Rx buffer...
  */
@@ -951,15 +923,15 @@
 			GoodPacket = false;
 			if (rxhdr.RxStatus & 0x100) {
 				PRINTK1("fifo error\n");
-				db->stats.rx_fifo_errors++;
+				dev->stats.rx_fifo_errors++;
 			}
 			if (rxhdr.RxStatus & 0x200) {
 				PRINTK1("crc error\n");
-				db->stats.rx_crc_errors++;
+				dev->stats.rx_crc_errors++;
 			}
 			if (rxhdr.RxStatus & 0x8000) {
 				PRINTK1("length error\n");
-				db->stats.rx_length_errors++;
+				dev->stats.rx_length_errors++;
 			}
 		}
 
@@ -972,12 +944,12 @@
 			/* Read received packet from RX SRAM */
 
 			(db->inblk)(db->io_data, rdptr, RxLen);
-			db->stats.rx_bytes += RxLen;
+			dev->stats.rx_bytes += RxLen;
 
 			/* Pass to upper layer */
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
-			db->stats.rx_packets++;
+			dev->stats.rx_packets++;
 
 		} else {
 			/* need to dump the packet's data */
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index 756a6bc..84e14f3 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -71,7 +71,6 @@
 	dev->change_mtu = NULL;
 	dev->flags |= IFF_NOARP;
 	dev->flags &= ~IFF_MULTICAST;
-	SET_MODULE_OWNER(dev);
 	random_ether_addr(dev->dev_addr);
 }
 
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 6b6401e..64f35e2 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -539,6 +539,7 @@
 	struct csr __iomem *csr;
 	enum scb_cmd_lo cuc_cmd;
 	unsigned int cbs_avail;
+	struct napi_struct napi;
 	struct cb *cbs;
 	struct cb *cb_to_use;
 	struct cb *cb_to_send;
@@ -557,7 +558,6 @@
 	enum mac mac;
 	enum phy phy;
 	struct params params;
-	struct net_device_stats net_stats;
 	struct timer_list watchdog;
 	struct timer_list blink_timer;
 	struct mii_if_info mii;
@@ -1482,7 +1482,8 @@
 
 static void e100_update_stats(struct nic *nic)
 {
-	struct net_device_stats *ns = &nic->net_stats;
+	struct net_device *dev = nic->netdev;
+	struct net_device_stats *ns = &dev->stats;
 	struct stats *s = &nic->mem->stats;
 	u32 *complete = (nic->mac < mac_82558_D101_A4) ? &s->fc_xmt_pause :
 		(nic->mac < mac_82559_D101M) ? (u32 *)&s->xmt_tco_frames :
@@ -1604,7 +1605,8 @@
 	else
 		nic->flags &= ~ich_10h_workaround;
 
-	mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD);
+	mod_timer(&nic->watchdog,
+		  round_jiffies(jiffies + E100_WATCHDOG_PERIOD));
 }
 
 static void e100_xmit_prepare(struct nic *nic, struct cb *cb,
@@ -1659,6 +1661,7 @@
 
 static int e100_tx_clean(struct nic *nic)
 {
+	struct net_device *dev = nic->netdev;
 	struct cb *cb;
 	int tx_cleaned = 0;
 
@@ -1673,8 +1676,8 @@
 		        cb->status);
 
 		if(likely(cb->skb != NULL)) {
-			nic->net_stats.tx_packets++;
-			nic->net_stats.tx_bytes += cb->skb->len;
+			dev->stats.tx_packets++;
+			dev->stats.tx_bytes += cb->skb->len;
 
 			pci_unmap_single(nic->pdev,
 				le32_to_cpu(cb->u.tcb.tbd.buf_addr),
@@ -1805,6 +1808,7 @@
 static int e100_rx_indicate(struct nic *nic, struct rx *rx,
 	unsigned int *work_done, unsigned int work_to_do)
 {
+	struct net_device *dev = nic->netdev;
 	struct sk_buff *skb = rx->skb;
 	struct rfd *rfd = (struct rfd *)skb->data;
 	u16 rfd_status, actual_size;
@@ -1849,8 +1853,8 @@
 		nic->rx_over_length_errors++;
 		dev_kfree_skb_any(skb);
 	} else {
-		nic->net_stats.rx_packets++;
-		nic->net_stats.rx_bytes += actual_size;
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += actual_size;
 		nic->netdev->last_rx = jiffies;
 		netif_receive_skb(skb);
 		if(work_done)
@@ -1974,35 +1978,31 @@
 	if(stat_ack & stat_ack_rnr)
 		nic->ru_running = RU_SUSPENDED;
 
-	if(likely(netif_rx_schedule_prep(netdev))) {
+	if(likely(netif_rx_schedule_prep(netdev, &nic->napi))) {
 		e100_disable_irq(nic);
-		__netif_rx_schedule(netdev);
+		__netif_rx_schedule(netdev, &nic->napi);
 	}
 
 	return IRQ_HANDLED;
 }
 
-static int e100_poll(struct net_device *netdev, int *budget)
+static int e100_poll(struct napi_struct *napi, int budget)
 {
-	struct nic *nic = netdev_priv(netdev);
-	unsigned int work_to_do = min(netdev->quota, *budget);
+	struct nic *nic = container_of(napi, struct nic, napi);
+	struct net_device *netdev = nic->netdev;
 	unsigned int work_done = 0;
 	int tx_cleaned;
 
-	e100_rx_clean(nic, &work_done, work_to_do);
+	e100_rx_clean(nic, &work_done, budget);
 	tx_cleaned = e100_tx_clean(nic);
 
 	/* If no Rx and Tx cleanup work was done, exit polling mode. */
 	if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
-		netif_rx_complete(netdev);
+		netif_rx_complete(netdev, napi);
 		e100_enable_irq(nic);
-		return 0;
 	}
 
-	*budget -= work_done;
-	netdev->quota -= work_done;
-
-	return 1;
+	return work_done;
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2017,12 +2017,6 @@
 }
 #endif
 
-static struct net_device_stats *e100_get_stats(struct net_device *netdev)
-{
-	struct nic *nic = netdev_priv(netdev);
-	return &nic->net_stats;
-}
-
 static int e100_set_mac_address(struct net_device *netdev, void *p)
 {
 	struct nic *nic = netdev_priv(netdev);
@@ -2071,7 +2065,7 @@
 		nic->netdev->name, nic->netdev)))
 		goto err_no_irq;
 	netif_wake_queue(nic->netdev);
-	netif_poll_enable(nic->netdev);
+	napi_enable(&nic->napi);
 	/* enable ints _after_ enabling poll, preventing a race between
 	 * disable ints+schedule */
 	e100_enable_irq(nic);
@@ -2089,7 +2083,7 @@
 static void e100_down(struct nic *nic)
 {
 	/* wait here for poll to complete */
-	netif_poll_disable(nic->netdev);
+	napi_disable(&nic->napi);
 	netif_stop_queue(nic->netdev);
 	e100_hw_reset(nic);
 	free_irq(nic->pdev->irq, nic->netdev);
@@ -2380,11 +2374,6 @@
 };
 #define E100_TEST_LEN	sizeof(e100_gstrings_test) / ETH_GSTRING_LEN
 
-static int e100_diag_test_count(struct net_device *netdev)
-{
-	return E100_TEST_LEN;
-}
-
 static void e100_diag_test(struct net_device *netdev,
 	struct ethtool_test *test, u64 *data)
 {
@@ -2447,9 +2436,16 @@
 #define E100_NET_STATS_LEN	21
 #define E100_STATS_LEN	sizeof(e100_gstrings_stats) / ETH_GSTRING_LEN
 
-static int e100_get_stats_count(struct net_device *netdev)
+static int e100_get_sset_count(struct net_device *netdev, int sset)
 {
-	return E100_STATS_LEN;
+	switch (sset) {
+	case ETH_SS_TEST:
+		return E100_TEST_LEN;
+	case ETH_SS_STATS:
+		return E100_STATS_LEN;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void e100_get_ethtool_stats(struct net_device *netdev,
@@ -2459,7 +2455,7 @@
 	int i;
 
 	for(i = 0; i < E100_NET_STATS_LEN; i++)
-		data[i] = ((unsigned long *)&nic->net_stats)[i];
+		data[i] = ((unsigned long *)&netdev->stats)[i];
 
 	data[i++] = nic->tx_deferred;
 	data[i++] = nic->tx_single_collisions;
@@ -2500,13 +2496,11 @@
 	.set_eeprom		= e100_set_eeprom,
 	.get_ringparam		= e100_get_ringparam,
 	.set_ringparam		= e100_set_ringparam,
-	.self_test_count	= e100_diag_test_count,
 	.self_test		= e100_diag_test,
 	.get_strings		= e100_get_strings,
 	.phys_id		= e100_phys_id,
-	.get_stats_count	= e100_get_stats_count,
 	.get_ethtool_stats	= e100_get_ethtool_stats,
-	.get_perm_addr		= ethtool_op_get_perm_addr,
+	.get_sset_count		= e100_get_sset_count,
 };
 
 static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
@@ -2555,6 +2549,7 @@
 	struct net_device *netdev;
 	struct nic *nic;
 	int err;
+	DECLARE_MAC_BUF(mac);
 
 	if(!(netdev = alloc_etherdev(sizeof(struct nic)))) {
 		if(((1 << debug) - 1) & NETIF_MSG_PROBE)
@@ -2565,7 +2560,6 @@
 	netdev->open = e100_open;
 	netdev->stop = e100_close;
 	netdev->hard_start_xmit = e100_xmit_frame;
-	netdev->get_stats = e100_get_stats;
 	netdev->set_multicast_list = e100_set_multicast_list;
 	netdev->set_mac_address = e100_set_mac_address;
 	netdev->change_mtu = e100_change_mtu;
@@ -2573,14 +2567,13 @@
 	SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops);
 	netdev->tx_timeout = e100_tx_timeout;
 	netdev->watchdog_timeo = E100_WATCHDOG_PERIOD;
-	netdev->poll = e100_poll;
-	netdev->weight = E100_NAPI_WEIGHT;
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	netdev->poll_controller = e100_netpoll;
 #endif
 	strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
 
 	nic = netdev_priv(netdev);
+	netif_napi_add(netdev, &nic->napi, e100_poll, E100_NAPI_WEIGHT);
 	nic->netdev = netdev;
 	nic->pdev = pdev;
 	nic->msg_enable = (1 << debug) - 1;
@@ -2608,7 +2601,6 @@
 		goto err_out_free_res;
 	}
 
-	SET_MODULE_OWNER(netdev);
 	SET_NETDEV_DEV(netdev, &pdev->dev);
 
 	if (use_io)
@@ -2689,11 +2681,9 @@
 		goto err_out_free;
 	}
 
-	DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, "
-		"MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n",
-		(unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0), pdev->irq,
-		netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
-		netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
+	DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %s\n",
+		(unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0),
+		pdev->irq, print_mac(mac, netdev->dev_addr));
 
 	return 0;
 
@@ -2734,7 +2724,7 @@
 	struct nic *nic = netdev_priv(netdev);
 
 	if (netif_running(netdev))
-		netif_poll_disable(nic->netdev);
+		napi_disable(&nic->napi);
 	del_timer_sync(&nic->watchdog);
 	netif_carrier_off(nic->netdev);
 	netif_device_detach(netdev);
@@ -2780,7 +2770,7 @@
 	struct nic *nic = netdev_priv(netdev);
 
 	if (netif_running(netdev))
-		netif_poll_disable(nic->netdev);
+		napi_disable(&nic->napi);
 	del_timer_sync(&nic->watchdog);
 	netif_carrier_off(nic->netdev);
 
@@ -2805,12 +2795,13 @@
 static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
 {
 	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct nic *nic = netdev_priv(netdev);
 
 	/* Similar to calling e100_down(), but avoids adpater I/O. */
 	netdev->stop(netdev);
 
 	/* Detach; put netif into state similar to hotplug unplug. */
-	netif_poll_enable(netdev);
+	napi_enable(&nic->napi);
 	netif_device_detach(netdev);
 	pci_disable_device(pdev);
 
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 16a6edf..781ed99 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -300,6 +300,7 @@
 				int cleaned_count);
 	struct e1000_rx_ring *rx_ring;      /* One per active queue */
 #ifdef CONFIG_E1000_NAPI
+	struct napi_struct napi;
 	struct net_device *polling_netdev;  /* One per active queue */
 #endif
 	int num_tx_queues;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index bb08375..6c9a643 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -106,8 +106,7 @@
 };
 
 #define E1000_QUEUE_STATS_LEN 0
-#define E1000_GLOBAL_STATS_LEN	\
-	sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats)
+#define E1000_GLOBAL_STATS_LEN ARRAY_SIZE(e1000_gstrings_stats)
 #define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN + E1000_QUEUE_STATS_LEN)
 static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
 	"Register test  (offline)", "Eeprom test    (offline)",
@@ -619,8 +618,6 @@
 
 	strncpy(drvinfo->fw_version, firmware_version, 32);
 	strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
-	drvinfo->n_stats = E1000_STATS_LEN;
-	drvinfo->testinfo_len = E1000_TEST_LEN;
 	drvinfo->regdump_len = e1000_get_regs_len(netdev);
 	drvinfo->eedump_len = e1000_get_eeprom_len(netdev);
 }
@@ -1612,9 +1609,16 @@
 }
 
 static int
-e1000_diag_test_count(struct net_device *netdev)
+e1000_get_sset_count(struct net_device *netdev, int sset)
 {
-	return E1000_TEST_LEN;
+	switch (sset) {
+	case ETH_SS_TEST:
+		return E1000_TEST_LEN;
+	case ETH_SS_STATS:
+		return E1000_STATS_LEN;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 extern void e1000_power_up_phy(struct e1000_adapter *);
@@ -1706,6 +1710,7 @@
 	case E1000_DEV_ID_82545EM_COPPER:
 	case E1000_DEV_ID_82546GB_QUAD_COPPER:
 	case E1000_DEV_ID_82546GB_PCIE:
+	case E1000_DEV_ID_82571EB_SERDES_QUAD:
 		/* these don't support WoL at all */
 		wol->supported = 0;
 		break;
@@ -1723,7 +1728,9 @@
 		retval = 0;
 		break;
 	case E1000_DEV_ID_82571EB_QUAD_COPPER:
+	case E1000_DEV_ID_82571EB_QUAD_FIBER:
 	case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE:
+	case E1000_DEV_ID_82571PT_QUAD_COPPER:
 	case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
 		/* quad port adapters only support WoL on port A */
 		if (!adapter->quad_port_a) {
@@ -1896,12 +1903,6 @@
 	return 0;
 }
 
-static int
-e1000_get_stats_count(struct net_device *netdev)
-{
-	return E1000_STATS_LEN;
-}
-
 static void
 e1000_get_ethtool_stats(struct net_device *netdev,
 		struct ethtool_stats *stats, uint64_t *data)
@@ -1963,17 +1964,13 @@
 	.set_rx_csum            = e1000_set_rx_csum,
 	.get_tx_csum            = e1000_get_tx_csum,
 	.set_tx_csum            = e1000_set_tx_csum,
-	.get_sg                 = ethtool_op_get_sg,
 	.set_sg                 = ethtool_op_set_sg,
-	.get_tso                = ethtool_op_get_tso,
 	.set_tso                = e1000_set_tso,
-	.self_test_count        = e1000_diag_test_count,
 	.self_test              = e1000_diag_test,
 	.get_strings            = e1000_get_strings,
 	.phys_id                = e1000_phys_id,
-	.get_stats_count        = e1000_get_stats_count,
 	.get_ethtool_stats      = e1000_get_ethtool_stats,
-	.get_perm_addr          = ethtool_op_get_perm_addr,
+	.get_sset_count		= e1000_get_sset_count,
 };
 
 void e1000_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 9be4469..8fa0fe4 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -384,7 +384,11 @@
 	case E1000_DEV_ID_82571EB_COPPER:
 	case E1000_DEV_ID_82571EB_FIBER:
 	case E1000_DEV_ID_82571EB_SERDES:
+	case E1000_DEV_ID_82571EB_SERDES_DUAL:
+	case E1000_DEV_ID_82571EB_SERDES_QUAD:
 	case E1000_DEV_ID_82571EB_QUAD_COPPER:
+	case E1000_DEV_ID_82571PT_QUAD_COPPER:
+	case E1000_DEV_ID_82571EB_QUAD_FIBER:
 	case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE:
 		hw->mac_type = e1000_82571;
 		break;
@@ -485,6 +489,8 @@
     case E1000_DEV_ID_82545GM_SERDES:
     case E1000_DEV_ID_82546GB_SERDES:
     case E1000_DEV_ID_82571EB_SERDES:
+    case E1000_DEV_ID_82571EB_SERDES_DUAL:
+    case E1000_DEV_ID_82571EB_SERDES_QUAD:
     case E1000_DEV_ID_82572EI_SERDES:
     case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
         hw->media_type = e1000_media_type_internal_serdes;
@@ -865,10 +871,6 @@
     uint32_t ctrl;
     uint32_t i;
     int32_t ret_val;
-    uint16_t pcix_cmd_word;
-    uint16_t pcix_stat_hi_word;
-    uint16_t cmd_mmrbc;
-    uint16_t stat_mmrbc;
     uint32_t mta_size;
     uint32_t reg_data;
     uint32_t ctrl_ext;
@@ -958,24 +960,9 @@
         break;
     default:
         /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
-        if (hw->bus_type == e1000_bus_type_pcix) {
-            e1000_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word);
-            e1000_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI,
-                &pcix_stat_hi_word);
-            cmd_mmrbc = (pcix_cmd_word & PCIX_COMMAND_MMRBC_MASK) >>
-                PCIX_COMMAND_MMRBC_SHIFT;
-            stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
-                PCIX_STATUS_HI_MMRBC_SHIFT;
-            if (stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
-                stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
-            if (cmd_mmrbc > stat_mmrbc) {
-                pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK;
-                pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
-                e1000_write_pci_cfg(hw, PCIX_COMMAND_REGISTER,
-                    &pcix_cmd_word);
-            }
-        }
-        break;
+	if (hw->bus_type == e1000_bus_type_pcix && e1000_pcix_get_mmrbc(hw) > 2048)
+		e1000_pcix_set_mmrbc(hw, 2048);
+	break;
     }
 
     /* More time needed for PHY to initialize */
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index bd000b80..a2a86c5 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -424,6 +424,8 @@
 void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
 void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
 int32_t e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value);
+void e1000_pcix_set_mmrbc(struct e1000_hw *hw, int mmrbc);
+int e1000_pcix_get_mmrbc(struct e1000_hw *hw);
 /* Port I/O is only supported on 82544 and newer */
 void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value);
 int32_t e1000_disable_pciex_master(struct e1000_hw *hw);
@@ -475,7 +477,11 @@
 #define E1000_DEV_ID_82571EB_FIBER       0x105F
 #define E1000_DEV_ID_82571EB_SERDES      0x1060
 #define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
+#define E1000_DEV_ID_82571PT_QUAD_COPPER 0x10D5
+#define E1000_DEV_ID_82571EB_QUAD_FIBER  0x10A5
 #define E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE  0x10BC
+#define E1000_DEV_ID_82571EB_SERDES_DUAL 0x10D9
+#define E1000_DEV_ID_82571EB_SERDES_QUAD 0x10DA
 #define E1000_DEV_ID_82572EI_COPPER      0x107D
 #define E1000_DEV_ID_82572EI_FIBER       0x107E
 #define E1000_DEV_ID_82572EI_SERDES      0x107F
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index f48b659..0472638 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -100,6 +100,7 @@
 	INTEL_E1000_ETHERNET_DEVICE(0x1099),
 	INTEL_E1000_ETHERNET_DEVICE(0x109A),
 	INTEL_E1000_ETHERNET_DEVICE(0x10A4),
+	INTEL_E1000_ETHERNET_DEVICE(0x10A5),
 	INTEL_E1000_ETHERNET_DEVICE(0x10B5),
 	INTEL_E1000_ETHERNET_DEVICE(0x10B9),
 	INTEL_E1000_ETHERNET_DEVICE(0x10BA),
@@ -107,6 +108,9 @@
 	INTEL_E1000_ETHERNET_DEVICE(0x10BC),
 	INTEL_E1000_ETHERNET_DEVICE(0x10C4),
 	INTEL_E1000_ETHERNET_DEVICE(0x10C5),
+	INTEL_E1000_ETHERNET_DEVICE(0x10D5),
+	INTEL_E1000_ETHERNET_DEVICE(0x10D9),
+	INTEL_E1000_ETHERNET_DEVICE(0x10DA),
 	/* required last entry */
 	{0,}
 };
@@ -162,7 +166,7 @@
 static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter,
                                     struct e1000_tx_ring *tx_ring);
 #ifdef CONFIG_E1000_NAPI
-static int e1000_clean(struct net_device *poll_dev, int *budget);
+static int e1000_clean(struct napi_struct *napi, int budget);
 static boolean_t e1000_clean_rx_irq(struct e1000_adapter *adapter,
                                     struct e1000_rx_ring *rx_ring,
                                     int *work_done, int work_to_do);
@@ -541,7 +545,7 @@
 	clear_bit(__E1000_DOWN, &adapter->flags);
 
 #ifdef CONFIG_E1000_NAPI
-	netif_poll_enable(adapter->netdev);
+	napi_enable(&adapter->napi);
 #endif
 	e1000_irq_enable(adapter);
 
@@ -630,7 +634,7 @@
 	set_bit(__E1000_DOWN, &adapter->flags);
 
 #ifdef CONFIG_E1000_NAPI
-	netif_poll_disable(netdev);
+	napi_disable(&adapter->napi);
 #endif
 	e1000_irq_disable(adapter);
 
@@ -868,6 +872,8 @@
 	int i, err, pci_using_dac;
 	uint16_t eeprom_data = 0;
 	uint16_t eeprom_apme_mask = E1000_EEPROM_APME;
+	DECLARE_MAC_BUF(mac);
+
 	if ((err = pci_enable_device(pdev)))
 		return err;
 
@@ -893,7 +899,6 @@
 	if (!netdev)
 		goto err_alloc_etherdev;
 
-	SET_MODULE_OWNER(netdev);
 	SET_NETDEV_DEV(netdev, &pdev->dev);
 
 	pci_set_drvdata(pdev, netdev);
@@ -932,8 +937,7 @@
 	netdev->tx_timeout = &e1000_tx_timeout;
 	netdev->watchdog_timeo = 5 * HZ;
 #ifdef CONFIG_E1000_NAPI
-	netdev->poll = &e1000_clean;
-	netdev->weight = 64;
+	netif_napi_add(netdev, &adapter->napi, e1000_clean, 64);
 #endif
 	netdev->vlan_rx_register = e1000_vlan_rx_register;
 	netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid;
@@ -1096,7 +1100,9 @@
 		break;
 	case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
 	case E1000_DEV_ID_82571EB_QUAD_COPPER:
+	case E1000_DEV_ID_82571EB_QUAD_FIBER:
 	case E1000_DEV_ID_82571EB_QUAD_COPPER_LOWPROFILE:
+	case E1000_DEV_ID_82571PT_QUAD_COPPER:
 		/* if quad port adapter, disable WoL on all but port A */
 		if (global_quad_port_a != 0)
 			adapter->eeprom_wol = 0;
@@ -1128,8 +1134,7 @@
 		 "32-bit"));
 	}
 
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", netdev->dev_addr[i], i == 5 ? '\n' : ':');
+	printk("%s\n", print_mac(mac, netdev->dev_addr));
 
 	/* reset the hardware with the new settings */
 	e1000_reset(adapter);
@@ -1145,9 +1150,6 @@
 	/* tell the stack to leave us alone until e1000_open() is called */
 	netif_carrier_off(netdev);
 	netif_stop_queue(netdev);
-#ifdef CONFIG_E1000_NAPI
-	netif_poll_disable(netdev);
-#endif
 
 	strcpy(netdev->name, "eth%d");
 	if ((err = register_netdev(netdev)))
@@ -1216,12 +1218,13 @@
 	 * would have already happened in close and is redundant. */
 	e1000_release_hw_control(adapter);
 
-	unregister_netdev(netdev);
 #ifdef CONFIG_E1000_NAPI
 	for (i = 0; i < adapter->num_rx_queues; i++)
 		dev_put(&adapter->polling_netdev[i]);
 #endif
 
+	unregister_netdev(netdev);
+
 	if (!e1000_check_phy_reset_block(&adapter->hw))
 		e1000_phy_hw_reset(&adapter->hw);
 
@@ -1319,8 +1322,6 @@
 #ifdef CONFIG_E1000_NAPI
 	for (i = 0; i < adapter->num_rx_queues; i++) {
 		adapter->polling_netdev[i].priv = adapter;
-		adapter->polling_netdev[i].poll = &e1000_clean;
-		adapter->polling_netdev[i].weight = 64;
 		dev_hold(&adapter->polling_netdev[i]);
 		set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state);
 	}
@@ -1437,7 +1438,7 @@
 	clear_bit(__E1000_DOWN, &adapter->flags);
 
 #ifdef CONFIG_E1000_NAPI
-	netif_poll_enable(netdev);
+	napi_enable(&adapter->napi);
 #endif
 
 	e1000_irq_enable(adapter);
@@ -3260,14 +3261,13 @@
 	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;
-	unsigned int len = skb->len;
+	unsigned int len = skb->len - skb->data_len;
 	unsigned long flags;
-	unsigned int nr_frags = 0;
-	unsigned int mss = 0;
+	unsigned int nr_frags;
+	unsigned int mss;
 	int count = 0;
 	int tso;
 	unsigned int f;
-	len -= skb->data_len;
 
 	/* This goes back to the question of how to logically map a tx queue
 	 * to a flow.  Right now, performance is impacted slightly negatively
@@ -3301,7 +3301,7 @@
 		* points to just header, pull a few bytes of payload from
 		* frags into skb->data */
 		hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
-		if (skb->data_len && (hdr_len == (skb->len - skb->data_len))) {
+		if (skb->data_len && hdr_len == len) {
 			switch (adapter->hw.mac_type) {
 				unsigned int pull_size;
 			case e1000_82544:
@@ -3780,12 +3780,12 @@
 	}
 
 #ifdef CONFIG_E1000_NAPI
-	if (likely(netif_rx_schedule_prep(netdev))) {
+	if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) {
 		adapter->total_tx_bytes = 0;
 		adapter->total_tx_packets = 0;
 		adapter->total_rx_bytes = 0;
 		adapter->total_rx_packets = 0;
-		__netif_rx_schedule(netdev);
+		__netif_rx_schedule(netdev, &adapter->napi);
 	} else
 		e1000_irq_enable(adapter);
 #else
@@ -3865,12 +3865,12 @@
 		E1000_WRITE_REG(hw, IMC, ~0);
 		E1000_WRITE_FLUSH(hw);
 	}
-	if (likely(netif_rx_schedule_prep(netdev))) {
+	if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) {
 		adapter->total_tx_bytes = 0;
 		adapter->total_tx_packets = 0;
 		adapter->total_rx_bytes = 0;
 		adapter->total_rx_packets = 0;
-		__netif_rx_schedule(netdev);
+		__netif_rx_schedule(netdev, &adapter->napi);
 	} else
 		/* this really should not happen! if it does it is basically a
 		 * bug, but not a hard error, so enable ints and continue */
@@ -3918,10 +3918,10 @@
  **/
 
 static int
-e1000_clean(struct net_device *poll_dev, int *budget)
+e1000_clean(struct napi_struct *napi, int budget)
 {
-	struct e1000_adapter *adapter;
-	int work_to_do = min(*budget, poll_dev->quota);
+	struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi);
+	struct net_device *poll_dev = adapter->netdev;
 	int tx_cleaned = 0, work_done = 0;
 
 	/* Must NOT use netdev_priv macro here. */
@@ -3942,23 +3942,19 @@
 	}
 
 	adapter->clean_rx(adapter, &adapter->rx_ring[0],
-	                  &work_done, work_to_do);
-
-	*budget -= work_done;
-	poll_dev->quota -= work_done;
+	                  &work_done, budget);
 
 	/* If no Tx and not enough Rx work done, exit the polling mode */
-	if ((!tx_cleaned && (work_done == 0)) ||
+	if ((!tx_cleaned && (work_done < budget)) ||
 	   !netif_running(poll_dev)) {
 quit_polling:
 		if (likely(adapter->itr_setting & 3))
 			e1000_set_itr(adapter);
-		netif_rx_complete(poll_dev);
+		netif_rx_complete(poll_dev, napi);
 		e1000_irq_enable(adapter);
-		return 0;
 	}
 
-	return 1;
+	return work_done;
 }
 
 #endif
@@ -4906,6 +4902,20 @@
 	pci_write_config_word(adapter->pdev, reg, *value);
 }
 
+int
+e1000_pcix_get_mmrbc(struct e1000_hw *hw)
+{
+	struct e1000_adapter *adapter = hw->back;
+	return pcix_get_mmrbc(adapter->pdev);
+}
+
+void
+e1000_pcix_set_mmrbc(struct e1000_hw *hw, int mmrbc)
+{
+	struct e1000_adapter *adapter = hw->back;
+	pcix_set_mmrbc(adapter->pdev, mmrbc);
+}
+
 int32_t
 e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
 {
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
new file mode 100644
index 0000000..cf70522
--- /dev/null
+++ b/drivers/net/e1000e/82571.c
@@ -0,0 +1,1351 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/*
+ * 82571EB Gigabit Ethernet Controller
+ * 82571EB Gigabit Ethernet Controller (Fiber)
+ * 82572EI Gigabit Ethernet Controller (Copper)
+ * 82572EI Gigabit Ethernet Controller (Fiber)
+ * 82572EI Gigabit Ethernet Controller
+ * 82573V Gigabit Ethernet Controller (Copper)
+ * 82573E Gigabit Ethernet Controller (Copper)
+ * 82573L Gigabit Ethernet Controller
+ */
+
+#include <linux/netdevice.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "e1000.h"
+
+#define ID_LED_RESERVED_F746 0xF746
+#define ID_LED_DEFAULT_82573 ((ID_LED_DEF1_DEF2 << 12) | \
+			      (ID_LED_OFF1_ON2  <<  8) | \
+			      (ID_LED_DEF1_DEF2 <<  4) | \
+			      (ID_LED_DEF1_DEF2))
+
+#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
+
+static s32 e1000_get_phy_id_82571(struct e1000_hw *hw);
+static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw);
+static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
+static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
+				      u16 words, u16 *data);
+static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
+static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw);
+static s32 e1000_setup_link_82571(struct e1000_hw *hw);
+static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw);
+
+/**
+ *  e1000_init_phy_params_82571 - Init PHY func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+
+	if (hw->media_type != e1000_media_type_copper) {
+		phy->type = e1000_phy_none;
+		return 0;
+	}
+
+	phy->addr			 = 1;
+	phy->autoneg_mask		 = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+	phy->reset_delay_us		 = 100;
+
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		phy->type		 = e1000_phy_igp_2;
+		break;
+	case e1000_82573:
+		phy->type		 = e1000_phy_m88;
+		break;
+	default:
+		return -E1000_ERR_PHY;
+		break;
+	}
+
+	/* This can only be done after all function pointers are setup. */
+	ret_val = e1000_get_phy_id_82571(hw);
+
+	/* Verify phy id */
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		if (phy->id != IGP01E1000_I_PHY_ID)
+			return -E1000_ERR_PHY;
+		break;
+	case e1000_82573:
+		if (phy->id != M88E1111_I_PHY_ID)
+			return -E1000_ERR_PHY;
+		break;
+	default:
+		return -E1000_ERR_PHY;
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_init_nvm_params_82571 - Init NVM func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = er32(EECD);
+	u16 size;
+
+	nvm->opcode_bits = 8;
+	nvm->delay_usec = 1;
+	switch (nvm->override) {
+	case e1000_nvm_override_spi_large:
+		nvm->page_size = 32;
+		nvm->address_bits = 16;
+		break;
+	case e1000_nvm_override_spi_small:
+		nvm->page_size = 8;
+		nvm->address_bits = 8;
+		break;
+	default:
+		nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+		nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+		break;
+	}
+
+	switch (hw->mac.type) {
+	case e1000_82573:
+		if (((eecd >> 15) & 0x3) == 0x3) {
+			nvm->type = e1000_nvm_flash_hw;
+			nvm->word_size = 2048;
+			/* Autonomous Flash update bit must be cleared due
+			 * to Flash update issue.
+			 */
+			eecd &= ~E1000_EECD_AUPDEN;
+			ew32(EECD, eecd);
+			break;
+		}
+		/* Fall Through */
+	default:
+		nvm->type	= e1000_nvm_eeprom_spi;
+		size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+				  E1000_EECD_SIZE_EX_SHIFT);
+		/* Added to a constant, "size" becomes the left-shift value
+		 * for setting word_size.
+		 */
+		size += NVM_WORD_SIZE_BASE_SHIFT;
+		nvm->word_size	= 1 << size;
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_init_mac_params_82571 - Init MAC func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_mac_info *mac = &hw->mac;
+	struct e1000_mac_operations *func = &mac->ops;
+
+	/* Set media type */
+	switch (adapter->pdev->device) {
+	case E1000_DEV_ID_82571EB_FIBER:
+	case E1000_DEV_ID_82572EI_FIBER:
+	case E1000_DEV_ID_82571EB_QUAD_FIBER:
+		hw->media_type = e1000_media_type_fiber;
+		break;
+	case E1000_DEV_ID_82571EB_SERDES:
+	case E1000_DEV_ID_82572EI_SERDES:
+		hw->media_type = e1000_media_type_internal_serdes;
+		break;
+	default:
+		hw->media_type = e1000_media_type_copper;
+		break;
+	}
+
+	/* Set mta register count */
+	mac->mta_reg_count = 128;
+	/* Set rar entry count */
+	mac->rar_entry_count = E1000_RAR_ENTRIES;
+	/* Set if manageability features are enabled. */
+	mac->arc_subsystem_valid =
+		(er32(FWSM) & E1000_FWSM_MODE_MASK) ? 1 : 0;
+
+	/* check for link */
+	switch (hw->media_type) {
+	case e1000_media_type_copper:
+		func->setup_physical_interface = e1000_setup_copper_link_82571;
+		func->check_for_link = e1000e_check_for_copper_link;
+		func->get_link_up_info = e1000e_get_speed_and_duplex_copper;
+		break;
+	case e1000_media_type_fiber:
+		func->setup_physical_interface = e1000_setup_fiber_serdes_link_82571;
+		func->check_for_link = e1000e_check_for_fiber_link;
+		func->get_link_up_info = e1000e_get_speed_and_duplex_fiber_serdes;
+		break;
+	case e1000_media_type_internal_serdes:
+		func->setup_physical_interface = e1000_setup_fiber_serdes_link_82571;
+		func->check_for_link = e1000e_check_for_serdes_link;
+		func->get_link_up_info = e1000e_get_speed_and_duplex_fiber_serdes;
+		break;
+	default:
+		return -E1000_ERR_CONFIG;
+		break;
+	}
+
+	return 0;
+}
+
+static s32 e1000_get_invariants_82571(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	static int global_quad_port_a; /* global port a indication */
+	struct pci_dev *pdev = adapter->pdev;
+	u16 eeprom_data = 0;
+	int is_port_b = er32(STATUS) & E1000_STATUS_FUNC_1;
+	s32 rc;
+
+	rc = e1000_init_mac_params_82571(adapter);
+	if (rc)
+		return rc;
+
+	rc = e1000_init_nvm_params_82571(hw);
+	if (rc)
+		return rc;
+
+	rc = e1000_init_phy_params_82571(hw);
+	if (rc)
+		return rc;
+
+	/* tag quad port adapters first, it's used below */
+	switch (pdev->device) {
+	case E1000_DEV_ID_82571EB_QUAD_COPPER:
+	case E1000_DEV_ID_82571EB_QUAD_FIBER:
+	case E1000_DEV_ID_82571EB_QUAD_COPPER_LP:
+		adapter->flags |= FLAG_IS_QUAD_PORT;
+		/* mark the first port */
+		if (global_quad_port_a == 0)
+			adapter->flags |= FLAG_IS_QUAD_PORT_A;
+		/* Reset for multiple quad port adapters */
+		global_quad_port_a++;
+		if (global_quad_port_a == 4)
+			global_quad_port_a = 0;
+		break;
+	default:
+		break;
+	}
+
+	switch (adapter->hw.mac.type) {
+	case e1000_82571:
+		/* these dual ports don't have WoL on port B at all */
+		if (((pdev->device == E1000_DEV_ID_82571EB_FIBER) ||
+		     (pdev->device == E1000_DEV_ID_82571EB_SERDES) ||
+		     (pdev->device == E1000_DEV_ID_82571EB_COPPER)) &&
+		    (is_port_b))
+			adapter->flags &= ~FLAG_HAS_WOL;
+		/* quad ports only support WoL on port A */
+		if (adapter->flags & FLAG_IS_QUAD_PORT &&
+		    (!adapter->flags & FLAG_IS_QUAD_PORT_A))
+			adapter->flags &= ~FLAG_HAS_WOL;
+		break;
+
+	case e1000_82573:
+		if (pdev->device == E1000_DEV_ID_82573L) {
+			e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1,
+				       &eeprom_data);
+			if (eeprom_data & NVM_WORD1A_ASPM_MASK)
+				adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES;
+		}
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_get_phy_id_82571 - Retrieve the PHY ID and revision
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the PHY registers and stores the PHY ID and possibly the PHY
+ *  revision in the hardware structure.
+ **/
+static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		/* The 82571 firmware may still be configuring the PHY.
+		 * In this case, we cannot access the PHY until the
+		 * configuration is done.  So we explicitly set the
+		 * PHY ID. */
+		phy->id = IGP01E1000_I_PHY_ID;
+		break;
+	case e1000_82573:
+		return e1000e_get_phy_id(hw);
+		break;
+	default:
+		return -E1000_ERR_PHY;
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_get_hw_semaphore_82571 - Acquire hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the HW semaphore to access the PHY or NVM
+ **/
+static s32 e1000_get_hw_semaphore_82571(struct e1000_hw *hw)
+{
+	u32 swsm;
+	s32 timeout = hw->nvm.word_size + 1;
+	s32 i = 0;
+
+	/* Get the FW semaphore. */
+	for (i = 0; i < timeout; i++) {
+		swsm = er32(SWSM);
+		ew32(SWSM, swsm | E1000_SWSM_SWESMBI);
+
+		/* Semaphore acquired if bit latched */
+		if (er32(SWSM) & E1000_SWSM_SWESMBI)
+			break;
+
+		udelay(50);
+	}
+
+	if (i == timeout) {
+		/* Release semaphores */
+		e1000e_put_hw_semaphore(hw);
+		hw_dbg(hw, "Driver can't access the NVM\n");
+		return -E1000_ERR_NVM;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_put_hw_semaphore_82571 - Release hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Release hardware semaphore used to access the PHY or NVM
+ **/
+static void e1000_put_hw_semaphore_82571(struct e1000_hw *hw)
+{
+	u32 swsm;
+
+	swsm = er32(SWSM);
+
+	swsm &= ~E1000_SWSM_SWESMBI;
+
+	ew32(SWSM, swsm);
+}
+
+/**
+ *  e1000_acquire_nvm_82571 - Request for access to the EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  To gain access to the EEPROM, first we must obtain a hardware semaphore.
+ *  Then for non-82573 hardware, set the EEPROM access request bit and wait
+ *  for EEPROM access grant bit.  If the access grant bit is not set, release
+ *  hardware semaphore.
+ **/
+static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw)
+{
+	s32 ret_val;
+
+	ret_val = e1000_get_hw_semaphore_82571(hw);
+	if (ret_val)
+		return ret_val;
+
+	if (hw->mac.type != e1000_82573)
+		ret_val = e1000e_acquire_nvm(hw);
+
+	if (ret_val)
+		e1000_put_hw_semaphore_82571(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_release_nvm_82571 - Release exclusive access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+static void e1000_release_nvm_82571(struct e1000_hw *hw)
+{
+	e1000e_release_nvm(hw);
+	e1000_put_hw_semaphore_82571(hw);
+}
+
+/**
+ *  e1000_write_nvm_82571 - Write to EEPROM using appropriate interface
+ *  @hw: pointer to the HW structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @words: number of words to write
+ *  @data: 16 bit word(s) to be written to the EEPROM
+ *
+ *  For non-82573 silicon, write data to EEPROM at offset using SPI interface.
+ *
+ *  If e1000e_update_nvm_checksum is not called after this function, the
+ *  EEPROM will most likley contain an invalid checksum.
+ **/
+static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words,
+				 u16 *data)
+{
+	s32 ret_val;
+
+	switch (hw->mac.type) {
+	case e1000_82573:
+		ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data);
+		break;
+	case e1000_82571:
+	case e1000_82572:
+		ret_val = e1000e_write_nvm_spi(hw, offset, words, data);
+		break;
+	default:
+		ret_val = -E1000_ERR_NVM;
+		break;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_update_nvm_checksum_82571 - Update EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  up to the checksum.  Then calculates the EEPROM checksum and writes the
+ *  value to the EEPROM.
+ **/
+static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw)
+{
+	u32 eecd;
+	s32 ret_val;
+	u16 i;
+
+	ret_val = e1000e_update_nvm_checksum_generic(hw);
+	if (ret_val)
+		return ret_val;
+
+	/* If our nvm is an EEPROM, then we're done
+	 * otherwise, commit the checksum to the flash NVM. */
+	if (hw->nvm.type != e1000_nvm_flash_hw)
+		return ret_val;
+
+	/* Check for pending operations. */
+	for (i = 0; i < E1000_FLASH_UPDATES; i++) {
+		msleep(1);
+		if ((er32(EECD) & E1000_EECD_FLUPD) == 0)
+			break;
+	}
+
+	if (i == E1000_FLASH_UPDATES)
+		return -E1000_ERR_NVM;
+
+	/* Reset the firmware if using STM opcode. */
+	if ((er32(FLOP) & 0xFF00) == E1000_STM_OPCODE) {
+		/* The enabling of and the actual reset must be done
+		 * in two write cycles.
+		 */
+		ew32(HICR, E1000_HICR_FW_RESET_ENABLE);
+		e1e_flush();
+		ew32(HICR, E1000_HICR_FW_RESET);
+	}
+
+	/* Commit the write to flash */
+	eecd = er32(EECD) | E1000_EECD_FLUPD;
+	ew32(EECD, eecd);
+
+	for (i = 0; i < E1000_FLASH_UPDATES; i++) {
+		msleep(1);
+		if ((er32(EECD) & E1000_EECD_FLUPD) == 0)
+			break;
+	}
+
+	if (i == E1000_FLASH_UPDATES)
+		return -E1000_ERR_NVM;
+
+	return 0;
+}
+
+/**
+ *  e1000_validate_nvm_checksum_82571 - Validate EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+static s32 e1000_validate_nvm_checksum_82571(struct e1000_hw *hw)
+{
+	if (hw->nvm.type == e1000_nvm_flash_hw)
+		e1000_fix_nvm_checksum_82571(hw);
+
+	return e1000e_validate_nvm_checksum_generic(hw);
+}
+
+/**
+ *  e1000_write_nvm_eewr_82571 - Write to EEPROM for 82573 silicon
+ *  @hw: pointer to the HW structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @words: number of words to write
+ *  @data: 16 bit word(s) to be written to the EEPROM
+ *
+ *  After checking for invalid values, poll the EEPROM to ensure the previous
+ *  command has completed before trying to write the next word.  After write
+ *  poll for completion.
+ *
+ *  If e1000e_update_nvm_checksum is not called after this function, the
+ *  EEPROM will most likley contain an invalid checksum.
+ **/
+static s32 e1000_write_nvm_eewr_82571(struct e1000_hw *hw, u16 offset,
+				      u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 i;
+	u32 eewr = 0;
+	s32 ret_val = 0;
+
+	/* A check for invalid values:  offset too large, too many words,
+	 * and not enough words. */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+		return -E1000_ERR_NVM;
+	}
+
+	for (i = 0; i < words; i++) {
+		eewr = (data[i] << E1000_NVM_RW_REG_DATA) |
+		       ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) |
+		       E1000_NVM_RW_REG_START;
+
+		ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
+		if (ret_val)
+			break;
+
+		ew32(EEWR, eewr);
+
+		ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_WRITE);
+		if (ret_val)
+			break;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_get_cfg_done_82571 - Poll for configuration done
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the management control register for the config done bit to be set.
+ **/
+static s32 e1000_get_cfg_done_82571(struct e1000_hw *hw)
+{
+	s32 timeout = PHY_CFG_TIMEOUT;
+
+	while (timeout) {
+		if (er32(EEMNGCTL) &
+		    E1000_NVM_CFG_DONE_PORT_0)
+			break;
+		msleep(1);
+		timeout--;
+	}
+	if (!timeout) {
+		hw_dbg(hw, "MNG configuration cycle has not completed.\n");
+		return -E1000_ERR_RESET;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_set_d0_lplu_state_82571 - Set Low Power Linkup D0 state
+ *  @hw: pointer to the HW structure
+ *  @active: TRUE to enable LPLU, FALSE to disable
+ *
+ *  Sets the LPLU D0 state according to the active flag.  When activating LPLU
+ *  this function also disables smart speed and vice versa.  LPLU will not be
+ *  activated unless the device autonegotiation advertisement meets standards
+ *  of either 10 or 10/100 or 10/100/1000 at all duplexes.  This is a function
+ *  pointer entry point only called by PHY setup routines.
+ **/
+static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+	if (ret_val)
+		return ret_val;
+
+	if (active) {
+		data |= IGP02E1000_PM_D0_LPLU;
+		ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data);
+		if (ret_val)
+			return ret_val;
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
+		if (ret_val)
+			return ret_val;
+	} else {
+		data &= ~IGP02E1000_PM_D0_LPLU;
+		ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data);
+		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained. */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+						     &data);
+			if (ret_val)
+				return ret_val;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+						     data);
+			if (ret_val)
+				return ret_val;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+						     &data);
+			if (ret_val)
+				return ret_val;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+						     data);
+			if (ret_val)
+				return ret_val;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_reset_hw_82571 - Reset hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This resets the hardware into a known state.  This is a
+ *  function pointer entry point called by the api module.
+ **/
+static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	u32 extcnf_ctrl;
+	u32 ctrl_ext;
+	u32 icr;
+	s32 ret_val;
+	u16 i = 0;
+
+	/* Prevent the PCI-E bus from sticking if there is no TLP connection
+	 * on the last TLP read/write transaction when MAC is reset.
+	 */
+	ret_val = e1000e_disable_pcie_master(hw);
+	if (ret_val)
+		hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+
+	hw_dbg(hw, "Masking off all interrupts\n");
+	ew32(IMC, 0xffffffff);
+
+	ew32(RCTL, 0);
+	ew32(TCTL, E1000_TCTL_PSP);
+	e1e_flush();
+
+	msleep(10);
+
+	/* Must acquire the MDIO ownership before MAC reset.
+	 * Ownership defaults to firmware after a reset. */
+	if (hw->mac.type == e1000_82573) {
+		extcnf_ctrl = er32(EXTCNF_CTRL);
+		extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+		do {
+			ew32(EXTCNF_CTRL, extcnf_ctrl);
+			extcnf_ctrl = er32(EXTCNF_CTRL);
+
+			if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
+				break;
+
+			extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
+
+			msleep(2);
+			i++;
+		} while (i < MDIO_OWNERSHIP_TIMEOUT);
+	}
+
+	ctrl = er32(CTRL);
+
+	hw_dbg(hw, "Issuing a global reset to MAC\n");
+	ew32(CTRL, ctrl | E1000_CTRL_RST);
+
+	if (hw->nvm.type == e1000_nvm_flash_hw) {
+		udelay(10);
+		ctrl_ext = er32(CTRL_EXT);
+		ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+		ew32(CTRL_EXT, ctrl_ext);
+		e1e_flush();
+	}
+
+	ret_val = e1000e_get_auto_rd_done(hw);
+	if (ret_val)
+		/* We don't want to continue accessing MAC registers. */
+		return ret_val;
+
+	/* Phy configuration from NVM just starts after EECD_AUTO_RD is set.
+	 * Need to wait for Phy configuration completion before accessing
+	 * NVM and Phy.
+	 */
+	if (hw->mac.type == e1000_82573)
+		msleep(25);
+
+	/* Clear any pending interrupt events. */
+	ew32(IMC, 0xffffffff);
+	icr = er32(ICR);
+
+	return 0;
+}
+
+/**
+ *  e1000_init_hw_82571 - Initialize hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  This inits the hardware readying it for operation.
+ **/
+static s32 e1000_init_hw_82571(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 reg_data;
+	s32 ret_val;
+	u16 i;
+	u16 rar_count = mac->rar_entry_count;
+
+	e1000_initialize_hw_bits_82571(hw);
+
+	/* Initialize identification LED */
+	ret_val = e1000e_id_led_init(hw);
+	if (ret_val) {
+		hw_dbg(hw, "Error initializing identification LED\n");
+		return ret_val;
+	}
+
+	/* Disabling VLAN filtering */
+	hw_dbg(hw, "Initializing the IEEE VLAN\n");
+	e1000e_clear_vfta(hw);
+
+	/* Setup the receive address. */
+	/* If, however, a locally administered address was assigned to the
+	 * 82571, we must reserve a RAR for it to work around an issue where
+	 * resetting one port will reload the MAC on the other port.
+	 */
+	if (e1000e_get_laa_state_82571(hw))
+		rar_count--;
+	e1000e_init_rx_addrs(hw, rar_count);
+
+	/* Zero out the Multicast HASH table */
+	hw_dbg(hw, "Zeroing the MTA\n");
+	for (i = 0; i < mac->mta_reg_count; i++)
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+	/* Setup link and flow control */
+	ret_val = e1000_setup_link_82571(hw);
+
+	/* Set the transmit descriptor write-back policy */
+	reg_data = er32(TXDCTL);
+	reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+		   E1000_TXDCTL_FULL_TX_DESC_WB |
+		   E1000_TXDCTL_COUNT_DESC;
+	ew32(TXDCTL, reg_data);
+
+	/* ...for both queues. */
+	if (mac->type != e1000_82573) {
+		reg_data = er32(TXDCTL1);
+		reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+			   E1000_TXDCTL_FULL_TX_DESC_WB |
+			   E1000_TXDCTL_COUNT_DESC;
+		ew32(TXDCTL1, reg_data);
+	} else {
+		e1000e_enable_tx_pkt_filtering(hw);
+		reg_data = er32(GCR);
+		reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
+		ew32(GCR, reg_data);
+	}
+
+	/* Clear all of the statistics registers (clear on read).  It is
+	 * important that we do this after we have tried to establish link
+	 * because the symbol error count will increment wildly if there
+	 * is no link.
+	 */
+	e1000_clear_hw_cntrs_82571(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_initialize_hw_bits_82571 - Initialize hardware-dependent bits
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes required hardware-dependent bits needed for normal operation.
+ **/
+static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
+{
+	u32 reg;
+
+	/* Transmit Descriptor Control 0 */
+	reg = er32(TXDCTL);
+	reg |= (1 << 22);
+	ew32(TXDCTL, reg);
+
+	/* Transmit Descriptor Control 1 */
+	reg = er32(TXDCTL1);
+	reg |= (1 << 22);
+	ew32(TXDCTL1, reg);
+
+	/* Transmit Arbitration Control 0 */
+	reg = er32(TARC0);
+	reg &= ~(0xF << 27); /* 30:27 */
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		reg |= (1 << 23) | (1 << 24) | (1 << 25) | (1 << 26);
+		break;
+	default:
+		break;
+	}
+	ew32(TARC0, reg);
+
+	/* Transmit Arbitration Control 1 */
+	reg = er32(TARC1);
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		reg &= ~((1 << 29) | (1 << 30));
+		reg |= (1 << 22) | (1 << 24) | (1 << 25) | (1 << 26);
+		if (er32(TCTL) & E1000_TCTL_MULR)
+			reg &= ~(1 << 28);
+		else
+			reg |= (1 << 28);
+		ew32(TARC1, reg);
+		break;
+	default:
+		break;
+	}
+
+	/* Device Control */
+	if (hw->mac.type == e1000_82573) {
+		reg = er32(CTRL);
+		reg &= ~(1 << 29);
+		ew32(CTRL, reg);
+	}
+
+	/* Extended Device Control */
+	if (hw->mac.type == e1000_82573) {
+		reg = er32(CTRL_EXT);
+		reg &= ~(1 << 23);
+		reg |= (1 << 22);
+		ew32(CTRL_EXT, reg);
+	}
+}
+
+/**
+ *  e1000e_clear_vfta - Clear VLAN filter table
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the register array which contains the VLAN filter table by
+ *  setting all the values to 0.
+ **/
+void e1000e_clear_vfta(struct e1000_hw *hw)
+{
+	u32 offset;
+	u32 vfta_value = 0;
+	u32 vfta_offset = 0;
+	u32 vfta_bit_in_reg = 0;
+
+	if (hw->mac.type == e1000_82573) {
+		if (hw->mng_cookie.vlan_id != 0) {
+			/* The VFTA is a 4096b bit-field, each identifying
+			 * a single VLAN ID.  The following operations
+			 * determine which 32b entry (i.e. offset) into the
+			 * array we want to set the VLAN ID (i.e. bit) of
+			 * the manageability unit.
+			 */
+			vfta_offset = (hw->mng_cookie.vlan_id >>
+				       E1000_VFTA_ENTRY_SHIFT) &
+				      E1000_VFTA_ENTRY_MASK;
+			vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id &
+					       E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
+		}
+	}
+	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
+		/* If the offset we want to clear is the same offset of the
+		 * manageability VLAN ID, then clear all bits except that of
+		 * the manageability unit.
+		 */
+		vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0;
+		E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, vfta_value);
+		e1e_flush();
+	}
+}
+
+/**
+ *  e1000_mc_addr_list_update_82571 - Update Multicast addresses
+ *  @hw: pointer to the HW structure
+ *  @mc_addr_list: array of multicast addresses to program
+ *  @mc_addr_count: number of multicast addresses to program
+ *  @rar_used_count: the first RAR register free to program
+ *  @rar_count: total number of supported Receive Address Registers
+ *
+ *  Updates the Receive Address Registers and Multicast Table Array.
+ *  The caller must have a packed mc_addr_list of multicast addresses.
+ *  The parameter rar_count will usually be hw->mac.rar_entry_count
+ *  unless there are workarounds that change this.
+ **/
+static void e1000_mc_addr_list_update_82571(struct e1000_hw *hw,
+					    u8 *mc_addr_list,
+					    u32 mc_addr_count,
+					    u32 rar_used_count,
+					    u32 rar_count)
+{
+	if (e1000e_get_laa_state_82571(hw))
+		rar_count--;
+
+	e1000e_mc_addr_list_update_generic(hw, mc_addr_list, mc_addr_count,
+					  rar_used_count, rar_count);
+}
+
+/**
+ *  e1000_setup_link_82571 - Setup flow control and link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines which flow control settings to use, then configures flow
+ *  control.  Calls the appropriate media-specific link configuration
+ *  function.  Assuming the adapter has a valid link partner, a valid link
+ *  should be established.  Assumes the hardware has previously been reset
+ *  and the transmitter and receiver are not enabled.
+ **/
+static s32 e1000_setup_link_82571(struct e1000_hw *hw)
+{
+	/* 82573 does not have a word in the NVM to determine
+	 * the default flow control setting, so we explicitly
+	 * set it to full.
+	 */
+	if (hw->mac.type == e1000_82573)
+		hw->mac.fc = e1000_fc_full;
+
+	return e1000e_setup_link(hw);
+}
+
+/**
+ *  e1000_setup_copper_link_82571 - Configure copper link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the link for auto-neg or forced speed and duplex.  Then we check
+ *  for link, once link is established calls to configure collision distance
+ *  and flow control are called.
+ **/
+static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	u32 led_ctrl;
+	s32 ret_val;
+
+	ctrl = er32(CTRL);
+	ctrl |= E1000_CTRL_SLU;
+	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	ew32(CTRL, ctrl);
+
+	switch (hw->phy.type) {
+	case e1000_phy_m88:
+		ret_val = e1000e_copper_link_setup_m88(hw);
+		break;
+	case e1000_phy_igp_2:
+		ret_val = e1000e_copper_link_setup_igp(hw);
+		/* Setup activity LED */
+		led_ctrl = er32(LEDCTL);
+		led_ctrl &= IGP_ACTIVITY_LED_MASK;
+		led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
+		ew32(LEDCTL, led_ctrl);
+		break;
+	default:
+		return -E1000_ERR_PHY;
+		break;
+	}
+
+	if (ret_val)
+		return ret_val;
+
+	ret_val = e1000e_setup_copper_link(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_setup_fiber_serdes_link_82571 - Setup link for fiber/serdes
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures collision distance and flow control for fiber and serdes links.
+ *  Upon successful setup, poll for link.
+ **/
+static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw)
+{
+	switch (hw->mac.type) {
+	case e1000_82571:
+	case e1000_82572:
+		/* If SerDes loopback mode is entered, there is no form
+		 * of reset to take the adapter out of that mode.  So we
+		 * have to explicitly take the adapter out of loopback
+		 * mode.  This prevents drivers from twidling their thumbs
+		 * if another tool failed to take it out of loopback mode.
+		 */
+		ew32(SCTL,
+				E1000_SCTL_DISABLE_SERDES_LOOPBACK);
+		break;
+	default:
+		break;
+	}
+
+	return e1000e_setup_fiber_serdes_link(hw);
+}
+
+/**
+ *  e1000_valid_led_default_82571 - Verify a valid default LED config
+ *  @hw: pointer to the HW structure
+ *  @data: pointer to the NVM (EEPROM)
+ *
+ *  Read the EEPROM for the current default LED configuration.  If the
+ *  LED configuration is not valid, set to a valid LED configuration.
+ **/
+static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data)
+{
+	s32 ret_val;
+
+	ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
+	if (ret_val) {
+		hw_dbg(hw, "NVM Read Error\n");
+		return ret_val;
+	}
+
+	if (hw->mac.type == e1000_82573 &&
+	    *data == ID_LED_RESERVED_F746)
+		*data = ID_LED_DEFAULT_82573;
+	else if (*data == ID_LED_RESERVED_0000 ||
+		 *data == ID_LED_RESERVED_FFFF)
+		*data = ID_LED_DEFAULT;
+
+	return 0;
+}
+
+/**
+ *  e1000e_get_laa_state_82571 - Get locally administered address state
+ *  @hw: pointer to the HW structure
+ *
+ *  Retrieve and return the current locally administed address state.
+ **/
+bool e1000e_get_laa_state_82571(struct e1000_hw *hw)
+{
+	if (hw->mac.type != e1000_82571)
+		return 0;
+
+	return hw->dev_spec.e82571.laa_is_present;
+}
+
+/**
+ *  e1000e_set_laa_state_82571 - Set locally administered address state
+ *  @hw: pointer to the HW structure
+ *  @state: enable/disable locally administered address
+ *
+ *  Enable/Disable the current locally administed address state.
+ **/
+void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state)
+{
+	if (hw->mac.type != e1000_82571)
+		return;
+
+	hw->dev_spec.e82571.laa_is_present = state;
+
+	/* If workaround is activated... */
+	if (state)
+		/* Hold a copy of the LAA in RAR[14] This is done so that
+		 * between the time RAR[0] gets clobbered and the time it
+		 * gets fixed, the actual LAA is in one of the RARs and no
+		 * incoming packets directed to this port are dropped.
+		 * Eventually the LAA will be in RAR[0] and RAR[14].
+		 */
+		e1000e_rar_set(hw, hw->mac.addr, hw->mac.rar_entry_count - 1);
+}
+
+/**
+ *  e1000_fix_nvm_checksum_82571 - Fix EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Verifies that the EEPROM has completed the update.  After updating the
+ *  EEPROM, we need to check bit 15 in work 0x23 for the checksum fix.  If
+ *  the checksum fix is not implemented, we need to set the bit and update
+ *  the checksum.  Otherwise, if bit 15 is set and the checksum is incorrect,
+ *  we need to return bad checksum.
+ **/
+static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	s32 ret_val;
+	u16 data;
+
+	if (nvm->type != e1000_nvm_flash_hw)
+		return 0;
+
+	/* Check bit 4 of word 10h.  If it is 0, firmware is done updating
+	 * 10h-12h.  Checksum may need to be fixed.
+	 */
+	ret_val = e1000_read_nvm(hw, 0x10, 1, &data);
+	if (ret_val)
+		return ret_val;
+
+	if (!(data & 0x10)) {
+		/* Read 0x23 and check bit 15.  This bit is a 1
+		 * when the checksum has already been fixed.  If
+		 * the checksum is still wrong and this bit is a
+		 * 1, we need to return bad checksum.  Otherwise,
+		 * we need to set this bit to a 1 and update the
+		 * checksum.
+		 */
+		ret_val = e1000_read_nvm(hw, 0x23, 1, &data);
+		if (ret_val)
+			return ret_val;
+
+		if (!(data & 0x8000)) {
+			data |= 0x8000;
+			ret_val = e1000_write_nvm(hw, 0x23, 1, &data);
+			if (ret_val)
+				return ret_val;
+			ret_val = e1000e_update_nvm_checksum(hw);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_clear_hw_cntrs_82571 - Clear device specific hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the hardware counters by reading the counter registers.
+ **/
+static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw)
+{
+	u32 temp;
+
+	e1000e_clear_hw_cntrs_base(hw);
+
+	temp = er32(PRC64);
+	temp = er32(PRC127);
+	temp = er32(PRC255);
+	temp = er32(PRC511);
+	temp = er32(PRC1023);
+	temp = er32(PRC1522);
+	temp = er32(PTC64);
+	temp = er32(PTC127);
+	temp = er32(PTC255);
+	temp = er32(PTC511);
+	temp = er32(PTC1023);
+	temp = er32(PTC1522);
+
+	temp = er32(ALGNERRC);
+	temp = er32(RXERRC);
+	temp = er32(TNCRS);
+	temp = er32(CEXTERR);
+	temp = er32(TSCTC);
+	temp = er32(TSCTFC);
+
+	temp = er32(MGTPRC);
+	temp = er32(MGTPDC);
+	temp = er32(MGTPTC);
+
+	temp = er32(IAC);
+	temp = er32(ICRXOC);
+
+	temp = er32(ICRXPTC);
+	temp = er32(ICRXATC);
+	temp = er32(ICTXPTC);
+	temp = er32(ICTXATC);
+	temp = er32(ICTXQEC);
+	temp = er32(ICTXQMTC);
+	temp = er32(ICRXDMTC);
+}
+
+static struct e1000_mac_operations e82571_mac_ops = {
+	.mng_mode_enab		= E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
+	/* .check_for_link: media type dependent */
+	.cleanup_led		= e1000e_cleanup_led_generic,
+	.clear_hw_cntrs		= e1000_clear_hw_cntrs_82571,
+	.get_bus_info		= e1000e_get_bus_info_pcie,
+	/* .get_link_up_info: media type dependent */
+	.led_on			= e1000e_led_on_generic,
+	.led_off		= e1000e_led_off_generic,
+	.mc_addr_list_update	= e1000_mc_addr_list_update_82571,
+	.reset_hw		= e1000_reset_hw_82571,
+	.init_hw		= e1000_init_hw_82571,
+	.setup_link		= e1000_setup_link_82571,
+	/* .setup_physical_interface: media type dependent */
+};
+
+static struct e1000_phy_operations e82_phy_ops_igp = {
+	.acquire_phy		= e1000_get_hw_semaphore_82571,
+	.check_reset_block	= e1000e_check_reset_block_generic,
+	.commit_phy		= NULL,
+	.force_speed_duplex	= e1000e_phy_force_speed_duplex_igp,
+	.get_cfg_done		= e1000_get_cfg_done_82571,
+	.get_cable_length	= e1000e_get_cable_length_igp_2,
+	.get_phy_info		= e1000e_get_phy_info_igp,
+	.read_phy_reg		= e1000e_read_phy_reg_igp,
+	.release_phy		= e1000_put_hw_semaphore_82571,
+	.reset_phy		= e1000e_phy_hw_reset_generic,
+	.set_d0_lplu_state	= e1000_set_d0_lplu_state_82571,
+	.set_d3_lplu_state	= e1000e_set_d3_lplu_state,
+	.write_phy_reg		= e1000e_write_phy_reg_igp,
+};
+
+static struct e1000_phy_operations e82_phy_ops_m88 = {
+	.acquire_phy		= e1000_get_hw_semaphore_82571,
+	.check_reset_block	= e1000e_check_reset_block_generic,
+	.commit_phy		= e1000e_phy_sw_reset,
+	.force_speed_duplex	= e1000e_phy_force_speed_duplex_m88,
+	.get_cfg_done		= e1000e_get_cfg_done,
+	.get_cable_length	= e1000e_get_cable_length_m88,
+	.get_phy_info		= e1000e_get_phy_info_m88,
+	.read_phy_reg		= e1000e_read_phy_reg_m88,
+	.release_phy		= e1000_put_hw_semaphore_82571,
+	.reset_phy		= e1000e_phy_hw_reset_generic,
+	.set_d0_lplu_state	= e1000_set_d0_lplu_state_82571,
+	.set_d3_lplu_state	= e1000e_set_d3_lplu_state,
+	.write_phy_reg		= e1000e_write_phy_reg_m88,
+};
+
+static struct e1000_nvm_operations e82571_nvm_ops = {
+	.acquire_nvm		= e1000_acquire_nvm_82571,
+	.read_nvm		= e1000e_read_nvm_spi,
+	.release_nvm		= e1000_release_nvm_82571,
+	.update_nvm		= e1000_update_nvm_checksum_82571,
+	.valid_led_default	= e1000_valid_led_default_82571,
+	.validate_nvm		= e1000_validate_nvm_checksum_82571,
+	.write_nvm		= e1000_write_nvm_82571,
+};
+
+static struct e1000_nvm_operations e82573_nvm_ops = {
+	.acquire_nvm		= e1000_acquire_nvm_82571,
+	.read_nvm		= e1000e_read_nvm_eerd,
+	.release_nvm		= e1000_release_nvm_82571,
+	.update_nvm		= e1000_update_nvm_checksum_82571,
+	.valid_led_default	= e1000_valid_led_default_82571,
+	.validate_nvm		= e1000_validate_nvm_checksum_82571,
+	.write_nvm		= e1000_write_nvm_82571,
+};
+
+struct e1000_info e1000_82571_info = {
+	.mac			= e1000_82571,
+	.flags			= FLAG_HAS_HW_VLAN_FILTER
+				  | FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_HAS_STATS_PTC_PRC
+				  | FLAG_HAS_WOL
+				  | FLAG_APME_IN_CTRL3
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_HAS_STATS_ICR_ICT
+				  | FLAG_HAS_SMART_POWER_DOWN
+				  | FLAG_RESET_OVERWRITES_LAA /* errata */
+				  | FLAG_TARC_SPEED_MODE_BIT /* errata */
+				  | FLAG_APME_CHECK_PORT_B,
+	.pba			= 38,
+	.get_invariants		= e1000_get_invariants_82571,
+	.mac_ops		= &e82571_mac_ops,
+	.phy_ops		= &e82_phy_ops_igp,
+	.nvm_ops		= &e82571_nvm_ops,
+};
+
+struct e1000_info e1000_82572_info = {
+	.mac			= e1000_82572,
+	.flags			= FLAG_HAS_HW_VLAN_FILTER
+				  | FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_HAS_STATS_PTC_PRC
+				  | FLAG_HAS_WOL
+				  | FLAG_APME_IN_CTRL3
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_HAS_STATS_ICR_ICT
+				  | FLAG_TARC_SPEED_MODE_BIT, /* errata */
+	.pba			= 38,
+	.get_invariants		= e1000_get_invariants_82571,
+	.mac_ops		= &e82571_mac_ops,
+	.phy_ops		= &e82_phy_ops_igp,
+	.nvm_ops		= &e82571_nvm_ops,
+};
+
+struct e1000_info e1000_82573_info = {
+	.mac			= e1000_82573,
+	.flags			= FLAG_HAS_HW_VLAN_FILTER
+				  | FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_HAS_STATS_PTC_PRC
+				  | FLAG_HAS_WOL
+				  | FLAG_APME_IN_CTRL3
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_STATS_ICR_ICT
+				  | FLAG_HAS_SMART_POWER_DOWN
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_ASPM
+				  | FLAG_HAS_ERT
+				  | FLAG_HAS_SWSM_ON_LOAD,
+	.pba			= 20,
+	.get_invariants		= e1000_get_invariants_82571,
+	.mac_ops		= &e82571_mac_ops,
+	.phy_ops		= &e82_phy_ops_m88,
+	.nvm_ops		= &e82573_nvm_ops,
+};
+
diff --git a/drivers/net/e1000e/Makefile b/drivers/net/e1000e/Makefile
new file mode 100644
index 0000000..650f866
--- /dev/null
+++ b/drivers/net/e1000e/Makefile
@@ -0,0 +1,37 @@
+################################################################################
+#
+# Intel PRO/1000 Linux driver
+# Copyright(c) 1999 - 2007 Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope 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.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Contact Information:
+# Linux NICS <linux.nics@intel.com>
+# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+#
+################################################################################
+
+#
+# Makefile for the Intel(R) PRO/1000 ethernet driver
+#
+
+obj-$(CONFIG_E1000E) += e1000e.o
+
+e1000e-objs := 82571.o ich8lan.o es2lan.o \
+	       lib.o phy.o param.o ethtool.o netdev.o
+
diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h
new file mode 100644
index 0000000..b32ed45
--- /dev/null
+++ b/drivers/net/e1000e/defines.h
@@ -0,0 +1,739 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_DEFINES_H_
+#define _E1000_DEFINES_H_
+
+#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE  8
+#define REQ_RX_DESCRIPTOR_MULTIPLE  8
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_APME       0x00000001 /* APM Enable */
+#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
+#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_RO_DIS    0x00020000 /* Relaxed Ordering disable */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES  0x00C00000
+#define E1000_CTRL_EXT_DRV_LOAD       0x10000000 /* Driver loaded bit for FW */
+#define E1000_CTRL_EXT_IAME           0x08000000 /* Interrupt acknowledge Auto-mask */
+#define E1000_CTRL_EXT_INT_TIMER_CLR  0x20000000 /* Clear Interrupt timers after IMS clear */
+
+/* Receive Decriptor bit definitions */
+#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
+#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
+#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
+#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_UDPCS    0x10    /* UDP xsum caculated */
+#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
+#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
+#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
+#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
+#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
+
+#define E1000_RXDEXT_STATERR_CE    0x01000000
+#define E1000_RXDEXT_STATERR_SE    0x02000000
+#define E1000_RXDEXT_STATERR_SEQ   0x04000000
+#define E1000_RXDEXT_STATERR_CXE   0x10000000
+#define E1000_RXDEXT_STATERR_RXE   0x80000000
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+    E1000_RXD_ERR_CE  |                \
+    E1000_RXD_ERR_SE  |                \
+    E1000_RXD_ERR_SEQ |                \
+    E1000_RXD_ERR_CXE |                \
+    E1000_RXD_ERR_RXE)
+
+/* Same mask, but for extended and packet split descriptors */
+#define E1000_RXDEXT_ERR_FRAME_ERR_MASK ( \
+    E1000_RXDEXT_STATERR_CE  |            \
+    E1000_RXDEXT_STATERR_SE  |            \
+    E1000_RXDEXT_STATERR_SEQ |            \
+    E1000_RXDEXT_STATERR_CXE |            \
+    E1000_RXDEXT_STATERR_RXE)
+
+#define E1000_RXDPS_HDRSTAT_HDRSP              0x00008000
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
+#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_BLK_PHY_RST_ON_IDE   0x00040000 /* Block phy resets */
+#define E1000_MANC_EN_MAC_ADDR_FILTER   0x00100000 /* Enable MAC address
+						    * filtering */
+#define E1000_MANC_EN_MNG2HOST   0x00200000 /* Enable MNG packets to host
+					     * memory */
+
+/* Receive Control */
+#define E1000_RCTL_EN             0x00000002    /* enable */
+#define E1000_RCTL_SBP            0x00000004    /* store bad packet */
+#define E1000_RCTL_UPE            0x00000008    /* unicast promiscuous enable */
+#define E1000_RCTL_MPE            0x00000010    /* multicast promiscuous enab */
+#define E1000_RCTL_LPE            0x00000020    /* long packet enable */
+#define E1000_RCTL_LBM_NO         0x00000000    /* no loopback mode */
+#define E1000_RCTL_LBM_MAC        0x00000040    /* MAC loopback mode */
+#define E1000_RCTL_LBM_TCVR       0x000000C0    /* tcvr loopback mode */
+#define E1000_RCTL_DTYP_PS        0x00000400    /* Packet Split descriptor */
+#define E1000_RCTL_RDMTS_HALF     0x00000000    /* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT       12            /* multicast offset shift */
+#define E1000_RCTL_BAM            0x00008000    /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048        0x00000000    /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024        0x00010000    /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512         0x00020000    /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256         0x00030000    /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384       0x00010000    /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192        0x00020000    /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096        0x00030000    /* rx buffer size 4096 */
+#define E1000_RCTL_VFE            0x00040000    /* vlan filter enable */
+#define E1000_RCTL_CFIEN          0x00080000    /* canonical form enable */
+#define E1000_RCTL_CFI            0x00100000    /* canonical form indicator */
+#define E1000_RCTL_BSEX           0x02000000    /* Buffer size extension */
+#define E1000_RCTL_SECRC          0x04000000    /* Strip Ethernet CRC */
+
+/* Use byte values for the following shift parameters
+ * Usage:
+ *     psrctl |= (((ROUNDUP(value0, 128) >> E1000_PSRCTL_BSIZE0_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE0_MASK) |
+ *                ((ROUNDUP(value1, 1024) >> E1000_PSRCTL_BSIZE1_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE1_MASK) |
+ *                ((ROUNDUP(value2, 1024) << E1000_PSRCTL_BSIZE2_SHIFT) &
+ *                  E1000_PSRCTL_BSIZE2_MASK) |
+ *                ((ROUNDUP(value3, 1024) << E1000_PSRCTL_BSIZE3_SHIFT) |;
+ *                  E1000_PSRCTL_BSIZE3_MASK))
+ * where value0 = [128..16256],  default=256
+ *       value1 = [1024..64512], default=4096
+ *       value2 = [0..64512],    default=4096
+ *       value3 = [0..64512],    default=0
+ */
+
+#define E1000_PSRCTL_BSIZE0_MASK   0x0000007F
+#define E1000_PSRCTL_BSIZE1_MASK   0x00003F00
+#define E1000_PSRCTL_BSIZE2_MASK   0x003F0000
+#define E1000_PSRCTL_BSIZE3_MASK   0x3F000000
+
+#define E1000_PSRCTL_BSIZE0_SHIFT  7            /* Shift _right_ 7 */
+#define E1000_PSRCTL_BSIZE1_SHIFT  2            /* Shift _right_ 2 */
+#define E1000_PSRCTL_BSIZE2_SHIFT  6            /* Shift _left_ 6 */
+#define E1000_PSRCTL_BSIZE3_SHIFT 14            /* Shift _left_ 14 */
+
+/* SWFW_SYNC Definitions */
+#define E1000_SWFW_EEP_SM   0x1
+#define E1000_SWFW_PHY0_SM  0x2
+#define E1000_SWFW_PHY1_SM  0x4
+
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_GIO_MASTER_DISABLE 0x00000004 /*Blocks new Master requests */
+#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
+#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
+#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+
+/* Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
+#define E1000_STATUS_FUNC_SHIFT 2
+#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
+#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
+#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+#define E1000_STATUS_LAN_INIT_DONE 0x00000200   /* Lan Init Completion by NVM */
+#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
+
+/* Constants used to intrepret the masked PCI-X bus speed. */
+
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+
+#define ADVERTISE_10_HALF                 0x0001
+#define ADVERTISE_10_FULL                 0x0002
+#define ADVERTISE_100_HALF                0x0004
+#define ADVERTISE_100_FULL                0x0008
+#define ADVERTISE_1000_HALF               0x0010 /* Not used, just FYI */
+#define ADVERTISE_1000_FULL               0x0020
+
+/* 1000/H is not supported, nor spec-compliant. */
+#define E1000_ALL_SPEED_DUPLEX ( ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
+				ADVERTISE_100_HALF |  ADVERTISE_100_FULL | \
+						     ADVERTISE_1000_FULL)
+#define E1000_ALL_NOT_GIG      ( ADVERTISE_10_HALF |   ADVERTISE_10_FULL | \
+				ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
+#define E1000_ALL_100_SPEED    (ADVERTISE_100_HALF |  ADVERTISE_100_FULL)
+#define E1000_ALL_10_SPEED      (ADVERTISE_10_HALF |   ADVERTISE_10_FULL)
+#define E1000_ALL_HALF_DUPLEX   (ADVERTISE_10_HALF |  ADVERTISE_100_HALF)
+
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT   E1000_ALL_SPEED_DUPLEX
+
+/* LED Control */
+#define E1000_LEDCTL_LED0_MODE_MASK       0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT      0
+#define E1000_LEDCTL_LED0_IVRT            0x00000040
+#define E1000_LEDCTL_LED0_BLINK           0x00000080
+
+#define E1000_LEDCTL_MODE_LED_ON        0xE
+#define E1000_LEDCTL_MODE_LED_OFF       0xF
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
+#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
+
+/* Transmit Control */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+#define E1000_TCTL_MULR   0x10000000    /* Multiple request support */
+
+/* Transmit Arbitration Count */
+
+/* SerDes Control */
+#define E1000_SCTL_DISABLE_SERDES_LOOPBACK 0x0400
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPPCSE    0x00001000   /* IP payload checksum enable */
+
+/* Header split receive */
+#define E1000_RFCTL_EXTEN               0x00008000
+#define E1000_RFCTL_IPV6_EX_DIS         0x00010000
+#define E1000_RFCTL_NEW_IPV6_EXT_DIS    0x00020000
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD       15
+#define E1000_CT_SHIFT                  4
+#define E1000_COLLISION_DISTANCE        63
+#define E1000_COLD_SHIFT                12
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_82543_TIPG_IPGT_COPPER 8
+
+#define E1000_TIPG_IPGT_MASK  0x000003FF
+
+#define DEFAULT_82543_TIPG_IPGR1 8
+#define E1000_TIPG_IPGR1_SHIFT  10
+
+#define DEFAULT_82543_TIPG_IPGR2 6
+#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7
+#define E1000_TIPG_IPGR2_SHIFT  20
+
+#define MAX_JUMBO_FRAME_SIZE    0x3F00
+
+/* Extended Configuration Control and Size */
+#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP      0x00000020
+#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE       0x00000001
+#define E1000_EXTCNF_CTRL_SWFLAG                 0x00000020
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK   0x00FF0000
+#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT          16
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK   0x0FFF0000
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT          16
+
+#define E1000_PHY_CTRL_D0A_LPLU           0x00000002
+#define E1000_PHY_CTRL_NOND0A_LPLU        0x00000004
+#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
+#define E1000_PHY_CTRL_GBE_DISABLE        0x00000040
+
+#define E1000_KABGTXD_BGSQLBIAS           0x00050000
+
+/* PBA constants */
+#define E1000_PBA_8K  0x0008    /* 8KB, default Rx allocation */
+#define E1000_PBA_16K 0x0010    /* 16KB, default TX allocation */
+
+#define E1000_PBS_16K E1000_PBA_16K
+
+#define IFS_MAX       80
+#define IFS_MIN       40
+#define IFS_RATIO     4
+#define IFS_STEP      10
+#define MIN_NUM_XMITS 1000
+
+/* SW Semaphore Register */
+#define E1000_SWSM_SMBI         0x00000001 /* Driver Semaphore bit */
+#define E1000_SWSM_SWESMBI      0x00000002 /* FW Semaphore bit */
+#define E1000_SWSM_DRV_LOAD     0x00000008 /* Driver Loaded Bit */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW          0x00000001 /* Transmit desc written back */
+#define E1000_ICR_LSC           0x00000004 /* Link Status Change */
+#define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
+#define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
+#define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_INT_ASSERTED  0x80000000 /* If this bit asserted, the driver should claim the interrupt */
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXT0   = Receiver Timer Interrupt (ring 0)
+ *   o TXDW   = Transmit Descriptor Written Back
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ *   o LSC    = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+    E1000_IMS_RXT0   |    \
+    E1000_IMS_TXDW   |    \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ  |    \
+    E1000_IMS_LSC)
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
+#define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
+#define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+#define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
+
+/* Interrupt Cause Set */
+#define E1000_ICS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_ICS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
+
+/* Transmit Descriptor Control */
+#define E1000_TXDCTL_PTHRESH 0x0000003F /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_WTHRESH 0x003F0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+#define E1000_TXDCTL_MAX_TX_DESC_PREFETCH 0x0100001F /* GRAN=1, PTHRESH=31 */
+#define E1000_TXDCTL_COUNT_DESC 0x00400000 /* Enable the counting of desc.
+					      still to be processed. */
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE         0x8808
+
+/* 802.1q VLAN Packet Size */
+#define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
+
+/* Receive Address */
+/* Number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor.
+ * Technically, we have 16 spots.  However, we reserve one of these spots
+ * (RAR[15]) for our directed address used by controllers with
+ * manageability enabled, allowing us room for 15 multicast addresses.
+ */
+#define E1000_RAR_ENTRIES     15
+#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
+
+/* Error Codes */
+#define E1000_ERR_NVM      1
+#define E1000_ERR_PHY      2
+#define E1000_ERR_CONFIG   3
+#define E1000_ERR_PARAM    4
+#define E1000_ERR_MAC_INIT 5
+#define E1000_ERR_PHY_TYPE 6
+#define E1000_ERR_RESET   9
+#define E1000_ERR_MASTER_REQUESTS_PENDING 10
+#define E1000_ERR_HOST_INTERFACE_COMMAND 11
+#define E1000_BLK_PHY_RESET   12
+#define E1000_ERR_SWFW_SYNC 13
+#define E1000_NOT_IMPLEMENTED 14
+
+/* Loop limit on how long we wait for auto-negotiation to complete */
+#define FIBER_LINK_UP_LIMIT               50
+#define COPPER_LINK_UP_LIMIT              10
+#define PHY_AUTO_NEG_LIMIT                45
+#define PHY_FORCE_LIMIT                   20
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define MASTER_DISABLE_TIMEOUT      800
+/* Number of milliseconds we wait for PHY configuration done after MAC reset */
+#define PHY_CFG_TIMEOUT             100
+/* Number of 2 milliseconds we wait for acquiring MDIO ownership. */
+#define MDIO_OWNERSHIP_TIMEOUT      10
+/* Number of milliseconds for NVM auto read done after MAC reset. */
+#define AUTO_READ_DONE_TIMEOUT      10
+
+/* Flow Control */
+#define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
+#define E1000_TXCW_PAUSE      0x00000080        /* TXCW sym pause request */
+#define E1000_TXCW_ASM_DIR    0x00000100        /* TXCW astm pause direction */
+#define E1000_TXCW_PAUSE_MASK 0x00000180        /* TXCW pause request mask */
+#define E1000_TXCW_ANE        0x80000000        /* Auto-neg enable */
+
+/* Receive Configuration Word */
+#define E1000_RXCW_IV         0x08000000        /* Receive config invalid */
+#define E1000_RXCW_C          0x20000000        /* Receive config */
+#define E1000_RXCW_SYNCH      0x40000000        /* Receive config synch */
+
+/* PCI Express Control */
+#define E1000_GCR_RXD_NO_SNOOP          0x00000001
+#define E1000_GCR_RXDSCW_NO_SNOOP       0x00000002
+#define E1000_GCR_RXDSCR_NO_SNOOP       0x00000004
+#define E1000_GCR_TXD_NO_SNOOP          0x00000008
+#define E1000_GCR_TXDSCW_NO_SNOOP       0x00000010
+#define E1000_GCR_TXDSCR_NO_SNOOP       0x00000020
+
+#define PCIE_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP         | \
+			   E1000_GCR_RXDSCW_NO_SNOOP      | \
+			   E1000_GCR_RXDSCR_NO_SNOOP      | \
+			   E1000_GCR_TXD_NO_SNOOP         | \
+			   E1000_GCR_TXDSCW_NO_SNOOP      | \
+			   E1000_GCR_TXDSCR_NO_SNOOP)
+
+/* PHY Control Register */
+#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
+#define MII_CR_POWER_DOWN       0x0800  /* Power down */
+#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
+#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
+#define MII_CR_SPEED_1000       0x0040
+#define MII_CR_SPEED_100        0x2000
+#define MII_CR_SPEED_10         0x0000
+
+/* PHY Status Register */
+#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_10T_HD_CAPS      0x0020   /* 10T   Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS      0x0040   /* 10T   Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS    0x0080   /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS    0x0100   /* 100TX Full Duplex Capable */
+#define NWAY_AR_PAUSE            0x0400   /* Pause operation desired */
+#define NWAY_AR_ASM_DIR          0x0800   /* Asymmetric Pause Direction bit */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
+
+/* Autoneg Expansion Register */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
+					/* 0=DTE device */
+#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
+					/* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE       0x1000 /* 1=Master/Slave manual config value */
+					/* 0=Automatic Master/Slave config */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
+
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CONTROL      0x00 /* Control Register */
+#define PHY_STATUS       0x01 /* Status Regiser */
+#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
+#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+
+/* NVM Control */
+#define E1000_EECD_SK        0x00000001 /* NVM Clock */
+#define E1000_EECD_CS        0x00000002 /* NVM Chip Select */
+#define E1000_EECD_DI        0x00000004 /* NVM Data In */
+#define E1000_EECD_DO        0x00000008 /* NVM Data Out */
+#define E1000_EECD_REQ       0x00000040 /* NVM Access Request */
+#define E1000_EECD_GNT       0x00000080 /* NVM Access Grant */
+#define E1000_EECD_SIZE      0x00000200 /* NVM Size (0=64 word 1=256 word) */
+#define E1000_EECD_ADDR_BITS 0x00000400 /* NVM Addressing bits based on type
+					 * (0-small, 1-large) */
+#define E1000_NVM_GRANT_ATTEMPTS   1000 /* NVM # attempts to gain grant */
+#define E1000_EECD_AUTO_RD          0x00000200  /* NVM Auto Read done */
+#define E1000_EECD_SIZE_EX_MASK     0x00007800  /* NVM Size */
+#define E1000_EECD_SIZE_EX_SHIFT     11
+#define E1000_EECD_FLUPD     0x00080000 /* Update FLASH */
+#define E1000_EECD_AUPDEN    0x00100000 /* Enable Autonomous FLASH update */
+#define E1000_EECD_SEC1VAL   0x00400000 /* Sector One Valid */
+
+#define E1000_NVM_RW_REG_DATA   16   /* Offset to data in NVM read/write registers */
+#define E1000_NVM_RW_REG_DONE   2    /* Offset to READ/WRITE done bit */
+#define E1000_NVM_RW_REG_START  1    /* Start operation */
+#define E1000_NVM_RW_ADDR_SHIFT 2    /* Shift to the address bits */
+#define E1000_NVM_POLL_WRITE    1    /* Flag for polling for write complete */
+#define E1000_NVM_POLL_READ     0    /* Flag for polling for read complete */
+#define E1000_FLASH_UPDATES  2000
+
+/* NVM Word Offsets */
+#define NVM_ID_LED_SETTINGS        0x0004
+#define NVM_INIT_CONTROL2_REG      0x000F
+#define NVM_INIT_CONTROL3_PORT_B   0x0014
+#define NVM_INIT_3GIO_3            0x001A
+#define NVM_INIT_CONTROL3_PORT_A   0x0024
+#define NVM_CFG                    0x0012
+#define NVM_CHECKSUM_REG           0x003F
+
+#define E1000_NVM_CFG_DONE_PORT_0  0x40000 /* MNG config cycle done */
+#define E1000_NVM_CFG_DONE_PORT_1  0x80000 /* ...for second port */
+
+/* Mask bits for fields in Word 0x0f of the NVM */
+#define NVM_WORD0F_PAUSE_MASK       0x3000
+#define NVM_WORD0F_PAUSE            0x1000
+#define NVM_WORD0F_ASM_DIR          0x2000
+
+/* Mask bits for fields in Word 0x1a of the NVM */
+#define NVM_WORD1A_ASPM_MASK  0x000C
+
+/* For checksumming, the sum of all words in the NVM should equal 0xBABA. */
+#define NVM_SUM                    0xBABA
+
+/* PBA (printed board assembly) number words */
+#define NVM_PBA_OFFSET_0           8
+#define NVM_PBA_OFFSET_1           9
+
+#define NVM_WORD_SIZE_BASE_SHIFT   6
+
+/* NVM Commands - SPI */
+#define NVM_MAX_RETRY_SPI          5000 /* Max wait of 5ms, for RDY signal */
+#define NVM_READ_OPCODE_SPI        0x03 /* NVM read opcode */
+#define NVM_WRITE_OPCODE_SPI       0x02 /* NVM write opcode */
+#define NVM_A8_OPCODE_SPI          0x08 /* opcode bit-3 = address bit-8 */
+#define NVM_WREN_OPCODE_SPI        0x06 /* NVM set Write Enable latch */
+#define NVM_RDSR_OPCODE_SPI        0x05 /* NVM read Status register */
+
+/* SPI NVM Status Register */
+#define NVM_STATUS_RDY_SPI         0x01
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT       ((ID_LED_OFF1_ON2  << 12) | \
+			      (ID_LED_OFF1_OFF2 <<  8) | \
+			      (ID_LED_DEF1_DEF2 <<  4) | \
+			      (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2     0x1
+#define ID_LED_DEF1_ON2      0x2
+#define ID_LED_DEF1_OFF2     0x3
+#define ID_LED_ON1_DEF2      0x4
+#define ID_LED_ON1_ON2       0x5
+#define ID_LED_ON1_OFF2      0x6
+#define ID_LED_OFF1_DEF2     0x7
+#define ID_LED_OFF1_ON2      0x8
+#define ID_LED_OFF1_OFF2     0x9
+
+#define IGP_ACTIVITY_LED_MASK   0xFFFFF0FF
+#define IGP_ACTIVITY_LED_ENABLE 0x0300
+#define IGP_LED3_MODE           0x07000000
+
+/* PCI/PCI-X/PCI-EX Config space */
+#define PCI_HEADER_TYPE_REGISTER     0x0E
+#define PCIE_LINK_STATUS             0x12
+
+#define PCI_HEADER_TYPE_MULTIFUNC    0x80
+#define PCIE_LINK_WIDTH_MASK         0x3F0
+#define PCIE_LINK_WIDTH_SHIFT        4
+
+#define PHY_REVISION_MASK      0xFFFFFFF0
+#define MAX_PHY_REG_ADDRESS    0x1F  /* 5 bit address bus (0-0x1F) */
+#define MAX_PHY_MULTI_PAGE_REG 0xF
+
+/* Bit definitions for valid PHY IDs. */
+/* I = Integrated
+ * E = External
+ */
+#define M88E1000_E_PHY_ID    0x01410C50
+#define M88E1000_I_PHY_ID    0x01410C30
+#define M88E1011_I_PHY_ID    0x01410C20
+#define IGP01E1000_I_PHY_ID  0x02A80380
+#define M88E1111_I_PHY_ID    0x01410CC0
+#define GG82563_E_PHY_ID     0x01410CA0
+#define IGP03E1000_E_PHY_ID  0x02A80390
+#define IFE_E_PHY_ID         0x02A80330
+#define IFE_PLUS_E_PHY_ID    0x02A80320
+#define IFE_C_E_PHY_ID       0x02A80310
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
+
+#define M88E1000_PHY_PAGE_SELECT   0x1D  /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL   0x1E  /* Its meaning depends on reg 29 */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000  /* MDI Crossover Mode bits 6:5 */
+					       /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
+#define M88E1000_PSCR_AUTO_X_1000T     0x0040  /* 1000BASE-T: Auto crossover,
+						*  100BASE-TX/10BASE-T:
+						*  MDI Mode
+						*/
+#define M88E1000_PSCR_AUTO_X_MODE      0x0060  /* Auto crossover enabled
+						* all speeds.
+						*/
+					/* 1=Enable Extended 10BASE-T distance
+					 * (Lower 10BASE-T RX Threshold)
+					 * 0=Normal 10BASE-T RX Threshold */
+					/* 1=5-Bit interface in 100BASE-TX
+					 * 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Transmit */
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
+#define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
+#define M88E1000_PSSR_CABLE_LENGTH       0x0380 /* 0=<50M;1=50-80M;2=80-110M;
+					    * 3=110-140M;4=>140M */
+#define M88E1000_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK  0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X    0x0100
+#define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
+
+/* M88EC018 Rev 2 specific DownShift settings */
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK  0x0E00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X    0x0800
+
+/* Bits...
+ * 15-5: page
+ * 4-0: register offset
+ */
+#define GG82563_PAGE_SHIFT        5
+#define GG82563_REG(page, reg)    \
+	(((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
+#define GG82563_MIN_ALT_REG       30
+
+/* GG82563 Specific Registers */
+#define GG82563_PHY_SPEC_CTRL           \
+	GG82563_REG(0, 16) /* PHY Specific Control */
+#define GG82563_PHY_PAGE_SELECT         \
+	GG82563_REG(0, 22) /* Page Select */
+#define GG82563_PHY_SPEC_CTRL_2         \
+	GG82563_REG(0, 26) /* PHY Specific Control 2 */
+#define GG82563_PHY_PAGE_SELECT_ALT     \
+	GG82563_REG(0, 29) /* Alternate Page Select */
+
+#define GG82563_PHY_MAC_SPEC_CTRL       \
+	GG82563_REG(2, 21) /* MAC Specific Control Register */
+
+#define GG82563_PHY_DSP_DISTANCE    \
+	GG82563_REG(5, 26) /* DSP Distance */
+
+/* Page 193 - Port Control Registers */
+#define GG82563_PHY_KMRN_MODE_CTRL   \
+	GG82563_REG(193, 16) /* Kumeran Mode Control */
+#define GG82563_PHY_PWR_MGMT_CTRL       \
+	GG82563_REG(193, 20) /* Power Management Control */
+
+/* Page 194 - KMRN Registers */
+#define GG82563_PHY_INBAND_CTRL         \
+	GG82563_REG(194, 18) /* Inband Control */
+
+/* MDI Control */
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE  0x04000000
+#define E1000_MDIC_OP_READ   0x08000000
+#define E1000_MDIC_READY     0x10000000
+#define E1000_MDIC_ERROR     0x40000000
+
+/* SerDes Control */
+#define E1000_GEN_POLL_TIMEOUT          640
+
+#endif /* _E1000_DEFINES_H_ */
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
new file mode 100644
index 0000000..d2499bb
--- /dev/null
+++ b/drivers/net/e1000e/e1000.h
@@ -0,0 +1,514 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* Linux PRO/1000 Ethernet Driver main header file */
+
+#ifndef _E1000_H_
+#define _E1000_H_
+
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
+#include <linux/io.h>
+#include <linux/netdevice.h>
+
+#include "hw.h"
+
+struct e1000_info;
+
+#define ndev_printk(level, netdev, format, arg...) \
+	printk(level "%s: %s: " format, (netdev)->dev.parent->bus_id, \
+	       (netdev)->name, ## arg)
+
+#ifdef DEBUG
+#define ndev_dbg(netdev, format, arg...) \
+	ndev_printk(KERN_DEBUG , netdev, format, ## arg)
+#else
+#define ndev_dbg(netdev, format, arg...) do { (void)(netdev); } while (0)
+#endif
+
+#define ndev_err(netdev, format, arg...) \
+	ndev_printk(KERN_ERR , netdev, format, ## arg)
+#define ndev_info(netdev, format, arg...) \
+	ndev_printk(KERN_INFO , netdev, format, ## arg)
+#define ndev_warn(netdev, format, arg...) \
+	ndev_printk(KERN_WARNING , netdev, format, ## arg)
+#define ndev_notice(netdev, format, arg...) \
+	ndev_printk(KERN_NOTICE , netdev, format, ## arg)
+
+
+/* TX/RX descriptor defines */
+#define E1000_DEFAULT_TXD		256
+#define E1000_MAX_TXD			4096
+#define E1000_MIN_TXD			80
+
+#define E1000_DEFAULT_RXD		256
+#define E1000_MAX_RXD			4096
+#define E1000_MIN_RXD			80
+
+/* Early Receive defines */
+#define E1000_ERT_2048			0x100
+
+#define E1000_FC_PAUSE_TIME		0x0680 /* 858 usec */
+
+/* How many Tx Descriptors do we need to call netif_wake_queue ? */
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define E1000_RX_BUFFER_WRITE		16 /* Must be power of 2 */
+
+#define AUTO_ALL_MODES			0
+#define E1000_EEPROM_APME		0x0400
+
+#define E1000_MNG_VLAN_NONE		(-1)
+
+/* Number of packet split data buffers (not including the header buffer) */
+#define PS_PAGE_BUFFERS			(MAX_PS_BUFFERS - 1)
+
+enum e1000_boards {
+	board_82571,
+	board_82572,
+	board_82573,
+	board_80003es2lan,
+	board_ich8lan,
+	board_ich9lan,
+};
+
+struct e1000_queue_stats {
+	u64 packets;
+	u64 bytes;
+};
+
+struct e1000_ps_page {
+	struct page *page;
+	u64 dma; /* must be u64 - written to hw */
+};
+
+/*
+ * wrappers around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer
+ */
+struct e1000_buffer {
+	dma_addr_t dma;
+	struct sk_buff *skb;
+	union {
+		/* TX */
+		struct {
+			unsigned long time_stamp;
+			u16 length;
+			u16 next_to_watch;
+		};
+		/* RX */
+		struct page *page;
+	};
+
+};
+
+struct e1000_ring {
+	void *desc;			/* pointer to ring memory  */
+	dma_addr_t dma;			/* phys address of ring    */
+	unsigned int size;		/* length of ring in bytes */
+	unsigned int count;		/* number of desc. in ring */
+
+	u16 next_to_use;
+	u16 next_to_clean;
+
+	u16 head;
+	u16 tail;
+
+	/* array of buffer information structs */
+	struct e1000_buffer *buffer_info;
+
+	/* arrays of page information for packet split */
+	struct e1000_ps_page *ps_pages;
+	struct sk_buff *rx_skb_top;
+
+	struct e1000_queue_stats stats;
+};
+
+/* board specific private data structure */
+struct e1000_adapter {
+	struct timer_list watchdog_timer;
+	struct timer_list phy_info_timer;
+	struct timer_list blink_timer;
+
+	struct work_struct reset_task;
+	struct work_struct watchdog_task;
+
+	const struct e1000_info *ei;
+
+	struct vlan_group *vlgrp;
+	u32 bd_number;
+	u32 rx_buffer_len;
+	u16 mng_vlan_id;
+	u16 link_speed;
+	u16 link_duplex;
+
+	spinlock_t tx_queue_lock; /* prevent concurrent tail updates */
+
+	/* this is still needed for 82571 and above */
+	atomic_t irq_sem;
+
+	/* track device up/down/testing state */
+	unsigned long state;
+
+	/* Interrupt Throttle Rate */
+	u32 itr;
+	u32 itr_setting;
+	u16 tx_itr;
+	u16 rx_itr;
+
+	/*
+	 * TX
+	 */
+	struct e1000_ring *tx_ring /* One per active queue */
+						____cacheline_aligned_in_smp;
+
+	struct napi_struct napi;
+
+	unsigned long tx_queue_len;
+	unsigned int restart_queue;
+	u32 txd_cmd;
+
+	bool detect_tx_hung;
+	u8 tx_timeout_factor;
+
+	u32 tx_int_delay;
+	u32 tx_abs_int_delay;
+
+	unsigned int total_tx_bytes;
+	unsigned int total_tx_packets;
+	unsigned int total_rx_bytes;
+	unsigned int total_rx_packets;
+
+	/* TX stats */
+	u64 tpt_old;
+	u64 colc_old;
+	u64 gotcl_old;
+	u32 gotcl;
+	u32 tx_timeout_count;
+	u32 tx_fifo_head;
+	u32 tx_head_addr;
+	u32 tx_fifo_size;
+	u32 tx_dma_failed;
+
+	/*
+	 * RX
+	 */
+	bool (*clean_rx) (struct e1000_adapter *adapter,
+			  int *work_done, int work_to_do)
+						____cacheline_aligned_in_smp;
+	void (*alloc_rx_buf) (struct e1000_adapter *adapter,
+			      int cleaned_count);
+	struct e1000_ring *rx_ring;
+
+	u32 rx_int_delay;
+	u32 rx_abs_int_delay;
+
+	/* RX stats */
+	u64 hw_csum_err;
+	u64 hw_csum_good;
+	u64 rx_hdr_split;
+	u64 gorcl_old;
+	u32 gorcl;
+	u32 alloc_rx_buff_failed;
+	u32 rx_dma_failed;
+
+	unsigned int rx_ps_pages;
+	u16 rx_ps_bsize0;
+
+	/* OS defined structs */
+	struct net_device *netdev;
+	struct pci_dev *pdev;
+	struct net_device_stats net_stats;
+	spinlock_t stats_lock;      /* prevent concurrent stats updates */
+
+	/* structs defined in e1000_hw.h */
+	struct e1000_hw hw;
+
+	struct e1000_hw_stats stats;
+	struct e1000_phy_info phy_info;
+	struct e1000_phy_stats phy_stats;
+
+	struct e1000_ring test_tx_ring;
+	struct e1000_ring test_rx_ring;
+	u32 test_icr;
+
+	u32 msg_enable;
+
+	u32 eeprom_wol;
+	u32 wol;
+	u32 pba;
+
+	u8 fc_autoneg;
+
+	unsigned long led_status;
+
+	unsigned int flags;
+};
+
+struct e1000_info {
+	enum e1000_mac_type	mac;
+	unsigned int		flags;
+	u32			pba;
+	s32			(*get_invariants)(struct e1000_adapter *);
+	struct e1000_mac_operations *mac_ops;
+	struct e1000_phy_operations *phy_ops;
+	struct e1000_nvm_operations *nvm_ops;
+};
+
+/* hardware capability, feature, and workaround flags */
+#define FLAG_HAS_AMT                      (1 << 0)
+#define FLAG_HAS_FLASH                    (1 << 1)
+#define FLAG_HAS_HW_VLAN_FILTER           (1 << 2)
+#define FLAG_HAS_WOL                      (1 << 3)
+#define FLAG_HAS_ERT                      (1 << 4)
+#define FLAG_HAS_CTRLEXT_ON_LOAD          (1 << 5)
+#define FLAG_HAS_SWSM_ON_LOAD             (1 << 6)
+#define FLAG_HAS_JUMBO_FRAMES             (1 << 7)
+#define FLAG_HAS_ASPM                     (1 << 8)
+#define FLAG_HAS_STATS_ICR_ICT            (1 << 9)
+#define FLAG_HAS_STATS_PTC_PRC            (1 << 10)
+#define FLAG_HAS_SMART_POWER_DOWN         (1 << 11)
+#define FLAG_IS_QUAD_PORT_A               (1 << 12)
+#define FLAG_IS_QUAD_PORT                 (1 << 13)
+#define FLAG_TIPG_MEDIUM_FOR_80003ESLAN   (1 << 14)
+#define FLAG_APME_IN_WUC                  (1 << 15)
+#define FLAG_APME_IN_CTRL3                (1 << 16)
+#define FLAG_APME_CHECK_PORT_B            (1 << 17)
+#define FLAG_DISABLE_FC_PAUSE_TIME        (1 << 18)
+#define FLAG_NO_WAKE_UCAST                (1 << 19)
+#define FLAG_MNG_PT_ENABLED               (1 << 20)
+#define FLAG_RESET_OVERWRITES_LAA         (1 << 21)
+#define FLAG_TARC_SPEED_MODE_BIT          (1 << 22)
+#define FLAG_TARC_SET_BIT_ZERO            (1 << 23)
+#define FLAG_RX_NEEDS_RESTART             (1 << 24)
+#define FLAG_LSC_GIG_SPEED_DROP           (1 << 25)
+#define FLAG_SMART_POWER_DOWN             (1 << 26)
+#define FLAG_MSI_ENABLED                  (1 << 27)
+#define FLAG_RX_CSUM_ENABLED              (1 << 28)
+#define FLAG_TSO_FORCE                    (1 << 29)
+
+#define E1000_RX_DESC_PS(R, i)	    \
+	(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
+#define E1000_GET_DESC(R, i, type)	(&(((struct type *)((R).desc))[i]))
+#define E1000_RX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_rx_desc)
+#define E1000_TX_DESC(R, i)		E1000_GET_DESC(R, i, e1000_tx_desc)
+#define E1000_CONTEXT_DESC(R, i)	E1000_GET_DESC(R, i, e1000_context_desc)
+
+enum e1000_state_t {
+	__E1000_TESTING,
+	__E1000_RESETTING,
+	__E1000_DOWN
+};
+
+enum latency_range {
+	lowest_latency = 0,
+	low_latency = 1,
+	bulk_latency = 2,
+	latency_invalid = 255
+};
+
+extern char e1000e_driver_name[];
+extern const char e1000e_driver_version[];
+
+extern void e1000e_check_options(struct e1000_adapter *adapter);
+extern void e1000e_set_ethtool_ops(struct net_device *netdev);
+
+extern int e1000e_up(struct e1000_adapter *adapter);
+extern void e1000e_down(struct e1000_adapter *adapter);
+extern void e1000e_reinit_locked(struct e1000_adapter *adapter);
+extern void e1000e_reset(struct e1000_adapter *adapter);
+extern void e1000e_power_up_phy(struct e1000_adapter *adapter);
+extern int e1000e_setup_rx_resources(struct e1000_adapter *adapter);
+extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter);
+extern void e1000e_free_rx_resources(struct e1000_adapter *adapter);
+extern void e1000e_free_tx_resources(struct e1000_adapter *adapter);
+extern void e1000e_update_stats(struct e1000_adapter *adapter);
+
+extern unsigned int copybreak;
+
+extern char *e1000e_get_hw_dev_name(struct e1000_hw *hw);
+
+extern struct e1000_info e1000_82571_info;
+extern struct e1000_info e1000_82572_info;
+extern struct e1000_info e1000_82573_info;
+extern struct e1000_info e1000_ich8_info;
+extern struct e1000_info e1000_ich9_info;
+extern struct e1000_info e1000_es2_info;
+
+extern s32 e1000e_read_part_num(struct e1000_hw *hw, u32 *part_num);
+
+extern s32  e1000e_commit_phy(struct e1000_hw *hw);
+
+extern bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw);
+
+extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
+extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state);
+
+extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
+						 bool state);
+extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
+extern void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw);
+
+extern s32 e1000e_check_for_copper_link(struct e1000_hw *hw);
+extern s32 e1000e_check_for_fiber_link(struct e1000_hw *hw);
+extern s32 e1000e_check_for_serdes_link(struct e1000_hw *hw);
+extern s32 e1000e_cleanup_led_generic(struct e1000_hw *hw);
+extern s32 e1000e_led_on_generic(struct e1000_hw *hw);
+extern s32 e1000e_led_off_generic(struct e1000_hw *hw);
+extern s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw);
+extern s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex);
+extern s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex);
+extern s32 e1000e_disable_pcie_master(struct e1000_hw *hw);
+extern s32 e1000e_get_auto_rd_done(struct e1000_hw *hw);
+extern s32 e1000e_id_led_init(struct e1000_hw *hw);
+extern void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw);
+extern s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw);
+extern s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw);
+extern s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw);
+extern s32 e1000e_setup_link(struct e1000_hw *hw);
+extern void e1000e_clear_vfta(struct e1000_hw *hw);
+extern void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
+extern void e1000e_mc_addr_list_update_generic(struct e1000_hw *hw,
+				       u8 *mc_addr_list, u32 mc_addr_count,
+				       u32 rar_used_count, u32 rar_count);
+extern void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
+extern s32 e1000e_set_fc_watermarks(struct e1000_hw *hw);
+extern void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop);
+extern s32 e1000e_get_hw_semaphore(struct e1000_hw *hw);
+extern s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data);
+extern void e1000e_config_collision_dist(struct e1000_hw *hw);
+extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw);
+extern s32 e1000e_force_mac_fc(struct e1000_hw *hw);
+extern s32 e1000e_blink_led(struct e1000_hw *hw);
+extern void e1000e_write_vfta(struct e1000_hw *hw, u32 offset, u32 value);
+extern void e1000e_reset_adaptive(struct e1000_hw *hw);
+extern void e1000e_update_adaptive(struct e1000_hw *hw);
+
+extern s32 e1000e_setup_copper_link(struct e1000_hw *hw);
+extern s32 e1000e_get_phy_id(struct e1000_hw *hw);
+extern void e1000e_put_hw_semaphore(struct e1000_hw *hw);
+extern s32 e1000e_check_reset_block_generic(struct e1000_hw *hw);
+extern s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw);
+extern s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw);
+extern s32 e1000e_get_phy_info_igp(struct e1000_hw *hw);
+extern s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw);
+extern s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active);
+extern s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data);
+extern s32 e1000e_phy_sw_reset(struct e1000_hw *hw);
+extern s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw);
+extern s32 e1000e_get_cfg_done(struct e1000_hw *hw);
+extern s32 e1000e_get_cable_length_m88(struct e1000_hw *hw);
+extern s32 e1000e_get_phy_info_m88(struct e1000_hw *hw);
+extern s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
+extern enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id);
+extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
+extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
+extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
+extern s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
+			       u32 usec_interval, bool *success);
+extern s32 e1000e_phy_reset_dsp(struct e1000_hw *hw);
+extern s32 e1000e_check_downshift(struct e1000_hw *hw);
+
+static inline s32 e1000_phy_hw_reset(struct e1000_hw *hw)
+{
+	return hw->phy.ops.reset_phy(hw);
+}
+
+static inline s32 e1000_check_reset_block(struct e1000_hw *hw)
+{
+	return hw->phy.ops.check_reset_block(hw);
+}
+
+static inline s32 e1e_rphy(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	return hw->phy.ops.read_phy_reg(hw, offset, data);
+}
+
+static inline s32 e1e_wphy(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	return hw->phy.ops.write_phy_reg(hw, offset, data);
+}
+
+static inline s32 e1000_get_cable_length(struct e1000_hw *hw)
+{
+	return hw->phy.ops.get_cable_length(hw);
+}
+
+extern s32 e1000e_acquire_nvm(struct e1000_hw *hw);
+extern s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+extern s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw);
+extern s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg);
+extern s32 e1000e_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+extern s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
+extern s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw);
+extern void e1000e_release_nvm(struct e1000_hw *hw);
+extern void e1000e_reload_nvm(struct e1000_hw *hw);
+extern s32 e1000e_read_mac_addr(struct e1000_hw *hw);
+
+static inline s32 e1000_validate_nvm_checksum(struct e1000_hw *hw)
+{
+	return hw->nvm.ops.validate_nvm(hw);
+}
+
+static inline s32 e1000e_update_nvm_checksum(struct e1000_hw *hw)
+{
+	return hw->nvm.ops.update_nvm(hw);
+}
+
+static inline s32 e1000_read_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	return hw->nvm.ops.read_nvm(hw, offset, words, data);
+}
+
+static inline s32 e1000_write_nvm(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	return hw->nvm.ops.write_nvm(hw, offset, words, data);
+}
+
+static inline s32 e1000_get_phy_info(struct e1000_hw *hw)
+{
+	return hw->phy.ops.get_phy_info(hw);
+}
+
+extern bool e1000e_check_mng_mode(struct e1000_hw *hw);
+extern bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw);
+extern s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length);
+
+static inline u32 __er32(struct e1000_hw *hw, unsigned long reg)
+{
+	return readl(hw->hw_addr + reg);
+}
+
+static inline void __ew32(struct e1000_hw *hw, unsigned long reg, u32 val)
+{
+	writel(val, hw->hw_addr + reg);
+}
+
+#endif /* _E1000_H_ */
diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c
new file mode 100644
index 0000000..88657ad
--- /dev/null
+++ b/drivers/net/e1000e/es2lan.c
@@ -0,0 +1,1232 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/*
+ * 80003ES2LAN Gigabit Ethernet Controller (Copper)
+ * 80003ES2LAN Gigabit Ethernet Controller (Serdes)
+ */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "e1000.h"
+
+#define E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL	 0x00
+#define E1000_KMRNCTRLSTA_OFFSET_INB_CTRL	 0x02
+#define E1000_KMRNCTRLSTA_OFFSET_HD_CTRL	 0x10
+
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS	 0x0008
+#define E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS	 0x0800
+#define E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING	 0x0010
+
+#define E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT 0x0004
+#define E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT	 0x0000
+
+#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */
+#define DEFAULT_TCTL_EXT_GCEX_80003ES2LAN	 0x00010000
+
+#define DEFAULT_TIPG_IPGT_1000_80003ES2LAN	 0x8
+#define DEFAULT_TIPG_IPGT_10_100_80003ES2LAN	 0x9
+
+/* GG82563 PHY Specific Status Register (Page 0, Register 16 */
+#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE	 0x0002 /* 1=Reversal Disab. */
+#define GG82563_PSCR_CROSSOVER_MODE_MASK	 0x0060
+#define GG82563_PSCR_CROSSOVER_MODE_MDI		 0x0000 /* 00=Manual MDI */
+#define GG82563_PSCR_CROSSOVER_MODE_MDIX	 0x0020 /* 01=Manual MDIX */
+#define GG82563_PSCR_CROSSOVER_MODE_AUTO	 0x0060 /* 11=Auto crossover */
+
+/* PHY Specific Control Register 2 (Page 0, Register 26) */
+#define GG82563_PSCR2_REVERSE_AUTO_NEG		 0x2000
+						/* 1=Reverse Auto-Negotiation */
+
+/* MAC Specific Control Register (Page 2, Register 21) */
+/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */
+#define GG82563_MSCR_TX_CLK_MASK		 0x0007
+#define GG82563_MSCR_TX_CLK_10MBPS_2_5		 0x0004
+#define GG82563_MSCR_TX_CLK_100MBPS_25		 0x0005
+#define GG82563_MSCR_TX_CLK_1000MBPS_25		 0x0007
+
+#define GG82563_MSCR_ASSERT_CRS_ON_TX		 0x0010 /* 1=Assert */
+
+/* DSP Distance Register (Page 5, Register 26) */
+#define GG82563_DSPD_CABLE_LENGTH		 0x0007 /* 0 = <50M
+							   1 = 50-80M
+							   2 = 80-110M
+							   3 = 110-140M
+							   4 = >140M */
+
+/* Kumeran Mode Control Register (Page 193, Register 16) */
+#define GG82563_KMCR_PASS_FALSE_CARRIER		 0x0800
+
+/* Power Management Control Register (Page 193, Register 20) */
+#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE	 0x0001
+					   /* 1=Enable SERDES Electrical Idle */
+
+/* In-Band Control Register (Page 194, Register 18) */
+#define GG82563_ICR_DIS_PADDING			 0x0010 /* Disable Padding */
+
+/* A table for the GG82563 cable length where the range is defined
+ * with a lower bound at "index" and the upper bound at
+ * "index + 5".
+ */
+static const u16 e1000_gg82563_cable_length_table[] =
+	 { 0, 60, 115, 150, 150, 60, 115, 150, 180, 180, 0xFF };
+
+static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw);
+static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask);
+static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask);
+static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw);
+static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw);
+static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw);
+static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex);
+
+/**
+ *  e1000_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_phy_params_80003es2lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+
+	if (hw->media_type != e1000_media_type_copper) {
+		phy->type	= e1000_phy_none;
+		return 0;
+	}
+
+	phy->addr		= 1;
+	phy->autoneg_mask	= AUTONEG_ADVERTISE_SPEED_DEFAULT;
+	phy->reset_delay_us      = 100;
+	phy->type		= e1000_phy_gg82563;
+
+	/* This can only be done after all function pointers are setup. */
+	ret_val = e1000e_get_phy_id(hw);
+
+	/* Verify phy id */
+	if (phy->id != GG82563_E_PHY_ID)
+		return -E1000_ERR_PHY;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_init_nvm_params_80003es2lan - Init ESB2 NVM func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_nvm_params_80003es2lan(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = er32(EECD);
+	u16 size;
+
+	nvm->opcode_bits	= 8;
+	nvm->delay_usec	 = 1;
+	switch (nvm->override) {
+	case e1000_nvm_override_spi_large:
+		nvm->page_size    = 32;
+		nvm->address_bits = 16;
+		break;
+	case e1000_nvm_override_spi_small:
+		nvm->page_size    = 8;
+		nvm->address_bits = 8;
+		break;
+	default:
+		nvm->page_size    = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
+		nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ? 16 : 8;
+		break;
+	}
+
+	nvm->type	       = e1000_nvm_eeprom_spi;
+
+	size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
+			  E1000_EECD_SIZE_EX_SHIFT);
+
+	/* Added to a constant, "size" becomes the left-shift value
+	 * for setting word_size.
+	 */
+	size += NVM_WORD_SIZE_BASE_SHIFT;
+	nvm->word_size	= 1 << size;
+
+	return 0;
+}
+
+/**
+ *  e1000_init_mac_params_80003es2lan - Init ESB2 MAC func ptrs.
+ *  @hw: pointer to the HW structure
+ *
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_mac_params_80003es2lan(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_mac_info *mac = &hw->mac;
+	struct e1000_mac_operations *func = &mac->ops;
+
+	/* Set media type */
+	switch (adapter->pdev->device) {
+	case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
+		hw->media_type = e1000_media_type_internal_serdes;
+		break;
+	default:
+		hw->media_type = e1000_media_type_copper;
+		break;
+	}
+
+	/* Set mta register count */
+	mac->mta_reg_count = 128;
+	/* Set rar entry count */
+	mac->rar_entry_count = E1000_RAR_ENTRIES;
+	/* Set if manageability features are enabled. */
+	mac->arc_subsystem_valid =
+		(er32(FWSM) & E1000_FWSM_MODE_MASK) ? 1 : 0;
+
+	/* check for link */
+	switch (hw->media_type) {
+	case e1000_media_type_copper:
+		func->setup_physical_interface = e1000_setup_copper_link_80003es2lan;
+		func->check_for_link = e1000e_check_for_copper_link;
+		break;
+	case e1000_media_type_fiber:
+		func->setup_physical_interface = e1000e_setup_fiber_serdes_link;
+		func->check_for_link = e1000e_check_for_fiber_link;
+		break;
+	case e1000_media_type_internal_serdes:
+		func->setup_physical_interface = e1000e_setup_fiber_serdes_link;
+		func->check_for_link = e1000e_check_for_serdes_link;
+		break;
+	default:
+		return -E1000_ERR_CONFIG;
+		break;
+	}
+
+	return 0;
+}
+
+static s32 e1000_get_invariants_80003es2lan(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	s32 rc;
+
+	rc = e1000_init_mac_params_80003es2lan(adapter);
+	if (rc)
+		return rc;
+
+	rc = e1000_init_nvm_params_80003es2lan(hw);
+	if (rc)
+		return rc;
+
+	rc = e1000_init_phy_params_80003es2lan(hw);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
+/**
+ *  e1000_acquire_phy_80003es2lan - Acquire rights to access PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  A wrapper to acquire access rights to the correct PHY.  This is a
+ *  function pointer entry point called by the api module.
+ **/
+static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw)
+{
+	u16 mask;
+
+	mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+
+	return e1000_acquire_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ *  e1000_release_phy_80003es2lan - Release rights to access PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  A wrapper to release access rights to the correct PHY.  This is a
+ *  function pointer entry point called by the api module.
+ **/
+static void e1000_release_phy_80003es2lan(struct e1000_hw *hw)
+{
+	u16 mask;
+
+	mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM;
+	e1000_release_swfw_sync_80003es2lan(hw, mask);
+}
+
+/**
+ *  e1000_acquire_nvm_80003es2lan - Acquire rights to access NVM
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the semaphore to access the EEPROM.  This is a function
+ *  pointer entry point called by the api module.
+ **/
+static s32 e1000_acquire_nvm_80003es2lan(struct e1000_hw *hw)
+{
+	s32 ret_val;
+
+	ret_val = e1000_acquire_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+	if (ret_val)
+		return ret_val;
+
+	ret_val = e1000e_acquire_nvm(hw);
+
+	if (ret_val)
+		e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_release_nvm_80003es2lan - Relinquish rights to access NVM
+ *  @hw: pointer to the HW structure
+ *
+ *  Release the semaphore used to access the EEPROM.  This is a
+ *  function pointer entry point called by the api module.
+ **/
+static void e1000_release_nvm_80003es2lan(struct e1000_hw *hw)
+{
+	e1000e_release_nvm(hw);
+	e1000_release_swfw_sync_80003es2lan(hw, E1000_SWFW_EEP_SM);
+}
+
+/**
+ *  e1000_acquire_swfw_sync_80003es2lan - Acquire SW/FW semaphore
+ *  @hw: pointer to the HW structure
+ *  @mask: specifies which semaphore to acquire
+ *
+ *  Acquire the SW/FW semaphore to access the PHY or NVM.  The mask
+ *  will also specify which port we're acquiring the lock for.
+ **/
+static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
+{
+	u32 swfw_sync;
+	u32 swmask = mask;
+	u32 fwmask = mask << 16;
+	s32 i = 0;
+	s32 timeout = 200;
+
+	while (i < timeout) {
+		if (e1000e_get_hw_semaphore(hw))
+			return -E1000_ERR_SWFW_SYNC;
+
+		swfw_sync = er32(SW_FW_SYNC);
+		if (!(swfw_sync & (fwmask | swmask)))
+			break;
+
+		/* Firmware currently using resource (fwmask)
+		 * or other software thread using resource (swmask) */
+		e1000e_put_hw_semaphore(hw);
+		mdelay(5);
+		i++;
+	}
+
+	if (i == timeout) {
+		hw_dbg(hw,
+		       "Driver can't access resource, SW_FW_SYNC timeout.\n");
+		return -E1000_ERR_SWFW_SYNC;
+	}
+
+	swfw_sync |= swmask;
+	ew32(SW_FW_SYNC, swfw_sync);
+
+	e1000e_put_hw_semaphore(hw);
+
+	return 0;
+}
+
+/**
+ *  e1000_release_swfw_sync_80003es2lan - Release SW/FW semaphore
+ *  @hw: pointer to the HW structure
+ *  @mask: specifies which semaphore to acquire
+ *
+ *  Release the SW/FW semaphore used to access the PHY or NVM.  The mask
+ *  will also specify which port we're releasing the lock for.
+ **/
+static void e1000_release_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask)
+{
+	u32 swfw_sync;
+
+	while (e1000e_get_hw_semaphore(hw) != 0);
+	/* Empty */
+
+	swfw_sync = er32(SW_FW_SYNC);
+	swfw_sync &= ~mask;
+	ew32(SW_FW_SYNC, swfw_sync);
+
+	e1000e_put_hw_semaphore(hw);
+}
+
+/**
+ *  e1000_read_phy_reg_gg82563_80003es2lan - Read GG82563 PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of the register to read
+ *  @data: pointer to the data returned from the operation
+ *
+ *  Read the GG82563 PHY register.  This is a function pointer entry
+ *  point called by the api module.
+ **/
+static s32 e1000_read_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+						  u32 offset, u16 *data)
+{
+	s32 ret_val;
+	u32 page_select;
+	u16 temp;
+
+	/* Select Configuration Page */
+	if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG)
+		page_select = GG82563_PHY_PAGE_SELECT;
+	else
+		/* Use Alternative Page Select register to access
+		 * registers 30 and 31
+		 */
+		page_select = GG82563_PHY_PAGE_SELECT_ALT;
+
+	temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
+	ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp);
+	if (ret_val)
+		return ret_val;
+
+	/* The "ready" bit in the MDIC register may be incorrectly set
+	 * before the device has completed the "Page Select" MDI
+	 * transaction.  So we wait 200us after each MDI command...
+	 */
+	udelay(200);
+
+	/* ...and verify the command was successful. */
+	ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp);
+
+	if (((u16)offset >> GG82563_PAGE_SHIFT) != temp) {
+		ret_val = -E1000_ERR_PHY;
+		return ret_val;
+	}
+
+	udelay(200);
+
+	ret_val = e1000e_read_phy_reg_m88(hw,
+					 MAX_PHY_REG_ADDRESS & offset,
+					 data);
+
+	udelay(200);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_write_phy_reg_gg82563_80003es2lan - Write GG82563 PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of the register to read
+ *  @data: value to write to the register
+ *
+ *  Write to the GG82563 PHY register.  This is a function pointer entry
+ *  point called by the api module.
+ **/
+static s32 e1000_write_phy_reg_gg82563_80003es2lan(struct e1000_hw *hw,
+						   u32 offset, u16 data)
+{
+	s32 ret_val;
+	u32 page_select;
+	u16 temp;
+
+	/* Select Configuration Page */
+	if ((offset & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG)
+		page_select = GG82563_PHY_PAGE_SELECT;
+	else
+		/* Use Alternative Page Select register to access
+		 * registers 30 and 31
+		 */
+		page_select = GG82563_PHY_PAGE_SELECT_ALT;
+
+	temp = (u16)((u16)offset >> GG82563_PAGE_SHIFT);
+	ret_val = e1000e_write_phy_reg_m88(hw, page_select, temp);
+	if (ret_val)
+		return ret_val;
+
+
+	/* The "ready" bit in the MDIC register may be incorrectly set
+	 * before the device has completed the "Page Select" MDI
+	 * transaction.  So we wait 200us after each MDI command...
+	 */
+	udelay(200);
+
+	/* ...and verify the command was successful. */
+	ret_val = e1000e_read_phy_reg_m88(hw, page_select, &temp);
+
+	if (((u16)offset >> GG82563_PAGE_SHIFT) != temp)
+		return -E1000_ERR_PHY;
+
+	udelay(200);
+
+	ret_val = e1000e_write_phy_reg_m88(hw,
+					  MAX_PHY_REG_ADDRESS & offset,
+					  data);
+
+	udelay(200);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_write_nvm_80003es2lan - Write to ESB2 NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of the register to read
+ *  @words: number of words to write
+ *  @data: buffer of data to write to the NVM
+ *
+ *  Write "words" of data to the ESB2 NVM.  This is a function
+ *  pointer entry point called by the api module.
+ **/
+static s32 e1000_write_nvm_80003es2lan(struct e1000_hw *hw, u16 offset,
+				       u16 words, u16 *data)
+{
+	return e1000e_write_nvm_spi(hw, offset, words, data);
+}
+
+/**
+ *  e1000_get_cfg_done_80003es2lan - Wait for configuration to complete
+ *  @hw: pointer to the HW structure
+ *
+ *  Wait a specific amount of time for manageability processes to complete.
+ *  This is a function pointer entry point called by the phy module.
+ **/
+static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw)
+{
+	s32 timeout = PHY_CFG_TIMEOUT;
+	u32 mask = E1000_NVM_CFG_DONE_PORT_0;
+
+	if (hw->bus.func == 1)
+		mask = E1000_NVM_CFG_DONE_PORT_1;
+
+	while (timeout) {
+		if (er32(EEMNGCTL) & mask)
+			break;
+		msleep(1);
+		timeout--;
+	}
+	if (!timeout) {
+		hw_dbg(hw, "MNG configuration cycle has not completed.\n");
+		return -E1000_ERR_RESET;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex_80003es2lan - Force PHY speed and duplex
+ *  @hw: pointer to the HW structure
+ *
+ *  Force the speed and duplex settings onto the PHY.  This is a
+ *  function pointer entry point called by the phy module.
+ **/
+static s32 e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw)
+{
+	s32 ret_val;
+	u16 phy_data;
+	bool link;
+
+	/* Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
+	 * forced whenever speed and duplex are forced.
+	 */
+	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_AUTO;
+	ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		return ret_val;
+
+	hw_dbg(hw, "GG82563 PSCR: %X\n", phy_data);
+
+	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	/* Reset the phy to commit changes. */
+	phy_data |= MII_CR_RESET;
+
+	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		return ret_val;
+
+	udelay(1);
+
+	if (hw->phy.wait_for_link) {
+		hw_dbg(hw, "Waiting for forced speed/duplex link "
+			 "on GG82563 phy.\n");
+
+		ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+						     100000, &link);
+		if (ret_val)
+			return ret_val;
+
+		if (!link) {
+			/* We didn't get link.
+			 * Reset the DSP and cross our fingers.
+			 */
+			ret_val = e1000e_phy_reset_dsp(hw);
+			if (ret_val)
+				return ret_val;
+		}
+
+		/* Try once more */
+		ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+						     100000, &link);
+		if (ret_val)
+			return ret_val;
+	}
+
+	ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	/* Resetting the phy means we need to verify the TX_CLK corresponds
+	 * to the link speed.  10Mbps -> 2.5MHz, else 25MHz.
+	 */
+	phy_data &= ~GG82563_MSCR_TX_CLK_MASK;
+	if (hw->mac.forced_speed_duplex & E1000_ALL_10_SPEED)
+		phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5;
+	else
+		phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25;
+
+	/* In addition, we must re-enable CRS on Tx for both half and full
+	 * duplex.
+	 */
+	phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+	ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_get_cable_length_80003es2lan - Set approximate cable length
+ *  @hw: pointer to the HW structure
+ *
+ *  Find the approximate cable length as measured by the GG82563 PHY.
+ *  This is a function pointer entry point called by the phy module.
+ **/
+static s32 e1000_get_cable_length_80003es2lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+	u16 index;
+
+	ret_val = e1e_rphy(hw, GG82563_PHY_DSP_DISTANCE, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	index = phy_data & GG82563_DSPD_CABLE_LENGTH;
+	phy->min_cable_length = e1000_gg82563_cable_length_table[index];
+	phy->max_cable_length = e1000_gg82563_cable_length_table[index+5];
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+	return 0;
+}
+
+/**
+ *  e1000_get_link_up_info_80003es2lan - Report speed and duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: pointer to speed buffer
+ *  @duplex: pointer to duplex buffer
+ *
+ *  Retrieve the current speed and duplex configuration.
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed,
+					      u16 *duplex)
+{
+	s32 ret_val;
+
+	if (hw->media_type == e1000_media_type_copper) {
+		ret_val = e1000e_get_speed_and_duplex_copper(hw,
+								    speed,
+								    duplex);
+		if (ret_val)
+			return ret_val;
+		if (*speed == SPEED_1000)
+			ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw);
+		else
+			ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw,
+							      *duplex);
+	} else {
+		ret_val = e1000e_get_speed_and_duplex_fiber_serdes(hw,
+								  speed,
+								  duplex);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_reset_hw_80003es2lan - Reset the ESB2 controller
+ *  @hw: pointer to the HW structure
+ *
+ *  Perform a global reset to the ESB2 controller.
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	u32 icr;
+	s32 ret_val;
+
+	/* Prevent the PCI-E bus from sticking if there is no TLP connection
+	 * on the last TLP read/write transaction when MAC is reset.
+	 */
+	ret_val = e1000e_disable_pcie_master(hw);
+	if (ret_val)
+		hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+
+	hw_dbg(hw, "Masking off all interrupts\n");
+	ew32(IMC, 0xffffffff);
+
+	ew32(RCTL, 0);
+	ew32(TCTL, E1000_TCTL_PSP);
+	e1e_flush();
+
+	msleep(10);
+
+	ctrl = er32(CTRL);
+
+	hw_dbg(hw, "Issuing a global reset to MAC\n");
+	ew32(CTRL, ctrl | E1000_CTRL_RST);
+
+	ret_val = e1000e_get_auto_rd_done(hw);
+	if (ret_val)
+		/* We don't want to continue accessing MAC registers. */
+		return ret_val;
+
+	/* Clear any pending interrupt events. */
+	ew32(IMC, 0xffffffff);
+	icr = er32(ICR);
+
+	return 0;
+}
+
+/**
+ *  e1000_init_hw_80003es2lan - Initialize the ESB2 controller
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize the hw bits, LED, VFTA, MTA, link and hw counters.
+ *  This is a function pointer entry point called by the api module.
+ **/
+static s32 e1000_init_hw_80003es2lan(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 reg_data;
+	s32 ret_val;
+	u16 i;
+
+	e1000_initialize_hw_bits_80003es2lan(hw);
+
+	/* Initialize identification LED */
+	ret_val = e1000e_id_led_init(hw);
+	if (ret_val) {
+		hw_dbg(hw, "Error initializing identification LED\n");
+		return ret_val;
+	}
+
+	/* Disabling VLAN filtering */
+	hw_dbg(hw, "Initializing the IEEE VLAN\n");
+	e1000e_clear_vfta(hw);
+
+	/* Setup the receive address. */
+	e1000e_init_rx_addrs(hw, mac->rar_entry_count);
+
+	/* Zero out the Multicast HASH table */
+	hw_dbg(hw, "Zeroing the MTA\n");
+	for (i = 0; i < mac->mta_reg_count; i++)
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+	/* Setup link and flow control */
+	ret_val = e1000e_setup_link(hw);
+
+	/* Set the transmit descriptor write-back policy */
+	reg_data = er32(TXDCTL);
+	reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+		   E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+	ew32(TXDCTL, reg_data);
+
+	/* ...for both queues. */
+	reg_data = er32(TXDCTL1);
+	reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
+		   E1000_TXDCTL_FULL_TX_DESC_WB | E1000_TXDCTL_COUNT_DESC;
+	ew32(TXDCTL1, reg_data);
+
+	/* Enable retransmit on late collisions */
+	reg_data = er32(TCTL);
+	reg_data |= E1000_TCTL_RTLC;
+	ew32(TCTL, reg_data);
+
+	/* Configure Gigabit Carry Extend Padding */
+	reg_data = er32(TCTL_EXT);
+	reg_data &= ~E1000_TCTL_EXT_GCEX_MASK;
+	reg_data |= DEFAULT_TCTL_EXT_GCEX_80003ES2LAN;
+	ew32(TCTL_EXT, reg_data);
+
+	/* Configure Transmit Inter-Packet Gap */
+	reg_data = er32(TIPG);
+	reg_data &= ~E1000_TIPG_IPGT_MASK;
+	reg_data |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
+	ew32(TIPG, reg_data);
+
+	reg_data = E1000_READ_REG_ARRAY(hw, E1000_FFLT, 0x0001);
+	reg_data &= ~0x00100000;
+	E1000_WRITE_REG_ARRAY(hw, E1000_FFLT, 0x0001, reg_data);
+
+	/* Clear all of the statistics registers (clear on read).  It is
+	 * important that we do this after we have tried to establish link
+	 * because the symbol error count will increment wildly if there
+	 * is no link.
+	 */
+	e1000_clear_hw_cntrs_80003es2lan(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_initialize_hw_bits_80003es2lan - Init hw bits of ESB2
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes required hardware-dependent bits needed for normal operation.
+ **/
+static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw)
+{
+	u32 reg;
+
+	/* Transmit Descriptor Control 0 */
+	reg = er32(TXDCTL);
+	reg |= (1 << 22);
+	ew32(TXDCTL, reg);
+
+	/* Transmit Descriptor Control 1 */
+	reg = er32(TXDCTL1);
+	reg |= (1 << 22);
+	ew32(TXDCTL1, reg);
+
+	/* Transmit Arbitration Control 0 */
+	reg = er32(TARC0);
+	reg &= ~(0xF << 27); /* 30:27 */
+	if (hw->media_type != e1000_media_type_copper)
+		reg &= ~(1 << 20);
+	ew32(TARC0, reg);
+
+	/* Transmit Arbitration Control 1 */
+	reg = er32(TARC1);
+	if (er32(TCTL) & E1000_TCTL_MULR)
+		reg &= ~(1 << 28);
+	else
+		reg |= (1 << 28);
+	ew32(TARC1, reg);
+}
+
+/**
+ *  e1000_copper_link_setup_gg82563_80003es2lan - Configure GG82563 Link
+ *  @hw: pointer to the HW structure
+ *
+ *  Setup some GG82563 PHY registers for obtaining link
+ **/
+static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u32 ctrl_ext;
+	u16 data;
+
+	ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL,
+				     &data);
+	if (ret_val)
+		return ret_val;
+
+	data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
+	/* Use 25MHz for both link down and 1000Base-T for Tx clock. */
+	data |= GG82563_MSCR_TX_CLK_1000MBPS_25;
+
+	ret_val = e1e_wphy(hw, GG82563_PHY_MAC_SPEC_CTRL,
+				      data);
+	if (ret_val)
+		return ret_val;
+
+	/* Options:
+	 *   MDI/MDI-X = 0 (default)
+	 *   0 - Auto for all speeds
+	 *   1 - MDI mode
+	 *   2 - MDI-X mode
+	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+	 */
+	ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL, &data);
+	if (ret_val)
+		return ret_val;
+
+	data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
+
+	switch (phy->mdix) {
+	case 1:
+		data |= GG82563_PSCR_CROSSOVER_MODE_MDI;
+		break;
+	case 2:
+		data |= GG82563_PSCR_CROSSOVER_MODE_MDIX;
+		break;
+	case 0:
+	default:
+		data |= GG82563_PSCR_CROSSOVER_MODE_AUTO;
+		break;
+	}
+
+	/* Options:
+	 *   disable_polarity_correction = 0 (default)
+	 *       Automatic Correction for Reversed Cable Polarity
+	 *   0 - Disabled
+	 *   1 - Enabled
+	 */
+	data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+	if (phy->disable_polarity_correction)
+		data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
+
+	ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL, data);
+	if (ret_val)
+		return ret_val;
+
+	/* SW Reset the PHY so all changes take effect */
+	ret_val = e1000e_commit_phy(hw);
+	if (ret_val) {
+		hw_dbg(hw, "Error Resetting the PHY\n");
+		return ret_val;
+	}
+
+	/* Bypass RX and TX FIFO's */
+	ret_val = e1000e_write_kmrn_reg(hw,
+				E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL,
+				E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS |
+					E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS);
+	if (ret_val)
+		return ret_val;
+
+	ret_val = e1e_rphy(hw, GG82563_PHY_SPEC_CTRL_2, &data);
+	if (ret_val)
+		return ret_val;
+
+	data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG;
+	ret_val = e1e_wphy(hw, GG82563_PHY_SPEC_CTRL_2, data);
+	if (ret_val)
+		return ret_val;
+
+	ctrl_ext = er32(CTRL_EXT);
+	ctrl_ext &= ~(E1000_CTRL_EXT_LINK_MODE_MASK);
+	ew32(CTRL_EXT, ctrl_ext);
+
+	ret_val = e1e_rphy(hw, GG82563_PHY_PWR_MGMT_CTRL, &data);
+	if (ret_val)
+		return ret_val;
+
+	/* Do not init these registers when the HW is in IAMT mode, since the
+	 * firmware will have already initialized them.  We only initialize
+	 * them if the HW is not in IAMT mode.
+	 */
+	if (!e1000e_check_mng_mode(hw)) {
+		/* Enable Electrical Idle on the PHY */
+		data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE;
+		ret_val = e1e_wphy(hw, GG82563_PHY_PWR_MGMT_CTRL, data);
+		if (ret_val)
+			return ret_val;
+
+		ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &data);
+		if (ret_val)
+			return ret_val;
+
+		data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+		ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, data);
+		if (ret_val)
+			return ret_val;
+	}
+
+	/* Workaround: Disable padding in Kumeran interface in the MAC
+	 * and in the PHY to avoid CRC errors.
+	 */
+	ret_val = e1e_rphy(hw, GG82563_PHY_INBAND_CTRL, &data);
+	if (ret_val)
+		return ret_val;
+
+	data |= GG82563_ICR_DIS_PADDING;
+	ret_val = e1e_wphy(hw, GG82563_PHY_INBAND_CTRL, data);
+	if (ret_val)
+		return ret_val;
+
+	return 0;
+}
+
+/**
+ *  e1000_setup_copper_link_80003es2lan - Setup Copper Link for ESB2
+ *  @hw: pointer to the HW structure
+ *
+ *  Essentially a wrapper for setting up all things "copper" related.
+ *  This is a function pointer entry point called by the mac module.
+ **/
+static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val;
+	u16 reg_data;
+
+	ctrl = er32(CTRL);
+	ctrl |= E1000_CTRL_SLU;
+	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	ew32(CTRL, ctrl);
+
+	/* Set the mac to wait the maximum time between each
+	 * iteration and increase the max iterations when
+	 * polling the phy; this fixes erroneous timeouts at 10Mbps. */
+	ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF);
+	if (ret_val)
+		return ret_val;
+	ret_val = e1000e_read_kmrn_reg(hw, GG82563_REG(0x34, 9), &reg_data);
+	if (ret_val)
+		return ret_val;
+	reg_data |= 0x3F;
+	ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data);
+	if (ret_val)
+		return ret_val;
+	ret_val = e1000e_read_kmrn_reg(hw,
+				      E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+				      &reg_data);
+	if (ret_val)
+		return ret_val;
+	reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING;
+	ret_val = e1000e_write_kmrn_reg(hw,
+				       E1000_KMRNCTRLSTA_OFFSET_INB_CTRL,
+				       reg_data);
+	if (ret_val)
+		return ret_val;
+
+	ret_val = e1000_copper_link_setup_gg82563_80003es2lan(hw);
+	if (ret_val)
+		return ret_val;
+
+	ret_val = e1000e_setup_copper_link(hw);
+
+	return 0;
+}
+
+/**
+ *  e1000_cfg_kmrn_10_100_80003es2lan - Apply "quirks" for 10/100 operation
+ *  @hw: pointer to the HW structure
+ *  @duplex: current duplex setting
+ *
+ *  Configure the KMRN interface by applying last minute quirks for
+ *  10/100 operation.
+ **/
+static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex)
+{
+	s32 ret_val;
+	u32 tipg;
+	u16 reg_data;
+
+	reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT;
+	ret_val = e1000e_write_kmrn_reg(hw,
+				       E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+				       reg_data);
+	if (ret_val)
+		return ret_val;
+
+	/* Configure Transmit Inter-Packet Gap */
+	tipg = er32(TIPG);
+	tipg &= ~E1000_TIPG_IPGT_MASK;
+	tipg |= DEFAULT_TIPG_IPGT_10_100_80003ES2LAN;
+	ew32(TIPG, tipg);
+
+	ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+	if (ret_val)
+		return ret_val;
+
+	if (duplex == HALF_DUPLEX)
+		reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
+	else
+		reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+
+	ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+	return 0;
+}
+
+/**
+ *  e1000_cfg_kmrn_1000_80003es2lan - Apply "quirks" for gigabit operation
+ *  @hw: pointer to the HW structure
+ *
+ *  Configure the KMRN interface by applying last minute quirks for
+ *  gigabit operation.
+ **/
+static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw)
+{
+	s32 ret_val;
+	u16 reg_data;
+	u32 tipg;
+
+	reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT;
+	ret_val = e1000e_write_kmrn_reg(hw,
+				       E1000_KMRNCTRLSTA_OFFSET_HD_CTRL,
+				       reg_data);
+	if (ret_val)
+		return ret_val;
+
+	/* Configure Transmit Inter-Packet Gap */
+	tipg = er32(TIPG);
+	tipg &= ~E1000_TIPG_IPGT_MASK;
+	tipg |= DEFAULT_TIPG_IPGT_1000_80003ES2LAN;
+	ew32(TIPG, tipg);
+
+	ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+	if (ret_val)
+		return ret_val;
+
+	reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+	ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the hardware counters by reading the counter registers.
+ **/
+static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
+{
+	u32 temp;
+
+	e1000e_clear_hw_cntrs_base(hw);
+
+	temp = er32(PRC64);
+	temp = er32(PRC127);
+	temp = er32(PRC255);
+	temp = er32(PRC511);
+	temp = er32(PRC1023);
+	temp = er32(PRC1522);
+	temp = er32(PTC64);
+	temp = er32(PTC127);
+	temp = er32(PTC255);
+	temp = er32(PTC511);
+	temp = er32(PTC1023);
+	temp = er32(PTC1522);
+
+	temp = er32(ALGNERRC);
+	temp = er32(RXERRC);
+	temp = er32(TNCRS);
+	temp = er32(CEXTERR);
+	temp = er32(TSCTC);
+	temp = er32(TSCTFC);
+
+	temp = er32(MGTPRC);
+	temp = er32(MGTPDC);
+	temp = er32(MGTPTC);
+
+	temp = er32(IAC);
+	temp = er32(ICRXOC);
+
+	temp = er32(ICRXPTC);
+	temp = er32(ICRXATC);
+	temp = er32(ICTXPTC);
+	temp = er32(ICTXATC);
+	temp = er32(ICTXQEC);
+	temp = er32(ICTXQMTC);
+	temp = er32(ICRXDMTC);
+}
+
+static struct e1000_mac_operations es2_mac_ops = {
+	.mng_mode_enab		= E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
+	/* check_for_link dependent on media type */
+	.cleanup_led		= e1000e_cleanup_led_generic,
+	.clear_hw_cntrs		= e1000_clear_hw_cntrs_80003es2lan,
+	.get_bus_info		= e1000e_get_bus_info_pcie,
+	.get_link_up_info	= e1000_get_link_up_info_80003es2lan,
+	.led_on			= e1000e_led_on_generic,
+	.led_off		= e1000e_led_off_generic,
+	.mc_addr_list_update	= e1000e_mc_addr_list_update_generic,
+	.reset_hw		= e1000_reset_hw_80003es2lan,
+	.init_hw		= e1000_init_hw_80003es2lan,
+	.setup_link		= e1000e_setup_link,
+	/* setup_physical_interface dependent on media type */
+};
+
+static struct e1000_phy_operations es2_phy_ops = {
+	.acquire_phy		= e1000_acquire_phy_80003es2lan,
+	.check_reset_block	= e1000e_check_reset_block_generic,
+	.commit_phy	 	= e1000e_phy_sw_reset,
+	.force_speed_duplex 	= e1000_phy_force_speed_duplex_80003es2lan,
+	.get_cfg_done       	= e1000_get_cfg_done_80003es2lan,
+	.get_cable_length   	= e1000_get_cable_length_80003es2lan,
+	.get_phy_info       	= e1000e_get_phy_info_m88,
+	.read_phy_reg       	= e1000_read_phy_reg_gg82563_80003es2lan,
+	.release_phy		= e1000_release_phy_80003es2lan,
+	.reset_phy	  	= e1000e_phy_hw_reset_generic,
+	.set_d0_lplu_state  	= NULL,
+	.set_d3_lplu_state  	= e1000e_set_d3_lplu_state,
+	.write_phy_reg      	= e1000_write_phy_reg_gg82563_80003es2lan,
+};
+
+static struct e1000_nvm_operations es2_nvm_ops = {
+	.acquire_nvm		= e1000_acquire_nvm_80003es2lan,
+	.read_nvm		= e1000e_read_nvm_eerd,
+	.release_nvm		= e1000_release_nvm_80003es2lan,
+	.update_nvm		= e1000e_update_nvm_checksum_generic,
+	.valid_led_default	= e1000e_valid_led_default,
+	.validate_nvm		= e1000e_validate_nvm_checksum_generic,
+	.write_nvm		= e1000_write_nvm_80003es2lan,
+};
+
+struct e1000_info e1000_es2_info = {
+	.mac			= e1000_80003es2lan,
+	.flags			= FLAG_HAS_HW_VLAN_FILTER
+				  | FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_HAS_STATS_PTC_PRC
+				  | FLAG_HAS_WOL
+				  | FLAG_APME_IN_CTRL3
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_HAS_STATS_ICR_ICT
+				  | FLAG_RX_NEEDS_RESTART /* errata */
+				  | FLAG_TARC_SET_BIT_ZERO /* errata */
+				  | FLAG_APME_CHECK_PORT_B
+				  | FLAG_DISABLE_FC_PAUSE_TIME /* errata */
+				  | FLAG_TIPG_MEDIUM_FOR_80003ESLAN,
+	.pba			= 38,
+	.get_invariants		= e1000_get_invariants_80003es2lan,
+	.mac_ops		= &es2_mac_ops,
+	.phy_ops		= &es2_phy_ops,
+	.nvm_ops		= &es2_nvm_ops,
+};
+
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
new file mode 100644
index 0000000..b7a7e2a
--- /dev/null
+++ b/drivers/net/e1000e/ethtool.c
@@ -0,0 +1,1780 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* ethtool support for e1000 */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "e1000.h"
+
+struct e1000_stats {
+	char stat_string[ETH_GSTRING_LEN];
+	int sizeof_stat;
+	int stat_offset;
+};
+
+#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \
+		      offsetof(struct e1000_adapter, m)
+static const struct e1000_stats e1000_gstrings_stats[] = {
+	{ "rx_packets", E1000_STAT(stats.gprc) },
+	{ "tx_packets", E1000_STAT(stats.gptc) },
+	{ "rx_bytes", E1000_STAT(stats.gorcl) },
+	{ "tx_bytes", E1000_STAT(stats.gotcl) },
+	{ "rx_broadcast", E1000_STAT(stats.bprc) },
+	{ "tx_broadcast", E1000_STAT(stats.bptc) },
+	{ "rx_multicast", E1000_STAT(stats.mprc) },
+	{ "tx_multicast", E1000_STAT(stats.mptc) },
+	{ "rx_errors", E1000_STAT(net_stats.rx_errors) },
+	{ "tx_errors", E1000_STAT(net_stats.tx_errors) },
+	{ "tx_dropped", E1000_STAT(net_stats.tx_dropped) },
+	{ "multicast", E1000_STAT(stats.mprc) },
+	{ "collisions", E1000_STAT(stats.colc) },
+	{ "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) },
+	{ "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) },
+	{ "rx_crc_errors", E1000_STAT(stats.crcerrs) },
+	{ "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) },
+	{ "rx_no_buffer_count", E1000_STAT(stats.rnbc) },
+	{ "rx_missed_errors", E1000_STAT(stats.mpc) },
+	{ "tx_aborted_errors", E1000_STAT(stats.ecol) },
+	{ "tx_carrier_errors", E1000_STAT(stats.tncrs) },
+	{ "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) },
+	{ "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) },
+	{ "tx_window_errors", E1000_STAT(stats.latecol) },
+	{ "tx_abort_late_coll", E1000_STAT(stats.latecol) },
+	{ "tx_deferred_ok", E1000_STAT(stats.dc) },
+	{ "tx_single_coll_ok", E1000_STAT(stats.scc) },
+	{ "tx_multi_coll_ok", E1000_STAT(stats.mcc) },
+	{ "tx_timeout_count", E1000_STAT(tx_timeout_count) },
+	{ "tx_restart_queue", E1000_STAT(restart_queue) },
+	{ "rx_long_length_errors", E1000_STAT(stats.roc) },
+	{ "rx_short_length_errors", E1000_STAT(stats.ruc) },
+	{ "rx_align_errors", E1000_STAT(stats.algnerrc) },
+	{ "tx_tcp_seg_good", E1000_STAT(stats.tsctc) },
+	{ "tx_tcp_seg_failed", E1000_STAT(stats.tsctfc) },
+	{ "rx_flow_control_xon", E1000_STAT(stats.xonrxc) },
+	{ "rx_flow_control_xoff", E1000_STAT(stats.xoffrxc) },
+	{ "tx_flow_control_xon", E1000_STAT(stats.xontxc) },
+	{ "tx_flow_control_xoff", E1000_STAT(stats.xofftxc) },
+	{ "rx_long_byte_count", E1000_STAT(stats.gorcl) },
+	{ "rx_csum_offload_good", E1000_STAT(hw_csum_good) },
+	{ "rx_csum_offload_errors", E1000_STAT(hw_csum_err) },
+	{ "rx_header_split", E1000_STAT(rx_hdr_split) },
+	{ "alloc_rx_buff_failed", E1000_STAT(alloc_rx_buff_failed) },
+	{ "tx_smbus", E1000_STAT(stats.mgptc) },
+	{ "rx_smbus", E1000_STAT(stats.mgprc) },
+	{ "dropped_smbus", E1000_STAT(stats.mgpdc) },
+	{ "rx_dma_failed", E1000_STAT(rx_dma_failed) },
+	{ "tx_dma_failed", E1000_STAT(tx_dma_failed) },
+};
+
+#define E1000_GLOBAL_STATS_LEN	\
+	sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats)
+#define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN)
+static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
+	"Register test  (offline)", "Eeprom test    (offline)",
+	"Interrupt test (offline)", "Loopback test  (offline)",
+	"Link test   (on/offline)"
+};
+#define E1000_TEST_LEN sizeof(e1000_gstrings_test) / ETH_GSTRING_LEN
+
+static int e1000_get_settings(struct net_device *netdev,
+			      struct ethtool_cmd *ecmd)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	if (hw->media_type == e1000_media_type_copper) {
+
+		ecmd->supported = (SUPPORTED_10baseT_Half |
+				   SUPPORTED_10baseT_Full |
+				   SUPPORTED_100baseT_Half |
+				   SUPPORTED_100baseT_Full |
+				   SUPPORTED_1000baseT_Full |
+				   SUPPORTED_Autoneg |
+				   SUPPORTED_TP);
+		if (hw->phy.type == e1000_phy_ife)
+			ecmd->supported &= ~SUPPORTED_1000baseT_Full;
+		ecmd->advertising = ADVERTISED_TP;
+
+		if (hw->mac.autoneg == 1) {
+			ecmd->advertising |= ADVERTISED_Autoneg;
+			/* the e1000 autoneg seems to match ethtool nicely */
+			ecmd->advertising |= hw->phy.autoneg_advertised;
+		}
+
+		ecmd->port = PORT_TP;
+		ecmd->phy_address = hw->phy.addr;
+		ecmd->transceiver = XCVR_INTERNAL;
+
+	} else {
+		ecmd->supported   = (SUPPORTED_1000baseT_Full |
+				     SUPPORTED_FIBRE |
+				     SUPPORTED_Autoneg);
+
+		ecmd->advertising = (ADVERTISED_1000baseT_Full |
+				     ADVERTISED_FIBRE |
+				     ADVERTISED_Autoneg);
+
+		ecmd->port = PORT_FIBRE;
+		ecmd->transceiver = XCVR_EXTERNAL;
+	}
+
+	if (er32(STATUS) & E1000_STATUS_LU) {
+
+		adapter->hw.mac.ops.get_link_up_info(hw, &adapter->link_speed,
+						  &adapter->link_duplex);
+		ecmd->speed = adapter->link_speed;
+
+		/* unfortunately FULL_DUPLEX != DUPLEX_FULL
+		 *	  and HALF_DUPLEX != DUPLEX_HALF */
+
+		if (adapter->link_duplex == FULL_DUPLEX)
+			ecmd->duplex = DUPLEX_FULL;
+		else
+			ecmd->duplex = DUPLEX_HALF;
+	} else {
+		ecmd->speed = -1;
+		ecmd->duplex = -1;
+	}
+
+	ecmd->autoneg = ((hw->media_type == e1000_media_type_fiber) ||
+			 hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+	return 0;
+}
+
+static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx)
+{
+	struct e1000_mac_info *mac = &adapter->hw.mac;
+
+	mac->autoneg = 0;
+
+	/* Fiber NICs only allow 1000 gbps Full duplex */
+	if ((adapter->hw.media_type == e1000_media_type_fiber) &&
+		spddplx != (SPEED_1000 + DUPLEX_FULL)) {
+		ndev_err(adapter->netdev, "Unsupported Speed/Duplex "
+			 "configuration\n");
+		return -EINVAL;
+	}
+
+	switch (spddplx) {
+	case SPEED_10 + DUPLEX_HALF:
+		mac->forced_speed_duplex = ADVERTISE_10_HALF;
+		break;
+	case SPEED_10 + DUPLEX_FULL:
+		mac->forced_speed_duplex = ADVERTISE_10_FULL;
+		break;
+	case SPEED_100 + DUPLEX_HALF:
+		mac->forced_speed_duplex = ADVERTISE_100_HALF;
+		break;
+	case SPEED_100 + DUPLEX_FULL:
+		mac->forced_speed_duplex = ADVERTISE_100_FULL;
+		break;
+	case SPEED_1000 + DUPLEX_FULL:
+		mac->autoneg = 1;
+		adapter->hw.phy.autoneg_advertised = ADVERTISE_1000_FULL;
+		break;
+	case SPEED_1000 + DUPLEX_HALF: /* not supported */
+	default:
+		ndev_err(adapter->netdev, "Unsupported Speed/Duplex "
+			 "configuration\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int e1000_set_settings(struct net_device *netdev,
+			      struct ethtool_cmd *ecmd)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	/* When SoL/IDER sessions are active, autoneg/speed/duplex
+	 * cannot be changed */
+	if (e1000_check_reset_block(hw)) {
+		ndev_err(netdev, "Cannot change link "
+			 "characteristics when SoL/IDER is active.\n");
+		return -EINVAL;
+	}
+
+	while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
+		msleep(1);
+
+	if (ecmd->autoneg == AUTONEG_ENABLE) {
+		hw->mac.autoneg = 1;
+		if (hw->media_type == e1000_media_type_fiber)
+			hw->phy.autoneg_advertised = ADVERTISED_1000baseT_Full |
+						     ADVERTISED_FIBRE |
+						     ADVERTISED_Autoneg;
+		else
+			hw->phy.autoneg_advertised = ecmd->advertising |
+						     ADVERTISED_TP |
+						     ADVERTISED_Autoneg;
+		ecmd->advertising = hw->phy.autoneg_advertised;
+	} else {
+		if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) {
+			clear_bit(__E1000_RESETTING, &adapter->state);
+			return -EINVAL;
+		}
+	}
+
+	/* reset the link */
+
+	if (netif_running(adapter->netdev)) {
+		e1000e_down(adapter);
+		e1000e_up(adapter);
+	} else {
+		e1000e_reset(adapter);
+	}
+
+	clear_bit(__E1000_RESETTING, &adapter->state);
+	return 0;
+}
+
+static void e1000_get_pauseparam(struct net_device *netdev,
+				 struct ethtool_pauseparam *pause)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	pause->autoneg =
+		(adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
+
+	if (hw->mac.fc == e1000_fc_rx_pause) {
+		pause->rx_pause = 1;
+	} else if (hw->mac.fc == e1000_fc_tx_pause) {
+		pause->tx_pause = 1;
+	} else if (hw->mac.fc == e1000_fc_full) {
+		pause->rx_pause = 1;
+		pause->tx_pause = 1;
+	}
+}
+
+static int e1000_set_pauseparam(struct net_device *netdev,
+				struct ethtool_pauseparam *pause)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	int retval = 0;
+
+	adapter->fc_autoneg = pause->autoneg;
+
+	while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
+		msleep(1);
+
+	if (pause->rx_pause && pause->tx_pause)
+		hw->mac.fc = e1000_fc_full;
+	else if (pause->rx_pause && !pause->tx_pause)
+		hw->mac.fc = e1000_fc_rx_pause;
+	else if (!pause->rx_pause && pause->tx_pause)
+		hw->mac.fc = e1000_fc_tx_pause;
+	else if (!pause->rx_pause && !pause->tx_pause)
+		hw->mac.fc = e1000_fc_none;
+
+	hw->mac.original_fc = hw->mac.fc;
+
+	if (adapter->fc_autoneg == AUTONEG_ENABLE) {
+		hw->mac.fc = e1000_fc_default;
+		if (netif_running(adapter->netdev)) {
+			e1000e_down(adapter);
+			e1000e_up(adapter);
+		} else {
+			e1000e_reset(adapter);
+		}
+	} else {
+		retval = ((hw->media_type == e1000_media_type_fiber) ?
+			  hw->mac.ops.setup_link(hw) : e1000e_force_mac_fc(hw));
+	}
+
+	clear_bit(__E1000_RESETTING, &adapter->state);
+	return retval;
+}
+
+static u32 e1000_get_rx_csum(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	return (adapter->flags & FLAG_RX_CSUM_ENABLED);
+}
+
+static int e1000_set_rx_csum(struct net_device *netdev, u32 data)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	if (data)
+		adapter->flags |= FLAG_RX_CSUM_ENABLED;
+	else
+		adapter->flags &= ~FLAG_RX_CSUM_ENABLED;
+
+	if (netif_running(netdev))
+		e1000e_reinit_locked(adapter);
+	else
+		e1000e_reset(adapter);
+	return 0;
+}
+
+static u32 e1000_get_tx_csum(struct net_device *netdev)
+{
+	return ((netdev->features & NETIF_F_HW_CSUM) != 0);
+}
+
+static int e1000_set_tx_csum(struct net_device *netdev, u32 data)
+{
+	if (data)
+		netdev->features |= NETIF_F_HW_CSUM;
+	else
+		netdev->features &= ~NETIF_F_HW_CSUM;
+
+	return 0;
+}
+
+static int e1000_set_tso(struct net_device *netdev, u32 data)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	if (data) {
+		netdev->features |= NETIF_F_TSO;
+		netdev->features |= NETIF_F_TSO6;
+	} else {
+		netdev->features &= ~NETIF_F_TSO;
+		netdev->features &= ~NETIF_F_TSO6;
+	}
+
+	ndev_info(netdev, "TSO is %s\n",
+		  data ? "Enabled" : "Disabled");
+	adapter->flags |= FLAG_TSO_FORCE;
+	return 0;
+}
+
+static u32 e1000_get_msglevel(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	return adapter->msg_enable;
+}
+
+static void e1000_set_msglevel(struct net_device *netdev, u32 data)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	adapter->msg_enable = data;
+}
+
+static int e1000_get_regs_len(struct net_device *netdev)
+{
+#define E1000_REGS_LEN 32 /* overestimate */
+	return E1000_REGS_LEN * sizeof(u32);
+}
+
+static void e1000_get_regs(struct net_device *netdev,
+			   struct ethtool_regs *regs, void *p)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 *regs_buff = p;
+	u16 phy_data;
+	u8 revision_id;
+
+	memset(p, 0, E1000_REGS_LEN * sizeof(u32));
+
+	pci_read_config_byte(adapter->pdev, PCI_REVISION_ID, &revision_id);
+
+	regs->version = (1 << 24) | (revision_id << 16) | adapter->pdev->device;
+
+	regs_buff[0]  = er32(CTRL);
+	regs_buff[1]  = er32(STATUS);
+
+	regs_buff[2]  = er32(RCTL);
+	regs_buff[3]  = er32(RDLEN);
+	regs_buff[4]  = er32(RDH);
+	regs_buff[5]  = er32(RDT);
+	regs_buff[6]  = er32(RDTR);
+
+	regs_buff[7]  = er32(TCTL);
+	regs_buff[8]  = er32(TDLEN);
+	regs_buff[9]  = er32(TDH);
+	regs_buff[10] = er32(TDT);
+	regs_buff[11] = er32(TIDV);
+
+	regs_buff[12] = adapter->hw.phy.type;  /* PHY type (IGP=1, M88=0) */
+	if (hw->phy.type == e1000_phy_m88) {
+		e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+		regs_buff[13] = (u32)phy_data; /* cable length */
+		regs_buff[14] = 0;  /* Dummy (to align w/ IGP phy reg dump) */
+		regs_buff[15] = 0;  /* Dummy (to align w/ IGP phy reg dump) */
+		regs_buff[16] = 0;  /* Dummy (to align w/ IGP phy reg dump) */
+		e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+		regs_buff[17] = (u32)phy_data; /* extended 10bt distance */
+		regs_buff[18] = regs_buff[13]; /* cable polarity */
+		regs_buff[19] = 0;  /* Dummy (to align w/ IGP phy reg dump) */
+		regs_buff[20] = regs_buff[17]; /* polarity correction */
+		/* phy receive errors */
+		regs_buff[22] = adapter->phy_stats.receive_errors;
+		regs_buff[23] = regs_buff[13]; /* mdix mode */
+	}
+	regs_buff[21] = adapter->phy_stats.idle_errors;  /* phy idle errors */
+	e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);
+	regs_buff[24] = (u32)phy_data;  /* phy local receiver status */
+	regs_buff[25] = regs_buff[24];  /* phy remote receiver status */
+}
+
+static int e1000_get_eeprom_len(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	return adapter->hw.nvm.word_size * 2;
+}
+
+static int e1000_get_eeprom(struct net_device *netdev,
+			    struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u16 *eeprom_buff;
+	int first_word;
+	int last_word;
+	int ret_val = 0;
+	u16 i;
+
+	if (eeprom->len == 0)
+		return -EINVAL;
+
+	eeprom->magic = adapter->pdev->vendor | (adapter->pdev->device << 16);
+
+	first_word = eeprom->offset >> 1;
+	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+
+	eeprom_buff = kmalloc(sizeof(u16) *
+			(last_word - first_word + 1), GFP_KERNEL);
+	if (!eeprom_buff)
+		return -ENOMEM;
+
+	if (hw->nvm.type == e1000_nvm_eeprom_spi) {
+		ret_val = e1000_read_nvm(hw, first_word,
+					 last_word - first_word + 1,
+					 eeprom_buff);
+	} else {
+		for (i = 0; i < last_word - first_word + 1; i++) {
+			ret_val = e1000_read_nvm(hw, first_word + i, 1,
+						      &eeprom_buff[i]);
+			if (ret_val)
+				break;
+		}
+	}
+
+	/* Device's eeprom is always little-endian, word addressable */
+	for (i = 0; i < last_word - first_word + 1; i++)
+		le16_to_cpus(&eeprom_buff[i]);
+
+	memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
+	kfree(eeprom_buff);
+
+	return ret_val;
+}
+
+static int e1000_set_eeprom(struct net_device *netdev,
+			    struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u16 *eeprom_buff;
+	void *ptr;
+	int max_len;
+	int first_word;
+	int last_word;
+	int ret_val = 0;
+	u16 i;
+
+	if (eeprom->len == 0)
+		return -EOPNOTSUPP;
+
+	if (eeprom->magic != (adapter->pdev->vendor | (adapter->pdev->device << 16)))
+		return -EFAULT;
+
+	max_len = hw->nvm.word_size * 2;
+
+	first_word = eeprom->offset >> 1;
+	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+	eeprom_buff = kmalloc(max_len, GFP_KERNEL);
+	if (!eeprom_buff)
+		return -ENOMEM;
+
+	ptr = (void *)eeprom_buff;
+
+	if (eeprom->offset & 1) {
+		/* need read/modify/write of first changed EEPROM word */
+		/* only the second byte of the word is being modified */
+		ret_val = e1000_read_nvm(hw, first_word, 1, &eeprom_buff[0]);
+		ptr++;
+	}
+	if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0))
+		/* need read/modify/write of last changed EEPROM word */
+		/* only the first byte of the word is being modified */
+		ret_val = e1000_read_nvm(hw, last_word, 1,
+				  &eeprom_buff[last_word - first_word]);
+
+	/* Device's eeprom is always little-endian, word addressable */
+	for (i = 0; i < last_word - first_word + 1; i++)
+		le16_to_cpus(&eeprom_buff[i]);
+
+	memcpy(ptr, bytes, eeprom->len);
+
+	for (i = 0; i < last_word - first_word + 1; i++)
+		eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]);
+
+	ret_val = e1000_write_nvm(hw, first_word,
+				  last_word - first_word + 1, eeprom_buff);
+
+	/* Update the checksum over the first part of the EEPROM if needed
+	 * and flush shadow RAM for 82573 controllers */
+	if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) ||
+			       (hw->mac.type == e1000_82573)))
+		e1000e_update_nvm_checksum(hw);
+
+	kfree(eeprom_buff);
+	return ret_val;
+}
+
+static void e1000_get_drvinfo(struct net_device *netdev,
+			      struct ethtool_drvinfo *drvinfo)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	char firmware_version[32];
+	u16 eeprom_data;
+
+	strncpy(drvinfo->driver,  e1000e_driver_name, 32);
+	strncpy(drvinfo->version, e1000e_driver_version, 32);
+
+	/* EEPROM image version # is reported as firmware version # for
+	 * PCI-E controllers */
+	e1000_read_nvm(&adapter->hw, 5, 1, &eeprom_data);
+	sprintf(firmware_version, "%d.%d-%d",
+		(eeprom_data & 0xF000) >> 12,
+		(eeprom_data & 0x0FF0) >> 4,
+		eeprom_data & 0x000F);
+
+	strncpy(drvinfo->fw_version, firmware_version, 32);
+	strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+	drvinfo->regdump_len = e1000_get_regs_len(netdev);
+	drvinfo->eedump_len = e1000_get_eeprom_len(netdev);
+}
+
+static void e1000_get_ringparam(struct net_device *netdev,
+				struct ethtool_ringparam *ring)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+
+	ring->rx_max_pending = E1000_MAX_RXD;
+	ring->tx_max_pending = E1000_MAX_TXD;
+	ring->rx_mini_max_pending = 0;
+	ring->rx_jumbo_max_pending = 0;
+	ring->rx_pending = rx_ring->count;
+	ring->tx_pending = tx_ring->count;
+	ring->rx_mini_pending = 0;
+	ring->rx_jumbo_pending = 0;
+}
+
+static int e1000_set_ringparam(struct net_device *netdev,
+			       struct ethtool_ringparam *ring)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_ring *tx_ring, *tx_old;
+	struct e1000_ring *rx_ring, *rx_old;
+	int err;
+
+	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+		return -EINVAL;
+
+	while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
+		msleep(1);
+
+	if (netif_running(adapter->netdev))
+		e1000e_down(adapter);
+
+	tx_old = adapter->tx_ring;
+	rx_old = adapter->rx_ring;
+
+	err = -ENOMEM;
+	tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+	if (!tx_ring)
+		goto err_alloc_tx;
+
+	rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+	if (!rx_ring)
+		goto err_alloc_rx;
+
+	adapter->tx_ring = tx_ring;
+	adapter->rx_ring = rx_ring;
+
+	rx_ring->count = max(ring->rx_pending, (u32)E1000_MIN_RXD);
+	rx_ring->count = min(rx_ring->count, (u32)(E1000_MAX_RXD));
+	rx_ring->count = ALIGN(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE);
+
+	tx_ring->count = max(ring->tx_pending, (u32)E1000_MIN_TXD);
+	tx_ring->count = min(tx_ring->count, (u32)(E1000_MAX_TXD));
+	tx_ring->count = ALIGN(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE);
+
+	if (netif_running(adapter->netdev)) {
+		/* Try to get new resources before deleting old */
+		err = e1000e_setup_rx_resources(adapter);
+		if (err)
+			goto err_setup_rx;
+		err = e1000e_setup_tx_resources(adapter);
+		if (err)
+			goto err_setup_tx;
+
+		/* save the new, restore the old in order to free it,
+		 * then restore the new back again */
+		adapter->rx_ring = rx_old;
+		adapter->tx_ring = tx_old;
+		e1000e_free_rx_resources(adapter);
+		e1000e_free_tx_resources(adapter);
+		kfree(tx_old);
+		kfree(rx_old);
+		adapter->rx_ring = rx_ring;
+		adapter->tx_ring = tx_ring;
+		err = e1000e_up(adapter);
+		if (err)
+			goto err_setup;
+	}
+
+	clear_bit(__E1000_RESETTING, &adapter->state);
+	return 0;
+err_setup_tx:
+	e1000e_free_rx_resources(adapter);
+err_setup_rx:
+	adapter->rx_ring = rx_old;
+	adapter->tx_ring = tx_old;
+	kfree(rx_ring);
+err_alloc_rx:
+	kfree(tx_ring);
+err_alloc_tx:
+	e1000e_up(adapter);
+err_setup:
+	clear_bit(__E1000_RESETTING, &adapter->state);
+	return err;
+}
+
+#define REG_PATTERN_TEST(R, M, W) REG_PATTERN_TEST_ARRAY(R, 0, M, W)
+#define REG_PATTERN_TEST_ARRAY(reg, offset, mask, writeable)		      \
+{									      \
+	u32 _pat;							      \
+	u32 _value;							      \
+	u32 _test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};	      \
+	for (_pat = 0; _pat < ARRAY_SIZE(_test); _pat++) {		      \
+		E1000_WRITE_REG_ARRAY(hw, reg, offset,	      \
+				      (_test[_pat] & writeable));	      \
+		_value = E1000_READ_REG_ARRAY(hw, reg, offset);     \
+		if (_value != (_test[_pat] & writeable & mask)) {	      \
+			ndev_err(netdev, "pattern test reg %04X "             \
+				 "failed: got 0x%08X expected 0x%08X\n",      \
+				 reg + offset,  \
+				 value, (_test[_pat] & writeable & mask));    \
+			*data = reg;					      \
+			return 1;					      \
+		}							      \
+	}								      \
+}
+
+#define REG_SET_AND_CHECK(R, M, W)					      \
+{									      \
+	u32 _value;							      \
+	__ew32(hw, R, W & M);						\
+	_value = __er32(hw, R);						\
+	if ((W & M) != (_value & M)) {					      \
+		ndev_err(netdev, "set/check reg %04X test failed: "           \
+			 "got 0x%08X expected 0x%08X\n", R, (_value & M),     \
+			 (W & M));					      \
+		*data = R;						      \
+		return 1;						      \
+	}								      \
+}
+
+static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_mac_info *mac = &adapter->hw.mac;
+	struct net_device *netdev = adapter->netdev;
+	u32 value;
+	u32 before;
+	u32 after;
+	u32 i;
+	u32 toggle;
+
+	/* The status register is Read Only, so a write should fail.
+	 * Some bits that get toggled are ignored.
+	 */
+	switch (mac->type) {
+	/* there are several bits on newer hardware that are r/w */
+	case e1000_82571:
+	case e1000_82572:
+	case e1000_80003es2lan:
+		toggle = 0x7FFFF3FF;
+		break;
+	case e1000_82573:
+	case e1000_ich8lan:
+	case e1000_ich9lan:
+		toggle = 0x7FFFF033;
+		break;
+	default:
+		toggle = 0xFFFFF833;
+		break;
+	}
+
+	before = er32(STATUS);
+	value = (er32(STATUS) & toggle);
+	ew32(STATUS, toggle);
+	after = er32(STATUS) & toggle;
+	if (value != after) {
+		ndev_err(netdev, "failed STATUS register test got: "
+			 "0x%08X expected: 0x%08X\n", after, value);
+		*data = 1;
+		return 1;
+	}
+	/* restore previous status */
+	ew32(STATUS, before);
+
+	if ((mac->type != e1000_ich8lan) &&
+	    (mac->type != e1000_ich9lan)) {
+		REG_PATTERN_TEST(E1000_FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
+		REG_PATTERN_TEST(E1000_FCAH, 0x0000FFFF, 0xFFFFFFFF);
+		REG_PATTERN_TEST(E1000_FCT, 0x0000FFFF, 0xFFFFFFFF);
+		REG_PATTERN_TEST(E1000_VET, 0x0000FFFF, 0xFFFFFFFF);
+	}
+
+	REG_PATTERN_TEST(E1000_RDTR, 0x0000FFFF, 0xFFFFFFFF);
+	REG_PATTERN_TEST(E1000_RDBAH, 0xFFFFFFFF, 0xFFFFFFFF);
+	REG_PATTERN_TEST(E1000_RDLEN, 0x000FFF80, 0x000FFFFF);
+	REG_PATTERN_TEST(E1000_RDH, 0x0000FFFF, 0x0000FFFF);
+	REG_PATTERN_TEST(E1000_RDT, 0x0000FFFF, 0x0000FFFF);
+	REG_PATTERN_TEST(E1000_FCRTH, 0x0000FFF8, 0x0000FFF8);
+	REG_PATTERN_TEST(E1000_FCTTV, 0x0000FFFF, 0x0000FFFF);
+	REG_PATTERN_TEST(E1000_TIPG, 0x3FFFFFFF, 0x3FFFFFFF);
+	REG_PATTERN_TEST(E1000_TDBAH, 0xFFFFFFFF, 0xFFFFFFFF);
+	REG_PATTERN_TEST(E1000_TDLEN, 0x000FFF80, 0x000FFFFF);
+
+	REG_SET_AND_CHECK(E1000_RCTL, 0xFFFFFFFF, 0x00000000);
+
+	before = (((mac->type == e1000_ich8lan) ||
+		   (mac->type == e1000_ich9lan)) ? 0x06C3B33E : 0x06DFB3FE);
+	REG_SET_AND_CHECK(E1000_RCTL, before, 0x003FFFFB);
+	REG_SET_AND_CHECK(E1000_TCTL, 0xFFFFFFFF, 0x00000000);
+
+	REG_SET_AND_CHECK(E1000_RCTL, before, 0xFFFFFFFF);
+	REG_PATTERN_TEST(E1000_RDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
+	if ((mac->type != e1000_ich8lan) &&
+	    (mac->type != e1000_ich9lan))
+		REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF);
+	REG_PATTERN_TEST(E1000_TDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
+	REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF);
+	for (i = 0; i < mac->rar_entry_count; i++)
+		REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1),
+				       0x8003FFFF, 0xFFFFFFFF);
+
+	for (i = 0; i < mac->mta_reg_count; i++)
+		REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF);
+
+	*data = 0;
+	return 0;
+}
+
+static int e1000_eeprom_test(struct e1000_adapter *adapter, u64 *data)
+{
+	u16 temp;
+	u16 checksum = 0;
+	u16 i;
+
+	*data = 0;
+	/* Read and add up the contents of the EEPROM */
+	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
+		if ((e1000_read_nvm(&adapter->hw, i, 1, &temp)) < 0) {
+			*data = 1;
+			break;
+		}
+		checksum += temp;
+	}
+
+	/* If Checksum is not Correct return error else test passed */
+	if ((checksum != (u16) NVM_SUM) && !(*data))
+		*data = 2;
+
+	return *data;
+}
+
+static irqreturn_t e1000_test_intr(int irq, void *data)
+{
+	struct net_device *netdev = (struct net_device *) data;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	adapter->test_icr |= er32(ICR);
+
+	return IRQ_HANDLED;
+}
+
+static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct e1000_hw *hw = &adapter->hw;
+	u32 mask;
+	u32 shared_int = 1;
+	u32 irq = adapter->pdev->irq;
+	int i;
+
+	*data = 0;
+
+	/* NOTE: we don't test MSI interrupts here, yet */
+	/* Hook up test interrupt handler just for this test */
+	if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name,
+			 netdev)) {
+		shared_int = 0;
+	} else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED,
+		 netdev->name, netdev)) {
+		*data = 1;
+		return -1;
+	}
+	ndev_info(netdev, "testing %s interrupt\n",
+		  (shared_int ? "shared" : "unshared"));
+
+	/* Disable all the interrupts */
+	ew32(IMC, 0xFFFFFFFF);
+	msleep(10);
+
+	/* Test each interrupt */
+	for (i = 0; i < 10; i++) {
+
+		if (((adapter->hw.mac.type == e1000_ich8lan) ||
+		     (adapter->hw.mac.type == e1000_ich9lan)) && i == 8)
+			continue;
+
+		/* Interrupt to test */
+		mask = 1 << i;
+
+		if (!shared_int) {
+			/* Disable the interrupt to be reported in
+			 * the cause register and then force the same
+			 * interrupt and see if one gets posted.  If
+			 * an interrupt was posted to the bus, the
+			 * test failed.
+			 */
+			adapter->test_icr = 0;
+			ew32(IMC, mask);
+			ew32(ICS, mask);
+			msleep(10);
+
+			if (adapter->test_icr & mask) {
+				*data = 3;
+				break;
+			}
+		}
+
+		/* Enable the interrupt to be reported in
+		 * the cause register and then force the same
+		 * interrupt and see if one gets posted.  If
+		 * an interrupt was not posted to the bus, the
+		 * test failed.
+		 */
+		adapter->test_icr = 0;
+		ew32(IMS, mask);
+		ew32(ICS, mask);
+		msleep(10);
+
+		if (!(adapter->test_icr & mask)) {
+			*data = 4;
+			break;
+		}
+
+		if (!shared_int) {
+			/* Disable the other interrupts to be reported in
+			 * the cause register and then force the other
+			 * interrupts and see if any get posted.  If
+			 * an interrupt was posted to the bus, the
+			 * test failed.
+			 */
+			adapter->test_icr = 0;
+			ew32(IMC, ~mask & 0x00007FFF);
+			ew32(ICS, ~mask & 0x00007FFF);
+			msleep(10);
+
+			if (adapter->test_icr) {
+				*data = 5;
+				break;
+			}
+		}
+	}
+
+	/* Disable all the interrupts */
+	ew32(IMC, 0xFFFFFFFF);
+	msleep(10);
+
+	/* Unhook test interrupt handler */
+	free_irq(irq, netdev);
+
+	return *data;
+}
+
+static void e1000_free_desc_rings(struct e1000_adapter *adapter)
+{
+	struct e1000_ring *tx_ring = &adapter->test_tx_ring;
+	struct e1000_ring *rx_ring = &adapter->test_rx_ring;
+	struct pci_dev *pdev = adapter->pdev;
+	int i;
+
+	if (tx_ring->desc && tx_ring->buffer_info) {
+		for (i = 0; i < tx_ring->count; i++) {
+			if (tx_ring->buffer_info[i].dma)
+				pci_unmap_single(pdev,
+					tx_ring->buffer_info[i].dma,
+					tx_ring->buffer_info[i].length,
+					PCI_DMA_TODEVICE);
+			if (tx_ring->buffer_info[i].skb)
+				dev_kfree_skb(tx_ring->buffer_info[i].skb);
+		}
+	}
+
+	if (rx_ring->desc && rx_ring->buffer_info) {
+		for (i = 0; i < rx_ring->count; i++) {
+			if (rx_ring->buffer_info[i].dma)
+				pci_unmap_single(pdev,
+					rx_ring->buffer_info[i].dma,
+					2048, PCI_DMA_FROMDEVICE);
+			if (rx_ring->buffer_info[i].skb)
+				dev_kfree_skb(rx_ring->buffer_info[i].skb);
+		}
+	}
+
+	if (tx_ring->desc) {
+		dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc,
+				  tx_ring->dma);
+		tx_ring->desc = NULL;
+	}
+	if (rx_ring->desc) {
+		dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc,
+				  rx_ring->dma);
+		rx_ring->desc = NULL;
+	}
+
+	kfree(tx_ring->buffer_info);
+	tx_ring->buffer_info = NULL;
+	kfree(rx_ring->buffer_info);
+	rx_ring->buffer_info = NULL;
+}
+
+static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
+{
+	struct e1000_ring *tx_ring = &adapter->test_tx_ring;
+	struct e1000_ring *rx_ring = &adapter->test_rx_ring;
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_hw *hw = &adapter->hw;
+	u32 rctl;
+	int size;
+	int i;
+	int ret_val;
+
+	/* Setup Tx descriptor ring and Tx buffers */
+
+	if (!tx_ring->count)
+		tx_ring->count = E1000_DEFAULT_TXD;
+
+	size = tx_ring->count * sizeof(struct e1000_buffer);
+	tx_ring->buffer_info = kmalloc(size, GFP_KERNEL);
+	if (!tx_ring->buffer_info) {
+		ret_val = 1;
+		goto err_nomem;
+	}
+	memset(tx_ring->buffer_info, 0, size);
+
+	tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc);
+	tx_ring->size = ALIGN(tx_ring->size, 4096);
+	tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size,
+					   &tx_ring->dma, GFP_KERNEL);
+	if (!tx_ring->desc) {
+		ret_val = 2;
+		goto err_nomem;
+	}
+	memset(tx_ring->desc, 0, tx_ring->size);
+	tx_ring->next_to_use = 0;
+	tx_ring->next_to_clean = 0;
+
+	ew32(TDBAL,
+			((u64) tx_ring->dma & 0x00000000FFFFFFFF));
+	ew32(TDBAH, ((u64) tx_ring->dma >> 32));
+	ew32(TDLEN,
+			tx_ring->count * sizeof(struct e1000_tx_desc));
+	ew32(TDH, 0);
+	ew32(TDT, 0);
+	ew32(TCTL,
+			E1000_TCTL_PSP | E1000_TCTL_EN |
+			E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT |
+			E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT);
+
+	for (i = 0; i < tx_ring->count; i++) {
+		struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*tx_ring, i);
+		struct sk_buff *skb;
+		unsigned int skb_size = 1024;
+
+		skb = alloc_skb(skb_size, GFP_KERNEL);
+		if (!skb) {
+			ret_val = 3;
+			goto err_nomem;
+		}
+		skb_put(skb, skb_size);
+		tx_ring->buffer_info[i].skb = skb;
+		tx_ring->buffer_info[i].length = skb->len;
+		tx_ring->buffer_info[i].dma =
+			pci_map_single(pdev, skb->data, skb->len,
+				       PCI_DMA_TODEVICE);
+		if (pci_dma_mapping_error(tx_ring->buffer_info[i].dma)) {
+			ret_val = 4;
+			goto err_nomem;
+		}
+		tx_desc->buffer_addr = cpu_to_le64(
+					 tx_ring->buffer_info[i].dma);
+		tx_desc->lower.data = cpu_to_le32(skb->len);
+		tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP |
+						   E1000_TXD_CMD_IFCS |
+						   E1000_TXD_CMD_RPS);
+		tx_desc->upper.data = 0;
+	}
+
+	/* Setup Rx descriptor ring and Rx buffers */
+
+	if (!rx_ring->count)
+		rx_ring->count = E1000_DEFAULT_RXD;
+
+	size = rx_ring->count * sizeof(struct e1000_buffer);
+	rx_ring->buffer_info = kmalloc(size, GFP_KERNEL);
+	if (!rx_ring->buffer_info) {
+		ret_val = 5;
+		goto err_nomem;
+	}
+	memset(rx_ring->buffer_info, 0, size);
+
+	rx_ring->size = rx_ring->count * sizeof(struct e1000_rx_desc);
+	rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size,
+					   &rx_ring->dma, GFP_KERNEL);
+	if (!rx_ring->desc) {
+		ret_val = 6;
+		goto err_nomem;
+	}
+	memset(rx_ring->desc, 0, rx_ring->size);
+	rx_ring->next_to_use = 0;
+	rx_ring->next_to_clean = 0;
+
+	rctl = er32(RCTL);
+	ew32(RCTL, rctl & ~E1000_RCTL_EN);
+	ew32(RDBAL, ((u64) rx_ring->dma & 0xFFFFFFFF));
+	ew32(RDBAH, ((u64) rx_ring->dma >> 32));
+	ew32(RDLEN, rx_ring->size);
+	ew32(RDH, 0);
+	ew32(RDT, 0);
+	rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 |
+		E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+		(adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
+	ew32(RCTL, rctl);
+
+	for (i = 0; i < rx_ring->count; i++) {
+		struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rx_ring, i);
+		struct sk_buff *skb;
+
+		skb = alloc_skb(2048 + NET_IP_ALIGN, GFP_KERNEL);
+		if (!skb) {
+			ret_val = 7;
+			goto err_nomem;
+		}
+		skb_reserve(skb, NET_IP_ALIGN);
+		rx_ring->buffer_info[i].skb = skb;
+		rx_ring->buffer_info[i].dma =
+			pci_map_single(pdev, skb->data, 2048,
+				       PCI_DMA_FROMDEVICE);
+		if (pci_dma_mapping_error(rx_ring->buffer_info[i].dma)) {
+			ret_val = 8;
+			goto err_nomem;
+		}
+		rx_desc->buffer_addr =
+			cpu_to_le64(rx_ring->buffer_info[i].dma);
+		memset(skb->data, 0x00, skb->len);
+	}
+
+	return 0;
+
+err_nomem:
+	e1000_free_desc_rings(adapter);
+	return ret_val;
+}
+
+static void e1000_phy_disable_receiver(struct e1000_adapter *adapter)
+{
+	/* Write out to PHY registers 29 and 30 to disable the Receiver. */
+	e1e_wphy(&adapter->hw, 29, 0x001F);
+	e1e_wphy(&adapter->hw, 30, 0x8FFC);
+	e1e_wphy(&adapter->hw, 29, 0x001A);
+	e1e_wphy(&adapter->hw, 30, 0x8FF0);
+}
+
+static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl_reg = 0;
+	u32 stat_reg = 0;
+
+	adapter->hw.mac.autoneg = 0;
+
+	if (adapter->hw.phy.type == e1000_phy_m88) {
+		/* Auto-MDI/MDIX Off */
+		e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
+		/* reset to update Auto-MDI/MDIX */
+		e1e_wphy(hw, PHY_CONTROL, 0x9140);
+		/* autoneg off */
+		e1e_wphy(hw, PHY_CONTROL, 0x8140);
+	} else if (adapter->hw.phy.type == e1000_phy_gg82563)
+		e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC);
+
+	ctrl_reg = er32(CTRL);
+
+	if (adapter->hw.phy.type == e1000_phy_ife) {
+		/* force 100, set loopback */
+		e1e_wphy(hw, PHY_CONTROL, 0x6100);
+
+		/* Now set up the MAC to the same speed/duplex as the PHY. */
+		ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+		ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+			     E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+			     E1000_CTRL_SPD_100 |/* Force Speed to 100 */
+			     E1000_CTRL_FD);	 /* Force Duplex to FULL */
+	} else {
+		/* force 1000, set loopback */
+		e1e_wphy(hw, PHY_CONTROL, 0x4140);
+
+		/* Now set up the MAC to the same speed/duplex as the PHY. */
+		ctrl_reg = er32(CTRL);
+		ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+		ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+			     E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+			     E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
+			     E1000_CTRL_FD);	 /* Force Duplex to FULL */
+	}
+
+	if (adapter->hw.media_type == e1000_media_type_copper &&
+	   adapter->hw.phy.type == e1000_phy_m88) {
+		ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
+	} else {
+		/* Set the ILOS bit on the fiber Nic if half duplex link is
+		 * detected. */
+		stat_reg = er32(STATUS);
+		if ((stat_reg & E1000_STATUS_FD) == 0)
+			ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU);
+	}
+
+	ew32(CTRL, ctrl_reg);
+
+	/* Disable the receiver on the PHY so when a cable is plugged in, the
+	 * PHY does not begin to autoneg when a cable is reconnected to the NIC.
+	 */
+	if (adapter->hw.phy.type == e1000_phy_m88)
+		e1000_phy_disable_receiver(adapter);
+
+	udelay(500);
+
+	return 0;
+}
+
+static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl = er32(CTRL);
+	int link = 0;
+
+	/* special requirements for 82571/82572 fiber adapters */
+
+	/* jump through hoops to make sure link is up because serdes
+	 * link is hardwired up */
+	ctrl |= E1000_CTRL_SLU;
+	ew32(CTRL, ctrl);
+
+	/* disable autoneg */
+	ctrl = er32(TXCW);
+	ctrl &= ~(1 << 31);
+	ew32(TXCW, ctrl);
+
+	link = (er32(STATUS) & E1000_STATUS_LU);
+
+	if (!link) {
+		/* set invert loss of signal */
+		ctrl = er32(CTRL);
+		ctrl |= E1000_CTRL_ILOS;
+		ew32(CTRL, ctrl);
+	}
+
+	/* special write to serdes control register to enable SerDes analog
+	 * loopback */
+#define E1000_SERDES_LB_ON 0x410
+	ew32(SCTL, E1000_SERDES_LB_ON);
+	msleep(10);
+
+	return 0;
+}
+
+/* only call this for fiber/serdes connections to es2lan */
+static int e1000_set_es2lan_mac_loopback(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrlext = er32(CTRL_EXT);
+	u32 ctrl = er32(CTRL);
+
+	/* save CTRL_EXT to restore later, reuse an empty variable (unused
+	   on mac_type 80003es2lan) */
+	adapter->tx_fifo_head = ctrlext;
+
+	/* clear the serdes mode bits, putting the device into mac loopback */
+	ctrlext &= ~E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES;
+	ew32(CTRL_EXT, ctrlext);
+
+	/* force speed to 1000/FD, link up */
+	ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+	ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX |
+		 E1000_CTRL_SPD_1000 | E1000_CTRL_FD);
+	ew32(CTRL, ctrl);
+
+	/* set mac loopback */
+	ctrl = er32(RCTL);
+	ctrl |= E1000_RCTL_LBM_MAC;
+	ew32(RCTL, ctrl);
+
+	/* set testing mode parameters (no need to reset later) */
+#define KMRNCTRLSTA_OPMODE (0x1F << 16)
+#define KMRNCTRLSTA_OPMODE_1GB_FD_GMII 0x0582
+	ew32(KMRNCTRLSTA,
+		(KMRNCTRLSTA_OPMODE | KMRNCTRLSTA_OPMODE_1GB_FD_GMII));
+
+	return 0;
+}
+
+static int e1000_setup_loopback_test(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 rctl;
+
+	if (hw->media_type == e1000_media_type_fiber ||
+	    hw->media_type == e1000_media_type_internal_serdes) {
+		switch (hw->mac.type) {
+		case e1000_80003es2lan:
+			return e1000_set_es2lan_mac_loopback(adapter);
+			break;
+		case e1000_82571:
+		case e1000_82572:
+			return e1000_set_82571_fiber_loopback(adapter);
+			break;
+		default:
+			rctl = er32(RCTL);
+			rctl |= E1000_RCTL_LBM_TCVR;
+			ew32(RCTL, rctl);
+			return 0;
+		}
+	} else if (hw->media_type == e1000_media_type_copper) {
+		return e1000_integrated_phy_loopback(adapter);
+	}
+
+	return 7;
+}
+
+static void e1000_loopback_cleanup(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 rctl;
+	u16 phy_reg;
+
+	rctl = er32(RCTL);
+	rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
+	ew32(RCTL, rctl);
+
+	switch (hw->mac.type) {
+	case e1000_80003es2lan:
+		if (hw->media_type == e1000_media_type_fiber ||
+		    hw->media_type == e1000_media_type_internal_serdes) {
+			/* restore CTRL_EXT, stealing space from tx_fifo_head */
+			ew32(CTRL_EXT,
+					adapter->tx_fifo_head);
+			adapter->tx_fifo_head = 0;
+		}
+		/* fall through */
+	case e1000_82571:
+	case e1000_82572:
+		if (hw->media_type == e1000_media_type_fiber ||
+		    hw->media_type == e1000_media_type_internal_serdes) {
+#define E1000_SERDES_LB_OFF 0x400
+			ew32(SCTL, E1000_SERDES_LB_OFF);
+			msleep(10);
+			break;
+		}
+		/* Fall Through */
+	default:
+		hw->mac.autoneg = 1;
+		if (hw->phy.type == e1000_phy_gg82563)
+			e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x180);
+		e1e_rphy(hw, PHY_CONTROL, &phy_reg);
+		if (phy_reg & MII_CR_LOOPBACK) {
+			phy_reg &= ~MII_CR_LOOPBACK;
+			e1e_wphy(hw, PHY_CONTROL, phy_reg);
+			e1000e_commit_phy(hw);
+		}
+		break;
+	}
+}
+
+static void e1000_create_lbtest_frame(struct sk_buff *skb,
+				      unsigned int frame_size)
+{
+	memset(skb->data, 0xFF, frame_size);
+	frame_size &= ~1;
+	memset(&skb->data[frame_size / 2], 0xAA, frame_size / 2 - 1);
+	memset(&skb->data[frame_size / 2 + 10], 0xBE, 1);
+	memset(&skb->data[frame_size / 2 + 12], 0xAF, 1);
+}
+
+static int e1000_check_lbtest_frame(struct sk_buff *skb,
+				    unsigned int frame_size)
+{
+	frame_size &= ~1;
+	if (*(skb->data + 3) == 0xFF)
+		if ((*(skb->data + frame_size / 2 + 10) == 0xBE) &&
+		   (*(skb->data + frame_size / 2 + 12) == 0xAF))
+			return 0;
+	return 13;
+}
+
+static int e1000_run_loopback_test(struct e1000_adapter *adapter)
+{
+	struct e1000_ring *tx_ring = &adapter->test_tx_ring;
+	struct e1000_ring *rx_ring = &adapter->test_rx_ring;
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_hw *hw = &adapter->hw;
+	int i, j, k, l;
+	int lc;
+	int good_cnt;
+	int ret_val = 0;
+	unsigned long time;
+
+	ew32(RDT, rx_ring->count - 1);
+
+	/* Calculate the loop count based on the largest descriptor ring
+	 * The idea is to wrap the largest ring a number of times using 64
+	 * send/receive pairs during each loop
+	 */
+
+	if (rx_ring->count <= tx_ring->count)
+		lc = ((tx_ring->count / 64) * 2) + 1;
+	else
+		lc = ((rx_ring->count / 64) * 2) + 1;
+
+	k = 0;
+	l = 0;
+	for (j = 0; j <= lc; j++) { /* loop count loop */
+		for (i = 0; i < 64; i++) { /* send the packets */
+			e1000_create_lbtest_frame(
+				tx_ring->buffer_info[i].skb, 1024);
+			pci_dma_sync_single_for_device(pdev,
+					tx_ring->buffer_info[k].dma,
+					tx_ring->buffer_info[k].length,
+					PCI_DMA_TODEVICE);
+			k++;
+			if (k == tx_ring->count)
+				k = 0;
+		}
+		ew32(TDT, k);
+		msleep(200);
+		time = jiffies; /* set the start time for the receive */
+		good_cnt = 0;
+		do { /* receive the sent packets */
+			pci_dma_sync_single_for_cpu(pdev,
+					rx_ring->buffer_info[l].dma, 2048,
+					PCI_DMA_FROMDEVICE);
+
+			ret_val = e1000_check_lbtest_frame(
+					rx_ring->buffer_info[l].skb, 1024);
+			if (!ret_val)
+				good_cnt++;
+			l++;
+			if (l == rx_ring->count)
+				l = 0;
+			/* time + 20 msecs (200 msecs on 2.4) is more than
+			 * enough time to complete the receives, if it's
+			 * exceeded, break and error off
+			 */
+		} while ((good_cnt < 64) && !time_after(jiffies, time + 20));
+		if (good_cnt != 64) {
+			ret_val = 13; /* ret_val is the same as mis-compare */
+			break;
+		}
+		if (jiffies >= (time + 2)) {
+			ret_val = 14; /* error code for time out error */
+			break;
+		}
+	} /* end loop count loop */
+	return ret_val;
+}
+
+static int e1000_loopback_test(struct e1000_adapter *adapter, u64 *data)
+{
+	/* PHY loopback cannot be performed if SoL/IDER
+	 * sessions are active */
+	if (e1000_check_reset_block(&adapter->hw)) {
+		ndev_err(adapter->netdev, "Cannot do PHY loopback test "
+			 "when SoL/IDER is active.\n");
+		*data = 0;
+		goto out;
+	}
+
+	*data = e1000_setup_desc_rings(adapter);
+	if (data)
+		goto out;
+
+	*data = e1000_setup_loopback_test(adapter);
+	if (data)
+		goto err_loopback;
+
+	*data = e1000_run_loopback_test(adapter);
+	e1000_loopback_cleanup(adapter);
+
+err_loopback:
+	e1000_free_desc_rings(adapter);
+out:
+	return *data;
+}
+
+static int e1000_link_test(struct e1000_adapter *adapter, u64 *data)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	*data = 0;
+	if (hw->media_type == e1000_media_type_internal_serdes) {
+		int i = 0;
+		hw->mac.serdes_has_link = 0;
+
+		/* On some blade server designs, link establishment
+		 * could take as long as 2-3 minutes */
+		do {
+			hw->mac.ops.check_for_link(hw);
+			if (hw->mac.serdes_has_link)
+				return *data;
+			msleep(20);
+		} while (i++ < 3750);
+
+		*data = 1;
+	} else {
+		hw->mac.ops.check_for_link(hw);
+		if (hw->mac.autoneg)
+			msleep(4000);
+
+		if (!(er32(STATUS) &
+		      E1000_STATUS_LU))
+			*data = 1;
+	}
+	return *data;
+}
+
+static int e1000e_get_sset_count(struct net_device *netdev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_TEST:
+		return E1000_TEST_LEN;
+	case ETH_SS_STATS:
+		return E1000_STATS_LEN;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static void e1000_diag_test(struct net_device *netdev,
+			    struct ethtool_test *eth_test, u64 *data)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	u16 autoneg_advertised;
+	u8 forced_speed_duplex;
+	u8 autoneg;
+	bool if_running = netif_running(netdev);
+
+	set_bit(__E1000_TESTING, &adapter->state);
+	if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+		/* Offline tests */
+
+		/* save speed, duplex, autoneg settings */
+		autoneg_advertised = adapter->hw.phy.autoneg_advertised;
+		forced_speed_duplex = adapter->hw.mac.forced_speed_duplex;
+		autoneg = adapter->hw.mac.autoneg;
+
+		ndev_info(netdev, "offline testing starting\n");
+
+		/* Link test performed before hardware reset so autoneg doesn't
+		 * interfere with test result */
+		if (e1000_link_test(adapter, &data[4]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		if (if_running)
+			/* indicate we're in test mode */
+			dev_close(netdev);
+		else
+			e1000e_reset(adapter);
+
+		if (e1000_reg_test(adapter, &data[0]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		e1000e_reset(adapter);
+		if (e1000_eeprom_test(adapter, &data[1]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		e1000e_reset(adapter);
+		if (e1000_intr_test(adapter, &data[2]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		e1000e_reset(adapter);
+		/* make sure the phy is powered up */
+		e1000e_power_up_phy(adapter);
+		if (e1000_loopback_test(adapter, &data[3]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		/* restore speed, duplex, autoneg settings */
+		adapter->hw.phy.autoneg_advertised = autoneg_advertised;
+		adapter->hw.mac.forced_speed_duplex = forced_speed_duplex;
+		adapter->hw.mac.autoneg = autoneg;
+
+		/* force this routine to wait until autoneg complete/timeout */
+		adapter->hw.phy.wait_for_link = 1;
+		e1000e_reset(adapter);
+		adapter->hw.phy.wait_for_link = 0;
+
+		clear_bit(__E1000_TESTING, &adapter->state);
+		if (if_running)
+			dev_open(netdev);
+	} else {
+		ndev_info(netdev, "online testing starting\n");
+		/* Online tests */
+		if (e1000_link_test(adapter, &data[4]))
+			eth_test->flags |= ETH_TEST_FL_FAILED;
+
+		/* Online tests aren't run; pass by default */
+		data[0] = 0;
+		data[1] = 0;
+		data[2] = 0;
+		data[3] = 0;
+
+		clear_bit(__E1000_TESTING, &adapter->state);
+	}
+	msleep_interruptible(4 * 1000);
+}
+
+static void e1000_get_wol(struct net_device *netdev,
+			  struct ethtool_wolinfo *wol)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	wol->supported = 0;
+	wol->wolopts = 0;
+
+	if (!(adapter->flags & FLAG_HAS_WOL))
+		return;
+
+	wol->supported = WAKE_UCAST | WAKE_MCAST |
+			 WAKE_BCAST | WAKE_MAGIC;
+
+	/* apply any specific unsupported masks here */
+	if (adapter->flags & FLAG_NO_WAKE_UCAST) {
+		wol->supported &= ~WAKE_UCAST;
+
+		if (adapter->wol & E1000_WUFC_EX)
+			ndev_err(netdev, "Interface does not support "
+				 "directed (unicast) frame wake-up packets\n");
+	}
+
+	if (adapter->wol & E1000_WUFC_EX)
+		wol->wolopts |= WAKE_UCAST;
+	if (adapter->wol & E1000_WUFC_MC)
+		wol->wolopts |= WAKE_MCAST;
+	if (adapter->wol & E1000_WUFC_BC)
+		wol->wolopts |= WAKE_BCAST;
+	if (adapter->wol & E1000_WUFC_MAG)
+		wol->wolopts |= WAKE_MAGIC;
+}
+
+static int e1000_set_wol(struct net_device *netdev,
+			 struct ethtool_wolinfo *wol)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+		return -EOPNOTSUPP;
+
+	if (!(adapter->flags & FLAG_HAS_WOL))
+		return wol->wolopts ? -EOPNOTSUPP : 0;
+
+	/* these settings will always override what we currently have */
+	adapter->wol = 0;
+
+	if (wol->wolopts & WAKE_UCAST)
+		adapter->wol |= E1000_WUFC_EX;
+	if (wol->wolopts & WAKE_MCAST)
+		adapter->wol |= E1000_WUFC_MC;
+	if (wol->wolopts & WAKE_BCAST)
+		adapter->wol |= E1000_WUFC_BC;
+	if (wol->wolopts & WAKE_MAGIC)
+		adapter->wol |= E1000_WUFC_MAG;
+
+	return 0;
+}
+
+/* toggle LED 4 times per second = 2 "blinks" per second */
+#define E1000_ID_INTERVAL	(HZ/4)
+
+/* bit defines for adapter->led_status */
+#define E1000_LED_ON		0
+
+static void e1000_led_blink_callback(unsigned long data)
+{
+	struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+
+	if (test_and_change_bit(E1000_LED_ON, &adapter->led_status))
+		adapter->hw.mac.ops.led_off(&adapter->hw);
+	else
+		adapter->hw.mac.ops.led_on(&adapter->hw);
+
+	mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL);
+}
+
+static int e1000_phys_id(struct net_device *netdev, u32 data)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
+		data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
+
+	if (adapter->hw.phy.type == e1000_phy_ife) {
+		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;
+		}
+		mod_timer(&adapter->blink_timer, jiffies);
+		msleep_interruptible(data * 1000);
+		del_timer_sync(&adapter->blink_timer);
+		e1e_wphy(&adapter->hw,
+				    IFE_PHY_SPECIAL_CONTROL_LED, 0);
+	} else {
+		e1000e_blink_led(&adapter->hw);
+		msleep_interruptible(data * 1000);
+	}
+
+	adapter->hw.mac.ops.led_off(&adapter->hw);
+	clear_bit(E1000_LED_ON, &adapter->led_status);
+	adapter->hw.mac.ops.cleanup_led(&adapter->hw);
+
+	return 0;
+}
+
+static int e1000_nway_reset(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	if (netif_running(netdev))
+		e1000e_reinit_locked(adapter);
+	return 0;
+}
+
+static void e1000_get_ethtool_stats(struct net_device *netdev,
+				    struct ethtool_stats *stats,
+				    u64 *data)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	int i;
+
+	e1000e_update_stats(adapter);
+	for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
+		char *p = (char *)adapter+e1000_gstrings_stats[i].stat_offset;
+		data[i] = (e1000_gstrings_stats[i].sizeof_stat ==
+			sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+	}
+}
+
+static void e1000_get_strings(struct net_device *netdev, u32 stringset,
+			      u8 *data)
+{
+	u8 *p = data;
+	int i;
+
+	switch (stringset) {
+	case ETH_SS_TEST:
+		memcpy(data, *e1000_gstrings_test,
+			E1000_TEST_LEN*ETH_GSTRING_LEN);
+		break;
+	case ETH_SS_STATS:
+		for (i = 0; i < E1000_GLOBAL_STATS_LEN; i++) {
+			memcpy(p, e1000_gstrings_stats[i].stat_string,
+			       ETH_GSTRING_LEN);
+			p += ETH_GSTRING_LEN;
+		}
+		break;
+	}
+}
+
+static const struct ethtool_ops e1000_ethtool_ops = {
+	.get_settings		= e1000_get_settings,
+	.set_settings		= e1000_set_settings,
+	.get_drvinfo		= e1000_get_drvinfo,
+	.get_regs_len		= e1000_get_regs_len,
+	.get_regs		= e1000_get_regs,
+	.get_wol		= e1000_get_wol,
+	.set_wol		= e1000_set_wol,
+	.get_msglevel		= e1000_get_msglevel,
+	.set_msglevel		= e1000_set_msglevel,
+	.nway_reset		= e1000_nway_reset,
+	.get_link		= ethtool_op_get_link,
+	.get_eeprom_len		= e1000_get_eeprom_len,
+	.get_eeprom		= e1000_get_eeprom,
+	.set_eeprom		= e1000_set_eeprom,
+	.get_ringparam		= e1000_get_ringparam,
+	.set_ringparam		= e1000_set_ringparam,
+	.get_pauseparam		= e1000_get_pauseparam,
+	.set_pauseparam		= e1000_set_pauseparam,
+	.get_rx_csum		= e1000_get_rx_csum,
+	.set_rx_csum		= e1000_set_rx_csum,
+	.get_tx_csum		= e1000_get_tx_csum,
+	.set_tx_csum		= e1000_set_tx_csum,
+	.get_sg			= ethtool_op_get_sg,
+	.set_sg			= ethtool_op_set_sg,
+	.get_tso		= ethtool_op_get_tso,
+	.set_tso		= e1000_set_tso,
+	.self_test		= e1000_diag_test,
+	.get_strings		= e1000_get_strings,
+	.phys_id		= e1000_phys_id,
+	.get_ethtool_stats	= e1000_get_ethtool_stats,
+	.get_sset_count		= e1000e_get_sset_count,
+};
+
+void e1000e_set_ethtool_ops(struct net_device *netdev)
+{
+	SET_ETHTOOL_OPS(netdev, &e1000_ethtool_ops);
+}
diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h
new file mode 100644
index 0000000..aa82f1a
--- /dev/null
+++ b/drivers/net/e1000e/hw.h
@@ -0,0 +1,864 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
+
+#include <linux/types.h>
+
+struct e1000_hw;
+struct e1000_adapter;
+
+#include "defines.h"
+
+#define er32(reg)	__er32(hw, E1000_##reg)
+#define ew32(reg,val)	__ew32(hw, E1000_##reg, (val))
+#define e1e_flush()	er32(STATUS)
+
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \
+	(writel((value), ((a)->hw_addr + reg + ((offset) << 2))))
+
+#define E1000_READ_REG_ARRAY(a, reg, offset) \
+	(readl((a)->hw_addr + reg + ((offset) << 2)))
+
+enum e1e_registers {
+	E1000_CTRL     = 0x00000, /* Device Control - RW */
+	E1000_STATUS   = 0x00008, /* Device Status - RO */
+	E1000_EECD     = 0x00010, /* EEPROM/Flash Control - RW */
+	E1000_EERD     = 0x00014, /* EEPROM Read - RW */
+	E1000_CTRL_EXT = 0x00018, /* Extended Device Control - RW */
+	E1000_FLA      = 0x0001C, /* Flash Access - RW */
+	E1000_MDIC     = 0x00020, /* MDI Control - RW */
+	E1000_SCTL     = 0x00024, /* SerDes Control - RW */
+	E1000_FCAL     = 0x00028, /* Flow Control Address Low - RW */
+	E1000_FCAH     = 0x0002C, /* Flow Control Address High -RW */
+	E1000_FEXTNVM  = 0x00028, /* Future Extended NVM - RW */
+	E1000_FCT      = 0x00030, /* Flow Control Type - RW */
+	E1000_VET      = 0x00038, /* VLAN Ether Type - RW */
+	E1000_ICR      = 0x000C0, /* Interrupt Cause Read - R/clr */
+	E1000_ITR      = 0x000C4, /* Interrupt Throttling Rate - RW */
+	E1000_ICS      = 0x000C8, /* Interrupt Cause Set - WO */
+	E1000_IMS      = 0x000D0, /* Interrupt Mask Set - RW */
+	E1000_IMC      = 0x000D8, /* Interrupt Mask Clear - WO */
+	E1000_IAM      = 0x000E0, /* Interrupt Acknowledge Auto Mask */
+	E1000_RCTL     = 0x00100, /* RX Control - RW */
+	E1000_FCTTV    = 0x00170, /* Flow Control Transmit Timer Value - RW */
+	E1000_TXCW     = 0x00178, /* TX Configuration Word - RW */
+	E1000_RXCW     = 0x00180, /* RX Configuration Word - RO */
+	E1000_TCTL     = 0x00400, /* TX Control - RW */
+	E1000_TCTL_EXT = 0x00404, /* Extended TX Control - RW */
+	E1000_TIPG     = 0x00410, /* TX Inter-packet gap -RW */
+	E1000_AIT      = 0x00458, /* Adaptive Interframe Spacing Throttle - RW */
+	E1000_LEDCTL   = 0x00E00, /* LED Control - RW */
+	E1000_EXTCNF_CTRL  = 0x00F00, /* Extended Configuration Control */
+	E1000_EXTCNF_SIZE  = 0x00F08, /* Extended Configuration Size */
+	E1000_PHY_CTRL     = 0x00F10, /* PHY Control Register in CSR */
+	E1000_PBA      = 0x01000, /* Packet Buffer Allocation - RW */
+	E1000_PBS      = 0x01008, /* Packet Buffer Size */
+	E1000_EEMNGCTL = 0x01010, /* MNG EEprom Control */
+	E1000_EEWR     = 0x0102C, /* EEPROM Write Register - RW */
+	E1000_FLOP     = 0x0103C, /* FLASH Opcode Register */
+	E1000_ERT      = 0x02008, /* Early Rx Threshold - RW */
+	E1000_FCRTL    = 0x02160, /* Flow Control Receive Threshold Low - RW */
+	E1000_FCRTH    = 0x02168, /* Flow Control Receive Threshold High - RW */
+	E1000_PSRCTL   = 0x02170, /* Packet Split Receive Control - RW */
+	E1000_RDBAL    = 0x02800, /* RX Descriptor Base Address Low - RW */
+	E1000_RDBAH    = 0x02804, /* RX Descriptor Base Address High - RW */
+	E1000_RDLEN    = 0x02808, /* RX Descriptor Length - RW */
+	E1000_RDH      = 0x02810, /* RX Descriptor Head - RW */
+	E1000_RDT      = 0x02818, /* RX Descriptor Tail - RW */
+	E1000_RDTR     = 0x02820, /* RX Delay Timer - RW */
+	E1000_RADV     = 0x0282C, /* RX Interrupt Absolute Delay Timer - RW */
+
+/* Convenience macros
+ *
+ * Note: "_n" is the queue number of the register to be written to.
+ *
+ * Example usage:
+ * E1000_RDBAL_REG(current_rx_queue)
+ *
+ */
+#define E1000_RDBAL_REG(_n)   (E1000_RDBAL + (_n << 8))
+	E1000_KABGTXD  = 0x03004, /* AFE Band Gap Transmit Ref Data */
+	E1000_TDBAL    = 0x03800, /* TX Descriptor Base Address Low - RW */
+	E1000_TDBAH    = 0x03804, /* TX Descriptor Base Address High - RW */
+	E1000_TDLEN    = 0x03808, /* TX Descriptor Length - RW */
+	E1000_TDH      = 0x03810, /* TX Descriptor Head - RW */
+	E1000_TDT      = 0x03818, /* TX Descriptor Tail - RW */
+	E1000_TIDV     = 0x03820, /* TX Interrupt Delay Value - RW */
+	E1000_TXDCTL   = 0x03828, /* TX Descriptor Control - RW */
+	E1000_TADV     = 0x0382C, /* TX Interrupt Absolute Delay Val - RW */
+	E1000_TARC0    = 0x03840, /* TX Arbitration Count (0) */
+	E1000_TXDCTL1  = 0x03928, /* TX Descriptor Control (1) - RW */
+	E1000_TARC1    = 0x03940, /* TX Arbitration Count (1) */
+	E1000_CRCERRS  = 0x04000, /* CRC Error Count - R/clr */
+	E1000_ALGNERRC = 0x04004, /* Alignment Error Count - R/clr */
+	E1000_SYMERRS  = 0x04008, /* Symbol Error Count - R/clr */
+	E1000_RXERRC   = 0x0400C, /* Receive Error Count - R/clr */
+	E1000_MPC      = 0x04010, /* Missed Packet Count - R/clr */
+	E1000_SCC      = 0x04014, /* Single Collision Count - R/clr */
+	E1000_ECOL     = 0x04018, /* Excessive Collision Count - R/clr */
+	E1000_MCC      = 0x0401C, /* Multiple Collision Count - R/clr */
+	E1000_LATECOL  = 0x04020, /* Late Collision Count - R/clr */
+	E1000_COLC     = 0x04028, /* Collision Count - R/clr */
+	E1000_DC       = 0x04030, /* Defer Count - R/clr */
+	E1000_TNCRS    = 0x04034, /* TX-No CRS - R/clr */
+	E1000_SEC      = 0x04038, /* Sequence Error Count - R/clr */
+	E1000_CEXTERR  = 0x0403C, /* Carrier Extension Error Count - R/clr */
+	E1000_RLEC     = 0x04040, /* Receive Length Error Count - R/clr */
+	E1000_XONRXC   = 0x04048, /* XON RX Count - R/clr */
+	E1000_XONTXC   = 0x0404C, /* XON TX Count - R/clr */
+	E1000_XOFFRXC  = 0x04050, /* XOFF RX Count - R/clr */
+	E1000_XOFFTXC  = 0x04054, /* XOFF TX Count - R/clr */
+	E1000_FCRUC    = 0x04058, /* Flow Control RX Unsupported Count- R/clr */
+	E1000_PRC64    = 0x0405C, /* Packets RX (64 bytes) - R/clr */
+	E1000_PRC127   = 0x04060, /* Packets RX (65-127 bytes) - R/clr */
+	E1000_PRC255   = 0x04064, /* Packets RX (128-255 bytes) - R/clr */
+	E1000_PRC511   = 0x04068, /* Packets RX (255-511 bytes) - R/clr */
+	E1000_PRC1023  = 0x0406C, /* Packets RX (512-1023 bytes) - R/clr */
+	E1000_PRC1522  = 0x04070, /* Packets RX (1024-1522 bytes) - R/clr */
+	E1000_GPRC     = 0x04074, /* Good Packets RX Count - R/clr */
+	E1000_BPRC     = 0x04078, /* Broadcast Packets RX Count - R/clr */
+	E1000_MPRC     = 0x0407C, /* Multicast Packets RX Count - R/clr */
+	E1000_GPTC     = 0x04080, /* Good Packets TX Count - R/clr */
+	E1000_GORCL    = 0x04088, /* Good Octets RX Count Low - R/clr */
+	E1000_GORCH    = 0x0408C, /* Good Octets RX Count High - R/clr */
+	E1000_GOTCL    = 0x04090, /* Good Octets TX Count Low - R/clr */
+	E1000_GOTCH    = 0x04094, /* Good Octets TX Count High - R/clr */
+	E1000_RNBC     = 0x040A0, /* RX No Buffers Count - R/clr */
+	E1000_RUC      = 0x040A4, /* RX Undersize Count - R/clr */
+	E1000_RFC      = 0x040A8, /* RX Fragment Count - R/clr */
+	E1000_ROC      = 0x040AC, /* RX Oversize Count - R/clr */
+	E1000_RJC      = 0x040B0, /* RX Jabber Count - R/clr */
+	E1000_MGTPRC   = 0x040B4, /* Management Packets RX Count - R/clr */
+	E1000_MGTPDC   = 0x040B8, /* Management Packets Dropped Count - R/clr */
+	E1000_MGTPTC   = 0x040BC, /* Management Packets TX Count - R/clr */
+	E1000_TORL     = 0x040C0, /* Total Octets RX Low - R/clr */
+	E1000_TORH     = 0x040C4, /* Total Octets RX High - R/clr */
+	E1000_TOTL     = 0x040C8, /* Total Octets TX Low - R/clr */
+	E1000_TOTH     = 0x040CC, /* Total Octets TX High - R/clr */
+	E1000_TPR      = 0x040D0, /* Total Packets RX - R/clr */
+	E1000_TPT      = 0x040D4, /* Total Packets TX - R/clr */
+	E1000_PTC64    = 0x040D8, /* Packets TX (64 bytes) - R/clr */
+	E1000_PTC127   = 0x040DC, /* Packets TX (65-127 bytes) - R/clr */
+	E1000_PTC255   = 0x040E0, /* Packets TX (128-255 bytes) - R/clr */
+	E1000_PTC511   = 0x040E4, /* Packets TX (256-511 bytes) - R/clr */
+	E1000_PTC1023  = 0x040E8, /* Packets TX (512-1023 bytes) - R/clr */
+	E1000_PTC1522  = 0x040EC, /* Packets TX (1024-1522 Bytes) - R/clr */
+	E1000_MPTC     = 0x040F0, /* Multicast Packets TX Count - R/clr */
+	E1000_BPTC     = 0x040F4, /* Broadcast Packets TX Count - R/clr */
+	E1000_TSCTC    = 0x040F8, /* TCP Segmentation Context TX - R/clr */
+	E1000_TSCTFC   = 0x040FC, /* TCP Segmentation Context TX Fail - R/clr */
+	E1000_IAC      = 0x04100, /* Interrupt Assertion Count */
+	E1000_ICRXPTC  = 0x04104, /* Irq Cause Rx Packet Timer Expire Count */
+	E1000_ICRXATC  = 0x04108, /* Irq Cause Rx Abs Timer Expire Count */
+	E1000_ICTXPTC  = 0x0410C, /* Irq Cause Tx Packet Timer Expire Count */
+	E1000_ICTXATC  = 0x04110, /* Irq Cause Tx Abs Timer Expire Count */
+	E1000_ICTXQEC  = 0x04118, /* Irq Cause Tx Queue Empty Count */
+	E1000_ICTXQMTC = 0x0411C, /* Irq Cause Tx Queue MinThreshold Count */
+	E1000_ICRXDMTC = 0x04120, /* Irq Cause Rx Desc MinThreshold Count */
+	E1000_ICRXOC   = 0x04124, /* Irq Cause Receiver Overrun Count */
+	E1000_RXCSUM   = 0x05000, /* RX Checksum Control - RW */
+	E1000_RFCTL    = 0x05008, /* Receive Filter Control*/
+	E1000_MTA      = 0x05200, /* Multicast Table Array - RW Array */
+	E1000_RA       = 0x05400, /* Receive Address - RW Array */
+	E1000_VFTA     = 0x05600, /* VLAN Filter Table Array - RW Array */
+	E1000_WUC      = 0x05800, /* Wakeup Control - RW */
+	E1000_WUFC     = 0x05808, /* Wakeup Filter Control - RW */
+	E1000_WUS      = 0x05810, /* Wakeup Status - RO */
+	E1000_MANC     = 0x05820, /* Management Control - RW */
+	E1000_FFLT     = 0x05F00, /* Flexible Filter Length Table - RW Array */
+	E1000_HOST_IF  = 0x08800, /* Host Interface */
+
+	E1000_KMRNCTRLSTA = 0x00034, /* MAC-PHY interface - RW */
+	E1000_MANC2H    = 0x05860, /* Management Control To Host - RW */
+	E1000_SW_FW_SYNC = 0x05B5C, /* Software-Firmware Synchronization - RW */
+	E1000_GCR	= 0x05B00, /* PCI-Ex Control */
+	E1000_FACTPS    = 0x05B30, /* Function Active and Power State to MNG */
+	E1000_SWSM      = 0x05B50, /* SW Semaphore */
+	E1000_FWSM      = 0x05B54, /* FW Semaphore */
+	E1000_HICR      = 0x08F00, /* Host Inteface Control */
+};
+
+/* RSS registers */
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG	0x10 /* Port Config */
+#define IGP01E1000_PHY_PORT_STATUS	0x11 /* Status */
+#define IGP01E1000_PHY_PORT_CTRL	0x12 /* Control */
+#define IGP01E1000_PHY_LINK_HEALTH	0x13 /* PHY Link Health */
+#define IGP02E1000_PHY_POWER_MGMT	0x19 /* Power Management */
+#define IGP01E1000_PHY_PAGE_SELECT	0x1F /* Page Select */
+
+#define IGP01E1000_PHY_PCS_INIT_REG	0x00B4
+#define IGP01E1000_PHY_POLARITY_MASK	0x0078
+
+#define IGP01E1000_PSCR_AUTO_MDIX	0x1000
+#define IGP01E1000_PSCR_FORCE_MDI_MDIX	0x2000 /* 0=MDI, 1=MDIX */
+
+#define IGP01E1000_PSCFR_SMART_SPEED	0x0080
+
+#define IGP02E1000_PM_SPD		0x0001 /* Smart Power Down */
+#define IGP02E1000_PM_D0_LPLU		0x0002 /* For D0a states */
+#define IGP02E1000_PM_D3_LPLU		0x0004 /* For all other states */
+
+#define IGP01E1000_PLHR_SS_DOWNGRADE	0x8000
+
+#define IGP01E1000_PSSR_POLARITY_REVERSED	0x0002
+#define IGP01E1000_PSSR_MDIX			0x0008
+#define IGP01E1000_PSSR_SPEED_MASK		0xC000
+#define IGP01E1000_PSSR_SPEED_1000MBPS		0xC000
+
+#define IGP02E1000_PHY_CHANNEL_NUM		4
+#define IGP02E1000_PHY_AGC_A			0x11B1
+#define IGP02E1000_PHY_AGC_B			0x12B1
+#define IGP02E1000_PHY_AGC_C			0x14B1
+#define IGP02E1000_PHY_AGC_D			0x18B1
+
+#define IGP02E1000_AGC_LENGTH_SHIFT	9 /* Course - 15:13, Fine - 12:9 */
+#define IGP02E1000_AGC_LENGTH_MASK	0x7F
+#define IGP02E1000_AGC_RANGE		15
+
+/* manage.c */
+#define E1000_VFTA_ENTRY_SHIFT		5
+#define E1000_VFTA_ENTRY_MASK		0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK	0x1F
+
+#define E1000_HICR_EN			0x01  /* Enable bit - RO */
+#define E1000_HICR_C			0x02  /* Driver sets this bit when done
+					       * to put command in RAM */
+#define E1000_HICR_FW_RESET_ENABLE	0x40
+#define E1000_HICR_FW_RESET		0x80
+
+#define E1000_FWSM_MODE_MASK		0xE
+#define E1000_FWSM_MODE_SHIFT		1
+
+#define E1000_MNG_IAMT_MODE		0x3
+#define E1000_MNG_DHCP_COOKIE_LENGTH	0x10
+#define E1000_MNG_DHCP_COOKIE_OFFSET	0x6F0
+#define E1000_MNG_DHCP_COMMAND_TIMEOUT	10
+#define E1000_MNG_DHCP_TX_PAYLOAD_CMD	64
+#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING	0x1
+#define E1000_MNG_DHCP_COOKIE_STATUS_VLAN	0x2
+
+/* nvm.c */
+#define E1000_STM_OPCODE  0xDB00
+
+#define E1000_KMRNCTRLSTA_OFFSET	0x001F0000
+#define E1000_KMRNCTRLSTA_OFFSET_SHIFT	16
+#define E1000_KMRNCTRLSTA_REN		0x00200000
+#define E1000_KMRNCTRLSTA_DIAG_OFFSET	0x3    /* Kumeran Diagnostic */
+#define E1000_KMRNCTRLSTA_DIAG_NELPBK	0x1000 /* Nearend Loopback mode */
+
+#define IFE_PHY_EXTENDED_STATUS_CONTROL	0x10
+#define IFE_PHY_SPECIAL_CONTROL		0x11 /* 100BaseTx PHY Special Control */
+#define IFE_PHY_SPECIAL_CONTROL_LED	0x1B /* PHY Special and LED Control */
+#define IFE_PHY_MDIX_CONTROL		0x1C /* MDI/MDI-X Control */
+
+/* IFE PHY Extended Status Control */
+#define IFE_PESC_POLARITY_REVERSED	0x0100
+
+/* IFE PHY Special Control */
+#define IFE_PSC_AUTO_POLARITY_DISABLE		0x0010
+#define IFE_PSC_FORCE_POLARITY			0x0020
+
+/* IFE PHY Special Control and LED Control */
+#define IFE_PSCL_PROBE_MODE		0x0020
+#define IFE_PSCL_PROBE_LEDS_OFF		0x0006 /* Force LEDs 0 and 2 off */
+#define IFE_PSCL_PROBE_LEDS_ON		0x0007 /* Force LEDs 0 and 2 on */
+
+/* IFE PHY MDIX Control */
+#define IFE_PMC_MDIX_STATUS	0x0020 /* 1=MDI-X, 0=MDI */
+#define IFE_PMC_FORCE_MDIX	0x0040 /* 1=force MDI-X, 0=force MDI */
+#define IFE_PMC_AUTO_MDIX	0x0080 /* 1=enable auto MDI/MDI-X, 0=disable */
+
+#define E1000_CABLE_LENGTH_UNDEFINED	0xFF
+
+#define E1000_DEV_ID_82571EB_COPPER		0x105E
+#define E1000_DEV_ID_82571EB_FIBER		0x105F
+#define E1000_DEV_ID_82571EB_SERDES		0x1060
+#define E1000_DEV_ID_82571EB_QUAD_COPPER	0x10A4
+#define E1000_DEV_ID_82571EB_QUAD_FIBER		0x10A5
+#define E1000_DEV_ID_82571EB_QUAD_COPPER_LP	0x10BC
+#define E1000_DEV_ID_82572EI_COPPER		0x107D
+#define E1000_DEV_ID_82572EI_FIBER		0x107E
+#define E1000_DEV_ID_82572EI_SERDES		0x107F
+#define E1000_DEV_ID_82572EI			0x10B9
+#define E1000_DEV_ID_82573E			0x108B
+#define E1000_DEV_ID_82573E_IAMT		0x108C
+#define E1000_DEV_ID_82573L			0x109A
+
+#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT	0x1096
+#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT	0x1098
+#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT	0x10BA
+#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT	0x10BB
+
+#define E1000_DEV_ID_ICH8_IGP_M_AMT		0x1049
+#define E1000_DEV_ID_ICH8_IGP_AMT		0x104A
+#define E1000_DEV_ID_ICH8_IGP_C			0x104B
+#define E1000_DEV_ID_ICH8_IFE			0x104C
+#define E1000_DEV_ID_ICH8_IFE_GT		0x10C4
+#define E1000_DEV_ID_ICH8_IFE_G			0x10C5
+#define E1000_DEV_ID_ICH8_IGP_M			0x104D
+#define E1000_DEV_ID_ICH9_IGP_AMT		0x10BD
+#define E1000_DEV_ID_ICH9_IGP_C			0x294C
+#define E1000_DEV_ID_ICH9_IFE			0x10C0
+#define E1000_DEV_ID_ICH9_IFE_GT		0x10C3
+#define E1000_DEV_ID_ICH9_IFE_G			0x10C2
+
+#define E1000_FUNC_1 1
+
+enum e1000_mac_type {
+	e1000_82571,
+	e1000_82572,
+	e1000_82573,
+	e1000_80003es2lan,
+	e1000_ich8lan,
+	e1000_ich9lan,
+};
+
+enum e1000_media_type {
+	e1000_media_type_unknown = 0,
+	e1000_media_type_copper = 1,
+	e1000_media_type_fiber = 2,
+	e1000_media_type_internal_serdes = 3,
+	e1000_num_media_types
+};
+
+enum e1000_nvm_type {
+	e1000_nvm_unknown = 0,
+	e1000_nvm_none,
+	e1000_nvm_eeprom_spi,
+	e1000_nvm_flash_hw,
+	e1000_nvm_flash_sw
+};
+
+enum e1000_nvm_override {
+	e1000_nvm_override_none = 0,
+	e1000_nvm_override_spi_small,
+	e1000_nvm_override_spi_large
+};
+
+enum e1000_phy_type {
+	e1000_phy_unknown = 0,
+	e1000_phy_none,
+	e1000_phy_m88,
+	e1000_phy_igp,
+	e1000_phy_igp_2,
+	e1000_phy_gg82563,
+	e1000_phy_igp_3,
+	e1000_phy_ife,
+};
+
+enum e1000_bus_width {
+	e1000_bus_width_unknown = 0,
+	e1000_bus_width_pcie_x1,
+	e1000_bus_width_pcie_x2,
+	e1000_bus_width_pcie_x4 = 4,
+	e1000_bus_width_32,
+	e1000_bus_width_64,
+	e1000_bus_width_reserved
+};
+
+enum e1000_1000t_rx_status {
+	e1000_1000t_rx_status_not_ok = 0,
+	e1000_1000t_rx_status_ok,
+	e1000_1000t_rx_status_undefined = 0xFF
+};
+
+enum e1000_rev_polarity{
+	e1000_rev_polarity_normal = 0,
+	e1000_rev_polarity_reversed,
+	e1000_rev_polarity_undefined = 0xFF
+};
+
+enum e1000_fc_mode {
+	e1000_fc_none = 0,
+	e1000_fc_rx_pause,
+	e1000_fc_tx_pause,
+	e1000_fc_full,
+	e1000_fc_default = 0xFF
+};
+
+enum e1000_ms_type {
+	e1000_ms_hw_default = 0,
+	e1000_ms_force_master,
+	e1000_ms_force_slave,
+	e1000_ms_auto
+};
+
+enum e1000_smart_speed {
+	e1000_smart_speed_default = 0,
+	e1000_smart_speed_on,
+	e1000_smart_speed_off
+};
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+	u64 buffer_addr; /* Address of the descriptor's data buffer */
+	u16 length;      /* Length of data DMAed into data buffer */
+	u16 csum;	/* Packet checksum */
+	u8  status;      /* Descriptor status */
+	u8  errors;      /* Descriptor Errors */
+	u16 special;
+};
+
+/* Receive Descriptor - Extended */
+union e1000_rx_desc_extended {
+	struct {
+		u64 buffer_addr;
+		u64 reserved;
+	} read;
+	struct {
+		struct {
+			u32 mrq;	      /* Multiple Rx Queues */
+			union {
+				u32 rss;	    /* RSS Hash */
+				struct {
+					u16 ip_id;  /* IP id */
+					u16 csum;   /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			u32 status_error;     /* ext status/error */
+			u16 length;
+			u16 vlan;	     /* VLAN tag */
+		} upper;
+	} wb;  /* writeback */
+};
+
+#define MAX_PS_BUFFERS 4
+/* Receive Descriptor - Packet Split */
+union e1000_rx_desc_packet_split {
+	struct {
+		/* one buffer for protocol header(s), three data buffers */
+		u64 buffer_addr[MAX_PS_BUFFERS];
+	} read;
+	struct {
+		struct {
+			u32 mrq;	      /* Multiple Rx Queues */
+			union {
+				u32 rss;	      /* RSS Hash */
+				struct {
+					u16 ip_id;    /* IP id */
+					u16 csum;     /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			u32 status_error;     /* ext status/error */
+			u16 length0;	  /* length of buffer 0 */
+			u16 vlan;	     /* VLAN tag */
+		} middle;
+		struct {
+			u16 header_status;
+			u16 length[3];	/* length of buffers 1-3 */
+		} upper;
+		u64 reserved;
+	} wb; /* writeback */
+};
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+	u64 buffer_addr;      /* Address of the descriptor's data buffer */
+	union {
+		u32 data;
+		struct {
+			u16 length;    /* Data buffer length */
+			u8 cso;	/* Checksum offset */
+			u8 cmd;	/* Descriptor control */
+		} flags;
+	} lower;
+	union {
+		u32 data;
+		struct {
+			u8 status;     /* Descriptor status */
+			u8 css;	/* Checksum start */
+			u16 special;
+		} fields;
+	} upper;
+};
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+	union {
+		u32 ip_config;
+		struct {
+			u8 ipcss;      /* IP checksum start */
+			u8 ipcso;      /* IP checksum offset */
+			u16 ipcse;     /* IP checksum end */
+		} ip_fields;
+	} lower_setup;
+	union {
+		u32 tcp_config;
+		struct {
+			u8 tucss;      /* TCP checksum start */
+			u8 tucso;      /* TCP checksum offset */
+			u16 tucse;     /* TCP checksum end */
+		} tcp_fields;
+	} upper_setup;
+	u32 cmd_and_length;
+	union {
+		u32 data;
+		struct {
+			u8 status;     /* Descriptor status */
+			u8 hdr_len;    /* Header length */
+			u16 mss;       /* Maximum segment size */
+		} fields;
+	} tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+	u64 buffer_addr;   /* Address of the descriptor's buffer address */
+	union {
+		u32 data;
+		struct {
+			u16 length;    /* Data buffer length */
+			u8 typ_len_ext;
+			u8 cmd;
+		} flags;
+	} lower;
+	union {
+		u32 data;
+		struct {
+			u8 status;     /* Descriptor status */
+			u8 popts;      /* Packet Options */
+			u16 special;   /* */
+		} fields;
+	} upper;
+};
+
+/* Statistics counters collected by the MAC */
+struct e1000_hw_stats {
+	u64 crcerrs;
+	u64 algnerrc;
+	u64 symerrs;
+	u64 rxerrc;
+	u64 mpc;
+	u64 scc;
+	u64 ecol;
+	u64 mcc;
+	u64 latecol;
+	u64 colc;
+	u64 dc;
+	u64 tncrs;
+	u64 sec;
+	u64 cexterr;
+	u64 rlec;
+	u64 xonrxc;
+	u64 xontxc;
+	u64 xoffrxc;
+	u64 xofftxc;
+	u64 fcruc;
+	u64 prc64;
+	u64 prc127;
+	u64 prc255;
+	u64 prc511;
+	u64 prc1023;
+	u64 prc1522;
+	u64 gprc;
+	u64 bprc;
+	u64 mprc;
+	u64 gptc;
+	u64 gorcl;
+	u64 gorch;
+	u64 gotcl;
+	u64 gotch;
+	u64 rnbc;
+	u64 ruc;
+	u64 rfc;
+	u64 roc;
+	u64 rjc;
+	u64 mgprc;
+	u64 mgpdc;
+	u64 mgptc;
+	u64 torl;
+	u64 torh;
+	u64 totl;
+	u64 toth;
+	u64 tpr;
+	u64 tpt;
+	u64 ptc64;
+	u64 ptc127;
+	u64 ptc255;
+	u64 ptc511;
+	u64 ptc1023;
+	u64 ptc1522;
+	u64 mptc;
+	u64 bptc;
+	u64 tsctc;
+	u64 tsctfc;
+	u64 iac;
+	u64 icrxptc;
+	u64 icrxatc;
+	u64 ictxptc;
+	u64 ictxatc;
+	u64 ictxqec;
+	u64 ictxqmtc;
+	u64 icrxdmtc;
+	u64 icrxoc;
+};
+
+struct e1000_phy_stats {
+	u32 idle_errors;
+	u32 receive_errors;
+};
+
+struct e1000_host_mng_dhcp_cookie {
+	u32 signature;
+	u8  status;
+	u8  reserved0;
+	u16 vlan_id;
+	u32 reserved1;
+	u16 reserved2;
+	u8  reserved3;
+	u8  checksum;
+};
+
+/* Host Interface "Rev 1" */
+struct e1000_host_command_header {
+	u8 command_id;
+	u8 command_length;
+	u8 command_options;
+	u8 checksum;
+};
+
+#define E1000_HI_MAX_DATA_LENGTH     252
+struct e1000_host_command_info {
+	struct e1000_host_command_header command_header;
+	u8 command_data[E1000_HI_MAX_DATA_LENGTH];
+};
+
+/* Host Interface "Rev 2" */
+struct e1000_host_mng_command_header {
+	u8  command_id;
+	u8  checksum;
+	u16 reserved1;
+	u16 reserved2;
+	u16 command_length;
+};
+
+#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8
+struct e1000_host_mng_command_info {
+	struct e1000_host_mng_command_header command_header;
+	u8 command_data[E1000_HI_MAX_MNG_DATA_LENGTH];
+};
+
+/* Function pointers and static data for the MAC. */
+struct e1000_mac_operations {
+	u32			mng_mode_enab;
+
+	s32  (*check_for_link)(struct e1000_hw *);
+	s32  (*cleanup_led)(struct e1000_hw *);
+	void (*clear_hw_cntrs)(struct e1000_hw *);
+	s32  (*get_bus_info)(struct e1000_hw *);
+	s32  (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
+	s32  (*led_on)(struct e1000_hw *);
+	s32  (*led_off)(struct e1000_hw *);
+	void (*mc_addr_list_update)(struct e1000_hw *, u8 *, u32, u32,
+					 u32);
+	s32  (*reset_hw)(struct e1000_hw *);
+	s32  (*init_hw)(struct e1000_hw *);
+	s32  (*setup_link)(struct e1000_hw *);
+	s32  (*setup_physical_interface)(struct e1000_hw *);
+};
+
+/* Function pointers for the PHY. */
+struct e1000_phy_operations {
+	s32  (*acquire_phy)(struct e1000_hw *);
+	s32  (*check_reset_block)(struct e1000_hw *);
+	s32  (*commit_phy)(struct e1000_hw *);
+	s32  (*force_speed_duplex)(struct e1000_hw *);
+	s32  (*get_cfg_done)(struct e1000_hw *hw);
+	s32  (*get_cable_length)(struct e1000_hw *);
+	s32  (*get_phy_info)(struct e1000_hw *);
+	s32  (*read_phy_reg)(struct e1000_hw *, u32, u16 *);
+	void (*release_phy)(struct e1000_hw *);
+	s32  (*reset_phy)(struct e1000_hw *);
+	s32  (*set_d0_lplu_state)(struct e1000_hw *, bool);
+	s32  (*set_d3_lplu_state)(struct e1000_hw *, bool);
+	s32  (*write_phy_reg)(struct e1000_hw *, u32, u16);
+};
+
+/* Function pointers for the NVM. */
+struct e1000_nvm_operations {
+	s32  (*acquire_nvm)(struct e1000_hw *);
+	s32  (*read_nvm)(struct e1000_hw *, u16, u16, u16 *);
+	void (*release_nvm)(struct e1000_hw *);
+	s32  (*update_nvm)(struct e1000_hw *);
+	s32  (*valid_led_default)(struct e1000_hw *, u16 *);
+	s32  (*validate_nvm)(struct e1000_hw *);
+	s32  (*write_nvm)(struct e1000_hw *, u16, u16, u16 *);
+};
+
+struct e1000_mac_info {
+	struct e1000_mac_operations ops;
+
+	u8 addr[6];
+	u8 perm_addr[6];
+
+	enum e1000_mac_type type;
+	enum e1000_fc_mode  fc;
+	enum e1000_fc_mode  original_fc;
+
+	u32 collision_delta;
+	u32 ledctl_default;
+	u32 ledctl_mode1;
+	u32 ledctl_mode2;
+	u32 max_frame_size;
+	u32 mc_filter_type;
+	u32 min_frame_size;
+	u32 tx_packet_delta;
+	u32 txcw;
+
+	u16 current_ifs_val;
+	u16 ifs_max_val;
+	u16 ifs_min_val;
+	u16 ifs_ratio;
+	u16 ifs_step_size;
+	u16 mta_reg_count;
+	u16 rar_entry_count;
+	u16 fc_high_water;
+	u16 fc_low_water;
+	u16 fc_pause_time;
+
+	u8  forced_speed_duplex;
+
+	bool arc_subsystem_valid;
+	bool autoneg;
+	bool autoneg_failed;
+	bool get_link_status;
+	bool in_ifs_mode;
+	bool serdes_has_link;
+	bool tx_pkt_filtering;
+};
+
+struct e1000_phy_info {
+	struct e1000_phy_operations ops;
+
+	enum e1000_phy_type type;
+
+	enum e1000_1000t_rx_status local_rx;
+	enum e1000_1000t_rx_status remote_rx;
+	enum e1000_ms_type ms_type;
+	enum e1000_ms_type original_ms_type;
+	enum e1000_rev_polarity cable_polarity;
+	enum e1000_smart_speed smart_speed;
+
+	u32 addr;
+	u32 id;
+	u32 reset_delay_us; /* in usec */
+	u32 revision;
+
+	u16 autoneg_advertised;
+	u16 autoneg_mask;
+	u16 cable_length;
+	u16 max_cable_length;
+	u16 min_cable_length;
+
+	u8 mdix;
+
+	bool disable_polarity_correction;
+	bool is_mdix;
+	bool polarity_correction;
+	bool speed_downgraded;
+	bool wait_for_link;
+};
+
+struct e1000_nvm_info {
+	struct e1000_nvm_operations ops;
+
+	enum e1000_nvm_type type;
+	enum e1000_nvm_override override;
+
+	u32 flash_bank_size;
+	u32 flash_base_addr;
+
+	u16 word_size;
+	u16 delay_usec;
+	u16 address_bits;
+	u16 opcode_bits;
+	u16 page_size;
+};
+
+struct e1000_bus_info {
+	enum e1000_bus_width width;
+
+	u16 func;
+};
+
+struct e1000_dev_spec_82571 {
+	bool laa_is_present;
+};
+
+struct e1000_shadow_ram {
+	u16  value;
+	bool modified;
+};
+
+#define E1000_ICH8_SHADOW_RAM_WORDS		2048
+
+struct e1000_dev_spec_ich8lan {
+	bool kmrn_lock_loss_workaround_enabled;
+	struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS];
+};
+
+struct e1000_hw {
+	struct e1000_adapter *adapter;
+
+	u8 __iomem *hw_addr;
+	u8 __iomem *flash_address;
+
+	struct e1000_mac_info  mac;
+	struct e1000_phy_info  phy;
+	struct e1000_nvm_info  nvm;
+	struct e1000_bus_info  bus;
+	struct e1000_host_mng_dhcp_cookie mng_cookie;
+
+	union {
+		struct e1000_dev_spec_82571	e82571;
+		struct e1000_dev_spec_ich8lan	ich8lan;
+	} dev_spec;
+
+	enum e1000_media_type media_type;
+};
+
+#ifdef DEBUG
+#define hw_dbg(hw, format, arg...) \
+	printk(KERN_DEBUG, "%s: " format, e1000e_get_hw_dev_name(hw), ##arg);
+#else
+static inline int __attribute__ ((format (printf, 2, 3)))
+hw_dbg(struct e1000_hw *hw, const char *format, ...)
+{
+	return 0;
+}
+#endif
+
+#endif
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
new file mode 100644
index 0000000..8f8139d
--- /dev/null
+++ b/drivers/net/e1000e/ich8lan.c
@@ -0,0 +1,2225 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/*
+ * 82562G-2 10/100 Network Connection
+ * 82562GT 10/100 Network Connection
+ * 82562GT-2 10/100 Network Connection
+ * 82562V 10/100 Network Connection
+ * 82562V-2 10/100 Network Connection
+ * 82566DC-2 Gigabit Network Connection
+ * 82566DC Gigabit Network Connection
+ * 82566DM-2 Gigabit Network Connection
+ * 82566DM Gigabit Network Connection
+ * 82566MC Gigabit Network Connection
+ * 82566MM Gigabit Network Connection
+ */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "e1000.h"
+
+#define ICH_FLASH_GFPREG		0x0000
+#define ICH_FLASH_HSFSTS		0x0004
+#define ICH_FLASH_HSFCTL		0x0006
+#define ICH_FLASH_FADDR			0x0008
+#define ICH_FLASH_FDATA0		0x0010
+
+#define ICH_FLASH_READ_COMMAND_TIMEOUT	500
+#define ICH_FLASH_WRITE_COMMAND_TIMEOUT	500
+#define ICH_FLASH_ERASE_COMMAND_TIMEOUT	3000000
+#define ICH_FLASH_LINEAR_ADDR_MASK	0x00FFFFFF
+#define ICH_FLASH_CYCLE_REPEAT_COUNT	10
+
+#define ICH_CYCLE_READ			0
+#define ICH_CYCLE_WRITE			2
+#define ICH_CYCLE_ERASE			3
+
+#define FLASH_GFPREG_BASE_MASK		0x1FFF
+#define FLASH_SECTOR_ADDR_SHIFT		12
+
+#define ICH_FLASH_SEG_SIZE_256		256
+#define ICH_FLASH_SEG_SIZE_4K		4096
+#define ICH_FLASH_SEG_SIZE_8K		8192
+#define ICH_FLASH_SEG_SIZE_64K		65536
+
+
+#define E1000_ICH_FWSM_RSPCIPHY	0x00000040 /* Reset PHY on PCI Reset */
+
+#define E1000_ICH_MNG_IAMT_MODE		0x2
+
+#define ID_LED_DEFAULT_ICH8LAN  ((ID_LED_DEF1_DEF2 << 12) | \
+				 (ID_LED_DEF1_OFF2 <<  8) | \
+				 (ID_LED_DEF1_ON2  <<  4) | \
+				 (ID_LED_DEF1_DEF2))
+
+#define E1000_ICH_NVM_SIG_WORD		0x13
+#define E1000_ICH_NVM_SIG_MASK		0xC000
+
+#define E1000_ICH8_LAN_INIT_TIMEOUT	1500
+
+#define E1000_FEXTNVM_SW_CONFIG		1
+#define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* Bit redefined for ICH8M :/ */
+
+#define PCIE_ICH8_SNOOP_ALL		PCIE_NO_SNOOP_ALL
+
+#define E1000_ICH_RAR_ENTRIES		7
+
+#define PHY_PAGE_SHIFT 5
+#define PHY_REG(page, reg) (((page) << PHY_PAGE_SHIFT) | \
+			   ((reg) & MAX_PHY_REG_ADDRESS))
+#define IGP3_KMRN_DIAG  PHY_REG(770, 19) /* KMRN Diagnostic */
+#define IGP3_VR_CTRL    PHY_REG(776, 18) /* Voltage Regulator Control */
+
+#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS	0x0002
+#define IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK 0x0300
+#define IGP3_VR_CTRL_MODE_SHUTDOWN	0x0200
+
+/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
+/* Offset 04h HSFSTS */
+union ich8_hws_flash_status {
+	struct ich8_hsfsts {
+		u16 flcdone    :1; /* bit 0 Flash Cycle Done */
+		u16 flcerr     :1; /* bit 1 Flash Cycle Error */
+		u16 dael       :1; /* bit 2 Direct Access error Log */
+		u16 berasesz   :2; /* bit 4:3 Sector Erase Size */
+		u16 flcinprog  :1; /* bit 5 flash cycle in Progress */
+		u16 reserved1  :2; /* bit 13:6 Reserved */
+		u16 reserved2  :6; /* bit 13:6 Reserved */
+		u16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */
+		u16 flockdn    :1; /* bit 15 Flash Config Lock-Down */
+	} hsf_status;
+	u16 regval;
+};
+
+/* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
+/* Offset 06h FLCTL */
+union ich8_hws_flash_ctrl {
+	struct ich8_hsflctl {
+		u16 flcgo      :1;   /* 0 Flash Cycle Go */
+		u16 flcycle    :2;   /* 2:1 Flash Cycle */
+		u16 reserved   :5;   /* 7:3 Reserved  */
+		u16 fldbcount  :2;   /* 9:8 Flash Data Byte Count */
+		u16 flockdn    :6;   /* 15:10 Reserved */
+	} hsf_ctrl;
+	u16 regval;
+};
+
+/* ICH Flash Region Access Permissions */
+union ich8_hws_flash_regacc {
+	struct ich8_flracc {
+		u32 grra      :8; /* 0:7 GbE region Read Access */
+		u32 grwa      :8; /* 8:15 GbE region Write Access */
+		u32 gmrag     :8; /* 23:16 GbE Master Read Access Grant */
+		u32 gmwag     :8; /* 31:24 GbE Master Write Access Grant */
+	} hsf_flregacc;
+	u16 regval;
+};
+
+static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
+static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
+static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
+static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw);
+static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
+static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
+						u32 offset, u8 byte);
+static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
+					 u16 *data);
+static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
+					 u8 size, u16 *data);
+static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
+static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
+
+static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
+{
+	return readw(hw->flash_address + reg);
+}
+
+static inline u32 __er32flash(struct e1000_hw *hw, unsigned long reg)
+{
+	return readl(hw->flash_address + reg);
+}
+
+static inline void __ew16flash(struct e1000_hw *hw, unsigned long reg, u16 val)
+{
+	writew(val, hw->flash_address + reg);
+}
+
+static inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val)
+{
+	writel(val, hw->flash_address + reg);
+}
+
+#define er16flash(reg)		__er16flash(hw, (reg))
+#define er32flash(reg)		__er32flash(hw, (reg))
+#define ew16flash(reg,val)	__ew16flash(hw, (reg), (val))
+#define ew32flash(reg,val)	__ew32flash(hw, (reg), (val))
+
+/**
+ *  e1000_init_phy_params_ich8lan - Initialize PHY function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize family-specific PHY parameters and function pointers.
+ **/
+static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 i = 0;
+
+	phy->addr			= 1;
+	phy->reset_delay_us		= 100;
+
+	phy->id = 0;
+	while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) &&
+	       (i++ < 100)) {
+		msleep(1);
+		ret_val = e1000e_get_phy_id(hw);
+		if (ret_val)
+			return ret_val;
+	}
+
+	/* Verify phy id */
+	switch (phy->id) {
+	case IGP03E1000_E_PHY_ID:
+		phy->type = e1000_phy_igp_3;
+		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+		break;
+	case IFE_E_PHY_ID:
+	case IFE_PLUS_E_PHY_ID:
+	case IFE_C_E_PHY_ID:
+		phy->type = e1000_phy_ife;
+		phy->autoneg_mask = E1000_ALL_NOT_GIG;
+		break;
+	default:
+		return -E1000_ERR_PHY;
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_init_nvm_params_ich8lan - Initialize NVM function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize family-specific NVM parameters and function
+ *  pointers.
+ **/
+static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+	u32 gfpreg;
+	u32 sector_base_addr;
+	u32 sector_end_addr;
+	u16 i;
+
+	/* Can't read flash registers if the register set isn't mapped.
+	 */
+	if (!hw->flash_address) {
+		hw_dbg(hw, "ERROR: Flash registers not mapped\n");
+		return -E1000_ERR_CONFIG;
+	}
+
+	nvm->type = e1000_nvm_flash_sw;
+
+	gfpreg = er32flash(ICH_FLASH_GFPREG);
+
+	/* sector_X_addr is a "sector"-aligned address (4096 bytes)
+	 * Add 1 to sector_end_addr since this sector is included in
+	 * the overall size. */
+	sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
+	sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
+
+	/* flash_base_addr is byte-aligned */
+	nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
+
+	/* find total size of the NVM, then cut in half since the total
+	 * size represents two separate NVM banks. */
+	nvm->flash_bank_size = (sector_end_addr - sector_base_addr)
+				<< FLASH_SECTOR_ADDR_SHIFT;
+	nvm->flash_bank_size /= 2;
+	/* Adjust to word count */
+	nvm->flash_bank_size /= sizeof(u16);
+
+	nvm->word_size = E1000_ICH8_SHADOW_RAM_WORDS;
+
+	/* Clear shadow ram */
+	for (i = 0; i < nvm->word_size; i++) {
+		dev_spec->shadow_ram[i].modified = 0;
+		dev_spec->shadow_ram[i].value    = 0xFFFF;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_init_mac_params_ich8lan - Initialize MAC function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Initialize family-specific MAC parameters and function
+ *  pointers.
+ **/
+static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_mac_info *mac = &hw->mac;
+
+	/* Set media type function pointer */
+	hw->media_type = e1000_media_type_copper;
+
+	/* Set mta register count */
+	mac->mta_reg_count = 32;
+	/* Set rar entry count */
+	mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
+	if (mac->type == e1000_ich8lan)
+		mac->rar_entry_count--;
+	/* Set if manageability features are enabled. */
+	mac->arc_subsystem_valid = 1;
+
+	/* Enable PCS Lock-loss workaround for ICH8 */
+	if (mac->type == e1000_ich8lan)
+		e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, 1);
+
+	return 0;
+}
+
+static s32 e1000_get_invariants_ich8lan(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	s32 rc;
+
+	rc = e1000_init_mac_params_ich8lan(adapter);
+	if (rc)
+		return rc;
+
+	rc = e1000_init_nvm_params_ich8lan(hw);
+	if (rc)
+		return rc;
+
+	rc = e1000_init_phy_params_ich8lan(hw);
+	if (rc)
+		return rc;
+
+	if ((adapter->hw.mac.type == e1000_ich8lan) &&
+	    (adapter->hw.phy.type == e1000_phy_igp_3))
+		adapter->flags |= FLAG_LSC_GIG_SPEED_DROP;
+
+	return 0;
+}
+
+/**
+ *  e1000_acquire_swflag_ich8lan - Acquire software control flag
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquires the software control flag for performing NVM and PHY
+ *  operations.  This is a function pointer entry point only called by
+ *  read/write routines for the PHY and NVM parts.
+ **/
+static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
+{
+	u32 extcnf_ctrl;
+	u32 timeout = PHY_CFG_TIMEOUT;
+
+	while (timeout) {
+		extcnf_ctrl = er32(EXTCNF_CTRL);
+		extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
+		ew32(EXTCNF_CTRL, extcnf_ctrl);
+
+		extcnf_ctrl = er32(EXTCNF_CTRL);
+		if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
+			break;
+		mdelay(1);
+		timeout--;
+	}
+
+	if (!timeout) {
+		hw_dbg(hw, "FW or HW has locked the resource for too long.\n");
+		return -E1000_ERR_CONFIG;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_release_swflag_ich8lan - Release software control flag
+ *  @hw: pointer to the HW structure
+ *
+ *  Releases the software control flag for performing NVM and PHY operations.
+ *  This is a function pointer entry point only called by read/write
+ *  routines for the PHY and NVM parts.
+ **/
+static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
+{
+	u32 extcnf_ctrl;
+
+	extcnf_ctrl = er32(EXTCNF_CTRL);
+	extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+	ew32(EXTCNF_CTRL, extcnf_ctrl);
+}
+
+/**
+ *  e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks if firmware is blocking the reset of the PHY.
+ *  This is a function pointer entry point only called by
+ *  reset routines.
+ **/
+static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
+{
+	u32 fwsm;
+
+	fwsm = er32(FWSM);
+
+	return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? 0 : E1000_BLK_PHY_RESET;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex_ich8lan - Force PHY speed & duplex
+ *  @hw: pointer to the HW structure
+ *
+ *  Forces the speed and duplex settings of the PHY.
+ *  This is a function pointer entry point only called by
+ *  PHY setup routines.
+ **/
+static s32 e1000_phy_force_speed_duplex_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	if (phy->type != e1000_phy_ife) {
+		ret_val = e1000e_phy_force_speed_duplex_igp(hw);
+		return ret_val;
+	}
+
+	ret_val = e1e_rphy(hw, PHY_CONTROL, &data);
+	if (ret_val)
+		return ret_val;
+
+	e1000e_phy_force_speed_duplex_setup(hw, &data);
+
+	ret_val = e1e_wphy(hw, PHY_CONTROL, data);
+	if (ret_val)
+		return ret_val;
+
+	/* Disable MDI-X support for 10/100 */
+	ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
+	if (ret_val)
+		return ret_val;
+
+	data &= ~IFE_PMC_AUTO_MDIX;
+	data &= ~IFE_PMC_FORCE_MDIX;
+
+	ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, data);
+	if (ret_val)
+		return ret_val;
+
+	hw_dbg(hw, "IFE PMC: %X\n", data);
+
+	udelay(1);
+
+	if (phy->wait_for_link) {
+		hw_dbg(hw, "Waiting for forced speed/duplex link on IFE phy.\n");
+
+		ret_val = e1000e_phy_has_link_generic(hw,
+						     PHY_FORCE_LIMIT,
+						     100000,
+						     &link);
+		if (ret_val)
+			return ret_val;
+
+		if (!link)
+			hw_dbg(hw, "Link taking longer than expected.\n");
+
+		/* Try once more */
+		ret_val = e1000e_phy_has_link_generic(hw,
+						     PHY_FORCE_LIMIT,
+						     100000,
+						     &link);
+		if (ret_val)
+			return ret_val;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_phy_hw_reset_ich8lan - Performs a PHY reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Resets the PHY
+ *  This is a function pointer entry point called by drivers
+ *  or other shared routines.
+ **/
+static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i;
+	u32 data, cnf_size, cnf_base_addr, sw_cfg_mask;
+	s32 ret_val;
+	u16 loop = E1000_ICH8_LAN_INIT_TIMEOUT;
+	u16 word_addr, reg_data, reg_addr, phy_page = 0;
+
+	ret_val = e1000e_phy_hw_reset_generic(hw);
+	if (ret_val)
+		return ret_val;
+
+	/* Initialize the PHY from the NVM on ICH platforms.  This
+	 * is needed due to an issue where the NVM configuration is
+	 * not properly autoloaded after power transitions.
+	 * Therefore, after each PHY reset, we will load the
+	 * configuration data out of the NVM manually.
+	 */
+	if (hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) {
+		struct e1000_adapter *adapter = hw->adapter;
+
+		/* Check if SW needs configure the PHY */
+		if ((adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
+		    (adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_M))
+			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
+		else
+			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
+
+		data = er32(FEXTNVM);
+		if (!(data & sw_cfg_mask))
+			return 0;
+
+		/* Wait for basic configuration completes before proceeding*/
+		do {
+			data = er32(STATUS);
+			data &= E1000_STATUS_LAN_INIT_DONE;
+			udelay(100);
+		} while ((!data) && --loop);
+
+		/* If basic configuration is incomplete before the above loop
+		 * count reaches 0, loading the configuration from NVM will
+		 * leave the PHY in a bad state possibly resulting in no link.
+		 */
+		if (loop == 0) {
+			hw_dbg(hw, "LAN_INIT_DONE not set, increase timeout\n");
+		}
+
+		/* Clear the Init Done bit for the next init event */
+		data = er32(STATUS);
+		data &= ~E1000_STATUS_LAN_INIT_DONE;
+		ew32(STATUS, data);
+
+		/* Make sure HW does not configure LCD from PHY
+		 * extended configuration before SW configuration */
+		data = er32(EXTCNF_CTRL);
+		if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
+			return 0;
+
+		cnf_size = er32(EXTCNF_SIZE);
+		cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
+		cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
+		if (!cnf_size)
+			return 0;
+
+		cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
+		cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
+
+		/* Configure LCD from extended configuration
+		 * region. */
+
+		/* cnf_base_addr is in DWORD */
+		word_addr = (u16)(cnf_base_addr << 1);
+
+		for (i = 0; i < cnf_size; i++) {
+			ret_val = e1000_read_nvm(hw,
+						(word_addr + i * 2),
+						1,
+						&reg_data);
+			if (ret_val)
+				return ret_val;
+
+			ret_val = e1000_read_nvm(hw,
+						(word_addr + i * 2 + 1),
+						1,
+						&reg_addr);
+			if (ret_val)
+				return ret_val;
+
+			/* Save off the PHY page for future writes. */
+			if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
+				phy_page = reg_data;
+				continue;
+			}
+
+			reg_addr |= phy_page;
+
+			ret_val = e1e_wphy(hw, (u32)reg_addr, reg_data);
+			if (ret_val)
+				return ret_val;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states
+ *  @hw: pointer to the HW structure
+ *
+ *  Populates "phy" structure with various feature states.
+ *  This function is only called by other family-specific
+ *  routines.
+ **/
+static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		return ret_val;
+
+	if (!link) {
+		hw_dbg(hw, "Phy info is only valid if link is up\n");
+		return -E1000_ERR_CONFIG;
+	}
+
+	ret_val = e1e_rphy(hw, IFE_PHY_SPECIAL_CONTROL, &data);
+	if (ret_val)
+		return ret_val;
+	phy->polarity_correction = (!(data & IFE_PSC_AUTO_POLARITY_DISABLE));
+
+	if (phy->polarity_correction) {
+		ret_val = e1000_check_polarity_ife_ich8lan(hw);
+		if (ret_val)
+			return ret_val;
+	} else {
+		/* Polarity is forced */
+		phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY)
+				      ? e1000_rev_polarity_reversed
+				      : e1000_rev_polarity_normal;
+	}
+
+	ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, &data);
+	if (ret_val)
+		return ret_val;
+
+	phy->is_mdix = (data & IFE_PMC_MDIX_STATUS);
+
+	/* The following parameters are undefined for 10/100 operation. */
+	phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+	phy->local_rx = e1000_1000t_rx_status_undefined;
+	phy->remote_rx = e1000_1000t_rx_status_undefined;
+
+	return 0;
+}
+
+/**
+ *  e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info
+ *  @hw: pointer to the HW structure
+ *
+ *  Wrapper for calling the get_phy_info routines for the appropriate phy type.
+ *  This is a function pointer entry point called by drivers
+ *  or other shared routines.
+ **/
+static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw)
+{
+	switch (hw->phy.type) {
+	case e1000_phy_ife:
+		return e1000_get_phy_info_ife_ich8lan(hw);
+		break;
+	case e1000_phy_igp_3:
+		return e1000e_get_phy_info_igp(hw);
+		break;
+	default:
+		break;
+	}
+
+	return -E1000_ERR_PHY_TYPE;
+}
+
+/**
+ *  e1000_check_polarity_ife_ich8lan - Check cable polarity for IFE PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Polarity is determined on the polarity reveral feature being enabled.
+ *  This function is only called by other family-specific
+ *  routines.
+ **/
+static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, offset, mask;
+
+	/* Polarity is determined based on the reversal feature
+	 * being enabled.
+	 */
+	if (phy->polarity_correction) {
+		offset	= IFE_PHY_EXTENDED_STATUS_CONTROL;
+		mask	= IFE_PESC_POLARITY_REVERSED;
+	} else {
+		offset	= IFE_PHY_SPECIAL_CONTROL;
+		mask	= IFE_PSC_FORCE_POLARITY;
+	}
+
+	ret_val = e1e_rphy(hw, offset, &phy_data);
+
+	if (!ret_val)
+		phy->cable_polarity = (phy_data & mask)
+				      ? e1000_rev_polarity_reversed
+				      : e1000_rev_polarity_normal;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
+ *  @hw: pointer to the HW structure
+ *  @active: TRUE to enable LPLU, FALSE to disable
+ *
+ *  Sets the LPLU D0 state according to the active flag.  When
+ *  activating LPLU this function also disables smart speed
+ *  and vice versa.  LPLU will not be activated unless the
+ *  device autonegotiation advertisement meets standards of
+ *  either 10 or 10/100 or 10/100/1000 at all duplexes.
+ *  This is a function pointer entry point only called by
+ *  PHY setup routines.
+ **/
+static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 phy_ctrl;
+	s32 ret_val = 0;
+	u16 data;
+
+	if (phy->type != e1000_phy_igp_3)
+		return ret_val;
+
+	phy_ctrl = er32(PHY_CTRL);
+
+	if (active) {
+		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
+		ew32(PHY_CTRL, phy_ctrl);
+
+		/* Call gig speed drop workaround on LPLU before accessing
+		 * any PHY registers */
+		if ((hw->mac.type == e1000_ich8lan) &&
+		    (hw->phy.type == e1000_phy_igp_3))
+			e1000e_gig_downshift_workaround_ich8lan(hw);
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
+		if (ret_val)
+			return ret_val;
+	} else {
+		phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
+		ew32(PHY_CTRL, phy_ctrl);
+
+		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained. */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+						    &data);
+			if (ret_val)
+				return ret_val;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+						     data);
+			if (ret_val)
+				return ret_val;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+						    &data);
+			if (ret_val)
+				return ret_val;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+						     data);
+			if (ret_val)
+				return ret_val;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
+ *  @hw: pointer to the HW structure
+ *  @active: TRUE to enable LPLU, FALSE to disable
+ *
+ *  Sets the LPLU D3 state according to the active flag.  When
+ *  activating LPLU this function also disables smart speed
+ *  and vice versa.  LPLU will not be activated unless the
+ *  device autonegotiation advertisement meets standards of
+ *  either 10 or 10/100 or 10/100/1000 at all duplexes.
+ *  This is a function pointer entry point only called by
+ *  PHY setup routines.
+ **/
+static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 phy_ctrl;
+	s32 ret_val;
+	u16 data;
+
+	phy_ctrl = er32(PHY_CTRL);
+
+	if (!active) {
+		phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
+		ew32(PHY_CTRL, phy_ctrl);
+		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained. */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = e1e_rphy(hw,
+						    IGP01E1000_PHY_PORT_CONFIG,
+						    &data);
+			if (ret_val)
+				return ret_val;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw,
+						     IGP01E1000_PHY_PORT_CONFIG,
+						     data);
+			if (ret_val)
+				return ret_val;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = e1e_rphy(hw,
+						    IGP01E1000_PHY_PORT_CONFIG,
+						    &data);
+			if (ret_val)
+				return ret_val;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw,
+						     IGP01E1000_PHY_PORT_CONFIG,
+						     data);
+			if (ret_val)
+				return ret_val;
+		}
+	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+		   (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+		   (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+		phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
+		ew32(PHY_CTRL, phy_ctrl);
+
+		/* Call gig speed drop workaround on LPLU before accessing
+		 * any PHY registers */
+		if ((hw->mac.type == e1000_ich8lan) &&
+		    (hw->phy.type == e1000_phy_igp_3))
+			e1000e_gig_downshift_workaround_ich8lan(hw);
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = e1e_rphy(hw,
+					    IGP01E1000_PHY_PORT_CONFIG,
+					    &data);
+		if (ret_val)
+			return ret_val;
+
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = e1e_wphy(hw,
+					     IGP01E1000_PHY_PORT_CONFIG,
+					     data);
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_read_nvm_ich8lan - Read word(s) from the NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset (in bytes) of the word(s) to read.
+ *  @words: Size of data to read in words
+ *  @data: Pointer to the word(s) to read at offset.
+ *
+ *  Reads a word(s) from the NVM using the flash access registers.
+ **/
+static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
+				  u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+	u32 act_offset;
+	s32 ret_val;
+	u16 i, word;
+
+	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
+	    (words == 0)) {
+		hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+		return -E1000_ERR_NVM;
+	}
+
+	ret_val = e1000_acquire_swflag_ich8lan(hw);
+	if (ret_val)
+		return ret_val;
+
+	/* Start with the bank offset, then add the relative offset. */
+	act_offset = (er32(EECD) & E1000_EECD_SEC1VAL)
+		     ? nvm->flash_bank_size
+		     : 0;
+	act_offset += offset;
+
+	for (i = 0; i < words; i++) {
+		if ((dev_spec->shadow_ram) &&
+		    (dev_spec->shadow_ram[offset+i].modified)) {
+			data[i] = dev_spec->shadow_ram[offset+i].value;
+		} else {
+			ret_val = e1000_read_flash_word_ich8lan(hw,
+								act_offset + i,
+								&word);
+			if (ret_val)
+				break;
+			data[i] = word;
+		}
+	}
+
+	e1000_release_swflag_ich8lan(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_flash_cycle_init_ich8lan - Initialize flash
+ *  @hw: pointer to the HW structure
+ *
+ *  This function does initial flash setup so that a new read/write/erase cycle
+ *  can be started.
+ **/
+static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
+{
+	union ich8_hws_flash_status hsfsts;
+	s32 ret_val = -E1000_ERR_NVM;
+	s32 i = 0;
+
+	hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+
+	/* Check if the flash descriptor is valid */
+	if (hsfsts.hsf_status.fldesvalid == 0) {
+		hw_dbg(hw, "Flash descriptor invalid.  "
+			 "SW Sequencing must be used.");
+		return -E1000_ERR_NVM;
+	}
+
+	/* Clear FCERR and DAEL in hw status by writing 1 */
+	hsfsts.hsf_status.flcerr = 1;
+	hsfsts.hsf_status.dael = 1;
+
+	ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
+
+	/* Either we should have a hardware SPI cycle in progress
+	 * bit to check against, in order to start a new cycle or
+	 * FDONE bit should be changed in the hardware so that it
+	 * is 1 after harware reset, which can then be used as an
+	 * indication whether a cycle is in progress or has been
+	 * completed.
+	 */
+
+	if (hsfsts.hsf_status.flcinprog == 0) {
+		/* There is no cycle running at present,
+		 * so we can start a cycle */
+		/* Begin by setting Flash Cycle Done. */
+		hsfsts.hsf_status.flcdone = 1;
+		ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
+		ret_val = 0;
+	} else {
+		/* otherwise poll for sometime so the current
+		 * cycle has a chance to end before giving up. */
+		for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
+			hsfsts.regval = __er16flash(hw, ICH_FLASH_HSFSTS);
+			if (hsfsts.hsf_status.flcinprog == 0) {
+				ret_val = 0;
+				break;
+			}
+			udelay(1);
+		}
+		if (ret_val == 0) {
+			/* Successful in waiting for previous cycle to timeout,
+			 * now set the Flash Cycle Done. */
+			hsfsts.hsf_status.flcdone = 1;
+			ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval);
+		} else {
+			hw_dbg(hw, "Flash controller busy, cannot get access");
+		}
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase)
+ *  @hw: pointer to the HW structure
+ *  @timeout: maximum time to wait for completion
+ *
+ *  This function starts a flash cycle and waits for its completion.
+ **/
+static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
+{
+	union ich8_hws_flash_ctrl hsflctl;
+	union ich8_hws_flash_status hsfsts;
+	s32 ret_val = -E1000_ERR_NVM;
+	u32 i = 0;
+
+	/* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
+	hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
+	hsflctl.hsf_ctrl.flcgo = 1;
+	ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
+
+	/* wait till FDONE bit is set to 1 */
+	do {
+		hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+		if (hsfsts.hsf_status.flcdone == 1)
+			break;
+		udelay(1);
+	} while (i++ < timeout);
+
+	if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0)
+		return 0;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_read_flash_word_ich8lan - Read word from flash
+ *  @hw: pointer to the HW structure
+ *  @offset: offset to data location
+ *  @data: pointer to the location for storing the data
+ *
+ *  Reads the flash word at offset into data.  Offset is converted
+ *  to bytes before read.
+ **/
+static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
+					 u16 *data)
+{
+	/* Must convert offset into bytes. */
+	offset <<= 1;
+
+	return e1000_read_flash_data_ich8lan(hw, offset, 2, data);
+}
+
+/**
+ *  e1000_read_flash_data_ich8lan - Read byte or word from NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset (in bytes) of the byte or word to read.
+ *  @size: Size of data to read, 1=byte 2=word
+ *  @data: Pointer to the word to store the value read.
+ *
+ *  Reads a byte or word from the NVM using the flash access registers.
+ **/
+static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
+					 u8 size, u16 *data)
+{
+	union ich8_hws_flash_status hsfsts;
+	union ich8_hws_flash_ctrl hsflctl;
+	u32 flash_linear_addr;
+	u32 flash_data = 0;
+	s32 ret_val = -E1000_ERR_NVM;
+	u8 count = 0;
+
+	if (size < 1  || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
+		return -E1000_ERR_NVM;
+
+	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+			    hw->nvm.flash_base_addr;
+
+	do {
+		udelay(1);
+		/* Steps */
+		ret_val = e1000_flash_cycle_init_ich8lan(hw);
+		if (ret_val != 0)
+			break;
+
+		hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
+		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+		hsflctl.hsf_ctrl.fldbcount = size - 1;
+		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
+		ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
+
+		ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
+
+		ret_val = e1000_flash_cycle_ich8lan(hw,
+						ICH_FLASH_READ_COMMAND_TIMEOUT);
+
+		/* Check if FCERR is set to 1, if set to 1, clear it
+		 * and try the whole sequence a few more times, else
+		 * read in (shift in) the Flash Data0, the order is
+		 * least significant byte first msb to lsb */
+		if (ret_val == 0) {
+			flash_data = er32flash(ICH_FLASH_FDATA0);
+			if (size == 1) {
+				*data = (u8)(flash_data & 0x000000FF);
+			} else if (size == 2) {
+				*data = (u16)(flash_data & 0x0000FFFF);
+			}
+			break;
+		} else {
+			/* If we've gotten here, then things are probably
+			 * completely hosed, but if the error condition is
+			 * detected, it won't hurt to give it another try...
+			 * ICH_FLASH_CYCLE_REPEAT_COUNT times.
+			 */
+			hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+			if (hsfsts.hsf_status.flcerr == 1) {
+				/* Repeat for some time before giving up. */
+				continue;
+			} else if (hsfsts.hsf_status.flcdone == 0) {
+				hw_dbg(hw, "Timeout error - flash cycle "
+					 "did not complete.");
+				break;
+			}
+		}
+	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_write_nvm_ich8lan - Write word(s) to the NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset (in bytes) of the word(s) to write.
+ *  @words: Size of data to write in words
+ *  @data: Pointer to the word(s) to write at offset.
+ *
+ *  Writes a byte or word to the NVM using the flash access registers.
+ **/
+static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
+				   u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+	s32 ret_val;
+	u16 i;
+
+	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
+	    (words == 0)) {
+		hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+		return -E1000_ERR_NVM;
+	}
+
+	ret_val = e1000_acquire_swflag_ich8lan(hw);
+	if (ret_val)
+		return ret_val;
+
+	for (i = 0; i < words; i++) {
+		dev_spec->shadow_ram[offset+i].modified = 1;
+		dev_spec->shadow_ram[offset+i].value = data[i];
+	}
+
+	e1000_release_swflag_ich8lan(hw);
+
+	return 0;
+}
+
+/**
+ *  e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
+ *  @hw: pointer to the HW structure
+ *
+ *  The NVM checksum is updated by calling the generic update_nvm_checksum,
+ *  which writes the checksum to the shadow ram.  The changes in the shadow
+ *  ram are then committed to the EEPROM by processing each bank at a time
+ *  checking for the modified bit and writing only the pending changes.
+ *  After a succesful commit, the shadow ram is cleared and is ready for
+ *  future writes.
+ **/
+static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+	u32 i, act_offset, new_bank_offset, old_bank_offset;
+	s32 ret_val;
+	u16 data;
+
+	ret_val = e1000e_update_nvm_checksum_generic(hw);
+	if (ret_val)
+		return ret_val;;
+
+	if (nvm->type != e1000_nvm_flash_sw)
+		return ret_val;;
+
+	ret_val = e1000_acquire_swflag_ich8lan(hw);
+	if (ret_val)
+		return ret_val;;
+
+	/* We're writing to the opposite bank so if we're on bank 1,
+	 * write to bank 0 etc.  We also need to erase the segment that
+	 * is going to be written */
+	if (!(er32(EECD) & E1000_EECD_SEC1VAL)) {
+		new_bank_offset = nvm->flash_bank_size;
+		old_bank_offset = 0;
+		e1000_erase_flash_bank_ich8lan(hw, 1);
+	} else {
+		old_bank_offset = nvm->flash_bank_size;
+		new_bank_offset = 0;
+		e1000_erase_flash_bank_ich8lan(hw, 0);
+	}
+
+	for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
+		/* Determine whether to write the value stored
+		 * in the other NVM bank or a modified value stored
+		 * in the shadow RAM */
+		if (dev_spec->shadow_ram[i].modified) {
+			data = dev_spec->shadow_ram[i].value;
+		} else {
+			e1000_read_flash_word_ich8lan(hw,
+						      i + old_bank_offset,
+						      &data);
+		}
+
+		/* If the word is 0x13, then make sure the signature bits
+		 * (15:14) are 11b until the commit has completed.
+		 * This will allow us to write 10b which indicates the
+		 * signature is valid.  We want to do this after the write
+		 * has completed so that we don't mark the segment valid
+		 * while the write is still in progress */
+		if (i == E1000_ICH_NVM_SIG_WORD)
+			data |= E1000_ICH_NVM_SIG_MASK;
+
+		/* Convert offset to bytes. */
+		act_offset = (i + new_bank_offset) << 1;
+
+		udelay(100);
+		/* Write the bytes to the new bank. */
+		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+							       act_offset,
+							       (u8)data);
+		if (ret_val)
+			break;
+
+		udelay(100);
+		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+							  act_offset + 1,
+							  (u8)(data >> 8));
+		if (ret_val)
+			break;
+	}
+
+	/* Don't bother writing the segment valid bits if sector
+	 * programming failed. */
+	if (ret_val) {
+		hw_dbg(hw, "Flash commit failed.\n");
+		e1000_release_swflag_ich8lan(hw);
+		return ret_val;
+	}
+
+	/* Finally validate the new segment by setting bit 15:14
+	 * to 10b in word 0x13 , this can be done without an
+	 * erase as well since these bits are 11 to start with
+	 * and we need to change bit 14 to 0b */
+	act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
+	e1000_read_flash_word_ich8lan(hw, act_offset, &data);
+	data &= 0xBFFF;
+	ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
+						       act_offset * 2 + 1,
+						       (u8)(data >> 8));
+	if (ret_val) {
+		e1000_release_swflag_ich8lan(hw);
+		return ret_val;
+	}
+
+	/* And invalidate the previously valid segment by setting
+	 * its signature word (0x13) high_byte to 0b. This can be
+	 * done without an erase because flash erase sets all bits
+	 * to 1's. We can write 1's to 0's without an erase */
+	act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
+	ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
+	if (ret_val) {
+		e1000_release_swflag_ich8lan(hw);
+		return ret_val;
+	}
+
+	/* Great!  Everything worked, we can now clear the cached entries. */
+	for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) {
+		dev_spec->shadow_ram[i].modified = 0;
+		dev_spec->shadow_ram[i].value = 0xFFFF;
+	}
+
+	e1000_release_swflag_ich8lan(hw);
+
+	/* Reload the EEPROM, or else modifications will not appear
+	 * until after the next adapter reset.
+	 */
+	e1000e_reload_nvm(hw);
+	msleep(10);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
+ *  If the bit is 0, that the EEPROM had been modified, but the checksum was not
+ *  calculated, in which case we need to calculate the checksum and set bit 6.
+ **/
+static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val;
+	u16 data;
+
+	/* Read 0x19 and check bit 6.  If this bit is 0, the checksum
+	 * needs to be fixed.  This bit is an indication that the NVM
+	 * was prepared by OEM software and did not calculate the
+	 * checksum...a likely scenario.
+	 */
+	ret_val = e1000_read_nvm(hw, 0x19, 1, &data);
+	if (ret_val)
+		return ret_val;
+
+	if ((data & 0x40) == 0) {
+		data |= 0x40;
+		ret_val = e1000_write_nvm(hw, 0x19, 1, &data);
+		if (ret_val)
+			return ret_val;
+		ret_val = e1000e_update_nvm_checksum(hw);
+		if (ret_val)
+			return ret_val;
+	}
+
+	return e1000e_validate_nvm_checksum_generic(hw);
+}
+
+/**
+ *  e1000_write_flash_data_ich8lan - Writes bytes to the NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset (in bytes) of the byte/word to read.
+ *  @size: Size of data to read, 1=byte 2=word
+ *  @data: The byte(s) to write to the NVM.
+ *
+ *  Writes one/two bytes to the NVM using the flash access registers.
+ **/
+static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
+					  u8 size, u16 data)
+{
+	union ich8_hws_flash_status hsfsts;
+	union ich8_hws_flash_ctrl hsflctl;
+	u32 flash_linear_addr;
+	u32 flash_data = 0;
+	s32 ret_val;
+	u8 count = 0;
+
+	if (size < 1 || size > 2 || data > size * 0xff ||
+	    offset > ICH_FLASH_LINEAR_ADDR_MASK)
+		return -E1000_ERR_NVM;
+
+	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
+			    hw->nvm.flash_base_addr;
+
+	do {
+		udelay(1);
+		/* Steps */
+		ret_val = e1000_flash_cycle_init_ich8lan(hw);
+		if (ret_val)
+			break;
+
+		hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
+		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+		hsflctl.hsf_ctrl.fldbcount = size -1;
+		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
+		ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
+
+		ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
+
+		if (size == 1)
+			flash_data = (u32)data & 0x00FF;
+		else
+			flash_data = (u32)data;
+
+		ew32flash(ICH_FLASH_FDATA0, flash_data);
+
+		/* check if FCERR is set to 1 , if set to 1, clear it
+		 * and try the whole sequence a few more times else done */
+		ret_val = e1000_flash_cycle_ich8lan(hw,
+					       ICH_FLASH_WRITE_COMMAND_TIMEOUT);
+		if (!ret_val)
+			break;
+
+		/* If we're here, then things are most likely
+		 * completely hosed, but if the error condition
+		 * is detected, it won't hurt to give it another
+		 * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
+		 */
+		hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+		if (hsfsts.hsf_status.flcerr == 1)
+			/* Repeat for some time before giving up. */
+			continue;
+		if (hsfsts.hsf_status.flcdone == 0) {
+			hw_dbg(hw, "Timeout error - flash cycle "
+				 "did not complete.");
+			break;
+		}
+	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_write_flash_byte_ich8lan - Write a single byte to NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The index of the byte to read.
+ *  @data: The byte to write to the NVM.
+ *
+ *  Writes a single byte to the NVM using the flash access registers.
+ **/
+static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
+					  u8 data)
+{
+	u16 word = (u16)data;
+
+	return e1000_write_flash_data_ich8lan(hw, offset, 1, word);
+}
+
+/**
+ *  e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
+ *  @hw: pointer to the HW structure
+ *  @offset: The offset of the byte to write.
+ *  @byte: The byte to write to the NVM.
+ *
+ *  Writes a single byte to the NVM using the flash access registers.
+ *  Goes through a retry algorithm before giving up.
+ **/
+static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
+						u32 offset, u8 byte)
+{
+	s32 ret_val;
+	u16 program_retries;
+
+	ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
+	if (!ret_val)
+		return ret_val;
+
+	for (program_retries = 0; program_retries < 100; program_retries++) {
+		hw_dbg(hw, "Retrying Byte %2.2X at offset %u\n", byte, offset);
+		udelay(100);
+		ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
+		if (!ret_val)
+			break;
+	}
+	if (program_retries == 100)
+		return -E1000_ERR_NVM;
+
+	return 0;
+}
+
+/**
+ *  e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
+ *  @hw: pointer to the HW structure
+ *  @bank: 0 for first bank, 1 for second bank, etc.
+ *
+ *  Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
+ *  bank N is 4096 * N + flash_reg_addr.
+ **/
+static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	union ich8_hws_flash_status hsfsts;
+	union ich8_hws_flash_ctrl hsflctl;
+	u32 flash_linear_addr;
+	/* bank size is in 16bit words - adjust to bytes */
+	u32 flash_bank_size = nvm->flash_bank_size * 2;
+	s32 ret_val;
+	s32 count = 0;
+	s32 iteration;
+	s32 sector_size;
+	s32 j;
+
+	hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+
+	/* Determine HW Sector size: Read BERASE bits of hw flash status
+	 * register */
+	/* 00: The Hw sector is 256 bytes, hence we need to erase 16
+	 *     consecutive sectors.  The start index for the nth Hw sector
+	 *     can be calculated as = bank * 4096 + n * 256
+	 * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
+	 *     The start index for the nth Hw sector can be calculated
+	 *     as = bank * 4096
+	 * 10: The Hw sector is 8K bytes, nth sector = bank * 8192
+	 *     (ich9 only, otherwise error condition)
+	 * 11: The Hw sector is 64K bytes, nth sector = bank * 65536
+	 */
+	switch (hsfsts.hsf_status.berasesz) {
+	case 0:
+		/* Hw sector size 256 */
+		sector_size = ICH_FLASH_SEG_SIZE_256;
+		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256;
+		break;
+	case 1:
+		sector_size = ICH_FLASH_SEG_SIZE_4K;
+		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_4K;
+		break;
+	case 2:
+		if (hw->mac.type == e1000_ich9lan) {
+			sector_size = ICH_FLASH_SEG_SIZE_8K;
+			iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_8K;
+		} else {
+			return -E1000_ERR_NVM;
+		}
+		break;
+	case 3:
+		sector_size = ICH_FLASH_SEG_SIZE_64K;
+		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_64K;
+		break;
+	default:
+		return -E1000_ERR_NVM;
+	}
+
+	/* Start with the base address, then add the sector offset. */
+	flash_linear_addr = hw->nvm.flash_base_addr;
+	flash_linear_addr += (bank) ? (sector_size * iteration) : 0;
+
+	for (j = 0; j < iteration ; j++) {
+		do {
+			/* Steps */
+			ret_val = e1000_flash_cycle_init_ich8lan(hw);
+			if (ret_val)
+				return ret_val;
+
+			/* Write a value 11 (block Erase) in Flash
+			 * Cycle field in hw flash control */
+			hsflctl.regval = er16flash(ICH_FLASH_HSFCTL);
+			hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
+			ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval);
+
+			/* Write the last 24 bits of an index within the
+			 * block into Flash Linear address field in Flash
+			 * Address.
+			 */
+			flash_linear_addr += (j * sector_size);
+			ew32flash(ICH_FLASH_FADDR, flash_linear_addr);
+
+			ret_val = e1000_flash_cycle_ich8lan(hw,
+					       ICH_FLASH_ERASE_COMMAND_TIMEOUT);
+			if (ret_val == 0)
+				break;
+
+			/* Check if FCERR is set to 1.  If 1,
+			 * clear it and try the whole sequence
+			 * a few more times else Done */
+			hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
+			if (hsfsts.hsf_status.flcerr == 1)
+				/* repeat for some time before
+				 * giving up */
+				continue;
+			else if (hsfsts.hsf_status.flcdone == 0)
+				return ret_val;
+		} while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_valid_led_default_ich8lan - Set the default LED settings
+ *  @hw: pointer to the HW structure
+ *  @data: Pointer to the LED settings
+ *
+ *  Reads the LED default settings from the NVM to data.  If the NVM LED
+ *  settings is all 0's or F's, set the LED default to a valid LED default
+ *  setting.
+ **/
+static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
+{
+	s32 ret_val;
+
+	ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
+	if (ret_val) {
+		hw_dbg(hw, "NVM Read Error\n");
+		return ret_val;
+	}
+
+	if (*data == ID_LED_RESERVED_0000 ||
+	    *data == ID_LED_RESERVED_FFFF)
+		*data = ID_LED_DEFAULT_ICH8LAN;
+
+	return 0;
+}
+
+/**
+ *  e1000_get_bus_info_ich8lan - Get/Set the bus type and width
+ *  @hw: pointer to the HW structure
+ *
+ *  ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
+ *  register, so the the bus width is hard coded.
+ **/
+static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_bus_info *bus = &hw->bus;
+	s32 ret_val;
+
+	ret_val = e1000e_get_bus_info_pcie(hw);
+
+	/* ICH devices are "PCI Express"-ish.  They have
+	 * a configuration space, but do not contain
+	 * PCI Express Capability registers, so bus width
+	 * must be hardcoded.
+	 */
+	if (bus->width == e1000_bus_width_unknown)
+		bus->width = e1000_bus_width_pcie_x1;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_reset_hw_ich8lan - Reset the hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  Does a full reset of the hardware which includes a reset of the PHY and
+ *  MAC.
+ **/
+static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
+{
+	u32 ctrl, icr, kab;
+	s32 ret_val;
+
+	/* Prevent the PCI-E bus from sticking if there is no TLP connection
+	 * on the last TLP read/write transaction when MAC is reset.
+	 */
+	ret_val = e1000e_disable_pcie_master(hw);
+	if (ret_val) {
+		hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+	}
+
+	hw_dbg(hw, "Masking off all interrupts\n");
+	ew32(IMC, 0xffffffff);
+
+	/* Disable the Transmit and Receive units.  Then delay to allow
+	 * any pending transactions to complete before we hit the MAC
+	 * with the global reset.
+	 */
+	ew32(RCTL, 0);
+	ew32(TCTL, E1000_TCTL_PSP);
+	e1e_flush();
+
+	msleep(10);
+
+	/* Workaround for ICH8 bit corruption issue in FIFO memory */
+	if (hw->mac.type == e1000_ich8lan) {
+		/* Set Tx and Rx buffer allocation to 8k apiece. */
+		ew32(PBA, E1000_PBA_8K);
+		/* Set Packet Buffer Size to 16k. */
+		ew32(PBS, E1000_PBS_16K);
+	}
+
+	ctrl = er32(CTRL);
+
+	if (!e1000_check_reset_block(hw)) {
+		/* PHY HW reset requires MAC CORE reset at the same
+		 * time to make sure the interface between MAC and the
+		 * external PHY is reset.
+		 */
+		ctrl |= E1000_CTRL_PHY_RST;
+	}
+	ret_val = e1000_acquire_swflag_ich8lan(hw);
+	hw_dbg(hw, "Issuing a global reset to ich8lan");
+	ew32(CTRL, (ctrl | E1000_CTRL_RST));
+	msleep(20);
+
+	ret_val = e1000e_get_auto_rd_done(hw);
+	if (ret_val) {
+		/*
+		 * When auto config read does not complete, do not
+		 * return with an error. This can happen in situations
+		 * where there is no eeprom and prevents getting link.
+		 */
+		hw_dbg(hw, "Auto Read Done did not complete\n");
+	}
+
+	ew32(IMC, 0xffffffff);
+	icr = er32(ICR);
+
+	kab = er32(KABGTXD);
+	kab |= E1000_KABGTXD_BGSQLBIAS;
+	ew32(KABGTXD, kab);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_init_hw_ich8lan - Initialize the hardware
+ *  @hw: pointer to the HW structure
+ *
+ *  Prepares the hardware for transmit and receive by doing the following:
+ *   - initialize hardware bits
+ *   - initialize LED identification
+ *   - setup receive address registers
+ *   - setup flow control
+ *   - setup transmit discriptors
+ *   - clear statistics
+ **/
+static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 ctrl_ext, txdctl, snoop;
+	s32 ret_val;
+	u16 i;
+
+	e1000_initialize_hw_bits_ich8lan(hw);
+
+	/* Initialize identification LED */
+	ret_val = e1000e_id_led_init(hw);
+	if (ret_val) {
+		hw_dbg(hw, "Error initializing identification LED\n");
+		return ret_val;
+	}
+
+	/* Setup the receive address. */
+	e1000e_init_rx_addrs(hw, mac->rar_entry_count);
+
+	/* Zero out the Multicast HASH table */
+	hw_dbg(hw, "Zeroing the MTA\n");
+	for (i = 0; i < mac->mta_reg_count; i++)
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+
+	/* Setup link and flow control */
+	ret_val = e1000_setup_link_ich8lan(hw);
+
+	/* Set the transmit descriptor write-back policy for both queues */
+	txdctl = er32(TXDCTL);
+	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
+		 E1000_TXDCTL_FULL_TX_DESC_WB;
+	txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
+		 E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+	ew32(TXDCTL, txdctl);
+	txdctl = er32(TXDCTL1);
+	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
+		 E1000_TXDCTL_FULL_TX_DESC_WB;
+	txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
+		 E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
+	ew32(TXDCTL1, txdctl);
+
+	/* ICH8 has opposite polarity of no_snoop bits.
+	 * By default, we should use snoop behavior. */
+	if (mac->type == e1000_ich8lan)
+		snoop = PCIE_ICH8_SNOOP_ALL;
+	else
+		snoop = (u32) ~(PCIE_NO_SNOOP_ALL);
+	e1000e_set_pcie_no_snoop(hw, snoop);
+
+	ctrl_ext = er32(CTRL_EXT);
+	ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
+	ew32(CTRL_EXT, ctrl_ext);
+
+	/* Clear all of the statistics registers (clear on read).  It is
+	 * important that we do this after we have tried to establish link
+	 * because the symbol error count will increment wildly if there
+	 * is no link.
+	 */
+	e1000_clear_hw_cntrs_ich8lan(hw);
+
+	return 0;
+}
+/**
+ *  e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets/Clears required hardware bits necessary for correctly setting up the
+ *  hardware for transmit and receive.
+ **/
+static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
+{
+	u32 reg;
+
+	/* Extended Device Control */
+	reg = er32(CTRL_EXT);
+	reg |= (1 << 22);
+	ew32(CTRL_EXT, reg);
+
+	/* Transmit Descriptor Control 0 */
+	reg = er32(TXDCTL);
+	reg |= (1 << 22);
+	ew32(TXDCTL, reg);
+
+	/* Transmit Descriptor Control 1 */
+	reg = er32(TXDCTL1);
+	reg |= (1 << 22);
+	ew32(TXDCTL1, reg);
+
+	/* Transmit Arbitration Control 0 */
+	reg = er32(TARC0);
+	if (hw->mac.type == e1000_ich8lan)
+		reg |= (1 << 28) | (1 << 29);
+	reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
+	ew32(TARC0, reg);
+
+	/* Transmit Arbitration Control 1 */
+	reg = er32(TARC1);
+	if (er32(TCTL) & E1000_TCTL_MULR)
+		reg &= ~(1 << 28);
+	else
+		reg |= (1 << 28);
+	reg |= (1 << 24) | (1 << 26) | (1 << 30);
+	ew32(TARC1, reg);
+
+	/* Device Status */
+	if (hw->mac.type == e1000_ich8lan) {
+		reg = er32(STATUS);
+		reg &= ~(1 << 31);
+		ew32(STATUS, reg);
+	}
+}
+
+/**
+ *  e1000_setup_link_ich8lan - Setup flow control and link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines which flow control settings to use, then configures flow
+ *  control.  Calls the appropriate media-specific link configuration
+ *  function.  Assuming the adapter has a valid link partner, a valid link
+ *  should be established.  Assumes the hardware has previously been reset
+ *  and the transmitter and receiver are not enabled.
+ **/
+static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+
+	if (e1000_check_reset_block(hw))
+		return 0;
+
+	/* ICH parts do not have a word in the NVM to determine
+	 * the default flow control setting, so we explicitly
+	 * set it to full.
+	 */
+	if (mac->fc == e1000_fc_default)
+		mac->fc = e1000_fc_full;
+
+	mac->original_fc = mac->fc;
+
+	hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", mac->fc);
+
+	/* Continue to configure the copper link. */
+	ret_val = e1000_setup_copper_link_ich8lan(hw);
+	if (ret_val)
+		return ret_val;
+
+	ew32(FCTTV, mac->fc_pause_time);
+
+	return e1000e_set_fc_watermarks(hw);
+}
+
+/**
+ *  e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the kumeran interface to the PHY to wait the appropriate time
+ *  when polling the PHY, then call the generic setup_copper_link to finish
+ *  configuring the copper link.
+ **/
+static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val;
+	u16 reg_data;
+
+	ctrl = er32(CTRL);
+	ctrl |= E1000_CTRL_SLU;
+	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	ew32(CTRL, ctrl);
+
+	/* Set the mac to wait the maximum time between each iteration
+	 * and increase the max iterations when polling the phy;
+	 * this fixes erroneous timeouts at 10Mbps. */
+	ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF);
+	if (ret_val)
+		return ret_val;
+	ret_val = e1000e_read_kmrn_reg(hw, GG82563_REG(0x34, 9), &reg_data);
+	if (ret_val)
+		return ret_val;
+	reg_data |= 0x3F;
+	ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data);
+	if (ret_val)
+		return ret_val;
+
+	if (hw->phy.type == e1000_phy_igp_3) {
+		ret_val = e1000e_copper_link_setup_igp(hw);
+		if (ret_val)
+			return ret_val;
+	}
+
+	return e1000e_setup_copper_link(hw);
+}
+
+/**
+ *  e1000_get_link_up_info_ich8lan - Get current link speed and duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: pointer to store current link speed
+ *  @duplex: pointer to store the current link duplex
+ *
+ *  Calls the generic get_speed_and_duplex to retreive the current link
+ *  information and then calls the Kumeran lock loss workaround for links at
+ *  gigabit speeds.
+ **/
+static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
+					  u16 *duplex)
+{
+	s32 ret_val;
+
+	ret_val = e1000e_get_speed_and_duplex_copper(hw, speed, duplex);
+	if (ret_val)
+		return ret_val;
+
+	if ((hw->mac.type == e1000_ich8lan) &&
+	    (hw->phy.type == e1000_phy_igp_3) &&
+	    (*speed == SPEED_1000)) {
+		ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
+ *  @hw: pointer to the HW structure
+ *
+ *  Work-around for 82566 Kumeran PCS lock loss:
+ *  On link status change (i.e. PCI reset, speed change) and link is up and
+ *  speed is gigabit-
+ *    0) if workaround is optionally disabled do nothing
+ *    1) wait 1ms for Kumeran link to come up
+ *    2) check Kumeran Diagnostic register PCS lock loss bit
+ *    3) if not set the link is locked (all is good), otherwise...
+ *    4) reset the PHY
+ *    5) repeat up to 10 times
+ *  Note: this is only called for IGP3 copper when speed is 1gb.
+ **/
+static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
+{
+	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+	u32 phy_ctrl;
+	s32 ret_val;
+	u16 i, data;
+	bool link;
+
+	if (!dev_spec->kmrn_lock_loss_workaround_enabled)
+		return 0;
+
+	/* Make sure link is up before proceeding.  If not just return.
+	 * Attempting this while link is negotiating fouled up link
+	 * stability */
+	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+	if (!link)
+		return 0;
+
+	for (i = 0; i < 10; i++) {
+		/* read once to clear */
+		ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data);
+		if (ret_val)
+			return ret_val;
+		/* and again to get new status */
+		ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data);
+		if (ret_val)
+			return ret_val;
+
+		/* check for PCS lock */
+		if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS))
+			return 0;
+
+		/* Issue PHY reset */
+		e1000_phy_hw_reset(hw);
+		mdelay(5);
+	}
+	/* Disable GigE link negotiation */
+	phy_ctrl = er32(PHY_CTRL);
+	phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE |
+		     E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+	ew32(PHY_CTRL, phy_ctrl);
+
+	/* Call gig speed drop workaround on Giga disable before accessing
+	 * any PHY registers */
+	e1000e_gig_downshift_workaround_ich8lan(hw);
+
+	/* unable to acquire PCS lock */
+	return -E1000_ERR_PHY;
+}
+
+/**
+ *  e1000_set_kmrn_lock_loss_workaound_ich8lan - Set Kumeran workaround state
+ *  @hw: pointer to the HW structure
+ *  @state: boolean value used to set the current Kumaran workaround state
+ *
+ *  If ICH8, set the current Kumeran workaround state (enabled - TRUE
+ *  /disabled - FALSE).
+ **/
+void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
+						 bool state)
+{
+	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
+
+	if (hw->mac.type != e1000_ich8lan) {
+		hw_dbg(hw, "Workaround applies to ICH8 only.\n");
+		return;
+	}
+
+	dev_spec->kmrn_lock_loss_workaround_enabled = state;
+}
+
+/**
+ *  e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
+ *  @hw: pointer to the HW structure
+ *
+ *  Workaround for 82566 power-down on D3 entry:
+ *    1) disable gigabit link
+ *    2) write VR power-down enable
+ *    3) read it back
+ *  Continue if successful, else issue LCD reset and repeat
+ **/
+void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
+{
+	u32 reg;
+	u16 data;
+	u8  retry = 0;
+
+	if (hw->phy.type != e1000_phy_igp_3)
+		return;
+
+	/* Try the workaround twice (if needed) */
+	do {
+		/* Disable link */
+		reg = er32(PHY_CTRL);
+		reg |= (E1000_PHY_CTRL_GBE_DISABLE |
+			E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+		ew32(PHY_CTRL, reg);
+
+		/* Call gig speed drop workaround on Giga disable before
+		 * accessing any PHY registers */
+		if (hw->mac.type == e1000_ich8lan)
+			e1000e_gig_downshift_workaround_ich8lan(hw);
+
+		/* Write VR power-down enable */
+		e1e_rphy(hw, IGP3_VR_CTRL, &data);
+		data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
+		e1e_wphy(hw, IGP3_VR_CTRL, data | IGP3_VR_CTRL_MODE_SHUTDOWN);
+
+		/* Read it back and test */
+		e1e_rphy(hw, IGP3_VR_CTRL, &data);
+		data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
+		if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry)
+			break;
+
+		/* Issue PHY reset and repeat at most one more time */
+		reg = er32(CTRL);
+		ew32(CTRL, reg | E1000_CTRL_PHY_RST);
+		retry++;
+	} while (retry);
+}
+
+/**
+ *  e1000e_gig_downshift_workaround_ich8lan - WoL from S5 stops working
+ *  @hw: pointer to the HW structure
+ *
+ *  Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
+ *  LPLU, Giga disable, MDIC PHY reset):
+ *    1) Set Kumeran Near-end loopback
+ *    2) Clear Kumeran Near-end loopback
+ *  Should only be called for ICH8[m] devices with IGP_3 Phy.
+ **/
+void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
+{
+	s32 ret_val;
+	u16 reg_data;
+
+	if ((hw->mac.type != e1000_ich8lan) ||
+	    (hw->phy.type != e1000_phy_igp_3))
+		return;
+
+	ret_val = e1000e_read_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
+				      &reg_data);
+	if (ret_val)
+		return;
+	reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
+	ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
+				       reg_data);
+	if (ret_val)
+		return;
+	reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
+	ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
+				       reg_data);
+}
+
+/**
+ *  e1000_cleanup_led_ich8lan - Restore the default LED operation
+ *  @hw: pointer to the HW structure
+ *
+ *  Return the LED back to the default configuration.
+ **/
+static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw)
+{
+	if (hw->phy.type == e1000_phy_ife)
+		return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0);
+
+	ew32(LEDCTL, hw->mac.ledctl_default);
+	return 0;
+}
+
+/**
+ *  e1000_led_on_ich8lan - Turn LED's on
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn on the LED's.
+ **/
+static s32 e1000_led_on_ich8lan(struct e1000_hw *hw)
+{
+	if (hw->phy.type == e1000_phy_ife)
+		return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+				(IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
+
+	ew32(LEDCTL, hw->mac.ledctl_mode2);
+	return 0;
+}
+
+/**
+ *  e1000_led_off_ich8lan - Turn LED's off
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn off the LED's.
+ **/
+static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
+{
+	if (hw->phy.type == e1000_phy_ife)
+		return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+			       (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
+
+	ew32(LEDCTL, hw->mac.ledctl_mode1);
+	return 0;
+}
+
+/**
+ *  e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears hardware counters specific to the silicon family and calls
+ *  clear_hw_cntrs_generic to clear all general purpose counters.
+ **/
+static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
+{
+	u32 temp;
+
+	e1000e_clear_hw_cntrs_base(hw);
+
+	temp = er32(ALGNERRC);
+	temp = er32(RXERRC);
+	temp = er32(TNCRS);
+	temp = er32(CEXTERR);
+	temp = er32(TSCTC);
+	temp = er32(TSCTFC);
+
+	temp = er32(MGTPRC);
+	temp = er32(MGTPDC);
+	temp = er32(MGTPTC);
+
+	temp = er32(IAC);
+	temp = er32(ICRXOC);
+
+}
+
+static struct e1000_mac_operations ich8_mac_ops = {
+	.mng_mode_enab		= E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
+	.check_for_link		= e1000e_check_for_copper_link,
+	.cleanup_led		= e1000_cleanup_led_ich8lan,
+	.clear_hw_cntrs		= e1000_clear_hw_cntrs_ich8lan,
+	.get_bus_info		= e1000_get_bus_info_ich8lan,
+	.get_link_up_info	= e1000_get_link_up_info_ich8lan,
+	.led_on			= e1000_led_on_ich8lan,
+	.led_off		= e1000_led_off_ich8lan,
+	.mc_addr_list_update	= e1000e_mc_addr_list_update_generic,
+	.reset_hw		= e1000_reset_hw_ich8lan,
+	.init_hw		= e1000_init_hw_ich8lan,
+	.setup_link		= e1000_setup_link_ich8lan,
+	.setup_physical_interface= e1000_setup_copper_link_ich8lan,
+};
+
+static struct e1000_phy_operations ich8_phy_ops = {
+	.acquire_phy		= e1000_acquire_swflag_ich8lan,
+	.check_reset_block	= e1000_check_reset_block_ich8lan,
+	.commit_phy		= NULL,
+	.force_speed_duplex	= e1000_phy_force_speed_duplex_ich8lan,
+	.get_cfg_done		= e1000e_get_cfg_done,
+	.get_cable_length	= e1000e_get_cable_length_igp_2,
+	.get_phy_info		= e1000_get_phy_info_ich8lan,
+	.read_phy_reg		= e1000e_read_phy_reg_igp,
+	.release_phy		= e1000_release_swflag_ich8lan,
+	.reset_phy		= e1000_phy_hw_reset_ich8lan,
+	.set_d0_lplu_state	= e1000_set_d0_lplu_state_ich8lan,
+	.set_d3_lplu_state	= e1000_set_d3_lplu_state_ich8lan,
+	.write_phy_reg		= e1000e_write_phy_reg_igp,
+};
+
+static struct e1000_nvm_operations ich8_nvm_ops = {
+	.acquire_nvm		= e1000_acquire_swflag_ich8lan,
+	.read_nvm	 	= e1000_read_nvm_ich8lan,
+	.release_nvm		= e1000_release_swflag_ich8lan,
+	.update_nvm		= e1000_update_nvm_checksum_ich8lan,
+	.valid_led_default	= e1000_valid_led_default_ich8lan,
+	.validate_nvm		= e1000_validate_nvm_checksum_ich8lan,
+	.write_nvm		= e1000_write_nvm_ich8lan,
+};
+
+struct e1000_info e1000_ich8_info = {
+	.mac			= e1000_ich8lan,
+	.flags			= FLAG_HAS_WOL
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_FLASH
+				  | FLAG_APME_IN_WUC,
+	.pba			= 8,
+	.get_invariants		= e1000_get_invariants_ich8lan,
+	.mac_ops		= &ich8_mac_ops,
+	.phy_ops		= &ich8_phy_ops,
+	.nvm_ops		= &ich8_nvm_ops,
+};
+
+struct e1000_info e1000_ich9_info = {
+	.mac			= e1000_ich9lan,
+	.flags			= FLAG_HAS_JUMBO_FRAMES
+				  | FLAG_HAS_WOL
+				  | FLAG_RX_CSUM_ENABLED
+				  | FLAG_HAS_CTRLEXT_ON_LOAD
+				  | FLAG_HAS_AMT
+				  | FLAG_HAS_ERT
+				  | FLAG_HAS_FLASH
+				  | FLAG_APME_IN_WUC,
+	.pba			= 10,
+	.get_invariants		= e1000_get_invariants_ich8lan,
+	.mac_ops		= &ich8_mac_ops,
+	.phy_ops		= &ich8_phy_ops,
+	.nvm_ops		= &ich8_nvm_ops,
+};
+
diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c
new file mode 100644
index 0000000..0bdeca3
--- /dev/null
+++ b/drivers/net/e1000e/lib.c
@@ -0,0 +1,2493 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include "e1000.h"
+
+enum e1000_mng_mode {
+	e1000_mng_mode_none = 0,
+	e1000_mng_mode_asf,
+	e1000_mng_mode_pt,
+	e1000_mng_mode_ipmi,
+	e1000_mng_mode_host_if_only
+};
+
+#define E1000_FACTPS_MNGCG		0x20000000
+
+#define E1000_IAMT_SIGNATURE		0x544D4149 /* Intel(R) Active Management
+						    * Technology signature */
+
+/**
+ *  e1000e_get_bus_info_pcie - Get PCIe bus information
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines and stores the system bus information for a particular
+ *  network interface.  The following bus information is determined and stored:
+ *  bus speed, bus width, type (PCIe), and PCIe function.
+ **/
+s32 e1000e_get_bus_info_pcie(struct e1000_hw *hw)
+{
+	struct e1000_bus_info *bus = &hw->bus;
+	struct e1000_adapter *adapter = hw->adapter;
+	u32 status;
+	u16 pcie_link_status, pci_header_type, cap_offset;
+
+	cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+	if (!cap_offset) {
+		bus->width = e1000_bus_width_unknown;
+	} else {
+		pci_read_config_word(adapter->pdev,
+				     cap_offset + PCIE_LINK_STATUS,
+				     &pcie_link_status);
+		bus->width = (enum e1000_bus_width)((pcie_link_status &
+						     PCIE_LINK_WIDTH_MASK) >>
+						    PCIE_LINK_WIDTH_SHIFT);
+	}
+
+	pci_read_config_word(adapter->pdev, PCI_HEADER_TYPE_REGISTER,
+			     &pci_header_type);
+	if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) {
+		status = er32(STATUS);
+		bus->func = (status & E1000_STATUS_FUNC_MASK)
+			    >> E1000_STATUS_FUNC_SHIFT;
+	} else {
+		bus->func = 0;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000e_write_vfta - Write value to VLAN filter table
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset in VLAN filter table
+ *  @value: register value written to VLAN filter table
+ *
+ *  Writes value at the given offset in the register array which stores
+ *  the VLAN filter table.
+ **/
+void e1000e_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
+{
+	E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
+	e1e_flush();
+}
+
+/**
+ *  e1000e_init_rx_addrs - Initialize receive address's
+ *  @hw: pointer to the HW structure
+ *  @rar_count: receive address registers
+ *
+ *  Setups the receive address registers by setting the base receive address
+ *  register to the devices MAC address and clearing all the other receive
+ *  address registers to 0.
+ **/
+void e1000e_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
+{
+	u32 i;
+
+	/* Setup the receive address */
+	hw_dbg(hw, "Programming MAC Address into RAR[0]\n");
+
+	e1000e_rar_set(hw, hw->mac.addr, 0);
+
+	/* Zero out the other (rar_entry_count - 1) receive addresses */
+	hw_dbg(hw, "Clearing RAR[1-%u]\n", rar_count-1);
+	for (i = 1; i < rar_count; i++) {
+		E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1), 0);
+		e1e_flush();
+		E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((i << 1) + 1), 0);
+		e1e_flush();
+	}
+}
+
+/**
+ *  e1000e_rar_set - Set receive address register
+ *  @hw: pointer to the HW structure
+ *  @addr: pointer to the receive address
+ *  @index: receive address array register
+ *
+ *  Sets the receive address array register at index to the address passed
+ *  in by addr.
+ **/
+void e1000e_rar_set(struct e1000_hw *hw, u8 *addr, u32 index)
+{
+	u32 rar_low, rar_high;
+
+	/* HW expects these in little endian so we reverse the byte order
+	 * from network order (big endian) to little endian
+	 */
+	rar_low = ((u32) addr[0] |
+		   ((u32) addr[1] << 8) |
+		    ((u32) addr[2] << 16) | ((u32) addr[3] << 24));
+
+	rar_high = ((u32) addr[4] | ((u32) addr[5] << 8));
+
+	rar_high |= E1000_RAH_AV;
+
+	E1000_WRITE_REG_ARRAY(hw, E1000_RA, (index << 1), rar_low);
+	E1000_WRITE_REG_ARRAY(hw, E1000_RA, ((index << 1) + 1), rar_high);
+}
+
+/**
+ *  e1000_mta_set - Set multicast filter table address
+ *  @hw: pointer to the HW structure
+ *  @hash_value: determines the MTA register and bit to set
+ *
+ *  The multicast table address is a register array of 32-bit registers.
+ *  The hash_value is used to determine what register the bit is in, the
+ *  current value is read, the new bit is OR'd in and the new value is
+ *  written back into the register.
+ **/
+static void e1000_mta_set(struct e1000_hw *hw, u32 hash_value)
+{
+	u32 hash_bit, hash_reg, mta;
+
+	/* The MTA is a register array of 32-bit registers. It is
+	 * treated like an array of (32*mta_reg_count) bits.  We want to
+	 * set bit BitArray[hash_value]. So we figure out what register
+	 * the bit is in, read it, OR in the new bit, then write
+	 * back the new value.  The (hw->mac.mta_reg_count - 1) serves as a
+	 * mask to bits 31:5 of the hash value which gives us the
+	 * register we're modifying.  The hash bit within that register
+	 * is determined by the lower 5 bits of the hash value.
+	 */
+	hash_reg = (hash_value >> 5) & (hw->mac.mta_reg_count - 1);
+	hash_bit = hash_value & 0x1F;
+
+	mta = E1000_READ_REG_ARRAY(hw, E1000_MTA, hash_reg);
+
+	mta |= (1 << hash_bit);
+
+	E1000_WRITE_REG_ARRAY(hw, E1000_MTA, hash_reg, mta);
+	e1e_flush();
+}
+
+/**
+ *  e1000_hash_mc_addr - Generate a multicast hash value
+ *  @hw: pointer to the HW structure
+ *  @mc_addr: pointer to a multicast address
+ *
+ *  Generates a multicast address hash value which is used to determine
+ *  the multicast filter table array address and new table value.  See
+ *  e1000_mta_set_generic()
+ **/
+static u32 e1000_hash_mc_addr(struct e1000_hw *hw, u8 *mc_addr)
+{
+	u32 hash_value, hash_mask;
+	u8 bit_shift = 0;
+
+	/* Register count multiplied by bits per register */
+	hash_mask = (hw->mac.mta_reg_count * 32) - 1;
+
+	/* For a mc_filter_type of 0, bit_shift is the number of left-shifts
+	 * where 0xFF would still fall within the hash mask. */
+	while (hash_mask >> bit_shift != 0xFF)
+		bit_shift++;
+
+	/* The portion of the address that is used for the hash table
+	 * is determined by the mc_filter_type setting.
+	 * The algorithm is such that there is a total of 8 bits of shifting.
+	 * The bit_shift for a mc_filter_type of 0 represents the number of
+	 * left-shifts where the MSB of mc_addr[5] would still fall within
+	 * the hash_mask.  Case 0 does this exactly.  Since there are a total
+	 * of 8 bits of shifting, then mc_addr[4] will shift right the
+	 * remaining number of bits. Thus 8 - bit_shift.  The rest of the
+	 * cases are a variation of this algorithm...essentially raising the
+	 * number of bits to shift mc_addr[5] left, while still keeping the
+	 * 8-bit shifting total.
+	 */
+	/* For example, given the following Destination MAC Address and an
+	 * mta register count of 128 (thus a 4096-bit vector and 0xFFF mask),
+	 * we can see that the bit_shift for case 0 is 4.  These are the hash
+	 * values resulting from each mc_filter_type...
+	 * [0] [1] [2] [3] [4] [5]
+	 * 01  AA  00  12  34  56
+	 * LSB		 MSB
+	 *
+	 * case 0: hash_value = ((0x34 >> 4) | (0x56 << 4)) & 0xFFF = 0x563
+	 * case 1: hash_value = ((0x34 >> 3) | (0x56 << 5)) & 0xFFF = 0xAC6
+	 * case 2: hash_value = ((0x34 >> 2) | (0x56 << 6)) & 0xFFF = 0x163
+	 * case 3: hash_value = ((0x34 >> 0) | (0x56 << 8)) & 0xFFF = 0x634
+	 */
+	switch (hw->mac.mc_filter_type) {
+	default:
+	case 0:
+		break;
+	case 1:
+		bit_shift += 1;
+		break;
+	case 2:
+		bit_shift += 2;
+		break;
+	case 3:
+		bit_shift += 4;
+		break;
+	}
+
+	hash_value = hash_mask & (((mc_addr[4] >> (8 - bit_shift)) |
+				  (((u16) mc_addr[5]) << bit_shift)));
+
+	return hash_value;
+}
+
+/**
+ *  e1000e_mc_addr_list_update_generic - Update Multicast addresses
+ *  @hw: pointer to the HW structure
+ *  @mc_addr_list: array of multicast addresses to program
+ *  @mc_addr_count: number of multicast addresses to program
+ *  @rar_used_count: the first RAR register free to program
+ *  @rar_count: total number of supported Receive Address Registers
+ *
+ *  Updates the Receive Address Registers and Multicast Table Array.
+ *  The caller must have a packed mc_addr_list of multicast addresses.
+ *  The parameter rar_count will usually be hw->mac.rar_entry_count
+ *  unless there are workarounds that change this.
+ **/
+void e1000e_mc_addr_list_update_generic(struct e1000_hw *hw,
+				       u8 *mc_addr_list, u32 mc_addr_count,
+				       u32 rar_used_count, u32 rar_count)
+{
+	u32 hash_value;
+	u32 i;
+
+	/* Load the first set of multicast addresses into the exact
+	 * filters (RAR).  If there are not enough to fill the RAR
+	 * array, clear the filters.
+	 */
+	for (i = rar_used_count; i < rar_count; i++) {
+		if (mc_addr_count) {
+			e1000e_rar_set(hw, mc_addr_list, i);
+			mc_addr_count--;
+			mc_addr_list += ETH_ALEN;
+		} else {
+			E1000_WRITE_REG_ARRAY(hw, E1000_RA, i << 1, 0);
+			e1e_flush();
+			E1000_WRITE_REG_ARRAY(hw, E1000_RA, (i << 1) + 1, 0);
+			e1e_flush();
+		}
+	}
+
+	/* Clear the old settings from the MTA */
+	hw_dbg(hw, "Clearing MTA\n");
+	for (i = 0; i < hw->mac.mta_reg_count; i++) {
+		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
+		e1e_flush();
+	}
+
+	/* Load any remaining multicast addresses into the hash table. */
+	for (; mc_addr_count > 0; mc_addr_count--) {
+		hash_value = e1000_hash_mc_addr(hw, mc_addr_list);
+		hw_dbg(hw, "Hash value = 0x%03X\n", hash_value);
+		e1000_mta_set(hw, hash_value);
+		mc_addr_list += ETH_ALEN;
+	}
+}
+
+/**
+ *  e1000e_clear_hw_cntrs_base - Clear base hardware counters
+ *  @hw: pointer to the HW structure
+ *
+ *  Clears the base hardware counters by reading the counter registers.
+ **/
+void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw)
+{
+	u32 temp;
+
+	temp = er32(CRCERRS);
+	temp = er32(SYMERRS);
+	temp = er32(MPC);
+	temp = er32(SCC);
+	temp = er32(ECOL);
+	temp = er32(MCC);
+	temp = er32(LATECOL);
+	temp = er32(COLC);
+	temp = er32(DC);
+	temp = er32(SEC);
+	temp = er32(RLEC);
+	temp = er32(XONRXC);
+	temp = er32(XONTXC);
+	temp = er32(XOFFRXC);
+	temp = er32(XOFFTXC);
+	temp = er32(FCRUC);
+	temp = er32(GPRC);
+	temp = er32(BPRC);
+	temp = er32(MPRC);
+	temp = er32(GPTC);
+	temp = er32(GORCL);
+	temp = er32(GORCH);
+	temp = er32(GOTCL);
+	temp = er32(GOTCH);
+	temp = er32(RNBC);
+	temp = er32(RUC);
+	temp = er32(RFC);
+	temp = er32(ROC);
+	temp = er32(RJC);
+	temp = er32(TORL);
+	temp = er32(TORH);
+	temp = er32(TOTL);
+	temp = er32(TOTH);
+	temp = er32(TPR);
+	temp = er32(TPT);
+	temp = er32(MPTC);
+	temp = er32(BPTC);
+}
+
+/**
+ *  e1000e_check_for_copper_link - Check for link (Copper)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks to see of the link status of the hardware has changed.  If a
+ *  change in link status has been detected, then we read the PHY registers
+ *  to get the current speed/duplex if link exists.
+ **/
+s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	bool link;
+
+	/* We only want to go out to the PHY registers to see if Auto-Neg
+	 * has completed and/or if our link status has changed.  The
+	 * get_link_status flag is set upon receiving a Link Status
+	 * Change or Rx Sequence Error interrupt.
+	 */
+	if (!mac->get_link_status)
+		return 0;
+
+	/* First we want to see if the MII Status Register reports
+	 * link.  If so, then we want to get the current speed/duplex
+	 * of the PHY.
+	 */
+	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		return ret_val;
+
+	if (!link)
+		return ret_val; /* No link detected */
+
+	mac->get_link_status = 0;
+
+	/* Check if there was DownShift, must be checked
+	 * immediately after link-up */
+	e1000e_check_downshift(hw);
+
+	/* If we are forcing speed/duplex, then we simply return since
+	 * we have already determined whether we have link or not.
+	 */
+	if (!mac->autoneg) {
+		ret_val = -E1000_ERR_CONFIG;
+		return ret_val;
+	}
+
+	/* Auto-Neg is enabled.  Auto Speed Detection takes care
+	 * of MAC speed/duplex configuration.  So we only need to
+	 * configure Collision Distance in the MAC.
+	 */
+	e1000e_config_collision_dist(hw);
+
+	/* Configure Flow Control now that Auto-Neg has completed.
+	 * First, we need to restore the desired flow control
+	 * settings because we may have had to re-autoneg with a
+	 * different link partner.
+	 */
+	ret_val = e1000e_config_fc_after_link_up(hw);
+	if (ret_val) {
+		hw_dbg(hw, "Error configuring flow control\n");
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_check_for_fiber_link - Check for link (Fiber)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks for link up on the hardware.  If link is not up and we have
+ *  a signal, then we need to force link up.
+ **/
+s32 e1000e_check_for_fiber_link(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 rxcw;
+	u32 ctrl;
+	u32 status;
+	s32 ret_val;
+
+	ctrl = er32(CTRL);
+	status = er32(STATUS);
+	rxcw = er32(RXCW);
+
+	/* If we don't have link (auto-negotiation failed or link partner
+	 * cannot auto-negotiate), the cable is plugged in (we have signal),
+	 * and our link partner is not trying to auto-negotiate with us (we
+	 * are receiving idles or data), we need to force link up. We also
+	 * need to give auto-negotiation time to complete, in case the cable
+	 * was just plugged in. The autoneg_failed flag does this.
+	 */
+	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+	if ((ctrl & E1000_CTRL_SWDPIN1) && (!(status & E1000_STATUS_LU)) &&
+	    (!(rxcw & E1000_RXCW_C))) {
+		if (mac->autoneg_failed == 0) {
+			mac->autoneg_failed = 1;
+			return 0;
+		}
+		hw_dbg(hw, "NOT RXing /C/, disable AutoNeg and force link.\n");
+
+		/* Disable auto-negotiation in the TXCW register */
+		ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+		/* Force link-up and also force full-duplex. */
+		ctrl = er32(CTRL);
+		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+		ew32(CTRL, ctrl);
+
+		/* Configure Flow Control after forcing link up. */
+		ret_val = e1000e_config_fc_after_link_up(hw);
+		if (ret_val) {
+			hw_dbg(hw, "Error configuring flow control\n");
+			return ret_val;
+		}
+	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+		/* If we are forcing link and we are receiving /C/ ordered
+		 * sets, re-enable auto-negotiation in the TXCW register
+		 * and disable forced link in the Device Control register
+		 * in an attempt to auto-negotiate with our link partner.
+		 */
+		hw_dbg(hw, "RXing /C/, enable AutoNeg and stop forcing link.\n");
+		ew32(TXCW, mac->txcw);
+		ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+		mac->serdes_has_link = 1;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000e_check_for_serdes_link - Check for link (Serdes)
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks for link up on the hardware.  If link is not up and we have
+ *  a signal, then we need to force link up.
+ **/
+s32 e1000e_check_for_serdes_link(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 rxcw;
+	u32 ctrl;
+	u32 status;
+	s32 ret_val;
+
+	ctrl = er32(CTRL);
+	status = er32(STATUS);
+	rxcw = er32(RXCW);
+
+	/* If we don't have link (auto-negotiation failed or link partner
+	 * cannot auto-negotiate), and our link partner is not trying to
+	 * auto-negotiate with us (we are receiving idles or data),
+	 * we need to force link up. We also need to give auto-negotiation
+	 * time to complete.
+	 */
+	/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
+	if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) {
+		if (mac->autoneg_failed == 0) {
+			mac->autoneg_failed = 1;
+			return 0;
+		}
+		hw_dbg(hw, "NOT RXing /C/, disable AutoNeg and force link.\n");
+
+		/* Disable auto-negotiation in the TXCW register */
+		ew32(TXCW, (mac->txcw & ~E1000_TXCW_ANE));
+
+		/* Force link-up and also force full-duplex. */
+		ctrl = er32(CTRL);
+		ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+		ew32(CTRL, ctrl);
+
+		/* Configure Flow Control after forcing link up. */
+		ret_val = e1000e_config_fc_after_link_up(hw);
+		if (ret_val) {
+			hw_dbg(hw, "Error configuring flow control\n");
+			return ret_val;
+		}
+	} else if ((ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+		/* If we are forcing link and we are receiving /C/ ordered
+		 * sets, re-enable auto-negotiation in the TXCW register
+		 * and disable forced link in the Device Control register
+		 * in an attempt to auto-negotiate with our link partner.
+		 */
+		hw_dbg(hw, "RXing /C/, enable AutoNeg and stop forcing link.\n");
+		ew32(TXCW, mac->txcw);
+		ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
+
+		mac->serdes_has_link = 1;
+	} else if (!(E1000_TXCW_ANE & er32(TXCW))) {
+		/* If we force link for non-auto-negotiation switch, check
+		 * link status based on MAC synchronization for internal
+		 * serdes media type.
+		 */
+		/* SYNCH bit and IV bit are sticky. */
+		udelay(10);
+		if (E1000_RXCW_SYNCH & er32(RXCW)) {
+			if (!(rxcw & E1000_RXCW_IV)) {
+				mac->serdes_has_link = 1;
+				hw_dbg(hw, "SERDES: Link is up.\n");
+			}
+		} else {
+			mac->serdes_has_link = 0;
+			hw_dbg(hw, "SERDES: Link is down.\n");
+		}
+	}
+
+	if (E1000_TXCW_ANE & er32(TXCW)) {
+		status = er32(STATUS);
+		mac->serdes_has_link = (status & E1000_STATUS_LU);
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_set_default_fc_generic - Set flow control default values
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the EEPROM for the default values for flow control and store the
+ *  values.
+ **/
+static s32 e1000_set_default_fc_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	u16 nvm_data;
+
+	if (mac->fc != e1000_fc_default)
+		return 0;
+
+	/* Read and store word 0x0F of the EEPROM. This word contains bits
+	 * that determine the hardware's default PAUSE (flow control) mode,
+	 * a bit that determines whether the HW defaults to enabling or
+	 * disabling auto-negotiation, and the direction of the
+	 * SW defined pins. If there is no SW over-ride of the flow
+	 * control setting, then the variable hw->fc will
+	 * be initialized based on a value in the EEPROM.
+	 */
+	ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data);
+
+	if (ret_val) {
+		hw_dbg(hw, "NVM Read Error\n");
+		return ret_val;
+	}
+
+	if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0)
+		mac->fc = e1000_fc_none;
+	else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) ==
+		 NVM_WORD0F_ASM_DIR)
+		mac->fc = e1000_fc_tx_pause;
+	else
+		mac->fc = e1000_fc_full;
+
+	return 0;
+}
+
+/**
+ *  e1000e_setup_link - Setup flow control and link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines which flow control settings to use, then configures flow
+ *  control.  Calls the appropriate media-specific link configuration
+ *  function.  Assuming the adapter has a valid link partner, a valid link
+ *  should be established.  Assumes the hardware has previously been reset
+ *  and the transmitter and receiver are not enabled.
+ **/
+s32 e1000e_setup_link(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+
+	/* In the case of the phy reset being blocked, we already have a link.
+	 * We do not need to set it up again.
+	 */
+	if (e1000_check_reset_block(hw))
+		return 0;
+
+	/*
+	 * If flow control is set to default, set flow control based on
+	 * the EEPROM flow control settings.
+	 */
+	if (mac->fc == e1000_fc_default) {
+		ret_val = e1000_set_default_fc_generic(hw);
+		if (ret_val)
+			return ret_val;
+	}
+
+	/* We want to save off the original Flow Control configuration just
+	 * in case we get disconnected and then reconnected into a different
+	 * hub or switch with different Flow Control capabilities.
+	 */
+	mac->original_fc = mac->fc;
+
+	hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", mac->fc);
+
+	/* Call the necessary media_type subroutine to configure the link. */
+	ret_val = mac->ops.setup_physical_interface(hw);
+	if (ret_val)
+		return ret_val;
+
+	/* Initialize the flow control address, type, and PAUSE timer
+	 * registers to their default values.  This is done even if flow
+	 * control is disabled, because it does not hurt anything to
+	 * initialize these registers.
+	 */
+	hw_dbg(hw, "Initializing the Flow Control address, type and timer regs\n");
+	ew32(FCT, FLOW_CONTROL_TYPE);
+	ew32(FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+	ew32(FCAL, FLOW_CONTROL_ADDRESS_LOW);
+
+	ew32(FCTTV, mac->fc_pause_time);
+
+	return e1000e_set_fc_watermarks(hw);
+}
+
+/**
+ *  e1000_commit_fc_settings_generic - Configure flow control
+ *  @hw: pointer to the HW structure
+ *
+ *  Write the flow control settings to the Transmit Config Word Register (TXCW)
+ *  base on the flow control settings in e1000_mac_info.
+ **/
+static s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 txcw;
+
+	/* Check for a software override of the flow control settings, and
+	 * setup the device accordingly.  If auto-negotiation is enabled, then
+	 * software will have to set the "PAUSE" bits to the correct value in
+	 * the Transmit Config Word Register (TXCW) and re-start auto-
+	 * negotiation.  However, if auto-negotiation is disabled, then
+	 * software will have to manually configure the two flow control enable
+	 * bits in the CTRL register.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause frames,
+	 *	  but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames but we
+	 *	  do not support receiving pause frames).
+	 *      3:  Both Rx and TX flow control (symmetric) are enabled.
+	 */
+	switch (mac->fc) {
+	case e1000_fc_none:
+		/* Flow control completely disabled by a software over-ride. */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+		break;
+	case e1000_fc_rx_pause:
+		/* RX Flow control is enabled and TX Flow control is disabled
+		 * by a software over-ride. Since there really isn't a way to
+		 * advertise that we are capable of RX Pause ONLY, we will
+		 * advertise that we support both symmetric and asymmetric RX
+		 * PAUSE.  Later, we will disable the adapter's ability to send
+		 * PAUSE frames.
+		 */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+		break;
+	case e1000_fc_tx_pause:
+		/* TX Flow control is enabled, and RX Flow control is disabled,
+		 * by a software over-ride.
+		 */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+		break;
+	case e1000_fc_full:
+		/* Flow control (both RX and TX) is enabled by a software
+		 * over-ride.
+		 */
+		txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+		break;
+	default:
+		hw_dbg(hw, "Flow control param set incorrectly\n");
+		return -E1000_ERR_CONFIG;
+		break;
+	}
+
+	ew32(TXCW, txcw);
+	mac->txcw = txcw;
+
+	return 0;
+}
+
+/**
+ *  e1000_poll_fiber_serdes_link_generic - Poll for link up
+ *  @hw: pointer to the HW structure
+ *
+ *  Polls for link up by reading the status register, if link fails to come
+ *  up with auto-negotiation, then the link is forced if a signal is detected.
+ **/
+static s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 i, status;
+	s32 ret_val;
+
+	/* If we have a signal (the cable is plugged in, or assumed true for
+	 * serdes media) then poll for a "Link-Up" indication in the Device
+	 * Status Register.  Time-out if a link isn't seen in 500 milliseconds
+	 * seconds (Auto-negotiation should complete in less than 500
+	 * milliseconds even if the other end is doing it in SW).
+	 */
+	for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
+		msleep(10);
+		status = er32(STATUS);
+		if (status & E1000_STATUS_LU)
+			break;
+	}
+	if (i == FIBER_LINK_UP_LIMIT) {
+		hw_dbg(hw, "Never got a valid link from auto-neg!!!\n");
+		mac->autoneg_failed = 1;
+		/* AutoNeg failed to achieve a link, so we'll call
+		 * mac->check_for_link. This routine will force the
+		 * link up if we detect a signal. This will allow us to
+		 * communicate with non-autonegotiating link partners.
+		 */
+		ret_val = mac->ops.check_for_link(hw);
+		if (ret_val) {
+			hw_dbg(hw, "Error while checking for link\n");
+			return ret_val;
+		}
+		mac->autoneg_failed = 0;
+	} else {
+		mac->autoneg_failed = 0;
+		hw_dbg(hw, "Valid Link Found\n");
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000e_setup_fiber_serdes_link - Setup link for fiber/serdes
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures collision distance and flow control for fiber and serdes
+ *  links.  Upon successful setup, poll for link.
+ **/
+s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 ret_val;
+
+	ctrl = er32(CTRL);
+
+	/* Take the link out of reset */
+	ctrl &= ~E1000_CTRL_LRST;
+
+	e1000e_config_collision_dist(hw);
+
+	ret_val = e1000_commit_fc_settings_generic(hw);
+	if (ret_val)
+		return ret_val;
+
+	/* Since auto-negotiation is enabled, take the link out of reset (the
+	 * link will be in reset, because we previously reset the chip). This
+	 * will restart auto-negotiation.  If auto-negotiation is successful
+	 * then the link-up status bit will be set and the flow control enable
+	 * bits (RFCE and TFCE) will be set according to their negotiated value.
+	 */
+	hw_dbg(hw, "Auto-negotiation enabled\n");
+
+	ew32(CTRL, ctrl);
+	e1e_flush();
+	msleep(1);
+
+	/* For these adapters, the SW defineable pin 1 is set when the optics
+	 * detect a signal.  If we have a signal, then poll for a "Link-Up"
+	 * indication.
+	 */
+	if (hw->media_type == e1000_media_type_internal_serdes ||
+	    (er32(CTRL) & E1000_CTRL_SWDPIN1)) {
+		ret_val = e1000_poll_fiber_serdes_link_generic(hw);
+	} else {
+		hw_dbg(hw, "No signal detected\n");
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000e_config_collision_dist - Configure collision distance
+ *  @hw: pointer to the HW structure
+ *
+ *  Configures the collision distance to the default value and is used
+ *  during link setup. Currently no func pointer exists and all
+ *  implementations are handled in the generic version of this function.
+ **/
+void e1000e_config_collision_dist(struct e1000_hw *hw)
+{
+	u32 tctl;
+
+	tctl = er32(TCTL);
+
+	tctl &= ~E1000_TCTL_COLD;
+	tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+	ew32(TCTL, tctl);
+	e1e_flush();
+}
+
+/**
+ *  e1000e_set_fc_watermarks - Set flow control high/low watermarks
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets the flow control high/low threshold (watermark) registers.  If
+ *  flow control XON frame transmission is enabled, then set XON frame
+ *  tansmission as well.
+ **/
+s32 e1000e_set_fc_watermarks(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 fcrtl = 0, fcrth = 0;
+
+	/* Set the flow control receive threshold registers.  Normally,
+	 * these registers will be set to a default threshold that may be
+	 * adjusted later by the driver's runtime code.  However, if the
+	 * ability to transmit pause frames is not enabled, then these
+	 * registers will be set to 0.
+	 */
+	if (mac->fc & e1000_fc_tx_pause) {
+		/* We need to set up the Receive Threshold high and low water
+		 * marks as well as (optionally) enabling the transmission of
+		 * XON frames.
+		 */
+		fcrtl = mac->fc_low_water;
+		fcrtl |= E1000_FCRTL_XONE;
+		fcrth = mac->fc_high_water;
+	}
+	ew32(FCRTL, fcrtl);
+	ew32(FCRTH, fcrth);
+
+	return 0;
+}
+
+/**
+ *  e1000e_force_mac_fc - Force the MAC's flow control settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Force the MAC's flow control settings.  Sets the TFCE and RFCE bits in the
+ *  device control register to reflect the adapter settings.  TFCE and RFCE
+ *  need to be explicitly set by software when a copper PHY is used because
+ *  autonegotiation is managed by the PHY rather than the MAC.  Software must
+ *  also configure these bits when link is forced on a fiber connection.
+ **/
+s32 e1000e_force_mac_fc(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 ctrl;
+
+	ctrl = er32(CTRL);
+
+	/* Because we didn't get link via the internal auto-negotiation
+	 * mechanism (we either forced link or we got link via PHY
+	 * auto-neg), we have to manually enable/disable transmit an
+	 * receive flow control.
+	 *
+	 * The "Case" statement below enables/disable flow control
+	 * according to the "mac->fc" parameter.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause
+	 *	  frames but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames
+	 *	  frames but we do not receive pause frames).
+	 *      3:  Both Rx and TX flow control (symmetric) is enabled.
+	 *  other:  No other values should be possible at this point.
+	 */
+	hw_dbg(hw, "mac->fc = %u\n", mac->fc);
+
+	switch (mac->fc) {
+	case e1000_fc_none:
+		ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+		break;
+	case e1000_fc_rx_pause:
+		ctrl &= (~E1000_CTRL_TFCE);
+		ctrl |= E1000_CTRL_RFCE;
+		break;
+	case e1000_fc_tx_pause:
+		ctrl &= (~E1000_CTRL_RFCE);
+		ctrl |= E1000_CTRL_TFCE;
+		break;
+	case e1000_fc_full:
+		ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+		break;
+	default:
+		hw_dbg(hw, "Flow control param set incorrectly\n");
+		return -E1000_ERR_CONFIG;
+	}
+
+	ew32(CTRL, ctrl);
+
+	return 0;
+}
+
+/**
+ *  e1000e_config_fc_after_link_up - Configures flow control after link
+ *  @hw: pointer to the HW structure
+ *
+ *  Checks the status of auto-negotiation after link up to ensure that the
+ *  speed and duplex were not forced.  If the link needed to be forced, then
+ *  flow control needs to be forced also.  If auto-negotiation is enabled
+ *  and did not fail, then we configure flow control based on our link
+ *  partner.
+ **/
+s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val = 0;
+	u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
+	u16 speed, duplex;
+
+	/* Check for the case where we have fiber media and auto-neg failed
+	 * so we had to force link.  In this case, we need to force the
+	 * configuration of the MAC to match the "fc" parameter.
+	 */
+	if (mac->autoneg_failed) {
+		if (hw->media_type == e1000_media_type_fiber ||
+		    hw->media_type == e1000_media_type_internal_serdes)
+			ret_val = e1000e_force_mac_fc(hw);
+	} else {
+		if (hw->media_type == e1000_media_type_copper)
+			ret_val = e1000e_force_mac_fc(hw);
+	}
+
+	if (ret_val) {
+		hw_dbg(hw, "Error forcing flow control settings\n");
+		return ret_val;
+	}
+
+	/* Check for the case where we have copper media and auto-neg is
+	 * enabled.  In this case, we need to check and see if Auto-Neg
+	 * has completed, and if so, how the PHY and link partner has
+	 * flow control configured.
+	 */
+	if ((hw->media_type == e1000_media_type_copper) && mac->autoneg) {
+		/* Read the MII Status Register and check to see if AutoNeg
+		 * has completed.  We read this twice because this reg has
+		 * some "sticky" (latched) bits.
+		 */
+		ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);
+		if (ret_val)
+			return ret_val;
+		ret_val = e1e_rphy(hw, PHY_STATUS, &mii_status_reg);
+		if (ret_val)
+			return ret_val;
+
+		if (!(mii_status_reg & MII_SR_AUTONEG_COMPLETE)) {
+			hw_dbg(hw, "Copper PHY and Auto Neg "
+				 "has not completed.\n");
+			return ret_val;
+		}
+
+		/* The AutoNeg process has completed, so we now need to
+		 * read both the Auto Negotiation Advertisement
+		 * Register (Address 4) and the Auto_Negotiation Base
+		 * Page Ability Register (Address 5) to determine how
+		 * flow control was negotiated.
+		 */
+		ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg);
+		if (ret_val)
+			return ret_val;
+		ret_val = e1e_rphy(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg);
+		if (ret_val)
+			return ret_val;
+
+		/* Two bits in the Auto Negotiation Advertisement Register
+		 * (Address 4) and two bits in the Auto Negotiation Base
+		 * Page Ability Register (Address 5) determine flow control
+		 * for both the PHY and the link partner.  The following
+		 * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+		 * 1999, describes these PAUSE resolution bits and how flow
+		 * control is determined based upon these settings.
+		 * NOTE:  DC = Don't Care
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+		 *-------|---------|-------|---------|--------------------
+		 *   0   |    0    |  DC   |   DC    | e1000_fc_none
+		 *   0   |    1    |   0   |   DC    | e1000_fc_none
+		 *   0   |    1    |   1   |    0    | e1000_fc_none
+		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+		 *   1   |    0    |   0   |   DC    | e1000_fc_none
+		 *   1   |   DC    |   1   |   DC    | e1000_fc_full
+		 *   1   |    1    |   0   |    0    | e1000_fc_none
+		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+		 *
+		 */
+		/* Are both PAUSE bits set to 1?  If so, this implies
+		 * Symmetric Flow Control is enabled at both ends.  The
+		 * ASM_DIR bits are irrelevant per the spec.
+		 *
+		 * For Symmetric Flow Control:
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   1   |   DC    |   1   |   DC    | E1000_fc_full
+		 *
+		 */
+		if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+		    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+			/* Now we need to check if the user selected RX ONLY
+			 * of pause frames.  In this case, we had to advertise
+			 * FULL flow control because we could not advertise RX
+			 * ONLY. Hence, we must now check to see if we need to
+			 * turn OFF  the TRANSMISSION of PAUSE frames.
+			 */
+			if (mac->original_fc == e1000_fc_full) {
+				mac->fc = e1000_fc_full;
+				hw_dbg(hw, "Flow Control = FULL.\r\n");
+			} else {
+				mac->fc = e1000_fc_rx_pause;
+				hw_dbg(hw, "Flow Control = "
+					 "RX PAUSE frames only.\r\n");
+			}
+		}
+		/* For receiving PAUSE frames ONLY.
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+		 *
+		 */
+		else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+			  (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+			  (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+			  (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+			mac->fc = e1000_fc_tx_pause;
+			hw_dbg(hw, "Flow Control = TX PAUSE frames only.\r\n");
+		}
+		/* For transmitting PAUSE frames ONLY.
+		 *
+		 *   LOCAL DEVICE  |   LINK PARTNER
+		 * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+		 *-------|---------|-------|---------|--------------------
+		 *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+		 *
+		 */
+		else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+			 (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+			 !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+			 (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+			mac->fc = e1000_fc_rx_pause;
+			hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n");
+		}
+		/* Per the IEEE spec, at this point flow control should be
+		 * disabled.  However, we want to consider that we could
+		 * be connected to a legacy switch that doesn't advertise
+		 * desired flow control, but can be forced on the link
+		 * partner.  So if we advertised no flow control, that is
+		 * what we will resolve to.  If we advertised some kind of
+		 * receive capability (Rx Pause Only or Full Flow Control)
+		 * and the link partner advertised none, we will configure
+		 * ourselves to enable Rx Flow Control only.  We can do
+		 * this safely for two reasons:  If the link partner really
+		 * didn't want flow control enabled, and we enable Rx, no
+		 * harm done since we won't be receiving any PAUSE frames
+		 * anyway.  If the intent on the link partner was to have
+		 * flow control enabled, then by us enabling RX only, we
+		 * can at least receive pause frames and process them.
+		 * This is a good idea because in most cases, since we are
+		 * predominantly a server NIC, more times than not we will
+		 * be asked to delay transmission of packets than asking
+		 * our link partner to pause transmission of frames.
+		 */
+		else if ((mac->original_fc == e1000_fc_none) ||
+			 (mac->original_fc == e1000_fc_tx_pause)) {
+			mac->fc = e1000_fc_none;
+			hw_dbg(hw, "Flow Control = NONE.\r\n");
+		} else {
+			mac->fc = e1000_fc_rx_pause;
+			hw_dbg(hw, "Flow Control = RX PAUSE frames only.\r\n");
+		}
+
+		/* Now we need to do one last check...  If we auto-
+		 * negotiated to HALF DUPLEX, flow control should not be
+		 * enabled per IEEE 802.3 spec.
+		 */
+		ret_val = mac->ops.get_link_up_info(hw, &speed, &duplex);
+		if (ret_val) {
+			hw_dbg(hw, "Error getting link speed and duplex\n");
+			return ret_val;
+		}
+
+		if (duplex == HALF_DUPLEX)
+			mac->fc = e1000_fc_none;
+
+		/* Now we call a subroutine to actually force the MAC
+		 * controller to use the correct flow control settings.
+		 */
+		ret_val = e1000e_force_mac_fc(hw);
+		if (ret_val) {
+			hw_dbg(hw, "Error forcing flow control settings\n");
+			return ret_val;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000e_get_speed_and_duplex_copper - Retreive current speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: stores the current speed
+ *  @duplex: stores the current duplex
+ *
+ *  Read the status register for the current speed/duplex and store the current
+ *  speed and duplex for copper connections.
+ **/
+s32 e1000e_get_speed_and_duplex_copper(struct e1000_hw *hw, u16 *speed, u16 *duplex)
+{
+	u32 status;
+
+	status = er32(STATUS);
+	if (status & E1000_STATUS_SPEED_1000) {
+		*speed = SPEED_1000;
+		hw_dbg(hw, "1000 Mbs, ");
+	} else if (status & E1000_STATUS_SPEED_100) {
+		*speed = SPEED_100;
+		hw_dbg(hw, "100 Mbs, ");
+	} else {
+		*speed = SPEED_10;
+		hw_dbg(hw, "10 Mbs, ");
+	}
+
+	if (status & E1000_STATUS_FD) {
+		*duplex = FULL_DUPLEX;
+		hw_dbg(hw, "Full Duplex\n");
+	} else {
+		*duplex = HALF_DUPLEX;
+		hw_dbg(hw, "Half Duplex\n");
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000e_get_speed_and_duplex_fiber_serdes - Retreive current speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @speed: stores the current speed
+ *  @duplex: stores the current duplex
+ *
+ *  Sets the speed and duplex to gigabit full duplex (the only possible option)
+ *  for fiber/serdes links.
+ **/
+s32 e1000e_get_speed_and_duplex_fiber_serdes(struct e1000_hw *hw, u16 *speed, u16 *duplex)
+{
+	*speed = SPEED_1000;
+	*duplex = FULL_DUPLEX;
+
+	return 0;
+}
+
+/**
+ *  e1000e_get_hw_semaphore - Acquire hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Acquire the HW semaphore to access the PHY or NVM
+ **/
+s32 e1000e_get_hw_semaphore(struct e1000_hw *hw)
+{
+	u32 swsm;
+	s32 timeout = hw->nvm.word_size + 1;
+	s32 i = 0;
+
+	/* Get the SW semaphore */
+	while (i < timeout) {
+		swsm = er32(SWSM);
+		if (!(swsm & E1000_SWSM_SMBI))
+			break;
+
+		udelay(50);
+		i++;
+	}
+
+	if (i == timeout) {
+		hw_dbg(hw, "Driver can't access device - SMBI bit is set.\n");
+		return -E1000_ERR_NVM;
+	}
+
+	/* Get the FW semaphore. */
+	for (i = 0; i < timeout; i++) {
+		swsm = er32(SWSM);
+		ew32(SWSM, swsm | E1000_SWSM_SWESMBI);
+
+		/* Semaphore acquired if bit latched */
+		if (er32(SWSM) & E1000_SWSM_SWESMBI)
+			break;
+
+		udelay(50);
+	}
+
+	if (i == timeout) {
+		/* Release semaphores */
+		e1000e_put_hw_semaphore(hw);
+		hw_dbg(hw, "Driver can't access the NVM\n");
+		return -E1000_ERR_NVM;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000e_put_hw_semaphore - Release hardware semaphore
+ *  @hw: pointer to the HW structure
+ *
+ *  Release hardware semaphore used to access the PHY or NVM
+ **/
+void e1000e_put_hw_semaphore(struct e1000_hw *hw)
+{
+	u32 swsm;
+
+	swsm = er32(SWSM);
+	swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI);
+	ew32(SWSM, swsm);
+}
+
+/**
+ *  e1000e_get_auto_rd_done - Check for auto read completion
+ *  @hw: pointer to the HW structure
+ *
+ *  Check EEPROM for Auto Read done bit.
+ **/
+s32 e1000e_get_auto_rd_done(struct e1000_hw *hw)
+{
+	s32 i = 0;
+
+	while (i < AUTO_READ_DONE_TIMEOUT) {
+		if (er32(EECD) & E1000_EECD_AUTO_RD)
+			break;
+		msleep(1);
+		i++;
+	}
+
+	if (i == AUTO_READ_DONE_TIMEOUT) {
+		hw_dbg(hw, "Auto read by HW from NVM has not completed.\n");
+		return -E1000_ERR_RESET;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000e_valid_led_default - Verify a valid default LED config
+ *  @hw: pointer to the HW structure
+ *  @data: pointer to the NVM (EEPROM)
+ *
+ *  Read the EEPROM for the current default LED configuration.  If the
+ *  LED configuration is not valid, set to a valid LED configuration.
+ **/
+s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data)
+{
+	s32 ret_val;
+
+	ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data);
+	if (ret_val) {
+		hw_dbg(hw, "NVM Read Error\n");
+		return ret_val;
+	}
+
+	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
+		*data = ID_LED_DEFAULT;
+
+	return 0;
+}
+
+/**
+ *  e1000e_id_led_init -
+ *  @hw: pointer to the HW structure
+ *
+ **/
+s32 e1000e_id_led_init(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	s32 ret_val;
+	const u32 ledctl_mask = 0x000000FF;
+	const u32 ledctl_on = E1000_LEDCTL_MODE_LED_ON;
+	const u32 ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
+	u16 data, i, temp;
+	const u16 led_mask = 0x0F;
+
+	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
+	if (ret_val)
+		return ret_val;
+
+	mac->ledctl_default = er32(LEDCTL);
+	mac->ledctl_mode1 = mac->ledctl_default;
+	mac->ledctl_mode2 = mac->ledctl_default;
+
+	for (i = 0; i < 4; i++) {
+		temp = (data >> (i << 2)) & led_mask;
+		switch (temp) {
+		case ID_LED_ON1_DEF2:
+		case ID_LED_ON1_ON2:
+		case ID_LED_ON1_OFF2:
+			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode1 |= ledctl_on << (i << 3);
+			break;
+		case ID_LED_OFF1_DEF2:
+		case ID_LED_OFF1_ON2:
+		case ID_LED_OFF1_OFF2:
+			mac->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode1 |= ledctl_off << (i << 3);
+			break;
+		default:
+			/* Do nothing */
+			break;
+		}
+		switch (temp) {
+		case ID_LED_DEF1_ON2:
+		case ID_LED_ON1_ON2:
+		case ID_LED_OFF1_ON2:
+			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode2 |= ledctl_on << (i << 3);
+			break;
+		case ID_LED_DEF1_OFF2:
+		case ID_LED_ON1_OFF2:
+		case ID_LED_OFF1_OFF2:
+			mac->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+			mac->ledctl_mode2 |= ledctl_off << (i << 3);
+			break;
+		default:
+			/* Do nothing */
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000e_cleanup_led_generic - Set LED config to default operation
+ *  @hw: pointer to the HW structure
+ *
+ *  Remove the current LED configuration and set the LED configuration
+ *  to the default value, saved from the EEPROM.
+ **/
+s32 e1000e_cleanup_led_generic(struct e1000_hw *hw)
+{
+	ew32(LEDCTL, hw->mac.ledctl_default);
+	return 0;
+}
+
+/**
+ *  e1000e_blink_led - Blink LED
+ *  @hw: pointer to the HW structure
+ *
+ *  Blink the led's which are set to be on.
+ **/
+s32 e1000e_blink_led(struct e1000_hw *hw)
+{
+	u32 ledctl_blink = 0;
+	u32 i;
+
+	if (hw->media_type == e1000_media_type_fiber) {
+		/* always blink LED0 for PCI-E fiber */
+		ledctl_blink = E1000_LEDCTL_LED0_BLINK |
+		     (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
+	} else {
+		/* set the blink bit for each LED that's "on" (0x0E)
+		 * in ledctl_mode2 */
+		ledctl_blink = hw->mac.ledctl_mode2;
+		for (i = 0; i < 4; i++)
+			if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
+			    E1000_LEDCTL_MODE_LED_ON)
+				ledctl_blink |= (E1000_LEDCTL_LED0_BLINK <<
+						 (i * 8));
+	}
+
+	ew32(LEDCTL, ledctl_blink);
+
+	return 0;
+}
+
+/**
+ *  e1000e_led_on_generic - Turn LED on
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn LED on.
+ **/
+s32 e1000e_led_on_generic(struct e1000_hw *hw)
+{
+	u32 ctrl;
+
+	switch (hw->media_type) {
+	case e1000_media_type_fiber:
+		ctrl = er32(CTRL);
+		ctrl &= ~E1000_CTRL_SWDPIN0;
+		ctrl |= E1000_CTRL_SWDPIO0;
+		ew32(CTRL, ctrl);
+		break;
+	case e1000_media_type_copper:
+		ew32(LEDCTL, hw->mac.ledctl_mode2);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000e_led_off_generic - Turn LED off
+ *  @hw: pointer to the HW structure
+ *
+ *  Turn LED off.
+ **/
+s32 e1000e_led_off_generic(struct e1000_hw *hw)
+{
+	u32 ctrl;
+
+	switch (hw->media_type) {
+	case e1000_media_type_fiber:
+		ctrl = er32(CTRL);
+		ctrl |= E1000_CTRL_SWDPIN0;
+		ctrl |= E1000_CTRL_SWDPIO0;
+		ew32(CTRL, ctrl);
+		break;
+	case e1000_media_type_copper:
+		ew32(LEDCTL, hw->mac.ledctl_mode1);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000e_set_pcie_no_snoop - Set PCI-express capabilities
+ *  @hw: pointer to the HW structure
+ *  @no_snoop: bitmap of snoop events
+ *
+ *  Set the PCI-express register to snoop for events enabled in 'no_snoop'.
+ **/
+void e1000e_set_pcie_no_snoop(struct e1000_hw *hw, u32 no_snoop)
+{
+	u32 gcr;
+
+	if (no_snoop) {
+		gcr = er32(GCR);
+		gcr &= ~(PCIE_NO_SNOOP_ALL);
+		gcr |= no_snoop;
+		ew32(GCR, gcr);
+	}
+}
+
+/**
+ *  e1000e_disable_pcie_master - Disables PCI-express master access
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns 0 if successful, else returns -10
+ *  (-E1000_ERR_MASTER_REQUESTS_PENDING) if master disable bit has not casued
+ *  the master requests to be disabled.
+ *
+ *  Disables PCI-Express master access and verifies there are no pending
+ *  requests.
+ **/
+s32 e1000e_disable_pcie_master(struct e1000_hw *hw)
+{
+	u32 ctrl;
+	s32 timeout = MASTER_DISABLE_TIMEOUT;
+
+	ctrl = er32(CTRL);
+	ctrl |= E1000_CTRL_GIO_MASTER_DISABLE;
+	ew32(CTRL, ctrl);
+
+	while (timeout) {
+		if (!(er32(STATUS) &
+		      E1000_STATUS_GIO_MASTER_ENABLE))
+			break;
+		udelay(100);
+		timeout--;
+	}
+
+	if (!timeout) {
+		hw_dbg(hw, "Master requests are pending.\n");
+		return -E1000_ERR_MASTER_REQUESTS_PENDING;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000e_reset_adaptive - Reset Adaptive Interframe Spacing
+ *  @hw: pointer to the HW structure
+ *
+ *  Reset the Adaptive Interframe Spacing throttle to default values.
+ **/
+void e1000e_reset_adaptive(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	mac->current_ifs_val = 0;
+	mac->ifs_min_val = IFS_MIN;
+	mac->ifs_max_val = IFS_MAX;
+	mac->ifs_step_size = IFS_STEP;
+	mac->ifs_ratio = IFS_RATIO;
+
+	mac->in_ifs_mode = 0;
+	ew32(AIT, 0);
+}
+
+/**
+ *  e1000e_update_adaptive - Update Adaptive Interframe Spacing
+ *  @hw: pointer to the HW structure
+ *
+ *  Update the Adaptive Interframe Spacing Throttle value based on the
+ *  time between transmitted packets and time between collisions.
+ **/
+void e1000e_update_adaptive(struct e1000_hw *hw)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+
+	if ((mac->collision_delta * mac->ifs_ratio) > mac->tx_packet_delta) {
+		if (mac->tx_packet_delta > MIN_NUM_XMITS) {
+			mac->in_ifs_mode = 1;
+			if (mac->current_ifs_val < mac->ifs_max_val) {
+				if (!mac->current_ifs_val)
+					mac->current_ifs_val = mac->ifs_min_val;
+				else
+					mac->current_ifs_val +=
+						mac->ifs_step_size;
+				ew32(AIT,
+						mac->current_ifs_val);
+			}
+		}
+	} else {
+		if (mac->in_ifs_mode &&
+		    (mac->tx_packet_delta <= MIN_NUM_XMITS)) {
+			mac->current_ifs_val = 0;
+			mac->in_ifs_mode = 0;
+			ew32(AIT, 0);
+		}
+	}
+}
+
+/**
+ *  e1000_raise_eec_clk - Raise EEPROM clock
+ *  @hw: pointer to the HW structure
+ *  @eecd: pointer to the EEPROM
+ *
+ *  Enable/Raise the EEPROM clock bit.
+ **/
+static void e1000_raise_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+	*eecd = *eecd | E1000_EECD_SK;
+	ew32(EECD, *eecd);
+	e1e_flush();
+	udelay(hw->nvm.delay_usec);
+}
+
+/**
+ *  e1000_lower_eec_clk - Lower EEPROM clock
+ *  @hw: pointer to the HW structure
+ *  @eecd: pointer to the EEPROM
+ *
+ *  Clear/Lower the EEPROM clock bit.
+ **/
+static void e1000_lower_eec_clk(struct e1000_hw *hw, u32 *eecd)
+{
+	*eecd = *eecd & ~E1000_EECD_SK;
+	ew32(EECD, *eecd);
+	e1e_flush();
+	udelay(hw->nvm.delay_usec);
+}
+
+/**
+ *  e1000_shift_out_eec_bits - Shift data bits our to the EEPROM
+ *  @hw: pointer to the HW structure
+ *  @data: data to send to the EEPROM
+ *  @count: number of bits to shift out
+ *
+ *  We need to shift 'count' bits out to the EEPROM.  So, the value in the
+ *  "data" parameter will be shifted out to the EEPROM one bit at a time.
+ *  In order to do this, "data" must be broken down into bits.
+ **/
+static void e1000_shift_out_eec_bits(struct e1000_hw *hw, u16 data, u16 count)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = er32(EECD);
+	u32 mask;
+
+	mask = 0x01 << (count - 1);
+	if (nvm->type == e1000_nvm_eeprom_spi)
+		eecd |= E1000_EECD_DO;
+
+	do {
+		eecd &= ~E1000_EECD_DI;
+
+		if (data & mask)
+			eecd |= E1000_EECD_DI;
+
+		ew32(EECD, eecd);
+		e1e_flush();
+
+		udelay(nvm->delay_usec);
+
+		e1000_raise_eec_clk(hw, &eecd);
+		e1000_lower_eec_clk(hw, &eecd);
+
+		mask >>= 1;
+	} while (mask);
+
+	eecd &= ~E1000_EECD_DI;
+	ew32(EECD, eecd);
+}
+
+/**
+ *  e1000_shift_in_eec_bits - Shift data bits in from the EEPROM
+ *  @hw: pointer to the HW structure
+ *  @count: number of bits to shift in
+ *
+ *  In order to read a register from the EEPROM, we need to shift 'count' bits
+ *  in from the EEPROM.  Bits are "shifted in" by raising the clock input to
+ *  the EEPROM (setting the SK bit), and then reading the value of the data out
+ *  "DO" bit.  During this "shifting in" process the data in "DI" bit should
+ *  always be clear.
+ **/
+static u16 e1000_shift_in_eec_bits(struct e1000_hw *hw, u16 count)
+{
+	u32 eecd;
+	u32 i;
+	u16 data;
+
+	eecd = er32(EECD);
+
+	eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+	data = 0;
+
+	for (i = 0; i < count; i++) {
+		data <<= 1;
+		e1000_raise_eec_clk(hw, &eecd);
+
+		eecd = er32(EECD);
+
+		eecd &= ~E1000_EECD_DI;
+		if (eecd & E1000_EECD_DO)
+			data |= 1;
+
+		e1000_lower_eec_clk(hw, &eecd);
+	}
+
+	return data;
+}
+
+/**
+ *  e1000e_poll_eerd_eewr_done - Poll for EEPROM read/write completion
+ *  @hw: pointer to the HW structure
+ *  @ee_reg: EEPROM flag for polling
+ *
+ *  Polls the EEPROM status bit for either read or write completion based
+ *  upon the value of 'ee_reg'.
+ **/
+s32 e1000e_poll_eerd_eewr_done(struct e1000_hw *hw, int ee_reg)
+{
+	u32 attempts = 100000;
+	u32 i, reg = 0;
+
+	for (i = 0; i < attempts; i++) {
+		if (ee_reg == E1000_NVM_POLL_READ)
+			reg = er32(EERD);
+		else
+			reg = er32(EEWR);
+
+		if (reg & E1000_NVM_RW_REG_DONE)
+			return 0;
+
+		udelay(5);
+	}
+
+	return -E1000_ERR_NVM;
+}
+
+/**
+ *  e1000e_acquire_nvm - Generic request for access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Set the EEPROM access request bit and wait for EEPROM access grant bit.
+ *  Return successful if access grant bit set, else clear the request for
+ *  EEPROM access and return -E1000_ERR_NVM (-1).
+ **/
+s32 e1000e_acquire_nvm(struct e1000_hw *hw)
+{
+	u32 eecd = er32(EECD);
+	s32 timeout = E1000_NVM_GRANT_ATTEMPTS;
+
+	ew32(EECD, eecd | E1000_EECD_REQ);
+	eecd = er32(EECD);
+
+	while (timeout) {
+		if (eecd & E1000_EECD_GNT)
+			break;
+		udelay(5);
+		eecd = er32(EECD);
+		timeout--;
+	}
+
+	if (!timeout) {
+		eecd &= ~E1000_EECD_REQ;
+		ew32(EECD, eecd);
+		hw_dbg(hw, "Could not acquire NVM grant\n");
+		return -E1000_ERR_NVM;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_standby_nvm - Return EEPROM to standby state
+ *  @hw: pointer to the HW structure
+ *
+ *  Return the EEPROM to a standby state.
+ **/
+static void e1000_standby_nvm(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = er32(EECD);
+
+	if (nvm->type == e1000_nvm_eeprom_spi) {
+		/* Toggle CS to flush commands */
+		eecd |= E1000_EECD_CS;
+		ew32(EECD, eecd);
+		e1e_flush();
+		udelay(nvm->delay_usec);
+		eecd &= ~E1000_EECD_CS;
+		ew32(EECD, eecd);
+		e1e_flush();
+		udelay(nvm->delay_usec);
+	}
+}
+
+/**
+ *  e1000_stop_nvm - Terminate EEPROM command
+ *  @hw: pointer to the HW structure
+ *
+ *  Terminates the current command by inverting the EEPROM's chip select pin.
+ **/
+static void e1000_stop_nvm(struct e1000_hw *hw)
+{
+	u32 eecd;
+
+	eecd = er32(EECD);
+	if (hw->nvm.type == e1000_nvm_eeprom_spi) {
+		/* Pull CS high */
+		eecd |= E1000_EECD_CS;
+		e1000_lower_eec_clk(hw, &eecd);
+	}
+}
+
+/**
+ *  e1000e_release_nvm - Release exclusive access to EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Stop any current commands to the EEPROM and clear the EEPROM request bit.
+ **/
+void e1000e_release_nvm(struct e1000_hw *hw)
+{
+	u32 eecd;
+
+	e1000_stop_nvm(hw);
+
+	eecd = er32(EECD);
+	eecd &= ~E1000_EECD_REQ;
+	ew32(EECD, eecd);
+}
+
+/**
+ *  e1000_ready_nvm_eeprom - Prepares EEPROM for read/write
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups the EEPROM for reading and writing.
+ **/
+static s32 e1000_ready_nvm_eeprom(struct e1000_hw *hw)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 eecd = er32(EECD);
+	u16 timeout = 0;
+	u8 spi_stat_reg;
+
+	if (nvm->type == e1000_nvm_eeprom_spi) {
+		/* Clear SK and CS */
+		eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+		ew32(EECD, eecd);
+		udelay(1);
+		timeout = NVM_MAX_RETRY_SPI;
+
+		/* Read "Status Register" repeatedly until the LSB is cleared.
+		 * The EEPROM will signal that the command has been completed
+		 * by clearing bit 0 of the internal status register.  If it's
+		 * not cleared within 'timeout', then error out. */
+		while (timeout) {
+			e1000_shift_out_eec_bits(hw, NVM_RDSR_OPCODE_SPI,
+						 hw->nvm.opcode_bits);
+			spi_stat_reg = (u8)e1000_shift_in_eec_bits(hw, 8);
+			if (!(spi_stat_reg & NVM_STATUS_RDY_SPI))
+				break;
+
+			udelay(5);
+			e1000_standby_nvm(hw);
+			timeout--;
+		}
+
+		if (!timeout) {
+			hw_dbg(hw, "SPI NVM Status error\n");
+			return -E1000_ERR_NVM;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000e_read_nvm_spi - Read EEPROM's using SPI
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of word in the EEPROM to read
+ *  @words: number of words to read
+ *  @data: word read from the EEPROM
+ *
+ *  Reads a 16 bit word from the EEPROM.
+ **/
+s32 e1000e_read_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 i = 0;
+	s32 ret_val;
+	u16 word_in;
+	u8 read_opcode = NVM_READ_OPCODE_SPI;
+
+	/* A check for invalid values:  offset too large, too many words,
+	 * and not enough words. */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+		return -E1000_ERR_NVM;
+	}
+
+	ret_val = nvm->ops.acquire_nvm(hw);
+	if (ret_val)
+		return ret_val;
+
+	ret_val = e1000_ready_nvm_eeprom(hw);
+	if (ret_val) {
+		nvm->ops.release_nvm(hw);
+		return ret_val;
+	}
+
+	e1000_standby_nvm(hw);
+
+	if ((nvm->address_bits == 8) && (offset >= 128))
+		read_opcode |= NVM_A8_OPCODE_SPI;
+
+	/* Send the READ command (opcode + addr) */
+	e1000_shift_out_eec_bits(hw, read_opcode, nvm->opcode_bits);
+	e1000_shift_out_eec_bits(hw, (u16)(offset*2), nvm->address_bits);
+
+	/* Read the data.  SPI NVMs increment the address with each byte
+	 * read and will roll over if reading beyond the end.  This allows
+	 * us to read the whole NVM from any offset */
+	for (i = 0; i < words; i++) {
+		word_in = e1000_shift_in_eec_bits(hw, 16);
+		data[i] = (word_in >> 8) | (word_in << 8);
+	}
+
+	nvm->ops.release_nvm(hw);
+	return 0;
+}
+
+/**
+ *  e1000e_read_nvm_eerd - Reads EEPROM using EERD register
+ *  @hw: pointer to the HW structure
+ *  @offset: offset of word in the EEPROM to read
+ *  @words: number of words to read
+ *  @data: word read from the EEPROM
+ *
+ *  Reads a 16 bit word from the EEPROM using the EERD register.
+ **/
+s32 e1000e_read_nvm_eerd(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	u32 i, eerd = 0;
+	s32 ret_val = 0;
+
+	/* A check for invalid values:  offset too large, too many words,
+	 * and not enough words. */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+		return -E1000_ERR_NVM;
+	}
+
+	for (i = 0; i < words; i++) {
+		eerd = ((offset+i) << E1000_NVM_RW_ADDR_SHIFT) +
+		       E1000_NVM_RW_REG_START;
+
+		ew32(EERD, eerd);
+		ret_val = e1000e_poll_eerd_eewr_done(hw, E1000_NVM_POLL_READ);
+		if (ret_val)
+			break;
+
+		data[i] = (er32(EERD) >>
+			   E1000_NVM_RW_REG_DATA);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_nvm_spi - Write to EEPROM using SPI
+ *  @hw: pointer to the HW structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @words: number of words to write
+ *  @data: 16 bit word(s) to be written to the EEPROM
+ *
+ *  Writes data to EEPROM at offset using SPI interface.
+ *
+ *  If e1000e_update_nvm_checksum is not called after this function , the
+ *  EEPROM will most likley contain an invalid checksum.
+ **/
+s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
+{
+	struct e1000_nvm_info *nvm = &hw->nvm;
+	s32 ret_val;
+	u16 widx = 0;
+
+	/* A check for invalid values:  offset too large, too many words,
+	 * and not enough words. */
+	if ((offset >= nvm->word_size) || (words > (nvm->word_size - offset)) ||
+	    (words == 0)) {
+		hw_dbg(hw, "nvm parameter(s) out of bounds\n");
+		return -E1000_ERR_NVM;
+	}
+
+	ret_val = nvm->ops.acquire_nvm(hw);
+	if (ret_val)
+		return ret_val;
+
+	msleep(10);
+
+	while (widx < words) {
+		u8 write_opcode = NVM_WRITE_OPCODE_SPI;
+
+		ret_val = e1000_ready_nvm_eeprom(hw);
+		if (ret_val) {
+			nvm->ops.release_nvm(hw);
+			return ret_val;
+		}
+
+		e1000_standby_nvm(hw);
+
+		/* Send the WRITE ENABLE command (8 bit opcode) */
+		e1000_shift_out_eec_bits(hw, NVM_WREN_OPCODE_SPI,
+					 nvm->opcode_bits);
+
+		e1000_standby_nvm(hw);
+
+		/* Some SPI eeproms use the 8th address bit embedded in the
+		 * opcode */
+		if ((nvm->address_bits == 8) && (offset >= 128))
+			write_opcode |= NVM_A8_OPCODE_SPI;
+
+		/* Send the Write command (8-bit opcode + addr) */
+		e1000_shift_out_eec_bits(hw, write_opcode, nvm->opcode_bits);
+		e1000_shift_out_eec_bits(hw, (u16)((offset + widx) * 2),
+					 nvm->address_bits);
+
+		/* Loop to allow for up to whole page write of eeprom */
+		while (widx < words) {
+			u16 word_out = data[widx];
+			word_out = (word_out >> 8) | (word_out << 8);
+			e1000_shift_out_eec_bits(hw, word_out, 16);
+			widx++;
+
+			if ((((offset + widx) * 2) % nvm->page_size) == 0) {
+				e1000_standby_nvm(hw);
+				break;
+			}
+		}
+	}
+
+	msleep(10);
+	return 0;
+}
+
+/**
+ *  e1000e_read_mac_addr - Read device MAC address
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the device MAC address from the EEPROM and stores the value.
+ *  Since devices with two ports use the same EEPROM, we increment the
+ *  last bit in the MAC address for the second port.
+ **/
+s32 e1000e_read_mac_addr(struct e1000_hw *hw)
+{
+	s32 ret_val;
+	u16 offset, nvm_data, i;
+
+	for (i = 0; i < ETH_ALEN; i += 2) {
+		offset = i >> 1;
+		ret_val = e1000_read_nvm(hw, offset, 1, &nvm_data);
+		if (ret_val) {
+			hw_dbg(hw, "NVM Read Error\n");
+			return ret_val;
+		}
+		hw->mac.perm_addr[i] = (u8)(nvm_data & 0xFF);
+		hw->mac.perm_addr[i+1] = (u8)(nvm_data >> 8);
+	}
+
+	/* Flip last bit of mac address if we're on second port */
+	if (hw->bus.func == E1000_FUNC_1)
+		hw->mac.perm_addr[5] ^= 1;
+
+	for (i = 0; i < ETH_ALEN; i++)
+		hw->mac.addr[i] = hw->mac.perm_addr[i];
+
+	return 0;
+}
+
+/**
+ *  e1000e_validate_nvm_checksum_generic - Validate EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
+ **/
+s32 e1000e_validate_nvm_checksum_generic(struct e1000_hw *hw)
+{
+	s32 ret_val;
+	u16 checksum = 0;
+	u16 i, nvm_data;
+
+	for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) {
+		ret_val = e1000_read_nvm(hw, i, 1, &nvm_data);
+		if (ret_val) {
+			hw_dbg(hw, "NVM Read Error\n");
+			return ret_val;
+		}
+		checksum += nvm_data;
+	}
+
+	if (checksum != (u16) NVM_SUM) {
+		hw_dbg(hw, "NVM Checksum Invalid\n");
+		return -E1000_ERR_NVM;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000e_update_nvm_checksum_generic - Update EEPROM checksum
+ *  @hw: pointer to the HW structure
+ *
+ *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
+ *  up to the checksum.  Then calculates the EEPROM checksum and writes the
+ *  value to the EEPROM.
+ **/
+s32 e1000e_update_nvm_checksum_generic(struct e1000_hw *hw)
+{
+	s32 ret_val;
+	u16 checksum = 0;
+	u16 i, nvm_data;
+
+	for (i = 0; i < NVM_CHECKSUM_REG; i++) {
+		ret_val = e1000_read_nvm(hw, i, 1, &nvm_data);
+		if (ret_val) {
+			hw_dbg(hw, "NVM Read Error while updating checksum.\n");
+			return ret_val;
+		}
+		checksum += nvm_data;
+	}
+	checksum = (u16) NVM_SUM - checksum;
+	ret_val = e1000_write_nvm(hw, NVM_CHECKSUM_REG, 1, &checksum);
+	if (ret_val)
+		hw_dbg(hw, "NVM Write Error while updating checksum.\n");
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_reload_nvm - Reloads EEPROM
+ *  @hw: pointer to the HW structure
+ *
+ *  Reloads the EEPROM by setting the "Reinitialize from EEPROM" bit in the
+ *  extended control register.
+ **/
+void e1000e_reload_nvm(struct e1000_hw *hw)
+{
+	u32 ctrl_ext;
+
+	udelay(10);
+	ctrl_ext = er32(CTRL_EXT);
+	ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+	ew32(CTRL_EXT, ctrl_ext);
+	e1e_flush();
+}
+
+/**
+ *  e1000_calculate_checksum - Calculate checksum for buffer
+ *  @buffer: pointer to EEPROM
+ *  @length: size of EEPROM to calculate a checksum for
+ *
+ *  Calculates the checksum for some buffer on a specified length.  The
+ *  checksum calculated is returned.
+ **/
+static u8 e1000_calculate_checksum(u8 *buffer, u32 length)
+{
+	u32 i;
+	u8  sum = 0;
+
+	if (!buffer)
+		return 0;
+
+	for (i = 0; i < length; i++)
+		sum += buffer[i];
+
+	return (u8) (0 - sum);
+}
+
+/**
+ *  e1000_mng_enable_host_if - Checks host interface is enabled
+ *  @hw: pointer to the HW structure
+ *
+ *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
+ *
+ *  This function checks whether the HOST IF is enabled for command operaton
+ *  and also checks whether the previous command is completed.  It busy waits
+ *  in case of previous command is not completed.
+ **/
+static s32 e1000_mng_enable_host_if(struct e1000_hw *hw)
+{
+	u32 hicr;
+	u8 i;
+
+	/* Check that the host interface is enabled. */
+	hicr = er32(HICR);
+	if ((hicr & E1000_HICR_EN) == 0) {
+		hw_dbg(hw, "E1000_HOST_EN bit disabled.\n");
+		return -E1000_ERR_HOST_INTERFACE_COMMAND;
+	}
+	/* check the previous command is completed */
+	for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
+		hicr = er32(HICR);
+		if (!(hicr & E1000_HICR_C))
+			break;
+		mdelay(1);
+	}
+
+	if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
+		hw_dbg(hw, "Previous command timeout failed .\n");
+		return -E1000_ERR_HOST_INTERFACE_COMMAND;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000e_check_mng_mode - check managament mode
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the firmware semaphore register and returns true (>0) if
+ *  manageability is enabled, else false (0).
+ **/
+bool e1000e_check_mng_mode(struct e1000_hw *hw)
+{
+	u32 fwsm = er32(FWSM);
+
+	return (fwsm & E1000_FWSM_MODE_MASK) == hw->mac.ops.mng_mode_enab;
+}
+
+/**
+ *  e1000e_enable_tx_pkt_filtering - Enable packet filtering on TX
+ *  @hw: pointer to the HW structure
+ *
+ *  Enables packet filtering on transmit packets if manageability is enabled
+ *  and host interface is enabled.
+ **/
+bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw)
+{
+	struct e1000_host_mng_dhcp_cookie *hdr = &hw->mng_cookie;
+	u32 *buffer = (u32 *)&hw->mng_cookie;
+	u32 offset;
+	s32 ret_val, hdr_csum, csum;
+	u8 i, len;
+
+	/* No manageability, no filtering */
+	if (!e1000e_check_mng_mode(hw)) {
+		hw->mac.tx_pkt_filtering = 0;
+		return 0;
+	}
+
+	/* If we can't read from the host interface for whatever
+	 * reason, disable filtering.
+	 */
+	ret_val = e1000_mng_enable_host_if(hw);
+	if (ret_val != 0) {
+		hw->mac.tx_pkt_filtering = 0;
+		return ret_val;
+	}
+
+	/* Read in the header.  Length and offset are in dwords. */
+	len    = E1000_MNG_DHCP_COOKIE_LENGTH >> 2;
+	offset = E1000_MNG_DHCP_COOKIE_OFFSET >> 2;
+	for (i = 0; i < len; i++)
+		*(buffer + i) = E1000_READ_REG_ARRAY(hw, E1000_HOST_IF, offset + i);
+	hdr_csum = hdr->checksum;
+	hdr->checksum = 0;
+	csum = e1000_calculate_checksum((u8 *)hdr,
+					E1000_MNG_DHCP_COOKIE_LENGTH);
+	/* If either the checksums or signature don't match, then
+	 * the cookie area isn't considered valid, in which case we
+	 * take the safe route of assuming Tx filtering is enabled.
+	 */
+	if ((hdr_csum != csum) || (hdr->signature != E1000_IAMT_SIGNATURE)) {
+		hw->mac.tx_pkt_filtering = 1;
+		return 1;
+	}
+
+	/* Cookie area is valid, make the final check for filtering. */
+	if (!(hdr->status & E1000_MNG_DHCP_COOKIE_STATUS_PARSING)) {
+		hw->mac.tx_pkt_filtering = 0;
+		return 0;
+	}
+
+	hw->mac.tx_pkt_filtering = 1;
+	return 1;
+}
+
+/**
+ *  e1000_mng_write_cmd_header - Writes manageability command header
+ *  @hw: pointer to the HW structure
+ *  @hdr: pointer to the host interface command header
+ *
+ *  Writes the command header after does the checksum calculation.
+ **/
+static s32 e1000_mng_write_cmd_header(struct e1000_hw *hw,
+				  struct e1000_host_mng_command_header *hdr)
+{
+	u16 i, length = sizeof(struct e1000_host_mng_command_header);
+
+	/* Write the whole command header structure with new checksum. */
+
+	hdr->checksum = e1000_calculate_checksum((u8 *)hdr, length);
+
+	length >>= 2;
+	/* Write the relevant command block into the ram area. */
+	for (i = 0; i < length; i++) {
+		E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, i,
+					    *((u32 *) hdr + i));
+		e1e_flush();
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000_mng_host_if_write - Writes to the manageability host interface
+ *  @hw: pointer to the HW structure
+ *  @buffer: pointer to the host interface buffer
+ *  @length: size of the buffer
+ *  @offset: location in the buffer to write to
+ *  @sum: sum of the data (not checksum)
+ *
+ *  This function writes the buffer content at the offset given on the host if.
+ *  It also does alignment considerations to do the writes in most efficient
+ *  way.  Also fills up the sum of the buffer in *buffer parameter.
+ **/
+static s32 e1000_mng_host_if_write(struct e1000_hw *hw, u8 *buffer,
+				   u16 length, u16 offset, u8 *sum)
+{
+	u8 *tmp;
+	u8 *bufptr = buffer;
+	u32 data = 0;
+	u16 remaining, i, j, prev_bytes;
+
+	/* sum = only sum of the data and it is not checksum */
+
+	if (length == 0 || offset + length > E1000_HI_MAX_MNG_DATA_LENGTH)
+		return -E1000_ERR_PARAM;
+
+	tmp = (u8 *)&data;
+	prev_bytes = offset & 0x3;
+	offset >>= 2;
+
+	if (prev_bytes) {
+		data = E1000_READ_REG_ARRAY(hw, E1000_HOST_IF, offset);
+		for (j = prev_bytes; j < sizeof(u32); j++) {
+			*(tmp + j) = *bufptr++;
+			*sum += *(tmp + j);
+		}
+		E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset, data);
+		length -= j - prev_bytes;
+		offset++;
+	}
+
+	remaining = length & 0x3;
+	length -= remaining;
+
+	/* Calculate length in DWORDs */
+	length >>= 2;
+
+	/* The device driver writes the relevant command block into the
+	 * ram area. */
+	for (i = 0; i < length; i++) {
+		for (j = 0; j < sizeof(u32); j++) {
+			*(tmp + j) = *bufptr++;
+			*sum += *(tmp + j);
+		}
+
+		E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset + i, data);
+	}
+	if (remaining) {
+		for (j = 0; j < sizeof(u32); j++) {
+			if (j < remaining)
+				*(tmp + j) = *bufptr++;
+			else
+				*(tmp + j) = 0;
+
+			*sum += *(tmp + j);
+		}
+		E1000_WRITE_REG_ARRAY(hw, E1000_HOST_IF, offset + i, data);
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000e_mng_write_dhcp_info - Writes DHCP info to host interface
+ *  @hw: pointer to the HW structure
+ *  @buffer: pointer to the host interface
+ *  @length: size of the buffer
+ *
+ *  Writes the DHCP information to the host interface.
+ **/
+s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length)
+{
+	struct e1000_host_mng_command_header hdr;
+	s32 ret_val;
+	u32 hicr;
+
+	hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
+	hdr.command_length = length;
+	hdr.reserved1 = 0;
+	hdr.reserved2 = 0;
+	hdr.checksum = 0;
+
+	/* Enable the host interface */
+	ret_val = e1000_mng_enable_host_if(hw);
+	if (ret_val)
+		return ret_val;
+
+	/* Populate the host interface with the contents of "buffer". */
+	ret_val = e1000_mng_host_if_write(hw, buffer, length,
+					  sizeof(hdr), &(hdr.checksum));
+	if (ret_val)
+		return ret_val;
+
+	/* Write the manageability command header */
+	ret_val = e1000_mng_write_cmd_header(hw, &hdr);
+	if (ret_val)
+		return ret_val;
+
+	/* Tell the ARC a new command is pending. */
+	hicr = er32(HICR);
+	ew32(HICR, hicr | E1000_HICR_C);
+
+	return 0;
+}
+
+/**
+ *  e1000e_enable_mng_pass_thru - Enable processing of ARP's
+ *  @hw: pointer to the HW structure
+ *
+ *  Verifies the hardware needs to allow ARPs to be processed by the host.
+ **/
+bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw)
+{
+	u32 manc;
+	u32 fwsm, factps;
+	bool ret_val = 0;
+
+	manc = er32(MANC);
+
+	if (!(manc & E1000_MANC_RCV_TCO_EN) ||
+	    !(manc & E1000_MANC_EN_MAC_ADDR_FILTER))
+		return ret_val;
+
+	if (hw->mac.arc_subsystem_valid) {
+		fwsm = er32(FWSM);
+		factps = er32(FACTPS);
+
+		if (!(factps & E1000_FACTPS_MNGCG) &&
+		    ((fwsm & E1000_FWSM_MODE_MASK) ==
+		     (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT))) {
+			ret_val = 1;
+			return ret_val;
+		}
+	} else {
+		if ((manc & E1000_MANC_SMBUS_EN) &&
+		    !(manc & E1000_MANC_ASF_EN)) {
+			ret_val = 1;
+			return ret_val;
+		}
+	}
+
+	return ret_val;
+}
+
+s32 e1000e_read_part_num(struct e1000_hw *hw, u32 *part_num)
+{
+	s32 ret_val;
+	u16 nvm_data;
+
+	ret_val = e1000_read_nvm(hw, NVM_PBA_OFFSET_0, 1, &nvm_data);
+	if (ret_val) {
+		hw_dbg(hw, "NVM Read Error\n");
+		return ret_val;
+	}
+	*part_num = (u32)(nvm_data << 16);
+
+	ret_val = e1000_read_nvm(hw, NVM_PBA_OFFSET_1, 1, &nvm_data);
+	if (ret_val) {
+		hw_dbg(hw, "NVM Read Error\n");
+		return ret_val;
+	}
+	*part_num |= nvm_data;
+
+	return 0;
+}
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
new file mode 100644
index 0000000..033e124
--- /dev/null
+++ b/drivers/net/e1000e/netdev.c
@@ -0,0 +1,4438 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/tcp.h>
+#include <linux/ipv6.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/cpu.h>
+#include <linux/smp.h>
+
+#include "e1000.h"
+
+#define DRV_VERSION "0.2.0"
+char e1000e_driver_name[] = "e1000e";
+const char e1000e_driver_version[] = DRV_VERSION;
+
+static const struct e1000_info *e1000_info_tbl[] = {
+	[board_82571]		= &e1000_82571_info,
+	[board_82572]		= &e1000_82572_info,
+	[board_82573]		= &e1000_82573_info,
+	[board_80003es2lan]	= &e1000_es2_info,
+	[board_ich8lan]		= &e1000_ich8_info,
+	[board_ich9lan]		= &e1000_ich9_info,
+};
+
+#ifdef DEBUG
+/**
+ * e1000_get_hw_dev_name - return device name string
+ * used by hardware layer to print debugging information
+ **/
+char *e1000e_get_hw_dev_name(struct e1000_hw *hw)
+{
+	return hw->adapter->netdev->name;
+}
+#endif
+
+/**
+ * e1000_desc_unused - calculate if we have unused descriptors
+ **/
+static int e1000_desc_unused(struct e1000_ring *ring)
+{
+	if (ring->next_to_clean > ring->next_to_use)
+		return ring->next_to_clean - ring->next_to_use - 1;
+
+	return ring->count + ring->next_to_clean - ring->next_to_use - 1;
+}
+
+/**
+ * e1000_receive_skb - helper function to handle rx indications
+ * @adapter: board private structure
+ * @status: descriptor status field as written by hardware
+ * @vlan: descriptor vlan field as written by hardware (no le/be conversion)
+ * @skb: pointer to sk_buff to be indicated to stack
+ **/
+static void e1000_receive_skb(struct e1000_adapter *adapter,
+			      struct net_device *netdev,
+			      struct sk_buff *skb,
+			      u8 status, u16 vlan)
+{
+	skb->protocol = eth_type_trans(skb, netdev);
+
+	if (adapter->vlgrp && (status & E1000_RXD_STAT_VP))
+		vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
+					 le16_to_cpu(vlan) &
+					 E1000_RXD_SPC_VLAN_MASK);
+	else
+		netif_receive_skb(skb);
+
+	netdev->last_rx = jiffies;
+}
+
+/**
+ * e1000_rx_checksum - Receive Checksum Offload for 82543
+ * @adapter:     board private structure
+ * @status_err:  receive descriptor status and error fields
+ * @csum:	receive descriptor csum field
+ * @sk_buff:     socket buffer with received data
+ **/
+static void e1000_rx_checksum(struct e1000_adapter *adapter, u32 status_err,
+			      u32 csum, struct sk_buff *skb)
+{
+	u16 status = (u16)status_err;
+	u8 errors = (u8)(status_err >> 24);
+	skb->ip_summed = CHECKSUM_NONE;
+
+	/* Ignore Checksum bit is set */
+	if (status & E1000_RXD_STAT_IXSM)
+		return;
+	/* TCP/UDP checksum error bit is set */
+	if (errors & E1000_RXD_ERR_TCPE) {
+		/* let the stack verify checksum errors */
+		adapter->hw_csum_err++;
+		return;
+	}
+
+	/* TCP/UDP Checksum has not been calculated */
+	if (!(status & (E1000_RXD_STAT_TCPCS | E1000_RXD_STAT_UDPCS)))
+		return;
+
+	/* It must be a TCP or UDP packet with a valid checksum */
+	if (status & E1000_RXD_STAT_TCPCS) {
+		/* TCP checksum is good */
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+	} else {
+		/* IP fragment with UDP payload */
+		/* Hardware complements the payload checksum, so we undo it
+		 * and then put the value in host order for further stack use.
+		 */
+		csum = ntohl(csum ^ 0xFFFF);
+		skb->csum = csum;
+		skb->ip_summed = CHECKSUM_COMPLETE;
+	}
+	adapter->hw_csum_good++;
+}
+
+/**
+ * e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended
+ * @adapter: address of board private structure
+ **/
+static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
+				   int cleaned_count)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	struct e1000_rx_desc *rx_desc;
+	struct e1000_buffer *buffer_info;
+	struct sk_buff *skb;
+	unsigned int i;
+	unsigned int bufsz = adapter->rx_buffer_len + NET_IP_ALIGN;
+
+	i = rx_ring->next_to_use;
+	buffer_info = &rx_ring->buffer_info[i];
+
+	while (cleaned_count--) {
+		skb = buffer_info->skb;
+		if (skb) {
+			skb_trim(skb, 0);
+			goto map_skb;
+		}
+
+		skb = netdev_alloc_skb(netdev, bufsz);
+		if (!skb) {
+			/* Better luck next round */
+			adapter->alloc_rx_buff_failed++;
+			break;
+		}
+
+		/* Make buffer alignment 2 beyond a 16 byte boundary
+		 * this will result in a 16 byte aligned IP header after
+		 * the 14 byte MAC header is removed
+		 */
+		skb_reserve(skb, NET_IP_ALIGN);
+
+		buffer_info->skb = skb;
+map_skb:
+		buffer_info->dma = pci_map_single(pdev, skb->data,
+						  adapter->rx_buffer_len,
+						  PCI_DMA_FROMDEVICE);
+		if (pci_dma_mapping_error(buffer_info->dma)) {
+			dev_err(&pdev->dev, "RX DMA map failed\n");
+			adapter->rx_dma_failed++;
+			break;
+		}
+
+		rx_desc = E1000_RX_DESC(*rx_ring, i);
+		rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+
+		i++;
+		if (i == rx_ring->count)
+			i = 0;
+		buffer_info = &rx_ring->buffer_info[i];
+	}
+
+	if (rx_ring->next_to_use != i) {
+		rx_ring->next_to_use = i;
+		if (i-- == 0)
+			i = (rx_ring->count - 1);
+
+		/* Force memory writes to complete before letting h/w
+		 * know there are new descriptors to fetch.  (Only
+		 * applicable for weak-ordered memory model archs,
+		 * such as IA-64). */
+		wmb();
+		writel(i, adapter->hw.hw_addr + rx_ring->tail);
+	}
+}
+
+/**
+ * e1000_alloc_rx_buffers_ps - Replace used receive buffers; packet split
+ * @adapter: address of board private structure
+ **/
+static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
+				      int cleaned_count)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	union e1000_rx_desc_packet_split *rx_desc;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	struct e1000_buffer *buffer_info;
+	struct e1000_ps_page *ps_page;
+	struct sk_buff *skb;
+	unsigned int i, j;
+
+	i = rx_ring->next_to_use;
+	buffer_info = &rx_ring->buffer_info[i];
+
+	while (cleaned_count--) {
+		rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
+
+		for (j = 0; j < PS_PAGE_BUFFERS; j++) {
+			ps_page = &rx_ring->ps_pages[(i * PS_PAGE_BUFFERS)
+						     + j];
+			if (j < adapter->rx_ps_pages) {
+				if (!ps_page->page) {
+					ps_page->page = alloc_page(GFP_ATOMIC);
+					if (!ps_page->page) {
+						adapter->alloc_rx_buff_failed++;
+						goto no_buffers;
+					}
+					ps_page->dma = pci_map_page(pdev,
+							   ps_page->page,
+							   0, PAGE_SIZE,
+							   PCI_DMA_FROMDEVICE);
+					if (pci_dma_mapping_error(
+							ps_page->dma)) {
+						dev_err(&adapter->pdev->dev,
+						  "RX DMA page map failed\n");
+						adapter->rx_dma_failed++;
+						goto no_buffers;
+					}
+				}
+				/*
+				 * Refresh the desc even if buffer_addrs
+				 * didn't change because each write-back
+				 * erases this info.
+				 */
+				rx_desc->read.buffer_addr[j+1] =
+				     cpu_to_le64(ps_page->dma);
+			} else {
+				rx_desc->read.buffer_addr[j+1] = ~0;
+			}
+		}
+
+		skb = netdev_alloc_skb(netdev,
+				       adapter->rx_ps_bsize0 + NET_IP_ALIGN);
+
+		if (!skb) {
+			adapter->alloc_rx_buff_failed++;
+			break;
+		}
+
+		/* Make buffer alignment 2 beyond a 16 byte boundary
+		 * this will result in a 16 byte aligned IP header after
+		 * the 14 byte MAC header is removed
+		 */
+		skb_reserve(skb, NET_IP_ALIGN);
+
+		buffer_info->skb = skb;
+		buffer_info->dma = pci_map_single(pdev, skb->data,
+						  adapter->rx_ps_bsize0,
+						  PCI_DMA_FROMDEVICE);
+		if (pci_dma_mapping_error(buffer_info->dma)) {
+			dev_err(&pdev->dev, "RX DMA map failed\n");
+			adapter->rx_dma_failed++;
+			/* cleanup skb */
+			dev_kfree_skb_any(skb);
+			buffer_info->skb = NULL;
+			break;
+		}
+
+		rx_desc->read.buffer_addr[0] = cpu_to_le64(buffer_info->dma);
+
+		i++;
+		if (i == rx_ring->count)
+			i = 0;
+		buffer_info = &rx_ring->buffer_info[i];
+	}
+
+no_buffers:
+	if (rx_ring->next_to_use != i) {
+		rx_ring->next_to_use = i;
+
+		if (!(i--))
+			i = (rx_ring->count - 1);
+
+		/* Force memory writes to complete before letting h/w
+		 * know there are new descriptors to fetch.  (Only
+		 * applicable for weak-ordered memory model archs,
+		 * such as IA-64). */
+		wmb();
+		/* Hardware increments by 16 bytes, but packet split
+		 * descriptors are 32 bytes...so we increment tail
+		 * twice as much.
+		 */
+		writel(i<<1, adapter->hw.hw_addr + rx_ring->tail);
+	}
+}
+
+/**
+ * e1000_alloc_rx_buffers_jumbo - Replace used jumbo receive buffers
+ *
+ * @adapter: address of board private structure
+ * @cleaned_count: number of buffers to allocate this pass
+ **/
+static void e1000_alloc_rx_buffers_jumbo(struct e1000_adapter *adapter,
+					 int cleaned_count)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	struct e1000_rx_desc *rx_desc;
+	struct e1000_buffer *buffer_info;
+	struct sk_buff *skb;
+	unsigned int i;
+	unsigned int bufsz = 256 -
+			     16 /*for skb_reserve */ -
+			     NET_IP_ALIGN;
+
+	i = rx_ring->next_to_use;
+	buffer_info = &rx_ring->buffer_info[i];
+
+	while (cleaned_count--) {
+		skb = buffer_info->skb;
+		if (skb) {
+			skb_trim(skb, 0);
+			goto check_page;
+		}
+
+		skb = netdev_alloc_skb(netdev, bufsz);
+		if (!skb) {
+			/* Better luck next round */
+			adapter->alloc_rx_buff_failed++;
+			break;
+		}
+
+		/* Make buffer alignment 2 beyond a 16 byte boundary
+		 * this will result in a 16 byte aligned IP header after
+		 * the 14 byte MAC header is removed
+		 */
+		skb_reserve(skb, NET_IP_ALIGN);
+
+		buffer_info->skb = skb;
+check_page:
+		/* allocate a new page if necessary */
+		if (!buffer_info->page) {
+			buffer_info->page = alloc_page(GFP_ATOMIC);
+			if (!buffer_info->page) {
+				adapter->alloc_rx_buff_failed++;
+				break;
+			}
+		}
+
+		if (!buffer_info->dma)
+			buffer_info->dma = pci_map_page(pdev,
+							buffer_info->page, 0,
+							PAGE_SIZE,
+							PCI_DMA_FROMDEVICE);
+		if (pci_dma_mapping_error(buffer_info->dma)) {
+			dev_err(&adapter->pdev->dev, "RX DMA page map failed\n");
+			adapter->rx_dma_failed++;
+			break;
+		}
+
+		rx_desc = E1000_RX_DESC(*rx_ring, i);
+		rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+
+		i++;
+		if (i == rx_ring->count)
+			i = 0;
+		buffer_info = &rx_ring->buffer_info[i];
+	}
+
+	if (rx_ring->next_to_use != i) {
+		rx_ring->next_to_use = i;
+		if (i-- == 0)
+			i = (rx_ring->count - 1);
+
+		/* Force memory writes to complete before letting h/w
+		 * know there are new descriptors to fetch.  (Only
+		 * applicable for weak-ordered memory model archs,
+		 * such as IA-64). */
+		wmb();
+		writel(i, adapter->hw.hw_addr + rx_ring->tail);
+	}
+}
+
+/**
+ * e1000_clean_rx_irq - Send received data up the network stack; legacy
+ * @adapter: board private structure
+ *
+ * the return value indicates whether actual cleaning was done, there
+ * is no guarantee that everything was cleaned
+ **/
+static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
+			       int *work_done, int work_to_do)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	struct e1000_rx_desc *rx_desc, *next_rxd;
+	struct e1000_buffer *buffer_info, *next_buffer;
+	u32 length;
+	unsigned int i;
+	int cleaned_count = 0;
+	bool cleaned = 0;
+	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+
+	i = rx_ring->next_to_clean;
+	rx_desc = E1000_RX_DESC(*rx_ring, i);
+	buffer_info = &rx_ring->buffer_info[i];
+
+	while (rx_desc->status & E1000_RXD_STAT_DD) {
+		struct sk_buff *skb;
+		u8 status;
+
+		if (*work_done >= work_to_do)
+			break;
+		(*work_done)++;
+
+		status = rx_desc->status;
+		skb = buffer_info->skb;
+		buffer_info->skb = NULL;
+
+		prefetch(skb->data - NET_IP_ALIGN);
+
+		i++;
+		if (i == rx_ring->count)
+			i = 0;
+		next_rxd = E1000_RX_DESC(*rx_ring, i);
+		prefetch(next_rxd);
+
+		next_buffer = &rx_ring->buffer_info[i];
+
+		cleaned = 1;
+		cleaned_count++;
+		pci_unmap_single(pdev,
+				 buffer_info->dma,
+				 adapter->rx_buffer_len,
+				 PCI_DMA_FROMDEVICE);
+		buffer_info->dma = 0;
+
+		length = le16_to_cpu(rx_desc->length);
+
+		/* !EOP means multiple descriptors were used to store a single
+		 * packet, also make sure the frame isn't just CRC only */
+		if (!(status & E1000_RXD_STAT_EOP) || (length <= 4)) {
+			/* All receives must fit into a single buffer */
+			ndev_dbg(netdev, "%s: Receive packet consumed "
+				 "multiple buffers\n", netdev->name);
+			/* recycle */
+			buffer_info->skb = skb;
+			goto next_desc;
+		}
+
+		if (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
+			/* recycle */
+			buffer_info->skb = skb;
+			goto next_desc;
+		}
+
+		/* adjust length to remove Ethernet CRC */
+		length -= 4;
+
+		/* probably a little skewed due to removing CRC */
+		total_rx_bytes += length;
+		total_rx_packets++;
+
+		/* code added for copybreak, this should improve
+		 * performance for small packets with large amounts
+		 * of reassembly being done in the stack */
+		if (length < copybreak) {
+			struct sk_buff *new_skb =
+			    netdev_alloc_skb(netdev, length + NET_IP_ALIGN);
+			if (new_skb) {
+				skb_reserve(new_skb, NET_IP_ALIGN);
+				memcpy(new_skb->data - NET_IP_ALIGN,
+				       skb->data - NET_IP_ALIGN,
+				       length + NET_IP_ALIGN);
+				/* save the skb in buffer_info as good */
+				buffer_info->skb = skb;
+				skb = new_skb;
+			}
+			/* else just continue with the old one */
+		}
+		/* end copybreak code */
+		skb_put(skb, length);
+
+		/* Receive Checksum Offload */
+		e1000_rx_checksum(adapter,
+				  (u32)(status) |
+				  ((u32)(rx_desc->errors) << 24),
+				  le16_to_cpu(rx_desc->csum), skb);
+
+		e1000_receive_skb(adapter, netdev, skb,status,rx_desc->special);
+
+next_desc:
+		rx_desc->status = 0;
+
+		/* return some buffers to hardware, one at a time is too slow */
+		if (cleaned_count >= E1000_RX_BUFFER_WRITE) {
+			adapter->alloc_rx_buf(adapter, cleaned_count);
+			cleaned_count = 0;
+		}
+
+		/* use prefetched values */
+		rx_desc = next_rxd;
+		buffer_info = next_buffer;
+	}
+	rx_ring->next_to_clean = i;
+
+	cleaned_count = e1000_desc_unused(rx_ring);
+	if (cleaned_count)
+		adapter->alloc_rx_buf(adapter, cleaned_count);
+
+	adapter->total_rx_packets += total_rx_packets;
+	adapter->total_rx_bytes += total_rx_bytes;
+	return cleaned;
+}
+
+static void e1000_consume_page(struct e1000_buffer *bi, struct sk_buff *skb,
+			       u16 length)
+{
+	bi->page = NULL;
+	skb->len += length;
+	skb->data_len += length;
+	skb->truesize += length;
+}
+
+static void e1000_put_txbuf(struct e1000_adapter *adapter,
+			     struct e1000_buffer *buffer_info)
+{
+	if (buffer_info->dma) {
+		pci_unmap_page(adapter->pdev, buffer_info->dma,
+			       buffer_info->length, PCI_DMA_TODEVICE);
+		buffer_info->dma = 0;
+	}
+	if (buffer_info->skb) {
+		dev_kfree_skb_any(buffer_info->skb);
+		buffer_info->skb = NULL;
+	}
+}
+
+static void e1000_print_tx_hang(struct e1000_adapter *adapter)
+{
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	unsigned int i = tx_ring->next_to_clean;
+	unsigned int eop = tx_ring->buffer_info[i].next_to_watch;
+	struct e1000_tx_desc *eop_desc = E1000_TX_DESC(*tx_ring, eop);
+	struct net_device *netdev = adapter->netdev;
+
+	/* detected Tx unit hang */
+	ndev_err(netdev,
+		 "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"
+		 "  time_stamp           <%lx>\n"
+		 "  next_to_watch        <%x>\n"
+		 "  jiffies              <%lx>\n"
+		 "  next_to_watch.status <%x>\n",
+		 readl(adapter->hw.hw_addr + tx_ring->head),
+		 readl(adapter->hw.hw_addr + tx_ring->tail),
+		 tx_ring->next_to_use,
+		 tx_ring->next_to_clean,
+		 tx_ring->buffer_info[eop].time_stamp,
+		 eop,
+		 jiffies,
+		 eop_desc->upper.fields.status);
+}
+
+/**
+ * e1000_clean_tx_irq - Reclaim resources after transmit completes
+ * @adapter: board private structure
+ *
+ * the return value indicates whether actual cleaning was done, there
+ * is no guarantee that everything was cleaned
+ **/
+static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	struct e1000_tx_desc *tx_desc, *eop_desc;
+	struct e1000_buffer *buffer_info;
+	unsigned int i, eop;
+	unsigned int count = 0;
+	bool cleaned = 0;
+	unsigned int total_tx_bytes = 0, total_tx_packets = 0;
+
+	i = tx_ring->next_to_clean;
+	eop = tx_ring->buffer_info[i].next_to_watch;
+	eop_desc = E1000_TX_DESC(*tx_ring, eop);
+
+	while (eop_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
+		for (cleaned = 0; !cleaned; ) {
+			tx_desc = E1000_TX_DESC(*tx_ring, i);
+			buffer_info = &tx_ring->buffer_info[i];
+			cleaned = (i == eop);
+
+			if (cleaned) {
+				struct sk_buff *skb = buffer_info->skb;
+				unsigned int segs, bytecount;
+				segs = skb_shinfo(skb)->gso_segs ?: 1;
+				/* multiply data chunks by size of headers */
+				bytecount = ((segs - 1) * skb_headlen(skb)) +
+					    skb->len;
+				total_tx_packets += segs;
+				total_tx_bytes += bytecount;
+			}
+
+			e1000_put_txbuf(adapter, buffer_info);
+			tx_desc->upper.data = 0;
+
+			i++;
+			if (i == tx_ring->count)
+				i = 0;
+		}
+
+		eop = tx_ring->buffer_info[i].next_to_watch;
+		eop_desc = E1000_TX_DESC(*tx_ring, eop);
+#define E1000_TX_WEIGHT 64
+		/* weight of a sort for tx, to avoid endless transmit cleanup */
+		if (count++ == E1000_TX_WEIGHT)
+			break;
+	}
+
+	tx_ring->next_to_clean = i;
+
+#define TX_WAKE_THRESHOLD 32
+	if (cleaned && netif_carrier_ok(netdev) &&
+		     e1000_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD) {
+		/* Make sure that anybody stopping the queue after this
+		 * sees the new next_to_clean.
+		 */
+		smp_mb();
+
+		if (netif_queue_stopped(netdev) &&
+		    !(test_bit(__E1000_DOWN, &adapter->state))) {
+			netif_wake_queue(netdev);
+			++adapter->restart_queue;
+		}
+	}
+
+	if (adapter->detect_tx_hung) {
+		/* Detect a transmit hang in hardware, this serializes the
+		 * check with the clearing of time_stamp and movement of i */
+		adapter->detect_tx_hung = 0;
+		if (tx_ring->buffer_info[eop].dma &&
+		    time_after(jiffies, tx_ring->buffer_info[eop].time_stamp
+			       + (adapter->tx_timeout_factor * HZ))
+		    && !(er32(STATUS) &
+			 E1000_STATUS_TXOFF)) {
+			e1000_print_tx_hang(adapter);
+			netif_stop_queue(netdev);
+		}
+	}
+	adapter->total_tx_bytes += total_tx_bytes;
+	adapter->total_tx_packets += total_tx_packets;
+	return cleaned;
+}
+
+/**
+ * e1000_clean_rx_irq_jumbo - Send received data up the network stack; legacy
+ * @adapter: board private structure
+ *
+ * the return value indicates whether actual cleaning was done, there
+ * is no guarantee that everything was cleaned
+ **/
+static bool e1000_clean_rx_irq_jumbo(struct e1000_adapter *adapter,
+				     int *work_done, int work_to_do)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	struct e1000_rx_desc *rx_desc, *next_rxd;
+	struct e1000_buffer *buffer_info, *next_buffer;
+	u32 length;
+	unsigned int i;
+	int cleaned_count = 0;
+	bool cleaned = 0;
+	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+
+	i = rx_ring->next_to_clean;
+	rx_desc = E1000_RX_DESC(*rx_ring, i);
+	buffer_info = &rx_ring->buffer_info[i];
+
+	while (rx_desc->status & E1000_RXD_STAT_DD) {
+		struct sk_buff *skb;
+		u8 status;
+
+		if (*work_done >= work_to_do)
+			break;
+		(*work_done)++;
+
+		status = rx_desc->status;
+		skb = buffer_info->skb;
+		buffer_info->skb = NULL;
+
+		i++;
+		if (i == rx_ring->count)
+			i = 0;
+		next_rxd = E1000_RX_DESC(*rx_ring, i);
+		prefetch(next_rxd);
+
+		next_buffer = &rx_ring->buffer_info[i];
+
+		cleaned = 1;
+		cleaned_count++;
+		pci_unmap_page(pdev,
+			       buffer_info->dma,
+			       PAGE_SIZE,
+			       PCI_DMA_FROMDEVICE);
+		buffer_info->dma = 0;
+
+		length = le16_to_cpu(rx_desc->length);
+
+		/* errors is only valid for DD + EOP descriptors */
+		if ((status & E1000_RXD_STAT_EOP) &&
+		    (rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK)) {
+			/* recycle both page and skb */
+			buffer_info->skb = skb;
+			/* an error means any chain goes out the window too */
+			if (rx_ring->rx_skb_top)
+				dev_kfree_skb(rx_ring->rx_skb_top);
+			rx_ring->rx_skb_top = NULL;
+			goto next_desc;
+		}
+
+#define rxtop rx_ring->rx_skb_top
+		if (!(status & E1000_RXD_STAT_EOP)) {
+			/* this descriptor is only the beginning (or middle) */
+			if (!rxtop) {
+				/* this is the beginning of a chain */
+				rxtop = skb;
+				skb_fill_page_desc(rxtop, 0, buffer_info->page,
+						   0, length);
+			} else {
+				/* this is the middle of a chain */
+				skb_fill_page_desc(rxtop,
+						   skb_shinfo(rxtop)->nr_frags,
+						   buffer_info->page, 0,
+						   length);
+				/* re-use the skb, only consumed the page */
+				buffer_info->skb = skb;
+			}
+			e1000_consume_page(buffer_info, rxtop, length);
+			goto next_desc;
+		} else {
+			if (rxtop) {
+				/* end of the chain */
+				skb_fill_page_desc(rxtop,
+				    skb_shinfo(rxtop)->nr_frags,
+				    buffer_info->page, 0, length);
+				/* re-use the current skb, we only consumed the
+				 * page */
+				buffer_info->skb = skb;
+				skb = rxtop;
+				rxtop = NULL;
+				e1000_consume_page(buffer_info, skb, length);
+			} else {
+				/* no chain, got EOP, this buf is the packet
+				 * copybreak to save the put_page/alloc_page */
+				if (length <= copybreak &&
+				    skb_tailroom(skb) >= length) {
+					u8 *vaddr;
+					vaddr = kmap_atomic(buffer_info->page,
+							   KM_SKB_DATA_SOFTIRQ);
+					memcpy(skb_tail_pointer(skb),
+					       vaddr, length);
+					kunmap_atomic(vaddr,
+						      KM_SKB_DATA_SOFTIRQ);
+					/* re-use the page, so don't erase
+					 * buffer_info->page */
+					skb_put(skb, length);
+				} else {
+					skb_fill_page_desc(skb, 0,
+							   buffer_info->page, 0,
+							   length);
+					e1000_consume_page(buffer_info, skb,
+							   length);
+				}
+			}
+		}
+
+		/* Receive Checksum Offload XXX recompute due to CRC strip? */
+		e1000_rx_checksum(adapter,
+				  (u32)(status) |
+				  ((u32)(rx_desc->errors) << 24),
+				  le16_to_cpu(rx_desc->csum), skb);
+
+		pskb_trim(skb, skb->len - 4);
+
+		/* probably a little skewed due to removing CRC */
+		total_rx_bytes += skb->len;
+		total_rx_packets++;
+
+		/* eth type trans needs skb->data to point to something */
+		if (!pskb_may_pull(skb, ETH_HLEN)) {
+			ndev_err(netdev, "__pskb_pull_tail failed.\n");
+			dev_kfree_skb(skb);
+			goto next_desc;
+		}
+
+		e1000_receive_skb(adapter, netdev, skb,status,rx_desc->special);
+
+next_desc:
+		rx_desc->status = 0;
+
+		/* return some buffers to hardware, one at a time is too slow */
+		if (cleaned_count >= E1000_RX_BUFFER_WRITE) {
+			adapter->alloc_rx_buf(adapter, cleaned_count);
+			cleaned_count = 0;
+		}
+
+		/* use prefetched values */
+		rx_desc = next_rxd;
+		buffer_info = next_buffer;
+	}
+	rx_ring->next_to_clean = i;
+
+	cleaned_count = e1000_desc_unused(rx_ring);
+	if (cleaned_count)
+		adapter->alloc_rx_buf(adapter, cleaned_count);
+
+	adapter->total_rx_packets += total_rx_packets;
+	adapter->total_rx_bytes += total_rx_bytes;
+	return cleaned;
+}
+
+/**
+ * e1000_clean_rx_irq_ps - Send received data up the network stack; packet split
+ * @adapter: board private structure
+ *
+ * the return value indicates whether actual cleaning was done, there
+ * is no guarantee that everything was cleaned
+ **/
+static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
+				  int *work_done, int work_to_do)
+{
+	union e1000_rx_desc_packet_split *rx_desc, *next_rxd;
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	struct e1000_buffer *buffer_info, *next_buffer;
+	struct e1000_ps_page *ps_page;
+	struct sk_buff *skb;
+	unsigned int i, j;
+	u32 length, staterr;
+	int cleaned_count = 0;
+	bool cleaned = 0;
+	unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+
+	i = rx_ring->next_to_clean;
+	rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
+	staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
+	buffer_info = &rx_ring->buffer_info[i];
+
+	while (staterr & E1000_RXD_STAT_DD) {
+		if (*work_done >= work_to_do)
+			break;
+		(*work_done)++;
+		skb = buffer_info->skb;
+
+		/* in the packet split case this is header only */
+		prefetch(skb->data - NET_IP_ALIGN);
+
+		i++;
+		if (i == rx_ring->count)
+			i = 0;
+		next_rxd = E1000_RX_DESC_PS(*rx_ring, i);
+		prefetch(next_rxd);
+
+		next_buffer = &rx_ring->buffer_info[i];
+
+		cleaned = 1;
+		cleaned_count++;
+		pci_unmap_single(pdev, buffer_info->dma,
+				 adapter->rx_ps_bsize0,
+				 PCI_DMA_FROMDEVICE);
+		buffer_info->dma = 0;
+
+		if (!(staterr & E1000_RXD_STAT_EOP)) {
+			ndev_dbg(netdev, "%s: Packet Split buffers didn't pick "
+				 "up the full packet\n", netdev->name);
+			dev_kfree_skb_irq(skb);
+			goto next_desc;
+		}
+
+		if (staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK) {
+			dev_kfree_skb_irq(skb);
+			goto next_desc;
+		}
+
+		length = le16_to_cpu(rx_desc->wb.middle.length0);
+
+		if (!length) {
+			ndev_dbg(netdev, "%s: Last part of the packet spanning"
+				 " multiple descriptors\n", netdev->name);
+			dev_kfree_skb_irq(skb);
+			goto next_desc;
+		}
+
+		/* Good Receive */
+		skb_put(skb, length);
+
+		{
+		/* this looks ugly, but it seems compiler issues make it
+		   more efficient than reusing j */
+		int l1 = le16_to_cpu(rx_desc->wb.upper.length[0]);
+
+		/* page alloc/put takes too long and effects small packet
+		 * throughput, so unsplit small packets and save the alloc/put*/
+		if (l1 && (l1 <= copybreak) &&
+		    ((length + l1) <= adapter->rx_ps_bsize0)) {
+			u8 *vaddr;
+
+			ps_page = &rx_ring->ps_pages[i * PS_PAGE_BUFFERS];
+
+			/* there is no documentation about how to call
+			 * kmap_atomic, so we can't hold the mapping
+			 * very long */
+			pci_dma_sync_single_for_cpu(pdev, ps_page->dma,
+				PAGE_SIZE, PCI_DMA_FROMDEVICE);
+			vaddr = kmap_atomic(ps_page->page, KM_SKB_DATA_SOFTIRQ);
+			memcpy(skb_tail_pointer(skb), vaddr, l1);
+			kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ);
+			pci_dma_sync_single_for_device(pdev, ps_page->dma,
+				PAGE_SIZE, PCI_DMA_FROMDEVICE);
+			/* remove the CRC */
+			l1 -= 4;
+			skb_put(skb, l1);
+			goto copydone;
+		} /* if */
+		}
+
+		for (j = 0; j < PS_PAGE_BUFFERS; j++) {
+			length = le16_to_cpu(rx_desc->wb.upper.length[j]);
+			if (!length)
+				break;
+
+			ps_page = &rx_ring->ps_pages[(i * PS_PAGE_BUFFERS) + j];
+			pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE,
+				       PCI_DMA_FROMDEVICE);
+			ps_page->dma = 0;
+			skb_fill_page_desc(skb, j, ps_page->page, 0, length);
+			ps_page->page = NULL;
+			skb->len += length;
+			skb->data_len += length;
+			skb->truesize += length;
+		}
+
+		/* strip the ethernet crc, problem is we're using pages now so
+		 * this whole operation can get a little cpu intensive */
+		pskb_trim(skb, skb->len - 4);
+
+copydone:
+		total_rx_bytes += skb->len;
+		total_rx_packets++;
+
+		e1000_rx_checksum(adapter, staterr, le16_to_cpu(
+			rx_desc->wb.lower.hi_dword.csum_ip.csum), skb);
+
+		if (rx_desc->wb.upper.header_status &
+			   cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP))
+			adapter->rx_hdr_split++;
+
+		e1000_receive_skb(adapter, netdev, skb,
+				  staterr, rx_desc->wb.middle.vlan);
+
+next_desc:
+		rx_desc->wb.middle.status_error &= cpu_to_le32(~0xFF);
+		buffer_info->skb = NULL;
+
+		/* return some buffers to hardware, one at a time is too slow */
+		if (cleaned_count >= E1000_RX_BUFFER_WRITE) {
+			adapter->alloc_rx_buf(adapter, cleaned_count);
+			cleaned_count = 0;
+		}
+
+		/* use prefetched values */
+		rx_desc = next_rxd;
+		buffer_info = next_buffer;
+
+		staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
+	}
+	rx_ring->next_to_clean = i;
+
+	cleaned_count = e1000_desc_unused(rx_ring);
+	if (cleaned_count)
+		adapter->alloc_rx_buf(adapter, cleaned_count);
+
+	adapter->total_rx_packets += total_rx_packets;
+	adapter->total_rx_bytes += total_rx_bytes;
+	return cleaned;
+}
+
+/**
+ * e1000_clean_rx_ring - Free Rx Buffers per Queue
+ * @adapter: board private structure
+ **/
+static void e1000_clean_rx_ring(struct e1000_adapter *adapter)
+{
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	struct e1000_buffer *buffer_info;
+	struct e1000_ps_page *ps_page;
+	struct pci_dev *pdev = adapter->pdev;
+	unsigned long size;
+	unsigned int i, j;
+
+	/* Free all the Rx ring sk_buffs */
+	for (i = 0; i < rx_ring->count; i++) {
+		buffer_info = &rx_ring->buffer_info[i];
+		if (buffer_info->dma) {
+			if (adapter->clean_rx == e1000_clean_rx_irq)
+				pci_unmap_single(pdev, buffer_info->dma,
+						 adapter->rx_buffer_len,
+						 PCI_DMA_FROMDEVICE);
+			else if (adapter->clean_rx == e1000_clean_rx_irq_jumbo)
+				pci_unmap_page(pdev, buffer_info->dma,
+					       PAGE_SIZE, PCI_DMA_FROMDEVICE);
+			else if (adapter->clean_rx == e1000_clean_rx_irq_ps)
+				pci_unmap_single(pdev, buffer_info->dma,
+						 adapter->rx_ps_bsize0,
+						 PCI_DMA_FROMDEVICE);
+			buffer_info->dma = 0;
+		}
+
+		if (buffer_info->page) {
+			put_page(buffer_info->page);
+			buffer_info->page = NULL;
+		}
+
+		if (buffer_info->skb) {
+			dev_kfree_skb(buffer_info->skb);
+			buffer_info->skb = NULL;
+		}
+
+		for (j = 0; j < PS_PAGE_BUFFERS; j++) {
+			ps_page = &rx_ring->ps_pages[(i * PS_PAGE_BUFFERS)
+						     + j];
+			if (!ps_page->page)
+				break;
+			pci_unmap_page(pdev, ps_page->dma, PAGE_SIZE,
+				       PCI_DMA_FROMDEVICE);
+			ps_page->dma = 0;
+			put_page(ps_page->page);
+			ps_page->page = NULL;
+		}
+	}
+
+	/* there also may be some cached data from a chained receive */
+	if (rx_ring->rx_skb_top) {
+		dev_kfree_skb(rx_ring->rx_skb_top);
+		rx_ring->rx_skb_top = NULL;
+	}
+
+	size = sizeof(struct e1000_buffer) * rx_ring->count;
+	memset(rx_ring->buffer_info, 0, size);
+	size = sizeof(struct e1000_ps_page)
+	       * (rx_ring->count * PS_PAGE_BUFFERS);
+	memset(rx_ring->ps_pages, 0, size);
+
+	/* Zero out the descriptor ring */
+	memset(rx_ring->desc, 0, rx_ring->size);
+
+	rx_ring->next_to_clean = 0;
+	rx_ring->next_to_use = 0;
+
+	writel(0, adapter->hw.hw_addr + rx_ring->head);
+	writel(0, adapter->hw.hw_addr + rx_ring->tail);
+}
+
+/**
+ * e1000_intr_msi - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ **/
+static irqreturn_t e1000_intr_msi(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 icr = er32(ICR);
+
+	/* read ICR disables interrupts using IAM, so keep up with our
+	 * enable/disable accounting */
+	atomic_inc(&adapter->irq_sem);
+
+	if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+		hw->mac.get_link_status = 1;
+		/* ICH8 workaround-- Call gig speed drop workaround on cable
+		 * disconnect (LSC) before accessing any PHY registers */
+		if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) &&
+		    (!(er32(STATUS) & E1000_STATUS_LU)))
+			e1000e_gig_downshift_workaround_ich8lan(hw);
+
+		/* 80003ES2LAN workaround-- For packet buffer work-around on
+		 * link down event; disable receives here in the ISR and reset
+		 * adapter in watchdog */
+		if (netif_carrier_ok(netdev) &&
+		    adapter->flags & FLAG_RX_NEEDS_RESTART) {
+			/* disable receives */
+			u32 rctl = er32(RCTL);
+			ew32(RCTL, rctl & ~E1000_RCTL_EN);
+		}
+		/* guard against interrupt when we're going down */
+		if (!test_bit(__E1000_DOWN, &adapter->state))
+			mod_timer(&adapter->watchdog_timer, jiffies + 1);
+	}
+
+	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+		adapter->total_tx_bytes = 0;
+		adapter->total_tx_packets = 0;
+		adapter->total_rx_bytes = 0;
+		adapter->total_rx_packets = 0;
+		__netif_rx_schedule(netdev, &adapter->napi);
+	} else {
+		atomic_dec(&adapter->irq_sem);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * e1000_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ **/
+static irqreturn_t e1000_intr(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	u32 rctl, icr = er32(ICR);
+	if (!icr)
+		return IRQ_NONE;  /* Not our interrupt */
+
+	/* IMS will not auto-mask if INT_ASSERTED is not set, and if it is
+	 * not set, then the adapter didn't send an interrupt */
+	if (!(icr & E1000_ICR_INT_ASSERTED))
+		return IRQ_NONE;
+
+	/* Interrupt Auto-Mask...upon reading ICR,
+	 * interrupts are masked.  No need for the
+	 * IMC write, but it does mean we should
+	 * account for it ASAP. */
+	atomic_inc(&adapter->irq_sem);
+
+	if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+		hw->mac.get_link_status = 1;
+		/* ICH8 workaround-- Call gig speed drop workaround on cable
+		 * disconnect (LSC) before accessing any PHY registers */
+		if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) &&
+		    (!(er32(STATUS) & E1000_STATUS_LU)))
+			e1000e_gig_downshift_workaround_ich8lan(hw);
+
+		/* 80003ES2LAN workaround--
+		 * For packet buffer work-around on link down event;
+		 * disable receives here in the ISR and
+		 * reset adapter in watchdog
+		 */
+		if (netif_carrier_ok(netdev) &&
+		    (adapter->flags & FLAG_RX_NEEDS_RESTART)) {
+			/* disable receives */
+			rctl = er32(RCTL);
+			ew32(RCTL, rctl & ~E1000_RCTL_EN);
+		}
+		/* guard against interrupt when we're going down */
+		if (!test_bit(__E1000_DOWN, &adapter->state))
+			mod_timer(&adapter->watchdog_timer, jiffies + 1);
+	}
+
+	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+		adapter->total_tx_bytes = 0;
+		adapter->total_tx_packets = 0;
+		adapter->total_rx_bytes = 0;
+		adapter->total_rx_packets = 0;
+		__netif_rx_schedule(netdev, &adapter->napi);
+	} else {
+		atomic_dec(&adapter->irq_sem);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int e1000_request_irq(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	void (*handler) = &e1000_intr;
+	int irq_flags = IRQF_SHARED;
+	int err;
+
+	err = pci_enable_msi(adapter->pdev);
+	if (err) {
+		ndev_warn(netdev,
+		 "Unable to allocate MSI interrupt Error: %d\n", err);
+	} else {
+		adapter->flags |= FLAG_MSI_ENABLED;
+		handler = &e1000_intr_msi;
+		irq_flags = 0;
+	}
+
+	err = request_irq(adapter->pdev->irq, handler, irq_flags, netdev->name,
+			  netdev);
+	if (err) {
+		if (adapter->flags & FLAG_MSI_ENABLED)
+			pci_disable_msi(adapter->pdev);
+		ndev_err(netdev,
+		       "Unable to allocate interrupt Error: %d\n", err);
+	}
+
+	return err;
+}
+
+static void e1000_free_irq(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	free_irq(adapter->pdev->irq, netdev);
+	if (adapter->flags & FLAG_MSI_ENABLED) {
+		pci_disable_msi(adapter->pdev);
+		adapter->flags &= ~FLAG_MSI_ENABLED;
+	}
+}
+
+/**
+ * e1000_irq_disable - Mask off interrupt generation on the NIC
+ **/
+static void e1000_irq_disable(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	atomic_inc(&adapter->irq_sem);
+	ew32(IMC, ~0);
+	e1e_flush();
+	synchronize_irq(adapter->pdev->irq);
+}
+
+/**
+ * e1000_irq_enable - Enable default interrupt generation settings
+ **/
+static void e1000_irq_enable(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	if (atomic_dec_and_test(&adapter->irq_sem)) {
+		ew32(IMS, IMS_ENABLE_MASK);
+		e1e_flush();
+	}
+}
+
+/**
+ * e1000_get_hw_control - get control of the h/w from f/w
+ * @adapter: address of board private structure
+ *
+ * e1000_get_hw_control sets {CTRL_EXT|FWSM}:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that
+ * the driver is loaded. For AMT version (only with 82573)
+ * of the f/w this means that the network i/f is open.
+ **/
+static void e1000_get_hw_control(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl_ext;
+	u32 swsm;
+
+	/* Let firmware know the driver has taken over */
+	if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) {
+		swsm = er32(SWSM);
+		ew32(SWSM, swsm | E1000_SWSM_DRV_LOAD);
+	} else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) {
+		ctrl_ext = er32(CTRL_EXT);
+		ew32(CTRL_EXT,
+				ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
+	}
+}
+
+/**
+ * e1000_release_hw_control - release control of the h/w to f/w
+ * @adapter: address of board private structure
+ *
+ * e1000_release_hw_control resets {CTRL_EXT|FWSM}:DRV_LOAD bit.
+ * For ASF and Pass Through versions of f/w this means that the
+ * driver is no longer loaded. For AMT version (only with 82573) i
+ * of the f/w this means that the network i/f is closed.
+ *
+ **/
+static void e1000_release_hw_control(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl_ext;
+	u32 swsm;
+
+	/* Let firmware taken over control of h/w */
+	if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) {
+		swsm = er32(SWSM);
+		ew32(SWSM, swsm & ~E1000_SWSM_DRV_LOAD);
+	} else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) {
+		ctrl_ext = er32(CTRL_EXT);
+		ew32(CTRL_EXT,
+				ctrl_ext & ~E1000_CTRL_EXT_DRV_LOAD);
+	}
+}
+
+static void e1000_release_manageability(struct e1000_adapter *adapter)
+{
+	if (adapter->flags & FLAG_MNG_PT_ENABLED) {
+		struct e1000_hw *hw = &adapter->hw;
+
+		u32 manc = er32(MANC);
+
+		/* re-enable hardware interception of ARP */
+		manc |= E1000_MANC_ARP_EN;
+		manc &= ~E1000_MANC_EN_MNG2HOST;
+
+		/* don't explicitly have to mess with MANC2H since
+		 * MANC has an enable disable that gates MANC2H */
+		ew32(MANC, manc);
+	}
+}
+
+/**
+ * @e1000_alloc_ring - allocate memory for a ring structure
+ **/
+static int e1000_alloc_ring_dma(struct e1000_adapter *adapter,
+				struct e1000_ring *ring)
+{
+	struct pci_dev *pdev = adapter->pdev;
+
+	ring->desc = dma_alloc_coherent(&pdev->dev, ring->size, &ring->dma,
+					GFP_KERNEL);
+	if (!ring->desc)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * e1000e_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ **/
+int e1000e_setup_tx_resources(struct e1000_adapter *adapter)
+{
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	int err = -ENOMEM, size;
+
+	size = sizeof(struct e1000_buffer) * tx_ring->count;
+	tx_ring->buffer_info = vmalloc(size);
+	if (!tx_ring->buffer_info)
+		goto err;
+	memset(tx_ring->buffer_info, 0, size);
+
+	/* round up to nearest 4K */
+	tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc);
+	tx_ring->size = ALIGN(tx_ring->size, 4096);
+
+	err = e1000_alloc_ring_dma(adapter, tx_ring);
+	if (err)
+		goto err;
+
+	tx_ring->next_to_use = 0;
+	tx_ring->next_to_clean = 0;
+	spin_lock_init(&adapter->tx_queue_lock);
+
+	return 0;
+err:
+	vfree(tx_ring->buffer_info);
+	ndev_err(adapter->netdev,
+	"Unable to allocate memory for the transmit descriptor ring\n");
+	return err;
+}
+
+/**
+ * e1000e_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @adapter: board private structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+int e1000e_setup_rx_resources(struct e1000_adapter *adapter)
+{
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	int size, desc_len, err = -ENOMEM;
+
+	size = sizeof(struct e1000_buffer) * rx_ring->count;
+	rx_ring->buffer_info = vmalloc(size);
+	if (!rx_ring->buffer_info)
+		goto err;
+	memset(rx_ring->buffer_info, 0, size);
+
+	rx_ring->ps_pages = kcalloc(rx_ring->count * PS_PAGE_BUFFERS,
+				    sizeof(struct e1000_ps_page),
+				    GFP_KERNEL);
+	if (!rx_ring->ps_pages)
+		goto err;
+
+	desc_len = sizeof(union e1000_rx_desc_packet_split);
+
+	/* Round up to nearest 4K */
+	rx_ring->size = rx_ring->count * desc_len;
+	rx_ring->size = ALIGN(rx_ring->size, 4096);
+
+	err = e1000_alloc_ring_dma(adapter, rx_ring);
+	if (err)
+		goto err;
+
+	rx_ring->next_to_clean = 0;
+	rx_ring->next_to_use = 0;
+	rx_ring->rx_skb_top = NULL;
+
+	return 0;
+err:
+	vfree(rx_ring->buffer_info);
+	kfree(rx_ring->ps_pages);
+	ndev_err(adapter->netdev,
+	"Unable to allocate memory for the transmit descriptor ring\n");
+	return err;
+}
+
+/**
+ * e1000_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ **/
+static void e1000_clean_tx_ring(struct e1000_adapter *adapter)
+{
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	struct e1000_buffer *buffer_info;
+	unsigned long size;
+	unsigned int i;
+
+	for (i = 0; i < tx_ring->count; i++) {
+		buffer_info = &tx_ring->buffer_info[i];
+		e1000_put_txbuf(adapter, buffer_info);
+	}
+
+	size = sizeof(struct e1000_buffer) * tx_ring->count;
+	memset(tx_ring->buffer_info, 0, size);
+
+	memset(tx_ring->desc, 0, tx_ring->size);
+
+	tx_ring->next_to_use = 0;
+	tx_ring->next_to_clean = 0;
+
+	writel(0, adapter->hw.hw_addr + tx_ring->head);
+	writel(0, adapter->hw.hw_addr + tx_ring->tail);
+}
+
+/**
+ * e1000e_free_tx_resources - Free Tx Resources per Queue
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ **/
+void e1000e_free_tx_resources(struct e1000_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+
+	e1000_clean_tx_ring(adapter);
+
+	vfree(tx_ring->buffer_info);
+	tx_ring->buffer_info = NULL;
+
+	dma_free_coherent(&pdev->dev, tx_ring->size, tx_ring->desc,
+			  tx_ring->dma);
+	tx_ring->desc = NULL;
+}
+
+/**
+ * e1000e_free_rx_resources - Free Rx Resources
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ **/
+
+void e1000e_free_rx_resources(struct e1000_adapter *adapter)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+
+	e1000_clean_rx_ring(adapter);
+
+	vfree(rx_ring->buffer_info);
+	rx_ring->buffer_info = NULL;
+
+	kfree(rx_ring->ps_pages);
+	rx_ring->ps_pages = NULL;
+
+	dma_free_coherent(&pdev->dev, rx_ring->size, rx_ring->desc,
+			  rx_ring->dma);
+	rx_ring->desc = NULL;
+}
+
+/**
+ * e1000_update_itr - update the dynamic ITR value based on statistics
+ *      Stores a new ITR value based on packets and byte
+ *      counts during the last interrupt.  The advantage of per interrupt
+ *      computation is faster updates and more accurate ITR for the current
+ *      traffic pattern.  Constants in this function were computed
+ *      based on theoretical maximum wire speed and thresholds were set based
+ *      on testing data as well as attempting to minimize response time
+ *      while increasing bulk throughput.
+ *      this functionality is controlled by the InterruptThrottleRate module
+ *      parameter (see e1000_param.c)
+ * @adapter: pointer to adapter
+ * @itr_setting: current adapter->itr
+ * @packets: the number of packets during this measurement interval
+ * @bytes: the number of bytes during this measurement interval
+ **/
+static unsigned int e1000_update_itr(struct e1000_adapter *adapter,
+				     u16 itr_setting, int packets,
+				     int bytes)
+{
+	unsigned int retval = itr_setting;
+
+	if (packets == 0)
+		goto update_itr_done;
+
+	switch (itr_setting) {
+	case lowest_latency:
+		/* handle TSO and jumbo frames */
+		if (bytes/packets > 8000)
+			retval = bulk_latency;
+		else if ((packets < 5) && (bytes > 512)) {
+			retval = low_latency;
+		}
+		break;
+	case low_latency:  /* 50 usec aka 20000 ints/s */
+		if (bytes > 10000) {
+			/* this if handles the TSO accounting */
+			if (bytes/packets > 8000) {
+				retval = bulk_latency;
+			} else if ((packets < 10) || ((bytes/packets) > 1200)) {
+				retval = bulk_latency;
+			} else if ((packets > 35)) {
+				retval = lowest_latency;
+			}
+		} else if (bytes/packets > 2000) {
+			retval = bulk_latency;
+		} else if (packets <= 2 && bytes < 512) {
+			retval = lowest_latency;
+		}
+		break;
+	case bulk_latency: /* 250 usec aka 4000 ints/s */
+		if (bytes > 25000) {
+			if (packets > 35) {
+				retval = low_latency;
+			}
+		} else if (bytes < 6000) {
+			retval = low_latency;
+		}
+		break;
+	}
+
+update_itr_done:
+	return retval;
+}
+
+static void e1000_set_itr(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u16 current_itr;
+	u32 new_itr = adapter->itr;
+
+	/* for non-gigabit speeds, just fix the interrupt rate at 4000 */
+	if (adapter->link_speed != SPEED_1000) {
+		current_itr = 0;
+		new_itr = 4000;
+		goto set_itr_now;
+	}
+
+	adapter->tx_itr = e1000_update_itr(adapter,
+				    adapter->tx_itr,
+				    adapter->total_tx_packets,
+				    adapter->total_tx_bytes);
+	/* conservative mode (itr 3) eliminates the lowest_latency setting */
+	if (adapter->itr_setting == 3 && adapter->tx_itr == lowest_latency)
+		adapter->tx_itr = low_latency;
+
+	adapter->rx_itr = e1000_update_itr(adapter,
+				    adapter->rx_itr,
+				    adapter->total_rx_packets,
+				    adapter->total_rx_bytes);
+	/* conservative mode (itr 3) eliminates the lowest_latency setting */
+	if (adapter->itr_setting == 3 && adapter->rx_itr == lowest_latency)
+		adapter->rx_itr = low_latency;
+
+	current_itr = max(adapter->rx_itr, adapter->tx_itr);
+
+	switch (current_itr) {
+	/* counts and packets in update_itr are dependent on these numbers */
+	case lowest_latency:
+		new_itr = 70000;
+		break;
+	case low_latency:
+		new_itr = 20000; /* aka hwitr = ~200 */
+		break;
+	case bulk_latency:
+		new_itr = 4000;
+		break;
+	default:
+		break;
+	}
+
+set_itr_now:
+	if (new_itr != adapter->itr) {
+		/* this attempts to bias the interrupt rate towards Bulk
+		 * by adding intermediate steps when interrupt rate is
+		 * increasing */
+		new_itr = new_itr > adapter->itr ?
+			     min(adapter->itr + (new_itr >> 2), new_itr) :
+			     new_itr;
+		adapter->itr = new_itr;
+		ew32(ITR, 1000000000 / (new_itr * 256));
+	}
+}
+
+/**
+ * e1000_clean - NAPI Rx polling callback
+ * @adapter: board private structure
+ **/
+static int e1000_clean(struct napi_struct *napi, int budget)
+{
+	struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi);
+	struct net_device *poll_dev = adapter->netdev;
+	int tx_cleaned = 0, work_done = 0;
+
+	/* Must NOT use netdev_priv macro here. */
+	adapter = poll_dev->priv;
+
+	/* Keep link state information with original netdev */
+	if (!netif_carrier_ok(poll_dev))
+		goto quit_polling;
+
+	/* e1000_clean is called per-cpu.  This lock protects
+	 * tx_ring from being cleaned by multiple cpus
+	 * simultaneously.  A failure obtaining the lock means
+	 * tx_ring is currently being cleaned anyway. */
+	if (spin_trylock(&adapter->tx_queue_lock)) {
+		tx_cleaned = e1000_clean_tx_irq(adapter);
+		spin_unlock(&adapter->tx_queue_lock);
+	}
+
+	adapter->clean_rx(adapter, &work_done, budget);
+
+	/* If no Tx and not enough Rx work done, exit the polling mode */
+	if ((!tx_cleaned && (work_done < budget)) ||
+	   !netif_running(poll_dev)) {
+quit_polling:
+		if (adapter->itr_setting & 3)
+			e1000_set_itr(adapter);
+		netif_rx_complete(poll_dev, napi);
+		e1000_irq_enable(adapter);
+	}
+
+	return work_done;
+}
+
+static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 vfta, index;
+
+	/* don't update vlan cookie if already programmed */
+	if ((adapter->hw.mng_cookie.status &
+	     E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
+	    (vid == adapter->mng_vlan_id))
+		return;
+	/* add VID to filter table */
+	index = (vid >> 5) & 0x7F;
+	vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index);
+	vfta |= (1 << (vid & 0x1F));
+	e1000e_write_vfta(hw, index, vfta);
+}
+
+static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 vfta, index;
+
+	e1000_irq_disable(adapter);
+	vlan_group_set_device(adapter->vlgrp, vid, NULL);
+	e1000_irq_enable(adapter);
+
+	if ((adapter->hw.mng_cookie.status &
+	     E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
+	    (vid == adapter->mng_vlan_id)) {
+		/* release control to f/w */
+		e1000_release_hw_control(adapter);
+		return;
+	}
+
+	/* remove VID from filter table */
+	index = (vid >> 5) & 0x7F;
+	vfta = E1000_READ_REG_ARRAY(hw, E1000_VFTA, index);
+	vfta &= ~(1 << (vid & 0x1F));
+	e1000e_write_vfta(hw, index, vfta);
+}
+
+static void e1000_update_mng_vlan(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	u16 vid = adapter->hw.mng_cookie.vlan_id;
+	u16 old_vid = adapter->mng_vlan_id;
+
+	if (!adapter->vlgrp)
+		return;
+
+	if (!vlan_group_get_device(adapter->vlgrp, vid)) {
+		adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
+		if (adapter->hw.mng_cookie.status &
+			E1000_MNG_DHCP_COOKIE_STATUS_VLAN) {
+			e1000_vlan_rx_add_vid(netdev, vid);
+			adapter->mng_vlan_id = vid;
+		}
+
+		if ((old_vid != (u16)E1000_MNG_VLAN_NONE) &&
+				(vid != old_vid) &&
+		    !vlan_group_get_device(adapter->vlgrp, old_vid))
+			e1000_vlan_rx_kill_vid(netdev, old_vid);
+	} else {
+		adapter->mng_vlan_id = vid;
+	}
+}
+
+
+static void e1000_vlan_rx_register(struct net_device *netdev,
+				   struct vlan_group *grp)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl, rctl;
+
+	e1000_irq_disable(adapter);
+	adapter->vlgrp = grp;
+
+	if (grp) {
+		/* enable VLAN tag insert/strip */
+		ctrl = er32(CTRL);
+		ctrl |= E1000_CTRL_VME;
+		ew32(CTRL, ctrl);
+
+		if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) {
+			/* enable VLAN receive filtering */
+			rctl = er32(RCTL);
+			rctl |= E1000_RCTL_VFE;
+			rctl &= ~E1000_RCTL_CFIEN;
+			ew32(RCTL, rctl);
+			e1000_update_mng_vlan(adapter);
+		}
+	} else {
+		/* disable VLAN tag insert/strip */
+		ctrl = er32(CTRL);
+		ctrl &= ~E1000_CTRL_VME;
+		ew32(CTRL, ctrl);
+
+		if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) {
+			/* disable VLAN filtering */
+			rctl = er32(RCTL);
+			rctl &= ~E1000_RCTL_VFE;
+			ew32(RCTL, rctl);
+			if (adapter->mng_vlan_id !=
+			    (u16)E1000_MNG_VLAN_NONE) {
+				e1000_vlan_rx_kill_vid(netdev,
+						       adapter->mng_vlan_id);
+				adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
+			}
+		}
+	}
+
+	e1000_irq_enable(adapter);
+}
+
+static void e1000_restore_vlan(struct e1000_adapter *adapter)
+{
+	u16 vid;
+
+	e1000_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+
+	if (!adapter->vlgrp)
+		return;
+
+	for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+		if (!vlan_group_get_device(adapter->vlgrp, vid))
+			continue;
+		e1000_vlan_rx_add_vid(adapter->netdev, vid);
+	}
+}
+
+static void e1000_init_manageability(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 manc, manc2h;
+
+	if (!(adapter->flags & FLAG_MNG_PT_ENABLED))
+		return;
+
+	manc = er32(MANC);
+
+	/* disable hardware interception of ARP */
+	manc &= ~(E1000_MANC_ARP_EN);
+
+	/* enable receiving management packets to the host. this will probably
+	 * generate destination unreachable messages from the host OS, but
+	 * the packets will be handled on SMBUS */
+	manc |= E1000_MANC_EN_MNG2HOST;
+	manc2h = er32(MANC2H);
+#define E1000_MNG2HOST_PORT_623 (1 << 5)
+#define E1000_MNG2HOST_PORT_664 (1 << 6)
+	manc2h |= E1000_MNG2HOST_PORT_623;
+	manc2h |= E1000_MNG2HOST_PORT_664;
+	ew32(MANC2H, manc2h);
+	ew32(MANC, manc);
+}
+
+/**
+ * e1000_configure_tx - Configure 8254x Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void e1000_configure_tx(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	u64 tdba;
+	u32 tdlen, tctl, tipg, tarc;
+	u32 ipgr1, ipgr2;
+
+	/* Setup the HW Tx Head and Tail descriptor pointers */
+	tdba = tx_ring->dma;
+	tdlen = tx_ring->count * sizeof(struct e1000_tx_desc);
+	ew32(TDBAL, (tdba & DMA_32BIT_MASK));
+	ew32(TDBAH, (tdba >> 32));
+	ew32(TDLEN, tdlen);
+	ew32(TDH, 0);
+	ew32(TDT, 0);
+	tx_ring->head = E1000_TDH;
+	tx_ring->tail = E1000_TDT;
+
+	/* Set the default values for the Tx Inter Packet Gap timer */
+	tipg = DEFAULT_82543_TIPG_IPGT_COPPER;          /*  8  */
+	ipgr1 = DEFAULT_82543_TIPG_IPGR1;               /*  8  */
+	ipgr2 = DEFAULT_82543_TIPG_IPGR2;               /*  6  */
+
+	if (adapter->flags & FLAG_TIPG_MEDIUM_FOR_80003ESLAN)
+		ipgr2 = DEFAULT_80003ES2LAN_TIPG_IPGR2; /*  7  */
+
+	tipg |= ipgr1 << E1000_TIPG_IPGR1_SHIFT;
+	tipg |= ipgr2 << E1000_TIPG_IPGR2_SHIFT;
+	ew32(TIPG, tipg);
+
+	/* Set the Tx Interrupt Delay register */
+	ew32(TIDV, adapter->tx_int_delay);
+	/* tx irq moderation */
+	ew32(TADV, adapter->tx_abs_int_delay);
+
+	/* Program the Transmit Control Register */
+	tctl = er32(TCTL);
+	tctl &= ~E1000_TCTL_CT;
+	tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
+		(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+
+	if (adapter->flags & FLAG_TARC_SPEED_MODE_BIT) {
+		tarc = er32(TARC0);
+		/* set the speed mode bit, we'll clear it if we're not at
+		 * gigabit link later */
+#define SPEED_MODE_BIT (1 << 21)
+		tarc |= SPEED_MODE_BIT;
+		ew32(TARC0, tarc);
+	}
+
+	/* errata: program both queues to unweighted RR */
+	if (adapter->flags & FLAG_TARC_SET_BIT_ZERO) {
+		tarc = er32(TARC0);
+		tarc |= 1;
+		ew32(TARC0, tarc);
+		tarc = er32(TARC1);
+		tarc |= 1;
+		ew32(TARC1, tarc);
+	}
+
+	e1000e_config_collision_dist(hw);
+
+	/* Setup Transmit Descriptor Settings for eop descriptor */
+	adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS;
+
+	/* only set IDE if we are delaying interrupts using the timers */
+	if (adapter->tx_int_delay)
+		adapter->txd_cmd |= E1000_TXD_CMD_IDE;
+
+	/* enable Report Status bit */
+	adapter->txd_cmd |= E1000_TXD_CMD_RS;
+
+	ew32(TCTL, tctl);
+
+	adapter->tx_queue_len = adapter->netdev->tx_queue_len;
+}
+
+/**
+ * e1000_setup_rctl - configure the receive control registers
+ * @adapter: Board private structure
+ **/
+#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \
+			   (((S) & (PAGE_SIZE - 1)) ? 1 : 0))
+static void e1000_setup_rctl(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u32 rctl, rfctl;
+	u32 psrctl = 0;
+	u32 pages = 0;
+
+	/* Program MC offset vector base */
+	rctl = er32(RCTL);
+	rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
+	rctl |= E1000_RCTL_EN | E1000_RCTL_BAM |
+		E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+		(adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
+
+	/* Do not Store bad packets */
+	rctl &= ~E1000_RCTL_SBP;
+
+	/* Enable Long Packet receive */
+	if (adapter->netdev->mtu <= ETH_DATA_LEN)
+		rctl &= ~E1000_RCTL_LPE;
+	else
+		rctl |= E1000_RCTL_LPE;
+
+	/* Setup buffer sizes */
+	rctl &= ~E1000_RCTL_SZ_4096;
+	rctl |= E1000_RCTL_BSEX;
+	switch (adapter->rx_buffer_len) {
+	case 256:
+		rctl |= E1000_RCTL_SZ_256;
+		rctl &= ~E1000_RCTL_BSEX;
+		break;
+	case 512:
+		rctl |= E1000_RCTL_SZ_512;
+		rctl &= ~E1000_RCTL_BSEX;
+		break;
+	case 1024:
+		rctl |= E1000_RCTL_SZ_1024;
+		rctl &= ~E1000_RCTL_BSEX;
+		break;
+	case 2048:
+	default:
+		rctl |= E1000_RCTL_SZ_2048;
+		rctl &= ~E1000_RCTL_BSEX;
+		break;
+	case 4096:
+		rctl |= E1000_RCTL_SZ_4096;
+		break;
+	case 8192:
+		rctl |= E1000_RCTL_SZ_8192;
+		break;
+	case 16384:
+		rctl |= E1000_RCTL_SZ_16384;
+		break;
+	}
+
+	/*
+	 * 82571 and greater support packet-split where the protocol
+	 * header is placed in skb->data and the packet data is
+	 * placed in pages hanging off of skb_shinfo(skb)->nr_frags.
+	 * In the case of a non-split, skb->data is linearly filled,
+	 * followed by the page buffers.  Therefore, skb->data is
+	 * sized to hold the largest protocol header.
+	 *
+	 * allocations using alloc_page take too long for regular MTU
+	 * so only enable packet split for jumbo frames
+	 *
+	 * Using pages when the page size is greater than 16k wastes
+	 * a lot of memory, since we allocate 3 pages at all times
+	 * per packet.
+	 */
+	adapter->rx_ps_pages = 0;
+	pages = PAGE_USE_COUNT(adapter->netdev->mtu);
+	if ((pages <= 3) && (PAGE_SIZE <= 16384) && (rctl & E1000_RCTL_LPE))
+		adapter->rx_ps_pages = pages;
+
+	if (adapter->rx_ps_pages) {
+		/* Configure extra packet-split registers */
+		rfctl = er32(RFCTL);
+		rfctl |= E1000_RFCTL_EXTEN;
+		/* disable packet split support for IPv6 extension headers,
+		 * because some malformed IPv6 headers can hang the RX */
+		rfctl |= (E1000_RFCTL_IPV6_EX_DIS |
+			  E1000_RFCTL_NEW_IPV6_EXT_DIS);
+
+		ew32(RFCTL, rfctl);
+
+		/* disable the stripping of CRC because it breaks
+		 * BMC firmware connected over SMBUS */
+		rctl |= E1000_RCTL_DTYP_PS /* | E1000_RCTL_SECRC */;
+
+		psrctl |= adapter->rx_ps_bsize0 >>
+			E1000_PSRCTL_BSIZE0_SHIFT;
+
+		switch (adapter->rx_ps_pages) {
+		case 3:
+			psrctl |= PAGE_SIZE <<
+				E1000_PSRCTL_BSIZE3_SHIFT;
+		case 2:
+			psrctl |= PAGE_SIZE <<
+				E1000_PSRCTL_BSIZE2_SHIFT;
+		case 1:
+			psrctl |= PAGE_SIZE >>
+				E1000_PSRCTL_BSIZE1_SHIFT;
+			break;
+		}
+
+		ew32(PSRCTL, psrctl);
+	}
+
+	ew32(RCTL, rctl);
+}
+
+/**
+ * e1000_configure_rx - Configure Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void e1000_configure_rx(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_ring *rx_ring = adapter->rx_ring;
+	u64 rdba;
+	u32 rdlen, rctl, rxcsum, ctrl_ext;
+
+	if (adapter->rx_ps_pages) {
+		/* this is a 32 byte descriptor */
+		rdlen = rx_ring->count *
+			sizeof(union e1000_rx_desc_packet_split);
+		adapter->clean_rx = e1000_clean_rx_irq_ps;
+		adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps;
+	} else if (adapter->netdev->mtu > ETH_FRAME_LEN + VLAN_HLEN + 4) {
+		rdlen = rx_ring->count *
+			sizeof(struct e1000_rx_desc);
+		adapter->clean_rx = e1000_clean_rx_irq_jumbo;
+		adapter->alloc_rx_buf = e1000_alloc_rx_buffers_jumbo;
+	} else {
+		rdlen = rx_ring->count *
+			sizeof(struct e1000_rx_desc);
+		adapter->clean_rx = e1000_clean_rx_irq;
+		adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
+	}
+
+	/* disable receives while setting up the descriptors */
+	rctl = er32(RCTL);
+	ew32(RCTL, rctl & ~E1000_RCTL_EN);
+	e1e_flush();
+	msleep(10);
+
+	/* set the Receive Delay Timer Register */
+	ew32(RDTR, adapter->rx_int_delay);
+
+	/* irq moderation */
+	ew32(RADV, adapter->rx_abs_int_delay);
+	if (adapter->itr_setting != 0)
+		ew32(ITR,
+			1000000000 / (adapter->itr * 256));
+
+	ctrl_ext = er32(CTRL_EXT);
+	/* Reset delay timers after every interrupt */
+	ctrl_ext |= E1000_CTRL_EXT_INT_TIMER_CLR;
+	/* Auto-Mask interrupts upon ICR access */
+	ctrl_ext |= E1000_CTRL_EXT_IAME;
+	ew32(IAM, 0xffffffff);
+	ew32(CTRL_EXT, ctrl_ext);
+	e1e_flush();
+
+	/* Setup the HW Rx Head and Tail Descriptor Pointers and
+	 * the Base and Length of the Rx Descriptor Ring */
+	rdba = rx_ring->dma;
+	ew32(RDBAL, (rdba & DMA_32BIT_MASK));
+	ew32(RDBAH, (rdba >> 32));
+	ew32(RDLEN, rdlen);
+	ew32(RDH, 0);
+	ew32(RDT, 0);
+	rx_ring->head = E1000_RDH;
+	rx_ring->tail = E1000_RDT;
+
+	/* Enable Receive Checksum Offload for TCP and UDP */
+	rxcsum = er32(RXCSUM);
+	if (adapter->flags & FLAG_RX_CSUM_ENABLED) {
+		rxcsum |= E1000_RXCSUM_TUOFL;
+
+		/* IPv4 payload checksum for UDP fragments must be
+		 * used in conjunction with packet-split. */
+		if (adapter->rx_ps_pages)
+			rxcsum |= E1000_RXCSUM_IPPCSE;
+	} else {
+		rxcsum &= ~E1000_RXCSUM_TUOFL;
+		/* no need to clear IPPCSE as it defaults to 0 */
+	}
+	ew32(RXCSUM, rxcsum);
+
+	/* Enable early receives on supported devices, only takes effect when
+	 * packet size is equal or larger than the specified value (in 8 byte
+	 * units), e.g. using jumbo frames when setting to E1000_ERT_2048 */
+	if ((adapter->flags & FLAG_HAS_ERT) &&
+	    (adapter->netdev->mtu > ETH_DATA_LEN))
+		ew32(ERT, E1000_ERT_2048);
+
+	/* Enable Receives */
+	ew32(RCTL, rctl);
+}
+
+/**
+ *  e1000_mc_addr_list_update - Update Multicast addresses
+ *  @hw: pointer to the HW structure
+ *  @mc_addr_list: array of multicast addresses to program
+ *  @mc_addr_count: number of multicast addresses to program
+ *  @rar_used_count: the first RAR register free to program
+ *  @rar_count: total number of supported Receive Address Registers
+ *
+ *  Updates the Receive Address Registers and Multicast Table Array.
+ *  The caller must have a packed mc_addr_list of multicast addresses.
+ *  The parameter rar_count will usually be hw->mac.rar_entry_count
+ *  unless there are workarounds that change this.  Currently no func pointer
+ *  exists and all implementations are handled in the generic version of this
+ *  function.
+ **/
+static void e1000_mc_addr_list_update(struct e1000_hw *hw, u8 *mc_addr_list,
+			       u32 mc_addr_count, u32 rar_used_count,
+			       u32 rar_count)
+{
+	hw->mac.ops.mc_addr_list_update(hw, mc_addr_list, mc_addr_count,
+				        rar_used_count, rar_count);
+}
+
+/**
+ * e1000_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi entry point is called whenever the multicast address
+ * list or the network interface flags are updated.  This routine is
+ * responsible for configuring the hardware for proper multicast,
+ * promiscuous mode, and all-multi behavior.
+ **/
+static void e1000_set_multi(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	struct e1000_mac_info *mac = &hw->mac;
+	struct dev_mc_list *mc_ptr;
+	u8  *mta_list;
+	u32 rctl;
+	int i;
+
+	/* Check for Promiscuous and All Multicast modes */
+
+	rctl = er32(RCTL);
+
+	if (netdev->flags & IFF_PROMISC) {
+		rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
+	} else if (netdev->flags & IFF_ALLMULTI) {
+		rctl |= E1000_RCTL_MPE;
+		rctl &= ~E1000_RCTL_UPE;
+	} else {
+		rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
+	}
+
+	ew32(RCTL, rctl);
+
+	if (netdev->mc_count) {
+		mta_list = kmalloc(netdev->mc_count * 6, GFP_ATOMIC);
+		if (!mta_list)
+			return;
+
+		/* prepare a packed array of only addresses. */
+		mc_ptr = netdev->mc_list;
+
+		for (i = 0; i < netdev->mc_count; i++) {
+			if (!mc_ptr)
+				break;
+			memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr,
+			       ETH_ALEN);
+			mc_ptr = mc_ptr->next;
+		}
+
+		e1000_mc_addr_list_update(hw, mta_list, i, 1,
+					  mac->rar_entry_count);
+		kfree(mta_list);
+	} else {
+		/*
+		 * if we're called from probe, we might not have
+		 * anything to do here, so clear out the list
+		 */
+		e1000_mc_addr_list_update(hw, NULL, 0, 1,
+					  mac->rar_entry_count);
+	}
+}
+
+/**
+ * e1000_configure - configure the hardware for RX and TX
+ * @adapter: private board structure
+ **/
+static void e1000_configure(struct e1000_adapter *adapter)
+{
+	e1000_set_multi(adapter->netdev);
+
+	e1000_restore_vlan(adapter);
+	e1000_init_manageability(adapter);
+
+	e1000_configure_tx(adapter);
+	e1000_setup_rctl(adapter);
+	e1000_configure_rx(adapter);
+	adapter->alloc_rx_buf(adapter,
+			      e1000_desc_unused(adapter->rx_ring));
+}
+
+/**
+ * e1000e_power_up_phy - restore link in case the phy was powered down
+ * @adapter: address of board private structure
+ *
+ * The phy may be powered down to save power and turn off link when the
+ * driver is unloaded and wake on lan is not enabled (among others)
+ * *** this routine MUST be followed by a call to e1000e_reset ***
+ **/
+void e1000e_power_up_phy(struct e1000_adapter *adapter)
+{
+	u16 mii_reg = 0;
+
+	/* Just clear the power down bit to wake the phy back up */
+	if (adapter->hw.media_type == e1000_media_type_copper) {
+		/* according to the manual, the phy will retain its
+		 * settings across a power-down/up cycle */
+		e1e_rphy(&adapter->hw, PHY_CONTROL, &mii_reg);
+		mii_reg &= ~MII_CR_POWER_DOWN;
+		e1e_wphy(&adapter->hw, PHY_CONTROL, mii_reg);
+	}
+
+	adapter->hw.mac.ops.setup_link(&adapter->hw);
+}
+
+/**
+ * e1000_power_down_phy - Power down the PHY
+ *
+ * Power down the PHY so no link is implied when interface is down
+ * The PHY cannot be powered down is management or WoL is active
+ */
+static void e1000_power_down_phy(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	u16 mii_reg;
+
+	/* WoL is enabled */
+	if (!adapter->wol)
+		return;
+
+	/* non-copper PHY? */
+	if (adapter->hw.media_type != e1000_media_type_copper)
+		return;
+
+	/* reset is blocked because of a SoL/IDER session */
+	if (e1000e_check_mng_mode(hw) ||
+	    e1000_check_reset_block(hw))
+		return;
+
+	/* managebility (AMT) is enabled */
+	if (er32(MANC) & E1000_MANC_SMBUS_EN)
+		return;
+
+	/* power down the PHY */
+	e1e_rphy(hw, PHY_CONTROL, &mii_reg);
+	mii_reg |= MII_CR_POWER_DOWN;
+	e1e_wphy(hw, PHY_CONTROL, mii_reg);
+	mdelay(1);
+}
+
+/**
+ * e1000e_reset - bring the hardware into a known good state
+ *
+ * This function boots the hardware and enables some settings that
+ * require a configuration cycle of the hardware - those cannot be
+ * set/changed during runtime. After reset the device needs to be
+ * properly configured for rx, tx etc.
+ */
+void e1000e_reset(struct e1000_adapter *adapter)
+{
+	struct e1000_mac_info *mac = &adapter->hw.mac;
+	struct e1000_hw *hw = &adapter->hw;
+	u32 tx_space, min_tx_space, min_rx_space;
+	u16 hwm;
+
+	if (mac->max_frame_size > ETH_FRAME_LEN + ETH_FCS_LEN ) {
+		/* To maintain wire speed transmits, the Tx FIFO should be
+		 * large enough to accommodate two full transmit packets,
+		 * rounded up to the next 1KB and expressed in KB.  Likewise,
+		 * the Rx FIFO should be large enough to accommodate at least
+		 * one full receive packet and is similarly rounded up and
+		 * expressed in KB. */
+		adapter->pba = er32(PBA);
+		/* upper 16 bits has Tx packet buffer allocation size in KB */
+		tx_space = adapter->pba >> 16;
+		/* lower 16 bits has Rx packet buffer allocation size in KB */
+		adapter->pba &= 0xffff;
+		/* the tx fifo also stores 16 bytes of information about the tx
+		 * but don't include ethernet FCS because hardware appends it */
+		min_tx_space = (mac->max_frame_size +
+				sizeof(struct e1000_tx_desc) -
+				ETH_FCS_LEN) * 2;
+		min_tx_space = ALIGN(min_tx_space, 1024);
+		min_tx_space >>= 10;
+		/* software strips receive CRC, so leave room for it */
+		min_rx_space = mac->max_frame_size;
+		min_rx_space = ALIGN(min_rx_space, 1024);
+		min_rx_space >>= 10;
+
+		/* If current Tx allocation is less than the min Tx FIFO size,
+		 * and the min Tx FIFO size is less than the current Rx FIFO
+		 * allocation, take space away from current Rx allocation */
+		if (tx_space < min_tx_space &&
+		    ((min_tx_space - tx_space) < adapter->pba)) {
+			adapter->pba -= - (min_tx_space - tx_space);
+
+			/* if short on rx space, rx wins and must trump tx
+			 * adjustment or use Early Receive if available */
+			if ((adapter->pba < min_rx_space) &&
+			    (!(adapter->flags & FLAG_HAS_ERT)))
+				/* ERT enabled in e1000_configure_rx */
+				adapter->pba = min_rx_space;
+		}
+	}
+
+	ew32(PBA, adapter->pba);
+
+	/* flow control settings */
+	/* The high water mark must be low enough to fit one full frame
+	 * (or the size used for early receive) above it in the Rx FIFO.
+	 * Set it to the lower of:
+	 * - 90% of the Rx FIFO size, and
+	 * - the full Rx FIFO size minus the early receive size (for parts
+	 *   with ERT support assuming ERT set to E1000_ERT_2048), or
+	 * - the full Rx FIFO size minus one full frame */
+	if (adapter->flags & FLAG_HAS_ERT)
+		hwm = min(((adapter->pba << 10) * 9 / 10),
+			  ((adapter->pba << 10) - (E1000_ERT_2048 << 3)));
+	else
+		hwm = min(((adapter->pba << 10) * 9 / 10),
+			  ((adapter->pba << 10) - mac->max_frame_size));
+
+	mac->fc_high_water = hwm & 0xFFF8; /* 8-byte granularity */
+	mac->fc_low_water = mac->fc_high_water - 8;
+
+	if (adapter->flags & FLAG_DISABLE_FC_PAUSE_TIME)
+		mac->fc_pause_time = 0xFFFF;
+	else
+		mac->fc_pause_time = E1000_FC_PAUSE_TIME;
+	mac->fc = mac->original_fc;
+
+	/* Allow time for pending master requests to run */
+	mac->ops.reset_hw(hw);
+	ew32(WUC, 0);
+
+	if (mac->ops.init_hw(hw))
+		ndev_err(adapter->netdev, "Hardware Error\n");
+
+	e1000_update_mng_vlan(adapter);
+
+	/* Enable h/w to recognize an 802.1Q VLAN Ethernet packet */
+	ew32(VET, ETH_P_8021Q);
+
+	e1000e_reset_adaptive(hw);
+	e1000_get_phy_info(hw);
+
+	if (!(adapter->flags & FLAG_SMART_POWER_DOWN)) {
+		u16 phy_data = 0;
+		/* speed up time to link by disabling smart power down, ignore
+		 * the return value of this function because there is nothing
+		 * different we would do if it failed */
+		e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
+		phy_data &= ~IGP02E1000_PM_SPD;
+		e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
+	}
+
+	e1000_release_manageability(adapter);
+}
+
+int e1000e_up(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+
+	/* hardware has been reset, we need to reload some things */
+	e1000_configure(adapter);
+
+	clear_bit(__E1000_DOWN, &adapter->state);
+
+	napi_enable(&adapter->napi);
+	e1000_irq_enable(adapter);
+
+	/* fire a link change interrupt to start the watchdog */
+	ew32(ICS, E1000_ICS_LSC);
+	return 0;
+}
+
+void e1000e_down(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct e1000_hw *hw = &adapter->hw;
+	u32 tctl, rctl;
+
+	/* signal that we're down so the interrupt handler does not
+	 * reschedule our watchdog timer */
+	set_bit(__E1000_DOWN, &adapter->state);
+
+	/* disable receives in the hardware */
+	rctl = er32(RCTL);
+	ew32(RCTL, rctl & ~E1000_RCTL_EN);
+	/* flush and sleep below */
+
+	netif_stop_queue(netdev);
+
+	/* disable transmits in the hardware */
+	tctl = er32(TCTL);
+	tctl &= ~E1000_TCTL_EN;
+	ew32(TCTL, tctl);
+	/* flush both disables and wait for them to finish */
+	e1e_flush();
+	msleep(10);
+
+	napi_disable(&adapter->napi);
+	e1000_irq_disable(adapter);
+
+	del_timer_sync(&adapter->watchdog_timer);
+	del_timer_sync(&adapter->phy_info_timer);
+
+	netdev->tx_queue_len = adapter->tx_queue_len;
+	netif_carrier_off(netdev);
+	adapter->link_speed = 0;
+	adapter->link_duplex = 0;
+
+	e1000e_reset(adapter);
+	e1000_clean_tx_ring(adapter);
+	e1000_clean_rx_ring(adapter);
+
+	/*
+	 * TODO: for power management, we could drop the link and
+	 * pci_disable_device here.
+	 */
+}
+
+void e1000e_reinit_locked(struct e1000_adapter *adapter)
+{
+	might_sleep();
+	while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
+		msleep(1);
+	e1000e_down(adapter);
+	e1000e_up(adapter);
+	clear_bit(__E1000_RESETTING, &adapter->state);
+}
+
+/**
+ * e1000_sw_init - Initialize general software structures (struct e1000_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * e1000_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+
+	adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN;
+	adapter->rx_ps_bsize0 = 128;
+	hw->mac.max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+	hw->mac.min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
+
+	adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+	if (!adapter->tx_ring)
+		goto err;
+
+	adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
+	if (!adapter->rx_ring)
+		goto err;
+
+	spin_lock_init(&adapter->tx_queue_lock);
+
+	/* Explicitly disable IRQ since the NIC can be in any state. */
+	atomic_set(&adapter->irq_sem, 0);
+	e1000_irq_disable(adapter);
+
+	spin_lock_init(&adapter->stats_lock);
+
+	set_bit(__E1000_DOWN, &adapter->state);
+	return 0;
+
+err:
+	ndev_err(netdev, "Unable to allocate memory for queues\n");
+	kfree(adapter->rx_ring);
+	kfree(adapter->tx_ring);
+	return -ENOMEM;
+}
+
+/**
+ * e1000_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+static int e1000_open(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	int err;
+
+	/* disallow open during test */
+	if (test_bit(__E1000_TESTING, &adapter->state))
+		return -EBUSY;
+
+	/* allocate transmit descriptors */
+	err = e1000e_setup_tx_resources(adapter);
+	if (err)
+		goto err_setup_tx;
+
+	/* allocate receive descriptors */
+	err = e1000e_setup_rx_resources(adapter);
+	if (err)
+		goto err_setup_rx;
+
+	e1000e_power_up_phy(adapter);
+
+	adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
+	if ((adapter->hw.mng_cookie.status &
+	     E1000_MNG_DHCP_COOKIE_STATUS_VLAN))
+		e1000_update_mng_vlan(adapter);
+
+	/* If AMT is enabled, let the firmware know that the network
+	 * interface is now open */
+	if ((adapter->flags & FLAG_HAS_AMT) &&
+	    e1000e_check_mng_mode(&adapter->hw))
+		e1000_get_hw_control(adapter);
+
+	/* before we allocate an interrupt, we must be ready to handle it.
+	 * Setting DEBUG_SHIRQ in the kernel makes it fire an interrupt
+	 * as soon as we call pci_request_irq, so we have to setup our
+	 * clean_rx handler before we do so.  */
+	e1000_configure(adapter);
+
+	err = e1000_request_irq(adapter);
+	if (err)
+		goto err_req_irq;
+
+	/* From here on the code is the same as e1000e_up() */
+	clear_bit(__E1000_DOWN, &adapter->state);
+
+	napi_enable(&adapter->napi);
+
+	e1000_irq_enable(adapter);
+
+	/* fire a link status change interrupt to start the watchdog */
+	ew32(ICS, E1000_ICS_LSC);
+
+	return 0;
+
+err_req_irq:
+	e1000_release_hw_control(adapter);
+	e1000_power_down_phy(adapter);
+	e1000e_free_rx_resources(adapter);
+err_setup_rx:
+	e1000e_free_tx_resources(adapter);
+err_setup_tx:
+	e1000e_reset(adapter);
+
+	return err;
+}
+
+/**
+ * e1000_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the drivers control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+static int e1000_close(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
+	e1000e_down(adapter);
+	e1000_power_down_phy(adapter);
+	e1000_free_irq(adapter);
+
+	e1000e_free_tx_resources(adapter);
+	e1000e_free_rx_resources(adapter);
+
+	/* kill manageability vlan ID if supported, but not if a vlan with
+	 * the same ID is registered on the host OS (let 8021q kill it) */
+	if ((adapter->hw.mng_cookie.status &
+			  E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
+	     !(adapter->vlgrp &&
+	       vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id)))
+		e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
+
+	/* If AMT is enabled, let the firmware know that the network
+	 * interface is now closed */
+	if ((adapter->flags & FLAG_HAS_AMT) &&
+	    e1000e_check_mng_mode(&adapter->hw))
+		e1000_release_hw_control(adapter);
+
+	return 0;
+}
+/**
+ * e1000_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int e1000_set_mac(struct net_device *netdev, void *p)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct sockaddr *addr = p;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+	memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len);
+
+	e1000e_rar_set(&adapter->hw, adapter->hw.mac.addr, 0);
+
+	if (adapter->flags & FLAG_RESET_OVERWRITES_LAA) {
+		/* activate the work around */
+		e1000e_set_laa_state_82571(&adapter->hw, 1);
+
+		/* Hold a copy of the LAA in RAR[14] This is done so that
+		 * between the time RAR[0] gets clobbered  and the time it
+		 * gets fixed (in e1000_watchdog), the actual LAA is in one
+		 * of the RARs and no incoming packets directed to this port
+		 * are dropped. Eventually the LAA will be in RAR[0] and
+		 * RAR[14] */
+		e1000e_rar_set(&adapter->hw,
+			      adapter->hw.mac.addr,
+			      adapter->hw.mac.rar_entry_count - 1);
+	}
+
+	return 0;
+}
+
+/* Need to wait a few seconds after link up to get diagnostic information from
+ * the phy */
+static void e1000_update_phy_info(unsigned long data)
+{
+	struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+	e1000_get_phy_info(&adapter->hw);
+}
+
+/**
+ * e1000e_update_stats - Update the board statistics counters
+ * @adapter: board private structure
+ **/
+void e1000e_update_stats(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct pci_dev *pdev = adapter->pdev;
+	unsigned long irq_flags;
+	u16 phy_tmp;
+
+#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
+
+	/*
+	 * Prevent stats update while adapter is being reset, or if the pci
+	 * connection is down.
+	 */
+	if (adapter->link_speed == 0)
+		return;
+	if (pci_channel_offline(pdev))
+		return;
+
+	spin_lock_irqsave(&adapter->stats_lock, irq_flags);
+
+	/* these counters are modified from e1000_adjust_tbi_stats,
+	 * called from the interrupt context, so they must only
+	 * be written while holding adapter->stats_lock
+	 */
+
+	adapter->stats.crcerrs += er32(CRCERRS);
+	adapter->stats.gprc += er32(GPRC);
+	adapter->stats.gorcl += er32(GORCL);
+	adapter->stats.gorch += er32(GORCH);
+	adapter->stats.bprc += er32(BPRC);
+	adapter->stats.mprc += er32(MPRC);
+	adapter->stats.roc += er32(ROC);
+
+	if (adapter->flags & FLAG_HAS_STATS_PTC_PRC) {
+		adapter->stats.prc64 += er32(PRC64);
+		adapter->stats.prc127 += er32(PRC127);
+		adapter->stats.prc255 += er32(PRC255);
+		adapter->stats.prc511 += er32(PRC511);
+		adapter->stats.prc1023 += er32(PRC1023);
+		adapter->stats.prc1522 += er32(PRC1522);
+		adapter->stats.symerrs += er32(SYMERRS);
+		adapter->stats.sec += er32(SEC);
+	}
+
+	adapter->stats.mpc += er32(MPC);
+	adapter->stats.scc += er32(SCC);
+	adapter->stats.ecol += er32(ECOL);
+	adapter->stats.mcc += er32(MCC);
+	adapter->stats.latecol += er32(LATECOL);
+	adapter->stats.dc += er32(DC);
+	adapter->stats.rlec += er32(RLEC);
+	adapter->stats.xonrxc += er32(XONRXC);
+	adapter->stats.xontxc += er32(XONTXC);
+	adapter->stats.xoffrxc += er32(XOFFRXC);
+	adapter->stats.xofftxc += er32(XOFFTXC);
+	adapter->stats.fcruc += er32(FCRUC);
+	adapter->stats.gptc += er32(GPTC);
+	adapter->stats.gotcl += er32(GOTCL);
+	adapter->stats.gotch += er32(GOTCH);
+	adapter->stats.rnbc += er32(RNBC);
+	adapter->stats.ruc += er32(RUC);
+	adapter->stats.rfc += er32(RFC);
+	adapter->stats.rjc += er32(RJC);
+	adapter->stats.torl += er32(TORL);
+	adapter->stats.torh += er32(TORH);
+	adapter->stats.totl += er32(TOTL);
+	adapter->stats.toth += er32(TOTH);
+	adapter->stats.tpr += er32(TPR);
+
+	if (adapter->flags & FLAG_HAS_STATS_PTC_PRC) {
+		adapter->stats.ptc64 += er32(PTC64);
+		adapter->stats.ptc127 += er32(PTC127);
+		adapter->stats.ptc255 += er32(PTC255);
+		adapter->stats.ptc511 += er32(PTC511);
+		adapter->stats.ptc1023 += er32(PTC1023);
+		adapter->stats.ptc1522 += er32(PTC1522);
+	}
+
+	adapter->stats.mptc += er32(MPTC);
+	adapter->stats.bptc += er32(BPTC);
+
+	/* used for adaptive IFS */
+
+	hw->mac.tx_packet_delta = er32(TPT);
+	adapter->stats.tpt += hw->mac.tx_packet_delta;
+	hw->mac.collision_delta = er32(COLC);
+	adapter->stats.colc += hw->mac.collision_delta;
+
+	adapter->stats.algnerrc += er32(ALGNERRC);
+	adapter->stats.rxerrc += er32(RXERRC);
+	adapter->stats.tncrs += er32(TNCRS);
+	adapter->stats.cexterr += er32(CEXTERR);
+	adapter->stats.tsctc += er32(TSCTC);
+	adapter->stats.tsctfc += er32(TSCTFC);
+
+	adapter->stats.iac += er32(IAC);
+
+	if (adapter->flags & FLAG_HAS_STATS_ICR_ICT) {
+		adapter->stats.icrxoc += er32(ICRXOC);
+		adapter->stats.icrxptc += er32(ICRXPTC);
+		adapter->stats.icrxatc += er32(ICRXATC);
+		adapter->stats.ictxptc += er32(ICTXPTC);
+		adapter->stats.ictxatc += er32(ICTXATC);
+		adapter->stats.ictxqec += er32(ICTXQEC);
+		adapter->stats.ictxqmtc += er32(ICTXQMTC);
+		adapter->stats.icrxdmtc += er32(ICRXDMTC);
+	}
+
+	/* Fill out the OS statistics structure */
+	adapter->net_stats.rx_packets = adapter->stats.gprc;
+	adapter->net_stats.tx_packets = adapter->stats.gptc;
+	adapter->net_stats.rx_bytes = adapter->stats.gorcl;
+	adapter->net_stats.tx_bytes = adapter->stats.gotcl;
+	adapter->net_stats.multicast = adapter->stats.mprc;
+	adapter->net_stats.collisions = adapter->stats.colc;
+
+	/* Rx Errors */
+
+	/* RLEC on some newer hardware can be incorrect so build
+	* our own version based on RUC and ROC */
+	adapter->net_stats.rx_errors = adapter->stats.rxerrc +
+		adapter->stats.crcerrs + adapter->stats.algnerrc +
+		adapter->stats.ruc + adapter->stats.roc +
+		adapter->stats.cexterr;
+	adapter->net_stats.rx_length_errors = adapter->stats.ruc +
+					      adapter->stats.roc;
+	adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
+	adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc;
+	adapter->net_stats.rx_missed_errors = adapter->stats.mpc;
+
+	/* Tx Errors */
+	adapter->net_stats.tx_errors = adapter->stats.ecol +
+				       adapter->stats.latecol;
+	adapter->net_stats.tx_aborted_errors = adapter->stats.ecol;
+	adapter->net_stats.tx_window_errors = adapter->stats.latecol;
+	adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs;
+
+	/* Tx Dropped needs to be maintained elsewhere */
+
+	/* Phy Stats */
+	if (hw->media_type == e1000_media_type_copper) {
+		if ((adapter->link_speed == SPEED_1000) &&
+		   (!e1e_rphy(hw, PHY_1000T_STATUS, &phy_tmp))) {
+			phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
+			adapter->phy_stats.idle_errors += phy_tmp;
+		}
+	}
+
+	/* Management Stats */
+	adapter->stats.mgptc += er32(MGTPTC);
+	adapter->stats.mgprc += er32(MGTPRC);
+	adapter->stats.mgpdc += er32(MGTPDC);
+
+	spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
+}
+
+static void e1000_print_link_info(struct e1000_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl = er32(CTRL);
+
+	ndev_info(netdev,
+		"Link is Up %d Mbps %s, Flow Control: %s\n",
+		adapter->link_speed,
+		(adapter->link_duplex == FULL_DUPLEX) ?
+				"Full Duplex" : "Half Duplex",
+		((ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE)) ?
+				"RX/TX" :
+		((ctrl & E1000_CTRL_RFCE) ? "RX" :
+		((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" )));
+}
+
+/**
+ * e1000_watchdog - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
+ **/
+static void e1000_watchdog(unsigned long data)
+{
+	struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+
+	/* Do the rest outside of interrupt context */
+	schedule_work(&adapter->watchdog_task);
+
+	/* TODO: make this use queue_delayed_work() */
+}
+
+static void e1000_watchdog_task(struct work_struct *work)
+{
+	struct e1000_adapter *adapter = container_of(work,
+					struct e1000_adapter, watchdog_task);
+
+	struct net_device *netdev = adapter->netdev;
+	struct e1000_mac_info *mac = &adapter->hw.mac;
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	struct e1000_hw *hw = &adapter->hw;
+	u32 link, tctl;
+	s32 ret_val;
+	int tx_pending = 0;
+
+	if ((netif_carrier_ok(netdev)) &&
+	    (er32(STATUS) & E1000_STATUS_LU))
+		goto link_up;
+
+	ret_val = mac->ops.check_for_link(hw);
+	if ((ret_val == E1000_ERR_PHY) &&
+	    (adapter->hw.phy.type == e1000_phy_igp_3) &&
+	    (er32(CTRL) &
+	     E1000_PHY_CTRL_GBE_DISABLE)) {
+		/* See e1000_kmrn_lock_loss_workaround_ich8lan() */
+		ndev_info(netdev,
+			"Gigabit has been disabled, downgrading speed\n");
+	}
+
+	if ((e1000e_enable_tx_pkt_filtering(hw)) &&
+	    (adapter->mng_vlan_id != adapter->hw.mng_cookie.vlan_id))
+		e1000_update_mng_vlan(adapter);
+
+	if ((adapter->hw.media_type == e1000_media_type_internal_serdes) &&
+	   !(er32(TXCW) & E1000_TXCW_ANE))
+		link = adapter->hw.mac.serdes_has_link;
+	else
+		link = er32(STATUS) & E1000_STATUS_LU;
+
+	if (link) {
+		if (!netif_carrier_ok(netdev)) {
+			bool txb2b = 1;
+			mac->ops.get_link_up_info(&adapter->hw,
+						   &adapter->link_speed,
+						   &adapter->link_duplex);
+			e1000_print_link_info(adapter);
+			/* tweak tx_queue_len according to speed/duplex
+			 * and adjust the timeout factor */
+			netdev->tx_queue_len = adapter->tx_queue_len;
+			adapter->tx_timeout_factor = 1;
+			switch (adapter->link_speed) {
+			case SPEED_10:
+				txb2b = 0;
+				netdev->tx_queue_len = 10;
+				adapter->tx_timeout_factor = 14;
+				break;
+			case SPEED_100:
+				txb2b = 0;
+				netdev->tx_queue_len = 100;
+				/* maybe add some timeout factor ? */
+				break;
+			}
+
+			/* workaround: re-program speed mode bit after
+			 * link-up event */
+			if ((adapter->flags & FLAG_TARC_SPEED_MODE_BIT) &&
+			    !txb2b) {
+				u32 tarc0;
+				tarc0 = er32(TARC0);
+				tarc0 &= ~SPEED_MODE_BIT;
+				ew32(TARC0, tarc0);
+			}
+
+			/* disable TSO for pcie and 10/100 speeds, to avoid
+			 * some hardware issues */
+			if (!(adapter->flags & FLAG_TSO_FORCE)) {
+				switch (adapter->link_speed) {
+				case SPEED_10:
+				case SPEED_100:
+					ndev_info(netdev,
+					"10/100 speed: disabling TSO\n");
+					netdev->features &= ~NETIF_F_TSO;
+					netdev->features &= ~NETIF_F_TSO6;
+					break;
+				case SPEED_1000:
+					netdev->features |= NETIF_F_TSO;
+					netdev->features |= NETIF_F_TSO6;
+					break;
+				default:
+					/* oops */
+					break;
+				}
+			}
+
+			/* enable transmits in the hardware, need to do this
+			 * after setting TARC0 */
+			tctl = er32(TCTL);
+			tctl |= E1000_TCTL_EN;
+			ew32(TCTL, tctl);
+
+			netif_carrier_on(netdev);
+			netif_wake_queue(netdev);
+
+			if (!test_bit(__E1000_DOWN, &adapter->state))
+				mod_timer(&adapter->phy_info_timer,
+					  round_jiffies(jiffies + 2 * HZ));
+		} else {
+			/* make sure the receive unit is started */
+			if (adapter->flags & FLAG_RX_NEEDS_RESTART) {
+				u32 rctl = er32(RCTL);
+				ew32(RCTL, rctl |
+						E1000_RCTL_EN);
+			}
+		}
+	} else {
+		if (netif_carrier_ok(netdev)) {
+			adapter->link_speed = 0;
+			adapter->link_duplex = 0;
+			ndev_info(netdev, "Link is Down\n");
+			netif_carrier_off(netdev);
+			netif_stop_queue(netdev);
+			if (!test_bit(__E1000_DOWN, &adapter->state))
+				mod_timer(&adapter->phy_info_timer,
+					  round_jiffies(jiffies + 2 * HZ));
+
+			if (adapter->flags & FLAG_RX_NEEDS_RESTART)
+				schedule_work(&adapter->reset_task);
+		}
+	}
+
+link_up:
+	e1000e_update_stats(adapter);
+
+	mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old;
+	adapter->tpt_old = adapter->stats.tpt;
+	mac->collision_delta = adapter->stats.colc - adapter->colc_old;
+	adapter->colc_old = adapter->stats.colc;
+
+	adapter->gorcl = adapter->stats.gorcl - adapter->gorcl_old;
+	adapter->gorcl_old = adapter->stats.gorcl;
+	adapter->gotcl = adapter->stats.gotcl - adapter->gotcl_old;
+	adapter->gotcl_old = adapter->stats.gotcl;
+
+	e1000e_update_adaptive(&adapter->hw);
+
+	if (!netif_carrier_ok(netdev)) {
+		tx_pending = (e1000_desc_unused(tx_ring) + 1 <
+			       tx_ring->count);
+		if (tx_pending) {
+			/* We've lost link, so the controller stops DMA,
+			 * but we've got queued Tx work that's never going
+			 * to get done, so reset controller to flush Tx.
+			 * (Do the reset outside of interrupt context). */
+			adapter->tx_timeout_count++;
+			schedule_work(&adapter->reset_task);
+		}
+	}
+
+	/* Cause software interrupt to ensure rx ring is cleaned */
+	ew32(ICS, E1000_ICS_RXDMT0);
+
+	/* Force detection of hung controller every watchdog period */
+	adapter->detect_tx_hung = 1;
+
+	/* With 82571 controllers, LAA may be overwritten due to controller
+	 * reset from the other port. Set the appropriate LAA in RAR[0] */
+	if (e1000e_get_laa_state_82571(hw))
+		e1000e_rar_set(hw, adapter->hw.mac.addr, 0);
+
+	/* Reset the timer */
+	if (!test_bit(__E1000_DOWN, &adapter->state))
+		mod_timer(&adapter->watchdog_timer,
+			  round_jiffies(jiffies + 2 * HZ));
+}
+
+#define E1000_TX_FLAGS_CSUM		0x00000001
+#define E1000_TX_FLAGS_VLAN		0x00000002
+#define E1000_TX_FLAGS_TSO		0x00000004
+#define E1000_TX_FLAGS_IPV4		0x00000008
+#define E1000_TX_FLAGS_VLAN_MASK	0xffff0000
+#define E1000_TX_FLAGS_VLAN_SHIFT	16
+
+static int e1000_tso(struct e1000_adapter *adapter,
+		     struct sk_buff *skb)
+{
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	struct e1000_context_desc *context_desc;
+	struct e1000_buffer *buffer_info;
+	unsigned int i;
+	u32 cmd_length = 0;
+	u16 ipcse = 0, tucse, mss;
+	u8 ipcss, ipcso, tucss, tucso, hdr_len;
+	int err;
+
+	if (skb_is_gso(skb)) {
+		if (skb_header_cloned(skb)) {
+			err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+			if (err)
+				return err;
+		}
+
+		hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+		mss = skb_shinfo(skb)->gso_size;
+		if (skb->protocol == htons(ETH_P_IP)) {
+			struct iphdr *iph = ip_hdr(skb);
+			iph->tot_len = 0;
+			iph->check = 0;
+			tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+								 iph->daddr, 0,
+								 IPPROTO_TCP,
+								 0);
+			cmd_length = E1000_TXD_CMD_IP;
+			ipcse = skb_transport_offset(skb) - 1;
+		} else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
+			ipv6_hdr(skb)->payload_len = 0;
+			tcp_hdr(skb)->check =
+				~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+						 &ipv6_hdr(skb)->daddr,
+						 0, IPPROTO_TCP, 0);
+			ipcse = 0;
+		}
+		ipcss = skb_network_offset(skb);
+		ipcso = (void *)&(ip_hdr(skb)->check) - (void *)skb->data;
+		tucss = skb_transport_offset(skb);
+		tucso = (void *)&(tcp_hdr(skb)->check) - (void *)skb->data;
+		tucse = 0;
+
+		cmd_length |= (E1000_TXD_CMD_DEXT | E1000_TXD_CMD_TSE |
+			       E1000_TXD_CMD_TCP | (skb->len - (hdr_len)));
+
+		i = tx_ring->next_to_use;
+		context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
+		buffer_info = &tx_ring->buffer_info[i];
+
+		context_desc->lower_setup.ip_fields.ipcss  = ipcss;
+		context_desc->lower_setup.ip_fields.ipcso  = ipcso;
+		context_desc->lower_setup.ip_fields.ipcse  = cpu_to_le16(ipcse);
+		context_desc->upper_setup.tcp_fields.tucss = tucss;
+		context_desc->upper_setup.tcp_fields.tucso = tucso;
+		context_desc->upper_setup.tcp_fields.tucse = cpu_to_le16(tucse);
+		context_desc->tcp_seg_setup.fields.mss     = cpu_to_le16(mss);
+		context_desc->tcp_seg_setup.fields.hdr_len = hdr_len;
+		context_desc->cmd_and_length = cpu_to_le32(cmd_length);
+
+		buffer_info->time_stamp = jiffies;
+		buffer_info->next_to_watch = i;
+
+		i++;
+		if (i == tx_ring->count)
+			i = 0;
+		tx_ring->next_to_use = i;
+
+		return 1;
+	}
+
+	return 0;
+}
+
+static bool e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
+{
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	struct e1000_context_desc *context_desc;
+	struct e1000_buffer *buffer_info;
+	unsigned int i;
+	u8 css;
+
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		css = skb_transport_offset(skb);
+
+		i = tx_ring->next_to_use;
+		buffer_info = &tx_ring->buffer_info[i];
+		context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
+
+		context_desc->lower_setup.ip_config = 0;
+		context_desc->upper_setup.tcp_fields.tucss = css;
+		context_desc->upper_setup.tcp_fields.tucso =
+					css + skb->csum_offset;
+		context_desc->upper_setup.tcp_fields.tucse = 0;
+		context_desc->tcp_seg_setup.data = 0;
+		context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
+
+		buffer_info->time_stamp = jiffies;
+		buffer_info->next_to_watch = i;
+
+		i++;
+		if (i == tx_ring->count)
+			i = 0;
+		tx_ring->next_to_use = i;
+
+		return 1;
+	}
+
+	return 0;
+}
+
+#define E1000_MAX_PER_TXD	8192
+#define E1000_MAX_TXD_PWR	12
+
+static int e1000_tx_map(struct e1000_adapter *adapter,
+			struct sk_buff *skb, unsigned int first,
+			unsigned int max_per_txd, unsigned int nr_frags,
+			unsigned int mss)
+{
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	struct e1000_buffer *buffer_info;
+	unsigned int len = skb->len - skb->data_len;
+	unsigned int offset = 0, size, count = 0, i;
+	unsigned int f;
+
+	i = tx_ring->next_to_use;
+
+	while (len) {
+		buffer_info = &tx_ring->buffer_info[i];
+		size = min(len, max_per_txd);
+
+		/* Workaround for premature desc write-backs
+		 * in TSO mode.  Append 4-byte sentinel desc */
+		if (mss && !nr_frags && size == len && size > 8)
+			size -= 4;
+
+		buffer_info->length = size;
+		/* set time_stamp *before* dma to help avoid a possible race */
+		buffer_info->time_stamp = jiffies;
+		buffer_info->dma =
+			pci_map_single(adapter->pdev,
+				skb->data + offset,
+				size,
+				PCI_DMA_TODEVICE);
+		if (pci_dma_mapping_error(buffer_info->dma)) {
+			dev_err(&adapter->pdev->dev, "TX DMA map failed\n");
+			adapter->tx_dma_failed++;
+			return -1;
+		}
+		buffer_info->next_to_watch = i;
+
+		len -= size;
+		offset += size;
+		count++;
+		i++;
+		if (i == tx_ring->count)
+			i = 0;
+	}
+
+	for (f = 0; f < nr_frags; f++) {
+		struct skb_frag_struct *frag;
+
+		frag = &skb_shinfo(skb)->frags[f];
+		len = frag->size;
+		offset = frag->page_offset;
+
+		while (len) {
+			buffer_info = &tx_ring->buffer_info[i];
+			size = min(len, max_per_txd);
+			/* Workaround for premature desc write-backs
+			 * in TSO mode.  Append 4-byte sentinel desc */
+			if (mss && f == (nr_frags-1) && size == len && size > 8)
+				size -= 4;
+
+			buffer_info->length = size;
+			buffer_info->time_stamp = jiffies;
+			buffer_info->dma =
+				pci_map_page(adapter->pdev,
+					frag->page,
+					offset,
+					size,
+					PCI_DMA_TODEVICE);
+			if (pci_dma_mapping_error(buffer_info->dma)) {
+				dev_err(&adapter->pdev->dev,
+					"TX DMA page map failed\n");
+				adapter->tx_dma_failed++;
+				return -1;
+			}
+
+			buffer_info->next_to_watch = i;
+
+			len -= size;
+			offset += size;
+			count++;
+
+			i++;
+			if (i == tx_ring->count)
+				i = 0;
+		}
+	}
+
+	if (i == 0)
+		i = tx_ring->count - 1;
+	else
+		i--;
+
+	tx_ring->buffer_info[i].skb = skb;
+	tx_ring->buffer_info[first].next_to_watch = i;
+
+	return count;
+}
+
+static void e1000_tx_queue(struct e1000_adapter *adapter,
+			   int tx_flags, int count)
+{
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	struct e1000_tx_desc *tx_desc = NULL;
+	struct e1000_buffer *buffer_info;
+	u32 txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS;
+	unsigned int i;
+
+	if (tx_flags & E1000_TX_FLAGS_TSO) {
+		txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D |
+			     E1000_TXD_CMD_TSE;
+		txd_upper |= E1000_TXD_POPTS_TXSM << 8;
+
+		if (tx_flags & E1000_TX_FLAGS_IPV4)
+			txd_upper |= E1000_TXD_POPTS_IXSM << 8;
+	}
+
+	if (tx_flags & E1000_TX_FLAGS_CSUM) {
+		txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
+		txd_upper |= E1000_TXD_POPTS_TXSM << 8;
+	}
+
+	if (tx_flags & E1000_TX_FLAGS_VLAN) {
+		txd_lower |= E1000_TXD_CMD_VLE;
+		txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK);
+	}
+
+	i = tx_ring->next_to_use;
+
+	while (count--) {
+		buffer_info = &tx_ring->buffer_info[i];
+		tx_desc = E1000_TX_DESC(*tx_ring, i);
+		tx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+		tx_desc->lower.data =
+			cpu_to_le32(txd_lower | buffer_info->length);
+		tx_desc->upper.data = cpu_to_le32(txd_upper);
+
+		i++;
+		if (i == tx_ring->count)
+			i = 0;
+	}
+
+	tx_desc->lower.data |= cpu_to_le32(adapter->txd_cmd);
+
+	/* Force memory writes to complete before letting h/w
+	 * know there are new descriptors to fetch.  (Only
+	 * applicable for weak-ordered memory model archs,
+	 * such as IA-64). */
+	wmb();
+
+	tx_ring->next_to_use = i;
+	writel(i, adapter->hw.hw_addr + tx_ring->tail);
+	/* we need this if more than one processor can write to our tail
+	 * at a time, it synchronizes IO on IA64/Altix systems */
+	mmiowb();
+}
+
+#define MINIMUM_DHCP_PACKET_SIZE 282
+static int e1000_transfer_dhcp_info(struct e1000_adapter *adapter,
+				    struct sk_buff *skb)
+{
+	struct e1000_hw *hw =  &adapter->hw;
+	u16 length, offset;
+
+	if (vlan_tx_tag_present(skb)) {
+		if (!((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id)
+		    && (adapter->hw.mng_cookie.status &
+			E1000_MNG_DHCP_COOKIE_STATUS_VLAN)))
+			return 0;
+	}
+
+	if (skb->len <= MINIMUM_DHCP_PACKET_SIZE)
+		return 0;
+
+	if (((struct ethhdr *) skb->data)->h_proto != htons(ETH_P_IP))
+		return 0;
+
+	{
+		const struct iphdr *ip = (struct iphdr *)((u8 *)skb->data+14);
+		struct udphdr *udp;
+
+		if (ip->protocol != IPPROTO_UDP)
+			return 0;
+
+		udp = (struct udphdr *)((u8 *)ip + (ip->ihl << 2));
+		if (ntohs(udp->dest) != 67)
+			return 0;
+
+		offset = (u8 *)udp + 8 - skb->data;
+		length = skb->len - offset;
+		return e1000e_mng_write_dhcp_info(hw, (u8 *)udp + 8, length);
+	}
+
+	return 0;
+}
+
+static int __e1000_maybe_stop_tx(struct net_device *netdev, int size)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	netif_stop_queue(netdev);
+	/* Herbert's original patch had:
+	 *  smp_mb__after_netif_stop_queue();
+	 * but since that doesn't exist yet, just open code it. */
+	smp_mb();
+
+	/* We need to check again in a case another CPU has just
+	 * made room available. */
+	if (e1000_desc_unused(adapter->tx_ring) < size)
+		return -EBUSY;
+
+	/* A reprieve! */
+	netif_start_queue(netdev);
+	++adapter->restart_queue;
+	return 0;
+}
+
+static int e1000_maybe_stop_tx(struct net_device *netdev, int size)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	if (e1000_desc_unused(adapter->tx_ring) >= size)
+		return 0;
+	return __e1000_maybe_stop_tx(netdev, size);
+}
+
+#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 )
+static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_ring *tx_ring = adapter->tx_ring;
+	unsigned int first;
+	unsigned int max_per_txd = E1000_MAX_PER_TXD;
+	unsigned int max_txd_pwr = E1000_MAX_TXD_PWR;
+	unsigned int tx_flags = 0;
+	unsigned int len = skb->len - skb->data_len;
+	unsigned long irq_flags;
+	unsigned int nr_frags;
+	unsigned int mss;
+	int count = 0;
+	int tso;
+	unsigned int f;
+
+	if (test_bit(__E1000_DOWN, &adapter->state)) {
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	if (skb->len <= 0) {
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	mss = skb_shinfo(skb)->gso_size;
+	/* The controller does a simple calculation to
+	 * make sure there is enough room in the FIFO before
+	 * initiating the DMA for each buffer.  The calc is:
+	 * 4 = ceil(buffer len/mss).  To make sure we don't
+	 * overrun the FIFO, adjust the max buffer len if mss
+	 * drops. */
+	if (mss) {
+		u8 hdr_len;
+		max_per_txd = min(mss << 2, max_per_txd);
+		max_txd_pwr = fls(max_per_txd) - 1;
+
+		/* TSO Workaround for 82571/2/3 Controllers -- if skb->data
+		* points to just header, pull a few bytes of payload from
+		* frags into skb->data */
+		hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+		if (skb->data_len && (hdr_len == len)) {
+			unsigned int pull_size;
+
+			pull_size = min((unsigned int)4, skb->data_len);
+			if (!__pskb_pull_tail(skb, pull_size)) {
+				ndev_err(netdev,
+					 "__pskb_pull_tail failed.\n");
+				dev_kfree_skb_any(skb);
+				return NETDEV_TX_OK;
+			}
+			len = skb->len - skb->data_len;
+		}
+	}
+
+	/* reserve a descriptor for the offload context */
+	if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL))
+		count++;
+	count++;
+
+	count += TXD_USE_COUNT(len, max_txd_pwr);
+
+	nr_frags = skb_shinfo(skb)->nr_frags;
+	for (f = 0; f < nr_frags; f++)
+		count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size,
+				       max_txd_pwr);
+
+	if (adapter->hw.mac.tx_pkt_filtering)
+		e1000_transfer_dhcp_info(adapter, skb);
+
+	if (!spin_trylock_irqsave(&adapter->tx_queue_lock, irq_flags))
+		/* Collision - tell upper layer to requeue */
+		return NETDEV_TX_LOCKED;
+
+	/* need: count + 2 desc gap to keep tail from touching
+	 * head, otherwise try next time */
+	if (e1000_maybe_stop_tx(netdev, count + 2)) {
+		spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags);
+		return NETDEV_TX_BUSY;
+	}
+
+	if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+		tx_flags |= E1000_TX_FLAGS_VLAN;
+		tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
+	}
+
+	first = tx_ring->next_to_use;
+
+	tso = e1000_tso(adapter, skb);
+	if (tso < 0) {
+		dev_kfree_skb_any(skb);
+		spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags);
+		return NETDEV_TX_OK;
+	}
+
+	if (tso)
+		tx_flags |= E1000_TX_FLAGS_TSO;
+	else if (e1000_tx_csum(adapter, skb))
+		tx_flags |= E1000_TX_FLAGS_CSUM;
+
+	/* Old method was to assume IPv4 packet by default if TSO was enabled.
+	 * 82571 hardware supports TSO capabilities for IPv6 as well...
+	 * no longer assume, we must. */
+	if (skb->protocol == htons(ETH_P_IP))
+		tx_flags |= E1000_TX_FLAGS_IPV4;
+
+	count = e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss);
+	if (count < 0) {
+		/* handle pci_map_single() error in e1000_tx_map */
+		dev_kfree_skb_any(skb);
+		spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags);
+		return NETDEV_TX_OK;
+	}
+
+	e1000_tx_queue(adapter, tx_flags, count);
+
+	netdev->trans_start = jiffies;
+
+	/* Make sure there is space in the ring for the next send. */
+	e1000_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 2);
+
+	spin_unlock_irqrestore(&adapter->tx_queue_lock, irq_flags);
+	return NETDEV_TX_OK;
+}
+
+/**
+ * e1000_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ **/
+static void e1000_tx_timeout(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	/* Do the reset outside of interrupt context */
+	adapter->tx_timeout_count++;
+	schedule_work(&adapter->reset_task);
+}
+
+static void e1000_reset_task(struct work_struct *work)
+{
+	struct e1000_adapter *adapter;
+	adapter = container_of(work, struct e1000_adapter, reset_task);
+
+	e1000e_reinit_locked(adapter);
+}
+
+/**
+ * e1000_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ **/
+static struct net_device_stats *e1000_get_stats(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	/* only return the current stats */
+	return &adapter->net_stats;
+}
+
+/**
+ * e1000_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
+
+	if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) ||
+	    (max_frame > MAX_JUMBO_FRAME_SIZE)) {
+		ndev_err(netdev, "Invalid MTU setting\n");
+		return -EINVAL;
+	}
+
+	/* Jumbo frame size limits */
+	if (max_frame > ETH_FRAME_LEN + ETH_FCS_LEN) {
+		if (!(adapter->flags & FLAG_HAS_JUMBO_FRAMES)) {
+			ndev_err(netdev, "Jumbo Frames not supported.\n");
+			return -EINVAL;
+		}
+		if (adapter->hw.phy.type == e1000_phy_ife) {
+			ndev_err(netdev, "Jumbo Frames not supported.\n");
+			return -EINVAL;
+		}
+	}
+
+#define MAX_STD_JUMBO_FRAME_SIZE 9234
+	if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) {
+		ndev_err(netdev, "MTU > 9216 not supported.\n");
+		return -EINVAL;
+	}
+
+	while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
+		msleep(1);
+	/* e1000e_down has a dependency on max_frame_size */
+	adapter->hw.mac.max_frame_size = max_frame;
+	if (netif_running(netdev))
+		e1000e_down(adapter);
+
+	/* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
+	 * means we reserve 2 more, this pushes us to allocate from the next
+	 * larger slab size.
+	 * i.e. RXBUFFER_2048 --> size-4096 slab
+	 *  however with the new *_jumbo* routines, jumbo receives will use
+	 *  fragmented skbs */
+
+	if (max_frame <= 256)
+		adapter->rx_buffer_len = 256;
+	else if (max_frame <= 512)
+		adapter->rx_buffer_len = 512;
+	else if (max_frame <= 1024)
+		adapter->rx_buffer_len = 1024;
+	else if (max_frame <= 2048)
+		adapter->rx_buffer_len = 2048;
+	else
+		adapter->rx_buffer_len = 4096;
+
+	/* adjust allocation if LPE protects us, and we aren't using SBP */
+	if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN) ||
+	     (max_frame == ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN))
+		adapter->rx_buffer_len = ETH_FRAME_LEN + VLAN_HLEN
+					 + ETH_FCS_LEN ;
+
+	ndev_info(netdev, "changing MTU from %d to %d\n",
+		netdev->mtu, new_mtu);
+	netdev->mtu = new_mtu;
+
+	if (netif_running(netdev))
+		e1000e_up(adapter);
+	else
+		e1000e_reset(adapter);
+
+	clear_bit(__E1000_RESETTING, &adapter->state);
+
+	return 0;
+}
+
+static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
+			   int cmd)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct mii_ioctl_data *data = if_mii(ifr);
+	unsigned long irq_flags;
+
+	if (adapter->hw.media_type != e1000_media_type_copper)
+		return -EOPNOTSUPP;
+
+	switch (cmd) {
+	case SIOCGMIIPHY:
+		data->phy_id = adapter->hw.phy.addr;
+		break;
+	case SIOCGMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		spin_lock_irqsave(&adapter->stats_lock, irq_flags);
+		if (e1e_rphy(&adapter->hw, data->reg_num & 0x1F,
+				   &data->val_out)) {
+			spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
+			return -EIO;
+		}
+		spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
+		break;
+	case SIOCSMIIREG:
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
+
+static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+	switch (cmd) {
+	case SIOCGMIIPHY:
+	case SIOCGMIIREG:
+	case SIOCSMIIREG:
+		return e1000_mii_ioctl(netdev, ifr, cmd);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int e1000_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 ctrl, ctrl_ext, rctl, status;
+	u32 wufc = adapter->wol;
+	int retval = 0;
+
+	netif_device_detach(netdev);
+
+	if (netif_running(netdev)) {
+		WARN_ON(test_bit(__E1000_RESETTING, &adapter->state));
+		e1000e_down(adapter);
+		e1000_free_irq(adapter);
+	}
+
+	retval = pci_save_state(pdev);
+	if (retval)
+		return retval;
+
+	status = er32(STATUS);
+	if (status & E1000_STATUS_LU)
+		wufc &= ~E1000_WUFC_LNKC;
+
+	if (wufc) {
+		e1000_setup_rctl(adapter);
+		e1000_set_multi(netdev);
+
+		/* turn on all-multi mode if wake on multicast is enabled */
+		if (wufc & E1000_WUFC_MC) {
+			rctl = er32(RCTL);
+			rctl |= E1000_RCTL_MPE;
+			ew32(RCTL, rctl);
+		}
+
+		ctrl = er32(CTRL);
+		/* advertise wake from D3Cold */
+		#define E1000_CTRL_ADVD3WUC 0x00100000
+		/* phy power management enable */
+		#define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000
+		ctrl |= E1000_CTRL_ADVD3WUC |
+			E1000_CTRL_EN_PHY_PWR_MGMT;
+		ew32(CTRL, ctrl);
+
+		if (adapter->hw.media_type == e1000_media_type_fiber ||
+		   adapter->hw.media_type == e1000_media_type_internal_serdes) {
+			/* keep the laser running in D3 */
+			ctrl_ext = er32(CTRL_EXT);
+			ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA;
+			ew32(CTRL_EXT, ctrl_ext);
+		}
+
+		/* Allow time for pending master requests to run */
+		e1000e_disable_pcie_master(&adapter->hw);
+
+		ew32(WUC, E1000_WUC_PME_EN);
+		ew32(WUFC, wufc);
+		pci_enable_wake(pdev, PCI_D3hot, 1);
+		pci_enable_wake(pdev, PCI_D3cold, 1);
+	} else {
+		ew32(WUC, 0);
+		ew32(WUFC, 0);
+		pci_enable_wake(pdev, PCI_D3hot, 0);
+		pci_enable_wake(pdev, PCI_D3cold, 0);
+	}
+
+	e1000_release_manageability(adapter);
+
+	/* make sure adapter isn't asleep if manageability is enabled */
+	if (adapter->flags & FLAG_MNG_PT_ENABLED) {
+		pci_enable_wake(pdev, PCI_D3hot, 1);
+		pci_enable_wake(pdev, PCI_D3cold, 1);
+	}
+
+	if (adapter->hw.phy.type == e1000_phy_igp_3)
+		e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw);
+
+	/* Release control of h/w to f/w.  If f/w is AMT enabled, this
+	 * would have already happened in close and is redundant. */
+	e1000_release_hw_control(adapter);
+
+	pci_disable_device(pdev);
+
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int e1000_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+	u32 err;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	err = pci_enable_device(pdev);
+	if (err) {
+		dev_err(&pdev->dev,
+			"Cannot enable PCI device from suspend\n");
+		return err;
+	}
+
+	pci_set_master(pdev);
+
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_enable_wake(pdev, PCI_D3cold, 0);
+
+	if (netif_running(netdev)) {
+		err = e1000_request_irq(adapter);
+		if (err)
+			return err;
+	}
+
+	e1000e_power_up_phy(adapter);
+	e1000e_reset(adapter);
+	ew32(WUS, ~0);
+
+	e1000_init_manageability(adapter);
+
+	if (netif_running(netdev))
+		e1000e_up(adapter);
+
+	netif_device_attach(netdev);
+
+	/* If the controller has AMT, do not set DRV_LOAD until the interface
+	 * is up.  For all other cases, let the f/w know that the h/w is now
+	 * under the control of the driver. */
+	if (!(adapter->flags & FLAG_HAS_AMT) || !e1000e_check_mng_mode(&adapter->hw))
+		e1000_get_hw_control(adapter);
+
+	return 0;
+}
+#endif
+
+static void e1000_shutdown(struct pci_dev *pdev)
+{
+	e1000_suspend(pdev, PMSG_SUSPEND);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void e1000_netpoll(struct net_device *netdev)
+{
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	disable_irq(adapter->pdev->irq);
+	e1000_intr(adapter->pdev->irq, netdev);
+
+	e1000_clean_tx_irq(adapter);
+
+	enable_irq(adapter->pdev->irq);
+}
+#endif
+
+/**
+ * e1000_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
+						pci_channel_state_t state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	netif_device_detach(netdev);
+
+	if (netif_running(netdev))
+		e1000e_down(adapter);
+	pci_disable_device(pdev);
+
+	/* Request a slot slot reset. */
+	return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * e1000_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot. Implementation
+ * resembles the first-half of the e1000_resume routine.
+ */
+static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+	struct e1000_hw *hw = &adapter->hw;
+
+	if (pci_enable_device(pdev)) {
+		dev_err(&pdev->dev,
+			"Cannot re-enable PCI device after reset.\n");
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+	pci_set_master(pdev);
+
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_enable_wake(pdev, PCI_D3cold, 0);
+
+	e1000e_reset(adapter);
+	ew32(WUS, ~0);
+
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * e1000_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation. Implementation resembles the
+ * second-half of the e1000_resume routine.
+ */
+static void e1000_io_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	e1000_init_manageability(adapter);
+
+	if (netif_running(netdev)) {
+		if (e1000e_up(adapter)) {
+			dev_err(&pdev->dev,
+				"can't bring device back up after reset\n");
+			return;
+		}
+	}
+
+	netif_device_attach(netdev);
+
+	/* If the controller has AMT, do not set DRV_LOAD until the interface
+	 * is up.  For all other cases, let the f/w know that the h/w is now
+	 * under the control of the driver. */
+	if (!(adapter->flags & FLAG_HAS_AMT) ||
+	    !e1000e_check_mng_mode(&adapter->hw))
+		e1000_get_hw_control(adapter);
+
+}
+
+static void e1000_print_device_info(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	u32 part_num;
+
+	/* print bus type/speed/width info */
+	ndev_info(netdev, "(PCI Express:2.5GB/s:%s) "
+		  "%02x:%02x:%02x:%02x:%02x:%02x\n",
+		  /* bus width */
+		 ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" :
+		  "Width x1"),
+		  /* MAC address */
+		  netdev->dev_addr[0], netdev->dev_addr[1],
+		  netdev->dev_addr[2], netdev->dev_addr[3],
+		  netdev->dev_addr[4], netdev->dev_addr[5]);
+	ndev_info(netdev, "Intel(R) PRO/%s Network Connection\n",
+		  (hw->phy.type == e1000_phy_ife)
+		   ? "10/100" : "1000");
+	e1000e_read_part_num(hw, &part_num);
+	ndev_info(netdev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
+		  hw->mac.type, hw->phy.type,
+		  (part_num >> 8), (part_num & 0xff));
+}
+
+/**
+ * e1000_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in e1000_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * e1000_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+static int __devinit e1000_probe(struct pci_dev *pdev,
+				 const struct pci_device_id *ent)
+{
+	struct net_device *netdev;
+	struct e1000_adapter *adapter;
+	struct e1000_hw *hw;
+	const struct e1000_info *ei = e1000_info_tbl[ent->driver_data];
+	unsigned long mmio_start, mmio_len;
+	unsigned long flash_start, flash_len;
+
+	static int cards_found;
+	int i, err, pci_using_dac;
+	u16 eeprom_data = 0;
+	u16 eeprom_apme_mask = E1000_EEPROM_APME;
+
+	err = pci_enable_device(pdev);
+	if (err)
+		return err;
+
+	pci_using_dac = 0;
+	err = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+	if (!err) {
+		err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+		if (!err)
+			pci_using_dac = 1;
+	} else {
+		err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+		if (err) {
+			err = pci_set_consistent_dma_mask(pdev,
+							  DMA_32BIT_MASK);
+			if (err) {
+				dev_err(&pdev->dev, "No usable DMA "
+					"configuration, aborting\n");
+				goto err_dma;
+			}
+		}
+	}
+
+	err = pci_request_regions(pdev, e1000e_driver_name);
+	if (err)
+		goto err_pci_reg;
+
+	pci_set_master(pdev);
+
+	err = -ENOMEM;
+	netdev = alloc_etherdev(sizeof(struct e1000_adapter));
+	if (!netdev)
+		goto err_alloc_etherdev;
+
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+
+	pci_set_drvdata(pdev, netdev);
+	adapter = netdev_priv(netdev);
+	hw = &adapter->hw;
+	adapter->netdev = netdev;
+	adapter->pdev = pdev;
+	adapter->ei = ei;
+	adapter->pba = ei->pba;
+	adapter->flags = ei->flags;
+	adapter->hw.adapter = adapter;
+	adapter->hw.mac.type = ei->mac;
+	adapter->msg_enable = (1 << NETIF_MSG_DRV | NETIF_MSG_PROBE) - 1;
+
+	mmio_start = pci_resource_start(pdev, 0);
+	mmio_len = pci_resource_len(pdev, 0);
+
+	err = -EIO;
+	adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
+	if (!adapter->hw.hw_addr)
+		goto err_ioremap;
+
+	if ((adapter->flags & FLAG_HAS_FLASH) &&
+	    (pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
+		flash_start = pci_resource_start(pdev, 1);
+		flash_len = pci_resource_len(pdev, 1);
+		adapter->hw.flash_address = ioremap(flash_start, flash_len);
+		if (!adapter->hw.flash_address)
+			goto err_flashmap;
+	}
+
+	/* construct the net_device struct */
+	netdev->open			= &e1000_open;
+	netdev->stop			= &e1000_close;
+	netdev->hard_start_xmit		= &e1000_xmit_frame;
+	netdev->get_stats		= &e1000_get_stats;
+	netdev->set_multicast_list	= &e1000_set_multi;
+	netdev->set_mac_address		= &e1000_set_mac;
+	netdev->change_mtu		= &e1000_change_mtu;
+	netdev->do_ioctl		= &e1000_ioctl;
+	e1000e_set_ethtool_ops(netdev);
+	netdev->tx_timeout		= &e1000_tx_timeout;
+	netdev->watchdog_timeo		= 5 * HZ;
+	netif_napi_add(netdev, &adapter->napi, e1000_clean, 64);
+	netdev->vlan_rx_register	= e1000_vlan_rx_register;
+	netdev->vlan_rx_add_vid		= e1000_vlan_rx_add_vid;
+	netdev->vlan_rx_kill_vid	= e1000_vlan_rx_kill_vid;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	netdev->poll_controller		= e1000_netpoll;
+#endif
+	strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
+
+	netdev->mem_start = mmio_start;
+	netdev->mem_end = mmio_start + mmio_len;
+
+	adapter->bd_number = cards_found++;
+
+	/* setup adapter struct */
+	err = e1000_sw_init(adapter);
+	if (err)
+		goto err_sw_init;
+
+	err = -EIO;
+
+	memcpy(&hw->mac.ops, ei->mac_ops, sizeof(hw->mac.ops));
+	memcpy(&hw->nvm.ops, ei->nvm_ops, sizeof(hw->nvm.ops));
+	memcpy(&hw->phy.ops, ei->phy_ops, sizeof(hw->phy.ops));
+
+	err = ei->get_invariants(adapter);
+	if (err)
+		goto err_hw_init;
+
+	hw->mac.ops.get_bus_info(&adapter->hw);
+
+	adapter->hw.phy.wait_for_link = 0;
+
+	/* Copper options */
+	if (adapter->hw.media_type == e1000_media_type_copper) {
+		adapter->hw.phy.mdix = AUTO_ALL_MODES;
+		adapter->hw.phy.disable_polarity_correction = 0;
+		adapter->hw.phy.ms_type = e1000_ms_hw_default;
+	}
+
+	if (e1000_check_reset_block(&adapter->hw))
+		ndev_info(netdev,
+			  "PHY reset is blocked due to SOL/IDER session.\n");
+
+	netdev->features = NETIF_F_SG |
+			   NETIF_F_HW_CSUM |
+			   NETIF_F_HW_VLAN_TX |
+			   NETIF_F_HW_VLAN_RX;
+
+	if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER)
+		netdev->features |= NETIF_F_HW_VLAN_FILTER;
+
+	netdev->features |= NETIF_F_TSO;
+	netdev->features |= NETIF_F_TSO6;
+
+	if (pci_using_dac)
+		netdev->features |= NETIF_F_HIGHDMA;
+
+	/* We should not be using LLTX anymore, but we are still TX faster with
+	 * it. */
+	netdev->features |= NETIF_F_LLTX;
+
+	if (e1000e_enable_mng_pass_thru(&adapter->hw))
+		adapter->flags |= FLAG_MNG_PT_ENABLED;
+
+	/* before reading the NVM, reset the controller to
+	 * put the device in a known good starting state */
+	adapter->hw.mac.ops.reset_hw(&adapter->hw);
+
+	/*
+	 * systems with ASPM and others may see the checksum fail on the first
+	 * attempt. Let's give it a few tries
+	 */
+	for (i = 0;; i++) {
+		if (e1000_validate_nvm_checksum(&adapter->hw) >= 0)
+			break;
+		if (i == 2) {
+			ndev_err(netdev, "The NVM Checksum Is Not Valid\n");
+			err = -EIO;
+			goto err_eeprom;
+		}
+	}
+
+	/* copy the MAC address out of the NVM */
+	if (e1000e_read_mac_addr(&adapter->hw))
+		ndev_err(netdev, "NVM Read Error while reading MAC address\n");
+
+	memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len);
+	memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len);
+
+	if (!is_valid_ether_addr(netdev->perm_addr)) {
+		ndev_err(netdev, "Invalid MAC Address: "
+			 "%02x:%02x:%02x:%02x:%02x:%02x\n",
+			 netdev->perm_addr[0], netdev->perm_addr[1],
+			 netdev->perm_addr[2], netdev->perm_addr[3],
+			 netdev->perm_addr[4], netdev->perm_addr[5]);
+		err = -EIO;
+		goto err_eeprom;
+	}
+
+	init_timer(&adapter->watchdog_timer);
+	adapter->watchdog_timer.function = &e1000_watchdog;
+	adapter->watchdog_timer.data = (unsigned long) adapter;
+
+	init_timer(&adapter->phy_info_timer);
+	adapter->phy_info_timer.function = &e1000_update_phy_info;
+	adapter->phy_info_timer.data = (unsigned long) adapter;
+
+	INIT_WORK(&adapter->reset_task, e1000_reset_task);
+	INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task);
+
+	e1000e_check_options(adapter);
+
+	/* Initialize link parameters. User can change them with ethtool */
+	adapter->hw.mac.autoneg = 1;
+	adapter->fc_autoneg = 1;
+	adapter->hw.mac.original_fc = e1000_fc_default;
+	adapter->hw.mac.fc = e1000_fc_default;
+	adapter->hw.phy.autoneg_advertised = 0x2f;
+
+	/* ring size defaults */
+	adapter->rx_ring->count = 256;
+	adapter->tx_ring->count = 256;
+
+	/*
+	 * Initial Wake on LAN setting - If APM wake is enabled in
+	 * the EEPROM, enable the ACPI Magic Packet filter
+	 */
+	if (adapter->flags & FLAG_APME_IN_WUC) {
+		/* APME bit in EEPROM is mapped to WUC.APME */
+		eeprom_data = er32(WUC);
+		eeprom_apme_mask = E1000_WUC_APME;
+	} else if (adapter->flags & FLAG_APME_IN_CTRL3) {
+		if (adapter->flags & FLAG_APME_CHECK_PORT_B &&
+		    (adapter->hw.bus.func == 1))
+			e1000_read_nvm(&adapter->hw,
+				NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data);
+		else
+			e1000_read_nvm(&adapter->hw,
+				NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
+	}
+
+	/* fetch WoL from EEPROM */
+	if (eeprom_data & eeprom_apme_mask)
+		adapter->eeprom_wol |= E1000_WUFC_MAG;
+
+	/*
+	 * now that we have the eeprom settings, apply the special cases
+	 * where the eeprom may be wrong or the board simply won't support
+	 * wake on lan on a particular port
+	 */
+	if (!(adapter->flags & FLAG_HAS_WOL))
+		adapter->eeprom_wol = 0;
+
+	/* initialize the wol settings based on the eeprom settings */
+	adapter->wol = adapter->eeprom_wol;
+
+	/* reset the hardware with the new settings */
+	e1000e_reset(adapter);
+
+	/* If the controller has AMT, do not set DRV_LOAD until the interface
+	 * is up.  For all other cases, let the f/w know that the h/w is now
+	 * under the control of the driver. */
+	if (!(adapter->flags & FLAG_HAS_AMT) ||
+	    !e1000e_check_mng_mode(&adapter->hw))
+		e1000_get_hw_control(adapter);
+
+	/* tell the stack to leave us alone until e1000_open() is called */
+	netif_carrier_off(netdev);
+	netif_stop_queue(netdev);
+
+	strcpy(netdev->name, "eth%d");
+	err = register_netdev(netdev);
+	if (err)
+		goto err_register;
+
+	e1000_print_device_info(adapter);
+
+	return 0;
+
+err_register:
+err_hw_init:
+	e1000_release_hw_control(adapter);
+err_eeprom:
+	if (!e1000_check_reset_block(&adapter->hw))
+		e1000_phy_hw_reset(&adapter->hw);
+
+	if (adapter->hw.flash_address)
+		iounmap(adapter->hw.flash_address);
+
+err_flashmap:
+	kfree(adapter->tx_ring);
+	kfree(adapter->rx_ring);
+err_sw_init:
+	iounmap(adapter->hw.hw_addr);
+err_ioremap:
+	free_netdev(netdev);
+err_alloc_etherdev:
+	pci_release_regions(pdev);
+err_pci_reg:
+err_dma:
+	pci_disable_device(pdev);
+	return err;
+}
+
+/**
+ * e1000_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * e1000_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.  The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void __devexit e1000_remove(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct e1000_adapter *adapter = netdev_priv(netdev);
+
+	/* flush_scheduled work may reschedule our watchdog task, so
+	 * explicitly disable watchdog tasks from being rescheduled  */
+	set_bit(__E1000_DOWN, &adapter->state);
+	del_timer_sync(&adapter->watchdog_timer);
+	del_timer_sync(&adapter->phy_info_timer);
+
+	flush_scheduled_work();
+
+	e1000_release_manageability(adapter);
+
+	/* Release control of h/w to f/w.  If f/w is AMT enabled, this
+	 * would have already happened in close and is redundant. */
+	e1000_release_hw_control(adapter);
+
+	unregister_netdev(netdev);
+
+	if (!e1000_check_reset_block(&adapter->hw))
+		e1000_phy_hw_reset(&adapter->hw);
+
+	kfree(adapter->tx_ring);
+	kfree(adapter->rx_ring);
+
+	iounmap(adapter->hw.hw_addr);
+	if (adapter->hw.flash_address)
+		iounmap(adapter->hw.flash_address);
+	pci_release_regions(pdev);
+
+	free_netdev(netdev);
+
+	pci_disable_device(pdev);
+}
+
+/* PCI Error Recovery (ERS) */
+static struct pci_error_handlers e1000_err_handler = {
+	.error_detected = e1000_io_error_detected,
+	.slot_reset = e1000_io_slot_reset,
+	.resume = e1000_io_resume,
+};
+
+static struct pci_device_id e1000_pci_tbl[] = {
+	/*
+	 * Support for 82571/2/3, es2lan and ich8 will be phased in
+	 * stepwise.
+
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_COPPER), board_82571 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_FIBER), board_82571 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER), board_82571 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_COPPER_LP), board_82571 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_QUAD_FIBER), board_82571 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82571EB_SERDES), board_82571 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI), board_82572 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_COPPER), board_82572 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_FIBER), board_82572 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82572EI_SERDES), board_82572 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E), board_82573 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E_IAMT), board_82573 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L), board_82573 },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_DPT),
+	  board_80003es2lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_SPT),
+	  board_80003es2lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_DPT),
+	  board_80003es2lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_SERDES_SPT),
+	  board_80003es2lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE), board_ich8lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_G), board_ich8lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IFE_GT), board_ich8lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_AMT), board_ich8lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_C), board_ich8lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M), board_ich8lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH8_IGP_M_AMT), board_ich8lan },
+	*/
+
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE), board_ich9lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_G), board_ich9lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_GT), board_ich9lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_AMT), board_ich9lan },
+	{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_C), board_ich9lan },
+
+	{ }	/* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
+
+/* PCI Device API Driver */
+static struct pci_driver e1000_driver = {
+	.name     = e1000e_driver_name,
+	.id_table = e1000_pci_tbl,
+	.probe    = e1000_probe,
+	.remove   = __devexit_p(e1000_remove),
+#ifdef CONFIG_PM
+	/* Power Managment Hooks */
+	.suspend  = e1000_suspend,
+	.resume   = e1000_resume,
+#endif
+	.shutdown = e1000_shutdown,
+	.err_handler = &e1000_err_handler
+};
+
+/**
+ * e1000_init_module - Driver Registration Routine
+ *
+ * e1000_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ **/
+static int __init e1000_init_module(void)
+{
+	int ret;
+	printk(KERN_INFO "%s: Intel(R) PRO/1000 Network Driver - %s\n",
+	       e1000e_driver_name, e1000e_driver_version);
+	printk(KERN_INFO "%s: Copyright (c) 1999-2007 Intel Corporation.\n",
+	       e1000e_driver_name);
+	ret = pci_register_driver(&e1000_driver);
+
+	return ret;
+}
+module_init(e1000_init_module);
+
+/**
+ * e1000_exit_module - Driver Exit Cleanup Routine
+ *
+ * e1000_exit_module is called just before the driver is removed
+ * from memory.
+ **/
+static void __exit e1000_exit_module(void)
+{
+	pci_unregister_driver(&e1000_driver);
+}
+module_exit(e1000_exit_module);
+
+
+MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
+MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+/* e1000_main.c */
diff --git a/drivers/net/e1000e/param.c b/drivers/net/e1000e/param.c
new file mode 100644
index 0000000..e4e655e
--- /dev/null
+++ b/drivers/net/e1000e/param.c
@@ -0,0 +1,382 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/netdevice.h>
+
+#include "e1000.h"
+
+/* This is the only thing that needs to be changed to adjust the
+ * maximum number of ports that the driver can manage.
+ */
+
+#define E1000_MAX_NIC 32
+
+#define OPTION_UNSET   -1
+#define OPTION_DISABLED 0
+#define OPTION_ENABLED  1
+
+#define COPYBREAK_DEFAULT 256
+unsigned int copybreak = COPYBREAK_DEFAULT;
+module_param(copybreak, uint, 0644);
+MODULE_PARM_DESC(copybreak,
+	"Maximum size of packet that is copied to a new buffer on receive");
+
+/* All parameters are treated the same, as an integer array of values.
+ * This macro just reduces the need to repeat the same declaration code
+ * over and over (plus this helps to avoid typo bugs).
+ */
+
+#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
+#define E1000_PARAM(X, desc) \
+	static int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \
+	static int num_##X; \
+	module_param_array_named(X, X, int, &num_##X, 0); \
+	MODULE_PARM_DESC(X, desc);
+
+
+/* Transmit Interrupt Delay in units of 1.024 microseconds
+ *  Tx interrupt delay needs to typically be set to something non zero
+ *
+ * Valid Range: 0-65535
+ */
+E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay");
+#define DEFAULT_TIDV 8
+#define MAX_TXDELAY 0xFFFF
+#define MIN_TXDELAY 0
+
+/* Transmit Absolute Interrupt Delay in units of 1.024 microseconds
+ *
+ * Valid Range: 0-65535
+ */
+E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay");
+#define DEFAULT_TADV 32
+#define MAX_TXABSDELAY 0xFFFF
+#define MIN_TXABSDELAY 0
+
+/* Receive Interrupt Delay in units of 1.024 microseconds
+ *   hardware will likely hang if you set this to anything but zero.
+ *
+ * Valid Range: 0-65535
+ */
+E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
+#define DEFAULT_RDTR 0
+#define MAX_RXDELAY 0xFFFF
+#define MIN_RXDELAY 0
+
+/* Receive Absolute Interrupt Delay in units of 1.024 microseconds
+ *
+ * Valid Range: 0-65535
+ */
+E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay");
+#define DEFAULT_RADV 8
+#define MAX_RXABSDELAY 0xFFFF
+#define MIN_RXABSDELAY 0
+
+/* Interrupt Throttle Rate (interrupts/sec)
+ *
+ * Valid Range: 100-100000 (0=off, 1=dynamic, 3=dynamic conservative)
+ */
+E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
+#define DEFAULT_ITR 3
+#define MAX_ITR 100000
+#define MIN_ITR 100
+
+/* Enable Smart Power Down of the PHY
+ *
+ * Valid Range: 0, 1
+ *
+ * Default Value: 0 (disabled)
+ */
+E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down");
+
+/* Enable Kumeran Lock Loss workaround
+ *
+ * Valid Range: 0, 1
+ *
+ * Default Value: 1 (enabled)
+ */
+E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
+
+struct e1000_option {
+	enum { enable_option, range_option, list_option } type;
+	char *name;
+	char *err;
+	int  def;
+	union {
+		struct { /* range_option info */
+			int min;
+			int max;
+		} r;
+		struct { /* list_option info */
+			int nr;
+			struct e1000_opt_list { int i; char *str; } *p;
+		} l;
+	} arg;
+};
+
+static int __devinit e1000_validate_option(int *value,
+					   struct e1000_option *opt,
+					   struct e1000_adapter *adapter)
+{
+	if (*value == OPTION_UNSET) {
+		*value = opt->def;
+		return 0;
+	}
+
+	switch (opt->type) {
+	case enable_option:
+		switch (*value) {
+		case OPTION_ENABLED:
+			ndev_info(adapter->netdev, "%s Enabled\n", opt->name);
+			return 0;
+		case OPTION_DISABLED:
+			ndev_info(adapter->netdev, "%s Disabled\n", opt->name);
+			return 0;
+		}
+		break;
+	case range_option:
+		if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
+			ndev_info(adapter->netdev,
+					"%s set to %i\n", opt->name, *value);
+			return 0;
+		}
+		break;
+	case list_option: {
+		int i;
+		struct e1000_opt_list *ent;
+
+		for (i = 0; i < opt->arg.l.nr; i++) {
+			ent = &opt->arg.l.p[i];
+			if (*value == ent->i) {
+				if (ent->str[0] != '\0')
+					ndev_info(adapter->netdev, "%s\n",
+						  ent->str);
+				return 0;
+			}
+		}
+	}
+		break;
+	default:
+		BUG();
+	}
+
+	ndev_info(adapter->netdev, "Invalid %s value specified (%i) %s\n",
+	       opt->name, *value, opt->err);
+	*value = opt->def;
+	return -1;
+}
+
+/**
+ * e1000e_check_options - Range Checking for Command Line Parameters
+ * @adapter: board private structure
+ *
+ * This routine checks all command line parameters for valid user
+ * input.  If an invalid value is given, or if no user specified
+ * value exists, a default value is used.  The final value is stored
+ * in a variable in the adapter structure.
+ **/
+void __devinit e1000e_check_options(struct e1000_adapter *adapter)
+{
+	struct e1000_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	int bd = adapter->bd_number;
+
+	if (bd >= E1000_MAX_NIC) {
+		ndev_notice(netdev,
+		       "Warning: no configuration for board #%i\n", bd);
+		ndev_notice(netdev, "Using defaults for all values\n");
+	}
+
+	{ /* Transmit Interrupt Delay */
+		struct e1000_option opt = {
+			.type = range_option,
+			.name = "Transmit Interrupt Delay",
+			.err  = "using default of "
+				__MODULE_STRING(DEFAULT_TIDV),
+			.def  = DEFAULT_TIDV,
+			.arg  = { .r = { .min = MIN_TXDELAY,
+					 .max = MAX_TXDELAY } }
+		};
+
+		if (num_TxIntDelay > bd) {
+			adapter->tx_int_delay = TxIntDelay[bd];
+			e1000_validate_option(&adapter->tx_int_delay, &opt,
+					      adapter);
+		} else {
+			adapter->tx_int_delay = opt.def;
+		}
+	}
+	{ /* Transmit Absolute Interrupt Delay */
+		struct e1000_option opt = {
+			.type = range_option,
+			.name = "Transmit Absolute Interrupt Delay",
+			.err  = "using default of "
+				__MODULE_STRING(DEFAULT_TADV),
+			.def  = DEFAULT_TADV,
+			.arg  = { .r = { .min = MIN_TXABSDELAY,
+					 .max = MAX_TXABSDELAY } }
+		};
+
+		if (num_TxAbsIntDelay > bd) {
+			adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
+			e1000_validate_option(&adapter->tx_abs_int_delay, &opt,
+					      adapter);
+		} else {
+			adapter->tx_abs_int_delay = opt.def;
+		}
+	}
+	{ /* Receive Interrupt Delay */
+		struct e1000_option opt = {
+			.type = range_option,
+			.name = "Receive Interrupt Delay",
+			.err  = "using default of "
+				__MODULE_STRING(DEFAULT_RDTR),
+			.def  = DEFAULT_RDTR,
+			.arg  = { .r = { .min = MIN_RXDELAY,
+					 .max = MAX_RXDELAY } }
+		};
+
+		/* modify min and default if 82573 for slow ping w/a,
+		 * a value greater than 8 needs to be set for RDTR */
+		if (adapter->flags & FLAG_HAS_ASPM) {
+			opt.def = 32;
+			opt.arg.r.min = 8;
+		}
+
+		if (num_RxIntDelay > bd) {
+			adapter->rx_int_delay = RxIntDelay[bd];
+			e1000_validate_option(&adapter->rx_int_delay, &opt,
+					      adapter);
+		} else {
+			adapter->rx_int_delay = opt.def;
+		}
+	}
+	{ /* Receive Absolute Interrupt Delay */
+		struct e1000_option opt = {
+			.type = range_option,
+			.name = "Receive Absolute Interrupt Delay",
+			.err  = "using default of "
+				__MODULE_STRING(DEFAULT_RADV),
+			.def  = DEFAULT_RADV,
+			.arg  = { .r = { .min = MIN_RXABSDELAY,
+					 .max = MAX_RXABSDELAY } }
+		};
+
+		if (num_RxAbsIntDelay > bd) {
+			adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
+			e1000_validate_option(&adapter->rx_abs_int_delay, &opt,
+					      adapter);
+		} else {
+			adapter->rx_abs_int_delay = opt.def;
+		}
+	}
+	{ /* Interrupt Throttling Rate */
+		struct e1000_option opt = {
+			.type = range_option,
+			.name = "Interrupt Throttling Rate (ints/sec)",
+			.err  = "using default of "
+				__MODULE_STRING(DEFAULT_ITR),
+			.def  = DEFAULT_ITR,
+			.arg  = { .r = { .min = MIN_ITR,
+					 .max = MAX_ITR } }
+		};
+
+		if (num_InterruptThrottleRate > bd) {
+			adapter->itr = InterruptThrottleRate[bd];
+			switch (adapter->itr) {
+			case 0:
+				ndev_info(netdev, "%s turned off\n",
+					opt.name);
+				break;
+			case 1:
+				ndev_info(netdev,
+					  "%s set to dynamic mode\n",
+					  opt.name);
+				adapter->itr_setting = adapter->itr;
+				adapter->itr = 20000;
+				break;
+			case 3:
+				ndev_info(netdev,
+					"%s set to dynamic conservative mode\n",
+					opt.name);
+				adapter->itr_setting = adapter->itr;
+				adapter->itr = 20000;
+				break;
+			default:
+				e1000_validate_option(&adapter->itr, &opt,
+					adapter);
+				/*
+				 * save the setting, because the dynamic bits
+				 * change itr. clear the lower two bits
+				 * because they are used as control
+				 */
+				adapter->itr_setting = adapter->itr & ~3;
+				break;
+			}
+		} else {
+			adapter->itr_setting = opt.def;
+			adapter->itr = 20000;
+		}
+	}
+	{ /* Smart Power Down */
+		struct e1000_option opt = {
+			.type = enable_option,
+			.name = "PHY Smart Power Down",
+			.err  = "defaulting to Disabled",
+			.def  = OPTION_DISABLED
+		};
+
+		if (num_SmartPowerDownEnable > bd) {
+			int spd = SmartPowerDownEnable[bd];
+			e1000_validate_option(&spd, &opt, adapter);
+			if ((adapter->flags & FLAG_HAS_SMART_POWER_DOWN)
+			    && spd)
+				adapter->flags |= FLAG_SMART_POWER_DOWN;
+		}
+	}
+	{ /* Kumeran Lock Loss Workaround */
+		struct e1000_option opt = {
+			.type = enable_option,
+			.name = "Kumeran Lock Loss Workaround",
+			.err  = "defaulting to Enabled",
+			.def  = OPTION_ENABLED
+		};
+
+		if (num_KumeranLockLoss > bd) {
+			int kmrn_lock_loss = KumeranLockLoss[bd];
+			e1000_validate_option(&kmrn_lock_loss, &opt, adapter);
+			if (hw->mac.type == e1000_ich8lan)
+				e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw,
+								kmrn_lock_loss);
+		} else {
+			if (hw->mac.type == e1000_ich8lan)
+				e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw,
+								       opt.def);
+		}
+	}
+}
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
new file mode 100644
index 0000000..7932318
--- /dev/null
+++ b/drivers/net/e1000e/phy.c
@@ -0,0 +1,1773 @@
+/*******************************************************************************
+
+  Intel PRO/1000 Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/delay.h>
+
+#include "e1000.h"
+
+static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw);
+static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw);
+static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active);
+static s32 e1000_wait_autoneg(struct e1000_hw *hw);
+
+/* Cable length tables */
+static const u16 e1000_m88_cable_length_table[] =
+	{ 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };
+
+static const u16 e1000_igp_2_cable_length_table[] =
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, 0, 0, 0, 3,
+	  6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41, 6, 10, 14, 18, 22,
+	  26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61, 21, 26, 31, 35, 40,
+	  44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82, 40, 45, 51, 56, 61,
+	  66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, 60, 66, 72, 77, 82,
+	  87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, 83, 89, 95,
+	  100, 105, 109, 113, 116, 119, 122, 124, 104, 109, 114, 118, 121,
+	  124};
+#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \
+		(sizeof(e1000_igp_2_cable_length_table) / \
+		 sizeof(e1000_igp_2_cable_length_table[0]))
+
+/**
+ *  e1000e_check_reset_block_generic - Check if PHY reset is blocked
+ *  @hw: pointer to the HW structure
+ *
+ *  Read the PHY management control register and check whether a PHY reset
+ *  is blocked.  If a reset is not blocked return 0, otherwise
+ *  return E1000_BLK_PHY_RESET (12).
+ **/
+s32 e1000e_check_reset_block_generic(struct e1000_hw *hw)
+{
+	u32 manc;
+
+	manc = er32(MANC);
+
+	return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
+	       E1000_BLK_PHY_RESET : 0;
+}
+
+/**
+ *  e1000e_get_phy_id - Retrieve the PHY ID and revision
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the PHY registers and stores the PHY ID and possibly the PHY
+ *  revision in the hardware structure.
+ **/
+s32 e1000e_get_phy_id(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_id;
+
+	ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
+	if (ret_val)
+		return ret_val;
+
+	phy->id = (u32)(phy_id << 16);
+	udelay(20);
+	ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
+	if (ret_val)
+		return ret_val;
+
+	phy->id |= (u32)(phy_id & PHY_REVISION_MASK);
+	phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
+
+	return 0;
+}
+
+/**
+ *  e1000e_phy_reset_dsp - Reset PHY DSP
+ *  @hw: pointer to the HW structure
+ *
+ *  Reset the digital signal processor.
+ **/
+s32 e1000e_phy_reset_dsp(struct e1000_hw *hw)
+{
+	s32 ret_val;
+
+	ret_val = e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0xC1);
+	if (ret_val)
+		return ret_val;
+
+	return e1e_wphy(hw, M88E1000_PHY_GEN_CONTROL, 0);
+}
+
+/**
+ *  e1000_read_phy_reg_mdic - Read MDI control register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Reads the MDI control regsiter in the PHY at offset and stores the
+ *  information read to data.
+ **/
+static s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, mdic = 0;
+
+	if (offset > MAX_PHY_REG_ADDRESS) {
+		hw_dbg(hw, "PHY Address %d is out of range\n", offset);
+		return -E1000_ERR_PARAM;
+	}
+
+	/* Set up Op-code, Phy Address, and register offset in the MDI
+	 * Control register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	mdic = ((offset << E1000_MDIC_REG_SHIFT) |
+		(phy->addr << E1000_MDIC_PHY_SHIFT) |
+		(E1000_MDIC_OP_READ));
+
+	ew32(MDIC, mdic);
+
+	/* Poll the ready bit to see if the MDI read completed */
+	for (i = 0; i < 64; i++) {
+		udelay(50);
+		mdic = er32(MDIC);
+		if (mdic & E1000_MDIC_READY)
+			break;
+	}
+	if (!(mdic & E1000_MDIC_READY)) {
+		hw_dbg(hw, "MDI Read did not complete\n");
+		return -E1000_ERR_PHY;
+	}
+	if (mdic & E1000_MDIC_ERROR) {
+		hw_dbg(hw, "MDI Error\n");
+		return -E1000_ERR_PHY;
+	}
+	*data = (u16) mdic;
+
+	return 0;
+}
+
+/**
+ *  e1000_write_phy_reg_mdic - Write MDI control register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write to register at offset
+ *
+ *  Writes data to MDI control register in the PHY at offset.
+ **/
+static s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	u32 i, mdic = 0;
+
+	if (offset > MAX_PHY_REG_ADDRESS) {
+		hw_dbg(hw, "PHY Address %d is out of range\n", offset);
+		return -E1000_ERR_PARAM;
+	}
+
+	/* Set up Op-code, Phy Address, and register offset in the MDI
+	 * Control register.  The MAC will take care of interfacing with the
+	 * PHY to retrieve the desired data.
+	 */
+	mdic = (((u32)data) |
+		(offset << E1000_MDIC_REG_SHIFT) |
+		(phy->addr << E1000_MDIC_PHY_SHIFT) |
+		(E1000_MDIC_OP_WRITE));
+
+	ew32(MDIC, mdic);
+
+	/* Poll the ready bit to see if the MDI read completed */
+	for (i = 0; i < E1000_GEN_POLL_TIMEOUT; i++) {
+		udelay(5);
+		mdic = er32(MDIC);
+		if (mdic & E1000_MDIC_READY)
+			break;
+	}
+	if (!(mdic & E1000_MDIC_READY)) {
+		hw_dbg(hw, "MDI Write did not complete\n");
+		return -E1000_ERR_PHY;
+	}
+
+	return 0;
+}
+
+/**
+ *  e1000e_read_phy_reg_m88 - Read m88 PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphores before exiting.
+ **/
+s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	s32 ret_val;
+
+	ret_val = hw->phy.ops.acquire_phy(hw);
+	if (ret_val)
+		return ret_val;
+
+	ret_val = e1000_read_phy_reg_mdic(hw,
+					  MAX_PHY_REG_ADDRESS & offset,
+					  data);
+
+	hw->phy.ops.release_phy(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_phy_reg_m88 - Write m88 PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	s32 ret_val;
+
+	ret_val = hw->phy.ops.acquire_phy(hw);
+	if (ret_val)
+		return ret_val;
+
+	ret_val = e1000_write_phy_reg_mdic(hw,
+					   MAX_PHY_REG_ADDRESS & offset,
+					   data);
+
+	hw->phy.ops.release_phy(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_phy_reg_igp - Read igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary, then reads the PHY register at offset
+ *  and storing the retrieved information in data.  Release any acquired
+ *  semaphores before exiting.
+ **/
+s32 e1000e_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	s32 ret_val;
+
+	ret_val = hw->phy.ops.acquire_phy(hw);
+	if (ret_val)
+		return ret_val;
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		ret_val = e1000_write_phy_reg_mdic(hw,
+						   IGP01E1000_PHY_PAGE_SELECT,
+						   (u16)offset);
+		if (ret_val) {
+			hw->phy.ops.release_phy(hw);
+			return ret_val;
+		}
+	}
+
+	ret_val = e1000_read_phy_reg_mdic(hw,
+					  MAX_PHY_REG_ADDRESS & offset,
+					  data);
+
+	hw->phy.ops.release_phy(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_phy_reg_igp - Write igp PHY register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary, then writes the data to PHY register
+ *  at the offset.  Release any acquired semaphores before exiting.
+ **/
+s32 e1000e_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	s32 ret_val;
+
+	ret_val = hw->phy.ops.acquire_phy(hw);
+	if (ret_val)
+		return ret_val;
+
+	if (offset > MAX_PHY_MULTI_PAGE_REG) {
+		ret_val = e1000_write_phy_reg_mdic(hw,
+						   IGP01E1000_PHY_PAGE_SELECT,
+						   (u16)offset);
+		if (ret_val) {
+			hw->phy.ops.release_phy(hw);
+			return ret_val;
+		}
+	}
+
+	ret_val = e1000_write_phy_reg_mdic(hw,
+					   MAX_PHY_REG_ADDRESS & offset,
+					   data);
+
+	hw->phy.ops.release_phy(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_read_kmrn_reg - Read kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to be read
+ *  @data: pointer to the read data
+ *
+ *  Acquires semaphore, if necessary.  Then reads the PHY register at offset
+ *  using the kumeran interface.  The information retrieved is stored in data.
+ *  Release any acquired semaphores before exiting.
+ **/
+s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data)
+{
+	u32 kmrnctrlsta;
+	s32 ret_val;
+
+	ret_val = hw->phy.ops.acquire_phy(hw);
+	if (ret_val)
+		return ret_val;
+
+	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+		       E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN;
+	ew32(KMRNCTRLSTA, kmrnctrlsta);
+
+	udelay(2);
+
+	kmrnctrlsta = er32(KMRNCTRLSTA);
+	*data = (u16)kmrnctrlsta;
+
+	hw->phy.ops.release_phy(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_write_kmrn_reg - Write kumeran register
+ *  @hw: pointer to the HW structure
+ *  @offset: register offset to write to
+ *  @data: data to write at register offset
+ *
+ *  Acquires semaphore, if necessary.  Then write the data to PHY register
+ *  at the offset using the kumeran interface.  Release any acquired semaphores
+ *  before exiting.
+ **/
+s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data)
+{
+	u32 kmrnctrlsta;
+	s32 ret_val;
+
+	ret_val = hw->phy.ops.acquire_phy(hw);
+	if (ret_val)
+		return ret_val;
+
+	kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) &
+		       E1000_KMRNCTRLSTA_OFFSET) | data;
+	ew32(KMRNCTRLSTA, kmrnctrlsta);
+
+	udelay(2);
+	hw->phy.ops.release_phy(hw);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_copper_link_setup_m88 - Setup m88 PHY's for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets up MDI/MDI-X and polarity for m88 PHY's.  If necessary, transmit clock
+ *  and downshift values are set also.
+ **/
+s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+
+	/* Enable CRS on TX. This must be set for half-duplex operation. */
+	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+	/* Options:
+	 *   MDI/MDI-X = 0 (default)
+	 *   0 - Auto for all speeds
+	 *   1 - MDI mode
+	 *   2 - MDI-X mode
+	 *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+	 */
+	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+	switch (phy->mdix) {
+	case 1:
+		phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+		break;
+	case 2:
+		phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+		break;
+	case 3:
+		phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+		break;
+	case 0:
+	default:
+		phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+		break;
+	}
+
+	/* Options:
+	 *   disable_polarity_correction = 0 (default)
+	 *       Automatic Correction for Reversed Cable Polarity
+	 *   0 - Disabled
+	 *   1 - Enabled
+	 */
+	phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+	if (phy->disable_polarity_correction == 1)
+		phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+
+	ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		return ret_val;
+
+	if (phy->revision < 4) {
+		/* Force TX_CLK in the Extended PHY Specific Control Register
+		 * to 25MHz clock.
+		 */
+		ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+		if (ret_val)
+			return ret_val;
+
+		phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+		if ((phy->revision == 2) &&
+		    (phy->id == M88E1111_I_PHY_ID)) {
+			/* 82573L PHY - set the downshift counter to 5x. */
+			phy_data &= ~M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK;
+			phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
+		} else {
+			/* Configure Master and Slave downshift values */
+			phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+				      M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+			phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+				     M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+		}
+		ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+		if (ret_val)
+			return ret_val;
+	}
+
+	/* Commit the changes. */
+	ret_val = e1000e_commit_phy(hw);
+	if (ret_val)
+		hw_dbg(hw, "Error committing the PHY changes\n");
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_copper_link_setup_igp - Setup igp PHY's for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Sets up LPLU, MDI/MDI-X, polarity, Smartspeed and Master/Slave config for
+ *  igp PHY's.
+ **/
+s32 e1000e_copper_link_setup_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	ret_val = e1000_phy_hw_reset(hw);
+	if (ret_val) {
+		hw_dbg(hw, "Error resetting the PHY.\n");
+		return ret_val;
+	}
+
+	/* Wait 15ms for MAC to configure PHY from NVM settings. */
+	msleep(15);
+
+	/* disable lplu d0 during driver init */
+	ret_val = e1000_set_d0_lplu_state(hw, 0);
+	if (ret_val) {
+		hw_dbg(hw, "Error Disabling LPLU D0\n");
+		return ret_val;
+	}
+	/* Configure mdi-mdix settings */
+	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &data);
+	if (ret_val)
+		return ret_val;
+
+	data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+
+	switch (phy->mdix) {
+	case 1:
+		data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+		break;
+	case 2:
+		data |= IGP01E1000_PSCR_FORCE_MDI_MDIX;
+		break;
+	case 0:
+	default:
+		data |= IGP01E1000_PSCR_AUTO_MDIX;
+		break;
+	}
+	ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, data);
+	if (ret_val)
+		return ret_val;
+
+	/* set auto-master slave resolution settings */
+	if (hw->mac.autoneg) {
+		/* when autonegotiation advertisement is only 1000Mbps then we
+		 * should disable SmartSpeed and enable Auto MasterSlave
+		 * resolution as hardware default. */
+		if (phy->autoneg_advertised == ADVERTISE_1000_FULL) {
+			/* Disable SmartSpeed */
+			ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+						     &data);
+			if (ret_val)
+				return ret_val;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+						     data);
+			if (ret_val)
+				return ret_val;
+
+			/* Set auto Master/Slave resolution process */
+			ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data);
+			if (ret_val)
+				return ret_val;
+
+			data &= ~CR_1000T_MS_ENABLE;
+			ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data);
+			if (ret_val)
+				return ret_val;
+		}
+
+		ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &data);
+		if (ret_val)
+			return ret_val;
+
+		/* load defaults for future use */
+		phy->original_ms_type = (data & CR_1000T_MS_ENABLE) ?
+			((data & CR_1000T_MS_VALUE) ?
+			e1000_ms_force_master :
+			e1000_ms_force_slave) :
+			e1000_ms_auto;
+
+		switch (phy->ms_type) {
+		case e1000_ms_force_master:
+			data |= (CR_1000T_MS_ENABLE | CR_1000T_MS_VALUE);
+			break;
+		case e1000_ms_force_slave:
+			data |= CR_1000T_MS_ENABLE;
+			data &= ~(CR_1000T_MS_VALUE);
+			break;
+		case e1000_ms_auto:
+			data &= ~CR_1000T_MS_ENABLE;
+		default:
+			break;
+		}
+		ret_val = e1e_wphy(hw, PHY_1000T_CTRL, data);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_phy_setup_autoneg - Configure PHY for auto-negotiation
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the MII auto-neg advertisement register and/or the 1000T control
+ *  register and if the PHY is already setup for auto-negotiation, then
+ *  return successful.  Otherwise, setup advertisement and flow control to
+ *  the appropriate values for the wanted auto-negotiation.
+ **/
+static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 mii_autoneg_adv_reg;
+	u16 mii_1000t_ctrl_reg = 0;
+
+	phy->autoneg_advertised &= phy->autoneg_mask;
+
+	/* Read the MII Auto-Neg Advertisement Register (Address 4). */
+	ret_val = e1e_rphy(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
+	if (ret_val)
+		return ret_val;
+
+	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+		/* Read the MII 1000Base-T Control Register (Address 9). */
+		ret_val = e1e_rphy(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
+		if (ret_val)
+			return ret_val;
+	}
+
+	/* Need to parse both autoneg_advertised and fc and set up
+	 * the appropriate PHY registers.  First we will parse for
+	 * autoneg_advertised software override.  Since we can advertise
+	 * a plethora of combinations, we need to check each bit
+	 * individually.
+	 */
+
+	/* First we clear all the 10/100 mb speed bits in the Auto-Neg
+	 * Advertisement Register (Address 4) and the 1000 mb speed bits in
+	 * the  1000Base-T Control Register (Address 9).
+	 */
+	mii_autoneg_adv_reg &= ~(NWAY_AR_100TX_FD_CAPS |
+				 NWAY_AR_100TX_HD_CAPS |
+				 NWAY_AR_10T_FD_CAPS   |
+				 NWAY_AR_10T_HD_CAPS);
+	mii_1000t_ctrl_reg &= ~(CR_1000T_HD_CAPS | CR_1000T_FD_CAPS);
+
+	hw_dbg(hw, "autoneg_advertised %x\n", phy->autoneg_advertised);
+
+	/* Do we want to advertise 10 Mb Half Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_10_HALF) {
+		hw_dbg(hw, "Advertise 10mb Half duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+	}
+
+	/* Do we want to advertise 10 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_10_FULL) {
+		hw_dbg(hw, "Advertise 10mb Full duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+	}
+
+	/* Do we want to advertise 100 Mb Half Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_100_HALF) {
+		hw_dbg(hw, "Advertise 100mb Half duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+	}
+
+	/* Do we want to advertise 100 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_100_FULL) {
+		hw_dbg(hw, "Advertise 100mb Full duplex\n");
+		mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+	}
+
+	/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+	if (phy->autoneg_advertised & ADVERTISE_1000_HALF)
+		hw_dbg(hw, "Advertise 1000mb Half duplex request denied!\n");
+
+	/* Do we want to advertise 1000 Mb Full Duplex? */
+	if (phy->autoneg_advertised & ADVERTISE_1000_FULL) {
+		hw_dbg(hw, "Advertise 1000mb Full duplex\n");
+		mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+	}
+
+	/* Check for a software override of the flow control settings, and
+	 * setup the PHY advertisement registers accordingly.  If
+	 * auto-negotiation is enabled, then software will have to set the
+	 * "PAUSE" bits to the correct value in the Auto-Negotiation
+	 * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-
+	 * negotiation.
+	 *
+	 * The possible values of the "fc" parameter are:
+	 *      0:  Flow control is completely disabled
+	 *      1:  Rx flow control is enabled (we can receive pause frames
+	 *	  but not send pause frames).
+	 *      2:  Tx flow control is enabled (we can send pause frames
+	 *	  but we do not support receiving pause frames).
+	 *      3:  Both Rx and TX flow control (symmetric) are enabled.
+	 *  other:  No software override.  The flow control configuration
+	 *	  in the EEPROM is used.
+	 */
+	switch (hw->mac.fc) {
+	case e1000_fc_none:
+		/* Flow control (RX & TX) is completely disabled by a
+		 * software over-ride.
+		 */
+		mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	case e1000_fc_rx_pause:
+		/* RX Flow control is enabled, and TX Flow control is
+		 * disabled, by a software over-ride.
+		 */
+		/* Since there really isn't a way to advertise that we are
+		 * capable of RX Pause ONLY, we will advertise that we
+		 * support both symmetric and asymmetric RX PAUSE.  Later
+		 * (in e1000e_config_fc_after_link_up) we will disable the
+		 * hw's ability to send PAUSE frames.
+		 */
+		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	case e1000_fc_tx_pause:
+		/* TX Flow control is enabled, and RX Flow control is
+		 * disabled, by a software over-ride.
+		 */
+		mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+		mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+		break;
+	case e1000_fc_full:
+		/* Flow control (both RX and TX) is enabled by a software
+		 * over-ride.
+		 */
+		mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+		break;
+	default:
+		hw_dbg(hw, "Flow control param set incorrectly\n");
+		ret_val = -E1000_ERR_CONFIG;
+		return ret_val;
+	}
+
+	ret_val = e1e_wphy(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
+	if (ret_val)
+		return ret_val;
+
+	hw_dbg(hw, "Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+	if (phy->autoneg_mask & ADVERTISE_1000_FULL) {
+		ret_val = e1e_wphy(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000_copper_link_autoneg - Setup/Enable autoneg for copper link
+ *  @hw: pointer to the HW structure
+ *
+ *  Performs initial bounds checking on autoneg advertisement parameter, then
+ *  configure to advertise the full capability.  Setup the PHY to autoneg
+ *  and restart the negotiation process between the link partner.  If
+ *  wait_for_link, then wait for autoneg to complete before exiting.
+ **/
+static s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_ctrl;
+
+	/* Perform some bounds checking on the autoneg advertisement
+	 * parameter.
+	 */
+	phy->autoneg_advertised &= phy->autoneg_mask;
+
+	/* If autoneg_advertised is zero, we assume it was not defaulted
+	 * by the calling code so we set to advertise full capability.
+	 */
+	if (phy->autoneg_advertised == 0)
+		phy->autoneg_advertised = phy->autoneg_mask;
+
+	hw_dbg(hw, "Reconfiguring auto-neg advertisement params\n");
+	ret_val = e1000_phy_setup_autoneg(hw);
+	if (ret_val) {
+		hw_dbg(hw, "Error Setting up Auto-Negotiation\n");
+		return ret_val;
+	}
+	hw_dbg(hw, "Restarting Auto-Neg\n");
+
+	/* Restart auto-negotiation by setting the Auto Neg Enable bit and
+	 * the Auto Neg Restart bit in the PHY control register.
+	 */
+	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);
+	if (ret_val)
+		return ret_val;
+
+	phy_ctrl |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);
+	if (ret_val)
+		return ret_val;
+
+	/* Does the user want to wait for Auto-Neg to complete here, or
+	 * check at a later time (for example, callback routine).
+	 */
+	if (phy->wait_for_link) {
+		ret_val = e1000_wait_autoneg(hw);
+		if (ret_val) {
+			hw_dbg(hw, "Error while waiting for "
+				 "autoneg to complete\n");
+			return ret_val;
+		}
+	}
+
+	hw->mac.get_link_status = 1;
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_setup_copper_link - Configure copper link settings
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the appropriate function to configure the link for auto-neg or forced
+ *  speed and duplex.  Then we check for link, once link is established calls
+ *  to configure collision distance and flow control are called.  If link is
+ *  not established, we return -E1000_ERR_PHY (-2).
+ **/
+s32 e1000e_setup_copper_link(struct e1000_hw *hw)
+{
+	s32 ret_val;
+	bool link;
+
+	if (hw->mac.autoneg) {
+		/* Setup autoneg and flow control advertisement and perform
+		 * autonegotiation. */
+		ret_val = e1000_copper_link_autoneg(hw);
+		if (ret_val)
+			return ret_val;
+	} else {
+		/* PHY will be set to 10H, 10F, 100H or 100F
+		 * depending on user settings. */
+		hw_dbg(hw, "Forcing Speed and Duplex\n");
+		ret_val = e1000_phy_force_speed_duplex(hw);
+		if (ret_val) {
+			hw_dbg(hw, "Error Forcing Speed and Duplex\n");
+			return ret_val;
+		}
+	}
+
+	/* Check link status. Wait up to 100 microseconds for link to become
+	 * valid.
+	 */
+	ret_val = e1000e_phy_has_link_generic(hw,
+					     COPPER_LINK_UP_LIMIT,
+					     10,
+					     &link);
+	if (ret_val)
+		return ret_val;
+
+	if (link) {
+		hw_dbg(hw, "Valid link established!!!\n");
+		e1000e_config_collision_dist(hw);
+		ret_val = e1000e_config_fc_after_link_up(hw);
+	} else {
+		hw_dbg(hw, "Unable to establish link!!!\n");
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_phy_force_speed_duplex_igp - Force speed/duplex for igp PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the PHY setup function to force speed and duplex.  Clears the
+ *  auto-crossover to force MDI manually.  Waits for link and returns
+ *  successful if link up is successful, else -E1000_ERR_PHY (-2).
+ **/
+s32 e1000e_phy_force_speed_duplex_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+	bool link;
+
+	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		return ret_val;
+
+	/* Clear Auto-Crossover to force MDI manually.  IGP requires MDI
+	 * forced whenever speed and duplex are forced.
+	 */
+	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
+	phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
+
+	ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
+	if (ret_val)
+		return ret_val;
+
+	hw_dbg(hw, "IGP PSCR: %X\n", phy_data);
+
+	udelay(1);
+
+	if (phy->wait_for_link) {
+		hw_dbg(hw, "Waiting for forced speed/duplex link on IGP phy.\n");
+
+		ret_val = e1000e_phy_has_link_generic(hw,
+						     PHY_FORCE_LIMIT,
+						     100000,
+						     &link);
+		if (ret_val)
+			return ret_val;
+
+		if (!link)
+			hw_dbg(hw, "Link taking longer than expected.\n");
+
+		/* Try once more */
+		ret_val = e1000e_phy_has_link_generic(hw,
+						     PHY_FORCE_LIMIT,
+						     100000,
+						     &link);
+		if (ret_val)
+			return ret_val;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_phy_force_speed_duplex_m88 - Force speed/duplex for m88 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Calls the PHY setup function to force speed and duplex.  Clears the
+ *  auto-crossover to force MDI manually.  Resets the PHY to commit the
+ *  changes.  If time expires while waiting for link up, we reset the DSP.
+ *  After reset, TX_CLK and CRS on TX must be set.  Return successful upon
+ *  successful completion, else return corresponding error code.
+ **/
+s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data;
+	bool link;
+
+	/* Clear Auto-Crossover to force MDI manually.  M88E1000 requires MDI
+	 * forced whenever speed and duplex are forced.
+	 */
+	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+	ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		return ret_val;
+
+	hw_dbg(hw, "M88E1000 PSCR: %X\n", phy_data);
+
+	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	e1000e_phy_force_speed_duplex_setup(hw, &phy_data);
+
+	/* Reset the phy to commit changes. */
+	phy_data |= MII_CR_RESET;
+
+	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data);
+	if (ret_val)
+		return ret_val;
+
+	udelay(1);
+
+	if (phy->wait_for_link) {
+		hw_dbg(hw, "Waiting for forced speed/duplex link on M88 phy.\n");
+
+		ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+						     100000, &link);
+		if (ret_val)
+			return ret_val;
+
+		if (!link) {
+			/* We didn't get link.
+			 * Reset the DSP and cross our fingers.
+			 */
+			ret_val = e1e_wphy(hw, M88E1000_PHY_PAGE_SELECT, 0x001d);
+			if (ret_val)
+				return ret_val;
+			ret_val = e1000e_phy_reset_dsp(hw);
+			if (ret_val)
+				return ret_val;
+		}
+
+		/* Try once more */
+		ret_val = e1000e_phy_has_link_generic(hw, PHY_FORCE_LIMIT,
+						     100000, &link);
+		if (ret_val)
+			return ret_val;
+	}
+
+	ret_val = e1e_rphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	/* Resetting the phy means we need to re-force TX_CLK in the
+	 * Extended PHY Specific Control Register to 25MHz clock from
+	 * the reset value of 2.5MHz.
+	 */
+	phy_data |= M88E1000_EPSCR_TX_CLK_25;
+	ret_val = e1e_wphy(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+	if (ret_val)
+		return ret_val;
+
+	/* In addition, we must re-enable CRS on Tx for both half and full
+	 * duplex.
+	 */
+	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+	ret_val = e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_phy_force_speed_duplex_setup - Configure forced PHY speed/duplex
+ *  @hw: pointer to the HW structure
+ *  @phy_ctrl: pointer to current value of PHY_CONTROL
+ *
+ *  Forces speed and duplex on the PHY by doing the following: disable flow
+ *  control, force speed/duplex on the MAC, disable auto speed detection,
+ *  disable auto-negotiation, configure duplex, configure speed, configure
+ *  the collision distance, write configuration to CTRL register.  The
+ *  caller must write to the PHY_CONTROL register for these settings to
+ *  take affect.
+ **/
+void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl)
+{
+	struct e1000_mac_info *mac = &hw->mac;
+	u32 ctrl;
+
+	/* Turn off flow control when forcing speed/duplex */
+	mac->fc = e1000_fc_none;
+
+	/* Force speed/duplex on the mac */
+	ctrl = er32(CTRL);
+	ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+	ctrl &= ~E1000_CTRL_SPD_SEL;
+
+	/* Disable Auto Speed Detection */
+	ctrl &= ~E1000_CTRL_ASDE;
+
+	/* Disable autoneg on the phy */
+	*phy_ctrl &= ~MII_CR_AUTO_NEG_EN;
+
+	/* Forcing Full or Half Duplex? */
+	if (mac->forced_speed_duplex & E1000_ALL_HALF_DUPLEX) {
+		ctrl &= ~E1000_CTRL_FD;
+		*phy_ctrl &= ~MII_CR_FULL_DUPLEX;
+		hw_dbg(hw, "Half Duplex\n");
+	} else {
+		ctrl |= E1000_CTRL_FD;
+		*phy_ctrl |= MII_CR_FULL_DUPLEX;
+		hw_dbg(hw, "Full Duplex\n");
+	}
+
+	/* Forcing 10mb or 100mb? */
+	if (mac->forced_speed_duplex & E1000_ALL_100_SPEED) {
+		ctrl |= E1000_CTRL_SPD_100;
+		*phy_ctrl |= MII_CR_SPEED_100;
+		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+		hw_dbg(hw, "Forcing 100mb\n");
+	} else {
+		ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+		*phy_ctrl |= MII_CR_SPEED_10;
+		*phy_ctrl &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+		hw_dbg(hw, "Forcing 10mb\n");
+	}
+
+	e1000e_config_collision_dist(hw);
+
+	ew32(CTRL, ctrl);
+}
+
+/**
+ *  e1000e_set_d3_lplu_state - Sets low power link up state for D3
+ *  @hw: pointer to the HW structure
+ *  @active: boolean used to enable/disable lplu
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  The low power link up (lplu) state is set to the power management level D3
+ *  and SmartSpeed is disabled when active is true, else clear lplu for D3
+ *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
+ *  is used during Dx states where the power conservation is most important.
+ *  During driver activity, SmartSpeed should be enabled so performance is
+ *  maintained.
+ **/
+s32 e1000e_set_d3_lplu_state(struct e1000_hw *hw, bool active)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	ret_val = e1e_rphy(hw, IGP02E1000_PHY_POWER_MGMT, &data);
+	if (ret_val)
+		return ret_val;
+
+	if (!active) {
+		data &= ~IGP02E1000_PM_D3_LPLU;
+		ret_val = e1e_wphy(hw,
+					     IGP02E1000_PHY_POWER_MGMT,
+					     data);
+		if (ret_val)
+			return ret_val;
+		/* LPLU and SmartSpeed are mutually exclusive.  LPLU is used
+		 * during Dx states where the power conservation is most
+		 * important.  During driver activity we should enable
+		 * SmartSpeed, so performance is maintained. */
+		if (phy->smart_speed == e1000_smart_speed_on) {
+			ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+						    &data);
+			if (ret_val)
+				return ret_val;
+
+			data |= IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+						     data);
+			if (ret_val)
+				return ret_val;
+		} else if (phy->smart_speed == e1000_smart_speed_off) {
+			ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+						     &data);
+			if (ret_val)
+				return ret_val;
+
+			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+			ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG,
+						     data);
+			if (ret_val)
+				return ret_val;
+		}
+	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
+		   (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
+		   (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
+		data |= IGP02E1000_PM_D3_LPLU;
+		ret_val = e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, data);
+		if (ret_val)
+			return ret_val;
+
+		/* When LPLU is enabled, we should disable SmartSpeed */
+		ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data);
+		if (ret_val)
+			return ret_val;
+
+		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
+		ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data);
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_check_downshift - Checks whether a downshift in speed occured
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  A downshift is detected by querying the PHY link health.
+ **/
+s32 e1000e_check_downshift(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, offset, mask;
+
+	switch (phy->type) {
+	case e1000_phy_m88:
+	case e1000_phy_gg82563:
+		offset	= M88E1000_PHY_SPEC_STATUS;
+		mask	= M88E1000_PSSR_DOWNSHIFT;
+		break;
+	case e1000_phy_igp_2:
+	case e1000_phy_igp_3:
+		offset	= IGP01E1000_PHY_LINK_HEALTH;
+		mask	= IGP01E1000_PLHR_SS_DOWNGRADE;
+		break;
+	default:
+		/* speed downshift not supported */
+		phy->speed_downgraded = 0;
+		return 0;
+	}
+
+	ret_val = e1e_rphy(hw, offset, &phy_data);
+
+	if (!ret_val)
+		phy->speed_downgraded = (phy_data & mask);
+
+	return ret_val;
+}
+
+/**
+ *  e1000_check_polarity_m88 - Checks the polarity.
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ *  Polarity is determined based on the PHY specific status register.
+ **/
+static s32 e1000_check_polarity_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+
+	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &data);
+
+	if (!ret_val)
+		phy->cable_polarity = (data & M88E1000_PSSR_REV_POLARITY)
+				      ? e1000_rev_polarity_reversed
+				      : e1000_rev_polarity_normal;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_check_polarity_igp - Checks the polarity.
+ *  @hw: pointer to the HW structure
+ *
+ *  Success returns 0, Failure returns -E1000_ERR_PHY (-2)
+ *
+ *  Polarity is determined based on the PHY port status register, and the
+ *  current speed (since there is no polarity at 100Mbps).
+ **/
+static s32 e1000_check_polarity_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data, offset, mask;
+
+	/* Polarity is determined based on the speed of
+	 * our connection. */
+	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+	if (ret_val)
+		return ret_val;
+
+	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+	    IGP01E1000_PSSR_SPEED_1000MBPS) {
+		offset	= IGP01E1000_PHY_PCS_INIT_REG;
+		mask	= IGP01E1000_PHY_POLARITY_MASK;
+	} else {
+		/* This really only applies to 10Mbps since
+		 * there is no polarity for 100Mbps (always 0).
+		 */
+		offset	= IGP01E1000_PHY_PORT_STATUS;
+		mask	= IGP01E1000_PSSR_POLARITY_REVERSED;
+	}
+
+	ret_val = e1e_rphy(hw, offset, &data);
+
+	if (!ret_val)
+		phy->cable_polarity = (data & mask)
+				      ? e1000_rev_polarity_reversed
+				      : e1000_rev_polarity_normal;
+
+	return ret_val;
+}
+
+/**
+ *  e1000_wait_autoneg - Wait for auto-neg compeletion
+ *  @hw: pointer to the HW structure
+ *
+ *  Waits for auto-negotiation to complete or for the auto-negotiation time
+ *  limit to expire, which ever happens first.
+ **/
+static s32 e1000_wait_autoneg(struct e1000_hw *hw)
+{
+	s32 ret_val = 0;
+	u16 i, phy_status;
+
+	/* Break after autoneg completes or PHY_AUTO_NEG_LIMIT expires. */
+	for (i = PHY_AUTO_NEG_LIMIT; i > 0; i--) {
+		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		if (phy_status & MII_SR_AUTONEG_COMPLETE)
+			break;
+		msleep(100);
+	}
+
+	/* PHY_AUTO_NEG_TIME expiration doesn't guarantee auto-negotiation
+	 * has completed.
+	 */
+	return ret_val;
+}
+
+/**
+ *  e1000e_phy_has_link_generic - Polls PHY for link
+ *  @hw: pointer to the HW structure
+ *  @iterations: number of times to poll for link
+ *  @usec_interval: delay between polling attempts
+ *  @success: pointer to whether polling was successful or not
+ *
+ *  Polls the PHY status register for link, 'iterations' number of times.
+ **/
+s32 e1000e_phy_has_link_generic(struct e1000_hw *hw, u32 iterations,
+			       u32 usec_interval, bool *success)
+{
+	s32 ret_val = 0;
+	u16 i, phy_status;
+
+	for (i = 0; i < iterations; i++) {
+		/* Some PHYs require the PHY_STATUS register to be read
+		 * twice due to the link bit being sticky.  No harm doing
+		 * it across the board.
+		 */
+		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		ret_val = e1e_rphy(hw, PHY_STATUS, &phy_status);
+		if (ret_val)
+			break;
+		if (phy_status & MII_SR_LINK_STATUS)
+			break;
+		if (usec_interval >= 1000)
+			mdelay(usec_interval/1000);
+		else
+			udelay(usec_interval);
+	}
+
+	*success = (i < iterations);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_get_cable_length_m88 - Determine cable length for m88 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  Reads the PHY specific status register to retrieve the cable length
+ *  information.  The cable length is determined by averaging the minimum and
+ *  maximum values to get the "average" cable length.  The m88 PHY has four
+ *  possible cable length values, which are:
+ *	Register Value		Cable Length
+ *	0			< 50 meters
+ *	1			50 - 80 meters
+ *	2			80 - 110 meters
+ *	3			110 - 140 meters
+ *	4			> 140 meters
+ **/
+s32 e1000e_get_cable_length_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, index;
+
+	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+		M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+	phy->min_cable_length = e1000_m88_cable_length_table[index];
+	phy->max_cable_length = e1000_m88_cable_length_table[index+1];
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_get_cable_length_igp_2 - Determine cable length for igp2 PHY
+ *  @hw: pointer to the HW structure
+ *
+ *  The automatic gain control (agc) normalizes the amplitude of the
+ *  received signal, adjusting for the attenuation produced by the
+ *  cable.  By reading the AGC registers, which reperesent the
+ *  cobination of course and fine gain value, the value can be put
+ *  into a lookup table to obtain the approximate cable length
+ *  for each channel.
+ **/
+s32 e1000e_get_cable_length_igp_2(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 phy_data, i, agc_value = 0;
+	u16 cur_agc_index, max_agc_index = 0;
+	u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1;
+	u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
+							 {IGP02E1000_PHY_AGC_A,
+							  IGP02E1000_PHY_AGC_B,
+							  IGP02E1000_PHY_AGC_C,
+							  IGP02E1000_PHY_AGC_D};
+
+	/* Read the AGC registers for all channels */
+	for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) {
+		ret_val = e1e_rphy(hw, agc_reg_array[i], &phy_data);
+		if (ret_val)
+			return ret_val;
+
+		/* Getting bits 15:9, which represent the combination of
+		 * course and fine gain values.  The result is a number
+		 * that can be put into the lookup table to obtain the
+		 * approximate cable length. */
+		cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+				IGP02E1000_AGC_LENGTH_MASK;
+
+		/* Array index bound check. */
+		if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) ||
+		    (cur_agc_index == 0))
+			return -E1000_ERR_PHY;
+
+		/* Remove min & max AGC values from calculation. */
+		if (e1000_igp_2_cable_length_table[min_agc_index] >
+		    e1000_igp_2_cable_length_table[cur_agc_index])
+			min_agc_index = cur_agc_index;
+		if (e1000_igp_2_cable_length_table[max_agc_index] <
+		    e1000_igp_2_cable_length_table[cur_agc_index])
+			max_agc_index = cur_agc_index;
+
+		agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
+	}
+
+	agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
+		      e1000_igp_2_cable_length_table[max_agc_index]);
+	agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
+
+	/* Calculate cable length with the error range of +/- 10 meters. */
+	phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ?
+				 (agc_value - IGP02E1000_AGC_RANGE) : 0;
+	phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE;
+
+	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_get_phy_info_m88 - Retrieve PHY information
+ *  @hw: pointer to the HW structure
+ *
+ *  Valid for only copper links.  Read the PHY status register (sticky read)
+ *  to verify that link is up.  Read the PHY special control register to
+ *  determine the polarity and 10base-T extended distance.  Read the PHY
+ *  special status register to determine MDI/MDIx and current speed.  If
+ *  speed is 1000, then determine cable length, local and remote receiver.
+ **/
+s32 e1000e_get_phy_info_m88(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32  ret_val;
+	u16 phy_data;
+	bool link;
+
+	if (hw->media_type != e1000_media_type_copper) {
+		hw_dbg(hw, "Phy info is only valid for copper media\n");
+		return -E1000_ERR_CONFIG;
+	}
+
+	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		return ret_val;
+
+	if (!link) {
+		hw_dbg(hw, "Phy info is only valid if link is up\n");
+		return -E1000_ERR_CONFIG;
+	}
+
+	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	phy->polarity_correction = (phy_data &
+				    M88E1000_PSCR_POLARITY_REVERSAL);
+
+	ret_val = e1000_check_polarity_m88(hw);
+	if (ret_val)
+		return ret_val;
+
+	ret_val = e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+	if (ret_val)
+		return ret_val;
+
+	phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX);
+
+	if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
+		ret_val = e1000_get_cable_length(hw);
+		if (ret_val)
+			return ret_val;
+
+		ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);
+		if (ret_val)
+			return ret_val;
+
+		phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS)
+				? e1000_1000t_rx_status_ok
+				: e1000_1000t_rx_status_not_ok;
+
+		phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS)
+				 ? e1000_1000t_rx_status_ok
+				 : e1000_1000t_rx_status_not_ok;
+	} else {
+		/* Set values to "undefined" */
+		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+		phy->local_rx = e1000_1000t_rx_status_undefined;
+		phy->remote_rx = e1000_1000t_rx_status_undefined;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_get_phy_info_igp - Retrieve igp PHY information
+ *  @hw: pointer to the HW structure
+ *
+ *  Read PHY status to determine if link is up.  If link is up, then
+ *  set/determine 10base-T extended distance and polarity correction.  Read
+ *  PHY port status to determine MDI/MDIx and speed.  Based on the speed,
+ *  determine on the cable length, local and remote receiver.
+ **/
+s32 e1000e_get_phy_info_igp(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u16 data;
+	bool link;
+
+	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
+	if (ret_val)
+		return ret_val;
+
+	if (!link) {
+		hw_dbg(hw, "Phy info is only valid if link is up\n");
+		return -E1000_ERR_CONFIG;
+	}
+
+	phy->polarity_correction = 1;
+
+	ret_val = e1000_check_polarity_igp(hw);
+	if (ret_val)
+		return ret_val;
+
+	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data);
+	if (ret_val)
+		return ret_val;
+
+	phy->is_mdix = (data & IGP01E1000_PSSR_MDIX);
+
+	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==
+	    IGP01E1000_PSSR_SPEED_1000MBPS) {
+		ret_val = e1000_get_cable_length(hw);
+		if (ret_val)
+			return ret_val;
+
+		ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data);
+		if (ret_val)
+			return ret_val;
+
+		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)
+				? e1000_1000t_rx_status_ok
+				: e1000_1000t_rx_status_not_ok;
+
+		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)
+				 ? e1000_1000t_rx_status_ok
+				 : e1000_1000t_rx_status_not_ok;
+	} else {
+		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
+		phy->local_rx = e1000_1000t_rx_status_undefined;
+		phy->remote_rx = e1000_1000t_rx_status_undefined;
+	}
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_phy_sw_reset - PHY software reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Does a software reset of the PHY by reading the PHY control register and
+ *  setting/write the control register reset bit to the PHY.
+ **/
+s32 e1000e_phy_sw_reset(struct e1000_hw *hw)
+{
+	s32 ret_val;
+	u16 phy_ctrl;
+
+	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);
+	if (ret_val)
+		return ret_val;
+
+	phy_ctrl |= MII_CR_RESET;
+	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);
+	if (ret_val)
+		return ret_val;
+
+	udelay(1);
+
+	return ret_val;
+}
+
+/**
+ *  e1000e_phy_hw_reset_generic - PHY hardware reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Verify the reset block is not blocking us from resetting.  Acquire
+ *  semaphore (if necessary) and read/set/write the device control reset
+ *  bit in the PHY.  Wait the appropriate delay time for the device to
+ *  reset and relase the semaphore (if necessary).
+ **/
+s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw)
+{
+	struct e1000_phy_info *phy = &hw->phy;
+	s32 ret_val;
+	u32 ctrl;
+
+	ret_val = e1000_check_reset_block(hw);
+	if (ret_val)
+		return 0;
+
+	ret_val = phy->ops.acquire_phy(hw);
+	if (ret_val)
+		return ret_val;
+
+	ctrl = er32(CTRL);
+	ew32(CTRL, ctrl | E1000_CTRL_PHY_RST);
+	e1e_flush();
+
+	udelay(phy->reset_delay_us);
+
+	ew32(CTRL, ctrl);
+	e1e_flush();
+
+	udelay(150);
+
+	phy->ops.release_phy(hw);
+
+	return e1000_get_phy_cfg_done(hw);
+}
+
+/**
+ *  e1000e_get_cfg_done - Generic configuration done
+ *  @hw: pointer to the HW structure
+ *
+ *  Generic function to wait 10 milli-seconds for configuration to complete
+ *  and return success.
+ **/
+s32 e1000e_get_cfg_done(struct e1000_hw *hw)
+{
+	mdelay(10);
+	return 0;
+}
+
+/* Internal function pointers */
+
+/**
+ *  e1000_get_phy_cfg_done - Generic PHY configuration done
+ *  @hw: pointer to the HW structure
+ *
+ *  Return success if silicon family did not implement a family specific
+ *  get_cfg_done function.
+ **/
+static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.get_cfg_done)
+		return hw->phy.ops.get_cfg_done(hw);
+
+	return 0;
+}
+
+/**
+ *  e1000_phy_force_speed_duplex - Generic force PHY speed/duplex
+ *  @hw: pointer to the HW structure
+ *
+ *  When the silicon family has not implemented a forced speed/duplex
+ *  function for the PHY, simply return 0.
+ **/
+static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.force_speed_duplex)
+		return hw->phy.ops.force_speed_duplex(hw);
+
+	return 0;
+}
+
+/**
+ *  e1000e_get_phy_type_from_id - Get PHY type from id
+ *  @phy_id: phy_id read from the phy
+ *
+ *  Returns the phy type from the id.
+ **/
+enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id)
+{
+	enum e1000_phy_type phy_type = e1000_phy_unknown;
+
+	switch (phy_id) {
+	case M88E1000_I_PHY_ID:
+	case M88E1000_E_PHY_ID:
+	case M88E1111_I_PHY_ID:
+	case M88E1011_I_PHY_ID:
+		phy_type = e1000_phy_m88;
+		break;
+	case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */
+		phy_type = e1000_phy_igp_2;
+		break;
+	case GG82563_E_PHY_ID:
+		phy_type = e1000_phy_gg82563;
+		break;
+	case IGP03E1000_E_PHY_ID:
+		phy_type = e1000_phy_igp_3;
+		break;
+	case IFE_E_PHY_ID:
+	case IFE_PLUS_E_PHY_ID:
+	case IFE_C_E_PHY_ID:
+		phy_type = e1000_phy_ife;
+		break;
+	default:
+		phy_type = e1000_phy_unknown;
+		break;
+	}
+	return phy_type;
+}
+
+/**
+ *  e1000e_commit_phy - Soft PHY reset
+ *  @hw: pointer to the HW structure
+ *
+ *  Performs a soft PHY reset on those that apply. This is a function pointer
+ *  entry point called by drivers.
+ **/
+s32 e1000e_commit_phy(struct e1000_hw *hw)
+{
+	if (hw->phy.ops.commit_phy)
+		return hw->phy.ops.commit_phy(hw);
+
+	return 0;
+}
+
+/**
+ *  e1000_set_d0_lplu_state - Sets low power link up state for D0
+ *  @hw: pointer to the HW structure
+ *  @active: boolean used to enable/disable lplu
+ *
+ *  Success returns 0, Failure returns 1
+ *
+ *  The low power link up (lplu) state is set to the power management level D0
+ *  and SmartSpeed is disabled when active is true, else clear lplu for D0
+ *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
+ *  is used during Dx states where the power conservation is most important.
+ *  During driver activity, SmartSpeed should be enabled so performance is
+ *  maintained.  This is a function pointer entry point called by drivers.
+ **/
+static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active)
+{
+	if (hw->phy.ops.set_d0_lplu_state)
+		return hw->phy.ops.set_d0_lplu_state(hw, active);
+
+	return 0;
+}
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index b2b0a96..6390f51 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -124,8 +124,6 @@
 	int base_addr = dev->base_addr;
 	int irq = dev->irq;
 
-	SET_MODULE_OWNER(dev);
-
 	if (base_addr > 0x1ff)		/* Check a single specified location. */
 		return e21_probe1(dev, base_addr);
 	else if (base_addr != 0)	/* Don't probe at all. */
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 4768023..83bda6c 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -192,7 +192,6 @@
 
 /* Information that need to be kept for each board. */
 struct eepro_local {
-	struct net_device_stats stats;
 	unsigned rx_start;
 	unsigned tx_start; /* start of the transmit chain */
 	int tx_last;  /* pointer to last packet in the transmit chain */
@@ -315,7 +314,6 @@
 static void 	eepro_rx(struct net_device *dev);
 static void 	eepro_transmit_interrupt(struct net_device *dev);
 static int	eepro_close(struct net_device *dev);
-static struct net_device_stats *eepro_get_stats(struct net_device *dev);
 static void     set_multicast_list(struct net_device *dev);
 static void     eepro_tx_timeout (struct net_device *dev);
 
@@ -514,7 +512,7 @@
 
 /* a complete sel reset */
 #define eepro_complete_selreset(ioaddr) { \
-						lp->stats.tx_errors++;\
+						dev->stats.tx_errors++;\
 						eepro_sel_reset(ioaddr);\
 						lp->tx_end = \
 							lp->xmt_lower_limit;\
@@ -537,8 +535,6 @@
 	int base_addr = dev->base_addr;
 	int irq = dev->irq;
 
-	SET_MODULE_OWNER(dev);
-
 #ifdef PnPWakeup
 	/* XXXX for multiple cards should this only be run once? */
 
@@ -594,8 +590,6 @@
 	if (!dev)
 		return ERR_PTR(-ENODEV);
 
-	SET_MODULE_OWNER(dev);
-
 	sprintf(dev->name, "eth%d", unit);
 	netdev_boot_setup_check(dev);
 
@@ -696,6 +690,7 @@
 	struct eepro_local *	lp = netdev_priv(dev);
 	int			i;
 	const char *		ifmap[] = {"AUI", "10Base2", "10BaseT"};
+	DECLARE_MAC_BUF(mac);
 
 	i = inb(dev->base_addr + ID_REG);
 	printk(KERN_DEBUG " id: %#x ",i);
@@ -717,10 +712,10 @@
 		case LAN595:
 			printk("%s: Intel 82595-based lan card at %#x,",
 					dev->name, (unsigned)dev->base_addr);
+			break;
 	}
 
-	for (i=0; i < 6; i++)
-		printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
+	printk(" %s", print_mac(mac, dev->dev_addr));
 
 	if (net_debug > 3)
 		printk(KERN_DEBUG ", %dK RCV buffer",
@@ -860,7 +855,6 @@
  	dev->open               = eepro_open;
  	dev->stop               = eepro_close;
  	dev->hard_start_xmit    = eepro_send_packet;
- 	dev->get_stats          = eepro_get_stats;
  	dev->set_multicast_list = &set_multicast_list;
  	dev->tx_timeout		= eepro_tx_timeout;
  	dev->watchdog_timeo	= TX_TIMEOUT;
@@ -1158,9 +1152,9 @@
 
 		if (hardware_send_packet(dev, buf, length))
 			/* we won't wake queue here because we're out of space */
-			lp->stats.tx_dropped++;
+			dev->stats.tx_dropped++;
 		else {
-		lp->stats.tx_bytes+=skb->len;
+		dev->stats.tx_bytes+=skb->len;
 		dev->trans_start = jiffies;
 			netif_wake_queue(dev);
 		}
@@ -1170,7 +1164,7 @@
 	dev_kfree_skb (skb);
 
 	/* You might need to clean up and record Tx statistics here. */
-	/* lp->stats.tx_aborted_errors++; */
+	/* dev->stats.tx_aborted_errors++; */
 
 	if (net_debug > 5)
 		printk(KERN_DEBUG "%s: exiting eepro_send_packet routine.\n", dev->name);
@@ -1277,16 +1271,6 @@
 	return 0;
 }
 
-/* Get the current statistics.	This may be called with the card open or
-   closed. */
-static struct net_device_stats *
-eepro_get_stats(struct net_device *dev)
-{
-	struct eepro_local *lp = netdev_priv(dev);
-
-	return &lp->stats;
-}
-
 /* Set or clear the multicast filter for this adaptor.
  */
 static void
@@ -1579,12 +1563,12 @@
 			/* Malloc up new buffer. */
 			struct sk_buff *skb;
 
-			lp->stats.rx_bytes+=rcv_size;
+			dev->stats.rx_bytes+=rcv_size;
 			rcv_size &= 0x3fff;
 			skb = dev_alloc_skb(rcv_size+5);
 			if (skb == NULL) {
 				printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
-				lp->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 				rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
 				lp->rx_start = rcv_next_frame;
 				outw(rcv_next_frame, ioaddr + HOST_ADDRESS_REG);
@@ -1606,28 +1590,28 @@
 			skb->protocol = eth_type_trans(skb,dev);
 			netif_rx(skb);
 			dev->last_rx = jiffies;
-			lp->stats.rx_packets++;
+			dev->stats.rx_packets++;
 		}
 
 		else { /* Not sure will ever reach here,
 			I set the 595 to discard bad received frames */
-			lp->stats.rx_errors++;
+			dev->stats.rx_errors++;
 
 			if (rcv_status & 0x0100)
-				lp->stats.rx_over_errors++;
+				dev->stats.rx_over_errors++;
 
 			else if (rcv_status & 0x0400)
-				lp->stats.rx_frame_errors++;
+				dev->stats.rx_frame_errors++;
 
 			else if (rcv_status & 0x0800)
-				lp->stats.rx_crc_errors++;
+				dev->stats.rx_crc_errors++;
 
 			printk(KERN_DEBUG "%s: event = %#x, status = %#x, next = %#x, size = %#x\n",
 				dev->name, rcv_event, rcv_status, rcv_next_frame, rcv_size);
 		}
 
 		if (rcv_status & 0x1000)
-			lp->stats.rx_length_errors++;
+			dev->stats.rx_length_errors++;
 
 		rcv_car = lp->rx_start + RCV_HEADER + rcv_size;
 		lp->rx_start = rcv_next_frame;
@@ -1670,11 +1654,11 @@
 		netif_wake_queue (dev);
 
 		if (xmt_status & TX_OK)
-			lp->stats.tx_packets++;
+			dev->stats.tx_packets++;
 		else {
-			lp->stats.tx_errors++;
+			dev->stats.tx_errors++;
 			if (xmt_status & 0x0400) {
-				lp->stats.tx_carrier_errors++;
+				dev->stats.tx_carrier_errors++;
 				printk(KERN_DEBUG "%s: carrier error\n",
 					dev->name);
 				printk(KERN_DEBUG "%s: XMT status = %#x\n",
@@ -1688,11 +1672,11 @@
 			}
 		}
 		if (xmt_status & 0x000f) {
-			lp->stats.collisions += (xmt_status & 0x000f);
+			dev->stats.collisions += (xmt_status & 0x000f);
 		}
 
 		if ((xmt_status & 0x0040) == 0x0) {
-			lp->stats.tx_heartbeat_errors++;
+			dev->stats.tx_heartbeat_errors++;
 		}
 	}
 }
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 3c54014..1548a80 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -622,6 +622,7 @@
 	int size;
 	void *tx_ring_space;
 	dma_addr_t tx_ring_dma;
+	DECLARE_MAC_BUF(mac);
 
 	size = TX_RING_SIZE * sizeof(struct TxFD) + sizeof(struct speedo_stats);
 	tx_ring_space = pci_alloc_consistent(pdev, size, &tx_ring_dma);
@@ -635,7 +636,6 @@
 		return -1;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	if (dev->mem_start > 0)
@@ -706,12 +706,8 @@
 	else
 		product = pci_name(pdev);
 
-	printk(KERN_INFO "%s: %s, ", dev->name, product);
-
-	for (i = 0; i < 5; i++)
-		printk("%2.2X:", dev->dev_addr[i]);
-	printk("%2.2X, ", dev->dev_addr[i]);
-	printk("IRQ %d.\n", pdev->irq);
+	printk(KERN_INFO "%s: %s, %s, IRQ %d.\n", dev->name, product,
+		   print_mac(mac, dev->dev_addr), pdev->irq);
 
 	sp = netdev_priv(dev);
 
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 7934ea3..9c85e50 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -135,7 +135,6 @@
 
 struct net_local
 {
-	struct net_device_stats stats;
 	unsigned long last_tx;       /* jiffies when last transmit started */
 	unsigned long init_time;     /* jiffies when eexp_hw_init586 called */
 	unsigned short rx_first;     /* first rx buf, same as RX_BUF_START */
@@ -247,7 +246,6 @@
 static int eexp_open(struct net_device *dev);
 static int eexp_close(struct net_device *dev);
 static void eexp_timeout(struct net_device *dev);
-static struct net_device_stats *eexp_stats(struct net_device *dev);
 static int eexp_xmit(struct sk_buff *buf, struct net_device *dev);
 
 static irqreturn_t eexp_irq(int irq, void *dev_addr);
@@ -341,8 +339,6 @@
 	int dev_irq = dev->irq;
 	int err;
 
-	SET_MODULE_OWNER(dev);
-
 	dev->if_port = 0xff; /* not set */
 
 #ifdef CONFIG_MCA_LEGACY
@@ -535,17 +531,6 @@
 }
 
 /*
- * Return interface stats
- */
-
-static struct net_device_stats *eexp_stats(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	return &lp->stats;
-}
-
-/*
  * This gets called when a higher level thinks we are broken.  Check that
  * nothing has become jammed in the CU.
  */
@@ -648,7 +633,7 @@
 	printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name,
 	       (SCB_complete(status)?"lost interrupt":
 		"board on fire"));
-	lp->stats.tx_errors++;
+	dev->stats.tx_errors++;
 	lp->last_tx = jiffies;
 	if (!SCB_complete(status)) {
 		scb_command(dev, SCB_CUabort);
@@ -696,7 +681,7 @@
 	{
 		unsigned short *data = (unsigned short *)buf->data;
 
-		lp->stats.tx_bytes += length;
+		dev->stats.tx_bytes += length;
 
 	        eexp_hw_tx_pio(dev,data,length);
 	}
@@ -845,7 +830,7 @@
 			outw(rbd+8, ioaddr+READ_PTR);
 			printk("[%04x]\n", inw(ioaddr+DATAPORT));
 #endif
-			lp->stats.rx_errors++;
+			dev->stats.rx_errors++;
 #if 1
 		        eexp_hw_rxinit(dev);
 #else
@@ -954,17 +939,17 @@
   			}
   			else if (!FD_OK(status))
 			{
-				lp->stats.rx_errors++;
+				dev->stats.rx_errors++;
 				if (FD_CRC(status))
-					lp->stats.rx_crc_errors++;
+					dev->stats.rx_crc_errors++;
 				if (FD_Align(status))
-					lp->stats.rx_frame_errors++;
+					dev->stats.rx_frame_errors++;
 				if (FD_Resrc(status))
-					lp->stats.rx_fifo_errors++;
+					dev->stats.rx_fifo_errors++;
 				if (FD_DMA(status))
-					lp->stats.rx_over_errors++;
+					dev->stats.rx_over_errors++;
 				if (FD_Short(status))
-					lp->stats.rx_length_errors++;
+					dev->stats.rx_length_errors++;
 			}
 			else
 			{
@@ -974,7 +959,7 @@
 				if (skb == NULL)
 				{
 					printk(KERN_WARNING "%s: Memory squeeze, dropping packet\n",dev->name);
-					lp->stats.rx_dropped++;
+					dev->stats.rx_dropped++;
 					break;
 				}
 				skb_reserve(skb, 2);
@@ -983,8 +968,8 @@
 				skb->protocol = eth_type_trans(skb,dev);
 				netif_rx(skb);
 				dev->last_rx = jiffies;
-				lp->stats.rx_packets++;
-				lp->stats.rx_bytes += pkt_len;
+				dev->stats.rx_packets++;
+				dev->stats.rx_bytes += pkt_len;
 			}
 			outw(rx_block, ioaddr+WRITE_PTR);
 			outw(0, ioaddr+DATAPORT);
@@ -1055,7 +1040,7 @@
 		outw(0xFFFF, ioaddr+SIGNAL_CA);
 	}
 
-	lp->stats.tx_packets++;
+	dev->stats.tx_packets++;
 	lp->last_tx = jiffies;
 }
 
@@ -1182,7 +1167,6 @@
 	dev->open = eexp_open;
 	dev->stop = eexp_close;
 	dev->hard_start_xmit = eexp_xmit;
-	dev->get_stats = eexp_stats;
 	dev->set_multicast_list = &eexp_set_multicast;
 	dev->tx_timeout = eexp_timeout;
 	dev->watchdog_timeo = 2*HZ;
@@ -1265,35 +1249,35 @@
 		else
 		{
 			lp->last_tx_restart = 0;
-			lp->stats.collisions += Stat_NoColl(status);
+			dev->stats.collisions += Stat_NoColl(status);
 			if (!Stat_OK(status))
 			{
 				char *whatsup = NULL;
-				lp->stats.tx_errors++;
+				dev->stats.tx_errors++;
   				if (Stat_Abort(status))
-  					lp->stats.tx_aborted_errors++;
+					dev->stats.tx_aborted_errors++;
 				if (Stat_TNoCar(status)) {
 					whatsup = "aborted, no carrier";
-					lp->stats.tx_carrier_errors++;
+					dev->stats.tx_carrier_errors++;
 				}
 				if (Stat_TNoCTS(status)) {
 					whatsup = "aborted, lost CTS";
-  					lp->stats.tx_carrier_errors++;
+					dev->stats.tx_carrier_errors++;
 				}
 				if (Stat_TNoDMA(status)) {
 					whatsup = "FIFO underran";
-  					lp->stats.tx_fifo_errors++;
+					dev->stats.tx_fifo_errors++;
 				}
 				if (Stat_TXColl(status)) {
 					whatsup = "aborted, too many collisions";
-					lp->stats.tx_aborted_errors++;
+					dev->stats.tx_aborted_errors++;
 				}
 				if (whatsup)
 					printk(KERN_INFO "%s: transmit %s\n",
 					       dev->name, whatsup);
 			}
 			else
-				lp->stats.tx_packets++;
+				dev->stats.tx_packets++;
 		}
 		if (tx_block == TX_BUF_START+((lp->num_tx_bufs-1)*TX_BUF_SIZE))
 			lp->tx_reap = tx_block = TX_BUF_START;
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 6628fa6..ac21526 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -33,19 +33,20 @@
 #include <linux/ethtool.h>
 #include <linux/vmalloc.h>
 #include <linux/if_vlan.h>
+#include <linux/inet_lro.h>
 
 #include <asm/ibmebus.h>
 #include <asm/abs_addr.h>
 #include <asm/io.h>
 
 #define DRV_NAME	"ehea"
-#define DRV_VERSION	"EHEA_0070"
+#define DRV_VERSION	"EHEA_0078"
 
 /* eHEA capability flags */
 #define DLPAR_PORT_ADD_REM 1
 #define DLPAR_MEM_ADD      2
 #define DLPAR_MEM_REM      4
-#define EHEA_CAPABILITIES  (DLPAR_PORT_ADD_REM)
+#define EHEA_CAPABILITIES  (DLPAR_PORT_ADD_REM | DLPAR_MEM_ADD)
 
 #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
 	| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
@@ -58,6 +59,7 @@
 
 #define EHEA_SMALL_QUEUES
 #define EHEA_NUM_TX_QP 1
+#define EHEA_LRO_MAX_AGGR 64
 
 #ifdef EHEA_SMALL_QUEUES
 #define EHEA_MAX_CQE_COUNT      1023
@@ -84,6 +86,8 @@
 #define EHEA_RQ2_PKT_SIZE       1522
 #define EHEA_L_PKT_SIZE         256	/* low latency */
 
+#define MAX_LRO_DESCRIPTORS 8
+
 /* Send completion signaling */
 
 /* Protection Domain Identifier */
@@ -351,6 +355,7 @@
  * Port resources
  */
 struct ehea_port_res {
+	struct napi_struct napi;
 	struct port_stats p_stats;
 	struct ehea_mr send_mr;       	/* send memory region */
 	struct ehea_mr recv_mr;       	/* receive memory region */
@@ -362,7 +367,6 @@
 	struct ehea_cq *send_cq;
 	struct ehea_cq *recv_cq;
 	struct ehea_eq *eq;
-	struct net_device *d_netdev;
 	struct ehea_q_skb_arr rq1_skba;
 	struct ehea_q_skb_arr rq2_skba;
 	struct ehea_q_skb_arr rq3_skba;
@@ -376,6 +380,8 @@
 	u64 tx_packets;
 	u64 rx_packets;
 	u32 poll_counter;
+	struct net_lro_mgr lro_mgr;
+	struct net_lro_desc lro_desc[MAX_LRO_DESCRIPTORS];
 };
 
 
@@ -385,7 +391,6 @@
 	struct ibmebus_dev *ebus_dev;
 	struct ehea_port *port[EHEA_MAX_PORTS];
 	struct ehea_eq *neq;       /* notification event queue */
-	struct workqueue_struct *ehea_wq;
 	struct tasklet_struct neq_tasklet;
 	struct ehea_mr mr;
 	u32 pd;                    /* protection domain */
@@ -402,6 +407,8 @@
 
 #define EHEA_PORT_UP 1
 #define EHEA_PORT_DOWN 0
+#define EHEA_PHY_LINK_UP 1
+#define EHEA_PHY_LINK_DOWN 0
 #define EHEA_MAX_PORT_RES 16
 struct ehea_port {
 	struct ehea_adapter *adapter;	 /* adapter that owns this port */
@@ -427,6 +434,8 @@
 	u32 msg_enable;
 	u32 sig_comp_iv;
 	u32 state;
+	u32 lro_max_aggr;
+	u8 phy_link;
 	u8 full_duplex;
 	u8 autoneg;
 	u8 num_def_qps;
diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c
index decec8c..679f40e 100644
--- a/drivers/net/ehea/ehea_ethtool.c
+++ b/drivers/net/ehea/ehea_ethtool.c
@@ -183,6 +183,9 @@
 	{"PR5 free_swqes"},
 	{"PR6 free_swqes"},
 	{"PR7 free_swqes"},
+	{"LRO aggregated"},
+	{"LRO flushed"},
+	{"LRO no_desc"},
 };
 
 static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -193,9 +196,14 @@
 	}
 }
 
-static int ehea_get_stats_count(struct net_device *dev)
+static int ehea_get_sset_count(struct net_device *dev, int sset)
 {
-	return ARRAY_SIZE(ehea_ethtool_stats_keys);
+	switch (sset) {
+	case ETH_SS_STATS:
+		return ARRAY_SIZE(ehea_ethtool_stats_keys);
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void ehea_get_ethtool_stats(struct net_device *dev,
@@ -204,7 +212,7 @@
 	int i, k, tmp;
 	struct ehea_port *port = netdev_priv(dev);
 
-	for (i = 0; i < ehea_get_stats_count(dev); i++)
+	for (i = 0; i < ehea_get_sset_count(dev, ETH_SS_STATS); i++)
 		data[i] = 0;
 	i = 0;
 
@@ -239,6 +247,18 @@
 	for (k = 0; k < 8; k++)
 		data[i++] = atomic_read(&port->port_res[k].swqe_avail);
 
+	for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+		tmp |= port->port_res[k].lro_mgr.stats.aggregated;
+	data[i++] = tmp;
+
+	for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+		tmp |= port->port_res[k].lro_mgr.stats.flushed;
+	data[i++] = tmp;
+
+	for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++)
+		tmp |= port->port_res[k].lro_mgr.stats.no_desc;
+	data[i++] = tmp;
+
 }
 
 const struct ethtool_ops ehea_ethtool_ops = {
@@ -247,12 +267,9 @@
 	.get_msglevel = ehea_get_msglevel,
 	.set_msglevel = ehea_set_msglevel,
 	.get_link = ethtool_op_get_link,
-	.get_tx_csum = ethtool_op_get_tx_csum,
-	.get_sg = ethtool_op_get_sg,
-	.get_tso = ethtool_op_get_tso,
 	.set_tso = ethtool_op_set_tso,
 	.get_strings = ehea_get_strings,
-	.get_stats_count = ehea_get_stats_count,
+	.get_sset_count = ehea_get_sset_count,
 	.get_ethtool_stats = ehea_get_ethtool_stats,
 	.get_rx_csum = ehea_get_rx_csum,
 	.set_settings = ehea_set_settings,
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 1d1571cf3..2ba57e6 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -52,18 +52,26 @@
 static int rq3_entries = EHEA_DEF_ENTRIES_RQ3;
 static int sq_entries = EHEA_DEF_ENTRIES_SQ;
 static int use_mcs = 0;
+static int use_lro = 0;
+static int lro_max_aggr = EHEA_LRO_MAX_AGGR;
 static int num_tx_qps = EHEA_NUM_TX_QP;
+static int prop_carrier_state = 0;
 
 module_param(msg_level, int, 0);
 module_param(rq1_entries, int, 0);
 module_param(rq2_entries, int, 0);
 module_param(rq3_entries, int, 0);
 module_param(sq_entries, int, 0);
+module_param(prop_carrier_state, int, 0);
 module_param(use_mcs, int, 0);
+module_param(use_lro, int, 0);
+module_param(lro_max_aggr, int, 0);
 module_param(num_tx_qps, int, 0);
 
 MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS");
 MODULE_PARM_DESC(msg_level, "msg_level");
+MODULE_PARM_DESC(prop_carrier_state, "Propagate carrier state of physical "
+		 "port to stack. 1:yes, 0:no.  Default = 0 ");
 MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 "
 		 "[2^x - 1], x = [6..14]. Default = "
 		 __MODULE_STRING(EHEA_DEF_ENTRIES_RQ3) ")");
@@ -76,14 +84,19 @@
 MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue  "
 		 "[2^x - 1], x = [6..14]. Default = "
 		 __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")");
-MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 1 ");
+MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 0 ");
+
+MODULE_PARM_DESC(lro_max_aggr, " LRO: Max packets to be aggregated. Default = "
+		 __MODULE_STRING(EHEA_LRO_MAX_AGGR));
+MODULE_PARM_DESC(use_lro, " Large Receive Offload, 1: enable, 0: disable, "
+		 "Default = 0");
 
 static int port_name_cnt = 0;
 static LIST_HEAD(adapter_list);
 u64 ehea_driver_flags = 0;
-struct workqueue_struct *ehea_driver_wq;
 struct work_struct ehea_rereg_mr_task;
 
+struct semaphore dlpar_mem_lock;
 
 static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev,
 					const struct of_device_id *id);
@@ -164,16 +177,24 @@
 	struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr;
 	struct net_device *dev = pr->port->netdev;
 	int max_index_mask = pr->rq1_skba.len - 1;
+	int fill_wqes = pr->rq1_skba.os_skbs + nr_of_wqes;
+	int adder = 0;
 	int i;
 
-	if (!nr_of_wqes)
-		return;
+	pr->rq1_skba.os_skbs = 0;
 
-	for (i = 0; i < nr_of_wqes; i++) {
+	if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) {
+		pr->rq1_skba.index = index;
+		pr->rq1_skba.os_skbs = fill_wqes;
+		return;
+	}
+
+	for (i = 0; i < fill_wqes; i++) {
 		if (!skb_arr_rq1[index]) {
 			skb_arr_rq1[index] = netdev_alloc_skb(dev,
 							      EHEA_L_PKT_SIZE);
 			if (!skb_arr_rq1[index]) {
+				pr->rq1_skba.os_skbs = fill_wqes - i;
 				ehea_error("%s: no mem for skb/%d wqes filled",
 					   dev->name, i);
 				break;
@@ -181,9 +202,14 @@
 		}
 		index--;
 		index &= max_index_mask;
+		adder++;
 	}
+
+	if (adder == 0)
+		return;
+
 	/* Ring doorbell */
-	ehea_update_rq1a(pr->qp, i);
+	ehea_update_rq1a(pr->qp, adder);
 }
 
 static int ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a)
@@ -217,16 +243,21 @@
 	struct sk_buff **skb_arr = q_skba->arr;
 	struct ehea_rwqe *rwqe;
 	int i, index, max_index_mask, fill_wqes;
+	int adder = 0;
 	int ret = 0;
 
 	fill_wqes = q_skba->os_skbs + num_wqes;
+	q_skba->os_skbs = 0;
 
-	if (!fill_wqes)
+	if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) {
+		q_skba->os_skbs = fill_wqes;
 		return ret;
+	}
 
 	index = q_skba->index;
 	max_index_mask = q_skba->len - 1;
 	for (i = 0; i < fill_wqes; i++) {
+		u64 tmp_addr;
 		struct sk_buff *skb = netdev_alloc_skb(dev, packet_size);
 		if (!skb) {
 			ehea_error("%s: no mem for skb/%d wqes filled",
@@ -238,30 +269,37 @@
 		skb_reserve(skb, NET_IP_ALIGN);
 
 		skb_arr[index] = skb;
+		tmp_addr = ehea_map_vaddr(skb->data);
+		if (tmp_addr == -1) {
+			dev_kfree_skb(skb);
+			q_skba->os_skbs = fill_wqes - i;
+			ret = 0;
+			break;
+		}
 
 		rwqe = ehea_get_next_rwqe(qp, rq_nr);
 		rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, wqe_type)
 			    | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index);
 		rwqe->sg_list[0].l_key = pr->recv_mr.lkey;
-		rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data);
+		rwqe->sg_list[0].vaddr = tmp_addr;
 		rwqe->sg_list[0].len = packet_size;
 		rwqe->data_segments = 1;
 
 		index++;
 		index &= max_index_mask;
-
-		if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)))
-			goto out;
+		adder++;
 	}
 
 	q_skba->index = index;
+	if (adder == 0)
+		goto out;
 
 	/* Ring doorbell */
 	iosync();
 	if (rq_nr == 2)
-		ehea_update_rq2a(pr->qp, i);
+		ehea_update_rq2a(pr->qp, adder);
 	else
-		ehea_update_rq3a(pr->qp, i);
+		ehea_update_rq3a(pr->qp, adder);
 out:
 	return ret;
 }
@@ -382,16 +420,70 @@
 
 	if (cqe->status & EHEA_CQE_STAT_FAT_ERR_MASK) {
 		ehea_error("Critical receive error. Resetting port.");
-		queue_work(pr->port->adapter->ehea_wq, &pr->port->reset_task);
+		schedule_work(&pr->port->reset_task);
 		return 1;
 	}
 
 	return 0;
 }
 
-static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev,
-					struct ehea_port_res *pr,
-					int *budget)
+static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
+		       void **tcph, u64 *hdr_flags, void *priv)
+{
+	struct ehea_cqe *cqe = priv;
+	unsigned int ip_len;
+	struct iphdr *iph;
+
+	/* non tcp/udp packets */
+	if (!cqe->header_length)
+		return -1;
+
+	/* non tcp packet */
+	skb_reset_network_header(skb);
+	iph = ip_hdr(skb);
+	if (iph->protocol != IPPROTO_TCP)
+		return -1;
+
+	ip_len = ip_hdrlen(skb);
+	skb_set_transport_header(skb, ip_len);
+	*tcph = tcp_hdr(skb);
+
+	/* check if ip header and tcp header are complete */
+	if (iph->tot_len < ip_len + tcp_hdrlen(skb))
+		return -1;
+
+	*hdr_flags = LRO_IPV4 | LRO_TCP;
+	*iphdr = iph;
+
+	return 0;
+}
+
+static void ehea_proc_skb(struct ehea_port_res *pr, struct ehea_cqe *cqe,
+			  struct sk_buff *skb)
+{
+	int vlan_extracted = (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT)
+		&& pr->port->vgrp;
+
+	if (use_lro) {
+		if (vlan_extracted)
+			lro_vlan_hwaccel_receive_skb(&pr->lro_mgr, skb,
+						     pr->port->vgrp,
+						     cqe->vlan_tag,
+						     cqe);
+		else
+			lro_receive_skb(&pr->lro_mgr, skb, cqe);
+	} else {
+		if (vlan_extracted)
+			vlan_hwaccel_receive_skb(skb, pr->port->vgrp,
+						 cqe->vlan_tag);
+		else
+			netif_receive_skb(skb);
+	}
+}
+
+static int ehea_proc_rwqes(struct net_device *dev,
+			   struct ehea_port_res *pr,
+			   int budget)
 {
 	struct ehea_port *port = pr->port;
 	struct ehea_qp *qp = pr->qp;
@@ -404,18 +496,16 @@
 	int skb_arr_rq2_len = pr->rq2_skba.len;
 	int skb_arr_rq3_len = pr->rq3_skba.len;
 	int processed, processed_rq1, processed_rq2, processed_rq3;
-	int wqe_index, last_wqe_index, rq, my_quota, port_reset;
+	int wqe_index, last_wqe_index, rq, port_reset;
 
 	processed = processed_rq1 = processed_rq2 = processed_rq3 = 0;
 	last_wqe_index = 0;
-	my_quota = min(*budget, dev->quota);
 
 	cqe = ehea_poll_rq1(qp, &wqe_index);
-	while ((my_quota > 0) && cqe) {
+	while ((processed < budget) && cqe) {
 		ehea_inc_rq1(qp);
 		processed_rq1++;
 		processed++;
-		my_quota--;
 		if (netif_msg_rx_status(port))
 			ehea_dump(cqe, sizeof(*cqe), "CQE");
 
@@ -430,14 +520,14 @@
 					if (netif_msg_rx_err(port))
 						ehea_error("LL rq1: skb=NULL");
 
-					skb = netdev_alloc_skb(port->netdev,
+					skb = netdev_alloc_skb(dev,
 							       EHEA_L_PKT_SIZE);
 					if (!skb)
 						break;
 				}
 				skb_copy_to_linear_data(skb, ((char*)cqe) + 64,
 						 cqe->num_bytes_transfered - 4);
-				ehea_fill_skb(port->netdev, skb, cqe);
+				ehea_fill_skb(dev, skb, cqe);
 			} else if (rq == 2) {  /* RQ2 */
 				skb = get_skb_by_index(skb_arr_rq2,
 						       skb_arr_rq2_len, cqe);
@@ -446,7 +536,7 @@
 						ehea_error("rq2: skb=NULL");
 					break;
 				}
-				ehea_fill_skb(port->netdev, skb, cqe);
+				ehea_fill_skb(dev, skb, cqe);
 				processed_rq2++;
 			} else {  /* RQ3 */
 				skb = get_skb_by_index(skb_arr_rq3,
@@ -456,16 +546,12 @@
 						ehea_error("rq3: skb=NULL");
 					break;
 				}
-				ehea_fill_skb(port->netdev, skb, cqe);
+				ehea_fill_skb(dev, skb, cqe);
 				processed_rq3++;
 			}
 
-			if ((cqe->status & EHEA_CQE_VLAN_TAG_XTRACT)
-			    && port->vgrp)
-				vlan_hwaccel_receive_skb(skb, port->vgrp,
-							 cqe->vlan_tag);
-			else
-				netif_receive_skb(skb);
+			ehea_proc_skb(pr, cqe, skb);
+			dev->last_rx = jiffies;
 		} else {
 			pr->p_stats.poll_receive_errors++;
 			port_reset = ehea_treat_poll_error(pr, rq, cqe,
@@ -476,16 +562,16 @@
 		}
 		cqe = ehea_poll_rq1(qp, &wqe_index);
 	}
+	if (use_lro)
+		lro_flush_all(&pr->lro_mgr);
 
 	pr->rx_packets += processed;
-	*budget -= processed;
 
 	ehea_refill_rq1(pr, last_wqe_index, processed_rq1);
 	ehea_refill_rq2(pr, processed_rq2);
 	ehea_refill_rq3(pr, processed_rq3);
 
-	cqe = ehea_poll_rq1(qp, &wqe_index);
-	return cqe;
+	return processed;
 }
 
 static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota)
@@ -509,8 +595,7 @@
 			ehea_error("Send Completion Error: Resetting port");
 			if (netif_msg_tx_err(pr->port))
 				ehea_dump(cqe, sizeof(*cqe), "Send CQE");
-			queue_work(pr->port->adapter->ehea_wq,
-				   &pr->port->reset_task);
+			schedule_work(&pr->port->reset_task);
 			break;
 		}
 
@@ -548,22 +633,27 @@
 }
 
 #define EHEA_NAPI_POLL_NUM_BEFORE_IRQ 16
+#define EHEA_POLL_MAX_CQES 65535
 
-static int ehea_poll(struct net_device *dev, int *budget)
+static int ehea_poll(struct napi_struct *napi, int budget)
 {
-	struct ehea_port_res *pr = dev->priv;
+	struct ehea_port_res *pr = container_of(napi, struct ehea_port_res, napi);
+	struct net_device *dev = pr->port->netdev;
 	struct ehea_cqe *cqe;
 	struct ehea_cqe *cqe_skb = NULL;
 	int force_irq, wqe_index;
-
-	cqe = ehea_poll_rq1(pr->qp, &wqe_index);
-	cqe_skb = ehea_poll_cq(pr->send_cq);
+	int rx = 0;
 
 	force_irq = (pr->poll_counter > EHEA_NAPI_POLL_NUM_BEFORE_IRQ);
+	cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES);
 
-	if ((!cqe && !cqe_skb) || force_irq) {
+	if (!force_irq)
+		rx += ehea_proc_rwqes(dev, pr, budget - rx);
+
+	while ((rx != budget) || force_irq) {
 		pr->poll_counter = 0;
-		netif_rx_complete(dev);
+		force_irq = 0;
+		netif_rx_complete(dev, napi);
 		ehea_reset_cq_ep(pr->recv_cq);
 		ehea_reset_cq_ep(pr->send_cq);
 		ehea_reset_cq_n1(pr->recv_cq);
@@ -572,26 +662,35 @@
 		cqe_skb = ehea_poll_cq(pr->send_cq);
 
 		if (!cqe && !cqe_skb)
-			return 0;
+			return rx;
 
-		if (!netif_rx_reschedule(dev, dev->quota))
-			return 0;
+		if (!netif_rx_reschedule(dev, napi))
+			return rx;
+
+		cqe_skb = ehea_proc_cqes(pr, EHEA_POLL_MAX_CQES);
+		rx += ehea_proc_rwqes(dev, pr, budget - rx);
 	}
 
-	cqe = ehea_proc_rwqes(dev, pr, budget);
-	cqe_skb = ehea_proc_cqes(pr, 300);
-
-	if (cqe || cqe_skb)
-		pr->poll_counter++;
-
-	return 1;
+	pr->poll_counter++;
+	return rx;
 }
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void ehea_netpoll(struct net_device *dev)
+{
+	struct ehea_port *port = netdev_priv(dev);
+	int i;
+
+	for (i = 0; i < port->num_def_qps; i++)
+		netif_rx_schedule(dev, &port->port_res[i].napi);
+}
+#endif
+
 static irqreturn_t ehea_recv_irq_handler(int irq, void *param)
 {
 	struct ehea_port_res *pr = param;
 
-	netif_rx_schedule(pr->d_netdev);
+	netif_rx_schedule(pr->port->netdev, &pr->napi);
 
 	return IRQ_HANDLED;
 }
@@ -615,7 +714,7 @@
 		eqe = ehea_poll_eq(port->qp_eq);
 	}
 
-	queue_work(port->adapter->ehea_wq, &port->reset_task);
+	schedule_work(&port->reset_task);
 
 	return IRQ_HANDLED;
 }
@@ -795,7 +894,9 @@
 			ehea_error("Failed setting port speed");
 		}
 	}
-	netif_carrier_on(port->netdev);
+	if (!prop_carrier_state || (port->phy_link == EHEA_PHY_LINK_UP))
+		netif_carrier_on(port->netdev);
+
 	kfree(cb4);
 out:
 	return ret;
@@ -850,13 +951,19 @@
 			}
 
 		if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PORT_UP, eqe)) {
+			port->phy_link = EHEA_PHY_LINK_UP;
 			if (netif_msg_link(port))
 				ehea_info("%s: Physical port up",
 					  port->netdev->name);
+			if (prop_carrier_state)
+				netif_carrier_on(port->netdev);
 		} else {
+			port->phy_link = EHEA_PHY_LINK_DOWN;
 			if (netif_msg_link(port))
 				ehea_info("%s: Physical port down",
 					  port->netdev->name);
+			if (prop_carrier_state)
+				netif_carrier_off(port->netdev);
 		}
 
 		if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PRIMARY, eqe))
@@ -1205,14 +1312,16 @@
 
 	kfree(init_attr);
 
-	pr->d_netdev = alloc_netdev(0, "", ether_setup);
-	if (!pr->d_netdev)
-		goto out_free;
-	pr->d_netdev->priv = pr;
-	pr->d_netdev->weight = 64;
-	pr->d_netdev->poll = ehea_poll;
-	set_bit(__LINK_STATE_START, &pr->d_netdev->state);
-	strcpy(pr->d_netdev->name, port->netdev->name);
+	netif_napi_add(pr->port->netdev, &pr->napi, ehea_poll, 64);
+
+	pr->lro_mgr.max_aggr = pr->port->lro_max_aggr;
+	pr->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS;
+	pr->lro_mgr.lro_arr = pr->lro_desc;
+	pr->lro_mgr.get_skb_header = get_skb_hdr;
+	pr->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
+	pr->lro_mgr.dev = port->netdev;
+	pr->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
+	pr->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
 
 	ret = 0;
 	goto out;
@@ -1235,8 +1344,6 @@
 {
 	int ret, i;
 
-	free_netdev(pr->d_netdev);
-
 	ret = ehea_destroy_qp(pr->qp);
 
 	if (!ret) {
@@ -1307,7 +1414,6 @@
 	u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0];
 	int skb_data_size = skb->len - skb->data_len;
 	int headersize;
-	u64 tmp_addr;
 
 	/* Packet is TCP with TSO enabled */
 	swqe->tx_control |= EHEA_SWQE_TSO;
@@ -1328,9 +1434,8 @@
 			/* set sg1entry data */
 			sg1entry->l_key = lkey;
 			sg1entry->len = skb_data_size - headersize;
-
-			tmp_addr = (u64)(skb->data + headersize);
-			sg1entry->vaddr = ehea_map_vaddr(tmp_addr);
+			sg1entry->vaddr =
+				ehea_map_vaddr(skb->data + headersize);
 			swqe->descriptors++;
 		}
 	} else
@@ -1343,7 +1448,6 @@
 	int skb_data_size = skb->len - skb->data_len;
 	u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0];
 	struct ehea_vsgentry *sg1entry = &swqe->u.immdata_desc.sg_entry;
-	u64 tmp_addr;
 
 	/* Packet is any nonTSO type
 	 *
@@ -1360,8 +1464,8 @@
 			/* copy sg1entry data */
 			sg1entry->l_key = lkey;
 			sg1entry->len = skb_data_size - SWQE2_MAX_IMM;
-			tmp_addr = (u64)(skb->data + SWQE2_MAX_IMM);
-			sg1entry->vaddr = ehea_map_vaddr(tmp_addr);
+			sg1entry->vaddr =
+				ehea_map_vaddr(skb->data + SWQE2_MAX_IMM);
 			swqe->descriptors++;
 		}
 	} else {
@@ -1376,7 +1480,6 @@
 	struct ehea_vsgentry *sg_list, *sg1entry, *sgentry;
 	skb_frag_t *frag;
 	int nfrags, sg1entry_contains_frag_data, i;
-	u64 tmp_addr;
 
 	nfrags = skb_shinfo(skb)->nr_frags;
 	sg1entry = &swqe->u.immdata_desc.sg_entry;
@@ -1398,9 +1501,9 @@
 			/* copy sg1entry data */
 			sg1entry->l_key = lkey;
 			sg1entry->len = frag->size;
-			tmp_addr =  (u64)(page_address(frag->page)
-					  + frag->page_offset);
-			sg1entry->vaddr = ehea_map_vaddr(tmp_addr);
+			sg1entry->vaddr =
+				ehea_map_vaddr(page_address(frag->page)
+					       + frag->page_offset);
 			swqe->descriptors++;
 			sg1entry_contains_frag_data = 1;
 		}
@@ -1412,10 +1515,9 @@
 
 			sgentry->l_key = lkey;
 			sgentry->len = frag->size;
-
-			tmp_addr = (u64)(page_address(frag->page)
-					 + frag->page_offset);
-			sgentry->vaddr = ehea_map_vaddr(tmp_addr);
+			sgentry->vaddr =
+				ehea_map_vaddr(page_address(frag->page)
+					       + frag->page_offset);
 			swqe->descriptors++;
 		}
 	}
@@ -1433,7 +1535,8 @@
 				     port->logical_port_id,
 				     reg_type, port->mac_addr, 0, hcallid);
 	if (hret != H_SUCCESS) {
-		ehea_error("reg_dereg_bcmc failed (tagged)");
+		ehea_error("%sregistering bc address failed (tagged)",
+                           hcallid == H_REG_BCMC ? "" : "de");
 		ret = -EIO;
 		goto out_herr;
 	}
@@ -1444,7 +1547,8 @@
 				     port->logical_port_id,
 				     reg_type, port->mac_addr, 0, hcallid);
 	if (hret != H_SUCCESS) {
-		ehea_error("reg_dereg_bcmc failed (vlan)");
+		ehea_error("%sregistering bc address failed (vlan)",
+			   hcallid == H_REG_BCMC ? "" : "de");
 		ret = -EIO;
 	}
 out_herr:
@@ -1887,11 +1991,12 @@
 		ehea_dump(swqe, 512, "swqe");
 	}
 
-	if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags)))
-		goto out;
+	if (unlikely(test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))) {
+		netif_stop_queue(dev);
+		swqe->tx_control |= EHEA_SWQE_PURGE;
+	}
 
 	ehea_post_swqe(pr->qp, swqe);
-	pr->tx_packets++;
 
 	if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
 		spin_lock_irqsave(&pr->netif_queue, flags);
@@ -1904,7 +2009,7 @@
 	}
 	dev->trans_start = jiffies;
 	spin_unlock(&pr->xmit_lock);
-out:
+
 	return NETDEV_TX_OK;
 }
 
@@ -2144,24 +2249,18 @@
 	return ret;
 }
 
-static void ehea_remove_adapter_mr (struct ehea_adapter *adapter)
+static void ehea_remove_adapter_mr(struct ehea_adapter *adapter)
 {
-	int i;
-
-	for (i=0; i < EHEA_MAX_PORTS; i++)
-		if (adapter->port[i])
-			return;
+	if (adapter->active_ports)
+		return;
 
 	ehea_rem_mr(&adapter->mr);
 }
 
-static int ehea_add_adapter_mr (struct ehea_adapter *adapter)
+static int ehea_add_adapter_mr(struct ehea_adapter *adapter)
 {
-	int i;
-
-	for (i=0; i < EHEA_MAX_PORTS; i++)
-		if (adapter->port[i])
-			return 0;
+	if (adapter->active_ports)
+		return 0;
 
 	return ehea_reg_kernel_mr(adapter, &adapter->mr);
 }
@@ -2170,7 +2269,6 @@
 {
 	int ret, i;
 	struct ehea_port *port = netdev_priv(dev);
-	u64 mac_addr = 0;
 
 	if (port->state == EHEA_PORT_UP)
 		return 0;
@@ -2189,18 +2287,10 @@
 		goto out_clean_pr;
 	}
 
-	ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
-	if (ret) {
-		ret = -EIO;
-		ehea_error("out_clean_pr");
-		goto out_clean_pr;
-	}
-	mac_addr = (*(u64*)dev->dev_addr) >> 16;
-
 	ret = ehea_reg_interrupts(dev);
 	if (ret) {
-		ehea_error("out_dereg_bc");
-		goto out_dereg_bc;
+		ehea_error("reg_interrupts failed. ret:%d", ret);
+		goto out_clean_pr;
 	}
 
 	for(i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
@@ -2226,9 +2316,6 @@
 out_free_irqs:
 	ehea_free_interrupts(dev);
 
-out_dereg_bc:
-	ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
-
 out_clean_pr:
 	ehea_clean_all_portres(port);
 out:
@@ -2238,6 +2325,22 @@
 	return ret;
 }
 
+static void port_napi_disable(struct ehea_port *port)
+{
+	int i;
+
+	for (i = 0; i < port->num_def_qps; i++)
+		napi_disable(&port->port_res[i].napi);
+}
+
+static void port_napi_enable(struct ehea_port *port)
+{
+	int i;
+
+	for (i = 0; i < port->num_def_qps; i++)
+		napi_enable(&port->port_res[i].napi);
+}
+
 static int ehea_open(struct net_device *dev)
 {
 	int ret;
@@ -2249,8 +2352,10 @@
 		ehea_info("enabling port %s", dev->name);
 
 	ret = ehea_up(dev);
-	if (!ret)
+	if (!ret) {
+		port_napi_enable(port);
 		netif_start_queue(dev);
+	}
 
 	up(&port->port_lock);
 
@@ -2259,7 +2364,7 @@
 
 static int ehea_down(struct net_device *dev)
 {
-	int ret, i;
+	int ret;
 	struct ehea_port *port = netdev_priv(dev);
 
 	if (port->state == EHEA_PORT_DOWN)
@@ -2268,12 +2373,8 @@
 	ehea_drop_multicast_list(dev);
 	ehea_free_interrupts(dev);
 
-	for (i = 0; i < port->num_def_qps; i++)
-		while (test_bit(__LINK_STATE_RX_SCHED,
-				&port->port_res[i].d_netdev->state))
-			msleep(1);
+	port_napi_disable(port);
 
-	ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
 	port->state = EHEA_PORT_DOWN;
 
 	ret = ehea_clean_all_portres(port);
@@ -2292,7 +2393,7 @@
 	if (netif_msg_ifdown(port))
 		ehea_info("disabling port %s", dev->name);
 
-	flush_workqueue(port->adapter->ehea_wq);
+	flush_scheduled_work();
 	down(&port->port_lock);
 	netif_stop_queue(dev);
 	ret = ehea_down(dev);
@@ -2300,6 +2401,192 @@
 	return ret;
 }
 
+void ehea_purge_sq(struct ehea_qp *orig_qp)
+{
+	struct ehea_qp qp = *orig_qp;
+	struct ehea_qp_init_attr *init_attr = &qp.init_attr;
+	struct ehea_swqe *swqe;
+	int wqe_index;
+	int i;
+
+	for (i = 0; i < init_attr->act_nr_send_wqes; i++) {
+		swqe = ehea_get_swqe(&qp, &wqe_index);
+		swqe->tx_control |= EHEA_SWQE_PURGE;
+	}
+}
+
+int ehea_stop_qps(struct net_device *dev)
+{
+	struct ehea_port *port = netdev_priv(dev);
+	struct ehea_adapter *adapter = port->adapter;
+	struct hcp_modify_qp_cb0* cb0;
+	int ret = -EIO;
+	int dret;
+	int i;
+	u64 hret;
+	u64 dummy64 = 0;
+	u16 dummy16 = 0;
+
+	cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!cb0) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	for (i = 0; i < (port->num_def_qps + port->num_add_tx_qps); i++) {
+		struct ehea_port_res *pr =  &port->port_res[i];
+		struct ehea_qp *qp = pr->qp;
+
+		/* Purge send queue */
+		ehea_purge_sq(qp);
+
+		/* Disable queue pair */
+		hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+					    EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
+					    cb0);
+		if (hret != H_SUCCESS) {
+			ehea_error("query_ehea_qp failed (1)");
+			goto out;
+		}
+
+		cb0->qp_ctl_reg = (cb0->qp_ctl_reg & H_QP_CR_RES_STATE) << 8;
+		cb0->qp_ctl_reg &= ~H_QP_CR_ENABLED;
+
+		hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
+					     EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG,
+							    1), cb0, &dummy64,
+					     &dummy64, &dummy16, &dummy16);
+		if (hret != H_SUCCESS) {
+			ehea_error("modify_ehea_qp failed (1)");
+			goto out;
+		}
+
+		hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+					    EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
+					    cb0);
+		if (hret != H_SUCCESS) {
+			ehea_error("query_ehea_qp failed (2)");
+			goto out;
+		}
+
+		/* deregister shared memory regions */
+		dret = ehea_rem_smrs(pr);
+		if (dret) {
+			ehea_error("unreg shared memory region failed");
+			goto out;
+		}
+	}
+
+	ret = 0;
+out:
+	kfree(cb0);
+
+	return ret;
+}
+
+void ehea_update_rqs(struct ehea_qp *orig_qp, struct ehea_port_res * pr)
+{
+	struct ehea_qp qp = *orig_qp;
+	struct ehea_qp_init_attr *init_attr = &qp.init_attr;
+	struct ehea_rwqe *rwqe;
+	struct sk_buff **skba_rq2 = pr->rq2_skba.arr;
+	struct sk_buff **skba_rq3 = pr->rq3_skba.arr;
+	struct sk_buff *skb;
+	u32 lkey = pr->recv_mr.lkey;
+
+
+	int i;
+	int index;
+
+	for (i = 0; i < init_attr->act_nr_rwqes_rq2 + 1; i++) {
+		rwqe = ehea_get_next_rwqe(&qp, 2);
+		rwqe->sg_list[0].l_key = lkey;
+		index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, rwqe->wr_id);
+		skb = skba_rq2[index];
+		if (skb)
+			rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data);
+	}
+
+	for (i = 0; i < init_attr->act_nr_rwqes_rq3 + 1; i++) {
+		rwqe = ehea_get_next_rwqe(&qp, 3);
+		rwqe->sg_list[0].l_key = lkey;
+		index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, rwqe->wr_id);
+		skb = skba_rq3[index];
+		if (skb)
+			rwqe->sg_list[0].vaddr = ehea_map_vaddr(skb->data);
+	}
+}
+
+int ehea_restart_qps(struct net_device *dev)
+{
+	struct ehea_port *port = netdev_priv(dev);
+	struct ehea_adapter *adapter = port->adapter;
+	int ret = 0;
+	int i;
+
+	struct hcp_modify_qp_cb0* cb0;
+	u64 hret;
+	u64 dummy64 = 0;
+	u16 dummy16 = 0;
+
+	cb0 = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!cb0) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	for (i = 0; i < (port->num_def_qps + port->num_add_tx_qps); i++) {
+		struct ehea_port_res *pr =  &port->port_res[i];
+		struct ehea_qp *qp = pr->qp;
+
+		ret = ehea_gen_smrs(pr);
+		if (ret) {
+			ehea_error("creation of shared memory regions failed");
+			goto out;
+		}
+
+		ehea_update_rqs(qp, pr);
+
+		/* Enable queue pair */
+		hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+					    EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
+					    cb0);
+		if (hret != H_SUCCESS) {
+			ehea_error("query_ehea_qp failed (1)");
+			goto out;
+		}
+
+		cb0->qp_ctl_reg = (cb0->qp_ctl_reg & H_QP_CR_RES_STATE) << 8;
+		cb0->qp_ctl_reg |= H_QP_CR_ENABLED;
+
+		hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
+					     EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG,
+							    1), cb0, &dummy64,
+					     &dummy64, &dummy16, &dummy16);
+		if (hret != H_SUCCESS) {
+			ehea_error("modify_ehea_qp failed (1)");
+			goto out;
+		}
+
+		hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+					    EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF),
+					    cb0);
+		if (hret != H_SUCCESS) {
+			ehea_error("query_ehea_qp failed (2)");
+			goto out;
+		}
+
+		/* refill entire queue */
+		ehea_refill_rq1(pr, pr->rq1_skba.index, 0);
+		ehea_refill_rq2(pr, 0);
+		ehea_refill_rq3(pr, 0);
+	}
+out:
+	kfree(cb0);
+
+	return ret;
+}
+
 static void ehea_reset_port(struct work_struct *work)
 {
 	int ret;
@@ -2310,7 +2597,8 @@
 	port->resets++;
 	down(&port->port_lock);
 	netif_stop_queue(dev);
-	netif_poll_disable(dev);
+
+	port_napi_disable(port);
 
 	ehea_down(dev);
 
@@ -2318,10 +2606,13 @@
 	if (ret)
 		goto out;
 
+	ehea_set_multicast_list(dev);
+
 	if (netif_msg_timer(port))
 		ehea_info("Device %s resetted successfully", dev->name);
 
-	netif_poll_enable(dev);
+	port_napi_enable(port);
+
 	netif_wake_queue(dev);
 out:
 	up(&port->port_lock);
@@ -2333,6 +2624,7 @@
 	int ret, i;
 	struct ehea_adapter *adapter;
 
+	down(&dlpar_mem_lock);
 	ehea_info("LPAR memory enlarged - re-initializing driver");
 
 	list_for_each_entry(adapter, &adapter_list, list)
@@ -2345,12 +2637,14 @@
 					struct net_device *dev = port->netdev;
 
 					if (dev->flags & IFF_UP) {
-						ehea_info("stopping %s",
-							  dev->name);
 						down(&port->port_lock);
 						netif_stop_queue(dev);
-						netif_poll_disable(dev);
-						ehea_down(dev);
+						ret = ehea_stop_qps(dev);
+						if (ret) {
+							up(&port->port_lock);
+							goto out;
+						}
+						port_napi_disable(port);
 						up(&port->port_lock);
 					}
 				}
@@ -2366,10 +2660,11 @@
 		}
 
 	ehea_destroy_busmap();
-
 	ret = ehea_create_busmap();
-	if (ret)
+	if (ret) {
+		ehea_error("creating ehea busmap failed");
 		goto out;
+	}
 
 	clear_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
 
@@ -2391,21 +2686,18 @@
 					struct net_device *dev = port->netdev;
 
 					if (dev->flags & IFF_UP) {
-						ehea_info("restarting %s",
-							  dev->name);
 						down(&port->port_lock);
-
-						ret = ehea_up(dev);
-						if (!ret) {
-							netif_poll_enable(dev);
+						port_napi_enable(port);
+						ret = ehea_restart_qps(dev);
+						if (!ret)
 							netif_wake_queue(dev);
-						}
-
 						up(&port->port_lock);
 					}
 				}
 			}
 		}
+       up(&dlpar_mem_lock);
+       ehea_info("re-initializing driver complete");
 out:
 	return;
 }
@@ -2414,8 +2706,9 @@
 {
 	struct ehea_port *port = netdev_priv(dev);
 
-	if (netif_carrier_ok(dev))
-		queue_work(port->adapter->ehea_wq, &port->reset_task);
+	if (netif_carrier_ok(dev) &&
+	    !test_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
+		schedule_work(&port->reset_task);
 }
 
 int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
@@ -2493,7 +2786,7 @@
 				 struct device_attribute *attr, char *buf)
 {
 	struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev);
-	return sprintf(buf, "0x%X", port->logical_port_id);
+	return sprintf(buf, "%d", port->logical_port_id);
 }
 
 static DEVICE_ATTR(log_port_id, S_IRUSR | S_IRGRP | S_IROTH, ehea_show_port_id,
@@ -2630,13 +2923,12 @@
 	SET_NETDEV_DEV(dev, port_dev);
 
 	/* initialize net_device structure */
-	SET_MODULE_OWNER(dev);
-
 	memcpy(dev->dev_addr, &port->mac_addr, ETH_ALEN);
 
 	dev->open = ehea_open;
-	dev->poll = ehea_poll;
-	dev->weight = 64;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller = ehea_netpoll;
+#endif
 	dev->stop = ehea_stop;
 	dev->hard_start_xmit = ehea_start_xmit;
 	dev->get_stats = ehea_get_stats;
@@ -2655,14 +2947,22 @@
 
 	INIT_WORK(&port->reset_task, ehea_reset_port);
 
+	ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
+	if (ret) {
+		ret = -EIO;
+		goto out_unreg_port;
+	}
+
 	ehea_set_ethtool_ops(dev);
 
 	ret = register_netdev(dev);
 	if (ret) {
 		ehea_error("register_netdev failed. ret=%d", ret);
-		goto out_unreg_port;
+		goto out_dereg_bc;
 	}
 
+	port->lro_max_aggr = lro_max_aggr;
+
 	ret = ehea_get_jumboframe_status(port, &jumbo);
 	if (ret)
 		ehea_error("failed determining jumbo frame status for %s",
@@ -2675,6 +2975,9 @@
 
 	return port;
 
+out_dereg_bc:
+	ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
+
 out_unreg_port:
 	ehea_unregister_port(port);
 
@@ -2694,6 +2997,7 @@
 {
 	unregister_netdev(port->netdev);
 	ehea_unregister_port(port);
+	ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
 	kfree(port->mc_list);
 	free_netdev(port->netdev);
 	port->adapter->active_ports--;
@@ -2771,7 +3075,7 @@
 
 	u32 logical_port_id;
 
-	sscanf(buf, "%X", &logical_port_id);
+	sscanf(buf, "%d", &logical_port_id);
 
 	port = ehea_get_port(adapter, logical_port_id);
 
@@ -2824,7 +3128,7 @@
 	int i;
 	u32 logical_port_id;
 
-	sscanf(buf, "%X", &logical_port_id);
+	sscanf(buf, "%d", &logical_port_id);
 
 	port = ehea_get_port(adapter, logical_port_id);
 
@@ -2937,15 +3241,9 @@
 		goto out_kill_eq;
 	}
 
-	adapter->ehea_wq = create_workqueue("ehea_wq");
-	if (!adapter->ehea_wq) {
-		ret = -EIO;
-		goto out_free_irq;
-	}
-
 	ret = ehea_create_device_sysfs(dev);
 	if (ret)
-		goto out_kill_wq;
+		goto out_free_irq;
 
 	ret = ehea_setup_ports(adapter);
 	if (ret) {
@@ -2959,9 +3257,6 @@
 out_rem_dev_sysfs:
 	ehea_remove_device_sysfs(dev);
 
-out_kill_wq:
-	destroy_workqueue(adapter->ehea_wq);
-
 out_free_irq:
 	ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter);
 
@@ -2987,7 +3282,7 @@
 
 	ehea_remove_device_sysfs(dev);
 
-	destroy_workqueue(adapter->ehea_wq);
+	flush_scheduled_work();
 
 	ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter);
 	tasklet_kill(&adapter->neq_tasklet);
@@ -3045,9 +3340,9 @@
 	printk(KERN_INFO "IBM eHEA ethernet device driver (Release %s)\n",
 	       DRV_VERSION);
 
-	ehea_driver_wq = create_workqueue("ehea_driver_wq");
 
 	INIT_WORK(&ehea_rereg_mr_task, ehea_rereg_mrs);
+	sema_init(&dlpar_mem_lock, 1);
 
 	ret = check_module_parm();
 	if (ret)
@@ -3078,6 +3373,7 @@
 
 static void __exit ehea_module_exit(void)
 {
+	flush_scheduled_work();
 	driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities);
 	ibmebus_unregister_driver(&ehea_driver);
 	ehea_destroy_busmap();
diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h
index 89b6353..faa191d 100644
--- a/drivers/net/ehea/ehea_phyp.h
+++ b/drivers/net/ehea/ehea_phyp.h
@@ -126,6 +126,7 @@
 #define H_QP_CR_STATE_RDY2RCV	    0x0000030000000000ULL /*  Ready to recv */
 #define H_QP_CR_STATE_RDY2SND	    0x0000050000000000ULL /*  Ready to send */
 #define H_QP_CR_STATE_ERROR	    0x0000800000000000ULL /*  Error */
+#define H_QP_CR_RES_STATE 	    0x0000007F00000000ULL /* Resultant state */
 
 struct hcp_modify_qp_cb1 {
 	u32 qpn;		/* 00 */
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
index a36fa6c2..83b7643 100644
--- a/drivers/net/ehea/ehea_qmr.c
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -34,7 +34,6 @@
 
 struct ehea_busmap ehea_bmap = { 0, 0, NULL };
 extern u64 ehea_driver_flags;
-extern struct workqueue_struct *ehea_driver_wq;
 extern struct work_struct ehea_rereg_mr_task;
 
 
@@ -235,6 +234,8 @@
 	if (!cq)
 		return 0;
 
+	hcp_epas_dtor(&cq->epas);
+
 	if ((hret = ehea_destroy_cq_res(cq, NORMAL_FREE)) == H_R_STATE) {
 		ehea_error_data(cq->adapter, cq->fw_handle);
 		hret = ehea_destroy_cq_res(cq, FORCE_FREE);
@@ -361,6 +362,8 @@
 	if (!eq)
 		return 0;
 
+	hcp_epas_dtor(&eq->epas);
+
 	if ((hret = ehea_destroy_eq_res(eq, NORMAL_FREE)) == H_R_STATE) {
 		ehea_error_data(eq->adapter, eq->fw_handle);
 		hret = ehea_destroy_eq_res(eq, FORCE_FREE);
@@ -541,6 +544,8 @@
 	if (!qp)
 		return 0;
 
+	hcp_epas_dtor(&qp->epas);
+
 	if ((hret = ehea_destroy_qp_res(qp, NORMAL_FREE)) == H_R_STATE) {
 		ehea_error_data(qp->adapter, qp->fw_handle);
 		hret = ehea_destroy_qp_res(qp, FORCE_FREE);
@@ -557,8 +562,7 @@
 int ehea_create_busmap( void )
 {
 	u64 vaddr = EHEA_BUSMAP_START;
-	unsigned long abs_max_pfn = 0;
-	unsigned long sec_max_pfn;
+	unsigned long high_section_index = 0;
 	int i;
 
 	/*
@@ -568,14 +572,10 @@
 	ehea_bmap.valid_sections = 0;
 
 	for (i = 0; i < NR_MEM_SECTIONS; i++)
-		if (valid_section_nr(i)) {
-			sec_max_pfn = section_nr_to_pfn(i);
-			if (sec_max_pfn > abs_max_pfn)
-				abs_max_pfn = sec_max_pfn;
-			ehea_bmap.valid_sections++;
-		}
+		if (valid_section_nr(i))
+			high_section_index = i;
 
-	ehea_bmap.entries = abs_max_pfn / EHEA_PAGES_PER_SECTION + 1;
+	ehea_bmap.entries = high_section_index + 1;
 	ehea_bmap.vaddr = vmalloc(ehea_bmap.entries * sizeof(*ehea_bmap.vaddr));
 
 	if (!ehea_bmap.vaddr)
@@ -587,6 +587,7 @@
 		if (pfn_valid(pfn)) {
 			ehea_bmap.vaddr[i] = vaddr;
 			vaddr += EHEA_SECTSIZE;
+			ehea_bmap.valid_sections++;
 		} else
 			ehea_bmap.vaddr[i] = 0;
 	}
@@ -616,7 +617,7 @@
 
 	if (unlikely(mapped_addr == -1))
 		if (!test_and_set_bit(__EHEA_STOP_XFER, &ehea_driver_flags))
-			queue_work(ehea_driver_wq, &ehea_rereg_mr_task);
+			schedule_work(&ehea_rereg_mr_task);
 
 	return mapped_addr;
 }
@@ -631,7 +632,7 @@
 
 	mr_len = ehea_bmap.valid_sections * EHEA_SECTSIZE;
 
-	pt =  kzalloc(EHEA_MAX_RPAGE * sizeof(u64), GFP_KERNEL);
+	pt =  kzalloc(PAGE_SIZE, GFP_KERNEL);
 	if (!pt) {
 		ehea_error("no mem");
 		ret = -ENOMEM;
@@ -654,8 +655,8 @@
 			void *sectbase = __va(i << SECTION_SIZE_BITS);
 			unsigned long k = 0;
 
-			for (j = 0; j < (PAGES_PER_SECTION / EHEA_MAX_RPAGE);
-			      j++) {
+			for (j = 0; j < (EHEA_PAGES_PER_SECTION /
+					 EHEA_MAX_RPAGE); j++) {
 
 				for (m = 0; m < EHEA_MAX_RPAGE; m++) {
 					pg = sectbase + ((k++) * EHEA_PAGESIZE);
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
index b71f845..562de0e 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -39,7 +39,7 @@
 #define EHEA_PAGESHIFT         12
 #define EHEA_PAGESIZE          (1UL << EHEA_PAGESHIFT)
 #define EHEA_SECTSIZE          (1UL << 24)
-#define EHEA_PAGES_PER_SECTION (EHEA_SECTSIZE >> PAGE_SHIFT)
+#define EHEA_PAGES_PER_SECTION (EHEA_SECTSIZE >> EHEA_PAGESHIFT)
 
 #if (1UL << SECTION_SIZE_BITS) < EHEA_SECTSIZE
 #error eHEA module can't work if kernel sectionsize < ehea sectionsize
@@ -145,7 +145,7 @@
 #define EHEA_CQE_VLAN_TAG_XTRACT   0x0400
 
 #define EHEA_CQE_TYPE_RQ           0x60
-#define EHEA_CQE_STAT_ERR_MASK     0x721F
+#define EHEA_CQE_STAT_ERR_MASK     0x720F
 #define EHEA_CQE_STAT_FAT_ERR_MASK 0x1F
 #define EHEA_CQE_STAT_ERR_TCP      0x4000
 #define EHEA_CQE_STAT_ERR_IP       0x2000
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 1197784..ecdd3fc 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -262,6 +262,7 @@
 	/* Ring pointers. */
 	spinlock_t lock;				/* Group with Tx control cache line. */
 	spinlock_t napi_lock;
+	struct napi_struct napi;
 	unsigned int reschedule_in_poll;
 	unsigned int cur_tx, dirty_tx;
 
@@ -294,7 +295,7 @@
 static void epic_init_ring(struct net_device *dev);
 static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static int epic_rx(struct net_device *dev, int budget);
-static int epic_poll(struct net_device *dev, int *budget);
+static int epic_poll(struct napi_struct *napi, int budget);
 static irqreturn_t epic_interrupt(int irq, void *dev_instance);
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static const struct ethtool_ops netdev_ethtool_ops;
@@ -316,6 +317,7 @@
 	int i, ret, option = 0, duplex = 0;
 	void *ring_space;
 	dma_addr_t ring_dma;
+	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -351,7 +353,6 @@
 		dev_err(&pdev->dev, "no memory for eth device\n");
 		goto err_out_free_res;
 	}
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 #ifdef USE_IO_OPS
@@ -487,18 +488,15 @@
 	dev->ethtool_ops = &netdev_ethtool_ops;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	dev->tx_timeout = &epic_tx_timeout;
-	dev->poll = epic_poll;
-	dev->weight = 64;
+	netif_napi_add(dev, &ep->napi, epic_poll, 64);
 
 	ret = register_netdev(dev);
 	if (ret < 0)
 		goto err_out_unmap_rx;
 
-	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ",
-		   dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq);
-	for (i = 0; i < 5; i++)
-		printk("%2.2x:", dev->dev_addr[i]);
-	printk("%2.2x.\n", dev->dev_addr[i]);
+	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %s\n",
+	       dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq,
+	       print_mac(mac, dev->dev_addr));
 
 out:
 	return ret;
@@ -660,8 +658,11 @@
 	/* Soft reset the chip. */
 	outl(0x4001, ioaddr + GENCTL);
 
-	if ((retval = request_irq(dev->irq, &epic_interrupt, IRQF_SHARED, dev->name, dev)))
+	napi_enable(&ep->napi);
+	if ((retval = request_irq(dev->irq, &epic_interrupt, IRQF_SHARED, dev->name, dev))) {
+		napi_disable(&ep->napi);
 		return retval;
+	}
 
 	epic_init_ring(dev);
 
@@ -1103,9 +1104,9 @@
 
 	if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) {
 		spin_lock(&ep->napi_lock);
-		if (netif_rx_schedule_prep(dev)) {
+		if (netif_rx_schedule_prep(dev, &ep->napi)) {
 			epic_napi_irq_off(dev, ep);
-			__netif_rx_schedule(dev);
+			__netif_rx_schedule(dev, &ep->napi);
 		} else
 			ep->reschedule_in_poll++;
 		spin_unlock(&ep->napi_lock);
@@ -1257,26 +1258,22 @@
 		outw(RxQueued, ioaddr + COMMAND);
 }
 
-static int epic_poll(struct net_device *dev, int *budget)
+static int epic_poll(struct napi_struct *napi, int budget)
 {
-	struct epic_private *ep = dev->priv;
-	int work_done = 0, orig_budget;
+	struct epic_private *ep = container_of(napi, struct epic_private, napi);
+	struct net_device *dev = ep->mii.dev;
+	int work_done = 0;
 	long ioaddr = dev->base_addr;
 
-	orig_budget = (*budget > dev->quota) ? dev->quota : *budget;
-
 rx_action:
 
 	epic_tx(dev, ep);
 
-	work_done += epic_rx(dev, *budget);
+	work_done += epic_rx(dev, budget);
 
 	epic_rx_err(dev, ep);
 
-	*budget -= work_done;
-	dev->quota -= work_done;
-
-	if (netif_running(dev) && (work_done < orig_budget)) {
+	if (netif_running(dev) && (work_done < budget)) {
 		unsigned long flags;
 		int more;
 
@@ -1286,7 +1283,7 @@
 
 		more = ep->reschedule_in_poll;
 		if (!more) {
-			__netif_rx_complete(dev);
+			__netif_rx_complete(dev, napi);
 			outl(EpicNapiEvent, ioaddr + INTSTAT);
 			epic_napi_irq_on(dev, ep);
 		} else
@@ -1298,7 +1295,7 @@
 			goto rx_action;
 	}
 
-	return (work_done >= orig_budget);
+	return work_done;
 }
 
 static int epic_close(struct net_device *dev)
@@ -1309,6 +1306,7 @@
 	int i;
 
 	netif_stop_queue(dev);
+	napi_disable(&ep->napi);
 
 	if (debug > 1)
 		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
@@ -1495,8 +1493,6 @@
 	.get_link		= netdev_get_link,
 	.get_msglevel		= netdev_get_msglevel,
 	.set_msglevel		= netdev_set_msglevel,
-	.get_sg			= ethtool_op_get_sg,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
 	.begin			= ethtool_begin,
 	.complete		= ethtool_complete
 };
diff --git a/drivers/net/eql.c b/drivers/net/eql.c
index a93700e..18f1364 100644
--- a/drivers/net/eql.c
+++ b/drivers/net/eql.c
@@ -116,6 +116,7 @@
 #include <linux/init.h>
 #include <linux/timer.h>
 #include <linux/netdevice.h>
+#include <net/net_namespace.h>
 
 #include <linux/if.h>
 #include <linux/if_arp.h>
@@ -127,7 +128,6 @@
 static int eql_close(struct net_device *dev);
 static int eql_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *eql_get_stats(struct net_device *dev);
 
 #define eql_is_slave(dev)	((dev->flags & IFF_SLAVE) == IFF_SLAVE)
 #define eql_is_master(dev)	((dev->flags & IFF_MASTER) == IFF_MASTER)
@@ -166,8 +166,6 @@
 {
 	equalizer_t *eql = netdev_priv(dev);
 
-	SET_MODULE_OWNER(dev);
-
 	init_timer(&eql->timer);
 	eql->timer.data     	= (unsigned long) eql;
 	eql->timer.expires  	= jiffies + EQL_DEFAULT_RESCHED_IVAL;
@@ -181,7 +179,6 @@
 	dev->stop		= eql_close;
 	dev->do_ioctl		= eql_ioctl;
 	dev->hard_start_xmit	= eql_slave_xmit;
-	dev->get_stats		= eql_get_stats;
 
 	/*
 	 *	Now we undo some of the things that eth_setup does
@@ -338,9 +335,9 @@
 		skb->priority = 1;
 		slave->bytes_queued += skb->len;
 		dev_queue_xmit(skb);
-		eql->stats.tx_packets++;
+		dev->stats.tx_packets++;
 	} else {
-		eql->stats.tx_dropped++;
+		dev->stats.tx_dropped++;
 		dev_kfree_skb(skb);
 	}
 
@@ -349,12 +346,6 @@
 	return 0;
 }
 
-static struct net_device_stats * eql_get_stats(struct net_device *dev)
-{
-	equalizer_t *eql = netdev_priv(dev);
-	return &eql->stats;
-}
-
 /*
  *	Private ioctl functions
  */
@@ -391,7 +382,7 @@
 		slave_t *duplicate_slave = NULL;
 
 		duplicate_slave = __eql_find_slave_dev(queue, slave->dev);
-		if (duplicate_slave != 0)
+		if (duplicate_slave)
 			eql_kill_one_slave(queue, duplicate_slave);
 
 		list_add(&slave->list, &queue->all_slaves);
@@ -412,7 +403,7 @@
 	if (copy_from_user(&srq, srqp, sizeof (slaving_request_t)))
 		return -EFAULT;
 
-	slave_dev  = dev_get_by_name(srq.slave_name);
+	slave_dev  = dev_get_by_name(&init_net, srq.slave_name);
 	if (slave_dev) {
 		if ((master_dev->flags & IFF_UP) == IFF_UP) {
 			/* slave is not a master & not already a slave: */
@@ -460,7 +451,7 @@
 	if (copy_from_user(&srq, srqp, sizeof (slaving_request_t)))
 		return -EFAULT;
 
-	slave_dev = dev_get_by_name(srq.slave_name);
+	slave_dev = dev_get_by_name(&init_net, srq.slave_name);
 	ret = -EINVAL;
 	if (slave_dev) {
 		spin_lock_bh(&eql->queue.lock);
@@ -493,7 +484,7 @@
 	if (copy_from_user(&sc, scp, sizeof (slave_config_t)))
 		return -EFAULT;
 
-	slave_dev = dev_get_by_name(sc.slave_name);
+	slave_dev = dev_get_by_name(&init_net, sc.slave_name);
 	if (!slave_dev)
 		return -ENODEV;
 
@@ -528,7 +519,7 @@
 	if (copy_from_user(&sc, scp, sizeof (slave_config_t)))
 		return -EFAULT;
 
-	slave_dev = dev_get_by_name(sc.slave_name);
+	slave_dev = dev_get_by_name(&init_net, sc.slave_name);
 	if (!slave_dev)
 		return -ENODEV;
 
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
index 822e5bf..deefa51 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -130,8 +130,6 @@
 	int irq = dev->irq;
 	int mem_start = dev->mem_start;
 
-	SET_MODULE_OWNER(dev);
-
 	if (ioaddr > 0x1ff)		/* Check a single specified location. */
 		return es_probe1(dev, ioaddr);
 	else if (ioaddr > 0)		/* Don't probe at all. */
@@ -181,6 +179,7 @@
 {
 	int i, retval;
 	unsigned long eisa_id;
+	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT, "es3210"))
 		return -ENODEV;
@@ -192,7 +191,6 @@
 		inb(ioaddr + ES_CFG4), inb(ioaddr + ES_CFG5), inb(ioaddr + ES_CFG6));
 #endif
 
-
 /*	Check the EISA ID of the card. */
 	eisa_id = inl(ioaddr + ES_ID_PORT);
 	if ((eisa_id != ES_EISA_ID1) && (eisa_id != ES_EISA_ID2)) {
@@ -200,21 +198,21 @@
 		goto out;
 	}
 
+	for (i = 0; i < ETHER_ADDR_LEN ; i++)
+		dev->dev_addr[i] = inb(ioaddr + ES_SA_PROM + i);
+
 /*	Check the Racal vendor ID as well. */
-	if (inb(ioaddr + ES_SA_PROM + 0) != ES_ADDR0
-		|| inb(ioaddr + ES_SA_PROM + 1) != ES_ADDR1
-		|| inb(ioaddr + ES_SA_PROM + 2) != ES_ADDR2 ) {
-		printk("es3210.c: card not found");
-		for(i = 0; i < ETHER_ADDR_LEN; i++)
-			printk(" %02x", inb(ioaddr + ES_SA_PROM + i));
-		printk(" (invalid prefix).\n");
+	if (dev->dev_addr[0] != ES_ADDR0 ||
+	    dev->dev_addr[1] != ES_ADDR1 ||
+	    dev->dev_addr[2] != ES_ADDR2) {
+		printk("es3210.c: card not found %s (invalid_prefix).\n",
+		       print_mac(mac, dev->dev_addr));
 		retval = -ENODEV;
 		goto out;
 	}
 
-	printk("es3210.c: ES3210 rev. %ld at %#x, node", eisa_id>>24, ioaddr);
-	for(i = 0; i < ETHER_ADDR_LEN; i++)
-		printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + ES_SA_PROM + i)));
+	printk("es3210.c: ES3210 rev. %ld at %#x, node %s",
+	       eisa_id>>24, ioaddr, print_mac(mac, dev->dev_addr));
 
 	/* Snarf the interrupt now. */
 	if (dev->irq == 0) {
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index 04abf59..243fc6b 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -380,7 +380,6 @@
 /* Information for each board */
 
 struct eth16i_local {
-	struct net_device_stats stats;
 	unsigned char     tx_started;
 	unsigned char     tx_buf_busy;
 	unsigned short    tx_queue;  /* Number of packets in transmit buffer */
@@ -426,8 +425,6 @@
 static ushort  eth16i_parse_mediatype(const char* s);
 #endif
 
-static struct net_device_stats *eth16i_get_stats(struct net_device *dev);
-
 static char cardname[] __initdata = "ICL EtherTeam 16i/32";
 
 static int __init do_eth16i_probe(struct net_device *dev)
@@ -436,8 +433,6 @@
 	int ioaddr;
 	int base_addr = dev->base_addr;
 
-	SET_MODULE_OWNER(dev);
-
 	if(eth16i_debug > 4)
 		printk(KERN_DEBUG "Probing started for %s\n", cardname);
 
@@ -559,7 +554,6 @@
 	dev->open               = eth16i_open;
 	dev->stop               = eth16i_close;
 	dev->hard_start_xmit    = eth16i_tx;
-	dev->get_stats          = eth16i_get_stats;
 	dev->set_multicast_list = eth16i_multicast;
 	dev->tx_timeout 	= eth16i_timeout;
 	dev->watchdog_timeo	= TX_TIMEOUT;
@@ -1047,7 +1041,7 @@
 		printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);
 		printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);
 	}
-	lp->stats.tx_errors++;
+	dev->stats.tx_errors++;
 	eth16i_reset(dev);
 	dev->trans_start = jiffies;
 	outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
@@ -1132,7 +1126,6 @@
 
 static void eth16i_rx(struct net_device *dev)
 {
-	struct eth16i_local *lp = netdev_priv(dev);
 	int ioaddr = dev->base_addr;
 	int boguscount = MAX_RX_LOOP;
 
@@ -1151,16 +1144,16 @@
 			       inb(ioaddr + RECEIVE_MODE_REG), status);
 
 		if( !(status & PKT_GOOD) ) {
-			lp->stats.rx_errors++;
+			dev->stats.rx_errors++;
 
 			if( (pkt_len < ETH_ZLEN) || (pkt_len > ETH_FRAME_LEN) ) {
-				lp->stats.rx_length_errors++;
+				dev->stats.rx_length_errors++;
 				eth16i_reset(dev);
 				return;
 			}
 			else {
 				eth16i_skip_packet(dev);
-				lp->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 			}
 		}
 		else {   /* Ok so now we should have a good packet */
@@ -1171,7 +1164,7 @@
 				printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n",
 				       dev->name, pkt_len);
 				eth16i_skip_packet(dev);
-				lp->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 				break;
 			}
 
@@ -1214,8 +1207,8 @@
 			}
 			netif_rx(skb);
 			dev->last_rx = jiffies;
-			lp->stats.rx_packets++;
-			lp->stats.rx_bytes += pkt_len;
+			dev->stats.rx_packets++;
+			dev->stats.rx_bytes += pkt_len;
 
 		} /* else */
 
@@ -1252,32 +1245,32 @@
 
 	if( status & 0x7f00 ) {
 
-		lp->stats.rx_errors++;
+		dev->stats.rx_errors++;
 
 		if(status & (BUS_RD_ERR << 8) )
 			printk(KERN_WARNING "%s: Bus read error.\n",dev->name);
-		if(status & (SHORT_PKT_ERR << 8) )   lp->stats.rx_length_errors++;
-		if(status & (ALIGN_ERR << 8) )       lp->stats.rx_frame_errors++;
-		if(status & (CRC_ERR << 8) )	    lp->stats.rx_crc_errors++;
-		if(status & (RX_BUF_OVERFLOW << 8) ) lp->stats.rx_over_errors++;
+		if(status & (SHORT_PKT_ERR << 8) )   dev->stats.rx_length_errors++;
+		if(status & (ALIGN_ERR << 8) )       dev->stats.rx_frame_errors++;
+		if(status & (CRC_ERR << 8) )	    dev->stats.rx_crc_errors++;
+		if(status & (RX_BUF_OVERFLOW << 8) ) dev->stats.rx_over_errors++;
 	}
 	if( status & 0x001a) {
 
-		lp->stats.tx_errors++;
+		dev->stats.tx_errors++;
 
-		if(status & CR_LOST) lp->stats.tx_carrier_errors++;
-		if(status & TX_JABBER_ERR) lp->stats.tx_window_errors++;
+		if(status & CR_LOST) dev->stats.tx_carrier_errors++;
+		if(status & TX_JABBER_ERR) dev->stats.tx_window_errors++;
 
 #if 0
 		if(status & COLLISION) {
-			lp->stats.collisions +=
+			dev->stats.collisions +=
 				((inb(ioaddr+TRANSMIT_MODE_REG) & 0xF0) >> 4);
 		}
 #endif
 		if(status & COLLISIONS_16) {
 			if(lp->col_16 < MAX_COL_16) {
 				lp->col_16++;
-				lp->stats.collisions++;
+				dev->stats.collisions++;
 				/* Resume transmitting, skip failed packet */
 				outb(0x02, ioaddr + COL_16_REG);
 			}
@@ -1290,8 +1283,8 @@
 	if( status & 0x00ff ) {          /* Let's check the transmit status reg */
 
 		if(status & TX_DONE) {         /* The transmit has been done */
-			lp->stats.tx_packets = lp->tx_buffered_packets;
-			lp->stats.tx_bytes += lp->tx_buffered_bytes;
+			dev->stats.tx_packets = lp->tx_buffered_packets;
+			dev->stats.tx_bytes += lp->tx_buffered_bytes;
 			lp->col_16 = 0;
 
 			if(lp->tx_queue) {           /* Is there still packets ? */
@@ -1371,12 +1364,6 @@
 	}
 }
 
-static struct net_device_stats *eth16i_get_stats(struct net_device *dev)
-{
-	struct eth16i_local *lp = netdev_priv(dev);
-	return &lp->stats;
-}
-
 static void eth16i_select_regbank(unsigned char banknbr, int ioaddr)
 {
 	unsigned char data;
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index cb0792c..593a120 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -275,7 +275,6 @@
 	u_long shmem_base;	/* Shared memory start address */
 	void __iomem *shmem;
 	u_long shmem_length;	/* Shared memory window length */
-	struct net_device_stats stats;	/* Public stats */
 	struct ewrk3_stats pktStats; /* Private stats counters */
 	u_char irq_mask;	/* Adapter IRQ mask bits */
 	u_char mPage;		/* Maximum 2kB Page number */
@@ -302,7 +301,6 @@
 static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t ewrk3_interrupt(int irq, void *dev_id);
 static int ewrk3_close(struct net_device *dev);
-static struct net_device_stats *ewrk3_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
 static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static const struct ethtool_ops ethtool_ops_203;
@@ -356,7 +354,6 @@
 		sprintf(dev->name, "eth%d", unit);
 		netdev_boot_setup_check(dev);
 	}
-	SET_MODULE_OWNER(dev);
 
 	err = ewrk3_probe1(dev, dev->base_addr, dev->irq);
 	if (err)
@@ -399,6 +396,7 @@
 	u_long mem_start, shmem_length;
 	u_char cr, cmr, icr, nicsr, lemac, hard_strapped = 0;
 	u_char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0;
+	DECLARE_MAC_BUF(mac);
 
 	/*
 	** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot.
@@ -463,10 +461,7 @@
 	if (lemac != LeMAC2)
 		DevicePresent(iobase);	/* need after EWRK3_INIT */
 	status = get_hw_addr(dev, eeprom_image, lemac);
-	for (i = 0; i < ETH_ALEN - 1; i++) {	/* get the ethernet addr. */
-		printk("%2.2x:", dev->dev_addr[i]);
-	}
-	printk("%2.2x,\n", dev->dev_addr[i]);
+	printk("%s\n", print_mac(mac, dev->dev_addr));
 
 	if (status) {
 		printk("      which has an EEPROM CRC error.\n");
@@ -612,7 +607,6 @@
 	dev->open = ewrk3_open;
 	dev->hard_start_xmit = ewrk3_queue_pkt;
 	dev->stop = ewrk3_close;
-	dev->get_stats = ewrk3_get_stats;
 	dev->set_multicast_list = set_multicast_list;
 	dev->do_ioctl = ewrk3_ioctl;
 	if (lp->adapter_name[4] == '3')
@@ -632,7 +626,7 @@
 {
 	struct ewrk3_private *lp = netdev_priv(dev);
 	u_long iobase = dev->base_addr;
-	int i, status = 0;
+	int status = 0;
 	u_char icr, csr;
 
 	/*
@@ -652,12 +646,10 @@
 			ewrk3_init(dev);
 
 			if (ewrk3_debug > 1) {
+				DECLARE_MAC_BUF(mac);
 				printk("%s: ewrk3 open with irq %d\n", dev->name, dev->irq);
-				printk("  physical address: ");
-				for (i = 0; i < 5; i++) {
-					printk("%2.2x:", (u_char) dev->dev_addr[i]);
-				}
-				printk("%2.2x\n", (u_char) dev->dev_addr[i]);
+				printk("  physical address: %s\n",
+				       print_mac(mac, dev->dev_addr));
 				if (lp->shmem_length == 0) {
 					printk("  no shared memory, I/O only mode\n");
 				} else {
@@ -864,7 +856,7 @@
 	ENABLE_IRQs;
 	spin_unlock_irq (&lp->hw_lock);
 
-	lp->stats.tx_bytes += skb->len;
+	dev->stats.tx_bytes += skb->len;
 	dev->trans_start = jiffies;
 	dev_kfree_skb (skb);
 
@@ -981,13 +973,13 @@
 				}
 
 				if (!(rx_status & R_ROK)) {	/* There was an error. */
-					lp->stats.rx_errors++;	/* Update the error stats. */
+					dev->stats.rx_errors++;	/* Update the error stats. */
 					if (rx_status & R_DBE)
-						lp->stats.rx_frame_errors++;
+						dev->stats.rx_frame_errors++;
 					if (rx_status & R_CRC)
-						lp->stats.rx_crc_errors++;
+						dev->stats.rx_crc_errors++;
 					if (rx_status & R_PLL)
-						lp->stats.rx_fifo_errors++;
+						dev->stats.rx_fifo_errors++;
 				} else {
 					struct sk_buff *skb;
 
@@ -1038,11 +1030,11 @@
 						   ** Update stats
 						 */
 						dev->last_rx = jiffies;
-						lp->stats.rx_packets++;
-						lp->stats.rx_bytes += pkt_len;
+						dev->stats.rx_packets++;
+						dev->stats.rx_bytes += pkt_len;
 					} else {
 						printk("%s: Insufficient memory; nuking packet.\n", dev->name);
-						lp->stats.rx_dropped++;		/* Really, deferred. */
+						dev->stats.rx_dropped++;		/* Really, deferred. */
 						break;
 					}
 				}
@@ -1072,11 +1064,11 @@
 	while ((tx_status = inb(EWRK3_TDQ)) > 0) {	/* Whilst there's old buffers */
 		if (tx_status & T_VSTS) {	/* The status is valid */
 			if (tx_status & T_TXE) {
-				lp->stats.tx_errors++;
+				dev->stats.tx_errors++;
 				if (tx_status & T_NCL)
-					lp->stats.tx_carrier_errors++;
+					dev->stats.tx_carrier_errors++;
 				if (tx_status & T_LCL)
-					lp->stats.tx_window_errors++;
+					dev->stats.tx_window_errors++;
 				if (tx_status & T_CTU) {
 					if ((tx_status & T_COLL) ^ T_XUR) {
 						lp->pktStats.tx_underruns++;
@@ -1085,13 +1077,13 @@
 					}
 				} else if (tx_status & T_COLL) {
 					if ((tx_status & T_COLL) ^ T_XCOLL) {
-						lp->stats.collisions++;
+						dev->stats.collisions++;
 					} else {
 						lp->pktStats.excessive_collisions++;
 					}
 				}
 			} else {
-				lp->stats.tx_packets++;
+				dev->stats.tx_packets++;
 			}
 		}
 	}
@@ -1134,14 +1126,6 @@
 	return 0;
 }
 
-static struct net_device_stats *ewrk3_get_stats(struct net_device *dev)
-{
-	struct ewrk3_private *lp = netdev_priv(dev);
-
-	/* Null body since there is no framing error counter */
-	return &lp->stats;
-}
-
 /*
    ** Set or clear the multicast filter for this adapter.
  */
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index ff9f177..43f7647 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -486,6 +486,7 @@
 #else
 	int bar = 1;
 #endif
+	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -527,7 +528,6 @@
 		err = -ENOMEM;
 		goto err_out_unmap;
 	}
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	/* read ethernet id */
@@ -665,11 +665,9 @@
 	if (err)
 		goto err_out_free_tx;
 
-	printk(KERN_INFO "%s: %s at %p, ",
-	       dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr);
-	for (i = 0; i < 5; i++)
-		printk("%2.2x:", dev->dev_addr[i]);
-	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+	printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",
+	       dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr,
+	       print_mac(mac, dev->dev_addr), irq);
 
 	return 0;
 
@@ -1892,8 +1890,6 @@
 	.get_link		= netdev_get_link,
 	.get_msglevel		= netdev_get_msglevel,
 	.set_msglevel		= netdev_set_msglevel,
-	.get_sg			= ethtool_op_get_sg,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
 };
 
 static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 03023dd..2b57820 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -47,6 +47,7 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
+#include <asm/cacheflush.h>
 
 #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \
     defined(CONFIG_M5272) || defined(CONFIG_M528x) || \
@@ -98,8 +99,6 @@
 #define	FEC_FLASHMAC	0xf0006006
 #elif defined(CONFIG_GILBARCONAP) || defined(CONFIG_SCALES)
 #define	FEC_FLASHMAC	0xf0006000
-#elif defined (CONFIG_MTD_KeyTechnology)
-#define	FEC_FLASHMAC	0xffe04000
 #elif defined(CONFIG_CANCam)
 #define	FEC_FLASHMAC	0xf0020000
 #elif defined (CONFIG_M5272C3)
@@ -191,6 +190,8 @@
 	/* Hardware registers of the FEC device */
 	volatile fec_t	*hwp;
 
+	struct net_device *netdev;
+
 	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
 	unsigned char *tx_bounce[TX_RING_SIZE];
 	struct	sk_buff* tx_skbuff[TX_RING_SIZE];
@@ -203,7 +204,6 @@
 	cbd_t	*tx_bd_base;
 	cbd_t	*cur_rx, *cur_tx;		/* The next free ring entry */
 	cbd_t	*dirty_tx;	/* The ring entries to be free()ed. */
-	struct	net_device_stats stats;
 	uint	tx_full;
 	spinlock_t lock;
 
@@ -233,7 +233,6 @@
 static void fec_enet_tx(struct net_device *dev);
 static void fec_enet_rx(struct net_device *dev);
 static int fec_enet_close(struct net_device *dev);
-static struct net_device_stats *fec_enet_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
 static void fec_restart(struct net_device *dev, int duplex);
 static void fec_stop(struct net_device *dev);
@@ -358,7 +357,7 @@
 	*/
 	fep->tx_skbuff[fep->skb_cur] = skb;
 
-	fep->stats.tx_bytes += skb->len;
+	dev->stats.tx_bytes += skb->len;
 	fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK;
 
 	/* Push the data cache so the CPM does not get stale memory
@@ -408,7 +407,7 @@
 	struct fec_enet_private *fep = netdev_priv(dev);
 
 	printk("%s: transmit timed out.\n", dev->name);
-	fep->stats.tx_errors++;
+	dev->stats.tx_errors++;
 #ifndef final_version
 	{
 	int	i;
@@ -510,19 +509,19 @@
 		if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
 				   BD_ENET_TX_RL | BD_ENET_TX_UN |
 				   BD_ENET_TX_CSL)) {
-			fep->stats.tx_errors++;
+			dev->stats.tx_errors++;
 			if (status & BD_ENET_TX_HB)  /* No heartbeat */
-				fep->stats.tx_heartbeat_errors++;
+				dev->stats.tx_heartbeat_errors++;
 			if (status & BD_ENET_TX_LC)  /* Late collision */
-				fep->stats.tx_window_errors++;
+				dev->stats.tx_window_errors++;
 			if (status & BD_ENET_TX_RL)  /* Retrans limit */
-				fep->stats.tx_aborted_errors++;
+				dev->stats.tx_aborted_errors++;
 			if (status & BD_ENET_TX_UN)  /* Underrun */
-				fep->stats.tx_fifo_errors++;
+				dev->stats.tx_fifo_errors++;
 			if (status & BD_ENET_TX_CSL) /* Carrier lost */
-				fep->stats.tx_carrier_errors++;
+				dev->stats.tx_carrier_errors++;
 		} else {
-			fep->stats.tx_packets++;
+			dev->stats.tx_packets++;
 		}
 
 #ifndef final_version
@@ -533,7 +532,7 @@
 		 * but we eventually sent the packet OK.
 		 */
 		if (status & BD_ENET_TX_DEF)
-			fep->stats.collisions++;
+			dev->stats.collisions++;
 
 		/* Free the sk buffer associated with this last transmit.
 		 */
@@ -606,17 +605,17 @@
 	/* Check for errors. */
 	if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
 			   BD_ENET_RX_CR | BD_ENET_RX_OV)) {
-		fep->stats.rx_errors++;
+		dev->stats.rx_errors++;
 		if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
 		/* Frame too long or too short. */
-			fep->stats.rx_length_errors++;
+			dev->stats.rx_length_errors++;
 		}
 		if (status & BD_ENET_RX_NO)	/* Frame alignment */
-			fep->stats.rx_frame_errors++;
+			dev->stats.rx_frame_errors++;
 		if (status & BD_ENET_RX_CR)	/* CRC Error */
-			fep->stats.rx_crc_errors++;
+			dev->stats.rx_crc_errors++;
 		if (status & BD_ENET_RX_OV)	/* FIFO overrun */
-			fep->stats.rx_fifo_errors++;
+			dev->stats.rx_fifo_errors++;
 	}
 
 	/* Report late collisions as a frame error.
@@ -624,16 +623,16 @@
 	 * have in the buffer.  So, just drop this frame on the floor.
 	 */
 	if (status & BD_ENET_RX_CL) {
-		fep->stats.rx_errors++;
-		fep->stats.rx_frame_errors++;
+		dev->stats.rx_errors++;
+		dev->stats.rx_frame_errors++;
 		goto rx_processing_done;
 	}
 
 	/* Process the incoming frame.
 	 */
-	fep->stats.rx_packets++;
+	dev->stats.rx_packets++;
 	pkt_len = bdp->cbd_datlen;
-	fep->stats.rx_bytes += pkt_len;
+	dev->stats.rx_bytes += pkt_len;
 	data = (__u8*)__va(bdp->cbd_bufaddr);
 
 	/* This does 16 byte alignment, exactly what we need.
@@ -645,7 +644,7 @@
 
 	if (skb == NULL) {
 		printk("%s: Memory squeeze, dropping packet.\n", dev->name);
-		fep->stats.rx_dropped++;
+		dev->stats.rx_dropped++;
 	} else {
 		skb_put(skb,pkt_len-4);	/* Make room */
 		skb_copy_to_linear_data(skb, data, pkt_len-4);
@@ -1269,7 +1268,7 @@
 	icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR3);
 	*icrp = 0x00000ddd;
 	icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
-	*icrp = (*icrp & 0x70777777) | 0x0d000000;
+	*icrp = 0x0d000000;
 }
 
 static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
@@ -1331,7 +1330,7 @@
 {
 	volatile unsigned long *icrp;
 	icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
-	*icrp = (*icrp & 0x70777777) | 0x08000000;
+	*icrp = 0x08000000;
 }
 
 static void __inline__ fec_phy_ack_intr(void)
@@ -1339,7 +1338,7 @@
 	volatile unsigned long *icrp;
 	/* Acknowledge the interrupt */
 	icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
-	*icrp = (*icrp & 0x77777777) | 0x08000000;
+	*icrp = 0x0d000000;
 }
 
 static void __inline__ fec_localhw_setup(void)
@@ -1426,6 +1425,29 @@
 		*gpio_pehlpar = 0xc0;
 	}
 #endif
+
+#if defined(CONFIG_M527x)
+	/* Set up gpio outputs for MII lines */
+	{
+		volatile u8 *gpio_par_fec;
+		volatile u16 *gpio_par_feci2c;
+
+		gpio_par_feci2c = (volatile u16 *)(MCF_IPSBAR + 0x100082);
+		/* Set up gpio outputs for FEC0 MII lines */
+		gpio_par_fec = (volatile u8 *)(MCF_IPSBAR + 0x100078);
+
+		*gpio_par_feci2c |= 0x0f00;
+		*gpio_par_fec |= 0xc0;
+
+#if defined(CONFIG_FEC2)
+		/* Set up gpio outputs for FEC1 MII lines */
+		gpio_par_fec = (volatile u8 *)(MCF_IPSBAR + 0x100079);
+
+		*gpio_par_feci2c |= 0x00a0;
+		*gpio_par_fec |= 0xc0;
+#endif /* CONFIG_FEC2 */
+	}
+#endif /* CONFIG_M527x */
 }
 
 static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
@@ -1940,9 +1962,10 @@
 	printk(".\n");
 }
 
-static void mii_display_config(struct net_device *dev)
+static void mii_display_config(struct work_struct *work)
 {
-	struct fec_enet_private *fep = netdev_priv(dev);
+	struct fec_enet_private *fep = container_of(work, struct fec_enet_private, phy_task);
+	struct net_device *dev = fep->netdev;
 	uint status = fep->phy_status;
 
 	/*
@@ -1976,9 +1999,10 @@
 	fep->sequence_done = 1;
 }
 
-static void mii_relink(struct net_device *dev)
+static void mii_relink(struct work_struct *work)
 {
-	struct fec_enet_private *fep = netdev_priv(dev);
+	struct fec_enet_private *fep = container_of(work, struct fec_enet_private, phy_task);
+	struct net_device *dev = fep->netdev;
 	int duplex;
 
 	/*
@@ -2022,7 +2046,7 @@
 		return;
 
 	fep->mii_phy_task_queued = 1;
-	INIT_WORK(&fep->phy_task, (void*)mii_relink, dev);
+	INIT_WORK(&fep->phy_task, mii_relink);
 	schedule_work(&fep->phy_task);
 }
 
@@ -2035,7 +2059,7 @@
 		return;
 
 	fep->mii_phy_task_queued = 1;
-	INIT_WORK(&fep->phy_task, (void*)mii_display_config, dev);
+	INIT_WORK(&fep->phy_task, mii_display_config);
 	schedule_work(&fep->phy_task);
 }
 
@@ -2194,13 +2218,6 @@
 	return 0;
 }
 
-static struct net_device_stats *fec_enet_get_stats(struct net_device *dev)
-{
-	struct fec_enet_private *fep = netdev_priv(dev);
-
-	return &fep->stats;
-}
-
 /* Set or clear the multicast filter for this adaptor.
  * Skeleton taken from sunlance driver.
  * The CPM Ethernet implementation allows Multicast as well as individual
@@ -2330,6 +2347,7 @@
 
 	fep->index = index;
 	fep->hwp = fecp;
+	fep->netdev = dev;
 
 	/* Whack a reset.  We should wait for this.
 	*/
@@ -2435,7 +2453,6 @@
 	dev->tx_timeout = fec_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 	dev->stop = fec_enet_close;
-	dev->get_stats = fec_enet_get_stats;
 	dev->set_multicast_list = set_multicast_list;
 
 	for (i=0; i<NMII-1; i++)
@@ -2618,6 +2635,7 @@
 {
 	struct net_device *dev;
 	int i, j, err;
+	DECLARE_MAC_BUF(mac);
 
 	printk("FEC ENET Version 0.2\n");
 
@@ -2636,10 +2654,8 @@
 			return -EIO;
 		}
 
-		printk("%s: ethernet ", dev->name);
-		for (j = 0; (j < 5); j++)
-			printk("%02x:", dev->dev_addr[j]);
-		printk("%02x\n", dev->dev_addr[5]);
+		printk("%s: ethernet %s\n",
+		       dev->name, print_mac(mac, dev->dev_addr));
 	}
 	return 0;
 }
diff --git a/drivers/net/fec_8xx/fec_8xx.h b/drivers/net/fec_8xx/fec_8xx.h
index 5af60b0..f3b1c6f 100644
--- a/drivers/net/fec_8xx/fec_8xx.h
+++ b/drivers/net/fec_8xx/fec_8xx.h
@@ -105,6 +105,8 @@
 struct fec_enet_private {
 	spinlock_t lock;	/* during all ops except TX pckt processing */
 	spinlock_t tx_lock;	/* during fec_start_xmit and fec_tx         */
+	struct net_device *dev;
+	struct napi_struct napi;
 	int fecno;
 	struct fec *fecp;
 	const struct fec_platform_info *fpi;
diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c
index e5502af..8d2904f 100644
--- a/drivers/net/fec_8xx/fec_main.c
+++ b/drivers/net/fec_8xx/fec_main.c
@@ -465,9 +465,9 @@
 }
 
 /* common receive function */
-static int fec_enet_rx_common(struct net_device *dev, int *budget)
+static int fec_enet_rx_common(struct fec_enet_private *ep,
+			      struct net_device *dev, int budget)
 {
-	struct fec_enet_private *fep = netdev_priv(dev);
 	fec_t *fecp = fep->fecp;
 	const struct fec_platform_info *fpi = fep->fpi;
 	cbd_t *bdp;
@@ -475,11 +475,8 @@
 	int received = 0;
 	__u16 pkt_len, sc;
 	int curidx;
-	int rx_work_limit;
 
 	if (fpi->use_napi) {
-		rx_work_limit = min(dev->quota, *budget);
-
 		if (!netif_running(dev))
 			return 0;
 	}
@@ -530,11 +527,6 @@
 			BUG_ON(skbn == NULL);
 
 		} else {
-
-			/* napi, got packet but no quota */
-			if (fpi->use_napi && --rx_work_limit < 0)
-				break;
-
 			skb = fep->rx_skbuff[curidx];
 			BUG_ON(skb == NULL);
 
@@ -599,25 +591,24 @@
 		 * able to keep up at the expense of system resources.
 		 */
 		FW(fecp, r_des_active, 0x01000000);
+
+		if (received >= budget)
+			break;
+
 	}
 
 	fep->cur_rx = bdp;
 
 	if (fpi->use_napi) {
-		dev->quota -= received;
-		*budget -= received;
+		if (received < budget) {
+			netif_rx_complete(dev, &fep->napi);
 
-		if (rx_work_limit < 0)
-			return 1;	/* not done */
-
-		/* done */
-		netif_rx_complete(dev);
-
-		/* enable RX interrupt bits */
-		FS(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB);
+			/* enable RX interrupt bits */
+			FS(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB);
+		}
 	}
 
-	return 0;
+	return received;
 }
 
 static void fec_enet_tx(struct net_device *dev)
@@ -743,12 +734,12 @@
 
 		if ((int_events & FEC_ENET_RXF) != 0) {
 			if (!fpi->use_napi)
-				fec_enet_rx_common(dev, NULL);
+				fec_enet_rx_common(fep, dev, ~0);
 			else {
-				if (netif_rx_schedule_prep(dev)) {
+				if (netif_rx_schedule_prep(dev, &fep->napi)) {
 					/* disable rx interrupts */
 					FC(fecp, imask, FEC_ENET_RXF | FEC_ENET_RXB);
-					__netif_rx_schedule(dev);
+					__netif_rx_schedule(dev, &fep->napi);
 				} else {
 					printk(KERN_ERR DRV_MODULE_NAME
 					       ": %s driver bug! interrupt while in poll!\n",
@@ -893,10 +884,13 @@
 	const struct fec_platform_info *fpi = fep->fpi;
 	unsigned long flags;
 
+	napi_enable(&fep->napi);
+
 	/* Install our interrupt handler. */
 	if (request_irq(fpi->fec_irq, fec_enet_interrupt, 0, "fec", dev) != 0) {
 		printk(KERN_ERR DRV_MODULE_NAME
 		       ": %s Could not allocate FEC IRQ!", dev->name);
+		napi_disable(&fep->napi);
 		return -EINVAL;
 	}
 
@@ -907,6 +901,7 @@
 		printk(KERN_ERR DRV_MODULE_NAME
 		       ": %s Could not allocate PHY IRQ!", dev->name);
 		free_irq(fpi->fec_irq, dev);
+		napi_disable(&fep->napi);
 		return -EINVAL;
 	}
 
@@ -932,6 +927,7 @@
 	unsigned long flags;
 
 	netif_stop_queue(dev);
+	napi_disable(&fep->napi);
 	netif_carrier_off(dev);
 
 	if (fpi->use_mdio)
@@ -955,9 +951,12 @@
 	return &fep->stats;
 }
 
-static int fec_enet_poll(struct net_device *dev, int *budget)
+static int fec_enet_poll(struct napi_struct *napi, int budget)
 {
-	return fec_enet_rx_common(dev, budget);
+	struct fec_enet_private *fep = container_of(napi, struct fec_enet_private, napi);
+	struct net_device *dev = fep->dev;
+
+	return fec_enet_rx_common(fep, dev, budget);
 }
 
 /*************************************************************************/
@@ -1042,9 +1041,7 @@
 	.get_link	= ethtool_op_get_link,
 	.get_msglevel	= fec_get_msglevel,
 	.set_msglevel	= fec_set_msglevel,
-	.get_tx_csum	= ethtool_op_get_tx_csum,
 	.set_tx_csum	= ethtool_op_set_tx_csum,	/* local! */
-	.get_sg		= ethtool_op_get_sg,
 	.set_sg		= ethtool_op_set_sg,
 	.get_regs	= fec_get_regs,
 };
@@ -1104,9 +1101,9 @@
 		err = -ENOMEM;
 		goto err;
 	}
-	SET_MODULE_OWNER(dev);
 
 	fep = netdev_priv(dev);
+	fep->dev = dev;
 
 	/* partial reset of FEC */
 	fec_whack_reset(fecp);
@@ -1172,10 +1169,9 @@
 	dev->get_stats = fec_enet_get_stats;
 	dev->set_multicast_list = fec_set_multicast_list;
 	dev->set_mac_address = fec_set_mac_address;
-	if (fpi->use_napi) {
-		dev->poll = fec_enet_poll;
-		dev->weight = fpi->napi_weight;
-	}
+	netif_napi_add(dev, &fec->napi,
+		       fec_enet_poll, fpi->napi_weight);
+
 	dev->ethtool_ops = &fec_ethtool_ops;
 	dev->do_ioctl = fec_ioctl;
 
diff --git a/drivers/net/fec_8xx/fec_mii.c b/drivers/net/fec_8xx/fec_mii.c
index b3fa0d6..e8e10a0 100644
--- a/drivers/net/fec_8xx/fec_mii.c
+++ b/drivers/net/fec_8xx/fec_mii.c
@@ -308,12 +308,11 @@
 		return -1;
 	}
 
-	for (i = 0, phy = phy_info; i < sizeof(phy_info) / sizeof(phy_info[0]);
-	     i++, phy++)
+	for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++)
 		if (phy->id == (phy_hwid >> 4) || phy->id == 0)
 			break;
 
-	if (i >= sizeof(phy_info) / sizeof(phy_info[0])) {
+	if (i >= ARRAY_SIZE(phy_info)) {
 		printk(KERN_ERR DRV_MODULE_NAME
 		       ": %s PHY id 0x%08x is not supported!\n",
 		       dev->name, phy_hwid);
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 136827f..dae30b7 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -159,6 +159,8 @@
 #define dprintk(x...)		do { } while (0)
 #endif
 
+#define TX_WORK_PER_LOOP  64
+#define RX_WORK_PER_LOOP  64
 
 /*
  * Hardware access:
@@ -178,6 +180,7 @@
 #define DEV_HAS_STATISTICS_V2   0x0800  /* device supports hw statistics version 2 */
 #define DEV_HAS_TEST_EXTENDED   0x1000  /* device supports extended diagnostic test */
 #define DEV_HAS_MGMT_UNIT       0x2000  /* device supports management unit */
+#define DEV_HAS_CORRECT_MACADDR 0x4000  /* device supports correct mac address order */
 
 enum {
 	NvRegIrqStatus = 0x000,
@@ -551,7 +554,7 @@
 #define PHY_OUI_MARVELL	0x5043
 #define PHY_OUI_CICADA	0x03f1
 #define PHY_OUI_VITESSE	0x01c1
-#define PHY_OUI_REALTEK	0x01c1
+#define PHY_OUI_REALTEK	0x0732
 #define PHYID1_OUI_MASK	0x03ff
 #define PHYID1_OUI_SHFT	6
 #define PHYID2_OUI_MASK	0xfc00
@@ -744,6 +747,9 @@
 struct fe_priv {
 	spinlock_t lock;
 
+	struct net_device *dev;
+	struct napi_struct napi;
+
 	/* General data:
 	 * Locking: spin_lock(&np->lock); */
 	struct net_device_stats stats;
@@ -1585,9 +1591,10 @@
 static void nv_do_rx_refill(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *) data;
+	struct fe_priv *np = netdev_priv(dev);
 
 	/* Just reschedule NAPI rx processing */
-	netif_rx_schedule(dev);
+	netif_rx_schedule(dev, &np->napi);
 }
 #else
 static void nv_do_rx_refill(unsigned long data)
@@ -2996,7 +3003,7 @@
 
 #ifdef CONFIG_FORCEDETH_NAPI
 		if (events & NVREG_IRQ_RX_ALL) {
-			netif_rx_schedule(dev);
+			netif_rx_schedule(dev, &np->napi);
 
 			/* Disable furthur receive irq's */
 			spin_lock(&np->lock);
@@ -3009,7 +3016,7 @@
 			spin_unlock(&np->lock);
 		}
 #else
-		if (nv_rx_process(dev, dev->weight)) {
+		if (nv_rx_process(dev, RX_WORK_PER_LOOP)) {
 			if (unlikely(nv_alloc_rx(dev))) {
 				spin_lock(&np->lock);
 				if (!np->in_shutdown)
@@ -3067,8 +3074,8 @@
 				np->nic_poll_irq = np->irqmask;
 				mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
 			}
-			printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
 			spin_unlock(&np->lock);
+			printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
 			break;
 		}
 
@@ -3078,8 +3085,6 @@
 	return IRQ_RETVAL(i);
 }
 
-#define TX_WORK_PER_LOOP  64
-#define RX_WORK_PER_LOOP  64
 /**
  * All _optimized functions are used to help increase performance
  * (reduce CPU and increase throughput). They use descripter version 3,
@@ -3113,7 +3118,7 @@
 
 #ifdef CONFIG_FORCEDETH_NAPI
 		if (events & NVREG_IRQ_RX_ALL) {
-			netif_rx_schedule(dev);
+			netif_rx_schedule(dev, &np->napi);
 
 			/* Disable furthur receive irq's */
 			spin_lock(&np->lock);
@@ -3126,7 +3131,7 @@
 			spin_unlock(&np->lock);
 		}
 #else
-		if (nv_rx_process_optimized(dev, dev->weight)) {
+		if (nv_rx_process_optimized(dev, RX_WORK_PER_LOOP)) {
 			if (unlikely(nv_alloc_rx_optimized(dev))) {
 				spin_lock(&np->lock);
 				if (!np->in_shutdown)
@@ -3185,8 +3190,8 @@
 				np->nic_poll_irq = np->irqmask;
 				mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
 			}
-			printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
 			spin_unlock(&np->lock);
+			printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
 			break;
 		}
 
@@ -3232,8 +3237,8 @@
 				np->nic_poll_irq |= NVREG_IRQ_TX_ALL;
 				mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
 			}
-			printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_tx.\n", dev->name, i);
 			spin_unlock_irqrestore(&np->lock, flags);
+			printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_tx.\n", dev->name, i);
 			break;
 		}
 
@@ -3244,19 +3249,19 @@
 }
 
 #ifdef CONFIG_FORCEDETH_NAPI
-static int nv_napi_poll(struct net_device *dev, int *budget)
+static int nv_napi_poll(struct napi_struct *napi, int budget)
 {
-	int pkts, limit = min(*budget, dev->quota);
-	struct fe_priv *np = netdev_priv(dev);
+	struct fe_priv *np = container_of(napi, struct fe_priv, napi);
+	struct net_device *dev = np->dev;
 	u8 __iomem *base = get_hwbase(dev);
 	unsigned long flags;
-	int retcode;
+	int pkts, retcode;
 
 	if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-		pkts = nv_rx_process(dev, limit);
+		pkts = nv_rx_process(dev, budget);
 		retcode = nv_alloc_rx(dev);
 	} else {
-		pkts = nv_rx_process_optimized(dev, limit);
+		pkts = nv_rx_process_optimized(dev, budget);
 		retcode = nv_alloc_rx_optimized(dev);
 	}
 
@@ -3267,13 +3272,12 @@
 		spin_unlock_irqrestore(&np->lock, flags);
 	}
 
-	if (pkts < limit) {
-		/* all done, no more packets present */
-		netif_rx_complete(dev);
-
+	if (pkts < budget) {
 		/* re-enable receive interrupts */
 		spin_lock_irqsave(&np->lock, flags);
 
+		__netif_rx_complete(dev, napi);
+
 		np->irqmask |= NVREG_IRQ_RX_ALL;
 		if (np->msi_flags & NV_MSI_X_ENABLED)
 			writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
@@ -3281,13 +3285,8 @@
 			writel(np->irqmask, base + NvRegIrqMask);
 
 		spin_unlock_irqrestore(&np->lock, flags);
-		return 0;
-	} else {
-		/* used up our quantum, so reschedule */
-		dev->quota -= pkts;
-		*budget -= pkts;
-		return 1;
 	}
+	return pkts;
 }
 #endif
 
@@ -3295,6 +3294,7 @@
 static irqreturn_t nv_nic_irq_rx(int foo, void *data)
 {
 	struct net_device *dev = (struct net_device *) data;
+	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 	u32 events;
 
@@ -3302,7 +3302,7 @@
 	writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
 
 	if (events) {
-		netif_rx_schedule(dev);
+		netif_rx_schedule(dev, &np->napi);
 		/* disable receive interrupts on the nic */
 		writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
 		pci_push(base);
@@ -3328,7 +3328,7 @@
 		if (!(events & np->irqmask))
 			break;
 
-		if (nv_rx_process_optimized(dev, dev->weight)) {
+		if (nv_rx_process_optimized(dev, RX_WORK_PER_LOOP)) {
 			if (unlikely(nv_alloc_rx_optimized(dev))) {
 				spin_lock_irqsave(&np->lock, flags);
 				if (!np->in_shutdown)
@@ -3347,8 +3347,8 @@
 				np->nic_poll_irq |= NVREG_IRQ_RX_ALL;
 				mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
 			}
-			printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_rx.\n", dev->name, i);
 			spin_unlock_irqrestore(&np->lock, flags);
+			printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_rx.\n", dev->name, i);
 			break;
 		}
 	}
@@ -3420,8 +3420,8 @@
 				np->nic_poll_irq |= NVREG_IRQ_OTHER;
 				mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
 			}
-			printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_other.\n", dev->name, i);
 			spin_unlock_irqrestore(&np->lock, flags);
+			printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_other.\n", dev->name, i);
 			break;
 		}
 
@@ -4333,16 +4333,26 @@
 		return -EOPNOTSUPP;
 }
 
-static int nv_get_stats_count(struct net_device *dev)
+static int nv_get_sset_count(struct net_device *dev, int sset)
 {
 	struct fe_priv *np = netdev_priv(dev);
 
-	if (np->driver_data & DEV_HAS_STATISTICS_V1)
-		return NV_DEV_STATISTICS_V1_COUNT;
-	else if (np->driver_data & DEV_HAS_STATISTICS_V2)
-		return NV_DEV_STATISTICS_V2_COUNT;
-	else
-		return 0;
+	switch (sset) {
+	case ETH_SS_TEST:
+		if (np->driver_data & DEV_HAS_TEST_EXTENDED)
+			return NV_TEST_COUNT_EXTENDED;
+		else
+			return NV_TEST_COUNT_BASE;
+	case ETH_SS_STATS:
+		if (np->driver_data & DEV_HAS_STATISTICS_V1)
+			return NV_DEV_STATISTICS_V1_COUNT;
+		else if (np->driver_data & DEV_HAS_STATISTICS_V2)
+			return NV_DEV_STATISTICS_V2_COUNT;
+		else
+			return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void nv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *estats, u64 *buffer)
@@ -4352,17 +4362,7 @@
 	/* update stats */
 	nv_do_stats_poll((unsigned long)dev);
 
-	memcpy(buffer, &np->estats, nv_get_stats_count(dev)*sizeof(u64));
-}
-
-static int nv_self_test_count(struct net_device *dev)
-{
-	struct fe_priv *np = netdev_priv(dev);
-
-	if (np->driver_data & DEV_HAS_TEST_EXTENDED)
-		return NV_TEST_COUNT_EXTENDED;
-	else
-		return NV_TEST_COUNT_BASE;
+	memcpy(buffer, &np->estats, nv_get_sset_count(dev, ETH_SS_STATS)*sizeof(u64));
 }
 
 static int nv_link_test(struct net_device *dev)
@@ -4609,7 +4609,7 @@
 	struct fe_priv *np = netdev_priv(dev);
 	u8 __iomem *base = get_hwbase(dev);
 	int result;
-	memset(buffer, 0, nv_self_test_count(dev)*sizeof(u64));
+	memset(buffer, 0, nv_get_sset_count(dev, ETH_SS_TEST)*sizeof(u64));
 
 	if (!nv_link_test(dev)) {
 		test->flags |= ETH_TEST_FL_FAILED;
@@ -4619,7 +4619,9 @@
 	if (test->flags & ETH_TEST_FL_OFFLINE) {
 		if (netif_running(dev)) {
 			netif_stop_queue(dev);
-			netif_poll_disable(dev);
+#ifdef CONFIG_FORCEDETH_NAPI
+			napi_disable(&np->napi);
+#endif
 			netif_tx_lock_bh(dev);
 			spin_lock_irq(&np->lock);
 			nv_disable_hw_interrupts(dev, np->irqmask);
@@ -4678,7 +4680,9 @@
 			nv_start_rx(dev);
 			nv_start_tx(dev);
 			netif_start_queue(dev);
-			netif_poll_enable(dev);
+#ifdef CONFIG_FORCEDETH_NAPI
+			napi_enable(&np->napi);
+#endif
 			nv_enable_hw_interrupts(dev, np->irqmask);
 		}
 	}
@@ -4688,10 +4692,10 @@
 {
 	switch (stringset) {
 	case ETH_SS_STATS:
-		memcpy(buffer, &nv_estats_str, nv_get_stats_count(dev)*sizeof(struct nv_ethtool_str));
+		memcpy(buffer, &nv_estats_str, nv_get_sset_count(dev, ETH_SS_STATS)*sizeof(struct nv_ethtool_str));
 		break;
 	case ETH_SS_TEST:
-		memcpy(buffer, &nv_etests_str, nv_self_test_count(dev)*sizeof(struct nv_ethtool_str));
+		memcpy(buffer, &nv_etests_str, nv_get_sset_count(dev, ETH_SS_TEST)*sizeof(struct nv_ethtool_str));
 		break;
 	}
 }
@@ -4706,8 +4710,6 @@
 	.get_regs_len = nv_get_regs_len,
 	.get_regs = nv_get_regs,
 	.nway_reset = nv_nway_reset,
-	.get_perm_addr = ethtool_op_get_perm_addr,
-	.get_tso = ethtool_op_get_tso,
 	.set_tso = nv_set_tso,
 	.get_ringparam = nv_get_ringparam,
 	.set_ringparam = nv_set_ringparam,
@@ -4715,14 +4717,11 @@
 	.set_pauseparam = nv_set_pauseparam,
 	.get_rx_csum = nv_get_rx_csum,
 	.set_rx_csum = nv_set_rx_csum,
-	.get_tx_csum = ethtool_op_get_tx_csum,
 	.set_tx_csum = nv_set_tx_csum,
-	.get_sg = ethtool_op_get_sg,
 	.set_sg = nv_set_sg,
 	.get_strings = nv_get_strings,
-	.get_stats_count = nv_get_stats_count,
 	.get_ethtool_stats = nv_get_ethtool_stats,
-	.self_test_count = nv_self_test_count,
+	.get_sset_count = nv_get_sset_count,
 	.self_test = nv_self_test,
 };
 
@@ -4911,12 +4910,14 @@
 	nv_start_rx(dev);
 	nv_start_tx(dev);
 	netif_start_queue(dev);
-	netif_poll_enable(dev);
+#ifdef CONFIG_FORCEDETH_NAPI
+	napi_enable(&np->napi);
+#endif
 
 	if (ret) {
 		netif_carrier_on(dev);
 	} else {
-		printk("%s: no link during initialization.\n", dev->name);
+		printk(KERN_INFO "%s: no link during initialization.\n", dev->name);
 		netif_carrier_off(dev);
 	}
 	if (oom)
@@ -4942,7 +4943,9 @@
 	spin_lock_irq(&np->lock);
 	np->in_shutdown = 1;
 	spin_unlock_irq(&np->lock);
-	netif_poll_disable(dev);
+#ifdef CONFIG_FORCEDETH_NAPI
+	napi_disable(&np->napi);
+#endif
 	synchronize_irq(dev->irq);
 
 	del_timer_sync(&np->oom_kick);
@@ -4987,6 +4990,7 @@
 	u32 powerstate, txreg;
 	u32 phystate_orig = 0, phystate;
 	int phyinitialized = 0;
+	DECLARE_MAC_BUF(mac);
 
 	dev = alloc_etherdev(sizeof(struct fe_priv));
 	err = -ENOMEM;
@@ -4994,9 +4998,9 @@
 		goto out;
 
 	np = netdev_priv(dev);
+	np->dev = dev;
 	np->pci_dev = pci_dev;
 	spin_lock_init(&np->lock);
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pci_dev->dev);
 
 	init_timer(&np->oom_kick);
@@ -5137,12 +5141,10 @@
 			goto out_unmap;
 		np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
 	}
-	np->rx_skb = kmalloc(sizeof(struct nv_skb_map) * np->rx_ring_size, GFP_KERNEL);
-	np->tx_skb = kmalloc(sizeof(struct nv_skb_map) * np->tx_ring_size, GFP_KERNEL);
+	np->rx_skb = kcalloc(np->rx_ring_size, sizeof(struct nv_skb_map), GFP_KERNEL);
+	np->tx_skb = kcalloc(np->tx_ring_size, sizeof(struct nv_skb_map), GFP_KERNEL);
 	if (!np->rx_skb || !np->tx_skb)
 		goto out_freering;
-	memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size);
-	memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size);
 
 	dev->open = nv_open;
 	dev->stop = nv_close;
@@ -5157,9 +5159,8 @@
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = nv_poll_controller;
 #endif
-	dev->weight = RX_WORK_PER_LOOP;
 #ifdef CONFIG_FORCEDETH_NAPI
-	dev->poll = nv_napi_poll;
+	netif_napi_add(dev, &np->napi, nv_napi_poll, RX_WORK_PER_LOOP);
 #endif
 	SET_ETHTOOL_OPS(dev, &ops);
 	dev->tx_timeout = nv_tx_timeout;
@@ -5174,7 +5175,8 @@
 
 	/* check the workaround bit for correct mac address order */
 	txreg = readl(base + NvRegTransmitPoll);
-	if (txreg & NVREG_TRANSMITPOLL_MAC_ADDR_REV) {
+	if ((txreg & NVREG_TRANSMITPOLL_MAC_ADDR_REV) ||
+	    (id->driver_data & DEV_HAS_CORRECT_MACADDR)) {
 		/* mac address is already in correct order */
 		dev->dev_addr[0] = (np->orig_mac[0] >>  0) & 0xff;
 		dev->dev_addr[1] = (np->orig_mac[0] >>  8) & 0xff;
@@ -5203,10 +5205,8 @@
 		 * Bad mac address. At least one bios sets the mac address
 		 * to 01:23:45:67:89:ab
 		 */
-		printk(KERN_ERR "%s: Invalid Mac address detected: %02x:%02x:%02x:%02x:%02x:%02x\n",
-			pci_name(pci_dev),
-			dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-			dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+		printk(KERN_ERR "%s: Invalid Mac address detected: %s\n",
+		       pci_name(pci_dev), print_mac(mac, dev->dev_addr));
 		printk(KERN_ERR "Please complain to your hardware vendor. Switching to a random MAC.\n");
 		dev->dev_addr[0] = 0x00;
 		dev->dev_addr[1] = 0x00;
@@ -5214,9 +5214,8 @@
 		get_random_bytes(&dev->dev_addr[3], 3);
 	}
 
-	dprintk(KERN_DEBUG "%s: MAC Address %02x:%02x:%02x:%02x:%02x:%02x\n", pci_name(pci_dev),
-			dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-			dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+	dprintk(KERN_DEBUG "%s: MAC Address %s\n",
+		pci_name(pci_dev), print_mac(mac, dev->dev_addr));
 
 	/* set mac address */
 	nv_copy_mac_to_hw(dev);
@@ -5502,51 +5501,67 @@
 	},
 	{	/* MCP61 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
 	},
 	{	/* MCP61 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
 	},
 	{	/* MCP61 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
 	},
 	{	/* MCP61 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
 	},
 	{	/* MCP65 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
 	},
 	{	/* MCP65 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
 	},
 	{	/* MCP65 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
 	},
 	{	/* MCP65 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
 	},
 	{	/* MCP67 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
 	},
 	{	/* MCP67 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
 	},
 	{	/* MCP67 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
 	},
 	{	/* MCP67 Ethernet Controller */
 		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27),
-		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+	},
+	{	/* MCP73 Ethernet Controller */
+		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_28),
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+	},
+	{	/* MCP73 Ethernet Controller */
+		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_29),
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+	},
+	{	/* MCP73 Ethernet Controller */
+		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_30),
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+	},
+	{	/* MCP73 Ethernet Controller */
+		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_31),
+		.driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
 	},
 	{0,},
 };
diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig
index e27ee21..2765e49 100644
--- a/drivers/net/fs_enet/Kconfig
+++ b/drivers/net/fs_enet/Kconfig
@@ -11,6 +11,7 @@
 config FS_ENET_HAS_FCC
 	bool "Chip has an FCC usable for ethernet"
 	depends on FS_ENET && CPM2
+	select MDIO_BITBANG
 	default y
 
 config FS_ENET_HAS_FEC
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index a4a2a0e..04c6fae 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -1,17 +1,17 @@
 /*
  * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
  *
- * Copyright (c) 2003 Intracom S.A. 
+ * Copyright (c) 2003 Intracom S.A.
  *  by Pantelis Antoniou <panto@intracom.gr>
- * 
- * 2005 (c) MontaVista Software, Inc. 
+ *
+ * 2005 (c) MontaVista Software, Inc.
  * Vitaly Bordug <vbordug@ru.mvista.com>
  *
  * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com>
  * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se>
  *
- * This file is licensed under the terms of the GNU General Public License 
- * version 2. This program is licensed "as is" without any warranty of any 
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
  * kind, whether express or implied.
  */
 
@@ -39,28 +39,35 @@
 
 #include <linux/vmalloc.h>
 #include <asm/pgtable.h>
-
-#include <asm/pgtable.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <asm/of_platform.h>
+#endif
+
 #include "fs_enet.h"
 
 /*************************************************/
 
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
 static char version[] __devinitdata =
     DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n";
+#endif
 
 MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>");
 MODULE_DESCRIPTION("Freescale Ethernet Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_MODULE_VERSION);
 
-int fs_enet_debug = -1;		/* -1 == use FS_ENET_DEF_MSG_ENABLE as value */
+static int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */
 module_param(fs_enet_debug, int, 0);
 MODULE_PARM_DESC(fs_enet_debug,
 		 "Freescale bitmapped debugging message enable value");
 
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void fs_enet_netpoll(struct net_device *dev);
+#endif
 
 static void fs_set_multicast_list(struct net_device *dev)
 {
@@ -69,19 +76,25 @@
 	(*fep->ops->set_multicast_list)(dev);
 }
 
-/* NAPI receive function */
-static int fs_enet_rx_napi(struct net_device *dev, int *budget)
+static void skb_align(struct sk_buff *skb, int align)
 {
-	struct fs_enet_private *fep = netdev_priv(dev);
+	int off = ((unsigned long)skb->data) & (align - 1);
+
+	if (off)
+		skb_reserve(skb, align - off);
+}
+
+/* NAPI receive function */
+static int fs_enet_rx_napi(struct napi_struct *napi, int budget)
+{
+	struct fs_enet_private *fep = container_of(napi, struct fs_enet_private, napi);
+	struct net_device *dev = to_net_dev(fep->dev);
 	const struct fs_platform_info *fpi = fep->fpi;
-	cbd_t *bdp;
+	cbd_t __iomem *bdp;
 	struct sk_buff *skb, *skbn, *skbt;
 	int received = 0;
 	u16 pkt_len, sc;
 	int curidx;
-	int rx_work_limit = 0;	/* pacify gcc */
-
-	rx_work_limit = min(dev->quota, *budget);
 
 	if (!netif_running(dev))
 		return 0;
@@ -96,7 +109,6 @@
 	(*fep->ops->napi_clear_rx_event)(dev);
 
 	while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) {
-
 		curidx = bdp - fep->rx_bd_base;
 
 		/*
@@ -109,7 +121,7 @@
 			       dev->name);
 
 		/*
-		 * Check for errors. 
+		 * Check for errors.
 		 */
 		if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL |
 			  BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) {
@@ -136,11 +148,6 @@
 			skbn = skb;
 
 		} else {
-
-			/* napi, got packet but no quota */
-			if (--rx_work_limit < 0)
-				break;
-
 			skb = fep->rx_skbuff[curidx];
 
 			dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp),
@@ -166,9 +173,13 @@
 					skb = skbn;
 					skbn = skbt;
 				}
-			} else
+			} else {
 				skbn = dev_alloc_skb(ENET_RX_FRSIZE);
 
+				if (skbn)
+					skb_align(skbn, ENET_RX_ALIGN);
+			}
+
 			if (skbn != NULL) {
 				skb_put(skb, pkt_len);	/* Make room */
 				skb->protocol = eth_type_trans(skb, dev);
@@ -191,7 +202,7 @@
 		CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY);
 
 		/*
-		 * Update BD pointer to next entry. 
+		 * Update BD pointer to next entry.
 		 */
 		if ((sc & BD_ENET_RX_WRAP) == 0)
 			bdp++;
@@ -199,22 +210,19 @@
 			bdp = fep->rx_bd_base;
 
 		(*fep->ops->rx_bd_done)(dev);
+
+		if (received >= budget)
+			break;
 	}
 
 	fep->cur_rx = bdp;
 
-	dev->quota -= received;
-	*budget -= received;
-
-	if (rx_work_limit < 0)
-		return 1;	/* not done */
-
-	/* done */
-	netif_rx_complete(dev);
-
-	(*fep->ops->napi_enable_rx)(dev);
-
-	return 0;
+	if (received >= budget) {
+		/* done */
+		netif_rx_complete(dev, napi);
+		(*fep->ops->napi_enable_rx)(dev);
+	}
+	return received;
 }
 
 /* non NAPI receive function */
@@ -222,7 +230,7 @@
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
 	const struct fs_platform_info *fpi = fep->fpi;
-	cbd_t *bdp;
+	cbd_t __iomem *bdp;
 	struct sk_buff *skb, *skbn, *skbt;
 	int received = 0;
 	u16 pkt_len, sc;
@@ -247,7 +255,7 @@
 			       dev->name);
 
 		/*
-		 * Check for errors. 
+		 * Check for errors.
 		 */
 		if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL |
 			  BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) {
@@ -300,9 +308,13 @@
 					skb = skbn;
 					skbn = skbt;
 				}
-			} else
+			} else {
 				skbn = dev_alloc_skb(ENET_RX_FRSIZE);
 
+				if (skbn)
+					skb_align(skbn, ENET_RX_ALIGN);
+			}
+
 			if (skbn != NULL) {
 				skb_put(skb, pkt_len);	/* Make room */
 				skb->protocol = eth_type_trans(skb, dev);
@@ -325,7 +337,7 @@
 		CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY);
 
 		/*
-		 * Update BD pointer to next entry. 
+		 * Update BD pointer to next entry.
 		 */
 		if ((sc & BD_ENET_RX_WRAP) == 0)
 			bdp++;
@@ -343,17 +355,16 @@
 static void fs_enet_tx(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	cbd_t *bdp;
+	cbd_t __iomem *bdp;
 	struct sk_buff *skb;
 	int dirtyidx, do_wake, do_restart;
 	u16 sc;
 
-	spin_lock(&fep->lock);
+	spin_lock(&fep->tx_lock);
 	bdp = fep->dirty_tx;
 
 	do_wake = do_restart = 0;
 	while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) {
-
 		dirtyidx = bdp - fep->tx_bd_base;
 
 		if (fep->tx_free == fep->tx_ring)
@@ -362,7 +373,7 @@
 		skb = fep->tx_skbuff[dirtyidx];
 
 		/*
-		 * Check for errors. 
+		 * Check for errors.
 		 */
 		if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC |
 			  BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) {
@@ -402,13 +413,13 @@
 				skb->len, DMA_TO_DEVICE);
 
 		/*
-		 * Free the sk buffer associated with this last transmit. 
+		 * Free the sk buffer associated with this last transmit.
 		 */
 		dev_kfree_skb_irq(skb);
 		fep->tx_skbuff[dirtyidx] = NULL;
 
 		/*
-		 * Update pointer to next buffer descriptor to be transmitted. 
+		 * Update pointer to next buffer descriptor to be transmitted.
 		 */
 		if ((sc & BD_ENET_TX_WRAP) == 0)
 			bdp++;
@@ -428,7 +439,7 @@
 	if (do_restart)
 		(*fep->ops->tx_restart)(dev);
 
-	spin_unlock(&fep->lock);
+	spin_unlock(&fep->tx_lock);
 
 	if (do_wake)
 		netif_wake_queue(dev);
@@ -454,7 +465,6 @@
 
 	nr = 0;
 	while ((int_events = (*fep->ops->get_int_events)(dev)) != 0) {
-
 		nr++;
 
 		int_clr_events = int_events;
@@ -470,7 +480,7 @@
 			if (!fpi->use_napi)
 				fs_enet_rx_non_napi(dev);
 			else {
-				napi_ok = netif_rx_schedule_prep(dev);
+				napi_ok = napi_schedule_prep(&fep->napi);
 
 				(*fep->ops->napi_disable_rx)(dev);
 				(*fep->ops->clear_int_events)(dev, fep->ev_napi_rx);
@@ -478,7 +488,7 @@
 				/* NOTE: it is possible for FCCs in NAPI mode    */
 				/* to submit a spurious interrupt while in poll  */
 				if (napi_ok)
-					__netif_rx_schedule(dev);
+					__netif_rx_schedule(dev, &fep->napi);
 			}
 		}
 
@@ -493,7 +503,7 @@
 void fs_init_bds(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	cbd_t *bdp;
+	cbd_t __iomem *bdp;
 	struct sk_buff *skb;
 	int i;
 
@@ -504,7 +514,7 @@
 	fep->cur_rx = fep->rx_bd_base;
 
 	/*
-	 * Initialize the receive buffer descriptors. 
+	 * Initialize the receive buffer descriptors.
 	 */
 	for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) {
 		skb = dev_alloc_skb(ENET_RX_FRSIZE);
@@ -514,6 +524,7 @@
 			       dev->name);
 			break;
 		}
+		skb_align(skb, ENET_RX_ALIGN);
 		fep->rx_skbuff[i] = skb;
 		CBDW_BUFADDR(bdp,
 			dma_map_single(fep->dev, skb->data,
@@ -524,7 +535,7 @@
 			((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP));
 	}
 	/*
-	 * if we failed, fillup remainder 
+	 * if we failed, fillup remainder
 	 */
 	for (; i < fep->rx_ring; i++, bdp++) {
 		fep->rx_skbuff[i] = NULL;
@@ -532,7 +543,7 @@
 	}
 
 	/*
-	 * ...and the same for transmit.  
+	 * ...and the same for transmit.
 	 */
 	for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) {
 		fep->tx_skbuff[i] = NULL;
@@ -546,11 +557,11 @@
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
 	struct sk_buff *skb;
-	cbd_t *bdp;
+	cbd_t __iomem *bdp;
 	int i;
 
 	/*
-	 * Reset SKB transmit buffers.  
+	 * Reset SKB transmit buffers.
 	 */
 	for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) {
 		if ((skb = fep->tx_skbuff[i]) == NULL)
@@ -565,7 +576,7 @@
 	}
 
 	/*
-	 * Reset SKB receive buffers 
+	 * Reset SKB receive buffers
 	 */
 	for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) {
 		if ((skb = fep->rx_skbuff[i]) == NULL)
@@ -587,7 +598,7 @@
 static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	cbd_t *bdp;
+	cbd_t __iomem *bdp;
 	int curidx;
 	u16 sc;
 	unsigned long flags;
@@ -595,7 +606,7 @@
 	spin_lock_irqsave(&fep->tx_lock, flags);
 
 	/*
-	 * Fill in a Tx ring entry 
+	 * Fill in a Tx ring entry
 	 */
 	bdp = fep->cur_tx;
 
@@ -614,19 +625,19 @@
 
 	curidx = bdp - fep->tx_bd_base;
 	/*
-	 * Clear all of the status flags. 
+	 * Clear all of the status flags.
 	 */
 	CBDC_SC(bdp, BD_ENET_TX_STATS);
 
 	/*
-	 * Save skb pointer. 
+	 * Save skb pointer.
 	 */
 	fep->tx_skbuff[curidx] = skb;
 
 	fep->stats.tx_bytes += skb->len;
 
 	/*
-	 * Push the data cache so the CPM does not get stale memory data. 
+	 * Push the data cache so the CPM does not get stale memory data.
 	 */
 	CBDW_BUFADDR(bdp, dma_map_single(fep->dev,
 				skb->data, skb->len, DMA_TO_DEVICE));
@@ -635,7 +646,7 @@
 	dev->trans_start = jiffies;
 
 	/*
-	 * If this was the last BD in the ring, start at the beginning again. 
+	 * If this was the last BD in the ring, start at the beginning again.
 	 */
 	if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0)
 		fep->cur_tx++;
@@ -710,45 +721,43 @@
  *-----------------------------------------------------------------------------*/
 static void generic_adjust_link(struct  net_device *dev)
 {
-       struct fs_enet_private *fep = netdev_priv(dev);
-       struct phy_device *phydev = fep->phydev;
-       int new_state = 0;
+	struct fs_enet_private *fep = netdev_priv(dev);
+	struct phy_device *phydev = fep->phydev;
+	int new_state = 0;
 
-       if (phydev->link) {
+	if (phydev->link) {
+		/* adjust to duplex mode */
+		if (phydev->duplex != fep->oldduplex) {
+			new_state = 1;
+			fep->oldduplex = phydev->duplex;
+		}
 
-               /* adjust to duplex mode */
-               if (phydev->duplex != fep->oldduplex){
-                       new_state = 1;
-                       fep->oldduplex = phydev->duplex;
-               }
+		if (phydev->speed != fep->oldspeed) {
+			new_state = 1;
+			fep->oldspeed = phydev->speed;
+		}
 
-               if (phydev->speed != fep->oldspeed) {
-                       new_state = 1;
-                       fep->oldspeed = phydev->speed;
-               }
+		if (!fep->oldlink) {
+			new_state = 1;
+			fep->oldlink = 1;
+			netif_schedule(dev);
+			netif_carrier_on(dev);
+			netif_start_queue(dev);
+		}
 
-               if (!fep->oldlink) {
-                       new_state = 1;
-                       fep->oldlink = 1;
-                       netif_schedule(dev);
-                       netif_carrier_on(dev);
-                       netif_start_queue(dev);
-               }
+		if (new_state)
+			fep->ops->restart(dev);
+	} else if (fep->oldlink) {
+		new_state = 1;
+		fep->oldlink = 0;
+		fep->oldspeed = 0;
+		fep->oldduplex = -1;
+		netif_carrier_off(dev);
+		netif_stop_queue(dev);
+	}
 
-               if (new_state)
-                       fep->ops->restart(dev);
-
-       } else if (fep->oldlink) {
-               new_state = 1;
-               fep->oldlink = 0;
-               fep->oldspeed = 0;
-               fep->oldduplex = -1;
-               netif_carrier_off(dev);
-               netif_stop_queue(dev);
-       }
-
-       if (new_state && netif_msg_link(fep))
-               phy_print_status(phydev);
+	if (new_state && netif_msg_link(fep))
+		phy_print_status(phydev);
 }
 
 
@@ -792,25 +801,28 @@
 	return 0;
 }
 
-
 static int fs_enet_open(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
 	int r;
 	int err;
 
+	napi_enable(&fep->napi);
+
 	/* Install our interrupt handler. */
 	r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt);
 	if (r != 0) {
 		printk(KERN_ERR DRV_MODULE_NAME
 		       ": %s Could not allocate FS_ENET IRQ!", dev->name);
+		napi_disable(&fep->napi);
 		return -EINVAL;
 	}
 
 	err = fs_init_phy(dev);
-	if(err)
+	if(err) {
+		napi_disable(&fep->napi);
 		return err;
-
+	}
 	phy_start(fep->phydev);
 
 	return 0;
@@ -823,10 +835,13 @@
 
 	netif_stop_queue(dev);
 	netif_carrier_off(dev);
+	napi_disable(&fep->napi);
 	phy_stop(fep->phydev);
 
 	spin_lock_irqsave(&fep->lock, flags);
+	spin_lock(&fep->tx_lock);
 	(*fep->ops->stop)(dev);
+	spin_unlock(&fep->tx_lock);
 	spin_unlock_irqrestore(&fep->lock, flags);
 
 	/* release any irqs */
@@ -915,9 +930,7 @@
 	.get_link = ethtool_op_get_link,
 	.get_msglevel = fs_get_msglevel,
 	.set_msglevel = fs_set_msglevel,
-	.get_tx_csum = ethtool_op_get_tx_csum,
 	.set_tx_csum = ethtool_op_set_tx_csum,	/* local! */
-	.get_sg = ethtool_op_get_sg,
 	.set_sg = ethtool_op_set_sg,
 	.get_regs = fs_get_regs,
 };
@@ -941,6 +954,7 @@
 extern int fs_mii_connect(struct net_device *dev);
 extern void fs_mii_disconnect(struct net_device *dev);
 
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
 static struct net_device *fs_init_instance(struct device *dev,
 		struct fs_platform_info *fpi)
 {
@@ -961,10 +975,8 @@
 		err = -ENOMEM;
 		goto err;
 	}
-	SET_MODULE_OWNER(ndev);
 
 	fep = netdev_priv(ndev);
-	memset(fep, 0, privsize);	/* clear everything */
 
 	fep->dev = dev;
 	dev_set_drvdata(dev, ndev);
@@ -978,7 +990,7 @@
 #endif
 
 #ifdef CONFIG_FS_ENET_HAS_SCC
-	if (fs_get_scc_index(fpi->fs_no) >=0 )
+	if (fs_get_scc_index(fpi->fs_no) >=0)
 		fep->ops = &fs_scc_ops;
 #endif
 
@@ -1013,13 +1025,13 @@
 	spin_lock_init(&fep->tx_lock);
 
 	/*
-	 * Set the Ethernet address. 
+	 * Set the Ethernet address.
 	 */
 	for (i = 0; i < 6; i++)
 		ndev->dev_addr[i] = fpi->macaddr[i];
-	
+
 	r = (*fep->ops->allocate_bd)(ndev);
-	
+
 	if (fep->ring_base == NULL) {
 		printk(KERN_ERR DRV_MODULE_NAME
 		       ": %s buffer descriptor alloc failed (%d).\n", ndev->name, r);
@@ -1038,7 +1050,7 @@
 	fep->rx_ring = fpi->rx_ring;
 
 	/*
-	 * The FEC Ethernet specific entries in the device structure. 
+	 * The FEC Ethernet specific entries in the device structure.
 	 */
 	ndev->open = fs_enet_open;
 	ndev->hard_start_xmit = fs_enet_start_xmit;
@@ -1047,10 +1059,14 @@
 	ndev->stop = fs_enet_close;
 	ndev->get_stats = fs_enet_get_stats;
 	ndev->set_multicast_list = fs_set_multicast_list;
-	if (fpi->use_napi) {
-		ndev->poll = fs_enet_rx_napi;
-		ndev->weight = fpi->napi_weight;
-	}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	ndev->poll_controller = fs_enet_netpoll;
+#endif
+
+	netif_napi_add(ndev, &fep->napi,
+		       fs_enet_rx_napi, fpi->napi_weight);
+
 	ndev->ethtool_ops = &fs_ethtool_ops;
 	ndev->do_ioctl = fs_ioctl;
 
@@ -1069,9 +1085,8 @@
 
 	return ndev;
 
-      err:
+err:
 	if (ndev != NULL) {
-
 		if (registered)
 			unregister_netdev(ndev);
 
@@ -1106,7 +1121,7 @@
 	unregister_netdev(ndev);
 
 	dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t),
-			  fep->ring_base, fep->ring_mem_addr);
+			  (void __force *)fep->ring_base, fep->ring_mem_addr);
 
 	/* reset it */
 	(*fep->ops->cleanup_data)(ndev);
@@ -1121,43 +1136,259 @@
 
 	return 0;
 }
+#endif
 
 /**************************************************************************************/
 
 /* handy pointer to the immap */
-void *fs_enet_immap = NULL;
+void __iomem *fs_enet_immap = NULL;
 
 static int setup_immap(void)
 {
-	phys_addr_t paddr = 0;
-	unsigned long size = 0;
-
 #ifdef CONFIG_CPM1
-	paddr = IMAP_ADDR;
-	size = 0x10000;	/* map 64K */
+	fs_enet_immap = ioremap(IMAP_ADDR, 0x4000);
+	WARN_ON(!fs_enet_immap);
+#elif defined(CONFIG_CPM2)
+	fs_enet_immap = cpm2_immr;
 #endif
 
-#ifdef CONFIG_CPM2
-	paddr = CPM_MAP_ADDR;
-	size = 0x40000;	/* map 256 K */
-#endif
-	fs_enet_immap = ioremap(paddr, size);
-	if (fs_enet_immap == NULL)
-		return -EBADF;	/* XXX ahem; maybe just BUG_ON? */
-
 	return 0;
 }
 
 static void cleanup_immap(void)
 {
-	if (fs_enet_immap != NULL) {
-		iounmap(fs_enet_immap);
-		fs_enet_immap = NULL;
-	}
+#if defined(CONFIG_CPM1)
+	iounmap(fs_enet_immap);
+#endif
 }
 
 /**************************************************************************************/
 
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static int __devinit find_phy(struct device_node *np,
+                              struct fs_platform_info *fpi)
+{
+	struct device_node *phynode, *mdionode;
+	struct resource res;
+	int ret = 0, len;
+
+	const u32 *data = of_get_property(np, "phy-handle", &len);
+	if (!data || len != 4)
+		return -EINVAL;
+
+	phynode = of_find_node_by_phandle(*data);
+	if (!phynode)
+		return -EINVAL;
+
+	mdionode = of_get_parent(phynode);
+	if (!mdionode)
+		goto out_put_phy;
+
+	ret = of_address_to_resource(mdionode, 0, &res);
+	if (ret)
+		goto out_put_mdio;
+
+	data = of_get_property(phynode, "reg", &len);
+	if (!data || len != 4)
+		goto out_put_mdio;
+
+	snprintf(fpi->bus_id, 16, PHY_ID_FMT, res.start, *data);
+
+out_put_mdio:
+	of_node_put(mdionode);
+out_put_phy:
+	of_node_put(phynode);
+	return ret;
+}
+
+#ifdef CONFIG_FS_ENET_HAS_FEC
+#define IS_FEC(match) ((match)->data == &fs_fec_ops)
+#else
+#define IS_FEC(match) 0
+#endif
+
+static int __devinit fs_enet_probe(struct of_device *ofdev,
+                                   const struct of_device_id *match)
+{
+	struct net_device *ndev;
+	struct fs_enet_private *fep;
+	struct fs_platform_info *fpi;
+	const u32 *data;
+	const u8 *mac_addr;
+	int privsize, len, ret = -ENODEV;
+
+	fpi = kzalloc(sizeof(*fpi), GFP_KERNEL);
+	if (!fpi)
+		return -ENOMEM;
+
+	if (!IS_FEC(match)) {
+		data = of_get_property(ofdev->node, "fsl,cpm-command", &len);
+		if (!data || len != 4)
+			goto out_free_fpi;
+
+		fpi->cp_command = *data;
+	}
+
+	fpi->rx_ring = 32;
+	fpi->tx_ring = 32;
+	fpi->rx_copybreak = 240;
+	fpi->use_napi = 0;
+	fpi->napi_weight = 17;
+
+	ret = find_phy(ofdev->node, fpi);
+	if (ret)
+		goto out_free_fpi;
+
+	privsize = sizeof(*fep) +
+	           sizeof(struct sk_buff **) *
+	           (fpi->rx_ring + fpi->tx_ring);
+
+	ndev = alloc_etherdev(privsize);
+	if (!ndev) {
+		ret = -ENOMEM;
+		goto out_free_fpi;
+	}
+
+	SET_MODULE_OWNER(ndev);
+	dev_set_drvdata(&ofdev->dev, ndev);
+
+	fep = netdev_priv(ndev);
+	fep->dev = &ofdev->dev;
+	fep->fpi = fpi;
+	fep->ops = match->data;
+
+	ret = fep->ops->setup_data(ndev);
+	if (ret)
+		goto out_free_dev;
+
+	fep->rx_skbuff = (struct sk_buff **)&fep[1];
+	fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring;
+
+	spin_lock_init(&fep->lock);
+	spin_lock_init(&fep->tx_lock);
+
+	mac_addr = of_get_mac_address(ofdev->node);
+	if (mac_addr)
+		memcpy(ndev->dev_addr, mac_addr, 6);
+
+	ret = fep->ops->allocate_bd(ndev);
+	if (ret)
+		goto out_cleanup_data;
+
+	fep->rx_bd_base = fep->ring_base;
+	fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring;
+
+	fep->tx_ring = fpi->tx_ring;
+	fep->rx_ring = fpi->rx_ring;
+
+	ndev->open = fs_enet_open;
+	ndev->hard_start_xmit = fs_enet_start_xmit;
+	ndev->tx_timeout = fs_timeout;
+	ndev->watchdog_timeo = 2 * HZ;
+	ndev->stop = fs_enet_close;
+	ndev->get_stats = fs_enet_get_stats;
+	ndev->set_multicast_list = fs_set_multicast_list;
+	if (fpi->use_napi) {
+		ndev->poll = fs_enet_rx_napi;
+		ndev->weight = fpi->napi_weight;
+	}
+	ndev->ethtool_ops = &fs_ethtool_ops;
+	ndev->do_ioctl = fs_ioctl;
+
+	init_timer(&fep->phy_timer_list);
+
+	netif_carrier_off(ndev);
+
+	ret = register_netdev(ndev);
+	if (ret)
+		goto out_free_bd;
+
+	printk(KERN_INFO "%s: fs_enet: %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       ndev->name,
+	       ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
+	       ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+
+	return 0;
+
+out_free_bd:
+	fep->ops->free_bd(ndev);
+out_cleanup_data:
+	fep->ops->cleanup_data(ndev);
+out_free_dev:
+	free_netdev(ndev);
+	dev_set_drvdata(&ofdev->dev, NULL);
+out_free_fpi:
+	kfree(fpi);
+	return ret;
+}
+
+static int fs_enet_remove(struct of_device *ofdev)
+{
+	struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
+	struct fs_enet_private *fep = netdev_priv(ndev);
+
+	unregister_netdev(ndev);
+
+	fep->ops->free_bd(ndev);
+	fep->ops->cleanup_data(ndev);
+	dev_set_drvdata(fep->dev, NULL);
+
+	free_netdev(ndev);
+	return 0;
+}
+
+static struct of_device_id fs_enet_match[] = {
+#ifdef CONFIG_FS_ENET_HAS_SCC
+	{
+		.compatible = "fsl,cpm1-scc-enet",
+		.data = (void *)&fs_scc_ops,
+	},
+#endif
+#ifdef CONFIG_FS_ENET_HAS_FCC
+	{
+		.compatible = "fsl,cpm2-fcc-enet",
+		.data = (void *)&fs_fcc_ops,
+	},
+#endif
+#ifdef CONFIG_FS_ENET_HAS_FEC
+	{
+		.compatible = "fsl,pq1-fec-enet",
+		.data = (void *)&fs_fec_ops,
+	},
+#endif
+	{}
+};
+
+static struct of_platform_driver fs_enet_driver = {
+	.name	= "fs_enet",
+	.match_table = fs_enet_match,
+	.probe = fs_enet_probe,
+	.remove = fs_enet_remove,
+};
+
+static int __init fs_init(void)
+{
+	int r = setup_immap();
+	if (r != 0)
+		return r;
+
+	r = of_register_platform_driver(&fs_enet_driver);
+	if (r != 0)
+		goto out;
+
+	return 0;
+
+out:
+	cleanup_immap();
+	return r;
+}
+
+static void __exit fs_cleanup(void)
+{
+	of_unregister_platform_driver(&fs_enet_driver);
+	cleanup_immap();
+}
+#else
 static int __devinit fs_enet_probe(struct device *dev)
 {
 	struct net_device *ndev;
@@ -1262,7 +1493,6 @@
 err:
 	cleanup_immap();
 	return r;
-	
 }
 
 static void __exit fs_cleanup(void)
@@ -1272,6 +1502,16 @@
 	driver_unregister(&fs_enet_scc_driver);
 	cleanup_immap();
 }
+#endif
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void fs_enet_netpoll(struct net_device *dev)
+{
+       disable_irq(dev->irq);
+       fs_enet_interrupt(dev->irq, dev, NULL);
+       enable_irq(dev->irq);
+}
+#endif
 
 /**************************************************************************************/
 
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index 569be22..baf6477 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -15,8 +15,8 @@
 #include <asm/commproc.h>
 
 struct fec_info {
-        fec_t*  fecp;
-	u32     mii_speed;
+	fec_t __iomem *fecp;
+	u32 mii_speed;
 };
 #endif
 
@@ -24,19 +24,6 @@
 #include <asm/cpm2.h>
 #endif
 
-/* This is used to operate with pins.
-  Note that the actual port size may
-    be different; cpm(s) handle it OK  */
-struct bb_info {
-	u8 mdio_dat_msk;
-	u8 mdio_dir_msk;
-	u8 *mdio_dir;
-	u8 *mdio_dat;
-	u8 mdc_msk;
-	u8 *mdc_dat;
-	int delay;
-};
-
 /* hw driver ops */
 struct fs_ops {
 	int (*setup_data)(struct net_device *dev);
@@ -82,60 +69,26 @@
 /* Must be a multiple of 32 (to cover both FEC & FCC) */
 #define PKT_MAXBLR_SIZE		((PKT_MAXBUF_SIZE + 31) & ~31)
 /* This is needed so that invalidate_xxx wont invalidate too much */
-#define ENET_RX_FRSIZE		L1_CACHE_ALIGN(PKT_MAXBUF_SIZE)
-
-struct fs_enet_mii_bus {
-	struct list_head list;
-	spinlock_t mii_lock;
-	const struct fs_mii_bus_info *bus_info;
-	int refs;
-	u32 usage_map;
-
-	int (*mii_read)(struct fs_enet_mii_bus *bus,
-			int phy_id, int location);
-
-	void (*mii_write)(struct fs_enet_mii_bus *bus,
-			int phy_id, int location, int value);
-
-	union {
-		struct {
-			unsigned int mii_speed;
-			void *fecp;
-		} fec;
-
-		struct {
-			/* note that the actual port size may */
-			/* be different; cpm(s) handle it OK  */
-			u8 mdio_msk;
-			u8 *mdio_dir;
-			u8 *mdio_dat;
-			u8 mdc_msk;
-			u8 *mdc_dir;
-			u8 *mdc_dat;
-		} bitbang;
-
-		struct {
-			u16 lpa;
-		} fixed;
-	};
-};
+#define ENET_RX_ALIGN  16
+#define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE + ENET_RX_ALIGN - 1)
 
 struct fs_enet_private {
+	struct napi_struct napi;
 	struct device *dev;	/* pointer back to the device (must be initialized first) */
 	spinlock_t lock;	/* during all ops except TX pckt processing */
 	spinlock_t tx_lock;	/* during fs_start_xmit and fs_tx         */
-	const struct fs_platform_info *fpi;
+	struct fs_platform_info *fpi;
 	const struct fs_ops *ops;
 	int rx_ring, tx_ring;
 	dma_addr_t ring_mem_addr;
-	void *ring_base;
+	void __iomem *ring_base;
 	struct sk_buff **rx_skbuff;
 	struct sk_buff **tx_skbuff;
-	cbd_t *rx_bd_base;	/* Address of Rx and Tx buffers.    */
-	cbd_t *tx_bd_base;
-	cbd_t *dirty_tx;	/* ring entries to be free()ed.     */
-	cbd_t *cur_rx;
-	cbd_t *cur_tx;
+	cbd_t __iomem *rx_bd_base;	/* Address of Rx and Tx buffers.    */
+	cbd_t __iomem *tx_bd_base;
+	cbd_t __iomem *dirty_tx;	/* ring entries to be free()ed.     */
+	cbd_t __iomem *cur_rx;
+	cbd_t __iomem *cur_tx;
 	int tx_free;
 	struct net_device_stats stats;
 	struct timer_list phy_timer_list;
@@ -143,7 +96,6 @@
 	u32 msg_enable;
 	struct mii_if_info mii_if;
 	unsigned int last_mii_status;
-	struct fs_enet_mii_bus *mii_bus;
 	int interrupt;
 
 	struct phy_device *phydev;
@@ -161,23 +113,23 @@
 	union {
 		struct {
 			int idx;		/* FEC1 = 0, FEC2 = 1  */
-			void *fecp;		/* hw registers        */
+			void __iomem *fecp;	/* hw registers        */
 			u32 hthi, htlo;		/* state for multicast */
 		} fec;
 
 		struct {
 			int idx;		/* FCC1-3 = 0-2	       */
-			void *fccp;		/* hw registers	       */
-			void *ep;		/* parameter ram       */
-			void *fcccp;		/* hw registers cont.  */
-			void *mem;		/* FCC DPRAM */
+			void __iomem *fccp;	/* hw registers	       */
+			void __iomem *ep;	/* parameter ram       */
+			void __iomem *fcccp;	/* hw registers cont.  */
+			void __iomem *mem;	/* FCC DPRAM */
 			u32 gaddrh, gaddrl;	/* group address       */
 		} fcc;
 
 		struct {
 			int idx;		/* FEC1 = 0, FEC2 = 1  */
-			void *sccp;		/* hw registers        */
-			void *ep;		/* parameter ram       */
+			void __iomem *sccp;	/* hw registers        */
+			void __iomem *ep;	/* parameter ram       */
 			u32 hthi, htlo;		/* state for multicast */
 		} scc;
 
@@ -185,9 +137,10 @@
 };
 
 /***************************************************************************/
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
 int fs_enet_mdio_bb_init(void);
-int fs_mii_fixed_init(struct fs_enet_mii_bus *bus);
 int fs_enet_mdio_fec_init(void);
+#endif
 
 void fs_init_bds(struct net_device *dev);
 void fs_cleanup_bds(struct net_device *dev);
@@ -247,7 +200,7 @@
 /*******************************************************************/
 
 /* handy pointer to the immap */
-extern void *fs_enet_immap;
+extern void __iomem *fs_enet_immap;
 
 /*******************************************************************/
 
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index 5603121..da4efbc 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -1,14 +1,14 @@
 /*
  * FCC driver for Motorola MPC82xx (PQ2).
  *
- * Copyright (c) 2003 Intracom S.A. 
+ * Copyright (c) 2003 Intracom S.A.
  *  by Pantelis Antoniou <panto@intracom.gr>
  *
- * 2005 (c) MontaVista Software, Inc. 
+ * 2005 (c) MontaVista Software, Inc.
  * Vitaly Bordug <vbordug@ru.mvista.com>
  *
- * This file is licensed under the terms of the GNU General Public License 
- * version 2. This program is licensed "as is" without any warranty of any 
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
  * kind, whether express or implied.
  */
 
@@ -42,34 +42,29 @@
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <asm/of_device.h>
+#endif
+
 #include "fs_enet.h"
 
 /*************************************************/
 
 /* FCC access macros */
 
-#define __fcc_out32(addr, x)	out_be32((unsigned *)addr, x)
-#define __fcc_out16(addr, x)	out_be16((unsigned short *)addr, x)
-#define __fcc_out8(addr, x)	out_8((unsigned char *)addr, x)
-#define __fcc_in32(addr)	in_be32((unsigned *)addr)
-#define __fcc_in16(addr)	in_be16((unsigned short *)addr)
-#define __fcc_in8(addr)		in_8((unsigned char *)addr)
-
-/* parameter space */
-
 /* write, read, set bits, clear bits */
-#define W32(_p, _m, _v)	__fcc_out32(&(_p)->_m, (_v))
-#define R32(_p, _m)	__fcc_in32(&(_p)->_m)
+#define W32(_p, _m, _v)	out_be32(&(_p)->_m, (_v))
+#define R32(_p, _m)	in_be32(&(_p)->_m)
 #define S32(_p, _m, _v)	W32(_p, _m, R32(_p, _m) | (_v))
 #define C32(_p, _m, _v)	W32(_p, _m, R32(_p, _m) & ~(_v))
 
-#define W16(_p, _m, _v)	__fcc_out16(&(_p)->_m, (_v))
-#define R16(_p, _m)	__fcc_in16(&(_p)->_m)
+#define W16(_p, _m, _v)	out_be16(&(_p)->_m, (_v))
+#define R16(_p, _m)	in_be16(&(_p)->_m)
 #define S16(_p, _m, _v)	W16(_p, _m, R16(_p, _m) | (_v))
 #define C16(_p, _m, _v)	W16(_p, _m, R16(_p, _m) & ~(_v))
 
-#define W8(_p, _m, _v)	__fcc_out8(&(_p)->_m, (_v))
-#define R8(_p, _m)	__fcc_in8(&(_p)->_m)
+#define W8(_p, _m, _v)	out_8(&(_p)->_m, (_v))
+#define R8(_p, _m)	in_8(&(_p)->_m)
 #define S8(_p, _m, _v)	W8(_p, _m, R8(_p, _m) | (_v))
 #define C8(_p, _m, _v)	W8(_p, _m, R8(_p, _m) & ~(_v))
 
@@ -83,34 +78,62 @@
 
 #define MAX_CR_CMD_LOOPS	10000
 
-static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op)
+static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 op)
 {
 	const struct fs_platform_info *fpi = fep->fpi;
-
-	cpm2_map_t *immap = fs_enet_immap;
-	cpm_cpm2_t *cpmp = &immap->im_cpm;
-	u32 v;
 	int i;
 
-	/* Currently I don't know what feature call will look like. But 
-	   I guess there'd be something like do_cpm_cmd() which will require page & sblock */
-	v = mk_cr_cmd(fpi->cp_page, fpi->cp_block, mcn, op);
-	W32(cpmp, cp_cpcr, v | CPM_CR_FLG);
+	W32(cpmp, cp_cpcr, fpi->cp_command | op | CPM_CR_FLG);
 	for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
 		if ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) == 0)
-			break;
+			return 0;
 
-	if (i >= MAX_CR_CMD_LOOPS) {
-		printk(KERN_ERR "%s(): Not able to issue CPM command\n",
-		       __FUNCTION__);
-		return 1;
-	}
-
-	return 0;
+	printk(KERN_ERR "%s(): Not able to issue CPM command\n",
+	       __FUNCTION__);
+	return 1;
 }
 
 static int do_pd_setup(struct fs_enet_private *fep)
 {
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+	struct of_device *ofdev = to_of_device(fep->dev);
+	struct fs_platform_info *fpi = fep->fpi;
+	int ret = -EINVAL;
+
+	fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+	if (fep->interrupt == NO_IRQ)
+		goto out;
+
+	fep->fcc.fccp = of_iomap(ofdev->node, 0);
+	if (!fep->fcc.fccp)
+		goto out;
+
+	fep->fcc.ep = of_iomap(ofdev->node, 1);
+	if (!fep->fcc.ep)
+		goto out_fccp;
+
+	fep->fcc.fcccp = of_iomap(ofdev->node, 2);
+	if (!fep->fcc.fcccp)
+		goto out_ep;
+
+	fep->fcc.mem = (void __iomem *)cpm2_immr;
+	fpi->dpram_offset = cpm_dpalloc(128, 8);
+	if (IS_ERR_VALUE(fpi->dpram_offset)) {
+		ret = fpi->dpram_offset;
+		goto out_fcccp;
+	}
+
+	return 0;
+
+out_fcccp:
+	iounmap(fep->fcc.fcccp);
+out_ep:
+	iounmap(fep->fcc.ep);
+out_fccp:
+	iounmap(fep->fcc.fccp);
+out:
+	return ret;
+#else
 	struct platform_device *pdev = to_platform_device(fep->dev);
 	struct resource *r;
 
@@ -121,33 +144,33 @@
 
 	/* Attach the memory for the FCC Parameter RAM */
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram");
-	fep->fcc.ep = (void *)ioremap(r->start, r->end - r->start + 1);
+	fep->fcc.ep = ioremap(r->start, r->end - r->start + 1);
 	if (fep->fcc.ep == NULL)
 		return -EINVAL;
 
 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs");
-	fep->fcc.fccp = (void *)ioremap(r->start, r->end - r->start + 1);
+	fep->fcc.fccp = ioremap(r->start, r->end - r->start + 1);
 	if (fep->fcc.fccp == NULL)
 		return -EINVAL;
 
 	if (fep->fpi->fcc_regs_c) {
-
-		fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c;
+		fep->fcc.fcccp = (void __iomem *)fep->fpi->fcc_regs_c;
 	} else {
 		r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
 				"fcc_regs_c");
-		fep->fcc.fcccp = (void *)ioremap(r->start,
+		fep->fcc.fcccp = ioremap(r->start,
 				r->end - r->start + 1);
 	}
 
 	if (fep->fcc.fcccp == NULL)
 		return -EINVAL;
 
-	fep->fcc.mem = (void *)fep->fpi->mem_offset;
+	fep->fcc.mem = (void __iomem *)fep->fpi->mem_offset;
 	if (fep->fcc.mem == NULL)
 		return -EINVAL;
 
 	return 0;
+#endif
 }
 
 #define FCC_NAPI_RX_EVENT_MSK	(FCC_ENET_RXF | FCC_ENET_RXB)
@@ -158,11 +181,17 @@
 static int setup_data(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	const struct fs_platform_info *fpi = fep->fpi;
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
+	struct fs_platform_info *fpi = fep->fpi;
+
+	fpi->cp_command = (fpi->cp_page << 26) |
+	                  (fpi->cp_block << 21) |
+	                  (12 << 6);
 
 	fep->fcc.idx = fs_get_fcc_index(fpi->fs_no);
 	if ((unsigned int)fep->fcc.idx >= 3)	/* max 3 FCCs */
 		return -EINVAL;
+#endif
 
 	if (do_pd_setup(fep) != 0)
 		return -EINVAL;
@@ -180,7 +209,7 @@
 	struct fs_enet_private *fep = netdev_priv(dev);
 	const struct fs_platform_info *fpi = fep->fpi;
 
-	fep->ring_base = dma_alloc_coherent(fep->dev,
+	fep->ring_base = (void __iomem __force *)dma_alloc_coherent(fep->dev,
 					    (fpi->tx_ring + fpi->rx_ring) *
 					    sizeof(cbd_t), &fep->ring_mem_addr,
 					    GFP_KERNEL);
@@ -198,7 +227,7 @@
 	if (fep->ring_base)
 		dma_free_coherent(fep->dev,
 			(fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t),
-			fep->ring_base, fep->ring_mem_addr);
+			(void __force *)fep->ring_base, fep->ring_mem_addr);
 }
 
 static void cleanup_data(struct net_device *dev)
@@ -209,7 +238,7 @@
 static void set_promiscuous_mode(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fcc_t *fccp = fep->fcc.fccp;
+	fcc_t __iomem *fccp = fep->fcc.fccp;
 
 	S32(fccp, fcc_fpsmr, FCC_PSMR_PRO);
 }
@@ -217,7 +246,7 @@
 static void set_multicast_start(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fcc_enet_t *ep = fep->fcc.ep;
+	fcc_enet_t __iomem *ep = fep->fcc.ep;
 
 	W32(ep, fen_gaddrh, 0);
 	W32(ep, fen_gaddrl, 0);
@@ -226,7 +255,7 @@
 static void set_multicast_one(struct net_device *dev, const u8 *mac)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fcc_enet_t *ep = fep->fcc.ep;
+	fcc_enet_t __iomem *ep = fep->fcc.ep;
 	u16 taddrh, taddrm, taddrl;
 
 	taddrh = ((u16)mac[5] << 8) | mac[4];
@@ -236,14 +265,14 @@
 	W16(ep, fen_taddrh, taddrh);
 	W16(ep, fen_taddrm, taddrm);
 	W16(ep, fen_taddrl, taddrl);
-	fcc_cr_cmd(fep, 0x0C, CPM_CR_SET_GADDR);
+	fcc_cr_cmd(fep, CPM_CR_SET_GADDR);
 }
 
 static void set_multicast_finish(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fcc_t *fccp = fep->fcc.fccp;
-	fcc_enet_t *ep = fep->fcc.ep;
+	fcc_t __iomem *fccp = fep->fcc.fccp;
+	fcc_enet_t __iomem *ep = fep->fcc.ep;
 
 	/* clear promiscuous always */
 	C32(fccp, fcc_fpsmr, FCC_PSMR_PRO);
@@ -278,12 +307,14 @@
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
 	const struct fs_platform_info *fpi = fep->fpi;
-	fcc_t *fccp = fep->fcc.fccp;
-	fcc_c_t *fcccp = fep->fcc.fcccp;
-	fcc_enet_t *ep = fep->fcc.ep;
+	fcc_t __iomem *fccp = fep->fcc.fccp;
+	fcc_c_t __iomem *fcccp = fep->fcc.fcccp;
+	fcc_enet_t __iomem *ep = fep->fcc.ep;
 	dma_addr_t rx_bd_base_phys, tx_bd_base_phys;
 	u16 paddrh, paddrm, paddrl;
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
 	u16 mem_addr;
+#endif
 	const unsigned char *mac;
 	int i;
 
@@ -291,7 +322,7 @@
 
 	/* clear everything (slow & steady does it) */
 	for (i = 0; i < sizeof(*ep); i++)
-		__fcc_out8((char *)ep + i, 0);
+		out_8((u8 __iomem *)ep + i, 0);
 
 	/* get physical address */
 	rx_bd_base_phys = fep->ring_mem_addr;
@@ -315,14 +346,22 @@
 	 * this area.
 	 */
 
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+	W16(ep, fen_genfcc.fcc_riptr, fpi->dpram_offset);
+	W16(ep, fen_genfcc.fcc_tiptr, fpi->dpram_offset + 32);
+
+	W16(ep, fen_padptr, fpi->dpram_offset + 64);
+#else
 	mem_addr = (u32) fep->fcc.mem;	/* de-fixup dpram offset */
 
 	W16(ep, fen_genfcc.fcc_riptr, (mem_addr & 0xffff));
 	W16(ep, fen_genfcc.fcc_tiptr, ((mem_addr + 32) & 0xffff));
+
 	W16(ep, fen_padptr, mem_addr + 64);
+#endif
 
 	/* fill with special symbol...  */
-	memset(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32);
+	memset_io(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32);
 
 	W32(ep, fen_genfcc.fcc_rbptr, 0);
 	W32(ep, fen_genfcc.fcc_tbptr, 0);
@@ -407,7 +446,7 @@
 			S8(fcccp, fcc_gfemr, 0x20);
 	}
 
-	fcc_cr_cmd(fep, 0x0c, CPM_CR_INIT_TRX);
+	fcc_cr_cmd(fep, CPM_CR_INIT_TRX);
 
 	/* clear events */
 	W16(fccp, fcc_fcce, 0xffff);
@@ -438,7 +477,7 @@
 static void stop(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fcc_t *fccp = fep->fcc.fccp;
+	fcc_t __iomem *fccp = fep->fcc.fccp;
 
 	/* stop ethernet */
 	C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT);
@@ -465,7 +504,7 @@
 static void napi_clear_rx_event(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fcc_t *fccp = fep->fcc.fccp;
+	fcc_t __iomem *fccp = fep->fcc.fccp;
 
 	W16(fccp, fcc_fcce, FCC_NAPI_RX_EVENT_MSK);
 }
@@ -473,7 +512,7 @@
 static void napi_enable_rx(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fcc_t *fccp = fep->fcc.fccp;
+	fcc_t __iomem *fccp = fep->fcc.fccp;
 
 	S16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK);
 }
@@ -481,7 +520,7 @@
 static void napi_disable_rx(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fcc_t *fccp = fep->fcc.fccp;
+	fcc_t __iomem *fccp = fep->fcc.fccp;
 
 	C16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK);
 }
@@ -494,15 +533,15 @@
 static void tx_kickstart(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fcc_t *fccp = fep->fcc.fccp;
+	fcc_t __iomem *fccp = fep->fcc.fccp;
 
-	S32(fccp, fcc_ftodr, 0x80);
+	S16(fccp, fcc_ftodr, 0x8000);
 }
 
 static u32 get_int_events(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fcc_t *fccp = fep->fcc.fccp;
+	fcc_t __iomem *fccp = fep->fcc.fccp;
 
 	return (u32)R16(fccp, fcc_fcce);
 }
@@ -510,7 +549,7 @@
 static void clear_int_events(struct net_device *dev, u32 int_events)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fcc_t *fccp = fep->fcc.fccp;
+	fcc_t __iomem *fccp = fep->fcc.fccp;
 
 	W16(fccp, fcc_fcce, int_events & 0xffff);
 }
@@ -521,47 +560,46 @@
 	       ": %s FS_ENET ERROR(s) 0x%x\n", dev->name, int_events);
 }
 
-int get_regs(struct net_device *dev, void *p, int *sizep)
+static int get_regs(struct net_device *dev, void *p, int *sizep)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
 
-	if (*sizep < sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t))
+	if (*sizep < sizeof(fcc_t) + sizeof(fcc_enet_t) + 1)
 		return -EINVAL;
 
 	memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t));
 	p = (char *)p + sizeof(fcc_t);
 
-	memcpy_fromio(p, fep->fcc.fcccp, sizeof(fcc_c_t));
-	p = (char *)p + sizeof(fcc_c_t);
-
 	memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t));
+	p = (char *)p + sizeof(fcc_enet_t);
 
+	memcpy_fromio(p, fep->fcc.fcccp, 1);
 	return 0;
 }
 
-int get_regs_len(struct net_device *dev)
+static int get_regs_len(struct net_device *dev)
 {
-	return sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t);
+	return sizeof(fcc_t) + sizeof(fcc_enet_t) + 1;
 }
 
 /* Some transmit errors cause the transmitter to shut
  * down.  We now issue a restart transmit.  Since the
  * errors close the BD and update the pointers, the restart
  * _should_ pick up without having to reset any of our
- * pointers either.  Also, To workaround 8260 device erratum 
+ * pointers either.  Also, To workaround 8260 device erratum
  * CPM37, we must disable and then re-enable the transmitter
  * following a Late Collision, Underrun, or Retry Limit error.
  */
-void tx_restart(struct net_device *dev)
+static void tx_restart(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fcc_t *fccp = fep->fcc.fccp;
+	fcc_t __iomem *fccp = fep->fcc.fccp;
 
 	C32(fccp, fcc_gfmr, FCC_GFMR_ENT);
 	udelay(10);
 	S32(fccp, fcc_gfmr, FCC_GFMR_ENT);
 
-	fcc_cr_cmd(fep, 0x0C, CPM_CR_RESTART_TX);
+	fcc_cr_cmd(fep, CPM_CR_RESTART_TX);
 }
 
 /*************************************************************************/
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index 04b4f80..c1fee48 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -1,14 +1,14 @@
 /*
  * Freescale Ethernet controllers
  *
- * Copyright (c) 2005 Intracom S.A. 
+ * Copyright (c) 2005 Intracom S.A.
  *  by Pantelis Antoniou <panto@intracom.gr>
  *
- * 2005 (c) MontaVista Software, Inc. 
+ * 2005 (c) MontaVista Software, Inc.
  * Vitaly Bordug <vbordug@ru.mvista.com>
  *
- * This file is licensed under the terms of the GNU General Public License 
- * version 2. This program is licensed "as is" without any warranty of any 
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
  * kind, whether express or implied.
  */
 
@@ -43,6 +43,10 @@
 #include <asm/commproc.h>
 #endif
 
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <asm/of_device.h>
+#endif
+
 #include "fs_enet.h"
 #include "fec.h"
 
@@ -79,7 +83,7 @@
  */
 #define FEC_RESET_DELAY		50
 
-static int whack_reset(fec_t * fecp)
+static int whack_reset(fec_t __iomem *fecp)
 {
 	int i;
 
@@ -95,9 +99,22 @@
 
 static int do_pd_setup(struct fs_enet_private *fep)
 {
-	struct platform_device *pdev = to_platform_device(fep->dev); 
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+	struct of_device *ofdev = to_of_device(fep->dev);
+
+	fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+	if (fep->interrupt == NO_IRQ)
+		return -EINVAL;
+
+	fep->fec.fecp = of_iomap(ofdev->node, 0);
+	if (!fep->fcc.fccp)
+		return -EINVAL;
+
+	return 0;
+#else
+	struct platform_device *pdev = to_platform_device(fep->dev);
 	struct resource	*r;
-	
+
 	/* Fill out IRQ field */
 	fep->interrupt = platform_get_irq_byname(pdev,"interrupt");
 	if (fep->interrupt < 0)
@@ -110,7 +127,7 @@
 		return -EINVAL;
 
 	return 0;
-	
+#endif
 }
 
 #define FEC_NAPI_RX_EVENT_MSK	(FEC_ENET_RXF | FEC_ENET_RXB)
@@ -141,8 +158,8 @@
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
 	const struct fs_platform_info *fpi = fep->fpi;
-	
-	fep->ring_base = dma_alloc_coherent(fep->dev,
+
+	fep->ring_base = (void __force __iomem *)dma_alloc_coherent(fep->dev,
 					    (fpi->tx_ring + fpi->rx_ring) *
 					    sizeof(cbd_t), &fep->ring_mem_addr,
 					    GFP_KERNEL);
@@ -160,7 +177,7 @@
 	if(fep->ring_base)
 		dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring)
 					* sizeof(cbd_t),
-					fep->ring_base,
+					(void __force *)fep->ring_base,
 					fep->ring_mem_addr);
 }
 
@@ -172,7 +189,7 @@
 static void set_promiscuous_mode(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fec_t *fecp = fep->fec.fecp;
+	fec_t __iomem *fecp = fep->fec.fecp;
 
 	FS(fecp, r_cntrl, FEC_RCNTRL_PROM);
 }
@@ -220,7 +237,7 @@
 static void set_multicast_finish(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fec_t *fecp = fep->fec.fecp;
+	fec_t __iomem *fecp = fep->fec.fecp;
 
 	/* if all multi or too many multicasts; just enable all */
 	if ((dev->flags & IFF_ALLMULTI) != 0 ||
@@ -254,7 +271,7 @@
 	u32 cptr;
 #endif
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fec_t *fecp = fep->fec.fecp;
+	fec_t __iomem *fecp = fep->fec.fecp;
 	const struct fs_platform_info *fpi = fep->fpi;
 	dma_addr_t rx_bd_base_phys, tx_bd_base_phys;
 	int r;
@@ -280,13 +297,13 @@
 	FW(fecp, addr_high, addrlo);
 
 	/*
-	 * Reset all multicast. 
+	 * Reset all multicast.
 	 */
 	FW(fecp, hash_table_high, fep->fec.hthi);
 	FW(fecp, hash_table_low, fep->fec.htlo);
 
 	/*
-	 * Set maximum receive buffer size. 
+	 * Set maximum receive buffer size.
 	 */
 	FW(fecp, r_buff_size, PKT_MAXBLR_SIZE);
 	FW(fecp, r_hash, PKT_MAXBUF_SIZE);
@@ -296,7 +313,7 @@
 	tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring;
 
 	/*
-	 * Set receive and transmit descriptor base. 
+	 * Set receive and transmit descriptor base.
 	 */
 	FW(fecp, r_des_start, rx_bd_base_phys);
 	FW(fecp, x_des_start, tx_bd_base_phys);
@@ -304,7 +321,7 @@
 	fs_init_bds(dev);
 
 	/*
-	 * Enable big endian and don't care about SDMA FC. 
+	 * Enable big endian and don't care about SDMA FC.
 	 */
 	FW(fecp, fun_code, 0x78000000);
 
@@ -366,13 +383,13 @@
 	}
 
 	/*
-	 * Enable interrupts we wish to service. 
+	 * Enable interrupts we wish to service.
 	 */
 	FW(fecp, imask, FEC_ENET_TXF | FEC_ENET_TXB |
 	   FEC_ENET_RXF | FEC_ENET_RXB);
 
 	/*
-	 * And last, enable the transmit and receive processing. 
+	 * And last, enable the transmit and receive processing.
 	 */
 	FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
 	FW(fecp, r_des_active, 0x01000000);
@@ -382,7 +399,7 @@
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
 	const struct fs_platform_info *fpi = fep->fpi;
-	fec_t *fecp = fep->fec.fecp;
+	fec_t __iomem *fecp = fep->fec.fecp;
 
 	struct fec_info* feci= fep->phydev->bus->priv;
 
@@ -401,7 +418,7 @@
 		       ": %s FEC timeout on graceful transmit stop\n",
 		       dev->name);
 	/*
-	 * Disable FEC. Let only MII interrupts. 
+	 * Disable FEC. Let only MII interrupts.
 	 */
 	FW(fecp, imask, 0);
 	FC(fecp, ecntrl, FEC_ECNTRL_ETHER_EN);
@@ -444,7 +461,7 @@
 static void napi_clear_rx_event(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fec_t *fecp = fep->fec.fecp;
+	fec_t __iomem *fecp = fep->fec.fecp;
 
 	FW(fecp, ievent, FEC_NAPI_RX_EVENT_MSK);
 }
@@ -452,7 +469,7 @@
 static void napi_enable_rx(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fec_t *fecp = fep->fec.fecp;
+	fec_t __iomem *fecp = fep->fec.fecp;
 
 	FS(fecp, imask, FEC_NAPI_RX_EVENT_MSK);
 }
@@ -460,7 +477,7 @@
 static void napi_disable_rx(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fec_t *fecp = fep->fec.fecp;
+	fec_t __iomem *fecp = fep->fec.fecp;
 
 	FC(fecp, imask, FEC_NAPI_RX_EVENT_MSK);
 }
@@ -468,7 +485,7 @@
 static void rx_bd_done(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fec_t *fecp = fep->fec.fecp;
+	fec_t __iomem *fecp = fep->fec.fecp;
 
 	FW(fecp, r_des_active, 0x01000000);
 }
@@ -476,7 +493,7 @@
 static void tx_kickstart(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fec_t *fecp = fep->fec.fecp;
+	fec_t __iomem *fecp = fep->fec.fecp;
 
 	FW(fecp, x_des_active, 0x01000000);
 }
@@ -484,7 +501,7 @@
 static u32 get_int_events(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fec_t *fecp = fep->fec.fecp;
+	fec_t __iomem *fecp = fep->fec.fecp;
 
 	return FR(fecp, ievent) & FR(fecp, imask);
 }
@@ -492,7 +509,7 @@
 static void clear_int_events(struct net_device *dev, u32 int_events)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	fec_t *fecp = fep->fec.fecp;
+	fec_t __iomem *fecp = fep->fec.fecp;
 
 	FW(fecp, ievent, int_events);
 }
@@ -503,7 +520,7 @@
 	       ": %s FEC ERROR(s) 0x%x\n", dev->name, int_events);
 }
 
-int get_regs(struct net_device *dev, void *p, int *sizep)
+static int get_regs(struct net_device *dev, void *p, int *sizep)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
 
@@ -515,12 +532,12 @@
 	return 0;
 }
 
-int get_regs_len(struct net_device *dev)
+static int get_regs_len(struct net_device *dev)
 {
 	return sizeof(fec_t);
 }
 
-void tx_restart(struct net_device *dev)
+static void tx_restart(struct net_device *dev)
 {
 	/* nothing */
 }
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index 7540966..03134f4 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -1,14 +1,14 @@
 /*
  * Ethernet on Serial Communications Controller (SCC) driver for Motorola MPC8xx and MPC82xx.
  *
- * Copyright (c) 2003 Intracom S.A. 
+ * Copyright (c) 2003 Intracom S.A.
  *  by Pantelis Antoniou <panto@intracom.gr>
- * 
- * 2005 (c) MontaVista Software, Inc. 
+ *
+ * 2005 (c) MontaVista Software, Inc.
  * Vitaly Bordug <vbordug@ru.mvista.com>
  *
- * This file is licensed under the terms of the GNU General Public License 
- * version 2. This program is licensed "as is" without any warranty of any 
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
  * kind, whether express or implied.
  */
 
@@ -43,6 +43,10 @@
 #include <asm/commproc.h>
 #endif
 
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <asm/of_platform.h>
+#endif
+
 #include "fs_enet.h"
 
 /*************************************************/
@@ -82,34 +86,45 @@
 #define SCC_MAX_MULTICAST_ADDRS	64
 
 /*
- * Delay to wait for SCC reset command to complete (in us) 
+ * Delay to wait for SCC reset command to complete (in us)
  */
 #define SCC_RESET_DELAY		50
 #define MAX_CR_CMD_LOOPS	10000
 
 static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op)
 {
-	cpm8xx_t *cpmp = &((immap_t *)fs_enet_immap)->im_cpm;
-	u32 v, ch;
-	int i = 0;
+	const struct fs_platform_info *fpi = fep->fpi;
+	int i;
 
-	ch = fep->scc.idx << 2;
-	v = mk_cr_cmd(ch, op);
-	W16(cpmp, cp_cpcr, v | CPM_CR_FLG);
+	W16(cpmp, cp_cpcr, fpi->cp_command | CPM_CR_FLG | (op << 8));
 	for (i = 0; i < MAX_CR_CMD_LOOPS; i++)
 		if ((R16(cpmp, cp_cpcr) & CPM_CR_FLG) == 0)
-			break;
+			return 0;
 
-	if (i >= MAX_CR_CMD_LOOPS) {
-		printk(KERN_ERR "%s(): Not able to issue CPM command\n",
-			__FUNCTION__);
-		return 1;
-	}
-	return 0;
+	printk(KERN_ERR "%s(): Not able to issue CPM command\n",
+		__FUNCTION__);
+	return 1;
 }
 
 static int do_pd_setup(struct fs_enet_private *fep)
 {
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+	struct of_device *ofdev = to_of_device(fep->dev);
+
+	fep->interrupt = of_irq_to_resource(ofdev->node, 0, NULL);
+	if (fep->interrupt == NO_IRQ)
+		return -EINVAL;
+
+	fep->scc.sccp = of_iomap(ofdev->node, 0);
+	if (!fep->scc.sccp)
+		return -EINVAL;
+
+	fep->scc.ep = of_iomap(ofdev->node, 1);
+	if (!fep->scc.ep) {
+		iounmap(fep->scc.sccp);
+		return -EINVAL;
+	}
+#else
 	struct platform_device *pdev = to_platform_device(fep->dev);
 	struct resource *r;
 
@@ -129,6 +144,7 @@
 
 	if (fep->scc.ep == NULL)
 		return -EINVAL;
+#endif
 
 	return 0;
 }
@@ -141,12 +157,17 @@
 static int setup_data(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	const struct fs_platform_info *fpi = fep->fpi;
+
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+	struct fs_platform_info *fpi = fep->fpi;
 
 	fep->scc.idx = fs_get_scc_index(fpi->fs_no);
-	if ((unsigned int)fep->fcc.idx > 4)	/* max 4 SCCs */
+	if ((unsigned int)fep->fcc.idx >= 4) /* max 4 SCCs */
 		return -EINVAL;
 
+	fpi->cp_command = fep->fcc.idx << 6;
+#endif
+
 	do_pd_setup(fep);
 
 	fep->scc.hthi = 0;
@@ -154,7 +175,7 @@
 
 	fep->ev_napi_rx = SCC_NAPI_RX_EVENT_MSK;
 	fep->ev_rx = SCC_RX_EVENT;
-	fep->ev_tx = SCC_TX_EVENT;
+	fep->ev_tx = SCC_TX_EVENT | SCCE_ENET_TXE;
 	fep->ev_err = SCC_ERR_EVENT_MSK;
 
 	return 0;
@@ -170,7 +191,8 @@
 	if (IS_ERR_VALUE(fep->ring_mem_addr))
 		return -ENOMEM;
 
-	fep->ring_base = cpm_dpram_addr(fep->ring_mem_addr);
+	fep->ring_base = (void __iomem __force*)
+		cpm_dpram_addr(fep->ring_mem_addr);
 
 	return 0;
 }
@@ -189,9 +211,9 @@
 }
 
 static void set_promiscuous_mode(struct net_device *dev)
-{				
+{
 	struct fs_enet_private *fep = netdev_priv(dev);
-	scc_t *sccp = fep->scc.sccp;
+	scc_t __iomem *sccp = fep->scc.sccp;
 
 	S16(sccp, scc_psmr, SCC_PSMR_PRO);
 }
@@ -199,7 +221,7 @@
 static void set_multicast_start(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	scc_enet_t *ep = fep->scc.ep;
+	scc_enet_t __iomem *ep = fep->scc.ep;
 
 	W16(ep, sen_gaddr1, 0);
 	W16(ep, sen_gaddr2, 0);
@@ -210,7 +232,7 @@
 static void set_multicast_one(struct net_device *dev, const u8 * mac)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	scc_enet_t *ep = fep->scc.ep;
+	scc_enet_t __iomem *ep = fep->scc.ep;
 	u16 taddrh, taddrm, taddrl;
 
 	taddrh = ((u16) mac[5] << 8) | mac[4];
@@ -226,8 +248,8 @@
 static void set_multicast_finish(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	scc_t *sccp = fep->scc.sccp;
-	scc_enet_t *ep = fep->scc.ep;
+	scc_t __iomem *sccp = fep->scc.sccp;
+	scc_enet_t __iomem *ep = fep->scc.ep;
 
 	/* clear promiscuous always */
 	C16(sccp, scc_psmr, SCC_PSMR_PRO);
@@ -264,8 +286,8 @@
 static void restart(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	scc_t *sccp = fep->scc.sccp;
-	scc_enet_t *ep = fep->scc.ep;
+	scc_t __iomem *sccp = fep->scc.sccp;
+	scc_enet_t __iomem *ep = fep->scc.ep;
 	const struct fs_platform_info *fpi = fep->fpi;
 	u16 paddrh, paddrm, paddrl;
 	const unsigned char *mac;
@@ -275,7 +297,7 @@
 
 	/* clear everything (slow & steady does it) */
 	for (i = 0; i < sizeof(*ep); i++)
-		__fs_out8((char *)ep + i, 0);
+		__fs_out8((u8 __iomem *)ep + i, 0);
 
 	/* point to bds */
 	W16(ep, sen_genscc.scc_rbase, fep->ring_mem_addr);
@@ -323,7 +345,7 @@
 	W16(ep, sen_iaddr3, 0);
 	W16(ep, sen_iaddr4, 0);
 
-	/* set address 
+	/* set address
 	 */
 	mac = dev->dev_addr;
 	paddrh = ((u16) mac[5] << 8) | mac[4];
@@ -345,7 +367,7 @@
 
 	W16(sccp, scc_scce, 0xffff);
 
-	/* Enable interrupts we wish to service. 
+	/* Enable interrupts we wish to service.
 	 */
 	W16(sccp, scc_sccm, SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB);
 
@@ -373,10 +395,10 @@
 	S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
 }
 
-static void stop(struct net_device *dev)	
+static void stop(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	scc_t *sccp = fep->scc.sccp;
+	scc_t __iomem *sccp = fep->scc.sccp;
 	int i;
 
 	for (i = 0; (R16(sccp, scc_sccm) == 0) && i < SCC_RESET_DELAY; i++)
@@ -420,7 +442,7 @@
 static void napi_clear_rx_event(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	scc_t *sccp = fep->scc.sccp;
+	scc_t __iomem *sccp = fep->scc.sccp;
 
 	W16(sccp, scc_scce, SCC_NAPI_RX_EVENT_MSK);
 }
@@ -428,7 +450,7 @@
 static void napi_enable_rx(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	scc_t *sccp = fep->scc.sccp;
+	scc_t __iomem *sccp = fep->scc.sccp;
 
 	S16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK);
 }
@@ -436,7 +458,7 @@
 static void napi_disable_rx(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	scc_t *sccp = fep->scc.sccp;
+	scc_t __iomem *sccp = fep->scc.sccp;
 
 	C16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK);
 }
@@ -454,7 +476,7 @@
 static u32 get_int_events(struct net_device *dev)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	scc_t *sccp = fep->scc.sccp;
+	scc_t __iomem *sccp = fep->scc.sccp;
 
 	return (u32) R16(sccp, scc_scce);
 }
@@ -462,7 +484,7 @@
 static void clear_int_events(struct net_device *dev, u32 int_events)
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
-	scc_t *sccp = fep->scc.sccp;
+	scc_t __iomem *sccp = fep->scc.sccp;
 
 	W16(sccp, scc_scce, int_events & 0xffff);
 }
@@ -477,20 +499,20 @@
 {
 	struct fs_enet_private *fep = netdev_priv(dev);
 
-	if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t))
+	if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t __iomem *))
 		return -EINVAL;
 
 	memcpy_fromio(p, fep->scc.sccp, sizeof(scc_t));
 	p = (char *)p + sizeof(scc_t);
 
-	memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t));
+	memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t __iomem *));
 
 	return 0;
 }
 
 static int get_regs_len(struct net_device *dev)
 {
-	return sizeof(scc_t) + sizeof(scc_enet_t);
+	return sizeof(scc_t) + sizeof(scc_enet_t __iomem *);
 }
 
 static void tx_restart(struct net_device *dev)
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
index d384010..b8e4a73 100644
--- a/drivers/net/fs_enet/mii-bitbang.c
+++ b/drivers/net/fs_enet/mii-bitbang.c
@@ -1,313 +1,287 @@
 /*
  * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
  *
- * Copyright (c) 2003 Intracom S.A. 
+ * Copyright (c) 2003 Intracom S.A.
  *  by Pantelis Antoniou <panto@intracom.gr>
- * 
- * 2005 (c) MontaVista Software, Inc. 
+ *
+ * 2005 (c) MontaVista Software, Inc.
  * Vitaly Bordug <vbordug@ru.mvista.com>
  *
- * This file is licensed under the terms of the GNU General Public License 
- * version 2. This program is licensed "as is" without any warranty of any 
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
  * kind, whether express or implied.
  */
 
-
 #include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
-#include <linux/interrupt.h>
 #include <linux/init.h>
-#include <linux/delay.h>
+#include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
 #include <linux/mii.h>
-#include <linux/ethtool.h>
-#include <linux/bitops.h>
 #include <linux/platform_device.h>
+#include <linux/mdio-bitbang.h>
 
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_platform.h>
+#endif
 
 #include "fs_enet.h"
 
-static int bitbang_prep_bit(u8 **datp, u8 *mskp,
-		struct fs_mii_bit *mii_bit)
+struct bb_info {
+	struct mdiobb_ctrl ctrl;
+	__be32 __iomem *dir;
+	__be32 __iomem *dat;
+	u32 mdio_msk;
+	u32 mdc_msk;
+};
+
+/* FIXME: If any other users of GPIO crop up, then these will have to
+ * have some sort of global synchronization to avoid races with other
+ * pins on the same port.  The ideal solution would probably be to
+ * bind the ports to a GPIO driver, and have this be a client of it.
+ */
+static inline void bb_set(u32 __iomem *p, u32 m)
 {
-	void *dat;
-	int adv;
-	u8 msk;
+	out_be32(p, in_be32(p) | m);
+}
 
-	dat = (void*) mii_bit->offset;
+static inline void bb_clr(u32 __iomem *p, u32 m)
+{
+	out_be32(p, in_be32(p) & ~m);
+}
 
-	adv = mii_bit->bit >> 3;
-	dat = (char *)dat + adv;
+static inline int bb_read(u32 __iomem *p, u32 m)
+{
+	return (in_be32(p) & m) != 0;
+}
 
-	msk = 1 << (7 - (mii_bit->bit & 7));
+static inline void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
+{
+	struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
 
-	*datp = dat;
-	*mskp = msk;
+	if (dir)
+		bb_set(bitbang->dir, bitbang->mdio_msk);
+	else
+		bb_clr(bitbang->dir, bitbang->mdio_msk);
+
+	/* Read back to flush the write. */
+	in_be32(bitbang->dir);
+}
+
+static inline int mdio_read(struct mdiobb_ctrl *ctrl)
+{
+	struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+	return bb_read(bitbang->dat, bitbang->mdio_msk);
+}
+
+static inline void mdio(struct mdiobb_ctrl *ctrl, int what)
+{
+	struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+
+	if (what)
+		bb_set(bitbang->dat, bitbang->mdio_msk);
+	else
+		bb_clr(bitbang->dat, bitbang->mdio_msk);
+
+	/* Read back to flush the write. */
+	in_be32(bitbang->dat);
+}
+
+static inline void mdc(struct mdiobb_ctrl *ctrl, int what)
+{
+	struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl);
+
+	if (what)
+		bb_set(bitbang->dat, bitbang->mdc_msk);
+	else
+		bb_clr(bitbang->dat, bitbang->mdc_msk);
+
+	/* Read back to flush the write. */
+	in_be32(bitbang->dat);
+}
+
+static struct mdiobb_ops bb_ops = {
+	.owner = THIS_MODULE,
+	.set_mdc = mdc,
+	.set_mdio_dir = mdio_dir,
+	.set_mdio_data = mdio,
+	.get_mdio_data = mdio_read,
+};
+
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static int __devinit fs_mii_bitbang_init(struct mii_bus *bus,
+                                         struct device_node *np)
+{
+	struct resource res;
+	const u32 *data;
+	int mdio_pin, mdc_pin, len;
+	struct bb_info *bitbang = bus->priv;
+
+	int ret = of_address_to_resource(np, 0, &res);
+	if (ret)
+		return ret;
+
+	if (res.end - res.start < 13)
+		return -ENODEV;
+
+	/* This should really encode the pin number as well, but all
+	 * we get is an int, and the odds of multiple bitbang mdio buses
+	 * is low enough that it's not worth going too crazy.
+	 */
+	bus->id = res.start;
+
+	data = of_get_property(np, "fsl,mdio-pin", &len);
+	if (!data || len != 4)
+		return -ENODEV;
+	mdio_pin = *data;
+
+	data = of_get_property(np, "fsl,mdc-pin", &len);
+	if (!data || len != 4)
+		return -ENODEV;
+	mdc_pin = *data;
+
+	bitbang->dir = ioremap(res.start, res.end - res.start + 1);
+	if (!bitbang->dir)
+		return -ENOMEM;
+
+	bitbang->dat = bitbang->dir + 4;
+	bitbang->mdio_msk = 1 << (31 - mdio_pin);
+	bitbang->mdc_msk = 1 << (31 - mdc_pin);
 
 	return 0;
 }
 
-static inline void bb_set(u8 *p, u8 m)
+static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
 {
-	out_8(p, in_8(p) | m);
+	const u32 *data;
+	int len, id, irq;
+
+	data = of_get_property(np, "reg", &len);
+	if (!data || len != 4)
+		return;
+
+	id = *data;
+	bus->phy_mask &= ~(1 << id);
+
+	irq = of_irq_to_resource(np, 0, NULL);
+	if (irq != NO_IRQ)
+		bus->irq[id] = irq;
 }
 
-static inline void bb_clr(u8 *p, u8 m)
+static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
+                                        const struct of_device_id *match)
 {
-	out_8(p, in_8(p) & ~m);
-}
+	struct device_node *np = NULL;
+	struct mii_bus *new_bus;
+	struct bb_info *bitbang;
+	int ret = -ENOMEM;
+	int i;
 
-static inline int bb_read(u8 *p, u8 m)
-{
-	return (in_8(p) & m) != 0;
-}
-
-static inline void mdio_active(struct bb_info *bitbang)
-{
-	bb_set(bitbang->mdio_dir, bitbang->mdio_dir_msk);
-}
-
-static inline void mdio_tristate(struct bb_info *bitbang )
-{
-	bb_clr(bitbang->mdio_dir, bitbang->mdio_dir_msk);
-}
-
-static inline int mdio_read(struct bb_info *bitbang )
-{
-	return bb_read(bitbang->mdio_dat, bitbang->mdio_dat_msk);
-}
-
-static inline void mdio(struct bb_info *bitbang , int what)
-{
-	if (what)
-		bb_set(bitbang->mdio_dat, bitbang->mdio_dat_msk);
-	else
-		bb_clr(bitbang->mdio_dat, bitbang->mdio_dat_msk);
-}
-
-static inline void mdc(struct bb_info *bitbang , int what)
-{
-	if (what)
-		bb_set(bitbang->mdc_dat, bitbang->mdc_msk);
-	else
-		bb_clr(bitbang->mdc_dat, bitbang->mdc_msk);
-}
-
-static inline void mii_delay(struct bb_info *bitbang )
-{
-	udelay(bitbang->delay);
-}
-
-/* Utility to send the preamble, address, and register (common to read and write). */
-static void bitbang_pre(struct bb_info *bitbang , int read, u8 addr, u8 reg)
-{
-	int j;
-
-	/*
-	 * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure.
-	 * The IEEE spec says this is a PHY optional requirement.  The AMD
-	 * 79C874 requires one after power up and one after a MII communications
-	 * error.  This means that we are doing more preambles than we need,
-	 * but it is safer and will be much more robust.
-	 */
-
-	mdio_active(bitbang);
-	mdio(bitbang, 1);
-	for (j = 0; j < 32; j++) {
-		mdc(bitbang, 0);
-		mii_delay(bitbang);
-		mdc(bitbang, 1);
-		mii_delay(bitbang);
-	}
-
-	/* send the start bit (01) and the read opcode (10) or write (10) */
-	mdc(bitbang, 0);
-	mdio(bitbang, 0);
-	mii_delay(bitbang);
-	mdc(bitbang, 1);
-	mii_delay(bitbang);
-	mdc(bitbang, 0);
-	mdio(bitbang, 1);
-	mii_delay(bitbang);
-	mdc(bitbang, 1);
-	mii_delay(bitbang);
-	mdc(bitbang, 0);
-	mdio(bitbang, read);
-	mii_delay(bitbang);
-	mdc(bitbang, 1);
-	mii_delay(bitbang);
-	mdc(bitbang, 0);
-	mdio(bitbang, !read);
-	mii_delay(bitbang);
-	mdc(bitbang, 1);
-	mii_delay(bitbang);
-
-	/* send the PHY address */
-	for (j = 0; j < 5; j++) {
-		mdc(bitbang, 0);
-		mdio(bitbang, (addr & 0x10) != 0);
-		mii_delay(bitbang);
-		mdc(bitbang, 1);
-		mii_delay(bitbang);
-		addr <<= 1;
-	}
-
-	/* send the register address */
-	for (j = 0; j < 5; j++) {
-		mdc(bitbang, 0);
-		mdio(bitbang, (reg & 0x10) != 0);
-		mii_delay(bitbang);
-		mdc(bitbang, 1);
-		mii_delay(bitbang);
-		reg <<= 1;
-	}
-}
-
-static int fs_enet_mii_bb_read(struct mii_bus *bus , int phy_id, int location)
-{
-	u16 rdreg;
-	int ret, j;
-	u8 addr = phy_id & 0xff;
-	u8 reg = location & 0xff;
-	struct bb_info* bitbang = bus->priv;
-
-	bitbang_pre(bitbang, 1, addr, reg);
-
-	/* tri-state our MDIO I/O pin so we can read */
-	mdc(bitbang, 0);
-	mdio_tristate(bitbang);
-	mii_delay(bitbang);
-	mdc(bitbang, 1);
-	mii_delay(bitbang);
-
-	/* check the turnaround bit: the PHY should be driving it to zero */
-	if (mdio_read(bitbang) != 0) {
-		/* PHY didn't drive TA low */
-		for (j = 0; j < 32; j++) {
-			mdc(bitbang, 0);
-			mii_delay(bitbang);
-			mdc(bitbang, 1);
-			mii_delay(bitbang);
-		}
-		ret = -1;
+	bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
+	if (!bitbang)
 		goto out;
-	}
 
-	mdc(bitbang, 0);
-	mii_delay(bitbang);
+	bitbang->ctrl.ops = &bb_ops;
 
-	/* read 16 bits of register data, MSB first */
-	rdreg = 0;
-	for (j = 0; j < 16; j++) {
-		mdc(bitbang, 1);
-		mii_delay(bitbang);
-		rdreg <<= 1;
-		rdreg |= mdio_read(bitbang);
-		mdc(bitbang, 0);
-		mii_delay(bitbang);
-	}
+	new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
+	if (!new_bus)
+		goto out_free_priv;
 
-	mdc(bitbang, 1);
-	mii_delay(bitbang);
-	mdc(bitbang, 0);
-	mii_delay(bitbang);
-	mdc(bitbang, 1);
-	mii_delay(bitbang);
+	new_bus->name = "CPM2 Bitbanged MII",
 
-	ret = rdreg;
+	ret = fs_mii_bitbang_init(new_bus, ofdev->node);
+	if (ret)
+		goto out_free_bus;
+
+	new_bus->phy_mask = ~0;
+	new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+	if (!new_bus->irq)
+		goto out_unmap_regs;
+
+	for (i = 0; i < PHY_MAX_ADDR; i++)
+		new_bus->irq[i] = -1;
+
+	while ((np = of_get_next_child(ofdev->node, np)))
+		if (!strcmp(np->type, "ethernet-phy"))
+			add_phy(new_bus, np);
+
+	new_bus->dev = &ofdev->dev;
+	dev_set_drvdata(&ofdev->dev, new_bus);
+
+	ret = mdiobus_register(new_bus);
+	if (ret)
+		goto out_free_irqs;
+
+	return 0;
+
+out_free_irqs:
+	dev_set_drvdata(&ofdev->dev, NULL);
+	kfree(new_bus->irq);
+out_unmap_regs:
+	iounmap(bitbang->dir);
+out_free_bus:
+	kfree(new_bus);
+out_free_priv:
+	free_mdio_bitbang(new_bus);
 out:
 	return ret;
 }
 
-static int fs_enet_mii_bb_write(struct mii_bus *bus, int phy_id, int location, u16 val)
+static int fs_enet_mdio_remove(struct of_device *ofdev)
 {
-	int j;
-	struct bb_info* bitbang = bus->priv;
+	struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
+	struct bb_info *bitbang = bus->priv;
 
-	u8 addr = phy_id & 0xff;
-	u8 reg = location & 0xff;
-	u16 value = val & 0xffff;
-
-	bitbang_pre(bitbang, 0, addr, reg);
-
-	/* send the turnaround (10) */
-	mdc(bitbang, 0);
-	mdio(bitbang, 1);
-	mii_delay(bitbang);
-	mdc(bitbang, 1);
-	mii_delay(bitbang);
-	mdc(bitbang, 0);
-	mdio(bitbang, 0);
-	mii_delay(bitbang);
-	mdc(bitbang, 1);
-	mii_delay(bitbang);
-
-	/* write 16 bits of register data, MSB first */
-	for (j = 0; j < 16; j++) {
-		mdc(bitbang, 0);
-		mdio(bitbang, (value & 0x8000) != 0);
-		mii_delay(bitbang);
-		mdc(bitbang, 1);
-		mii_delay(bitbang);
-		value <<= 1;
-	}
-
-	/*
-	 * Tri-state the MDIO line.
-	 */
-	mdio_tristate(bitbang);
-	mdc(bitbang, 0);
-	mii_delay(bitbang);
-	mdc(bitbang, 1);
-	mii_delay(bitbang);
-	return 0;
-}
-
-static int fs_enet_mii_bb_reset(struct mii_bus *bus)
-{
-	/*nothing here - dunno how to reset it*/
-	return 0;
-}
-
-static int fs_mii_bitbang_init(struct bb_info *bitbang, struct fs_mii_bb_platform_info* fmpi)
-{
-	int r;
-
-	bitbang->delay = fmpi->delay;
-
-	r = bitbang_prep_bit(&bitbang->mdio_dir,
-			 &bitbang->mdio_dir_msk,
-			 &fmpi->mdio_dir);
-	if (r != 0)
-		return r;
-
-	r = bitbang_prep_bit(&bitbang->mdio_dat,
-			 &bitbang->mdio_dat_msk,
-			 &fmpi->mdio_dat);
-	if (r != 0)
-		return r;
-
-	r = bitbang_prep_bit(&bitbang->mdc_dat,
-			 &bitbang->mdc_msk,
-			 &fmpi->mdc_dat);
-	if (r != 0)
-		return r;
+	mdiobus_unregister(bus);
+	free_mdio_bitbang(bus);
+	dev_set_drvdata(&ofdev->dev, NULL);
+	kfree(bus->irq);
+	iounmap(bitbang->dir);
+	kfree(bitbang);
+	kfree(bus);
 
 	return 0;
 }
 
+static struct of_device_id fs_enet_mdio_bb_match[] = {
+	{
+		.compatible = "fsl,cpm2-mdio-bitbang",
+	},
+	{},
+};
+
+static struct of_platform_driver fs_enet_bb_mdio_driver = {
+	.name = "fsl-bb-mdio",
+	.match_table = fs_enet_mdio_bb_match,
+	.probe = fs_enet_mdio_probe,
+	.remove = fs_enet_mdio_remove,
+};
+
+static int fs_enet_mdio_bb_init(void)
+{
+	return of_register_platform_driver(&fs_enet_bb_mdio_driver);
+}
+
+static void fs_enet_mdio_bb_exit(void)
+{
+	of_unregister_platform_driver(&fs_enet_bb_mdio_driver);
+}
+
+module_init(fs_enet_mdio_bb_init);
+module_exit(fs_enet_mdio_bb_exit);
+#else
+static int __devinit fs_mii_bitbang_init(struct bb_info *bitbang,
+                                         struct fs_mii_bb_platform_info *fmpi)
+{
+	bitbang->dir = (u32 __iomem *)fmpi->mdio_dir.offset;
+	bitbang->dat = (u32 __iomem *)fmpi->mdio_dat.offset;
+	bitbang->mdio_msk = 1U << (31 - fmpi->mdio_dat.bit);
+	bitbang->mdc_msk = 1U << (31 - fmpi->mdc_dat.bit);
+
+	return 0;
+}
 
 static int __devinit fs_enet_mdio_probe(struct device *dev)
 {
@@ -320,20 +294,19 @@
 	if (NULL == dev)
 		return -EINVAL;
 
-	new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
-
-	if (NULL == new_bus)
-		return -ENOMEM;
-
 	bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
 
 	if (NULL == bitbang)
 		return -ENOMEM;
 
+	bitbang->ctrl.ops = &bb_ops;
+
+	new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
+
+	if (NULL == new_bus)
+		return -ENOMEM;
+
 	new_bus->name = "BB MII Bus",
-	new_bus->read = &fs_enet_mii_bb_read,
-	new_bus->write = &fs_enet_mii_bb_write,
-	new_bus->reset = &fs_enet_mii_bb_reset,
 	new_bus->id = pdev->id;
 
 	new_bus->phy_mask = ~0x9;
@@ -365,13 +338,12 @@
 	return 0;
 
 bus_register_fail:
+	free_mdio_bitbang(new_bus);
 	kfree(bitbang);
-	kfree(new_bus);
 
 	return err;
 }
 
-
 static int fs_enet_mdio_remove(struct device *dev)
 {
 	struct mii_bus *bus = dev_get_drvdata(dev);
@@ -380,9 +352,7 @@
 
 	dev_set_drvdata(dev, NULL);
 
-	iounmap((void *) (&bus->priv));
-	bus->priv = NULL;
-	kfree(bus);
+	free_mdio_bitbang(bus);
 
 	return 0;
 }
@@ -403,4 +373,4 @@
 {
 	driver_unregister(&fs_enet_bb_mdio_driver);
 }
-
+#endif
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index 0a563a8..a89cf15 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -36,6 +36,10 @@
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <asm/of_platform.h>
+#endif
+
 #include "fs_enet.h"
 #include "fec.h"
 
@@ -47,6 +51,7 @@
 
 #define FEC_MII_LOOPS	10000
 
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
 static int match_has_phy (struct device *dev, void* data)
 {
 	struct platform_device* pdev = container_of(dev, struct platform_device, dev);
@@ -65,7 +70,7 @@
 static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info *fmpi)
 {
 	struct resource *r;
-	fec_t *fecp;
+	fec_t __iomem *fecp;
 	char* name = "fsl-cpm-fec";
 
 	/* we need fec in order to be useful */
@@ -80,7 +85,7 @@
 
 	r = platform_get_resource_byname(fec_pdev, IORESOURCE_MEM, "regs");
 
-	fec->fecp = fecp = (fec_t*)ioremap(r->start,sizeof(fec_t));
+	fec->fecp = fecp = ioremap(r->start,sizeof(fec_t));
 	fec->mii_speed = fmpi->mii_speed;
 
 	setbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);	/* MII enable */
@@ -90,11 +95,12 @@
 
 	return 0;
 }
+#endif
 
 static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location)
 {
 	struct fec_info* fec = bus->priv;
-	fec_t *fecp = fec->fecp;
+	fec_t __iomem *fecp = fec->fecp;
 	int i, ret = -1;
 
 	if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
@@ -113,13 +119,12 @@
 	}
 
 	return ret;
-
 }
 
 static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val)
 {
 	struct fec_info* fec = bus->priv;
-	fec_t *fecp = fec->fecp;
+	fec_t __iomem *fecp = fec->fecp;
 	int i;
 
 	/* this must never happen */
@@ -146,6 +151,141 @@
 	return 0;
 }
 
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
+{
+	const u32 *data;
+	int len, id, irq;
+
+	data = of_get_property(np, "reg", &len);
+	if (!data || len != 4)
+		return;
+
+	id = *data;
+	bus->phy_mask &= ~(1 << id);
+
+	irq = of_irq_to_resource(np, 0, NULL);
+	if (irq != NO_IRQ)
+		bus->irq[id] = irq;
+}
+
+static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
+                                        const struct of_device_id *match)
+{
+	struct device_node *np = NULL;
+	struct resource res;
+	struct mii_bus *new_bus;
+	struct fec_info *fec;
+	int ret = -ENOMEM, i;
+
+	new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+	if (!new_bus)
+		goto out;
+
+	fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL);
+	if (!fec)
+		goto out_mii;
+
+	new_bus->priv = fec;
+	new_bus->name = "FEC MII Bus";
+	new_bus->read = &fs_enet_fec_mii_read;
+	new_bus->write = &fs_enet_fec_mii_write;
+	new_bus->reset = &fs_enet_fec_mii_reset;
+
+	ret = of_address_to_resource(ofdev->node, 0, &res);
+	if (ret)
+		return ret;
+
+	new_bus->id = res.start;
+
+	fec->fecp = ioremap(res.start, res.end - res.start + 1);
+	if (!fec->fecp)
+		goto out_fec;
+
+	fec->mii_speed = ((ppc_proc_freq + 4999999) / 5000000) << 1;
+
+	setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE);
+	setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX |
+	                                  FEC_ECNTRL_ETHER_EN);
+	out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII);
+	out_be32(&fec->fecp->fec_mii_speed, fec->mii_speed);
+
+	new_bus->phy_mask = ~0;
+	new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+	if (!new_bus->irq)
+		goto out_unmap_regs;
+
+	for (i = 0; i < PHY_MAX_ADDR; i++)
+		new_bus->irq[i] = -1;
+
+	while ((np = of_get_next_child(ofdev->node, np)))
+		if (!strcmp(np->type, "ethernet-phy"))
+			add_phy(new_bus, np);
+
+	new_bus->dev = &ofdev->dev;
+	dev_set_drvdata(&ofdev->dev, new_bus);
+
+	ret = mdiobus_register(new_bus);
+	if (ret)
+		goto out_free_irqs;
+
+	return 0;
+
+out_free_irqs:
+	dev_set_drvdata(&ofdev->dev, NULL);
+	kfree(new_bus->irq);
+out_unmap_regs:
+	iounmap(fec->fecp);
+out_fec:
+	kfree(fec);
+out_mii:
+	kfree(new_bus);
+out:
+	return ret;
+}
+
+static int fs_enet_mdio_remove(struct of_device *ofdev)
+{
+	struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
+	struct fec_info *fec = bus->priv;
+
+	mdiobus_unregister(bus);
+	dev_set_drvdata(&ofdev->dev, NULL);
+	kfree(bus->irq);
+	iounmap(fec->fecp);
+	kfree(fec);
+	kfree(bus);
+
+	return 0;
+}
+
+static struct of_device_id fs_enet_mdio_fec_match[] = {
+	{
+		.compatible = "fsl,pq1-fec-mdio",
+	},
+	{},
+};
+
+static struct of_platform_driver fs_enet_fec_mdio_driver = {
+	.name = "fsl-fec-mdio",
+	.match_table = fs_enet_mdio_fec_match,
+	.probe = fs_enet_mdio_probe,
+	.remove = fs_enet_mdio_remove,
+};
+
+static int fs_enet_mdio_fec_init(void)
+{
+	return of_register_platform_driver(&fs_enet_fec_mdio_driver);
+}
+
+static void fs_enet_mdio_fec_exit(void)
+{
+	of_unregister_platform_driver(&fs_enet_fec_mdio_driver);
+}
+
+module_init(fs_enet_mdio_fec_init);
+module_exit(fs_enet_mdio_fec_exit);
+#else
 static int __devinit fs_enet_fec_mdio_probe(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
@@ -236,4 +376,4 @@
 {
 	driver_unregister(&fs_enet_fec_mdio_driver);
 }
-
+#endif
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index d7a1a58..0db5e6f 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -116,7 +116,6 @@
 static void gfar_timeout(struct net_device *dev);
 static int gfar_close(struct net_device *dev);
 struct sk_buff *gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp);
-static struct net_device_stats *gfar_get_stats(struct net_device *dev);
 static int gfar_set_mac_address(struct net_device *dev);
 static int gfar_change_mtu(struct net_device *dev, int new_mtu);
 static irqreturn_t gfar_error(int irq, void *dev_id);
@@ -134,7 +133,7 @@
 extern int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id, int regnum, u16 value);
 extern int gfar_local_mdio_read(struct gfar_mii *regs, int mii_id, int regnum);
 #ifdef CONFIG_GFAR_NAPI
-static int gfar_poll(struct net_device *dev, int *budget);
+static int gfar_poll(struct napi_struct *napi, int budget);
 #endif
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void gfar_netpoll(struct net_device *dev);
@@ -171,6 +170,7 @@
 	struct resource *r;
 	int idx;
 	int err = 0;
+	DECLARE_MAC_BUF(mac);
 
 	einfo = (struct gianfar_platform_data *) pdev->dev.platform_data;
 
@@ -188,6 +188,7 @@
 		return -ENOMEM;
 
 	priv = netdev_priv(dev);
+	priv->dev = dev;
 
 	/* Set the info in the priv to the current info */
 	priv->einfo = einfo;
@@ -253,7 +254,6 @@
 	/* Set the dev->base_addr to the gfar reg region */
 	dev->base_addr = (unsigned long) (priv->regs);
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	/* Fill in the dev structure */
@@ -261,15 +261,11 @@
 	dev->hard_start_xmit = gfar_start_xmit;
 	dev->tx_timeout = gfar_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
-#ifdef CONFIG_GFAR_NAPI
-	dev->poll = gfar_poll;
-	dev->weight = GFAR_DEV_WEIGHT;
-#endif
+	netif_napi_add(dev, &priv->napi, gfar_poll, GFAR_DEV_WEIGHT);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = gfar_netpoll;
 #endif
 	dev->stop = gfar_close;
-	dev->get_stats = gfar_get_stats;
 	dev->change_mtu = gfar_change_mtu;
 	dev->mtu = 1500;
 	dev->set_multicast_list = gfar_set_multi;
@@ -361,10 +357,8 @@
 	gfar_init_sysfs(dev);
 
 	/* Print out the device info */
-	printk(KERN_INFO DEVICE_NAME, dev->name);
-	for (idx = 0; idx < 6; idx++)
-		printk("%2.2x%c", dev->dev_addr[idx], idx == 5 ? ' ' : ':');
-	printk("\n");
+	printk(KERN_INFO DEVICE_NAME "%s\n",
+	       dev->name, print_mac(mac, dev->dev_addr));
 
 	/* Even more device info helps when determining which kernel */
 	/* provided which set of benchmarks. */
@@ -420,8 +414,18 @@
 	if (ecntrl & ECNTRL_REDUCED_MODE) {
 		if (ecntrl & ECNTRL_REDUCED_MII_MODE)
 			return PHY_INTERFACE_MODE_RMII;
-		else
+		else {
+			phy_interface_t interface = priv->einfo->interface;
+
+			/*
+			 * This isn't autodetected right now, so it must
+			 * be set by the device tree or platform code.
+			 */
+			if (interface == PHY_INTERFACE_MODE_RGMII_ID)
+				return PHY_INTERFACE_MODE_RGMII_ID;
+
 			return PHY_INTERFACE_MODE_RGMII;
+		}
 	}
 
 	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT)
@@ -929,6 +933,8 @@
 {
 	int err;
 
+	napi_enable(&priv->napi);
+
 	/* Initialize a bunch of registers */
 	init_registers(dev);
 
@@ -936,10 +942,14 @@
 
 	err = init_phy(dev);
 
-	if(err)
+	if(err) {
+		napi_disable(&priv->napi);
 		return err;
+	}
 
 	err = startup_gfar(dev);
+	if (err)
+		napi_disable(&priv->napi);
 
 	netif_start_queue(dev);
 
@@ -1000,7 +1010,7 @@
 	unsigned long flags;
 
 	/* Update transmit stats */
-	priv->stats.tx_bytes += skb->len;
+	dev->stats.tx_bytes += skb->len;
 
 	/* Lock priv now */
 	spin_lock_irqsave(&priv->txlock, flags);
@@ -1073,7 +1083,7 @@
 	if (txbdp == priv->dirty_tx) {
 		netif_stop_queue(dev);
 
-		priv->stats.tx_fifo_errors++;
+		dev->stats.tx_fifo_errors++;
 	}
 
 	/* Update the current txbd to the next one */
@@ -1092,6 +1102,9 @@
 static int gfar_close(struct net_device *dev)
 {
 	struct gfar_private *priv = netdev_priv(dev);
+
+	napi_disable(&priv->napi);
+
 	stop_gfar(dev);
 
 	/* Disconnect from the PHY */
@@ -1103,14 +1116,6 @@
 	return 0;
 }
 
-/* returns a net_device_stats structure pointer */
-static struct net_device_stats * gfar_get_stats(struct net_device *dev)
-{
-	struct gfar_private *priv = netdev_priv(dev);
-
-	return &(priv->stats);
-}
-
 /* Changes the mac address if the controller is not running. */
 int gfar_set_mac_address(struct net_device *dev)
 {
@@ -1222,7 +1227,7 @@
 {
 	struct gfar_private *priv = netdev_priv(dev);
 
-	priv->stats.tx_errors++;
+	dev->stats.tx_errors++;
 
 	if (dev->flags & IFF_UP) {
 		stop_gfar(dev);
@@ -1252,12 +1257,12 @@
 		if ((bdp == priv->cur_tx) && (netif_queue_stopped(dev) == 0))
 			break;
 
-		priv->stats.tx_packets++;
+		dev->stats.tx_packets++;
 
 		/* Deferred means some collisions occurred during transmit, */
 		/* but we eventually sent the packet. */
 		if (bdp->status & TXBD_DEF)
-			priv->stats.collisions++;
+			dev->stats.collisions++;
 
 		/* Free the sk buffer associated with this TxBD */
 		dev_kfree_skb_irq(priv->tx_skbuff[priv->skb_dirtytx]);
@@ -1308,7 +1313,7 @@
 		return NULL;
 
 	alignamount = RXBUF_ALIGNMENT -
-		(((unsigned) skb->data) & (RXBUF_ALIGNMENT - 1));
+		(((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1));
 
 	/* We need the data buffer to be aligned properly.  We will reserve
 	 * as many bytes as needed to align the data properly
@@ -1329,7 +1334,7 @@
 
 static inline void count_errors(unsigned short status, struct gfar_private *priv)
 {
-	struct net_device_stats *stats = &priv->stats;
+	struct net_device_stats *stats = &dev->stats;
 	struct gfar_extra_stats *estats = &priv->extra_stats;
 
 	/* If the packet was truncated, none of the other errors
@@ -1380,12 +1385,12 @@
 
 	/* support NAPI */
 #ifdef CONFIG_GFAR_NAPI
-	if (netif_rx_schedule_prep(dev)) {
+	if (netif_rx_schedule_prep(dev, &priv->napi)) {
 		tempval = gfar_read(&priv->regs->imask);
 		tempval &= IMASK_RX_DISABLED;
 		gfar_write(&priv->regs->imask, tempval);
 
-		__netif_rx_schedule(dev);
+		__netif_rx_schedule(dev, &priv->napi);
 	} else {
 		if (netif_msg_rx_err(priv))
 			printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
@@ -1454,7 +1459,7 @@
 	if (NULL == skb) {
 		if (netif_msg_rx_err(priv))
 			printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name);
-		priv->stats.rx_dropped++;
+		dev->stats.rx_dropped++;
 		priv->extra_stats.rx_skbmissing++;
 	} else {
 		int ret;
@@ -1512,7 +1517,7 @@
 		      (RXBD_LARGE | RXBD_SHORT | RXBD_NONOCTET
 		       | RXBD_CRCERR | RXBD_OVERRUN | RXBD_TRUNCATED))) {
 			/* Increment the number of packets */
-			priv->stats.rx_packets++;
+			dev->stats.rx_packets++;
 			howmany++;
 
 			/* Remove the FCS from the packet length */
@@ -1520,7 +1525,7 @@
 
 			gfar_process_frame(dev, skb, pkt_len);
 
-			priv->stats.rx_bytes += pkt_len;
+			dev->stats.rx_bytes += pkt_len;
 		} else {
 			count_errors(bdp->status, priv);
 
@@ -1559,23 +1564,16 @@
 }
 
 #ifdef CONFIG_GFAR_NAPI
-static int gfar_poll(struct net_device *dev, int *budget)
+static int gfar_poll(struct napi_struct *napi, int budget)
 {
+	struct gfar_private *priv = container_of(napi, struct gfar_private, napi);
+	struct net_device *dev = priv->dev;
 	int howmany;
-	struct gfar_private *priv = netdev_priv(dev);
-	int rx_work_limit = *budget;
 
-	if (rx_work_limit > dev->quota)
-		rx_work_limit = dev->quota;
+	howmany = gfar_clean_rx_ring(dev, budget);
 
-	howmany = gfar_clean_rx_ring(dev, rx_work_limit);
-
-	dev->quota -= howmany;
-	rx_work_limit -= howmany;
-	*budget -= howmany;
-
-	if (rx_work_limit > 0) {
-		netif_rx_complete(dev);
+	if (howmany < budget) {
+		netif_rx_complete(dev, napi);
 
 		/* Clear the halt bit in RSTAT */
 		gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
@@ -1591,8 +1589,7 @@
 			gfar_write(&priv->regs->rxic, 0);
 	}
 
-	/* Return 1 if there's more work to do */
-	return (rx_work_limit > 0) ? 0 : 1;
+	return howmany;
 }
 #endif
 
@@ -1908,17 +1905,17 @@
 
 	/* Update the error counters */
 	if (events & IEVENT_TXE) {
-		priv->stats.tx_errors++;
+		dev->stats.tx_errors++;
 
 		if (events & IEVENT_LC)
-			priv->stats.tx_window_errors++;
+			dev->stats.tx_window_errors++;
 		if (events & IEVENT_CRL)
-			priv->stats.tx_aborted_errors++;
+			dev->stats.tx_aborted_errors++;
 		if (events & IEVENT_XFUN) {
 			if (netif_msg_tx_err(priv))
 				printk(KERN_DEBUG "%s: TX FIFO underrun, "
 				       "packet dropped.\n", dev->name);
-			priv->stats.tx_dropped++;
+			dev->stats.tx_dropped++;
 			priv->extra_stats.tx_underrun++;
 
 			/* Reactivate the Tx Queues */
@@ -1928,7 +1925,7 @@
 			printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
 	}
 	if (events & IEVENT_BSY) {
-		priv->stats.rx_errors++;
+		dev->stats.rx_errors++;
 		priv->extra_stats.rx_bsy++;
 
 		gfar_receive(irq, dev_id);
@@ -1943,7 +1940,7 @@
 			       dev->name, gfar_read(&priv->regs->rstat));
 	}
 	if (events & IEVENT_BABR) {
-		priv->stats.rx_errors++;
+		dev->stats.rx_errors++;
 		priv->extra_stats.rx_babr++;
 
 		if (netif_msg_rx_err(priv))
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index d8e779c..c16cc8b 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -45,7 +45,6 @@
 #include <linux/crc32.h>
 #include <linux/workqueue.h>
 #include <linux/ethtool.h>
-#include <linux/netdevice.h>
 #include <linux/fsl_devices.h>
 #include "gianfar_mii.h"
 
@@ -691,6 +690,9 @@
 	/* RX Locked fields */
 	spinlock_t rxlock;
 
+	struct net_device *dev;
+	struct napi_struct napi;
+
 	/* skb array and index */
 	struct sk_buff ** rx_skbuff;
 	u16 skb_currx;
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 7b411c1..6007147 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -34,7 +34,6 @@
 #include <linux/module.h>
 #include <linux/crc32.h>
 #include <asm/types.h>
-#include <asm/uaccess.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/phy.h>
@@ -153,15 +152,19 @@
 			buf[i] = extra[i];
 }
 
-/* Returns the number of stats (and their corresponding strings) */
-static int gfar_stats_count(struct net_device *dev)
+static int gfar_sset_count(struct net_device *dev, int sset)
 {
 	struct gfar_private *priv = netdev_priv(dev);
 
-	if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
-		return GFAR_STATS_LEN;
-	else
-		return GFAR_EXTRA_STATS_LEN;
+	switch (sset) {
+	case ETH_SS_STATS:
+		if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+			return GFAR_STATS_LEN;
+		else
+			return GFAR_EXTRA_STATS_LEN;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 /* Fills in the drvinfo structure with some basic info */
@@ -172,8 +175,6 @@
 	strncpy(drvinfo->version, gfar_driver_version, GFAR_INFOSTR_LEN);
 	strncpy(drvinfo->fw_version, "N/A", GFAR_INFOSTR_LEN);
 	strncpy(drvinfo->bus_info, "N/A", GFAR_INFOSTR_LEN);
-	drvinfo->n_stats = GFAR_STATS_LEN;
-	drvinfo->testinfo_len = 0;
 	drvinfo->regdump_len = 0;
 	drvinfo->eedump_len = 0;
 }
@@ -576,7 +577,7 @@
 	.get_ringparam = gfar_gringparam,
 	.set_ringparam = gfar_sringparam,
 	.get_strings = gfar_gstrings,
-	.get_stats_count = gfar_stats_count,
+	.get_sset_count = gfar_sset_count,
 	.get_ethtool_stats = gfar_fill_stats,
 	.get_rx_csum = gfar_get_rx_csum,
 	.get_tx_csum = gfar_get_tx_csum,
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index ac3596f..100bf41 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -245,7 +245,7 @@
 	return driver_register(&gianfar_mdio_driver);
 }
 
-void __exit gfar_mdio_exit(void)
+void gfar_mdio_exit(void)
 {
 	driver_unregister(&gianfar_mdio_driver);
 }
diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h
index 5d34004..b373091 100644
--- a/drivers/net/gianfar_mii.h
+++ b/drivers/net/gianfar_mii.h
@@ -42,5 +42,5 @@
 int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
 int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
 int __init gfar_mdio_init(void);
-void __exit gfar_mdio_exit(void);
+void gfar_mdio_exit(void);
 #endif /* GIANFAR_PHY_H */
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 15254dc..ed407c8 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -580,6 +580,7 @@
 	void *ring_space;
 	dma_addr_t ring_dma;
 	int ret = -ENOMEM;
+	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -613,7 +614,6 @@
 	if (!dev)
 		goto err_out_iounmap;
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 #ifdef TX_CHECKSUM
@@ -742,12 +742,9 @@
 		goto err_out_unmap_rx;
 	}
 
-	printk(KERN_INFO "%s: %s type %x at %p, ",
+	printk(KERN_INFO "%s: %s type %x at %p, %s, IRQ %d.\n",
 		   dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev),
-		   ioaddr);
-	for (i = 0; i < 5; i++)
-			printk("%2.2x:", dev->dev_addr[i]);
-	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+		   ioaddr, print_mac(mac, dev->dev_addr), irq);
 	i = readb(ioaddr + PCIClkMeas);
 	printk(KERN_INFO "%s:  %d-bit %d Mhz PCI bus (%d), Virtual Jumpers "
 		   "%2.2x, LPA %4.4x.\n",
@@ -1020,7 +1017,7 @@
 			break;
 		/* Free the original skb. */
 		skb = hmp->tx_skbuff[entry];
-		if (skb != 0) {
+		if (skb) {
 			pci_unmap_single(hmp->pci_dev,
 				hmp->tx_ring[entry].addr, skb->len,
 				PCI_DMA_TODEVICE);
@@ -1072,7 +1069,6 @@
 		   " resetting...\n", dev->name, (int)readw(ioaddr + TxStatus));
 
 	{
-		int i;
 		printk(KERN_DEBUG "  Rx ring %p: ", hmp->rx_ring);
 		for (i = 0; i < RX_RING_SIZE; i++)
 			printk(" %8.8x", (unsigned int)hmp->rx_ring[i].status_n_length);
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 760d04a6..ecd156d 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -288,7 +288,8 @@
 
 /* Return the frame type ID */
 static int sp_header(struct sk_buff *skb, struct net_device *dev,
-	unsigned short type, void *daddr, void *saddr, unsigned len)
+		     unsigned short type, const void *daddr,
+		     const void *saddr, unsigned len)
 {
 #ifdef CONFIG_INET
 	if (type != htons(ETH_P_AX25))
@@ -323,6 +324,11 @@
 #endif
 }
 
+static const struct header_ops sp_header_ops = {
+	.create		= sp_header,
+	.rebuild	= sp_rebuild_header,
+};
+
 static void sp_setup(struct net_device *dev)
 {
 	/* Finish setting up the DEVICE info. */
@@ -331,22 +337,21 @@
 	dev->open		= sp_open_dev;
 	dev->destructor		= free_netdev;
 	dev->stop		= sp_close;
-	dev->hard_header	= sp_header;
+
 	dev->get_stats	        = sp_get_stats;
 	dev->set_mac_address    = sp_set_mac_address;
 	dev->hard_header_len	= AX25_MAX_HEADER_LEN;
+	dev->header_ops 	= &sp_header_ops;
+
 	dev->addr_len		= AX25_ADDR_LEN;
 	dev->type		= ARPHRD_AX25;
 	dev->tx_queue_len	= 10;
-	dev->rebuild_header	= sp_rebuild_header;
 	dev->tx_timeout		= NULL;
 
 	/* Only activated in AX.25 mode */
 	memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
 	memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
 
-	SET_MODULE_OWNER(dev);
-
 	dev->flags		= 0;
 }
 
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index 84aa211..1a5a75a 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -320,7 +320,7 @@
 	sprintf(portarg, "%ld", bc->pdev->port->base);
 	printk(KERN_DEBUG "%s: %s -s -p %s -m %s\n", bc_drvname, eppconfig_path, portarg, modearg);
 
-	return call_usermodehelper(eppconfig_path, argv, envp, 1);
+	return call_usermodehelper(eppconfig_path, argv, envp, UMH_WAIT_PROC);
 }
 
 /* ---------------------------------------------------------------------- */
@@ -1159,8 +1159,7 @@
 	/* Fill in the fields of the device structure */
 	bc->skb = NULL;
 	
-	dev->hard_header = ax25_hard_header;
-	dev->rebuild_header = ax25_rebuild_header;
+	dev->header_ops = &ax25_header_ops;
 	dev->set_mac_address = baycom_set_mac_address;
 	
 	dev->type = ARPHRD_AX25;           /* AF_AX25 device */
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 656f278..5ddf8b0 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -64,7 +64,7 @@
 #include <net/ax25.h>
 #include <linux/inet.h>
 #include <linux/netdevice.h>
-#include <linux/if_ether.h>
+#include <linux/etherdevice.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
@@ -83,6 +83,7 @@
 
 #include <net/ip.h>
 #include <net/arp.h>
+#include <net/net_namespace.h>
 
 #include <linux/bpqether.h>
 
@@ -94,7 +95,6 @@
 
 static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
 static int bpq_device_event(struct notifier_block *, unsigned long, void *);
-static const char *bpq_print_ethaddr(const unsigned char *);
 
 static struct packet_type bpq_packet_type = {
 	.type	= __constant_htons(ETH_P_BPQ),
@@ -172,6 +172,9 @@
 	struct ethhdr *eth;
 	struct bpqdev *bpq;
 
+	if (dev->nd_net != &init_net)
+		goto drop;
+
 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
 		return NET_RX_DROP;
 
@@ -283,7 +286,7 @@
 
 	skb->protocol = ax25_type_trans(skb, dev);
 	skb_reset_network_header(skb);
-	dev->hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0);
+	dev_hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0);
 	bpq->stats.tx_packets++;
 	bpq->stats.tx_bytes+=skb->len;
   
@@ -379,16 +382,6 @@
 /*
  *	Proc filesystem
  */
-static const char * bpq_print_ethaddr(const unsigned char *e)
-{
-	static char buf[18];
-
-	sprintf(buf, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
-		e[0], e[1], e[2], e[3], e[4], e[5]);
-
-	return buf;
-}
-
 static void *bpq_seq_start(struct seq_file *seq, loff_t *pos)
 {
 	int i = 1;
@@ -413,12 +406,12 @@
 	++*pos;
 
 	if (v == SEQ_START_TOKEN)
-		p = bpq_devices.next;
+		p = rcu_dereference(bpq_devices.next);
 	else
-		p = ((struct bpqdev *)v)->bpq_list.next;
+		p = rcu_dereference(((struct bpqdev *)v)->bpq_list.next);
 
 	return (p == &bpq_devices) ? NULL 
-		: rcu_dereference(list_entry(p, struct bpqdev, bpq_list));
+		: list_entry(p, struct bpqdev, bpq_list);
 }
 
 static void bpq_seq_stop(struct seq_file *seq, void *v)
@@ -434,14 +427,16 @@
 			 "dev   ether      destination        accept from\n");
 	else {
 		const struct bpqdev *bpqdev = v;
+		DECLARE_MAC_BUF(mac);
 
 		seq_printf(seq, "%-5s %-10s %s  ",
 			bpqdev->axdev->name, bpqdev->ethdev->name,
-			bpq_print_ethaddr(bpqdev->dest_addr));
+			print_mac(mac, bpqdev->dest_addr));
 
-		seq_printf(seq, "%s\n",
-			(bpqdev->acpt_addr[0] & 0x01) ? "*" 
-			   : bpq_print_ethaddr(bpqdev->acpt_addr));
+		if (is_multicast_ether_addr(bpqdev->acpt_addr))
+			seq_printf(seq, "*\n");
+		else
+			seq_printf(seq, "%s\n", print_mac(mac, bpqdev->acpt_addr));
 
 	}
 	return 0;
@@ -488,8 +483,7 @@
 	dev->flags      = 0;
 
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
-	dev->hard_header     = ax25_hard_header;
-	dev->rebuild_header  = ax25_rebuild_header;
+	dev->header_ops      = &ax25_header_ops;
 #endif
 
 	dev->type            = ARPHRD_AX25;
@@ -559,6 +553,9 @@
 {
 	struct net_device *dev = (struct net_device *)ptr;
 
+	if (dev->nd_net != &init_net)
+		return NOTIFY_DONE;
+
 	if (!dev_is_ethdev(dev))
 		return NOTIFY_DONE;
 
@@ -594,7 +591,7 @@
 static int __init bpq_init_driver(void)
 {
 #ifdef CONFIG_PROC_FS
-	if (!proc_net_fops_create("bpqether", S_IRUGO, &bpq_info_fops)) {
+	if (!proc_net_fops_create(&init_net, "bpqether", S_IRUGO, &bpq_info_fops)) {
 		printk(KERN_ERR
 			"bpq: cannot create /proc/net/bpqether entry.\n");
 		return -ENOENT;
@@ -618,7 +615,7 @@
 
 	unregister_netdevice_notifier(&bpq_dev_notifier);
 
-	proc_net_remove("bpqether");
+	proc_net_remove(&init_net, "bpqether");
 
 	rtnl_lock();
 	while (!list_empty(&bpq_devices)) {
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 3be8c50..bc02e46 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -453,8 +453,8 @@
 	int scc_base = card_base + hw[type].scc_offset;
 	char *chipnames[] = CHIPNAMES;
 
-	/* Allocate memory */
-	info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA);
+	/* Initialize what is necessary for write_scc and write_scc_data */
+	info = kzalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA);
 	if (!info) {
 		printk(KERN_ERR "dmascc: "
 		       "could not allocate memory for %s at %#3x\n",
@@ -462,8 +462,6 @@
 		goto out;
 	}
 
-	/* Initialize what is necessary for write_scc and write_scc_data */
-	memset(info, 0, sizeof(struct scc_info));
 
 	info->dev[0] = alloc_netdev(0, "", dev_setup);
 	if (!info->dev[0]) {
@@ -583,8 +581,7 @@
 		dev->do_ioctl = scc_ioctl;
 		dev->hard_start_xmit = scc_send_packet;
 		dev->get_stats = scc_get_stats;
-		dev->hard_header = ax25_hard_header;
-		dev->rebuild_header = ax25_rebuild_header;
+		dev->header_ops = &ax25_header_ops;
 		dev->set_mac_address = scc_set_mac_address;
 	}
 	if (register_netdev(info->dev[0])) {
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index b33adc6..ae9629f 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -682,8 +682,7 @@
 
 	s->skb = NULL;
 	
-	dev->hard_header = ax25_hard_header;
-	dev->rebuild_header = ax25_rebuild_header;
+	dev->header_ops = &ax25_header_ops;
 	dev->set_mac_address = hdlcdrv_set_mac_address;
 	
 	dev->type = ARPHRD_AX25;           /* AF_AX25 device */
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index d08fbc3..9e43c47 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -578,8 +578,9 @@
 #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
 
 /* Return the frame type ID */
-static int ax_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-	  void *daddr, void *saddr, unsigned len)
+static int ax_header(struct sk_buff *skb, struct net_device *dev,
+		     unsigned short type, const void *daddr,
+		     const void *saddr, unsigned len)
 {
 #ifdef CONFIG_INET
 	if (type != htons(ETH_P_AX25))
@@ -670,6 +671,11 @@
 	return &ax->stats;
 }
 
+static const struct header_ops ax_header_ops = {
+	.create    = ax_header,
+	.rebuild   = ax_rebuild_header,
+};
+
 static void ax_setup(struct net_device *dev)
 {
 	/* Finish setting up the DEVICE info. */
@@ -683,8 +689,8 @@
 	dev->addr_len        = 0;
 	dev->type            = ARPHRD_AX25;
 	dev->tx_queue_len    = 10;
-	dev->hard_header     = ax_header;
-	dev->rebuild_header  = ax_rebuild_header;
+	dev->header_ops      = &ax_header_ops;
+
 
 	memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
 	memcpy(dev->dev_addr,  &ax25_defaddr,  AX25_ADDR_LEN);
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 6fdaad5..353d13e 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -174,6 +174,7 @@
 #include <linux/seq_file.h>
 #include <linux/bitops.h>
 
+#include <net/net_namespace.h>
 #include <net/ax25.h>
 
 #include <asm/irq.h>
@@ -1550,8 +1551,8 @@
 	dev->stop	     = scc_net_close;
 
 	dev->hard_start_xmit = scc_net_tx;
-	dev->hard_header     = ax25_hard_header;
-	dev->rebuild_header  = ax25_rebuild_header;
+	dev->header_ops      = &ax25_header_ops;
+
 	dev->set_mac_address = scc_net_set_mac_address;
 	dev->get_stats       = scc_net_get_stats;
 	dev->do_ioctl        = scc_net_ioctl;
@@ -2114,7 +2115,7 @@
 	}
 	rtnl_unlock();
 
-	proc_net_fops_create("z8530drv", 0, &scc_net_seq_fops);
+	proc_net_fops_create(&init_net, "z8530drv", 0, &scc_net_seq_fops);
 
 	return 0;
 }
@@ -2169,7 +2170,7 @@
 	if (Vector_Latch)
 		release_region(Vector_Latch, 1);
 
-	proc_net_remove("z8530drv");
+	proc_net_remove(&init_net, "z8530drv");
 }
 
 MODULE_AUTHOR("Joerg Reuter <jreuter@yaina.de>");
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index 467559d..1c94286 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -65,6 +65,7 @@
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <net/net_namespace.h>
 
 #include <asm/uaccess.h>
 #include <linux/init.h>
@@ -1096,8 +1097,7 @@
 
 	skb_queue_head_init(&yp->send_queue);
 
-	dev->hard_header = ax25_hard_header;
-	dev->rebuild_header = ax25_rebuild_header;
+	dev->header_ops = &ax25_header_ops;
 
 	dev->set_mac_address = yam_set_mac_address;
 
@@ -1142,7 +1142,7 @@
 	yam_timer.expires = jiffies + HZ / 100;
 	add_timer(&yam_timer);
 
-	proc_net_fops_create("yam", S_IRUGO, &yam_info_fops);
+	proc_net_fops_create(&init_net, "yam", S_IRUGO, &yam_info_fops);
 	return 0;
  error:
 	while (--i >= 0) {
@@ -1174,7 +1174,7 @@
 		kfree(p);
 	}
 
-	proc_net_remove("yam");
+	proc_net_remove(&init_net, "yam");
 }
 
 /* --------------------------------------------------------------------- */
diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
index 99a36cc..c2c4f49 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/hp-plus.c
@@ -122,8 +122,6 @@
 	int base_addr = dev->base_addr;
 	int irq = dev->irq;
 
-	SET_MODULE_OWNER(dev);
-
 	if (base_addr > 0x1ff)		/* Check a single specified location. */
 		return hpp_probe1(dev, base_addr);
 	else if (base_addr != 0)	/* Don't probe at all. */
@@ -168,6 +166,7 @@
 	const char name[] = "HP-PC-LAN+";
 	int mem_start;
 	static unsigned version_printed;
+	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -182,7 +181,7 @@
 	if (ei_debug  &&  version_printed++ == 0)
 		printk(version);
 
-	printk("%s: %s at %#3x,", dev->name, name, ioaddr);
+	printk("%s: %s at %#3x, ", dev->name, name, ioaddr);
 
 	/* Retrieve and checksum the station address. */
 	outw(MAC_Page, ioaddr + HP_PAGING);
@@ -191,10 +190,11 @@
 		unsigned char inval = inb(ioaddr + 8 + i);
 		dev->dev_addr[i] = inval;
 		checksum += inval;
-		printk(" %2.2x", inval);
 	}
 	checksum += inb(ioaddr + 14);
 
+	printk("%s", print_mac(mac, dev->dev_addr));
+
 	if (checksum != 0xff) {
 		printk(" bad checksum %2.2x.\n", checksum);
 		retval = -ENODEV;
diff --git a/drivers/net/hp.c b/drivers/net/hp.c
index 635b13c..c649a80 100644
--- a/drivers/net/hp.c
+++ b/drivers/net/hp.c
@@ -86,8 +86,6 @@
 	int base_addr = dev->base_addr;
 	int irq = dev->irq;
 
-	SET_MODULE_OWNER(dev);
-
 	if (base_addr > 0x1ff)		/* Check a single specified location. */
 		return hp_probe1(dev, base_addr);
 	else if (base_addr != 0)	/* Don't probe at all. */
@@ -129,6 +127,7 @@
 	int i, retval, board_id, wordmode;
 	const char *name;
 	static unsigned version_printed;
+	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -160,7 +159,9 @@
 	printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr);
 
 	for(i = 0; i < ETHER_ADDR_LEN; i++)
-		printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+		dev->dev_addr[i] = inb(ioaddr + i);
+
+	printk(" %s", print_mac(mac, dev->dev_addr));
 
 	/* Snarf the interrupt now.  Someday this could be moved to open(). */
 	if (dev->irq < 2) {
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 8caa591c..e4fde17 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -404,8 +404,6 @@
 	if (!dev)
 		return ERR_PTR(-ENODEV);
 
-	SET_MODULE_OWNER(dev);
-
 #ifdef HP100_DEBUG_B
 	hp100_outw(0x4200, TRACE);
 	printk("hp100: %s: probe\n", dev->name);
@@ -2095,9 +2093,9 @@
 				addrs = dmi->dmi_addr;
 				if ((*addrs & 0x01) == 0x01) {	/* multicast address? */
 #ifdef HP100_DEBUG
-					printk("hp100: %s: multicast = %02x:%02x:%02x:%02x:%02x:%02x, ",
-						     dev->name, addrs[0], addrs[1], addrs[2],
-						     addrs[3], addrs[4], addrs[5]);
+					DECLARE_MAC_BUF(mac);
+					printk("hp100: %s: multicast = %s, ",
+						     dev->name, print_mac(mac, addrs));
 #endif
 					for (j = idx = 0; j < 6; j++) {
 						idx ^= *addrs++ & 0x3f;
@@ -2843,7 +2841,6 @@
 	if (!dev)
 		return -ENOMEM;
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &edev->dev);
 
 	err = hp100_probe1(dev, edev->base_addr + 0xC38, HP100_BUS_EISA, NULL);
@@ -2896,7 +2893,6 @@
 		goto out0;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
@@ -2993,7 +2989,6 @@
 
 			return -ENOMEM;
 		}
-		SET_MODULE_OWNER(dev);
 
 		err = hp100_isa_probe(dev, hp100_port[i]);
 		if (!err)
diff --git a/drivers/net/hplance.c b/drivers/net/hplance.c
index c991cb8..be6e5bc 100644
--- a/drivers/net/hplance.c
+++ b/drivers/net/hplance.c
@@ -141,7 +141,6 @@
         dev->poll_controller = lance_poll;
 #endif
         dev->hard_start_xmit = &lance_start_xmit;
-        dev->get_stats = &lance_get_stats;
         dev->set_multicast_list = &lance_set_multicast;
         dev->dma = 0;
 
diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c
index f970bfb..b96cf2d 100644
--- a/drivers/net/hydra.c
+++ b/drivers/net/hydra.c
@@ -103,6 +103,7 @@
     int start_page, stop_page;
     int j;
     int err;
+    DECLARE_MAC_BUF(mac);
 
     static u32 hydra_offsets[16] = {
 	0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
@@ -112,7 +113,6 @@
     dev = ____alloc_ei_netdev(0);
     if (!dev)
 	return -ENOMEM;
-    SET_MODULE_OWNER(dev);
 
     for(j = 0; j < ETHER_ADDR_LEN; j++)
 	dev->dev_addr[j] = *((u8 *)(board + HYDRA_ADDRPROM + 2*j));
@@ -163,10 +163,8 @@
     zorro_set_drvdata(z, dev);
 
     printk(KERN_INFO "%s: Hydra at 0x%08lx, address "
-	   "%02x:%02x:%02x:%02x:%02x:%02x (hydra.c " HYDRA_VERSION ")\n",
-	   dev->name, z->resource.start, dev->dev_addr[0], dev->dev_addr[1],
-	   dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4],
-	   dev->dev_addr[5]);
+	   "%s (hydra.c " HYDRA_VERSION ")\n",
+	   dev->name, z->resource.start, print_mac(mac, dev->dev_addr));
 
     return 0;
 }
diff --git a/drivers/net/ibm_emac/Kconfig b/drivers/net/ibm_emac/Kconfig
new file mode 100644
index 0000000..f61c480
--- /dev/null
+++ b/drivers/net/ibm_emac/Kconfig
@@ -0,0 +1,70 @@
+config IBM_EMAC
+	tristate "PowerPC 4xx on-chip Ethernet support"
+	depends on 4xx && !PPC_MERGE
+	help
+	  This driver supports the PowerPC 4xx EMAC family of on-chip
+          Ethernet controllers.
+
+config IBM_EMAC_RXB
+	int "Number of receive buffers"
+	depends on IBM_EMAC
+	default "128"
+
+config IBM_EMAC_TXB
+	int "Number of transmit buffers"
+	depends on IBM_EMAC
+	default "64"
+
+config IBM_EMAC_POLL_WEIGHT
+	int "MAL NAPI polling weight"
+	depends on IBM_EMAC
+	default "32"
+
+config IBM_EMAC_RX_COPY_THRESHOLD
+	int "RX skb copy threshold (bytes)"
+	depends on IBM_EMAC
+	default "256"
+
+config IBM_EMAC_RX_SKB_HEADROOM
+	int "Additional RX skb headroom (bytes)"
+	depends on IBM_EMAC
+	default "0"
+	help
+	  Additional receive skb headroom. Note, that driver
+	  will always reserve at least 2 bytes to make IP header
+	  aligned, so usually there is no need to add any additional
+	  headroom.
+
+	  If unsure, set to 0.
+
+config IBM_EMAC_PHY_RX_CLK_FIX
+	bool "PHY Rx clock workaround"
+	depends on IBM_EMAC && (405EP || 440GX || 440EP || 440GR)
+	help
+	  Enable this if EMAC attached to a PHY which doesn't generate
+	  RX clock if there is no link, if this is the case, you will
+	  see "TX disable timeout" or "RX disable timeout" in the system
+	  log.
+
+	  If unsure, say N.
+
+config IBM_EMAC_DEBUG
+	bool "Debugging"
+	depends on IBM_EMAC
+	default n
+
+config IBM_EMAC_ZMII
+	bool
+	depends on IBM_EMAC && (NP405H || NP405L || 44x)
+	default y
+
+config IBM_EMAC_RGMII
+	bool
+	depends on IBM_EMAC && 440GX
+	default y
+
+config IBM_EMAC_TAH
+	bool
+	depends on IBM_EMAC && 440GX
+	default y
+
diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c
index f752e5f..73664f2 100644
--- a/drivers/net/ibm_emac/ibm_emac_core.c
+++ b/drivers/net/ibm_emac/ibm_emac_core.c
@@ -353,10 +353,9 @@
 
 	for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) {
 		int bit;
-		DBG2("%d: mc %02x:%02x:%02x:%02x:%02x:%02x" NL,
-		     dev->def->index,
-		     dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
-		     dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]);
+		DECLARE_MAC_BUF(mac);
+		DBG2("%d: mc %s" NL,
+		     dev->def->index, print_mac(mac, dmi->dmi_addr));
 
 		bit = 63 - (ether_crc(ETH_ALEN, dmi->dmi_addr) >> 26);
 		gaht[bit >> 4] |= 0x8000 >> (bit & 0x0f);
@@ -1843,9 +1842,14 @@
 	return res;
 }
 
-static int emac_ethtool_get_stats_count(struct net_device *ndev)
+static int emac_get_sset_count(struct net_device *ndev, int sset)
 {
-	return EMAC_ETHTOOL_STATS_COUNT;
+	switch (sset) {
+	case ETH_SS_STATS:
+		return EMAC_ETHTOOL_STATS_COUNT;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void emac_ethtool_get_strings(struct net_device *ndev, u32 stringset,
@@ -1876,7 +1880,6 @@
 	strcpy(info->version, DRV_VERSION);
 	info->fw_version[0] = '\0';
 	sprintf(info->bus_info, "PPC 4xx EMAC %d", dev->def->index);
-	info->n_stats = emac_ethtool_get_stats_count(ndev);
 	info->regdump_len = emac_ethtool_get_regs_len(ndev);
 }
 
@@ -1896,12 +1899,10 @@
 	.get_rx_csum = emac_ethtool_get_rx_csum,
 
 	.get_strings = emac_ethtool_get_strings,
-	.get_stats_count = emac_ethtool_get_stats_count,
+	.get_sset_count = emac_get_sset_count,
 	.get_ethtool_stats = emac_ethtool_get_ethtool_stats,
 
 	.get_link = ethtool_op_get_link,
-	.get_tx_csum = ethtool_op_get_tx_csum,
-	.get_sg = ethtool_op_get_sg,
 };
 
 static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
@@ -1942,6 +1943,7 @@
 	struct ocp_device *maldev;
 	struct ocp_enet_private *dev;
 	int err, i;
+	DECLARE_MAC_BUF(mac);
 
 	DBG("%d: probe" NL, ocpdev->def->index);
 
@@ -1962,7 +1964,6 @@
 	dev->ndev = ndev;
 	dev->ldev = &ocpdev->dev;
 	dev->def = ocpdev->def;
-	SET_MODULE_OWNER(ndev);
 
 	/* Find MAL device we are connected to */
 	maldev =
@@ -2191,10 +2192,8 @@
 
 	ocp_set_drvdata(ocpdev, dev);
 
-	printk("%s: emac%d, MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       ndev->name, dev->def->index,
-	       ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
-	       ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+	printk("%s: emac%d, MAC %s\n",
+	       ndev->name, dev->def->index, print_mac(mac, ndev->dev_addr));
 
 	if (dev->phy.address >= 0)
 		printk("%s: found %s PHY (0x%02x)\n", ndev->name,
diff --git a/drivers/net/ibm_emac/ibm_emac_debug.c b/drivers/net/ibm_emac/ibm_emac_debug.c
index 92f970d..1f70906 100644
--- a/drivers/net/ibm_emac/ibm_emac_debug.c
+++ b/drivers/net/ibm_emac/ibm_emac_debug.c
@@ -132,7 +132,7 @@
 {
 	unsigned long flags;
 
-	if (idx >= sizeof(__emacs) / sizeof(__emacs[0])) {
+	if (idx >= ARRAY_SIZE(__emacs)) {
 		printk(KERN_WARNING
 		       "invalid index %d when registering EMAC for debugging\n",
 		       idx);
@@ -148,7 +148,7 @@
 {
 	unsigned long flags;
 
-	if (idx >= sizeof(__mals) / sizeof(__mals[0])) {
+	if (idx >= ARRAY_SIZE(__mals)) {
 		printk(KERN_WARNING
 		       "invalid index %d when registering MAL for debugging\n",
 		       idx);
@@ -167,11 +167,11 @@
 
 	local_irq_save(flags);
 
-	for (i = 0; i < sizeof(__mals) / sizeof(__mals[0]); ++i)
+	for (i = 0; i < ARRAY_SIZE(__mals); ++i)
 		if (__mals[i])
 			emac_mal_dump(__mals[i]);
 
-	for (i = 0; i < sizeof(__emacs) / sizeof(__emacs[0]); ++i)
+	for (i = 0; i < ARRAY_SIZE(__emacs); ++i)
 		if (__emacs[i])
 			emac_mac_dump(i, __emacs[i]);
 
diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c
index cabd984..4e49e8c 100644
--- a/drivers/net/ibm_emac/ibm_emac_mal.c
+++ b/drivers/net/ibm_emac/ibm_emac_mal.c
@@ -207,10 +207,10 @@
 
 static inline void mal_schedule_poll(struct ibm_ocp_mal *mal)
 {
-	if (likely(netif_rx_schedule_prep(&mal->poll_dev))) {
+	if (likely(napi_schedule_prep(&mal->napi))) {
 		MAL_DBG2("%d: schedule_poll" NL, mal->def->index);
 		mal_disable_eob_irq(mal);
-		__netif_rx_schedule(&mal->poll_dev);
+		__napi_schedule(&mal->napi);
 	} else
 		MAL_DBG2("%d: already in poll" NL, mal->def->index);
 }
@@ -273,11 +273,11 @@
 	return IRQ_HANDLED;
 }
 
-static int mal_poll(struct net_device *ndev, int *budget)
+static int mal_poll(struct napi_struct *napi, int budget)
 {
-	struct ibm_ocp_mal *mal = ndev->priv;
+	struct ibm_ocp_mal *mal = container_of(napi, struct ibm_ocp_mal, napi);
 	struct list_head *l;
-	int rx_work_limit = min(ndev->quota, *budget), received = 0, done;
+	int received = 0;
 
 	MAL_DBG2("%d: poll(%d) %d ->" NL, mal->def->index, *budget,
 		 rx_work_limit);
@@ -295,38 +295,34 @@
 	list_for_each(l, &mal->poll_list) {
 		struct mal_commac *mc =
 		    list_entry(l, struct mal_commac, poll_list);
-		int n = mc->ops->poll_rx(mc->dev, rx_work_limit);
+		int n = mc->ops->poll_rx(mc->dev, budget);
 		if (n) {
 			received += n;
-			rx_work_limit -= n;
-			if (rx_work_limit <= 0) {
-				done = 0;
+			budget -= n;
+			if (budget <= 0)
 				goto more_work;	// XXX What if this is the last one ?
-			}
 		}
 	}
 
 	/* We need to disable IRQs to protect from RXDE IRQ here */
 	local_irq_disable();
-	__netif_rx_complete(ndev);
+	__napi_complete(napi);
 	mal_enable_eob_irq(mal);
 	local_irq_enable();
 
-	done = 1;
-
 	/* Check for "rotting" packet(s) */
 	list_for_each(l, &mal->poll_list) {
 		struct mal_commac *mc =
 		    list_entry(l, struct mal_commac, poll_list);
 		if (unlikely(mc->ops->peek_rx(mc->dev) || mc->rx_stopped)) {
 			MAL_DBG2("%d: rotting packet" NL, mal->def->index);
-			if (netif_rx_reschedule(ndev, received))
+			if (napi_reschedule(napi))
 				mal_disable_eob_irq(mal);
 			else
 				MAL_DBG2("%d: already in poll list" NL,
 					 mal->def->index);
 
-			if (rx_work_limit > 0)
+			if (budget > 0)
 				goto again;
 			else
 				goto more_work;
@@ -335,12 +331,8 @@
 	}
 
       more_work:
-	ndev->quota -= received;
-	*budget -= received;
-
-	MAL_DBG2("%d: poll() %d <- %d" NL, mal->def->index, *budget,
-		 done ? 0 : 1);
-	return done ? 0 : 1;
+	MAL_DBG2("%d: poll() %d <- %d" NL, mal->def->index, budget, received);
+	return received;
 }
 
 static void mal_reset(struct ibm_ocp_mal *mal)
@@ -425,11 +417,8 @@
 	mal->def = ocpdev->def;
 
 	INIT_LIST_HEAD(&mal->poll_list);
-	set_bit(__LINK_STATE_START, &mal->poll_dev.state);
-	mal->poll_dev.weight = CONFIG_IBM_EMAC_POLL_WEIGHT;
-	mal->poll_dev.poll = mal_poll;
-	mal->poll_dev.priv = mal;
-	atomic_set(&mal->poll_dev.refcnt, 1);
+	mal->napi.weight = CONFIG_IBM_EMAC_POLL_WEIGHT;
+	mal->napi.poll = mal_poll;
 
 	INIT_LIST_HEAD(&mal->list);
 
@@ -520,11 +509,8 @@
 
 	MAL_DBG("%d: remove" NL, mal->def->index);
 
-	/* Syncronize with scheduled polling, 
-	   stolen from net/core/dev.c:dev_close() 
-	 */
-	clear_bit(__LINK_STATE_START, &mal->poll_dev.state);
-	netif_poll_disable(&mal->poll_dev);
+	/* Synchronize with scheduled polling */
+	napi_disable(&mal->napi);
 
 	if (!list_empty(&mal->list)) {
 		/* This is *very* bad */
diff --git a/drivers/net/ibm_emac/ibm_emac_mal.h b/drivers/net/ibm_emac/ibm_emac_mal.h
index 64bc338..8f54d62 100644
--- a/drivers/net/ibm_emac/ibm_emac_mal.h
+++ b/drivers/net/ibm_emac/ibm_emac_mal.h
@@ -195,7 +195,7 @@
 	dcr_host_t		dcrhost;
 
 	struct list_head	poll_list;
-	struct net_device	poll_dev;
+	struct napi_struct	napi;
 
 	struct list_head	list;
 	u32			tx_chan_mask;
diff --git a/drivers/net/ibm_newemac/Kconfig b/drivers/net/ibm_newemac/Kconfig
new file mode 100644
index 0000000..0d3e738
--- /dev/null
+++ b/drivers/net/ibm_newemac/Kconfig
@@ -0,0 +1,63 @@
+config IBM_NEW_EMAC
+	tristate "IBM EMAC Ethernet support"
+	depends on PPC_DCR && PPC_MERGE
+	help
+	  This driver supports the IBM EMAC family of Ethernet controllers
+	  typically found on 4xx embedded PowerPC chips, but also on the
+	  Axon southbridge for Cell.
+
+config IBM_NEW_EMAC_RXB
+	int "Number of receive buffers"
+	depends on IBM_NEW_EMAC
+	default "128"
+
+config IBM_NEW_EMAC_TXB
+	int "Number of transmit buffers"
+	depends on IBM_NEW_EMAC
+	default "64"
+
+config IBM_NEW_EMAC_POLL_WEIGHT
+	int "MAL NAPI polling weight"
+	depends on IBM_NEW_EMAC
+	default "32"
+
+config IBM_NEW_EMAC_RX_COPY_THRESHOLD
+	int "RX skb copy threshold (bytes)"
+	depends on IBM_NEW_EMAC
+	default "256"
+
+config IBM_NEW_EMAC_RX_SKB_HEADROOM
+	int "Additional RX skb headroom (bytes)"
+	depends on IBM_NEW_EMAC
+	default "0"
+	help
+	  Additional receive skb headroom. Note, that driver
+	  will always reserve at least 2 bytes to make IP header
+	  aligned, so usually there is no need to add any additional
+	  headroom.
+
+	  If unsure, set to 0.
+
+config IBM_NEW_EMAC_DEBUG
+	bool "Debugging"
+	depends on IBM_NEW_EMAC
+	default n
+
+# The options below has to be select'ed by the respective
+# processor types or platforms
+
+config IBM_NEW_EMAC_ZMII
+	bool
+	default n
+
+config IBM_NEW_EMAC_RGMII
+	bool
+	default n
+
+config IBM_NEW_EMAC_TAH
+	bool
+	default n
+
+config IBM_NEW_EMAC_EMAC4
+	bool
+	default n
diff --git a/drivers/net/ibm_newemac/Makefile b/drivers/net/ibm_newemac/Makefile
new file mode 100644
index 0000000..0b5c995
--- /dev/null
+++ b/drivers/net/ibm_newemac/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the PowerPC 4xx on-chip ethernet driver
+#
+
+obj-$(CONFIG_IBM_NEW_EMAC) += ibm_newemac.o
+
+ibm_newemac-y := mal.o core.o phy.o
+ibm_newemac-$(CONFIG_IBM_NEW_EMAC_ZMII) += zmii.o
+ibm_newemac-$(CONFIG_IBM_NEW_EMAC_RGMII) += rgmii.o
+ibm_newemac-$(CONFIG_IBM_NEW_EMAC_TAH) += tah.o
+ibm_newemac-$(CONFIG_IBM_NEW_EMAC_DEBUG) += debug.o
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
new file mode 100644
index 0000000..8ea5009
--- /dev/null
+++ b/drivers/net/ibm_newemac/core.c
@@ -0,0 +1,2906 @@
+/*
+ * drivers/net/ibm_newemac/core.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * 	Matt Porter <mporter@kernel.crashing.org>
+ *	(c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *      Armin Kuster <akuster@mvista.com>
+ * 	Johnnie Peters <jpeters@mvista.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/bitops.h>
+#include <linux/workqueue.h>
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+
+#include "core.h"
+
+/*
+ * Lack of dma_unmap_???? calls is intentional.
+ *
+ * API-correct usage requires additional support state information to be
+ * maintained for every RX and TX buffer descriptor (BD). Unfortunately, due to
+ * EMAC design (e.g. TX buffer passed from network stack can be split into
+ * several BDs, dma_map_single/dma_map_page can be used to map particular BD),
+ * maintaining such information will add additional overhead.
+ * Current DMA API implementation for 4xx processors only ensures cache coherency
+ * and dma_unmap_???? routines are empty and are likely to stay this way.
+ * I decided to omit dma_unmap_??? calls because I don't want to add additional
+ * complexity just for the sake of following some abstract API, when it doesn't
+ * add any real benefit to the driver. I understand that this decision maybe
+ * controversial, but I really tried to make code API-correct and efficient
+ * at the same time and didn't come up with code I liked :(.                --ebs
+ */
+
+#define DRV_NAME        "emac"
+#define DRV_VERSION     "3.54"
+#define DRV_DESC        "PPC 4xx OCP EMAC driver"
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_AUTHOR
+    ("Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>");
+MODULE_LICENSE("GPL");
+
+/*
+ * PPC64 doesn't (yet) have a cacheable_memcpy
+ */
+#ifdef CONFIG_PPC64
+#define cacheable_memcpy(d,s,n) memcpy((d),(s),(n))
+#endif
+
+/* minimum number of free TX descriptors required to wake up TX process */
+#define EMAC_TX_WAKEUP_THRESH		(NUM_TX_BUFF / 4)
+
+/* If packet size is less than this number, we allocate small skb and copy packet
+ * contents into it instead of just sending original big skb up
+ */
+#define EMAC_RX_COPY_THRESH		CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD
+
+/* Since multiple EMACs share MDIO lines in various ways, we need
+ * to avoid re-using the same PHY ID in cases where the arch didn't
+ * setup precise phy_map entries
+ *
+ * XXX This is something that needs to be reworked as we can have multiple
+ * EMAC "sets" (multiple ASICs containing several EMACs) though we can
+ * probably require in that case to have explicit PHY IDs in the device-tree
+ */
+static u32 busy_phy_map;
+static DEFINE_MUTEX(emac_phy_map_lock);
+
+/* This is the wait queue used to wait on any event related to probe, that
+ * is discovery of MALs, other EMACs, ZMII/RGMIIs, etc...
+ */
+static DECLARE_WAIT_QUEUE_HEAD(emac_probe_wait);
+
+/* Having stable interface names is a doomed idea. However, it would be nice
+ * if we didn't have completely random interface names at boot too :-) It's
+ * just a matter of making everybody's life easier. Since we are doing
+ * threaded probing, it's a bit harder though. The base idea here is that
+ * we make up a list of all emacs in the device-tree before we register the
+ * driver. Every emac will then wait for the previous one in the list to
+ * initialize before itself. We should also keep that list ordered by
+ * cell_index.
+ * That list is only 4 entries long, meaning that additional EMACs don't
+ * get ordering guarantees unless EMAC_BOOT_LIST_SIZE is increased.
+ */
+
+#define EMAC_BOOT_LIST_SIZE	4
+static struct device_node *emac_boot_list[EMAC_BOOT_LIST_SIZE];
+
+/* How long should I wait for dependent devices ? */
+#define EMAC_PROBE_DEP_TIMEOUT	(HZ * 5)
+
+/* I don't want to litter system log with timeout errors
+ * when we have brain-damaged PHY.
+ */
+static inline void emac_report_timeout_error(struct emac_instance *dev,
+					     const char *error)
+{
+	if (net_ratelimit())
+		printk(KERN_ERR "%s: %s\n", dev->ndev->name, error);
+}
+
+/* PHY polling intervals */
+#define PHY_POLL_LINK_ON	HZ
+#define PHY_POLL_LINK_OFF	(HZ / 5)
+
+/* Graceful stop timeouts in us.
+ * We should allow up to 1 frame time (full-duplex, ignoring collisions)
+ */
+#define STOP_TIMEOUT_10		1230
+#define STOP_TIMEOUT_100	124
+#define STOP_TIMEOUT_1000	13
+#define STOP_TIMEOUT_1000_JUMBO	73
+
+/* Please, keep in sync with struct ibm_emac_stats/ibm_emac_error_stats */
+static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = {
+	"rx_packets", "rx_bytes", "tx_packets", "tx_bytes", "rx_packets_csum",
+	"tx_packets_csum", "tx_undo", "rx_dropped_stack", "rx_dropped_oom",
+	"rx_dropped_error", "rx_dropped_resize", "rx_dropped_mtu",
+	"rx_stopped", "rx_bd_errors", "rx_bd_overrun", "rx_bd_bad_packet",
+	"rx_bd_runt_packet", "rx_bd_short_event", "rx_bd_alignment_error",
+	"rx_bd_bad_fcs", "rx_bd_packet_too_long", "rx_bd_out_of_range",
+	"rx_bd_in_range", "rx_parity", "rx_fifo_overrun", "rx_overrun",
+	"rx_bad_packet", "rx_runt_packet", "rx_short_event",
+	"rx_alignment_error", "rx_bad_fcs", "rx_packet_too_long",
+	"rx_out_of_range", "rx_in_range", "tx_dropped", "tx_bd_errors",
+	"tx_bd_bad_fcs", "tx_bd_carrier_loss", "tx_bd_excessive_deferral",
+	"tx_bd_excessive_collisions", "tx_bd_late_collision",
+	"tx_bd_multple_collisions", "tx_bd_single_collision",
+	"tx_bd_underrun", "tx_bd_sqe", "tx_parity", "tx_underrun", "tx_sqe",
+	"tx_errors"
+};
+
+static irqreturn_t emac_irq(int irq, void *dev_instance);
+static void emac_clean_tx_ring(struct emac_instance *dev);
+static void __emac_set_multicast_list(struct emac_instance *dev);
+
+static inline int emac_phy_supports_gige(int phy_mode)
+{
+	return  phy_mode == PHY_MODE_GMII ||
+		phy_mode == PHY_MODE_RGMII ||
+		phy_mode == PHY_MODE_TBI ||
+		phy_mode == PHY_MODE_RTBI;
+}
+
+static inline int emac_phy_gpcs(int phy_mode)
+{
+	return  phy_mode == PHY_MODE_TBI ||
+		phy_mode == PHY_MODE_RTBI;
+}
+
+static inline void emac_tx_enable(struct emac_instance *dev)
+{
+	struct emac_regs __iomem *p = dev->emacp;
+	u32 r;
+
+	DBG(dev, "tx_enable" NL);
+
+	r = in_be32(&p->mr0);
+	if (!(r & EMAC_MR0_TXE))
+		out_be32(&p->mr0, r | EMAC_MR0_TXE);
+}
+
+static void emac_tx_disable(struct emac_instance *dev)
+{
+	struct emac_regs __iomem *p = dev->emacp;
+	u32 r;
+
+	DBG(dev, "tx_disable" NL);
+
+	r = in_be32(&p->mr0);
+	if (r & EMAC_MR0_TXE) {
+		int n = dev->stop_timeout;
+		out_be32(&p->mr0, r & ~EMAC_MR0_TXE);
+		while (!(in_be32(&p->mr0) & EMAC_MR0_TXI) && n) {
+			udelay(1);
+			--n;
+		}
+		if (unlikely(!n))
+			emac_report_timeout_error(dev, "TX disable timeout");
+	}
+}
+
+static void emac_rx_enable(struct emac_instance *dev)
+{
+	struct emac_regs __iomem *p = dev->emacp;
+	u32 r;
+
+	if (unlikely(test_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags)))
+		goto out;
+
+	DBG(dev, "rx_enable" NL);
+
+	r = in_be32(&p->mr0);
+	if (!(r & EMAC_MR0_RXE)) {
+		if (unlikely(!(r & EMAC_MR0_RXI))) {
+			/* Wait if previous async disable is still in progress */
+			int n = dev->stop_timeout;
+			while (!(r = in_be32(&p->mr0) & EMAC_MR0_RXI) && n) {
+				udelay(1);
+				--n;
+			}
+			if (unlikely(!n))
+				emac_report_timeout_error(dev,
+							  "RX disable timeout");
+		}
+		out_be32(&p->mr0, r | EMAC_MR0_RXE);
+	}
+ out:
+	;
+}
+
+static void emac_rx_disable(struct emac_instance *dev)
+{
+	struct emac_regs __iomem *p = dev->emacp;
+	u32 r;
+
+	DBG(dev, "rx_disable" NL);
+
+	r = in_be32(&p->mr0);
+	if (r & EMAC_MR0_RXE) {
+		int n = dev->stop_timeout;
+		out_be32(&p->mr0, r & ~EMAC_MR0_RXE);
+		while (!(in_be32(&p->mr0) & EMAC_MR0_RXI) && n) {
+			udelay(1);
+			--n;
+		}
+		if (unlikely(!n))
+			emac_report_timeout_error(dev, "RX disable timeout");
+	}
+}
+
+static inline void emac_netif_stop(struct emac_instance *dev)
+{
+	netif_tx_lock_bh(dev->ndev);
+	dev->no_mcast = 1;
+	netif_tx_unlock_bh(dev->ndev);
+	dev->ndev->trans_start = jiffies;	/* prevent tx timeout */
+	mal_poll_disable(dev->mal, &dev->commac);
+	netif_tx_disable(dev->ndev);
+}
+
+static inline void emac_netif_start(struct emac_instance *dev)
+{
+	netif_tx_lock_bh(dev->ndev);
+	dev->no_mcast = 0;
+	if (dev->mcast_pending && netif_running(dev->ndev))
+		__emac_set_multicast_list(dev);
+	netif_tx_unlock_bh(dev->ndev);
+
+	netif_wake_queue(dev->ndev);
+
+	/* NOTE: unconditional netif_wake_queue is only appropriate
+	 * so long as all callers are assured to have free tx slots
+	 * (taken from tg3... though the case where that is wrong is
+	 *  not terribly harmful)
+	 */
+	mal_poll_enable(dev->mal, &dev->commac);
+}
+
+static inline void emac_rx_disable_async(struct emac_instance *dev)
+{
+	struct emac_regs __iomem *p = dev->emacp;
+	u32 r;
+
+	DBG(dev, "rx_disable_async" NL);
+
+	r = in_be32(&p->mr0);
+	if (r & EMAC_MR0_RXE)
+		out_be32(&p->mr0, r & ~EMAC_MR0_RXE);
+}
+
+static int emac_reset(struct emac_instance *dev)
+{
+	struct emac_regs __iomem *p = dev->emacp;
+	int n = 20;
+
+	DBG(dev, "reset" NL);
+
+	if (!dev->reset_failed) {
+		/* 40x erratum suggests stopping RX channel before reset,
+		 * we stop TX as well
+		 */
+		emac_rx_disable(dev);
+		emac_tx_disable(dev);
+	}
+
+	out_be32(&p->mr0, EMAC_MR0_SRST);
+	while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n)
+		--n;
+
+	if (n) {
+		dev->reset_failed = 0;
+		return 0;
+	} else {
+		emac_report_timeout_error(dev, "reset timeout");
+		dev->reset_failed = 1;
+		return -ETIMEDOUT;
+	}
+}
+
+static void emac_hash_mc(struct emac_instance *dev)
+{
+	struct emac_regs __iomem *p = dev->emacp;
+	u16 gaht[4] = { 0 };
+	struct dev_mc_list *dmi;
+
+	DBG(dev, "hash_mc %d" NL, dev->ndev->mc_count);
+
+	for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) {
+		int bit;
+		DBG2(dev, "mc %02x:%02x:%02x:%02x:%02x:%02x" NL,
+		     dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
+		     dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]);
+
+		bit = 63 - (ether_crc(ETH_ALEN, dmi->dmi_addr) >> 26);
+		gaht[bit >> 4] |= 0x8000 >> (bit & 0x0f);
+	}
+	out_be32(&p->gaht1, gaht[0]);
+	out_be32(&p->gaht2, gaht[1]);
+	out_be32(&p->gaht3, gaht[2]);
+	out_be32(&p->gaht4, gaht[3]);
+}
+
+static inline u32 emac_iff2rmr(struct net_device *ndev)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+	u32 r;
+
+	r = EMAC_RMR_SP | EMAC_RMR_SFCS | EMAC_RMR_IAE | EMAC_RMR_BAE;
+
+	if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+	    r |= EMAC4_RMR_BASE;
+	else
+	    r |= EMAC_RMR_BASE;
+
+	if (ndev->flags & IFF_PROMISC)
+		r |= EMAC_RMR_PME;
+	else if (ndev->flags & IFF_ALLMULTI || ndev->mc_count > 32)
+		r |= EMAC_RMR_PMME;
+	else if (ndev->mc_count > 0)
+		r |= EMAC_RMR_MAE;
+
+	return r;
+}
+
+static u32 __emac_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_size)
+{
+	u32 ret = EMAC_MR1_VLE | EMAC_MR1_IST | EMAC_MR1_TR0_MULT;
+
+	DBG2(dev, "__emac_calc_base_mr1" NL);
+
+	switch(tx_size) {
+	case 2048:
+		ret |= EMAC_MR1_TFS_2K;
+		break;
+	default:
+		printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n",
+		       dev->ndev->name, tx_size);
+	}
+
+	switch(rx_size) {
+	case 16384:
+		ret |= EMAC_MR1_RFS_16K;
+		break;
+	case 4096:
+		ret |= EMAC_MR1_RFS_4K;
+		break;
+	default:
+		printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n",
+		       dev->ndev->name, rx_size);
+	}
+
+	return ret;
+}
+
+static u32 __emac4_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_size)
+{
+	u32 ret = EMAC_MR1_VLE | EMAC_MR1_IST | EMAC4_MR1_TR |
+		EMAC4_MR1_OBCI(dev->opb_bus_freq);
+
+	DBG2(dev, "__emac4_calc_base_mr1" NL);
+
+	switch(tx_size) {
+	case 4096:
+		ret |= EMAC4_MR1_TFS_4K;
+		break;
+	case 2048:
+		ret |= EMAC4_MR1_TFS_2K;
+		break;
+	default:
+		printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n",
+		       dev->ndev->name, tx_size);
+	}
+
+	switch(rx_size) {
+	case 16384:
+		ret |= EMAC4_MR1_RFS_16K;
+		break;
+	case 4096:
+		ret |= EMAC4_MR1_RFS_4K;
+		break;
+	case 2048:
+		ret |= EMAC4_MR1_RFS_2K;
+		break;
+	default:
+		printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n",
+		       dev->ndev->name, rx_size);
+	}
+
+	return ret;
+}
+
+static u32 emac_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_size)
+{
+	return emac_has_feature(dev, EMAC_FTR_EMAC4) ?
+		__emac4_calc_base_mr1(dev, tx_size, rx_size) :
+		__emac_calc_base_mr1(dev, tx_size, rx_size);
+}
+
+static inline u32 emac_calc_trtr(struct emac_instance *dev, unsigned int size)
+{
+	if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+		return ((size >> 6) - 1) << EMAC_TRTR_SHIFT_EMAC4;
+	else
+		return ((size >> 6) - 1) << EMAC_TRTR_SHIFT;
+}
+
+static inline u32 emac_calc_rwmr(struct emac_instance *dev,
+				 unsigned int low, unsigned int high)
+{
+	if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+		return (low << 22) | ( (high & 0x3ff) << 6);
+	else
+		return (low << 23) | ( (high & 0x1ff) << 7);
+}
+
+static int emac_configure(struct emac_instance *dev)
+{
+	struct emac_regs __iomem *p = dev->emacp;
+	struct net_device *ndev = dev->ndev;
+	int tx_size, rx_size;
+	u32 r, mr1 = 0;
+
+	DBG(dev, "configure" NL);
+
+	if (emac_reset(dev) < 0)
+		return -ETIMEDOUT;
+
+	if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
+		tah_reset(dev->tah_dev);
+
+	DBG(dev, " duplex = %d, pause = %d, asym_pause = %d\n",
+	    dev->phy.duplex, dev->phy.pause, dev->phy.asym_pause);
+
+	/* Default fifo sizes */
+	tx_size = dev->tx_fifo_size;
+	rx_size = dev->rx_fifo_size;
+
+	/* Check for full duplex */
+	if (dev->phy.duplex == DUPLEX_FULL)
+		mr1 |= EMAC_MR1_FDE | EMAC_MR1_MWSW_001;
+
+	/* Adjust fifo sizes, mr1 and timeouts based on link speed */
+	dev->stop_timeout = STOP_TIMEOUT_10;
+	switch (dev->phy.speed) {
+	case SPEED_1000:
+		if (emac_phy_gpcs(dev->phy.mode)) {
+			mr1 |= EMAC_MR1_MF_1000GPCS |
+				EMAC_MR1_MF_IPPA(dev->phy.address);
+
+			/* Put some arbitrary OUI, Manuf & Rev IDs so we can
+			 * identify this GPCS PHY later.
+			 */
+			out_be32(&p->ipcr, 0xdeadbeef);
+		} else
+			mr1 |= EMAC_MR1_MF_1000;
+
+		/* Extended fifo sizes */
+		tx_size = dev->tx_fifo_size_gige;
+		rx_size = dev->rx_fifo_size_gige;
+
+		if (dev->ndev->mtu > ETH_DATA_LEN) {
+			mr1 |= EMAC_MR1_JPSM;
+			dev->stop_timeout = STOP_TIMEOUT_1000_JUMBO;
+		} else
+			dev->stop_timeout = STOP_TIMEOUT_1000;
+		break;
+	case SPEED_100:
+		mr1 |= EMAC_MR1_MF_100;
+		dev->stop_timeout = STOP_TIMEOUT_100;
+		break;
+	default: /* make gcc happy */
+		break;
+	}
+
+	if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+		rgmii_set_speed(dev->rgmii_dev, dev->rgmii_port,
+				dev->phy.speed);
+	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+		zmii_set_speed(dev->zmii_dev, dev->zmii_port, dev->phy.speed);
+
+	/* on 40x erratum forces us to NOT use integrated flow control,
+	 * let's hope it works on 44x ;)
+	 */
+	if (!emac_has_feature(dev, EMAC_FTR_NO_FLOW_CONTROL_40x) &&
+	    dev->phy.duplex == DUPLEX_FULL) {
+		if (dev->phy.pause)
+			mr1 |= EMAC_MR1_EIFC | EMAC_MR1_APP;
+		else if (dev->phy.asym_pause)
+			mr1 |= EMAC_MR1_APP;
+	}
+
+	/* Add base settings & fifo sizes & program MR1 */
+	mr1 |= emac_calc_base_mr1(dev, tx_size, rx_size);
+	out_be32(&p->mr1, mr1);
+
+	/* Set individual MAC address */
+	out_be32(&p->iahr, (ndev->dev_addr[0] << 8) | ndev->dev_addr[1]);
+	out_be32(&p->ialr, (ndev->dev_addr[2] << 24) |
+		 (ndev->dev_addr[3] << 16) | (ndev->dev_addr[4] << 8) |
+		 ndev->dev_addr[5]);
+
+	/* VLAN Tag Protocol ID */
+	out_be32(&p->vtpid, 0x8100);
+
+	/* Receive mode register */
+	r = emac_iff2rmr(ndev);
+	if (r & EMAC_RMR_MAE)
+		emac_hash_mc(dev);
+	out_be32(&p->rmr, r);
+
+	/* FIFOs thresholds */
+	if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+		r = EMAC4_TMR1((dev->mal_burst_size / dev->fifo_entry_size) + 1,
+			       tx_size / 2 / dev->fifo_entry_size);
+	else
+		r = EMAC_TMR1((dev->mal_burst_size / dev->fifo_entry_size) + 1,
+			      tx_size / 2 / dev->fifo_entry_size);
+	out_be32(&p->tmr1, r);
+	out_be32(&p->trtr, emac_calc_trtr(dev, tx_size / 2));
+
+	/* PAUSE frame is sent when RX FIFO reaches its high-water mark,
+	   there should be still enough space in FIFO to allow the our link
+	   partner time to process this frame and also time to send PAUSE
+	   frame itself.
+
+	   Here is the worst case scenario for the RX FIFO "headroom"
+	   (from "The Switch Book") (100Mbps, without preamble, inter-frame gap):
+
+	   1) One maximum-length frame on TX                    1522 bytes
+	   2) One PAUSE frame time                                64 bytes
+	   3) PAUSE frame decode time allowance                   64 bytes
+	   4) One maximum-length frame on RX                    1522 bytes
+	   5) Round-trip propagation delay of the link (100Mb)    15 bytes
+	   ----------
+	   3187 bytes
+
+	   I chose to set high-water mark to RX_FIFO_SIZE / 4 (1024 bytes)
+	   low-water mark  to RX_FIFO_SIZE / 8 (512 bytes)
+	 */
+	r = emac_calc_rwmr(dev, rx_size / 8 / dev->fifo_entry_size,
+			   rx_size / 4 / dev->fifo_entry_size);
+	out_be32(&p->rwmr, r);
+
+	/* Set PAUSE timer to the maximum */
+	out_be32(&p->ptr, 0xffff);
+
+	/* IRQ sources */
+	r = EMAC_ISR_OVR | EMAC_ISR_BP | EMAC_ISR_SE |
+		EMAC_ISR_ALE | EMAC_ISR_BFCS | EMAC_ISR_PTLE | EMAC_ISR_ORE |
+		EMAC_ISR_IRE | EMAC_ISR_TE;
+	if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+	    r |= EMAC4_ISR_TXPE | EMAC4_ISR_RXPE /* | EMAC4_ISR_TXUE |
+						  EMAC4_ISR_RXOE | */;
+	out_be32(&p->iser,  r);
+
+	/* We need to take GPCS PHY out of isolate mode after EMAC reset */
+	if (emac_phy_gpcs(dev->phy.mode))
+		emac_mii_reset_phy(&dev->phy);
+
+	return 0;
+}
+
+static void emac_reinitialize(struct emac_instance *dev)
+{
+	DBG(dev, "reinitialize" NL);
+
+	emac_netif_stop(dev);
+	if (!emac_configure(dev)) {
+		emac_tx_enable(dev);
+		emac_rx_enable(dev);
+	}
+	emac_netif_start(dev);
+}
+
+static void emac_full_tx_reset(struct emac_instance *dev)
+{
+	DBG(dev, "full_tx_reset" NL);
+
+	emac_tx_disable(dev);
+	mal_disable_tx_channel(dev->mal, dev->mal_tx_chan);
+	emac_clean_tx_ring(dev);
+	dev->tx_cnt = dev->tx_slot = dev->ack_slot = 0;
+
+	emac_configure(dev);
+
+	mal_enable_tx_channel(dev->mal, dev->mal_tx_chan);
+	emac_tx_enable(dev);
+	emac_rx_enable(dev);
+}
+
+static void emac_reset_work(struct work_struct *work)
+{
+	struct emac_instance *dev = container_of(work, struct emac_instance, reset_work);
+
+	DBG(dev, "reset_work" NL);
+
+	mutex_lock(&dev->link_lock);
+	emac_netif_stop(dev);
+	emac_full_tx_reset(dev);
+	emac_netif_start(dev);
+	mutex_unlock(&dev->link_lock);
+}
+
+static void emac_tx_timeout(struct net_device *ndev)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+
+	DBG(dev, "tx_timeout" NL);
+
+	schedule_work(&dev->reset_work);
+}
+
+
+static inline int emac_phy_done(struct emac_instance *dev, u32 stacr)
+{
+	int done = !!(stacr & EMAC_STACR_OC);
+
+	if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT))
+		done = !done;
+
+	return done;
+};
+
+static int __emac_mdio_read(struct emac_instance *dev, u8 id, u8 reg)
+{
+	struct emac_regs __iomem *p = dev->emacp;
+	u32 r = 0;
+	int n, err = -ETIMEDOUT;
+
+	mutex_lock(&dev->mdio_lock);
+
+	DBG2(dev, "mdio_read(%02x,%02x)" NL, id, reg);
+
+	/* Enable proper MDIO port */
+	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+		zmii_get_mdio(dev->zmii_dev, dev->zmii_port);
+	if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+		rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port);
+
+	/* Wait for management interface to become idle */
+	n = 10;
+	while (!emac_phy_done(dev, in_be32(&p->stacr))) {
+		udelay(1);
+		if (!--n) {
+			DBG2(dev, " -> timeout wait idle\n");
+			goto bail;
+		}
+	}
+
+	/* Issue read command */
+	if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+		r = EMAC4_STACR_BASE(dev->opb_bus_freq);
+	else
+		r = EMAC_STACR_BASE(dev->opb_bus_freq);
+	if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT))
+		r |= EMAC_STACR_OC;
+	if (emac_has_feature(dev, EMAC_FTR_HAS_AXON_STACR))
+		r |= EMACX_STACR_STAC_READ;
+	else
+		r |= EMAC_STACR_STAC_READ;
+	r |= (reg & EMAC_STACR_PRA_MASK)
+		| ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT);
+	out_be32(&p->stacr, r);
+
+	/* Wait for read to complete */
+	n = 100;
+	while (!emac_phy_done(dev, (r = in_be32(&p->stacr)))) {
+		udelay(1);
+		if (!--n) {
+			DBG2(dev, " -> timeout wait complete\n");
+			goto bail;
+		}
+	}
+
+	if (unlikely(r & EMAC_STACR_PHYE)) {
+		DBG(dev, "mdio_read(%02x, %02x) failed" NL, id, reg);
+		err = -EREMOTEIO;
+		goto bail;
+	}
+
+	r = ((r >> EMAC_STACR_PHYD_SHIFT) & EMAC_STACR_PHYD_MASK);
+
+	DBG2(dev, "mdio_read -> %04x" NL, r);
+	err = 0;
+ bail:
+	if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+		rgmii_put_mdio(dev->rgmii_dev, dev->rgmii_port);
+	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+		zmii_put_mdio(dev->zmii_dev, dev->zmii_port);
+	mutex_unlock(&dev->mdio_lock);
+
+	return err == 0 ? r : err;
+}
+
+static void __emac_mdio_write(struct emac_instance *dev, u8 id, u8 reg,
+			      u16 val)
+{
+	struct emac_regs __iomem *p = dev->emacp;
+	u32 r = 0;
+	int n, err = -ETIMEDOUT;
+
+	mutex_lock(&dev->mdio_lock);
+
+	DBG2(dev, "mdio_write(%02x,%02x,%04x)" NL, id, reg, val);
+
+	/* Enable proper MDIO port */
+	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+		zmii_get_mdio(dev->zmii_dev, dev->zmii_port);
+	if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+		rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port);
+
+	/* Wait for management interface to be idle */
+	n = 10;
+	while (!emac_phy_done(dev, in_be32(&p->stacr))) {
+		udelay(1);
+		if (!--n) {
+			DBG2(dev, " -> timeout wait idle\n");
+			goto bail;
+		}
+	}
+
+	/* Issue write command */
+	if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+		r = EMAC4_STACR_BASE(dev->opb_bus_freq);
+	else
+		r = EMAC_STACR_BASE(dev->opb_bus_freq);
+	if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT))
+		r |= EMAC_STACR_OC;
+	if (emac_has_feature(dev, EMAC_FTR_HAS_AXON_STACR))
+		r |= EMACX_STACR_STAC_WRITE;
+	else
+		r |= EMAC_STACR_STAC_WRITE;
+	r |= (reg & EMAC_STACR_PRA_MASK) |
+		((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT) |
+		(val << EMAC_STACR_PHYD_SHIFT);
+	out_be32(&p->stacr, r);
+
+	/* Wait for write to complete */
+	n = 100;
+	while (!emac_phy_done(dev, in_be32(&p->stacr))) {
+		udelay(1);
+		if (!--n) {
+			DBG2(dev, " -> timeout wait complete\n");
+			goto bail;
+		}
+	}
+	err = 0;
+ bail:
+	if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+		rgmii_put_mdio(dev->rgmii_dev, dev->rgmii_port);
+	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+		zmii_put_mdio(dev->zmii_dev, dev->zmii_port);
+	mutex_unlock(&dev->mdio_lock);
+}
+
+static int emac_mdio_read(struct net_device *ndev, int id, int reg)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+	int res;
+
+	res = __emac_mdio_read(dev->mdio_instance ? dev->mdio_instance : dev,
+			       (u8) id, (u8) reg);
+	return res;
+}
+
+static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+
+	__emac_mdio_write(dev->mdio_instance ? dev->mdio_instance : dev,
+			  (u8) id, (u8) reg, (u16) val);
+}
+
+/* Tx lock BH */
+static void __emac_set_multicast_list(struct emac_instance *dev)
+{
+	struct emac_regs __iomem *p = dev->emacp;
+	u32 rmr = emac_iff2rmr(dev->ndev);
+
+	DBG(dev, "__multicast %08x" NL, rmr);
+
+	/* I decided to relax register access rules here to avoid
+	 * full EMAC reset.
+	 *
+	 * There is a real problem with EMAC4 core if we use MWSW_001 bit
+	 * in MR1 register and do a full EMAC reset.
+	 * One TX BD status update is delayed and, after EMAC reset, it
+	 * never happens, resulting in TX hung (it'll be recovered by TX
+	 * timeout handler eventually, but this is just gross).
+	 * So we either have to do full TX reset or try to cheat here :)
+	 *
+	 * The only required change is to RX mode register, so I *think* all
+	 * we need is just to stop RX channel. This seems to work on all
+	 * tested SoCs.                                                --ebs
+	 *
+	 * If we need the full reset, we might just trigger the workqueue
+	 * and do it async... a bit nasty but should work --BenH
+	 */
+	dev->mcast_pending = 0;
+	emac_rx_disable(dev);
+	if (rmr & EMAC_RMR_MAE)
+		emac_hash_mc(dev);
+	out_be32(&p->rmr, rmr);
+	emac_rx_enable(dev);
+}
+
+/* Tx lock BH */
+static void emac_set_multicast_list(struct net_device *ndev)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+
+	DBG(dev, "multicast" NL);
+
+	BUG_ON(!netif_running(dev->ndev));
+
+	if (dev->no_mcast) {
+		dev->mcast_pending = 1;
+		return;
+	}
+	__emac_set_multicast_list(dev);
+}
+
+static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu)
+{
+	int rx_sync_size = emac_rx_sync_size(new_mtu);
+	int rx_skb_size = emac_rx_skb_size(new_mtu);
+	int i, ret = 0;
+
+	mutex_lock(&dev->link_lock);
+	emac_netif_stop(dev);
+	emac_rx_disable(dev);
+	mal_disable_rx_channel(dev->mal, dev->mal_rx_chan);
+
+	if (dev->rx_sg_skb) {
+		++dev->estats.rx_dropped_resize;
+		dev_kfree_skb(dev->rx_sg_skb);
+		dev->rx_sg_skb = NULL;
+	}
+
+	/* Make a first pass over RX ring and mark BDs ready, dropping
+	 * non-processed packets on the way. We need this as a separate pass
+	 * to simplify error recovery in the case of allocation failure later.
+	 */
+	for (i = 0; i < NUM_RX_BUFF; ++i) {
+		if (dev->rx_desc[i].ctrl & MAL_RX_CTRL_FIRST)
+			++dev->estats.rx_dropped_resize;
+
+		dev->rx_desc[i].data_len = 0;
+		dev->rx_desc[i].ctrl = MAL_RX_CTRL_EMPTY |
+		    (i == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);
+	}
+
+	/* Reallocate RX ring only if bigger skb buffers are required */
+	if (rx_skb_size <= dev->rx_skb_size)
+		goto skip;
+
+	/* Second pass, allocate new skbs */
+	for (i = 0; i < NUM_RX_BUFF; ++i) {
+		struct sk_buff *skb = alloc_skb(rx_skb_size, GFP_ATOMIC);
+		if (!skb) {
+			ret = -ENOMEM;
+			goto oom;
+		}
+
+		BUG_ON(!dev->rx_skb[i]);
+		dev_kfree_skb(dev->rx_skb[i]);
+
+		skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2);
+		dev->rx_desc[i].data_ptr =
+		    dma_map_single(&dev->ofdev->dev, skb->data - 2, rx_sync_size,
+				   DMA_FROM_DEVICE) + 2;
+		dev->rx_skb[i] = skb;
+	}
+ skip:
+	/* Check if we need to change "Jumbo" bit in MR1 */
+	if ((new_mtu > ETH_DATA_LEN) ^ (dev->ndev->mtu > ETH_DATA_LEN)) {
+		/* This is to prevent starting RX channel in emac_rx_enable() */
+		set_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags);
+
+		dev->ndev->mtu = new_mtu;
+		emac_full_tx_reset(dev);
+	}
+
+	mal_set_rcbs(dev->mal, dev->mal_rx_chan, emac_rx_size(new_mtu));
+ oom:
+	/* Restart RX */
+	clear_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags);
+	dev->rx_slot = 0;
+	mal_enable_rx_channel(dev->mal, dev->mal_rx_chan);
+	emac_rx_enable(dev);
+	emac_netif_start(dev);
+	mutex_unlock(&dev->link_lock);
+
+	return ret;
+}
+
+/* Process ctx, rtnl_lock semaphore */
+static int emac_change_mtu(struct net_device *ndev, int new_mtu)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+	int ret = 0;
+
+	if (new_mtu < EMAC_MIN_MTU || new_mtu > dev->max_mtu)
+		return -EINVAL;
+
+	DBG(dev, "change_mtu(%d)" NL, new_mtu);
+
+	if (netif_running(ndev)) {
+		/* Check if we really need to reinitalize RX ring */
+		if (emac_rx_skb_size(ndev->mtu) != emac_rx_skb_size(new_mtu))
+			ret = emac_resize_rx_ring(dev, new_mtu);
+	}
+
+	if (!ret) {
+		ndev->mtu = new_mtu;
+		dev->rx_skb_size = emac_rx_skb_size(new_mtu);
+		dev->rx_sync_size = emac_rx_sync_size(new_mtu);
+	}
+
+	return ret;
+}
+
+static void emac_clean_tx_ring(struct emac_instance *dev)
+{
+	int i;
+
+	for (i = 0; i < NUM_TX_BUFF; ++i) {
+		if (dev->tx_skb[i]) {
+			dev_kfree_skb(dev->tx_skb[i]);
+			dev->tx_skb[i] = NULL;
+			if (dev->tx_desc[i].ctrl & MAL_TX_CTRL_READY)
+				++dev->estats.tx_dropped;
+		}
+		dev->tx_desc[i].ctrl = 0;
+		dev->tx_desc[i].data_ptr = 0;
+	}
+}
+
+static void emac_clean_rx_ring(struct emac_instance *dev)
+{
+	int i;
+
+	for (i = 0; i < NUM_RX_BUFF; ++i)
+		if (dev->rx_skb[i]) {
+			dev->rx_desc[i].ctrl = 0;
+			dev_kfree_skb(dev->rx_skb[i]);
+			dev->rx_skb[i] = NULL;
+			dev->rx_desc[i].data_ptr = 0;
+		}
+
+	if (dev->rx_sg_skb) {
+		dev_kfree_skb(dev->rx_sg_skb);
+		dev->rx_sg_skb = NULL;
+	}
+}
+
+static inline int emac_alloc_rx_skb(struct emac_instance *dev, int slot,
+				    gfp_t flags)
+{
+	struct sk_buff *skb = alloc_skb(dev->rx_skb_size, flags);
+	if (unlikely(!skb))
+		return -ENOMEM;
+
+	dev->rx_skb[slot] = skb;
+	dev->rx_desc[slot].data_len = 0;
+
+	skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2);
+	dev->rx_desc[slot].data_ptr =
+	    dma_map_single(&dev->ofdev->dev, skb->data - 2, dev->rx_sync_size,
+			   DMA_FROM_DEVICE) + 2;
+	wmb();
+	dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY |
+	    (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);
+
+	return 0;
+}
+
+static void emac_print_link_status(struct emac_instance *dev)
+{
+	if (netif_carrier_ok(dev->ndev))
+		printk(KERN_INFO "%s: link is up, %d %s%s\n",
+		       dev->ndev->name, dev->phy.speed,
+		       dev->phy.duplex == DUPLEX_FULL ? "FDX" : "HDX",
+		       dev->phy.pause ? ", pause enabled" :
+		       dev->phy.asym_pause ? ", asymmetric pause enabled" : "");
+	else
+		printk(KERN_INFO "%s: link is down\n", dev->ndev->name);
+}
+
+/* Process ctx, rtnl_lock semaphore */
+static int emac_open(struct net_device *ndev)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+	int err, i;
+
+	DBG(dev, "open" NL);
+
+	/* Setup error IRQ handler */
+	err = request_irq(dev->emac_irq, emac_irq, 0, "EMAC", dev);
+	if (err) {
+		printk(KERN_ERR "%s: failed to request IRQ %d\n",
+		       ndev->name, dev->emac_irq);
+		return err;
+	}
+
+	/* Allocate RX ring */
+	for (i = 0; i < NUM_RX_BUFF; ++i)
+		if (emac_alloc_rx_skb(dev, i, GFP_KERNEL)) {
+			printk(KERN_ERR "%s: failed to allocate RX ring\n",
+			       ndev->name);
+			goto oom;
+		}
+
+	dev->tx_cnt = dev->tx_slot = dev->ack_slot = dev->rx_slot = 0;
+	clear_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags);
+	dev->rx_sg_skb = NULL;
+
+	mutex_lock(&dev->link_lock);
+
+	/* XXX Start PHY polling now. Shouldn't wr do like sungem instead and
+	 * always poll the PHY even when the iface is down ? That would allow
+	 * things like laptop-net to work. --BenH
+	 */
+	if (dev->phy.address >= 0) {
+		int link_poll_interval;
+		if (dev->phy.def->ops->poll_link(&dev->phy)) {
+			dev->phy.def->ops->read_link(&dev->phy);
+			netif_carrier_on(dev->ndev);
+			link_poll_interval = PHY_POLL_LINK_ON;
+		} else {
+			netif_carrier_off(dev->ndev);
+			link_poll_interval = PHY_POLL_LINK_OFF;
+		}
+		dev->link_polling = 1;
+		wmb();
+		schedule_delayed_work(&dev->link_work, link_poll_interval);
+		emac_print_link_status(dev);
+	} else
+		netif_carrier_on(dev->ndev);
+
+	emac_configure(dev);
+	mal_poll_add(dev->mal, &dev->commac);
+	mal_enable_tx_channel(dev->mal, dev->mal_tx_chan);
+	mal_set_rcbs(dev->mal, dev->mal_rx_chan, emac_rx_size(ndev->mtu));
+	mal_enable_rx_channel(dev->mal, dev->mal_rx_chan);
+	emac_tx_enable(dev);
+	emac_rx_enable(dev);
+	emac_netif_start(dev);
+
+	mutex_unlock(&dev->link_lock);
+
+	return 0;
+ oom:
+	emac_clean_rx_ring(dev);
+	free_irq(dev->emac_irq, dev);
+
+	return -ENOMEM;
+}
+
+/* BHs disabled */
+#if 0
+static int emac_link_differs(struct emac_instance *dev)
+{
+	u32 r = in_be32(&dev->emacp->mr1);
+
+	int duplex = r & EMAC_MR1_FDE ? DUPLEX_FULL : DUPLEX_HALF;
+	int speed, pause, asym_pause;
+
+	if (r & EMAC_MR1_MF_1000)
+		speed = SPEED_1000;
+	else if (r & EMAC_MR1_MF_100)
+		speed = SPEED_100;
+	else
+		speed = SPEED_10;
+
+	switch (r & (EMAC_MR1_EIFC | EMAC_MR1_APP)) {
+	case (EMAC_MR1_EIFC | EMAC_MR1_APP):
+		pause = 1;
+		asym_pause = 0;
+		break;
+	case EMAC_MR1_APP:
+		pause = 0;
+		asym_pause = 1;
+		break;
+	default:
+		pause = asym_pause = 0;
+	}
+	return speed != dev->phy.speed || duplex != dev->phy.duplex ||
+	    pause != dev->phy.pause || asym_pause != dev->phy.asym_pause;
+}
+#endif
+
+static void emac_link_timer(struct work_struct *work)
+{
+	struct emac_instance *dev =
+		container_of((struct delayed_work *)work,
+			     struct emac_instance, link_work);
+	int link_poll_interval;
+
+	mutex_lock(&dev->link_lock);
+
+	DBG2(dev, "link timer" NL);
+
+	if (dev->phy.def->ops->poll_link(&dev->phy)) {
+		if (!netif_carrier_ok(dev->ndev)) {
+			/* Get new link parameters */
+			dev->phy.def->ops->read_link(&dev->phy);
+
+			netif_carrier_on(dev->ndev);
+			emac_netif_stop(dev);
+			emac_full_tx_reset(dev);
+			emac_netif_start(dev);
+			emac_print_link_status(dev);
+		}
+		link_poll_interval = PHY_POLL_LINK_ON;
+	} else {
+		if (netif_carrier_ok(dev->ndev)) {
+			emac_reinitialize(dev);
+			netif_carrier_off(dev->ndev);
+			netif_tx_disable(dev->ndev);
+			emac_print_link_status(dev);
+		}
+		link_poll_interval = PHY_POLL_LINK_OFF;
+	}
+	schedule_delayed_work(&dev->link_work, link_poll_interval);
+
+	mutex_unlock(&dev->link_lock);
+}
+
+static void emac_force_link_update(struct emac_instance *dev)
+{
+	netif_carrier_off(dev->ndev);
+	if (dev->link_polling) {
+		cancel_rearming_delayed_work(&dev->link_work);
+		if (dev->link_polling)
+			schedule_delayed_work(&dev->link_work,  PHY_POLL_LINK_OFF);
+	}
+}
+
+/* Process ctx, rtnl_lock semaphore */
+static int emac_close(struct net_device *ndev)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+
+	DBG(dev, "close" NL);
+
+	if (dev->phy.address >= 0)
+		cancel_rearming_delayed_work(&dev->link_work);
+
+	emac_netif_stop(dev);
+	flush_scheduled_work();
+
+	emac_rx_disable(dev);
+	emac_tx_disable(dev);
+	mal_disable_rx_channel(dev->mal, dev->mal_rx_chan);
+	mal_disable_tx_channel(dev->mal, dev->mal_tx_chan);
+	mal_poll_del(dev->mal, &dev->commac);
+
+	emac_clean_tx_ring(dev);
+	emac_clean_rx_ring(dev);
+
+	free_irq(dev->emac_irq, dev);
+
+	return 0;
+}
+
+static inline u16 emac_tx_csum(struct emac_instance *dev,
+			       struct sk_buff *skb)
+{
+	if (emac_has_feature(dev, EMAC_FTR_HAS_TAH &&
+			     skb->ip_summed == CHECKSUM_PARTIAL)) {
+		++dev->stats.tx_packets_csum;
+		return EMAC_TX_CTRL_TAH_CSUM;
+	}
+	return 0;
+}
+
+static inline int emac_xmit_finish(struct emac_instance *dev, int len)
+{
+	struct emac_regs __iomem *p = dev->emacp;
+	struct net_device *ndev = dev->ndev;
+
+	/* Send the packet out. If the if makes a significant perf
+	 * difference, then we can store the TMR0 value in "dev"
+	 * instead
+	 */
+	if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+		out_be32(&p->tmr0, EMAC4_TMR0_XMIT);
+	else
+		out_be32(&p->tmr0, EMAC_TMR0_XMIT);
+
+	if (unlikely(++dev->tx_cnt == NUM_TX_BUFF)) {
+		netif_stop_queue(ndev);
+		DBG2(dev, "stopped TX queue" NL);
+	}
+
+	ndev->trans_start = jiffies;
+	++dev->stats.tx_packets;
+	dev->stats.tx_bytes += len;
+
+	return 0;
+}
+
+/* Tx lock BH */
+static int emac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+	unsigned int len = skb->len;
+	int slot;
+
+	u16 ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY |
+	    MAL_TX_CTRL_LAST | emac_tx_csum(dev, skb);
+
+	slot = dev->tx_slot++;
+	if (dev->tx_slot == NUM_TX_BUFF) {
+		dev->tx_slot = 0;
+		ctrl |= MAL_TX_CTRL_WRAP;
+	}
+
+	DBG2(dev, "xmit(%u) %d" NL, len, slot);
+
+	dev->tx_skb[slot] = skb;
+	dev->tx_desc[slot].data_ptr = dma_map_single(&dev->ofdev->dev,
+						     skb->data, len,
+						     DMA_TO_DEVICE);
+	dev->tx_desc[slot].data_len = (u16) len;
+	wmb();
+	dev->tx_desc[slot].ctrl = ctrl;
+
+	return emac_xmit_finish(dev, len);
+}
+
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+static inline int emac_xmit_split(struct emac_instance *dev, int slot,
+				  u32 pd, int len, int last, u16 base_ctrl)
+{
+	while (1) {
+		u16 ctrl = base_ctrl;
+		int chunk = min(len, MAL_MAX_TX_SIZE);
+		len -= chunk;
+
+		slot = (slot + 1) % NUM_TX_BUFF;
+
+		if (last && !len)
+			ctrl |= MAL_TX_CTRL_LAST;
+		if (slot == NUM_TX_BUFF - 1)
+			ctrl |= MAL_TX_CTRL_WRAP;
+
+		dev->tx_skb[slot] = NULL;
+		dev->tx_desc[slot].data_ptr = pd;
+		dev->tx_desc[slot].data_len = (u16) chunk;
+		dev->tx_desc[slot].ctrl = ctrl;
+		++dev->tx_cnt;
+
+		if (!len)
+			break;
+
+		pd += chunk;
+	}
+	return slot;
+}
+
+/* Tx lock BH disabled (SG version for TAH equipped EMACs) */
+static int emac_start_xmit_sg(struct sk_buff *skb, struct net_device *ndev)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+	int nr_frags = skb_shinfo(skb)->nr_frags;
+	int len = skb->len, chunk;
+	int slot, i;
+	u16 ctrl;
+	u32 pd;
+
+	/* This is common "fast" path */
+	if (likely(!nr_frags && len <= MAL_MAX_TX_SIZE))
+		return emac_start_xmit(skb, ndev);
+
+	len -= skb->data_len;
+
+	/* Note, this is only an *estimation*, we can still run out of empty
+	 * slots because of the additional fragmentation into
+	 * MAL_MAX_TX_SIZE-sized chunks
+	 */
+	if (unlikely(dev->tx_cnt + nr_frags + mal_tx_chunks(len) > NUM_TX_BUFF))
+		goto stop_queue;
+
+	ctrl = EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP | MAL_TX_CTRL_READY |
+	    emac_tx_csum(dev, skb);
+	slot = dev->tx_slot;
+
+	/* skb data */
+	dev->tx_skb[slot] = NULL;
+	chunk = min(len, MAL_MAX_TX_SIZE);
+	dev->tx_desc[slot].data_ptr = pd =
+	    dma_map_single(&dev->ofdev->dev, skb->data, len, DMA_TO_DEVICE);
+	dev->tx_desc[slot].data_len = (u16) chunk;
+	len -= chunk;
+	if (unlikely(len))
+		slot = emac_xmit_split(dev, slot, pd + chunk, len, !nr_frags,
+				       ctrl);
+	/* skb fragments */
+	for (i = 0; i < nr_frags; ++i) {
+		struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
+		len = frag->size;
+
+		if (unlikely(dev->tx_cnt + mal_tx_chunks(len) >= NUM_TX_BUFF))
+			goto undo_frame;
+
+		pd = dma_map_page(&dev->ofdev->dev, frag->page, frag->page_offset, len,
+				  DMA_TO_DEVICE);
+
+		slot = emac_xmit_split(dev, slot, pd, len, i == nr_frags - 1,
+				       ctrl);
+	}
+
+	DBG2(dev, "xmit_sg(%u) %d - %d" NL, skb->len, dev->tx_slot, slot);
+
+	/* Attach skb to the last slot so we don't release it too early */
+	dev->tx_skb[slot] = skb;
+
+	/* Send the packet out */
+	if (dev->tx_slot == NUM_TX_BUFF - 1)
+		ctrl |= MAL_TX_CTRL_WRAP;
+	wmb();
+	dev->tx_desc[dev->tx_slot].ctrl = ctrl;
+	dev->tx_slot = (slot + 1) % NUM_TX_BUFF;
+
+	return emac_xmit_finish(dev, skb->len);
+
+ undo_frame:
+	/* Well, too bad. Our previous estimation was overly optimistic.
+	 * Undo everything.
+	 */
+	while (slot != dev->tx_slot) {
+		dev->tx_desc[slot].ctrl = 0;
+		--dev->tx_cnt;
+		if (--slot < 0)
+			slot = NUM_TX_BUFF - 1;
+	}
+	++dev->estats.tx_undo;
+
+ stop_queue:
+	netif_stop_queue(ndev);
+	DBG2(dev, "stopped TX queue" NL);
+	return 1;
+}
+#else
+# define emac_start_xmit_sg	emac_start_xmit
+#endif	/* !defined(CONFIG_IBM_NEW_EMAC_TAH) */
+
+/* Tx lock BHs */
+static void emac_parse_tx_error(struct emac_instance *dev, u16 ctrl)
+{
+	struct emac_error_stats *st = &dev->estats;
+
+	DBG(dev, "BD TX error %04x" NL, ctrl);
+
+	++st->tx_bd_errors;
+	if (ctrl & EMAC_TX_ST_BFCS)
+		++st->tx_bd_bad_fcs;
+	if (ctrl & EMAC_TX_ST_LCS)
+		++st->tx_bd_carrier_loss;
+	if (ctrl & EMAC_TX_ST_ED)
+		++st->tx_bd_excessive_deferral;
+	if (ctrl & EMAC_TX_ST_EC)
+		++st->tx_bd_excessive_collisions;
+	if (ctrl & EMAC_TX_ST_LC)
+		++st->tx_bd_late_collision;
+	if (ctrl & EMAC_TX_ST_MC)
+		++st->tx_bd_multple_collisions;
+	if (ctrl & EMAC_TX_ST_SC)
+		++st->tx_bd_single_collision;
+	if (ctrl & EMAC_TX_ST_UR)
+		++st->tx_bd_underrun;
+	if (ctrl & EMAC_TX_ST_SQE)
+		++st->tx_bd_sqe;
+}
+
+static void emac_poll_tx(void *param)
+{
+	struct emac_instance *dev = param;
+	u32 bad_mask;
+
+	DBG2(dev, "poll_tx, %d %d" NL, dev->tx_cnt, dev->ack_slot);
+
+	if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
+		bad_mask = EMAC_IS_BAD_TX_TAH;
+	else
+		bad_mask = EMAC_IS_BAD_TX;
+
+	netif_tx_lock_bh(dev->ndev);
+	if (dev->tx_cnt) {
+		u16 ctrl;
+		int slot = dev->ack_slot, n = 0;
+	again:
+		ctrl = dev->tx_desc[slot].ctrl;
+		if (!(ctrl & MAL_TX_CTRL_READY)) {
+			struct sk_buff *skb = dev->tx_skb[slot];
+			++n;
+
+			if (skb) {
+				dev_kfree_skb(skb);
+				dev->tx_skb[slot] = NULL;
+			}
+			slot = (slot + 1) % NUM_TX_BUFF;
+
+			if (unlikely(ctrl & bad_mask))
+				emac_parse_tx_error(dev, ctrl);
+
+			if (--dev->tx_cnt)
+				goto again;
+		}
+		if (n) {
+			dev->ack_slot = slot;
+			if (netif_queue_stopped(dev->ndev) &&
+			    dev->tx_cnt < EMAC_TX_WAKEUP_THRESH)
+				netif_wake_queue(dev->ndev);
+
+			DBG2(dev, "tx %d pkts" NL, n);
+		}
+	}
+	netif_tx_unlock_bh(dev->ndev);
+}
+
+static inline void emac_recycle_rx_skb(struct emac_instance *dev, int slot,
+				       int len)
+{
+	struct sk_buff *skb = dev->rx_skb[slot];
+
+	DBG2(dev, "recycle %d %d" NL, slot, len);
+
+	if (len)
+		dma_map_single(&dev->ofdev->dev, skb->data - 2,
+			       EMAC_DMA_ALIGN(len + 2), DMA_FROM_DEVICE);
+
+	dev->rx_desc[slot].data_len = 0;
+	wmb();
+	dev->rx_desc[slot].ctrl = MAL_RX_CTRL_EMPTY |
+	    (slot == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);
+}
+
+static void emac_parse_rx_error(struct emac_instance *dev, u16 ctrl)
+{
+	struct emac_error_stats *st = &dev->estats;
+
+	DBG(dev, "BD RX error %04x" NL, ctrl);
+
+	++st->rx_bd_errors;
+	if (ctrl & EMAC_RX_ST_OE)
+		++st->rx_bd_overrun;
+	if (ctrl & EMAC_RX_ST_BP)
+		++st->rx_bd_bad_packet;
+	if (ctrl & EMAC_RX_ST_RP)
+		++st->rx_bd_runt_packet;
+	if (ctrl & EMAC_RX_ST_SE)
+		++st->rx_bd_short_event;
+	if (ctrl & EMAC_RX_ST_AE)
+		++st->rx_bd_alignment_error;
+	if (ctrl & EMAC_RX_ST_BFCS)
+		++st->rx_bd_bad_fcs;
+	if (ctrl & EMAC_RX_ST_PTL)
+		++st->rx_bd_packet_too_long;
+	if (ctrl & EMAC_RX_ST_ORE)
+		++st->rx_bd_out_of_range;
+	if (ctrl & EMAC_RX_ST_IRE)
+		++st->rx_bd_in_range;
+}
+
+static inline void emac_rx_csum(struct emac_instance *dev,
+				struct sk_buff *skb, u16 ctrl)
+{
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+	if (!ctrl && dev->tah_dev) {
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+		++dev->stats.rx_packets_csum;
+	}
+#endif
+}
+
+static inline int emac_rx_sg_append(struct emac_instance *dev, int slot)
+{
+	if (likely(dev->rx_sg_skb != NULL)) {
+		int len = dev->rx_desc[slot].data_len;
+		int tot_len = dev->rx_sg_skb->len + len;
+
+		if (unlikely(tot_len + 2 > dev->rx_skb_size)) {
+			++dev->estats.rx_dropped_mtu;
+			dev_kfree_skb(dev->rx_sg_skb);
+			dev->rx_sg_skb = NULL;
+		} else {
+			cacheable_memcpy(dev->rx_sg_skb->tail,
+					 dev->rx_skb[slot]->data, len);
+			skb_put(dev->rx_sg_skb, len);
+			emac_recycle_rx_skb(dev, slot, len);
+			return 0;
+		}
+	}
+	emac_recycle_rx_skb(dev, slot, 0);
+	return -1;
+}
+
+/* NAPI poll context */
+static int emac_poll_rx(void *param, int budget)
+{
+	struct emac_instance *dev = param;
+	int slot = dev->rx_slot, received = 0;
+
+	DBG2(dev, "poll_rx(%d)" NL, budget);
+
+ again:
+	while (budget > 0) {
+		int len;
+		struct sk_buff *skb;
+		u16 ctrl = dev->rx_desc[slot].ctrl;
+
+		if (ctrl & MAL_RX_CTRL_EMPTY)
+			break;
+
+		skb = dev->rx_skb[slot];
+		mb();
+		len = dev->rx_desc[slot].data_len;
+
+		if (unlikely(!MAL_IS_SINGLE_RX(ctrl)))
+			goto sg;
+
+		ctrl &= EMAC_BAD_RX_MASK;
+		if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) {
+			emac_parse_rx_error(dev, ctrl);
+			++dev->estats.rx_dropped_error;
+			emac_recycle_rx_skb(dev, slot, 0);
+			len = 0;
+			goto next;
+		}
+
+		if (len && len < EMAC_RX_COPY_THRESH) {
+			struct sk_buff *copy_skb =
+			    alloc_skb(len + EMAC_RX_SKB_HEADROOM + 2, GFP_ATOMIC);
+			if (unlikely(!copy_skb))
+				goto oom;
+
+			skb_reserve(copy_skb, EMAC_RX_SKB_HEADROOM + 2);
+			cacheable_memcpy(copy_skb->data - 2, skb->data - 2,
+					 len + 2);
+			emac_recycle_rx_skb(dev, slot, len);
+			skb = copy_skb;
+		} else if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC)))
+			goto oom;
+
+		skb_put(skb, len);
+	push_packet:
+		skb->dev = dev->ndev;
+		skb->protocol = eth_type_trans(skb, dev->ndev);
+		emac_rx_csum(dev, skb, ctrl);
+
+		if (unlikely(netif_receive_skb(skb) == NET_RX_DROP))
+			++dev->estats.rx_dropped_stack;
+	next:
+		++dev->stats.rx_packets;
+	skip:
+		dev->stats.rx_bytes += len;
+		slot = (slot + 1) % NUM_RX_BUFF;
+		--budget;
+		++received;
+		continue;
+	sg:
+		if (ctrl & MAL_RX_CTRL_FIRST) {
+			BUG_ON(dev->rx_sg_skb);
+			if (unlikely(emac_alloc_rx_skb(dev, slot, GFP_ATOMIC))) {
+				DBG(dev, "rx OOM %d" NL, slot);
+				++dev->estats.rx_dropped_oom;
+				emac_recycle_rx_skb(dev, slot, 0);
+			} else {
+				dev->rx_sg_skb = skb;
+				skb_put(skb, len);
+			}
+		} else if (!emac_rx_sg_append(dev, slot) &&
+			   (ctrl & MAL_RX_CTRL_LAST)) {
+
+			skb = dev->rx_sg_skb;
+			dev->rx_sg_skb = NULL;
+
+			ctrl &= EMAC_BAD_RX_MASK;
+			if (unlikely(ctrl && ctrl != EMAC_RX_TAH_BAD_CSUM)) {
+				emac_parse_rx_error(dev, ctrl);
+				++dev->estats.rx_dropped_error;
+				dev_kfree_skb(skb);
+				len = 0;
+			} else
+				goto push_packet;
+		}
+		goto skip;
+	oom:
+		DBG(dev, "rx OOM %d" NL, slot);
+		/* Drop the packet and recycle skb */
+		++dev->estats.rx_dropped_oom;
+		emac_recycle_rx_skb(dev, slot, 0);
+		goto next;
+	}
+
+	if (received) {
+		DBG2(dev, "rx %d BDs" NL, received);
+		dev->rx_slot = slot;
+	}
+
+	if (unlikely(budget && test_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags))) {
+		mb();
+		if (!(dev->rx_desc[slot].ctrl & MAL_RX_CTRL_EMPTY)) {
+			DBG2(dev, "rx restart" NL);
+			received = 0;
+			goto again;
+		}
+
+		if (dev->rx_sg_skb) {
+			DBG2(dev, "dropping partial rx packet" NL);
+			++dev->estats.rx_dropped_error;
+			dev_kfree_skb(dev->rx_sg_skb);
+			dev->rx_sg_skb = NULL;
+		}
+
+		clear_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags);
+		mal_enable_rx_channel(dev->mal, dev->mal_rx_chan);
+		emac_rx_enable(dev);
+		dev->rx_slot = 0;
+	}
+	return received;
+}
+
+/* NAPI poll context */
+static int emac_peek_rx(void *param)
+{
+	struct emac_instance *dev = param;
+
+	return !(dev->rx_desc[dev->rx_slot].ctrl & MAL_RX_CTRL_EMPTY);
+}
+
+/* NAPI poll context */
+static int emac_peek_rx_sg(void *param)
+{
+	struct emac_instance *dev = param;
+
+	int slot = dev->rx_slot;
+	while (1) {
+		u16 ctrl = dev->rx_desc[slot].ctrl;
+		if (ctrl & MAL_RX_CTRL_EMPTY)
+			return 0;
+		else if (ctrl & MAL_RX_CTRL_LAST)
+			return 1;
+
+		slot = (slot + 1) % NUM_RX_BUFF;
+
+		/* I'm just being paranoid here :) */
+		if (unlikely(slot == dev->rx_slot))
+			return 0;
+	}
+}
+
+/* Hard IRQ */
+static void emac_rxde(void *param)
+{
+	struct emac_instance *dev = param;
+
+	++dev->estats.rx_stopped;
+	emac_rx_disable_async(dev);
+}
+
+/* Hard IRQ */
+static irqreturn_t emac_irq(int irq, void *dev_instance)
+{
+	struct emac_instance *dev = dev_instance;
+	struct emac_regs __iomem *p = dev->emacp;
+	struct emac_error_stats *st = &dev->estats;
+	u32 isr;
+
+	spin_lock(&dev->lock);
+
+	isr = in_be32(&p->isr);
+	out_be32(&p->isr, isr);
+
+	DBG(dev, "isr = %08x" NL, isr);
+
+	if (isr & EMAC4_ISR_TXPE)
+		++st->tx_parity;
+	if (isr & EMAC4_ISR_RXPE)
+		++st->rx_parity;
+	if (isr & EMAC4_ISR_TXUE)
+		++st->tx_underrun;
+	if (isr & EMAC4_ISR_RXOE)
+		++st->rx_fifo_overrun;
+	if (isr & EMAC_ISR_OVR)
+		++st->rx_overrun;
+	if (isr & EMAC_ISR_BP)
+		++st->rx_bad_packet;
+	if (isr & EMAC_ISR_RP)
+		++st->rx_runt_packet;
+	if (isr & EMAC_ISR_SE)
+		++st->rx_short_event;
+	if (isr & EMAC_ISR_ALE)
+		++st->rx_alignment_error;
+	if (isr & EMAC_ISR_BFCS)
+		++st->rx_bad_fcs;
+	if (isr & EMAC_ISR_PTLE)
+		++st->rx_packet_too_long;
+	if (isr & EMAC_ISR_ORE)
+		++st->rx_out_of_range;
+	if (isr & EMAC_ISR_IRE)
+		++st->rx_in_range;
+	if (isr & EMAC_ISR_SQE)
+		++st->tx_sqe;
+	if (isr & EMAC_ISR_TE)
+		++st->tx_errors;
+
+	spin_unlock(&dev->lock);
+
+	return IRQ_HANDLED;
+}
+
+static struct net_device_stats *emac_stats(struct net_device *ndev)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+	struct emac_stats *st = &dev->stats;
+	struct emac_error_stats *est = &dev->estats;
+	struct net_device_stats *nst = &dev->nstats;
+	unsigned long flags;
+
+	DBG2(dev, "stats" NL);
+
+	/* Compute "legacy" statistics */
+	spin_lock_irqsave(&dev->lock, flags);
+	nst->rx_packets = (unsigned long)st->rx_packets;
+	nst->rx_bytes = (unsigned long)st->rx_bytes;
+	nst->tx_packets = (unsigned long)st->tx_packets;
+	nst->tx_bytes = (unsigned long)st->tx_bytes;
+	nst->rx_dropped = (unsigned long)(est->rx_dropped_oom +
+					  est->rx_dropped_error +
+					  est->rx_dropped_resize +
+					  est->rx_dropped_mtu);
+	nst->tx_dropped = (unsigned long)est->tx_dropped;
+
+	nst->rx_errors = (unsigned long)est->rx_bd_errors;
+	nst->rx_fifo_errors = (unsigned long)(est->rx_bd_overrun +
+					      est->rx_fifo_overrun +
+					      est->rx_overrun);
+	nst->rx_frame_errors = (unsigned long)(est->rx_bd_alignment_error +
+					       est->rx_alignment_error);
+	nst->rx_crc_errors = (unsigned long)(est->rx_bd_bad_fcs +
+					     est->rx_bad_fcs);
+	nst->rx_length_errors = (unsigned long)(est->rx_bd_runt_packet +
+						est->rx_bd_short_event +
+						est->rx_bd_packet_too_long +
+						est->rx_bd_out_of_range +
+						est->rx_bd_in_range +
+						est->rx_runt_packet +
+						est->rx_short_event +
+						est->rx_packet_too_long +
+						est->rx_out_of_range +
+						est->rx_in_range);
+
+	nst->tx_errors = (unsigned long)(est->tx_bd_errors + est->tx_errors);
+	nst->tx_fifo_errors = (unsigned long)(est->tx_bd_underrun +
+					      est->tx_underrun);
+	nst->tx_carrier_errors = (unsigned long)est->tx_bd_carrier_loss;
+	nst->collisions = (unsigned long)(est->tx_bd_excessive_deferral +
+					  est->tx_bd_excessive_collisions +
+					  est->tx_bd_late_collision +
+					  est->tx_bd_multple_collisions);
+	spin_unlock_irqrestore(&dev->lock, flags);
+	return nst;
+}
+
+static struct mal_commac_ops emac_commac_ops = {
+	.poll_tx = &emac_poll_tx,
+	.poll_rx = &emac_poll_rx,
+	.peek_rx = &emac_peek_rx,
+	.rxde = &emac_rxde,
+};
+
+static struct mal_commac_ops emac_commac_sg_ops = {
+	.poll_tx = &emac_poll_tx,
+	.poll_rx = &emac_poll_rx,
+	.peek_rx = &emac_peek_rx_sg,
+	.rxde = &emac_rxde,
+};
+
+/* Ethtool support */
+static int emac_ethtool_get_settings(struct net_device *ndev,
+				     struct ethtool_cmd *cmd)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+
+	cmd->supported = dev->phy.features;
+	cmd->port = PORT_MII;
+	cmd->phy_address = dev->phy.address;
+	cmd->transceiver =
+	    dev->phy.address >= 0 ? XCVR_EXTERNAL : XCVR_INTERNAL;
+
+	mutex_lock(&dev->link_lock);
+	cmd->advertising = dev->phy.advertising;
+	cmd->autoneg = dev->phy.autoneg;
+	cmd->speed = dev->phy.speed;
+	cmd->duplex = dev->phy.duplex;
+	mutex_unlock(&dev->link_lock);
+
+	return 0;
+}
+
+static int emac_ethtool_set_settings(struct net_device *ndev,
+				     struct ethtool_cmd *cmd)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+	u32 f = dev->phy.features;
+
+	DBG(dev, "set_settings(%d, %d, %d, 0x%08x)" NL,
+	    cmd->autoneg, cmd->speed, cmd->duplex, cmd->advertising);
+
+	/* Basic sanity checks */
+	if (dev->phy.address < 0)
+		return -EOPNOTSUPP;
+	if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE)
+		return -EINVAL;
+	if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0)
+		return -EINVAL;
+	if (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL)
+		return -EINVAL;
+
+	if (cmd->autoneg == AUTONEG_DISABLE) {
+		switch (cmd->speed) {
+		case SPEED_10:
+			if (cmd->duplex == DUPLEX_HALF
+			    && !(f & SUPPORTED_10baseT_Half))
+				return -EINVAL;
+			if (cmd->duplex == DUPLEX_FULL
+			    && !(f & SUPPORTED_10baseT_Full))
+				return -EINVAL;
+			break;
+		case SPEED_100:
+			if (cmd->duplex == DUPLEX_HALF
+			    && !(f & SUPPORTED_100baseT_Half))
+				return -EINVAL;
+			if (cmd->duplex == DUPLEX_FULL
+			    && !(f & SUPPORTED_100baseT_Full))
+				return -EINVAL;
+			break;
+		case SPEED_1000:
+			if (cmd->duplex == DUPLEX_HALF
+			    && !(f & SUPPORTED_1000baseT_Half))
+				return -EINVAL;
+			if (cmd->duplex == DUPLEX_FULL
+			    && !(f & SUPPORTED_1000baseT_Full))
+				return -EINVAL;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		mutex_lock(&dev->link_lock);
+		dev->phy.def->ops->setup_forced(&dev->phy, cmd->speed,
+						cmd->duplex);
+		mutex_unlock(&dev->link_lock);
+
+	} else {
+		if (!(f & SUPPORTED_Autoneg))
+			return -EINVAL;
+
+		mutex_lock(&dev->link_lock);
+		dev->phy.def->ops->setup_aneg(&dev->phy,
+					      (cmd->advertising & f) |
+					      (dev->phy.advertising &
+					       (ADVERTISED_Pause |
+						ADVERTISED_Asym_Pause)));
+		mutex_unlock(&dev->link_lock);
+	}
+	emac_force_link_update(dev);
+
+	return 0;
+}
+
+static void emac_ethtool_get_ringparam(struct net_device *ndev,
+				       struct ethtool_ringparam *rp)
+{
+	rp->rx_max_pending = rp->rx_pending = NUM_RX_BUFF;
+	rp->tx_max_pending = rp->tx_pending = NUM_TX_BUFF;
+}
+
+static void emac_ethtool_get_pauseparam(struct net_device *ndev,
+					struct ethtool_pauseparam *pp)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+
+	mutex_lock(&dev->link_lock);
+	if ((dev->phy.features & SUPPORTED_Autoneg) &&
+	    (dev->phy.advertising & (ADVERTISED_Pause | ADVERTISED_Asym_Pause)))
+		pp->autoneg = 1;
+
+	if (dev->phy.duplex == DUPLEX_FULL) {
+		if (dev->phy.pause)
+			pp->rx_pause = pp->tx_pause = 1;
+		else if (dev->phy.asym_pause)
+			pp->tx_pause = 1;
+	}
+	mutex_unlock(&dev->link_lock);
+}
+
+static u32 emac_ethtool_get_rx_csum(struct net_device *ndev)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+
+	return dev->tah_dev != 0;
+}
+
+static int emac_get_regs_len(struct emac_instance *dev)
+{
+	if (emac_has_feature(dev, EMAC_FTR_EMAC4))
+		return sizeof(struct emac_ethtool_regs_subhdr) +
+			EMAC4_ETHTOOL_REGS_SIZE;
+	else
+		return sizeof(struct emac_ethtool_regs_subhdr) +
+			EMAC_ETHTOOL_REGS_SIZE;
+}
+
+static int emac_ethtool_get_regs_len(struct net_device *ndev)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+	int size;
+
+	size = sizeof(struct emac_ethtool_regs_hdr) +
+		emac_get_regs_len(dev) + mal_get_regs_len(dev->mal);
+	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+		size += zmii_get_regs_len(dev->zmii_dev);
+	if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+		size += rgmii_get_regs_len(dev->rgmii_dev);
+	if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
+		size += tah_get_regs_len(dev->tah_dev);
+
+	return size;
+}
+
+static void *emac_dump_regs(struct emac_instance *dev, void *buf)
+{
+	struct emac_ethtool_regs_subhdr *hdr = buf;
+
+	hdr->index = dev->cell_index;
+	if (emac_has_feature(dev, EMAC_FTR_EMAC4)) {
+		hdr->version = EMAC4_ETHTOOL_REGS_VER;
+		memcpy_fromio(hdr + 1, dev->emacp, EMAC4_ETHTOOL_REGS_SIZE);
+		return ((void *)(hdr + 1) + EMAC4_ETHTOOL_REGS_SIZE);
+	} else {
+		hdr->version = EMAC_ETHTOOL_REGS_VER;
+		memcpy_fromio(hdr + 1, dev->emacp, EMAC_ETHTOOL_REGS_SIZE);
+		return ((void *)(hdr + 1) + EMAC_ETHTOOL_REGS_SIZE);
+	}
+}
+
+static void emac_ethtool_get_regs(struct net_device *ndev,
+				  struct ethtool_regs *regs, void *buf)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+	struct emac_ethtool_regs_hdr *hdr = buf;
+
+	hdr->components = 0;
+	buf = hdr + 1;
+
+	buf = mal_dump_regs(dev->mal, buf);
+	buf = emac_dump_regs(dev, buf);
+	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII)) {
+		hdr->components |= EMAC_ETHTOOL_REGS_ZMII;
+		buf = zmii_dump_regs(dev->zmii_dev, buf);
+	}
+	if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) {
+		hdr->components |= EMAC_ETHTOOL_REGS_RGMII;
+		buf = rgmii_dump_regs(dev->rgmii_dev, buf);
+	}
+	if (emac_has_feature(dev, EMAC_FTR_HAS_TAH)) {
+		hdr->components |= EMAC_ETHTOOL_REGS_TAH;
+		buf = tah_dump_regs(dev->tah_dev, buf);
+	}
+}
+
+static int emac_ethtool_nway_reset(struct net_device *ndev)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+	int res = 0;
+
+	DBG(dev, "nway_reset" NL);
+
+	if (dev->phy.address < 0)
+		return -EOPNOTSUPP;
+
+	mutex_lock(&dev->link_lock);
+	if (!dev->phy.autoneg) {
+		res = -EINVAL;
+		goto out;
+	}
+
+	dev->phy.def->ops->setup_aneg(&dev->phy, dev->phy.advertising);
+ out:
+	mutex_unlock(&dev->link_lock);
+	emac_force_link_update(dev);
+	return res;
+}
+
+static int emac_ethtool_get_stats_count(struct net_device *ndev)
+{
+	return EMAC_ETHTOOL_STATS_COUNT;
+}
+
+static void emac_ethtool_get_strings(struct net_device *ndev, u32 stringset,
+				     u8 * buf)
+{
+	if (stringset == ETH_SS_STATS)
+		memcpy(buf, &emac_stats_keys, sizeof(emac_stats_keys));
+}
+
+static void emac_ethtool_get_ethtool_stats(struct net_device *ndev,
+					   struct ethtool_stats *estats,
+					   u64 * tmp_stats)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+
+	memcpy(tmp_stats, &dev->stats, sizeof(dev->stats));
+	tmp_stats += sizeof(dev->stats) / sizeof(u64);
+	memcpy(tmp_stats, &dev->estats, sizeof(dev->estats));
+}
+
+static void emac_ethtool_get_drvinfo(struct net_device *ndev,
+				     struct ethtool_drvinfo *info)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+
+	strcpy(info->driver, "ibm_emac");
+	strcpy(info->version, DRV_VERSION);
+	info->fw_version[0] = '\0';
+	sprintf(info->bus_info, "PPC 4xx EMAC-%d %s",
+		dev->cell_index, dev->ofdev->node->full_name);
+	info->n_stats = emac_ethtool_get_stats_count(ndev);
+	info->regdump_len = emac_ethtool_get_regs_len(ndev);
+}
+
+static const struct ethtool_ops emac_ethtool_ops = {
+	.get_settings = emac_ethtool_get_settings,
+	.set_settings = emac_ethtool_set_settings,
+	.get_drvinfo = emac_ethtool_get_drvinfo,
+
+	.get_regs_len = emac_ethtool_get_regs_len,
+	.get_regs = emac_ethtool_get_regs,
+
+	.nway_reset = emac_ethtool_nway_reset,
+
+	.get_ringparam = emac_ethtool_get_ringparam,
+	.get_pauseparam = emac_ethtool_get_pauseparam,
+
+	.get_rx_csum = emac_ethtool_get_rx_csum,
+
+	.get_strings = emac_ethtool_get_strings,
+	.get_stats_count = emac_ethtool_get_stats_count,
+	.get_ethtool_stats = emac_ethtool_get_ethtool_stats,
+
+	.get_link = ethtool_op_get_link,
+	.get_tx_csum = ethtool_op_get_tx_csum,
+	.get_sg = ethtool_op_get_sg,
+};
+
+static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
+{
+	struct emac_instance *dev = netdev_priv(ndev);
+	uint16_t *data = (uint16_t *) & rq->ifr_ifru;
+
+	DBG(dev, "ioctl %08x" NL, cmd);
+
+	if (dev->phy.address < 0)
+		return -EOPNOTSUPP;
+
+	switch (cmd) {
+	case SIOCGMIIPHY:
+	case SIOCDEVPRIVATE:
+		data[0] = dev->phy.address;
+		/* Fall through */
+	case SIOCGMIIREG:
+	case SIOCDEVPRIVATE + 1:
+		data[3] = emac_mdio_read(ndev, dev->phy.address, data[1]);
+		return 0;
+
+	case SIOCSMIIREG:
+	case SIOCDEVPRIVATE + 2:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		emac_mdio_write(ndev, dev->phy.address, data[1], data[2]);
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+struct emac_depentry {
+	u32			phandle;
+	struct device_node	*node;
+	struct of_device	*ofdev;
+	void			*drvdata;
+};
+
+#define	EMAC_DEP_MAL_IDX	0
+#define	EMAC_DEP_ZMII_IDX	1
+#define	EMAC_DEP_RGMII_IDX	2
+#define	EMAC_DEP_TAH_IDX	3
+#define	EMAC_DEP_MDIO_IDX	4
+#define	EMAC_DEP_PREV_IDX	5
+#define	EMAC_DEP_COUNT		6
+
+static int __devinit emac_check_deps(struct emac_instance *dev,
+				     struct emac_depentry *deps)
+{
+	int i, there = 0;
+	struct device_node *np;
+
+	for (i = 0; i < EMAC_DEP_COUNT; i++) {
+		/* no dependency on that item, allright */
+		if (deps[i].phandle == 0) {
+			there++;
+			continue;
+		}
+		/* special case for blist as the dependency might go away */
+		if (i == EMAC_DEP_PREV_IDX) {
+			np = *(dev->blist - 1);
+			if (np == NULL) {
+				deps[i].phandle = 0;
+				there++;
+				continue;
+			}
+			if (deps[i].node == NULL)
+				deps[i].node = of_node_get(np);
+		}
+		if (deps[i].node == NULL)
+			deps[i].node = of_find_node_by_phandle(deps[i].phandle);
+		if (deps[i].node == NULL)
+			continue;
+		if (deps[i].ofdev == NULL)
+			deps[i].ofdev = of_find_device_by_node(deps[i].node);
+		if (deps[i].ofdev == NULL)
+			continue;
+		if (deps[i].drvdata == NULL)
+			deps[i].drvdata = dev_get_drvdata(&deps[i].ofdev->dev);
+		if (deps[i].drvdata != NULL)
+			there++;
+	}
+	return (there == EMAC_DEP_COUNT);
+}
+
+static void emac_put_deps(struct emac_instance *dev)
+{
+	if (dev->mal_dev)
+		of_dev_put(dev->mal_dev);
+	if (dev->zmii_dev)
+		of_dev_put(dev->zmii_dev);
+	if (dev->rgmii_dev)
+		of_dev_put(dev->rgmii_dev);
+	if (dev->mdio_dev)
+		of_dev_put(dev->mdio_dev);
+	if (dev->tah_dev)
+		of_dev_put(dev->tah_dev);
+}
+
+static int __devinit emac_of_bus_notify(struct notifier_block *nb,
+					unsigned long action, void *data)
+{
+	/* We are only intereted in device addition */
+	if (action == BUS_NOTIFY_BOUND_DRIVER)
+		wake_up_all(&emac_probe_wait);
+	return 0;
+}
+
+static struct notifier_block emac_of_bus_notifier = {
+	.notifier_call = emac_of_bus_notify
+};
+
+static int __devinit emac_wait_deps(struct emac_instance *dev)
+{
+	struct emac_depentry deps[EMAC_DEP_COUNT];
+	int i, err;
+
+	memset(&deps, 0, sizeof(deps));
+
+	deps[EMAC_DEP_MAL_IDX].phandle = dev->mal_ph;
+	deps[EMAC_DEP_ZMII_IDX].phandle = dev->zmii_ph;
+	deps[EMAC_DEP_RGMII_IDX].phandle = dev->rgmii_ph;
+	if (dev->tah_ph)
+		deps[EMAC_DEP_TAH_IDX].phandle = dev->tah_ph;
+	if (dev->mdio_ph)
+		deps[EMAC_DEP_MDIO_IDX].phandle = dev->mdio_ph;
+	if (dev->blist && dev->blist > emac_boot_list)
+		deps[EMAC_DEP_PREV_IDX].phandle = 0xffffffffu;
+	bus_register_notifier(&of_platform_bus_type, &emac_of_bus_notifier);
+	wait_event_timeout(emac_probe_wait,
+			   emac_check_deps(dev, deps),
+			   EMAC_PROBE_DEP_TIMEOUT);
+	bus_unregister_notifier(&of_platform_bus_type, &emac_of_bus_notifier);
+	err = emac_check_deps(dev, deps) ? 0 : -ENODEV;
+	for (i = 0; i < EMAC_DEP_COUNT; i++) {
+		if (deps[i].node)
+			of_node_put(deps[i].node);
+		if (err && deps[i].ofdev)
+			of_dev_put(deps[i].ofdev);
+	}
+	if (err == 0) {
+		dev->mal_dev = deps[EMAC_DEP_MAL_IDX].ofdev;
+		dev->zmii_dev = deps[EMAC_DEP_ZMII_IDX].ofdev;
+		dev->rgmii_dev = deps[EMAC_DEP_RGMII_IDX].ofdev;
+		dev->tah_dev = deps[EMAC_DEP_TAH_IDX].ofdev;
+		dev->mdio_dev = deps[EMAC_DEP_MDIO_IDX].ofdev;
+	}
+	if (deps[EMAC_DEP_PREV_IDX].ofdev)
+		of_dev_put(deps[EMAC_DEP_PREV_IDX].ofdev);
+	return err;
+}
+
+static int __devinit emac_read_uint_prop(struct device_node *np, const char *name,
+					 u32 *val, int fatal)
+{
+	int len;
+	const u32 *prop = of_get_property(np, name, &len);
+	if (prop == NULL || len < sizeof(u32)) {
+		if (fatal)
+			printk(KERN_ERR "%s: missing %s property\n",
+			       np->full_name, name);
+		return -ENODEV;
+	}
+	*val = *prop;
+	return 0;
+}
+
+static int __devinit emac_init_phy(struct emac_instance *dev)
+{
+	struct device_node *np = dev->ofdev->node;
+	struct net_device *ndev = dev->ndev;
+	u32 phy_map, adv;
+	int i;
+
+	dev->phy.dev = ndev;
+	dev->phy.mode = dev->phy_mode;
+
+	/* PHY-less configuration.
+	 * XXX I probably should move these settings to the dev tree
+	 */
+	if (dev->phy_address == 0xffffffff && dev->phy_map == 0xffffffff) {
+		emac_reset(dev);
+
+		/* PHY-less configuration.
+		 * XXX I probably should move these settings to the dev tree
+		 */
+		dev->phy.address = -1;
+		dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII;
+		dev->phy.pause = 1;
+
+		return 0;
+	}
+
+	mutex_lock(&emac_phy_map_lock);
+	phy_map = dev->phy_map | busy_phy_map;
+
+	DBG(dev, "PHY maps %08x %08x" NL, dev->phy_map, busy_phy_map);
+
+	dev->phy.mdio_read = emac_mdio_read;
+	dev->phy.mdio_write = emac_mdio_write;
+
+	/* Configure EMAC with defaults so we can at least use MDIO
+	 * This is needed mostly for 440GX
+	 */
+	if (emac_phy_gpcs(dev->phy.mode)) {
+		/* XXX
+		 * Make GPCS PHY address equal to EMAC index.
+		 * We probably should take into account busy_phy_map
+		 * and/or phy_map here.
+		 *
+		 * Note that the busy_phy_map is currently global
+		 * while it should probably be per-ASIC...
+		 */
+		dev->phy.address = dev->cell_index;
+	}
+
+	emac_configure(dev);
+
+	if (dev->phy_address != 0xffffffff)
+		phy_map = ~(1 << dev->phy_address);
+
+	for (i = 0; i < 0x20; phy_map >>= 1, ++i)
+		if (!(phy_map & 1)) {
+			int r;
+			busy_phy_map |= 1 << i;
+
+			/* Quick check if there is a PHY at the address */
+			r = emac_mdio_read(dev->ndev, i, MII_BMCR);
+			if (r == 0xffff || r < 0)
+				continue;
+			if (!emac_mii_phy_probe(&dev->phy, i))
+				break;
+		}
+	mutex_unlock(&emac_phy_map_lock);
+	if (i == 0x20) {
+		printk(KERN_WARNING "%s: can't find PHY!\n", np->full_name);
+		return -ENXIO;
+	}
+
+	/* Init PHY */
+	if (dev->phy.def->ops->init)
+		dev->phy.def->ops->init(&dev->phy);
+
+	/* Disable any PHY features not supported by the platform */
+	dev->phy.def->features &= ~dev->phy_feat_exc;
+
+	/* Setup initial link parameters */
+	if (dev->phy.features & SUPPORTED_Autoneg) {
+		adv = dev->phy.features;
+		if (!emac_has_feature(dev, EMAC_FTR_NO_FLOW_CONTROL_40x))
+			adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
+		/* Restart autonegotiation */
+		dev->phy.def->ops->setup_aneg(&dev->phy, adv);
+	} else {
+		u32 f = dev->phy.def->features;
+		int speed = SPEED_10, fd = DUPLEX_HALF;
+
+		/* Select highest supported speed/duplex */
+		if (f & SUPPORTED_1000baseT_Full) {
+			speed = SPEED_1000;
+			fd = DUPLEX_FULL;
+		} else if (f & SUPPORTED_1000baseT_Half)
+			speed = SPEED_1000;
+		else if (f & SUPPORTED_100baseT_Full) {
+			speed = SPEED_100;
+			fd = DUPLEX_FULL;
+		} else if (f & SUPPORTED_100baseT_Half)
+			speed = SPEED_100;
+		else if (f & SUPPORTED_10baseT_Full)
+			fd = DUPLEX_FULL;
+
+		/* Force link parameters */
+		dev->phy.def->ops->setup_forced(&dev->phy, speed, fd);
+	}
+	return 0;
+}
+
+static int __devinit emac_init_config(struct emac_instance *dev)
+{
+	struct device_node *np = dev->ofdev->node;
+	const void *p;
+	unsigned int plen;
+	const char *pm, *phy_modes[] = {
+		[PHY_MODE_NA] = "",
+		[PHY_MODE_MII] = "mii",
+		[PHY_MODE_RMII] = "rmii",
+		[PHY_MODE_SMII] = "smii",
+		[PHY_MODE_RGMII] = "rgmii",
+		[PHY_MODE_TBI] = "tbi",
+		[PHY_MODE_GMII] = "gmii",
+		[PHY_MODE_RTBI] = "rtbi",
+		[PHY_MODE_SGMII] = "sgmii",
+	};
+
+	/* Read config from device-tree */
+	if (emac_read_uint_prop(np, "mal-device", &dev->mal_ph, 1))
+		return -ENXIO;
+	if (emac_read_uint_prop(np, "mal-tx-channel", &dev->mal_tx_chan, 1))
+		return -ENXIO;
+	if (emac_read_uint_prop(np, "mal-rx-channel", &dev->mal_rx_chan, 1))
+		return -ENXIO;
+	if (emac_read_uint_prop(np, "cell-index", &dev->cell_index, 1))
+		return -ENXIO;
+	if (emac_read_uint_prop(np, "max-frame-size", &dev->max_mtu, 0))
+		dev->max_mtu = 1500;
+	if (emac_read_uint_prop(np, "rx-fifo-size", &dev->rx_fifo_size, 0))
+		dev->rx_fifo_size = 2048;
+	if (emac_read_uint_prop(np, "tx-fifo-size", &dev->tx_fifo_size, 0))
+		dev->tx_fifo_size = 2048;
+	if (emac_read_uint_prop(np, "rx-fifo-size-gige", &dev->rx_fifo_size_gige, 0))
+		dev->rx_fifo_size_gige = dev->rx_fifo_size;
+	if (emac_read_uint_prop(np, "tx-fifo-size-gige", &dev->tx_fifo_size_gige, 0))
+		dev->tx_fifo_size_gige = dev->tx_fifo_size;
+	if (emac_read_uint_prop(np, "phy-address", &dev->phy_address, 0))
+		dev->phy_address = 0xffffffff;
+	if (emac_read_uint_prop(np, "phy-map", &dev->phy_map, 0))
+		dev->phy_map = 0xffffffff;
+	if (emac_read_uint_prop(np->parent, "clock-frequency", &dev->opb_bus_freq, 1))
+		return -ENXIO;
+	if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0))
+		dev->tah_ph = 0;
+	if (emac_read_uint_prop(np, "tah-channel", &dev->tah_port, 0))
+		dev->tah_ph = 0;
+	if (emac_read_uint_prop(np, "mdio-device", &dev->mdio_ph, 0))
+		dev->mdio_ph = 0;
+	if (emac_read_uint_prop(np, "zmii-device", &dev->zmii_ph, 0))
+		dev->zmii_ph = 0;;
+	if (emac_read_uint_prop(np, "zmii-channel", &dev->zmii_port, 0))
+		dev->zmii_port = 0xffffffff;;
+	if (emac_read_uint_prop(np, "rgmii-device", &dev->rgmii_ph, 0))
+		dev->rgmii_ph = 0;;
+	if (emac_read_uint_prop(np, "rgmii-channel", &dev->rgmii_port, 0))
+		dev->rgmii_port = 0xffffffff;;
+	if (emac_read_uint_prop(np, "fifo-entry-size", &dev->fifo_entry_size, 0))
+		dev->fifo_entry_size = 16;
+	if (emac_read_uint_prop(np, "mal-burst-size", &dev->mal_burst_size, 0))
+		dev->mal_burst_size = 256;
+
+	/* PHY mode needs some decoding */
+	dev->phy_mode = PHY_MODE_NA;
+	pm = of_get_property(np, "phy-mode", &plen);
+	if (pm != NULL) {
+		int i;
+		for (i = 0; i < ARRAY_SIZE(phy_modes); i++)
+			if (!strcasecmp(pm, phy_modes[i])) {
+				dev->phy_mode = i;
+				break;
+			}
+	}
+
+	/* Backward compat with non-final DT */
+	if (dev->phy_mode == PHY_MODE_NA && pm != NULL && plen == 4) {
+		u32 nmode = *(const u32 *)pm;
+		if (nmode > PHY_MODE_NA && nmode <= PHY_MODE_SGMII)
+			dev->phy_mode = nmode;
+	}
+
+	/* Check EMAC version */
+	if (of_device_is_compatible(np, "ibm,emac4"))
+		dev->features |= EMAC_FTR_EMAC4;
+	if (of_device_is_compatible(np, "ibm,emac-axon")
+	    || of_device_is_compatible(np, "ibm,emac-440epx"))
+		dev->features |= EMAC_FTR_HAS_AXON_STACR
+			| EMAC_FTR_STACR_OC_INVERT;
+	if (of_device_is_compatible(np, "ibm,emac-440spe"))
+		dev->features |= EMAC_FTR_STACR_OC_INVERT;
+
+	/* Fixup some feature bits based on the device tree and verify
+	 * we have support for them compiled in
+	 */
+	if (dev->tah_ph != 0) {
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+		dev->features |= EMAC_FTR_HAS_TAH;
+#else
+		printk(KERN_ERR "%s: TAH support not enabled !\n",
+		       np->full_name);
+		return -ENXIO;
+#endif
+	}
+
+	if (dev->zmii_ph != 0) {
+#ifdef CONFIG_IBM_NEW_EMAC_ZMII
+		dev->features |= EMAC_FTR_HAS_ZMII;
+#else
+		printk(KERN_ERR "%s: ZMII support not enabled !\n",
+		       np->full_name);
+		return -ENXIO;
+#endif
+	}
+
+	if (dev->rgmii_ph != 0) {
+#ifdef CONFIG_IBM_NEW_EMAC_RGMII
+		dev->features |= EMAC_FTR_HAS_RGMII;
+#else
+		printk(KERN_ERR "%s: RGMII support not enabled !\n",
+		       np->full_name);
+		return -ENXIO;
+#endif
+	}
+
+	/* Read MAC-address */
+	p = of_get_property(np, "local-mac-address", NULL);
+	if (p == NULL) {
+		printk(KERN_ERR "%s: Can't find local-mac-address property\n",
+		       np->full_name);
+		return -ENXIO;
+	}
+	memcpy(dev->ndev->dev_addr, p, 6);
+
+	DBG(dev, "features     : 0x%08x / 0x%08x\n", dev->features, EMAC_FTRS_POSSIBLE);
+	DBG(dev, "tx_fifo_size : %d (%d gige)\n", dev->tx_fifo_size, dev->tx_fifo_size_gige);
+	DBG(dev, "rx_fifo_size : %d (%d gige)\n", dev->rx_fifo_size, dev->rx_fifo_size_gige);
+	DBG(dev, "max_mtu      : %d\n", dev->max_mtu);
+	DBG(dev, "OPB freq     : %d\n", dev->opb_bus_freq);
+
+	return 0;
+}
+
+static int __devinit emac_probe(struct of_device *ofdev,
+				const struct of_device_id *match)
+{
+	struct net_device *ndev;
+	struct emac_instance *dev;
+	struct device_node *np = ofdev->node;
+	struct device_node **blist = NULL;
+	int err, i;
+
+	/* Find ourselves in the bootlist if we are there */
+	for (i = 0; i < EMAC_BOOT_LIST_SIZE; i++)
+		if (emac_boot_list[i] == np)
+			blist = &emac_boot_list[i];
+
+	/* Allocate our net_device structure */
+	err = -ENOMEM;
+	ndev = alloc_etherdev(sizeof(struct emac_instance));
+	if (!ndev) {
+		printk(KERN_ERR "%s: could not allocate ethernet device!\n",
+		       np->full_name);
+		goto err_gone;
+	}
+	dev = netdev_priv(ndev);
+	dev->ndev = ndev;
+	dev->ofdev = ofdev;
+	dev->blist = blist;
+	SET_NETDEV_DEV(ndev, &ofdev->dev);
+
+	/* Initialize some embedded data structures */
+	mutex_init(&dev->mdio_lock);
+	mutex_init(&dev->link_lock);
+	spin_lock_init(&dev->lock);
+	INIT_WORK(&dev->reset_work, emac_reset_work);
+
+	/* Init various config data based on device-tree */
+	err = emac_init_config(dev);
+	if (err != 0)
+		goto err_free;
+
+	/* Get interrupts. EMAC irq is mandatory, WOL irq is optional */
+	dev->emac_irq = irq_of_parse_and_map(np, 0);
+	dev->wol_irq = irq_of_parse_and_map(np, 1);
+	if (dev->emac_irq == NO_IRQ) {
+		printk(KERN_ERR "%s: Can't map main interrupt\n", np->full_name);
+		goto err_free;
+	}
+	ndev->irq = dev->emac_irq;
+
+	/* Map EMAC regs */
+	if (of_address_to_resource(np, 0, &dev->rsrc_regs)) {
+		printk(KERN_ERR "%s: Can't get registers address\n",
+		       np->full_name);
+		goto err_irq_unmap;
+	}
+	// TODO : request_mem_region
+	dev->emacp = ioremap(dev->rsrc_regs.start, sizeof(struct emac_regs));
+	if (dev->emacp == NULL) {
+		printk(KERN_ERR "%s: Can't map device registers!\n",
+		       np->full_name);
+		err = -ENOMEM;
+		goto err_irq_unmap;
+	}
+
+	/* Wait for dependent devices */
+	err = emac_wait_deps(dev);
+	if (err) {
+		printk(KERN_ERR
+		       "%s: Timeout waiting for dependent devices\n",
+		       np->full_name);
+		/*  display more info about what's missing ? */
+		goto err_reg_unmap;
+	}
+	dev->mal = dev_get_drvdata(&dev->mal_dev->dev);
+	if (dev->mdio_dev != NULL)
+		dev->mdio_instance = dev_get_drvdata(&dev->mdio_dev->dev);
+
+	/* Register with MAL */
+	dev->commac.ops = &emac_commac_ops;
+	dev->commac.dev = dev;
+	dev->commac.tx_chan_mask = MAL_CHAN_MASK(dev->mal_tx_chan);
+	dev->commac.rx_chan_mask = MAL_CHAN_MASK(dev->mal_rx_chan);
+	err = mal_register_commac(dev->mal, &dev->commac);
+	if (err) {
+		printk(KERN_ERR "%s: failed to register with mal %s!\n",
+		       np->full_name, dev->mal_dev->node->full_name);
+		goto err_rel_deps;
+	}
+	dev->rx_skb_size = emac_rx_skb_size(ndev->mtu);
+	dev->rx_sync_size = emac_rx_sync_size(ndev->mtu);
+
+	/* Get pointers to BD rings */
+	dev->tx_desc =
+	    dev->mal->bd_virt + mal_tx_bd_offset(dev->mal, dev->mal_tx_chan);
+	dev->rx_desc =
+	    dev->mal->bd_virt + mal_rx_bd_offset(dev->mal, dev->mal_rx_chan);
+
+	DBG(dev, "tx_desc %p" NL, dev->tx_desc);
+	DBG(dev, "rx_desc %p" NL, dev->rx_desc);
+
+	/* Clean rings */
+	memset(dev->tx_desc, 0, NUM_TX_BUFF * sizeof(struct mal_descriptor));
+	memset(dev->rx_desc, 0, NUM_RX_BUFF * sizeof(struct mal_descriptor));
+
+	/* Attach to ZMII, if needed */
+	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII) &&
+	    (err = zmii_attach(dev->zmii_dev, dev->zmii_port, &dev->phy_mode)) != 0)
+		goto err_unreg_commac;
+
+	/* Attach to RGMII, if needed */
+	if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII) &&
+	    (err = rgmii_attach(dev->rgmii_dev, dev->rgmii_port, dev->phy_mode)) != 0)
+		goto err_detach_zmii;
+
+	/* Attach to TAH, if needed */
+	if (emac_has_feature(dev, EMAC_FTR_HAS_TAH) &&
+	    (err = tah_attach(dev->tah_dev, dev->tah_port)) != 0)
+		goto err_detach_rgmii;
+
+	/* Set some link defaults before we can find out real parameters */
+	dev->phy.speed = SPEED_100;
+	dev->phy.duplex = DUPLEX_FULL;
+	dev->phy.autoneg = AUTONEG_DISABLE;
+	dev->phy.pause = dev->phy.asym_pause = 0;
+	dev->stop_timeout = STOP_TIMEOUT_100;
+	INIT_DELAYED_WORK(&dev->link_work, emac_link_timer);
+
+	/* Find PHY if any */
+	err = emac_init_phy(dev);
+	if (err != 0)
+		goto err_detach_tah;
+
+	/* Fill in the driver function table */
+	ndev->open = &emac_open;
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+	if (dev->tah_dev) {
+		ndev->hard_start_xmit = &emac_start_xmit_sg;
+		ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
+	} else
+#endif
+		ndev->hard_start_xmit = &emac_start_xmit;
+	ndev->tx_timeout = &emac_tx_timeout;
+	ndev->watchdog_timeo = 5 * HZ;
+	ndev->stop = &emac_close;
+	ndev->get_stats = &emac_stats;
+	ndev->set_multicast_list = &emac_set_multicast_list;
+	ndev->do_ioctl = &emac_ioctl;
+	if (emac_phy_supports_gige(dev->phy_mode)) {
+		ndev->change_mtu = &emac_change_mtu;
+		dev->commac.ops = &emac_commac_sg_ops;
+	}
+	SET_ETHTOOL_OPS(ndev, &emac_ethtool_ops);
+
+	netif_carrier_off(ndev);
+	netif_stop_queue(ndev);
+
+	err = register_netdev(ndev);
+	if (err) {
+		printk(KERN_ERR "%s: failed to register net device (%d)!\n",
+		       np->full_name, err);
+		goto err_detach_tah;
+	}
+
+	/* Set our drvdata last as we don't want them visible until we are
+	 * fully initialized
+	 */
+	wmb();
+	dev_set_drvdata(&ofdev->dev, dev);
+
+	/* There's a new kid in town ! Let's tell everybody */
+	wake_up_all(&emac_probe_wait);
+
+
+	printk(KERN_INFO
+	       "%s: EMAC-%d %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       ndev->name, dev->cell_index, np->full_name,
+	       ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
+	       ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+
+	if (dev->phy.address >= 0)
+		printk("%s: found %s PHY (0x%02x)\n", ndev->name,
+		       dev->phy.def->name, dev->phy.address);
+
+	emac_dbg_register(dev);
+
+	/* Life is good */
+	return 0;
+
+	/* I have a bad feeling about this ... */
+
+ err_detach_tah:
+	if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
+		tah_detach(dev->tah_dev, dev->tah_port);
+ err_detach_rgmii:
+	if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+		rgmii_detach(dev->rgmii_dev, dev->rgmii_port);
+ err_detach_zmii:
+	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+		zmii_detach(dev->zmii_dev, dev->zmii_port);
+ err_unreg_commac:
+	mal_unregister_commac(dev->mal, &dev->commac);
+ err_rel_deps:
+	emac_put_deps(dev);
+ err_reg_unmap:
+	iounmap(dev->emacp);
+ err_irq_unmap:
+	if (dev->wol_irq != NO_IRQ)
+		irq_dispose_mapping(dev->wol_irq);
+	if (dev->emac_irq != NO_IRQ)
+		irq_dispose_mapping(dev->emac_irq);
+ err_free:
+	kfree(ndev);
+ err_gone:
+	/* if we were on the bootlist, remove us as we won't show up and
+	 * wake up all waiters to notify them in case they were waiting
+	 * on us
+	 */
+	if (blist) {
+		*blist = NULL;
+		wake_up_all(&emac_probe_wait);
+	}
+	return err;
+}
+
+static int __devexit emac_remove(struct of_device *ofdev)
+{
+	struct emac_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+	DBG(dev, "remove" NL);
+
+	dev_set_drvdata(&ofdev->dev, NULL);
+
+	unregister_netdev(dev->ndev);
+
+	if (emac_has_feature(dev, EMAC_FTR_HAS_TAH))
+		tah_detach(dev->tah_dev, dev->tah_port);
+	if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))
+		rgmii_detach(dev->rgmii_dev, dev->rgmii_port);
+	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
+		zmii_detach(dev->zmii_dev, dev->zmii_port);
+
+	mal_unregister_commac(dev->mal, &dev->commac);
+	emac_put_deps(dev);
+
+	emac_dbg_unregister(dev);
+	iounmap(dev->emacp);
+
+	if (dev->wol_irq != NO_IRQ)
+		irq_dispose_mapping(dev->wol_irq);
+	if (dev->emac_irq != NO_IRQ)
+		irq_dispose_mapping(dev->emac_irq);
+
+	kfree(dev->ndev);
+
+	return 0;
+}
+
+/* XXX Features in here should be replaced by properties... */
+static struct of_device_id emac_match[] =
+{
+	{
+		.type		= "network",
+		.compatible	= "ibm,emac",
+	},
+	{
+		.type		= "network",
+		.compatible	= "ibm,emac4",
+	},
+	{},
+};
+
+static struct of_platform_driver emac_driver = {
+	.name = "emac",
+	.match_table = emac_match,
+
+	.probe = emac_probe,
+	.remove = emac_remove,
+};
+
+static void __init emac_make_bootlist(void)
+{
+	struct device_node *np = NULL;
+	int j, max, i = 0, k;
+	int cell_indices[EMAC_BOOT_LIST_SIZE];
+
+	/* Collect EMACs */
+	while((np = of_find_all_nodes(np)) != NULL) {
+		const u32 *idx;
+
+		if (of_match_node(emac_match, np) == NULL)
+			continue;
+		if (of_get_property(np, "unused", NULL))
+			continue;
+		idx = of_get_property(np, "cell-index", NULL);
+		if (idx == NULL)
+			continue;
+		cell_indices[i] = *idx;
+		emac_boot_list[i++] = of_node_get(np);
+		if (i >= EMAC_BOOT_LIST_SIZE) {
+			of_node_put(np);
+			break;
+		}
+	}
+	max = i;
+
+	/* Bubble sort them (doh, what a creative algorithm :-) */
+	for (i = 0; max > 1 && (i < (max - 1)); i++)
+		for (j = i; j < max; j++) {
+			if (cell_indices[i] > cell_indices[j]) {
+				np = emac_boot_list[i];
+				emac_boot_list[i] = emac_boot_list[j];
+				emac_boot_list[j] = np;
+				k = cell_indices[i];
+				cell_indices[i] = cell_indices[j];
+				cell_indices[j] = k;
+			}
+		}
+}
+
+static int __init emac_init(void)
+{
+	int rc;
+
+	printk(KERN_INFO DRV_DESC ", version " DRV_VERSION "\n");
+
+	/* Init debug stuff */
+	emac_init_debug();
+
+	/* Build EMAC boot list */
+	emac_make_bootlist();
+
+	/* Init submodules */
+	rc = mal_init();
+	if (rc)
+		goto err;
+	rc = zmii_init();
+	if (rc)
+		goto err_mal;
+	rc = rgmii_init();
+	if (rc)
+		goto err_zmii;
+	rc = tah_init();
+	if (rc)
+		goto err_rgmii;
+	rc = of_register_platform_driver(&emac_driver);
+	if (rc)
+		goto err_tah;
+
+	return 0;
+
+ err_tah:
+	tah_exit();
+ err_rgmii:
+	rgmii_exit();
+ err_zmii:
+	zmii_exit();
+ err_mal:
+	mal_exit();
+ err:
+	return rc;
+}
+
+static void __exit emac_exit(void)
+{
+	int i;
+
+	of_unregister_platform_driver(&emac_driver);
+
+	tah_exit();
+	rgmii_exit();
+	zmii_exit();
+	mal_exit();
+	emac_fini_debug();
+
+	/* Destroy EMAC boot list */
+	for (i = 0; i < EMAC_BOOT_LIST_SIZE; i++)
+		if (emac_boot_list[i])
+			of_node_put(emac_boot_list[i]);
+}
+
+module_init(emac_init);
+module_exit(emac_exit);
diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h
new file mode 100644
index 0000000..4011803
--- /dev/null
+++ b/drivers/net/ibm_newemac/core.h
@@ -0,0 +1,355 @@
+/*
+ * drivers/net/ibm_newemac/core.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ *      Armin Kuster <akuster@mvista.com>
+ * 	Johnnie Peters <jpeters@mvista.com>
+ *      Copyright 2000, 2001 MontaVista Softare Inc.
+ *
+ * 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.
+ *
+ */
+#ifndef __IBM_NEWEMAC_CORE_H
+#define __IBM_NEWEMAC_CORE_H
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/dma-mapping.h>
+#include <linux/spinlock.h>
+
+#include <asm/of_platform.h>
+#include <asm/io.h>
+#include <asm/dcr.h>
+
+#include "emac.h"
+#include "phy.h"
+#include "zmii.h"
+#include "rgmii.h"
+#include "mal.h"
+#include "tah.h"
+#include "debug.h"
+
+#define NUM_TX_BUFF			CONFIG_IBM_NEW_EMAC_TXB
+#define NUM_RX_BUFF			CONFIG_IBM_NEW_EMAC_RXB
+
+/* Simple sanity check */
+#if NUM_TX_BUFF > 256 || NUM_RX_BUFF > 256
+#error Invalid number of buffer descriptors (greater than 256)
+#endif
+
+#define EMAC_MIN_MTU			46
+
+/* Maximum L2 header length (VLAN tagged, no FCS) */
+#define EMAC_MTU_OVERHEAD		(6 * 2 + 2 + 4)
+
+/* RX BD size for the given MTU */
+static inline int emac_rx_size(int mtu)
+{
+	if (mtu > ETH_DATA_LEN)
+		return MAL_MAX_RX_SIZE;
+	else
+		return mal_rx_size(ETH_DATA_LEN + EMAC_MTU_OVERHEAD);
+}
+
+#define EMAC_DMA_ALIGN(x)		ALIGN((x), dma_get_cache_alignment())
+
+#define EMAC_RX_SKB_HEADROOM		\
+	EMAC_DMA_ALIGN(CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM)
+
+/* Size of RX skb for the given MTU */
+static inline int emac_rx_skb_size(int mtu)
+{
+	int size = max(mtu + EMAC_MTU_OVERHEAD, emac_rx_size(mtu));
+	return EMAC_DMA_ALIGN(size + 2) + EMAC_RX_SKB_HEADROOM;
+}
+
+/* RX DMA sync size */
+static inline int emac_rx_sync_size(int mtu)
+{
+	return EMAC_DMA_ALIGN(emac_rx_size(mtu) + 2);
+}
+
+/* Driver statistcs is split into two parts to make it more cache friendly:
+ *   - normal statistics (packet count, etc)
+ *   - error statistics
+ *
+ * When statistics is requested by ethtool, these parts are concatenated,
+ * normal one goes first.
+ *
+ * Please, keep these structures in sync with emac_stats_keys.
+ */
+
+/* Normal TX/RX Statistics */
+struct emac_stats {
+	u64 rx_packets;
+	u64 rx_bytes;
+	u64 tx_packets;
+	u64 tx_bytes;
+	u64 rx_packets_csum;
+	u64 tx_packets_csum;
+};
+
+/* Error statistics */
+struct emac_error_stats {
+	u64 tx_undo;
+
+	/* Software RX Errors */
+	u64 rx_dropped_stack;
+	u64 rx_dropped_oom;
+	u64 rx_dropped_error;
+	u64 rx_dropped_resize;
+	u64 rx_dropped_mtu;
+	u64 rx_stopped;
+	/* BD reported RX errors */
+	u64 rx_bd_errors;
+	u64 rx_bd_overrun;
+	u64 rx_bd_bad_packet;
+	u64 rx_bd_runt_packet;
+	u64 rx_bd_short_event;
+	u64 rx_bd_alignment_error;
+	u64 rx_bd_bad_fcs;
+	u64 rx_bd_packet_too_long;
+	u64 rx_bd_out_of_range;
+	u64 rx_bd_in_range;
+	/* EMAC IRQ reported RX errors */
+	u64 rx_parity;
+	u64 rx_fifo_overrun;
+	u64 rx_overrun;
+	u64 rx_bad_packet;
+	u64 rx_runt_packet;
+	u64 rx_short_event;
+	u64 rx_alignment_error;
+	u64 rx_bad_fcs;
+	u64 rx_packet_too_long;
+	u64 rx_out_of_range;
+	u64 rx_in_range;
+
+	/* Software TX Errors */
+	u64 tx_dropped;
+	/* BD reported TX errors */
+	u64 tx_bd_errors;
+	u64 tx_bd_bad_fcs;
+	u64 tx_bd_carrier_loss;
+	u64 tx_bd_excessive_deferral;
+	u64 tx_bd_excessive_collisions;
+	u64 tx_bd_late_collision;
+	u64 tx_bd_multple_collisions;
+	u64 tx_bd_single_collision;
+	u64 tx_bd_underrun;
+	u64 tx_bd_sqe;
+	/* EMAC IRQ reported TX errors */
+	u64 tx_parity;
+	u64 tx_underrun;
+	u64 tx_sqe;
+	u64 tx_errors;
+};
+
+#define EMAC_ETHTOOL_STATS_COUNT	((sizeof(struct emac_stats) + \
+					  sizeof(struct emac_error_stats)) \
+					 / sizeof(u64))
+
+struct emac_instance {
+	struct net_device		*ndev;
+	struct resource			rsrc_regs;
+	struct emac_regs		__iomem *emacp;
+	struct of_device		*ofdev;
+	struct device_node		**blist; /* bootlist entry */
+
+	/* MAL linkage */
+	u32				mal_ph;
+	struct of_device		*mal_dev;
+	u32				mal_rx_chan;
+	u32				mal_tx_chan;
+	struct mal_instance		*mal;
+	struct mal_commac		commac;
+
+	/* PHY infos */
+	u32				phy_mode;
+	u32				phy_map;
+	u32				phy_address;
+	u32				phy_feat_exc;
+	struct mii_phy			phy;
+	struct mutex			link_lock;
+	struct delayed_work		link_work;
+	int				link_polling;
+
+	/* Shared MDIO if any */
+	u32				mdio_ph;
+	struct of_device		*mdio_dev;
+	struct emac_instance		*mdio_instance;
+	struct mutex			mdio_lock;
+
+	/* ZMII infos if any */
+	u32				zmii_ph;
+	u32				zmii_port;
+	struct of_device		*zmii_dev;
+
+	/* RGMII infos if any */
+	u32				rgmii_ph;
+	u32				rgmii_port;
+	struct of_device		*rgmii_dev;
+
+	/* TAH infos if any */
+	u32				tah_ph;
+	u32				tah_port;
+	struct of_device		*tah_dev;
+
+	/* IRQs */
+	int				wol_irq;
+	int				emac_irq;
+
+	/* OPB bus frequency in Mhz */
+	u32				opb_bus_freq;
+
+	/* Cell index within an ASIC (for clk mgmnt) */
+	u32				cell_index;
+
+	/* Max supported MTU */
+	u32				max_mtu;
+
+	/* Feature bits (from probe table) */
+	unsigned int			features;
+
+	/* Tx and Rx fifo sizes & other infos in bytes */
+	u32				tx_fifo_size;
+	u32				tx_fifo_size_gige;
+	u32				rx_fifo_size;
+	u32				rx_fifo_size_gige;
+	u32				fifo_entry_size;
+	u32				mal_burst_size; /* move to MAL ? */
+
+	/* Descriptor management
+	 */
+	struct mal_descriptor		*tx_desc;
+	int				tx_cnt;
+	int				tx_slot;
+	int				ack_slot;
+
+	struct mal_descriptor		*rx_desc;
+	int				rx_slot;
+	struct sk_buff			*rx_sg_skb;	/* 1 */
+	int 				rx_skb_size;
+	int				rx_sync_size;
+
+	struct sk_buff			*tx_skb[NUM_TX_BUFF];
+	struct sk_buff			*rx_skb[NUM_RX_BUFF];
+
+	/* Stats
+	 */
+	struct emac_error_stats		estats;
+	struct net_device_stats		nstats;
+	struct emac_stats 		stats;
+
+	/* Misc
+	 */
+	int				reset_failed;
+	int				stop_timeout;	/* in us */
+	int				no_mcast;
+	int				mcast_pending;
+	struct work_struct		reset_work;
+	spinlock_t			lock;
+};
+
+/*
+ * Features of various EMAC implementations
+ */
+
+/*
+ * No flow control on 40x according to the original driver
+ */
+#define EMAC_FTR_NO_FLOW_CONTROL_40x	0x00000001
+/*
+ * Cell is an EMAC4
+ */
+#define EMAC_FTR_EMAC4			0x00000002
+/*
+ * For the 440SPe, AMCC inexplicably changed the polarity of
+ * the "operation complete" bit in the MII control register.
+ */
+#define EMAC_FTR_STACR_OC_INVERT	0x00000004
+/*
+ * Set if we have a TAH.
+ */
+#define EMAC_FTR_HAS_TAH		0x00000008
+/*
+ * Set if we have a ZMII.
+ */
+#define EMAC_FTR_HAS_ZMII		0x00000010
+/*
+ * Set if we have a RGMII.
+ */
+#define EMAC_FTR_HAS_RGMII		0x00000020
+/*
+ * Set if we have axon-type STACR
+ */
+#define EMAC_FTR_HAS_AXON_STACR		0x00000040
+
+
+/* Right now, we don't quite handle the always/possible masks on the
+ * most optimal way as we don't have a way to say something like
+ * always EMAC4. Patches welcome.
+ */
+enum {
+	EMAC_FTRS_ALWAYS	= 0,
+
+	EMAC_FTRS_POSSIBLE	=
+#ifdef CONFIG_IBM_NEW_EMAC_EMAC4
+	    EMAC_FTR_EMAC4	| EMAC_FTR_HAS_AXON_STACR	|
+	    EMAC_FTR_STACR_OC_INVERT	|
+#endif
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+	    EMAC_FTR_HAS_TAH	|
+#endif
+#ifdef CONFIG_IBM_NEW_EMAC_ZMII
+	    EMAC_FTR_HAS_ZMII	|
+#endif
+#ifdef CONFIG_IBM_NEW_EMAC_RGMII
+	    EMAC_FTR_HAS_RGMII	|
+#endif
+	    0,
+};
+
+static inline int emac_has_feature(struct emac_instance *dev,
+				   unsigned long feature)
+{
+	return (EMAC_FTRS_ALWAYS & feature) ||
+	       (EMAC_FTRS_POSSIBLE & dev->features & feature);
+}
+
+
+/* Ethtool get_regs complex data.
+ * We want to get not just EMAC registers, but also MAL, ZMII, RGMII, TAH
+ * when available.
+ *
+ * Returned BLOB consists of the ibm_emac_ethtool_regs_hdr,
+ * MAL registers, EMAC registers and optional ZMII, RGMII, TAH registers.
+ * Each register component is preceded with emac_ethtool_regs_subhdr.
+ * Order of the optional headers follows their relative bit posititions
+ * in emac_ethtool_regs_hdr.components
+ */
+#define EMAC_ETHTOOL_REGS_ZMII		0x00000001
+#define EMAC_ETHTOOL_REGS_RGMII		0x00000002
+#define EMAC_ETHTOOL_REGS_TAH		0x00000004
+
+struct emac_ethtool_regs_hdr {
+	u32 components;
+};
+
+struct emac_ethtool_regs_subhdr {
+	u32 version;
+	u32 index;
+};
+
+#endif /* __IBM_NEWEMAC_CORE_H */
diff --git a/drivers/net/ibm_newemac/debug.c b/drivers/net/ibm_newemac/debug.c
new file mode 100644
index 0000000..170524e
--- /dev/null
+++ b/drivers/net/ibm_newemac/debug.c
@@ -0,0 +1,238 @@
+/*
+ * drivers/net/ibm_newemac/debug.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/sysrq.h>
+#include <asm/io.h>
+
+#include "core.h"
+
+static spinlock_t emac_dbg_lock = SPIN_LOCK_UNLOCKED;
+
+static void emac_desc_dump(struct emac_instance *p)
+{
+	int i;
+	printk("** EMAC %s TX BDs **\n"
+	       " tx_cnt = %d tx_slot = %d ack_slot = %d\n",
+	       p->ofdev->node->full_name,
+	       p->tx_cnt, p->tx_slot, p->ack_slot);
+	for (i = 0; i < NUM_TX_BUFF / 2; ++i)
+		printk
+		    ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n",
+		     i, p->tx_desc[i].data_ptr, p->tx_skb[i] ? 'V' : ' ',
+		     p->tx_desc[i].ctrl, p->tx_desc[i].data_len,
+		     NUM_TX_BUFF / 2 + i,
+		     p->tx_desc[NUM_TX_BUFF / 2 + i].data_ptr,
+		     p->tx_skb[NUM_TX_BUFF / 2 + i] ? 'V' : ' ',
+		     p->tx_desc[NUM_TX_BUFF / 2 + i].ctrl,
+		     p->tx_desc[NUM_TX_BUFF / 2 + i].data_len);
+
+	printk("** EMAC %s RX BDs **\n"
+	       " rx_slot = %d flags = 0x%lx rx_skb_size = %d rx_sync_size = %d\n"
+	       " rx_sg_skb = 0x%p\n",
+	       p->ofdev->node->full_name,
+	       p->rx_slot, p->commac.flags, p->rx_skb_size,
+	       p->rx_sync_size, p->rx_sg_skb);
+	for (i = 0; i < NUM_RX_BUFF / 2; ++i)
+		printk
+		    ("bd[%2d] 0x%08x %c 0x%04x %4u - bd[%2d] 0x%08x %c 0x%04x %4u\n",
+		     i, p->rx_desc[i].data_ptr, p->rx_skb[i] ? 'V' : ' ',
+		     p->rx_desc[i].ctrl, p->rx_desc[i].data_len,
+		     NUM_RX_BUFF / 2 + i,
+		     p->rx_desc[NUM_RX_BUFF / 2 + i].data_ptr,
+		     p->rx_skb[NUM_RX_BUFF / 2 + i] ? 'V' : ' ',
+		     p->rx_desc[NUM_RX_BUFF / 2 + i].ctrl,
+		     p->rx_desc[NUM_RX_BUFF / 2 + i].data_len);
+}
+
+static void emac_mac_dump(struct emac_instance *dev)
+{
+	struct emac_regs __iomem *p = dev->emacp;
+
+	printk("** EMAC %s registers **\n"
+	       "MR0 = 0x%08x MR1 = 0x%08x TMR0 = 0x%08x TMR1 = 0x%08x\n"
+	       "RMR = 0x%08x ISR = 0x%08x ISER = 0x%08x\n"
+	       "IAR = %04x%08x VTPID = 0x%04x VTCI = 0x%04x\n"
+	       "IAHT: 0x%04x 0x%04x 0x%04x 0x%04x "
+	       "GAHT: 0x%04x 0x%04x 0x%04x 0x%04x\n"
+	       "LSA = %04x%08x IPGVR = 0x%04x\n"
+	       "STACR = 0x%08x TRTR = 0x%08x RWMR = 0x%08x\n"
+	       "OCTX = 0x%08x OCRX = 0x%08x IPCR = 0x%08x\n",
+	       dev->ofdev->node->full_name, in_be32(&p->mr0), in_be32(&p->mr1),
+	       in_be32(&p->tmr0), in_be32(&p->tmr1),
+	       in_be32(&p->rmr), in_be32(&p->isr), in_be32(&p->iser),
+	       in_be32(&p->iahr), in_be32(&p->ialr), in_be32(&p->vtpid),
+	       in_be32(&p->vtci),
+	       in_be32(&p->iaht1), in_be32(&p->iaht2), in_be32(&p->iaht3),
+	       in_be32(&p->iaht4),
+	       in_be32(&p->gaht1), in_be32(&p->gaht2), in_be32(&p->gaht3),
+	       in_be32(&p->gaht4),
+	       in_be32(&p->lsah), in_be32(&p->lsal), in_be32(&p->ipgvr),
+	       in_be32(&p->stacr), in_be32(&p->trtr), in_be32(&p->rwmr),
+	       in_be32(&p->octx), in_be32(&p->ocrx), in_be32(&p->ipcr)
+	    );
+
+	emac_desc_dump(dev);
+}
+
+static void emac_mal_dump(struct mal_instance *mal)
+{
+	int i;
+
+	printk("** MAL %s Registers **\n"
+	       "CFG = 0x%08x ESR = 0x%08x IER = 0x%08x\n"
+	       "TX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n"
+	       "RX|CASR = 0x%08x CARR = 0x%08x EOBISR = 0x%08x DEIR = 0x%08x\n",
+	       mal->ofdev->node->full_name,
+	       get_mal_dcrn(mal, MAL_CFG), get_mal_dcrn(mal, MAL_ESR),
+	       get_mal_dcrn(mal, MAL_IER),
+	       get_mal_dcrn(mal, MAL_TXCASR), get_mal_dcrn(mal, MAL_TXCARR),
+	       get_mal_dcrn(mal, MAL_TXEOBISR), get_mal_dcrn(mal, MAL_TXDEIR),
+	       get_mal_dcrn(mal, MAL_RXCASR), get_mal_dcrn(mal, MAL_RXCARR),
+	       get_mal_dcrn(mal, MAL_RXEOBISR), get_mal_dcrn(mal, MAL_RXDEIR)
+	    );
+
+	printk("TX|");
+	for (i = 0; i < mal->num_tx_chans; ++i) {
+		if (i && !(i % 4))
+			printk("\n   ");
+		printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_TXCTPR(i)));
+	}
+	printk("\nRX|");
+	for (i = 0; i < mal->num_rx_chans; ++i) {
+		if (i && !(i % 4))
+			printk("\n   ");
+		printk("CTP%d = 0x%08x ", i, get_mal_dcrn(mal, MAL_RXCTPR(i)));
+	}
+	printk("\n   ");
+	for (i = 0; i < mal->num_rx_chans; ++i) {
+		u32 r = get_mal_dcrn(mal, MAL_RCBS(i));
+		if (i && !(i % 3))
+			printk("\n   ");
+		printk("RCBS%d = 0x%08x (%d) ", i, r, r * 16);
+	}
+	printk("\n");
+}
+
+static struct emac_instance *__emacs[4];
+static struct mal_instance *__mals[1];
+
+void emac_dbg_register(struct emac_instance *dev)
+{
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&emac_dbg_lock, flags);
+	for (i = 0; i < ARRAY_SIZE(__emacs); i++)
+		if (__emacs[i] == NULL) {
+			__emacs[i] = dev;
+			break;
+		}
+	spin_unlock_irqrestore(&emac_dbg_lock, flags);
+}
+
+void emac_dbg_unregister(struct emac_instance *dev)
+{
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&emac_dbg_lock, flags);
+	for (i = 0; i < ARRAY_SIZE(__emacs); i++)
+		if (__emacs[i] == dev) {
+			__emacs[i] = NULL;
+			break;
+		}
+	spin_unlock_irqrestore(&emac_dbg_lock, flags);
+}
+
+void mal_dbg_register(struct mal_instance *mal)
+{
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&emac_dbg_lock, flags);
+	for (i = 0; i < ARRAY_SIZE(__mals); i++)
+		if (__mals[i] == NULL) {
+			__mals[i] = mal;
+			break;
+		}
+	spin_unlock_irqrestore(&emac_dbg_lock, flags);
+}
+
+void mal_dbg_unregister(struct mal_instance *mal)
+{
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&emac_dbg_lock, flags);
+	for (i = 0; i < ARRAY_SIZE(__mals); i++)
+		if (__mals[i] == mal) {
+			__mals[i] = NULL;
+			break;
+		}
+	spin_unlock_irqrestore(&emac_dbg_lock, flags);
+}
+
+void emac_dbg_dump_all(void)
+{
+	unsigned int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&emac_dbg_lock, flags);
+
+	for (i = 0; i < ARRAY_SIZE(__mals); ++i)
+		if (__mals[i])
+			emac_mal_dump(__mals[i]);
+
+	for (i = 0; i < ARRAY_SIZE(__emacs); ++i)
+		if (__emacs[i])
+			emac_mac_dump(__emacs[i]);
+
+	spin_unlock_irqrestore(&emac_dbg_lock, flags);
+}
+
+#if defined(CONFIG_MAGIC_SYSRQ)
+static void emac_sysrq_handler(int key, struct tty_struct *tty)
+{
+	emac_dbg_dump_all();
+}
+
+static struct sysrq_key_op emac_sysrq_op = {
+	.handler = emac_sysrq_handler,
+	.help_msg = "emaC",
+	.action_msg = "Show EMAC(s) status",
+};
+
+int __init emac_init_debug(void)
+{
+	return register_sysrq_key('c', &emac_sysrq_op);
+}
+
+void __exit emac_fini_debug(void)
+{
+	unregister_sysrq_key('c', &emac_sysrq_op);
+}
+
+#else
+int __init emac_init_debug(void)
+{
+	return 0;
+}
+void __exit emac_fini_debug(void)
+{
+}
+#endif				/* CONFIG_MAGIC_SYSRQ */
diff --git a/drivers/net/ibm_newemac/debug.h b/drivers/net/ibm_newemac/debug.h
new file mode 100644
index 0000000..1dd2dcb
--- /dev/null
+++ b/drivers/net/ibm_newemac/debug.h
@@ -0,0 +1,78 @@
+/*
+ * drivers/net/ibm_newemac/debug.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, debug print routines.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __IBM_NEWEMAC_DEBUG_H
+#define __IBM_NEWEMAC_DEBUG_H
+
+#include <linux/init.h>
+
+#include "core.h"
+
+#if defined(CONFIG_IBM_NEW_EMAC_DEBUG)
+
+struct emac_instance;
+struct mal_instance;
+
+extern void emac_dbg_register(struct emac_instance *dev);
+extern void emac_dbg_unregister(struct emac_instance *dev);
+extern void mal_dbg_register(struct mal_instance *mal);
+extern void mal_dbg_unregister(struct mal_instance *mal);
+extern int emac_init_debug(void) __init;
+extern void emac_fini_debug(void) __exit;
+extern void emac_dbg_dump_all(void);
+
+# define DBG_LEVEL		1
+
+#else
+
+# define emac_dbg_register(x)	do { } while(0)
+# define emac_dbg_unregister(x)	do { } while(0)
+# define mal_dbg_register(x)	do { } while(0)
+# define mal_dbg_unregister(x)	do { } while(0)
+# define emac_init_debug()	do { } while(0)
+# define emac_fini_debug()	do { } while(0)
+# define emac_dbg_dump_all()	do { } while(0)
+
+# define DBG_LEVEL		0
+
+#endif
+
+#define EMAC_DBG(dev, name, fmt, arg...) \
+	printk(KERN_DEBUG #name "%s: " fmt, dev->ofdev->node->full_name, ## arg)
+
+#if DBG_LEVEL > 0
+#  define DBG(d,f,x...)		EMAC_DBG(d, emac, f, ##x)
+#  define MAL_DBG(d,f,x...)	EMAC_DBG(d, mal, f, ##x)
+#  define ZMII_DBG(d,f,x...)	EMAC_DBG(d, zmii, f, ##x)
+#  define RGMII_DBG(d,f,x...)	EMAC_DBG(d, rgmii, f, ##x)
+#  define NL			"\n"
+#else
+#  define DBG(f,x...)		((void)0)
+#  define MAL_DBG(d,f,x...)	((void)0)
+#  define ZMII_DBG(d,f,x...)	((void)0)
+#  define RGMII_DBG(d,f,x...)	((void)0)
+#endif
+#if DBG_LEVEL > 1
+#  define DBG2(d,f,x...) 	DBG(d,f, ##x)
+#  define MAL_DBG2(d,f,x...) 	MAL_DBG(d,f, ##x)
+#  define ZMII_DBG2(d,f,x...) 	ZMII_DBG(d,f, ##x)
+#  define RGMII_DBG2(d,f,x...) 	RGMII_DBG(d,f, ##x)
+#else
+#  define DBG2(f,x...) 		((void)0)
+#  define MAL_DBG2(d,f,x...) 	((void)0)
+#  define ZMII_DBG2(d,f,x...) 	((void)0)
+#  define RGMII_DBG2(d,f,x...) 	((void)0)
+#endif
+
+#endif /* __IBM_NEWEMAC_DEBUG_H */
diff --git a/drivers/net/ibm_newemac/emac.h b/drivers/net/ibm_newemac/emac.h
new file mode 100644
index 0000000..bef92ef
--- /dev/null
+++ b/drivers/net/ibm_newemac/emac.h
@@ -0,0 +1,268 @@
+/*
+ * drivers/net/ibm_newemac/emac.h
+ *
+ * Register definitions for PowerPC 4xx on-chip ethernet contoller
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ *      Matt Porter <mporter@kernel.crashing.org>
+ *      Armin Kuster <akuster@mvista.com>
+ * 	Copyright 2002-2004 MontaVista Software Inc.
+ *
+ * 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.
+ *
+ */
+#ifndef __IBM_NEWEMAC_H
+#define __IBM_NEWEMAC_H
+
+#include <linux/types.h>
+
+/* EMAC registers 		Write Access rules */
+struct emac_regs {
+	u32 mr0;		/* special 	*/
+	u32 mr1;		/* Reset 	*/
+	u32 tmr0;		/* special 	*/
+	u32 tmr1;		/* special 	*/
+	u32 rmr;		/* Reset 	*/
+	u32 isr;		/* Always 	*/
+	u32 iser;		/* Reset 	*/
+	u32 iahr;		/* Reset, R, T 	*/
+	u32 ialr;		/* Reset, R, T 	*/
+	u32 vtpid;		/* Reset, R, T 	*/
+	u32 vtci;		/* Reset, R, T 	*/
+	u32 ptr;		/* Reset,    T 	*/
+	u32 iaht1;		/* Reset, R	*/
+	u32 iaht2;		/* Reset, R	*/
+	u32 iaht3;		/* Reset, R	*/
+	u32 iaht4;		/* Reset, R	*/
+	u32 gaht1;		/* Reset, R	*/
+	u32 gaht2;		/* Reset, R	*/
+	u32 gaht3;		/* Reset, R	*/
+	u32 gaht4;		/* Reset, R	*/
+	u32 lsah;
+	u32 lsal;
+	u32 ipgvr;		/* Reset,    T 	*/
+	u32 stacr;		/* special 	*/
+	u32 trtr;		/* special 	*/
+	u32 rwmr;		/* Reset 	*/
+	u32 octx;
+	u32 ocrx;
+	u32 ipcr;
+};
+
+/*
+ * PHY mode settings (EMAC <-> ZMII/RGMII bridge <-> PHY)
+ */
+#define PHY_MODE_NA	0
+#define PHY_MODE_MII	1
+#define PHY_MODE_RMII	2
+#define PHY_MODE_SMII	3
+#define PHY_MODE_RGMII	4
+#define PHY_MODE_TBI	5
+#define PHY_MODE_GMII	6
+#define PHY_MODE_RTBI	7
+#define PHY_MODE_SGMII	8
+
+
+#define EMAC_ETHTOOL_REGS_VER		0
+#define EMAC_ETHTOOL_REGS_SIZE		(sizeof(struct emac_regs) - sizeof(u32))
+#define EMAC4_ETHTOOL_REGS_VER      	1
+#define EMAC4_ETHTOOL_REGS_SIZE		sizeof(struct emac_regs)
+
+/* EMACx_MR0 */
+#define EMAC_MR0_RXI			0x80000000
+#define EMAC_MR0_TXI			0x40000000
+#define EMAC_MR0_SRST			0x20000000
+#define EMAC_MR0_TXE			0x10000000
+#define EMAC_MR0_RXE			0x08000000
+#define EMAC_MR0_WKE			0x04000000
+
+/* EMACx_MR1 */
+#define EMAC_MR1_FDE			0x80000000
+#define EMAC_MR1_ILE			0x40000000
+#define EMAC_MR1_VLE			0x20000000
+#define EMAC_MR1_EIFC			0x10000000
+#define EMAC_MR1_APP			0x08000000
+#define EMAC_MR1_IST			0x01000000
+
+#define EMAC_MR1_MF_MASK		0x00c00000
+#define EMAC_MR1_MF_10			0x00000000
+#define EMAC_MR1_MF_100			0x00400000
+#define EMAC_MR1_MF_1000		0x00800000
+#define EMAC_MR1_MF_1000GPCS		0x00c00000
+#define EMAC_MR1_MF_IPPA(id)		(((id) & 0x1f) << 6)
+
+#define EMAC_MR1_RFS_4K			0x00300000
+#define EMAC_MR1_RFS_16K		0x00000000
+#define EMAC_MR1_TFS_2K			0x00080000
+#define EMAC_MR1_TR0_MULT		0x00008000
+#define EMAC_MR1_JPSM			0x00000000
+#define EMAC_MR1_MWSW_001		0x00000000
+#define EMAC_MR1_BASE(opb)		(EMAC_MR1_TFS_2K | EMAC_MR1_TR0_MULT)
+
+
+#define EMAC4_MR1_RFS_2K		0x00100000
+#define EMAC4_MR1_RFS_4K		0x00180000
+#define EMAC4_MR1_RFS_16K		0x00280000
+#define EMAC4_MR1_TFS_2K       		0x00020000
+#define EMAC4_MR1_TFS_4K		0x00030000
+#define EMAC4_MR1_TR			0x00008000
+#define EMAC4_MR1_MWSW_001		0x00001000
+#define EMAC4_MR1_JPSM			0x00000800
+#define EMAC4_MR1_OBCI_MASK		0x00000038
+#define EMAC4_MR1_OBCI_50		0x00000000
+#define EMAC4_MR1_OBCI_66		0x00000008
+#define EMAC4_MR1_OBCI_83		0x00000010
+#define EMAC4_MR1_OBCI_100		0x00000018
+#define EMAC4_MR1_OBCI_100P		0x00000020
+#define EMAC4_MR1_OBCI(freq)		((freq) <= 50  ? EMAC4_MR1_OBCI_50 : \
+					 (freq) <= 66  ? EMAC4_MR1_OBCI_66 : \
+					 (freq) <= 83  ? EMAC4_MR1_OBCI_83 : \
+					 (freq) <= 100 ? EMAC4_MR1_OBCI_100 : \
+						EMAC4_MR1_OBCI_100P)
+
+/* EMACx_TMR0 */
+#define EMAC_TMR0_GNP			0x80000000
+#define EMAC_TMR0_DEFAULT		0x00000000
+#define EMAC4_TMR0_TFAE_2_32		0x00000001
+#define EMAC4_TMR0_TFAE_4_64		0x00000002
+#define EMAC4_TMR0_TFAE_8_128		0x00000003
+#define EMAC4_TMR0_TFAE_16_256		0x00000004
+#define EMAC4_TMR0_TFAE_32_512		0x00000005
+#define EMAC4_TMR0_TFAE_64_1024		0x00000006
+#define EMAC4_TMR0_TFAE_128_2048	0x00000007
+#define EMAC4_TMR0_DEFAULT		EMAC4_TMR0_TFAE_2_32
+#define EMAC_TMR0_XMIT			(EMAC_TMR0_GNP | EMAC_TMR0_DEFAULT)
+#define EMAC4_TMR0_XMIT			(EMAC_TMR0_GNP | EMAC4_TMR0_DEFAULT)
+
+/* EMACx_TMR1 */
+
+#define EMAC_TMR1(l,h)			(((l) << 27) | (((h) & 0xff) << 16))
+#define EMAC4_TMR1(l,h)			(((l) << 27) | (((h) & 0x3ff) << 14))
+
+/* EMACx_RMR */
+#define EMAC_RMR_SP			0x80000000
+#define EMAC_RMR_SFCS			0x40000000
+#define EMAC_RMR_RRP			0x20000000
+#define EMAC_RMR_RFP			0x10000000
+#define EMAC_RMR_ROP			0x08000000
+#define EMAC_RMR_RPIR			0x04000000
+#define EMAC_RMR_PPP			0x02000000
+#define EMAC_RMR_PME			0x01000000
+#define EMAC_RMR_PMME			0x00800000
+#define EMAC_RMR_IAE			0x00400000
+#define EMAC_RMR_MIAE			0x00200000
+#define EMAC_RMR_BAE			0x00100000
+#define EMAC_RMR_MAE			0x00080000
+#define EMAC_RMR_BASE			0x00000000
+#define EMAC4_RMR_RFAF_2_32		0x00000001
+#define EMAC4_RMR_RFAF_4_64		0x00000002
+#define EMAC4_RMR_RFAF_8_128		0x00000003
+#define EMAC4_RMR_RFAF_16_256		0x00000004
+#define EMAC4_RMR_RFAF_32_512		0x00000005
+#define EMAC4_RMR_RFAF_64_1024		0x00000006
+#define EMAC4_RMR_RFAF_128_2048		0x00000007
+#define EMAC4_RMR_BASE			EMAC4_RMR_RFAF_128_2048
+
+/* EMACx_ISR & EMACx_ISER */
+#define EMAC4_ISR_TXPE			0x20000000
+#define EMAC4_ISR_RXPE			0x10000000
+#define EMAC4_ISR_TXUE			0x08000000
+#define EMAC4_ISR_RXOE			0x04000000
+#define EMAC_ISR_OVR			0x02000000
+#define EMAC_ISR_PP			0x01000000
+#define EMAC_ISR_BP			0x00800000
+#define EMAC_ISR_RP			0x00400000
+#define EMAC_ISR_SE			0x00200000
+#define EMAC_ISR_ALE			0x00100000
+#define EMAC_ISR_BFCS			0x00080000
+#define EMAC_ISR_PTLE			0x00040000
+#define EMAC_ISR_ORE			0x00020000
+#define EMAC_ISR_IRE			0x00010000
+#define EMAC_ISR_SQE			0x00000080
+#define EMAC_ISR_TE			0x00000040
+#define EMAC_ISR_MOS			0x00000002
+#define EMAC_ISR_MOF			0x00000001
+
+/* EMACx_STACR */
+#define EMAC_STACR_PHYD_MASK		0xffff
+#define EMAC_STACR_PHYD_SHIFT		16
+#define EMAC_STACR_OC			0x00008000
+#define EMAC_STACR_PHYE			0x00004000
+#define EMAC_STACR_STAC_MASK		0x00003000
+#define EMAC_STACR_STAC_READ		0x00001000
+#define EMAC_STACR_STAC_WRITE		0x00002000
+#define EMAC_STACR_OPBC_MASK		0x00000C00
+#define EMAC_STACR_OPBC_50		0x00000000
+#define EMAC_STACR_OPBC_66		0x00000400
+#define EMAC_STACR_OPBC_83		0x00000800
+#define EMAC_STACR_OPBC_100		0x00000C00
+#define EMAC_STACR_OPBC(freq)		((freq) <= 50 ? EMAC_STACR_OPBC_50 : \
+					 (freq) <= 66 ? EMAC_STACR_OPBC_66 : \
+					 (freq) <= 83 ? EMAC_STACR_OPBC_83 : EMAC_STACR_OPBC_100)
+#define EMAC_STACR_BASE(opb)		EMAC_STACR_OPBC(opb)
+#define EMAC4_STACR_BASE(opb)		0x00000000
+#define EMAC_STACR_PCDA_MASK		0x1f
+#define EMAC_STACR_PCDA_SHIFT		5
+#define EMAC_STACR_PRA_MASK		0x1f
+#define EMACX_STACR_STAC_MASK		0x00003800
+#define EMACX_STACR_STAC_READ		0x00001000
+#define EMACX_STACR_STAC_WRITE		0x00000800
+#define EMACX_STACR_STAC_IND_ADDR	0x00002000
+#define EMACX_STACR_STAC_IND_READ	0x00003800
+#define EMACX_STACR_STAC_IND_READINC	0x00003000
+#define EMACX_STACR_STAC_IND_WRITE	0x00002800
+
+
+/* EMACx_TRTR */
+#define EMAC_TRTR_SHIFT_EMAC4		27
+#define EMAC_TRTR_SHIFT			24
+
+/* EMAC specific TX descriptor control fields (write access) */
+#define EMAC_TX_CTRL_GFCS		0x0200
+#define EMAC_TX_CTRL_GP			0x0100
+#define EMAC_TX_CTRL_ISA		0x0080
+#define EMAC_TX_CTRL_RSA		0x0040
+#define EMAC_TX_CTRL_IVT		0x0020
+#define EMAC_TX_CTRL_RVT		0x0010
+#define EMAC_TX_CTRL_TAH_CSUM		0x000e
+
+/* EMAC specific TX descriptor status fields (read access) */
+#define EMAC_TX_ST_BFCS			0x0200
+#define EMAC_TX_ST_LCS			0x0080
+#define EMAC_TX_ST_ED			0x0040
+#define EMAC_TX_ST_EC			0x0020
+#define EMAC_TX_ST_LC			0x0010
+#define EMAC_TX_ST_MC			0x0008
+#define EMAC_TX_ST_SC			0x0004
+#define EMAC_TX_ST_UR			0x0002
+#define EMAC_TX_ST_SQE			0x0001
+#define EMAC_IS_BAD_TX			(EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \
+					 EMAC_TX_ST_EC | EMAC_TX_ST_LC | \
+					 EMAC_TX_ST_MC | EMAC_TX_ST_UR)
+#define EMAC_IS_BAD_TX_TAH		(EMAC_TX_ST_LCS | EMAC_TX_ST_ED | \
+					 EMAC_TX_ST_EC | EMAC_TX_ST_LC)
+
+/* EMAC specific RX descriptor status fields (read access) */
+#define EMAC_RX_ST_OE			0x0200
+#define EMAC_RX_ST_PP			0x0100
+#define EMAC_RX_ST_BP			0x0080
+#define EMAC_RX_ST_RP			0x0040
+#define EMAC_RX_ST_SE			0x0020
+#define EMAC_RX_ST_AE			0x0010
+#define EMAC_RX_ST_BFCS			0x0008
+#define EMAC_RX_ST_PTL			0x0004
+#define EMAC_RX_ST_ORE			0x0002
+#define EMAC_RX_ST_IRE			0x0001
+#define EMAC_RX_TAH_BAD_CSUM		0x0003
+#define EMAC_BAD_RX_MASK		(EMAC_RX_ST_OE | EMAC_RX_ST_BP | \
+					 EMAC_RX_ST_RP | EMAC_RX_ST_SE | \
+					 EMAC_RX_ST_AE | EMAC_RX_ST_BFCS | \
+					 EMAC_RX_ST_PTL | EMAC_RX_ST_ORE | \
+					 EMAC_RX_ST_IRE )
+#endif /* __IBM_NEWEMAC_H */
diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c
new file mode 100644
index 0000000..5885411
--- /dev/null
+++ b/drivers/net/ibm_newemac/mal.c
@@ -0,0 +1,711 @@
+/*
+ * drivers/net/ibm_newemac/mal.c
+ *
+ * Memory Access Layer (MAL) support
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ *      Benjamin Herrenschmidt <benh@kernel.crashing.org>,
+ *      David Gibson <hermes@gibson.dropbear.id.au>,
+ *
+ *      Armin Kuster <akuster@mvista.com>
+ *      Copyright 2002 MontaVista Softare Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/delay.h>
+
+#include "core.h"
+
+static int mal_count;
+
+int __devinit mal_register_commac(struct mal_instance	*mal,
+				  struct mal_commac	*commac)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mal->lock, flags);
+
+	MAL_DBG(mal, "reg(%08x, %08x)" NL,
+		commac->tx_chan_mask, commac->rx_chan_mask);
+
+	/* Don't let multiple commacs claim the same channel(s) */
+	if ((mal->tx_chan_mask & commac->tx_chan_mask) ||
+	    (mal->rx_chan_mask & commac->rx_chan_mask)) {
+		spin_unlock_irqrestore(&mal->lock, flags);
+		printk(KERN_WARNING "mal%d: COMMAC channels conflict!\n",
+		       mal->index);
+		return -EBUSY;
+	}
+
+	mal->tx_chan_mask |= commac->tx_chan_mask;
+	mal->rx_chan_mask |= commac->rx_chan_mask;
+	list_add(&commac->list, &mal->list);
+
+	spin_unlock_irqrestore(&mal->lock, flags);
+
+	return 0;
+}
+
+void __devexit mal_unregister_commac(struct mal_instance	*mal,
+				     struct mal_commac		*commac)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mal->lock, flags);
+
+	MAL_DBG(mal, "unreg(%08x, %08x)" NL,
+		commac->tx_chan_mask, commac->rx_chan_mask);
+
+	mal->tx_chan_mask &= ~commac->tx_chan_mask;
+	mal->rx_chan_mask &= ~commac->rx_chan_mask;
+	list_del_init(&commac->list);
+
+	spin_unlock_irqrestore(&mal->lock, flags);
+}
+
+int mal_set_rcbs(struct mal_instance *mal, int channel, unsigned long size)
+{
+	BUG_ON(channel < 0 || channel >= mal->num_rx_chans ||
+	       size > MAL_MAX_RX_SIZE);
+
+	MAL_DBG(mal, "set_rbcs(%d, %lu)" NL, channel, size);
+
+	if (size & 0xf) {
+		printk(KERN_WARNING
+		       "mal%d: incorrect RX size %lu for the channel %d\n",
+		       mal->index, size, channel);
+		return -EINVAL;
+	}
+
+	set_mal_dcrn(mal, MAL_RCBS(channel), size >> 4);
+	return 0;
+}
+
+int mal_tx_bd_offset(struct mal_instance *mal, int channel)
+{
+	BUG_ON(channel < 0 || channel >= mal->num_tx_chans);
+
+	return channel * NUM_TX_BUFF;
+}
+
+int mal_rx_bd_offset(struct mal_instance *mal, int channel)
+{
+	BUG_ON(channel < 0 || channel >= mal->num_rx_chans);
+	return mal->num_tx_chans * NUM_TX_BUFF + channel * NUM_RX_BUFF;
+}
+
+void mal_enable_tx_channel(struct mal_instance *mal, int channel)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mal->lock, flags);
+
+	MAL_DBG(mal, "enable_tx(%d)" NL, channel);
+
+	set_mal_dcrn(mal, MAL_TXCASR,
+		     get_mal_dcrn(mal, MAL_TXCASR) | MAL_CHAN_MASK(channel));
+
+	spin_unlock_irqrestore(&mal->lock, flags);
+}
+
+void mal_disable_tx_channel(struct mal_instance *mal, int channel)
+{
+	set_mal_dcrn(mal, MAL_TXCARR, MAL_CHAN_MASK(channel));
+
+	MAL_DBG(mal, "disable_tx(%d)" NL, channel);
+}
+
+void mal_enable_rx_channel(struct mal_instance *mal, int channel)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mal->lock, flags);
+
+	MAL_DBG(mal, "enable_rx(%d)" NL, channel);
+
+	set_mal_dcrn(mal, MAL_RXCASR,
+		     get_mal_dcrn(mal, MAL_RXCASR) | MAL_CHAN_MASK(channel));
+
+	spin_unlock_irqrestore(&mal->lock, flags);
+}
+
+void mal_disable_rx_channel(struct mal_instance *mal, int channel)
+{
+	set_mal_dcrn(mal, MAL_RXCARR, MAL_CHAN_MASK(channel));
+
+	MAL_DBG(mal, "disable_rx(%d)" NL, channel);
+}
+
+void mal_poll_add(struct mal_instance *mal, struct mal_commac *commac)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mal->lock, flags);
+
+	MAL_DBG(mal, "poll_add(%p)" NL, commac);
+
+	/* starts disabled */
+	set_bit(MAL_COMMAC_POLL_DISABLED, &commac->flags);
+
+	list_add_tail(&commac->poll_list, &mal->poll_list);
+
+	spin_unlock_irqrestore(&mal->lock, flags);
+}
+
+void mal_poll_del(struct mal_instance *mal, struct mal_commac *commac)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&mal->lock, flags);
+
+	MAL_DBG(mal, "poll_del(%p)" NL, commac);
+
+	list_del(&commac->poll_list);
+
+	spin_unlock_irqrestore(&mal->lock, flags);
+}
+
+/* synchronized by mal_poll() */
+static inline void mal_enable_eob_irq(struct mal_instance *mal)
+{
+	MAL_DBG2(mal, "enable_irq" NL);
+
+	// XXX might want to cache MAL_CFG as the DCR read can be slooooow
+	set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) | MAL_CFG_EOPIE);
+}
+
+/* synchronized by __LINK_STATE_RX_SCHED bit in ndev->state */
+static inline void mal_disable_eob_irq(struct mal_instance *mal)
+{
+	// XXX might want to cache MAL_CFG as the DCR read can be slooooow
+	set_mal_dcrn(mal, MAL_CFG, get_mal_dcrn(mal, MAL_CFG) & ~MAL_CFG_EOPIE);
+
+	MAL_DBG2(mal, "disable_irq" NL);
+}
+
+static irqreturn_t mal_serr(int irq, void *dev_instance)
+{
+	struct mal_instance *mal = dev_instance;
+
+	u32 esr = get_mal_dcrn(mal, MAL_ESR);
+
+	/* Clear the error status register */
+	set_mal_dcrn(mal, MAL_ESR, esr);
+
+	MAL_DBG(mal, "SERR %08x" NL, esr);
+
+	if (esr & MAL_ESR_EVB) {
+		if (esr & MAL_ESR_DE) {
+			/* We ignore Descriptor error,
+			 * TXDE or RXDE interrupt will be generated anyway.
+			 */
+			return IRQ_HANDLED;
+		}
+
+		if (esr & MAL_ESR_PEIN) {
+			/* PLB error, it's probably buggy hardware or
+			 * incorrect physical address in BD (i.e. bug)
+			 */
+			if (net_ratelimit())
+				printk(KERN_ERR
+				       "mal%d: system error, "
+				       "PLB (ESR = 0x%08x)\n",
+				       mal->index, esr);
+			return IRQ_HANDLED;
+		}
+
+		/* OPB error, it's probably buggy hardware or incorrect
+		 * EBC setup
+		 */
+		if (net_ratelimit())
+			printk(KERN_ERR
+			       "mal%d: system error, OPB (ESR = 0x%08x)\n",
+			       mal->index, esr);
+	}
+	return IRQ_HANDLED;
+}
+
+static inline void mal_schedule_poll(struct mal_instance *mal)
+{
+	if (likely(napi_schedule_prep(&mal->napi))) {
+		MAL_DBG2(mal, "schedule_poll" NL);
+		mal_disable_eob_irq(mal);
+		__napi_schedule(&mal->napi);
+	} else
+		MAL_DBG2(mal, "already in poll" NL);
+}
+
+static irqreturn_t mal_txeob(int irq, void *dev_instance)
+{
+	struct mal_instance *mal = dev_instance;
+
+	u32 r = get_mal_dcrn(mal, MAL_TXEOBISR);
+
+	MAL_DBG2(mal, "txeob %08x" NL, r);
+
+	mal_schedule_poll(mal);
+	set_mal_dcrn(mal, MAL_TXEOBISR, r);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mal_rxeob(int irq, void *dev_instance)
+{
+	struct mal_instance *mal = dev_instance;
+
+	u32 r = get_mal_dcrn(mal, MAL_RXEOBISR);
+
+	MAL_DBG2(mal, "rxeob %08x" NL, r);
+
+	mal_schedule_poll(mal);
+	set_mal_dcrn(mal, MAL_RXEOBISR, r);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mal_txde(int irq, void *dev_instance)
+{
+	struct mal_instance *mal = dev_instance;
+
+	u32 deir = get_mal_dcrn(mal, MAL_TXDEIR);
+	set_mal_dcrn(mal, MAL_TXDEIR, deir);
+
+	MAL_DBG(mal, "txde %08x" NL, deir);
+
+	if (net_ratelimit())
+		printk(KERN_ERR
+		       "mal%d: TX descriptor error (TXDEIR = 0x%08x)\n",
+		       mal->index, deir);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mal_rxde(int irq, void *dev_instance)
+{
+	struct mal_instance *mal = dev_instance;
+	struct list_head *l;
+
+	u32 deir = get_mal_dcrn(mal, MAL_RXDEIR);
+
+	MAL_DBG(mal, "rxde %08x" NL, deir);
+
+	list_for_each(l, &mal->list) {
+		struct mal_commac *mc = list_entry(l, struct mal_commac, list);
+		if (deir & mc->rx_chan_mask) {
+			set_bit(MAL_COMMAC_RX_STOPPED, &mc->flags);
+			mc->ops->rxde(mc->dev);
+		}
+	}
+
+	mal_schedule_poll(mal);
+	set_mal_dcrn(mal, MAL_RXDEIR, deir);
+
+	return IRQ_HANDLED;
+}
+
+void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac)
+{
+	/* Spinlock-type semantics: only one caller disable poll at a time */
+	while (test_and_set_bit(MAL_COMMAC_POLL_DISABLED, &commac->flags))
+		msleep(1);
+
+	/* Synchronize with the MAL NAPI poller. */
+	napi_disable(&mal->napi);
+}
+
+void mal_poll_enable(struct mal_instance *mal, struct mal_commac *commac)
+{
+	smp_wmb();
+	clear_bit(MAL_COMMAC_POLL_DISABLED, &commac->flags);
+
+	// XXX might want to kick a poll now...
+}
+
+static int mal_poll(struct napi_struct *napi, int budget)
+{
+	struct mal_instance *mal = container_of(napi, struct mal_instance, napi);
+	struct list_head *l;
+	int received = 0;
+	unsigned long flags;
+
+	MAL_DBG2(mal, "poll(%d) %d ->" NL, *budget,
+		 rx_work_limit);
+ again:
+	/* Process TX skbs */
+	list_for_each(l, &mal->poll_list) {
+		struct mal_commac *mc =
+			list_entry(l, struct mal_commac, poll_list);
+		mc->ops->poll_tx(mc->dev);
+	}
+
+	/* Process RX skbs.
+	 *
+	 * We _might_ need something more smart here to enforce polling
+	 * fairness.
+	 */
+	list_for_each(l, &mal->poll_list) {
+		struct mal_commac *mc =
+			list_entry(l, struct mal_commac, poll_list);
+		int n;
+		if (unlikely(test_bit(MAL_COMMAC_POLL_DISABLED, &mc->flags)))
+			continue;
+		n = mc->ops->poll_rx(mc->dev, budget);
+		if (n) {
+			received += n;
+			budget -= n;
+			if (budget <= 0)
+				goto more_work; // XXX What if this is the last one ?
+		}
+	}
+
+	/* We need to disable IRQs to protect from RXDE IRQ here */
+	spin_lock_irqsave(&mal->lock, flags);
+	__napi_complete(napi);
+	mal_enable_eob_irq(mal);
+	spin_unlock_irqrestore(&mal->lock, flags);
+
+	/* Check for "rotting" packet(s) */
+	list_for_each(l, &mal->poll_list) {
+		struct mal_commac *mc =
+			list_entry(l, struct mal_commac, poll_list);
+		if (unlikely(test_bit(MAL_COMMAC_POLL_DISABLED, &mc->flags)))
+			continue;
+		if (unlikely(mc->ops->peek_rx(mc->dev) ||
+			     test_bit(MAL_COMMAC_RX_STOPPED, &mc->flags))) {
+			MAL_DBG2(mal, "rotting packet" NL);
+			if (napi_reschedule(napi))
+				mal_disable_eob_irq(mal);
+			else
+				MAL_DBG2(mal, "already in poll list" NL);
+
+			if (budget > 0)
+				goto again;
+			else
+				goto more_work;
+		}
+		mc->ops->poll_tx(mc->dev);
+	}
+
+ more_work:
+	MAL_DBG2(mal, "poll() %d <- %d" NL, budget, received);
+	return received;
+}
+
+static void mal_reset(struct mal_instance *mal)
+{
+	int n = 10;
+
+	MAL_DBG(mal, "reset" NL);
+
+	set_mal_dcrn(mal, MAL_CFG, MAL_CFG_SR);
+
+	/* Wait for reset to complete (1 system clock) */
+	while ((get_mal_dcrn(mal, MAL_CFG) & MAL_CFG_SR) && n)
+		--n;
+
+	if (unlikely(!n))
+		printk(KERN_ERR "mal%d: reset timeout\n", mal->index);
+}
+
+int mal_get_regs_len(struct mal_instance *mal)
+{
+	return sizeof(struct emac_ethtool_regs_subhdr) +
+	    sizeof(struct mal_regs);
+}
+
+void *mal_dump_regs(struct mal_instance *mal, void *buf)
+{
+	struct emac_ethtool_regs_subhdr *hdr = buf;
+	struct mal_regs *regs = (struct mal_regs *)(hdr + 1);
+	int i;
+
+	hdr->version = mal->version;
+	hdr->index = mal->index;
+
+	regs->tx_count = mal->num_tx_chans;
+	regs->rx_count = mal->num_rx_chans;
+
+	regs->cfg = get_mal_dcrn(mal, MAL_CFG);
+	regs->esr = get_mal_dcrn(mal, MAL_ESR);
+	regs->ier = get_mal_dcrn(mal, MAL_IER);
+	regs->tx_casr = get_mal_dcrn(mal, MAL_TXCASR);
+	regs->tx_carr = get_mal_dcrn(mal, MAL_TXCARR);
+	regs->tx_eobisr = get_mal_dcrn(mal, MAL_TXEOBISR);
+	regs->tx_deir = get_mal_dcrn(mal, MAL_TXDEIR);
+	regs->rx_casr = get_mal_dcrn(mal, MAL_RXCASR);
+	regs->rx_carr = get_mal_dcrn(mal, MAL_RXCARR);
+	regs->rx_eobisr = get_mal_dcrn(mal, MAL_RXEOBISR);
+	regs->rx_deir = get_mal_dcrn(mal, MAL_RXDEIR);
+
+	for (i = 0; i < regs->tx_count; ++i)
+		regs->tx_ctpr[i] = get_mal_dcrn(mal, MAL_TXCTPR(i));
+
+	for (i = 0; i < regs->rx_count; ++i) {
+		regs->rx_ctpr[i] = get_mal_dcrn(mal, MAL_RXCTPR(i));
+		regs->rcbs[i] = get_mal_dcrn(mal, MAL_RCBS(i));
+	}
+	return regs + 1;
+}
+
+static int __devinit mal_probe(struct of_device *ofdev,
+			       const struct of_device_id *match)
+{
+	struct mal_instance *mal;
+	int err = 0, i, bd_size;
+	int index = mal_count++;
+	const u32 *prop;
+	u32 cfg;
+
+	mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL);
+	if (!mal) {
+		printk(KERN_ERR
+		       "mal%d: out of memory allocating MAL structure!\n",
+		       index);
+		return -ENOMEM;
+	}
+	mal->index = index;
+	mal->ofdev = ofdev;
+	mal->version = of_device_is_compatible(ofdev->node, "ibm,mcmal2") ? 2 : 1;
+
+	MAL_DBG(mal, "probe" NL);
+
+	prop = of_get_property(ofdev->node, "num-tx-chans", NULL);
+	if (prop == NULL) {
+		printk(KERN_ERR
+		       "mal%d: can't find MAL num-tx-chans property!\n",
+		       index);
+		err = -ENODEV;
+		goto fail;
+	}
+	mal->num_tx_chans = prop[0];
+
+	prop = of_get_property(ofdev->node, "num-rx-chans", NULL);
+	if (prop == NULL) {
+		printk(KERN_ERR
+		       "mal%d: can't find MAL num-rx-chans property!\n",
+		       index);
+		err = -ENODEV;
+		goto fail;
+	}
+	mal->num_rx_chans = prop[0];
+
+	mal->dcr_base = dcr_resource_start(ofdev->node, 0);
+	if (mal->dcr_base == 0) {
+		printk(KERN_ERR
+		       "mal%d: can't find DCR resource!\n", index);
+		err = -ENODEV;
+		goto fail;
+	}
+        mal->dcr_host = dcr_map(ofdev->node, mal->dcr_base, 0x100);
+	if (!DCR_MAP_OK(mal->dcr_host)) {
+		printk(KERN_ERR
+		       "mal%d: failed to map DCRs !\n", index);
+		err = -ENODEV;
+		goto fail;
+	}
+
+	mal->txeob_irq = irq_of_parse_and_map(ofdev->node, 0);
+	mal->rxeob_irq = irq_of_parse_and_map(ofdev->node, 1);
+	mal->serr_irq = irq_of_parse_and_map(ofdev->node, 2);
+	mal->txde_irq = irq_of_parse_and_map(ofdev->node, 3);
+	mal->rxde_irq = irq_of_parse_and_map(ofdev->node, 4);
+	if (mal->txeob_irq == NO_IRQ || mal->rxeob_irq == NO_IRQ ||
+	    mal->serr_irq == NO_IRQ || mal->txde_irq == NO_IRQ ||
+	    mal->rxde_irq == NO_IRQ) {
+		printk(KERN_ERR
+		       "mal%d: failed to map interrupts !\n", index);
+		err = -ENODEV;
+		goto fail_unmap;
+	}
+
+	INIT_LIST_HEAD(&mal->poll_list);
+	mal->napi.weight = CONFIG_IBM_NEW_EMAC_POLL_WEIGHT;
+	mal->napi.poll = mal_poll;
+	INIT_LIST_HEAD(&mal->list);
+	spin_lock_init(&mal->lock);
+
+	/* Load power-on reset defaults */
+	mal_reset(mal);
+
+	/* Set the MAL configuration register */
+	cfg = (mal->version == 2) ? MAL2_CFG_DEFAULT : MAL1_CFG_DEFAULT;
+	cfg |= MAL_CFG_PLBB | MAL_CFG_OPBBL | MAL_CFG_LEA;
+
+	/* Current Axon is not happy with priority being non-0, it can
+	 * deadlock, fix it up here
+	 */
+	if (of_device_is_compatible(ofdev->node, "ibm,mcmal-axon"))
+		cfg &= ~(MAL2_CFG_RPP_10 | MAL2_CFG_WPP_10);
+
+	/* Apply configuration */
+	set_mal_dcrn(mal, MAL_CFG, cfg);
+
+	/* Allocate space for BD rings */
+	BUG_ON(mal->num_tx_chans <= 0 || mal->num_tx_chans > 32);
+	BUG_ON(mal->num_rx_chans <= 0 || mal->num_rx_chans > 32);
+
+	bd_size = sizeof(struct mal_descriptor) *
+		(NUM_TX_BUFF * mal->num_tx_chans +
+		 NUM_RX_BUFF * mal->num_rx_chans);
+	mal->bd_virt =
+		dma_alloc_coherent(&ofdev->dev, bd_size, &mal->bd_dma,
+				   GFP_KERNEL);
+	if (mal->bd_virt == NULL) {
+		printk(KERN_ERR
+		       "mal%d: out of memory allocating RX/TX descriptors!\n",
+		       index);
+		err = -ENOMEM;
+		goto fail_unmap;
+	}
+	memset(mal->bd_virt, 0, bd_size);
+
+	for (i = 0; i < mal->num_tx_chans; ++i)
+		set_mal_dcrn(mal, MAL_TXCTPR(i), mal->bd_dma +
+			     sizeof(struct mal_descriptor) *
+			     mal_tx_bd_offset(mal, i));
+
+	for (i = 0; i < mal->num_rx_chans; ++i)
+		set_mal_dcrn(mal, MAL_RXCTPR(i), mal->bd_dma +
+			     sizeof(struct mal_descriptor) *
+			     mal_rx_bd_offset(mal, i));
+
+	err = request_irq(mal->serr_irq, mal_serr, 0, "MAL SERR", mal);
+	if (err)
+		goto fail2;
+	err = request_irq(mal->txde_irq, mal_txde, 0, "MAL TX DE", mal);
+	if (err)
+		goto fail3;
+	err = request_irq(mal->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal);
+	if (err)
+		goto fail4;
+	err = request_irq(mal->rxde_irq, mal_rxde, 0, "MAL RX DE", mal);
+	if (err)
+		goto fail5;
+	err = request_irq(mal->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal);
+	if (err)
+		goto fail6;
+
+	/* Enable all MAL SERR interrupt sources */
+	if (mal->version == 2)
+		set_mal_dcrn(mal, MAL_IER, MAL2_IER_EVENTS);
+	else
+		set_mal_dcrn(mal, MAL_IER, MAL1_IER_EVENTS);
+
+	/* Enable EOB interrupt */
+	mal_enable_eob_irq(mal);
+
+	printk(KERN_INFO
+	       "MAL v%d %s, %d TX channels, %d RX channels\n",
+	       mal->version, ofdev->node->full_name,
+	       mal->num_tx_chans, mal->num_rx_chans);
+
+	/* Advertise this instance to the rest of the world */
+	wmb();
+	dev_set_drvdata(&ofdev->dev, mal);
+
+	mal_dbg_register(mal);
+
+	return 0;
+
+ fail6:
+	free_irq(mal->rxde_irq, mal);
+ fail5:
+	free_irq(mal->txeob_irq, mal);
+ fail4:
+	free_irq(mal->txde_irq, mal);
+ fail3:
+	free_irq(mal->serr_irq, mal);
+ fail2:
+	dma_free_coherent(&ofdev->dev, bd_size, mal->bd_virt, mal->bd_dma);
+ fail_unmap:
+	dcr_unmap(mal->dcr_host, mal->dcr_base, 0x100);
+ fail:
+	kfree(mal);
+
+	return err;
+}
+
+static int __devexit mal_remove(struct of_device *ofdev)
+{
+	struct mal_instance *mal = dev_get_drvdata(&ofdev->dev);
+
+	MAL_DBG(mal, "remove" NL);
+
+	/* Synchronize with scheduled polling */
+	napi_disable(&mal->napi);
+
+	if (!list_empty(&mal->list)) {
+		/* This is *very* bad */
+		printk(KERN_EMERG
+		       "mal%d: commac list is not empty on remove!\n",
+		       mal->index);
+		WARN_ON(1);
+	}
+
+	dev_set_drvdata(&ofdev->dev, NULL);
+
+	free_irq(mal->serr_irq, mal);
+	free_irq(mal->txde_irq, mal);
+	free_irq(mal->txeob_irq, mal);
+	free_irq(mal->rxde_irq, mal);
+	free_irq(mal->rxeob_irq, mal);
+
+	mal_reset(mal);
+
+	mal_dbg_unregister(mal);
+
+	dma_free_coherent(&ofdev->dev,
+			  sizeof(struct mal_descriptor) *
+			  (NUM_TX_BUFF * mal->num_tx_chans +
+			   NUM_RX_BUFF * mal->num_rx_chans), mal->bd_virt,
+			  mal->bd_dma);
+	kfree(mal);
+
+	return 0;
+}
+
+static struct of_device_id mal_platform_match[] =
+{
+	{
+		.compatible	= "ibm,mcmal",
+	},
+	{
+		.compatible	= "ibm,mcmal2",
+	},
+	/* Backward compat */
+	{
+		.type		= "mcmal-dma",
+		.compatible	= "ibm,mcmal",
+	},
+	{
+		.type		= "mcmal-dma",
+		.compatible	= "ibm,mcmal2",
+	},
+	{},
+};
+
+static struct of_platform_driver mal_of_driver = {
+	.name = "mcmal",
+	.match_table = mal_platform_match,
+
+	.probe = mal_probe,
+	.remove = mal_remove,
+};
+
+int __init mal_init(void)
+{
+	return of_register_platform_driver(&mal_of_driver);
+}
+
+void mal_exit(void)
+{
+	of_unregister_platform_driver(&mal_of_driver);
+}
diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h
new file mode 100644
index 0000000..cb1a16d
--- /dev/null
+++ b/drivers/net/ibm_newemac/mal.h
@@ -0,0 +1,276 @@
+/*
+ * drivers/net/ibm_newemac/mal.h
+ *
+ * Memory Access Layer (MAL) support
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ *      Armin Kuster <akuster@mvista.com>
+ *      Copyright 2002 MontaVista Softare Inc.
+ *
+ * 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.
+ *
+ */
+#ifndef __IBM_NEWEMAC_MAL_H
+#define __IBM_NEWEMAC_MAL_H
+
+/*
+ * There are some variations on the MAL, we express them in this driver as
+ * MAL Version 1 and 2 though that doesn't match any IBM terminology.
+ *
+ * We call MAL 1 the version in 405GP, 405GPR, 405EP, 440EP, 440GR and
+ * NP405H.
+ *
+ * We call MAL 2 the version in 440GP, 440GX, 440SP, 440SPE and Axon
+ *
+ * The driver expects a "version" property in the emac node containing
+ * a number 1 or 2. New device-trees for EMAC capable platforms are thus
+ * required to include that when porting to arch/powerpc.
+ */
+
+/* MALx DCR registers */
+#define	MAL_CFG			0x00
+#define	  MAL_CFG_SR		0x80000000
+#define   MAL_CFG_PLBB		0x00004000
+#define   MAL_CFG_OPBBL		0x00000080
+#define   MAL_CFG_EOPIE		0x00000004
+#define   MAL_CFG_LEA		0x00000002
+#define   MAL_CFG_SD		0x00000001
+
+/* MAL V1 CFG bits */
+#define   MAL1_CFG_PLBP_MASK	0x00c00000
+#define   MAL1_CFG_PLBP_10	0x00800000
+#define   MAL1_CFG_GA		0x00200000
+#define   MAL1_CFG_OA		0x00100000
+#define   MAL1_CFG_PLBLE	0x00080000
+#define   MAL1_CFG_PLBT_MASK	0x00078000
+#define   MAL1_CFG_DEFAULT	(MAL1_CFG_PLBP_10 | MAL1_CFG_PLBT_MASK)
+
+/* MAL V2 CFG bits */
+#define   MAL2_CFG_RPP_MASK	0x00c00000
+#define   MAL2_CFG_RPP_10	0x00800000
+#define   MAL2_CFG_RMBS_MASK	0x00300000
+#define   MAL2_CFG_WPP_MASK	0x000c0000
+#define   MAL2_CFG_WPP_10	0x00080000
+#define   MAL2_CFG_WMBS_MASK	0x00030000
+#define   MAL2_CFG_PLBLE	0x00008000
+#define   MAL2_CFG_DEFAULT	(MAL2_CFG_RMBS_MASK | MAL2_CFG_WMBS_MASK | \
+				 MAL2_CFG_RPP_10 | MAL2_CFG_WPP_10)
+
+#define MAL_ESR			0x01
+#define   MAL_ESR_EVB		0x80000000
+#define   MAL_ESR_CIDT		0x40000000
+#define   MAL_ESR_CID_MASK	0x3e000000
+#define   MAL_ESR_CID_SHIFT	25
+#define   MAL_ESR_DE		0x00100000
+#define   MAL_ESR_OTE		0x00040000
+#define   MAL_ESR_OSE		0x00020000
+#define   MAL_ESR_PEIN		0x00010000
+#define   MAL_ESR_DEI		0x00000010
+#define   MAL_ESR_OTEI		0x00000004
+#define   MAL_ESR_OSEI		0x00000002
+#define   MAL_ESR_PBEI		0x00000001
+
+/* MAL V1 ESR bits */
+#define   MAL1_ESR_ONE		0x00080000
+#define   MAL1_ESR_ONEI		0x00000008
+
+/* MAL V2 ESR bits */
+#define   MAL2_ESR_PTE		0x00800000
+#define   MAL2_ESR_PRE		0x00400000
+#define   MAL2_ESR_PWE		0x00200000
+#define   MAL2_ESR_PTEI		0x00000080
+#define   MAL2_ESR_PREI		0x00000040
+#define   MAL2_ESR_PWEI		0x00000020
+
+
+#define MAL_IER			0x02
+#define   MAL_IER_DE		0x00000010
+#define   MAL_IER_OTE		0x00000004
+#define   MAL_IER_OE		0x00000002
+#define   MAL_IER_PE		0x00000001
+/* MAL V1 IER bits */
+#define   MAL1_IER_NWE		0x00000008
+#define   MAL1_IER_SOC_EVENTS	MAL1_IER_NWE
+#define   MAL1_IER_EVENTS	(MAL1_IER_SOC_EVENTS | MAL_IER_OTE | \
+				 MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE)
+
+/* MAL V2 IER bits */
+#define   MAL2_IER_PT		0x00000080
+#define   MAL2_IER_PRE		0x00000040
+#define   MAL2_IER_PWE		0x00000020
+#define   MAL2_IER_SOC_EVENTS	(MAL2_IER_PT | MAL2_IER_PRE | MAL2_IER_PWE)
+#define   MAL2_IER_EVENTS	(MAL2_IER_SOC_EVENTS | MAL_IER_OTE | \
+				 MAL_IER_OTE | MAL_IER_OE | MAL_IER_PE)
+
+
+#define MAL_TXCASR		0x04
+#define MAL_TXCARR		0x05
+#define MAL_TXEOBISR		0x06
+#define MAL_TXDEIR		0x07
+#define MAL_RXCASR		0x10
+#define MAL_RXCARR		0x11
+#define MAL_RXEOBISR		0x12
+#define MAL_RXDEIR		0x13
+#define MAL_TXCTPR(n)		((n) + 0x20)
+#define MAL_RXCTPR(n)		((n) + 0x40)
+#define MAL_RCBS(n)		((n) + 0x60)
+
+/* In reality MAL can handle TX buffers up to 4095 bytes long,
+ * but this isn't a good round number :) 		 --ebs
+ */
+#define MAL_MAX_TX_SIZE		4080
+#define MAL_MAX_RX_SIZE		4080
+
+static inline int mal_rx_size(int len)
+{
+	len = (len + 0xf) & ~0xf;
+	return len > MAL_MAX_RX_SIZE ? MAL_MAX_RX_SIZE : len;
+}
+
+static inline int mal_tx_chunks(int len)
+{
+	return (len + MAL_MAX_TX_SIZE - 1) / MAL_MAX_TX_SIZE;
+}
+
+#define MAL_CHAN_MASK(n)	(0x80000000 >> (n))
+
+/* MAL Buffer Descriptor structure */
+struct mal_descriptor {
+	u16 ctrl;		/* MAL / Commac status control bits */
+	u16 data_len;		/* Max length is 4K-1 (12 bits)     */
+	u32 data_ptr;		/* pointer to actual data buffer    */
+};
+
+/* the following defines are for the MadMAL status and control registers. */
+/* MADMAL transmit and receive status/control bits  */
+#define MAL_RX_CTRL_EMPTY	0x8000
+#define MAL_RX_CTRL_WRAP	0x4000
+#define MAL_RX_CTRL_CM		0x2000
+#define MAL_RX_CTRL_LAST	0x1000
+#define MAL_RX_CTRL_FIRST	0x0800
+#define MAL_RX_CTRL_INTR	0x0400
+#define MAL_RX_CTRL_SINGLE	(MAL_RX_CTRL_LAST | MAL_RX_CTRL_FIRST)
+#define MAL_IS_SINGLE_RX(ctrl)	(((ctrl) & MAL_RX_CTRL_SINGLE) == MAL_RX_CTRL_SINGLE)
+
+#define MAL_TX_CTRL_READY	0x8000
+#define MAL_TX_CTRL_WRAP	0x4000
+#define MAL_TX_CTRL_CM		0x2000
+#define MAL_TX_CTRL_LAST	0x1000
+#define MAL_TX_CTRL_INTR	0x0400
+
+struct mal_commac_ops {
+	void	(*poll_tx) (void *dev);
+	int	(*poll_rx) (void *dev, int budget);
+	int	(*peek_rx) (void *dev);
+	void	(*rxde) (void *dev);
+};
+
+struct mal_commac {
+	struct mal_commac_ops	*ops;
+	void			*dev;
+	struct list_head	poll_list;
+	long       		flags;
+#define MAL_COMMAC_RX_STOPPED		0
+#define MAL_COMMAC_POLL_DISABLED	1
+	u32			tx_chan_mask;
+	u32			rx_chan_mask;
+	struct list_head	list;
+};
+
+struct mal_instance {
+	int			version;
+	int			dcr_base;
+	dcr_host_t		dcr_host;
+
+	int			num_tx_chans;	/* Number of TX channels */
+	int			num_rx_chans;	/* Number of RX channels */
+	int 			txeob_irq;	/* TX End Of Buffer IRQ  */
+	int 			rxeob_irq;	/* RX End Of Buffer IRQ  */
+	int			txde_irq;	/* TX Descriptor Error IRQ */
+	int			rxde_irq;	/* RX Descriptor Error IRQ */
+	int			serr_irq;	/* MAL System Error IRQ    */
+
+	struct list_head	poll_list;
+	struct napi_struct	napi;
+
+	struct list_head	list;
+	u32			tx_chan_mask;
+	u32			rx_chan_mask;
+
+	dma_addr_t		bd_dma;
+	struct mal_descriptor	*bd_virt;
+
+	struct of_device	*ofdev;
+	int			index;
+	spinlock_t		lock;
+};
+
+static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg)
+{
+	return dcr_read(mal->dcr_host, mal->dcr_base + reg);
+}
+
+static inline void set_mal_dcrn(struct mal_instance *mal, int reg, u32 val)
+{
+	dcr_write(mal->dcr_host, mal->dcr_base + reg, val);
+}
+
+/* Register MAL devices */
+int mal_init(void);
+void mal_exit(void);
+
+int mal_register_commac(struct mal_instance *mal,
+			struct mal_commac *commac);
+void mal_unregister_commac(struct mal_instance *mal,
+			   struct mal_commac *commac);
+int mal_set_rcbs(struct mal_instance *mal, int channel, unsigned long size);
+
+/* Returns BD ring offset for a particular channel
+   (in 'struct mal_descriptor' elements)
+*/
+int mal_tx_bd_offset(struct mal_instance *mal, int channel);
+int mal_rx_bd_offset(struct mal_instance *mal, int channel);
+
+void mal_enable_tx_channel(struct mal_instance *mal, int channel);
+void mal_disable_tx_channel(struct mal_instance *mal, int channel);
+void mal_enable_rx_channel(struct mal_instance *mal, int channel);
+void mal_disable_rx_channel(struct mal_instance *mal, int channel);
+
+void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac);
+void mal_poll_enable(struct mal_instance *mal, struct mal_commac *commac);
+
+/* Add/remove EMAC to/from MAL polling list */
+void mal_poll_add(struct mal_instance *mal, struct mal_commac *commac);
+void mal_poll_del(struct mal_instance *mal, struct mal_commac *commac);
+
+/* Ethtool MAL registers */
+struct mal_regs {
+	u32 tx_count;
+	u32 rx_count;
+
+	u32 cfg;
+	u32 esr;
+	u32 ier;
+	u32 tx_casr;
+	u32 tx_carr;
+	u32 tx_eobisr;
+	u32 tx_deir;
+	u32 rx_casr;
+	u32 rx_carr;
+	u32 rx_eobisr;
+	u32 rx_deir;
+	u32 tx_ctpr[32];
+	u32 rx_ctpr[32];
+	u32 rcbs[32];
+};
+
+int mal_get_regs_len(struct mal_instance *mal);
+void *mal_dump_regs(struct mal_instance *mal, void *buf);
+
+#endif /* __IBM_NEWEMAC_MAL_H */
diff --git a/drivers/net/ibm_newemac/phy.c b/drivers/net/ibm_newemac/phy.c
new file mode 100644
index 0000000..aa1f0dd
--- /dev/null
+++ b/drivers/net/ibm_newemac/phy.c
@@ -0,0 +1,373 @@
+/*
+ * drivers/net/ibm_newemac/phy.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, PHY support.
+ * Borrowed from sungem_phy.c, though I only kept the generic MII
+ * driver for now.
+ *
+ * This file should be shared with other drivers or eventually
+ * merged as the "low level" part of miilib
+ *
+ * (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org)
+ * (c) 2004-2005, Eugene Surovegin <ebs@ebshome.net>
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+
+#include "emac.h"
+#include "phy.h"
+
+static inline int phy_read(struct mii_phy *phy, int reg)
+{
+	return phy->mdio_read(phy->dev, phy->address, reg);
+}
+
+static inline void phy_write(struct mii_phy *phy, int reg, int val)
+{
+	phy->mdio_write(phy->dev, phy->address, reg, val);
+}
+
+int emac_mii_reset_phy(struct mii_phy *phy)
+{
+	int val;
+	int limit = 10000;
+
+	val = phy_read(phy, MII_BMCR);
+	val &= ~(BMCR_ISOLATE | BMCR_ANENABLE);
+	val |= BMCR_RESET;
+	phy_write(phy, MII_BMCR, val);
+
+	udelay(300);
+
+	while (limit--) {
+		val = phy_read(phy, MII_BMCR);
+		if (val >= 0 && (val & BMCR_RESET) == 0)
+			break;
+		udelay(10);
+	}
+	if ((val & BMCR_ISOLATE) && limit > 0)
+		phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);
+
+	return limit <= 0;
+}
+
+static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
+{
+	int ctl, adv;
+
+	phy->autoneg = AUTONEG_ENABLE;
+	phy->speed = SPEED_10;
+	phy->duplex = DUPLEX_HALF;
+	phy->pause = phy->asym_pause = 0;
+	phy->advertising = advertise;
+
+	ctl = phy_read(phy, MII_BMCR);
+	if (ctl < 0)
+		return ctl;
+	ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
+
+	/* First clear the PHY */
+	phy_write(phy, MII_BMCR, ctl);
+
+	/* Setup standard advertise */
+	adv = phy_read(phy, MII_ADVERTISE);
+	if (adv < 0)
+		return adv;
+	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
+		 ADVERTISE_PAUSE_ASYM);
+	if (advertise & ADVERTISED_10baseT_Half)
+		adv |= ADVERTISE_10HALF;
+	if (advertise & ADVERTISED_10baseT_Full)
+		adv |= ADVERTISE_10FULL;
+	if (advertise & ADVERTISED_100baseT_Half)
+		adv |= ADVERTISE_100HALF;
+	if (advertise & ADVERTISED_100baseT_Full)
+		adv |= ADVERTISE_100FULL;
+	if (advertise & ADVERTISED_Pause)
+		adv |= ADVERTISE_PAUSE_CAP;
+	if (advertise & ADVERTISED_Asym_Pause)
+		adv |= ADVERTISE_PAUSE_ASYM;
+	phy_write(phy, MII_ADVERTISE, adv);
+
+	if (phy->features &
+	    (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
+		adv = phy_read(phy, MII_CTRL1000);
+		if (adv < 0)
+			return adv;
+		adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+		if (advertise & ADVERTISED_1000baseT_Full)
+			adv |= ADVERTISE_1000FULL;
+		if (advertise & ADVERTISED_1000baseT_Half)
+			adv |= ADVERTISE_1000HALF;
+		phy_write(phy, MII_CTRL1000, adv);
+	}
+
+	/* Start/Restart aneg */
+	ctl = phy_read(phy, MII_BMCR);
+	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+	phy_write(phy, MII_BMCR, ctl);
+
+	return 0;
+}
+
+static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
+{
+	int ctl;
+
+	phy->autoneg = AUTONEG_DISABLE;
+	phy->speed = speed;
+	phy->duplex = fd;
+	phy->pause = phy->asym_pause = 0;
+
+	ctl = phy_read(phy, MII_BMCR);
+	if (ctl < 0)
+		return ctl;
+	ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
+
+	/* First clear the PHY */
+	phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
+
+	/* Select speed & duplex */
+	switch (speed) {
+	case SPEED_10:
+		break;
+	case SPEED_100:
+		ctl |= BMCR_SPEED100;
+		break;
+	case SPEED_1000:
+		ctl |= BMCR_SPEED1000;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (fd == DUPLEX_FULL)
+		ctl |= BMCR_FULLDPLX;
+	phy_write(phy, MII_BMCR, ctl);
+
+	return 0;
+}
+
+static int genmii_poll_link(struct mii_phy *phy)
+{
+	int status;
+
+	/* Clear latched value with dummy read */
+	phy_read(phy, MII_BMSR);
+	status = phy_read(phy, MII_BMSR);
+	if (status < 0 || (status & BMSR_LSTATUS) == 0)
+		return 0;
+	if (phy->autoneg == AUTONEG_ENABLE && !(status & BMSR_ANEGCOMPLETE))
+		return 0;
+	return 1;
+}
+
+static int genmii_read_link(struct mii_phy *phy)
+{
+	if (phy->autoneg == AUTONEG_ENABLE) {
+		int glpa = 0;
+		int lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE);
+		if (lpa < 0)
+			return lpa;
+
+		if (phy->features &
+		    (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
+			int adv = phy_read(phy, MII_CTRL1000);
+			glpa = phy_read(phy, MII_STAT1000);
+
+			if (glpa < 0 || adv < 0)
+				return adv;
+
+			glpa &= adv << 2;
+		}
+
+		phy->speed = SPEED_10;
+		phy->duplex = DUPLEX_HALF;
+		phy->pause = phy->asym_pause = 0;
+
+		if (glpa & (LPA_1000FULL | LPA_1000HALF)) {
+			phy->speed = SPEED_1000;
+			if (glpa & LPA_1000FULL)
+				phy->duplex = DUPLEX_FULL;
+		} else if (lpa & (LPA_100FULL | LPA_100HALF)) {
+			phy->speed = SPEED_100;
+			if (lpa & LPA_100FULL)
+				phy->duplex = DUPLEX_FULL;
+		} else if (lpa & LPA_10FULL)
+			phy->duplex = DUPLEX_FULL;
+
+		if (phy->duplex == DUPLEX_FULL) {
+			phy->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
+			phy->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
+		}
+	} else {
+		int bmcr = phy_read(phy, MII_BMCR);
+		if (bmcr < 0)
+			return bmcr;
+
+		if (bmcr & BMCR_FULLDPLX)
+			phy->duplex = DUPLEX_FULL;
+		else
+			phy->duplex = DUPLEX_HALF;
+		if (bmcr & BMCR_SPEED1000)
+			phy->speed = SPEED_1000;
+		else if (bmcr & BMCR_SPEED100)
+			phy->speed = SPEED_100;
+		else
+			phy->speed = SPEED_10;
+
+		phy->pause = phy->asym_pause = 0;
+	}
+	return 0;
+}
+
+/* Generic implementation for most 10/100/1000 PHYs */
+static struct mii_phy_ops generic_phy_ops = {
+	.setup_aneg	= genmii_setup_aneg,
+	.setup_forced	= genmii_setup_forced,
+	.poll_link	= genmii_poll_link,
+	.read_link	= genmii_read_link
+};
+
+static struct mii_phy_def genmii_phy_def = {
+	.phy_id		= 0x00000000,
+	.phy_id_mask	= 0x00000000,
+	.name		= "Generic MII",
+	.ops		= &generic_phy_ops
+};
+
+/* CIS8201 */
+#define MII_CIS8201_10BTCSR	0x16
+#define  TENBTCSR_ECHO_DISABLE	0x2000
+#define MII_CIS8201_EPCR	0x17
+#define  EPCR_MODE_MASK		0x3000
+#define  EPCR_GMII_MODE		0x0000
+#define  EPCR_RGMII_MODE	0x1000
+#define  EPCR_TBI_MODE		0x2000
+#define  EPCR_RTBI_MODE		0x3000
+#define MII_CIS8201_ACSR	0x1c
+#define  ACSR_PIN_PRIO_SELECT	0x0004
+
+static int cis8201_init(struct mii_phy *phy)
+{
+	int epcr;
+
+	epcr = phy_read(phy, MII_CIS8201_EPCR);
+	if (epcr < 0)
+		return epcr;
+
+	epcr &= ~EPCR_MODE_MASK;
+
+	switch (phy->mode) {
+	case PHY_MODE_TBI:
+		epcr |= EPCR_TBI_MODE;
+		break;
+	case PHY_MODE_RTBI:
+		epcr |= EPCR_RTBI_MODE;
+		break;
+	case PHY_MODE_GMII:
+		epcr |= EPCR_GMII_MODE;
+		break;
+	case PHY_MODE_RGMII:
+	default:
+		epcr |= EPCR_RGMII_MODE;
+	}
+
+	phy_write(phy, MII_CIS8201_EPCR, epcr);
+
+	/* MII regs override strap pins */
+	phy_write(phy, MII_CIS8201_ACSR,
+		  phy_read(phy, MII_CIS8201_ACSR) | ACSR_PIN_PRIO_SELECT);
+
+	/* Disable TX_EN -> CRS echo mode, otherwise 10/HDX doesn't work */
+	phy_write(phy, MII_CIS8201_10BTCSR,
+		  phy_read(phy, MII_CIS8201_10BTCSR) | TENBTCSR_ECHO_DISABLE);
+
+	return 0;
+}
+
+static struct mii_phy_ops cis8201_phy_ops = {
+	.init		= cis8201_init,
+	.setup_aneg	= genmii_setup_aneg,
+	.setup_forced	= genmii_setup_forced,
+	.poll_link	= genmii_poll_link,
+	.read_link	= genmii_read_link
+};
+
+static struct mii_phy_def cis8201_phy_def = {
+	.phy_id		= 0x000fc410,
+	.phy_id_mask	= 0x000ffff0,
+	.name		= "CIS8201 Gigabit Ethernet",
+	.ops		= &cis8201_phy_ops
+};
+
+static struct mii_phy_def *mii_phy_table[] = {
+	&cis8201_phy_def,
+	&genmii_phy_def,
+	NULL
+};
+
+int emac_mii_phy_probe(struct mii_phy *phy, int address)
+{
+	struct mii_phy_def *def;
+	int i;
+	u32 id;
+
+	phy->autoneg = AUTONEG_DISABLE;
+	phy->advertising = 0;
+	phy->address = address;
+	phy->speed = SPEED_10;
+	phy->duplex = DUPLEX_HALF;
+	phy->pause = phy->asym_pause = 0;
+
+	/* Take PHY out of isolate mode and reset it. */
+	if (emac_mii_reset_phy(phy))
+		return -ENODEV;
+
+	/* Read ID and find matching entry */
+	id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2);
+	for (i = 0; (def = mii_phy_table[i]) != NULL; i++)
+		if ((id & def->phy_id_mask) == def->phy_id)
+			break;
+	/* Should never be NULL (we have a generic entry), but... */
+	if (!def)
+		return -ENODEV;
+
+	phy->def = def;
+
+	/* Determine PHY features if needed */
+	phy->features = def->features;
+	if (!phy->features) {
+		u16 bmsr = phy_read(phy, MII_BMSR);
+		if (bmsr & BMSR_ANEGCAPABLE)
+			phy->features |= SUPPORTED_Autoneg;
+		if (bmsr & BMSR_10HALF)
+			phy->features |= SUPPORTED_10baseT_Half;
+		if (bmsr & BMSR_10FULL)
+			phy->features |= SUPPORTED_10baseT_Full;
+		if (bmsr & BMSR_100HALF)
+			phy->features |= SUPPORTED_100baseT_Half;
+		if (bmsr & BMSR_100FULL)
+			phy->features |= SUPPORTED_100baseT_Full;
+		if (bmsr & BMSR_ESTATEN) {
+			u16 esr = phy_read(phy, MII_ESTATUS);
+			if (esr & ESTATUS_1000_TFULL)
+				phy->features |= SUPPORTED_1000baseT_Full;
+			if (esr & ESTATUS_1000_THALF)
+				phy->features |= SUPPORTED_1000baseT_Half;
+		}
+		phy->features |= SUPPORTED_MII;
+	}
+
+	/* Setup default advertising */
+	phy->advertising = phy->features;
+
+	return 0;
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ibm_newemac/phy.h b/drivers/net/ibm_newemac/phy.h
new file mode 100644
index 0000000..6feca26
--- /dev/null
+++ b/drivers/net/ibm_newemac/phy.h
@@ -0,0 +1,80 @@
+/*
+ * drivers/net/ibm_newemac/phy.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, PHY support
+ *
+ * Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ * February 2003
+ *
+ * Minor additions by Eugene Surovegin <ebs@ebshome.net>, 2004
+ *
+ * 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 file basically duplicates sungem_phy.{c,h} with different PHYs
+ * supported. I'm looking into merging that in a single mii layer more
+ * flexible than mii.c
+ */
+
+#ifndef __IBM_NEWEMAC_PHY_H
+#define __IBM_NEWEMAC_PHY_H
+
+struct mii_phy;
+
+/* Operations supported by any kind of PHY */
+struct mii_phy_ops {
+	int (*init) (struct mii_phy * phy);
+	int (*suspend) (struct mii_phy * phy, int wol_options);
+	int (*setup_aneg) (struct mii_phy * phy, u32 advertise);
+	int (*setup_forced) (struct mii_phy * phy, int speed, int fd);
+	int (*poll_link) (struct mii_phy * phy);
+	int (*read_link) (struct mii_phy * phy);
+};
+
+/* Structure used to statically define an mii/gii based PHY */
+struct mii_phy_def {
+	u32 phy_id;		/* Concatenated ID1 << 16 | ID2 */
+	u32 phy_id_mask;	/* Significant bits */
+	u32 features;		/* Ethtool SUPPORTED_* defines or
+				   0 for autodetect */
+	int magic_aneg;		/* Autoneg does all speed test for us */
+	const char *name;
+	const struct mii_phy_ops *ops;
+};
+
+/* An instance of a PHY, partially borrowed from mii_if_info */
+struct mii_phy {
+	struct mii_phy_def *def;
+	u32 advertising;	/* Ethtool ADVERTISED_* defines */
+	u32 features;		/* Copied from mii_phy_def.features
+				   or determined automaticaly */
+	int address;		/* PHY address */
+	int mode;		/* PHY mode */
+
+	/* 1: autoneg enabled, 0: disabled */
+	int autoneg;
+
+	/* forced speed & duplex (no autoneg)
+	 * partner speed & duplex & pause (autoneg)
+	 */
+	int speed;
+	int duplex;
+	int pause;
+	int asym_pause;
+
+	/* Provided by host chip */
+	struct net_device *dev;
+	int (*mdio_read) (struct net_device * dev, int addr, int reg);
+	void (*mdio_write) (struct net_device * dev, int addr, int reg,
+			    int val);
+};
+
+/* Pass in a struct mii_phy with dev, mdio_read and mdio_write
+ * filled, the remaining fields will be filled on return
+ */
+int emac_mii_phy_probe(struct mii_phy *phy, int address);
+int emac_mii_reset_phy(struct mii_phy *phy);
+
+#endif /* __IBM_NEWEMAC_PHY_H */
diff --git a/drivers/net/ibm_newemac/rgmii.c b/drivers/net/ibm_newemac/rgmii.c
new file mode 100644
index 0000000..bcd7fc6
--- /dev/null
+++ b/drivers/net/ibm_newemac/rgmii.c
@@ -0,0 +1,323 @@
+/*
+ * drivers/net/ibm_newemac/rgmii.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ * 	Matt Porter <mporter@kernel.crashing.org>
+ * 	Copyright 2004 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/ethtool.h>
+#include <asm/io.h>
+
+#include "emac.h"
+#include "debug.h"
+
+// XXX FIXME: Axon seems to support a subset of the RGMII, we
+// thus need to take that into account and possibly change some
+// of the bit settings below that don't seem to quite match the
+// AXON spec
+
+/* RGMIIx_FER */
+#define RGMII_FER_MASK(idx)	(0x7 << ((idx) * 4))
+#define RGMII_FER_RTBI(idx)	(0x4 << ((idx) * 4))
+#define RGMII_FER_RGMII(idx)	(0x5 << ((idx) * 4))
+#define RGMII_FER_TBI(idx)	(0x6 << ((idx) * 4))
+#define RGMII_FER_GMII(idx)	(0x7 << ((idx) * 4))
+
+/* RGMIIx_SSR */
+#define RGMII_SSR_MASK(idx)	(0x7 << ((idx) * 8))
+#define RGMII_SSR_100(idx)	(0x2 << ((idx) * 8))
+#define RGMII_SSR_1000(idx)	(0x4 << ((idx) * 8))
+
+/* RGMII bridge supports only GMII/TBI and RGMII/RTBI PHYs */
+static inline int rgmii_valid_mode(int phy_mode)
+{
+	return  phy_mode == PHY_MODE_GMII ||
+		phy_mode == PHY_MODE_RGMII ||
+		phy_mode == PHY_MODE_TBI ||
+		phy_mode == PHY_MODE_RTBI;
+}
+
+static inline const char *rgmii_mode_name(int mode)
+{
+	switch (mode) {
+	case PHY_MODE_RGMII:
+		return "RGMII";
+	case PHY_MODE_TBI:
+		return "TBI";
+	case PHY_MODE_GMII:
+		return "GMII";
+	case PHY_MODE_RTBI:
+		return "RTBI";
+	default:
+		BUG();
+	}
+}
+
+static inline u32 rgmii_mode_mask(int mode, int input)
+{
+	switch (mode) {
+	case PHY_MODE_RGMII:
+		return RGMII_FER_RGMII(input);
+	case PHY_MODE_TBI:
+		return RGMII_FER_TBI(input);
+	case PHY_MODE_GMII:
+		return RGMII_FER_GMII(input);
+	case PHY_MODE_RTBI:
+		return RGMII_FER_RTBI(input);
+	default:
+		BUG();
+	}
+}
+
+int __devinit rgmii_attach(struct of_device *ofdev, int input, int mode)
+{
+	struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+	struct rgmii_regs *p = dev->base;
+
+	RGMII_DBG(dev, "attach(%d)" NL, input);
+
+	/* Check if we need to attach to a RGMII */
+	if (input < 0 || !rgmii_valid_mode(mode)) {
+		printk(KERN_ERR "%s: unsupported settings !\n",
+		       ofdev->node->full_name);
+		return -ENODEV;
+	}
+
+	mutex_lock(&dev->lock);
+
+	/* Enable this input */
+	out_be32(&p->fer, in_be32(&p->fer) | rgmii_mode_mask(mode, input));
+
+	printk(KERN_NOTICE "%s: input %d in %s mode\n",
+	       ofdev->node->full_name, input, rgmii_mode_name(mode));
+
+	++dev->users;
+
+	mutex_unlock(&dev->lock);
+
+	return 0;
+}
+
+void rgmii_set_speed(struct of_device *ofdev, int input, int speed)
+{
+	struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+	struct rgmii_regs *p = dev->base;
+	u32 ssr;
+
+	mutex_lock(&dev->lock);
+
+	ssr = in_be32(&p->ssr) & ~RGMII_SSR_MASK(input);
+
+	RGMII_DBG(dev, "speed(%d, %d)" NL, input, speed);
+
+	if (speed == SPEED_1000)
+		ssr |= RGMII_SSR_1000(input);
+	else if (speed == SPEED_100)
+		ssr |= RGMII_SSR_100(input);
+
+	out_be32(&p->ssr, ssr);
+
+	mutex_unlock(&dev->lock);
+}
+
+void rgmii_get_mdio(struct of_device *ofdev, int input)
+{
+	struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+	struct rgmii_regs *p = dev->base;
+	u32 fer;
+
+	RGMII_DBG2(dev, "get_mdio(%d)" NL, input);
+
+	if (dev->type != RGMII_AXON)
+		return;
+
+	mutex_lock(&dev->lock);
+
+	fer = in_be32(&p->fer);
+	fer |= 0x00080000u >> input;
+	out_be32(&p->fer, fer);
+	(void)in_be32(&p->fer);
+
+	DBG2(dev, " fer = 0x%08x\n", fer);
+}
+
+void rgmii_put_mdio(struct of_device *ofdev, int input)
+{
+	struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+	struct rgmii_regs *p = dev->base;
+	u32 fer;
+
+	RGMII_DBG2(dev, "put_mdio(%d)" NL, input);
+
+	if (dev->type != RGMII_AXON)
+		return;
+
+	fer = in_be32(&p->fer);
+	fer &= ~(0x00080000u >> input);
+	out_be32(&p->fer, fer);
+	(void)in_be32(&p->fer);
+
+	DBG2(dev, " fer = 0x%08x\n", fer);
+
+	mutex_unlock(&dev->lock);
+}
+
+void __devexit rgmii_detach(struct of_device *ofdev, int input)
+{
+	struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+	struct rgmii_regs *p = dev->base;
+
+	mutex_lock(&dev->lock);
+
+	BUG_ON(!dev || dev->users == 0);
+
+	RGMII_DBG(dev, "detach(%d)" NL, input);
+
+	/* Disable this input */
+	out_be32(&p->fer, in_be32(&p->fer) & ~RGMII_FER_MASK(input));
+
+	--dev->users;
+
+	mutex_unlock(&dev->lock);
+}
+
+int rgmii_get_regs_len(struct of_device *ofdev)
+{
+	return sizeof(struct emac_ethtool_regs_subhdr) +
+		sizeof(struct rgmii_regs);
+}
+
+void *rgmii_dump_regs(struct of_device *ofdev, void *buf)
+{
+	struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+	struct emac_ethtool_regs_subhdr *hdr = buf;
+	struct rgmii_regs *regs = (struct rgmii_regs *)(hdr + 1);
+
+	hdr->version = 0;
+	hdr->index = 0; /* for now, are there chips with more than one
+			 * rgmii ? if yes, then we'll add a cell_index
+			 * like we do for emac
+			 */
+	memcpy_fromio(regs, dev->base, sizeof(struct rgmii_regs));
+	return regs + 1;
+}
+
+
+static int __devinit rgmii_probe(struct of_device *ofdev,
+				 const struct of_device_id *match)
+{
+	struct device_node *np = ofdev->node;
+	struct rgmii_instance *dev;
+	struct resource regs;
+	int rc;
+
+	rc = -ENOMEM;
+	dev = kzalloc(sizeof(struct rgmii_instance), GFP_KERNEL);
+	if (dev == NULL) {
+		printk(KERN_ERR "%s: could not allocate RGMII device!\n",
+		       np->full_name);
+		goto err_gone;
+	}
+
+	mutex_init(&dev->lock);
+	dev->ofdev = ofdev;
+
+	rc = -ENXIO;
+	if (of_address_to_resource(np, 0, &regs)) {
+		printk(KERN_ERR "%s: Can't get registers address\n",
+		       np->full_name);
+		goto err_free;
+	}
+
+	rc = -ENOMEM;
+	dev->base = (struct rgmii_regs *)ioremap(regs.start,
+						 sizeof(struct rgmii_regs));
+	if (dev->base == NULL) {
+		printk(KERN_ERR "%s: Can't map device registers!\n",
+		       np->full_name);
+		goto err_free;
+	}
+
+	/* Check for RGMII type */
+	if (device_is_compatible(ofdev->node, "ibm,rgmii-axon"))
+		dev->type = RGMII_AXON;
+	else
+		dev->type = RGMII_STANDARD;
+
+	DBG2(dev, " Boot FER = 0x%08x, SSR = 0x%08x\n",
+	     in_be32(&dev->base->fer), in_be32(&dev->base->ssr));
+
+	/* Disable all inputs by default */
+	out_be32(&dev->base->fer, 0);
+
+	printk(KERN_INFO
+	       "RGMII %s %s initialized\n",
+	       dev->type == RGMII_STANDARD ? "standard" : "axon",
+	       ofdev->node->full_name);
+
+	wmb();
+	dev_set_drvdata(&ofdev->dev, dev);
+
+	return 0;
+
+ err_free:
+	kfree(dev);
+ err_gone:
+	return rc;
+}
+
+static int __devexit rgmii_remove(struct of_device *ofdev)
+{
+	struct rgmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+	dev_set_drvdata(&ofdev->dev, NULL);
+
+	WARN_ON(dev->users != 0);
+
+	iounmap(dev->base);
+	kfree(dev);
+
+	return 0;
+}
+
+static struct of_device_id rgmii_match[] =
+{
+	{
+		.type		= "rgmii-interface",
+		.compatible	= "ibm,rgmii",
+	},
+	{
+		.type		= "emac-rgmii",
+	},
+	{},
+};
+
+static struct of_platform_driver rgmii_driver = {
+	.name = "emac-rgmii",
+	.match_table = rgmii_match,
+
+	.probe = rgmii_probe,
+	.remove = rgmii_remove,
+};
+
+int __init rgmii_init(void)
+{
+	return of_register_platform_driver(&rgmii_driver);
+}
+
+void rgmii_exit(void)
+{
+	of_unregister_platform_driver(&rgmii_driver);
+}
diff --git a/drivers/net/ibm_newemac/rgmii.h b/drivers/net/ibm_newemac/rgmii.h
new file mode 100644
index 0000000..5780683
--- /dev/null
+++ b/drivers/net/ibm_newemac/rgmii.h
@@ -0,0 +1,76 @@
+/*
+ * drivers/net/ibm_newemac/rgmii.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support.
+ *
+ * Based on ocp_zmii.h/ibm_emac_zmii.h
+ * Armin Kuster akuster@mvista.com
+ *
+ * Copyright 2004 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __IBM_NEWEMAC_RGMII_H
+#define __IBM_NEWEMAC_RGMII_H
+
+/* RGMII bridge type */
+#define RGMII_STANDARD		0
+#define RGMII_AXON		1
+
+/* RGMII bridge */
+struct rgmii_regs {
+	u32 fer;		/* Function enable register */
+	u32 ssr;		/* Speed select register */
+};
+
+/* RGMII device */
+struct rgmii_instance {
+	struct rgmii_regs __iomem	*base;
+
+	/* Type of RGMII bridge */
+	int				type;
+
+	/* Only one EMAC whacks us at a time */
+	struct mutex			lock;
+
+	/* number of EMACs using this RGMII bridge */
+	int				users;
+
+	/* OF device instance */
+	struct of_device		*ofdev;
+};
+
+#ifdef CONFIG_IBM_NEW_EMAC_RGMII
+
+extern int rgmii_init(void);
+extern void rgmii_exit(void);
+extern int rgmii_attach(struct of_device *ofdev, int input, int mode);
+extern void rgmii_detach(struct of_device *ofdev, int input);
+extern void rgmii_get_mdio(struct of_device *ofdev, int input);
+extern void rgmii_put_mdio(struct of_device *ofdev, int input);
+extern void rgmii_set_speed(struct of_device *ofdev, int input, int speed);
+extern int rgmii_get_regs_len(struct of_device *ofdev);
+extern void *rgmii_dump_regs(struct of_device *ofdev, void *buf);
+
+#else
+
+# define rgmii_init()		0
+# define rgmii_exit()		do { } while(0)
+# define rgmii_attach(x,y,z)	(-ENXIO)
+# define rgmii_detach(x,y)	do { } while(0)
+# define rgmii_get_mdio(o,i)	do { } while (0)
+# define rgmii_put_mdio(o,i)	do { } while (0)
+# define rgmii_set_speed(x,y,z)	do { } while(0)
+# define rgmii_get_regs_len(x)	0
+# define rgmii_dump_regs(x,buf)	(buf)
+#endif				/* !CONFIG_IBM_NEW_EMAC_RGMII */
+
+#endif /* __IBM_NEWEMAC_RGMII_H */
diff --git a/drivers/net/ibm_newemac/tah.c b/drivers/net/ibm_newemac/tah.c
new file mode 100644
index 0000000..e05c7e8
--- /dev/null
+++ b/drivers/net/ibm_newemac/tah.c
@@ -0,0 +1,173 @@
+/*
+ * drivers/net/ibm_newemac/tah.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, TAH support.
+ *
+ * Copyright 2004 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Copyright (c) 2005 Eugene Surovegin <ebs@ebshome.net>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#include <asm/io.h>
+
+#include "emac.h"
+#include "core.h"
+
+int __devinit tah_attach(struct of_device *ofdev, int channel)
+{
+	struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+	mutex_lock(&dev->lock);
+	/* Reset has been done at probe() time... nothing else to do for now */
+	++dev->users;
+	mutex_unlock(&dev->lock);
+
+	return 0;
+}
+
+void __devexit tah_detach(struct of_device *ofdev, int channel)
+{
+	struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+	mutex_lock(&dev->lock);
+	--dev->users;
+	mutex_unlock(&dev->lock);
+}
+
+void tah_reset(struct of_device *ofdev)
+{
+	struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+	struct tah_regs *p = dev->base;
+	int n;
+
+	/* Reset TAH */
+	out_be32(&p->mr, TAH_MR_SR);
+	n = 100;
+	while ((in_be32(&p->mr) & TAH_MR_SR) && n)
+		--n;
+
+	if (unlikely(!n))
+		printk(KERN_ERR "%s: reset timeout\n", ofdev->node->full_name);
+
+	/* 10KB TAH TX FIFO accomodates the max MTU of 9000 */
+	out_be32(&p->mr,
+		 TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP |
+		 TAH_MR_DIG);
+}
+
+int tah_get_regs_len(struct of_device *ofdev)
+{
+	return sizeof(struct emac_ethtool_regs_subhdr) +
+		sizeof(struct tah_regs);
+}
+
+void *tah_dump_regs(struct of_device *ofdev, void *buf)
+{
+	struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+	struct emac_ethtool_regs_subhdr *hdr = buf;
+	struct tah_regs *regs = (struct tah_regs *)(hdr + 1);
+
+	hdr->version = 0;
+	hdr->index = 0; /* for now, are there chips with more than one
+			 * zmii ? if yes, then we'll add a cell_index
+			 * like we do for emac
+			 */
+	memcpy_fromio(regs, dev->base, sizeof(struct tah_regs));
+	return regs + 1;
+}
+
+static int __devinit tah_probe(struct of_device *ofdev,
+			       const struct of_device_id *match)
+{
+	struct device_node *np = ofdev->node;
+	struct tah_instance *dev;
+	struct resource regs;
+	int rc;
+
+	rc = -ENOMEM;
+	dev = kzalloc(sizeof(struct tah_instance), GFP_KERNEL);
+	if (dev == NULL) {
+		printk(KERN_ERR "%s: could not allocate TAH device!\n",
+		       np->full_name);
+		goto err_gone;
+	}
+
+	mutex_init(&dev->lock);
+	dev->ofdev = ofdev;
+
+	rc = -ENXIO;
+	if (of_address_to_resource(np, 0, &regs)) {
+		printk(KERN_ERR "%s: Can't get registers address\n",
+		       np->full_name);
+		goto err_free;
+	}
+
+	rc = -ENOMEM;
+	dev->base = (struct tah_regs *)ioremap(regs.start,
+					       sizeof(struct tah_regs));
+	if (dev->base == NULL) {
+		printk(KERN_ERR "%s: Can't map device registers!\n",
+		       np->full_name);
+		goto err_free;
+	}
+
+	/* Initialize TAH and enable IPv4 checksum verification, no TSO yet */
+	tah_reset(ofdev);
+
+	printk(KERN_INFO
+	       "TAH %s initialized\n", ofdev->node->full_name);
+	wmb();
+	dev_set_drvdata(&ofdev->dev, dev);
+
+	return 0;
+
+ err_free:
+	kfree(dev);
+ err_gone:
+	return rc;
+}
+
+static int __devexit tah_remove(struct of_device *ofdev)
+{
+	struct tah_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+	dev_set_drvdata(&ofdev->dev, NULL);
+
+	WARN_ON(dev->users != 0);
+
+	iounmap(dev->base);
+	kfree(dev);
+
+	return 0;
+}
+
+static struct of_device_id tah_match[] =
+{
+	{
+		.type		= "tah",
+	},
+	{},
+};
+
+static struct of_platform_driver tah_driver = {
+	.name = "emac-tah",
+	.match_table = tah_match,
+
+	.probe = tah_probe,
+	.remove = tah_remove,
+};
+
+int __init tah_init(void)
+{
+	return of_register_platform_driver(&tah_driver);
+}
+
+void tah_exit(void)
+{
+	of_unregister_platform_driver(&tah_driver);
+}
diff --git a/drivers/net/ibm_newemac/tah.h b/drivers/net/ibm_newemac/tah.h
new file mode 100644
index 0000000..bc41853
--- /dev/null
+++ b/drivers/net/ibm_newemac/tah.h
@@ -0,0 +1,90 @@
+/*
+ * drivers/net/ibm_newemac/tah.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, TAH support.
+ *
+ * Copyright 2004 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * Copyright (c) 2005 Eugene Surovegin <ebs@ebshome.net>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __IBM_NEWEMAC_TAH_H
+#define __IBM_NEWEMAC_TAH_H
+
+/* TAH */
+struct tah_regs {
+	u32 revid;
+	u32 pad[3];
+	u32 mr;
+	u32 ssr0;
+	u32 ssr1;
+	u32 ssr2;
+	u32 ssr3;
+	u32 ssr4;
+	u32 ssr5;
+	u32 tsr;
+};
+
+
+/* TAH device */
+struct tah_instance {
+	struct tah_regs __iomem		*base;
+
+	/* Only one EMAC whacks us at a time */
+	struct mutex			lock;
+
+	/* number of EMACs using this TAH */
+	int				users;
+
+	/* OF device instance */
+	struct of_device		*ofdev;
+};
+
+
+/* TAH engine */
+#define TAH_MR_CVR		0x80000000
+#define TAH_MR_SR		0x40000000
+#define TAH_MR_ST_256		0x01000000
+#define TAH_MR_ST_512		0x02000000
+#define TAH_MR_ST_768		0x03000000
+#define TAH_MR_ST_1024		0x04000000
+#define TAH_MR_ST_1280		0x05000000
+#define TAH_MR_ST_1536		0x06000000
+#define TAH_MR_TFS_16KB		0x00000000
+#define TAH_MR_TFS_2KB		0x00200000
+#define TAH_MR_TFS_4KB		0x00400000
+#define TAH_MR_TFS_6KB		0x00600000
+#define TAH_MR_TFS_8KB		0x00800000
+#define TAH_MR_TFS_10KB		0x00a00000
+#define TAH_MR_DTFP		0x00100000
+#define TAH_MR_DIG		0x00080000
+
+#ifdef CONFIG_IBM_NEW_EMAC_TAH
+
+extern int tah_init(void);
+extern void tah_exit(void);
+extern int tah_attach(struct of_device *ofdev, int channel);
+extern void tah_detach(struct of_device *ofdev, int channel);
+extern void tah_reset(struct of_device *ofdev);
+extern int tah_get_regs_len(struct of_device *ofdev);
+extern void *tah_dump_regs(struct of_device *ofdev, void *buf);
+
+#else
+
+# define tah_init()		0
+# define tah_exit()		do { } while(0)
+# define tah_attach(x,y)	(-ENXIO)
+# define tah_detach(x,y)	do { } while(0)
+# define tah_reset(x)		do { } while(0)
+# define tah_get_regs_len(x)	0
+# define tah_dump_regs(x,buf)	(buf)
+
+#endif				/* !CONFIG_IBM_NEW_EMAC_TAH */
+
+#endif /* __IBM_NEWEMAC_TAH_H */
diff --git a/drivers/net/ibm_newemac/zmii.c b/drivers/net/ibm_newemac/zmii.c
new file mode 100644
index 0000000..d063129
--- /dev/null
+++ b/drivers/net/ibm_newemac/zmii.c
@@ -0,0 +1,322 @@
+/*
+ * drivers/net/ibm_newemac/zmii.c
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ *      Armin Kuster <akuster@mvista.com>
+ * 	Copyright 2001 MontaVista Softare Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/ethtool.h>
+#include <asm/io.h>
+
+#include "emac.h"
+#include "core.h"
+
+/* ZMIIx_FER */
+#define ZMII_FER_MDI(idx)	(0x80000000 >> ((idx) * 4))
+#define ZMII_FER_MDI_ALL	(ZMII_FER_MDI(0) | ZMII_FER_MDI(1) | \
+				 ZMII_FER_MDI(2) | ZMII_FER_MDI(3))
+
+#define ZMII_FER_SMII(idx)	(0x40000000 >> ((idx) * 4))
+#define ZMII_FER_RMII(idx)	(0x20000000 >> ((idx) * 4))
+#define ZMII_FER_MII(idx)	(0x10000000 >> ((idx) * 4))
+
+/* ZMIIx_SSR */
+#define ZMII_SSR_SCI(idx)	(0x40000000 >> ((idx) * 4))
+#define ZMII_SSR_FSS(idx)	(0x20000000 >> ((idx) * 4))
+#define ZMII_SSR_SP(idx)	(0x10000000 >> ((idx) * 4))
+
+/* ZMII only supports MII, RMII and SMII
+ * we also support autodetection for backward compatibility
+ */
+static inline int zmii_valid_mode(int mode)
+{
+	return  mode == PHY_MODE_MII ||
+		mode == PHY_MODE_RMII ||
+		mode == PHY_MODE_SMII ||
+		mode == PHY_MODE_NA;
+}
+
+static inline const char *zmii_mode_name(int mode)
+{
+	switch (mode) {
+	case PHY_MODE_MII:
+		return "MII";
+	case PHY_MODE_RMII:
+		return "RMII";
+	case PHY_MODE_SMII:
+		return "SMII";
+	default:
+		BUG();
+	}
+}
+
+static inline u32 zmii_mode_mask(int mode, int input)
+{
+	switch (mode) {
+	case PHY_MODE_MII:
+		return ZMII_FER_MII(input);
+	case PHY_MODE_RMII:
+		return ZMII_FER_RMII(input);
+	case PHY_MODE_SMII:
+		return ZMII_FER_SMII(input);
+	default:
+		return 0;
+	}
+}
+
+int __devinit zmii_attach(struct of_device *ofdev, int input, int *mode)
+{
+	struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+	struct zmii_regs *p = dev->base;
+
+	ZMII_DBG(dev, "init(%d, %d)" NL, input, *mode);
+
+	if (!zmii_valid_mode(*mode))
+		/* Probably an EMAC connected to RGMII,
+		 * but it still may need ZMII for MDIO so
+		 * we don't fail here.
+		 */
+		return 0;
+
+	mutex_lock(&dev->lock);
+
+	/* Autodetect ZMII mode if not specified.
+	 * This is only for backward compatibility with the old driver.
+	 * Please, always specify PHY mode in your board port to avoid
+	 * any surprises.
+	 */
+	if (dev->mode == PHY_MODE_NA) {
+		if (*mode == PHY_MODE_NA) {
+			u32 r = dev->fer_save;
+
+			ZMII_DBG(dev, "autodetecting mode, FER = 0x%08x" NL, r);
+
+			if (r & (ZMII_FER_MII(0) | ZMII_FER_MII(1)))
+				dev->mode = PHY_MODE_MII;
+			else if (r & (ZMII_FER_RMII(0) | ZMII_FER_RMII(1)))
+				dev->mode = PHY_MODE_RMII;
+			else
+				dev->mode = PHY_MODE_SMII;
+		} else
+			dev->mode = *mode;
+
+		printk(KERN_NOTICE "%s: bridge in %s mode\n",
+		       ofdev->node->full_name, zmii_mode_name(dev->mode));
+	} else {
+		/* All inputs must use the same mode */
+		if (*mode != PHY_MODE_NA && *mode != dev->mode) {
+			printk(KERN_ERR
+			       "%s: invalid mode %d specified for input %d\n",
+			       ofdev->node->full_name, *mode, input);
+			mutex_unlock(&dev->lock);
+			return -EINVAL;
+		}
+	}
+
+	/* Report back correct PHY mode,
+	 * it may be used during PHY initialization.
+	 */
+	*mode = dev->mode;
+
+	/* Enable this input */
+	out_be32(&p->fer, in_be32(&p->fer) | zmii_mode_mask(dev->mode, input));
+	++dev->users;
+
+	mutex_unlock(&dev->lock);
+
+	return 0;
+}
+
+void zmii_get_mdio(struct of_device *ofdev, int input)
+{
+	struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+	u32 fer;
+
+	ZMII_DBG2(dev, "get_mdio(%d)" NL, input);
+
+	mutex_lock(&dev->lock);
+
+	fer = in_be32(&dev->base->fer) & ~ZMII_FER_MDI_ALL;
+	out_be32(&dev->base->fer, fer | ZMII_FER_MDI(input));
+}
+
+void zmii_put_mdio(struct of_device *ofdev, int input)
+{
+	struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+	ZMII_DBG2(dev, "put_mdio(%d)" NL, input);
+	mutex_unlock(&dev->lock);
+}
+
+
+void zmii_set_speed(struct of_device *ofdev, int input, int speed)
+{
+	struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+	u32 ssr;
+
+	mutex_lock(&dev->lock);
+
+	ssr = in_be32(&dev->base->ssr);
+
+	ZMII_DBG(dev, "speed(%d, %d)" NL, input, speed);
+
+	if (speed == SPEED_100)
+		ssr |= ZMII_SSR_SP(input);
+	else
+		ssr &= ~ZMII_SSR_SP(input);
+
+	out_be32(&dev->base->ssr, ssr);
+
+	mutex_unlock(&dev->lock);
+}
+
+void __devexit zmii_detach(struct of_device *ofdev, int input)
+{
+	struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+	BUG_ON(!dev || dev->users == 0);
+
+	mutex_lock(&dev->lock);
+
+	ZMII_DBG(dev, "detach(%d)" NL, input);
+
+	/* Disable this input */
+	out_be32(&dev->base->fer,
+		 in_be32(&dev->base->fer) & ~zmii_mode_mask(dev->mode, input));
+
+	--dev->users;
+
+	mutex_unlock(&dev->lock);
+}
+
+int zmii_get_regs_len(struct of_device *ofdev)
+{
+	return sizeof(struct emac_ethtool_regs_subhdr) +
+		sizeof(struct zmii_regs);
+}
+
+void *zmii_dump_regs(struct of_device *ofdev, void *buf)
+{
+	struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+	struct emac_ethtool_regs_subhdr *hdr = buf;
+	struct zmii_regs *regs = (struct zmii_regs *)(hdr + 1);
+
+	hdr->version = 0;
+	hdr->index = 0; /* for now, are there chips with more than one
+			 * zmii ? if yes, then we'll add a cell_index
+			 * like we do for emac
+			 */
+	memcpy_fromio(regs, dev->base, sizeof(struct zmii_regs));
+	return regs + 1;
+}
+
+static int __devinit zmii_probe(struct of_device *ofdev,
+				const struct of_device_id *match)
+{
+	struct device_node *np = ofdev->node;
+	struct zmii_instance *dev;
+	struct resource regs;
+	int rc;
+
+	rc = -ENOMEM;
+	dev = kzalloc(sizeof(struct zmii_instance), GFP_KERNEL);
+	if (dev == NULL) {
+		printk(KERN_ERR "%s: could not allocate ZMII device!\n",
+		       np->full_name);
+		goto err_gone;
+	}
+
+	mutex_init(&dev->lock);
+	dev->ofdev = ofdev;
+	dev->mode = PHY_MODE_NA;
+
+	rc = -ENXIO;
+	if (of_address_to_resource(np, 0, &regs)) {
+		printk(KERN_ERR "%s: Can't get registers address\n",
+		       np->full_name);
+		goto err_free;
+	}
+
+	rc = -ENOMEM;
+	dev->base = (struct zmii_regs *)ioremap(regs.start,
+						sizeof(struct zmii_regs));
+	if (dev->base == NULL) {
+		printk(KERN_ERR "%s: Can't map device registers!\n",
+		       np->full_name);
+		goto err_free;
+	}
+
+	/* We may need FER value for autodetection later */
+	dev->fer_save = in_be32(&dev->base->fer);
+
+	/* Disable all inputs by default */
+	out_be32(&dev->base->fer, 0);
+
+	printk(KERN_INFO
+	       "ZMII %s initialized\n", ofdev->node->full_name);
+	wmb();
+	dev_set_drvdata(&ofdev->dev, dev);
+
+	return 0;
+
+ err_free:
+	kfree(dev);
+ err_gone:
+	return rc;
+}
+
+static int __devexit zmii_remove(struct of_device *ofdev)
+{
+	struct zmii_instance *dev = dev_get_drvdata(&ofdev->dev);
+
+	dev_set_drvdata(&ofdev->dev, NULL);
+
+	WARN_ON(dev->users != 0);
+
+	iounmap(dev->base);
+	kfree(dev);
+
+	return 0;
+}
+
+static struct of_device_id zmii_match[] =
+{
+	{
+		.compatible	= "ibm,zmii",
+	},
+	/* For backward compat with old DT */
+	{
+		.type		= "emac-zmii",
+	},
+	{},
+};
+
+static struct of_platform_driver zmii_driver = {
+	.name = "emac-zmii",
+	.match_table = zmii_match,
+
+	.probe = zmii_probe,
+	.remove = zmii_remove,
+};
+
+int __init zmii_init(void)
+{
+	return of_register_platform_driver(&zmii_driver);
+}
+
+void zmii_exit(void)
+{
+	of_unregister_platform_driver(&zmii_driver);
+}
diff --git a/drivers/net/ibm_newemac/zmii.h b/drivers/net/ibm_newemac/zmii.h
new file mode 100644
index 0000000..82a9968
--- /dev/null
+++ b/drivers/net/ibm_newemac/zmii.h
@@ -0,0 +1,73 @@
+/*
+ * drivers/net/ibm_newemac/zmii.h
+ *
+ * Driver for PowerPC 4xx on-chip ethernet controller, ZMII bridge support.
+ *
+ * Copyright (c) 2004, 2005 Zultys Technologies.
+ * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
+ *
+ * Based on original work by
+ *      Armin Kuster <akuster@mvista.com>
+ * 	Copyright 2001 MontaVista Softare Inc.
+ *
+ * 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.
+ *
+ */
+#ifndef __IBM_NEWEMAC_ZMII_H
+#define __IBM_NEWEMAC_ZMII_H
+
+/* ZMII bridge registers */
+struct zmii_regs {
+	u32 fer;		/* Function enable reg */
+	u32 ssr;		/* Speed select reg */
+	u32 smiirs;		/* SMII status reg */
+};
+
+/* ZMII device */
+struct zmii_instance {
+	struct zmii_regs __iomem	*base;
+
+	/* Only one EMAC whacks us at a time */
+	struct mutex			lock;
+
+	/* subset of PHY_MODE_XXXX */
+	int				mode;
+
+	/* number of EMACs using this ZMII bridge */
+	int				users;
+
+	/* FER value left by firmware */
+	u32				fer_save;
+
+	/* OF device instance */
+	struct of_device		*ofdev;
+};
+
+#ifdef CONFIG_IBM_NEW_EMAC_ZMII
+
+extern int zmii_init(void);
+extern void zmii_exit(void);
+extern int zmii_attach(struct of_device *ofdev, int input, int *mode);
+extern void zmii_detach(struct of_device *ofdev, int input);
+extern void zmii_get_mdio(struct of_device *ofdev, int input);
+extern void zmii_put_mdio(struct of_device *ofdev, int input);
+extern void zmii_set_speed(struct of_device *ofdev, int input, int speed);
+extern int zmii_get_regs_len(struct of_device *ocpdev);
+extern void *zmii_dump_regs(struct of_device *ofdev, void *buf);
+
+#else
+# define zmii_init()		0
+# define zmii_exit()		do { } while(0)
+# define zmii_attach(x,y,z)	(-ENXIO)
+# define zmii_detach(x,y)	do { } while(0)
+# define zmii_get_mdio(x,y)	do { } while(0)
+# define zmii_put_mdio(x,y)	do { } while(0)
+# define zmii_set_speed(x,y,z)	do { } while(0)
+# define zmii_get_regs_len(x)	0
+# define zmii_dump_regs(x,buf)	(buf)
+#endif				/* !CONFIG_IBM_NEW_EMAC_ZMII */
+
+#endif /* __IBM_NEWEMAC_ZMII_H */
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index fe85d6f..91d83ac 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -591,7 +591,7 @@
 
 			skb = dev_alloc_skb(rda.length + 2);
 			if (skb == NULL)
-				priv->stat.rx_dropped++;
+				dev->stats.rx_dropped++;
 			else {
 				/* copy out data */
 
@@ -606,8 +606,8 @@
 
 				/* bookkeeping */
 				dev->last_rx = jiffies;
-				priv->stat.rx_packets++;
-				priv->stat.rx_bytes += rda.length;
+				dev->stats.rx_packets++;
+				dev->stats.rx_bytes += rda.length;
 
 				/* pass to the upper layers */
 				netif_rx(skb);
@@ -617,11 +617,11 @@
 		/* otherwise check error status bits and increase statistics */
 
 		else {
-			priv->stat.rx_errors++;
+			dev->stats.rx_errors++;
 			if (rda.status & RCREG_FAER)
-				priv->stat.rx_frame_errors++;
+				dev->stats.rx_frame_errors++;
 			if (rda.status & RCREG_CRCR)
-				priv->stat.rx_crc_errors++;
+				dev->stats.rx_crc_errors++;
 		}
 
 		/* descriptor processed, will become new last descriptor in queue */
@@ -656,8 +656,8 @@
 	memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
 
 	/* update statistics */
-	priv->stat.tx_packets++;
-	priv->stat.tx_bytes += tda.length;
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += tda.length;
 
 	/* update our pointers */
 	priv->txused[priv->currtxdescr] = 0;
@@ -680,15 +680,15 @@
 	memcpy_fromio(&tda, priv->base + priv->tdastart + (priv->currtxdescr * sizeof(tda_t)), sizeof(tda_t));
 
 	/* update statistics */
-	priv->stat.tx_errors++;
+	dev->stats.tx_errors++;
 	if (tda.status & (TCREG_NCRS | TCREG_CRSL))
-		priv->stat.tx_carrier_errors++;
+		dev->stats.tx_carrier_errors++;
 	if (tda.status & TCREG_EXC)
-		priv->stat.tx_aborted_errors++;
+		dev->stats.tx_aborted_errors++;
 	if (tda.status & TCREG_OWC)
-		priv->stat.tx_window_errors++;
+		dev->stats.tx_window_errors++;
 	if (tda.status & TCREG_FU)
-		priv->stat.tx_fifo_errors++;
+		dev->stats.tx_fifo_errors++;
 
 	/* update our pointers */
 	priv->txused[priv->currtxdescr] = 0;
@@ -824,7 +824,7 @@
 
 	if (priv->txusedcnt >= TXBUFCNT) {
 		retval = -EIO;
-		priv->stat.tx_dropped++;
+		dev->stats.tx_dropped++;
 		goto tx_done;
 	}
 
@@ -876,14 +876,6 @@
 	return retval;
 }
 
-/* return pointer to Ethernet statistics */
-
-static struct net_device_stats *ibmlana_stats(struct net_device *dev)
-{
-	ibmlana_priv *priv = netdev_priv(dev);
-	return &priv->stat;
-}
-
 /* switch receiver mode. */
 
 static void ibmlana_set_multicast_list(struct net_device *dev)
@@ -906,8 +898,7 @@
 	int base = 0, irq = 0, iobase = 0, memlen = 0;
 	ibmlana_priv *priv;
 	ibmlana_medium medium;
-
-	SET_MODULE_OWNER(dev);
+	DECLARE_MAC_BUF(mac);
 
 	/* can't work without an MCA bus ;-) */
 	if (MCA_bus == 0)
@@ -980,7 +971,6 @@
 	dev->stop = ibmlana_close;
 	dev->hard_start_xmit = ibmlana_tx;
 	dev->do_ioctl = NULL;
-	dev->get_stats = ibmlana_stats;
 	dev->set_multicast_list = ibmlana_set_multicast_list;
 	dev->flags |= IFF_MULTICAST;
 
@@ -992,11 +982,10 @@
 	/* print config */
 
 	printk(KERN_INFO "%s: IRQ %d, I/O %#lx, memory %#lx-%#lx, "
-	       "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n",
+	       "MAC address %s.\n",
 	       dev->name, priv->realirq, dev->base_addr,
 	       dev->mem_start, dev->mem_end - 1,
-	       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-	       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+	       print_mac(mac, dev->dev_addr));
 	printk(KERN_INFO "%s: %s medium\n", dev->name, MediaNames[priv->medium]);
 
 	/* reset board */
diff --git a/drivers/net/ibmlana.h b/drivers/net/ibmlana.h
index 6b58bab..aa3ddbd 100644
--- a/drivers/net/ibmlana.h
+++ b/drivers/net/ibmlana.h
@@ -26,7 +26,6 @@
 
 typedef struct {
 	unsigned int slot;		/* MCA-Slot-#                       */
-	struct net_device_stats stat;	/* packet statistics            */
 	int realirq;			/* memorizes actual IRQ, even when
 					   currently not allocated          */
 	ibmlana_medium medium;		/* physical cannector               */
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index d96eb72..7d7758f 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -28,7 +28,6 @@
 /**************************************************************************/
 /*
   TODO:
-  - remove frag processing code - no longer needed
   - add support for sysfs
   - possibly remove procfs support
 */
@@ -47,6 +46,9 @@
 #include <linux/mm.h>
 #include <linux/ethtool.h>
 #include <linux/proc_fs.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <net/net_namespace.h>
 #include <asm/semaphore.h>
 #include <asm/hvcall.h>
 #include <asm/atomic.h>
@@ -83,9 +85,8 @@
 static int ibmveth_open(struct net_device *dev);
 static int ibmveth_close(struct net_device *dev);
 static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-static int ibmveth_poll(struct net_device *dev, int *budget);
+static int ibmveth_poll(struct napi_struct *napi, int budget);
 static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *ibmveth_get_stats(struct net_device *dev);
 static void ibmveth_set_multicast_list(struct net_device *dev);
 static int ibmveth_change_mtu(struct net_device *dev, int new_mtu);
 static void ibmveth_proc_register_driver(void);
@@ -97,7 +98,7 @@
 static struct kobj_type ktype_veth_pool;
 
 #ifdef CONFIG_PROC_FS
-#define IBMVETH_PROC_DIR "net/ibmveth"
+#define IBMVETH_PROC_DIR "ibmveth"
 static struct proc_dir_entry *ibmveth_proc_dir;
 #endif
 
@@ -110,20 +111,49 @@
 MODULE_LICENSE("GPL");
 MODULE_VERSION(ibmveth_driver_version);
 
+struct ibmveth_stat {
+	char name[ETH_GSTRING_LEN];
+	int offset;
+};
+
+#define IBMVETH_STAT_OFF(stat) offsetof(struct ibmveth_adapter, stat)
+#define IBMVETH_GET_STAT(a, off) *((u64 *)(((unsigned long)(a)) + off))
+
+struct ibmveth_stat ibmveth_stats[] = {
+	{ "replenish_task_cycles", IBMVETH_STAT_OFF(replenish_task_cycles) },
+	{ "replenish_no_mem", IBMVETH_STAT_OFF(replenish_no_mem) },
+	{ "replenish_add_buff_failure", IBMVETH_STAT_OFF(replenish_add_buff_failure) },
+	{ "replenish_add_buff_success", IBMVETH_STAT_OFF(replenish_add_buff_success) },
+	{ "rx_invalid_buffer", IBMVETH_STAT_OFF(rx_invalid_buffer) },
+	{ "rx_no_buffer", IBMVETH_STAT_OFF(rx_no_buffer) },
+	{ "tx_map_failed", IBMVETH_STAT_OFF(tx_map_failed) },
+	{ "tx_send_failed", IBMVETH_STAT_OFF(tx_send_failed) },
+};
+
 /* simple methods of getting data from the current rxq entry */
+static inline u32 ibmveth_rxq_flags(struct ibmveth_adapter *adapter)
+{
+	return adapter->rx_queue.queue_addr[adapter->rx_queue.index].flags_off;
+}
+
+static inline int ibmveth_rxq_toggle(struct ibmveth_adapter *adapter)
+{
+	return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_TOGGLE) >> IBMVETH_RXQ_TOGGLE_SHIFT;
+}
+
 static inline int ibmveth_rxq_pending_buffer(struct ibmveth_adapter *adapter)
 {
-	return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].toggle == adapter->rx_queue.toggle);
+	return (ibmveth_rxq_toggle(adapter) == adapter->rx_queue.toggle);
 }
 
 static inline int ibmveth_rxq_buffer_valid(struct ibmveth_adapter *adapter)
 {
-	return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].valid);
+	return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_VALID);
 }
 
 static inline int ibmveth_rxq_frame_offset(struct ibmveth_adapter *adapter)
 {
-	return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].offset);
+	return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_OFF_MASK);
 }
 
 static inline int ibmveth_rxq_frame_length(struct ibmveth_adapter *adapter)
@@ -131,6 +161,11 @@
 	return (adapter->rx_queue.queue_addr[adapter->rx_queue.index].length);
 }
 
+static inline int ibmveth_rxq_csum_good(struct ibmveth_adapter *adapter)
+{
+	return (ibmveth_rxq_flags(adapter) & IBMVETH_RXQ_CSUM_GOOD);
+}
+
 /* setup the initial settings for a buffer pool */
 static void ibmveth_init_buffer_pool(struct ibmveth_buff_pool *pool, u32 pool_index, u32 pool_size, u32 buff_size, u32 pool_active)
 {
@@ -228,9 +263,7 @@
 		correlator = ((u64)pool->index << 32) | index;
 		*(u64*)skb->data = correlator;
 
-		desc.desc = 0;
-		desc.fields.valid = 1;
-		desc.fields.length = pool->buff_size;
+		desc.fields.flags_len = IBMVETH_BUF_VALID | pool->buff_size;
 		desc.fields.address = dma_addr;
 
 		lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc);
@@ -371,9 +404,8 @@
 		return;
 	}
 
-	desc.desc = 0;
-	desc.fields.valid = 1;
-	desc.fields.length = adapter->rx_buff_pool[pool].buff_size;
+	desc.fields.flags_len = IBMVETH_BUF_VALID |
+		adapter->rx_buff_pool[pool].buff_size;
 	desc.fields.address = adapter->rx_buff_pool[pool].dma_addr[index];
 
 	lpar_rc = h_add_logical_lan_buffer(adapter->vdev->unit_address, desc.desc);
@@ -480,6 +512,8 @@
 
 	ibmveth_debug_printk("open starting\n");
 
+	napi_enable(&adapter->napi);
+
 	for(i = 0; i<IbmVethNumBufferPools; i++)
 		rxq_entries += adapter->rx_buff_pool[i].size;
 
@@ -489,6 +523,7 @@
 	if(!adapter->buffer_list_addr || !adapter->filter_list_addr) {
 		ibmveth_error_printk("unable to allocate filter or buffer list pages\n");
 		ibmveth_cleanup(adapter);
+		napi_disable(&adapter->napi);
 		return -ENOMEM;
 	}
 
@@ -498,6 +533,7 @@
 	if(!adapter->rx_queue.queue_addr) {
 		ibmveth_error_printk("unable to allocate rx queue pages\n");
 		ibmveth_cleanup(adapter);
+		napi_disable(&adapter->napi);
 		return -ENOMEM;
 	}
 
@@ -514,6 +550,7 @@
 	   (dma_mapping_error(adapter->rx_queue.queue_dma))) {
 		ibmveth_error_printk("unable to map filter or buffer list pages\n");
 		ibmveth_cleanup(adapter);
+		napi_disable(&adapter->napi);
 		return -ENOMEM;
 	}
 
@@ -524,9 +561,7 @@
 	memcpy(&mac_address, netdev->dev_addr, netdev->addr_len);
 	mac_address = mac_address >> 16;
 
-	rxq_desc.desc = 0;
-	rxq_desc.fields.valid = 1;
-	rxq_desc.fields.length = adapter->rx_queue.queue_len;
+	rxq_desc.fields.flags_len = IBMVETH_BUF_VALID | adapter->rx_queue.queue_len;
 	rxq_desc.fields.address = adapter->rx_queue.queue_dma;
 
 	ibmveth_debug_printk("buffer list @ 0x%p\n", adapter->buffer_list_addr);
@@ -545,6 +580,7 @@
 				     rxq_desc.desc,
 				     mac_address);
 		ibmveth_cleanup(adapter);
+		napi_disable(&adapter->napi);
 		return -ENONET;
 	}
 
@@ -555,6 +591,7 @@
 			ibmveth_error_printk("unable to alloc pool\n");
 			adapter->rx_buff_pool[i].active = 0;
 			ibmveth_cleanup(adapter);
+			napi_disable(&adapter->napi);
 			return -ENOMEM ;
 		}
 	}
@@ -567,6 +604,7 @@
 		} while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY));
 
 		ibmveth_cleanup(adapter);
+		napi_disable(&adapter->napi);
 		return rc;
 	}
 
@@ -587,6 +625,8 @@
 
 	ibmveth_debug_printk("close starting\n");
 
+	napi_disable(&adapter->napi);
+
 	if (!adapter->pool_config)
 		netif_stop_queue(netdev);
 
@@ -634,12 +674,164 @@
 	return 1;
 }
 
+static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data)
+{
+	struct ibmveth_adapter *adapter = dev->priv;
+
+	if (data)
+		adapter->rx_csum = 1;
+	else {
+		/*
+		 * Since the ibmveth firmware interface does not have the concept of
+		 * separate tx/rx checksum offload enable, if rx checksum is disabled
+		 * we also have to disable tx checksum offload. Once we disable rx
+		 * checksum offload, we are no longer allowed to send tx buffers that
+		 * are not properly checksummed.
+		 */
+		adapter->rx_csum = 0;
+		dev->features &= ~NETIF_F_IP_CSUM;
+	}
+}
+
+static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data)
+{
+	struct ibmveth_adapter *adapter = dev->priv;
+
+	if (data) {
+		dev->features |= NETIF_F_IP_CSUM;
+		adapter->rx_csum = 1;
+	} else
+		dev->features &= ~NETIF_F_IP_CSUM;
+}
+
+static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
+				    void (*done) (struct net_device *, u32))
+{
+	struct ibmveth_adapter *adapter = dev->priv;
+	u64 set_attr, clr_attr, ret_attr;
+	long ret;
+	int rc1 = 0, rc2 = 0;
+	int restart = 0;
+
+	if (netif_running(dev)) {
+		restart = 1;
+		adapter->pool_config = 1;
+		ibmveth_close(dev);
+		adapter->pool_config = 0;
+	}
+
+	set_attr = 0;
+	clr_attr = 0;
+
+	if (data)
+		set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
+	else
+		clr_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
+
+	ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr);
+
+	if (ret == H_SUCCESS && !(ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK) &&
+	    !(ret_attr & IBMVETH_ILLAN_TRUNK_PRI_MASK) &&
+	    (ret_attr & IBMVETH_ILLAN_PADDED_PKT_CSUM)) {
+		ret = h_illan_attributes(adapter->vdev->unit_address, clr_attr,
+					 set_attr, &ret_attr);
+
+		if (ret != H_SUCCESS) {
+			rc1 = -EIO;
+			ibmveth_error_printk("unable to change checksum offload settings."
+					     " %d rc=%ld\n", data, ret);
+
+			ret = h_illan_attributes(adapter->vdev->unit_address,
+						 set_attr, clr_attr, &ret_attr);
+		} else
+			done(dev, data);
+	} else {
+		rc1 = -EIO;
+		ibmveth_error_printk("unable to change checksum offload settings."
+				     " %d rc=%ld ret_attr=%lx\n", data, ret, ret_attr);
+	}
+
+	if (restart)
+		rc2 = ibmveth_open(dev);
+
+	return rc1 ? rc1 : rc2;
+}
+
+static int ibmveth_set_rx_csum(struct net_device *dev, u32 data)
+{
+	struct ibmveth_adapter *adapter = dev->priv;
+
+	if ((data && adapter->rx_csum) || (!data && !adapter->rx_csum))
+		return 0;
+
+	return ibmveth_set_csum_offload(dev, data, ibmveth_set_rx_csum_flags);
+}
+
+static int ibmveth_set_tx_csum(struct net_device *dev, u32 data)
+{
+	struct ibmveth_adapter *adapter = dev->priv;
+	int rc = 0;
+
+	if (data && (dev->features & NETIF_F_IP_CSUM))
+		return 0;
+	if (!data && !(dev->features & NETIF_F_IP_CSUM))
+		return 0;
+
+	if (data && !adapter->rx_csum)
+		rc = ibmveth_set_csum_offload(dev, data, ibmveth_set_tx_csum_flags);
+	else
+		ibmveth_set_tx_csum_flags(dev, data);
+
+	return rc;
+}
+
+static u32 ibmveth_get_rx_csum(struct net_device *dev)
+{
+	struct ibmveth_adapter *adapter = dev->priv;
+	return adapter->rx_csum;
+}
+
+static void ibmveth_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+	int i;
+
+	if (stringset != ETH_SS_STATS)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(ibmveth_stats); i++, data += ETH_GSTRING_LEN)
+		memcpy(data, ibmveth_stats[i].name, ETH_GSTRING_LEN);
+}
+
+static int ibmveth_get_sset_count(struct net_device *dev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_STATS:
+		return ARRAY_SIZE(ibmveth_stats);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static void ibmveth_get_ethtool_stats(struct net_device *dev,
+				      struct ethtool_stats *stats, u64 *data)
+{
+	int i;
+	struct ibmveth_adapter *adapter = dev->priv;
+
+	for (i = 0; i < ARRAY_SIZE(ibmveth_stats); i++)
+		data[i] = IBMVETH_GET_STAT(adapter, ibmveth_stats[i].offset);
+}
+
 static const struct ethtool_ops netdev_ethtool_ops = {
 	.get_drvinfo		= netdev_get_drvinfo,
 	.get_settings		= netdev_get_settings,
 	.get_link		= netdev_get_link,
-	.get_sg			= ethtool_op_get_sg,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
+	.set_tx_csum		= ibmveth_set_tx_csum,
+	.get_rx_csum		= ibmveth_get_rx_csum,
+	.set_rx_csum		= ibmveth_set_rx_csum,
+	.get_strings		= ibmveth_get_strings,
+	.get_sset_count		= ibmveth_get_sset_count,
+	.get_ethtool_stats	= ibmveth_get_ethtool_stats,
 };
 
 static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -652,9 +844,8 @@
 static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct ibmveth_adapter *adapter = netdev->priv;
-	union ibmveth_buf_desc desc[IbmVethMaxSendFrags];
+	union ibmveth_buf_desc desc;
 	unsigned long lpar_rc;
-	int nfrags = 0, curfrag;
 	unsigned long correlator;
 	unsigned long flags;
 	unsigned int retry_count;
@@ -664,83 +855,48 @@
 	unsigned int tx_send_failed = 0;
 	unsigned int tx_map_failed = 0;
 
+	desc.fields.flags_len = IBMVETH_BUF_VALID | skb->len;
+	desc.fields.address = dma_map_single(&adapter->vdev->dev, skb->data,
+					     skb->len, DMA_TO_DEVICE);
 
-	if ((skb_shinfo(skb)->nr_frags + 1) > IbmVethMaxSendFrags) {
+	if (skb->ip_summed == CHECKSUM_PARTIAL &&
+	    ip_hdr(skb)->protocol != IPPROTO_TCP && skb_checksum_help(skb)) {
+		ibmveth_error_printk("tx: failed to checksum packet\n");
 		tx_dropped++;
 		goto out;
 	}
 
-	memset(&desc, 0, sizeof(desc));
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		unsigned char *buf = skb_transport_header(skb) + skb->csum_offset;
 
-	/* nfrags = number of frags after the initial fragment */
-	nfrags = skb_shinfo(skb)->nr_frags;
+		desc.fields.flags_len |= (IBMVETH_BUF_NO_CSUM | IBMVETH_BUF_CSUM_GOOD);
 
-	if(nfrags)
-		adapter->tx_multidesc_send++;
+		/* Need to zero out the checksum */
+		buf[0] = 0;
+		buf[1] = 0;
+	}
 
-	/* map the initial fragment */
-	desc[0].fields.length  = nfrags ? skb->len - skb->data_len : skb->len;
-	desc[0].fields.address = dma_map_single(&adapter->vdev->dev, skb->data,
-					desc[0].fields.length, DMA_TO_DEVICE);
-	desc[0].fields.valid   = 1;
-
-	if(dma_mapping_error(desc[0].fields.address)) {
-		ibmveth_error_printk("tx: unable to map initial fragment\n");
+	if (dma_mapping_error(desc.fields.address)) {
+		ibmveth_error_printk("tx: unable to map xmit buffer\n");
 		tx_map_failed++;
 		tx_dropped++;
 		goto out;
 	}
 
-	curfrag = nfrags;
-
-	/* map fragments past the initial portion if there are any */
-	while(curfrag--) {
-		skb_frag_t *frag = &skb_shinfo(skb)->frags[curfrag];
-		desc[curfrag+1].fields.address
-			= dma_map_single(&adapter->vdev->dev,
-				page_address(frag->page) + frag->page_offset,
-				frag->size, DMA_TO_DEVICE);
-		desc[curfrag+1].fields.length = frag->size;
-		desc[curfrag+1].fields.valid  = 1;
-
-		if(dma_mapping_error(desc[curfrag+1].fields.address)) {
-			ibmveth_error_printk("tx: unable to map fragment %d\n", curfrag);
-			tx_map_failed++;
-			tx_dropped++;
-			/* Free all the mappings we just created */
-			while(curfrag < nfrags) {
-				dma_unmap_single(&adapter->vdev->dev,
-						 desc[curfrag+1].fields.address,
-						 desc[curfrag+1].fields.length,
-						 DMA_TO_DEVICE);
-				curfrag++;
-			}
-			goto out;
-		}
-	}
-
 	/* send the frame. Arbitrarily set retrycount to 1024 */
 	correlator = 0;
 	retry_count = 1024;
 	do {
 		lpar_rc = h_send_logical_lan(adapter->vdev->unit_address,
-					     desc[0].desc,
-					     desc[1].desc,
-					     desc[2].desc,
-					     desc[3].desc,
-					     desc[4].desc,
-					     desc[5].desc,
-					     correlator,
-					     &correlator);
+					     desc.desc, 0, 0, 0, 0, 0,
+					     correlator, &correlator);
 	} while ((lpar_rc == H_BUSY) && (retry_count--));
 
 	if(lpar_rc != H_SUCCESS && lpar_rc != H_DROPPED) {
-		int i;
 		ibmveth_error_printk("tx: h_send_logical_lan failed with rc=%ld\n", lpar_rc);
-		for(i = 0; i < 6; i++) {
-			ibmveth_error_printk("tx: desc[%i] valid=%d, len=%d, address=0x%d\n", i,
-					     desc[i].fields.valid, desc[i].fields.length, desc[i].fields.address);
-		}
+		ibmveth_error_printk("tx: valid=%d, len=%d, address=0x%08x\n",
+				     (desc.fields.flags_len & IBMVETH_BUF_VALID) ? 1 : 0,
+				     skb->len, desc.fields.address);
 		tx_send_failed++;
 		tx_dropped++;
 	} else {
@@ -749,16 +905,13 @@
 		netdev->trans_start = jiffies;
 	}
 
-	do {
-		dma_unmap_single(&adapter->vdev->dev,
-				desc[nfrags].fields.address,
-				desc[nfrags].fields.length, DMA_TO_DEVICE);
-	} while(--nfrags >= 0);
+	dma_unmap_single(&adapter->vdev->dev, desc.fields.address,
+			 skb->len, DMA_TO_DEVICE);
 
 out:	spin_lock_irqsave(&adapter->stats_lock, flags);
-	adapter->stats.tx_dropped += tx_dropped;
-	adapter->stats.tx_bytes += tx_bytes;
-	adapter->stats.tx_packets += tx_packets;
+	netdev->stats.tx_dropped += tx_dropped;
+	netdev->stats.tx_bytes += tx_bytes;
+	netdev->stats.tx_packets += tx_packets;
 	adapter->tx_send_failed += tx_send_failed;
 	adapter->tx_map_failed += tx_map_failed;
 	spin_unlock_irqrestore(&adapter->stats_lock, flags);
@@ -767,80 +920,72 @@
 	return 0;
 }
 
-static int ibmveth_poll(struct net_device *netdev, int *budget)
+static int ibmveth_poll(struct napi_struct *napi, int budget)
 {
-	struct ibmveth_adapter *adapter = netdev->priv;
-	int max_frames_to_process = netdev->quota;
+	struct ibmveth_adapter *adapter = container_of(napi, struct ibmveth_adapter, napi);
+	struct net_device *netdev = adapter->netdev;
 	int frames_processed = 0;
-	int more_work = 1;
 	unsigned long lpar_rc;
 
  restart_poll:
 	do {
-		struct net_device *netdev = adapter->netdev;
+		struct sk_buff *skb;
 
-		if(ibmveth_rxq_pending_buffer(adapter)) {
-			struct sk_buff *skb;
+		if (!ibmveth_rxq_pending_buffer(adapter))
+			break;
 
-			rmb();
-
-			if(!ibmveth_rxq_buffer_valid(adapter)) {
-				wmb(); /* suggested by larson1 */
-				adapter->rx_invalid_buffer++;
-				ibmveth_debug_printk("recycling invalid buffer\n");
-				ibmveth_rxq_recycle_buffer(adapter);
-			} else {
-				int length = ibmveth_rxq_frame_length(adapter);
-				int offset = ibmveth_rxq_frame_offset(adapter);
-				skb = ibmveth_rxq_get_buffer(adapter);
-
-				ibmveth_rxq_harvest_buffer(adapter);
-
-				skb_reserve(skb, offset);
-				skb_put(skb, length);
-				skb->protocol = eth_type_trans(skb, netdev);
-
-				netif_receive_skb(skb);	/* send it up */
-
-				adapter->stats.rx_packets++;
-				adapter->stats.rx_bytes += length;
-				frames_processed++;
-				netdev->last_rx = jiffies;
-			}
+		rmb();
+		if (!ibmveth_rxq_buffer_valid(adapter)) {
+			wmb(); /* suggested by larson1 */
+			adapter->rx_invalid_buffer++;
+			ibmveth_debug_printk("recycling invalid buffer\n");
+			ibmveth_rxq_recycle_buffer(adapter);
 		} else {
-			more_work = 0;
+			int length = ibmveth_rxq_frame_length(adapter);
+			int offset = ibmveth_rxq_frame_offset(adapter);
+			int csum_good = ibmveth_rxq_csum_good(adapter);
+
+			skb = ibmveth_rxq_get_buffer(adapter);
+			if (csum_good)
+				skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+			ibmveth_rxq_harvest_buffer(adapter);
+
+			skb_reserve(skb, offset);
+			skb_put(skb, length);
+			skb->protocol = eth_type_trans(skb, netdev);
+
+			netif_receive_skb(skb);	/* send it up */
+
+			netdev->stats.rx_packets++;
+			netdev->stats.rx_bytes += length;
+			frames_processed++;
+			netdev->last_rx = jiffies;
 		}
-	} while(more_work && (frames_processed < max_frames_to_process));
+	} while (frames_processed < budget);
 
 	ibmveth_replenish_task(adapter);
 
-	if(more_work) {
-		/* more work to do - return that we are not done yet */
-		netdev->quota -= frames_processed;
-		*budget -= frames_processed;
-		return 1;
-	}
+	if (frames_processed < budget) {
+		/* We think we are done - reenable interrupts,
+		 * then check once more to make sure we are done.
+		 */
+		lpar_rc = h_vio_signal(adapter->vdev->unit_address,
+				       VIO_IRQ_ENABLE);
 
-	/* we think we are done - reenable interrupts, then check once more to make sure we are done */
-	lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_ENABLE);
-
-	ibmveth_assert(lpar_rc == H_SUCCESS);
-
-	netif_rx_complete(netdev);
-
-	if(ibmveth_rxq_pending_buffer(adapter) && netif_rx_reschedule(netdev, frames_processed))
-	{
-		lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE);
 		ibmveth_assert(lpar_rc == H_SUCCESS);
-		more_work = 1;
-		goto restart_poll;
+
+		netif_rx_complete(netdev, napi);
+
+		if (ibmveth_rxq_pending_buffer(adapter) &&
+		    netif_rx_reschedule(netdev, napi)) {
+			lpar_rc = h_vio_signal(adapter->vdev->unit_address,
+					       VIO_IRQ_DISABLE);
+			goto restart_poll;
+		}
 	}
 
-	netdev->quota -= frames_processed;
-	*budget -= frames_processed;
-
-	/* we really are done */
-	return 0;
+	return frames_processed;
 }
 
 static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance)
@@ -849,20 +994,15 @@
 	struct ibmveth_adapter *adapter = netdev->priv;
 	unsigned long lpar_rc;
 
-	if(netif_rx_schedule_prep(netdev)) {
-		lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE);
+	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+		lpar_rc = h_vio_signal(adapter->vdev->unit_address,
+				       VIO_IRQ_DISABLE);
 		ibmveth_assert(lpar_rc == H_SUCCESS);
-		__netif_rx_schedule(netdev);
+		__netif_rx_schedule(netdev, &adapter->napi);
 	}
 	return IRQ_HANDLED;
 }
 
-static struct net_device_stats *ibmveth_get_stats(struct net_device *dev)
-{
-	struct ibmveth_adapter *adapter = dev->priv;
-	return &adapter->stats;
-}
-
 static void ibmveth_set_multicast_list(struct net_device *netdev)
 {
 	struct ibmveth_adapter *adapter = netdev->priv;
@@ -962,8 +1102,10 @@
 static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
 {
 	int rc, i;
+	long ret;
 	struct net_device *netdev;
-	struct ibmveth_adapter *adapter = NULL;
+	struct ibmveth_adapter *adapter;
+	u64 set_attr, ret_attr;
 
 	unsigned char *mac_addr_p;
 	unsigned int *mcastFilterSize_p;
@@ -994,10 +1136,7 @@
 	if(!netdev)
 		return -ENOMEM;
 
-	SET_MODULE_OWNER(netdev);
-
 	adapter = netdev->priv;
-	memset(adapter, 0, sizeof(adapter));
 	dev->dev.driver_data = netdev;
 
 	adapter->vdev = dev;
@@ -1005,6 +1144,8 @@
 	adapter->mcastFilterSize= *mcastFilterSize_p;
 	adapter->pool_config = 0;
 
+	netif_napi_add(netdev, &adapter->napi, ibmveth_poll, 16);
+
 	/* 	Some older boxes running PHYP non-natively have an OF that
 		returns a 8-byte local-mac-address field (and the first
 		2 bytes have to be ignored) while newer boxes' OF return
@@ -1021,11 +1162,8 @@
 
 	netdev->irq = dev->irq;
 	netdev->open               = ibmveth_open;
-	netdev->poll               = ibmveth_poll;
-	netdev->weight             = 16;
 	netdev->stop               = ibmveth_close;
 	netdev->hard_start_xmit    = ibmveth_start_xmit;
-	netdev->get_stats          = ibmveth_get_stats;
 	netdev->set_multicast_list = ibmveth_set_multicast_list;
 	netdev->do_ioctl           = ibmveth_ioctl;
 	netdev->ethtool_ops           = &netdev_ethtool_ops;
@@ -1045,7 +1183,7 @@
 					 pool_count[i], pool_size[i],
 					 pool_active[i]);
 		kobj->parent = &dev->dev.kobj;
-		sprintf(kobj->name, "pool%d", i);
+		kobject_set_name(kobj, "pool%d", i);
 		kobj->ktype = &ktype_veth_pool;
 		kobject_register(kobj);
 	}
@@ -1058,6 +1196,22 @@
 
 	ibmveth_debug_printk("registering netdev...\n");
 
+	ret = h_illan_attributes(dev->unit_address, 0, 0, &ret_attr);
+
+	if (ret == H_SUCCESS && !(ret_attr & IBMVETH_ILLAN_ACTIVE_TRUNK) &&
+	    !(ret_attr & IBMVETH_ILLAN_TRUNK_PRI_MASK) &&
+	    (ret_attr & IBMVETH_ILLAN_PADDED_PKT_CSUM)) {
+		set_attr = IBMVETH_ILLAN_IPV4_TCP_CSUM;
+
+		ret = h_illan_attributes(dev->unit_address, 0, set_attr, &ret_attr);
+
+		if (ret == H_SUCCESS) {
+			adapter->rx_csum = 1;
+			netdev->features |= NETIF_F_IP_CSUM;
+		} else
+			ret = h_illan_attributes(dev->unit_address, set_attr, 0, &ret_attr);
+	}
+
 	rc = register_netdev(netdev);
 
 	if(rc) {
@@ -1093,15 +1247,14 @@
 #ifdef CONFIG_PROC_FS
 static void ibmveth_proc_register_driver(void)
 {
-	ibmveth_proc_dir = proc_mkdir(IBMVETH_PROC_DIR, NULL);
+	ibmveth_proc_dir = proc_mkdir(IBMVETH_PROC_DIR, init_net.proc_net);
 	if (ibmveth_proc_dir) {
-		SET_MODULE_OWNER(ibmveth_proc_dir);
 	}
 }
 
 static void ibmveth_proc_unregister_driver(void)
 {
-	remove_proc_entry(IBMVETH_PROC_DIR, NULL);
+	remove_proc_entry(IBMVETH_PROC_DIR, init_net.proc_net);
 }
 
 static void *ibmveth_seq_start(struct seq_file *seq, loff_t *pos)
@@ -1128,22 +1281,16 @@
 	struct ibmveth_adapter *adapter = seq->private;
 	char *current_mac = ((char*) &adapter->netdev->dev_addr);
 	char *firmware_mac = ((char*) &adapter->mac_addr) ;
+	DECLARE_MAC_BUF(mac);
 
 	seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version);
 
 	seq_printf(seq, "Unit Address:    0x%x\n", adapter->vdev->unit_address);
-	seq_printf(seq, "Current MAC:     %02X:%02X:%02X:%02X:%02X:%02X\n",
-		   current_mac[0], current_mac[1], current_mac[2],
-		   current_mac[3], current_mac[4], current_mac[5]);
-	seq_printf(seq, "Firmware MAC:    %02X:%02X:%02X:%02X:%02X:%02X\n",
-		   firmware_mac[0], firmware_mac[1], firmware_mac[2],
-		   firmware_mac[3], firmware_mac[4], firmware_mac[5]);
+	seq_printf(seq, "Current MAC:     %s\n", print_mac(mac, current_mac));
+	seq_printf(seq, "Firmware MAC:    %s\n", print_mac(mac, firmware_mac));
 
 	seq_printf(seq, "\nAdapter Statistics:\n");
-	seq_printf(seq, "  TX:  skbuffs linearized:          %ld\n", adapter->tx_linearized);
-	seq_printf(seq, "       multi-descriptor sends:      %ld\n", adapter->tx_multidesc_send);
-	seq_printf(seq, "       skb_linearize failures:      %ld\n", adapter->tx_linearize_failed);
-	seq_printf(seq, "       vio_map_single failres:      %ld\n", adapter->tx_map_failed);
+	seq_printf(seq, "  TX:  vio_map_single failres:      %ld\n", adapter->tx_map_failed);
 	seq_printf(seq, "       send failures:               %ld\n", adapter->tx_send_failed);
 	seq_printf(seq, "  RX:  replenish task cycles:       %ld\n", adapter->replenish_task_cycles);
 	seq_printf(seq, "       alloc_skb_failures:          %ld\n", adapter->replenish_no_mem);
@@ -1196,7 +1343,6 @@
 		} else {
 			entry->data = (void *) adapter;
 			entry->proc_fops = &ibmveth_proc_fops;
-			SET_MODULE_OWNER(entry);
 		}
 	}
 	return;
@@ -1280,24 +1426,28 @@
 			int i;
 			/* Make sure there is a buffer pool with buffers that
 			   can hold a packet of the size of the MTU */
-			for(i = 0; i<IbmVethNumBufferPools; i++) {
+			for (i = 0; i < IbmVethNumBufferPools; i++) {
 				if (pool == &adapter->rx_buff_pool[i])
 					continue;
 				if (!adapter->rx_buff_pool[i].active)
 					continue;
-				if (mtu < adapter->rx_buff_pool[i].buff_size) {
-					pool->active = 0;
-					h_free_logical_lan_buffer(adapter->
-								  vdev->
-								  unit_address,
-								  pool->
-								  buff_size);
-				}
+				if (mtu <= adapter->rx_buff_pool[i].buff_size)
+					break;
 			}
-			if (pool->active) {
+
+			if (i == IbmVethNumBufferPools) {
 				ibmveth_error_printk("no active pool >= MTU\n");
 				return -EPERM;
 			}
+
+			pool->active = 0;
+			if (netif_running(netdev)) {
+				adapter->pool_config = 1;
+				ibmveth_close(netdev);
+				adapter->pool_config = 0;
+				if ((rc = ibmveth_open(netdev)))
+					return rc;
+			}
 		}
 	} else if (attr == &veth_num_attr) {
 		if (value <= 0 || value > IBMVETH_MAX_POOL_COUNT)
diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h
index bb69cca..41f61cd 100644
--- a/drivers/net/ibmveth.h
+++ b/drivers/net/ibmveth.h
@@ -25,8 +25,6 @@
 #ifndef _IBMVETH_H
 #define _IBMVETH_H
 
-#define IbmVethMaxSendFrags 6
-
 /* constants for H_MULTICAST_CTRL */
 #define IbmVethMcastReceptionModifyBit     0x80000UL
 #define IbmVethMcastReceptionEnableBit     0x20000UL
@@ -41,6 +39,12 @@
 #define IbmVethMcastRemoveFilter     0x2UL
 #define IbmVethMcastClearFilterTable 0x3UL
 
+#define IBMVETH_ILLAN_PADDED_PKT_CSUM	0x0000000000002000ULL
+#define IBMVETH_ILLAN_TRUNK_PRI_MASK	0x0000000000000F00ULL
+#define IBMVETH_ILLAN_IPV6_TCP_CSUM		0x0000000000000004ULL
+#define IBMVETH_ILLAN_IPV4_TCP_CSUM		0x0000000000000002ULL
+#define IBMVETH_ILLAN_ACTIVE_TRUNK		0x0000000000000001ULL
+
 /* hcall macros */
 #define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \
   plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac)
@@ -67,15 +71,27 @@
 	return rc;
 }
 
+static inline long h_illan_attributes(unsigned long unit_address,
+				      unsigned long reset_mask, unsigned long set_mask,
+				      unsigned long *ret_attributes)
+{
+	long rc;
+	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+
+	rc = plpar_hcall(H_ILLAN_ATTRIBUTES, retbuf, unit_address,
+			 reset_mask, set_mask);
+
+	*ret_attributes = retbuf[0];
+
+	return rc;
+}
+
 #define h_multicast_ctrl(ua, cmd, mac) \
   plpar_hcall_norets(H_MULTICAST_CTRL, ua, cmd, mac)
 
 #define h_change_logical_lan_mac(ua, mac) \
   plpar_hcall_norets(H_CHANGE_LOGICAL_LAN_MAC, ua, mac)
 
-#define h_free_logical_lan_buffer(ua, bufsize) \
-  plpar_hcall_norets(H_FREE_LOGICAL_LAN_BUFFER, ua, bufsize)
-
 #define IbmVethNumBufferPools 5
 #define IBMVETH_BUFF_OH 22 /* Overhead: 14 ethernet header + 8 opaque handle */
 #define IBMVETH_MAX_MTU 68
@@ -115,6 +131,7 @@
 struct ibmveth_adapter {
     struct vio_dev *vdev;
     struct net_device *netdev;
+    struct napi_struct napi;
     struct net_device_stats stats;
     unsigned int mcastFilterSize;
     unsigned long mac_addr;
@@ -125,6 +142,7 @@
     struct ibmveth_buff_pool rx_buff_pool[IbmVethNumBufferPools];
     struct ibmveth_rx_q rx_queue;
     int pool_config;
+    int rx_csum;
 
     /* adapter specific stats */
     u64 replenish_task_cycles;
@@ -133,20 +151,19 @@
     u64 replenish_add_buff_success;
     u64 rx_invalid_buffer;
     u64 rx_no_buffer;
-    u64 tx_multidesc_send;
-    u64 tx_linearized;
-    u64 tx_linearize_failed;
     u64 tx_map_failed;
     u64 tx_send_failed;
     spinlock_t stats_lock;
 };
 
 struct ibmveth_buf_desc_fields {
-    u32 valid : 1;
-    u32 toggle : 1;
-    u32 reserved : 6;
-    u32 length : 24;
-    u32 address;
+	u32 flags_len;
+#define IBMVETH_BUF_VALID	0x80000000
+#define IBMVETH_BUF_TOGGLE	0x40000000
+#define IBMVETH_BUF_NO_CSUM	0x02000000
+#define IBMVETH_BUF_CSUM_GOOD	0x01000000
+#define IBMVETH_BUF_LEN_MASK	0x00FFFFFF
+	u32 address;
 };
 
 union ibmveth_buf_desc {
@@ -155,12 +172,16 @@
 };
 
 struct ibmveth_rx_q_entry {
-    u16 toggle : 1;
-    u16 valid : 1;
-    u16 reserved : 14;
-    u16 offset;
-    u32 length;
-    u64 correlator;
+	u32 flags_off;
+#define IBMVETH_RXQ_TOGGLE		0x80000000
+#define IBMVETH_RXQ_TOGGLE_SHIFT	31
+#define IBMVETH_RXQ_VALID		0x40000000
+#define IBMVETH_RXQ_NO_CSUM		0x02000000
+#define IBMVETH_RXQ_CSUM_GOOD		0x01000000
+#define IBMVETH_RXQ_OFF_MASK		0x0000FFFF
+
+	u32 length;
+	u64 correlator;
 };
 
 #endif /* _IBMVETH_H */
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index f5c3598..15949d3 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -34,12 +34,12 @@
 #include <linux/init.h>
 #include <linux/moduleparam.h>
 #include <net/pkt_sched.h>
+#include <net/net_namespace.h>
 
 #define TX_TIMEOUT  (2*HZ)
 
 #define TX_Q_LIMIT    32
 struct ifb_private {
-	struct net_device_stats stats;
 	struct tasklet_struct   ifb_tasklet;
 	int     tasklet_pending;
 	/* mostly debug stats leave in for now */
@@ -60,7 +60,6 @@
 
 static void ri_tasklet(unsigned long dev);
 static int ifb_xmit(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *ifb_get_stats(struct net_device *dev);
 static int ifb_open(struct net_device *dev);
 static int ifb_close(struct net_device *dev);
 
@@ -69,7 +68,7 @@
 
 	struct net_device *_dev = (struct net_device *)dev;
 	struct ifb_private *dp = netdev_priv(_dev);
-	struct net_device_stats *stats = &dp->stats;
+	struct net_device_stats *stats = &_dev->stats;
 	struct sk_buff *skb;
 
 	dp->st_task_enter++;
@@ -97,7 +96,7 @@
 		stats->tx_packets++;
 		stats->tx_bytes +=skb->len;
 
-		skb->dev = __dev_get_by_index(skb->iif);
+		skb->dev = __dev_get_by_index(&init_net, skb->iif);
 		if (!skb->dev) {
 			dev_kfree_skb(skb);
 			stats->tx_dropped++;
@@ -139,7 +138,6 @@
 static void ifb_setup(struct net_device *dev)
 {
 	/* Initialize the device structure. */
-	dev->get_stats = ifb_get_stats;
 	dev->hard_start_xmit = ifb_xmit;
 	dev->open = &ifb_open;
 	dev->stop = &ifb_close;
@@ -151,14 +149,13 @@
 	dev->change_mtu = NULL;
 	dev->flags |= IFF_NOARP;
 	dev->flags &= ~IFF_MULTICAST;
-	SET_MODULE_OWNER(dev);
 	random_ether_addr(dev->dev_addr);
 }
 
 static int ifb_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct ifb_private *dp = netdev_priv(dev);
-	struct net_device_stats *stats = &dp->stats;
+	struct net_device_stats *stats = &dev->stats;
 	int ret = 0;
 	u32 from = G_TC_FROM(skb->tc_verd);
 
@@ -185,19 +182,6 @@
 	return ret;
 }
 
-static struct net_device_stats *ifb_get_stats(struct net_device *dev)
-{
-	struct ifb_private *dp = netdev_priv(dev);
-	struct net_device_stats *stats = &dp->stats;
-
-	pr_debug("tasklets stats %ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld \n",
-		dp->st_task_enter, dp->st_txq_refl_try, dp->st_rxq_enter,
-		dp->st_rx2tx_tran, dp->st_rxq_notenter, dp->st_rx_frm_egr,
-		dp->st_rx_frm_ing, dp->st_rxq_check, dp->st_rxq_rsch);
-
-	return stats;
-}
-
 static int ifb_close(struct net_device *dev)
 {
 	struct ifb_private *dp = netdev_priv(dev);
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index 3ca1e8e..373f72c 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -5,7 +5,7 @@
  *
  * Driver for SGI's IOC3 based Ethernet cards as found in the PCI card.
  *
- * Copyright (C) 1999, 2000, 2001, 2003 Ralf Baechle
+ * Copyright (C) 1999, 2000, 01, 03, 06 Ralf Baechle
  * Copyright (C) 1995, 1999, 2000, 2001 by Silicon Graphics, Inc.
  *
  * References:
@@ -48,6 +48,7 @@
 #ifdef CONFIG_SERIAL_8250
 #include <linux/serial_core.h>
 #include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
 #endif
 
 #include <linux/netdevice.h>
@@ -61,12 +62,7 @@
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 #include <asm/sn/types.h>
-#include <asm/sn/sn0/addrs.h>
-#include <asm/sn/sn0/hubni.h>
-#include <asm/sn/sn0/hubio.h>
-#include <asm/sn/klconfig.h>
 #include <asm/sn/ioc3.h>
-#include <asm/sn/sn0/ip27.h>
 #include <asm/pci/bridge.h>
 
 /*
@@ -94,6 +90,9 @@
 	u32 emcr, ehar_h, ehar_l;
 	spinlock_t ioc3_lock;
 	struct mii_if_info mii;
+	unsigned long flags;
+#define IOC3_FLAG_RX_CHECKSUMS	1
+
 	struct pci_dev *pdev;
 
 	/* Members used by autonegotiation  */
@@ -444,18 +443,12 @@
  */
 static void ioc3_get_eaddr(struct ioc3_private *ip)
 {
-	int i;
-
+	DECLARE_MAC_BUF(mac);
 
 	ioc3_get_eaddr_nic(ip);
 
-	printk("Ethernet address is ");
-	for (i = 0; i < 6; i++) {
-		printk("%02x", priv_netdev(ip)->dev_addr[i]);
-		if (i < 5)
-			printk(":");
-	}
-	printk(".\n");
+	printk("Ethernet address is %s.\n",
+	       print_mac(mac, priv_netdev(ip)->dev_addr));
 }
 
 static void __ioc3_set_mac_address(struct net_device *dev)
@@ -520,8 +513,6 @@
 	return &ip->stats;
 }
 
-#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM
-
 static void ioc3_tcpudp_checksum(struct sk_buff *skb, uint32_t hwsum, int len)
 {
 	struct ethhdr *eh = eth_hdr(skb);
@@ -589,7 +580,6 @@
 	if (csum == 0xffff)
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 }
-#endif /* CONFIG_SGI_IOC3_ETH_HW_RX_CSUM */
 
 static inline void ioc3_rx(struct ioc3_private *ip)
 {
@@ -624,9 +614,9 @@
 				goto next;
 			}
 
-#ifdef CONFIG_SGI_IOC3_ETH_HW_RX_CSUM
-			ioc3_tcpudp_checksum(skb, w0 & ERXBUF_IPCKSUM_MASK,len);
-#endif
+			if (likely(ip->flags & IOC3_FLAG_RX_CHECKSUMS))
+				ioc3_tcpudp_checksum(skb,
+					w0 & ERXBUF_IPCKSUM_MASK, len);
 
 			netif_rx(skb);
 
@@ -1151,13 +1141,41 @@
  * Also look in ip27-pci.c:pci_fixup_ioc3() for some comments on working
  * around ioc3 oddities in this respect.
  *
- * The IOC3 serials use a 22MHz clock rate with an additional divider by 3.
+ * The IOC3 serials use a 22MHz clock rate with an additional divider which
+ * can be programmed in the SCR register if the DLAB bit is set.
+ *
+ * Register to interrupt zero because we share the interrupt with
+ * the serial driver which we don't properly support yet.
+ *
+ * Can't use UPF_IOREMAP as the whole of IOC3 resources have already been
+ * registered.
  */
+static void __devinit ioc3_8250_register(struct ioc3_uartregs __iomem *uart)
+{
+#define COSMISC_CONSTANT 6
+
+	struct uart_port port = {
+		.irq		= 0,
+		.flags		= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
+		.iotype		= UPIO_MEM,
+		.regshift	= 0,
+		.uartclk	= (22000000 << 1) / COSMISC_CONSTANT,
+
+		.membase	= (unsigned char __iomem *) uart,
+		.mapbase	= (unsigned long) uart,
+	};
+	unsigned char lcr;
+
+	lcr = uart->iu_lcr;
+	uart->iu_lcr = lcr | UART_LCR_DLAB;
+	uart->iu_scr = COSMISC_CONSTANT,
+	uart->iu_lcr = lcr;
+	uart->iu_lcr;
+	serial8250_register_port(&port);
+}
 
 static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)
 {
-	struct uart_port port;
-
 	/*
 	 * We need to recognice and treat the fourth MENET serial as it
 	 * does not have an SuperIO chip attached to it, therefore attempting
@@ -1171,24 +1189,35 @@
 		return;
 
 	/*
-	 * Register to interrupt zero because we share the interrupt with
-	 * the serial driver which we don't properly support yet.
-	 *
-	 * Can't use UPF_IOREMAP as the whole of IOC3 resources have already
-	 * been registered.
+	 * Switch IOC3 to PIO mode.  It probably already was but let's be
+	 * paranoid
 	 */
-	memset(&port, 0, sizeof(port));
-	port.irq      = 0;
-	port.flags    = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
-	port.iotype   = UPIO_MEM;
-	port.regshift = 0;
-	port.uartclk  = 22000000 / 3;
+	ioc3->gpcr_s = GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL;
+	ioc3->gpcr_s;
+	ioc3->gppr_6 = 0;
+	ioc3->gppr_6;
+	ioc3->gppr_7 = 0;
+	ioc3->gppr_7;
+	ioc3->sscr_a = ioc3->sscr_a & ~SSCR_DMA_EN;
+	ioc3->sscr_a;
+	ioc3->sscr_b = ioc3->sscr_b & ~SSCR_DMA_EN;
+	ioc3->sscr_b;
+	/* Disable all SA/B interrupts except for SA/B_INT in SIO_IEC. */
+	ioc3->sio_iec &= ~ (SIO_IR_SA_TX_MT | SIO_IR_SA_RX_FULL |
+			    SIO_IR_SA_RX_HIGH | SIO_IR_SA_RX_TIMER |
+			    SIO_IR_SA_DELTA_DCD | SIO_IR_SA_DELTA_CTS |
+			    SIO_IR_SA_TX_EXPLICIT | SIO_IR_SA_MEMERR);
+	ioc3->sio_iec |= SIO_IR_SA_INT;
+	ioc3->sscr_a = 0;
+	ioc3->sio_iec &= ~ (SIO_IR_SB_TX_MT | SIO_IR_SB_RX_FULL |
+			    SIO_IR_SB_RX_HIGH | SIO_IR_SB_RX_TIMER |
+			    SIO_IR_SB_DELTA_DCD | SIO_IR_SB_DELTA_CTS |
+			    SIO_IR_SB_TX_EXPLICIT | SIO_IR_SB_MEMERR);
+	ioc3->sio_iec |= SIO_IR_SB_INT;
+	ioc3->sscr_b = 0;
 
-	port.membase  = (unsigned char *) &ioc3->sregs.uarta;
-	serial8250_register_port(&port);
-
-	port.membase  = (unsigned char *) &ioc3->sregs.uartb;
-	serial8250_register_port(&port);
+	ioc3_8250_register(&ioc3->sregs.uarta);
+	ioc3_8250_register(&ioc3->sregs.uartb);
 }
 #endif
 
@@ -1238,7 +1267,6 @@
 	if (err)
 		goto out_free;
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	ip = netdev_priv(dev);
@@ -1298,9 +1326,7 @@
 	dev->set_multicast_list	= ioc3_set_multicast_list;
 	dev->set_mac_address	= ioc3_set_mac_address;
 	dev->ethtool_ops	= &ioc3_ethtool_ops;
-#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM
 	dev->features		= NETIF_F_IP_CSUM;
-#endif
 
 	sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1);
 	sw_physid2 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID2);
@@ -1390,7 +1416,6 @@
 	uint32_t w0 = 0;
 	int produce;
 
-#ifdef CONFIG_SGI_IOC3_ETH_HW_TX_CSUM
 	/*
 	 * IOC3 has a fairly simple minded checksumming hardware which simply
 	 * adds up the 1's complement checksum for the entire packet and
@@ -1438,7 +1463,6 @@
 
 		w0 = ETXD_DOCHECKSUM | (csoff << ETXD_CHKOFF_SHIFT);
 	}
-#endif /* CONFIG_SGI_IOC3_ETH_HW_TX_CSUM */
 
 	spin_lock_irq(&ip->ioc3_lock);
 
@@ -1593,12 +1617,37 @@
 	return rc;
 }
 
+static u32 ioc3_get_rx_csum(struct net_device *dev)
+{
+	struct ioc3_private *ip = netdev_priv(dev);
+
+	return ip->flags & IOC3_FLAG_RX_CHECKSUMS;
+}
+
+static int ioc3_set_rx_csum(struct net_device *dev, u32 data)
+{
+	struct ioc3_private *ip = netdev_priv(dev);
+
+	spin_lock_bh(&ip->ioc3_lock);
+	if (data)
+		ip->flags |= IOC3_FLAG_RX_CHECKSUMS;
+	else
+		ip->flags &= ~IOC3_FLAG_RX_CHECKSUMS;
+	spin_unlock_bh(&ip->ioc3_lock);
+
+	return 0;
+}
+
 static const struct ethtool_ops ioc3_ethtool_ops = {
 	.get_drvinfo		= ioc3_get_drvinfo,
 	.get_settings		= ioc3_get_settings,
 	.set_settings		= ioc3_set_settings,
 	.nway_reset		= ioc3_nway_reset,
 	.get_link		= ioc3_get_link,
+	.get_rx_csum		= ioc3_get_rx_csum,
+	.set_rx_csum		= ioc3_set_rx_csum,
+	.get_tx_csum		= ethtool_op_get_tx_csum,
+	.set_tx_csum		= ethtool_op_set_tx_csum
 };
 
 static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c
new file mode 100644
index 0000000..59898ce
--- /dev/null
+++ b/drivers/net/ipg.c
@@ -0,0 +1,2332 @@
+/*
+ * ipg.c: Device Driver for the IP1000 Gigabit Ethernet Adapter
+ *
+ * Copyright (C) 2003, 2007  IC Plus Corp
+ *
+ * Original Author:
+ *
+ *   Craig Rich
+ *   Sundance Technology, Inc.
+ *   www.sundanceti.com
+ *   craig_rich@sundanceti.com
+ *
+ * Current Maintainer:
+ *
+ *   Sorbica Shieh.
+ *   http://www.icplus.com.tw
+ *   sorbica@icplus.com.tw
+ *
+ *   Jesse Huang
+ *   http://www.icplus.com.tw
+ *   jesse@icplus.com.tw
+ */
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/mutex.h>
+
+#include <asm/div64.h>
+
+#define IPG_RX_RING_BYTES	(sizeof(struct ipg_rx) * IPG_RFDLIST_LENGTH)
+#define IPG_TX_RING_BYTES	(sizeof(struct ipg_tx) * IPG_TFDLIST_LENGTH)
+#define IPG_RESET_MASK \
+	(IPG_AC_GLOBAL_RESET | IPG_AC_RX_RESET | IPG_AC_TX_RESET | \
+	 IPG_AC_DMA | IPG_AC_FIFO | IPG_AC_NETWORK | IPG_AC_HOST | \
+	 IPG_AC_AUTO_INIT)
+
+#define ipg_w32(val32,reg)	iowrite32((val32), ioaddr + (reg))
+#define ipg_w16(val16,reg)	iowrite16((val16), ioaddr + (reg))
+#define ipg_w8(val8,reg)	iowrite8((val8), ioaddr + (reg))
+
+#define ipg_r32(reg)		ioread32(ioaddr + (reg))
+#define ipg_r16(reg)		ioread16(ioaddr + (reg))
+#define ipg_r8(reg)		ioread8(ioaddr + (reg))
+
+#define JUMBO_FRAME_4k_ONLY
+enum {
+	netdev_io_size = 128
+};
+
+#include "ipg.h"
+#define DRV_NAME	"ipg"
+
+MODULE_AUTHOR("IC Plus Corp. 2003");
+MODULE_DESCRIPTION("IC Plus IP1000 Gigabit Ethernet Adapter Linux Driver "
+		   DrvVer);
+MODULE_LICENSE("GPL");
+
+static const char *ipg_brand_name[] = {
+	"IC PLUS IP1000 1000/100/10 based NIC",
+	"Sundance Technology ST2021 based NIC",
+	"Tamarack Microelectronics TC9020/9021 based NIC",
+	"Tamarack Microelectronics TC9020/9021 based NIC",
+	"D-Link NIC",
+	"D-Link NIC IP1000A"
+};
+
+static struct pci_device_id ipg_pci_tbl[] __devinitdata = {
+	{ PCI_VDEVICE(SUNDANCE,	0x1023), 0 },
+	{ PCI_VDEVICE(SUNDANCE,	0x2021), 1 },
+	{ PCI_VDEVICE(SUNDANCE,	0x1021), 2 },
+	{ PCI_VDEVICE(DLINK,	0x9021), 3 },
+	{ PCI_VDEVICE(DLINK,	0x4000), 4 },
+	{ PCI_VDEVICE(DLINK,	0x4020), 5 },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, ipg_pci_tbl);
+
+static inline void __iomem *ipg_ioaddr(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	return sp->ioaddr;
+}
+
+#ifdef IPG_DEBUG
+static void ipg_dump_rfdlist(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int i;
+	u32 offset;
+
+	IPG_DEBUG_MSG("_dump_rfdlist\n");
+
+	printk(KERN_INFO "rx_current = %2.2x\n", sp->rx_current);
+	printk(KERN_INFO "rx_dirty   = %2.2x\n", sp->rx_dirty);
+	printk(KERN_INFO "RFDList start address = %16.16lx\n",
+	       (unsigned long) sp->rxd_map);
+	printk(KERN_INFO "RFDListPtr register   = %8.8x%8.8x\n",
+	       ipg_r32(IPG_RFDLISTPTR1), ipg_r32(IPG_RFDLISTPTR0));
+
+	for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
+		offset = (u32) &sp->rxd[i].next_desc - (u32) sp->rxd;
+		printk(KERN_INFO "%2.2x %4.4x RFDNextPtr = %16.16lx\n", i,
+		       offset, (unsigned long) sp->rxd[i].next_desc);
+		offset = (u32) &sp->rxd[i].rfs - (u32) sp->rxd;
+		printk(KERN_INFO "%2.2x %4.4x RFS        = %16.16lx\n", i,
+		       offset, (unsigned long) sp->rxd[i].rfs);
+		offset = (u32) &sp->rxd[i].frag_info - (u32) sp->rxd;
+		printk(KERN_INFO "%2.2x %4.4x frag_info   = %16.16lx\n", i,
+		       offset, (unsigned long) sp->rxd[i].frag_info);
+	}
+}
+
+static void ipg_dump_tfdlist(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int i;
+	u32 offset;
+
+	IPG_DEBUG_MSG("_dump_tfdlist\n");
+
+	printk(KERN_INFO "tx_current         = %2.2x\n", sp->tx_current);
+	printk(KERN_INFO "tx_dirty = %2.2x\n", sp->tx_dirty);
+	printk(KERN_INFO "TFDList start address = %16.16lx\n",
+	       (unsigned long) sp->txd_map);
+	printk(KERN_INFO "TFDListPtr register   = %8.8x%8.8x\n",
+	       ipg_r32(IPG_TFDLISTPTR1), ipg_r32(IPG_TFDLISTPTR0));
+
+	for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
+		offset = (u32) &sp->txd[i].next_desc - (u32) sp->txd;
+		printk(KERN_INFO "%2.2x %4.4x TFDNextPtr = %16.16lx\n", i,
+		       offset, (unsigned long) sp->txd[i].next_desc);
+
+		offset = (u32) &sp->txd[i].tfc - (u32) sp->txd;
+		printk(KERN_INFO "%2.2x %4.4x TFC        = %16.16lx\n", i,
+		       offset, (unsigned long) sp->txd[i].tfc);
+		offset = (u32) &sp->txd[i].frag_info - (u32) sp->txd;
+		printk(KERN_INFO "%2.2x %4.4x frag_info   = %16.16lx\n", i,
+		       offset, (unsigned long) sp->txd[i].frag_info);
+	}
+}
+#endif
+
+static void ipg_write_phy_ctl(void __iomem *ioaddr, u8 data)
+{
+	ipg_w8(IPG_PC_RSVD_MASK & data, PHY_CTRL);
+	ndelay(IPG_PC_PHYCTRLWAIT_NS);
+}
+
+static void ipg_drive_phy_ctl_low_high(void __iomem *ioaddr, u8 data)
+{
+	ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | data);
+	ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | data);
+}
+
+static void send_three_state(void __iomem *ioaddr, u8 phyctrlpolarity)
+{
+	phyctrlpolarity |= (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR;
+
+	ipg_drive_phy_ctl_low_high(ioaddr, phyctrlpolarity);
+}
+
+static void send_end(void __iomem *ioaddr, u8 phyctrlpolarity)
+{
+	ipg_w8((IPG_PC_MGMTCLK_LO | (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR |
+		phyctrlpolarity) & IPG_PC_RSVD_MASK, PHY_CTRL);
+}
+
+static u16 read_phy_bit(void __iomem * ioaddr, u8 phyctrlpolarity)
+{
+	u16 bit_data;
+
+	ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | phyctrlpolarity);
+
+	bit_data = ((ipg_r8(PHY_CTRL) & IPG_PC_MGMTDATA) >> 1) & 1;
+
+	ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | phyctrlpolarity);
+
+	return bit_data;
+}
+
+/*
+ * Read a register from the Physical Layer device located
+ * on the IPG NIC, using the IPG PHYCTRL register.
+ */
+static int mdio_read(struct net_device * dev, int phy_id, int phy_reg)
+{
+	void __iomem *ioaddr = ipg_ioaddr(dev);
+	/*
+	 * The GMII mangement frame structure for a read is as follows:
+	 *
+	 * |Preamble|st|op|phyad|regad|ta|      data      |idle|
+	 * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z   |
+	 *
+	 * <32 1s> = 32 consecutive logic 1 values
+	 * A = bit of Physical Layer device address (MSB first)
+	 * R = bit of register address (MSB first)
+	 * z = High impedance state
+	 * D = bit of read data (MSB first)
+	 *
+	 * Transmission order is 'Preamble' field first, bits transmitted
+	 * left to right (first to last).
+	 */
+	struct {
+		u32 field;
+		unsigned int len;
+	} p[] = {
+		{ GMII_PREAMBLE,	32 },	/* Preamble */
+		{ GMII_ST,		2  },	/* ST */
+		{ GMII_READ,		2  },	/* OP */
+		{ phy_id,		5  },	/* PHYAD */
+		{ phy_reg,		5  },	/* REGAD */
+		{ 0x0000,		2  },	/* TA */
+		{ 0x0000,		16 },	/* DATA */
+		{ 0x0000,		1  }	/* IDLE */
+	};
+	unsigned int i, j;
+	u8 polarity, data;
+
+	polarity  = ipg_r8(PHY_CTRL);
+	polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY);
+
+	/* Create the Preamble, ST, OP, PHYAD, and REGAD field. */
+	for (j = 0; j < 5; j++) {
+		for (i = 0; i < p[j].len; i++) {
+			/* For each variable length field, the MSB must be
+			 * transmitted first. Rotate through the field bits,
+			 * starting with the MSB, and move each bit into the
+			 * the 1st (2^1) bit position (this is the bit position
+			 * corresponding to the MgmtData bit of the PhyCtrl
+			 * register for the IPG).
+			 *
+			 * Example: ST = 01;
+			 *
+			 *          First write a '0' to bit 1 of the PhyCtrl
+			 *          register, then write a '1' to bit 1 of the
+			 *          PhyCtrl register.
+			 *
+			 * To do this, right shift the MSB of ST by the value:
+			 * [field length - 1 - #ST bits already written]
+			 * then left shift this result by 1.
+			 */
+			data  = (p[j].field >> (p[j].len - 1 - i)) << 1;
+			data &= IPG_PC_MGMTDATA;
+			data |= polarity | IPG_PC_MGMTDIR;
+
+			ipg_drive_phy_ctl_low_high(ioaddr, data);
+		}
+	}
+
+	send_three_state(ioaddr, polarity);
+
+	read_phy_bit(ioaddr, polarity);
+
+	/*
+	 * For a read cycle, the bits for the next two fields (TA and
+	 * DATA) are driven by the PHY (the IPG reads these bits).
+	 */
+	for (i = 0; i < p[6].len; i++) {
+		p[6].field |=
+		    (read_phy_bit(ioaddr, polarity) << (p[6].len - 1 - i));
+	}
+
+	send_three_state(ioaddr, polarity);
+	send_three_state(ioaddr, polarity);
+	send_three_state(ioaddr, polarity);
+	send_end(ioaddr, polarity);
+
+	/* Return the value of the DATA field. */
+	return p[6].field;
+}
+
+/*
+ * Write to a register from the Physical Layer device located
+ * on the IPG NIC, using the IPG PHYCTRL register.
+ */
+static void mdio_write(struct net_device *dev, int phy_id, int phy_reg, int val)
+{
+	void __iomem *ioaddr = ipg_ioaddr(dev);
+	/*
+	 * The GMII mangement frame structure for a read is as follows:
+	 *
+	 * |Preamble|st|op|phyad|regad|ta|      data      |idle|
+	 * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z   |
+	 *
+	 * <32 1s> = 32 consecutive logic 1 values
+	 * A = bit of Physical Layer device address (MSB first)
+	 * R = bit of register address (MSB first)
+	 * z = High impedance state
+	 * D = bit of write data (MSB first)
+	 *
+	 * Transmission order is 'Preamble' field first, bits transmitted
+	 * left to right (first to last).
+	 */
+	struct {
+		u32 field;
+		unsigned int len;
+	} p[] = {
+		{ GMII_PREAMBLE,	32 },	/* Preamble */
+		{ GMII_ST,		2  },	/* ST */
+		{ GMII_WRITE,		2  },	/* OP */
+		{ phy_id,		5  },	/* PHYAD */
+		{ phy_reg,		5  },	/* REGAD */
+		{ 0x0002,		2  },	/* TA */
+		{ val & 0xffff,		16 },	/* DATA */
+		{ 0x0000,		1  }	/* IDLE */
+	};
+	unsigned int i, j;
+	u8 polarity, data;
+
+	polarity  = ipg_r8(PHY_CTRL);
+	polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY);
+
+	/* Create the Preamble, ST, OP, PHYAD, and REGAD field. */
+	for (j = 0; j < 7; j++) {
+		for (i = 0; i < p[j].len; i++) {
+			/* For each variable length field, the MSB must be
+			 * transmitted first. Rotate through the field bits,
+			 * starting with the MSB, and move each bit into the
+			 * the 1st (2^1) bit position (this is the bit position
+			 * corresponding to the MgmtData bit of the PhyCtrl
+			 * register for the IPG).
+			 *
+			 * Example: ST = 01;
+			 *
+			 *          First write a '0' to bit 1 of the PhyCtrl
+			 *          register, then write a '1' to bit 1 of the
+			 *          PhyCtrl register.
+			 *
+			 * To do this, right shift the MSB of ST by the value:
+			 * [field length - 1 - #ST bits already written]
+			 * then left shift this result by 1.
+			 */
+			data  = (p[j].field >> (p[j].len - 1 - i)) << 1;
+			data &= IPG_PC_MGMTDATA;
+			data |= polarity | IPG_PC_MGMTDIR;
+
+			ipg_drive_phy_ctl_low_high(ioaddr, data);
+		}
+	}
+
+	/* The last cycle is a tri-state, so read from the PHY. */
+	for (j = 7; j < 8; j++) {
+		for (i = 0; i < p[j].len; i++) {
+			ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | polarity);
+
+			p[j].field |= ((ipg_r8(PHY_CTRL) &
+				IPG_PC_MGMTDATA) >> 1) << (p[j].len - 1 - i);
+
+			ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | polarity);
+		}
+	}
+}
+
+/* Set LED_Mode JES20040127EEPROM */
+static void ipg_set_led_mode(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	u32 mode;
+
+	mode = ipg_r32(ASIC_CTRL);
+	mode &= ~(IPG_AC_LED_MODE_BIT_1 | IPG_AC_LED_MODE | IPG_AC_LED_SPEED);
+
+	if ((sp->LED_Mode & 0x03) > 1)
+		mode |= IPG_AC_LED_MODE_BIT_1;	/* Write Asic Control Bit 29 */
+
+	if ((sp->LED_Mode & 0x01) == 1)
+		mode |= IPG_AC_LED_MODE;	/* Write Asic Control Bit 14 */
+
+	if ((sp->LED_Mode & 0x08) == 8)
+		mode |= IPG_AC_LED_SPEED;	/* Write Asic Control Bit 27 */
+
+	ipg_w32(mode, ASIC_CTRL);
+}
+
+/* Set PHYSet JES20040127EEPROM */
+static void ipg_set_phy_set(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	int physet;
+
+	physet = ipg_r8(PHY_SET);
+	physet &= ~(IPG_PS_MEM_LENB9B | IPG_PS_MEM_LEN9 | IPG_PS_NON_COMPDET);
+	physet |= ((sp->LED_Mode & 0x70) >> 4);
+	ipg_w8(physet, PHY_SET);
+}
+
+static int ipg_reset(struct net_device *dev, u32 resetflags)
+{
+	/* Assert functional resets via the IPG AsicCtrl
+	 * register as specified by the 'resetflags' input
+	 * parameter.
+	 */
+	void __iomem *ioaddr = ipg_ioaddr(dev);	//JES20040127EEPROM:
+	unsigned int timeout_count = 0;
+
+	IPG_DEBUG_MSG("_reset\n");
+
+	ipg_w32(ipg_r32(ASIC_CTRL) | resetflags, ASIC_CTRL);
+
+	/* Delay added to account for problem with 10Mbps reset. */
+	mdelay(IPG_AC_RESETWAIT);
+
+	while (IPG_AC_RESET_BUSY & ipg_r32(ASIC_CTRL)) {
+		mdelay(IPG_AC_RESETWAIT);
+		if (++timeout_count > IPG_AC_RESET_TIMEOUT)
+			return -ETIME;
+	}
+	/* Set LED Mode in Asic Control JES20040127EEPROM */
+	ipg_set_led_mode(dev);
+
+	/* Set PHYSet Register Value JES20040127EEPROM */
+	ipg_set_phy_set(dev);
+	return 0;
+}
+
+/* Find the GMII PHY address. */
+static int ipg_find_phyaddr(struct net_device *dev)
+{
+	unsigned int phyaddr, i;
+
+	for (i = 0; i < 32; i++) {
+		u32 status;
+
+		/* Search for the correct PHY address among 32 possible. */
+		phyaddr = (IPG_NIC_PHY_ADDRESS + i) % 32;
+
+		/* 10/22/03 Grace change verify from GMII_PHY_STATUS to
+		   GMII_PHY_ID1
+		 */
+
+		status = mdio_read(dev, phyaddr, MII_BMSR);
+
+		if ((status != 0xFFFF) && (status != 0))
+			return phyaddr;
+	}
+
+	return 0x1f;
+}
+
+/*
+ * Configure IPG based on result of IEEE 802.3 PHY
+ * auto-negotiation.
+ */
+static int ipg_config_autoneg(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int txflowcontrol;
+	unsigned int rxflowcontrol;
+	unsigned int fullduplex;
+	unsigned int gig;
+	u32 mac_ctrl_val;
+	u32 asicctrl;
+	u8 phyctrl;
+
+	IPG_DEBUG_MSG("_config_autoneg\n");
+
+	asicctrl = ipg_r32(ASIC_CTRL);
+	phyctrl = ipg_r8(PHY_CTRL);
+	mac_ctrl_val = ipg_r32(MAC_CTRL);
+
+	/* Set flags for use in resolving auto-negotation, assuming
+	 * non-1000Mbps, half duplex, no flow control.
+	 */
+	fullduplex = 0;
+	txflowcontrol = 0;
+	rxflowcontrol = 0;
+	gig = 0;
+
+	/* To accomodate a problem in 10Mbps operation,
+	 * set a global flag if PHY running in 10Mbps mode.
+	 */
+	sp->tenmbpsmode = 0;
+
+	printk(KERN_INFO "%s: Link speed = ", dev->name);
+
+	/* Determine actual speed of operation. */
+	switch (phyctrl & IPG_PC_LINK_SPEED) {
+	case IPG_PC_LINK_SPEED_10MBPS:
+		printk("10Mbps.\n");
+		printk(KERN_INFO "%s: 10Mbps operational mode enabled.\n",
+		       dev->name);
+		sp->tenmbpsmode = 1;
+		break;
+	case IPG_PC_LINK_SPEED_100MBPS:
+		printk("100Mbps.\n");
+		break;
+	case IPG_PC_LINK_SPEED_1000MBPS:
+		printk("1000Mbps.\n");
+		gig = 1;
+		break;
+	default:
+		printk("undefined!\n");
+		return 0;
+	}
+
+	if (phyctrl & IPG_PC_DUPLEX_STATUS) {
+		fullduplex = 1;
+		txflowcontrol = 1;
+		rxflowcontrol = 1;
+	}
+
+	/* Configure full duplex, and flow control. */
+	if (fullduplex == 1) {
+		/* Configure IPG for full duplex operation. */
+		printk(KERN_INFO "%s: setting full duplex, ", dev->name);
+
+		mac_ctrl_val |= IPG_MC_DUPLEX_SELECT_FD;
+
+		if (txflowcontrol == 1) {
+			printk("TX flow control");
+			mac_ctrl_val |= IPG_MC_TX_FLOW_CONTROL_ENABLE;
+		} else {
+			printk("no TX flow control");
+			mac_ctrl_val &= ~IPG_MC_TX_FLOW_CONTROL_ENABLE;
+		}
+
+		if (rxflowcontrol == 1) {
+			printk(", RX flow control.");
+			mac_ctrl_val |= IPG_MC_RX_FLOW_CONTROL_ENABLE;
+		} else {
+			printk(", no RX flow control.");
+			mac_ctrl_val &= ~IPG_MC_RX_FLOW_CONTROL_ENABLE;
+		}
+
+		printk("\n");
+	} else {
+		/* Configure IPG for half duplex operation. */
+	        printk(KERN_INFO "%s: setting half duplex, "
+		       "no TX flow control, no RX flow control.\n", dev->name);
+
+		mac_ctrl_val &= ~IPG_MC_DUPLEX_SELECT_FD &
+			~IPG_MC_TX_FLOW_CONTROL_ENABLE &
+			~IPG_MC_RX_FLOW_CONTROL_ENABLE;
+	}
+	ipg_w32(mac_ctrl_val, MAC_CTRL);
+	return 0;
+}
+
+/* Determine and configure multicast operation and set
+ * receive mode for IPG.
+ */
+static void ipg_nic_set_multicast_list(struct net_device *dev)
+{
+	void __iomem *ioaddr = ipg_ioaddr(dev);
+	struct dev_mc_list *mc_list_ptr;
+	unsigned int hashindex;
+	u32 hashtable[2];
+	u8 receivemode;
+
+	IPG_DEBUG_MSG("_nic_set_multicast_list\n");
+
+	receivemode = IPG_RM_RECEIVEUNICAST | IPG_RM_RECEIVEBROADCAST;
+
+	if (dev->flags & IFF_PROMISC) {
+		/* NIC to be configured in promiscuous mode. */
+		receivemode = IPG_RM_RECEIVEALLFRAMES;
+	} else if ((dev->flags & IFF_ALLMULTI) ||
+		   (dev->flags & IFF_MULTICAST &
+		    (dev->mc_count > IPG_MULTICAST_HASHTABLE_SIZE))) {
+		/* NIC to be configured to receive all multicast
+		 * frames. */
+		receivemode |= IPG_RM_RECEIVEMULTICAST;
+	} else if (dev->flags & IFF_MULTICAST & (dev->mc_count > 0)) {
+		/* NIC to be configured to receive selected
+		 * multicast addresses. */
+		receivemode |= IPG_RM_RECEIVEMULTICASTHASH;
+	}
+
+	/* Calculate the bits to set for the 64 bit, IPG HASHTABLE.
+	 * The IPG applies a cyclic-redundancy-check (the same CRC
+	 * used to calculate the frame data FCS) to the destination
+	 * address all incoming multicast frames whose destination
+	 * address has the multicast bit set. The least significant
+	 * 6 bits of the CRC result are used as an addressing index
+	 * into the hash table. If the value of the bit addressed by
+	 * this index is a 1, the frame is passed to the host system.
+	 */
+
+	/* Clear hashtable. */
+	hashtable[0] = 0x00000000;
+	hashtable[1] = 0x00000000;
+
+	/* Cycle through all multicast addresses to filter. */
+	for (mc_list_ptr = dev->mc_list;
+	     mc_list_ptr != NULL; mc_list_ptr = mc_list_ptr->next) {
+		/* Calculate CRC result for each multicast address. */
+		hashindex = crc32_le(0xffffffff, mc_list_ptr->dmi_addr,
+				     ETH_ALEN);
+
+		/* Use only the least significant 6 bits. */
+		hashindex = hashindex & 0x3F;
+
+		/* Within "hashtable", set bit number "hashindex"
+		 * to a logic 1.
+		 */
+		set_bit(hashindex, (void *)hashtable);
+	}
+
+	/* Write the value of the hashtable, to the 4, 16 bit
+	 * HASHTABLE IPG registers.
+	 */
+	ipg_w32(hashtable[0], HASHTABLE_0);
+	ipg_w32(hashtable[1], HASHTABLE_1);
+
+	ipg_w8(IPG_RM_RSVD_MASK & receivemode, RECEIVE_MODE);
+
+	IPG_DEBUG_MSG("ReceiveMode = %x\n", ipg_r8(RECEIVE_MODE));
+}
+
+static int ipg_io_config(struct net_device *dev)
+{
+	void __iomem *ioaddr = ipg_ioaddr(dev);
+	u32 origmacctrl;
+	u32 restoremacctrl;
+
+	IPG_DEBUG_MSG("_io_config\n");
+
+	origmacctrl = ipg_r32(MAC_CTRL);
+
+	restoremacctrl = origmacctrl | IPG_MC_STATISTICS_ENABLE;
+
+	/* Based on compilation option, determine if FCS is to be
+	 * stripped on receive frames by IPG.
+	 */
+	if (!IPG_STRIP_FCS_ON_RX)
+		restoremacctrl |= IPG_MC_RCV_FCS;
+
+	/* Determine if transmitter and/or receiver are
+	 * enabled so we may restore MACCTRL correctly.
+	 */
+	if (origmacctrl & IPG_MC_TX_ENABLED)
+		restoremacctrl |= IPG_MC_TX_ENABLE;
+
+	if (origmacctrl & IPG_MC_RX_ENABLED)
+		restoremacctrl |= IPG_MC_RX_ENABLE;
+
+	/* Transmitter and receiver must be disabled before setting
+	 * IFSSelect.
+	 */
+	ipg_w32((origmacctrl & (IPG_MC_RX_DISABLE | IPG_MC_TX_DISABLE)) &
+		IPG_MC_RSVD_MASK, MAC_CTRL);
+
+	/* Now that transmitter and receiver are disabled, write
+	 * to IFSSelect.
+	 */
+	ipg_w32((origmacctrl & IPG_MC_IFS_96BIT) & IPG_MC_RSVD_MASK, MAC_CTRL);
+
+	/* Set RECEIVEMODE register. */
+	ipg_nic_set_multicast_list(dev);
+
+	ipg_w16(IPG_MAX_RXFRAME_SIZE, MAX_FRAME_SIZE);
+
+	ipg_w8(IPG_RXDMAPOLLPERIOD_VALUE,   RX_DMA_POLL_PERIOD);
+	ipg_w8(IPG_RXDMAURGENTTHRESH_VALUE, RX_DMA_URGENT_THRESH);
+	ipg_w8(IPG_RXDMABURSTTHRESH_VALUE,  RX_DMA_BURST_THRESH);
+	ipg_w8(IPG_TXDMAPOLLPERIOD_VALUE,   TX_DMA_POLL_PERIOD);
+	ipg_w8(IPG_TXDMAURGENTTHRESH_VALUE, TX_DMA_URGENT_THRESH);
+	ipg_w8(IPG_TXDMABURSTTHRESH_VALUE,  TX_DMA_BURST_THRESH);
+	ipg_w16((IPG_IE_HOST_ERROR | IPG_IE_TX_DMA_COMPLETE |
+		 IPG_IE_TX_COMPLETE | IPG_IE_INT_REQUESTED |
+		 IPG_IE_UPDATE_STATS | IPG_IE_LINK_EVENT |
+		 IPG_IE_RX_DMA_COMPLETE | IPG_IE_RX_DMA_PRIORITY), INT_ENABLE);
+	ipg_w16(IPG_FLOWONTHRESH_VALUE,  FLOW_ON_THRESH);
+	ipg_w16(IPG_FLOWOFFTHRESH_VALUE, FLOW_OFF_THRESH);
+
+	/* IPG multi-frag frame bug workaround.
+	 * Per silicon revision B3 eratta.
+	 */
+	ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0200, DEBUG_CTRL);
+
+	/* IPG TX poll now bug workaround.
+	 * Per silicon revision B3 eratta.
+	 */
+	ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0010, DEBUG_CTRL);
+
+	/* IPG RX poll now bug workaround.
+	 * Per silicon revision B3 eratta.
+	 */
+	ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0020, DEBUG_CTRL);
+
+	/* Now restore MACCTRL to original setting. */
+	ipg_w32(IPG_MC_RSVD_MASK & restoremacctrl, MAC_CTRL);
+
+	/* Disable unused RMON statistics. */
+	ipg_w32(IPG_RZ_ALL, RMON_STATISTICS_MASK);
+
+	/* Disable unused MIB statistics. */
+	ipg_w32(IPG_SM_MACCONTROLFRAMESXMTD | IPG_SM_MACCONTROLFRAMESRCVD |
+		IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK | IPG_SM_TXJUMBOFRAMES |
+		IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK | IPG_SM_RXJUMBOFRAMES |
+		IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK |
+		IPG_SM_UDPCHECKSUMERRORS | IPG_SM_TCPCHECKSUMERRORS |
+		IPG_SM_IPCHECKSUMERRORS, STATISTICS_MASK);
+
+	return 0;
+}
+
+/*
+ * Create a receive buffer within system memory and update
+ * NIC private structure appropriately.
+ */
+static int ipg_get_rxbuff(struct net_device *dev, int entry)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	struct ipg_rx *rxfd = sp->rxd + entry;
+	struct sk_buff *skb;
+	u64 rxfragsize;
+
+	IPG_DEBUG_MSG("_get_rxbuff\n");
+
+	skb = netdev_alloc_skb(dev, IPG_RXSUPPORT_SIZE + NET_IP_ALIGN);
+	if (!skb) {
+		sp->RxBuff[entry] = NULL;
+		return -ENOMEM;
+	}
+
+	/* Adjust the data start location within the buffer to
+	 * align IP address field to a 16 byte boundary.
+	 */
+	skb_reserve(skb, NET_IP_ALIGN);
+
+	/* Associate the receive buffer with the IPG NIC. */
+	skb->dev = dev;
+
+	/* Save the address of the sk_buff structure. */
+	sp->RxBuff[entry] = skb;
+
+	rxfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data,
+		sp->rx_buf_sz, PCI_DMA_FROMDEVICE));
+
+	/* Set the RFD fragment length. */
+	rxfragsize = IPG_RXFRAG_SIZE;
+	rxfd->frag_info |= cpu_to_le64((rxfragsize << 48) & IPG_RFI_FRAGLEN);
+
+	return 0;
+}
+
+static int init_rfdlist(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int i;
+
+	IPG_DEBUG_MSG("_init_rfdlist\n");
+
+	for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
+		struct ipg_rx *rxfd = sp->rxd + i;
+
+		if (sp->RxBuff[i]) {
+			pci_unmap_single(sp->pdev,
+				le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+				sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			IPG_DEV_KFREE_SKB(sp->RxBuff[i]);
+			sp->RxBuff[i] = NULL;
+		}
+
+		/* Clear out the RFS field. */
+		rxfd->rfs = 0x0000000000000000;
+
+		if (ipg_get_rxbuff(dev, i) < 0) {
+			/*
+			 * A receive buffer was not ready, break the
+			 * RFD list here.
+			 */
+			IPG_DEBUG_MSG("Cannot allocate Rx buffer.\n");
+
+			/* Just in case we cannot allocate a single RFD.
+			 * Should not occur.
+			 */
+			if (i == 0) {
+				printk(KERN_ERR "%s: No memory available"
+					" for RFD list.\n", dev->name);
+				return -ENOMEM;
+			}
+		}
+
+		rxfd->next_desc = cpu_to_le64(sp->rxd_map +
+			sizeof(struct ipg_rx)*(i + 1));
+	}
+	sp->rxd[i - 1].next_desc = cpu_to_le64(sp->rxd_map);
+
+	sp->rx_current = 0;
+	sp->rx_dirty = 0;
+
+	/* Write the location of the RFDList to the IPG. */
+	ipg_w32((u32) sp->rxd_map, RFD_LIST_PTR_0);
+	ipg_w32(0x00000000, RFD_LIST_PTR_1);
+
+	return 0;
+}
+
+static void init_tfdlist(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int i;
+
+	IPG_DEBUG_MSG("_init_tfdlist\n");
+
+	for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
+		struct ipg_tx *txfd = sp->txd + i;
+
+		txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE);
+
+		if (sp->TxBuff[i]) {
+			IPG_DEV_KFREE_SKB(sp->TxBuff[i]);
+			sp->TxBuff[i] = NULL;
+		}
+
+		txfd->next_desc = cpu_to_le64(sp->txd_map +
+			sizeof(struct ipg_tx)*(i + 1));
+	}
+	sp->txd[i - 1].next_desc = cpu_to_le64(sp->txd_map);
+
+	sp->tx_current = 0;
+	sp->tx_dirty = 0;
+
+	/* Write the location of the TFDList to the IPG. */
+	IPG_DDEBUG_MSG("Starting TFDListPtr = %8.8x\n",
+		       (u32) sp->txd_map);
+	ipg_w32((u32) sp->txd_map, TFD_LIST_PTR_0);
+	ipg_w32(0x00000000, TFD_LIST_PTR_1);
+
+	sp->ResetCurrentTFD = 1;
+}
+
+/*
+ * Free all transmit buffers which have already been transfered
+ * via DMA to the IPG.
+ */
+static void ipg_nic_txfree(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int curr;
+	u64 txd_map;
+	unsigned int released, pending;
+
+	txd_map = (u64)sp->txd_map;
+	curr = ipg_r32(TFD_LIST_PTR_0) -
+		do_div(txd_map, sizeof(struct ipg_tx)) - 1;
+
+	IPG_DEBUG_MSG("_nic_txfree\n");
+
+	pending = sp->tx_current - sp->tx_dirty;
+
+	for (released = 0; released < pending; released++) {
+		unsigned int dirty = sp->tx_dirty % IPG_TFDLIST_LENGTH;
+		struct sk_buff *skb = sp->TxBuff[dirty];
+		struct ipg_tx *txfd = sp->txd + dirty;
+
+		IPG_DEBUG_MSG("TFC = %16.16lx\n", (unsigned long) txfd->tfc);
+
+		/* Look at each TFD's TFC field beginning
+		 * at the last freed TFD up to the current TFD.
+		 * If the TFDDone bit is set, free the associated
+		 * buffer.
+		 */
+		if (dirty == curr)
+			break;
+
+		/* Setup TFDDONE for compatible issue. */
+		txfd->tfc |= cpu_to_le64(IPG_TFC_TFDDONE);
+
+		/* Free the transmit buffer. */
+		if (skb) {
+			pci_unmap_single(sp->pdev,
+				le64_to_cpu(txfd->frag_info & ~IPG_TFI_FRAGLEN),
+				skb->len, PCI_DMA_TODEVICE);
+
+			IPG_DEV_KFREE_SKB(skb);
+
+			sp->TxBuff[dirty] = NULL;
+		}
+	}
+
+	sp->tx_dirty += released;
+
+	if (netif_queue_stopped(dev) &&
+	    (sp->tx_current != (sp->tx_dirty + IPG_TFDLIST_LENGTH))) {
+		netif_wake_queue(dev);
+	}
+}
+
+static void ipg_tx_timeout(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+
+	ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA | IPG_AC_NETWORK |
+		  IPG_AC_FIFO);
+
+	spin_lock_irq(&sp->lock);
+
+	/* Re-configure after DMA reset. */
+	if (ipg_io_config(dev) < 0) {
+		printk(KERN_INFO "%s: Error during re-configuration.\n",
+		       dev->name);
+	}
+
+	init_tfdlist(dev);
+
+	spin_unlock_irq(&sp->lock);
+
+	ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & IPG_MC_RSVD_MASK,
+		MAC_CTRL);
+}
+
+/*
+ * For TxComplete interrupts, free all transmit
+ * buffers which have already been transfered via DMA
+ * to the IPG.
+ */
+static void ipg_nic_txcleanup(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int i;
+
+	IPG_DEBUG_MSG("_nic_txcleanup\n");
+
+	for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
+		/* Reading the TXSTATUS register clears the
+		 * TX_COMPLETE interrupt.
+		 */
+		u32 txstatusdword = ipg_r32(TX_STATUS);
+
+		IPG_DEBUG_MSG("TxStatus = %8.8x\n", txstatusdword);
+
+		/* Check for Transmit errors. Error bits only valid if
+		 * TX_COMPLETE bit in the TXSTATUS register is a 1.
+		 */
+		if (!(txstatusdword & IPG_TS_TX_COMPLETE))
+			break;
+
+		/* If in 10Mbps mode, indicate transmit is ready. */
+		if (sp->tenmbpsmode) {
+			netif_wake_queue(dev);
+		}
+
+		/* Transmit error, increment stat counters. */
+		if (txstatusdword & IPG_TS_TX_ERROR) {
+			IPG_DEBUG_MSG("Transmit error.\n");
+			sp->stats.tx_errors++;
+		}
+
+		/* Late collision, re-enable transmitter. */
+		if (txstatusdword & IPG_TS_LATE_COLLISION) {
+			IPG_DEBUG_MSG("Late collision on transmit.\n");
+			ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
+				IPG_MC_RSVD_MASK, MAC_CTRL);
+		}
+
+		/* Maximum collisions, re-enable transmitter. */
+		if (txstatusdword & IPG_TS_TX_MAX_COLL) {
+			IPG_DEBUG_MSG("Maximum collisions on transmit.\n");
+			ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
+				IPG_MC_RSVD_MASK, MAC_CTRL);
+		}
+
+		/* Transmit underrun, reset and re-enable
+		 * transmitter.
+		 */
+		if (txstatusdword & IPG_TS_TX_UNDERRUN) {
+			IPG_DEBUG_MSG("Transmitter underrun.\n");
+			sp->stats.tx_fifo_errors++;
+			ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA |
+				  IPG_AC_NETWORK | IPG_AC_FIFO);
+
+			/* Re-configure after DMA reset. */
+			if (ipg_io_config(dev) < 0) {
+				printk(KERN_INFO
+				       "%s: Error during re-configuration.\n",
+				       dev->name);
+			}
+			init_tfdlist(dev);
+
+			ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
+				IPG_MC_RSVD_MASK, MAC_CTRL);
+		}
+	}
+
+	ipg_nic_txfree(dev);
+}
+
+/* Provides statistical information about the IPG NIC. */
+struct net_device_stats *ipg_nic_get_stats(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	u16 temp1;
+	u16 temp2;
+
+	IPG_DEBUG_MSG("_nic_get_stats\n");
+
+	/* Check to see if the NIC has been initialized via nic_open,
+	 * before trying to read statistic registers.
+	 */
+	if (!test_bit(__LINK_STATE_START, &dev->state))
+		return &sp->stats;
+
+	sp->stats.rx_packets += ipg_r32(IPG_FRAMESRCVDOK);
+	sp->stats.tx_packets += ipg_r32(IPG_FRAMESXMTDOK);
+	sp->stats.rx_bytes += ipg_r32(IPG_OCTETRCVOK);
+	sp->stats.tx_bytes += ipg_r32(IPG_OCTETXMTOK);
+	temp1 = ipg_r16(IPG_FRAMESLOSTRXERRORS);
+	sp->stats.rx_errors += temp1;
+	sp->stats.rx_missed_errors += temp1;
+	temp1 = ipg_r32(IPG_SINGLECOLFRAMES) + ipg_r32(IPG_MULTICOLFRAMES) +
+		ipg_r32(IPG_LATECOLLISIONS);
+	temp2 = ipg_r16(IPG_CARRIERSENSEERRORS);
+	sp->stats.collisions += temp1;
+	sp->stats.tx_dropped += ipg_r16(IPG_FRAMESABORTXSCOLLS);
+	sp->stats.tx_errors += ipg_r16(IPG_FRAMESWEXDEFERRAL) +
+		ipg_r32(IPG_FRAMESWDEFERREDXMT) + temp1 + temp2;
+	sp->stats.multicast += ipg_r32(IPG_MCSTOCTETRCVDOK);
+
+	/* detailed tx_errors */
+	sp->stats.tx_carrier_errors += temp2;
+
+	/* detailed rx_errors */
+	sp->stats.rx_length_errors += ipg_r16(IPG_INRANGELENGTHERRORS) +
+		ipg_r16(IPG_FRAMETOOLONGERRRORS);
+	sp->stats.rx_crc_errors += ipg_r16(IPG_FRAMECHECKSEQERRORS);
+
+	/* Unutilized IPG statistic registers. */
+	ipg_r32(IPG_MCSTFRAMESRCVDOK);
+
+	return &sp->stats;
+}
+
+/* Restore used receive buffers. */
+static int ipg_nic_rxrestore(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	const unsigned int curr = sp->rx_current;
+	unsigned int dirty = sp->rx_dirty;
+
+	IPG_DEBUG_MSG("_nic_rxrestore\n");
+
+	for (dirty = sp->rx_dirty; curr - dirty > 0; dirty++) {
+		unsigned int entry = dirty % IPG_RFDLIST_LENGTH;
+
+		/* rx_copybreak may poke hole here and there. */
+		if (sp->RxBuff[entry])
+			continue;
+
+		/* Generate a new receive buffer to replace the
+		 * current buffer (which will be released by the
+		 * Linux system).
+		 */
+		if (ipg_get_rxbuff(dev, entry) < 0) {
+			IPG_DEBUG_MSG("Cannot allocate new Rx buffer.\n");
+
+			break;
+		}
+
+		/* Reset the RFS field. */
+		sp->rxd[entry].rfs = 0x0000000000000000;
+	}
+	sp->rx_dirty = dirty;
+
+	return 0;
+}
+
+#ifdef JUMBO_FRAME
+
+/* use jumboindex and jumbosize to control jumbo frame status
+   initial status is jumboindex=-1 and jumbosize=0
+   1. jumboindex = -1 and jumbosize=0 : previous jumbo frame has been done.
+   2. jumboindex != -1 and jumbosize != 0 : jumbo frame is not over size and receiving
+   3. jumboindex = -1 and jumbosize != 0 : jumbo frame is over size, already dump
+                previous receiving and need to continue dumping the current one
+*/
+enum {
+	NormalPacket,
+	ErrorPacket
+};
+
+enum {
+	Frame_NoStart_NoEnd	= 0,
+	Frame_WithStart		= 1,
+	Frame_WithEnd		= 10,
+	Frame_WithStart_WithEnd = 11
+};
+
+inline void ipg_nic_rx_free_skb(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH;
+
+	if (sp->RxBuff[entry]) {
+		struct ipg_rx *rxfd = sp->rxd + entry;
+
+		pci_unmap_single(sp->pdev,
+			le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+			sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+		IPG_DEV_KFREE_SKB(sp->RxBuff[entry]);
+		sp->RxBuff[entry] = NULL;
+	}
+}
+
+inline int ipg_nic_rx_check_frame_type(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	struct ipg_rx *rxfd = sp->rxd + (sp->rx_current % IPG_RFDLIST_LENGTH);
+	int type = Frame_NoStart_NoEnd;
+
+	if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART)
+		type += Frame_WithStart;
+	if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND)
+		type += Frame_WithEnd;
+	return type;
+}
+
+inline int ipg_nic_rx_check_error(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH;
+	struct ipg_rx *rxfd = sp->rxd + entry;
+
+	if (IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) &
+	     (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME |
+	      IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR |
+	      IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))) {
+		IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n",
+			      (unsigned long) rxfd->rfs);
+
+		/* Increment general receive error statistic. */
+		sp->stats.rx_errors++;
+
+		/* Increment detailed receive error statistics. */
+		if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) {
+			IPG_DEBUG_MSG("RX FIFO overrun occured.\n");
+
+			sp->stats.rx_fifo_errors++;
+		}
+
+		if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) {
+			IPG_DEBUG_MSG("RX runt occured.\n");
+			sp->stats.rx_length_errors++;
+		}
+
+		/* Do nothing for IPG_RFS_RXOVERSIZEDFRAME,
+		 * error count handled by a IPG statistic register.
+		 */
+
+		if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) {
+			IPG_DEBUG_MSG("RX alignment error occured.\n");
+			sp->stats.rx_frame_errors++;
+		}
+
+		/* Do nothing for IPG_RFS_RXFCSERROR, error count
+		 * handled by a IPG statistic register.
+		 */
+
+		/* Free the memory associated with the RX
+		 * buffer since it is erroneous and we will
+		 * not pass it to higher layer processes.
+		 */
+		if (sp->RxBuff[entry]) {
+			pci_unmap_single(sp->pdev,
+				le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+				sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+
+			IPG_DEV_KFREE_SKB(sp->RxBuff[entry]);
+			sp->RxBuff[entry] = NULL;
+		}
+		return ErrorPacket;
+	}
+	return NormalPacket;
+}
+
+static void ipg_nic_rx_with_start_and_end(struct net_device *dev,
+					  struct ipg_nic_private *sp,
+					  struct ipg_rx *rxfd, unsigned entry)
+{
+	struct SJumbo *jumbo = &sp->Jumbo;
+	struct sk_buff *skb;
+	int framelen;
+
+	if (jumbo->FoundStart) {
+		IPG_DEV_KFREE_SKB(jumbo->skb);
+		jumbo->FoundStart = 0;
+		jumbo->CurrentSize = 0;
+		jumbo->skb = NULL;
+	}
+
+	// 1: found error, 0 no error
+	if (ipg_nic_rx_check_error(dev) != NormalPacket)
+		return;
+
+	skb = sp->RxBuff[entry];
+	if (!skb)
+		return;
+
+	// accept this frame and send to upper layer
+	framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
+	if (framelen > IPG_RXFRAG_SIZE)
+		framelen = IPG_RXFRAG_SIZE;
+
+	skb_put(skb, framelen);
+	skb->protocol = eth_type_trans(skb, dev);
+	skb->ip_summed = CHECKSUM_NONE;
+	netif_rx(skb);
+	dev->last_rx = jiffies;
+	sp->RxBuff[entry] = NULL;
+}
+
+static void ipg_nic_rx_with_start(struct net_device *dev,
+				  struct ipg_nic_private *sp,
+				  struct ipg_rx *rxfd, unsigned entry)
+{
+	struct SJumbo *jumbo = &sp->Jumbo;
+	struct pci_dev *pdev = sp->pdev;
+	struct sk_buff *skb;
+
+	// 1: found error, 0 no error
+	if (ipg_nic_rx_check_error(dev) != NormalPacket)
+		return;
+
+	// accept this frame and send to upper layer
+	skb = sp->RxBuff[entry];
+	if (!skb)
+		return;
+
+	if (jumbo->FoundStart)
+		IPG_DEV_KFREE_SKB(jumbo->skb);
+
+	pci_unmap_single(pdev, le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+			 sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+
+	skb_put(skb, IPG_RXFRAG_SIZE);
+
+	jumbo->FoundStart = 1;
+	jumbo->CurrentSize = IPG_RXFRAG_SIZE;
+	jumbo->skb = skb;
+
+	sp->RxBuff[entry] = NULL;
+	dev->last_rx = jiffies;
+}
+
+static void ipg_nic_rx_with_end(struct net_device *dev,
+				struct ipg_nic_private *sp,
+				struct ipg_rx *rxfd, unsigned entry)
+{
+	struct SJumbo *jumbo = &sp->Jumbo;
+
+	//1: found error, 0 no error
+	if (ipg_nic_rx_check_error(dev) == NormalPacket) {
+		struct sk_buff *skb = sp->RxBuff[entry];
+
+		if (!skb)
+			return;
+
+		if (jumbo->FoundStart) {
+			int framelen, endframelen;
+
+			framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
+
+			endframeLen = framelen - jumbo->CurrentSize;
+			/*
+			if (framelen > IPG_RXFRAG_SIZE)
+				framelen=IPG_RXFRAG_SIZE;
+			 */
+			if (framelen > IPG_RXSUPPORT_SIZE)
+				IPG_DEV_KFREE_SKB(jumbo->skb);
+			else {
+				memcpy(skb_put(jumbo->skb, endframeLen),
+				       skb->data, endframeLen);
+
+				jumbo->skb->protocol =
+				    eth_type_trans(jumbo->skb, dev);
+
+				jumbo->skb->ip_summed = CHECKSUM_NONE;
+				netif_rx(jumbo->skb);
+			}
+		}
+
+		dev->last_rx = jiffies;
+		jumbo->FoundStart = 0;
+		jumbo->CurrentSize = 0;
+		jumbo->skb = NULL;
+
+		ipg_nic_rx_free_skb(dev);
+	} else {
+		IPG_DEV_KFREE_SKB(jumbo->skb);
+		jumbo->FoundStart = 0;
+		jumbo->CurrentSize = 0;
+		jumbo->skb = NULL;
+	}
+}
+
+static void ipg_nic_rx_no_start_no_end(struct net_device *dev,
+				       struct ipg_nic_private *sp,
+				       struct ipg_rx *rxfd, unsigned entry)
+{
+	struct SJumbo *jumbo = &sp->Jumbo;
+
+	//1: found error, 0 no error
+	if (ipg_nic_rx_check_error(dev) == NormalPacket) {
+		struct sk_buff *skb = sp->RxBuff[entry];
+
+		if (skb) {
+			if (jumbo->FoundStart) {
+				jumbo->CurrentSize += IPG_RXFRAG_SIZE;
+				if (jumbo->CurrentSize <= IPG_RXSUPPORT_SIZE) {
+					memcpy(skb_put(jumbo->skb,
+						       IPG_RXFRAG_SIZE),
+					       skb->data, IPG_RXFRAG_SIZE);
+				}
+			}
+			dev->last_rx = jiffies;
+			ipg_nic_rx_free_skb(dev);
+		}
+	} else {
+		IPG_DEV_KFREE_SKB(jumbo->skb);
+		jumbo->FoundStart = 0;
+		jumbo->CurrentSize = 0;
+		jumbo->skb = NULL;
+	}
+}
+
+static int ipg_nic_rx(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	unsigned int curr = sp->rx_current;
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int i;
+
+	IPG_DEBUG_MSG("_nic_rx\n");
+
+	for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) {
+		unsigned int entry = curr % IPG_RFDLIST_LENGTH;
+		struct ipg_rx *rxfd = sp->rxd + entry;
+
+		if (!(rxfd->rfs & le64_to_cpu(IPG_RFS_RFDDONE)))
+			break;
+
+		switch (ipg_nic_rx_check_frame_type(dev)) {
+		case Frame_WithStart_WithEnd:
+			ipg_nic_rx_with_start_and_end(dev, tp, rxfd, entry);
+			break;
+		case Frame_WithStart:
+			ipg_nic_rx_with_start(dev, tp, rxfd, entry);
+			break;
+		case Frame_WithEnd:
+			ipg_nic_rx_with_end(dev, tp, rxfd, entry);
+			break;
+		case Frame_NoStart_NoEnd:
+			ipg_nic_rx_no_start_no_end(dev, tp, rxfd, entry);
+			break;
+		}
+	}
+
+	sp->rx_current = curr;
+
+	if (i == IPG_MAXRFDPROCESS_COUNT) {
+		/* There are more RFDs to process, however the
+		 * allocated amount of RFD processing time has
+		 * expired. Assert Interrupt Requested to make
+		 * sure we come back to process the remaining RFDs.
+		 */
+		ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL);
+	}
+
+	ipg_nic_rxrestore(dev);
+
+	return 0;
+}
+
+#else
+static int ipg_nic_rx(struct net_device *dev)
+{
+	/* Transfer received Ethernet frames to higher network layers. */
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	unsigned int curr = sp->rx_current;
+	void __iomem *ioaddr = sp->ioaddr;
+	struct ipg_rx *rxfd;
+	unsigned int i;
+
+	IPG_DEBUG_MSG("_nic_rx\n");
+
+#define __RFS_MASK \
+	cpu_to_le64(IPG_RFS_RFDDONE | IPG_RFS_FRAMESTART | IPG_RFS_FRAMEEND)
+
+	for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) {
+		unsigned int entry = curr % IPG_RFDLIST_LENGTH;
+		struct sk_buff *skb = sp->RxBuff[entry];
+		unsigned int framelen;
+
+		rxfd = sp->rxd + entry;
+
+		if (((rxfd->rfs & __RFS_MASK) != __RFS_MASK) || !skb)
+			break;
+
+		/* Get received frame length. */
+		framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
+
+		/* Check for jumbo frame arrival with too small
+		 * RXFRAG_SIZE.
+		 */
+		if (framelen > IPG_RXFRAG_SIZE) {
+			IPG_DEBUG_MSG
+			    ("RFS FrameLen > allocated fragment size.\n");
+
+			framelen = IPG_RXFRAG_SIZE;
+		}
+
+		if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs &
+		       (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME |
+			IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR |
+			IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))))) {
+
+			IPG_DEBUG_MSG("Rx error, RFS = %16.16lx\n",
+				      (unsigned long int) rxfd->rfs);
+
+			/* Increment general receive error statistic. */
+			sp->stats.rx_errors++;
+
+			/* Increment detailed receive error statistics. */
+			if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXFIFOOVERRUN)) {
+				IPG_DEBUG_MSG("RX FIFO overrun occured.\n");
+				sp->stats.rx_fifo_errors++;
+			}
+
+			if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXRUNTFRAME)) {
+				IPG_DEBUG_MSG("RX runt occured.\n");
+				sp->stats.rx_length_errors++;
+			}
+
+			if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXOVERSIZEDFRAME)) ;
+			/* Do nothing, error count handled by a IPG
+			 * statistic register.
+			 */
+
+			if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXALIGNMENTERROR)) {
+				IPG_DEBUG_MSG("RX alignment error occured.\n");
+				sp->stats.rx_frame_errors++;
+			}
+
+			if (le64_to_cpu(rxfd->rfs & IPG_RFS_RXFCSERROR)) ;
+			/* Do nothing, error count handled by a IPG
+			 * statistic register.
+			 */
+
+			/* Free the memory associated with the RX
+			 * buffer since it is erroneous and we will
+			 * not pass it to higher layer processes.
+			 */
+			if (skb) {
+				u64 info = rxfd->frag_info;
+
+				pci_unmap_single(sp->pdev,
+					le64_to_cpu(info & ~IPG_RFI_FRAGLEN),
+					sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+
+				IPG_DEV_KFREE_SKB(skb);
+			}
+		} else {
+
+			/* Adjust the new buffer length to accomodate the size
+			 * of the received frame.
+			 */
+			skb_put(skb, framelen);
+
+			/* Set the buffer's protocol field to Ethernet. */
+			skb->protocol = eth_type_trans(skb, dev);
+
+			/* If the frame contains an IP/TCP/UDP frame,
+			 * determine if upper layer must check IP/TCP/UDP
+			 * checksums.
+			 *
+			 * NOTE: DO NOT RELY ON THE TCP/UDP CHECKSUM
+			 *       VERIFICATION FOR SILICON REVISIONS B3
+			 *       AND EARLIER!
+			 *
+			 if ((le64_to_cpu(rxfd->rfs &
+			     (IPG_RFS_TCPDETECTED | IPG_RFS_UDPDETECTED |
+			      IPG_RFS_IPDETECTED))) &&
+			    !(le64_to_cpu(rxfd->rfs &
+			      (IPG_RFS_TCPERROR | IPG_RFS_UDPERROR |
+			       IPG_RFS_IPERROR)))) {
+				 * Indicate IP checksums were performed
+				 * by the IPG.
+				 *
+				skb->ip_summed = CHECKSUM_UNNECESSARY;
+			 } else
+			 */
+			 {
+				/* The IPG encountered an error with (or
+				 * there were no) IP/TCP/UDP checksums.
+				 * This may or may not indicate an invalid
+				 * IP/TCP/UDP frame was received. Let the
+				 * upper layer decide.
+				 */
+				skb->ip_summed = CHECKSUM_NONE;
+			}
+
+			/* Hand off frame for higher layer processing.
+			 * The function netif_rx() releases the sk_buff
+			 * when processing completes.
+			 */
+			netif_rx(skb);
+
+			/* Record frame receive time (jiffies = Linux
+			 * kernel current time stamp).
+			 */
+			dev->last_rx = jiffies;
+		}
+
+		/* Assure RX buffer is not reused by IPG. */
+		sp->RxBuff[entry] = NULL;
+	}
+
+	/*
+	 * If there are more RFDs to proces and the allocated amount of RFD
+	 * processing time has expired, assert Interrupt Requested to make
+	 * sure we come back to process the remaining RFDs.
+	 */
+	if (i == IPG_MAXRFDPROCESS_COUNT)
+		ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL);
+
+#ifdef IPG_DEBUG
+	/* Check if the RFD list contained no receive frame data. */
+	if (!i)
+		sp->EmptyRFDListCount++;
+#endif
+	while ((le64_to_cpu(rxfd->rfs & IPG_RFS_RFDDONE)) &&
+	       !((le64_to_cpu(rxfd->rfs & IPG_RFS_FRAMESTART)) &&
+		 (le64_to_cpu(rxfd->rfs & IPG_RFS_FRAMEEND)))) {
+		unsigned int entry = curr++ % IPG_RFDLIST_LENGTH;
+
+		rxfd = sp->rxd + entry;
+
+		IPG_DEBUG_MSG("Frame requires multiple RFDs.\n");
+
+		/* An unexpected event, additional code needed to handle
+		 * properly. So for the time being, just disregard the
+		 * frame.
+		 */
+
+		/* Free the memory associated with the RX
+		 * buffer since it is erroneous and we will
+		 * not pass it to higher layer processes.
+		 */
+		if (sp->RxBuff[entry]) {
+			pci_unmap_single(sp->pdev,
+				le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+				sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+			IPG_DEV_KFREE_SKB(sp->RxBuff[entry]);
+		}
+
+		/* Assure RX buffer is not reused by IPG. */
+		sp->RxBuff[entry] = NULL;
+	}
+
+	sp->rx_current = curr;
+
+	/* Check to see if there are a minimum number of used
+	 * RFDs before restoring any (should improve performance.)
+	 */
+	if ((curr - sp->rx_dirty) >= IPG_MINUSEDRFDSTOFREE)
+		ipg_nic_rxrestore(dev);
+
+	return 0;
+}
+#endif
+
+static void ipg_reset_after_host_error(struct work_struct *work)
+{
+	struct ipg_nic_private *sp =
+		container_of(work, struct ipg_nic_private, task.work);
+	struct net_device *dev = sp->dev;
+
+	IPG_DDEBUG_MSG("DMACtrl = %8.8x\n", ioread32(sp->ioaddr + IPG_DMACTRL));
+
+	/*
+	 * Acknowledge HostError interrupt by resetting
+	 * IPG DMA and HOST.
+	 */
+	ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA);
+
+	init_rfdlist(dev);
+	init_tfdlist(dev);
+
+	if (ipg_io_config(dev) < 0) {
+		printk(KERN_INFO "%s: Cannot recover from PCI error.\n",
+		       dev->name);
+		schedule_delayed_work(&sp->task, HZ);
+	}
+}
+
+static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst)
+{
+	struct net_device *dev = dev_inst;
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int handled = 0;
+	u16 status;
+
+	IPG_DEBUG_MSG("_interrupt_handler\n");
+
+#ifdef JUMBO_FRAME
+	ipg_nic_rxrestore(dev);
+#endif
+	/* Get interrupt source information, and acknowledge
+	 * some (i.e. TxDMAComplete, RxDMAComplete, RxEarly,
+	 * IntRequested, MacControlFrame, LinkEvent) interrupts
+	 * if issued. Also, all IPG interrupts are disabled by
+	 * reading IntStatusAck.
+	 */
+	status = ipg_r16(INT_STATUS_ACK);
+
+	IPG_DEBUG_MSG("IntStatusAck = %4.4x\n", status);
+
+	/* Shared IRQ of remove event. */
+	if (!(status & IPG_IS_RSVD_MASK))
+		goto out_enable;
+
+	handled = 1;
+
+	if (unlikely(!netif_running(dev)))
+		goto out;
+
+	spin_lock(&sp->lock);
+
+	/* If RFDListEnd interrupt, restore all used RFDs. */
+	if (status & IPG_IS_RFD_LIST_END) {
+		IPG_DEBUG_MSG("RFDListEnd Interrupt.\n");
+
+		/* The RFD list end indicates an RFD was encountered
+		 * with a 0 NextPtr, or with an RFDDone bit set to 1
+		 * (indicating the RFD is not read for use by the
+		 * IPG.) Try to restore all RFDs.
+		 */
+		ipg_nic_rxrestore(dev);
+
+#ifdef IPG_DEBUG
+		/* Increment the RFDlistendCount counter. */
+		sp->RFDlistendCount++;
+#endif
+	}
+
+	/* If RFDListEnd, RxDMAPriority, RxDMAComplete, or
+	 * IntRequested interrupt, process received frames. */
+	if ((status & IPG_IS_RX_DMA_PRIORITY) ||
+	    (status & IPG_IS_RFD_LIST_END) ||
+	    (status & IPG_IS_RX_DMA_COMPLETE) ||
+	    (status & IPG_IS_INT_REQUESTED)) {
+#ifdef IPG_DEBUG
+		/* Increment the RFD list checked counter if interrupted
+		 * only to check the RFD list. */
+		if (status & (~(IPG_IS_RX_DMA_PRIORITY | IPG_IS_RFD_LIST_END |
+				IPG_IS_RX_DMA_COMPLETE | IPG_IS_INT_REQUESTED) &
+			       (IPG_IS_HOST_ERROR | IPG_IS_TX_DMA_COMPLETE |
+				IPG_IS_LINK_EVENT | IPG_IS_TX_COMPLETE |
+				IPG_IS_UPDATE_STATS)))
+			sp->RFDListCheckedCount++;
+#endif
+
+		ipg_nic_rx(dev);
+	}
+
+	/* If TxDMAComplete interrupt, free used TFDs. */
+	if (status & IPG_IS_TX_DMA_COMPLETE)
+		ipg_nic_txfree(dev);
+
+	/* TxComplete interrupts indicate one of numerous actions.
+	 * Determine what action to take based on TXSTATUS register.
+	 */
+	if (status & IPG_IS_TX_COMPLETE)
+		ipg_nic_txcleanup(dev);
+
+	/* If UpdateStats interrupt, update Linux Ethernet statistics */
+	if (status & IPG_IS_UPDATE_STATS)
+		ipg_nic_get_stats(dev);
+
+	/* If HostError interrupt, reset IPG. */
+	if (status & IPG_IS_HOST_ERROR) {
+		IPG_DDEBUG_MSG("HostError Interrupt\n");
+
+		schedule_delayed_work(&sp->task, 0);
+	}
+
+	/* If LinkEvent interrupt, resolve autonegotiation. */
+	if (status & IPG_IS_LINK_EVENT) {
+		if (ipg_config_autoneg(dev) < 0)
+			printk(KERN_INFO "%s: Auto-negotiation error.\n",
+			       dev->name);
+	}
+
+	/* If MACCtrlFrame interrupt, do nothing. */
+	if (status & IPG_IS_MAC_CTRL_FRAME)
+		IPG_DEBUG_MSG("MACCtrlFrame interrupt.\n");
+
+	/* If RxComplete interrupt, do nothing. */
+	if (status & IPG_IS_RX_COMPLETE)
+		IPG_DEBUG_MSG("RxComplete interrupt.\n");
+
+	/* If RxEarly interrupt, do nothing. */
+	if (status & IPG_IS_RX_EARLY)
+		IPG_DEBUG_MSG("RxEarly interrupt.\n");
+
+out_enable:
+	/* Re-enable IPG interrupts. */
+	ipg_w16(IPG_IE_TX_DMA_COMPLETE | IPG_IE_RX_DMA_COMPLETE |
+		IPG_IE_HOST_ERROR | IPG_IE_INT_REQUESTED | IPG_IE_TX_COMPLETE |
+		IPG_IE_LINK_EVENT | IPG_IE_UPDATE_STATS, INT_ENABLE);
+
+	spin_unlock(&sp->lock);
+out:
+	return IRQ_RETVAL(handled);
+}
+
+static void ipg_rx_clear(struct ipg_nic_private *sp)
+{
+	unsigned int i;
+
+	for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
+		if (sp->RxBuff[i]) {
+			struct ipg_rx *rxfd = sp->rxd + i;
+
+			IPG_DEV_KFREE_SKB(sp->RxBuff[i]);
+			sp->RxBuff[i] = NULL;
+			pci_unmap_single(sp->pdev,
+				le64_to_cpu(rxfd->frag_info & ~IPG_RFI_FRAGLEN),
+				sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+		}
+	}
+}
+
+static void ipg_tx_clear(struct ipg_nic_private *sp)
+{
+	unsigned int i;
+
+	for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
+		if (sp->TxBuff[i]) {
+			struct ipg_tx *txfd = sp->txd + i;
+
+			pci_unmap_single(sp->pdev,
+				le64_to_cpu(txfd->frag_info & ~IPG_TFI_FRAGLEN),
+				sp->TxBuff[i]->len, PCI_DMA_TODEVICE);
+
+			IPG_DEV_KFREE_SKB(sp->TxBuff[i]);
+
+			sp->TxBuff[i] = NULL;
+		}
+	}
+}
+
+static int ipg_nic_open(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	struct pci_dev *pdev = sp->pdev;
+	int rc;
+
+	IPG_DEBUG_MSG("_nic_open\n");
+
+	sp->rx_buf_sz = IPG_RXSUPPORT_SIZE;
+
+	/* Check for interrupt line conflicts, and request interrupt
+	 * line for IPG.
+	 *
+	 * IMPORTANT: Disable IPG interrupts prior to registering
+	 *            IRQ.
+	 */
+	ipg_w16(0x0000, INT_ENABLE);
+
+	/* Register the interrupt line to be used by the IPG within
+	 * the Linux system.
+	 */
+	rc = request_irq(pdev->irq, &ipg_interrupt_handler, IRQF_SHARED,
+			 dev->name, dev);
+	if (rc < 0) {
+		printk(KERN_INFO "%s: Error when requesting interrupt.\n",
+		       dev->name);
+		goto out;
+	}
+
+	dev->irq = pdev->irq;
+
+	rc = -ENOMEM;
+
+	sp->rxd = dma_alloc_coherent(&pdev->dev, IPG_RX_RING_BYTES,
+				     &sp->rxd_map, GFP_KERNEL);
+	if (!sp->rxd)
+		goto err_free_irq_0;
+
+	sp->txd = dma_alloc_coherent(&pdev->dev, IPG_TX_RING_BYTES,
+				     &sp->txd_map, GFP_KERNEL);
+	if (!sp->txd)
+		goto err_free_rx_1;
+
+	rc = init_rfdlist(dev);
+	if (rc < 0) {
+		printk(KERN_INFO "%s: Error during configuration.\n",
+		       dev->name);
+		goto err_free_tx_2;
+	}
+
+	init_tfdlist(dev);
+
+	rc = ipg_io_config(dev);
+	if (rc < 0) {
+		printk(KERN_INFO "%s: Error during configuration.\n",
+		       dev->name);
+		goto err_release_tfdlist_3;
+	}
+
+	/* Resolve autonegotiation. */
+	if (ipg_config_autoneg(dev) < 0)
+		printk(KERN_INFO "%s: Auto-negotiation error.\n", dev->name);
+
+#ifdef JUMBO_FRAME
+	/* initialize JUMBO Frame control variable */
+	sp->Jumbo.FoundStart = 0;
+	sp->Jumbo.CurrentSize = 0;
+	sp->Jumbo.skb = 0;
+	dev->mtu = IPG_TXFRAG_SIZE;
+#endif
+
+	/* Enable transmit and receive operation of the IPG. */
+	ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_RX_ENABLE | IPG_MC_TX_ENABLE) &
+		 IPG_MC_RSVD_MASK, MAC_CTRL);
+
+	netif_start_queue(dev);
+out:
+	return rc;
+
+err_release_tfdlist_3:
+	ipg_tx_clear(sp);
+	ipg_rx_clear(sp);
+err_free_tx_2:
+	dma_free_coherent(&pdev->dev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map);
+err_free_rx_1:
+	dma_free_coherent(&pdev->dev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map);
+err_free_irq_0:
+	free_irq(pdev->irq, dev);
+	goto out;
+}
+
+static int ipg_nic_stop(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	struct pci_dev *pdev = sp->pdev;
+
+	IPG_DEBUG_MSG("_nic_stop\n");
+
+	netif_stop_queue(dev);
+
+	IPG_DDEBUG_MSG("RFDlistendCount = %i\n", sp->RFDlistendCount);
+	IPG_DDEBUG_MSG("RFDListCheckedCount = %i\n", sp->rxdCheckedCount);
+	IPG_DDEBUG_MSG("EmptyRFDListCount = %i\n", sp->EmptyRFDListCount);
+	IPG_DUMPTFDLIST(dev);
+
+	do {
+		(void) ipg_r16(INT_STATUS_ACK);
+
+		ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA);
+
+		synchronize_irq(pdev->irq);
+	} while (ipg_r16(INT_ENABLE) & IPG_IE_RSVD_MASK);
+
+	ipg_rx_clear(sp);
+
+	ipg_tx_clear(sp);
+
+	pci_free_consistent(pdev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map);
+	pci_free_consistent(pdev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map);
+
+	free_irq(pdev->irq, dev);
+
+	return 0;
+}
+
+static int ipg_nic_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int entry = sp->tx_current % IPG_TFDLIST_LENGTH;
+	unsigned long flags;
+	struct ipg_tx *txfd;
+
+	IPG_DDEBUG_MSG("_nic_hard_start_xmit\n");
+
+	/* If in 10Mbps mode, stop the transmit queue so
+	 * no more transmit frames are accepted.
+	 */
+	if (sp->tenmbpsmode)
+		netif_stop_queue(dev);
+
+	if (sp->ResetCurrentTFD) {
+		sp->ResetCurrentTFD = 0;
+		entry = 0;
+	}
+
+	txfd = sp->txd + entry;
+
+	sp->TxBuff[entry] = skb;
+
+	/* Clear all TFC fields, except TFDDONE. */
+	txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE);
+
+	/* Specify the TFC field within the TFD. */
+	txfd->tfc |= cpu_to_le64(IPG_TFC_WORDALIGNDISABLED |
+		(IPG_TFC_FRAMEID & cpu_to_le64(sp->tx_current)) |
+		(IPG_TFC_FRAGCOUNT & (1 << 24)));
+
+	/* Request TxComplete interrupts at an interval defined
+	 * by the constant IPG_FRAMESBETWEENTXCOMPLETES.
+	 * Request TxComplete interrupt for every frame
+	 * if in 10Mbps mode to accomodate problem with 10Mbps
+	 * processing.
+	 */
+	if (sp->tenmbpsmode)
+		txfd->tfc |= cpu_to_le64(IPG_TFC_TXINDICATE);
+	else if (!((sp->tx_current - sp->tx_dirty + 1) >
+	    IPG_FRAMESBETWEENTXDMACOMPLETES)) {
+		txfd->tfc |= cpu_to_le64(IPG_TFC_TXDMAINDICATE);
+	}
+	/* Based on compilation option, determine if FCS is to be
+	 * appended to transmit frame by IPG.
+	 */
+	if (!(IPG_APPEND_FCS_ON_TX))
+		txfd->tfc |= cpu_to_le64(IPG_TFC_FCSAPPENDDISABLE);
+
+	/* Based on compilation option, determine if IP, TCP and/or
+	 * UDP checksums are to be added to transmit frame by IPG.
+	 */
+	if (IPG_ADD_IPCHECKSUM_ON_TX)
+		txfd->tfc |= cpu_to_le64(IPG_TFC_IPCHECKSUMENABLE);
+
+	if (IPG_ADD_TCPCHECKSUM_ON_TX)
+		txfd->tfc |= cpu_to_le64(IPG_TFC_TCPCHECKSUMENABLE);
+
+	if (IPG_ADD_UDPCHECKSUM_ON_TX)
+		txfd->tfc |= cpu_to_le64(IPG_TFC_UDPCHECKSUMENABLE);
+
+	/* Based on compilation option, determine if VLAN tag info is to be
+	 * inserted into transmit frame by IPG.
+	 */
+	if (IPG_INSERT_MANUAL_VLAN_TAG) {
+		txfd->tfc |= cpu_to_le64(IPG_TFC_VLANTAGINSERT |
+			((u64) IPG_MANUAL_VLAN_VID << 32) |
+			((u64) IPG_MANUAL_VLAN_CFI << 44) |
+			((u64) IPG_MANUAL_VLAN_USERPRIORITY << 45));
+	}
+
+	/* The fragment start location within system memory is defined
+	 * by the sk_buff structure's data field. The physical address
+	 * of this location within the system's virtual memory space
+	 * is determined using the IPG_HOST2BUS_MAP function.
+	 */
+	txfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data,
+		skb->len, PCI_DMA_TODEVICE));
+
+	/* The length of the fragment within system memory is defined by
+	 * the sk_buff structure's len field.
+	 */
+	txfd->frag_info |= cpu_to_le64(IPG_TFI_FRAGLEN &
+		((u64) (skb->len & 0xffff) << 48));
+
+	/* Clear the TFDDone bit last to indicate the TFD is ready
+	 * for transfer to the IPG.
+	 */
+	txfd->tfc &= cpu_to_le64(~IPG_TFC_TFDDONE);
+
+	spin_lock_irqsave(&sp->lock, flags);
+
+	sp->tx_current++;
+
+	mmiowb();
+
+	ipg_w32(IPG_DC_TX_DMA_POLL_NOW, DMA_CTRL);
+
+	if (sp->tx_current == (sp->tx_dirty + IPG_TFDLIST_LENGTH))
+		netif_wake_queue(dev);
+
+	spin_unlock_irqrestore(&sp->lock, flags);
+
+	return NETDEV_TX_OK;
+}
+
+static void ipg_set_phy_default_param(unsigned char rev,
+				      struct net_device *dev, int phy_address)
+{
+	unsigned short length;
+	unsigned char revision;
+	unsigned short *phy_param;
+	unsigned short address, value;
+
+	phy_param = &DefaultPhyParam[0];
+	length = *phy_param & 0x00FF;
+	revision = (unsigned char)((*phy_param) >> 8);
+	phy_param++;
+	while (length != 0) {
+		if (rev == revision) {
+			while (length > 1) {
+				address = *phy_param;
+				value = *(phy_param + 1);
+				phy_param += 2;
+				mdio_write(dev, phy_address, address, value);
+				length -= 4;
+			}
+			break;
+		} else {
+			phy_param += length / 2;
+			length = *phy_param & 0x00FF;
+			revision = (unsigned char)((*phy_param) >> 8);
+			phy_param++;
+		}
+	}
+}
+
+/* JES20040127EEPROM */
+static int read_eeprom(struct net_device *dev, int eep_addr)
+{
+	void __iomem *ioaddr = ipg_ioaddr(dev);
+	unsigned int i;
+	int ret = 0;
+	u16 value;
+
+	value = IPG_EC_EEPROM_READOPCODE | (eep_addr & 0xff);
+	ipg_w16(value, EEPROM_CTRL);
+
+	for (i = 0; i < 1000; i++) {
+		u16 data;
+
+		mdelay(10);
+		data = ipg_r16(EEPROM_CTRL);
+		if (!(data & IPG_EC_EEPROM_BUSY)) {
+			ret = ipg_r16(EEPROM_DATA);
+			break;
+		}
+	}
+	return ret;
+}
+
+static void ipg_init_mii(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	struct mii_if_info *mii_if = &sp->mii_if;
+	int phyaddr;
+
+	mii_if->dev          = dev;
+	mii_if->mdio_read    = mdio_read;
+	mii_if->mdio_write   = mdio_write;
+	mii_if->phy_id_mask  = 0x1f;
+	mii_if->reg_num_mask = 0x1f;
+
+	mii_if->phy_id = phyaddr = ipg_find_phyaddr(dev);
+
+	if (phyaddr != 0x1f) {
+		u16 mii_phyctrl, mii_1000cr;
+		u8 revisionid = 0;
+
+		mii_1000cr  = mdio_read(dev, phyaddr, MII_CTRL1000);
+		mii_1000cr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF |
+			GMII_PHY_1000BASETCONTROL_PreferMaster;
+		mdio_write(dev, phyaddr, MII_CTRL1000, mii_1000cr);
+
+		mii_phyctrl = mdio_read(dev, phyaddr, MII_BMCR);
+
+		/* Set default phyparam */
+		pci_read_config_byte(sp->pdev, PCI_REVISION_ID, &revisionid);
+		ipg_set_phy_default_param(revisionid, dev, phyaddr);
+
+		/* Reset PHY */
+		mii_phyctrl |= BMCR_RESET | BMCR_ANRESTART;
+		mdio_write(dev, phyaddr, MII_BMCR, mii_phyctrl);
+
+	}
+}
+
+static int ipg_hw_init(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	void __iomem *ioaddr = sp->ioaddr;
+	unsigned int i;
+	int rc;
+
+	/* Read/Write and Reset EEPROM Value Jesse20040128EEPROM_VALUE */
+	/* Read LED Mode Configuration from EEPROM */
+	sp->LED_Mode = read_eeprom(dev, 6);
+
+	/* Reset all functions within the IPG. Do not assert
+	 * RST_OUT as not compatible with some PHYs.
+	 */
+	rc = ipg_reset(dev, IPG_RESET_MASK);
+	if (rc < 0)
+		goto out;
+
+	ipg_init_mii(dev);
+
+	/* Read MAC Address from EEPROM */
+	for (i = 0; i < 3; i++)
+		sp->station_addr[i] = read_eeprom(dev, 16 + i);
+
+	for (i = 0; i < 3; i++)
+		ipg_w16(sp->station_addr[i], STATION_ADDRESS_0 + 2*i);
+
+	/* Set station address in ethernet_device structure. */
+	dev->dev_addr[0] =  ipg_r16(STATION_ADDRESS_0) & 0x00ff;
+	dev->dev_addr[1] = (ipg_r16(STATION_ADDRESS_0) & 0xff00) >> 8;
+	dev->dev_addr[2] =  ipg_r16(STATION_ADDRESS_1) & 0x00ff;
+	dev->dev_addr[3] = (ipg_r16(STATION_ADDRESS_1) & 0xff00) >> 8;
+	dev->dev_addr[4] =  ipg_r16(STATION_ADDRESS_2) & 0x00ff;
+	dev->dev_addr[5] = (ipg_r16(STATION_ADDRESS_2) & 0xff00) >> 8;
+out:
+	return rc;
+}
+
+static int ipg_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	int rc;
+
+	mutex_lock(&sp->mii_mutex);
+	rc = generic_mii_ioctl(&sp->mii_if, if_mii(ifr), cmd, NULL);
+	mutex_unlock(&sp->mii_mutex);
+
+	return rc;
+}
+
+static int ipg_nic_change_mtu(struct net_device *dev, int new_mtu)
+{
+	/* Function to accomodate changes to Maximum Transfer Unit
+	 * (or MTU) of IPG NIC. Cannot use default function since
+	 * the default will not allow for MTU > 1500 bytes.
+	 */
+
+	IPG_DEBUG_MSG("_nic_change_mtu\n");
+
+	/* Check that the new MTU value is between 68 (14 byte header, 46
+	 * byte payload, 4 byte FCS) and IPG_MAX_RXFRAME_SIZE, which
+	 * corresponds to the MAXFRAMESIZE register in the IPG.
+	 */
+	if ((new_mtu < 68) || (new_mtu > IPG_MAX_RXFRAME_SIZE))
+		return -EINVAL;
+
+	dev->mtu = new_mtu;
+
+	return 0;
+}
+
+static int ipg_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	int rc;
+
+	mutex_lock(&sp->mii_mutex);
+	rc = mii_ethtool_gset(&sp->mii_if, cmd);
+	mutex_unlock(&sp->mii_mutex);
+
+	return rc;
+}
+
+static int ipg_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	int rc;
+
+	mutex_lock(&sp->mii_mutex);
+	rc = mii_ethtool_sset(&sp->mii_if, cmd);
+	mutex_unlock(&sp->mii_mutex);
+
+	return rc;
+}
+
+static int ipg_nway_reset(struct net_device *dev)
+{
+	struct ipg_nic_private *sp = netdev_priv(dev);
+	int rc;
+
+	mutex_lock(&sp->mii_mutex);
+	rc = mii_nway_restart(&sp->mii_if);
+	mutex_unlock(&sp->mii_mutex);
+
+	return rc;
+}
+
+static struct ethtool_ops ipg_ethtool_ops = {
+	.get_settings = ipg_get_settings,
+	.set_settings = ipg_set_settings,
+	.nway_reset   = ipg_nway_reset,
+};
+
+static void ipg_remove(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct ipg_nic_private *sp = netdev_priv(dev);
+
+	IPG_DEBUG_MSG("_remove\n");
+
+	/* Un-register Ethernet device. */
+	unregister_netdev(dev);
+
+	pci_iounmap(pdev, sp->ioaddr);
+
+	pci_release_regions(pdev);
+
+	free_netdev(dev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+}
+
+static int __devinit ipg_probe(struct pci_dev *pdev,
+			       const struct pci_device_id *id)
+{
+	unsigned int i = id->driver_data;
+	struct ipg_nic_private *sp;
+	struct net_device *dev;
+	void __iomem *ioaddr;
+	int rc;
+
+	rc = pci_enable_device(pdev);
+	if (rc < 0)
+		goto out;
+
+	printk(KERN_INFO "%s: %s\n", pci_name(pdev), ipg_brand_name[i]);
+
+	pci_set_master(pdev);
+
+	rc = pci_set_dma_mask(pdev, DMA_40BIT_MASK);
+	if (rc < 0) {
+		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+		if (rc < 0) {
+			printk(KERN_ERR "%s: DMA config failed.\n",
+			       pci_name(pdev));
+			goto err_disable_0;
+		}
+	}
+
+	/*
+	 * Initialize net device.
+	 */
+	dev = alloc_etherdev(sizeof(struct ipg_nic_private));
+	if (!dev) {
+		printk(KERN_ERR "%s: alloc_etherdev failed\n", pci_name(pdev));
+		rc = -ENOMEM;
+		goto err_disable_0;
+	}
+
+	sp = netdev_priv(dev);
+	spin_lock_init(&sp->lock);
+	mutex_init(&sp->mii_mutex);
+
+	/* Declare IPG NIC functions for Ethernet device methods.
+	 */
+	dev->open = &ipg_nic_open;
+	dev->stop = &ipg_nic_stop;
+	dev->hard_start_xmit = &ipg_nic_hard_start_xmit;
+	dev->get_stats = &ipg_nic_get_stats;
+	dev->set_multicast_list = &ipg_nic_set_multicast_list;
+	dev->do_ioctl = ipg_ioctl;
+	dev->tx_timeout = ipg_tx_timeout;
+	dev->change_mtu = &ipg_nic_change_mtu;
+
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	SET_ETHTOOL_OPS(dev, &ipg_ethtool_ops);
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_free_dev_1;
+
+	ioaddr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1));
+	if (!ioaddr) {
+		printk(KERN_ERR "%s cannot map MMIO\n", pci_name(pdev));
+		rc = -EIO;
+		goto err_release_regions_2;
+	}
+
+	/* Save the pointer to the PCI device information. */
+	sp->ioaddr = ioaddr;
+	sp->pdev = pdev;
+	sp->dev = dev;
+
+	INIT_DELAYED_WORK(&sp->task, ipg_reset_after_host_error);
+
+	pci_set_drvdata(pdev, dev);
+
+	rc = ipg_hw_init(dev);
+	if (rc < 0)
+		goto err_unmap_3;
+
+	rc = register_netdev(dev);
+	if (rc < 0)
+		goto err_unmap_3;
+
+	printk(KERN_INFO "Ethernet device registered as: %s\n", dev->name);
+out:
+	return rc;
+
+err_unmap_3:
+	pci_iounmap(pdev, ioaddr);
+err_release_regions_2:
+	pci_release_regions(pdev);
+err_free_dev_1:
+	free_netdev(dev);
+err_disable_0:
+	pci_disable_device(pdev);
+	goto out;
+}
+
+static struct pci_driver ipg_pci_driver = {
+	.name		= IPG_DRIVER_NAME,
+	.id_table	= ipg_pci_tbl,
+	.probe		= ipg_probe,
+	.remove		= __devexit_p(ipg_remove),
+};
+
+static int __init ipg_init_module(void)
+{
+	return pci_register_driver(&ipg_pci_driver);
+}
+
+static void __exit ipg_exit_module(void)
+{
+	pci_unregister_driver(&ipg_pci_driver);
+}
+
+module_init(ipg_init_module);
+module_exit(ipg_exit_module);
diff --git a/drivers/net/ipg.h b/drivers/net/ipg.h
new file mode 100644
index 0000000..1952d0d
--- /dev/null
+++ b/drivers/net/ipg.h
@@ -0,0 +1,856 @@
+/*
+ *
+ * ipg.h
+ *
+ * Include file for Gigabit Ethernet device driver for Network
+ * Interface Cards (NICs) utilizing the Tamarack Microelectronics
+ * Inc. IPG Gigabit or Triple Speed Ethernet Media Access
+ * Controller.
+ *
+ * Craig Rich
+ * Sundance Technology, Inc.
+ * 1485 Saratoga Avenue
+ * Suite 200
+ * San Jose, CA 95129
+ * 408 873 4117
+ * www.sundanceti.com
+ * craig_rich@sundanceti.com
+ */
+#ifndef __LINUX_IPG_H
+#define __LINUX_IPG_H
+
+#include <linux/version.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/version.h>
+#include <asm/bitops.h>
+/*#include <asm/spinlock.h>*/
+
+#define DrvVer "2.09d"
+
+#define IPG_DEV_KFREE_SKB(skb) dev_kfree_skb_irq(skb)
+
+/*
+ *	Constants
+ */
+
+/* GMII based PHY IDs */
+#define		NS				0x2000
+#define		MARVELL				0x0141
+#define		ICPLUS_PHY		0x243
+
+/* NIC Physical Layer Device MII register fields. */
+#define         MII_PHY_SELECTOR_IEEE8023       0x0001
+#define         MII_PHY_TECHABILITYFIELD        0x1FE0
+
+/* GMII_PHY_1000 need to set to prefer master */
+#define         GMII_PHY_1000BASETCONTROL_PreferMaster 0x0400
+
+/* NIC Physical Layer Device GMII constants. */
+#define         GMII_PREAMBLE                    0xFFFFFFFF
+#define         GMII_ST                          0x1
+#define         GMII_READ                        0x2
+#define         GMII_WRITE                       0x1
+#define         GMII_TA_READ_MASK                0x1
+#define         GMII_TA_WRITE                    0x2
+
+/* I/O register offsets. */
+enum ipg_regs {
+	DMA_CTRL		= 0x00,
+	RX_DMA_STATUS		= 0x08, // Unused + reserved
+	TFD_LIST_PTR_0		= 0x10,
+	TFD_LIST_PTR_1		= 0x14,
+	TX_DMA_BURST_THRESH	= 0x18,
+	TX_DMA_URGENT_THRESH	= 0x19,
+	TX_DMA_POLL_PERIOD	= 0x1a,
+	RFD_LIST_PTR_0		= 0x1c,
+	RFD_LIST_PTR_1		= 0x20,
+	RX_DMA_BURST_THRESH	= 0x24,
+	RX_DMA_URGENT_THRESH	= 0x25,
+	RX_DMA_POLL_PERIOD	= 0x26,
+	DEBUG_CTRL		= 0x2c,
+	ASIC_CTRL		= 0x30,
+	FIFO_CTRL		= 0x38, // Unused
+	FLOW_OFF_THRESH		= 0x3c,
+	FLOW_ON_THRESH		= 0x3e,
+	EEPROM_DATA		= 0x48,
+	EEPROM_CTRL		= 0x4a,
+	EXPROM_ADDR		= 0x4c, // Unused
+	EXPROM_DATA		= 0x50, // Unused
+	WAKE_EVENT		= 0x51, // Unused
+	COUNTDOWN		= 0x54, // Unused
+	INT_STATUS_ACK		= 0x5a,
+	INT_ENABLE		= 0x5c,
+	INT_STATUS		= 0x5e, // Unused
+	TX_STATUS		= 0x60,
+	MAC_CTRL		= 0x6c,
+	VLAN_TAG		= 0x70, // Unused
+	PHY_SET			= 0x75,	// JES20040127EEPROM
+	PHY_CTRL		= 0x76,
+	STATION_ADDRESS_0	= 0x78,
+	STATION_ADDRESS_1	= 0x7a,
+	STATION_ADDRESS_2	= 0x7c,
+	MAX_FRAME_SIZE		= 0x86,
+	RECEIVE_MODE		= 0x88,
+	HASHTABLE_0		= 0x8c,
+	HASHTABLE_1		= 0x90,
+	RMON_STATISTICS_MASK	= 0x98,
+	STATISTICS_MASK		= 0x9c,
+	RX_JUMBO_FRAMES		= 0xbc, // Unused
+	TCP_CHECKSUM_ERRORS	= 0xc0, // Unused
+	IP_CHECKSUM_ERRORS	= 0xc2, // Unused
+	UDP_CHECKSUM_ERRORS	= 0xc4, // Unused
+	TX_JUMBO_FRAMES		= 0xf4  // Unused
+};
+
+/* Ethernet MIB statistic register offsets. */
+#define	IPG_OCTETRCVOK		0xA8
+#define	IPG_MCSTOCTETRCVDOK		0xAC
+#define	IPG_BCSTOCTETRCVOK		0xB0
+#define	IPG_FRAMESRCVDOK		0xB4
+#define	IPG_MCSTFRAMESRCVDOK		0xB8
+#define	IPG_BCSTFRAMESRCVDOK		0xBE
+#define	IPG_MACCONTROLFRAMESRCVD	0xC6
+#define	IPG_FRAMETOOLONGERRRORS	0xC8
+#define	IPG_INRANGELENGTHERRORS	0xCA
+#define	IPG_FRAMECHECKSEQERRORS	0xCC
+#define	IPG_FRAMESLOSTRXERRORS	0xCE
+#define	IPG_OCTETXMTOK		0xD0
+#define	IPG_MCSTOCTETXMTOK		0xD4
+#define	IPG_BCSTOCTETXMTOK		0xD8
+#define	IPG_FRAMESXMTDOK		0xDC
+#define	IPG_MCSTFRAMESXMTDOK		0xE0
+#define	IPG_FRAMESWDEFERREDXMT	0xE4
+#define	IPG_LATECOLLISIONS		0xE8
+#define	IPG_MULTICOLFRAMES		0xEC
+#define	IPG_SINGLECOLFRAMES		0xF0
+#define	IPG_BCSTFRAMESXMTDOK		0xF6
+#define	IPG_CARRIERSENSEERRORS	0xF8
+#define	IPG_MACCONTROLFRAMESXMTDOK	0xFA
+#define	IPG_FRAMESABORTXSCOLLS	0xFC
+#define	IPG_FRAMESWEXDEFERRAL	0xFE
+
+/* RMON statistic register offsets. */
+#define	IPG_ETHERSTATSCOLLISIONS			0x100
+#define	IPG_ETHERSTATSOCTETSTRANSMIT			0x104
+#define	IPG_ETHERSTATSPKTSTRANSMIT			0x108
+#define	IPG_ETHERSTATSPKTS64OCTESTSTRANSMIT		0x10C
+#define	IPG_ETHERSTATSPKTS65TO127OCTESTSTRANSMIT	0x110
+#define	IPG_ETHERSTATSPKTS128TO255OCTESTSTRANSMIT	0x114
+#define	IPG_ETHERSTATSPKTS256TO511OCTESTSTRANSMIT	0x118
+#define	IPG_ETHERSTATSPKTS512TO1023OCTESTSTRANSMIT	0x11C
+#define	IPG_ETHERSTATSPKTS1024TO1518OCTESTSTRANSMIT	0x120
+#define	IPG_ETHERSTATSCRCALIGNERRORS			0x124
+#define	IPG_ETHERSTATSUNDERSIZEPKTS			0x128
+#define	IPG_ETHERSTATSFRAGMENTS			0x12C
+#define	IPG_ETHERSTATSJABBERS			0x130
+#define	IPG_ETHERSTATSOCTETS				0x134
+#define	IPG_ETHERSTATSPKTS				0x138
+#define	IPG_ETHERSTATSPKTS64OCTESTS			0x13C
+#define	IPG_ETHERSTATSPKTS65TO127OCTESTS		0x140
+#define	IPG_ETHERSTATSPKTS128TO255OCTESTS		0x144
+#define	IPG_ETHERSTATSPKTS256TO511OCTESTS		0x148
+#define	IPG_ETHERSTATSPKTS512TO1023OCTESTS		0x14C
+#define	IPG_ETHERSTATSPKTS1024TO1518OCTESTS		0x150
+
+/* RMON statistic register equivalents. */
+#define	IPG_ETHERSTATSMULTICASTPKTSTRANSMIT		0xE0
+#define	IPG_ETHERSTATSBROADCASTPKTSTRANSMIT		0xF6
+#define	IPG_ETHERSTATSMULTICASTPKTS			0xB8
+#define	IPG_ETHERSTATSBROADCASTPKTS			0xBE
+#define	IPG_ETHERSTATSOVERSIZEPKTS			0xC8
+#define	IPG_ETHERSTATSDROPEVENTS			0xCE
+
+/* Serial EEPROM offsets */
+#define	IPG_EEPROM_CONFIGPARAM	0x00
+#define	IPG_EEPROM_ASICCTRL		0x01
+#define	IPG_EEPROM_SUBSYSTEMVENDORID	0x02
+#define	IPG_EEPROM_SUBSYSTEMID	0x03
+#define	IPG_EEPROM_STATIONADDRESS0	0x10
+#define	IPG_EEPROM_STATIONADDRESS1	0x11
+#define	IPG_EEPROM_STATIONADDRESS2	0x12
+
+/* Register & data structure bit masks */
+
+/* PCI register masks. */
+
+/* IOBaseAddress */
+#define         IPG_PIB_RSVD_MASK		0xFFFFFE01
+#define         IPG_PIB_IOBASEADDRESS	0xFFFFFF00
+#define         IPG_PIB_IOBASEADDRIND	0x00000001
+
+/* MemBaseAddress */
+#define         IPG_PMB_RSVD_MASK		0xFFFFFE07
+#define         IPG_PMB_MEMBASEADDRIND	0x00000001
+#define         IPG_PMB_MEMMAPTYPE		0x00000006
+#define         IPG_PMB_MEMMAPTYPE0		0x00000002
+#define         IPG_PMB_MEMMAPTYPE1		0x00000004
+#define         IPG_PMB_MEMBASEADDRESS	0xFFFFFE00
+
+/* ConfigStatus */
+#define IPG_CS_RSVD_MASK                0xFFB0
+#define IPG_CS_CAPABILITIES             0x0010
+#define IPG_CS_66MHZCAPABLE             0x0020
+#define IPG_CS_FASTBACK2BACK            0x0080
+#define IPG_CS_DATAPARITYREPORTED       0x0100
+#define IPG_CS_DEVSELTIMING             0x0600
+#define IPG_CS_SIGNALEDTARGETABORT      0x0800
+#define IPG_CS_RECEIVEDTARGETABORT      0x1000
+#define IPG_CS_RECEIVEDMASTERABORT      0x2000
+#define IPG_CS_SIGNALEDSYSTEMERROR      0x4000
+#define IPG_CS_DETECTEDPARITYERROR      0x8000
+
+/* TFD data structure masks. */
+
+/* TFDList, TFC */
+#define	IPG_TFC_RSVD_MASK			0x0000FFFF9FFFFFFF
+#define	IPG_TFC_FRAMEID			0x000000000000FFFF
+#define	IPG_TFC_WORDALIGN			0x0000000000030000
+#define	IPG_TFC_WORDALIGNTODWORD		0x0000000000000000
+#define	IPG_TFC_WORDALIGNTOWORD		0x0000000000020000
+#define	IPG_TFC_WORDALIGNDISABLED		0x0000000000030000
+#define	IPG_TFC_TCPCHECKSUMENABLE		0x0000000000040000
+#define	IPG_TFC_UDPCHECKSUMENABLE		0x0000000000080000
+#define	IPG_TFC_IPCHECKSUMENABLE		0x0000000000100000
+#define	IPG_TFC_FCSAPPENDDISABLE		0x0000000000200000
+#define	IPG_TFC_TXINDICATE			0x0000000000400000
+#define	IPG_TFC_TXDMAINDICATE		0x0000000000800000
+#define	IPG_TFC_FRAGCOUNT			0x000000000F000000
+#define	IPG_TFC_VLANTAGINSERT		0x0000000010000000
+#define	IPG_TFC_TFDDONE			0x0000000080000000
+#define	IPG_TFC_VID				0x00000FFF00000000
+#define	IPG_TFC_CFI				0x0000100000000000
+#define	IPG_TFC_USERPRIORITY			0x0000E00000000000
+
+/* TFDList, FragInfo */
+#define	IPG_TFI_RSVD_MASK			0xFFFF00FFFFFFFFFF
+#define	IPG_TFI_FRAGADDR			0x000000FFFFFFFFFF
+#define	IPG_TFI_FRAGLEN			0xFFFF000000000000LL
+
+/* RFD data structure masks. */
+
+/* RFDList, RFS */
+#define	IPG_RFS_RSVD_MASK			0x0000FFFFFFFFFFFF
+#define	IPG_RFS_RXFRAMELEN			0x000000000000FFFF
+#define	IPG_RFS_RXFIFOOVERRUN		0x0000000000010000
+#define	IPG_RFS_RXRUNTFRAME			0x0000000000020000
+#define	IPG_RFS_RXALIGNMENTERROR		0x0000000000040000
+#define	IPG_RFS_RXFCSERROR			0x0000000000080000
+#define	IPG_RFS_RXOVERSIZEDFRAME		0x0000000000100000
+#define	IPG_RFS_RXLENGTHERROR		0x0000000000200000
+#define	IPG_RFS_VLANDETECTED			0x0000000000400000
+#define	IPG_RFS_TCPDETECTED			0x0000000000800000
+#define	IPG_RFS_TCPERROR			0x0000000001000000
+#define	IPG_RFS_UDPDETECTED			0x0000000002000000
+#define	IPG_RFS_UDPERROR			0x0000000004000000
+#define	IPG_RFS_IPDETECTED			0x0000000008000000
+#define	IPG_RFS_IPERROR			0x0000000010000000
+#define	IPG_RFS_FRAMESTART			0x0000000020000000
+#define	IPG_RFS_FRAMEEND			0x0000000040000000
+#define	IPG_RFS_RFDDONE			0x0000000080000000
+#define	IPG_RFS_TCI				0x0000FFFF00000000
+
+/* RFDList, FragInfo */
+#define	IPG_RFI_RSVD_MASK			0xFFFF00FFFFFFFFFF
+#define	IPG_RFI_FRAGADDR			0x000000FFFFFFFFFF
+#define	IPG_RFI_FRAGLEN			0xFFFF000000000000LL
+
+/* I/O Register masks. */
+
+/* RMON Statistics Mask */
+#define	IPG_RZ_ALL					0x0FFFFFFF
+
+/* Statistics Mask */
+#define	IPG_SM_ALL					0x0FFFFFFF
+#define	IPG_SM_OCTETRCVOK_FRAMESRCVDOK		0x00000001
+#define	IPG_SM_MCSTOCTETRCVDOK_MCSTFRAMESRCVDOK	0x00000002
+#define	IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK	0x00000004
+#define	IPG_SM_RXJUMBOFRAMES				0x00000008
+#define	IPG_SM_TCPCHECKSUMERRORS			0x00000010
+#define	IPG_SM_IPCHECKSUMERRORS			0x00000020
+#define	IPG_SM_UDPCHECKSUMERRORS			0x00000040
+#define	IPG_SM_MACCONTROLFRAMESRCVD			0x00000080
+#define	IPG_SM_FRAMESTOOLONGERRORS			0x00000100
+#define	IPG_SM_INRANGELENGTHERRORS			0x00000200
+#define	IPG_SM_FRAMECHECKSEQERRORS			0x00000400
+#define	IPG_SM_FRAMESLOSTRXERRORS			0x00000800
+#define	IPG_SM_OCTETXMTOK_FRAMESXMTOK		0x00001000
+#define	IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK	0x00002000
+#define	IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK	0x00004000
+#define	IPG_SM_FRAMESWDEFERREDXMT			0x00008000
+#define	IPG_SM_LATECOLLISIONS			0x00010000
+#define	IPG_SM_MULTICOLFRAMES			0x00020000
+#define	IPG_SM_SINGLECOLFRAMES			0x00040000
+#define	IPG_SM_TXJUMBOFRAMES				0x00080000
+#define	IPG_SM_CARRIERSENSEERRORS			0x00100000
+#define	IPG_SM_MACCONTROLFRAMESXMTD			0x00200000
+#define	IPG_SM_FRAMESABORTXSCOLLS			0x00400000
+#define	IPG_SM_FRAMESWEXDEFERAL			0x00800000
+
+/* Countdown */
+#define	IPG_CD_RSVD_MASK		0x0700FFFF
+#define	IPG_CD_COUNT			0x0000FFFF
+#define	IPG_CD_COUNTDOWNSPEED	0x01000000
+#define	IPG_CD_COUNTDOWNMODE		0x02000000
+#define	IPG_CD_COUNTINTENABLED	0x04000000
+
+/* TxDMABurstThresh */
+#define IPG_TB_RSVD_MASK                0xFF
+
+/* TxDMAUrgentThresh */
+#define IPG_TU_RSVD_MASK                0xFF
+
+/* TxDMAPollPeriod */
+#define IPG_TP_RSVD_MASK                0xFF
+
+/* RxDMAUrgentThresh */
+#define IPG_RU_RSVD_MASK                0xFF
+
+/* RxDMAPollPeriod */
+#define IPG_RP_RSVD_MASK                0xFF
+
+/* ReceiveMode */
+#define IPG_RM_RSVD_MASK                0x3F
+#define IPG_RM_RECEIVEUNICAST           0x01
+#define IPG_RM_RECEIVEMULTICAST         0x02
+#define IPG_RM_RECEIVEBROADCAST         0x04
+#define IPG_RM_RECEIVEALLFRAMES         0x08
+#define IPG_RM_RECEIVEMULTICASTHASH     0x10
+#define IPG_RM_RECEIVEIPMULTICAST       0x20
+
+/* PhySet JES20040127EEPROM*/
+#define IPG_PS_MEM_LENB9B               0x01
+#define IPG_PS_MEM_LEN9                 0x02
+#define IPG_PS_NON_COMPDET              0x04
+
+/* PhyCtrl */
+#define IPG_PC_RSVD_MASK                0xFF
+#define IPG_PC_MGMTCLK_LO               0x00
+#define IPG_PC_MGMTCLK_HI               0x01
+#define IPG_PC_MGMTCLK                  0x01
+#define IPG_PC_MGMTDATA                 0x02
+#define IPG_PC_MGMTDIR                  0x04
+#define IPG_PC_DUPLEX_POLARITY          0x08
+#define IPG_PC_DUPLEX_STATUS            0x10
+#define IPG_PC_LINK_POLARITY            0x20
+#define IPG_PC_LINK_SPEED               0xC0
+#define IPG_PC_LINK_SPEED_10MBPS        0x40
+#define IPG_PC_LINK_SPEED_100MBPS       0x80
+#define IPG_PC_LINK_SPEED_1000MBPS      0xC0
+
+/* DMACtrl */
+#define IPG_DC_RSVD_MASK                0xC07D9818
+#define IPG_DC_RX_DMA_COMPLETE          0x00000008
+#define IPG_DC_RX_DMA_POLL_NOW          0x00000010
+#define IPG_DC_TX_DMA_COMPLETE          0x00000800
+#define IPG_DC_TX_DMA_POLL_NOW          0x00001000
+#define IPG_DC_TX_DMA_IN_PROG           0x00008000
+#define IPG_DC_RX_EARLY_DISABLE         0x00010000
+#define IPG_DC_MWI_DISABLE              0x00040000
+#define IPG_DC_TX_WRITE_BACK_DISABLE    0x00080000
+#define IPG_DC_TX_BURST_LIMIT           0x00700000
+#define IPG_DC_TARGET_ABORT             0x40000000
+#define IPG_DC_MASTER_ABORT             0x80000000
+
+/* ASICCtrl */
+#define IPG_AC_RSVD_MASK                0x07FFEFF2
+#define IPG_AC_EXP_ROM_SIZE             0x00000002
+#define IPG_AC_PHY_SPEED10              0x00000010
+#define IPG_AC_PHY_SPEED100             0x00000020
+#define IPG_AC_PHY_SPEED1000            0x00000040
+#define IPG_AC_PHY_MEDIA                0x00000080
+#define IPG_AC_FORCED_CFG               0x00000700
+#define IPG_AC_D3RESETDISABLE           0x00000800
+#define IPG_AC_SPEED_UP_MODE            0x00002000
+#define IPG_AC_LED_MODE                 0x00004000
+#define IPG_AC_RST_OUT_POLARITY         0x00008000
+#define IPG_AC_GLOBAL_RESET             0x00010000
+#define IPG_AC_RX_RESET                 0x00020000
+#define IPG_AC_TX_RESET                 0x00040000
+#define IPG_AC_DMA                      0x00080000
+#define IPG_AC_FIFO                     0x00100000
+#define IPG_AC_NETWORK                  0x00200000
+#define IPG_AC_HOST                     0x00400000
+#define IPG_AC_AUTO_INIT                0x00800000
+#define IPG_AC_RST_OUT                  0x01000000
+#define IPG_AC_INT_REQUEST              0x02000000
+#define IPG_AC_RESET_BUSY               0x04000000
+#define IPG_AC_LED_SPEED                0x08000000	//JES20040127EEPROM
+#define IPG_AC_LED_MODE_BIT_1           0x20000000	//JES20040127EEPROM
+
+/* EepromCtrl */
+#define IPG_EC_RSVD_MASK                0x83FF
+#define IPG_EC_EEPROM_ADDR              0x00FF
+#define IPG_EC_EEPROM_OPCODE            0x0300
+#define IPG_EC_EEPROM_SUBCOMMAD         0x0000
+#define IPG_EC_EEPROM_WRITEOPCODE       0x0100
+#define IPG_EC_EEPROM_READOPCODE        0x0200
+#define IPG_EC_EEPROM_ERASEOPCODE       0x0300
+#define IPG_EC_EEPROM_BUSY              0x8000
+
+/* FIFOCtrl */
+#define IPG_FC_RSVD_MASK                0xC001
+#define IPG_FC_RAM_TEST_MODE            0x0001
+#define IPG_FC_TRANSMITTING             0x4000
+#define IPG_FC_RECEIVING                0x8000
+
+/* TxStatus */
+#define IPG_TS_RSVD_MASK                0xFFFF00DD
+#define IPG_TS_TX_ERROR                 0x00000001
+#define IPG_TS_LATE_COLLISION           0x00000004
+#define IPG_TS_TX_MAX_COLL              0x00000008
+#define IPG_TS_TX_UNDERRUN              0x00000010
+#define IPG_TS_TX_IND_REQD              0x00000040
+#define IPG_TS_TX_COMPLETE              0x00000080
+#define IPG_TS_TX_FRAMEID               0xFFFF0000
+
+/* WakeEvent */
+#define IPG_WE_WAKE_PKT_ENABLE          0x01
+#define IPG_WE_MAGIC_PKT_ENABLE         0x02
+#define IPG_WE_LINK_EVT_ENABLE          0x04
+#define IPG_WE_WAKE_POLARITY            0x08
+#define IPG_WE_WAKE_PKT_EVT             0x10
+#define IPG_WE_MAGIC_PKT_EVT            0x20
+#define IPG_WE_LINK_EVT                 0x40
+#define IPG_WE_WOL_ENABLE               0x80
+
+/* IntEnable */
+#define IPG_IE_RSVD_MASK                0x1FFE
+#define IPG_IE_HOST_ERROR               0x0002
+#define IPG_IE_TX_COMPLETE              0x0004
+#define IPG_IE_MAC_CTRL_FRAME           0x0008
+#define IPG_IE_RX_COMPLETE              0x0010
+#define IPG_IE_RX_EARLY                 0x0020
+#define IPG_IE_INT_REQUESTED            0x0040
+#define IPG_IE_UPDATE_STATS             0x0080
+#define IPG_IE_LINK_EVENT               0x0100
+#define IPG_IE_TX_DMA_COMPLETE          0x0200
+#define IPG_IE_RX_DMA_COMPLETE          0x0400
+#define IPG_IE_RFD_LIST_END             0x0800
+#define IPG_IE_RX_DMA_PRIORITY          0x1000
+
+/* IntStatus */
+#define IPG_IS_RSVD_MASK                0x1FFF
+#define IPG_IS_INTERRUPT_STATUS         0x0001
+#define IPG_IS_HOST_ERROR               0x0002
+#define IPG_IS_TX_COMPLETE              0x0004
+#define IPG_IS_MAC_CTRL_FRAME           0x0008
+#define IPG_IS_RX_COMPLETE              0x0010
+#define IPG_IS_RX_EARLY                 0x0020
+#define IPG_IS_INT_REQUESTED            0x0040
+#define IPG_IS_UPDATE_STATS             0x0080
+#define IPG_IS_LINK_EVENT               0x0100
+#define IPG_IS_TX_DMA_COMPLETE          0x0200
+#define IPG_IS_RX_DMA_COMPLETE          0x0400
+#define IPG_IS_RFD_LIST_END             0x0800
+#define IPG_IS_RX_DMA_PRIORITY          0x1000
+
+/* MACCtrl */
+#define IPG_MC_RSVD_MASK                0x7FE33FA3
+#define IPG_MC_IFS_SELECT               0x00000003
+#define IPG_MC_IFS_4352BIT              0x00000003
+#define IPG_MC_IFS_1792BIT              0x00000002
+#define IPG_MC_IFS_1024BIT              0x00000001
+#define IPG_MC_IFS_96BIT                0x00000000
+#define IPG_MC_DUPLEX_SELECT            0x00000020
+#define IPG_MC_DUPLEX_SELECT_FD         0x00000020
+#define IPG_MC_DUPLEX_SELECT_HD         0x00000000
+#define IPG_MC_TX_FLOW_CONTROL_ENABLE   0x00000080
+#define IPG_MC_RX_FLOW_CONTROL_ENABLE   0x00000100
+#define IPG_MC_RCV_FCS                  0x00000200
+#define IPG_MC_FIFO_LOOPBACK            0x00000400
+#define IPG_MC_MAC_LOOPBACK             0x00000800
+#define IPG_MC_AUTO_VLAN_TAGGING        0x00001000
+#define IPG_MC_AUTO_VLAN_UNTAGGING      0x00002000
+#define IPG_MC_COLLISION_DETECT         0x00010000
+#define IPG_MC_CARRIER_SENSE            0x00020000
+#define IPG_MC_STATISTICS_ENABLE        0x00200000
+#define IPG_MC_STATISTICS_DISABLE       0x00400000
+#define IPG_MC_STATISTICS_ENABLED       0x00800000
+#define IPG_MC_TX_ENABLE                0x01000000
+#define IPG_MC_TX_DISABLE               0x02000000
+#define IPG_MC_TX_ENABLED               0x04000000
+#define IPG_MC_RX_ENABLE                0x08000000
+#define IPG_MC_RX_DISABLE               0x10000000
+#define IPG_MC_RX_ENABLED               0x20000000
+#define IPG_MC_PAUSED                   0x40000000
+
+/*
+ *	Tune
+ */
+
+/* Miscellaneous Constants. */
+#define   TRUE  1
+#define   FALSE 0
+
+/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS append on TX. */
+#define         IPG_APPEND_FCS_ON_TX         TRUE
+
+/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS strip on RX. */
+#define         IPG_STRIP_FCS_ON_RX          TRUE
+
+/* Assign IPG_DROP_ON_RX_ETH_ERRORS > 0 to drop RX frames with
+ * Ethernet errors.
+ */
+#define         IPG_DROP_ON_RX_ETH_ERRORS    TRUE
+
+/* Assign IPG_INSERT_MANUAL_VLAN_TAG > 0 to insert VLAN tags manually
+ * (via TFC).
+ */
+#define		IPG_INSERT_MANUAL_VLAN_TAG   FALSE
+
+/* Assign IPG_ADD_IPCHECKSUM_ON_TX > 0 for auto IP checksum on TX. */
+#define         IPG_ADD_IPCHECKSUM_ON_TX     FALSE
+
+/* Assign IPG_ADD_TCPCHECKSUM_ON_TX > 0 for auto TCP checksum on TX.
+ * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER.
+ */
+#define         IPG_ADD_TCPCHECKSUM_ON_TX    FALSE
+
+/* Assign IPG_ADD_UDPCHECKSUM_ON_TX > 0 for auto UDP checksum on TX.
+ * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER.
+ */
+#define         IPG_ADD_UDPCHECKSUM_ON_TX    FALSE
+
+/* If inserting VLAN tags manually, assign the IPG_MANUAL_VLAN_xx
+ * constants as desired.
+ */
+#define		IPG_MANUAL_VLAN_VID		0xABC
+#define		IPG_MANUAL_VLAN_CFI		0x1
+#define		IPG_MANUAL_VLAN_USERPRIORITY 0x5
+
+#define         IPG_IO_REG_RANGE		0xFF
+#define         IPG_MEM_REG_RANGE		0x154
+#define         IPG_DRIVER_NAME		"Sundance Technology IPG Triple-Speed Ethernet"
+#define         IPG_NIC_PHY_ADDRESS          0x01
+#define		IPG_DMALIST_ALIGN_PAD	0x07
+#define		IPG_MULTICAST_HASHTABLE_SIZE	0x40
+
+/* Number of miliseconds to wait after issuing a software reset.
+ * 0x05 <= IPG_AC_RESETWAIT to account for proper 10Mbps operation.
+ */
+#define         IPG_AC_RESETWAIT             0x05
+
+/* Number of IPG_AC_RESETWAIT timeperiods before declaring timeout. */
+#define         IPG_AC_RESET_TIMEOUT         0x0A
+
+/* Minimum number of nanoseconds used to toggle MDC clock during
+ * MII/GMII register access.
+ */
+#define		IPG_PC_PHYCTRLWAIT_NS		200
+
+#define		IPG_TFDLIST_LENGTH		0x100
+
+/* Number of frames between TxDMAComplete interrupt.
+ * 0 < IPG_FRAMESBETWEENTXDMACOMPLETES <= IPG_TFDLIST_LENGTH
+ */
+#define		IPG_FRAMESBETWEENTXDMACOMPLETES 0x1
+
+#ifdef JUMBO_FRAME
+
+# ifdef JUMBO_FRAME_SIZE_2K
+# define JUMBO_FRAME_SIZE 2048
+# define __IPG_RXFRAG_SIZE 2048
+# else
+#  ifdef JUMBO_FRAME_SIZE_3K
+#  define JUMBO_FRAME_SIZE 3072
+#  define __IPG_RXFRAG_SIZE 3072
+#  else
+#   ifdef JUMBO_FRAME_SIZE_4K
+#   define JUMBO_FRAME_SIZE 4096
+#   define __IPG_RXFRAG_SIZE 4088
+#   else
+#    ifdef JUMBO_FRAME_SIZE_5K
+#    define JUMBO_FRAME_SIZE 5120
+#    define __IPG_RXFRAG_SIZE 4088
+#    else
+#     ifdef JUMBO_FRAME_SIZE_6K
+#     define JUMBO_FRAME_SIZE 6144
+#     define __IPG_RXFRAG_SIZE 4088
+#     else
+#      ifdef JUMBO_FRAME_SIZE_7K
+#      define JUMBO_FRAME_SIZE 7168
+#      define __IPG_RXFRAG_SIZE 4088
+#      else
+#       ifdef JUMBO_FRAME_SIZE_8K
+#       define JUMBO_FRAME_SIZE 8192
+#       define __IPG_RXFRAG_SIZE 4088
+#       else
+#        ifdef JUMBO_FRAME_SIZE_9K
+#        define JUMBO_FRAME_SIZE 9216
+#        define __IPG_RXFRAG_SIZE 4088
+#        else
+#         ifdef JUMBO_FRAME_SIZE_10K
+#         define JUMBO_FRAME_SIZE 10240
+#         define __IPG_RXFRAG_SIZE 4088
+#         else
+#         define JUMBO_FRAME_SIZE 4096
+#         endif
+#        endif
+#       endif
+#      endif
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+/* Size of allocated received buffers. Nominally 0x0600.
+ * Define larger if expecting jumbo frames.
+ */
+#ifdef JUMBO_FRAME
+//IPG_TXFRAG_SIZE must <= 0x2b00, or TX will crash
+#define		IPG_TXFRAG_SIZE		JUMBO_FRAME_SIZE
+#endif
+
+/* Size of allocated received buffers. Nominally 0x0600.
+ * Define larger if expecting jumbo frames.
+ */
+#ifdef JUMBO_FRAME
+//4088=4096-8
+#define		IPG_RXFRAG_SIZE		__IPG_RXFRAG_SIZE
+#define     IPG_RXSUPPORT_SIZE   IPG_MAX_RXFRAME_SIZE
+#else
+#define		IPG_RXFRAG_SIZE		0x0600
+#define     IPG_RXSUPPORT_SIZE   IPG_RXFRAG_SIZE
+#endif
+
+/* IPG_MAX_RXFRAME_SIZE <= IPG_RXFRAG_SIZE */
+#ifdef JUMBO_FRAME
+#define		IPG_MAX_RXFRAME_SIZE		JUMBO_FRAME_SIZE
+#else
+#define		IPG_MAX_RXFRAME_SIZE		0x0600
+#endif
+
+#define		IPG_RFDLIST_LENGTH		0x100
+
+/* Maximum number of RFDs to process per interrupt.
+ * 1 < IPG_MAXRFDPROCESS_COUNT < IPG_RFDLIST_LENGTH
+ */
+#define		IPG_MAXRFDPROCESS_COUNT	0x80
+
+/* Minimum margin between last freed RFD, and current RFD.
+ * 1 < IPG_MINUSEDRFDSTOFREE < IPG_RFDLIST_LENGTH
+ */
+#define		IPG_MINUSEDRFDSTOFREE	0x80
+
+/* specify the jumbo frame maximum size
+ * per unit is 0x600 (the RxBuffer size that one RFD can carry)
+ */
+#define     MAX_JUMBOSIZE	        0x8	// max is 12K
+
+/* Key register values loaded at driver start up. */
+
+/* TXDMAPollPeriod is specified in 320ns increments.
+ *
+ * Value	Time
+ * ---------------------
+ * 0x00-0x01	320ns
+ * 0x03		~1us
+ * 0x1F		~10us
+ * 0xFF		~82us
+ */
+#define		IPG_TXDMAPOLLPERIOD_VALUE	0x26
+
+/* TxDMAUrgentThresh specifies the minimum amount of
+ * data in the transmit FIFO before asserting an
+ * urgent transmit DMA request.
+ *
+ * Value	Min TxFIFO occupied space before urgent TX request
+ * ---------------------------------------------------------------
+ * 0x00-0x04	128 bytes (1024 bits)
+ * 0x27		1248 bytes (~10000 bits)
+ * 0x30		1536 bytes (12288 bits)
+ * 0xFF		8192 bytes (65535 bits)
+ */
+#define		IPG_TXDMAURGENTTHRESH_VALUE	0x04
+
+/* TxDMABurstThresh specifies the minimum amount of
+ * free space in the transmit FIFO before asserting an
+ * transmit DMA request.
+ *
+ * Value	Min TxFIFO free space before TX request
+ * ----------------------------------------------------
+ * 0x00-0x08	256 bytes
+ * 0x30		1536 bytes
+ * 0xFF		8192 bytes
+ */
+#define		IPG_TXDMABURSTTHRESH_VALUE	0x30
+
+/* RXDMAPollPeriod is specified in 320ns increments.
+ *
+ * Value	Time
+ * ---------------------
+ * 0x00-0x01	320ns
+ * 0x03		~1us
+ * 0x1F		~10us
+ * 0xFF		~82us
+ */
+#define		IPG_RXDMAPOLLPERIOD_VALUE	0x01
+
+/* RxDMAUrgentThresh specifies the minimum amount of
+ * free space within the receive FIFO before asserting
+ * a urgent receive DMA request.
+ *
+ * Value	Min RxFIFO free space before urgent RX request
+ * ---------------------------------------------------------------
+ * 0x00-0x04	128 bytes (1024 bits)
+ * 0x27		1248 bytes (~10000 bits)
+ * 0x30		1536 bytes (12288 bits)
+ * 0xFF		8192 bytes (65535 bits)
+ */
+#define		IPG_RXDMAURGENTTHRESH_VALUE	0x30
+
+/* RxDMABurstThresh specifies the minimum amount of
+ * occupied space within the receive FIFO before asserting
+ * a receive DMA request.
+ *
+ * Value	Min TxFIFO free space before TX request
+ * ----------------------------------------------------
+ * 0x00-0x08	256 bytes
+ * 0x30		1536 bytes
+ * 0xFF		8192 bytes
+ */
+#define		IPG_RXDMABURSTTHRESH_VALUE	0x30
+
+/* FlowOnThresh specifies the maximum amount of occupied
+ * space in the receive FIFO before a PAUSE frame with
+ * maximum pause time transmitted.
+ *
+ * Value	Max RxFIFO occupied space before PAUSE
+ * ---------------------------------------------------
+ * 0x0000	0 bytes
+ * 0x0740	29,696 bytes
+ * 0x07FF	32,752 bytes
+ */
+#define		IPG_FLOWONTHRESH_VALUE	0x0740
+
+/* FlowOffThresh specifies the minimum amount of occupied
+ * space in the receive FIFO before a PAUSE frame with
+ * zero pause time is transmitted.
+ *
+ * Value	Max RxFIFO occupied space before PAUSE
+ * ---------------------------------------------------
+ * 0x0000	0 bytes
+ * 0x00BF	3056 bytes
+ * 0x07FF	32,752 bytes
+ */
+#define		IPG_FLOWOFFTHRESH_VALUE	0x00BF
+
+/*
+ * Miscellaneous macros.
+ */
+
+/* Marco for printing debug statements.
+#  define IPG_DDEBUG_MSG(args...) printk(KERN_DEBUG "IPG: " ## args) */
+#ifdef IPG_DEBUG
+#  define IPG_DEBUG_MSG(args...)
+#  define IPG_DDEBUG_MSG(args...) printk(KERN_DEBUG "IPG: " args)
+#  define IPG_DUMPRFDLIST(args) ipg_dump_rfdlist(args)
+#  define IPG_DUMPTFDLIST(args) ipg_dump_tfdlist(args)
+#else
+#  define IPG_DEBUG_MSG(args...)
+#  define IPG_DDEBUG_MSG(args...)
+#  define IPG_DUMPRFDLIST(args)
+#  define IPG_DUMPTFDLIST(args)
+#endif
+
+/*
+ * End miscellaneous macros.
+ */
+
+/* Transmit Frame Descriptor. The IPG supports 15 fragments,
+ * however Linux requires only a single fragment. Note, each
+ * TFD field is 64 bits wide.
+ */
+struct ipg_tx {
+	u64 next_desc;
+	u64 tfc;
+	u64 frag_info;
+};
+
+/* Receive Frame Descriptor. Note, each RFD field is 64 bits wide.
+ */
+struct ipg_rx {
+	u64 next_desc;
+	u64 rfs;
+	u64 frag_info;
+};
+
+struct SJumbo {
+	int FoundStart;
+	int CurrentSize;
+	struct sk_buff *skb;
+};
+/* Structure of IPG NIC specific data. */
+struct ipg_nic_private {
+	void __iomem *ioaddr;
+	struct ipg_tx *txd;
+	struct ipg_rx *rxd;
+	dma_addr_t txd_map;
+	dma_addr_t rxd_map;
+	struct sk_buff *TxBuff[IPG_TFDLIST_LENGTH];
+	struct sk_buff *RxBuff[IPG_RFDLIST_LENGTH];
+	unsigned int tx_current;
+	unsigned int tx_dirty;
+	unsigned int rx_current;
+	unsigned int rx_dirty;
+// Add by Grace 2005/05/19
+#ifdef JUMBO_FRAME
+	struct SJumbo Jumbo;
+#endif
+	unsigned int rx_buf_sz;
+	struct pci_dev *pdev;
+	struct net_device *dev;
+	struct net_device_stats stats;
+	spinlock_t lock;
+	int tenmbpsmode;
+
+	/*Jesse20040128EEPROM_VALUE */
+	u16 LED_Mode;
+	u16 station_addr[3];	/* Station Address in EEPROM Reg 0x10..0x12 */
+
+	struct mutex		mii_mutex;
+	struct mii_if_info	mii_if;
+	int ResetCurrentTFD;
+#ifdef IPG_DEBUG
+	int RFDlistendCount;
+	int RFDListCheckedCount;
+	int EmptyRFDListCount;
+#endif
+	struct delayed_work task;
+};
+
+//variable record -- index by leading revision/length
+//Revision/Length(=N*4), Address1, Data1, Address2, Data2,...,AddressN,DataN
+unsigned short DefaultPhyParam[] = {
+	// 11/12/03 IP1000A v1-3 rev=0x40
+	/*--------------------------------------------------------------------------
+	(0x4000|(15*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 22, 0x85bd, 24, 0xfff2,
+				 27, 0x0c10, 28, 0x0c10, 29, 0x2c10, 31, 0x0003, 23, 0x92f6,
+				 31, 0x0000, 23, 0x003d, 30, 0x00de, 20, 0x20e7,  9, 0x0700,
+	  --------------------------------------------------------------------------*/
+	// 12/17/03 IP1000A v1-4 rev=0x40
+	(0x4000 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31,
+	    0x0000,
+	30, 0x005e, 9, 0x0700,
+	// 01/09/04 IP1000A v1-5 rev=0x41
+	(0x4100 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31,
+	    0x0000,
+	30, 0x005e, 9, 0x0700,
+	0x0000
+};
+
+#endif				/* __LINUX_IPG_H */
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index 829da9a..6580695 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -155,6 +155,41 @@
 	  To compile it as a module, choose M here: the module will be called
 	  kingsun-sir.
 
+config EP7211_DONGLE
+	tristate "EP7211 I/R support"
+	depends on IRTTY_SIR && ARCH_EP7211 && IRDA && EXPERIMENTAL
+	help
+	  Say Y here if you want to build support for the Cirrus logic
+	  EP7211 chipset's infrared module.
+
+config KSDAZZLE_DONGLE
+	tristate "KingSun Dazzle IrDA-USB dongle (EXPERIMENTAL)"
+	depends on IRDA && USB && EXPERIMENTAL
+	help
+	  Say Y or M here if you want to build support for the KingSun Dazzle
+	  IrDA-USB bridge device driver.
+
+	  This USB bridge does not conform to the IrDA-USB device class
+	  specification, and therefore needs its own specific driver. This
+	  dongle supports SIR speeds only (9600 through 115200 bps).
+
+	  To compile it as a module, choose M here: the module will be called
+	  ksdazzle-sir.
+
+config KS959_DONGLE
+	tristate "KingSun KS-959 IrDA-USB dongle (EXPERIMENTAL)"
+	depends on IRDA && USB && EXPERIMENTAL
+	help
+	  Say Y or M here if you want to build support for the KingSun KS-959
+	  IrDA-USB bridge device driver.
+
+	  This USB bridge does not conform to the IrDA-USB device class
+	  specification, and therefore needs its own specific driver. This
+	  dongle supports SIR speeds only (9600 through 57600 bps).
+
+	  To compile it as a module, choose M here: the module will be called
+	  ks959-sir.
+
 comment "Old SIR device drivers"
 
 config IRPORT_SIR
@@ -355,7 +390,7 @@
 
 config TOSHIBA_FIR
 	tristate "Toshiba Type-O IR Port"
-	depends on IRDA && PCI && !64BIT
+	depends on IRDA && PCI && !64BIT && VIRT_TO_BUS
 	help
 	  Say Y here if you want to build support for the Toshiba Type-O IR
 	  and Donau oboe chipsets. These chipsets are used by the Toshiba
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
index 233a2f9..fefbb59 100644
--- a/drivers/net/irda/Makefile
+++ b/drivers/net/irda/Makefile
@@ -45,7 +45,10 @@
 obj-$(CONFIG_ACT200L_DONGLE)	+= act200l-sir.o
 obj-$(CONFIG_MA600_DONGLE)	+= ma600-sir.o
 obj-$(CONFIG_TOIM3232_DONGLE)	+= toim3232-sir.o
+obj-$(CONFIG_EP7211_DONGLE)	+= ep7211-sir.o
 obj-$(CONFIG_KINGSUN_DONGLE)	+= kingsun-sir.o
+obj-$(CONFIG_KSDAZZLE_DONGLE)	+= ksdazzle-sir.o
+obj-$(CONFIG_KS959_DONGLE)    	+= ks959-sir.o
 
 # The SIR helper module
 sir-dev-objs := sir_dev.o sir_dongle.o
diff --git a/drivers/net/irda/actisys-sir.c b/drivers/net/irda/actisys-sir.c
index 9715ab5..ccf6ec5 100644
--- a/drivers/net/irda/actisys-sir.c
+++ b/drivers/net/irda/actisys-sir.c
@@ -67,7 +67,7 @@
 /* Note : the 220L doesn't support 38400, but we will fix that below */
 static unsigned baud_rates[] = { 9600, 19200, 57600, 115200, 38400 };
 
-#define MAX_SPEEDS (sizeof(baud_rates)/sizeof(baud_rates[0]))
+#define MAX_SPEEDS ARRAY_SIZE(baud_rates)
 
 static struct dongle_driver act220l = {
 	.owner		= THIS_MODULE,
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index f9c889c..9f58452 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -360,10 +360,6 @@
 	self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
 	self->tx_fifo.tail = self->tx_buff.head;
 
-	
-	/* Keep track of module usage */
-	SET_MODULE_OWNER(dev);
-
 	/* Override the network functions we need to use */
 	dev->hard_start_xmit = ali_ircc_sir_hard_xmit;
 	dev->open            = ali_ircc_net_open;
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 3ca47bf..3e5eca1 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -1660,7 +1660,6 @@
       }
 #endif
 
-  SET_MODULE_OWNER(dev);
   SET_NETDEV_DEV(dev, &pci_dev->dev);
   dev->hard_start_xmit = toshoboe_hard_xmit;
   dev->open = toshoboe_net_open;
diff --git a/drivers/net/irda/ep7211-sir.c b/drivers/net/irda/ep7211-sir.c
new file mode 100644
index 0000000..8315724
--- /dev/null
+++ b/drivers/net/irda/ep7211-sir.c
@@ -0,0 +1,89 @@
+/*
+ * IR port driver for the Cirrus Logic EP7211 processor.
+ *
+ * Copyright 2001, Blue Mug Inc.  All rights reserved.
+ * Copyright 2007, Samuel Ortiz <samuel@sortiz.org>
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irda_device.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+#include "sir-dev.h"
+
+#define MIN_DELAY 25      /* 15 us, but wait a little more to be sure */
+#define MAX_DELAY 10000   /* 1 ms */
+
+static int ep7211_open(struct sir_dev *dev);
+static int ep7211_close(struct sir_dev *dev);
+static int ep7211_change_speed(struct sir_dev *dev, unsigned speed);
+static int ep7211_reset(struct sir_dev *dev);
+
+static struct dongle_driver ep7211 = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "EP7211 IR driver",
+	.type		= IRDA_EP7211_DONGLE,
+	.open		= ep7211_open,
+	.close		= ep7211_close,
+	.reset		= ep7211_reset,
+	.set_speed	= ep7211_change_speed,
+};
+
+static int __init ep7211_sir_init(void)
+{
+	return irda_register_dongle(&ep7211);
+}
+
+static void __exit ep7211_sir_cleanup(void)
+{
+	irda_unregister_dongle(&ep7211);
+}
+
+static int ep7211_open(struct sir_dev *dev)
+{
+	unsigned int syscon;
+
+	/* Turn on the SIR encoder. */
+	syscon = clps_readl(SYSCON1);
+	syscon |= SYSCON1_SIREN;
+	clps_writel(syscon, SYSCON1);
+
+	return 0;
+}
+
+static int ep7211_close(struct sir_dev *dev)
+{
+	unsigned int syscon;
+
+	/* Turn off the SIR encoder. */
+	syscon = clps_readl(SYSCON1);
+	syscon &= ~SYSCON1_SIREN;
+	clps_writel(syscon, SYSCON1);
+
+	return 0;
+}
+
+static int ep7211_change_speed(struct sir_dev *dev, unsigned speed)
+{
+	return 0;
+}
+
+static int ep7211_reset(struct sir_dev *dev)
+{
+	return 0;
+}
+
+MODULE_AUTHOR("Samuel Ortiz <samuel@sortiz.org>");
+MODULE_DESCRIPTION("EP7211 IR dongle driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("irda-dongle-13"); /* IRDA_EP7211_DONGLE */
+
+module_init(ep7211_sir_init);
+module_exit(ep7211_sir_cleanup);
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 0ac240c..c6355c0 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -1561,10 +1561,9 @@
 	struct irda_class_desc *desc;
 	int ret;
 
-	desc = kmalloc(sizeof (*desc), GFP_KERNEL);
-	if (desc == NULL) 
+	desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+	if (!desc)
 		return NULL;
-	memset(desc, 0, sizeof(*desc));
 
 	/* USB-IrDA class spec 1.0:
 	 *	6.1.3: Standard "Get Descriptor" Device Request is not
@@ -1617,7 +1616,7 @@
 {
 	struct net_device *net;
 	struct usb_device *dev = interface_to_usbdev(intf);
-	struct irda_usb_cb *self = NULL;
+	struct irda_usb_cb *self;
 	struct usb_host_interface *interface;
 	struct irda_class_desc *irda_desc;
 	int ret = -ENOMEM;
@@ -1636,7 +1635,6 @@
 	if (!net) 
 		goto err_out;
 
-	SET_MODULE_OWNER(net);
 	SET_NETDEV_DEV(net, &intf->dev);
 	self = net->priv;
 	self->netdev = net;
@@ -1655,7 +1653,7 @@
 		self->header_length = USB_IRDA_HEADER;
 	}
 
-	self->rx_urb = kzalloc(self->max_rx_urb * sizeof(struct urb *),
+	self->rx_urb = kcalloc(self->max_rx_urb, sizeof(struct urb *),
 				GFP_KERNEL);
 
 	for (i = 0; i < self->max_rx_urb; i++) {
@@ -1715,7 +1713,7 @@
 	/* Find IrDA class descriptor */
 	irda_desc = irda_usb_find_class_desc(intf);
 	ret = -ENODEV;
-	if (irda_desc == NULL)
+	if (!irda_desc)
 		goto err_out_3;
 
 	if (self->needspatch) {
@@ -1738,15 +1736,13 @@
 	/* Don't change this buffer size and allocation without doing
 	 * some heavy and complete testing. Don't ask why :-(
 	 * Jean II */
-	self->speed_buff = kmalloc(IRDA_USB_SPEED_MTU, GFP_KERNEL);
-	if (self->speed_buff == NULL) 
+	self->speed_buff = kzalloc(IRDA_USB_SPEED_MTU, GFP_KERNEL);
+	if (!self->speed_buff)
 		goto err_out_3;
 
-	memset(self->speed_buff, 0, IRDA_USB_SPEED_MTU);
-
 	self->tx_buff = kzalloc(IRDA_SKB_MAX_MTU + self->header_length,
 				GFP_KERNEL);
-	if (self->tx_buff == NULL)
+	if (!self->tx_buff)
 		goto err_out_4;
 
 	ret = irda_usb_open(self);
@@ -1767,12 +1763,11 @@
 
 		/* replace IrDA class descriptor with what patched device is now reporting */
 		irda_desc = irda_usb_find_class_desc (self->usbintf);
-		if (irda_desc == NULL) {
+		if (!irda_desc) {
 			ret = -ENODEV;
 			goto err_out_6;
 		}
-		if (self->irda_desc)
-			kfree (self->irda_desc);
+		kfree(self->irda_desc);
 		self->irda_desc = irda_desc;
 		irda_usb_init_qos(self);
 	}
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
index 3078c41..c79caa5 100644
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -164,20 +164,17 @@
 	
 	/* Allocate memory if needed */
 	if (self->tx_buff.truesize > 0) {
-		self->tx_buff.head = kmalloc(self->tx_buff.truesize,
+		self->tx_buff.head = kzalloc(self->tx_buff.truesize,
 						      GFP_KERNEL);
 		if (self->tx_buff.head == NULL) {
 			IRDA_ERROR("%s(), can't allocate memory for "
 				   "transmit buffer!\n", __FUNCTION__);
 			goto err_out4;
 		}
-		memset(self->tx_buff.head, 0, self->tx_buff.truesize);
 	}	
 	self->tx_buff.data = self->tx_buff.head;
 
 	self->netdev = dev;
-	/* Keep track of module usage */
-	SET_MODULE_OWNER(dev);
 
 	/* May be overridden by piggyback drivers */
 	self->interrupt    = irport_interrupt;
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index ad18573..6f5f697 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -505,10 +505,9 @@
 	}
 
 	/* allocate private device info block */
-	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 	if (!priv)
 		goto out_put;
-	memset(priv, 0, sizeof(*priv));
 
 	priv->magic = IRTTY_MAGIC;
 	priv->tty = tty;
diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c
index bdd5c97..648e54b 100644
--- a/drivers/net/irda/kingsun-sir.c
+++ b/drivers/net/irda/kingsun-sir.c
@@ -66,7 +66,6 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/module.h>
 #include <linux/kref.h>
 #include <linux/usb.h>
 #include <linux/device.h>
@@ -488,7 +487,6 @@
 	if(!net)
 		goto err_out1;
 
-	SET_MODULE_OWNER(net);
 	SET_NETDEV_DEV(net, &intf->dev);
 	kingsun = netdev_priv(net);
 	kingsun->irlap = NULL;
@@ -509,12 +507,12 @@
 	spin_lock_init(&kingsun->lock);
 
 	/* Allocate input buffer */
-	kingsun->in_buf = (__u8 *)kmalloc(kingsun->max_rx, GFP_KERNEL);
+	kingsun->in_buf = kmalloc(kingsun->max_rx, GFP_KERNEL);
 	if (!kingsun->in_buf)
 		goto free_mem;
 
 	/* Allocate output buffer */
-	kingsun->out_buf = (__u8 *)kmalloc(KINGSUN_FIFO_SIZE, GFP_KERNEL);
+	kingsun->out_buf = kmalloc(KINGSUN_FIFO_SIZE, GFP_KERNEL);
 	if (!kingsun->out_buf)
 		goto free_mem;
 
diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c
new file mode 100644
index 0000000..8c257a5
--- /dev/null
+++ b/drivers/net/irda/ks959-sir.c
@@ -0,0 +1,938 @@
+/*****************************************************************************
+*
+* Filename:      ks959-sir.c
+* Version:       0.1.2
+* Description:   Irda KingSun KS-959 USB Dongle
+* Status:        Experimental
+* Author:        Alex Villacís Lasso <a_villacis@palosanto.com>
+*         with help from Domen Puncer <domen@coderock.org>
+*
+*    Based on stir4200, mcs7780, kingsun-sir drivers.
+*
+*    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.
+*
+*    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.
+*
+*****************************************************************************/
+
+/*
+ * Following is my most current (2007-07-17) understanding of how the Kingsun
+ * KS-959 dongle is supposed to work. This information was deduced by
+ * reverse-engineering and examining the USB traffic captured with USBSnoopy
+ * from the WinXP driver. Feel free to update here as more of the dongle is
+ * known.
+ *
+ * My most sincere thanks must go to Domen Puncer <domen@coderock.org> for
+ * invaluable help in cracking the obfuscation and padding required for this
+ * dongle.
+ *
+ * General: This dongle exposes one interface with one interrupt IN endpoint.
+ * However, the interrupt endpoint is NOT used at all for this dongle. Instead,
+ * this dongle uses control transfers for everything, including sending and
+ * receiving the IrDA frame data. Apparently the interrupt endpoint is just a
+ * dummy to ensure the dongle has a valid interface to present to the PC.And I
+ * thought the DonShine dongle was weird... In addition, this dongle uses
+ * obfuscation (?!?!), applied at the USB level, to hide the traffic, both sent
+ * and received, from the dongle. I call it obfuscation because the XOR keying
+ * and padding required to produce an USB traffic acceptable for the dongle can
+ * not be explained by any other technical requirement.
+ *
+ * Transmission: To transmit an IrDA frame, the driver must prepare a control
+ * URB with the following as a setup packet:
+ *    bRequestType    USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
+ *    bRequest        0x09
+ *    wValue          <length of valid data before padding, little endian>
+ *    wIndex          0x0000
+ *    wLength         <length of padded data>
+ * The payload packet must be manually wrapped and escaped (as in stir4200.c),
+ * then padded and obfuscated before being sent. Both padding and obfuscation
+ * are implemented in the procedure obfuscate_tx_buffer(). Suffice to say, the
+ * designer/programmer of the dongle used his name as a source for the
+ * obfuscation. WTF?!
+ * Apparently the dongle cannot handle payloads larger than 256 bytes. The
+ * driver has to perform fragmentation in order to send anything larger than
+ * this limit.
+ *
+ * Reception: To receive data, the driver must poll the dongle regularly (like
+ * kingsun-sir.c) with control URBs and the following as a setup packet:
+ *    bRequestType    USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE
+ *    bRequest        0x01
+ *    wValue          0x0200
+ *    wIndex          0x0000
+ *    wLength         0x0800 (size of available buffer)
+ * If there is data to be read, it will be returned as the response payload.
+ * This data is (apparently) not padded, but it is obfuscated. To de-obfuscate
+ * it, the driver must XOR every byte, in sequence, with a value that starts at
+ * 1 and is incremented with each byte processed, and then with 0x55. The value
+ * incremented with each byte processed overflows as an unsigned char. The
+ * resulting bytes form a wrapped SIR frame that is unwrapped and unescaped
+ * as in stir4200.c The incremented value is NOT reset with each frame, but is
+ * kept across the entire session with the dongle. Also, the dongle inserts an
+ * extra garbage byte with value 0x95 (after decoding) every 0xff bytes, which
+ * must be skipped.
+ *
+ * Speed change: To change the speed of the dongle, the driver prepares a
+ * control URB with the following as a setup packet:
+ *    bRequestType    USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
+ *    bRequest        0x09
+ *    wValue          0x0200
+ *    wIndex          0x0001
+ *    wLength         0x0008 (length of the payload)
+ * The payload is a 8-byte record, apparently identical to the one used in
+ * drivers/usb/serial/cypress_m8.c to change speed:
+ *     __u32 baudSpeed;
+ *    unsigned int dataBits : 2;    // 0 - 5 bits 3 - 8 bits
+ *    unsigned int : 1;
+ *    unsigned int stopBits : 1;
+ *    unsigned int parityEnable : 1;
+ *    unsigned int parityType : 1;
+ *    unsigned int : 1;
+ *    unsigned int reset : 1;
+ *    unsigned char reserved[3];    // set to 0
+ *
+ * For now only SIR speeds have been observed with this dongle. Therefore,
+ * nothing is known on what changes (if any) must be done to frame wrapping /
+ * unwrapping for higher than SIR speeds. This driver assumes no change is
+ * necessary and announces support for all the way to 57600 bps. Although the
+ * package announces support for up to 4MBps, tests with a Sony Ericcson K300
+ * phone show corruption when receiving large frames at 115200 bps, the highest
+ * speed announced by the phone. However, transmission at 115200 bps is OK. Go
+ * figure. Since I don't know whether the phone or the dongle is at fault, max
+ * announced speed is 57600 bps until someone produces a device that can run
+ * at higher speeds with this dongle.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/crc32.h>
+
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/crc.h>
+
+#define KS959_VENDOR_ID 0x07d0
+#define KS959_PRODUCT_ID 0x4959
+
+/* These are the currently known USB ids */
+static struct usb_device_id dongles[] = {
+	/* KingSun Co,Ltd  IrDA/USB Bridge */
+	{USB_DEVICE(KS959_VENDOR_ID, KS959_PRODUCT_ID)},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, dongles);
+
+#define KINGSUN_MTT 0x07
+#define KINGSUN_REQ_RECV 0x01
+#define KINGSUN_REQ_SEND 0x09
+
+#define KINGSUN_RCV_FIFO_SIZE    2048	/* Max length we can receive */
+#define KINGSUN_SND_FIFO_SIZE    2048	/* Max packet we can send */
+#define KINGSUN_SND_PACKET_SIZE    256	/* Max packet dongle can handle */
+
+struct ks959_speedparams {
+	__le32 baudrate;	/* baud rate, little endian */
+	__u8 flags;
+	__u8 reserved[3];
+} __attribute__ ((packed));
+
+#define KS_DATA_5_BITS 0x00
+#define KS_DATA_6_BITS 0x01
+#define KS_DATA_7_BITS 0x02
+#define KS_DATA_8_BITS 0x03
+
+#define KS_STOP_BITS_1 0x00
+#define KS_STOP_BITS_2 0x08
+
+#define KS_PAR_DISABLE    0x00
+#define KS_PAR_EVEN    0x10
+#define KS_PAR_ODD    0x30
+#define KS_RESET    0x80
+
+struct ks959_cb {
+	struct usb_device *usbdev;	/* init: probe_irda */
+	struct net_device *netdev;	/* network layer */
+	struct irlap_cb *irlap;	/* The link layer we are binded to */
+	struct net_device_stats stats;	/* network statistics */
+	struct qos_info qos;
+
+	struct usb_ctrlrequest *tx_setuprequest;
+	struct urb *tx_urb;
+	__u8 *tx_buf_clear;
+	unsigned int tx_buf_clear_used;
+	unsigned int tx_buf_clear_sent;
+	__u8 *tx_buf_xored;
+
+	struct usb_ctrlrequest *rx_setuprequest;
+	struct urb *rx_urb;
+	__u8 *rx_buf;
+	__u8 rx_variable_xormask;
+	iobuff_t rx_unwrap_buff;
+	struct timeval rx_time;
+
+	struct usb_ctrlrequest *speed_setuprequest;
+	struct urb *speed_urb;
+	struct ks959_speedparams speedparams;
+	unsigned int new_speed;
+
+	spinlock_t lock;
+	int receiving;
+};
+
+/* Procedure to perform the obfuscation/padding expected by the dongle
+ *
+ * buf_cleartext    (IN) Cleartext version of the IrDA frame to transmit
+ * len_cleartext    (IN) Length of the cleartext version of IrDA frame
+ * buf_xoredtext    (OUT) Obfuscated version of frame built by proc
+ * len_maxbuf        (OUT) Maximum space available at buf_xoredtext
+ *
+ * (return)         length of obfuscated frame with padding
+ *
+ * If not enough space (as indicated by len_maxbuf vs. required padding),
+ * zero is returned
+ *
+ * The value of lookup_string is actually a required portion of the algorithm.
+ * Seems the designer of the dongle wanted to state who exactly is responsible
+ * for implementing obfuscation. Send your best (or other) wishes to him ]:-)
+ */
+static unsigned int obfuscate_tx_buffer(const __u8 * buf_cleartext,
+					unsigned int len_cleartext,
+					__u8 * buf_xoredtext,
+					unsigned int len_maxbuf)
+{
+	unsigned int len_xoredtext;
+
+	/* Calculate required length with padding, check for necessary space */
+	len_xoredtext = ((len_cleartext + 7) & ~0x7) + 0x10;
+	if (len_xoredtext <= len_maxbuf) {
+		static const __u8 lookup_string[] = "wangshuofei19710";
+		__u8 xor_mask;
+
+		/* Unlike the WinXP driver, we *do* clear out the padding */
+		memset(buf_xoredtext, 0, len_xoredtext);
+
+		xor_mask = lookup_string[(len_cleartext & 0x0f) ^ 0x06] ^ 0x55;
+
+		while (len_cleartext-- > 0) {
+			*buf_xoredtext++ = *buf_cleartext++ ^ xor_mask;
+		}
+	} else {
+		len_xoredtext = 0;
+	}
+	return len_xoredtext;
+}
+
+/* Callback transmission routine */
+static void ks959_speed_irq(struct urb *urb)
+{
+	/* unlink, shutdown, unplug, other nasties */
+	if (urb->status != 0) {
+		err("ks959_speed_irq: urb asynchronously failed - %d",
+		    urb->status);
+	}
+}
+
+/* Send a control request to change speed of the dongle */
+static int ks959_change_speed(struct ks959_cb *kingsun, unsigned speed)
+{
+	static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400,
+		57600, 115200, 576000, 1152000, 4000000, 0
+	};
+	int err;
+	unsigned int i;
+
+	if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL)
+		return -ENOMEM;
+
+	/* Check that requested speed is among the supported ones */
+	for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ;
+	if (supported_speeds[i] == 0)
+		return -EOPNOTSUPP;
+
+	memset(&(kingsun->speedparams), 0, sizeof(struct ks959_speedparams));
+	kingsun->speedparams.baudrate = cpu_to_le32(speed);
+	kingsun->speedparams.flags = KS_DATA_8_BITS;
+
+	/* speed_setuprequest pre-filled in ks959_probe */
+	usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev,
+			     usb_sndctrlpipe(kingsun->usbdev, 0),
+			     (unsigned char *)kingsun->speed_setuprequest,
+			     &(kingsun->speedparams),
+			     sizeof(struct ks959_speedparams), ks959_speed_irq,
+			     kingsun);
+	kingsun->speed_urb->status = 0;
+	err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC);
+
+	return err;
+}
+
+/* Submit one fragment of an IrDA frame to the dongle */
+static void ks959_send_irq(struct urb *urb);
+static int ks959_submit_tx_fragment(struct ks959_cb *kingsun)
+{
+	unsigned int padlen;
+	unsigned int wraplen;
+	int ret;
+
+	/* Check whether current plaintext can produce a padded buffer that fits
+	   within the range handled by the dongle */
+	wraplen = (KINGSUN_SND_PACKET_SIZE & ~0x7) - 0x10;
+	if (wraplen > kingsun->tx_buf_clear_used)
+		wraplen = kingsun->tx_buf_clear_used;
+
+	/* Perform dongle obfuscation. Also remove the portion of the frame that
+	   was just obfuscated and will now be sent to the dongle. */
+	padlen = obfuscate_tx_buffer(kingsun->tx_buf_clear, wraplen,
+				     kingsun->tx_buf_xored,
+				     KINGSUN_SND_PACKET_SIZE);
+
+	/* Calculate how much data can be transmitted in this urb */
+	kingsun->tx_setuprequest->wValue = cpu_to_le16(wraplen);
+	kingsun->tx_setuprequest->wLength = cpu_to_le16(padlen);
+	/* Rest of the fields were filled in ks959_probe */
+	usb_fill_control_urb(kingsun->tx_urb, kingsun->usbdev,
+			     usb_sndctrlpipe(kingsun->usbdev, 0),
+			     (unsigned char *)kingsun->tx_setuprequest,
+			     kingsun->tx_buf_xored, padlen,
+			     ks959_send_irq, kingsun);
+	kingsun->tx_urb->status = 0;
+	ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC);
+
+	/* Remember how much data was sent, in order to update at callback */
+	kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0;
+	return ret;
+}
+
+/* Callback transmission routine */
+static void ks959_send_irq(struct urb *urb)
+{
+	struct ks959_cb *kingsun = urb->context;
+	struct net_device *netdev = kingsun->netdev;
+	int ret = 0;
+
+	/* in process of stopping, just drop data */
+	if (!netif_running(kingsun->netdev)) {
+		err("ks959_send_irq: Network not running!");
+		return;
+	}
+
+	/* unlink, shutdown, unplug, other nasties */
+	if (urb->status != 0) {
+		err("ks959_send_irq: urb asynchronously failed - %d",
+		    urb->status);
+		return;
+	}
+
+	if (kingsun->tx_buf_clear_used > 0) {
+		/* Update data remaining to be sent */
+		if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) {
+			memmove(kingsun->tx_buf_clear,
+				kingsun->tx_buf_clear +
+				kingsun->tx_buf_clear_sent,
+				kingsun->tx_buf_clear_used -
+				kingsun->tx_buf_clear_sent);
+		}
+		kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent;
+		kingsun->tx_buf_clear_sent = 0;
+
+		if (kingsun->tx_buf_clear_used > 0) {
+			/* There is more data to be sent */
+			if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
+				err("ks959_send_irq: failed tx_urb submit: %d",
+				    ret);
+				switch (ret) {
+				case -ENODEV:
+				case -EPIPE:
+					break;
+				default:
+					kingsun->stats.tx_errors++;
+					netif_start_queue(netdev);
+				}
+			}
+		} else {
+			/* All data sent, send next speed && wake network queue */
+			if (kingsun->new_speed != -1 &&
+			    cpu_to_le32(kingsun->new_speed) !=
+			    kingsun->speedparams.baudrate)
+				ks959_change_speed(kingsun, kingsun->new_speed);
+
+			netif_wake_queue(netdev);
+		}
+	}
+}
+
+/*
+ * Called from net/core when new frame is available.
+ */
+static int ks959_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct ks959_cb *kingsun;
+	unsigned int wraplen;
+	int ret = 0;
+
+	if (skb == NULL || netdev == NULL)
+		return -EINVAL;
+
+	netif_stop_queue(netdev);
+
+	/* the IRDA wrapping routines don't deal with non linear skb */
+	SKB_LINEAR_ASSERT(skb);
+
+	kingsun = netdev_priv(netdev);
+
+	spin_lock(&kingsun->lock);
+	kingsun->new_speed = irda_get_next_speed(skb);
+
+	/* Append data to the end of whatever data remains to be transmitted */
+	wraplen =
+	    async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE);
+	kingsun->tx_buf_clear_used = wraplen;
+
+	if ((ret = ks959_submit_tx_fragment(kingsun)) != 0) {
+		err("ks959_hard_xmit: failed tx_urb submit: %d", ret);
+		switch (ret) {
+		case -ENODEV:
+		case -EPIPE:
+			break;
+		default:
+			kingsun->stats.tx_errors++;
+			netif_start_queue(netdev);
+		}
+	} else {
+		kingsun->stats.tx_packets++;
+		kingsun->stats.tx_bytes += skb->len;
+
+	}
+
+	dev_kfree_skb(skb);
+	spin_unlock(&kingsun->lock);
+
+	return ret;
+}
+
+/* Receive callback function */
+static void ks959_rcv_irq(struct urb *urb)
+{
+	struct ks959_cb *kingsun = urb->context;
+	int ret;
+
+	/* in process of stopping, just drop data */
+	if (!netif_running(kingsun->netdev)) {
+		kingsun->receiving = 0;
+		return;
+	}
+
+	/* unlink, shutdown, unplug, other nasties */
+	if (urb->status != 0) {
+		err("kingsun_rcv_irq: urb asynchronously failed - %d",
+		    urb->status);
+		kingsun->receiving = 0;
+		return;
+	}
+
+	if (urb->actual_length > 0) {
+		__u8 *bytes = urb->transfer_buffer;
+		unsigned int i;
+
+		for (i = 0; i < urb->actual_length; i++) {
+			/* De-obfuscation implemented here: variable portion of
+			   xormask is incremented, and then used with the encoded
+			   byte for the XOR. The result of the operation is used
+			   to unwrap the SIR frame. */
+			kingsun->rx_variable_xormask++;
+			bytes[i] =
+			    bytes[i] ^ kingsun->rx_variable_xormask ^ 0x55u;
+
+			/* rx_variable_xormask doubles as an index counter so we
+			   can skip the byte at 0xff (wrapped around to 0).
+			 */
+			if (kingsun->rx_variable_xormask != 0) {
+				async_unwrap_char(kingsun->netdev,
+						  &kingsun->stats,
+						  &kingsun->rx_unwrap_buff,
+						  bytes[i]);
+			}
+		}
+		kingsun->netdev->last_rx = jiffies;
+		do_gettimeofday(&kingsun->rx_time);
+		kingsun->receiving =
+		    (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0;
+	}
+
+	/* This urb has already been filled in kingsun_net_open. Setup
+	   packet must be re-filled, but it is assumed that urb keeps the
+	   pointer to the initial setup packet, as well as the payload buffer.
+	   Setup packet is already pre-filled at ks959_probe.
+	 */
+	urb->status = 0;
+	ret = usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+/*
+ * Function kingsun_net_open (dev)
+ *
+ *    Network device is taken up. Usually this is done by "ifconfig irda0 up"
+ */
+static int ks959_net_open(struct net_device *netdev)
+{
+	struct ks959_cb *kingsun = netdev_priv(netdev);
+	int err = -ENOMEM;
+	char hwname[16];
+
+	/* At this point, urbs are NULL, and skb is NULL (see kingsun_probe) */
+	kingsun->receiving = 0;
+
+	/* Initialize for SIR to copy data directly into skb.  */
+	kingsun->rx_unwrap_buff.in_frame = FALSE;
+	kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+	kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU;
+	kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
+	if (!kingsun->rx_unwrap_buff.skb)
+		goto free_mem;
+
+	skb_reserve(kingsun->rx_unwrap_buff.skb, 1);
+	kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data;
+	do_gettimeofday(&kingsun->rx_time);
+
+	kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!kingsun->rx_urb)
+		goto free_mem;
+
+	kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!kingsun->tx_urb)
+		goto free_mem;
+
+	kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!kingsun->speed_urb)
+		goto free_mem;
+
+	/* Initialize speed for dongle */
+	kingsun->new_speed = 9600;
+	err = ks959_change_speed(kingsun, 9600);
+	if (err < 0)
+		goto free_mem;
+
+	/*
+	 * Now that everything should be initialized properly,
+	 * Open new IrLAP layer instance to take care of us...
+	 */
+	sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
+	kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
+	if (!kingsun->irlap) {
+		err("ks959-sir: irlap_open failed");
+		goto free_mem;
+	}
+
+	/* Start reception. Setup request already pre-filled in ks959_probe */
+	usb_fill_control_urb(kingsun->rx_urb, kingsun->usbdev,
+			     usb_rcvctrlpipe(kingsun->usbdev, 0),
+			     (unsigned char *)kingsun->rx_setuprequest,
+			     kingsun->rx_buf, KINGSUN_RCV_FIFO_SIZE,
+			     ks959_rcv_irq, kingsun);
+	kingsun->rx_urb->status = 0;
+	err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+	if (err) {
+		err("ks959-sir: first urb-submit failed: %d", err);
+		goto close_irlap;
+	}
+
+	netif_start_queue(netdev);
+
+	/* Situation at this point:
+	   - all work buffers allocated
+	   - urbs allocated and ready to fill
+	   - max rx packet known (in max_rx)
+	   - unwrap state machine initialized, in state outside of any frame
+	   - receive request in progress
+	   - IrLAP layer started, about to hand over packets to send
+	 */
+
+	return 0;
+
+      close_irlap:
+	irlap_close(kingsun->irlap);
+      free_mem:
+	usb_free_urb(kingsun->speed_urb);
+	kingsun->speed_urb = NULL;
+	usb_free_urb(kingsun->tx_urb);
+	kingsun->tx_urb = NULL;
+	usb_free_urb(kingsun->rx_urb);
+	kingsun->rx_urb = NULL;
+	if (kingsun->rx_unwrap_buff.skb) {
+		kfree_skb(kingsun->rx_unwrap_buff.skb);
+		kingsun->rx_unwrap_buff.skb = NULL;
+		kingsun->rx_unwrap_buff.head = NULL;
+	}
+	return err;
+}
+
+/*
+ * Function kingsun_net_close (kingsun)
+ *
+ *    Network device is taken down. Usually this is done by
+ *    "ifconfig irda0 down"
+ */
+static int ks959_net_close(struct net_device *netdev)
+{
+	struct ks959_cb *kingsun = netdev_priv(netdev);
+
+	/* Stop transmit processing */
+	netif_stop_queue(netdev);
+
+	/* Mop up receive && transmit urb's */
+	usb_kill_urb(kingsun->tx_urb);
+	usb_free_urb(kingsun->tx_urb);
+	kingsun->tx_urb = NULL;
+
+	usb_kill_urb(kingsun->speed_urb);
+	usb_free_urb(kingsun->speed_urb);
+	kingsun->speed_urb = NULL;
+
+	usb_kill_urb(kingsun->rx_urb);
+	usb_free_urb(kingsun->rx_urb);
+	kingsun->rx_urb = NULL;
+
+	kfree_skb(kingsun->rx_unwrap_buff.skb);
+	kingsun->rx_unwrap_buff.skb = NULL;
+	kingsun->rx_unwrap_buff.head = NULL;
+	kingsun->rx_unwrap_buff.in_frame = FALSE;
+	kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+	kingsun->receiving = 0;
+
+	/* Stop and remove instance of IrLAP */
+	if (kingsun->irlap)
+		irlap_close(kingsun->irlap);
+
+	kingsun->irlap = NULL;
+
+	return 0;
+}
+
+/*
+ * IOCTLs : Extra out-of-band network commands...
+ */
+static int ks959_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
+{
+	struct if_irda_req *irq = (struct if_irda_req *)rq;
+	struct ks959_cb *kingsun = netdev_priv(netdev);
+	int ret = 0;
+
+	switch (cmd) {
+	case SIOCSBANDWIDTH:	/* Set bandwidth */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		/* Check if the device is still there */
+		if (netif_device_present(kingsun->netdev))
+			return ks959_change_speed(kingsun, irq->ifr_baudrate);
+		break;
+
+	case SIOCSMEDIABUSY:	/* Set media busy */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		/* Check if the IrDA stack is still there */
+		if (netif_running(kingsun->netdev))
+			irda_device_set_media_busy(kingsun->netdev, TRUE);
+		break;
+
+	case SIOCGRECEIVING:
+		/* Only approximately true */
+		irq->ifr_receiving = kingsun->receiving;
+		break;
+
+	default:
+		ret = -EOPNOTSUPP;
+	}
+
+	return ret;
+}
+
+/*
+ * Get device stats (for /proc/net/dev and ifconfig)
+ */
+static struct net_device_stats *ks959_net_get_stats(struct net_device *netdev)
+{
+	struct ks959_cb *kingsun = netdev_priv(netdev);
+	return &kingsun->stats;
+}
+
+/*
+ * This routine is called by the USB subsystem for each new device
+ * in the system. We need to check if the device is ours, and in
+ * this case start handling it.
+ */
+static int ks959_probe(struct usb_interface *intf,
+		       const struct usb_device_id *id)
+{
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct ks959_cb *kingsun = NULL;
+	struct net_device *net = NULL;
+	int ret = -ENOMEM;
+
+	/* Allocate network device container. */
+	net = alloc_irdadev(sizeof(*kingsun));
+	if (!net)
+		goto err_out1;
+
+	SET_NETDEV_DEV(net, &intf->dev);
+	kingsun = netdev_priv(net);
+	kingsun->netdev = net;
+	kingsun->usbdev = dev;
+	kingsun->irlap = NULL;
+	kingsun->tx_setuprequest = NULL;
+	kingsun->tx_urb = NULL;
+	kingsun->tx_buf_clear = NULL;
+	kingsun->tx_buf_xored = NULL;
+	kingsun->tx_buf_clear_used = 0;
+	kingsun->tx_buf_clear_sent = 0;
+
+	kingsun->rx_setuprequest = NULL;
+	kingsun->rx_urb = NULL;
+	kingsun->rx_buf = NULL;
+	kingsun->rx_variable_xormask = 0;
+	kingsun->rx_unwrap_buff.in_frame = FALSE;
+	kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+	kingsun->rx_unwrap_buff.skb = NULL;
+	kingsun->receiving = 0;
+	spin_lock_init(&kingsun->lock);
+
+	kingsun->speed_setuprequest = NULL;
+	kingsun->speed_urb = NULL;
+	kingsun->speedparams.baudrate = 0;
+
+	/* Allocate input buffer */
+	kingsun->rx_buf = kmalloc(KINGSUN_RCV_FIFO_SIZE, GFP_KERNEL);
+	if (!kingsun->rx_buf)
+		goto free_mem;
+
+	/* Allocate input setup packet */
+	kingsun->rx_setuprequest =
+	    kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+	if (!kingsun->rx_setuprequest)
+		goto free_mem;
+	kingsun->rx_setuprequest->bRequestType =
+	    USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+	kingsun->rx_setuprequest->bRequest = KINGSUN_REQ_RECV;
+	kingsun->rx_setuprequest->wValue = cpu_to_le16(0x0200);
+	kingsun->rx_setuprequest->wIndex = 0;
+	kingsun->rx_setuprequest->wLength = cpu_to_le16(KINGSUN_RCV_FIFO_SIZE);
+
+	/* Allocate output buffer */
+	kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL);
+	if (!kingsun->tx_buf_clear)
+		goto free_mem;
+	kingsun->tx_buf_xored = kmalloc(KINGSUN_SND_PACKET_SIZE, GFP_KERNEL);
+	if (!kingsun->tx_buf_xored)
+		goto free_mem;
+
+	/* Allocate and initialize output setup packet */
+	kingsun->tx_setuprequest =
+	    kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+	if (!kingsun->tx_setuprequest)
+		goto free_mem;
+	kingsun->tx_setuprequest->bRequestType =
+	    USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+	kingsun->tx_setuprequest->bRequest = KINGSUN_REQ_SEND;
+	kingsun->tx_setuprequest->wValue = 0;
+	kingsun->tx_setuprequest->wIndex = 0;
+	kingsun->tx_setuprequest->wLength = 0;
+
+	/* Allocate and initialize speed setup packet */
+	kingsun->speed_setuprequest =
+	    kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+	if (!kingsun->speed_setuprequest)
+		goto free_mem;
+	kingsun->speed_setuprequest->bRequestType =
+	    USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+	kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND;
+	kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200);
+	kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001);
+	kingsun->speed_setuprequest->wLength =
+	    cpu_to_le16(sizeof(struct ks959_speedparams));
+
+	printk(KERN_INFO "KingSun KS-959 IRDA/USB found at address %d, "
+	       "Vendor: %x, Product: %x\n",
+	       dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
+	       le16_to_cpu(dev->descriptor.idProduct));
+
+	/* Initialize QoS for this device */
+	irda_init_max_qos_capabilies(&kingsun->qos);
+
+	/* Baud rates known to be supported. Please uncomment if devices (other
+	   than a SonyEriccson K300 phone) can be shown to support higher speed
+	   with this dongle.
+	 */
+	kingsun->qos.baud_rate.bits =
+	    IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600;
+	kingsun->qos.min_turn_time.bits &= KINGSUN_MTT;
+	irda_qos_bits_to_value(&kingsun->qos);
+
+	/* Override the network functions we need to use */
+	net->hard_start_xmit = ks959_hard_xmit;
+	net->open = ks959_net_open;
+	net->stop = ks959_net_close;
+	net->get_stats = ks959_net_get_stats;
+	net->do_ioctl = ks959_net_ioctl;
+
+	ret = register_netdev(net);
+	if (ret != 0)
+		goto free_mem;
+
+	info("IrDA: Registered KingSun KS-959 device %s", net->name);
+
+	usb_set_intfdata(intf, kingsun);
+
+	/* Situation at this point:
+	   - all work buffers allocated
+	   - setup requests pre-filled
+	   - urbs not allocated, set to NULL
+	   - max rx packet known (is KINGSUN_FIFO_SIZE)
+	   - unwrap state machine (partially) initialized, but skb == NULL
+	 */
+
+	return 0;
+
+      free_mem:
+	kfree(kingsun->speed_setuprequest);
+	kfree(kingsun->tx_setuprequest);
+	kfree(kingsun->tx_buf_xored);
+	kfree(kingsun->tx_buf_clear);
+	kfree(kingsun->rx_setuprequest);
+	kfree(kingsun->rx_buf);
+	free_netdev(net);
+      err_out1:
+	return ret;
+}
+
+/*
+ * The current device is removed, the USB layer tell us to shut it down...
+ */
+static void ks959_disconnect(struct usb_interface *intf)
+{
+	struct ks959_cb *kingsun = usb_get_intfdata(intf);
+
+	if (!kingsun)
+		return;
+
+	unregister_netdev(kingsun->netdev);
+
+	/* Mop up receive && transmit urb's */
+	if (kingsun->speed_urb != NULL) {
+		usb_kill_urb(kingsun->speed_urb);
+		usb_free_urb(kingsun->speed_urb);
+		kingsun->speed_urb = NULL;
+	}
+	if (kingsun->tx_urb != NULL) {
+		usb_kill_urb(kingsun->tx_urb);
+		usb_free_urb(kingsun->tx_urb);
+		kingsun->tx_urb = NULL;
+	}
+	if (kingsun->rx_urb != NULL) {
+		usb_kill_urb(kingsun->rx_urb);
+		usb_free_urb(kingsun->rx_urb);
+		kingsun->rx_urb = NULL;
+	}
+
+	kfree(kingsun->speed_setuprequest);
+	kfree(kingsun->tx_setuprequest);
+	kfree(kingsun->tx_buf_xored);
+	kfree(kingsun->tx_buf_clear);
+	kfree(kingsun->rx_setuprequest);
+	kfree(kingsun->rx_buf);
+	free_netdev(kingsun->netdev);
+
+	usb_set_intfdata(intf, NULL);
+}
+
+#ifdef CONFIG_PM
+/* USB suspend, so power off the transmitter/receiver */
+static int ks959_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct ks959_cb *kingsun = usb_get_intfdata(intf);
+
+	netif_device_detach(kingsun->netdev);
+	if (kingsun->speed_urb != NULL)
+		usb_kill_urb(kingsun->speed_urb);
+	if (kingsun->tx_urb != NULL)
+		usb_kill_urb(kingsun->tx_urb);
+	if (kingsun->rx_urb != NULL)
+		usb_kill_urb(kingsun->rx_urb);
+	return 0;
+}
+
+/* Coming out of suspend, so reset hardware */
+static int ks959_resume(struct usb_interface *intf)
+{
+	struct ks959_cb *kingsun = usb_get_intfdata(intf);
+
+	if (kingsun->rx_urb != NULL) {
+		/* Setup request already filled in ks959_probe */
+		usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+	}
+	netif_device_attach(kingsun->netdev);
+
+	return 0;
+}
+#endif
+
+/*
+ * USB device callbacks
+ */
+static struct usb_driver irda_driver = {
+	.name = "ks959-sir",
+	.probe = ks959_probe,
+	.disconnect = ks959_disconnect,
+	.id_table = dongles,
+#ifdef CONFIG_PM
+	.suspend = ks959_suspend,
+	.resume = ks959_resume,
+#endif
+};
+
+/*
+ * Module insertion
+ */
+static int __init ks959_init(void)
+{
+	return usb_register(&irda_driver);
+}
+
+module_init(ks959_init);
+
+/*
+ * Module removal
+ */
+static void __exit ks959_cleanup(void)
+{
+	/* Deregister the driver and remove all pending instances */
+	usb_deregister(&irda_driver);
+}
+
+module_exit(ks959_cleanup);
+
+MODULE_AUTHOR("Alex Villacís Lasso <a_villacis@palosanto.com>");
+MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun KS-959");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c
new file mode 100644
index 0000000..d01a285
--- /dev/null
+++ b/drivers/net/irda/ksdazzle-sir.c
@@ -0,0 +1,832 @@
+/*****************************************************************************
+*
+* Filename:      ksdazzle.c
+* Version:       0.1.2
+* Description:   Irda KingSun Dazzle USB Dongle
+* Status:        Experimental
+* Author:        Alex Villacís Lasso <a_villacis@palosanto.com>
+*
+*    Based on stir4200, mcs7780, kingsun-sir drivers.
+*
+*    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.
+*
+*    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.
+*
+*****************************************************************************/
+
+/*
+ * Following is my most current (2007-07-26) understanding of how the Kingsun
+ * 07D0:4100 dongle (sometimes known as the MA-660) is supposed to work. This
+ * information was deduced by examining the USB traffic captured with USBSnoopy
+ * from the WinXP driver. Feel free to update here as more of the dongle is
+ * known.
+ *
+ * General: This dongle exposes one interface with two interrupt endpoints, one
+ * IN and one OUT. In this regard, it is similar to what the Kingsun/Donshine
+ * dongle (07c0:4200) exposes. Traffic is raw and needs to be wrapped and
+ * unwrapped manually as in stir4200, kingsun-sir, and ks959-sir.
+ *
+ * Transmission: To transmit an IrDA frame, it is necessary to wrap it, then
+ * split it into multiple segments of up to 7 bytes each, and transmit each in
+ * sequence. It seems that sending a single big block (like kingsun-sir does)
+ * won't work with this dongle. Each segment needs to be prefixed with a value
+ * equal to (unsigned char)0xF8 + <number of bytes in segment>, inside a payload
+ * of exactly 8 bytes. For example, a segment of 1 byte gets prefixed by 0xF9,
+ * and one of 7 bytes gets prefixed by 0xFF. The bytes at the end of the
+ * payload, not considered by the prefix, are ignored (set to 0 by this
+ * implementation).
+ *
+ * Reception: To receive data, the driver must poll the dongle regularly (like
+ * kingsun-sir.c) with interrupt URBs. If data is available, it will be returned
+ * in payloads from 0 to 8 bytes long. When concatenated, these payloads form
+ * a raw IrDA stream that needs to be unwrapped as in stir4200 and kingsun-sir
+ *
+ * Speed change: To change the speed of the dongle, the driver prepares a
+ * control URB with the following as a setup packet:
+ *    bRequestType    USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE
+ *    bRequest        0x09
+ *    wValue          0x0200
+ *    wIndex          0x0001
+ *    wLength         0x0008 (length of the payload)
+ * The payload is a 8-byte record, apparently identical to the one used in
+ * drivers/usb/serial/cypress_m8.c to change speed:
+ *     __u32 baudSpeed;
+ *    unsigned int dataBits : 2;    // 0 - 5 bits 3 - 8 bits
+ *    unsigned int : 1;
+ *    unsigned int stopBits : 1;
+ *    unsigned int parityEnable : 1;
+ *    unsigned int parityType : 1;
+ *    unsigned int : 1;
+ *    unsigned int reset : 1;
+ *    unsigned char reserved[3];    // set to 0
+ *
+ * For now only SIR speeds have been observed with this dongle. Therefore,
+ * nothing is known on what changes (if any) must be done to frame wrapping /
+ * unwrapping for higher than SIR speeds. This driver assumes no change is
+ * necessary and announces support for all the way to 115200 bps.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/usb.h>
+#include <linux/device.h>
+#include <linux/crc32.h>
+
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/crc.h>
+
+#define KSDAZZLE_VENDOR_ID 0x07d0
+#define KSDAZZLE_PRODUCT_ID 0x4100
+
+/* These are the currently known USB ids */
+static struct usb_device_id dongles[] = {
+	/* KingSun Co,Ltd  IrDA/USB Bridge */
+	{USB_DEVICE(KSDAZZLE_VENDOR_ID, KSDAZZLE_PRODUCT_ID)},
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, dongles);
+
+#define KINGSUN_MTT 0x07
+#define KINGSUN_REQ_RECV 0x01
+#define KINGSUN_REQ_SEND 0x09
+
+#define KINGSUN_SND_FIFO_SIZE    2048	/* Max packet we can send */
+#define KINGSUN_RCV_MAX 2048	/* Max transfer we can receive */
+
+struct ksdazzle_speedparams {
+	__le32 baudrate;	/* baud rate, little endian */
+	__u8 flags;
+	__u8 reserved[3];
+} __attribute__ ((packed));
+
+#define KS_DATA_5_BITS 0x00
+#define KS_DATA_6_BITS 0x01
+#define KS_DATA_7_BITS 0x02
+#define KS_DATA_8_BITS 0x03
+
+#define KS_STOP_BITS_1 0x00
+#define KS_STOP_BITS_2 0x08
+
+#define KS_PAR_DISABLE    0x00
+#define KS_PAR_EVEN    0x10
+#define KS_PAR_ODD    0x30
+#define KS_RESET    0x80
+
+#define KINGSUN_EP_IN			0
+#define KINGSUN_EP_OUT			1
+
+struct ksdazzle_cb {
+	struct usb_device *usbdev;	/* init: probe_irda */
+	struct net_device *netdev;	/* network layer */
+	struct irlap_cb *irlap;	/* The link layer we are binded to */
+	struct net_device_stats stats;	/* network statistics */
+	struct qos_info qos;
+
+	struct urb *tx_urb;
+	__u8 *tx_buf_clear;
+	unsigned int tx_buf_clear_used;
+	unsigned int tx_buf_clear_sent;
+	__u8 tx_payload[8];
+
+	struct urb *rx_urb;
+	__u8 *rx_buf;
+	iobuff_t rx_unwrap_buff;
+
+	struct usb_ctrlrequest *speed_setuprequest;
+	struct urb *speed_urb;
+	struct ksdazzle_speedparams speedparams;
+	unsigned int new_speed;
+
+	__u8 ep_in;
+	__u8 ep_out;
+
+	spinlock_t lock;
+	int receiving;
+};
+
+/* Callback transmission routine */
+static void ksdazzle_speed_irq(struct urb *urb)
+{
+	/* unlink, shutdown, unplug, other nasties */
+	if (urb->status != 0) {
+		err("ksdazzle_speed_irq: urb asynchronously failed - %d",
+		    urb->status);
+	}
+}
+
+/* Send a control request to change speed of the dongle */
+static int ksdazzle_change_speed(struct ksdazzle_cb *kingsun, unsigned speed)
+{
+	static unsigned int supported_speeds[] = { 2400, 9600, 19200, 38400,
+		57600, 115200, 576000, 1152000, 4000000, 0
+	};
+	int err;
+	unsigned int i;
+
+	if (kingsun->speed_setuprequest == NULL || kingsun->speed_urb == NULL)
+		return -ENOMEM;
+
+	/* Check that requested speed is among the supported ones */
+	for (i = 0; supported_speeds[i] && supported_speeds[i] != speed; i++) ;
+	if (supported_speeds[i] == 0)
+		return -EOPNOTSUPP;
+
+	memset(&(kingsun->speedparams), 0, sizeof(struct ksdazzle_speedparams));
+	kingsun->speedparams.baudrate = cpu_to_le32(speed);
+	kingsun->speedparams.flags = KS_DATA_8_BITS;
+
+	/* speed_setuprequest pre-filled in ksdazzle_probe */
+	usb_fill_control_urb(kingsun->speed_urb, kingsun->usbdev,
+			     usb_sndctrlpipe(kingsun->usbdev, 0),
+			     (unsigned char *)kingsun->speed_setuprequest,
+			     &(kingsun->speedparams),
+			     sizeof(struct ksdazzle_speedparams),
+			     ksdazzle_speed_irq, kingsun);
+	kingsun->speed_urb->status = 0;
+	err = usb_submit_urb(kingsun->speed_urb, GFP_ATOMIC);
+
+	return err;
+}
+
+/* Submit one fragment of an IrDA frame to the dongle */
+static void ksdazzle_send_irq(struct urb *urb);
+static int ksdazzle_submit_tx_fragment(struct ksdazzle_cb *kingsun)
+{
+	unsigned int wraplen;
+	int ret;
+
+	/* We can send at most 7 bytes of payload at a time */
+	wraplen = 7;
+	if (wraplen > kingsun->tx_buf_clear_used)
+		wraplen = kingsun->tx_buf_clear_used;
+
+	/* Prepare payload prefix with used length */
+	memset(kingsun->tx_payload, 0, 8);
+	kingsun->tx_payload[0] = (unsigned char)0xf8 + wraplen;
+	memcpy(kingsun->tx_payload + 1, kingsun->tx_buf_clear, wraplen);
+
+	usb_fill_int_urb(kingsun->tx_urb, kingsun->usbdev,
+			 usb_sndintpipe(kingsun->usbdev, kingsun->ep_out),
+			 kingsun->tx_payload, 8, ksdazzle_send_irq, kingsun, 1);
+	kingsun->tx_urb->status = 0;
+	ret = usb_submit_urb(kingsun->tx_urb, GFP_ATOMIC);
+
+	/* Remember how much data was sent, in order to update at callback */
+	kingsun->tx_buf_clear_sent = (ret == 0) ? wraplen : 0;
+	return ret;
+}
+
+/* Callback transmission routine */
+static void ksdazzle_send_irq(struct urb *urb)
+{
+	struct ksdazzle_cb *kingsun = urb->context;
+	struct net_device *netdev = kingsun->netdev;
+	int ret = 0;
+
+	/* in process of stopping, just drop data */
+	if (!netif_running(kingsun->netdev)) {
+		err("ksdazzle_send_irq: Network not running!");
+		return;
+	}
+
+	/* unlink, shutdown, unplug, other nasties */
+	if (urb->status != 0) {
+		err("ksdazzle_send_irq: urb asynchronously failed - %d",
+		    urb->status);
+		return;
+	}
+
+	if (kingsun->tx_buf_clear_used > 0) {
+		/* Update data remaining to be sent */
+		if (kingsun->tx_buf_clear_sent < kingsun->tx_buf_clear_used) {
+			memmove(kingsun->tx_buf_clear,
+				kingsun->tx_buf_clear +
+				kingsun->tx_buf_clear_sent,
+				kingsun->tx_buf_clear_used -
+				kingsun->tx_buf_clear_sent);
+		}
+		kingsun->tx_buf_clear_used -= kingsun->tx_buf_clear_sent;
+		kingsun->tx_buf_clear_sent = 0;
+
+		if (kingsun->tx_buf_clear_used > 0) {
+			/* There is more data to be sent */
+			if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) {
+				err("ksdazzle_send_irq: failed tx_urb submit: %d", ret);
+				switch (ret) {
+				case -ENODEV:
+				case -EPIPE:
+					break;
+				default:
+					kingsun->stats.tx_errors++;
+					netif_start_queue(netdev);
+				}
+			}
+		} else {
+			/* All data sent, send next speed && wake network queue */
+			if (kingsun->new_speed != -1 &&
+			    cpu_to_le32(kingsun->new_speed) !=
+			    kingsun->speedparams.baudrate)
+				ksdazzle_change_speed(kingsun,
+						      kingsun->new_speed);
+
+			netif_wake_queue(netdev);
+		}
+	}
+}
+
+/*
+ * Called from net/core when new frame is available.
+ */
+static int ksdazzle_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct ksdazzle_cb *kingsun;
+	unsigned int wraplen;
+	int ret = 0;
+
+	if (skb == NULL || netdev == NULL)
+		return -EINVAL;
+
+	netif_stop_queue(netdev);
+
+	/* the IRDA wrapping routines don't deal with non linear skb */
+	SKB_LINEAR_ASSERT(skb);
+
+	kingsun = netdev_priv(netdev);
+
+	spin_lock(&kingsun->lock);
+	kingsun->new_speed = irda_get_next_speed(skb);
+
+	/* Append data to the end of whatever data remains to be transmitted */
+	wraplen =
+	    async_wrap_skb(skb, kingsun->tx_buf_clear, KINGSUN_SND_FIFO_SIZE);
+	kingsun->tx_buf_clear_used = wraplen;
+
+	if ((ret = ksdazzle_submit_tx_fragment(kingsun)) != 0) {
+		err("ksdazzle_hard_xmit: failed tx_urb submit: %d", ret);
+		switch (ret) {
+		case -ENODEV:
+		case -EPIPE:
+			break;
+		default:
+			kingsun->stats.tx_errors++;
+			netif_start_queue(netdev);
+		}
+	} else {
+		kingsun->stats.tx_packets++;
+		kingsun->stats.tx_bytes += skb->len;
+
+	}
+
+	dev_kfree_skb(skb);
+	spin_unlock(&kingsun->lock);
+
+	return ret;
+}
+
+/* Receive callback function */
+static void ksdazzle_rcv_irq(struct urb *urb)
+{
+	struct ksdazzle_cb *kingsun = urb->context;
+
+	/* in process of stopping, just drop data */
+	if (!netif_running(kingsun->netdev)) {
+		kingsun->receiving = 0;
+		return;
+	}
+
+	/* unlink, shutdown, unplug, other nasties */
+	if (urb->status != 0) {
+		err("ksdazzle_rcv_irq: urb asynchronously failed - %d",
+		    urb->status);
+		kingsun->receiving = 0;
+		return;
+	}
+
+	if (urb->actual_length > 0) {
+		__u8 *bytes = urb->transfer_buffer;
+		unsigned int i;
+
+		for (i = 0; i < urb->actual_length; i++) {
+			async_unwrap_char(kingsun->netdev, &kingsun->stats,
+					  &kingsun->rx_unwrap_buff, bytes[i]);
+		}
+		kingsun->netdev->last_rx = jiffies;
+		kingsun->receiving =
+		    (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0;
+	}
+
+	/* This urb has already been filled in ksdazzle_net_open. It is assumed that
+	   urb keeps the pointer to the payload buffer.
+	 */
+	urb->status = 0;
+	usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+/*
+ * Function ksdazzle_net_open (dev)
+ *
+ *    Network device is taken up. Usually this is done by "ifconfig irda0 up"
+ */
+static int ksdazzle_net_open(struct net_device *netdev)
+{
+	struct ksdazzle_cb *kingsun = netdev_priv(netdev);
+	int err = -ENOMEM;
+	char hwname[16];
+
+	/* At this point, urbs are NULL, and skb is NULL (see ksdazzle_probe) */
+	kingsun->receiving = 0;
+
+	/* Initialize for SIR to copy data directly into skb.  */
+	kingsun->rx_unwrap_buff.in_frame = FALSE;
+	kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+	kingsun->rx_unwrap_buff.truesize = IRDA_SKB_MAX_MTU;
+	kingsun->rx_unwrap_buff.skb = dev_alloc_skb(IRDA_SKB_MAX_MTU);
+	if (!kingsun->rx_unwrap_buff.skb)
+		goto free_mem;
+
+	skb_reserve(kingsun->rx_unwrap_buff.skb, 1);
+	kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data;
+
+	kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!kingsun->rx_urb)
+		goto free_mem;
+
+	kingsun->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!kingsun->tx_urb)
+		goto free_mem;
+
+	kingsun->speed_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!kingsun->speed_urb)
+		goto free_mem;
+
+	/* Initialize speed for dongle */
+	kingsun->new_speed = 9600;
+	err = ksdazzle_change_speed(kingsun, 9600);
+	if (err < 0)
+		goto free_mem;
+
+	/*
+	 * Now that everything should be initialized properly,
+	 * Open new IrLAP layer instance to take care of us...
+	 */
+	sprintf(hwname, "usb#%d", kingsun->usbdev->devnum);
+	kingsun->irlap = irlap_open(netdev, &kingsun->qos, hwname);
+	if (!kingsun->irlap) {
+		err("ksdazzle-sir: irlap_open failed");
+		goto free_mem;
+	}
+
+	/* Start reception. */
+	usb_fill_int_urb(kingsun->rx_urb, kingsun->usbdev,
+			 usb_rcvintpipe(kingsun->usbdev, kingsun->ep_in),
+			 kingsun->rx_buf, KINGSUN_RCV_MAX, ksdazzle_rcv_irq,
+			 kingsun, 1);
+	kingsun->rx_urb->status = 0;
+	err = usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+	if (err) {
+		err("ksdazzle-sir: first urb-submit failed: %d", err);
+		goto close_irlap;
+	}
+
+	netif_start_queue(netdev);
+
+	/* Situation at this point:
+	   - all work buffers allocated
+	   - urbs allocated and ready to fill
+	   - max rx packet known (in max_rx)
+	   - unwrap state machine initialized, in state outside of any frame
+	   - receive request in progress
+	   - IrLAP layer started, about to hand over packets to send
+	 */
+
+	return 0;
+
+      close_irlap:
+	irlap_close(kingsun->irlap);
+      free_mem:
+	usb_free_urb(kingsun->speed_urb);
+	kingsun->speed_urb = NULL;
+	usb_free_urb(kingsun->tx_urb);
+	kingsun->tx_urb = NULL;
+	usb_free_urb(kingsun->rx_urb);
+	kingsun->rx_urb = NULL;
+	if (kingsun->rx_unwrap_buff.skb) {
+		kfree_skb(kingsun->rx_unwrap_buff.skb);
+		kingsun->rx_unwrap_buff.skb = NULL;
+		kingsun->rx_unwrap_buff.head = NULL;
+	}
+	return err;
+}
+
+/*
+ * Function ksdazzle_net_close (dev)
+ *
+ *    Network device is taken down. Usually this is done by
+ *    "ifconfig irda0 down"
+ */
+static int ksdazzle_net_close(struct net_device *netdev)
+{
+	struct ksdazzle_cb *kingsun = netdev_priv(netdev);
+
+	/* Stop transmit processing */
+	netif_stop_queue(netdev);
+
+	/* Mop up receive && transmit urb's */
+	usb_kill_urb(kingsun->tx_urb);
+	usb_free_urb(kingsun->tx_urb);
+	kingsun->tx_urb = NULL;
+
+	usb_kill_urb(kingsun->speed_urb);
+	usb_free_urb(kingsun->speed_urb);
+	kingsun->speed_urb = NULL;
+
+	usb_kill_urb(kingsun->rx_urb);
+	usb_free_urb(kingsun->rx_urb);
+	kingsun->rx_urb = NULL;
+
+	kfree_skb(kingsun->rx_unwrap_buff.skb);
+	kingsun->rx_unwrap_buff.skb = NULL;
+	kingsun->rx_unwrap_buff.head = NULL;
+	kingsun->rx_unwrap_buff.in_frame = FALSE;
+	kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+	kingsun->receiving = 0;
+
+	/* Stop and remove instance of IrLAP */
+	irlap_close(kingsun->irlap);
+
+	kingsun->irlap = NULL;
+
+	return 0;
+}
+
+/*
+ * IOCTLs : Extra out-of-band network commands...
+ */
+static int ksdazzle_net_ioctl(struct net_device *netdev, struct ifreq *rq,
+			      int cmd)
+{
+	struct if_irda_req *irq = (struct if_irda_req *)rq;
+	struct ksdazzle_cb *kingsun = netdev_priv(netdev);
+	int ret = 0;
+
+	switch (cmd) {
+	case SIOCSBANDWIDTH:	/* Set bandwidth */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		/* Check if the device is still there */
+		if (netif_device_present(kingsun->netdev))
+			return ksdazzle_change_speed(kingsun,
+						     irq->ifr_baudrate);
+		break;
+
+	case SIOCSMEDIABUSY:	/* Set media busy */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		/* Check if the IrDA stack is still there */
+		if (netif_running(kingsun->netdev))
+			irda_device_set_media_busy(kingsun->netdev, TRUE);
+		break;
+
+	case SIOCGRECEIVING:
+		/* Only approximately true */
+		irq->ifr_receiving = kingsun->receiving;
+		break;
+
+	default:
+		ret = -EOPNOTSUPP;
+	}
+
+	return ret;
+}
+
+/*
+ * Get device stats (for /proc/net/dev and ifconfig)
+ */
+static struct net_device_stats *ksdazzle_net_get_stats(struct net_device
+						       *netdev)
+{
+	struct ksdazzle_cb *kingsun = netdev_priv(netdev);
+	return &kingsun->stats;
+}
+
+/*
+ * This routine is called by the USB subsystem for each new device
+ * in the system. We need to check if the device is ours, and in
+ * this case start handling it.
+ */
+static int ksdazzle_probe(struct usb_interface *intf,
+			  const struct usb_device_id *id)
+{
+	struct usb_host_interface *interface;
+	struct usb_endpoint_descriptor *endpoint;
+
+	struct usb_device *dev = interface_to_usbdev(intf);
+	struct ksdazzle_cb *kingsun = NULL;
+	struct net_device *net = NULL;
+	int ret = -ENOMEM;
+	int pipe, maxp_in, maxp_out;
+	__u8 ep_in;
+	__u8 ep_out;
+
+	/* Check that there really are two interrupt endpoints. Check based on the
+	   one in drivers/usb/input/usbmouse.c
+	 */
+	interface = intf->cur_altsetting;
+	if (interface->desc.bNumEndpoints != 2) {
+		err("ksdazzle: expected 2 endpoints, found %d",
+		    interface->desc.bNumEndpoints);
+		return -ENODEV;
+	}
+	endpoint = &interface->endpoint[KINGSUN_EP_IN].desc;
+	if (!usb_endpoint_is_int_in(endpoint)) {
+		err("ksdazzle: endpoint 0 is not interrupt IN");
+		return -ENODEV;
+	}
+
+	ep_in = endpoint->bEndpointAddress;
+	pipe = usb_rcvintpipe(dev, ep_in);
+	maxp_in = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+	if (maxp_in > 255 || maxp_in <= 1) {
+		err("ksdazzle: endpoint 0 has max packet size %d not in range [2..255]", maxp_in);
+		return -ENODEV;
+	}
+
+	endpoint = &interface->endpoint[KINGSUN_EP_OUT].desc;
+	if (!usb_endpoint_is_int_out(endpoint)) {
+		err("ksdazzle: endpoint 1 is not interrupt OUT");
+		return -ENODEV;
+	}
+
+	ep_out = endpoint->bEndpointAddress;
+	pipe = usb_sndintpipe(dev, ep_out);
+	maxp_out = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+	/* Allocate network device container. */
+	net = alloc_irdadev(sizeof(*kingsun));
+	if (!net)
+		goto err_out1;
+
+	SET_NETDEV_DEV(net, &intf->dev);
+	kingsun = netdev_priv(net);
+	kingsun->netdev = net;
+	kingsun->usbdev = dev;
+	kingsun->ep_in = ep_in;
+	kingsun->ep_out = ep_out;
+	kingsun->irlap = NULL;
+	kingsun->tx_urb = NULL;
+	kingsun->tx_buf_clear = NULL;
+	kingsun->tx_buf_clear_used = 0;
+	kingsun->tx_buf_clear_sent = 0;
+
+	kingsun->rx_urb = NULL;
+	kingsun->rx_buf = NULL;
+	kingsun->rx_unwrap_buff.in_frame = FALSE;
+	kingsun->rx_unwrap_buff.state = OUTSIDE_FRAME;
+	kingsun->rx_unwrap_buff.skb = NULL;
+	kingsun->receiving = 0;
+	spin_lock_init(&kingsun->lock);
+
+	kingsun->speed_setuprequest = NULL;
+	kingsun->speed_urb = NULL;
+	kingsun->speedparams.baudrate = 0;
+
+	/* Allocate input buffer */
+	kingsun->rx_buf = kmalloc(KINGSUN_RCV_MAX, GFP_KERNEL);
+	if (!kingsun->rx_buf)
+		goto free_mem;
+
+	/* Allocate output buffer */
+	kingsun->tx_buf_clear = kmalloc(KINGSUN_SND_FIFO_SIZE, GFP_KERNEL);
+	if (!kingsun->tx_buf_clear)
+		goto free_mem;
+
+	/* Allocate and initialize speed setup packet */
+	kingsun->speed_setuprequest =
+	    kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
+	if (!kingsun->speed_setuprequest)
+		goto free_mem;
+	kingsun->speed_setuprequest->bRequestType =
+	    USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+	kingsun->speed_setuprequest->bRequest = KINGSUN_REQ_SEND;
+	kingsun->speed_setuprequest->wValue = cpu_to_le16(0x0200);
+	kingsun->speed_setuprequest->wIndex = cpu_to_le16(0x0001);
+	kingsun->speed_setuprequest->wLength =
+	    cpu_to_le16(sizeof(struct ksdazzle_speedparams));
+
+	printk(KERN_INFO "KingSun/Dazzle IRDA/USB found at address %d, "
+	       "Vendor: %x, Product: %x\n",
+	       dev->devnum, le16_to_cpu(dev->descriptor.idVendor),
+	       le16_to_cpu(dev->descriptor.idProduct));
+
+	/* Initialize QoS for this device */
+	irda_init_max_qos_capabilies(&kingsun->qos);
+
+	/* Baud rates known to be supported. Please uncomment if devices (other
+	   than a SonyEriccson K300 phone) can be shown to support higher speeds
+	   with this dongle.
+	 */
+	kingsun->qos.baud_rate.bits =
+	    IR_2400 | IR_9600 | IR_19200 | IR_38400 | IR_57600 | IR_115200;
+	kingsun->qos.min_turn_time.bits &= KINGSUN_MTT;
+	irda_qos_bits_to_value(&kingsun->qos);
+
+	/* Override the network functions we need to use */
+	net->hard_start_xmit = ksdazzle_hard_xmit;
+	net->open = ksdazzle_net_open;
+	net->stop = ksdazzle_net_close;
+	net->get_stats = ksdazzle_net_get_stats;
+	net->do_ioctl = ksdazzle_net_ioctl;
+
+	ret = register_netdev(net);
+	if (ret != 0)
+		goto free_mem;
+
+	info("IrDA: Registered KingSun/Dazzle device %s", net->name);
+
+	usb_set_intfdata(intf, kingsun);
+
+	/* Situation at this point:
+	   - all work buffers allocated
+	   - setup requests pre-filled
+	   - urbs not allocated, set to NULL
+	   - max rx packet known (is KINGSUN_FIFO_SIZE)
+	   - unwrap state machine (partially) initialized, but skb == NULL
+	 */
+
+	return 0;
+
+      free_mem:
+	kfree(kingsun->speed_setuprequest);
+	kfree(kingsun->tx_buf_clear);
+	kfree(kingsun->rx_buf);
+	free_netdev(net);
+      err_out1:
+	return ret;
+}
+
+/*
+ * The current device is removed, the USB layer tell us to shut it down...
+ */
+static void ksdazzle_disconnect(struct usb_interface *intf)
+{
+	struct ksdazzle_cb *kingsun = usb_get_intfdata(intf);
+
+	if (!kingsun)
+		return;
+
+	unregister_netdev(kingsun->netdev);
+
+	/* Mop up receive && transmit urb's */
+	usb_kill_urb(kingsun->speed_urb);
+	usb_free_urb(kingsun->speed_urb);
+	kingsun->speed_urb = NULL;
+
+	usb_kill_urb(kingsun->tx_urb);
+	usb_free_urb(kingsun->tx_urb);
+	kingsun->tx_urb = NULL;
+
+	usb_kill_urb(kingsun->rx_urb);
+	usb_free_urb(kingsun->rx_urb);
+	kingsun->rx_urb = NULL;
+
+	kfree(kingsun->speed_setuprequest);
+	kfree(kingsun->tx_buf_clear);
+	kfree(kingsun->rx_buf);
+	free_netdev(kingsun->netdev);
+
+	usb_set_intfdata(intf, NULL);
+}
+
+#ifdef CONFIG_PM
+/* USB suspend, so power off the transmitter/receiver */
+static int ksdazzle_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct ksdazzle_cb *kingsun = usb_get_intfdata(intf);
+
+	netif_device_detach(kingsun->netdev);
+	if (kingsun->speed_urb != NULL)
+		usb_kill_urb(kingsun->speed_urb);
+	if (kingsun->tx_urb != NULL)
+		usb_kill_urb(kingsun->tx_urb);
+	if (kingsun->rx_urb != NULL)
+		usb_kill_urb(kingsun->rx_urb);
+	return 0;
+}
+
+/* Coming out of suspend, so reset hardware */
+static int ksdazzle_resume(struct usb_interface *intf)
+{
+	struct ksdazzle_cb *kingsun = usb_get_intfdata(intf);
+
+	if (kingsun->rx_urb != NULL) {
+		/* Setup request already filled in ksdazzle_probe */
+		usb_submit_urb(kingsun->rx_urb, GFP_KERNEL);
+	}
+	netif_device_attach(kingsun->netdev);
+
+	return 0;
+}
+#endif
+
+/*
+ * USB device callbacks
+ */
+static struct usb_driver irda_driver = {
+	.name = "ksdazzle-sir",
+	.probe = ksdazzle_probe,
+	.disconnect = ksdazzle_disconnect,
+	.id_table = dongles,
+#ifdef CONFIG_PM
+	.suspend = ksdazzle_suspend,
+	.resume = ksdazzle_resume,
+#endif
+};
+
+/*
+ * Module insertion
+ */
+static int __init ksdazzle_init(void)
+{
+	return usb_register(&irda_driver);
+}
+
+module_init(ksdazzle_init);
+
+/*
+ * Module removal
+ */
+static void __exit ksdazzle_cleanup(void)
+{
+	/* Deregister the driver and remove all pending instances */
+	usb_deregister(&irda_driver);
+}
+
+module_exit(ksdazzle_cleanup);
+
+MODULE_AUTHOR("Alex Villacís Lasso <a_villacis@palosanto.com>");
+MODULE_DESCRIPTION("IrDA-USB Dongle Driver for KingSun Dazzle");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index 0de8672..0b76919 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -50,7 +50,6 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/module.h>
 #include <linux/kref.h>
 #include <linux/usb.h>
 #include <linux/device.h>
@@ -465,7 +464,7 @@
 	}
 
 	fcs = ~(crc32_le(~0, buf, new_len));
-	if(fcs != le32_to_cpu(get_unaligned((u32 *)(buf+new_len)))) {
+	if(fcs != le32_to_cpu(get_unaligned((__le32 *)(buf+new_len)))) {
 		IRDA_ERROR("crc error calc 0x%x len %d\n", fcs, new_len);
 		mcs->stats.rx_errors++;
 		mcs->stats.rx_crc_errors++;
@@ -899,8 +898,6 @@
 
 	IRDA_DEBUG(1, "MCS7780 USB-IrDA bridge found at %d.\n", udev->devnum);
 
-	/* what is it realy for? */
-	SET_MODULE_OWNER(ndev);
 	SET_NETDEV_DEV(ndev, &intf->dev);
 
 	ret = usb_reset_configuration(udev);
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index d96c897..12b9378 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -437,7 +437,6 @@
 	self->tx_fifo.tail = self->tx_buff.head;
 
 	/* Override the network functions we need to use */
-	SET_MODULE_OWNER(dev);
 	dev->hard_start_xmit = nsc_ircc_hard_xmit_sir;
 	dev->open            = nsc_ircc_net_open;
 	dev->stop            = nsc_ircc_net_close;
diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c
index 9d6c8f3..6078e03 100644
--- a/drivers/net/irda/sir_dev.c
+++ b/drivers/net/irda/sir_dev.c
@@ -414,7 +414,7 @@
 int sirdev_set_dtr_rts(struct sir_dev *dev, int dtr, int rts)
 {
 	int ret = -ENXIO;
-	if (dev->drv->set_dtr_rts != 0)
+	if (dev->drv->set_dtr_rts)
 		ret =  dev->drv->set_dtr_rts(dev, dtr, rts);
 	return ret;
 }
@@ -913,8 +913,6 @@
 	dev->drv = drv;
 	dev->netdev = ndev;
 
-	SET_MODULE_OWNER(ndev);
-
 	/* Override the network functions we need to use */
 	ndev->hard_start_xmit = sirdev_hard_xmit;
 	ndev->open = sirdev_open;
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 36ab983..7e7b582 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -81,7 +81,7 @@
 
 static int smsc_nopnp = 1;
 module_param_named(nopnp, smsc_nopnp, bool, 0);
-MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
+MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings, defaults to true");
 
 #define DMA_INVAL 255
 static int ircc_dma = DMA_INVAL;
@@ -519,8 +519,6 @@
 		goto err_out1;
 	}
 
-	SET_MODULE_OWNER(dev);
-
 	dev->hard_start_xmit = smsc_ircc_hard_xmit_sir;
 #if SMSC_IRCC2_C_NET_TIMEOUT
 	dev->tx_timeout	     = smsc_ircc_timeout;
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index 755aa44..042bc2f 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -332,7 +332,7 @@
 	}
 
 	fcs = ~(crc32_le(~0, rx_buff->data, len));
-	if (fcs != le32_to_cpu(get_unaligned((u32 *)(rx_buff->data+len)))) {
+	if (fcs != le32_to_cpu(get_unaligned((__le32 *)(rx_buff->data+len)))) {
 		pr_debug("crc error calc 0x%x len %d\n", fcs, len);
 		stir->stats.rx_errors++;
 		stir->stats.rx_crc_errors++;
@@ -1034,7 +1034,6 @@
 	if(!net)
 		goto err_out1;
 
-	SET_MODULE_OWNER(net);
 	SET_NETDEV_DEV(net, &intf->dev);
 	stir = netdev_priv(net);
 	stir->netdev = net;
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index ff53585..126ec7c 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -429,9 +429,6 @@
 	self->tx_fifo.len = self->tx_fifo.ptr = self->tx_fifo.free = 0;
 	self->tx_fifo.tail = self->tx_buff.head;
 
-	/* Keep track of module usage */
-	SET_MODULE_OWNER(dev);
-
 	/* Override the network functions we need to use */
 	dev->hard_start_xmit = via_ircc_hard_xmit_sir;
 	dev->open = via_ircc_net_open;
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index 0538ca9..acd082a 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -1584,8 +1584,6 @@
 	vlsi_irda_dev_t *idev = ndev->priv;
 	struct pci_dev *pdev = idev->pdev;
 
-	SET_MODULE_OWNER(ndev);
-
 	ndev->irq = pdev->irq;
 	ndev->base_addr = pci_resource_start(pdev,0);
 
diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h
index ca12a60..c8b9c74 100644
--- a/drivers/net/irda/vlsi_ir.h
+++ b/drivers/net/irda/vlsi_ir.h
@@ -537,10 +537,10 @@
  */
 
 struct ring_descr_hw {
-	volatile u16	rd_count;	/* tx/rx count [11:0] */
-	u16		reserved;
+	volatile __le16	rd_count;	/* tx/rx count [11:0] */
+	__le16		reserved;
 	union {
-		u32	addr;		/* [23:0] of the buffer's busaddress */
+		__le32	addr;		/* [23:0] of the buffer's busaddress */
 		struct {
 			u8		addr_res[3];
 			volatile u8	status;		/* descriptor status */
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index 5182e80..9fd2451 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -232,9 +232,6 @@
 	self->rx_buff.data = self->rx_buff.head;
 	self->netdev = dev;
 
-	/* Keep track of module usage */
-	SET_MODULE_OWNER(dev);
-
 	/* Override the network functions we need to use */
 	dev->hard_start_xmit = w83977af_hard_xmit;
 	dev->open            = w83977af_net_open;
diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c
index 0343f12..d6ff26a 100644
--- a/drivers/net/isa-skeleton.c
+++ b/drivers/net/isa-skeleton.c
@@ -133,8 +133,6 @@
 	int base_addr = dev->base_addr;
 	int irq = dev->irq;
 
-	SET_MODULE_OWNER(dev);
-
 	if (base_addr > 0x1ff)    /* Check a single specified location. */
 		return netcard_probe1(dev, base_addr);
 	else if (base_addr != 0)  /* Don't probe at all. */
@@ -194,6 +192,7 @@
 	static unsigned version_printed;
 	int i;
 	int err = -ENODEV;
+	DECLARE_MAC_BUF(mac);
 
 	/* Grab the region so that no one else tries to probe our ioports. */
 	if (!request_region(ioaddr, NETCARD_IO_EXTENT, cardname))
@@ -219,7 +218,9 @@
 
 	/* Retrieve and print the ethernet address. */
 	for (i = 0; i < 6; i++)
-		printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+		dev->dev_addr[i] = inb(ioaddr + i);
+
+	printk("%s", print_mac(mac, dev->dev_addr));
 
 	err = -EAGAIN;
 #ifdef jumpered_interrupts
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 347d50c..97bd9dc 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -196,7 +196,6 @@
 
 struct veth_port {
 	struct device *dev;
-	struct net_device_stats stats;
 	u64 mac_addr;
 	HvLpIndexMap lpar_map;
 
@@ -822,10 +821,9 @@
 	     || ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) )
 		return 0;
 
-	cnx = kmalloc(sizeof(*cnx), GFP_KERNEL);
+	cnx = kzalloc(sizeof(*cnx), GFP_KERNEL);
 	if (! cnx)
 		return -ENOMEM;
-	memset(cnx, 0, sizeof(*cnx));
 
 	cnx->remote_lp = rlp;
 	spin_lock_init(&cnx->lock);
@@ -852,14 +850,13 @@
 	if (rc != 0)
 		return rc;
 
-	msgs = kmalloc(VETH_NUMBUFFERS * sizeof(struct veth_msg), GFP_KERNEL);
+	msgs = kcalloc(VETH_NUMBUFFERS, sizeof(struct veth_msg), GFP_KERNEL);
 	if (! msgs) {
 		veth_error("Can't allocate buffers for LPAR %d.\n", rlp);
 		return -ENOMEM;
 	}
 
 	cnx->msgs = msgs;
-	memset(msgs, 0, VETH_NUMBUFFERS * sizeof(struct veth_msg));
 
 	for (i = 0; i < VETH_NUMBUFFERS; i++) {
 		msgs[i].token = i;
@@ -938,9 +935,6 @@
 
 static int veth_open(struct net_device *dev)
 {
-	struct veth_port *port = (struct veth_port *) dev->priv;
-
-	memset(&port->stats, 0, sizeof (port->stats));
 	netif_start_queue(dev);
 	return 0;
 }
@@ -951,13 +945,6 @@
 	return 0;
 }
 
-static struct net_device_stats *veth_get_stats(struct net_device *dev)
-{
-	struct veth_port *port = (struct veth_port *) dev->priv;
-
-	return &port->stats;
-}
-
 static int veth_change_mtu(struct net_device *dev, int new_mtu)
 {
 	if ((new_mtu < 68) || (new_mtu > VETH_MAX_MTU))
@@ -1086,7 +1073,6 @@
 	dev->open = veth_open;
 	dev->hard_start_xmit = veth_start_xmit;
 	dev->stop = veth_close;
-	dev->get_stats = veth_get_stats;
 	dev->change_mtu = veth_change_mtu;
 	dev->set_mac_address = NULL;
 	dev->set_multicast_list = veth_set_multicast_list;
@@ -1185,7 +1171,6 @@
 					  HvLpIndexMap lpmask,
 					  struct net_device *dev)
 {
-	struct veth_port *port = (struct veth_port *) dev->priv;
 	int i, success, error;
 
 	success = error = 0;
@@ -1201,11 +1186,11 @@
 	}
 
 	if (error)
-		port->stats.tx_errors++;
+		dev->stats.tx_errors++;
 
 	if (success) {
-		port->stats.tx_packets++;
-		port->stats.tx_bytes += skb->len;
+		dev->stats.tx_packets++;
+		dev->stats.tx_bytes += skb->len;
 	}
 }
 
@@ -1543,8 +1528,8 @@
 		skb->protocol = eth_type_trans(skb, dev);
 		skb->ip_summed = CHECKSUM_NONE;
 		netif_rx(skb);	/* send it up */
-		port->stats.rx_packets++;
-		port->stats.rx_bytes += length;
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += length;
 	} while (startchunk += nchunks, startchunk < VETH_MAX_FRAMES_PER_MSG);
 
 	/* Ack it */
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index 3569d5b..1eee889 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -184,6 +184,7 @@
 	boolean_t rx_csum;
 
 	/* OS defined structs */
+	struct napi_struct napi;
 	struct net_device *netdev;
 	struct pci_dev *pdev;
 	struct net_device_stats net_stats;
diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c
index 52c99d0..e8eb0fd 100644
--- a/drivers/net/ixgb/ixgb_ee.c
+++ b/drivers/net/ixgb/ixgb_ee.c
@@ -411,7 +411,7 @@
 	ixgb_cleanup_eeprom(hw);
 
 	/* clear the init_ctrl_reg_1 to signify that the cache is invalidated */
-	ee_map->init_ctrl_reg_1 = le16_to_cpu(EEPROM_ICW1_SIGNATURE_CLEAR);
+	ee_map->init_ctrl_reg_1 = cpu_to_le16(EEPROM_ICW1_SIGNATURE_CLEAR);
 
 	return;
 }
@@ -476,19 +476,19 @@
 		uint16_t ee_data;
 		ee_data = ixgb_read_eeprom(hw, i);
 		checksum += ee_data;
-		hw->eeprom[i] = le16_to_cpu(ee_data);
+		hw->eeprom[i] = cpu_to_le16(ee_data);
 	}
 
 	if (checksum != (uint16_t) EEPROM_SUM) {
 		DEBUGOUT("ixgb_ee: Checksum invalid.\n");
 		/* clear the init_ctrl_reg_1 to signify that the cache is
 		 * invalidated */
-		ee_map->init_ctrl_reg_1 = le16_to_cpu(EEPROM_ICW1_SIGNATURE_CLEAR);
+		ee_map->init_ctrl_reg_1 = cpu_to_le16(EEPROM_ICW1_SIGNATURE_CLEAR);
 		return (FALSE);
 	}
 
-	if ((ee_map->init_ctrl_reg_1 & le16_to_cpu(EEPROM_ICW1_SIGNATURE_MASK))
-		 != le16_to_cpu(EEPROM_ICW1_SIGNATURE_VALID)) {
+	if ((ee_map->init_ctrl_reg_1 & cpu_to_le16(EEPROM_ICW1_SIGNATURE_MASK))
+		 != cpu_to_le16(EEPROM_ICW1_SIGNATURE_VALID)) {
 		DEBUGOUT("ixgb_ee: Signature invalid.\n");
 		return(FALSE);
 	}
@@ -511,8 +511,8 @@
 {
 	struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom;
 
-	if ((ee_map->init_ctrl_reg_1 & le16_to_cpu(EEPROM_ICW1_SIGNATURE_MASK))
-	    == le16_to_cpu(EEPROM_ICW1_SIGNATURE_VALID)) {
+	if ((ee_map->init_ctrl_reg_1 & cpu_to_le16(EEPROM_ICW1_SIGNATURE_MASK))
+	    == cpu_to_le16(EEPROM_ICW1_SIGNATURE_VALID)) {
 		return (TRUE);
 	} else {
 		return ixgb_get_eeprom_data(hw);
@@ -528,7 +528,7 @@
  * Returns:
  *          Word at indexed offset in eeprom, if valid, 0 otherwise.
  ******************************************************************************/
-uint16_t
+__le16
 ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index)
 {
 
diff --git a/drivers/net/ixgb/ixgb_ee.h b/drivers/net/ixgb/ixgb_ee.h
index ef236b9..7908bf3 100644
--- a/drivers/net/ixgb/ixgb_ee.h
+++ b/drivers/net/ixgb/ixgb_ee.h
@@ -76,22 +76,22 @@
 /* EEPROM structure */
 struct ixgb_ee_map_type {
 	uint8_t mac_addr[IXGB_ETH_LENGTH_OF_ADDRESS];
-	uint16_t compatibility;
-	uint16_t reserved1[4];
-	uint32_t pba_number;
-	uint16_t init_ctrl_reg_1;
-	uint16_t subsystem_id;
-	uint16_t subvendor_id;
-	uint16_t device_id;
-	uint16_t vendor_id;
-	uint16_t init_ctrl_reg_2;
-	uint16_t oem_reserved[16];
-	uint16_t swdpins_reg;
-	uint16_t circuit_ctrl_reg;
+	__le16 compatibility;
+	__le16 reserved1[4];
+	__le32 pba_number;
+	__le16 init_ctrl_reg_1;
+	__le16 subsystem_id;
+	__le16 subvendor_id;
+	__le16 device_id;
+	__le16 vendor_id;
+	__le16 init_ctrl_reg_2;
+	__le16 oem_reserved[16];
+	__le16 swdpins_reg;
+	__le16 circuit_ctrl_reg;
 	uint8_t d3_power;
 	uint8_t d0_power;
-	uint16_t reserved2[28];
-	uint16_t checksum;
+	__le16 reserved2[28];
+	__le16 checksum;
 };
 
 /* EEPROM Functions */
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index afde848..fddd584 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -94,8 +94,7 @@
 	{"tx_csum_offload_errors", IXGB_STAT(hw_csum_tx_error)}
 };
 
-#define IXGB_STATS_LEN	\
-	sizeof(ixgb_gstrings_stats) / sizeof(struct ixgb_stats)
+#define IXGB_STATS_LEN	ARRAY_SIZE(ixgb_gstrings_stats)
 
 static int
 ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
@@ -423,7 +422,7 @@
 {
 	struct ixgb_adapter *adapter = netdev_priv(netdev);
 	struct ixgb_hw *hw = &adapter->hw;
-	uint16_t *eeprom_buff;
+	__le16 *eeprom_buff;
 	int i, max_len, first_word, last_word;
 	int ret_val = 0;
 
@@ -447,7 +446,7 @@
 	first_word = eeprom->offset >> 1;
 	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
 
-	eeprom_buff = kmalloc(sizeof(uint16_t) *
+	eeprom_buff = kmalloc(sizeof(__le16) *
 			(last_word - first_word + 1), GFP_KERNEL);
 	if(!eeprom_buff)
 		return -ENOMEM;
@@ -660,9 +659,14 @@
 }
 
 static int 
-ixgb_get_stats_count(struct net_device *netdev)
+ixgb_get_sset_count(struct net_device *netdev, int sset)
 {
-	return IXGB_STATS_LEN;
+	switch (sset) {
+	case ETH_SS_STATS:
+		return IXGB_STATS_LEN;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void 
@@ -714,17 +718,14 @@
 	.set_rx_csum = ixgb_set_rx_csum,
 	.get_tx_csum = ixgb_get_tx_csum,
 	.set_tx_csum = ixgb_set_tx_csum,
-	.get_sg	= ethtool_op_get_sg,
 	.set_sg	= ethtool_op_set_sg,
 	.get_msglevel = ixgb_get_msglevel,
 	.set_msglevel = ixgb_set_msglevel,
-	.get_tso = ethtool_op_get_tso,
 	.set_tso = ixgb_set_tso,
 	.get_strings = ixgb_get_strings,
 	.phys_id = ixgb_phys_id,
-	.get_stats_count = ixgb_get_stats_count,
+	.get_sset_count = ixgb_get_sset_count,
 	.get_ethtool_stats = ixgb_get_ethtool_stats,
-	.get_perm_addr = ethtool_op_get_perm_addr,
 };
 
 void ixgb_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h
index 40ef5ca..af56433 100644
--- a/drivers/net/ixgb/ixgb_hw.h
+++ b/drivers/net/ixgb/ixgb_hw.h
@@ -711,7 +711,7 @@
 	uint32_t bar2;
 	uint32_t bar3;
 	uint16_t pci_cmd_word;	/* PCI command register id from PCI configuration space */
-	uint16_t eeprom[IXGB_EEPROM_SIZE];	/* EEPROM contents read at init time  */
+	__le16 eeprom[IXGB_EEPROM_SIZE];	/* EEPROM contents read at init time  */
 	unsigned long io_base;	/* Our I/O mapped location */
 	uint32_t lastLFC;
 	uint32_t lastRFC;
@@ -809,7 +809,7 @@
 uint32_t ixgb_get_ee_pba_number(struct ixgb_hw *hw);
 uint16_t ixgb_get_ee_device_id(struct ixgb_hw *hw);
 boolean_t ixgb_get_eeprom_data(struct ixgb_hw *hw);
-uint16_t ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index);
+__le16 ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index);
 
 /* Everything else */
 void ixgb_led_on(struct ixgb_hw *hw);
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 991c883..d444de5 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -97,7 +97,7 @@
 static boolean_t ixgb_clean_tx_irq(struct ixgb_adapter *adapter);
 
 #ifdef CONFIG_IXGB_NAPI
-static int ixgb_clean(struct net_device *netdev, int *budget);
+static int ixgb_clean(struct napi_struct *napi, int budget);
 static boolean_t ixgb_clean_rx_irq(struct ixgb_adapter *adapter,
 				   int *work_done, int work_to_do);
 #else
@@ -288,7 +288,7 @@
 	mod_timer(&adapter->watchdog_timer, jiffies);
 
 #ifdef CONFIG_IXGB_NAPI
-	netif_poll_enable(netdev);
+	napi_enable(&adapter->napi);
 #endif
 	ixgb_irq_enable(adapter);
 
@@ -309,7 +309,7 @@
 	if(kill_watchdog)
 		del_timer_sync(&adapter->watchdog_timer);
 #ifdef CONFIG_IXGB_NAPI
-	netif_poll_disable(netdev);
+	napi_disable(&adapter->napi);
 #endif
 	adapter->link_speed = 0;
 	adapter->link_duplex = 0;
@@ -382,7 +382,6 @@
 		goto err_alloc_etherdev;
 	}
 
-	SET_MODULE_OWNER(netdev);
 	SET_NETDEV_DEV(netdev, &pdev->dev);
 
 	pci_set_drvdata(pdev, netdev);
@@ -421,8 +420,7 @@
 	netdev->tx_timeout = &ixgb_tx_timeout;
 	netdev->watchdog_timeo = 5 * HZ;
 #ifdef CONFIG_IXGB_NAPI
-	netdev->poll = &ixgb_clean;
-	netdev->weight = 64;
+	netif_napi_add(netdev, &adapter->napi, ixgb_clean, 64);
 #endif
 	netdev->vlan_rx_register = ixgb_vlan_rx_register;
 	netdev->vlan_rx_add_vid = ixgb_vlan_rx_add_vid;
@@ -1746,7 +1744,7 @@
 	}
 
 #ifdef CONFIG_IXGB_NAPI
-	if(netif_rx_schedule_prep(netdev)) {
+	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
 
 		/* Disable interrupts and register for poll. The flush 
 		  of the posted write is intentionally left out.
@@ -1754,7 +1752,7 @@
 
 		atomic_inc(&adapter->irq_sem);
 		IXGB_WRITE_REG(&adapter->hw, IMC, ~0);
-		__netif_rx_schedule(netdev);
+		__netif_rx_schedule(netdev, &adapter->napi);
 	}
 #else
 	/* yes, that is actually a & and it is meant to make sure that
@@ -1776,27 +1774,23 @@
  **/
 
 static int
-ixgb_clean(struct net_device *netdev, int *budget)
+ixgb_clean(struct napi_struct *napi, int budget)
 {
-	struct ixgb_adapter *adapter = netdev_priv(netdev);
-	int work_to_do = min(*budget, netdev->quota);
+	struct ixgb_adapter *adapter = container_of(napi, struct ixgb_adapter, napi);
+	struct net_device *netdev = adapter->netdev;
 	int tx_cleaned;
 	int work_done = 0;
 
 	tx_cleaned = ixgb_clean_tx_irq(adapter);
-	ixgb_clean_rx_irq(adapter, &work_done, work_to_do);
-
-	*budget -= work_done;
-	netdev->quota -= work_done;
+	ixgb_clean_rx_irq(adapter, &work_done, budget);
 
 	/* if no Tx and not enough Rx work done, exit the polling mode */
 	if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
-		netif_rx_complete(netdev);
+		netif_rx_complete(netdev, napi);
 		ixgb_irq_enable(adapter);
-		return 0;
 	}
 
-	return 1;
+	return work_done;
 }
 #endif
 
diff --git a/drivers/net/ixgbe/Makefile b/drivers/net/ixgbe/Makefile
new file mode 100644
index 0000000..ccd83d9
--- /dev/null
+++ b/drivers/net/ixgbe/Makefile
@@ -0,0 +1,36 @@
+################################################################################
+#
+# Intel 10 Gigabit PCI Express Linux driver
+# Copyright(c) 1999 - 2007 Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope 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.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Contact Information:
+# Linux NICS <linux.nics@intel.com>
+# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+#
+################################################################################
+
+#
+# Makefile for the Intel(R) 10GbE PCI Express ethernet driver
+#
+
+obj-$(CONFIG_IXGBE) += ixgbe.o
+
+ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \
+              ixgbe_82598.o ixgbe_phy.o
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
new file mode 100644
index 0000000..c160a7d
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -0,0 +1,259 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_H_
+#define _IXGBE_H_
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+
+#include "ixgbe_type.h"
+#include "ixgbe_common.h"
+
+
+#define IXGBE_ERR(args...) printk(KERN_ERR "ixgbe: " args)
+
+#define PFX "ixgbe: "
+#define DPRINTK(nlevel, klevel, fmt, args...) \
+	((void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \
+	printk(KERN_##klevel PFX "%s: %s: " fmt, adapter->netdev->name, \
+		__FUNCTION__ , ## args)))
+
+/* TX/RX descriptor defines */
+#define IXGBE_DEFAULT_TXD		   1024
+#define IXGBE_MAX_TXD			   4096
+#define IXGBE_MIN_TXD			     64
+
+#define IXGBE_DEFAULT_RXD		   1024
+#define IXGBE_MAX_RXD			   4096
+#define IXGBE_MIN_RXD			     64
+
+#define IXGBE_DEFAULT_RXQ			   1
+#define IXGBE_MAX_RXQ				   1
+#define IXGBE_MIN_RXQ				   1
+
+#define IXGBE_DEFAULT_ITR_RX_USECS	    125  /*   8k irqs/sec */
+#define IXGBE_DEFAULT_ITR_TX_USECS	    250  /*   4k irqs/sec */
+#define IXGBE_MIN_ITR_USECS		    100  /* 500k irqs/sec */
+#define IXGBE_MAX_ITR_USECS		  10000  /* 100  irqs/sec */
+
+/* flow control */
+#define IXGBE_DEFAULT_FCRTL		0x10000
+#define IXGBE_MIN_FCRTL			      0
+#define IXGBE_MAX_FCRTL			0x7FF80
+#define IXGBE_DEFAULT_FCRTH		0x20000
+#define IXGBE_MIN_FCRTH			      0
+#define IXGBE_MAX_FCRTH			0x7FFF0
+#define IXGBE_DEFAULT_FCPAUSE		 0x6800  /* may be too long */
+#define IXGBE_MIN_FCPAUSE		      0
+#define IXGBE_MAX_FCPAUSE		 0xFFFF
+
+/* Supported Rx Buffer Sizes */
+#define IXGBE_RXBUFFER_64    64     /* Used for packet split */
+#define IXGBE_RXBUFFER_128   128    /* Used for packet split */
+#define IXGBE_RXBUFFER_256   256    /* Used for packet split */
+#define IXGBE_RXBUFFER_2048  2048
+
+#define IXGBE_RX_HDR_SIZE IXGBE_RXBUFFER_256
+
+#define MAXIMUM_ETHERNET_VLAN_SIZE (ETH_FRAME_LEN + ETH_FCS_LEN + VLAN_HLEN)
+
+/* How many Tx Descriptors do we need to call netif_wake_queue? */
+#define IXGBE_TX_QUEUE_WAKE 16
+
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define IXGBE_RX_BUFFER_WRITE	16	/* Must be power of 2 */
+
+#define IXGBE_TX_FLAGS_CSUM		(u32)(1)
+#define IXGBE_TX_FLAGS_VLAN		(u32)(1 << 1)
+#define IXGBE_TX_FLAGS_TSO		(u32)(1 << 2)
+#define IXGBE_TX_FLAGS_IPV4		(u32)(1 << 3)
+#define IXGBE_TX_FLAGS_VLAN_MASK	0xffff0000
+#define IXGBE_TX_FLAGS_VLAN_SHIFT	16
+
+/* wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer */
+struct ixgbe_tx_buffer {
+	struct sk_buff *skb;
+	dma_addr_t dma;
+	unsigned long time_stamp;
+	u16 length;
+	u16 next_to_watch;
+};
+
+struct ixgbe_rx_buffer {
+	struct sk_buff *skb;
+	dma_addr_t dma;
+	struct page *page;
+	dma_addr_t page_dma;
+};
+
+struct ixgbe_queue_stats {
+	u64 packets;
+	u64 bytes;
+};
+
+struct ixgbe_ring {
+	struct ixgbe_adapter *adapter;	/* backlink */
+	void *desc;			/* descriptor ring memory */
+	dma_addr_t dma;			/* phys. address of descriptor ring */
+	unsigned int size;		/* length in bytes */
+	unsigned int count;		/* amount of descriptors */
+	unsigned int next_to_use;
+	unsigned int next_to_clean;
+
+	union {
+		struct ixgbe_tx_buffer *tx_buffer_info;
+		struct ixgbe_rx_buffer *rx_buffer_info;
+	};
+
+	u16 head;
+	u16 tail;
+
+	/* To protect race between sender and clean_tx_irq */
+	spinlock_t tx_lock;
+
+	struct ixgbe_queue_stats stats;
+
+	u32 eims_value;
+	u16 itr_register;
+
+	char name[IFNAMSIZ + 5];
+	u16 work_limit;                /* max work per interrupt */
+};
+
+/* Helper macros to switch between ints/sec and what the register uses.
+ * And yes, it's the same math going both ways.
+ */
+#define EITR_INTS_PER_SEC_TO_REG(_eitr) \
+	((_eitr) ? (1000000000 / ((_eitr) * 256)) : 0)
+#define EITR_REG_TO_INTS_PER_SEC EITR_INTS_PER_SEC_TO_REG
+
+#define IXGBE_DESC_UNUSED(R) \
+	((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
+	(R)->next_to_clean - (R)->next_to_use - 1)
+
+#define IXGBE_RX_DESC_ADV(R, i)	    \
+	(&(((union ixgbe_adv_rx_desc *)((R).desc))[i]))
+#define IXGBE_TX_DESC_ADV(R, i)	    \
+	(&(((union ixgbe_adv_tx_desc *)((R).desc))[i]))
+#define IXGBE_TX_CTXTDESC_ADV(R, i)	    \
+	(&(((struct ixgbe_adv_tx_context_desc *)((R).desc))[i]))
+
+#define IXGBE_MAX_JUMBO_FRAME_SIZE        16128
+
+/* board specific private data structure */
+struct ixgbe_adapter {
+	struct timer_list watchdog_timer;
+	struct vlan_group *vlgrp;
+	u16 bd_number;
+	u16 rx_buf_len;
+	atomic_t irq_sem;
+	struct work_struct reset_task;
+
+	/* TX */
+	struct ixgbe_ring *tx_ring;	/* One per active queue */
+	struct napi_struct napi;
+	u64 restart_queue;
+	u64 lsc_int;
+	u64 hw_tso_ctxt;
+	u64 hw_tso6_ctxt;
+	u32 tx_timeout_count;
+	bool detect_tx_hung;
+
+	/* RX */
+	struct ixgbe_ring *rx_ring;	/* One per active queue */
+	u64 hw_csum_tx_good;
+	u64 hw_csum_rx_error;
+	u64 hw_csum_rx_good;
+	u64 non_eop_descs;
+	int num_tx_queues;
+	int num_rx_queues;
+	struct msix_entry *msix_entries;
+
+	u64 rx_hdr_split;
+	u32 alloc_rx_page_failed;
+	u32 alloc_rx_buff_failed;
+
+	u32 flags;
+#define IXGBE_FLAG_RX_CSUM_ENABLED              (u32)(1)
+#define IXGBE_FLAG_MSI_ENABLED                  (u32)(1 << 1)
+#define IXGBE_FLAG_MSIX_ENABLED			(u32)(1 << 2)
+#define IXGBE_FLAG_RX_PS_ENABLED		(u32)(1 << 3)
+#define IXGBE_FLAG_IN_NETPOLL			(u32)(1 << 4)
+
+	/* Interrupt Throttle Rate */
+	u32 rx_eitr;
+	u32 tx_eitr;
+
+	/* OS defined structs */
+	struct net_device *netdev;
+	struct pci_dev *pdev;
+	struct net_device_stats net_stats;
+
+	/* structs defined in ixgbe_hw.h */
+	struct ixgbe_hw hw;
+	u16 msg_enable;
+	struct ixgbe_hw_stats stats;
+	char lsc_name[IFNAMSIZ + 5];
+
+	unsigned long state;
+	u64 tx_busy;
+};
+
+enum ixbge_state_t {
+	__IXGBE_TESTING,
+	__IXGBE_RESETTING,
+	__IXGBE_DOWN
+};
+
+enum ixgbe_boards {
+	board_82598AF,
+	board_82598EB,
+	board_82598AT,
+};
+
+extern struct ixgbe_info ixgbe_82598AF_info;
+extern struct ixgbe_info ixgbe_82598EB_info;
+extern struct ixgbe_info ixgbe_82598AT_info;
+
+extern char ixgbe_driver_name[];
+extern char ixgbe_driver_version[];
+
+extern int ixgbe_up(struct ixgbe_adapter *adapter);
+extern void ixgbe_down(struct ixgbe_adapter *adapter);
+extern void ixgbe_reset(struct ixgbe_adapter *adapter);
+extern void ixgbe_update_stats(struct ixgbe_adapter *adapter);
+extern void ixgbe_set_ethtool_ops(struct net_device *netdev);
+extern int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
+				    struct ixgbe_ring *rxdr);
+extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
+				    struct ixgbe_ring *txdr);
+
+#endif /* _IXGBE_H_ */
diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c
new file mode 100644
index 0000000..00ee201
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_82598.c
@@ -0,0 +1,589 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include "ixgbe_type.h"
+#include "ixgbe_common.h"
+#include "ixgbe_phy.h"
+
+#define IXGBE_82598_MAX_TX_QUEUES 32
+#define IXGBE_82598_MAX_RX_QUEUES 64
+#define IXGBE_82598_RAR_ENTRIES   16
+
+static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw);
+static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed,
+					 bool *autoneg);
+static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw,
+						u32 *speed, bool *autoneg);
+static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw);
+static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw);
+static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed,
+				      bool *link_up);
+static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
+					    bool autoneg,
+					    bool autoneg_wait_to_complete);
+static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw);
+static s32 ixgbe_check_copper_link_82598(struct ixgbe_hw *hw, u32 *speed,
+					 bool *link_up);
+static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
+					       bool autoneg,
+					       bool autoneg_wait_to_complete);
+static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw);
+
+
+static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw)
+{
+	hw->mac.num_rx_queues = IXGBE_82598_MAX_TX_QUEUES;
+	hw->mac.num_tx_queues = IXGBE_82598_MAX_RX_QUEUES;
+	hw->mac.num_rx_addrs = IXGBE_82598_RAR_ENTRIES;
+
+	return 0;
+}
+
+/**
+ *  ixgbe_get_link_settings_82598 - Determines default link settings
+ *  @hw: pointer to hardware structure
+ *  @speed: pointer to link speed
+ *  @autoneg: boolean auto-negotiation value
+ *
+ *  Determines the default link settings by reading the AUTOC register.
+ **/
+static s32 ixgbe_get_link_settings_82598(struct ixgbe_hw *hw, u32 *speed,
+					 bool *autoneg)
+{
+	s32 status = 0;
+	s32 autoc_reg;
+
+	autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+
+	if (hw->mac.link_settings_loaded) {
+		autoc_reg &= ~IXGBE_AUTOC_LMS_ATTACH_TYPE;
+		autoc_reg &= ~IXGBE_AUTOC_LMS_MASK;
+		autoc_reg |= hw->mac.link_attach_type;
+		autoc_reg |= hw->mac.link_mode_select;
+	}
+
+	switch (autoc_reg & IXGBE_AUTOC_LMS_MASK) {
+	case IXGBE_AUTOC_LMS_1G_LINK_NO_AN:
+		*speed = IXGBE_LINK_SPEED_1GB_FULL;
+		*autoneg = false;
+		break;
+
+	case IXGBE_AUTOC_LMS_10G_LINK_NO_AN:
+		*speed = IXGBE_LINK_SPEED_10GB_FULL;
+		*autoneg = false;
+		break;
+
+	case IXGBE_AUTOC_LMS_1G_AN:
+		*speed = IXGBE_LINK_SPEED_1GB_FULL;
+		*autoneg = true;
+		break;
+
+	case IXGBE_AUTOC_LMS_KX4_AN:
+	case IXGBE_AUTOC_LMS_KX4_AN_1G_AN:
+		*speed = IXGBE_LINK_SPEED_UNKNOWN;
+		if (autoc_reg & IXGBE_AUTOC_KX4_SUPP)
+			*speed |= IXGBE_LINK_SPEED_10GB_FULL;
+		if (autoc_reg & IXGBE_AUTOC_KX_SUPP)
+			*speed |= IXGBE_LINK_SPEED_1GB_FULL;
+		*autoneg = true;
+		break;
+
+	default:
+		status = IXGBE_ERR_LINK_SETUP;
+		break;
+	}
+
+	return status;
+}
+
+/**
+ *  ixgbe_get_copper_link_settings_82598 - Determines default link settings
+ *  @hw: pointer to hardware structure
+ *  @speed: pointer to link speed
+ *  @autoneg: boolean auto-negotiation value
+ *
+ *  Determines the default link settings by reading the AUTOC register.
+ **/
+static s32 ixgbe_get_copper_link_settings_82598(struct ixgbe_hw *hw,
+						u32 *speed, bool *autoneg)
+{
+	s32 status = IXGBE_ERR_LINK_SETUP;
+	u16 speed_ability;
+
+	*speed = 0;
+	*autoneg = true;
+
+	status = ixgbe_read_phy_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY,
+				    IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+				    &speed_ability);
+
+	if (status == 0) {
+		if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G)
+		    *speed |= IXGBE_LINK_SPEED_10GB_FULL;
+		if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G)
+		    *speed |= IXGBE_LINK_SPEED_1GB_FULL;
+	}
+
+	return status;
+}
+
+/**
+ *  ixgbe_get_media_type_82598 - Determines media type
+ *  @hw: pointer to hardware structure
+ *
+ *  Returns the media type (fiber, copper, backplane)
+ **/
+static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw)
+{
+	enum ixgbe_media_type media_type;
+
+	/* Media type for I82598 is based on device ID */
+	switch (hw->device_id) {
+	case IXGBE_DEV_ID_82598AF_DUAL_PORT:
+	case IXGBE_DEV_ID_82598AF_SINGLE_PORT:
+	case IXGBE_DEV_ID_82598EB_CX4:
+		media_type = ixgbe_media_type_fiber;
+		break;
+	case IXGBE_DEV_ID_82598AT_DUAL_PORT:
+		media_type = ixgbe_media_type_copper;
+		break;
+	default:
+		media_type = ixgbe_media_type_unknown;
+		break;
+	}
+
+	return media_type;
+}
+
+/**
+ *  ixgbe_setup_mac_link_82598 - Configures MAC link settings
+ *  @hw: pointer to hardware structure
+ *
+ *  Configures link settings based on values in the ixgbe_hw struct.
+ *  Restarts the link.  Performs autonegotiation if needed.
+ **/
+static s32 ixgbe_setup_mac_link_82598(struct ixgbe_hw *hw)
+{
+	u32 autoc_reg;
+	u32 links_reg;
+	u32 i;
+	s32 status = 0;
+
+	autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+
+	if (hw->mac.link_settings_loaded) {
+		autoc_reg &= ~IXGBE_AUTOC_LMS_ATTACH_TYPE;
+		autoc_reg &= ~IXGBE_AUTOC_LMS_MASK;
+		autoc_reg |= hw->mac.link_attach_type;
+		autoc_reg |= hw->mac.link_mode_select;
+
+		IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
+		msleep(50);
+	}
+
+	/* Restart link */
+	autoc_reg |= IXGBE_AUTOC_AN_RESTART;
+	IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
+
+	/* Only poll for autoneg to complete if specified to do so */
+	if (hw->phy.autoneg_wait_to_complete) {
+		if (hw->mac.link_mode_select == IXGBE_AUTOC_LMS_KX4_AN ||
+		    hw->mac.link_mode_select == IXGBE_AUTOC_LMS_KX4_AN_1G_AN) {
+			links_reg = 0; /* Just in case Autoneg time = 0 */
+			for (i = 0; i < IXGBE_AUTO_NEG_TIME; i++) {
+				links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
+				if (links_reg & IXGBE_LINKS_KX_AN_COMP)
+					break;
+				msleep(100);
+			}
+			if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) {
+				status = IXGBE_ERR_AUTONEG_NOT_COMPLETE;
+				hw_dbg(hw,
+				       "Autonegotiation did not complete.\n");
+			}
+		}
+	}
+
+	/*
+	 * We want to save off the original Flow Control configuration just in
+	 * case we get disconnected and then reconnected into a different hub
+	 * or switch with different Flow Control capabilities.
+	 */
+	hw->fc.type = hw->fc.original_type;
+	ixgbe_setup_fc(hw, 0);
+
+	/* Add delay to filter out noises during initial link setup */
+	msleep(50);
+
+	return status;
+}
+
+/**
+ *  ixgbe_check_mac_link_82598 - Get link/speed status
+ *  @hw: pointer to hardware structure
+ *  @speed: pointer to link speed
+ *  @link_up: true is link is up, false otherwise
+ *
+ *  Reads the links register to determine if link is up and the current speed
+ **/
+static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, u32 *speed,
+				      bool *link_up)
+{
+	u32 links_reg;
+
+	links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
+
+	if (links_reg & IXGBE_LINKS_UP)
+		*link_up = true;
+	else
+		*link_up = false;
+
+	if (links_reg & IXGBE_LINKS_SPEED)
+		*speed = IXGBE_LINK_SPEED_10GB_FULL;
+	else
+		*speed = IXGBE_LINK_SPEED_1GB_FULL;
+
+	return 0;
+}
+
+/**
+ *  ixgbe_setup_mac_link_speed_82598 - Set MAC link speed
+ *  @hw: pointer to hardware structure
+ *  @speed: new link speed
+ *  @autoneg: true if auto-negotiation enabled
+ *  @autoneg_wait_to_complete: true if waiting is needed to complete
+ *
+ *  Set the link speed in the AUTOC register and restarts link.
+ **/
+static s32 ixgbe_setup_mac_link_speed_82598(struct ixgbe_hw *hw,
+					    u32 speed, bool autoneg,
+					    bool autoneg_wait_to_complete)
+{
+	s32 status = 0;
+
+	/* If speed is 10G, then check for CX4 or XAUI. */
+	if ((speed == IXGBE_LINK_SPEED_10GB_FULL) &&
+	    (!(hw->mac.link_attach_type & IXGBE_AUTOC_10G_KX4)))
+		hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN;
+	else if ((speed == IXGBE_LINK_SPEED_1GB_FULL) && (!autoneg))
+		hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_LINK_NO_AN;
+	else if (autoneg) {
+		/* BX mode - Autonegotiate 1G */
+		if (!(hw->mac.link_attach_type & IXGBE_AUTOC_1G_PMA_PMD))
+			hw->mac.link_mode_select = IXGBE_AUTOC_LMS_1G_AN;
+		else /* KX/KX4 mode */
+			hw->mac.link_mode_select = IXGBE_AUTOC_LMS_KX4_AN_1G_AN;
+	} else {
+		status = IXGBE_ERR_LINK_SETUP;
+	}
+
+	if (status == 0) {
+		hw->phy.autoneg_wait_to_complete = autoneg_wait_to_complete;
+
+		hw->mac.link_settings_loaded = true;
+		/*
+		 * Setup and restart the link based on the new values in
+		 * ixgbe_hw This will write the AUTOC register based on the new
+		 * stored values
+		 */
+		hw->phy.ops.setup(hw);
+	}
+
+	return status;
+}
+
+
+/**
+ *  ixgbe_setup_copper_link_82598 - Setup copper link settings
+ *  @hw: pointer to hardware structure
+ *
+ *  Configures link settings based on values in the ixgbe_hw struct.
+ *  Restarts the link.  Performs autonegotiation if needed.  Restart
+ *  phy and wait for autonegotiate to finish.  Then synchronize the
+ *  MAC and PHY.
+ **/
+static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw)
+{
+	s32 status;
+	u32 speed = 0;
+	bool link_up = false;
+
+	/* Set up MAC */
+	hw->phy.ops.setup(hw);
+
+	/* Restart autonegotiation on PHY */
+	status = hw->phy.ops.setup(hw);
+
+	/* Synchronize MAC to PHY speed */
+	if (status == 0)
+		status = hw->phy.ops.check(hw, &speed, &link_up);
+
+	return status;
+}
+
+/**
+ *  ixgbe_check_copper_link_82598 - Syncs MAC & PHY link settings
+ *  @hw: pointer to hardware structure
+ *  @speed: pointer to link speed
+ *  @link_up: true if link is up, false otherwise
+ *
+ *  Reads the mac link, phy link, and synchronizes the MAC to PHY.
+ **/
+static s32 ixgbe_check_copper_link_82598(struct ixgbe_hw *hw, u32 *speed,
+					 bool *link_up)
+{
+	s32 status;
+	u32 phy_speed = 0;
+	bool phy_link = false;
+
+	/* This is the speed and link the MAC is set at */
+	hw->phy.ops.check(hw, speed, link_up);
+
+	/*
+	 * Check current speed and link status of the PHY register.
+	 * This is a vendor specific register and may have to
+	 * be changed for other copper PHYs.
+	 */
+	status = hw->phy.ops.check(hw, &phy_speed, &phy_link);
+
+	if ((status == 0) && (phy_link)) {
+		/*
+		 * Check current link status of the MACs link's register
+		 * matches that of the speed in the PHY register
+		 */
+		if (*speed != phy_speed) {
+			/*
+			 * The copper PHY requires 82598 attach type to be XAUI
+			 * for 10G and BX for 1G
+			 */
+			hw->mac.link_attach_type =
+				(IXGBE_AUTOC_10G_XAUI | IXGBE_AUTOC_1G_BX);
+
+			/* Synchronize the MAC speed to the PHY speed */
+			status = hw->phy.ops.setup_speed(hw, phy_speed, false,
+							  false);
+			if (status == 0)
+				hw->phy.ops.check(hw, speed, link_up);
+			else
+				status = IXGBE_ERR_LINK_SETUP;
+		}
+	} else {
+		*link_up = phy_link;
+	}
+
+	return status;
+}
+
+/**
+ *  ixgbe_setup_copper_link_speed_82598 - Set the PHY autoneg advertised field
+ *  @hw: pointer to hardware structure
+ *  @speed: new link speed
+ *  @autoneg: true if autonegotiation enabled
+ *  @autoneg_wait_to_complete: true if waiting is needed to complete
+ *
+ *  Sets the link speed in the AUTOC register in the MAC and restarts link.
+ **/
+static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, u32 speed,
+					       bool autoneg,
+					       bool autoneg_wait_to_complete)
+{
+	s32 status;
+	bool link_up = 0;
+
+	/* Setup the PHY according to input speed */
+	status = hw->phy.ops.setup_speed(hw, speed, autoneg,
+					  autoneg_wait_to_complete);
+
+	/* Synchronize MAC to PHY speed */
+	if (status == 0)
+		status = hw->phy.ops.check(hw, &speed, &link_up);
+
+	return status;
+}
+
+/**
+ *  ixgbe_reset_hw_82598 - Performs hardware reset
+ *  @hw: pointer to hardware structure
+ *
+ *  Resets the hardware by reseting the transmit and receive units, masks and
+ *  clears all interrupts, performing a PHY reset, and performing a link (MAC)
+ *  reset.
+ **/
+static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw)
+{
+	s32 status = 0;
+	u32 ctrl;
+	u32 gheccr;
+	u32 i;
+	u32 autoc;
+	u8  analog_val;
+
+	/* Call adapter stop to disable tx/rx and clear interrupts */
+	ixgbe_stop_adapter(hw);
+
+	/*
+	 * Power up the Atlas TX lanes if they are currently powered down.
+	 * Atlas TX lanes are powered down for MAC loopback tests, but
+	 * they are not automatically restored on reset.
+	 */
+	ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val);
+	if (analog_val & IXGBE_ATLAS_PDN_TX_REG_EN) {
+		/* Enable TX Atlas so packets can be transmitted again */
+		ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, &analog_val);
+		analog_val &= ~IXGBE_ATLAS_PDN_TX_REG_EN;
+		ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_LPBK, analog_val);
+
+		ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, &analog_val);
+		analog_val &= ~IXGBE_ATLAS_PDN_TX_10G_QL_ALL;
+		ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_10G, analog_val);
+
+		ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, &analog_val);
+		analog_val &= ~IXGBE_ATLAS_PDN_TX_1G_QL_ALL;
+		ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_1G, analog_val);
+
+		ixgbe_read_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, &analog_val);
+		analog_val &= ~IXGBE_ATLAS_PDN_TX_AN_QL_ALL;
+		ixgbe_write_analog_reg8(hw, IXGBE_ATLAS_PDN_AN, analog_val);
+	}
+
+	/* Reset PHY */
+	ixgbe_reset_phy(hw);
+
+	/*
+	 * Prevent the PCI-E bus from from hanging by disabling PCI-E master
+	 * access and verify no pending requests before reset
+	 */
+	if (ixgbe_disable_pcie_master(hw) != 0) {
+		status = IXGBE_ERR_MASTER_REQUESTS_PENDING;
+		hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+	}
+
+	/*
+	 * Issue global reset to the MAC.  This needs to be a SW reset.
+	 * If link reset is used, it might reset the MAC when mng is using it
+	 */
+	ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
+	IXGBE_WRITE_REG(hw, IXGBE_CTRL, (ctrl | IXGBE_CTRL_RST));
+	IXGBE_WRITE_FLUSH(hw);
+
+	/* Poll for reset bit to self-clear indicating reset is complete */
+	for (i = 0; i < 10; i++) {
+		udelay(1);
+		ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
+		if (!(ctrl & IXGBE_CTRL_RST))
+			break;
+	}
+	if (ctrl & IXGBE_CTRL_RST) {
+		status = IXGBE_ERR_RESET_FAILED;
+		hw_dbg(hw, "Reset polling failed to complete.\n");
+	}
+
+	msleep(50);
+
+	gheccr = IXGBE_READ_REG(hw, IXGBE_GHECCR);
+	gheccr &= ~((1 << 21) | (1 << 18) | (1 << 9) | (1 << 6));
+	IXGBE_WRITE_REG(hw, IXGBE_GHECCR, gheccr);
+
+	/*
+	 * AUTOC register which stores link settings gets cleared
+	 * and reloaded from EEPROM after reset. We need to restore
+	 * our stored value from init in case SW changed the attach
+	 * type or speed.  If this is the first time and link settings
+	 * have not been stored, store default settings from AUTOC.
+	 */
+	autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+	if (hw->mac.link_settings_loaded) {
+		autoc &= ~(IXGBE_AUTOC_LMS_ATTACH_TYPE);
+		autoc &= ~(IXGBE_AUTOC_LMS_MASK);
+		autoc |= hw->mac.link_attach_type;
+		autoc |= hw->mac.link_mode_select;
+		IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc);
+	} else {
+		hw->mac.link_attach_type =
+					 (autoc & IXGBE_AUTOC_LMS_ATTACH_TYPE);
+		hw->mac.link_mode_select = (autoc & IXGBE_AUTOC_LMS_MASK);
+		hw->mac.link_settings_loaded = true;
+	}
+
+	/* Store the permanent mac address */
+	ixgbe_get_mac_addr(hw, hw->mac.perm_addr);
+
+	return status;
+}
+
+static struct ixgbe_mac_operations mac_ops_82598 = {
+	.reset			= &ixgbe_reset_hw_82598,
+	.get_media_type		= &ixgbe_get_media_type_82598,
+};
+
+static struct ixgbe_phy_operations phy_ops_82598EB = {
+	.setup			= &ixgbe_setup_copper_link_82598,
+	.check			= &ixgbe_check_copper_link_82598,
+	.setup_speed		= &ixgbe_setup_copper_link_speed_82598,
+	.get_settings		= &ixgbe_get_copper_link_settings_82598,
+};
+
+struct ixgbe_info ixgbe_82598EB_info = {
+	.mac			= ixgbe_mac_82598EB,
+	.get_invariants		= &ixgbe_get_invariants_82598,
+	.mac_ops		= &mac_ops_82598,
+	.phy_ops		= &phy_ops_82598EB,
+};
+
+static struct ixgbe_phy_operations phy_ops_82598AT = {
+	.setup			= &ixgbe_setup_tnx_phy_link,
+	.check			= &ixgbe_check_tnx_phy_link,
+	.setup_speed		= &ixgbe_setup_tnx_phy_link_speed,
+	.get_settings		= &ixgbe_get_copper_link_settings_82598,
+};
+
+struct ixgbe_info ixgbe_82598AT_info = {
+	.mac			= ixgbe_mac_82598EB,
+	.get_invariants		= &ixgbe_get_invariants_82598,
+	.mac_ops		= &mac_ops_82598,
+	.phy_ops		= &phy_ops_82598AT,
+};
+
+static struct ixgbe_phy_operations phy_ops_82598AF = {
+	.setup			= &ixgbe_setup_mac_link_82598,
+	.check			= &ixgbe_check_mac_link_82598,
+	.setup_speed		= &ixgbe_setup_mac_link_speed_82598,
+	.get_settings		= &ixgbe_get_link_settings_82598,
+};
+
+struct ixgbe_info ixgbe_82598AF_info = {
+	.mac			= ixgbe_mac_82598EB,
+	.get_invariants		= &ixgbe_get_invariants_82598,
+	.mac_ops		= &mac_ops_82598,
+	.phy_ops		= &phy_ops_82598AF,
+};
+
diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c
new file mode 100644
index 0000000..512e3b2
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_common.c
@@ -0,0 +1,1175 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include "ixgbe_common.h"
+#include "ixgbe_phy.h"
+
+static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw);
+
+static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw);
+static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw);
+static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw);
+static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw);
+
+static s32 ixgbe_clear_vfta(struct ixgbe_hw *hw);
+static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw);
+static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr);
+static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr);
+
+/**
+ *  ixgbe_start_hw - Prepare hardware for TX/RX
+ *  @hw: pointer to hardware structure
+ *
+ *  Starts the hardware by filling the bus info structure and media type, clears
+ *  all on chip counters, initializes receive address registers, multicast
+ *  table, VLAN filter table, calls routine to set up link and flow control
+ *  settings, and leaves transmit and receive units disabled and uninitialized
+ **/
+s32 ixgbe_start_hw(struct ixgbe_hw *hw)
+{
+	u32 ctrl_ext;
+
+	/* Set the media type */
+	hw->phy.media_type = hw->mac.ops.get_media_type(hw);
+
+	/* Identify the PHY */
+	ixgbe_identify_phy(hw);
+
+	/*
+	 * Store MAC address from RAR0, clear receive address registers, and
+	 * clear the multicast table
+	 */
+	ixgbe_init_rx_addrs(hw);
+
+	/* Clear the VLAN filter table */
+	ixgbe_clear_vfta(hw);
+
+	/* Set up link */
+	hw->phy.ops.setup(hw);
+
+	/* Clear statistics registers */
+	ixgbe_clear_hw_cntrs(hw);
+
+	/* Set No Snoop Disable */
+	ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
+	ctrl_ext |= IXGBE_CTRL_EXT_NS_DIS;
+	IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
+
+	/* Clear adapter stopped flag */
+	hw->adapter_stopped = false;
+
+	return 0;
+}
+
+/**
+ *  ixgbe_init_hw - Generic hardware initialization
+ *  @hw: pointer to hardware structure
+ *
+ *  Initialize the hardware by reseting the hardware, filling the bus info
+ *  structure and media type, clears all on chip counters, initializes receive
+ *  address registers, multicast table, VLAN filter table, calls routine to set
+ *  up link and flow control settings, and leaves transmit and receive units
+ *  disabled and uninitialized
+ **/
+s32 ixgbe_init_hw(struct ixgbe_hw *hw)
+{
+	/* Reset the hardware */
+	hw->mac.ops.reset(hw);
+
+	/* Start the HW */
+	ixgbe_start_hw(hw);
+
+	return 0;
+}
+
+/**
+ *  ixgbe_clear_hw_cntrs - Generic clear hardware counters
+ *  @hw: pointer to hardware structure
+ *
+ *  Clears all hardware statistics counters by reading them from the hardware
+ *  Statistics counters are clear on read.
+ **/
+static s32 ixgbe_clear_hw_cntrs(struct ixgbe_hw *hw)
+{
+	u16 i = 0;
+
+	IXGBE_READ_REG(hw, IXGBE_CRCERRS);
+	IXGBE_READ_REG(hw, IXGBE_ILLERRC);
+	IXGBE_READ_REG(hw, IXGBE_ERRBC);
+	IXGBE_READ_REG(hw, IXGBE_MSPDC);
+	for (i = 0; i < 8; i++)
+		IXGBE_READ_REG(hw, IXGBE_MPC(i));
+
+	IXGBE_READ_REG(hw, IXGBE_MLFC);
+	IXGBE_READ_REG(hw, IXGBE_MRFC);
+	IXGBE_READ_REG(hw, IXGBE_RLEC);
+	IXGBE_READ_REG(hw, IXGBE_LXONTXC);
+	IXGBE_READ_REG(hw, IXGBE_LXONRXC);
+	IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
+	IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
+
+	for (i = 0; i < 8; i++) {
+		IXGBE_READ_REG(hw, IXGBE_PXONTXC(i));
+		IXGBE_READ_REG(hw, IXGBE_PXONRXC(i));
+		IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(i));
+		IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(i));
+	}
+
+	IXGBE_READ_REG(hw, IXGBE_PRC64);
+	IXGBE_READ_REG(hw, IXGBE_PRC127);
+	IXGBE_READ_REG(hw, IXGBE_PRC255);
+	IXGBE_READ_REG(hw, IXGBE_PRC511);
+	IXGBE_READ_REG(hw, IXGBE_PRC1023);
+	IXGBE_READ_REG(hw, IXGBE_PRC1522);
+	IXGBE_READ_REG(hw, IXGBE_GPRC);
+	IXGBE_READ_REG(hw, IXGBE_BPRC);
+	IXGBE_READ_REG(hw, IXGBE_MPRC);
+	IXGBE_READ_REG(hw, IXGBE_GPTC);
+	IXGBE_READ_REG(hw, IXGBE_GORCL);
+	IXGBE_READ_REG(hw, IXGBE_GORCH);
+	IXGBE_READ_REG(hw, IXGBE_GOTCL);
+	IXGBE_READ_REG(hw, IXGBE_GOTCH);
+	for (i = 0; i < 8; i++)
+		IXGBE_READ_REG(hw, IXGBE_RNBC(i));
+	IXGBE_READ_REG(hw, IXGBE_RUC);
+	IXGBE_READ_REG(hw, IXGBE_RFC);
+	IXGBE_READ_REG(hw, IXGBE_ROC);
+	IXGBE_READ_REG(hw, IXGBE_RJC);
+	IXGBE_READ_REG(hw, IXGBE_MNGPRC);
+	IXGBE_READ_REG(hw, IXGBE_MNGPDC);
+	IXGBE_READ_REG(hw, IXGBE_MNGPTC);
+	IXGBE_READ_REG(hw, IXGBE_TORL);
+	IXGBE_READ_REG(hw, IXGBE_TORH);
+	IXGBE_READ_REG(hw, IXGBE_TPR);
+	IXGBE_READ_REG(hw, IXGBE_TPT);
+	IXGBE_READ_REG(hw, IXGBE_PTC64);
+	IXGBE_READ_REG(hw, IXGBE_PTC127);
+	IXGBE_READ_REG(hw, IXGBE_PTC255);
+	IXGBE_READ_REG(hw, IXGBE_PTC511);
+	IXGBE_READ_REG(hw, IXGBE_PTC1023);
+	IXGBE_READ_REG(hw, IXGBE_PTC1522);
+	IXGBE_READ_REG(hw, IXGBE_MPTC);
+	IXGBE_READ_REG(hw, IXGBE_BPTC);
+	for (i = 0; i < 16; i++) {
+		IXGBE_READ_REG(hw, IXGBE_QPRC(i));
+		IXGBE_READ_REG(hw, IXGBE_QBRC(i));
+		IXGBE_READ_REG(hw, IXGBE_QPTC(i));
+		IXGBE_READ_REG(hw, IXGBE_QBTC(i));
+	}
+
+	return 0;
+}
+
+/**
+ *  ixgbe_get_mac_addr - Generic get MAC address
+ *  @hw: pointer to hardware structure
+ *  @mac_addr: Adapter MAC address
+ *
+ *  Reads the adapter's MAC address from first Receive Address Register (RAR0)
+ *  A reset of the adapter must be performed prior to calling this function
+ *  in order for the MAC address to have been loaded from the EEPROM into RAR0
+ **/
+s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr)
+{
+	u32 rar_high;
+	u32 rar_low;
+	u16 i;
+
+	rar_high = IXGBE_READ_REG(hw, IXGBE_RAH(0));
+	rar_low = IXGBE_READ_REG(hw, IXGBE_RAL(0));
+
+	for (i = 0; i < 4; i++)
+		mac_addr[i] = (u8)(rar_low >> (i*8));
+
+	for (i = 0; i < 2; i++)
+		mac_addr[i+4] = (u8)(rar_high >> (i*8));
+
+	return 0;
+}
+
+s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num)
+{
+	s32 ret_val;
+	u16 data;
+
+	ret_val = ixgbe_read_eeprom(hw, IXGBE_PBANUM0_PTR, &data);
+	if (ret_val) {
+		hw_dbg(hw, "NVM Read Error\n");
+		return ret_val;
+	}
+	*part_num = (u32)(data << 16);
+
+	ret_val = ixgbe_read_eeprom(hw, IXGBE_PBANUM1_PTR, &data);
+	if (ret_val) {
+		hw_dbg(hw, "NVM Read Error\n");
+		return ret_val;
+	}
+	*part_num |= data;
+
+	return 0;
+}
+
+/**
+ *  ixgbe_stop_adapter - Generic stop TX/RX units
+ *  @hw: pointer to hardware structure
+ *
+ *  Sets the adapter_stopped flag within ixgbe_hw struct. Clears interrupts,
+ *  disables transmit and receive units. The adapter_stopped flag is used by
+ *  the shared code and drivers to determine if the adapter is in a stopped
+ *  state and should not touch the hardware.
+ **/
+s32 ixgbe_stop_adapter(struct ixgbe_hw *hw)
+{
+	u32 number_of_queues;
+	u32 reg_val;
+	u16 i;
+
+	/*
+	 * Set the adapter_stopped flag so other driver functions stop touching
+	 * the hardware
+	 */
+	hw->adapter_stopped = true;
+
+	/* Disable the receive unit */
+	reg_val = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+	reg_val &= ~(IXGBE_RXCTRL_RXEN);
+	IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val);
+	msleep(2);
+
+	/* Clear interrupt mask to stop from interrupts being generated */
+	IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_IRQ_CLEAR_MASK);
+
+	/* Clear any pending interrupts */
+	IXGBE_READ_REG(hw, IXGBE_EICR);
+
+	/* Disable the transmit unit.  Each queue must be disabled. */
+	number_of_queues = hw->mac.num_tx_queues;
+	for (i = 0; i < number_of_queues; i++) {
+		reg_val = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i));
+		if (reg_val & IXGBE_TXDCTL_ENABLE) {
+			reg_val &= ~IXGBE_TXDCTL_ENABLE;
+			IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(i), reg_val);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ *  ixgbe_led_on - Turns on the software controllable LEDs.
+ *  @hw: pointer to hardware structure
+ *  @index: led number to turn on
+ **/
+s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index)
+{
+	u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+
+	/* To turn on the LED, set mode to ON. */
+	led_reg &= ~IXGBE_LED_MODE_MASK(index);
+	led_reg |= IXGBE_LED_ON << IXGBE_LED_MODE_SHIFT(index);
+	IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg);
+
+	return 0;
+}
+
+/**
+ *  ixgbe_led_off - Turns off the software controllable LEDs.
+ *  @hw: pointer to hardware structure
+ *  @index: led number to turn off
+ **/
+s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index)
+{
+	u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+
+	/* To turn off the LED, set mode to OFF. */
+	led_reg &= ~IXGBE_LED_MODE_MASK(index);
+	led_reg |= IXGBE_LED_OFF << IXGBE_LED_MODE_SHIFT(index);
+	IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg);
+
+	return 0;
+}
+
+
+/**
+ *  ixgbe_init_eeprom - Initialize EEPROM params
+ *  @hw: pointer to hardware structure
+ *
+ *  Initializes the EEPROM parameters ixgbe_eeprom_info within the
+ *  ixgbe_hw struct in order to set up EEPROM access.
+ **/
+s32 ixgbe_init_eeprom(struct ixgbe_hw *hw)
+{
+	struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+	u32 eec;
+	u16 eeprom_size;
+
+	if (eeprom->type == ixgbe_eeprom_uninitialized) {
+		eeprom->type = ixgbe_eeprom_none;
+
+		/*
+		 * Check for EEPROM present first.
+		 * If not present leave as none
+		 */
+		eec = IXGBE_READ_REG(hw, IXGBE_EEC);
+		if (eec & IXGBE_EEC_PRES) {
+			eeprom->type = ixgbe_eeprom_spi;
+
+			/*
+			 * SPI EEPROM is assumed here.  This code would need to
+			 * change if a future EEPROM is not SPI.
+			 */
+			eeprom_size = (u16)((eec & IXGBE_EEC_SIZE) >>
+					    IXGBE_EEC_SIZE_SHIFT);
+			eeprom->word_size = 1 << (eeprom_size +
+						  IXGBE_EEPROM_WORD_SIZE_SHIFT);
+		}
+
+		if (eec & IXGBE_EEC_ADDR_SIZE)
+			eeprom->address_bits = 16;
+		else
+			eeprom->address_bits = 8;
+		hw_dbg(hw, "Eeprom params: type = %d, size = %d, address bits: "
+			  "%d\n", eeprom->type, eeprom->word_size,
+			  eeprom->address_bits);
+	}
+
+	return 0;
+}
+
+/**
+ *  ixgbe_read_eeprom - Read EEPROM word using EERD
+ *  @hw: pointer to hardware structure
+ *  @offset: offset of  word in the EEPROM to read
+ *  @data: word read from the EEPROM
+ *
+ *  Reads a 16 bit word from the EEPROM using the EERD register.
+ **/
+s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data)
+{
+	u32 eerd;
+	s32 status;
+
+	eerd = (offset << IXGBE_EEPROM_READ_ADDR_SHIFT) +
+	       IXGBE_EEPROM_READ_REG_START;
+
+	IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd);
+	status = ixgbe_poll_eeprom_eerd_done(hw);
+
+	if (status == 0)
+		*data = (IXGBE_READ_REG(hw, IXGBE_EERD) >>
+			IXGBE_EEPROM_READ_REG_DATA);
+	else
+		hw_dbg(hw, "Eeprom read timed out\n");
+
+	return status;
+}
+
+/**
+ *  ixgbe_poll_eeprom_eerd_done - Poll EERD status
+ *  @hw: pointer to hardware structure
+ *
+ *  Polls the status bit (bit 1) of the EERD to determine when the read is done.
+ **/
+static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw)
+{
+	u32 i;
+	u32 reg;
+	s32 status = IXGBE_ERR_EEPROM;
+
+	for (i = 0; i < IXGBE_EERD_ATTEMPTS; i++) {
+		reg = IXGBE_READ_REG(hw, IXGBE_EERD);
+		if (reg & IXGBE_EEPROM_READ_REG_DONE) {
+			status = 0;
+			break;
+		}
+		udelay(5);
+	}
+	return status;
+}
+
+/**
+ *  ixgbe_get_eeprom_semaphore - Get hardware semaphore
+ *  @hw: pointer to hardware structure
+ *
+ *  Sets the hardware semaphores so EEPROM access can occur for bit-bang method
+ **/
+static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw)
+{
+	s32 status = IXGBE_ERR_EEPROM;
+	u32 timeout;
+	u32 i;
+	u32 swsm;
+
+	/* Set timeout value based on size of EEPROM */
+	timeout = hw->eeprom.word_size + 1;
+
+	/* Get SMBI software semaphore between device drivers first */
+	for (i = 0; i < timeout; i++) {
+		/*
+		 * If the SMBI bit is 0 when we read it, then the bit will be
+		 * set and we have the semaphore
+		 */
+		swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+		if (!(swsm & IXGBE_SWSM_SMBI)) {
+			status = 0;
+			break;
+		}
+		msleep(1);
+	}
+
+	/* Now get the semaphore between SW/FW through the SWESMBI bit */
+	if (status == 0) {
+		for (i = 0; i < timeout; i++) {
+			swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+
+			/* Set the SW EEPROM semaphore bit to request access */
+			swsm |= IXGBE_SWSM_SWESMBI;
+			IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm);
+
+			/*
+			 * If we set the bit successfully then we got the
+			 * semaphore.
+			 */
+			swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+			if (swsm & IXGBE_SWSM_SWESMBI)
+				break;
+
+			udelay(50);
+		}
+
+		/*
+		 * Release semaphores and return error if SW EEPROM semaphore
+		 * was not granted because we don't have access to the EEPROM
+		 */
+		if (i >= timeout) {
+			hw_dbg(hw, "Driver can't access the Eeprom - Semaphore "
+				 "not granted.\n");
+			ixgbe_release_eeprom_semaphore(hw);
+			status = IXGBE_ERR_EEPROM;
+		}
+	}
+
+	return status;
+}
+
+/**
+ *  ixgbe_release_eeprom_semaphore - Release hardware semaphore
+ *  @hw: pointer to hardware structure
+ *
+ *  This function clears hardware semaphore bits.
+ **/
+static void ixgbe_release_eeprom_semaphore(struct ixgbe_hw *hw)
+{
+	u32 swsm;
+
+	swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+
+	/* Release both semaphores by writing 0 to the bits SWESMBI and SMBI */
+	swsm &= ~(IXGBE_SWSM_SWESMBI | IXGBE_SWSM_SMBI);
+	IXGBE_WRITE_REG(hw, IXGBE_SWSM, swsm);
+}
+
+/**
+ *  ixgbe_calc_eeprom_checksum - Calculates and returns the checksum
+ *  @hw: pointer to hardware structure
+ **/
+static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw)
+{
+	u16 i;
+	u16 j;
+	u16 checksum = 0;
+	u16 length = 0;
+	u16 pointer = 0;
+	u16 word = 0;
+
+	/* Include 0x0-0x3F in the checksum */
+	for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) {
+		if (ixgbe_read_eeprom(hw, i, &word) != 0) {
+			hw_dbg(hw, "EEPROM read failed\n");
+			break;
+		}
+		checksum += word;
+	}
+
+	/* Include all data from pointers except for the fw pointer */
+	for (i = IXGBE_PCIE_ANALOG_PTR; i < IXGBE_FW_PTR; i++) {
+		ixgbe_read_eeprom(hw, i, &pointer);
+
+		/* Make sure the pointer seems valid */
+		if (pointer != 0xFFFF && pointer != 0) {
+			ixgbe_read_eeprom(hw, pointer, &length);
+
+			if (length != 0xFFFF && length != 0) {
+				for (j = pointer+1; j <= pointer+length; j++) {
+					ixgbe_read_eeprom(hw, j, &word);
+					checksum += word;
+				}
+			}
+		}
+	}
+
+	checksum = (u16)IXGBE_EEPROM_SUM - checksum;
+
+	return checksum;
+}
+
+/**
+ *  ixgbe_validate_eeprom_checksum - Validate EEPROM checksum
+ *  @hw: pointer to hardware structure
+ *  @checksum_val: calculated checksum
+ *
+ *  Performs checksum calculation and validates the EEPROM checksum.  If the
+ *  caller does not need checksum_val, the value can be NULL.
+ **/
+s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val)
+{
+	s32 status;
+	u16 checksum;
+	u16 read_checksum = 0;
+
+	/*
+	 * Read the first word from the EEPROM. If this times out or fails, do
+	 * not continue or we could be in for a very long wait while every
+	 * EEPROM read fails
+	 */
+	status = ixgbe_read_eeprom(hw, 0, &checksum);
+
+	if (status == 0) {
+		checksum = ixgbe_calc_eeprom_checksum(hw);
+
+		ixgbe_read_eeprom(hw, IXGBE_EEPROM_CHECKSUM, &read_checksum);
+
+		/*
+		 * Verify read checksum from EEPROM is the same as
+		 * calculated checksum
+		 */
+		if (read_checksum != checksum)
+			status = IXGBE_ERR_EEPROM_CHECKSUM;
+
+		/* If the user cares, return the calculated checksum */
+		if (checksum_val)
+			*checksum_val = checksum;
+	} else {
+		hw_dbg(hw, "EEPROM read failed\n");
+	}
+
+	return status;
+}
+
+/**
+ *  ixgbe_validate_mac_addr - Validate MAC address
+ *  @mac_addr: pointer to MAC address.
+ *
+ *  Tests a MAC address to ensure it is a valid Individual Address
+ **/
+s32 ixgbe_validate_mac_addr(u8 *mac_addr)
+{
+	s32 status = 0;
+
+	/* Make sure it is not a multicast address */
+	if (IXGBE_IS_MULTICAST(mac_addr))
+		status = IXGBE_ERR_INVALID_MAC_ADDR;
+	/* Not a broadcast address */
+	else if (IXGBE_IS_BROADCAST(mac_addr))
+		status = IXGBE_ERR_INVALID_MAC_ADDR;
+	/* Reject the zero address */
+	else if (mac_addr[0] == 0 && mac_addr[1] == 0 && mac_addr[2] == 0 &&
+		 mac_addr[3] == 0 && mac_addr[4] == 0 && mac_addr[5] == 0)
+		status = IXGBE_ERR_INVALID_MAC_ADDR;
+
+	return status;
+}
+
+/**
+ *  ixgbe_set_rar - Set RX address register
+ *  @hw: pointer to hardware structure
+ *  @addr: Address to put into receive address register
+ *  @index: Receive address register to write
+ *  @vind: Vind to set RAR to
+ *  @enable_addr: set flag that address is active
+ *
+ *  Puts an ethernet address into a receive address register.
+ **/
+s32 ixgbe_set_rar(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vind,
+		  u32 enable_addr)
+{
+	u32 rar_low, rar_high;
+
+	/*
+	 * HW expects these in little endian so we reverse the byte order from
+	 * network order (big endian) to little endian
+	 */
+	rar_low = ((u32)addr[0] |
+		   ((u32)addr[1] << 8) |
+		   ((u32)addr[2] << 16) |
+		   ((u32)addr[3] << 24));
+
+	rar_high = ((u32)addr[4] |
+		    ((u32)addr[5] << 8) |
+		    ((vind << IXGBE_RAH_VIND_SHIFT) & IXGBE_RAH_VIND_MASK));
+
+	if (enable_addr != 0)
+		rar_high |= IXGBE_RAH_AV;
+
+	IXGBE_WRITE_REG(hw, IXGBE_RAL(index), rar_low);
+	IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high);
+
+	return 0;
+}
+
+/**
+ *  ixgbe_init_rx_addrs - Initializes receive address filters.
+ *  @hw: pointer to hardware structure
+ *
+ *  Places the MAC address in receive address register 0 and clears the rest
+ *  of the receive addresss registers. Clears the multicast table. Assumes
+ *  the receiver is in reset when the routine is called.
+ **/
+static s32 ixgbe_init_rx_addrs(struct ixgbe_hw *hw)
+{
+	u32 i;
+	u32 rar_entries = hw->mac.num_rx_addrs;
+
+	/*
+	 * If the current mac address is valid, assume it is a software override
+	 * to the permanent address.
+	 * Otherwise, use the permanent address from the eeprom.
+	 */
+	if (ixgbe_validate_mac_addr(hw->mac.addr) ==
+	    IXGBE_ERR_INVALID_MAC_ADDR) {
+		/* Get the MAC address from the RAR0 for later reference */
+		ixgbe_get_mac_addr(hw, hw->mac.addr);
+
+		hw_dbg(hw, " Keeping Current RAR0 Addr =%.2X %.2X %.2X ",
+			  hw->mac.addr[0], hw->mac.addr[1],
+			  hw->mac.addr[2]);
+		hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3],
+			  hw->mac.addr[4], hw->mac.addr[5]);
+	} else {
+		/* Setup the receive address. */
+		hw_dbg(hw, "Overriding MAC Address in RAR[0]\n");
+		hw_dbg(hw, " New MAC Addr =%.2X %.2X %.2X ",
+			  hw->mac.addr[0], hw->mac.addr[1],
+			  hw->mac.addr[2]);
+		hw_dbg(hw, "%.2X %.2X %.2X\n", hw->mac.addr[3],
+			  hw->mac.addr[4], hw->mac.addr[5]);
+
+		ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
+	}
+
+	hw->addr_ctrl.rar_used_count = 1;
+
+	/* Zero out the other receive addresses. */
+	hw_dbg(hw, "Clearing RAR[1-15]\n");
+	for (i = 1; i < rar_entries; i++) {
+		IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0);
+		IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0);
+	}
+
+	/* Clear the MTA */
+	hw->addr_ctrl.mc_addr_in_rar_count = 0;
+	hw->addr_ctrl.mta_in_use = 0;
+	IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, hw->mac.mc_filter_type);
+
+	hw_dbg(hw, " Clearing MTA\n");
+	for (i = 0; i < IXGBE_MC_TBL_SIZE; i++)
+		IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0);
+
+	return 0;
+}
+
+/**
+ *  ixgbe_mta_vector - Determines bit-vector in multicast table to set
+ *  @hw: pointer to hardware structure
+ *  @mc_addr: the multicast address
+ *
+ *  Extracts the 12 bits, from a multicast address, to determine which
+ *  bit-vector to set in the multicast table. The hardware uses 12 bits, from
+ *  incoming rx multicast addresses, to determine the bit-vector to check in
+ *  the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set
+ *  by the MO field of the MCSTCTRL. The MO field is set during initalization
+ *  to mc_filter_type.
+ **/
+static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr)
+{
+	u32 vector = 0;
+
+	switch (hw->mac.mc_filter_type) {
+	case 0:	  /* use bits [47:36] of the address */
+		vector = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4));
+		break;
+	case 1:	  /* use bits [46:35] of the address */
+		vector = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5));
+		break;
+	case 2:	  /* use bits [45:34] of the address */
+		vector = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6));
+		break;
+	case 3:	  /* use bits [43:32] of the address */
+		vector = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8));
+		break;
+	default:	 /* Invalid mc_filter_type */
+		hw_dbg(hw, "MC filter type param set incorrectly\n");
+		break;
+	}
+
+	/* vector can only be 12-bits or boundary will be exceeded */
+	vector &= 0xFFF;
+	return vector;
+}
+
+/**
+ *  ixgbe_set_mta - Set bit-vector in multicast table
+ *  @hw: pointer to hardware structure
+ *  @hash_value: Multicast address hash value
+ *
+ *  Sets the bit-vector in the multicast table.
+ **/
+static void ixgbe_set_mta(struct ixgbe_hw *hw, u8 *mc_addr)
+{
+	u32 vector;
+	u32 vector_bit;
+	u32 vector_reg;
+	u32 mta_reg;
+
+	hw->addr_ctrl.mta_in_use++;
+
+	vector = ixgbe_mta_vector(hw, mc_addr);
+	hw_dbg(hw, " bit-vector = 0x%03X\n", vector);
+
+	/*
+	 * The MTA is a register array of 128 32-bit registers. It is treated
+	 * like an array of 4096 bits.  We want to set bit
+	 * BitArray[vector_value]. So we figure out what register the bit is
+	 * in, read it, OR in the new bit, then write back the new value.  The
+	 * register is determined by the upper 7 bits of the vector value and
+	 * the bit within that register are determined by the lower 5 bits of
+	 * the value.
+	 */
+	vector_reg = (vector >> 5) & 0x7F;
+	vector_bit = vector & 0x1F;
+	mta_reg = IXGBE_READ_REG(hw, IXGBE_MTA(vector_reg));
+	mta_reg |= (1 << vector_bit);
+	IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg);
+}
+
+/**
+ *  ixgbe_add_mc_addr - Adds a multicast address.
+ *  @hw: pointer to hardware structure
+ *  @mc_addr: new multicast address
+ *
+ *  Adds it to unused receive address register or to the multicast table.
+ **/
+static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr)
+{
+	u32 rar_entries = hw->mac.num_rx_addrs;
+
+	hw_dbg(hw, " MC Addr =%.2X %.2X %.2X %.2X %.2X %.2X\n",
+		  mc_addr[0], mc_addr[1], mc_addr[2],
+		  mc_addr[3], mc_addr[4], mc_addr[5]);
+
+	/*
+	 * Place this multicast address in the RAR if there is room,
+	 * else put it in the MTA
+	 */
+	if (hw->addr_ctrl.rar_used_count < rar_entries) {
+		ixgbe_set_rar(hw, hw->addr_ctrl.rar_used_count,
+			      mc_addr, 0, IXGBE_RAH_AV);
+		hw_dbg(hw, "Added a multicast address to RAR[%d]\n",
+			  hw->addr_ctrl.rar_used_count);
+		hw->addr_ctrl.rar_used_count++;
+		hw->addr_ctrl.mc_addr_in_rar_count++;
+	} else {
+		ixgbe_set_mta(hw, mc_addr);
+	}
+
+	hw_dbg(hw, "ixgbe_add_mc_addr Complete\n");
+}
+
+/**
+ *  ixgbe_update_mc_addr_list - Updates MAC list of multicast addresses
+ *  @hw: pointer to hardware structure
+ *  @mc_addr_list: the list of new multicast addresses
+ *  @mc_addr_count: number of addresses
+ *  @pad: number of bytes between addresses in the list
+ *
+ *  The given list replaces any existing list. Clears the MC addrs from receive
+ *  address registers and the multicast table. Uses unsed receive address
+ *  registers for the first multicast addresses, and hashes the rest into the
+ *  multicast table.
+ **/
+s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list,
+			      u32 mc_addr_count, u32 pad)
+{
+	u32 i;
+	u32 rar_entries = hw->mac.num_rx_addrs;
+
+	/*
+	 * Set the new number of MC addresses that we are being requested to
+	 * use.
+	 */
+	hw->addr_ctrl.num_mc_addrs = mc_addr_count;
+	hw->addr_ctrl.rar_used_count -= hw->addr_ctrl.mc_addr_in_rar_count;
+	hw->addr_ctrl.mc_addr_in_rar_count = 0;
+	hw->addr_ctrl.mta_in_use = 0;
+
+	/* Zero out the other receive addresses. */
+	hw_dbg(hw, "Clearing RAR[1-15]\n");
+	for (i = hw->addr_ctrl.rar_used_count; i < rar_entries; i++) {
+		IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0);
+		IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0);
+	}
+
+	/* Clear the MTA */
+	hw_dbg(hw, " Clearing MTA\n");
+	for (i = 0; i < IXGBE_MC_TBL_SIZE; i++)
+		IXGBE_WRITE_REG(hw, IXGBE_MTA(i), 0);
+
+	/* Add the new addresses */
+	for (i = 0; i < mc_addr_count; i++) {
+		hw_dbg(hw, " Adding the multicast addresses:\n");
+		ixgbe_add_mc_addr(hw, mc_addr_list +
+				  (i * (IXGBE_ETH_LENGTH_OF_ADDRESS + pad)));
+	}
+
+	/* Enable mta */
+	if (hw->addr_ctrl.mta_in_use > 0)
+		IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL,
+				IXGBE_MCSTCTRL_MFE | hw->mac.mc_filter_type);
+
+	hw_dbg(hw, "ixgbe_update_mc_addr_list Complete\n");
+	return 0;
+}
+
+/**
+ *  ixgbe_clear_vfta - Clear VLAN filter table
+ *  @hw: pointer to hardware structure
+ *
+ *  Clears the VLAN filer table, and the VMDq index associated with the filter
+ **/
+static s32 ixgbe_clear_vfta(struct ixgbe_hw *hw)
+{
+	u32 offset;
+	u32 vlanbyte;
+
+	for (offset = 0; offset < IXGBE_VLAN_FILTER_TBL_SIZE; offset++)
+		IXGBE_WRITE_REG(hw, IXGBE_VFTA(offset), 0);
+
+	for (vlanbyte = 0; vlanbyte < 4; vlanbyte++)
+		for (offset = 0; offset < IXGBE_VLAN_FILTER_TBL_SIZE; offset++)
+			IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(vlanbyte, offset),
+					0);
+
+	return 0;
+}
+
+/**
+ *  ixgbe_set_vfta - Set VLAN filter table
+ *  @hw: pointer to hardware structure
+ *  @vlan: VLAN id to write to VLAN filter
+ *  @vind: VMDq output index that maps queue to VLAN id in VFTA
+ *  @vlan_on: boolean flag to turn on/off VLAN in VFTA
+ *
+ *  Turn on/off specified VLAN in the VLAN filter table.
+ **/
+s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind,
+		   bool vlan_on)
+{
+	u32 VftaIndex;
+	u32 BitOffset;
+	u32 VftaReg;
+	u32 VftaByte;
+
+	/* Determine 32-bit word position in array */
+	VftaIndex = (vlan >> 5) & 0x7F;   /* upper seven bits */
+
+	/* Determine the location of the (VMD) queue index */
+	VftaByte =  ((vlan >> 3) & 0x03); /* bits (4:3) indicating byte array */
+	BitOffset = (vlan & 0x7) << 2;    /* lower 3 bits indicate nibble */
+
+	/* Set the nibble for VMD queue index */
+	VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex));
+	VftaReg &= (~(0x0F << BitOffset));
+	VftaReg |= (vind << BitOffset);
+	IXGBE_WRITE_REG(hw, IXGBE_VFTAVIND(VftaByte, VftaIndex), VftaReg);
+
+	/* Determine the location of the bit for this VLAN id */
+	BitOffset = vlan & 0x1F;	   /* lower five bits */
+
+	VftaReg = IXGBE_READ_REG(hw, IXGBE_VFTA(VftaIndex));
+	if (vlan_on)
+		/* Turn on this VLAN id */
+		VftaReg |= (1 << BitOffset);
+	else
+		/* Turn off this VLAN id */
+		VftaReg &= ~(1 << BitOffset);
+	IXGBE_WRITE_REG(hw, IXGBE_VFTA(VftaIndex), VftaReg);
+
+	return 0;
+}
+
+/**
+ *  ixgbe_setup_fc - Configure flow control settings
+ *  @hw: pointer to hardware structure
+ *  @packetbuf_num: packet buffer number (0-7)
+ *
+ *  Configures the flow control settings based on SW configuration.
+ *  This function is used for 802.3x flow control configuration only.
+ **/
+s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num)
+{
+	u32 frctl_reg;
+	u32 rmcs_reg;
+
+	if (packetbuf_num < 0 || packetbuf_num > 7)
+		hw_dbg(hw, "Invalid packet buffer number [%d], expected range"
+		       "is 0-7\n", packetbuf_num);
+
+	frctl_reg = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+	frctl_reg &= ~(IXGBE_FCTRL_RFCE | IXGBE_FCTRL_RPFCE);
+
+	rmcs_reg = IXGBE_READ_REG(hw, IXGBE_RMCS);
+	rmcs_reg &= ~(IXGBE_RMCS_TFCE_PRIORITY | IXGBE_RMCS_TFCE_802_3X);
+
+	/*
+	 * We want to save off the original Flow Control configuration just in
+	 * case we get disconnected and then reconnected into a different hub
+	 * or switch with different Flow Control capabilities.
+	 */
+	hw->fc.type = hw->fc.original_type;
+
+	/*
+	 * The possible values of the "flow_control" parameter are:
+	 * 0: Flow control is completely disabled
+	 * 1: Rx flow control is enabled (we can receive pause frames but not
+	 *    send pause frames).
+	 * 2: Tx flow control is enabled (we can send pause frames but we do not
+	 *    support receiving pause frames)
+	 * 3: Both Rx and TX flow control (symmetric) are enabled.
+	 * other: Invalid.
+	 */
+	switch (hw->fc.type) {
+	case ixgbe_fc_none:
+		break;
+	case ixgbe_fc_rx_pause:
+		/*
+		 * RX Flow control is enabled,
+		 * and TX Flow control is disabled.
+		 */
+		frctl_reg |= IXGBE_FCTRL_RFCE;
+		break;
+	case ixgbe_fc_tx_pause:
+		/*
+		 * TX Flow control is enabled, and RX Flow control is disabled,
+		 * by a software over-ride.
+		 */
+		rmcs_reg |= IXGBE_RMCS_TFCE_802_3X;
+		break;
+	case ixgbe_fc_full:
+		/*
+		 * Flow control (both RX and TX) is enabled by a software
+		 * over-ride.
+		 */
+		frctl_reg |= IXGBE_FCTRL_RFCE;
+		rmcs_reg |= IXGBE_RMCS_TFCE_802_3X;
+		break;
+	default:
+		/* We should never get here.  The value should be 0-3. */
+		hw_dbg(hw, "Flow control param set incorrectly\n");
+		break;
+	}
+
+	/* Enable 802.3x based flow control settings. */
+	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, frctl_reg);
+	IXGBE_WRITE_REG(hw, IXGBE_RMCS, rmcs_reg);
+
+	/*
+	 * We need to set up the Receive Threshold high and low water
+	 * marks as well as (optionally) enabling the transmission of
+	 * XON frames.
+	 */
+	if (hw->fc.type & ixgbe_fc_tx_pause) {
+		if (hw->fc.send_xon) {
+			IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num),
+					(hw->fc.low_water | IXGBE_FCRTL_XONE));
+		} else {
+			IXGBE_WRITE_REG(hw, IXGBE_FCRTL(packetbuf_num),
+					hw->fc.low_water);
+		}
+		IXGBE_WRITE_REG(hw, IXGBE_FCRTH(packetbuf_num),
+				(hw->fc.high_water)|IXGBE_FCRTH_FCEN);
+	}
+
+	IXGBE_WRITE_REG(hw, IXGBE_FCTTV(0), hw->fc.pause_time);
+	IXGBE_WRITE_REG(hw, IXGBE_FCRTV, (hw->fc.pause_time >> 1));
+
+	return 0;
+}
+
+/**
+ *  ixgbe_disable_pcie_master - Disable PCI-express master access
+ *  @hw: pointer to hardware structure
+ *
+ *  Disables PCI-Express master access and verifies there are no pending
+ *  requests. IXGBE_ERR_MASTER_REQUESTS_PENDING is returned if master disable
+ *  bit hasn't caused the master requests to be disabled, else 0
+ *  is returned signifying master requests disabled.
+ **/
+s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw)
+{
+	u32 ctrl;
+	s32 i;
+	s32 status = IXGBE_ERR_MASTER_REQUESTS_PENDING;
+
+	ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
+	ctrl |= IXGBE_CTRL_GIO_DIS;
+	IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
+
+	for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) {
+		if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO)) {
+			status = 0;
+			break;
+		}
+		udelay(100);
+	}
+
+	return status;
+}
+
+
+/**
+ *  ixgbe_acquire_swfw_sync - Aquire SWFW semaphore
+ *  @hw: pointer to hardware structure
+ *  @mask: Mask to specify wich semaphore to acquire
+ *
+ *  Aquires the SWFW semaphore throught the GSSR register for the specified
+ *  function (CSR, PHY0, PHY1, EEPROM, Flash)
+ **/
+s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask)
+{
+	u32 gssr;
+	u32 swmask = mask;
+	u32 fwmask = mask << 5;
+	s32 timeout = 200;
+
+	while (timeout) {
+		if (ixgbe_get_eeprom_semaphore(hw))
+			return -IXGBE_ERR_SWFW_SYNC;
+
+		gssr = IXGBE_READ_REG(hw, IXGBE_GSSR);
+		if (!(gssr & (fwmask | swmask)))
+			break;
+
+		/*
+		 * Firmware currently using resource (fwmask) or other software
+		 * thread currently using resource (swmask)
+		 */
+		ixgbe_release_eeprom_semaphore(hw);
+		msleep(5);
+		timeout--;
+	}
+
+	if (!timeout) {
+		hw_dbg(hw, "Driver can't access resource, GSSR timeout.\n");
+		return -IXGBE_ERR_SWFW_SYNC;
+	}
+
+	gssr |= swmask;
+	IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr);
+
+	ixgbe_release_eeprom_semaphore(hw);
+	return 0;
+}
+
+/**
+ *  ixgbe_release_swfw_sync - Release SWFW semaphore
+ *  @hw: pointer to hardware structure
+ *  @mask: Mask to specify wich semaphore to release
+ *
+ *  Releases the SWFW semaphore throught the GSSR register for the specified
+ *  function (CSR, PHY0, PHY1, EEPROM, Flash)
+ **/
+void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask)
+{
+	u32 gssr;
+	u32 swmask = mask;
+
+	ixgbe_get_eeprom_semaphore(hw);
+
+	gssr = IXGBE_READ_REG(hw, IXGBE_GSSR);
+	gssr &= ~swmask;
+	IXGBE_WRITE_REG(hw, IXGBE_GSSR, gssr);
+
+	ixgbe_release_eeprom_semaphore(hw);
+}
+
+/**
+ *  ixgbe_read_analog_reg8- Reads 8 bit 82598 Atlas analog register
+ *  @hw: pointer to hardware structure
+ *  @reg: analog register to read
+ *  @val: read value
+ *
+ *  Performs write operation to analog register specified.
+ **/
+s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val)
+{
+	u32  atlas_ctl;
+
+	IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL,
+			IXGBE_ATLASCTL_WRITE_CMD | (reg << 8));
+	IXGBE_WRITE_FLUSH(hw);
+	udelay(10);
+	atlas_ctl = IXGBE_READ_REG(hw, IXGBE_ATLASCTL);
+	*val = (u8)atlas_ctl;
+
+	return 0;
+}
+
+/**
+ *  ixgbe_write_analog_reg8- Writes 8 bit Atlas analog register
+ *  @hw: pointer to hardware structure
+ *  @reg: atlas register to write
+ *  @val: value to write
+ *
+ *  Performs write operation to Atlas analog register specified.
+ **/
+s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val)
+{
+	u32  atlas_ctl;
+
+	atlas_ctl = (reg << 8) | val;
+	IXGBE_WRITE_REG(hw, IXGBE_ATLASCTL, atlas_ctl);
+	IXGBE_WRITE_FLUSH(hw);
+	udelay(10);
+
+	return 0;
+}
+
diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h
new file mode 100644
index 0000000..de6ddd5
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_common.h
@@ -0,0 +1,86 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_COMMON_H_
+#define _IXGBE_COMMON_H_
+
+#include "ixgbe_type.h"
+
+s32 ixgbe_init_hw(struct ixgbe_hw *hw);
+s32 ixgbe_start_hw(struct ixgbe_hw *hw);
+s32 ixgbe_get_mac_addr(struct ixgbe_hw *hw, u8 *mac_addr);
+s32 ixgbe_stop_adapter(struct ixgbe_hw *hw);
+s32 ixgbe_read_part_num(struct ixgbe_hw *hw, u32 *part_num);
+
+s32 ixgbe_led_on(struct ixgbe_hw *hw, u32 index);
+s32 ixgbe_led_off(struct ixgbe_hw *hw, u32 index);
+
+s32 ixgbe_init_eeprom(struct ixgbe_hw *hw);
+s32 ixgbe_read_eeprom(struct ixgbe_hw *hw, u16 offset, u16 *data);
+s32 ixgbe_validate_eeprom_checksum(struct ixgbe_hw *hw, u16 *checksum_val);
+
+s32 ixgbe_set_rar(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vind,
+		  u32 enable_addr);
+s32 ixgbe_update_mc_addr_list(struct ixgbe_hw *hw, u8 *mc_addr_list,
+			      u32 mc_addr_count, u32 pad);
+s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on);
+s32 ixgbe_validate_mac_addr(u8 *mac_addr);
+
+s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packtetbuf_num);
+
+s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask);
+void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask);
+s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw);
+
+s32 ixgbe_read_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 *val);
+s32 ixgbe_write_analog_reg8(struct ixgbe_hw *hw, u32 reg, u8 val);
+
+#define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
+
+#define IXGBE_READ_REG(a, reg) readl((a)->hw_addr + (reg))
+
+#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) (\
+    writel((value), ((a)->hw_addr + (reg) + ((offset) << 2))))
+
+#define IXGBE_READ_REG_ARRAY(a, reg, offset) (\
+    readl((a)->hw_addr + (reg) + ((offset) << 2)))
+
+#define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS)
+
+#ifdef DEBUG
+#define hw_dbg(hw, format, arg...) \
+printk(KERN_DEBUG, "%s: " format, ixgbe_get_hw_dev_name(hw), ##arg);
+#else
+static inline int __attribute__ ((format (printf, 2, 3)))
+hw_dbg(struct ixgbe_hw *hw, const char *format, ...)
+{
+	return 0;
+}
+#endif
+
+#endif /* IXGBE_COMMON */
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
new file mode 100644
index 0000000..a4e576a
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -0,0 +1,948 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* ethtool support for ixgbe */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+
+#include "ixgbe.h"
+
+
+#define IXGBE_ALL_RAR_ENTRIES 16
+
+struct ixgbe_stats {
+	char stat_string[ETH_GSTRING_LEN];
+	int sizeof_stat;
+	int stat_offset;
+};
+
+#define IXGBE_STAT(m) sizeof(((struct ixgbe_adapter *)0)->m), \
+		      offsetof(struct ixgbe_adapter, m)
+static struct ixgbe_stats ixgbe_gstrings_stats[] = {
+	{"rx_packets", IXGBE_STAT(net_stats.rx_packets)},
+	{"tx_packets", IXGBE_STAT(net_stats.tx_packets)},
+	{"rx_bytes", IXGBE_STAT(net_stats.rx_bytes)},
+	{"tx_bytes", IXGBE_STAT(net_stats.tx_bytes)},
+	{"lsc_int", IXGBE_STAT(lsc_int)},
+	{"tx_busy", IXGBE_STAT(tx_busy)},
+	{"non_eop_descs", IXGBE_STAT(non_eop_descs)},
+	{"rx_errors", IXGBE_STAT(net_stats.rx_errors)},
+	{"tx_errors", IXGBE_STAT(net_stats.tx_errors)},
+	{"rx_dropped", IXGBE_STAT(net_stats.rx_dropped)},
+	{"tx_dropped", IXGBE_STAT(net_stats.tx_dropped)},
+	{"multicast", IXGBE_STAT(net_stats.multicast)},
+	{"broadcast", IXGBE_STAT(stats.bprc)},
+	{"rx_no_buffer_count", IXGBE_STAT(stats.rnbc[0]) },
+	{"collisions", IXGBE_STAT(net_stats.collisions)},
+	{"rx_over_errors", IXGBE_STAT(net_stats.rx_over_errors)},
+	{"rx_crc_errors", IXGBE_STAT(net_stats.rx_crc_errors)},
+	{"rx_frame_errors", IXGBE_STAT(net_stats.rx_frame_errors)},
+	{"rx_fifo_errors", IXGBE_STAT(net_stats.rx_fifo_errors)},
+	{"rx_missed_errors", IXGBE_STAT(net_stats.rx_missed_errors)},
+	{"tx_aborted_errors", IXGBE_STAT(net_stats.tx_aborted_errors)},
+	{"tx_carrier_errors", IXGBE_STAT(net_stats.tx_carrier_errors)},
+	{"tx_fifo_errors", IXGBE_STAT(net_stats.tx_fifo_errors)},
+	{"tx_heartbeat_errors", IXGBE_STAT(net_stats.tx_heartbeat_errors)},
+	{"tx_timeout_count", IXGBE_STAT(tx_timeout_count)},
+	{"tx_restart_queue", IXGBE_STAT(restart_queue)},
+	{"rx_long_length_errors", IXGBE_STAT(stats.roc)},
+	{"rx_short_length_errors", IXGBE_STAT(stats.ruc)},
+	{"tx_tcp4_seg_ctxt", IXGBE_STAT(hw_tso_ctxt)},
+	{"tx_tcp6_seg_ctxt", IXGBE_STAT(hw_tso6_ctxt)},
+	{"tx_flow_control_xon", IXGBE_STAT(stats.lxontxc)},
+	{"rx_flow_control_xon", IXGBE_STAT(stats.lxonrxc)},
+	{"tx_flow_control_xoff", IXGBE_STAT(stats.lxofftxc)},
+	{"rx_flow_control_xoff", IXGBE_STAT(stats.lxoffrxc)},
+	{"rx_csum_offload_good", IXGBE_STAT(hw_csum_rx_good)},
+	{"rx_csum_offload_errors", IXGBE_STAT(hw_csum_rx_error)},
+	{"tx_csum_offload_ctxt", IXGBE_STAT(hw_csum_tx_good)},
+	{"rx_header_split", IXGBE_STAT(rx_hdr_split)},
+	{"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)},
+	{"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)},
+};
+
+#define IXGBE_QUEUE_STATS_LEN \
+		((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \
+		 ((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \
+		 (sizeof(struct ixgbe_queue_stats) / sizeof(u64)))
+#define IXGBE_GLOBAL_STATS_LEN \
+	sizeof(ixgbe_gstrings_stats) / sizeof(struct ixgbe_stats)
+#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN)
+
+static int ixgbe_get_settings(struct net_device *netdev,
+			      struct ethtool_cmd *ecmd)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
+	ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
+	ecmd->port = PORT_FIBRE;
+	ecmd->transceiver = XCVR_EXTERNAL;
+
+	if (netif_carrier_ok(adapter->netdev)) {
+		ecmd->speed = SPEED_10000;
+		ecmd->duplex = DUPLEX_FULL;
+	} else {
+		ecmd->speed = -1;
+		ecmd->duplex = -1;
+	}
+
+	ecmd->autoneg = AUTONEG_DISABLE;
+	return 0;
+}
+
+static int ixgbe_set_settings(struct net_device *netdev,
+			      struct ethtool_cmd *ecmd)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	if (ecmd->autoneg == AUTONEG_ENABLE ||
+	    ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)
+		return -EINVAL;
+
+	if (netif_running(adapter->netdev)) {
+		ixgbe_down(adapter);
+		ixgbe_reset(adapter);
+		ixgbe_up(adapter);
+	} else {
+		ixgbe_reset(adapter);
+	}
+
+	return 0;
+}
+
+static void ixgbe_get_pauseparam(struct net_device *netdev,
+				 struct ethtool_pauseparam *pause)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	struct ixgbe_hw *hw = &adapter->hw;
+
+	pause->autoneg = AUTONEG_DISABLE;
+
+	if (hw->fc.type == ixgbe_fc_rx_pause) {
+		pause->rx_pause = 1;
+	} else if (hw->fc.type == ixgbe_fc_tx_pause) {
+		pause->tx_pause = 1;
+	} else if (hw->fc.type == ixgbe_fc_full) {
+		pause->rx_pause = 1;
+		pause->tx_pause = 1;
+	}
+}
+
+static int ixgbe_set_pauseparam(struct net_device *netdev,
+				struct ethtool_pauseparam *pause)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	struct ixgbe_hw *hw = &adapter->hw;
+
+	if (pause->autoneg == AUTONEG_ENABLE)
+		return -EINVAL;
+
+	if (pause->rx_pause && pause->tx_pause)
+		hw->fc.type = ixgbe_fc_full;
+	else if (pause->rx_pause && !pause->tx_pause)
+		hw->fc.type = ixgbe_fc_rx_pause;
+	else if (!pause->rx_pause && pause->tx_pause)
+		hw->fc.type = ixgbe_fc_tx_pause;
+	else if (!pause->rx_pause && !pause->tx_pause)
+		hw->fc.type = ixgbe_fc_none;
+
+	hw->fc.original_type = hw->fc.type;
+
+	if (netif_running(adapter->netdev)) {
+		ixgbe_down(adapter);
+		ixgbe_up(adapter);
+	} else {
+		ixgbe_reset(adapter);
+	}
+
+	return 0;
+}
+
+static u32 ixgbe_get_rx_csum(struct net_device *netdev)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	return (adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED);
+}
+
+static int ixgbe_set_rx_csum(struct net_device *netdev, u32 data)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	if (data)
+		adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED;
+	else
+		adapter->flags &= ~IXGBE_FLAG_RX_CSUM_ENABLED;
+
+	if (netif_running(netdev)) {
+		ixgbe_down(adapter);
+		ixgbe_up(adapter);
+	} else {
+		ixgbe_reset(adapter);
+	}
+
+	return 0;
+}
+
+static u32 ixgbe_get_tx_csum(struct net_device *netdev)
+{
+	return (netdev->features & NETIF_F_HW_CSUM) != 0;
+}
+
+static int ixgbe_set_tx_csum(struct net_device *netdev, u32 data)
+{
+	if (data)
+		netdev->features |= NETIF_F_HW_CSUM;
+	else
+		netdev->features &= ~NETIF_F_HW_CSUM;
+
+	return 0;
+}
+
+static int ixgbe_set_tso(struct net_device *netdev, u32 data)
+{
+
+	if (data) {
+		netdev->features |= NETIF_F_TSO;
+		netdev->features |= NETIF_F_TSO6;
+	} else {
+		netdev->features &= ~NETIF_F_TSO;
+		netdev->features &= ~NETIF_F_TSO6;
+	}
+	return 0;
+}
+
+static u32 ixgbe_get_msglevel(struct net_device *netdev)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	return adapter->msg_enable;
+}
+
+static void ixgbe_set_msglevel(struct net_device *netdev, u32 data)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	adapter->msg_enable = data;
+}
+
+static int ixgbe_get_regs_len(struct net_device *netdev)
+{
+#define IXGBE_REGS_LEN  1128
+	return IXGBE_REGS_LEN * sizeof(u32);
+}
+
+#define IXGBE_GET_STAT(_A_, _R_) _A_->stats._R_
+
+static void ixgbe_get_regs(struct net_device *netdev,
+			   struct ethtool_regs *regs, void *p)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 *regs_buff = p;
+	u8 i;
+
+	memset(p, 0, IXGBE_REGS_LEN * sizeof(u32));
+
+	regs->version = (1 << 24) | hw->revision_id << 16 | hw->device_id;
+
+	/* General Registers */
+	regs_buff[0] = IXGBE_READ_REG(hw, IXGBE_CTRL);
+	regs_buff[1] = IXGBE_READ_REG(hw, IXGBE_STATUS);
+	regs_buff[2] = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
+	regs_buff[3] = IXGBE_READ_REG(hw, IXGBE_ESDP);
+	regs_buff[4] = IXGBE_READ_REG(hw, IXGBE_EODSDP);
+	regs_buff[5] = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+	regs_buff[6] = IXGBE_READ_REG(hw, IXGBE_FRTIMER);
+	regs_buff[7] = IXGBE_READ_REG(hw, IXGBE_TCPTIMER);
+
+	/* NVM Register */
+	regs_buff[8] = IXGBE_READ_REG(hw, IXGBE_EEC);
+	regs_buff[9] = IXGBE_READ_REG(hw, IXGBE_EERD);
+	regs_buff[10] = IXGBE_READ_REG(hw, IXGBE_FLA);
+	regs_buff[11] = IXGBE_READ_REG(hw, IXGBE_EEMNGCTL);
+	regs_buff[12] = IXGBE_READ_REG(hw, IXGBE_EEMNGDATA);
+	regs_buff[13] = IXGBE_READ_REG(hw, IXGBE_FLMNGCTL);
+	regs_buff[14] = IXGBE_READ_REG(hw, IXGBE_FLMNGDATA);
+	regs_buff[15] = IXGBE_READ_REG(hw, IXGBE_FLMNGCNT);
+	regs_buff[16] = IXGBE_READ_REG(hw, IXGBE_FLOP);
+	regs_buff[17] = IXGBE_READ_REG(hw, IXGBE_GRC);
+
+	/* Interrupt */
+	regs_buff[18] = IXGBE_READ_REG(hw, IXGBE_EICR);
+	regs_buff[19] = IXGBE_READ_REG(hw, IXGBE_EICS);
+	regs_buff[20] = IXGBE_READ_REG(hw, IXGBE_EIMS);
+	regs_buff[21] = IXGBE_READ_REG(hw, IXGBE_EIMC);
+	regs_buff[22] = IXGBE_READ_REG(hw, IXGBE_EIAC);
+	regs_buff[23] = IXGBE_READ_REG(hw, IXGBE_EIAM);
+	regs_buff[24] = IXGBE_READ_REG(hw, IXGBE_EITR(0));
+	regs_buff[25] = IXGBE_READ_REG(hw, IXGBE_IVAR(0));
+	regs_buff[26] = IXGBE_READ_REG(hw, IXGBE_MSIXT);
+	regs_buff[27] = IXGBE_READ_REG(hw, IXGBE_MSIXPBA);
+	regs_buff[28] = IXGBE_READ_REG(hw, IXGBE_PBACL);
+	regs_buff[29] = IXGBE_READ_REG(hw, IXGBE_GPIE);
+
+	/* Flow Control */
+	regs_buff[30] = IXGBE_READ_REG(hw, IXGBE_PFCTOP);
+	regs_buff[31] = IXGBE_READ_REG(hw, IXGBE_FCTTV(0));
+	regs_buff[32] = IXGBE_READ_REG(hw, IXGBE_FCTTV(1));
+	regs_buff[33] = IXGBE_READ_REG(hw, IXGBE_FCTTV(2));
+	regs_buff[34] = IXGBE_READ_REG(hw, IXGBE_FCTTV(3));
+	for (i = 0; i < 8; i++)
+		regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL(i));
+	for (i = 0; i < 8; i++)
+		regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH(i));
+	regs_buff[51] = IXGBE_READ_REG(hw, IXGBE_FCRTV);
+	regs_buff[52] = IXGBE_READ_REG(hw, IXGBE_TFCS);
+
+	/* Receive DMA */
+	for (i = 0; i < 64; i++)
+		regs_buff[53 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAL(i));
+	for (i = 0; i < 64; i++)
+		regs_buff[117 + i] = IXGBE_READ_REG(hw, IXGBE_RDBAH(i));
+	for (i = 0; i < 64; i++)
+		regs_buff[181 + i] = IXGBE_READ_REG(hw, IXGBE_RDLEN(i));
+	for (i = 0; i < 64; i++)
+		regs_buff[245 + i] = IXGBE_READ_REG(hw, IXGBE_RDH(i));
+	for (i = 0; i < 64; i++)
+		regs_buff[309 + i] = IXGBE_READ_REG(hw, IXGBE_RDT(i));
+	for (i = 0; i < 64; i++)
+		regs_buff[373 + i] = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i));
+	for (i = 0; i < 16; i++)
+		regs_buff[437 + i] = IXGBE_READ_REG(hw, IXGBE_SRRCTL(i));
+	for (i = 0; i < 16; i++)
+		regs_buff[453 + i] = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i));
+	regs_buff[469] = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
+	for (i = 0; i < 8; i++)
+		regs_buff[470 + i] = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(i));
+	regs_buff[478] = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+	regs_buff[479] = IXGBE_READ_REG(hw, IXGBE_DROPEN);
+
+	/* Receive */
+	regs_buff[480] = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
+	regs_buff[481] = IXGBE_READ_REG(hw, IXGBE_RFCTL);
+	for (i = 0; i < 16; i++)
+		regs_buff[482 + i] = IXGBE_READ_REG(hw, IXGBE_RAL(i));
+	for (i = 0; i < 16; i++)
+		regs_buff[498 + i] = IXGBE_READ_REG(hw, IXGBE_RAH(i));
+	regs_buff[514] = IXGBE_READ_REG(hw, IXGBE_PSRTYPE);
+	regs_buff[515] = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+	regs_buff[516] = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
+	regs_buff[517] = IXGBE_READ_REG(hw, IXGBE_MCSTCTRL);
+	regs_buff[518] = IXGBE_READ_REG(hw, IXGBE_MRQC);
+	regs_buff[519] = IXGBE_READ_REG(hw, IXGBE_VMD_CTL);
+	for (i = 0; i < 8; i++)
+		regs_buff[520 + i] = IXGBE_READ_REG(hw, IXGBE_IMIR(i));
+	for (i = 0; i < 8; i++)
+		regs_buff[528 + i] = IXGBE_READ_REG(hw, IXGBE_IMIREXT(i));
+	regs_buff[536] = IXGBE_READ_REG(hw, IXGBE_IMIRVP);
+
+	/* Transmit */
+	for (i = 0; i < 32; i++)
+		regs_buff[537 + i] = IXGBE_READ_REG(hw, IXGBE_TDBAL(i));
+	for (i = 0; i < 32; i++)
+		regs_buff[569 + i] = IXGBE_READ_REG(hw, IXGBE_TDBAH(i));
+	for (i = 0; i < 32; i++)
+		regs_buff[601 + i] = IXGBE_READ_REG(hw, IXGBE_TDLEN(i));
+	for (i = 0; i < 32; i++)
+		regs_buff[633 + i] = IXGBE_READ_REG(hw, IXGBE_TDH(i));
+	for (i = 0; i < 32; i++)
+		regs_buff[665 + i] = IXGBE_READ_REG(hw, IXGBE_TDT(i));
+	for (i = 0; i < 32; i++)
+		regs_buff[697 + i] = IXGBE_READ_REG(hw, IXGBE_TXDCTL(i));
+	for (i = 0; i < 32; i++)
+		regs_buff[729 + i] = IXGBE_READ_REG(hw, IXGBE_TDWBAL(i));
+	for (i = 0; i < 32; i++)
+		regs_buff[761 + i] = IXGBE_READ_REG(hw, IXGBE_TDWBAH(i));
+	regs_buff[793] = IXGBE_READ_REG(hw, IXGBE_DTXCTL);
+	for (i = 0; i < 16; i++)
+		regs_buff[794 + i] = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i));
+	regs_buff[810] = IXGBE_READ_REG(hw, IXGBE_TIPG);
+	for (i = 0; i < 8; i++)
+		regs_buff[811 + i] = IXGBE_READ_REG(hw, IXGBE_TXPBSIZE(i));
+	regs_buff[819] = IXGBE_READ_REG(hw, IXGBE_MNGTXMAP);
+
+	/* Wake Up */
+	regs_buff[820] = IXGBE_READ_REG(hw, IXGBE_WUC);
+	regs_buff[821] = IXGBE_READ_REG(hw, IXGBE_WUFC);
+	regs_buff[822] = IXGBE_READ_REG(hw, IXGBE_WUS);
+	regs_buff[823] = IXGBE_READ_REG(hw, IXGBE_IPAV);
+	regs_buff[824] = IXGBE_READ_REG(hw, IXGBE_IP4AT);
+	regs_buff[825] = IXGBE_READ_REG(hw, IXGBE_IP6AT);
+	regs_buff[826] = IXGBE_READ_REG(hw, IXGBE_WUPL);
+	regs_buff[827] = IXGBE_READ_REG(hw, IXGBE_WUPM);
+	regs_buff[828] = IXGBE_READ_REG(hw, IXGBE_FHFT);
+
+	/* DCE */
+	regs_buff[829] = IXGBE_READ_REG(hw, IXGBE_RMCS);
+	regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_DPMCS);
+	regs_buff[831] = IXGBE_READ_REG(hw, IXGBE_PDPMCS);
+	regs_buff[832] = IXGBE_READ_REG(hw, IXGBE_RUPPBMR);
+	for (i = 0; i < 8; i++)
+		regs_buff[833 + i] = IXGBE_READ_REG(hw, IXGBE_RT2CR(i));
+	for (i = 0; i < 8; i++)
+		regs_buff[841 + i] = IXGBE_READ_REG(hw, IXGBE_RT2SR(i));
+	for (i = 0; i < 8; i++)
+		regs_buff[849 + i] = IXGBE_READ_REG(hw, IXGBE_TDTQ2TCCR(i));
+	for (i = 0; i < 8; i++)
+		regs_buff[857 + i] = IXGBE_READ_REG(hw, IXGBE_TDTQ2TCSR(i));
+	for (i = 0; i < 8; i++)
+		regs_buff[865 + i] = IXGBE_READ_REG(hw, IXGBE_TDPT2TCCR(i));
+	for (i = 0; i < 8; i++)
+		regs_buff[873 + i] = IXGBE_READ_REG(hw, IXGBE_TDPT2TCSR(i));
+
+	/* Statistics */
+	regs_buff[881] = IXGBE_GET_STAT(adapter, crcerrs);
+	regs_buff[882] = IXGBE_GET_STAT(adapter, illerrc);
+	regs_buff[883] = IXGBE_GET_STAT(adapter, errbc);
+	regs_buff[884] = IXGBE_GET_STAT(adapter, mspdc);
+	for (i = 0; i < 8; i++)
+		regs_buff[885 + i] = IXGBE_GET_STAT(adapter, mpc[i]);
+	regs_buff[893] = IXGBE_GET_STAT(adapter, mlfc);
+	regs_buff[894] = IXGBE_GET_STAT(adapter, mrfc);
+	regs_buff[895] = IXGBE_GET_STAT(adapter, rlec);
+	regs_buff[896] = IXGBE_GET_STAT(adapter, lxontxc);
+	regs_buff[897] = IXGBE_GET_STAT(adapter, lxonrxc);
+	regs_buff[898] = IXGBE_GET_STAT(adapter, lxofftxc);
+	regs_buff[899] = IXGBE_GET_STAT(adapter, lxoffrxc);
+	for (i = 0; i < 8; i++)
+		regs_buff[900 + i] = IXGBE_GET_STAT(adapter, pxontxc[i]);
+	for (i = 0; i < 8; i++)
+		regs_buff[908 + i] = IXGBE_GET_STAT(adapter, pxonrxc[i]);
+	for (i = 0; i < 8; i++)
+		regs_buff[916 + i] = IXGBE_GET_STAT(adapter, pxofftxc[i]);
+	for (i = 0; i < 8; i++)
+		regs_buff[924 + i] = IXGBE_GET_STAT(adapter, pxoffrxc[i]);
+	regs_buff[932] = IXGBE_GET_STAT(adapter, prc64);
+	regs_buff[933] = IXGBE_GET_STAT(adapter, prc127);
+	regs_buff[934] = IXGBE_GET_STAT(adapter, prc255);
+	regs_buff[935] = IXGBE_GET_STAT(adapter, prc511);
+	regs_buff[936] = IXGBE_GET_STAT(adapter, prc1023);
+	regs_buff[937] = IXGBE_GET_STAT(adapter, prc1522);
+	regs_buff[938] = IXGBE_GET_STAT(adapter, gprc);
+	regs_buff[939] = IXGBE_GET_STAT(adapter, bprc);
+	regs_buff[940] = IXGBE_GET_STAT(adapter, mprc);
+	regs_buff[941] = IXGBE_GET_STAT(adapter, gptc);
+	regs_buff[942] = IXGBE_GET_STAT(adapter, gorc);
+	regs_buff[944] = IXGBE_GET_STAT(adapter, gotc);
+	for (i = 0; i < 8; i++)
+		regs_buff[946 + i] = IXGBE_GET_STAT(adapter, rnbc[i]);
+	regs_buff[954] = IXGBE_GET_STAT(adapter, ruc);
+	regs_buff[955] = IXGBE_GET_STAT(adapter, rfc);
+	regs_buff[956] = IXGBE_GET_STAT(adapter, roc);
+	regs_buff[957] = IXGBE_GET_STAT(adapter, rjc);
+	regs_buff[958] = IXGBE_GET_STAT(adapter, mngprc);
+	regs_buff[959] = IXGBE_GET_STAT(adapter, mngpdc);
+	regs_buff[960] = IXGBE_GET_STAT(adapter, mngptc);
+	regs_buff[961] = IXGBE_GET_STAT(adapter, tor);
+	regs_buff[963] = IXGBE_GET_STAT(adapter, tpr);
+	regs_buff[964] = IXGBE_GET_STAT(adapter, tpt);
+	regs_buff[965] = IXGBE_GET_STAT(adapter, ptc64);
+	regs_buff[966] = IXGBE_GET_STAT(adapter, ptc127);
+	regs_buff[967] = IXGBE_GET_STAT(adapter, ptc255);
+	regs_buff[968] = IXGBE_GET_STAT(adapter, ptc511);
+	regs_buff[969] = IXGBE_GET_STAT(adapter, ptc1023);
+	regs_buff[970] = IXGBE_GET_STAT(adapter, ptc1522);
+	regs_buff[971] = IXGBE_GET_STAT(adapter, mptc);
+	regs_buff[972] = IXGBE_GET_STAT(adapter, bptc);
+	regs_buff[973] = IXGBE_GET_STAT(adapter, xec);
+	for (i = 0; i < 16; i++)
+		regs_buff[974 + i] = IXGBE_GET_STAT(adapter, qprc[i]);
+	for (i = 0; i < 16; i++)
+		regs_buff[990 + i] = IXGBE_GET_STAT(adapter, qptc[i]);
+	for (i = 0; i < 16; i++)
+		regs_buff[1006 + i] = IXGBE_GET_STAT(adapter, qbrc[i]);
+	for (i = 0; i < 16; i++)
+		regs_buff[1022 + i] = IXGBE_GET_STAT(adapter, qbtc[i]);
+
+	/* MAC */
+	regs_buff[1038] = IXGBE_READ_REG(hw, IXGBE_PCS1GCFIG);
+	regs_buff[1039] = IXGBE_READ_REG(hw, IXGBE_PCS1GLCTL);
+	regs_buff[1040] = IXGBE_READ_REG(hw, IXGBE_PCS1GLSTA);
+	regs_buff[1041] = IXGBE_READ_REG(hw, IXGBE_PCS1GDBG0);
+	regs_buff[1042] = IXGBE_READ_REG(hw, IXGBE_PCS1GDBG1);
+	regs_buff[1043] = IXGBE_READ_REG(hw, IXGBE_PCS1GANA);
+	regs_buff[1044] = IXGBE_READ_REG(hw, IXGBE_PCS1GANLP);
+	regs_buff[1045] = IXGBE_READ_REG(hw, IXGBE_PCS1GANNP);
+	regs_buff[1046] = IXGBE_READ_REG(hw, IXGBE_PCS1GANLPNP);
+	regs_buff[1047] = IXGBE_READ_REG(hw, IXGBE_HLREG0);
+	regs_buff[1048] = IXGBE_READ_REG(hw, IXGBE_HLREG1);
+	regs_buff[1049] = IXGBE_READ_REG(hw, IXGBE_PAP);
+	regs_buff[1050] = IXGBE_READ_REG(hw, IXGBE_MACA);
+	regs_buff[1051] = IXGBE_READ_REG(hw, IXGBE_APAE);
+	regs_buff[1052] = IXGBE_READ_REG(hw, IXGBE_ARD);
+	regs_buff[1053] = IXGBE_READ_REG(hw, IXGBE_AIS);
+	regs_buff[1054] = IXGBE_READ_REG(hw, IXGBE_MSCA);
+	regs_buff[1055] = IXGBE_READ_REG(hw, IXGBE_MSRWD);
+	regs_buff[1056] = IXGBE_READ_REG(hw, IXGBE_MLADD);
+	regs_buff[1057] = IXGBE_READ_REG(hw, IXGBE_MHADD);
+	regs_buff[1058] = IXGBE_READ_REG(hw, IXGBE_TREG);
+	regs_buff[1059] = IXGBE_READ_REG(hw, IXGBE_PCSS1);
+	regs_buff[1060] = IXGBE_READ_REG(hw, IXGBE_PCSS2);
+	regs_buff[1061] = IXGBE_READ_REG(hw, IXGBE_XPCSS);
+	regs_buff[1062] = IXGBE_READ_REG(hw, IXGBE_SERDESC);
+	regs_buff[1063] = IXGBE_READ_REG(hw, IXGBE_MACS);
+	regs_buff[1064] = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+	regs_buff[1065] = IXGBE_READ_REG(hw, IXGBE_LINKS);
+	regs_buff[1066] = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
+	regs_buff[1067] = IXGBE_READ_REG(hw, IXGBE_AUTOC3);
+	regs_buff[1068] = IXGBE_READ_REG(hw, IXGBE_ANLP1);
+	regs_buff[1069] = IXGBE_READ_REG(hw, IXGBE_ANLP2);
+	regs_buff[1070] = IXGBE_READ_REG(hw, IXGBE_ATLASCTL);
+
+	/* Diagnostic */
+	regs_buff[1071] = IXGBE_READ_REG(hw, IXGBE_RDSTATCTL);
+	for (i = 0; i < 8; i++)
+		regs_buff[1072] = IXGBE_READ_REG(hw, IXGBE_RDSTAT(i));
+	regs_buff[1080] = IXGBE_READ_REG(hw, IXGBE_RDHMPN);
+	regs_buff[1081] = IXGBE_READ_REG(hw, IXGBE_RIC_DW0);
+	regs_buff[1082] = IXGBE_READ_REG(hw, IXGBE_RIC_DW1);
+	regs_buff[1083] = IXGBE_READ_REG(hw, IXGBE_RIC_DW2);
+	regs_buff[1084] = IXGBE_READ_REG(hw, IXGBE_RIC_DW3);
+	regs_buff[1085] = IXGBE_READ_REG(hw, IXGBE_RDPROBE);
+	regs_buff[1086] = IXGBE_READ_REG(hw, IXGBE_TDSTATCTL);
+	for (i = 0; i < 8; i++)
+		regs_buff[1087] = IXGBE_READ_REG(hw, IXGBE_TDSTAT(i));
+	regs_buff[1095] = IXGBE_READ_REG(hw, IXGBE_TDHMPN);
+	regs_buff[1096] = IXGBE_READ_REG(hw, IXGBE_TIC_DW0);
+	regs_buff[1097] = IXGBE_READ_REG(hw, IXGBE_TIC_DW1);
+	regs_buff[1098] = IXGBE_READ_REG(hw, IXGBE_TIC_DW2);
+	regs_buff[1099] = IXGBE_READ_REG(hw, IXGBE_TIC_DW3);
+	regs_buff[1100] = IXGBE_READ_REG(hw, IXGBE_TDPROBE);
+	regs_buff[1101] = IXGBE_READ_REG(hw, IXGBE_TXBUFCTRL);
+	regs_buff[1102] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA0);
+	regs_buff[1103] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA1);
+	regs_buff[1104] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA2);
+	regs_buff[1105] = IXGBE_READ_REG(hw, IXGBE_TXBUFDATA3);
+	regs_buff[1106] = IXGBE_READ_REG(hw, IXGBE_RXBUFCTRL);
+	regs_buff[1107] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA0);
+	regs_buff[1108] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA1);
+	regs_buff[1109] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA2);
+	regs_buff[1110] = IXGBE_READ_REG(hw, IXGBE_RXBUFDATA3);
+	for (i = 0; i < 8; i++)
+		regs_buff[1111] = IXGBE_READ_REG(hw, IXGBE_PCIE_DIAG(i));
+	regs_buff[1119] = IXGBE_READ_REG(hw, IXGBE_RFVAL);
+	regs_buff[1120] = IXGBE_READ_REG(hw, IXGBE_MDFTC1);
+	regs_buff[1121] = IXGBE_READ_REG(hw, IXGBE_MDFTC2);
+	regs_buff[1122] = IXGBE_READ_REG(hw, IXGBE_MDFTFIFO1);
+	regs_buff[1123] = IXGBE_READ_REG(hw, IXGBE_MDFTFIFO2);
+	regs_buff[1124] = IXGBE_READ_REG(hw, IXGBE_MDFTS);
+	regs_buff[1125] = IXGBE_READ_REG(hw, IXGBE_PCIEECCCTL);
+	regs_buff[1126] = IXGBE_READ_REG(hw, IXGBE_PBTXECC);
+	regs_buff[1127] = IXGBE_READ_REG(hw, IXGBE_PBRXECC);
+}
+
+static int ixgbe_get_eeprom_len(struct net_device *netdev)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	return adapter->hw.eeprom.word_size * 2;
+}
+
+static int ixgbe_get_eeprom(struct net_device *netdev,
+			    struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	struct ixgbe_hw *hw = &adapter->hw;
+	u16 *eeprom_buff;
+	int first_word, last_word, eeprom_len;
+	int ret_val = 0;
+	u16 i;
+
+	if (eeprom->len == 0)
+		return -EINVAL;
+
+	eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+	first_word = eeprom->offset >> 1;
+	last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+	eeprom_len = last_word - first_word + 1;
+
+	eeprom_buff = kmalloc(sizeof(u16) * eeprom_len, GFP_KERNEL);
+	if (!eeprom_buff)
+		return -ENOMEM;
+
+	for (i = 0; i < eeprom_len; i++) {
+		if ((ret_val = ixgbe_read_eeprom(hw, first_word + i,
+						 &eeprom_buff[i])))
+			break;
+	}
+
+	/* Device's eeprom is always little-endian, word addressable */
+	for (i = 0; i < eeprom_len; i++)
+		le16_to_cpus(&eeprom_buff[i]);
+
+	memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
+	kfree(eeprom_buff);
+
+	return ret_val;
+}
+
+static void ixgbe_get_drvinfo(struct net_device *netdev,
+			      struct ethtool_drvinfo *drvinfo)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	strncpy(drvinfo->driver, ixgbe_driver_name, 32);
+	strncpy(drvinfo->version, ixgbe_driver_version, 32);
+	strncpy(drvinfo->fw_version, "N/A", 32);
+	strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
+	drvinfo->n_stats = IXGBE_STATS_LEN;
+	drvinfo->regdump_len = ixgbe_get_regs_len(netdev);
+}
+
+static void ixgbe_get_ringparam(struct net_device *netdev,
+				struct ethtool_ringparam *ring)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	struct ixgbe_ring *tx_ring = adapter->tx_ring;
+	struct ixgbe_ring *rx_ring = adapter->rx_ring;
+
+	ring->rx_max_pending = IXGBE_MAX_RXD;
+	ring->tx_max_pending = IXGBE_MAX_TXD;
+	ring->rx_mini_max_pending = 0;
+	ring->rx_jumbo_max_pending = 0;
+	ring->rx_pending = rx_ring->count;
+	ring->tx_pending = tx_ring->count;
+	ring->rx_mini_pending = 0;
+	ring->rx_jumbo_pending = 0;
+}
+
+static int ixgbe_set_ringparam(struct net_device *netdev,
+			       struct ethtool_ringparam *ring)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	struct ixgbe_tx_buffer *old_buf;
+	struct ixgbe_rx_buffer *old_rx_buf;
+	void *old_desc;
+	int i, err;
+	u32 new_rx_count, new_tx_count, old_size;
+	dma_addr_t old_dma;
+
+	if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+		return -EINVAL;
+
+	new_rx_count = max(ring->rx_pending, (u32)IXGBE_MIN_RXD);
+	new_rx_count = min(new_rx_count, (u32)IXGBE_MAX_RXD);
+	new_rx_count = ALIGN(new_rx_count, IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE);
+
+	new_tx_count = max(ring->tx_pending, (u32)IXGBE_MIN_TXD);
+	new_tx_count = min(new_tx_count, (u32)IXGBE_MAX_TXD);
+	new_tx_count = ALIGN(new_tx_count, IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE);
+
+	if ((new_tx_count == adapter->tx_ring->count) &&
+	    (new_rx_count == adapter->rx_ring->count)) {
+		/* nothing to do */
+		return 0;
+	}
+
+	if (netif_running(adapter->netdev))
+		ixgbe_down(adapter);
+
+	/*
+	 * We can't just free everything and then setup again,
+	 * because the ISRs in MSI-X mode get passed pointers
+	 * to the tx and rx ring structs.
+	 */
+	if (new_tx_count != adapter->tx_ring->count) {
+		for (i = 0; i < adapter->num_tx_queues; i++) {
+			/* Save existing descriptor ring */
+			old_buf = adapter->tx_ring[i].tx_buffer_info;
+			old_desc = adapter->tx_ring[i].desc;
+			old_size = adapter->tx_ring[i].size;
+			old_dma = adapter->tx_ring[i].dma;
+			/* Try to allocate a new one */
+			adapter->tx_ring[i].tx_buffer_info = NULL;
+			adapter->tx_ring[i].desc = NULL;
+			adapter->tx_ring[i].count = new_tx_count;
+			err = ixgbe_setup_tx_resources(adapter,
+						       &adapter->tx_ring[i]);
+			if (err) {
+				/* Restore the old one so at least
+				   the adapter still works, even if
+				   we failed the request */
+				adapter->tx_ring[i].tx_buffer_info = old_buf;
+				adapter->tx_ring[i].desc = old_desc;
+				adapter->tx_ring[i].size = old_size;
+				adapter->tx_ring[i].dma = old_dma;
+				goto err_setup;
+			}
+			/* Free the old buffer manually */
+			vfree(old_buf);
+			pci_free_consistent(adapter->pdev, old_size,
+					    old_desc, old_dma);
+		}
+	}
+
+	if (new_rx_count != adapter->rx_ring->count) {
+		for (i = 0; i < adapter->num_rx_queues; i++) {
+
+			old_rx_buf = adapter->rx_ring[i].rx_buffer_info;
+			old_desc = adapter->rx_ring[i].desc;
+			old_size = adapter->rx_ring[i].size;
+			old_dma = adapter->rx_ring[i].dma;
+
+			adapter->rx_ring[i].rx_buffer_info = NULL;
+			adapter->rx_ring[i].desc = NULL;
+			adapter->rx_ring[i].dma = 0;
+			adapter->rx_ring[i].count = new_rx_count;
+			err = ixgbe_setup_rx_resources(adapter,
+						       &adapter->rx_ring[i]);
+			if (err) {
+				adapter->rx_ring[i].rx_buffer_info = old_rx_buf;
+				adapter->rx_ring[i].desc = old_desc;
+				adapter->rx_ring[i].size = old_size;
+				adapter->rx_ring[i].dma = old_dma;
+				goto err_setup;
+			}
+
+			vfree(old_rx_buf);
+			pci_free_consistent(adapter->pdev, old_size, old_desc,
+					    old_dma);
+		}
+	}
+
+	err = 0;
+err_setup:
+	if (netif_running(adapter->netdev))
+		ixgbe_up(adapter);
+
+	return err;
+}
+
+static int ixgbe_get_sset_count(struct net_device *netdev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_STATS:
+		return IXGBE_STATS_LEN;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static void ixgbe_get_ethtool_stats(struct net_device *netdev,
+				    struct ethtool_stats *stats, u64 *data)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	u64 *queue_stat;
+	int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64);
+	int j, k;
+	int i;
+
+	ixgbe_update_stats(adapter);
+	for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
+		char *p = (char *)adapter + ixgbe_gstrings_stats[i].stat_offset;
+		data[i] = (ixgbe_gstrings_stats[i].sizeof_stat ==
+			   sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+	}
+	for (j = 0; j < adapter->num_tx_queues; j++) {
+		queue_stat = (u64 *)&adapter->tx_ring[j].stats;
+		for (k = 0; k < stat_count; k++)
+			data[i + k] = queue_stat[k];
+		i += k;
+	}
+	for (j = 0; j < adapter->num_rx_queues; j++) {
+		queue_stat = (u64 *)&adapter->rx_ring[j].stats;
+		for (k = 0; k < stat_count; k++)
+			data[i + k] = queue_stat[k];
+		i += k;
+	}
+}
+
+static void ixgbe_get_strings(struct net_device *netdev, u32 stringset,
+			      u8 *data)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	u8 *p = data;
+	int i;
+
+	switch (stringset) {
+	case ETH_SS_STATS:
+		for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
+			memcpy(p, ixgbe_gstrings_stats[i].stat_string,
+			       ETH_GSTRING_LEN);
+			p += ETH_GSTRING_LEN;
+		}
+		for (i = 0; i < adapter->num_tx_queues; i++) {
+			sprintf(p, "tx_queue_%u_packets", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "tx_queue_%u_bytes", i);
+			p += ETH_GSTRING_LEN;
+		}
+		for (i = 0; i < adapter->num_rx_queues; i++) {
+			sprintf(p, "rx_queue_%u_packets", i);
+			p += ETH_GSTRING_LEN;
+			sprintf(p, "rx_queue_%u_bytes", i);
+			p += ETH_GSTRING_LEN;
+		}
+/*		BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */
+		break;
+	}
+}
+
+
+static void ixgbe_get_wol(struct net_device *netdev,
+			  struct ethtool_wolinfo *wol)
+{
+	wol->supported = 0;
+	wol->wolopts = 0;
+
+	return;
+}
+
+static int ixgbe_nway_reset(struct net_device *netdev)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	if (netif_running(netdev)) {
+		ixgbe_down(adapter);
+		ixgbe_reset(adapter);
+		ixgbe_up(adapter);
+	}
+
+	return 0;
+}
+
+static int ixgbe_phys_id(struct net_device *netdev, u32 data)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	u32 led_reg = IXGBE_READ_REG(&adapter->hw, IXGBE_LEDCTL);
+	u32 i;
+
+	if (!data || data > 300)
+		data = 300;
+
+	for (i = 0; i < (data * 1000); i += 400) {
+		ixgbe_led_on(&adapter->hw, IXGBE_LED_ON);
+		msleep_interruptible(200);
+		ixgbe_led_off(&adapter->hw, IXGBE_LED_ON);
+		msleep_interruptible(200);
+	}
+
+	/* Restore LED settings */
+	IXGBE_WRITE_REG(&adapter->hw, IXGBE_LEDCTL, led_reg);
+
+	return 0;
+}
+
+static int ixgbe_get_coalesce(struct net_device *netdev,
+			      struct ethtool_coalesce *ec)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	if (adapter->rx_eitr == 0)
+		ec->rx_coalesce_usecs = 0;
+	else
+		ec->rx_coalesce_usecs = 1000000 / adapter->rx_eitr;
+
+	if (adapter->tx_eitr == 0)
+		ec->tx_coalesce_usecs = 0;
+	else
+		ec->tx_coalesce_usecs = 1000000 / adapter->tx_eitr;
+
+	ec->tx_max_coalesced_frames_irq = adapter->tx_ring[0].work_limit;
+	return 0;
+}
+
+static int ixgbe_set_coalesce(struct net_device *netdev,
+			      struct ethtool_coalesce *ec)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	if ((ec->rx_coalesce_usecs > IXGBE_MAX_ITR_USECS) ||
+	    ((ec->rx_coalesce_usecs > 0) &&
+	     (ec->rx_coalesce_usecs < IXGBE_MIN_ITR_USECS)))
+		return -EINVAL;
+	if ((ec->tx_coalesce_usecs > IXGBE_MAX_ITR_USECS) ||
+	    ((ec->tx_coalesce_usecs > 0) &&
+	     (ec->tx_coalesce_usecs < IXGBE_MIN_ITR_USECS)))
+		return -EINVAL;
+
+	/* convert to rate of irq's per second */
+	if (ec->rx_coalesce_usecs == 0)
+		adapter->rx_eitr = 0;
+	else
+		adapter->rx_eitr = (1000000 / ec->rx_coalesce_usecs);
+
+	if (ec->tx_coalesce_usecs == 0)
+		adapter->tx_eitr = 0;
+	else
+		adapter->tx_eitr = (1000000 / ec->tx_coalesce_usecs);
+
+	if (ec->tx_max_coalesced_frames_irq)
+		adapter->tx_ring[0].work_limit =
+					ec->tx_max_coalesced_frames_irq;
+
+	if (netif_running(netdev)) {
+		ixgbe_down(adapter);
+		ixgbe_up(adapter);
+	}
+
+	return 0;
+}
+
+
+static struct ethtool_ops ixgbe_ethtool_ops = {
+	.get_settings           = ixgbe_get_settings,
+	.set_settings           = ixgbe_set_settings,
+	.get_drvinfo            = ixgbe_get_drvinfo,
+	.get_regs_len           = ixgbe_get_regs_len,
+	.get_regs               = ixgbe_get_regs,
+	.get_wol                = ixgbe_get_wol,
+	.nway_reset             = ixgbe_nway_reset,
+	.get_link               = ethtool_op_get_link,
+	.get_eeprom_len         = ixgbe_get_eeprom_len,
+	.get_eeprom             = ixgbe_get_eeprom,
+	.get_ringparam          = ixgbe_get_ringparam,
+	.set_ringparam          = ixgbe_set_ringparam,
+	.get_pauseparam         = ixgbe_get_pauseparam,
+	.set_pauseparam         = ixgbe_set_pauseparam,
+	.get_rx_csum            = ixgbe_get_rx_csum,
+	.set_rx_csum            = ixgbe_set_rx_csum,
+	.get_tx_csum            = ixgbe_get_tx_csum,
+	.set_tx_csum            = ixgbe_set_tx_csum,
+	.get_sg                 = ethtool_op_get_sg,
+	.set_sg                 = ethtool_op_set_sg,
+	.get_msglevel           = ixgbe_get_msglevel,
+	.set_msglevel           = ixgbe_set_msglevel,
+	.get_tso                = ethtool_op_get_tso,
+	.set_tso                = ixgbe_set_tso,
+	.get_strings            = ixgbe_get_strings,
+	.phys_id                = ixgbe_phys_id,
+	.get_sset_count		= ixgbe_get_sset_count,
+	.get_ethtool_stats      = ixgbe_get_ethtool_stats,
+	.get_coalesce           = ixgbe_get_coalesce,
+	.set_coalesce           = ixgbe_set_coalesce,
+};
+
+void ixgbe_set_ethtool_ops(struct net_device *netdev)
+{
+	SET_ETHTOOL_OPS(netdev, &ixgbe_ethtool_ops);
+}
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
new file mode 100644
index 0000000..b75f1c6
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -0,0 +1,2872 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/ipv6.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+
+#include "ixgbe.h"
+#include "ixgbe_common.h"
+
+char ixgbe_driver_name[] = "ixgbe";
+static char ixgbe_driver_string[] =
+			"Intel(R) 10 Gigabit PCI Express Network Driver";
+
+#define DRV_VERSION "1.1.18"
+char ixgbe_driver_version[] = DRV_VERSION;
+static char ixgbe_copyright[] = "Copyright (c) 1999-2007 Intel Corporation.";
+
+static const struct ixgbe_info *ixgbe_info_tbl[] = {
+	[board_82598AF]			= &ixgbe_82598AF_info,
+	[board_82598EB]			= &ixgbe_82598EB_info,
+	[board_82598AT]			= &ixgbe_82598AT_info,
+};
+
+/* ixgbe_pci_tbl - PCI Device ID Table
+ *
+ * Wildcard entries (PCI_ANY_ID) should come last
+ * Last entry must be all 0s
+ *
+ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
+ *   Class, Class Mask, private data (not used) }
+ */
+static struct pci_device_id ixgbe_pci_tbl[] = {
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_DUAL_PORT),
+	 board_82598AF },
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_SINGLE_PORT),
+	 board_82598AF },
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT_DUAL_PORT),
+	 board_82598AT },
+	{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4),
+	 board_82598EB },
+
+	/* required last entry */
+	{0, }
+};
+MODULE_DEVICE_TABLE(pci, ixgbe_pci_tbl);
+
+MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
+MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+#define DEFAULT_DEBUG_LEVEL_SHIFT 3
+
+
+#ifdef DEBUG
+/**
+ * ixgbe_get_hw_dev_name - return device name string
+ * used by hardware layer to print debugging information
+ **/
+char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw)
+{
+	struct ixgbe_adapter *adapter = hw->back;
+	struct net_device *netdev = adapter->netdev;
+	return netdev->name;
+}
+#endif
+
+static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, u16 int_alloc_entry,
+			   u8 msix_vector)
+{
+	u32 ivar, index;
+
+	msix_vector |= IXGBE_IVAR_ALLOC_VAL;
+	index = (int_alloc_entry >> 2) & 0x1F;
+	ivar = IXGBE_READ_REG(&adapter->hw, IXGBE_IVAR(index));
+	ivar &= ~(0xFF << (8 * (int_alloc_entry & 0x3)));
+	ivar |= (msix_vector << (8 * (int_alloc_entry & 0x3)));
+	IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR(index), ivar);
+}
+
+static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
+					     struct ixgbe_tx_buffer
+					     *tx_buffer_info)
+{
+	if (tx_buffer_info->dma) {
+		pci_unmap_page(adapter->pdev,
+			       tx_buffer_info->dma,
+			       tx_buffer_info->length, PCI_DMA_TODEVICE);
+		tx_buffer_info->dma = 0;
+	}
+	if (tx_buffer_info->skb) {
+		dev_kfree_skb_any(tx_buffer_info->skb);
+		tx_buffer_info->skb = NULL;
+	}
+	/* tx_buffer_info must be completely set up in the transmit path */
+}
+
+static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter,
+				       struct ixgbe_ring *tx_ring,
+				       unsigned int eop,
+				       union ixgbe_adv_tx_desc *eop_desc)
+{
+	/* Detect a transmit hang in hardware, this serializes the
+	 * check with the clearing of time_stamp and movement of i */
+	adapter->detect_tx_hung = false;
+	if (tx_ring->tx_buffer_info[eop].dma &&
+	    time_after(jiffies, tx_ring->tx_buffer_info[eop].time_stamp + HZ) &&
+	    !(IXGBE_READ_REG(&adapter->hw, IXGBE_TFCS) & IXGBE_TFCS_TXOFF)) {
+		/* detected Tx unit hang */
+		DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n"
+			"  TDH                  <%x>\n"
+			"  TDT                  <%x>\n"
+			"  next_to_use          <%x>\n"
+			"  next_to_clean        <%x>\n"
+			"tx_buffer_info[next_to_clean]\n"
+			"  time_stamp           <%lx>\n"
+			"  next_to_watch        <%x>\n"
+			"  jiffies              <%lx>\n"
+			"  next_to_watch.status <%x>\n",
+			readl(adapter->hw.hw_addr + tx_ring->head),
+			readl(adapter->hw.hw_addr + tx_ring->tail),
+			tx_ring->next_to_use,
+			tx_ring->next_to_clean,
+			tx_ring->tx_buffer_info[eop].time_stamp,
+			eop, jiffies, eop_desc->wb.status);
+		return true;
+	}
+
+	return false;
+}
+
+/**
+ * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
+ * @adapter: board private structure
+ **/
+static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
+				    struct ixgbe_ring *tx_ring)
+{
+	struct net_device *netdev = adapter->netdev;
+	union ixgbe_adv_tx_desc *tx_desc, *eop_desc;
+	struct ixgbe_tx_buffer *tx_buffer_info;
+	unsigned int i, eop;
+	bool cleaned = false;
+	int count = 0;
+
+	i = tx_ring->next_to_clean;
+	eop = tx_ring->tx_buffer_info[i].next_to_watch;
+	eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
+	while (eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) {
+		for (cleaned = false; !cleaned;) {
+			tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
+			tx_buffer_info = &tx_ring->tx_buffer_info[i];
+			cleaned = (i == eop);
+
+			tx_ring->stats.bytes += tx_buffer_info->length;
+			ixgbe_unmap_and_free_tx_resource(adapter,
+							 tx_buffer_info);
+			tx_desc->wb.status = 0;
+
+			i++;
+			if (i == tx_ring->count)
+				i = 0;
+		}
+
+		tx_ring->stats.packets++;
+
+		eop = tx_ring->tx_buffer_info[i].next_to_watch;
+		eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
+
+		/* weight of a sort for tx, avoid endless transmit cleanup */
+		if (count++ >= tx_ring->work_limit)
+			break;
+	}
+
+	tx_ring->next_to_clean = i;
+
+#define TX_WAKE_THRESHOLD 32
+	spin_lock(&tx_ring->tx_lock);
+
+	if (cleaned && netif_carrier_ok(netdev) &&
+	    (IXGBE_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD) &&
+	    !test_bit(__IXGBE_DOWN, &adapter->state))
+		netif_wake_queue(netdev);
+
+	spin_unlock(&tx_ring->tx_lock);
+
+	if (adapter->detect_tx_hung)
+		if (ixgbe_check_tx_hang(adapter, tx_ring, eop, eop_desc))
+			netif_stop_queue(netdev);
+
+	if (count >= tx_ring->work_limit)
+		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->eims_value);
+
+	return cleaned;
+}
+
+/**
+ * ixgbe_receive_skb - Send a completed packet up the stack
+ * @adapter: board private structure
+ * @skb: packet to send up
+ * @is_vlan: packet has a VLAN tag
+ * @tag: VLAN tag from descriptor
+ **/
+static void ixgbe_receive_skb(struct ixgbe_adapter *adapter,
+			      struct sk_buff *skb, bool is_vlan,
+			      u16 tag)
+{
+	if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) {
+		if (adapter->vlgrp && is_vlan)
+			vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag);
+		else
+			netif_receive_skb(skb);
+	} else {
+
+		if (adapter->vlgrp && is_vlan)
+			vlan_hwaccel_rx(skb, adapter->vlgrp, tag);
+		else
+			netif_rx(skb);
+	}
+}
+
+static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
+					 u32 status_err,
+					 struct sk_buff *skb)
+{
+	skb->ip_summed = CHECKSUM_NONE;
+
+	/* Ignore Checksum bit is set */
+	if ((status_err & IXGBE_RXD_STAT_IXSM) ||
+		     !(adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED))
+		return;
+	/* TCP/UDP checksum error bit is set */
+	if (status_err & (IXGBE_RXDADV_ERR_TCPE | IXGBE_RXDADV_ERR_IPE)) {
+		/* let the stack verify checksum errors */
+		adapter->hw_csum_rx_error++;
+		return;
+	}
+	/* It must be a TCP or UDP packet with a valid checksum */
+	if (status_err & (IXGBE_RXD_STAT_L4CS | IXGBE_RXD_STAT_UDPCS))
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+	adapter->hw_csum_rx_good++;
+}
+
+/**
+ * ixgbe_alloc_rx_buffers - Replace used receive buffers; packet split
+ * @adapter: address of board private structure
+ **/
+static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
+				       struct ixgbe_ring *rx_ring,
+				       int cleaned_count)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	union ixgbe_adv_rx_desc *rx_desc;
+	struct ixgbe_rx_buffer *rx_buffer_info;
+	struct sk_buff *skb;
+	unsigned int i;
+	unsigned int bufsz = adapter->rx_buf_len + NET_IP_ALIGN;
+
+	i = rx_ring->next_to_use;
+	rx_buffer_info = &rx_ring->rx_buffer_info[i];
+
+	while (cleaned_count--) {
+		rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
+
+		if (!rx_buffer_info->page &&
+				(adapter->flags & IXGBE_FLAG_RX_PS_ENABLED)) {
+			rx_buffer_info->page = alloc_page(GFP_ATOMIC);
+			if (!rx_buffer_info->page) {
+				adapter->alloc_rx_page_failed++;
+				goto no_buffers;
+			}
+			rx_buffer_info->page_dma =
+			    pci_map_page(pdev, rx_buffer_info->page,
+					 0, PAGE_SIZE, PCI_DMA_FROMDEVICE);
+		}
+
+		if (!rx_buffer_info->skb) {
+			skb = netdev_alloc_skb(netdev, bufsz);
+
+			if (!skb) {
+				adapter->alloc_rx_buff_failed++;
+				goto no_buffers;
+			}
+
+			/*
+			 * Make buffer alignment 2 beyond a 16 byte boundary
+			 * this will result in a 16 byte aligned IP header after
+			 * the 14 byte MAC header is removed
+			 */
+			skb_reserve(skb, NET_IP_ALIGN);
+
+			rx_buffer_info->skb = skb;
+			rx_buffer_info->dma = pci_map_single(pdev, skb->data,
+							  bufsz,
+							  PCI_DMA_FROMDEVICE);
+		}
+		/* Refresh the desc even if buffer_addrs didn't change because
+		 * each write-back erases this info. */
+		if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+			rx_desc->read.pkt_addr =
+			    cpu_to_le64(rx_buffer_info->page_dma);
+			rx_desc->read.hdr_addr =
+					cpu_to_le64(rx_buffer_info->dma);
+		} else {
+			rx_desc->read.pkt_addr =
+					cpu_to_le64(rx_buffer_info->dma);
+		}
+
+		i++;
+		if (i == rx_ring->count)
+			i = 0;
+		rx_buffer_info = &rx_ring->rx_buffer_info[i];
+	}
+no_buffers:
+	if (rx_ring->next_to_use != i) {
+		rx_ring->next_to_use = i;
+		if (i-- == 0)
+			i = (rx_ring->count - 1);
+
+		/*
+		 * Force memory writes to complete before letting h/w
+		 * know there are new descriptors to fetch.  (Only
+		 * applicable for weak-ordered memory model archs,
+		 * such as IA-64).
+		 */
+		wmb();
+		writel(i, adapter->hw.hw_addr + rx_ring->tail);
+	}
+}
+
+static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter,
+			       struct ixgbe_ring *rx_ring,
+			       int *work_done, int work_to_do)
+{
+	struct net_device *netdev = adapter->netdev;
+	struct pci_dev *pdev = adapter->pdev;
+	union ixgbe_adv_rx_desc *rx_desc, *next_rxd;
+	struct ixgbe_rx_buffer *rx_buffer_info, *next_buffer;
+	struct sk_buff *skb;
+	unsigned int i;
+	u32 upper_len, len, staterr;
+	u16 hdr_info, vlan_tag;
+	bool is_vlan, cleaned = false;
+	int cleaned_count = 0;
+
+	i = rx_ring->next_to_clean;
+	upper_len = 0;
+	rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
+	staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+	rx_buffer_info = &rx_ring->rx_buffer_info[i];
+	is_vlan = (staterr & IXGBE_RXD_STAT_VP);
+	vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan);
+
+	while (staterr & IXGBE_RXD_STAT_DD) {
+		if (*work_done >= work_to_do)
+			break;
+		(*work_done)++;
+
+		if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+			hdr_info =
+			    le16_to_cpu(rx_desc->wb.lower.lo_dword.hdr_info);
+			len =
+			    ((hdr_info & IXGBE_RXDADV_HDRBUFLEN_MASK) >>
+			     IXGBE_RXDADV_HDRBUFLEN_SHIFT);
+			if (hdr_info & IXGBE_RXDADV_SPH)
+				adapter->rx_hdr_split++;
+			if (len > IXGBE_RX_HDR_SIZE)
+				len = IXGBE_RX_HDR_SIZE;
+			upper_len = le16_to_cpu(rx_desc->wb.upper.length);
+		} else
+			len = le16_to_cpu(rx_desc->wb.upper.length);
+
+		cleaned = true;
+		skb = rx_buffer_info->skb;
+		prefetch(skb->data - NET_IP_ALIGN);
+		rx_buffer_info->skb = NULL;
+
+		if (len && !skb_shinfo(skb)->nr_frags) {
+			pci_unmap_single(pdev, rx_buffer_info->dma,
+					 adapter->rx_buf_len + NET_IP_ALIGN,
+					 PCI_DMA_FROMDEVICE);
+			skb_put(skb, len);
+		}
+
+		if (upper_len) {
+			pci_unmap_page(pdev, rx_buffer_info->page_dma,
+				       PAGE_SIZE, PCI_DMA_FROMDEVICE);
+			rx_buffer_info->page_dma = 0;
+			skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
+					   rx_buffer_info->page, 0, upper_len);
+			rx_buffer_info->page = NULL;
+
+			skb->len += upper_len;
+			skb->data_len += upper_len;
+			skb->truesize += upper_len;
+		}
+
+		i++;
+		if (i == rx_ring->count)
+			i = 0;
+		next_buffer = &rx_ring->rx_buffer_info[i];
+
+		next_rxd = IXGBE_RX_DESC_ADV(*rx_ring, i);
+		prefetch(next_rxd);
+
+		cleaned_count++;
+		if (staterr & IXGBE_RXD_STAT_EOP) {
+			rx_ring->stats.packets++;
+			rx_ring->stats.bytes += skb->len;
+		} else {
+			rx_buffer_info->skb = next_buffer->skb;
+			rx_buffer_info->dma = next_buffer->dma;
+			next_buffer->skb = skb;
+			adapter->non_eop_descs++;
+			goto next_desc;
+		}
+
+		if (staterr & IXGBE_RXDADV_ERR_FRAME_ERR_MASK) {
+			dev_kfree_skb_irq(skb);
+			goto next_desc;
+		}
+
+		ixgbe_rx_checksum(adapter, staterr, skb);
+		skb->protocol = eth_type_trans(skb, netdev);
+		ixgbe_receive_skb(adapter, skb, is_vlan, vlan_tag);
+		netdev->last_rx = jiffies;
+
+next_desc:
+		rx_desc->wb.upper.status_error = 0;
+
+		/* return some buffers to hardware, one at a time is too slow */
+		if (cleaned_count >= IXGBE_RX_BUFFER_WRITE) {
+			ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
+			cleaned_count = 0;
+		}
+
+		/* use prefetched values */
+		rx_desc = next_rxd;
+		rx_buffer_info = next_buffer;
+
+		staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
+		is_vlan = (staterr & IXGBE_RXD_STAT_VP);
+		vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan);
+	}
+
+	rx_ring->next_to_clean = i;
+	cleaned_count = IXGBE_DESC_UNUSED(rx_ring);
+
+	if (cleaned_count)
+		ixgbe_alloc_rx_buffers(adapter, rx_ring, cleaned_count);
+
+	return cleaned;
+}
+
+#define IXGBE_MAX_INTR 10
+/**
+ * ixgbe_configure_msix - Configure MSI-X hardware
+ * @adapter: board private structure
+ *
+ * ixgbe_configure_msix sets up the hardware to properly generate MSI-X
+ * interrupts.
+ **/
+static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
+{
+	int i, vector = 0;
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(i),
+			       IXGBE_MSIX_VECTOR(vector));
+		writel(EITR_INTS_PER_SEC_TO_REG(adapter->tx_eitr),
+		       adapter->hw.hw_addr + adapter->tx_ring[i].itr_register);
+		vector++;
+	}
+
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(i),
+			       IXGBE_MSIX_VECTOR(vector));
+		writel(EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr),
+		       adapter->hw.hw_addr + adapter->rx_ring[i].itr_register);
+		vector++;
+	}
+
+	vector = adapter->num_tx_queues + adapter->num_rx_queues;
+	ixgbe_set_ivar(adapter, IXGBE_IVAR_OTHER_CAUSES_INDEX,
+		       IXGBE_MSIX_VECTOR(vector));
+	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(vector), 1950);
+}
+
+static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
+
+	if (eicr & IXGBE_EICR_LSC) {
+		adapter->lsc_int++;
+		if (!test_bit(__IXGBE_DOWN, &adapter->state))
+			mod_timer(&adapter->watchdog_timer, jiffies);
+	}
+	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t ixgbe_msix_clean_tx(int irq, void *data)
+{
+	struct ixgbe_ring *txr = data;
+	struct ixgbe_adapter *adapter = txr->adapter;
+
+	ixgbe_clean_tx_irq(adapter, txr);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data)
+{
+	struct ixgbe_ring *rxr = data;
+	struct ixgbe_adapter *adapter = rxr->adapter;
+
+	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rxr->eims_value);
+	netif_rx_schedule(adapter->netdev, &adapter->napi);
+	return IRQ_HANDLED;
+}
+
+static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget)
+{
+	struct ixgbe_adapter *adapter = container_of(napi,
+					struct ixgbe_adapter, napi);
+	struct net_device *netdev = adapter->netdev;
+	int work_done = 0;
+	struct ixgbe_ring *rxr = adapter->rx_ring;
+
+	/* Keep link state information with original netdev */
+	if (!netif_carrier_ok(netdev))
+		goto quit_polling;
+
+	ixgbe_clean_rx_irq(adapter, rxr, &work_done, budget);
+
+	/* If no Tx and not enough Rx work done, exit the polling mode */
+	if ((work_done < budget) || !netif_running(netdev)) {
+quit_polling:
+		netif_rx_complete(netdev, napi);
+		if (!test_bit(__IXGBE_DOWN, &adapter->state))
+			IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS,
+					rxr->eims_value);
+	}
+
+	return work_done;
+}
+
+/**
+ * ixgbe_setup_msix - Initialize MSI-X interrupts
+ *
+ * ixgbe_setup_msix allocates MSI-X vectors and requests
+ * interrutps from the kernel.
+ **/
+static int ixgbe_setup_msix(struct ixgbe_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	int i, int_vector = 0, err = 0;
+	int max_msix_count;
+
+	/* +1 for the LSC interrupt */
+	max_msix_count = adapter->num_rx_queues + adapter->num_tx_queues + 1;
+	adapter->msix_entries = kcalloc(max_msix_count,
+					sizeof(struct msix_entry), GFP_KERNEL);
+	if (!adapter->msix_entries)
+		return -ENOMEM;
+
+	for (i = 0; i < max_msix_count; i++)
+		adapter->msix_entries[i].entry = i;
+
+	err = pci_enable_msix(adapter->pdev, adapter->msix_entries,
+			      max_msix_count);
+	if (err)
+		goto out;
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		sprintf(adapter->tx_ring[i].name, "%s-tx%d", netdev->name, i);
+		err = request_irq(adapter->msix_entries[int_vector].vector,
+				  &ixgbe_msix_clean_tx,
+				  0,
+				  adapter->tx_ring[i].name,
+				  &(adapter->tx_ring[i]));
+		if (err) {
+			DPRINTK(PROBE, ERR,
+				"request_irq failed for MSIX interrupt "
+				"Error: %d\n", err);
+			goto release_irqs;
+		}
+		adapter->tx_ring[i].eims_value =
+		    (1 << IXGBE_MSIX_VECTOR(int_vector));
+		adapter->tx_ring[i].itr_register = IXGBE_EITR(int_vector);
+		int_vector++;
+	}
+
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		if (strlen(netdev->name) < (IFNAMSIZ - 5))
+			sprintf(adapter->rx_ring[i].name,
+				"%s-rx%d", netdev->name, i);
+		else
+			memcpy(adapter->rx_ring[i].name,
+			       netdev->name, IFNAMSIZ);
+		err = request_irq(adapter->msix_entries[int_vector].vector,
+				  &ixgbe_msix_clean_rx, 0,
+				  adapter->rx_ring[i].name,
+				  &(adapter->rx_ring[i]));
+		if (err) {
+			DPRINTK(PROBE, ERR,
+				"request_irq failed for MSIX interrupt "
+				"Error: %d\n", err);
+			goto release_irqs;
+		}
+
+		adapter->rx_ring[i].eims_value =
+		    (1 << IXGBE_MSIX_VECTOR(int_vector));
+		adapter->rx_ring[i].itr_register = IXGBE_EITR(int_vector);
+		int_vector++;
+	}
+
+	sprintf(adapter->lsc_name, "%s-lsc", netdev->name);
+	err = request_irq(adapter->msix_entries[int_vector].vector,
+			  &ixgbe_msix_lsc, 0, adapter->lsc_name, netdev);
+	if (err) {
+		DPRINTK(PROBE, ERR,
+			"request_irq for msix_lsc failed: %d\n", err);
+		goto release_irqs;
+	}
+
+	/* FIXME: implement netif_napi_remove() instead */
+	adapter->napi.poll = ixgbe_clean_rxonly;
+	adapter->flags |= IXGBE_FLAG_MSIX_ENABLED;
+	return 0;
+
+release_irqs:
+	int_vector--;
+	for (; int_vector >= adapter->num_tx_queues; int_vector--)
+		free_irq(adapter->msix_entries[int_vector].vector,
+			 &(adapter->rx_ring[int_vector -
+					    adapter->num_tx_queues]));
+
+	for (; int_vector >= 0; int_vector--)
+		free_irq(adapter->msix_entries[int_vector].vector,
+			 &(adapter->tx_ring[int_vector]));
+out:
+	kfree(adapter->msix_entries);
+	adapter->msix_entries = NULL;
+	adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
+	return err;
+}
+
+/**
+ * ixgbe_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ * @pt_regs: CPU registers structure
+ **/
+static irqreturn_t ixgbe_intr(int irq, void *data)
+{
+	struct net_device *netdev = data;
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 eicr;
+
+	eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
+
+	if (!eicr)
+		return IRQ_NONE;	/* Not our interrupt */
+
+	if (eicr & IXGBE_EICR_LSC) {
+		adapter->lsc_int++;
+		if (!test_bit(__IXGBE_DOWN, &adapter->state))
+			mod_timer(&adapter->watchdog_timer, jiffies);
+	}
+	if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
+		/* Disable interrupts and register for poll. The flush of the
+		 * posted write is intentionally left out. */
+		atomic_inc(&adapter->irq_sem);
+		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
+		__netif_rx_schedule(netdev, &adapter->napi);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * ixgbe_request_irq - initialize interrupts
+ * @adapter: board private structure
+ *
+ * Attempts to configure interrupts using the best available
+ * capabilities of the hardware and kernel.
+ **/
+static int ixgbe_request_irq(struct ixgbe_adapter *adapter, u32 *num_rx_queues)
+{
+	struct net_device *netdev = adapter->netdev;
+	int flags, err;
+	irqreturn_t(*handler) (int, void *) = &ixgbe_intr;
+
+	flags = IRQF_SHARED;
+
+	err = ixgbe_setup_msix(adapter);
+	if (!err)
+		goto request_done;
+
+	/*
+	 * if we can't do MSI-X, fall through and try MSI
+	 * No need to reallocate memory since we're decreasing the number of
+	 * queues. We just won't use the other ones, also it is freed correctly
+	 * on ixgbe_remove.
+	 */
+	*num_rx_queues = 1;
+
+	/* do MSI */
+	err = pci_enable_msi(adapter->pdev);
+	if (!err) {
+		adapter->flags |= IXGBE_FLAG_MSI_ENABLED;
+		flags &= ~IRQF_SHARED;
+		handler = &ixgbe_intr;
+	}
+
+	err = request_irq(adapter->pdev->irq, handler, flags,
+			  netdev->name, netdev);
+	if (err)
+		DPRINTK(PROBE, ERR, "request_irq failed, Error %d\n", err);
+
+request_done:
+	return err;
+}
+
+static void ixgbe_free_irq(struct ixgbe_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+
+	if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+		int i;
+
+		for (i = 0; i < adapter->num_tx_queues; i++)
+			free_irq(adapter->msix_entries[i].vector,
+				 &(adapter->tx_ring[i]));
+		for (i = 0; i < adapter->num_rx_queues; i++)
+			free_irq(adapter->msix_entries[i +
+						adapter->num_tx_queues].vector,
+				&(adapter->rx_ring[i]));
+		i = adapter->num_rx_queues + adapter->num_tx_queues;
+		free_irq(adapter->msix_entries[i].vector, netdev);
+		pci_disable_msix(adapter->pdev);
+		kfree(adapter->msix_entries);
+		adapter->msix_entries = NULL;
+		adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
+		return;
+	}
+
+	free_irq(adapter->pdev->irq, netdev);
+	if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) {
+		pci_disable_msi(adapter->pdev);
+		adapter->flags &= ~IXGBE_FLAG_MSI_ENABLED;
+	}
+}
+
+/**
+ * ixgbe_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
+{
+	atomic_inc(&adapter->irq_sem);
+	IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
+	IXGBE_WRITE_FLUSH(&adapter->hw);
+	synchronize_irq(adapter->pdev->irq);
+}
+
+/**
+ * ixgbe_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter)
+{
+	if (atomic_dec_and_test(&adapter->irq_sem)) {
+		if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
+			IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIAC,
+					(IXGBE_EIMS_ENABLE_MASK &
+					 ~(IXGBE_EIMS_OTHER | IXGBE_EIMS_LSC)));
+		IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS,
+				IXGBE_EIMS_ENABLE_MASK);
+		IXGBE_WRITE_FLUSH(&adapter->hw);
+	}
+}
+
+/**
+ * ixgbe_configure_msi_and_legacy - Initialize PIN (INTA...) and MSI interrupts
+ *
+ **/
+static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter)
+{
+	int i;
+	struct ixgbe_hw *hw = &adapter->hw;
+
+	if (adapter->rx_eitr)
+		IXGBE_WRITE_REG(hw, IXGBE_EITR(0),
+				EITR_INTS_PER_SEC_TO_REG(adapter->rx_eitr));
+
+	/* for re-triggering the interrupt in non-NAPI mode */
+	adapter->rx_ring[0].eims_value = (1 << IXGBE_MSIX_VECTOR(0));
+	adapter->tx_ring[0].eims_value = (1 << IXGBE_MSIX_VECTOR(0));
+
+	ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(0), 0);
+	for (i = 0; i < adapter->num_tx_queues; i++)
+		ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(i), i);
+}
+
+/**
+ * ixgbe_configure_tx - Configure 8254x Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+static void ixgbe_configure_tx(struct ixgbe_adapter *adapter)
+{
+	u64 tdba;
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 i, tdlen;
+
+	/* Setup the HW Tx Head and Tail descriptor pointers */
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		tdba = adapter->tx_ring[i].dma;
+		tdlen = adapter->tx_ring[i].count *
+		    sizeof(union ixgbe_adv_tx_desc);
+		IXGBE_WRITE_REG(hw, IXGBE_TDBAL(i), (tdba & DMA_32BIT_MASK));
+		IXGBE_WRITE_REG(hw, IXGBE_TDBAH(i), (tdba >> 32));
+		IXGBE_WRITE_REG(hw, IXGBE_TDLEN(i), tdlen);
+		IXGBE_WRITE_REG(hw, IXGBE_TDH(i), 0);
+		IXGBE_WRITE_REG(hw, IXGBE_TDT(i), 0);
+		adapter->tx_ring[i].head = IXGBE_TDH(i);
+		adapter->tx_ring[i].tail = IXGBE_TDT(i);
+	}
+
+	IXGBE_WRITE_REG(hw, IXGBE_TIPG, IXGBE_TIPG_FIBER_DEFAULT);
+}
+
+#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \
+			(((S) & (PAGE_SIZE - 1)) ? 1 : 0))
+
+#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT			2
+/**
+ * ixgbe_configure_rx - Configure 8254x Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
+{
+	u64 rdba;
+	struct ixgbe_hw *hw = &adapter->hw;
+	struct net_device *netdev = adapter->netdev;
+	int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+	u32 rdlen, rxctrl, rxcsum;
+	u32 random[10];
+	u32 reta, mrqc;
+	int i;
+	u32 fctrl, hlreg0;
+	u32 srrctl;
+	u32 pages;
+
+	/* Decide whether to use packet split mode or not */
+	if (netdev->mtu > ETH_DATA_LEN)
+		adapter->flags |= IXGBE_FLAG_RX_PS_ENABLED;
+	else
+		adapter->flags &= ~IXGBE_FLAG_RX_PS_ENABLED;
+
+	/* Set the RX buffer length according to the mode */
+	if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+		adapter->rx_buf_len = IXGBE_RX_HDR_SIZE;
+	} else {
+		if (netdev->mtu <= ETH_DATA_LEN)
+			adapter->rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE;
+		else
+			adapter->rx_buf_len = ALIGN(max_frame, 1024);
+	}
+
+	fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
+	fctrl |= IXGBE_FCTRL_BAM;
+	IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl);
+
+	hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
+	if (adapter->netdev->mtu <= ETH_DATA_LEN)
+		hlreg0 &= ~IXGBE_HLREG0_JUMBOEN;
+	else
+		hlreg0 |= IXGBE_HLREG0_JUMBOEN;
+	IXGBE_WRITE_REG(hw, IXGBE_HLREG0, hlreg0);
+
+	pages = PAGE_USE_COUNT(adapter->netdev->mtu);
+
+	srrctl = IXGBE_READ_REG(&adapter->hw, IXGBE_SRRCTL(0));
+	srrctl &= ~IXGBE_SRRCTL_BSIZEHDR_MASK;
+	srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK;
+
+	if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
+		srrctl |= PAGE_SIZE >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+		srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
+		srrctl |= ((IXGBE_RX_HDR_SIZE <<
+			    IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) &
+			   IXGBE_SRRCTL_BSIZEHDR_MASK);
+	} else {
+		srrctl |= IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF;
+
+		if (adapter->rx_buf_len == MAXIMUM_ETHERNET_VLAN_SIZE)
+			srrctl |=
+			     IXGBE_RXBUFFER_2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+		else
+			srrctl |=
+			     adapter->rx_buf_len >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+	}
+	IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(0), srrctl);
+
+	rdlen = adapter->rx_ring[0].count * sizeof(union ixgbe_adv_rx_desc);
+	/* disable receives while setting up the descriptors */
+	rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+	IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN);
+
+	/* Setup the HW Rx Head and Tail Descriptor Pointers and
+	 * the Base and Length of the Rx Descriptor Ring */
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		rdba = adapter->rx_ring[i].dma;
+		IXGBE_WRITE_REG(hw, IXGBE_RDBAL(i), (rdba & DMA_32BIT_MASK));
+		IXGBE_WRITE_REG(hw, IXGBE_RDBAH(i), (rdba >> 32));
+		IXGBE_WRITE_REG(hw, IXGBE_RDLEN(i), rdlen);
+		IXGBE_WRITE_REG(hw, IXGBE_RDH(i), 0);
+		IXGBE_WRITE_REG(hw, IXGBE_RDT(i), 0);
+		adapter->rx_ring[i].head = IXGBE_RDH(i);
+		adapter->rx_ring[i].tail = IXGBE_RDT(i);
+	}
+
+	if (adapter->num_rx_queues > 1) {
+		/* Random 40bytes used as random key in RSS hash function */
+		get_random_bytes(&random[0], 40);
+
+		switch (adapter->num_rx_queues) {
+		case 8:
+		case 4:
+			/* Bits [3:0] in each byte refers the Rx queue no */
+			reta = 0x00010203;
+			break;
+		case 2:
+			reta = 0x00010001;
+			break;
+		default:
+			reta = 0x00000000;
+			break;
+		}
+
+		/* Fill out redirection table */
+		for (i = 0; i < 32; i++) {
+			IXGBE_WRITE_REG_ARRAY(hw, IXGBE_RETA(0), i, reta);
+			if (adapter->num_rx_queues > 4) {
+				i++;
+				IXGBE_WRITE_REG_ARRAY(hw, IXGBE_RETA(0), i,
+						      0x04050607);
+			}
+		}
+
+		/* Fill out hash function seeds */
+		for (i = 0; i < 10; i++)
+			IXGBE_WRITE_REG_ARRAY(hw, IXGBE_RSSRK(0), i, random[i]);
+
+		mrqc = IXGBE_MRQC_RSSEN
+		    /* Perform hash on these packet types */
+		    | IXGBE_MRQC_RSS_FIELD_IPV4
+		    | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
+		    | IXGBE_MRQC_RSS_FIELD_IPV4_UDP
+		    | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP
+		    | IXGBE_MRQC_RSS_FIELD_IPV6_EX
+		    | IXGBE_MRQC_RSS_FIELD_IPV6
+		    | IXGBE_MRQC_RSS_FIELD_IPV6_TCP
+		    | IXGBE_MRQC_RSS_FIELD_IPV6_UDP
+		    | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
+		IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
+
+		/* Multiqueue and packet checksumming are mutually exclusive. */
+		rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
+		rxcsum |= IXGBE_RXCSUM_PCSD;
+		IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
+	} else {
+		/* Enable Receive Checksum Offload for TCP and UDP */
+		rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
+		if (adapter->flags & IXGBE_FLAG_RX_CSUM_ENABLED) {
+			/* Enable IPv4 payload checksum for UDP fragments
+			 * Must be used in conjunction with packet-split. */
+			rxcsum |= IXGBE_RXCSUM_IPPCSE;
+		} else {
+			/* don't need to clear IPPCSE as it defaults to 0 */
+		}
+		IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
+	}
+	/* Enable Receives */
+	IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl);
+	rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+}
+
+static void ixgbe_vlan_rx_register(struct net_device *netdev,
+				   struct vlan_group *grp)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	u32 ctrl;
+
+	ixgbe_irq_disable(adapter);
+	adapter->vlgrp = grp;
+
+	if (grp) {
+		/* enable VLAN tag insert/strip */
+		ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL);
+		ctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE;
+		ctrl &= ~IXGBE_VLNCTRL_CFIEN;
+		IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl);
+	}
+
+	ixgbe_irq_enable(adapter);
+}
+
+static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	/* add VID to filter table */
+	ixgbe_set_vfta(&adapter->hw, vid, 0, true);
+}
+
+static void ixgbe_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	ixgbe_irq_disable(adapter);
+	vlan_group_set_device(adapter->vlgrp, vid, NULL);
+	ixgbe_irq_enable(adapter);
+
+	/* remove VID from filter table */
+	ixgbe_set_vfta(&adapter->hw, vid, 0, false);
+}
+
+static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter)
+{
+	ixgbe_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+
+	if (adapter->vlgrp) {
+		u16 vid;
+		for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+			if (!vlan_group_get_device(adapter->vlgrp, vid))
+				continue;
+			ixgbe_vlan_rx_add_vid(adapter->netdev, vid);
+		}
+	}
+}
+
+/**
+ * ixgbe_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi entry point is called whenever the multicast address
+ * list or the network interface flags are updated.  This routine is
+ * responsible for configuring the hardware for proper multicast,
+ * promiscuous mode, and all-multi behavior.
+ **/
+static void ixgbe_set_multi(struct net_device *netdev)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	struct ixgbe_hw *hw = &adapter->hw;
+	struct dev_mc_list *mc_ptr;
+	u8 *mta_list;
+	u32 fctrl;
+	int i;
+
+	/* Check for Promiscuous and All Multicast modes */
+
+	fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+
+	if (netdev->flags & IFF_PROMISC) {
+		fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+	} else if (netdev->flags & IFF_ALLMULTI) {
+		fctrl |= IXGBE_FCTRL_MPE;
+		fctrl &= ~IXGBE_FCTRL_UPE;
+	} else {
+		fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+	}
+
+	IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
+
+	if (netdev->mc_count) {
+		mta_list = kcalloc(netdev->mc_count, ETH_ALEN, GFP_ATOMIC);
+		if (!mta_list)
+			return;
+
+		/* Shared function expects packed array of only addresses. */
+		mc_ptr = netdev->mc_list;
+
+		for (i = 0; i < netdev->mc_count; i++) {
+			if (!mc_ptr)
+				break;
+			memcpy(mta_list + (i * ETH_ALEN), mc_ptr->dmi_addr,
+			       ETH_ALEN);
+			mc_ptr = mc_ptr->next;
+		}
+
+		ixgbe_update_mc_addr_list(hw, mta_list, i, 0);
+		kfree(mta_list);
+	} else {
+		ixgbe_update_mc_addr_list(hw, NULL, 0, 0);
+	}
+
+}
+
+static void ixgbe_configure(struct ixgbe_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	int i;
+
+	ixgbe_set_multi(netdev);
+
+	ixgbe_restore_vlan(adapter);
+
+	ixgbe_configure_tx(adapter);
+	ixgbe_configure_rx(adapter);
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		ixgbe_alloc_rx_buffers(adapter, &adapter->rx_ring[i],
+					   (adapter->rx_ring[i].count - 1));
+}
+
+static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	int i;
+	u32 gpie = 0;
+	struct ixgbe_hw *hw = &adapter->hw;
+	u32 txdctl, rxdctl, mhadd;
+	int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
+
+	if (adapter->flags & (IXGBE_FLAG_MSIX_ENABLED |
+			      IXGBE_FLAG_MSI_ENABLED)) {
+		if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+			gpie = (IXGBE_GPIE_MSIX_MODE | IXGBE_GPIE_EIAME |
+				IXGBE_GPIE_PBA_SUPPORT | IXGBE_GPIE_OCD);
+		} else {
+			/* MSI only */
+			gpie = (IXGBE_GPIE_EIAME |
+				IXGBE_GPIE_PBA_SUPPORT);
+		}
+		IXGBE_WRITE_REG(&adapter->hw, IXGBE_GPIE, gpie);
+		gpie = IXGBE_READ_REG(&adapter->hw, IXGBE_GPIE);
+	}
+
+	mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
+
+	if (max_frame != (mhadd >> IXGBE_MHADD_MFS_SHIFT)) {
+		mhadd &= ~IXGBE_MHADD_MFS_MASK;
+		mhadd |= max_frame << IXGBE_MHADD_MFS_SHIFT;
+
+		IXGBE_WRITE_REG(hw, IXGBE_MHADD, mhadd);
+	}
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		txdctl = IXGBE_READ_REG(&adapter->hw, IXGBE_TXDCTL(i));
+		txdctl |= IXGBE_TXDCTL_ENABLE;
+		IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(i), txdctl);
+	}
+
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		rxdctl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXDCTL(i));
+		rxdctl |= IXGBE_RXDCTL_ENABLE;
+		IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(i), rxdctl);
+	}
+	/* enable all receives */
+	rxdctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
+	rxdctl |= (IXGBE_RXCTRL_DMBYPS | IXGBE_RXCTRL_RXEN);
+	IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxdctl);
+
+	if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
+		ixgbe_configure_msix(adapter);
+	else
+		ixgbe_configure_msi_and_legacy(adapter);
+
+	clear_bit(__IXGBE_DOWN, &adapter->state);
+	napi_enable(&adapter->napi);
+	ixgbe_irq_enable(adapter);
+
+	/* bring the link up in the watchdog, this could race with our first
+	 * link up interrupt but shouldn't be a problem */
+	mod_timer(&adapter->watchdog_timer, jiffies);
+	return 0;
+}
+
+int ixgbe_up(struct ixgbe_adapter *adapter)
+{
+	/* hardware has been reset, we need to reload some things */
+	ixgbe_configure(adapter);
+
+	return ixgbe_up_complete(adapter);
+}
+
+void ixgbe_reset(struct ixgbe_adapter *adapter)
+{
+	if (ixgbe_init_hw(&adapter->hw))
+		DPRINTK(PROBE, ERR, "Hardware Error\n");
+
+	/* reprogram the RAR[0] in case user changed it. */
+	ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV);
+
+}
+
+#ifdef CONFIG_PM
+static int ixgbe_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	u32 err, num_rx_queues = adapter->num_rx_queues;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR "ixgbe: Cannot enable PCI device from " \
+				"suspend\n");
+		return err;
+	}
+	pci_set_master(pdev);
+
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_enable_wake(pdev, PCI_D3cold, 0);
+
+	if (netif_running(netdev)) {
+		err = ixgbe_request_irq(adapter, &num_rx_queues);
+		if (err)
+			return err;
+	}
+
+	ixgbe_reset(adapter);
+
+	if (netif_running(netdev))
+		ixgbe_up(adapter);
+
+	netif_device_attach(netdev);
+
+	return 0;
+}
+#endif
+
+/**
+ * ixgbe_clean_rx_ring - Free Rx Buffers per Queue
+ * @adapter: board private structure
+ * @rx_ring: ring to free buffers from
+ **/
+static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
+				struct ixgbe_ring *rx_ring)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	unsigned long size;
+	unsigned int i;
+
+	/* Free all the Rx ring sk_buffs */
+
+	for (i = 0; i < rx_ring->count; i++) {
+		struct ixgbe_rx_buffer *rx_buffer_info;
+
+		rx_buffer_info = &rx_ring->rx_buffer_info[i];
+		if (rx_buffer_info->dma) {
+			pci_unmap_single(pdev, rx_buffer_info->dma,
+					 adapter->rx_buf_len,
+					 PCI_DMA_FROMDEVICE);
+			rx_buffer_info->dma = 0;
+		}
+		if (rx_buffer_info->skb) {
+			dev_kfree_skb(rx_buffer_info->skb);
+			rx_buffer_info->skb = NULL;
+		}
+		if (!rx_buffer_info->page)
+			continue;
+		pci_unmap_page(pdev, rx_buffer_info->page_dma, PAGE_SIZE,
+			       PCI_DMA_FROMDEVICE);
+		rx_buffer_info->page_dma = 0;
+
+		put_page(rx_buffer_info->page);
+		rx_buffer_info->page = NULL;
+	}
+
+	size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count;
+	memset(rx_ring->rx_buffer_info, 0, size);
+
+	/* Zero out the descriptor ring */
+	memset(rx_ring->desc, 0, rx_ring->size);
+
+	rx_ring->next_to_clean = 0;
+	rx_ring->next_to_use = 0;
+
+	writel(0, adapter->hw.hw_addr + rx_ring->head);
+	writel(0, adapter->hw.hw_addr + rx_ring->tail);
+}
+
+/**
+ * ixgbe_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ * @tx_ring: ring to be cleaned
+ **/
+static void ixgbe_clean_tx_ring(struct ixgbe_adapter *adapter,
+				struct ixgbe_ring *tx_ring)
+{
+	struct ixgbe_tx_buffer *tx_buffer_info;
+	unsigned long size;
+	unsigned int i;
+
+	/* Free all the Tx ring sk_buffs */
+
+	for (i = 0; i < tx_ring->count; i++) {
+		tx_buffer_info = &tx_ring->tx_buffer_info[i];
+		ixgbe_unmap_and_free_tx_resource(adapter, tx_buffer_info);
+	}
+
+	size = sizeof(struct ixgbe_tx_buffer) * tx_ring->count;
+	memset(tx_ring->tx_buffer_info, 0, size);
+
+	/* Zero out the descriptor ring */
+	memset(tx_ring->desc, 0, tx_ring->size);
+
+	tx_ring->next_to_use = 0;
+	tx_ring->next_to_clean = 0;
+
+	writel(0, adapter->hw.hw_addr + tx_ring->head);
+	writel(0, adapter->hw.hw_addr + tx_ring->tail);
+}
+
+/**
+ * ixgbe_clean_all_tx_rings - Free Tx Buffers for all queues
+ * @adapter: board private structure
+ **/
+static void ixgbe_clean_all_tx_rings(struct ixgbe_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_tx_queues; i++)
+		ixgbe_clean_tx_ring(adapter, &adapter->tx_ring[i]);
+}
+
+/**
+ * ixgbe_clean_all_rx_rings - Free Rx Buffers for all queues
+ * @adapter: board private structure
+ **/
+static void ixgbe_clean_all_rx_rings(struct ixgbe_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		ixgbe_clean_rx_ring(adapter, &adapter->rx_ring[i]);
+}
+
+void ixgbe_down(struct ixgbe_adapter *adapter)
+{
+	struct net_device *netdev = adapter->netdev;
+	u32 rxctrl;
+
+	/* signal that we are down to the interrupt handler */
+	set_bit(__IXGBE_DOWN, &adapter->state);
+
+	/* disable receives */
+	rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXCTRL);
+	IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL,
+			rxctrl & ~IXGBE_RXCTRL_RXEN);
+
+	netif_tx_disable(netdev);
+
+	/* disable transmits in the hardware */
+
+	/* flush both disables */
+	IXGBE_WRITE_FLUSH(&adapter->hw);
+	msleep(10);
+
+	ixgbe_irq_disable(adapter);
+
+	napi_disable(&adapter->napi);
+	del_timer_sync(&adapter->watchdog_timer);
+
+	netif_carrier_off(netdev);
+	netif_stop_queue(netdev);
+
+	ixgbe_reset(adapter);
+	ixgbe_clean_all_tx_rings(adapter);
+	ixgbe_clean_all_rx_rings(adapter);
+
+}
+
+static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+#ifdef CONFIG_PM
+	int retval = 0;
+#endif
+
+	netif_device_detach(netdev);
+
+	if (netif_running(netdev)) {
+		ixgbe_down(adapter);
+		ixgbe_free_irq(adapter);
+	}
+
+#ifdef CONFIG_PM
+	retval = pci_save_state(pdev);
+	if (retval)
+		return retval;
+#endif
+
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_enable_wake(pdev, PCI_D3cold, 0);
+
+	pci_disable_device(pdev);
+
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	return 0;
+}
+
+static void ixgbe_shutdown(struct pci_dev *pdev)
+{
+	ixgbe_suspend(pdev, PMSG_SUSPEND);
+}
+
+/**
+ * ixgbe_clean - NAPI Rx polling callback
+ * @adapter: board private structure
+ **/
+static int ixgbe_clean(struct napi_struct *napi, int budget)
+{
+	struct ixgbe_adapter *adapter = container_of(napi,
+					struct ixgbe_adapter, napi);
+	struct net_device *netdev = adapter->netdev;
+	int tx_cleaned = 0, work_done = 0;
+
+	/* Keep link state information with original netdev */
+	if (!netif_carrier_ok(adapter->netdev))
+		goto quit_polling;
+
+	/* In non-MSIX case, there is no multi-Tx/Rx queue */
+	tx_cleaned = ixgbe_clean_tx_irq(adapter, adapter->tx_ring);
+	ixgbe_clean_rx_irq(adapter, &adapter->rx_ring[0], &work_done,
+			   budget);
+
+	/* If no Tx and not enough Rx work done, exit the polling mode */
+	if ((!tx_cleaned && (work_done < budget)) ||
+	    !netif_running(adapter->netdev)) {
+quit_polling:
+		netif_rx_complete(netdev, napi);
+		ixgbe_irq_enable(adapter);
+	}
+
+	return work_done;
+}
+
+/**
+ * ixgbe_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ **/
+static void ixgbe_tx_timeout(struct net_device *netdev)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	/* Do the reset outside of interrupt context */
+	schedule_work(&adapter->reset_task);
+}
+
+static void ixgbe_reset_task(struct work_struct *work)
+{
+	struct ixgbe_adapter *adapter;
+	adapter = container_of(work, struct ixgbe_adapter, reset_task);
+
+	adapter->tx_timeout_count++;
+
+	ixgbe_down(adapter);
+	ixgbe_up(adapter);
+}
+
+/**
+ * ixgbe_alloc_queues - Allocate memory for all rings
+ * @adapter: board private structure to initialize
+ *
+ * We allocate one ring per queue at run-time since we don't know the
+ * number of queues at compile-time.  The polling_netdev array is
+ * intended for Multiqueue, but should work fine with a single queue.
+ **/
+static int __devinit ixgbe_alloc_queues(struct ixgbe_adapter *adapter)
+{
+	int i;
+
+	adapter->tx_ring = kcalloc(adapter->num_tx_queues,
+				   sizeof(struct ixgbe_ring), GFP_KERNEL);
+	if (!adapter->tx_ring)
+		return -ENOMEM;
+
+	for (i = 0; i < adapter->num_tx_queues; i++)
+		adapter->tx_ring[i].count = IXGBE_DEFAULT_TXD;
+
+	adapter->rx_ring = kcalloc(adapter->num_rx_queues,
+				   sizeof(struct ixgbe_ring), GFP_KERNEL);
+	if (!adapter->rx_ring) {
+		kfree(adapter->tx_ring);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		adapter->rx_ring[i].adapter = adapter;
+		adapter->rx_ring[i].itr_register = IXGBE_EITR(i);
+		adapter->rx_ring[i].count = IXGBE_DEFAULT_RXD;
+	}
+
+	return 0;
+}
+
+/**
+ * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * ixgbe_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+	struct pci_dev *pdev = adapter->pdev;
+
+	/* default flow control settings */
+	hw->fc.original_type = ixgbe_fc_full;
+	hw->fc.type = ixgbe_fc_full;
+
+	hw->mac.link_mode_select = IXGBE_AUTOC_LMS_10G_LINK_NO_AN;
+	if (hw->mac.ops.reset(hw)) {
+		dev_err(&pdev->dev, "HW Init failed\n");
+		return -EIO;
+	}
+	if (hw->phy.ops.setup_speed(hw, IXGBE_LINK_SPEED_10GB_FULL, true,
+				   false)) {
+		dev_err(&pdev->dev, "Link Speed setup failed\n");
+		return -EIO;
+	}
+
+	/* initialize eeprom parameters */
+	if (ixgbe_init_eeprom(hw)) {
+		dev_err(&pdev->dev, "EEPROM initialization failed\n");
+		return -EIO;
+	}
+
+	/* Set the default values */
+	adapter->num_rx_queues = IXGBE_DEFAULT_RXQ;
+	adapter->num_tx_queues = 1;
+	adapter->flags |= IXGBE_FLAG_RX_CSUM_ENABLED;
+
+	if (ixgbe_alloc_queues(adapter)) {
+		dev_err(&pdev->dev, "Unable to allocate memory for queues\n");
+		return -ENOMEM;
+	}
+
+	atomic_set(&adapter->irq_sem, 1);
+	set_bit(__IXGBE_DOWN, &adapter->state);
+
+	return 0;
+}
+
+/**
+ * ixgbe_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @adapter: board private structure
+ * @txdr:    tx descriptor ring (for a specific queue) to setup
+ *
+ * Return 0 on success, negative on failure
+ **/
+int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
+			     struct ixgbe_ring *txdr)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	int size;
+
+	size = sizeof(struct ixgbe_tx_buffer) * txdr->count;
+	txdr->tx_buffer_info = vmalloc(size);
+	if (!txdr->tx_buffer_info) {
+		DPRINTK(PROBE, ERR,
+		"Unable to allocate memory for the transmit descriptor ring\n");
+		return -ENOMEM;
+	}
+	memset(txdr->tx_buffer_info, 0, size);
+
+	/* round up to nearest 4K */
+	txdr->size = txdr->count * sizeof(union ixgbe_adv_tx_desc);
+	txdr->size = ALIGN(txdr->size, 4096);
+
+	txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
+	if (!txdr->desc) {
+		vfree(txdr->tx_buffer_info);
+		DPRINTK(PROBE, ERR,
+			"Memory allocation failed for the tx desc ring\n");
+		return -ENOMEM;
+	}
+
+	txdr->adapter = adapter;
+	txdr->next_to_use = 0;
+	txdr->next_to_clean = 0;
+	txdr->work_limit = txdr->count;
+	spin_lock_init(&txdr->tx_lock);
+
+	return 0;
+}
+
+/**
+ * ixgbe_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @adapter: board private structure
+ * @rxdr:    rx descriptor ring (for a specific queue) to setup
+ *
+ * Returns 0 on success, negative on failure
+ **/
+int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
+			     struct ixgbe_ring *rxdr)
+{
+	struct pci_dev *pdev = adapter->pdev;
+	int size, desc_len;
+
+	size = sizeof(struct ixgbe_rx_buffer) * rxdr->count;
+	rxdr->rx_buffer_info = vmalloc(size);
+	if (!rxdr->rx_buffer_info) {
+		DPRINTK(PROBE, ERR,
+			"vmalloc allocation failed for the rx desc ring\n");
+		return -ENOMEM;
+	}
+	memset(rxdr->rx_buffer_info, 0, size);
+
+	desc_len = sizeof(union ixgbe_adv_rx_desc);
+
+	/* Round up to nearest 4K */
+	rxdr->size = rxdr->count * desc_len;
+	rxdr->size = ALIGN(rxdr->size, 4096);
+
+	rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
+
+	if (!rxdr->desc) {
+		DPRINTK(PROBE, ERR,
+			"Memory allocation failed for the rx desc ring\n");
+		vfree(rxdr->rx_buffer_info);
+		return -ENOMEM;
+	}
+
+	rxdr->next_to_clean = 0;
+	rxdr->next_to_use = 0;
+	rxdr->adapter = adapter;
+
+	return 0;
+}
+
+/**
+ * ixgbe_free_tx_resources - Free Tx Resources per Queue
+ * @adapter: board private structure
+ * @tx_ring: Tx descriptor ring for a specific queue
+ *
+ * Free all transmit software resources
+ **/
+static void ixgbe_free_tx_resources(struct ixgbe_adapter *adapter,
+				    struct ixgbe_ring *tx_ring)
+{
+	struct pci_dev *pdev = adapter->pdev;
+
+	ixgbe_clean_tx_ring(adapter, tx_ring);
+
+	vfree(tx_ring->tx_buffer_info);
+	tx_ring->tx_buffer_info = NULL;
+
+	pci_free_consistent(pdev, tx_ring->size, tx_ring->desc, tx_ring->dma);
+
+	tx_ring->desc = NULL;
+}
+
+/**
+ * ixgbe_free_all_tx_resources - Free Tx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ **/
+static void ixgbe_free_all_tx_resources(struct ixgbe_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_tx_queues; i++)
+		ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]);
+}
+
+/**
+ * ixgbe_free_rx_resources - Free Rx Resources
+ * @adapter: board private structure
+ * @rx_ring: ring to clean the resources from
+ *
+ * Free all receive software resources
+ **/
+static void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter,
+				    struct ixgbe_ring *rx_ring)
+{
+	struct pci_dev *pdev = adapter->pdev;
+
+	ixgbe_clean_rx_ring(adapter, rx_ring);
+
+	vfree(rx_ring->rx_buffer_info);
+	rx_ring->rx_buffer_info = NULL;
+
+	pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma);
+
+	rx_ring->desc = NULL;
+}
+
+/**
+ * ixgbe_free_all_rx_resources - Free Rx Resources for All Queues
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ **/
+static void ixgbe_free_all_rx_resources(struct ixgbe_adapter *adapter)
+{
+	int i;
+
+	for (i = 0; i < adapter->num_rx_queues; i++)
+		ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]);
+}
+
+/**
+ * ixgbe_setup_all_tx_resources - wrapper to allocate Tx resources
+ *				  (Descriptors) for all queues
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not).  It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter)
+{
+	int i, err = 0;
+
+	for (i = 0; i < adapter->num_tx_queues; i++) {
+		err = ixgbe_setup_tx_resources(adapter, &adapter->tx_ring[i]);
+		if (err) {
+			DPRINTK(PROBE, ERR,
+				"Allocation for Tx Queue %u failed\n", i);
+			break;
+		}
+	}
+
+	return err;
+}
+
+/**
+ * ixgbe_setup_all_rx_resources - wrapper to allocate Rx resources
+ *				  (Descriptors) for all queues
+ * @adapter: board private structure
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not).  It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+
+static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter)
+{
+	int i, err = 0;
+
+	for (i = 0; i < adapter->num_rx_queues; i++) {
+		err = ixgbe_setup_rx_resources(adapter, &adapter->rx_ring[i]);
+		if (err) {
+			DPRINTK(PROBE, ERR,
+				"Allocation for Rx Queue %u failed\n", i);
+			break;
+		}
+	}
+
+	return err;
+}
+
+/**
+ * ixgbe_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
+
+	if ((max_frame < (ETH_ZLEN + ETH_FCS_LEN)) ||
+	    (max_frame > IXGBE_MAX_JUMBO_FRAME_SIZE))
+		return -EINVAL;
+
+	netdev->mtu = new_mtu;
+
+	if (netif_running(netdev)) {
+		ixgbe_down(adapter);
+		ixgbe_up(adapter);
+	}
+
+	return 0;
+}
+
+/**
+ * ixgbe_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+static int ixgbe_open(struct net_device *netdev)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	int err;
+	u32 ctrl_ext;
+	u32 num_rx_queues = adapter->num_rx_queues;
+
+	/* Let firmware know the driver has taken over */
+	ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
+	IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
+			ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
+
+try_intr_reinit:
+	/* allocate transmit descriptors */
+	err = ixgbe_setup_all_tx_resources(adapter);
+	if (err)
+		goto err_setup_tx;
+
+	if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) {
+		num_rx_queues = 1;
+		adapter->num_rx_queues = num_rx_queues;
+	}
+
+	/* allocate receive descriptors */
+	err = ixgbe_setup_all_rx_resources(adapter);
+	if (err)
+		goto err_setup_rx;
+
+	ixgbe_configure(adapter);
+
+	err = ixgbe_request_irq(adapter, &num_rx_queues);
+	if (err)
+		goto err_req_irq;
+
+	/* ixgbe_request might have reduced num_rx_queues */
+	if (num_rx_queues < adapter->num_rx_queues) {
+		/* We didn't get MSI-X, so we need to release everything,
+		 * set our Rx queue count to num_rx_queues, and redo the
+		 * whole init process.
+		 */
+		ixgbe_free_irq(adapter);
+		if (adapter->flags & IXGBE_FLAG_MSI_ENABLED) {
+			pci_disable_msi(adapter->pdev);
+			adapter->flags &= ~IXGBE_FLAG_MSI_ENABLED;
+		}
+		ixgbe_free_all_rx_resources(adapter);
+		ixgbe_free_all_tx_resources(adapter);
+		adapter->num_rx_queues = num_rx_queues;
+
+		/* Reset the hardware, and start over. */
+		ixgbe_reset(adapter);
+
+		goto try_intr_reinit;
+	}
+
+	err = ixgbe_up_complete(adapter);
+	if (err)
+		goto err_up;
+
+	return 0;
+
+err_up:
+	ixgbe_free_irq(adapter);
+err_req_irq:
+	ixgbe_free_all_rx_resources(adapter);
+err_setup_rx:
+	ixgbe_free_all_tx_resources(adapter);
+err_setup_tx:
+	ixgbe_reset(adapter);
+
+	return err;
+}
+
+/**
+ * ixgbe_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the drivers control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+static int ixgbe_close(struct net_device *netdev)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	u32 ctrl_ext;
+
+	ixgbe_down(adapter);
+	ixgbe_free_irq(adapter);
+
+	ixgbe_free_all_tx_resources(adapter);
+	ixgbe_free_all_rx_resources(adapter);
+
+	ctrl_ext = IXGBE_READ_REG(&adapter->hw, IXGBE_CTRL_EXT);
+	IXGBE_WRITE_REG(&adapter->hw, IXGBE_CTRL_EXT,
+			ctrl_ext & ~IXGBE_CTRL_EXT_DRV_LOAD);
+
+	return 0;
+}
+
+/**
+ * ixgbe_update_stats - Update the board statistics counters.
+ * @adapter: board private structure
+ **/
+void ixgbe_update_stats(struct ixgbe_adapter *adapter)
+{
+	struct ixgbe_hw *hw = &adapter->hw;
+	u64 good_rx, missed_rx, bprc;
+
+	adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
+	good_rx = IXGBE_READ_REG(hw, IXGBE_GPRC);
+	missed_rx = IXGBE_READ_REG(hw, IXGBE_MPC(0));
+	missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(1));
+	missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(2));
+	missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(3));
+	missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(4));
+	missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(5));
+	missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(6));
+	missed_rx += IXGBE_READ_REG(hw, IXGBE_MPC(7));
+	adapter->stats.gprc += (good_rx - missed_rx);
+
+	adapter->stats.mpc[0] += missed_rx;
+	adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
+	bprc = IXGBE_READ_REG(hw, IXGBE_BPRC);
+	adapter->stats.bprc += bprc;
+	adapter->stats.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC);
+	adapter->stats.mprc -= bprc;
+	adapter->stats.roc += IXGBE_READ_REG(hw, IXGBE_ROC);
+	adapter->stats.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64);
+	adapter->stats.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127);
+	adapter->stats.prc255 += IXGBE_READ_REG(hw, IXGBE_PRC255);
+	adapter->stats.prc511 += IXGBE_READ_REG(hw, IXGBE_PRC511);
+	adapter->stats.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023);
+	adapter->stats.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522);
+
+	adapter->stats.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC);
+	adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
+	adapter->stats.lxontxc += IXGBE_READ_REG(hw, IXGBE_LXONTXC);
+	adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
+	adapter->stats.lxofftxc += IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
+	adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
+	adapter->stats.gptc += IXGBE_READ_REG(hw, IXGBE_GPTC);
+	adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
+	adapter->stats.rnbc[0] += IXGBE_READ_REG(hw, IXGBE_RNBC(0));
+	adapter->stats.ruc += IXGBE_READ_REG(hw, IXGBE_RUC);
+	adapter->stats.rfc += IXGBE_READ_REG(hw, IXGBE_RFC);
+	adapter->stats.rjc += IXGBE_READ_REG(hw, IXGBE_RJC);
+	adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH);
+	adapter->stats.tpr += IXGBE_READ_REG(hw, IXGBE_TPR);
+	adapter->stats.ptc64 += IXGBE_READ_REG(hw, IXGBE_PTC64);
+	adapter->stats.ptc127 += IXGBE_READ_REG(hw, IXGBE_PTC127);
+	adapter->stats.ptc255 += IXGBE_READ_REG(hw, IXGBE_PTC255);
+	adapter->stats.ptc511 += IXGBE_READ_REG(hw, IXGBE_PTC511);
+	adapter->stats.ptc1023 += IXGBE_READ_REG(hw, IXGBE_PTC1023);
+	adapter->stats.ptc1522 += IXGBE_READ_REG(hw, IXGBE_PTC1522);
+	adapter->stats.mptc += IXGBE_READ_REG(hw, IXGBE_MPTC);
+	adapter->stats.bptc += IXGBE_READ_REG(hw, IXGBE_BPTC);
+
+	/* Fill out the OS statistics structure */
+	adapter->net_stats.rx_packets = adapter->stats.gprc;
+	adapter->net_stats.tx_packets = adapter->stats.gptc;
+	adapter->net_stats.rx_bytes = adapter->stats.gorc;
+	adapter->net_stats.tx_bytes = adapter->stats.gotc;
+	adapter->net_stats.multicast = adapter->stats.mprc;
+
+	/* Rx Errors */
+	adapter->net_stats.rx_errors = adapter->stats.crcerrs +
+						adapter->stats.rlec;
+	adapter->net_stats.rx_dropped = 0;
+	adapter->net_stats.rx_length_errors = adapter->stats.rlec;
+	adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
+	adapter->net_stats.rx_missed_errors = adapter->stats.mpc[0];
+
+}
+
+/**
+ * ixgbe_watchdog - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
+ **/
+static void ixgbe_watchdog(unsigned long data)
+{
+	struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
+	struct net_device *netdev = adapter->netdev;
+	bool link_up;
+	u32 link_speed = 0;
+
+	adapter->hw.phy.ops.check(&adapter->hw, &(link_speed), &link_up);
+
+	if (link_up) {
+		if (!netif_carrier_ok(netdev)) {
+			u32 frctl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
+			u32 rmcs = IXGBE_READ_REG(&adapter->hw, IXGBE_RMCS);
+#define FLOW_RX (frctl & IXGBE_FCTRL_RFCE)
+#define FLOW_TX (rmcs & IXGBE_RMCS_TFCE_802_3X)
+			DPRINTK(LINK, INFO, "NIC Link is Up %s, "
+				"Flow Control: %s\n",
+				(link_speed == IXGBE_LINK_SPEED_10GB_FULL ?
+				 "10 Gbps" :
+				 (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
+				  "1 Gpbs" : "unknown speed")),
+				((FLOW_RX && FLOW_TX) ? "RX/TX" :
+				 (FLOW_RX ? "RX" :
+				 (FLOW_TX ? "TX" : "None"))));
+
+			netif_carrier_on(netdev);
+			netif_wake_queue(netdev);
+		} else {
+			/* Force detection of hung controller */
+			adapter->detect_tx_hung = true;
+		}
+	} else {
+		if (netif_carrier_ok(netdev)) {
+			DPRINTK(LINK, INFO, "NIC Link is Down\n");
+			netif_carrier_off(netdev);
+			netif_stop_queue(netdev);
+		}
+	}
+
+	ixgbe_update_stats(adapter);
+
+	/* Reset the timer */
+	if (!test_bit(__IXGBE_DOWN, &adapter->state))
+		mod_timer(&adapter->watchdog_timer,
+			  round_jiffies(jiffies + 2 * HZ));
+}
+
+#define IXGBE_MAX_TXD_PWR	14
+#define IXGBE_MAX_DATA_PER_TXD	(1 << IXGBE_MAX_TXD_PWR)
+
+/* Tx Descriptors needed, worst case */
+#define TXD_USE_COUNT(S) (((S) >> IXGBE_MAX_TXD_PWR) + \
+			 (((S) & (IXGBE_MAX_DATA_PER_TXD - 1)) ? 1 : 0))
+#define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \
+	MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1)	/* for context */
+
+static int ixgbe_tso(struct ixgbe_adapter *adapter,
+			 struct ixgbe_ring *tx_ring, struct sk_buff *skb,
+			 u32 tx_flags, u8 *hdr_len)
+{
+	struct ixgbe_adv_tx_context_desc *context_desc;
+	unsigned int i;
+	int err;
+	struct ixgbe_tx_buffer *tx_buffer_info;
+	u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0;
+	u32 mss_l4len_idx = 0, l4len;
+	*hdr_len = 0;
+
+	if (skb_is_gso(skb)) {
+		if (skb_header_cloned(skb)) {
+			err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+			if (err)
+				return err;
+		}
+		l4len = tcp_hdrlen(skb);
+		*hdr_len += l4len;
+
+		if (skb->protocol == ntohs(ETH_P_IP)) {
+			struct iphdr *iph = ip_hdr(skb);
+			iph->tot_len = 0;
+			iph->check = 0;
+			tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
+								 iph->daddr, 0,
+								 IPPROTO_TCP,
+								 0);
+			adapter->hw_tso_ctxt++;
+		} else if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6) {
+			ipv6_hdr(skb)->payload_len = 0;
+			tcp_hdr(skb)->check =
+			    ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+					     &ipv6_hdr(skb)->daddr,
+					     0, IPPROTO_TCP, 0);
+			adapter->hw_tso6_ctxt++;
+		}
+
+		i = tx_ring->next_to_use;
+
+		tx_buffer_info = &tx_ring->tx_buffer_info[i];
+		context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i);
+
+		/* VLAN MACLEN IPLEN */
+		if (tx_flags & IXGBE_TX_FLAGS_VLAN)
+			vlan_macip_lens |=
+			    (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK);
+		vlan_macip_lens |= ((skb_network_offset(skb)) <<
+				    IXGBE_ADVTXD_MACLEN_SHIFT);
+		*hdr_len += skb_network_offset(skb);
+		vlan_macip_lens |=
+		    (skb_transport_header(skb) - skb_network_header(skb));
+		*hdr_len +=
+		    (skb_transport_header(skb) - skb_network_header(skb));
+		context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
+		context_desc->seqnum_seed = 0;
+
+		/* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
+		type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT |
+				    IXGBE_ADVTXD_DTYP_CTXT);
+
+		if (skb->protocol == ntohs(ETH_P_IP))
+			type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
+		type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
+		context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
+
+		/* MSS L4LEN IDX */
+		mss_l4len_idx |=
+		    (skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT);
+		mss_l4len_idx |= (l4len << IXGBE_ADVTXD_L4LEN_SHIFT);
+		context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
+
+		tx_buffer_info->time_stamp = jiffies;
+		tx_buffer_info->next_to_watch = i;
+
+		i++;
+		if (i == tx_ring->count)
+			i = 0;
+		tx_ring->next_to_use = i;
+
+		return true;
+	}
+	return false;
+}
+
+static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
+				   struct ixgbe_ring *tx_ring,
+				   struct sk_buff *skb, u32 tx_flags)
+{
+	struct ixgbe_adv_tx_context_desc *context_desc;
+	unsigned int i;
+	struct ixgbe_tx_buffer *tx_buffer_info;
+	u32 vlan_macip_lens = 0, type_tucmd_mlhl = 0;
+
+	if (skb->ip_summed == CHECKSUM_PARTIAL ||
+	    (tx_flags & IXGBE_TX_FLAGS_VLAN)) {
+		i = tx_ring->next_to_use;
+		tx_buffer_info = &tx_ring->tx_buffer_info[i];
+		context_desc = IXGBE_TX_CTXTDESC_ADV(*tx_ring, i);
+
+		if (tx_flags & IXGBE_TX_FLAGS_VLAN)
+			vlan_macip_lens |=
+			    (tx_flags & IXGBE_TX_FLAGS_VLAN_MASK);
+		vlan_macip_lens |= (skb_network_offset(skb) <<
+				    IXGBE_ADVTXD_MACLEN_SHIFT);
+		if (skb->ip_summed == CHECKSUM_PARTIAL)
+			vlan_macip_lens |= (skb_transport_header(skb) -
+					    skb_network_header(skb));
+
+		context_desc->vlan_macip_lens = cpu_to_le32(vlan_macip_lens);
+		context_desc->seqnum_seed = 0;
+
+		type_tucmd_mlhl |= (IXGBE_TXD_CMD_DEXT |
+				    IXGBE_ADVTXD_DTYP_CTXT);
+
+		if (skb->ip_summed == CHECKSUM_PARTIAL) {
+			if (skb->protocol == ntohs(ETH_P_IP))
+				type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4;
+
+			if (skb->sk->sk_protocol == IPPROTO_TCP)
+				type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP;
+		}
+
+		context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl);
+		context_desc->mss_l4len_idx = 0;
+
+		tx_buffer_info->time_stamp = jiffies;
+		tx_buffer_info->next_to_watch = i;
+		adapter->hw_csum_tx_good++;
+		i++;
+		if (i == tx_ring->count)
+			i = 0;
+		tx_ring->next_to_use = i;
+
+		return true;
+	}
+	return false;
+}
+
+static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
+			struct ixgbe_ring *tx_ring,
+			struct sk_buff *skb, unsigned int first)
+{
+	struct ixgbe_tx_buffer *tx_buffer_info;
+	unsigned int len = skb->len;
+	unsigned int offset = 0, size, count = 0, i;
+	unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
+	unsigned int f;
+
+	len -= skb->data_len;
+
+	i = tx_ring->next_to_use;
+
+	while (len) {
+		tx_buffer_info = &tx_ring->tx_buffer_info[i];
+		size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD);
+
+		tx_buffer_info->length = size;
+		tx_buffer_info->dma = pci_map_single(adapter->pdev,
+						  skb->data + offset,
+						  size, PCI_DMA_TODEVICE);
+		tx_buffer_info->time_stamp = jiffies;
+		tx_buffer_info->next_to_watch = i;
+
+		len -= size;
+		offset += size;
+		count++;
+		i++;
+		if (i == tx_ring->count)
+			i = 0;
+	}
+
+	for (f = 0; f < nr_frags; f++) {
+		struct skb_frag_struct *frag;
+
+		frag = &skb_shinfo(skb)->frags[f];
+		len = frag->size;
+		offset = frag->page_offset;
+
+		while (len) {
+			tx_buffer_info = &tx_ring->tx_buffer_info[i];
+			size = min(len, (uint)IXGBE_MAX_DATA_PER_TXD);
+
+			tx_buffer_info->length = size;
+			tx_buffer_info->dma = pci_map_page(adapter->pdev,
+							frag->page,
+							offset,
+							size, PCI_DMA_TODEVICE);
+			tx_buffer_info->time_stamp = jiffies;
+			tx_buffer_info->next_to_watch = i;
+
+			len -= size;
+			offset += size;
+			count++;
+			i++;
+			if (i == tx_ring->count)
+				i = 0;
+		}
+	}
+	if (i == 0)
+		i = tx_ring->count - 1;
+	else
+		i = i - 1;
+	tx_ring->tx_buffer_info[i].skb = skb;
+	tx_ring->tx_buffer_info[first].next_to_watch = i;
+
+	return count;
+}
+
+static void ixgbe_tx_queue(struct ixgbe_adapter *adapter,
+			       struct ixgbe_ring *tx_ring,
+			       int tx_flags, int count, u32 paylen, u8 hdr_len)
+{
+	union ixgbe_adv_tx_desc *tx_desc = NULL;
+	struct ixgbe_tx_buffer *tx_buffer_info;
+	u32 olinfo_status = 0, cmd_type_len = 0;
+	unsigned int i;
+	u32 txd_cmd = IXGBE_TXD_CMD_EOP | IXGBE_TXD_CMD_RS | IXGBE_TXD_CMD_IFCS;
+
+	cmd_type_len |= IXGBE_ADVTXD_DTYP_DATA;
+
+	cmd_type_len |= IXGBE_ADVTXD_DCMD_IFCS | IXGBE_ADVTXD_DCMD_DEXT;
+
+	if (tx_flags & IXGBE_TX_FLAGS_VLAN)
+		cmd_type_len |= IXGBE_ADVTXD_DCMD_VLE;
+
+	if (tx_flags & IXGBE_TX_FLAGS_TSO) {
+		cmd_type_len |= IXGBE_ADVTXD_DCMD_TSE;
+
+		olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
+						IXGBE_ADVTXD_POPTS_SHIFT;
+
+		if (tx_flags & IXGBE_TX_FLAGS_IPV4)
+			olinfo_status |= IXGBE_TXD_POPTS_IXSM <<
+						IXGBE_ADVTXD_POPTS_SHIFT;
+
+	} else if (tx_flags & IXGBE_TX_FLAGS_CSUM)
+		olinfo_status |= IXGBE_TXD_POPTS_TXSM <<
+						IXGBE_ADVTXD_POPTS_SHIFT;
+
+	olinfo_status |= ((paylen - hdr_len) << IXGBE_ADVTXD_PAYLEN_SHIFT);
+
+	i = tx_ring->next_to_use;
+	while (count--) {
+		tx_buffer_info = &tx_ring->tx_buffer_info[i];
+		tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
+		tx_desc->read.buffer_addr = cpu_to_le64(tx_buffer_info->dma);
+		tx_desc->read.cmd_type_len =
+			cpu_to_le32(cmd_type_len | tx_buffer_info->length);
+		tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
+
+		i++;
+		if (i == tx_ring->count)
+			i = 0;
+	}
+
+	tx_desc->read.cmd_type_len |= cpu_to_le32(txd_cmd);
+
+	/*
+	 * Force memory writes to complete before letting h/w
+	 * know there are new descriptors to fetch.  (Only
+	 * applicable for weak-ordered memory model archs,
+	 * such as IA-64).
+	 */
+	wmb();
+
+	tx_ring->next_to_use = i;
+	writel(i, adapter->hw.hw_addr + tx_ring->tail);
+}
+
+static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	struct ixgbe_ring *tx_ring;
+	unsigned int len = skb->len;
+	unsigned int first;
+	unsigned int tx_flags = 0;
+	unsigned long flags = 0;
+	u8 hdr_len;
+	int tso;
+	unsigned int mss = 0;
+	int count = 0;
+	unsigned int f;
+	unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
+	len -= skb->data_len;
+
+	tx_ring = adapter->tx_ring;
+
+	if (skb->len <= 0) {
+		dev_kfree_skb(skb);
+		return NETDEV_TX_OK;
+	}
+	mss = skb_shinfo(skb)->gso_size;
+
+	if (mss)
+		count++;
+	else if (skb->ip_summed == CHECKSUM_PARTIAL)
+		count++;
+
+	count += TXD_USE_COUNT(len);
+	for (f = 0; f < nr_frags; f++)
+		count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
+
+	spin_lock_irqsave(&tx_ring->tx_lock, flags);
+	if (IXGBE_DESC_UNUSED(tx_ring) < (count + 2)) {
+		adapter->tx_busy++;
+		netif_stop_queue(netdev);
+		spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+		return NETDEV_TX_BUSY;
+	}
+	spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+	if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
+		tx_flags |= IXGBE_TX_FLAGS_VLAN;
+		tx_flags |= (vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT);
+	}
+
+	if (skb->protocol == ntohs(ETH_P_IP))
+		tx_flags |= IXGBE_TX_FLAGS_IPV4;
+	first = tx_ring->next_to_use;
+	tso = ixgbe_tso(adapter, tx_ring, skb, tx_flags, &hdr_len);
+	if (tso < 0) {
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	if (tso)
+		tx_flags |= IXGBE_TX_FLAGS_TSO;
+	else if (ixgbe_tx_csum(adapter, tx_ring, skb, tx_flags) &&
+		 (skb->ip_summed == CHECKSUM_PARTIAL))
+		tx_flags |= IXGBE_TX_FLAGS_CSUM;
+
+	ixgbe_tx_queue(adapter, tx_ring, tx_flags,
+			   ixgbe_tx_map(adapter, tx_ring, skb, first),
+			   skb->len, hdr_len);
+
+	netdev->trans_start = jiffies;
+
+	spin_lock_irqsave(&tx_ring->tx_lock, flags);
+	/* Make sure there is space in the ring for the next send. */
+	if (IXGBE_DESC_UNUSED(tx_ring) < DESC_NEEDED)
+		netif_stop_queue(netdev);
+	spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
+
+	return NETDEV_TX_OK;
+}
+
+/**
+ * ixgbe_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ **/
+static struct net_device_stats *ixgbe_get_stats(struct net_device *netdev)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	/* only return the current stats */
+	return &adapter->net_stats;
+}
+
+/**
+ * ixgbe_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int ixgbe_set_mac(struct net_device *netdev, void *p)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+	struct sockaddr *addr = p;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+	memcpy(adapter->hw.mac.addr, addr->sa_data, netdev->addr_len);
+
+	ixgbe_set_rar(&adapter->hw, 0, adapter->hw.mac.addr, 0, IXGBE_RAH_AV);
+
+	return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void ixgbe_netpoll(struct net_device *netdev)
+{
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	disable_irq(adapter->pdev->irq);
+	adapter->flags |= IXGBE_FLAG_IN_NETPOLL;
+	ixgbe_intr(adapter->pdev->irq, netdev);
+	adapter->flags &= ~IXGBE_FLAG_IN_NETPOLL;
+	enable_irq(adapter->pdev->irq);
+}
+#endif
+
+/**
+ * ixgbe_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in ixgbe_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * ixgbe_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+static int __devinit ixgbe_probe(struct pci_dev *pdev,
+				 const struct pci_device_id *ent)
+{
+	struct net_device *netdev;
+	struct ixgbe_adapter *adapter = NULL;
+	struct ixgbe_hw *hw;
+	const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data];
+	unsigned long mmio_start, mmio_len;
+	static int cards_found;
+	int i, err, pci_using_dac;
+	u16 link_status, link_speed, link_width;
+	u32 part_num;
+
+	err = pci_enable_device(pdev);
+	if (err)
+		return err;
+
+	if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK) &&
+	    !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) {
+		pci_using_dac = 1;
+	} else {
+		err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+		if (err) {
+			err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+			if (err) {
+				dev_err(&pdev->dev, "No usable DMA "
+					"configuration, aborting\n");
+				goto err_dma;
+			}
+		}
+		pci_using_dac = 0;
+	}
+
+	err = pci_request_regions(pdev, ixgbe_driver_name);
+	if (err) {
+		dev_err(&pdev->dev, "pci_request_regions failed 0x%x\n", err);
+		goto err_pci_reg;
+	}
+
+	pci_set_master(pdev);
+
+	netdev = alloc_etherdev(sizeof(struct ixgbe_adapter));
+	if (!netdev) {
+		err = -ENOMEM;
+		goto err_alloc_etherdev;
+	}
+
+	SET_NETDEV_DEV(netdev, &pdev->dev);
+
+	pci_set_drvdata(pdev, netdev);
+	adapter = netdev_priv(netdev);
+
+	adapter->netdev = netdev;
+	adapter->pdev = pdev;
+	hw = &adapter->hw;
+	hw->back = adapter;
+	adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1;
+
+	mmio_start = pci_resource_start(pdev, 0);
+	mmio_len = pci_resource_len(pdev, 0);
+
+	hw->hw_addr = ioremap(mmio_start, mmio_len);
+	if (!hw->hw_addr) {
+		err = -EIO;
+		goto err_ioremap;
+	}
+
+	for (i = 1; i <= 5; i++) {
+		if (pci_resource_len(pdev, i) == 0)
+			continue;
+	}
+
+	netdev->open = &ixgbe_open;
+	netdev->stop = &ixgbe_close;
+	netdev->hard_start_xmit = &ixgbe_xmit_frame;
+	netdev->get_stats = &ixgbe_get_stats;
+	netdev->set_multicast_list = &ixgbe_set_multi;
+	netdev->set_mac_address = &ixgbe_set_mac;
+	netdev->change_mtu = &ixgbe_change_mtu;
+	ixgbe_set_ethtool_ops(netdev);
+	netdev->tx_timeout = &ixgbe_tx_timeout;
+	netdev->watchdog_timeo = 5 * HZ;
+	netif_napi_add(netdev, &adapter->napi, ixgbe_clean, 64);
+	netdev->vlan_rx_register = ixgbe_vlan_rx_register;
+	netdev->vlan_rx_add_vid = ixgbe_vlan_rx_add_vid;
+	netdev->vlan_rx_kill_vid = ixgbe_vlan_rx_kill_vid;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	netdev->poll_controller = ixgbe_netpoll;
+#endif
+	strcpy(netdev->name, pci_name(pdev));
+
+	netdev->mem_start = mmio_start;
+	netdev->mem_end = mmio_start + mmio_len;
+
+	adapter->bd_number = cards_found;
+
+	/* PCI config space info */
+	hw->vendor_id = pdev->vendor;
+	hw->device_id = pdev->device;
+	hw->revision_id = pdev->revision;
+	hw->subsystem_vendor_id = pdev->subsystem_vendor;
+	hw->subsystem_device_id = pdev->subsystem_device;
+
+	/* Setup hw api */
+	memcpy(&hw->mac.ops, ii->mac_ops, sizeof(hw->mac.ops));
+	memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops));
+
+	err = ii->get_invariants(hw);
+	if (err)
+		goto err_hw_init;
+
+	/* setup the private structure */
+	err = ixgbe_sw_init(adapter);
+	if (err)
+		goto err_sw_init;
+
+	netdev->features = NETIF_F_SG |
+			   NETIF_F_HW_CSUM |
+			   NETIF_F_HW_VLAN_TX |
+			   NETIF_F_HW_VLAN_RX |
+			   NETIF_F_HW_VLAN_FILTER;
+
+	netdev->features |= NETIF_F_TSO;
+
+	netdev->features |= NETIF_F_TSO6;
+	if (pci_using_dac)
+		netdev->features |= NETIF_F_HIGHDMA;
+
+
+	/* make sure the EEPROM is good */
+	if (ixgbe_validate_eeprom_checksum(hw, NULL) < 0) {
+		dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n");
+		err = -EIO;
+		goto err_eeprom;
+	}
+
+	memcpy(netdev->dev_addr, hw->mac.perm_addr, netdev->addr_len);
+	memcpy(netdev->perm_addr, hw->mac.perm_addr, netdev->addr_len);
+
+	if (ixgbe_validate_mac_addr(netdev->dev_addr)) {
+		err = -EIO;
+		goto err_eeprom;
+	}
+
+	init_timer(&adapter->watchdog_timer);
+	adapter->watchdog_timer.function = &ixgbe_watchdog;
+	adapter->watchdog_timer.data = (unsigned long)adapter;
+
+	INIT_WORK(&adapter->reset_task, ixgbe_reset_task);
+
+	/* initialize default flow control settings */
+	hw->fc.original_type = ixgbe_fc_full;
+	hw->fc.type = ixgbe_fc_full;
+	hw->fc.high_water = IXGBE_DEFAULT_FCRTH;
+	hw->fc.low_water = IXGBE_DEFAULT_FCRTL;
+	hw->fc.pause_time = IXGBE_DEFAULT_FCPAUSE;
+
+	/* Interrupt Throttle Rate */
+	adapter->rx_eitr = (1000000 / IXGBE_DEFAULT_ITR_RX_USECS);
+	adapter->tx_eitr = (1000000 / IXGBE_DEFAULT_ITR_TX_USECS);
+
+	/* print bus type/speed/width info */
+	pci_read_config_word(pdev, IXGBE_PCI_LINK_STATUS, &link_status);
+	link_speed = link_status & IXGBE_PCI_LINK_SPEED;
+	link_width = link_status & IXGBE_PCI_LINK_WIDTH;
+	dev_info(&pdev->dev, "(PCI Express:%s:%s) "
+		 "%02x:%02x:%02x:%02x:%02x:%02x\n",
+		((link_speed == IXGBE_PCI_LINK_SPEED_5000) ? "5.0Gb/s" :
+		 (link_speed == IXGBE_PCI_LINK_SPEED_2500) ? "2.5Gb/s" :
+		 "Unknown"),
+		((link_width == IXGBE_PCI_LINK_WIDTH_8) ? "Width x8" :
+		 (link_width == IXGBE_PCI_LINK_WIDTH_4) ? "Width x4" :
+		 (link_width == IXGBE_PCI_LINK_WIDTH_2) ? "Width x2" :
+		 (link_width == IXGBE_PCI_LINK_WIDTH_1) ? "Width x1" :
+		 "Unknown"),
+		netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
+		netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
+	ixgbe_read_part_num(hw, &part_num);
+	dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
+		 hw->mac.type, hw->phy.type,
+		 (part_num >> 8), (part_num & 0xff));
+
+	/* reset the hardware with the new settings */
+	ixgbe_start_hw(hw);
+
+	netif_carrier_off(netdev);
+	netif_stop_queue(netdev);
+
+	strcpy(netdev->name, "eth%d");
+	err = register_netdev(netdev);
+	if (err)
+		goto err_register;
+
+
+	dev_info(&pdev->dev, "Intel(R) 10 Gigabit Network Connection\n");
+	cards_found++;
+	return 0;
+
+err_register:
+err_hw_init:
+err_sw_init:
+err_eeprom:
+	iounmap(hw->hw_addr);
+err_ioremap:
+	free_netdev(netdev);
+err_alloc_etherdev:
+	pci_release_regions(pdev);
+err_pci_reg:
+err_dma:
+	pci_disable_device(pdev);
+	return err;
+}
+
+/**
+ * ixgbe_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * ixgbe_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.  The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void __devexit ixgbe_remove(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+	set_bit(__IXGBE_DOWN, &adapter->state);
+	del_timer_sync(&adapter->watchdog_timer);
+
+	flush_scheduled_work();
+
+	unregister_netdev(netdev);
+
+	kfree(adapter->tx_ring);
+	kfree(adapter->rx_ring);
+
+	iounmap(adapter->hw.hw_addr);
+	pci_release_regions(pdev);
+
+	free_netdev(netdev);
+
+	pci_disable_device(pdev);
+}
+
+/**
+ * ixgbe_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
+						pci_channel_state_t state)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct ixgbe_adapter *adapter = netdev->priv;
+
+	netif_device_detach(netdev);
+
+	if (netif_running(netdev))
+		ixgbe_down(adapter);
+	pci_disable_device(pdev);
+
+	/* Request a slot slot reset. */
+	return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * ixgbe_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ */
+static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct ixgbe_adapter *adapter = netdev->priv;
+
+	if (pci_enable_device(pdev)) {
+		DPRINTK(PROBE, ERR,
+			"Cannot re-enable PCI device after reset.\n");
+		return PCI_ERS_RESULT_DISCONNECT;
+	}
+	pci_set_master(pdev);
+
+	pci_enable_wake(pdev, PCI_D3hot, 0);
+	pci_enable_wake(pdev, PCI_D3cold, 0);
+
+	ixgbe_reset(adapter);
+
+	return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * ixgbe_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation.
+ */
+static void ixgbe_io_resume(struct pci_dev *pdev)
+{
+	struct net_device *netdev = pci_get_drvdata(pdev);
+	struct ixgbe_adapter *adapter = netdev->priv;
+
+	if (netif_running(netdev)) {
+		if (ixgbe_up(adapter)) {
+			DPRINTK(PROBE, INFO, "ixgbe_up failed after reset\n");
+			return;
+		}
+	}
+
+	netif_device_attach(netdev);
+
+}
+
+static struct pci_error_handlers ixgbe_err_handler = {
+	.error_detected = ixgbe_io_error_detected,
+	.slot_reset = ixgbe_io_slot_reset,
+	.resume = ixgbe_io_resume,
+};
+
+static struct pci_driver ixgbe_driver = {
+	.name     = ixgbe_driver_name,
+	.id_table = ixgbe_pci_tbl,
+	.probe    = ixgbe_probe,
+	.remove   = __devexit_p(ixgbe_remove),
+#ifdef CONFIG_PM
+	.suspend  = ixgbe_suspend,
+	.resume   = ixgbe_resume,
+#endif
+	.shutdown = ixgbe_shutdown,
+	.err_handler = &ixgbe_err_handler
+};
+
+/**
+ * ixgbe_init_module - Driver Registration Routine
+ *
+ * ixgbe_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ **/
+static int __init ixgbe_init_module(void)
+{
+	int ret;
+	printk(KERN_INFO "%s: %s - version %s\n", ixgbe_driver_name,
+	       ixgbe_driver_string, ixgbe_driver_version);
+
+	printk(KERN_INFO "%s: %s\n", ixgbe_driver_name, ixgbe_copyright);
+
+	ret = pci_register_driver(&ixgbe_driver);
+	return ret;
+}
+module_init(ixgbe_init_module);
+
+/**
+ * ixgbe_exit_module - Driver Exit Cleanup Routine
+ *
+ * ixgbe_exit_module is called just before the driver is removed
+ * from memory.
+ **/
+static void __exit ixgbe_exit_module(void)
+{
+	pci_unregister_driver(&ixgbe_driver);
+}
+module_exit(ixgbe_exit_module);
+
+/* ixgbe_main.c */
diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c
new file mode 100644
index 0000000..8002931
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_phy.c
@@ -0,0 +1,494 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include "ixgbe_common.h"
+#include "ixgbe_phy.h"
+
+static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id);
+static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw);
+static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr);
+static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
+			       u32 device_type, u16 phy_data);
+
+/**
+ *  ixgbe_identify_phy - Get physical layer module
+ *  @hw: pointer to hardware structure
+ *
+ *  Determines the physical layer module found on the current adapter.
+ **/
+s32 ixgbe_identify_phy(struct ixgbe_hw *hw)
+{
+	s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
+	u32 phy_addr;
+
+	for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) {
+		if (ixgbe_validate_phy_addr(hw, phy_addr)) {
+			hw->phy.addr = phy_addr;
+			ixgbe_get_phy_id(hw);
+			hw->phy.type = ixgbe_get_phy_type_from_id(hw->phy.id);
+			status = 0;
+			break;
+		}
+	}
+	return status;
+}
+
+/**
+ *  ixgbe_validate_phy_addr - Determines phy address is valid
+ *  @hw: pointer to hardware structure
+ *
+ **/
+static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr)
+{
+	u16 phy_id = 0;
+	bool valid = false;
+
+	hw->phy.addr = phy_addr;
+	ixgbe_read_phy_reg(hw,
+			   IXGBE_MDIO_PHY_ID_HIGH,
+			   IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+			   &phy_id);
+
+	if (phy_id != 0xFFFF && phy_id != 0x0)
+		valid = true;
+
+	return valid;
+}
+
+/**
+ *  ixgbe_get_phy_id - Get the phy type
+ *  @hw: pointer to hardware structure
+ *
+ **/
+static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw)
+{
+	u32 status;
+	u16 phy_id_high = 0;
+	u16 phy_id_low = 0;
+
+	status = ixgbe_read_phy_reg(hw,
+				   IXGBE_MDIO_PHY_ID_HIGH,
+				   IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+				   &phy_id_high);
+
+	if (status == 0) {
+		hw->phy.id = (u32)(phy_id_high << 16);
+		status = ixgbe_read_phy_reg(hw,
+					   IXGBE_MDIO_PHY_ID_LOW,
+					   IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+					   &phy_id_low);
+		hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK);
+		hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK);
+	}
+
+	return status;
+}
+
+/**
+ *  ixgbe_get_phy_type_from_id - Get the phy type
+ *  @hw: pointer to hardware structure
+ *
+ **/
+static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
+{
+	enum ixgbe_phy_type phy_type;
+
+	switch (phy_id) {
+	case TN1010_PHY_ID:
+		phy_type = ixgbe_phy_tn;
+		break;
+	case QT2022_PHY_ID:
+		phy_type = ixgbe_phy_qt;
+		break;
+	default:
+		phy_type = ixgbe_phy_unknown;
+		break;
+	}
+
+	return phy_type;
+}
+
+/**
+ *  ixgbe_reset_phy - Performs a PHY reset
+ *  @hw: pointer to hardware structure
+ **/
+s32 ixgbe_reset_phy(struct ixgbe_hw *hw)
+{
+	/*
+	 * Perform soft PHY reset to the PHY_XS.
+	 * This will cause a soft reset to the PHY
+	 */
+	return ixgbe_write_phy_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
+				   IXGBE_MDIO_PHY_XS_DEV_TYPE,
+				   IXGBE_MDIO_PHY_XS_RESET);
+}
+
+/**
+ *  ixgbe_read_phy_reg - Reads a value from a specified PHY register
+ *  @hw: pointer to hardware structure
+ *  @reg_addr: 32 bit address of PHY register to read
+ *  @phy_data: Pointer to read data from PHY register
+ **/
+s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
+		       u32 device_type, u16 *phy_data)
+{
+	u32 command;
+	u32 i;
+	u32 timeout = 10;
+	u32 data;
+	s32 status = 0;
+	u16 gssr;
+
+	if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
+		gssr = IXGBE_GSSR_PHY1_SM;
+	else
+		gssr = IXGBE_GSSR_PHY0_SM;
+
+	if (ixgbe_acquire_swfw_sync(hw, gssr) != 0)
+		status = IXGBE_ERR_SWFW_SYNC;
+
+	if (status == 0) {
+		/* Setup and write the address cycle command */
+		command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
+			   (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+			   (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+			   (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
+
+		IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
+
+		/*
+		 * Check every 10 usec to see if the address cycle completed.
+		 * The MDI Command bit will clear when the operation is
+		 * complete
+		 */
+		for (i = 0; i < timeout; i++) {
+			udelay(10);
+
+			command = IXGBE_READ_REG(hw, IXGBE_MSCA);
+
+			if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
+				break;
+		}
+
+		if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
+			hw_dbg(hw, "PHY address command did not complete.\n");
+			status = IXGBE_ERR_PHY;
+		}
+
+		if (status == 0) {
+			/*
+			 * Address cycle complete, setup and write the read
+			 * command
+			 */
+			command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
+				   (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+				   (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+				   (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND));
+
+			IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
+
+			/*
+			 * Check every 10 usec to see if the address cycle
+			 * completed. The MDI Command bit will clear when the
+			 * operation is complete
+			 */
+			for (i = 0; i < timeout; i++) {
+				udelay(10);
+
+				command = IXGBE_READ_REG(hw, IXGBE_MSCA);
+
+				if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
+					break;
+			}
+
+			if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
+				hw_dbg(hw,
+				       "PHY read command didn't complete\n");
+				status = IXGBE_ERR_PHY;
+			} else {
+				/*
+				 * Read operation is complete.  Get the data
+				 * from MSRWD
+				 */
+				data = IXGBE_READ_REG(hw, IXGBE_MSRWD);
+				data >>= IXGBE_MSRWD_READ_DATA_SHIFT;
+				*phy_data = (u16)(data);
+			}
+		}
+
+		ixgbe_release_swfw_sync(hw, gssr);
+	}
+	return status;
+}
+
+/**
+ *  ixgbe_write_phy_reg - Writes a value to specified PHY register
+ *  @hw: pointer to hardware structure
+ *  @reg_addr: 32 bit PHY register to write
+ *  @device_type: 5 bit device type
+ *  @phy_data: Data to write to the PHY register
+ **/
+static s32 ixgbe_write_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
+			       u32 device_type, u16 phy_data)
+{
+	u32 command;
+	u32 i;
+	u32 timeout = 10;
+	s32 status = 0;
+	u16 gssr;
+
+	if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
+		gssr = IXGBE_GSSR_PHY1_SM;
+	else
+		gssr = IXGBE_GSSR_PHY0_SM;
+
+	if (ixgbe_acquire_swfw_sync(hw, gssr) != 0)
+		status = IXGBE_ERR_SWFW_SYNC;
+
+	if (status == 0) {
+		/* Put the data in the MDI single read and write data register*/
+		IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data);
+
+		/* Setup and write the address cycle command */
+		command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
+			   (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+			   (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+			   (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
+
+		IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
+
+		/*
+		 * Check every 10 usec to see if the address cycle completed.
+		 * The MDI Command bit will clear when the operation is
+		 * complete
+		 */
+		for (i = 0; i < timeout; i++) {
+			udelay(10);
+
+			command = IXGBE_READ_REG(hw, IXGBE_MSCA);
+
+			if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) {
+				hw_dbg(hw, "PHY address cmd didn't complete\n");
+				break;
+			}
+		}
+
+		if ((command & IXGBE_MSCA_MDI_COMMAND) != 0)
+			status = IXGBE_ERR_PHY;
+
+		if (status == 0) {
+			/*
+			 * Address cycle complete, setup and write the write
+			 * command
+			 */
+			command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT)  |
+				   (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
+				   (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
+				   (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND));
+
+			IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
+
+			/*
+			 * Check every 10 usec to see if the address cycle
+			 * completed. The MDI Command bit will clear when the
+			 * operation is complete
+			 */
+			for (i = 0; i < timeout; i++) {
+				udelay(10);
+
+				command = IXGBE_READ_REG(hw, IXGBE_MSCA);
+
+				if ((command & IXGBE_MSCA_MDI_COMMAND) == 0) {
+					hw_dbg(hw, "PHY write command did not "
+						  "complete.\n");
+					break;
+				}
+			}
+
+			if ((command & IXGBE_MSCA_MDI_COMMAND) != 0)
+				status = IXGBE_ERR_PHY;
+		}
+
+		ixgbe_release_swfw_sync(hw, gssr);
+	}
+
+	return status;
+}
+
+/**
+ *  ixgbe_setup_tnx_phy_link - Set and restart autoneg
+ *  @hw: pointer to hardware structure
+ *
+ *  Restart autonegotiation and PHY and waits for completion.
+ **/
+s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw)
+{
+	s32 status = IXGBE_NOT_IMPLEMENTED;
+	u32 time_out;
+	u32 max_time_out = 10;
+	u16 autoneg_speed_selection_register = 0x10;
+	u16 autoneg_restart_mask = 0x0200;
+	u16 autoneg_complete_mask = 0x0020;
+	u16 autoneg_reg = 0;
+
+	/*
+	 * Set advertisement settings in PHY based on autoneg_advertised
+	 * settings. If autoneg_advertised = 0, then advertise default values
+	 * txn devices cannot be "forced" to a autoneg 10G and fail.  But can
+	 * for a 1G.
+	 */
+	ixgbe_read_phy_reg(hw,
+		  autoneg_speed_selection_register,
+		  IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+		  &autoneg_reg);
+
+	if (hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_1GB_FULL)
+		autoneg_reg &= 0xEFFF; /* 0 in bit 12 is 1G operation */
+	else
+		autoneg_reg |= 0x1000; /* 1 in bit 12 is 10G/1G operation */
+
+	ixgbe_write_phy_reg(hw,
+		  autoneg_speed_selection_register,
+		  IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+		  autoneg_reg);
+
+
+	/* Restart PHY autonegotiation and wait for completion */
+	ixgbe_read_phy_reg(hw,
+		  IXGBE_MDIO_AUTO_NEG_CONTROL,
+		  IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+		  &autoneg_reg);
+
+	autoneg_reg |= autoneg_restart_mask;
+
+	ixgbe_write_phy_reg(hw,
+		  IXGBE_MDIO_AUTO_NEG_CONTROL,
+		  IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+		  autoneg_reg);
+
+	/* Wait for autonegotiation to finish */
+	for (time_out = 0; time_out < max_time_out; time_out++) {
+		udelay(10);
+		/* Restart PHY autonegotiation and wait for completion */
+		status = ixgbe_read_phy_reg(hw,
+					    IXGBE_MDIO_AUTO_NEG_STATUS,
+					    IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
+					    &autoneg_reg);
+
+		autoneg_reg &= autoneg_complete_mask;
+		if (autoneg_reg == autoneg_complete_mask) {
+			status = 0;
+			break;
+		}
+	}
+
+	if (time_out == max_time_out)
+		status = IXGBE_ERR_LINK_SETUP;
+
+	return status;
+}
+
+/**
+ *  ixgbe_check_tnx_phy_link - Determine link and speed status
+ *  @hw: pointer to hardware structure
+ *
+ *  Reads the VS1 register to determine if link is up and the current speed for
+ *  the PHY.
+ **/
+s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed,
+			     bool *link_up)
+{
+	s32 status = 0;
+	u32 time_out;
+	u32 max_time_out = 10;
+	u16 phy_link = 0;
+	u16 phy_speed = 0;
+	u16 phy_data = 0;
+
+	/* Initialize speed and link to default case */
+	*link_up = false;
+	*speed = IXGBE_LINK_SPEED_10GB_FULL;
+
+	/*
+	 * Check current speed and link status of the PHY register.
+	 * This is a vendor specific register and may have to
+	 * be changed for other copper PHYs.
+	 */
+	for (time_out = 0; time_out < max_time_out; time_out++) {
+		udelay(10);
+		if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) {
+			*link_up = true;
+			if (phy_speed ==
+			    IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS)
+				*speed = IXGBE_LINK_SPEED_1GB_FULL;
+			break;
+		} else {
+			status = ixgbe_read_phy_reg(hw,
+				     IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS,
+				     IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
+				     &phy_data);
+			phy_link = phy_data &
+				IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS;
+			phy_speed = phy_data &
+				IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS;
+		}
+	}
+
+	return status;
+}
+
+/**
+ *  ixgbe_setup_tnx_phy_link_speed - Sets the auto advertised capabilities
+ *  @hw: pointer to hardware structure
+ *  @speed: new link speed
+ *  @autoneg: true if autonegotiation enabled
+ **/
+s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed,
+				   bool autoneg,
+				   bool autoneg_wait_to_complete)
+{
+	/*
+	 * Clear autoneg_advertised and set new values based on input link
+	 * speed.
+	 */
+	hw->phy.autoneg_advertised = 0;
+
+	if (speed & IXGBE_LINK_SPEED_10GB_FULL)
+		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
+	if (speed & IXGBE_LINK_SPEED_1GB_FULL)
+		hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
+
+	/* Setup link based on the new speed settings */
+	ixgbe_setup_tnx_phy_link(hw);
+
+	return 0;
+}
diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h
new file mode 100644
index 0000000..199e8f67
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_phy.h
@@ -0,0 +1,50 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_PHY_H_
+#define _IXGBE_PHY_H_
+
+#include "ixgbe_type.h"
+
+s32 ixgbe_init_shared_code_phy(struct ixgbe_hw *hw);
+s32 ixgbe_setup_phy_link(struct ixgbe_hw *hw);
+s32 ixgbe_check_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up);
+s32 ixgbe_setup_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg,
+			       bool autoneg_wait_to_complete);
+s32 ixgbe_identify_phy(struct ixgbe_hw *hw);
+s32 ixgbe_reset_phy(struct ixgbe_hw *hw);
+s32 ixgbe_read_phy_reg(struct ixgbe_hw *hw, u32 reg_addr,
+			       u32 device_type, u16 *phy_data);
+
+/* PHY specific */
+s32 ixgbe_setup_tnx_phy_link(struct ixgbe_hw *hw);
+s32 ixgbe_check_tnx_phy_link(struct ixgbe_hw *hw, u32 *speed, bool *link_up);
+s32 ixgbe_setup_tnx_phy_link_speed(struct ixgbe_hw *hw, u32 speed, bool autoneg,
+				  bool autoneg_wait_to_complete);
+
+#endif /* _IXGBE_PHY_H_ */
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
new file mode 100644
index 0000000..fdcde16
--- /dev/null
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -0,0 +1,1332 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2007 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope 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.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _IXGBE_TYPE_H_
+#define _IXGBE_TYPE_H_
+
+#include <linux/types.h>
+
+/* Vendor ID */
+#define IXGBE_INTEL_VENDOR_ID   0x8086
+
+/* Device IDs */
+#define IXGBE_DEV_ID_82598AF_DUAL_PORT   0x10C6
+#define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7
+#define IXGBE_DEV_ID_82598AT_DUAL_PORT   0x10C8
+#define IXGBE_DEV_ID_82598EB_CX4         0x10DD
+
+/* General Registers */
+#define IXGBE_CTRL      0x00000
+#define IXGBE_STATUS    0x00008
+#define IXGBE_CTRL_EXT  0x00018
+#define IXGBE_ESDP      0x00020
+#define IXGBE_EODSDP    0x00028
+#define IXGBE_LEDCTL    0x00200
+#define IXGBE_FRTIMER   0x00048
+#define IXGBE_TCPTIMER  0x0004C
+
+/* NVM Registers */
+#define IXGBE_EEC       0x10010
+#define IXGBE_EERD      0x10014
+#define IXGBE_FLA       0x1001C
+#define IXGBE_EEMNGCTL  0x10110
+#define IXGBE_EEMNGDATA 0x10114
+#define IXGBE_FLMNGCTL  0x10118
+#define IXGBE_FLMNGDATA 0x1011C
+#define IXGBE_FLMNGCNT  0x10120
+#define IXGBE_FLOP      0x1013C
+#define IXGBE_GRC       0x10200
+
+/* Interrupt Registers */
+#define IXGBE_EICR      0x00800
+#define IXGBE_EICS      0x00808
+#define IXGBE_EIMS      0x00880
+#define IXGBE_EIMC      0x00888
+#define IXGBE_EIAC      0x00810
+#define IXGBE_EIAM      0x00890
+#define IXGBE_EITR(_i) (0x00820 + ((_i) * 4)) /* 0x820-0x86c */
+#define IXGBE_IVAR(_i) (0x00900 + ((_i) * 4)) /* 24 at 0x900-0x960 */
+#define IXGBE_MSIXT     0x00000 /* MSI-X Table. 0x0000 - 0x01C */
+#define IXGBE_MSIXPBA   0x02000 /* MSI-X Pending bit array */
+#define IXGBE_PBACL     0x11068
+#define IXGBE_GPIE      0x00898
+
+/* Flow Control Registers */
+#define IXGBE_PFCTOP    0x03008
+#define IXGBE_FCTTV(_i) (0x03200 + ((_i) * 4)) /* 4 of these (0-3) */
+#define IXGBE_FCRTL(_i) (0x03220 + ((_i) * 8)) /* 8 of these (0-7) */
+#define IXGBE_FCRTH(_i) (0x03260 + ((_i) * 8)) /* 8 of these (0-7) */
+#define IXGBE_FCRTV     0x032A0
+#define IXGBE_TFCS      0x0CE00
+
+/* Receive DMA Registers */
+#define IXGBE_RDBAL(_i) (0x01000 + ((_i) * 0x40)) /* 64 of each (0-63)*/
+#define IXGBE_RDBAH(_i) (0x01004 + ((_i) * 0x40))
+#define IXGBE_RDLEN(_i) (0x01008 + ((_i) * 0x40))
+#define IXGBE_RDH(_i)   (0x01010 + ((_i) * 0x40))
+#define IXGBE_RDT(_i)   (0x01018 + ((_i) * 0x40))
+#define IXGBE_RXDCTL(_i) (0x01028 + ((_i) * 0x40))
+#define IXGBE_RSCCTL(_i) (0x0102C + ((_i) * 0x40))
+#define IXGBE_SRRCTL(_i) (0x02100 + ((_i) * 4))
+					     /* array of 16 (0x02100-0x0213C) */
+#define IXGBE_DCA_RXCTRL(_i)    (0x02200 + ((_i) * 4))
+					     /* array of 16 (0x02200-0x0223C) */
+#define IXGBE_RDRXCTL    0x02F00
+#define IXGBE_RXPBSIZE(_i)      (0x03C00 + ((_i) * 4))
+					     /* 8 of these 0x03C00 - 0x03C1C */
+#define IXGBE_RXCTRL    0x03000
+#define IXGBE_DROPEN    0x03D04
+#define IXGBE_RXPBSIZE_SHIFT 10
+
+/* Receive Registers */
+#define IXGBE_RXCSUM    0x05000
+#define IXGBE_RFCTL     0x05008
+#define IXGBE_MTA(_i)   (0x05200 + ((_i) * 4))
+				   /* Multicast Table Array - 128 entries */
+#define IXGBE_RAL(_i)   (0x05400 + ((_i) * 8)) /* 16 of these (0-15) */
+#define IXGBE_RAH(_i)   (0x05404 + ((_i) * 8)) /* 16 of these (0-15) */
+#define IXGBE_PSRTYPE   0x05480
+				   /* 0x5480-0x54BC Packet split receive type */
+#define IXGBE_VFTA(_i)  (0x0A000 + ((_i) * 4))
+					 /* array of 4096 1-bit vlan filters */
+#define IXGBE_VFTAVIND(_j, _i)  (0x0A200 + ((_j) * 0x200) + ((_i) * 4))
+				     /*array of 4096 4-bit vlan vmdq indicies */
+#define IXGBE_FCTRL     0x05080
+#define IXGBE_VLNCTRL   0x05088
+#define IXGBE_MCSTCTRL  0x05090
+#define IXGBE_MRQC      0x05818
+#define IXGBE_VMD_CTL   0x0581C
+#define IXGBE_IMIR(_i)  (0x05A80 + ((_i) * 4))  /* 8 of these (0-7) */
+#define IXGBE_IMIREXT(_i)       (0x05AA0 + ((_i) * 4))  /* 8 of these (0-7) */
+#define IXGBE_IMIRVP    0x05AC0
+#define IXGBE_RETA(_i)  (0x05C00 + ((_i) * 4))  /* 32 of these (0-31) */
+#define IXGBE_RSSRK(_i) (0x05C80 + ((_i) * 4))  /* 10 of these (0-9) */
+
+/* Transmit DMA registers */
+#define IXGBE_TDBAL(_i) (0x06000 + ((_i) * 0x40))/* 32 of these (0-31)*/
+#define IXGBE_TDBAH(_i) (0x06004 + ((_i) * 0x40))
+#define IXGBE_TDLEN(_i) (0x06008 + ((_i) * 0x40))
+#define IXGBE_TDH(_i)   (0x06010 + ((_i) * 0x40))
+#define IXGBE_TDT(_i)   (0x06018 + ((_i) * 0x40))
+#define IXGBE_TXDCTL(_i) (0x06028 + ((_i) * 0x40))
+#define IXGBE_TDWBAL(_i) (0x06038 + ((_i) * 0x40))
+#define IXGBE_TDWBAH(_i) (0x0603C + ((_i) * 0x40))
+#define IXGBE_DTXCTL    0x07E00
+#define IXGBE_DCA_TXCTRL(_i)    (0x07200 + ((_i) * 4))
+					      /* there are 16 of these (0-15) */
+#define IXGBE_TIPG      0x0CB00
+#define IXGBE_TXPBSIZE(_i)      (0x0CC00 + ((_i) *0x04))
+						      /* there are 8 of these */
+#define IXGBE_MNGTXMAP  0x0CD10
+#define IXGBE_TIPG_FIBER_DEFAULT 3
+#define IXGBE_TXPBSIZE_SHIFT    10
+
+/* Wake up registers */
+#define IXGBE_WUC       0x05800
+#define IXGBE_WUFC      0x05808
+#define IXGBE_WUS       0x05810
+#define IXGBE_IPAV      0x05838
+#define IXGBE_IP4AT     0x05840 /* IPv4 table 0x5840-0x5858 */
+#define IXGBE_IP6AT     0x05880 /* IPv6 table 0x5880-0x588F */
+#define IXGBE_WUPL      0x05900
+#define IXGBE_WUPM      0x05A00 /* wake up pkt memory 0x5A00-0x5A7C */
+#define IXGBE_FHFT      0x09000 /* Flex host filter table 9000-93FC */
+
+/* Music registers */
+#define IXGBE_RMCS      0x03D00
+#define IXGBE_DPMCS     0x07F40
+#define IXGBE_PDPMCS    0x0CD00
+#define IXGBE_RUPPBMR   0x050A0
+#define IXGBE_RT2CR(_i) (0x03C20 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_RT2SR(_i) (0x03C40 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_TDTQ2TCCR(_i)     (0x0602C + ((_i) * 0x40)) /* 8 of these (0-7) */
+#define IXGBE_TDTQ2TCSR(_i)     (0x0622C + ((_i) * 0x40)) /* 8 of these (0-7) */
+#define IXGBE_TDPT2TCCR(_i)     (0x0CD20 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_TDPT2TCSR(_i)     (0x0CD40 + ((_i) * 4)) /* 8 of these (0-7) */
+
+/* Stats registers */
+#define IXGBE_CRCERRS   0x04000
+#define IXGBE_ILLERRC   0x04004
+#define IXGBE_ERRBC     0x04008
+#define IXGBE_MSPDC     0x04010
+#define IXGBE_MPC(_i)   (0x03FA0 + ((_i) * 4)) /* 8 of these 3FA0-3FBC*/
+#define IXGBE_MLFC      0x04034
+#define IXGBE_MRFC      0x04038
+#define IXGBE_RLEC      0x04040
+#define IXGBE_LXONTXC   0x03F60
+#define IXGBE_LXONRXC   0x0CF60
+#define IXGBE_LXOFFTXC  0x03F68
+#define IXGBE_LXOFFRXC  0x0CF68
+#define IXGBE_PXONTXC(_i)       (0x03F00 + ((_i) * 4)) /* 8 of these 3F00-3F1C*/
+#define IXGBE_PXONRXC(_i)       (0x0CF00 + ((_i) * 4)) /* 8 of these CF00-CF1C*/
+#define IXGBE_PXOFFTXC(_i)      (0x03F20 + ((_i) * 4)) /* 8 of these 3F20-3F3C*/
+#define IXGBE_PXOFFRXC(_i)      (0x0CF20 + ((_i) * 4)) /* 8 of these CF20-CF3C*/
+#define IXGBE_PRC64     0x0405C
+#define IXGBE_PRC127    0x04060
+#define IXGBE_PRC255    0x04064
+#define IXGBE_PRC511    0x04068
+#define IXGBE_PRC1023   0x0406C
+#define IXGBE_PRC1522   0x04070
+#define IXGBE_GPRC      0x04074
+#define IXGBE_BPRC      0x04078
+#define IXGBE_MPRC      0x0407C
+#define IXGBE_GPTC      0x04080
+#define IXGBE_GORCL     0x04088
+#define IXGBE_GORCH     0x0408C
+#define IXGBE_GOTCL     0x04090
+#define IXGBE_GOTCH     0x04094
+#define IXGBE_RNBC(_i)  (0x03FC0 + ((_i) * 4)) /* 8 of these 3FC0-3FDC*/
+#define IXGBE_RUC       0x040A4
+#define IXGBE_RFC       0x040A8
+#define IXGBE_ROC       0x040AC
+#define IXGBE_RJC       0x040B0
+#define IXGBE_MNGPRC    0x040B4
+#define IXGBE_MNGPDC    0x040B8
+#define IXGBE_MNGPTC    0x0CF90
+#define IXGBE_TORL      0x040C0
+#define IXGBE_TORH      0x040C4
+#define IXGBE_TPR       0x040D0
+#define IXGBE_TPT       0x040D4
+#define IXGBE_PTC64     0x040D8
+#define IXGBE_PTC127    0x040DC
+#define IXGBE_PTC255    0x040E0
+#define IXGBE_PTC511    0x040E4
+#define IXGBE_PTC1023   0x040E8
+#define IXGBE_PTC1522   0x040EC
+#define IXGBE_MPTC      0x040F0
+#define IXGBE_BPTC      0x040F4
+#define IXGBE_XEC       0x04120
+
+#define IXGBE_RQSMR(_i) (0x02300 + ((_i) * 4)) /* 16 of these */
+#define IXGBE_TQSMR(_i) (0x07300 + ((_i) * 4)) /* 8 of these */
+
+#define IXGBE_QPRC(_i) (0x01030 + ((_i) * 0x40)) /* 16 of these */
+#define IXGBE_QPTC(_i) (0x06030 + ((_i) * 0x40)) /* 16 of these */
+#define IXGBE_QBRC(_i) (0x01034 + ((_i) * 0x40)) /* 16 of these */
+#define IXGBE_QBTC(_i) (0x06034 + ((_i) * 0x40)) /* 16 of these */
+
+/* Management */
+#define IXGBE_MAVTV(_i) (0x05010 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_MFUTP(_i) (0x05030 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_MANC      0x05820
+#define IXGBE_MFVAL     0x05824
+#define IXGBE_MANC2H    0x05860
+#define IXGBE_MDEF(_i)  (0x05890 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_MIPAF     0x058B0
+#define IXGBE_MMAL(_i)  (0x05910 + ((_i) * 8)) /* 4 of these (0-3) */
+#define IXGBE_MMAH(_i)  (0x05914 + ((_i) * 8)) /* 4 of these (0-3) */
+#define IXGBE_FTFT      0x09400 /* 0x9400-0x97FC */
+
+/* ARC Subsystem registers */
+#define IXGBE_HICR      0x15F00
+#define IXGBE_FWSTS     0x15F0C
+#define IXGBE_HSMC0R    0x15F04
+#define IXGBE_HSMC1R    0x15F08
+#define IXGBE_SWSR      0x15F10
+#define IXGBE_HFDR      0x15FE8
+#define IXGBE_FLEX_MNG  0x15800 /* 0x15800 - 0x15EFC */
+
+/* PCI-E registers */
+#define IXGBE_GCR       0x11000
+#define IXGBE_GTV       0x11004
+#define IXGBE_FUNCTAG   0x11008
+#define IXGBE_GLT       0x1100C
+#define IXGBE_GSCL_1    0x11010
+#define IXGBE_GSCL_2    0x11014
+#define IXGBE_GSCL_3    0x11018
+#define IXGBE_GSCL_4    0x1101C
+#define IXGBE_GSCN_0    0x11020
+#define IXGBE_GSCN_1    0x11024
+#define IXGBE_GSCN_2    0x11028
+#define IXGBE_GSCN_3    0x1102C
+#define IXGBE_FACTPS    0x10150
+#define IXGBE_PCIEANACTL  0x11040
+#define IXGBE_SWSM      0x10140
+#define IXGBE_FWSM      0x10148
+#define IXGBE_GSSR      0x10160
+#define IXGBE_MREVID    0x11064
+#define IXGBE_DCA_ID    0x11070
+#define IXGBE_DCA_CTRL  0x11074
+
+/* Diagnostic Registers */
+#define IXGBE_RDSTATCTL 0x02C20
+#define IXGBE_RDSTAT(_i) (0x02C00 + ((_i) * 4)) /* 0x02C00-0x02C1C */
+#define IXGBE_RDHMPN    0x02F08
+#define IXGBE_RIC_DW0   0x02F10
+#define IXGBE_RIC_DW1   0x02F14
+#define IXGBE_RIC_DW2   0x02F18
+#define IXGBE_RIC_DW3   0x02F1C
+#define IXGBE_RDPROBE   0x02F20
+#define IXGBE_TDSTATCTL 0x07C20
+#define IXGBE_TDSTAT(_i) (0x07C00 + ((_i) * 4)) /* 0x07C00 - 0x07C1C */
+#define IXGBE_TDHMPN    0x07F08
+#define IXGBE_TIC_DW0   0x07F10
+#define IXGBE_TIC_DW1   0x07F14
+#define IXGBE_TIC_DW2   0x07F18
+#define IXGBE_TIC_DW3   0x07F1C
+#define IXGBE_TDPROBE   0x07F20
+#define IXGBE_TXBUFCTRL 0x0C600
+#define IXGBE_TXBUFDATA0  0x0C610
+#define IXGBE_TXBUFDATA1  0x0C614
+#define IXGBE_TXBUFDATA2  0x0C618
+#define IXGBE_TXBUFDATA3  0x0C61C
+#define IXGBE_RXBUFCTRL   0x03600
+#define IXGBE_RXBUFDATA0  0x03610
+#define IXGBE_RXBUFDATA1  0x03614
+#define IXGBE_RXBUFDATA2  0x03618
+#define IXGBE_RXBUFDATA3  0x0361C
+#define IXGBE_PCIE_DIAG(_i)     (0x11090 + ((_i) * 4)) /* 8 of these */
+#define IXGBE_RFVAL     0x050A4
+#define IXGBE_MDFTC1    0x042B8
+#define IXGBE_MDFTC2    0x042C0
+#define IXGBE_MDFTFIFO1 0x042C4
+#define IXGBE_MDFTFIFO2 0x042C8
+#define IXGBE_MDFTS     0x042CC
+#define IXGBE_RXDATAWRPTR(_i)   (0x03700 + ((_i) * 4)) /* 8 of these 3700-370C*/
+#define IXGBE_RXDESCWRPTR(_i)   (0x03710 + ((_i) * 4)) /* 8 of these 3710-371C*/
+#define IXGBE_RXDATARDPTR(_i)   (0x03720 + ((_i) * 4)) /* 8 of these 3720-372C*/
+#define IXGBE_RXDESCRDPTR(_i)   (0x03730 + ((_i) * 4)) /* 8 of these 3730-373C*/
+#define IXGBE_TXDATAWRPTR(_i)   (0x0C700 + ((_i) * 4)) /* 8 of these C700-C70C*/
+#define IXGBE_TXDESCWRPTR(_i)   (0x0C710 + ((_i) * 4)) /* 8 of these C710-C71C*/
+#define IXGBE_TXDATARDPTR(_i)   (0x0C720 + ((_i) * 4)) /* 8 of these C720-C72C*/
+#define IXGBE_TXDESCRDPTR(_i)   (0x0C730 + ((_i) * 4)) /* 8 of these C730-C73C*/
+#define IXGBE_PCIEECCCTL 0x1106C
+#define IXGBE_PBTXECC   0x0C300
+#define IXGBE_PBRXECC   0x03300
+#define IXGBE_GHECCR    0x110B0
+
+/* MAC Registers */
+#define IXGBE_PCS1GCFIG 0x04200
+#define IXGBE_PCS1GLCTL 0x04208
+#define IXGBE_PCS1GLSTA 0x0420C
+#define IXGBE_PCS1GDBG0 0x04210
+#define IXGBE_PCS1GDBG1 0x04214
+#define IXGBE_PCS1GANA  0x04218
+#define IXGBE_PCS1GANLP 0x0421C
+#define IXGBE_PCS1GANNP 0x04220
+#define IXGBE_PCS1GANLPNP 0x04224
+#define IXGBE_HLREG0    0x04240
+#define IXGBE_HLREG1    0x04244
+#define IXGBE_PAP       0x04248
+#define IXGBE_MACA      0x0424C
+#define IXGBE_APAE      0x04250
+#define IXGBE_ARD       0x04254
+#define IXGBE_AIS       0x04258
+#define IXGBE_MSCA      0x0425C
+#define IXGBE_MSRWD     0x04260
+#define IXGBE_MLADD     0x04264
+#define IXGBE_MHADD     0x04268
+#define IXGBE_TREG      0x0426C
+#define IXGBE_PCSS1     0x04288
+#define IXGBE_PCSS2     0x0428C
+#define IXGBE_XPCSS     0x04290
+#define IXGBE_SERDESC   0x04298
+#define IXGBE_MACS      0x0429C
+#define IXGBE_AUTOC     0x042A0
+#define IXGBE_LINKS     0x042A4
+#define IXGBE_AUTOC2    0x042A8
+#define IXGBE_AUTOC3    0x042AC
+#define IXGBE_ANLP1     0x042B0
+#define IXGBE_ANLP2     0x042B4
+#define IXGBE_ATLASCTL  0x04800
+
+/* RSCCTL Bit Masks */
+#define IXGBE_RSCCTL_RSCEN          0x01
+#define IXGBE_RSCCTL_MAXDESC_1      0x00
+#define IXGBE_RSCCTL_MAXDESC_4      0x04
+#define IXGBE_RSCCTL_MAXDESC_8      0x08
+#define IXGBE_RSCCTL_MAXDESC_16     0x0C
+
+/* CTRL Bit Masks */
+#define IXGBE_CTRL_GIO_DIS      0x00000004 /* Global IO Master Disable bit */
+#define IXGBE_CTRL_LNK_RST      0x00000008 /* Link Reset. Resets everything. */
+#define IXGBE_CTRL_RST          0x04000000 /* Reset (SW) */
+
+/* FACTPS */
+#define IXGBE_FACTPS_LFS        0x40000000 /* LAN Function Select */
+
+/* MHADD Bit Masks */
+#define IXGBE_MHADD_MFS_MASK    0xFFFF0000
+#define IXGBE_MHADD_MFS_SHIFT   16
+
+/* Extended Device Control */
+#define IXGBE_CTRL_EXT_NS_DIS   0x00010000 /* No Snoop disable */
+#define IXGBE_CTRL_EXT_RO_DIS   0x00020000 /* Relaxed Ordering disable */
+#define IXGBE_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
+
+/* Direct Cache Access (DCA) definitions */
+#define IXGBE_DCA_CTRL_DCA_ENABLE  0x00000000 /* DCA Enable */
+#define IXGBE_DCA_CTRL_DCA_DISABLE 0x00000001 /* DCA Disable */
+
+#define IXGBE_DCA_CTRL_DCA_MODE_CB1 0x00 /* DCA Mode CB1 */
+#define IXGBE_DCA_CTRL_DCA_MODE_CB2 0x02 /* DCA Mode CB2 */
+
+#define IXGBE_DCA_RXCTRL_CPUID_MASK 0x0000001F /* Rx CPUID Mask */
+#define IXGBE_DCA_RXCTRL_DESC_DCA_EN (1 << 5) /* DCA Rx Desc enable */
+#define IXGBE_DCA_RXCTRL_HEAD_DCA_EN (1 << 6) /* DCA Rx Desc header enable */
+#define IXGBE_DCA_RXCTRL_DATA_DCA_EN (1 << 7) /* DCA Rx Desc payload enable */
+
+#define IXGBE_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */
+#define IXGBE_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */
+#define IXGBE_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* TX Desc writeback RO bit */
+#define IXGBE_DCA_MAX_QUEUES_82598   16 /* DCA regs only on 16 queues */
+
+/* MSCA Bit Masks */
+#define IXGBE_MSCA_NP_ADDR_MASK      0x0000FFFF /* MDI Address (new protocol) */
+#define IXGBE_MSCA_NP_ADDR_SHIFT     0
+#define IXGBE_MSCA_DEV_TYPE_MASK     0x001F0000 /* Device Type (new protocol) */
+#define IXGBE_MSCA_DEV_TYPE_SHIFT    16 /* Register Address (old protocol */
+#define IXGBE_MSCA_PHY_ADDR_MASK     0x03E00000 /* PHY Address mask */
+#define IXGBE_MSCA_PHY_ADDR_SHIFT    21 /* PHY Address shift*/
+#define IXGBE_MSCA_OP_CODE_MASK      0x0C000000 /* OP CODE mask */
+#define IXGBE_MSCA_OP_CODE_SHIFT     26 /* OP CODE shift */
+#define IXGBE_MSCA_ADDR_CYCLE        0x00000000 /* OP CODE 00 (addr cycle) */
+#define IXGBE_MSCA_WRITE             0x04000000 /* OP CODE 01 (write) */
+#define IXGBE_MSCA_READ              0x08000000 /* OP CODE 10 (read) */
+#define IXGBE_MSCA_READ_AUTOINC      0x0C000000 /* OP CODE 11 (read, auto inc)*/
+#define IXGBE_MSCA_ST_CODE_MASK      0x30000000 /* ST Code mask */
+#define IXGBE_MSCA_ST_CODE_SHIFT     28 /* ST Code shift */
+#define IXGBE_MSCA_NEW_PROTOCOL      0x00000000 /* ST CODE 00 (new protocol) */
+#define IXGBE_MSCA_OLD_PROTOCOL      0x10000000 /* ST CODE 01 (old protocol) */
+#define IXGBE_MSCA_MDI_COMMAND       0x40000000 /* Initiate MDI command */
+#define IXGBE_MSCA_MDI_IN_PROG_EN    0x80000000 /* MDI in progress enable */
+
+/* MSRWD bit masks */
+#define IXGBE_MSRWD_WRITE_DATA_MASK  0x0000FFFF
+#define IXGBE_MSRWD_WRITE_DATA_SHIFT 0
+#define IXGBE_MSRWD_READ_DATA_MASK   0xFFFF0000
+#define IXGBE_MSRWD_READ_DATA_SHIFT  16
+
+/* Atlas registers */
+#define IXGBE_ATLAS_PDN_LPBK    0x24
+#define IXGBE_ATLAS_PDN_10G     0xB
+#define IXGBE_ATLAS_PDN_1G      0xC
+#define IXGBE_ATLAS_PDN_AN      0xD
+
+/* Atlas bit masks */
+#define IXGBE_ATLASCTL_WRITE_CMD        0x00010000
+#define IXGBE_ATLAS_PDN_TX_REG_EN       0x10
+#define IXGBE_ATLAS_PDN_TX_10G_QL_ALL   0xF0
+#define IXGBE_ATLAS_PDN_TX_1G_QL_ALL    0xF0
+#define IXGBE_ATLAS_PDN_TX_AN_QL_ALL    0xF0
+
+/* Device Type definitions for new protocol MDIO commands */
+#define IXGBE_MDIO_PMA_PMD_DEV_TYPE               0x1
+#define IXGBE_MDIO_PCS_DEV_TYPE                   0x3
+#define IXGBE_MDIO_PHY_XS_DEV_TYPE                0x4
+#define IXGBE_MDIO_AUTO_NEG_DEV_TYPE              0x7
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE     0x1E   /* Device 30 */
+
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_CONTROL      0x0    /* VS1 Control Reg */
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS       0x1    /* VS1 Status Reg */
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS  0x0008 /* 1 = Link Up */
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS 0x0010 /* 0 - 10G, 1 - 1G */
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_10G_SPEED    0x0018
+#define IXGBE_MDIO_VENDOR_SPECIFIC_1_1G_SPEED     0x0010
+
+#define IXGBE_MDIO_AUTO_NEG_CONTROL    0x0 /* AUTO_NEG Control Reg */
+#define IXGBE_MDIO_AUTO_NEG_STATUS     0x1 /* AUTO_NEG Status Reg */
+#define IXGBE_MDIO_PHY_XS_CONTROL      0x0 /* PHY_XS Control Reg */
+#define IXGBE_MDIO_PHY_XS_RESET        0x8000 /* PHY_XS Reset */
+#define IXGBE_MDIO_PHY_ID_HIGH         0x2 /* PHY ID High Reg*/
+#define IXGBE_MDIO_PHY_ID_LOW          0x3 /* PHY ID Low Reg*/
+#define IXGBE_MDIO_PHY_SPEED_ABILITY   0x4 /* Speed Abilty Reg */
+#define IXGBE_MDIO_PHY_SPEED_10G       0x0001 /* 10G capable */
+#define IXGBE_MDIO_PHY_SPEED_1G        0x0010 /* 1G capable */
+
+#define IXGBE_PHY_REVISION_MASK        0xFFFFFFF0
+#define IXGBE_MAX_PHY_ADDR             32
+
+/* PHY IDs*/
+#define TN1010_PHY_ID    0x00A19410
+#define QT2022_PHY_ID    0x0043A400
+
+/* General purpose Interrupt Enable */
+#define IXGBE_GPIE_MSIX_MODE      0x00000010 /* MSI-X mode */
+#define IXGBE_GPIE_OCD            0x00000020 /* Other Clear Disable */
+#define IXGBE_GPIE_EIMEN          0x00000040 /* Immediate Interrupt Enable */
+#define IXGBE_GPIE_EIAME          0x40000000
+#define IXGBE_GPIE_PBA_SUPPORT    0x80000000
+
+/* Transmit Flow Control status */
+#define IXGBE_TFCS_TXOFF         0x00000001
+#define IXGBE_TFCS_TXOFF0        0x00000100
+#define IXGBE_TFCS_TXOFF1        0x00000200
+#define IXGBE_TFCS_TXOFF2        0x00000400
+#define IXGBE_TFCS_TXOFF3        0x00000800
+#define IXGBE_TFCS_TXOFF4        0x00001000
+#define IXGBE_TFCS_TXOFF5        0x00002000
+#define IXGBE_TFCS_TXOFF6        0x00004000
+#define IXGBE_TFCS_TXOFF7        0x00008000
+
+/* TCP Timer */
+#define IXGBE_TCPTIMER_KS            0x00000100
+#define IXGBE_TCPTIMER_COUNT_ENABLE  0x00000200
+#define IXGBE_TCPTIMER_COUNT_FINISH  0x00000400
+#define IXGBE_TCPTIMER_LOOP          0x00000800
+#define IXGBE_TCPTIMER_DURATION_MASK 0x000000FF
+
+/* HLREG0 Bit Masks */
+#define IXGBE_HLREG0_TXCRCEN      0x00000001   /* bit  0 */
+#define IXGBE_HLREG0_RXCRCSTRP    0x00000002   /* bit  1 */
+#define IXGBE_HLREG0_JUMBOEN      0x00000004   /* bit  2 */
+#define IXGBE_HLREG0_TXPADEN      0x00000400   /* bit 10 */
+#define IXGBE_HLREG0_TXPAUSEEN    0x00001000   /* bit 12 */
+#define IXGBE_HLREG0_RXPAUSEEN    0x00004000   /* bit 14 */
+#define IXGBE_HLREG0_LPBK         0x00008000   /* bit 15 */
+#define IXGBE_HLREG0_MDCSPD       0x00010000   /* bit 16 */
+#define IXGBE_HLREG0_CONTMDC      0x00020000   /* bit 17 */
+#define IXGBE_HLREG0_CTRLFLTR     0x00040000   /* bit 18 */
+#define IXGBE_HLREG0_PREPEND      0x00F00000   /* bits 20-23 */
+#define IXGBE_HLREG0_PRIPAUSEEN   0x01000000   /* bit 24 */
+#define IXGBE_HLREG0_RXPAUSERECDA 0x06000000   /* bits 25-26 */
+#define IXGBE_HLREG0_RXLNGTHERREN 0x08000000   /* bit 27 */
+#define IXGBE_HLREG0_RXPADSTRIPEN 0x10000000   /* bit 28 */
+
+/* VMD_CTL bitmasks */
+#define IXGBE_VMD_CTL_VMDQ_EN     0x00000001
+#define IXGBE_VMD_CTL_VMDQ_FILTER 0x00000002
+
+/* RDHMPN and TDHMPN bitmasks */
+#define IXGBE_RDHMPN_RDICADDR       0x007FF800
+#define IXGBE_RDHMPN_RDICRDREQ      0x00800000
+#define IXGBE_RDHMPN_RDICADDR_SHIFT 11
+#define IXGBE_TDHMPN_TDICADDR       0x003FF800
+#define IXGBE_TDHMPN_TDICRDREQ      0x00800000
+#define IXGBE_TDHMPN_TDICADDR_SHIFT 11
+
+/* Receive Checksum Control */
+#define IXGBE_RXCSUM_IPPCSE     0x00001000   /* IP payload checksum enable */
+#define IXGBE_RXCSUM_PCSD       0x00002000   /* packet checksum disabled */
+
+/* FCRTL Bit Masks */
+#define IXGBE_FCRTL_XONE        0x80000000  /* bit 31, XON enable */
+#define IXGBE_FCRTH_FCEN        0x80000000  /* Rx Flow control enable */
+
+/* PAP bit masks*/
+#define IXGBE_PAP_TXPAUSECNT_MASK   0x0000FFFF /* Pause counter mask */
+
+/* RMCS Bit Masks */
+#define IXGBE_RMCS_RRM          0x00000002 /* Receive Recylce Mode enable */
+/* Receive Arbitration Control: 0 Round Robin, 1 DFP */
+#define IXGBE_RMCS_RAC          0x00000004
+#define IXGBE_RMCS_DFP          IXGBE_RMCS_RAC /* Deficit Fixed Priority ena */
+#define IXGBE_RMCS_TFCE_802_3X  0x00000008 /* Tx Priority flow control ena */
+#define IXGBE_RMCS_TFCE_PRIORITY 0x00000010 /* Tx Priority flow control ena */
+#define IXGBE_RMCS_ARBDIS       0x00000040 /* Arbitration disable bit */
+
+/* Interrupt register bitmasks */
+
+/* Extended Interrupt Cause Read */
+#define IXGBE_EICR_RTX_QUEUE    0x0000FFFF /* RTx Queue Interrupt */
+#define IXGBE_EICR_LSC          0x00100000 /* Link Status Change */
+#define IXGBE_EICR_MNG          0x00400000 /* Managability Event Interrupt */
+#define IXGBE_EICR_PBUR         0x10000000 /* Packet Buffer Handler Error */
+#define IXGBE_EICR_DHER         0x20000000 /* Descriptor Handler Error */
+#define IXGBE_EICR_TCP_TIMER    0x40000000 /* TCP Timer */
+#define IXGBE_EICR_OTHER        0x80000000 /* Interrupt Cause Active */
+
+/* Extended Interrupt Cause Set */
+#define IXGBE_EICS_RTX_QUEUE    IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EICS_LSC          IXGBE_EICR_LSC /* Link Status Change */
+#define IXGBE_EICR_GPI_SDP0     0x01000000 /* Gen Purpose Interrupt on SDP0 */
+#define IXGBE_EICS_MNG          IXGBE_EICR_MNG /* MNG Event Interrupt */
+#define IXGBE_EICS_PBUR         IXGBE_EICR_PBUR /* Pkt Buf Handler Error */
+#define IXGBE_EICS_DHER         IXGBE_EICR_DHER /* Desc Handler Error */
+#define IXGBE_EICS_TCP_TIMER    IXGBE_EICR_TCP_TIMER /* TCP Timer */
+#define IXGBE_EICS_OTHER        IXGBE_EICR_OTHER     /* INT Cause Active */
+
+/* Extended Interrupt Mask Set */
+#define IXGBE_EIMS_RTX_QUEUE    IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EIMS_LSC          IXGBE_EICR_LSC       /* Link Status Change */
+#define IXGBE_EIMS_MNG          IXGBE_EICR_MNG       /* MNG Event Interrupt */
+#define IXGBE_EIMS_PBUR         IXGBE_EICR_PBUR      /* Pkt Buf Handler Error */
+#define IXGBE_EIMS_DHER         IXGBE_EICR_DHER      /* Descr Handler Error */
+#define IXGBE_EIMS_TCP_TIMER    IXGBE_EICR_TCP_TIMER /* TCP Timer */
+#define IXGBE_EIMS_OTHER        IXGBE_EICR_OTHER     /* INT Cause Active */
+
+/* Extended Interrupt Mask Clear */
+#define IXGBE_EIMC_RTX_QUEUE    IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EIMC_LSC          IXGBE_EICR_LSC       /* Link Status Change */
+#define IXGBE_EIMC_MNG          IXGBE_EICR_MNG       /* MNG Event Interrupt */
+#define IXGBE_EIMC_PBUR         IXGBE_EICR_PBUR      /* Pkt Buf Handler Error */
+#define IXGBE_EIMC_DHER         IXGBE_EICR_DHER      /* Desc Handler Error */
+#define IXGBE_EIMC_TCP_TIMER    IXGBE_EICR_TCP_TIMER /* TCP Timer */
+#define IXGBE_EIMC_OTHER        IXGBE_EICR_OTHER     /* INT Cause Active */
+
+#define IXGBE_EIMS_ENABLE_MASK (\
+				IXGBE_EIMS_RTX_QUEUE       | \
+				IXGBE_EIMS_LSC             | \
+				IXGBE_EIMS_TCP_TIMER       | \
+				IXGBE_EIMS_OTHER)
+
+/* Immediate Interrupt RX (A.K.A. Low Latency Interrupt) */
+#define IXGBE_IMIR_PORT_IM_EN     0x00010000  /* TCP port enable */
+#define IXGBE_IMIR_PORT_BP        0x00020000  /* TCP port check bypass */
+#define IXGBE_IMIREXT_SIZE_BP     0x00001000  /* Packet size bypass */
+#define IXGBE_IMIREXT_CTRL_URG    0x00002000  /* Check URG bit in header */
+#define IXGBE_IMIREXT_CTRL_ACK    0x00004000  /* Check ACK bit in header */
+#define IXGBE_IMIREXT_CTRL_PSH    0x00008000  /* Check PSH bit in header */
+#define IXGBE_IMIREXT_CTRL_RST    0x00010000  /* Check RST bit in header */
+#define IXGBE_IMIREXT_CTRL_SYN    0x00020000  /* Check SYN bit in header */
+#define IXGBE_IMIREXT_CTRL_FIN    0x00040000  /* Check FIN bit in header */
+#define IXGBE_IMIREXT_CTRL_BP     0x00080000  /* Bypass check of control bits */
+
+/* Interrupt clear mask */
+#define IXGBE_IRQ_CLEAR_MASK    0xFFFFFFFF
+
+/* Interrupt Vector Allocation Registers */
+#define IXGBE_IVAR_REG_NUM      25
+#define IXGBE_IVAR_TXRX_ENTRY   96
+#define IXGBE_IVAR_RX_ENTRY     64
+#define IXGBE_IVAR_RX_QUEUE(_i)    (0 + (_i))
+#define IXGBE_IVAR_TX_QUEUE(_i)    (64 + (_i))
+#define IXGBE_IVAR_TX_ENTRY     32
+
+#define IXGBE_IVAR_TCP_TIMER_INDEX       96 /* 0 based index */
+#define IXGBE_IVAR_OTHER_CAUSES_INDEX    97 /* 0 based index */
+
+#define IXGBE_MSIX_VECTOR(_i)   (0 + (_i))
+
+#define IXGBE_IVAR_ALLOC_VAL    0x80 /* Interrupt Allocation valid */
+
+/* VLAN Control Bit Masks */
+#define IXGBE_VLNCTRL_VET       0x0000FFFF  /* bits 0-15 */
+#define IXGBE_VLNCTRL_CFI       0x10000000  /* bit 28 */
+#define IXGBE_VLNCTRL_CFIEN     0x20000000  /* bit 29 */
+#define IXGBE_VLNCTRL_VFE       0x40000000  /* bit 30 */
+#define IXGBE_VLNCTRL_VME       0x80000000  /* bit 31 */
+
+#define IXGBE_ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.1q protocol */
+
+/* STATUS Bit Masks */
+#define IXGBE_STATUS_LAN_ID     0x0000000C /* LAN ID */
+#define IXGBE_STATUS_GIO        0x00080000 /* GIO Master Enable Status */
+
+#define IXGBE_STATUS_LAN_ID_0   0x00000000 /* LAN ID 0 */
+#define IXGBE_STATUS_LAN_ID_1   0x00000004 /* LAN ID 1 */
+
+/* ESDP Bit Masks */
+#define IXGBE_ESDP_SDP4 0x00000001 /* SDP4 Data Value */
+#define IXGBE_ESDP_SDP5 0x00000002 /* SDP5 Data Value */
+#define IXGBE_ESDP_SDP4_DIR     0x00000004 /* SDP4 IO direction */
+#define IXGBE_ESDP_SDP5_DIR     0x00000008 /* SDP5 IO direction */
+
+/* LEDCTL Bit Masks */
+#define IXGBE_LED_IVRT_BASE      0x00000040
+#define IXGBE_LED_BLINK_BASE     0x00000080
+#define IXGBE_LED_MODE_MASK_BASE 0x0000000F
+#define IXGBE_LED_OFFSET(_base, _i) (_base << (8 * (_i)))
+#define IXGBE_LED_MODE_SHIFT(_i) (8*(_i))
+#define IXGBE_LED_IVRT(_i)       IXGBE_LED_OFFSET(IXGBE_LED_IVRT_BASE, _i)
+#define IXGBE_LED_BLINK(_i)      IXGBE_LED_OFFSET(IXGBE_LED_BLINK_BASE, _i)
+#define IXGBE_LED_MODE_MASK(_i)  IXGBE_LED_OFFSET(IXGBE_LED_MODE_MASK_BASE, _i)
+
+/* LED modes */
+#define IXGBE_LED_LINK_UP       0x0
+#define IXGBE_LED_LINK_10G      0x1
+#define IXGBE_LED_MAC           0x2
+#define IXGBE_LED_FILTER        0x3
+#define IXGBE_LED_LINK_ACTIVE   0x4
+#define IXGBE_LED_LINK_1G       0x5
+#define IXGBE_LED_ON            0xE
+#define IXGBE_LED_OFF           0xF
+
+/* AUTOC Bit Masks */
+#define IXGBE_AUTOC_KX4_SUPP    0x80000000
+#define IXGBE_AUTOC_KX_SUPP     0x40000000
+#define IXGBE_AUTOC_PAUSE       0x30000000
+#define IXGBE_AUTOC_RF          0x08000000
+#define IXGBE_AUTOC_PD_TMR      0x06000000
+#define IXGBE_AUTOC_AN_RX_LOOSE 0x01000000
+#define IXGBE_AUTOC_AN_RX_DRIFT 0x00800000
+#define IXGBE_AUTOC_AN_RX_ALIGN 0x007C0000
+#define IXGBE_AUTOC_AN_RESTART  0x00001000
+#define IXGBE_AUTOC_FLU         0x00000001
+#define IXGBE_AUTOC_LMS_SHIFT   13
+#define IXGBE_AUTOC_LMS_MASK   (0x7 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_1G_LINK_NO_AN  (0x0 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_10G_LINK_NO_AN (0x1 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_1G_AN  (0x2 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_KX4_AN (0x4 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_KX4_AN_1G_AN   (0x6 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_ATTACH_TYPE    (0x7 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
+
+#define IXGBE_AUTOC_1G_PMA_PMD      0x00000200
+#define IXGBE_AUTOC_10G_PMA_PMD     0x00000180
+#define IXGBE_AUTOC_10G_PMA_PMD_SHIFT 7
+#define IXGBE_AUTOC_1G_PMA_PMD_SHIFT 9
+#define IXGBE_AUTOC_10G_XAUI   (0x0 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC_10G_KX4    (0x1 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC_10G_CX4    (0x2 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC_1G_BX      (0x0 << IXGBE_AUTOC_1G_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC_1G_KX      (0x1 << IXGBE_AUTOC_1G_PMA_PMD_SHIFT)
+
+/* LINKS Bit Masks */
+#define IXGBE_LINKS_KX_AN_COMP  0x80000000
+#define IXGBE_LINKS_UP          0x40000000
+#define IXGBE_LINKS_SPEED       0x20000000
+#define IXGBE_LINKS_MODE        0x18000000
+#define IXGBE_LINKS_RX_MODE     0x06000000
+#define IXGBE_LINKS_TX_MODE     0x01800000
+#define IXGBE_LINKS_XGXS_EN     0x00400000
+#define IXGBE_LINKS_PCS_1G_EN   0x00200000
+#define IXGBE_LINKS_1G_AN_EN    0x00100000
+#define IXGBE_LINKS_KX_AN_IDLE  0x00080000
+#define IXGBE_LINKS_1G_SYNC     0x00040000
+#define IXGBE_LINKS_10G_ALIGN   0x00020000
+#define IXGBE_LINKS_10G_LANE_SYNC 0x00017000
+#define IXGBE_LINKS_TL_FAULT    0x00001000
+#define IXGBE_LINKS_SIGNAL      0x00000F00
+
+#define IXGBE_AUTO_NEG_TIME     45 /* 4.5 Seconds */
+
+/* SW Semaphore Register bitmasks */
+#define IXGBE_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
+#define IXGBE_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
+#define IXGBE_SWSM_WMNG 0x00000004 /* Wake MNG Clock */
+
+/* GSSR definitions */
+#define IXGBE_GSSR_EEP_SM     0x0001
+#define IXGBE_GSSR_PHY0_SM    0x0002
+#define IXGBE_GSSR_PHY1_SM    0x0004
+#define IXGBE_GSSR_MAC_CSR_SM 0x0008
+#define IXGBE_GSSR_FLASH_SM   0x0010
+
+/* EEC Register */
+#define IXGBE_EEC_SK        0x00000001 /* EEPROM Clock */
+#define IXGBE_EEC_CS        0x00000002 /* EEPROM Chip Select */
+#define IXGBE_EEC_DI        0x00000004 /* EEPROM Data In */
+#define IXGBE_EEC_DO        0x00000008 /* EEPROM Data Out */
+#define IXGBE_EEC_FWE_MASK  0x00000030 /* FLASH Write Enable */
+#define IXGBE_EEC_FWE_DIS   0x00000010 /* Disable FLASH writes */
+#define IXGBE_EEC_FWE_EN    0x00000020 /* Enable FLASH writes */
+#define IXGBE_EEC_FWE_SHIFT 4
+#define IXGBE_EEC_REQ       0x00000040 /* EEPROM Access Request */
+#define IXGBE_EEC_GNT       0x00000080 /* EEPROM Access Grant */
+#define IXGBE_EEC_PRES      0x00000100 /* EEPROM Present */
+#define IXGBE_EEC_ARD       0x00000200 /* EEPROM Auto Read Done */
+/* EEPROM Addressing bits based on type (0-small, 1-large) */
+#define IXGBE_EEC_ADDR_SIZE 0x00000400
+#define IXGBE_EEC_SIZE      0x00007800 /* EEPROM Size */
+
+#define IXGBE_EEC_SIZE_SHIFT          11
+#define IXGBE_EEPROM_WORD_SIZE_SHIFT  6
+#define IXGBE_EEPROM_OPCODE_BITS      8
+
+/* Checksum and EEPROM pointers */
+#define IXGBE_EEPROM_CHECKSUM   0x3F
+#define IXGBE_EEPROM_SUM        0xBABA
+#define IXGBE_PCIE_ANALOG_PTR   0x03
+#define IXGBE_ATLAS0_CONFIG_PTR 0x04
+#define IXGBE_ATLAS1_CONFIG_PTR 0x05
+#define IXGBE_PCIE_GENERAL_PTR  0x06
+#define IXGBE_PCIE_CONFIG0_PTR  0x07
+#define IXGBE_PCIE_CONFIG1_PTR  0x08
+#define IXGBE_CORE0_PTR         0x09
+#define IXGBE_CORE1_PTR         0x0A
+#define IXGBE_MAC0_PTR          0x0B
+#define IXGBE_MAC1_PTR          0x0C
+#define IXGBE_CSR0_CONFIG_PTR   0x0D
+#define IXGBE_CSR1_CONFIG_PTR   0x0E
+#define IXGBE_FW_PTR            0x0F
+#define IXGBE_PBANUM0_PTR       0x15
+#define IXGBE_PBANUM1_PTR       0x16
+
+/* EEPROM Commands - SPI */
+#define IXGBE_EEPROM_MAX_RETRY_SPI      5000 /* Max wait 5ms for RDY signal */
+#define IXGBE_EEPROM_STATUS_RDY_SPI     0x01
+#define IXGBE_EEPROM_READ_OPCODE_SPI    0x03  /* EEPROM read opcode */
+#define IXGBE_EEPROM_WRITE_OPCODE_SPI   0x02  /* EEPROM write opcode */
+#define IXGBE_EEPROM_A8_OPCODE_SPI      0x08  /* opcode bit-3 = addr bit-8 */
+#define IXGBE_EEPROM_WREN_OPCODE_SPI    0x06  /* EEPROM set Write Ena latch */
+/* EEPROM reset Write Enbale latch */
+#define IXGBE_EEPROM_WRDI_OPCODE_SPI    0x04
+#define IXGBE_EEPROM_RDSR_OPCODE_SPI    0x05  /* EEPROM read Status reg */
+#define IXGBE_EEPROM_WRSR_OPCODE_SPI    0x01  /* EEPROM write Status reg */
+#define IXGBE_EEPROM_ERASE4K_OPCODE_SPI 0x20  /* EEPROM ERASE 4KB */
+#define IXGBE_EEPROM_ERASE64K_OPCODE_SPI  0xD8  /* EEPROM ERASE 64KB */
+#define IXGBE_EEPROM_ERASE256_OPCODE_SPI  0xDB  /* EEPROM ERASE 256B */
+
+/* EEPROM Read Register */
+#define IXGBE_EEPROM_READ_REG_DATA   16   /* data offset in EEPROM read reg */
+#define IXGBE_EEPROM_READ_REG_DONE   2    /* Offset to READ done bit */
+#define IXGBE_EEPROM_READ_REG_START  1    /* First bit to start operation */
+#define IXGBE_EEPROM_READ_ADDR_SHIFT 2    /* Shift to the address bits */
+
+#define IXGBE_ETH_LENGTH_OF_ADDRESS   6
+
+#ifndef IXGBE_EEPROM_GRANT_ATTEMPTS
+#define IXGBE_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
+#endif
+
+#ifndef IXGBE_EERD_ATTEMPTS
+/* Number of 5 microseconds we wait for EERD read to complete */
+#define IXGBE_EERD_ATTEMPTS 100000
+#endif
+
+/* PCI Bus Info */
+#define IXGBE_PCI_LINK_STATUS     0xB2
+#define IXGBE_PCI_LINK_WIDTH      0x3F0
+#define IXGBE_PCI_LINK_WIDTH_1    0x10
+#define IXGBE_PCI_LINK_WIDTH_2    0x20
+#define IXGBE_PCI_LINK_WIDTH_4    0x40
+#define IXGBE_PCI_LINK_WIDTH_8    0x80
+#define IXGBE_PCI_LINK_SPEED      0xF
+#define IXGBE_PCI_LINK_SPEED_2500 0x1
+#define IXGBE_PCI_LINK_SPEED_5000 0x2
+
+/* Number of 100 microseconds we wait for PCI Express master disable */
+#define IXGBE_PCI_MASTER_DISABLE_TIMEOUT 800
+
+/* PHY Types */
+#define IXGBE_M88E1145_E_PHY_ID  0x01410CD0
+
+/* Check whether address is multicast.  This is little-endian specific check.*/
+#define IXGBE_IS_MULTICAST(Address) \
+		(bool)(((u8 *)(Address))[0] & ((u8)0x01))
+
+/* Check whether an address is broadcast. */
+#define IXGBE_IS_BROADCAST(Address)                      \
+		((((u8 *)(Address))[0] == ((u8)0xff)) && \
+		(((u8 *)(Address))[1] == ((u8)0xff)))
+
+/* RAH */
+#define IXGBE_RAH_VIND_MASK     0x003C0000
+#define IXGBE_RAH_VIND_SHIFT    18
+#define IXGBE_RAH_AV            0x80000000
+
+/* Filters */
+#define IXGBE_MC_TBL_SIZE       128  /* Multicast Filter Table (4096 bits) */
+#define IXGBE_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
+
+/* Header split receive */
+#define IXGBE_RFCTL_ISCSI_DIS       0x00000001
+#define IXGBE_RFCTL_ISCSI_DWC_MASK  0x0000003E
+#define IXGBE_RFCTL_ISCSI_DWC_SHIFT 1
+#define IXGBE_RFCTL_NFSW_DIS        0x00000040
+#define IXGBE_RFCTL_NFSR_DIS        0x00000080
+#define IXGBE_RFCTL_NFS_VER_MASK    0x00000300
+#define IXGBE_RFCTL_NFS_VER_SHIFT   8
+#define IXGBE_RFCTL_NFS_VER_2       0
+#define IXGBE_RFCTL_NFS_VER_3       1
+#define IXGBE_RFCTL_NFS_VER_4       2
+#define IXGBE_RFCTL_IPV6_DIS        0x00000400
+#define IXGBE_RFCTL_IPV6_XSUM_DIS   0x00000800
+#define IXGBE_RFCTL_IPFRSP_DIS      0x00004000
+#define IXGBE_RFCTL_IPV6_EX_DIS     0x00010000
+#define IXGBE_RFCTL_NEW_IPV6_EXT_DIS 0x00020000
+
+/* Transmit Config masks */
+#define IXGBE_TXDCTL_ENABLE     0x02000000 /* Enable specific Tx Queue */
+#define IXGBE_TXDCTL_SWFLSH     0x04000000 /* Tx Desc. write-back flushing */
+/* Enable short packet padding to 64 bytes */
+#define IXGBE_TX_PAD_ENABLE     0x00000400
+#define IXGBE_JUMBO_FRAME_ENABLE 0x00000004  /* Allow jumbo frames */
+/* This allows for 16K packets + 4k for vlan */
+#define IXGBE_MAX_FRAME_SZ      0x40040000
+
+#define IXGBE_TDWBAL_HEAD_WB_ENABLE   0x1      /* Tx head write-back enable */
+#define IXGBE_TDWBAL_SEQNUM_WB_ENABLE 0x2      /* Tx seq. # write-back enable */
+
+/* Receive Config masks */
+#define IXGBE_RXCTRL_RXEN       0x00000001  /* Enable Receiver */
+#define IXGBE_RXCTRL_DMBYPS     0x00000002  /* Descriptor Monitor Bypass */
+#define IXGBE_RXDCTL_ENABLE     0x02000000  /* Enable specific Rx Queue */
+
+#define IXGBE_FCTRL_SBP 0x00000002 /* Store Bad Packet */
+#define IXGBE_FCTRL_MPE 0x00000100 /* Multicast Promiscuous Ena*/
+#define IXGBE_FCTRL_UPE 0x00000200 /* Unicast Promiscuous Ena */
+#define IXGBE_FCTRL_BAM 0x00000400 /* Broadcast Accept Mode */
+#define IXGBE_FCTRL_PMCF 0x00001000 /* Pass MAC Control Frames */
+#define IXGBE_FCTRL_DPF 0x00002000 /* Discard Pause Frame */
+/* Receive Priority Flow Control Enbale */
+#define IXGBE_FCTRL_RPFCE 0x00004000
+#define IXGBE_FCTRL_RFCE 0x00008000 /* Receive Flow Control Ena */
+
+/* Multiple Receive Queue Control */
+#define IXGBE_MRQC_RSSEN                 0x00000001  /* RSS Enable */
+#define IXGBE_MRQC_RSS_FIELD_MASK        0xFFFF0000
+#define IXGBE_MRQC_RSS_FIELD_IPV4_TCP    0x00010000
+#define IXGBE_MRQC_RSS_FIELD_IPV4        0x00020000
+#define IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP 0x00040000
+#define IXGBE_MRQC_RSS_FIELD_IPV6_EX     0x00080000
+#define IXGBE_MRQC_RSS_FIELD_IPV6        0x00100000
+#define IXGBE_MRQC_RSS_FIELD_IPV6_TCP    0x00200000
+#define IXGBE_MRQC_RSS_FIELD_IPV4_UDP    0x00400000
+#define IXGBE_MRQC_RSS_FIELD_IPV6_UDP    0x00800000
+#define IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP 0x01000000
+
+#define IXGBE_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define IXGBE_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define IXGBE_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define IXGBE_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define IXGBE_TXD_CMD_IC     0x04000000 /* Insert Checksum */
+#define IXGBE_TXD_CMD_RS     0x08000000 /* Report Status */
+#define IXGBE_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define IXGBE_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
+#define IXGBE_TXD_STAT_DD    0x00000001 /* Descriptor Done */
+
+/* Receive Descriptor bit definitions */
+#define IXGBE_RXD_STAT_DD       0x01    /* Descriptor Done */
+#define IXGBE_RXD_STAT_EOP      0x02    /* End of Packet */
+#define IXGBE_RXD_STAT_IXSM     0x04    /* Ignore checksum */
+#define IXGBE_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define IXGBE_RXD_STAT_UDPCS    0x10    /* UDP xsum caculated */
+#define IXGBE_RXD_STAT_L4CS     0x20    /* L4 xsum calculated */
+#define IXGBE_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
+#define IXGBE_RXD_STAT_PIF      0x80    /* passed in-exact filter */
+#define IXGBE_RXD_STAT_CRCV     0x100   /* Speculative CRC Valid */
+#define IXGBE_RXD_STAT_VEXT     0x200   /* 1st VLAN found */
+#define IXGBE_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
+#define IXGBE_RXD_STAT_DYNINT   0x800   /* Pkt caused INT via DYNINT */
+#define IXGBE_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
+#define IXGBE_RXD_ERR_CE        0x01    /* CRC Error */
+#define IXGBE_RXD_ERR_LE        0x02    /* Length Error */
+#define IXGBE_RXD_ERR_PE        0x08    /* Packet Error */
+#define IXGBE_RXD_ERR_OSE       0x10    /* Oversize Error */
+#define IXGBE_RXD_ERR_USE       0x20    /* Undersize Error */
+#define IXGBE_RXD_ERR_TCPE      0x40    /* TCP/UDP Checksum Error */
+#define IXGBE_RXD_ERR_IPE       0x80    /* IP Checksum Error */
+#define IXGBE_RXDADV_HBO        0x00800000
+#define IXGBE_RXDADV_ERR_CE     0x01000000 /* CRC Error */
+#define IXGBE_RXDADV_ERR_LE     0x02000000 /* Length Error */
+#define IXGBE_RXDADV_ERR_PE     0x08000000 /* Packet Error */
+#define IXGBE_RXDADV_ERR_OSE    0x10000000 /* Oversize Error */
+#define IXGBE_RXDADV_ERR_USE    0x20000000 /* Undersize Error */
+#define IXGBE_RXDADV_ERR_TCPE   0x40000000 /* TCP/UDP Checksum Error */
+#define IXGBE_RXDADV_ERR_IPE    0x80000000 /* IP Checksum Error */
+#define IXGBE_RXD_VLAN_ID_MASK  0x0FFF  /* VLAN ID is in lower 12 bits */
+#define IXGBE_RXD_PRI_MASK      0xE000  /* Priority is in upper 3 bits */
+#define IXGBE_RXD_PRI_SHIFT     13
+#define IXGBE_RXD_CFI_MASK      0x1000  /* CFI is bit 12 */
+#define IXGBE_RXD_CFI_SHIFT     12
+
+/* SRRCTL bit definitions */
+#define IXGBE_SRRCTL_BSIZEPKT_SHIFT 10     /* so many KBs */
+#define IXGBE_SRRCTL_BSIZEPKT_MASK  0x0000007F
+#define IXGBE_SRRCTL_BSIZEHDR_MASK  0x00003F00
+#define IXGBE_SRRCTL_DESCTYPE_LEGACY 0x00000000
+#define IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF 0x02000000
+#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT  0x04000000
+#define IXGBE_SRRCTL_DESCTYPE_HDR_REPLICATION_LARGE_PKT 0x08000000
+#define IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS 0x0A000000
+
+#define IXGBE_RXDPS_HDRSTAT_HDRSP       0x00008000
+#define IXGBE_RXDPS_HDRSTAT_HDRLEN_MASK 0x000003FF
+
+#define IXGBE_RXDADV_RSSTYPE_MASK       0x0000000F
+#define IXGBE_RXDADV_PKTTYPE_MASK       0x0000FFF0
+#define IXGBE_RXDADV_HDRBUFLEN_MASK     0x00007FE0
+#define IXGBE_RXDADV_HDRBUFLEN_SHIFT    5
+#define IXGBE_RXDADV_SPLITHEADER_EN     0x00001000
+#define IXGBE_RXDADV_SPH                0x8000
+
+/* RSS Hash results */
+#define IXGBE_RXDADV_RSSTYPE_NONE       0x00000000
+#define IXGBE_RXDADV_RSSTYPE_IPV4_TCP   0x00000001
+#define IXGBE_RXDADV_RSSTYPE_IPV4       0x00000002
+#define IXGBE_RXDADV_RSSTYPE_IPV6_TCP   0x00000003
+#define IXGBE_RXDADV_RSSTYPE_IPV6_EX    0x00000004
+#define IXGBE_RXDADV_RSSTYPE_IPV6       0x00000005
+#define IXGBE_RXDADV_RSSTYPE_IPV6_TCP_EX 0x00000006
+#define IXGBE_RXDADV_RSSTYPE_IPV4_UDP   0x00000007
+#define IXGBE_RXDADV_RSSTYPE_IPV6_UDP   0x00000008
+#define IXGBE_RXDADV_RSSTYPE_IPV6_UDP_EX 0x00000009
+
+/* RSS Packet Types as indicated in the receive descriptor. */
+#define IXGBE_RXDADV_PKTTYPE_NONE       0x00000000
+#define IXGBE_RXDADV_PKTTYPE_IPV4       0x00000010 /* IPv4 hdr present */
+#define IXGBE_RXDADV_PKTTYPE_IPV4_EX    0x00000020 /* IPv4 hdr + extensions */
+#define IXGBE_RXDADV_PKTTYPE_IPV6       0x00000040 /* IPv6 hdr present */
+#define IXGBE_RXDADV_PKTTYPE_IPV6_EX    0x00000080 /* IPv6 hdr + extensions */
+#define IXGBE_RXDADV_PKTTYPE_TCP        0x00000100 /* TCP hdr present */
+#define IXGBE_RXDADV_PKTTYPE_UDP        0x00000200 /* UDP hdr present */
+#define IXGBE_RXDADV_PKTTYPE_SCTP       0x00000400 /* SCTP hdr present */
+#define IXGBE_RXDADV_PKTTYPE_NFS        0x00000800 /* NFS hdr present */
+
+/* Masks to determine if packets should be dropped due to frame errors */
+#define IXGBE_RXD_ERR_FRAME_ERR_MASK (\
+				      IXGBE_RXD_ERR_CE | \
+				      IXGBE_RXD_ERR_LE | \
+				      IXGBE_RXD_ERR_PE | \
+				      IXGBE_RXD_ERR_OSE | \
+				      IXGBE_RXD_ERR_USE)
+
+#define IXGBE_RXDADV_ERR_FRAME_ERR_MASK (\
+				      IXGBE_RXDADV_ERR_CE | \
+				      IXGBE_RXDADV_ERR_LE | \
+				      IXGBE_RXDADV_ERR_PE | \
+				      IXGBE_RXDADV_ERR_OSE | \
+				      IXGBE_RXDADV_ERR_USE)
+
+/* Multicast bit mask */
+#define IXGBE_MCSTCTRL_MFE      0x4
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define IXGBE_REQ_TX_DESCRIPTOR_MULTIPLE  8
+#define IXGBE_REQ_RX_DESCRIPTOR_MULTIPLE  8
+#define IXGBE_REQ_TX_BUFFER_GRANULARITY   1024
+
+/* Vlan-specific macros */
+#define IXGBE_RX_DESC_SPECIAL_VLAN_MASK  0x0FFF /* VLAN ID in lower 12 bits */
+#define IXGBE_RX_DESC_SPECIAL_PRI_MASK   0xE000 /* Priority in upper 3 bits */
+#define IXGBE_RX_DESC_SPECIAL_PRI_SHIFT  0x000D /* Priority in upper 3 of 16 */
+#define IXGBE_TX_DESC_SPECIAL_PRI_SHIFT  IXGBE_RX_DESC_SPECIAL_PRI_SHIFT
+
+/* Transmit Descriptor - Legacy */
+struct ixgbe_legacy_tx_desc {
+	u64 buffer_addr;       /* Address of the descriptor's data buffer */
+	union {
+		u32 data;
+		struct {
+			u16 length;    /* Data buffer length */
+			u8 cso; /* Checksum offset */
+			u8 cmd; /* Descriptor control */
+		} flags;
+	} lower;
+	union {
+		u32 data;
+		struct {
+			u8 status;     /* Descriptor status */
+			u8 css; /* Checksum start */
+			u16 vlan;
+		} fields;
+	} upper;
+};
+
+/* Transmit Descriptor - Advanced */
+union ixgbe_adv_tx_desc {
+	struct {
+		u64 buffer_addr;       /* Address of descriptor's data buf */
+		u32 cmd_type_len;
+		u32 olinfo_status;
+	} read;
+	struct {
+		u64 rsvd;       /* Reserved */
+		u32 nxtseq_seed;
+		u32 status;
+	} wb;
+};
+
+/* Receive Descriptor - Legacy */
+struct ixgbe_legacy_rx_desc {
+	u64 buffer_addr; /* Address of the descriptor's data buffer */
+	u16 length;      /* Length of data DMAed into data buffer */
+	u16 csum;        /* Packet checksum */
+	u8 status;       /* Descriptor status */
+	u8 errors;       /* Descriptor Errors */
+	u16 vlan;
+};
+
+/* Receive Descriptor - Advanced */
+union ixgbe_adv_rx_desc {
+	struct {
+		u64 pkt_addr; /* Packet buffer address */
+		u64 hdr_addr; /* Header buffer address */
+	} read;
+	struct {
+		struct {
+			struct {
+				u16 pkt_info; /* RSS type, Packet type */
+				u16 hdr_info; /* Split Header, header len */
+			} lo_dword;
+			union {
+				u32 rss; /* RSS Hash */
+				struct {
+					u16 ip_id; /* IP id */
+					u16 csum; /* Packet Checksum */
+				} csum_ip;
+			} hi_dword;
+		} lower;
+		struct {
+			u32 status_error; /* ext status/error */
+			u16 length; /* Packet length */
+			u16 vlan; /* VLAN tag */
+		} upper;
+	} wb;  /* writeback */
+};
+
+/* Context descriptors */
+struct ixgbe_adv_tx_context_desc {
+	u32 vlan_macip_lens;
+	u32 seqnum_seed;
+	u32 type_tucmd_mlhl;
+	u32 mss_l4len_idx;
+};
+
+/* Adv Transmit Descriptor Config Masks */
+#define IXGBE_ADVTXD_DTALEN_MASK      0x0000FFFF /* Data buffer length(bytes) */
+#define IXGBE_ADVTXD_DTYP_MASK  0x00F00000 /* DTYP mask */
+#define IXGBE_ADVTXD_DTYP_CTXT  0x00200000 /* Advanced Context Desc */
+#define IXGBE_ADVTXD_DTYP_DATA  0x00300000 /* Advanced Data Descriptor */
+#define IXGBE_ADVTXD_DCMD_EOP   IXGBE_TXD_CMD_EOP  /* End of Packet */
+#define IXGBE_ADVTXD_DCMD_IFCS  IXGBE_TXD_CMD_IFCS /* Insert FCS */
+#define IXGBE_ADVTXD_DCMD_RDMA  0x04000000 /* RDMA */
+#define IXGBE_ADVTXD_DCMD_RS    IXGBE_TXD_CMD_RS   /* Report Status */
+#define IXGBE_ADVTXD_DCMD_DDTYP_ISCSI 0x10000000     /* DDP hdr type or iSCSI */
+#define IXGBE_ADVTXD_DCMD_DEXT  IXGBE_TXD_CMD_DEXT /* Desc ext (1=Adv) */
+#define IXGBE_ADVTXD_DCMD_VLE   IXGBE_TXD_CMD_VLE  /* VLAN pkt enable */
+#define IXGBE_ADVTXD_DCMD_TSE   0x80000000 /* TCP Seg enable */
+#define IXGBE_ADVTXD_STAT_DD    IXGBE_TXD_STAT_DD  /* Descriptor Done */
+#define IXGBE_ADVTXD_STAT_SN_CRC      0x00000002 /* NXTSEQ/SEED present in WB */
+#define IXGBE_ADVTXD_STAT_RSV   0x0000000C /* STA Reserved */
+#define IXGBE_ADVTXD_IDX_SHIFT  4 /* Adv desc Index shift */
+#define IXGBE_ADVTXD_POPTS_SHIFT      8  /* Adv desc POPTS shift */
+#define IXGBE_ADVTXD_POPTS_IXSM (IXGBE_TXD_POPTS_IXSM << \
+				IXGBE_ADVTXD_POPTS_SHIFT)
+#define IXGBE_ADVTXD_POPTS_TXSM (IXGBE_TXD_POPTS_TXSM << \
+				IXGBE_ADVTXD_POPTS_SHIFT)
+#define IXGBE_ADVTXD_POPTS_EOM  0x00000400 /* Enable L bit-RDMA DDP hdr */
+#define IXGBE_ADVTXD_POPTS_ISCO_1ST   0x00000000 /* 1st TSO of iSCSI PDU */
+#define IXGBE_ADVTXD_POPTS_ISCO_MDL   0x00000800 /* Middle TSO of iSCSI PDU */
+#define IXGBE_ADVTXD_POPTS_ISCO_LAST  0x00001000 /* Last TSO of iSCSI PDU */
+#define IXGBE_ADVTXD_POPTS_ISCO_FULL 0x00001800 /* 1st&Last TSO-full iSCSI PDU*/
+#define IXGBE_ADVTXD_POPTS_RSV  0x00002000 /* POPTS Reserved */
+#define IXGBE_ADVTXD_PAYLEN_SHIFT  14 /* Adv desc PAYLEN shift */
+#define IXGBE_ADVTXD_MACLEN_SHIFT  9  /* Adv ctxt desc mac len shift */
+#define IXGBE_ADVTXD_VLAN_SHIFT    16  /* Adv ctxt vlan tag shift */
+#define IXGBE_ADVTXD_TUCMD_IPV4    0x00000400  /* IP Packet Type: 1=IPv4 */
+#define IXGBE_ADVTXD_TUCMD_IPV6    0x00000000  /* IP Packet Type: 0=IPv6 */
+#define IXGBE_ADVTXD_TUCMD_L4T_UDP 0x00000000  /* L4 Packet TYPE of UDP */
+#define IXGBE_ADVTXD_TUCMD_L4T_TCP 0x00000800  /* L4 Packet TYPE of TCP */
+#define IXGBE_ADVTXD_TUCMD_MKRREQ  0x00002000 /* Req requires Markers and CRC */
+#define IXGBE_ADVTXD_L4LEN_SHIFT   8  /* Adv ctxt L4LEN shift */
+#define IXGBE_ADVTXD_MSS_SHIFT     16  /* Adv ctxt MSS shift */
+
+/* Link speed */
+#define IXGBE_LINK_SPEED_UNKNOWN   0
+#define IXGBE_LINK_SPEED_100_FULL  0x0008
+#define IXGBE_LINK_SPEED_1GB_FULL  0x0020
+#define IXGBE_LINK_SPEED_10GB_FULL 0x0080
+
+
+enum ixgbe_eeprom_type {
+	ixgbe_eeprom_uninitialized = 0,
+	ixgbe_eeprom_spi,
+	ixgbe_eeprom_none /* No NVM support */
+};
+
+enum ixgbe_mac_type {
+	ixgbe_mac_unknown = 0,
+	ixgbe_mac_82598EB,
+	ixgbe_num_macs
+};
+
+enum ixgbe_phy_type {
+	ixgbe_phy_unknown = 0,
+	ixgbe_phy_tn,
+	ixgbe_phy_qt,
+	ixgbe_phy_xaui
+};
+
+enum ixgbe_media_type {
+	ixgbe_media_type_unknown = 0,
+	ixgbe_media_type_fiber,
+	ixgbe_media_type_copper,
+	ixgbe_media_type_backplane
+};
+
+/* Flow Control Settings */
+enum ixgbe_fc_type {
+	ixgbe_fc_none = 0,
+	ixgbe_fc_rx_pause,
+	ixgbe_fc_tx_pause,
+	ixgbe_fc_full,
+	ixgbe_fc_default
+};
+
+struct ixgbe_addr_filter_info {
+	u32 num_mc_addrs;
+	u32 rar_used_count;
+	u32 mc_addr_in_rar_count;
+	u32 mta_in_use;
+};
+
+/* Flow control parameters */
+struct ixgbe_fc_info {
+	u32 high_water; /* Flow Control High-water */
+	u32 low_water; /* Flow Control Low-water */
+	u16 pause_time; /* Flow Control Pause timer */
+	bool send_xon; /* Flow control send XON */
+	bool strict_ieee; /* Strict IEEE mode */
+	enum ixgbe_fc_type type; /* Type of flow control */
+	enum ixgbe_fc_type original_type;
+};
+
+/* Statistics counters collected by the MAC */
+struct ixgbe_hw_stats {
+	u64 crcerrs;
+	u64 illerrc;
+	u64 errbc;
+	u64 mspdc;
+	u64 mpctotal;
+	u64 mpc[8];
+	u64 mlfc;
+	u64 mrfc;
+	u64 rlec;
+	u64 lxontxc;
+	u64 lxonrxc;
+	u64 lxofftxc;
+	u64 lxoffrxc;
+	u64 pxontxc[8];
+	u64 pxonrxc[8];
+	u64 pxofftxc[8];
+	u64 pxoffrxc[8];
+	u64 prc64;
+	u64 prc127;
+	u64 prc255;
+	u64 prc511;
+	u64 prc1023;
+	u64 prc1522;
+	u64 gprc;
+	u64 bprc;
+	u64 mprc;
+	u64 gptc;
+	u64 gorc;
+	u64 gotc;
+	u64 rnbc[8];
+	u64 ruc;
+	u64 rfc;
+	u64 roc;
+	u64 rjc;
+	u64 mngprc;
+	u64 mngpdc;
+	u64 mngptc;
+	u64 tor;
+	u64 tpr;
+	u64 tpt;
+	u64 ptc64;
+	u64 ptc127;
+	u64 ptc255;
+	u64 ptc511;
+	u64 ptc1023;
+	u64 ptc1522;
+	u64 mptc;
+	u64 bptc;
+	u64 xec;
+	u64 rqsmr[16];
+	u64 tqsmr[8];
+	u64 qprc[16];
+	u64 qptc[16];
+	u64 qbrc[16];
+	u64 qbtc[16];
+};
+
+/* forward declaration */
+struct ixgbe_hw;
+
+struct ixgbe_mac_operations {
+	s32 (*reset)(struct ixgbe_hw *);
+	enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *);
+};
+
+struct ixgbe_phy_operations {
+	s32 (*setup)(struct ixgbe_hw *);
+	s32 (*check)(struct ixgbe_hw *, u32 *, bool *);
+	s32 (*setup_speed)(struct ixgbe_hw *, u32, bool, bool);
+	s32 (*get_settings)(struct ixgbe_hw *, u32 *, bool *);
+};
+
+struct ixgbe_mac_info {
+	struct ixgbe_mac_operations	ops;
+	enum ixgbe_mac_type		type;
+	u8				addr[IXGBE_ETH_LENGTH_OF_ADDRESS];
+	u8				perm_addr[IXGBE_ETH_LENGTH_OF_ADDRESS];
+	s32				mc_filter_type;
+	u32				num_rx_queues;
+	u32				num_tx_queues;
+	u32				num_rx_addrs;
+	u32				link_attach_type;
+	u32				link_mode_select;
+	bool				link_settings_loaded;
+};
+
+
+struct ixgbe_eeprom_info {
+	enum ixgbe_eeprom_type		type;
+	u16				word_size;
+	u16				address_bits;
+};
+
+struct ixgbe_phy_info {
+	struct ixgbe_phy_operations	ops;
+
+	enum ixgbe_phy_type		type;
+	u32				addr;
+	u32				id;
+	u32				revision;
+	enum ixgbe_media_type		media_type;
+	u32				autoneg_advertised;
+	bool				autoneg_wait_to_complete;
+};
+
+struct ixgbe_info {
+	enum ixgbe_mac_type		mac;
+	s32 				(*get_invariants)(struct ixgbe_hw *);
+	struct ixgbe_mac_operations	*mac_ops;
+	struct ixgbe_phy_operations	*phy_ops;
+};
+
+struct ixgbe_hw {
+	u8 __iomem			*hw_addr;
+	void				*back;
+	struct ixgbe_mac_info		mac;
+	struct ixgbe_addr_filter_info	addr_ctrl;
+	struct ixgbe_fc_info		fc;
+	struct ixgbe_phy_info		phy;
+	struct ixgbe_eeprom_info	eeprom;
+	u16				device_id;
+	u16				vendor_id;
+	u16				subsystem_device_id;
+	u16				subsystem_vendor_id;
+	u8				revision_id;
+	bool				adapter_stopped;
+};
+
+/* Error Codes */
+#define IXGBE_ERR_EEPROM                        -1
+#define IXGBE_ERR_EEPROM_CHECKSUM               -2
+#define IXGBE_ERR_PHY                           -3
+#define IXGBE_ERR_CONFIG                        -4
+#define IXGBE_ERR_PARAM                         -5
+#define IXGBE_ERR_MAC_TYPE                      -6
+#define IXGBE_ERR_UNKNOWN_PHY                   -7
+#define IXGBE_ERR_LINK_SETUP                    -8
+#define IXGBE_ERR_ADAPTER_STOPPED               -9
+#define IXGBE_ERR_INVALID_MAC_ADDR              -10
+#define IXGBE_ERR_DEVICE_NOT_SUPPORTED          -11
+#define IXGBE_ERR_MASTER_REQUESTS_PENDING       -12
+#define IXGBE_ERR_INVALID_LINK_SETTINGS         -13
+#define IXGBE_ERR_AUTONEG_NOT_COMPLETE          -14
+#define IXGBE_ERR_RESET_FAILED                  -15
+#define IXGBE_ERR_SWFW_SYNC                     -16
+#define IXGBE_ERR_PHY_ADDR_INVALID              -17
+#define IXGBE_NOT_IMPLEMENTED                   0x7FFFFFFF
+
+#endif /* _IXGBE_TYPE_H_ */
diff --git a/drivers/net/ixp2000/enp2611.c b/drivers/net/ixp2000/enp2611.c
index d3f4235..b02a981 100644
--- a/drivers/net/ixp2000/enp2611.c
+++ b/drivers/net/ixp2000/enp2611.c
@@ -210,7 +210,6 @@
 			return -ENOMEM;
 		}
 
-		SET_MODULE_OWNER(nds[i]);
 		nds[i]->get_stats = enp2611_get_stats;
 		pm3386_init_port(i);
 		pm3386_get_mac(i, nds[i]->dev_addr);
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c
index d9ce1ae..6c0dd49 100644
--- a/drivers/net/ixp2000/ixpdev.c
+++ b/drivers/net/ixp2000/ixpdev.c
@@ -74,9 +74,9 @@
 }
 
 
-static int ixpdev_rx(struct net_device *dev, int *budget)
+static int ixpdev_rx(struct net_device *dev, int processed, int budget)
 {
-	while (*budget > 0) {
+	while (processed < budget) {
 		struct ixpdev_rx_desc *desc;
 		struct sk_buff *skb;
 		void *buf;
@@ -122,29 +122,34 @@
 
 err:
 		ixp2000_reg_write(RING_RX_PENDING, _desc);
-		dev->quota--;
-		(*budget)--;
+		processed++;
 	}
 
-	return 1;
+	return processed;
 }
 
 /* dev always points to nds[0].  */
-static int ixpdev_poll(struct net_device *dev, int *budget)
+static int ixpdev_poll(struct napi_struct *napi, int budget)
 {
+	struct ixpdev_priv *ip = container_of(napi, struct ixpdev_priv, napi);
+	struct net_device *dev = ip->dev;
+	int rx;
+
 	/* @@@ Have to stop polling when nds[0] is administratively
 	 * downed while we are polling.  */
+	rx = 0;
 	do {
 		ixp2000_reg_write(IXP2000_IRQ_THD_RAW_STATUS_A_0, 0x00ff);
 
-		if (ixpdev_rx(dev, budget))
-			return 1;
+		rx = ixpdev_rx(dev, rx, budget);
+		if (rx >= budget)
+			break;
 	} while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff);
 
-	netif_rx_complete(dev);
+	netif_rx_complete(dev, napi);
 	ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff);
 
-	return 0;
+	return rx;
 }
 
 static void ixpdev_tx_complete(void)
@@ -199,9 +204,12 @@
 	 * Any of the eight receive units signaled RX?
 	 */
 	if (status & 0x00ff) {
+		struct net_device *dev = nds[0];
+		struct ixpdev_priv *ip = netdev_priv(dev);
+
 		ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff);
-		if (likely(__netif_rx_schedule_prep(nds[0]))) {
-			__netif_rx_schedule(nds[0]);
+		if (likely(napi_schedule_prep(&ip->napi))) {
+			__netif_rx_schedule(dev, &ip->napi);
 		} else {
 			printk(KERN_CRIT "ixp2000: irq while polling!!\n");
 		}
@@ -232,11 +240,13 @@
 	struct ixpdev_priv *ip = netdev_priv(dev);
 	int err;
 
+	napi_enable(&ip->napi);
 	if (!nds_open++) {
 		err = request_irq(IRQ_IXP2000_THDA0, ixpdev_interrupt,
 					IRQF_SHARED, "ixp2000_eth", nds);
 		if (err) {
 			nds_open--;
+			napi_disable(&ip->napi);
 			return err;
 		}
 
@@ -254,6 +264,7 @@
 	struct ixpdev_priv *ip = netdev_priv(dev);
 
 	netif_stop_queue(dev);
+	napi_disable(&ip->napi);
 	set_port_admin_status(ip->channel, 0);
 
 	if (!--nds_open) {
@@ -274,7 +285,6 @@
 		return NULL;
 
 	dev->hard_start_xmit = ixpdev_xmit;
-	dev->poll = ixpdev_poll;
 	dev->open = ixpdev_open;
 	dev->stop = ixpdev_close;
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -282,9 +292,10 @@
 #endif
 
 	dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
-	dev->weight = 64;
 
 	ip = netdev_priv(dev);
+	ip->dev = dev;
+	netif_napi_add(dev, &ip->napi, ixpdev_poll, 64);
 	ip->channel = channel;
 	ip->tx_queue_entries = 0;
 
diff --git a/drivers/net/ixp2000/ixpdev.h b/drivers/net/ixp2000/ixpdev.h
index bd686cb..391ece6 100644
--- a/drivers/net/ixp2000/ixpdev.h
+++ b/drivers/net/ixp2000/ixpdev.h
@@ -14,6 +14,8 @@
 
 struct ixpdev_priv
 {
+	struct net_device *dev;
+	struct napi_struct napi;
 	int	channel;
 	int	tx_queue_entries;
 };
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
index 75f6f44..d3825c8 100644
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/jazzsonic.c
@@ -45,7 +45,6 @@
 #include <asm/jazzdma.h>
 
 static char jazz_sonic_string[] = "jazzsonic";
-static struct platform_device *jazz_sonic_device;
 
 #define SONIC_MEM_SIZE	0x100
 
@@ -70,14 +69,6 @@
 #endif
 
 /*
- * Base address and interrupt of the SONIC controller on JAZZ boards
- */
-static struct {
-	unsigned int port;
-	unsigned int irq;
-} sonic_portlist[] = { {JAZZ_ETHERNET_BASE, JAZZ_ETHERNET_IRQ}, {0, 0}};
-
-/*
  * We cannot use station (ethernet) address prefixes to detect the
  * sonic controller since these are board manufacturer depended.
  * So we check for known Silicon Revision IDs instead.
@@ -215,13 +206,13 @@
 {
 	struct net_device *dev;
 	struct sonic_local *lp;
+	struct resource *res;
 	int err = 0;
 	int i;
+	DECLARE_MAC_BUF(mac);
 
-	/*
-	 * Don't probe if we're not running on a Jazz board.
-	 */
-	if (mips_machgroup != MACH_GROUP_JAZZ)
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
 		return -ENODEV;
 
 	dev = alloc_etherdev(sizeof(struct sonic_local));
@@ -231,37 +222,20 @@
 	lp = netdev_priv(dev);
 	lp->device = &pdev->dev;
 	SET_NETDEV_DEV(dev, &pdev->dev);
- 	SET_MODULE_OWNER(dev);
 
 	netdev_boot_setup_check(dev);
 
-	if (dev->base_addr >= KSEG0) { /* Check a single specified location. */
-		err = sonic_probe1(dev);
-	} else if (dev->base_addr != 0) { /* Don't probe at all. */
-		err = -ENXIO;
-	} else {
-		for (i = 0; sonic_portlist[i].port; i++) {
-			dev->base_addr = sonic_portlist[i].port;
-			dev->irq = sonic_portlist[i].irq;
-			if (sonic_probe1(dev) == 0)
-				break;
-		}
-		if (!sonic_portlist[i].port)
-			err = -ENODEV;
-	}
+	dev->base_addr = res->start;
+	dev->irq = platform_get_irq(pdev, 0);
+	err = sonic_probe1(dev);
 	if (err)
 		goto out;
 	err = register_netdev(dev);
 	if (err)
 		goto out1;
 
-	printk("%s: MAC ", dev->name);
-	for (i = 0; i < 6; i++) {
-		printk("%2.2x", dev->dev_addr[i]);
-		if (i < 5)
-			printk(":");
-	}
-	printk(" IRQ %d\n", dev->irq);
+	printk("%s: MAC %s IRQ %d\n",
+	       dev->name, print_mac(mac, dev->dev_addr), dev->irq);
 
 	return 0;
 
@@ -303,38 +277,12 @@
 
 static int __init jazz_sonic_init_module(void)
 {
-	int err;
-
-	if ((err = platform_driver_register(&jazz_sonic_driver))) {
-		printk(KERN_ERR "Driver registration failed\n");
-		return err;
-	}
-
-	jazz_sonic_device = platform_device_alloc(jazz_sonic_string, 0);
-	if (!jazz_sonic_device)
-		goto out_unregister;
-
-	if (platform_device_add(jazz_sonic_device)) {
-		platform_device_put(jazz_sonic_device);
-		jazz_sonic_device = NULL;
-	}
-
-	return 0;
-
-out_unregister:
-	platform_driver_unregister(&jazz_sonic_driver);
-
-	return -ENOMEM;
+	return platform_driver_register(&jazz_sonic_driver);
 }
 
 static void __exit jazz_sonic_cleanup_module(void)
 {
 	platform_driver_unregister(&jazz_sonic_driver);
-
-	if (jazz_sonic_device) {
-		platform_device_unregister(jazz_sonic_device);
-		jazz_sonic_device = NULL;
-	}
 }
 
 module_init(jazz_sonic_init_module);
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index a2f37e5..977ed34 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -466,6 +466,7 @@
 	unsigned long flags;
 	int err = -ENOMEM;
 	void __iomem *bios;
+	DECLARE_MAC_BUF(mac);
 
 	/* First we look for special cases.
 	   Check for HP's on-board ethernet by looking for 'HP' in the BIOS.
@@ -521,23 +522,22 @@
 
 	/* We can't allocate dev->priv from alloc_etherdev() because it must
 	   a ISA DMA-able region. */
-	SET_MODULE_OWNER(dev);
 	chipname = chip_table[lance_version].name;
-	printk("%s: %s at %#3x,", dev->name, chipname, ioaddr);
+	printk("%s: %s at %#3x, ", dev->name, chipname, ioaddr);
 
 	/* There is a 16 byte station address PROM at the base address.
 	   The first six bytes are the station address. */
 	for (i = 0; i < 6; i++)
-		printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
+		dev->dev_addr[i] = inb(ioaddr + i);
+	printk("%s", print_mac(mac, dev->dev_addr));
 
 	dev->base_addr = ioaddr;
 	/* Make certain the data structures used by the LANCE are aligned and DMAble. */
 
-	lp = kmalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
+	lp = kzalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
 	if(lp==NULL)
 		return -ENODEV;
 	if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp);
-	memset(lp, 0, sizeof(*lp));
 	dev->priv = lp;
 	lp->name = chipname;
 	lp->rx_buffs = (unsigned long)kmalloc(PKT_BUF_SZ*RX_RING_SIZE,
diff --git a/drivers/net/lguest_net.c b/drivers/net/lguest_net.c
new file mode 100644
index 0000000..abce2ee
--- /dev/null
+++ b/drivers/net/lguest_net.c
@@ -0,0 +1,555 @@
+/*D:500
+ * The Guest network driver.
+ *
+ * This is very simple a virtual network driver, and our last Guest driver.
+ * The only trick is that it can talk directly to multiple other recipients
+ * (ie. other Guests on the same network).  It can also be used with only the
+ * Host on the network.
+ :*/
+
+/* Copyright 2006 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
+ *
+ * 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
+ */
+//#define DEBUG
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/mm_types.h>
+#include <linux/io.h>
+#include <linux/lguest_bus.h>
+
+#define SHARED_SIZE		PAGE_SIZE
+#define MAX_LANS		4
+#define NUM_SKBS		8
+
+/*M:011 Network code master Jeff Garzik points out numerous shortcomings in
+ * this driver if it aspires to greatness.
+ *
+ * Firstly, it doesn't use "NAPI": the networking's New API, and is poorer for
+ * it.  As he says "NAPI means system-wide load leveling, across multiple
+ * network interfaces.  Lack of NAPI can mean competition at higher loads."
+ *
+ * He also points out that we don't implement set_mac_address, so users cannot
+ * change the devices hardware address.  When I asked why one would want to:
+ * "Bonding, and situations where you /do/ want the MAC address to "leak" out
+ * of the host onto the wider net."
+ *
+ * Finally, he would like module unloading: "It is not unrealistic to think of
+ * [un|re|]loading the net support module in an lguest guest.  And, adding
+ * module support makes the programmer more responsible, because they now have
+ * to learn to clean up after themselves.  Any driver that cannot clean up
+ * after itself is an incomplete driver in my book."
+ :*/
+
+/*D:530 The "struct lguestnet_info" contains all the information we need to
+ * know about the network device. */
+struct lguestnet_info
+{
+	/* The mapped device page(s) (an array of "struct lguest_net"). */
+	struct lguest_net *peer;
+	/* The physical address of the device page(s) */
+	unsigned long peer_phys;
+	/* The size of the device page(s). */
+	unsigned long mapsize;
+
+	/* The lguest_device I come from */
+	struct lguest_device *lgdev;
+
+	/* My peerid (ie. my slot in the array). */
+	unsigned int me;
+
+	/* Receive queue: the network packets waiting to be filled. */
+	struct sk_buff *skb[NUM_SKBS];
+	struct lguest_dma dma[NUM_SKBS];
+};
+/*:*/
+
+/* How many bytes left in this page. */
+static unsigned int rest_of_page(void *data)
+{
+	return PAGE_SIZE - ((unsigned long)data % PAGE_SIZE);
+}
+
+/*D:570 Each peer (ie. Guest or Host) on the network binds their receive
+ * buffers to a different key: we simply use the physical address of the
+ * device's memory page plus the peer number.  The Host insists that all keys
+ * be a multiple of 4, so we multiply the peer number by 4. */
+static unsigned long peer_key(struct lguestnet_info *info, unsigned peernum)
+{
+	return info->peer_phys + 4 * peernum;
+}
+
+/* This is the routine which sets up a "struct lguest_dma" to point to a
+ * network packet, similar to req_to_dma() in lguest_blk.c.  The structure of a
+ * "struct sk_buff" has grown complex over the years: it consists of a "head"
+ * linear section pointed to by "skb->data", and possibly an array of
+ * "fragments" in the case of a non-linear packet.
+ *
+ * Our receive buffers don't use fragments at all but outgoing skbs might, so
+ * we handle it. */
+static void skb_to_dma(const struct sk_buff *skb, unsigned int headlen,
+		       struct lguest_dma *dma)
+{
+	unsigned int i, seg;
+
+	/* First, we put the linear region into the "struct lguest_dma".  Each
+	 * entry can't go over a page boundary, so even though all our packets
+	 * are 1514 bytes or less, we might need to use two entries here: */
+	for (i = seg = 0; i < headlen; seg++, i += rest_of_page(skb->data+i)) {
+		dma->addr[seg] = virt_to_phys(skb->data + i);
+		dma->len[seg] = min((unsigned)(headlen - i),
+				    rest_of_page(skb->data + i));
+	}
+
+	/* Now we handle the fragments: at least they're guaranteed not to go
+	 * over a page.  skb_shinfo(skb) returns a pointer to the structure
+	 * which tells us about the number of fragments and the fragment
+	 * array. */
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++, seg++) {
+		const skb_frag_t *f = &skb_shinfo(skb)->frags[i];
+		/* Should not happen with MTU less than 64k - 2 * PAGE_SIZE. */
+		if (seg == LGUEST_MAX_DMA_SECTIONS) {
+			/* We will end up sending a truncated packet should
+			 * this ever happen.  Plus, a cool log message! */
+			printk("Woah dude!  Megapacket!\n");
+			break;
+		}
+		dma->addr[seg] = page_to_phys(f->page) + f->page_offset;
+		dma->len[seg] = f->size;
+	}
+
+	/* If after all that we didn't use the entire "struct lguest_dma"
+	 * array, we terminate it with a 0 length. */
+	if (seg < LGUEST_MAX_DMA_SECTIONS)
+		dma->len[seg] = 0;
+}
+
+/*
+ * Packet transmission.
+ *
+ * Our packet transmission is a little unusual.  A real network card would just
+ * send out the packet and leave the receivers to decide if they're interested.
+ * Instead, we look through the network device memory page and see if any of
+ * the ethernet addresses match the packet destination, and if so we send it to
+ * that Guest.
+ *
+ * This is made a little more complicated in two cases.  The first case is
+ * broadcast packets: for that we send the packet to all Guests on the network,
+ * one at a time.  The second case is "promiscuous" mode, where a Guest wants
+ * to see all the packets on the network.  We need a way for the Guest to tell
+ * us it wants to see all packets, so it sets the "multicast" bit on its
+ * published MAC address, which is never valid in a real ethernet address.
+ */
+#define PROMISC_BIT		0x01
+
+/* This is the callback which is summoned whenever the network device's
+ * multicast or promiscuous state changes.  If the card is in promiscuous mode,
+ * we advertise that in our ethernet address in the device's memory.  We do the
+ * same if Linux wants any or all multicast traffic.  */
+static void lguestnet_set_multicast(struct net_device *dev)
+{
+	struct lguestnet_info *info = netdev_priv(dev);
+
+	if ((dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) || dev->mc_count)
+		info->peer[info->me].mac[0] |= PROMISC_BIT;
+	else
+		info->peer[info->me].mac[0] &= ~PROMISC_BIT;
+}
+
+/* A simple test function to see if a peer wants to see all packets.*/
+static int promisc(struct lguestnet_info *info, unsigned int peer)
+{
+	return info->peer[peer].mac[0] & PROMISC_BIT;
+}
+
+/* Another simple function to see if a peer's advertised ethernet address
+ * matches a packet's destination ethernet address. */
+static int mac_eq(const unsigned char mac[ETH_ALEN],
+		  struct lguestnet_info *info, unsigned int peer)
+{
+	/* Ignore multicast bit, which peer turns on to mean promisc. */
+	if ((info->peer[peer].mac[0] & (~PROMISC_BIT)) != mac[0])
+		return 0;
+	return memcmp(mac+1, info->peer[peer].mac+1, ETH_ALEN-1) == 0;
+}
+
+/* This is the function which actually sends a packet once we've decided a
+ * peer wants it: */
+static void transfer_packet(struct net_device *dev,
+			    struct sk_buff *skb,
+			    unsigned int peernum)
+{
+	struct lguestnet_info *info = netdev_priv(dev);
+	struct lguest_dma dma;
+
+	/* We use our handy "struct lguest_dma" packing function to prepare
+	 * the skb for sending. */
+	skb_to_dma(skb, skb_headlen(skb), &dma);
+	pr_debug("xfer length %04x (%u)\n", htons(skb->len), skb->len);
+
+	/* This is the actual send call which copies the packet. */
+	lguest_send_dma(peer_key(info, peernum), &dma);
+
+	/* Check that the entire packet was transmitted.  If not, it could mean
+	 * that the other Guest registered a short receive buffer, but this
+	 * driver should never do that.  More likely, the peer is dead. */
+	if (dma.used_len != skb->len) {
+		dev->stats.tx_carrier_errors++;
+		pr_debug("Bad xfer to peer %i: %i of %i (dma %p/%i)\n",
+			 peernum, dma.used_len, skb->len,
+			 (void *)dma.addr[0], dma.len[0]);
+	} else {
+		/* On success we update the stats. */
+		dev->stats.tx_bytes += skb->len;
+		dev->stats.tx_packets++;
+	}
+}
+
+/* Another helper function to tell is if a slot in the device memory is unused.
+ * Since we always set the Local Assignment bit in the ethernet address, the
+ * first byte can never be 0. */
+static int unused_peer(const struct lguest_net peer[], unsigned int num)
+{
+	return peer[num].mac[0] == 0;
+}
+
+/* Finally, here is the routine which handles an outgoing packet.  It's called
+ * "start_xmit" for traditional reasons. */
+static int lguestnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	unsigned int i;
+	int broadcast;
+	struct lguestnet_info *info = netdev_priv(dev);
+	/* Extract the destination ethernet address from the packet. */
+	const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
+	DECLARE_MAC_BUF(mac);
+
+	pr_debug("%s: xmit %s\n", dev->name, print_mac(mac, dest));
+
+	/* If it's a multicast packet, we broadcast to everyone.  That's not
+	 * very efficient, but there are very few applications which actually
+	 * use multicast, which is a shame really.
+	 *
+	 * As etherdevice.h points out: "By definition the broadcast address is
+	 * also a multicast address."  So we don't have to test for broadcast
+	 * packets separately. */
+	broadcast = is_multicast_ether_addr(dest);
+
+	/* Look through all the published ethernet addresses to see if we
+	 * should send this packet. */
+	for (i = 0; i < info->mapsize/sizeof(struct lguest_net); i++) {
+		/* We don't send to ourselves (we actually can't SEND_DMA to
+		 * ourselves anyway), and don't send to unused slots.*/
+		if (i == info->me || unused_peer(info->peer, i))
+			continue;
+
+		/* If it's broadcast we send it.  If they want every packet we
+		 * send it.  If the destination matches their address we send
+		 * it.  Otherwise we go to the next peer. */
+		if (!broadcast && !promisc(info, i) && !mac_eq(dest, info, i))
+			continue;
+
+		pr_debug("lguestnet %s: sending from %i to %i\n",
+			 dev->name, info->me, i);
+		/* Our routine which actually does the transfer. */
+		transfer_packet(dev, skb, i);
+	}
+
+	/* An xmit routine is expected to dispose of the packet, so we do. */
+	dev_kfree_skb(skb);
+
+	/* As per kernel convention, 0 means success.  This is why I love
+	 * networking: even if we never sent to anyone, that's still
+	 * success! */
+	return 0;
+}
+
+/*D:560
+ * Packet receiving.
+ *
+ * First, here's a helper routine which fills one of our array of receive
+ * buffers: */
+static int fill_slot(struct net_device *dev, unsigned int slot)
+{
+	struct lguestnet_info *info = netdev_priv(dev);
+
+	/* We can receive ETH_DATA_LEN (1500) byte packets, plus a standard
+	 * ethernet header of ETH_HLEN (14) bytes. */
+	info->skb[slot] = netdev_alloc_skb(dev, ETH_HLEN + ETH_DATA_LEN);
+	if (!info->skb[slot]) {
+		printk("%s: could not fill slot %i\n", dev->name, slot);
+		return -ENOMEM;
+	}
+
+	/* skb_to_dma() is a helper which sets up the "struct lguest_dma" to
+	 * point to the data in the skb: we also use it for sending out a
+	 * packet. */
+	skb_to_dma(info->skb[slot], ETH_HLEN + ETH_DATA_LEN, &info->dma[slot]);
+
+	/* This is a Write Memory Barrier: it ensures that the entry in the
+	 * receive buffer array is written *before* we set the "used_len" entry
+	 * to 0.  If the Host were looking at the receive buffer array from a
+	 * different CPU, it could potentially see "used_len = 0" and not see
+	 * the updated receive buffer information.  This would be a horribly
+	 * nasty bug, so make sure the compiler and CPU know this has to happen
+	 * first. */
+	wmb();
+	/* Writing 0 to "used_len" tells the Host it can use this receive
+	 * buffer now. */
+	info->dma[slot].used_len = 0;
+	return 0;
+}
+
+/* This is the actual receive routine.  When we receive an interrupt from the
+ * Host to tell us a packet has been delivered, we arrive here: */
+static irqreturn_t lguestnet_rcv(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct lguestnet_info *info = netdev_priv(dev);
+	unsigned int i, done = 0;
+
+	/* Look through our entire receive array for an entry which has data
+	 * in it. */
+	for (i = 0; i < ARRAY_SIZE(info->dma); i++) {
+		unsigned int length;
+		struct sk_buff *skb;
+
+		length = info->dma[i].used_len;
+		if (length == 0)
+			continue;
+
+		/* We've found one!  Remember the skb (we grabbed the length
+		 * above), and immediately refill the slot we've taken it
+		 * from. */
+		done++;
+		skb = info->skb[i];
+		fill_slot(dev, i);
+
+		/* This shouldn't happen: micropackets could be sent by a
+		 * badly-behaved Guest on the network, but the Host will never
+		 * stuff more data in the buffer than the buffer length. */
+		if (length < ETH_HLEN || length > ETH_HLEN + ETH_DATA_LEN) {
+			pr_debug(KERN_WARNING "%s: unbelievable skb len: %i\n",
+				 dev->name, length);
+			dev_kfree_skb(skb);
+			continue;
+		}
+
+		/* skb_put(), what a great function!  I've ranted about this
+		 * function before (http://lkml.org/lkml/1999/9/26/24).  You
+		 * call it after you've added data to the end of an skb (in
+		 * this case, it was the Host which wrote the data). */
+		skb_put(skb, length);
+
+		/* The ethernet header contains a protocol field: we use the
+		 * standard helper to extract it, and place the result in
+		 * skb->protocol.  The helper also sets up skb->pkt_type and
+		 * eats up the ethernet header from the front of the packet. */
+		skb->protocol = eth_type_trans(skb, dev);
+
+		/* If this device doesn't need checksums for sending, we also
+		 * don't need to check the packets when they come in. */
+		if (dev->features & NETIF_F_NO_CSUM)
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+		/* As a last resort for debugging the driver or the lguest I/O
+		 * subsystem, you can uncomment the "#define DEBUG" at the top
+		 * of this file, which turns all the pr_debug() into printk()
+		 * and floods the logs. */
+		pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
+			 ntohs(skb->protocol), skb->len, skb->pkt_type);
+
+		/* Update the packet and byte counts (visible from ifconfig,
+		 * and good for debugging). */
+		dev->stats.rx_bytes += skb->len;
+		dev->stats.rx_packets++;
+
+		/* Hand our fresh network packet into the stack's "network
+		 * interface receive" routine.  That will free the packet
+		 * itself when it's finished. */
+		netif_rx(skb);
+	}
+
+	/* If we found any packets, we assume the interrupt was for us. */
+	return done ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/*D:550 This is where we start: when the device is brought up by dhcpd or
+ * ifconfig.  At this point we advertise our MAC address to the rest of the
+ * network, and register receive buffers ready for incoming packets. */
+static int lguestnet_open(struct net_device *dev)
+{
+	int i;
+	struct lguestnet_info *info = netdev_priv(dev);
+
+	/* Copy our MAC address into the device page, so others on the network
+	 * can find us. */
+	memcpy(info->peer[info->me].mac, dev->dev_addr, ETH_ALEN);
+
+	/* We might already be in promisc mode (dev->flags & IFF_PROMISC).  Our
+	 * set_multicast callback handles this already, so we call it now. */
+	lguestnet_set_multicast(dev);
+
+	/* Allocate packets and put them into our "struct lguest_dma" array.
+	 * If we fail to allocate all the packets we could still limp along,
+	 * but it's a sign of real stress so we should probably give up now. */
+	for (i = 0; i < ARRAY_SIZE(info->dma); i++) {
+		if (fill_slot(dev, i) != 0)
+			goto cleanup;
+	}
+
+	/* Finally we tell the Host where our array of "struct lguest_dma"
+	 * receive buffers is, binding it to the key corresponding to the
+	 * device's physical memory plus our peerid. */
+	if (lguest_bind_dma(peer_key(info,info->me), info->dma,
+			    NUM_SKBS, lgdev_irq(info->lgdev)) != 0)
+		goto cleanup;
+	return 0;
+
+cleanup:
+	while (--i >= 0)
+		dev_kfree_skb(info->skb[i]);
+	return -ENOMEM;
+}
+/*:*/
+
+/* The close routine is called when the device is no longer in use: we clean up
+ * elegantly. */
+static int lguestnet_close(struct net_device *dev)
+{
+	unsigned int i;
+	struct lguestnet_info *info = netdev_priv(dev);
+
+	/* Clear all trace of our existence out of the device memory by setting
+	 * the slot which held our MAC address to 0 (unused). */
+	memset(&info->peer[info->me], 0, sizeof(info->peer[info->me]));
+
+	/* Unregister our array of receive buffers */
+	lguest_unbind_dma(peer_key(info, info->me), info->dma);
+	for (i = 0; i < ARRAY_SIZE(info->dma); i++)
+		dev_kfree_skb(info->skb[i]);
+	return 0;
+}
+
+/*D:510 The network device probe function is basically a standard ethernet
+ * device setup.  It reads the "struct lguest_device_desc" and sets the "struct
+ * net_device".  Oh, the line-by-line excitement!  Let's skip over it. :*/
+static int lguestnet_probe(struct lguest_device *lgdev)
+{
+	int err, irqf = IRQF_SHARED;
+	struct net_device *dev;
+	struct lguestnet_info *info;
+	struct lguest_device_desc *desc = &lguest_devices[lgdev->index];
+
+	pr_debug("lguest_net: probing for device %i\n", lgdev->index);
+
+	dev = alloc_etherdev(sizeof(struct lguestnet_info));
+	if (!dev)
+		return -ENOMEM;
+
+	/* Ethernet defaults with some changes */
+	ether_setup(dev);
+	dev->set_mac_address = NULL;
+
+	dev->dev_addr[0] = 0x02; /* set local assignment bit (IEEE802) */
+	dev->dev_addr[1] = 0x00;
+	memcpy(&dev->dev_addr[2], &lguest_data.guestid, 2);
+	dev->dev_addr[4] = 0x00;
+	dev->dev_addr[5] = 0x00;
+
+	dev->open = lguestnet_open;
+	dev->stop = lguestnet_close;
+	dev->hard_start_xmit = lguestnet_start_xmit;
+
+	/* We don't actually support multicast yet, but turning on/off
+	 * promisc also calls dev->set_multicast_list. */
+	dev->set_multicast_list = lguestnet_set_multicast;
+	SET_NETDEV_DEV(dev, &lgdev->dev);
+
+	/* The network code complains if you have "scatter-gather" capability
+	 * if you don't also handle checksums (it seem that would be
+	 * "illogical").  So we use a lie of omission and don't tell it that we
+	 * can handle scattered packets unless we also don't want checksums,
+	 * even though to us they're completely independent. */
+	if (desc->features & LGUEST_NET_F_NOCSUM)
+		dev->features = NETIF_F_SG|NETIF_F_NO_CSUM;
+
+	info = netdev_priv(dev);
+	info->mapsize = PAGE_SIZE * desc->num_pages;
+	info->peer_phys = ((unsigned long)desc->pfn << PAGE_SHIFT);
+	info->lgdev = lgdev;
+	info->peer = lguest_map(info->peer_phys, desc->num_pages);
+	if (!info->peer) {
+		err = -ENOMEM;
+		goto free;
+	}
+
+	/* This stores our peerid (upper bits reserved for future). */
+	info->me = (desc->features & (info->mapsize-1));
+
+	err = register_netdev(dev);
+	if (err) {
+		pr_debug("lguestnet: registering device failed\n");
+		goto unmap;
+	}
+
+	if (lguest_devices[lgdev->index].features & LGUEST_DEVICE_F_RANDOMNESS)
+		irqf |= IRQF_SAMPLE_RANDOM;
+	if (request_irq(lgdev_irq(lgdev), lguestnet_rcv, irqf, "lguestnet",
+			dev) != 0) {
+		pr_debug("lguestnet: cannot get irq %i\n", lgdev_irq(lgdev));
+		goto unregister;
+	}
+
+	pr_debug("lguestnet: registered device %s\n", dev->name);
+	/* Finally, we put the "struct net_device" in the generic "struct
+	 * lguest_device"s private pointer.  Again, it's not necessary, but
+	 * makes sure the cool kernel kids don't tease us. */
+	lgdev->private = dev;
+	return 0;
+
+unregister:
+	unregister_netdev(dev);
+unmap:
+	lguest_unmap(info->peer);
+free:
+	free_netdev(dev);
+	return err;
+}
+
+static struct lguest_driver lguestnet_drv = {
+	.name = "lguestnet",
+	.owner = THIS_MODULE,
+	.device_type = LGUEST_DEVICE_T_NET,
+	.probe = lguestnet_probe,
+};
+
+static __init int lguestnet_init(void)
+{
+	return register_lguest_driver(&lguestnet_drv);
+}
+module_init(lguestnet_init);
+
+MODULE_DESCRIPTION("Lguest network driver");
+MODULE_LICENSE("GPL");
+
+/*D:580
+ * This is the last of the Drivers, and with this we have covered the many and
+ * wonderous and fine (and boring) details of the Guest.
+ *
+ * "make Launcher" beckons, where we answer questions like "Where do Guests
+ * come from?", and "What do you do when someone asks for optimization?"
+ */
diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c
index 5884f5b..ffaa14f 100644
--- a/drivers/net/lib82596.c
+++ b/drivers/net/lib82596.c
@@ -322,7 +322,6 @@
 	struct i596_cmd *cmd_head;
 	int cmd_backlog;
 	u32    last_cmd;
-	struct net_device_stats stats;
 	int next_tx_cmd;
 	int options;
 	spinlock_t lock;       /* serialize access to chip */
@@ -352,7 +351,6 @@
 static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t i596_interrupt(int irq, void *dev_id);
 static int i596_close(struct net_device *dev);
-static struct net_device_stats *i596_get_stats(struct net_device *dev);
 static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
 static void i596_tx_timeout (struct net_device *dev);
 static void print_eth(unsigned char *buf, char *str);
@@ -725,7 +723,7 @@
 				printk(KERN_ERR
 				       "%s: i596_rx Memory squeeze, dropping packet.\n",
 				       dev->name);
-				lp->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 			} else {
 				if (!rx_in_place) {
 					/* 16 byte align the data fields */
@@ -742,28 +740,28 @@
 				skb->protocol = eth_type_trans(skb, dev);
 				netif_rx(skb);
 				dev->last_rx = jiffies;
-				lp->stats.rx_packets++;
-				lp->stats.rx_bytes += pkt_len;
+				dev->stats.rx_packets++;
+				dev->stats.rx_bytes += pkt_len;
 			}
 		} else {
 			DEB(DEB_ERRORS, printk(KERN_DEBUG
 					       "%s: Error, rfd.stat = 0x%04x\n",
 					       dev->name, rfd->stat));
-			lp->stats.rx_errors++;
+			dev->stats.rx_errors++;
 			if (rfd->stat & SWAP16(0x0100))
-				lp->stats.collisions++;
+				dev->stats.collisions++;
 			if (rfd->stat & SWAP16(0x8000))
-				lp->stats.rx_length_errors++;
+				dev->stats.rx_length_errors++;
 			if (rfd->stat & SWAP16(0x0001))
-				lp->stats.rx_over_errors++;
+				dev->stats.rx_over_errors++;
 			if (rfd->stat & SWAP16(0x0002))
-				lp->stats.rx_fifo_errors++;
+				dev->stats.rx_fifo_errors++;
 			if (rfd->stat & SWAP16(0x0004))
-				lp->stats.rx_frame_errors++;
+				dev->stats.rx_frame_errors++;
 			if (rfd->stat & SWAP16(0x0008))
-				lp->stats.rx_crc_errors++;
+				dev->stats.rx_crc_errors++;
 			if (rfd->stat & SWAP16(0x0010))
-				lp->stats.rx_length_errors++;
+				dev->stats.rx_length_errors++;
 		}
 
 		/* Clear the buffer descriptor count and EOF + F flags */
@@ -821,8 +819,8 @@
 
 				dev_kfree_skb(skb);
 
-				lp->stats.tx_errors++;
-				lp->stats.tx_aborted_errors++;
+				dev->stats.tx_errors++;
+				dev->stats.tx_aborted_errors++;
 
 				ptr->v_next = NULL;
 				ptr->b_next = I596_NULL;
@@ -951,10 +949,10 @@
 			       "%s: transmit timed out, status resetting.\n",
 			       dev->name));
 
-	lp->stats.tx_errors++;
+	dev->stats.tx_errors++;
 
 	/* Try to restart the adaptor */
-	if (lp->last_restart == lp->stats.tx_packets) {
+	if (lp->last_restart == dev->stats.tx_packets) {
 		DEB(DEB_ERRORS, printk(KERN_DEBUG "Resetting board.\n"));
 		/* Shutdown and restart */
 		i596_reset (dev, lp);
@@ -964,7 +962,7 @@
 		lp->dma->scb.command = SWAP16(CUC_START | RX_START);
 		DMA_WBACK_INV(dev, &(lp->dma->scb), sizeof(struct i596_scb));
 		ca (dev);
-		lp->last_restart = lp->stats.tx_packets;
+		lp->last_restart = dev->stats.tx_packets;
 	}
 
 	dev->trans_start = jiffies;
@@ -999,7 +997,7 @@
 		DEB(DEB_ERRORS, printk(KERN_DEBUG
 				       "%s: xmit ring full, dropping packet.\n",
 				       dev->name));
-		lp->stats.tx_dropped++;
+		dev->stats.tx_dropped++;
 
 		dev_kfree_skb(skb);
 	} else {
@@ -1025,8 +1023,8 @@
 		DMA_WBACK_INV(dev, tbd, sizeof(struct i596_tbd));
 		i596_add_cmd(dev, &tx_cmd->cmd);
 
-		lp->stats.tx_packets++;
-		lp->stats.tx_bytes += length;
+		dev->stats.tx_packets++;
+		dev->stats.tx_bytes += length;
 	}
 
 	netif_start_queue(dev);
@@ -1036,15 +1034,12 @@
 
 static void print_eth(unsigned char *add, char *str)
 {
-	int i;
+	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mac2);
 
-	printk(KERN_DEBUG "i596 0x%p, ", add);
-	for (i = 0; i < 6; i++)
-		printk(" %02X", add[i + 6]);
-	printk(" -->");
-	for (i = 0; i < 6; i++)
-		printk(" %02X", add[i]);
-	printk(" %02X%02X, %s\n", add[12], add[13], str);
+	printk(KERN_DEBUG "i596 0x%p, %s --> %s %02X%02X, %s\n",
+	       add, print_mac(mac, add + 6), print_mac(mac2, add),
+	       add[12], add[13], str);
 }
 
 static int __devinit i82596_probe(struct net_device *dev)
@@ -1076,7 +1071,6 @@
 	dev->open = i596_open;
 	dev->stop = i596_close;
 	dev->hard_start_xmit = i596_start_xmit;
-	dev->get_stats = i596_get_stats;
 	dev->set_multicast_list = set_multicast_list;
 	dev->tx_timeout = i596_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
@@ -1197,17 +1191,17 @@
 					DEB(DEB_TXADDR,
 					    print_eth(skb->data, "tx-done"));
 				} else {
-					lp->stats.tx_errors++;
+					dev->stats.tx_errors++;
 					if (ptr->status & SWAP16(0x0020))
-						lp->stats.collisions++;
+						dev->stats.collisions++;
 					if (!(ptr->status & SWAP16(0x0040)))
-						lp->stats.tx_heartbeat_errors++;
+						dev->stats.tx_heartbeat_errors++;
 					if (ptr->status & SWAP16(0x0400))
-						lp->stats.tx_carrier_errors++;
+						dev->stats.tx_carrier_errors++;
 					if (ptr->status & SWAP16(0x0800))
-						lp->stats.collisions++;
+						dev->stats.collisions++;
 					if (ptr->status & SWAP16(0x1000))
-						lp->stats.tx_aborted_errors++;
+						dev->stats.tx_aborted_errors++;
 				}
 				dma_unmap_single(dev->dev.parent,
 						 tx_cmd->dma_addr,
@@ -1292,8 +1286,8 @@
 					   "%s: i596 interrupt receive unit inactive, status 0x%x\n",
 					   dev->name, status));
 				ack_cmd |= RX_START;
-				lp->stats.rx_errors++;
-				lp->stats.rx_fifo_errors++;
+				dev->stats.rx_errors++;
+				dev->stats.rx_fifo_errors++;
 				rebuild_rx_bufs(dev);
 			}
 		}
@@ -1346,13 +1340,6 @@
 	return 0;
 }
 
-static struct net_device_stats *i596_get_stats(struct net_device *dev)
-{
-	struct i596_private *lp = netdev_priv(dev);
-
-	return &lp->stats;
-}
-
 /*
  *    Set or clear the multicast filter for this adaptor.
  */
@@ -1362,6 +1349,7 @@
 	struct i596_private *lp = netdev_priv(dev);
 	struct i596_dma *dma = lp->dma;
 	int config = 0, cnt;
+	DECLARE_MAC_BUF(mac);
 
 	DEB(DEB_MULTI,
 	    printk(KERN_DEBUG
@@ -1425,8 +1413,8 @@
 			if (i596_debug > 1)
 				DEB(DEB_MULTI,
 				    printk(KERN_DEBUG
-					   "%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n",
-					   dev->name, cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]));
+					   "%s: Adding address %s\n",
+					   dev->name, print_mac(mac, cp)));
 		}
 		DMA_WBACK_INV(dev, &dma->mc_cmd, sizeof(struct mc_cmd));
 		i596_add_cmd(dev, &cmd->cmd);
diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c
index 5c86e73..c429a50 100644
--- a/drivers/net/lib8390.c
+++ b/drivers/net/lib8390.c
@@ -143,6 +143,52 @@
  *	annoying the transmit function is called bh atomic. That places
  *	restrictions on the user context callers as disable_irq won't save
  *	them.
+ *
+ *	Additional explanation of problems with locking by Alan Cox:
+ *
+ *	"The author (me) didn't use spin_lock_irqsave because the slowness of the
+ *	card means that approach caused horrible problems like losing serial data
+ *	at 38400 baud on some chips. Rememeber many 8390 nics on PCI were ISA
+ *	chips with FPGA front ends.
+ *	
+ *	Ok the logic behind the 8390 is very simple:
+ *	
+ *	Things to know
+ *		- IRQ delivery is asynchronous to the PCI bus
+ *		- Blocking the local CPU IRQ via spin locks was too slow
+ *		- The chip has register windows needing locking work
+ *	
+ *	So the path was once (I say once as people appear to have changed it
+ *	in the mean time and it now looks rather bogus if the changes to use
+ *	disable_irq_nosync_irqsave are disabling the local IRQ)
+ *	
+ *	
+ *		Take the page lock
+ *		Mask the IRQ on chip
+ *		Disable the IRQ (but not mask locally- someone seems to have
+ *			broken this with the lock validator stuff)
+ *			[This must be _nosync as the page lock may otherwise
+ *				deadlock us]
+ *		Drop the page lock and turn IRQs back on
+ *		
+ *		At this point an existing IRQ may still be running but we can't
+ *		get a new one
+ *	
+ *		Take the lock (so we know the IRQ has terminated) but don't mask
+ *	the IRQs on the processor
+ *		Set irqlock [for debug]
+ *	
+ *		Transmit (slow as ****)
+ *	
+ *		re-enable the IRQ
+ *	
+ *	
+ *	We have to use disable_irq because otherwise you will get delayed
+ *	interrupts on the APIC bus deadlocking the transmit path.
+ *	
+ *	Quite hairy but the chip simply wasn't designed for SMP and you can't
+ *	even ACK an interrupt without risking corrupting other parallel
+ *	activities on the chip." [lkml, 25 Jul 2007]
  */
 
 
@@ -219,15 +265,6 @@
 	int txsr, isr, tickssofar = jiffies - dev->trans_start;
 	unsigned long flags;
 
-#if defined(CONFIG_M32R) && defined(CONFIG_SMP)
-	unsigned long icucr;
-
-	local_irq_save(flags);
-	icucr = inl(M32R_ICU_CR1_PORTL);
-	icucr |= M32R_ICUCR_ISMOD11;
-	outl(icucr, M32R_ICU_CR1_PORTL);
-	local_irq_restore(flags);
-#endif
 	ei_local->stat.tx_errors++;
 
 	spin_lock_irqsave(&ei_local->page_lock, flags);
diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c
index 0a08d0c..b369890 100644
--- a/drivers/net/lne390.c
+++ b/drivers/net/lne390.c
@@ -111,8 +111,6 @@
 	int mem_start = dev->mem_start;
 	int ret;
 
-	SET_MODULE_OWNER(dev);
-
 	if (ioaddr > 0x1ff) {		/* Check a single specified location. */
 		if (!request_region(ioaddr, LNE390_IO_EXTENT, DRV_NAME))
 			return -EBUSY;
@@ -171,6 +169,7 @@
 {
 	int i, revision, ret;
 	unsigned long eisa_id;
+	DECLARE_MAC_BUF(mac);
 
 	if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV;
 
@@ -202,10 +201,12 @@
 	}
 #endif
 
-	printk("lne390.c: LNE390%X in EISA slot %d, address", 0xa+revision, ioaddr/0x1000);
 	for(i = 0; i < ETHER_ADDR_LEN; i++)
-		printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i)));
-	printk(".\nlne390.c: ");
+		dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i);
+	printk("lne390.c: LNE390%X in EISA slot %d, address %s.\n",
+	       0xa+revision, ioaddr/0x1000, print_mac(mac, dev->dev_addr));
+
+	printk("lne390.c: ");
 
 	/* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
 	if (dev->irq == 0) {
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 6ba6ed2..be25aa3 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -57,12 +57,12 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/percpu.h>
+#include <net/net_namespace.h>
 
 struct pcpu_lstats {
 	unsigned long packets;
 	unsigned long bytes;
 };
-static DEFINE_PER_CPU(struct pcpu_lstats, pcpu_lstats);
 
 #define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16)
 
@@ -134,7 +134,7 @@
  */
 static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct pcpu_lstats *lb_stats;
+	struct pcpu_lstats *pcpu_lstats, *lb_stats;
 
 	skb_orphan(skb);
 
@@ -154,8 +154,9 @@
 #endif
 	dev->last_rx = jiffies;
 
-	/* it's OK to use __get_cpu_var() because BHs are off */
-	lb_stats = &__get_cpu_var(pcpu_lstats);
+	/* it's OK to use per_cpu_ptr() because BHs are off */
+	pcpu_lstats = netdev_priv(dev);
+	lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id());
 	lb_stats->bytes += skb->len;
 	lb_stats->packets++;
 
@@ -166,15 +167,17 @@
 
 static struct net_device_stats *get_stats(struct net_device *dev)
 {
+	const struct pcpu_lstats *pcpu_lstats;
 	struct net_device_stats *stats = &dev->stats;
 	unsigned long bytes = 0;
 	unsigned long packets = 0;
 	int i;
 
+	pcpu_lstats = netdev_priv(dev);
 	for_each_possible_cpu(i) {
 		const struct pcpu_lstats *lb_stats;
 
-		lb_stats = &per_cpu(pcpu_lstats, i);
+		lb_stats = per_cpu_ptr(pcpu_lstats, i);
 		bytes   += lb_stats->bytes;
 		packets += lb_stats->packets;
 	}
@@ -192,46 +195,107 @@
 
 static const struct ethtool_ops loopback_ethtool_ops = {
 	.get_link		= always_on,
-	.get_tso		= ethtool_op_get_tso,
 	.set_tso		= ethtool_op_set_tso,
 	.get_tx_csum		= always_on,
 	.get_sg			= always_on,
 	.get_rx_csum		= always_on,
 };
 
+static int loopback_dev_init(struct net_device *dev)
+{
+	struct pcpu_lstats *lstats;
+
+	lstats = alloc_percpu(struct pcpu_lstats);
+	if (!lstats)
+		return -ENOMEM;
+
+	dev->priv = lstats;
+	return 0;
+}
+
+static void loopback_dev_free(struct net_device *dev)
+{
+	struct pcpu_lstats *lstats = netdev_priv(dev);
+
+	free_percpu(lstats);
+	free_netdev(dev);
+}
+
 /*
- * The loopback device is special. There is only one instance and
- * it is statically allocated. Don't do this for other devices.
+ * The loopback device is special. There is only one instance
+ * per network namespace.
  */
-struct net_device loopback_dev = {
-	.name	 		= "lo",
-	.get_stats		= &get_stats,
-	.mtu			= (16 * 1024) + 20 + 20 + 12,
-	.hard_start_xmit	= loopback_xmit,
-	.hard_header		= eth_header,
-	.hard_header_cache	= eth_header_cache,
-	.header_cache_update	= eth_header_cache_update,
-	.hard_header_len	= ETH_HLEN,	/* 14	*/
-	.addr_len		= ETH_ALEN,	/* 6	*/
-	.tx_queue_len		= 0,
-	.type			= ARPHRD_LOOPBACK,	/* 0x0001*/
-	.rebuild_header		= eth_rebuild_header,
-	.flags			= IFF_LOOPBACK,
-	.features 		= NETIF_F_SG | NETIF_F_FRAGLIST
+static void loopback_setup(struct net_device *dev)
+{
+	dev->get_stats		= &get_stats;
+	dev->mtu		= (16 * 1024) + 20 + 20 + 12;
+	dev->hard_start_xmit	= loopback_xmit;
+	dev->hard_header_len	= ETH_HLEN;	/* 14	*/
+	dev->addr_len		= ETH_ALEN;	/* 6	*/
+	dev->tx_queue_len	= 0;
+	dev->type		= ARPHRD_LOOPBACK;	/* 0x0001*/
+	dev->flags		= IFF_LOOPBACK;
+	dev->features 		= NETIF_F_SG | NETIF_F_FRAGLIST
 #ifdef LOOPBACK_TSO
-				  | NETIF_F_TSO
+		| NETIF_F_TSO
 #endif
-				  | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA
-				  | NETIF_F_LLTX,
-	.ethtool_ops		= &loopback_ethtool_ops,
-};
+		| NETIF_F_NO_CSUM
+		| NETIF_F_HIGHDMA
+		| NETIF_F_LLTX
+		| NETIF_F_NETNS_LOCAL,
+	dev->ethtool_ops	= &loopback_ethtool_ops;
+	dev->header_ops		= &eth_header_ops;
+	dev->init = loopback_dev_init;
+	dev->destructor = loopback_dev_free;
+}
 
 /* Setup and register the loopback device. */
-static int __init loopback_init(void)
+static __net_init int loopback_net_init(struct net *net)
 {
-	return register_netdev(&loopback_dev);
+	struct net_device *dev;
+	int err;
+
+	err = -ENOMEM;
+	dev = alloc_netdev(0, "lo", loopback_setup);
+	if (!dev)
+		goto out;
+
+	dev->nd_net = net;
+	err = register_netdev(dev);
+	if (err)
+		goto out_free_netdev;
+
+	err = 0;
+	net->loopback_dev = dev;
+
+out:
+	if (err)
+		panic("loopback: Failed to register netdevice: %d\n", err);
+	return err;
+
+out_free_netdev:
+	free_netdev(dev);
+	goto out;
+}
+
+static __net_exit void loopback_net_exit(struct net *net)
+{
+	struct net_device *dev = net->loopback_dev;
+
+	unregister_netdev(dev);
+}
+
+static struct pernet_operations __net_initdata loopback_net_ops = {
+       .init = loopback_net_init,
+       .exit = loopback_net_exit,
 };
 
-module_init(loopback_init);
+static int __init loopback_init(void)
+{
+	return register_pernet_device(&loopback_net_ops);
+}
 
-EXPORT_SYMBOL(loopback_dev);
+/* Loopback is special. It should be initialized before any other network
+ * device and network subsystem.
+ */
+fs_initcall(loopback_init);
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
index 5fc18da..c5095ec 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -350,7 +350,6 @@
 	struct i596_cmd *cmd_head;
 	int cmd_backlog;
 	unsigned long last_cmd;
-	struct net_device_stats stats;
 	spinlock_t cmd_lock;
 };
 
@@ -381,7 +380,6 @@
 static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t i596_interrupt(int irq, void *dev_id);
 static int i596_close(struct net_device *dev);
-static struct net_device_stats *i596_get_stats(struct net_device *dev);
 static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
 static void print_eth(char *);
 static void set_multicast_list(struct net_device *dev);
@@ -515,8 +513,6 @@
 	outb(0, IOADDR+8);
 }
 
-#define SIZE(x)	(sizeof(x)/sizeof((x)[0]))
-
 #if 0
 /* selftest or dump */
 static void
@@ -532,7 +528,7 @@
 	mdelay(30);             /* random, unmotivated */
 
 	printk("lp486e i82596 %s result:\n", cmdname);
-	for (m = SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--)
+	for (m = ARRAY_SIZE(lp->dump.dump); m && lp->dump.dump[m-1] == 0; m--)
 		;
 	for (i = 0; i < m; i++) {
 		printk(" %04x", lp->dump.dump[i]);
@@ -672,7 +668,7 @@
 		if (skb == NULL) {
 			printk ("%s: i596_rx Memory squeeze, "
 				"dropping packet.\n", dev->name);
-			lp->stats.rx_dropped++;
+			dev->stats.rx_dropped++;
 			return 1;
 		}
 
@@ -681,27 +677,27 @@
 		skb->protocol = eth_type_trans(skb,dev);
 		netif_rx(skb);
 		dev->last_rx = jiffies;
-		lp->stats.rx_packets++;
+		dev->stats.rx_packets++;
 	} else {
 #if 0
 		printk("Frame reception error status %04x\n",
 		       rfd->stat);
 #endif
-		lp->stats.rx_errors++;
+		dev->stats.rx_errors++;
 		if (rfd->stat & RFD_COLLISION)
-			lp->stats.collisions++;
+			dev->stats.collisions++;
 		if (rfd->stat & RFD_SHORT_FRAME_ERR)
-			lp->stats.rx_length_errors++;
+			dev->stats.rx_length_errors++;
 		if (rfd->stat & RFD_DMA_ERR)
-			lp->stats.rx_over_errors++;
+			dev->stats.rx_over_errors++;
 		if (rfd->stat & RFD_NOBUFS_ERR)
-			lp->stats.rx_fifo_errors++;
+			dev->stats.rx_fifo_errors++;
 		if (rfd->stat & RFD_ALIGN_ERR)
-			lp->stats.rx_frame_errors++;
+			dev->stats.rx_frame_errors++;
 		if (rfd->stat & RFD_CRC_ERR)
-			lp->stats.rx_crc_errors++;
+			dev->stats.rx_crc_errors++;
 		if (rfd->stat & RFD_LENGTH_ERR)
-			lp->stats.rx_length_errors++;
+			dev->stats.rx_length_errors++;
 	}
 	rfd->stat = rfd->count = 0;
 	return 0;
@@ -757,8 +753,8 @@
 
 				dev_kfree_skb_any(tx_cmd_tbd->skb);
 
-				lp->stats.tx_errors++;
-				lp->stats.tx_aborted_errors++;
+				dev->stats.tx_errors++;
+				dev->stats.tx_aborted_errors++;
 
 				cmd->pa_next = I596_NULL;
 				kfree((unsigned char *)tx_cmd);
@@ -869,7 +865,6 @@
 }
 
 static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
-	struct i596_private *lp = dev->priv;
 	struct tx_cmd *tx_cmd;
 	short length;
 
@@ -886,7 +881,7 @@
 	tx_cmd = kmalloc((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
 	if (tx_cmd == NULL) {
 		printk(KERN_WARNING "%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name);
-		lp->stats.tx_dropped++;
+		dev->stats.tx_dropped++;
 		dev_kfree_skb (skb);
 	} else {
 		struct i596_tbd *tx_cmd_tbd;
@@ -909,7 +904,7 @@
 
 		i596_add_cmd (dev, (struct i596_cmd *) tx_cmd);
 
-		lp->stats.tx_packets++;
+		dev->stats.tx_packets++;
 	}
 
 	return 0;
@@ -922,10 +917,10 @@
 
 	/* Transmitter timeout, serious problems. */
 	printk(KERN_WARNING "%s: transmit timed out, status resetting.\n", dev->name);
-	lp->stats.tx_errors++;
+	dev->stats.tx_errors++;
 
 	/* Try to restart the adaptor */
-	if (lp->last_restart == lp->stats.tx_packets) {
+	if (lp->last_restart == dev->stats.tx_packets) {
 		printk ("Resetting board.\n");
 
 		/* Shutdown and restart */
@@ -935,7 +930,7 @@
 		printk ("Kicking board.\n");
 		lp->scb.command = (CUC_START | RX_START);
 		CA();
-		lp->last_restart = lp->stats.tx_packets;
+		lp->last_restart = dev->stats.tx_packets;
 	}
 	netif_wake_queue(dev);
 }
@@ -1023,7 +1018,6 @@
 	dev->open = &i596_open;
 	dev->stop = &i596_close;
 	dev->hard_start_xmit = &i596_start_xmit;
-	dev->get_stats = &i596_get_stats;
 	dev->set_multicast_list = &set_multicast_list;
 	dev->watchdog_timeo = 5*HZ;
 	dev->tx_timeout = i596_tx_timeout;
@@ -1080,20 +1074,20 @@
 				if (i596_debug)
 					print_eth(pa_to_va(tx_cmd_tbd->pa_data));
 			} else {
-				lp->stats.tx_errors++;
+				dev->stats.tx_errors++;
 				if (i596_debug)
 					printk("transmission failure:%04x\n",
 					       cmd->status);
 				if (cmd->status & 0x0020)
-					lp->stats.collisions++;
+					dev->stats.collisions++;
 				if (!(cmd->status & 0x0040))
-					lp->stats.tx_heartbeat_errors++;
+					dev->stats.tx_heartbeat_errors++;
 				if (cmd->status & 0x0400)
-					lp->stats.tx_carrier_errors++;
+					dev->stats.tx_carrier_errors++;
 				if (cmd->status & 0x0800)
-					lp->stats.collisions++;
+					dev->stats.collisions++;
 				if (cmd->status & 0x1000)
-					lp->stats.tx_aborted_errors++;
+					dev->stats.tx_aborted_errors++;
 			}
 			dev_kfree_skb_irq(tx_cmd_tbd->skb);
 
@@ -1244,12 +1238,6 @@
 	return 0;
 }
 
-static struct net_device_stats * i596_get_stats(struct net_device *dev) {
-	struct i596_private *lp = dev->priv;
-
-	return &lp->stats;
-}
-
 /*
 *	Set or clear the multicast filter for this adaptor.
 */
diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c
index 90b0c3e..9e70074 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/mac8390.c
@@ -313,8 +313,6 @@
 	if (unit >= 0)
 		sprintf(dev->name, "eth%d", unit);
 
- 	SET_MODULE_OWNER(dev);
-
 	while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev))) {
 		/* Have we seen it already? */
 		if (slots & (1<<ndev->board->slot))
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index 26a3b45..30854f0 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -181,6 +181,7 @@
 	unsigned long ioaddr;
 	unsigned short sig;
 	int err = -ENODEV;
+	DECLARE_MAC_BUF(mac);
 
 	dev = alloc_etherdev(sizeof(struct net_local));
 	if (!dev)
@@ -191,8 +192,6 @@
 		netdev_boot_setup_check(dev);
 	}
 
-	SET_MODULE_OWNER(dev);
-
 	if (once_is_enough)
 		goto out;
 	once_is_enough = 1;
@@ -274,13 +273,11 @@
         }
 
 	dev->irq = SLOT2IRQ(slot);
-	printk(" IRQ %d ADDR ", dev->irq);
 
-	/* print the ethernet address. */
-	for (i = 0; i < ETH_ALEN; i++)
-		printk("%2.2x%s", dev->dev_addr[i],
-		       ((i < ETH_ALEN-1) ? ":" : ""));
-	printk("\n");
+	/* print the IRQ and ethernet address. */
+
+	printk(" IRQ %d ADDR %s\n",
+	       dev->irq, print_mac(mac, dev->dev_addr));
 
 	dev->open		= net_open;
 	dev->stop		= net_close;
@@ -608,7 +605,7 @@
 MODULE_PARM_DESC(debug, "CS89[02]0 debug level (0-5)");
 MODULE_LICENSE("GPL");
 
-int
+int __init
 init_module(void)
 {
 	net_debug = debug;
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index a4bb026..047ea7b 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -470,47 +470,41 @@
 	return received;
 }
 
-static int macb_poll(struct net_device *dev, int *budget)
+static int macb_poll(struct napi_struct *napi, int budget)
 {
-	struct macb *bp = netdev_priv(dev);
-	int orig_budget, work_done, retval = 0;
+	struct macb *bp = container_of(napi, struct macb, napi);
+	struct net_device *dev = bp->dev;
+	int work_done;
 	u32 status;
 
 	status = macb_readl(bp, RSR);
 	macb_writel(bp, RSR, status);
 
+	work_done = 0;
 	if (!status) {
 		/*
 		 * This may happen if an interrupt was pending before
 		 * this function was called last time, and no packets
 		 * have been received since.
 		 */
-		netif_rx_complete(dev);
+		netif_rx_complete(dev, napi);
 		goto out;
 	}
 
 	dev_dbg(&bp->pdev->dev, "poll: status = %08lx, budget = %d\n",
-		(unsigned long)status, *budget);
+		(unsigned long)status, budget);
 
 	if (!(status & MACB_BIT(REC))) {
 		dev_warn(&bp->pdev->dev,
 			 "No RX buffers complete, status = %02lx\n",
 			 (unsigned long)status);
-		netif_rx_complete(dev);
+		netif_rx_complete(dev, napi);
 		goto out;
 	}
 
-	orig_budget = *budget;
-	if (orig_budget > dev->quota)
-		orig_budget = dev->quota;
-
-	work_done = macb_rx(bp, orig_budget);
-	if (work_done < orig_budget) {
-		netif_rx_complete(dev);
-		retval = 0;
-	} else {
-		retval = 1;
-	}
+	work_done = macb_rx(bp, budget);
+	if (work_done < budget)
+		netif_rx_complete(dev, napi);
 
 	/*
 	 * We've done what we can to clean the buffers. Make sure we
@@ -521,7 +515,7 @@
 
 	/* TODO: Handle errors */
 
-	return retval;
+	return work_done;
 }
 
 static irqreturn_t macb_interrupt(int irq, void *dev_id)
@@ -545,7 +539,7 @@
 		}
 
 		if (status & MACB_RX_INT_FLAGS) {
-			if (netif_rx_schedule_prep(dev)) {
+			if (netif_rx_schedule_prep(dev, &bp->napi)) {
 				/*
 				 * There's no point taking any more interrupts
 				 * until we have processed the buffers
@@ -553,7 +547,7 @@
 				macb_writel(bp, IDR, MACB_RX_INT_FLAGS);
 				dev_dbg(&bp->pdev->dev,
 					"scheduling RX softirq\n");
-				__netif_rx_schedule(dev);
+				__netif_rx_schedule(dev, &bp->napi);
 			}
 		}
 
@@ -937,6 +931,8 @@
 		return err;
 	}
 
+	napi_enable(&bp->napi);
+
 	macb_init_rings(bp);
 	macb_init_hw(bp);
 
@@ -954,6 +950,7 @@
 	unsigned long flags;
 
 	netif_stop_queue(dev);
+	napi_disable(&bp->napi);
 
 	if (bp->phy_dev)
 		phy_stop(bp->phy_dev);
@@ -1074,6 +1071,7 @@
 	unsigned long pclk_hz;
 	u32 config;
 	int err = -ENXIO;
+	DECLARE_MAC_BUF(mac);
 
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!regs) {
@@ -1088,7 +1086,6 @@
 		goto err_out;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	/* TODO: Actually, we have some interesting features... */
@@ -1146,8 +1143,7 @@
 	dev->get_stats = macb_get_stats;
 	dev->set_multicast_list = macb_set_rx_mode;
 	dev->do_ioctl = macb_ioctl;
-	dev->poll = macb_poll;
-	dev->weight = 64;
+	netif_napi_add(dev, &bp->napi, macb_poll, 64);
 	dev->ethtool_ops = &macb_ethtool_ops;
 
 	dev->base_addr = regs->start;
@@ -1195,10 +1191,9 @@
 	platform_set_drvdata(pdev, dev);
 
 	printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d "
-	       "(%02x:%02x:%02x:%02x:%02x:%02x)\n",
+	       "(%s)\n",
 	       dev->name, dev->base_addr, dev->irq,
-	       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-	       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+	       print_mac(mac, dev->dev_addr));
 
 	phydev = bp->phy_dev;
 	printk(KERN_INFO "%s: attached PHY driver [%s] "
diff --git a/drivers/net/macb.h b/drivers/net/macb.h
index 4e3283e..57b85ac 100644
--- a/drivers/net/macb.h
+++ b/drivers/net/macb.h
@@ -374,6 +374,7 @@
 	struct clk		*pclk;
 	struct clk		*hclk;
 	struct net_device	*dev;
+	struct napi_struct	napi;
 	struct net_device_stats	stats;
 	struct macb_stats	hw_stats;
 
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 52b9332..95ebe72 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -57,7 +57,6 @@
     unsigned char tx_fullup;
     unsigned char tx_active;
     unsigned char tx_bad_runt;
-    struct net_device_stats stats;
     struct timer_list tx_timeout;
     int timeout_active;
     int port_aaui;
@@ -78,7 +77,6 @@
 static int mace_open(struct net_device *dev);
 static int mace_close(struct net_device *dev);
 static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *mace_stats(struct net_device *dev);
 static void mace_set_multicast(struct net_device *dev);
 static void mace_reset(struct net_device *dev);
 static int mace_set_address(struct net_device *dev, void *addr);
@@ -103,6 +101,7 @@
 	struct mace_data *mp;
 	const unsigned char *addr;
 	int j, rev, rc = -EBUSY;
+	DECLARE_MAC_BUF(mac);
 
 	if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
 		printk(KERN_ERR "can't use MACE %s: need 3 addrs and 3 irqs\n",
@@ -143,7 +142,6 @@
 		rc = -ENOMEM;
 		goto err_release;
 	}
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
 
 	mp = dev->priv;
@@ -189,7 +187,6 @@
 	mp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(mp + 1);
 	mp->rx_cmds = mp->tx_cmds + NCMDS_TX * N_TX_RING + 1;
 
-	memset(&mp->stats, 0, sizeof(mp->stats));
 	memset((char *) mp->tx_cmds, 0,
 	       (NCMDS_TX*N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
 	init_timer(&mp->tx_timeout);
@@ -214,7 +211,6 @@
 	dev->open = mace_open;
 	dev->stop = mace_close;
 	dev->hard_start_xmit = mace_xmit_start;
-	dev->get_stats = mace_stats;
 	dev->set_multicast_list = mace_set_multicast;
 	dev->set_mac_address = mace_set_address;
 
@@ -245,11 +241,9 @@
 		goto err_free_rx_irq;
 	}
 
-	printk(KERN_INFO "%s: MACE at", dev->name);
-	for (j = 0; j < 6; ++j) {
-		printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
-	}
-	printk(", chip revision %d.%d\n", mp->chipid >> 8, mp->chipid & 0xff);
+	printk(KERN_INFO "%s: MACE at %s, chip revision %d.%d\n",
+	       dev->name, print_mac(mac, dev->dev_addr),
+	       mp->chipid >> 8, mp->chipid & 0xff);
 
 	return 0;
 
@@ -585,13 +579,6 @@
     return 0;
 }
 
-static struct net_device_stats *mace_stats(struct net_device *dev)
-{
-    struct mace_data *p = (struct mace_data *) dev->priv;
-
-    return &p->stats;
-}
-
 static void mace_set_multicast(struct net_device *dev)
 {
     struct mace_data *mp = (struct mace_data *) dev->priv;
@@ -645,19 +632,19 @@
     spin_unlock_irqrestore(&mp->lock, flags);
 }
 
-static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
+static void mace_handle_misc_intrs(struct mace_data *mp, int intr, struct net_device *dev)
 {
     volatile struct mace __iomem *mb = mp->mace;
     static int mace_babbles, mace_jabbers;
 
     if (intr & MPCO)
-	mp->stats.rx_missed_errors += 256;
-    mp->stats.rx_missed_errors += in_8(&mb->mpc);   /* reading clears it */
+	dev->stats.rx_missed_errors += 256;
+    dev->stats.rx_missed_errors += in_8(&mb->mpc);   /* reading clears it */
     if (intr & RNTPCO)
-	mp->stats.rx_length_errors += 256;
-    mp->stats.rx_length_errors += in_8(&mb->rntpc); /* reading clears it */
+	dev->stats.rx_length_errors += 256;
+    dev->stats.rx_length_errors += in_8(&mb->rntpc); /* reading clears it */
     if (intr & CERR)
-	++mp->stats.tx_heartbeat_errors;
+	++dev->stats.tx_heartbeat_errors;
     if (intr & BABBLE)
 	if (mace_babbles++ < 4)
 	    printk(KERN_DEBUG "mace: babbling transmitter\n");
@@ -681,7 +668,7 @@
     spin_lock_irqsave(&mp->lock, flags);
     intr = in_8(&mb->ir);		/* read interrupt register */
     in_8(&mb->xmtrc);			/* get retries */
-    mace_handle_misc_intrs(mp, intr);
+    mace_handle_misc_intrs(mp, intr, dev);
 
     i = mp->tx_empty;
     while (in_8(&mb->pr) & XMTSV) {
@@ -694,7 +681,7 @@
 	 */
 	intr = in_8(&mb->ir);
 	if (intr != 0)
-	    mace_handle_misc_intrs(mp, intr);
+	    mace_handle_misc_intrs(mp, intr, dev);
 	if (mp->tx_bad_runt) {
 	    fs = in_8(&mb->xmtfs);
 	    mp->tx_bad_runt = 0;
@@ -768,14 +755,14 @@
 	}
 	/* Update stats */
 	if (fs & (UFLO|LCOL|LCAR|RTRY)) {
-	    ++mp->stats.tx_errors;
+	    ++dev->stats.tx_errors;
 	    if (fs & LCAR)
-		++mp->stats.tx_carrier_errors;
+		++dev->stats.tx_carrier_errors;
 	    if (fs & (UFLO|LCOL|RTRY))
-		++mp->stats.tx_aborted_errors;
+		++dev->stats.tx_aborted_errors;
 	} else {
-	    mp->stats.tx_bytes += mp->tx_bufs[i]->len;
-	    ++mp->stats.tx_packets;
+	    dev->stats.tx_bytes += mp->tx_bufs[i]->len;
+	    ++dev->stats.tx_packets;
 	}
 	dev_kfree_skb_irq(mp->tx_bufs[i]);
 	--mp->tx_active;
@@ -829,7 +816,7 @@
 	goto out;
 
     /* update various counters */
-    mace_handle_misc_intrs(mp, in_8(&mb->ir));
+    mace_handle_misc_intrs(mp, in_8(&mb->ir), dev);
 
     cp = mp->tx_cmds + NCMDS_TX * mp->tx_empty;
 
@@ -849,7 +836,7 @@
     /* fix up the transmit side */
     i = mp->tx_empty;
     mp->tx_active = 0;
-    ++mp->stats.tx_errors;
+    ++dev->stats.tx_errors;
     if (mp->tx_bad_runt) {
 	mp->tx_bad_runt = 0;
     } else if (i != mp->tx_fill) {
@@ -917,18 +904,18 @@
 	/* got a packet, have a look at it */
 	skb = mp->rx_bufs[i];
 	if (skb == 0) {
-	    ++mp->stats.rx_dropped;
+	    ++dev->stats.rx_dropped;
 	} else if (nb > 8) {
 	    data = skb->data;
 	    frame_status = (data[nb-3] << 8) + data[nb-4];
 	    if (frame_status & (RS_OFLO|RS_CLSN|RS_FRAMERR|RS_FCSERR)) {
-		++mp->stats.rx_errors;
+		++dev->stats.rx_errors;
 		if (frame_status & RS_OFLO)
-		    ++mp->stats.rx_over_errors;
+		    ++dev->stats.rx_over_errors;
 		if (frame_status & RS_FRAMERR)
-		    ++mp->stats.rx_frame_errors;
+		    ++dev->stats.rx_frame_errors;
 		if (frame_status & RS_FCSERR)
-		    ++mp->stats.rx_crc_errors;
+		    ++dev->stats.rx_crc_errors;
 	    } else {
 		/* Mace feature AUTO_STRIP_RCV is on by default, dropping the
 		 * FCS on frames with 802.3 headers. This means that Ethernet
@@ -940,15 +927,15 @@
 		    nb -= 8;
 		skb_put(skb, nb);
 		skb->protocol = eth_type_trans(skb, dev);
-		mp->stats.rx_bytes += skb->len;
+		dev->stats.rx_bytes += skb->len;
 		netif_rx(skb);
 		dev->last_rx = jiffies;
 		mp->rx_bufs[i] = NULL;
-		++mp->stats.rx_packets;
+		++dev->stats.rx_packets;
 	    }
 	} else {
-	    ++mp->stats.rx_errors;
-	    ++mp->stats.rx_length_errors;
+	    ++dev->stats.rx_errors;
+	    ++dev->stats.rx_length_errors;
 	}
 
 	/* advance to next */
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 9a343b96..6589239 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -65,7 +65,6 @@
 	unsigned char *rx_ring;
 	dma_addr_t rx_ring_phys;
 	int dma_intr;
-	struct net_device_stats stats;
 	int rx_slot, rx_tail;
 	int tx_slot, tx_sloti, tx_count;
 	int chipid;
@@ -92,7 +91,6 @@
 static int mace_open(struct net_device *dev);
 static int mace_close(struct net_device *dev);
 static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
-static struct net_device_stats *mace_stats(struct net_device *dev);
 static void mace_set_multicast(struct net_device *dev);
 static int mace_set_address(struct net_device *dev, void *addr);
 static void mace_reset(struct net_device *dev);
@@ -196,6 +194,7 @@
 	unsigned char checksum = 0;
 	static int found = 0;
 	int err;
+	DECLARE_MAC_BUF(mac);
 
 	if (found || macintosh_config->ether_type != MAC_ETHER_MACE)
 		return -ENODEV;
@@ -210,7 +209,6 @@
 
 	mp->device = &pdev->dev;
 	SET_NETDEV_DEV(dev, &pdev->dev);
- 	SET_MODULE_OWNER(dev);
 
 	dev->base_addr = (u32)MACE_BASE;
 	mp->mace = (volatile struct mace *) MACE_BASE;
@@ -243,20 +241,16 @@
 		return -ENODEV;
 	}
 
-	memset(&mp->stats, 0, sizeof(mp->stats));
-
 	dev->open		= mace_open;
 	dev->stop		= mace_close;
 	dev->hard_start_xmit	= mace_xmit_start;
 	dev->tx_timeout		= mace_tx_timeout;
 	dev->watchdog_timeo	= TX_TIMEOUT;
-	dev->get_stats		= mace_stats;
 	dev->set_multicast_list	= mace_set_multicast;
 	dev->set_mac_address	= mace_set_address;
 
-	printk(KERN_INFO "%s: 68K MACE, hardware address %.2X", dev->name, dev->dev_addr[0]);
-	for (j = 1 ; j < 6 ; j++) printk(":%.2X", dev->dev_addr[j]);
-	printk("\n");
+	printk(KERN_INFO "%s: 68K MACE, hardware address %s\n",
+	       dev->name, print_mac(mac, dev->dev_addr));
 
 	err = register_netdev(dev);
 	if (!err)
@@ -473,8 +467,8 @@
 	mp->tx_count--;
 	local_irq_restore(flags);
 
-	mp->stats.tx_packets++;
-	mp->stats.tx_bytes += skb->len;
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
 
 	/* We need to copy into our xmit buffer to take care of alignment and caching issues */
 	skb_copy_from_linear_data(skb, mp->tx_ring, skb->len);
@@ -493,12 +487,6 @@
 	return NETDEV_TX_OK;
 }
 
-static struct net_device_stats *mace_stats(struct net_device *dev)
-{
-	struct mace_data *mp = netdev_priv(dev);
-	return &mp->stats;
-}
-
 static void mace_set_multicast(struct net_device *dev)
 {
 	struct mace_data *mp = netdev_priv(dev);
@@ -556,13 +544,13 @@
 	static int mace_babbles, mace_jabbers;
 
 	if (intr & MPCO)
-		mp->stats.rx_missed_errors += 256;
-	mp->stats.rx_missed_errors += mb->mpc;   /* reading clears it */
+		dev->stats.rx_missed_errors += 256;
+	dev->stats.rx_missed_errors += mb->mpc;   /* reading clears it */
 	if (intr & RNTPCO)
-		mp->stats.rx_length_errors += 256;
-	mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */
+		dev->stats.rx_length_errors += 256;
+	dev->stats.rx_length_errors += mb->rntpc; /* reading clears it */
 	if (intr & CERR)
-		++mp->stats.tx_heartbeat_errors;
+		++dev->stats.tx_heartbeat_errors;
 	if (intr & BABBLE)
 		if (mace_babbles++ < 4)
 			printk(KERN_DEBUG "macmace: babbling transmitter\n");
@@ -601,14 +589,14 @@
 		}
 		/* Update stats */
 		if (fs & (UFLO|LCOL|LCAR|RTRY)) {
-			++mp->stats.tx_errors;
+			++dev->stats.tx_errors;
 			if (fs & LCAR)
-				++mp->stats.tx_carrier_errors;
+				++dev->stats.tx_carrier_errors;
 			else if (fs & (UFLO|LCOL|RTRY)) {
-				++mp->stats.tx_aborted_errors;
+				++dev->stats.tx_aborted_errors;
 				if (mb->xmtfs & UFLO) {
 					printk(KERN_ERR "%s: DMA underrun.\n", dev->name);
-					mp->stats.tx_fifo_errors++;
+					dev->stats.tx_fifo_errors++;
 					mace_txdma_reset(dev);
 				}
 			}
@@ -662,23 +650,23 @@
 	unsigned int frame_status = mf->rcvsts;
 
 	if (frame_status & (RS_OFLO | RS_CLSN | RS_FRAMERR | RS_FCSERR)) {
-		mp->stats.rx_errors++;
+		dev->stats.rx_errors++;
 		if (frame_status & RS_OFLO) {
 			printk(KERN_DEBUG "%s: fifo overflow.\n", dev->name);
-			mp->stats.rx_fifo_errors++;
+			dev->stats.rx_fifo_errors++;
 		}
 		if (frame_status & RS_CLSN)
-			mp->stats.collisions++;
+			dev->stats.collisions++;
 		if (frame_status & RS_FRAMERR)
-			mp->stats.rx_frame_errors++;
+			dev->stats.rx_frame_errors++;
 		if (frame_status & RS_FCSERR)
-			mp->stats.rx_crc_errors++;
+			dev->stats.rx_crc_errors++;
 	} else {
 		unsigned int frame_length = mf->rcvcnt + ((frame_status & 0x0F) << 8 );
 
 		skb = dev_alloc_skb(frame_length + 2);
 		if (!skb) {
-			mp->stats.rx_dropped++;
+			dev->stats.rx_dropped++;
 			return;
 		}
 		skb_reserve(skb, 2);
@@ -687,8 +675,8 @@
 		skb->protocol = eth_type_trans(skb, dev);
 		netif_rx(skb);
 		dev->last_rx = jiffies;
-		mp->stats.rx_packets++;
-		mp->stats.rx_bytes += frame_length;
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += frame_length;
 	}
 }
 
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index e9ecdbf..b267161 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -223,6 +223,7 @@
 	struct sonic_local *lp = netdev_priv(dev);
 	const int prom_addr = ONBOARD_SONIC_PROM_BASE;
 	int i;
+	DECLARE_MAC_BUF(mac);
 
 	/* On NuBus boards we can sometimes look in the ROM resources.
 	   No such luck for comm-slot/onboard. */
@@ -266,13 +267,8 @@
 		dev->dev_addr[1] = val >> 8;
 		dev->dev_addr[0] = val & 0xff;
 
-		printk(KERN_INFO "HW Address from CAM 15: ");
-		for (i = 0; i < 6; i++) {
-			printk("%2.2x", dev->dev_addr[i]);
-			if (i < 5)
-				printk(":");
-		}
-		printk("\n");
+		printk(KERN_INFO "HW Address from CAM 15: %s\n",
+		       print_mac(mac, dev->dev_addr));
 	} else return 0;
 
 	if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) &&
@@ -567,7 +563,7 @@
 	struct net_device *dev;
 	struct sonic_local *lp;
 	int err;
-	int i;
+	DECLARE_MAC_BUF(mac);
 
 	dev = alloc_etherdev(sizeof(struct sonic_local));
 	if (!dev)
@@ -576,7 +572,6 @@
 	lp = netdev_priv(dev);
 	lp->device = &pdev->dev;
 	SET_NETDEV_DEV(dev, &pdev->dev);
- 	SET_MODULE_OWNER(dev);
 
 	/* This will catch fatal stuff like -ENOMEM as well as success */
 	err = mac_onboard_sonic_probe(dev);
@@ -592,13 +587,8 @@
 	if (err)
 		goto out;
 
-	printk("%s: MAC ", dev->name);
-	for (i = 0; i < 6; i++) {
-		printk("%2.2x", dev->dev_addr[i]);
-		if (i < 5)
-			printk(":");
-	}
-	printk(" IRQ %d\n", dev->irq);
+	printk("%s: MAC %s IRQ %d\n",
+	       dev->name, print_mac(mac, dev->dev_addr), dev->irq);
 
 	return 0;
 
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index dc74d00..b7c81c8 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -164,16 +164,25 @@
 }
 
 static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev,
-			       unsigned short type, void *daddr, void *saddr,
-			       unsigned len)
+			       unsigned short type, const void *daddr,
+			       const void *saddr, unsigned len)
 {
 	const struct macvlan_dev *vlan = netdev_priv(dev);
 	struct net_device *lowerdev = vlan->lowerdev;
 
-	return lowerdev->hard_header(skb, lowerdev, type, daddr,
-				     saddr ? : dev->dev_addr, len);
+	return dev_hard_header(skb, lowerdev, type, daddr,
+			       saddr ? : dev->dev_addr, len);
 }
 
+static const struct header_ops macvlan_hard_header_ops = {
+	.create  	= macvlan_hard_header,
+	.rebuild	= eth_rebuild_header,
+	.parse		= eth_header_parse,
+	.rebuild	= eth_rebuild_header,
+	.cache		= eth_header_cache,
+	.cache_update	= eth_header_cache_update,
+};
+
 static int macvlan_open(struct net_device *dev)
 {
 	struct macvlan_dev *vlan = netdev_priv(dev);
@@ -282,10 +291,6 @@
 static const struct ethtool_ops macvlan_ethtool_ops = {
 	.get_link		= ethtool_op_get_link,
 	.get_rx_csum		= macvlan_ethtool_get_rx_csum,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.get_tso		= ethtool_op_get_tso,
-	.get_ufo		= ethtool_op_get_ufo,
-	.get_sg			= ethtool_op_get_sg,
 	.get_drvinfo		= macvlan_ethtool_get_drvinfo,
 };
 
@@ -299,9 +304,9 @@
 	dev->change_mtu		= macvlan_change_mtu;
 	dev->change_rx_flags	= macvlan_change_rx_flags;
 	dev->set_multicast_list	= macvlan_set_multicast_list;
-	dev->hard_header	= macvlan_hard_header;
 	dev->hard_start_xmit	= macvlan_hard_start_xmit;
 	dev->destructor		= free_netdev;
+	dev->header_ops		= &macvlan_hard_header_ops,
 	dev->ethtool_ops	= &macvlan_ethtool_ops;
 	dev->tx_queue_len	= 0;
 }
@@ -376,7 +381,7 @@
 	if (!tb[IFLA_LINK])
 		return -EINVAL;
 
-	lowerdev = __dev_get_by_index(nla_get_u32(tb[IFLA_LINK]));
+	lowerdev = __dev_get_by_index(dev->nd_net, nla_get_u32(tb[IFLA_LINK]));
 	if (lowerdev == NULL)
 		return -ENODEV;
 
diff --git a/drivers/net/meth.c b/drivers/net/meth.c
index 92b403b..e25dbab 100644
--- a/drivers/net/meth.c
+++ b/drivers/net/meth.c
@@ -66,7 +66,6 @@
  * packets in and out, so there is place for a packet
  */
 struct meth_private {
-	struct net_device_stats stats;
 	/* in-memory copy of MAC Control register */
 	unsigned long mac_ctrl;
 	/* in-memory copy of DMA Control register */
@@ -96,11 +95,11 @@
 static inline void load_eaddr(struct net_device *dev)
 {
 	int i;
-	DPRINTK("Loading MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
-		(int)o2meth_eaddr[0]&0xFF,(int)o2meth_eaddr[1]&0xFF,(int)o2meth_eaddr[2]&0xFF,
-		(int)o2meth_eaddr[3]&0xFF,(int)o2meth_eaddr[4]&0xFF,(int)o2meth_eaddr[5]&0xFF);
+	DECLARE_MAC_BUF(mac);
+
 	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = o2meth_eaddr[i];
+	DPRINTK("Loading MAC Address: %s\n", print_mac(mac, dev->dev_addr));
 	mace->eth.mac_addr = (*(unsigned long*)o2meth_eaddr) >> 16;
 }
 
@@ -401,15 +400,15 @@
 				printk(KERN_DEBUG "%s: bogus packet size: %ld, status=%#2lx.\n",
 				       dev->name, priv->rx_write,
 				       priv->rx_ring[priv->rx_write]->status.raw);
-				priv->stats.rx_errors++;
-				priv->stats.rx_length_errors++;
+				dev->stats.rx_errors++;
+				dev->stats.rx_length_errors++;
 				skb = priv->rx_skbs[priv->rx_write];
 			} else {
-				skb = alloc_skb(METH_RX_BUFF_SIZE, GFP_ATOMIC | GFP_DMA);
+				skb = alloc_skb(METH_RX_BUFF_SIZE, GFP_ATOMIC);
 				if (!skb) {
 					/* Ouch! No memory! Drop packet on the floor */
 					DPRINTK("No mem: dropping packet\n");
-					priv->stats.rx_dropped++;
+					dev->stats.rx_dropped++;
 					skb = priv->rx_skbs[priv->rx_write];
 				} else {
 					struct sk_buff *skb_c = priv->rx_skbs[priv->rx_write];
@@ -421,13 +420,13 @@
 					priv->rx_skbs[priv->rx_write] = skb;
 					skb_c->protocol = eth_type_trans(skb_c, dev);
 					dev->last_rx = jiffies;
-					priv->stats.rx_packets++;
-					priv->stats.rx_bytes += len;
+					dev->stats.rx_packets++;
+					dev->stats.rx_bytes += len;
 					netif_rx(skb_c);
 				}
 			}
 		} else {
-			priv->stats.rx_errors++;
+			dev->stats.rx_errors++;
 			skb=priv->rx_skbs[priv->rx_write];
 #if MFE_DEBUG>0
 			printk(KERN_WARNING "meth: RX error: status=0x%016lx\n",status);
@@ -490,10 +489,10 @@
 #endif
 		if (status & METH_TX_ST_DONE) {
 			if (status & METH_TX_ST_SUCCESS){
-				priv->stats.tx_packets++;
-				priv->stats.tx_bytes += skb->len;
+				dev->stats.tx_packets++;
+				dev->stats.tx_bytes += skb->len;
 			} else {
-				priv->stats.tx_errors++;
+				dev->stats.tx_errors++;
 #if MFE_DEBUG>=1
 				DPRINTK("TX error: status=%016lx <",status);
 				if(status & METH_TX_ST_SUCCESS)
@@ -734,7 +733,7 @@
 	/* Try to reset the interface. */
 	meth_reset(dev);
 
-	priv->stats.tx_errors++;
+	dev->stats.tx_errors++;
 
 	/* Clear all rings */
 	meth_free_tx_ring(priv);
@@ -773,12 +772,6 @@
 /*
  * Return statistics to the caller
  */
-static struct net_device_stats *meth_stats(struct net_device *dev)
-{
-	struct meth_private *priv = netdev_priv(dev);
-	return &priv->stats;
-}
-
 /*
  * The init function.
  */
@@ -796,7 +789,6 @@
 	dev->stop            = meth_release;
 	dev->hard_start_xmit = meth_tx;
 	dev->do_ioctl        = meth_ioctl;
-	dev->get_stats       = meth_stats;
 #ifdef HAVE_TX_TIMEOUT
 	dev->tx_timeout      = meth_tx_timeout;
 	dev->watchdog_timeo  = timeout;
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
index 9853c74..d593175 100644
--- a/drivers/net/mipsnet.c
+++ b/drivers/net/mipsnet.c
@@ -11,7 +11,6 @@
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
-#include <linux/netdevice.h>
 #include <linux/platform_device.h>
 #include <asm/io.h>
 #include <asm/mips-boards/simint.h>
@@ -22,10 +21,6 @@
 
 #define mipsnet_reg_address(dev, field) (dev->base_addr + field_offset(field))
 
-struct mipsnet_priv {
-	struct net_device_stats stats;
-};
-
 static char mipsnet_string[] = "mipsnet";
 
 /*
@@ -50,7 +45,6 @@
 {
 	int count_to_go = skb->len;
 	char *buf_ptr = skb->data;
-	struct mipsnet_priv *mp = netdev_priv(dev);
 
 	pr_debug("%s: %s(): telling MIPSNET txDataCount(%d)\n",
 	         dev->name, __FUNCTION__, skb->len);
@@ -64,8 +58,8 @@
 		outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer));
 	}
 
-	mp->stats.tx_packets++;
-	mp->stats.tx_bytes += skb->len;
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
 
 	return skb->len;
 }
@@ -88,10 +82,9 @@
 {
 	struct sk_buff *skb;
 	size_t len = count;
-	struct mipsnet_priv *mp = netdev_priv(dev);
 
 	if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) {
-		mp->stats.rx_dropped++;
+		dev->stats.rx_dropped++;
 		return -ENOMEM;
 	}
 
@@ -106,8 +99,8 @@
 	         dev->name, __FUNCTION__);
 	netif_rx(skb);
 
-	mp->stats.rx_packets++;
-	mp->stats.rx_bytes += len;
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += len;
 
 	return count;
 }
@@ -204,13 +197,6 @@
 	return 0;
 }
 
-static struct net_device_stats *mipsnet_get_stats(struct net_device *dev)
-{
-	struct mipsnet_priv *mp = netdev_priv(dev);
-
-	return &mp->stats;
-}
-
 static void mipsnet_set_mclist(struct net_device *dev)
 {
 	// we don't do anything
@@ -222,7 +208,7 @@
 	struct net_device *netdev;
 	int err;
 
-	netdev = alloc_etherdev(sizeof(struct mipsnet_priv));
+	netdev = alloc_etherdev(0);
 	if (!netdev) {
 		err = -ENOMEM;
 		goto out;
@@ -233,7 +219,6 @@
 	netdev->open			= mipsnet_open;
 	netdev->stop			= mipsnet_close;
 	netdev->hard_start_xmit		= mipsnet_xmit;
-	netdev->get_stats		= mipsnet_get_stats;
 	netdev->set_multicast_list	= mipsnet_set_mclist;
 
 	/*
diff --git a/drivers/net/mlx4/catas.c b/drivers/net/mlx4/catas.c
index 1bb088a..6b32ec9 100644
--- a/drivers/net/mlx4/catas.c
+++ b/drivers/net/mlx4/catas.c
@@ -30,41 +30,133 @@
  * SOFTWARE.
  */
 
+#include <linux/workqueue.h>
+
 #include "mlx4.h"
 
-void mlx4_handle_catas_err(struct mlx4_dev *dev)
+enum {
+	MLX4_CATAS_POLL_INTERVAL	= 5 * HZ,
+};
+
+static DEFINE_SPINLOCK(catas_lock);
+
+static LIST_HEAD(catas_list);
+static struct workqueue_struct *catas_wq;
+static struct work_struct catas_work;
+
+static int internal_err_reset = 1;
+module_param(internal_err_reset, int, 0644);
+MODULE_PARM_DESC(internal_err_reset,
+		 "Reset device on internal errors if non-zero (default 1)");
+
+static void dump_err_buf(struct mlx4_dev *dev)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
 
 	int i;
 
-	mlx4_err(dev, "Catastrophic error detected:\n");
+	mlx4_err(dev, "Internal error detected:\n");
 	for (i = 0; i < priv->fw.catas_size; ++i)
 		mlx4_err(dev, "  buf[%02x]: %08x\n",
 			 i, swab32(readl(priv->catas_err.map + i)));
-
-	mlx4_dispatch_event(dev, MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR, 0, 0);
 }
 
-void mlx4_map_catas_buf(struct mlx4_dev *dev)
+static void poll_catas(unsigned long dev_ptr)
+{
+	struct mlx4_dev *dev = (struct mlx4_dev *) dev_ptr;
+	struct mlx4_priv *priv = mlx4_priv(dev);
+
+	if (readl(priv->catas_err.map)) {
+		dump_err_buf(dev);
+
+		mlx4_dispatch_event(dev, MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR, 0, 0);
+
+		if (internal_err_reset) {
+			spin_lock(&catas_lock);
+			list_add(&priv->catas_err.list, &catas_list);
+			spin_unlock(&catas_lock);
+
+			queue_work(catas_wq, &catas_work);
+		}
+	} else
+		mod_timer(&priv->catas_err.timer,
+			  round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL));
+}
+
+static void catas_reset(struct work_struct *work)
+{
+	struct mlx4_priv *priv, *tmppriv;
+	struct mlx4_dev *dev;
+
+	LIST_HEAD(tlist);
+	int ret;
+
+	spin_lock_irq(&catas_lock);
+	list_splice_init(&catas_list, &tlist);
+	spin_unlock_irq(&catas_lock);
+
+	list_for_each_entry_safe(priv, tmppriv, &tlist, catas_err.list) {
+		ret = mlx4_restart_one(priv->dev.pdev);
+		dev = &priv->dev;
+		if (ret)
+			mlx4_err(dev, "Reset failed (%d)\n", ret);
+		else
+			mlx4_dbg(dev, "Reset succeeded\n");
+	}
+}
+
+void mlx4_start_catas_poll(struct mlx4_dev *dev)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
 	unsigned long addr;
 
+	INIT_LIST_HEAD(&priv->catas_err.list);
+	init_timer(&priv->catas_err.timer);
+	priv->catas_err.map = NULL;
+
 	addr = pci_resource_start(dev->pdev, priv->fw.catas_bar) +
 		priv->fw.catas_offset;
 
 	priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4);
-	if (!priv->catas_err.map)
-		mlx4_warn(dev, "Failed to map catastrophic error buffer at 0x%lx\n",
+	if (!priv->catas_err.map) {
+		mlx4_warn(dev, "Failed to map internal error buffer at 0x%lx\n",
 			  addr);
+		return;
+	}
 
+	priv->catas_err.timer.data     = (unsigned long) dev;
+	priv->catas_err.timer.function = poll_catas;
+	priv->catas_err.timer.expires  =
+		round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL);
+	add_timer(&priv->catas_err.timer);
 }
 
-void mlx4_unmap_catas_buf(struct mlx4_dev *dev)
+void mlx4_stop_catas_poll(struct mlx4_dev *dev)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
 
+	del_timer_sync(&priv->catas_err.timer);
+
 	if (priv->catas_err.map)
 		iounmap(priv->catas_err.map);
+
+	spin_lock_irq(&catas_lock);
+	list_del(&priv->catas_err.list);
+	spin_unlock_irq(&catas_lock);
+}
+
+int __init mlx4_catas_init(void)
+{
+	INIT_WORK(&catas_work, catas_reset);
+
+	catas_wq = create_singlethread_workqueue("mlx4_err");
+	if (!catas_wq)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void mlx4_catas_cleanup(void)
+{
+	destroy_workqueue(catas_wq);
 }
diff --git a/drivers/net/mlx4/cmd.c b/drivers/net/mlx4/cmd.c
index c1f81a9..db49051 100644
--- a/drivers/net/mlx4/cmd.c
+++ b/drivers/net/mlx4/cmd.c
@@ -95,7 +95,7 @@
 };
 
 enum {
-	GO_BIT_TIMEOUT		= 10000
+	GO_BIT_TIMEOUT_MSECS	= 10000
 };
 
 struct mlx4_cmd_context {
@@ -155,7 +155,7 @@
 
 	end = jiffies;
 	if (event)
-		end += HZ * 10;
+		end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS);
 
 	while (cmd_pending(dev)) {
 		if (time_after_eq(jiffies, end))
@@ -184,6 +184,13 @@
 					       (event ? (1 << HCR_E_BIT) : 0)	|
 					       (op_modifier << HCR_OPMOD_SHIFT) |
 					       op),			  hcr + 6);
+
+	/*
+	 * Make sure that our HCR writes don't get mixed in with
+	 * writes from another CPU starting a FW command.
+	 */
+	mmiowb();
+
 	cmd->toggle = cmd->toggle ^ 1;
 
 	ret = 0;
@@ -246,8 +253,6 @@
 	context->result    = mlx4_status_to_errno(status);
 	context->out_param = out_param;
 
-	context->token += priv->cmd.token_mask + 1;
-
 	complete(&context->done);
 }
 
@@ -264,6 +269,7 @@
 	spin_lock(&cmd->context_lock);
 	BUG_ON(cmd->free_head < 0);
 	context = &cmd->context[cmd->free_head];
+	context->token += cmd->token_mask + 1;
 	cmd->free_head = context->next;
 	spin_unlock(&cmd->context_lock);
 
diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c
index 39253d0..d4441fe 100644
--- a/drivers/net/mlx4/cq.c
+++ b/drivers/net/mlx4/cq.c
@@ -231,7 +231,7 @@
 }
 EXPORT_SYMBOL_GPL(mlx4_cq_free);
 
-int __devinit mlx4_init_cq_table(struct mlx4_dev *dev)
+int mlx4_init_cq_table(struct mlx4_dev *dev)
 {
 	struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table;
 	int err;
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
index 27a82ce..9c36c20 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/mlx4/eq.c
@@ -89,14 +89,12 @@
 			       (1ull << MLX4_EVENT_TYPE_PATH_MIG_FAILED)    | \
 			       (1ull << MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \
 			       (1ull << MLX4_EVENT_TYPE_WQ_ACCESS_ERROR)    | \
-			       (1ull << MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR)  | \
 			       (1ull << MLX4_EVENT_TYPE_PORT_CHANGE)	    | \
 			       (1ull << MLX4_EVENT_TYPE_ECC_DETECT)	    | \
 			       (1ull << MLX4_EVENT_TYPE_SRQ_CATAS_ERROR)    | \
 			       (1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE)    | \
 			       (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT)	    | \
 			       (1ull << MLX4_EVENT_TYPE_CMD))
-#define MLX4_CATAS_EVENT_MASK  (1ull << MLX4_EVENT_TYPE_LOCAL_CATAS_ERROR)
 
 struct mlx4_eqe {
 	u8			reserved1;
@@ -264,7 +262,7 @@
 
 	writel(priv->eq_table.clr_mask, priv->eq_table.clr_int);
 
-	for (i = 0; i < MLX4_EQ_CATAS; ++i)
+	for (i = 0; i < MLX4_NUM_EQ; ++i)
 		work |= mlx4_eq_int(dev, &priv->eq_table.eq[i]);
 
 	return IRQ_RETVAL(work);
@@ -281,14 +279,6 @@
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t mlx4_catas_interrupt(int irq, void *dev_ptr)
-{
-	mlx4_handle_catas_err(dev_ptr);
-
-	/* MSI-X vectors always belong to us */
-	return IRQ_HANDLED;
-}
-
 static int mlx4_MAP_EQ(struct mlx4_dev *dev, u64 event_mask, int unmap,
 			int eq_num)
 {
@@ -310,8 +300,7 @@
 			    MLX4_CMD_TIME_CLASS_A);
 }
 
-static void __devinit __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev,
-					       struct mlx4_eq *eq)
+static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
 	int index;
@@ -333,8 +322,8 @@
 	return priv->eq_table.uar_map[index] + 0x800 + 8 * (eq->eqn % 4);
 }
 
-static int __devinit mlx4_create_eq(struct mlx4_dev *dev, int nent,
-				    u8 intr, struct mlx4_eq *eq)
+static int mlx4_create_eq(struct mlx4_dev *dev, int nent,
+			  u8 intr, struct mlx4_eq *eq)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
 	struct mlx4_cmd_mailbox *mailbox;
@@ -490,14 +479,12 @@
 
 	if (eq_table->have_irq)
 		free_irq(dev->pdev->irq, dev);
-	for (i = 0; i < MLX4_EQ_CATAS; ++i)
+	for (i = 0; i < MLX4_NUM_EQ; ++i)
 		if (eq_table->eq[i].have_irq)
 			free_irq(eq_table->eq[i].irq, eq_table->eq + i);
-	if (eq_table->eq[MLX4_EQ_CATAS].have_irq)
-		free_irq(eq_table->eq[MLX4_EQ_CATAS].irq, dev);
 }
 
-static int __devinit mlx4_map_clr_int(struct mlx4_dev *dev)
+static int mlx4_map_clr_int(struct mlx4_dev *dev)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
 
@@ -518,7 +505,7 @@
 	iounmap(priv->clr_base);
 }
 
-int __devinit mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt)
+int mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
 	int ret;
@@ -560,7 +547,7 @@
 	__free_page(priv->eq_table.icm_page);
 }
 
-int __devinit mlx4_init_eq_table(struct mlx4_dev *dev)
+int mlx4_init_eq_table(struct mlx4_dev *dev)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
 	int err;
@@ -598,32 +585,19 @@
 	if (dev->flags & MLX4_FLAG_MSI_X) {
 		static const char *eq_name[] = {
 			[MLX4_EQ_COMP]  = DRV_NAME " (comp)",
-			[MLX4_EQ_ASYNC] = DRV_NAME " (async)",
-			[MLX4_EQ_CATAS] = DRV_NAME " (catas)"
+			[MLX4_EQ_ASYNC] = DRV_NAME " (async)"
 		};
 
-		err = mlx4_create_eq(dev, 1, MLX4_EQ_CATAS,
-				     &priv->eq_table.eq[MLX4_EQ_CATAS]);
-		if (err)
-			goto err_out_async;
-
-		for (i = 0; i < MLX4_EQ_CATAS; ++i) {
+		for (i = 0; i < MLX4_NUM_EQ; ++i) {
 			err = request_irq(priv->eq_table.eq[i].irq,
 					  mlx4_msi_x_interrupt,
 					  0, eq_name[i], priv->eq_table.eq + i);
 			if (err)
-				goto err_out_catas;
+				goto err_out_async;
 
 			priv->eq_table.eq[i].have_irq = 1;
 		}
 
-		err = request_irq(priv->eq_table.eq[MLX4_EQ_CATAS].irq,
-				  mlx4_catas_interrupt, 0,
-				  eq_name[MLX4_EQ_CATAS], dev);
-		if (err)
-			goto err_out_catas;
-
-		priv->eq_table.eq[MLX4_EQ_CATAS].have_irq = 1;
 	} else {
 		err = request_irq(dev->pdev->irq, mlx4_interrupt,
 				  IRQF_SHARED, DRV_NAME, dev);
@@ -639,22 +613,11 @@
 		mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n",
 			   priv->eq_table.eq[MLX4_EQ_ASYNC].eqn, err);
 
-	for (i = 0; i < MLX4_EQ_CATAS; ++i)
+	for (i = 0; i < MLX4_NUM_EQ; ++i)
 		eq_set_ci(&priv->eq_table.eq[i], 1);
 
-	if (dev->flags & MLX4_FLAG_MSI_X) {
-		err = mlx4_MAP_EQ(dev, MLX4_CATAS_EVENT_MASK, 0,
-				  priv->eq_table.eq[MLX4_EQ_CATAS].eqn);
-		if (err)
-			mlx4_warn(dev, "MAP_EQ for catas EQ %d failed (%d)\n",
-				  priv->eq_table.eq[MLX4_EQ_CATAS].eqn, err);
-	}
-
 	return 0;
 
-err_out_catas:
-	mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_CATAS]);
-
 err_out_async:
 	mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_ASYNC]);
 
@@ -675,19 +638,13 @@
 	struct mlx4_priv *priv = mlx4_priv(dev);
 	int i;
 
-	if (dev->flags & MLX4_FLAG_MSI_X)
-		mlx4_MAP_EQ(dev, MLX4_CATAS_EVENT_MASK, 1,
-			    priv->eq_table.eq[MLX4_EQ_CATAS].eqn);
-
 	mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1,
 		    priv->eq_table.eq[MLX4_EQ_ASYNC].eqn);
 
 	mlx4_free_irqs(dev);
 
-	for (i = 0; i < MLX4_EQ_CATAS; ++i)
+	for (i = 0; i < MLX4_NUM_EQ; ++i)
 		mlx4_free_eq(dev, &priv->eq_table.eq[i]);
-	if (dev->flags & MLX4_FLAG_MSI_X)
-		mlx4_free_eq(dev, &priv->eq_table.eq[MLX4_EQ_CATAS]);
 
 	mlx4_unmap_clr_int(dev);
 
diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c
index c45cbe4..6471d33 100644
--- a/drivers/net/mlx4/fw.c
+++ b/drivers/net/mlx4/fw.c
@@ -76,7 +76,7 @@
 		[ 0] = "RC transport",
 		[ 1] = "UC transport",
 		[ 2] = "UD transport",
-		[ 3] = "SRC transport",
+		[ 3] = "XRC transport",
 		[ 4] = "reliable multicast",
 		[ 5] = "FCoIB support",
 		[ 6] = "SRQ support",
diff --git a/drivers/net/mlx4/icm.c b/drivers/net/mlx4/icm.c
index b7a4aa8..4b3c109d 100644
--- a/drivers/net/mlx4/icm.c
+++ b/drivers/net/mlx4/icm.c
@@ -34,6 +34,7 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/mm.h>
+#include <linux/scatterlist.h>
 
 #include <linux/mlx4/cmd.h>
 
@@ -50,19 +51,41 @@
 	MLX4_TABLE_CHUNK_SIZE	= 1 << 18
 };
 
-void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm)
+static void mlx4_free_icm_pages(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk)
 {
-	struct mlx4_icm_chunk *chunk, *tmp;
 	int i;
 
-	list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) {
-		if (chunk->nsg > 0)
-			pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages,
-				     PCI_DMA_BIDIRECTIONAL);
+	if (chunk->nsg > 0)
+		pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages,
+			     PCI_DMA_BIDIRECTIONAL);
 
-		for (i = 0; i < chunk->npages; ++i)
-			__free_pages(chunk->mem[i].page,
-				     get_order(chunk->mem[i].length));
+	for (i = 0; i < chunk->npages; ++i)
+		__free_pages(chunk->mem[i].page,
+			     get_order(chunk->mem[i].length));
+}
+
+static void mlx4_free_icm_coherent(struct mlx4_dev *dev, struct mlx4_icm_chunk *chunk)
+{
+	int i;
+
+	for (i = 0; i < chunk->npages; ++i)
+		dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length,
+				  lowmem_page_address(chunk->mem[i].page),
+				  sg_dma_address(&chunk->mem[i]));
+}
+
+void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent)
+{
+	struct mlx4_icm_chunk *chunk, *tmp;
+
+	if (!icm)
+		return;
+
+	list_for_each_entry_safe(chunk, tmp, &icm->chunk_list, list) {
+		if (coherent)
+			mlx4_free_icm_coherent(dev, chunk);
+		else
+			mlx4_free_icm_pages(dev, chunk);
 
 		kfree(chunk);
 	}
@@ -70,16 +93,45 @@
 	kfree(icm);
 }
 
+static int mlx4_alloc_icm_pages(struct scatterlist *mem, int order, gfp_t gfp_mask)
+{
+	mem->page = alloc_pages(gfp_mask, order);
+	if (!mem->page)
+		return -ENOMEM;
+
+	mem->length = PAGE_SIZE << order;
+	mem->offset = 0;
+	return 0;
+}
+
+static int mlx4_alloc_icm_coherent(struct device *dev, struct scatterlist *mem,
+				    int order, gfp_t gfp_mask)
+{
+	void *buf = dma_alloc_coherent(dev, PAGE_SIZE << order,
+				       &sg_dma_address(mem), gfp_mask);
+	if (!buf)
+		return -ENOMEM;
+
+	sg_set_buf(mem, buf, PAGE_SIZE << order);
+	BUG_ON(mem->offset);
+	sg_dma_len(mem) = PAGE_SIZE << order;
+	return 0;
+}
+
 struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
-				gfp_t gfp_mask)
+				gfp_t gfp_mask, int coherent)
 {
 	struct mlx4_icm *icm;
 	struct mlx4_icm_chunk *chunk = NULL;
 	int cur_order;
+	int ret;
+
+	/* We use sg_set_buf for coherent allocs, which assumes low memory */
+	BUG_ON(coherent && (gfp_mask & __GFP_HIGHMEM));
 
 	icm = kmalloc(sizeof *icm, gfp_mask & ~(__GFP_HIGHMEM | __GFP_NOWARN));
 	if (!icm)
-		return icm;
+		return NULL;
 
 	icm->refcount = 0;
 	INIT_LIST_HEAD(&icm->chunk_list);
@@ -101,12 +153,20 @@
 		while (1 << cur_order > npages)
 			--cur_order;
 
-		chunk->mem[chunk->npages].page = alloc_pages(gfp_mask, cur_order);
-		if (chunk->mem[chunk->npages].page) {
-			chunk->mem[chunk->npages].length = PAGE_SIZE << cur_order;
-			chunk->mem[chunk->npages].offset = 0;
+		if (coherent)
+			ret = mlx4_alloc_icm_coherent(&dev->pdev->dev,
+						      &chunk->mem[chunk->npages],
+						      cur_order, gfp_mask);
+		else
+			ret = mlx4_alloc_icm_pages(&chunk->mem[chunk->npages],
+						   cur_order, gfp_mask);
 
-			if (++chunk->npages == MLX4_ICM_CHUNK_LEN) {
+		if (!ret) {
+			++chunk->npages;
+
+			if (coherent)
+				++chunk->nsg;
+			else if (chunk->npages == MLX4_ICM_CHUNK_LEN) {
 				chunk->nsg = pci_map_sg(dev->pdev, chunk->mem,
 							chunk->npages,
 							PCI_DMA_BIDIRECTIONAL);
@@ -125,7 +185,7 @@
 		}
 	}
 
-	if (chunk) {
+	if (!coherent && chunk) {
 		chunk->nsg = pci_map_sg(dev->pdev, chunk->mem,
 					chunk->npages,
 					PCI_DMA_BIDIRECTIONAL);
@@ -137,7 +197,7 @@
 	return icm;
 
 fail:
-	mlx4_free_icm(dev, icm);
+	mlx4_free_icm(dev, icm, coherent);
 	return NULL;
 }
 
@@ -202,7 +262,7 @@
 
 	table->icm[i] = mlx4_alloc_icm(dev, MLX4_TABLE_CHUNK_SIZE >> PAGE_SHIFT,
 				       (table->lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
-				       __GFP_NOWARN);
+				       __GFP_NOWARN, table->coherent);
 	if (!table->icm[i]) {
 		ret = -ENOMEM;
 		goto out;
@@ -210,7 +270,7 @@
 
 	if (mlx4_MAP_ICM(dev, table->icm[i], table->virt +
 			 (u64) i * MLX4_TABLE_CHUNK_SIZE)) {
-		mlx4_free_icm(dev, table->icm[i]);
+		mlx4_free_icm(dev, table->icm[i], table->coherent);
 		table->icm[i] = NULL;
 		ret = -ENOMEM;
 		goto out;
@@ -234,16 +294,16 @@
 	if (--table->icm[i]->refcount == 0) {
 		mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE,
 			       MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE);
-		mlx4_free_icm(dev, table->icm[i]);
+		mlx4_free_icm(dev, table->icm[i], table->coherent);
 		table->icm[i] = NULL;
 	}
 
 	mutex_unlock(&table->mutex);
 }
 
-void *mlx4_table_find(struct mlx4_icm_table *table, int obj)
+void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle)
 {
-	int idx, offset, i;
+	int idx, offset, dma_offset, i;
 	struct mlx4_icm_chunk *chunk;
 	struct mlx4_icm *icm;
 	struct page *page = NULL;
@@ -253,15 +313,26 @@
 
 	mutex_lock(&table->mutex);
 
-	idx = obj & (table->num_obj - 1);
-	icm = table->icm[idx / (MLX4_TABLE_CHUNK_SIZE / table->obj_size)];
-	offset = idx % (MLX4_TABLE_CHUNK_SIZE / table->obj_size);
+	idx = (obj & (table->num_obj - 1)) * table->obj_size;
+	icm = table->icm[idx / MLX4_TABLE_CHUNK_SIZE];
+	dma_offset = offset = idx % MLX4_TABLE_CHUNK_SIZE;
 
 	if (!icm)
 		goto out;
 
 	list_for_each_entry(chunk, &icm->chunk_list, list) {
 		for (i = 0; i < chunk->npages; ++i) {
+			if (dma_handle && dma_offset >= 0) {
+				if (sg_dma_len(&chunk->mem[i]) > dma_offset)
+					*dma_handle = sg_dma_address(&chunk->mem[i]) +
+						dma_offset;
+				dma_offset -= sg_dma_len(&chunk->mem[i]);
+			}
+			/*
+			 * DMA mapping can merge pages but not split them,
+			 * so if we found the page, dma_handle has already
+			 * been assigned to.
+			 */
 			if (chunk->mem[i].length > offset) {
 				page = chunk->mem[i].page;
 				goto out;
@@ -309,7 +380,7 @@
 
 int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
 			u64 virt, int obj_size,	int nobj, int reserved,
-			int use_lowmem)
+			int use_lowmem, int use_coherent)
 {
 	int obj_per_chunk;
 	int num_icm;
@@ -327,6 +398,7 @@
 	table->num_obj  = nobj;
 	table->obj_size = obj_size;
 	table->lowmem   = use_lowmem;
+	table->coherent = use_coherent;
 	mutex_init(&table->mutex);
 
 	for (i = 0; i * MLX4_TABLE_CHUNK_SIZE < reserved * obj_size; ++i) {
@@ -336,11 +408,11 @@
 
 		table->icm[i] = mlx4_alloc_icm(dev, chunk_size >> PAGE_SHIFT,
 					       (use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
-					       __GFP_NOWARN);
+					       __GFP_NOWARN, use_coherent);
 		if (!table->icm[i])
 			goto err;
 		if (mlx4_MAP_ICM(dev, table->icm[i], virt + i * MLX4_TABLE_CHUNK_SIZE)) {
-			mlx4_free_icm(dev, table->icm[i]);
+			mlx4_free_icm(dev, table->icm[i], use_coherent);
 			table->icm[i] = NULL;
 			goto err;
 		}
@@ -359,7 +431,7 @@
 		if (table->icm[i]) {
 			mlx4_UNMAP_ICM(dev, virt + i * MLX4_TABLE_CHUNK_SIZE,
 				       MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE);
-			mlx4_free_icm(dev, table->icm[i]);
+			mlx4_free_icm(dev, table->icm[i], use_coherent);
 		}
 
 	return -ENOMEM;
@@ -373,7 +445,7 @@
 		if (table->icm[i]) {
 			mlx4_UNMAP_ICM(dev, table->virt + i * MLX4_TABLE_CHUNK_SIZE,
 				       MLX4_TABLE_CHUNK_SIZE / MLX4_ICM_PAGE_SIZE);
-			mlx4_free_icm(dev, table->icm[i]);
+			mlx4_free_icm(dev, table->icm[i], table->coherent);
 		}
 
 	kfree(table->icm);
diff --git a/drivers/net/mlx4/icm.h b/drivers/net/mlx4/icm.h
index bea223d..6c44edf 100644
--- a/drivers/net/mlx4/icm.h
+++ b/drivers/net/mlx4/icm.h
@@ -67,8 +67,9 @@
 
 struct mlx4_dev;
 
-struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages, gfp_t gfp_mask);
-void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm);
+struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
+				gfp_t gfp_mask, int coherent);
+void mlx4_free_icm(struct mlx4_dev *dev, struct mlx4_icm *icm, int coherent);
 
 int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
 void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
@@ -78,11 +79,11 @@
 			  int start, int end);
 int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
 			u64 virt, int obj_size,	int nobj, int reserved,
-			int use_lowmem);
+			int use_lowmem, int use_coherent);
 void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table);
 int mlx4_table_get(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
 void mlx4_table_put(struct mlx4_dev *dev, struct mlx4_icm_table *table, int obj);
-void *mlx4_table_find(struct mlx4_icm_table *table, int obj);
+void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle);
 int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
 			 int start, int end);
 void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
diff --git a/drivers/net/mlx4/intf.c b/drivers/net/mlx4/intf.c
index 9ae951b..be5d9e9 100644
--- a/drivers/net/mlx4/intf.c
+++ b/drivers/net/mlx4/intf.c
@@ -142,6 +142,7 @@
 		mlx4_add_device(intf, priv);
 
 	mutex_unlock(&intf_mutex);
+	mlx4_start_catas_poll(dev);
 
 	return 0;
 }
@@ -151,6 +152,7 @@
 	struct mlx4_priv *priv = mlx4_priv(dev);
 	struct mlx4_interface *intf;
 
+	mlx4_stop_catas_poll(dev);
 	mutex_lock(&intf_mutex);
 
 	list_for_each_entry(intf, &intf_list, list)
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index a4f2e04..e029b8a 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -61,7 +61,7 @@
 
 #ifdef CONFIG_PCI_MSI
 
-static int msi_x;
+static int msi_x = 1;
 module_param(msi_x, int, 0444);
 MODULE_PARM_DESC(msi_x, "attempt to use MSI-X if nonzero");
 
@@ -78,14 +78,14 @@
 static struct mlx4_profile default_profile = {
 	.num_qp		= 1 << 16,
 	.num_srq	= 1 << 16,
-	.rdmarc_per_qp	= 4,
+	.rdmarc_per_qp	= 1 << 4,
 	.num_cq		= 1 << 16,
 	.num_mcg	= 1 << 13,
 	.num_mpt	= 1 << 17,
 	.num_mtt	= 1 << 20,
 };
 
-static int __devinit mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
+static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 {
 	int err;
 	int i;
@@ -149,7 +149,8 @@
 	dev->caps.max_cqes	     = dev_cap->max_cq_sz - 1;
 	dev->caps.reserved_cqs	     = dev_cap->reserved_cqs;
 	dev->caps.reserved_eqs	     = dev_cap->reserved_eqs;
-	dev->caps.reserved_mtts	     = dev_cap->reserved_mtts;
+	dev->caps.reserved_mtts	     = DIV_ROUND_UP(dev_cap->reserved_mtts,
+						    MLX4_MTT_ENTRY_PER_SEG);
 	dev->caps.reserved_mrws	     = dev_cap->reserved_mrws;
 	dev->caps.reserved_uars	     = dev_cap->reserved_uars;
 	dev->caps.reserved_pds	     = dev_cap->reserved_pds;
@@ -168,7 +169,7 @@
 	int err;
 
 	priv->fw.fw_icm = mlx4_alloc_icm(dev, priv->fw.fw_pages,
-					 GFP_HIGHUSER | __GFP_NOWARN);
+					 GFP_HIGHUSER | __GFP_NOWARN, 0);
 	if (!priv->fw.fw_icm) {
 		mlx4_err(dev, "Couldn't allocate FW area, aborting.\n");
 		return -ENOMEM;
@@ -192,7 +193,7 @@
 	mlx4_UNMAP_FA(dev);
 
 err_free:
-	mlx4_free_icm(dev, priv->fw.fw_icm);
+	mlx4_free_icm(dev, priv->fw.fw_icm, 0);
 	return err;
 }
 
@@ -207,7 +208,7 @@
 				  ((u64) (MLX4_CMPT_TYPE_QP *
 					  cmpt_entry_sz) << MLX4_CMPT_SHIFT),
 				  cmpt_entry_sz, dev->caps.num_qps,
-				  dev->caps.reserved_qps, 0);
+				  dev->caps.reserved_qps, 0, 0);
 	if (err)
 		goto err;
 
@@ -216,7 +217,7 @@
 				  ((u64) (MLX4_CMPT_TYPE_SRQ *
 					  cmpt_entry_sz) << MLX4_CMPT_SHIFT),
 				  cmpt_entry_sz, dev->caps.num_srqs,
-				  dev->caps.reserved_srqs, 0);
+				  dev->caps.reserved_srqs, 0, 0);
 	if (err)
 		goto err_qp;
 
@@ -225,7 +226,7 @@
 				  ((u64) (MLX4_CMPT_TYPE_CQ *
 					  cmpt_entry_sz) << MLX4_CMPT_SHIFT),
 				  cmpt_entry_sz, dev->caps.num_cqs,
-				  dev->caps.reserved_cqs, 0);
+				  dev->caps.reserved_cqs, 0, 0);
 	if (err)
 		goto err_srq;
 
@@ -236,7 +237,7 @@
 				  cmpt_entry_sz,
 				  roundup_pow_of_two(MLX4_NUM_EQ +
 						     dev->caps.reserved_eqs),
-				  MLX4_NUM_EQ + dev->caps.reserved_eqs, 0);
+				  MLX4_NUM_EQ + dev->caps.reserved_eqs, 0, 0);
 	if (err)
 		goto err_cq;
 
@@ -255,10 +256,8 @@
 	return err;
 }
 
-static int __devinit mlx4_init_icm(struct mlx4_dev *dev,
-				   struct mlx4_dev_cap *dev_cap,
-				   struct mlx4_init_hca_param *init_hca,
-				   u64 icm_size)
+static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap,
+			 struct mlx4_init_hca_param *init_hca, u64 icm_size)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
 	u64 aux_pages;
@@ -275,7 +274,7 @@
 		 (unsigned long long) aux_pages << 2);
 
 	priv->fw.aux_icm = mlx4_alloc_icm(dev, aux_pages,
-					  GFP_HIGHUSER | __GFP_NOWARN);
+					  GFP_HIGHUSER | __GFP_NOWARN, 0);
 	if (!priv->fw.aux_icm) {
 		mlx4_err(dev, "Couldn't allocate aux memory, aborting.\n");
 		return -ENOMEM;
@@ -299,11 +298,22 @@
 		goto err_unmap_cmpt;
 	}
 
+	/*
+	 * Reserved MTT entries must be aligned up to a cacheline
+	 * boundary, since the FW will write to them, while the driver
+	 * writes to all other MTT entries. (The variable
+	 * dev->caps.mtt_entry_sz below is really the MTT segment
+	 * size, not the raw entry size)
+	 */
+	dev->caps.reserved_mtts =
+		ALIGN(dev->caps.reserved_mtts * dev->caps.mtt_entry_sz,
+		      dma_get_cache_alignment()) / dev->caps.mtt_entry_sz;
+
 	err = mlx4_init_icm_table(dev, &priv->mr_table.mtt_table,
 				  init_hca->mtt_base,
 				  dev->caps.mtt_entry_sz,
 				  dev->caps.num_mtt_segs,
-				  dev->caps.reserved_mtts, 1);
+				  dev->caps.reserved_mtts, 1, 0);
 	if (err) {
 		mlx4_err(dev, "Failed to map MTT context memory, aborting.\n");
 		goto err_unmap_eq;
@@ -313,7 +323,7 @@
 				  init_hca->dmpt_base,
 				  dev_cap->dmpt_entry_sz,
 				  dev->caps.num_mpts,
-				  dev->caps.reserved_mrws, 1);
+				  dev->caps.reserved_mrws, 1, 1);
 	if (err) {
 		mlx4_err(dev, "Failed to map dMPT context memory, aborting.\n");
 		goto err_unmap_mtt;
@@ -323,7 +333,7 @@
 				  init_hca->qpc_base,
 				  dev_cap->qpc_entry_sz,
 				  dev->caps.num_qps,
-				  dev->caps.reserved_qps, 0);
+				  dev->caps.reserved_qps, 0, 0);
 	if (err) {
 		mlx4_err(dev, "Failed to map QP context memory, aborting.\n");
 		goto err_unmap_dmpt;
@@ -333,7 +343,7 @@
 				  init_hca->auxc_base,
 				  dev_cap->aux_entry_sz,
 				  dev->caps.num_qps,
-				  dev->caps.reserved_qps, 0);
+				  dev->caps.reserved_qps, 0, 0);
 	if (err) {
 		mlx4_err(dev, "Failed to map AUXC context memory, aborting.\n");
 		goto err_unmap_qp;
@@ -343,7 +353,7 @@
 				  init_hca->altc_base,
 				  dev_cap->altc_entry_sz,
 				  dev->caps.num_qps,
-				  dev->caps.reserved_qps, 0);
+				  dev->caps.reserved_qps, 0, 0);
 	if (err) {
 		mlx4_err(dev, "Failed to map ALTC context memory, aborting.\n");
 		goto err_unmap_auxc;
@@ -353,7 +363,7 @@
 				  init_hca->rdmarc_base,
 				  dev_cap->rdmarc_entry_sz << priv->qp_table.rdmarc_shift,
 				  dev->caps.num_qps,
-				  dev->caps.reserved_qps, 0);
+				  dev->caps.reserved_qps, 0, 0);
 	if (err) {
 		mlx4_err(dev, "Failed to map RDMARC context memory, aborting\n");
 		goto err_unmap_altc;
@@ -363,7 +373,7 @@
 				  init_hca->cqc_base,
 				  dev_cap->cqc_entry_sz,
 				  dev->caps.num_cqs,
-				  dev->caps.reserved_cqs, 0);
+				  dev->caps.reserved_cqs, 0, 0);
 	if (err) {
 		mlx4_err(dev, "Failed to map CQ context memory, aborting.\n");
 		goto err_unmap_rdmarc;
@@ -373,7 +383,7 @@
 				  init_hca->srqc_base,
 				  dev_cap->srq_entry_sz,
 				  dev->caps.num_srqs,
-				  dev->caps.reserved_srqs, 0);
+				  dev->caps.reserved_srqs, 0, 0);
 	if (err) {
 		mlx4_err(dev, "Failed to map SRQ context memory, aborting.\n");
 		goto err_unmap_cq;
@@ -388,7 +398,7 @@
 				  init_hca->mc_base, MLX4_MGM_ENTRY_SIZE,
 				  dev->caps.num_mgms + dev->caps.num_amgms,
 				  dev->caps.num_mgms + dev->caps.num_amgms,
-				  0);
+				  0, 0);
 	if (err) {
 		mlx4_err(dev, "Failed to map MCG context memory, aborting.\n");
 		goto err_unmap_srq;
@@ -433,7 +443,7 @@
 	mlx4_UNMAP_ICM_AUX(dev);
 
 err_free_aux:
-	mlx4_free_icm(dev, priv->fw.aux_icm);
+	mlx4_free_icm(dev, priv->fw.aux_icm, 0);
 
 	return err;
 }
@@ -458,7 +468,7 @@
 	mlx4_unmap_eq_icm(dev);
 
 	mlx4_UNMAP_ICM_AUX(dev);
-	mlx4_free_icm(dev, priv->fw.aux_icm);
+	mlx4_free_icm(dev, priv->fw.aux_icm, 0);
 }
 
 static void mlx4_close_hca(struct mlx4_dev *dev)
@@ -466,10 +476,10 @@
 	mlx4_CLOSE_HCA(dev, 0);
 	mlx4_free_icms(dev);
 	mlx4_UNMAP_FA(dev);
-	mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm);
+	mlx4_free_icm(dev, mlx4_priv(dev)->fw.fw_icm, 0);
 }
 
-static int __devinit mlx4_init_hca(struct mlx4_dev *dev)
+static int mlx4_init_hca(struct mlx4_dev *dev)
 {
 	struct mlx4_priv	  *priv = mlx4_priv(dev);
 	struct mlx4_adapter	   adapter;
@@ -524,8 +534,8 @@
 	}
 
 	priv->eq_table.inta_pin = adapter.inta_pin;
-	priv->rev_id		= adapter.revision_id;
-	memcpy(priv->board_id, adapter.board_id, sizeof priv->board_id);
+	dev->rev_id		= adapter.revision_id;
+	memcpy(dev->board_id, adapter.board_id, sizeof dev->board_id);
 
 	return 0;
 
@@ -537,12 +547,12 @@
 
 err_stop_fw:
 	mlx4_UNMAP_FA(dev);
-	mlx4_free_icm(dev, priv->fw.fw_icm);
+	mlx4_free_icm(dev, priv->fw.fw_icm, 0);
 
 	return err;
 }
 
-static int __devinit mlx4_setup_hca(struct mlx4_dev *dev)
+static int mlx4_setup_hca(struct mlx4_dev *dev)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
 	int err;
@@ -583,13 +593,11 @@
 		goto err_pd_table_free;
 	}
 
-	mlx4_map_catas_buf(dev);
-
 	err = mlx4_init_eq_table(dev);
 	if (err) {
 		mlx4_err(dev, "Failed to initialize "
 			 "event queue table, aborting.\n");
-		goto err_catas_buf;
+		goto err_mr_table_free;
 	}
 
 	err = mlx4_cmd_use_events(dev);
@@ -601,13 +609,17 @@
 
 	err = mlx4_NOP(dev);
 	if (err) {
-		mlx4_err(dev, "NOP command failed to generate interrupt "
-			 "(IRQ %d), aborting.\n",
-			 priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
-		if (dev->flags & MLX4_FLAG_MSI_X)
-			mlx4_err(dev, "Try again with MSI-X disabled.\n");
-		else
+		if (dev->flags & MLX4_FLAG_MSI_X) {
+			mlx4_warn(dev, "NOP command failed to generate MSI-X "
+				  "interrupt IRQ %d).\n",
+				  priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
+			mlx4_warn(dev, "Trying again without MSI-X.\n");
+		} else {
+			mlx4_err(dev, "NOP command failed to generate interrupt "
+				 "(IRQ %d), aborting.\n",
+				 priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
 			mlx4_err(dev, "BIOS or ACPI interrupt routing problem?\n");
+		}
 
 		goto err_cmd_poll;
 	}
@@ -659,8 +671,7 @@
 err_eq_table_free:
 	mlx4_cleanup_eq_table(dev);
 
-err_catas_buf:
-	mlx4_unmap_catas_buf(dev);
+err_mr_table_free:
 	mlx4_cleanup_mr_table(dev);
 
 err_pd_table_free:
@@ -708,19 +719,12 @@
 		priv->eq_table.eq[i].irq = dev->pdev->irq;
 }
 
-static int __devinit mlx4_init_one(struct pci_dev *pdev,
-				   const struct pci_device_id *id)
+static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-	static int mlx4_version_printed;
 	struct mlx4_priv *priv;
 	struct mlx4_dev *dev;
 	int err;
 
-	if (!mlx4_version_printed) {
-		printk(KERN_INFO "%s", mlx4_version);
-		++mlx4_version_printed;
-	}
-
 	printk(KERN_INFO PFX "Initializing %s\n",
 	       pci_name(pdev));
 
@@ -806,8 +810,6 @@
 		goto err_free_dev;
 	}
 
-	mlx4_enable_msi_x(dev);
-
 	if (mlx4_cmd_init(dev)) {
 		mlx4_err(dev, "Failed to init command interface, aborting.\n");
 		goto err_free_dev;
@@ -817,7 +819,15 @@
 	if (err)
 		goto err_cmd;
 
+	mlx4_enable_msi_x(dev);
+
 	err = mlx4_setup_hca(dev);
+	if (err == -EBUSY && (dev->flags & MLX4_FLAG_MSI_X)) {
+		dev->flags &= ~MLX4_FLAG_MSI_X;
+		pci_disable_msix(pdev);
+		err = mlx4_setup_hca(dev);
+	}
+
 	if (err)
 		goto err_close;
 
@@ -836,23 +846,20 @@
 	mlx4_cleanup_cq_table(dev);
 	mlx4_cmd_use_polling(dev);
 	mlx4_cleanup_eq_table(dev);
-
-	mlx4_unmap_catas_buf(dev);
-
 	mlx4_cleanup_mr_table(dev);
 	mlx4_cleanup_pd_table(dev);
 	mlx4_cleanup_uar_table(dev);
 
 err_close:
+	if (dev->flags & MLX4_FLAG_MSI_X)
+		pci_disable_msix(pdev);
+
 	mlx4_close_hca(dev);
 
 err_cmd:
 	mlx4_cmd_cleanup(dev);
 
 err_free_dev:
-	if (dev->flags & MLX4_FLAG_MSI_X)
-		pci_disable_msix(pdev);
-
 	kfree(priv);
 
 err_release_bar2:
@@ -867,7 +874,20 @@
 	return err;
 }
 
-static void __devexit mlx4_remove_one(struct pci_dev *pdev)
+static int __devinit mlx4_init_one(struct pci_dev *pdev,
+				   const struct pci_device_id *id)
+{
+	static int mlx4_version_printed;
+
+	if (!mlx4_version_printed) {
+		printk(KERN_INFO "%s", mlx4_version);
+		++mlx4_version_printed;
+	}
+
+	return mlx4_init_one(pdev, id);
+}
+
+static void mlx4_remove_one(struct pci_dev *pdev)
 {
 	struct mlx4_dev  *dev  = pci_get_drvdata(pdev);
 	struct mlx4_priv *priv = mlx4_priv(dev);
@@ -885,9 +905,6 @@
 		mlx4_cleanup_cq_table(dev);
 		mlx4_cmd_use_polling(dev);
 		mlx4_cleanup_eq_table(dev);
-
-		mlx4_unmap_catas_buf(dev);
-
 		mlx4_cleanup_mr_table(dev);
 		mlx4_cleanup_pd_table(dev);
 
@@ -908,6 +925,12 @@
 	}
 }
 
+int mlx4_restart_one(struct pci_dev *pdev)
+{
+	mlx4_remove_one(pdev);
+	return __mlx4_init_one(pdev, NULL);
+}
+
 static struct pci_device_id mlx4_pci_table[] = {
 	{ PCI_VDEVICE(MELLANOX, 0x6340) }, /* MT25408 "Hermon" SDR */
 	{ PCI_VDEVICE(MELLANOX, 0x634a) }, /* MT25408 "Hermon" DDR */
@@ -930,6 +953,10 @@
 {
 	int ret;
 
+	ret = mlx4_catas_init();
+	if (ret)
+		return ret;
+
 	ret = pci_register_driver(&mlx4_driver);
 	return ret < 0 ? ret : 0;
 }
@@ -937,6 +964,7 @@
 static void __exit mlx4_cleanup(void)
 {
 	pci_unregister_driver(&mlx4_driver);
+	mlx4_catas_cleanup();
 }
 
 module_init(mlx4_init);
diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c
index 672024a..a99e772 100644
--- a/drivers/net/mlx4/mcg.c
+++ b/drivers/net/mlx4/mcg.c
@@ -359,7 +359,7 @@
 }
 EXPORT_SYMBOL_GPL(mlx4_multicast_detach);
 
-int __devinit mlx4_init_mcg_table(struct mlx4_dev *dev)
+int mlx4_init_mcg_table(struct mlx4_dev *dev)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
 	int err;
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index d9c91a7..53a1cdd 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -39,6 +39,7 @@
 
 #include <linux/mutex.h>
 #include <linux/radix-tree.h>
+#include <linux/timer.h>
 
 #include <linux/mlx4/device.h>
 #include <linux/mlx4/doorbell.h>
@@ -55,11 +56,7 @@
 };
 
 enum {
-	MLX4_BOARD_ID_LEN	= 64
-};
-
-enum {
-	MLX4_MGM_ENTRY_SIZE	=  0x40,
+	MLX4_MGM_ENTRY_SIZE	=  0x100,
 	MLX4_QP_PER_MGM		= 4 * (MLX4_MGM_ENTRY_SIZE / 16 - 2),
 	MLX4_MTT_ENTRY_PER_SEG	= 8
 };
@@ -67,7 +64,6 @@
 enum {
 	MLX4_EQ_ASYNC,
 	MLX4_EQ_COMP,
-	MLX4_EQ_CATAS,
 	MLX4_NUM_EQ
 };
 
@@ -133,6 +129,7 @@
 	int			num_obj;
 	int			obj_size;
 	int			lowmem;
+	int			coherent;
 	struct mutex		mutex;
 	struct mlx4_icm	      **icm;
 };
@@ -248,7 +245,8 @@
 
 struct mlx4_catas_err {
 	u32 __iomem	       *map;
-	int			size;
+	struct timer_list	timer;
+	struct list_head	list;
 };
 
 struct mlx4_priv {
@@ -276,9 +274,6 @@
 
 	struct mlx4_uar		driver_uar;
 	void __iomem	       *kar;
-
-	u32			rev_id;
-	char			board_id[MLX4_BOARD_ID_LEN];
 };
 
 static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev)
@@ -311,9 +306,11 @@
 void mlx4_cleanup_srq_table(struct mlx4_dev *dev);
 void mlx4_cleanup_mcg_table(struct mlx4_dev *dev);
 
-void mlx4_map_catas_buf(struct mlx4_dev *dev);
-void mlx4_unmap_catas_buf(struct mlx4_dev *dev);
-
+void mlx4_start_catas_poll(struct mlx4_dev *dev);
+void mlx4_stop_catas_poll(struct mlx4_dev *dev);
+int mlx4_catas_init(void);
+void mlx4_catas_cleanup(void);
+int mlx4_restart_one(struct pci_dev *pdev);
 int mlx4_register_device(struct mlx4_dev *dev);
 void mlx4_unregister_device(struct mlx4_dev *dev);
 void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_event type,
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c
index d0808fa..0c05a10 100644
--- a/drivers/net/mlx4/mr.c
+++ b/drivers/net/mlx4/mr.c
@@ -68,6 +68,9 @@
 
 #define MLX4_MTT_FLAG_PRESENT		1
 
+#define MLX4_MPT_STATUS_SW		0xF0
+#define MLX4_MPT_STATUS_HW		0x00
+
 static u32 mlx4_buddy_alloc(struct mlx4_buddy *buddy, int order)
 {
 	int o;
@@ -255,10 +258,8 @@
 	int err;
 
 	index = mlx4_bitmap_alloc(&priv->mr_table.mpt_bitmap);
-	if (index == -1) {
-		err = -ENOMEM;
-		goto err;
-	}
+	if (index == -1)
+		return -ENOMEM;
 
 	mr->iova       = iova;
 	mr->size       = size;
@@ -269,15 +270,8 @@
 
 	err = mlx4_mtt_init(dev, npages, page_shift, &mr->mtt);
 	if (err)
-		goto err_index;
+		mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, index);
 
-	return 0;
-
-err_index:
-	mlx4_bitmap_free(&priv->mr_table.mpt_bitmap, index);
-
-err:
-	kfree(mr);
 	return err;
 }
 EXPORT_SYMBOL_GPL(mlx4_mr_alloc);
@@ -358,58 +352,57 @@
 }
 EXPORT_SYMBOL_GPL(mlx4_mr_enable);
 
-static int mlx4_WRITE_MTT(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
-			  int num_mtt)
+static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
+				int start_index, int npages, u64 *page_list)
 {
-	return mlx4_cmd(dev, mailbox->dma, num_mtt, 0, MLX4_CMD_WRITE_MTT,
-			MLX4_CMD_TIME_CLASS_B);
+	struct mlx4_priv *priv = mlx4_priv(dev);
+	__be64 *mtts;
+	dma_addr_t dma_handle;
+	int i;
+	int s = start_index * sizeof (u64);
+
+	/* All MTTs must fit in the same page */
+	if (start_index / (PAGE_SIZE / sizeof (u64)) !=
+	    (start_index + npages - 1) / (PAGE_SIZE / sizeof (u64)))
+		return -EINVAL;
+
+	if (start_index & (MLX4_MTT_ENTRY_PER_SEG - 1))
+		return -EINVAL;
+
+	mtts = mlx4_table_find(&priv->mr_table.mtt_table, mtt->first_seg +
+				s / dev->caps.mtt_entry_sz, &dma_handle);
+	if (!mtts)
+		return -ENOMEM;
+
+	for (i = 0; i < npages; ++i)
+		mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT);
+
+	dma_sync_single(&dev->pdev->dev, dma_handle, npages * sizeof (u64), DMA_TO_DEVICE);
+
+	return 0;
 }
 
 int mlx4_write_mtt(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
 		   int start_index, int npages, u64 *page_list)
 {
-	struct mlx4_cmd_mailbox *mailbox;
-	__be64 *mtt_entry;
-	int i;
-	int err = 0;
+	int chunk;
+	int err;
 
 	if (mtt->order < 0)
 		return -EINVAL;
 
-	mailbox = mlx4_alloc_cmd_mailbox(dev);
-	if (IS_ERR(mailbox))
-		return PTR_ERR(mailbox);
-
-	mtt_entry = mailbox->buf;
-
 	while (npages > 0) {
-		mtt_entry[0] = cpu_to_be64(mlx4_mtt_addr(dev, mtt) + start_index * 8);
-		mtt_entry[1] = 0;
-
-		for (i = 0; i < npages && i < MLX4_MAILBOX_SIZE / 8 - 2; ++i)
-			mtt_entry[i + 2] = cpu_to_be64(page_list[i] |
-						       MLX4_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 = mlx4_WRITE_MTT(dev, mailbox, (i + 1) & ~1);
+		chunk = min_t(int, PAGE_SIZE / sizeof(u64), npages);
+		err = mlx4_write_mtt_chunk(dev, mtt, start_index, chunk, page_list);
 		if (err)
-			goto out;
+			return err;
 
-		npages      -= i;
-		start_index += i;
-		page_list   += i;
+		npages      -= chunk;
+		start_index += chunk;
+		page_list   += chunk;
 	}
 
-out:
-	mlx4_free_cmd_mailbox(dev, mailbox);
-
-	return err;
+	return 0;
 }
 EXPORT_SYMBOL_GPL(mlx4_write_mtt);
 
@@ -437,7 +430,7 @@
 }
 EXPORT_SYMBOL_GPL(mlx4_buf_write_mtt);
 
-int __devinit mlx4_init_mr_table(struct mlx4_dev *dev)
+int mlx4_init_mr_table(struct mlx4_dev *dev)
 {
 	struct mlx4_mr_table *mr_table = &mlx4_priv(dev)->mr_table;
 	int err;
@@ -453,7 +446,7 @@
 		goto err_buddy;
 
 	if (dev->caps.reserved_mtts) {
-		if (mlx4_alloc_mtt_range(dev, ilog2(dev->caps.reserved_mtts)) == -1) {
+		if (mlx4_alloc_mtt_range(dev, fls(dev->caps.reserved_mtts - 1)) == -1) {
 			mlx4_warn(dev, "MTT table of order %d is too small.\n",
 				  mr_table->mtt_buddy.max_order);
 			err = -ENOMEM;
@@ -479,3 +472,165 @@
 	mlx4_buddy_cleanup(&mr_table->mtt_buddy);
 	mlx4_bitmap_cleanup(&mr_table->mpt_bitmap);
 }
+
+static inline int mlx4_check_fmr(struct mlx4_fmr *fmr, u64 *page_list,
+				  int npages, u64 iova)
+{
+	int i, page_mask;
+
+	if (npages > fmr->max_pages)
+		return -EINVAL;
+
+	page_mask = (1 << fmr->page_shift) - 1;
+
+	/* We are getting page lists, so va must be page aligned. */
+	if (iova & page_mask)
+		return -EINVAL;
+
+	/* Trust the user not to pass misaligned data in page_list */
+	if (0)
+		for (i = 0; i < npages; ++i) {
+			if (page_list[i] & ~page_mask)
+				return -EINVAL;
+		}
+
+	if (fmr->maps >= fmr->max_maps)
+		return -EINVAL;
+
+	return 0;
+}
+
+int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list,
+		      int npages, u64 iova, u32 *lkey, u32 *rkey)
+{
+	u32 key;
+	int i, err;
+
+	err = mlx4_check_fmr(fmr, page_list, npages, iova);
+	if (err)
+		return err;
+
+	++fmr->maps;
+
+	key = key_to_hw_index(fmr->mr.key);
+	key += dev->caps.num_mpts;
+	*lkey = *rkey = fmr->mr.key = hw_index_to_key(key);
+
+	*(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW;
+
+	/* Make sure MPT status is visible before writing MTT entries */
+	wmb();
+
+	for (i = 0; i < npages; ++i)
+		fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT);
+
+	dma_sync_single(&dev->pdev->dev, fmr->dma_handle,
+			npages * sizeof(u64), DMA_TO_DEVICE);
+
+	fmr->mpt->key    = cpu_to_be32(key);
+	fmr->mpt->lkey   = cpu_to_be32(key);
+	fmr->mpt->length = cpu_to_be64(npages * (1ull << fmr->page_shift));
+	fmr->mpt->start  = cpu_to_be64(iova);
+
+	/* Make MTT entries are visible before setting MPT status */
+	wmb();
+
+	*(u8 *) fmr->mpt = MLX4_MPT_STATUS_HW;
+
+	/* Make sure MPT status is visible before consumer can use FMR */
+	wmb();
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_map_phys_fmr);
+
+int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages,
+		   int max_maps, u8 page_shift, struct mlx4_fmr *fmr)
+{
+	struct mlx4_priv *priv = mlx4_priv(dev);
+	u64 mtt_seg;
+	int err = -ENOMEM;
+
+	if (page_shift < 12 || page_shift >= 32)
+		return -EINVAL;
+
+	/* All MTTs must fit in the same page */
+	if (max_pages * sizeof *fmr->mtts > PAGE_SIZE)
+		return -EINVAL;
+
+	fmr->page_shift = page_shift;
+	fmr->max_pages  = max_pages;
+	fmr->max_maps   = max_maps;
+	fmr->maps = 0;
+
+	err = mlx4_mr_alloc(dev, pd, 0, 0, access, max_pages,
+			    page_shift, &fmr->mr);
+	if (err)
+		return err;
+
+	mtt_seg = fmr->mr.mtt.first_seg * dev->caps.mtt_entry_sz;
+
+	fmr->mtts = mlx4_table_find(&priv->mr_table.mtt_table,
+				    fmr->mr.mtt.first_seg,
+				    &fmr->dma_handle);
+	if (!fmr->mtts) {
+		err = -ENOMEM;
+		goto err_free;
+	}
+
+	fmr->mpt = mlx4_table_find(&priv->mr_table.dmpt_table,
+				    key_to_hw_index(fmr->mr.key), NULL);
+	if (!fmr->mpt) {
+		err = -ENOMEM;
+		goto err_free;
+	}
+
+	return 0;
+
+err_free:
+	mlx4_mr_free(dev, &fmr->mr);
+	return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_fmr_alloc);
+
+int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr)
+{
+	return mlx4_mr_enable(dev, &fmr->mr);
+}
+EXPORT_SYMBOL_GPL(mlx4_fmr_enable);
+
+void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr,
+		    u32 *lkey, u32 *rkey)
+{
+	u32 key;
+
+	if (!fmr->maps)
+		return;
+
+	key = key_to_hw_index(fmr->mr.key);
+	key &= dev->caps.num_mpts - 1;
+	*lkey = *rkey = fmr->mr.key = hw_index_to_key(key);
+
+	fmr->maps = 0;
+
+	*(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW;
+}
+EXPORT_SYMBOL_GPL(mlx4_fmr_unmap);
+
+int mlx4_fmr_free(struct mlx4_dev *dev, struct mlx4_fmr *fmr)
+{
+	if (fmr->maps)
+		return -EBUSY;
+
+	fmr->mr.enabled = 0;
+	mlx4_mr_free(dev, &fmr->mr);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mlx4_fmr_free);
+
+int mlx4_SYNC_TPT(struct mlx4_dev *dev)
+{
+	return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000);
+}
+EXPORT_SYMBOL_GPL(mlx4_SYNC_TPT);
diff --git a/drivers/net/mlx4/pd.c b/drivers/net/mlx4/pd.c
index 23dea1e..3a93c5f 100644
--- a/drivers/net/mlx4/pd.c
+++ b/drivers/net/mlx4/pd.c
@@ -57,7 +57,7 @@
 }
 EXPORT_SYMBOL_GPL(mlx4_pd_free);
 
-int __devinit mlx4_init_pd_table(struct mlx4_dev *dev)
+int mlx4_init_pd_table(struct mlx4_dev *dev)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
 
diff --git a/drivers/net/mlx4/qp.c b/drivers/net/mlx4/qp.c
index 19b48c7..cc4b1be 100644
--- a/drivers/net/mlx4/qp.c
+++ b/drivers/net/mlx4/qp.c
@@ -240,7 +240,8 @@
 	mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn);
 	mlx4_table_put(dev, &qp_table->qp_table, qp->qpn);
 
-	mlx4_bitmap_free(&qp_table->bitmap, qp->qpn);
+	if (qp->qpn < dev->caps.sqp_start + 8)
+		mlx4_bitmap_free(&qp_table->bitmap, qp->qpn);
 }
 EXPORT_SYMBOL_GPL(mlx4_qp_free);
 
@@ -250,7 +251,7 @@
 			MLX4_CMD_TIME_CLASS_B);
 }
 
-int __devinit mlx4_init_qp_table(struct mlx4_dev *dev)
+int mlx4_init_qp_table(struct mlx4_dev *dev)
 {
 	struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
 	int err;
diff --git a/drivers/net/mlx4/reset.c b/drivers/net/mlx4/reset.c
index e4dfd4b..e199715 100644
--- a/drivers/net/mlx4/reset.c
+++ b/drivers/net/mlx4/reset.c
@@ -119,6 +119,9 @@
 	writel(MLX4_RESET_VALUE, reset + MLX4_RESET_OFFSET);
 	iounmap(reset);
 
+	/* Docs say to wait one second before accessing device */
+	msleep(1000);
+
 	end = jiffies + MLX4_RESET_TIMEOUT_JIFFIES;
 	do {
 		if (!pci_read_config_word(dev->pdev, PCI_VENDOR_ID, &vendor) &&
diff --git a/drivers/net/mlx4/srq.c b/drivers/net/mlx4/srq.c
index b061c86..d23f46d 100644
--- a/drivers/net/mlx4/srq.c
+++ b/drivers/net/mlx4/srq.c
@@ -227,7 +227,7 @@
 	err = mlx4_QUERY_SRQ(dev, mailbox, srq->srqn);
 	if (err)
 		goto err_out;
-	*limit_watermark = srq_context->limit_watermark;
+	*limit_watermark = be16_to_cpu(srq_context->limit_watermark);
 
 err_out:
 	mlx4_free_cmd_mailbox(dev, mailbox);
@@ -235,7 +235,7 @@
 }
 EXPORT_SYMBOL_GPL(mlx4_srq_query);
 
-int __devinit mlx4_init_srq_table(struct mlx4_dev *dev)
+int mlx4_init_srq_table(struct mlx4_dev *dev)
 {
 	struct mlx4_srq_table *srq_table = &mlx4_priv(dev)->srq_table;
 	int err;
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 1799eee..b33d21f 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -63,10 +63,9 @@
 static int mv643xx_eth_open(struct net_device *);
 static int mv643xx_eth_stop(struct net_device *);
 static int mv643xx_eth_change_mtu(struct net_device *, int);
-static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *);
 static void eth_port_init_mac_tables(unsigned int eth_port_num);
 #ifdef MV643XX_NAPI
-static int mv643xx_poll(struct net_device *dev, int *budget);
+static int mv643xx_poll(struct napi_struct *napi, int budget);
 #endif
 static int ethernet_phy_get(unsigned int eth_port_num);
 static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr);
@@ -341,7 +340,7 @@
 
 		if (cmd_sts & ETH_ERROR_SUMMARY) {
 			printk("%s: Error in TX\n", dev->name);
-			mp->stats.tx_errors++;
+			dev->stats.tx_errors++;
 		}
 
 		spin_unlock_irqrestore(&mp->lock, flags);
@@ -388,7 +387,7 @@
 static int mv643xx_eth_receive_queue(struct net_device *dev, int budget)
 {
 	struct mv643xx_private *mp = netdev_priv(dev);
-	struct net_device_stats *stats = &mp->stats;
+	struct net_device_stats *stats = &dev->stats;
 	unsigned int received_packets = 0;
 	struct sk_buff *skb;
 	struct pkt_info pkt_info;
@@ -534,7 +533,7 @@
 	}
 
 	/* PHY status changed */
-	if (eth_int_cause_ext & ETH_INT_CAUSE_PHY) {
+	if (eth_int_cause_ext & (ETH_INT_CAUSE_PHY | ETH_INT_CAUSE_STATE)) {
 		struct ethtool_cmd cmd;
 
 		if (mii_link_ok(&mp->mii)) {
@@ -562,7 +561,7 @@
 		/* wait for previous write to complete */
 		mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num));
 
-		netif_rx_schedule(dev);
+		netif_rx_schedule(dev, &mp->napi);
 	}
 #else
 	if (eth_int_cause & ETH_INT_CAUSE_RX)
@@ -785,6 +784,7 @@
 	unsigned int port_num = mp->port_num;
 	unsigned int size;
 	int err;
+	DECLARE_MAC_BUF(mac);
 
 	/* Clear any pending ethernet port interrupts */
 	mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
@@ -880,6 +880,10 @@
 
 	mv643xx_eth_rx_refill_descs(dev);	/* Fill RX ring with skb's */
 
+#ifdef MV643XX_NAPI
+	napi_enable(&mp->napi);
+#endif
+
 	eth_port_start(dev);
 
 	/* Interrupt Coalescing */
@@ -982,7 +986,7 @@
 	mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num));
 
 #ifdef MV643XX_NAPI
-	netif_poll_disable(dev);
+	napi_disable(&mp->napi);
 #endif
 	netif_carrier_off(dev);
 	netif_stop_queue(dev);
@@ -992,10 +996,6 @@
 	mv643xx_eth_free_tx_rings(dev);
 	mv643xx_eth_free_rx_rings(dev);
 
-#ifdef MV643XX_NAPI
-	netif_poll_enable(dev);
-#endif
-
 	free_irq(dev->irq, dev);
 
 	return 0;
@@ -1007,11 +1007,12 @@
  *
  * This function is used in case of NAPI
  */
-static int mv643xx_poll(struct net_device *dev, int *budget)
+static int mv643xx_poll(struct napi_struct *napi, int budget)
 {
-	struct mv643xx_private *mp = netdev_priv(dev);
-	int done = 1, orig_budget, work_done;
+	struct mv643xx_private *mp = container_of(napi, struct mv643xx_private, napi);
+	struct net_device *dev = mp->dev;
 	unsigned int port_num = mp->port_num;
+	int work_done;
 
 #ifdef MV643XX_TX_FAST_REFILL
 	if (++mp->tx_clean_threshold > 5) {
@@ -1020,27 +1021,20 @@
 	}
 #endif
 
+	work_done = 0;
 	if ((mv_read(MV643XX_ETH_RX_CURRENT_QUEUE_DESC_PTR_0(port_num)))
-						!= (u32) mp->rx_used_desc_q) {
-		orig_budget = *budget;
-		if (orig_budget > dev->quota)
-			orig_budget = dev->quota;
-		work_done = mv643xx_eth_receive_queue(dev, orig_budget);
-		*budget -= work_done;
-		dev->quota -= work_done;
-		if (work_done >= orig_budget)
-			done = 0;
-	}
+	    != (u32) mp->rx_used_desc_q)
+		work_done = mv643xx_eth_receive_queue(dev, budget);
 
-	if (done) {
-		netif_rx_complete(dev);
+	if (work_done < budget) {
+		netif_rx_complete(dev, napi);
 		mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0);
 		mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0);
 		mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
 						ETH_INT_UNMASK_ALL);
 	}
 
-	return done ? 0 : 1;
+	return work_done;
 }
 #endif
 
@@ -1198,7 +1192,7 @@
 static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct mv643xx_private *mp = netdev_priv(dev);
-	struct net_device_stats *stats = &mp->stats;
+	struct net_device_stats *stats = &dev->stats;
 	unsigned long flags;
 
 	BUG_ON(netif_queue_stopped(dev));
@@ -1222,7 +1216,7 @@
 	spin_lock_irqsave(&mp->lock, flags);
 
 	eth_tx_submit_descs_for_skb(mp, skb);
-	stats->tx_bytes = skb->len;
+	stats->tx_bytes += skb->len;
 	stats->tx_packets++;
 	dev->trans_start = jiffies;
 
@@ -1234,23 +1228,6 @@
 	return 0;		/* success */
 }
 
-/*
- * mv643xx_eth_get_stats
- *
- * Returns a pointer to the interface statistics.
- *
- * Input :	dev - a pointer to the required interface
- *
- * Output :	a pointer to the interface's statistics
- */
-
-static struct net_device_stats *mv643xx_eth_get_stats(struct net_device *dev)
-{
-	struct mv643xx_private *mp = netdev_priv(dev);
-
-	return &mp->stats;
-}
-
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void mv643xx_netpoll(struct net_device *netdev)
 {
@@ -1333,6 +1310,10 @@
 	platform_set_drvdata(pdev, dev);
 
 	mp = netdev_priv(dev);
+	mp->dev = dev;
+#ifdef MV643XX_NAPI
+	netif_napi_add(dev, &mp->napi, mv643xx_poll, 64);
+#endif
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	BUG_ON(!res);
@@ -1341,23 +1322,17 @@
 	dev->open = mv643xx_eth_open;
 	dev->stop = mv643xx_eth_stop;
 	dev->hard_start_xmit = mv643xx_eth_start_xmit;
-	dev->get_stats = mv643xx_eth_get_stats;
 	dev->set_mac_address = mv643xx_eth_set_mac_address;
 	dev->set_multicast_list = mv643xx_eth_set_rx_mode;
 
 	/* No need to Tx Timeout */
 	dev->tx_timeout = mv643xx_eth_tx_timeout;
-#ifdef MV643XX_NAPI
-	dev->poll = mv643xx_poll;
-	dev->weight = 64;
-#endif
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = mv643xx_netpoll;
 #endif
 
 	dev->watchdog_timeo = 2 * HZ;
-	dev->tx_queue_len = mp->tx_ring_size;
 	dev->base_addr = 0;
 	dev->change_mtu = mv643xx_eth_change_mtu;
 	dev->do_ioctl = mv643xx_eth_do_ioctl;
@@ -1432,7 +1407,6 @@
 	mv643xx_eth_update_pscr(dev, &cmd);
 	mv643xx_set_settings(dev, &cmd);
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 	err = register_netdev(dev);
 	if (err)
@@ -1440,8 +1414,8 @@
 
 	p = dev->dev_addr;
 	printk(KERN_NOTICE
-		"%s: port %d with MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
-		dev->name, port_num, p[0], p[1], p[2], p[3], p[4], p[5]);
+		"%s: port %d with MAC address %s\n",
+		dev->name, port_num, print_mac(mac, p));
 
 	if (dev->features & NETIF_F_SG)
 		printk(KERN_NOTICE "%s: Scatter Gather Enabled\n", dev->name);
@@ -2688,8 +2662,7 @@
 	{ "late_collision", MV643XX_STAT(mib_counters.late_collision) },
 };
 
-#define MV643XX_STATS_LEN	\
-	sizeof(mv643xx_gstrings_stats) / sizeof(struct mv643xx_stats)
+#define MV643XX_STATS_LEN	ARRAY_SIZE(mv643xx_gstrings_stats)
 
 static void mv643xx_get_drvinfo(struct net_device *netdev,
 				struct ethtool_drvinfo *drvinfo)
@@ -2701,9 +2674,14 @@
 	drvinfo->n_stats = MV643XX_STATS_LEN;
 }
 
-static int mv643xx_get_stats_count(struct net_device *netdev)
+static int mv643xx_get_sset_count(struct net_device *netdev, int sset)
 {
-	return MV643XX_STATS_LEN;
+	switch (sset) {
+	case ETH_SS_STATS:
+		return MV643XX_STATS_LEN;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void mv643xx_get_ethtool_stats(struct net_device *netdev,
@@ -2763,13 +2741,9 @@
 	.set_settings           = mv643xx_set_settings,
 	.get_drvinfo            = mv643xx_get_drvinfo,
 	.get_link               = mv643xx_eth_get_link,
-	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
-	.get_stats_count        = mv643xx_get_stats_count,
 	.get_ethtool_stats      = mv643xx_get_ethtool_stats,
 	.get_strings            = mv643xx_get_strings,
-	.get_stats_count        = mv643xx_get_stats_count,
-	.get_ethtool_stats      = mv643xx_get_ethtool_stats,
 	.nway_reset		= mv643xx_eth_nway_restart,
 };
 
diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h
index 82f8c0c..be669eb 100644
--- a/drivers/net/mv643xx_eth.h
+++ b/drivers/net/mv643xx_eth.h
@@ -64,7 +64,9 @@
 #define ETH_INT_CAUSE_TX_ERROR	(ETH_TX_QUEUES_ENABLED << 8)
 #define ETH_INT_CAUSE_TX	(ETH_INT_CAUSE_TX_DONE | ETH_INT_CAUSE_TX_ERROR)
 #define ETH_INT_CAUSE_PHY	0x00010000
-#define ETH_INT_UNMASK_ALL_EXT	(ETH_INT_CAUSE_TX | ETH_INT_CAUSE_PHY)
+#define ETH_INT_CAUSE_STATE	0x00100000
+#define ETH_INT_UNMASK_ALL_EXT	(ETH_INT_CAUSE_TX | ETH_INT_CAUSE_PHY | \
+					ETH_INT_CAUSE_STATE)
 
 #define ETH_INT_MASK_ALL	0x00000000
 #define ETH_INT_MASK_ALL_EXT	0x00000000
@@ -318,6 +320,8 @@
 
 	struct work_struct tx_timeout_task;
 
+	struct net_device *dev;
+	struct napi_struct napi;
 	struct net_device_stats stats;
 	struct mv643xx_mib_counters mib_counters;
 	spinlock_t lock;
diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c
index e246d00..86c9c06 100644
--- a/drivers/net/mvme147.c
+++ b/drivers/net/mvme147.c
@@ -67,6 +67,7 @@
 	u_long *addr;
 	u_long address;
 	int err;
+	DECLARE_MAC_BUF(mac);
 
 	if (!MACH_IS_MVME147 || called)
 		return ERR_PTR(-ENODEV);
@@ -79,8 +80,6 @@
 	if (unit >= 0)
 		sprintf(dev->name, "eth%d", unit);
 
-	SET_MODULE_OWNER(dev);
-
 	/* Fill the dev fields */
 	dev->base_addr = (unsigned long)MVME147_LANCE_BASE;
 	dev->open = &m147lance_open;
@@ -103,12 +102,10 @@
 	address=address>>8;
 	dev->dev_addr[3]=address&0xff;
 
-	printk("%s: MVME147 at 0x%08lx, irq %d, Hardware Address %02x:%02x:%02x:%02x:%02x:%02x\n",
-		dev->name, dev->base_addr, MVME147_LANCE_IRQ,
-		dev->dev_addr[0],
-		dev->dev_addr[1], dev->dev_addr[2],
-		dev->dev_addr[3], dev->dev_addr[4],
-		dev->dev_addr[5]);
+	printk("%s: MVME147 at 0x%08lx, irq %d, "
+	       "Hardware Address %s\n",
+	       dev->name, dev->base_addr, MVME147_LANCE_IRQ,
+	       print_mac(mac, dev->dev_addr));
 
 	lp = (struct m147lance_private *)dev->priv;
 	lp->ram = __get_dma_pages(GFP_ATOMIC, 3);	/* 16K */
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index deca653..e8afa10 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -48,6 +48,7 @@
 #include <linux/etherdevice.h>
 #include <linux/if_ether.h>
 #include <linux/if_vlan.h>
+#include <linux/inet_lro.h>
 #include <linux/ip.h>
 #include <linux/inet.h>
 #include <linux/in.h>
@@ -62,6 +63,8 @@
 #include <linux/io.h>
 #include <linux/log2.h>
 #include <net/checksum.h>
+#include <net/ip.h>
+#include <net/tcp.h>
 #include <asm/byteorder.h>
 #include <asm/io.h>
 #include <asm/processor.h>
@@ -72,7 +75,7 @@
 #include "myri10ge_mcp.h"
 #include "myri10ge_mcp_gen_header.h"
 
-#define MYRI10GE_VERSION_STR "1.3.1-1.248"
+#define MYRI10GE_VERSION_STR "1.3.2-1.269"
 
 MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");
 MODULE_AUTHOR("Maintainer: help@myri.com");
@@ -89,6 +92,8 @@
 
 #define MYRI10GE_EEPROM_STRINGS_SIZE 256
 #define MYRI10GE_MAX_SEND_DESC_TSO ((65536 / 2048) * 2)
+#define MYRI10GE_MAX_LRO_DESCRIPTORS 8
+#define MYRI10GE_LRO_MAX_PKTS 64
 
 #define MYRI10GE_NO_CONFIRM_DATA htonl(0xffffffff)
 #define MYRI10GE_NO_RESPONSE_RESULT 0xffffffff
@@ -151,6 +156,8 @@
 	dma_addr_t bus;
 	int cnt;
 	int idx;
+	struct net_lro_mgr lro_mgr;
+	struct net_lro_desc lro_desc[MYRI10GE_MAX_LRO_DESCRIPTORS];
 };
 
 struct myri10ge_priv {
@@ -163,6 +170,7 @@
 	int small_bytes;
 	int big_bytes;
 	struct net_device *dev;
+	struct napi_struct napi;
 	struct net_device_stats stats;
 	u8 __iomem *sram;
 	int sram_size;
@@ -191,6 +199,7 @@
 	struct timer_list watchdog_timer;
 	int watchdog_tx_done;
 	int watchdog_tx_req;
+	int watchdog_pause;
 	int watchdog_resets;
 	int tx_linearized;
 	int pause;
@@ -276,6 +285,14 @@
 module_param(myri10ge_debug, int, 0);
 MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)");
 
+static int myri10ge_lro = 1;
+module_param(myri10ge_lro, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_lro, "Enable large receive offload\n");
+
+static int myri10ge_lro_max_pkts = MYRI10GE_LRO_MAX_PKTS;
+module_param(myri10ge_lro_max_pkts, int, S_IRUGO);
+MODULE_PARM_DESC(myri10ge_lro, "Number of LRO packets to be aggregated\n");
+
 static int myri10ge_fill_thresh = 256;
 module_param(myri10ge_fill_thresh, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(myri10ge_fill_thresh, "Number of empty rx slots allowed\n");
@@ -1019,6 +1036,15 @@
 		remainder -= MYRI10GE_ALLOC_SIZE;
 	}
 
+	if (mgp->csum_flag && myri10ge_lro) {
+		rx_frags[0].page_offset += MXGEFW_PAD;
+		rx_frags[0].size -= MXGEFW_PAD;
+		len -= MXGEFW_PAD;
+		lro_receive_frags(&mgp->rx_done.lro_mgr, rx_frags,
+				  len, len, (void *)(unsigned long)csum, csum);
+		return 1;
+	}
+
 	hlen = MYRI10GE_HLEN > len ? len : MYRI10GE_HLEN;
 
 	/* allocate an skb to attach the page(s) to. */
@@ -1099,7 +1125,7 @@
 	}
 }
 
-static inline void myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int *limit)
+static inline int myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int budget)
 {
 	struct myri10ge_rx_done *rx_done = &mgp->rx_done;
 	unsigned long rx_bytes = 0;
@@ -1108,10 +1134,11 @@
 
 	int idx = rx_done->idx;
 	int cnt = rx_done->cnt;
+	int work_done = 0;
 	u16 length;
 	__wsum checksum;
 
-	while (rx_done->entry[idx].length != 0 && *limit != 0) {
+	while (rx_done->entry[idx].length != 0 && work_done++ < budget) {
 		length = ntohs(rx_done->entry[idx].length);
 		rx_done->entry[idx].length = 0;
 		checksum = csum_unfold(rx_done->entry[idx].checksum);
@@ -1127,16 +1154,15 @@
 		rx_bytes += rx_ok * (unsigned long)length;
 		cnt++;
 		idx = cnt & (myri10ge_max_intr_slots - 1);
-
-		/* limit potential for livelock by only handling a
-		 * limited number of frames. */
-		(*limit)--;
 	}
 	rx_done->idx = idx;
 	rx_done->cnt = cnt;
 	mgp->stats.rx_packets += rx_packets;
 	mgp->stats.rx_bytes += rx_bytes;
 
+	if (myri10ge_lro)
+		lro_flush_all(&rx_done->lro_mgr);
+
 	/* restock receive rings if needed */
 	if (mgp->rx_small.fill_cnt - mgp->rx_small.cnt < myri10ge_fill_thresh)
 		myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
@@ -1144,6 +1170,7 @@
 	if (mgp->rx_big.fill_cnt - mgp->rx_big.cnt < myri10ge_fill_thresh)
 		myri10ge_alloc_rx_pages(mgp, &mgp->rx_big, mgp->big_bytes, 0);
 
+	return work_done;
 }
 
 static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
@@ -1188,26 +1215,21 @@
 	}
 }
 
-static int myri10ge_poll(struct net_device *netdev, int *budget)
+static int myri10ge_poll(struct napi_struct *napi, int budget)
 {
-	struct myri10ge_priv *mgp = netdev_priv(netdev);
+	struct myri10ge_priv *mgp = container_of(napi, struct myri10ge_priv, napi);
+	struct net_device *netdev = mgp->dev;
 	struct myri10ge_rx_done *rx_done = &mgp->rx_done;
-	int limit, orig_limit, work_done;
+	int work_done;
 
 	/* process as many rx events as NAPI will allow */
-	limit = min(*budget, netdev->quota);
-	orig_limit = limit;
-	myri10ge_clean_rx_done(mgp, &limit);
-	work_done = orig_limit - limit;
-	*budget -= work_done;
-	netdev->quota -= work_done;
+	work_done = myri10ge_clean_rx_done(mgp, budget);
 
 	if (rx_done->entry[rx_done->idx].length == 0 || !netif_running(netdev)) {
-		netif_rx_complete(netdev);
+		netif_rx_complete(netdev, napi);
 		put_be32(htonl(3), mgp->irq_claim);
-		return 0;
 	}
-	return 1;
+	return work_done;
 }
 
 static irqreturn_t myri10ge_intr(int irq, void *arg)
@@ -1225,7 +1247,7 @@
 	/* low bit indicates receives are present, so schedule
 	 * napi poll handler */
 	if (stats->valid & 1)
-		netif_rx_schedule(mgp->dev);
+		netif_rx_schedule(mgp->dev, &mgp->napi);
 
 	if (!mgp->msi_enabled) {
 		put_be32(0, mgp->irq_deassert);
@@ -1378,7 +1400,8 @@
 	"dropped_pause", "dropped_bad_phy", "dropped_bad_crc32",
 	"dropped_unicast_filtered", "dropped_multicast_filtered",
 	"dropped_runt", "dropped_overrun", "dropped_no_small_buffer",
-	"dropped_no_big_buffer"
+	"dropped_no_big_buffer", "LRO aggregated", "LRO flushed",
+	"LRO avg aggr", "LRO no_desc"
 };
 
 #define MYRI10GE_NET_STATS_LEN      21
@@ -1395,9 +1418,14 @@
 	}
 }
 
-static int myri10ge_get_stats_count(struct net_device *netdev)
+static int myri10ge_get_sset_count(struct net_device *netdev, int sset)
 {
-	return MYRI10GE_STATS_LEN;
+	switch (sset) {
+	case ETH_SS_STATS:
+		return MYRI10GE_STATS_LEN;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void
@@ -1444,6 +1472,14 @@
 	data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_overrun);
 	data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_small_buffer);
 	data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_big_buffer);
+	data[i++] = mgp->rx_done.lro_mgr.stats.aggregated;
+	data[i++] = mgp->rx_done.lro_mgr.stats.flushed;
+	if (mgp->rx_done.lro_mgr.stats.flushed)
+		data[i++] = mgp->rx_done.lro_mgr.stats.aggregated /
+		    mgp->rx_done.lro_mgr.stats.flushed;
+	else
+		data[i++] = 0;
+	data[i++] = mgp->rx_done.lro_mgr.stats.no_desc;
 }
 
 static void myri10ge_set_msglevel(struct net_device *netdev, u32 value)
@@ -1468,15 +1504,12 @@
 	.get_ringparam = myri10ge_get_ringparam,
 	.get_rx_csum = myri10ge_get_rx_csum,
 	.set_rx_csum = myri10ge_set_rx_csum,
-	.get_tx_csum = ethtool_op_get_tx_csum,
 	.set_tx_csum = ethtool_op_set_tx_hw_csum,
-	.get_sg = ethtool_op_get_sg,
 	.set_sg = ethtool_op_set_sg,
-	.get_tso = ethtool_op_get_tso,
 	.set_tso = ethtool_op_set_tso,
 	.get_link = ethtool_op_get_link,
 	.get_strings = myri10ge_get_strings,
-	.get_stats_count = myri10ge_get_stats_count,
+	.get_sset_count = myri10ge_get_sset_count,
 	.get_ethtool_stats = myri10ge_get_ethtool_stats,
 	.set_msglevel = myri10ge_set_msglevel,
 	.get_msglevel = myri10ge_get_msglevel
@@ -1717,10 +1750,69 @@
 		pci_disable_msi(pdev);
 }
 
+static int
+myri10ge_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr,
+			 void **ip_hdr, void **tcpudp_hdr,
+			 u64 * hdr_flags, void *priv)
+{
+	struct ethhdr *eh;
+	struct vlan_ethhdr *veh;
+	struct iphdr *iph;
+	u8 *va = page_address(frag->page) + frag->page_offset;
+	unsigned long ll_hlen;
+	__wsum csum = (__wsum) (unsigned long)priv;
+
+	/* find the mac header, aborting if not IPv4 */
+
+	eh = (struct ethhdr *)va;
+	*mac_hdr = eh;
+	ll_hlen = ETH_HLEN;
+	if (eh->h_proto != htons(ETH_P_IP)) {
+		if (eh->h_proto == htons(ETH_P_8021Q)) {
+			veh = (struct vlan_ethhdr *)va;
+			if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP))
+				return -1;
+
+			ll_hlen += VLAN_HLEN;
+
+			/*
+			 *  HW checksum starts ETH_HLEN bytes into
+			 *  frame, so we must subtract off the VLAN
+			 *  header's checksum before csum can be used
+			 */
+			csum = csum_sub(csum, csum_partial(va + ETH_HLEN,
+							   VLAN_HLEN, 0));
+		} else {
+			return -1;
+		}
+	}
+	*hdr_flags = LRO_IPV4;
+
+	iph = (struct iphdr *)(va + ll_hlen);
+	*ip_hdr = iph;
+	if (iph->protocol != IPPROTO_TCP)
+		return -1;
+	*hdr_flags |= LRO_TCP;
+	*tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2);
+
+	/* verify the IP checksum */
+	if (unlikely(ip_fast_csum((u8 *) iph, iph->ihl)))
+		return -1;
+
+	/* verify the  checksum */
+	if (unlikely(csum_tcpudp_magic(iph->saddr, iph->daddr,
+				       ntohs(iph->tot_len) - (iph->ihl << 2),
+				       IPPROTO_TCP, csum)))
+		return -1;
+
+	return 0;
+}
+
 static int myri10ge_open(struct net_device *dev)
 {
 	struct myri10ge_priv *mgp;
 	struct myri10ge_cmd cmd;
+	struct net_lro_mgr *lro_mgr;
 	int status, big_pow2;
 
 	mgp = netdev_priv(dev);
@@ -1852,7 +1944,19 @@
 	mgp->link_state = htonl(~0U);
 	mgp->rdma_tags_available = 15;
 
-	netif_poll_enable(mgp->dev);	/* must happen prior to any irq */
+	lro_mgr = &mgp->rx_done.lro_mgr;
+	lro_mgr->dev = dev;
+	lro_mgr->features = LRO_F_NAPI;
+	lro_mgr->ip_summed = CHECKSUM_COMPLETE;
+	lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
+	lro_mgr->max_desc = MYRI10GE_MAX_LRO_DESCRIPTORS;
+	lro_mgr->lro_arr = mgp->rx_done.lro_desc;
+	lro_mgr->get_frag_header = myri10ge_get_frag_header;
+	lro_mgr->max_aggr = myri10ge_lro_max_pkts;
+	if (lro_mgr->max_aggr > MAX_SKB_FRAGS)
+		lro_mgr->max_aggr = MAX_SKB_FRAGS;
+
+	napi_enable(&mgp->napi);	/* must happen prior to any irq */
 
 	status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0);
 	if (status) {
@@ -1896,7 +2000,7 @@
 
 	del_timer_sync(&mgp->watchdog_timer);
 	mgp->running = MYRI10GE_ETH_STOPPING;
-	netif_poll_disable(mgp->dev);
+	napi_disable(&mgp->napi);
 	netif_carrier_off(dev);
 	netif_stop_queue(dev);
 	old_down_cnt = mgp->down_cnt;
@@ -2296,6 +2400,7 @@
 	struct dev_mc_list *mc_list;
 	__be32 data[2] = { 0, 0 };
 	int err;
+	DECLARE_MAC_BUF(mac);
 
 	mgp = netdev_priv(dev);
 	/* can be called from atomic contexts,
@@ -2343,14 +2448,8 @@
 			printk(KERN_ERR "myri10ge: %s: Failed "
 			       "MXGEFW_JOIN_MULTICAST_GROUP, error status:"
 			       "%d\t", dev->name, err);
-			printk(KERN_ERR "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
-			       ((unsigned char *)&mc_list->dmi_addr)[0],
-			       ((unsigned char *)&mc_list->dmi_addr)[1],
-			       ((unsigned char *)&mc_list->dmi_addr)[2],
-			       ((unsigned char *)&mc_list->dmi_addr)[3],
-			       ((unsigned char *)&mc_list->dmi_addr)[4],
-			       ((unsigned char *)&mc_list->dmi_addr)[5]
-			    );
+			printk(KERN_ERR "MAC %s\n",
+			       print_mac(mac, mc_list->dmi_addr));
 			goto abort;
 		}
 	}
@@ -2513,26 +2612,20 @@
 {
 	struct pci_dev *pdev = mgp->pdev;
 	struct device *dev = &pdev->dev;
-	int cap, status;
-	u16 val;
+	int status;
 
 	mgp->tx.boundary = 4096;
 	/*
 	 * Verify the max read request size was set to 4KB
 	 * before trying the test with 4KB.
 	 */
-	cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
-	if (cap < 64) {
-		dev_err(dev, "Bad PCI_CAP_ID_EXP location %d\n", cap);
-		goto abort;
-	}
-	status = pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &val);
-	if (status != 0) {
+	status = pcie_get_readrq(pdev);
+	if (status < 0) {
 		dev_err(dev, "Couldn't read max read req size: %d\n", status);
 		goto abort;
 	}
-	if ((val & (5 << 12)) != (5 << 12)) {
-		dev_warn(dev, "Max Read Request size != 4096 (0x%x)\n", val);
+	if (status != 4096) {
+		dev_warn(dev, "Max Read Request size != 4096 (%d)\n", status);
 		mgp->tx.boundary = 2048;
 	}
 	/*
@@ -2800,6 +2893,7 @@
 static void myri10ge_watchdog_timer(unsigned long arg)
 {
 	struct myri10ge_priv *mgp;
+	u32 rx_pause_cnt;
 
 	mgp = (struct myri10ge_priv *)arg;
 
@@ -2816,19 +2910,28 @@
 		    myri10ge_fill_thresh)
 			mgp->rx_big.watchdog_needed = 0;
 	}
+	rx_pause_cnt = ntohl(mgp->fw_stats->dropped_pause);
 
 	if (mgp->tx.req != mgp->tx.done &&
 	    mgp->tx.done == mgp->watchdog_tx_done &&
-	    mgp->watchdog_tx_req != mgp->watchdog_tx_done)
+	    mgp->watchdog_tx_req != mgp->watchdog_tx_done) {
 		/* nic seems like it might be stuck.. */
-		schedule_work(&mgp->watchdog_work);
-	else
-		/* rearm timer */
-		mod_timer(&mgp->watchdog_timer,
-			  jiffies + myri10ge_watchdog_timeout * HZ);
-
+		if (rx_pause_cnt != mgp->watchdog_pause) {
+			if (net_ratelimit())
+				printk(KERN_WARNING "myri10ge %s:"
+				       "TX paused, check link partner\n",
+				       mgp->dev->name);
+		} else {
+			schedule_work(&mgp->watchdog_work);
+			return;
+		}
+	}
+	/* rearm timer */
+	mod_timer(&mgp->watchdog_timer,
+		  jiffies + myri10ge_watchdog_timeout * HZ);
 	mgp->watchdog_tx_done = mgp->tx.done;
 	mgp->watchdog_tx_req = mgp->tx.req;
+	mgp->watchdog_pause = rx_pause_cnt;
 }
 
 static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -2839,9 +2942,7 @@
 	size_t bytes;
 	int i;
 	int status = -ENXIO;
-	int cap;
 	int dac_enabled;
-	u16 val;
 
 	netdev = alloc_etherdev(sizeof(*mgp));
 	if (netdev == NULL) {
@@ -2852,8 +2953,9 @@
 	SET_NETDEV_DEV(netdev, &pdev->dev);
 
 	mgp = netdev_priv(netdev);
-	memset(mgp, 0, sizeof(*mgp));
 	mgp->dev = netdev;
+	netif_napi_add(netdev, &mgp->napi,
+		       myri10ge_poll, myri10ge_napi_weight);
 	mgp->pdev = pdev;
 	mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
 	mgp->pause = myri10ge_flow_control;
@@ -2873,19 +2975,7 @@
 	    = pci_find_capability(pdev, PCI_CAP_ID_VNDR);
 
 	/* Set our max read request to 4KB */
-	cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
-	if (cap < 64) {
-		dev_err(&pdev->dev, "Bad PCI_CAP_ID_EXP location %d\n", cap);
-		goto abort_with_netdev;
-	}
-	status = pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &val);
-	if (status != 0) {
-		dev_err(&pdev->dev, "Error %d reading PCI_EXP_DEVCTL\n",
-			status);
-		goto abort_with_netdev;
-	}
-	val = (val & ~PCI_EXP_DEVCTL_READRQ) | (5 << 12);
-	status = pci_write_config_word(pdev, cap + PCI_EXP_DEVCTL, val);
+	status = pcie_set_readrq(pdev, 4096);
 	if (status != 0) {
 		dev_err(&pdev->dev, "Error %d writing PCI_EXP_DEVCTL\n",
 			status);
@@ -2990,8 +3080,6 @@
 	netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO;
 	if (dac_enabled)
 		netdev->features |= NETIF_F_HIGHDMA;
-	netdev->poll = myri10ge_poll;
-	netdev->weight = myri10ge_napi_weight;
 
 	/* make sure we can get an irq, and that MSI can be
 	 * setup (if available).  Also ensure netdev->irq
@@ -3103,9 +3191,12 @@
 }
 
 #define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E 	0x0008
+#define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9	0x0009
 
 static struct pci_device_id myri10ge_pci_tbl[] = {
 	{PCI_DEVICE(PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E)},
+	{PCI_DEVICE
+	 (PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9)},
 	{0},
 };
 
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 13444da..8d29319 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -311,12 +311,12 @@
 #ifdef DEBUG_HEADER
 static void dump_ehdr(struct ethhdr *ehdr)
 {
-	printk("ehdr[h_dst(%02x:%02x:%02x:%02x:%02x:%02x)"
-	       "h_source(%02x:%02x:%02x:%02x:%02x:%02x)h_proto(%04x)]\n",
-	       ehdr->h_dest[0], ehdr->h_dest[1], ehdr->h_dest[2],
-	       ehdr->h_dest[3], ehdr->h_dest[4], ehdr->h_dest[4],
-	       ehdr->h_source[0], ehdr->h_source[1], ehdr->h_source[2],
-	       ehdr->h_source[3], ehdr->h_source[4], ehdr->h_source[4],
+	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mac2);
+	printk("ehdr[h_dst(%s)"
+	       "h_source(%s)"
+	       "h_proto(%04x)]\n",
+	       print_mac(mac, ehdr->h_dest), print_mac(mac2, ehdr->h_source),
 	       ehdr->h_proto);
 }
 
@@ -325,13 +325,7 @@
 	struct ethhdr *ehdr = (struct ethhdr *) (stuff + 2);
 
 	printk("pad[%02x:%02x]", stuff[0], stuff[1]);
-	printk("ehdr[h_dst(%02x:%02x:%02x:%02x:%02x:%02x)"
-	       "h_source(%02x:%02x:%02x:%02x:%02x:%02x)h_proto(%04x)]\n",
-	       ehdr->h_dest[0], ehdr->h_dest[1], ehdr->h_dest[2],
-	       ehdr->h_dest[3], ehdr->h_dest[4], ehdr->h_dest[4],
-	       ehdr->h_source[0], ehdr->h_source[1], ehdr->h_source[2],
-	       ehdr->h_source[3], ehdr->h_source[4], ehdr->h_source[4],
-	       ehdr->h_proto);
+	dump_ehdr(ehdr);
 }
 #endif
 
@@ -353,7 +347,7 @@
 		sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE);
 		dev_kfree_skb(skb);
 		mp->tx_skbs[entry] = NULL;
-		mp->enet_stats.tx_packets++;
+		dev->stats.tx_packets++;
 		entry = NEXT_TX(entry);
 	}
 	mp->tx_old = entry;
@@ -434,20 +428,20 @@
 					     RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE);
 		if (len < (ETH_HLEN + MYRI_PAD_LEN) || (skb->data[0] != MYRI_PAD_LEN)) {
 			DRX(("ERROR["));
-			mp->enet_stats.rx_errors++;
+			dev->stats.rx_errors++;
 			if (len < (ETH_HLEN + MYRI_PAD_LEN)) {
 				DRX(("BAD_LENGTH] "));
-				mp->enet_stats.rx_length_errors++;
+				dev->stats.rx_length_errors++;
 			} else {
 				DRX(("NO_PADDING] "));
-				mp->enet_stats.rx_frame_errors++;
+				dev->stats.rx_frame_errors++;
 			}
 
 			/* Return it to the LANAI. */
 	drop_it:
 			drops++;
 			DRX(("DROP "));
-			mp->enet_stats.rx_dropped++;
+			dev->stats.rx_dropped++;
 			sbus_dma_sync_single_for_device(mp->myri_sdev,
 							sbus_readl(&rxd->myri_scatters[0].addr),
 							RX_ALLOC_SIZE,
@@ -527,8 +521,8 @@
 		netif_rx(skb);
 
 		dev->last_rx = jiffies;
-		mp->enet_stats.rx_packets++;
-		mp->enet_stats.rx_bytes += len;
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += len;
 	next:
 		DRX(("NEXT\n"));
 		entry = NEXT_RX(entry);
@@ -596,7 +590,7 @@
 
 	printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name);
 
-	mp->enet_stats.tx_errors++;
+	dev->stats.tx_errors++;
 	myri_init(mp, 0);
 	netif_wake_queue(dev);
 }
@@ -682,8 +676,9 @@
  * saddr=NULL	means use device source address
  * daddr=NULL	means leave destination address (eg unresolved arp)
  */
-static int myri_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-		       void *daddr, void *saddr, unsigned len)
+static int myri_header(struct sk_buff *skb, struct net_device *dev,
+		       unsigned short type, const void *daddr,
+		       const void *saddr, unsigned len)
 {
 	struct ethhdr *eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
 	unsigned char *pad = (unsigned char *) skb_push(skb, MYRI_PAD_LEN);
@@ -765,18 +760,18 @@
 	return 0;
 }
 
-int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+static int myri_header_cache(const struct neighbour *neigh, struct hh_cache *hh)
 {
 	unsigned short type = hh->hh_type;
 	unsigned char *pad;
 	struct ethhdr *eth;
-	struct net_device *dev = neigh->dev;
+	const struct net_device *dev = neigh->dev;
 
 	pad = ((unsigned char *) hh->hh_data) +
 		HH_DATA_OFF(sizeof(*eth) + MYRI_PAD_LEN);
 	eth = (struct ethhdr *) (pad + MYRI_PAD_LEN);
 
-	if (type == __constant_htons(ETH_P_802_3))
+	if (type == htons(ETH_P_802_3))
 		return -1;
 
 	/* Refill MyriNet padding identifiers, this is just being anal. */
@@ -792,7 +787,9 @@
 
 
 /* Called by Address Resolution module to notify changes in address. */
-void myri_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr)
+void myri_header_cache_update(struct hh_cache *hh,
+			      const struct net_device *dev,
+			      const unsigned char * haddr)
 {
 	memcpy(((u8*)hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)),
 	       haddr, dev->addr_len);
@@ -806,9 +803,6 @@
 	return 0;
 }
 
-static struct net_device_stats *myri_get_stats(struct net_device *dev)
-{ return &(((struct myri_eth *)dev->priv)->enet_stats); }
-
 static void myri_set_multicast(struct net_device *dev)
 {
 	/* Do nothing, all MyriCOM nodes transmit multicast frames
@@ -890,6 +884,13 @@
 }
 #endif
 
+static const struct header_ops myri_header_ops = {
+	.create		= myri_header,
+	.rebuild	= myri_rebuild_header,
+	.cache	 	= myri_header_cache,
+	.cache_update	= myri_header_cache_update,
+};
+
 static int __devinit myri_ether_init(struct sbus_dev *sdev)
 {
 	static int num;
@@ -898,6 +899,7 @@
 	struct myri_eth *mp;
 	unsigned char prop_buf[32];
 	int i;
+	DECLARE_MAC_BUF(mac);
 
 	DET(("myri_ether_init(%p,%d):\n", sdev, num));
 	dev = alloc_etherdev(sizeof(struct myri_eth));
@@ -908,7 +910,6 @@
 	if (version_printed++ == 0)
 		printk(version);
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
 
 	mp = (struct myri_eth *) dev->priv;
@@ -1061,7 +1062,6 @@
 	dev->hard_start_xmit = &myri_start_xmit;
 	dev->tx_timeout = &myri_tx_timeout;
 	dev->watchdog_timeo = 5*HZ;
-	dev->get_stats = &myri_get_stats;
 	dev->set_multicast_list = &myri_set_multicast;
 	dev->irq = sdev->irqs[0];
 
@@ -1075,11 +1075,9 @@
 
 	dev->mtu		= MYRINET_MTU;
 	dev->change_mtu		= myri_change_mtu;
-	dev->hard_header	= myri_header;
-	dev->rebuild_header	= myri_rebuild_header;
+	dev->header_ops		= &myri_header_ops;
+
 	dev->hard_header_len	= (ETH_HLEN + MYRI_PAD_LEN);
-	dev->hard_header_cache 	= myri_header_cache;
-	dev->header_cache_update= myri_header_cache_update;
 
 	/* Load code onto the LANai. */
 	DET(("Loading LANAI firmware\n"));
@@ -1094,12 +1092,8 @@
 
 	num++;
 
-	printk("%s: MyriCOM MyriNET Ethernet ", dev->name);
-
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", dev->dev_addr[i],
-		       i == 5 ? ' ' : ':');
-	printk("\n");
+	printk("%s: MyriCOM MyriNET Ethernet %s\n",
+	       dev->name, print_mac(mac, dev->dev_addr));
 
 	return 0;
 
diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h
index 2f69ef7..5d93fcc 100644
--- a/drivers/net/myri_sbus.h
+++ b/drivers/net/myri_sbus.h
@@ -280,7 +280,6 @@
 	void __iomem			*lregs;		/* Quick ptr to LANAI regs.   */
 	struct sk_buff	       *rx_skbs[RX_RING_SIZE+1];/* RX skb's                   */
 	struct sk_buff	       *tx_skbs[TX_RING_SIZE];  /* TX skb's                   */
-	struct net_device_stats		enet_stats;	/* Interface stats.           */
 
 	/* These are less frequently accessed. */
 	void __iomem			*regs;          /* MyriCOM register space.    */
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 6bb48ba..527f9dc 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -108,7 +108,7 @@
 #define TX_TIMEOUT  (2*HZ)
 
 #define NATSEMI_HW_TIMEOUT	400
-#define NATSEMI_TIMER_FREQ	3*HZ
+#define NATSEMI_TIMER_FREQ	5*HZ
 #define NATSEMI_PG0_NREGS	64
 #define NATSEMI_RFDR_NREGS	8
 #define NATSEMI_PG1_NREGS	4
@@ -560,6 +560,8 @@
 	/* address of a sent-in-place packet/buffer, for later free() */
 	struct sk_buff *tx_skbuff[TX_RING_SIZE];
 	dma_addr_t tx_dma[TX_RING_SIZE];
+	struct net_device *dev;
+	struct napi_struct napi;
 	struct net_device_stats stats;
 	/* Media monitoring timer */
 	struct timer_list timer;
@@ -636,7 +638,7 @@
 static int start_tx(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t intr_handler(int irq, void *dev_instance);
 static void netdev_error(struct net_device *dev, int intr_status);
-static int natsemi_poll(struct net_device *dev, int *budget);
+static int natsemi_poll(struct napi_struct *napi, int budget);
 static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do);
 static void netdev_tx_done(struct net_device *dev);
 static int natsemi_change_mtu(struct net_device *dev, int new_mtu);
@@ -803,6 +805,7 @@
 	const int pcibar = 1; /* PCI base address register */
 	int prev_eedata;
 	u32 tmp;
+	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -835,7 +838,6 @@
 	dev = alloc_etherdev(sizeof (struct netdev_private));
 	if (!dev)
 		return -ENOMEM;
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	i = pci_request_regions(pdev, DRV_NAME);
@@ -861,6 +863,7 @@
 	dev->irq = irq;
 
 	np = netdev_priv(dev);
+	netif_napi_add(dev, &np->napi, natsemi_poll, 64);
 
 	np->pci_dev = pdev;
 	pci_set_drvdata(pdev, dev);
@@ -931,8 +934,6 @@
 	dev->do_ioctl = &netdev_ioctl;
 	dev->tx_timeout = &tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
-	dev->poll = natsemi_poll;
-	dev->weight = 64;
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = &natsemi_poll_controller;
@@ -958,12 +959,10 @@
 		goto err_create_file;
 
 	if (netif_msg_drv(np)) {
-		printk(KERN_INFO "natsemi %s: %s at %#08lx (%s), ",
-			dev->name, natsemi_pci_info[chip_idx].name, iostart,
-			pci_name(np->pci_dev));
-		for (i = 0; i < ETH_ALEN-1; i++)
-				printk("%02x:", dev->dev_addr[i]);
-		printk("%02x, IRQ %d", dev->dev_addr[i], irq);
+		printk(KERN_INFO "natsemi %s: %s at %#08lx "
+		       "(%s), %s, IRQ %d",
+		       dev->name, natsemi_pci_info[chip_idx].name, iostart,
+		       pci_name(np->pci_dev), print_mac(mac, dev->dev_addr), irq);
 		if (dev->if_port == PORT_TP)
 			printk(", port TP.\n");
 		else if (np->ignore_phy)
@@ -1554,6 +1553,8 @@
 		free_irq(dev->irq, dev);
 		return i;
 	}
+	napi_enable(&np->napi);
+
 	init_ring(dev);
 	spin_lock_irq(&np->lock);
 	init_registers(dev);
@@ -1614,7 +1615,7 @@
 		 * (these values all come from National)
 		 */
 		if (!(data & 0x80) || ((data >= 0xd8) && (data <= 0xff))) {
-			struct netdev_private *np = netdev_priv(dev);
+			np = netdev_priv(dev);
 
 			/* the bug has been triggered - fix the coefficient */
 			writew(TSTDAT_FIXED, ioaddr + TSTDAT);
@@ -1797,7 +1798,7 @@
 	struct net_device *dev = (struct net_device *)data;
 	struct netdev_private *np = netdev_priv(dev);
 	void __iomem * ioaddr = ns_ioaddr(dev);
-	int next_tick = 5*HZ;
+	int next_tick = NATSEMI_TIMER_FREQ;
 
 	if (netif_msg_timer(np)) {
 		/* DO NOT read the IntrStatus register,
@@ -2200,10 +2201,10 @@
 
 	prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]);
 
-	if (netif_rx_schedule_prep(dev)) {
+	if (netif_rx_schedule_prep(dev, &np->napi)) {
 		/* Disable interrupts and register for poll */
 		natsemi_irq_disable(dev);
-		__netif_rx_schedule(dev);
+		__netif_rx_schedule(dev, &np->napi);
 	} else
 		printk(KERN_WARNING
 	       	       "%s: Ignoring interrupt, status %#08x, mask %#08x.\n",
@@ -2216,12 +2217,11 @@
 /* This is the NAPI poll routine.  As well as the standard RX handling
  * it also handles all other interrupts that the chip might raise.
  */
-static int natsemi_poll(struct net_device *dev, int *budget)
+static int natsemi_poll(struct napi_struct *napi, int budget)
 {
-	struct netdev_private *np = netdev_priv(dev);
+	struct netdev_private *np = container_of(napi, struct netdev_private, napi);
+	struct net_device *dev = np->dev;
 	void __iomem * ioaddr = ns_ioaddr(dev);
-
-	int work_to_do = min(*budget, dev->quota);
 	int work_done = 0;
 
 	do {
@@ -2236,7 +2236,7 @@
 		if (np->intr_status &
 		    (IntrRxDone | IntrRxIntr | RxStatusFIFOOver |
 		     IntrRxErr | IntrRxOverrun)) {
-			netdev_rx(dev, &work_done, work_to_do);
+			netdev_rx(dev, &work_done, budget);
 		}
 
 		if (np->intr_status &
@@ -2250,16 +2250,13 @@
 		if (np->intr_status & IntrAbnormalSummary)
 			netdev_error(dev, np->intr_status);
 
-		*budget -= work_done;
-		dev->quota -= work_done;
-
-		if (work_done >= work_to_do)
-			return 1;
+		if (work_done >= budget)
+			return work_done;
 
 		np->intr_status = readl(ioaddr + IntrStatus);
 	} while (np->intr_status);
 
-	netif_rx_complete(dev);
+	netif_rx_complete(dev, napi);
 
 	/* Reenable interrupts providing nothing is trying to shut
 	 * the chip down. */
@@ -2268,7 +2265,7 @@
 		natsemi_irq_enable(dev);
 	spin_unlock(&np->lock);
 
-	return 0;
+	return work_done;
 }
 
 /* This routine is logically part of the interrupt handler, but separated
@@ -2438,13 +2435,16 @@
 				dev->name);
 		}
 		np->stats.rx_fifo_errors++;
+		np->stats.rx_errors++;
 	}
 	/* Hmmmmm, it's not clear how to recover from PCI faults. */
 	if (intr_status & IntrPCIErr) {
 		printk(KERN_NOTICE "%s: PCI error %#08x\n", dev->name,
 			intr_status & IntrPCIErr);
 		np->stats.tx_fifo_errors++;
+		np->stats.tx_errors++;
 		np->stats.rx_fifo_errors++;
+		np->stats.rx_errors++;
 	}
 	spin_unlock(&np->lock);
 }
@@ -2502,8 +2502,8 @@
 		memset(mc_filter, 0, sizeof(mc_filter));
 		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
 			 i++, mclist = mclist->next) {
-			int i = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff;
-			mc_filter[i/8] |= (1 << (i & 0x07));
+			int b = (ether_crc(ETH_ALEN, mclist->dmi_addr) >> 23) & 0x1ff;
+			mc_filter[b/8] |= (1 << (b & 0x07));
 		}
 		rx_mode = RxFilterEnable | AcceptBroadcast
 			| AcceptMulticast | AcceptMyPhys;
@@ -3155,6 +3155,8 @@
 			dev->name, np->cur_tx, np->dirty_tx,
 			np->cur_rx, np->dirty_rx);
 
+	napi_disable(&np->napi);
+
 	/*
 	 * FIXME: what if someone tries to close a device
 	 * that is suspended?
@@ -3250,7 +3252,7 @@
  *		disable_irq() to enforce synchronization.
  *      * natsemi_poll: checks before reenabling interrupts.  suspend
  *              sets hands_off, disables interrupts and then waits with
- *              netif_poll_disable().
+ *              napi_disable().
  *
  * Interrupts must be disabled, otherwise hands_off can cause irq storms.
  */
@@ -3276,7 +3278,7 @@
 		spin_unlock_irq(&np->lock);
 		enable_irq(dev->irq);
 
-		netif_poll_disable(dev);
+		napi_disable(&np->napi);
 
 		/* Update the error counts. */
 		__get_stats(dev);
@@ -3317,6 +3319,8 @@
 		pci_enable_device(pdev);
 	/*	pci_power_on(pdev); */
 
+		napi_enable(&np->napi);
+
 		natsemi_reset(dev);
 		init_ring(dev);
 		disable_irq(dev->irq);
@@ -3330,7 +3334,6 @@
 		mod_timer(&np->timer, jiffies + 1*HZ);
 	}
 	netif_device_attach(dev);
-	netif_poll_enable(dev);
 out:
 	rtnl_unlock();
 	return 0;
diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c
index 38fd525..368f256 100644
--- a/drivers/net/ne-h8300.c
+++ b/drivers/net/ne-h8300.c
@@ -149,8 +149,6 @@
 {
 	unsigned int base_addr = dev->base_addr;
 
-	SET_MODULE_OWNER(dev);
-
 	/* First check any supplied i/o locations. User knows best. <cough> */
 	if (base_addr > 0x1ff)	/* Check a single specified location. */
 		return ne_probe1(dev, base_addr);
@@ -206,6 +204,7 @@
 	static unsigned version_printed;
 	struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
 	unsigned char bus_width;
+	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -259,7 +258,7 @@
 			{E8390_RREAD+E8390_START, E8390_CMD},
 		};
 
-		for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+		for (i = 0; i < ARRAY_SIZE(program_seq); i++)
 			outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
 
 	}
@@ -298,12 +297,11 @@
 
 	dev->base_addr = ioaddr;
 
-	for(i = 0; i < ETHER_ADDR_LEN; i++) {
-		printk(" %2.2x", SA_prom[i]);
+	for(i = 0; i < ETHER_ADDR_LEN; i++)
 		dev->dev_addr[i] = SA_prom[i];
-	}
+	printk(" %s\n", print_mac(mac, dev->dev_addr));
 
-	printk("\n%s: %s found at %#x, using IRQ %d.\n",
+	printk("%s: %s found at %#x, using IRQ %d.\n",
 		dev->name, name, ioaddr, dev->irq);
 
 	ei_status.name = name;
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index c9f74bf..874d291 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -191,8 +191,6 @@
 	int orig_irq = dev->irq;
 #endif
 
-	SET_MODULE_OWNER(dev);
-
 	/* First check any supplied i/o locations. User knows best. <cough> */
 	if (base_addr > 0x1ff)	/* Check a single specified location. */
 		return ne_probe1(dev, base_addr);
@@ -293,6 +291,7 @@
 	int neX000, ctron, copam, bad_card;
 	int reg0, ret;
 	static unsigned version_printed;
+	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -377,7 +376,7 @@
 			{E8390_RREAD+E8390_START, E8390_CMD},
 		};
 
-		for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+		for (i = 0; i < ARRAY_SIZE(program_seq); i++)
 			outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
 
 	}
@@ -505,16 +504,14 @@
 	for (i = 0 ; i < ETHER_ADDR_LEN ; i++) {
 		dev->dev_addr[i] = SA_prom[i]
 			= inb_p(ioaddr + EN1_PHYS_SHIFT(i));
-		printk(" %2.2x", SA_prom[i]);
 	}
 #else
 	for(i = 0; i < ETHER_ADDR_LEN; i++) {
-		printk(" %2.2x", SA_prom[i]);
 		dev->dev_addr[i] = SA_prom[i];
 	}
 #endif
 
-	printk("\n");
+	printk("%s\n", print_mac(mac, dev->dev_addr));
 
 	ei_status.name = name;
 	ei_status.tx_start_page = start_page;
diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c
index 089b5bb..f4cd8c7 100644
--- a/drivers/net/ne2.c
+++ b/drivers/net/ne2.c
@@ -251,8 +251,6 @@
 	int i;
 	int adapter_found = 0;
 
-	SET_MODULE_OWNER(dev);
-
 	/* Do not check any supplied i/o locations.
 	   POS registers usually don't fail :) */
 
@@ -304,6 +302,7 @@
 static int ne2_procinfo(char *buf, int slot, struct net_device *dev)
 {
 	int len=0;
+	DECLARE_MAC_BUF(mac);
 
 	len += sprintf(buf+len, "The NE/2 Ethernet Adapter\n" );
 	len += sprintf(buf+len, "Driver written by Wim Dumon ");
@@ -314,12 +313,7 @@
 	len += sprintf(buf+len, "Based on the original NE2000 drivers\n" );
 	len += sprintf(buf+len, "Base IO: %#x\n", (unsigned int)dev->base_addr);
 	len += sprintf(buf+len, "IRQ    : %d\n", dev->irq);
-
-#define HW_ADDR(i) dev->dev_addr[i]
-	len += sprintf(buf+len, "HW addr : %x:%x:%x:%x:%x:%x\n",
-			HW_ADDR(0), HW_ADDR(1), HW_ADDR(2),
-			HW_ADDR(3), HW_ADDR(4), HW_ADDR(5) );
-#undef HW_ADDR
+	len += sprintf(buf+len, "HW addr : %s\n", print_mac(mac, dev->dev_addr));
 
 	return len;
 }
@@ -332,6 +326,7 @@
 	const char *name = "NE/2";
 	int start_page, stop_page;
 	static unsigned version_printed;
+	DECLARE_MAC_BUF(mac);
 
 	if (ei_debug && version_printed++ == 0)
 		printk(version);
@@ -432,7 +427,7 @@
 			{E8390_RREAD+E8390_START, E8390_CMD},
 		};
 
-		for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+		for (i = 0; i < ARRAY_SIZE(program_seq); i++)
 			outb_p(program_seq[i].value, base_addr +
 				program_seq[i].offset);
 
@@ -471,12 +466,12 @@
 
 	dev->base_addr = base_addr;
 
-	for(i = 0; i < ETHER_ADDR_LEN; i++) {
-		printk(" %2.2x", SA_prom[i]);
+	for(i = 0; i < ETHER_ADDR_LEN; i++)
 		dev->dev_addr[i] = SA_prom[i];
-	}
 
-	printk("\n%s: %s found at %#x, using IRQ %d.\n",
+	printk(" %s\n", print_mac(mac, dev->dev_addr));
+
+	printk("%s: %s found at %#x, using IRQ %d.\n",
 			dev->name, name, base_addr, dev->irq);
 
 	mca_set_adapter_procfn(slot, (MCA_ProcFn) ne2_procinfo, dev);
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index cfdeaf7..b569c90 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -212,6 +212,7 @@
 	static unsigned int fnd_cnt;
 	long ioaddr;
 	int flags = pci_clone_list[chip_idx].flags;
+	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -265,7 +266,6 @@
 		dev_err(&pdev->dev, "cannot allocate ethernet device\n");
 		goto err_out_free_res;
 	}
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	/* Reset card. Who knows what dain-bramaged state it was left in. */
@@ -308,7 +308,7 @@
 			{0x00,	EN0_RSARHI},
 			{E8390_RREAD+E8390_START, E8390_CMD},
 		};
-		for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+		for (i = 0; i < ARRAY_SIZE(program_seq); i++)
 			outb(program_seq[i].value, ioaddr + program_seq[i].offset);
 
 	}
@@ -366,12 +366,12 @@
 	if (i)
 		goto err_out_free_netdev;
 
-	printk("%s: %s found at %#lx, IRQ %d, ",
-		   dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq);
-	for(i = 0; i < 6; i++) {
-		printk("%2.2X%s", SA_prom[i], i == 5 ? ".\n": ":");
+	for(i = 0; i < 6; i++)
 		dev->dev_addr[i] = SA_prom[i];
-	}
+	printk("%s: %s found at %#lx, IRQ %d, %s.\n",
+	       dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq,
+	       print_mac(mac, dev->dev_addr));
+
 	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
 
 	return 0;
@@ -636,9 +636,6 @@
 
 static const struct ethtool_ops ne2k_pci_ethtool_ops = {
 	.get_drvinfo		= ne2k_pci_get_drvinfo,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.get_sg			= ethtool_op_get_sg,
-	.get_perm_addr		= ethtool_op_get_perm_addr,
 };
 
 static void __devexit ne2k_pci_remove_one (struct pci_dev *pdev)
diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c
index 1a6fed7..425043a 100644
--- a/drivers/net/ne3210.c
+++ b/drivers/net/ne3210.c
@@ -99,6 +99,7 @@
 	int i, retval, port_index;
 	struct eisa_device *edev = to_eisa_device (device);
 	struct net_device *dev;
+	DECLARE_MAC_BUF(mac);
 
 	/* Allocate dev->priv and fill in 8390 specific dev fields. */
 	if (!(dev = alloc_ei_netdev ())) {
@@ -106,7 +107,6 @@
 		return -ENOMEM;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, device);
 	device->driver_data = dev;
 	ioaddr = edev->base_addr;
@@ -128,17 +128,15 @@
 		inb(ioaddr + NE3210_CFG1), inb(ioaddr + NE3210_CFG2));
 #endif
 
-
 	port_index = inb(ioaddr + NE3210_CFG2) >> 6;
-	printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr:",
-		edev->slot, ifmap[port_index]);
 	for(i = 0; i < ETHER_ADDR_LEN; i++)
-		printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i)));
-
+		dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i);
+	printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %s.\n",
+		edev->slot, ifmap[port_index], print_mac(mac, dev->dev_addr));
 
 	/* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
 	dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07];
-	printk(".\nne3210.c: using IRQ %d, ", dev->irq);
+	printk("ne3210.c: using IRQ %d, ", dev->irq);
 
 	retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
 	if (retval) {
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 69233f6..5ffbb88 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -35,95 +35,780 @@
  ****************************************************************/
 
 #include <linux/mm.h>
-#include <linux/tty.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/console.h>
-#include <linux/tty_driver.h>
 #include <linux/moduleparam.h>
 #include <linux/string.h>
-#include <linux/sysrq.h>
-#include <linux/smp.h>
 #include <linux/netpoll.h>
+#include <linux/inet.h>
+#include <linux/configfs.h>
 
 MODULE_AUTHOR("Maintainer: Matt Mackall <mpm@selenic.com>");
 MODULE_DESCRIPTION("Console driver for network interfaces");
 MODULE_LICENSE("GPL");
 
-static char config[256];
-module_param_string(netconsole, config, 256, 0);
+#define MAX_PARAM_LENGTH	256
+#define MAX_PRINT_CHUNK		1000
+
+static char config[MAX_PARAM_LENGTH];
+module_param_string(netconsole, config, MAX_PARAM_LENGTH, 0);
 MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@<tgt-ip>/[tgt-macaddr]\n");
 
-static struct netpoll np = {
-	.name = "netconsole",
-	.dev_name = "eth0",
-	.local_port = 6665,
-	.remote_port = 6666,
-	.remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
-};
-static int configured = 0;
+#ifndef	MODULE
+static int __init option_setup(char *opt)
+{
+	strlcpy(config, opt, MAX_PARAM_LENGTH);
+	return 1;
+}
+__setup("netconsole=", option_setup);
+#endif	/* MODULE */
 
-#define MAX_PRINT_CHUNK 1000
+/* Linked list of all configured targets */
+static LIST_HEAD(target_list);
+
+/* This needs to be a spinlock because write_msg() cannot sleep */
+static DEFINE_SPINLOCK(target_list_lock);
+
+/**
+ * struct netconsole_target - Represents a configured netconsole target.
+ * @list:	Links this target into the target_list.
+ * @item:	Links us into the configfs subsystem hierarchy.
+ * @enabled:	On / off knob to enable / disable target.
+ *		Visible from userspace (read-write).
+ *		We maintain a strict 1:1 correspondence between this and
+ *		whether the corresponding netpoll is active or inactive.
+ *		Also, other parameters of a target may be modified at
+ *		runtime only when it is disabled (enabled == 0).
+ * @np:		The netpoll structure for this target.
+ *		Contains the other userspace visible parameters:
+ *		dev_name	(read-write)
+ *		local_port	(read-write)
+ *		remote_port	(read-write)
+ *		local_ip	(read-write)
+ *		remote_ip	(read-write)
+ *		local_mac	(read-only)
+ *		remote_mac	(read-write)
+ */
+struct netconsole_target {
+	struct list_head	list;
+#ifdef	CONFIG_NETCONSOLE_DYNAMIC
+	struct config_item	item;
+#endif
+	int			enabled;
+	struct netpoll		np;
+};
+
+#ifdef	CONFIG_NETCONSOLE_DYNAMIC
+
+static struct configfs_subsystem netconsole_subsys;
+
+static int __init dynamic_netconsole_init(void)
+{
+	config_group_init(&netconsole_subsys.su_group);
+	mutex_init(&netconsole_subsys.su_mutex);
+	return configfs_register_subsystem(&netconsole_subsys);
+}
+
+static void __exit dynamic_netconsole_exit(void)
+{
+	configfs_unregister_subsystem(&netconsole_subsys);
+}
+
+/*
+ * Targets that were created by parsing the boot/module option string
+ * do not exist in the configfs hierarchy (and have NULL names) and will
+ * never go away, so make these a no-op for them.
+ */
+static void netconsole_target_get(struct netconsole_target *nt)
+{
+	if (config_item_name(&nt->item))
+		config_item_get(&nt->item);
+}
+
+static void netconsole_target_put(struct netconsole_target *nt)
+{
+	if (config_item_name(&nt->item))
+		config_item_put(&nt->item);
+}
+
+#else	/* !CONFIG_NETCONSOLE_DYNAMIC */
+
+static int __init dynamic_netconsole_init(void)
+{
+	return 0;
+}
+
+static void __exit dynamic_netconsole_exit(void)
+{
+}
+
+/*
+ * No danger of targets going away from under us when dynamic
+ * reconfigurability is off.
+ */
+static void netconsole_target_get(struct netconsole_target *nt)
+{
+}
+
+static void netconsole_target_put(struct netconsole_target *nt)
+{
+}
+
+#endif	/* CONFIG_NETCONSOLE_DYNAMIC */
+
+/* Allocate new target (from boot/module param) and setup netpoll for it */
+static struct netconsole_target *alloc_param_target(char *target_config)
+{
+	int err = -ENOMEM;
+	struct netconsole_target *nt;
+
+	/*
+	 * Allocate and initialize with defaults.
+	 * Note that these targets get their config_item fields zeroed-out.
+	 */
+	nt = kzalloc(sizeof(*nt), GFP_KERNEL);
+	if (!nt) {
+		printk(KERN_ERR "netconsole: failed to allocate memory\n");
+		goto fail;
+	}
+
+	nt->np.name = "netconsole";
+	strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
+	nt->np.local_port = 6665;
+	nt->np.remote_port = 6666;
+	memset(nt->np.remote_mac, 0xff, ETH_ALEN);
+
+	/* Parse parameters and setup netpoll */
+	err = netpoll_parse_options(&nt->np, target_config);
+	if (err)
+		goto fail;
+
+	err = netpoll_setup(&nt->np);
+	if (err)
+		goto fail;
+
+	nt->enabled = 1;
+
+	return nt;
+
+fail:
+	kfree(nt);
+	return ERR_PTR(err);
+}
+
+/* Cleanup netpoll for given target (from boot/module param) and free it */
+static void free_param_target(struct netconsole_target *nt)
+{
+	netpoll_cleanup(&nt->np);
+	kfree(nt);
+}
+
+#ifdef	CONFIG_NETCONSOLE_DYNAMIC
+
+/*
+ * Our subsystem hierarchy is:
+ *
+ * /sys/kernel/config/netconsole/
+ *				|
+ *				<target>/
+ *				|	enabled
+ *				|	dev_name
+ *				|	local_port
+ *				|	remote_port
+ *				|	local_ip
+ *				|	remote_ip
+ *				|	local_mac
+ *				|	remote_mac
+ *				|
+ *				<target>/...
+ */
+
+struct netconsole_target_attr {
+	struct configfs_attribute	attr;
+	ssize_t				(*show)(struct netconsole_target *nt,
+						char *buf);
+	ssize_t				(*store)(struct netconsole_target *nt,
+						 const char *buf,
+						 size_t count);
+};
+
+static struct netconsole_target *to_target(struct config_item *item)
+{
+	return item ?
+		container_of(item, struct netconsole_target, item) :
+		NULL;
+}
+
+/*
+ * Wrapper over simple_strtol (base 10) with sanity and range checking.
+ * We return (signed) long only because we may want to return errors.
+ * Do not use this to convert numbers that are allowed to be negative.
+ */
+static long strtol10_check_range(const char *cp, long min, long max)
+{
+	long ret;
+	char *p = (char *) cp;
+
+	WARN_ON(min < 0);
+	WARN_ON(max < min);
+
+	ret = simple_strtol(p, &p, 10);
+
+	if (*p && (*p != '\n')) {
+		printk(KERN_ERR "netconsole: invalid input\n");
+		return -EINVAL;
+	}
+	if ((ret < min) || (ret > max)) {
+		printk(KERN_ERR "netconsole: input %ld must be between "
+				"%ld and %ld\n", ret, min, max);
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+/*
+ * Attribute operations for netconsole_target.
+ */
+
+static ssize_t show_enabled(struct netconsole_target *nt, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", nt->enabled);
+}
+
+static ssize_t show_dev_name(struct netconsole_target *nt, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", nt->np.dev_name);
+}
+
+static ssize_t show_local_port(struct netconsole_target *nt, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.local_port);
+}
+
+static ssize_t show_remote_port(struct netconsole_target *nt, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.remote_port);
+}
+
+static ssize_t show_local_ip(struct netconsole_target *nt, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n",
+			HIPQUAD(nt->np.local_ip));
+}
+
+static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n",
+			HIPQUAD(nt->np.remote_ip));
+}
+
+static ssize_t show_local_mac(struct netconsole_target *nt, char *buf)
+{
+	DECLARE_MAC_BUF(mac);
+	return snprintf(buf, PAGE_SIZE, "%s\n",
+			print_mac(mac, nt->np.local_mac));
+}
+
+static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf)
+{
+	DECLARE_MAC_BUF(mac);
+	return snprintf(buf, PAGE_SIZE, "%s\n",
+			print_mac(mac, nt->np.remote_mac));
+}
+
+/*
+ * This one is special -- targets created through the configfs interface
+ * are not enabled (and the corresponding netpoll activated) by default.
+ * The user is expected to set the desired parameters first (which
+ * would enable him to dynamically add new netpoll targets for new
+ * network interfaces as and when they come up).
+ */
+static ssize_t store_enabled(struct netconsole_target *nt,
+			     const char *buf,
+			     size_t count)
+{
+	int err;
+	long enabled;
+
+	enabled = strtol10_check_range(buf, 0, 1);
+	if (enabled < 0)
+		return enabled;
+
+	if (enabled) {	/* 1 */
+
+		/*
+		 * Skip netpoll_parse_options() -- all the attributes are
+		 * already configured via configfs. Just print them out.
+		 */
+		netpoll_print_options(&nt->np);
+
+		err = netpoll_setup(&nt->np);
+		if (err)
+			return err;
+
+		printk(KERN_INFO "netconsole: network logging started\n");
+
+	} else {	/* 0 */
+		netpoll_cleanup(&nt->np);
+	}
+
+	nt->enabled = enabled;
+
+	return strnlen(buf, count);
+}
+
+static ssize_t store_dev_name(struct netconsole_target *nt,
+			      const char *buf,
+			      size_t count)
+{
+	size_t len;
+
+	if (nt->enabled) {
+		printk(KERN_ERR "netconsole: target (%s) is enabled, "
+				"disable to update parameters\n",
+				config_item_name(&nt->item));
+		return -EINVAL;
+	}
+
+	strlcpy(nt->np.dev_name, buf, IFNAMSIZ);
+
+	/* Get rid of possible trailing newline from echo(1) */
+	len = strnlen(nt->np.dev_name, IFNAMSIZ);
+	if (nt->np.dev_name[len - 1] == '\n')
+		nt->np.dev_name[len - 1] = '\0';
+
+	return strnlen(buf, count);
+}
+
+static ssize_t store_local_port(struct netconsole_target *nt,
+				const char *buf,
+				size_t count)
+{
+	long local_port;
+#define __U16_MAX	((__u16) ~0U)
+
+	if (nt->enabled) {
+		printk(KERN_ERR "netconsole: target (%s) is enabled, "
+				"disable to update parameters\n",
+				config_item_name(&nt->item));
+		return -EINVAL;
+	}
+
+	local_port = strtol10_check_range(buf, 0, __U16_MAX);
+	if (local_port < 0)
+		return local_port;
+
+	nt->np.local_port = local_port;
+
+	return strnlen(buf, count);
+}
+
+static ssize_t store_remote_port(struct netconsole_target *nt,
+				 const char *buf,
+				 size_t count)
+{
+	long remote_port;
+#define __U16_MAX	((__u16) ~0U)
+
+	if (nt->enabled) {
+		printk(KERN_ERR "netconsole: target (%s) is enabled, "
+				"disable to update parameters\n",
+				config_item_name(&nt->item));
+		return -EINVAL;
+	}
+
+	remote_port = strtol10_check_range(buf, 0, __U16_MAX);
+	if (remote_port < 0)
+		return remote_port;
+
+	nt->np.remote_port = remote_port;
+
+	return strnlen(buf, count);
+}
+
+static ssize_t store_local_ip(struct netconsole_target *nt,
+			      const char *buf,
+			      size_t count)
+{
+	if (nt->enabled) {
+		printk(KERN_ERR "netconsole: target (%s) is enabled, "
+				"disable to update parameters\n",
+				config_item_name(&nt->item));
+		return -EINVAL;
+	}
+
+	nt->np.local_ip = ntohl(in_aton(buf));
+
+	return strnlen(buf, count);
+}
+
+static ssize_t store_remote_ip(struct netconsole_target *nt,
+			       const char *buf,
+			       size_t count)
+{
+	if (nt->enabled) {
+		printk(KERN_ERR "netconsole: target (%s) is enabled, "
+				"disable to update parameters\n",
+				config_item_name(&nt->item));
+		return -EINVAL;
+	}
+
+	nt->np.remote_ip = ntohl(in_aton(buf));
+
+	return strnlen(buf, count);
+}
+
+static ssize_t store_remote_mac(struct netconsole_target *nt,
+				const char *buf,
+				size_t count)
+{
+	u8 remote_mac[ETH_ALEN];
+	char *p = (char *) buf;
+	int i;
+
+	if (nt->enabled) {
+		printk(KERN_ERR "netconsole: target (%s) is enabled, "
+				"disable to update parameters\n",
+				config_item_name(&nt->item));
+		return -EINVAL;
+	}
+
+	for (i = 0; i < ETH_ALEN - 1; i++) {
+		remote_mac[i] = simple_strtoul(p, &p, 16);
+		if (*p != ':')
+			goto invalid;
+		p++;
+	}
+	remote_mac[ETH_ALEN - 1] = simple_strtoul(p, &p, 16);
+	if (*p && (*p != '\n'))
+		goto invalid;
+
+	memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);
+
+	return strnlen(buf, count);
+
+invalid:
+	printk(KERN_ERR "netconsole: invalid input\n");
+	return -EINVAL;
+}
+
+/*
+ * Attribute definitions for netconsole_target.
+ */
+
+#define NETCONSOLE_TARGET_ATTR_RO(_name)				\
+static struct netconsole_target_attr netconsole_target_##_name =	\
+	__CONFIGFS_ATTR(_name, S_IRUGO, show_##_name, NULL)
+
+#define NETCONSOLE_TARGET_ATTR_RW(_name)				\
+static struct netconsole_target_attr netconsole_target_##_name =	\
+	__CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, show_##_name, store_##_name)
+
+NETCONSOLE_TARGET_ATTR_RW(enabled);
+NETCONSOLE_TARGET_ATTR_RW(dev_name);
+NETCONSOLE_TARGET_ATTR_RW(local_port);
+NETCONSOLE_TARGET_ATTR_RW(remote_port);
+NETCONSOLE_TARGET_ATTR_RW(local_ip);
+NETCONSOLE_TARGET_ATTR_RW(remote_ip);
+NETCONSOLE_TARGET_ATTR_RO(local_mac);
+NETCONSOLE_TARGET_ATTR_RW(remote_mac);
+
+static struct configfs_attribute *netconsole_target_attrs[] = {
+	&netconsole_target_enabled.attr,
+	&netconsole_target_dev_name.attr,
+	&netconsole_target_local_port.attr,
+	&netconsole_target_remote_port.attr,
+	&netconsole_target_local_ip.attr,
+	&netconsole_target_remote_ip.attr,
+	&netconsole_target_local_mac.attr,
+	&netconsole_target_remote_mac.attr,
+	NULL,
+};
+
+/*
+ * Item operations and type for netconsole_target.
+ */
+
+static void netconsole_target_release(struct config_item *item)
+{
+	kfree(to_target(item));
+}
+
+static ssize_t netconsole_target_attr_show(struct config_item *item,
+					   struct configfs_attribute *attr,
+					   char *buf)
+{
+	ssize_t ret = -EINVAL;
+	struct netconsole_target *nt = to_target(item);
+	struct netconsole_target_attr *na =
+		container_of(attr, struct netconsole_target_attr, attr);
+
+	if (na->show)
+		ret = na->show(nt, buf);
+
+	return ret;
+}
+
+static ssize_t netconsole_target_attr_store(struct config_item *item,
+					    struct configfs_attribute *attr,
+					    const char *buf,
+					    size_t count)
+{
+	ssize_t ret = -EINVAL;
+	struct netconsole_target *nt = to_target(item);
+	struct netconsole_target_attr *na =
+		container_of(attr, struct netconsole_target_attr, attr);
+
+	if (na->store)
+		ret = na->store(nt, buf, count);
+
+	return ret;
+}
+
+static struct configfs_item_operations netconsole_target_item_ops = {
+	.release		= netconsole_target_release,
+	.show_attribute		= netconsole_target_attr_show,
+	.store_attribute	= netconsole_target_attr_store,
+};
+
+static struct config_item_type netconsole_target_type = {
+	.ct_attrs		= netconsole_target_attrs,
+	.ct_item_ops		= &netconsole_target_item_ops,
+	.ct_owner		= THIS_MODULE,
+};
+
+/*
+ * Group operations and type for netconsole_subsys.
+ */
+
+static struct config_item *make_netconsole_target(struct config_group *group,
+						  const char *name)
+{
+	unsigned long flags;
+	struct netconsole_target *nt;
+
+	/*
+	 * Allocate and initialize with defaults.
+	 * Target is disabled at creation (enabled == 0).
+	 */
+	nt = kzalloc(sizeof(*nt), GFP_KERNEL);
+	if (!nt) {
+		printk(KERN_ERR "netconsole: failed to allocate memory\n");
+		return NULL;
+	}
+
+	nt->np.name = "netconsole";
+	strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ);
+	nt->np.local_port = 6665;
+	nt->np.remote_port = 6666;
+	memset(nt->np.remote_mac, 0xff, ETH_ALEN);
+
+	/* Initialize the config_item member */
+	config_item_init_type_name(&nt->item, name, &netconsole_target_type);
+
+	/* Adding, but it is disabled */
+	spin_lock_irqsave(&target_list_lock, flags);
+	list_add(&nt->list, &target_list);
+	spin_unlock_irqrestore(&target_list_lock, flags);
+
+	return &nt->item;
+}
+
+static void drop_netconsole_target(struct config_group *group,
+				   struct config_item *item)
+{
+	unsigned long flags;
+	struct netconsole_target *nt = to_target(item);
+
+	spin_lock_irqsave(&target_list_lock, flags);
+	list_del(&nt->list);
+	spin_unlock_irqrestore(&target_list_lock, flags);
+
+	/*
+	 * The target may have never been enabled, or was manually disabled
+	 * before being removed so netpoll may have already been cleaned up.
+	 */
+	if (nt->enabled)
+		netpoll_cleanup(&nt->np);
+
+	config_item_put(&nt->item);
+}
+
+static struct configfs_group_operations netconsole_subsys_group_ops = {
+	.make_item	= make_netconsole_target,
+	.drop_item	= drop_netconsole_target,
+};
+
+static struct config_item_type netconsole_subsys_type = {
+	.ct_group_ops	= &netconsole_subsys_group_ops,
+	.ct_owner	= THIS_MODULE,
+};
+
+/* The netconsole configfs subsystem */
+static struct configfs_subsystem netconsole_subsys = {
+	.su_group	= {
+		.cg_item	= {
+			.ci_namebuf	= "netconsole",
+			.ci_type	= &netconsole_subsys_type,
+		},
+	},
+};
+
+#endif	/* CONFIG_NETCONSOLE_DYNAMIC */
+
+/* Handle network interface device notifications */
+static int netconsole_netdev_event(struct notifier_block *this,
+				   unsigned long event,
+				   void *ptr)
+{
+	unsigned long flags;
+	struct netconsole_target *nt;
+	struct net_device *dev = ptr;
+
+	if (!(event == NETDEV_CHANGEADDR || event == NETDEV_CHANGENAME))
+		goto done;
+
+	spin_lock_irqsave(&target_list_lock, flags);
+	list_for_each_entry(nt, &target_list, list) {
+		netconsole_target_get(nt);
+		if (nt->np.dev == dev) {
+			switch (event) {
+			case NETDEV_CHANGEADDR:
+				memcpy(nt->np.local_mac, dev->dev_addr, ETH_ALEN);
+				break;
+
+			case NETDEV_CHANGENAME:
+				strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ);
+				break;
+			}
+		}
+		netconsole_target_put(nt);
+	}
+	spin_unlock_irqrestore(&target_list_lock, flags);
+
+done:
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block netconsole_netdev_notifier = {
+	.notifier_call  = netconsole_netdev_event,
+};
 
 static void write_msg(struct console *con, const char *msg, unsigned int len)
 {
 	int frag, left;
 	unsigned long flags;
+	struct netconsole_target *nt;
+	const char *tmp;
 
-	if (!np.dev)
+	/* Avoid taking lock and disabling interrupts unnecessarily */
+	if (list_empty(&target_list))
 		return;
 
-	local_irq_save(flags);
-
-	for(left = len; left; ) {
-		frag = min(left, MAX_PRINT_CHUNK);
-		netpoll_send_udp(&np, msg, frag);
-		msg += frag;
-		left -= frag;
+	spin_lock_irqsave(&target_list_lock, flags);
+	list_for_each_entry(nt, &target_list, list) {
+		netconsole_target_get(nt);
+		if (nt->enabled && netif_running(nt->np.dev)) {
+			/*
+			 * We nest this inside the for-each-target loop above
+			 * so that we're able to get as much logging out to
+			 * at least one target if we die inside here, instead
+			 * of unnecessarily keeping all targets in lock-step.
+			 */
+			tmp = msg;
+			for (left = len; left;) {
+				frag = min(left, MAX_PRINT_CHUNK);
+				netpoll_send_udp(&nt->np, tmp, frag);
+				tmp += frag;
+				left -= frag;
+			}
+		}
+		netconsole_target_put(nt);
 	}
-
-	local_irq_restore(flags);
+	spin_unlock_irqrestore(&target_list_lock, flags);
 }
 
 static struct console netconsole = {
-	.name = "netcon",
-	.flags = CON_ENABLED | CON_PRINTBUFFER,
-	.write = write_msg
+	.name	= "netcon",
+	.flags	= CON_ENABLED | CON_PRINTBUFFER,
+	.write	= write_msg,
 };
 
-static int option_setup(char *opt)
-{
-	configured = !netpoll_parse_options(&np, opt);
-	return 1;
-}
-
-__setup("netconsole=", option_setup);
-
-static int init_netconsole(void)
+static int __init init_netconsole(void)
 {
 	int err;
+	struct netconsole_target *nt, *tmp;
+	unsigned long flags;
+	char *target_config;
+	char *input = config;
 
-	if(strlen(config))
-		option_setup(config);
-
-	if(!configured) {
-		printk("netconsole: not configured, aborting\n");
-		return 0;
+	if (strnlen(input, MAX_PARAM_LENGTH)) {
+		while ((target_config = strsep(&input, ";"))) {
+			nt = alloc_param_target(target_config);
+			if (IS_ERR(nt)) {
+				err = PTR_ERR(nt);
+				goto fail;
+			}
+			spin_lock_irqsave(&target_list_lock, flags);
+			list_add(&nt->list, &target_list);
+			spin_unlock_irqrestore(&target_list_lock, flags);
+		}
 	}
 
-	err = netpoll_setup(&np);
+	err = register_netdevice_notifier(&netconsole_netdev_notifier);
 	if (err)
-		return err;
+		goto fail;
+
+	err = dynamic_netconsole_init();
+	if (err)
+		goto undonotifier;
 
 	register_console(&netconsole);
 	printk(KERN_INFO "netconsole: network logging started\n");
-	return 0;
+
+	return err;
+
+undonotifier:
+	unregister_netdevice_notifier(&netconsole_netdev_notifier);
+
+fail:
+	printk(KERN_ERR "netconsole: cleaning up\n");
+
+	/*
+	 * Remove all targets and destroy them (only targets created
+	 * from the boot/module option exist here). Skipping the list
+	 * lock is safe here, and netpoll_cleanup() will sleep.
+	 */
+	list_for_each_entry_safe(nt, tmp, &target_list, list) {
+		list_del(&nt->list);
+		free_param_target(nt);
+	}
+
+	return err;
 }
 
-static void cleanup_netconsole(void)
+static void __exit cleanup_netconsole(void)
 {
+	struct netconsole_target *nt, *tmp;
+
 	unregister_console(&netconsole);
-	netpoll_cleanup(&np);
+	dynamic_netconsole_exit();
+	unregister_netdevice_notifier(&netconsole_netdev_notifier);
+
+	/*
+	 * Targets created via configfs pin references on our module
+	 * and would first be rmdir(2)'ed from userspace. We reach
+	 * here only when they are already destroyed, and only those
+	 * created from the boot/module option are left, so remove and
+	 * destroy them. Skipping the list lock is safe here, and
+	 * netpoll_cleanup() will sleep.
+	 */
+	list_for_each_entry_safe(nt, tmp, &target_list, list) {
+		list_del(&nt->list);
+		free_param_target(nt);
+	}
 }
 
 module_init(init_netconsole);
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c
index 2b8da0a..eb0aff7 100644
--- a/drivers/net/netx-eth.c
+++ b/drivers/net/netx-eth.c
@@ -97,7 +97,6 @@
 struct netx_eth_priv {
 	void                    __iomem *sram_base, *xpec_base, *xmac_base;
 	int                     id;
-	struct net_device_stats stats;
 	struct mii_if_info      mii;
 	u32                     msg_enable;
 	struct xc               *xc;
@@ -129,8 +128,8 @@
 	           FIFO_PTR_FRAMELEN(len));
 
 	ndev->trans_start = jiffies;
-	priv->stats.tx_packets++;
-	priv->stats.tx_bytes += skb->len;
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
 
 	netif_stop_queue(ndev);
 	spin_unlock_irq(&priv->lock);
@@ -156,7 +155,7 @@
 	if (unlikely(skb == NULL)) {
 		printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
 			ndev->name);
-		priv->stats.rx_dropped++;
+		dev->stats.rx_dropped++;
 		return;
 	}
 
@@ -170,8 +169,8 @@
 	ndev->last_rx = jiffies;
 	skb->protocol = eth_type_trans(skb, ndev);
 	netif_rx(skb);
-	priv->stats.rx_packets++;
-	priv->stats.rx_bytes += len;
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += len;
 }
 
 static irqreturn_t
@@ -210,12 +209,6 @@
 	return IRQ_HANDLED;
 }
 
-static struct net_device_stats *netx_eth_query_statistics(struct net_device *ndev)
-{
-	struct netx_eth_priv *priv = netdev_priv(ndev);
-	return &priv->stats;
-}
-
 static int netx_eth_open(struct net_device *ndev)
 {
 	struct netx_eth_priv *priv = netdev_priv(ndev);
@@ -323,7 +316,6 @@
 	ndev->hard_start_xmit = netx_eth_hard_start_xmit;
 	ndev->tx_timeout = netx_eth_timeout;
 	ndev->watchdog_timeo = msecs_to_jiffies(5000);
-	ndev->get_stats = netx_eth_query_statistics;
 	ndev->set_multicast_list = netx_eth_set_multicast_list;
 
 	priv->msg_enable       = NETIF_MSG_LINK;
@@ -390,7 +382,6 @@
 		ret = -ENOMEM;
 		goto exit;
 	}
-	SET_MODULE_OWNER(ndev);
 	SET_NETDEV_DEV(ndev, &pdev->dev);
 
 	platform_set_drvdata(pdev, ndev);
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index 325269d..fbc2553 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -880,6 +880,7 @@
 	struct netxen_adapter *master;
 	struct net_device *netdev;
 	struct pci_dev *pdev;
+	struct napi_struct napi;
 	struct net_device_stats net_stats;
 	unsigned char mac_addr[ETH_ALEN];
 	int mtu;
@@ -918,7 +919,7 @@
 	u16 link_duplex;
 	u16 state;
 	u16 link_autoneg;
-	int rcsum;
+	int rx_csum;
 	int status;
 	spinlock_t stats_lock;
 
@@ -1118,7 +1119,7 @@
 	{NETXEN_BRDTYPE_P2_SB31_2G, 2, "Dual Gb"},
 };
 
-#define NUM_SUPPORTED_BOARDS (sizeof(netxen_boards)/sizeof(struct netxen_brdinfo))
+#define NUM_SUPPORTED_BOARDS ARRAY_SIZE(netxen_boards)
 
 static inline void get_brd_port_by_type(u32 type, int *ports)
 {
@@ -1179,8 +1180,7 @@
 	    NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), &ctrl, 4))
 		printk(KERN_ERR "failed to read dma watchdog status\n");
 
-	return ((netxen_get_dma_watchdog_enabled(ctrl) == 0) &&
-		(netxen_get_dma_watchdog_disabled(ctrl) == 0));
+	return (netxen_get_dma_watchdog_enabled(ctrl) == 0);
 }
 
 static inline int
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index 0175f6c..cfb847b0 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -115,8 +115,6 @@
 	sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build);
 
 	strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32);
-	drvinfo->n_stats = NETXEN_NIC_STATS_LEN;
-	drvinfo->testinfo_len = NETXEN_NIC_TEST_LEN;
 	drvinfo->regdump_len = NETXEN_NIC_REGS_LEN;
 	drvinfo->eedump_len = netxen_nic_get_eeprom_len(dev);
 }
@@ -518,17 +516,17 @@
 	ring->rx_jumbo_pending = 0;
 	for (i = 0; i < MAX_RCV_CTX; ++i) {
 		ring->rx_pending += adapter->recv_ctx[i].
-		    rcv_desc[RCV_DESC_NORMAL_CTXID].rcv_pending;
+		    rcv_desc[RCV_DESC_NORMAL_CTXID].max_rx_desc_count;
 		ring->rx_jumbo_pending += adapter->recv_ctx[i].
-		    rcv_desc[RCV_DESC_JUMBO_CTXID].rcv_pending;
+		    rcv_desc[RCV_DESC_JUMBO_CTXID].max_rx_desc_count;
 	}
+	ring->tx_pending = adapter->max_tx_desc_count;
 
-	ring->rx_max_pending = adapter->max_rx_desc_count;
-	ring->tx_max_pending = adapter->max_tx_desc_count;
-	ring->rx_jumbo_max_pending = adapter->max_jumbo_rx_desc_count;
+	ring->rx_max_pending = MAX_RCV_DESCRIPTORS;
+	ring->tx_max_pending = MAX_CMD_DESCRIPTORS_HOST;
+	ring->rx_jumbo_max_pending = MAX_JUMBO_RCV_DESCRIPTORS;
 	ring->rx_mini_max_pending = 0;
 	ring->rx_mini_pending = 0;
-	ring->rx_jumbo_pending = 0;
 }
 
 static void
@@ -672,9 +670,16 @@
 	return 0;
 }
 
-static int netxen_nic_diag_test_count(struct net_device *dev)
+static int netxen_get_sset_count(struct net_device *dev, int sset)
 {
-	return NETXEN_NIC_TEST_LEN;
+	switch (sset) {
+	case ETH_SS_TEST:
+		return NETXEN_NIC_TEST_LEN;
+	case ETH_SS_STATS:
+		return NETXEN_NIC_STATS_LEN;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void
@@ -709,11 +714,6 @@
 	}
 }
 
-static int netxen_nic_get_stats_count(struct net_device *dev)
-{
-	return NETXEN_NIC_STATS_LEN;
-}
-
 static void
 netxen_nic_get_ethtool_stats(struct net_device *dev,
 			     struct ethtool_stats *stats, u64 * data)
@@ -731,6 +731,19 @@
 	}
 }
 
+static u32 netxen_nic_get_rx_csum(struct net_device *dev)
+{
+	struct netxen_adapter *adapter = netdev_priv(dev);
+	return adapter->rx_csum;
+}
+
+static int netxen_nic_set_rx_csum(struct net_device *dev, u32 data)
+{
+	struct netxen_adapter *adapter = netdev_priv(dev);
+	adapter->rx_csum = !!data;
+	return 0;
+}
+
 struct ethtool_ops netxen_nic_ethtool_ops = {
 	.get_settings = netxen_nic_get_settings,
 	.set_settings = netxen_nic_set_settings,
@@ -744,16 +757,13 @@
 	.get_ringparam = netxen_nic_get_ringparam,
 	.get_pauseparam = netxen_nic_get_pauseparam,
 	.set_pauseparam = netxen_nic_set_pauseparam,
-	.get_tx_csum = ethtool_op_get_tx_csum,
 	.set_tx_csum = ethtool_op_set_tx_csum,
-	.get_sg = ethtool_op_get_sg,
 	.set_sg = ethtool_op_set_sg,
-	.get_tso = ethtool_op_get_tso,
 	.set_tso = ethtool_op_set_tso,
-	.self_test_count = netxen_nic_diag_test_count,
 	.self_test = netxen_nic_diag_test,
 	.get_strings = netxen_nic_get_strings,
-	.get_stats_count = netxen_nic_get_stats_count,
 	.get_ethtool_stats = netxen_nic_get_ethtool_stats,
-	.get_perm_addr = ethtool_op_get_perm_addr,
+	.get_sset_count = netxen_get_sset_count,
+	.get_rx_csum = netxen_nic_get_rx_csum,
+	.set_rx_csum = netxen_nic_set_rx_csum,
 };
diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h
index 3276866..d72f8f8 100644
--- a/drivers/net/netxen/netxen_nic_hdr.h
+++ b/drivers/net/netxen/netxen_nic_hdr.h
@@ -649,9 +649,11 @@
 #define PCIX_INT_VECTOR		(0x10100)
 #define PCIX_INT_MASK		(0x10104)
 
-#define PCIX_MN_WINDOW		(0x10200)
+#define PCIX_MN_WINDOW_F0	(0x10200)
+#define PCIX_MN_WINDOW(_f)	(PCIX_MN_WINDOW_F0 + (0x20 * (_f)))
 #define PCIX_MS_WINDOW		(0x10204)
-#define PCIX_SN_WINDOW		(0x10208)
+#define PCIX_SN_WINDOW_F0	(0x10208)
+#define PCIX_SN_WINDOW(_f)	(PCIX_SN_WINDOW_F0 + (0x20 * (_f)))
 #define PCIX_CRB_WINDOW		(0x10210)
 #define PCIX_CRB_WINDOW_F0	(0x10210)
 #define PCIX_CRB_WINDOW_F1	(0x10230)
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index aac1542..2c19b8d 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -569,7 +569,7 @@
 	/* if the flash size less than 4Mb, make huge war cry and die */
 	for (j = 1; j < 4; j++) {
 		addr = j * NETXEN_NIC_WINDOW_MARGIN;
-		for (i = 0; i < (sizeof(locs) / sizeof(locs[0])); i++) {
+		for (i = 0; i < ARRAY_SIZE(locs); i++) {
 			if (netxen_rom_fast_read(adapter, locs[i], &val01) == 0
 			    && netxen_rom_fast_read(adapter, (addr + locs[i]),
 						    &val02) == 0) {
@@ -904,11 +904,11 @@
 			ddr_mn_window = window;
 			writel(window, PCI_OFFSET_SECOND_RANGE(adapter,
 							       NETXEN_PCIX_PH_REG
-							       (PCIX_MN_WINDOW)));
+							       (PCIX_MN_WINDOW(adapter->ahw.pci_func))));
 			/* MUST make sure window is set before we forge on... */
 			readl(PCI_OFFSET_SECOND_RANGE(adapter,
 						      NETXEN_PCIX_PH_REG
-						      (PCIX_MN_WINDOW)));
+						      (PCIX_MN_WINDOW(adapter->ahw.pci_func))));
 		}
 		addr -= (window * NETXEN_WINDOW_ONE);
 		addr += NETXEN_PCI_DDR_NET;
@@ -929,11 +929,11 @@
 			writel((window << 22),
 			       PCI_OFFSET_SECOND_RANGE(adapter,
 						       NETXEN_PCIX_PH_REG
-						       (PCIX_SN_WINDOW)));
+						       (PCIX_SN_WINDOW(adapter->ahw.pci_func))));
 			/* MUST make sure window is set before we forge on... */
 			readl(PCI_OFFSET_SECOND_RANGE(adapter,
 						      NETXEN_PCIX_PH_REG
-						      (PCIX_SN_WINDOW)));
+						      (PCIX_SN_WINDOW(adapter->ahw.pci_func))));
 		}
 		addr -= (window * 0x400000);
 		addr += NETXEN_PCI_QDR_NET;
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 1811bcb..3758926 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -1118,10 +1118,13 @@
 
 	skb = (struct sk_buff *)buffer->skb;
 
-	if (likely(netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) {
+	if (likely(adapter->rx_csum &&
+				netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) {
 		adapter->stats.csummed++;
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
-	}
+	} else
+		skb->ip_summed = CHECKSUM_NONE;
+
 	skb->dev = netdev;
 	if (desc_ctx == RCV_DESC_LRO_CTXID) {
 		/* True length was only available on the last pkt */
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index b703ccf..2a1d6d7 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -39,14 +39,13 @@
 #include "netxen_nic_phan_reg.h"
 
 #include <linux/dma-mapping.h>
-#include <linux/vmalloc.h>
 #include <net/ip.h>
 
 MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(NETXEN_NIC_LINUX_VERSIONID);
 
-char netxen_nic_driver_name[] = "netxen-nic";
+char netxen_nic_driver_name[] = "netxen_nic";
 static char netxen_nic_driver_string[] = "NetXen Network Driver version "
     NETXEN_NIC_LINUX_VERSIONID;
 
@@ -68,7 +67,7 @@
 static void netxen_tx_timeout_task(struct work_struct *work);
 static void netxen_watchdog(unsigned long);
 static int netxen_handle_int(struct netxen_adapter *, struct net_device *);
-static int netxen_nic_poll(struct net_device *dev, int *budget);
+static int netxen_nic_poll(struct napi_struct *napi, int budget);
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void netxen_nic_poll_controller(struct net_device *netdev);
 #endif
@@ -286,6 +285,7 @@
 	int valid_mac = 0;
 	u32 val;
 	int pci_func_id = PCI_FUNC(pdev->devfn);
+	DECLARE_MAC_BUF(mac);
 
 	printk(KERN_INFO "%s \n", netxen_nic_driver_string);
 
@@ -326,16 +326,13 @@
 		goto err_out_free_res;
 	}
 
-	SET_MODULE_OWNER(netdev);
 	SET_NETDEV_DEV(netdev, &pdev->dev);
 
 	adapter = netdev->priv;
-	memset(adapter, 0 , sizeof(struct netxen_adapter));
 
 	adapter->ahw.pdev = pdev;
 	adapter->ahw.pci_func  = pci_func_id;
 	spin_lock_init(&adapter->tx_lock);
-	spin_lock_init(&adapter->lock);
 
 	/* remap phys address */
 	mem_base = pci_resource_start(pdev, 0);	/* 0 is for BAR 0 */
@@ -403,12 +400,16 @@
 	adapter->netdev  = netdev;
 	adapter->pdev    = pdev;
 
+	netif_napi_add(netdev, &adapter->napi,
+		       netxen_nic_poll, NETXEN_NETDEV_WEIGHT);
+
 	/* this will be read from FW later */
 	adapter->intr_scheme = -1;
 
 	/* This will be reset for mezz cards  */
 	adapter->portnum = pci_func_id;
 	adapter->status   &= ~NETXEN_NETDEV_STATUS;
+	adapter->rx_csum = 1;
 
 	netdev->open		   = netxen_nic_open;
 	netdev->stop		   = netxen_nic_close;
@@ -423,8 +424,6 @@
 	netxen_nic_change_mtu(netdev, netdev->mtu);
 
 	SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
-	netdev->poll = netxen_nic_poll;
-	netdev->weight = NETXEN_NETDEV_WEIGHT;
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	netdev->poll_controller = netxen_nic_poll_controller;
 #endif
@@ -576,15 +575,9 @@
 		memcpy(netdev->perm_addr, netdev->dev_addr,
 			netdev->addr_len);
 		if (!is_valid_ether_addr(netdev->perm_addr)) {
-			printk(KERN_ERR "%s: Bad MAC address "
-				"%02x:%02x:%02x:%02x:%02x:%02x.\n",
-				netxen_nic_driver_name,
-				netdev->dev_addr[0],
-				netdev->dev_addr[1],
-				netdev->dev_addr[2],
-				netdev->dev_addr[3],
-				netdev->dev_addr[4],
-				netdev->dev_addr[5]);
+			printk(KERN_ERR "%s: Bad MAC address %s.\n",
+			       netxen_nic_driver_name,
+			       print_mac(mac, netdev->dev_addr));
 		} else {
 			if (adapter->macaddr_set)
 				adapter->macaddr_set(adapter,
@@ -747,9 +740,6 @@
 
 	netxen_nic_disable_int(adapter);
 
-	if (adapter->irq)
-		free_irq(adapter->irq, adapter);
-
 	if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
 		init_firmware_done++;
 		netxen_free_hw_resources(adapter);
@@ -773,28 +763,22 @@
 		}
 	}
 
-	if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
-		pci_disable_msi(pdev);
-
 	vfree(adapter->cmd_buf_arr);
 
-	pci_disable_device(pdev);
-
 	if (adapter->portnum == 0) {
 		if (init_firmware_done) {
-			dma_watchdog_shutdown_request(adapter);
-			msleep(100);
 			i = 100;
-			while ((dma_watchdog_shutdown_poll_result(adapter) != 1) && i) {
-				printk(KERN_INFO "dma_watchdog_shutdown_poll still in progress\n");
+			do {
+				if (dma_watchdog_shutdown_request(adapter) == 1)
+					break;
 				msleep(100);
-				i--;
-			}
+				if (dma_watchdog_shutdown_poll_result(adapter) == 1)
+					break;
+			} while (--i);
 
-			if (i == 0) {
-				printk(KERN_ERR "dma_watchdog_shutdown_request failed\n");
-				return;
-			}
+			if (i == 0)
+				printk(KERN_ERR "%s: dma_watchdog_shutdown failed\n",
+						netdev->name);
 
 			/* clear the register for future unloads/loads */
 			writel(0, NETXEN_CRB_NORMALIZE(adapter, NETXEN_CAM_RAM(0x1fc)));
@@ -803,11 +787,9 @@
 
 			/* leave the hw in the same state as reboot */
 			writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
-			if (netxen_pinit_from_rom(adapter, 0))
-				return;
+			netxen_pinit_from_rom(adapter, 0);
 			msleep(1);
-			if (netxen_load_firmware(adapter))
-				return;
+			netxen_load_firmware(adapter);
 			netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
 		}
 
@@ -816,30 +798,36 @@
 		printk(KERN_INFO "State: 0x%0x\n",
 			readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)));
 
-		dma_watchdog_shutdown_request(adapter);
-		msleep(100);
 		i = 100;
-		while ((dma_watchdog_shutdown_poll_result(adapter) != 1) && i) {
-			printk(KERN_INFO "dma_watchdog_shutdown_poll still in progress\n");
+		do {
+			if (dma_watchdog_shutdown_request(adapter) == 1)
+				break;
 			msleep(100);
-			i--;
-		}
+			if (dma_watchdog_shutdown_poll_result(adapter) == 1)
+				break;
+		} while (--i);
 
 		if (i) {
 			netxen_free_adapter_offload(adapter);
 		} else {
-			printk(KERN_ERR "failed to dma shutdown\n");
-			return;
+			printk(KERN_ERR "%s: dma_watchdog_shutdown failed\n",
+					netdev->name);
 		}
-
 	}
 
+	if (adapter->irq)
+		free_irq(adapter->irq, adapter);
+
+	if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
+		pci_disable_msi(pdev);
+
 	iounmap(adapter->ahw.db_base);
 	iounmap(adapter->ahw.pci_base0);
 	iounmap(adapter->ahw.pci_base1);
 	iounmap(adapter->ahw.pci_base2);
 
 	pci_release_regions(pdev);
+	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
 
 	free_netdev(netdev);
@@ -891,19 +879,22 @@
 	if (!adapter->driver_mismatch)
 		mod_timer(&adapter->watchdog_timer, jiffies);
 
+	napi_enable(&adapter->napi);
+
 	netxen_nic_enable_int(adapter);
 
 	/* Done here again so that even if phantom sw overwrote it,
 	 * we set it */
-	if (adapter->macaddr_set)
-		adapter->macaddr_set(adapter, netdev->dev_addr);
 	if (adapter->init_port
 	    && adapter->init_port(adapter, adapter->portnum) != 0) {
 	    del_timer_sync(&adapter->watchdog_timer);
 		printk(KERN_ERR "%s: Failed to initialize port %d\n",
 				netxen_nic_driver_name, adapter->portnum);
+		napi_disable(&adapter->napi);
 		return -EIO;
 	}
+	if (adapter->macaddr_set)
+		adapter->macaddr_set(adapter, netdev->dev_addr);
 
 	netxen_nic_set_link_parameters(adapter);
 
@@ -929,6 +920,9 @@
 
 	netif_carrier_off(netdev);
 	netif_stop_queue(netdev);
+	napi_disable(&adapter->napi);
+
+	netxen_nic_disable_int(adapter);
 
 	cmd_buff = adapter->cmd_buf_arr;
 	for (i = 0; i < adapter->max_tx_desc_count; i++) {
@@ -1226,15 +1220,12 @@
 {
 	struct netxen_adapter *adapter = 
 		container_of(work, struct netxen_adapter, tx_timeout_task);
-	unsigned long flags;
 
 	printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
 	       netxen_nic_driver_name, adapter->netdev->name);
 
-	spin_lock_irqsave(&adapter->lock, flags);
 	netxen_nic_close(adapter->netdev);
 	netxen_nic_open(adapter->netdev);
-	spin_unlock_irqrestore(&adapter->lock, flags);
 	adapter->netdev->trans_start = jiffies;
 	netif_wake_queue(adapter->netdev);
 }
@@ -1243,34 +1234,18 @@
 netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev)
 {
 	u32 ret = 0;
-	u32 our_int = 0;
 
 	DPRINTK(INFO, "Entered handle ISR\n");
 	adapter->stats.ints++;
 
-	if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
-		our_int = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
-		/* not our interrupt */
-		if ((our_int & (0x80 << adapter->portnum)) == 0)
-			return ret;
-	}
-
 	netxen_nic_disable_int(adapter);
 
-	if (adapter->intr_scheme == INTR_SCHEME_PERPORT) {
-		/* claim interrupt */
-		if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
-			writel(our_int & ~((u32)(0x80 << adapter->portnum)),
-			NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
-		}
-	}
-
 	if (netxen_nic_rx_has_work(adapter) || netxen_nic_tx_has_work(adapter)) {
-		if (netif_rx_schedule_prep(netdev)) {
+		if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
 			/*
 			 * Interrupts are already disabled.
 			 */
-			__netif_rx_schedule(netdev);
+			__netif_rx_schedule(netdev, &adapter->napi);
 		} else {
 			static unsigned int intcount = 0;
 			if ((++intcount & 0xfff) == 0xfff)
@@ -1298,6 +1273,7 @@
 {
 	struct netxen_adapter *adapter;
 	struct net_device *netdev;
+	u32 our_int = 0;
 
 	if (unlikely(!irq)) {
 		return IRQ_NONE;	/* Not our interrupt */
@@ -1305,21 +1281,35 @@
 
 	adapter = (struct netxen_adapter *)data;
 	netdev  = adapter->netdev;
-	/* process our status queue (for all 4 ports) */
+
+	if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
+		our_int = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
+		/* not our interrupt */
+		if ((our_int & (0x80 << adapter->portnum)) == 0)
+			return IRQ_NONE;
+	}
+
+	if (adapter->intr_scheme == INTR_SCHEME_PERPORT) {
+		/* claim interrupt */
+		if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
+			writel(our_int & ~((u32)(0x80 << adapter->portnum)),
+			NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR));
+		}
+	}
+
 	if (netif_running(netdev))
 		netxen_handle_int(adapter, netdev);
 
 	return IRQ_HANDLED;
 }
 
-static int netxen_nic_poll(struct net_device *netdev, int *budget)
+static int netxen_nic_poll(struct napi_struct *napi, int budget)
 {
-	struct netxen_adapter *adapter = netdev_priv(netdev);
-	int work_to_do = min(*budget, netdev->quota);
+	struct netxen_adapter *adapter = container_of(napi, struct netxen_adapter, napi);
+	struct net_device *netdev = adapter->netdev;
 	int done = 1;
 	int ctx;
-	int this_work_done;
-	int work_done = 0;
+	int work_done;
 
 	DPRINTK(INFO, "polling for %d descriptors\n", *budget);
 
@@ -1337,16 +1327,11 @@
 		 * packets are on one context, it gets only half of the quota,
 		 * and ends up not processing it.
 		 */
-		this_work_done = netxen_process_rcv_ring(adapter, ctx,
-							 work_to_do /
-							 MAX_RCV_CTX);
-		work_done += this_work_done;
+		work_done += netxen_process_rcv_ring(adapter, ctx,
+						     budget / MAX_RCV_CTX);
 	}
 
-	netdev->quota -= work_done;
-	*budget -= work_done;
-
-	if (work_done >= work_to_do && netxen_nic_rx_has_work(adapter) != 0)
+	if (work_done >= budget && netxen_nic_rx_has_work(adapter) != 0)
 		done = 0;
 
 	if (netxen_process_cmd_ring((unsigned long)adapter) == 0)
@@ -1355,11 +1340,11 @@
 	DPRINTK(INFO, "new work_done: %d work_to_do: %d\n",
 		work_done, work_to_do);
 	if (done) {
-		netif_rx_complete(netdev);
+		netif_rx_complete(netdev, napi);
 		netxen_nic_enable_int(adapter);
 	}
 
-	return !done;
+	return work_done;
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c
index 05e0577..5b9e1b3 100644
--- a/drivers/net/netxen/netxen_nic_niu.c
+++ b/drivers/net/netxen/netxen_nic_niu.c
@@ -603,6 +603,7 @@
 	int phy = physical_port[adapter->portnum];
 	unsigned char mac_addr[6];
 	int i;
+	DECLARE_MAC_BUF(mac);
 
 	for (i = 0; i < 10; i++) {
 		temp[0] = temp[1] = 0;
@@ -627,15 +628,10 @@
 	if (i == 10) {
 		printk(KERN_ERR "%s: cannot set Mac addr for %s\n",
 		       netxen_nic_driver_name, adapter->netdev->name);
-		printk(KERN_ERR "MAC address set: "
-		       "%02x:%02x:%02x:%02x:%02x:%02x.\n",
-		       addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
-
-		printk(KERN_ERR "MAC address get: "
-		       "%02x:%02x:%02x:%02x:%02x:%02x.\n",
-		       mac_addr[0],
-		       mac_addr[1],
-		       mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
+		printk(KERN_ERR "MAC address set: %s.\n",
+		       print_mac(mac, addr));
+		printk(KERN_ERR "MAC address get: %s.\n",
+		       print_mac(mac, mac_addr));
 	}
 	return 0;
 }
diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c
index 3d5b423..14a768f 100644
--- a/drivers/net/ni5010.c
+++ b/drivers/net/ni5010.c
@@ -89,7 +89,6 @@
 
 /* Information that needs to be kept for each board. */
 struct ni5010_local {
-	struct net_device_stats stats;
 	int o_pkt_size;
 	spinlock_t lock;
 };
@@ -103,7 +102,6 @@
 static void	ni5010_rx(struct net_device *dev);
 static void	ni5010_timeout(struct net_device *dev);
 static int	ni5010_close(struct net_device *dev);
-static struct net_device_stats *ni5010_get_stats(struct net_device *dev);
 static void 	ni5010_set_multicast_list(struct net_device *dev);
 static void	reset_receiver(struct net_device *dev);
 
@@ -135,8 +133,6 @@
 
 	PRINTK2((KERN_DEBUG "%s: Entering ni5010_probe\n", dev->name));
 
-	SET_MODULE_OWNER(dev);
-
 	if (io > 0x1ff)	{	/* Check a single specified location. */
 		err = ni5010_probe1(dev, io);
 	} else if (io != 0) {	/* Don't probe at all. */
@@ -207,6 +203,7 @@
 	unsigned int data = 0;
 	int boguscount = 40;
 	int err = -ENODEV;
+	DECLARE_MAC_BUF(mac);
 
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
@@ -272,8 +269,9 @@
 
 	for (i=0; i<6; i++) {
 		outw(i, IE_GP);
-		printk("%2.2x ", dev->dev_addr[i] = inb(IE_SAPROM));
+		dev->dev_addr[i] = inb(IE_SAPROM);
 	}
+	printk("%s ", print_mac(mac, dev->dev_addr));
 
 	PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name));
 
@@ -336,7 +334,6 @@
 	dev->open		= ni5010_open;
 	dev->stop		= ni5010_close;
 	dev->hard_start_xmit	= ni5010_send_packet;
-	dev->get_stats		= ni5010_get_stats;
 	dev->set_multicast_list = ni5010_set_multicast_list;
 	dev->tx_timeout		= ni5010_timeout;
 	dev->watchdog_timeo	= HZ/20;
@@ -534,11 +531,11 @@
 
 	if ( (rcv_stat & RS_VALID_BITS) != RS_PKT_OK) {
 		PRINTK((KERN_INFO "%s: receive error.\n", dev->name));
-		lp->stats.rx_errors++;
-		if (rcv_stat & RS_RUNT) lp->stats.rx_length_errors++;
-		if (rcv_stat & RS_ALIGN) lp->stats.rx_frame_errors++;
-		if (rcv_stat & RS_CRC_ERR) lp->stats.rx_crc_errors++;
-		if (rcv_stat & RS_OFLW) lp->stats.rx_fifo_errors++;
+		dev->stats.rx_errors++;
+		if (rcv_stat & RS_RUNT) dev->stats.rx_length_errors++;
+		if (rcv_stat & RS_ALIGN) dev->stats.rx_frame_errors++;
+		if (rcv_stat & RS_CRC_ERR) dev->stats.rx_crc_errors++;
+		if (rcv_stat & RS_OFLW) dev->stats.rx_fifo_errors++;
         	outb(0xff, EDLC_RCLR); /* Clear the interrupt */
 		return;
 	}
@@ -549,8 +546,8 @@
 	if (i_pkt_size > ETH_FRAME_LEN || i_pkt_size < 10 ) {
 		PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n",
 			dev->name, i_pkt_size));
-		lp->stats.rx_errors++;
-		lp->stats.rx_length_errors++;
+		dev->stats.rx_errors++;
+		dev->stats.rx_length_errors++;
 		return;
 	}
 
@@ -558,7 +555,7 @@
 	skb = dev_alloc_skb(i_pkt_size + 3);
 	if (skb == NULL) {
 		printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
-		lp->stats.rx_dropped++;
+		dev->stats.rx_dropped++;
 		return;
 	}
 
@@ -575,8 +572,8 @@
 	skb->protocol = eth_type_trans(skb,dev);
 	netif_rx(skb);
 	dev->last_rx = jiffies;
-	lp->stats.rx_packets++;
-	lp->stats.rx_bytes += i_pkt_size;
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += i_pkt_size;
 
 	PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n",
 		dev->name, i_pkt_size));
@@ -604,14 +601,14 @@
 		/* outb(0, IE_MMODE); */ /* xmt buf on sysbus FIXME: needed ? */
 		outb(MM_EN_XMT | MM_MUX, IE_MMODE);
 		outb(XM_ALL, EDLC_XMASK); /* Enable xmt IRQ's */
-		lp->stats.collisions++;
+		dev->stats.collisions++;
 		return 1;
 	}
 
 	/* FIXME: handle other xmt error conditions */
 
-	lp->stats.tx_packets++;
-	lp->stats.tx_bytes += lp->o_pkt_size;
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += lp->o_pkt_size;
 	netif_wake_queue(dev);
 
 	PRINTK2((KERN_DEBUG "%s: sent packet, size=%#4.4x\n",
@@ -640,24 +637,6 @@
 
 }
 
-/* Get the current statistics.	This may be called with the card open or
-   closed. */
-static struct net_device_stats *ni5010_get_stats(struct net_device *dev)
-{
-	struct ni5010_local *lp = netdev_priv(dev);
-
-	PRINTK2((KERN_DEBUG "%s: entering ni5010_get_stats\n", dev->name));
-
-	if (NI5010_DEBUG) ni5010_show_registers(dev);
-
-	/* cli(); */
-	/* Update the statistics from the device registers. */
-	/* We do this in the interrupt handler */
-	/* sti(); */
-
-	return &lp->stats;
-}
-
 /* Set or clear the multicast filter for this adaptor.
    num_addrs == -1      Promiscuous mode, receive all packets
    num_addrs == 0       Normal mode, clear multicast list
@@ -670,14 +649,10 @@
 
 	PRINTK2((KERN_DEBUG "%s: entering set_multicast_list\n", dev->name));
 
-	if (dev->flags&IFF_PROMISC || dev->flags&IFF_ALLMULTI) {
+	if (dev->flags&IFF_PROMISC || dev->flags&IFF_ALLMULTI || dev->mc_list) {
 		dev->flags |= IFF_PROMISC;
 		outb(RMD_PROMISC, EDLC_RMODE); /* Enable promiscuous mode */
 		PRINTK((KERN_DEBUG "%s: Entering promiscuous mode\n", dev->name));
-	} else if (dev->mc_list) {
-		/* Sorry, multicast not supported */
-		PRINTK((KERN_DEBUG "%s: No multicast, entering broadcast mode\n", dev->name));
-		outb(RMD_BROADCAST, EDLC_RMODE);
 	} else {
 		PRINTK((KERN_DEBUG "%s: Entering broadcast mode\n", dev->name));
 		outb(RMD_BROADCAST, EDLC_RMODE);  /* Disable promiscuous mode, use normal mode */
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index 5e7999d..6b3384a 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -382,8 +382,6 @@
 		memend = dev->mem_end;
 	}
 
-	SET_MODULE_OWNER(dev);
-
 	if (io > 0x1ff)	{	/* Check a single specified location. */
 		err = ni52_probe1(dev, io);
 	} else if (io > 0) {		/* Don't probe at all. */
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index 4ef5fe3..0976852 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -550,7 +550,6 @@
 	}
 
 	dev->base_addr = ioaddr;
-	SET_MODULE_OWNER(dev);
 	dev->open		= ni65_open;
 	dev->stop		= ni65_close;
 	dev->hard_start_xmit	= ni65_send_packet;
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
new file mode 100644
index 0000000..43bfe7e
--- /dev/null
+++ b/drivers/net/niu.c
@@ -0,0 +1,7939 @@
+/* niu.c: Neptune ethernet driver.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/mii.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/ipv6.h>
+#include <linux/log2.h>
+#include <linux/jiffies.h>
+#include <linux/crc32.h>
+
+#include <linux/io.h>
+
+#ifdef CONFIG_SPARC64
+#include <linux/of_device.h>
+#endif
+
+#include "niu.h"
+
+#define DRV_MODULE_NAME		"niu"
+#define PFX DRV_MODULE_NAME	": "
+#define DRV_MODULE_VERSION	"0.5"
+#define DRV_MODULE_RELDATE	"October 5, 2007"
+
+static char version[] __devinitdata =
+	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("NIU ethernet driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+#ifndef DMA_44BIT_MASK
+#define DMA_44BIT_MASK	0x00000fffffffffffULL
+#endif
+
+#ifndef readq
+static u64 readq(void __iomem *reg)
+{
+	return (((u64)readl(reg + 0x4UL) << 32) |
+		(u64)readl(reg));
+}
+
+static void writeq(u64 val, void __iomem *reg)
+{
+	writel(val & 0xffffffff, reg);
+	writel(val >> 32, reg + 0x4UL);
+}
+#endif
+
+static struct pci_device_id niu_pci_tbl[] = {
+	{PCI_DEVICE(PCI_VENDOR_ID_SUN, 0xabcd)},
+	{}
+};
+
+MODULE_DEVICE_TABLE(pci, niu_pci_tbl);
+
+#define NIU_TX_TIMEOUT			(5 * HZ)
+
+#define nr64(reg)		readq(np->regs + (reg))
+#define nw64(reg, val)		writeq((val), np->regs + (reg))
+
+#define nr64_mac(reg)		readq(np->mac_regs + (reg))
+#define nw64_mac(reg, val)	writeq((val), np->mac_regs + (reg))
+
+#define nr64_ipp(reg)		readq(np->regs + np->ipp_off + (reg))
+#define nw64_ipp(reg, val)	writeq((val), np->regs + np->ipp_off + (reg))
+
+#define nr64_pcs(reg)		readq(np->regs + np->pcs_off + (reg))
+#define nw64_pcs(reg, val)	writeq((val), np->regs + np->pcs_off + (reg))
+
+#define nr64_xpcs(reg)		readq(np->regs + np->xpcs_off + (reg))
+#define nw64_xpcs(reg, val)	writeq((val), np->regs + np->xpcs_off + (reg))
+
+#define NIU_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
+
+static int niu_debug;
+static int debug = -1;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "NIU debug level");
+
+#define niudbg(TYPE, f, a...) \
+do {	if ((np)->msg_enable & NETIF_MSG_##TYPE) \
+		printk(KERN_DEBUG PFX f, ## a); \
+} while (0)
+
+#define niuinfo(TYPE, f, a...) \
+do {	if ((np)->msg_enable & NETIF_MSG_##TYPE) \
+		printk(KERN_INFO PFX f, ## a); \
+} while (0)
+
+#define niuwarn(TYPE, f, a...) \
+do {	if ((np)->msg_enable & NETIF_MSG_##TYPE) \
+		printk(KERN_WARNING PFX f, ## a); \
+} while (0)
+
+#define niu_lock_parent(np, flags) \
+	spin_lock_irqsave(&np->parent->lock, flags)
+#define niu_unlock_parent(np, flags) \
+	spin_unlock_irqrestore(&np->parent->lock, flags)
+
+static int __niu_wait_bits_clear_mac(struct niu *np, unsigned long reg,
+				     u64 bits, int limit, int delay)
+{
+	while (--limit >= 0) {
+		u64 val = nr64_mac(reg);
+
+		if (!(val & bits))
+			break;
+		udelay(delay);
+	}
+	if (limit < 0)
+		return -ENODEV;
+	return 0;
+}
+
+static int __niu_set_and_wait_clear_mac(struct niu *np, unsigned long reg,
+					u64 bits, int limit, int delay,
+					const char *reg_name)
+{
+	int err;
+
+	nw64_mac(reg, bits);
+	err = __niu_wait_bits_clear_mac(np, reg, bits, limit, delay);
+	if (err)
+		dev_err(np->device, PFX "%s: bits (%llx) of register %s "
+			"would not clear, val[%llx]\n",
+			np->dev->name, (unsigned long long) bits, reg_name,
+			(unsigned long long) nr64_mac(reg));
+	return err;
+}
+
+#define niu_set_and_wait_clear_mac(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \
+({	BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \
+	__niu_set_and_wait_clear_mac(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \
+})
+
+static int __niu_wait_bits_clear_ipp(struct niu *np, unsigned long reg,
+				     u64 bits, int limit, int delay)
+{
+	while (--limit >= 0) {
+		u64 val = nr64_ipp(reg);
+
+		if (!(val & bits))
+			break;
+		udelay(delay);
+	}
+	if (limit < 0)
+		return -ENODEV;
+	return 0;
+}
+
+static int __niu_set_and_wait_clear_ipp(struct niu *np, unsigned long reg,
+					u64 bits, int limit, int delay,
+					const char *reg_name)
+{
+	int err;
+	u64 val;
+
+	val = nr64_ipp(reg);
+	val |= bits;
+	nw64_ipp(reg, val);
+
+	err = __niu_wait_bits_clear_ipp(np, reg, bits, limit, delay);
+	if (err)
+		dev_err(np->device, PFX "%s: bits (%llx) of register %s "
+			"would not clear, val[%llx]\n",
+			np->dev->name, (unsigned long long) bits, reg_name,
+			(unsigned long long) nr64_ipp(reg));
+	return err;
+}
+
+#define niu_set_and_wait_clear_ipp(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \
+({	BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \
+	__niu_set_and_wait_clear_ipp(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \
+})
+
+static int __niu_wait_bits_clear(struct niu *np, unsigned long reg,
+				 u64 bits, int limit, int delay)
+{
+	while (--limit >= 0) {
+		u64 val = nr64(reg);
+
+		if (!(val & bits))
+			break;
+		udelay(delay);
+	}
+	if (limit < 0)
+		return -ENODEV;
+	return 0;
+}
+
+#define niu_wait_bits_clear(NP, REG, BITS, LIMIT, DELAY) \
+({	BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \
+	__niu_wait_bits_clear(NP, REG, BITS, LIMIT, DELAY); \
+})
+
+static int __niu_set_and_wait_clear(struct niu *np, unsigned long reg,
+				    u64 bits, int limit, int delay,
+				    const char *reg_name)
+{
+	int err;
+
+	nw64(reg, bits);
+	err = __niu_wait_bits_clear(np, reg, bits, limit, delay);
+	if (err)
+		dev_err(np->device, PFX "%s: bits (%llx) of register %s "
+			"would not clear, val[%llx]\n",
+			np->dev->name, (unsigned long long) bits, reg_name,
+			(unsigned long long) nr64(reg));
+	return err;
+}
+
+#define niu_set_and_wait_clear(NP, REG, BITS, LIMIT, DELAY, REG_NAME) \
+({	BUILD_BUG_ON(LIMIT <= 0 || DELAY < 0); \
+	__niu_set_and_wait_clear(NP, REG, BITS, LIMIT, DELAY, REG_NAME); \
+})
+
+static void niu_ldg_rearm(struct niu *np, struct niu_ldg *lp, int on)
+{
+	u64 val = (u64) lp->timer;
+
+	if (on)
+		val |= LDG_IMGMT_ARM;
+
+	nw64(LDG_IMGMT(lp->ldg_num), val);
+}
+
+static int niu_ldn_irq_enable(struct niu *np, int ldn, int on)
+{
+	unsigned long mask_reg, bits;
+	u64 val;
+
+	if (ldn < 0 || ldn > LDN_MAX)
+		return -EINVAL;
+
+	if (ldn < 64) {
+		mask_reg = LD_IM0(ldn);
+		bits = LD_IM0_MASK;
+	} else {
+		mask_reg = LD_IM1(ldn - 64);
+		bits = LD_IM1_MASK;
+	}
+
+	val = nr64(mask_reg);
+	if (on)
+		val &= ~bits;
+	else
+		val |= bits;
+	nw64(mask_reg, val);
+
+	return 0;
+}
+
+static int niu_enable_ldn_in_ldg(struct niu *np, struct niu_ldg *lp, int on)
+{
+	struct niu_parent *parent = np->parent;
+	int i;
+
+	for (i = 0; i <= LDN_MAX; i++) {
+		int err;
+
+		if (parent->ldg_map[i] != lp->ldg_num)
+			continue;
+
+		err = niu_ldn_irq_enable(np, i, on);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+static int niu_enable_interrupts(struct niu *np, int on)
+{
+	int i;
+
+	for (i = 0; i < np->num_ldg; i++) {
+		struct niu_ldg *lp = &np->ldg[i];
+		int err;
+
+		err = niu_enable_ldn_in_ldg(np, lp, on);
+		if (err)
+			return err;
+	}
+	for (i = 0; i < np->num_ldg; i++)
+		niu_ldg_rearm(np, &np->ldg[i], on);
+
+	return 0;
+}
+
+static u32 phy_encode(u32 type, int port)
+{
+	return (type << (port * 2));
+}
+
+static u32 phy_decode(u32 val, int port)
+{
+	return (val >> (port * 2)) & PORT_TYPE_MASK;
+}
+
+static int mdio_wait(struct niu *np)
+{
+	int limit = 1000;
+	u64 val;
+
+	while (--limit > 0) {
+		val = nr64(MIF_FRAME_OUTPUT);
+		if ((val >> MIF_FRAME_OUTPUT_TA_SHIFT) & 0x1)
+			return val & MIF_FRAME_OUTPUT_DATA;
+
+		udelay(10);
+	}
+
+	return -ENODEV;
+}
+
+static int mdio_read(struct niu *np, int port, int dev, int reg)
+{
+	int err;
+
+	nw64(MIF_FRAME_OUTPUT, MDIO_ADDR_OP(port, dev, reg));
+	err = mdio_wait(np);
+	if (err < 0)
+		return err;
+
+	nw64(MIF_FRAME_OUTPUT, MDIO_READ_OP(port, dev));
+	return mdio_wait(np);
+}
+
+static int mdio_write(struct niu *np, int port, int dev, int reg, int data)
+{
+	int err;
+
+	nw64(MIF_FRAME_OUTPUT, MDIO_ADDR_OP(port, dev, reg));
+	err = mdio_wait(np);
+	if (err < 0)
+		return err;
+
+	nw64(MIF_FRAME_OUTPUT, MDIO_WRITE_OP(port, dev, data));
+	err = mdio_wait(np);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int mii_read(struct niu *np, int port, int reg)
+{
+	nw64(MIF_FRAME_OUTPUT, MII_READ_OP(port, reg));
+	return mdio_wait(np);
+}
+
+static int mii_write(struct niu *np, int port, int reg, int data)
+{
+	int err;
+
+	nw64(MIF_FRAME_OUTPUT, MII_WRITE_OP(port, reg, data));
+	err = mdio_wait(np);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int esr2_set_tx_cfg(struct niu *np, unsigned long channel, u32 val)
+{
+	int err;
+
+	err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+			 ESR2_TI_PLL_TX_CFG_L(channel),
+			 val & 0xffff);
+	if (!err)
+		err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+				 ESR2_TI_PLL_TX_CFG_H(channel),
+				 val >> 16);
+	return err;
+}
+
+static int esr2_set_rx_cfg(struct niu *np, unsigned long channel, u32 val)
+{
+	int err;
+
+	err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+			 ESR2_TI_PLL_RX_CFG_L(channel),
+			 val & 0xffff);
+	if (!err)
+		err = mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+				 ESR2_TI_PLL_RX_CFG_H(channel),
+				 val >> 16);
+	return err;
+}
+
+/* Mode is always 10G fiber.  */
+static int serdes_init_niu(struct niu *np)
+{
+	struct niu_link_config *lp = &np->link_config;
+	u32 tx_cfg, rx_cfg;
+	unsigned long i;
+
+	tx_cfg = (PLL_TX_CFG_ENTX | PLL_TX_CFG_SWING_1375MV);
+	rx_cfg = (PLL_RX_CFG_ENRX | PLL_RX_CFG_TERM_0P8VDDT |
+		  PLL_RX_CFG_ALIGN_ENA | PLL_RX_CFG_LOS_LTHRESH |
+		  PLL_RX_CFG_EQ_LP_ADAPTIVE);
+
+	if (lp->loopback_mode == LOOPBACK_PHY) {
+		u16 test_cfg = PLL_TEST_CFG_LOOPBACK_CML_DIS;
+
+		mdio_write(np, np->port, NIU_ESR2_DEV_ADDR,
+			   ESR2_TI_PLL_TEST_CFG_L, test_cfg);
+
+		tx_cfg |= PLL_TX_CFG_ENTEST;
+		rx_cfg |= PLL_RX_CFG_ENTEST;
+	}
+
+	/* Initialize all 4 lanes of the SERDES.  */
+	for (i = 0; i < 4; i++) {
+		int err = esr2_set_tx_cfg(np, i, tx_cfg);
+		if (err)
+			return err;
+	}
+
+	for (i = 0; i < 4; i++) {
+		int err = esr2_set_rx_cfg(np, i, rx_cfg);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int esr_read_rxtx_ctrl(struct niu *np, unsigned long chan, u32 *val)
+{
+	int err;
+
+	err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR, ESR_RXTX_CTRL_L(chan));
+	if (err >= 0) {
+		*val = (err & 0xffff);
+		err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
+				ESR_RXTX_CTRL_H(chan));
+		if (err >= 0)
+			*val |= ((err & 0xffff) << 16);
+		err = 0;
+	}
+	return err;
+}
+
+static int esr_read_glue0(struct niu *np, unsigned long chan, u32 *val)
+{
+	int err;
+
+	err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
+			ESR_GLUE_CTRL0_L(chan));
+	if (err >= 0) {
+		*val = (err & 0xffff);
+		err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
+				ESR_GLUE_CTRL0_H(chan));
+		if (err >= 0) {
+			*val |= ((err & 0xffff) << 16);
+			err = 0;
+		}
+	}
+	return err;
+}
+
+static int esr_read_reset(struct niu *np, u32 *val)
+{
+	int err;
+
+	err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
+			ESR_RXTX_RESET_CTRL_L);
+	if (err >= 0) {
+		*val = (err & 0xffff);
+		err = mdio_read(np, np->port, NIU_ESR_DEV_ADDR,
+				ESR_RXTX_RESET_CTRL_H);
+		if (err >= 0) {
+			*val |= ((err & 0xffff) << 16);
+			err = 0;
+		}
+	}
+	return err;
+}
+
+static int esr_write_rxtx_ctrl(struct niu *np, unsigned long chan, u32 val)
+{
+	int err;
+
+	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+			 ESR_RXTX_CTRL_L(chan), val & 0xffff);
+	if (!err)
+		err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+				 ESR_RXTX_CTRL_H(chan), (val >> 16));
+	return err;
+}
+
+static int esr_write_glue0(struct niu *np, unsigned long chan, u32 val)
+{
+	int err;
+
+	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+			ESR_GLUE_CTRL0_L(chan), val & 0xffff);
+	if (!err)
+		err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+				 ESR_GLUE_CTRL0_H(chan), (val >> 16));
+	return err;
+}
+
+static int esr_reset(struct niu *np)
+{
+	u32 reset;
+	int err;
+
+	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+			 ESR_RXTX_RESET_CTRL_L, 0x0000);
+	if (err)
+		return err;
+	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+			 ESR_RXTX_RESET_CTRL_H, 0xffff);
+	if (err)
+		return err;
+	udelay(200);
+
+	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+			 ESR_RXTX_RESET_CTRL_L, 0xffff);
+	if (err)
+		return err;
+	udelay(200);
+
+	err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR,
+			 ESR_RXTX_RESET_CTRL_H, 0x0000);
+	if (err)
+		return err;
+	udelay(200);
+
+	err = esr_read_reset(np, &reset);
+	if (err)
+		return err;
+	if (reset != 0) {
+		dev_err(np->device, PFX "Port %u ESR_RESET "
+			"did not clear [%08x]\n",
+			np->port, reset);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int serdes_init_10g(struct niu *np)
+{
+	struct niu_link_config *lp = &np->link_config;
+	unsigned long ctrl_reg, test_cfg_reg, i;
+	u64 ctrl_val, test_cfg_val, sig, mask, val;
+	int err;
+
+	switch (np->port) {
+	case 0:
+		ctrl_reg = ENET_SERDES_0_CTRL_CFG;
+		test_cfg_reg = ENET_SERDES_0_TEST_CFG;
+		break;
+	case 1:
+		ctrl_reg = ENET_SERDES_1_CTRL_CFG;
+		test_cfg_reg = ENET_SERDES_1_TEST_CFG;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	ctrl_val = (ENET_SERDES_CTRL_SDET_0 |
+		    ENET_SERDES_CTRL_SDET_1 |
+		    ENET_SERDES_CTRL_SDET_2 |
+		    ENET_SERDES_CTRL_SDET_3 |
+		    (0x5 << ENET_SERDES_CTRL_EMPH_0_SHIFT) |
+		    (0x5 << ENET_SERDES_CTRL_EMPH_1_SHIFT) |
+		    (0x5 << ENET_SERDES_CTRL_EMPH_2_SHIFT) |
+		    (0x5 << ENET_SERDES_CTRL_EMPH_3_SHIFT) |
+		    (0x1 << ENET_SERDES_CTRL_LADJ_0_SHIFT) |
+		    (0x1 << ENET_SERDES_CTRL_LADJ_1_SHIFT) |
+		    (0x1 << ENET_SERDES_CTRL_LADJ_2_SHIFT) |
+		    (0x1 << ENET_SERDES_CTRL_LADJ_3_SHIFT));
+	test_cfg_val = 0;
+
+	if (lp->loopback_mode == LOOPBACK_PHY) {
+		test_cfg_val |= ((ENET_TEST_MD_PAD_LOOPBACK <<
+				  ENET_SERDES_TEST_MD_0_SHIFT) |
+				 (ENET_TEST_MD_PAD_LOOPBACK <<
+				  ENET_SERDES_TEST_MD_1_SHIFT) |
+				 (ENET_TEST_MD_PAD_LOOPBACK <<
+				  ENET_SERDES_TEST_MD_2_SHIFT) |
+				 (ENET_TEST_MD_PAD_LOOPBACK <<
+				  ENET_SERDES_TEST_MD_3_SHIFT));
+	}
+
+	nw64(ctrl_reg, ctrl_val);
+	nw64(test_cfg_reg, test_cfg_val);
+
+	/* Initialize all 4 lanes of the SERDES.  */
+	for (i = 0; i < 4; i++) {
+		u32 rxtx_ctrl, glue0;
+
+		err = esr_read_rxtx_ctrl(np, i, &rxtx_ctrl);
+		if (err)
+			return err;
+		err = esr_read_glue0(np, i, &glue0);
+		if (err)
+			return err;
+
+		rxtx_ctrl &= ~(ESR_RXTX_CTRL_VMUXLO);
+		rxtx_ctrl |= (ESR_RXTX_CTRL_ENSTRETCH |
+			      (2 << ESR_RXTX_CTRL_VMUXLO_SHIFT));
+
+		glue0 &= ~(ESR_GLUE_CTRL0_SRATE |
+			   ESR_GLUE_CTRL0_THCNT |
+			   ESR_GLUE_CTRL0_BLTIME);
+		glue0 |= (ESR_GLUE_CTRL0_RXLOSENAB |
+			  (0xf << ESR_GLUE_CTRL0_SRATE_SHIFT) |
+			  (0xff << ESR_GLUE_CTRL0_THCNT_SHIFT) |
+			  (BLTIME_300_CYCLES <<
+			   ESR_GLUE_CTRL0_BLTIME_SHIFT));
+
+		err = esr_write_rxtx_ctrl(np, i, rxtx_ctrl);
+		if (err)
+			return err;
+		err = esr_write_glue0(np, i, glue0);
+		if (err)
+			return err;
+	}
+
+	err = esr_reset(np);
+	if (err)
+		return err;
+
+	sig = nr64(ESR_INT_SIGNALS);
+	switch (np->port) {
+	case 0:
+		mask = ESR_INT_SIGNALS_P0_BITS;
+		val = (ESR_INT_SRDY0_P0 |
+		       ESR_INT_DET0_P0 |
+		       ESR_INT_XSRDY_P0 |
+		       ESR_INT_XDP_P0_CH3 |
+		       ESR_INT_XDP_P0_CH2 |
+		       ESR_INT_XDP_P0_CH1 |
+		       ESR_INT_XDP_P0_CH0);
+		break;
+
+	case 1:
+		mask = ESR_INT_SIGNALS_P1_BITS;
+		val = (ESR_INT_SRDY0_P1 |
+		       ESR_INT_DET0_P1 |
+		       ESR_INT_XSRDY_P1 |
+		       ESR_INT_XDP_P1_CH3 |
+		       ESR_INT_XDP_P1_CH2 |
+		       ESR_INT_XDP_P1_CH1 |
+		       ESR_INT_XDP_P1_CH0);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if ((sig & mask) != val) {
+		dev_err(np->device, PFX "Port %u signal bits [%08x] are not "
+			"[%08x]\n", np->port, (int) (sig & mask), (int) val);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int serdes_init_1g(struct niu *np)
+{
+	u64 val;
+
+	val = nr64(ENET_SERDES_1_PLL_CFG);
+	val &= ~ENET_SERDES_PLL_FBDIV2;
+	switch (np->port) {
+	case 0:
+		val |= ENET_SERDES_PLL_HRATE0;
+		break;
+	case 1:
+		val |= ENET_SERDES_PLL_HRATE1;
+		break;
+	case 2:
+		val |= ENET_SERDES_PLL_HRATE2;
+		break;
+	case 3:
+		val |= ENET_SERDES_PLL_HRATE3;
+		break;
+	default:
+		return -EINVAL;
+	}
+	nw64(ENET_SERDES_1_PLL_CFG, val);
+
+	return 0;
+}
+
+static int bcm8704_reset(struct niu *np)
+{
+	int err, limit;
+
+	err = mdio_read(np, np->phy_addr,
+			BCM8704_PHYXS_DEV_ADDR, MII_BMCR);
+	if (err < 0)
+		return err;
+	err |= BMCR_RESET;
+	err = mdio_write(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR,
+			 MII_BMCR, err);
+	if (err)
+		return err;
+
+	limit = 1000;
+	while (--limit >= 0) {
+		err = mdio_read(np, np->phy_addr,
+				BCM8704_PHYXS_DEV_ADDR, MII_BMCR);
+		if (err < 0)
+			return err;
+		if (!(err & BMCR_RESET))
+			break;
+	}
+	if (limit < 0) {
+		dev_err(np->device, PFX "Port %u PHY will not reset "
+			"(bmcr=%04x)\n", np->port, (err & 0xffff));
+		return -ENODEV;
+	}
+	return 0;
+}
+
+/* When written, certain PHY registers need to be read back twice
+ * in order for the bits to settle properly.
+ */
+static int bcm8704_user_dev3_readback(struct niu *np, int reg)
+{
+	int err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, reg);
+	if (err < 0)
+		return err;
+	err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, reg);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static int bcm8704_init_user_dev3(struct niu *np)
+{
+	int err;
+
+	err = mdio_write(np, np->phy_addr,
+			 BCM8704_USER_DEV3_ADDR, BCM8704_USER_CONTROL,
+			 (USER_CONTROL_OPTXRST_LVL |
+			  USER_CONTROL_OPBIASFLT_LVL |
+			  USER_CONTROL_OBTMPFLT_LVL |
+			  USER_CONTROL_OPPRFLT_LVL |
+			  USER_CONTROL_OPTXFLT_LVL |
+			  USER_CONTROL_OPRXLOS_LVL |
+			  USER_CONTROL_OPRXFLT_LVL |
+			  USER_CONTROL_OPTXON_LVL |
+			  (0x3f << USER_CONTROL_RES1_SHIFT)));
+	if (err)
+		return err;
+
+	err = mdio_write(np, np->phy_addr,
+			 BCM8704_USER_DEV3_ADDR, BCM8704_USER_PMD_TX_CONTROL,
+			 (USER_PMD_TX_CTL_XFP_CLKEN |
+			  (1 << USER_PMD_TX_CTL_TX_DAC_TXD_SH) |
+			  (2 << USER_PMD_TX_CTL_TX_DAC_TXCK_SH) |
+			  USER_PMD_TX_CTL_TSCK_LPWREN));
+	if (err)
+		return err;
+
+	err = bcm8704_user_dev3_readback(np, BCM8704_USER_CONTROL);
+	if (err)
+		return err;
+	err = bcm8704_user_dev3_readback(np, BCM8704_USER_PMD_TX_CONTROL);
+	if (err)
+		return err;
+
+	err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+			BCM8704_USER_OPT_DIGITAL_CTRL);
+	if (err < 0)
+		return err;
+	err &= ~USER_ODIG_CTRL_GPIOS;
+	err |= (0x3 << USER_ODIG_CTRL_GPIOS_SHIFT);
+	err = mdio_write(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+			 BCM8704_USER_OPT_DIGITAL_CTRL, err);
+	if (err)
+		return err;
+
+	mdelay(1000);
+
+	return 0;
+}
+
+static int xcvr_init_10g(struct niu *np)
+{
+	struct niu_link_config *lp = &np->link_config;
+	u16 analog_stat0, tx_alarm_status;
+	int err;
+	u64 val;
+
+	val = nr64_mac(XMAC_CONFIG);
+	val &= ~XMAC_CONFIG_LED_POLARITY;
+	val |= XMAC_CONFIG_FORCE_LED_ON;
+	nw64_mac(XMAC_CONFIG, val);
+
+	/* XXX shared resource, lock parent XXX */
+	val = nr64(MIF_CONFIG);
+	val |= MIF_CONFIG_INDIRECT_MODE;
+	nw64(MIF_CONFIG, val);
+
+	err = bcm8704_reset(np);
+	if (err)
+		return err;
+
+	err = bcm8704_init_user_dev3(np);
+	if (err)
+		return err;
+
+	err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
+			MII_BMCR);
+	if (err < 0)
+		return err;
+	err &= ~BMCR_LOOPBACK;
+
+	if (lp->loopback_mode == LOOPBACK_MAC)
+		err |= BMCR_LOOPBACK;
+
+	err = mdio_write(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
+			 MII_BMCR, err);
+	if (err)
+		return err;
+
+#if 1
+	err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR,
+			MII_STAT1000);
+	if (err < 0)
+		return err;
+	pr_info(PFX "Port %u PMA_PMD(MII_STAT1000) [%04x]\n",
+		np->port, err);
+
+	err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR, 0x20);
+	if (err < 0)
+		return err;
+	pr_info(PFX "Port %u USER_DEV3(0x20) [%04x]\n",
+		np->port, err);
+
+	err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR,
+			MII_NWAYTEST);
+	if (err < 0)
+		return err;
+	pr_info(PFX "Port %u PHYXS(MII_NWAYTEST) [%04x]\n",
+		np->port, err);
+#endif
+
+	/* XXX dig this out it might not be so useful XXX */
+	err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+			BCM8704_USER_ANALOG_STATUS0);
+	if (err < 0)
+		return err;
+	err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+			BCM8704_USER_ANALOG_STATUS0);
+	if (err < 0)
+		return err;
+	analog_stat0 = err;
+
+	err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+			BCM8704_USER_TX_ALARM_STATUS);
+	if (err < 0)
+		return err;
+	err = mdio_read(np, np->phy_addr, BCM8704_USER_DEV3_ADDR,
+			BCM8704_USER_TX_ALARM_STATUS);
+	if (err < 0)
+		return err;
+	tx_alarm_status = err;
+
+	if (analog_stat0 != 0x03fc) {
+		if ((analog_stat0 == 0x43bc) && (tx_alarm_status != 0)) {
+			pr_info(PFX "Port %u cable not connected "
+				"or bad cable.\n", np->port);
+		} else if (analog_stat0 == 0x639c) {
+			pr_info(PFX "Port %u optical module is bad "
+				"or missing.\n", np->port);
+		}
+	}
+
+	return 0;
+}
+
+static int mii_reset(struct niu *np)
+{
+	int limit, err;
+
+	err = mii_write(np, np->phy_addr, MII_BMCR, BMCR_RESET);
+	if (err)
+		return err;
+
+	limit = 1000;
+	while (--limit >= 0) {
+		udelay(500);
+		err = mii_read(np, np->phy_addr, MII_BMCR);
+		if (err < 0)
+			return err;
+		if (!(err & BMCR_RESET))
+			break;
+	}
+	if (limit < 0) {
+		dev_err(np->device, PFX "Port %u MII would not reset, "
+			"bmcr[%04x]\n", np->port, err);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int mii_init_common(struct niu *np)
+{
+	struct niu_link_config *lp = &np->link_config;
+	u16 bmcr, bmsr, adv, estat;
+	int err;
+
+	err = mii_reset(np);
+	if (err)
+		return err;
+
+	err = mii_read(np, np->phy_addr, MII_BMSR);
+	if (err < 0)
+		return err;
+	bmsr = err;
+
+	estat = 0;
+	if (bmsr & BMSR_ESTATEN) {
+		err = mii_read(np, np->phy_addr, MII_ESTATUS);
+		if (err < 0)
+			return err;
+		estat = err;
+	}
+
+	bmcr = 0;
+	err = mii_write(np, np->phy_addr, MII_BMCR, bmcr);
+	if (err)
+		return err;
+
+	if (lp->loopback_mode == LOOPBACK_MAC) {
+		bmcr |= BMCR_LOOPBACK;
+		if (lp->active_speed == SPEED_1000)
+			bmcr |= BMCR_SPEED1000;
+		if (lp->active_duplex == DUPLEX_FULL)
+			bmcr |= BMCR_FULLDPLX;
+	}
+
+	if (lp->loopback_mode == LOOPBACK_PHY) {
+		u16 aux;
+
+		aux = (BCM5464R_AUX_CTL_EXT_LB |
+		       BCM5464R_AUX_CTL_WRITE_1);
+		err = mii_write(np, np->phy_addr, BCM5464R_AUX_CTL, aux);
+		if (err)
+			return err;
+	}
+
+	/* XXX configurable XXX */
+	/* XXX for now don't advertise half-duplex or asym pause... XXX */
+	adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
+	if (bmsr & BMSR_10FULL)
+		adv |= ADVERTISE_10FULL;
+	if (bmsr & BMSR_100FULL)
+		adv |= ADVERTISE_100FULL;
+	err = mii_write(np, np->phy_addr, MII_ADVERTISE, adv);
+	if (err)
+		return err;
+
+	if (bmsr & BMSR_ESTATEN) {
+		u16 ctrl1000 = 0;
+
+		if (estat & ESTATUS_1000_TFULL)
+			ctrl1000 |= ADVERTISE_1000FULL;
+		err = mii_write(np, np->phy_addr, MII_CTRL1000, ctrl1000);
+		if (err)
+			return err;
+	}
+	bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+
+	err = mii_write(np, np->phy_addr, MII_BMCR, bmcr);
+	if (err)
+		return err;
+
+	err = mii_read(np, np->phy_addr, MII_BMCR);
+	if (err < 0)
+		return err;
+	err = mii_read(np, np->phy_addr, MII_BMSR);
+	if (err < 0)
+		return err;
+#if 0
+	pr_info(PFX "Port %u after MII init bmcr[%04x] bmsr[%04x]\n",
+		np->port, bmcr, bmsr);
+#endif
+
+	return 0;
+}
+
+static int xcvr_init_1g(struct niu *np)
+{
+	u64 val;
+
+	/* XXX shared resource, lock parent XXX */
+	val = nr64(MIF_CONFIG);
+	val &= ~MIF_CONFIG_INDIRECT_MODE;
+	nw64(MIF_CONFIG, val);
+
+	return mii_init_common(np);
+}
+
+static int niu_xcvr_init(struct niu *np)
+{
+	const struct niu_phy_ops *ops = np->phy_ops;
+	int err;
+
+	err = 0;
+	if (ops->xcvr_init)
+		err = ops->xcvr_init(np);
+
+	return err;
+}
+
+static int niu_serdes_init(struct niu *np)
+{
+	const struct niu_phy_ops *ops = np->phy_ops;
+	int err;
+
+	err = 0;
+	if (ops->serdes_init)
+		err = ops->serdes_init(np);
+
+	return err;
+}
+
+static void niu_init_xif(struct niu *);
+
+static int niu_link_status_common(struct niu *np, int link_up)
+{
+	struct niu_link_config *lp = &np->link_config;
+	struct net_device *dev = np->dev;
+	unsigned long flags;
+
+	if (!netif_carrier_ok(dev) && link_up) {
+		niuinfo(LINK, "%s: Link is up at %s, %s duplex\n",
+		       dev->name,
+		       (lp->active_speed == SPEED_10000 ?
+			"10Gb/sec" :
+			(lp->active_speed == SPEED_1000 ?
+			 "1Gb/sec" :
+			 (lp->active_speed == SPEED_100 ?
+			  "100Mbit/sec" : "10Mbit/sec"))),
+		       (lp->active_duplex == DUPLEX_FULL ?
+			"full" : "half"));
+
+		spin_lock_irqsave(&np->lock, flags);
+		niu_init_xif(np);
+		spin_unlock_irqrestore(&np->lock, flags);
+
+		netif_carrier_on(dev);
+	} else if (netif_carrier_ok(dev) && !link_up) {
+		niuwarn(LINK, "%s: Link is down\n", dev->name);
+		netif_carrier_off(dev);
+	}
+
+	return 0;
+}
+
+static int link_status_10g(struct niu *np, int *link_up_p)
+{
+	unsigned long flags;
+	int err, link_up;
+
+	link_up = 0;
+
+	spin_lock_irqsave(&np->lock, flags);
+
+	err = -EINVAL;
+	if (np->link_config.loopback_mode != LOOPBACK_DISABLED)
+		goto out;
+
+	err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR,
+			BCM8704_PMD_RCV_SIGDET);
+	if (err < 0)
+		goto out;
+	if (!(err & PMD_RCV_SIGDET_GLOBAL)) {
+		err = 0;
+		goto out;
+	}
+
+	err = mdio_read(np, np->phy_addr, BCM8704_PCS_DEV_ADDR,
+			BCM8704_PCS_10G_R_STATUS);
+	if (err < 0)
+		goto out;
+	if (!(err & PCS_10G_R_STATUS_BLK_LOCK)) {
+		err = 0;
+		goto out;
+	}
+
+	err = mdio_read(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR,
+			BCM8704_PHYXS_XGXS_LANE_STAT);
+	if (err < 0)
+		goto out;
+
+	if (err != (PHYXS_XGXS_LANE_STAT_ALINGED |
+		    PHYXS_XGXS_LANE_STAT_MAGIC |
+		    PHYXS_XGXS_LANE_STAT_LANE3 |
+		    PHYXS_XGXS_LANE_STAT_LANE2 |
+		    PHYXS_XGXS_LANE_STAT_LANE1 |
+		    PHYXS_XGXS_LANE_STAT_LANE0)) {
+		err = 0;
+		goto out;
+	}
+
+	link_up = 1;
+	np->link_config.active_speed = SPEED_10000;
+	np->link_config.active_duplex = DUPLEX_FULL;
+	err = 0;
+
+out:
+	spin_unlock_irqrestore(&np->lock, flags);
+
+	*link_up_p = link_up;
+	return err;
+}
+
+static int link_status_1g(struct niu *np, int *link_up_p)
+{
+	u16 current_speed, bmsr;
+	unsigned long flags;
+	u8 current_duplex;
+	int err, link_up;
+
+	link_up = 0;
+	current_speed = SPEED_INVALID;
+	current_duplex = DUPLEX_INVALID;
+
+	spin_lock_irqsave(&np->lock, flags);
+
+	err = -EINVAL;
+	if (np->link_config.loopback_mode != LOOPBACK_DISABLED)
+		goto out;
+
+	err = mii_read(np, np->phy_addr, MII_BMSR);
+	if (err < 0)
+		goto out;
+
+	bmsr = err;
+	if (bmsr & BMSR_LSTATUS) {
+		u16 adv, lpa, common, estat;
+
+		err = mii_read(np, np->phy_addr, MII_ADVERTISE);
+		if (err < 0)
+			goto out;
+		adv = err;
+
+		err = mii_read(np, np->phy_addr, MII_LPA);
+		if (err < 0)
+			goto out;
+		lpa = err;
+
+		common = adv & lpa;
+
+		err = mii_read(np, np->phy_addr, MII_ESTATUS);
+		if (err < 0)
+			goto out;
+		estat = err;
+
+		link_up = 1;
+		if (estat & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) {
+			current_speed = SPEED_1000;
+			if (estat & ESTATUS_1000_TFULL)
+				current_duplex = DUPLEX_FULL;
+			else
+				current_duplex = DUPLEX_HALF;
+		} else {
+			if (common & ADVERTISE_100BASE4) {
+				current_speed = SPEED_100;
+				current_duplex = DUPLEX_HALF;
+			} else if (common & ADVERTISE_100FULL) {
+				current_speed = SPEED_100;
+				current_duplex = DUPLEX_FULL;
+			} else if (common & ADVERTISE_100HALF) {
+				current_speed = SPEED_100;
+				current_duplex = DUPLEX_HALF;
+			} else if (common & ADVERTISE_10FULL) {
+				current_speed = SPEED_10;
+				current_duplex = DUPLEX_FULL;
+			} else if (common & ADVERTISE_10HALF) {
+				current_speed = SPEED_10;
+				current_duplex = DUPLEX_HALF;
+			} else
+				link_up = 0;
+		}
+	}
+	err = 0;
+
+out:
+	spin_unlock_irqrestore(&np->lock, flags);
+
+	*link_up_p = link_up;
+	return err;
+}
+
+static int niu_link_status(struct niu *np, int *link_up_p)
+{
+	const struct niu_phy_ops *ops = np->phy_ops;
+	int err;
+
+	err = 0;
+	if (ops->link_status)
+		err = ops->link_status(np, link_up_p);
+
+	return err;
+}
+
+static void niu_timer(unsigned long __opaque)
+{
+	struct niu *np = (struct niu *) __opaque;
+	unsigned long off;
+	int err, link_up;
+
+	err = niu_link_status(np, &link_up);
+	if (!err)
+		niu_link_status_common(np, link_up);
+
+	if (netif_carrier_ok(np->dev))
+		off = 5 * HZ;
+	else
+		off = 1 * HZ;
+	np->timer.expires = jiffies + off;
+
+	add_timer(&np->timer);
+}
+
+static const struct niu_phy_ops phy_ops_10g_fiber_niu = {
+	.serdes_init		= serdes_init_niu,
+	.xcvr_init		= xcvr_init_10g,
+	.link_status		= link_status_10g,
+};
+
+static const struct niu_phy_ops phy_ops_10g_fiber = {
+	.serdes_init		= serdes_init_10g,
+	.xcvr_init		= xcvr_init_10g,
+	.link_status		= link_status_10g,
+};
+
+static const struct niu_phy_ops phy_ops_10g_copper = {
+	.serdes_init		= serdes_init_10g,
+	.link_status		= link_status_10g, /* XXX */
+};
+
+static const struct niu_phy_ops phy_ops_1g_fiber = {
+	.serdes_init		= serdes_init_1g,
+	.xcvr_init		= xcvr_init_1g,
+	.link_status		= link_status_1g,
+};
+
+static const struct niu_phy_ops phy_ops_1g_copper = {
+	.xcvr_init		= xcvr_init_1g,
+	.link_status		= link_status_1g,
+};
+
+struct niu_phy_template {
+	const struct niu_phy_ops	*ops;
+	u32				phy_addr_base;
+};
+
+static const struct niu_phy_template phy_template_niu = {
+	.ops		= &phy_ops_10g_fiber_niu,
+	.phy_addr_base	= 16,
+};
+
+static const struct niu_phy_template phy_template_10g_fiber = {
+	.ops		= &phy_ops_10g_fiber,
+	.phy_addr_base	= 8,
+};
+
+static const struct niu_phy_template phy_template_10g_copper = {
+	.ops		= &phy_ops_10g_copper,
+	.phy_addr_base	= 10,
+};
+
+static const struct niu_phy_template phy_template_1g_fiber = {
+	.ops		= &phy_ops_1g_fiber,
+	.phy_addr_base	= 0,
+};
+
+static const struct niu_phy_template phy_template_1g_copper = {
+	.ops		= &phy_ops_1g_copper,
+	.phy_addr_base	= 0,
+};
+
+static int niu_determine_phy_disposition(struct niu *np)
+{
+	struct niu_parent *parent = np->parent;
+	u8 plat_type = parent->plat_type;
+	const struct niu_phy_template *tp;
+	u32 phy_addr_off = 0;
+
+	if (plat_type == PLAT_TYPE_NIU) {
+		tp = &phy_template_niu;
+		phy_addr_off += np->port;
+	} else {
+		switch (np->flags & (NIU_FLAGS_10G | NIU_FLAGS_FIBER)) {
+		case 0:
+			/* 1G copper */
+			tp = &phy_template_1g_copper;
+			if (plat_type == PLAT_TYPE_VF_P0)
+				phy_addr_off = 10;
+			else if (plat_type == PLAT_TYPE_VF_P1)
+				phy_addr_off = 26;
+
+			phy_addr_off += (np->port ^ 0x3);
+			break;
+
+		case NIU_FLAGS_10G:
+			/* 10G copper */
+			tp = &phy_template_1g_copper;
+			break;
+
+		case NIU_FLAGS_FIBER:
+			/* 1G fiber */
+			tp = &phy_template_1g_fiber;
+			break;
+
+		case NIU_FLAGS_10G | NIU_FLAGS_FIBER:
+			/* 10G fiber */
+			tp = &phy_template_10g_fiber;
+			if (plat_type == PLAT_TYPE_VF_P0 ||
+			    plat_type == PLAT_TYPE_VF_P1)
+				phy_addr_off = 8;
+			phy_addr_off += np->port;
+			break;
+
+		default:
+			return -EINVAL;
+		}
+	}
+
+	np->phy_ops = tp->ops;
+	np->phy_addr = tp->phy_addr_base + phy_addr_off;
+
+	return 0;
+}
+
+static int niu_init_link(struct niu *np)
+{
+	struct niu_parent *parent = np->parent;
+	int err, ignore;
+
+	if (parent->plat_type == PLAT_TYPE_NIU) {
+		err = niu_xcvr_init(np);
+		if (err)
+			return err;
+		msleep(200);
+	}
+	err = niu_serdes_init(np);
+	if (err)
+		return err;
+	msleep(200);
+	err = niu_xcvr_init(np);
+	if (!err)
+		niu_link_status(np, &ignore);
+	return 0;
+}
+
+static void niu_set_primary_mac(struct niu *np, unsigned char *addr)
+{
+	u16 reg0 = addr[4] << 8 | addr[5];
+	u16 reg1 = addr[2] << 8 | addr[3];
+	u16 reg2 = addr[0] << 8 | addr[1];
+
+	if (np->flags & NIU_FLAGS_XMAC) {
+		nw64_mac(XMAC_ADDR0, reg0);
+		nw64_mac(XMAC_ADDR1, reg1);
+		nw64_mac(XMAC_ADDR2, reg2);
+	} else {
+		nw64_mac(BMAC_ADDR0, reg0);
+		nw64_mac(BMAC_ADDR1, reg1);
+		nw64_mac(BMAC_ADDR2, reg2);
+	}
+}
+
+static int niu_num_alt_addr(struct niu *np)
+{
+	if (np->flags & NIU_FLAGS_XMAC)
+		return XMAC_NUM_ALT_ADDR;
+	else
+		return BMAC_NUM_ALT_ADDR;
+}
+
+static int niu_set_alt_mac(struct niu *np, int index, unsigned char *addr)
+{
+	u16 reg0 = addr[4] << 8 | addr[5];
+	u16 reg1 = addr[2] << 8 | addr[3];
+	u16 reg2 = addr[0] << 8 | addr[1];
+
+	if (index >= niu_num_alt_addr(np))
+		return -EINVAL;
+
+	if (np->flags & NIU_FLAGS_XMAC) {
+		nw64_mac(XMAC_ALT_ADDR0(index), reg0);
+		nw64_mac(XMAC_ALT_ADDR1(index), reg1);
+		nw64_mac(XMAC_ALT_ADDR2(index), reg2);
+	} else {
+		nw64_mac(BMAC_ALT_ADDR0(index), reg0);
+		nw64_mac(BMAC_ALT_ADDR1(index), reg1);
+		nw64_mac(BMAC_ALT_ADDR2(index), reg2);
+	}
+
+	return 0;
+}
+
+static int niu_enable_alt_mac(struct niu *np, int index, int on)
+{
+	unsigned long reg;
+	u64 val, mask;
+
+	if (index >= niu_num_alt_addr(np))
+		return -EINVAL;
+
+	if (np->flags & NIU_FLAGS_XMAC)
+		reg = XMAC_ADDR_CMPEN;
+	else
+		reg = BMAC_ADDR_CMPEN;
+
+	mask = 1 << index;
+
+	val = nr64_mac(reg);
+	if (on)
+		val |= mask;
+	else
+		val &= ~mask;
+	nw64_mac(reg, val);
+
+	return 0;
+}
+
+static void __set_rdc_table_num_hw(struct niu *np, unsigned long reg,
+				   int num, int mac_pref)
+{
+	u64 val = nr64_mac(reg);
+	val &= ~(HOST_INFO_MACRDCTBLN | HOST_INFO_MPR);
+	val |= num;
+	if (mac_pref)
+		val |= HOST_INFO_MPR;
+	nw64_mac(reg, val);
+}
+
+static int __set_rdc_table_num(struct niu *np,
+			       int xmac_index, int bmac_index,
+			       int rdc_table_num, int mac_pref)
+{
+	unsigned long reg;
+
+	if (rdc_table_num & ~HOST_INFO_MACRDCTBLN)
+		return -EINVAL;
+	if (np->flags & NIU_FLAGS_XMAC)
+		reg = XMAC_HOST_INFO(xmac_index);
+	else
+		reg = BMAC_HOST_INFO(bmac_index);
+	__set_rdc_table_num_hw(np, reg, rdc_table_num, mac_pref);
+	return 0;
+}
+
+static int niu_set_primary_mac_rdc_table(struct niu *np, int table_num,
+					 int mac_pref)
+{
+	return __set_rdc_table_num(np, 17, 0, table_num, mac_pref);
+}
+
+static int niu_set_multicast_mac_rdc_table(struct niu *np, int table_num,
+					   int mac_pref)
+{
+	return __set_rdc_table_num(np, 16, 8, table_num, mac_pref);
+}
+
+static int niu_set_alt_mac_rdc_table(struct niu *np, int idx,
+				     int table_num, int mac_pref)
+{
+	if (idx >= niu_num_alt_addr(np))
+		return -EINVAL;
+	return __set_rdc_table_num(np, idx, idx + 1, table_num, mac_pref);
+}
+
+static u64 vlan_entry_set_parity(u64 reg_val)
+{
+	u64 port01_mask;
+	u64 port23_mask;
+
+	port01_mask = 0x00ff;
+	port23_mask = 0xff00;
+
+	if (hweight64(reg_val & port01_mask) & 1)
+		reg_val |= ENET_VLAN_TBL_PARITY0;
+	else
+		reg_val &= ~ENET_VLAN_TBL_PARITY0;
+
+	if (hweight64(reg_val & port23_mask) & 1)
+		reg_val |= ENET_VLAN_TBL_PARITY1;
+	else
+		reg_val &= ~ENET_VLAN_TBL_PARITY1;
+
+	return reg_val;
+}
+
+static void vlan_tbl_write(struct niu *np, unsigned long index,
+			   int port, int vpr, int rdc_table)
+{
+	u64 reg_val = nr64(ENET_VLAN_TBL(index));
+
+	reg_val &= ~((ENET_VLAN_TBL_VPR |
+		      ENET_VLAN_TBL_VLANRDCTBLN) <<
+		     ENET_VLAN_TBL_SHIFT(port));
+	if (vpr)
+		reg_val |= (ENET_VLAN_TBL_VPR <<
+			    ENET_VLAN_TBL_SHIFT(port));
+	reg_val |= (rdc_table << ENET_VLAN_TBL_SHIFT(port));
+
+	reg_val = vlan_entry_set_parity(reg_val);
+
+	nw64(ENET_VLAN_TBL(index), reg_val);
+}
+
+static void vlan_tbl_clear(struct niu *np)
+{
+	int i;
+
+	for (i = 0; i < ENET_VLAN_TBL_NUM_ENTRIES; i++)
+		nw64(ENET_VLAN_TBL(i), 0);
+}
+
+static int tcam_wait_bit(struct niu *np, u64 bit)
+{
+	int limit = 1000;
+
+	while (--limit > 0) {
+		if (nr64(TCAM_CTL) & bit)
+			break;
+		udelay(1);
+	}
+	if (limit < 0)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int tcam_flush(struct niu *np, int index)
+{
+	nw64(TCAM_KEY_0, 0x00);
+	nw64(TCAM_KEY_MASK_0, 0xff);
+	nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_WRITE | index));
+
+	return tcam_wait_bit(np, TCAM_CTL_STAT);
+}
+
+#if 0
+static int tcam_read(struct niu *np, int index,
+		     u64 *key, u64 *mask)
+{
+	int err;
+
+	nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_READ | index));
+	err = tcam_wait_bit(np, TCAM_CTL_STAT);
+	if (!err) {
+		key[0] = nr64(TCAM_KEY_0);
+		key[1] = nr64(TCAM_KEY_1);
+		key[2] = nr64(TCAM_KEY_2);
+		key[3] = nr64(TCAM_KEY_3);
+		mask[0] = nr64(TCAM_KEY_MASK_0);
+		mask[1] = nr64(TCAM_KEY_MASK_1);
+		mask[2] = nr64(TCAM_KEY_MASK_2);
+		mask[3] = nr64(TCAM_KEY_MASK_3);
+	}
+	return err;
+}
+#endif
+
+static int tcam_write(struct niu *np, int index,
+		      u64 *key, u64 *mask)
+{
+	nw64(TCAM_KEY_0, key[0]);
+	nw64(TCAM_KEY_1, key[1]);
+	nw64(TCAM_KEY_2, key[2]);
+	nw64(TCAM_KEY_3, key[3]);
+	nw64(TCAM_KEY_MASK_0, mask[0]);
+	nw64(TCAM_KEY_MASK_1, mask[1]);
+	nw64(TCAM_KEY_MASK_2, mask[2]);
+	nw64(TCAM_KEY_MASK_3, mask[3]);
+	nw64(TCAM_CTL, (TCAM_CTL_RWC_TCAM_WRITE | index));
+
+	return tcam_wait_bit(np, TCAM_CTL_STAT);
+}
+
+#if 0
+static int tcam_assoc_read(struct niu *np, int index, u64 *data)
+{
+	int err;
+
+	nw64(TCAM_CTL, (TCAM_CTL_RWC_RAM_READ | index));
+	err = tcam_wait_bit(np, TCAM_CTL_STAT);
+	if (!err)
+		*data = nr64(TCAM_KEY_1);
+
+	return err;
+}
+#endif
+
+static int tcam_assoc_write(struct niu *np, int index, u64 assoc_data)
+{
+	nw64(TCAM_KEY_1, assoc_data);
+	nw64(TCAM_CTL, (TCAM_CTL_RWC_RAM_WRITE | index));
+
+	return tcam_wait_bit(np, TCAM_CTL_STAT);
+}
+
+static void tcam_enable(struct niu *np, int on)
+{
+	u64 val = nr64(FFLP_CFG_1);
+
+	if (on)
+		val &= ~FFLP_CFG_1_TCAM_DIS;
+	else
+		val |= FFLP_CFG_1_TCAM_DIS;
+	nw64(FFLP_CFG_1, val);
+}
+
+static void tcam_set_lat_and_ratio(struct niu *np, u64 latency, u64 ratio)
+{
+	u64 val = nr64(FFLP_CFG_1);
+
+	val &= ~(FFLP_CFG_1_FFLPINITDONE |
+		 FFLP_CFG_1_CAMLAT |
+		 FFLP_CFG_1_CAMRATIO);
+	val |= (latency << FFLP_CFG_1_CAMLAT_SHIFT);
+	val |= (ratio << FFLP_CFG_1_CAMRATIO_SHIFT);
+	nw64(FFLP_CFG_1, val);
+
+	val = nr64(FFLP_CFG_1);
+	val |= FFLP_CFG_1_FFLPINITDONE;
+	nw64(FFLP_CFG_1, val);
+}
+
+static int tcam_user_eth_class_enable(struct niu *np, unsigned long class,
+				      int on)
+{
+	unsigned long reg;
+	u64 val;
+
+	if (class < CLASS_CODE_ETHERTYPE1 ||
+	    class > CLASS_CODE_ETHERTYPE2)
+		return -EINVAL;
+
+	reg = L2_CLS(class - CLASS_CODE_ETHERTYPE1);
+	val = nr64(reg);
+	if (on)
+		val |= L2_CLS_VLD;
+	else
+		val &= ~L2_CLS_VLD;
+	nw64(reg, val);
+
+	return 0;
+}
+
+#if 0
+static int tcam_user_eth_class_set(struct niu *np, unsigned long class,
+				   u64 ether_type)
+{
+	unsigned long reg;
+	u64 val;
+
+	if (class < CLASS_CODE_ETHERTYPE1 ||
+	    class > CLASS_CODE_ETHERTYPE2 ||
+	    (ether_type & ~(u64)0xffff) != 0)
+		return -EINVAL;
+
+	reg = L2_CLS(class - CLASS_CODE_ETHERTYPE1);
+	val = nr64(reg);
+	val &= ~L2_CLS_ETYPE;
+	val |= (ether_type << L2_CLS_ETYPE_SHIFT);
+	nw64(reg, val);
+
+	return 0;
+}
+#endif
+
+static int tcam_user_ip_class_enable(struct niu *np, unsigned long class,
+				     int on)
+{
+	unsigned long reg;
+	u64 val;
+
+	if (class < CLASS_CODE_USER_PROG1 ||
+	    class > CLASS_CODE_USER_PROG4)
+		return -EINVAL;
+
+	reg = L3_CLS(class - CLASS_CODE_USER_PROG1);
+	val = nr64(reg);
+	if (on)
+		val |= L3_CLS_VALID;
+	else
+		val &= ~L3_CLS_VALID;
+	nw64(reg, val);
+
+	return 0;
+}
+
+#if 0
+static int tcam_user_ip_class_set(struct niu *np, unsigned long class,
+				  int ipv6, u64 protocol_id,
+				  u64 tos_mask, u64 tos_val)
+{
+	unsigned long reg;
+	u64 val;
+
+	if (class < CLASS_CODE_USER_PROG1 ||
+	    class > CLASS_CODE_USER_PROG4 ||
+	    (protocol_id & ~(u64)0xff) != 0 ||
+	    (tos_mask & ~(u64)0xff) != 0 ||
+	    (tos_val & ~(u64)0xff) != 0)
+		return -EINVAL;
+
+	reg = L3_CLS(class - CLASS_CODE_USER_PROG1);
+	val = nr64(reg);
+	val &= ~(L3_CLS_IPVER | L3_CLS_PID |
+		 L3_CLS_TOSMASK | L3_CLS_TOS);
+	if (ipv6)
+		val |= L3_CLS_IPVER;
+	val |= (protocol_id << L3_CLS_PID_SHIFT);
+	val |= (tos_mask << L3_CLS_TOSMASK_SHIFT);
+	val |= (tos_val << L3_CLS_TOS_SHIFT);
+	nw64(reg, val);
+
+	return 0;
+}
+#endif
+
+static int tcam_early_init(struct niu *np)
+{
+	unsigned long i;
+	int err;
+
+	tcam_enable(np, 0);
+	tcam_set_lat_and_ratio(np,
+			       DEFAULT_TCAM_LATENCY,
+			       DEFAULT_TCAM_ACCESS_RATIO);
+	for (i = CLASS_CODE_ETHERTYPE1; i <= CLASS_CODE_ETHERTYPE2; i++) {
+		err = tcam_user_eth_class_enable(np, i, 0);
+		if (err)
+			return err;
+	}
+	for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_USER_PROG4; i++) {
+		err = tcam_user_ip_class_enable(np, i, 0);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int tcam_flush_all(struct niu *np)
+{
+	unsigned long i;
+
+	for (i = 0; i < np->parent->tcam_num_entries; i++) {
+		int err = tcam_flush(np, i);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+static u64 hash_addr_regval(unsigned long index, unsigned long num_entries)
+{
+	return ((u64)index | (num_entries == 1 ?
+			      HASH_TBL_ADDR_AUTOINC : 0));
+}
+
+#if 0
+static int hash_read(struct niu *np, unsigned long partition,
+		     unsigned long index, unsigned long num_entries,
+		     u64 *data)
+{
+	u64 val = hash_addr_regval(index, num_entries);
+	unsigned long i;
+
+	if (partition >= FCRAM_NUM_PARTITIONS ||
+	    index + num_entries > FCRAM_SIZE)
+		return -EINVAL;
+
+	nw64(HASH_TBL_ADDR(partition), val);
+	for (i = 0; i < num_entries; i++)
+		data[i] = nr64(HASH_TBL_DATA(partition));
+
+	return 0;
+}
+#endif
+
+static int hash_write(struct niu *np, unsigned long partition,
+		      unsigned long index, unsigned long num_entries,
+		      u64 *data)
+{
+	u64 val = hash_addr_regval(index, num_entries);
+	unsigned long i;
+
+	if (partition >= FCRAM_NUM_PARTITIONS ||
+	    index + (num_entries * 8) > FCRAM_SIZE)
+		return -EINVAL;
+
+	nw64(HASH_TBL_ADDR(partition), val);
+	for (i = 0; i < num_entries; i++)
+		nw64(HASH_TBL_DATA(partition), data[i]);
+
+	return 0;
+}
+
+static void fflp_reset(struct niu *np)
+{
+	u64 val;
+
+	nw64(FFLP_CFG_1, FFLP_CFG_1_PIO_FIO_RST);
+	udelay(10);
+	nw64(FFLP_CFG_1, 0);
+
+	val = FFLP_CFG_1_FCRAMOUTDR_NORMAL | FFLP_CFG_1_FFLPINITDONE;
+	nw64(FFLP_CFG_1, val);
+}
+
+static void fflp_set_timings(struct niu *np)
+{
+	u64 val = nr64(FFLP_CFG_1);
+
+	val &= ~FFLP_CFG_1_FFLPINITDONE;
+	val |= (DEFAULT_FCRAMRATIO << FFLP_CFG_1_FCRAMRATIO_SHIFT);
+	nw64(FFLP_CFG_1, val);
+
+	val = nr64(FFLP_CFG_1);
+	val |= FFLP_CFG_1_FFLPINITDONE;
+	nw64(FFLP_CFG_1, val);
+
+	val = nr64(FCRAM_REF_TMR);
+	val &= ~(FCRAM_REF_TMR_MAX | FCRAM_REF_TMR_MIN);
+	val |= (DEFAULT_FCRAM_REFRESH_MAX << FCRAM_REF_TMR_MAX_SHIFT);
+	val |= (DEFAULT_FCRAM_REFRESH_MIN << FCRAM_REF_TMR_MIN_SHIFT);
+	nw64(FCRAM_REF_TMR, val);
+}
+
+static int fflp_set_partition(struct niu *np, u64 partition,
+			      u64 mask, u64 base, int enable)
+{
+	unsigned long reg;
+	u64 val;
+
+	if (partition >= FCRAM_NUM_PARTITIONS ||
+	    (mask & ~(u64)0x1f) != 0 ||
+	    (base & ~(u64)0x1f) != 0)
+		return -EINVAL;
+
+	reg = FLW_PRT_SEL(partition);
+
+	val = nr64(reg);
+	val &= ~(FLW_PRT_SEL_EXT | FLW_PRT_SEL_MASK | FLW_PRT_SEL_BASE);
+	val |= (mask << FLW_PRT_SEL_MASK_SHIFT);
+	val |= (base << FLW_PRT_SEL_BASE_SHIFT);
+	if (enable)
+		val |= FLW_PRT_SEL_EXT;
+	nw64(reg, val);
+
+	return 0;
+}
+
+static int fflp_disable_all_partitions(struct niu *np)
+{
+	unsigned long i;
+
+	for (i = 0; i < FCRAM_NUM_PARTITIONS; i++) {
+		int err = fflp_set_partition(np, 0, 0, 0, 0);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+static void fflp_llcsnap_enable(struct niu *np, int on)
+{
+	u64 val = nr64(FFLP_CFG_1);
+
+	if (on)
+		val |= FFLP_CFG_1_LLCSNAP;
+	else
+		val &= ~FFLP_CFG_1_LLCSNAP;
+	nw64(FFLP_CFG_1, val);
+}
+
+static void fflp_errors_enable(struct niu *np, int on)
+{
+	u64 val = nr64(FFLP_CFG_1);
+
+	if (on)
+		val &= ~FFLP_CFG_1_ERRORDIS;
+	else
+		val |= FFLP_CFG_1_ERRORDIS;
+	nw64(FFLP_CFG_1, val);
+}
+
+static int fflp_hash_clear(struct niu *np)
+{
+	struct fcram_hash_ipv4 ent;
+	unsigned long i;
+
+	/* IPV4 hash entry with valid bit clear, rest is don't care.  */
+	memset(&ent, 0, sizeof(ent));
+	ent.header = HASH_HEADER_EXT;
+
+	for (i = 0; i < FCRAM_SIZE; i += sizeof(ent)) {
+		int err = hash_write(np, 0, i, 1, (u64 *) &ent);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+static int fflp_early_init(struct niu *np)
+{
+	struct niu_parent *parent;
+	unsigned long flags;
+	int err;
+
+	niu_lock_parent(np, flags);
+
+	parent = np->parent;
+	err = 0;
+	if (!(parent->flags & PARENT_FLGS_CLS_HWINIT)) {
+		niudbg(PROBE, "fflp_early_init: Initting hw on port %u\n",
+		       np->port);
+		if (np->parent->plat_type != PLAT_TYPE_NIU) {
+			fflp_reset(np);
+			fflp_set_timings(np);
+			err = fflp_disable_all_partitions(np);
+			if (err) {
+				niudbg(PROBE, "fflp_disable_all_partitions "
+				       "failed, err=%d\n", err);
+				goto out;
+			}
+		}
+
+		err = tcam_early_init(np);
+		if (err) {
+			niudbg(PROBE, "tcam_early_init failed, err=%d\n",
+			       err);
+			goto out;
+		}
+		fflp_llcsnap_enable(np, 1);
+		fflp_errors_enable(np, 0);
+		nw64(H1POLY, 0);
+		nw64(H2POLY, 0);
+
+		err = tcam_flush_all(np);
+		if (err) {
+			niudbg(PROBE, "tcam_flush_all failed, err=%d\n",
+			       err);
+			goto out;
+		}
+		if (np->parent->plat_type != PLAT_TYPE_NIU) {
+			err = fflp_hash_clear(np);
+			if (err) {
+				niudbg(PROBE, "fflp_hash_clear failed, "
+				       "err=%d\n", err);
+				goto out;
+			}
+		}
+
+		vlan_tbl_clear(np);
+
+		niudbg(PROBE, "fflp_early_init: Success\n");
+		parent->flags |= PARENT_FLGS_CLS_HWINIT;
+	}
+out:
+	niu_unlock_parent(np, flags);
+	return err;
+}
+
+static int niu_set_flow_key(struct niu *np, unsigned long class_code, u64 key)
+{
+	if (class_code < CLASS_CODE_USER_PROG1 ||
+	    class_code > CLASS_CODE_SCTP_IPV6)
+		return -EINVAL;
+
+	nw64(FLOW_KEY(class_code - CLASS_CODE_USER_PROG1), key);
+	return 0;
+}
+
+static int niu_set_tcam_key(struct niu *np, unsigned long class_code, u64 key)
+{
+	if (class_code < CLASS_CODE_USER_PROG1 ||
+	    class_code > CLASS_CODE_SCTP_IPV6)
+		return -EINVAL;
+
+	nw64(TCAM_KEY(class_code - CLASS_CODE_USER_PROG1), key);
+	return 0;
+}
+
+static void niu_rx_skb_append(struct sk_buff *skb, struct page *page,
+			      u32 offset, u32 size)
+{
+	int i = skb_shinfo(skb)->nr_frags;
+	skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+	frag->page = page;
+	frag->page_offset = offset;
+	frag->size = size;
+
+	skb->len += size;
+	skb->data_len += size;
+	skb->truesize += size;
+
+	skb_shinfo(skb)->nr_frags = i + 1;
+}
+
+static unsigned int niu_hash_rxaddr(struct rx_ring_info *rp, u64 a)
+{
+	a >>= PAGE_SHIFT;
+	a ^= (a >> ilog2(MAX_RBR_RING_SIZE));
+
+	return (a & (MAX_RBR_RING_SIZE - 1));
+}
+
+static struct page *niu_find_rxpage(struct rx_ring_info *rp, u64 addr,
+				    struct page ***link)
+{
+	unsigned int h = niu_hash_rxaddr(rp, addr);
+	struct page *p, **pp;
+
+	addr &= PAGE_MASK;
+	pp = &rp->rxhash[h];
+	for (; (p = *pp) != NULL; pp = (struct page **) &p->mapping) {
+		if (p->index == addr) {
+			*link = pp;
+			break;
+		}
+	}
+
+	return p;
+}
+
+static void niu_hash_page(struct rx_ring_info *rp, struct page *page, u64 base)
+{
+	unsigned int h = niu_hash_rxaddr(rp, base);
+
+	page->index = base;
+	page->mapping = (struct address_space *) rp->rxhash[h];
+	rp->rxhash[h] = page;
+}
+
+static int niu_rbr_add_page(struct niu *np, struct rx_ring_info *rp,
+			    gfp_t mask, int start_index)
+{
+	struct page *page;
+	u64 addr;
+	int i;
+
+	page = alloc_page(mask);
+	if (!page)
+		return -ENOMEM;
+
+	addr = np->ops->map_page(np->device, page, 0,
+				 PAGE_SIZE, DMA_FROM_DEVICE);
+
+	niu_hash_page(rp, page, addr);
+	if (rp->rbr_blocks_per_page > 1)
+		atomic_add(rp->rbr_blocks_per_page - 1,
+			   &compound_head(page)->_count);
+
+	for (i = 0; i < rp->rbr_blocks_per_page; i++) {
+		__le32 *rbr = &rp->rbr[start_index + i];
+
+		*rbr = cpu_to_le32(addr >> RBR_DESCR_ADDR_SHIFT);
+		addr += rp->rbr_block_size;
+	}
+
+	return 0;
+}
+
+static void niu_rbr_refill(struct niu *np, struct rx_ring_info *rp, gfp_t mask)
+{
+	int index = rp->rbr_index;
+
+	rp->rbr_pending++;
+	if ((rp->rbr_pending % rp->rbr_blocks_per_page) == 0) {
+		int err = niu_rbr_add_page(np, rp, mask, index);
+
+		if (unlikely(err)) {
+			rp->rbr_pending--;
+			return;
+		}
+
+		rp->rbr_index += rp->rbr_blocks_per_page;
+		BUG_ON(rp->rbr_index > rp->rbr_table_size);
+		if (rp->rbr_index == rp->rbr_table_size)
+			rp->rbr_index = 0;
+
+		if (rp->rbr_pending >= rp->rbr_kick_thresh) {
+			nw64(RBR_KICK(rp->rx_channel), rp->rbr_pending);
+			rp->rbr_pending = 0;
+		}
+	}
+}
+
+static int niu_rx_pkt_ignore(struct niu *np, struct rx_ring_info *rp)
+{
+	unsigned int index = rp->rcr_index;
+	int num_rcr = 0;
+
+	rp->rx_dropped++;
+	while (1) {
+		struct page *page, **link;
+		u64 addr, val;
+		u32 rcr_size;
+
+		num_rcr++;
+
+		val = le64_to_cpup(&rp->rcr[index]);
+		addr = (val & RCR_ENTRY_PKT_BUF_ADDR) <<
+			RCR_ENTRY_PKT_BUF_ADDR_SHIFT;
+		page = niu_find_rxpage(rp, addr, &link);
+
+		rcr_size = rp->rbr_sizes[(val & RCR_ENTRY_PKTBUFSZ) >>
+					 RCR_ENTRY_PKTBUFSZ_SHIFT];
+		if ((page->index + PAGE_SIZE) - rcr_size == addr) {
+			*link = (struct page *) page->mapping;
+			np->ops->unmap_page(np->device, page->index,
+					    PAGE_SIZE, DMA_FROM_DEVICE);
+			page->index = 0;
+			page->mapping = NULL;
+			__free_page(page);
+			rp->rbr_refill_pending++;
+		}
+
+		index = NEXT_RCR(rp, index);
+		if (!(val & RCR_ENTRY_MULTI))
+			break;
+
+	}
+	rp->rcr_index = index;
+
+	return num_rcr;
+}
+
+static int niu_process_rx_pkt(struct niu *np, struct rx_ring_info *rp)
+{
+	unsigned int index = rp->rcr_index;
+	struct sk_buff *skb;
+	int len, num_rcr;
+
+	skb = netdev_alloc_skb(np->dev, RX_SKB_ALLOC_SIZE);
+	if (unlikely(!skb))
+		return niu_rx_pkt_ignore(np, rp);
+
+	num_rcr = 0;
+	while (1) {
+		struct page *page, **link;
+		u32 rcr_size, append_size;
+		u64 addr, val, off;
+
+		num_rcr++;
+
+		val = le64_to_cpup(&rp->rcr[index]);
+
+		len = (val & RCR_ENTRY_L2_LEN) >>
+			RCR_ENTRY_L2_LEN_SHIFT;
+		len -= ETH_FCS_LEN;
+
+		addr = (val & RCR_ENTRY_PKT_BUF_ADDR) <<
+			RCR_ENTRY_PKT_BUF_ADDR_SHIFT;
+		page = niu_find_rxpage(rp, addr, &link);
+
+		rcr_size = rp->rbr_sizes[(val & RCR_ENTRY_PKTBUFSZ) >>
+					 RCR_ENTRY_PKTBUFSZ_SHIFT];
+
+		off = addr & ~PAGE_MASK;
+		append_size = rcr_size;
+		if (num_rcr == 1) {
+			int ptype;
+
+			off += 2;
+			append_size -= 2;
+
+			ptype = (val >> RCR_ENTRY_PKT_TYPE_SHIFT);
+			if ((ptype == RCR_PKT_TYPE_TCP ||
+			     ptype == RCR_PKT_TYPE_UDP) &&
+			    !(val & (RCR_ENTRY_NOPORT |
+				     RCR_ENTRY_ERROR)))
+				skb->ip_summed = CHECKSUM_UNNECESSARY;
+			else
+				skb->ip_summed = CHECKSUM_NONE;
+		}
+		if (!(val & RCR_ENTRY_MULTI))
+			append_size = len - skb->len;
+
+		niu_rx_skb_append(skb, page, off, append_size);
+		if ((page->index + rp->rbr_block_size) - rcr_size == addr) {
+			*link = (struct page *) page->mapping;
+			np->ops->unmap_page(np->device, page->index,
+					    PAGE_SIZE, DMA_FROM_DEVICE);
+			page->index = 0;
+			page->mapping = NULL;
+			rp->rbr_refill_pending++;
+		} else
+			get_page(page);
+
+		index = NEXT_RCR(rp, index);
+		if (!(val & RCR_ENTRY_MULTI))
+			break;
+
+	}
+	rp->rcr_index = index;
+
+	skb_reserve(skb, NET_IP_ALIGN);
+	__pskb_pull_tail(skb, min(len, NIU_RXPULL_MAX));
+
+	rp->rx_packets++;
+	rp->rx_bytes += skb->len;
+
+	skb->protocol = eth_type_trans(skb, np->dev);
+	netif_receive_skb(skb);
+
+	return num_rcr;
+}
+
+static int niu_rbr_fill(struct niu *np, struct rx_ring_info *rp, gfp_t mask)
+{
+	int blocks_per_page = rp->rbr_blocks_per_page;
+	int err, index = rp->rbr_index;
+
+	err = 0;
+	while (index < (rp->rbr_table_size - blocks_per_page)) {
+		err = niu_rbr_add_page(np, rp, mask, index);
+		if (err)
+			break;
+
+		index += blocks_per_page;
+	}
+
+	rp->rbr_index = index;
+	return err;
+}
+
+static void niu_rbr_free(struct niu *np, struct rx_ring_info *rp)
+{
+	int i;
+
+	for (i = 0; i < MAX_RBR_RING_SIZE; i++) {
+		struct page *page;
+
+		page = rp->rxhash[i];
+		while (page) {
+			struct page *next = (struct page *) page->mapping;
+			u64 base = page->index;
+
+			np->ops->unmap_page(np->device, base, PAGE_SIZE,
+					    DMA_FROM_DEVICE);
+			page->index = 0;
+			page->mapping = NULL;
+
+			__free_page(page);
+
+			page = next;
+		}
+	}
+
+	for (i = 0; i < rp->rbr_table_size; i++)
+		rp->rbr[i] = cpu_to_le32(0);
+	rp->rbr_index = 0;
+}
+
+static int release_tx_packet(struct niu *np, struct tx_ring_info *rp, int idx)
+{
+	struct tx_buff_info *tb = &rp->tx_buffs[idx];
+	struct sk_buff *skb = tb->skb;
+	struct tx_pkt_hdr *tp;
+	u64 tx_flags;
+	int i, len;
+
+	tp = (struct tx_pkt_hdr *) skb->data;
+	tx_flags = le64_to_cpup(&tp->flags);
+
+	rp->tx_packets++;
+	rp->tx_bytes += (((tx_flags & TXHDR_LEN) >> TXHDR_LEN_SHIFT) -
+			 ((tx_flags & TXHDR_PAD) / 2));
+
+	len = skb_headlen(skb);
+	np->ops->unmap_single(np->device, tb->mapping,
+			      len, DMA_TO_DEVICE);
+
+	if (le64_to_cpu(rp->descr[idx]) & TX_DESC_MARK)
+		rp->mark_pending--;
+
+	tb->skb = NULL;
+	do {
+		idx = NEXT_TX(rp, idx);
+		len -= MAX_TX_DESC_LEN;
+	} while (len > 0);
+
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+		tb = &rp->tx_buffs[idx];
+		BUG_ON(tb->skb != NULL);
+		np->ops->unmap_page(np->device, tb->mapping,
+				    skb_shinfo(skb)->frags[i].size,
+				    DMA_TO_DEVICE);
+		idx = NEXT_TX(rp, idx);
+	}
+
+	dev_kfree_skb(skb);
+
+	return idx;
+}
+
+#define NIU_TX_WAKEUP_THRESH(rp)		((rp)->pending / 4)
+
+static void niu_tx_work(struct niu *np, struct tx_ring_info *rp)
+{
+	u16 pkt_cnt, tmp;
+	int cons;
+	u64 cs;
+
+	cs = rp->tx_cs;
+	if (unlikely(!(cs & (TX_CS_MK | TX_CS_MMK))))
+		goto out;
+
+	tmp = pkt_cnt = (cs & TX_CS_PKT_CNT) >> TX_CS_PKT_CNT_SHIFT;
+	pkt_cnt = (pkt_cnt - rp->last_pkt_cnt) &
+		(TX_CS_PKT_CNT >> TX_CS_PKT_CNT_SHIFT);
+
+	rp->last_pkt_cnt = tmp;
+
+	cons = rp->cons;
+
+	niudbg(TX_DONE, "%s: niu_tx_work() pkt_cnt[%u] cons[%d]\n",
+	       np->dev->name, pkt_cnt, cons);
+
+	while (pkt_cnt--)
+		cons = release_tx_packet(np, rp, cons);
+
+	rp->cons = cons;
+	smp_mb();
+
+out:
+	if (unlikely(netif_queue_stopped(np->dev) &&
+		     (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp)))) {
+		netif_tx_lock(np->dev);
+		if (netif_queue_stopped(np->dev) &&
+		    (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp)))
+			netif_wake_queue(np->dev);
+		netif_tx_unlock(np->dev);
+	}
+}
+
+static int niu_rx_work(struct niu *np, struct rx_ring_info *rp, int budget)
+{
+	int qlen, rcr_done = 0, work_done = 0;
+	struct rxdma_mailbox *mbox = rp->mbox;
+	u64 stat;
+
+#if 1
+	stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel));
+	qlen = nr64(RCRSTAT_A(rp->rx_channel)) & RCRSTAT_A_QLEN;
+#else
+	stat = le64_to_cpup(&mbox->rx_dma_ctl_stat);
+	qlen = (le64_to_cpup(&mbox->rcrstat_a) & RCRSTAT_A_QLEN);
+#endif
+	mbox->rx_dma_ctl_stat = 0;
+	mbox->rcrstat_a = 0;
+
+	niudbg(RX_STATUS, "%s: niu_rx_work(chan[%d]), stat[%llx] qlen=%d\n",
+	       np->dev->name, rp->rx_channel, (unsigned long long) stat, qlen);
+
+	rcr_done = work_done = 0;
+	qlen = min(qlen, budget);
+	while (work_done < qlen) {
+		rcr_done += niu_process_rx_pkt(np, rp);
+		work_done++;
+	}
+
+	if (rp->rbr_refill_pending >= rp->rbr_kick_thresh) {
+		unsigned int i;
+
+		for (i = 0; i < rp->rbr_refill_pending; i++)
+			niu_rbr_refill(np, rp, GFP_ATOMIC);
+		rp->rbr_refill_pending = 0;
+	}
+
+	stat = (RX_DMA_CTL_STAT_MEX |
+		((u64)work_done << RX_DMA_CTL_STAT_PKTREAD_SHIFT) |
+		((u64)rcr_done << RX_DMA_CTL_STAT_PTRREAD_SHIFT));
+
+	nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat);
+
+	return work_done;
+}
+
+static int niu_poll_core(struct niu *np, struct niu_ldg *lp, int budget)
+{
+	u64 v0 = lp->v0;
+	u32 tx_vec = (v0 >> 32);
+	u32 rx_vec = (v0 & 0xffffffff);
+	int i, work_done = 0;
+
+	niudbg(INTR, "%s: niu_poll_core() v0[%016llx]\n",
+	       np->dev->name, (unsigned long long) v0);
+
+	for (i = 0; i < np->num_tx_rings; i++) {
+		struct tx_ring_info *rp = &np->tx_rings[i];
+		if (tx_vec & (1 << rp->tx_channel))
+			niu_tx_work(np, rp);
+		nw64(LD_IM0(LDN_TXDMA(rp->tx_channel)), 0);
+	}
+
+	for (i = 0; i < np->num_rx_rings; i++) {
+		struct rx_ring_info *rp = &np->rx_rings[i];
+
+		if (rx_vec & (1 << rp->rx_channel)) {
+			int this_work_done;
+
+			this_work_done = niu_rx_work(np, rp,
+						     budget);
+
+			budget -= this_work_done;
+			work_done += this_work_done;
+		}
+		nw64(LD_IM0(LDN_RXDMA(rp->rx_channel)), 0);
+	}
+
+	return work_done;
+}
+
+static int niu_poll(struct napi_struct *napi, int budget)
+{
+	struct niu_ldg *lp = container_of(napi, struct niu_ldg, napi);
+	struct niu *np = lp->np;
+	int work_done;
+
+	work_done = niu_poll_core(np, lp, budget);
+
+	if (work_done < budget) {
+		netif_rx_complete(np->dev, napi);
+		niu_ldg_rearm(np, lp, 1);
+	}
+	return work_done;
+}
+
+static void niu_log_rxchan_errors(struct niu *np, struct rx_ring_info *rp,
+				  u64 stat)
+{
+	dev_err(np->device, PFX "%s: RX channel %u errors ( ",
+		np->dev->name, rp->rx_channel);
+
+	if (stat & RX_DMA_CTL_STAT_RBR_TMOUT)
+		printk("RBR_TMOUT ");
+	if (stat & RX_DMA_CTL_STAT_RSP_CNT_ERR)
+		printk("RSP_CNT ");
+	if (stat & RX_DMA_CTL_STAT_BYTE_EN_BUS)
+		printk("BYTE_EN_BUS ");
+	if (stat & RX_DMA_CTL_STAT_RSP_DAT_ERR)
+		printk("RSP_DAT ");
+	if (stat & RX_DMA_CTL_STAT_RCR_ACK_ERR)
+		printk("RCR_ACK ");
+	if (stat & RX_DMA_CTL_STAT_RCR_SHA_PAR)
+		printk("RCR_SHA_PAR ");
+	if (stat & RX_DMA_CTL_STAT_RBR_PRE_PAR)
+		printk("RBR_PRE_PAR ");
+	if (stat & RX_DMA_CTL_STAT_CONFIG_ERR)
+		printk("CONFIG ");
+	if (stat & RX_DMA_CTL_STAT_RCRINCON)
+		printk("RCRINCON ");
+	if (stat & RX_DMA_CTL_STAT_RCRFULL)
+		printk("RCRFULL ");
+	if (stat & RX_DMA_CTL_STAT_RBRFULL)
+		printk("RBRFULL ");
+	if (stat & RX_DMA_CTL_STAT_RBRLOGPAGE)
+		printk("RBRLOGPAGE ");
+	if (stat & RX_DMA_CTL_STAT_CFIGLOGPAGE)
+		printk("CFIGLOGPAGE ");
+	if (stat & RX_DMA_CTL_STAT_DC_FIFO_ERR)
+		printk("DC_FIDO ");
+
+	printk(")\n");
+}
+
+static int niu_rx_error(struct niu *np, struct rx_ring_info *rp)
+{
+	u64 stat = nr64(RX_DMA_CTL_STAT(rp->rx_channel));
+	int err = 0;
+
+	dev_err(np->device, PFX "%s: RX channel %u error, stat[%llx]\n",
+		np->dev->name, rp->rx_channel, (unsigned long long) stat);
+
+	niu_log_rxchan_errors(np, rp, stat);
+
+	if (stat & (RX_DMA_CTL_STAT_CHAN_FATAL |
+		    RX_DMA_CTL_STAT_PORT_FATAL))
+		err = -EINVAL;
+
+	nw64(RX_DMA_CTL_STAT(rp->rx_channel),
+	     stat & RX_DMA_CTL_WRITE_CLEAR_ERRS);
+
+	return err;
+}
+
+static void niu_log_txchan_errors(struct niu *np, struct tx_ring_info *rp,
+				  u64 cs)
+{
+	dev_err(np->device, PFX "%s: TX channel %u errors ( ",
+		np->dev->name, rp->tx_channel);
+
+	if (cs & TX_CS_MBOX_ERR)
+		printk("MBOX ");
+	if (cs & TX_CS_PKT_SIZE_ERR)
+		printk("PKT_SIZE ");
+	if (cs & TX_CS_TX_RING_OFLOW)
+		printk("TX_RING_OFLOW ");
+	if (cs & TX_CS_PREF_BUF_PAR_ERR)
+		printk("PREF_BUF_PAR ");
+	if (cs & TX_CS_NACK_PREF)
+		printk("NACK_PREF ");
+	if (cs & TX_CS_NACK_PKT_RD)
+		printk("NACK_PKT_RD ");
+	if (cs & TX_CS_CONF_PART_ERR)
+		printk("CONF_PART ");
+	if (cs & TX_CS_PKT_PRT_ERR)
+		printk("PKT_PTR ");
+
+	printk(")\n");
+}
+
+static int niu_tx_error(struct niu *np, struct tx_ring_info *rp)
+{
+	u64 cs, logh, logl;
+
+	cs = nr64(TX_CS(rp->tx_channel));
+	logh = nr64(TX_RNG_ERR_LOGH(rp->tx_channel));
+	logl = nr64(TX_RNG_ERR_LOGL(rp->tx_channel));
+
+	dev_err(np->device, PFX "%s: TX channel %u error, "
+		"cs[%llx] logh[%llx] logl[%llx]\n",
+		np->dev->name, rp->tx_channel,
+		(unsigned long long) cs,
+		(unsigned long long) logh,
+		(unsigned long long) logl);
+
+	niu_log_txchan_errors(np, rp, cs);
+
+	return -ENODEV;
+}
+
+static int niu_mif_interrupt(struct niu *np)
+{
+	u64 mif_status = nr64(MIF_STATUS);
+	int phy_mdint = 0;
+
+	if (np->flags & NIU_FLAGS_XMAC) {
+		u64 xrxmac_stat = nr64_mac(XRXMAC_STATUS);
+
+		if (xrxmac_stat & XRXMAC_STATUS_PHY_MDINT)
+			phy_mdint = 1;
+	}
+
+	dev_err(np->device, PFX "%s: MIF interrupt, "
+		"stat[%llx] phy_mdint(%d)\n",
+		np->dev->name, (unsigned long long) mif_status, phy_mdint);
+
+	return -ENODEV;
+}
+
+static void niu_xmac_interrupt(struct niu *np)
+{
+	struct niu_xmac_stats *mp = &np->mac_stats.xmac;
+	u64 val;
+
+	val = nr64_mac(XTXMAC_STATUS);
+	if (val & XTXMAC_STATUS_FRAME_CNT_EXP)
+		mp->tx_frames += TXMAC_FRM_CNT_COUNT;
+	if (val & XTXMAC_STATUS_BYTE_CNT_EXP)
+		mp->tx_bytes += TXMAC_BYTE_CNT_COUNT;
+	if (val & XTXMAC_STATUS_TXFIFO_XFR_ERR)
+		mp->tx_fifo_errors++;
+	if (val & XTXMAC_STATUS_TXMAC_OFLOW)
+		mp->tx_overflow_errors++;
+	if (val & XTXMAC_STATUS_MAX_PSIZE_ERR)
+		mp->tx_max_pkt_size_errors++;
+	if (val & XTXMAC_STATUS_TXMAC_UFLOW)
+		mp->tx_underflow_errors++;
+
+	val = nr64_mac(XRXMAC_STATUS);
+	if (val & XRXMAC_STATUS_LCL_FLT_STATUS)
+		mp->rx_local_faults++;
+	if (val & XRXMAC_STATUS_RFLT_DET)
+		mp->rx_remote_faults++;
+	if (val & XRXMAC_STATUS_LFLT_CNT_EXP)
+		mp->rx_link_faults += LINK_FAULT_CNT_COUNT;
+	if (val & XRXMAC_STATUS_ALIGNERR_CNT_EXP)
+		mp->rx_align_errors += RXMAC_ALIGN_ERR_CNT_COUNT;
+	if (val & XRXMAC_STATUS_RXFRAG_CNT_EXP)
+		mp->rx_frags += RXMAC_FRAG_CNT_COUNT;
+	if (val & XRXMAC_STATUS_RXMULTF_CNT_EXP)
+		mp->rx_mcasts += RXMAC_MC_FRM_CNT_COUNT;
+	if (val & XRXMAC_STATUS_RXBCAST_CNT_EXP)
+		mp->rx_bcasts += RXMAC_BC_FRM_CNT_COUNT;
+	if (val & XRXMAC_STATUS_RXBCAST_CNT_EXP)
+		mp->rx_bcasts += RXMAC_BC_FRM_CNT_COUNT;
+	if (val & XRXMAC_STATUS_RXHIST1_CNT_EXP)
+		mp->rx_hist_cnt1 += RXMAC_HIST_CNT1_COUNT;
+	if (val & XRXMAC_STATUS_RXHIST2_CNT_EXP)
+		mp->rx_hist_cnt2 += RXMAC_HIST_CNT2_COUNT;
+	if (val & XRXMAC_STATUS_RXHIST3_CNT_EXP)
+		mp->rx_hist_cnt3 += RXMAC_HIST_CNT3_COUNT;
+	if (val & XRXMAC_STATUS_RXHIST4_CNT_EXP)
+		mp->rx_hist_cnt4 += RXMAC_HIST_CNT4_COUNT;
+	if (val & XRXMAC_STATUS_RXHIST5_CNT_EXP)
+		mp->rx_hist_cnt5 += RXMAC_HIST_CNT5_COUNT;
+	if (val & XRXMAC_STATUS_RXHIST6_CNT_EXP)
+		mp->rx_hist_cnt6 += RXMAC_HIST_CNT6_COUNT;
+	if (val & XRXMAC_STATUS_RXHIST7_CNT_EXP)
+		mp->rx_hist_cnt7 += RXMAC_HIST_CNT7_COUNT;
+	if (val & XRXMAC_STAT_MSK_RXOCTET_CNT_EXP)
+		mp->rx_octets += RXMAC_BT_CNT_COUNT;
+	if (val & XRXMAC_STATUS_CVIOLERR_CNT_EXP)
+		mp->rx_code_violations += RXMAC_CD_VIO_CNT_COUNT;
+	if (val & XRXMAC_STATUS_LENERR_CNT_EXP)
+		mp->rx_len_errors += RXMAC_MPSZER_CNT_COUNT;
+	if (val & XRXMAC_STATUS_CRCERR_CNT_EXP)
+		mp->rx_crc_errors += RXMAC_CRC_ER_CNT_COUNT;
+	if (val & XRXMAC_STATUS_RXUFLOW)
+		mp->rx_underflows++;
+	if (val & XRXMAC_STATUS_RXOFLOW)
+		mp->rx_overflows++;
+
+	val = nr64_mac(XMAC_FC_STAT);
+	if (val & XMAC_FC_STAT_TX_MAC_NPAUSE)
+		mp->pause_off_state++;
+	if (val & XMAC_FC_STAT_TX_MAC_PAUSE)
+		mp->pause_on_state++;
+	if (val & XMAC_FC_STAT_RX_MAC_RPAUSE)
+		mp->pause_received++;
+}
+
+static void niu_bmac_interrupt(struct niu *np)
+{
+	struct niu_bmac_stats *mp = &np->mac_stats.bmac;
+	u64 val;
+
+	val = nr64_mac(BTXMAC_STATUS);
+	if (val & BTXMAC_STATUS_UNDERRUN)
+		mp->tx_underflow_errors++;
+	if (val & BTXMAC_STATUS_MAX_PKT_ERR)
+		mp->tx_max_pkt_size_errors++;
+	if (val & BTXMAC_STATUS_BYTE_CNT_EXP)
+		mp->tx_bytes += BTXMAC_BYTE_CNT_COUNT;
+	if (val & BTXMAC_STATUS_FRAME_CNT_EXP)
+		mp->tx_frames += BTXMAC_FRM_CNT_COUNT;
+
+	val = nr64_mac(BRXMAC_STATUS);
+	if (val & BRXMAC_STATUS_OVERFLOW)
+		mp->rx_overflows++;
+	if (val & BRXMAC_STATUS_FRAME_CNT_EXP)
+		mp->rx_frames += BRXMAC_FRAME_CNT_COUNT;
+	if (val & BRXMAC_STATUS_ALIGN_ERR_EXP)
+		mp->rx_align_errors += BRXMAC_ALIGN_ERR_CNT_COUNT;
+	if (val & BRXMAC_STATUS_CRC_ERR_EXP)
+		mp->rx_crc_errors += BRXMAC_ALIGN_ERR_CNT_COUNT;
+	if (val & BRXMAC_STATUS_LEN_ERR_EXP)
+		mp->rx_len_errors += BRXMAC_CODE_VIOL_ERR_CNT_COUNT;
+
+	val = nr64_mac(BMAC_CTRL_STATUS);
+	if (val & BMAC_CTRL_STATUS_NOPAUSE)
+		mp->pause_off_state++;
+	if (val & BMAC_CTRL_STATUS_PAUSE)
+		mp->pause_on_state++;
+	if (val & BMAC_CTRL_STATUS_PAUSE_RECV)
+		mp->pause_received++;
+}
+
+static int niu_mac_interrupt(struct niu *np)
+{
+	if (np->flags & NIU_FLAGS_XMAC)
+		niu_xmac_interrupt(np);
+	else
+		niu_bmac_interrupt(np);
+
+	return 0;
+}
+
+static void niu_log_device_error(struct niu *np, u64 stat)
+{
+	dev_err(np->device, PFX "%s: Core device errors ( ",
+		np->dev->name);
+
+	if (stat & SYS_ERR_MASK_META2)
+		printk("META2 ");
+	if (stat & SYS_ERR_MASK_META1)
+		printk("META1 ");
+	if (stat & SYS_ERR_MASK_PEU)
+		printk("PEU ");
+	if (stat & SYS_ERR_MASK_TXC)
+		printk("TXC ");
+	if (stat & SYS_ERR_MASK_RDMC)
+		printk("RDMC ");
+	if (stat & SYS_ERR_MASK_TDMC)
+		printk("TDMC ");
+	if (stat & SYS_ERR_MASK_ZCP)
+		printk("ZCP ");
+	if (stat & SYS_ERR_MASK_FFLP)
+		printk("FFLP ");
+	if (stat & SYS_ERR_MASK_IPP)
+		printk("IPP ");
+	if (stat & SYS_ERR_MASK_MAC)
+		printk("MAC ");
+	if (stat & SYS_ERR_MASK_SMX)
+		printk("SMX ");
+
+	printk(")\n");
+}
+
+static int niu_device_error(struct niu *np)
+{
+	u64 stat = nr64(SYS_ERR_STAT);
+
+	dev_err(np->device, PFX "%s: Core device error, stat[%llx]\n",
+		np->dev->name, (unsigned long long) stat);
+
+	niu_log_device_error(np, stat);
+
+	return -ENODEV;
+}
+
+static int niu_slowpath_interrupt(struct niu *np, struct niu_ldg *lp)
+{
+	u64 v0 = lp->v0;
+	u64 v1 = lp->v1;
+	u64 v2 = lp->v2;
+	int i, err = 0;
+
+	if (v1 & 0x00000000ffffffffULL) {
+		u32 rx_vec = (v1 & 0xffffffff);
+
+		for (i = 0; i < np->num_rx_rings; i++) {
+			struct rx_ring_info *rp = &np->rx_rings[i];
+
+			if (rx_vec & (1 << rp->rx_channel)) {
+				int r = niu_rx_error(np, rp);
+				if (r)
+					err = r;
+			}
+		}
+	}
+	if (v1 & 0x7fffffff00000000ULL) {
+		u32 tx_vec = (v1 >> 32) & 0x7fffffff;
+
+		for (i = 0; i < np->num_tx_rings; i++) {
+			struct tx_ring_info *rp = &np->tx_rings[i];
+
+			if (tx_vec & (1 << rp->tx_channel)) {
+				int r = niu_tx_error(np, rp);
+				if (r)
+					err = r;
+			}
+		}
+	}
+	if ((v0 | v1) & 0x8000000000000000ULL) {
+		int r = niu_mif_interrupt(np);
+		if (r)
+			err = r;
+	}
+	if (v2) {
+		if (v2 & 0x01ef) {
+			int r = niu_mac_interrupt(np);
+			if (r)
+				err = r;
+		}
+		if (v2 & 0x0210) {
+			int r = niu_device_error(np);
+			if (r)
+				err = r;
+		}
+	}
+
+	if (err)
+		niu_enable_interrupts(np, 0);
+
+	return -EINVAL;
+}
+
+static void niu_rxchan_intr(struct niu *np, struct rx_ring_info *rp,
+			    int ldn)
+{
+	struct rxdma_mailbox *mbox = rp->mbox;
+	u64 stat_write, stat = le64_to_cpup(&mbox->rx_dma_ctl_stat);
+
+	stat_write = (RX_DMA_CTL_STAT_RCRTHRES |
+		      RX_DMA_CTL_STAT_RCRTO);
+	nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat_write);
+
+	niudbg(INTR, "%s: rxchan_intr stat[%llx]\n",
+	       np->dev->name, (unsigned long long) stat);
+}
+
+static void niu_txchan_intr(struct niu *np, struct tx_ring_info *rp,
+			    int ldn)
+{
+	rp->tx_cs = nr64(TX_CS(rp->tx_channel));
+
+	niudbg(INTR, "%s: txchan_intr cs[%llx]\n",
+	       np->dev->name, (unsigned long long) rp->tx_cs);
+}
+
+static void __niu_fastpath_interrupt(struct niu *np, int ldg, u64 v0)
+{
+	struct niu_parent *parent = np->parent;
+	u32 rx_vec, tx_vec;
+	int i;
+
+	tx_vec = (v0 >> 32);
+	rx_vec = (v0 & 0xffffffff);
+
+	for (i = 0; i < np->num_rx_rings; i++) {
+		struct rx_ring_info *rp = &np->rx_rings[i];
+		int ldn = LDN_RXDMA(rp->rx_channel);
+
+		if (parent->ldg_map[ldn] != ldg)
+			continue;
+
+		nw64(LD_IM0(ldn), LD_IM0_MASK);
+		if (rx_vec & (1 << rp->rx_channel))
+			niu_rxchan_intr(np, rp, ldn);
+	}
+
+	for (i = 0; i < np->num_tx_rings; i++) {
+		struct tx_ring_info *rp = &np->tx_rings[i];
+		int ldn = LDN_TXDMA(rp->tx_channel);
+
+		if (parent->ldg_map[ldn] != ldg)
+			continue;
+
+		nw64(LD_IM0(ldn), LD_IM0_MASK);
+		if (tx_vec & (1 << rp->tx_channel))
+			niu_txchan_intr(np, rp, ldn);
+	}
+}
+
+static void niu_schedule_napi(struct niu *np, struct niu_ldg *lp,
+			      u64 v0, u64 v1, u64 v2)
+{
+	if (likely(netif_rx_schedule_prep(np->dev, &lp->napi))) {
+		lp->v0 = v0;
+		lp->v1 = v1;
+		lp->v2 = v2;
+		__niu_fastpath_interrupt(np, lp->ldg_num, v0);
+		__netif_rx_schedule(np->dev, &lp->napi);
+	}
+}
+
+static irqreturn_t niu_interrupt(int irq, void *dev_id)
+{
+	struct niu_ldg *lp = dev_id;
+	struct niu *np = lp->np;
+	int ldg = lp->ldg_num;
+	unsigned long flags;
+	u64 v0, v1, v2;
+
+	if (netif_msg_intr(np))
+		printk(KERN_DEBUG PFX "niu_interrupt() ldg[%p](%d) ",
+		       lp, ldg);
+
+	spin_lock_irqsave(&np->lock, flags);
+
+	v0 = nr64(LDSV0(ldg));
+	v1 = nr64(LDSV1(ldg));
+	v2 = nr64(LDSV2(ldg));
+
+	if (netif_msg_intr(np))
+		printk("v0[%llx] v1[%llx] v2[%llx]\n",
+		       (unsigned long long) v0,
+		       (unsigned long long) v1,
+		       (unsigned long long) v2);
+
+	if (unlikely(!v0 && !v1 && !v2)) {
+		spin_unlock_irqrestore(&np->lock, flags);
+		return IRQ_NONE;
+	}
+
+	if (unlikely((v0 & ((u64)1 << LDN_MIF)) || v1 || v2)) {
+		int err = niu_slowpath_interrupt(np, lp);
+		if (err)
+			goto out;
+	}
+	if (likely(v0 & ~((u64)1 << LDN_MIF)))
+		niu_schedule_napi(np, lp, v0, v1, v2);
+	else
+		niu_ldg_rearm(np, lp, 1);
+out:
+	spin_unlock_irqrestore(&np->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static void niu_free_rx_ring_info(struct niu *np, struct rx_ring_info *rp)
+{
+	if (rp->mbox) {
+		np->ops->free_coherent(np->device,
+				       sizeof(struct rxdma_mailbox),
+				       rp->mbox, rp->mbox_dma);
+		rp->mbox = NULL;
+	}
+	if (rp->rcr) {
+		np->ops->free_coherent(np->device,
+				       MAX_RCR_RING_SIZE * sizeof(__le64),
+				       rp->rcr, rp->rcr_dma);
+		rp->rcr = NULL;
+		rp->rcr_table_size = 0;
+		rp->rcr_index = 0;
+	}
+	if (rp->rbr) {
+		niu_rbr_free(np, rp);
+
+		np->ops->free_coherent(np->device,
+				       MAX_RBR_RING_SIZE * sizeof(__le32),
+				       rp->rbr, rp->rbr_dma);
+		rp->rbr = NULL;
+		rp->rbr_table_size = 0;
+		rp->rbr_index = 0;
+	}
+	kfree(rp->rxhash);
+	rp->rxhash = NULL;
+}
+
+static void niu_free_tx_ring_info(struct niu *np, struct tx_ring_info *rp)
+{
+	if (rp->mbox) {
+		np->ops->free_coherent(np->device,
+				       sizeof(struct txdma_mailbox),
+				       rp->mbox, rp->mbox_dma);
+		rp->mbox = NULL;
+	}
+	if (rp->descr) {
+		int i;
+
+		for (i = 0; i < MAX_TX_RING_SIZE; i++) {
+			if (rp->tx_buffs[i].skb)
+				(void) release_tx_packet(np, rp, i);
+		}
+
+		np->ops->free_coherent(np->device,
+				       MAX_TX_RING_SIZE * sizeof(__le64),
+				       rp->descr, rp->descr_dma);
+		rp->descr = NULL;
+		rp->pending = 0;
+		rp->prod = 0;
+		rp->cons = 0;
+		rp->wrap_bit = 0;
+	}
+}
+
+static void niu_free_channels(struct niu *np)
+{
+	int i;
+
+	if (np->rx_rings) {
+		for (i = 0; i < np->num_rx_rings; i++) {
+			struct rx_ring_info *rp = &np->rx_rings[i];
+
+			niu_free_rx_ring_info(np, rp);
+		}
+		kfree(np->rx_rings);
+		np->rx_rings = NULL;
+		np->num_rx_rings = 0;
+	}
+
+	if (np->tx_rings) {
+		for (i = 0; i < np->num_tx_rings; i++) {
+			struct tx_ring_info *rp = &np->tx_rings[i];
+
+			niu_free_tx_ring_info(np, rp);
+		}
+		kfree(np->tx_rings);
+		np->tx_rings = NULL;
+		np->num_tx_rings = 0;
+	}
+}
+
+static int niu_alloc_rx_ring_info(struct niu *np,
+				  struct rx_ring_info *rp)
+{
+	BUILD_BUG_ON(sizeof(struct rxdma_mailbox) != 64);
+
+	rp->rxhash = kzalloc(MAX_RBR_RING_SIZE * sizeof(struct page *),
+			     GFP_KERNEL);
+	if (!rp->rxhash)
+		return -ENOMEM;
+
+	rp->mbox = np->ops->alloc_coherent(np->device,
+					   sizeof(struct rxdma_mailbox),
+					   &rp->mbox_dma, GFP_KERNEL);
+	if (!rp->mbox)
+		return -ENOMEM;
+	if ((unsigned long)rp->mbox & (64UL - 1)) {
+		dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
+			"RXDMA mailbox %p\n", np->dev->name, rp->mbox);
+		return -EINVAL;
+	}
+
+	rp->rcr = np->ops->alloc_coherent(np->device,
+					  MAX_RCR_RING_SIZE * sizeof(__le64),
+					  &rp->rcr_dma, GFP_KERNEL);
+	if (!rp->rcr)
+		return -ENOMEM;
+	if ((unsigned long)rp->rcr & (64UL - 1)) {
+		dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
+			"RXDMA RCR table %p\n", np->dev->name, rp->rcr);
+		return -EINVAL;
+	}
+	rp->rcr_table_size = MAX_RCR_RING_SIZE;
+	rp->rcr_index = 0;
+
+	rp->rbr = np->ops->alloc_coherent(np->device,
+					  MAX_RBR_RING_SIZE * sizeof(__le32),
+					  &rp->rbr_dma, GFP_KERNEL);
+	if (!rp->rbr)
+		return -ENOMEM;
+	if ((unsigned long)rp->rbr & (64UL - 1)) {
+		dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
+			"RXDMA RBR table %p\n", np->dev->name, rp->rbr);
+		return -EINVAL;
+	}
+	rp->rbr_table_size = MAX_RBR_RING_SIZE;
+	rp->rbr_index = 0;
+	rp->rbr_pending = 0;
+
+	return 0;
+}
+
+static void niu_set_max_burst(struct niu *np, struct tx_ring_info *rp)
+{
+	int mtu = np->dev->mtu;
+
+	/* These values are recommended by the HW designers for fair
+	 * utilization of DRR amongst the rings.
+	 */
+	rp->max_burst = mtu + 32;
+	if (rp->max_burst > 4096)
+		rp->max_burst = 4096;
+}
+
+static int niu_alloc_tx_ring_info(struct niu *np,
+				  struct tx_ring_info *rp)
+{
+	BUILD_BUG_ON(sizeof(struct txdma_mailbox) != 64);
+
+	rp->mbox = np->ops->alloc_coherent(np->device,
+					   sizeof(struct txdma_mailbox),
+					   &rp->mbox_dma, GFP_KERNEL);
+	if (!rp->mbox)
+		return -ENOMEM;
+	if ((unsigned long)rp->mbox & (64UL - 1)) {
+		dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
+			"TXDMA mailbox %p\n", np->dev->name, rp->mbox);
+		return -EINVAL;
+	}
+
+	rp->descr = np->ops->alloc_coherent(np->device,
+					    MAX_TX_RING_SIZE * sizeof(__le64),
+					    &rp->descr_dma, GFP_KERNEL);
+	if (!rp->descr)
+		return -ENOMEM;
+	if ((unsigned long)rp->descr & (64UL - 1)) {
+		dev_err(np->device, PFX "%s: Coherent alloc gives misaligned "
+			"TXDMA descr table %p\n", np->dev->name, rp->descr);
+		return -EINVAL;
+	}
+
+	rp->pending = MAX_TX_RING_SIZE;
+	rp->prod = 0;
+	rp->cons = 0;
+	rp->wrap_bit = 0;
+
+	/* XXX make these configurable... XXX */
+	rp->mark_freq = rp->pending / 4;
+
+	niu_set_max_burst(np, rp);
+
+	return 0;
+}
+
+static void niu_size_rbr(struct niu *np, struct rx_ring_info *rp)
+{
+	u16 bs;
+
+	switch (PAGE_SIZE) {
+	case 4 * 1024:
+	case 8 * 1024:
+	case 16 * 1024:
+	case 32 * 1024:
+		rp->rbr_block_size = PAGE_SIZE;
+		rp->rbr_blocks_per_page = 1;
+		break;
+
+	default:
+		if (PAGE_SIZE % (32 * 1024) == 0)
+			bs = 32 * 1024;
+		else if (PAGE_SIZE % (16 * 1024) == 0)
+			bs = 16 * 1024;
+		else if (PAGE_SIZE % (8 * 1024) == 0)
+			bs = 8 * 1024;
+		else if (PAGE_SIZE % (4 * 1024) == 0)
+			bs = 4 * 1024;
+		else
+			BUG();
+		rp->rbr_block_size = bs;
+		rp->rbr_blocks_per_page = PAGE_SIZE / bs;
+	}
+
+	rp->rbr_sizes[0] = 256;
+	rp->rbr_sizes[1] = 1024;
+	if (np->dev->mtu > ETH_DATA_LEN) {
+		switch (PAGE_SIZE) {
+		case 4 * 1024:
+			rp->rbr_sizes[2] = 4096;
+			break;
+
+		default:
+			rp->rbr_sizes[2] = 8192;
+			break;
+		}
+	} else {
+		rp->rbr_sizes[2] = 2048;
+	}
+	rp->rbr_sizes[3] = rp->rbr_block_size;
+}
+
+static int niu_alloc_channels(struct niu *np)
+{
+	struct niu_parent *parent = np->parent;
+	int first_rx_channel, first_tx_channel;
+	int i, port, err;
+
+	port = np->port;
+	first_rx_channel = first_tx_channel = 0;
+	for (i = 0; i < port; i++) {
+		first_rx_channel += parent->rxchan_per_port[i];
+		first_tx_channel += parent->txchan_per_port[i];
+	}
+
+	np->num_rx_rings = parent->rxchan_per_port[port];
+	np->num_tx_rings = parent->txchan_per_port[port];
+
+	np->rx_rings = kzalloc(np->num_rx_rings * sizeof(struct rx_ring_info),
+			       GFP_KERNEL);
+	err = -ENOMEM;
+	if (!np->rx_rings)
+		goto out_err;
+
+	for (i = 0; i < np->num_rx_rings; i++) {
+		struct rx_ring_info *rp = &np->rx_rings[i];
+
+		rp->np = np;
+		rp->rx_channel = first_rx_channel + i;
+
+		err = niu_alloc_rx_ring_info(np, rp);
+		if (err)
+			goto out_err;
+
+		niu_size_rbr(np, rp);
+
+		/* XXX better defaults, configurable, etc... XXX */
+		rp->nonsyn_window = 64;
+		rp->nonsyn_threshold = rp->rcr_table_size - 64;
+		rp->syn_window = 64;
+		rp->syn_threshold = rp->rcr_table_size - 64;
+		rp->rcr_pkt_threshold = 16;
+		rp->rcr_timeout = 8;
+		rp->rbr_kick_thresh = RBR_REFILL_MIN;
+		if (rp->rbr_kick_thresh < rp->rbr_blocks_per_page)
+			rp->rbr_kick_thresh = rp->rbr_blocks_per_page;
+
+		err = niu_rbr_fill(np, rp, GFP_KERNEL);
+		if (err)
+			return err;
+	}
+
+	np->tx_rings = kzalloc(np->num_tx_rings * sizeof(struct tx_ring_info),
+			       GFP_KERNEL);
+	err = -ENOMEM;
+	if (!np->tx_rings)
+		goto out_err;
+
+	for (i = 0; i < np->num_tx_rings; i++) {
+		struct tx_ring_info *rp = &np->tx_rings[i];
+
+		rp->np = np;
+		rp->tx_channel = first_tx_channel + i;
+
+		err = niu_alloc_tx_ring_info(np, rp);
+		if (err)
+			goto out_err;
+	}
+
+	return 0;
+
+out_err:
+	niu_free_channels(np);
+	return err;
+}
+
+static int niu_tx_cs_sng_poll(struct niu *np, int channel)
+{
+	int limit = 1000;
+
+	while (--limit > 0) {
+		u64 val = nr64(TX_CS(channel));
+		if (val & TX_CS_SNG_STATE)
+			return 0;
+	}
+	return -ENODEV;
+}
+
+static int niu_tx_channel_stop(struct niu *np, int channel)
+{
+	u64 val = nr64(TX_CS(channel));
+
+	val |= TX_CS_STOP_N_GO;
+	nw64(TX_CS(channel), val);
+
+	return niu_tx_cs_sng_poll(np, channel);
+}
+
+static int niu_tx_cs_reset_poll(struct niu *np, int channel)
+{
+	int limit = 1000;
+
+	while (--limit > 0) {
+		u64 val = nr64(TX_CS(channel));
+		if (!(val & TX_CS_RST))
+			return 0;
+	}
+	return -ENODEV;
+}
+
+static int niu_tx_channel_reset(struct niu *np, int channel)
+{
+	u64 val = nr64(TX_CS(channel));
+	int err;
+
+	val |= TX_CS_RST;
+	nw64(TX_CS(channel), val);
+
+	err = niu_tx_cs_reset_poll(np, channel);
+	if (!err)
+		nw64(TX_RING_KICK(channel), 0);
+
+	return err;
+}
+
+static int niu_tx_channel_lpage_init(struct niu *np, int channel)
+{
+	u64 val;
+
+	nw64(TX_LOG_MASK1(channel), 0);
+	nw64(TX_LOG_VAL1(channel), 0);
+	nw64(TX_LOG_MASK2(channel), 0);
+	nw64(TX_LOG_VAL2(channel), 0);
+	nw64(TX_LOG_PAGE_RELO1(channel), 0);
+	nw64(TX_LOG_PAGE_RELO2(channel), 0);
+	nw64(TX_LOG_PAGE_HDL(channel), 0);
+
+	val  = (u64)np->port << TX_LOG_PAGE_VLD_FUNC_SHIFT;
+	val |= (TX_LOG_PAGE_VLD_PAGE0 | TX_LOG_PAGE_VLD_PAGE1);
+	nw64(TX_LOG_PAGE_VLD(channel), val);
+
+	/* XXX TXDMA 32bit mode? XXX */
+
+	return 0;
+}
+
+static void niu_txc_enable_port(struct niu *np, int on)
+{
+	unsigned long flags;
+	u64 val, mask;
+
+	niu_lock_parent(np, flags);
+	val = nr64(TXC_CONTROL);
+	mask = (u64)1 << np->port;
+	if (on) {
+		val |= TXC_CONTROL_ENABLE | mask;
+	} else {
+		val &= ~mask;
+		if ((val & ~TXC_CONTROL_ENABLE) == 0)
+			val &= ~TXC_CONTROL_ENABLE;
+	}
+	nw64(TXC_CONTROL, val);
+	niu_unlock_parent(np, flags);
+}
+
+static void niu_txc_set_imask(struct niu *np, u64 imask)
+{
+	unsigned long flags;
+	u64 val;
+
+	niu_lock_parent(np, flags);
+	val = nr64(TXC_INT_MASK);
+	val &= ~TXC_INT_MASK_VAL(np->port);
+	val |= (imask << TXC_INT_MASK_VAL_SHIFT(np->port));
+	niu_unlock_parent(np, flags);
+}
+
+static void niu_txc_port_dma_enable(struct niu *np, int on)
+{
+	u64 val = 0;
+
+	if (on) {
+		int i;
+
+		for (i = 0; i < np->num_tx_rings; i++)
+			val |= (1 << np->tx_rings[i].tx_channel);
+	}
+	nw64(TXC_PORT_DMA(np->port), val);
+}
+
+static int niu_init_one_tx_channel(struct niu *np, struct tx_ring_info *rp)
+{
+	int err, channel = rp->tx_channel;
+	u64 val, ring_len;
+
+	err = niu_tx_channel_stop(np, channel);
+	if (err)
+		return err;
+
+	err = niu_tx_channel_reset(np, channel);
+	if (err)
+		return err;
+
+	err = niu_tx_channel_lpage_init(np, channel);
+	if (err)
+		return err;
+
+	nw64(TXC_DMA_MAX(channel), rp->max_burst);
+	nw64(TX_ENT_MSK(channel), 0);
+
+	if (rp->descr_dma & ~(TX_RNG_CFIG_STADDR_BASE |
+			      TX_RNG_CFIG_STADDR)) {
+		dev_err(np->device, PFX "%s: TX ring channel %d "
+			"DMA addr (%llx) is not aligned.\n",
+			np->dev->name, channel,
+			(unsigned long long) rp->descr_dma);
+		return -EINVAL;
+	}
+
+	/* The length field in TX_RNG_CFIG is measured in 64-byte
+	 * blocks.  rp->pending is the number of TX descriptors in
+	 * our ring, 8 bytes each, thus we divide by 8 bytes more
+	 * to get the proper value the chip wants.
+	 */
+	ring_len = (rp->pending / 8);
+
+	val = ((ring_len << TX_RNG_CFIG_LEN_SHIFT) |
+	       rp->descr_dma);
+	nw64(TX_RNG_CFIG(channel), val);
+
+	if (((rp->mbox_dma >> 32) & ~TXDMA_MBH_MBADDR) ||
+	    ((u32)rp->mbox_dma & ~TXDMA_MBL_MBADDR)) {
+		dev_err(np->device, PFX "%s: TX ring channel %d "
+			"MBOX addr (%llx) is has illegal bits.\n",
+			np->dev->name, channel,
+			(unsigned long long) rp->mbox_dma);
+		return -EINVAL;
+	}
+	nw64(TXDMA_MBH(channel), rp->mbox_dma >> 32);
+	nw64(TXDMA_MBL(channel), rp->mbox_dma & TXDMA_MBL_MBADDR);
+
+	nw64(TX_CS(channel), 0);
+
+	rp->last_pkt_cnt = 0;
+
+	return 0;
+}
+
+static void niu_init_rdc_groups(struct niu *np)
+{
+	struct niu_rdc_tables *tp = &np->parent->rdc_group_cfg[np->port];
+	int i, first_table_num = tp->first_table_num;
+
+	for (i = 0; i < tp->num_tables; i++) {
+		struct rdc_table *tbl = &tp->tables[i];
+		int this_table = first_table_num + i;
+		int slot;
+
+		for (slot = 0; slot < NIU_RDC_TABLE_SLOTS; slot++)
+			nw64(RDC_TBL(this_table, slot),
+			     tbl->rxdma_channel[slot]);
+	}
+
+	nw64(DEF_RDC(np->port), np->parent->rdc_default[np->port]);
+}
+
+static void niu_init_drr_weight(struct niu *np)
+{
+	int type = phy_decode(np->parent->port_phy, np->port);
+	u64 val;
+
+	switch (type) {
+	case PORT_TYPE_10G:
+		val = PT_DRR_WEIGHT_DEFAULT_10G;
+		break;
+
+	case PORT_TYPE_1G:
+	default:
+		val = PT_DRR_WEIGHT_DEFAULT_1G;
+		break;
+	}
+	nw64(PT_DRR_WT(np->port), val);
+}
+
+static int niu_init_hostinfo(struct niu *np)
+{
+	struct niu_parent *parent = np->parent;
+	struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port];
+	int i, err, num_alt = niu_num_alt_addr(np);
+	int first_rdc_table = tp->first_table_num;
+
+	err = niu_set_primary_mac_rdc_table(np, first_rdc_table, 1);
+	if (err)
+		return err;
+
+	err = niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1);
+	if (err)
+		return err;
+
+	for (i = 0; i < num_alt; i++) {
+		err = niu_set_alt_mac_rdc_table(np, i, first_rdc_table, 1);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int niu_rx_channel_reset(struct niu *np, int channel)
+{
+	return niu_set_and_wait_clear(np, RXDMA_CFIG1(channel),
+				      RXDMA_CFIG1_RST, 1000, 10,
+				      "RXDMA_CFIG1");
+}
+
+static int niu_rx_channel_lpage_init(struct niu *np, int channel)
+{
+	u64 val;
+
+	nw64(RX_LOG_MASK1(channel), 0);
+	nw64(RX_LOG_VAL1(channel), 0);
+	nw64(RX_LOG_MASK2(channel), 0);
+	nw64(RX_LOG_VAL2(channel), 0);
+	nw64(RX_LOG_PAGE_RELO1(channel), 0);
+	nw64(RX_LOG_PAGE_RELO2(channel), 0);
+	nw64(RX_LOG_PAGE_HDL(channel), 0);
+
+	val  = (u64)np->port << RX_LOG_PAGE_VLD_FUNC_SHIFT;
+	val |= (RX_LOG_PAGE_VLD_PAGE0 | RX_LOG_PAGE_VLD_PAGE1);
+	nw64(RX_LOG_PAGE_VLD(channel), val);
+
+	return 0;
+}
+
+static void niu_rx_channel_wred_init(struct niu *np, struct rx_ring_info *rp)
+{
+	u64 val;
+
+	val = (((u64)rp->nonsyn_window << RDC_RED_PARA_WIN_SHIFT) |
+	       ((u64)rp->nonsyn_threshold << RDC_RED_PARA_THRE_SHIFT) |
+	       ((u64)rp->syn_window << RDC_RED_PARA_WIN_SYN_SHIFT) |
+	       ((u64)rp->syn_threshold << RDC_RED_PARA_THRE_SYN_SHIFT));
+	nw64(RDC_RED_PARA(rp->rx_channel), val);
+}
+
+static int niu_compute_rbr_cfig_b(struct rx_ring_info *rp, u64 *ret)
+{
+	u64 val = 0;
+
+	switch (rp->rbr_block_size) {
+	case 4 * 1024:
+		val |= (RBR_BLKSIZE_4K << RBR_CFIG_B_BLKSIZE_SHIFT);
+		break;
+	case 8 * 1024:
+		val |= (RBR_BLKSIZE_8K << RBR_CFIG_B_BLKSIZE_SHIFT);
+		break;
+	case 16 * 1024:
+		val |= (RBR_BLKSIZE_16K << RBR_CFIG_B_BLKSIZE_SHIFT);
+		break;
+	case 32 * 1024:
+		val |= (RBR_BLKSIZE_32K << RBR_CFIG_B_BLKSIZE_SHIFT);
+		break;
+	default:
+		return -EINVAL;
+	}
+	val |= RBR_CFIG_B_VLD2;
+	switch (rp->rbr_sizes[2]) {
+	case 2 * 1024:
+		val |= (RBR_BUFSZ2_2K << RBR_CFIG_B_BUFSZ2_SHIFT);
+		break;
+	case 4 * 1024:
+		val |= (RBR_BUFSZ2_4K << RBR_CFIG_B_BUFSZ2_SHIFT);
+		break;
+	case 8 * 1024:
+		val |= (RBR_BUFSZ2_8K << RBR_CFIG_B_BUFSZ2_SHIFT);
+		break;
+	case 16 * 1024:
+		val |= (RBR_BUFSZ2_16K << RBR_CFIG_B_BUFSZ2_SHIFT);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	val |= RBR_CFIG_B_VLD1;
+	switch (rp->rbr_sizes[1]) {
+	case 1 * 1024:
+		val |= (RBR_BUFSZ1_1K << RBR_CFIG_B_BUFSZ1_SHIFT);
+		break;
+	case 2 * 1024:
+		val |= (RBR_BUFSZ1_2K << RBR_CFIG_B_BUFSZ1_SHIFT);
+		break;
+	case 4 * 1024:
+		val |= (RBR_BUFSZ1_4K << RBR_CFIG_B_BUFSZ1_SHIFT);
+		break;
+	case 8 * 1024:
+		val |= (RBR_BUFSZ1_8K << RBR_CFIG_B_BUFSZ1_SHIFT);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+	val |= RBR_CFIG_B_VLD0;
+	switch (rp->rbr_sizes[0]) {
+	case 256:
+		val |= (RBR_BUFSZ0_256 << RBR_CFIG_B_BUFSZ0_SHIFT);
+		break;
+	case 512:
+		val |= (RBR_BUFSZ0_512 << RBR_CFIG_B_BUFSZ0_SHIFT);
+		break;
+	case 1 * 1024:
+		val |= (RBR_BUFSZ0_1K << RBR_CFIG_B_BUFSZ0_SHIFT);
+		break;
+	case 2 * 1024:
+		val |= (RBR_BUFSZ0_2K << RBR_CFIG_B_BUFSZ0_SHIFT);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	*ret = val;
+	return 0;
+}
+
+static int niu_enable_rx_channel(struct niu *np, int channel, int on)
+{
+	u64 val = nr64(RXDMA_CFIG1(channel));
+	int limit;
+
+	if (on)
+		val |= RXDMA_CFIG1_EN;
+	else
+		val &= ~RXDMA_CFIG1_EN;
+	nw64(RXDMA_CFIG1(channel), val);
+
+	limit = 1000;
+	while (--limit > 0) {
+		if (nr64(RXDMA_CFIG1(channel)) & RXDMA_CFIG1_QST)
+			break;
+		udelay(10);
+	}
+	if (limit <= 0)
+		return -ENODEV;
+	return 0;
+}
+
+static int niu_init_one_rx_channel(struct niu *np, struct rx_ring_info *rp)
+{
+	int err, channel = rp->rx_channel;
+	u64 val;
+
+	err = niu_rx_channel_reset(np, channel);
+	if (err)
+		return err;
+
+	err = niu_rx_channel_lpage_init(np, channel);
+	if (err)
+		return err;
+
+	niu_rx_channel_wred_init(np, rp);
+
+	nw64(RX_DMA_ENT_MSK(channel), RX_DMA_ENT_MSK_RBR_EMPTY);
+	nw64(RX_DMA_CTL_STAT(channel),
+	     (RX_DMA_CTL_STAT_MEX |
+	      RX_DMA_CTL_STAT_RCRTHRES |
+	      RX_DMA_CTL_STAT_RCRTO |
+	      RX_DMA_CTL_STAT_RBR_EMPTY));
+	nw64(RXDMA_CFIG1(channel), rp->mbox_dma >> 32);
+	nw64(RXDMA_CFIG2(channel), (rp->mbox_dma & 0x00000000ffffffc0));
+	nw64(RBR_CFIG_A(channel),
+	     ((u64)rp->rbr_table_size << RBR_CFIG_A_LEN_SHIFT) |
+	     (rp->rbr_dma & (RBR_CFIG_A_STADDR_BASE | RBR_CFIG_A_STADDR)));
+	err = niu_compute_rbr_cfig_b(rp, &val);
+	if (err)
+		return err;
+	nw64(RBR_CFIG_B(channel), val);
+	nw64(RCRCFIG_A(channel),
+	     ((u64)rp->rcr_table_size << RCRCFIG_A_LEN_SHIFT) |
+	     (rp->rcr_dma & (RCRCFIG_A_STADDR_BASE | RCRCFIG_A_STADDR)));
+	nw64(RCRCFIG_B(channel),
+	     ((u64)rp->rcr_pkt_threshold << RCRCFIG_B_PTHRES_SHIFT) |
+	     RCRCFIG_B_ENTOUT |
+	     ((u64)rp->rcr_timeout << RCRCFIG_B_TIMEOUT_SHIFT));
+
+	err = niu_enable_rx_channel(np, channel, 1);
+	if (err)
+		return err;
+
+	nw64(RBR_KICK(channel), rp->rbr_index);
+
+	val = nr64(RX_DMA_CTL_STAT(channel));
+	val |= RX_DMA_CTL_STAT_RBR_EMPTY;
+	nw64(RX_DMA_CTL_STAT(channel), val);
+
+	return 0;
+}
+
+static int niu_init_rx_channels(struct niu *np)
+{
+	unsigned long flags;
+	u64 seed = jiffies_64;
+	int err, i;
+
+	niu_lock_parent(np, flags);
+	nw64(RX_DMA_CK_DIV, np->parent->rxdma_clock_divider);
+	nw64(RED_RAN_INIT, RED_RAN_INIT_OPMODE | (seed & RED_RAN_INIT_VAL));
+	niu_unlock_parent(np, flags);
+
+	/* XXX RXDMA 32bit mode? XXX */
+
+	niu_init_rdc_groups(np);
+	niu_init_drr_weight(np);
+
+	err = niu_init_hostinfo(np);
+	if (err)
+		return err;
+
+	for (i = 0; i < np->num_rx_rings; i++) {
+		struct rx_ring_info *rp = &np->rx_rings[i];
+
+		err = niu_init_one_rx_channel(np, rp);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int niu_set_ip_frag_rule(struct niu *np)
+{
+	struct niu_parent *parent = np->parent;
+	struct niu_classifier *cp = &np->clas;
+	struct niu_tcam_entry *tp;
+	int index, err;
+
+	/* XXX fix this allocation scheme XXX */
+	index = cp->tcam_index;
+	tp = &parent->tcam[index];
+
+	/* Note that the noport bit is the same in both ipv4 and
+	 * ipv6 format TCAM entries.
+	 */
+	memset(tp, 0, sizeof(*tp));
+	tp->key[1] = TCAM_V4KEY1_NOPORT;
+	tp->key_mask[1] = TCAM_V4KEY1_NOPORT;
+	tp->assoc_data = (TCAM_ASSOCDATA_TRES_USE_OFFSET |
+			  ((u64)0 << TCAM_ASSOCDATA_OFFSET_SHIFT));
+	err = tcam_write(np, index, tp->key, tp->key_mask);
+	if (err)
+		return err;
+	err = tcam_assoc_write(np, index, tp->assoc_data);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int niu_init_classifier_hw(struct niu *np)
+{
+	struct niu_parent *parent = np->parent;
+	struct niu_classifier *cp = &np->clas;
+	int i, err;
+
+	nw64(H1POLY, cp->h1_init);
+	nw64(H2POLY, cp->h2_init);
+
+	err = niu_init_hostinfo(np);
+	if (err)
+		return err;
+
+	for (i = 0; i < ENET_VLAN_TBL_NUM_ENTRIES; i++) {
+		struct niu_vlan_rdc *vp = &cp->vlan_mappings[i];
+
+		vlan_tbl_write(np, i, np->port,
+			       vp->vlan_pref, vp->rdc_num);
+	}
+
+	for (i = 0; i < cp->num_alt_mac_mappings; i++) {
+		struct niu_altmac_rdc *ap = &cp->alt_mac_mappings[i];
+
+		err = niu_set_alt_mac_rdc_table(np, ap->alt_mac_num,
+						ap->rdc_num, ap->mac_pref);
+		if (err)
+			return err;
+	}
+
+	for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_SCTP_IPV6; i++) {
+		int index = i - CLASS_CODE_USER_PROG1;
+
+		err = niu_set_tcam_key(np, i, parent->tcam_key[index]);
+		if (err)
+			return err;
+		err = niu_set_flow_key(np, i, parent->flow_key[index]);
+		if (err)
+			return err;
+	}
+
+	err = niu_set_ip_frag_rule(np);
+	if (err)
+		return err;
+
+	tcam_enable(np, 1);
+
+	return 0;
+}
+
+static int niu_zcp_write(struct niu *np, int index, u64 *data)
+{
+	nw64(ZCP_RAM_DATA0, data[0]);
+	nw64(ZCP_RAM_DATA1, data[1]);
+	nw64(ZCP_RAM_DATA2, data[2]);
+	nw64(ZCP_RAM_DATA3, data[3]);
+	nw64(ZCP_RAM_DATA4, data[4]);
+	nw64(ZCP_RAM_BE, ZCP_RAM_BE_VAL);
+	nw64(ZCP_RAM_ACC,
+	     (ZCP_RAM_ACC_WRITE |
+	      (0 << ZCP_RAM_ACC_ZFCID_SHIFT) |
+	      (ZCP_RAM_SEL_CFIFO(np->port) << ZCP_RAM_ACC_RAM_SEL_SHIFT)));
+
+	return niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY,
+				   1000, 100);
+}
+
+static int niu_zcp_read(struct niu *np, int index, u64 *data)
+{
+	int err;
+
+	err = niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY,
+				  1000, 100);
+	if (err) {
+		dev_err(np->device, PFX "%s: ZCP read busy won't clear, "
+			"ZCP_RAM_ACC[%llx]\n", np->dev->name,
+			(unsigned long long) nr64(ZCP_RAM_ACC));
+		return err;
+	}
+
+	nw64(ZCP_RAM_ACC,
+	     (ZCP_RAM_ACC_READ |
+	      (0 << ZCP_RAM_ACC_ZFCID_SHIFT) |
+	      (ZCP_RAM_SEL_CFIFO(np->port) << ZCP_RAM_ACC_RAM_SEL_SHIFT)));
+
+	err = niu_wait_bits_clear(np, ZCP_RAM_ACC, ZCP_RAM_ACC_BUSY,
+				  1000, 100);
+	if (err) {
+		dev_err(np->device, PFX "%s: ZCP read busy2 won't clear, "
+			"ZCP_RAM_ACC[%llx]\n", np->dev->name,
+			(unsigned long long) nr64(ZCP_RAM_ACC));
+		return err;
+	}
+
+	data[0] = nr64(ZCP_RAM_DATA0);
+	data[1] = nr64(ZCP_RAM_DATA1);
+	data[2] = nr64(ZCP_RAM_DATA2);
+	data[3] = nr64(ZCP_RAM_DATA3);
+	data[4] = nr64(ZCP_RAM_DATA4);
+
+	return 0;
+}
+
+static void niu_zcp_cfifo_reset(struct niu *np)
+{
+	u64 val = nr64(RESET_CFIFO);
+
+	val |= RESET_CFIFO_RST(np->port);
+	nw64(RESET_CFIFO, val);
+	udelay(10);
+
+	val &= ~RESET_CFIFO_RST(np->port);
+	nw64(RESET_CFIFO, val);
+}
+
+static int niu_init_zcp(struct niu *np)
+{
+	u64 data[5], rbuf[5];
+	int i, max, err;
+
+	if (np->parent->plat_type != PLAT_TYPE_NIU) {
+		if (np->port == 0 || np->port == 1)
+			max = ATLAS_P0_P1_CFIFO_ENTRIES;
+		else
+			max = ATLAS_P2_P3_CFIFO_ENTRIES;
+	} else
+		max = NIU_CFIFO_ENTRIES;
+
+	data[0] = 0;
+	data[1] = 0;
+	data[2] = 0;
+	data[3] = 0;
+	data[4] = 0;
+
+	for (i = 0; i < max; i++) {
+		err = niu_zcp_write(np, i, data);
+		if (err)
+			return err;
+		err = niu_zcp_read(np, i, rbuf);
+		if (err)
+			return err;
+	}
+
+	niu_zcp_cfifo_reset(np);
+	nw64(CFIFO_ECC(np->port), 0);
+	nw64(ZCP_INT_STAT, ZCP_INT_STAT_ALL);
+	(void) nr64(ZCP_INT_STAT);
+	nw64(ZCP_INT_MASK, ZCP_INT_MASK_ALL);
+
+	return 0;
+}
+
+static void niu_ipp_write(struct niu *np, int index, u64 *data)
+{
+	u64 val = nr64_ipp(IPP_CFIG);
+
+	nw64_ipp(IPP_CFIG, val | IPP_CFIG_DFIFO_PIO_W);
+	nw64_ipp(IPP_DFIFO_WR_PTR, index);
+	nw64_ipp(IPP_DFIFO_WR0, data[0]);
+	nw64_ipp(IPP_DFIFO_WR1, data[1]);
+	nw64_ipp(IPP_DFIFO_WR2, data[2]);
+	nw64_ipp(IPP_DFIFO_WR3, data[3]);
+	nw64_ipp(IPP_DFIFO_WR4, data[4]);
+	nw64_ipp(IPP_CFIG, val & ~IPP_CFIG_DFIFO_PIO_W);
+}
+
+static void niu_ipp_read(struct niu *np, int index, u64 *data)
+{
+	nw64_ipp(IPP_DFIFO_RD_PTR, index);
+	data[0] = nr64_ipp(IPP_DFIFO_RD0);
+	data[1] = nr64_ipp(IPP_DFIFO_RD1);
+	data[2] = nr64_ipp(IPP_DFIFO_RD2);
+	data[3] = nr64_ipp(IPP_DFIFO_RD3);
+	data[4] = nr64_ipp(IPP_DFIFO_RD4);
+}
+
+static int niu_ipp_reset(struct niu *np)
+{
+	return niu_set_and_wait_clear_ipp(np, IPP_CFIG, IPP_CFIG_SOFT_RST,
+					  1000, 100, "IPP_CFIG");
+}
+
+static int niu_init_ipp(struct niu *np)
+{
+	u64 data[5], rbuf[5], val;
+	int i, max, err;
+
+	if (np->parent->plat_type != PLAT_TYPE_NIU) {
+		if (np->port == 0 || np->port == 1)
+			max = ATLAS_P0_P1_DFIFO_ENTRIES;
+		else
+			max = ATLAS_P2_P3_DFIFO_ENTRIES;
+	} else
+		max = NIU_DFIFO_ENTRIES;
+
+	data[0] = 0;
+	data[1] = 0;
+	data[2] = 0;
+	data[3] = 0;
+	data[4] = 0;
+
+	for (i = 0; i < max; i++) {
+		niu_ipp_write(np, i, data);
+		niu_ipp_read(np, i, rbuf);
+	}
+
+	(void) nr64_ipp(IPP_INT_STAT);
+	(void) nr64_ipp(IPP_INT_STAT);
+
+	err = niu_ipp_reset(np);
+	if (err)
+		return err;
+
+	(void) nr64_ipp(IPP_PKT_DIS);
+	(void) nr64_ipp(IPP_BAD_CS_CNT);
+	(void) nr64_ipp(IPP_ECC);
+
+	(void) nr64_ipp(IPP_INT_STAT);
+
+	nw64_ipp(IPP_MSK, ~IPP_MSK_ALL);
+
+	val = nr64_ipp(IPP_CFIG);
+	val &= ~IPP_CFIG_IP_MAX_PKT;
+	val |= (IPP_CFIG_IPP_ENABLE |
+		IPP_CFIG_DFIFO_ECC_EN |
+		IPP_CFIG_DROP_BAD_CRC |
+		IPP_CFIG_CKSUM_EN |
+		(0x1ffff << IPP_CFIG_IP_MAX_PKT_SHIFT));
+	nw64_ipp(IPP_CFIG, val);
+
+	return 0;
+}
+
+static void niu_init_xif_xmac(struct niu *np)
+{
+	struct niu_link_config *lp = &np->link_config;
+	u64 val;
+
+	val = nr64_mac(XMAC_CONFIG);
+
+	if ((np->flags & NIU_FLAGS_10G) != 0 &&
+	    (np->flags & NIU_FLAGS_FIBER) != 0) {
+		if (netif_carrier_ok(np->dev)) {
+			val |= XMAC_CONFIG_LED_POLARITY;
+			val &= ~XMAC_CONFIG_FORCE_LED_ON;
+		} else {
+			val |= XMAC_CONFIG_FORCE_LED_ON;
+			val &= ~XMAC_CONFIG_LED_POLARITY;
+		}
+	}
+
+	val &= ~XMAC_CONFIG_SEL_POR_CLK_SRC;
+
+	val |= XMAC_CONFIG_TX_OUTPUT_EN;
+
+	if (lp->loopback_mode == LOOPBACK_MAC) {
+		val &= ~XMAC_CONFIG_SEL_POR_CLK_SRC;
+		val |= XMAC_CONFIG_LOOPBACK;
+	} else {
+		val &= ~XMAC_CONFIG_LOOPBACK;
+	}
+
+	if (np->flags & NIU_FLAGS_10G) {
+		val &= ~XMAC_CONFIG_LFS_DISABLE;
+	} else {
+		val |= XMAC_CONFIG_LFS_DISABLE;
+		if (!(np->flags & NIU_FLAGS_FIBER))
+			val |= XMAC_CONFIG_1G_PCS_BYPASS;
+		else
+			val &= ~XMAC_CONFIG_1G_PCS_BYPASS;
+	}
+
+	val &= ~XMAC_CONFIG_10G_XPCS_BYPASS;
+
+	if (lp->active_speed == SPEED_100)
+		val |= XMAC_CONFIG_SEL_CLK_25MHZ;
+	else
+		val &= ~XMAC_CONFIG_SEL_CLK_25MHZ;
+
+	nw64_mac(XMAC_CONFIG, val);
+
+	val = nr64_mac(XMAC_CONFIG);
+	val &= ~XMAC_CONFIG_MODE_MASK;
+	if (np->flags & NIU_FLAGS_10G) {
+		val |= XMAC_CONFIG_MODE_XGMII;
+	} else {
+		if (lp->active_speed == SPEED_100)
+			val |= XMAC_CONFIG_MODE_MII;
+		else
+			val |= XMAC_CONFIG_MODE_GMII;
+	}
+
+	nw64_mac(XMAC_CONFIG, val);
+}
+
+static void niu_init_xif_bmac(struct niu *np)
+{
+	struct niu_link_config *lp = &np->link_config;
+	u64 val;
+
+	val = BMAC_XIF_CONFIG_TX_OUTPUT_EN;
+
+	if (lp->loopback_mode == LOOPBACK_MAC)
+		val |= BMAC_XIF_CONFIG_MII_LOOPBACK;
+	else
+		val &= ~BMAC_XIF_CONFIG_MII_LOOPBACK;
+
+	if (lp->active_speed == SPEED_1000)
+		val |= BMAC_XIF_CONFIG_GMII_MODE;
+	else
+		val &= ~BMAC_XIF_CONFIG_GMII_MODE;
+
+	val &= ~(BMAC_XIF_CONFIG_LINK_LED |
+		 BMAC_XIF_CONFIG_LED_POLARITY);
+
+	if (!(np->flags & NIU_FLAGS_10G) &&
+	    !(np->flags & NIU_FLAGS_FIBER) &&
+	    lp->active_speed == SPEED_100)
+		val |= BMAC_XIF_CONFIG_25MHZ_CLOCK;
+	else
+		val &= ~BMAC_XIF_CONFIG_25MHZ_CLOCK;
+
+	nw64_mac(BMAC_XIF_CONFIG, val);
+}
+
+static void niu_init_xif(struct niu *np)
+{
+	if (np->flags & NIU_FLAGS_XMAC)
+		niu_init_xif_xmac(np);
+	else
+		niu_init_xif_bmac(np);
+}
+
+static void niu_pcs_mii_reset(struct niu *np)
+{
+	u64 val = nr64_pcs(PCS_MII_CTL);
+	val |= PCS_MII_CTL_RST;
+	nw64_pcs(PCS_MII_CTL, val);
+}
+
+static void niu_xpcs_reset(struct niu *np)
+{
+	u64 val = nr64_xpcs(XPCS_CONTROL1);
+	val |= XPCS_CONTROL1_RESET;
+	nw64_xpcs(XPCS_CONTROL1, val);
+}
+
+static int niu_init_pcs(struct niu *np)
+{
+	struct niu_link_config *lp = &np->link_config;
+	u64 val;
+
+	switch (np->flags & (NIU_FLAGS_10G | NIU_FLAGS_FIBER)) {
+	case NIU_FLAGS_FIBER:
+		/* 1G fiber */
+		nw64_pcs(PCS_CONF, PCS_CONF_MASK | PCS_CONF_ENABLE);
+		nw64_pcs(PCS_DPATH_MODE, 0);
+		niu_pcs_mii_reset(np);
+		break;
+
+	case NIU_FLAGS_10G:
+	case NIU_FLAGS_10G | NIU_FLAGS_FIBER:
+		if (!(np->flags & NIU_FLAGS_XMAC))
+			return -EINVAL;
+
+		/* 10G copper or fiber */
+		val = nr64_mac(XMAC_CONFIG);
+		val &= ~XMAC_CONFIG_10G_XPCS_BYPASS;
+		nw64_mac(XMAC_CONFIG, val);
+
+		niu_xpcs_reset(np);
+
+		val = nr64_xpcs(XPCS_CONTROL1);
+		if (lp->loopback_mode == LOOPBACK_PHY)
+			val |= XPCS_CONTROL1_LOOPBACK;
+		else
+			val &= ~XPCS_CONTROL1_LOOPBACK;
+		nw64_xpcs(XPCS_CONTROL1, val);
+
+		nw64_xpcs(XPCS_DESKEW_ERR_CNT, 0);
+		(void) nr64_xpcs(XPCS_SYMERR_CNT01);
+		(void) nr64_xpcs(XPCS_SYMERR_CNT23);
+		break;
+
+	case 0:
+		/* 1G copper */
+		nw64_pcs(PCS_DPATH_MODE, PCS_DPATH_MODE_MII);
+		niu_pcs_mii_reset(np);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int niu_reset_tx_xmac(struct niu *np)
+{
+	return niu_set_and_wait_clear_mac(np, XTXMAC_SW_RST,
+					  (XTXMAC_SW_RST_REG_RS |
+					   XTXMAC_SW_RST_SOFT_RST),
+					  1000, 100, "XTXMAC_SW_RST");
+}
+
+static int niu_reset_tx_bmac(struct niu *np)
+{
+	int limit;
+
+	nw64_mac(BTXMAC_SW_RST, BTXMAC_SW_RST_RESET);
+	limit = 1000;
+	while (--limit >= 0) {
+		if (!(nr64_mac(BTXMAC_SW_RST) & BTXMAC_SW_RST_RESET))
+			break;
+		udelay(100);
+	}
+	if (limit < 0) {
+		dev_err(np->device, PFX "Port %u TX BMAC would not reset, "
+			"BTXMAC_SW_RST[%llx]\n",
+			np->port,
+			(unsigned long long) nr64_mac(BTXMAC_SW_RST));
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int niu_reset_tx_mac(struct niu *np)
+{
+	if (np->flags & NIU_FLAGS_XMAC)
+		return niu_reset_tx_xmac(np);
+	else
+		return niu_reset_tx_bmac(np);
+}
+
+static void niu_init_tx_xmac(struct niu *np, u64 min, u64 max)
+{
+	u64 val;
+
+	val = nr64_mac(XMAC_MIN);
+	val &= ~(XMAC_MIN_TX_MIN_PKT_SIZE |
+		 XMAC_MIN_RX_MIN_PKT_SIZE);
+	val |= (min << XMAC_MIN_RX_MIN_PKT_SIZE_SHFT);
+	val |= (min << XMAC_MIN_TX_MIN_PKT_SIZE_SHFT);
+	nw64_mac(XMAC_MIN, val);
+
+	nw64_mac(XMAC_MAX, max);
+
+	nw64_mac(XTXMAC_STAT_MSK, ~(u64)0);
+
+	val = nr64_mac(XMAC_IPG);
+	if (np->flags & NIU_FLAGS_10G) {
+		val &= ~XMAC_IPG_IPG_XGMII;
+		val |= (IPG_12_15_XGMII << XMAC_IPG_IPG_XGMII_SHIFT);
+	} else {
+		val &= ~XMAC_IPG_IPG_MII_GMII;
+		val |= (IPG_12_MII_GMII << XMAC_IPG_IPG_MII_GMII_SHIFT);
+	}
+	nw64_mac(XMAC_IPG, val);
+
+	val = nr64_mac(XMAC_CONFIG);
+	val &= ~(XMAC_CONFIG_ALWAYS_NO_CRC |
+		 XMAC_CONFIG_STRETCH_MODE |
+		 XMAC_CONFIG_VAR_MIN_IPG_EN |
+		 XMAC_CONFIG_TX_ENABLE);
+	nw64_mac(XMAC_CONFIG, val);
+
+	nw64_mac(TXMAC_FRM_CNT, 0);
+	nw64_mac(TXMAC_BYTE_CNT, 0);
+}
+
+static void niu_init_tx_bmac(struct niu *np, u64 min, u64 max)
+{
+	u64 val;
+
+	nw64_mac(BMAC_MIN_FRAME, min);
+	nw64_mac(BMAC_MAX_FRAME, max);
+
+	nw64_mac(BTXMAC_STATUS_MASK, ~(u64)0);
+	nw64_mac(BMAC_CTRL_TYPE, 0x8808);
+	nw64_mac(BMAC_PREAMBLE_SIZE, 7);
+
+	val = nr64_mac(BTXMAC_CONFIG);
+	val &= ~(BTXMAC_CONFIG_FCS_DISABLE |
+		 BTXMAC_CONFIG_ENABLE);
+	nw64_mac(BTXMAC_CONFIG, val);
+}
+
+static void niu_init_tx_mac(struct niu *np)
+{
+	u64 min, max;
+
+	min = 64;
+	if (np->dev->mtu > ETH_DATA_LEN)
+		max = 9216;
+	else
+		max = 1522;
+
+	/* The XMAC_MIN register only accepts values for TX min which
+	 * have the low 3 bits cleared.
+	 */
+	BUILD_BUG_ON(min & 0x7);
+
+	if (np->flags & NIU_FLAGS_XMAC)
+		niu_init_tx_xmac(np, min, max);
+	else
+		niu_init_tx_bmac(np, min, max);
+}
+
+static int niu_reset_rx_xmac(struct niu *np)
+{
+	int limit;
+
+	nw64_mac(XRXMAC_SW_RST,
+		 XRXMAC_SW_RST_REG_RS | XRXMAC_SW_RST_SOFT_RST);
+	limit = 1000;
+	while (--limit >= 0) {
+		if (!(nr64_mac(XRXMAC_SW_RST) & (XRXMAC_SW_RST_REG_RS |
+						 XRXMAC_SW_RST_SOFT_RST)))
+		    break;
+		udelay(100);
+	}
+	if (limit < 0) {
+		dev_err(np->device, PFX "Port %u RX XMAC would not reset, "
+			"XRXMAC_SW_RST[%llx]\n",
+			np->port,
+			(unsigned long long) nr64_mac(XRXMAC_SW_RST));
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int niu_reset_rx_bmac(struct niu *np)
+{
+	int limit;
+
+	nw64_mac(BRXMAC_SW_RST, BRXMAC_SW_RST_RESET);
+	limit = 1000;
+	while (--limit >= 0) {
+		if (!(nr64_mac(BRXMAC_SW_RST) & BRXMAC_SW_RST_RESET))
+			break;
+		udelay(100);
+	}
+	if (limit < 0) {
+		dev_err(np->device, PFX "Port %u RX BMAC would not reset, "
+			"BRXMAC_SW_RST[%llx]\n",
+			np->port,
+			(unsigned long long) nr64_mac(BRXMAC_SW_RST));
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int niu_reset_rx_mac(struct niu *np)
+{
+	if (np->flags & NIU_FLAGS_XMAC)
+		return niu_reset_rx_xmac(np);
+	else
+		return niu_reset_rx_bmac(np);
+}
+
+static void niu_init_rx_xmac(struct niu *np)
+{
+	struct niu_parent *parent = np->parent;
+	struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port];
+	int first_rdc_table = tp->first_table_num;
+	unsigned long i;
+	u64 val;
+
+	nw64_mac(XMAC_ADD_FILT0, 0);
+	nw64_mac(XMAC_ADD_FILT1, 0);
+	nw64_mac(XMAC_ADD_FILT2, 0);
+	nw64_mac(XMAC_ADD_FILT12_MASK, 0);
+	nw64_mac(XMAC_ADD_FILT00_MASK, 0);
+	for (i = 0; i < MAC_NUM_HASH; i++)
+		nw64_mac(XMAC_HASH_TBL(i), 0);
+	nw64_mac(XRXMAC_STAT_MSK, ~(u64)0);
+	niu_set_primary_mac_rdc_table(np, first_rdc_table, 1);
+	niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1);
+
+	val = nr64_mac(XMAC_CONFIG);
+	val &= ~(XMAC_CONFIG_RX_MAC_ENABLE |
+		 XMAC_CONFIG_PROMISCUOUS |
+		 XMAC_CONFIG_PROMISC_GROUP |
+		 XMAC_CONFIG_ERR_CHK_DIS |
+		 XMAC_CONFIG_RX_CRC_CHK_DIS |
+		 XMAC_CONFIG_RESERVED_MULTICAST |
+		 XMAC_CONFIG_RX_CODEV_CHK_DIS |
+		 XMAC_CONFIG_ADDR_FILTER_EN |
+		 XMAC_CONFIG_RCV_PAUSE_ENABLE |
+		 XMAC_CONFIG_STRIP_CRC |
+		 XMAC_CONFIG_PASS_FLOW_CTRL |
+		 XMAC_CONFIG_MAC2IPP_PKT_CNT_EN);
+	val |= (XMAC_CONFIG_HASH_FILTER_EN);
+	nw64_mac(XMAC_CONFIG, val);
+
+	nw64_mac(RXMAC_BT_CNT, 0);
+	nw64_mac(RXMAC_BC_FRM_CNT, 0);
+	nw64_mac(RXMAC_MC_FRM_CNT, 0);
+	nw64_mac(RXMAC_FRAG_CNT, 0);
+	nw64_mac(RXMAC_HIST_CNT1, 0);
+	nw64_mac(RXMAC_HIST_CNT2, 0);
+	nw64_mac(RXMAC_HIST_CNT3, 0);
+	nw64_mac(RXMAC_HIST_CNT4, 0);
+	nw64_mac(RXMAC_HIST_CNT5, 0);
+	nw64_mac(RXMAC_HIST_CNT6, 0);
+	nw64_mac(RXMAC_HIST_CNT7, 0);
+	nw64_mac(RXMAC_MPSZER_CNT, 0);
+	nw64_mac(RXMAC_CRC_ER_CNT, 0);
+	nw64_mac(RXMAC_CD_VIO_CNT, 0);
+	nw64_mac(LINK_FAULT_CNT, 0);
+}
+
+static void niu_init_rx_bmac(struct niu *np)
+{
+	struct niu_parent *parent = np->parent;
+	struct niu_rdc_tables *tp = &parent->rdc_group_cfg[np->port];
+	int first_rdc_table = tp->first_table_num;
+	unsigned long i;
+	u64 val;
+
+	nw64_mac(BMAC_ADD_FILT0, 0);
+	nw64_mac(BMAC_ADD_FILT1, 0);
+	nw64_mac(BMAC_ADD_FILT2, 0);
+	nw64_mac(BMAC_ADD_FILT12_MASK, 0);
+	nw64_mac(BMAC_ADD_FILT00_MASK, 0);
+	for (i = 0; i < MAC_NUM_HASH; i++)
+		nw64_mac(BMAC_HASH_TBL(i), 0);
+	niu_set_primary_mac_rdc_table(np, first_rdc_table, 1);
+	niu_set_multicast_mac_rdc_table(np, first_rdc_table, 1);
+	nw64_mac(BRXMAC_STATUS_MASK, ~(u64)0);
+
+	val = nr64_mac(BRXMAC_CONFIG);
+	val &= ~(BRXMAC_CONFIG_ENABLE |
+		 BRXMAC_CONFIG_STRIP_PAD |
+		 BRXMAC_CONFIG_STRIP_FCS |
+		 BRXMAC_CONFIG_PROMISC |
+		 BRXMAC_CONFIG_PROMISC_GRP |
+		 BRXMAC_CONFIG_ADDR_FILT_EN |
+		 BRXMAC_CONFIG_DISCARD_DIS);
+	val |= (BRXMAC_CONFIG_HASH_FILT_EN);
+	nw64_mac(BRXMAC_CONFIG, val);
+
+	val = nr64_mac(BMAC_ADDR_CMPEN);
+	val |= BMAC_ADDR_CMPEN_EN0;
+	nw64_mac(BMAC_ADDR_CMPEN, val);
+}
+
+static void niu_init_rx_mac(struct niu *np)
+{
+	niu_set_primary_mac(np, np->dev->dev_addr);
+
+	if (np->flags & NIU_FLAGS_XMAC)
+		niu_init_rx_xmac(np);
+	else
+		niu_init_rx_bmac(np);
+}
+
+static void niu_enable_tx_xmac(struct niu *np, int on)
+{
+	u64 val = nr64_mac(XMAC_CONFIG);
+
+	if (on)
+		val |= XMAC_CONFIG_TX_ENABLE;
+	else
+		val &= ~XMAC_CONFIG_TX_ENABLE;
+	nw64_mac(XMAC_CONFIG, val);
+}
+
+static void niu_enable_tx_bmac(struct niu *np, int on)
+{
+	u64 val = nr64_mac(BTXMAC_CONFIG);
+
+	if (on)
+		val |= BTXMAC_CONFIG_ENABLE;
+	else
+		val &= ~BTXMAC_CONFIG_ENABLE;
+	nw64_mac(BTXMAC_CONFIG, val);
+}
+
+static void niu_enable_tx_mac(struct niu *np, int on)
+{
+	if (np->flags & NIU_FLAGS_XMAC)
+		niu_enable_tx_xmac(np, on);
+	else
+		niu_enable_tx_bmac(np, on);
+}
+
+static void niu_enable_rx_xmac(struct niu *np, int on)
+{
+	u64 val = nr64_mac(XMAC_CONFIG);
+
+	val &= ~(XMAC_CONFIG_HASH_FILTER_EN |
+		 XMAC_CONFIG_PROMISCUOUS);
+
+	if (np->flags & NIU_FLAGS_MCAST)
+		val |= XMAC_CONFIG_HASH_FILTER_EN;
+	if (np->flags & NIU_FLAGS_PROMISC)
+		val |= XMAC_CONFIG_PROMISCUOUS;
+
+	if (on)
+		val |= XMAC_CONFIG_RX_MAC_ENABLE;
+	else
+		val &= ~XMAC_CONFIG_RX_MAC_ENABLE;
+	nw64_mac(XMAC_CONFIG, val);
+}
+
+static void niu_enable_rx_bmac(struct niu *np, int on)
+{
+	u64 val = nr64_mac(BRXMAC_CONFIG);
+
+	val &= ~(BRXMAC_CONFIG_HASH_FILT_EN |
+		 BRXMAC_CONFIG_PROMISC);
+
+	if (np->flags & NIU_FLAGS_MCAST)
+		val |= BRXMAC_CONFIG_HASH_FILT_EN;
+	if (np->flags & NIU_FLAGS_PROMISC)
+		val |= BRXMAC_CONFIG_PROMISC;
+
+	if (on)
+		val |= BRXMAC_CONFIG_ENABLE;
+	else
+		val &= ~BRXMAC_CONFIG_ENABLE;
+	nw64_mac(BRXMAC_CONFIG, val);
+}
+
+static void niu_enable_rx_mac(struct niu *np, int on)
+{
+	if (np->flags & NIU_FLAGS_XMAC)
+		niu_enable_rx_xmac(np, on);
+	else
+		niu_enable_rx_bmac(np, on);
+}
+
+static int niu_init_mac(struct niu *np)
+{
+	int err;
+
+	niu_init_xif(np);
+	err = niu_init_pcs(np);
+	if (err)
+		return err;
+
+	err = niu_reset_tx_mac(np);
+	if (err)
+		return err;
+	niu_init_tx_mac(np);
+	err = niu_reset_rx_mac(np);
+	if (err)
+		return err;
+	niu_init_rx_mac(np);
+
+	/* This looks hookey but the RX MAC reset we just did will
+	 * undo some of the state we setup in niu_init_tx_mac() so we
+	 * have to call it again.  In particular, the RX MAC reset will
+	 * set the XMAC_MAX register back to it's default value.
+	 */
+	niu_init_tx_mac(np);
+	niu_enable_tx_mac(np, 1);
+
+	niu_enable_rx_mac(np, 1);
+
+	return 0;
+}
+
+static void niu_stop_one_tx_channel(struct niu *np, struct tx_ring_info *rp)
+{
+	(void) niu_tx_channel_stop(np, rp->tx_channel);
+}
+
+static void niu_stop_tx_channels(struct niu *np)
+{
+	int i;
+
+	for (i = 0; i < np->num_tx_rings; i++) {
+		struct tx_ring_info *rp = &np->tx_rings[i];
+
+		niu_stop_one_tx_channel(np, rp);
+	}
+}
+
+static void niu_reset_one_tx_channel(struct niu *np, struct tx_ring_info *rp)
+{
+	(void) niu_tx_channel_reset(np, rp->tx_channel);
+}
+
+static void niu_reset_tx_channels(struct niu *np)
+{
+	int i;
+
+	for (i = 0; i < np->num_tx_rings; i++) {
+		struct tx_ring_info *rp = &np->tx_rings[i];
+
+		niu_reset_one_tx_channel(np, rp);
+	}
+}
+
+static void niu_stop_one_rx_channel(struct niu *np, struct rx_ring_info *rp)
+{
+	(void) niu_enable_rx_channel(np, rp->rx_channel, 0);
+}
+
+static void niu_stop_rx_channels(struct niu *np)
+{
+	int i;
+
+	for (i = 0; i < np->num_rx_rings; i++) {
+		struct rx_ring_info *rp = &np->rx_rings[i];
+
+		niu_stop_one_rx_channel(np, rp);
+	}
+}
+
+static void niu_reset_one_rx_channel(struct niu *np, struct rx_ring_info *rp)
+{
+	int channel = rp->rx_channel;
+
+	(void) niu_rx_channel_reset(np, channel);
+	nw64(RX_DMA_ENT_MSK(channel), RX_DMA_ENT_MSK_ALL);
+	nw64(RX_DMA_CTL_STAT(channel), 0);
+	(void) niu_enable_rx_channel(np, channel, 0);
+}
+
+static void niu_reset_rx_channels(struct niu *np)
+{
+	int i;
+
+	for (i = 0; i < np->num_rx_rings; i++) {
+		struct rx_ring_info *rp = &np->rx_rings[i];
+
+		niu_reset_one_rx_channel(np, rp);
+	}
+}
+
+static void niu_disable_ipp(struct niu *np)
+{
+	u64 rd, wr, val;
+	int limit;
+
+	rd = nr64_ipp(IPP_DFIFO_RD_PTR);
+	wr = nr64_ipp(IPP_DFIFO_WR_PTR);
+	limit = 100;
+	while (--limit >= 0 && (rd != wr)) {
+		rd = nr64_ipp(IPP_DFIFO_RD_PTR);
+		wr = nr64_ipp(IPP_DFIFO_WR_PTR);
+	}
+	if (limit < 0 &&
+	    (rd != 0 && wr != 1)) {
+		dev_err(np->device, PFX "%s: IPP would not quiesce, "
+			"rd_ptr[%llx] wr_ptr[%llx]\n",
+			np->dev->name,
+			(unsigned long long) nr64_ipp(IPP_DFIFO_RD_PTR),
+			(unsigned long long) nr64_ipp(IPP_DFIFO_WR_PTR));
+	}
+
+	val = nr64_ipp(IPP_CFIG);
+	val &= ~(IPP_CFIG_IPP_ENABLE |
+		 IPP_CFIG_DFIFO_ECC_EN |
+		 IPP_CFIG_DROP_BAD_CRC |
+		 IPP_CFIG_CKSUM_EN);
+	nw64_ipp(IPP_CFIG, val);
+
+	(void) niu_ipp_reset(np);
+}
+
+static int niu_init_hw(struct niu *np)
+{
+	int i, err;
+
+	niudbg(IFUP, "%s: Initialize TXC\n", np->dev->name);
+	niu_txc_enable_port(np, 1);
+	niu_txc_port_dma_enable(np, 1);
+	niu_txc_set_imask(np, 0);
+
+	niudbg(IFUP, "%s: Initialize TX channels\n", np->dev->name);
+	for (i = 0; i < np->num_tx_rings; i++) {
+		struct tx_ring_info *rp = &np->tx_rings[i];
+
+		err = niu_init_one_tx_channel(np, rp);
+		if (err)
+			return err;
+	}
+
+	niudbg(IFUP, "%s: Initialize RX channels\n", np->dev->name);
+	err = niu_init_rx_channels(np);
+	if (err)
+		goto out_uninit_tx_channels;
+
+	niudbg(IFUP, "%s: Initialize classifier\n", np->dev->name);
+	err = niu_init_classifier_hw(np);
+	if (err)
+		goto out_uninit_rx_channels;
+
+	niudbg(IFUP, "%s: Initialize ZCP\n", np->dev->name);
+	err = niu_init_zcp(np);
+	if (err)
+		goto out_uninit_rx_channels;
+
+	niudbg(IFUP, "%s: Initialize IPP\n", np->dev->name);
+	err = niu_init_ipp(np);
+	if (err)
+		goto out_uninit_rx_channels;
+
+	niudbg(IFUP, "%s: Initialize MAC\n", np->dev->name);
+	err = niu_init_mac(np);
+	if (err)
+		goto out_uninit_ipp;
+
+	return 0;
+
+out_uninit_ipp:
+	niudbg(IFUP, "%s: Uninit IPP\n", np->dev->name);
+	niu_disable_ipp(np);
+
+out_uninit_rx_channels:
+	niudbg(IFUP, "%s: Uninit RX channels\n", np->dev->name);
+	niu_stop_rx_channels(np);
+	niu_reset_rx_channels(np);
+
+out_uninit_tx_channels:
+	niudbg(IFUP, "%s: Uninit TX channels\n", np->dev->name);
+	niu_stop_tx_channels(np);
+	niu_reset_tx_channels(np);
+
+	return err;
+}
+
+static void niu_stop_hw(struct niu *np)
+{
+	niudbg(IFDOWN, "%s: Disable interrupts\n", np->dev->name);
+	niu_enable_interrupts(np, 0);
+
+	niudbg(IFDOWN, "%s: Disable RX MAC\n", np->dev->name);
+	niu_enable_rx_mac(np, 0);
+
+	niudbg(IFDOWN, "%s: Disable IPP\n", np->dev->name);
+	niu_disable_ipp(np);
+
+	niudbg(IFDOWN, "%s: Stop TX channels\n", np->dev->name);
+	niu_stop_tx_channels(np);
+
+	niudbg(IFDOWN, "%s: Stop RX channels\n", np->dev->name);
+	niu_stop_rx_channels(np);
+
+	niudbg(IFDOWN, "%s: Reset TX channels\n", np->dev->name);
+	niu_reset_tx_channels(np);
+
+	niudbg(IFDOWN, "%s: Reset RX channels\n", np->dev->name);
+	niu_reset_rx_channels(np);
+}
+
+static int niu_request_irq(struct niu *np)
+{
+	int i, j, err;
+
+	err = 0;
+	for (i = 0; i < np->num_ldg; i++) {
+		struct niu_ldg *lp = &np->ldg[i];
+
+		err = request_irq(lp->irq, niu_interrupt,
+				  IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+				  np->dev->name, lp);
+		if (err)
+			goto out_free_irqs;
+
+	}
+
+	return 0;
+
+out_free_irqs:
+	for (j = 0; j < i; j++) {
+		struct niu_ldg *lp = &np->ldg[j];
+
+		free_irq(lp->irq, lp);
+	}
+	return err;
+}
+
+static void niu_free_irq(struct niu *np)
+{
+	int i;
+
+	for (i = 0; i < np->num_ldg; i++) {
+		struct niu_ldg *lp = &np->ldg[i];
+
+		free_irq(lp->irq, lp);
+	}
+}
+
+static void niu_enable_napi(struct niu *np)
+{
+	int i;
+
+	for (i = 0; i < np->num_ldg; i++)
+		napi_enable(&np->ldg[i].napi);
+}
+
+static void niu_disable_napi(struct niu *np)
+{
+	int i;
+
+	for (i = 0; i < np->num_ldg; i++)
+		napi_disable(&np->ldg[i].napi);
+}
+
+static int niu_open(struct net_device *dev)
+{
+	struct niu *np = netdev_priv(dev);
+	int err;
+
+	netif_carrier_off(dev);
+
+	err = niu_alloc_channels(np);
+	if (err)
+		goto out_err;
+
+	err = niu_enable_interrupts(np, 0);
+	if (err)
+		goto out_free_channels;
+
+	err = niu_request_irq(np);
+	if (err)
+		goto out_free_channels;
+
+	niu_enable_napi(np);
+
+	spin_lock_irq(&np->lock);
+
+	err = niu_init_hw(np);
+	if (!err) {
+		init_timer(&np->timer);
+		np->timer.expires = jiffies + HZ;
+		np->timer.data = (unsigned long) np;
+		np->timer.function = niu_timer;
+
+		err = niu_enable_interrupts(np, 1);
+		if (err)
+			niu_stop_hw(np);
+	}
+
+	spin_unlock_irq(&np->lock);
+
+	if (err) {
+		niu_disable_napi(np);
+		goto out_free_irq;
+	}
+
+	netif_start_queue(dev);
+
+	if (np->link_config.loopback_mode != LOOPBACK_DISABLED)
+		netif_carrier_on(dev);
+
+	add_timer(&np->timer);
+
+	return 0;
+
+out_free_irq:
+	niu_free_irq(np);
+
+out_free_channels:
+	niu_free_channels(np);
+
+out_err:
+	return err;
+}
+
+static void niu_full_shutdown(struct niu *np, struct net_device *dev)
+{
+	cancel_work_sync(&np->reset_task);
+
+	niu_disable_napi(np);
+	netif_stop_queue(dev);
+
+	del_timer_sync(&np->timer);
+
+	spin_lock_irq(&np->lock);
+
+	niu_stop_hw(np);
+
+	spin_unlock_irq(&np->lock);
+}
+
+static int niu_close(struct net_device *dev)
+{
+	struct niu *np = netdev_priv(dev);
+
+	niu_full_shutdown(np, dev);
+
+	niu_free_irq(np);
+
+	niu_free_channels(np);
+
+	return 0;
+}
+
+static void niu_sync_xmac_stats(struct niu *np)
+{
+	struct niu_xmac_stats *mp = &np->mac_stats.xmac;
+
+	mp->tx_frames += nr64_mac(TXMAC_FRM_CNT);
+	mp->tx_bytes += nr64_mac(TXMAC_BYTE_CNT);
+
+	mp->rx_link_faults += nr64_mac(LINK_FAULT_CNT);
+	mp->rx_align_errors += nr64_mac(RXMAC_ALIGN_ERR_CNT);
+	mp->rx_frags += nr64_mac(RXMAC_FRAG_CNT);
+	mp->rx_mcasts += nr64_mac(RXMAC_MC_FRM_CNT);
+	mp->rx_bcasts += nr64_mac(RXMAC_BC_FRM_CNT);
+	mp->rx_hist_cnt1 += nr64_mac(RXMAC_HIST_CNT1);
+	mp->rx_hist_cnt2 += nr64_mac(RXMAC_HIST_CNT2);
+	mp->rx_hist_cnt3 += nr64_mac(RXMAC_HIST_CNT3);
+	mp->rx_hist_cnt4 += nr64_mac(RXMAC_HIST_CNT4);
+	mp->rx_hist_cnt5 += nr64_mac(RXMAC_HIST_CNT5);
+	mp->rx_hist_cnt6 += nr64_mac(RXMAC_HIST_CNT6);
+	mp->rx_hist_cnt7 += nr64_mac(RXMAC_HIST_CNT7);
+	mp->rx_octets += nr64_mac(RXMAC_BT_CNT);
+	mp->rx_code_violations += nr64_mac(RXMAC_CD_VIO_CNT);
+	mp->rx_len_errors += nr64_mac(RXMAC_MPSZER_CNT);
+	mp->rx_crc_errors += nr64_mac(RXMAC_CRC_ER_CNT);
+}
+
+static void niu_sync_bmac_stats(struct niu *np)
+{
+	struct niu_bmac_stats *mp = &np->mac_stats.bmac;
+
+	mp->tx_bytes += nr64_mac(BTXMAC_BYTE_CNT);
+	mp->tx_frames += nr64_mac(BTXMAC_FRM_CNT);
+
+	mp->rx_frames += nr64_mac(BRXMAC_FRAME_CNT);
+	mp->rx_align_errors += nr64_mac(BRXMAC_ALIGN_ERR_CNT);
+	mp->rx_crc_errors += nr64_mac(BRXMAC_ALIGN_ERR_CNT);
+	mp->rx_len_errors += nr64_mac(BRXMAC_CODE_VIOL_ERR_CNT);
+}
+
+static void niu_sync_mac_stats(struct niu *np)
+{
+	if (np->flags & NIU_FLAGS_XMAC)
+		niu_sync_xmac_stats(np);
+	else
+		niu_sync_bmac_stats(np);
+}
+
+static void niu_get_rx_stats(struct niu *np)
+{
+	unsigned long pkts, dropped, errors, bytes;
+	int i;
+
+	pkts = dropped = errors = bytes = 0;
+	for (i = 0; i < np->num_rx_rings; i++) {
+		struct rx_ring_info *rp = &np->rx_rings[i];
+
+		pkts += rp->rx_packets;
+		bytes += rp->rx_bytes;
+		dropped += rp->rx_dropped;
+		errors += rp->rx_errors;
+	}
+	np->net_stats.rx_packets = pkts;
+	np->net_stats.rx_bytes = bytes;
+	np->net_stats.rx_dropped = dropped;
+	np->net_stats.rx_errors = errors;
+}
+
+static void niu_get_tx_stats(struct niu *np)
+{
+	unsigned long pkts, errors, bytes;
+	int i;
+
+	pkts = errors = bytes = 0;
+	for (i = 0; i < np->num_tx_rings; i++) {
+		struct tx_ring_info *rp = &np->tx_rings[i];
+
+		pkts += rp->tx_packets;
+		bytes += rp->tx_bytes;
+		errors += rp->tx_errors;
+	}
+	np->net_stats.tx_packets = pkts;
+	np->net_stats.tx_bytes = bytes;
+	np->net_stats.tx_errors = errors;
+}
+
+static struct net_device_stats *niu_get_stats(struct net_device *dev)
+{
+	struct niu *np = netdev_priv(dev);
+
+	niu_get_rx_stats(np);
+	niu_get_tx_stats(np);
+
+	return &np->net_stats;
+}
+
+static void niu_load_hash_xmac(struct niu *np, u16 *hash)
+{
+	int i;
+
+	for (i = 0; i < 16; i++)
+		nw64_mac(XMAC_HASH_TBL(i), hash[i]);
+}
+
+static void niu_load_hash_bmac(struct niu *np, u16 *hash)
+{
+	int i;
+
+	for (i = 0; i < 16; i++)
+		nw64_mac(BMAC_HASH_TBL(i), hash[i]);
+}
+
+static void niu_load_hash(struct niu *np, u16 *hash)
+{
+	if (np->flags & NIU_FLAGS_XMAC)
+		niu_load_hash_xmac(np, hash);
+	else
+		niu_load_hash_bmac(np, hash);
+}
+
+static void niu_set_rx_mode(struct net_device *dev)
+{
+	struct niu *np = netdev_priv(dev);
+	int i, alt_cnt, err;
+	struct dev_addr_list *addr;
+	unsigned long flags;
+	u16 hash[16] = { 0, };
+
+	spin_lock_irqsave(&np->lock, flags);
+	niu_enable_rx_mac(np, 0);
+
+	np->flags &= ~(NIU_FLAGS_MCAST | NIU_FLAGS_PROMISC);
+	if (dev->flags & IFF_PROMISC)
+		np->flags |= NIU_FLAGS_PROMISC;
+	if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 0))
+		np->flags |= NIU_FLAGS_MCAST;
+
+	alt_cnt = dev->uc_count;
+	if (alt_cnt > niu_num_alt_addr(np)) {
+		alt_cnt = 0;
+		np->flags |= NIU_FLAGS_PROMISC;
+	}
+
+	if (alt_cnt) {
+		int index = 0;
+
+		for (addr = dev->uc_list; addr; addr = addr->next) {
+			err = niu_set_alt_mac(np, index,
+					      addr->da_addr);
+			if (err)
+				printk(KERN_WARNING PFX "%s: Error %d "
+				       "adding alt mac %d\n",
+				       dev->name, err, index);
+			err = niu_enable_alt_mac(np, index, 1);
+			if (err)
+				printk(KERN_WARNING PFX "%s: Error %d "
+				       "enabling alt mac %d\n",
+				       dev->name, err, index);
+
+			index++;
+		}
+	} else {
+		for (i = 0; i < niu_num_alt_addr(np); i++) {
+			err = niu_enable_alt_mac(np, i, 0);
+			if (err)
+				printk(KERN_WARNING PFX "%s: Error %d "
+				       "disabling alt mac %d\n",
+				       dev->name, err, i);
+		}
+	}
+	if (dev->flags & IFF_ALLMULTI) {
+		for (i = 0; i < 16; i++)
+			hash[i] = 0xffff;
+	} else if (dev->mc_count > 0) {
+		for (addr = dev->mc_list; addr; addr = addr->next) {
+			u32 crc = ether_crc_le(ETH_ALEN, addr->da_addr);
+
+			crc >>= 24;
+			hash[crc >> 4] |= (1 << (15 - (crc & 0xf)));
+		}
+	}
+
+	if (np->flags & NIU_FLAGS_MCAST)
+		niu_load_hash(np, hash);
+
+	niu_enable_rx_mac(np, 1);
+	spin_unlock_irqrestore(&np->lock, flags);
+}
+
+static int niu_set_mac_addr(struct net_device *dev, void *p)
+{
+	struct niu *np = netdev_priv(dev);
+	struct sockaddr *addr = p;
+	unsigned long flags;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EINVAL;
+
+	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+
+	if (!netif_running(dev))
+		return 0;
+
+	spin_lock_irqsave(&np->lock, flags);
+	niu_enable_rx_mac(np, 0);
+	niu_set_primary_mac(np, dev->dev_addr);
+	niu_enable_rx_mac(np, 1);
+	spin_unlock_irqrestore(&np->lock, flags);
+
+	return 0;
+}
+
+static int niu_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	return -EOPNOTSUPP;
+}
+
+static void niu_netif_stop(struct niu *np)
+{
+	np->dev->trans_start = jiffies;	/* prevent tx timeout */
+
+	niu_disable_napi(np);
+
+	netif_tx_disable(np->dev);
+}
+
+static void niu_netif_start(struct niu *np)
+{
+	/* NOTE: unconditional netif_wake_queue is only appropriate
+	 * so long as all callers are assured to have free tx slots
+	 * (such as after niu_init_hw).
+	 */
+	netif_wake_queue(np->dev);
+
+	niu_enable_napi(np);
+
+	niu_enable_interrupts(np, 1);
+}
+
+static void niu_reset_task(struct work_struct *work)
+{
+	struct niu *np = container_of(work, struct niu, reset_task);
+	unsigned long flags;
+	int err;
+
+	spin_lock_irqsave(&np->lock, flags);
+	if (!netif_running(np->dev)) {
+		spin_unlock_irqrestore(&np->lock, flags);
+		return;
+	}
+
+	spin_unlock_irqrestore(&np->lock, flags);
+
+	del_timer_sync(&np->timer);
+
+	niu_netif_stop(np);
+
+	spin_lock_irqsave(&np->lock, flags);
+
+	niu_stop_hw(np);
+
+	err = niu_init_hw(np);
+	if (!err) {
+		np->timer.expires = jiffies + HZ;
+		add_timer(&np->timer);
+		niu_netif_start(np);
+	}
+
+	spin_unlock_irqrestore(&np->lock, flags);
+}
+
+static void niu_tx_timeout(struct net_device *dev)
+{
+	struct niu *np = netdev_priv(dev);
+
+	dev_err(np->device, PFX "%s: Transmit timed out, resetting\n",
+		dev->name);
+
+	schedule_work(&np->reset_task);
+}
+
+static void niu_set_txd(struct tx_ring_info *rp, int index,
+			u64 mapping, u64 len, u64 mark,
+			u64 n_frags)
+{
+	__le64 *desc = &rp->descr[index];
+
+	*desc = cpu_to_le64(mark |
+			    (n_frags << TX_DESC_NUM_PTR_SHIFT) |
+			    (len << TX_DESC_TR_LEN_SHIFT) |
+			    (mapping & TX_DESC_SAD));
+}
+
+static u64 niu_compute_tx_flags(struct sk_buff *skb, struct ethhdr *ehdr,
+				u64 pad_bytes, u64 len)
+{
+	u16 eth_proto, eth_proto_inner;
+	u64 csum_bits, l3off, ihl, ret;
+	u8 ip_proto;
+	int ipv6;
+
+	eth_proto = be16_to_cpu(ehdr->h_proto);
+	eth_proto_inner = eth_proto;
+	if (eth_proto == ETH_P_8021Q) {
+		struct vlan_ethhdr *vp = (struct vlan_ethhdr *) ehdr;
+		__be16 val = vp->h_vlan_encapsulated_proto;
+
+		eth_proto_inner = be16_to_cpu(val);
+	}
+
+	ipv6 = ihl = 0;
+	switch (skb->protocol) {
+	case __constant_htons(ETH_P_IP):
+		ip_proto = ip_hdr(skb)->protocol;
+		ihl = ip_hdr(skb)->ihl;
+		break;
+	case __constant_htons(ETH_P_IPV6):
+		ip_proto = ipv6_hdr(skb)->nexthdr;
+		ihl = (40 >> 2);
+		ipv6 = 1;
+		break;
+	default:
+		ip_proto = ihl = 0;
+		break;
+	}
+
+	csum_bits = TXHDR_CSUM_NONE;
+	if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		u64 start, stuff;
+
+		csum_bits = (ip_proto == IPPROTO_TCP ?
+			     TXHDR_CSUM_TCP :
+			     (ip_proto == IPPROTO_UDP ?
+			      TXHDR_CSUM_UDP : TXHDR_CSUM_SCTP));
+
+		start = skb_transport_offset(skb) -
+			(pad_bytes + sizeof(struct tx_pkt_hdr));
+		stuff = start + skb->csum_offset;
+
+		csum_bits |= (start / 2) << TXHDR_L4START_SHIFT;
+		csum_bits |= (stuff / 2) << TXHDR_L4STUFF_SHIFT;
+	}
+
+	l3off = skb_network_offset(skb) -
+		(pad_bytes + sizeof(struct tx_pkt_hdr));
+
+	ret = (((pad_bytes / 2) << TXHDR_PAD_SHIFT) |
+	       (len << TXHDR_LEN_SHIFT) |
+	       ((l3off / 2) << TXHDR_L3START_SHIFT) |
+	       (ihl << TXHDR_IHL_SHIFT) |
+	       ((eth_proto_inner < 1536) ? TXHDR_LLC : 0) |
+	       ((eth_proto == ETH_P_8021Q) ? TXHDR_VLAN : 0) |
+	       (ipv6 ? TXHDR_IP_VER : 0) |
+	       csum_bits);
+
+	return ret;
+}
+
+static struct tx_ring_info *tx_ring_select(struct niu *np, struct sk_buff *skb)
+{
+	return &np->tx_rings[0];
+}
+
+static int niu_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct niu *np = netdev_priv(dev);
+	unsigned long align, headroom;
+	struct tx_ring_info *rp;
+	struct tx_pkt_hdr *tp;
+	unsigned int len, nfg;
+	struct ethhdr *ehdr;
+	int prod, i, tlen;
+	u64 mapping, mrk;
+
+	rp = tx_ring_select(np, skb);
+
+	if (niu_tx_avail(rp) <= (skb_shinfo(skb)->nr_frags + 1)) {
+		netif_stop_queue(dev);
+		dev_err(np->device, PFX "%s: BUG! Tx ring full when "
+			"queue awake!\n", dev->name);
+		rp->tx_errors++;
+		return NETDEV_TX_BUSY;
+	}
+
+	if (skb->len < ETH_ZLEN) {
+		unsigned int pad_bytes = ETH_ZLEN - skb->len;
+
+		if (skb_pad(skb, pad_bytes))
+			goto out;
+		skb_put(skb, pad_bytes);
+	}
+
+	len = sizeof(struct tx_pkt_hdr) + 15;
+	if (skb_headroom(skb) < len) {
+		struct sk_buff *skb_new;
+
+		skb_new = skb_realloc_headroom(skb, len);
+		if (!skb_new) {
+			rp->tx_errors++;
+			goto out_drop;
+		}
+		kfree_skb(skb);
+		skb = skb_new;
+	}
+
+	align = ((unsigned long) skb->data & (16 - 1));
+	headroom = align + sizeof(struct tx_pkt_hdr);
+
+	ehdr = (struct ethhdr *) skb->data;
+	tp = (struct tx_pkt_hdr *) skb_push(skb, headroom);
+
+	len = skb->len - sizeof(struct tx_pkt_hdr);
+	tp->flags = cpu_to_le64(niu_compute_tx_flags(skb, ehdr, align, len));
+	tp->resv = 0;
+
+	len = skb_headlen(skb);
+	mapping = np->ops->map_single(np->device, skb->data,
+				      len, DMA_TO_DEVICE);
+
+	prod = rp->prod;
+
+	rp->tx_buffs[prod].skb = skb;
+	rp->tx_buffs[prod].mapping = mapping;
+
+	mrk = TX_DESC_SOP;
+	if (++rp->mark_counter == rp->mark_freq) {
+		rp->mark_counter = 0;
+		mrk |= TX_DESC_MARK;
+		rp->mark_pending++;
+	}
+
+	tlen = len;
+	nfg = skb_shinfo(skb)->nr_frags;
+	while (tlen > 0) {
+		tlen -= MAX_TX_DESC_LEN;
+		nfg++;
+	}
+
+	while (len > 0) {
+		unsigned int this_len = len;
+
+		if (this_len > MAX_TX_DESC_LEN)
+			this_len = MAX_TX_DESC_LEN;
+
+		niu_set_txd(rp, prod, mapping, this_len, mrk, nfg);
+		mrk = nfg = 0;
+
+		prod = NEXT_TX(rp, prod);
+		mapping += this_len;
+		len -= this_len;
+	}
+
+	for (i = 0; i <  skb_shinfo(skb)->nr_frags; i++) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+		len = frag->size;
+		mapping = np->ops->map_page(np->device, frag->page,
+					    frag->page_offset, len,
+					    DMA_TO_DEVICE);
+
+		rp->tx_buffs[prod].skb = NULL;
+		rp->tx_buffs[prod].mapping = mapping;
+
+		niu_set_txd(rp, prod, mapping, len, 0, 0);
+
+		prod = NEXT_TX(rp, prod);
+	}
+
+	if (prod < rp->prod)
+		rp->wrap_bit ^= TX_RING_KICK_WRAP;
+	rp->prod = prod;
+
+	nw64(TX_RING_KICK(rp->tx_channel), rp->wrap_bit | (prod << 3));
+
+	if (unlikely(niu_tx_avail(rp) <= (MAX_SKB_FRAGS + 1))) {
+		netif_stop_queue(dev);
+		if (niu_tx_avail(rp) > NIU_TX_WAKEUP_THRESH(rp))
+			netif_wake_queue(dev);
+	}
+
+	dev->trans_start = jiffies;
+
+out:
+	return NETDEV_TX_OK;
+
+out_drop:
+	rp->tx_errors++;
+	kfree_skb(skb);
+	goto out;
+}
+
+static int niu_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct niu *np = netdev_priv(dev);
+	int err, orig_jumbo, new_jumbo;
+
+	if (new_mtu < 68 || new_mtu > NIU_MAX_MTU)
+		return -EINVAL;
+
+	orig_jumbo = (dev->mtu > ETH_DATA_LEN);
+	new_jumbo = (new_mtu > ETH_DATA_LEN);
+
+	dev->mtu = new_mtu;
+
+	if (!netif_running(dev) ||
+	    (orig_jumbo == new_jumbo))
+		return 0;
+
+	niu_full_shutdown(np, dev);
+
+	niu_free_channels(np);
+
+	niu_enable_napi(np);
+
+	err = niu_alloc_channels(np);
+	if (err)
+		return err;
+
+	spin_lock_irq(&np->lock);
+
+	err = niu_init_hw(np);
+	if (!err) {
+		init_timer(&np->timer);
+		np->timer.expires = jiffies + HZ;
+		np->timer.data = (unsigned long) np;
+		np->timer.function = niu_timer;
+
+		err = niu_enable_interrupts(np, 1);
+		if (err)
+			niu_stop_hw(np);
+	}
+
+	spin_unlock_irq(&np->lock);
+
+	if (!err) {
+		netif_start_queue(dev);
+		if (np->link_config.loopback_mode != LOOPBACK_DISABLED)
+			netif_carrier_on(dev);
+
+		add_timer(&np->timer);
+	}
+
+	return err;
+}
+
+static void niu_get_drvinfo(struct net_device *dev,
+			    struct ethtool_drvinfo *info)
+{
+	struct niu *np = netdev_priv(dev);
+	struct niu_vpd *vpd = &np->vpd;
+
+	strcpy(info->driver, DRV_MODULE_NAME);
+	strcpy(info->version, DRV_MODULE_VERSION);
+	sprintf(info->fw_version, "%d.%d",
+		vpd->fcode_major, vpd->fcode_minor);
+	if (np->parent->plat_type != PLAT_TYPE_NIU)
+		strcpy(info->bus_info, pci_name(np->pdev));
+}
+
+static int niu_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	struct niu *np = netdev_priv(dev);
+	struct niu_link_config *lp;
+
+	lp = &np->link_config;
+
+	memset(cmd, 0, sizeof(*cmd));
+	cmd->phy_address = np->phy_addr;
+	cmd->supported = lp->supported;
+	cmd->advertising = lp->advertising;
+	cmd->autoneg = lp->autoneg;
+	cmd->speed = lp->active_speed;
+	cmd->duplex = lp->active_duplex;
+
+	return 0;
+}
+
+static int niu_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	return -EINVAL;
+}
+
+static u32 niu_get_msglevel(struct net_device *dev)
+{
+	struct niu *np = netdev_priv(dev);
+	return np->msg_enable;
+}
+
+static void niu_set_msglevel(struct net_device *dev, u32 value)
+{
+	struct niu *np = netdev_priv(dev);
+	np->msg_enable = value;
+}
+
+static int niu_get_eeprom_len(struct net_device *dev)
+{
+	struct niu *np = netdev_priv(dev);
+
+	return np->eeprom_len;
+}
+
+static int niu_get_eeprom(struct net_device *dev,
+			  struct ethtool_eeprom *eeprom, u8 *data)
+{
+	struct niu *np = netdev_priv(dev);
+	u32 offset, len, val;
+
+	offset = eeprom->offset;
+	len = eeprom->len;
+
+	if (offset + len < offset)
+		return -EINVAL;
+	if (offset >= np->eeprom_len)
+		return -EINVAL;
+	if (offset + len > np->eeprom_len)
+		len = eeprom->len = np->eeprom_len - offset;
+
+	if (offset & 3) {
+		u32 b_offset, b_count;
+
+		b_offset = offset & 3;
+		b_count = 4 - b_offset;
+		if (b_count > len)
+			b_count = len;
+
+		val = nr64(ESPC_NCR((offset - b_offset) / 4));
+		memcpy(data, ((char *)&val) + b_offset, b_count);
+		data += b_count;
+		len -= b_count;
+		offset += b_count;
+	}
+	while (len >= 4) {
+		val = nr64(ESPC_NCR(offset / 4));
+		memcpy(data, &val, 4);
+		data += 4;
+		len -= 4;
+		offset += 4;
+	}
+	if (len) {
+		val = nr64(ESPC_NCR(offset / 4));
+		memcpy(data, &val, len);
+	}
+	return 0;
+}
+
+static const struct {
+	const char string[ETH_GSTRING_LEN];
+} niu_xmac_stat_keys[] = {
+	{ "tx_frames" },
+	{ "tx_bytes" },
+	{ "tx_fifo_errors" },
+	{ "tx_overflow_errors" },
+	{ "tx_max_pkt_size_errors" },
+	{ "tx_underflow_errors" },
+	{ "rx_local_faults" },
+	{ "rx_remote_faults" },
+	{ "rx_link_faults" },
+	{ "rx_align_errors" },
+	{ "rx_frags" },
+	{ "rx_mcasts" },
+	{ "rx_bcasts" },
+	{ "rx_hist_cnt1" },
+	{ "rx_hist_cnt2" },
+	{ "rx_hist_cnt3" },
+	{ "rx_hist_cnt4" },
+	{ "rx_hist_cnt5" },
+	{ "rx_hist_cnt6" },
+	{ "rx_hist_cnt7" },
+	{ "rx_octets" },
+	{ "rx_code_violations" },
+	{ "rx_len_errors" },
+	{ "rx_crc_errors" },
+	{ "rx_underflows" },
+	{ "rx_overflows" },
+	{ "pause_off_state" },
+	{ "pause_on_state" },
+	{ "pause_received" },
+};
+
+#define NUM_XMAC_STAT_KEYS	ARRAY_SIZE(niu_xmac_stat_keys)
+
+static const struct {
+	const char string[ETH_GSTRING_LEN];
+} niu_bmac_stat_keys[] = {
+	{ "tx_underflow_errors" },
+	{ "tx_max_pkt_size_errors" },
+	{ "tx_bytes" },
+	{ "tx_frames" },
+	{ "rx_overflows" },
+	{ "rx_frames" },
+	{ "rx_align_errors" },
+	{ "rx_crc_errors" },
+	{ "rx_len_errors" },
+	{ "pause_off_state" },
+	{ "pause_on_state" },
+	{ "pause_received" },
+};
+
+#define NUM_BMAC_STAT_KEYS	ARRAY_SIZE(niu_bmac_stat_keys)
+
+static const struct {
+	const char string[ETH_GSTRING_LEN];
+} niu_rxchan_stat_keys[] = {
+	{ "rx_channel" },
+	{ "rx_packets" },
+	{ "rx_bytes" },
+	{ "rx_dropped" },
+	{ "rx_errors" },
+};
+
+#define NUM_RXCHAN_STAT_KEYS	ARRAY_SIZE(niu_rxchan_stat_keys)
+
+static const struct {
+	const char string[ETH_GSTRING_LEN];
+} niu_txchan_stat_keys[] = {
+	{ "tx_channel" },
+	{ "tx_packets" },
+	{ "tx_bytes" },
+	{ "tx_errors" },
+};
+
+#define NUM_TXCHAN_STAT_KEYS	ARRAY_SIZE(niu_txchan_stat_keys)
+
+static void niu_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+	struct niu *np = netdev_priv(dev);
+	int i;
+
+	if (stringset != ETH_SS_STATS)
+		return;
+
+	if (np->flags & NIU_FLAGS_XMAC) {
+		memcpy(data, niu_xmac_stat_keys,
+		       sizeof(niu_xmac_stat_keys));
+		data += sizeof(niu_xmac_stat_keys);
+	} else {
+		memcpy(data, niu_bmac_stat_keys,
+		       sizeof(niu_bmac_stat_keys));
+		data += sizeof(niu_bmac_stat_keys);
+	}
+	for (i = 0; i < np->num_rx_rings; i++) {
+		memcpy(data, niu_rxchan_stat_keys,
+		       sizeof(niu_rxchan_stat_keys));
+		data += sizeof(niu_rxchan_stat_keys);
+	}
+	for (i = 0; i < np->num_tx_rings; i++) {
+		memcpy(data, niu_txchan_stat_keys,
+		       sizeof(niu_txchan_stat_keys));
+		data += sizeof(niu_txchan_stat_keys);
+	}
+}
+
+static int niu_get_stats_count(struct net_device *dev)
+{
+	struct niu *np = netdev_priv(dev);
+
+	return ((np->flags & NIU_FLAGS_XMAC ?
+		 NUM_XMAC_STAT_KEYS :
+		 NUM_BMAC_STAT_KEYS) +
+		(np->num_rx_rings * NUM_RXCHAN_STAT_KEYS) +
+		(np->num_tx_rings * NUM_TXCHAN_STAT_KEYS));
+}
+
+static void niu_get_ethtool_stats(struct net_device *dev,
+				  struct ethtool_stats *stats, u64 *data)
+{
+	struct niu *np = netdev_priv(dev);
+	int i;
+
+	niu_sync_mac_stats(np);
+	if (np->flags & NIU_FLAGS_XMAC) {
+		memcpy(data, &np->mac_stats.xmac,
+		       sizeof(struct niu_xmac_stats));
+		data += (sizeof(struct niu_xmac_stats) / sizeof(u64));
+	} else {
+		memcpy(data, &np->mac_stats.bmac,
+		       sizeof(struct niu_bmac_stats));
+		data += (sizeof(struct niu_bmac_stats) / sizeof(u64));
+	}
+	for (i = 0; i < np->num_rx_rings; i++) {
+		struct rx_ring_info *rp = &np->rx_rings[i];
+
+		data[0] = rp->rx_channel;
+		data[1] = rp->rx_packets;
+		data[2] = rp->rx_bytes;
+		data[3] = rp->rx_dropped;
+		data[4] = rp->rx_errors;
+		data += 5;
+	}
+	for (i = 0; i < np->num_tx_rings; i++) {
+		struct tx_ring_info *rp = &np->tx_rings[i];
+
+		data[0] = rp->tx_channel;
+		data[1] = rp->tx_packets;
+		data[2] = rp->tx_bytes;
+		data[3] = rp->tx_errors;
+		data += 4;
+	}
+}
+
+static u64 niu_led_state_save(struct niu *np)
+{
+	if (np->flags & NIU_FLAGS_XMAC)
+		return nr64_mac(XMAC_CONFIG);
+	else
+		return nr64_mac(BMAC_XIF_CONFIG);
+}
+
+static void niu_led_state_restore(struct niu *np, u64 val)
+{
+	if (np->flags & NIU_FLAGS_XMAC)
+		nw64_mac(XMAC_CONFIG, val);
+	else
+		nw64_mac(BMAC_XIF_CONFIG, val);
+}
+
+static void niu_force_led(struct niu *np, int on)
+{
+	u64 val, reg, bit;
+
+	if (np->flags & NIU_FLAGS_XMAC) {
+		reg = XMAC_CONFIG;
+		bit = XMAC_CONFIG_FORCE_LED_ON;
+	} else {
+		reg = BMAC_XIF_CONFIG;
+		bit = BMAC_XIF_CONFIG_LINK_LED;
+	}
+
+	val = nr64_mac(reg);
+	if (on)
+		val |= bit;
+	else
+		val &= ~bit;
+	nw64_mac(reg, val);
+}
+
+static int niu_phys_id(struct net_device *dev, u32 data)
+{
+	struct niu *np = netdev_priv(dev);
+	u64 orig_led_state;
+	int i;
+
+	if (!netif_running(dev))
+		return -EAGAIN;
+
+	if (data == 0)
+		data = 2;
+
+	orig_led_state = niu_led_state_save(np);
+	for (i = 0; i < (data * 2); i++) {
+		int on = ((i % 2) == 0);
+
+		niu_force_led(np, on);
+
+		if (msleep_interruptible(500))
+			break;
+	}
+	niu_led_state_restore(np, orig_led_state);
+
+	return 0;
+}
+
+static const struct ethtool_ops niu_ethtool_ops = {
+	.get_drvinfo		= niu_get_drvinfo,
+	.get_link		= ethtool_op_get_link,
+	.get_msglevel		= niu_get_msglevel,
+	.set_msglevel		= niu_set_msglevel,
+	.get_eeprom_len		= niu_get_eeprom_len,
+	.get_eeprom		= niu_get_eeprom,
+	.get_settings		= niu_get_settings,
+	.set_settings		= niu_set_settings,
+	.get_strings		= niu_get_strings,
+	.get_stats_count	= niu_get_stats_count,
+	.get_ethtool_stats	= niu_get_ethtool_stats,
+	.phys_id		= niu_phys_id,
+};
+
+static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent,
+			      int ldg, int ldn)
+{
+	if (ldg < NIU_LDG_MIN || ldg > NIU_LDG_MAX)
+		return -EINVAL;
+	if (ldn < 0 || ldn > LDN_MAX)
+		return -EINVAL;
+
+	parent->ldg_map[ldn] = ldg;
+
+	if (np->parent->plat_type == PLAT_TYPE_NIU) {
+		/* On N2 NIU, the ldn-->ldg assignments are setup and fixed by
+		 * the firmware, and we're not supposed to change them.
+		 * Validate the mapping, because if it's wrong we probably
+		 * won't get any interrupts and that's painful to debug.
+		 */
+		if (nr64(LDG_NUM(ldn)) != ldg) {
+			dev_err(np->device, PFX "Port %u, mis-matched "
+				"LDG assignment "
+				"for ldn %d, should be %d is %llu\n",
+				np->port, ldn, ldg,
+				(unsigned long long) nr64(LDG_NUM(ldn)));
+			return -EINVAL;
+		}
+	} else
+		nw64(LDG_NUM(ldn), ldg);
+
+	return 0;
+}
+
+static int niu_set_ldg_timer_res(struct niu *np, int res)
+{
+	if (res < 0 || res > LDG_TIMER_RES_VAL)
+		return -EINVAL;
+
+
+	nw64(LDG_TIMER_RES, res);
+
+	return 0;
+}
+
+static int niu_set_ldg_sid(struct niu *np, int ldg, int func, int vector)
+{
+	if ((ldg < NIU_LDG_MIN || ldg > NIU_LDG_MAX) ||
+	    (func < 0 || func > 3) ||
+	    (vector < 0 || vector > 0x1f))
+		return -EINVAL;
+
+	nw64(SID(ldg), (func << SID_FUNC_SHIFT) | vector);
+
+	return 0;
+}
+
+static int __devinit niu_pci_eeprom_read(struct niu *np, u32 addr)
+{
+	u64 frame, frame_base = (ESPC_PIO_STAT_READ_START |
+				 (addr << ESPC_PIO_STAT_ADDR_SHIFT));
+	int limit;
+
+	if (addr > (ESPC_PIO_STAT_ADDR >> ESPC_PIO_STAT_ADDR_SHIFT))
+		return -EINVAL;
+
+	frame = frame_base;
+	nw64(ESPC_PIO_STAT, frame);
+	limit = 64;
+	do {
+		udelay(5);
+		frame = nr64(ESPC_PIO_STAT);
+		if (frame & ESPC_PIO_STAT_READ_END)
+			break;
+	} while (limit--);
+	if (!(frame & ESPC_PIO_STAT_READ_END)) {
+		dev_err(np->device, PFX "EEPROM read timeout frame[%llx]\n",
+			(unsigned long long) frame);
+		return -ENODEV;
+	}
+
+	frame = frame_base;
+	nw64(ESPC_PIO_STAT, frame);
+	limit = 64;
+	do {
+		udelay(5);
+		frame = nr64(ESPC_PIO_STAT);
+		if (frame & ESPC_PIO_STAT_READ_END)
+			break;
+	} while (limit--);
+	if (!(frame & ESPC_PIO_STAT_READ_END)) {
+		dev_err(np->device, PFX "EEPROM read timeout frame[%llx]\n",
+			(unsigned long long) frame);
+		return -ENODEV;
+	}
+
+	frame = nr64(ESPC_PIO_STAT);
+	return (frame & ESPC_PIO_STAT_DATA) >> ESPC_PIO_STAT_DATA_SHIFT;
+}
+
+static int __devinit niu_pci_eeprom_read16(struct niu *np, u32 off)
+{
+	int err = niu_pci_eeprom_read(np, off);
+	u16 val;
+
+	if (err < 0)
+		return err;
+	val = (err << 8);
+	err = niu_pci_eeprom_read(np, off + 1);
+	if (err < 0)
+		return err;
+	val |= (err & 0xff);
+
+	return val;
+}
+
+static int __devinit niu_pci_eeprom_read16_swp(struct niu *np, u32 off)
+{
+	int err = niu_pci_eeprom_read(np, off);
+	u16 val;
+
+	if (err < 0)
+		return err;
+
+	val = (err & 0xff);
+	err = niu_pci_eeprom_read(np, off + 1);
+	if (err < 0)
+		return err;
+
+	val |= (err & 0xff) << 8;
+
+	return val;
+}
+
+static int __devinit niu_pci_vpd_get_propname(struct niu *np,
+					      u32 off,
+					      char *namebuf,
+					      int namebuf_len)
+{
+	int i;
+
+	for (i = 0; i < namebuf_len; i++) {
+		int err = niu_pci_eeprom_read(np, off + i);
+		if (err < 0)
+			return err;
+		*namebuf++ = err;
+		if (!err)
+			break;
+	}
+	if (i >= namebuf_len)
+		return -EINVAL;
+
+	return i + 1;
+}
+
+static void __devinit niu_vpd_parse_version(struct niu *np)
+{
+	struct niu_vpd *vpd = &np->vpd;
+	int len = strlen(vpd->version) + 1;
+	const char *s = vpd->version;
+	int i;
+
+	for (i = 0; i < len - 5; i++) {
+		if (!strncmp(s + i, "FCode ", 5))
+			break;
+	}
+	if (i >= len - 5)
+		return;
+
+	s += i + 5;
+	sscanf(s, "%d.%d", &vpd->fcode_major, &vpd->fcode_minor);
+
+	niudbg(PROBE, "VPD_SCAN: FCODE major(%d) minor(%d)\n",
+	       vpd->fcode_major, vpd->fcode_minor);
+	if (vpd->fcode_major > NIU_VPD_MIN_MAJOR ||
+	    (vpd->fcode_major == NIU_VPD_MIN_MAJOR &&
+	     vpd->fcode_minor >= NIU_VPD_MIN_MINOR))
+		np->flags |= NIU_FLAGS_VPD_VALID;
+}
+
+/* ESPC_PIO_EN_ENABLE must be set */
+static int __devinit niu_pci_vpd_scan_props(struct niu *np,
+					    u32 start, u32 end)
+{
+	unsigned int found_mask = 0;
+#define FOUND_MASK_MODEL	0x00000001
+#define FOUND_MASK_BMODEL	0x00000002
+#define FOUND_MASK_VERS		0x00000004
+#define FOUND_MASK_MAC		0x00000008
+#define FOUND_MASK_NMAC		0x00000010
+#define FOUND_MASK_PHY		0x00000020
+#define FOUND_MASK_ALL		0x0000003f
+
+	niudbg(PROBE, "VPD_SCAN: start[%x] end[%x]\n",
+	       start, end);
+	while (start < end) {
+		int len, err, instance, type, prop_len;
+		char namebuf[64];
+		u8 *prop_buf;
+		int max_len;
+
+		if (found_mask == FOUND_MASK_ALL) {
+			niu_vpd_parse_version(np);
+			return 1;
+		}
+
+		err = niu_pci_eeprom_read(np, start + 2);
+		if (err < 0)
+			return err;
+		len = err;
+		start += 3;
+
+		instance = niu_pci_eeprom_read(np, start);
+		type = niu_pci_eeprom_read(np, start + 3);
+		prop_len = niu_pci_eeprom_read(np, start + 4);
+		err = niu_pci_vpd_get_propname(np, start + 5, namebuf, 64);
+		if (err < 0)
+			return err;
+
+		prop_buf = NULL;
+		max_len = 0;
+		if (!strcmp(namebuf, "model")) {
+			prop_buf = np->vpd.model;
+			max_len = NIU_VPD_MODEL_MAX;
+			found_mask |= FOUND_MASK_MODEL;
+		} else if (!strcmp(namebuf, "board-model")) {
+			prop_buf = np->vpd.board_model;
+			max_len = NIU_VPD_BD_MODEL_MAX;
+			found_mask |= FOUND_MASK_BMODEL;
+		} else if (!strcmp(namebuf, "version")) {
+			prop_buf = np->vpd.version;
+			max_len = NIU_VPD_VERSION_MAX;
+			found_mask |= FOUND_MASK_VERS;
+		} else if (!strcmp(namebuf, "local-mac-address")) {
+			prop_buf = np->vpd.local_mac;
+			max_len = ETH_ALEN;
+			found_mask |= FOUND_MASK_MAC;
+		} else if (!strcmp(namebuf, "num-mac-addresses")) {
+			prop_buf = &np->vpd.mac_num;
+			max_len = 1;
+			found_mask |= FOUND_MASK_NMAC;
+		} else if (!strcmp(namebuf, "phy-type")) {
+			prop_buf = np->vpd.phy_type;
+			max_len = NIU_VPD_PHY_TYPE_MAX;
+			found_mask |= FOUND_MASK_PHY;
+		}
+
+		if (max_len && prop_len > max_len) {
+			dev_err(np->device, PFX "Property '%s' length (%d) is "
+				"too long.\n", namebuf, prop_len);
+			return -EINVAL;
+		}
+
+		if (prop_buf) {
+			u32 off = start + 5 + err;
+			int i;
+
+			niudbg(PROBE, "VPD_SCAN: Reading in property [%s] "
+			       "len[%d]\n", namebuf, prop_len);
+			for (i = 0; i < prop_len; i++)
+				*prop_buf++ = niu_pci_eeprom_read(np, off + i);
+		}
+
+		start += len;
+	}
+
+	return 0;
+}
+
+/* ESPC_PIO_EN_ENABLE must be set */
+static void __devinit niu_pci_vpd_fetch(struct niu *np, u32 start)
+{
+	u32 offset;
+	int err;
+
+	err = niu_pci_eeprom_read16_swp(np, start + 1);
+	if (err < 0)
+		return;
+
+	offset = err + 3;
+
+	while (start + offset < ESPC_EEPROM_SIZE) {
+		u32 here = start + offset;
+		u32 end;
+
+		err = niu_pci_eeprom_read(np, here);
+		if (err != 0x90)
+			return;
+
+		err = niu_pci_eeprom_read16_swp(np, here + 1);
+		if (err < 0)
+			return;
+
+		here = start + offset + 3;
+		end = start + offset + err;
+
+		offset += err;
+
+		err = niu_pci_vpd_scan_props(np, here, end);
+		if (err < 0 || err == 1)
+			return;
+	}
+}
+
+/* ESPC_PIO_EN_ENABLE must be set */
+static u32 __devinit niu_pci_vpd_offset(struct niu *np)
+{
+	u32 start = 0, end = ESPC_EEPROM_SIZE, ret;
+	int err;
+
+	while (start < end) {
+		ret = start;
+
+		/* ROM header signature?  */
+		err = niu_pci_eeprom_read16(np, start +  0);
+		if (err != 0x55aa)
+			return 0;
+
+		/* Apply offset to PCI data structure.  */
+		err = niu_pci_eeprom_read16(np, start + 23);
+		if (err < 0)
+			return 0;
+		start += err;
+
+		/* Check for "PCIR" signature.  */
+		err = niu_pci_eeprom_read16(np, start +  0);
+		if (err != 0x5043)
+			return 0;
+		err = niu_pci_eeprom_read16(np, start +  2);
+		if (err != 0x4952)
+			return 0;
+
+		/* Check for OBP image type.  */
+		err = niu_pci_eeprom_read(np, start + 20);
+		if (err < 0)
+			return 0;
+		if (err != 0x01) {
+			err = niu_pci_eeprom_read(np, ret + 2);
+			if (err < 0)
+				return 0;
+
+			start = ret + (err * 512);
+			continue;
+		}
+
+		err = niu_pci_eeprom_read16_swp(np, start + 8);
+		if (err < 0)
+			return err;
+		ret += err;
+
+		err = niu_pci_eeprom_read(np, ret + 0);
+		if (err != 0x82)
+			return 0;
+
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __devinit niu_phy_type_prop_decode(struct niu *np,
+					      const char *phy_prop)
+{
+	if (!strcmp(phy_prop, "mif")) {
+		/* 1G copper, MII */
+		np->flags &= ~(NIU_FLAGS_FIBER |
+			       NIU_FLAGS_10G);
+		np->mac_xcvr = MAC_XCVR_MII;
+	} else if (!strcmp(phy_prop, "xgf")) {
+		/* 10G fiber, XPCS */
+		np->flags |= (NIU_FLAGS_10G |
+			      NIU_FLAGS_FIBER);
+		np->mac_xcvr = MAC_XCVR_XPCS;
+	} else if (!strcmp(phy_prop, "pcs")) {
+		/* 1G fiber, PCS */
+		np->flags &= ~NIU_FLAGS_10G;
+		np->flags |= NIU_FLAGS_FIBER;
+		np->mac_xcvr = MAC_XCVR_PCS;
+	} else if (!strcmp(phy_prop, "xgc")) {
+		/* 10G copper, XPCS */
+		np->flags |= NIU_FLAGS_10G;
+		np->flags &= ~NIU_FLAGS_FIBER;
+		np->mac_xcvr = MAC_XCVR_XPCS;
+	} else {
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void __devinit niu_pci_vpd_validate(struct niu *np)
+{
+	struct net_device *dev = np->dev;
+	struct niu_vpd *vpd = &np->vpd;
+	u8 val8;
+
+	if (!is_valid_ether_addr(&vpd->local_mac[0])) {
+		dev_err(np->device, PFX "VPD MAC invalid, "
+			"falling back to SPROM.\n");
+
+		np->flags &= ~NIU_FLAGS_VPD_VALID;
+		return;
+	}
+
+	if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) {
+		dev_err(np->device, PFX "Illegal phy string [%s].\n",
+			np->vpd.phy_type);
+		dev_err(np->device, PFX "Falling back to SPROM.\n");
+		np->flags &= ~NIU_FLAGS_VPD_VALID;
+		return;
+	}
+
+	memcpy(dev->perm_addr, vpd->local_mac, ETH_ALEN);
+
+	val8 = dev->perm_addr[5];
+	dev->perm_addr[5] += np->port;
+	if (dev->perm_addr[5] < val8)
+		dev->perm_addr[4]++;
+
+	memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
+}
+
+static int __devinit niu_pci_probe_sprom(struct niu *np)
+{
+	struct net_device *dev = np->dev;
+	int len, i;
+	u64 val, sum;
+	u8 val8;
+
+	val = (nr64(ESPC_VER_IMGSZ) & ESPC_VER_IMGSZ_IMGSZ);
+	val >>= ESPC_VER_IMGSZ_IMGSZ_SHIFT;
+	len = val / 4;
+
+	np->eeprom_len = len;
+
+	niudbg(PROBE, "SPROM: Image size %llu\n", (unsigned long long) val);
+
+	sum = 0;
+	for (i = 0; i < len; i++) {
+		val = nr64(ESPC_NCR(i));
+		sum += (val >>  0) & 0xff;
+		sum += (val >>  8) & 0xff;
+		sum += (val >> 16) & 0xff;
+		sum += (val >> 24) & 0xff;
+	}
+	niudbg(PROBE, "SPROM: Checksum %x\n", (int)(sum & 0xff));
+	if ((sum & 0xff) != 0xab) {
+		dev_err(np->device, PFX "Bad SPROM checksum "
+			"(%x, should be 0xab)\n", (int) (sum & 0xff));
+		return -EINVAL;
+	}
+
+	val = nr64(ESPC_PHY_TYPE);
+	switch (np->port) {
+	case 0:
+		val = (val & ESPC_PHY_TYPE_PORT0) >>
+			ESPC_PHY_TYPE_PORT0_SHIFT;
+		break;
+	case 1:
+		val = (val & ESPC_PHY_TYPE_PORT1) >>
+			ESPC_PHY_TYPE_PORT1_SHIFT;
+		break;
+	case 2:
+		val = (val & ESPC_PHY_TYPE_PORT2) >>
+			ESPC_PHY_TYPE_PORT2_SHIFT;
+		break;
+	case 3:
+		val = (val & ESPC_PHY_TYPE_PORT3) >>
+			ESPC_PHY_TYPE_PORT3_SHIFT;
+		break;
+	default:
+		dev_err(np->device, PFX "Bogus port number %u\n",
+			np->port);
+		return -EINVAL;
+	}
+	niudbg(PROBE, "SPROM: PHY type %llx\n", (unsigned long long) val);
+
+	switch (val) {
+	case ESPC_PHY_TYPE_1G_COPPER:
+		/* 1G copper, MII */
+		np->flags &= ~(NIU_FLAGS_FIBER |
+			       NIU_FLAGS_10G);
+		np->mac_xcvr = MAC_XCVR_MII;
+		break;
+
+	case ESPC_PHY_TYPE_1G_FIBER:
+		/* 1G fiber, PCS */
+		np->flags &= ~NIU_FLAGS_10G;
+		np->flags |= NIU_FLAGS_FIBER;
+		np->mac_xcvr = MAC_XCVR_PCS;
+		break;
+
+	case ESPC_PHY_TYPE_10G_COPPER:
+		/* 10G copper, XPCS */
+		np->flags |= NIU_FLAGS_10G;
+		np->flags &= ~NIU_FLAGS_FIBER;
+		np->mac_xcvr = MAC_XCVR_XPCS;
+		break;
+
+	case ESPC_PHY_TYPE_10G_FIBER:
+		/* 10G fiber, XPCS */
+		np->flags |= (NIU_FLAGS_10G |
+			      NIU_FLAGS_FIBER);
+		np->mac_xcvr = MAC_XCVR_XPCS;
+		break;
+
+	default:
+		dev_err(np->device, PFX "Bogus SPROM phy type %llu\n",
+			(unsigned long long) val);
+		return -EINVAL;
+	}
+
+	val = nr64(ESPC_MAC_ADDR0);
+	niudbg(PROBE, "SPROM: MAC_ADDR0[%08llx]\n",
+	       (unsigned long long) val);
+	dev->perm_addr[0] = (val >>  0) & 0xff;
+	dev->perm_addr[1] = (val >>  8) & 0xff;
+	dev->perm_addr[2] = (val >> 16) & 0xff;
+	dev->perm_addr[3] = (val >> 24) & 0xff;
+
+	val = nr64(ESPC_MAC_ADDR1);
+	niudbg(PROBE, "SPROM: MAC_ADDR1[%08llx]\n",
+	       (unsigned long long) val);
+	dev->perm_addr[4] = (val >>  0) & 0xff;
+	dev->perm_addr[5] = (val >>  8) & 0xff;
+
+	if (!is_valid_ether_addr(&dev->perm_addr[0])) {
+		dev_err(np->device, PFX "SPROM MAC address invalid\n");
+		dev_err(np->device, PFX "[ \n");
+		for (i = 0; i < 6; i++)
+			printk("%02x ", dev->perm_addr[i]);
+		printk("]\n");
+		return -EINVAL;
+	}
+
+	val8 = dev->perm_addr[5];
+	dev->perm_addr[5] += np->port;
+	if (dev->perm_addr[5] < val8)
+		dev->perm_addr[4]++;
+
+	memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
+
+	val = nr64(ESPC_MOD_STR_LEN);
+	niudbg(PROBE, "SPROM: MOD_STR_LEN[%llu]\n",
+	       (unsigned long long) val);
+	if (val > 8 * 4)
+		return -EINVAL;
+
+	for (i = 0; i < val; i += 4) {
+		u64 tmp = nr64(ESPC_NCR(5 + (i / 4)));
+
+		np->vpd.model[i + 3] = (tmp >>  0) & 0xff;
+		np->vpd.model[i + 2] = (tmp >>  8) & 0xff;
+		np->vpd.model[i + 1] = (tmp >> 16) & 0xff;
+		np->vpd.model[i + 0] = (tmp >> 24) & 0xff;
+	}
+	np->vpd.model[val] = '\0';
+
+	val = nr64(ESPC_BD_MOD_STR_LEN);
+	niudbg(PROBE, "SPROM: BD_MOD_STR_LEN[%llu]\n",
+	       (unsigned long long) val);
+	if (val > 4 * 4)
+		return -EINVAL;
+
+	for (i = 0; i < val; i += 4) {
+		u64 tmp = nr64(ESPC_NCR(14 + (i / 4)));
+
+		np->vpd.board_model[i + 3] = (tmp >>  0) & 0xff;
+		np->vpd.board_model[i + 2] = (tmp >>  8) & 0xff;
+		np->vpd.board_model[i + 1] = (tmp >> 16) & 0xff;
+		np->vpd.board_model[i + 0] = (tmp >> 24) & 0xff;
+	}
+	np->vpd.board_model[val] = '\0';
+
+	np->vpd.mac_num =
+		nr64(ESPC_NUM_PORTS_MACS) & ESPC_NUM_PORTS_MACS_VAL;
+	niudbg(PROBE, "SPROM: NUM_PORTS_MACS[%d]\n",
+	       np->vpd.mac_num);
+
+	return 0;
+}
+
+static int __devinit niu_get_and_validate_port(struct niu *np)
+{
+	struct niu_parent *parent = np->parent;
+
+	if (np->port <= 1)
+		np->flags |= NIU_FLAGS_XMAC;
+
+	if (!parent->num_ports) {
+		if (parent->plat_type == PLAT_TYPE_NIU) {
+			parent->num_ports = 2;
+		} else {
+			parent->num_ports = nr64(ESPC_NUM_PORTS_MACS) &
+				ESPC_NUM_PORTS_MACS_VAL;
+
+			if (!parent->num_ports)
+				parent->num_ports = 4;
+		}
+	}
+
+	niudbg(PROBE, "niu_get_and_validate_port: port[%d] num_ports[%d]\n",
+	       np->port, parent->num_ports);
+	if (np->port >= parent->num_ports)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int __devinit phy_record(struct niu_parent *parent,
+				struct phy_probe_info *p,
+				int dev_id_1, int dev_id_2, u8 phy_port,
+				int type)
+{
+	u32 id = (dev_id_1 << 16) | dev_id_2;
+	u8 idx;
+
+	if (dev_id_1 < 0 || dev_id_2 < 0)
+		return 0;
+	if (type == PHY_TYPE_PMA_PMD || type == PHY_TYPE_PCS) {
+		if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM8704)
+			return 0;
+	} else {
+		if ((id & NIU_PHY_ID_MASK) != NIU_PHY_ID_BCM5464R)
+			return 0;
+	}
+
+	pr_info("niu%d: Found PHY %08x type %s at phy_port %u\n",
+		parent->index, id,
+		(type == PHY_TYPE_PMA_PMD ?
+		 "PMA/PMD" :
+		 (type == PHY_TYPE_PCS ?
+		  "PCS" : "MII")),
+		phy_port);
+
+	if (p->cur[type] >= NIU_MAX_PORTS) {
+		printk(KERN_ERR PFX "Too many PHY ports.\n");
+		return -EINVAL;
+	}
+	idx = p->cur[type];
+	p->phy_id[type][idx] = id;
+	p->phy_port[type][idx] = phy_port;
+	p->cur[type] = idx + 1;
+	return 0;
+}
+
+static int __devinit port_has_10g(struct phy_probe_info *p, int port)
+{
+	int i;
+
+	for (i = 0; i < p->cur[PHY_TYPE_PMA_PMD]; i++) {
+		if (p->phy_port[PHY_TYPE_PMA_PMD][i] == port)
+			return 1;
+	}
+	for (i = 0; i < p->cur[PHY_TYPE_PCS]; i++) {
+		if (p->phy_port[PHY_TYPE_PCS][i] == port)
+			return 1;
+	}
+
+	return 0;
+}
+
+static int __devinit count_10g_ports(struct phy_probe_info *p, int *lowest)
+{
+	int port, cnt;
+
+	cnt = 0;
+	*lowest = 32;
+	for (port = 8; port < 32; port++) {
+		if (port_has_10g(p, port)) {
+			if (!cnt)
+				*lowest = port;
+			cnt++;
+		}
+	}
+
+	return cnt;
+}
+
+static int __devinit count_1g_ports(struct phy_probe_info *p, int *lowest)
+{
+	*lowest = 32;
+	if (p->cur[PHY_TYPE_MII])
+		*lowest = p->phy_port[PHY_TYPE_MII][0];
+
+	return p->cur[PHY_TYPE_MII];
+}
+
+static void __devinit niu_n2_divide_channels(struct niu_parent *parent)
+{
+	int num_ports = parent->num_ports;
+	int i;
+
+	for (i = 0; i < num_ports; i++) {
+		parent->rxchan_per_port[i] = (16 / num_ports);
+		parent->txchan_per_port[i] = (16 / num_ports);
+
+		pr_info(PFX "niu%d: Port %u [%u RX chans] "
+			"[%u TX chans]\n",
+			parent->index, i,
+			parent->rxchan_per_port[i],
+			parent->txchan_per_port[i]);
+	}
+}
+
+static void __devinit niu_divide_channels(struct niu_parent *parent,
+					  int num_10g, int num_1g)
+{
+	int num_ports = parent->num_ports;
+	int rx_chans_per_10g, rx_chans_per_1g;
+	int tx_chans_per_10g, tx_chans_per_1g;
+	int i, tot_rx, tot_tx;
+
+	if (!num_10g || !num_1g) {
+		rx_chans_per_10g = rx_chans_per_1g =
+			(NIU_NUM_RXCHAN / num_ports);
+		tx_chans_per_10g = tx_chans_per_1g =
+			(NIU_NUM_TXCHAN / num_ports);
+	} else {
+		rx_chans_per_1g = NIU_NUM_RXCHAN / 8;
+		rx_chans_per_10g = (NIU_NUM_RXCHAN -
+				    (rx_chans_per_1g * num_1g)) /
+			num_10g;
+
+		tx_chans_per_1g = NIU_NUM_TXCHAN / 6;
+		tx_chans_per_10g = (NIU_NUM_TXCHAN -
+				    (tx_chans_per_1g * num_1g)) /
+			num_10g;
+	}
+
+	tot_rx = tot_tx = 0;
+	for (i = 0; i < num_ports; i++) {
+		int type = phy_decode(parent->port_phy, i);
+
+		if (type == PORT_TYPE_10G) {
+			parent->rxchan_per_port[i] = rx_chans_per_10g;
+			parent->txchan_per_port[i] = tx_chans_per_10g;
+		} else {
+			parent->rxchan_per_port[i] = rx_chans_per_1g;
+			parent->txchan_per_port[i] = tx_chans_per_1g;
+		}
+		pr_info(PFX "niu%d: Port %u [%u RX chans] "
+			"[%u TX chans]\n",
+			parent->index, i,
+			parent->rxchan_per_port[i],
+			parent->txchan_per_port[i]);
+		tot_rx += parent->rxchan_per_port[i];
+		tot_tx += parent->txchan_per_port[i];
+	}
+
+	if (tot_rx > NIU_NUM_RXCHAN) {
+		printk(KERN_ERR PFX "niu%d: Too many RX channels (%d), "
+		       "resetting to one per port.\n",
+		       parent->index, tot_rx);
+		for (i = 0; i < num_ports; i++)
+			parent->rxchan_per_port[i] = 1;
+	}
+	if (tot_tx > NIU_NUM_TXCHAN) {
+		printk(KERN_ERR PFX "niu%d: Too many TX channels (%d), "
+		       "resetting to one per port.\n",
+		       parent->index, tot_tx);
+		for (i = 0; i < num_ports; i++)
+			parent->txchan_per_port[i] = 1;
+	}
+	if (tot_rx < NIU_NUM_RXCHAN || tot_tx < NIU_NUM_TXCHAN) {
+		printk(KERN_WARNING PFX "niu%d: Driver bug, wasted channels, "
+		       "RX[%d] TX[%d]\n",
+		       parent->index, tot_rx, tot_tx);
+	}
+}
+
+static void __devinit niu_divide_rdc_groups(struct niu_parent *parent,
+					    int num_10g, int num_1g)
+{
+	int i, num_ports = parent->num_ports;
+	int rdc_group, rdc_groups_per_port;
+	int rdc_channel_base;
+
+	rdc_group = 0;
+	rdc_groups_per_port = NIU_NUM_RDC_TABLES / num_ports;
+
+	rdc_channel_base = 0;
+
+	for (i = 0; i < num_ports; i++) {
+		struct niu_rdc_tables *tp = &parent->rdc_group_cfg[i];
+		int grp, num_channels = parent->rxchan_per_port[i];
+		int this_channel_offset;
+
+		tp->first_table_num = rdc_group;
+		tp->num_tables = rdc_groups_per_port;
+		this_channel_offset = 0;
+		for (grp = 0; grp < tp->num_tables; grp++) {
+			struct rdc_table *rt = &tp->tables[grp];
+			int slot;
+
+			pr_info(PFX "niu%d: Port %d RDC tbl(%d) [ ",
+				parent->index, i, tp->first_table_num + grp);
+			for (slot = 0; slot < NIU_RDC_TABLE_SLOTS; slot++) {
+				rt->rxdma_channel[slot] =
+					rdc_channel_base + this_channel_offset;
+
+				printk("%d ", rt->rxdma_channel[slot]);
+
+				if (++this_channel_offset == num_channels)
+					this_channel_offset = 0;
+			}
+			printk("]\n");
+		}
+
+		parent->rdc_default[i] = rdc_channel_base;
+
+		rdc_channel_base += num_channels;
+		rdc_group += rdc_groups_per_port;
+	}
+}
+
+static int __devinit fill_phy_probe_info(struct niu *np,
+					 struct niu_parent *parent,
+					 struct phy_probe_info *info)
+{
+	unsigned long flags;
+	int port, err;
+
+	memset(info, 0, sizeof(*info));
+
+	/* Port 0 to 7 are reserved for onboard Serdes, probe the rest.  */
+	niu_lock_parent(np, flags);
+	err = 0;
+	for (port = 8; port < 32; port++) {
+		int dev_id_1, dev_id_2;
+
+		dev_id_1 = mdio_read(np, port,
+				     NIU_PMA_PMD_DEV_ADDR, MII_PHYSID1);
+		dev_id_2 = mdio_read(np, port,
+				     NIU_PMA_PMD_DEV_ADDR, MII_PHYSID2);
+		err = phy_record(parent, info, dev_id_1, dev_id_2, port,
+				 PHY_TYPE_PMA_PMD);
+		if (err)
+			break;
+		dev_id_1 = mdio_read(np, port,
+				     NIU_PCS_DEV_ADDR, MII_PHYSID1);
+		dev_id_2 = mdio_read(np, port,
+				     NIU_PCS_DEV_ADDR, MII_PHYSID2);
+		err = phy_record(parent, info, dev_id_1, dev_id_2, port,
+				 PHY_TYPE_PCS);
+		if (err)
+			break;
+		dev_id_1 = mii_read(np, port, MII_PHYSID1);
+		dev_id_2 = mii_read(np, port, MII_PHYSID2);
+		err = phy_record(parent, info, dev_id_1, dev_id_2, port,
+				 PHY_TYPE_MII);
+		if (err)
+			break;
+	}
+	niu_unlock_parent(np, flags);
+
+	return err;
+}
+
+static int __devinit walk_phys(struct niu *np, struct niu_parent *parent)
+{
+	struct phy_probe_info *info = &parent->phy_probe_info;
+	int lowest_10g, lowest_1g;
+	int num_10g, num_1g;
+	u32 val;
+	int err;
+
+	err = fill_phy_probe_info(np, parent, info);
+	if (err)
+		return err;
+
+	num_10g = count_10g_ports(info, &lowest_10g);
+	num_1g = count_1g_ports(info, &lowest_1g);
+
+	switch ((num_10g << 4) | num_1g) {
+	case 0x24:
+		if (lowest_1g == 10)
+			parent->plat_type = PLAT_TYPE_VF_P0;
+		else if (lowest_1g == 26)
+			parent->plat_type = PLAT_TYPE_VF_P1;
+		else
+			goto unknown_vg_1g_port;
+
+		/* fallthru */
+	case 0x22:
+		val = (phy_encode(PORT_TYPE_10G, 0) |
+		       phy_encode(PORT_TYPE_10G, 1) |
+		       phy_encode(PORT_TYPE_1G, 2) |
+		       phy_encode(PORT_TYPE_1G, 3));
+		break;
+
+	case 0x20:
+		val = (phy_encode(PORT_TYPE_10G, 0) |
+		       phy_encode(PORT_TYPE_10G, 1));
+		break;
+
+	case 0x10:
+		val = phy_encode(PORT_TYPE_10G, np->port);
+		break;
+
+	case 0x14:
+		if (lowest_1g == 10)
+			parent->plat_type = PLAT_TYPE_VF_P0;
+		else if (lowest_1g == 26)
+			parent->plat_type = PLAT_TYPE_VF_P1;
+		else
+			goto unknown_vg_1g_port;
+
+		/* fallthru */
+	case 0x13:
+		if ((lowest_10g & 0x7) == 0)
+			val = (phy_encode(PORT_TYPE_10G, 0) |
+			       phy_encode(PORT_TYPE_1G, 1) |
+			       phy_encode(PORT_TYPE_1G, 2) |
+			       phy_encode(PORT_TYPE_1G, 3));
+		else
+			val = (phy_encode(PORT_TYPE_1G, 0) |
+			       phy_encode(PORT_TYPE_10G, 1) |
+			       phy_encode(PORT_TYPE_1G, 2) |
+			       phy_encode(PORT_TYPE_1G, 3));
+		break;
+
+	case 0x04:
+		if (lowest_1g == 10)
+			parent->plat_type = PLAT_TYPE_VF_P0;
+		else if (lowest_1g == 26)
+			parent->plat_type = PLAT_TYPE_VF_P1;
+		else
+			goto unknown_vg_1g_port;
+
+		val = (phy_encode(PORT_TYPE_1G, 0) |
+		       phy_encode(PORT_TYPE_1G, 1) |
+		       phy_encode(PORT_TYPE_1G, 2) |
+		       phy_encode(PORT_TYPE_1G, 3));
+		break;
+
+	default:
+		printk(KERN_ERR PFX "Unsupported port config "
+		       "10G[%d] 1G[%d]\n",
+		       num_10g, num_1g);
+		return -EINVAL;
+	}
+
+	parent->port_phy = val;
+
+	if (parent->plat_type == PLAT_TYPE_NIU)
+		niu_n2_divide_channels(parent);
+	else
+		niu_divide_channels(parent, num_10g, num_1g);
+
+	niu_divide_rdc_groups(parent, num_10g, num_1g);
+
+	return 0;
+
+unknown_vg_1g_port:
+	printk(KERN_ERR PFX "Cannot identify platform type, 1gport=%d\n",
+	       lowest_1g);
+	return -EINVAL;
+}
+
+static int __devinit niu_probe_ports(struct niu *np)
+{
+	struct niu_parent *parent = np->parent;
+	int err, i;
+
+	niudbg(PROBE, "niu_probe_ports(): port_phy[%08x]\n",
+	       parent->port_phy);
+
+	if (parent->port_phy == PORT_PHY_UNKNOWN) {
+		err = walk_phys(np, parent);
+		if (err)
+			return err;
+
+		niu_set_ldg_timer_res(np, 2);
+		for (i = 0; i <= LDN_MAX; i++)
+			niu_ldn_irq_enable(np, i, 0);
+	}
+
+	if (parent->port_phy == PORT_PHY_INVALID)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int __devinit niu_classifier_swstate_init(struct niu *np)
+{
+	struct niu_classifier *cp = &np->clas;
+
+	niudbg(PROBE, "niu_classifier_swstate_init: num_tcam(%d)\n",
+	       np->parent->tcam_num_entries);
+
+	cp->tcam_index = (u16) np->port;
+	cp->h1_init = 0xffffffff;
+	cp->h2_init = 0xffff;
+
+	return fflp_early_init(np);
+}
+
+static void __devinit niu_link_config_init(struct niu *np)
+{
+	struct niu_link_config *lp = &np->link_config;
+
+	lp->advertising = (ADVERTISED_10baseT_Half |
+			   ADVERTISED_10baseT_Full |
+			   ADVERTISED_100baseT_Half |
+			   ADVERTISED_100baseT_Full |
+			   ADVERTISED_1000baseT_Half |
+			   ADVERTISED_1000baseT_Full |
+			   ADVERTISED_10000baseT_Full |
+			   ADVERTISED_Autoneg);
+	lp->speed = lp->active_speed = SPEED_INVALID;
+	lp->duplex = lp->active_duplex = DUPLEX_INVALID;
+#if 0
+	lp->loopback_mode = LOOPBACK_MAC;
+	lp->active_speed = SPEED_10000;
+	lp->active_duplex = DUPLEX_FULL;
+#else
+	lp->loopback_mode = LOOPBACK_DISABLED;
+#endif
+}
+
+static int __devinit niu_init_mac_ipp_pcs_base(struct niu *np)
+{
+	switch (np->port) {
+	case 0:
+		np->mac_regs = np->regs + XMAC_PORT0_OFF;
+		np->ipp_off  = 0x00000;
+		np->pcs_off  = 0x04000;
+		np->xpcs_off = 0x02000;
+		break;
+
+	case 1:
+		np->mac_regs = np->regs + XMAC_PORT1_OFF;
+		np->ipp_off  = 0x08000;
+		np->pcs_off  = 0x0a000;
+		np->xpcs_off = 0x08000;
+		break;
+
+	case 2:
+		np->mac_regs = np->regs + BMAC_PORT2_OFF;
+		np->ipp_off  = 0x04000;
+		np->pcs_off  = 0x0e000;
+		np->xpcs_off = ~0UL;
+		break;
+
+	case 3:
+		np->mac_regs = np->regs + BMAC_PORT3_OFF;
+		np->ipp_off  = 0x0c000;
+		np->pcs_off  = 0x12000;
+		np->xpcs_off = ~0UL;
+		break;
+
+	default:
+		dev_err(np->device, PFX "Port %u is invalid, cannot "
+			"compute MAC block offset.\n", np->port);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void __devinit niu_try_msix(struct niu *np, u8 *ldg_num_map)
+{
+	struct msix_entry msi_vec[NIU_NUM_LDG];
+	struct niu_parent *parent = np->parent;
+	struct pci_dev *pdev = np->pdev;
+	int i, num_irqs, err;
+	u8 first_ldg;
+
+	first_ldg = (NIU_NUM_LDG / parent->num_ports) * np->port;
+	for (i = 0; i < (NIU_NUM_LDG / parent->num_ports); i++)
+		ldg_num_map[i] = first_ldg + i;
+
+	num_irqs = (parent->rxchan_per_port[np->port] +
+		    parent->txchan_per_port[np->port] +
+		    (np->port == 0 ? 3 : 1));
+	BUG_ON(num_irqs > (NIU_NUM_LDG / parent->num_ports));
+
+retry:
+	for (i = 0; i < num_irqs; i++) {
+		msi_vec[i].vector = 0;
+		msi_vec[i].entry = i;
+	}
+
+	err = pci_enable_msix(pdev, msi_vec, num_irqs);
+	if (err < 0) {
+		np->flags &= ~NIU_FLAGS_MSIX;
+		return;
+	}
+	if (err > 0) {
+		num_irqs = err;
+		goto retry;
+	}
+
+	np->flags |= NIU_FLAGS_MSIX;
+	for (i = 0; i < num_irqs; i++)
+		np->ldg[i].irq = msi_vec[i].vector;
+	np->num_ldg = num_irqs;
+}
+
+static int __devinit niu_n2_irq_init(struct niu *np, u8 *ldg_num_map)
+{
+#ifdef CONFIG_SPARC64
+	struct of_device *op = np->op;
+	const u32 *int_prop;
+	int i;
+
+	int_prop = of_get_property(op->node, "interrupts", NULL);
+	if (!int_prop)
+		return -ENODEV;
+
+	for (i = 0; i < op->num_irqs; i++) {
+		ldg_num_map[i] = int_prop[i];
+		np->ldg[i].irq = op->irqs[i];
+	}
+
+	np->num_ldg = op->num_irqs;
+
+	return 0;
+#else
+	return -EINVAL;
+#endif
+}
+
+static int __devinit niu_ldg_init(struct niu *np)
+{
+	struct niu_parent *parent = np->parent;
+	u8 ldg_num_map[NIU_NUM_LDG];
+	int first_chan, num_chan;
+	int i, err, ldg_rotor;
+	u8 port;
+
+	np->num_ldg = 1;
+	np->ldg[0].irq = np->dev->irq;
+	if (parent->plat_type == PLAT_TYPE_NIU) {
+		err = niu_n2_irq_init(np, ldg_num_map);
+		if (err)
+			return err;
+	} else
+		niu_try_msix(np, ldg_num_map);
+
+	port = np->port;
+	for (i = 0; i < np->num_ldg; i++) {
+		struct niu_ldg *lp = &np->ldg[i];
+
+		netif_napi_add(np->dev, &lp->napi, niu_poll, 64);
+
+		lp->np = np;
+		lp->ldg_num = ldg_num_map[i];
+		lp->timer = 2; /* XXX */
+
+		/* On N2 NIU the firmware has setup the SID mappings so they go
+		 * to the correct values that will route the LDG to the proper
+		 * interrupt in the NCU interrupt table.
+		 */
+		if (np->parent->plat_type != PLAT_TYPE_NIU) {
+			err = niu_set_ldg_sid(np, lp->ldg_num, port, i);
+			if (err)
+				return err;
+		}
+	}
+
+	/* We adopt the LDG assignment ordering used by the N2 NIU
+	 * 'interrupt' properties because that simplifies a lot of
+	 * things.  This ordering is:
+	 *
+	 *	MAC
+	 *	MIF	(if port zero)
+	 *	SYSERR	(if port zero)
+	 *	RX channels
+	 *	TX channels
+	 */
+
+	ldg_rotor = 0;
+
+	err = niu_ldg_assign_ldn(np, parent, ldg_num_map[ldg_rotor],
+				  LDN_MAC(port));
+	if (err)
+		return err;
+
+	ldg_rotor++;
+	if (ldg_rotor == np->num_ldg)
+		ldg_rotor = 0;
+
+	if (port == 0) {
+		err = niu_ldg_assign_ldn(np, parent,
+					 ldg_num_map[ldg_rotor],
+					 LDN_MIF);
+		if (err)
+			return err;
+
+		ldg_rotor++;
+		if (ldg_rotor == np->num_ldg)
+			ldg_rotor = 0;
+
+		err = niu_ldg_assign_ldn(np, parent,
+					 ldg_num_map[ldg_rotor],
+					 LDN_DEVICE_ERROR);
+		if (err)
+			return err;
+
+		ldg_rotor++;
+		if (ldg_rotor == np->num_ldg)
+			ldg_rotor = 0;
+
+	}
+
+	first_chan = 0;
+	for (i = 0; i < port; i++)
+		first_chan += parent->rxchan_per_port[port];
+	num_chan = parent->rxchan_per_port[port];
+
+	for (i = first_chan; i < (first_chan + num_chan); i++) {
+		err = niu_ldg_assign_ldn(np, parent,
+					 ldg_num_map[ldg_rotor],
+					 LDN_RXDMA(i));
+		if (err)
+			return err;
+		ldg_rotor++;
+		if (ldg_rotor == np->num_ldg)
+			ldg_rotor = 0;
+	}
+
+	first_chan = 0;
+	for (i = 0; i < port; i++)
+		first_chan += parent->txchan_per_port[port];
+	num_chan = parent->txchan_per_port[port];
+	for (i = first_chan; i < (first_chan + num_chan); i++) {
+		err = niu_ldg_assign_ldn(np, parent,
+					 ldg_num_map[ldg_rotor],
+					 LDN_TXDMA(i));
+		if (err)
+			return err;
+		ldg_rotor++;
+		if (ldg_rotor == np->num_ldg)
+			ldg_rotor = 0;
+	}
+
+	return 0;
+}
+
+static void __devexit niu_ldg_free(struct niu *np)
+{
+	if (np->flags & NIU_FLAGS_MSIX)
+		pci_disable_msix(np->pdev);
+}
+
+static int __devinit niu_get_of_props(struct niu *np)
+{
+#ifdef CONFIG_SPARC64
+	struct net_device *dev = np->dev;
+	struct device_node *dp;
+	const char *phy_type;
+	const u8 *mac_addr;
+	int prop_len;
+
+	if (np->parent->plat_type == PLAT_TYPE_NIU)
+		dp = np->op->node;
+	else
+		dp = pci_device_to_OF_node(np->pdev);
+
+	phy_type = of_get_property(dp, "phy-type", &prop_len);
+	if (!phy_type) {
+		dev_err(np->device, PFX "%s: OF node lacks "
+			"phy-type property\n",
+			dp->full_name);
+		return -EINVAL;
+	}
+
+	if (!strcmp(phy_type, "none"))
+		return -ENODEV;
+
+	strcpy(np->vpd.phy_type, phy_type);
+
+	if (niu_phy_type_prop_decode(np, np->vpd.phy_type)) {
+		dev_err(np->device, PFX "%s: Illegal phy string [%s].\n",
+			dp->full_name, np->vpd.phy_type);
+		return -EINVAL;
+	}
+
+	mac_addr = of_get_property(dp, "local-mac-address", &prop_len);
+	if (!mac_addr) {
+		dev_err(np->device, PFX "%s: OF node lacks "
+			"local-mac-address property\n",
+			dp->full_name);
+		return -EINVAL;
+	}
+	if (prop_len != dev->addr_len) {
+		dev_err(np->device, PFX "%s: OF MAC address prop len (%d) "
+			"is wrong.\n",
+			dp->full_name, prop_len);
+	}
+	memcpy(dev->perm_addr, mac_addr, dev->addr_len);
+	if (!is_valid_ether_addr(&dev->perm_addr[0])) {
+		int i;
+
+		dev_err(np->device, PFX "%s: OF MAC address is invalid\n",
+			dp->full_name);
+		dev_err(np->device, PFX "%s: [ \n",
+			dp->full_name);
+		for (i = 0; i < 6; i++)
+			printk("%02x ", dev->perm_addr[i]);
+		printk("]\n");
+		return -EINVAL;
+	}
+
+	memcpy(dev->dev_addr, dev->perm_addr, dev->addr_len);
+
+	return 0;
+#else
+	return -EINVAL;
+#endif
+}
+
+static int __devinit niu_get_invariants(struct niu *np)
+{
+	int err, have_props;
+	u32 offset;
+
+	err = niu_get_of_props(np);
+	if (err == -ENODEV)
+		return err;
+
+	have_props = !err;
+
+	err = niu_get_and_validate_port(np);
+	if (err)
+		return err;
+
+	err = niu_init_mac_ipp_pcs_base(np);
+	if (err)
+		return err;
+
+	if (!have_props) {
+		if (np->parent->plat_type == PLAT_TYPE_NIU)
+			return -EINVAL;
+
+		nw64(ESPC_PIO_EN, ESPC_PIO_EN_ENABLE);
+		offset = niu_pci_vpd_offset(np);
+		niudbg(PROBE, "niu_get_invariants: VPD offset [%08x]\n",
+		       offset);
+		if (offset)
+			niu_pci_vpd_fetch(np, offset);
+		nw64(ESPC_PIO_EN, 0);
+
+		if (np->flags & NIU_FLAGS_VPD_VALID)
+			niu_pci_vpd_validate(np);
+
+		if (!(np->flags & NIU_FLAGS_VPD_VALID)) {
+			err = niu_pci_probe_sprom(np);
+			if (err)
+				return err;
+		}
+	}
+
+	err = niu_probe_ports(np);
+	if (err)
+		return err;
+
+	niu_ldg_init(np);
+
+	niu_classifier_swstate_init(np);
+	niu_link_config_init(np);
+
+	err = niu_determine_phy_disposition(np);
+	if (!err)
+		err = niu_init_link(np);
+
+	return err;
+}
+
+static LIST_HEAD(niu_parent_list);
+static DEFINE_MUTEX(niu_parent_lock);
+static int niu_parent_index;
+
+static ssize_t show_port_phy(struct device *dev,
+			     struct device_attribute *attr, char *buf)
+{
+	struct platform_device *plat_dev = to_platform_device(dev);
+	struct niu_parent *p = plat_dev->dev.platform_data;
+	u32 port_phy = p->port_phy;
+	char *orig_buf = buf;
+	int i;
+
+	if (port_phy == PORT_PHY_UNKNOWN ||
+	    port_phy == PORT_PHY_INVALID)
+		return 0;
+
+	for (i = 0; i < p->num_ports; i++) {
+		const char *type_str;
+		int type;
+
+		type = phy_decode(port_phy, i);
+		if (type == PORT_TYPE_10G)
+			type_str = "10G";
+		else
+			type_str = "1G";
+		buf += sprintf(buf,
+			       (i == 0) ? "%s" : " %s",
+			       type_str);
+	}
+	buf += sprintf(buf, "\n");
+	return buf - orig_buf;
+}
+
+static ssize_t show_plat_type(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct platform_device *plat_dev = to_platform_device(dev);
+	struct niu_parent *p = plat_dev->dev.platform_data;
+	const char *type_str;
+
+	switch (p->plat_type) {
+	case PLAT_TYPE_ATLAS:
+		type_str = "atlas";
+		break;
+	case PLAT_TYPE_NIU:
+		type_str = "niu";
+		break;
+	case PLAT_TYPE_VF_P0:
+		type_str = "vf_p0";
+		break;
+	case PLAT_TYPE_VF_P1:
+		type_str = "vf_p1";
+		break;
+	default:
+		type_str = "unknown";
+		break;
+	}
+
+	return sprintf(buf, "%s\n", type_str);
+}
+
+static ssize_t __show_chan_per_port(struct device *dev,
+				    struct device_attribute *attr, char *buf,
+				    int rx)
+{
+	struct platform_device *plat_dev = to_platform_device(dev);
+	struct niu_parent *p = plat_dev->dev.platform_data;
+	char *orig_buf = buf;
+	u8 *arr;
+	int i;
+
+	arr = (rx ? p->rxchan_per_port : p->txchan_per_port);
+
+	for (i = 0; i < p->num_ports; i++) {
+		buf += sprintf(buf,
+			       (i == 0) ? "%d" : " %d",
+			       arr[i]);
+	}
+	buf += sprintf(buf, "\n");
+
+	return buf - orig_buf;
+}
+
+static ssize_t show_rxchan_per_port(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	return __show_chan_per_port(dev, attr, buf, 1);
+}
+
+static ssize_t show_txchan_per_port(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	return __show_chan_per_port(dev, attr, buf, 1);
+}
+
+static ssize_t show_num_ports(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct platform_device *plat_dev = to_platform_device(dev);
+	struct niu_parent *p = plat_dev->dev.platform_data;
+
+	return sprintf(buf, "%d\n", p->num_ports);
+}
+
+static struct device_attribute niu_parent_attributes[] = {
+	__ATTR(port_phy, S_IRUGO, show_port_phy, NULL),
+	__ATTR(plat_type, S_IRUGO, show_plat_type, NULL),
+	__ATTR(rxchan_per_port, S_IRUGO, show_rxchan_per_port, NULL),
+	__ATTR(txchan_per_port, S_IRUGO, show_txchan_per_port, NULL),
+	__ATTR(num_ports, S_IRUGO, show_num_ports, NULL),
+	{}
+};
+
+static struct niu_parent * __devinit niu_new_parent(struct niu *np,
+						    union niu_parent_id *id,
+						    u8 ptype)
+{
+	struct platform_device *plat_dev;
+	struct niu_parent *p;
+	int i;
+
+	niudbg(PROBE, "niu_new_parent: Creating new parent.\n");
+
+	plat_dev = platform_device_register_simple("niu", niu_parent_index,
+						   NULL, 0);
+	if (!plat_dev)
+		return NULL;
+
+	for (i = 0; attr_name(niu_parent_attributes[i]); i++) {
+		int err = device_create_file(&plat_dev->dev,
+					     &niu_parent_attributes[i]);
+		if (err)
+			goto fail_unregister;
+	}
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
+		goto fail_unregister;
+
+	p->index = niu_parent_index++;
+
+	plat_dev->dev.platform_data = p;
+	p->plat_dev = plat_dev;
+
+	memcpy(&p->id, id, sizeof(*id));
+	p->plat_type = ptype;
+	INIT_LIST_HEAD(&p->list);
+	atomic_set(&p->refcnt, 0);
+	list_add(&p->list, &niu_parent_list);
+	spin_lock_init(&p->lock);
+
+	p->rxdma_clock_divider = 7500;
+
+	p->tcam_num_entries = NIU_PCI_TCAM_ENTRIES;
+	if (p->plat_type == PLAT_TYPE_NIU)
+		p->tcam_num_entries = NIU_NONPCI_TCAM_ENTRIES;
+
+	for (i = CLASS_CODE_USER_PROG1; i <= CLASS_CODE_SCTP_IPV6; i++) {
+		int index = i - CLASS_CODE_USER_PROG1;
+
+		p->tcam_key[index] = TCAM_KEY_TSEL;
+		p->flow_key[index] = (FLOW_KEY_IPSA |
+				      FLOW_KEY_IPDA |
+				      FLOW_KEY_PROTO |
+				      (FLOW_KEY_L4_BYTE12 <<
+				       FLOW_KEY_L4_0_SHIFT) |
+				      (FLOW_KEY_L4_BYTE12 <<
+				       FLOW_KEY_L4_1_SHIFT));
+	}
+
+	for (i = 0; i < LDN_MAX + 1; i++)
+		p->ldg_map[i] = LDG_INVALID;
+
+	return p;
+
+fail_unregister:
+	platform_device_unregister(plat_dev);
+	return NULL;
+}
+
+static struct niu_parent * __devinit niu_get_parent(struct niu *np,
+						    union niu_parent_id *id,
+						    u8 ptype)
+{
+	struct niu_parent *p, *tmp;
+	int port = np->port;
+
+	niudbg(PROBE, "niu_get_parent: platform_type[%u] port[%u]\n",
+	       ptype, port);
+
+	mutex_lock(&niu_parent_lock);
+	p = NULL;
+	list_for_each_entry(tmp, &niu_parent_list, list) {
+		if (!memcmp(id, &tmp->id, sizeof(*id))) {
+			p = tmp;
+			break;
+		}
+	}
+	if (!p)
+		p = niu_new_parent(np, id, ptype);
+
+	if (p) {
+		char port_name[6];
+		int err;
+
+		sprintf(port_name, "port%d", port);
+		err = sysfs_create_link(&p->plat_dev->dev.kobj,
+					&np->device->kobj,
+					port_name);
+		if (!err) {
+			p->ports[port] = np;
+			atomic_inc(&p->refcnt);
+		}
+	}
+	mutex_unlock(&niu_parent_lock);
+
+	return p;
+}
+
+static void niu_put_parent(struct niu *np)
+{
+	struct niu_parent *p = np->parent;
+	u8 port = np->port;
+	char port_name[6];
+
+	BUG_ON(!p || p->ports[port] != np);
+
+	niudbg(PROBE, "niu_put_parent: port[%u]\n", port);
+
+	sprintf(port_name, "port%d", port);
+
+	mutex_lock(&niu_parent_lock);
+
+	sysfs_remove_link(&p->plat_dev->dev.kobj, port_name);
+
+	p->ports[port] = NULL;
+	np->parent = NULL;
+
+	if (atomic_dec_and_test(&p->refcnt)) {
+		list_del(&p->list);
+		platform_device_unregister(p->plat_dev);
+	}
+
+	mutex_unlock(&niu_parent_lock);
+}
+
+static void *niu_pci_alloc_coherent(struct device *dev, size_t size,
+				    u64 *handle, gfp_t flag)
+{
+	dma_addr_t dh;
+	void *ret;
+
+	ret = dma_alloc_coherent(dev, size, &dh, flag);
+	if (ret)
+		*handle = dh;
+	return ret;
+}
+
+static void niu_pci_free_coherent(struct device *dev, size_t size,
+				  void *cpu_addr, u64 handle)
+{
+	dma_free_coherent(dev, size, cpu_addr, handle);
+}
+
+static u64 niu_pci_map_page(struct device *dev, struct page *page,
+			    unsigned long offset, size_t size,
+			    enum dma_data_direction direction)
+{
+	return dma_map_page(dev, page, offset, size, direction);
+}
+
+static void niu_pci_unmap_page(struct device *dev, u64 dma_address,
+			       size_t size, enum dma_data_direction direction)
+{
+	return dma_unmap_page(dev, dma_address, size, direction);
+}
+
+static u64 niu_pci_map_single(struct device *dev, void *cpu_addr,
+			      size_t size,
+			      enum dma_data_direction direction)
+{
+	return dma_map_single(dev, cpu_addr, size, direction);
+}
+
+static void niu_pci_unmap_single(struct device *dev, u64 dma_address,
+				 size_t size,
+				 enum dma_data_direction direction)
+{
+	dma_unmap_single(dev, dma_address, size, direction);
+}
+
+static const struct niu_ops niu_pci_ops = {
+	.alloc_coherent	= niu_pci_alloc_coherent,
+	.free_coherent	= niu_pci_free_coherent,
+	.map_page	= niu_pci_map_page,
+	.unmap_page	= niu_pci_unmap_page,
+	.map_single	= niu_pci_map_single,
+	.unmap_single	= niu_pci_unmap_single,
+};
+
+static void __devinit niu_driver_version(void)
+{
+	static int niu_version_printed;
+
+	if (niu_version_printed++ == 0)
+		pr_info("%s", version);
+}
+
+static struct net_device * __devinit niu_alloc_and_init(
+	struct device *gen_dev, struct pci_dev *pdev,
+	struct of_device *op, const struct niu_ops *ops,
+	u8 port)
+{
+	struct net_device *dev = alloc_etherdev(sizeof(struct niu));
+	struct niu *np;
+
+	if (!dev) {
+		dev_err(gen_dev, PFX "Etherdev alloc failed, aborting.\n");
+		return NULL;
+	}
+
+	SET_NETDEV_DEV(dev, gen_dev);
+
+	np = netdev_priv(dev);
+	np->dev = dev;
+	np->pdev = pdev;
+	np->op = op;
+	np->device = gen_dev;
+	np->ops = ops;
+
+	np->msg_enable = niu_debug;
+
+	spin_lock_init(&np->lock);
+	INIT_WORK(&np->reset_task, niu_reset_task);
+
+	np->port = port;
+
+	return dev;
+}
+
+static void __devinit niu_assign_netdev_ops(struct net_device *dev)
+{
+	dev->open = niu_open;
+	dev->stop = niu_close;
+	dev->get_stats = niu_get_stats;
+	dev->set_multicast_list = niu_set_rx_mode;
+	dev->set_mac_address = niu_set_mac_addr;
+	dev->do_ioctl = niu_ioctl;
+	dev->tx_timeout = niu_tx_timeout;
+	dev->hard_start_xmit = niu_start_xmit;
+	dev->ethtool_ops = &niu_ethtool_ops;
+	dev->watchdog_timeo = NIU_TX_TIMEOUT;
+	dev->change_mtu = niu_change_mtu;
+}
+
+static void __devinit niu_device_announce(struct niu *np)
+{
+	struct net_device *dev = np->dev;
+	int i;
+
+	pr_info("%s: NIU Ethernet ", dev->name);
+	for (i = 0; i < 6; i++)
+		printk("%2.2x%c", dev->dev_addr[i],
+		       i == 5 ? '\n' : ':');
+
+	pr_info("%s: Port type[%s] mode[%s:%s] XCVR[%s] phy[%s]\n",
+		dev->name,
+		(np->flags & NIU_FLAGS_XMAC ? "XMAC" : "BMAC"),
+		(np->flags & NIU_FLAGS_10G ? "10G" : "1G"),
+		(np->flags & NIU_FLAGS_FIBER ? "FIBER" : "COPPER"),
+		(np->mac_xcvr == MAC_XCVR_MII ? "MII" :
+		 (np->mac_xcvr == MAC_XCVR_PCS ? "PCS" : "XPCS")),
+		np->vpd.phy_type);
+}
+
+static int __devinit niu_pci_init_one(struct pci_dev *pdev,
+				      const struct pci_device_id *ent)
+{
+	unsigned long niureg_base, niureg_len;
+	union niu_parent_id parent_id;
+	struct net_device *dev;
+	struct niu *np;
+	int err, pos;
+	u64 dma_mask;
+	u16 val16;
+
+	niu_driver_version();
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		dev_err(&pdev->dev, PFX "Cannot enable PCI device, "
+			"aborting.\n");
+		return err;
+	}
+
+	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
+	    !(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
+		dev_err(&pdev->dev, PFX "Cannot find proper PCI device "
+			"base addresses, aborting.\n");
+		err = -ENODEV;
+		goto err_out_disable_pdev;
+	}
+
+	err = pci_request_regions(pdev, DRV_MODULE_NAME);
+	if (err) {
+		dev_err(&pdev->dev, PFX "Cannot obtain PCI resources, "
+			"aborting.\n");
+		goto err_out_disable_pdev;
+	}
+
+	pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+	if (pos <= 0) {
+		dev_err(&pdev->dev, PFX "Cannot find PCI Express capability, "
+			"aborting.\n");
+		goto err_out_free_res;
+	}
+
+	dev = niu_alloc_and_init(&pdev->dev, pdev, NULL,
+				 &niu_pci_ops, PCI_FUNC(pdev->devfn));
+	if (!dev) {
+		err = -ENOMEM;
+		goto err_out_free_res;
+	}
+	np = netdev_priv(dev);
+
+	memset(&parent_id, 0, sizeof(parent_id));
+	parent_id.pci.domain = pci_domain_nr(pdev->bus);
+	parent_id.pci.bus = pdev->bus->number;
+	parent_id.pci.device = PCI_SLOT(pdev->devfn);
+
+	np->parent = niu_get_parent(np, &parent_id,
+				    PLAT_TYPE_ATLAS);
+	if (!np->parent) {
+		err = -ENOMEM;
+		goto err_out_free_dev;
+	}
+
+	pci_read_config_word(pdev, pos + PCI_EXP_DEVCTL, &val16);
+	val16 &= ~PCI_EXP_DEVCTL_NOSNOOP_EN;
+	val16 |= (PCI_EXP_DEVCTL_CERE |
+		  PCI_EXP_DEVCTL_NFERE |
+		  PCI_EXP_DEVCTL_FERE |
+		  PCI_EXP_DEVCTL_URRE |
+		  PCI_EXP_DEVCTL_RELAX_EN);
+	pci_write_config_word(pdev, pos + PCI_EXP_DEVCTL, val16);
+
+	dma_mask = DMA_44BIT_MASK;
+	err = pci_set_dma_mask(pdev, dma_mask);
+	if (!err) {
+		dev->features |= NETIF_F_HIGHDMA;
+		err = pci_set_consistent_dma_mask(pdev, dma_mask);
+		if (err) {
+			dev_err(&pdev->dev, PFX "Unable to obtain 44 bit "
+				"DMA for consistent allocations, "
+				"aborting.\n");
+			goto err_out_release_parent;
+		}
+	}
+	if (err || dma_mask == DMA_32BIT_MASK) {
+		err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+		if (err) {
+			dev_err(&pdev->dev, PFX "No usable DMA configuration, "
+				"aborting.\n");
+			goto err_out_release_parent;
+		}
+	}
+
+	dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM);
+
+	niureg_base = pci_resource_start(pdev, 0);
+	niureg_len = pci_resource_len(pdev, 0);
+
+	np->regs = ioremap_nocache(niureg_base, niureg_len);
+	if (!np->regs) {
+		dev_err(&pdev->dev, PFX "Cannot map device registers, "
+			"aborting.\n");
+		err = -ENOMEM;
+		goto err_out_release_parent;
+	}
+
+	pci_set_master(pdev);
+	pci_save_state(pdev);
+
+	dev->irq = pdev->irq;
+
+	niu_assign_netdev_ops(dev);
+
+	err = niu_get_invariants(np);
+	if (err) {
+		if (err != -ENODEV)
+			dev_err(&pdev->dev, PFX "Problem fetching invariants "
+				"of chip, aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	err = register_netdev(dev);
+	if (err) {
+		dev_err(&pdev->dev, PFX "Cannot register net device, "
+			"aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	pci_set_drvdata(pdev, dev);
+
+	niu_device_announce(np);
+
+	return 0;
+
+err_out_iounmap:
+	if (np->regs) {
+		iounmap(np->regs);
+		np->regs = NULL;
+	}
+
+err_out_release_parent:
+	niu_put_parent(np);
+
+err_out_free_dev:
+	free_netdev(dev);
+
+err_out_free_res:
+	pci_release_regions(pdev);
+
+err_out_disable_pdev:
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+
+	return err;
+}
+
+static void __devexit niu_pci_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+
+	if (dev) {
+		struct niu *np = netdev_priv(dev);
+
+		unregister_netdev(dev);
+		if (np->regs) {
+			iounmap(np->regs);
+			np->regs = NULL;
+		}
+
+		niu_ldg_free(np);
+
+		niu_put_parent(np);
+
+		free_netdev(dev);
+		pci_release_regions(pdev);
+		pci_disable_device(pdev);
+		pci_set_drvdata(pdev, NULL);
+	}
+}
+
+static int niu_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct niu *np = netdev_priv(dev);
+	unsigned long flags;
+
+	if (!netif_running(dev))
+		return 0;
+
+	flush_scheduled_work();
+	niu_netif_stop(np);
+
+	del_timer_sync(&np->timer);
+
+	spin_lock_irqsave(&np->lock, flags);
+	niu_enable_interrupts(np, 0);
+	spin_unlock_irqrestore(&np->lock, flags);
+
+	netif_device_detach(dev);
+
+	spin_lock_irqsave(&np->lock, flags);
+	niu_stop_hw(np);
+	spin_unlock_irqrestore(&np->lock, flags);
+
+	pci_save_state(pdev);
+
+	return 0;
+}
+
+static int niu_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	struct niu *np = netdev_priv(dev);
+	unsigned long flags;
+	int err;
+
+	if (!netif_running(dev))
+		return 0;
+
+	pci_restore_state(pdev);
+
+	netif_device_attach(dev);
+
+	spin_lock_irqsave(&np->lock, flags);
+
+	err = niu_init_hw(np);
+	if (!err) {
+		np->timer.expires = jiffies + HZ;
+		add_timer(&np->timer);
+		niu_netif_start(np);
+	}
+
+	spin_unlock_irqrestore(&np->lock, flags);
+
+	return err;
+}
+
+static struct pci_driver niu_pci_driver = {
+	.name		= DRV_MODULE_NAME,
+	.id_table	= niu_pci_tbl,
+	.probe		= niu_pci_init_one,
+	.remove		= __devexit_p(niu_pci_remove_one),
+	.suspend	= niu_suspend,
+	.resume		= niu_resume,
+};
+
+#ifdef CONFIG_SPARC64
+static void *niu_phys_alloc_coherent(struct device *dev, size_t size,
+				     u64 *dma_addr, gfp_t flag)
+{
+	unsigned long order = get_order(size);
+	unsigned long page = __get_free_pages(flag, order);
+
+	if (page == 0UL)
+		return NULL;
+	memset((char *)page, 0, PAGE_SIZE << order);
+	*dma_addr = __pa(page);
+
+	return (void *) page;
+}
+
+static void niu_phys_free_coherent(struct device *dev, size_t size,
+				   void *cpu_addr, u64 handle)
+{
+	unsigned long order = get_order(size);
+
+	free_pages((unsigned long) cpu_addr, order);
+}
+
+static u64 niu_phys_map_page(struct device *dev, struct page *page,
+			     unsigned long offset, size_t size,
+			     enum dma_data_direction direction)
+{
+	return page_to_phys(page) + offset;
+}
+
+static void niu_phys_unmap_page(struct device *dev, u64 dma_address,
+				size_t size, enum dma_data_direction direction)
+{
+	/* Nothing to do.  */
+}
+
+static u64 niu_phys_map_single(struct device *dev, void *cpu_addr,
+			       size_t size,
+			       enum dma_data_direction direction)
+{
+	return __pa(cpu_addr);
+}
+
+static void niu_phys_unmap_single(struct device *dev, u64 dma_address,
+				  size_t size,
+				  enum dma_data_direction direction)
+{
+	/* Nothing to do.  */
+}
+
+static const struct niu_ops niu_phys_ops = {
+	.alloc_coherent	= niu_phys_alloc_coherent,
+	.free_coherent	= niu_phys_free_coherent,
+	.map_page	= niu_phys_map_page,
+	.unmap_page	= niu_phys_unmap_page,
+	.map_single	= niu_phys_map_single,
+	.unmap_single	= niu_phys_unmap_single,
+};
+
+static unsigned long res_size(struct resource *r)
+{
+	return r->end - r->start + 1UL;
+}
+
+static int __devinit niu_of_probe(struct of_device *op,
+				  const struct of_device_id *match)
+{
+	union niu_parent_id parent_id;
+	struct net_device *dev;
+	struct niu *np;
+	const u32 *reg;
+	int err;
+
+	niu_driver_version();
+
+	reg = of_get_property(op->node, "reg", NULL);
+	if (!reg) {
+		dev_err(&op->dev, PFX "%s: No 'reg' property, aborting.\n",
+			op->node->full_name);
+		return -ENODEV;
+	}
+
+	dev = niu_alloc_and_init(&op->dev, NULL, op,
+				 &niu_phys_ops, reg[0] & 0x1);
+	if (!dev) {
+		err = -ENOMEM;
+		goto err_out;
+	}
+	np = netdev_priv(dev);
+
+	memset(&parent_id, 0, sizeof(parent_id));
+	parent_id.of = of_get_parent(op->node);
+
+	np->parent = niu_get_parent(np, &parent_id,
+				    PLAT_TYPE_NIU);
+	if (!np->parent) {
+		err = -ENOMEM;
+		goto err_out_free_dev;
+	}
+
+	dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM);
+
+	np->regs = of_ioremap(&op->resource[1], 0,
+			      res_size(&op->resource[1]),
+			      "niu regs");
+	if (!np->regs) {
+		dev_err(&op->dev, PFX "Cannot map device registers, "
+			"aborting.\n");
+		err = -ENOMEM;
+		goto err_out_release_parent;
+	}
+
+	np->vir_regs_1 = of_ioremap(&op->resource[2], 0,
+				    res_size(&op->resource[2]),
+				    "niu vregs-1");
+	if (!np->vir_regs_1) {
+		dev_err(&op->dev, PFX "Cannot map device vir registers 1, "
+			"aborting.\n");
+		err = -ENOMEM;
+		goto err_out_iounmap;
+	}
+
+	np->vir_regs_2 = of_ioremap(&op->resource[3], 0,
+				    res_size(&op->resource[3]),
+				    "niu vregs-2");
+	if (!np->vir_regs_2) {
+		dev_err(&op->dev, PFX "Cannot map device vir registers 2, "
+			"aborting.\n");
+		err = -ENOMEM;
+		goto err_out_iounmap;
+	}
+
+	niu_assign_netdev_ops(dev);
+
+	err = niu_get_invariants(np);
+	if (err) {
+		if (err != -ENODEV)
+			dev_err(&op->dev, PFX "Problem fetching invariants "
+				"of chip, aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	err = register_netdev(dev);
+	if (err) {
+		dev_err(&op->dev, PFX "Cannot register net device, "
+			"aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	dev_set_drvdata(&op->dev, dev);
+
+	niu_device_announce(np);
+
+	return 0;
+
+err_out_iounmap:
+	if (np->vir_regs_1) {
+		of_iounmap(&op->resource[2], np->vir_regs_1,
+			   res_size(&op->resource[2]));
+		np->vir_regs_1 = NULL;
+	}
+
+	if (np->vir_regs_2) {
+		of_iounmap(&op->resource[3], np->vir_regs_2,
+			   res_size(&op->resource[3]));
+		np->vir_regs_2 = NULL;
+	}
+
+	if (np->regs) {
+		of_iounmap(&op->resource[1], np->regs,
+			   res_size(&op->resource[1]));
+		np->regs = NULL;
+	}
+
+err_out_release_parent:
+	niu_put_parent(np);
+
+err_out_free_dev:
+	free_netdev(dev);
+
+err_out:
+	return err;
+}
+
+static int __devexit niu_of_remove(struct of_device *op)
+{
+	struct net_device *dev = dev_get_drvdata(&op->dev);
+
+	if (dev) {
+		struct niu *np = netdev_priv(dev);
+
+		unregister_netdev(dev);
+
+		if (np->vir_regs_1) {
+			of_iounmap(&op->resource[2], np->vir_regs_1,
+				   res_size(&op->resource[2]));
+			np->vir_regs_1 = NULL;
+		}
+
+		if (np->vir_regs_2) {
+			of_iounmap(&op->resource[3], np->vir_regs_2,
+				   res_size(&op->resource[3]));
+			np->vir_regs_2 = NULL;
+		}
+
+		if (np->regs) {
+			of_iounmap(&op->resource[1], np->regs,
+				   res_size(&op->resource[1]));
+			np->regs = NULL;
+		}
+
+		niu_ldg_free(np);
+
+		niu_put_parent(np);
+
+		free_netdev(dev);
+		dev_set_drvdata(&op->dev, NULL);
+	}
+	return 0;
+}
+
+static struct of_device_id niu_match[] = {
+	{
+		.name = "network",
+		.compatible = "SUNW,niusl",
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(of, niu_match);
+
+static struct of_platform_driver niu_of_driver = {
+	.name		= "niu",
+	.match_table	= niu_match,
+	.probe		= niu_of_probe,
+	.remove		= __devexit_p(niu_of_remove),
+};
+
+#endif /* CONFIG_SPARC64 */
+
+static int __init niu_init(void)
+{
+	int err = 0;
+
+	BUILD_BUG_ON((PAGE_SIZE < 4 * 1024) ||
+		     ((PAGE_SIZE > 32 * 1024) &&
+		      ((PAGE_SIZE % (32 * 1024)) != 0 &&
+		       (PAGE_SIZE % (16 * 1024)) != 0 &&
+		       (PAGE_SIZE % (8 * 1024)) != 0 &&
+		       (PAGE_SIZE % (4 * 1024)) != 0)));
+
+	niu_debug = netif_msg_init(debug, NIU_MSG_DEFAULT);
+
+#ifdef CONFIG_SPARC64
+	err = of_register_driver(&niu_of_driver, &of_bus_type);
+#endif
+
+	if (!err) {
+		err = pci_register_driver(&niu_pci_driver);
+#ifdef CONFIG_SPARC64
+		if (err)
+			of_unregister_driver(&niu_of_driver);
+#endif
+	}
+
+	return err;
+}
+
+static void __exit niu_exit(void)
+{
+	pci_unregister_driver(&niu_pci_driver);
+#ifdef CONFIG_SPARC64
+	of_unregister_driver(&niu_of_driver);
+#endif
+}
+
+module_init(niu_init);
+module_exit(niu_exit);
diff --git a/drivers/net/niu.h b/drivers/net/niu.h
new file mode 100644
index 0000000..10e3f11
--- /dev/null
+++ b/drivers/net/niu.h
@@ -0,0 +1,3222 @@
+/* niu.h: Definitions for Neptune ethernet driver.
+ *
+ * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ */
+
+#ifndef _NIU_H
+#define _NIU_H
+
+#define PIO			0x000000UL
+#define FZC_PIO			0x080000UL
+#define FZC_MAC			0x180000UL
+#define FZC_IPP			0x280000UL
+#define FFLP			0x300000UL
+#define FZC_FFLP		0x380000UL
+#define PIO_VADDR		0x400000UL
+#define ZCP			0x500000UL
+#define FZC_ZCP			0x580000UL
+#define DMC			0x600000UL
+#define FZC_DMC			0x680000UL
+#define TXC			0x700000UL
+#define FZC_TXC			0x780000UL
+#define PIO_LDSV		0x800000UL
+#define PIO_PIO_LDGIM		0x900000UL
+#define PIO_IMASK0		0xa00000UL
+#define PIO_IMASK1		0xb00000UL
+#define FZC_PROM		0xc80000UL
+#define FZC_PIM			0xd80000UL
+
+#define LDSV0(LDG)		(PIO_LDSV + 0x00000UL + (LDG) * 0x2000UL)
+#define LDSV1(LDG)		(PIO_LDSV + 0x00008UL + (LDG) * 0x2000UL)
+#define LDSV2(LDG)		(PIO_LDSV + 0x00010UL + (LDG) * 0x2000UL)
+
+#define LDG_IMGMT(LDG)		(PIO_LDSV + 0x00018UL + (LDG) * 0x2000UL)
+#define  LDG_IMGMT_ARM		0x0000000080000000ULL
+#define  LDG_IMGMT_TIMER	0x000000000000003fULL
+
+#define LD_IM0(IDX)		(PIO_IMASK0 + 0x00000UL + (IDX) * 0x2000UL)
+#define  LD_IM0_MASK		0x0000000000000003ULL
+
+#define LD_IM1(IDX)		(PIO_IMASK1 + 0x00000UL + (IDX) * 0x2000UL)
+#define  LD_IM1_MASK		0x0000000000000003ULL
+
+#define LDG_TIMER_RES		(FZC_PIO + 0x00008UL)
+#define  LDG_TIMER_RES_VAL	0x00000000000fffffULL
+
+#define DIRTY_TID_CTL		(FZC_PIO + 0x00010UL)
+#define  DIRTY_TID_CTL_NPTHRED	0x00000000003f0000ULL
+#define  DIRTY_TID_CTL_RDTHRED	0x00000000000003f0ULL
+#define  DIRTY_TID_CTL_DTIDCLR	0x0000000000000002ULL
+#define  DIRTY_TID_CTL_DTIDENAB	0x0000000000000001ULL
+
+#define DIRTY_TID_STAT		(FZC_PIO + 0x00018UL)
+#define  DIRTY_TID_STAT_NPWSTAT	0x0000000000003f00ULL
+#define  DIRTY_TID_STAT_RDSTAT	0x000000000000003fULL
+
+#define RST_CTL			(FZC_PIO + 0x00038UL)
+#define  RST_CTL_MAC_RST3	0x0000000000400000ULL
+#define  RST_CTL_MAC_RST2	0x0000000000200000ULL
+#define  RST_CTL_MAC_RST1	0x0000000000100000ULL
+#define  RST_CTL_MAC_RST0	0x0000000000080000ULL
+#define  RST_CTL_ACK_TO_EN	0x0000000000000800ULL
+#define  RST_CTL_ACK_TO_VAL	0x00000000000007feULL
+
+#define SMX_CFIG_DAT		(FZC_PIO + 0x00040UL)
+#define  SMX_CFIG_DAT_RAS_DET	0x0000000080000000ULL
+#define  SMX_CFIG_DAT_RAS_INJ	0x0000000040000000ULL
+#define  SMX_CFIG_DAT_XACT_TO	0x000000000fffffffULL
+
+#define SMX_INT_STAT		(FZC_PIO + 0x00048UL)
+#define  SMX_INT_STAT_STAT	0x00000000ffffffffULL
+
+#define SMX_CTL			(FZC_PIO + 0x00050UL)
+#define  SMX_CTL_CTL		0x00000000ffffffffULL
+
+#define SMX_DBG_VEC		(FZC_PIO + 0x00058UL)
+#define  SMX_DBG_VEC_VEC	0x00000000ffffffffULL
+
+#define PIO_DBG_SEL		(FZC_PIO + 0x00060UL)
+#define  PIO_DBG_SEL_SEL	0x000000000000003fULL
+
+#define PIO_TRAIN_VEC		(FZC_PIO + 0x00068UL)
+#define  PIO_TRAIN_VEC_VEC	0x00000000ffffffffULL
+
+#define PIO_ARB_CTL		(FZC_PIO + 0x00070UL)
+#define  PIO_ARB_CTL_CTL	0x00000000ffffffffULL
+
+#define PIO_ARB_DBG_VEC		(FZC_PIO + 0x00078UL)
+#define  PIO_ARB_DBG_VEC_VEC	0x00000000ffffffffULL
+
+#define SYS_ERR_MASK		(FZC_PIO + 0x00090UL)
+#define  SYS_ERR_MASK_META2	0x0000000000000400ULL
+#define  SYS_ERR_MASK_META1	0x0000000000000200ULL
+#define  SYS_ERR_MASK_PEU	0x0000000000000100ULL
+#define  SYS_ERR_MASK_TXC	0x0000000000000080ULL
+#define  SYS_ERR_MASK_RDMC	0x0000000000000040ULL
+#define  SYS_ERR_MASK_TDMC	0x0000000000000020ULL
+#define  SYS_ERR_MASK_ZCP	0x0000000000000010ULL
+#define  SYS_ERR_MASK_FFLP	0x0000000000000008ULL
+#define  SYS_ERR_MASK_IPP	0x0000000000000004ULL
+#define  SYS_ERR_MASK_MAC	0x0000000000000002ULL
+#define  SYS_ERR_MASK_SMX	0x0000000000000001ULL
+
+#define SYS_ERR_STAT			(FZC_PIO + 0x00098UL)
+#define  SYS_ERR_STAT_META2		0x0000000000000400ULL
+#define  SYS_ERR_STAT_META1		0x0000000000000200ULL
+#define  SYS_ERR_STAT_PEU		0x0000000000000100ULL
+#define  SYS_ERR_STAT_TXC		0x0000000000000080ULL
+#define  SYS_ERR_STAT_RDMC		0x0000000000000040ULL
+#define  SYS_ERR_STAT_TDMC		0x0000000000000020ULL
+#define  SYS_ERR_STAT_ZCP		0x0000000000000010ULL
+#define  SYS_ERR_STAT_FFLP		0x0000000000000008ULL
+#define  SYS_ERR_STAT_IPP		0x0000000000000004ULL
+#define  SYS_ERR_STAT_MAC		0x0000000000000002ULL
+#define  SYS_ERR_STAT_SMX		0x0000000000000001ULL
+
+#define SID(LDG)			(FZC_PIO + 0x10200UL + (LDG) * 8UL)
+#define  SID_FUNC			0x0000000000000060ULL
+#define  SID_FUNC_SHIFT			5
+#define  SID_VECTOR			0x000000000000001fULL
+#define  SID_VECTOR_SHIFT		0
+
+#define LDG_NUM(LDN)			(FZC_PIO + 0x20000UL + (LDN) * 8UL)
+
+#define XMAC_PORT0_OFF			(FZC_MAC + 0x000000)
+#define XMAC_PORT1_OFF			(FZC_MAC + 0x006000)
+#define BMAC_PORT2_OFF			(FZC_MAC + 0x00c000)
+#define BMAC_PORT3_OFF			(FZC_MAC + 0x010000)
+
+/* XMAC registers, offset from np->mac_regs  */
+
+#define XTXMAC_SW_RST			0x00000UL
+#define  XTXMAC_SW_RST_REG_RS		0x0000000000000002ULL
+#define  XTXMAC_SW_RST_SOFT_RST		0x0000000000000001ULL
+
+#define XRXMAC_SW_RST			0x00008UL
+#define  XRXMAC_SW_RST_REG_RS		0x0000000000000002ULL
+#define  XRXMAC_SW_RST_SOFT_RST		0x0000000000000001ULL
+
+#define XTXMAC_STATUS			0x00020UL
+#define  XTXMAC_STATUS_FRAME_CNT_EXP	0x0000000000000800ULL
+#define  XTXMAC_STATUS_BYTE_CNT_EXP	0x0000000000000400ULL
+#define  XTXMAC_STATUS_TXFIFO_XFR_ERR	0x0000000000000010ULL
+#define  XTXMAC_STATUS_TXMAC_OFLOW	0x0000000000000008ULL
+#define  XTXMAC_STATUS_MAX_PSIZE_ERR	0x0000000000000004ULL
+#define  XTXMAC_STATUS_TXMAC_UFLOW	0x0000000000000002ULL
+#define  XTXMAC_STATUS_FRAME_XMITED	0x0000000000000001ULL
+
+#define XRXMAC_STATUS			0x00028UL
+#define  XRXMAC_STATUS_RXHIST7_CNT_EXP	0x0000000000100000ULL
+#define  XRXMAC_STATUS_LCL_FLT_STATUS	0x0000000000080000ULL
+#define  XRXMAC_STATUS_RFLT_DET		0x0000000000040000ULL
+#define  XRXMAC_STATUS_LFLT_CNT_EXP	0x0000000000020000ULL
+#define  XRXMAC_STATUS_PHY_MDINT	0x0000000000010000ULL
+#define  XRXMAC_STATUS_ALIGNERR_CNT_EXP	0x0000000000010000ULL
+#define  XRXMAC_STATUS_RXFRAG_CNT_EXP	0x0000000000008000ULL
+#define  XRXMAC_STATUS_RXMULTF_CNT_EXP	0x0000000000004000ULL
+#define  XRXMAC_STATUS_RXBCAST_CNT_EXP	0x0000000000002000ULL
+#define  XRXMAC_STATUS_RXHIST6_CNT_EXP	0x0000000000001000ULL
+#define  XRXMAC_STATUS_RXHIST5_CNT_EXP	0x0000000000000800ULL
+#define  XRXMAC_STATUS_RXHIST4_CNT_EXP	0x0000000000000400ULL
+#define  XRXMAC_STATUS_RXHIST3_CNT_EXP	0x0000000000000200ULL
+#define  XRXMAC_STATUS_RXHIST2_CNT_EXP	0x0000000000000100ULL
+#define  XRXMAC_STATUS_RXHIST1_CNT_EXP	0x0000000000000080ULL
+#define  XRXMAC_STATUS_RXOCTET_CNT_EXP	0x0000000000000040ULL
+#define  XRXMAC_STATUS_CVIOLERR_CNT_EXP	0x0000000000000020ULL
+#define  XRXMAC_STATUS_LENERR_CNT_EXP	0x0000000000000010ULL
+#define  XRXMAC_STATUS_CRCERR_CNT_EXP	0x0000000000000008ULL
+#define  XRXMAC_STATUS_RXUFLOW		0x0000000000000004ULL
+#define  XRXMAC_STATUS_RXOFLOW		0x0000000000000002ULL
+#define  XRXMAC_STATUS_FRAME_RCVD	0x0000000000000001ULL
+
+#define XMAC_FC_STAT			0x00030UL
+#define  XMAC_FC_STAT_RX_RCV_PAUSE_TIME	0x00000000ffff0000ULL
+#define  XMAC_FC_STAT_TX_MAC_NPAUSE	0x0000000000000004ULL
+#define  XMAC_FC_STAT_TX_MAC_PAUSE	0x0000000000000002ULL
+#define  XMAC_FC_STAT_RX_MAC_RPAUSE	0x0000000000000001ULL
+
+#define XTXMAC_STAT_MSK			0x00040UL
+#define  XTXMAC_STAT_MSK_FRAME_CNT_EXP	0x0000000000000800ULL
+#define  XTXMAC_STAT_MSK_BYTE_CNT_EXP	0x0000000000000400ULL
+#define  XTXMAC_STAT_MSK_TXFIFO_XFR_ERR	0x0000000000000010ULL
+#define  XTXMAC_STAT_MSK_TXMAC_OFLOW	0x0000000000000008ULL
+#define  XTXMAC_STAT_MSK_MAX_PSIZE_ERR	0x0000000000000004ULL
+#define  XTXMAC_STAT_MSK_TXMAC_UFLOW	0x0000000000000002ULL
+#define  XTXMAC_STAT_MSK_FRAME_XMITED	0x0000000000000001ULL
+
+#define XRXMAC_STAT_MSK				0x00048UL
+#define  XRXMAC_STAT_MSK_LCL_FLT_STAT_MSK	0x0000000000080000ULL
+#define  XRXMAC_STAT_MSK_RFLT_DET		0x0000000000040000ULL
+#define  XRXMAC_STAT_MSK_LFLT_CNT_EXP		0x0000000000020000ULL
+#define  XRXMAC_STAT_MSK_PHY_MDINT		0x0000000000010000ULL
+#define  XRXMAC_STAT_MSK_RXFRAG_CNT_EXP		0x0000000000008000ULL
+#define  XRXMAC_STAT_MSK_RXMULTF_CNT_EXP	0x0000000000004000ULL
+#define  XRXMAC_STAT_MSK_RXBCAST_CNT_EXP	0x0000000000002000ULL
+#define  XRXMAC_STAT_MSK_RXHIST6_CNT_EXP	0x0000000000001000ULL
+#define  XRXMAC_STAT_MSK_RXHIST5_CNT_EXP	0x0000000000000800ULL
+#define  XRXMAC_STAT_MSK_RXHIST4_CNT_EXP	0x0000000000000400ULL
+#define  XRXMAC_STAT_MSK_RXHIST3_CNT_EXP	0x0000000000000200ULL
+#define  XRXMAC_STAT_MSK_RXHIST2_CNT_EXP	0x0000000000000100ULL
+#define  XRXMAC_STAT_MSK_RXHIST1_CNT_EXP	0x0000000000000080ULL
+#define  XRXMAC_STAT_MSK_RXOCTET_CNT_EXP	0x0000000000000040ULL
+#define  XRXMAC_STAT_MSK_CVIOLERR_CNT_EXP	0x0000000000000020ULL
+#define  XRXMAC_STAT_MSK_LENERR_CNT_EXP		0x0000000000000010ULL
+#define  XRXMAC_STAT_MSK_CRCERR_CNT_EXP		0x0000000000000008ULL
+#define  XRXMAC_STAT_MSK_RXUFLOW_CNT_EXP	0x0000000000000004ULL
+#define  XRXMAC_STAT_MSK_RXOFLOW_CNT_EXP	0x0000000000000002ULL
+#define  XRXMAC_STAT_MSK_FRAME_RCVD		0x0000000000000001ULL
+
+#define XMAC_FC_MSK			0x00050UL
+#define  XMAC_FC_MSK_TX_MAC_NPAUSE	0x0000000000000004ULL
+#define  XMAC_FC_MSK_TX_MAC_PAUSE	0x0000000000000002ULL
+#define  XMAC_FC_MSK_RX_MAC_RPAUSE	0x0000000000000001ULL
+
+#define XMAC_CONFIG			0x00060UL
+#define  XMAC_CONFIG_SEL_CLK_25MHZ	0x0000000080000000ULL
+#define  XMAC_CONFIG_1G_PCS_BYPASS	0x0000000040000000ULL
+#define  XMAC_CONFIG_10G_XPCS_BYPASS	0x0000000020000000ULL
+#define  XMAC_CONFIG_MODE_MASK		0x0000000018000000ULL
+#define  XMAC_CONFIG_MODE_XGMII		0x0000000000000000ULL
+#define  XMAC_CONFIG_MODE_GMII		0x0000000008000000ULL
+#define  XMAC_CONFIG_MODE_MII		0x0000000010000000ULL
+#define  XMAC_CONFIG_LFS_DISABLE	0x0000000004000000ULL
+#define  XMAC_CONFIG_LOOPBACK		0x0000000002000000ULL
+#define  XMAC_CONFIG_TX_OUTPUT_EN	0x0000000001000000ULL
+#define  XMAC_CONFIG_SEL_POR_CLK_SRC	0x0000000000800000ULL
+#define  XMAC_CONFIG_LED_POLARITY	0x0000000000400000ULL
+#define  XMAC_CONFIG_FORCE_LED_ON	0x0000000000200000ULL
+#define  XMAC_CONFIG_PASS_FLOW_CTRL	0x0000000000100000ULL
+#define  XMAC_CONFIG_RCV_PAUSE_ENABLE	0x0000000000080000ULL
+#define  XMAC_CONFIG_MAC2IPP_PKT_CNT_EN	0x0000000000040000ULL
+#define  XMAC_CONFIG_STRIP_CRC		0x0000000000020000ULL
+#define  XMAC_CONFIG_ADDR_FILTER_EN	0x0000000000010000ULL
+#define  XMAC_CONFIG_HASH_FILTER_EN	0x0000000000008000ULL
+#define  XMAC_CONFIG_RX_CODEV_CHK_DIS	0x0000000000004000ULL
+#define  XMAC_CONFIG_RESERVED_MULTICAST	0x0000000000002000ULL
+#define  XMAC_CONFIG_RX_CRC_CHK_DIS	0x0000000000001000ULL
+#define  XMAC_CONFIG_ERR_CHK_DIS	0x0000000000000800ULL
+#define  XMAC_CONFIG_PROMISC_GROUP	0x0000000000000400ULL
+#define  XMAC_CONFIG_PROMISCUOUS	0x0000000000000200ULL
+#define  XMAC_CONFIG_RX_MAC_ENABLE	0x0000000000000100ULL
+#define  XMAC_CONFIG_WARNING_MSG_EN	0x0000000000000080ULL
+#define  XMAC_CONFIG_ALWAYS_NO_CRC	0x0000000000000008ULL
+#define  XMAC_CONFIG_VAR_MIN_IPG_EN	0x0000000000000004ULL
+#define  XMAC_CONFIG_STRETCH_MODE	0x0000000000000002ULL
+#define  XMAC_CONFIG_TX_ENABLE		0x0000000000000001ULL
+
+#define XMAC_IPG			0x00080UL
+#define  XMAC_IPG_STRETCH_CONST		0x0000000000e00000ULL
+#define  XMAC_IPG_STRETCH_CONST_SHIFT	21
+#define  XMAC_IPG_STRETCH_RATIO		0x00000000001f0000ULL
+#define  XMAC_IPG_STRETCH_RATIO_SHIFT	16
+#define  XMAC_IPG_IPG_MII_GMII		0x000000000000ff00ULL
+#define  XMAC_IPG_IPG_MII_GMII_SHIFT	8
+#define  XMAC_IPG_IPG_XGMII		0x0000000000000007ULL
+#define  XMAC_IPG_IPG_XGMII_SHIFT	0
+
+#define IPG_12_15_XGMII			3
+#define IPG_16_19_XGMII			4
+#define IPG_20_23_XGMII			5
+#define IPG_12_MII_GMII			10
+#define IPG_13_MII_GMII			11
+#define IPG_14_MII_GMII			12
+#define IPG_15_MII_GMII			13
+#define IPG_16_MII_GMII			14
+
+#define XMAC_MIN			0x00088UL
+#define  XMAC_MIN_RX_MIN_PKT_SIZE	0x000000003ff00000ULL
+#define  XMAC_MIN_RX_MIN_PKT_SIZE_SHFT	20
+#define  XMAC_MIN_SLOT_TIME		0x000000000003fc00ULL
+#define  XMAC_MIN_SLOT_TIME_SHFT	10
+#define  XMAC_MIN_TX_MIN_PKT_SIZE	0x00000000000003ffULL
+#define  XMAC_MIN_TX_MIN_PKT_SIZE_SHFT	0
+
+#define XMAC_MAX			0x00090UL
+#define  XMAC_MAX_FRAME_SIZE		0x0000000000003fffULL
+#define  XMAC_MAX_FRAME_SIZE_SHFT	0
+
+#define XMAC_ADDR0			0x000a0UL
+#define  XMAC_ADDR0_ADDR0		0x000000000000ffffULL
+
+#define XMAC_ADDR1			0x000a8UL
+#define  XMAC_ADDR1_ADDR1		0x000000000000ffffULL
+
+#define XMAC_ADDR2			0x000b0UL 
+#define  XMAC_ADDR2_ADDR2		0x000000000000ffffULL
+
+#define XMAC_ADDR_CMPEN			0x00208UL
+#define  XMAC_ADDR_CMPEN_EN15		0x0000000000008000ULL
+#define  XMAC_ADDR_CMPEN_EN14		0x0000000000004000ULL
+#define  XMAC_ADDR_CMPEN_EN13		0x0000000000002000ULL
+#define  XMAC_ADDR_CMPEN_EN12		0x0000000000001000ULL
+#define  XMAC_ADDR_CMPEN_EN11		0x0000000000000800ULL
+#define  XMAC_ADDR_CMPEN_EN10		0x0000000000000400ULL
+#define  XMAC_ADDR_CMPEN_EN9		0x0000000000000200ULL
+#define  XMAC_ADDR_CMPEN_EN8		0x0000000000000100ULL
+#define  XMAC_ADDR_CMPEN_EN7		0x0000000000000080ULL
+#define  XMAC_ADDR_CMPEN_EN6		0x0000000000000040ULL
+#define  XMAC_ADDR_CMPEN_EN5		0x0000000000000020ULL
+#define  XMAC_ADDR_CMPEN_EN4		0x0000000000000010ULL
+#define  XMAC_ADDR_CMPEN_EN3		0x0000000000000008ULL
+#define  XMAC_ADDR_CMPEN_EN2		0x0000000000000004ULL
+#define  XMAC_ADDR_CMPEN_EN1		0x0000000000000002ULL
+#define  XMAC_ADDR_CMPEN_EN0		0x0000000000000001ULL
+
+#define XMAC_NUM_ALT_ADDR		16
+
+#define XMAC_ALT_ADDR0(NUM)		(0x00218UL + (NUM)*0x18UL)
+#define  XMAC_ALT_ADDR0_ADDR0		0x000000000000ffffULL
+
+#define XMAC_ALT_ADDR1(NUM)		(0x00220UL + (NUM)*0x18UL)
+#define  XMAC_ALT_ADDR1_ADDR1		0x000000000000ffffULL
+
+#define XMAC_ALT_ADDR2(NUM)		(0x00228UL + (NUM)*0x18UL)
+#define  XMAC_ALT_ADDR2_ADDR2		0x000000000000ffffULL
+
+#define XMAC_ADD_FILT0			0x00818UL
+#define  XMAC_ADD_FILT0_FILT0		0x000000000000ffffULL
+
+#define XMAC_ADD_FILT1			0x00820UL
+#define  XMAC_ADD_FILT1_FILT1		0x000000000000ffffULL
+
+#define XMAC_ADD_FILT2			0x00828UL
+#define  XMAC_ADD_FILT2_FILT2		0x000000000000ffffULL
+
+#define XMAC_ADD_FILT12_MASK		0x00830UL
+#define  XMAC_ADD_FILT12_MASK_VAL	0x00000000000000ffULL
+
+#define XMAC_ADD_FILT00_MASK		0x00838UL
+#define  XMAC_ADD_FILT00_MASK_VAL	0x000000000000ffffULL
+
+#define XMAC_HASH_TBL(NUM)		(0x00840UL + (NUM) * 0x8UL)
+#define XMAC_HASH_TBL_VAL		0x000000000000ffffULL
+
+#define XMAC_NUM_HOST_INFO		20
+
+#define XMAC_HOST_INFO(NUM)		(0x00900UL + (NUM) * 0x8UL)
+
+#define XMAC_PA_DATA0			0x00b80UL
+#define XMAC_PA_DATA0_VAL		0x00000000ffffffffULL
+
+#define XMAC_PA_DATA1			0x00b88UL
+#define XMAC_PA_DATA1_VAL		0x00000000ffffffffULL
+
+#define XMAC_DEBUG_SEL			0x00b90UL
+#define  XMAC_DEBUG_SEL_XMAC		0x0000000000000078ULL
+#define  XMAC_DEBUG_SEL_MAC		0x0000000000000007ULL
+
+#define XMAC_TRAIN_VEC			0x00b98UL
+#define  XMAC_TRAIN_VEC_VAL		0x00000000ffffffffULL
+
+#define RXMAC_BT_CNT			0x00100UL
+#define  RXMAC_BT_CNT_COUNT		0x00000000ffffffffULL
+
+#define RXMAC_BC_FRM_CNT		0x00108UL
+#define  RXMAC_BC_FRM_CNT_COUNT		0x00000000001fffffULL
+
+#define RXMAC_MC_FRM_CNT		0x00110UL
+#define  RXMAC_MC_FRM_CNT_COUNT		0x00000000001fffffULL
+
+#define RXMAC_FRAG_CNT			0x00118UL
+#define  RXMAC_FRAG_CNT_COUNT		0x00000000001fffffULL
+
+#define RXMAC_HIST_CNT1			0x00120UL
+#define  RXMAC_HIST_CNT1_COUNT		0x00000000001fffffULL
+
+#define RXMAC_HIST_CNT2			0x00128UL
+#define  RXMAC_HIST_CNT2_COUNT		0x00000000001fffffULL
+
+#define RXMAC_HIST_CNT3			0x00130UL
+#define  RXMAC_HIST_CNT3_COUNT		0x00000000000fffffULL
+
+#define RXMAC_HIST_CNT4			0x00138UL
+#define  RXMAC_HIST_CNT4_COUNT		0x000000000007ffffULL
+
+#define RXMAC_HIST_CNT5			0x00140UL
+#define  RXMAC_HIST_CNT5_COUNT		0x000000000003ffffULL
+
+#define RXMAC_HIST_CNT6			0x00148UL
+#define  RXMAC_HIST_CNT6_COUNT		0x000000000000ffffULL
+
+#define RXMAC_MPSZER_CNT		0x00150UL
+#define  RXMAC_MPSZER_CNT_COUNT		0x00000000000000ffULL
+
+#define RXMAC_CRC_ER_CNT		0x00158UL
+#define  RXMAC_CRC_ER_CNT_COUNT		0x00000000000000ffULL
+
+#define RXMAC_CD_VIO_CNT		0x00160UL
+#define  RXMAC_CD_VIO_CNT_COUNT		0x00000000000000ffULL
+
+#define RXMAC_ALIGN_ERR_CNT		0x00168UL
+#define  RXMAC_ALIGN_ERR_CNT_COUNT	0x00000000000000ffULL
+
+#define TXMAC_FRM_CNT			0x00170UL
+#define  TXMAC_FRM_CNT_COUNT		0x00000000ffffffffULL
+
+#define TXMAC_BYTE_CNT			0x00178UL
+#define  TXMAC_BYTE_CNT_COUNT		0x00000000ffffffffULL
+
+#define LINK_FAULT_CNT			0x00180UL
+#define  LINK_FAULT_CNT_COUNT		0x00000000000000ffULL
+
+#define RXMAC_HIST_CNT7			0x00188UL
+#define  RXMAC_HIST_CNT7_COUNT		0x0000000007ffffffULL
+
+#define XMAC_SM_REG			0x001a8UL
+#define  XMAC_SM_REG_STATE		0x00000000ffffffffULL
+
+#define XMAC_INTER1			0x001b0UL
+#define  XMAC_INTERN1_SIGNALS1		0x00000000ffffffffULL
+
+#define XMAC_INTER2			0x001b8UL
+#define  XMAC_INTERN2_SIGNALS2		0x00000000ffffffffULL
+
+/* BMAC registers, offset from np->mac_regs  */
+
+#define BTXMAC_SW_RST			0x00000UL
+#define  BTXMAC_SW_RST_RESET		0x0000000000000001ULL
+
+#define BRXMAC_SW_RST			0x00008UL
+#define  BRXMAC_SW_RST_RESET		0x0000000000000001ULL
+
+#define BMAC_SEND_PAUSE			0x00010UL
+#define  BMAC_SEND_PAUSE_SEND		0x0000000000010000ULL
+#define  BMAC_SEND_PAUSE_TIME		0x000000000000ffffULL
+
+#define BTXMAC_STATUS			0x00020UL
+#define  BTXMAC_STATUS_XMIT		0x0000000000000001ULL
+#define  BTXMAC_STATUS_UNDERRUN		0x0000000000000002ULL
+#define  BTXMAC_STATUS_MAX_PKT_ERR	0x0000000000000004ULL
+#define  BTXMAC_STATUS_BYTE_CNT_EXP	0x0000000000000400ULL
+#define  BTXMAC_STATUS_FRAME_CNT_EXP	0x0000000000000800ULL
+
+#define BRXMAC_STATUS			0x00028UL
+#define  BRXMAC_STATUS_RX_PKT		0x0000000000000001ULL
+#define  BRXMAC_STATUS_OVERFLOW		0x0000000000000002ULL
+#define  BRXMAC_STATUS_FRAME_CNT_EXP	0x0000000000000004ULL
+#define  BRXMAC_STATUS_ALIGN_ERR_EXP	0x0000000000000008ULL
+#define  BRXMAC_STATUS_CRC_ERR_EXP	0x0000000000000010ULL
+#define  BRXMAC_STATUS_LEN_ERR_EXP	0x0000000000000020ULL
+
+#define BMAC_CTRL_STATUS		0x00030UL
+#define  BMAC_CTRL_STATUS_PAUSE_RECV	0x0000000000000001ULL
+#define  BMAC_CTRL_STATUS_PAUSE		0x0000000000000002ULL
+#define  BMAC_CTRL_STATUS_NOPAUSE	0x0000000000000004ULL
+#define  BMAC_CTRL_STATUS_TIME		0x00000000ffff0000ULL
+#define  BMAC_CTRL_STATUS_TIME_SHIFT	16
+
+#define BTXMAC_STATUS_MASK		0x00040UL
+#define BRXMAC_STATUS_MASK		0x00048UL
+#define BMAC_CTRL_STATUS_MASK		0x00050UL
+
+#define BTXMAC_CONFIG			0x00060UL
+#define  BTXMAC_CONFIG_ENABLE		0x0000000000000001ULL
+#define  BTXMAC_CONFIG_FCS_DISABLE	0x0000000000000002ULL
+
+#define BRXMAC_CONFIG			0x00068UL
+#define  BRXMAC_CONFIG_DISCARD_DIS	0x0000000000000080ULL
+#define  BRXMAC_CONFIG_ADDR_FILT_EN	0x0000000000000040ULL
+#define  BRXMAC_CONFIG_HASH_FILT_EN	0x0000000000000020ULL
+#define  BRXMAC_CONFIG_PROMISC_GRP	0x0000000000000010ULL
+#define  BRXMAC_CONFIG_PROMISC		0x0000000000000008ULL
+#define  BRXMAC_CONFIG_STRIP_FCS	0x0000000000000004ULL
+#define  BRXMAC_CONFIG_STRIP_PAD	0x0000000000000002ULL
+#define  BRXMAC_CONFIG_ENABLE		0x0000000000000001ULL
+
+#define BMAC_CTRL_CONFIG		0x00070UL
+#define  BMAC_CTRL_CONFIG_TX_PAUSE_EN	0x0000000000000001ULL
+#define  BMAC_CTRL_CONFIG_RX_PAUSE_EN	0x0000000000000002ULL
+#define  BMAC_CTRL_CONFIG_PASS_CTRL	0x0000000000000004ULL
+
+#define BMAC_XIF_CONFIG			0x00078UL
+#define  BMAC_XIF_CONFIG_TX_OUTPUT_EN	0x0000000000000001ULL
+#define  BMAC_XIF_CONFIG_MII_LOOPBACK	0x0000000000000002ULL
+#define  BMAC_XIF_CONFIG_GMII_MODE	0x0000000000000008ULL
+#define  BMAC_XIF_CONFIG_LINK_LED	0x0000000000000020ULL
+#define  BMAC_XIF_CONFIG_LED_POLARITY	0x0000000000000040ULL
+#define  BMAC_XIF_CONFIG_25MHZ_CLOCK	0x0000000000000080ULL
+
+#define BMAC_MIN_FRAME			0x000a0UL
+#define  BMAC_MIN_FRAME_VAL		0x00000000000003ffULL
+
+#define BMAC_MAX_FRAME			0x000a8UL
+#define  BMAC_MAX_FRAME_MAX_BURST	0x000000003fff0000ULL
+#define  BMAC_MAX_FRAME_MAX_BURST_SHIFT	16
+#define  BMAC_MAX_FRAME_MAX_FRAME	0x0000000000003fffULL
+#define  BMAC_MAX_FRAME_MAX_FRAME_SHIFT	0
+
+#define BMAC_PREAMBLE_SIZE		0x000b0UL
+#define  BMAC_PREAMBLE_SIZE_VAL		0x00000000000003ffULL
+
+#define BMAC_CTRL_TYPE			0x000c8UL
+
+#define BMAC_ADDR0			0x00100UL
+#define  BMAC_ADDR0_ADDR0		0x000000000000ffffULL
+
+#define BMAC_ADDR1			0x00108UL
+#define  BMAC_ADDR1_ADDR1		0x000000000000ffffULL
+
+#define BMAC_ADDR2			0x00110UL
+#define  BMAC_ADDR2_ADDR2		0x000000000000ffffULL
+
+#define BMAC_NUM_ALT_ADDR		7
+
+#define BMAC_ALT_ADDR0(NUM)		(0x00118UL + (NUM)*0x18UL)
+#define  BMAC_ALT_ADDR0_ADDR0		0x000000000000ffffULL
+
+#define BMAC_ALT_ADDR1(NUM)		(0x00120UL + (NUM)*0x18UL)
+#define  BMAC_ALT_ADDR1_ADDR1		0x000000000000ffffULL
+
+#define BMAC_ALT_ADDR2(NUM)		(0x00128UL + (NUM)*0x18UL)
+#define  BMAC_ALT_ADDR2_ADDR2		0x000000000000ffffULL
+
+#define BMAC_FC_ADDR0			0x00268UL
+#define  BMAC_FC_ADDR0_ADDR0		0x000000000000ffffULL
+
+#define BMAC_FC_ADDR1			0x00270UL
+#define  BMAC_FC_ADDR1_ADDR1		0x000000000000ffffULL
+
+#define BMAC_FC_ADDR2			0x00278UL
+#define  BMAC_FC_ADDR2_ADDR2		0x000000000000ffffULL
+
+#define BMAC_ADD_FILT0			0x00298UL
+#define  BMAC_ADD_FILT0_FILT0		0x000000000000ffffULL
+
+#define BMAC_ADD_FILT1			0x002a0UL
+#define  BMAC_ADD_FILT1_FILT1		0x000000000000ffffULL
+
+#define BMAC_ADD_FILT2			0x002a8UL
+#define  BMAC_ADD_FILT2_FILT2		0x000000000000ffffULL
+
+#define BMAC_ADD_FILT12_MASK		0x002b0UL
+#define  BMAC_ADD_FILT12_MASK_VAL	0x00000000000000ffULL
+
+#define BMAC_ADD_FILT00_MASK		0x002b8UL
+#define  BMAC_ADD_FILT00_MASK_VAL	0x000000000000ffffULL
+
+#define BMAC_HASH_TBL(NUM)		(0x002c0UL + (NUM) * 0x8UL)
+#define BMAC_HASH_TBL_VAL		0x000000000000ffffULL
+
+#define BRXMAC_FRAME_CNT		0x00370
+#define  BRXMAC_FRAME_CNT_COUNT		0x000000000000ffffULL
+
+#define BRXMAC_MAX_LEN_ERR_CNT		0x00378
+
+#define BRXMAC_ALIGN_ERR_CNT		0x00380
+#define  BRXMAC_ALIGN_ERR_CNT_COUNT	0x000000000000ffffULL
+
+#define BRXMAC_CRC_ERR_CNT		0x00388
+#define  BRXMAC_ALIGN_ERR_CNT_COUNT	0x000000000000ffffULL
+
+#define BRXMAC_CODE_VIOL_ERR_CNT	0x00390
+#define  BRXMAC_CODE_VIOL_ERR_CNT_COUNT	0x000000000000ffffULL
+
+#define BMAC_STATE_MACHINE		0x003a0
+
+#define BMAC_ADDR_CMPEN			0x003f8UL
+#define  BMAC_ADDR_CMPEN_EN15		0x0000000000008000ULL
+#define  BMAC_ADDR_CMPEN_EN14		0x0000000000004000ULL
+#define  BMAC_ADDR_CMPEN_EN13		0x0000000000002000ULL
+#define  BMAC_ADDR_CMPEN_EN12		0x0000000000001000ULL
+#define  BMAC_ADDR_CMPEN_EN11		0x0000000000000800ULL
+#define  BMAC_ADDR_CMPEN_EN10		0x0000000000000400ULL
+#define  BMAC_ADDR_CMPEN_EN9		0x0000000000000200ULL
+#define  BMAC_ADDR_CMPEN_EN8		0x0000000000000100ULL
+#define  BMAC_ADDR_CMPEN_EN7		0x0000000000000080ULL
+#define  BMAC_ADDR_CMPEN_EN6		0x0000000000000040ULL
+#define  BMAC_ADDR_CMPEN_EN5		0x0000000000000020ULL
+#define  BMAC_ADDR_CMPEN_EN4		0x0000000000000010ULL
+#define  BMAC_ADDR_CMPEN_EN3		0x0000000000000008ULL
+#define  BMAC_ADDR_CMPEN_EN2		0x0000000000000004ULL
+#define  BMAC_ADDR_CMPEN_EN1		0x0000000000000002ULL
+#define  BMAC_ADDR_CMPEN_EN0		0x0000000000000001ULL
+
+#define BMAC_NUM_HOST_INFO		9
+
+#define BMAC_HOST_INFO(NUM)		(0x00400UL + (NUM) * 0x8UL)
+
+#define BTXMAC_BYTE_CNT			0x00448UL
+#define  BTXMAC_BYTE_CNT_COUNT		0x00000000ffffffffULL
+
+#define BTXMAC_FRM_CNT			0x00450UL
+#define  BTXMAC_FRM_CNT_COUNT		0x00000000ffffffffULL
+
+#define BRXMAC_BYTE_CNT			0x00458UL
+#define  BRXMAC_BYTE_CNT_COUNT		0x00000000ffffffffULL
+
+#define HOST_INFO_MPR			0x0000000000000100ULL
+#define HOST_INFO_MACRDCTBLN		0x0000000000000007ULL
+
+/* XPCS registers, offset from np->regs + np->xpcs_off  */
+
+#define XPCS_CONTROL1			(FZC_MAC + 0x00000UL)
+#define  XPCS_CONTROL1_RESET		0x0000000000008000ULL
+#define  XPCS_CONTROL1_LOOPBACK		0x0000000000004000ULL
+#define  XPCS_CONTROL1_SPEED_SELECT3	0x0000000000002000ULL
+#define  XPCS_CONTROL1_CSR_LOW_PWR	0x0000000000000800ULL
+#define  XPCS_CONTROL1_CSR_SPEED1	0x0000000000000040ULL
+#define  XPCS_CONTROL1_CSR_SPEED0	0x000000000000003cULL
+
+#define XPCS_STATUS1			(FZC_MAC + 0x00008UL)
+#define  XPCS_STATUS1_CSR_FAULT		0x0000000000000080ULL
+#define  XPCS_STATUS1_CSR_RXLNK_STAT	0x0000000000000004ULL
+#define  XPCS_STATUS1_CSR_LPWR_ABLE	0x0000000000000002ULL
+
+#define XPCS_DEVICE_IDENTIFIER		(FZC_MAC + 0x00010UL)
+#define  XPCS_DEVICE_IDENTIFIER_VAL	0x00000000ffffffffULL
+
+#define XPCS_SPEED_ABILITY		(FZC_MAC + 0x00018UL)
+#define  XPCS_SPEED_ABILITY_10GIG	0x0000000000000001ULL
+
+#define XPCS_DEV_IN_PKG			(FZC_MAC + 0x00020UL)
+#define  XPCS_DEV_IN_PKG_CSR_VEND2	0x0000000080000000ULL
+#define  XPCS_DEV_IN_PKG_CSR_VEND1	0x0000000040000000ULL
+#define  XPCS_DEV_IN_PKG_DTE_XS		0x0000000000000020ULL
+#define  XPCS_DEV_IN_PKG_PHY_XS		0x0000000000000010ULL
+#define  XPCS_DEV_IN_PKG_PCS		0x0000000000000008ULL
+#define  XPCS_DEV_IN_PKG_WIS		0x0000000000000004ULL
+#define  XPCS_DEV_IN_PKG_PMD_PMA	0x0000000000000002ULL
+#define  XPCS_DEV_IN_PKG_CLS22		0x0000000000000001ULL
+
+#define XPCS_CONTROL2			(FZC_MAC + 0x00028UL)
+#define  XPCS_CONTROL2_CSR_PSC_SEL	0x0000000000000003ULL
+
+#define XPCS_STATUS2			(FZC_MAC + 0x00030UL)
+#define  XPCS_STATUS2_CSR_DEV_PRES	0x000000000000c000ULL
+#define  XPCS_STATUS2_CSR_TX_FAULT	0x0000000000000800ULL
+#define  XPCS_STATUS2_CSR_RCV_FAULT	0x0000000000000400ULL
+#define  XPCS_STATUS2_TEN_GBASE_W	0x0000000000000004ULL
+#define  XPCS_STATUS2_TEN_GBASE_X	0x0000000000000002ULL
+#define  XPCS_STATUS2_TEN_GBASE_R	0x0000000000000001ULL
+
+#define XPCS_PKG_ID			(FZC_MAC + 0x00038UL)
+#define  XPCS_PKG_ID_VAL		0x00000000ffffffffULL
+
+#define XPCS_STATUS(IDX)		(FZC_MAC + 0x00040UL)
+#define  XPCS_STATUS_CSR_LANE_ALIGN	0x0000000000001000ULL
+#define  XPCS_STATUS_CSR_PATTEST_CAP	0x0000000000000800ULL
+#define  XPCS_STATUS_CSR_LANE3_SYNC	0x0000000000000008ULL
+#define  XPCS_STATUS_CSR_LANE2_SYNC	0x0000000000000004ULL
+#define  XPCS_STATUS_CSR_LANE1_SYNC	0x0000000000000002ULL
+#define  XPCS_STATUS_CSR_LANE0_SYNC	0x0000000000000001ULL
+
+#define XPCS_TEST_CONTROL		(FZC_MAC + 0x00048UL)
+#define  XPCS_TEST_CONTROL_TXTST_EN	0x0000000000000004ULL
+#define  XPCS_TEST_CONTROL_TPAT_SEL	0x0000000000000003ULL
+
+#define XPCS_CFG_VENDOR1		(FZC_MAC + 0x00050UL)
+#define  XPCS_CFG_VENDOR1_DBG_IOTST	0x0000000000000080ULL
+#define  XPCS_CFG_VENDOR1_DBG_SEL	0x0000000000000078ULL
+#define  XPCS_CFG_VENDOR1_BYPASS_DET	0x0000000000000004ULL
+#define  XPCS_CFG_VENDOR1_TXBUF_EN	0x0000000000000002ULL
+#define  XPCS_CFG_VENDOR1_XPCS_EN	0x0000000000000001ULL
+
+#define XPCS_DIAG_VENDOR2		(FZC_MAC + 0x00058UL)
+#define  XPCS_DIAG_VENDOR2_SSM_LANE3	0x0000000001e00000ULL
+#define  XPCS_DIAG_VENDOR2_SSM_LANE2	0x00000000001e0000ULL
+#define  XPCS_DIAG_VENDOR2_SSM_LANE1	0x000000000001e000ULL
+#define  XPCS_DIAG_VENDOR2_SSM_LANE0	0x0000000000001e00ULL
+#define  XPCS_DIAG_VENDOR2_EBUF_SM	0x00000000000001feULL
+#define  XPCS_DIAG_VENDOR2_RCV_SM	0x0000000000000001ULL
+
+#define XPCS_MASK1			(FZC_MAC + 0x00060UL)
+#define  XPCS_MASK1_FAULT_MASK		0x0000000000000080ULL
+#define  XPCS_MASK1_RXALIGN_STAT_MSK	0x0000000000000004ULL
+
+#define XPCS_PKT_COUNT			(FZC_MAC + 0x00068UL)
+#define  XPCS_PKT_COUNT_TX		0x00000000ffff0000ULL
+#define  XPCS_PKT_COUNT_RX		0x000000000000ffffULL
+
+#define XPCS_TX_SM			(FZC_MAC + 0x00070UL)
+#define  XPCS_TX_SM_VAL			0x000000000000000fULL
+
+#define XPCS_DESKEW_ERR_CNT		(FZC_MAC + 0x00078UL)
+#define  XPCS_DESKEW_ERR_CNT_VAL	0x00000000000000ffULL
+
+#define XPCS_SYMERR_CNT01		(FZC_MAC + 0x00080UL)
+#define  XPCS_SYMERR_CNT01_LANE1	0x00000000ffff0000ULL
+#define  XPCS_SYMERR_CNT01_LANE0	0x000000000000ffffULL
+
+#define XPCS_SYMERR_CNT23		(FZC_MAC + 0x00088UL)
+#define  XPCS_SYMERR_CNT23_LANE3	0x00000000ffff0000ULL
+#define  XPCS_SYMERR_CNT23_LANE2	0x000000000000ffffULL
+
+#define XPCS_TRAINING_VECTOR		(FZC_MAC + 0x00090UL)
+#define  XPCS_TRAINING_VECTOR_VAL	0x00000000ffffffffULL
+
+/* PCS registers, offset from np->regs + np->pcs_off  */
+
+#define PCS_MII_CTL			(FZC_MAC + 0x00000UL)
+#define  PCS_MII_CTL_RST		0x0000000000008000ULL
+#define  PCS_MII_CTL_10_100_SPEED	0x0000000000002000ULL
+#define  PCS_MII_AUTONEG_EN		0x0000000000001000ULL
+#define  PCS_MII_PWR_DOWN		0x0000000000000800ULL
+#define  PCS_MII_ISOLATE		0x0000000000000400ULL
+#define  PCS_MII_AUTONEG_RESTART	0x0000000000000200ULL
+#define  PCS_MII_DUPLEX			0x0000000000000100ULL
+#define  PCS_MII_COLL_TEST		0x0000000000000080ULL
+#define  PCS_MII_1000MB_SPEED		0x0000000000000040ULL
+
+#define PCS_MII_STAT			(FZC_MAC + 0x00008UL)
+#define  PCS_MII_STAT_EXT_STATUS	0x0000000000000100ULL
+#define  PCS_MII_STAT_AUTONEG_DONE	0x0000000000000020ULL
+#define  PCS_MII_STAT_REMOTE_FAULT	0x0000000000000010ULL
+#define  PCS_MII_STAT_AUTONEG_ABLE	0x0000000000000008ULL
+#define  PCS_MII_STAT_LINK_STATUS	0x0000000000000004ULL
+#define  PCS_MII_STAT_JABBER_DET	0x0000000000000002ULL
+#define  PCS_MII_STAT_EXT_CAP		0x0000000000000001ULL
+
+#define PCS_MII_ADV			(FZC_MAC + 0x00010UL)
+#define  PCS_MII_ADV_NEXT_PAGE		0x0000000000008000ULL
+#define  PCS_MII_ADV_ACK		0x0000000000004000ULL
+#define  PCS_MII_ADV_REMOTE_FAULT	0x0000000000003000ULL
+#define  PCS_MII_ADV_ASM_DIR		0x0000000000000100ULL
+#define  PCS_MII_ADV_PAUSE		0x0000000000000080ULL
+#define  PCS_MII_ADV_HALF_DUPLEX	0x0000000000000040ULL
+#define  PCS_MII_ADV_FULL_DUPLEX	0x0000000000000020ULL
+
+#define PCS_MII_PARTNER			(FZC_MAC + 0x00018UL)
+#define  PCS_MII_PARTNER_NEXT_PAGE	0x0000000000008000ULL
+#define  PCS_MII_PARTNER_ACK		0x0000000000004000ULL
+#define  PCS_MII_PARTNER_REMOTE_FAULT	0x0000000000002000ULL
+#define  PCS_MII_PARTNER_PAUSE		0x0000000000000180ULL
+#define  PCS_MII_PARTNER_HALF_DUPLEX	0x0000000000000040ULL
+#define  PCS_MII_PARTNER_FULL_DUPLEX	0x0000000000000020ULL
+
+#define PCS_CONF			(FZC_MAC + 0x00020UL)
+#define  PCS_CONF_MASK			0x0000000000000040ULL
+#define  PCS_CONF_10MS_TMR_OVERRIDE	0x0000000000000020ULL
+#define  PCS_CONF_JITTER_STUDY		0x0000000000000018ULL
+#define  PCS_CONF_SIGDET_ACTIVE_LOW	0x0000000000000004ULL
+#define  PCS_CONF_SIGDET_OVERRIDE	0x0000000000000002ULL
+#define  PCS_CONF_ENABLE		0x0000000000000001ULL
+
+#define PCS_STATE			(FZC_MAC + 0x00028UL)
+#define  PCS_STATE_D_PARTNER_FAIL	0x0000000020000000ULL
+#define  PCS_STATE_D_WAIT_C_CODES_ACK	0x0000000010000000ULL
+#define  PCS_STATE_D_SYNC_LOSS		0x0000000008000000ULL
+#define  PCS_STATE_D_NO_GOOD_C_CODES	0x0000000004000000ULL
+#define  PCS_STATE_D_SERDES		0x0000000002000000ULL
+#define  PCS_STATE_D_BREAKLINK_C_CODES	0x0000000001000000ULL
+#define  PCS_STATE_L_SIGDET		0x0000000000400000ULL
+#define  PCS_STATE_L_SYNC_LOSS		0x0000000000200000ULL
+#define  PCS_STATE_L_C_CODES		0x0000000000100000ULL
+#define  PCS_STATE_LINK_CFG_STATE	0x000000000001e000ULL
+#define  PCS_STATE_SEQ_DET_STATE	0x0000000000001800ULL
+#define  PCS_STATE_WORD_SYNC_STATE	0x0000000000000700ULL
+#define  PCS_STATE_NO_IDLE		0x000000000000000fULL
+
+#define PCS_INTERRUPT			(FZC_MAC + 0x00030UL)
+#define  PCS_INTERRUPT_LSTATUS		0x0000000000000004ULL
+
+#define PCS_DPATH_MODE			(FZC_MAC + 0x000a0UL)
+#define  PCS_DPATH_MODE_PCS		0x0000000000000000ULL
+#define  PCS_DPATH_MODE_MII		0x0000000000000002ULL
+#define  PCS_DPATH_MODE_LINKUP_F_ENAB	0x0000000000000001ULL
+
+#define PCS_PKT_CNT			(FZC_MAC + 0x000c0UL)
+#define  PCS_PKT_CNT_RX			0x0000000007ff0000ULL
+#define  PCS_PKT_CNT_TX			0x00000000000007ffULL
+
+#define MIF_BB_MDC			(FZC_MAC + 0x16000UL)
+#define  MIF_BB_MDC_CLK			0x0000000000000001ULL
+
+#define MIF_BB_MDO			(FZC_MAC + 0x16008UL)
+#define  MIF_BB_MDO_DAT			0x0000000000000001ULL
+
+#define MIF_BB_MDO_EN			(FZC_MAC + 0x16010UL)
+#define  MIF_BB_MDO_EN_VAL		0x0000000000000001ULL
+
+#define MIF_FRAME_OUTPUT		(FZC_MAC + 0x16018UL)
+#define  MIF_FRAME_OUTPUT_ST		0x00000000c0000000ULL
+#define  MIF_FRAME_OUTPUT_ST_SHIFT	30
+#define  MIF_FRAME_OUTPUT_OP_ADDR	0x0000000000000000ULL
+#define  MIF_FRAME_OUTPUT_OP_WRITE	0x0000000010000000ULL
+#define  MIF_FRAME_OUTPUT_OP_READ_INC	0x0000000020000000ULL
+#define  MIF_FRAME_OUTPUT_OP_READ	0x0000000030000000ULL
+#define  MIF_FRAME_OUTPUT_OP_SHIFT	28
+#define  MIF_FRAME_OUTPUT_PORT		0x000000000f800000ULL
+#define  MIF_FRAME_OUTPUT_PORT_SHIFT	23
+#define  MIF_FRAME_OUTPUT_REG		0x00000000007c0000ULL
+#define  MIF_FRAME_OUTPUT_REG_SHIFT	18
+#define  MIF_FRAME_OUTPUT_TA		0x0000000000030000ULL
+#define  MIF_FRAME_OUTPUT_TA_SHIFT	16
+#define  MIF_FRAME_OUTPUT_DATA		0x000000000000ffffULL
+#define  MIF_FRAME_OUTPUT_DATA_SHIFT	0
+
+#define MDIO_ADDR_OP(port, dev, reg) \
+	((0 << MIF_FRAME_OUTPUT_ST_SHIFT) | \
+	 MIF_FRAME_OUTPUT_OP_ADDR | \
+	 (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \
+	 (dev << MIF_FRAME_OUTPUT_REG_SHIFT) | \
+	 (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT) | \
+	 (reg << MIF_FRAME_OUTPUT_DATA_SHIFT))
+
+#define MDIO_READ_OP(port, dev) \
+	((0 << MIF_FRAME_OUTPUT_ST_SHIFT) | \
+	 MIF_FRAME_OUTPUT_OP_READ | \
+	 (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \
+	 (dev << MIF_FRAME_OUTPUT_REG_SHIFT) | \
+	 (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT))
+
+#define MDIO_WRITE_OP(port, dev, data) \
+	((0 << MIF_FRAME_OUTPUT_ST_SHIFT) | \
+	 MIF_FRAME_OUTPUT_OP_WRITE | \
+	 (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \
+	 (dev << MIF_FRAME_OUTPUT_REG_SHIFT) | \
+	 (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT) | \
+	 (data << MIF_FRAME_OUTPUT_DATA_SHIFT))
+
+#define MII_READ_OP(port, reg) \
+	((1 << MIF_FRAME_OUTPUT_ST_SHIFT) | \
+	 (2 << MIF_FRAME_OUTPUT_OP_SHIFT) | \
+	 (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \
+	 (reg << MIF_FRAME_OUTPUT_REG_SHIFT) | \
+	 (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT))
+
+#define MII_WRITE_OP(port, reg, data) \
+	((1 << MIF_FRAME_OUTPUT_ST_SHIFT) | \
+	 (1 << MIF_FRAME_OUTPUT_OP_SHIFT) | \
+	 (port << MIF_FRAME_OUTPUT_PORT_SHIFT) | \
+	 (reg << MIF_FRAME_OUTPUT_REG_SHIFT) | \
+	 (0x2 << MIF_FRAME_OUTPUT_TA_SHIFT) | \
+	 (data << MIF_FRAME_OUTPUT_DATA_SHIFT))
+
+#define MIF_CONFIG			(FZC_MAC + 0x16020UL)
+#define  MIF_CONFIG_ATCA_GE		0x0000000000010000ULL
+#define  MIF_CONFIG_INDIRECT_MODE	0x0000000000008000ULL
+#define  MIF_CONFIG_POLL_PRT_PHYADDR	0x0000000000003c00ULL
+#define  MIF_CONFIG_POLL_DEV_REG_ADDR	0x00000000000003e0ULL
+#define  MIF_CONFIG_BB_MODE		0x0000000000000010ULL
+#define  MIF_CONFIG_POLL_EN		0x0000000000000008ULL
+#define  MIF_CONFIG_BB_SER_SEL		0x0000000000000006ULL
+#define  MIF_CONFIG_MANUAL_MODE		0x0000000000000001ULL
+
+#define MIF_POLL_STATUS			(FZC_MAC + 0x16028UL)
+#define  MIF_POLL_STATUS_DATA		0x00000000ffff0000ULL
+#define  MIF_POLL_STATUS_STAT		0x000000000000ffffULL
+
+#define MIF_POLL_MASK			(FZC_MAC + 0x16030UL)
+#define  MIF_POLL_MASK_VAL		0x000000000000ffffULL
+
+#define MIF_SM				(FZC_MAC + 0x16038UL)
+#define  MIF_SM_PORT_ADDR		0x00000000001f0000ULL
+#define  MIF_SM_MDI_1			0x0000000000004000ULL
+#define  MIF_SM_MDI_0			0x0000000000002400ULL
+#define  MIF_SM_MDCLK			0x0000000000001000ULL
+#define  MIF_SM_MDO_EN			0x0000000000000800ULL
+#define  MIF_SM_MDO			0x0000000000000400ULL
+#define  MIF_SM_MDI			0x0000000000000200ULL
+#define  MIF_SM_CTL			0x00000000000001c0ULL
+#define  MIF_SM_EX			0x000000000000003fULL
+
+#define MIF_STATUS			(FZC_MAC + 0x16040UL)
+#define  MIF_STATUS_MDINT1		0x0000000000000020ULL
+#define  MIF_STATUS_MDINT0		0x0000000000000010ULL
+
+#define MIF_MASK			(FZC_MAC + 0x16048UL)
+#define  MIF_MASK_MDINT1		0x0000000000000020ULL
+#define  MIF_MASK_MDINT0		0x0000000000000010ULL
+#define  MIF_MASK_PEU_ERR		0x0000000000000008ULL
+#define  MIF_MASK_YC			0x0000000000000004ULL
+#define  MIF_MASK_XGE_ERR0		0x0000000000000002ULL
+#define  MIF_MASK_MIF_INIT_DONE		0x0000000000000001ULL
+
+#define ENET_SERDES_RESET		(FZC_MAC + 0x14000UL)
+#define  ENET_SERDES_RESET_1		0x0000000000000002ULL
+#define  ENET_SERDES_RESET_0		0x0000000000000001ULL
+
+#define ENET_SERDES_CFG			(FZC_MAC + 0x14008UL)
+#define  ENET_SERDES_BE_LOOPBACK	0x0000000000000002ULL
+#define  ENET_SERDES_CFG_FORCE_RDY	0x0000000000000001ULL
+
+#define ENET_SERDES_0_PLL_CFG		(FZC_MAC + 0x14010UL)
+#define  ENET_SERDES_PLL_FBDIV0		0x0000000000000001ULL
+#define  ENET_SERDES_PLL_FBDIV1		0x0000000000000002ULL
+#define  ENET_SERDES_PLL_FBDIV2		0x0000000000000004ULL
+#define  ENET_SERDES_PLL_HRATE0		0x0000000000000008ULL
+#define  ENET_SERDES_PLL_HRATE1		0x0000000000000010ULL
+#define  ENET_SERDES_PLL_HRATE2		0x0000000000000020ULL
+#define  ENET_SERDES_PLL_HRATE3		0x0000000000000040ULL
+
+#define ENET_SERDES_0_CTRL_CFG		(FZC_MAC + 0x14018UL)
+#define  ENET_SERDES_CTRL_SDET_0	0x0000000000000001ULL
+#define  ENET_SERDES_CTRL_SDET_1	0x0000000000000002ULL
+#define  ENET_SERDES_CTRL_SDET_2	0x0000000000000004ULL
+#define  ENET_SERDES_CTRL_SDET_3	0x0000000000000008ULL
+#define  ENET_SERDES_CTRL_EMPH_0	0x0000000000000070ULL
+#define  ENET_SERDES_CTRL_EMPH_0_SHIFT	4
+#define  ENET_SERDES_CTRL_EMPH_1	0x0000000000000380ULL
+#define  ENET_SERDES_CTRL_EMPH_1_SHIFT	7
+#define  ENET_SERDES_CTRL_EMPH_2	0x0000000000001c00ULL
+#define  ENET_SERDES_CTRL_EMPH_2_SHIFT	10
+#define  ENET_SERDES_CTRL_EMPH_3	0x000000000000e000ULL
+#define  ENET_SERDES_CTRL_EMPH_3_SHIFT	13
+#define  ENET_SERDES_CTRL_LADJ_0	0x0000000000070000ULL
+#define  ENET_SERDES_CTRL_LADJ_0_SHIFT	16
+#define  ENET_SERDES_CTRL_LADJ_1	0x0000000000380000ULL
+#define  ENET_SERDES_CTRL_LADJ_1_SHIFT	19
+#define  ENET_SERDES_CTRL_LADJ_2	0x0000000001c00000ULL
+#define  ENET_SERDES_CTRL_LADJ_2_SHIFT	22
+#define  ENET_SERDES_CTRL_LADJ_3	0x000000000e000000ULL
+#define  ENET_SERDES_CTRL_LADJ_3_SHIFT	25
+#define  ENET_SERDES_CTRL_RXITERM_0	0x0000000010000000ULL
+#define  ENET_SERDES_CTRL_RXITERM_1	0x0000000020000000ULL
+#define  ENET_SERDES_CTRL_RXITERM_2	0x0000000040000000ULL
+#define  ENET_SERDES_CTRL_RXITERM_3	0x0000000080000000ULL
+
+#define ENET_SERDES_0_TEST_CFG		(FZC_MAC + 0x14020UL)
+#define  ENET_SERDES_TEST_MD_0		0x0000000000000003ULL
+#define  ENET_SERDES_TEST_MD_0_SHIFT	0
+#define  ENET_SERDES_TEST_MD_1		0x000000000000000cULL
+#define  ENET_SERDES_TEST_MD_1_SHIFT	2
+#define  ENET_SERDES_TEST_MD_2		0x0000000000000030ULL
+#define  ENET_SERDES_TEST_MD_2_SHIFT	4
+#define  ENET_SERDES_TEST_MD_3		0x00000000000000c0ULL
+#define  ENET_SERDES_TEST_MD_3_SHIFT	6
+
+#define ENET_TEST_MD_NO_LOOPBACK	0x0
+#define ENET_TEST_MD_EWRAP		0x1
+#define ENET_TEST_MD_PAD_LOOPBACK	0x2
+#define ENET_TEST_MD_REV_LOOPBACK	0x3
+
+#define ENET_SERDES_1_PLL_CFG		(FZC_MAC + 0x14028UL)
+#define ENET_SERDES_1_CTRL_CFG		(FZC_MAC + 0x14030UL)
+#define ENET_SERDES_1_TEST_CFG		(FZC_MAC + 0x14038UL)
+
+#define ENET_RGMII_CFG_REG		(FZC_MAC + 0x14040UL)
+
+#define ESR_INT_SIGNALS			(FZC_MAC + 0x14800UL)
+#define  ESR_INT_SIGNALS_ALL		0x00000000ffffffffULL
+#define  ESR_INT_SIGNALS_P0_BITS	0x0000000033e0000fULL
+#define  ESR_INT_SIGNALS_P1_BITS	0x000000000c1f00f0ULL
+#define  ESR_INT_SRDY0_P0		0x0000000020000000ULL
+#define  ESR_INT_DET0_P0		0x0000000010000000ULL
+#define  ESR_INT_SRDY0_P1		0x0000000008000000ULL
+#define  ESR_INT_DET0_P1		0x0000000004000000ULL
+#define  ESR_INT_XSRDY_P0		0x0000000002000000ULL
+#define  ESR_INT_XDP_P0_CH3		0x0000000001000000ULL
+#define  ESR_INT_XDP_P0_CH2		0x0000000000800000ULL
+#define  ESR_INT_XDP_P0_CH1		0x0000000000400000ULL
+#define  ESR_INT_XDP_P0_CH0		0x0000000000200000ULL
+#define  ESR_INT_XSRDY_P1		0x0000000000100000ULL
+#define  ESR_INT_XDP_P1_CH3		0x0000000000080000ULL
+#define  ESR_INT_XDP_P1_CH2		0x0000000000040000ULL
+#define  ESR_INT_XDP_P1_CH1		0x0000000000020000ULL
+#define  ESR_INT_XDP_P1_CH0		0x0000000000010000ULL
+#define  ESR_INT_SLOSS_P1_CH3		0x0000000000000080ULL
+#define  ESR_INT_SLOSS_P1_CH2		0x0000000000000040ULL
+#define  ESR_INT_SLOSS_P1_CH1		0x0000000000000020ULL
+#define  ESR_INT_SLOSS_P1_CH0		0x0000000000000010ULL
+#define  ESR_INT_SLOSS_P0_CH3		0x0000000000000008ULL
+#define  ESR_INT_SLOSS_P0_CH2		0x0000000000000004ULL
+#define  ESR_INT_SLOSS_P0_CH1		0x0000000000000002ULL
+#define  ESR_INT_SLOSS_P0_CH0		0x0000000000000001ULL
+
+#define ESR_DEBUG_SEL			(FZC_MAC + 0x14808UL)
+#define  ESR_DEBUG_SEL_VAL		0x000000000000003fULL
+
+/* SerDes registers behind MIF */
+#define NIU_ESR_DEV_ADDR		0x1e
+#define ESR_BASE			0x0000
+
+#define ESR_RXTX_COMM_CTRL_L		(ESR_BASE + 0x0000)
+#define ESR_RXTX_COMM_CTRL_H		(ESR_BASE + 0x0001)
+
+#define ESR_RXTX_RESET_CTRL_L		(ESR_BASE + 0x0002)
+#define ESR_RXTX_RESET_CTRL_H		(ESR_BASE + 0x0003)
+
+#define ESR_RX_POWER_CTRL_L		(ESR_BASE + 0x0004)
+#define ESR_RX_POWER_CTRL_H		(ESR_BASE + 0x0005)
+
+#define ESR_TX_POWER_CTRL_L		(ESR_BASE + 0x0006)
+#define ESR_TX_POWER_CTRL_H		(ESR_BASE + 0x0007)
+
+#define ESR_MISC_POWER_CTRL_L		(ESR_BASE + 0x0008)
+#define ESR_MISC_POWER_CTRL_H		(ESR_BASE + 0x0009)
+
+#define ESR_RXTX_CTRL_L(CHAN)		(ESR_BASE + 0x0080 + (CHAN) * 0x10)
+#define ESR_RXTX_CTRL_H(CHAN)		(ESR_BASE + 0x0081 + (CHAN) * 0x10)
+#define  ESR_RXTX_CTRL_BIASCNTL		0x80000000
+#define  ESR_RXTX_CTRL_RESV1		0x7c000000
+#define  ESR_RXTX_CTRL_TDENFIFO		0x02000000
+#define  ESR_RXTX_CTRL_TDWS20		0x01000000
+#define  ESR_RXTX_CTRL_VMUXLO		0x00c00000
+#define  ESR_RXTX_CTRL_VMUXLO_SHIFT	22
+#define  ESR_RXTX_CTRL_VPULSELO		0x00300000
+#define  ESR_RXTX_CTRL_VPULSELO_SHIFT	20
+#define  ESR_RXTX_CTRL_RESV2		0x000f0000
+#define  ESR_RXTX_CTRL_RESV3		0x0000c000
+#define  ESR_RXTX_CTRL_RXPRESWIN	0x00003000
+#define  ESR_RXTX_CTRL_RXPRESWIN_SHIFT	12
+#define  ESR_RXTX_CTRL_RESV4		0x00000800
+#define  ESR_RXTX_CTRL_RISEFALL		0x00000700
+#define  ESR_RXTX_CTRL_RISEFALL_SHIFT	8
+#define  ESR_RXTX_CTRL_RESV5		0x000000fe
+#define  ESR_RXTX_CTRL_ENSTRETCH	0x00000001
+
+#define ESR_RXTX_TUNING_L(CHAN)		(ESR_BASE + 0x0082 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING_H(CHAN)		(ESR_BASE + 0x0083 + (CHAN) * 0x10)
+
+#define ESR_RX_SYNCCHAR_L(CHAN)		(ESR_BASE + 0x0084 + (CHAN) * 0x10)
+#define ESR_RX_SYNCCHAR_H(CHAN)		(ESR_BASE + 0x0085 + (CHAN) * 0x10)
+
+#define ESR_RXTX_TEST_L(CHAN)		(ESR_BASE + 0x0086 + (CHAN) * 0x10)
+#define ESR_RXTX_TEST_H(CHAN)		(ESR_BASE + 0x0087 + (CHAN) * 0x10)
+
+#define ESR_GLUE_CTRL0_L(CHAN)		(ESR_BASE + 0x0088 + (CHAN) * 0x10)
+#define ESR_GLUE_CTRL0_H(CHAN)		(ESR_BASE + 0x0089 + (CHAN) * 0x10)
+#define  ESR_GLUE_CTRL0_RESV1		0xf8000000
+#define  ESR_GLUE_CTRL0_BLTIME		0x07000000
+#define  ESR_GLUE_CTRL0_BLTIME_SHIFT	24
+#define  ESR_GLUE_CTRL0_RESV2		0x00ff0000
+#define  ESR_GLUE_CTRL0_RXLOS_TEST	0x00008000
+#define  ESR_GLUE_CTRL0_RESV3		0x00004000
+#define  ESR_GLUE_CTRL0_RXLOSENAB	0x00002000
+#define  ESR_GLUE_CTRL0_FASTRESYNC	0x00001000
+#define  ESR_GLUE_CTRL0_SRATE		0x00000f00
+#define  ESR_GLUE_CTRL0_SRATE_SHIFT	8
+#define  ESR_GLUE_CTRL0_THCNT		0x000000ff
+#define  ESR_GLUE_CTRL0_THCNT_SHIFT	0
+
+#define BLTIME_64_CYCLES		0
+#define BLTIME_128_CYCLES		1
+#define BLTIME_256_CYCLES		2
+#define BLTIME_300_CYCLES		3
+#define BLTIME_384_CYCLES		4
+#define BLTIME_512_CYCLES		5
+#define BLTIME_1024_CYCLES		6
+#define BLTIME_2048_CYCLES		7
+
+#define ESR_GLUE_CTRL1_L(CHAN)		(ESR_BASE + 0x008a + (CHAN) * 0x10)
+#define ESR_GLUE_CTRL1_H(CHAN)		(ESR_BASE + 0x008b + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING1_L(CHAN)	(ESR_BASE + 0x00c2 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING1_H(CHAN)	(ESR_BASE + 0x00c2 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING2_L(CHAN)	(ESR_BASE + 0x0102 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING2_H(CHAN)	(ESR_BASE + 0x0102 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING3_L(CHAN)	(ESR_BASE + 0x0142 + (CHAN) * 0x10)
+#define ESR_RXTX_TUNING3_H(CHAN)	(ESR_BASE + 0x0142 + (CHAN) * 0x10)
+
+#define NIU_ESR2_DEV_ADDR		0x1e
+#define ESR2_BASE			0x8000
+
+#define ESR2_TI_PLL_CFG_L		(ESR2_BASE + 0x000)
+#define ESR2_TI_PLL_CFG_H		(ESR2_BASE + 0x001)
+#define  PLL_CFG_STD			0x00000c00
+#define  PLL_CFG_STD_SHIFT		10
+#define  PLL_CFG_LD			0x00000300
+#define  PLL_CFG_LD_SHIFT		8
+#define  PLL_CFG_MPY			0x0000001e
+#define  PLL_CFG_MPY_SHIFT		1
+#define  PLL_CFG_ENPLL			0x00000001
+
+#define ESR2_TI_PLL_STS_L		(ESR2_BASE + 0x002)
+#define ESR2_TI_PLL_STS_H		(ESR2_BASE + 0x003)
+#define  PLL_STS_LOCK			0x00000001
+
+#define ESR2_TI_PLL_TEST_CFG_L		(ESR2_BASE + 0x004)
+#define ESR2_TI_PLL_TEST_CFG_H		(ESR2_BASE + 0x005)
+#define  PLL_TEST_INVPATT		0x00004000
+#define  PLL_TEST_RATE			0x00003000
+#define  PLL_TEST_RATE_SHIFT		12
+#define  PLL_TEST_CFG_ENBSAC		0x00000400
+#define  PLL_TEST_CFG_ENBSRX		0x00000200
+#define  PLL_TEST_CFG_ENBSTX		0x00000100
+#define  PLL_TEST_CFG_LOOPBACK_PAD	0x00000040
+#define  PLL_TEST_CFG_LOOPBACK_CML_DIS	0x00000080
+#define  PLL_TEST_CFG_LOOPBACK_CML_EN	0x000000c0
+#define  PLL_TEST_CFG_CLKBYP		0x00000030
+#define  PLL_TEST_CFG_CLKBYP_SHIFT	4
+#define  PLL_TEST_CFG_EN_RXPATT		0x00000008
+#define  PLL_TEST_CFG_EN_TXPATT		0x00000004
+#define  PLL_TEST_CFG_TPATT		0x00000003
+#define  PLL_TEST_CFG_TPATT_SHIFT	0
+
+#define ESR2_TI_PLL_TX_CFG_L(CHAN)	(ESR2_BASE + 0x100 + (CHAN) * 4)
+#define ESR2_TI_PLL_TX_CFG_H(CHAN)	(ESR2_BASE + 0x101 + (CHAN) * 4)
+#define  PLL_TX_CFG_RDTCT		0x00600000
+#define  PLL_TX_CFG_RDTCT_SHIFT		21
+#define  PLL_TX_CFG_ENIDL		0x00100000
+#define  PLL_TX_CFG_BSTX		0x00020000
+#define  PLL_TX_CFG_ENFTP		0x00010000
+#define  PLL_TX_CFG_DE			0x0000f000
+#define  PLL_TX_CFG_DE_SHIFT		12
+#define  PLL_TX_CFG_SWING_125MV		0x00000000
+#define  PLL_TX_CFG_SWING_250MV		0x00000200
+#define  PLL_TX_CFG_SWING_500MV		0x00000400
+#define  PLL_TX_CFG_SWING_625MV		0x00000600
+#define  PLL_TX_CFG_SWING_750MV		0x00000800
+#define  PLL_TX_CFG_SWING_1000MV	0x00000a00
+#define  PLL_TX_CFG_SWING_1250MV	0x00000c00
+#define  PLL_TX_CFG_SWING_1375MV	0x00000e00
+#define  PLL_TX_CFG_CM			0x00000100
+#define  PLL_TX_CFG_INVPAIR		0x00000080
+#define  PLL_TX_CFG_RATE		0x00000060
+#define  PLL_TX_CFG_RATE_SHIFT		5
+#define  PLL_TX_CFG_BUSWIDTH		0x0000001c
+#define  PLL_TX_CFG_BUSWIDTH_SHIFT	2
+#define  PLL_TX_CFG_ENTEST		0x00000002
+#define  PLL_TX_CFG_ENTX		0x00000001
+
+#define ESR2_TI_PLL_TX_STS_L(CHAN)	(ESR2_BASE + 0x102 + (CHAN) * 4)
+#define ESR2_TI_PLL_TX_STS_H(CHAN)	(ESR2_BASE + 0x103 + (CHAN) * 4)
+#define  PLL_TX_STS_RDTCTIP		0x00000002
+#define  PLL_TX_STS_TESTFAIL		0x00000001
+
+#define ESR2_TI_PLL_RX_CFG_L(CHAN)	(ESR2_BASE + 0x120 + (CHAN) * 4)
+#define ESR2_TI_PLL_RX_CFG_H(CHAN)	(ESR2_BASE + 0x121 + (CHAN) * 4)
+#define  PLL_RX_CFG_BSINRXN		0x02000000
+#define  PLL_RX_CFG_BSINRXP		0x01000000
+#define  PLL_RX_CFG_EQ_MAX_LF		0x00000000
+#define  PLL_RX_CFG_EQ_LP_ADAPTIVE	0x00080000
+#define  PLL_RX_CFG_EQ_LP_1084MHZ	0x00400000
+#define  PLL_RX_CFG_EQ_LP_805MHZ	0x00480000
+#define  PLL_RX_CFG_EQ_LP_573MHZ	0x00500000
+#define  PLL_RX_CFG_EQ_LP_402MHZ	0x00580000
+#define  PLL_RX_CFG_EQ_LP_304MHZ	0x00600000
+#define  PLL_RX_CFG_EQ_LP_216MHZ	0x00680000
+#define  PLL_RX_CFG_EQ_LP_156MHZ	0x00700000
+#define  PLL_RX_CFG_EQ_LP_135MHZ	0x00780000
+#define  PLL_RX_CFG_EQ_SHIFT		19
+#define  PLL_RX_CFG_CDR			0x00070000
+#define  PLL_RX_CFG_CDR_SHIFT		16
+#define  PLL_RX_CFG_LOS_DIS		0x00000000
+#define  PLL_RX_CFG_LOS_HTHRESH		0x00004000
+#define  PLL_RX_CFG_LOS_LTHRESH		0x00008000
+#define  PLL_RX_CFG_ALIGN_DIS		0x00000000
+#define  PLL_RX_CFG_ALIGN_ENA		0x00001000
+#define  PLL_RX_CFG_ALIGN_JOG		0x00002000
+#define  PLL_RX_CFG_TERM_VDDT		0x00000000
+#define  PLL_RX_CFG_TERM_0P8VDDT	0x00000100
+#define  PLL_RX_CFG_TERM_FLOAT		0x00000300
+#define  PLL_RX_CFG_INVPAIR		0x00000080
+#define  PLL_RX_CFG_RATE		0x00000060
+#define  PLL_RX_CFG_RATE_SHIFT		5
+#define  PLL_RX_CFG_BUSWIDTH		0x0000001c
+#define  PLL_RX_CFG_BUSWIDTH_SHIFT	2
+#define  PLL_RX_CFG_ENTEST		0x00000002
+#define  PLL_RX_CFG_ENRX		0x00000001
+
+#define ESR2_TI_PLL_RX_STS_L(CHAN)	(ESR2_BASE + 0x122 + (CHAN) * 4)
+#define ESR2_TI_PLL_RX_STS_H(CHAN)	(ESR2_BASE + 0x123 + (CHAN) * 4)
+#define  PLL_RX_STS_CRCIDTCT		0x00000200
+#define  PLL_RX_STS_CWDTCT		0x00000100
+#define  PLL_RX_STS_BSRXN		0x00000020
+#define  PLL_RX_STS_BSRXP		0x00000010
+#define  PLL_RX_STS_LOSDTCT		0x00000008
+#define  PLL_RX_STS_ODDCG		0x00000004
+#define  PLL_RX_STS_SYNC		0x00000002
+#define  PLL_RX_STS_TESTFAIL		0x00000001
+
+#define ENET_VLAN_TBL(IDX)		(FZC_FFLP + 0x00000UL + (IDX) * 8UL)
+#define  ENET_VLAN_TBL_PARITY1		0x0000000000020000ULL
+#define  ENET_VLAN_TBL_PARITY0		0x0000000000010000ULL
+#define  ENET_VLAN_TBL_VPR		0x0000000000000008ULL
+#define  ENET_VLAN_TBL_VLANRDCTBLN	0x0000000000000007ULL
+#define  ENET_VLAN_TBL_SHIFT(PORT)	((PORT) * 4)
+
+#define ENET_VLAN_TBL_NUM_ENTRIES	4096
+
+#define FFLP_VLAN_PAR_ERR		(FZC_FFLP + 0x0800UL)
+#define  FFLP_VLAN_PAR_ERR_ERR		0x0000000080000000ULL
+#define  FFLP_VLAN_PAR_ERR_M_ERR	0x0000000040000000ULL
+#define  FFLP_VLAN_PAR_ERR_ADDR		0x000000003ffc0000ULL
+#define  FFLP_VLAN_PAR_ERR_DATA		0x000000000003ffffULL
+
+#define L2_CLS(IDX)			(FZC_FFLP + 0x20000UL + (IDX) * 8UL)
+#define  L2_CLS_VLD			0x0000000000010000ULL
+#define  L2_CLS_ETYPE			0x000000000000ffffULL
+#define  L2_CLS_ETYPE_SHIFT		0
+
+#define L3_CLS(IDX)			(FZC_FFLP + 0x20010UL + (IDX) * 8UL)
+#define  L3_CLS_VALID			0x0000000002000000ULL
+#define  L3_CLS_IPVER			0x0000000001000000ULL
+#define  L3_CLS_PID			0x0000000000ff0000ULL
+#define  L3_CLS_PID_SHIFT		16
+#define  L3_CLS_TOSMASK			0x000000000000ff00ULL
+#define  L3_CLS_TOSMASK_SHIFT		8
+#define  L3_CLS_TOS			0x00000000000000ffULL
+#define  L3_CLS_TOS_SHIFT		0
+
+#define TCAM_KEY(IDX)			(FZC_FFLP + 0x20030UL + (IDX) * 8UL)
+#define  TCAM_KEY_DISC			0x0000000000000008ULL
+#define  TCAM_KEY_TSEL			0x0000000000000004ULL
+#define  TCAM_KEY_IPADDR		0x0000000000000001ULL
+
+#define TCAM_KEY_0			(FZC_FFLP + 0x20090UL)
+#define  TCAM_KEY_0_KEY			0x00000000000000ffULL /* bits 192-199 */
+
+#define TCAM_KEY_1			(FZC_FFLP + 0x20098UL)
+#define  TCAM_KEY_1_KEY			0xffffffffffffffffULL /* bits 128-191 */
+
+#define TCAM_KEY_2			(FZC_FFLP + 0x200a0UL)
+#define  TCAM_KEY_2_KEY			0xffffffffffffffffULL /* bits 64-127 */
+
+#define TCAM_KEY_3			(FZC_FFLP + 0x200a8UL)
+#define  TCAM_KEY_3_KEY			0xffffffffffffffffULL /* bits 0-63 */
+
+#define TCAM_KEY_MASK_0			(FZC_FFLP + 0x200b0UL)
+#define  TCAM_KEY_MASK_0_KEY_SEL	0x00000000000000ffULL /* bits 192-199 */
+
+#define TCAM_KEY_MASK_1			(FZC_FFLP + 0x200b8UL)
+#define  TCAM_KEY_MASK_1_KEY_SEL	0xffffffffffffffffULL /* bits 128-191 */
+
+#define TCAM_KEY_MASK_2			(FZC_FFLP + 0x200c0UL)
+#define  TCAM_KEY_MASK_2_KEY_SEL	0xffffffffffffffffULL /* bits 64-127 */
+
+#define TCAM_KEY_MASK_3			(FZC_FFLP + 0x200c8UL)
+#define  TCAM_KEY_MASK_3_KEY_SEL	0xffffffffffffffffULL /* bits 0-63 */
+
+#define TCAM_CTL			(FZC_FFLP + 0x200d0UL)
+#define  TCAM_CTL_RWC			0x00000000001c0000ULL
+#define  TCAM_CTL_RWC_TCAM_WRITE	0x0000000000000000ULL
+#define  TCAM_CTL_RWC_TCAM_READ		0x0000000000040000ULL
+#define  TCAM_CTL_RWC_TCAM_COMPARE	0x0000000000080000ULL
+#define  TCAM_CTL_RWC_RAM_WRITE		0x0000000000100000ULL
+#define  TCAM_CTL_RWC_RAM_READ		0x0000000000140000ULL
+#define  TCAM_CTL_STAT			0x0000000000020000ULL
+#define  TCAM_CTL_MATCH			0x0000000000010000ULL
+#define  TCAM_CTL_LOC			0x00000000000003ffULL
+
+#define TCAM_ERR			(FZC_FFLP + 0x200d8UL)
+#define  TCAM_ERR_ERR			0x0000000080000000ULL
+#define  TCAM_ERR_P_ECC			0x0000000040000000ULL
+#define  TCAM_ERR_MULT			0x0000000020000000ULL
+#define  TCAM_ERR_ADDR			0x0000000000ff0000ULL
+#define  TCAM_ERR_SYNDROME		0x000000000000ffffULL
+
+#define HASH_LOOKUP_ERR_LOG1		(FZC_FFLP + 0x200e0UL)
+#define  HASH_LOOKUP_ERR_LOG1_ERR	0x0000000000000008ULL
+#define  HASH_LOOKUP_ERR_LOG1_MULT_LK	0x0000000000000004ULL
+#define  HASH_LOOKUP_ERR_LOG1_CU	0x0000000000000002ULL
+#define  HASH_LOOKUP_ERR_LOG1_MULT_BIT	0x0000000000000001ULL
+
+#define HASH_LOOKUP_ERR_LOG2		(FZC_FFLP + 0x200e8UL)
+#define  HASH_LOOKUP_ERR_LOG2_H1	0x000000007ffff800ULL
+#define  HASH_LOOKUP_ERR_LOG2_SUBAREA	0x0000000000000700ULL
+#define  HASH_LOOKUP_ERR_LOG2_SYNDROME	0x00000000000000ffULL
+
+#define FFLP_CFG_1			(FZC_FFLP + 0x20100UL)
+#define  FFLP_CFG_1_TCAM_DIS		0x0000000004000000ULL
+#define  FFLP_CFG_1_PIO_DBG_SEL		0x0000000003800000ULL
+#define  FFLP_CFG_1_PIO_FIO_RST		0x0000000000400000ULL
+#define  FFLP_CFG_1_PIO_FIO_LAT		0x0000000000300000ULL
+#define  FFLP_CFG_1_CAMLAT		0x00000000000f0000ULL
+#define  FFLP_CFG_1_CAMLAT_SHIFT	16
+#define  FFLP_CFG_1_CAMRATIO		0x000000000000f000ULL
+#define  FFLP_CFG_1_CAMRATIO_SHIFT	12
+#define  FFLP_CFG_1_FCRAMRATIO		0x0000000000000f00ULL
+#define  FFLP_CFG_1_FCRAMRATIO_SHIFT	8
+#define  FFLP_CFG_1_FCRAMOUTDR_MASK	0x00000000000000f0ULL
+#define  FFLP_CFG_1_FCRAMOUTDR_NORMAL	0x0000000000000000ULL
+#define  FFLP_CFG_1_FCRAMOUTDR_STRONG	0x0000000000000050ULL
+#define  FFLP_CFG_1_FCRAMOUTDR_WEAK	0x00000000000000a0ULL
+#define  FFLP_CFG_1_FCRAMQS		0x0000000000000008ULL
+#define  FFLP_CFG_1_ERRORDIS		0x0000000000000004ULL
+#define  FFLP_CFG_1_FFLPINITDONE	0x0000000000000002ULL
+#define  FFLP_CFG_1_LLCSNAP		0x0000000000000001ULL
+
+#define DEFAULT_FCRAMRATIO		10
+
+#define DEFAULT_TCAM_LATENCY		4
+#define DEFAULT_TCAM_ACCESS_RATIO	10
+
+#define TCP_CFLAG_MSK			(FZC_FFLP + 0x20108UL)
+#define  TCP_CFLAG_MSK_MASK		0x0000000000000fffULL
+
+#define FCRAM_REF_TMR			(FZC_FFLP + 0x20110UL)
+#define  FCRAM_REF_TMR_MAX		0x00000000ffff0000ULL
+#define  FCRAM_REF_TMR_MAX_SHIFT	16
+#define  FCRAM_REF_TMR_MIN		0x000000000000ffffULL
+#define  FCRAM_REF_TMR_MIN_SHIFT	0
+
+#define DEFAULT_FCRAM_REFRESH_MAX	512
+#define DEFAULT_FCRAM_REFRESH_MIN	512
+
+#define FCRAM_FIO_ADDR			(FZC_FFLP + 0x20118UL)
+#define  FCRAM_FIO_ADDR_ADDR		0x00000000000000ffULL
+
+#define FCRAM_FIO_DAT			(FZC_FFLP + 0x20120UL)
+#define  FCRAM_FIO_DAT_DATA		0x000000000000ffffULL
+
+#define FCRAM_ERR_TST0			(FZC_FFLP + 0x20128UL)
+#define  FCRAM_ERR_TST0_SYND		0x00000000000000ffULL
+
+#define FCRAM_ERR_TST1			(FZC_FFLP + 0x20130UL)
+#define  FCRAM_ERR_TST1_DAT		0x00000000ffffffffULL
+
+#define FCRAM_ERR_TST2			(FZC_FFLP + 0x20138UL)
+#define  FCRAM_ERR_TST2_DAT		0x00000000ffffffffULL
+
+#define FFLP_ERR_MASK			(FZC_FFLP + 0x20140UL)
+#define  FFLP_ERR_MASK_HSH_TBL_DAT	0x00000000000007f8ULL
+#define  FFLP_ERR_MASK_HSH_TBL_LKUP	0x0000000000000004ULL
+#define  FFLP_ERR_MASK_TCAM		0x0000000000000002ULL
+#define  FFLP_ERR_MASK_VLAN		0x0000000000000001ULL
+
+#define FFLP_DBG_TRAIN_VCT		(FZC_FFLP + 0x20148UL)
+#define  FFLP_DBG_TRAIN_VCT_VECTOR	0x00000000ffffffffULL
+
+#define FCRAM_PHY_RD_LAT		(FZC_FFLP + 0x20150UL)
+#define  FCRAM_PHY_RD_LAT_LAT		0x00000000000000ffULL
+
+/* Ethernet TCAM format */
+#define TCAM_ETHKEY0_RESV1		0xffffffffffffff00ULL
+#define TCAM_ETHKEY0_CLASS_CODE		0x00000000000000f8ULL
+#define TCAM_ETHKEY0_CLASS_CODE_SHIFT	3
+#define TCAM_ETHKEY0_RESV2		0x0000000000000007ULL
+#define TCAM_ETHKEY1_FRAME_BYTE0_7(NUM)	(0xff << ((7 - NUM) * 8))
+#define TCAM_ETHKEY2_FRAME_BYTE8	0xff00000000000000ULL
+#define TCAM_ETHKEY2_FRAME_BYTE8_SHIFT	56
+#define TCAM_ETHKEY2_FRAME_BYTE9	0x00ff000000000000ULL
+#define TCAM_ETHKEY2_FRAME_BYTE9_SHIFT	48
+#define TCAM_ETHKEY2_FRAME_BYTE10	0x0000ff0000000000ULL
+#define TCAM_ETHKEY2_FRAME_BYTE10_SHIFT	40
+#define TCAM_ETHKEY2_FRAME_RESV		0x000000ffffffffffULL
+#define TCAM_ETHKEY3_FRAME_RESV		0xffffffffffffffffULL
+
+/* IPV4 TCAM format */
+#define TCAM_V4KEY0_RESV1		0xffffffffffffff00ULL
+#define TCAM_V4KEY0_CLASS_CODE		0x00000000000000f8ULL
+#define TCAM_V4KEY0_CLASS_CODE_SHIFT	3
+#define TCAM_V4KEY0_RESV2		0x0000000000000007ULL
+#define TCAM_V4KEY1_L2RDCNUM		0xf800000000000000ULL
+#define TCAM_V4KEY1_L2RDCNUM_SHIFT	59
+#define TCAM_V4KEY1_NOPORT		0x0400000000000000ULL
+#define TCAM_V4KEY1_RESV		0x03ffffffffffffffULL
+#define TCAM_V4KEY2_RESV		0xffff000000000000ULL
+#define TCAM_V4KEY2_TOS			0x0000ff0000000000ULL
+#define TCAM_V4KEY2_TOS_SHIFT		40
+#define TCAM_V4KEY2_PROTO		0x000000ff00000000ULL
+#define TCAM_V4KEY2_PROTO_SHIFT		32
+#define TCAM_V4KEY2_PORT_SPI		0x00000000ffffffffULL
+#define TCAM_V4KEY2_PORT_SPI_SHIFT	0
+#define TCAM_V4KEY3_SADDR		0xffffffff00000000ULL
+#define TCAM_V4KEY3_SADDR_SHIFT		32
+#define TCAM_V4KEY3_DADDR		0x00000000ffffffffULL
+#define TCAM_V4KEY3_DADDR_SHIFT		0
+
+/* IPV6 TCAM format */
+#define TCAM_V6KEY0_RESV1		0xffffffffffffff00ULL
+#define TCAM_V6KEY0_CLASS_CODE		0x00000000000000f8ULL
+#define TCAM_V6KEY0_CLASS_CODE_SHIFT	3
+#define TCAM_V6KEY0_RESV2		0x0000000000000007ULL
+#define TCAM_V6KEY1_L2RDCNUM		0xf800000000000000ULL
+#define TCAM_V6KEY1_L2RDCNUM_SHIFT	59
+#define TCAM_V6KEY1_NOPORT		0x0400000000000000ULL
+#define TCAM_V6KEY1_RESV		0x03ff000000000000ULL
+#define TCAM_V6KEY1_TOS			0x0000ff0000000000ULL
+#define TCAM_V6KEY1_TOS_SHIFT		40
+#define TCAM_V6KEY1_NEXT_HDR		0x000000ff00000000ULL
+#define TCAM_V6KEY1_NEXT_HDR_SHIFT	32
+#define TCAM_V6KEY1_PORT_SPI		0x00000000ffffffffULL
+#define TCAM_V6KEY1_PORT_SPI_SHIFT	0
+#define TCAM_V6KEY2_ADDR_HIGH		0xffffffffffffffffULL
+#define TCAM_V6KEY3_ADDR_LOW		0xffffffffffffffffULL
+
+#define TCAM_ASSOCDATA_SYNDROME		0x000003fffc000000ULL
+#define TCAM_ASSOCDATA_SYNDROME_SHIFT	26
+#define TCAM_ASSOCDATA_ZFID		0x0000000003ffc000ULL
+#define TCAM_ASSOCDATA_ZFID_SHIFT	14
+#define TCAM_ASSOCDATA_V4_ECC_OK	0x0000000000002000ULL
+#define TCAM_ASSOCDATA_DISC		0x0000000000001000ULL
+#define TCAM_ASSOCDATA_TRES_MASK	0x0000000000000c00ULL
+#define TCAM_ASSOCDATA_TRES_USE_L2RDC	0x0000000000000000ULL
+#define TCAM_ASSOCDATA_TRES_USE_OFFSET	0x0000000000000400ULL
+#define TCAM_ASSOCDATA_TRES_OVR_RDC	0x0000000000000800ULL
+#define TCAM_ASSOCDATA_TRES_OVR_RDC_OFF	0x0000000000000c00ULL
+#define TCAM_ASSOCDATA_RDCTBL		0x0000000000000380ULL
+#define TCAM_ASSOCDATA_RDCTBL_SHIFT	7
+#define TCAM_ASSOCDATA_OFFSET		0x000000000000007cULL
+#define TCAM_ASSOCDATA_OFFSET_SHIFT	2
+#define TCAM_ASSOCDATA_ZFVLD		0x0000000000000002ULL
+#define TCAM_ASSOCDATA_AGE		0x0000000000000001ULL
+
+#define FLOW_KEY(IDX)			(FZC_FFLP + 0x40000UL + (IDX) * 8UL)
+#define  FLOW_KEY_PORT			0x0000000000000200ULL
+#define  FLOW_KEY_L2DA			0x0000000000000100ULL
+#define  FLOW_KEY_VLAN			0x0000000000000080ULL
+#define  FLOW_KEY_IPSA			0x0000000000000040ULL
+#define  FLOW_KEY_IPDA			0x0000000000000020ULL
+#define  FLOW_KEY_PROTO			0x0000000000000010ULL
+#define  FLOW_KEY_L4_0			0x000000000000000cULL
+#define  FLOW_KEY_L4_0_SHIFT		2
+#define  FLOW_KEY_L4_1			0x0000000000000003ULL
+#define  FLOW_KEY_L4_1_SHIFT		0
+
+#define  FLOW_KEY_L4_NONE		0x0
+#define  FLOW_KEY_L4_RESV		0x1
+#define  FLOW_KEY_L4_BYTE12		0x2
+#define  FLOW_KEY_L4_BYTE56		0x3
+
+#define H1POLY				(FZC_FFLP + 0x40060UL)
+#define  H1POLY_INITVAL			0x00000000ffffffffULL
+
+#define H2POLY				(FZC_FFLP + 0x40068UL)
+#define  H2POLY_INITVAL			0x000000000000ffffULL
+
+#define FLW_PRT_SEL(IDX)		(FZC_FFLP + 0x40070UL + (IDX) * 8UL)
+#define  FLW_PRT_SEL_EXT		0x0000000000010000ULL
+#define  FLW_PRT_SEL_MASK		0x0000000000001f00ULL
+#define  FLW_PRT_SEL_MASK_SHIFT		8
+#define  FLW_PRT_SEL_BASE		0x000000000000001fULL
+#define  FLW_PRT_SEL_BASE_SHIFT		0
+
+#define HASH_TBL_ADDR(IDX)		(FFLP + 0x00000UL + (IDX) * 8192UL)
+#define  HASH_TBL_ADDR_AUTOINC		0x0000000000800000ULL
+#define  HASH_TBL_ADDR_ADDR		0x00000000007fffffULL
+
+#define HASH_TBL_DATA(IDX)		(FFLP + 0x00008UL + (IDX) * 8192UL)
+#define  HASH_TBL_DATA_DATA		0xffffffffffffffffULL
+
+/* FCRAM hash table entries are up to 8 64-bit words in size.
+ * The layout of each entry is determined by the settings in the
+ * first word, which is the header.
+ *
+ * The indexing is controllable per partition (there is one partition
+ * per RDC group, thus a total of eight) using the BASE and MASK fields
+ * of FLW_PRT_SEL above.
+ */
+#define FCRAM_SIZE			0x800000
+#define FCRAM_NUM_PARTITIONS		8
+
+/* Generic HASH entry header, used for all non-optimized formats.  */
+#define HASH_HEADER_FMT			0x8000000000000000ULL
+#define HASH_HEADER_EXT			0x4000000000000000ULL
+#define HASH_HEADER_VALID		0x2000000000000000ULL
+#define HASH_HEADER_RESVD		0x1000000000000000ULL
+#define HASH_HEADER_L2_DADDR		0x0ffffffffffff000ULL
+#define HASH_HEADER_L2_DADDR_SHIFT	12
+#define HASH_HEADER_VLAN		0x0000000000000fffULL
+#define HASH_HEADER_VLAN_SHIFT		0
+
+/* Optimized format, just a header with a special layout defined below.
+ * Set FMT and EXT both to zero to indicate this layout is being used.
+ */
+#define HASH_OPT_HEADER_FMT		0x8000000000000000ULL
+#define HASH_OPT_HEADER_EXT		0x4000000000000000ULL
+#define HASH_OPT_HEADER_VALID		0x2000000000000000ULL
+#define HASH_OPT_HEADER_RDCOFF		0x1f00000000000000ULL
+#define HASH_OPT_HEADER_RDCOFF_SHIFT	56
+#define HASH_OPT_HEADER_HASH2		0x00ffff0000000000ULL
+#define HASH_OPT_HEADER_HASH2_SHIFT	40
+#define HASH_OPT_HEADER_RESVD		0x000000ff00000000ULL
+#define HASH_OPT_HEADER_USERINFO	0x00000000ffffffffULL
+#define HASH_OPT_HEADER_USERINFO_SHIFT	0
+
+/* Port and protocol word used for ipv4 and ipv6 layouts.  */
+#define HASH_PORT_DPORT			0xffff000000000000ULL
+#define HASH_PORT_DPORT_SHIFT		48
+#define HASH_PORT_SPORT			0x0000ffff00000000ULL
+#define HASH_PORT_SPORT_SHIFT		32
+#define HASH_PORT_PROTO			0x00000000ff000000ULL
+#define HASH_PORT_PROTO_SHIFT		24
+#define HASH_PORT_PORT_OFF		0x0000000000c00000ULL
+#define HASH_PORT_PORT_OFF_SHIFT	22
+#define HASH_PORT_PORT_RESV		0x00000000003fffffULL
+
+/* Action word used for ipv4 and ipv6 layouts.  */
+#define HASH_ACTION_RESV1		0xe000000000000000ULL
+#define HASH_ACTION_RDCOFF		0x1f00000000000000ULL
+#define HASH_ACTION_RDCOFF_SHIFT	56
+#define HASH_ACTION_ZFVALID		0x0080000000000000ULL
+#define HASH_ACTION_RESV2		0x0070000000000000ULL
+#define HASH_ACTION_ZFID		0x000fff0000000000ULL
+#define HASH_ACTION_ZFID_SHIFT		40
+#define HASH_ACTION_RESV3		0x000000ff00000000ULL
+#define HASH_ACTION_USERINFO		0x00000000ffffffffULL
+#define HASH_ACTION_USERINFO_SHIFT	0
+
+/* IPV4 address word.  Addresses are in network endian. */
+#define HASH_IP4ADDR_SADDR		0xffffffff00000000ULL
+#define HASH_IP4ADDR_SADDR_SHIFT	32
+#define HASH_IP4ADDR_DADDR		0x00000000ffffffffULL
+#define HASH_IP4ADDR_DADDR_SHIFT	0
+
+/* IPV6 address layout is 4 words, first two are saddr, next two
+ * are daddr.  Addresses are in network endian.
+ */
+
+struct fcram_hash_opt {
+	u64	header;
+};
+
+/* EXT=1, FMT=0 */
+struct fcram_hash_ipv4 {
+	u64	header;
+	u64	addrs;
+	u64	ports;
+	u64	action;
+};
+
+/* EXT=1, FMT=1 */
+struct fcram_hash_ipv6 {
+	u64	header;
+	u64	addrs[4];
+	u64	ports;
+	u64	action;
+};
+
+#define HASH_TBL_DATA_LOG(IDX)		(FFLP + 0x00010UL + (IDX) * 8192UL)
+#define  HASH_TBL_DATA_LOG_ERR		0x0000000080000000ULL
+#define  HASH_TBL_DATA_LOG_ADDR		0x000000007fffff00ULL
+#define  HASH_TBL_DATA_LOG_SYNDROME	0x00000000000000ffULL
+
+#define RX_DMA_CK_DIV			(FZC_DMC + 0x00000UL)
+#define  RX_DMA_CK_DIV_CNT		0x000000000000ffffULL
+
+#define DEF_RDC(IDX)			(FZC_DMC + 0x00008UL + (IDX) * 0x8UL)
+#define  DEF_RDC_VAL			0x000000000000001fULL
+
+#define PT_DRR_WT(IDX)			(FZC_DMC + 0x00028UL + (IDX) * 0x8UL)
+#define  PT_DRR_WT_VAL			0x000000000000ffffULL
+
+#define PT_DRR_WEIGHT_DEFAULT_10G	0x0400
+#define PT_DRR_WEIGHT_DEFAULT_1G	0x0066
+
+#define PT_USE(IDX)			(FZC_DMC + 0x00048UL + (IDX) * 0x8UL)
+#define  PT_USE_CNT			0x00000000000fffffULL
+
+#define RED_RAN_INIT			(FZC_DMC + 0x00068UL)
+#define  RED_RAN_INIT_OPMODE		0x0000000000010000ULL
+#define  RED_RAN_INIT_VAL		0x000000000000ffffULL
+
+#define RX_ADDR_MD			(FZC_DMC + 0x00070UL)
+#define  RX_ADDR_MD_DBG_PT_MUX_SEL	0x000000000000000cULL
+#define  RX_ADDR_MD_RAM_ACC		0x0000000000000002ULL
+#define  RX_ADDR_MD_MODE32		0x0000000000000001ULL
+
+#define RDMC_PRE_PAR_ERR		(FZC_DMC + 0x00078UL)
+#define  RDMC_PRE_PAR_ERR_ERR		0x0000000000008000ULL
+#define  RDMC_PRE_PAR_ERR_MERR		0x0000000000004000ULL
+#define  RDMC_PRE_PAR_ERR_ADDR		0x00000000000000ffULL
+
+#define RDMC_SHA_PAR_ERR		(FZC_DMC + 0x00080UL)
+#define  RDMC_SHA_PAR_ERR_ERR		0x0000000000008000ULL
+#define  RDMC_SHA_PAR_ERR_MERR		0x0000000000004000ULL
+#define  RDMC_SHA_PAR_ERR_ADDR		0x00000000000000ffULL
+
+#define RDMC_MEM_ADDR			(FZC_DMC + 0x00088UL)
+#define  RDMC_MEM_ADDR_PRE_SHAD		0x0000000000000100ULL
+#define  RDMC_MEM_ADDR_ADDR		0x00000000000000ffULL
+
+#define RDMC_MEM_DAT0			(FZC_DMC + 0x00090UL)
+#define  RDMC_MEM_DAT0_DATA		0x00000000ffffffffULL /* bits 31:0 */
+
+#define RDMC_MEM_DAT1			(FZC_DMC + 0x00098UL)
+#define  RDMC_MEM_DAT1_DATA		0x00000000ffffffffULL /* bits 63:32 */
+
+#define RDMC_MEM_DAT2			(FZC_DMC + 0x000a0UL)
+#define  RDMC_MEM_DAT2_DATA		0x00000000ffffffffULL /* bits 95:64 */
+
+#define RDMC_MEM_DAT3			(FZC_DMC + 0x000a8UL)
+#define  RDMC_MEM_DAT3_DATA		0x00000000ffffffffULL /* bits 127:96 */
+
+#define RDMC_MEM_DAT4			(FZC_DMC + 0x000b0UL)
+#define  RDMC_MEM_DAT4_DATA		0x00000000000fffffULL /* bits 147:128 */
+
+#define RX_CTL_DAT_FIFO_STAT			(FZC_DMC + 0x000b8UL)
+#define  RX_CTL_DAT_FIFO_STAT_ID_MISMATCH	0x0000000000000100ULL
+#define  RX_CTL_DAT_FIFO_STAT_ZCP_EOP_ERR	0x00000000000000f0ULL
+#define  RX_CTL_DAT_FIFO_STAT_IPP_EOP_ERR	0x000000000000000fULL
+
+#define RX_CTL_DAT_FIFO_MASK			(FZC_DMC + 0x000c0UL)
+#define  RX_CTL_DAT_FIFO_MASK_ID_MISMATCH	0x0000000000000100ULL
+#define  RX_CTL_DAT_FIFO_MASK_ZCP_EOP_ERR	0x00000000000000f0ULL
+#define  RX_CTL_DAT_FIFO_MASK_IPP_EOP_ERR	0x000000000000000fULL
+
+#define RDMC_TRAINING_VECTOR			(FZC_DMC + 0x000c8UL)
+#define  RDMC_TRAINING_VECTOR_TRAINING_VECTOR	0x00000000ffffffffULL
+
+#define RX_CTL_DAT_FIFO_STAT_DBG		(FZC_DMC + 0x000d0UL)
+#define  RX_CTL_DAT_FIFO_STAT_DBG_ID_MISMATCH	0x0000000000000100ULL
+#define  RX_CTL_DAT_FIFO_STAT_DBG_ZCP_EOP_ERR	0x00000000000000f0ULL
+#define  RX_CTL_DAT_FIFO_STAT_DBG_IPP_EOP_ERR	0x000000000000000fULL
+
+#define RDC_TBL(TBL,SLOT)		(FZC_ZCP + 0x10000UL + \
+					 (TBL) * (8UL * 16UL) + \
+					 (SLOT) * 8UL)
+#define  RDC_TBL_RDC			0x000000000000000fULL
+
+#define RX_LOG_PAGE_VLD(IDX)		(FZC_DMC + 0x20000UL + (IDX) * 0x40UL)
+#define  RX_LOG_PAGE_VLD_FUNC		0x000000000000000cULL
+#define  RX_LOG_PAGE_VLD_FUNC_SHIFT	2
+#define  RX_LOG_PAGE_VLD_PAGE1		0x0000000000000002ULL
+#define  RX_LOG_PAGE_VLD_PAGE0		0x0000000000000001ULL
+
+#define RX_LOG_MASK1(IDX)		(FZC_DMC + 0x20008UL + (IDX) * 0x40UL)
+#define  RX_LOG_MASK1_MASK		0x00000000ffffffffULL
+
+#define RX_LOG_VAL1(IDX)		(FZC_DMC + 0x20010UL + (IDX) * 0x40UL)
+#define  RX_LOG_VAL1_VALUE		0x00000000ffffffffULL
+
+#define RX_LOG_MASK2(IDX)		(FZC_DMC + 0x20018UL + (IDX) * 0x40UL)
+#define  RX_LOG_MASK2_MASK		0x00000000ffffffffULL
+
+#define RX_LOG_VAL2(IDX)		(FZC_DMC + 0x20020UL + (IDX) * 0x40UL)
+#define  RX_LOG_VAL2_VALUE		0x00000000ffffffffULL
+
+#define RX_LOG_PAGE_RELO1(IDX)		(FZC_DMC + 0x20028UL + (IDX) * 0x40UL)
+#define  RX_LOG_PAGE_RELO1_RELO		0x00000000ffffffffULL
+
+#define RX_LOG_PAGE_RELO2(IDX)		(FZC_DMC + 0x20030UL + (IDX) * 0x40UL)
+#define  RX_LOG_PAGE_RELO2_RELO		0x00000000ffffffffULL
+
+#define RX_LOG_PAGE_HDL(IDX)		(FZC_DMC + 0x20038UL + (IDX) * 0x40UL)
+#define  RX_LOG_PAGE_HDL_HANDLE		0x00000000000fffffULL
+
+#define TX_LOG_PAGE_VLD(IDX)		(FZC_DMC + 0x40000UL + (IDX) * 0x200UL)
+#define  TX_LOG_PAGE_VLD_FUNC		0x000000000000000cULL
+#define  TX_LOG_PAGE_VLD_FUNC_SHIFT	2
+#define  TX_LOG_PAGE_VLD_PAGE1		0x0000000000000002ULL
+#define  TX_LOG_PAGE_VLD_PAGE0		0x0000000000000001ULL
+
+#define TX_LOG_MASK1(IDX)		(FZC_DMC + 0x40008UL + (IDX) * 0x200UL)
+#define  TX_LOG_MASK1_MASK		0x00000000ffffffffULL
+
+#define TX_LOG_VAL1(IDX)		(FZC_DMC + 0x40010UL + (IDX) * 0x200UL)
+#define  TX_LOG_VAL1_VALUE		0x00000000ffffffffULL
+
+#define TX_LOG_MASK2(IDX)		(FZC_DMC + 0x40018UL + (IDX) * 0x200UL)
+#define  TX_LOG_MASK2_MASK		0x00000000ffffffffULL
+
+#define TX_LOG_VAL2(IDX)		(FZC_DMC + 0x40020UL + (IDX) * 0x200UL)
+#define  TX_LOG_VAL2_VALUE		0x00000000ffffffffULL
+
+#define TX_LOG_PAGE_RELO1(IDX)		(FZC_DMC + 0x40028UL + (IDX) * 0x200UL)
+#define  TX_LOG_PAGE_RELO1_RELO		0x00000000ffffffffULL
+
+#define TX_LOG_PAGE_RELO2(IDX)		(FZC_DMC + 0x40030UL + (IDX) * 0x200UL)
+#define  TX_LOG_PAGE_RELO2_RELO		0x00000000ffffffffULL
+
+#define TX_LOG_PAGE_HDL(IDX)		(FZC_DMC + 0x40038UL + (IDX) * 0x200UL)
+#define  TX_LOG_PAGE_HDL_HANDLE		0x00000000000fffffULL
+
+#define TX_ADDR_MD			(FZC_DMC + 0x45000UL)
+#define  TX_ADDR_MD_MODE32		0x0000000000000001ULL
+
+#define RDC_RED_PARA(IDX)		(FZC_DMC + 0x30000UL + (IDX) * 0x40UL)
+#define  RDC_RED_PARA_THRE_SYN		0x00000000fff00000ULL
+#define  RDC_RED_PARA_THRE_SYN_SHIFT	20
+#define  RDC_RED_PARA_WIN_SYN		0x00000000000f0000ULL
+#define  RDC_RED_PARA_WIN_SYN_SHIFT	16
+#define  RDC_RED_PARA_THRE		0x000000000000fff0ULL
+#define  RDC_RED_PARA_THRE_SHIFT	4
+#define  RDC_RED_PARA_WIN		0x000000000000000fULL
+#define  RDC_RED_PARA_WIN_SHIFT		0
+
+#define RED_DIS_CNT(IDX)		(FZC_DMC + 0x30008UL + (IDX) * 0x40UL)
+#define  RED_DIS_CNT_OFLOW		0x0000000000010000ULL
+#define  RED_DIS_CNT_COUNT		0x000000000000ffffULL
+
+#define IPP_CFIG			(FZC_IPP + 0x00000UL)
+#define  IPP_CFIG_SOFT_RST		0x0000000080000000ULL
+#define  IPP_CFIG_IP_MAX_PKT		0x0000000001ffff00ULL
+#define  IPP_CFIG_IP_MAX_PKT_SHIFT	8
+#define  IPP_CFIG_FFLP_CS_PIO_W		0x0000000000000080ULL
+#define  IPP_CFIG_PFIFO_PIO_W		0x0000000000000040ULL
+#define  IPP_CFIG_DFIFO_PIO_W		0x0000000000000020ULL
+#define  IPP_CFIG_CKSUM_EN		0x0000000000000010ULL
+#define  IPP_CFIG_DROP_BAD_CRC		0x0000000000000008ULL
+#define  IPP_CFIG_DFIFO_ECC_EN		0x0000000000000004ULL
+#define  IPP_CFIG_DEBUG_BUS_OUT_EN	0x0000000000000002ULL
+#define  IPP_CFIG_IPP_ENABLE		0x0000000000000001ULL
+
+#define IPP_PKT_DIS			(FZC_IPP + 0x00020UL)
+#define  IPP_PKT_DIS_COUNT		0x0000000000003fffULL
+
+#define IPP_BAD_CS_CNT			(FZC_IPP + 0x00028UL)
+#define  IPP_BAD_CS_CNT_COUNT		0x0000000000003fffULL
+
+#define IPP_ECC				(FZC_IPP + 0x00030UL)
+#define  IPP_ECC_COUNT			0x00000000000000ffULL
+
+#define IPP_INT_STAT			(FZC_IPP + 0x00040UL)
+#define  IPP_INT_STAT_SOP_MISS		0x0000000080000000ULL
+#define  IPP_INT_STAT_EOP_MISS		0x0000000040000000ULL
+#define  IPP_INT_STAT_DFIFO_UE		0x0000000030000000ULL
+#define  IPP_INT_STAT_DFIFO_CE		0x000000000c000000ULL
+#define  IPP_INT_STAT_DFIFO_ECC		0x0000000003000000ULL
+#define  IPP_INT_STAT_DFIFO_ECC_IDX	0x00000000007ff000ULL
+#define  IPP_INT_STAT_PFIFO_PERR	0x0000000000000800ULL
+#define  IPP_INT_STAT_ECC_ERR_MAX	0x0000000000000400ULL
+#define  IPP_INT_STAT_PFIFO_ERR_IDX	0x00000000000003f0ULL
+#define  IPP_INT_STAT_PFIFO_OVER	0x0000000000000008ULL
+#define  IPP_INT_STAT_PFIFO_UND		0x0000000000000004ULL
+#define  IPP_INT_STAT_BAD_CS_MX		0x0000000000000002ULL
+#define  IPP_INT_STAT_PKT_DIS_MX	0x0000000000000001ULL
+#define  IPP_INT_STAT_ALL		0x00000000ff7fffffULL
+
+#define IPP_MSK				(FZC_IPP + 0x00048UL)
+#define  IPP_MSK_ECC_ERR_MX		0x0000000000000080ULL
+#define  IPP_MSK_DFIFO_EOP_SOP		0x0000000000000040ULL
+#define  IPP_MSK_DFIFO_UC		0x0000000000000020ULL
+#define  IPP_MSK_PFIFO_PAR		0x0000000000000010ULL
+#define  IPP_MSK_PFIFO_OVER		0x0000000000000008ULL
+#define  IPP_MSK_PFIFO_UND		0x0000000000000004ULL
+#define  IPP_MSK_BAD_CS			0x0000000000000002ULL
+#define  IPP_MSK_PKT_DIS_CNT		0x0000000000000001ULL
+#define  IPP_MSK_ALL			0x00000000000000ffULL
+
+#define IPP_PFIFO_RD0			(FZC_IPP + 0x00060UL)
+#define  IPP_PFIFO_RD0_DATA		0x00000000ffffffffULL /* bits 31:0 */
+
+#define IPP_PFIFO_RD1			(FZC_IPP + 0x00068UL)
+#define  IPP_PFIFO_RD1_DATA		0x00000000ffffffffULL /* bits 63:32 */
+
+#define IPP_PFIFO_RD2			(FZC_IPP + 0x00070UL)
+#define  IPP_PFIFO_RD2_DATA		0x00000000ffffffffULL /* bits 95:64 */
+
+#define IPP_PFIFO_RD3			(FZC_IPP + 0x00078UL)
+#define  IPP_PFIFO_RD3_DATA		0x00000000ffffffffULL /* bits 127:96 */
+
+#define IPP_PFIFO_RD4			(FZC_IPP + 0x00080UL)
+#define  IPP_PFIFO_RD4_DATA		0x00000000ffffffffULL /* bits 145:128 */
+
+#define IPP_PFIFO_WR0			(FZC_IPP + 0x00088UL)
+#define  IPP_PFIFO_WR0_DATA		0x00000000ffffffffULL /* bits 31:0 */
+
+#define IPP_PFIFO_WR1			(FZC_IPP + 0x00090UL)
+#define  IPP_PFIFO_WR1_DATA		0x00000000ffffffffULL /* bits 63:32 */
+
+#define IPP_PFIFO_WR2			(FZC_IPP + 0x00098UL)
+#define  IPP_PFIFO_WR2_DATA		0x00000000ffffffffULL /* bits 95:64 */
+
+#define IPP_PFIFO_WR3			(FZC_IPP + 0x000a0UL)
+#define  IPP_PFIFO_WR3_DATA		0x00000000ffffffffULL /* bits 127:96 */
+
+#define IPP_PFIFO_WR4			(FZC_IPP + 0x000a8UL)
+#define  IPP_PFIFO_WR4_DATA		0x00000000ffffffffULL /* bits 145:128 */
+
+#define IPP_PFIFO_RD_PTR		(FZC_IPP + 0x000b0UL)
+#define  IPP_PFIFO_RD_PTR_PTR		0x000000000000003fULL
+
+#define IPP_PFIFO_WR_PTR		(FZC_IPP + 0x000b8UL)
+#define  IPP_PFIFO_WR_PTR_PTR		0x000000000000007fULL
+
+#define IPP_DFIFO_RD0			(FZC_IPP + 0x000c0UL)
+#define  IPP_DFIFO_RD0_DATA		0x00000000ffffffffULL /* bits 31:0 */
+
+#define IPP_DFIFO_RD1			(FZC_IPP + 0x000c8UL)
+#define  IPP_DFIFO_RD1_DATA		0x00000000ffffffffULL /* bits 63:32 */
+
+#define IPP_DFIFO_RD2			(FZC_IPP + 0x000d0UL)
+#define  IPP_DFIFO_RD2_DATA		0x00000000ffffffffULL /* bits 95:64 */
+
+#define IPP_DFIFO_RD3			(FZC_IPP + 0x000d8UL)
+#define  IPP_DFIFO_RD3_DATA		0x00000000ffffffffULL /* bits 127:96 */
+
+#define IPP_DFIFO_RD4			(FZC_IPP + 0x000e0UL)
+#define  IPP_DFIFO_RD4_DATA		0x00000000ffffffffULL /* bits 145:128 */
+
+#define IPP_DFIFO_WR0			(FZC_IPP + 0x000e8UL)
+#define  IPP_DFIFO_WR0_DATA		0x00000000ffffffffULL /* bits 31:0 */
+
+#define IPP_DFIFO_WR1			(FZC_IPP + 0x000f0UL)
+#define  IPP_DFIFO_WR1_DATA		0x00000000ffffffffULL /* bits 63:32 */
+
+#define IPP_DFIFO_WR2			(FZC_IPP + 0x000f8UL)
+#define  IPP_DFIFO_WR2_DATA		0x00000000ffffffffULL /* bits 95:64 */
+
+#define IPP_DFIFO_WR3			(FZC_IPP + 0x00100UL)
+#define  IPP_DFIFO_WR3_DATA		0x00000000ffffffffULL /* bits 127:96 */
+
+#define IPP_DFIFO_WR4			(FZC_IPP + 0x00108UL)
+#define  IPP_DFIFO_WR4_DATA		0x00000000ffffffffULL /* bits 145:128 */
+
+#define IPP_DFIFO_RD_PTR		(FZC_IPP + 0x00110UL)
+#define  IPP_DFIFO_RD_PTR_PTR		0x0000000000000fffULL
+
+#define IPP_DFIFO_WR_PTR		(FZC_IPP + 0x00118UL)
+#define  IPP_DFIFO_WR_PTR_PTR		0x0000000000000fffULL
+
+#define IPP_SM				(FZC_IPP + 0x00120UL)
+#define  IPP_SM_SM			0x00000000ffffffffULL
+
+#define IPP_CS_STAT			(FZC_IPP + 0x00128UL)
+#define  IPP_CS_STAT_BCYC_CNT		0x00000000ff000000ULL
+#define  IPP_CS_STAT_IP_LEN		0x0000000000fff000ULL
+#define  IPP_CS_STAT_CS_FAIL		0x0000000000000800ULL
+#define  IPP_CS_STAT_TERM		0x0000000000000400ULL
+#define  IPP_CS_STAT_BAD_NUM		0x0000000000000200ULL
+#define  IPP_CS_STAT_CS_STATE		0x00000000000001ffULL
+
+#define IPP_FFLP_CS_INFO		(FZC_IPP + 0x00130UL)
+#define  IPP_FFLP_CS_INFO_PKT_ID	0x0000000000003c00ULL
+#define  IPP_FFLP_CS_INFO_L4_PROTO	0x0000000000000300ULL
+#define  IPP_FFLP_CS_INFO_V4_HD_LEN	0x00000000000000f0ULL
+#define  IPP_FFLP_CS_INFO_L3_VER	0x000000000000000cULL
+#define  IPP_FFLP_CS_INFO_L2_OP		0x0000000000000003ULL
+
+#define IPP_DBG_SEL			(FZC_IPP + 0x00138UL)
+#define  IPP_DBG_SEL_SEL		0x000000000000000fULL
+
+#define IPP_DFIFO_ECC_SYND		(FZC_IPP + 0x00140UL)
+#define  IPP_DFIFO_ECC_SYND_SYND	0x000000000000ffffULL
+
+#define IPP_DFIFO_EOP_RD_PTR		(FZC_IPP + 0x00148UL)
+#define  IPP_DFIFO_EOP_RD_PTR_PTR	0x0000000000000fffULL
+
+#define IPP_ECC_CTL			(FZC_IPP + 0x00150UL)
+#define  IPP_ECC_CTL_DIS_DBL		0x0000000080000000ULL
+#define  IPP_ECC_CTL_COR_DBL		0x0000000000020000ULL
+#define  IPP_ECC_CTL_COR_SNG		0x0000000000010000ULL
+#define  IPP_ECC_CTL_COR_ALL		0x0000000000000400ULL
+#define  IPP_ECC_CTL_COR_1		0x0000000000000100ULL
+#define  IPP_ECC_CTL_COR_LST		0x0000000000000004ULL
+#define  IPP_ECC_CTL_COR_SND		0x0000000000000002ULL
+#define  IPP_ECC_CTL_COR_FSR		0x0000000000000001ULL
+
+#define NIU_DFIFO_ENTRIES		1024
+#define ATLAS_P0_P1_DFIFO_ENTRIES	2048
+#define ATLAS_P2_P3_DFIFO_ENTRIES	1024
+
+#define ZCP_CFIG			(FZC_ZCP + 0x00000UL)
+#define  ZCP_CFIG_ZCP_32BIT_MODE	0x0000000001000000ULL
+#define  ZCP_CFIG_ZCP_DEBUG_SEL		0x0000000000ff0000ULL
+#define  ZCP_CFIG_DMA_TH		0x000000000000ffe0ULL
+#define  ZCP_CFIG_ECC_CHK_DIS		0x0000000000000010ULL
+#define  ZCP_CFIG_PAR_CHK_DIS		0x0000000000000008ULL
+#define  ZCP_CFIG_DIS_BUFF_RSP_IF	0x0000000000000004ULL
+#define  ZCP_CFIG_DIS_BUFF_REQ_IF	0x0000000000000002ULL
+#define  ZCP_CFIG_ZC_ENABLE		0x0000000000000001ULL
+
+#define ZCP_INT_STAT			(FZC_ZCP + 0x00008UL)
+#define  ZCP_INT_STAT_RRFIFO_UNDERRUN	0x0000000000008000ULL
+#define  ZCP_INT_STAT_RRFIFO_OVERRUN	0x0000000000004000ULL
+#define  ZCP_INT_STAT_RSPFIFO_UNCOR_ERR	0x0000000000001000ULL
+#define  ZCP_INT_STAT_BUFFER_OVERFLOW	0x0000000000000800ULL
+#define  ZCP_INT_STAT_STAT_TBL_PERR	0x0000000000000400ULL
+#define  ZCP_INT_STAT_DYN_TBL_PERR	0x0000000000000200ULL
+#define  ZCP_INT_STAT_BUF_TBL_PERR	0x0000000000000100ULL
+#define  ZCP_INT_STAT_TT_PROGRAM_ERR	0x0000000000000080ULL
+#define  ZCP_INT_STAT_RSP_TT_INDEX_ERR	0x0000000000000040ULL
+#define  ZCP_INT_STAT_SLV_TT_INDEX_ERR	0x0000000000000020ULL
+#define  ZCP_INT_STAT_ZCP_TT_INDEX_ERR	0x0000000000000010ULL
+#define  ZCP_INT_STAT_CFIFO_ECC3	0x0000000000000008ULL
+#define  ZCP_INT_STAT_CFIFO_ECC2	0x0000000000000004ULL
+#define  ZCP_INT_STAT_CFIFO_ECC1	0x0000000000000002ULL
+#define  ZCP_INT_STAT_CFIFO_ECC0	0x0000000000000001ULL
+#define  ZCP_INT_STAT_ALL		0x000000000000ffffULL
+
+#define ZCP_INT_MASK			(FZC_ZCP + 0x00010UL)
+#define  ZCP_INT_MASK_RRFIFO_UNDERRUN	0x0000000000008000ULL
+#define  ZCP_INT_MASK_RRFIFO_OVERRUN	0x0000000000004000ULL
+#define  ZCP_INT_MASK_LOJ		0x0000000000002000ULL
+#define  ZCP_INT_MASK_RSPFIFO_UNCOR_ERR	0x0000000000001000ULL
+#define  ZCP_INT_MASK_BUFFER_OVERFLOW	0x0000000000000800ULL
+#define  ZCP_INT_MASK_STAT_TBL_PERR	0x0000000000000400ULL
+#define  ZCP_INT_MASK_DYN_TBL_PERR	0x0000000000000200ULL
+#define  ZCP_INT_MASK_BUF_TBL_PERR	0x0000000000000100ULL
+#define  ZCP_INT_MASK_TT_PROGRAM_ERR	0x0000000000000080ULL
+#define  ZCP_INT_MASK_RSP_TT_INDEX_ERR	0x0000000000000040ULL
+#define  ZCP_INT_MASK_SLV_TT_INDEX_ERR	0x0000000000000020ULL
+#define  ZCP_INT_MASK_ZCP_TT_INDEX_ERR	0x0000000000000010ULL
+#define  ZCP_INT_MASK_CFIFO_ECC3	0x0000000000000008ULL
+#define  ZCP_INT_MASK_CFIFO_ECC2	0x0000000000000004ULL
+#define  ZCP_INT_MASK_CFIFO_ECC1	0x0000000000000002ULL
+#define  ZCP_INT_MASK_CFIFO_ECC0	0x0000000000000001ULL
+#define  ZCP_INT_MASK_ALL		0x000000000000ffffULL
+
+#define BAM4BUF				(FZC_ZCP + 0x00018UL)
+#define  BAM4BUF_LOJ			0x0000000080000000ULL
+#define  BAM4BUF_EN_CK			0x0000000040000000ULL
+#define  BAM4BUF_IDX_END0		0x000000003ff00000ULL
+#define  BAM4BUF_IDX_ST0		0x00000000000ffc00ULL
+#define  BAM4BUF_OFFSET0		0x00000000000003ffULL
+
+#define BAM8BUF				(FZC_ZCP + 0x00020UL)
+#define  BAM8BUF_LOJ			0x0000000080000000ULL
+#define  BAM8BUF_EN_CK			0x0000000040000000ULL
+#define  BAM8BUF_IDX_END1		0x000000003ff00000ULL
+#define  BAM8BUF_IDX_ST1		0x00000000000ffc00ULL
+#define  BAM8BUF_OFFSET1		0x00000000000003ffULL
+
+#define BAM16BUF			(FZC_ZCP + 0x00028UL)
+#define  BAM16BUF_LOJ			0x0000000080000000ULL
+#define  BAM16BUF_EN_CK			0x0000000040000000ULL
+#define  BAM16BUF_IDX_END2		0x000000003ff00000ULL
+#define  BAM16BUF_IDX_ST2		0x00000000000ffc00ULL
+#define  BAM16BUF_OFFSET2		0x00000000000003ffULL
+
+#define BAM32BUF			(FZC_ZCP + 0x00030UL)
+#define  BAM32BUF_LOJ			0x0000000080000000ULL
+#define  BAM32BUF_EN_CK			0x0000000040000000ULL
+#define  BAM32BUF_IDX_END3		0x000000003ff00000ULL
+#define  BAM32BUF_IDX_ST3		0x00000000000ffc00ULL
+#define  BAM32BUF_OFFSET3		0x00000000000003ffULL
+
+#define DST4BUF				(FZC_ZCP + 0x00038UL)
+#define  DST4BUF_DS_OFFSET0		0x00000000000003ffULL
+
+#define DST8BUF				(FZC_ZCP + 0x00040UL)
+#define  DST8BUF_DS_OFFSET1		0x00000000000003ffULL
+
+#define DST16BUF			(FZC_ZCP + 0x00048UL)
+#define  DST16BUF_DS_OFFSET2		0x00000000000003ffULL
+
+#define DST32BUF			(FZC_ZCP + 0x00050UL)
+#define  DST32BUF_DS_OFFSET3		0x00000000000003ffULL
+
+#define ZCP_RAM_DATA0			(FZC_ZCP + 0x00058UL)
+#define  ZCP_RAM_DATA0_DAT0		0x00000000ffffffffULL
+
+#define ZCP_RAM_DATA1			(FZC_ZCP + 0x00060UL)
+#define  ZCP_RAM_DAT10_DAT1		0x00000000ffffffffULL
+
+#define ZCP_RAM_DATA2			(FZC_ZCP + 0x00068UL)
+#define  ZCP_RAM_DATA2_DAT2		0x00000000ffffffffULL
+
+#define ZCP_RAM_DATA3			(FZC_ZCP + 0x00070UL)
+#define  ZCP_RAM_DATA3_DAT3		0x00000000ffffffffULL
+
+#define ZCP_RAM_DATA4			(FZC_ZCP + 0x00078UL)
+#define  ZCP_RAM_DATA4_DAT4		0x00000000000000ffULL
+
+#define ZCP_RAM_BE			(FZC_ZCP + 0x00080UL)
+#define  ZCP_RAM_BE_VAL			0x000000000001ffffULL
+
+#define ZCP_RAM_ACC			(FZC_ZCP + 0x00088UL)
+#define  ZCP_RAM_ACC_BUSY		0x0000000080000000ULL
+#define  ZCP_RAM_ACC_READ		0x0000000040000000ULL
+#define  ZCP_RAM_ACC_WRITE		0x0000000000000000ULL
+#define  ZCP_RAM_ACC_LOJ		0x0000000020000000ULL
+#define  ZCP_RAM_ACC_ZFCID		0x000000001ffe0000ULL
+#define  ZCP_RAM_ACC_ZFCID_SHIFT	17
+#define  ZCP_RAM_ACC_RAM_SEL		0x000000000001f000ULL
+#define  ZCP_RAM_ACC_RAM_SEL_SHIFT	12
+#define  ZCP_RAM_ACC_CFIFOADDR		0x0000000000000fffULL
+#define  ZCP_RAM_ACC_CFIFOADDR_SHIFT	0
+
+#define ZCP_RAM_SEL_BAM(INDEX)		(0x00 + (INDEX))
+#define ZCP_RAM_SEL_TT_STATIC		0x08
+#define ZCP_RAM_SEL_TT_DYNAMIC		0x09
+#define ZCP_RAM_SEL_CFIFO(PORT)		(0x10 + (PORT))
+
+#define NIU_CFIFO_ENTRIES		1024
+#define ATLAS_P0_P1_CFIFO_ENTRIES	2048
+#define ATLAS_P2_P3_CFIFO_ENTRIES	1024
+
+#define CHK_BIT_DATA			(FZC_ZCP + 0x00090UL)
+#define  CHK_BIT_DATA_DATA		0x000000000000ffffULL
+
+#define RESET_CFIFO			(FZC_ZCP + 0x00098UL)
+#define  RESET_CFIFO_RST(PORT)		(0x1 << (PORT))
+
+#define CFIFO_ECC(PORT)			(FZC_ZCP + 0x000a0UL + (PORT) * 8UL)
+#define  CFIFO_ECC_DIS_DBLBIT_ERR	0x0000000080000000ULL
+#define  CFIFO_ECC_DBLBIT_ERR		0x0000000000020000ULL
+#define  CFIFO_ECC_SINGLEBIT_ERR	0x0000000000010000ULL
+#define  CFIFO_ECC_ALL_PKT		0x0000000000000400ULL
+#define  CFIFO_ECC_LAST_LINE		0x0000000000000004ULL
+#define  CFIFO_ECC_2ND_LINE		0x0000000000000002ULL
+#define  CFIFO_ECC_1ST_LINE		0x0000000000000001ULL
+
+#define ZCP_TRAINING_VECTOR		(FZC_ZCP + 0x000c0UL)
+#define  ZCP_TRAINING_VECTOR_VECTOR	0x00000000ffffffffULL
+
+#define ZCP_STATE_MACHINE		(FZC_ZCP + 0x000c8UL)
+#define  ZCP_STATE_MACHINE_SM		0x00000000ffffffffULL
+
+/* Same bits as ZCP_INT_STAT */
+#define ZCP_INT_STAT_TEST		(FZC_ZCP + 0x00108UL)
+
+#define RXDMA_CFIG1(IDX)		(DMC + 0x00000UL + (IDX) * 0x200UL)
+#define  RXDMA_CFIG1_EN			0x0000000080000000ULL
+#define  RXDMA_CFIG1_RST		0x0000000040000000ULL
+#define  RXDMA_CFIG1_QST		0x0000000020000000ULL
+#define  RXDMA_CFIG1_MBADDR_H		0x0000000000000fffULL /* mboxaddr 43:32 */
+
+#define RXDMA_CFIG2(IDX)		(DMC + 0x00008UL + (IDX) * 0x200UL)
+#define  RXDMA_CFIG2_MBADDR_L		0x00000000ffffffc0ULL /* mboxaddr 31:6 */
+#define  RXDMA_CFIG2_OFFSET		0x0000000000000006ULL
+#define  RXDMA_CFIG2_OFFSET_SHIFT	1
+#define  RXDMA_CFIG2_FULL_HDR		0x0000000000000001ULL
+
+#define RBR_CFIG_A(IDX)			(DMC + 0x00010UL + (IDX) * 0x200UL)
+#define  RBR_CFIG_A_LEN			0xffff000000000000ULL
+#define  RBR_CFIG_A_LEN_SHIFT		48
+#define  RBR_CFIG_A_STADDR_BASE		0x00000ffffffc0000ULL
+#define  RBR_CFIG_A_STADDR		0x000000000003ffc0ULL
+
+#define RBR_CFIG_B(IDX)			(DMC + 0x00018UL + (IDX) * 0x200UL)
+#define  RBR_CFIG_B_BLKSIZE		0x0000000003000000ULL
+#define  RBR_CFIG_B_BLKSIZE_SHIFT	24
+#define  RBR_CFIG_B_VLD2		0x0000000000800000ULL
+#define  RBR_CFIG_B_BUFSZ2		0x0000000000030000ULL
+#define  RBR_CFIG_B_BUFSZ2_SHIFT	16
+#define  RBR_CFIG_B_VLD1		0x0000000000008000ULL
+#define  RBR_CFIG_B_BUFSZ1		0x0000000000000300ULL
+#define  RBR_CFIG_B_BUFSZ1_SHIFT	8
+#define  RBR_CFIG_B_VLD0		0x0000000000000080ULL
+#define  RBR_CFIG_B_BUFSZ0		0x0000000000000003ULL
+#define  RBR_CFIG_B_BUFSZ0_SHIFT	0
+
+#define RBR_BLKSIZE_4K			0x0
+#define RBR_BLKSIZE_8K			0x1
+#define RBR_BLKSIZE_16K			0x2
+#define RBR_BLKSIZE_32K			0x3
+#define RBR_BUFSZ2_2K			0x0
+#define RBR_BUFSZ2_4K			0x1
+#define RBR_BUFSZ2_8K			0x2
+#define RBR_BUFSZ2_16K			0x3
+#define RBR_BUFSZ1_1K			0x0
+#define RBR_BUFSZ1_2K			0x1
+#define RBR_BUFSZ1_4K			0x2
+#define RBR_BUFSZ1_8K			0x3
+#define RBR_BUFSZ0_256			0x0
+#define RBR_BUFSZ0_512			0x1
+#define RBR_BUFSZ0_1K			0x2
+#define RBR_BUFSZ0_2K			0x3
+
+#define RBR_KICK(IDX)			(DMC + 0x00020UL + (IDX) * 0x200UL)
+#define  RBR_KICK_BKADD			0x000000000000ffffULL
+
+#define RBR_STAT(IDX)			(DMC + 0x00028UL + (IDX) * 0x200UL)
+#define  RBR_STAT_QLEN			0x000000000000ffffULL
+
+#define RBR_HDH(IDX)			(DMC + 0x00030UL + (IDX) * 0x200UL)
+#define  RBR_HDH_HEAD_H			0x0000000000000fffULL
+
+#define RBR_HDL(IDX)			(DMC + 0x00038UL + (IDX) * 0x200UL)
+#define  RBR_HDL_HEAD_L			0x00000000fffffffcULL
+
+#define RCRCFIG_A(IDX)			(DMC + 0x00040UL + (IDX) * 0x200UL)
+#define  RCRCFIG_A_LEN			0xffff000000000000ULL
+#define  RCRCFIG_A_LEN_SHIFT		48
+#define  RCRCFIG_A_STADDR_BASE		0x00000ffffff80000ULL
+#define  RCRCFIG_A_STADDR		0x000000000007ffc0ULL
+
+#define RCRCFIG_B(IDX)			(DMC + 0x00048UL + (IDX) * 0x200UL)
+#define  RCRCFIG_B_PTHRES		0x00000000ffff0000ULL
+#define  RCRCFIG_B_PTHRES_SHIFT		16
+#define  RCRCFIG_B_ENTOUT		0x0000000000008000ULL
+#define  RCRCFIG_B_TIMEOUT		0x000000000000003fULL
+#define  RCRCFIG_B_TIMEOUT_SHIFT	0
+
+#define RCRSTAT_A(IDX)			(DMC + 0x00050UL + (IDX) * 0x200UL)
+#define  RCRSTAT_A_QLEN			0x000000000000ffffULL
+
+#define RCRSTAT_B(IDX)			(DMC + 0x00058UL + (IDX) * 0x200UL)
+#define  RCRSTAT_B_TIPTR_H		0x0000000000000fffULL
+
+#define RCRSTAT_C(IDX)			(DMC + 0x00060UL + (IDX) * 0x200UL)
+#define  RCRSTAT_C_TIPTR_L		0x00000000fffffff8ULL
+
+#define RX_DMA_CTL_STAT(IDX)		(DMC + 0x00070UL + (IDX) * 0x200UL)
+#define  RX_DMA_CTL_STAT_RBR_TMOUT	0x0020000000000000ULL
+#define  RX_DMA_CTL_STAT_RSP_CNT_ERR	0x0010000000000000ULL
+#define  RX_DMA_CTL_STAT_BYTE_EN_BUS	0x0008000000000000ULL
+#define  RX_DMA_CTL_STAT_RSP_DAT_ERR	0x0004000000000000ULL
+#define  RX_DMA_CTL_STAT_RCR_ACK_ERR	0x0002000000000000ULL
+#define  RX_DMA_CTL_STAT_DC_FIFO_ERR	0x0001000000000000ULL
+#define  RX_DMA_CTL_STAT_MEX		0x0000800000000000ULL
+#define  RX_DMA_CTL_STAT_RCRTHRES	0x0000400000000000ULL
+#define  RX_DMA_CTL_STAT_RCRTO		0x0000200000000000ULL
+#define  RX_DMA_CTL_STAT_RCR_SHA_PAR	0x0000100000000000ULL
+#define  RX_DMA_CTL_STAT_RBR_PRE_PAR	0x0000080000000000ULL
+#define  RX_DMA_CTL_STAT_PORT_DROP_PKT	0x0000040000000000ULL
+#define  RX_DMA_CTL_STAT_WRED_DROP	0x0000020000000000ULL
+#define  RX_DMA_CTL_STAT_RBR_PRE_EMTY	0x0000010000000000ULL
+#define  RX_DMA_CTL_STAT_RCRSHADOW_FULL	0x0000008000000000ULL
+#define  RX_DMA_CTL_STAT_CONFIG_ERR	0x0000004000000000ULL
+#define  RX_DMA_CTL_STAT_RCRINCON	0x0000002000000000ULL
+#define  RX_DMA_CTL_STAT_RCRFULL	0x0000001000000000ULL
+#define  RX_DMA_CTL_STAT_RBR_EMPTY	0x0000000800000000ULL
+#define  RX_DMA_CTL_STAT_RBRFULL	0x0000000400000000ULL
+#define  RX_DMA_CTL_STAT_RBRLOGPAGE	0x0000000200000000ULL
+#define  RX_DMA_CTL_STAT_CFIGLOGPAGE	0x0000000100000000ULL
+#define  RX_DMA_CTL_STAT_PTRREAD	0x00000000ffff0000ULL
+#define  RX_DMA_CTL_STAT_PTRREAD_SHIFT	16
+#define  RX_DMA_CTL_STAT_PKTREAD	0x000000000000ffffULL
+#define  RX_DMA_CTL_STAT_PKTREAD_SHIFT	0
+
+#define  RX_DMA_CTL_STAT_CHAN_FATAL	(RX_DMA_CTL_STAT_RBR_TMOUT | \
+					 RX_DMA_CTL_STAT_RSP_CNT_ERR | \
+					 RX_DMA_CTL_STAT_BYTE_EN_BUS | \
+					 RX_DMA_CTL_STAT_RSP_DAT_ERR | \
+					 RX_DMA_CTL_STAT_RCR_ACK_ERR | \
+					 RX_DMA_CTL_STAT_RCR_SHA_PAR | \
+					 RX_DMA_CTL_STAT_RBR_PRE_PAR | \
+					 RX_DMA_CTL_STAT_CONFIG_ERR | \
+					 RX_DMA_CTL_STAT_RCRINCON | \
+					 RX_DMA_CTL_STAT_RCRFULL | \
+					 RX_DMA_CTL_STAT_RBRFULL | \
+					 RX_DMA_CTL_STAT_RBRLOGPAGE | \
+					 RX_DMA_CTL_STAT_CFIGLOGPAGE)
+
+#define RX_DMA_CTL_STAT_PORT_FATAL	(RX_DMA_CTL_STAT_DC_FIFO_ERR)
+
+#define RX_DMA_CTL_WRITE_CLEAR_ERRS	(RX_DMA_CTL_STAT_RBR_EMPTY | \
+					 RX_DMA_CTL_STAT_RCRSHADOW_FULL | \
+					 RX_DMA_CTL_STAT_RBR_PRE_EMTY | \
+					 RX_DMA_CTL_STAT_WRED_DROP | \
+					 RX_DMA_CTL_STAT_PORT_DROP_PKT | \
+					 RX_DMA_CTL_STAT_RCRTO | \
+					 RX_DMA_CTL_STAT_RCRTHRES | \
+					 RX_DMA_CTL_STAT_DC_FIFO_ERR)
+
+#define RCR_FLSH(IDX)			(DMC + 0x00078UL + (IDX) * 0x200UL)
+#define  RCR_FLSH_FLSH			0x0000000000000001ULL
+
+#define RXMISC(IDX)			(DMC + 0x00090UL + (IDX) * 0x200UL)
+#define  RXMISC_OFLOW			0x0000000000010000ULL
+#define  RXMISC_COUNT			0x000000000000ffffULL
+
+#define RX_DMA_CTL_STAT_DBG(IDX)	(DMC + 0x00098UL + (IDX) * 0x200UL)
+#define  RX_DMA_CTL_STAT_DBG_RBR_TMOUT		0x0020000000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_RSP_CNT_ERR	0x0010000000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_BYTE_EN_BUS	0x0008000000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_RSP_DAT_ERR	0x0004000000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_RCR_ACK_ERR	0x0002000000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_DC_FIFO_ERR	0x0001000000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_MEX		0x0000800000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_RCRTHRES		0x0000400000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_RCRTO		0x0000200000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_RCR_SHA_PAR	0x0000100000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_RBR_PRE_PAR	0x0000080000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_PORT_DROP_PKT	0x0000040000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_WRED_DROP		0x0000020000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_RBR_PRE_EMTY	0x0000010000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_RCRSHADOW_FULL	0x0000008000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_CONFIG_ERR		0x0000004000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_RCRINCON		0x0000002000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_RCRFULL		0x0000001000000000ULL
+#define  RX_DMA_CTL_STAT_DBG_RBR_EMPTY		0x0000000800000000ULL
+#define  RX_DMA_CTL_STAT_DBG_RBRFULL		0x0000000400000000ULL
+#define  RX_DMA_CTL_STAT_DBG_RBRLOGPAGE		0x0000000200000000ULL
+#define  RX_DMA_CTL_STAT_DBG_CFIGLOGPAGE	0x0000000100000000ULL
+#define  RX_DMA_CTL_STAT_DBG_PTRREAD		0x00000000ffff0000ULL
+#define  RX_DMA_CTL_STAT_DBG_PKTREAD		0x000000000000ffffULL
+
+#define RX_DMA_ENT_MSK(IDX)		(DMC + 0x00068UL + (IDX) * 0x200UL)
+#define  RX_DMA_ENT_MSK_RBR_TMOUT	0x0000000000200000ULL
+#define  RX_DMA_ENT_MSK_RSP_CNT_ERR	0x0000000000100000ULL
+#define  RX_DMA_ENT_MSK_BYTE_EN_BUS	0x0000000000080000ULL
+#define  RX_DMA_ENT_MSK_RSP_DAT_ERR	0x0000000000040000ULL
+#define  RX_DMA_ENT_MSK_RCR_ACK_ERR	0x0000000000020000ULL
+#define  RX_DMA_ENT_MSK_DC_FIFO_ERR	0x0000000000010000ULL
+#define  RX_DMA_ENT_MSK_RCRTHRES	0x0000000000004000ULL
+#define  RX_DMA_ENT_MSK_RCRTO		0x0000000000002000ULL
+#define  RX_DMA_ENT_MSK_RCR_SHA_PAR	0x0000000000001000ULL
+#define  RX_DMA_ENT_MSK_RBR_PRE_PAR	0x0000000000000800ULL
+#define  RX_DMA_ENT_MSK_PORT_DROP_PKT	0x0000000000000400ULL
+#define  RX_DMA_ENT_MSK_WRED_DROP	0x0000000000000200ULL
+#define  RX_DMA_ENT_MSK_RBR_PRE_EMTY	0x0000000000000100ULL
+#define  RX_DMA_ENT_MSK_RCR_SHADOW_FULL	0x0000000000000080ULL
+#define  RX_DMA_ENT_MSK_CONFIG_ERR	0x0000000000000040ULL
+#define  RX_DMA_ENT_MSK_RCRINCON	0x0000000000000020ULL
+#define  RX_DMA_ENT_MSK_RCRFULL		0x0000000000000010ULL
+#define  RX_DMA_ENT_MSK_RBR_EMPTY	0x0000000000000008ULL
+#define  RX_DMA_ENT_MSK_RBRFULL		0x0000000000000004ULL
+#define  RX_DMA_ENT_MSK_RBRLOGPAGE	0x0000000000000002ULL
+#define  RX_DMA_ENT_MSK_CFIGLOGPAGE	0x0000000000000001ULL
+#define  RX_DMA_ENT_MSK_ALL		0x00000000003f7fffULL
+
+#define TX_RNG_CFIG(IDX)		(DMC + 0x40000UL + (IDX) * 0x200UL)
+#define  TX_RNG_CFIG_LEN		0x1fff000000000000ULL
+#define  TX_RNG_CFIG_LEN_SHIFT		48
+#define  TX_RNG_CFIG_STADDR_BASE	0x00000ffffff80000ULL
+#define  TX_RNG_CFIG_STADDR		0x000000000007ffc0ULL
+
+#define TX_RING_HDL(IDX)		(DMC + 0x40010UL + (IDX) * 0x200UL)
+#define  TX_RING_HDL_WRAP		0x0000000000080000ULL
+#define  TX_RING_HDL_HEAD		0x000000000007fff8ULL
+#define  TX_RING_HDL_HEAD_SHIFT		3
+
+#define TX_RING_KICK(IDX)		(DMC + 0x40018UL + (IDX) * 0x200UL)
+#define  TX_RING_KICK_WRAP		0x0000000000080000ULL
+#define  TX_RING_KICK_TAIL		0x000000000007fff8ULL
+
+#define TX_ENT_MSK(IDX)			(DMC + 0x40020UL + (IDX) * 0x200UL)
+#define  TX_ENT_MSK_MK			0x0000000000008000ULL
+#define  TX_ENT_MSK_MBOX_ERR		0x0000000000000080ULL
+#define  TX_ENT_MSK_PKT_SIZE_ERR	0x0000000000000040ULL
+#define  TX_ENT_MSK_TX_RING_OFLOW	0x0000000000000020ULL
+#define  TX_ENT_MSK_PREF_BUF_ECC_ERR	0x0000000000000010ULL
+#define  TX_ENT_MSK_NACK_PREF		0x0000000000000008ULL
+#define  TX_ENT_MSK_NACK_PKT_RD		0x0000000000000004ULL
+#define  TX_ENT_MSK_CONF_PART_ERR	0x0000000000000002ULL
+#define  TX_ENT_MSK_PKT_PRT_ERR		0x0000000000000001ULL
+
+#define TX_CS(IDX)			(DMC + 0x40028UL + (IDX)*0x200UL)
+#define  TX_CS_PKT_CNT			0x0fff000000000000ULL
+#define  TX_CS_PKT_CNT_SHIFT		48
+#define  TX_CS_LASTMARK			0x00000fff00000000ULL
+#define  TX_CS_LASTMARK_SHIFT		32
+#define  TX_CS_RST			0x0000000080000000ULL
+#define  TX_CS_RST_STATE		0x0000000040000000ULL
+#define  TX_CS_MB			0x0000000020000000ULL
+#define  TX_CS_STOP_N_GO		0x0000000010000000ULL
+#define  TX_CS_SNG_STATE		0x0000000008000000ULL
+#define  TX_CS_MK			0x0000000000008000ULL
+#define  TX_CS_MMK			0x0000000000004000ULL
+#define  TX_CS_MBOX_ERR			0x0000000000000080ULL
+#define  TX_CS_PKT_SIZE_ERR		0x0000000000000040ULL
+#define  TX_CS_TX_RING_OFLOW		0x0000000000000020ULL
+#define  TX_CS_PREF_BUF_PAR_ERR		0x0000000000000010ULL
+#define  TX_CS_NACK_PREF		0x0000000000000008ULL
+#define  TX_CS_NACK_PKT_RD		0x0000000000000004ULL
+#define  TX_CS_CONF_PART_ERR		0x0000000000000002ULL
+#define  TX_CS_PKT_PRT_ERR		0x0000000000000001ULL
+
+#define TXDMA_MBH(IDX)			(DMC + 0x40030UL + (IDX) * 0x200UL)
+#define  TXDMA_MBH_MBADDR		0x0000000000000fffULL
+
+#define TXDMA_MBL(IDX)			(DMC + 0x40038UL + (IDX) * 0x200UL)
+#define  TXDMA_MBL_MBADDR		0x00000000ffffffc0ULL
+
+#define TX_DMA_PRE_ST(IDX)		(DMC + 0x40040UL + (IDX) * 0x200UL)
+#define  TX_DMA_PRE_ST_SHADOW_HD	0x000000000007ffffULL
+
+#define TX_RNG_ERR_LOGH(IDX)		(DMC + 0x40048UL + (IDX) * 0x200UL)
+#define  TX_RNG_ERR_LOGH_ERR		0x0000000080000000ULL
+#define  TX_RNG_ERR_LOGH_MERR		0x0000000040000000ULL
+#define  TX_RNG_ERR_LOGH_ERRCODE	0x0000000038000000ULL
+#define  TX_RNG_ERR_LOGH_ERRADDR	0x0000000000000fffULL
+
+#define TX_RNG_ERR_LOGL(IDX)		(DMC + 0x40050UL + (IDX) * 0x200UL)
+#define  TX_RNG_ERR_LOGL_ERRADDR	0x00000000ffffffffULL
+
+#define TDMC_INTR_DBG(IDX)		(DMC + 0x40060UL + (IDX) * 0x200UL)
+#define  TDMC_INTR_DBG_MK		0x0000000000008000ULL
+#define  TDMC_INTR_DBG_MBOX_ERR		0x0000000000000080ULL
+#define  TDMC_INTR_DBG_PKT_SIZE_ERR	0x0000000000000040ULL
+#define  TDMC_INTR_DBG_TX_RING_OFLOW	0x0000000000000020ULL
+#define  TDMC_INTR_DBG_PREF_BUF_PAR_ERR	0x0000000000000010ULL
+#define  TDMC_INTR_DBG_NACK_PREF	0x0000000000000008ULL
+#define  TDMC_INTR_DBG_NACK_PKT_RD	0x0000000000000004ULL
+#define  TDMC_INTR_DBG_CONF_PART_ERR	0x0000000000000002ULL
+#define  TDMC_INTR_DBG_PKT_PART_ERR	0x0000000000000001ULL
+
+#define TX_CS_DBG(IDX)			(DMC + 0x40068UL + (IDX) * 0x200UL)
+#define  TX_CS_DBG_PKT_CNT		0x0fff000000000000ULL
+
+#define TDMC_INJ_PAR_ERR(IDX)		(DMC + 0x45040UL + (IDX) * 0x200UL)
+#define  TDMC_INJ_PAR_ERR_VAL		0x000000000000ffffULL
+
+#define TDMC_DBG_SEL(IDX)		(DMC + 0x45080UL + (IDX) * 0x200UL)
+#define  TDMC_DBG_SEL_DBG_SEL		0x000000000000003fULL
+
+#define TDMC_TRAINING_VECTOR(IDX)	(DMC + 0x45088UL + (IDX) * 0x200UL)
+#define  TDMC_TRAINING_VECTOR_VEC	0x00000000ffffffffULL
+
+#define TXC_DMA_MAX(CHAN)		(FZC_TXC + 0x00000UL + (CHAN)*0x1000UL)
+#define TXC_DMA_MAX_LEN(CHAN)		(FZC_TXC + 0x00008UL + (CHAN)*0x1000UL)
+
+#define TXC_CONTROL			(FZC_TXC + 0x20000UL)
+#define  TXC_CONTROL_ENABLE		0x0000000000000010ULL
+#define  TXC_CONTROL_PORT_ENABLE(X)	(1 << (X))
+
+#define TXC_TRAINING_VEC		(FZC_TXC + 0x20008UL)
+#define  TXC_TRAINING_VEC_MASK		0x00000000ffffffffULL
+
+#define TXC_DEBUG			(FZC_TXC + 0x20010UL)
+#define  TXC_DEBUG_SELECT		0x000000000000003fULL
+
+#define TXC_MAX_REORDER			(FZC_TXC + 0x20018UL)
+#define  TXC_MAX_REORDER_PORT3		0x000000000f000000ULL
+#define  TXC_MAX_REORDER_PORT2		0x00000000000f0000ULL
+#define  TXC_MAX_REORDER_PORT1		0x0000000000000f00ULL
+#define  TXC_MAX_REORDER_PORT0		0x000000000000000fULL
+
+#define TXC_PORT_CTL(PORT)		(FZC_TXC + 0x20020UL + (PORT)*0x100UL)
+#define  TXC_PORT_CTL_CLR_ALL_STAT	0x0000000000000001ULL
+
+#define TXC_PKT_STUFFED(PORT)		(FZC_TXC + 0x20030UL + (PORT)*0x100UL)
+#define  TXC_PKT_STUFFED_PP_REORDER	0x00000000ffff0000ULL
+#define  TXC_PKT_STUFFED_PP_PACKETASSY	0x000000000000ffffULL
+
+#define TXC_PKT_XMIT(PORT)		(FZC_TXC + 0x20038UL + (PORT)*0x100UL)
+#define  TXC_PKT_XMIT_BYTES		0x00000000ffff0000ULL
+#define  TXC_PKT_XMIT_PKTS		0x000000000000ffffULL
+
+#define TXC_ROECC_CTL(PORT)		(FZC_TXC + 0x20040UL + (PORT)*0x100UL)
+#define  TXC_ROECC_CTL_DISABLE_UE	0x0000000080000000ULL
+#define  TXC_ROECC_CTL_DBL_BIT_ERR	0x0000000000020000ULL
+#define  TXC_ROECC_CTL_SNGL_BIT_ERR	0x0000000000010000ULL
+#define  TXC_ROECC_CTL_ALL_PKTS		0x0000000000000400ULL
+#define  TXC_ROECC_CTL_ALT_PKTS		0x0000000000000200ULL
+#define  TXC_ROECC_CTL_ONE_PKT_ONLY	0x0000000000000100ULL
+#define  TXC_ROECC_CTL_LST_PKT_LINE	0x0000000000000004ULL
+#define  TXC_ROECC_CTL_2ND_PKT_LINE	0x0000000000000002ULL
+#define  TXC_ROECC_CTL_1ST_PKT_LINE	0x0000000000000001ULL
+
+#define TXC_ROECC_ST(PORT)		(FZC_TXC + 0x20048UL + (PORT)*0x100UL)
+#define  TXC_ROECC_CLR_ST		0x0000000080000000ULL
+#define  TXC_ROECC_CE			0x0000000000020000ULL
+#define  TXC_ROECC_UE			0x0000000000010000ULL
+#define  TXC_ROECC_ST_ECC_ADDR		0x00000000000003ffULL
+
+#define TXC_RO_DATA0(PORT)		(FZC_TXC + 0x20050UL + (PORT)*0x100UL)
+#define  TXC_RO_DATA0_DATA0		0x00000000ffffffffULL /* bits 31:0 */
+
+#define TXC_RO_DATA1(PORT)		(FZC_TXC + 0x20058UL + (PORT)*0x100UL)
+#define  TXC_RO_DATA1_DATA1		0x00000000ffffffffULL /* bits 63:32 */
+
+#define TXC_RO_DATA2(PORT)		(FZC_TXC + 0x20060UL + (PORT)*0x100UL)
+#define  TXC_RO_DATA2_DATA2		0x00000000ffffffffULL /* bits 95:64 */
+
+#define TXC_RO_DATA3(PORT)		(FZC_TXC + 0x20068UL + (PORT)*0x100UL)
+#define  TXC_RO_DATA3_DATA3		0x00000000ffffffffULL /* bits 127:96 */
+
+#define TXC_RO_DATA4(PORT)		(FZC_TXC + 0x20070UL + (PORT)*0x100UL)
+#define  TXC_RO_DATA4_DATA4		0x0000000000ffffffULL /* bits 151:128 */
+
+#define TXC_SFECC_CTL(PORT)		(FZC_TXC + 0x20078UL + (PORT)*0x100UL)
+#define  TXC_SFECC_CTL_DISABLE_UE	0x0000000080000000ULL
+#define  TXC_SFECC_CTL_DBL_BIT_ERR	0x0000000000020000ULL
+#define  TXC_SFECC_CTL_SNGL_BIT_ERR	0x0000000000010000ULL
+#define  TXC_SFECC_CTL_ALL_PKTS		0x0000000000000400ULL
+#define  TXC_SFECC_CTL_ALT_PKTS		0x0000000000000200ULL
+#define  TXC_SFECC_CTL_ONE_PKT_ONLY	0x0000000000000100ULL
+#define  TXC_SFECC_CTL_LST_PKT_LINE	0x0000000000000004ULL
+#define  TXC_SFECC_CTL_2ND_PKT_LINE	0x0000000000000002ULL
+#define  TXC_SFECC_CTL_1ST_PKT_LINE	0x0000000000000001ULL
+
+#define TXC_SFECC_ST(PORT)		(FZC_TXC + 0x20080UL + (PORT)*0x100UL)
+#define  TXC_SFECC_ST_CLR_ST		0x0000000080000000ULL
+#define  TXC_SFECC_ST_CE		0x0000000000020000ULL
+#define  TXC_SFECC_ST_UE		0x0000000000010000ULL
+#define  TXC_SFECC_ST_ECC_ADDR		0x00000000000003ffULL
+
+#define TXC_SF_DATA0(PORT)		(FZC_TXC + 0x20088UL + (PORT)*0x100UL)
+#define  TXC_SF_DATA0_DATA0		0x00000000ffffffffULL /* bits 31:0 */
+
+#define TXC_SF_DATA1(PORT)		(FZC_TXC + 0x20090UL + (PORT)*0x100UL)
+#define  TXC_SF_DATA1_DATA1		0x00000000ffffffffULL /* bits 63:32 */
+
+#define TXC_SF_DATA2(PORT)		(FZC_TXC + 0x20098UL + (PORT)*0x100UL)
+#define  TXC_SF_DATA2_DATA2		0x00000000ffffffffULL /* bits 95:64 */
+
+#define TXC_SF_DATA3(PORT)		(FZC_TXC + 0x200a0UL + (PORT)*0x100UL)
+#define  TXC_SF_DATA3_DATA3		0x00000000ffffffffULL /* bits 127:96 */
+
+#define TXC_SF_DATA4(PORT)		(FZC_TXC + 0x200a8UL + (PORT)*0x100UL)
+#define  TXC_SF_DATA4_DATA4		0x0000000000ffffffULL /* bits 151:128 */
+
+#define TXC_RO_TIDS(PORT)		(FZC_TXC + 0x200b0UL + (PORT)*0x100UL)
+#define  TXC_RO_TIDS_IN_USE		0x00000000ffffffffULL
+
+#define TXC_RO_STATE0(PORT)		(FZC_TXC + 0x200b8UL + (PORT)*0x100UL)
+#define  TXC_RO_STATE0_DUPLICATE_TID	0x00000000ffffffffULL
+
+#define TXC_RO_STATE1(PORT)		(FZC_TXC + 0x200c0UL + (PORT)*0x100UL)
+#define  TXC_RO_STATE1_UNUSED_TID	0x00000000ffffffffULL
+
+#define TXC_RO_STATE2(PORT)		(FZC_TXC + 0x200c8UL + (PORT)*0x100UL)
+#define  TXC_RO_STATE2_TRANS_TIMEOUT	0x00000000ffffffffULL
+
+#define TXC_RO_STATE3(PORT)		(FZC_TXC + 0x200d0UL + (PORT)*0x100UL)
+#define  TXC_RO_STATE3_ENAB_SPC_WMARK	0x0000000080000000ULL
+#define  TXC_RO_STATE3_RO_SPC_WMARK	0x000000007fe00000ULL
+#define  TXC_RO_STATE3_ROFIFO_SPC_AVAIL	0x00000000001ff800ULL
+#define  TXC_RO_STATE3_ENAB_RO_WMARK	0x0000000000000100ULL
+#define  TXC_RO_STATE3_HIGH_RO_USED	0x00000000000000f0ULL
+#define  TXC_RO_STATE3_NUM_RO_USED	0x000000000000000fULL
+
+#define TXC_RO_CTL(PORT)		(FZC_TXC + 0x200d8UL + (PORT)*0x100UL)
+#define  TXC_RO_CTL_CLR_FAIL_STATE	0x0000000080000000ULL
+#define  TXC_RO_CTL_RO_ADDR		0x000000000f000000ULL
+#define  TXC_RO_CTL_ADDR_FAILED		0x0000000000400000ULL
+#define  TXC_RO_CTL_DMA_FAILED		0x0000000000200000ULL
+#define  TXC_RO_CTL_LEN_FAILED		0x0000000000100000ULL
+#define  TXC_RO_CTL_CAPT_ADDR_FAILED	0x0000000000040000ULL
+#define  TXC_RO_CTL_CAPT_DMA_FAILED	0x0000000000020000ULL
+#define  TXC_RO_CTL_CAPT_LEN_FAILED	0x0000000000010000ULL
+#define  TXC_RO_CTL_RO_STATE_RD_DONE	0x0000000000000080ULL
+#define  TXC_RO_CTL_RO_STATE_WR_DONE	0x0000000000000040ULL
+#define  TXC_RO_CTL_RO_STATE_RD		0x0000000000000020ULL
+#define  TXC_RO_CTL_RO_STATE_WR		0x0000000000000010ULL
+#define  TXC_RO_CTL_RO_STATE_ADDR	0x000000000000000fULL
+
+#define TXC_RO_ST_DATA0(PORT)		(FZC_TXC + 0x200e0UL + (PORT)*0x100UL)
+#define  TXC_RO_ST_DATA0_DATA0		0x00000000ffffffffULL
+
+#define TXC_RO_ST_DATA1(PORT)		(FZC_TXC + 0x200e8UL + (PORT)*0x100UL)
+#define  TXC_RO_ST_DATA1_DATA1		0x00000000ffffffffULL
+
+#define TXC_RO_ST_DATA2(PORT)		(FZC_TXC + 0x200f0UL + (PORT)*0x100UL)
+#define  TXC_RO_ST_DATA2_DATA2		0x00000000ffffffffULL
+
+#define TXC_RO_ST_DATA3(PORT)		(FZC_TXC + 0x200f8UL + (PORT)*0x100UL)
+#define  TXC_RO_ST_DATA3_DATA3		0x00000000ffffffffULL
+
+#define TXC_PORT_PACKET_REQ(PORT)	(FZC_TXC + 0x20100UL + (PORT)*0x100UL)
+#define  TXC_PORT_PACKET_REQ_GATHER_REQ	0x00000000f0000000ULL
+#define  TXC_PORT_PACKET_REQ_PKT_REQ	0x000000000fff0000ULL
+#define  TXC_PORT_PACKET_REQ_PERR_ABRT	0x000000000000ffffULL
+
+	/* bits are same as TXC_INT_STAT */
+#define TXC_INT_STAT_DBG		(FZC_TXC + 0x20420UL)
+
+#define TXC_INT_STAT			(FZC_TXC + 0x20428UL)
+#define  TXC_INT_STAT_VAL_SHIFT(PORT)	((PORT) * 8)
+#define  TXC_INT_STAT_VAL(PORT)		(0x3f << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define  TXC_INT_STAT_SF_CE(PORT)	(0x01 << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define  TXC_INT_STAT_SF_UE(PORT)	(0x02 << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define  TXC_INT_STAT_RO_CE(PORT)	(0x04 << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define  TXC_INT_STAT_RO_UE(PORT)	(0x08 << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define  TXC_INT_STAT_REORDER_ERR(PORT)	(0x10 << TXC_INT_STAT_VAL_SHIFT(PORT))
+#define  TXC_INT_STAT_PKTASM_DEAD(PORT)	(0x20 << TXC_INT_STAT_VAL_SHIFT(PORT))
+
+#define TXC_INT_MASK			(FZC_TXC + 0x20430UL)
+#define  TXC_INT_MASK_VAL_SHIFT(PORT)	((PORT) * 8)
+#define  TXC_INT_MASK_VAL(PORT)		(0x3f << TXC_INT_STAT_VAL_SHIFT(PORT))
+
+#define TXC_INT_MASK_SF_CE		0x01
+#define TXC_INT_MASK_SF_UE		0x02
+#define TXC_INT_MASK_RO_CE		0x04
+#define TXC_INT_MASK_RO_UE		0x08
+#define TXC_INT_MASK_REORDER_ERR	0x10
+#define TXC_INT_MASK_PKTASM_DEAD	0x20
+#define TXC_INT_MASK_ALL		0x3f
+
+#define TXC_PORT_DMA(IDX)		(FZC_TXC + 0x20028UL + (IDX)*0x100UL)
+
+#define ESPC_PIO_EN			(FZC_PROM + 0x40000UL)
+#define  ESPC_PIO_EN_ENABLE		0x0000000000000001ULL
+
+#define ESPC_PIO_STAT			(FZC_PROM + 0x40008UL)
+#define  ESPC_PIO_STAT_READ_START	0x0000000080000000ULL
+#define  ESPC_PIO_STAT_READ_END		0x0000000040000000ULL
+#define  ESPC_PIO_STAT_WRITE_INIT	0x0000000020000000ULL
+#define  ESPC_PIO_STAT_WRITE_END	0x0000000010000000ULL
+#define  ESPC_PIO_STAT_ADDR		0x0000000003ffff00ULL
+#define  ESPC_PIO_STAT_ADDR_SHIFT	8
+#define  ESPC_PIO_STAT_DATA		0x00000000000000ffULL
+#define  ESPC_PIO_STAT_DATA_SHIFT	0
+
+#define ESPC_NCR(IDX)			(FZC_PROM + 0x40020UL + (IDX)*0x8UL)
+#define  ESPC_NCR_VAL			0x00000000ffffffffULL
+
+#define ESPC_MAC_ADDR0			ESPC_NCR(0)
+#define ESPC_MAC_ADDR1			ESPC_NCR(1)
+#define ESPC_NUM_PORTS_MACS		ESPC_NCR(2)
+#define  ESPC_NUM_PORTS_MACS_VAL	0x00000000000000ffULL
+#define ESPC_MOD_STR_LEN		ESPC_NCR(4)
+#define ESPC_MOD_STR_1			ESPC_NCR(5)
+#define ESPC_MOD_STR_2			ESPC_NCR(6)
+#define ESPC_MOD_STR_3			ESPC_NCR(7)
+#define ESPC_MOD_STR_4			ESPC_NCR(8)
+#define ESPC_MOD_STR_5			ESPC_NCR(9)
+#define ESPC_MOD_STR_6			ESPC_NCR(10)
+#define ESPC_MOD_STR_7			ESPC_NCR(11)
+#define ESPC_MOD_STR_8			ESPC_NCR(12)
+#define ESPC_BD_MOD_STR_LEN		ESPC_NCR(13)
+#define ESPC_BD_MOD_STR_1		ESPC_NCR(14)
+#define ESPC_BD_MOD_STR_2		ESPC_NCR(15)
+#define ESPC_BD_MOD_STR_3		ESPC_NCR(16)
+#define ESPC_BD_MOD_STR_4		ESPC_NCR(17)
+
+#define ESPC_PHY_TYPE			ESPC_NCR(18)
+#define  ESPC_PHY_TYPE_PORT0		0x00000000ff000000ULL
+#define  ESPC_PHY_TYPE_PORT0_SHIFT	24
+#define  ESPC_PHY_TYPE_PORT1		0x0000000000ff0000ULL
+#define  ESPC_PHY_TYPE_PORT1_SHIFT	16
+#define  ESPC_PHY_TYPE_PORT2		0x000000000000ff00ULL
+#define  ESPC_PHY_TYPE_PORT2_SHIFT	8
+#define  ESPC_PHY_TYPE_PORT3		0x00000000000000ffULL
+#define  ESPC_PHY_TYPE_PORT3_SHIFT	0
+
+#define  ESPC_PHY_TYPE_1G_COPPER	3
+#define  ESPC_PHY_TYPE_1G_FIBER		2
+#define  ESPC_PHY_TYPE_10G_COPPER	1
+#define  ESPC_PHY_TYPE_10G_FIBER	0
+
+#define ESPC_MAX_FM_SZ			ESPC_NCR(19)
+
+#define ESPC_INTR_NUM			ESPC_NCR(20)
+#define  ESPC_INTR_NUM_PORT0		0x00000000ff000000ULL
+#define  ESPC_INTR_NUM_PORT1		0x0000000000ff0000ULL
+#define  ESPC_INTR_NUM_PORT2		0x000000000000ff00ULL
+#define  ESPC_INTR_NUM_PORT3		0x00000000000000ffULL
+
+#define ESPC_VER_IMGSZ			ESPC_NCR(21)
+#define  ESPC_VER_IMGSZ_IMGSZ		0x00000000ffff0000ULL
+#define  ESPC_VER_IMGSZ_IMGSZ_SHIFT	16
+#define  ESPC_VER_IMGSZ_VER		0x000000000000ffffULL
+#define  ESPC_VER_IMGSZ_VER_SHIFT	0
+
+#define ESPC_CHKSUM			ESPC_NCR(22)
+#define  ESPC_CHKSUM_SUM		0x00000000000000ffULL
+
+#define ESPC_EEPROM_SIZE		0x100000
+
+#define CLASS_CODE_UNRECOG		0x00
+#define CLASS_CODE_DUMMY1		0x01
+#define CLASS_CODE_ETHERTYPE1		0x02
+#define CLASS_CODE_ETHERTYPE2		0x03
+#define CLASS_CODE_USER_PROG1		0x04
+#define CLASS_CODE_USER_PROG2		0x05
+#define CLASS_CODE_USER_PROG3		0x06
+#define CLASS_CODE_USER_PROG4		0x07
+#define CLASS_CODE_TCP_IPV4		0x08
+#define CLASS_CODE_UDP_IPV4		0x09
+#define CLASS_CODE_AH_ESP_IPV4		0x0a
+#define CLASS_CODE_SCTP_IPV4		0x0b
+#define CLASS_CODE_TCP_IPV6		0x0c
+#define CLASS_CODE_UDP_IPV6		0x0d
+#define CLASS_CODE_AH_ESP_IPV6		0x0e
+#define CLASS_CODE_SCTP_IPV6		0x0f
+#define CLASS_CODE_ARP			0x10
+#define CLASS_CODE_RARP			0x11
+#define CLASS_CODE_DUMMY2		0x12
+#define CLASS_CODE_DUMMY3		0x13
+#define CLASS_CODE_DUMMY4		0x14
+#define CLASS_CODE_DUMMY5		0x15
+#define CLASS_CODE_DUMMY6		0x16
+#define CLASS_CODE_DUMMY7		0x17
+#define CLASS_CODE_DUMMY8		0x18
+#define CLASS_CODE_DUMMY9		0x19
+#define CLASS_CODE_DUMMY10		0x1a
+#define CLASS_CODE_DUMMY11		0x1b
+#define CLASS_CODE_DUMMY12		0x1c
+#define CLASS_CODE_DUMMY13		0x1d
+#define CLASS_CODE_DUMMY14		0x1e
+#define CLASS_CODE_DUMMY15		0x1f
+
+/* Logical devices and device groups */
+#define LDN_RXDMA(CHAN)			(0 + (CHAN))
+#define LDN_RESV1(OFF)			(16 + (OFF))
+#define LDN_TXDMA(CHAN)			(32 + (CHAN))
+#define LDN_RESV2(OFF)			(56 + (OFF))
+#define LDN_MIF				63
+#define LDN_MAC(PORT)			(64 + (PORT))
+#define LDN_DEVICE_ERROR		68
+#define LDN_MAX				LDN_DEVICE_ERROR
+
+#define NIU_LDG_MIN			0
+#define NIU_LDG_MAX			63
+#define NIU_NUM_LDG			64
+#define LDG_INVALID			0xff
+
+/* PHY stuff */
+#define NIU_PMA_PMD_DEV_ADDR		1
+#define NIU_PCS_DEV_ADDR		3
+
+#define NIU_PHY_ID_MASK			0xfffff0f0
+#define NIU_PHY_ID_BCM8704		0x00206030
+#define NIU_PHY_ID_BCM5464R		0x002060b0
+
+#define BCM8704_PMA_PMD_DEV_ADDR	1
+#define BCM8704_PCS_DEV_ADDR		2
+#define BCM8704_USER_DEV3_ADDR		3
+#define BCM8704_PHYXS_DEV_ADDR		4
+#define BCM8704_USER_DEV4_ADDR		4
+
+#define BCM8704_PMD_RCV_SIGDET		0x000a
+#define  PMD_RCV_SIGDET_LANE3		0x0010
+#define  PMD_RCV_SIGDET_LANE2		0x0008
+#define  PMD_RCV_SIGDET_LANE1		0x0004
+#define  PMD_RCV_SIGDET_LANE0		0x0002
+#define  PMD_RCV_SIGDET_GLOBAL		0x0001
+
+#define BCM8704_PCS_10G_R_STATUS	0x0020
+#define  PCS_10G_R_STATUS_LINKSTAT	0x1000
+#define  PCS_10G_R_STATUS_PRBS31_ABLE	0x0004
+#define  PCS_10G_R_STATUS_HI_BER	0x0002
+#define  PCS_10G_R_STATUS_BLK_LOCK	0x0001
+
+#define BCM8704_USER_CONTROL		0xc800
+#define  USER_CONTROL_OPTXENB_LVL	0x8000
+#define  USER_CONTROL_OPTXRST_LVL	0x4000
+#define  USER_CONTROL_OPBIASFLT_LVL	0x2000
+#define  USER_CONTROL_OBTMPFLT_LVL	0x1000
+#define  USER_CONTROL_OPPRFLT_LVL	0x0800
+#define  USER_CONTROL_OPTXFLT_LVL	0x0400
+#define  USER_CONTROL_OPRXLOS_LVL	0x0200
+#define  USER_CONTROL_OPRXFLT_LVL	0x0100
+#define  USER_CONTROL_OPTXON_LVL	0x0080
+#define  USER_CONTROL_RES1		0x007f
+#define  USER_CONTROL_RES1_SHIFT	0
+
+#define BCM8704_USER_ANALOG_CLK		0xc801
+#define BCM8704_USER_PMD_RX_CONTROL	0xc802
+
+#define BCM8704_USER_PMD_TX_CONTROL	0xc803
+#define  USER_PMD_TX_CTL_RES1		0xfe00
+#define  USER_PMD_TX_CTL_XFP_CLKEN	0x0100
+#define  USER_PMD_TX_CTL_TX_DAC_TXD	0x00c0
+#define  USER_PMD_TX_CTL_TX_DAC_TXD_SH	6
+#define  USER_PMD_TX_CTL_TX_DAC_TXCK	0x0030
+#define  USER_PMD_TX_CTL_TX_DAC_TXCK_SH	4
+#define  USER_PMD_TX_CTL_TSD_LPWREN	0x0008
+#define  USER_PMD_TX_CTL_TSCK_LPWREN	0x0004
+#define  USER_PMD_TX_CTL_CMU_LPWREN	0x0002
+#define  USER_PMD_TX_CTL_SFIFORST	0x0001
+
+#define BCM8704_USER_ANALOG_STATUS0	0xc804
+#define BCM8704_USER_OPT_DIGITAL_CTRL	0xc808
+#define BCM8704_USER_TX_ALARM_STATUS	0x9004
+
+#define  USER_ODIG_CTRL_FMODE		0x8000
+#define  USER_ODIG_CTRL_TX_PDOWN	0x4000
+#define  USER_ODIG_CTRL_RX_PDOWN	0x2000
+#define  USER_ODIG_CTRL_EFILT_EN	0x1000
+#define  USER_ODIG_CTRL_OPT_RST		0x0800
+#define  USER_ODIG_CTRL_PCS_TIB		0x0400
+#define  USER_ODIG_CTRL_PCS_RI		0x0200
+#define  USER_ODIG_CTRL_RESV1		0x0180
+#define  USER_ODIG_CTRL_GPIOS		0x0060
+#define  USER_ODIG_CTRL_GPIOS_SHIFT	5
+#define  USER_ODIG_CTRL_RESV2		0x0010
+#define  USER_ODIG_CTRL_LB_ERR_DIS	0x0008
+#define  USER_ODIG_CTRL_RESV3		0x0006
+#define  USER_ODIG_CTRL_TXONOFF_PD_DIS	0x0001
+
+#define BCM8704_PHYXS_XGXS_LANE_STAT	0x0018
+#define  PHYXS_XGXS_LANE_STAT_ALINGED	0x1000
+#define  PHYXS_XGXS_LANE_STAT_PATTEST	0x0800
+#define  PHYXS_XGXS_LANE_STAT_MAGIC	0x0400
+#define  PHYXS_XGXS_LANE_STAT_LANE3	0x0008
+#define  PHYXS_XGXS_LANE_STAT_LANE2	0x0004
+#define  PHYXS_XGXS_LANE_STAT_LANE1	0x0002
+#define  PHYXS_XGXS_LANE_STAT_LANE0	0x0001
+
+#define BCM5464R_AUX_CTL		24
+#define  BCM5464R_AUX_CTL_EXT_LB	0x8000
+#define  BCM5464R_AUX_CTL_EXT_PLEN	0x4000
+#define  BCM5464R_AUX_CTL_ER1000	0x3000
+#define  BCM5464R_AUX_CTL_ER1000_SHIFT	12
+#define  BCM5464R_AUX_CTL_RESV1		0x0800
+#define  BCM5464R_AUX_CTL_WRITE_1	0x0400
+#define  BCM5464R_AUX_CTL_RESV2		0x0300
+#define  BCM5464R_AUX_CTL_PRESP_DIS	0x0080
+#define  BCM5464R_AUX_CTL_RESV3		0x0040
+#define  BCM5464R_AUX_CTL_ER100		0x0030
+#define  BCM5464R_AUX_CTL_ER100_SHIFT	4
+#define  BCM5464R_AUX_CTL_DIAG_MODE	0x0008
+#define  BCM5464R_AUX_CTL_SR_SEL	0x0007
+#define  BCM5464R_AUX_CTL_SR_SEL_SHIFT	0
+
+#define  BCM5464R_CTRL1000_AS_MASTER		0x0800
+#define  BCM5464R_CTRL1000_ENABLE_AS_MASTER	0x1000
+
+#define RCR_ENTRY_MULTI			0x8000000000000000ULL
+#define RCR_ENTRY_PKT_TYPE		0x6000000000000000ULL
+#define RCR_ENTRY_PKT_TYPE_SHIFT	61
+#define RCR_ENTRY_ZERO_COPY		0x1000000000000000ULL
+#define RCR_ENTRY_NOPORT		0x0800000000000000ULL
+#define RCR_ENTRY_PROMISC		0x0400000000000000ULL
+#define RCR_ENTRY_ERROR			0x0380000000000000ULL
+#define RCR_ENTRY_DCF_ERR		0x0040000000000000ULL
+#define RCR_ENTRY_L2_LEN		0x003fff0000000000ULL
+#define RCR_ENTRY_L2_LEN_SHIFT		40
+#define RCR_ENTRY_PKTBUFSZ		0x000000c000000000ULL
+#define RCR_ENTRY_PKTBUFSZ_SHIFT	38
+#define RCR_ENTRY_PKT_BUF_ADDR		0x0000003fffffffffULL /* bits 43:6 */
+#define RCR_ENTRY_PKT_BUF_ADDR_SHIFT	6
+
+#define RCR_PKT_TYPE_OTHER		0x0
+#define RCR_PKT_TYPE_TCP		0x1
+#define RCR_PKT_TYPE_UDP		0x2
+#define RCR_PKT_TYPE_SCTP		0x3
+
+#define NIU_RXPULL_MAX			ETH_HLEN
+
+struct rx_pkt_hdr0 {
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u8	inputport:2,
+		maccheck:1,
+		class:4;
+	u8	vlan:1,
+		llcsnap:1,
+		noport:1,
+		badip:1,
+		tcamhit:1,
+		tres:2,
+		tzfvld:1;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	u8	class:4,
+		maccheck:1,
+		inputport:2;
+	u8	tzfvld:1,
+		tres:2,
+		tcamhit:1,
+		badip:1,
+		noport:1,
+		llcsnap:1,
+		vlan:1;
+#endif
+};
+
+struct rx_pkt_hdr1 {
+	u8	hwrsvd1;
+	u8	tcammatch;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u8	hwrsvd2:2,
+		hashit:1,
+		exact:1,
+		hzfvld:1,
+		hashsidx:3;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	u8	hashsidx:3,
+		hzfvld:1,
+		exact:1,
+		hashit:1,
+		hwrsvd2:2;
+#endif
+	u8	zcrsvd;
+
+	/* Bits 11:8 of zero copy flow ID.  */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u8	hwrsvd3:4, zflowid0:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	u8	zflowid0:4, hwrsvd3:4;
+#endif
+
+	/* Bits 7:0 of zero copy flow ID.  */
+	u8	zflowid1;
+
+	/* Bits 15:8 of hash value, H2.  */
+	u8	hashval2_0;
+
+	/* Bits 7:0 of hash value, H2.  */
+	u8	hashval2_1;
+
+	/* Bits 19:16 of hash value, H1.  */
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+	u8	hwrsvd4:4, hashval1_0:4;
+#elif defined(__BIG_ENDIAN_BITFIELD)
+	u8	hashval1_0:4, hwrsvd4:4;
+#endif
+
+	/* Bits 15:8 of hash value, H1.  */
+	u8	hashval1_1;
+
+	/* Bits 7:0 of hash value, H1.  */
+	u8	hashval1_2;
+
+	u8	usrdata_0;	/* Bits 39:32 of user data.  */
+	u8	usrdata_1;	/* Bits 31:24 of user data.  */
+	u8	usrdata_2;	/* Bits 23:16 of user data.  */
+	u8	usrdata_3;	/* Bits 15:8 of user data.  */
+	u8	usrdata_4;	/* Bits 7:0 of user data.  */
+};
+
+struct tx_dma_mbox {
+	u64	tx_dma_pre_st;
+	u64	tx_cs;
+	u64	tx_ring_kick;
+	u64	tx_ring_hdl;
+	u64	resv1;
+	u32	tx_rng_err_logl;
+	u32	tx_rng_err_logh;
+	u64	resv2;
+	u64	resv3;
+};
+
+struct tx_pkt_hdr {
+	__le64	flags;
+#define TXHDR_PAD		0x0000000000000007ULL
+#define  TXHDR_PAD_SHIFT	0
+#define TXHDR_LEN		0x000000003fff0000ULL
+#define  TXHDR_LEN_SHIFT	16
+#define TXHDR_L4STUFF		0x0000003f00000000ULL
+#define  TXHDR_L4STUFF_SHIFT	32
+#define TXHDR_L4START		0x00003f0000000000ULL
+#define  TXHDR_L4START_SHIFT	40
+#define TXHDR_L3START		0x000f000000000000ULL
+#define  TXHDR_L3START_SHIFT	48
+#define TXHDR_IHL		0x00f0000000000000ULL
+#define  TXHDR_IHL_SHIFT	52
+#define TXHDR_VLAN		0x0100000000000000ULL
+#define TXHDR_LLC		0x0200000000000000ULL
+#define TXHDR_IP_VER		0x2000000000000000ULL
+#define TXHDR_CSUM_NONE		0x0000000000000000ULL
+#define TXHDR_CSUM_TCP		0x4000000000000000ULL
+#define TXHDR_CSUM_UDP		0x8000000000000000ULL
+#define TXHDR_CSUM_SCTP		0xc000000000000000ULL
+	__le64	resv;
+};
+
+#define TX_DESC_SOP		0x8000000000000000ULL
+#define TX_DESC_MARK		0x4000000000000000ULL
+#define TX_DESC_NUM_PTR		0x3c00000000000000ULL
+#define TX_DESC_NUM_PTR_SHIFT	58
+#define TX_DESC_TR_LEN		0x01fff00000000000ULL
+#define TX_DESC_TR_LEN_SHIFT	44
+#define TX_DESC_SAD		0x00000fffffffffffULL
+#define TX_DESC_SAD_SHIFT	0
+
+struct tx_buff_info {
+	struct sk_buff *skb;
+	u64 mapping;
+};
+
+struct txdma_mailbox {
+	__le64	tx_dma_pre_st;
+	__le64	tx_cs;
+	__le64	tx_ring_kick;
+	__le64	tx_ring_hdl;
+	__le64	resv1;
+	__le32	tx_rng_err_logl;
+	__le32	tx_rng_err_logh;
+	__le64	resv2[2];
+} __attribute__((aligned(64)));
+
+#define MAX_TX_RING_SIZE	256
+#define MAX_TX_DESC_LEN		4076
+
+struct tx_ring_info {
+	struct tx_buff_info	tx_buffs[MAX_TX_RING_SIZE];
+	struct niu		*np;
+	u64			tx_cs;
+	int			pending;
+	int			prod;
+	int			cons;
+	int			wrap_bit;
+	u16			last_pkt_cnt;
+	u16			tx_channel;
+	u16			mark_counter;
+	u16			mark_freq;
+	u16			mark_pending;
+	u16			__pad;
+	struct txdma_mailbox	*mbox;
+	__le64			*descr;
+
+	u64			tx_packets;
+	u64			tx_bytes;
+	u64			tx_errors;
+
+	u64			mbox_dma;
+	u64			descr_dma;
+	int			max_burst;
+};
+
+#define NEXT_TX(tp, index) \
+	(((index) + 1) < (tp)->pending ? ((index) + 1) : 0)
+
+static inline u32 niu_tx_avail(struct tx_ring_info *tp)
+{
+	return (tp->pending -
+		((tp->prod - tp->cons) & (MAX_TX_RING_SIZE - 1)));
+}
+
+struct rxdma_mailbox {
+	__le64	rx_dma_ctl_stat;
+	__le64	rbr_stat;
+	__le32	rbr_hdl;
+	__le32	rbr_hdh;
+	__le64	resv1;
+	__le32	rcrstat_c;
+	__le32	rcrstat_b;
+	__le64	rcrstat_a;
+	__le64	resv2[2];
+} __attribute__((aligned(64)));
+
+#define MAX_RBR_RING_SIZE	128
+#define MAX_RCR_RING_SIZE	(MAX_RBR_RING_SIZE * 2)
+
+#define RBR_REFILL_MIN		16
+
+#define RX_SKB_ALLOC_SIZE	128 + NET_IP_ALIGN
+
+struct rx_ring_info {
+	struct niu		*np;
+	int			rx_channel;
+	u16			rbr_block_size;
+	u16			rbr_blocks_per_page;
+	u16			rbr_sizes[4];
+	unsigned int		rcr_index;
+	unsigned int		rcr_table_size;
+	unsigned int		rbr_index;
+	unsigned int		rbr_pending;
+	unsigned int		rbr_refill_pending;
+	unsigned int		rbr_kick_thresh;
+	unsigned int		rbr_table_size;
+	struct page		**rxhash;
+	struct rxdma_mailbox	*mbox;
+	__le64			*rcr;
+	__le32			*rbr;
+#define RBR_DESCR_ADDR_SHIFT	12
+
+	u64			rx_packets;
+	u64			rx_bytes;
+	u64			rx_dropped;
+	u64			rx_errors;
+
+	u64			mbox_dma;
+	u64			rcr_dma;
+	u64			rbr_dma;
+
+	/* WRED */
+	int			nonsyn_window;
+	int			nonsyn_threshold;
+	int			syn_window;
+	int			syn_threshold;
+
+	/* interrupt mitigation */
+	int			rcr_pkt_threshold;
+	int			rcr_timeout;
+};
+
+#define NEXT_RCR(rp, index) \
+	(((index) + 1) < (rp)->rcr_table_size ? ((index) + 1) : 0)
+#define NEXT_RBR(rp, index) \
+	(((index) + 1) < (rp)->rbr_table_size ? ((index) + 1) : 0)
+
+#define NIU_MAX_PORTS		4
+#define NIU_NUM_RXCHAN		16
+#define NIU_NUM_TXCHAN		24
+#define MAC_NUM_HASH		16
+
+#define NIU_MAX_MTU		9216
+
+#define NIU_VPD_MIN_MAJOR	3
+#define NIU_VPD_MIN_MINOR	4
+
+#define NIU_VPD_MODEL_MAX	32
+#define NIU_VPD_BD_MODEL_MAX	16
+#define NIU_VPD_VERSION_MAX	64
+#define NIU_VPD_PHY_TYPE_MAX	8
+
+struct niu_vpd {
+	char			model[NIU_VPD_MODEL_MAX];
+	char			board_model[NIU_VPD_BD_MODEL_MAX];
+	char			version[NIU_VPD_VERSION_MAX];
+	char			phy_type[NIU_VPD_PHY_TYPE_MAX];
+	u8			mac_num;
+	u8			__pad;
+	u8			local_mac[6];
+	int			fcode_major;
+	int			fcode_minor;
+};
+
+struct niu_altmac_rdc {
+	u8			alt_mac_num;
+	u8			rdc_num;
+	u8			mac_pref;
+};
+
+struct niu_vlan_rdc {
+	u8			rdc_num;
+	u8			vlan_pref;
+};
+
+struct niu_classifier {
+	struct niu_altmac_rdc	alt_mac_mappings[16];
+	struct niu_vlan_rdc	vlan_mappings[ENET_VLAN_TBL_NUM_ENTRIES];
+
+	u16			tcam_index;
+	u16			num_alt_mac_mappings;
+
+	u32			h1_init;
+	u16			h2_init;
+};
+
+#define NIU_NUM_RDC_TABLES	8
+#define NIU_RDC_TABLE_SLOTS	16
+
+struct rdc_table {
+	u8			rxdma_channel[NIU_RDC_TABLE_SLOTS];
+};
+
+struct niu_rdc_tables {
+	struct rdc_table	tables[NIU_NUM_RDC_TABLES];
+	int			first_table_num;
+	int			num_tables;
+};
+
+#define PHY_TYPE_PMA_PMD	0
+#define PHY_TYPE_PCS		1
+#define PHY_TYPE_MII		2
+#define PHY_TYPE_MAX		3
+
+struct phy_probe_info {
+	u32	phy_id[PHY_TYPE_MAX][NIU_MAX_PORTS];
+	u8	phy_port[PHY_TYPE_MAX][NIU_MAX_PORTS];
+	u8	cur[PHY_TYPE_MAX];
+
+	struct device_attribute	phy_port_attrs[PHY_TYPE_MAX * NIU_MAX_PORTS];
+	struct device_attribute	phy_type_attrs[PHY_TYPE_MAX * NIU_MAX_PORTS];
+	struct device_attribute	phy_id_attrs[PHY_TYPE_MAX * NIU_MAX_PORTS];
+};
+
+struct niu_tcam_entry {
+	u64			key[4];
+	u64			key_mask[4];
+	u64			assoc_data;
+};
+
+struct device_node;
+union niu_parent_id {
+	struct {
+		int		domain;
+		int		bus;
+		int		device;
+	} pci;
+	struct device_node	*of;
+};
+
+struct niu;
+struct niu_parent {
+	struct platform_device	*plat_dev;
+	int			index;
+
+	union niu_parent_id	id;
+
+	struct niu		*ports[NIU_MAX_PORTS];
+
+	atomic_t		refcnt;
+	struct list_head	list;
+
+	spinlock_t		lock;
+
+	u32			flags;
+#define PARENT_FLGS_CLS_HWINIT	0x00000001
+
+	u32			port_phy;
+#define PORT_PHY_UNKNOWN	0x00000000
+#define PORT_PHY_INVALID	0xffffffff
+#define PORT_TYPE_10G		0x01
+#define PORT_TYPE_1G		0x02
+#define PORT_TYPE_MASK		0x03
+
+	u8			rxchan_per_port[NIU_MAX_PORTS];
+	u8			txchan_per_port[NIU_MAX_PORTS];
+
+	struct niu_rdc_tables	rdc_group_cfg[NIU_MAX_PORTS];
+	u8			rdc_default[NIU_MAX_PORTS];
+
+	u8			ldg_map[LDN_MAX + 1];
+
+	u8			plat_type;
+#define PLAT_TYPE_INVALID	0x00
+#define PLAT_TYPE_ATLAS		0x01
+#define PLAT_TYPE_NIU		0x02
+#define PLAT_TYPE_VF_P0		0x03
+#define PLAT_TYPE_VF_P1		0x04
+
+	u8			num_ports;
+
+	u16			tcam_num_entries;
+#define NIU_PCI_TCAM_ENTRIES	256
+#define NIU_NONPCI_TCAM_ENTRIES	128
+#define NIU_TCAM_ENTRIES_MAX	256
+
+	int			rxdma_clock_divider;
+
+	struct phy_probe_info	phy_probe_info;
+
+	struct niu_tcam_entry	tcam[NIU_TCAM_ENTRIES_MAX];
+	u64			l2_cls[2];
+	u64			l3_cls[4];
+	u64			tcam_key[12];
+	u64			flow_key[12];
+};
+
+struct niu_ops {
+	void *(*alloc_coherent)(struct device *dev, size_t size,
+				u64 *handle, gfp_t flag);
+	void (*free_coherent)(struct device *dev, size_t size,
+			      void *cpu_addr, u64 handle);
+	u64 (*map_page)(struct device *dev, struct page *page,
+			unsigned long offset, size_t size,
+			enum dma_data_direction direction);
+	void (*unmap_page)(struct device *dev, u64 dma_address,
+			   size_t size, enum dma_data_direction direction);
+	u64 (*map_single)(struct device *dev, void *cpu_addr,
+			  size_t size,
+			  enum dma_data_direction direction);
+	void (*unmap_single)(struct device *dev, u64 dma_address,
+			     size_t size, enum dma_data_direction direction);
+};
+
+struct niu_link_config {
+	/* Describes what we're trying to get. */
+	u32				advertising;
+	u32				supported;
+	u16				speed;
+	u8				duplex;
+	u8				autoneg;
+
+	/* Describes what we actually have. */
+	u16				active_speed;
+	u8				active_duplex;
+#define SPEED_INVALID		0xffff
+#define DUPLEX_INVALID		0xff
+#define AUTONEG_INVALID		0xff
+
+	u8				loopback_mode;
+#define LOOPBACK_DISABLED	0x00
+#define LOOPBACK_PHY		0x01
+#define LOOPBACK_MAC		0x02
+};
+
+struct niu_ldg {
+	struct napi_struct	napi;
+	struct niu	*np;
+	u8		ldg_num;
+	u8		timer;
+	u64		v0, v1, v2;
+	unsigned int	irq;
+};
+
+struct niu_xmac_stats {
+	u64	tx_frames;
+	u64	tx_bytes;
+	u64	tx_fifo_errors;
+	u64	tx_overflow_errors;
+	u64	tx_max_pkt_size_errors;
+	u64	tx_underflow_errors;
+
+	u64	rx_local_faults;
+	u64	rx_remote_faults;
+	u64	rx_link_faults;
+	u64	rx_align_errors;
+	u64	rx_frags;
+	u64	rx_mcasts;
+	u64	rx_bcasts;
+	u64	rx_hist_cnt1;
+	u64	rx_hist_cnt2;
+	u64	rx_hist_cnt3;
+	u64	rx_hist_cnt4;
+	u64	rx_hist_cnt5;
+	u64	rx_hist_cnt6;
+	u64	rx_hist_cnt7;
+	u64	rx_octets;
+	u64	rx_code_violations;
+	u64	rx_len_errors;
+	u64	rx_crc_errors;
+	u64	rx_underflows;
+	u64	rx_overflows;
+
+	u64	pause_off_state;
+	u64	pause_on_state;
+	u64	pause_received;
+};
+
+struct niu_bmac_stats {
+	u64	tx_underflow_errors;
+	u64	tx_max_pkt_size_errors;
+	u64	tx_bytes;
+	u64	tx_frames;
+
+	u64	rx_overflows;
+	u64	rx_frames;
+	u64	rx_align_errors;
+	u64	rx_crc_errors;
+	u64	rx_len_errors;
+
+	u64	pause_off_state;
+	u64	pause_on_state;
+	u64	pause_received;
+};
+
+union niu_mac_stats {
+	struct niu_xmac_stats	xmac;
+	struct niu_bmac_stats	bmac;
+};
+
+struct niu_phy_ops {
+	int (*serdes_init)(struct niu *np);
+	int (*xcvr_init)(struct niu *np);
+	int (*link_status)(struct niu *np, int *);
+};
+
+struct of_device;
+struct niu {
+	void __iomem			*regs;
+	struct net_device		*dev;
+	struct pci_dev			*pdev;
+	struct device			*device;
+	struct niu_parent		*parent;
+
+	u32				flags;
+#define NIU_FLAGS_MSIX			0x00400000 /* MSI-X in use */
+#define NIU_FLAGS_MCAST			0x00200000 /* multicast filter enabled */
+#define NIU_FLAGS_PROMISC		0x00100000 /* PROMISC enabled */
+#define NIU_FLAGS_VPD_VALID		0x00080000 /* VPD has valid version */
+#define NIU_FLAGS_10G			0x00040000 /* 0=1G 1=10G */
+#define NIU_FLAGS_FIBER			0x00020000 /* 0=COPPER 1=FIBER */
+#define NIU_FLAGS_XMAC			0x00010000 /* 0=BMAC 1=XMAC */
+
+	u32				msg_enable;
+
+	/* Protects hw programming, and ring state.  */
+	spinlock_t			lock;
+
+	const struct niu_ops		*ops;
+	struct net_device_stats		net_stats;
+	union niu_mac_stats		mac_stats;
+
+	struct rx_ring_info		*rx_rings;
+	struct tx_ring_info		*tx_rings;
+	int				num_rx_rings;
+	int				num_tx_rings;
+
+	struct niu_ldg			ldg[NIU_NUM_LDG];
+	int				num_ldg;
+
+	void __iomem			*mac_regs;
+	unsigned long			ipp_off;
+	unsigned long			pcs_off;
+	unsigned long			xpcs_off;
+
+	struct timer_list		timer;
+	const struct niu_phy_ops	*phy_ops;
+	int				phy_addr;
+
+	struct niu_link_config		link_config;
+
+	struct work_struct		reset_task;
+
+	u8				port;
+	u8				mac_xcvr;
+#define MAC_XCVR_MII			1
+#define MAC_XCVR_PCS			2
+#define MAC_XCVR_XPCS			3
+
+	struct niu_classifier		clas;
+
+	struct niu_vpd			vpd;
+	u32				eeprom_len;
+
+	struct of_device		*op;
+	void __iomem			*vir_regs_1;
+	void __iomem			*vir_regs_2;
+};
+
+#endif /* _NIU_H */
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 104aab3..ea71f6d 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -1,4 +1,4 @@
-#define VERSION "0.22"
+#define VERSION "0.23"
 /* ns83820.c by Benjamin LaHaise with contributions.
  *
  * Questions/comments/discussion to linux-ns83820@kvack.org.
@@ -1247,6 +1247,149 @@
 	return &dev->stats;
 }
 
+/* Let ethtool retrieve info */
+static int ns83820_get_settings(struct net_device *ndev,
+				struct ethtool_cmd *cmd)
+{
+	struct ns83820 *dev = PRIV(ndev);
+	u32 cfg, tanar, tbicr;
+	int have_optical = 0;
+	int fullduplex   = 0;
+
+	/*
+	 * Here's the list of available ethtool commands from other drivers:
+	 *	cmd->advertising =
+	 *	cmd->speed =
+	 *	cmd->duplex =
+	 *	cmd->port = 0;
+	 *	cmd->phy_address =
+	 *	cmd->transceiver = 0;
+	 *	cmd->autoneg =
+	 *	cmd->maxtxpkt = 0;
+	 *	cmd->maxrxpkt = 0;
+	 */
+
+	/* read current configuration */
+	cfg   = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
+	tanar = readl(dev->base + TANAR);
+	tbicr = readl(dev->base + TBICR);
+
+	if (dev->CFG_cache & CFG_TBI_EN) {
+		/* we have an optical interface */
+		have_optical = 1;
+		fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0;
+
+	} else {
+		/* We have copper */
+		fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0;
+        }
+
+	cmd->supported = SUPPORTED_Autoneg;
+
+	/* we have optical interface */
+	if (dev->CFG_cache & CFG_TBI_EN) {
+		cmd->supported |= SUPPORTED_1000baseT_Half |
+					SUPPORTED_1000baseT_Full |
+					SUPPORTED_FIBRE;
+		cmd->port       = PORT_FIBRE;
+	} /* TODO: else copper related  support */
+
+	cmd->duplex = fullduplex ? DUPLEX_FULL : DUPLEX_HALF;
+	switch (cfg / CFG_SPDSTS0 & 3) {
+	case 2:
+		cmd->speed = SPEED_1000;
+		break;
+	case 1:
+		cmd->speed = SPEED_100;
+		break;
+	default:
+		cmd->speed = SPEED_10;
+		break;
+	}
+	cmd->autoneg = (tbicr & TBICR_MR_AN_ENABLE) ? 1: 0;
+	return 0;
+}
+
+/* Let ethool change settings*/
+static int ns83820_set_settings(struct net_device *ndev,
+				struct ethtool_cmd *cmd)
+{
+	struct ns83820 *dev = PRIV(ndev);
+	u32 cfg, tanar;
+	int have_optical = 0;
+	int fullduplex   = 0;
+
+	/* read current configuration */
+	cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY;
+	tanar = readl(dev->base + TANAR);
+
+	if (dev->CFG_cache & CFG_TBI_EN) {
+		/* we have optical */
+		have_optical = 1;
+		fullduplex   = (tanar & TANAR_FULL_DUP);
+
+	} else {
+		/* we have copper */
+		fullduplex = cfg & CFG_DUPSTS;
+	}
+
+	spin_lock_irq(&dev->misc_lock);
+	spin_lock(&dev->tx_lock);
+
+	/* Set duplex */
+	if (cmd->duplex != fullduplex) {
+		if (have_optical) {
+			/*set full duplex*/
+			if (cmd->duplex == DUPLEX_FULL) {
+				/* force full duplex */
+				writel(readl(dev->base + TXCFG)
+					| TXCFG_CSI | TXCFG_HBI | TXCFG_ATP,
+					dev->base + TXCFG);
+				writel(readl(dev->base + RXCFG) | RXCFG_RX_FD,
+					dev->base + RXCFG);
+				/* Light up full duplex LED */
+				writel(readl(dev->base + GPIOR) | GPIOR_GP1_OUT,
+					dev->base + GPIOR);
+			} else {
+				/*TODO: set half duplex */
+			}
+
+		} else {
+			/*we have copper*/
+			/* TODO: Set duplex for copper cards */
+		}
+		printk(KERN_INFO "%s: Duplex set via ethtool\n",
+		ndev->name);
+	}
+
+	/* Set autonegotiation */
+	if (1) {
+		if (cmd->autoneg == AUTONEG_ENABLE) {
+			/* restart auto negotiation */
+			writel(TBICR_MR_AN_ENABLE | TBICR_MR_RESTART_AN,
+				dev->base + TBICR);
+			writel(TBICR_MR_AN_ENABLE, dev->base + TBICR);
+				dev->linkstate = LINK_AUTONEGOTIATE;
+
+			printk(KERN_INFO "%s: autoneg enabled via ethtool\n",
+				ndev->name);
+		} else {
+			/* disable auto negotiation */
+			writel(0x00000000, dev->base + TBICR);
+		}
+
+		printk(KERN_INFO "%s: autoneg %s via ethtool\n", ndev->name,
+				cmd->autoneg ? "ENABLED" : "DISABLED");
+	}
+
+	phy_intr(ndev);
+	spin_unlock(&dev->tx_lock);
+	spin_unlock_irq(&dev->misc_lock);
+
+	return 0;
+}
+/* end ethtool get/set support -df */
+
 static void ns83820_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
 {
 	struct ns83820 *dev = PRIV(ndev);
@@ -1263,8 +1406,10 @@
 }
 
 static const struct ethtool_ops ops = {
-	.get_drvinfo = ns83820_get_drvinfo,
-	.get_link = ns83820_get_link
+	.get_settings    = ns83820_get_settings,
+	.set_settings    = ns83820_set_settings,
+	.get_drvinfo     = ns83820_get_drvinfo,
+	.get_link        = ns83820_get_link
 };
 
 /* this function is called in irq context from the ISR */
@@ -1582,7 +1727,7 @@
 	else
 		and_mask &= ~(RFCR_AAU | RFCR_AAM);
 
-	if (ndev->flags & IFF_ALLMULTI)
+	if (ndev->flags & IFF_ALLMULTI || ndev->mc_count)
 		or_mask |= RFCR_AAM;
 	else
 		and_mask &= ~RFCR_AAM;
@@ -1817,6 +1962,7 @@
 	long addr;
 	int err;
 	int using_dac = 0;
+	DECLARE_MAC_BUF(mac);
 
 	/* See if we can set the dma mask early on; failure is fatal. */
 	if (sizeof(dma_addr_t) == 8 &&
@@ -1843,7 +1989,6 @@
 	spin_lock_init(&dev->misc_lock);
 	dev->pci_dev = pci_dev;
 
-	SET_MODULE_OWNER(ndev);
 	SET_NETDEV_DEV(ndev, &pci_dev->dev);
 
 	INIT_WORK(&dev->tq_refill, queue_refill);
@@ -2082,13 +2227,11 @@
 		ndev->features |= NETIF_F_HIGHDMA;
 	}
 
-	printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %02x:%02x:%02x:%02x:%02x:%02x io=0x%08lx irq=%d f=%s\n",
+	printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %s io=0x%08lx irq=%d f=%s\n",
 		ndev->name,
 		(unsigned)readl(dev->base + SRR) >> 8,
 		(unsigned)readl(dev->base + SRR) & 0xff,
-		ndev->dev_addr[0], ndev->dev_addr[1],
-		ndev->dev_addr[2], ndev->dev_addr[3],
-		ndev->dev_addr[4], ndev->dev_addr[5],
+		print_mac(mac, ndev->dev_addr),
 		addr, pci_dev->irq,
 		(ndev->features & NETIF_F_HIGHDMA) ? "h,sg" : "sg"
 		);
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index 0b3066a..9f9a421 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -34,24 +34,29 @@
 #include <net/checksum.h>
 
 #include <asm/irq.h>
+#include <asm/firmware.h>
 
 #include "pasemi_mac.h"
 
+/* We have our own align, since ppc64 in general has it at 0 because
+ * of design flaws in some of the server bridge chips. However, for
+ * PWRficient doing the unaligned copies is more expensive than doing
+ * unaligned DMA, so make sure the data is aligned instead.
+ */
+#define LOCAL_SKB_ALIGN	2
 
 /* TODO list
  *
- * - Get rid of pci_{read,write}_config(), map registers with ioremap
- *   for performance
- * - PHY support
  * - Multicast support
  * - Large MTU support
- * - Other performance improvements
+ * - SW LRO
+ * - Multiqueue RX/TX
  */
 
 
 /* Must be a power of two */
-#define RX_RING_SIZE 512
-#define TX_RING_SIZE 512
+#define RX_RING_SIZE 4096
+#define TX_RING_SIZE 4096
 
 #define DEFAULT_MSG_ENABLE	  \
 	(NETIF_MSG_DRV		| \
@@ -63,12 +68,16 @@
 	 NETIF_MSG_RX_ERR	| \
 	 NETIF_MSG_TX_ERR)
 
-#define TX_DESC(mac, num)	((mac)->tx->desc[(num) & (TX_RING_SIZE-1)])
-#define TX_DESC_INFO(mac, num)	((mac)->tx->desc_info[(num) & (TX_RING_SIZE-1)])
-#define RX_DESC(mac, num)	((mac)->rx->desc[(num) & (RX_RING_SIZE-1)])
-#define RX_DESC_INFO(mac, num)	((mac)->rx->desc_info[(num) & (RX_RING_SIZE-1)])
+#define TX_RING(mac, num)	((mac)->tx->ring[(num) & (TX_RING_SIZE-1)])
+#define TX_RING_INFO(mac, num)	((mac)->tx->ring_info[(num) & (TX_RING_SIZE-1)])
+#define RX_RING(mac, num)	((mac)->rx->ring[(num) & (RX_RING_SIZE-1)])
+#define RX_RING_INFO(mac, num)	((mac)->rx->ring_info[(num) & (RX_RING_SIZE-1)])
 #define RX_BUFF(mac, num)	((mac)->rx->buffers[(num) & (RX_RING_SIZE-1)])
 
+#define RING_USED(ring)		(((ring)->next_to_fill - (ring)->next_to_clean) \
+				 & ((ring)->size - 1))
+#define RING_AVAIL(ring)	((ring->size) - RING_USED(ring))
+
 #define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
 
 MODULE_LICENSE("GPL");
@@ -81,6 +90,43 @@
 
 static struct pasdma_status *dma_status;
 
+static int translation_enabled(void)
+{
+#if defined(CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE)
+	return 1;
+#else
+	return firmware_has_feature(FW_FEATURE_LPAR);
+#endif
+}
+
+static void write_iob_reg(struct pasemi_mac *mac, unsigned int reg,
+			  unsigned int val)
+{
+	out_le32(mac->iob_regs+reg, val);
+}
+
+static unsigned int read_mac_reg(struct pasemi_mac *mac, unsigned int reg)
+{
+	return in_le32(mac->regs+reg);
+}
+
+static void write_mac_reg(struct pasemi_mac *mac, unsigned int reg,
+			  unsigned int val)
+{
+	out_le32(mac->regs+reg, val);
+}
+
+static unsigned int read_dma_reg(struct pasemi_mac *mac, unsigned int reg)
+{
+	return in_le32(mac->dma_regs+reg);
+}
+
+static void write_dma_reg(struct pasemi_mac *mac, unsigned int reg,
+			  unsigned int val)
+{
+	out_le32(mac->dma_regs+reg, val);
+}
+
 static int pasemi_get_mac_addr(struct pasemi_mac *mac)
 {
 	struct pci_dev *pdev = mac->pdev;
@@ -128,11 +174,36 @@
 	return 0;
 }
 
+static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac,
+				    struct sk_buff *skb,
+				    dma_addr_t *dmas)
+{
+	int f;
+	int nfrags = skb_shinfo(skb)->nr_frags;
+
+	pci_unmap_single(mac->dma_pdev, dmas[0], skb_headlen(skb),
+			 PCI_DMA_TODEVICE);
+
+	for (f = 0; f < nfrags; f++) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[f];
+
+		pci_unmap_page(mac->dma_pdev, dmas[f+1], frag->size,
+			       PCI_DMA_TODEVICE);
+	}
+	dev_kfree_skb_irq(skb);
+
+	/* Freed descriptor slot + main SKB ptr + nfrags additional ptrs,
+	 * aligned up to a power of 2
+	 */
+	return (nfrags + 3) & ~1;
+}
+
 static int pasemi_mac_setup_rx_resources(struct net_device *dev)
 {
 	struct pasemi_mac_rxring *ring;
 	struct pasemi_mac *mac = netdev_priv(dev);
 	int chan_id = mac->dma_rxch;
+	unsigned int cfg;
 
 	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
 
@@ -141,22 +212,22 @@
 
 	spin_lock_init(&ring->lock);
 
-	ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+	ring->size = RX_RING_SIZE;
+	ring->ring_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
 				  RX_RING_SIZE, GFP_KERNEL);
 
-	if (!ring->desc_info)
-		goto out_desc_info;
+	if (!ring->ring_info)
+		goto out_ring_info;
 
 	/* Allocate descriptors */
-	ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
-					RX_RING_SIZE *
-					sizeof(struct pas_dma_xct_descr),
+	ring->ring = dma_alloc_coherent(&mac->dma_pdev->dev,
+					RX_RING_SIZE * sizeof(u64),
 					&ring->dma, GFP_KERNEL);
 
-	if (!ring->desc)
-		goto out_desc;
+	if (!ring->ring)
+		goto out_ring_desc;
 
-	memset(ring->desc, 0, RX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+	memset(ring->ring, 0, RX_RING_SIZE * sizeof(u64));
 
 	ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev,
 					   RX_RING_SIZE * sizeof(u64),
@@ -166,22 +237,34 @@
 
 	memset(ring->buffers, 0, RX_RING_SIZE * sizeof(u64));
 
-	pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEL(chan_id),
-			       PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma));
+	write_dma_reg(mac, PAS_DMA_RXCHAN_BASEL(chan_id), PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma));
 
-	pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEU(chan_id),
-			       PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) |
-			       PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2));
+	write_dma_reg(mac, PAS_DMA_RXCHAN_BASEU(chan_id),
+			   PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) |
+			   PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 3));
 
-	pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_CFG(chan_id),
-			       PAS_DMA_RXCHAN_CFG_HBU(1));
+	cfg = PAS_DMA_RXCHAN_CFG_HBU(2);
 
-	pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEL(mac->dma_if),
-			       PAS_DMA_RXINT_BASEL_BRBL(__pa(ring->buffers)));
+	if (translation_enabled())
+		cfg |= PAS_DMA_RXCHAN_CFG_CTR;
 
-	pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEU(mac->dma_if),
-			       PAS_DMA_RXINT_BASEU_BRBH(__pa(ring->buffers) >> 32) |
-			       PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3));
+	write_dma_reg(mac, PAS_DMA_RXCHAN_CFG(chan_id), cfg);
+
+	write_dma_reg(mac, PAS_DMA_RXINT_BASEL(mac->dma_if),
+			   PAS_DMA_RXINT_BASEL_BRBL(ring->buf_dma));
+
+	write_dma_reg(mac, PAS_DMA_RXINT_BASEU(mac->dma_if),
+			   PAS_DMA_RXINT_BASEU_BRBH(ring->buf_dma >> 32) |
+			   PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3));
+
+	cfg = PAS_DMA_RXINT_CFG_DHL(3) | PAS_DMA_RXINT_CFG_L2 |
+	      PAS_DMA_RXINT_CFG_LW | PAS_DMA_RXINT_CFG_RBP |
+	      PAS_DMA_RXINT_CFG_HEN;
+
+	if (translation_enabled())
+		cfg |= PAS_DMA_RXINT_CFG_ITRR | PAS_DMA_RXINT_CFG_ITR;
+
+	write_dma_reg(mac, PAS_DMA_RXINT_CFG(mac->dma_if), cfg);
 
 	ring->next_to_fill = 0;
 	ring->next_to_clean = 0;
@@ -194,11 +277,11 @@
 
 out_buffers:
 	dma_free_coherent(&mac->dma_pdev->dev,
-			  RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
-			  mac->rx->desc, mac->rx->dma);
-out_desc:
-	kfree(ring->desc_info);
-out_desc_info:
+			  RX_RING_SIZE * sizeof(u64),
+			  mac->rx->ring, mac->rx->dma);
+out_ring_desc:
+	kfree(ring->ring_info);
+out_ring_info:
 	kfree(ring);
 out_ring:
 	return -ENOMEM;
@@ -211,6 +294,7 @@
 	u32 val;
 	int chan_id = mac->dma_txch;
 	struct pasemi_mac_txring *ring;
+	unsigned int cfg;
 
 	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
 	if (!ring)
@@ -218,35 +302,39 @@
 
 	spin_lock_init(&ring->lock);
 
-	ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+	ring->size = TX_RING_SIZE;
+	ring->ring_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
 				  TX_RING_SIZE, GFP_KERNEL);
-	if (!ring->desc_info)
-		goto out_desc_info;
+	if (!ring->ring_info)
+		goto out_ring_info;
 
 	/* Allocate descriptors */
-	ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
-					TX_RING_SIZE *
-					sizeof(struct pas_dma_xct_descr),
+	ring->ring = dma_alloc_coherent(&mac->dma_pdev->dev,
+					TX_RING_SIZE * sizeof(u64),
 					&ring->dma, GFP_KERNEL);
-	if (!ring->desc)
-		goto out_desc;
+	if (!ring->ring)
+		goto out_ring_desc;
 
-	memset(ring->desc, 0, TX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+	memset(ring->ring, 0, TX_RING_SIZE * sizeof(u64));
 
-	pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEL(chan_id),
-			       PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma));
+	write_dma_reg(mac, PAS_DMA_TXCHAN_BASEL(chan_id),
+			   PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma));
 	val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32);
-	val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2);
+	val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 3);
 
-	pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEU(chan_id), val);
+	write_dma_reg(mac, PAS_DMA_TXCHAN_BASEU(chan_id), val);
 
-	pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_CFG(chan_id),
-			       PAS_DMA_TXCHAN_CFG_TY_IFACE |
-			       PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) |
-			       PAS_DMA_TXCHAN_CFG_UP |
-			       PAS_DMA_TXCHAN_CFG_WT(2));
+	cfg = PAS_DMA_TXCHAN_CFG_TY_IFACE |
+	      PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) |
+	      PAS_DMA_TXCHAN_CFG_UP |
+	      PAS_DMA_TXCHAN_CFG_WT(2);
 
-	ring->next_to_use = 0;
+	if (translation_enabled())
+		cfg |= PAS_DMA_TXCHAN_CFG_TRD | PAS_DMA_TXCHAN_CFG_TRR;
+
+	write_dma_reg(mac, PAS_DMA_TXCHAN_CFG(chan_id), cfg);
+
+	ring->next_to_fill = 0;
 	ring->next_to_clean = 0;
 
 	snprintf(ring->irq_name, sizeof(ring->irq_name),
@@ -255,9 +343,9 @@
 
 	return 0;
 
-out_desc:
-	kfree(ring->desc_info);
-out_desc_info:
+out_ring_desc:
+	kfree(ring->ring_info);
+out_ring_info:
 	kfree(ring);
 out_ring:
 	return -ENOMEM;
@@ -266,33 +354,37 @@
 static void pasemi_mac_free_tx_resources(struct net_device *dev)
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
-	unsigned int i;
+	unsigned int i, j;
 	struct pasemi_mac_buffer *info;
-	struct pas_dma_xct_descr *dp;
+	dma_addr_t dmas[MAX_SKB_FRAGS+1];
+	int freed;
+	int start, limit;
 
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		info = &TX_DESC_INFO(mac, i);
-		dp = &TX_DESC(mac, i);
-		if (info->dma) {
-			if (info->skb) {
-				pci_unmap_single(mac->dma_pdev,
-						 info->dma,
-						 info->skb->len,
-						 PCI_DMA_TODEVICE);
-				dev_kfree_skb_any(info->skb);
-			}
-			info->dma = 0;
-			info->skb = NULL;
-			dp->mactx = 0;
-			dp->ptr = 0;
-		}
+	start = mac->tx->next_to_clean;
+	limit = mac->tx->next_to_fill;
+
+	/* Compensate for when fill has wrapped and clean has not */
+	if (start > limit)
+		limit += TX_RING_SIZE;
+
+	for (i = start; i < limit; i += freed) {
+		info = &TX_RING_INFO(mac, i+1);
+		if (info->dma && info->skb) {
+			for (j = 0; j <= skb_shinfo(info->skb)->nr_frags; j++)
+				dmas[j] = TX_RING_INFO(mac, i+1+j).dma;
+			freed = pasemi_mac_unmap_tx_skb(mac, info->skb, dmas);
+		} else
+			freed = 2;
 	}
 
-	dma_free_coherent(&mac->dma_pdev->dev,
-			  TX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
-			  mac->tx->desc, mac->tx->dma);
+	for (i = 0; i < TX_RING_SIZE; i++)
+		TX_RING(mac, i) = 0;
 
-	kfree(mac->tx->desc_info);
+	dma_free_coherent(&mac->dma_pdev->dev,
+			  TX_RING_SIZE * sizeof(u64),
+			  mac->tx->ring, mac->tx->dma);
+
+	kfree(mac->tx->ring_info);
 	kfree(mac->tx);
 	mac->tx = NULL;
 }
@@ -302,72 +394,66 @@
 	struct pasemi_mac *mac = netdev_priv(dev);
 	unsigned int i;
 	struct pasemi_mac_buffer *info;
-	struct pas_dma_xct_descr *dp;
 
 	for (i = 0; i < RX_RING_SIZE; i++) {
-		info = &RX_DESC_INFO(mac, i);
-		dp = &RX_DESC(mac, i);
-		if (info->skb) {
-			if (info->dma) {
-				pci_unmap_single(mac->dma_pdev,
-						 info->dma,
-						 info->skb->len,
-						 PCI_DMA_FROMDEVICE);
-				dev_kfree_skb_any(info->skb);
-			}
-			info->dma = 0;
-			info->skb = NULL;
-			dp->macrx = 0;
-			dp->ptr = 0;
+		info = &RX_RING_INFO(mac, i);
+		if (info->skb && info->dma) {
+			pci_unmap_single(mac->dma_pdev,
+					 info->dma,
+					 info->skb->len,
+					 PCI_DMA_FROMDEVICE);
+			dev_kfree_skb_any(info->skb);
 		}
+		info->dma = 0;
+		info->skb = NULL;
 	}
 
+	for (i = 0; i < RX_RING_SIZE; i++)
+		RX_RING(mac, i) = 0;
+
 	dma_free_coherent(&mac->dma_pdev->dev,
-			  RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
-			  mac->rx->desc, mac->rx->dma);
+			  RX_RING_SIZE * sizeof(u64),
+			  mac->rx->ring, mac->rx->dma);
 
 	dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64),
 			  mac->rx->buffers, mac->rx->buf_dma);
 
-	kfree(mac->rx->desc_info);
+	kfree(mac->rx->ring_info);
 	kfree(mac->rx);
 	mac->rx = NULL;
 }
 
-static void pasemi_mac_replenish_rx_ring(struct net_device *dev)
+static void pasemi_mac_replenish_rx_ring(struct net_device *dev, int limit)
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
-	unsigned int i;
-	int start = mac->rx->next_to_fill;
-	unsigned int limit, count;
-
-	limit = (mac->rx->next_to_clean + RX_RING_SIZE -
-		 mac->rx->next_to_fill) & (RX_RING_SIZE - 1);
-
-	/* Check to see if we're doing first-time setup */
-	if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0))
-		limit = RX_RING_SIZE;
+	int fill, count;
 
 	if (limit <= 0)
 		return;
 
-	i = start;
-	for (count = limit; count; count--) {
-		struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i);
-		u64 *buff = &RX_BUFF(mac, i);
+	fill = mac->rx->next_to_fill;
+	for (count = 0; count < limit; count++) {
+		struct pasemi_mac_buffer *info = &RX_RING_INFO(mac, fill);
+		u64 *buff = &RX_BUFF(mac, fill);
 		struct sk_buff *skb;
 		dma_addr_t dma;
 
+		/* Entry in use? */
+		WARN_ON(*buff);
+
 		/* skb might still be in there for recycle on short receives */
 		if (info->skb)
 			skb = info->skb;
-		else
+		else {
 			skb = dev_alloc_skb(BUF_SIZE);
+			skb_reserve(skb, LOCAL_SKB_ALIGN);
+		}
 
 		if (unlikely(!skb))
 			break;
 
-		dma = pci_map_single(mac->dma_pdev, skb->data, skb->len,
+		dma = pci_map_single(mac->dma_pdev, skb->data,
+				     BUF_SIZE - LOCAL_SKB_ALIGN,
 				     PCI_DMA_FROMDEVICE);
 
 		if (unlikely(dma_mapping_error(dma))) {
@@ -378,19 +464,15 @@
 		info->skb = skb;
 		info->dma = dma;
 		*buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma);
-		i++;
+		fill++;
 	}
 
 	wmb();
 
-	pci_write_config_dword(mac->dma_pdev,
-			       PAS_DMA_RXCHAN_INCR(mac->dma_rxch),
-			       limit - count);
-	pci_write_config_dword(mac->dma_pdev,
-			       PAS_DMA_RXINT_INCR(mac->dma_if),
-			       limit - count);
+	write_dma_reg(mac, PAS_DMA_RXINT_INCR(mac->dma_if), count);
 
-	mac->rx->next_to_fill += limit - count;
+	mac->rx->next_to_fill = (mac->rx->next_to_fill + count) &
+				(RX_RING_SIZE - 1);
 }
 
 static void pasemi_mac_restart_rx_intr(struct pasemi_mac *mac)
@@ -404,9 +486,7 @@
 
 	reg = PAS_IOB_DMA_RXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_RXCH_RESET_PINTC;
 
-	pci_write_config_dword(mac->iob_pdev,
-			       PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch),
-			       reg);
+	write_iob_reg(mac, PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
 }
 
 static void pasemi_mac_restart_tx_intr(struct pasemi_mac *mac)
@@ -418,69 +498,96 @@
 
 	reg = PAS_IOB_DMA_TXCH_RESET_PCNT(pcnt) | PAS_IOB_DMA_TXCH_RESET_PINTC;
 
-	pci_write_config_dword(mac->iob_pdev,
-			       PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg);
+	write_iob_reg(mac, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg);
 }
 
 
+static inline void pasemi_mac_rx_error(struct pasemi_mac *mac, u64 macrx)
+{
+	unsigned int rcmdsta, ccmdsta;
+
+	if (!netif_msg_rx_err(mac))
+		return;
+
+	rcmdsta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+	ccmdsta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));
+
+	printk(KERN_ERR "pasemi_mac: rx error. macrx %016lx, rx status %lx\n",
+		macrx, *mac->rx_status);
+
+	printk(KERN_ERR "pasemi_mac: rcmdsta %08x ccmdsta %08x\n",
+		rcmdsta, ccmdsta);
+}
+
+static inline void pasemi_mac_tx_error(struct pasemi_mac *mac, u64 mactx)
+{
+	unsigned int cmdsta;
+
+	if (!netif_msg_tx_err(mac))
+		return;
+
+	cmdsta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));
+
+	printk(KERN_ERR "pasemi_mac: tx error. mactx 0x%016lx, "\
+		"tx status 0x%016lx\n", mactx, *mac->tx_status);
+
+	printk(KERN_ERR "pasemi_mac: tcmdsta 0x%08x\n", cmdsta);
+}
+
 static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
 {
 	unsigned int n;
 	int count;
-	struct pas_dma_xct_descr *dp;
 	struct pasemi_mac_buffer *info;
 	struct sk_buff *skb;
-	unsigned int i, len;
+	unsigned int len;
 	u64 macrx;
 	dma_addr_t dma;
+	int buf_index;
+	u64 eval;
 
 	spin_lock(&mac->rx->lock);
 
 	n = mac->rx->next_to_clean;
 
-	for (count = limit; count; count--) {
+	prefetch(RX_RING(mac, n));
 
-		rmb();
+	for (count = 0; count < limit; count++) {
+		macrx = RX_RING(mac, n);
 
-		dp = &RX_DESC(mac, n);
-		macrx = dp->macrx;
+		if ((macrx & XCT_MACRX_E) ||
+		    (*mac->rx_status & PAS_STATUS_ERROR))
+			pasemi_mac_rx_error(mac, macrx);
 
 		if (!(macrx & XCT_MACRX_O))
 			break;
 
-
 		info = NULL;
 
-		/* We have to scan for our skb since there's no way
-		 * to back-map them from the descriptor, and if we
-		 * have several receive channels then they might not
-		 * show up in the same order as they were put on the
-		 * interface ring.
-		 */
+		BUG_ON(!(macrx & XCT_MACRX_RR_8BRES));
 
-		dma = (dp->ptr & XCT_PTR_ADDR_M);
-		for (i = n; i < (n + RX_RING_SIZE); i++) {
-			info = &RX_DESC_INFO(mac, i);
-			if (info->dma == dma)
-				break;
-		}
+		eval = (RX_RING(mac, n+1) & XCT_RXRES_8B_EVAL_M) >>
+			XCT_RXRES_8B_EVAL_S;
+		buf_index = eval-1;
+
+		dma = (RX_RING(mac, n+2) & XCT_PTR_ADDR_M);
+		info = &RX_RING_INFO(mac, buf_index);
 
 		skb = info->skb;
-		info->dma = 0;
 
-		pci_unmap_single(mac->dma_pdev, dma, skb->len,
-				 PCI_DMA_FROMDEVICE);
+		prefetch(skb);
+		prefetch(&skb->data_len);
 
 		len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
 
 		if (len < 256) {
-			struct sk_buff *new_skb =
-			    netdev_alloc_skb(mac->netdev, len + NET_IP_ALIGN);
+			struct sk_buff *new_skb;
+
+			new_skb = netdev_alloc_skb(mac->netdev,
+						   len + LOCAL_SKB_ALIGN);
 			if (new_skb) {
-				skb_reserve(new_skb, NET_IP_ALIGN);
-				memcpy(new_skb->data - NET_IP_ALIGN,
-					skb->data - NET_IP_ALIGN,
-					len + NET_IP_ALIGN);
+				skb_reserve(new_skb, LOCAL_SKB_ALIGN);
+				memcpy(new_skb->data, skb->data, len);
 				/* save the skb in buffer_info as good */
 				skb = new_skb;
 			}
@@ -488,73 +595,131 @@
 		} else
 			info->skb = NULL;
 
+		pci_unmap_single(mac->dma_pdev, dma, len, PCI_DMA_FROMDEVICE);
+
+		info->dma = 0;
+
 		skb_put(skb, len);
 
-		skb->protocol = eth_type_trans(skb, mac->netdev);
-
-		if ((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) {
-			skb->ip_summed = CHECKSUM_COMPLETE;
+		if (likely((macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK)) {
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
 			skb->csum = (macrx & XCT_MACRX_CSUM_M) >>
 					   XCT_MACRX_CSUM_S;
 		} else
 			skb->ip_summed = CHECKSUM_NONE;
 
-		mac->stats.rx_bytes += len;
-		mac->stats.rx_packets++;
+		mac->netdev->stats.rx_bytes += len;
+		mac->netdev->stats.rx_packets++;
 
+		skb->protocol = eth_type_trans(skb, mac->netdev);
 		netif_receive_skb(skb);
 
-		dp->ptr = 0;
-		dp->macrx = 0;
+		RX_RING(mac, n) = 0;
+		RX_RING(mac, n+1) = 0;
 
-		n++;
+		/* Need to zero it out since hardware doesn't, since the
+		 * replenish loop uses it to tell when it's done.
+		 */
+		RX_BUFF(mac, buf_index) = 0;
+
+		n += 4;
 	}
 
-	mac->rx->next_to_clean += limit - count;
-	pasemi_mac_replenish_rx_ring(mac->netdev);
+	if (n > RX_RING_SIZE) {
+		/* Errata 5971 workaround: L2 target of headers */
+		write_iob_reg(mac, PAS_IOB_COM_PKTHDRCNT, 0);
+		n &= (RX_RING_SIZE-1);
+	}
+
+	mac->rx->next_to_clean = n;
+
+	/* Increase is in number of 16-byte entries, and since each descriptor
+	 * with an 8BRES takes up 3x8 bytes (padded to 4x8), increase with
+	 * count*2.
+	 */
+	write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), count << 1);
+
+	pasemi_mac_replenish_rx_ring(mac->netdev, count);
 
 	spin_unlock(&mac->rx->lock);
 
 	return count;
 }
 
+/* Can't make this too large or we blow the kernel stack limits */
+#define TX_CLEAN_BATCHSIZE (128/MAX_SKB_FRAGS)
+
 static int pasemi_mac_clean_tx(struct pasemi_mac *mac)
 {
-	int i;
-	struct pasemi_mac_buffer *info;
-	struct pas_dma_xct_descr *dp;
-	int start, count;
-	int flags;
+	int i, j;
+	unsigned int start, descr_count, buf_count, batch_limit;
+	unsigned int ring_limit;
+	unsigned int total_count;
+	unsigned long flags;
+	struct sk_buff *skbs[TX_CLEAN_BATCHSIZE];
+	dma_addr_t dmas[TX_CLEAN_BATCHSIZE][MAX_SKB_FRAGS+1];
 
+	total_count = 0;
+	batch_limit = TX_CLEAN_BATCHSIZE;
+restart:
 	spin_lock_irqsave(&mac->tx->lock, flags);
 
 	start = mac->tx->next_to_clean;
-	count = 0;
+	ring_limit = mac->tx->next_to_fill;
 
-	for (i = start; i < mac->tx->next_to_use; i++) {
-		dp = &TX_DESC(mac, i);
-		if (!dp || (dp->mactx & XCT_MACTX_O))
+	/* Compensate for when fill has wrapped but clean has not */
+	if (start > ring_limit)
+		ring_limit += TX_RING_SIZE;
+
+	buf_count = 0;
+	descr_count = 0;
+
+	for (i = start;
+	     descr_count < batch_limit && i < ring_limit;
+	     i += buf_count) {
+		u64 mactx = TX_RING(mac, i);
+		struct sk_buff *skb;
+
+		if ((mactx  & XCT_MACTX_E) ||
+		    (*mac->tx_status & PAS_STATUS_ERROR))
+			pasemi_mac_tx_error(mac, mactx);
+
+		if (unlikely(mactx & XCT_MACTX_O))
+			/* Not yet transmitted */
 			break;
 
-		count++;
+		skb = TX_RING_INFO(mac, i+1).skb;
+		skbs[descr_count] = skb;
 
-		info = &TX_DESC_INFO(mac, i);
+		buf_count = 2 + skb_shinfo(skb)->nr_frags;
+		for (j = 0; j <= skb_shinfo(skb)->nr_frags; j++)
+			dmas[descr_count][j] = TX_RING_INFO(mac, i+1+j).dma;
 
-		pci_unmap_single(mac->dma_pdev, info->dma,
-				 info->skb->len, PCI_DMA_TODEVICE);
-		dev_kfree_skb_irq(info->skb);
+		TX_RING(mac, i) = 0;
+		TX_RING(mac, i+1) = 0;
 
-		info->skb = NULL;
-		info->dma = 0;
-		dp->mactx = 0;
-		dp->ptr = 0;
+		/* Since we always fill with an even number of entries, make
+		 * sure we skip any unused one at the end as well.
+		 */
+		if (buf_count & 1)
+			buf_count++;
+		descr_count++;
 	}
-	mac->tx->next_to_clean += count;
-	spin_unlock_irqrestore(&mac->tx->lock, flags);
+	mac->tx->next_to_clean = i & (TX_RING_SIZE-1);
 
+	spin_unlock_irqrestore(&mac->tx->lock, flags);
 	netif_wake_queue(mac->netdev);
 
-	return count;
+	for (i = 0; i < descr_count; i++)
+		pasemi_mac_unmap_tx_skb(mac, skbs[i], dmas[i]);
+
+	total_count += descr_count;
+
+	/* If the batch was full, try to clean more */
+	if (descr_count == batch_limit)
+		goto restart;
+
+	return total_count;
 }
 
 
@@ -567,15 +732,10 @@
 	if (!(*mac->rx_status & PAS_STATUS_CAUSE_M))
 		return IRQ_NONE;
 
-	if (*mac->rx_status & PAS_STATUS_ERROR)
-		printk("rx_status reported error\n");
-
 	/* Don't reset packet count so it won't fire again but clear
 	 * all others.
 	 */
 
-	pci_read_config_dword(mac->dma_pdev, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), &reg);
-
 	reg = 0;
 	if (*mac->rx_status & PAS_STATUS_SOFT)
 		reg |= PAS_IOB_DMA_RXCH_RESET_SINTC;
@@ -584,11 +744,9 @@
 	if (*mac->rx_status & PAS_STATUS_TIMER)
 		reg |= PAS_IOB_DMA_RXCH_RESET_TINTC;
 
-	netif_rx_schedule(dev);
+	netif_rx_schedule(dev, &mac->napi);
 
-	pci_write_config_dword(mac->iob_pdev,
-			       PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
-
+	write_iob_reg(mac, PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
 
 	return IRQ_HANDLED;
 }
@@ -613,9 +771,7 @@
 	if (*mac->tx_status & PAS_STATUS_ERROR)
 		reg |= PAS_IOB_DMA_TXCH_RESET_DINTC;
 
-	pci_write_config_dword(mac->iob_pdev,
-			       PAS_IOB_DMA_TXCH_RESET(mac->dma_txch),
-			       reg);
+	write_iob_reg(mac, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch), reg);
 
 	return IRQ_HANDLED;
 }
@@ -641,7 +797,7 @@
 	} else
 		netif_carrier_on(dev);
 
-	pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags);
+	flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
 	new_flags = flags & ~(PAS_MAC_CFG_PCFG_HD | PAS_MAC_CFG_PCFG_SPD_M |
 			      PAS_MAC_CFG_PCFG_TSR_M);
 
@@ -673,7 +829,7 @@
 	mac->link = mac->phydev->link;
 
 	if (new_flags != flags)
-		pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, new_flags);
+		write_mac_reg(mac, PAS_MAC_CFG_PCFG, new_flags);
 
 	if (msg && netif_msg_link(mac))
 		printk(KERN_INFO "%s: Link is up at %d Mbps, %s duplex.\n",
@@ -736,39 +892,30 @@
 	int ret;
 
 	/* enable rx section */
-	pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_RXCMD,
-			       PAS_DMA_COM_RXCMD_EN);
+	write_dma_reg(mac, PAS_DMA_COM_RXCMD, PAS_DMA_COM_RXCMD_EN);
 
 	/* enable tx section */
-	pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_TXCMD,
-			       PAS_DMA_COM_TXCMD_EN);
+	write_dma_reg(mac, PAS_DMA_COM_TXCMD, PAS_DMA_COM_TXCMD_EN);
 
 	flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) |
 		PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) |
 		PAS_MAC_CFG_TXP_TIFT(8) | PAS_MAC_CFG_TXP_TIFG(12);
 
-	pci_write_config_dword(mac->pdev, PAS_MAC_CFG_TXP, flags);
+	write_mac_reg(mac, PAS_MAC_CFG_TXP, flags);
 
-	flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE |
-		PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE;
+	write_iob_reg(mac, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch),
+			   PAS_IOB_DMA_RXCH_CFG_CNTTH(0));
 
-	flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G;
-
-	pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch),
-			       PAS_IOB_DMA_RXCH_CFG_CNTTH(0));
-
-	pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch),
-			       PAS_IOB_DMA_TXCH_CFG_CNTTH(32));
+	write_iob_reg(mac, PAS_IOB_DMA_TXCH_CFG(mac->dma_txch),
+			   PAS_IOB_DMA_TXCH_CFG_CNTTH(128));
 
 	/* Clear out any residual packet count state from firmware */
 	pasemi_mac_restart_rx_intr(mac);
 	pasemi_mac_restart_tx_intr(mac);
 
 	/* 0xffffff is max value, about 16ms */
-	pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
-			       PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff));
-
-	pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
+	write_iob_reg(mac, PAS_IOB_DMA_COM_TIMEOUTCFG,
+			   PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0xffffff));
 
 	ret = pasemi_mac_setup_rx_resources(dev);
 	if (ret)
@@ -778,27 +925,48 @@
 	if (ret)
 		goto out_tx_resources;
 
-	pci_write_config_dword(mac->pdev, PAS_MAC_IPC_CHNL,
-			       PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) |
-			       PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch));
+	write_mac_reg(mac, PAS_MAC_IPC_CHNL,
+			   PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) |
+			   PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch));
 
 	/* enable rx if */
-	pci_write_config_dword(mac->dma_pdev,
-			       PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
-			       PAS_DMA_RXINT_RCMDSTA_EN);
+	write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+			   PAS_DMA_RXINT_RCMDSTA_EN |
+			   PAS_DMA_RXINT_RCMDSTA_DROPS_M |
+			   PAS_DMA_RXINT_RCMDSTA_BP |
+			   PAS_DMA_RXINT_RCMDSTA_OO |
+			   PAS_DMA_RXINT_RCMDSTA_BT);
 
 	/* enable rx channel */
-	pci_write_config_dword(mac->dma_pdev,
-			       PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
-			       PAS_DMA_RXCHAN_CCMDSTA_EN |
-			       PAS_DMA_RXCHAN_CCMDSTA_DU);
+	write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+			   PAS_DMA_RXCHAN_CCMDSTA_EN |
+			   PAS_DMA_RXCHAN_CCMDSTA_DU |
+			   PAS_DMA_RXCHAN_CCMDSTA_OD |
+			   PAS_DMA_RXCHAN_CCMDSTA_FD |
+			   PAS_DMA_RXCHAN_CCMDSTA_DT);
 
 	/* enable tx channel */
-	pci_write_config_dword(mac->dma_pdev,
-			       PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
-			       PAS_DMA_TXCHAN_TCMDSTA_EN);
+	write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+			   PAS_DMA_TXCHAN_TCMDSTA_EN |
+			   PAS_DMA_TXCHAN_TCMDSTA_SZ |
+			   PAS_DMA_TXCHAN_TCMDSTA_DB |
+			   PAS_DMA_TXCHAN_TCMDSTA_DE |
+			   PAS_DMA_TXCHAN_TCMDSTA_DA);
 
-	pasemi_mac_replenish_rx_ring(dev);
+	pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE);
+
+	write_dma_reg(mac, PAS_DMA_RXCHAN_INCR(mac->dma_rxch), RX_RING_SIZE>>1);
+
+	flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE |
+		PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE;
+
+	if (mac->type == MAC_TYPE_GMAC)
+		flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G;
+	else
+		flags |= PAS_MAC_CFG_PCFG_TSR_10G | PAS_MAC_CFG_PCFG_SPD_10G;
+
+	/* Enable interface in MAC */
+	write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
 
 	ret = pasemi_mac_phy_init(dev);
 	/* Some configs don't have PHYs (XAUI etc), so don't complain about
@@ -808,7 +976,7 @@
 		dev_warn(&mac->pdev->dev, "phy init failed: %d\n", ret);
 
 	netif_start_queue(dev);
-	netif_poll_enable(dev);
+	napi_enable(&mac->napi);
 
 	/* Interrupts are a bit different for our DMA controller: While
 	 * it's got one a regular PCI device header, the interrupt there
@@ -845,7 +1013,7 @@
 out_rx_int:
 	free_irq(mac->tx_irq, dev);
 out_tx_int:
-	netif_poll_disable(dev);
+	napi_disable(&mac->napi);
 	netif_stop_queue(dev);
 	pasemi_mac_free_tx_resources(dev);
 out_tx_resources:
@@ -860,7 +1028,7 @@
 static int pasemi_mac_close(struct net_device *dev)
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
-	unsigned int stat;
+	unsigned int sta;
 	int retries;
 
 	if (mac->phydev) {
@@ -869,68 +1037,74 @@
 	}
 
 	netif_stop_queue(dev);
+	napi_disable(&mac->napi);
+
+	sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+	if (sta & (PAS_DMA_RXINT_RCMDSTA_BP |
+		      PAS_DMA_RXINT_RCMDSTA_OO |
+		      PAS_DMA_RXINT_RCMDSTA_BT))
+		printk(KERN_DEBUG "pasemi_mac: rcmdsta error: 0x%08x\n", sta);
+
+	sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));
+	if (sta & (PAS_DMA_RXCHAN_CCMDSTA_DU |
+		     PAS_DMA_RXCHAN_CCMDSTA_OD |
+		     PAS_DMA_RXCHAN_CCMDSTA_FD |
+		     PAS_DMA_RXCHAN_CCMDSTA_DT))
+		printk(KERN_DEBUG "pasemi_mac: ccmdsta error: 0x%08x\n", sta);
+
+	sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));
+	if (sta & (PAS_DMA_TXCHAN_TCMDSTA_SZ |
+		      PAS_DMA_TXCHAN_TCMDSTA_DB |
+		      PAS_DMA_TXCHAN_TCMDSTA_DE |
+		      PAS_DMA_TXCHAN_TCMDSTA_DA))
+		printk(KERN_DEBUG "pasemi_mac: tcmdsta error: 0x%08x\n", sta);
 
 	/* Clean out any pending buffers */
 	pasemi_mac_clean_tx(mac);
 	pasemi_mac_clean_rx(mac, RX_RING_SIZE);
 
 	/* Disable interface */
-	pci_write_config_dword(mac->dma_pdev,
-			       PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
-			       PAS_DMA_TXCHAN_TCMDSTA_ST);
-	pci_write_config_dword(mac->dma_pdev,
-		      PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
-		      PAS_DMA_RXINT_RCMDSTA_ST);
-	pci_write_config_dword(mac->dma_pdev,
-		      PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
-		      PAS_DMA_RXCHAN_CCMDSTA_ST);
+	write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), PAS_DMA_TXCHAN_TCMDSTA_ST);
+	write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), PAS_DMA_RXINT_RCMDSTA_ST);
+	write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), PAS_DMA_RXCHAN_CCMDSTA_ST);
 
 	for (retries = 0; retries < MAX_RETRIES; retries++) {
-		pci_read_config_dword(mac->dma_pdev,
-				      PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
-				      &stat);
-		if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT))
+		sta = read_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch));
+		if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT))
 			break;
 		cond_resched();
 	}
 
-	if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)
+	if (sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)
 		dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n");
 
 	for (retries = 0; retries < MAX_RETRIES; retries++) {
-		pci_read_config_dword(mac->dma_pdev,
-				      PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
-				      &stat);
-		if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT))
+		sta = read_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch));
+		if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT))
 			break;
 		cond_resched();
 	}
 
-	if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)
+	if (sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)
 		dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n");
 
 	for (retries = 0; retries < MAX_RETRIES; retries++) {
-		pci_read_config_dword(mac->dma_pdev,
-				      PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
-				      &stat);
-		if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT))
+		sta = read_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if));
+		if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT))
 			break;
 		cond_resched();
 	}
 
-	if (stat & PAS_DMA_RXINT_RCMDSTA_ACT)
+	if (sta & PAS_DMA_RXINT_RCMDSTA_ACT)
 		dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n");
 
 	/* Then, disable the channel. This must be done separately from
 	 * stopping, since you can't disable when active.
 	 */
 
-	pci_write_config_dword(mac->dma_pdev,
-			       PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0);
-	pci_write_config_dword(mac->dma_pdev,
-			       PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0);
-	pci_write_config_dword(mac->dma_pdev,
-			       PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
+	write_dma_reg(mac, PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0);
+	write_dma_reg(mac, PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0);
+	write_dma_reg(mac, PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
 
 	free_irq(mac->tx_irq, dev);
 	free_irq(mac->rx_irq, dev);
@@ -946,11 +1120,11 @@
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
 	struct pasemi_mac_txring *txring;
-	struct pasemi_mac_buffer *info;
-	struct pas_dma_xct_descr *dp;
-	u64 dflags;
-	dma_addr_t map;
-	int flags;
+	u64 dflags, mactx;
+	dma_addr_t map[MAX_SKB_FRAGS+1];
+	unsigned int map_size[MAX_SKB_FRAGS+1];
+	unsigned long flags;
+	int i, nfrags;
 
 	dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_SS | XCT_MACTX_CRC_PAD;
 
@@ -971,71 +1145,87 @@
 		}
 	}
 
-	map = pci_map_single(mac->dma_pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+	nfrags = skb_shinfo(skb)->nr_frags;
 
-	if (dma_mapping_error(map))
-		return NETDEV_TX_BUSY;
+	map[0] = pci_map_single(mac->dma_pdev, skb->data, skb_headlen(skb),
+				PCI_DMA_TODEVICE);
+	map_size[0] = skb_headlen(skb);
+	if (dma_mapping_error(map[0]))
+		goto out_err_nolock;
+
+	for (i = 0; i < nfrags; i++) {
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+		map[i+1] = pci_map_page(mac->dma_pdev, frag->page,
+					frag->page_offset, frag->size,
+					PCI_DMA_TODEVICE);
+		map_size[i+1] = frag->size;
+		if (dma_mapping_error(map[i+1])) {
+			nfrags = i;
+			goto out_err_nolock;
+		}
+	}
+
+	mactx = dflags | XCT_MACTX_LLEN(skb->len);
 
 	txring = mac->tx;
 
 	spin_lock_irqsave(&txring->lock, flags);
 
-	if (txring->next_to_clean - txring->next_to_use == TX_RING_SIZE) {
-		spin_unlock_irqrestore(&txring->lock, flags);
-		pasemi_mac_clean_tx(mac);
-		pasemi_mac_restart_tx_intr(mac);
-		spin_lock_irqsave(&txring->lock, flags);
-
-		if (txring->next_to_clean - txring->next_to_use ==
-		    TX_RING_SIZE) {
-			/* Still no room -- stop the queue and wait for tx
-			 * intr when there's room.
-			 */
-			netif_stop_queue(dev);
-			goto out_err;
-		}
+	/* Avoid stepping on the same cache line that the DMA controller
+	 * is currently about to send, so leave at least 8 words available.
+	 * Total free space needed is mactx + fragments + 8
+	 */
+	if (RING_AVAIL(txring) < nfrags + 10) {
+		/* no room -- stop the queue and wait for tx intr */
+		netif_stop_queue(dev);
+		goto out_err;
 	}
 
+	TX_RING(mac, txring->next_to_fill) = mactx;
+	txring->next_to_fill++;
+	TX_RING_INFO(mac, txring->next_to_fill).skb = skb;
+	for (i = 0; i <= nfrags; i++) {
+		TX_RING(mac, txring->next_to_fill+i) =
+		XCT_PTR_LEN(map_size[i]) | XCT_PTR_ADDR(map[i]);
+		TX_RING_INFO(mac, txring->next_to_fill+i).dma = map[i];
+	}
 
-	dp = &TX_DESC(mac, txring->next_to_use);
-	info = &TX_DESC_INFO(mac, txring->next_to_use);
+	/* We have to add an even number of 8-byte entries to the ring
+	 * even if the last one is unused. That means always an odd number
+	 * of pointers + one mactx descriptor.
+	 */
+	if (nfrags & 1)
+		nfrags++;
 
-	dp->mactx = dflags | XCT_MACTX_LLEN(skb->len);
-	dp->ptr   = XCT_PTR_LEN(skb->len) | XCT_PTR_ADDR(map);
-	info->dma = map;
-	info->skb = skb;
+	txring->next_to_fill = (txring->next_to_fill + nfrags + 1) &
+				(TX_RING_SIZE-1);
 
-	txring->next_to_use++;
-	mac->stats.tx_packets++;
-	mac->stats.tx_bytes += skb->len;
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += skb->len;
 
 	spin_unlock_irqrestore(&txring->lock, flags);
 
-	pci_write_config_dword(mac->dma_pdev,
-			       PAS_DMA_TXCHAN_INCR(mac->dma_txch), 1);
+	write_dma_reg(mac, PAS_DMA_TXCHAN_INCR(mac->dma_txch), (nfrags+2) >> 1);
 
 	return NETDEV_TX_OK;
 
 out_err:
 	spin_unlock_irqrestore(&txring->lock, flags);
-	pci_unmap_single(mac->dma_pdev, map, skb->len, PCI_DMA_TODEVICE);
+out_err_nolock:
+	while (nfrags--)
+		pci_unmap_single(mac->dma_pdev, map[nfrags], map_size[nfrags],
+				 PCI_DMA_TODEVICE);
+
 	return NETDEV_TX_BUSY;
 }
 
-static struct net_device_stats *pasemi_mac_get_stats(struct net_device *dev)
-{
-	struct pasemi_mac *mac = netdev_priv(dev);
-
-	return &mac->stats;
-}
-
-
 static void pasemi_mac_set_rx_mode(struct net_device *dev)
 {
 	struct pasemi_mac *mac = netdev_priv(dev);
 	unsigned int flags;
 
-	pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags);
+	flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG);
 
 	/* Set promiscuous */
 	if (dev->flags & IFF_PROMISC)
@@ -1043,30 +1233,92 @@
 	else
 		flags &= ~PAS_MAC_CFG_PCFG_PR;
 
-	pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
+	write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags);
 }
 
 
-static int pasemi_mac_poll(struct net_device *dev, int *budget)
+static int pasemi_mac_poll(struct napi_struct *napi, int budget)
 {
-	int pkts, limit = min(*budget, dev->quota);
-	struct pasemi_mac *mac = netdev_priv(dev);
+	struct pasemi_mac *mac = container_of(napi, struct pasemi_mac, napi);
+	struct net_device *dev = mac->netdev;
+	int pkts;
 
-	pkts = pasemi_mac_clean_rx(mac, limit);
-
-	dev->quota -= pkts;
-	*budget -= pkts;
-
-	if (pkts < limit) {
+	pasemi_mac_clean_tx(mac);
+	pkts = pasemi_mac_clean_rx(mac, budget);
+	if (pkts < budget) {
 		/* all done, no more packets present */
-		netif_rx_complete(dev);
+		netif_rx_complete(dev, napi);
 
 		pasemi_mac_restart_rx_intr(mac);
-		return 0;
-	} else {
-		/* used up our quantum, so reschedule */
-		return 1;
 	}
+	return pkts;
+}
+
+static void __iomem * __devinit map_onedev(struct pci_dev *p, int index)
+{
+	struct device_node *dn;
+	void __iomem *ret;
+
+	dn = pci_device_to_OF_node(p);
+	if (!dn)
+		goto fallback;
+
+	ret = of_iomap(dn, index);
+	if (!ret)
+		goto fallback;
+
+	return ret;
+fallback:
+	/* This is hardcoded and ugly, but we have some firmware versions
+	 * that don't provide the register space in the device tree. Luckily
+	 * they are at well-known locations so we can just do the math here.
+	 */
+	return ioremap(0xe0000000 + (p->devfn << 12), 0x2000);
+}
+
+static int __devinit pasemi_mac_map_regs(struct pasemi_mac *mac)
+{
+	struct resource res;
+	struct device_node *dn;
+	int err;
+
+	mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
+	if (!mac->dma_pdev) {
+		dev_err(&mac->pdev->dev, "Can't find DMA Controller\n");
+		return -ENODEV;
+	}
+
+	mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
+	if (!mac->iob_pdev) {
+		dev_err(&mac->pdev->dev, "Can't find I/O Bridge\n");
+		return -ENODEV;
+	}
+
+	mac->regs = map_onedev(mac->pdev, 0);
+	mac->dma_regs = map_onedev(mac->dma_pdev, 0);
+	mac->iob_regs = map_onedev(mac->iob_pdev, 0);
+
+	if (!mac->regs || !mac->dma_regs || !mac->iob_regs) {
+		dev_err(&mac->pdev->dev, "Can't map registers\n");
+		return -ENODEV;
+	}
+
+	/* The dma status structure is located in the I/O bridge, and
+	 * is cache coherent.
+	 */
+	if (!dma_status) {
+		dn = pci_device_to_OF_node(mac->iob_pdev);
+		if (dn)
+			err = of_address_to_resource(dn, 1, &res);
+		if (!dn || err) {
+			/* Fallback for old firmware */
+			res.start = 0xfd800000;
+			res.end = res.start + 0x1000;
+		}
+		dma_status = __ioremap(res.start, res.end-res.start, 0);
+	}
+
+	return 0;
 }
 
 static int __devinit
@@ -1076,6 +1328,7 @@
 	struct net_device *dev;
 	struct pasemi_mac *mac;
 	int err;
+	DECLARE_MAC_BUF(mac_buf);
 
 	err = pci_enable_device(pdev);
 	if (err)
@@ -1089,7 +1342,6 @@
 		goto out_disable_device;
 	}
 
-	SET_MODULE_OWNER(dev);
 	pci_set_drvdata(pdev, dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
@@ -1097,21 +1349,10 @@
 
 	mac->pdev = pdev;
 	mac->netdev = dev;
-	mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
 
-	if (!mac->dma_pdev) {
-		dev_err(&pdev->dev, "Can't find DMA Controller\n");
-		err = -ENODEV;
-		goto out_free_netdev;
-	}
+	netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64);
 
-	mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
-
-	if (!mac->iob_pdev) {
-		dev_err(&pdev->dev, "Can't find I/O Bridge\n");
-		err = -ENODEV;
-		goto out_put_dma_pdev;
-	}
+	dev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX | NETIF_F_SG;
 
 	/* These should come out of the device tree eventually */
 	mac->dma_txch = index;
@@ -1148,18 +1389,11 @@
 	dev->open = pasemi_mac_open;
 	dev->stop = pasemi_mac_close;
 	dev->hard_start_xmit = pasemi_mac_start_tx;
-	dev->get_stats = pasemi_mac_get_stats;
 	dev->set_multicast_list = pasemi_mac_set_rx_mode;
-	dev->weight = 64;
-	dev->poll = pasemi_mac_poll;
-	dev->features = NETIF_F_HW_CSUM;
 
-	/* The dma status structure is located in the I/O bridge, and
-	 * is cache coherent.
-	 */
-	if (!dma_status)
-		/* XXXOJN This should come from the device tree */
-		dma_status = __ioremap(0xfd800000, 0x1000, 0);
+	err = pasemi_mac_map_regs(mac);
+	if (err)
+		goto out;
 
 	mac->rx_status = &dma_status->rx_sta[mac->dma_rxch];
 	mac->tx_status = &dma_status->tx_sta[mac->dma_txch];
@@ -1175,21 +1409,27 @@
 		dev_err(&mac->pdev->dev, "register_netdev failed with error %d\n",
 			err);
 		goto out;
-	} else
+	} else if netif_msg_probe(mac)
 		printk(KERN_INFO "%s: PA Semi %s: intf %d, txch %d, rxch %d, "
-		       "hw addr %02x:%02x:%02x:%02x:%02x:%02x\n",
+		       "hw addr %s\n",
 		       dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI",
 		       mac->dma_if, mac->dma_txch, mac->dma_rxch,
-		       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-		       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+		       print_mac(mac_buf, dev->dev_addr));
 
 	return err;
 
 out:
-	pci_dev_put(mac->iob_pdev);
-out_put_dma_pdev:
-	pci_dev_put(mac->dma_pdev);
-out_free_netdev:
+	if (mac->iob_pdev)
+		pci_dev_put(mac->iob_pdev);
+	if (mac->dma_pdev)
+		pci_dev_put(mac->dma_pdev);
+	if (mac->dma_regs)
+		iounmap(mac->dma_regs);
+	if (mac->iob_regs)
+		iounmap(mac->iob_regs);
+	if (mac->regs)
+		iounmap(mac->regs);
+
 	free_netdev(dev);
 out_disable_device:
 	pci_disable_device(pdev);
@@ -1213,6 +1453,10 @@
 	pci_dev_put(mac->dma_pdev);
 	pci_dev_put(mac->iob_pdev);
 
+	iounmap(mac->regs);
+	iounmap(mac->dma_regs);
+	iounmap(mac->iob_regs);
+
 	pci_set_drvdata(pdev, NULL);
 	free_netdev(netdev);
 }
diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h
index c29ee15..60368df 100644
--- a/drivers/net/pasemi_mac.h
+++ b/drivers/net/pasemi_mac.h
@@ -28,35 +28,38 @@
 
 struct pasemi_mac_txring {
 	spinlock_t	 lock;
-	struct pas_dma_xct_descr	*desc;
+	u64		*ring;
 	dma_addr_t	 dma;
 	unsigned int	 size;
-	unsigned int	 next_to_use;
+	unsigned int	 next_to_fill;
 	unsigned int	 next_to_clean;
-	struct pasemi_mac_buffer *desc_info;
+	struct pasemi_mac_buffer *ring_info;
 	char		 irq_name[10];  /* "eth%d tx" */
 };
 
 struct pasemi_mac_rxring {
 	spinlock_t	 lock;
-	struct pas_dma_xct_descr	*desc;	/* RX channel descriptor ring */
+	u64		*ring;	/* RX channel descriptor ring */
 	dma_addr_t	 dma;
 	u64		*buffers;	/* RX interface buffer ring */
 	dma_addr_t	 buf_dma;
 	unsigned int	 size;
 	unsigned int	 next_to_fill;
 	unsigned int	 next_to_clean;
-	struct pasemi_mac_buffer *desc_info;
+	struct pasemi_mac_buffer *ring_info;
 	char		 irq_name[10];  /* "eth%d rx" */
 };
 
 struct pasemi_mac {
 	struct net_device *netdev;
+	void __iomem *regs;
+	void __iomem *dma_regs;
+	void __iomem *iob_regs;
 	struct pci_dev *pdev;
 	struct pci_dev *dma_pdev;
 	struct pci_dev *iob_pdev;
 	struct phy_device *phydev;
-	struct net_device_stats stats;
+	struct napi_struct napi;
 
 	/* Pointer to the cacheable per-channel status registers */
 	u64	*rx_status;
@@ -85,7 +88,7 @@
 	char	phy_id[BUS_ID_SIZE];
 };
 
-/* Software status descriptor (desc_info) */
+/* Software status descriptor (ring_info) */
 struct pasemi_mac_buffer {
 	struct sk_buff *skb;
 	dma_addr_t	dma;
@@ -98,20 +101,7 @@
 	u64 tx_sta[20];
 };
 
-/* descriptor structure */
-struct pas_dma_xct_descr {
-	union {
-		u64	mactx;
-		u64	macrx;
-	};
-	union {
-		u64	ptr;
-		u64	rxb;
-	};
-};
-
 /* MAC CFG register offsets */
-
 enum {
 	PAS_MAC_CFG_PCFG = 0x80,
 	PAS_MAC_CFG_TXP = 0x98,
@@ -215,6 +205,20 @@
 #define    PAS_DMA_RXINT_RCMDSTA_ACT	0x00010000
 #define    PAS_DMA_RXINT_RCMDSTA_DROPS_M	0xfffe0000
 #define    PAS_DMA_RXINT_RCMDSTA_DROPS_S	17
+#define PAS_DMA_RXINT_CFG(i)		(0x204+(i)*_PAS_DMA_RXINT_STRIDE)
+#define    PAS_DMA_RXINT_CFG_RBP	0x80000000
+#define    PAS_DMA_RXINT_CFG_ITRR	0x40000000
+#define    PAS_DMA_RXINT_CFG_DHL_M	0x07000000
+#define    PAS_DMA_RXINT_CFG_DHL_S	24
+#define    PAS_DMA_RXINT_CFG_DHL(x)	(((x) << PAS_DMA_RXINT_CFG_DHL_S) & \
+					 PAS_DMA_RXINT_CFG_DHL_M)
+#define    PAS_DMA_RXINT_CFG_ITR	0x00400000
+#define    PAS_DMA_RXINT_CFG_LW		0x00200000
+#define    PAS_DMA_RXINT_CFG_L2		0x00100000
+#define    PAS_DMA_RXINT_CFG_HEN	0x00080000
+#define    PAS_DMA_RXINT_CFG_WIF	0x00000002
+#define    PAS_DMA_RXINT_CFG_WIL	0x00000001
+
 #define PAS_DMA_RXINT_INCR(i)		(0x210+(i)*_PAS_DMA_RXINT_STRIDE)
 #define    PAS_DMA_RXINT_INCR_INCR_M	0x0000ffff
 #define    PAS_DMA_RXINT_INCR_INCR_S	0
@@ -241,6 +245,10 @@
 #define    PAS_DMA_TXCHAN_TCMDSTA_EN	0x00000001	/* Enabled */
 #define    PAS_DMA_TXCHAN_TCMDSTA_ST	0x00000002	/* Stop interface */
 #define    PAS_DMA_TXCHAN_TCMDSTA_ACT	0x00010000	/* Active */
+#define    PAS_DMA_TXCHAN_TCMDSTA_SZ	0x00000800
+#define    PAS_DMA_TXCHAN_TCMDSTA_DB	0x00000400
+#define    PAS_DMA_TXCHAN_TCMDSTA_DE	0x00000200
+#define    PAS_DMA_TXCHAN_TCMDSTA_DA	0x00000100
 #define PAS_DMA_TXCHAN_CFG(c)     (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE)
 #define    PAS_DMA_TXCHAN_CFG_TY_IFACE	0x00000000	/* Type = interface */
 #define    PAS_DMA_TXCHAN_CFG_TATTR_M	0x0000003c
@@ -251,9 +259,11 @@
 #define    PAS_DMA_TXCHAN_CFG_WT_S	6
 #define    PAS_DMA_TXCHAN_CFG_WT(x)	(((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \
 					 PAS_DMA_TXCHAN_CFG_WT_M)
-#define    PAS_DMA_TXCHAN_CFG_CF	0x00001000	/* Clean first line */
-#define    PAS_DMA_TXCHAN_CFG_CL	0x00002000	/* Clean last line */
+#define    PAS_DMA_TXCHAN_CFG_TRD	0x00010000	/* translate data */
+#define    PAS_DMA_TXCHAN_CFG_TRR	0x00008000	/* translate rings */
 #define    PAS_DMA_TXCHAN_CFG_UP	0x00004000	/* update tx descr when sent */
+#define    PAS_DMA_TXCHAN_CFG_CL	0x00002000	/* Clean last line */
+#define    PAS_DMA_TXCHAN_CFG_CF	0x00001000	/* Clean first line */
 #define PAS_DMA_TXCHAN_INCR(c)    (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE)
 #define PAS_DMA_TXCHAN_BASEL(c)   (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE)
 #define    PAS_DMA_TXCHAN_BASEL_BRBL_M	0xffffffc0
@@ -283,7 +293,11 @@
 #define    PAS_DMA_RXCHAN_CCMDSTA_ST	0x00000002	/* Stop interface */
 #define    PAS_DMA_RXCHAN_CCMDSTA_ACT	0x00010000	/* Active */
 #define    PAS_DMA_RXCHAN_CCMDSTA_DU	0x00020000
+#define    PAS_DMA_RXCHAN_CCMDSTA_OD	0x00002000
+#define    PAS_DMA_RXCHAN_CCMDSTA_FD	0x00001000
+#define    PAS_DMA_RXCHAN_CCMDSTA_DT	0x00000800
 #define PAS_DMA_RXCHAN_CFG(c)     (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define    PAS_DMA_RXCHAN_CFG_CTR	0x00000400
 #define    PAS_DMA_RXCHAN_CFG_HBU_M	0x00000380
 #define    PAS_DMA_RXCHAN_CFG_HBU_S	7
 #define    PAS_DMA_RXCHAN_CFG_HBU(x)	(((x) << PAS_DMA_RXCHAN_CFG_HBU_S) & \
@@ -317,6 +331,12 @@
 #define    PAS_STATUS_SOFT		0x4000000000000000ull
 #define    PAS_STATUS_INT		0x8000000000000000ull
 
+#define PAS_IOB_COM_PKTHDRCNT		0x120
+#define    PAS_IOB_COM_PKTHDRCNT_PKTHDR1_M	0x0fff0000
+#define    PAS_IOB_COM_PKTHDRCNT_PKTHDR1_S	16
+#define    PAS_IOB_COM_PKTHDRCNT_PKTHDR0_M	0x00000fff
+#define    PAS_IOB_COM_PKTHDRCNT_PKTHDR0_S	0
+
 #define PAS_IOB_DMA_RXCH_CFG(i)		(0x1100 + (i)*4)
 #define    PAS_IOB_DMA_RXCH_CFG_CNTTH_M		0x00000fff
 #define    PAS_IOB_DMA_RXCH_CFG_CNTTH_S		0
@@ -412,10 +432,9 @@
 /* Receive descriptor fields */
 #define	XCT_MACRX_T		0x8000000000000000ull
 #define	XCT_MACRX_ST		0x4000000000000000ull
-#define XCT_MACRX_NORES		0x0000000000000000ull
-#define XCT_MACRX_8BRES		0x1000000000000000ull
-#define XCT_MACRX_24BRES	0x2000000000000000ull
-#define XCT_MACRX_40BRES	0x3000000000000000ull
+#define XCT_MACRX_RR_M		0x3000000000000000ull
+#define XCT_MACRX_RR_NORES	0x0000000000000000ull
+#define XCT_MACRX_RR_8BRES	0x1000000000000000ull
 #define XCT_MACRX_O		0x0400000000000000ull
 #define XCT_MACRX_E		0x0200000000000000ull
 #define XCT_MACRX_FF		0x0100000000000000ull
@@ -463,6 +482,17 @@
 #define XCT_PTR_ADDR(x)		((((long)(x)) << XCT_PTR_ADDR_S) & \
 				 XCT_PTR_ADDR_M)
 
+/* Receive interface 8byte result fields */
+#define XCT_RXRES_8B_L4O_M	0xff00000000000000ull
+#define XCT_RXRES_8B_L4O_S	56
+#define XCT_RXRES_8B_RULE_M	0x00ffff0000000000ull
+#define XCT_RXRES_8B_RULE_S	40
+#define XCT_RXRES_8B_EVAL_M	0x000000ffff000000ull
+#define XCT_RXRES_8B_EVAL_S	24
+#define XCT_RXRES_8B_HTYPE_M	0x0000000000f00000ull
+#define XCT_RXRES_8B_HASH_M	0x00000000000fffffull
+#define XCT_RXRES_8B_HASH_S	0
+
 /* Receive interface buffer fields */
 #define XCT_RXB_LEN_M		0x0ffff00000000000ull
 #define XCT_RXB_LEN_S		44
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index 3cdbe118..ed402e0 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -457,7 +457,6 @@
 	void *mmio_addr;
 	int drv_flags;
 	struct pci_dev *pci_dev;
-	struct net_device_stats stats;
 	struct timer_list timer;	/* Media selection timer. */
 	unsigned char *rx_ring;
 	unsigned int cur_rx;	/* Index into the Rx buffer of next Rx pkt. */
@@ -505,7 +504,6 @@
 static irqreturn_t netdrv_interrupt (int irq, void *dev_instance);
 static int netdrv_close (struct net_device *dev);
 static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
-static struct net_device_stats *netdrv_get_stats (struct net_device *dev);
 static void netdrv_set_rx_mode (struct net_device *dev);
 static void netdrv_hw_start (struct net_device *dev);
 
@@ -604,7 +602,6 @@
 		DPRINTK ("EXIT, returning -ENOMEM\n");
 		return -ENOMEM;
 	}
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 	tp = dev->priv;
 
@@ -740,6 +737,7 @@
 	int i, addr_len, option;
 	void *ioaddr = NULL;
 	static int board_idx = -1;
+	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -776,7 +774,6 @@
 	dev->open = netdrv_open;
 	dev->hard_start_xmit = netdrv_start_xmit;
 	dev->stop = netdrv_close;
-	dev->get_stats = netdrv_get_stats;
 	dev->set_multicast_list = netdrv_set_rx_mode;
 	dev->do_ioctl = netdrv_ioctl;
 	dev->tx_timeout = netdrv_tx_timeout;
@@ -800,15 +797,11 @@
 
 	tp->phys[0] = 32;
 
-	printk (KERN_INFO "%s: %s at 0x%lx, "
-		"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
-		"IRQ %d\n",
+	printk (KERN_INFO "%s: %s at 0x%lx, %sIRQ %d\n",
 		dev->name,
 		board_info[ent->driver_data].name,
 		dev->base_addr,
-		dev->dev_addr[0], dev->dev_addr[1],
-		dev->dev_addr[2], dev->dev_addr[3],
-		dev->dev_addr[4], dev->dev_addr[5],
+		print_mac(mac, dev->dev_addr),
 		dev->irq);
 
 	printk (KERN_DEBUG "%s:  Identified 8139 chip type '%s'\n",
@@ -1277,7 +1270,7 @@
 		if (rp->skb) {
 			dev_kfree_skb (rp->skb);
 			rp->skb = NULL;
-			tp->stats.tx_dropped++;
+			dev->stats.tx_dropped++;
 		}
 	}
 }
@@ -1390,25 +1383,25 @@
 			/* There was an major error, log it. */
 			DPRINTK ("%s: Transmit error, Tx status %8.8x.\n",
 				 dev->name, txstatus);
-			tp->stats.tx_errors++;
+			dev->stats.tx_errors++;
 			if (txstatus & TxAborted) {
-				tp->stats.tx_aborted_errors++;
+				dev->stats.tx_aborted_errors++;
 				NETDRV_W32 (TxConfig, TxClearAbt | (TX_DMA_BURST << TxDMAShift));
 			}
 			if (txstatus & TxCarrierLost)
-				tp->stats.tx_carrier_errors++;
+				dev->stats.tx_carrier_errors++;
 			if (txstatus & TxOutOfWindow)
-				tp->stats.tx_window_errors++;
+				dev->stats.tx_window_errors++;
 		} else {
 			if (txstatus & TxUnderrun) {
 				/* Add 64 to the Tx FIFO threshold. */
 				if (tp->tx_flag < 0x00300000)
 					tp->tx_flag += 0x00020000;
-				tp->stats.tx_fifo_errors++;
+				dev->stats.tx_fifo_errors++;
 			}
-			tp->stats.collisions += (txstatus >> 24) & 15;
-			tp->stats.tx_bytes += txstatus & 0x7ff;
-			tp->stats.tx_packets++;
+			dev->stats.collisions += (txstatus >> 24) & 15;
+			dev->stats.tx_bytes += txstatus & 0x7ff;
+			dev->stats.tx_packets++;
 		}
 
 		/* Free the original skb. */
@@ -1461,13 +1454,13 @@
 			 dev->name, rx_status);
 		/* A.C.: The chip hangs here. */
 	}
-	tp->stats.rx_errors++;
+	dev->stats.rx_errors++;
 	if (rx_status & (RxBadSymbol | RxBadAlign))
-		tp->stats.rx_frame_errors++;
+		dev->stats.rx_frame_errors++;
 	if (rx_status & (RxRunt | RxTooLong))
-		tp->stats.rx_length_errors++;
+		dev->stats.rx_length_errors++;
 	if (rx_status & RxCRCErr)
-		tp->stats.rx_crc_errors++;
+		dev->stats.rx_crc_errors++;
 	/* Reset the receiver, based on RealTek recommendation. (Bug?) */
 	tp->cur_rx = 0;
 
@@ -1573,13 +1566,13 @@
 			skb->protocol = eth_type_trans (skb, dev);
 			netif_rx (skb);
 			dev->last_rx = jiffies;
-			tp->stats.rx_bytes += pkt_size;
-			tp->stats.rx_packets++;
+			dev->stats.rx_bytes += pkt_size;
+			dev->stats.rx_packets++;
 		} else {
 			printk (KERN_WARNING
 				"%s: Memory squeeze, dropping packet.\n",
 				dev->name);
-			tp->stats.rx_dropped++;
+			dev->stats.rx_dropped++;
 		}
 
 		cur_rx = (cur_rx + rx_size + 4 + 3) & ~3;
@@ -1608,7 +1601,7 @@
 	assert (ioaddr != NULL);
 
 	/* Update the error count. */
-	tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
+	dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
 	NETDRV_W32 (RxMissed, 0);
 
 	if ((status & RxUnderrun) && link_changed &&
@@ -1629,14 +1622,14 @@
 	/* XXX along with netdrv_rx_err, are we double-counting errors? */
 	if (status &
 	    (RxUnderrun | RxOverflow | RxErr | RxFIFOOver))
-		tp->stats.rx_errors++;
+		dev->stats.rx_errors++;
 
 	if (status & (PCSTimeout))
-		tp->stats.rx_length_errors++;
+		dev->stats.rx_length_errors++;
 	if (status & (RxUnderrun | RxFIFOOver))
-		tp->stats.rx_fifo_errors++;
+		dev->stats.rx_fifo_errors++;
 	if (status & RxOverflow) {
-		tp->stats.rx_over_errors++;
+		dev->stats.rx_over_errors++;
 		tp->cur_rx = NETDRV_R16 (RxBufAddr) % RX_BUF_LEN;
 		NETDRV_W16_F (RxBufPtr, tp->cur_rx - 16);
 	}
@@ -1740,7 +1733,7 @@
 	NETDRV_W16 (IntrMask, 0x0000);
 
 	/* Update the error counts. */
-	tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
+	dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
 	NETDRV_W32 (RxMissed, 0);
 
 	spin_unlock_irqrestore (&tp->lock, flags);
@@ -1807,31 +1800,6 @@
 	return rc;
 }
 
-
-static struct net_device_stats *netdrv_get_stats (struct net_device *dev)
-{
-	struct netdrv_private *tp = dev->priv;
-	void *ioaddr = tp->mmio_addr;
-
-	DPRINTK ("ENTER\n");
-
-	assert (tp != NULL);
-
-	if (netif_running(dev)) {
-		unsigned long flags;
-
-		spin_lock_irqsave (&tp->lock, flags);
-
-		tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
-		NETDRV_W32 (RxMissed, 0);
-
-		spin_unlock_irqrestore (&tp->lock, flags);
-	}
-
-	DPRINTK ("EXIT\n");
-	return &tp->stats;
-}
-
 /* Set or clear the multicast filter for this adaptor.
    This routine is not state sensitive and need not be SMP locked. */
 
@@ -1909,7 +1877,7 @@
 	NETDRV_W8 (ChipCmd, (NETDRV_R8 (ChipCmd) & ChipCmdClear));
 
 	/* Update the error counts. */
-	tp->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
+	dev->stats.rx_missed_errors += NETDRV_R32 (RxMissed);
 	NETDRV_W32 (RxMissed, 0);
 
 	spin_unlock_irqrestore (&tp->lock, flags);
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index 2b395ee..73dcbb7 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -343,6 +343,7 @@
 	u16 *phys_addr;
 	char *cardname;
 	union wn3_config config;
+	DECLARE_MAC_BUF(mac);
 
 	phys_addr = (u16 *)dev->dev_addr;
 
@@ -458,10 +459,10 @@
 
 	strcpy(lp->node.dev_name, dev->name);
 
-	printk(KERN_INFO "%s: %s at io %#3lx, irq %d, hw_addr ",
-		   dev->name, cardname, dev->base_addr, dev->irq);
-	for (i = 0; i < 6; i++)
-		printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : ".\n"));
+	printk(KERN_INFO "%s: %s at io %#3lx, irq %d, "
+	       "hw_addr %s.\n",
+	       dev->name, cardname, dev->base_addr, dev->irq,
+	       print_mac(mac, dev->dev_addr));
 	printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n",
 		   8 << config.u.ram_size, ram_split[config.u.ram_split],
 		   config.u.autoselect ? "autoselect " : "");
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 503f268..32076ca 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -197,7 +197,6 @@
     link->conf.ConfigIndex = 1;
 
     /* The EL3-specific entries in the device structure. */
-    SET_MODULE_OWNER(dev);
     dev->hard_start_xmit = &el3_start_xmit;
     dev->set_config = &el3_config;
     dev->get_stats = &el3_get_stats;
@@ -256,6 +255,7 @@
     int last_fn, last_ret, i, j, multi = 0, fifo;
     kio_addr_t ioaddr;
     char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+    DECLARE_MAC_BUF(mac);
     
     DEBUG(0, "3c589_config(0x%p)\n", link);
 
@@ -331,11 +331,10 @@
 
     strcpy(lp->node.dev_name, dev->name);
 
-    printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, hw_addr ",
-	   dev->name, (multi ? "562" : "589"), dev->base_addr,
-	   dev->irq);
-    for (i = 0; i < 6; i++)
-	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+    printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, "
+	   "hw_addr %s\n",
+	   dev->name, (multi ? "562" : "589"), dev->base_addr, dev->irq,
+	   print_mac(mac, dev->dev_addr));
     printk(KERN_INFO "  %dK FIFO split %s Rx:Tx, %s xcvr\n",
 	   (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3],
 	   if_names[dev->if_port]);
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 50dff1b..a95a2ca 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -232,7 +232,7 @@
     axnet_reset_8390(dev);
     mdelay(10);
 
-    for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+    for (i = 0; i < ARRAY_SIZE(program_seq); i++)
 	outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
 
     for (i = 0; i < 6; i += 2) {
@@ -292,6 +292,7 @@
     cisparse_t parse;
     int i, j, last_ret, last_fn;
     u_short buf[64];
+    DECLARE_MAC_BUF(mac);
 
     DEBUG(0, "axnet_config(0x%p)\n", link);
 
@@ -403,11 +404,11 @@
 
     strcpy(info->node.dev_name, dev->name);
 
-    printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, hw_addr ",
+    printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, "
+	   "hw_addr %s\n",
 	   dev->name, ((info->flags & IS_AX88790) ? 7 : 1),
-	   dev->base_addr, dev->irq);
-    for (i = 0; i < 6; i++)
-	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+	   dev->base_addr, dev->irq,
+	   print_mac(mac, dev->dev_addr));
     if (info->phy_id != -1) {
 	DEBUG(0, "  MII transceiver at index %d, status %x.\n", info->phy_id, j);
     } else {
@@ -771,6 +772,7 @@
 	PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106),
 	PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab),
 	PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), 
+	PCMCIA_DEVICE_MANF_CARD(0xffff, 0x1090),
 	PCMCIA_DEVICE_PROD_ID12("AmbiCom,Inc.", "Fast Ethernet PC Card(AMB8110)", 0x49b020a7, 0x119cc9fc),
 	PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef),
 	PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef),
@@ -1728,9 +1730,6 @@
 	if (ei_debug > 1)
 		printk(version_8390);
     
-	SET_MODULE_OWNER(dev);
-
-		
 	ei_local = (struct ei_device *)netdev_priv(dev);
 	spin_lock_init(&ei_local->page_lock);
     
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c
index 0d1c7a4..ea9414c4 100644
--- a/drivers/net/pcmcia/com20020_cs.c
+++ b/drivers/net/pcmcia/com20020_cs.c
@@ -147,7 +147,7 @@
     DEBUG(0, "com20020_attach()\n");
 
     /* Create new network device */
-    info = kmalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
+    info = kzalloc(sizeof(struct com20020_dev_t), GFP_KERNEL);
     if (!info)
 	goto fail_alloc_info;
 
@@ -155,7 +155,6 @@
     if (!dev)
 	goto fail_alloc_dev;
 
-    memset(info, 0, sizeof(struct com20020_dev_t));
     lp = dev->priv;
     lp->timeout = timeout;
     lp->backplane = backplane;
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 85d5f2c..6284467 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -259,7 +259,6 @@
     link->conf.IntType = INT_MEMORY_AND_IO;
 
     /* The FMVJ18x specific entries in the device structure. */
-    SET_MODULE_OWNER(dev);
     dev->hard_start_xmit = &fjn_start_xmit;
     dev->set_config = &fjn_config;
     dev->get_stats = &fjn_get_stats;
@@ -347,6 +346,7 @@
     cardtype_t cardtype;
     char *card_name = "unknown";
     u_char *node_id;
+    DECLARE_MAC_BUF(mac);
 
     DEBUG(0, "fmvj18x_config(0x%p)\n", link);
 
@@ -534,11 +534,10 @@
     strcpy(lp->node.dev_name, dev->name);
 
     /* print current configuration */
-    printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, hw_addr ", 
+    printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, "
+	   "hw_addr %s\n",
 	   dev->name, card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2", 
-	   dev->base_addr, dev->irq);
-    for (i = 0; i < 6; i++)
-	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+	   dev->base_addr, dev->irq, print_mac(mac, dev->dev_addr));
 
     return 0;
     
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
index 4ecb8ca..4eafa4f 100644
--- a/drivers/net/pcmcia/ibmtr_cs.c
+++ b/drivers/net/pcmcia/ibmtr_cs.c
@@ -146,9 +146,8 @@
     DEBUG(0, "ibmtr_attach()\n");
 
     /* Create new token-ring device */
-    info = kmalloc(sizeof(*info), GFP_KERNEL); 
+    info = kzalloc(sizeof(*info), GFP_KERNEL);
     if (!info) return -ENOMEM;
-    memset(info,0,sizeof(*info));
     dev = alloc_trdev(sizeof(struct tok_info));
     if (!dev) {
 	kfree(info);
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 73da611..a355a93 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -474,7 +474,6 @@
 
     lp->tx_free_frames=AM2150_MAX_TX_FRAMES;
 
-    SET_MODULE_OWNER(dev);
     dev->hard_start_xmit = &mace_start_xmit;
     dev->set_config = &mace_config;
     dev->get_stats = &mace_get_stats;
@@ -659,6 +658,7 @@
   u_char buf[64];
   int i, last_ret, last_fn;
   kio_addr_t ioaddr;
+  DECLARE_MAC_BUF(mac);
 
   DEBUG(0, "nmclan_config(0x%p)\n", link);
 
@@ -717,10 +717,10 @@
 
   strcpy(lp->node.dev_name, dev->name);
 
-  printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port, hw_addr ",
-	 dev->name, dev->base_addr, dev->irq, if_names[dev->if_port]);
-  for (i = 0; i < 6; i++)
-      printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+  printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port,"
+	 " hw_addr %s\n",
+	 dev->name, dev->base_addr, dev->irq, if_names[dev->if_port],
+	 print_mac(mac, dev->dev_addr));
   return 0;
 
 cs_failed:
@@ -996,7 +996,7 @@
 {
   struct net_device *dev = (struct net_device *) dev_id;
   mace_private *lp = netdev_priv(dev);
-  kio_addr_t ioaddr = dev->base_addr;
+  kio_addr_t ioaddr;
   int status;
   int IntrCnt = MACE_MAX_IR_ITERATIONS;
 
@@ -1006,6 +1006,8 @@
     return IRQ_NONE;
   }
 
+  ioaddr = dev->base_addr;
+
   if (lp->tx_irq_disabled) {
     printk(
       (lp->tx_irq_disabled?
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 63de89e..9d45e96 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -38,7 +38,7 @@
 #include <linux/delay.h>
 #include <linux/ethtool.h>
 #include <linux/netdevice.h>
-#include <../drivers/net/8390.h>
+#include "../8390.h"
 
 #include <pcmcia/cs_types.h>
 #include <pcmcia/cs.h>
@@ -207,7 +207,7 @@
     { /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 }
 };
 
-#define NR_INFO		(sizeof(hw_info)/sizeof(hw_info_t))
+#define NR_INFO		ARRAY_SIZE(hw_info)
 
 static hw_info_t default_info = { 0, 0, 0, 0, 0 };
 static hw_info_t dl10019_info = { 0, 0, 0, 0, IS_DL10019|HAS_MII };
@@ -259,7 +259,6 @@
     link->conf.Attributes = CONF_ENABLE_IRQ;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
-    SET_MODULE_OWNER(dev);
     dev->open = &pcnet_open;
     dev->stop = &pcnet_close;
     dev->set_config = &set_config;
@@ -375,7 +374,7 @@
     pcnet_reset_8390(dev);
     mdelay(10);
 
-    for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+    for (i = 0; i < ARRAY_SIZE(program_seq); i++)
 	outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
 
     for (i = 0; i < 32; i++)
@@ -522,6 +521,7 @@
     int has_shmem = 0;
     u_short buf[64];
     hw_info_t *hw_info;
+    DECLARE_MAC_BUF(mac);
 
     DEBUG(0, "pcnet_config(0x%p)\n", link);
 
@@ -671,9 +671,7 @@
 	printk (" mem %#5lx,", dev->mem_start);
     if (info->flags & HAS_MISC_REG)
 	printk(" %s xcvr,", if_names[dev->if_port]);
-    printk(" hw_addr ");
-    for (i = 0; i < 6; i++)
-	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+    printk(" hw_addr %s\n", print_mac(mac, dev->dev_addr));
     return 0;
 
 cs_failed:
@@ -1664,6 +1662,7 @@
 	PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDF", 0x1b7827b2, 0xfec71e40),
 	PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDL/T", 0x1b7827b2, 0x79fba4f7),
 	PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDS", 0x1b7827b2, 0x931afaab),
+	PCMCIA_DEVICE_PROD_ID12("LEMEL", "LM-N89TX PRO", 0xbbefb52f, 0xd2897a97),
 	PCMCIA_DEVICE_PROD_ID12("Linksys", "Combo PCMCIA EthernetCard (EC2T)", 0x0733cc81, 0x32ee8c78),
 	PCMCIA_DEVICE_PROD_ID12("LINKSYS", "E-CARD", 0xf7cb0b07, 0x6701da11),
 	PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 Integrated PC Card (PCM100)", 0x0733cc81, 0x453c3f9d),
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 7912dbd..58d716f 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -336,7 +336,6 @@
     link->conf.IntType = INT_MEMORY_AND_IO;
 
     /* The SMC91c92-specific entries in the device structure. */
-    SET_MODULE_OWNER(dev);
     dev->hard_start_xmit = &smc_start_xmit;
     dev->get_stats = &smc_get_stats;
     dev->set_config = &s9k_config;
@@ -963,6 +962,7 @@
     int i, j, rev;
     kio_addr_t ioaddr;
     u_long mir;
+    DECLARE_MAC_BUF(mac);
 
     DEBUG(0, "smc91c92_config(0x%p)\n", link);
 
@@ -1075,10 +1075,9 @@
     strcpy(smc->node.dev_name, dev->name);
 
     printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, "
-	   "hw_addr ", dev->name, name, (rev & 0x0f), dev->base_addr,
-	   dev->irq);
-    for (i = 0; i < 6; i++)
-	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+	   "hw_addr %s\n",
+	   dev->name, name, (rev & 0x0f), dev->base_addr, dev->irq,
+	   print_mac(mac, dev->dev_addr));
 
     if (rev > 0) {
 	if (mir & 0x3ff)
@@ -1368,6 +1367,7 @@
     kio_addr_t ioaddr = dev->base_addr;
     u_short num_pages;
     short time_out, ir;
+    unsigned long flags;
 
     netif_stop_queue(dev);
 
@@ -1395,6 +1395,7 @@
     /* A packet is now waiting. */
     smc->packets_waiting++;
 
+    spin_lock_irqsave(&smc->lock, flags);
     SMC_SELECT_BANK(2);	/* Paranoia, we should always be in window 2 */
 
     /* need MC_RESET to keep the memory consistent. errata? */
@@ -1411,6 +1412,7 @@
 	    /* Acknowledge the interrupt, send the packet. */
 	    outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT);
 	    smc_hardware_send_packet(dev);	/* Send the packet now.. */
+	    spin_unlock_irqrestore(&smc->lock, flags);
 	    return 0;
 	}
     }
@@ -1418,6 +1420,7 @@
     /* Otherwise defer until the Tx-space-allocated interrupt. */
     DEBUG(2, "%s: memory allocation deferred.\n", dev->name);
     outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
+    spin_unlock_irqrestore(&smc->lock, flags);
 
     return 0;
 }
@@ -1523,6 +1526,7 @@
     DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
 	  irq, ioaddr);
 
+    spin_lock(&smc->lock);
     smc->watchdog = 0;
     saved_bank = inw(ioaddr + BANK_SELECT);
     if ((saved_bank & 0xff00) != 0x3300) {
@@ -1620,6 +1624,7 @@
 	readb(smc->base+MEGAHERTZ_ISR);
     }
 #endif
+    spin_unlock(&smc->lock);
     return IRQ_RETVAL(handled);
 }
 
@@ -1902,6 +1907,9 @@
     kio_addr_t ioaddr = dev->base_addr;
     u_short i, media, saved_bank;
     u_short link;
+    unsigned long flags;
+
+    spin_lock_irqsave(&smc->lock, flags);
 
     saved_bank = inw(ioaddr + BANK_SELECT);
 
@@ -1934,6 +1942,7 @@
 	smc->media.expires = jiffies + HZ/100;
 	add_timer(&smc->media);
 	SMC_SELECT_BANK(saved_bank);
+	spin_unlock_irqrestore(&smc->lock, flags);
 	return;
     }
 
@@ -2007,6 +2016,7 @@
     smc->media.expires = jiffies + HZ;
     add_timer(&smc->media);
     SMC_SELECT_BANK(saved_bank);
+    spin_unlock_irqrestore(&smc->lock, flags);
 }
 
 static int smc_link_ok(struct net_device *dev)
@@ -2094,14 +2104,14 @@
 	u16 saved_bank = inw(ioaddr + BANK_SELECT);
 	int ret;
 
-	SMC_SELECT_BANK(3);
 	spin_lock_irq(&smc->lock);
+	SMC_SELECT_BANK(3);
 	if (smc->cfg & CFG_MII_SELECT)
 		ret = mii_ethtool_gset(&smc->mii_if, ecmd);
 	else
 		ret = smc_netdev_get_ecmd(dev, ecmd);
-	spin_unlock_irq(&smc->lock);
 	SMC_SELECT_BANK(saved_bank);
+	spin_unlock_irq(&smc->lock);
 	return ret;
 }
 
@@ -2112,14 +2122,14 @@
 	u16 saved_bank = inw(ioaddr + BANK_SELECT);
 	int ret;
 
-	SMC_SELECT_BANK(3);
 	spin_lock_irq(&smc->lock);
+	SMC_SELECT_BANK(3);
 	if (smc->cfg & CFG_MII_SELECT)
 		ret = mii_ethtool_sset(&smc->mii_if, ecmd);
 	else
 		ret = smc_netdev_set_ecmd(dev, ecmd);
-	spin_unlock_irq(&smc->lock);
 	SMC_SELECT_BANK(saved_bank);
+	spin_unlock_irq(&smc->lock);
 	return ret;
 }
 
@@ -2130,11 +2140,11 @@
 	u16 saved_bank = inw(ioaddr + BANK_SELECT);
 	u32 ret;
 
-	SMC_SELECT_BANK(3);
 	spin_lock_irq(&smc->lock);
+	SMC_SELECT_BANK(3);
 	ret = smc_link_ok(dev);
-	spin_unlock_irq(&smc->lock);
 	SMC_SELECT_BANK(saved_bank);
+	spin_unlock_irq(&smc->lock);
 	return ret;
 }
 
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 258d6f3..c3b6960 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -580,7 +580,6 @@
     link->irq.Instance = dev;
 
     /* Fill in card specific entries */
-    SET_MODULE_OWNER(dev);
     dev->hard_start_xmit = &do_start_xmit;
     dev->set_config = &do_config;
     dev->get_stats = &do_get_stats;
@@ -732,6 +731,7 @@
     u_char buf[64];
     cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data;
     cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    DECLARE_MAC_BUF(mac);
 
     local->dingo_ccr = NULL;
 
@@ -1033,11 +1033,9 @@
     strcpy(local->node.dev_name, dev->name);
 
     /* give some infos about the hardware */
-    printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr",
-	 dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq);
-    for (i = 0; i < 6; i++)
-	printk("%c%02X", i?':':' ', dev->dev_addr[i]);
-    printk("\n");
+    printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr %s\n",
+	   dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq,
+	   print_mac(mac, dev->dev_addr));
 
     return 0;
 
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 465485a..5f994b5 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -23,11 +23,11 @@
 
 #define DRV_NAME	"pcnet32"
 #ifdef CONFIG_PCNET32_NAPI
-#define DRV_VERSION	"1.33-NAPI"
+#define DRV_VERSION	"1.34-NAPI"
 #else
-#define DRV_VERSION	"1.33"
+#define DRV_VERSION	"1.34"
 #endif
-#define DRV_RELDATE	"27.Jun.2006"
+#define DRV_RELDATE	"14.Aug.2007"
 #define PFX		DRV_NAME ": "
 
 static const char *const version =
@@ -210,31 +210,31 @@
 
 /* The PCNET32 Rx and Tx ring descriptors. */
 struct pcnet32_rx_head {
-	u32	base;
-	s16	buf_length;	/* two`s complement of length */
-	s16	status;
-	u32	msg_length;
-	u32	reserved;
+	__le32	base;
+	__le16	buf_length;	/* two`s complement of length */
+	__le16	status;
+	__le32	msg_length;
+	__le32	reserved;
 };
 
 struct pcnet32_tx_head {
-	u32	base;
-	s16	length;		/* two`s complement of length */
-	s16	status;
-	u32	misc;
-	u32	reserved;
+	__le32	base;
+	__le16	length;		/* two`s complement of length */
+	__le16	status;
+	__le32	misc;
+	__le32	reserved;
 };
 
 /* The PCNET32 32-Bit initialization block, described in databook. */
 struct pcnet32_init_block {
-	u16	mode;
-	u16	tlen_rlen;
+	__le16	mode;
+	__le16	tlen_rlen;
 	u8	phys_addr[6];
-	u16	reserved;
-	u32	filter[2];
+	__le16	reserved;
+	__le32	filter[2];
 	/* Receive and transmit ring base, along with extra bits. */
-	u32	rx_ring;
-	u32	tx_ring;
+	__le32	rx_ring;
+	__le32	tx_ring;
 };
 
 /* PCnet32 access functions */
@@ -280,6 +280,8 @@
 	unsigned int		dirty_rx,	/* ring entries to be freed. */
 				dirty_tx;
 
+	struct net_device	*dev;
+	struct napi_struct	napi;
 	struct net_device_stats	stats;
 	char			tx_full;
 	char			phycount;	/* number of phys found */
@@ -440,15 +442,21 @@
 
 static void pcnet32_netif_stop(struct net_device *dev)
 {
+	struct pcnet32_private *lp = netdev_priv(dev);
 	dev->trans_start = jiffies;
-	netif_poll_disable(dev);
+#ifdef CONFIG_PCNET32_NAPI
+	napi_disable(&lp->napi);
+#endif
 	netif_tx_disable(dev);
 }
 
 static void pcnet32_netif_start(struct net_device *dev)
 {
+	struct pcnet32_private *lp = netdev_priv(dev);
 	netif_wake_queue(dev);
-	netif_poll_enable(dev);
+#ifdef CONFIG_PCNET32_NAPI
+	napi_enable(&lp->napi);
+#endif
 }
 
 /*
@@ -602,9 +610,9 @@
 		new_dma_addr_list[new] =
 			    pci_map_single(lp->pci_dev, rx_skbuff->data,
 					   PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
-		new_rx_ring[new].base = (u32) le32_to_cpu(new_dma_addr_list[new]);
-		new_rx_ring[new].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
-		new_rx_ring[new].status = le16_to_cpu(0x8000);
+		new_rx_ring[new].base = cpu_to_le32(new_dma_addr_list[new]);
+		new_rx_ring[new].buf_length = cpu_to_le16(2 - PKT_BUF_SZ);
+		new_rx_ring[new].status = cpu_to_le16(0x8000);
 	}
 	/* and free any unneeded buffers */
 	for (; new < lp->rx_ring_size; new++) {
@@ -816,7 +824,7 @@
 	if ((1 << i) != lp->rx_ring_size)
 		pcnet32_realloc_rx_ring(dev, lp, i);
 
-	dev->weight = lp->rx_ring_size / 2;
+	lp->napi.weight = lp->rx_ring_size / 2;
 
 	if (netif_running(dev)) {
 		pcnet32_netif_start(dev);
@@ -839,9 +847,14 @@
 	memcpy(data, pcnet32_gstrings_test, sizeof(pcnet32_gstrings_test));
 }
 
-static int pcnet32_self_test_count(struct net_device *dev)
+static int pcnet32_get_sset_count(struct net_device *dev, int sset)
 {
-	return PCNET32_TEST_LEN;
+	switch (sset) {
+	case ETH_SS_TEST:
+		return PCNET32_TEST_LEN;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void pcnet32_ethtool_test(struct net_device *dev,
@@ -875,7 +888,7 @@
 	int x, i;		/* counters */
 	int numbuffs = 4;	/* number of TX/RX buffers and descs */
 	u16 status = 0x8300;	/* TX ring status */
-	u16 teststatus;		/* test of ring status */
+	__le16 teststatus;	/* test of ring status */
 	int rc;			/* return code */
 	int size;		/* size of packets */
 	unsigned char *packet;	/* source packet data */
@@ -922,7 +935,7 @@
 			packet = skb->data;
 			skb_put(skb, size);	/* create space for data */
 			lp->tx_skbuff[x] = skb;
-			lp->tx_ring[x].length = le16_to_cpu(-skb->len);
+			lp->tx_ring[x].length = cpu_to_le16(-skb->len);
 			lp->tx_ring[x].misc = 0;
 
 			/* put DA and SA into the skb */
@@ -942,10 +955,9 @@
 			lp->tx_dma_addr[x] =
 			    pci_map_single(lp->pci_dev, skb->data, skb->len,
 					   PCI_DMA_TODEVICE);
-			lp->tx_ring[x].base =
-			    (u32) le32_to_cpu(lp->tx_dma_addr[x]);
+			lp->tx_ring[x].base = cpu_to_le32(lp->tx_dma_addr[x]);
 			wmb();	/* Make sure owner changes after all others are visible */
-			lp->tx_ring[x].status = le16_to_cpu(status);
+			lp->tx_ring[x].status = cpu_to_le16(status);
 		}
 	}
 
@@ -956,7 +968,7 @@
 	x = a->read_csr(ioaddr, CSR15) & 0xfffc;
 	lp->a.write_csr(ioaddr, CSR15, x | 0x0044);
 
-	teststatus = le16_to_cpu(0x8000);
+	teststatus = cpu_to_le16(0x8000);
 	lp->a.write_csr(ioaddr, CSR0, CSR0_START);	/* Set STRT bit */
 
 	/* Check status of descriptors */
@@ -1086,6 +1098,7 @@
 	mod_timer(&lp->blink_timer, jiffies);
 	set_current_state(TASK_INTERRUPTIBLE);
 
+	/* AV: the limit here makes no sense whatsoever */
 	if ((!data) || (data > (u32) (MAX_SCHEDULE_TIMEOUT / HZ)))
 		data = (u32) (MAX_SCHEDULE_TIMEOUT / HZ);
 
@@ -1211,7 +1224,7 @@
 							   newskb->data,
 							   PKT_BUF_SZ - 2,
 							   PCI_DMA_FROMDEVICE);
-			rxp->base = le32_to_cpu(lp->rx_dma_addr[entry]);
+			rxp->base = cpu_to_le32(lp->rx_dma_addr[entry]);
 			rx_in_place = 1;
 		} else
 			skb = NULL;
@@ -1255,7 +1268,7 @@
 	return;
 }
 
-static int pcnet32_rx(struct net_device *dev, int quota)
+static int pcnet32_rx(struct net_device *dev, int budget)
 {
 	struct pcnet32_private *lp = netdev_priv(dev);
 	int entry = lp->cur_rx & lp->rx_mod_mask;
@@ -1263,16 +1276,16 @@
 	int npackets = 0;
 
 	/* If we own the next entry, it's a new packet. Send it up. */
-	while (quota > npackets && (short)le16_to_cpu(rxp->status) >= 0) {
+	while (npackets < budget && (short)le16_to_cpu(rxp->status) >= 0) {
 		pcnet32_rx_entry(dev, lp, rxp, entry);
 		npackets += 1;
 		/*
 		 * The docs say that the buffer length isn't touched, but Andrew
 		 * Boyd of QNX reports that some revs of the 79C965 clear it.
 		 */
-		rxp->buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
+		rxp->buf_length = cpu_to_le16(2 - PKT_BUF_SZ);
 		wmb();	/* Make sure owner changes after others are visible */
-		rxp->status = le16_to_cpu(0x8000);
+		rxp->status = cpu_to_le16(0x8000);
 		entry = (++lp->cur_rx) & lp->rx_mod_mask;
 		rxp = &lp->rx_ring[entry];
 	}
@@ -1379,15 +1392,16 @@
 }
 
 #ifdef CONFIG_PCNET32_NAPI
-static int pcnet32_poll(struct net_device *dev, int *budget)
+static int pcnet32_poll(struct napi_struct *napi, int budget)
 {
-	struct pcnet32_private *lp = netdev_priv(dev);
-	int quota = min(dev->quota, *budget);
+	struct pcnet32_private *lp = container_of(napi, struct pcnet32_private, napi);
+	struct net_device *dev = lp->dev;
 	unsigned long ioaddr = dev->base_addr;
 	unsigned long flags;
+	int work_done;
 	u16 val;
 
-	quota = pcnet32_rx(dev, quota);
+	work_done = pcnet32_rx(dev, budget);
 
 	spin_lock_irqsave(&lp->lock, flags);
 	if (pcnet32_tx(dev)) {
@@ -1399,28 +1413,22 @@
 	}
 	spin_unlock_irqrestore(&lp->lock, flags);
 
-	*budget -= quota;
-	dev->quota -= quota;
+	if (work_done < budget) {
+		spin_lock_irqsave(&lp->lock, flags);
 
-	if (dev->quota == 0) {
-		return 1;
+		__netif_rx_complete(dev, napi);
+
+		/* clear interrupt masks */
+		val = lp->a.read_csr(ioaddr, CSR3);
+		val &= 0x00ff;
+		lp->a.write_csr(ioaddr, CSR3, val);
+
+		/* Set interrupt enable. */
+		lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN);
+		mmiowb();
+		spin_unlock_irqrestore(&lp->lock, flags);
 	}
-
-	netif_rx_complete(dev);
-
-	spin_lock_irqsave(&lp->lock, flags);
-
-	/* clear interrupt masks */
-	val = lp->a.read_csr(ioaddr, CSR3);
-	val &= 0x00ff;
-	lp->a.write_csr(ioaddr, CSR3, val);
-
-	/* Set interrupt enable. */
-	lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN);
-	mmiowb();
-	spin_unlock_irqrestore(&lp->lock, flags);
-
-	return 0;
+	return work_done;
 }
 #endif
 
@@ -1506,16 +1514,12 @@
 	.get_link		= pcnet32_get_link,
 	.get_ringparam		= pcnet32_get_ringparam,
 	.set_ringparam		= pcnet32_set_ringparam,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.get_sg			= ethtool_op_get_sg,
-	.get_tso		= ethtool_op_get_tso,
 	.get_strings		= pcnet32_get_strings,
-	.self_test_count	= pcnet32_self_test_count,
 	.self_test		= pcnet32_ethtool_test,
 	.phys_id		= pcnet32_phys_id,
 	.get_regs_len		= pcnet32_get_regs_len,
 	.get_regs		= pcnet32_get_regs,
-	.get_perm_addr		= ethtool_op_get_perm_addr,
+	.get_sset_count		= pcnet32_get_sset_count,
 };
 
 /* only probes for non-PCI devices, the rest are handled by
@@ -1816,9 +1820,10 @@
 	}
 	lp->pci_dev = pdev;
 
+	lp->dev = dev;
+
 	spin_lock_init(&lp->lock);
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 	lp->name = chipname;
 	lp->shared_irq = shared;
@@ -1844,6 +1849,10 @@
 	lp->mii_if.mdio_read = mdio_read;
 	lp->mii_if.mdio_write = mdio_write;
 
+#ifdef CONFIG_PCNET32_NAPI
+	netif_napi_add(dev, &lp->napi, pcnet32_poll, lp->rx_ring_size / 2);
+#endif
+
 	if (fdx && !(lp->options & PCNET32_PORT_ASEL) &&
 	    ((cards_found >= MAX_UNITS) || full_duplex[cards_found]))
 		lp->options |= PCNET32_PORT_FD;
@@ -1866,15 +1875,15 @@
 	    && dev->dev_addr[2] == 0x75)
 		lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI;
 
-	lp->init_block->mode = le16_to_cpu(0x0003);	/* Disable Rx and Tx. */
+	lp->init_block->mode = cpu_to_le16(0x0003);	/* Disable Rx and Tx. */
 	lp->init_block->tlen_rlen =
-	    le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits);
+	    cpu_to_le16(lp->tx_len_bits | lp->rx_len_bits);
 	for (i = 0; i < 6; i++)
 		lp->init_block->phys_addr[i] = dev->dev_addr[i];
 	lp->init_block->filter[0] = 0x00000000;
 	lp->init_block->filter[1] = 0x00000000;
-	lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
-	lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
+	lp->init_block->rx_ring = cpu_to_le32(lp->rx_ring_dma_addr);
+	lp->init_block->tx_ring = cpu_to_le32(lp->tx_ring_dma_addr);
 
 	/* switch pcnet32 to 32bit mode */
 	a->write_bcr(ioaddr, 20, 2);
@@ -1954,10 +1963,6 @@
 	dev->ethtool_ops = &pcnet32_ethtool_ops;
 	dev->tx_timeout = pcnet32_tx_timeout;
 	dev->watchdog_timeo = (5 * HZ);
-	dev->weight = lp->rx_ring_size / 2;
-#ifdef CONFIG_PCNET32_NAPI
-	dev->poll = pcnet32_poll;
-#endif
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = pcnet32_poll_controller;
@@ -2269,7 +2274,7 @@
 #endif
 
 	lp->init_block->mode =
-	    le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
+	    cpu_to_le16((lp->options & PCNET32_PORT_PORTSEL) << 7);
 	pcnet32_load_multicast(dev);
 
 	if (pcnet32_init_ring(dev)) {
@@ -2277,6 +2282,10 @@
 		goto err_free_ring;
 	}
 
+#ifdef CONFIG_PCNET32_NAPI
+	napi_enable(&lp->napi);
+#endif
+
 	/* Re-initialize the PCNET32, and start it when done. */
 	lp->a.write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff));
 	lp->a.write_csr(ioaddr, 2, (lp->init_dma_addr >> 16));
@@ -2392,10 +2401,10 @@
 			lp->rx_dma_addr[i] =
 			    pci_map_single(lp->pci_dev, rx_skbuff->data,
 					   PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
-		lp->rx_ring[i].base = (u32) le32_to_cpu(lp->rx_dma_addr[i]);
-		lp->rx_ring[i].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
+		lp->rx_ring[i].base = cpu_to_le32(lp->rx_dma_addr[i]);
+		lp->rx_ring[i].buf_length = cpu_to_le16(2 - PKT_BUF_SZ);
 		wmb();		/* Make sure owner changes after all others are visible */
-		lp->rx_ring[i].status = le16_to_cpu(0x8000);
+		lp->rx_ring[i].status = cpu_to_le16(0x8000);
 	}
 	/* The Tx buffer address is filled in as needed, but we do need to clear
 	 * the upper ownership bit. */
@@ -2407,11 +2416,11 @@
 	}
 
 	lp->init_block->tlen_rlen =
-	    le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits);
+	    cpu_to_le16(lp->tx_len_bits | lp->rx_len_bits);
 	for (i = 0; i < 6; i++)
 		lp->init_block->phys_addr[i] = dev->dev_addr[i];
-	lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr);
-	lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr);
+	lp->init_block->rx_ring = cpu_to_le32(lp->rx_ring_dma_addr);
+	lp->init_block->tx_ring = cpu_to_le32(lp->tx_ring_dma_addr);
 	wmb();			/* Make sure all changes are visible */
 	return 0;
 }
@@ -2520,16 +2529,16 @@
 	/* Caution: the write order is important here, set the status
 	 * with the "ownership" bits last. */
 
-	lp->tx_ring[entry].length = le16_to_cpu(-skb->len);
+	lp->tx_ring[entry].length = cpu_to_le16(-skb->len);
 
 	lp->tx_ring[entry].misc = 0x00000000;
 
 	lp->tx_skbuff[entry] = skb;
 	lp->tx_dma_addr[entry] =
 	    pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
-	lp->tx_ring[entry].base = (u32) le32_to_cpu(lp->tx_dma_addr[entry]);
+	lp->tx_ring[entry].base = cpu_to_le32(lp->tx_dma_addr[entry]);
 	wmb();			/* Make sure owner changes after all others are visible */
-	lp->tx_ring[entry].status = le16_to_cpu(status);
+	lp->tx_ring[entry].status = cpu_to_le16(status);
 
 	lp->cur_tx++;
 	lp->stats.tx_bytes += skb->len;
@@ -2600,18 +2609,18 @@
 			/* unlike for the lance, there is no restart needed */
 		}
 #ifdef CONFIG_PCNET32_NAPI
-		if (netif_rx_schedule_prep(dev)) {
+		if (netif_rx_schedule_prep(dev, &lp->napi)) {
 			u16 val;
 			/* set interrupt masks */
 			val = lp->a.read_csr(ioaddr, CSR3);
 			val |= 0x5f00;
 			lp->a.write_csr(ioaddr, CSR3, val);
 			mmiowb();
-			__netif_rx_schedule(dev);
+			__netif_rx_schedule(dev, &lp->napi);
 			break;
 		}
 #else
-		pcnet32_rx(dev, dev->weight);
+		pcnet32_rx(dev, lp->napi.weight);
 		if (pcnet32_tx(dev)) {
 			/* reset the chip to clear the error condition, then restart */
 			lp->a.reset(ioaddr);
@@ -2646,6 +2655,9 @@
 	del_timer_sync(&lp->watchdog_timer);
 
 	netif_stop_queue(dev);
+#ifdef CONFIG_PCNET32_NAPI
+	napi_disable(&lp->napi);
+#endif
 
 	spin_lock_irqsave(&lp->lock, flags);
 
@@ -2697,7 +2709,7 @@
 {
 	struct pcnet32_private *lp = netdev_priv(dev);
 	volatile struct pcnet32_init_block *ib = lp->init_block;
-	volatile u16 *mcast_table = (u16 *) & ib->filter;
+	volatile __le16 *mcast_table = (__le16 *)ib->filter;
 	struct dev_mc_list *dmi = dev->mc_list;
 	unsigned long ioaddr = dev->base_addr;
 	char *addrs;
@@ -2706,8 +2718,8 @@
 
 	/* set all multicast bits */
 	if (dev->flags & IFF_ALLMULTI) {
-		ib->filter[0] = 0xffffffff;
-		ib->filter[1] = 0xffffffff;
+		ib->filter[0] = cpu_to_le32(~0U);
+		ib->filter[1] = cpu_to_le32(~0U);
 		lp->a.write_csr(ioaddr, PCNET32_MC_FILTER, 0xffff);
 		lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+1, 0xffff);
 		lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+2, 0xffff);
@@ -2729,9 +2741,7 @@
 
 		crc = ether_crc_le(6, addrs);
 		crc = crc >> 26;
-		mcast_table[crc >> 4] =
-		    le16_to_cpu(le16_to_cpu(mcast_table[crc >> 4]) |
-				(1 << (crc & 0xf)));
+		mcast_table[crc >> 4] |= cpu_to_le16(1 << (crc & 0xf));
 	}
 	for (i = 0; i < 4; i++)
 		lp->a.write_csr(ioaddr, PCNET32_MC_FILTER + i,
@@ -2757,12 +2767,12 @@
 			printk(KERN_INFO "%s: Promiscuous mode enabled.\n",
 			       dev->name);
 		lp->init_block->mode =
-		    le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
+		    cpu_to_le16(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
 				7);
 		lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000);
 	} else {
 		lp->init_block->mode =
-		    le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
+		    cpu_to_le16((lp->options & PCNET32_PORT_PORTSEL) << 7);
 		lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff);
 		pcnet32_load_multicast(dev);
 	}
@@ -2944,6 +2954,33 @@
 	mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
 }
 
+static int pcnet32_pm_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+
+	if (netif_running(dev)) {
+		netif_device_detach(dev);
+		pcnet32_close(dev);
+	}
+	pci_save_state(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+	return 0;
+}
+
+static int pcnet32_pm_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	if (netif_running(dev)) {
+		pcnet32_open(dev);
+		netif_device_attach(dev);
+	}
+	return 0;
+}
+
 static void __devexit pcnet32_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
@@ -2967,6 +3004,8 @@
 	.probe = pcnet32_probe_pci,
 	.remove = __devexit_p(pcnet32_remove_one),
 	.id_table = pcnet32_pci_tbl,
+	.suspend = pcnet32_pm_suspend,
+	.resume = pcnet32_pm_resume,
 };
 
 /* An additional parameter that may be passed in... */
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index dd09011..54b2ba9 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -76,4 +76,27 @@
 	bool "Emulation for 100M Fdx fixed PHY behavior"
 	depends on FIXED_PHY
 
+config FIXED_MII_1000_FDX
+	bool "Emulation for 1000M Fdx fixed PHY behavior"
+	depends on FIXED_PHY
+
+config FIXED_MII_AMNT
+        int "Number of emulated PHYs to allocate "
+        depends on FIXED_PHY
+        default "1"
+        ---help---
+        Sometimes it is required to have several independent emulated
+        PHYs on the bus (in case of multi-eth but phy-less HW for instance).
+        This control will have specified number allocated for each fixed
+        PHY type enabled.
+
+config MDIO_BITBANG
+	tristate "Support for bitbanged MDIO buses"
+	help
+	  This module implements the MDIO bus protocol in software,
+	  for use by low level drivers that export the ability to
+	  drive the relevant pins.
+
+	  If in doubt, say N.
+
 endif # PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 8885650..3d6cc7b 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -13,3 +13,4 @@
 obj-$(CONFIG_BROADCOM_PHY)	+= broadcom.o
 obj-$(CONFIG_ICPLUS_PHY)	+= icplus.o
 obj-$(CONFIG_FIXED_PHY)		+= fixed.o
+obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
index bb96691..5619182 100644
--- a/drivers/net/phy/fixed.c
+++ b/drivers/net/phy/fixed.c
@@ -30,53 +30,31 @@
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/phy.h>
+#include <linux/phy_fixed.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
-#define MII_REGS_NUM	7
-
-/*
-    The idea is to emulate normal phy behavior by responding with
-    pre-defined values to mii BMCR read, so that read_status hook could
-    take all the needed info.
-*/
-
-struct fixed_phy_status {
-	u8 	link;
-	u16	speed;
-	u8 	duplex;
-};
-
-/*-----------------------------------------------------------------------------
- *  Private information hoder for mii_bus
- *-----------------------------------------------------------------------------*/
-struct fixed_info {
-	u16 *regs;
-	u8 regs_num;
-	struct fixed_phy_status phy_status;
-	struct phy_device *phydev; /* pointer to the container */
-	/* link & speed cb */
-	int(*link_update)(struct net_device*, struct fixed_phy_status*);
-
-};
+/* we need to track the allocated pointers in order to free them on exit */
+static struct fixed_info *fixed_phy_ptrs[CONFIG_FIXED_MII_AMNT*MAX_PHY_AMNT];
 
 /*-----------------------------------------------------------------------------
  *  If something weird is required to be done with link/speed,
  * network driver is able to assign a function to implement this.
  * May be useful for PHY's that need to be software-driven.
  *-----------------------------------------------------------------------------*/
-int fixed_mdio_set_link_update(struct phy_device* phydev,
-		int(*link_update)(struct net_device*, struct fixed_phy_status*))
+int fixed_mdio_set_link_update(struct phy_device *phydev,
+			       int (*link_update) (struct net_device *,
+						   struct fixed_phy_status *))
 {
 	struct fixed_info *fixed;
 
-	if(link_update == NULL)
+	if (link_update == NULL)
 		return -EINVAL;
 
-	if(phydev) {
-		if(phydev->bus)	{
+	if (phydev) {
+		if (phydev->bus) {
 			fixed = phydev->bus->priv;
 			fixed->link_update = link_update;
 			return 0;
@@ -84,54 +62,64 @@
 	}
 	return -EINVAL;
 }
+
 EXPORT_SYMBOL(fixed_mdio_set_link_update);
 
+struct fixed_info *fixed_mdio_get_phydev (int phydev_ind)
+{
+	if (phydev_ind >= MAX_PHY_AMNT)
+		return NULL;
+	return fixed_phy_ptrs[phydev_ind];
+}
+
+EXPORT_SYMBOL(fixed_mdio_get_phydev);
+
 /*-----------------------------------------------------------------------------
  *  This is used for updating internal mii regs from the status
  *-----------------------------------------------------------------------------*/
-#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX)
+#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX)
 static int fixed_mdio_update_regs(struct fixed_info *fixed)
 {
 	u16 *regs = fixed->regs;
 	u16 bmsr = 0;
 	u16 bmcr = 0;
 
-	if(!regs) {
+	if (!regs) {
 		printk(KERN_ERR "%s: regs not set up", __FUNCTION__);
 		return -EINVAL;
 	}
 
-	if(fixed->phy_status.link)
+	if (fixed->phy_status.link)
 		bmsr |= BMSR_LSTATUS;
 
-	if(fixed->phy_status.duplex) {
+	if (fixed->phy_status.duplex) {
 		bmcr |= BMCR_FULLDPLX;
 
-		switch ( fixed->phy_status.speed ) {
+		switch (fixed->phy_status.speed) {
 		case 100:
 			bmsr |= BMSR_100FULL;
 			bmcr |= BMCR_SPEED100;
-		break;
+			break;
 
 		case 10:
 			bmsr |= BMSR_10FULL;
-		break;
+			break;
 		}
 	} else {
-		switch ( fixed->phy_status.speed ) {
+		switch (fixed->phy_status.speed) {
 		case 100:
 			bmsr |= BMSR_100HALF;
 			bmcr |= BMCR_SPEED100;
-		break;
+			break;
 
 		case 10:
 			bmsr |= BMSR_100HALF;
-		break;
+			break;
 		}
 	}
 
-	regs[MII_BMCR] =  bmcr;
-	regs[MII_BMSR] =  bmsr | 0x800; /*we are always capable of 10 hdx*/
+	regs[MII_BMCR] = bmcr;
+	regs[MII_BMSR] = bmsr | 0x800;	/*we are always capable of 10 hdx */
 
 	return 0;
 }
@@ -141,29 +129,30 @@
 	struct fixed_info *fixed = bus->priv;
 
 	/* if user has registered link update callback, use it */
-	if(fixed->phydev)
-		if(fixed->phydev->attached_dev) {
-			if(fixed->link_update) {
+	if (fixed->phydev)
+		if (fixed->phydev->attached_dev) {
+			if (fixed->link_update) {
 				fixed->link_update(fixed->phydev->attached_dev,
-						&fixed->phy_status);
+						   &fixed->phy_status);
 				fixed_mdio_update_regs(fixed);
 			}
-	}
+		}
 
 	if ((unsigned int)location >= fixed->regs_num)
 		return -1;
 	return fixed->regs[location];
 }
 
-static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val)
+static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location,
+			   u16 val)
 {
-	/* do nothing for now*/
+	/* do nothing for now */
 	return 0;
 }
 
 static int fixed_mii_reset(struct mii_bus *bus)
 {
-	/*nothing here - no way/need to reset it*/
+	/*nothing here - no way/need to reset it */
 	return 0;
 }
 #endif
@@ -171,8 +160,8 @@
 static int fixed_config_aneg(struct phy_device *phydev)
 {
 	/* :TODO:03/13/2006 09:45:37 PM::
-	 The full autoneg funcionality can be emulated,
-	 but no need to have anything here for now
+	   The full autoneg funcionality can be emulated,
+	   but no need to have anything here for now
 	 */
 	return 0;
 }
@@ -182,59 +171,79 @@
  * match will never return true...
  *-----------------------------------------------------------------------------*/
 static struct phy_driver fixed_mdio_driver = {
-	.name		= "Fixed PHY",
-	.features	= PHY_BASIC_FEATURES,
-	.config_aneg	= fixed_config_aneg,
-	.read_status	= genphy_read_status,
-	.driver 	= { .owner = THIS_MODULE,},
+	.name = "Fixed PHY",
+#ifdef CONFIG_FIXED_MII_1000_FDX
+	.features = PHY_GBIT_FEATURES,
+#else
+	.features = PHY_BASIC_FEATURES,
+#endif
+	.config_aneg = fixed_config_aneg,
+	.read_status = genphy_read_status,
+	.driver = { .owner = THIS_MODULE, },
 };
 
+static void fixed_mdio_release(struct device *dev)
+{
+	struct phy_device *phydev = container_of(dev, struct phy_device, dev);
+	struct mii_bus *bus = phydev->bus;
+	struct fixed_info *fixed = bus->priv;
+
+	kfree(phydev);
+	kfree(bus->dev);
+	kfree(bus);
+	kfree(fixed->regs);
+	kfree(fixed);
+}
+
 /*-----------------------------------------------------------------------------
  *  This func is used to create all the necessary stuff, bind
  * the fixed phy driver and register all it on the mdio_bus_type.
- * speed is either 10 or 100, duplex is boolean.
+ * speed is either 10 or 100 or 1000, duplex is boolean.
  * number is used to create multiple fixed PHYs, so that several devices can
  * utilize them simultaneously.
+ *
+ * The device on mdio bus will look like [bus_id]:[phy_id],
+ * bus_id = number
+ * phy_id = speed+duplex.
  *-----------------------------------------------------------------------------*/
-#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX)
-static int fixed_mdio_register_device(int number, int speed, int duplex)
+#if defined(CONFIG_FIXED_MII_100_FDX) || defined(CONFIG_FIXED_MII_10_FDX) || defined(CONFIG_FIXED_MII_1000_FDX)
+struct fixed_info *fixed_mdio_register_device(
+	int bus_id, int speed, int duplex, u8 phy_id)
 {
 	struct mii_bus *new_bus;
 	struct fixed_info *fixed;
 	struct phy_device *phydev;
-	int err = 0;
+	int err;
 
-	struct device* dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+	struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
 
-	if (NULL == dev)
-		return -ENOMEM;
+	if (dev == NULL)
+		goto err_dev_alloc;
 
 	new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
 
-	if (NULL == new_bus) {
-		kfree(dev);
-		return -ENOMEM;
-	}
+	if (new_bus == NULL)
+		goto err_bus_alloc;
+
 	fixed = kzalloc(sizeof(struct fixed_info), GFP_KERNEL);
 
-	if (NULL == fixed) {
-		kfree(dev);
-		kfree(new_bus);
-		return -ENOMEM;
-	}
+	if (fixed == NULL)
+		goto err_fixed_alloc;
 
-	fixed->regs = kzalloc(MII_REGS_NUM*sizeof(int), GFP_KERNEL);
+	fixed->regs = kzalloc(MII_REGS_NUM * sizeof(int), GFP_KERNEL);
+	if (NULL == fixed->regs)
+		goto err_fixed_regs_alloc;
+
 	fixed->regs_num = MII_REGS_NUM;
 	fixed->phy_status.speed = speed;
 	fixed->phy_status.duplex = duplex;
 	fixed->phy_status.link = 1;
 
-	new_bus->name = "Fixed MII Bus",
-	new_bus->read = &fixed_mii_read,
-	new_bus->write = &fixed_mii_write,
-	new_bus->reset = &fixed_mii_reset,
-
-	/*set up workspace*/
+	new_bus->name = "Fixed MII Bus";
+	new_bus->read = &fixed_mii_read;
+	new_bus->write = &fixed_mii_write;
+	new_bus->reset = &fixed_mii_reset;
+	/*set up workspace */
 	fixed_mdio_update_regs(fixed);
 	new_bus->priv = fixed;
 
@@ -243,119 +252,110 @@
 
 	/* create phy_device and register it on the mdio bus */
 	phydev = phy_device_create(new_bus, 0, 0);
+	if (phydev == NULL)
+		goto err_phy_dev_create;
 
 	/*
-	 Put the phydev pointer into the fixed pack so that bus read/write code could
-	 be able to access for instance attached netdev. Well it doesn't have to do
-	 so, only in case of utilizing user-specified link-update...
+	 * Put the phydev pointer into the fixed pack so that bus read/write
+	 * code could be able to access for instance attached netdev. Well it
+	 * doesn't have to do so, only in case of utilizing user-specified
+	 * link-update...
 	 */
-	fixed->phydev = phydev;
 
-	if(NULL == phydev) {
-		err = -ENOMEM;
-		goto device_create_fail;
-	}
+	fixed->phydev = phydev;
+	phydev->speed = speed;
+	phydev->duplex = duplex;
 
 	phydev->irq = PHY_IGNORE_INTERRUPT;
 	phydev->dev.bus = &mdio_bus_type;
 
-	if(number)
-		snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
-				"fixed_%d@%d:%d", number, speed, duplex);
-	else
-		snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
-				"fixed@%d:%d", speed, duplex);
+	snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
+		 PHY_ID_FMT, bus_id, phy_id);
+
 	phydev->bus = new_bus;
 
-	err = device_register(&phydev->dev);
-	if(err) {
-		printk(KERN_ERR "Phy %s failed to register\n",
-				phydev->dev.bus_id);
-		goto bus_register_fail;
-	}
-
-	/*
-	   the mdio bus has phy_id match... In order not to do it
-	   artificially, we are binding the driver here by hand;
-	   it will be the same for all the fixed phys anyway.
-	 */
 	phydev->dev.driver = &fixed_mdio_driver.driver;
-
+	phydev->dev.release = fixed_mdio_release;
 	err = phydev->dev.driver->probe(&phydev->dev);
-	if(err < 0) {
-		printk(KERN_ERR "Phy %s: problems with fixed driver\n",phydev->dev.bus_id);
-		goto probe_fail;
+	if (err < 0) {
+		printk(KERN_ERR "Phy %s: problems with fixed driver\n",
+		       phydev->dev.bus_id);
+		goto err_out;
 	}
+	err = device_register(&phydev->dev);
+	if (err) {
+		printk(KERN_ERR "Phy %s failed to register\n",
+		       phydev->dev.bus_id);
+		goto err_out;
+	}
+	//phydev->state = PHY_RUNNING; /* make phy go up quick, but in 10Mbit/HDX
+	return fixed;
 
-	err = device_bind_driver(&phydev->dev);
-	if (err)
-		goto probe_fail;
-
-	return 0;
-
-probe_fail:
-	device_unregister(&phydev->dev);
-bus_register_fail:
+err_out:
 	kfree(phydev);
-device_create_fail:
-	kfree(dev);
-	kfree(new_bus);
+err_phy_dev_create:
+	kfree(fixed->regs);
+err_fixed_regs_alloc:
 	kfree(fixed);
+err_fixed_alloc:
+	kfree(new_bus);
+err_bus_alloc:
+	kfree(dev);
+err_dev_alloc:
 
-	return err;
+	return NULL;
+
 }
 #endif
 
-
 MODULE_DESCRIPTION("Fixed PHY device & driver for PAL");
 MODULE_AUTHOR("Vitaly Bordug");
 MODULE_LICENSE("GPL");
 
 static int __init fixed_init(void)
 {
-#if 0
-	int ret;
-	int duplex = 0;
-#endif
-
-	/* register on the bus... Not expected to be matched with anything there... */
+	int cnt = 0;
+	int i;
+/* register on the bus... Not expected to be matched
+ * with anything there...
+ *
+ */
 	phy_driver_register(&fixed_mdio_driver);
 
-	/* So let the fun begin...
-	   We will create several mdio devices here, and will bound the upper
-	   driver to them.
-
-	   Then the external software can lookup the phy bus by searching
-	   fixed@speed:duplex, e.g. fixed@100:1, to be connected to the
-	   virtual 100M Fdx phy.
-
-	   In case several virtual PHYs required, the bus_id will be in form
-	   fixed_<num>@<speed>:<duplex>, which make it able even to define
-	   driver-specific link control callback, if for instance PHY is completely
-	   SW-driven.
-
-	*/
-
-#ifdef CONFIG_FIXED_MII_DUPLEX
-#if 0
-	duplex = 1;
+/* We will create several mdio devices here, and will bound the upper
+ * driver to them.
+ *
+ * Then the external software can lookup the phy bus by searching
+ * for 0:101, to be connected to the virtual 100M Fdx phy.
+ *
+ * In case several virtual PHYs required, the bus_id will be in form
+ * [num]:[duplex]+[speed], which make it able even to define
+ * driver-specific link control callback, if for instance PHY is
+ * completely SW-driven.
+ */
+	for (i=1; i <= CONFIG_FIXED_MII_AMNT; i++) {
+#ifdef CONFIG_FIXED_MII_1000_FDX
+		fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(0, 1000, 1, i);
 #endif
-#endif
-
 #ifdef CONFIG_FIXED_MII_100_FDX
-	fixed_mdio_register_device(0, 100, 1);
+		fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(1, 100, 1, i);
 #endif
-
 #ifdef CONFIG_FIXED_MII_10_FDX
-	fixed_mdio_register_device(0, 10, 1);
+		fixed_phy_ptrs[cnt++] = fixed_mdio_register_device(2, 10, 1, i);
 #endif
+	}
+
 	return 0;
 }
 
 static void __exit fixed_exit(void)
 {
+	int i;
+
 	phy_driver_unregister(&fixed_mdio_driver);
-	/* :WARNING:02/18/2006 04:32:40 AM:: Cleanup all the created stuff */
+	for (i=0; i < MAX_PHY_AMNT; i++)
+		if ( fixed_phy_ptrs[i] )
+			device_unregister(&fixed_phy_ptrs[i]->phydev->dev);
 }
 
 module_init(fixed_init);
diff --git a/drivers/net/phy/mdio-bitbang.c b/drivers/net/phy/mdio-bitbang.c
new file mode 100644
index 0000000..8cd243d
--- /dev/null
+++ b/drivers/net/phy/mdio-bitbang.c
@@ -0,0 +1,187 @@
+/*
+ * Bitbanged MDIO support.
+ *
+ * Author: Scott Wood <scottwood@freescale.com>
+ * Copyright (c) 2007 Freescale Semiconductor
+ *
+ * Based on CPM2 MDIO code which is:
+ *
+ * Copyright (c) 2003 Intracom S.A.
+ *  by Pantelis Antoniou <panto@intracom.gr>
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/mdio-bitbang.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#define MDIO_READ 1
+#define MDIO_WRITE 0
+
+#define MDIO_SETUP_TIME 10
+#define MDIO_HOLD_TIME 10
+
+/* Minimum MDC period is 400 ns, plus some margin for error.  MDIO_DELAY
+ * is done twice per period.
+ */
+#define MDIO_DELAY 250
+
+/* The PHY may take up to 300 ns to produce data, plus some margin
+ * for error.
+ */
+#define MDIO_READ_DELAY 350
+
+/* MDIO must already be configured as output. */
+static void mdiobb_send_bit(struct mdiobb_ctrl *ctrl, int val)
+{
+	const struct mdiobb_ops *ops = ctrl->ops;
+
+	ops->set_mdio_data(ctrl, val);
+	ndelay(MDIO_DELAY);
+	ops->set_mdc(ctrl, 1);
+	ndelay(MDIO_DELAY);
+	ops->set_mdc(ctrl, 0);
+}
+
+/* MDIO must already be configured as input. */
+static int mdiobb_get_bit(struct mdiobb_ctrl *ctrl)
+{
+	const struct mdiobb_ops *ops = ctrl->ops;
+
+	ndelay(MDIO_DELAY);
+	ops->set_mdc(ctrl, 1);
+	ndelay(MDIO_READ_DELAY);
+	ops->set_mdc(ctrl, 0);
+
+	return ops->get_mdio_data(ctrl);
+}
+
+/* MDIO must already be configured as output. */
+static void mdiobb_send_num(struct mdiobb_ctrl *ctrl, u16 val, int bits)
+{
+	int i;
+
+	for (i = bits - 1; i >= 0; i--)
+		mdiobb_send_bit(ctrl, (val >> i) & 1);
+}
+
+/* MDIO must already be configured as input. */
+static u16 mdiobb_get_num(struct mdiobb_ctrl *ctrl, int bits)
+{
+	int i;
+	u16 ret = 0;
+
+	for (i = bits - 1; i >= 0; i--) {
+		ret <<= 1;
+		ret |= mdiobb_get_bit(ctrl);
+	}
+
+	return ret;
+}
+
+/* Utility to send the preamble, address, and
+ * register (common to read and write).
+ */
+static void mdiobb_cmd(struct mdiobb_ctrl *ctrl, int read, u8 phy, u8 reg)
+{
+	const struct mdiobb_ops *ops = ctrl->ops;
+	int i;
+
+	ops->set_mdio_dir(ctrl, 1);
+
+	/*
+	 * Send a 32 bit preamble ('1's) with an extra '1' bit for good
+	 * measure.  The IEEE spec says this is a PHY optional
+	 * requirement.  The AMD 79C874 requires one after power up and
+	 * one after a MII communications error.  This means that we are
+	 * doing more preambles than we need, but it is safer and will be
+	 * much more robust.
+	 */
+
+	for (i = 0; i < 32; i++)
+		mdiobb_send_bit(ctrl, 1);
+
+	/* send the start bit (01) and the read opcode (10) or write (10) */
+	mdiobb_send_bit(ctrl, 0);
+	mdiobb_send_bit(ctrl, 1);
+	mdiobb_send_bit(ctrl, read);
+	mdiobb_send_bit(ctrl, !read);
+
+	mdiobb_send_num(ctrl, phy, 5);
+	mdiobb_send_num(ctrl, reg, 5);
+}
+
+
+static int mdiobb_read(struct mii_bus *bus, int phy, int reg)
+{
+	struct mdiobb_ctrl *ctrl = bus->priv;
+	int ret, i;
+
+	mdiobb_cmd(ctrl, MDIO_READ, phy, reg);
+	ctrl->ops->set_mdio_dir(ctrl, 0);
+
+	/* check the turnaround bit: the PHY should be driving it to zero */
+	if (mdiobb_get_bit(ctrl) != 0) {
+		/* PHY didn't drive TA low -- flush any bits it
+		 * may be trying to send.
+		 */
+		for (i = 0; i < 32; i++)
+			mdiobb_get_bit(ctrl);
+
+		return 0xffff;
+	}
+
+	ret = mdiobb_get_num(ctrl, 16);
+	mdiobb_get_bit(ctrl);
+	return ret;
+}
+
+static int mdiobb_write(struct mii_bus *bus, int phy, int reg, u16 val)
+{
+	struct mdiobb_ctrl *ctrl = bus->priv;
+
+	mdiobb_cmd(ctrl, MDIO_WRITE, phy, reg);
+
+	/* send the turnaround (10) */
+	mdiobb_send_bit(ctrl, 1);
+	mdiobb_send_bit(ctrl, 0);
+
+	mdiobb_send_num(ctrl, val, 16);
+
+	ctrl->ops->set_mdio_dir(ctrl, 0);
+	mdiobb_get_bit(ctrl);
+	return 0;
+}
+
+struct mii_bus *alloc_mdio_bitbang(struct mdiobb_ctrl *ctrl)
+{
+	struct mii_bus *bus;
+
+	bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+	if (!bus)
+		return NULL;
+
+	__module_get(ctrl->ops->owner);
+
+	bus->read = mdiobb_read;
+	bus->write = mdiobb_write;
+	bus->priv = ctrl;
+
+	return bus;
+}
+
+void free_mdio_bitbang(struct mii_bus *bus)
+{
+	struct mdiobb_ctrl *ctrl = bus->priv;
+
+	module_put(ctrl->ops->owner);
+	kfree(bus);
+}
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index f71dab3..9bc1177 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -7,7 +7,7 @@
  * Author: Andy Fleming
  *
  * Copyright (c) 2004 Freescale Semiconductor, Inc.
- * Copyright (c) 2006  Maciej W. Rozycki
+ * Copyright (c) 2006, 2007  Maciej W. Rozycki
  *
  * 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
@@ -35,6 +35,7 @@
 #include <linux/timer.h>
 #include <linux/workqueue.h>
 
+#include <asm/atomic.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
@@ -204,7 +205,7 @@
 	},
 };
 
-#define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting))
+#define MAX_NUM_SETTINGS ARRAY_SIZE(settings)
 
 /**
  * phy_find_setting - find a PHY settings array entry that matches speed & duplex
@@ -261,7 +262,7 @@
 
 	/* Sanitize settings based on PHY capabilities */
 	if ((features & SUPPORTED_Autoneg) == 0)
-		phydev->autoneg = 0;
+		phydev->autoneg = AUTONEG_DISABLE;
 
 	idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex),
 			features);
@@ -374,7 +375,7 @@
 		if (mii_data->phy_id == phydev->addr) {
 			switch(mii_data->reg_num) {
 			case MII_BMCR:
-				if (val & (BMCR_RESET|BMCR_ANENABLE))
+				if ((val & (BMCR_RESET|BMCR_ANENABLE)) == 0)
 					phydev->autoneg = AUTONEG_DISABLE;
 				else
 					phydev->autoneg = AUTONEG_ENABLE;
@@ -409,6 +410,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(phy_mii_ioctl);
 
 /**
  * phy_start_aneg - start auto-negotiation for this PHY device
@@ -423,7 +425,7 @@
 {
 	int err;
 
-	spin_lock(&phydev->lock);
+	spin_lock_bh(&phydev->lock);
 
 	if (AUTONEG_DISABLE == phydev->autoneg)
 		phy_sanitize_settings(phydev);
@@ -444,7 +446,7 @@
 	}
 
 out_unlock:
-	spin_unlock(&phydev->lock);
+	spin_unlock_bh(&phydev->lock);
 	return err;
 }
 EXPORT_SYMBOL(phy_start_aneg);
@@ -489,10 +491,10 @@
 {
 	del_timer_sync(&phydev->phy_timer);
 
-	spin_lock(&phydev->lock);
+	spin_lock_bh(&phydev->lock);
 	if (phydev->state > PHY_UP)
 		phydev->state = PHY_UP;
-	spin_unlock(&phydev->lock);
+	spin_unlock_bh(&phydev->lock);
 
 	phydev->adjust_state = NULL;
 }
@@ -536,9 +538,9 @@
  */
 void phy_error(struct phy_device *phydev)
 {
-	spin_lock(&phydev->lock);
+	spin_lock_bh(&phydev->lock);
 	phydev->state = PHY_HALTED;
-	spin_unlock(&phydev->lock);
+	spin_unlock_bh(&phydev->lock);
 }
 
 /**
@@ -561,6 +563,7 @@
 	 * queue will write the PHY to disable and clear the
 	 * interrupt, and then reenable the irq line. */
 	disable_irq_nosync(irq);
+	atomic_inc(&phydev->irq_disable);
 
 	schedule_work(&phydev->phy_queue);
 
@@ -631,6 +634,7 @@
 
 	INIT_WORK(&phydev->phy_queue, phy_change);
 
+	atomic_set(&phydev->irq_disable, 0);
 	if (request_irq(phydev->irq, phy_interrupt,
 				IRQF_SHARED,
 				"phy_interrupt",
@@ -661,13 +665,22 @@
 	if (err)
 		phy_error(phydev);
 
+	free_irq(phydev->irq, phydev);
+
 	/*
-	 * Finish any pending work; we might have been scheduled to be called
-	 * from keventd ourselves, but cancel_work_sync() handles that.
+	 * Cannot call flush_scheduled_work() here as desired because
+	 * of rtnl_lock(), but we do not really care about what would
+	 * be done, except from enable_irq(), so cancel any work
+	 * possibly pending and take care of the matter below.
 	 */
 	cancel_work_sync(&phydev->phy_queue);
-
-	free_irq(phydev->irq, phydev);
+	/*
+	 * If work indeed has been cancelled, disable_irq() will have
+	 * been left unbalanced from phy_interrupt() and enable_irq()
+	 * has to be called so that other devices on the line work.
+	 */
+	while (atomic_dec_return(&phydev->irq_disable) >= 0)
+		enable_irq(phydev->irq);
 
 	return err;
 }
@@ -689,11 +702,12 @@
 	if (err)
 		goto phy_err;
 
-	spin_lock(&phydev->lock);
+	spin_lock_bh(&phydev->lock);
 	if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
 		phydev->state = PHY_CHANGELINK;
-	spin_unlock(&phydev->lock);
+	spin_unlock_bh(&phydev->lock);
 
+	atomic_dec(&phydev->irq_disable);
 	enable_irq(phydev->irq);
 
 	/* Reenable interrupts */
@@ -707,6 +721,7 @@
 
 irq_enable_err:
 	disable_irq(phydev->irq);
+	atomic_inc(&phydev->irq_disable);
 phy_err:
 	phy_error(phydev);
 }
@@ -717,13 +732,11 @@
  */
 void phy_stop(struct phy_device *phydev)
 {
-	spin_lock(&phydev->lock);
+	spin_lock_bh(&phydev->lock);
 
 	if (PHY_HALTED == phydev->state)
 		goto out_unlock;
 
-	phydev->state = PHY_HALTED;
-
 	if (phydev->irq != PHY_POLL) {
 		/* Disable PHY Interrupts */
 		phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
@@ -732,8 +745,10 @@
 		phy_clear_interrupt(phydev);
 	}
 
+	phydev->state = PHY_HALTED;
+
 out_unlock:
-	spin_unlock(&phydev->lock);
+	spin_unlock_bh(&phydev->lock);
 
 	/*
 	 * Cannot call flush_scheduled_work() here as desired because
@@ -755,7 +770,7 @@
  */
 void phy_start(struct phy_device *phydev)
 {
-	spin_lock(&phydev->lock);
+	spin_lock_bh(&phydev->lock);
 
 	switch (phydev->state) {
 		case PHY_STARTING:
@@ -769,7 +784,7 @@
 		default:
 			break;
 	}
-	spin_unlock(&phydev->lock);
+	spin_unlock_bh(&phydev->lock);
 }
 EXPORT_SYMBOL(phy_stop);
 EXPORT_SYMBOL(phy_start);
@@ -781,7 +796,7 @@
 	int needs_aneg = 0;
 	int err = 0;
 
-	spin_lock(&phydev->lock);
+	spin_lock_bh(&phydev->lock);
 
 	if (phydev->adjust_state)
 		phydev->adjust_state(phydev->attached_dev);
@@ -947,7 +962,7 @@
 			break;
 	}
 
-	spin_unlock(&phydev->lock);
+	spin_unlock_bh(&phydev->lock);
 
 	if (needs_aneg)
 		err = phy_start_aneg(phydev);
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index a8b74cd..c046121 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -364,7 +364,7 @@
  */
 int genphy_setup_forced(struct phy_device *phydev)
 {
-	int ctl = BMCR_RESET;
+	int ctl = 0;
 
 	phydev->pause = phydev->asym_pause = 0;
 
@@ -644,7 +644,7 @@
 	if (!(phydrv->flags & PHY_HAS_INTERRUPT))
 		phydev->irq = PHY_POLL;
 
-	spin_lock(&phydev->lock);
+	spin_lock_bh(&phydev->lock);
 
 	/* Start out supporting everything. Eventually,
 	 * a controller will attach, and may modify one
@@ -658,7 +658,7 @@
 	if (phydev->drv->probe)
 		err = phydev->drv->probe(phydev);
 
-	spin_unlock(&phydev->lock);
+	spin_unlock_bh(&phydev->lock);
 
 	return err;
 
@@ -670,9 +670,9 @@
 
 	phydev = to_phy_device(dev);
 
-	spin_lock(&phydev->lock);
+	spin_lock_bh(&phydev->lock);
 	phydev->state = PHY_DOWN;
-	spin_unlock(&phydev->lock);
+	spin_unlock_bh(&phydev->lock);
 
 	if (phydev->drv->remove)
 		phydev->drv->remove(phydev);
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index 596222b..8874497 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -21,6 +21,10 @@
 /* Vitesse Extended Control Register 1 */
 #define MII_VSC8244_EXT_CON1           0x17
 #define MII_VSC8244_EXTCON1_INIT       0x0000
+#define MII_VSC8244_EXTCON1_TX_SKEW_MASK	0x0c00
+#define MII_VSC8244_EXTCON1_RX_SKEW_MASK	0x0300
+#define MII_VSC8244_EXTCON1_TX_SKEW	0x0800
+#define MII_VSC8244_EXTCON1_RX_SKEW	0x0200
 
 /* Vitesse Interrupt Mask Register */
 #define MII_VSC8244_IMASK		0x19
@@ -39,7 +43,7 @@
 
 /* Vitesse Auxiliary Control/Status Register */
 #define MII_VSC8244_AUX_CONSTAT        	0x1c
-#define MII_VSC8244_AUXCONSTAT_INIT    	0x0004
+#define MII_VSC8244_AUXCONSTAT_INIT    	0x0000
 #define MII_VSC8244_AUXCONSTAT_DUPLEX  	0x0020
 #define MII_VSC8244_AUXCONSTAT_SPEED   	0x0018
 #define MII_VSC8244_AUXCONSTAT_GBIT    	0x0010
@@ -51,6 +55,7 @@
 
 static int vsc824x_config_init(struct phy_device *phydev)
 {
+	int extcon;
 	int err;
 
 	err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT,
@@ -58,14 +63,34 @@
 	if (err < 0)
 		return err;
 
-	err = phy_write(phydev, MII_VSC8244_EXT_CON1,
-			MII_VSC8244_EXTCON1_INIT);
+	extcon = phy_read(phydev, MII_VSC8244_EXT_CON1);
+
+	if (extcon < 0)
+		return err;
+
+	extcon &= ~(MII_VSC8244_EXTCON1_TX_SKEW_MASK |
+			MII_VSC8244_EXTCON1_RX_SKEW_MASK);
+
+	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
+		extcon |= (MII_VSC8244_EXTCON1_TX_SKEW |
+				MII_VSC8244_EXTCON1_RX_SKEW);
+
+	err = phy_write(phydev, MII_VSC8244_EXT_CON1, extcon);
+
 	return err;
 }
 
 static int vsc824x_ack_interrupt(struct phy_device *phydev)
 {
-	int err = phy_read(phydev, MII_VSC8244_ISTAT);
+	int err = 0;
+	
+	/*
+	 * Don't bother to ACK the interrupts if interrupts
+	 * are disabled.  The 824x cannot clear the interrupts
+	 * if they are disabled.
+	 */
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_read(phydev, MII_VSC8244_ISTAT);
 
 	return (err < 0) ? err : 0;
 }
@@ -77,8 +102,19 @@
 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
 		err = phy_write(phydev, MII_VSC8244_IMASK,
 				MII_VSC8244_IMASK_MASK);
-	else
+	else {
+		/*
+		 * The Vitesse PHY cannot clear the interrupt
+		 * once it has disabled them, so we clear them first
+		 */
+		err = phy_read(phydev, MII_VSC8244_ISTAT);
+
+		if (err < 0)
+			return err;
+
 		err = phy_write(phydev, MII_VSC8244_IMASK, 0);
+	}
+
 	return err;
 }
 
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index 8754cf3..b5e9981 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -148,13 +148,12 @@
 /* Functions for DEV methods */
 static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev);
 static int plip_hard_header(struct sk_buff *skb, struct net_device *dev,
-                            unsigned short type, void *daddr,
-                            void *saddr, unsigned len);
-static int plip_hard_header_cache(struct neighbour *neigh,
+                            unsigned short type, const void *daddr,
+			    const void *saddr, unsigned len);
+static int plip_hard_header_cache(const struct neighbour *neigh,
                                   struct hh_cache *hh);
 static int plip_open(struct net_device *dev);
 static int plip_close(struct net_device *dev);
-static struct net_device_stats *plip_get_stats(struct net_device *dev);
 static int plip_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 static int plip_preempt(void *handle);
 static void plip_wakeup(void *handle);
@@ -206,7 +205,6 @@
 };
 
 struct net_local {
-	struct net_device_stats enet_stats;
 	struct net_device *dev;
 	struct work_struct immediate;
 	struct delayed_work deferred;
@@ -221,11 +219,6 @@
 	int is_deferred;
 	int port_owner;
 	int should_relinquish;
-	int (*orig_hard_header)(struct sk_buff *skb, struct net_device *dev,
-	                        unsigned short type, void *daddr,
-	                        void *saddr, unsigned len);
-	int (*orig_hard_header_cache)(struct neighbour *neigh,
-	                              struct hh_cache *hh);
 	spinlock_t lock;
 	atomic_t kill_timer;
 	struct semaphore killed_timer_sem;
@@ -267,6 +260,11 @@
 	return port->ops->read_status (port);
 }
 
+static const struct header_ops plip_header_ops = {
+	.create	= plip_hard_header,
+	.cache  = plip_hard_header_cache,
+};
+
 /* Entry point of PLIP driver.
    Probe the hardware, and register/initialize the driver.
 
@@ -285,19 +283,13 @@
 	dev->hard_start_xmit	 = plip_tx_packet;
 	dev->open		 = plip_open;
 	dev->stop		 = plip_close;
-	dev->get_stats 		 = plip_get_stats;
 	dev->do_ioctl		 = plip_ioctl;
-	dev->header_cache_update = NULL;
+
 	dev->tx_queue_len 	 = 10;
 	dev->flags	         = IFF_POINTOPOINT|IFF_NOARP;
 	memset(dev->dev_addr, 0xfc, ETH_ALEN);
 
-	/* Set the private structure */
-	nl->orig_hard_header    = dev->hard_header;
-	dev->hard_header        = plip_hard_header;
-
-	nl->orig_hard_header_cache = dev->hard_header_cache;
-	dev->hard_header_cache     = plip_hard_header_cache;
+	dev->header_ops          = &plip_header_ops;
 
 
 	nl->port_owner = 0;
@@ -430,8 +422,8 @@
 			       dev->name, snd->state, c0);
 		} else
 			error = HS_TIMEOUT;
-		nl->enet_stats.tx_errors++;
-		nl->enet_stats.tx_aborted_errors++;
+		dev->stats.tx_errors++;
+		dev->stats.tx_aborted_errors++;
 	} else if (nl->connection == PLIP_CN_RECEIVE) {
 		if (rcv->state == PLIP_PK_TRIGGER) {
 			/* Transmission was interrupted. */
@@ -448,7 +440,7 @@
 			printk(KERN_WARNING "%s: receive timeout(%d,%02x)\n",
 			       dev->name, rcv->state, c0);
 		}
-		nl->enet_stats.rx_dropped++;
+		dev->stats.rx_dropped++;
 	}
 	rcv->state = PLIP_PK_DONE;
 	if (rcv->skb) {
@@ -661,7 +653,7 @@
 				 &rcv->nibble, &rcv->data))
 			return TIMEOUT;
 		if (rcv->data != rcv->checksum) {
-			nl->enet_stats.rx_crc_errors++;
+			dev->stats.rx_crc_errors++;
 			if (net_debug)
 				printk(KERN_DEBUG "%s: checksum error\n", dev->name);
 			return ERROR;
@@ -673,8 +665,8 @@
 		rcv->skb->protocol=plip_type_trans(rcv->skb, dev);
 		netif_rx(rcv->skb);
 		dev->last_rx = jiffies;
-		nl->enet_stats.rx_bytes += rcv->length.h;
-		nl->enet_stats.rx_packets++;
+		dev->stats.rx_bytes += rcv->length.h;
+		dev->stats.rx_packets++;
 		rcv->skb = NULL;
 		if (net_debug > 2)
 			printk(KERN_DEBUG "%s: receive end\n", dev->name);
@@ -776,7 +768,7 @@
 			if (nl->connection == PLIP_CN_RECEIVE) {
 				spin_unlock_irq(&nl->lock);
 				/* Interrupted. */
-				nl->enet_stats.collisions++;
+				dev->stats.collisions++;
 				return OK;
 			}
 			c0 = read_status(dev);
@@ -792,7 +784,7 @@
 					   {enable,disable}_irq *counts*
 					   them.  -- AV  */
 					ENABLE(dev->irq);
-					nl->enet_stats.collisions++;
+					dev->stats.collisions++;
 					return OK;
 				}
 				disable_parport_interrupts (dev);
@@ -840,9 +832,9 @@
 			      &snd->nibble, snd->checksum))
 			return TIMEOUT;
 
-		nl->enet_stats.tx_bytes += snd->skb->len;
+		dev->stats.tx_bytes += snd->skb->len;
 		dev_kfree_skb(snd->skb);
-		nl->enet_stats.tx_packets++;
+		dev->stats.tx_packets++;
 		snd->state = PLIP_PK_DONE;
 
 	case PLIP_PK_DONE:
@@ -996,14 +988,14 @@
 }
 
 static void
-plip_rewrite_address(struct net_device *dev, struct ethhdr *eth)
+plip_rewrite_address(const struct net_device *dev, struct ethhdr *eth)
 {
-	struct in_device *in_dev;
+	const struct in_device *in_dev = dev->ip_ptr;
 
-	if ((in_dev=dev->ip_ptr) != NULL) {
+	if (in_dev) {
 		/* Any address will do - we take the first */
-		struct in_ifaddr *ifa=in_dev->ifa_list;
-		if (ifa != NULL) {
+		const struct in_ifaddr *ifa = in_dev->ifa_list;
+		if (ifa) {
 			memcpy(eth->h_source, dev->dev_addr, 6);
 			memset(eth->h_dest, 0xfc, 2);
 			memcpy(eth->h_dest+2, &ifa->ifa_address, 4);
@@ -1013,26 +1005,25 @@
 
 static int
 plip_hard_header(struct sk_buff *skb, struct net_device *dev,
-                 unsigned short type, void *daddr,
-	         void *saddr, unsigned len)
+		 unsigned short type, const void *daddr,
+		 const void *saddr, unsigned len)
 {
-	struct net_local *nl = netdev_priv(dev);
 	int ret;
 
-	if ((ret = nl->orig_hard_header(skb, dev, type, daddr, saddr, len)) >= 0)
+	ret = eth_header(skb, dev, type, daddr, saddr, len);
+	if (ret >= 0)
 		plip_rewrite_address (dev, (struct ethhdr *)skb->data);
 
 	return ret;
 }
 
-int plip_hard_header_cache(struct neighbour *neigh,
+int plip_hard_header_cache(const struct neighbour *neigh,
                            struct hh_cache *hh)
 {
-	struct net_local *nl = neigh->dev->priv;
 	int ret;
 
-	if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0)
-	{
+	ret = eth_header_cache(neigh, hh);
+	if (ret == 0) {
 		struct ethhdr *eth;
 
 		eth = (struct ethhdr*)(((u8*)hh->hh_data) +
@@ -1199,15 +1190,6 @@
 	return;
 }
 
-static struct net_device_stats *
-plip_get_stats(struct net_device *dev)
-{
-	struct net_local *nl = netdev_priv(dev);
-	struct net_device_stats *r = &nl->enet_stats;
-
-	return r;
-}
-
 static int
 plip_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
@@ -1278,7 +1260,6 @@
 
 		strcpy(dev->name, name);
 
-		SET_MODULE_OWNER(dev);
 		dev->irq = port->irq;
 		dev->base_addr = port->base;
 		if (port->irq == -1) {
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index caabbc4..27f5b90 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -159,12 +159,11 @@
 	int err;
 
 	err = -ENOMEM;
-	ap = kmalloc(sizeof(*ap), GFP_KERNEL);
+	ap = kzalloc(sizeof(*ap), GFP_KERNEL);
 	if (ap == 0)
 		goto out;
 
 	/* initialize the asyncppp structure */
-	memset(ap, 0, sizeof(*ap));
 	ap->tty = tty;
 	ap->mru = PPP_MRU;
 	spin_lock_init(&ap->xmit_lock);
diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c
index 72c8d66..eb98b66 100644
--- a/drivers/net/ppp_deflate.c
+++ b/drivers/net/ppp_deflate.c
@@ -121,12 +121,11 @@
 	if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
 		return NULL;
 
-	state = kmalloc(sizeof(*state),
+	state = kzalloc(sizeof(*state),
 						     GFP_KERNEL);
 	if (state == NULL)
 		return NULL;
 
-	memset (state, 0, sizeof (struct ppp_deflate_state));
 	state->strm.next_in   = NULL;
 	state->w_size         = w_size;
 	state->strm.workspace = vmalloc(zlib_deflate_workspacesize());
@@ -341,11 +340,10 @@
 	if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
 		return NULL;
 
-	state = kmalloc(sizeof(*state), GFP_KERNEL);
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
 	if (state == NULL)
 		return NULL;
 
-	memset (state, 0, sizeof (struct ppp_deflate_state));
 	state->w_size         = w_size;
 	state->strm.next_out  = NULL;
 	state->strm.workspace = kmalloc(zlib_inflate_workspacesize(),
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 3ef0092..4b49d0e 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -899,17 +899,9 @@
 
 	/* Put the 2-byte PPP protocol number on the front,
 	   making sure there is room for the address and control fields. */
-	if (skb_headroom(skb) < PPP_HDRLEN) {
-		struct sk_buff *ns;
+	if (skb_cow_head(skb, PPP_HDRLEN))
+		goto outf;
 
-		ns = alloc_skb(skb->len + dev->hard_header_len, GFP_ATOMIC);
-		if (ns == 0)
-			goto outf;
-		skb_reserve(ns, dev->hard_header_len);
-		skb_copy_bits(skb, 0, skb_put(ns, skb->len), skb->len);
-		kfree_skb(skb);
-		skb = ns;
-	}
 	pp = skb_push(skb, 2);
 	proto = npindex_to_proto[npi];
 	pp[0] = proto >> 8;
@@ -1533,7 +1525,7 @@
 static void
 ppp_receive_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
 {
-	if (skb->len >= 2) {
+	if (pskb_may_pull(skb, 2)) {
 #ifdef CONFIG_PPP_MULTILINK
 		/* XXX do channel-level decompression here */
 		if (PPP_PROTO(skb) == PPP_MP)
@@ -1585,7 +1577,7 @@
 		if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP))
 			goto err;
 
-		if (skb_tailroom(skb) < 124) {
+		if (skb_tailroom(skb) < 124 || skb_cloned(skb)) {
 			/* copy to a new sk_buff with more tailroom */
 			ns = dev_alloc_skb(skb->len + 128);
 			if (ns == 0) {
@@ -1656,23 +1648,29 @@
 		/* check if the packet passes the pass and active filters */
 		/* the filter instructions are constructed assuming
 		   a four-byte PPP header on each packet */
-		*skb_push(skb, 2) = 0;
-		if (ppp->pass_filter
-		    && sk_run_filter(skb, ppp->pass_filter,
-				     ppp->pass_len) == 0) {
-			if (ppp->debug & 1)
-				printk(KERN_DEBUG "PPP: inbound frame not passed\n");
-			kfree_skb(skb);
-			return;
-		}
-		if (!(ppp->active_filter
-		      && sk_run_filter(skb, ppp->active_filter,
-				       ppp->active_len) == 0))
-			ppp->last_recv = jiffies;
-		skb_pull(skb, 2);
-#else
-		ppp->last_recv = jiffies;
+		if (ppp->pass_filter || ppp->active_filter) {
+			if (skb_cloned(skb) &&
+			    pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+				goto err;
+
+			*skb_push(skb, 2) = 0;
+			if (ppp->pass_filter
+			    && sk_run_filter(skb, ppp->pass_filter,
+					     ppp->pass_len) == 0) {
+				if (ppp->debug & 1)
+					printk(KERN_DEBUG "PPP: inbound frame "
+					       "not passed\n");
+				kfree_skb(skb);
+				return;
+			}
+			if (!(ppp->active_filter
+			      && sk_run_filter(skb, ppp->active_filter,
+					       ppp->active_len) == 0))
+				ppp->last_recv = jiffies;
+			__skb_pull(skb, 2);
+		} else
 #endif /* CONFIG_PPP_FILTER */
+			ppp->last_recv = jiffies;
 
 		if ((ppp->dev->flags & IFF_UP) == 0
 		    || ppp->npmode[npi] != NPMODE_PASS) {
@@ -1726,7 +1724,7 @@
 		}
 		/* the decompressor still expects the A/C bytes in the hdr */
 		len = ppp->rcomp->decompress(ppp->rc_state, skb->data - 2,
-				skb->len + 2, ns->data, ppp->mru + PPP_HDRLEN);
+				skb->len + 2, ns->data, obuff_size);
 		if (len < 0) {
 			/* Pass the compressed frame to pppd as an
 			   error indication. */
@@ -1770,7 +1768,7 @@
 	struct channel *ch;
 	int mphdrlen = (ppp->flags & SC_MP_SHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
 
-	if (!pskb_may_pull(skb, mphdrlen) || ppp->mrru == 0)
+	if (!pskb_may_pull(skb, mphdrlen + 1) || ppp->mrru == 0)
 		goto err;		/* no good, throw it away */
 
 	/* Decode sequence number and begin/end bits */
@@ -2684,8 +2682,7 @@
 	if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count))
 		printk(KERN_ERR "PPP: removing module but units remain!\n");
 	cardmap_destroy(&all_ppp_units);
-	if (unregister_chrdev(PPP_MAJOR, "ppp") != 0)
-		printk(KERN_ERR "PPP: failed to unregister PPP device\n");
+	unregister_chrdev(PPP_MAJOR, "ppp");
 	device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
 	class_destroy(ppp_class);
 }
diff --git a/drivers/net/ppp_mppe.c b/drivers/net/ppp_mppe.c
index d5bdd25..c0b6d19 100644
--- a/drivers/net/ppp_mppe.c
+++ b/drivers/net/ppp_mppe.c
@@ -136,7 +136,7 @@
  * Key Derivation, from RFC 3078, RFC 3079.
  * Equivalent to Get_Key() for MS-CHAP as described in RFC 3079.
  */
-static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *InterimKey)
+static void get_new_key_from_sha(struct ppp_mppe_state * state)
 {
 	struct hash_desc desc;
 	struct scatterlist sg[4];
@@ -153,8 +153,6 @@
 	desc.flags = 0;
 
 	crypto_hash_digest(&desc, sg, nbytes, state->sha1_digest);
-
-	memcpy(InterimKey, state->sha1_digest, state->keylen);
 }
 
 /*
@@ -163,21 +161,21 @@
  */
 static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
 {
-	unsigned char InterimKey[MPPE_MAX_KEY_LEN];
 	struct scatterlist sg_in[1], sg_out[1];
 	struct blkcipher_desc desc = { .tfm = state->arc4 };
 
-	get_new_key_from_sha(state, InterimKey);
+	get_new_key_from_sha(state);
 	if (!initial_key) {
-		crypto_blkcipher_setkey(state->arc4, InterimKey, state->keylen);
-		setup_sg(sg_in, InterimKey, state->keylen);
+		crypto_blkcipher_setkey(state->arc4, state->sha1_digest,
+					state->keylen);
+		setup_sg(sg_in, state->sha1_digest, state->keylen);
 		setup_sg(sg_out, state->session_key, state->keylen);
 		if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
 					     state->keylen) != 0) {
     		    printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n");
 		}
 	} else {
-		memcpy(state->session_key, InterimKey, state->keylen);
+		memcpy(state->session_key, state->sha1_digest, state->keylen);
 	}
 	if (state->keylen == 8) {
 		/* See RFC 3078 */
@@ -200,11 +198,10 @@
 	    || options[0] != CI_MPPE || options[1] != CILEN_MPPE)
 		goto out;
 
-	state = kmalloc(sizeof(*state), GFP_KERNEL);
+	state = kzalloc(sizeof(*state), GFP_KERNEL);
 	if (state == NULL)
 		goto out;
 
-	memset(state, 0, sizeof(*state));
 
 	state->arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
 	if (IS_ERR(state->arc4)) {
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index 5918fab..ce64032 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -207,13 +207,12 @@
 	struct syncppp *ap;
 	int err;
 
-	ap = kmalloc(sizeof(*ap), GFP_KERNEL);
+	ap = kzalloc(sizeof(*ap), GFP_KERNEL);
 	err = -ENOMEM;
 	if (ap == 0)
 		goto out;
 
 	/* initialize the syncppp structure */
-	memset(ap, 0, sizeof(*ap));
 	ap->tty = tty;
 	ap->mru = PPP_MRU;
 	spin_lock_init(&ap->xmit_lock);
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 6f98834..8936ed3 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -78,6 +78,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 
+#include <net/net_namespace.h>
 #include <net/sock.h>
 
 #include <asm/uaccess.h>
@@ -102,25 +103,30 @@
 		(memcmp(a->remote, b->remote, ETH_ALEN) == 0));
 }
 
-static inline int cmp_addr(struct pppoe_addr *a, unsigned long sid, char *addr)
+static inline int cmp_addr(struct pppoe_addr *a, __be16 sid, char *addr)
 {
 	return (a->sid == sid &&
 		(memcmp(a->remote,addr,ETH_ALEN) == 0));
 }
 
-static int hash_item(unsigned long sid, unsigned char *addr)
+#if 8%PPPOE_HASH_BITS
+#error 8 must be a multiple of PPPOE_HASH_BITS
+#endif
+
+static int hash_item(__be16 sid, unsigned char *addr)
 {
-	char hash = 0;
-	int i, j;
+	unsigned char hash = 0;
+	unsigned int i;
 
-	for (i = 0; i < ETH_ALEN ; ++i) {
-		for (j = 0; j < 8/PPPOE_HASH_BITS ; ++j) {
-			hash ^= addr[i] >> ( j * PPPOE_HASH_BITS );
-		}
+	for (i = 0 ; i < ETH_ALEN ; i++) {
+		hash ^= addr[i];
 	}
-
-	for (i = 0; i < (sizeof(unsigned long)*8) / PPPOE_HASH_BITS ; ++i)
-		hash ^= sid >> (i*PPPOE_HASH_BITS);
+	for (i = 0 ; i < sizeof(sid_t)*8 ; i += 8 ){
+		hash ^= (__force __u32)sid>>i;
+	}
+	for (i = 8 ; (i>>=1) >= PPPOE_HASH_BITS ; ) {
+		hash ^= hash>>i;
+	}
 
 	return hash & ( PPPOE_HASH_SIZE - 1 );
 }
@@ -133,7 +139,7 @@
  *  Set/get/delete/rehash items  (internal versions)
  *
  **********************************************************************/
-static struct pppox_sock *__get_item(unsigned long sid, unsigned char *addr, int ifindex)
+static struct pppox_sock *__get_item(__be16 sid, unsigned char *addr, int ifindex)
 {
 	int hash = hash_item(sid, addr);
 	struct pppox_sock *ret;
@@ -165,7 +171,7 @@
 	return 0;
 }
 
-static struct pppox_sock *__delete_item(unsigned long sid, char *addr, int ifindex)
+static struct pppox_sock *__delete_item(__be16 sid, char *addr, int ifindex)
 {
 	int hash = hash_item(sid, addr);
 	struct pppox_sock *ret, **src;
@@ -191,7 +197,7 @@
  *  Set/get/delete/rehash items
  *
  **********************************************************************/
-static inline struct pppox_sock *get_item(unsigned long sid,
+static inline struct pppox_sock *get_item(__be16 sid,
 					 unsigned char *addr, int ifindex)
 {
 	struct pppox_sock *po;
@@ -210,7 +216,7 @@
 	struct net_device *dev;
 	int ifindex;
 
-	dev = dev_get_by_name(sp->sa_addr.pppoe.dev);
+	dev = dev_get_by_name(&init_net, sp->sa_addr.pppoe.dev);
 	if(!dev)
 		return NULL;
 	ifindex = dev->ifindex;
@@ -218,7 +224,7 @@
 	return get_item(sp->sa_addr.pppoe.sid, sp->sa_addr.pppoe.remote, ifindex);
 }
 
-static inline struct pppox_sock *delete_item(unsigned long sid, char *addr, int ifindex)
+static inline struct pppox_sock *delete_item(__be16 sid, char *addr, int ifindex)
 {
 	struct pppox_sock *ret;
 
@@ -295,6 +301,9 @@
 {
 	struct net_device *dev = (struct net_device *) ptr;
 
+	if (dev->nd_net != &init_net)
+		return NOTIFY_DONE;
+
 	/* Only look at sockets that are using this specific device. */
 	switch (event) {
 	case NETDEV_CHANGEMTU:
@@ -380,15 +389,18 @@
 	struct pppoe_hdr *ph;
 	struct pppox_sock *po;
 
-	if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
-		goto drop;
-
 	if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
 		goto out;
 
+	if (dev->nd_net != &init_net)
+		goto drop;
+
+	if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
+		goto drop;
+
 	ph = pppoe_hdr(skb);
 
-	po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
+	po = get_item(ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
 	if (po != NULL)
 		return sk_receive_skb(sk_pppox(po), skb, 0);
 drop:
@@ -412,6 +424,9 @@
 	struct pppoe_hdr *ph;
 	struct pppox_sock *po;
 
+	if (dev->nd_net != &init_net)
+		goto abort;
+
 	if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
 		goto abort;
 
@@ -422,7 +437,7 @@
 	if (ph->code != PADT_CODE)
 		goto abort;
 
-	po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
+	po = get_item(ph->sid, eth_hdr(skb)->h_source, dev->ifindex);
 	if (po) {
 		struct sock *sk = sk_pppox(po);
 
@@ -471,12 +486,12 @@
  * Initialize a new struct sock.
  *
  **********************************************************************/
-static int pppoe_create(struct socket *sock)
+static int pppoe_create(struct net *net, struct socket *sock)
 {
 	int error = -ENOMEM;
 	struct sock *sk;
 
-	sk = sk_alloc(PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto, 1);
+	sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppoe_sk_proto, 1);
 	if (!sk)
 		goto out;
 
@@ -588,7 +603,7 @@
 
 	/* Don't re-bind if sid==0 */
 	if (sp->sa_addr.pppoe.sid != 0) {
-		dev = dev_get_by_name(sp->sa_addr.pppoe.dev);
+		dev = dev_get_by_name(&init_net, sp->sa_addr.pppoe.dev);
 
 		error = -ENODEV;
 		if (!dev)
@@ -664,8 +679,8 @@
 {
 	struct sock *sk = sock->sk;
 	struct pppox_sock *po = pppox_sk(sk);
-	int val = 0;
-	int err = 0;
+	int val;
+	int err;
 
 	switch (cmd) {
 	case PPPIOCGMRU:
@@ -754,8 +769,9 @@
 		err = 0;
 		break;
 
-	default:;
-	};
+	default:
+		err = -ENOTTY;
+	}
 
 	return err;
 }
@@ -773,6 +789,7 @@
 	struct net_device *dev;
 	char *start;
 
+	lock_sock(sk);
 	if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) {
 		error = -ENOTCONN;
 		goto end;
@@ -783,8 +800,6 @@
 	hdr.code = 0;
 	hdr.sid = po->num;
 
-	lock_sock(sk);
-
 	dev = po->pppoe_dev;
 
 	error = -EMSGSIZE;
@@ -819,8 +834,8 @@
 	}
 
 	error = total_len;
-	dev->hard_header(skb, dev, ETH_P_PPP_SES,
-			 po->pppoe_pa.remote, NULL, total_len);
+	dev_hard_header(skb, dev, ETH_P_PPP_SES,
+			po->pppoe_pa.remote, NULL, total_len);
 
 	memcpy(ph, &hdr, sizeof(struct pppoe_hdr));
 
@@ -843,71 +858,44 @@
 {
 	struct pppox_sock *po = pppox_sk(sk);
 	struct net_device *dev = po->pppoe_dev;
-	struct pppoe_hdr hdr;
 	struct pppoe_hdr *ph;
-	int headroom = skb_headroom(skb);
 	int data_len = skb->len;
-	struct sk_buff *skb2;
 
 	if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
 		goto abort;
 
-	hdr.ver	= 1;
-	hdr.type = 1;
-	hdr.code = 0;
-	hdr.sid	= po->num;
-	hdr.length = htons(skb->len);
-
 	if (!dev)
 		goto abort;
 
-	/* Copy the skb if there is no space for the header. */
-	if (headroom < (sizeof(struct pppoe_hdr) + dev->hard_header_len)) {
-		skb2 = dev_alloc_skb(32+skb->len +
-				     sizeof(struct pppoe_hdr) +
-				     dev->hard_header_len);
-
-		if (skb2 == NULL)
-			goto abort;
-
-		skb_reserve(skb2, dev->hard_header_len + sizeof(struct pppoe_hdr));
-		skb_copy_from_linear_data(skb, skb_put(skb2, skb->len),
-					  skb->len);
-	} else {
-		/* Make a clone so as to not disturb the original skb,
-		 * give dev_queue_xmit something it can free.
-		 */
-		skb2 = skb_clone(skb, GFP_ATOMIC);
-
-		if (skb2 == NULL)
-			goto abort;
-	}
-
-	ph = (struct pppoe_hdr *) skb_push(skb2, sizeof(struct pppoe_hdr));
-	memcpy(ph, &hdr, sizeof(struct pppoe_hdr));
-	skb2->protocol = __constant_htons(ETH_P_PPP_SES);
-
-	skb_reset_network_header(skb2);
-
-	skb2->dev = dev;
-
-	dev->hard_header(skb2, dev, ETH_P_PPP_SES,
-			 po->pppoe_pa.remote, NULL, data_len);
-
-	/* We're transmitting skb2, and assuming that dev_queue_xmit
-	 * will free it.  The generic ppp layer however, is expecting
-	 * that we give back 'skb' (not 'skb2') in case of failure,
-	 * but free it in case of success.
+	/* Copy the data if there is no space for the header or if it's
+	 * read-only.
 	 */
-
-	if (dev_queue_xmit(skb2) < 0)
+	if (skb_cow_head(skb, sizeof(*ph) + dev->hard_header_len))
 		goto abort;
 
-	kfree_skb(skb);
+	__skb_push(skb, sizeof(*ph));
+	skb_reset_network_header(skb);
+
+	ph = pppoe_hdr(skb);
+	ph->ver	= 1;
+	ph->type = 1;
+	ph->code = 0;
+	ph->sid	= po->num;
+	ph->length = htons(data_len);
+
+	skb->protocol = __constant_htons(ETH_P_PPP_SES);
+	skb->dev = dev;
+
+	dev_hard_header(skb, dev, ETH_P_PPP_SES,
+			po->pppoe_pa.remote, NULL, data_len);
+
+	dev_queue_xmit(skb);
+
 	return 1;
 
 abort:
-	return 0;
+	kfree_skb(skb);
+	return 1;
 }
 
 
@@ -967,6 +955,7 @@
 {
 	struct pppox_sock *po;
 	char *dev_name;
+	DECLARE_MAC_BUF(mac);
 
 	if (v == SEQ_START_TOKEN) {
 		seq_puts(seq, "Id       Address              Device\n");
@@ -976,11 +965,8 @@
 	po = v;
 	dev_name = po->pppoe_pa.dev;
 
-	seq_printf(seq, "%08X %02X:%02X:%02X:%02X:%02X:%02X %8s\n",
-		   po->pppoe_pa.sid,
-		   po->pppoe_pa.remote[0], po->pppoe_pa.remote[1],
-		   po->pppoe_pa.remote[2], po->pppoe_pa.remote[3],
-		   po->pppoe_pa.remote[4], po->pppoe_pa.remote[5], dev_name);
+	seq_printf(seq, "%08X %s %8s\n",
+		   po->pppoe_pa.sid, print_mac(mac, po->pppoe_pa.remote), dev_name);
 out:
 	return 0;
 }
@@ -1064,7 +1050,7 @@
 {
 	struct proc_dir_entry *p;
 
-	p = create_proc_entry("net/pppoe", S_IRUGO, NULL);
+	p = create_proc_entry("pppoe", S_IRUGO, init_net.proc_net);
 	if (!p)
 		return -ENOMEM;
 
@@ -1135,7 +1121,7 @@
 	dev_remove_pack(&pppoes_ptype);
 	dev_remove_pack(&pppoed_ptype);
 	unregister_netdevice_notifier(&pppoe_notifier);
-	remove_proc_entry("net/pppoe", NULL);
+	remove_proc_entry("pppoe", init_net.proc_net);
 	proto_unregister(&pppoe_sk_proto);
 }
 
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index 5891a0f..921d4ef 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -91,6 +91,7 @@
 #include <linux/hash.h>
 #include <linux/sort.h>
 #include <linux/proc_fs.h>
+#include <net/net_namespace.h>
 #include <net/dst.h>
 #include <net/ip.h>
 #include <net/udp.h>
@@ -491,44 +492,46 @@
 	u16 hdrflags;
 	u16 tunnel_id, session_id;
 	int length;
-	struct udphdr *uh;
+	int offset;
 
 	tunnel = pppol2tp_sock_to_tunnel(sock);
 	if (tunnel == NULL)
 		goto error;
 
+	/* UDP always verifies the packet length. */
+	__skb_pull(skb, sizeof(struct udphdr));
+
 	/* Short packet? */
-	if (skb->len < sizeof(struct udphdr)) {
+	if (!pskb_may_pull(skb, 12)) {
 		PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
 		       "%s: recv short packet (len=%d)\n", tunnel->name, skb->len);
 		goto error;
 	}
 
 	/* Point to L2TP header */
-	ptr = skb->data + sizeof(struct udphdr);
+	ptr = skb->data;
 
 	/* Get L2TP header flags */
 	hdrflags = ntohs(*(__be16*)ptr);
 
 	/* Trace packet contents, if enabled */
 	if (tunnel->debug & PPPOL2TP_MSG_DATA) {
+		length = min(16u, skb->len);
+		if (!pskb_may_pull(skb, length))
+			goto error;
+
 		printk(KERN_DEBUG "%s: recv: ", tunnel->name);
 
-		for (length = 0; length < 16; length++)
-			printk(" %02X", ptr[length]);
+		offset = 0;
+		do {
+			printk(" %02X", ptr[offset]);
+		} while (++offset < length);
+
 		printk("\n");
 	}
 
 	/* Get length of L2TP packet */
-	uh = (struct udphdr *) skb_transport_header(skb);
-	length = ntohs(uh->len) - sizeof(struct udphdr);
-
-	/* Too short? */
-	if (length < 12) {
-		PRINTK(tunnel->debug, PPPOL2TP_MSG_DATA, KERN_INFO,
-		       "%s: recv short L2TP packet (len=%d)\n", tunnel->name, length);
-		goto error;
-	}
+	length = skb->len;
 
 	/* If type is control packet, it is handled by userspace. */
 	if (hdrflags & L2TP_HDRFLAG_T) {
@@ -606,7 +609,6 @@
 			       "%s: recv data has no seq numbers when required. "
 			       "Discarding\n", session->name);
 			session->stats.rx_seq_discards++;
-			session->stats.rx_errors++;
 			goto discard;
 		}
 
@@ -625,7 +627,6 @@
 			       "%s: recv data has no seq numbers when required. "
 			       "Discarding\n", session->name);
 			session->stats.rx_seq_discards++;
-			session->stats.rx_errors++;
 			goto discard;
 		}
 
@@ -634,10 +635,14 @@
 	}
 
 	/* If offset bit set, skip it. */
-	if (hdrflags & L2TP_HDRFLAG_O)
-		ptr += 2 + ntohs(*(__be16 *) ptr);
+	if (hdrflags & L2TP_HDRFLAG_O) {
+		offset = ntohs(*(__be16 *)ptr);
+		skb->transport_header += 2 + offset;
+		if (!pskb_may_pull(skb, skb_transport_offset(skb) + 2))
+			goto discard;
+	}
 
-	skb_pull(skb, ptr - skb->data);
+	__skb_pull(skb, skb_transport_offset(skb));
 
 	/* Skip PPP header, if present.	 In testing, Microsoft L2TP clients
 	 * don't send the PPP header (PPP header compression enabled), but
@@ -673,7 +678,6 @@
 			 */
 			if (PPPOL2TP_SKB_CB(skb)->ns != session->nr) {
 				session->stats.rx_seq_discards++;
-				session->stats.rx_errors++;
 				PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
 				       "%s: oos pkt %hu len %d discarded, "
 				       "waiting for %hu, reorder_q_len=%d\n",
@@ -698,6 +702,7 @@
 	return 0;
 
 discard:
+	session->stats.rx_errors++;
 	kfree_skb(skb);
 	sock_put(session->sock);
 
@@ -824,6 +829,7 @@
 	struct pppol2tp_session *session;
 	struct pppol2tp_tunnel *tunnel;
 	struct udphdr *uh;
+	unsigned int len;
 
 	error = -ENOTCONN;
 	if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
@@ -912,14 +918,15 @@
 	}
 
 	/* Queue the packet to IP for output */
+	len = skb->len;
 	error = ip_queue_xmit(skb, 1);
 
 	/* Update stats */
 	if (error >= 0) {
 		tunnel->stats.tx_packets++;
-		tunnel->stats.tx_bytes += skb->len;
+		tunnel->stats.tx_bytes += len;
 		session->stats.tx_packets++;
-		session->stats.tx_bytes += skb->len;
+		session->stats.tx_bytes += len;
 	} else {
 		tunnel->stats.tx_errors++;
 		session->stats.tx_errors++;
@@ -956,8 +963,8 @@
 	int data_len = skb->len;
 	struct inet_sock *inet;
 	__wsum csum = 0;
-	struct sk_buff *skb2 = NULL;
 	struct udphdr *uh;
+	unsigned int len;
 
 	if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED))
 		goto abort;
@@ -986,41 +993,30 @@
 	 */
 	headroom = NET_SKB_PAD + sizeof(struct iphdr) +
 		sizeof(struct udphdr) + hdr_len + sizeof(ppph);
-	if (skb_headroom(skb) < headroom) {
-		skb2 = skb_realloc_headroom(skb, headroom);
-		if (skb2 == NULL)
-			goto abort;
-	} else
-		skb2 = skb;
-
-	/* Check that the socket has room */
-	if (atomic_read(&sk_tun->sk_wmem_alloc) < sk_tun->sk_sndbuf)
-		skb_set_owner_w(skb2, sk_tun);
-	else
-		goto discard;
+	if (skb_cow_head(skb, headroom))
+		goto abort;
 
 	/* Setup PPP header */
-	skb_push(skb2, sizeof(ppph));
-	skb2->data[0] = ppph[0];
-	skb2->data[1] = ppph[1];
+	__skb_push(skb, sizeof(ppph));
+	skb->data[0] = ppph[0];
+	skb->data[1] = ppph[1];
 
 	/* Setup L2TP header */
-	skb_push(skb2, hdr_len);
-	pppol2tp_build_l2tp_header(session, skb2->data);
+	pppol2tp_build_l2tp_header(session, __skb_push(skb, hdr_len));
 
 	/* Setup UDP header */
 	inet = inet_sk(sk_tun);
-	skb_push(skb2, sizeof(struct udphdr));
-	skb_reset_transport_header(skb2);
-	uh = (struct udphdr *) skb2->data;
+	__skb_push(skb, sizeof(*uh));
+	skb_reset_transport_header(skb);
+	uh = udp_hdr(skb);
 	uh->source = inet->sport;
 	uh->dest = inet->dport;
 	uh->len = htons(sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len);
 	uh->check = 0;
 
-	/* Calculate UDP checksum if configured to do so */
+	/* *BROKEN* Calculate UDP checksum if configured to do so */
 	if (sk_tun->sk_no_check != UDP_CSUM_NOXMIT)
-		csum = udp_csum_outgoing(sk_tun, skb2);
+		csum = udp_csum_outgoing(sk_tun, skb);
 
 	/* Debug */
 	if (session->send_seq)
@@ -1033,7 +1029,7 @@
 
 	if (session->debug & PPPOL2TP_MSG_DATA) {
 		int i;
-		unsigned char *datap = skb2->data;
+		unsigned char *datap = skb->data;
 
 		printk(KERN_DEBUG "%s: xmit:", session->name);
 		for (i = 0; i < data_len; i++) {
@@ -1046,34 +1042,36 @@
 		printk("\n");
 	}
 
+	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+	IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
+			      IPSKB_REROUTED);
+	nf_reset(skb);
+
 	/* Get routing info from the tunnel socket */
-	skb2->dst = sk_dst_get(sk_tun);
+	dst_release(skb->dst);
+	skb->dst = sk_dst_get(sk_tun);
 
 	/* Queue the packet to IP for output */
-	rc = ip_queue_xmit(skb2, 1);
+	len = skb->len;
+	rc = ip_queue_xmit(skb, 1);
 
 	/* Update stats */
 	if (rc >= 0) {
 		tunnel->stats.tx_packets++;
-		tunnel->stats.tx_bytes += skb2->len;
+		tunnel->stats.tx_bytes += len;
 		session->stats.tx_packets++;
-		session->stats.tx_bytes += skb2->len;
+		session->stats.tx_bytes += len;
 	} else {
 		tunnel->stats.tx_errors++;
 		session->stats.tx_errors++;
 	}
 
-	/* Free the original skb */
-	kfree_skb(skb);
-
 	return 1;
 
-discard:
-	/* Free the new skb. Caller will free original skb. */
-	if (skb2 != skb)
-		kfree_skb(skb2);
 abort:
-	return 0;
+	/* Free the original skb */
+	kfree_skb(skb);
+	return 1;
 }
 
 /*****************************************************************************
@@ -1316,12 +1314,14 @@
 		goto err;
 	}
 
+	sk = sock->sk;
+
 	/* Quick sanity checks */
-	err = -ESOCKTNOSUPPORT;
-	if (sock->type != SOCK_DGRAM) {
+	err = -EPROTONOSUPPORT;
+	if (sk->sk_protocol != IPPROTO_UDP) {
 		PRINTK(-1, PPPOL2TP_MSG_CONTROL, KERN_ERR,
-		       "tunl %hu: fd %d wrong type, got %d, expected %d\n",
-		       tunnel_id, fd, sock->type, SOCK_DGRAM);
+		       "tunl %hu: fd %d wrong protocol, got %d, expected %d\n",
+		       tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP);
 		goto err;
 	}
 	err = -EAFNOSUPPORT;
@@ -1333,7 +1333,6 @@
 	}
 
 	err = -ENOTCONN;
-	sk = sock->sk;
 
 	/* Check if this socket has already been prepped */
 	tunnel = (struct pppol2tp_tunnel *)sk->sk_user_data;
@@ -1412,12 +1411,12 @@
 
 /* socket() handler. Initialize a new struct sock.
  */
-static int pppol2tp_create(struct socket *sock)
+static int pppol2tp_create(struct net *net, struct socket *sock)
 {
 	int error = -ENOMEM;
 	struct sock *sk;
 
-	sk = sk_alloc(PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto, 1);
+	sk = sk_alloc(net, PF_PPPOX, GFP_KERNEL, &pppol2tp_sk_proto, 1);
 	if (!sk)
 		goto out;
 
@@ -2044,7 +2043,7 @@
  */
 static int pppol2tp_tunnel_getsockopt(struct sock *sk,
 				      struct pppol2tp_tunnel *tunnel,
-				      int optname, int __user *val)
+				      int optname, int *val)
 {
 	int err = 0;
 
@@ -2067,7 +2066,7 @@
  */
 static int pppol2tp_session_getsockopt(struct sock *sk,
 				       struct pppol2tp_session *session,
-				       int optname, int __user *val)
+				       int optname, int *val)
 {
 	int err = 0;
 
@@ -2446,7 +2445,7 @@
 		goto out_unregister_pppol2tp_proto;
 
 #ifdef CONFIG_PROC_FS
-	pppol2tp_proc = create_proc_entry("pppol2tp", 0, proc_net);
+	pppol2tp_proc = create_proc_entry("pppol2tp", 0, init_net.proc_net);
 	if (!pppol2tp_proc) {
 		err = -ENOMEM;
 		goto out_unregister_pppox_proto;
@@ -2471,7 +2470,7 @@
 	unregister_pppox_proto(PX_PROTO_OL2TP);
 
 #ifdef CONFIG_PROC_FS
-	remove_proc_entry("pppol2tp", proc_net);
+	remove_proc_entry("pppol2tp", init_net.proc_net);
 #endif
 	proto_unregister(&pppol2tp_sk_proto);
 }
diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c
index f3e47d0..c6898c1 100644
--- a/drivers/net/pppox.c
+++ b/drivers/net/pppox.c
@@ -73,7 +73,7 @@
 {
 	struct sock *sk = sock->sk;
 	struct pppox_sock *po = pppox_sk(sk);
-	int rc = 0;
+	int rc;
 
 	lock_sock(sk);
 
@@ -94,12 +94,9 @@
 		break;
 	}
 	default:
-		if (pppox_protos[sk->sk_protocol]->ioctl)
-			rc = pppox_protos[sk->sk_protocol]->ioctl(sock, cmd,
-								  arg);
-
-		break;
-	};
+		rc = pppox_protos[sk->sk_protocol]->ioctl ?
+			pppox_protos[sk->sk_protocol]->ioctl(sock, cmd, arg) : -ENOTTY;
+	}
 
 	release_sock(sk);
 	return rc;
@@ -107,10 +104,13 @@
 
 EXPORT_SYMBOL(pppox_ioctl);
 
-static int pppox_create(struct socket *sock, int protocol)
+static int pppox_create(struct net *net, struct socket *sock, int protocol)
 {
 	int rc = -EPROTOTYPE;
 
+	if (net != &init_net)
+		return -EAFNOSUPPORT;
+
 	if (protocol < 0 || protocol > PX_MAX_PROTO)
 		goto out;
 
@@ -126,7 +126,7 @@
 	    !try_module_get(pppox_protos[protocol]->owner))
 		goto out;
 
-	rc = pppox_protos[protocol]->create(sock);
+	rc = pppox_protos[protocol]->create(net, sock);
 
 	module_put(pppox_protos[protocol]->owner);
 out:
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c
index 08d2506..0a42bf5 100644
--- a/drivers/net/ps3_gelic_net.c
+++ b/drivers/net/ps3_gelic_net.c
@@ -290,7 +290,8 @@
 			descr->buf_addr = 0;
 			dev_kfree_skb_any(descr->skb);
 			descr->skb = NULL;
-			descr->dmac_cmd_status = GELIC_NET_DESCR_NOT_IN_USE;
+			gelic_net_set_descr_status(descr,
+						   GELIC_NET_DESCR_NOT_IN_USE);
 		}
 		descr = descr->next;
 	} while (descr != card->rx_chain.head);
@@ -350,19 +351,13 @@
 static void gelic_net_release_tx_descr(struct gelic_net_card *card,
 			    struct gelic_net_descr *descr)
 {
-	struct sk_buff *skb;
+	struct sk_buff *skb = descr->skb;
 
+	BUG_ON(!(descr->data_status & (1 << GELIC_NET_TXDESC_TAIL)));
 
-	if (descr->data_status & (1 << GELIC_NET_TXDESC_TAIL)) {
-		/* 2nd descriptor */
-		skb = descr->skb;
-		dma_unmap_single(ctodev(card), descr->buf_addr, skb->len,
-				 DMA_TO_DEVICE);
-		dev_kfree_skb_any(skb);
-	} else {
-		dma_unmap_single(ctodev(card), descr->buf_addr,
-				 descr->buf_size, DMA_TO_DEVICE);
-	}
+	dma_unmap_single(ctodev(card), descr->buf_addr, skb->len,
+			 DMA_TO_DEVICE);
+	dev_kfree_skb_any(skb);
 
 	descr->buf_addr = 0;
 	descr->buf_size = 0;
@@ -374,7 +369,7 @@
 	descr->skb = NULL;
 
 	/* set descr status */
-	descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOT_IN_USE;
+	gelic_net_set_descr_status(descr, GELIC_NET_DESCR_NOT_IN_USE);
 }
 
 /**
@@ -403,23 +398,26 @@
 					 "%s: forcing end of tx descriptor " \
 					 "with status %x\n",
 					 __func__, status);
-			card->netdev_stats.tx_dropped++;
+			card->netdev->stats.tx_dropped++;
 			break;
 
 		case GELIC_NET_DESCR_COMPLETE:
-			card->netdev_stats.tx_packets++;
-			card->netdev_stats.tx_bytes +=
-				tx_chain->tail->skb->len;
+			if (tx_chain->tail->skb) {
+				card->netdev->stats.tx_packets++;
+				card->netdev->stats.tx_bytes +=
+					tx_chain->tail->skb->len;
+			}
 			break;
 
 		case GELIC_NET_DESCR_CARDOWNED:
 			/* pending tx request */
 		default:
 			/* any other value (== GELIC_NET_DESCR_NOT_IN_USE) */
-			goto out;
+			if (!stop)
+				goto out;
 		}
 		gelic_net_release_tx_descr(card, tx_chain->tail);
-		release = 1;
+		release ++;
 	}
 out:
 	if (!stop && release)
@@ -552,7 +550,7 @@
 {
 	struct gelic_net_card *card = netdev_priv(netdev);
 
-	netif_poll_disable(netdev);
+	napi_disable(&card->napi);
 	netif_stop_queue(netdev);
 
 	/* turn off DMA, force end */
@@ -589,13 +587,10 @@
 {
 	if (!card->tx_chain.head)
 		return NULL;
-	/*  see if we can two consecutive free descrs */
+	/*  see if the next descriptor is free */
 	if (card->tx_chain.tail != card->tx_chain.head->next &&
 	    gelic_net_get_descr_status(card->tx_chain.head) ==
-	    GELIC_NET_DESCR_NOT_IN_USE &&
-	    card->tx_chain.tail != card->tx_chain.head->next->next &&
-	    gelic_net_get_descr_status(card->tx_chain.head->next) ==
-	     GELIC_NET_DESCR_NOT_IN_USE )
+	    GELIC_NET_DESCR_NOT_IN_USE)
 		return card->tx_chain.head;
 	else
 		return NULL;
@@ -606,44 +601,66 @@
  * gelic_net_set_txdescr_cmdstat - sets the tx descriptor command field
  * @descr: descriptor structure to fill out
  * @skb: packet to consider
- * @middle: middle of frame
  *
  * fills out the command and status field of the descriptor structure,
  * depending on hardware checksum settings. This function assumes a wmb()
  * has executed before.
  */
 static void gelic_net_set_txdescr_cmdstat(struct gelic_net_descr *descr,
-					  struct sk_buff *skb, int middle)
+					  struct sk_buff *skb)
 {
-	u32 eofr;
-
-	if (middle)
-		eofr = 0;
-	else
-		eofr = GELIC_NET_DMAC_CMDSTAT_END_FRAME;
-
 	if (skb->ip_summed != CHECKSUM_PARTIAL)
-		descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOCS | eofr;
+		descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOCS |
+			GELIC_NET_DMAC_CMDSTAT_END_FRAME;
 	else {
 		/* is packet ip?
 		 * if yes: tcp? udp? */
 		if (skb->protocol == htons(ETH_P_IP)) {
 			if (ip_hdr(skb)->protocol == IPPROTO_TCP)
 				descr->dmac_cmd_status =
-					GELIC_NET_DMAC_CMDSTAT_TCPCS | eofr;
+					GELIC_NET_DMAC_CMDSTAT_TCPCS |
+					GELIC_NET_DMAC_CMDSTAT_END_FRAME;
+
 			else if (ip_hdr(skb)->protocol == IPPROTO_UDP)
 				descr->dmac_cmd_status =
-					GELIC_NET_DMAC_CMDSTAT_UDPCS | eofr;
+					GELIC_NET_DMAC_CMDSTAT_UDPCS |
+					GELIC_NET_DMAC_CMDSTAT_END_FRAME;
 			else	/*
 				 * the stack should checksum non-tcp and non-udp
 				 * packets on his own: NETIF_F_IP_CSUM
 				 */
 				descr->dmac_cmd_status =
-					GELIC_NET_DMAC_CMDSTAT_NOCS | eofr;
+					GELIC_NET_DMAC_CMDSTAT_NOCS |
+					GELIC_NET_DMAC_CMDSTAT_END_FRAME;
 		}
 	}
 }
 
+static inline struct sk_buff *gelic_put_vlan_tag(struct sk_buff *skb,
+						 unsigned short tag)
+{
+	struct vlan_ethhdr *veth;
+	static unsigned int c;
+
+	if (skb_headroom(skb) < VLAN_HLEN) {
+		struct sk_buff *sk_tmp = skb;
+		pr_debug("%s: hd=%d c=%ud\n", __func__, skb_headroom(skb), c);
+		skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN);
+		if (!skb)
+			return NULL;
+		dev_kfree_skb_any(sk_tmp);
+	}
+	veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
+
+	/* Move the mac addresses to the top of buffer */
+	memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN);
+
+	veth->h_vlan_proto = __constant_htons(ETH_P_8021Q);
+	veth->h_vlan_TCI = htons(tag);
+
+	return skb;
+}
+
 /**
  * gelic_net_prepare_tx_descr_v - get dma address of skb_data
  * @card: card structure
@@ -657,66 +674,35 @@
 					struct gelic_net_descr *descr,
 					struct sk_buff *skb)
 {
-	dma_addr_t buf[2];
-	unsigned int vlan_len;
+	dma_addr_t buf;
 
-	if (skb->len < GELIC_NET_VLAN_POS)
-		return -EINVAL;
-
-	memcpy(&descr->vlan, skb->data, GELIC_NET_VLAN_POS);
 	if (card->vlan_index != -1) {
-		descr->vlan.h_vlan_proto = htons(ETH_P_8021Q); /* vlan 0x8100*/
-		descr->vlan.h_vlan_TCI = htons(card->vlan_id[card->vlan_index]);
-		vlan_len = GELIC_NET_VLAN_POS + VLAN_HLEN; /* VLAN_HLEN=4 */
-	} else
-		vlan_len = GELIC_NET_VLAN_POS; /* no vlan tag */
-
-	/* first descr */
-	buf[0] = dma_map_single(ctodev(card), &descr->vlan,
-			     vlan_len, DMA_TO_DEVICE);
-
-	if (!buf[0]) {
-		dev_err(ctodev(card),
-			"dma map 1 failed (%p, %i). Dropping packet\n",
-			skb->data, vlan_len);
-		return -ENOMEM;
+		struct sk_buff *skb_tmp;
+		skb_tmp = gelic_put_vlan_tag(skb,
+					     card->vlan_id[card->vlan_index]);
+		if (!skb_tmp)
+			return -ENOMEM;
+		skb = skb_tmp;
 	}
 
-	descr->buf_addr = buf[0];
-	descr->buf_size = vlan_len;
-	descr->skb = skb; /* not used */
-	descr->data_status = 0;
-	gelic_net_set_txdescr_cmdstat(descr, skb, 1); /* not the frame end */
+	buf = dma_map_single(ctodev(card), skb->data, skb->len, DMA_TO_DEVICE);
 
-	/* second descr */
-	card->tx_chain.head = card->tx_chain.head->next;
-	descr->next_descr_addr = descr->next->bus_addr;
-	descr = descr->next;
-	if (gelic_net_get_descr_status(descr) != GELIC_NET_DESCR_NOT_IN_USE)
-		/* XXX will be removed */
-		dev_err(ctodev(card), "descr is not free!\n");
-
-	buf[1] = dma_map_single(ctodev(card), skb->data + GELIC_NET_VLAN_POS,
-			     skb->len - GELIC_NET_VLAN_POS,
-			     DMA_TO_DEVICE);
-
-	if (!buf[1]) {
+	if (!buf) {
 		dev_err(ctodev(card),
 			"dma map 2 failed (%p, %i). Dropping packet\n",
-			skb->data + GELIC_NET_VLAN_POS,
-			skb->len - GELIC_NET_VLAN_POS);
-		dma_unmap_single(ctodev(card), buf[0], vlan_len,
-				 DMA_TO_DEVICE);
+			skb->data, skb->len);
 		return -ENOMEM;
 	}
 
-	descr->buf_addr = buf[1];
-	descr->buf_size = skb->len - GELIC_NET_VLAN_POS;
+	descr->buf_addr = buf;
+	descr->buf_size = skb->len;
 	descr->skb = skb;
 	descr->data_status = 0;
 	descr->next_descr_addr = 0; /* terminate hw descr */
-	gelic_net_set_txdescr_cmdstat(descr, skb, 0);
+	gelic_net_set_txdescr_cmdstat(descr, skb);
 
+	/* bump free descriptor pointer */
+	card->tx_chain.head = descr->next;
 	return 0;
 }
 
@@ -729,26 +715,18 @@
 static int gelic_net_kick_txdma(struct gelic_net_card *card,
 				struct gelic_net_descr *descr)
 {
-	int status = -ENXIO;
-	int count = 10;
+	int status = 0;
 
 	if (card->tx_dma_progress)
 		return 0;
 
 	if (gelic_net_get_descr_status(descr) == GELIC_NET_DESCR_CARDOWNED) {
 		card->tx_dma_progress = 1;
-		/* sometimes we need retry here */
-		while (count--) {
-			status = lv1_net_start_tx_dma(bus_id(card),
-						      dev_id(card),
-						      descr->bus_addr, 0);
-			if (!status)
-				break;
-		}
-		if (!count)
+		status = lv1_net_start_tx_dma(bus_id(card), dev_id(card),
+					      descr->bus_addr, 0);
+		if (status)
 			dev_info(ctodev(card), "lv1_net_start_txdma failed," \
-				"status=%d %#lx\n",
-				 status, card->irq_status);
+				 "status=%d\n", status);
 	}
 	return status;
 }
@@ -763,47 +741,62 @@
 static int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
 	struct gelic_net_card *card = netdev_priv(netdev);
-	struct gelic_net_descr *descr = NULL;
+	struct gelic_net_descr *descr;
 	int result;
 	unsigned long flags;
 
 	spin_lock_irqsave(&card->tx_dma_lock, flags);
 
 	gelic_net_release_tx_chain(card, 0);
-	if (!skb)
-		goto kick;
+
 	descr = gelic_net_get_next_tx_descr(card);
 	if (!descr) {
+		/*
+		 * no more descriptors free
+		 */
 		netif_stop_queue(netdev);
 		spin_unlock_irqrestore(&card->tx_dma_lock, flags);
 		return NETDEV_TX_BUSY;
 	}
+
 	result = gelic_net_prepare_tx_descr_v(card, descr, skb);
-
-	if (result)
-		goto error;
-
-	card->tx_chain.head = card->tx_chain.head->next;
-
-	if (descr->prev)
-		descr->prev->next_descr_addr = descr->bus_addr;
-kick:
+	if (result) {
+		/*
+		 * DMA map failed.  As chanses are that failure
+		 * would continue, just release skb and return
+		 */
+		card->netdev->stats.tx_dropped++;
+		dev_kfree_skb_any(skb);
+		spin_unlock_irqrestore(&card->tx_dma_lock, flags);
+		return NETDEV_TX_OK;
+	}
+	/*
+	 * link this prepared descriptor to previous one
+	 * to achieve high performance
+	 */
+	descr->prev->next_descr_addr = descr->bus_addr;
 	/*
 	 * as hardware descriptor is modified in the above lines,
 	 * ensure that the hardware sees it
 	 */
 	wmb();
-	if (gelic_net_kick_txdma(card, card->tx_chain.tail))
-		goto error;
+	if (gelic_net_kick_txdma(card, descr)) {
+		/*
+		 * kick failed.
+		 * release descriptors which were just prepared
+		 */
+		card->netdev->stats.tx_dropped++;
+		gelic_net_release_tx_descr(card, descr);
+		gelic_net_release_tx_descr(card, descr->next);
+		card->tx_chain.tail = descr->next->next;
+		dev_info(ctodev(card), "%s: kick failure\n", __func__);
+	} else {
+		/* OK, DMA started/reserved */
+		netdev->trans_start = jiffies;
+	}
 
-	netdev->trans_start = jiffies;
 	spin_unlock_irqrestore(&card->tx_dma_lock, flags);
 	return NETDEV_TX_OK;
-
-error:
-	card->netdev_stats.tx_dropped++;
-	spin_unlock_irqrestore(&card->tx_dma_lock, flags);
-	return NETDEV_TX_LOCKED;
 }
 
 /**
@@ -854,8 +847,8 @@
 		skb->ip_summed = CHECKSUM_NONE;
 
 	/* update netdevice statistics */
-	card->netdev_stats.rx_packets++;
-	card->netdev_stats.rx_bytes += skb->len;
+	card->netdev->stats.rx_packets++;
+	card->netdev->stats.rx_bytes += skb->len;
 
 	/* pass skb up to stack */
 	netif_receive_skb(skb);
@@ -895,38 +888,67 @@
 	    (status == GELIC_NET_DESCR_FORCE_END)) {
 		dev_info(ctodev(card), "dropping RX descriptor with state %x\n",
 			 status);
-		card->netdev_stats.rx_dropped++;
+		card->netdev->stats.rx_dropped++;
 		goto refill;
 	}
 
-	if ((status != GELIC_NET_DESCR_COMPLETE) &&
-	    (status != GELIC_NET_DESCR_FRAME_END)) {
+	if (status == GELIC_NET_DESCR_BUFFER_FULL) {
+		/*
+		 * Buffer full would occur if and only if
+		 * the frame length was longer than the size of this
+		 * descriptor's buffer.  If the frame length was equal
+		 * to or shorter than buffer'size, FRAME_END condition
+		 * would occur.
+		 * Anyway this frame was longer than the MTU,
+		 * just drop it.
+		 */
+		dev_info(ctodev(card), "overlength frame\n");
+		goto refill;
+	}
+	/*
+	 * descriptoers any other than FRAME_END here should
+	 * be treated as error.
+	 */
+	if (status != GELIC_NET_DESCR_FRAME_END) {
 		dev_dbg(ctodev(card), "RX descriptor with state %x\n",
 			status);
 		goto refill;
 	}
 
 	/* ok, we've got a packet in descr */
-	gelic_net_pass_skb_up(descr, card); /* 1: skb_up sccess */
-
+	gelic_net_pass_skb_up(descr, card);
 refill:
-	descr->next_descr_addr = 0; /* unlink the descr */
+	/*
+	 * So that always DMAC can see the end
+	 * of the descriptor chain to avoid
+	 * from unwanted DMAC overrun.
+	 */
+	descr->next_descr_addr = 0;
 
 	/* change the descriptor state: */
 	gelic_net_set_descr_status(descr, GELIC_NET_DESCR_NOT_IN_USE);
 
-	/* refill one desc
-	 * FIXME: this can fail, but for now, just leave this
-	 * descriptor without skb
+	/*
+	 * this call can fail, but for now, just leave this
+	 * decriptor without skb
 	 */
 	gelic_net_prepare_rx_descr(card, descr);
+
 	chain->head = descr;
 	chain->tail = descr->next;
+
+	/*
+	 * Set this descriptor the end of the chain.
+	 */
 	descr->prev->next_descr_addr = descr->bus_addr;
 
+	/*
+	 * If dmac chain was met, DMAC stopped.
+	 * thus re-enable it
+	 */
 	if (dmac_chain_ended) {
-		gelic_net_enable_rxdmac(card);
-		dev_dbg(ctodev(card), "reenable rx dma\n");
+		card->rx_dma_restart_required = 1;
+		dev_dbg(ctodev(card), "reenable rx dma scheduled\n");
 	}
 
 	return 1;
@@ -941,47 +963,25 @@
  * if the quota is exceeded, but the driver has still packets.
  *
  */
-static int gelic_net_poll(struct net_device *netdev, int *budget)
+static int gelic_net_poll(struct napi_struct *napi, int budget)
 {
-	struct gelic_net_card *card = netdev_priv(netdev);
-	int packets_to_do, packets_done = 0;
-	int no_more_packets = 0;
+	struct gelic_net_card *card = container_of(napi, struct gelic_net_card, napi);
+	struct net_device *netdev = card->netdev;
+	int packets_done = 0;
 
-	packets_to_do = min(*budget, netdev->quota);
-
-	while (packets_to_do) {
-		if (gelic_net_decode_one_descr(card)) {
-			packets_done++;
-			packets_to_do--;
-		} else {
-			/* no more packets for the stack */
-			no_more_packets = 1;
+	while (packets_done < budget) {
+		if (!gelic_net_decode_one_descr(card))
 			break;
-		}
+
+		packets_done++;
 	}
-	netdev->quota -= packets_done;
-	*budget -= packets_done;
-	if (no_more_packets) {
-		netif_rx_complete(netdev);
+
+	if (packets_done < budget) {
+		netif_rx_complete(netdev, napi);
 		gelic_net_rx_irq_on(card);
-		return 0;
-	} else
-		return 1;
+	}
+	return packets_done;
 }
-
-/**
- * gelic_net_get_stats - get interface statistics
- * @netdev: interface device structure
- *
- * returns the interface statistics residing in the gelic_net_card struct
- */
-static struct net_device_stats *gelic_net_get_stats(struct net_device *netdev)
-{
-	struct gelic_net_card *card = netdev_priv(netdev);
-
-	return &card->netdev_stats;
-}
-
 /**
  * gelic_net_change_mtu - changes the MTU of an interface
  * @netdev: interface device structure
@@ -1016,17 +1016,23 @@
 	if (!status)
 		return IRQ_NONE;
 
+	if (card->rx_dma_restart_required) {
+		card->rx_dma_restart_required = 0;
+		gelic_net_enable_rxdmac(card);
+	}
+
 	if (status & GELIC_NET_RXINT) {
 		gelic_net_rx_irq_off(card);
-		netif_rx_schedule(netdev);
+		netif_rx_schedule(netdev, &card->napi);
 	}
 
 	if (status & GELIC_NET_TXINT) {
 		spin_lock_irqsave(&card->tx_dma_lock, flags);
 		card->tx_dma_progress = 0;
+		gelic_net_release_tx_chain(card, 0);
+		/* kick outstanding tx descriptor if any */
+		gelic_net_kick_txdma(card, card->tx_chain.tail);
 		spin_unlock_irqrestore(&card->tx_dma_lock, flags);
-		/* start pending DMA */
-		gelic_net_xmit(NULL, netdev);
 	}
 	return IRQ_HANDLED;
 }
@@ -1068,7 +1074,7 @@
 	}
 
 	result = request_irq(card->netdev->irq, gelic_net_interrupt,
-			     IRQF_DISABLED, "gelic network", card->netdev);
+			     IRQF_DISABLED, card->netdev->name, card->netdev);
 
 	if (result) {
 		dev_info(ctodev(card), "%s:%d: request_irq failed (%d)\n",
@@ -1107,7 +1113,7 @@
 			card->descr, GELIC_NET_TX_DESCRIPTORS))
 		goto alloc_tx_failed;
 	if (gelic_net_init_chain(card, &card->rx_chain,
-				 card->descr + GELIC_NET_RX_DESCRIPTORS,
+				 card->descr + GELIC_NET_TX_DESCRIPTORS,
 				 GELIC_NET_RX_DESCRIPTORS))
 		goto alloc_rx_failed;
 
@@ -1121,6 +1127,8 @@
 	if (gelic_net_alloc_rx_skbs(card))
 		goto alloc_skbs_failed;
 
+	napi_enable(&card->napi);
+
 	card->tx_dma_progress = 0;
 	card->ghiintmask = GELIC_NET_RXINT | GELIC_NET_TXINT;
 
@@ -1129,7 +1137,6 @@
 
 	netif_start_queue(netdev);
 	netif_carrier_on(netdev);
-	netif_poll_enable(netdev);
 
 	return 0;
 
@@ -1141,7 +1148,6 @@
 	return -ENOMEM;
 }
 
-#ifdef GELIC_NET_ETHTOOL
 static void gelic_net_get_drvinfo (struct net_device *netdev,
 				   struct ethtool_drvinfo *info)
 {
@@ -1261,7 +1267,6 @@
 	.get_rx_csum	= gelic_net_get_rx_csum,
 	.set_rx_csum	= gelic_net_set_rx_csum,
 };
-#endif
 
 /**
  * gelic_net_tx_timeout_task - task scheduled by the watchdog timeout
@@ -1320,18 +1325,12 @@
 	netdev->open = &gelic_net_open;
 	netdev->stop = &gelic_net_stop;
 	netdev->hard_start_xmit = &gelic_net_xmit;
-	netdev->get_stats = &gelic_net_get_stats;
 	netdev->set_multicast_list = &gelic_net_set_multi;
 	netdev->change_mtu = &gelic_net_change_mtu;
 	/* tx watchdog */
 	netdev->tx_timeout = &gelic_net_tx_timeout;
 	netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT;
-	/* NAPI */
-	netdev->poll = &gelic_net_poll;
-	netdev->weight = GELIC_NET_NAPI_WEIGHT;
-#ifdef GELIC_NET_ETHTOOL
 	netdev->ethtool_ops = &gelic_net_ethtool_ops;
-#endif
 }
 
 /**
@@ -1349,8 +1348,8 @@
 	unsigned int i;
 	int status;
 	u64 v1, v2;
+	DECLARE_MAC_BUF(mac);
 
-	SET_MODULE_OWNER(netdev);
 	SET_NETDEV_DEV(netdev, &card->dev->core);
 	spin_lock_init(&card->tx_dma_lock);
 
@@ -1358,6 +1357,9 @@
 
 	gelic_net_setup_netdev_ops(netdev);
 
+	netif_napi_add(netdev, &card->napi,
+		       gelic_net_poll, GELIC_NET_NAPI_WEIGHT);
+
 	netdev->features = NETIF_F_IP_CSUM;
 
 	status = lv1_net_control(bus_id(card), dev_id(card),
@@ -1372,10 +1374,8 @@
 	v1 <<= 16;
 	memcpy(addr.sa_data, &v1, ETH_ALEN);
 	memcpy(netdev->dev_addr, addr.sa_data, ETH_ALEN);
-	dev_info(ctodev(card), "MAC addr %02x:%02x:%02x:%02x:%02x:%02x\n",
-		 netdev->dev_addr[0], netdev->dev_addr[1],
-		 netdev->dev_addr[2], netdev->dev_addr[3],
-		 netdev->dev_addr[4], netdev->dev_addr[5]);
+	dev_info(ctodev(card), "MAC addr %s\n",
+		 print_mac(mac, netdev->dev_addr));
 
 	card->vlan_index = -1;	/* no vlan */
 	for (i = 0; i < GELIC_NET_VLAN_MAX; i++) {
@@ -1398,8 +1398,11 @@
 			dev_dbg(ctodev(card), "vlan_id:%d, %lx\n", i, v1);
 		}
 	}
-	if (card->vlan_id[GELIC_NET_VLAN_WIRED - 1])
+
+	if (card->vlan_id[GELIC_NET_VLAN_WIRED - 1]) {
 		card->vlan_index = GELIC_NET_VLAN_WIRED - 1;
+		netdev->hard_header_len += VLAN_HLEN;
+	}
 
 	status = register_netdev(netdev);
 	if (status) {
diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h
index 5e1c286..9685602 100644
--- a/drivers/net/ps3_gelic_net.h
+++ b/drivers/net/ps3_gelic_net.h
@@ -28,21 +28,12 @@
 #ifndef _GELIC_NET_H
 #define _GELIC_NET_H
 
-#define GELIC_NET_DRV_NAME "Gelic Network Driver"
-#define GELIC_NET_DRV_VERSION "1.0"
-
-#define GELIC_NET_ETHTOOL               /* use ethtool */
-
-/* ioctl */
-#define GELIC_NET_GET_MODE              (SIOCDEVPRIVATE + 0)
-#define GELIC_NET_SET_MODE              (SIOCDEVPRIVATE + 1)
-
 /* descriptors */
 #define GELIC_NET_RX_DESCRIPTORS        128 /* num of descriptors */
 #define GELIC_NET_TX_DESCRIPTORS        128 /* num of descriptors */
 
-#define GELIC_NET_MAX_MTU               2308
-#define GELIC_NET_MIN_MTU               64
+#define GELIC_NET_MAX_MTU               VLAN_ETH_FRAME_LEN
+#define GELIC_NET_MIN_MTU               VLAN_ETH_ZLEN
 #define GELIC_NET_RXBUF_ALIGN           128
 #define GELIC_NET_RX_CSUM_DEFAULT       1 /* hw chksum */
 #define GELIC_NET_WATCHDOG_TIMEOUT      5*HZ
@@ -90,7 +81,8 @@
 					    */
 #define GELIC_NET_RXVLNPKT	0x00200000 /* VLAN packet */
 /* bit 20..16 reserved */
-#define GELIC_NET_RXRECNUM	0x0000ff00 /* reception receipt number */
+#define GELIC_NET_RXRRECNUM	0x0000ff00 /* reception receipt number */
+#define GELIC_NET_RXRRECNUM_SHIFT	8
 /* bit 7..0 reserved */
 
 #define GELIC_NET_TXDESC_TAIL		0
@@ -133,19 +125,19 @@
 						      * interrupt status */
 
 #define GELIC_NET_DMAC_CMDSTAT_CHAIN_END  0x00000002 /* RXDCEIS:DMA stopped */
-#define GELIC_NET_DMAC_CMDSTAT_NOT_IN_USE 0xb0000000
 #define GELIC_NET_DESCR_IND_PROC_SHIFT    28
 #define GELIC_NET_DESCR_IND_PROC_MASKO    0x0fffffff
 
 
 enum gelic_net_descr_status {
-	GELIC_NET_DESCR_COMPLETE            = 0x00, /* used in rx and tx */
+	GELIC_NET_DESCR_COMPLETE            = 0x00, /* used in tx */
+	GELIC_NET_DESCR_BUFFER_FULL         = 0x00, /* used in rx */
 	GELIC_NET_DESCR_RESPONSE_ERROR      = 0x01, /* used in rx and tx */
 	GELIC_NET_DESCR_PROTECTION_ERROR    = 0x02, /* used in rx and tx */
 	GELIC_NET_DESCR_FRAME_END           = 0x04, /* used in rx */
 	GELIC_NET_DESCR_FORCE_END           = 0x05, /* used in rx and tx */
 	GELIC_NET_DESCR_CARDOWNED           = 0x0a, /* used in rx and tx */
-	GELIC_NET_DESCR_NOT_IN_USE                  /* any other value */
+	GELIC_NET_DESCR_NOT_IN_USE          = 0x0b  /* any other value */
 };
 /* for lv1_net_control */
 #define GELIC_NET_GET_MAC_ADDRESS               0x0000000000000001
@@ -202,6 +194,7 @@
 
 struct gelic_net_card {
 	struct net_device *netdev;
+	struct napi_struct napi;
 	/*
 	 * hypervisor requires irq_status should be
 	 * 8 bytes aligned, but u64 member is
@@ -216,10 +209,10 @@
 
 	struct gelic_net_descr_chain tx_chain;
 	struct gelic_net_descr_chain rx_chain;
+	int rx_dma_restart_required;
 	/* gurad dmac descriptor chain*/
 	spinlock_t chain_lock;
 
-	struct net_device_stats netdev_stats;
 	int rx_csum;
 	/* guard tx_dma_progress */
 	spinlock_t tx_dma_lock;
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
old mode 100755
new mode 100644
index 8be8be4..30adf72
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -31,7 +31,6 @@
 #include <linux/skbuff.h>
 #include <linux/rtnetlink.h>
 #include <linux/if_vlan.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
 
@@ -82,7 +81,7 @@
 } PHY_DEVICE_et;
 
 typedef struct {
-	PHY_DEVICE_et phyDevice; 
+	PHY_DEVICE_et phyDevice;
 	u32		phyIdOUI;
 	u16		phyIdModel;
 	char 		*name;
@@ -331,7 +330,7 @@
 					     PCI_DMA_FROMDEVICE);
 			err = pci_dma_mapping_error(map);
 			if(err) {
-				printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", 
+				printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
 				       qdev->ndev->name, err);
 				dev_kfree_skb(lrg_buf_cb->skb);
 				lrg_buf_cb->skb = NULL;
@@ -885,14 +884,14 @@
 	u16 reg;
 
 	/* Enable Auto-negotiation sense */
-	ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, &reg, 
+	ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, &reg,
 			   PHYAddr[qdev->mac_index]);
 	reg |= PETBI_TBI_AUTO_SENSE;
-	ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, 
+	ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg,
 			    PHYAddr[qdev->mac_index]);
 
 	ql_mii_write_reg_ex(qdev, PETBI_NEG_ADVER,
-			    PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, 
+			    PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX,
 			    PHYAddr[qdev->mac_index]);
 
 	ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG,
@@ -946,7 +945,7 @@
 	ql_mii_write_reg_ex(qdev, 0x10, 0x2806, miiAddr);
 	/* Write new PHYAD w/bit 5 set */
 	ql_mii_write_reg_ex(qdev, 0x11, 0x0020 | (PHYAddr[qdev->mac_index] >> 8), miiAddr);
-	/* 
+	/*
 	 * Disable diagnostic mode bit 2 = 0
 	 * Power up device bit 11 = 0
 	 * Link up (on) and activity (blink)
@@ -956,18 +955,18 @@
 	ql_mii_write_reg(qdev, 0x1c, 0xfaf0);
 }
 
-static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev, 
+static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev,
 				 u16 phyIdReg0, u16 phyIdReg1)
 {
 	PHY_DEVICE_et result = PHY_TYPE_UNKNOWN;
-	u32   oui;     
+	u32   oui;
 	u16   model;
-	int i;   
+	int i;
 
 	if (phyIdReg0 == 0xffff) {
 		return result;
 	}
-   
+
 	if (phyIdReg1 == 0xffff) {
 		return result;
 	}
@@ -985,7 +984,7 @@
 
 			printk(KERN_INFO "%s: Phy: %s\n",
 				qdev->ndev->name, PHY_DEVICES[i].name);
-			
+
 		        break;
 		}
 	}
@@ -1034,7 +1033,7 @@
 	{
 		if (ql_mii_read_reg(qdev, 0x1A, &reg))
 			return 0;
-			
+
 		return ((reg & 0x0080) && (reg & 0x1000)) != 0;
 	}
 	case PHY_VITESSE_VSC8211:
@@ -1083,19 +1082,19 @@
 	/*  Check if we have a Agere PHY */
 	if ((reg1 == 0xffff) || (reg2 == 0xffff)) {
 
-		/* Determine which MII address we should be using 
+		/* Determine which MII address we should be using
 		   determined by the index of the card */
 		if (qdev->mac_index == 0) {
 			miiAddr = MII_AGERE_ADDR_1;
 		} else {
 			miiAddr = MII_AGERE_ADDR_2;
 		}
-      
+
 		err =ql_mii_read_reg_ex(qdev, PHY_ID_0_REG, &reg1, miiAddr);
 		if(err != 0) {
 			printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n",
 		       	       qdev->ndev->name);
-                	return err; 
+			return err;
 		}
 
 		err = ql_mii_read_reg_ex(qdev, PHY_ID_1_REG, &reg2, miiAddr);
@@ -1104,9 +1103,9 @@
 			       qdev->ndev->name);
         	        return err;
 		}
-   
+
 		/*  We need to remember to initialize the Agere PHY */
-         	agereAddrChangeNeeded = true; 
+		agereAddrChangeNeeded = true;
 	}
 
 	/*  Determine the particular PHY we have on board to apply
@@ -1115,7 +1114,7 @@
 
 	if ((qdev->phyType == PHY_AGERE_ET1011C) && agereAddrChangeNeeded) {
 		/* need this here so address gets changed */
-		phyAgereSpecificInit(qdev, miiAddr);  
+		phyAgereSpecificInit(qdev, miiAddr);
 	} else if (qdev->phyType == PHY_TYPE_UNKNOWN) {
 		printk(KERN_ERR "%s: PHY is unknown\n", qdev->ndev->name);
 		return -EIO;
@@ -1428,7 +1427,7 @@
 
 static void ql_phy_reset_ex(struct ql3_adapter *qdev)
 {
-	ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, 
+	ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET,
 			    PHYAddr[qdev->mac_index]);
 }
 
@@ -1439,7 +1438,7 @@
 
 	if(qdev->phyType == PHY_AGERE_ET1011C) {
 		/* turn off external loopback */
-		ql_mii_write_reg(qdev, 0x13, 0x0000); 
+		ql_mii_write_reg(qdev, 0x13, 0x0000);
 	}
 
 	if(qdev->mac_index == 0)
@@ -1453,23 +1452,23 @@
 		portConfiguration = PORT_CONFIG_DEFAULT;
 
 	/* Set the 1000 advertisements */
-	ql_mii_read_reg_ex(qdev, PHY_GIG_CONTROL, &reg, 
+	ql_mii_read_reg_ex(qdev, PHY_GIG_CONTROL, &reg,
 			   PHYAddr[qdev->mac_index]);
 	reg &= ~PHY_GIG_ALL_PARAMS;
 
-	if(portConfiguration & 
+	if(portConfiguration &
 	   PORT_CONFIG_FULL_DUPLEX_ENABLED &
 	   PORT_CONFIG_1000MB_SPEED) {
 		reg |= PHY_GIG_ADV_1000F;
 	}
-	 
-	if(portConfiguration & 
+
+	if(portConfiguration &
 	   PORT_CONFIG_HALF_DUPLEX_ENABLED &
 	   PORT_CONFIG_1000MB_SPEED) {
 		reg |= PHY_GIG_ADV_1000H;
 	}
 
-	ql_mii_write_reg_ex(qdev, PHY_GIG_CONTROL, reg, 
+	ql_mii_write_reg_ex(qdev, PHY_GIG_CONTROL, reg,
 			    PHYAddr[qdev->mac_index]);
 
 	/* Set the 10/100 & pause negotiation advertisements */
@@ -1483,7 +1482,7 @@
 	if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) {
 		if(portConfiguration & PORT_CONFIG_100MB_SPEED)
 			reg |= PHY_NEG_ADV_100F;
-		
+
 		if(portConfiguration & PORT_CONFIG_10MB_SPEED)
 			reg |= PHY_NEG_ADV_10F;
 	}
@@ -1491,22 +1490,22 @@
 	if(portConfiguration & PORT_CONFIG_HALF_DUPLEX_ENABLED) {
 		if(portConfiguration & PORT_CONFIG_100MB_SPEED)
 			reg |= PHY_NEG_ADV_100H;
-		
+
 		if(portConfiguration & PORT_CONFIG_10MB_SPEED)
 			reg |= PHY_NEG_ADV_10H;
 	}
 
 	if(portConfiguration &
 	   PORT_CONFIG_1000MB_SPEED) {
-		reg |= 1;	
+		reg |= 1;
 	}
 
-	ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg, 
+	ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg,
 			    PHYAddr[qdev->mac_index]);
 
 	ql_mii_read_reg_ex(qdev, CONTROL_REG, &reg, PHYAddr[qdev->mac_index]);
-	
-	ql_mii_write_reg_ex(qdev, CONTROL_REG, 
+
+	ql_mii_write_reg_ex(qdev, CONTROL_REG,
 			    reg | PHY_CTRL_RESTART_NEG | PHY_CTRL_AUTO_NEG,
 			    PHYAddr[qdev->mac_index]);
 }
@@ -1661,7 +1660,7 @@
 			       "%s: Reset in progress, skip processing link "
 			       "state.\n", qdev->ndev->name);
 
-		spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);		
+		spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
 		return;
 	}
 
@@ -1753,7 +1752,7 @@
 		return -1;
 
 	if (qdev->device_id == QL3032_DEVICE_ID)
-		ql_write_page0_reg(qdev, 
+		ql_write_page0_reg(qdev,
 			&port_regs->macMIIMgmtControlReg, 0x0f00000);
 
 	/* Divide 125MHz clock by 28 to meet PHY timing requirements */
@@ -1866,8 +1865,6 @@
 	strncpy(drvinfo->version, ql3xxx_driver_version, 32);
 	strncpy(drvinfo->fw_version, "N/A", 32);
 	strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32);
-	drvinfo->n_stats = 0;
-	drvinfo->testinfo_len = 0;
 	drvinfo->regdump_len = 0;
 	drvinfo->eedump_len = 0;
 }
@@ -1904,7 +1901,6 @@
 static const struct ethtool_ops ql3xxx_ethtool_ops = {
 	.get_settings = ql_get_settings,
 	.get_drvinfo = ql_get_drvinfo,
-	.get_perm_addr = ethtool_op_get_perm_addr,
 	.get_link = ethtool_op_get_link,
 	.get_msglevel = ql_get_msglevel,
 	.set_msglevel = ql_set_msglevel,
@@ -1940,7 +1936,7 @@
 
 				err = pci_dma_mapping_error(map);
 				if(err) {
-					printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", 
+					printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
 					       qdev->ndev->name, err);
 					dev_kfree_skb(lrg_buf_cb->skb);
 					lrg_buf_cb->skb = NULL;
@@ -2048,14 +2044,14 @@
 	if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) {
 		printk(KERN_WARNING "Frame short but, frame was padded and sent.\n");
 	}
-	
+
 	tx_cb = &qdev->tx_buf[mac_rsp->transaction_id];
 
 	/*  Check the transmit response flags for any errors */
 	if(mac_rsp->flags & OB_MAC_IOCB_RSP_S) {
 		printk(KERN_ERR "Frame too short to be legal, frame not sent.\n");
 
-		qdev->stats.tx_errors++;
+		qdev->ndev->stats.tx_errors++;
 		retval = -EIO;
 		goto frame_not_sent;
 	}
@@ -2063,7 +2059,7 @@
 	if(tx_cb->seg_count == 0) {
 		printk(KERN_ERR "tx_cb->seg_count == 0: %d\n", mac_rsp->transaction_id);
 
-		qdev->stats.tx_errors++;
+		qdev->ndev->stats.tx_errors++;
 		retval = -EIO;
 		goto invalid_seg_count;
 	}
@@ -2082,8 +2078,8 @@
 				       PCI_DMA_TODEVICE);
 		}
 	}
-	qdev->stats.tx_packets++;
-	qdev->stats.tx_bytes += tx_cb->skb->len;
+	qdev->ndev->stats.tx_packets++;
+	qdev->ndev->stats.tx_bytes += tx_cb->skb->len;
 
 frame_not_sent:
 	dev_kfree_skb_irq(tx_cb->skb);
@@ -2112,13 +2108,13 @@
 
 /*
  * The difference between 3022 and 3032 for inbound completions:
- * 3022 uses two buffers per completion.  The first buffer contains 
- * (some) header info, the second the remainder of the headers plus 
- * the data.  For this chip we reserve some space at the top of the 
- * receive buffer so that the header info in buffer one can be 
- * prepended to the buffer two.  Buffer two is the sent up while 
+ * 3022 uses two buffers per completion.  The first buffer contains
+ * (some) header info, the second the remainder of the headers plus
+ * the data.  For this chip we reserve some space at the top of the
+ * receive buffer so that the header info in buffer one can be
+ * prepended to the buffer two.  Buffer two is the sent up while
  * buffer one is returned to the hardware to be reused.
- * 3032 receives all of it's data and headers in one buffer for a 
+ * 3032 receives all of it's data and headers in one buffer for a
  * simpler process.  3032 also supports checksum verification as
  * can be seen in ql_process_macip_rx_intr().
  */
@@ -2142,8 +2138,8 @@
 	lrg_buf_cb2 = ql_get_lbuf(qdev);
 	skb = lrg_buf_cb2->skb;
 
-	qdev->stats.rx_packets++;
-	qdev->stats.rx_bytes += length;
+	qdev->ndev->stats.rx_packets++;
+	qdev->ndev->stats.rx_bytes += length;
 
 	skb_put(skb, length);
 	pci_unmap_single(qdev->pdev,
@@ -2209,13 +2205,13 @@
 						 skb_push(skb2, size), size);
 	} else {
 		u16 checksum = le16_to_cpu(ib_ip_rsp_ptr->checksum);
-		if (checksum & 
-			(IB_IP_IOCB_RSP_3032_ICE | 
-			 IB_IP_IOCB_RSP_3032_CE)) { 
+		if (checksum &
+			(IB_IP_IOCB_RSP_3032_ICE |
+			 IB_IP_IOCB_RSP_3032_CE)) {
 			printk(KERN_ERR
 			       "%s: Bad checksum for this %s packet, checksum = %x.\n",
 			       __func__,
-			       ((checksum & 
+			       ((checksum &
 				IB_IP_IOCB_RSP_3032_TCP) ? "TCP" :
 				"UDP"),checksum);
 		} else if ((checksum & IB_IP_IOCB_RSP_3032_TCP) ||
@@ -2227,8 +2223,8 @@
 	skb2->protocol = eth_type_trans(skb2, qdev->ndev);
 
 	netif_receive_skb(skb2);
-	qdev->stats.rx_packets++;
-	qdev->stats.rx_bytes += length;
+	ndev->stats.rx_packets++;
+	ndev->stats.rx_bytes += length;
 	ndev->last_rx = jiffies;
 	lrg_buf_cb2->skb = NULL;
 
@@ -2249,6 +2245,13 @@
 		qdev->rsp_consumer_index) && (work_done < work_to_do)) {
 
 		net_rsp = qdev->rsp_current;
+		rmb();
+		/*
+		 * Fix 4032 chipe undocumented "feature" where bit-8 is set if the
+		 * inbound completion is for a VLAN.
+		 */
+		if (qdev->device_id == QL3032_DEVICE_ID)
+			net_rsp->opcode &= 0x7f;
 		switch (net_rsp->opcode) {
 
 		case OPCODE_OB_MAC_IOCB_FN0:
@@ -2304,10 +2307,10 @@
 	return work_done;
 }
 
-static int ql_poll(struct net_device *ndev, int *budget)
+static int ql_poll(struct napi_struct *napi, int budget)
 {
-	struct ql3_adapter *qdev = netdev_priv(ndev);
-	int work_to_do = min(*budget, ndev->quota);
+	struct ql3_adapter *qdev = container_of(napi, struct ql3_adapter, napi);
+	struct net_device *ndev = qdev->ndev;
 	int rx_cleaned = 0, tx_cleaned = 0;
 	unsigned long hw_flags;
 	struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
@@ -2315,16 +2318,13 @@
 	if (!netif_carrier_ok(ndev))
 		goto quit_polling;
 
-	ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, work_to_do);
-	*budget -= rx_cleaned;
-	ndev->quota -= rx_cleaned;
+	ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, budget);
 
-	if( tx_cleaned + rx_cleaned != work_to_do ||
+	if (tx_cleaned + rx_cleaned != budget ||
 	    !netif_running(ndev)) {
 quit_polling:
-		netif_rx_complete(ndev);
-
 		spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+		__netif_rx_complete(ndev, napi);
 		ql_update_small_bufq_prod_index(qdev);
 		ql_update_lrg_bufq_prod_index(qdev);
 		writel(qdev->rsp_consumer_index,
@@ -2332,9 +2332,8 @@
 		spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
 
 		ql_enable_interrupts(qdev);
-		return 0;
 	}
-	return 1;
+	return tx_cleaned + rx_cleaned;
 }
 
 static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
@@ -2384,8 +2383,8 @@
 		spin_unlock(&qdev->adapter_lock);
 	} else if (value & ISP_IMR_DISABLE_CMPL_INT) {
 		ql_disable_interrupts(qdev);
-		if (likely(netif_rx_schedule_prep(ndev))) {
-			__netif_rx_schedule(ndev);
+		if (likely(netif_rx_schedule_prep(ndev, &qdev->napi))) {
+			__netif_rx_schedule(ndev, &qdev->napi);
 		}
 	} else {
 		return IRQ_NONE;
@@ -2395,12 +2394,12 @@
 }
 
 /*
- * Get the total number of segments needed for the 
+ * Get the total number of segments needed for the
  * given number of fragments.  This is necessary because
  * outbound address lists (OAL) will be used when more than
- * two frags are given.  Each address list has 5 addr/len 
+ * two frags are given.  Each address list has 5 addr/len
  * pairs.  The 5th pair in each AOL is used to  point to
- * the next AOL if more frags are coming.  
+ * the next AOL if more frags are coming.
  * That is why the frags:segment count  ratio is not linear.
  */
 static int ql_get_seg_count(struct ql3_adapter *qdev,
@@ -2477,12 +2476,12 @@
 
 	err = pci_dma_mapping_error(map);
 	if(err) {
-		printk(KERN_ERR "%s: PCI mapping failed with error: %d\n", 
+		printk(KERN_ERR "%s: PCI mapping failed with error: %d\n",
 		       qdev->ndev->name, err);
 
 		return NETDEV_TX_BUSY;
 	}
-	
+
 	oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low;
 	oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
 	oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
@@ -2512,7 +2511,7 @@
 				err = pci_dma_mapping_error(map);
 				if(err) {
 
-					printk(KERN_ERR "%s: PCI mapping outbound address list with error: %d\n", 
+					printk(KERN_ERR "%s: PCI mapping outbound address list with error: %d\n",
 					       qdev->ndev->name, err);
 					goto map_error;
 				}
@@ -2538,7 +2537,7 @@
 
 			err = pci_dma_mapping_error(map);
 			if(err) {
-				printk(KERN_ERR "%s: PCI mapping frags failed with error: %d\n", 
+				printk(KERN_ERR "%s: PCI mapping frags failed with error: %d\n",
 				       qdev->ndev->name, err);
 				goto map_error;
 			}
@@ -2559,10 +2558,10 @@
 
 map_error:
 	/* A PCI mapping failed and now we will need to back out
-	 * We need to traverse through the oal's and associated pages which 
+	 * We need to traverse through the oal's and associated pages which
 	 * have been mapped and now we must unmap them to clean up properly
 	 */
-	
+
 	seg = 1;
 	oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low;
 	oal = tx_cb->oal;
@@ -2600,11 +2599,11 @@
  * The difference between 3022 and 3032 sends:
  * 3022 only supports a simple single segment transmission.
  * 3032 supports checksumming and scatter/gather lists (fragments).
- * The 3032 supports sglists by using the 3 addr/len pairs (ALP) 
- * in the IOCB plus a chain of outbound address lists (OAL) that 
- * each contain 5 ALPs.  The last ALP of the IOCB (3rd) or OAL (5th) 
- * will used to point to an OAL when more ALP entries are required.  
- * The IOCB is always the top of the chain followed by one or more 
+ * The 3032 supports sglists by using the 3 addr/len pairs (ALP)
+ * in the IOCB plus a chain of outbound address lists (OAL) that
+ * each contain 5 ALPs.  The last ALP of the IOCB (3rd) or OAL (5th)
+ * will used to point to an OAL when more ALP entries are required.
+ * The IOCB is always the top of the chain followed by one or more
  * OALs (when necessary).
  */
 static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
@@ -2618,14 +2617,14 @@
 	if (unlikely(atomic_read(&qdev->tx_count) < 2)) {
 		return NETDEV_TX_BUSY;
 	}
-	
+
 	tx_cb = &qdev->tx_buf[qdev->req_producer_index] ;
 	if((tx_cb->seg_count = ql_get_seg_count(qdev,
 						(skb_shinfo(skb)->nr_frags))) == -1) {
 		printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__);
 		return NETDEV_TX_OK;
 	}
-	
+
 	mac_iocb_ptr = tx_cb->queue_entry;
 	memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req));
 	mac_iocb_ptr->opcode = qdev->mac_ob_opcode;
@@ -2637,12 +2636,12 @@
 	if (qdev->device_id == QL3032_DEVICE_ID &&
 	    skb->ip_summed == CHECKSUM_PARTIAL)
 		ql_hw_csum_setup(skb, mac_iocb_ptr);
-	
+
 	if(ql_send_map(qdev,mac_iocb_ptr,tx_cb,skb) != NETDEV_TX_OK) {
 		printk(KERN_ERR PFX"%s: Could not map the segments!\n",__func__);
 		return NETDEV_TX_BUSY;
 	}
-	
+
 	wmb();
 	qdev->req_producer_index++;
 	if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES)
@@ -2740,7 +2739,7 @@
 		       "%s: qdev->lrg_buf alloc failed.\n", qdev->ndev->name);
 		return -ENOMEM;
 	}
-	
+
 	qdev->lrg_buf_q_alloc_virt_addr =
 	    pci_alloc_consistent(qdev->pdev,
 				 qdev->lrg_buf_q_alloc_size,
@@ -3556,6 +3555,7 @@
 {
 	struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
 	struct pci_dev *pdev = qdev->pdev;
+	DECLARE_MAC_BUF(mac);
 
 	printk(KERN_INFO PFX
 	       "\n%s Adapter %d RevisionID %d found %s on PCI slot %d.\n",
@@ -3581,10 +3581,8 @@
 
 	if (netif_msg_probe(qdev))
 		printk(KERN_INFO PFX
-		       "%s: MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
-		       ndev->name, ndev->dev_addr[0], ndev->dev_addr[1],
-		       ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4],
-		       ndev->dev_addr[5]);
+		       "%s: MAC address %s\n",
+		       ndev->name, print_mac(mac, ndev->dev_addr));
 }
 
 static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset)
@@ -3611,7 +3609,7 @@
 
 	del_timer_sync(&qdev->adapter_timer);
 
-	netif_poll_disable(ndev);
+	napi_disable(&qdev->napi);
 
 	if (do_reset) {
 		int soft_reset;
@@ -3699,7 +3697,7 @@
 
 	mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);
 
-	netif_poll_enable(ndev);
+	napi_enable(&qdev->napi);
 	ql_enable_interrupts(qdev);
 	return 0;
 
@@ -3752,12 +3750,6 @@
 	return (ql_adapter_up(qdev));
 }
 
-static struct net_device_stats *ql3xxx_get_stats(struct net_device *dev)
-{
-	struct ql3_adapter *qdev = (struct ql3_adapter *)dev->priv;
-	return &qdev->stats;
-}
-
 static void ql3xxx_set_multicast_list(struct net_device *ndev)
 {
 	/*
@@ -4010,7 +4002,6 @@
 		goto err_out_free_regions;
 	}
 
-	SET_MODULE_OWNER(ndev);
 	SET_NETDEV_DEV(ndev, &pdev->dev);
 
 	pci_set_drvdata(pdev, ndev);
@@ -4048,15 +4039,13 @@
 	ndev->open = ql3xxx_open;
 	ndev->hard_start_xmit = ql3xxx_send;
 	ndev->stop = ql3xxx_close;
-	ndev->get_stats = ql3xxx_get_stats;
 	ndev->set_multicast_list = ql3xxx_set_multicast_list;
 	SET_ETHTOOL_OPS(ndev, &ql3xxx_ethtool_ops);
 	ndev->set_mac_address = ql3xxx_set_mac_address;
 	ndev->tx_timeout = ql3xxx_tx_timeout;
 	ndev->watchdog_timeo = 5 * HZ;
 
-	ndev->poll = &ql_poll;
-	ndev->weight = 64;
+	netif_napi_add(ndev, &qdev->napi, ql_poll, 64);
 
 	ndev->irq = pdev->irq;
 
diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h
old mode 100755
new mode 100644
index 4a832c4..fbcb0b9
--- a/drivers/net/qla3xxx.h
+++ b/drivers/net/qla3xxx.h
@@ -556,7 +556,7 @@
 	IP_ADDR_INDEX_REG_FUNC_3_SEC = 0x0007,
 	IP_ADDR_INDEX_REG_6 = 0x0008,
 	IP_ADDR_INDEX_REG_OFFSET_MASK = 0x0030,
-	IP_ADDR_INDEX_REG_E = 0x0040, 
+	IP_ADDR_INDEX_REG_E = 0x0040,
 };
 enum {
 	QL3032_PORT_CONTROL_DS = 0x0001,
@@ -1112,7 +1112,7 @@
  * OAL has 5 entries:
  * 1 thru 4 point to frags
  * fifth points to next oal.
- */ 
+ */
 #define MAX_OAL_CNT ((MAX_SKB_FRAGS-1)/4 + 1)
 
 struct oal_entry {
@@ -1137,7 +1137,7 @@
 	struct ob_mac_iocb_req *queue_entry ;
 	int seg_count;
 	struct oal *oal;
-	struct map_list map[MAX_SKB_FRAGS+1]; 
+	struct map_list map[MAX_SKB_FRAGS+1];
 };
 
 /* definitions for type field */
@@ -1175,6 +1175,8 @@
 	struct pci_dev *pdev;
 	struct net_device *ndev;	/* Parent NET device */
 
+	struct napi_struct napi;
+
 	/* Hardware information */
 	u8 chip_rev_id;
 	u8 pci_slot;
@@ -1281,7 +1283,6 @@
 	u32 update_ob_opcode;	/* Opcode to use for updating NCB */
 	u32 mb_bit_mask;	/* MA Bits mask to use on transmission */
 	u32 numPorts;
-	struct net_device_stats stats;
 	struct workqueue_struct *workqueue;
 	struct delayed_work reset_work;
 	struct delayed_work tx_timeout_work;
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index bb6896a..419c00c 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -384,6 +384,7 @@
 	void __iomem *mmio_addr;	/* memory map physical address */
 	struct pci_dev *pci_dev;	/* Index of PCI device */
 	struct net_device *dev;
+	struct napi_struct napi;
 	struct net_device_stats stats;	/* statistics of net device */
 	spinlock_t lock;		/* spin lock flag */
 	u32 msg_enable;
@@ -443,13 +444,13 @@
 static void rtl8169_tx_timeout(struct net_device *dev);
 static struct net_device_stats *rtl8169_get_stats(struct net_device *dev);
 static int rtl8169_rx_interrupt(struct net_device *, struct rtl8169_private *,
-				void __iomem *);
+				void __iomem *, u32 budget);
 static int rtl8169_change_mtu(struct net_device *dev, int new_mtu);
 static void rtl8169_down(struct net_device *dev);
 static void rtl8169_rx_clear(struct rtl8169_private *tp);
 
 #ifdef CONFIG_R8169_NAPI
-static int rtl8169_poll(struct net_device *dev, int *budget);
+static int rtl8169_poll(struct napi_struct *napi, int budget);
 #endif
 
 static const unsigned int rtl8169_rx_config =
@@ -725,6 +726,12 @@
 
 	auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
 
+	if (tp->mac_version == RTL_GIGA_MAC_VER_12) {
+		/* Vendor specific (0x1f) and reserved (0x0e) MII registers. */
+		mdio_write(ioaddr, 0x1f, 0x0000);
+		mdio_write(ioaddr, 0x0e, 0x0000);
+	}
+
 	tp->phy_auto_nego_reg = auto_nego;
 	tp->phy_1000_ctrl_reg = giga_ctrl;
 
@@ -970,24 +977,29 @@
 };
 
 struct rtl8169_counters {
-	u64	tx_packets;
-	u64	rx_packets;
-	u64	tx_errors;
-	u32	rx_errors;
-	u16	rx_missed;
-	u16	align_errors;
-	u32	tx_one_collision;
-	u32	tx_multi_collision;
-	u64	rx_unicast;
-	u64	rx_broadcast;
-	u32	rx_multicast;
-	u16	tx_aborted;
-	u16	tx_underun;
+	__le64	tx_packets;
+	__le64	rx_packets;
+	__le64	tx_errors;
+	__le32	rx_errors;
+	__le16	rx_missed;
+	__le16	align_errors;
+	__le32	tx_one_collision;
+	__le32	tx_multi_collision;
+	__le64	rx_unicast;
+	__le64	rx_broadcast;
+	__le32	rx_multicast;
+	__le16	tx_aborted;
+	__le16	tx_underun;
 };
 
-static int rtl8169_get_stats_count(struct net_device *dev)
+static int rtl8169_get_sset_count(struct net_device *dev, int sset)
 {
-	return ARRAY_SIZE(rtl8169_gstrings);
+	switch (sset) {
+	case ETH_SS_STATS:
+		return ARRAY_SIZE(rtl8169_gstrings);
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void rtl8169_get_ethtool_stats(struct net_device *dev,
@@ -1054,19 +1066,15 @@
 	.set_msglevel		= rtl8169_set_msglevel,
 	.get_rx_csum		= rtl8169_get_rx_csum,
 	.set_rx_csum		= rtl8169_set_rx_csum,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
 	.set_tx_csum		= ethtool_op_set_tx_csum,
-	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
-	.get_tso		= ethtool_op_get_tso,
 	.set_tso		= ethtool_op_set_tso,
 	.get_regs		= rtl8169_get_regs,
 	.get_wol		= rtl8169_get_wol,
 	.set_wol		= rtl8169_set_wol,
 	.get_strings		= rtl8169_get_strings,
-	.get_stats_count	= rtl8169_get_stats_count,
+	.get_sset_count		= rtl8169_get_sset_count,
 	.get_ethtool_stats	= rtl8169_get_ethtool_stats,
-	.get_perm_addr		= ethtool_op_get_perm_addr,
 };
 
 static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg,
@@ -1223,7 +1231,10 @@
 		return;
 	}
 
-	/* phy config for RTL8169s mac_version C chip */
+	if ((tp->mac_version != RTL_GIGA_MAC_VER_02) &&
+	    (tp->mac_version != RTL_GIGA_MAC_VER_03))
+		return;
+
 	mdio_write(ioaddr, 31, 0x0001);			//w 31 2 0 1
 	mdio_write(ioaddr, 21, 0x1000);			//w 21 15 0 1000
 	mdio_write(ioaddr, 24, 0x65c7);			//w 24 15 0 65c7
@@ -1497,7 +1508,6 @@
 		goto out;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 	tp = netdev_priv(dev);
 	tp->dev = dev;
@@ -1648,8 +1658,7 @@
 	dev->set_mac_address = rtl_set_mac_address;
 
 #ifdef CONFIG_R8169_NAPI
-	dev->poll = rtl8169_poll;
-	dev->weight = R8169_NAPI_WEIGHT;
+	netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT);
 #endif
 
 #ifdef CONFIG_R8169_VLAN
@@ -1769,6 +1778,10 @@
 	if (retval < 0)
 		goto err_release_ring_2;
 
+#ifdef CONFIG_R8169_NAPI
+	napi_enable(&tp->napi);
+#endif
+
 	rtl_hw_start(dev);
 
 	rtl8169_request_timer(dev);
@@ -1910,7 +1923,11 @@
 
 	rtl_set_rx_max_size(ioaddr);
 
-	rtl_set_rx_tx_config_registers(tp);
+	if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
+	    (tp->mac_version == RTL_GIGA_MAC_VER_04))
+		rtl_set_rx_tx_config_registers(tp);
 
 	tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
 
@@ -1933,6 +1950,14 @@
 
 	rtl_set_rx_tx_desc_registers(tp, ioaddr);
 
+	if ((tp->mac_version != RTL_GIGA_MAC_VER_01) &&
+	    (tp->mac_version != RTL_GIGA_MAC_VER_02) &&
+	    (tp->mac_version != RTL_GIGA_MAC_VER_03) &&
+	    (tp->mac_version != RTL_GIGA_MAC_VER_04)) {
+		RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+		rtl_set_rx_tx_config_registers(tp);
+	}
+
 	RTL_W8(Cfg9346, Cfg9346_Lock);
 
 	/* Initially a 10 us delay. Turned it into a PCI commit. - FR */
@@ -1947,8 +1972,6 @@
 
 	/* Enable all known interrupts by setting the interrupt mask. */
 	RTL_W16(IntrMask, tp->intr_event);
-
-	RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
 }
 
 static void rtl_hw_start_8168(struct net_device *dev)
@@ -2064,7 +2087,9 @@
 	if (ret < 0)
 		goto out;
 
-	netif_poll_enable(dev);
+#ifdef CONFIG_R8169_NAPI
+	napi_enable(&tp->napi);
+#endif
 
 	rtl_hw_start(dev);
 
@@ -2256,11 +2281,15 @@
 	synchronize_irq(dev->irq);
 
 	/* Wait for any pending NAPI task to complete */
-	netif_poll_disable(dev);
+#ifdef CONFIG_R8169_NAPI
+	napi_disable(&tp->napi);
+#endif
 
 	rtl8169_irq_mask_and_ack(ioaddr);
 
-	netif_poll_enable(dev);
+#ifdef CONFIG_R8169_NAPI
+	napi_enable(&tp->napi);
+#endif
 }
 
 static void rtl8169_reinit_task(struct work_struct *work)
@@ -2304,7 +2333,7 @@
 
 	rtl8169_wait_for_quiescence(dev);
 
-	rtl8169_rx_interrupt(dev, tp, tp->mmio_addr);
+	rtl8169_rx_interrupt(dev, tp, tp->mmio_addr, ~(u32)0);
 	rtl8169_tx_clear(tp);
 
 	if (tp->dirty_rx == tp->cur_rx) {
@@ -2562,6 +2591,15 @@
 		    (TX_BUFFS_AVAIL(tp) >= MAX_SKB_FRAGS)) {
 			netif_wake_queue(dev);
 		}
+		/*
+		 * 8168 hack: TxPoll requests are lost when the Tx packets are
+		 * too close. Let's kick an extra TxPoll request when a burst
+		 * of start_xmit activity is detected (if it is not detected,
+		 * it is slow enough). -- FR
+		 */
+		smp_rmb();
+		if (tp->cur_tx != dirty_tx)
+			RTL_W8(TxPoll, NPQ);
 	}
 }
 
@@ -2609,14 +2647,14 @@
 
 static int rtl8169_rx_interrupt(struct net_device *dev,
 				struct rtl8169_private *tp,
-				void __iomem *ioaddr)
+				void __iomem *ioaddr, u32 budget)
 {
 	unsigned int cur_rx, rx_left;
 	unsigned int delta, count;
 
 	cur_rx = tp->cur_rx;
 	rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
-	rx_left = rtl8169_rx_quota(rx_left, (u32) dev->quota);
+	rx_left = rtl8169_rx_quota(rx_left, budget);
 
 	for (; rx_left > 0; rx_left--, cur_rx++) {
 		unsigned int entry = cur_rx % NUM_RX_DESC;
@@ -2761,20 +2799,22 @@
 			rtl8169_check_link_status(dev, tp, ioaddr);
 
 #ifdef CONFIG_R8169_NAPI
-		RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
-		tp->intr_mask = ~tp->napi_event;
+		if (status & tp->napi_event) {
+			RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event);
+			tp->intr_mask = ~tp->napi_event;
 
-		if (likely(netif_rx_schedule_prep(dev)))
-			__netif_rx_schedule(dev);
-		else if (netif_msg_intr(tp)) {
-			printk(KERN_INFO "%s: interrupt %04x taken in poll\n",
-			       dev->name, status);
+		if (likely(netif_rx_schedule_prep(dev, &tp->napi)))
+			__netif_rx_schedule(dev, &tp->napi);
+			else if (netif_msg_intr(tp)) {
+				printk(KERN_INFO "%s: interrupt %04x in poll\n",
+				       dev->name, status);
+			}
 		}
 		break;
 #else
 		/* Rx interrupt */
 		if (status & (RxOK | RxOverflow | RxFIFOOver))
-			rtl8169_rx_interrupt(dev, tp, ioaddr);
+			rtl8169_rx_interrupt(dev, tp, ioaddr, ~(u32)0);
 
 		/* Tx interrupt */
 		if (status & (TxOK | TxErr))
@@ -2797,20 +2837,18 @@
 }
 
 #ifdef CONFIG_R8169_NAPI
-static int rtl8169_poll(struct net_device *dev, int *budget)
+static int rtl8169_poll(struct napi_struct *napi, int budget)
 {
-	unsigned int work_done, work_to_do = min(*budget, dev->quota);
-	struct rtl8169_private *tp = netdev_priv(dev);
+	struct rtl8169_private *tp = container_of(napi, struct rtl8169_private, napi);
+	struct net_device *dev = tp->dev;
 	void __iomem *ioaddr = tp->mmio_addr;
+	int work_done;
 
-	work_done = rtl8169_rx_interrupt(dev, tp, ioaddr);
+	work_done = rtl8169_rx_interrupt(dev, tp, ioaddr, (u32) budget);
 	rtl8169_tx_interrupt(dev, tp, ioaddr);
 
-	*budget -= work_done;
-	dev->quota -= work_done;
-
-	if (work_done < work_to_do) {
-		netif_rx_complete(dev);
+	if (work_done < budget) {
+		netif_rx_complete(dev, napi);
 		tp->intr_mask = 0xffff;
 		/*
 		 * 20040426: the barrier is not strictly required but the
@@ -2822,7 +2860,7 @@
 		RTL_W16(IntrMask, tp->intr_event);
 	}
 
-	return (work_done >= work_to_do);
+	return work_done;
 }
 #endif
 
@@ -2851,7 +2889,7 @@
 	synchronize_irq(dev->irq);
 
 	if (!poll_locked) {
-		netif_poll_disable(dev);
+		napi_disable(&tp->napi);
 		poll_locked++;
 	}
 
@@ -2889,8 +2927,6 @@
 
 	free_irq(dev->irq, dev);
 
-	netif_poll_enable(dev);
-
 	pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray,
 			    tp->RxPhyAddr);
 	pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray,
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index df6b738..e7fd08a 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -53,7 +53,6 @@
 	struct rio_mport *mport;
 	struct sk_buff *rx_skb[RIONET_RX_RING_SIZE];
 	struct sk_buff *tx_skb[RIONET_TX_RING_SIZE];
-	struct net_device_stats stats;
 	int rx_slot;
 	int tx_slot;
 	int tx_cnt;
@@ -91,12 +90,6 @@
 #define RIONET_MAC_MATCH(x)	(*(u32 *)x == 0x00010001)
 #define RIONET_GET_DESTID(x)	(*(u16 *)(x + 4))
 
-static struct net_device_stats *rionet_stats(struct net_device *ndev)
-{
-	struct rionet_private *rnet = ndev->priv;
-	return &rnet->stats;
-}
-
 static int rionet_rx_clean(struct net_device *ndev)
 {
 	int i;
@@ -120,15 +113,15 @@
 		error = netif_rx(rnet->rx_skb[i]);
 
 		if (error == NET_RX_DROP) {
-			rnet->stats.rx_dropped++;
+			ndev->stats.rx_dropped++;
 		} else if (error == NET_RX_BAD) {
 			if (netif_msg_rx_err(rnet))
 				printk(KERN_WARNING "%s: bad rx packet\n",
 				       DRV_NAME);
-			rnet->stats.rx_errors++;
+			ndev->stats.rx_errors++;
 		} else {
-			rnet->stats.rx_packets++;
-			rnet->stats.rx_bytes += RIO_MAX_MSG_SIZE;
+			ndev->stats.rx_packets++;
+			ndev->stats.rx_bytes += RIO_MAX_MSG_SIZE;
 		}
 
 	} while ((i = (i + 1) % RIONET_RX_RING_SIZE) != rnet->rx_slot);
@@ -163,8 +156,8 @@
 	rio_add_outb_message(rnet->mport, rdev, 0, skb->data, skb->len);
 	rnet->tx_skb[rnet->tx_slot] = skb;
 
-	rnet->stats.tx_packets++;
-	rnet->stats.tx_bytes += skb->len;
+	ndev->stats.tx_packets++;
+	ndev->stats.tx_bytes += skb->len;
 
 	if (++rnet->tx_cnt == RIONET_TX_RING_SIZE)
 		netif_stop_queue(ndev);
@@ -439,6 +432,7 @@
 	struct net_device *ndev = NULL;
 	struct rionet_private *rnet;
 	u16 device_id;
+	DECLARE_MAC_BUF(mac);
 
 	/* Allocate our net_device structure */
 	ndev = alloc_etherdev(sizeof(struct rionet_private));
@@ -466,13 +460,10 @@
 	ndev->open = &rionet_open;
 	ndev->hard_start_xmit = &rionet_start_xmit;
 	ndev->stop = &rionet_close;
-	ndev->get_stats = &rionet_stats;
 	ndev->mtu = RIO_MAX_MSG_SIZE - 14;
 	ndev->features = NETIF_F_LLTX;
 	SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops);
 
-	SET_MODULE_OWNER(ndev);
-
 	spin_lock_init(&rnet->lock);
 	spin_lock_init(&rnet->tx_lock);
 
@@ -482,13 +473,12 @@
 	if (rc != 0)
 		goto out;
 
-	printk("%s: %s %s Version %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+	printk("%s: %s %s Version %s, MAC %s\n",
 	       ndev->name,
 	       DRV_NAME,
 	       DRV_DESC,
 	       DRV_VERSION,
-	       ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
-	       ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+	       print_mac(mac, ndev->dev_addr));
 
       out:
 	return rc;
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index 5c2e41f..19152f5 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -109,7 +109,6 @@
 
 	rrpriv = netdev_priv(dev);
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	if (pci_request_regions(pdev, "rrunner")) {
@@ -127,7 +126,6 @@
 	dev->open = &rr_open;
 	dev->hard_start_xmit = &rr_start_xmit;
 	dev->stop = &rr_close;
-	dev->get_stats = &rr_get_stats;
 	dev->do_ioctl = &rr_ioctl;
 
 	dev->base_addr = pci_resource_start(pdev, 0);
@@ -522,7 +520,7 @@
 	struct rr_regs __iomem *regs;
 	struct eeprom *hw = NULL;
 	u32 sram_size, rev;
-	int i;
+	DECLARE_MAC_BUF(mac);
 
 	rrpriv = netdev_priv(dev);
 	regs = rrpriv->regs;
@@ -560,11 +558,7 @@
 	*(u32 *)(dev->dev_addr+2) =
 	  htonl(rr_read_eeprom_word(rrpriv, &hw->manf.BoardULA[4]));
 
-	printk("  MAC: ");
-
-	for (i = 0; i < 5; i++)
-		printk("%2.2x:", dev->dev_addr[i]);
-	printk("%2.2x\n", dev->dev_addr[i]);
+	printk("  MAC: %s\n", print_mac(mac, dev->dev_addr));
 
 	sram_size = rr_read_eeprom_word(rrpriv, (void *)8);
 	printk("  SRAM size 0x%06x\n", sram_size);
@@ -809,7 +803,7 @@
 		case E_CON_REJ:
 			printk(KERN_WARNING "%s: Connection rejected\n",
 			       dev->name);
-			rrpriv->stats.tx_aborted_errors++;
+			dev->stats.tx_aborted_errors++;
 			break;
 		case E_CON_TMOUT:
 			printk(KERN_WARNING "%s: Connection timeout\n",
@@ -818,7 +812,7 @@
 		case E_DISC_ERR:
 			printk(KERN_WARNING "%s: HIPPI disconnect error\n",
 			       dev->name);
-			rrpriv->stats.tx_aborted_errors++;
+			dev->stats.tx_aborted_errors++;
 			break;
 		case E_INT_PRTY:
 			printk(KERN_ERR "%s: HIPPI Internal Parity error\n",
@@ -834,7 +828,7 @@
 		case E_TX_LINK_DROP:
 			printk(KERN_WARNING "%s: Link lost during transmit\n",
 			       dev->name);
-			rrpriv->stats.tx_aborted_errors++;
+			dev->stats.tx_aborted_errors++;
 			writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
 			       &regs->HostCtrl);
 			wmb();
@@ -974,7 +968,7 @@
 		printk("len %x, mode %x\n", pkt_len, desc->mode);
 #endif
 		if ( (rrpriv->rx_ring[index].mode & PACKET_BAD) == PACKET_BAD){
-			rrpriv->stats.rx_dropped++;
+			dev->stats.rx_dropped++;
 			goto defer;
 		}
 
@@ -987,7 +981,7 @@
 				skb = alloc_skb(pkt_len, GFP_ATOMIC);
 				if (skb == NULL){
 					printk(KERN_WARNING "%s: Unable to allocate skb (%i bytes), deferring packet\n", dev->name, pkt_len);
-					rrpriv->stats.rx_dropped++;
+					dev->stats.rx_dropped++;
 					goto defer;
 				} else {
 					pci_dma_sync_single_for_cpu(rrpriv->pci_dev,
@@ -1025,7 +1019,7 @@
 				} else {
 					printk("%s: Out of memory, deferring "
 					       "packet\n", dev->name);
-					rrpriv->stats.rx_dropped++;
+					dev->stats.rx_dropped++;
 					goto defer;
 				}
 			}
@@ -1034,8 +1028,8 @@
 			netif_rx(skb);		/* send it up */
 
 			dev->last_rx = jiffies;
-			rrpriv->stats.rx_packets++;
-			rrpriv->stats.rx_bytes += pkt_len;
+			dev->stats.rx_packets++;
+			dev->stats.rx_bytes += pkt_len;
 		}
 	defer:
 		desc->mode = 0;
@@ -1103,8 +1097,8 @@
 				desc = &(rrpriv->tx_ring[txcon]);
 				skb = rrpriv->tx_skbuff[txcon];
 
-				rrpriv->stats.tx_packets++;
-				rrpriv->stats.tx_bytes += skb->len;
+				dev->stats.tx_packets++;
+				dev->stats.tx_bytes += skb->len;
 
 				pci_unmap_single(rrpriv->pci_dev,
 						 desc->addr.addrlo, skb->len,
@@ -1492,16 +1486,6 @@
 }
 
 
-static struct net_device_stats *rr_get_stats(struct net_device *dev)
-{
-	struct rr_private *rrpriv;
-
-	rrpriv = netdev_priv(dev);
-
-	return(&rrpriv->stats);
-}
-
-
 /*
  * Read the firmware out of the EEPROM and put it into the SRAM
  * (or from user space - later)
diff --git a/drivers/net/rrunner.h b/drivers/net/rrunner.h
index 9f3e050..6a79825 100644
--- a/drivers/net/rrunner.h
+++ b/drivers/net/rrunner.h
@@ -819,7 +819,6 @@
 	u32			tx_full;
 	u32			fw_rev;
 	volatile short		fw_running;
-	struct net_device_stats stats;
 	struct pci_dev		*pci_dev;
 };
 
@@ -834,7 +833,6 @@
 static int rr_open(struct net_device *dev);
 static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static int rr_close(struct net_device *dev);
-static struct net_device_stats *rr_get_stats(struct net_device *dev);
 static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static unsigned int rr_read_eeprom(struct rr_private *rrpriv,
 				   unsigned long offset,
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index 4cb710b..aef66e2 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -220,7 +220,7 @@
 	u64 scheduled_int_ctrl;
 #define SCHED_INT_CTRL_TIMER_EN                BIT(0)
 #define SCHED_INT_CTRL_ONE_SHOT                BIT(1)
-#define SCHED_INT_CTRL_INT2MSI                 TBD
+#define SCHED_INT_CTRL_INT2MSI(val)		vBIT(val,10,6)
 #define SCHED_INT_PERIOD                       TBD
 
 	u64 txreqtimeout;
@@ -325,33 +325,66 @@
 #define TXDMA_TPA_INT                  BIT(5)
 #define TXDMA_SM_INT                   BIT(6)
 	u64 pfc_err_reg;
+#define PFC_ECC_SG_ERR			BIT(7)
+#define PFC_ECC_DB_ERR			BIT(15)
+#define PFC_SM_ERR_ALARM		BIT(23)
+#define PFC_MISC_0_ERR			BIT(31)
+#define PFC_MISC_1_ERR			BIT(32)
+#define PFC_PCIX_ERR			BIT(39)
 	u64 pfc_err_mask;
 	u64 pfc_err_alarm;
 
 	u64 tda_err_reg;
+#define TDA_Fn_ECC_SG_ERR		vBIT(0xff,0,8)
+#define TDA_Fn_ECC_DB_ERR		vBIT(0xff,8,8)
+#define TDA_SM0_ERR_ALARM		BIT(22)
+#define TDA_SM1_ERR_ALARM		BIT(23)
+#define TDA_PCIX_ERR			BIT(39)
 	u64 tda_err_mask;
 	u64 tda_err_alarm;
 
 	u64 pcc_err_reg;
-#define PCC_FB_ECC_DB_ERR		vBIT(0xFF, 16, 8)
+#define PCC_FB_ECC_SG_ERR		vBIT(0xFF,0,8)
+#define PCC_TXB_ECC_SG_ERR		vBIT(0xFF,8,8)
+#define PCC_FB_ECC_DB_ERR		vBIT(0xFF,16, 8)
+#define PCC_TXB_ECC_DB_ERR		vBIT(0xff,24,8)
+#define PCC_SM_ERR_ALARM		vBIT(0xff,32,8)
+#define PCC_WR_ERR_ALARM		vBIT(0xff,40,8)
+#define PCC_N_SERR			vBIT(0xff,48,8)
+#define PCC_6_COF_OV_ERR		BIT(56)
+#define PCC_7_COF_OV_ERR		BIT(57)
+#define PCC_6_LSO_OV_ERR		BIT(58)
+#define PCC_7_LSO_OV_ERR		BIT(59)
 #define PCC_ENABLE_FOUR			vBIT(0x0F,0,8)
-
 	u64 pcc_err_mask;
 	u64 pcc_err_alarm;
 
 	u64 tti_err_reg;
+#define TTI_ECC_SG_ERR			BIT(7)
+#define TTI_ECC_DB_ERR			BIT(15)
+#define TTI_SM_ERR_ALARM		BIT(23)
 	u64 tti_err_mask;
 	u64 tti_err_alarm;
 
 	u64 lso_err_reg;
+#define LSO6_SEND_OFLOW			BIT(12)
+#define LSO7_SEND_OFLOW			BIT(13)
+#define LSO6_ABORT			BIT(14)
+#define LSO7_ABORT			BIT(15)
+#define LSO6_SM_ERR_ALARM		BIT(22)
+#define LSO7_SM_ERR_ALARM		BIT(23)
 	u64 lso_err_mask;
 	u64 lso_err_alarm;
 
 	u64 tpa_err_reg;
+#define TPA_TX_FRM_DROP			BIT(7)
+#define TPA_SM_ERR_ALARM		BIT(23)
+
 	u64 tpa_err_mask;
 	u64 tpa_err_alarm;
 
 	u64 sm_err_reg;
+#define SM_SM_ERR_ALARM			BIT(15)
 	u64 sm_err_mask;
 	u64 sm_err_alarm;
 
@@ -450,22 +483,52 @@
 #define RXDMA_INT_RTI_INT_M            BIT(3)
 
 	u64 rda_err_reg;
+#define RDA_RXDn_ECC_SG_ERR		vBIT(0xFF,0,8)
+#define RDA_RXDn_ECC_DB_ERR		vBIT(0xFF,8,8)
+#define RDA_FRM_ECC_SG_ERR		BIT(23)
+#define RDA_FRM_ECC_DB_N_AERR		BIT(31)
+#define RDA_SM1_ERR_ALARM		BIT(38)
+#define RDA_SM0_ERR_ALARM		BIT(39)
+#define RDA_MISC_ERR			BIT(47)
+#define RDA_PCIX_ERR			BIT(55)
+#define RDA_RXD_ECC_DB_SERR		BIT(63)
 	u64 rda_err_mask;
 	u64 rda_err_alarm;
 
 	u64 rc_err_reg;
+#define RC_PRCn_ECC_SG_ERR		vBIT(0xFF,0,8)
+#define RC_PRCn_ECC_DB_ERR		vBIT(0xFF,8,8)
+#define RC_FTC_ECC_SG_ERR		BIT(23)
+#define RC_FTC_ECC_DB_ERR		BIT(31)
+#define RC_PRCn_SM_ERR_ALARM		vBIT(0xFF,32,8)
+#define RC_FTC_SM_ERR_ALARM		BIT(47)
+#define RC_RDA_FAIL_WR_Rn		vBIT(0xFF,48,8)
 	u64 rc_err_mask;
 	u64 rc_err_alarm;
 
 	u64 prc_pcix_err_reg;
+#define PRC_PCI_AB_RD_Rn		vBIT(0xFF,0,8)
+#define PRC_PCI_DP_RD_Rn		vBIT(0xFF,8,8)
+#define PRC_PCI_AB_WR_Rn		vBIT(0xFF,16,8)
+#define PRC_PCI_DP_WR_Rn		vBIT(0xFF,24,8)
+#define PRC_PCI_AB_F_WR_Rn		vBIT(0xFF,32,8)
+#define PRC_PCI_DP_F_WR_Rn		vBIT(0xFF,40,8)
 	u64 prc_pcix_err_mask;
 	u64 prc_pcix_err_alarm;
 
 	u64 rpa_err_reg;
+#define RPA_ECC_SG_ERR			BIT(7)
+#define RPA_ECC_DB_ERR			BIT(15)
+#define RPA_FLUSH_REQUEST		BIT(22)
+#define RPA_SM_ERR_ALARM		BIT(23)
+#define RPA_CREDIT_ERR			BIT(31)
 	u64 rpa_err_mask;
 	u64 rpa_err_alarm;
 
 	u64 rti_err_reg;
+#define RTI_ECC_SG_ERR			BIT(7)
+#define RTI_ECC_DB_ERR			BIT(15)
+#define RTI_SM_ERR_ALARM		BIT(23)
 	u64 rti_err_mask;
 	u64 rti_err_alarm;
 
@@ -582,17 +645,43 @@
 #define MAC_INT_STATUS_RMAC_INT            BIT(1)
 
 	u64 mac_tmac_err_reg;
-#define TMAC_ERR_REG_TMAC_ECC_DB_ERR       BIT(15)
-#define TMAC_ERR_REG_TMAC_TX_BUF_OVRN      BIT(23)
-#define TMAC_ERR_REG_TMAC_TX_CRI_ERR       BIT(31)
+#define TMAC_ECC_SG_ERR				BIT(7)
+#define TMAC_ECC_DB_ERR				BIT(15)
+#define TMAC_TX_BUF_OVRN			BIT(23)
+#define TMAC_TX_CRI_ERR				BIT(31)
+#define TMAC_TX_SM_ERR				BIT(39)
+#define TMAC_DESC_ECC_SG_ERR			BIT(47)
+#define TMAC_DESC_ECC_DB_ERR			BIT(55)
+
 	u64 mac_tmac_err_mask;
 	u64 mac_tmac_err_alarm;
 
 	u64 mac_rmac_err_reg;
-#define RMAC_ERR_REG_RX_BUFF_OVRN          BIT(0)
-#define RMAC_ERR_REG_RTS_ECC_DB_ERR        BIT(14)
-#define RMAC_ERR_REG_ECC_DB_ERR            BIT(15)
-#define RMAC_LINK_STATE_CHANGE_INT         BIT(31)
+#define RMAC_RX_BUFF_OVRN			BIT(0)
+#define RMAC_FRM_RCVD_INT			BIT(1)
+#define RMAC_UNUSED_INT				BIT(2)
+#define RMAC_RTS_PNUM_ECC_SG_ERR		BIT(5)
+#define RMAC_RTS_DS_ECC_SG_ERR			BIT(6)
+#define RMAC_RD_BUF_ECC_SG_ERR			BIT(7)
+#define RMAC_RTH_MAP_ECC_SG_ERR			BIT(8)
+#define RMAC_RTH_SPDM_ECC_SG_ERR		BIT(9)
+#define RMAC_RTS_VID_ECC_SG_ERR			BIT(10)
+#define RMAC_DA_SHADOW_ECC_SG_ERR		BIT(11)
+#define RMAC_RTS_PNUM_ECC_DB_ERR		BIT(13)
+#define RMAC_RTS_DS_ECC_DB_ERR			BIT(14)
+#define RMAC_RD_BUF_ECC_DB_ERR			BIT(15)
+#define RMAC_RTH_MAP_ECC_DB_ERR			BIT(16)
+#define RMAC_RTH_SPDM_ECC_DB_ERR		BIT(17)
+#define RMAC_RTS_VID_ECC_DB_ERR			BIT(18)
+#define RMAC_DA_SHADOW_ECC_DB_ERR		BIT(19)
+#define RMAC_LINK_STATE_CHANGE_INT		BIT(31)
+#define RMAC_RX_SM_ERR				BIT(39)
+#define RMAC_SINGLE_ECC_ERR			(BIT(5) | BIT(6) | BIT(7) |\
+						BIT(8)  | BIT(9) | BIT(10)|\
+						BIT(11))
+#define RMAC_DOUBLE_ECC_ERR			(BIT(13) | BIT(14) | BIT(15) |\
+						BIT(16)  | BIT(17) | BIT(18)|\
+						BIT(19))
 	u64 mac_rmac_err_mask;
 	u64 mac_rmac_err_alarm;
 
@@ -747,10 +836,10 @@
 #define MC_ERR_REG_MIRI_CRI_ERR_1          BIT(23)
 #define MC_ERR_REG_SM_ERR                  BIT(31)
 #define MC_ERR_REG_ECC_ALL_SNG		   (BIT(2) | BIT(3) | BIT(4) | BIT(5) |\
-					    BIT(6) | BIT(7) | BIT(17) | BIT(19))
+					BIT(17) | BIT(19))
 #define MC_ERR_REG_ECC_ALL_DBL		   (BIT(10) | BIT(11) | BIT(12) |\
-					    BIT(13) | BIT(14) | BIT(15) |\
-					    BIT(18) | BIT(20))
+					BIT(13) | BIT(18) | BIT(20))
+#define PLL_LOCK_N			BIT(39)
 	u64 mc_err_mask;
 	u64 mc_err_alarm;
 
@@ -824,11 +913,17 @@
 #define XGXS_INT_MASK_RXGXS                BIT(1)
 
 	u64 xgxs_txgxs_err_reg;
-#define TXGXS_ECC_DB_ERR                   BIT(15)
+#define TXGXS_ECC_SG_ERR		BIT(7)
+#define TXGXS_ECC_DB_ERR		BIT(15)
+#define TXGXS_ESTORE_UFLOW		BIT(31)
+#define TXGXS_TX_SM_ERR			BIT(39)
+
 	u64 xgxs_txgxs_err_mask;
 	u64 xgxs_txgxs_err_alarm;
 
 	u64 xgxs_rxgxs_err_reg;
+#define RXGXS_ESTORE_OFLOW		BIT(7)
+#define RXGXS_RX_SM_ERR			BIT(39)
 	u64 xgxs_rxgxs_err_mask;
 	u64 xgxs_rxgxs_err_alarm;
 
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index afef6c0..22e4054 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -32,13 +32,13 @@
  * rx_ring_sz: This defines the number of receive blocks each ring can have.
  *     This is also an array of size 8.
  * rx_ring_mode: This defines the operation mode of all 8 rings. The valid
- *		values are 1, 2 and 3.
+ *		values are 1, 2.
  * tx_fifo_num: This defines the number of Tx FIFOs thats used int the driver.
  * tx_fifo_len: This too is an array of 8. Each element defines the number of
  * Tx descriptors that can be associated with each corresponding FIFO.
  * intr_type: This defines the type of interrupt. The values can be 0(INTA),
- *     1(MSI), 2(MSI_X). Default value is '0(INTA)'
- * lro: Specifies whether to enable Large Receive Offload (LRO) or not.
+ *     2(MSI_X). Default value is '2(MSI_X)'
+ * lro_enable: Specifies whether to enable Large Receive Offload (LRO) or not.
  *     Possible values '1' for enable '0' for disable. Default is '0'
  * lro_max_pkts: This parameter defines maximum number of packets can be
  *     aggregated as a single large packet
@@ -84,14 +84,14 @@
 #include "s2io.h"
 #include "s2io-regs.h"
 
-#define DRV_VERSION "2.0.23.1"
+#define DRV_VERSION "2.0.26.5"
 
 /* S2io Driver name & version. */
 static char s2io_driver_name[] = "Neterion";
 static char s2io_driver_version[] = DRV_VERSION;
 
-static int rxd_size[4] = {32,48,48,64};
-static int rxd_count[4] = {127,85,85,63};
+static int rxd_size[2] = {32,48};
+static int rxd_count[2] = {127,85};
 
 static inline int RXD_IS_UP2DT(struct RxD_t *rxdp)
 {
@@ -130,6 +130,11 @@
 	return 0;
 }
 
+static inline int is_s2io_card_up(const struct s2io_nic * sp)
+{
+	return test_bit(__S2IO_STATE_CARD_UP, &sp->state);
+}
+
 /* Ethtool related variables and Macros. */
 static char s2io_gstrings[][ETH_GSTRING_LEN] = {
 	"Register test\t(offline)",
@@ -263,46 +268,71 @@
 	{"serious_err_cnt"},
 	{"soft_reset_cnt"},
 	{"fifo_full_cnt"},
-	{"ring_full_cnt"},
-	("alarm_transceiver_temp_high"),
-	("alarm_transceiver_temp_low"),
-	("alarm_laser_bias_current_high"),
-	("alarm_laser_bias_current_low"),
-	("alarm_laser_output_power_high"),
-	("alarm_laser_output_power_low"),
-	("warn_transceiver_temp_high"),
-	("warn_transceiver_temp_low"),
-	("warn_laser_bias_current_high"),
-	("warn_laser_bias_current_low"),
-	("warn_laser_output_power_high"),
-	("warn_laser_output_power_low"),
-	("lro_aggregated_pkts"),
-	("lro_flush_both_count"),
-	("lro_out_of_sequence_pkts"),
-	("lro_flush_due_to_max_pkts"),
-	("lro_avg_aggr_pkts"),
-	("mem_alloc_fail_cnt"),
-	("watchdog_timer_cnt"),
-	("mem_allocated"),
-	("mem_freed"),
-	("link_up_cnt"),
-	("link_down_cnt"),
-	("link_up_time"),
-	("link_down_time"),
-	("tx_tcode_buf_abort_cnt"),
-	("tx_tcode_desc_abort_cnt"),
-	("tx_tcode_parity_err_cnt"),
-	("tx_tcode_link_loss_cnt"),
-	("tx_tcode_list_proc_err_cnt"),
-	("rx_tcode_parity_err_cnt"),
-	("rx_tcode_abort_cnt"),
-	("rx_tcode_parity_abort_cnt"),
-	("rx_tcode_rda_fail_cnt"),
-	("rx_tcode_unkn_prot_cnt"),
-	("rx_tcode_fcs_err_cnt"),
-	("rx_tcode_buf_size_err_cnt"),
-	("rx_tcode_rxd_corrupt_cnt"),
-	("rx_tcode_unkn_err_cnt")
+	{"ring_0_full_cnt"},
+	{"ring_1_full_cnt"},
+	{"ring_2_full_cnt"},
+	{"ring_3_full_cnt"},
+	{"ring_4_full_cnt"},
+	{"ring_5_full_cnt"},
+	{"ring_6_full_cnt"},
+	{"ring_7_full_cnt"},
+	{"alarm_transceiver_temp_high"},
+	{"alarm_transceiver_temp_low"},
+	{"alarm_laser_bias_current_high"},
+	{"alarm_laser_bias_current_low"},
+	{"alarm_laser_output_power_high"},
+	{"alarm_laser_output_power_low"},
+	{"warn_transceiver_temp_high"},
+	{"warn_transceiver_temp_low"},
+	{"warn_laser_bias_current_high"},
+	{"warn_laser_bias_current_low"},
+	{"warn_laser_output_power_high"},
+	{"warn_laser_output_power_low"},
+	{"lro_aggregated_pkts"},
+	{"lro_flush_both_count"},
+	{"lro_out_of_sequence_pkts"},
+	{"lro_flush_due_to_max_pkts"},
+	{"lro_avg_aggr_pkts"},
+	{"mem_alloc_fail_cnt"},
+	{"pci_map_fail_cnt"},
+	{"watchdog_timer_cnt"},
+	{"mem_allocated"},
+	{"mem_freed"},
+	{"link_up_cnt"},
+	{"link_down_cnt"},
+	{"link_up_time"},
+	{"link_down_time"},
+	{"tx_tcode_buf_abort_cnt"},
+	{"tx_tcode_desc_abort_cnt"},
+	{"tx_tcode_parity_err_cnt"},
+	{"tx_tcode_link_loss_cnt"},
+	{"tx_tcode_list_proc_err_cnt"},
+	{"rx_tcode_parity_err_cnt"},
+	{"rx_tcode_abort_cnt"},
+	{"rx_tcode_parity_abort_cnt"},
+	{"rx_tcode_rda_fail_cnt"},
+	{"rx_tcode_unkn_prot_cnt"},
+	{"rx_tcode_fcs_err_cnt"},
+	{"rx_tcode_buf_size_err_cnt"},
+	{"rx_tcode_rxd_corrupt_cnt"},
+	{"rx_tcode_unkn_err_cnt"},
+	{"tda_err_cnt"},
+	{"pfc_err_cnt"},
+	{"pcc_err_cnt"},
+	{"tti_err_cnt"},
+	{"tpa_err_cnt"},
+	{"sm_err_cnt"},
+	{"lso_err_cnt"},
+	{"mac_tmac_err_cnt"},
+	{"mac_rmac_err_cnt"},
+	{"xgxs_txgxs_err_cnt"},
+	{"xgxs_rxgxs_err_cnt"},
+	{"rc_err_cnt"},
+	{"prc_pcix_err_cnt"},
+	{"rpa_err_cnt"},
+	{"rda_err_cnt"},
+	{"rti_err_cnt"},
+	{"mc_err_cnt"}
 };
 
 #define S2IO_XENA_STAT_LEN sizeof(ethtool_xena_stats_keys)/ ETH_GSTRING_LEN
@@ -325,6 +355,16 @@
 			timer.data = (unsigned long) arg;	\
 			mod_timer(&timer, (jiffies + exp))	\
 
+/* copy mac addr to def_mac_addr array */
+static void do_s2io_copy_mac_addr(struct s2io_nic *sp, int offset, u64 mac_addr)
+{
+	sp->def_mac_addr[offset].mac_addr[5] = (u8) (mac_addr);
+	sp->def_mac_addr[offset].mac_addr[4] = (u8) (mac_addr >> 8);
+	sp->def_mac_addr[offset].mac_addr[3] = (u8) (mac_addr >> 16);
+	sp->def_mac_addr[offset].mac_addr[2] = (u8) (mac_addr >> 24);
+	sp->def_mac_addr[offset].mac_addr[1] = (u8) (mac_addr >> 32);
+	sp->def_mac_addr[offset].mac_addr[0] = (u8) (mac_addr >> 40);
+}
 /* Add the vlan */
 static void s2io_vlan_rx_register(struct net_device *dev,
 					struct vlan_group *grp)
@@ -422,14 +462,15 @@
 S2IO_PARM_INT(shared_splits, 0);
 S2IO_PARM_INT(tmac_util_period, 5);
 S2IO_PARM_INT(rmac_util_period, 5);
-S2IO_PARM_INT(bimodal, 0);
 S2IO_PARM_INT(l3l4hdr_size, 128);
 /* Frequency of Rx desc syncs expressed as power of 2 */
 S2IO_PARM_INT(rxsync_frequency, 3);
-/* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */
-S2IO_PARM_INT(intr_type, 0);
+/* Interrupt type. Values can be 0(INTA), 2(MSI_X) */
+S2IO_PARM_INT(intr_type, 2);
 /* Large receive offload feature */
-S2IO_PARM_INT(lro, 0);
+static unsigned int lro_enable;
+module_param_named(lro, lro_enable, uint, 0);
+
 /* Max pkts to be aggregated by LRO at one time. If not specified,
  * aggregation happens until we hit max IP pkt size(64K)
  */
@@ -531,7 +572,7 @@
 	for (i = 0; i < config->tx_fifo_num; i++) {
 		int fifo_len = config->tx_cfg[i].fifo_len;
 		int list_holder_size = fifo_len * sizeof(struct list_info_hold);
-		mac_control->fifos[i].list_info = kmalloc(list_holder_size,
+		mac_control->fifos[i].list_info = kzalloc(list_holder_size,
 							  GFP_KERNEL);
 		if (!mac_control->fifos[i].list_info) {
 			DBG_PRINT(INFO_DBG,
@@ -539,7 +580,6 @@
 			return -ENOMEM;
 		}
 		mem_allocated += list_holder_size;
-		memset(mac_control->fifos[i].list_info, 0, list_holder_size);
 	}
 	for (i = 0; i < config->tx_fifo_num; i++) {
 		int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
@@ -670,7 +710,7 @@
 						  GFP_KERNEL);
 			if (!rx_blocks->rxds)
 				return -ENOMEM;
-			mem_allocated += 
+			mem_allocated +=
 			(sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]);
 			for (l=0; l<rxd_count[nic->rxd_mode];l++) {
 				rx_blocks->rxds[l].virt_addr =
@@ -701,7 +741,7 @@
 			    (u64) tmp_p_addr_next;
 		}
 	}
-	if (nic->rxd_mode >= RXD_MODE_3A) {
+	if (nic->rxd_mode == RXD_MODE_3B) {
 		/*
 		 * Allocation of Storages for buffer addresses in 2BUFF mode
 		 * and the buffers as well.
@@ -732,7 +772,7 @@
 					    (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL);
 					if (!ba->ba_0_org)
 						return -ENOMEM;
-					mem_allocated += 
+					mem_allocated +=
 						(BUF0_LEN + ALIGN_SIZE);
 					tmp = (unsigned long)ba->ba_0_org;
 					tmp += ALIGN_SIZE;
@@ -743,7 +783,7 @@
 					    (BUF1_LEN + ALIGN_SIZE, GFP_KERNEL);
 					if (!ba->ba_1_org)
 						return -ENOMEM;
-					mem_allocated 
+					mem_allocated
 						+= (BUF1_LEN + ALIGN_SIZE);
 					tmp = (unsigned long) ba->ba_1_org;
 					tmp += ALIGN_SIZE;
@@ -828,7 +868,7 @@
 					    mac_control->fifos[i].
 					    list_info[mem_blks].
 					    list_phy_addr);
-			nic->mac_control.stats_info->sw_stat.mem_freed 
+			nic->mac_control.stats_info->sw_stat.mem_freed
 						+= PAGE_SIZE;
 		}
 		/* If we got a zero DMA address during allocation,
@@ -843,11 +883,11 @@
 				dev->name);
 			DBG_PRINT(INIT_DBG, "Virtual address %p\n",
 				mac_control->zerodma_virt_addr);
-			nic->mac_control.stats_info->sw_stat.mem_freed 
+			nic->mac_control.stats_info->sw_stat.mem_freed
 						+= PAGE_SIZE;
 		}
 		kfree(mac_control->fifos[i].list_info);
-		nic->mac_control.stats_info->sw_stat.mem_freed += 
+		nic->mac_control.stats_info->sw_stat.mem_freed +=
 		(nic->config.tx_cfg[i].fifo_len *sizeof(struct list_info_hold));
 	}
 
@@ -865,12 +905,12 @@
 					    tmp_v_addr, tmp_p_addr);
 			nic->mac_control.stats_info->sw_stat.mem_freed += size;
 			kfree(mac_control->rings[i].rx_blocks[j].rxds);
-			nic->mac_control.stats_info->sw_stat.mem_freed += 
+			nic->mac_control.stats_info->sw_stat.mem_freed +=
 			( sizeof(struct rxd_info)* rxd_count[nic->rxd_mode]);
 		}
 	}
 
-	if (nic->rxd_mode >= RXD_MODE_3A) {
+	if (nic->rxd_mode == RXD_MODE_3B) {
 		/* Freeing buffer storage addresses in 2BUFF mode. */
 		for (i = 0; i < config->rx_ring_num; i++) {
 			blk_cnt = config->rx_cfg[i].num_rxd /
@@ -891,11 +931,12 @@
 					k++;
 				}
 				kfree(mac_control->rings[i].ba[j]);
-				nic->mac_control.stats_info->sw_stat.mem_freed 				+= (sizeof(struct buffAdd) * 
-				(rxd_count[nic->rxd_mode] + 1));
+				nic->mac_control.stats_info->sw_stat.mem_freed +=
+					(sizeof(struct buffAdd) *
+					(rxd_count[nic->rxd_mode] + 1));
 			}
 			kfree(mac_control->rings[i].ba);
-			nic->mac_control.stats_info->sw_stat.mem_freed += 
+			nic->mac_control.stats_info->sw_stat.mem_freed +=
 			(sizeof(struct buffAdd *) * blk_cnt);
 		}
 	}
@@ -905,12 +946,12 @@
 				    mac_control->stats_mem_sz,
 				    mac_control->stats_mem,
 				    mac_control->stats_mem_phy);
-		nic->mac_control.stats_info->sw_stat.mem_freed += 
+		nic->mac_control.stats_info->sw_stat.mem_freed +=
 			mac_control->stats_mem_sz;
 	}
 	if (nic->ufo_in_band_v) {
 		kfree(nic->ufo_in_band_v);
-		nic->mac_control.stats_info->sw_stat.mem_freed 
+		nic->mac_control.stats_info->sw_stat.mem_freed
 			+= (ufo_size * sizeof(u64));
 	}
 }
@@ -1455,7 +1496,7 @@
 				&bar0->rts_frm_len_n[i]);
 		}
 	}
-	
+
 	/* Disable differentiated services steering logic */
 	for (i = 0; i < 64; i++) {
 		if (rts_ds_steer(nic, i, 0) == FAILURE) {
@@ -1535,90 +1576,57 @@
 		time++;
 	}
 
-	if (nic->config.bimodal) {
-		int k = 0;
-		for (k = 0; k < config->rx_ring_num; k++) {
-			val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
-			val64 |= TTI_CMD_MEM_OFFSET(0x38+k);
-			writeq(val64, &bar0->tti_command_mem);
+	/* RTI Initialization */
+	if (nic->device_type == XFRAME_II_DEVICE) {
+		/*
+		 * Programmed to generate Apprx 500 Intrs per
+		 * second
+		 */
+		int count = (nic->config.bus_speed * 125)/4;
+		val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count);
+	} else
+		val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF);
+	val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) |
+		 RTI_DATA1_MEM_RX_URNG_B(0x10) |
+		 RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN;
+
+	writeq(val64, &bar0->rti_data1_mem);
+
+	val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
+		RTI_DATA2_MEM_RX_UFC_B(0x2) ;
+	if (nic->config.intr_type == MSI_X)
+	    val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \
+			RTI_DATA2_MEM_RX_UFC_D(0x40));
+	else
+	    val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \
+			RTI_DATA2_MEM_RX_UFC_D(0x80));
+	writeq(val64, &bar0->rti_data2_mem);
+
+	for (i = 0; i < config->rx_ring_num; i++) {
+		val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD
+				| RTI_CMD_MEM_OFFSET(i);
+		writeq(val64, &bar0->rti_command_mem);
 
 		/*
-		 * Once the operation completes, the Strobe bit of the command
-		 * register will be reset. We poll for this particular condition
-		 * We wait for a maximum of 500ms for the operation to complete,
-		 * if it's not complete by then we return error.
-		*/
-			time = 0;
-			while (TRUE) {
-				val64 = readq(&bar0->tti_command_mem);
-				if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) {
-					break;
-				}
-				if (time > 10) {
-					DBG_PRINT(ERR_DBG,
-						"%s: TTI init Failed\n",
-					dev->name);
-					return -1;
-				}
-				time++;
-				msleep(50);
+		 * Once the operation completes, the Strobe bit of the
+		 * command register will be reset. We poll for this
+		 * particular condition. We wait for a maximum of 500ms
+		 * for the operation to complete, if it's not complete
+		 * by then we return error.
+		 */
+		time = 0;
+		while (TRUE) {
+			val64 = readq(&bar0->rti_command_mem);
+			if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD))
+				break;
+
+			if (time > 10) {
+				DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n",
+					  dev->name);
+				return -1;
 			}
-		}
-	} else {
-
-		/* RTI Initialization */
-		if (nic->device_type == XFRAME_II_DEVICE) {
-			/*
-			 * Programmed to generate Apprx 500 Intrs per
-			 * second
-			 */
-			int count = (nic->config.bus_speed * 125)/4;
-			val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count);
-		} else {
-			val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF);
-		}
-		val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) |
-		    RTI_DATA1_MEM_RX_URNG_B(0x10) |
-		    RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN;
-
-		writeq(val64, &bar0->rti_data1_mem);
-
-		val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
-		    RTI_DATA2_MEM_RX_UFC_B(0x2) ;
-		if (nic->intr_type == MSI_X)
-		    val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | \
-				RTI_DATA2_MEM_RX_UFC_D(0x40));
-		else
-		    val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | \
-				RTI_DATA2_MEM_RX_UFC_D(0x80));
-		writeq(val64, &bar0->rti_data2_mem);
-
-		for (i = 0; i < config->rx_ring_num; i++) {
-			val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD
-					| RTI_CMD_MEM_OFFSET(i);
-			writeq(val64, &bar0->rti_command_mem);
-
-			/*
-			 * Once the operation completes, the Strobe bit of the
-			 * command register will be reset. We poll for this
-			 * particular condition. We wait for a maximum of 500ms
-			 * for the operation to complete, if it's not complete
-			 * by then we return error.
-			 */
-			time = 0;
-			while (TRUE) {
-				val64 = readq(&bar0->rti_command_mem);
-				if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) {
-					break;
-				}
-				if (time > 10) {
-					DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n",
-						  dev->name);
-					return -1;
-				}
-				time++;
-				msleep(50);
-			}
+			time++;
+			msleep(50);
 		}
 	}
 
@@ -1723,7 +1731,7 @@
 
 static int s2io_link_fault_indication(struct s2io_nic *nic)
 {
-	if (nic->intr_type != INTA)
+	if (nic->config.intr_type != INTA)
 		return MAC_RMAC_ERR_TIMER;
 	if (nic->device_type == XFRAME_II_DEVICE)
 		return LINK_UP_DOWN_INTERRUPT;
@@ -1732,6 +1740,150 @@
 }
 
 /**
+ *  do_s2io_write_bits -  update alarm bits in alarm register
+ *  @value: alarm bits
+ *  @flag: interrupt status
+ *  @addr: address value
+ *  Description: update alarm bits in alarm register
+ *  Return Value:
+ *  NONE.
+ */
+static void do_s2io_write_bits(u64 value, int flag, void __iomem *addr)
+{
+	u64 temp64;
+
+	temp64 = readq(addr);
+
+	if(flag == ENABLE_INTRS)
+		temp64 &= ~((u64) value);
+	else
+		temp64 |= ((u64) value);
+	writeq(temp64, addr);
+}
+
+static void en_dis_err_alarms(struct s2io_nic *nic, u16 mask, int flag)
+{
+	struct XENA_dev_config __iomem *bar0 = nic->bar0;
+	register u64 gen_int_mask = 0;
+
+	if (mask & TX_DMA_INTR) {
+
+		gen_int_mask |= TXDMA_INT_M;
+
+		do_s2io_write_bits(TXDMA_TDA_INT | TXDMA_PFC_INT |
+				TXDMA_PCC_INT | TXDMA_TTI_INT |
+				TXDMA_LSO_INT | TXDMA_TPA_INT |
+				TXDMA_SM_INT, flag, &bar0->txdma_int_mask);
+
+		do_s2io_write_bits(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM |
+				PFC_MISC_0_ERR | PFC_MISC_1_ERR |
+				PFC_PCIX_ERR | PFC_ECC_SG_ERR, flag,
+				&bar0->pfc_err_mask);
+
+		do_s2io_write_bits(TDA_Fn_ECC_DB_ERR | TDA_SM0_ERR_ALARM |
+				TDA_SM1_ERR_ALARM | TDA_Fn_ECC_SG_ERR |
+				TDA_PCIX_ERR, flag, &bar0->tda_err_mask);
+
+		do_s2io_write_bits(PCC_FB_ECC_DB_ERR | PCC_TXB_ECC_DB_ERR |
+				PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM |
+				PCC_N_SERR | PCC_6_COF_OV_ERR |
+				PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR |
+				PCC_7_LSO_OV_ERR | PCC_FB_ECC_SG_ERR |
+				PCC_TXB_ECC_SG_ERR, flag, &bar0->pcc_err_mask);
+
+		do_s2io_write_bits(TTI_SM_ERR_ALARM | TTI_ECC_SG_ERR |
+				TTI_ECC_DB_ERR, flag, &bar0->tti_err_mask);
+
+		do_s2io_write_bits(LSO6_ABORT | LSO7_ABORT |
+				LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM |
+				LSO6_SEND_OFLOW | LSO7_SEND_OFLOW,
+				flag, &bar0->lso_err_mask);
+
+		do_s2io_write_bits(TPA_SM_ERR_ALARM | TPA_TX_FRM_DROP,
+				flag, &bar0->tpa_err_mask);
+
+		do_s2io_write_bits(SM_SM_ERR_ALARM, flag, &bar0->sm_err_mask);
+
+	}
+
+	if (mask & TX_MAC_INTR) {
+		gen_int_mask |= TXMAC_INT_M;
+		do_s2io_write_bits(MAC_INT_STATUS_TMAC_INT, flag,
+				&bar0->mac_int_mask);
+		do_s2io_write_bits(TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR |
+				TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR |
+				TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR,
+				flag, &bar0->mac_tmac_err_mask);
+	}
+
+	if (mask & TX_XGXS_INTR) {
+		gen_int_mask |= TXXGXS_INT_M;
+		do_s2io_write_bits(XGXS_INT_STATUS_TXGXS, flag,
+				&bar0->xgxs_int_mask);
+		do_s2io_write_bits(TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR |
+				TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR,
+				flag, &bar0->xgxs_txgxs_err_mask);
+	}
+
+	if (mask & RX_DMA_INTR) {
+		gen_int_mask |= RXDMA_INT_M;
+		do_s2io_write_bits(RXDMA_INT_RC_INT_M | RXDMA_INT_RPA_INT_M |
+				RXDMA_INT_RDA_INT_M | RXDMA_INT_RTI_INT_M,
+				flag, &bar0->rxdma_int_mask);
+		do_s2io_write_bits(RC_PRCn_ECC_DB_ERR | RC_FTC_ECC_DB_ERR |
+				RC_PRCn_SM_ERR_ALARM | RC_FTC_SM_ERR_ALARM |
+				RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR |
+				RC_RDA_FAIL_WR_Rn, flag, &bar0->rc_err_mask);
+		do_s2io_write_bits(PRC_PCI_AB_RD_Rn | PRC_PCI_AB_WR_Rn |
+				PRC_PCI_AB_F_WR_Rn | PRC_PCI_DP_RD_Rn |
+				PRC_PCI_DP_WR_Rn | PRC_PCI_DP_F_WR_Rn, flag,
+				&bar0->prc_pcix_err_mask);
+		do_s2io_write_bits(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR |
+				RPA_ECC_SG_ERR | RPA_ECC_DB_ERR, flag,
+				&bar0->rpa_err_mask);
+		do_s2io_write_bits(RDA_RXDn_ECC_DB_ERR | RDA_FRM_ECC_DB_N_AERR |
+				RDA_SM1_ERR_ALARM | RDA_SM0_ERR_ALARM |
+				RDA_RXD_ECC_DB_SERR | RDA_RXDn_ECC_SG_ERR |
+				RDA_FRM_ECC_SG_ERR | RDA_MISC_ERR|RDA_PCIX_ERR,
+				flag, &bar0->rda_err_mask);
+		do_s2io_write_bits(RTI_SM_ERR_ALARM |
+				RTI_ECC_SG_ERR | RTI_ECC_DB_ERR,
+				flag, &bar0->rti_err_mask);
+	}
+
+	if (mask & RX_MAC_INTR) {
+		gen_int_mask |= RXMAC_INT_M;
+		do_s2io_write_bits(MAC_INT_STATUS_RMAC_INT, flag,
+				&bar0->mac_int_mask);
+		do_s2io_write_bits(RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR |
+				RMAC_UNUSED_INT | RMAC_SINGLE_ECC_ERR |
+				RMAC_DOUBLE_ECC_ERR |
+				RMAC_LINK_STATE_CHANGE_INT,
+				flag, &bar0->mac_rmac_err_mask);
+	}
+
+	if (mask & RX_XGXS_INTR)
+	{
+		gen_int_mask |= RXXGXS_INT_M;
+		do_s2io_write_bits(XGXS_INT_STATUS_RXGXS, flag,
+				&bar0->xgxs_int_mask);
+		do_s2io_write_bits(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR, flag,
+				&bar0->xgxs_rxgxs_err_mask);
+	}
+
+	if (mask & MC_INTR) {
+		gen_int_mask |= MC_INT_M;
+		do_s2io_write_bits(MC_INT_MASK_MC_INT, flag, &bar0->mc_int_mask);
+		do_s2io_write_bits(MC_ERR_REG_SM_ERR | MC_ERR_REG_ECC_ALL_SNG |
+				MC_ERR_REG_ECC_ALL_DBL | PLL_LOCK_N, flag,
+				&bar0->mc_err_mask);
+	}
+	nic->general_int_mask = gen_int_mask;
+
+	/* Remove this line when alarm interrupts are enabled */
+	nic->general_int_mask = 0;
+}
+/**
  *  en_dis_able_nic_intrs - Enable or Disable the interrupts
  *  @nic: device private variable,
  *  @mask: A mask indicating which Intr block must be modified and,
@@ -1745,17 +1897,16 @@
 static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
 {
 	struct XENA_dev_config __iomem *bar0 = nic->bar0;
-	register u64 val64 = 0, temp64 = 0;
+	register u64 temp64 = 0, intr_mask = 0;
+
+	intr_mask = nic->general_int_mask;
 
 	/*  Top level interrupt classification */
 	/*  PIC Interrupts */
-	if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) {
+	if (mask & TX_PIC_INTR) {
 		/*  Enable PIC Intrs in the general intr mask register */
-		val64 = TXPIC_INT_M;
+		intr_mask |= TXPIC_INT_M;
 		if (flag == ENABLE_INTRS) {
-			temp64 = readq(&bar0->general_int_mask);
-			temp64 &= ~((u64) val64);
-			writeq(temp64, &bar0->general_int_mask);
 			/*
 			 * If Hercules adapter enable GPIO otherwise
 			 * disable all PCIX, Flash, MDIO, IIC and GPIO
@@ -1764,64 +1915,25 @@
 			 */
 			if (s2io_link_fault_indication(nic) ==
 					LINK_UP_DOWN_INTERRUPT ) {
-				temp64 = readq(&bar0->pic_int_mask);
-				temp64 &= ~((u64) PIC_INT_GPIO);
-				writeq(temp64, &bar0->pic_int_mask);
-				temp64 = readq(&bar0->gpio_int_mask);
-				temp64 &= ~((u64) GPIO_INT_MASK_LINK_UP);
-				writeq(temp64, &bar0->gpio_int_mask);
-			} else {
+				do_s2io_write_bits(PIC_INT_GPIO, flag,
+						&bar0->pic_int_mask);
+				do_s2io_write_bits(GPIO_INT_MASK_LINK_UP, flag,
+						&bar0->gpio_int_mask);
+			} else
 				writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
-			}
-			/*
-			 * No MSI Support is available presently, so TTI and
-			 * RTI interrupts are also disabled.
-			 */
 		} else if (flag == DISABLE_INTRS) {
 			/*
 			 * Disable PIC Intrs in the general
 			 * intr mask register
 			 */
 			writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
-			temp64 = readq(&bar0->general_int_mask);
-			val64 |= temp64;
-			writeq(val64, &bar0->general_int_mask);
-		}
-	}
-
-	/*  MAC Interrupts */
-	/*  Enabling/Disabling MAC interrupts */
-	if (mask & (TX_MAC_INTR | RX_MAC_INTR)) {
-		val64 = TXMAC_INT_M | RXMAC_INT_M;
-		if (flag == ENABLE_INTRS) {
-			temp64 = readq(&bar0->general_int_mask);
-			temp64 &= ~((u64) val64);
-			writeq(temp64, &bar0->general_int_mask);
-			/*
-			 * All MAC block error interrupts are disabled for now
-			 * TODO
-			 */
-		} else if (flag == DISABLE_INTRS) {
-			/*
-			 * Disable MAC Intrs in the general intr mask register
-			 */
-			writeq(DISABLE_ALL_INTRS, &bar0->mac_int_mask);
-			writeq(DISABLE_ALL_INTRS,
-			       &bar0->mac_rmac_err_mask);
-
-			temp64 = readq(&bar0->general_int_mask);
-			val64 |= temp64;
-			writeq(val64, &bar0->general_int_mask);
 		}
 	}
 
 	/*  Tx traffic interrupts */
 	if (mask & TX_TRAFFIC_INTR) {
-		val64 = TXTRAFFIC_INT_M;
+		intr_mask |= TXTRAFFIC_INT_M;
 		if (flag == ENABLE_INTRS) {
-			temp64 = readq(&bar0->general_int_mask);
-			temp64 &= ~((u64) val64);
-			writeq(temp64, &bar0->general_int_mask);
 			/*
 			 * Enable all the Tx side interrupts
 			 * writing 0 Enables all 64 TX interrupt levels
@@ -1833,19 +1945,13 @@
 			 * register.
 			 */
 			writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask);
-			temp64 = readq(&bar0->general_int_mask);
-			val64 |= temp64;
-			writeq(val64, &bar0->general_int_mask);
 		}
 	}
 
 	/*  Rx traffic interrupts */
 	if (mask & RX_TRAFFIC_INTR) {
-		val64 = RXTRAFFIC_INT_M;
+		intr_mask |= RXTRAFFIC_INT_M;
 		if (flag == ENABLE_INTRS) {
-			temp64 = readq(&bar0->general_int_mask);
-			temp64 &= ~((u64) val64);
-			writeq(temp64, &bar0->general_int_mask);
 			/* writing 0 Enables all 8 RX interrupt levels */
 			writeq(0x0, &bar0->rx_traffic_mask);
 		} else if (flag == DISABLE_INTRS) {
@@ -1854,11 +1960,17 @@
 			 * register.
 			 */
 			writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask);
-			temp64 = readq(&bar0->general_int_mask);
-			val64 |= temp64;
-			writeq(val64, &bar0->general_int_mask);
 		}
 	}
+
+	temp64 = readq(&bar0->general_int_mask);
+	if (flag == ENABLE_INTRS)
+		temp64 &= ~((u64) intr_mask);
+	else
+		temp64 = DISABLE_ALL_INTRS;
+	writeq(temp64, &bar0->general_int_mask);
+
+	nic->general_int_mask = readq(&bar0->general_int_mask);
 }
 
 /**
@@ -1871,7 +1983,7 @@
 	int ret = 0, herc;
 	struct XENA_dev_config __iomem *bar0 = sp->bar0;
 	u64 val64 = readq(&bar0->adapter_status);
-	
+
 	herc = (sp->device_type == XFRAME_II_DEVICE);
 
 	if (flag == FALSE) {
@@ -2017,8 +2129,6 @@
 		       &bar0->prc_rxd0_n[i]);
 
 		val64 = readq(&bar0->prc_ctrl_n[i]);
-		if (nic->config.bimodal)
-			val64 |= PRC_CTRL_BIMODAL_INTERRUPT;
 		if (nic->rxd_mode == RXD_MODE_1)
 			val64 |= PRC_CTRL_RC_ENABLED;
 		else
@@ -2062,14 +2172,6 @@
 	writeq(val64, &bar0->adapter_control);
 
 	/*
-	 * Clearing any possible Link state change interrupts that
-	 * could have popped up just before Enabling the card.
-	 */
-	val64 = readq(&bar0->mac_rmac_err_reg);
-	if (val64)
-		writeq(val64, &bar0->mac_rmac_err_reg);
-
-	/*
 	 * Verify if the device is ready to be enabled, if so enable
 	 * it.
 	 */
@@ -2186,7 +2288,7 @@
 			mac_control->fifos[i].list_info[j].list_virt_addr;
 			skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
 			if (skb) {
-				nic->mac_control.stats_info->sw_stat.mem_freed 
+				nic->mac_control.stats_info->sw_stat.mem_freed
 					+= skb->truesize;
 				dev_kfree_skb(skb);
 				cnt++;
@@ -2222,9 +2324,9 @@
 	config = &nic->config;
 
 	/*  Disable all interrupts */
+	en_dis_err_alarms(nic, ENA_ALL_INTRS, DISABLE_INTRS);
 	interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
-	interruptible |= TX_PIC_INTR | RX_PIC_INTR;
-	interruptible |= TX_MAC_INTR | RX_MAC_INTR;
+	interruptible |= TX_PIC_INTR;
 	en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS);
 
 	/* Clearing Adapter_En bit of ADAPTER_CONTROL Register */
@@ -2233,44 +2335,6 @@
 	writeq(val64, &bar0->adapter_control);
 }
 
-static int fill_rxd_3buf(struct s2io_nic *nic, struct RxD_t *rxdp, struct \
-				sk_buff *skb)
-{
-	struct net_device *dev = nic->dev;
-	struct sk_buff *frag_list;
-	void *tmp;
-
-	/* Buffer-1 receives L3/L4 headers */
-	((struct RxD3*)rxdp)->Buffer1_ptr = pci_map_single
-			(nic->pdev, skb->data, l3l4hdr_size + 4,
-			PCI_DMA_FROMDEVICE);
-
-	/* skb_shinfo(skb)->frag_list will have L4 data payload */
-	skb_shinfo(skb)->frag_list = dev_alloc_skb(dev->mtu + ALIGN_SIZE);
-	if (skb_shinfo(skb)->frag_list == NULL) {
-		nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
-		DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n ", dev->name);
-		return -ENOMEM ;
-	}
-	frag_list = skb_shinfo(skb)->frag_list;
-	skb->truesize += frag_list->truesize;
-	nic->mac_control.stats_info->sw_stat.mem_allocated 
-		+= frag_list->truesize;
-	frag_list->next = NULL;
-	tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1);
-	frag_list->data = tmp;
-	skb_reset_tail_pointer(frag_list);
-
-	/* Buffer-2 receives L4 data payload */
-	((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
-				frag_list->data, dev->mtu,
-				PCI_DMA_FROMDEVICE);
-	rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
-	rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu);
-
-	return SUCCESS;
-}
-
 /**
  *  fill_rx_buffers - Allocates the Rx side skbs
  *  @nic:  device private variable
@@ -2307,6 +2371,9 @@
 	unsigned long flags;
 	struct RxD_t *first_rxdp = NULL;
 	u64 Buffer0_ptr = 0, Buffer1_ptr = 0;
+	struct RxD1 *rxdp1;
+	struct RxD3 *rxdp3;
+	struct swStat *stats = &nic->mac_control.stats_info->sw_stat;
 
 	mac_control = &nic->mac_control;
 	config = &nic->config;
@@ -2359,7 +2426,7 @@
 			(block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
 		}
 		if ((rxdp->Control_1 & RXD_OWN_XENA) &&
-			((nic->rxd_mode >= RXD_MODE_3A) &&
+			((nic->rxd_mode == RXD_MODE_3B) &&
 				(rxdp->Control_2 & BIT(0)))) {
 			mac_control->rings[ring_no].rx_curr_put_info.
 					offset = off;
@@ -2370,10 +2437,8 @@
 				HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
 		if (nic->rxd_mode == RXD_MODE_1)
 			size += NET_IP_ALIGN;
-		else if (nic->rxd_mode == RXD_MODE_3B)
-			size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
 		else
-			size = l3l4hdr_size + ALIGN_SIZE + BUF0_LEN + 4;
+			size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
 
 		/* allocate skb */
 		skb = dev_alloc_skb(size);
@@ -2388,37 +2453,39 @@
 				mem_alloc_fail_cnt++;
 			return -ENOMEM ;
 		}
-		nic->mac_control.stats_info->sw_stat.mem_allocated 
+		nic->mac_control.stats_info->sw_stat.mem_allocated
 			+= skb->truesize;
 		if (nic->rxd_mode == RXD_MODE_1) {
 			/* 1 buffer mode - normal operation mode */
+			rxdp1 = (struct RxD1*)rxdp;
 			memset(rxdp, 0, sizeof(struct RxD1));
 			skb_reserve(skb, NET_IP_ALIGN);
-			((struct RxD1*)rxdp)->Buffer0_ptr = pci_map_single
+			rxdp1->Buffer0_ptr = pci_map_single
 			    (nic->pdev, skb->data, size - NET_IP_ALIGN,
 				PCI_DMA_FROMDEVICE);
-			rxdp->Control_2 = 
+			if( (rxdp1->Buffer0_ptr == 0) ||
+				(rxdp1->Buffer0_ptr ==
+				DMA_ERROR_CODE))
+				goto pci_map_failed;
+
+			rxdp->Control_2 =
 				SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
 
-		} else if (nic->rxd_mode >= RXD_MODE_3A) {
+		} else if (nic->rxd_mode == RXD_MODE_3B) {
 			/*
-			 * 2 or 3 buffer mode -
-			 * Both 2 buffer mode and 3 buffer mode provides 128
+			 * 2 buffer mode -
+			 * 2 buffer mode provides 128
 			 * byte aligned receive buffers.
-			 *
-			 * 3 buffer mode provides header separation where in
-			 * skb->data will have L3/L4 headers where as
-			 * skb_shinfo(skb)->frag_list will have the L4 data
-			 * payload
 			 */
 
+			rxdp3 = (struct RxD3*)rxdp;
 			/* save buffer pointers to avoid frequent dma mapping */
-			Buffer0_ptr = ((struct RxD3*)rxdp)->Buffer0_ptr;
-			Buffer1_ptr = ((struct RxD3*)rxdp)->Buffer1_ptr;
+			Buffer0_ptr = rxdp3->Buffer0_ptr;
+			Buffer1_ptr = rxdp3->Buffer1_ptr;
 			memset(rxdp, 0, sizeof(struct RxD3));
 			/* restore the buffer pointers for dma sync*/
-			((struct RxD3*)rxdp)->Buffer0_ptr = Buffer0_ptr;
-			((struct RxD3*)rxdp)->Buffer1_ptr = Buffer1_ptr;
+			rxdp3->Buffer0_ptr = Buffer0_ptr;
+			rxdp3->Buffer1_ptr = Buffer1_ptr;
 
 			ba = &mac_control->rings[ring_no].ba[block_no][off];
 			skb_reserve(skb, BUF0_LEN);
@@ -2428,14 +2495,18 @@
 			skb->data = (void *) (unsigned long)tmp;
 			skb_reset_tail_pointer(skb);
 
-			if (!(((struct RxD3*)rxdp)->Buffer0_ptr))
-				((struct RxD3*)rxdp)->Buffer0_ptr =
+			if (!(rxdp3->Buffer0_ptr))
+				rxdp3->Buffer0_ptr =
 				   pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
 					   PCI_DMA_FROMDEVICE);
 			else
 				pci_dma_sync_single_for_device(nic->pdev,
-				(dma_addr_t) ((struct RxD3*)rxdp)->Buffer0_ptr,
+				(dma_addr_t) rxdp3->Buffer0_ptr,
 				    BUF0_LEN, PCI_DMA_FROMDEVICE);
+			if( (rxdp3->Buffer0_ptr == 0) ||
+				(rxdp3->Buffer0_ptr == DMA_ERROR_CODE))
+				goto pci_map_failed;
+
 			rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
 			if (nic->rxd_mode == RXD_MODE_3B) {
 				/* Two buffer mode */
@@ -2444,33 +2515,30 @@
 				 * Buffer2 will have L3/L4 header plus
 				 * L4 payload
 				 */
-				((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single
+				rxdp3->Buffer2_ptr = pci_map_single
 				(nic->pdev, skb->data, dev->mtu + 4,
 						PCI_DMA_FROMDEVICE);
 
-				/* Buffer-1 will be dummy buffer. Not used */
-				if (!(((struct RxD3*)rxdp)->Buffer1_ptr)) {
-					((struct RxD3*)rxdp)->Buffer1_ptr =
+				if( (rxdp3->Buffer2_ptr == 0) ||
+					(rxdp3->Buffer2_ptr == DMA_ERROR_CODE))
+					goto pci_map_failed;
+
+				rxdp3->Buffer1_ptr =
 						pci_map_single(nic->pdev,
 						ba->ba_1, BUF1_LEN,
 						PCI_DMA_FROMDEVICE);
+				if( (rxdp3->Buffer1_ptr == 0) ||
+					(rxdp3->Buffer1_ptr == DMA_ERROR_CODE)) {
+					pci_unmap_single
+						(nic->pdev,
+						(dma_addr_t)rxdp3->Buffer2_ptr,
+						dev->mtu + 4,
+						PCI_DMA_FROMDEVICE);
+					goto pci_map_failed;
 				}
 				rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
 				rxdp->Control_2 |= SET_BUFFER2_SIZE_3
 								(dev->mtu + 4);
-			} else {
-				/* 3 buffer mode */
-				if (fill_rxd_3buf(nic, rxdp, skb) == -ENOMEM) {
-					nic->mac_control.stats_info->sw_stat.\
-					mem_freed += skb->truesize;
-					dev_kfree_skb_irq(skb);
-					if (first_rxdp) {
-						wmb();
-						first_rxdp->Control_1 |=
-							RXD_OWN_XENA;
-					}
-					return -ENOMEM ;
-				}
 			}
 			rxdp->Control_2 |= BIT(0);
 		}
@@ -2505,6 +2573,11 @@
 	}
 
 	return SUCCESS;
+pci_map_failed:
+	stats->pci_map_fail_cnt++;
+	stats->mem_freed += skb->truesize;
+	dev_kfree_skb_irq(skb);
+	return -ENOMEM;
 }
 
 static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
@@ -2515,6 +2588,8 @@
 	struct RxD_t *rxdp;
 	struct mac_info *mac_control;
 	struct buffAdd *ba;
+	struct RxD1 *rxdp1;
+	struct RxD3 *rxdp3;
 
 	mac_control = &sp->mac_control;
 	for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) {
@@ -2526,40 +2601,30 @@
 			continue;
 		}
 		if (sp->rxd_mode == RXD_MODE_1) {
+			rxdp1 = (struct RxD1*)rxdp;
 			pci_unmap_single(sp->pdev, (dma_addr_t)
-				 ((struct RxD1*)rxdp)->Buffer0_ptr,
-				 dev->mtu +
-				 HEADER_ETHERNET_II_802_3_SIZE
-				 + HEADER_802_2_SIZE +
-				 HEADER_SNAP_SIZE,
-				 PCI_DMA_FROMDEVICE);
+				rxdp1->Buffer0_ptr,
+				dev->mtu +
+				HEADER_ETHERNET_II_802_3_SIZE
+				+ HEADER_802_2_SIZE +
+				HEADER_SNAP_SIZE,
+				PCI_DMA_FROMDEVICE);
 			memset(rxdp, 0, sizeof(struct RxD1));
 		} else if(sp->rxd_mode == RXD_MODE_3B) {
+			rxdp3 = (struct RxD3*)rxdp;
 			ba = &mac_control->rings[ring_no].
 				ba[blk][j];
 			pci_unmap_single(sp->pdev, (dma_addr_t)
-				 ((struct RxD3*)rxdp)->Buffer0_ptr,
-				 BUF0_LEN,
-				 PCI_DMA_FROMDEVICE);
-			pci_unmap_single(sp->pdev, (dma_addr_t)
-				 ((struct RxD3*)rxdp)->Buffer1_ptr,
-				 BUF1_LEN,
-				 PCI_DMA_FROMDEVICE);
-			pci_unmap_single(sp->pdev, (dma_addr_t)
-				 ((struct RxD3*)rxdp)->Buffer2_ptr,
-				 dev->mtu + 4,
-				 PCI_DMA_FROMDEVICE);
-			memset(rxdp, 0, sizeof(struct RxD3));
-		} else {
-			pci_unmap_single(sp->pdev, (dma_addr_t)
-				((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
+				rxdp3->Buffer0_ptr,
+				BUF0_LEN,
 				PCI_DMA_FROMDEVICE);
 			pci_unmap_single(sp->pdev, (dma_addr_t)
-				((struct RxD3*)rxdp)->Buffer1_ptr,
-				l3l4hdr_size + 4,
+				rxdp3->Buffer1_ptr,
+				BUF1_LEN,
 				PCI_DMA_FROMDEVICE);
 			pci_unmap_single(sp->pdev, (dma_addr_t)
-				((struct RxD3*)rxdp)->Buffer2_ptr, dev->mtu,
+				rxdp3->Buffer2_ptr,
+				dev->mtu + 4,
 				PCI_DMA_FROMDEVICE);
 			memset(rxdp, 0, sizeof(struct RxD3));
 		}
@@ -2604,7 +2669,7 @@
 
 /**
  * s2io_poll - Rx interrupt handler for NAPI support
- * @dev : pointer to the device structure.
+ * @napi : pointer to the napi structure.
  * @budget : The number of packets that were budgeted to be processed
  * during  one pass through the 'Poll" function.
  * Description:
@@ -2615,22 +2680,23 @@
  * 0 on success and 1 if there are No Rx packets to be processed.
  */
 
-static int s2io_poll(struct net_device *dev, int *budget)
+static int s2io_poll(struct napi_struct *napi, int budget)
 {
-	struct s2io_nic *nic = dev->priv;
+	struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi);
+	struct net_device *dev = nic->dev;
 	int pkt_cnt = 0, org_pkts_to_process;
 	struct mac_info *mac_control;
 	struct config_param *config;
 	struct XENA_dev_config __iomem *bar0 = nic->bar0;
 	int i;
 
-	atomic_inc(&nic->isr_cnt);
+	if (!is_s2io_card_up(nic))
+		return 0;
+
 	mac_control = &nic->mac_control;
 	config = &nic->config;
 
-	nic->pkts_to_process = *budget;
-	if (nic->pkts_to_process > dev->quota)
-		nic->pkts_to_process = dev->quota;
+	nic->pkts_to_process = budget;
 	org_pkts_to_process = nic->pkts_to_process;
 
 	writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
@@ -2644,12 +2710,8 @@
 			goto no_rx;
 		}
 	}
-	if (!pkt_cnt)
-		pkt_cnt = 1;
 
-	dev->quota -= pkt_cnt;
-	*budget -= pkt_cnt;
-	netif_rx_complete(dev);
+	netif_rx_complete(dev, napi);
 
 	for (i = 0; i < config->rx_ring_num; i++) {
 		if (fill_rx_buffers(nic, i) == -ENOMEM) {
@@ -2661,13 +2723,9 @@
 	/* Re enable the Rx interrupts. */
 	writeq(0x0, &bar0->rx_traffic_mask);
 	readl(&bar0->rx_traffic_mask);
-	atomic_dec(&nic->isr_cnt);
-	return 0;
+	return pkt_cnt;
 
 no_rx:
-	dev->quota -= pkt_cnt;
-	*budget -= pkt_cnt;
-
 	for (i = 0; i < config->rx_ring_num; i++) {
 		if (fill_rx_buffers(nic, i) == -ENOMEM) {
 			DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
@@ -2675,8 +2733,7 @@
 			break;
 		}
 	}
-	atomic_dec(&nic->isr_cnt);
-	return 1;
+	return pkt_cnt;
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2703,7 +2760,6 @@
 
 	disable_irq(dev->irq);
 
-	atomic_inc(&nic->isr_cnt);
 	mac_control = &nic->mac_control;
 	config = &nic->config;
 
@@ -2728,7 +2784,6 @@
 			break;
 		}
 	}
-	atomic_dec(&nic->isr_cnt);
 	enable_irq(dev->irq);
 	return;
 }
@@ -2756,14 +2811,10 @@
 	struct sk_buff *skb;
 	int pkt_cnt = 0;
 	int i;
+	struct RxD1* rxdp1;
+	struct RxD3* rxdp3;
 
 	spin_lock(&nic->rx_lock);
-	if (atomic_read(&nic->card_state) == CARD_DOWN) {
-		DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n",
-			  __FUNCTION__, dev->name);
-		spin_unlock(&nic->rx_lock);
-		return;
-	}
 
 	get_info = ring_data->rx_curr_get_info;
 	get_block = get_info.block_index;
@@ -2796,32 +2847,23 @@
 			return;
 		}
 		if (nic->rxd_mode == RXD_MODE_1) {
+			rxdp1 = (struct RxD1*)rxdp;
 			pci_unmap_single(nic->pdev, (dma_addr_t)
-				 ((struct RxD1*)rxdp)->Buffer0_ptr,
-				 dev->mtu +
-				 HEADER_ETHERNET_II_802_3_SIZE +
-				 HEADER_802_2_SIZE +
-				 HEADER_SNAP_SIZE,
-				 PCI_DMA_FROMDEVICE);
+				rxdp1->Buffer0_ptr,
+				dev->mtu +
+				HEADER_ETHERNET_II_802_3_SIZE +
+				HEADER_802_2_SIZE +
+				HEADER_SNAP_SIZE,
+				PCI_DMA_FROMDEVICE);
 		} else if (nic->rxd_mode == RXD_MODE_3B) {
+			rxdp3 = (struct RxD3*)rxdp;
 			pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
-				 ((struct RxD3*)rxdp)->Buffer0_ptr,
-				 BUF0_LEN, PCI_DMA_FROMDEVICE);
+				rxdp3->Buffer0_ptr,
+				BUF0_LEN, PCI_DMA_FROMDEVICE);
 			pci_unmap_single(nic->pdev, (dma_addr_t)
-				 ((struct RxD3*)rxdp)->Buffer2_ptr,
-				 dev->mtu + 4,
-				 PCI_DMA_FROMDEVICE);
-		} else {
-			pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
-					 ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
-					 PCI_DMA_FROMDEVICE);
-			pci_unmap_single(nic->pdev, (dma_addr_t)
-					 ((struct RxD3*)rxdp)->Buffer1_ptr,
-					 l3l4hdr_size + 4,
-					 PCI_DMA_FROMDEVICE);
-			pci_unmap_single(nic->pdev, (dma_addr_t)
-					 ((struct RxD3*)rxdp)->Buffer2_ptr,
-					 dev->mtu, PCI_DMA_FROMDEVICE);
+				rxdp3->Buffer2_ptr,
+				dev->mtu + 4,
+				PCI_DMA_FROMDEVICE);
 		}
 		prefetch(skb->data);
 		rx_osm_handler(ring_data, rxdp);
@@ -3207,135 +3249,6 @@
 }
 
 /**
- *  alarm_intr_handler - Alarm Interrrupt handler
- *  @nic: device private variable
- *  Description: If the interrupt was neither because of Rx packet or Tx
- *  complete, this function is called. If the interrupt was to indicate
- *  a loss of link, the OSM link status handler is invoked for any other
- *  alarm interrupt the block that raised the interrupt is displayed
- *  and a H/W reset is issued.
- *  Return Value:
- *  NONE
-*/
-
-static void alarm_intr_handler(struct s2io_nic *nic)
-{
-	struct net_device *dev = (struct net_device *) nic->dev;
-	struct XENA_dev_config __iomem *bar0 = nic->bar0;
-	register u64 val64 = 0, err_reg = 0;
-	u64 cnt;
-	int i;
-	if (atomic_read(&nic->card_state) == CARD_DOWN)
-		return;
-	if (pci_channel_offline(nic->pdev))
-		return;
-	nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
-	/* Handling the XPAK counters update */
-	if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
-		/* waiting for an hour */
-		nic->mac_control.stats_info->xpak_stat.xpak_timer_count++;
-	} else {
-		s2io_updt_xpak_counter(dev);
-		/* reset the count to zero */
-		nic->mac_control.stats_info->xpak_stat.xpak_timer_count = 0;
-	}
-
-	/* Handling link status change error Intr */
-	if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
-		err_reg = readq(&bar0->mac_rmac_err_reg);
-		writeq(err_reg, &bar0->mac_rmac_err_reg);
-		if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
-			schedule_work(&nic->set_link_task);
-		}
-	}
-
-	/* Handling Ecc errors */
-	val64 = readq(&bar0->mc_err_reg);
-	writeq(val64, &bar0->mc_err_reg);
-	if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
-		if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
-			nic->mac_control.stats_info->sw_stat.
-				double_ecc_errs++;
-			DBG_PRINT(INIT_DBG, "%s: Device indicates ",
-				  dev->name);
-			DBG_PRINT(INIT_DBG, "double ECC error!!\n");
-			if (nic->device_type != XFRAME_II_DEVICE) {
-				/* Reset XframeI only if critical error */
-				if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
-					     MC_ERR_REG_MIRI_ECC_DB_ERR_1)) {
-					netif_stop_queue(dev);
-					schedule_work(&nic->rst_timer_task);
-					nic->mac_control.stats_info->sw_stat.
-							soft_reset_cnt++;
-				}
-			}
-		} else {
-			nic->mac_control.stats_info->sw_stat.
-				single_ecc_errs++;
-		}
-	}
-
-	/* In case of a serious error, the device will be Reset. */
-	val64 = readq(&bar0->serr_source);
-	if (val64 & SERR_SOURCE_ANY) {
-		nic->mac_control.stats_info->sw_stat.serious_err_cnt++;
-		DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
-		DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
-			  (unsigned long long)val64);
-		netif_stop_queue(dev);
-		schedule_work(&nic->rst_timer_task);
-		nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
-	}
-
-	/*
-	 * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC
-	 * Error occurs, the adapter will be recycled by disabling the
-	 * adapter enable bit and enabling it again after the device
-	 * becomes Quiescent.
-	 */
-	val64 = readq(&bar0->pcc_err_reg);
-	writeq(val64, &bar0->pcc_err_reg);
-	if (val64 & PCC_FB_ECC_DB_ERR) {
-		u64 ac = readq(&bar0->adapter_control);
-		ac &= ~(ADAPTER_CNTL_EN);
-		writeq(ac, &bar0->adapter_control);
-		ac = readq(&bar0->adapter_control);
-		schedule_work(&nic->set_link_task);
-	}
-	/* Check for data parity error */
-	val64 = readq(&bar0->pic_int_status);
-	if (val64 & PIC_INT_GPIO) {
-		val64 = readq(&bar0->gpio_int_reg);
-		if (val64 & GPIO_INT_REG_DP_ERR_INT) {
-			nic->mac_control.stats_info->sw_stat.parity_err_cnt++;
-			schedule_work(&nic->rst_timer_task);
-			nic->mac_control.stats_info->sw_stat.soft_reset_cnt++;
-		}
-	}
-
-	/* Check for ring full counter */
-	if (nic->device_type & XFRAME_II_DEVICE) {
-		val64 = readq(&bar0->ring_bump_counter1);
-		for (i=0; i<4; i++) {
-			cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
-			cnt >>= 64 - ((i+1)*16);
-			nic->mac_control.stats_info->sw_stat.ring_full_cnt
-				+= cnt;
-		}
-
-		val64 = readq(&bar0->ring_bump_counter2);
-		for (i=0; i<4; i++) {
-			cnt = ( val64 & vBIT(0xFFFF,(i*16),16));
-			cnt >>= 64 - ((i+1)*16);
-			nic->mac_control.stats_info->sw_stat.ring_full_cnt
-				+= cnt;
-		}
-	}
-
-	/* Other type of interrupts are not being handled now,  TODO */
-}
-
-/**
  *  wait_for_cmd_complete - waits for a command to complete.
  *  @sp : private member of the device structure, which is a pointer to the
  *  s2io_nic structure.
@@ -3425,23 +3338,8 @@
 	/* Back up  the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
 	pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
 
-	if (sp->device_type == XFRAME_II_DEVICE) {
-		int ret;
-		ret = pci_set_power_state(sp->pdev, 3);
-		if (!ret)
-			ret = pci_set_power_state(sp->pdev, 0);
-		else {
-			DBG_PRINT(ERR_DBG,"%s PME based SW_Reset failed!\n",
-					__FUNCTION__);
-			goto old_way;
-		}
-		msleep(20);
-		goto new_way;
-	}
-old_way:
 	val64 = SW_RESET_ALL;
 	writeq(val64, &bar0->sw_reset);
-new_way:
 	if (strstr(sp->product_name, "CX4")) {
 		msleep(750);
 	}
@@ -3484,7 +3382,7 @@
 
 	/* Reset device statistics maintained by OS */
 	memset(&sp->stats, 0, sizeof (struct net_device_stats));
-	
+
 	up_cnt = sp->mac_control.stats_info->sw_stat.link_up_cnt;
 	down_cnt = sp->mac_control.stats_info->sw_stat.link_down_cnt;
 	up_time = sp->mac_control.stats_info->sw_stat.link_up_time;
@@ -3526,7 +3424,7 @@
 	}
 
 	/* restore the previously assigned mac address */
-	s2io_set_mac_addr(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr);
+	do_s2io_prog_unicast(sp->dev, (u8 *)&sp->def_mac_addr[0].mac_addr);
 
 	sp->device_enabled_once = FALSE;
 }
@@ -3623,7 +3521,7 @@
 		 SWAPPER_CTRL_RXF_W_FE |
 		 SWAPPER_CTRL_XMSI_FE |
 		 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
-	if (sp->intr_type == INTA)
+	if (sp->config.intr_type == INTA)
 		val64 |= SWAPPER_CTRL_XMSI_SE;
 	writeq(val64, &bar0->swapper_ctrl);
 #else
@@ -3646,7 +3544,7 @@
 		 SWAPPER_CTRL_RXF_W_FE |
 		 SWAPPER_CTRL_XMSI_FE |
 		 SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE);
-	if (sp->intr_type == INTA)
+	if (sp->config.intr_type == INTA)
 		val64 |= SWAPPER_CTRL_XMSI_SE;
 	writeq(val64, &bar0->swapper_ctrl);
 #endif
@@ -3731,56 +3629,6 @@
 	}
 }
 
-int s2io_enable_msi(struct s2io_nic *nic)
-{
-	struct XENA_dev_config __iomem *bar0 = nic->bar0;
-	u16 msi_ctrl, msg_val;
-	struct config_param *config = &nic->config;
-	struct net_device *dev = nic->dev;
-	u64 val64, tx_mat, rx_mat;
-	int i, err;
-
-	val64 = readq(&bar0->pic_control);
-	val64 &= ~BIT(1);
-	writeq(val64, &bar0->pic_control);
-
-	err = pci_enable_msi(nic->pdev);
-	if (err) {
-		DBG_PRINT(ERR_DBG, "%s: enabling MSI failed\n",
-			  nic->dev->name);
-		return err;
-	}
-
-	/*
-	 * Enable MSI and use MSI-1 in stead of the standard MSI-0
-	 * for interrupt handling.
-	 */
-	pci_read_config_word(nic->pdev, 0x4c, &msg_val);
-	msg_val ^= 0x1;
-	pci_write_config_word(nic->pdev, 0x4c, msg_val);
-	pci_read_config_word(nic->pdev, 0x4c, &msg_val);
-
-	pci_read_config_word(nic->pdev, 0x42, &msi_ctrl);
-	msi_ctrl |= 0x10;
-	pci_write_config_word(nic->pdev, 0x42, msi_ctrl);
-
-	/* program MSI-1 into all usable Tx_Mat and Rx_Mat fields */
-	tx_mat = readq(&bar0->tx_mat0_n[0]);
-	for (i=0; i<config->tx_fifo_num; i++) {
-		tx_mat |= TX_MAT_SET(i, 1);
-	}
-	writeq(tx_mat, &bar0->tx_mat0_n[0]);
-
-	rx_mat = readq(&bar0->rx_mat);
-	for (i=0; i<config->rx_ring_num; i++) {
-		rx_mat |= RX_MAT_SET(i, 1);
-	}
-	writeq(rx_mat, &bar0->rx_mat);
-
-	dev->irq = nic->pdev->irq;
-	return 0;
-}
-
 static int s2io_enable_msi_x(struct s2io_nic *nic)
 {
 	struct XENA_dev_config __iomem *bar0 = nic->bar0;
@@ -3788,34 +3636,31 @@
 	u16 msi_control; /* Temp variable */
 	int ret, i, j, msix_indx = 1;
 
-	nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry),
+	nic->entries = kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct msix_entry),
 			       GFP_KERNEL);
-	if (nic->entries == NULL) {
+	if (!nic->entries) {
 		DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", \
 			__FUNCTION__);
 		nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
 		return -ENOMEM;
 	}
-	nic->mac_control.stats_info->sw_stat.mem_allocated 
+	nic->mac_control.stats_info->sw_stat.mem_allocated
 		+= (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
-	memset(nic->entries, 0,MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
 
 	nic->s2io_entries =
-		kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry),
+		kcalloc(MAX_REQUESTED_MSI_X, sizeof(struct s2io_msix_entry),
 				   GFP_KERNEL);
-	if (nic->s2io_entries == NULL) {
-		DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", 
+	if (!nic->s2io_entries) {
+		DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n",
 			__FUNCTION__);
 		nic->mac_control.stats_info->sw_stat.mem_alloc_fail_cnt++;
 		kfree(nic->entries);
-		nic->mac_control.stats_info->sw_stat.mem_freed 
+		nic->mac_control.stats_info->sw_stat.mem_freed
 			+= (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
 		return -ENOMEM;
 	}
-	 nic->mac_control.stats_info->sw_stat.mem_allocated 
+	 nic->mac_control.stats_info->sw_stat.mem_allocated
 		+= (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
-	memset(nic->s2io_entries, 0,
-	       MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
 
 	for (i=0; i< MAX_REQUESTED_MSI_X; i++) {
 		nic->entries[i].entry = i;
@@ -3833,27 +3678,15 @@
 	}
 	writeq(tx_mat, &bar0->tx_mat0_n[0]);
 
-	if (!nic->config.bimodal) {
-		rx_mat = readq(&bar0->rx_mat);
-		for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
-			rx_mat |= RX_MAT_SET(j, msix_indx);
-			nic->s2io_entries[msix_indx].arg 
-				= &nic->mac_control.rings[j];
-			nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
-			nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
-		}
-		writeq(rx_mat, &bar0->rx_mat);
-	} else {
-		tx_mat = readq(&bar0->tx_mat0_n[7]);
-		for (j=0; j<nic->config.rx_ring_num; j++, msix_indx++) {
-			tx_mat |= TX_MAT_SET(i, msix_indx);
-			nic->s2io_entries[msix_indx].arg 
-				= &nic->mac_control.rings[j];
-			nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
-			nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
-		}
-		writeq(tx_mat, &bar0->tx_mat0_n[7]);
+	rx_mat = readq(&bar0->rx_mat);
+	for (j = 0; j < nic->config.rx_ring_num; j++, msix_indx++) {
+		rx_mat |= RX_MAT_SET(j, msix_indx);
+		nic->s2io_entries[msix_indx].arg
+			= &nic->mac_control.rings[j];
+		nic->s2io_entries[msix_indx].type = MSIX_RING_TYPE;
+		nic->s2io_entries[msix_indx].in_use = MSIX_FLG;
 	}
+	writeq(rx_mat, &bar0->rx_mat);
 
 	nic->avail_msix_vectors = 0;
 	ret = pci_enable_msix(nic->pdev, nic->entries, MAX_REQUESTED_MSI_X);
@@ -3865,10 +3698,10 @@
 	if (ret) {
 		DBG_PRINT(ERR_DBG, "%s: Enabling MSIX failed\n", nic->dev->name);
 		kfree(nic->entries);
-		nic->mac_control.stats_info->sw_stat.mem_freed 
+		nic->mac_control.stats_info->sw_stat.mem_freed
 			+= (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
 		kfree(nic->s2io_entries);
-		nic->mac_control.stats_info->sw_stat.mem_freed 
+		nic->mac_control.stats_info->sw_stat.mem_freed
 		+= (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
 		nic->entries = NULL;
 		nic->s2io_entries = NULL;
@@ -3889,6 +3722,59 @@
 	return 0;
 }
 
+/* Handle software interrupt used during MSI(X) test */
+static irqreturn_t __devinit s2io_test_intr(int irq, void *dev_id)
+{
+	struct s2io_nic *sp = dev_id;
+
+	sp->msi_detected = 1;
+	wake_up(&sp->msi_wait);
+
+	return IRQ_HANDLED;
+}
+
+/* Test interrupt path by forcing a a software IRQ */
+static int __devinit s2io_test_msi(struct s2io_nic *sp)
+{
+	struct pci_dev *pdev = sp->pdev;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
+	int err;
+	u64 val64, saved64;
+
+	err = request_irq(sp->entries[1].vector, s2io_test_intr, 0,
+			sp->name, sp);
+	if (err) {
+		DBG_PRINT(ERR_DBG, "%s: PCI %s: cannot assign irq %d\n",
+		       sp->dev->name, pci_name(pdev), pdev->irq);
+		return err;
+	}
+
+	init_waitqueue_head (&sp->msi_wait);
+	sp->msi_detected = 0;
+
+	saved64 = val64 = readq(&bar0->scheduled_int_ctrl);
+	val64 |= SCHED_INT_CTRL_ONE_SHOT;
+	val64 |= SCHED_INT_CTRL_TIMER_EN;
+	val64 |= SCHED_INT_CTRL_INT2MSI(1);
+	writeq(val64, &bar0->scheduled_int_ctrl);
+
+	wait_event_timeout(sp->msi_wait, sp->msi_detected, HZ/10);
+
+	if (!sp->msi_detected) {
+		/* MSI(X) test failed, go back to INTx mode */
+		DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated"
+			"using MSI(X) during test\n", sp->dev->name,
+			pci_name(pdev));
+
+		err = -EOPNOTSUPP;
+	}
+
+	free_irq(sp->entries[1].vector, sp);
+
+	writeq(saved64, &bar0->scheduled_int_ctrl);
+
+	return err;
+}
 /* ********************************************************* *
  * Functions defined below concern the OS part of the driver *
  * ********************************************************* */
@@ -3917,6 +3803,50 @@
 	netif_carrier_off(dev);
 	sp->last_link_state = 0;
 
+	napi_enable(&sp->napi);
+
+	if (sp->config.intr_type == MSI_X) {
+		int ret = s2io_enable_msi_x(sp);
+
+		if (!ret) {
+			u16 msi_control;
+
+			ret = s2io_test_msi(sp);
+
+			/* rollback MSI-X, will re-enable during add_isr() */
+			kfree(sp->entries);
+			sp->mac_control.stats_info->sw_stat.mem_freed +=
+				(MAX_REQUESTED_MSI_X *
+				sizeof(struct msix_entry));
+			kfree(sp->s2io_entries);
+			sp->mac_control.stats_info->sw_stat.mem_freed +=
+				(MAX_REQUESTED_MSI_X *
+				sizeof(struct s2io_msix_entry));
+			sp->entries = NULL;
+			sp->s2io_entries = NULL;
+
+			pci_read_config_word(sp->pdev, 0x42, &msi_control);
+			msi_control &= 0xFFFE; /* Disable MSI */
+			pci_write_config_word(sp->pdev, 0x42, msi_control);
+
+			pci_disable_msix(sp->pdev);
+
+		}
+		if (ret) {
+
+			DBG_PRINT(ERR_DBG,
+			  "%s: MSI-X requested but failed to enable\n",
+			  dev->name);
+			sp->config.intr_type = INTA;
+		}
+	}
+
+	/* NAPI doesn't work well with MSI(X) */
+	 if (sp->config.intr_type != INTA) {
+		if(sp->config.napi)
+			sp->config.napi = 0;
+	}
+
 	/* Initialize H/W and enable interrupts */
 	err = s2io_card_up(sp);
 	if (err) {
@@ -3925,7 +3855,7 @@
 		goto hw_init_failed;
 	}
 
-	if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
+	if (do_s2io_prog_unicast(dev, dev->dev_addr) == FAILURE) {
 		DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
 		s2io_card_down(sp);
 		err = -ENODEV;
@@ -3936,15 +3866,16 @@
 	return 0;
 
 hw_init_failed:
-	if (sp->intr_type == MSI_X) {
+	napi_disable(&sp->napi);
+	if (sp->config.intr_type == MSI_X) {
 		if (sp->entries) {
 			kfree(sp->entries);
-			sp->mac_control.stats_info->sw_stat.mem_freed 
+			sp->mac_control.stats_info->sw_stat.mem_freed
 			+= (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
 		}
 		if (sp->s2io_entries) {
 			kfree(sp->s2io_entries);
-			sp->mac_control.stats_info->sw_stat.mem_freed 
+			sp->mac_control.stats_info->sw_stat.mem_freed
 			+= (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
 		}
 	}
@@ -3969,6 +3900,7 @@
 	struct s2io_nic *sp = dev->priv;
 
 	netif_stop_queue(dev);
+	napi_disable(&sp->napi);
 	/* Reset card, kill tasklet and free Tx and Rx buffers. */
 	s2io_card_down(sp);
 
@@ -4001,6 +3933,7 @@
 	struct mac_info *mac_control;
 	struct config_param *config;
 	int offload_type;
+	struct swStat *stats = &sp->mac_control.stats_info->sw_stat;
 
 	mac_control = &sp->mac_control;
 	config = &sp->config;
@@ -4014,7 +3947,7 @@
 }
 
 	spin_lock_irqsave(&sp->tx_lock, flags);
-	if (atomic_read(&sp->card_state) == CARD_DOWN) {
+	if (!is_s2io_card_up(sp)) {
 		DBG_PRINT(TX_DBG, "%s: Card going down for reset\n",
 			  dev->name);
 		spin_unlock_irqrestore(&sp->tx_lock, flags);
@@ -4085,11 +4018,18 @@
 		txdp->Buffer_Pointer = pci_map_single(sp->pdev,
 					sp->ufo_in_band_v,
 					sizeof(u64), PCI_DMA_TODEVICE);
+		if((txdp->Buffer_Pointer == 0) ||
+			(txdp->Buffer_Pointer == DMA_ERROR_CODE))
+			goto pci_map_failed;
 		txdp++;
 	}
 
 	txdp->Buffer_Pointer = pci_map_single
 	    (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
+	if((txdp->Buffer_Pointer == 0) ||
+		(txdp->Buffer_Pointer == DMA_ERROR_CODE))
+		goto pci_map_failed;
+
 	txdp->Host_Control = (unsigned long) skb;
 	txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
 	if (offload_type == SKB_GSO_UDP)
@@ -4146,14 +4086,22 @@
 	spin_unlock_irqrestore(&sp->tx_lock, flags);
 
 	return 0;
+pci_map_failed:
+	stats->pci_map_fail_cnt++;
+	netif_stop_queue(dev);
+	stats->mem_freed += skb->truesize;
+	dev_kfree_skb(skb);
+	spin_unlock_irqrestore(&sp->tx_lock, flags);
+	return 0;
 }
 
 static void
 s2io_alarm_handle(unsigned long data)
 {
 	struct s2io_nic *sp = (struct s2io_nic *)data;
+	struct net_device *dev = sp->dev;
 
-	alarm_intr_handler(sp);
+	s2io_handle_errors(dev);
 	mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
 }
 
@@ -4186,50 +4134,17 @@
 	return 0;
 }
 
-static irqreturn_t s2io_msi_handle(int irq, void *dev_id)
-{
-	struct net_device *dev = (struct net_device *) dev_id;
-	struct s2io_nic *sp = dev->priv;
-	int i;
-	struct mac_info *mac_control;
-	struct config_param *config;
-
-	atomic_inc(&sp->isr_cnt);
-	mac_control = &sp->mac_control;
-	config = &sp->config;
-	DBG_PRINT(INTR_DBG, "%s: MSI handler\n", __FUNCTION__);
-
-	/* If Intr is because of Rx Traffic */
-	for (i = 0; i < config->rx_ring_num; i++)
-		rx_intr_handler(&mac_control->rings[i]);
-
-	/* If Intr is because of Tx Traffic */
-	for (i = 0; i < config->tx_fifo_num; i++)
-		tx_intr_handler(&mac_control->fifos[i]);
-
-	/*
-	 * If the Rx buffer count is below the panic threshold then
-	 * reallocate the buffers from the interrupt handler itself,
-	 * else schedule a tasklet to reallocate the buffers.
-	 */
-	for (i = 0; i < config->rx_ring_num; i++)
-		s2io_chk_rx_buffers(sp, i);
-
-	atomic_dec(&sp->isr_cnt);
-	return IRQ_HANDLED;
-}
-
 static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
 {
 	struct ring_info *ring = (struct ring_info *)dev_id;
 	struct s2io_nic *sp = ring->nic;
 
-	atomic_inc(&sp->isr_cnt);
+	if (!is_s2io_card_up(sp))
+		return IRQ_HANDLED;
 
 	rx_intr_handler(ring);
 	s2io_chk_rx_buffers(sp, ring->ring_no);
 
-	atomic_dec(&sp->isr_cnt);
 	return IRQ_HANDLED;
 }
 
@@ -4238,9 +4153,10 @@
 	struct fifo_info *fifo = (struct fifo_info *)dev_id;
 	struct s2io_nic *sp = fifo->nic;
 
-	atomic_inc(&sp->isr_cnt);
+	if (!is_s2io_card_up(sp))
+		return IRQ_HANDLED;
+
 	tx_intr_handler(fifo);
-	atomic_dec(&sp->isr_cnt);
 	return IRQ_HANDLED;
 }
 static void s2io_txpic_intr_handle(struct s2io_nic *sp)
@@ -4305,6 +4221,292 @@
 }
 
 /**
+ *  do_s2io_chk_alarm_bit - Check for alarm and incrment the counter
+ *  @value: alarm bits
+ *  @addr: address value
+ *  @cnt: counter variable
+ *  Description: Check for alarm and increment the counter
+ *  Return Value:
+ *  1 - if alarm bit set
+ *  0 - if alarm bit is not set
+ */
+static int do_s2io_chk_alarm_bit(u64 value, void __iomem * addr,
+			  unsigned long long *cnt)
+{
+	u64 val64;
+	val64 = readq(addr);
+	if ( val64 & value ) {
+		writeq(val64, addr);
+		(*cnt)++;
+		return 1;
+	}
+	return 0;
+
+}
+
+/**
+ *  s2io_handle_errors - Xframe error indication handler
+ *  @nic: device private variable
+ *  Description: Handle alarms such as loss of link, single or
+ *  double ECC errors, critical and serious errors.
+ *  Return Value:
+ *  NONE
+ */
+static void s2io_handle_errors(void * dev_id)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+	struct s2io_nic *sp = dev->priv;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
+	u64 temp64 = 0,val64=0;
+	int i = 0;
+
+	struct swStat *sw_stat = &sp->mac_control.stats_info->sw_stat;
+	struct xpakStat *stats = &sp->mac_control.stats_info->xpak_stat;
+
+	if (!is_s2io_card_up(sp))
+		return;
+
+	if (pci_channel_offline(sp->pdev))
+		return;
+
+	memset(&sw_stat->ring_full_cnt, 0,
+		sizeof(sw_stat->ring_full_cnt));
+
+	/* Handling the XPAK counters update */
+	if(stats->xpak_timer_count < 72000) {
+		/* waiting for an hour */
+		stats->xpak_timer_count++;
+	} else {
+		s2io_updt_xpak_counter(dev);
+		/* reset the count to zero */
+		stats->xpak_timer_count = 0;
+	}
+
+	/* Handling link status change error Intr */
+	if (s2io_link_fault_indication(sp) == MAC_RMAC_ERR_TIMER) {
+		val64 = readq(&bar0->mac_rmac_err_reg);
+		writeq(val64, &bar0->mac_rmac_err_reg);
+		if (val64 & RMAC_LINK_STATE_CHANGE_INT)
+			schedule_work(&sp->set_link_task);
+	}
+
+	/* In case of a serious error, the device will be Reset. */
+	if (do_s2io_chk_alarm_bit(SERR_SOURCE_ANY, &bar0->serr_source,
+				&sw_stat->serious_err_cnt))
+		goto reset;
+
+	/* Check for data parity error */
+	if (do_s2io_chk_alarm_bit(GPIO_INT_REG_DP_ERR_INT, &bar0->gpio_int_reg,
+				&sw_stat->parity_err_cnt))
+		goto reset;
+
+	/* Check for ring full counter */
+	if (sp->device_type == XFRAME_II_DEVICE) {
+		val64 = readq(&bar0->ring_bump_counter1);
+		for (i=0; i<4; i++) {
+			temp64 = ( val64 & vBIT(0xFFFF,(i*16),16));
+			temp64 >>= 64 - ((i+1)*16);
+			sw_stat->ring_full_cnt[i] += temp64;
+		}
+
+		val64 = readq(&bar0->ring_bump_counter2);
+		for (i=0; i<4; i++) {
+			temp64 = ( val64 & vBIT(0xFFFF,(i*16),16));
+			temp64 >>= 64 - ((i+1)*16);
+			 sw_stat->ring_full_cnt[i+4] += temp64;
+		}
+	}
+
+	val64 = readq(&bar0->txdma_int_status);
+	/*check for pfc_err*/
+	if (val64 & TXDMA_PFC_INT) {
+		if (do_s2io_chk_alarm_bit(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM|
+				PFC_MISC_0_ERR | PFC_MISC_1_ERR|
+				PFC_PCIX_ERR, &bar0->pfc_err_reg,
+				&sw_stat->pfc_err_cnt))
+			goto reset;
+		do_s2io_chk_alarm_bit(PFC_ECC_SG_ERR, &bar0->pfc_err_reg,
+				&sw_stat->pfc_err_cnt);
+	}
+
+	/*check for tda_err*/
+	if (val64 & TXDMA_TDA_INT) {
+		if(do_s2io_chk_alarm_bit(TDA_Fn_ECC_DB_ERR | TDA_SM0_ERR_ALARM |
+				TDA_SM1_ERR_ALARM, &bar0->tda_err_reg,
+				&sw_stat->tda_err_cnt))
+			goto reset;
+		do_s2io_chk_alarm_bit(TDA_Fn_ECC_SG_ERR | TDA_PCIX_ERR,
+				&bar0->tda_err_reg, &sw_stat->tda_err_cnt);
+	}
+	/*check for pcc_err*/
+	if (val64 & TXDMA_PCC_INT) {
+		if (do_s2io_chk_alarm_bit(PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM
+				| PCC_N_SERR | PCC_6_COF_OV_ERR
+				| PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR
+				| PCC_7_LSO_OV_ERR | PCC_FB_ECC_DB_ERR
+				| PCC_TXB_ECC_DB_ERR, &bar0->pcc_err_reg,
+				&sw_stat->pcc_err_cnt))
+			goto reset;
+		do_s2io_chk_alarm_bit(PCC_FB_ECC_SG_ERR | PCC_TXB_ECC_SG_ERR,
+				&bar0->pcc_err_reg, &sw_stat->pcc_err_cnt);
+	}
+
+	/*check for tti_err*/
+	if (val64 & TXDMA_TTI_INT) {
+		if (do_s2io_chk_alarm_bit(TTI_SM_ERR_ALARM, &bar0->tti_err_reg,
+				&sw_stat->tti_err_cnt))
+			goto reset;
+		do_s2io_chk_alarm_bit(TTI_ECC_SG_ERR | TTI_ECC_DB_ERR,
+				&bar0->tti_err_reg, &sw_stat->tti_err_cnt);
+	}
+
+	/*check for lso_err*/
+	if (val64 & TXDMA_LSO_INT) {
+		if (do_s2io_chk_alarm_bit(LSO6_ABORT | LSO7_ABORT
+				| LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM,
+				&bar0->lso_err_reg, &sw_stat->lso_err_cnt))
+			goto reset;
+		do_s2io_chk_alarm_bit(LSO6_SEND_OFLOW | LSO7_SEND_OFLOW,
+				&bar0->lso_err_reg, &sw_stat->lso_err_cnt);
+	}
+
+	/*check for tpa_err*/
+	if (val64 & TXDMA_TPA_INT) {
+		if (do_s2io_chk_alarm_bit(TPA_SM_ERR_ALARM, &bar0->tpa_err_reg,
+			&sw_stat->tpa_err_cnt))
+			goto reset;
+		do_s2io_chk_alarm_bit(TPA_TX_FRM_DROP, &bar0->tpa_err_reg,
+			&sw_stat->tpa_err_cnt);
+	}
+
+	/*check for sm_err*/
+	if (val64 & TXDMA_SM_INT) {
+		if (do_s2io_chk_alarm_bit(SM_SM_ERR_ALARM, &bar0->sm_err_reg,
+			&sw_stat->sm_err_cnt))
+			goto reset;
+	}
+
+	val64 = readq(&bar0->mac_int_status);
+	if (val64 & MAC_INT_STATUS_TMAC_INT) {
+		if (do_s2io_chk_alarm_bit(TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR,
+				&bar0->mac_tmac_err_reg,
+				&sw_stat->mac_tmac_err_cnt))
+			goto reset;
+		do_s2io_chk_alarm_bit(TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR
+				| TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR,
+				&bar0->mac_tmac_err_reg,
+				&sw_stat->mac_tmac_err_cnt);
+	}
+
+	val64 = readq(&bar0->xgxs_int_status);
+	if (val64 & XGXS_INT_STATUS_TXGXS) {
+		if (do_s2io_chk_alarm_bit(TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR,
+				&bar0->xgxs_txgxs_err_reg,
+				&sw_stat->xgxs_txgxs_err_cnt))
+			goto reset;
+		do_s2io_chk_alarm_bit(TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR,
+				&bar0->xgxs_txgxs_err_reg,
+				&sw_stat->xgxs_txgxs_err_cnt);
+	}
+
+	val64 = readq(&bar0->rxdma_int_status);
+	if (val64 & RXDMA_INT_RC_INT_M) {
+		if (do_s2io_chk_alarm_bit(RC_PRCn_ECC_DB_ERR | RC_FTC_ECC_DB_ERR
+				| RC_PRCn_SM_ERR_ALARM |RC_FTC_SM_ERR_ALARM,
+				&bar0->rc_err_reg, &sw_stat->rc_err_cnt))
+			goto reset;
+		do_s2io_chk_alarm_bit(RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR
+				| RC_RDA_FAIL_WR_Rn, &bar0->rc_err_reg,
+				&sw_stat->rc_err_cnt);
+		if (do_s2io_chk_alarm_bit(PRC_PCI_AB_RD_Rn | PRC_PCI_AB_WR_Rn
+				| PRC_PCI_AB_F_WR_Rn, &bar0->prc_pcix_err_reg,
+				&sw_stat->prc_pcix_err_cnt))
+			goto reset;
+		do_s2io_chk_alarm_bit(PRC_PCI_DP_RD_Rn | PRC_PCI_DP_WR_Rn
+				| PRC_PCI_DP_F_WR_Rn, &bar0->prc_pcix_err_reg,
+				&sw_stat->prc_pcix_err_cnt);
+	}
+
+	if (val64 & RXDMA_INT_RPA_INT_M) {
+		if (do_s2io_chk_alarm_bit(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR,
+				&bar0->rpa_err_reg, &sw_stat->rpa_err_cnt))
+			goto reset;
+		do_s2io_chk_alarm_bit(RPA_ECC_SG_ERR | RPA_ECC_DB_ERR,
+				&bar0->rpa_err_reg, &sw_stat->rpa_err_cnt);
+	}
+
+	if (val64 & RXDMA_INT_RDA_INT_M) {
+		if (do_s2io_chk_alarm_bit(RDA_RXDn_ECC_DB_ERR
+				| RDA_FRM_ECC_DB_N_AERR | RDA_SM1_ERR_ALARM
+				| RDA_SM0_ERR_ALARM | RDA_RXD_ECC_DB_SERR,
+				&bar0->rda_err_reg, &sw_stat->rda_err_cnt))
+			goto reset;
+		do_s2io_chk_alarm_bit(RDA_RXDn_ECC_SG_ERR | RDA_FRM_ECC_SG_ERR
+				| RDA_MISC_ERR | RDA_PCIX_ERR,
+				&bar0->rda_err_reg, &sw_stat->rda_err_cnt);
+	}
+
+	if (val64 & RXDMA_INT_RTI_INT_M) {
+		if (do_s2io_chk_alarm_bit(RTI_SM_ERR_ALARM, &bar0->rti_err_reg,
+				&sw_stat->rti_err_cnt))
+			goto reset;
+		do_s2io_chk_alarm_bit(RTI_ECC_SG_ERR | RTI_ECC_DB_ERR,
+				&bar0->rti_err_reg, &sw_stat->rti_err_cnt);
+	}
+
+	val64 = readq(&bar0->mac_int_status);
+	if (val64 & MAC_INT_STATUS_RMAC_INT) {
+		if (do_s2io_chk_alarm_bit(RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR,
+				&bar0->mac_rmac_err_reg,
+				&sw_stat->mac_rmac_err_cnt))
+			goto reset;
+		do_s2io_chk_alarm_bit(RMAC_UNUSED_INT|RMAC_SINGLE_ECC_ERR|
+				RMAC_DOUBLE_ECC_ERR, &bar0->mac_rmac_err_reg,
+				&sw_stat->mac_rmac_err_cnt);
+	}
+
+	val64 = readq(&bar0->xgxs_int_status);
+	if (val64 & XGXS_INT_STATUS_RXGXS) {
+		if (do_s2io_chk_alarm_bit(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR,
+				&bar0->xgxs_rxgxs_err_reg,
+				&sw_stat->xgxs_rxgxs_err_cnt))
+			goto reset;
+	}
+
+	val64 = readq(&bar0->mc_int_status);
+	if(val64 & MC_INT_STATUS_MC_INT) {
+		if (do_s2io_chk_alarm_bit(MC_ERR_REG_SM_ERR, &bar0->mc_err_reg,
+				&sw_stat->mc_err_cnt))
+			goto reset;
+
+		/* Handling Ecc errors */
+		if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) {
+			writeq(val64, &bar0->mc_err_reg);
+			if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
+				sw_stat->double_ecc_errs++;
+				if (sp->device_type != XFRAME_II_DEVICE) {
+					/*
+					 * Reset XframeI only if critical error
+					 */
+					if (val64 &
+						(MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
+						MC_ERR_REG_MIRI_ECC_DB_ERR_1))
+								goto reset;
+					}
+			} else
+				sw_stat->single_ecc_errs++;
+		}
+	}
+	return;
+
+reset:
+	netif_stop_queue(dev);
+	schedule_work(&sp->rst_timer_task);
+	sw_stat->soft_reset_cnt++;
+	return;
+}
+
+/**
  *  s2io_isr - ISR handler of the device .
  *  @irq: the irq of the device.
  *  @dev_id: a void pointer to the dev structure of the NIC.
@@ -4331,7 +4533,9 @@
 	if (pci_channel_offline(sp->pdev))
 		return IRQ_NONE;
 
-	atomic_inc(&sp->isr_cnt);
+	if (!is_s2io_card_up(sp))
+		return IRQ_NONE;
+
 	mac_control = &sp->mac_control;
 	config = &sp->config;
 
@@ -4341,73 +4545,75 @@
 	 * 1. Rx of packet.
 	 * 2. Tx complete.
 	 * 3. Link down.
-	 * 4. Error in any functional blocks of the NIC.
 	 */
 	reason = readq(&bar0->general_int_status);
 
-	if (!reason) {
-		/* The interrupt was not raised by us. */
-		atomic_dec(&sp->isr_cnt);
-		return IRQ_NONE;
-	}
-	else if (unlikely(reason == S2IO_MINUS_ONE) ) {
-		/* Disable device and get out */
-		atomic_dec(&sp->isr_cnt);
-		return IRQ_NONE;
+	if (unlikely(reason == S2IO_MINUS_ONE) ) {
+		/* Nothing much can be done. Get out */
+		return IRQ_HANDLED;
 	}
 
-	if (napi) {
-		if (reason & GEN_INTR_RXTRAFFIC) {
-			if ( likely ( netif_rx_schedule_prep(dev)) ) {
-				__netif_rx_schedule(dev);
-				writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
+	if (reason & (GEN_INTR_RXTRAFFIC |
+		GEN_INTR_TXTRAFFIC | GEN_INTR_TXPIC))
+	{
+		writeq(S2IO_MINUS_ONE, &bar0->general_int_mask);
+
+		if (config->napi) {
+			if (reason & GEN_INTR_RXTRAFFIC) {
+				if (likely(netif_rx_schedule_prep(dev,
+							&sp->napi))) {
+					__netif_rx_schedule(dev, &sp->napi);
+					writeq(S2IO_MINUS_ONE,
+					       &bar0->rx_traffic_mask);
+				} else
+					writeq(S2IO_MINUS_ONE,
+					       &bar0->rx_traffic_int);
 			}
-			else
+		} else {
+			/*
+			 * rx_traffic_int reg is an R1 register, writing all 1's
+			 * will ensure that the actual interrupt causing bit
+			 * get's cleared and hence a read can be avoided.
+			 */
+			if (reason & GEN_INTR_RXTRAFFIC)
 				writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+
+			for (i = 0; i < config->rx_ring_num; i++)
+				rx_intr_handler(&mac_control->rings[i]);
 		}
-	} else {
+
 		/*
-		 * Rx handler is called by default, without checking for the
-		 * cause of interrupt.
-		 * rx_traffic_int reg is an R1 register, writing all 1's
+		 * tx_traffic_int reg is an R1 register, writing all 1's
 		 * will ensure that the actual interrupt causing bit get's
 		 * cleared and hence a read can be avoided.
 		 */
-		if (reason & GEN_INTR_RXTRAFFIC)
-			writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+		if (reason & GEN_INTR_TXTRAFFIC)
+			writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
 
-		for (i = 0; i < config->rx_ring_num; i++) {
-			rx_intr_handler(&mac_control->rings[i]);
+		for (i = 0; i < config->tx_fifo_num; i++)
+			tx_intr_handler(&mac_control->fifos[i]);
+
+		if (reason & GEN_INTR_TXPIC)
+			s2io_txpic_intr_handle(sp);
+
+		/*
+		 * Reallocate the buffers from the interrupt handler itself.
+		 */
+		if (!config->napi) {
+			for (i = 0; i < config->rx_ring_num; i++)
+				s2io_chk_rx_buffers(sp, i);
 		}
+		writeq(sp->general_int_mask, &bar0->general_int_mask);
+		readl(&bar0->general_int_status);
+
+		return IRQ_HANDLED;
+
+	}
+	else if (!reason) {
+		/* The interrupt was not raised by us */
+		return IRQ_NONE;
 	}
 
-	/*
-	 * tx_traffic_int reg is an R1 register, writing all 1's
-	 * will ensure that the actual interrupt causing bit get's
-	 * cleared and hence a read can be avoided.
-	 */
-	if (reason & GEN_INTR_TXTRAFFIC)
-		writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
-
-	for (i = 0; i < config->tx_fifo_num; i++)
-		tx_intr_handler(&mac_control->fifos[i]);
-
-	if (reason & GEN_INTR_TXPIC)
-		s2io_txpic_intr_handle(sp);
-	/*
-	 * If the Rx buffer count is below the panic threshold then
-	 * reallocate the buffers from the interrupt handler itself,
-	 * else schedule a tasklet to reallocate the buffers.
-	 */
-	if (!napi) {
-		for (i = 0; i < config->rx_ring_num; i++)
-			s2io_chk_rx_buffers(sp, i);
-	}
-
-	writeq(0, &bar0->general_int_mask);
-	readl(&bar0->general_int_status);
-
-	atomic_dec(&sp->isr_cnt);
 	return IRQ_HANDLED;
 }
 
@@ -4420,7 +4626,7 @@
 	u64 val64;
 	int cnt = 0;
 
-	if (atomic_read(&sp->card_state) == CARD_UP) {
+	if (is_s2io_card_up(sp)) {
 		/* Apprx 30us on a 133 MHz bus */
 		val64 = SET_UPDT_CLICKS(10) |
 			STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN;
@@ -4434,7 +4640,7 @@
 			if (cnt == 5)
 				break; /* Updt failed */
 		} while(1);
-	} 
+	}
 }
 
 /**
@@ -4651,8 +4857,48 @@
 	}
 }
 
+/* add unicast MAC address to CAM */
+static int do_s2io_add_unicast(struct s2io_nic *sp, u64 addr, int off)
+{
+	u64 val64;
+	struct XENA_dev_config __iomem *bar0 = sp->bar0;
+
+	writeq(RMAC_ADDR_DATA0_MEM_ADDR(addr),
+		&bar0->rmac_addr_data0_mem);
+
+	val64 =
+		RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
+		RMAC_ADDR_CMD_MEM_OFFSET(off);
+	writeq(val64, &bar0->rmac_addr_cmd_mem);
+
+	/* Wait till command completes */
+	if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
+		RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
+		S2IO_BIT_RESET)) {
+		DBG_PRINT(INFO_DBG, "add_mac_addr failed\n");
+		return FAILURE;
+	}
+	return SUCCESS;
+}
+
 /**
- *  s2io_set_mac_addr - Programs the Xframe mac address
+ * s2io_set_mac_addr driver entry point
+ */
+static int s2io_set_mac_addr(struct net_device *dev, void *p)
+{
+	struct sockaddr *addr = p;
+
+	if (!is_valid_ether_addr(addr->sa_data))
+		return -EINVAL;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	/* store the MAC address in CAM */
+	return (do_s2io_prog_unicast(dev, dev->dev_addr));
+}
+
+/**
+ *  do_s2io_prog_unicast - Programs the Xframe mac address
  *  @dev : pointer to the device structure.
  *  @addr: a uchar pointer to the new mac address which is to be set.
  *  Description : This procedure will program the Xframe to receive
@@ -4660,56 +4906,31 @@
  *  Return value: SUCCESS on success and an appropriate (-)ve integer
  *  as defined in errno.h file on failure.
  */
-
-static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
+static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr)
 {
 	struct s2io_nic *sp = dev->priv;
-	struct XENA_dev_config __iomem *bar0 = sp->bar0;
-	register u64 val64, mac_addr = 0;
+	register u64 mac_addr = 0, perm_addr = 0;
 	int i;
-	u64 old_mac_addr = 0;
 
 	/*
-	 * Set the new MAC address as the new unicast filter and reflect this
-	 * change on the device address registered with the OS. It will be
-	 * at offset 0.
-	 */
+	* Set the new MAC address as the new unicast filter and reflect this
+	* change on the device address registered with the OS. It will be
+	* at offset 0.
+	*/
 	for (i = 0; i < ETH_ALEN; i++) {
 		mac_addr <<= 8;
 		mac_addr |= addr[i];
-		old_mac_addr <<= 8;
-		old_mac_addr |= sp->def_mac_addr[0].mac_addr[i];
+		perm_addr <<= 8;
+		perm_addr |= sp->def_mac_addr[0].mac_addr[i];
 	}
 
-	if(0 == mac_addr)
+	/* check if the dev_addr is different than perm_addr */
+	if (mac_addr == perm_addr)
 		return SUCCESS;
 
 	/* Update the internal structure with this new mac address */
-	if(mac_addr != old_mac_addr) {
-		memset(sp->def_mac_addr[0].mac_addr, 0, sizeof(ETH_ALEN));
-		sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_addr);
-		sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_addr >> 8);
-		sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_addr >> 16);
-		sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_addr >> 24);
-		sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_addr >> 32);
-		sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_addr >> 40);
-	}
-
-	writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr),
-	       &bar0->rmac_addr_data0_mem);
-
-	val64 =
-	    RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
-	    RMAC_ADDR_CMD_MEM_OFFSET(0);
-	writeq(val64, &bar0->rmac_addr_cmd_mem);
-	/* Wait till command completes */
-	if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
-		      RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, S2IO_BIT_RESET)) {
-		DBG_PRINT(ERR_DBG, "%s: set_mac_addr failed\n", dev->name);
-		return FAILURE;
-	}
-
-	return SUCCESS;
+	do_s2io_copy_mac_addr(sp, 0, mac_addr);
+	return (do_s2io_add_unicast(sp, mac_addr, 0));
 }
 
 /**
@@ -4757,7 +4978,9 @@
 	info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
 	info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
 	info->port = PORT_FIBRE;
-	/* info->transceiver?? TODO */
+
+	/* info->transceiver */
+	info->transceiver = XCVR_EXTERNAL;
 
 	if (netif_carrier_ok(sp->dev)) {
 		info->speed = 10000;
@@ -4794,12 +5017,6 @@
 	strncpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info));
 	info->regdump_len = XENA_REG_SPACE;
 	info->eedump_len = XENA_EEPROM_SPACE;
-	info->testinfo_len = S2IO_TEST_LEN;
-
-	if (sp->device_type == XFRAME_I_DEVICE)
-		info->n_stats = XFRAME_I_STAT_LEN;
-	else
-		info->n_stats = XFRAME_II_STAT_LEN;
 }
 
 /**
@@ -4927,19 +5144,17 @@
 		ering->rx_max_pending = MAX_RX_DESC_1;
 	else if (sp->rxd_mode == RXD_MODE_3B)
 		ering->rx_max_pending = MAX_RX_DESC_2;
-	else if (sp->rxd_mode == RXD_MODE_3A)
-		ering->rx_max_pending = MAX_RX_DESC_3;
 
 	ering->tx_max_pending = MAX_TX_DESC;
-	for (i = 0 ; i < sp->config.tx_fifo_num ; i++) {
+	for (i = 0 ; i < sp->config.tx_fifo_num ; i++)
 		tx_desc_count += sp->config.tx_cfg[i].fifo_len;
-	}
+
 	DBG_PRINT(INFO_DBG,"\nmax txds : %d\n",sp->config.max_txds);
 	ering->tx_pending = tx_desc_count;
 	rx_desc_count = 0;
-	for (i = 0 ; i < sp->config.rx_ring_num ; i++) {
+	for (i = 0 ; i < sp->config.rx_ring_num ; i++)
 		rx_desc_count += sp->config.rx_cfg[i].num_rxd;
-	}
+
 	ering->rx_pending = rx_desc_count;
 
 	ering->rx_mini_max_pending = 0;
@@ -5695,7 +5910,7 @@
 				   struct ethtool_stats *estats,
 				   u64 * tmp_stats)
 {
-	int i = 0;
+	int i = 0, k;
 	struct s2io_nic *sp = dev->priv;
 	struct stat_block *stat_info = sp->mac_control.stats_info;
 
@@ -5890,7 +6105,8 @@
 	tmp_stats[i++] = stat_info->sw_stat.serious_err_cnt;
 	tmp_stats[i++] = stat_info->sw_stat.soft_reset_cnt;
 	tmp_stats[i++] = stat_info->sw_stat.fifo_full_cnt;
-	tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt;
+	for (k = 0; k < MAX_RX_RINGS; k++)
+		tmp_stats[i++] = stat_info->sw_stat.ring_full_cnt[k];
 	tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_high;
 	tmp_stats[i++] = stat_info->xpak_stat.alarm_transceiver_temp_low;
 	tmp_stats[i++] = stat_info->xpak_stat.alarm_laser_bias_current_high;
@@ -5923,6 +6139,7 @@
 	else
 		tmp_stats[i++] = 0;
 	tmp_stats[i++] = stat_info->sw_stat.mem_alloc_fail_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.pci_map_fail_cnt;
 	tmp_stats[i++] = stat_info->sw_stat.watchdog_timer_cnt;
 	tmp_stats[i++] = stat_info->sw_stat.mem_allocated;
 	tmp_stats[i++] = stat_info->sw_stat.mem_freed;
@@ -5946,6 +6163,23 @@
 	tmp_stats[i++] = stat_info->sw_stat.rx_buf_size_err_cnt;
 	tmp_stats[i++] = stat_info->sw_stat.rx_rxd_corrupt_cnt;
 	tmp_stats[i++] = stat_info->sw_stat.rx_unkn_err_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.tda_err_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.pfc_err_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.pcc_err_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.tti_err_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.tpa_err_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.sm_err_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.lso_err_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.mac_tmac_err_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.mac_rmac_err_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.xgxs_txgxs_err_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.xgxs_rxgxs_err_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.rc_err_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.prc_pcix_err_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.rpa_err_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.rda_err_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.rti_err_cnt;
+	tmp_stats[i++] = stat_info->sw_stat.mc_err_cnt;
 }
 
 static int s2io_ethtool_get_regs_len(struct net_device *dev)
@@ -5978,9 +6212,25 @@
 	return (XENA_EEPROM_SPACE);
 }
 
-static int s2io_ethtool_self_test_count(struct net_device *dev)
+static int s2io_get_sset_count(struct net_device *dev, int sset)
 {
-	return (S2IO_TEST_LEN);
+	struct s2io_nic *sp = dev->priv;
+
+	switch (sset) {
+	case ETH_SS_TEST:
+		return S2IO_TEST_LEN;
+	case ETH_SS_STATS:
+		switch(sp->device_type) {
+		case XFRAME_I_DEVICE:
+			return XFRAME_I_STAT_LEN;
+		case XFRAME_II_DEVICE:
+			return XFRAME_II_STAT_LEN;
+		default:
+			return 0;
+		}
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void s2io_ethtool_get_strings(struct net_device *dev,
@@ -6007,22 +6257,6 @@
 			sizeof(ethtool_driver_stats_keys));
 	}
 }
-static int s2io_ethtool_get_stats_count(struct net_device *dev)
-{
-	struct s2io_nic *sp = dev->priv;
-	int stat_count = 0;
-	switch(sp->device_type) {
-	case XFRAME_I_DEVICE:
-		stat_count = XFRAME_I_STAT_LEN;
-	break;
-
-	case XFRAME_II_DEVICE:
-		stat_count = XFRAME_II_STAT_LEN;
-	break;
-	}
-
-	return stat_count;
-}
 
 static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
 {
@@ -6063,20 +6297,16 @@
 	.set_pauseparam = s2io_ethtool_setpause_data,
 	.get_rx_csum = s2io_ethtool_get_rx_csum,
 	.set_rx_csum = s2io_ethtool_set_rx_csum,
-	.get_tx_csum = ethtool_op_get_tx_csum,
 	.set_tx_csum = s2io_ethtool_op_set_tx_csum,
-	.get_sg = ethtool_op_get_sg,
 	.set_sg = ethtool_op_set_sg,
 	.get_tso = s2io_ethtool_op_get_tso,
 	.set_tso = s2io_ethtool_op_set_tso,
-	.get_ufo = ethtool_op_get_ufo,
 	.set_ufo = ethtool_op_set_ufo,
-	.self_test_count = s2io_ethtool_self_test_count,
 	.self_test = s2io_ethtool_test,
 	.get_strings = s2io_ethtool_get_strings,
 	.phys_id = s2io_ethtool_idnic,
-	.get_stats_count = s2io_ethtool_get_stats_count,
-	.get_ethtool_stats = s2io_get_ethtool_stats
+	.get_ethtool_stats = s2io_get_ethtool_stats,
+	.get_sset_count = s2io_get_sset_count,
 };
 
 /**
@@ -6199,7 +6429,7 @@
 	if (!netif_running(dev))
 		goto out_unlock;
 
-	if (test_and_set_bit(0, &(nic->link_state))) {
+	if (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(nic->state))) {
 		/* The card is being reset, no point doing anything */
 		goto out_unlock;
 	}
@@ -6237,13 +6467,10 @@
 				netif_stop_queue(dev);
 			}
 		}
-		val64 = readq(&bar0->adapter_status);
-		if (!LINK_IS_UP(val64)) {
-			DBG_PRINT(ERR_DBG, "%s:", dev->name);
-			DBG_PRINT(ERR_DBG, " Link down after enabling ");
-			DBG_PRINT(ERR_DBG, "device \n");
-		} else
-			s2io_link(nic, LINK_UP);
+		val64 = readq(&bar0->adapter_control);
+		val64 |= ADAPTER_LED_ON;
+		writeq(val64, &bar0->adapter_control);
+		s2io_link(nic, LINK_UP);
 	} else {
 		if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
 						      subid)) {
@@ -6252,9 +6479,13 @@
 			writeq(val64, &bar0->gpio_control);
 			val64 = readq(&bar0->gpio_control);
 		}
+		/* turn off LED */
+		val64 = readq(&bar0->adapter_control);
+		val64 = val64 &(~ADAPTER_LED_ON);
+		writeq(val64, &bar0->adapter_control);
 		s2io_link(nic, LINK_DOWN);
 	}
-	clear_bit(0, &(nic->link_state));
+	clear_bit(__S2IO_STATE_LINK_TASK, &(nic->state));
 
 out_unlock:
 	rtnl_unlock();
@@ -6266,9 +6497,10 @@
 				u64 *temp2, int size)
 {
 	struct net_device *dev = sp->dev;
-	struct sk_buff *frag_list;
+	struct swStat *stats = &sp->mac_control.stats_info->sw_stat;
 
 	if ((sp->rxd_mode == RXD_MODE_1) && (rxdp->Host_Control == 0)) {
+		struct RxD1 *rxdp1 = (struct RxD1 *)rxdp;
 		/* allocate skb */
 		if (*skb) {
 			DBG_PRINT(INFO_DBG, "SKB is not NULL\n");
@@ -6277,7 +6509,7 @@
 			 * using same mapped address for the Rxd
 			 * buffer pointer
 			 */
-			((struct RxD1*)rxdp)->Buffer0_ptr = *temp0;
+			rxdp1->Buffer0_ptr = *temp0;
 		} else {
 			*skb = dev_alloc_skb(size);
 			if (!(*skb)) {
@@ -6288,24 +6520,29 @@
 					mem_alloc_fail_cnt++;
 				return -ENOMEM ;
 			}
-			sp->mac_control.stats_info->sw_stat.mem_allocated 
+			sp->mac_control.stats_info->sw_stat.mem_allocated
 				+= (*skb)->truesize;
 			/* storing the mapped addr in a temp variable
 			 * such it will be used for next rxd whose
 			 * Host Control is NULL
 			 */
-			((struct RxD1*)rxdp)->Buffer0_ptr = *temp0 =
+			rxdp1->Buffer0_ptr = *temp0 =
 				pci_map_single( sp->pdev, (*skb)->data,
 					size - NET_IP_ALIGN,
 					PCI_DMA_FROMDEVICE);
+			if( (rxdp1->Buffer0_ptr == 0) ||
+				(rxdp1->Buffer0_ptr == DMA_ERROR_CODE)) {
+				goto memalloc_failed;
+			}
 			rxdp->Host_Control = (unsigned long) (*skb);
 		}
 	} else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
+		struct RxD3 *rxdp3 = (struct RxD3 *)rxdp;
 		/* Two buffer Mode */
 		if (*skb) {
-			((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
-			((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
-			((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
+			rxdp3->Buffer2_ptr = *temp2;
+			rxdp3->Buffer0_ptr = *temp0;
+			rxdp3->Buffer1_ptr = *temp1;
 		} else {
 			*skb = dev_alloc_skb(size);
 			if (!(*skb)) {
@@ -6316,75 +6553,52 @@
 					mem_alloc_fail_cnt++;
 				return -ENOMEM;
 			}
-			sp->mac_control.stats_info->sw_stat.mem_allocated 
+			sp->mac_control.stats_info->sw_stat.mem_allocated
 				+= (*skb)->truesize;
-			((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
+			rxdp3->Buffer2_ptr = *temp2 =
 				pci_map_single(sp->pdev, (*skb)->data,
 					       dev->mtu + 4,
 					       PCI_DMA_FROMDEVICE);
-			((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
+			if( (rxdp3->Buffer2_ptr == 0) ||
+				(rxdp3->Buffer2_ptr == DMA_ERROR_CODE)) {
+				goto memalloc_failed;
+			}
+			rxdp3->Buffer0_ptr = *temp0 =
 				pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
 						PCI_DMA_FROMDEVICE);
+			if( (rxdp3->Buffer0_ptr == 0) ||
+				(rxdp3->Buffer0_ptr == DMA_ERROR_CODE)) {
+				pci_unmap_single (sp->pdev,
+					(dma_addr_t)rxdp3->Buffer2_ptr,
+					dev->mtu + 4, PCI_DMA_FROMDEVICE);
+				goto memalloc_failed;
+			}
 			rxdp->Host_Control = (unsigned long) (*skb);
 
 			/* Buffer-1 will be dummy buffer not used */
-			((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
+			rxdp3->Buffer1_ptr = *temp1 =
 				pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
-					       PCI_DMA_FROMDEVICE);
-		}
-	} else if ((rxdp->Host_Control == 0)) {
-		/* Three buffer mode */
-		if (*skb) {
-			((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
-			((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
-			((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
-		} else {
-			*skb = dev_alloc_skb(size);
-			if (!(*skb)) {
-				DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
-				DBG_PRINT(INFO_DBG, "memory to allocate ");
-				DBG_PRINT(INFO_DBG, "3 buf mode SKBs\n");
-				sp->mac_control.stats_info->sw_stat. \
-					mem_alloc_fail_cnt++;
-				return -ENOMEM;
-			}
-			sp->mac_control.stats_info->sw_stat.mem_allocated 
-				+= (*skb)->truesize;
-			((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
-				pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN,
-					       PCI_DMA_FROMDEVICE);
-			/* Buffer-1 receives L3/L4 headers */
-			((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
-				pci_map_single( sp->pdev, (*skb)->data,
-						l3l4hdr_size + 4,
 						PCI_DMA_FROMDEVICE);
-			/*
-			 * skb_shinfo(skb)->frag_list will have L4
-			 * data payload
-			 */
-			skb_shinfo(*skb)->frag_list = dev_alloc_skb(dev->mtu +
-								   ALIGN_SIZE);
-			if (skb_shinfo(*skb)->frag_list == NULL) {
-				DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb \
-					  failed\n ", dev->name);
-				sp->mac_control.stats_info->sw_stat. \
-					mem_alloc_fail_cnt++;
-				return -ENOMEM ;
+			if( (rxdp3->Buffer1_ptr == 0) ||
+				(rxdp3->Buffer1_ptr == DMA_ERROR_CODE)) {
+				pci_unmap_single (sp->pdev,
+					(dma_addr_t)rxdp3->Buffer0_ptr,
+					BUF0_LEN, PCI_DMA_FROMDEVICE);
+				pci_unmap_single (sp->pdev,
+					(dma_addr_t)rxdp3->Buffer2_ptr,
+					dev->mtu + 4, PCI_DMA_FROMDEVICE);
+				goto memalloc_failed;
 			}
-			frag_list = skb_shinfo(*skb)->frag_list;
-			frag_list->next = NULL;
-			sp->mac_control.stats_info->sw_stat.mem_allocated 
-				+= frag_list->truesize;
-			/*
-			 * Buffer-2 receives L4 data payload
-			 */
-			((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
-				pci_map_single( sp->pdev, frag_list->data,
-						dev->mtu, PCI_DMA_FROMDEVICE);
 		}
 	}
 	return 0;
+	memalloc_failed:
+		stats->pci_map_fail_cnt++;
+		stats->mem_freed += (*skb)->truesize;
+		dev_kfree_skb(*skb);
+		return -ENOMEM;
 }
+
 static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp,
 				int size)
 {
@@ -6395,10 +6609,6 @@
 		rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
 		rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
 		rxdp->Control_2 |= SET_BUFFER2_SIZE_3( dev->mtu + 4);
-	} else {
-		rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
-		rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
-		rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu);
 	}
 }
 
@@ -6420,8 +6630,6 @@
 		size += NET_IP_ALIGN;
 	else if (sp->rxd_mode == RXD_MODE_3B)
 		size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
-	else
-		size = l3l4hdr_size + ALIGN_SIZE + BUF0_LEN + 4;
 
 	for (i = 0; i < config->rx_ring_num; i++) {
 		blk_cnt = config->rx_cfg[i].num_rxd /
@@ -6431,7 +6639,7 @@
 			for (k = 0; k < rxd_count[sp->rxd_mode]; k++) {
 				rxdp = mac_control->rings[i].
 					rx_blocks[j].rxds[k].virt_addr;
-				if(sp->rxd_mode >= RXD_MODE_3A)
+				if(sp->rxd_mode == RXD_MODE_3B)
 					ba = &mac_control->rings[i].ba[j][k];
 				if (set_rxd_buffer_pointer(sp, rxdp, ba,
 						       &skb,(u64 *)&temp0_64,
@@ -6458,30 +6666,18 @@
 	struct net_device *dev = sp->dev;
 	int err = 0;
 
-	if (sp->intr_type == MSI)
-		ret = s2io_enable_msi(sp);
-	else if (sp->intr_type == MSI_X)
+	if (sp->config.intr_type == MSI_X)
 		ret = s2io_enable_msi_x(sp);
 	if (ret) {
 		DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
-		sp->intr_type = INTA;
+		sp->config.intr_type = INTA;
 	}
 
 	/* Store the values of the MSIX table in the struct s2io_nic structure */
 	store_xmsi_data(sp);
 
 	/* After proper initialization of H/W, register ISR */
-	if (sp->intr_type == MSI) {
-		err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
-			IRQF_SHARED, sp->name, dev);
-		if (err) {
-			pci_disable_msi(sp->pdev);
-			DBG_PRINT(ERR_DBG, "%s: MSI registration failed\n",
-				  dev->name);
-			return -1;
-		}
-	}
-	if (sp->intr_type == MSI_X) {
+	if (sp->config.intr_type == MSI_X) {
 		int i, msix_tx_cnt=0,msix_rx_cnt=0;
 
 		for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
@@ -6533,7 +6729,7 @@
 		printk("MSI-X-TX %d entries enabled\n",msix_tx_cnt);
 		printk("MSI-X-RX %d entries enabled\n",msix_rx_cnt);
 	}
-	if (sp->intr_type == INTA) {
+	if (sp->config.intr_type == INTA) {
 		err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
 				sp->name, dev);
 		if (err) {
@@ -6546,10 +6742,10 @@
 }
 static void s2io_rem_isr(struct s2io_nic * sp)
 {
-	int cnt = 0;
 	struct net_device *dev = sp->dev;
+	struct swStat *stats = &sp->mac_control.stats_info->sw_stat;
 
-	if (sp->intr_type == MSI_X) {
+	if (sp->config.intr_type == MSI_X) {
 		int i;
 		u16 msi_control;
 
@@ -6558,32 +6754,28 @@
 			int vector = sp->entries[i].vector;
 			void *arg = sp->s2io_entries[i].arg;
 
+			synchronize_irq(vector);
 			free_irq(vector, arg);
 		}
+
+		kfree(sp->entries);
+		stats->mem_freed +=
+			(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
+		kfree(sp->s2io_entries);
+		stats->mem_freed +=
+			(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
+		sp->entries = NULL;
+		sp->s2io_entries = NULL;
+
 		pci_read_config_word(sp->pdev, 0x42, &msi_control);
 		msi_control &= 0xFFFE; /* Disable MSI */
 		pci_write_config_word(sp->pdev, 0x42, msi_control);
 
 		pci_disable_msix(sp->pdev);
 	} else {
+		synchronize_irq(sp->pdev->irq);
 		free_irq(sp->pdev->irq, dev);
-		if (sp->intr_type == MSI) {
-			u16 val;
-
-			pci_disable_msi(sp->pdev);
-			pci_read_config_word(sp->pdev, 0x4c, &val);
-			val ^= 0x1;
-			pci_write_config_word(sp->pdev, 0x4c, val);
-		}
 	}
-	/* Waiting till all Interrupt handlers are complete */
-	cnt = 0;
-	do {
-		msleep(10);
-		if (!atomic_read(&sp->isr_cnt))
-			break;
-		cnt++;
-	} while(cnt < 5);
 }
 
 static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
@@ -6595,10 +6787,10 @@
 
 	del_timer_sync(&sp->alarm_timer);
 	/* If s2io_set_link task is executing, wait till it completes. */
-	while (test_and_set_bit(0, &(sp->link_state))) {
+	while (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(sp->state))) {
 		msleep(50);
 	}
-	atomic_set(&sp->card_state, CARD_DOWN);
+	clear_bit(__S2IO_STATE_CARD_UP, &sp->state);
 
 	/* disable Tx and Rx traffic on the NIC */
 	if (do_io)
@@ -6649,7 +6841,7 @@
 	free_rx_buffers(sp);
 	spin_unlock_irqrestore(&sp->rx_lock, flags);
 
-	clear_bit(0, &(sp->link_state));
+	clear_bit(__S2IO_STATE_LINK_TASK, &(sp->state));
 }
 
 static void s2io_card_down(struct s2io_nic * sp)
@@ -6720,7 +6912,7 @@
 
 	/* Add interrupt service routine */
 	if (s2io_add_isr(sp) != 0) {
-		if (sp->intr_type == MSI_X)
+		if (sp->config.intr_type == MSI_X)
 			s2io_rem_isr(sp);
 		s2io_reset(sp);
 		free_rx_buffers(sp);
@@ -6733,17 +6925,16 @@
 	tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
 
 	/*  Enable select interrupts */
-	if (sp->intr_type != INTA)
+	en_dis_err_alarms(sp, ENA_ALL_INTRS, ENABLE_INTRS);
+	if (sp->config.intr_type != INTA)
 		en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS);
 	else {
 		interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
-		interruptible |= TX_PIC_INTR | RX_PIC_INTR;
-		interruptible |= TX_MAC_INTR | RX_MAC_INTR;
+		interruptible |= TX_PIC_INTR;
 		en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS);
 	}
 
-
-	atomic_set(&sp->card_state, CARD_UP);
+	set_bit(__S2IO_STATE_CARD_UP, &sp->state);
 	return 0;
 }
 
@@ -6897,7 +7088,7 @@
 			DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%x\n",
 				dev->name, err_mask);
 			sp->stats.rx_crc_errors++;
-			sp->mac_control.stats_info->sw_stat.mem_freed 
+			sp->mac_control.stats_info->sw_stat.mem_freed
 				+= skb->truesize;
 			dev_kfree_skb(skb);
 			atomic_dec(&sp->rx_bufs_left[ring_no]);
@@ -6907,6 +7098,7 @@
 	}
 
 	/* Updating statistics */
+	sp->stats.rx_packets++;
 	rxdp->Host_Control = 0;
 	if (sp->rxd_mode == RXD_MODE_1) {
 		int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
@@ -6914,7 +7106,7 @@
 		sp->stats.rx_bytes += len;
 		skb_put(skb, len);
 
-	} else if (sp->rxd_mode >= RXD_MODE_3A) {
+	} else if (sp->rxd_mode == RXD_MODE_3B) {
 		int get_block = ring_data->rx_curr_get_info.block_index;
 		int get_off = ring_data->rx_curr_get_info.offset;
 		int buf0_len = RXD_GET_BUFFER0_SIZE_3(rxdp->Control_2);
@@ -6924,18 +7116,7 @@
 		struct buffAdd *ba = &ring_data->ba[get_block][get_off];
 		sp->stats.rx_bytes += buf0_len + buf2_len;
 		memcpy(buff, ba->ba_0, buf0_len);
-
-		if (sp->rxd_mode == RXD_MODE_3A) {
-			int buf1_len = RXD_GET_BUFFER1_SIZE_3(rxdp->Control_2);
-
-			skb_put(skb, buf1_len);
-			skb->len += buf2_len;
-			skb->data_len += buf2_len;
-			skb_put(skb_shinfo(skb)->frag_list, buf2_len);
-			sp->stats.rx_bytes += buf1_len;
-
-		} else
-			skb_put(skb, buf2_len);
+		skb_put(skb, buf2_len);
 	}
 
 	if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) ||
@@ -6956,7 +7137,8 @@
 				int ret = 0;
 
 				ret = s2io_club_tcp_session(skb->data, &tcp,
-						&tcp_len, &lro, rxdp, sp);
+							    &tcp_len, &lro,
+							    rxdp, sp);
 				switch (ret) {
 					case 3: /* Begin anew */
 						lro->parent = skb;
@@ -7061,13 +7243,13 @@
 			DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
 			netif_carrier_off(dev);
 			if(sp->mac_control.stats_info->sw_stat.link_up_cnt)
-			sp->mac_control.stats_info->sw_stat.link_up_time = 
+			sp->mac_control.stats_info->sw_stat.link_up_time =
 				jiffies - sp->start_time;
 			sp->mac_control.stats_info->sw_stat.link_down_cnt++;
 		} else {
 			DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name);
 			if (sp->mac_control.stats_info->sw_stat.link_down_cnt)
-			sp->mac_control.stats_info->sw_stat.link_down_time = 
+			sp->mac_control.stats_info->sw_stat.link_down_time =
 				jiffies - sp->start_time;
 			sp->mac_control.stats_info->sw_stat.link_up_cnt++;
 			netif_carrier_on(dev);
@@ -7124,19 +7306,12 @@
 	if (*dev_intr_type != INTA)
 		napi = 0;
 
-#ifndef CONFIG_PCI_MSI
-	if (*dev_intr_type != INTA) {
-		DBG_PRINT(ERR_DBG, "s2io: This kernel does not support"
-			  "MSI/MSI-X. Defaulting to INTA\n");
-		*dev_intr_type = INTA;
-	}
-#else
-	if (*dev_intr_type > MSI_X) {
+	if ((*dev_intr_type != INTA) && (*dev_intr_type != MSI_X)) {
 		DBG_PRINT(ERR_DBG, "s2io: Wrong intr_type requested. "
 			  "Defaulting to INTA\n");
 		*dev_intr_type = INTA;
 	}
-#endif
+
 	if ((*dev_intr_type == MSI_X) &&
 			((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
 			(pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
@@ -7145,10 +7320,10 @@
 		*dev_intr_type = INTA;
 	}
 
-	if (rx_ring_mode > 3) {
+	if ((rx_ring_mode != 1) && (rx_ring_mode != 2)) {
 		DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n");
-		DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n");
-		rx_ring_mode = 3;
+		DBG_PRINT(ERR_DBG, "s2io: Defaulting to 1-buffer mode\n");
+		rx_ring_mode = 1;
 	}
 	return SUCCESS;
 }
@@ -7213,6 +7388,7 @@
 	struct config_param *config;
 	int mode;
 	u8 dev_intr_type = intr_type;
+	DECLARE_MAC_BUF(mac);
 
 	if ((ret = s2io_verify_parm(pdev, &dev_intr_type)))
 		return ret;
@@ -7240,28 +7416,10 @@
 		pci_disable_device(pdev);
 		return -ENOMEM;
 	}
-	if (dev_intr_type != MSI_X) {
-		if (pci_request_regions(pdev, s2io_driver_name)) {
-			DBG_PRINT(ERR_DBG, "Request Regions failed\n");
-			pci_disable_device(pdev);
-			return -ENODEV;
-		}
-	}
-	else {
-		if (!(request_mem_region(pci_resource_start(pdev, 0),
-               	         pci_resource_len(pdev, 0), s2io_driver_name))) {
-			DBG_PRINT(ERR_DBG, "bar0 Request Regions failed\n");
-			pci_disable_device(pdev);
-			return -ENODEV;
-		}
-        	if (!(request_mem_region(pci_resource_start(pdev, 2),
-               	         pci_resource_len(pdev, 2), s2io_driver_name))) {
-			DBG_PRINT(ERR_DBG, "bar1 Request Regions failed\n");
-                	release_mem_region(pci_resource_start(pdev, 0),
-                                   pci_resource_len(pdev, 0));
-			pci_disable_device(pdev);
-			return -ENODEV;
-		}
+	if ((ret = pci_request_regions(pdev, s2io_driver_name))) {
+		DBG_PRINT(ERR_DBG, "%s: Request Regions failed - %x \n", __FUNCTION__, ret);
+		pci_disable_device(pdev);
+		return -ENODEV;
 	}
 
 	dev = alloc_etherdev(sizeof(struct s2io_nic));
@@ -7274,7 +7432,6 @@
 
 	pci_set_master(pdev);
 	pci_set_drvdata(pdev, dev);
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	/*  Private member variable initialized to s2io NIC structure */
@@ -7288,10 +7445,8 @@
 		sp->rxd_mode = RXD_MODE_1;
 	if (rx_ring_mode == 2)
 		sp->rxd_mode = RXD_MODE_3B;
-	if (rx_ring_mode == 3)
-		sp->rxd_mode = RXD_MODE_3A;
 
-	sp->intr_type = dev_intr_type;
+	sp->config.intr_type = dev_intr_type;
 
 	if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) ||
 		(pdev->device == PCI_DEVICE_ID_HERC_UNI))
@@ -7299,7 +7454,7 @@
 	else
 		sp->device_type = XFRAME_I_DEVICE;
 
-	sp->lro = lro;
+	sp->lro = lro_enable;
 
 	/* Initialize some PCI/PCI-X fields of the NIC. */
 	s2io_init_pci(sp);
@@ -7314,6 +7469,8 @@
 	mac_control = &sp->mac_control;
 	config = &sp->config;
 
+	config->napi = napi;
+
 	/* Tx side parameters. */
 	config->tx_fifo_num = tx_fifo_num;
 	for (i = 0; i < MAX_TX_FIFOS; i++) {
@@ -7361,9 +7518,6 @@
 	for (i = 0; i < config->rx_ring_num; i++)
 		atomic_set(&sp->rx_bufs_left[i], 0);
 
-	/* Initialize the number of ISRs currently running */
-	atomic_set(&sp->isr_cnt, 0);
-
 	/*  initialize the shared memory used by the NIC and the host */
 	if (init_shared_mem(sp)) {
 		DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
@@ -7406,6 +7560,7 @@
 	dev->get_stats = &s2io_get_stats;
 	dev->set_multicast_list = &s2io_set_multicast;
 	dev->do_ioctl = &s2io_ioctl;
+	dev->set_mac_address = &s2io_set_mac_addr;
 	dev->change_mtu = &s2io_change_mtu;
 	SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
@@ -7415,8 +7570,7 @@
 	 * will use eth_mac_addr() for  dev->set_mac_address
 	 * mac address will be set every time dev->open() is called
 	 */
-	dev->poll = s2io_poll;
-	dev->weight = 32;
+	netif_napi_add(dev, &sp->napi, s2io_poll, 32);
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = s2io_netpoll;
@@ -7492,7 +7646,10 @@
 	/*  Set the factory defined MAC address initially   */
 	dev->addr_len = ETH_ALEN;
 	memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
+	memcpy(dev->perm_addr, dev->dev_addr, ETH_ALEN);
 
+	 /* Store the values of the MSIX table in the s2io_nic structure */
+	store_xmsi_data(sp);
 	/* reset Nic and bring it to known state */
 	s2io_reset(sp);
 
@@ -7500,9 +7657,8 @@
 	 * Initialize the tasklet status and link state flags
 	 * and the card state parameter
 	 */
-	atomic_set(&(sp->card_state), 0);
 	sp->tasklet_status = 0;
-	sp->link_state = 0;
+	sp->state = 0;
 
 	/* Initialize spinlocks */
 	spin_lock_init(&sp->tx_lock);
@@ -7538,14 +7694,8 @@
 		  sp->product_name, pdev->revision);
 	DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
 		  s2io_driver_version);
-	DBG_PRINT(ERR_DBG, "%s: MAC ADDR: "
-			  "%02x:%02x:%02x:%02x:%02x:%02x", dev->name,
-			  sp->def_mac_addr[0].mac_addr[0],
-			  sp->def_mac_addr[0].mac_addr[1],
-			  sp->def_mac_addr[0].mac_addr[2],
-			  sp->def_mac_addr[0].mac_addr[3],
-			  sp->def_mac_addr[0].mac_addr[4],
-			  sp->def_mac_addr[0].mac_addr[5]);
+	DBG_PRINT(ERR_DBG, "%s: MAC ADDR: %s\n",
+		  dev->name, print_mac(mac, dev->dev_addr));
 	DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num);
 	if (sp->device_type & XFRAME_II_DEVICE) {
 		mode = s2io_print_pci_mode(sp);
@@ -7565,21 +7715,14 @@
 		    DBG_PRINT(ERR_DBG, "%s: 2-Buffer receive mode enabled\n",
 						dev->name);
 		    break;
-		case RXD_MODE_3A:
-		    DBG_PRINT(ERR_DBG, "%s: 3-Buffer receive mode enabled\n",
-						dev->name);
-		    break;
 	}
 
 	if (napi)
 		DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
-	switch(sp->intr_type) {
+	switch(sp->config.intr_type) {
 		case INTA:
 		    DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
 		    break;
-		case MSI:
-		    DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI\n", dev->name);
-		    break;
 		case MSI_X:
 		    DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name);
 		    break;
@@ -7593,14 +7736,6 @@
 	/* Initialize device name */
 	sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
 
-	/* Initialize bimodal Interrupts */
-	sp->config.bimodal = bimodal;
-	if (!(sp->device_type & XFRAME_II_DEVICE) && bimodal) {
-		sp->config.bimodal = 0;
-		DBG_PRINT(ERR_DBG,"%s:Bimodal intr not supported by Xframe I\n",
-			dev->name);
-	}
-
 	/*
 	 * Make Link state as off at this point, when the Link change
 	 * interrupt comes the state will be automatically changed to
@@ -7619,14 +7754,7 @@
       mem_alloc_failed:
 	free_shared_mem(sp);
 	pci_disable_device(pdev);
-	if (dev_intr_type != MSI_X)
-		pci_release_regions(pdev);
-	else {
-		release_mem_region(pci_resource_start(pdev, 0),
-			pci_resource_len(pdev, 0));
-		release_mem_region(pci_resource_start(pdev, 2),
-			pci_resource_len(pdev, 2));
-	}
+	pci_release_regions(pdev);
 	pci_set_drvdata(pdev, NULL);
 	free_netdev(dev);
 
@@ -7661,14 +7789,7 @@
 	free_shared_mem(sp);
 	iounmap(sp->bar0);
 	iounmap(sp->bar1);
-	if (sp->intr_type != MSI_X)
-		pci_release_regions(pdev);
-	else {
-		release_mem_region(pci_resource_start(pdev, 0),
-			pci_resource_len(pdev, 0));
-		release_mem_region(pci_resource_start(pdev, 2),
-			pci_resource_len(pdev, 2));
-	}
+	pci_release_regions(pdev);
 	pci_set_drvdata(pdev, NULL);
 	free_netdev(dev);
 	pci_disable_device(pdev);
@@ -7680,7 +7801,7 @@
  * the module loadable parameters and initializes PCI configuration space.
  */
 
-int __init s2io_starter(void)
+static int __init s2io_starter(void)
 {
 	return pci_register_driver(&s2io_driver);
 }
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 3887fe6..f6b4556 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -74,6 +74,10 @@
 /* DEBUG message print. */
 #define DBG_PRINT(dbg_level, args...)  if(!(debug_level<dbg_level)) printk(args)
 
+#ifndef DMA_ERROR_CODE
+#define DMA_ERROR_CODE          (~(dma_addr_t)0x0)
+#endif
+
 /* Protocol assist features of the NIC */
 #define L3_CKSUM_OK 0xFFFF
 #define L4_CKSUM_OK 0xFFFF
@@ -87,7 +91,7 @@
 	unsigned long long serious_err_cnt;
 	unsigned long long soft_reset_cnt;
 	unsigned long long fifo_full_cnt;
-	unsigned long long ring_full_cnt;
+	unsigned long long ring_full_cnt[8];
 	/* LRO statistics */
 	unsigned long long clubbed_frms_cnt;
 	unsigned long long sending_both;
@@ -97,6 +101,7 @@
 	unsigned long long num_aggregations;
 	/* Other statistics */
 	unsigned long long mem_alloc_fail_cnt;
+	unsigned long long pci_map_fail_cnt;
 	unsigned long long watchdog_timer_cnt;
 	unsigned long long mem_allocated;
 	unsigned long long mem_freed;
@@ -121,6 +126,26 @@
 	unsigned long long rx_buf_size_err_cnt;
 	unsigned long long rx_rxd_corrupt_cnt;
 	unsigned long long rx_unkn_err_cnt;
+
+	/* Error/alarm statistics*/
+	unsigned long long tda_err_cnt;
+	unsigned long long pfc_err_cnt;
+	unsigned long long pcc_err_cnt;
+	unsigned long long tti_err_cnt;
+	unsigned long long lso_err_cnt;
+	unsigned long long tpa_err_cnt;
+	unsigned long long sm_err_cnt;
+	unsigned long long mac_tmac_err_cnt;
+	unsigned long long mac_rmac_err_cnt;
+	unsigned long long xgxs_txgxs_err_cnt;
+	unsigned long long xgxs_rxgxs_err_cnt;
+	unsigned long long rc_err_cnt;
+	unsigned long long prc_pcix_err_cnt;
+	unsigned long long rpa_err_cnt;
+	unsigned long long rda_err_cnt;
+	unsigned long long rti_err_cnt;
+	unsigned long long mc_err_cnt;
+
 };
 
 /* Xpak releated alarm and warnings */
@@ -407,6 +432,11 @@
 	struct tx_fifo_config tx_cfg[MAX_TX_FIFOS];	/*Per-Tx FIFO config */
 	u32 max_txds;		/*Max no. of Tx buffer descriptor per TxDL */
 	u64 tx_intr_type;
+#define INTA	0
+#define MSI_X	2
+	u8 intr_type;
+	u8 napi;
+
 	/* Specifies if Tx Intr is UTILZ or PER_LIST type. */
 
 /* Rx Side */
@@ -414,7 +444,6 @@
 #define MAX_RX_BLOCKS_PER_RING  150
 
 	struct rx_ring_config rx_cfg[MAX_RX_RINGS];	/*Per-Rx Ring config */
-	u8 bimodal;		/*Flag for setting bimodal interrupts*/
 
 #define HEADER_ETHERNET_II_802_3_SIZE 14
 #define HEADER_802_2_SIZE              3
@@ -575,8 +604,7 @@
 #define SIZE_OF_BLOCK	4096
 
 #define RXD_MODE_1	0 /* One Buffer mode */
-#define RXD_MODE_3A	1 /* Three Buffer mode */
-#define RXD_MODE_3B	2 /* Two Buffer mode */
+#define RXD_MODE_3B	1 /* Two Buffer mode */
 
 /* Structure to hold virtual addresses of Buf0 and Buf1 in
  * 2buf mode. */
@@ -773,6 +801,13 @@
 	u8		saw_ts;
 };
 
+/* These flags represent the devices temporary state */
+enum s2io_device_state_t
+{
+	__S2IO_STATE_LINK_TASK=0,
+	__S2IO_STATE_CARD_UP
+};
+
 /* Structure representing one instance of the NIC */
 struct s2io_nic {
 	int rxd_mode;
@@ -782,6 +817,7 @@
 	 */
 	int pkts_to_process;
 	struct net_device *dev;
+	struct napi_struct napi;
 	struct mac_info mac_control;
 	struct config_param config;
 	struct pci_dev *pdev;
@@ -850,13 +886,11 @@
 
 	int task_flag;
 	unsigned long long start_time;
-#define CARD_DOWN 1
-#define CARD_UP 2
-	atomic_t card_state;
-	volatile unsigned long link_state;
 	struct vlan_group *vlgrp;
 #define MSIX_FLG                0xA5
 	struct msix_entry *entries;
+	int msi_detected;
+	wait_queue_head_t msi_wait;
 	struct s2io_msix_entry *s2io_entries;
 	char desc[MAX_REQUESTED_MSI_X][25];
 
@@ -874,14 +908,9 @@
 	unsigned long	sending_both;
 	u8		lro;
 	u16		lro_max_aggr_per_sess;
-
-#define INTA	0
-#define MSI	1
-#define MSI_X	2
-	u8 intr_type;
-
+	volatile unsigned long state;
 	spinlock_t	rx_lock;
-	atomic_t	isr_cnt;
+	u64		general_int_mask;
 	u64 *ufo_in_band_v;
 #define VPD_STRING_LEN 80
 	u8  product_name[VPD_STRING_LEN];
@@ -1006,7 +1035,7 @@
 static int init_nic(struct s2io_nic *nic);
 static void rx_intr_handler(struct ring_info *ring_data);
 static void tx_intr_handler(struct fifo_info *fifo_data);
-static void alarm_intr_handler(struct s2io_nic *sp);
+static void s2io_handle_errors(void * dev_id);
 
 static int s2io_starter(void);
 static void s2io_closer(void);
@@ -1016,12 +1045,10 @@
 static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp);
 static void s2io_link(struct s2io_nic * sp, int link);
 static void s2io_reset(struct s2io_nic * sp);
-static int s2io_poll(struct net_device *dev, int *budget);
+static int s2io_poll(struct napi_struct *napi, int budget);
 static void s2io_init_pci(struct s2io_nic * sp);
-static int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
+static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr);
 static void s2io_alarm_handle(unsigned long data);
-static int s2io_enable_msi(struct s2io_nic *nic);
-static irqreturn_t s2io_msi_handle(int irq, void *dev_id);
 static irqreturn_t
 s2io_msix_ring_handle(int irq, void *dev_id);
 static irqreturn_t
diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c
index 451486b..14361e8 100644
--- a/drivers/net/saa9730.c
+++ b/drivers/net/saa9730.c
@@ -151,30 +151,30 @@
 		printk("lp->lan_saa9730_regs->CamData = %x\n",
 		       readl(&lp->lan_saa9730_regs->CamData));
 	}
-	printk("lp->stats.tx_packets = %lx\n", lp->stats.tx_packets);
-	printk("lp->stats.tx_errors = %lx\n", lp->stats.tx_errors);
-	printk("lp->stats.tx_aborted_errors = %lx\n",
-	       lp->stats.tx_aborted_errors);
-	printk("lp->stats.tx_window_errors = %lx\n",
-	       lp->stats.tx_window_errors);
-	printk("lp->stats.tx_carrier_errors = %lx\n",
-	       lp->stats.tx_carrier_errors);
-	printk("lp->stats.tx_fifo_errors = %lx\n",
-	       lp->stats.tx_fifo_errors);
-	printk("lp->stats.tx_heartbeat_errors = %lx\n",
-	       lp->stats.tx_heartbeat_errors);
-	printk("lp->stats.collisions = %lx\n", lp->stats.collisions);
+	printk("dev->stats.tx_packets = %lx\n", dev->stats.tx_packets);
+	printk("dev->stats.tx_errors = %lx\n", dev->stats.tx_errors);
+	printk("dev->stats.tx_aborted_errors = %lx\n",
+	       dev->stats.tx_aborted_errors);
+	printk("dev->stats.tx_window_errors = %lx\n",
+	       dev->stats.tx_window_errors);
+	printk("dev->stats.tx_carrier_errors = %lx\n",
+	       dev->stats.tx_carrier_errors);
+	printk("dev->stats.tx_fifo_errors = %lx\n",
+	       dev->stats.tx_fifo_errors);
+	printk("dev->stats.tx_heartbeat_errors = %lx\n",
+	       dev->stats.tx_heartbeat_errors);
+	printk("dev->stats.collisions = %lx\n", dev->stats.collisions);
 
-	printk("lp->stats.rx_packets = %lx\n", lp->stats.rx_packets);
-	printk("lp->stats.rx_errors = %lx\n", lp->stats.rx_errors);
-	printk("lp->stats.rx_dropped = %lx\n", lp->stats.rx_dropped);
-	printk("lp->stats.rx_crc_errors = %lx\n", lp->stats.rx_crc_errors);
-	printk("lp->stats.rx_frame_errors = %lx\n",
-	       lp->stats.rx_frame_errors);
-	printk("lp->stats.rx_fifo_errors = %lx\n",
-	       lp->stats.rx_fifo_errors);
-	printk("lp->stats.rx_length_errors = %lx\n",
-	       lp->stats.rx_length_errors);
+	printk("dev->stats.rx_packets = %lx\n", dev->stats.rx_packets);
+	printk("dev->stats.rx_errors = %lx\n", dev->stats.rx_errors);
+	printk("dev->stats.rx_dropped = %lx\n", dev->stats.rx_dropped);
+	printk("dev->stats.rx_crc_errors = %lx\n", dev->stats.rx_crc_errors);
+	printk("dev->stats.rx_frame_errors = %lx\n",
+	       dev->stats.rx_frame_errors);
+	printk("dev->stats.rx_fifo_errors = %lx\n",
+	       dev->stats.rx_fifo_errors);
+	printk("dev->stats.rx_length_errors = %lx\n",
+	       dev->stats.rx_length_errors);
 
 	printk("lp->lan_saa9730_regs->DebugPCIMasterAddr = %x\n",
 	       readl(&lp->lan_saa9730_regs->DebugPCIMasterAddr));
@@ -605,24 +605,24 @@
 				printk("lan_saa9730_tx: tx error = %x\n",
 				       tx_status);
 
-			lp->stats.tx_errors++;
+			dev->stats.tx_errors++;
 			if (tx_status &
 			    (TX_STATUS_EX_COLL << TX_STAT_CTL_STATUS_SHF))
-				lp->stats.tx_aborted_errors++;
+				dev->stats.tx_aborted_errors++;
 			if (tx_status &
 			    (TX_STATUS_LATE_COLL << TX_STAT_CTL_STATUS_SHF))
-				lp->stats.tx_window_errors++;
+				dev->stats.tx_window_errors++;
 			if (tx_status &
 			    (TX_STATUS_L_CARR << TX_STAT_CTL_STATUS_SHF))
-				lp->stats.tx_carrier_errors++;
+				dev->stats.tx_carrier_errors++;
 			if (tx_status &
 			    (TX_STATUS_UNDER << TX_STAT_CTL_STATUS_SHF))
-				lp->stats.tx_fifo_errors++;
+				dev->stats.tx_fifo_errors++;
 			if (tx_status &
 			    (TX_STATUS_SQ_ERR << TX_STAT_CTL_STATUS_SHF))
-				lp->stats.tx_heartbeat_errors++;
+				dev->stats.tx_heartbeat_errors++;
 
-			lp->stats.collisions +=
+			dev->stats.collisions +=
 				tx_status & TX_STATUS_TX_COLL_MSK;
 		}
 
@@ -684,10 +684,10 @@
 				printk
 				    ("%s: Memory squeeze, deferring packet.\n",
 				     dev->name);
-				lp->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 			} else {
-				lp->stats.rx_bytes += len;
-				lp->stats.rx_packets++;
+				dev->stats.rx_bytes += len;
+				dev->stats.rx_packets++;
 				skb_reserve(skb, 2);	/* 16 byte align */
 				skb_put(skb, len);	/* make room */
 				skb_copy_to_linear_data(skb,
@@ -704,19 +704,19 @@
 				    ("lan_saa9730_rx: We got an error packet = %x\n",
 				     rx_status);
 
-			lp->stats.rx_errors++;
+			dev->stats.rx_errors++;
 			if (rx_status &
 			    (RX_STATUS_CRC_ERR << RX_STAT_CTL_STATUS_SHF))
-				lp->stats.rx_crc_errors++;
+				dev->stats.rx_crc_errors++;
 			if (rx_status &
 			    (RX_STATUS_ALIGN_ERR << RX_STAT_CTL_STATUS_SHF))
-				lp->stats.rx_frame_errors++;
+				dev->stats.rx_frame_errors++;
 			if (rx_status &
 			    (RX_STATUS_OVERFLOW << RX_STAT_CTL_STATUS_SHF))
-				lp->stats.rx_fifo_errors++;
+				dev->stats.rx_fifo_errors++;
 			if (rx_status &
 			    (RX_STATUS_LONG_ERR << RX_STAT_CTL_STATUS_SHF))
-				lp->stats.rx_length_errors++;
+				dev->stats.rx_length_errors++;
 		}
 
 		/* Indicate we have processed the buffer. */
@@ -853,7 +853,7 @@
 	struct lan_saa9730_private *lp = netdev_priv(dev);
 
 	/* Transmitter timeout, serious problems */
-	lp->stats.tx_errors++;
+	dev->stats.tx_errors++;
 	printk("%s: transmit timed out, reset\n", dev->name);
 	/*show_saa9730_regs(lp); */
 	lan_saa9730_restart(lp);
@@ -886,8 +886,8 @@
 		return -1;
 	}
 
-	lp->stats.tx_bytes += len;
-	lp->stats.tx_packets++;
+	dev->stats.tx_bytes += len;
+	dev->stats.tx_packets++;
 
 	dev->trans_start = jiffies;
 	netif_wake_queue(dev);
@@ -919,14 +919,6 @@
 	return 0;
 }
 
-static struct net_device_stats *lan_saa9730_get_stats(struct net_device
-						      *dev)
-{
-	struct lan_saa9730_private *lp = netdev_priv(dev);
-
-	return &lp->stats;
-}
-
 static void lan_saa9730_set_multicast(struct net_device *dev)
 {
 	struct lan_saa9730_private *lp = netdev_priv(dev);
@@ -940,15 +932,14 @@
 		       CAM_CONTROL_GROUP_ACC | CAM_CONTROL_BROAD_ACC,
 		       &lp->lan_saa9730_regs->CamCtl);
 	} else {
-		if (dev->flags & IFF_ALLMULTI) {
+		if (dev->flags & IFF_ALLMULTI || dev->mc_count) {
 			/* accept all multicast packets */
-			writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC |
-			       CAM_CONTROL_BROAD_ACC,
-			       &lp->lan_saa9730_regs->CamCtl);
-		} else {
 			/*
 			 * Will handle the multicast stuff later. -carstenl
 			 */
+			writel(CAM_CONTROL_COMP_EN | CAM_CONTROL_GROUP_ACC |
+			       CAM_CONTROL_BROAD_ACC,
+			       &lp->lan_saa9730_regs->CamCtl);
 		}
 	}
 
@@ -1041,7 +1032,6 @@
 	dev->open = lan_saa9730_open;
 	dev->hard_start_xmit = lan_saa9730_start_xmit;
 	dev->stop = lan_saa9730_close;
-	dev->get_stats = lan_saa9730_get_stats;
 	dev->set_multicast_list = lan_saa9730_set_multicast;
 	dev->tx_timeout = lan_saa9730_tx_timeout;
 	dev->watchdog_timeo = (HZ >> 1);
diff --git a/drivers/net/saa9730.h b/drivers/net/saa9730.h
index f656f2f..010a120 100644
--- a/drivers/net/saa9730.h
+++ b/drivers/net/saa9730.h
@@ -378,7 +378,6 @@
 
 	unsigned char PhysicalAddress[LAN_SAA9730_CAM_ENTRIES][6];
 
-	struct net_device_stats stats;
 	spinlock_t lock;
 };
 
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index 1de3eec..487f9d2 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -76,7 +76,6 @@
 	unsigned char rx_session_id[NPIDS];
 	unsigned char rx_frame_id[NPIDS];
 	unsigned char rx_pkt_type[NPIDS];
-	struct net_device_stats stats;
 };
 
 /* prototypes for Linux interface */
@@ -85,7 +84,6 @@
 static int sb1000_dev_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd);
 static int sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t sb1000_interrupt(int irq, void *dev_id);
-static struct net_device_stats *sb1000_stats(struct net_device *dev);
 static int sb1000_close(struct net_device *dev);
 
 
@@ -189,7 +187,6 @@
 	 */
 	dev->flags = IFF_POINTOPOINT|IFF_NOARP;
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	if (sb1000_debug > 0)
@@ -200,7 +197,6 @@
 	dev->do_ioctl		= sb1000_dev_ioctl;
 	dev->hard_start_xmit	= sb1000_start_xmit;
 	dev->stop		= sb1000_close;
-	dev->get_stats		= sb1000_stats;
 
 	/* hardware address is 0:0:serial_number */
 	dev->dev_addr[2]	= serial_number >> 24 & 0xff;
@@ -740,7 +736,7 @@
 	unsigned int skbsize;
 	struct sk_buff *skb;
 	struct sb1000_private *lp = netdev_priv(dev);
-	struct net_device_stats *stats = &lp->stats;
+	struct net_device_stats *stats = &dev->stats;
 
 	/* SB1000 frame constants */
 	const int FrameSize = FRAMESIZE;
@@ -1003,11 +999,11 @@
 
 	switch (cmd) {
 	case SIOCGCMSTATS:		/* get statistics */
-		stats[0] = lp->stats.rx_bytes;
+		stats[0] = dev->stats.rx_bytes;
 		stats[1] = lp->rx_frames;
-		stats[2] = lp->stats.rx_packets;
-		stats[3] = lp->stats.rx_errors;
-		stats[4] = lp->stats.rx_dropped;
+		stats[2] = dev->stats.rx_packets;
+		stats[3] = dev->stats.rx_errors;
+		stats[4] = dev->stats.rx_dropped;
 		if(copy_to_user(ifr->ifr_data, stats, sizeof(stats)))
 			return -EFAULT;
 		status = 0;
@@ -1133,12 +1129,6 @@
 	return IRQ_HANDLED;
 }
 
-static struct net_device_stats *sb1000_stats(struct net_device *dev)
-{
-	struct sb1000_private *lp = netdev_priv(dev);
-	return &lp->stats;
-}
-
 static int sb1000_close(struct net_device *dev)
 {
 	int i;
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index e7fdcf1..7b53d65 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2001,2002,2003,2004 Broadcom Corporation
+ * Copyright (c) 2006, 2007  Maciej W. Rozycki
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -18,7 +19,12 @@
  *
  * This driver is designed for the Broadcom SiByte SOC built-in
  * Ethernet controllers. Written by Mitch Lichtenberg at Broadcom Corp.
+ *
+ * Updated to the driver model and the PHY abstraction layer
+ * by Maciej W. Rozycki.
  */
+
+#include <linux/bug.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -32,9 +38,15 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/bitops.h>
-#include <asm/processor.h>		/* Processor type for cache alignment. */
-#include <asm/io.h>
+#include <linux/err.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/platform_device.h>
+
 #include <asm/cache.h>
+#include <asm/io.h>
+#include <asm/processor.h>	/* Processor type for cache alignment. */
 
 /* This is only here until the firmware is ready.  In that case,
    the firmware leaves the ethernet address in the register for us. */
@@ -48,7 +60,7 @@
 
 /* These identify the driver base version and may not be removed. */
 #if 0
-static char version1[] __devinitdata =
+static char version1[] __initdata =
 "sb1250-mac.c:1.00 1/11/2001 Written by Mitch Lichtenberg\n";
 #endif
 
@@ -57,8 +69,6 @@
 
 #define CONFIG_SBMAC_COALESCE
 
-#define MAX_UNITS 4		/* More are supported, limit only on options */
-
 /* Time in jiffies before concluding the transmitter is hung. */
 #define TX_TIMEOUT  (2*HZ)
 
@@ -74,26 +84,6 @@
 module_param(debug, int, S_IRUGO);
 MODULE_PARM_DESC(debug, "Debug messages");
 
-/* mii status msgs */
-static int noisy_mii = 1;
-module_param(noisy_mii, int, S_IRUGO);
-MODULE_PARM_DESC(noisy_mii, "MII status messages");
-
-/* Used to pass the media type, etc.
-   Both 'options[]' and 'full_duplex[]' should exist for driver
-   interoperability.
-   The media type is usually passed in 'options[]'.
-*/
-#ifdef MODULE
-static int options[MAX_UNITS] = {-1, -1, -1, -1};
-module_param_array(options, int, NULL, S_IRUGO);
-MODULE_PARM_DESC(options, "1-" __MODULE_STRING(MAX_UNITS));
-
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1};
-module_param_array(full_duplex, int, NULL, S_IRUGO);
-MODULE_PARM_DESC(full_duplex, "1-" __MODULE_STRING(MAX_UNITS));
-#endif
-
 #ifdef CONFIG_SBMAC_COALESCE
 static int int_pktcnt_tx = 255;
 module_param(int_pktcnt_tx, int, S_IRUGO);
@@ -112,6 +102,7 @@
 MODULE_PARM_DESC(int_timeout_rx, "RX timeout value");
 #endif
 
+#include <asm/sibyte/board.h>
 #include <asm/sibyte/sb1250.h>
 #if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80)
 #include <asm/sibyte/bcm1480_regs.h>
@@ -135,22 +126,43 @@
 #error invalid SiByte MAC configuation
 #endif
 
+#ifdef K_INT_PHY
+#define SBMAC_PHY_INT			K_INT_PHY
+#else
+#define SBMAC_PHY_INT			PHY_POLL
+#endif
+
 /**********************************************************************
  *  Simple types
  ********************************************************************* */
 
+enum sbmac_speed {
+	sbmac_speed_none = 0,
+	sbmac_speed_10 = SPEED_10,
+	sbmac_speed_100 = SPEED_100,
+	sbmac_speed_1000 = SPEED_1000,
+};
 
-typedef enum { sbmac_speed_auto, sbmac_speed_10,
-	       sbmac_speed_100, sbmac_speed_1000 } sbmac_speed_t;
+enum sbmac_duplex {
+	sbmac_duplex_none = -1,
+	sbmac_duplex_half = DUPLEX_HALF,
+	sbmac_duplex_full = DUPLEX_FULL,
+};
 
-typedef enum { sbmac_duplex_auto, sbmac_duplex_half,
-	       sbmac_duplex_full } sbmac_duplex_t;
+enum sbmac_fc {
+	sbmac_fc_none,
+	sbmac_fc_disabled,
+	sbmac_fc_frame,
+	sbmac_fc_collision,
+	sbmac_fc_carrier,
+};
 
-typedef enum { sbmac_fc_auto, sbmac_fc_disabled, sbmac_fc_frame,
-	       sbmac_fc_collision, sbmac_fc_carrier } sbmac_fc_t;
-
-typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on,
-	       sbmac_state_broken } sbmac_state_t;
+enum sbmac_state {
+	sbmac_state_uninit,
+	sbmac_state_off,
+	sbmac_state_on,
+	sbmac_state_broken,
+};
 
 
 /**********************************************************************
@@ -176,55 +188,61 @@
  *  DMA Descriptor structure
  ********************************************************************* */
 
-typedef struct sbdmadscr_s {
+struct sbdmadscr {
 	uint64_t  dscr_a;
 	uint64_t  dscr_b;
-} sbdmadscr_t;
-
-typedef unsigned long paddr_t;
+};
 
 /**********************************************************************
  *  DMA Controller structure
  ********************************************************************* */
 
-typedef struct sbmacdma_s {
+struct sbmacdma {
 
 	/*
 	 * This stuff is used to identify the channel and the registers
 	 * associated with it.
 	 */
-
-	struct sbmac_softc *sbdma_eth;	    /* back pointer to associated MAC */
-	int              sbdma_channel;	    /* channel number */
-	int		 sbdma_txdir;       /* direction (1=transmit) */
-	int		 sbdma_maxdescr;    /* total # of descriptors in ring */
+	struct sbmac_softc	*sbdma_eth;	/* back pointer to associated
+						   MAC */
+	int			sbdma_channel;	/* channel number */
+	int			sbdma_txdir;	/* direction (1=transmit) */
+	int			sbdma_maxdescr;	/* total # of descriptors
+						   in ring */
 #ifdef CONFIG_SBMAC_COALESCE
-	int		 sbdma_int_pktcnt;  /* # descriptors rx/tx before interrupt*/
-	int		 sbdma_int_timeout; /* # usec rx/tx interrupt */
+	int			sbdma_int_pktcnt;
+						/* # descriptors rx/tx
+						   before interrupt */
+	int			sbdma_int_timeout;
+						/* # usec rx/tx interrupt */
 #endif
-
-	volatile void __iomem *sbdma_config0;	/* DMA config register 0 */
-	volatile void __iomem *sbdma_config1;	/* DMA config register 1 */
-	volatile void __iomem *sbdma_dscrbase;	/* Descriptor base address */
-	volatile void __iomem *sbdma_dscrcnt;   /* Descriptor count register */
-	volatile void __iomem *sbdma_curdscr;	/* current descriptor address */
-	volatile void __iomem *sbdma_oodpktlost;/* pkt drop (rx only) */
-
+	void __iomem		*sbdma_config0;	/* DMA config register 0 */
+	void __iomem		*sbdma_config1;	/* DMA config register 1 */
+	void __iomem		*sbdma_dscrbase;
+						/* descriptor base address */
+	void __iomem		*sbdma_dscrcnt;	/* descriptor count register */
+	void __iomem		*sbdma_curdscr;	/* current descriptor
+						   address */
+	void __iomem		*sbdma_oodpktlost;
+						/* pkt drop (rx only) */
 
 	/*
 	 * This stuff is for maintenance of the ring
 	 */
-
-	sbdmadscr_t     *sbdma_dscrtable_unaligned;
-	sbdmadscr_t     *sbdma_dscrtable;	/* base of descriptor table */
-	sbdmadscr_t     *sbdma_dscrtable_end; /* end of descriptor table */
-
-	struct sk_buff **sbdma_ctxtable;    /* context table, one per descr */
-
-	paddr_t          sbdma_dscrtable_phys; /* and also the phys addr */
-	sbdmadscr_t     *sbdma_addptr;	/* next dscr for sw to add */
-	sbdmadscr_t     *sbdma_remptr;	/* next dscr for sw to remove */
-} sbmacdma_t;
+	void			*sbdma_dscrtable_unaligned;
+	struct sbdmadscr	*sbdma_dscrtable;
+						/* base of descriptor table */
+	struct sbdmadscr	*sbdma_dscrtable_end;
+						/* end of descriptor table */
+	struct sk_buff		**sbdma_ctxtable;
+						/* context table, one
+						   per descr */
+	dma_addr_t		sbdma_dscrtable_phys;
+						/* and also the phys addr */
+	struct sbdmadscr	*sbdma_addptr;	/* next dscr for sw to add */
+	struct sbdmadscr	*sbdma_remptr;	/* next dscr for sw
+						   to remove */
+};
 
 
 /**********************************************************************
@@ -236,47 +254,43 @@
 	/*
 	 * Linux-specific things
 	 */
+	struct net_device	*sbm_dev;	/* pointer to linux device */
+	struct napi_struct	napi;
+	struct phy_device	*phy_dev;	/* the associated PHY device */
+	struct mii_bus		mii_bus;	/* the MII bus */
+	int			phy_irq[PHY_MAX_ADDR];
+	spinlock_t		sbm_lock;	/* spin lock */
+	int			sbm_devflags;	/* current device flags */
 
-	struct net_device *sbm_dev;		/* pointer to linux device */
-	spinlock_t sbm_lock;		/* spin lock */
-	struct timer_list sbm_timer;     	/* for monitoring MII */
-	struct net_device_stats sbm_stats;
-	int sbm_devflags;			/* current device flags */
-
-	int	     sbm_phy_oldbmsr;
-	int	     sbm_phy_oldanlpar;
-	int	     sbm_phy_oldk1stsr;
-	int	     sbm_phy_oldlinkstat;
-	int sbm_buffersize;
-
-	unsigned char sbm_phys[2];
+	int			sbm_buffersize;
 
 	/*
 	 * Controller-specific things
 	 */
+	void __iomem		*sbm_base;	/* MAC's base address */
+	enum sbmac_state	sbm_state;	/* current state */
 
-	void __iomem		*sbm_base;          /* MAC's base address */
-	sbmac_state_t    sbm_state;         /* current state */
+	void __iomem		*sbm_macenable;	/* MAC Enable Register */
+	void __iomem		*sbm_maccfg;	/* MAC Config Register */
+	void __iomem		*sbm_fifocfg;	/* FIFO Config Register */
+	void __iomem		*sbm_framecfg;	/* Frame Config Register */
+	void __iomem		*sbm_rxfilter;	/* Receive Filter Register */
+	void __iomem		*sbm_isr;	/* Interrupt Status Register */
+	void __iomem		*sbm_imr;	/* Interrupt Mask Register */
+	void __iomem		*sbm_mdio;	/* MDIO Register */
 
-	volatile void __iomem	*sbm_macenable;	/* MAC Enable Register */
-	volatile void __iomem	*sbm_maccfg;	/* MAC Configuration Register */
-	volatile void __iomem	*sbm_fifocfg;	/* FIFO configuration register */
-	volatile void __iomem	*sbm_framecfg;	/* Frame configuration register */
-	volatile void __iomem	*sbm_rxfilter;	/* receive filter register */
-	volatile void __iomem	*sbm_isr;	/* Interrupt status register */
-	volatile void __iomem	*sbm_imr;	/* Interrupt mask register */
-	volatile void __iomem	*sbm_mdio;	/* MDIO register */
+	enum sbmac_speed	sbm_speed;	/* current speed */
+	enum sbmac_duplex	sbm_duplex;	/* current duplex */
+	enum sbmac_fc		sbm_fc;		/* cur. flow control setting */
+	int			sbm_pause;	/* current pause setting */
+	int			sbm_link;	/* current link state */
 
-	sbmac_speed_t    sbm_speed;		/* current speed */
-	sbmac_duplex_t   sbm_duplex;	/* current duplex */
-	sbmac_fc_t       sbm_fc;		/* current flow control setting */
+	unsigned char		sbm_hwaddr[ETHER_ADDR_LEN];
 
-	unsigned char    sbm_hwaddr[ETHER_ADDR_LEN];
-
-	sbmacdma_t       sbm_txdma;		/* for now, only use channel 0 */
-	sbmacdma_t       sbm_rxdma;
-	int              rx_hw_checksum;
-	int 		 sbe_idx;
+	struct sbmacdma		sbm_txdma;	/* only channel 0 for now */
+	struct sbmacdma		sbm_rxdma;
+	int			rx_hw_checksum;
+	int			sbe_idx;
 };
 
 
@@ -288,55 +302,58 @@
  *  Prototypes
  ********************************************************************* */
 
-static void sbdma_initctx(sbmacdma_t *d,
-			  struct sbmac_softc *s,
-			  int chan,
-			  int txrx,
-			  int maxdescr);
-static void sbdma_channel_start(sbmacdma_t *d, int rxtx);
-static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *m);
-static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m);
-static void sbdma_emptyring(sbmacdma_t *d);
-static void sbdma_fillring(sbmacdma_t *d);
-static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, int work_to_do, int poll);
-static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll);
+static void sbdma_initctx(struct sbmacdma *d, struct sbmac_softc *s, int chan,
+			  int txrx, int maxdescr);
+static void sbdma_channel_start(struct sbmacdma *d, int rxtx);
+static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *m);
+static int sbdma_add_txbuffer(struct sbmacdma *d, struct sk_buff *m);
+static void sbdma_emptyring(struct sbmacdma *d);
+static void sbdma_fillring(struct sbmacdma *d);
+static int sbdma_rx_process(struct sbmac_softc *sc, struct sbmacdma *d,
+			    int work_to_do, int poll);
+static void sbdma_tx_process(struct sbmac_softc *sc, struct sbmacdma *d,
+			     int poll);
 static int sbmac_initctx(struct sbmac_softc *s);
 static void sbmac_channel_start(struct sbmac_softc *s);
 static void sbmac_channel_stop(struct sbmac_softc *s);
-static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *,sbmac_state_t);
-static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff);
+static enum sbmac_state sbmac_set_channel_state(struct sbmac_softc *,
+						enum sbmac_state);
+static void sbmac_promiscuous_mode(struct sbmac_softc *sc, int onoff);
 static uint64_t sbmac_addr2reg(unsigned char *ptr);
-static irqreturn_t sbmac_intr(int irq,void *dev_instance);
+static irqreturn_t sbmac_intr(int irq, void *dev_instance);
 static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev);
 static void sbmac_setmulti(struct sbmac_softc *sc);
-static int sbmac_init(struct net_device *dev, int idx);
-static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed);
-static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc);
+static int sbmac_init(struct platform_device *pldev, long long base);
+static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed);
+static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex,
+			    enum sbmac_fc fc);
 
 static int sbmac_open(struct net_device *dev);
-static void sbmac_timer(unsigned long data);
 static void sbmac_tx_timeout (struct net_device *dev);
-static struct net_device_stats *sbmac_get_stats(struct net_device *dev);
 static void sbmac_set_rx_mode(struct net_device *dev);
 static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static int sbmac_close(struct net_device *dev);
-static int sbmac_poll(struct net_device *poll_dev, int *budget);
+static int sbmac_poll(struct napi_struct *napi, int budget);
 
-static int sbmac_mii_poll(struct sbmac_softc *s,int noisy);
+static void sbmac_mii_poll(struct net_device *dev);
 static int sbmac_mii_probe(struct net_device *dev);
 
-static void sbmac_mii_sync(struct sbmac_softc *s);
-static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt);
-static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx);
-static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
-			    unsigned int regval);
+static void sbmac_mii_sync(void __iomem *sbm_mdio);
+static void sbmac_mii_senddata(void __iomem *sbm_mdio, unsigned int data,
+			       int bitcnt);
+static int sbmac_mii_read(struct mii_bus *bus, int phyaddr, int regidx);
+static int sbmac_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
+			   u16 val);
 
 
 /**********************************************************************
  *  Globals
  ********************************************************************* */
 
-static uint64_t sbmac_orig_hwaddr[MAX_UNITS];
+static char sbmac_string[] = "sb1250-mac";
+static char sbmac_pretty[] = "SB1250 MAC";
+
+static char sbmac_mdio_string[] = "sb1250-mac-mdio";
 
 
 /**********************************************************************
@@ -348,185 +365,66 @@
 #define	MII_COMMAND_WRITE	0x01
 #define	MII_COMMAND_ACK		0x02
 
-#define BMCR_RESET     0x8000
-#define BMCR_LOOPBACK  0x4000
-#define BMCR_SPEED0    0x2000
-#define BMCR_ANENABLE  0x1000
-#define BMCR_POWERDOWN 0x0800
-#define BMCR_ISOLATE   0x0400
-#define BMCR_RESTARTAN 0x0200
-#define BMCR_DUPLEX    0x0100
-#define BMCR_COLTEST   0x0080
-#define BMCR_SPEED1    0x0040
-#define BMCR_SPEED1000	BMCR_SPEED1
-#define BMCR_SPEED100	BMCR_SPEED0
-#define BMCR_SPEED10 	0
-
-#define BMSR_100BT4	0x8000
-#define BMSR_100BT_FDX	0x4000
-#define BMSR_100BT_HDX  0x2000
-#define BMSR_10BT_FDX   0x1000
-#define BMSR_10BT_HDX   0x0800
-#define BMSR_100BT2_FDX 0x0400
-#define BMSR_100BT2_HDX 0x0200
-#define BMSR_1000BT_XSR	0x0100
-#define BMSR_PRESUP	0x0040
-#define BMSR_ANCOMPLT	0x0020
-#define BMSR_REMFAULT	0x0010
-#define BMSR_AUTONEG	0x0008
-#define BMSR_LINKSTAT	0x0004
-#define BMSR_JABDETECT	0x0002
-#define BMSR_EXTCAPAB	0x0001
-
-#define PHYIDR1 	0x2000
-#define PHYIDR2		0x5C60
-
-#define ANAR_NP		0x8000
-#define ANAR_RF		0x2000
-#define ANAR_ASYPAUSE	0x0800
-#define ANAR_PAUSE	0x0400
-#define ANAR_T4		0x0200
-#define ANAR_TXFD	0x0100
-#define ANAR_TXHD	0x0080
-#define ANAR_10FD	0x0040
-#define ANAR_10HD	0x0020
-#define ANAR_PSB	0x0001
-
-#define ANLPAR_NP	0x8000
-#define ANLPAR_ACK	0x4000
-#define ANLPAR_RF	0x2000
-#define ANLPAR_ASYPAUSE	0x0800
-#define ANLPAR_PAUSE	0x0400
-#define ANLPAR_T4	0x0200
-#define ANLPAR_TXFD	0x0100
-#define ANLPAR_TXHD	0x0080
-#define ANLPAR_10FD	0x0040
-#define ANLPAR_10HD	0x0020
-#define ANLPAR_PSB	0x0001	/* 802.3 */
-
-#define ANER_PDF	0x0010
-#define ANER_LPNPABLE	0x0008
-#define ANER_NPABLE	0x0004
-#define ANER_PAGERX	0x0002
-#define ANER_LPANABLE	0x0001
-
-#define ANNPTR_NP	0x8000
-#define ANNPTR_MP	0x2000
-#define ANNPTR_ACK2	0x1000
-#define ANNPTR_TOGTX	0x0800
-#define ANNPTR_CODE	0x0008
-
-#define ANNPRR_NP	0x8000
-#define ANNPRR_MP	0x2000
-#define ANNPRR_ACK3	0x1000
-#define ANNPRR_TOGTX	0x0800
-#define ANNPRR_CODE	0x0008
-
-#define K1TCR_TESTMODE	0x0000
-#define K1TCR_MSMCE	0x1000
-#define K1TCR_MSCV	0x0800
-#define K1TCR_RPTR	0x0400
-#define K1TCR_1000BT_FDX 0x200
-#define K1TCR_1000BT_HDX 0x100
-
-#define K1STSR_MSMCFLT	0x8000
-#define K1STSR_MSCFGRES	0x4000
-#define K1STSR_LRSTAT	0x2000
-#define K1STSR_RRSTAT	0x1000
-#define K1STSR_LP1KFD	0x0800
-#define K1STSR_LP1KHD   0x0400
-#define K1STSR_LPASMDIR	0x0200
-
-#define K1SCR_1KX_FDX	0x8000
-#define K1SCR_1KX_HDX	0x4000
-#define K1SCR_1KT_FDX	0x2000
-#define K1SCR_1KT_HDX	0x1000
-
-#define STRAP_PHY1	0x0800
-#define STRAP_NCMODE	0x0400
-#define STRAP_MANMSCFG	0x0200
-#define STRAP_ANENABLE	0x0100
-#define STRAP_MSVAL	0x0080
-#define STRAP_1KHDXADV	0x0010
-#define STRAP_1KFDXADV	0x0008
-#define STRAP_100ADV	0x0004
-#define STRAP_SPEEDSEL	0x0000
-#define STRAP_SPEED100	0x0001
-
-#define PHYSUP_SPEED1000 0x10
-#define PHYSUP_SPEED100  0x08
-#define PHYSUP_SPEED10   0x00
-#define PHYSUP_LINKUP	 0x04
-#define PHYSUP_FDX       0x02
-
-#define	MII_BMCR	0x00 	/* Basic mode control register (rw) */
-#define	MII_BMSR	0x01	/* Basic mode status register (ro) */
-#define	MII_PHYIDR1	0x02
-#define	MII_PHYIDR2	0x03
-
-#define MII_K1STSR	0x0A	/* 1K Status Register (ro) */
-#define	MII_ANLPAR	0x05	/* Autonegotiation lnk partner abilities (rw) */
-
-
 #define M_MAC_MDIO_DIR_OUTPUT	0		/* for clarity */
 
 #define ENABLE 		1
 #define DISABLE		0
 
 /**********************************************************************
- *  SBMAC_MII_SYNC(s)
+ *  SBMAC_MII_SYNC(sbm_mdio)
  *
  *  Synchronize with the MII - send a pattern of bits to the MII
  *  that will guarantee that it is ready to accept a command.
  *
  *  Input parameters:
- *  	   s - sbmac structure
+ *  	   sbm_mdio - address of the MAC's MDIO register
  *
  *  Return value:
  *  	   nothing
  ********************************************************************* */
 
-static void sbmac_mii_sync(struct sbmac_softc *s)
+static void sbmac_mii_sync(void __iomem *sbm_mdio)
 {
 	int cnt;
 	uint64_t bits;
 	int mac_mdio_genc;
 
-	mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
+	mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC;
 
 	bits = M_MAC_MDIO_DIR_OUTPUT | M_MAC_MDIO_OUT;
 
-	__raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
+	__raw_writeq(bits | mac_mdio_genc, sbm_mdio);
 
 	for (cnt = 0; cnt < 32; cnt++) {
-		__raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
-		__raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
+		__raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, sbm_mdio);
+		__raw_writeq(bits | mac_mdio_genc, sbm_mdio);
 	}
 }
 
 /**********************************************************************
- *  SBMAC_MII_SENDDATA(s,data,bitcnt)
+ *  SBMAC_MII_SENDDATA(sbm_mdio, data, bitcnt)
  *
  *  Send some bits to the MII.  The bits to be sent are right-
  *  justified in the 'data' parameter.
  *
  *  Input parameters:
- *  	   s - sbmac structure
- *  	   data - data to send
- *  	   bitcnt - number of bits to send
+ *  	   sbm_mdio - address of the MAC's MDIO register
+ *  	   data     - data to send
+ *  	   bitcnt   - number of bits to send
  ********************************************************************* */
 
-static void sbmac_mii_senddata(struct sbmac_softc *s,unsigned int data, int bitcnt)
+static void sbmac_mii_senddata(void __iomem *sbm_mdio, unsigned int data,
+			       int bitcnt)
 {
 	int i;
 	uint64_t bits;
 	unsigned int curmask;
 	int mac_mdio_genc;
 
-	mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
+	mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC;
 
 	bits = M_MAC_MDIO_DIR_OUTPUT;
-	__raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
+	__raw_writeq(bits | mac_mdio_genc, sbm_mdio);
 
 	curmask = 1 << (bitcnt - 1);
 
@@ -534,9 +432,9 @@
 		if (data & curmask)
 			bits |= M_MAC_MDIO_OUT;
 		else bits &= ~M_MAC_MDIO_OUT;
-		__raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
-		__raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
-		__raw_writeq(bits | mac_mdio_genc, s->sbm_mdio);
+		__raw_writeq(bits | mac_mdio_genc, sbm_mdio);
+		__raw_writeq(bits | M_MAC_MDC | mac_mdio_genc, sbm_mdio);
+		__raw_writeq(bits | mac_mdio_genc, sbm_mdio);
 		curmask >>= 1;
 	}
 }
@@ -544,21 +442,22 @@
 
 
 /**********************************************************************
- *  SBMAC_MII_READ(s,phyaddr,regidx)
- *
+ *  SBMAC_MII_READ(bus, phyaddr, regidx)
  *  Read a PHY register.
  *
  *  Input parameters:
- *  	   s - sbmac structure
+ *  	   bus     - MDIO bus handle
  *  	   phyaddr - PHY's address
- *  	   regidx = index of register to read
+ *  	   regnum  - index of register to read
  *
  *  Return value:
- *  	   value read, or 0 if an error occurred.
+ *  	   value read, or 0xffff if an error occurred.
  ********************************************************************* */
 
-static unsigned int sbmac_mii_read(struct sbmac_softc *s,int phyaddr,int regidx)
+static int sbmac_mii_read(struct mii_bus *bus, int phyaddr, int regidx)
 {
+	struct sbmac_softc *sc = (struct sbmac_softc *)bus->priv;
+	void __iomem *sbm_mdio = sc->sbm_mdio;
 	int idx;
 	int error;
 	int regval;
@@ -568,8 +467,7 @@
 	 * Synchronize ourselves so that the PHY knows the next
 	 * thing coming down is a command
 	 */
-
-	sbmac_mii_sync(s);
+	sbmac_mii_sync(sbm_mdio);
 
 	/*
 	 * Send the data to the PHY.  The sequence is
@@ -578,37 +476,37 @@
 	 * the PHY addr (5 bits)
 	 * the register index (5 bits)
 	 */
+	sbmac_mii_senddata(sbm_mdio, MII_COMMAND_START, 2);
+	sbmac_mii_senddata(sbm_mdio, MII_COMMAND_READ, 2);
+	sbmac_mii_senddata(sbm_mdio, phyaddr, 5);
+	sbmac_mii_senddata(sbm_mdio, regidx, 5);
 
-	sbmac_mii_senddata(s,MII_COMMAND_START, 2);
-	sbmac_mii_senddata(s,MII_COMMAND_READ, 2);
-	sbmac_mii_senddata(s,phyaddr, 5);
-	sbmac_mii_senddata(s,regidx, 5);
-
-	mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
+	mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC;
 
 	/*
 	 * Switch the port around without a clock transition.
 	 */
-	__raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
+	__raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio);
 
 	/*
 	 * Send out a clock pulse to signal we want the status
 	 */
-
-	__raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
-	__raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
+	__raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc,
+		     sbm_mdio);
+	__raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio);
 
 	/*
 	 * If an error occurred, the PHY will signal '1' back
 	 */
-	error = __raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN;
+	error = __raw_readq(sbm_mdio) & M_MAC_MDIO_IN;
 
 	/*
 	 * Issue an 'idle' clock pulse, but keep the direction
 	 * the same.
 	 */
-	__raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
-	__raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
+	__raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc,
+		     sbm_mdio);
+	__raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio);
 
 	regval = 0;
 
@@ -616,55 +514,60 @@
 		regval <<= 1;
 
 		if (error == 0) {
-			if (__raw_readq(s->sbm_mdio) & M_MAC_MDIO_IN)
+			if (__raw_readq(sbm_mdio) & M_MAC_MDIO_IN)
 				regval |= 1;
 		}
 
-		__raw_writeq(M_MAC_MDIO_DIR_INPUT|M_MAC_MDC | mac_mdio_genc, s->sbm_mdio);
-		__raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, s->sbm_mdio);
+		__raw_writeq(M_MAC_MDIO_DIR_INPUT | M_MAC_MDC | mac_mdio_genc,
+			     sbm_mdio);
+		__raw_writeq(M_MAC_MDIO_DIR_INPUT | mac_mdio_genc, sbm_mdio);
 	}
 
 	/* Switch back to output */
-	__raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio);
+	__raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, sbm_mdio);
 
 	if (error == 0)
 		return regval;
-	return 0;
+	return 0xffff;
 }
 
 
 /**********************************************************************
- *  SBMAC_MII_WRITE(s,phyaddr,regidx,regval)
+ *  SBMAC_MII_WRITE(bus, phyaddr, regidx, regval)
  *
  *  Write a value to a PHY register.
  *
  *  Input parameters:
- *  	   s - sbmac structure
+ *  	   bus     - MDIO bus handle
  *  	   phyaddr - PHY to use
- *  	   regidx - register within the PHY
- *  	   regval - data to write to register
+ *  	   regidx  - register within the PHY
+ *  	   regval  - data to write to register
  *
  *  Return value:
- *  	   nothing
+ *  	   0 for success
  ********************************************************************* */
 
-static void sbmac_mii_write(struct sbmac_softc *s,int phyaddr,int regidx,
-			    unsigned int regval)
+static int sbmac_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
+			   u16 regval)
 {
+	struct sbmac_softc *sc = (struct sbmac_softc *)bus->priv;
+	void __iomem *sbm_mdio = sc->sbm_mdio;
 	int mac_mdio_genc;
 
-	sbmac_mii_sync(s);
+	sbmac_mii_sync(sbm_mdio);
 
-	sbmac_mii_senddata(s,MII_COMMAND_START,2);
-	sbmac_mii_senddata(s,MII_COMMAND_WRITE,2);
-	sbmac_mii_senddata(s,phyaddr, 5);
-	sbmac_mii_senddata(s,regidx, 5);
-	sbmac_mii_senddata(s,MII_COMMAND_ACK,2);
-	sbmac_mii_senddata(s,regval,16);
+	sbmac_mii_senddata(sbm_mdio, MII_COMMAND_START, 2);
+	sbmac_mii_senddata(sbm_mdio, MII_COMMAND_WRITE, 2);
+	sbmac_mii_senddata(sbm_mdio, phyaddr, 5);
+	sbmac_mii_senddata(sbm_mdio, regidx, 5);
+	sbmac_mii_senddata(sbm_mdio, MII_COMMAND_ACK, 2);
+	sbmac_mii_senddata(sbm_mdio, regval, 16);
 
-	mac_mdio_genc = __raw_readq(s->sbm_mdio) & M_MAC_GENC;
+	mac_mdio_genc = __raw_readq(sbm_mdio) & M_MAC_GENC;
 
-	__raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, s->sbm_mdio);
+	__raw_writeq(M_MAC_MDIO_DIR_OUTPUT | mac_mdio_genc, sbm_mdio);
+
+	return 0;
 }
 
 
@@ -677,8 +580,8 @@
  *  way.
  *
  *  Input parameters:
- *  	   d - sbmacdma_t structure (DMA channel context)
- *  	   s - sbmac_softc structure (pointer to a MAC)
+ *  	   d - struct sbmacdma (DMA channel context)
+ *  	   s - struct sbmac_softc (pointer to a MAC)
  *  	   chan - channel number (0..1 right now)
  *  	   txrx - Identifies DMA_TX or DMA_RX for channel direction
  *      maxdescr - number of descriptors
@@ -687,11 +590,8 @@
  *  	   nothing
  ********************************************************************* */
 
-static void sbdma_initctx(sbmacdma_t *d,
-			  struct sbmac_softc *s,
-			  int chan,
-			  int txrx,
-			  int maxdescr)
+static void sbdma_initctx(struct sbmacdma *d, struct sbmac_softc *s, int chan,
+			  int txrx, int maxdescr)
 {
 #ifdef CONFIG_SBMAC_COALESCE
 	int int_pktcnt, int_timeout;
@@ -710,27 +610,27 @@
 	s->sbe_idx =(s->sbm_base - A_MAC_BASE_0)/MAC_SPACING;
 #endif
 
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BYTES)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_COLLISIONS)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_LATE_COL)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_EX_COL)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_FCS_ERROR)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_ABORT)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_BAD)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_GOOD)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_RUNT)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_TX_OVERSIZE)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BYTES)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_MCAST)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BCAST)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_BAD)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_GOOD)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_RUNT)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_OVERSIZE)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_FCS_ERROR)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_LENGTH_ERROR)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_CODE_ERROR)));
-	__raw_writeq(0, IOADDR(A_MAC_REGISTER(s->sbe_idx, R_MAC_RMON_RX_ALIGN_ERROR)));
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_BYTES);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_COLLISIONS);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_LATE_COL);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_EX_COL);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_FCS_ERROR);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_ABORT);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_BAD);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_GOOD);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_RUNT);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_TX_OVERSIZE);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BYTES);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_MCAST);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BCAST);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_BAD);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_GOOD);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_RUNT);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_OVERSIZE);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_FCS_ERROR);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_LENGTH_ERROR);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_CODE_ERROR);
+	__raw_writeq(0, s->sbm_base + R_MAC_RMON_RX_ALIGN_ERROR);
 
 	/*
 	 * initialize register pointers
@@ -758,18 +658,17 @@
 
 	d->sbdma_maxdescr = maxdescr;
 
-	d->sbdma_dscrtable_unaligned =
-	d->sbdma_dscrtable = (sbdmadscr_t *)
-		kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL);
+	d->sbdma_dscrtable_unaligned = kcalloc(d->sbdma_maxdescr + 1,
+					       sizeof(*d->sbdma_dscrtable),
+					       GFP_KERNEL);
 
 	/*
 	 * The descriptor table must be aligned to at least 16 bytes or the
 	 * MAC will corrupt it.
 	 */
-	d->sbdma_dscrtable = (sbdmadscr_t *)
-		ALIGN((unsigned long)d->sbdma_dscrtable, sizeof(sbdmadscr_t));
-
-	memset(d->sbdma_dscrtable,0,d->sbdma_maxdescr*sizeof(sbdmadscr_t));
+	d->sbdma_dscrtable = (struct sbdmadscr *)
+			     ALIGN((unsigned long)d->sbdma_dscrtable_unaligned,
+				   sizeof(*d->sbdma_dscrtable));
 
 	d->sbdma_dscrtable_end = d->sbdma_dscrtable + d->sbdma_maxdescr;
 
@@ -779,10 +678,8 @@
 	 * And context table
 	 */
 
-	d->sbdma_ctxtable = (struct sk_buff **)
-		kmalloc(d->sbdma_maxdescr*sizeof(struct sk_buff *), GFP_KERNEL);
-
-	memset(d->sbdma_ctxtable,0,d->sbdma_maxdescr*sizeof(struct sk_buff *));
+	d->sbdma_ctxtable = kcalloc(d->sbdma_maxdescr,
+				    sizeof(*d->sbdma_ctxtable), GFP_KERNEL);
 
 #ifdef CONFIG_SBMAC_COALESCE
 	/*
@@ -819,7 +716,7 @@
  *  	   nothing
  ********************************************************************* */
 
-static void sbdma_channel_start(sbmacdma_t *d, int rxtx )
+static void sbdma_channel_start(struct sbmacdma *d, int rxtx)
 {
 	/*
 	 * Turn on the DMA channel
@@ -860,7 +757,7 @@
  *  	   nothing
  ********************************************************************* */
 
-static void sbdma_channel_stop(sbmacdma_t *d)
+static void sbdma_channel_stop(struct sbmacdma *d)
 {
 	/*
 	 * Turn off the DMA channel
@@ -909,10 +806,10 @@
  ********************************************************************* */
 
 
-static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
+static int sbdma_add_rcvbuffer(struct sbmacdma *d, struct sk_buff *sb)
 {
-	sbdmadscr_t *dsc;
-	sbdmadscr_t *nextdsc;
+	struct sbdmadscr *dsc;
+	struct sbdmadscr *nextdsc;
 	struct sk_buff *sb_new = NULL;
 	int pktsize = ENET_PACKET_SIZE;
 
@@ -953,7 +850,7 @@
 	if (sb == NULL) {
 		sb_new = dev_alloc_skb(ENET_PACKET_SIZE + SMP_CACHE_BYTES * 2 + ETHER_ALIGN);
 		if (sb_new == NULL) {
-			printk(KERN_INFO "%s: sk_buff allocation failed\n",
+			pr_info("%s: sk_buff allocation failed\n",
 			       d->sbdma_eth->sbm_dev->name);
 			return -ENOBUFS;
 		}
@@ -1024,10 +921,10 @@
  ********************************************************************* */
 
 
-static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *sb)
+static int sbdma_add_txbuffer(struct sbmacdma *d, struct sk_buff *sb)
 {
-	sbdmadscr_t *dsc;
-	sbdmadscr_t *nextdsc;
+	struct sbdmadscr *dsc;
+	struct sbdmadscr *nextdsc;
 	uint64_t phys;
 	uint64_t ncb;
 	int length;
@@ -1113,7 +1010,7 @@
  *  	   nothing
  ********************************************************************* */
 
-static void sbdma_emptyring(sbmacdma_t *d)
+static void sbdma_emptyring(struct sbmacdma *d)
 {
 	int idx;
 	struct sk_buff *sb;
@@ -1141,7 +1038,7 @@
  *  	   nothing
  ********************************************************************* */
 
-static void sbdma_fillring(sbmacdma_t *d)
+static void sbdma_fillring(struct sbmacdma *d)
 {
 	int idx;
 
@@ -1188,12 +1085,13 @@
  *  	   nothing
  ********************************************************************* */
 
-static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d,
-                             int work_to_do, int poll)
+static int sbdma_rx_process(struct sbmac_softc *sc, struct sbmacdma *d,
+			    int work_to_do, int poll)
 {
+	struct net_device *dev = sc->sbm_dev;
 	int curidx;
 	int hwidx;
-	sbdmadscr_t *dsc;
+	struct sbdmadscr *dsc;
 	struct sk_buff *sb;
 	int len;
 	int work_done = 0;
@@ -1203,7 +1101,7 @@
 
 again:
 	/* Check if the HW dropped any frames */
-	sc->sbm_stats.rx_fifo_errors
+	dev->stats.rx_fifo_errors
 	    += __raw_readq(sc->sbm_rxdma.sbdma_oodpktlost) & 0xffff;
 	__raw_writeq(0, sc->sbm_rxdma.sbdma_oodpktlost);
 
@@ -1225,8 +1123,9 @@
 		prefetch(dsc);
 		prefetch(&d->sbdma_ctxtable[curidx]);
 
-		hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
-				d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+		hwidx = ((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
+			 d->sbdma_dscrtable_phys) /
+			sizeof(*d->sbdma_dscrtable);
 
 		/*
 		 * If they're the same, that means we've processed all
@@ -1262,7 +1161,7 @@
 
 			if (unlikely (sbdma_add_rcvbuffer(d,NULL) ==
 				      -ENOBUFS)) {
- 				sc->sbm_stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 				sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */
 				/* No point in continuing at the moment */
 				printk(KERN_ERR "dropped packet (1)\n");
@@ -1298,13 +1197,13 @@
 					dropped = netif_rx(sb);
 
 				if (dropped == NET_RX_DROP) {
-					sc->sbm_stats.rx_dropped++;
+					dev->stats.rx_dropped++;
 					d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr);
 					goto done;
 				}
 				else {
-					sc->sbm_stats.rx_bytes += len;
-					sc->sbm_stats.rx_packets++;
+					dev->stats.rx_bytes += len;
+					dev->stats.rx_packets++;
 				}
 			}
 		} else {
@@ -1312,7 +1211,7 @@
 			 * Packet was mangled somehow.  Just drop it and
 			 * put it back on the receive ring.
 			 */
-			sc->sbm_stats.rx_errors++;
+			dev->stats.rx_errors++;
 			sbdma_add_rcvbuffer(d,sb);
 		}
 
@@ -1350,11 +1249,13 @@
  *  	   nothing
  ********************************************************************* */
 
-static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll)
+static void sbdma_tx_process(struct sbmac_softc *sc, struct sbmacdma *d,
+			     int poll)
 {
+	struct net_device *dev = sc->sbm_dev;
 	int curidx;
 	int hwidx;
-	sbdmadscr_t *dsc;
+	struct sbdmadscr *dsc;
 	struct sk_buff *sb;
 	unsigned long flags;
 	int packets_handled = 0;
@@ -1364,8 +1265,8 @@
 	if (d->sbdma_remptr == d->sbdma_addptr)
 	  goto end_unlock;
 
-	hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
-			d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t));
+	hwidx = ((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) -
+		 d->sbdma_dscrtable_phys) / sizeof(*d->sbdma_dscrtable);
 
 	for (;;) {
 		/*
@@ -1402,8 +1303,8 @@
 		 * Stats
 		 */
 
-		sc->sbm_stats.tx_bytes += sb->len;
-		sc->sbm_stats.tx_packets++;
+		dev->stats.tx_bytes += sb->len;
+		dev->stats.tx_packets++;
 
 		/*
 		 * for transmits, we just free buffers.
@@ -1468,14 +1369,6 @@
 	s->sbm_imr       = s->sbm_base + R_MAC_INT_MASK;
 	s->sbm_mdio      = s->sbm_base + R_MAC_MDIO;
 
-	s->sbm_phys[0]   = 1;
-	s->sbm_phys[1]   = 0;
-
-	s->sbm_phy_oldbmsr = 0;
-	s->sbm_phy_oldanlpar = 0;
-	s->sbm_phy_oldk1stsr = 0;
-	s->sbm_phy_oldlinkstat = 0;
-
 	/*
 	 * Initialize the DMA channels.  Right now, only one per MAC is used
 	 * Note: Only do this _once_, as it allocates memory from the kernel!
@@ -1490,19 +1383,11 @@
 
 	s->sbm_state = sbmac_state_off;
 
-	/*
-	 * Initial speed is (XXX TEMP) 10MBit/s HDX no FC
-	 */
-
-	s->sbm_speed = sbmac_speed_10;
-	s->sbm_duplex = sbmac_duplex_half;
-	s->sbm_fc = sbmac_fc_disabled;
-
 	return 0;
 }
 
 
-static void sbdma_uninitctx(struct sbmacdma_s *d)
+static void sbdma_uninitctx(struct sbmacdma *d)
 {
 	if (d->sbdma_dscrtable_unaligned) {
 		kfree(d->sbdma_dscrtable_unaligned);
@@ -1538,7 +1423,7 @@
 static void sbmac_channel_start(struct sbmac_softc *s)
 {
 	uint64_t reg;
-	volatile void __iomem *port;
+	void __iomem *port;
 	uint64_t cfg,fifo,framecfg;
 	int idx, th_value;
 
@@ -1801,10 +1686,10 @@
  *  Return value:
  *  	   old state
  ********************************************************************* */
-static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *sc,
-					     sbmac_state_t state)
+static enum sbmac_state sbmac_set_channel_state(struct sbmac_softc *sc,
+						enum sbmac_state state)
 {
-	sbmac_state_t oldstate = sc->sbm_state;
+	enum sbmac_state oldstate = sc->sbm_state;
 
 	/*
 	 * If same as previous state, return
@@ -1939,14 +1824,14 @@
  *
  *  Input parameters:
  *  	   s - sbmac structure
- *  	   speed - speed to set MAC to (see sbmac_speed_t enum)
+ *  	   speed - speed to set MAC to (see enum sbmac_speed)
  *
  *  Return value:
  *  	   1 if successful
  *      0 indicates invalid parameters
  ********************************************************************* */
 
-static int sbmac_set_speed(struct sbmac_softc *s,sbmac_speed_t speed)
+static int sbmac_set_speed(struct sbmac_softc *s, enum sbmac_speed speed)
 {
 	uint64_t cfg;
 	uint64_t framecfg;
@@ -2004,8 +1889,6 @@
 		cfg |= V_MAC_SPEED_SEL_1000MBPS | M_MAC_BURST_EN;
 		break;
 
-	case sbmac_speed_auto:		/* XXX not implemented */
-		/* fall through */
 	default:
 		return 0;
 	}
@@ -2028,15 +1911,16 @@
  *
  *  Input parameters:
  *  	   s - sbmac structure
- *  	   duplex - duplex setting (see sbmac_duplex_t)
- *  	   fc - flow control setting (see sbmac_fc_t)
+ *  	   duplex - duplex setting (see enum sbmac_duplex)
+ *  	   fc - flow control setting (see enum sbmac_fc)
  *
  *  Return value:
  *  	   1 if ok
  *  	   0 if an invalid parameter combination was specified
  ********************************************************************* */
 
-static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc_t fc)
+static int sbmac_set_duplex(struct sbmac_softc *s, enum sbmac_duplex duplex,
+			    enum sbmac_fc fc)
 {
 	uint64_t cfg;
 
@@ -2078,8 +1962,6 @@
 			cfg |= M_MAC_HDX_EN | V_MAC_FC_CMD_ENAB_FALSECARR;
 			break;
 
-		case sbmac_fc_auto:		/* XXX not implemented */
-			/* fall through */
 		case sbmac_fc_frame:		/* not valid in half duplex */
 		default:			/* invalid selection */
 			return 0;
@@ -2098,15 +1980,12 @@
 
 		case sbmac_fc_collision:	/* not valid in full duplex */
 		case sbmac_fc_carrier:		/* not valid in full duplex */
-		case sbmac_fc_auto:		/* XXX not implemented */
-			/* fall through */
 		default:
 			return 0;
 		}
 		break;
-	case sbmac_duplex_auto:
-		/* XXX not implemented */
-		break;
+	default:
+		return 0;
 	}
 
 	/*
@@ -2154,20 +2033,13 @@
 	 * Transmits on channel 0
 	 */
 
-	if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) {
+	if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0))
 		sbdma_tx_process(sc,&(sc->sbm_txdma), 0);
-#ifdef CONFIG_NETPOLL_TRAP
-		if (netpoll_trap()) {
-			if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state))
-				__netif_schedule(dev);
-		}
-#endif
-	}
 
 	if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) {
-		if (netif_rx_schedule_prep(dev)) {
+		if (netif_rx_schedule_prep(dev, &sc->napi)) {
 			__raw_writeq(0, sc->sbm_imr);
-			__netif_rx_schedule(dev);
+			__netif_rx_schedule(dev, &sc->napi);
 			/* Depend on the exit from poll to reenable intr */
 		}
 		else {
@@ -2236,7 +2108,7 @@
 static void sbmac_setmulti(struct sbmac_softc *sc)
 {
 	uint64_t reg;
-	volatile void __iomem *port;
+	void __iomem *port;
 	int idx;
 	struct dev_mc_list *mclist;
 	struct net_device *dev = sc->sbm_dev;
@@ -2392,7 +2264,7 @@
 	if (new_mtu >  ENET_PACKET_SIZE)
 		return -EINVAL;
 	_dev->mtu = new_mtu;
-	printk(KERN_INFO "changing the mtu to %d\n", new_mtu);
+	pr_info("changing the mtu to %d\n", new_mtu);
 	return 0;
 }
 
@@ -2408,19 +2280,17 @@
  *  	   status
  ********************************************************************* */
 
-static int sbmac_init(struct net_device *dev, int idx)
+static int sbmac_init(struct platform_device *pldev, long long base)
 {
-	struct sbmac_softc *sc;
+	struct net_device *dev = pldev->dev.driver_data;
+	int idx = pldev->id;
+	struct sbmac_softc *sc = netdev_priv(dev);
 	unsigned char *eaddr;
 	uint64_t ea_reg;
 	int i;
 	int err;
+	DECLARE_MAC_BUF(mac);
 
-	sc = netdev_priv(dev);
-
-	/* Determine controller base address */
-
-	sc->sbm_base = IOADDR(dev->base_addr);
 	sc->sbm_dev = dev;
 	sc->sbe_idx = idx;
 
@@ -2465,58 +2335,67 @@
 	dev->open               = sbmac_open;
 	dev->hard_start_xmit    = sbmac_start_tx;
 	dev->stop               = sbmac_close;
-	dev->get_stats          = sbmac_get_stats;
 	dev->set_multicast_list = sbmac_set_rx_mode;
 	dev->do_ioctl           = sbmac_mii_ioctl;
 	dev->tx_timeout         = sbmac_tx_timeout;
 	dev->watchdog_timeo     = TX_TIMEOUT;
-	dev->poll               = sbmac_poll;
-	dev->weight             = 16;
+
+	netif_napi_add(dev, &sc->napi, sbmac_poll, 16);
 
 	dev->change_mtu         = sb1250_change_mtu;
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = sbmac_netpoll;
 #endif
 
+	dev->irq		= UNIT_INT(idx);
+
 	/* This is needed for PASS2 for Rx H/W checksum feature */
 	sbmac_set_iphdr_offset(sc);
 
 	err = register_netdev(dev);
-	if (err)
-		goto out_uninit;
-
-	if (sc->rx_hw_checksum == ENABLE) {
-		printk(KERN_INFO "%s: enabling TCP rcv checksum\n",
-			sc->sbm_dev->name);
+	if (err) {
+		printk(KERN_ERR "%s.%d: unable to register netdev\n",
+		       sbmac_string, idx);
+		sbmac_uninitctx(sc);
+		return err;
 	}
 
+	pr_info("%s.%d: registered as %s\n", sbmac_string, idx, dev->name);
+
+	if (sc->rx_hw_checksum == ENABLE)
+		pr_info("%s: enabling TCP rcv checksum\n", dev->name);
+
 	/*
 	 * Display Ethernet address (this is called during the config
 	 * process so we need to finish off the config message that
 	 * was being displayed)
 	 */
-	printk(KERN_INFO
-	       "%s: SiByte Ethernet at 0x%08lX, address: %02X:%02X:%02X:%02X:%02X:%02X\n",
-	       dev->name, dev->base_addr,
-	       eaddr[0],eaddr[1],eaddr[2],eaddr[3],eaddr[4],eaddr[5]);
+	pr_info("%s: SiByte Ethernet at 0x%08Lx, address: %s\n",
+	       dev->name, base, print_mac(mac, eaddr));
 
+	sc->mii_bus.name = sbmac_mdio_string;
+	sc->mii_bus.id = idx;
+	sc->mii_bus.priv = sc;
+	sc->mii_bus.read = sbmac_mii_read;
+	sc->mii_bus.write = sbmac_mii_write;
+	sc->mii_bus.irq = sc->phy_irq;
+	for (i = 0; i < PHY_MAX_ADDR; ++i)
+		sc->mii_bus.irq[i] = SBMAC_PHY_INT;
+
+	sc->mii_bus.dev = &pldev->dev;
+	dev_set_drvdata(&pldev->dev, &sc->mii_bus);
 
 	return 0;
-
-out_uninit:
-	sbmac_uninitctx(sc);
-
-	return err;
 }
 
 
 static int sbmac_open(struct net_device *dev)
 {
 	struct sbmac_softc *sc = netdev_priv(dev);
+	int err;
 
-	if (debug > 1) {
-		printk(KERN_DEBUG "%s: sbmac_open() irq %d.\n", dev->name, dev->irq);
-	}
+	if (debug > 1)
+		pr_debug("%s: sbmac_open() irq %d.\n", dev->name, dev->irq);
 
 	/*
 	 * map/route interrupt (clear status first, in case something
@@ -2525,23 +2404,35 @@
 	 */
 
 	__raw_readq(sc->sbm_isr);
-	if (request_irq(dev->irq, &sbmac_intr, IRQF_SHARED, dev->name, dev))
-		return -EBUSY;
-
-	/*
-	 * Probe phy address
-	 */
-
-	if(sbmac_mii_probe(dev) == -1) {
-		printk("%s: failed to probe PHY.\n", dev->name);
-		return -EINVAL;
+	err = request_irq(dev->irq, &sbmac_intr, IRQF_SHARED, dev->name, dev);
+	if (err) {
+		printk(KERN_ERR "%s: unable to get IRQ %d\n", dev->name,
+		       dev->irq);
+		goto out_err;
 	}
 
 	/*
-	 * Configure default speed
+	 * Probe PHY address
 	 */
+	err = mdiobus_register(&sc->mii_bus);
+	if (err) {
+		printk(KERN_ERR "%s: unable to register MDIO bus\n",
+		       dev->name);
+		goto out_unirq;
+	}
 
-	sbmac_mii_poll(sc,noisy_mii);
+	sc->sbm_speed = sbmac_speed_none;
+	sc->sbm_duplex = sbmac_duplex_none;
+	sc->sbm_fc = sbmac_fc_none;
+	sc->sbm_pause = -1;
+	sc->sbm_link = 0;
+
+	/*
+	 * Attach to the PHY
+	 */
+	err = sbmac_mii_probe(dev);
+	if (err)
+		goto out_unregister;
 
 	/*
 	 * Turn on the channel
@@ -2549,200 +2440,133 @@
 
 	sbmac_set_channel_state(sc,sbmac_state_on);
 
-	/*
-	 * XXX Station address is in dev->dev_addr
-	 */
-
-	if (dev->if_port == 0)
-		dev->if_port = 0;
-
 	netif_start_queue(dev);
 
 	sbmac_set_rx_mode(dev);
 
-	/* Set the timer to check for link beat. */
-	init_timer(&sc->sbm_timer);
-	sc->sbm_timer.expires = jiffies + 2 * HZ/100;
-	sc->sbm_timer.data = (unsigned long)dev;
-	sc->sbm_timer.function = &sbmac_timer;
-	add_timer(&sc->sbm_timer);
+	phy_start(sc->phy_dev);
+
+	napi_enable(&sc->napi);
 
 	return 0;
+
+out_unregister:
+	mdiobus_unregister(&sc->mii_bus);
+
+out_unirq:
+	free_irq(dev->irq, dev);
+
+out_err:
+	return err;
 }
 
 static int sbmac_mii_probe(struct net_device *dev)
 {
-	int i;
-	struct sbmac_softc *s = netdev_priv(dev);
-	u16 bmsr, id1, id2;
-	u32 vendor, device;
-
-	for (i=1; i<31; i++) {
-	bmsr = sbmac_mii_read(s, i, MII_BMSR);
-		if (bmsr != 0) {
-			s->sbm_phys[0] = i;
-			id1 = sbmac_mii_read(s, i, MII_PHYIDR1);
-			id2 = sbmac_mii_read(s, i, MII_PHYIDR2);
-			vendor = ((u32)id1 << 6) | ((id2 >> 10) & 0x3f);
-			device = (id2 >> 4) & 0x3f;
-
-			printk(KERN_INFO "%s: found phy %d, vendor %06x part %02x\n",
-				dev->name, i, vendor, device);
-			return i;
-		}
-	}
-	return -1;
-}
-
-
-static int sbmac_mii_poll(struct sbmac_softc *s,int noisy)
-{
-    int bmsr,bmcr,k1stsr,anlpar;
-    int chg;
-    char buffer[100];
-    char *p = buffer;
-
-    /* Read the mode status and mode control registers. */
-    bmsr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMSR);
-    bmcr = sbmac_mii_read(s,s->sbm_phys[0],MII_BMCR);
-
-    /* get the link partner status */
-    anlpar = sbmac_mii_read(s,s->sbm_phys[0],MII_ANLPAR);
-
-    /* if supported, read the 1000baseT register */
-    if (bmsr & BMSR_1000BT_XSR) {
-	k1stsr = sbmac_mii_read(s,s->sbm_phys[0],MII_K1STSR);
-	}
-    else {
-	k1stsr = 0;
-	}
-
-    chg = 0;
-
-    if ((bmsr & BMSR_LINKSTAT) == 0) {
-	/*
-	 * If link status is down, clear out old info so that when
-	 * it comes back up it will force us to reconfigure speed
-	 */
-	s->sbm_phy_oldbmsr = 0;
-	s->sbm_phy_oldanlpar = 0;
-	s->sbm_phy_oldk1stsr = 0;
-	return 0;
-	}
-
-    if ((s->sbm_phy_oldbmsr != bmsr) ||
-	(s->sbm_phy_oldanlpar != anlpar) ||
-	(s->sbm_phy_oldk1stsr != k1stsr)) {
-	if (debug > 1) {
-	    printk(KERN_DEBUG "%s: bmsr:%x/%x anlpar:%x/%x  k1stsr:%x/%x\n",
-	       s->sbm_dev->name,
-	       s->sbm_phy_oldbmsr,bmsr,
-	       s->sbm_phy_oldanlpar,anlpar,
-	       s->sbm_phy_oldk1stsr,k1stsr);
-	    }
-	s->sbm_phy_oldbmsr = bmsr;
-	s->sbm_phy_oldanlpar = anlpar;
-	s->sbm_phy_oldk1stsr = k1stsr;
-	chg = 1;
-	}
-
-    if (chg == 0)
-	    return 0;
-
-    p += sprintf(p,"Link speed: ");
-
-    if (k1stsr & K1STSR_LP1KFD) {
-	s->sbm_speed = sbmac_speed_1000;
-	s->sbm_duplex = sbmac_duplex_full;
-	s->sbm_fc = sbmac_fc_frame;
-	p += sprintf(p,"1000BaseT FDX");
-	}
-    else if (k1stsr & K1STSR_LP1KHD) {
-	s->sbm_speed = sbmac_speed_1000;
-	s->sbm_duplex = sbmac_duplex_half;
-	s->sbm_fc = sbmac_fc_disabled;
-	p += sprintf(p,"1000BaseT HDX");
-	}
-    else if (anlpar & ANLPAR_TXFD) {
-	s->sbm_speed = sbmac_speed_100;
-	s->sbm_duplex = sbmac_duplex_full;
-	s->sbm_fc = (anlpar & ANLPAR_PAUSE) ? sbmac_fc_frame : sbmac_fc_disabled;
-	p += sprintf(p,"100BaseT FDX");
-	}
-    else if (anlpar & ANLPAR_TXHD) {
-	s->sbm_speed = sbmac_speed_100;
-	s->sbm_duplex = sbmac_duplex_half;
-	s->sbm_fc = sbmac_fc_disabled;
-	p += sprintf(p,"100BaseT HDX");
-	}
-    else if (anlpar & ANLPAR_10FD) {
-	s->sbm_speed = sbmac_speed_10;
-	s->sbm_duplex = sbmac_duplex_full;
-	s->sbm_fc = sbmac_fc_frame;
-	p += sprintf(p,"10BaseT FDX");
-	}
-    else if (anlpar & ANLPAR_10HD) {
-	s->sbm_speed = sbmac_speed_10;
-	s->sbm_duplex = sbmac_duplex_half;
-	s->sbm_fc = sbmac_fc_collision;
-	p += sprintf(p,"10BaseT HDX");
-	}
-    else {
-	p += sprintf(p,"Unknown");
-	}
-
-    if (noisy) {
-	    printk(KERN_INFO "%s: %s\n",s->sbm_dev->name,buffer);
-	    }
-
-    return 1;
-}
-
-
-static void sbmac_timer(unsigned long data)
-{
-	struct net_device *dev = (struct net_device *)data;
 	struct sbmac_softc *sc = netdev_priv(dev);
-	int next_tick = HZ;
-	int mii_status;
+	struct phy_device *phy_dev;
+	int i;
 
-	spin_lock_irq (&sc->sbm_lock);
-
-	/* make IFF_RUNNING follow the MII status bit "Link established" */
-	mii_status = sbmac_mii_read(sc, sc->sbm_phys[0], MII_BMSR);
-
-	if ( (mii_status & BMSR_LINKSTAT) != (sc->sbm_phy_oldlinkstat) ) {
-    	        sc->sbm_phy_oldlinkstat = mii_status & BMSR_LINKSTAT;
-		if (mii_status & BMSR_LINKSTAT) {
-			netif_carrier_on(dev);
-		}
-		else {
-			netif_carrier_off(dev);
-		}
+	for (i = 0; i < PHY_MAX_ADDR; i++) {
+		phy_dev = sc->mii_bus.phy_map[i];
+		if (phy_dev)
+			break;
+	}
+	if (!phy_dev) {
+		printk(KERN_ERR "%s: no PHY found\n", dev->name);
+		return -ENXIO;
 	}
 
-	/*
-	 * Poll the PHY to see what speed we should be running at
-	 */
-
-	if (sbmac_mii_poll(sc,noisy_mii)) {
-		if (sc->sbm_state != sbmac_state_off) {
-			/*
-			 * something changed, restart the channel
-			 */
-			if (debug > 1) {
-				printk("%s: restarting channel because speed changed\n",
-				       sc->sbm_dev->name);
-			}
-			sbmac_channel_stop(sc);
-			sbmac_channel_start(sc);
-		}
+	phy_dev = phy_connect(dev, phy_dev->dev.bus_id, &sbmac_mii_poll, 0,
+			      PHY_INTERFACE_MODE_GMII);
+	if (IS_ERR(phy_dev)) {
+		printk(KERN_ERR "%s: could not attach to PHY\n", dev->name);
+		return PTR_ERR(phy_dev);
 	}
 
-	spin_unlock_irq (&sc->sbm_lock);
+	/* Remove any features not supported by the controller */
+	phy_dev->supported &= SUPPORTED_10baseT_Half |
+			      SUPPORTED_10baseT_Full |
+			      SUPPORTED_100baseT_Half |
+			      SUPPORTED_100baseT_Full |
+			      SUPPORTED_1000baseT_Half |
+			      SUPPORTED_1000baseT_Full |
+			      SUPPORTED_Autoneg |
+			      SUPPORTED_MII |
+			      SUPPORTED_Pause |
+			      SUPPORTED_Asym_Pause;
+	phy_dev->advertising = phy_dev->supported;
 
-	sc->sbm_timer.expires = jiffies + next_tick;
-	add_timer(&sc->sbm_timer);
+	pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
+		dev->name, phy_dev->drv->name,
+		phy_dev->dev.bus_id, phy_dev->irq);
+
+	sc->phy_dev = phy_dev;
+
+	return 0;
+}
+
+
+static void sbmac_mii_poll(struct net_device *dev)
+{
+	struct sbmac_softc *sc = netdev_priv(dev);
+	struct phy_device *phy_dev = sc->phy_dev;
+	unsigned long flags;
+	enum sbmac_fc fc;
+	int link_chg, speed_chg, duplex_chg, pause_chg, fc_chg;
+
+	link_chg = (sc->sbm_link != phy_dev->link);
+	speed_chg = (sc->sbm_speed != phy_dev->speed);
+	duplex_chg = (sc->sbm_duplex != phy_dev->duplex);
+	pause_chg = (sc->sbm_pause != phy_dev->pause);
+
+	if (!link_chg && !speed_chg && !duplex_chg && !pause_chg)
+		return;					/* Hmmm... */
+
+	if (!phy_dev->link) {
+		if (link_chg) {
+			sc->sbm_link = phy_dev->link;
+			sc->sbm_speed = sbmac_speed_none;
+			sc->sbm_duplex = sbmac_duplex_none;
+			sc->sbm_fc = sbmac_fc_disabled;
+			sc->sbm_pause = -1;
+			pr_info("%s: link unavailable\n", dev->name);
+		}
+		return;
+	}
+
+	if (phy_dev->duplex == DUPLEX_FULL) {
+		if (phy_dev->pause)
+			fc = sbmac_fc_frame;
+		else
+			fc = sbmac_fc_disabled;
+	} else
+		fc = sbmac_fc_collision;
+	fc_chg = (sc->sbm_fc != fc);
+
+	pr_info("%s: link available: %dbase-%cD\n", dev->name, phy_dev->speed,
+		phy_dev->duplex == DUPLEX_FULL ? 'F' : 'H');
+
+	spin_lock_irqsave(&sc->sbm_lock, flags);
+
+	sc->sbm_speed = phy_dev->speed;
+	sc->sbm_duplex = phy_dev->duplex;
+	sc->sbm_fc = fc;
+	sc->sbm_pause = phy_dev->pause;
+	sc->sbm_link = phy_dev->link;
+
+	if ((speed_chg || duplex_chg || fc_chg) &&
+	    sc->sbm_state != sbmac_state_off) {
+		/*
+		 * something changed, restart the channel
+		 */
+		if (debug > 1)
+			pr_debug("%s: restarting channel "
+				 "because PHY state changed\n", dev->name);
+		sbmac_channel_stop(sc);
+		sbmac_channel_start(sc);
+	}
+
+	spin_unlock_irqrestore(&sc->sbm_lock, flags);
 }
 
 
@@ -2754,7 +2578,7 @@
 
 
 	dev->trans_start = jiffies;
-	sc->sbm_stats.tx_errors++;
+	dev->stats.tx_errors++;
 
 	spin_unlock_irq (&sc->sbm_lock);
 
@@ -2764,22 +2588,6 @@
 
 
 
-static struct net_device_stats *sbmac_get_stats(struct net_device *dev)
-{
-	struct sbmac_softc *sc = netdev_priv(dev);
-	unsigned long flags;
-
-	spin_lock_irqsave(&sc->sbm_lock, flags);
-
-	/* XXX update other stats here */
-
-	spin_unlock_irqrestore(&sc->sbm_lock, flags);
-
-	return &sc->sbm_stats;
-}
-
-
-
 static void sbmac_set_rx_mode(struct net_device *dev)
 {
 	unsigned long flags;
@@ -2811,62 +2619,34 @@
 static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct sbmac_softc *sc = netdev_priv(dev);
-	u16 *data = (u16 *)&rq->ifr_ifru;
-	unsigned long flags;
-	int retval;
 
-	spin_lock_irqsave(&sc->sbm_lock, flags);
-	retval = 0;
+	if (!netif_running(dev) || !sc->phy_dev)
+		return -EINVAL;
 
-	switch(cmd) {
-	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
-		data[0] = sc->sbm_phys[0] & 0x1f;
-		/* Fall Through */
-	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
-		data[3] = sbmac_mii_read(sc, data[0] & 0x1f, data[1] & 0x1f);
-		break;
-	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
-		if (!capable(CAP_NET_ADMIN)) {
-			retval = -EPERM;
-			break;
-		}
-		if (debug > 1) {
-		    printk(KERN_DEBUG "%s: sbmac_mii_ioctl: write %02X %02X %02X\n",dev->name,
-		       data[0],data[1],data[2]);
-		    }
-		sbmac_mii_write(sc, data[0] & 0x1f, data[1] & 0x1f, data[2]);
-		break;
-	default:
-		retval = -EOPNOTSUPP;
-	}
-
-	spin_unlock_irqrestore(&sc->sbm_lock, flags);
-	return retval;
+	return phy_mii_ioctl(sc->phy_dev, if_mii(rq), cmd);
 }
 
 static int sbmac_close(struct net_device *dev)
 {
 	struct sbmac_softc *sc = netdev_priv(dev);
-	unsigned long flags;
-	int irq;
 
-	sbmac_set_channel_state(sc,sbmac_state_off);
+	napi_disable(&sc->napi);
 
-	del_timer_sync(&sc->sbm_timer);
+	phy_stop(sc->phy_dev);
 
-	spin_lock_irqsave(&sc->sbm_lock, flags);
+	sbmac_set_channel_state(sc, sbmac_state_off);
 
 	netif_stop_queue(dev);
 
-	if (debug > 1) {
-		printk(KERN_DEBUG "%s: Shutting down ethercard\n",dev->name);
-	}
+	if (debug > 1)
+		pr_debug("%s: Shutting down ethercard\n", dev->name);
 
-	spin_unlock_irqrestore(&sc->sbm_lock, flags);
+	phy_disconnect(sc->phy_dev);
+	sc->phy_dev = NULL;
 
-	irq = dev->irq;
-	synchronize_irq(irq);
-	free_irq(irq, dev);
+	mdiobus_unregister(&sc->mii_bus);
+
+	free_irq(dev->irq, dev);
 
 	sbdma_emptyring(&(sc->sbm_txdma));
 	sbdma_emptyring(&(sc->sbm_rxdma));
@@ -2874,26 +2654,17 @@
 	return 0;
 }
 
-static int sbmac_poll(struct net_device *dev, int *budget)
+static int sbmac_poll(struct napi_struct *napi, int budget)
 {
-	int work_to_do;
+	struct sbmac_softc *sc = container_of(napi, struct sbmac_softc, napi);
+	struct net_device *dev = sc->sbm_dev;
 	int work_done;
-	struct sbmac_softc *sc = netdev_priv(dev);
 
-	work_to_do = min(*budget, dev->quota);
-	work_done = sbdma_rx_process(sc, &(sc->sbm_rxdma), work_to_do, 1);
-
-	if (work_done > work_to_do)
-		printk(KERN_ERR "%s exceeded work_to_do budget=%d quota=%d work-done=%d\n",
-		       sc->sbm_dev->name, *budget, dev->quota, work_done);
-
+	work_done = sbdma_rx_process(sc, &(sc->sbm_rxdma), budget, 1);
 	sbdma_tx_process(sc, &(sc->sbm_txdma), 1);
 
-	*budget -= work_done;
-	dev->quota -= work_done;
-
-	if (work_done < work_to_do) {
-		netif_rx_complete(dev);
+	if (work_done < budget) {
+		netif_rx_complete(dev, napi);
 
 #ifdef CONFIG_SBMAC_COALESCE
 		__raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) |
@@ -2905,57 +2676,198 @@
 #endif
 	}
 
-	return (work_done >= work_to_do);
+	return work_done;
 }
 
-#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
-static void
-sbmac_setup_hwaddr(int chan,char *addr)
+
+static int __init sbmac_probe(struct platform_device *pldev)
 {
+	struct net_device *dev;
+	struct sbmac_softc *sc;
+	void __iomem *sbm_base;
+	struct resource *res;
+	u64 sbmac_orig_hwaddr;
+	int err;
+
+	res = platform_get_resource(pldev, IORESOURCE_MEM, 0);
+	BUG_ON(!res);
+	sbm_base = ioremap_nocache(res->start, res->end - res->start + 1);
+	if (!sbm_base) {
+		printk(KERN_ERR "%s: unable to map device registers\n",
+		       pldev->dev.bus_id);
+		err = -ENOMEM;
+		goto out_out;
+	}
+
+	/*
+	 * The R_MAC_ETHERNET_ADDR register will be set to some nonzero
+	 * value for us by the firmware if we're going to use this MAC.
+	 * If we find a zero, skip this MAC.
+	 */
+	sbmac_orig_hwaddr = __raw_readq(sbm_base + R_MAC_ETHERNET_ADDR);
+	pr_debug("%s: %sconfiguring MAC at 0x%08Lx\n", pldev->dev.bus_id,
+		 sbmac_orig_hwaddr ? "" : "not ", (long long)res->start);
+	if (sbmac_orig_hwaddr == 0) {
+		err = 0;
+		goto out_unmap;
+	}
+
+	/*
+	 * Okay, cool.  Initialize this MAC.
+	 */
+	dev = alloc_etherdev(sizeof(struct sbmac_softc));
+	if (!dev) {
+		printk(KERN_ERR "%s: unable to allocate etherdev\n",
+		       pldev->dev.bus_id);
+		err = -ENOMEM;
+		goto out_unmap;
+	}
+
+	pldev->dev.driver_data = dev;
+	SET_NETDEV_DEV(dev, &pldev->dev);
+
+	sc = netdev_priv(dev);
+	sc->sbm_base = sbm_base;
+
+	err = sbmac_init(pldev, res->start);
+	if (err)
+		goto out_kfree;
+
+	return 0;
+
+out_kfree:
+	free_netdev(dev);
+	__raw_writeq(sbmac_orig_hwaddr, sbm_base + R_MAC_ETHERNET_ADDR);
+
+out_unmap:
+	iounmap(sbm_base);
+
+out_out:
+	return err;
+}
+
+static int __exit sbmac_remove(struct platform_device *pldev)
+{
+	struct net_device *dev = pldev->dev.driver_data;
+	struct sbmac_softc *sc = netdev_priv(dev);
+
+	unregister_netdev(dev);
+	sbmac_uninitctx(sc);
+	iounmap(sc->sbm_base);
+	free_netdev(dev);
+
+	return 0;
+}
+
+
+static struct platform_device **sbmac_pldev;
+static int sbmac_max_units;
+
+#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR)
+static void __init sbmac_setup_hwaddr(int idx, char *addr)
+{
+	void __iomem *sbm_base;
+	unsigned long start, end;
 	uint8_t eaddr[6];
 	uint64_t val;
-	unsigned long port;
 
-	port = A_MAC_CHANNEL_BASE(chan);
-	sbmac_parse_hwaddr(addr,eaddr);
+	if (idx >= sbmac_max_units)
+		return;
+
+	start = A_MAC_CHANNEL_BASE(idx);
+	end = A_MAC_CHANNEL_BASE(idx + 1) - 1;
+
+	sbm_base = ioremap_nocache(start, end - start + 1);
+	if (!sbm_base) {
+		printk(KERN_ERR "%s: unable to map device registers\n",
+		       sbmac_string);
+		return;
+	}
+
+	sbmac_parse_hwaddr(addr, eaddr);
 	val = sbmac_addr2reg(eaddr);
-	__raw_writeq(val, IOADDR(port+R_MAC_ETHERNET_ADDR));
-	val = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR));
+	__raw_writeq(val, sbm_base + R_MAC_ETHERNET_ADDR);
+	val = __raw_readq(sbm_base + R_MAC_ETHERNET_ADDR);
+
+	iounmap(sbm_base);
 }
 #endif
 
-static struct net_device *dev_sbmac[MAX_UNITS];
-
-static int __init
-sbmac_init_module(void)
+static int __init sbmac_platform_probe_one(int idx)
 {
-	int idx;
-	struct net_device *dev;
-	unsigned long port;
-	int chip_max_units;
+	struct platform_device *pldev;
+	struct {
+		struct resource r;
+		char name[strlen(sbmac_pretty) + 4];
+	} *res;
+	int err;
+
+	res = kzalloc(sizeof(*res), GFP_KERNEL);
+	if (!res) {
+		printk(KERN_ERR "%s.%d: unable to allocate memory\n",
+		       sbmac_string, idx);
+		err = -ENOMEM;
+		goto out_err;
+	}
+
+	/*
+	 * This is the base address of the MAC.
+	 */
+	snprintf(res->name, sizeof(res->name), "%s %d", sbmac_pretty, idx);
+	res->r.name = res->name;
+	res->r.flags = IORESOURCE_MEM;
+	res->r.start = A_MAC_CHANNEL_BASE(idx);
+	res->r.end = A_MAC_CHANNEL_BASE(idx + 1) - 1;
+
+	pldev = platform_device_register_simple(sbmac_string, idx, &res->r, 1);
+	if (IS_ERR(pldev)) {
+		printk(KERN_ERR "%s.%d: unable to register platform device\n",
+		       sbmac_string, idx);
+		err = PTR_ERR(pldev);
+		goto out_kfree;
+	}
+
+	if (!pldev->dev.driver) {
+		err = 0;		/* No hardware at this address. */
+		goto out_unregister;
+	}
+
+	sbmac_pldev[idx] = pldev;
+	return 0;
+
+out_unregister:
+	platform_device_unregister(pldev);
+
+out_kfree:
+	kfree(res);
+
+out_err:
+	return err;
+}
+
+static void __init sbmac_platform_probe(void)
+{
+	int i;
 
 	/* Set the number of available units based on the SOC type.  */
 	switch (soc_type) {
 	case K_SYS_SOC_TYPE_BCM1250:
 	case K_SYS_SOC_TYPE_BCM1250_ALT:
-		chip_max_units = 3;
+		sbmac_max_units = 3;
 		break;
 	case K_SYS_SOC_TYPE_BCM1120:
 	case K_SYS_SOC_TYPE_BCM1125:
 	case K_SYS_SOC_TYPE_BCM1125H:
-	case K_SYS_SOC_TYPE_BCM1250_ALT2: /* Hybrid */
-		chip_max_units = 2;
+	case K_SYS_SOC_TYPE_BCM1250_ALT2:	/* Hybrid */
+		sbmac_max_units = 2;
 		break;
 	case K_SYS_SOC_TYPE_BCM1x55:
 	case K_SYS_SOC_TYPE_BCM1x80:
-		chip_max_units = 4;
+		sbmac_max_units = 4;
 		break;
 	default:
-		chip_max_units = 0;
-		break;
+		return;				/* none */
 	}
-	if (chip_max_units > MAX_UNITS)
-		chip_max_units = MAX_UNITS;
 
 	/*
 	 * For bringup when not using the firmware, we can pre-fill
@@ -2963,89 +2875,71 @@
 	 * specified in this file (or maybe from the config file?)
 	 */
 #ifdef SBMAC_ETH0_HWADDR
-	if (chip_max_units > 0)
-	  sbmac_setup_hwaddr(0,SBMAC_ETH0_HWADDR);
+	sbmac_setup_hwaddr(0, SBMAC_ETH0_HWADDR);
 #endif
 #ifdef SBMAC_ETH1_HWADDR
-	if (chip_max_units > 1)
-	  sbmac_setup_hwaddr(1,SBMAC_ETH1_HWADDR);
+	sbmac_setup_hwaddr(1, SBMAC_ETH1_HWADDR);
 #endif
 #ifdef SBMAC_ETH2_HWADDR
-	if (chip_max_units > 2)
-	  sbmac_setup_hwaddr(2,SBMAC_ETH2_HWADDR);
+	sbmac_setup_hwaddr(2, SBMAC_ETH2_HWADDR);
 #endif
 #ifdef SBMAC_ETH3_HWADDR
-	if (chip_max_units > 3)
-	  sbmac_setup_hwaddr(3,SBMAC_ETH3_HWADDR);
+	sbmac_setup_hwaddr(3, SBMAC_ETH3_HWADDR);
 #endif
 
+	sbmac_pldev = kcalloc(sbmac_max_units, sizeof(*sbmac_pldev),
+			      GFP_KERNEL);
+	if (!sbmac_pldev) {
+		printk(KERN_ERR "%s: unable to allocate memory\n",
+		       sbmac_string);
+		return;
+	}
+
 	/*
 	 * Walk through the Ethernet controllers and find
 	 * those who have their MAC addresses set.
 	 */
-	for (idx = 0; idx < chip_max_units; idx++) {
-
-	        /*
-	         * This is the base address of the MAC.
-		 */
-
-	        port = A_MAC_CHANNEL_BASE(idx);
-
-		/*
-		 * The R_MAC_ETHERNET_ADDR register will be set to some nonzero
-		 * value for us by the firmware if we are going to use this MAC.
-		 * If we find a zero, skip this MAC.
-		 */
-
-		sbmac_orig_hwaddr[idx] = __raw_readq(IOADDR(port+R_MAC_ETHERNET_ADDR));
-		if (sbmac_orig_hwaddr[idx] == 0) {
-			printk(KERN_DEBUG "sbmac: not configuring MAC at "
-			       "%lx\n", port);
-		    continue;
-		}
-
-		/*
-		 * Okay, cool.  Initialize this MAC.
-		 */
-
-		dev = alloc_etherdev(sizeof(struct sbmac_softc));
-		if (!dev)
-			return -ENOMEM;
-
-		printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port);
-
-		dev->irq = UNIT_INT(idx);
-		dev->base_addr = port;
-		dev->mem_end = 0;
-		if (sbmac_init(dev, idx)) {
-			port = A_MAC_CHANNEL_BASE(idx);
-			__raw_writeq(sbmac_orig_hwaddr[idx], IOADDR(port+R_MAC_ETHERNET_ADDR));
-			free_netdev(dev);
-			continue;
-		}
-		dev_sbmac[idx] = dev;
-	}
-	return 0;
+	for (i = 0; i < sbmac_max_units; i++)
+		if (sbmac_platform_probe_one(i))
+			break;
 }
 
 
-static void __exit
-sbmac_cleanup_module(void)
+static void __exit sbmac_platform_cleanup(void)
 {
-	struct net_device *dev;
-	int idx;
+	int i;
 
-	for (idx = 0; idx < MAX_UNITS; idx++) {
-		struct sbmac_softc *sc;
-		dev = dev_sbmac[idx];
-		if (!dev)
-			continue;
+	for (i = 0; i < sbmac_max_units; i++)
+		platform_device_unregister(sbmac_pldev[i]);
+	kfree(sbmac_pldev);
+}
 
-		sc = netdev_priv(dev);
-		unregister_netdev(dev);
-		sbmac_uninitctx(sc);
-		free_netdev(dev);
-	}
+
+static struct platform_driver sbmac_driver = {
+	.probe = sbmac_probe,
+	.remove = __exit_p(sbmac_remove),
+	.driver = {
+		.name = sbmac_string,
+	},
+};
+
+static int __init sbmac_init_module(void)
+{
+	int err;
+
+	err = platform_driver_register(&sbmac_driver);
+	if (err)
+		return err;
+
+	sbmac_platform_probe();
+
+	return err;
+}
+
+static void __exit sbmac_cleanup_module(void)
+{
+	sbmac_platform_cleanup();
+	platform_driver_unregister(&sbmac_driver);
 }
 
 module_init(sbmac_init_module);
diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c
index 5b7284c..37b4239 100644
--- a/drivers/net/sc92031.c
+++ b/drivers/net/sc92031.c
@@ -1372,9 +1372,14 @@
 				SILAN_STATS_NUM * ETH_GSTRING_LEN);
 }
 
-static int sc92031_ethtool_get_stats_count(struct net_device *dev)
+static int sc92031_ethtool_get_sset_count(struct net_device *dev, int sset)
 {
-	return SILAN_STATS_NUM;
+	switch (sset) {
+	case ETH_SS_STATS:
+		return SILAN_STATS_NUM;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev,
@@ -1396,14 +1401,9 @@
 	.set_wol		= sc92031_ethtool_set_wol,
 	.nway_reset		= sc92031_ethtool_nway_reset,
 	.get_link		= ethtool_op_get_link,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.get_sg			= ethtool_op_get_sg,
-	.get_tso		= ethtool_op_get_tso,
 	.get_strings		= sc92031_ethtool_get_strings,
-	.get_stats_count	= sc92031_ethtool_get_stats_count,
+	.get_sset_count		= sc92031_ethtool_get_sset_count,
 	.get_ethtool_stats	= sc92031_ethtool_get_ethtool_stats,
-	.get_perm_addr		= ethtool_op_get_perm_addr,
-	.get_ufo		= ethtool_op_get_ufo,
 };
 
 static int __devinit sc92031_probe(struct pci_dev *pdev,
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index 4bce7c4..48c64fb 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -67,7 +67,6 @@
 
 /* Information that need to be kept for each board. */
 struct net_local {
-	struct net_device_stats stats;
 	unsigned short receive_ptr;		/* What address in packet memory do we expect a recv_pkt_header? */
 	long open_time;				/* Useless example local info. */
 };
@@ -86,7 +85,6 @@
 static irqreturn_t seeq8005_interrupt(int irq, void *dev_id);
 static void seeq8005_rx(struct net_device *dev);
 static int seeq8005_close(struct net_device *dev);
-static struct net_device_stats *seeq8005_get_stats(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
 
 /* Example routines you must write ;->. */
@@ -160,6 +158,7 @@
 	int old_dmaar;
 	int old_rear;
 	int retval;
+	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, SEEQ8005_IO_EXTENT, "seeq8005"))
 		return -ENODEV;
@@ -303,7 +302,8 @@
 
 	/* Retrieve and print the ethernet address. */
 	for (i = 0; i < 6; i++)
-		printk(" %2.2x", dev->dev_addr[i] = SA_prom[i+6]);
+		dev->dev_addr[i] = SA_prom[i+6];
+	printk("%s", print_mac(mac, dev->dev_addr));
 
 	if (dev->irq == 0xff)
 		;			/* Do nothing: a user-level program will set it. */
@@ -338,7 +338,6 @@
 	dev->hard_start_xmit 	= seeq8005_send_packet;
 	dev->tx_timeout		= seeq8005_timeout;
 	dev->watchdog_timeo	= HZ/20;
-	dev->get_stats		= seeq8005_get_stats;
 	dev->set_multicast_list = set_multicast_list;
 	dev->flags &= ~IFF_MULTICAST;
 
@@ -391,7 +390,6 @@
 
 static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-	struct net_local *lp = netdev_priv(dev);
 	short length = skb->len;
 	unsigned char *buf;
 
@@ -407,7 +405,7 @@
 
 	hardware_send_packet(dev, buf, length);
 	dev->trans_start = jiffies;
-	lp->stats.tx_bytes += length;
+	dev->stats.tx_bytes += length;
 	dev_kfree_skb (skb);
 	/* You might need to clean up and record Tx statistics here. */
 
@@ -463,7 +461,7 @@
 		if (status & SEEQSTAT_TX_INT) {
 			handled = 1;
 			outw( SEEQCMD_TX_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-			lp->stats.tx_packets++;
+			dev->stats.tx_packets++;
 			netif_wake_queue(dev);	/* Inform upper layers. */
 		}
 		if (status & SEEQSTAT_RX_INT) {
@@ -531,11 +529,11 @@
 		}
 
 		if (pkt_hdr & SEEQPKTS_ANY_ERROR) {				/* There was an error. */
-			lp->stats.rx_errors++;
-			if (pkt_hdr & SEEQPKTS_SHORT) lp->stats.rx_frame_errors++;
-			if (pkt_hdr & SEEQPKTS_DRIB) lp->stats.rx_frame_errors++;
-			if (pkt_hdr & SEEQPKTS_OVERSIZE) lp->stats.rx_over_errors++;
-			if (pkt_hdr & SEEQPKTS_CRC_ERR) lp->stats.rx_crc_errors++;
+			dev->stats.rx_errors++;
+			if (pkt_hdr & SEEQPKTS_SHORT) dev->stats.rx_frame_errors++;
+			if (pkt_hdr & SEEQPKTS_DRIB) dev->stats.rx_frame_errors++;
+			if (pkt_hdr & SEEQPKTS_OVERSIZE) dev->stats.rx_over_errors++;
+			if (pkt_hdr & SEEQPKTS_CRC_ERR) dev->stats.rx_crc_errors++;
 			/* skip over this packet */
 			outw( SEEQCMD_FIFO_WRITE | SEEQCMD_DMA_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
 			outw( (lp->receive_ptr & 0xff00)>>8, SEEQ_REA);
@@ -547,7 +545,7 @@
 			skb = dev_alloc_skb(pkt_len);
 			if (skb == NULL) {
 				printk("%s: Memory squeeze, dropping packet.\n", dev->name);
-				lp->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 				break;
 			}
 			skb_reserve(skb, 2);	/* align data on 16 byte */
@@ -567,8 +565,8 @@
 			skb->protocol=eth_type_trans(skb,dev);
 			netif_rx(skb);
 			dev->last_rx = jiffies;
-			lp->stats.rx_packets++;
-			lp->stats.rx_bytes += pkt_len;
+			dev->stats.rx_packets++;
+			dev->stats.rx_bytes += pkt_len;
 		}
 	} while ((--boguscount) && (pkt_hdr & SEEQPKTH_CHAIN));
 
@@ -599,15 +597,6 @@
 
 }
 
-/* Get the current statistics.	This may be called with the card open or
-   closed. */
-static struct net_device_stats *seeq8005_get_stats(struct net_device *dev)
-{
-	struct net_local *lp = netdev_priv(dev);
-
-	return &lp->stats;
-}
-
 /* Set or clear the multicast filter for this adaptor.
    num_addrs == -1	Promiscuous mode, receive all packets
    num_addrs == 0	Normal mode, clear multicast list
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index 384b468..ff40563 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -75,6 +75,7 @@
 
 struct sgiseeq_private {
 	struct sgiseeq_init_block *srings;
+	dma_addr_t srings_dma;
 
 	/* Ptrs to the descriptors in uncached space. */
 	struct sgiseeq_rx_desc *rx_desc;
@@ -92,8 +93,6 @@
 	unsigned char control;
 	unsigned char mode;
 
-	struct net_device_stats stats;
-
 	spinlock_t tx_lock;
 };
 
@@ -266,18 +265,17 @@
 	return 0;
 }
 
-static inline void record_rx_errors(struct sgiseeq_private *sp,
-				    unsigned char status)
+static void record_rx_errors(struct net_device *dev, unsigned char status)
 {
 	if (status & SEEQ_RSTAT_OVERF ||
 	    status & SEEQ_RSTAT_SFRAME)
-		sp->stats.rx_over_errors++;
+		dev->stats.rx_over_errors++;
 	if (status & SEEQ_RSTAT_CERROR)
-		sp->stats.rx_crc_errors++;
+		dev->stats.rx_crc_errors++;
 	if (status & SEEQ_RSTAT_DERROR)
-		sp->stats.rx_frame_errors++;
+		dev->stats.rx_frame_errors++;
 	if (status & SEEQ_RSTAT_REOF)
-		sp->stats.rx_errors++;
+		dev->stats.rx_errors++;
 }
 
 static inline void rx_maybe_restart(struct sgiseeq_private *sp,
@@ -327,8 +325,8 @@
 				if (memcmp(eth_hdr(skb)->h_source, dev->dev_addr, ETH_ALEN)) {
 					netif_rx(skb);
 					dev->last_rx = jiffies;
-					sp->stats.rx_packets++;
-					sp->stats.rx_bytes += len;
+					dev->stats.rx_packets++;
+					dev->stats.rx_bytes += len;
 				} else {
 					/* Silently drop my own packets */
 					dev_kfree_skb_irq(skb);
@@ -336,10 +334,10 @@
 			} else {
 				printk (KERN_NOTICE "%s: Memory squeeze, deferring packet.\n",
 					dev->name);
-				sp->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 			}
 		} else {
-			record_rx_errors(sp, pkt_status);
+			record_rx_errors(dev, pkt_status);
 		}
 
 		/* Return the entry to the ring pool. */
@@ -391,11 +389,11 @@
 	if (!(status & (HPC3_ETXCTRL_ACTIVE | SEEQ_TSTAT_PTRANS))) {
 		/* Oops, HPC detected some sort of error. */
 		if (status & SEEQ_TSTAT_R16)
-			sp->stats.tx_aborted_errors++;
+			dev->stats.tx_aborted_errors++;
 		if (status & SEEQ_TSTAT_UFLOW)
-			sp->stats.tx_fifo_errors++;
+			dev->stats.tx_fifo_errors++;
 		if (status & SEEQ_TSTAT_LCLS)
-			sp->stats.collisions++;
+			dev->stats.collisions++;
 	}
 
 	/* Ack 'em... */
@@ -411,7 +409,7 @@
 			}
 			break;
 		}
-		sp->stats.tx_packets++;
+		dev->stats.tx_packets++;
 		sp->tx_old = NEXT_TX(sp->tx_old);
 		td->tdma.cntinfo &= ~(HPCDMA_XIU | HPCDMA_XIE);
 		td->tdma.cntinfo |= HPCDMA_EOX;
@@ -515,7 +513,7 @@
 	/* Setup... */
 	skblen = skb->len;
 	len = (skblen <= ETH_ZLEN) ? ETH_ZLEN : skblen;
-	sp->stats.tx_bytes += len;
+	dev->stats.tx_bytes += len;
 	entry = sp->tx_new;
 	td = &sp->tx_desc[entry];
 
@@ -568,13 +566,6 @@
 	netif_wake_queue(dev);
 }
 
-static struct net_device_stats *sgiseeq_get_stats(struct net_device *dev)
-{
-	struct sgiseeq_private *sp = netdev_priv(dev);
-
-	return &sp->stats;
-}
-
 static void sgiseeq_set_multicast(struct net_device *dev)
 {
 	struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv;
@@ -631,6 +622,7 @@
 	struct sgiseeq_private *sp;
 	struct net_device *dev;
 	int err, i;
+	DECLARE_MAC_BUF(mac);
 
 	dev = alloc_etherdev(sizeof (struct sgiseeq_private));
 	if (!dev) {
@@ -643,13 +635,20 @@
 	sp = netdev_priv(dev);
 
 	/* Make private data page aligned */
-	sr = (struct sgiseeq_init_block *) get_zeroed_page(GFP_KERNEL);
+	sr = dma_alloc_coherent(&pdev->dev, sizeof(*sp->srings),
+				&sp->srings_dma, GFP_KERNEL);
 	if (!sr) {
 		printk(KERN_ERR "Sgiseeq: Page alloc failed, aborting.\n");
 		err = -ENOMEM;
 		goto err_out_free_dev;
 	}
 	sp->srings = sr;
+	sp->rx_desc = sp->srings->rxvector;
+	sp->tx_desc = sp->srings->txvector;
+
+	/* A couple calculations now, saves many cycles later. */
+	setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS);
+	setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS);
 
 	memcpy(dev->dev_addr, pd->mac, ETH_ALEN);
 
@@ -662,19 +661,6 @@
 	sp->name = sgiseeqstr;
 	sp->mode = SEEQ_RCMD_RBCAST;
 
-	sp->rx_desc = (struct sgiseeq_rx_desc *)
-	              CKSEG1ADDR(ALIGNED(&sp->srings->rxvector[0]));
-	dma_cache_wback_inv((unsigned long)&sp->srings->rxvector,
-	                    sizeof(sp->srings->rxvector));
-	sp->tx_desc = (struct sgiseeq_tx_desc *)
-	              CKSEG1ADDR(ALIGNED(&sp->srings->txvector[0]));
-	dma_cache_wback_inv((unsigned long)&sp->srings->txvector,
-	                    sizeof(sp->srings->txvector));
-
-	/* A couple calculations now, saves many cycles later. */
-	setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS);
-	setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS);
-
 	/* Setup PIO and DMA transfer timing */
 	sp->hregs->pconfig = 0x161;
 	sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP |
@@ -699,7 +685,6 @@
 	dev->hard_start_xmit	= sgiseeq_start_xmit;
 	dev->tx_timeout		= timeout;
 	dev->watchdog_timeo	= (200 * HZ) / 1000;
-	dev->get_stats		= sgiseeq_get_stats;
 	dev->set_multicast_list	= sgiseeq_set_multicast;
 	dev->set_mac_address	= sgiseeq_set_mac_address;
 	dev->irq		= irq;
@@ -711,9 +696,8 @@
 		goto err_out_free_page;
 	}
 
-	printk(KERN_INFO "%s: %s ", dev->name, sgiseeqstr);
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+	printk(KERN_INFO "%s: %s %s\n",
+	       dev->name, sgiseeqstr, print_mac(mac, dev->dev_addr));
 
 	return 0;
 
@@ -726,15 +710,18 @@
 	return err;
 }
 
-static void __exit sgiseeq_remove(struct platform_device *pdev)
+static int __exit sgiseeq_remove(struct platform_device *pdev)
 {
 	struct net_device *dev = platform_get_drvdata(pdev);
 	struct sgiseeq_private *sp = netdev_priv(dev);
 
 	unregister_netdev(dev);
-	free_page((unsigned long) sp->srings);
+	dma_free_coherent(&pdev->dev, sizeof(*sp->srings), sp->srings,
+	                  sp->srings_dma);
 	free_netdev(dev);
 	platform_set_drvdata(pdev, NULL);
+
+	return 0;
 }
 
 static struct platform_driver sgiseeq_driver = {
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c
index e886e8d..228f650 100644
--- a/drivers/net/shaper.c
+++ b/drivers/net/shaper.c
@@ -86,6 +86,7 @@
 
 #include <net/dst.h>
 #include <net/arp.h>
+#include <net/net_namespace.h>
 
 struct shaper_cb {
 	unsigned long	shapeclock;		/* Time it should go out */
@@ -170,7 +171,7 @@
 		 */
 		if(time_after(SHAPERCB(skb)->shapeclock,jiffies + SHAPER_LATENCY)) {
 			dev_kfree_skb(skb);
-			shaper->stats.tx_dropped++;
+			dev->stats.tx_dropped++;
 		} else
 			skb_queue_tail(&shaper->sendq, skb);
 	}
@@ -181,7 +182,7 @@
  	{
  		ptr=skb_dequeue(&shaper->sendq);
                 dev_kfree_skb(ptr);
-                shaper->stats.collisions++;
+                dev->stats.collisions++;
  	}
 	shaper_kick(shaper);
 	spin_unlock(&shaper->lock);
@@ -206,8 +207,8 @@
 				shaper->dev->name,newskb->priority);
 		dev_queue_xmit(newskb);
 
-                shaper->stats.tx_bytes += skb->len;
-		shaper->stats.tx_packets++;
+                shaper->dev->stats.tx_bytes += skb->len;
+		shaper->dev->stats.tx_packets++;
 
                 if(sh_debug)
 			printk("Kicked new frame out.\n");
@@ -329,22 +330,17 @@
  *	ARP and other resolutions and not before.
  */
 
-static struct net_device_stats *shaper_get_stats(struct net_device *dev)
-{
-     	struct shaper *sh=dev->priv;
-	return &sh->stats;
-}
-
 static int shaper_header(struct sk_buff *skb, struct net_device *dev,
-	unsigned short type, void *daddr, void *saddr, unsigned len)
+			 unsigned short type,
+			 const void *daddr, const void *saddr, unsigned len)
 {
 	struct shaper *sh=dev->priv;
 	int v;
 	if(sh_debug)
 		printk("Shaper header\n");
-	skb->dev=sh->dev;
-	v=sh->hard_header(skb,sh->dev,type,daddr,saddr,len);
-	skb->dev=dev;
+	skb->dev = sh->dev;
+	v = dev_hard_header(skb, sh->dev, type, daddr, saddr, len);
+	skb->dev = dev;
 	return v;
 }
 
@@ -356,7 +352,7 @@
 	if(sh_debug)
 		printk("Shaper rebuild header\n");
 	skb->dev=sh->dev;
-	v=sh->rebuild_header(skb);
+	v = sh->dev->header_ops->rebuild(skb);
 	skb->dev=dev;
 	return v;
 }
@@ -420,51 +416,17 @@
 
 #endif
 
+static const struct header_ops shaper_ops = {
+	.create	 = shaper_header,
+	.rebuild = shaper_rebuild_header,
+};
+
 static int shaper_attach(struct net_device *shdev, struct shaper *sh, struct net_device *dev)
 {
 	sh->dev = dev;
-	sh->hard_start_xmit=dev->hard_start_xmit;
 	sh->get_stats=dev->get_stats;
-	if(dev->hard_header)
-	{
-		sh->hard_header=dev->hard_header;
-		shdev->hard_header = shaper_header;
-	}
-	else
-		shdev->hard_header = NULL;
 
-	if(dev->rebuild_header)
-	{
-		sh->rebuild_header	= dev->rebuild_header;
-		shdev->rebuild_header	= shaper_rebuild_header;
-	}
-	else
-		shdev->rebuild_header	= NULL;
-
-#if 0
-	if(dev->hard_header_cache)
-	{
-		sh->hard_header_cache	= dev->hard_header_cache;
-		shdev->hard_header_cache= shaper_cache;
-	}
-	else
-	{
-		shdev->hard_header_cache= NULL;
-	}
-
-	if(dev->header_cache_update)
-	{
-		sh->header_cache_update	= dev->header_cache_update;
-		shdev->header_cache_update = shaper_cache_update;
-	}
-	else
-		shdev->header_cache_update= NULL;
-#else
-	shdev->header_cache_update = NULL;
-	shdev->hard_header_cache = NULL;
-#endif
 	shdev->neigh_setup = shaper_neigh_setup_dev;
-
 	shdev->hard_header_len=dev->hard_header_len;
 	shdev->type=dev->type;
 	shdev->addr_len=dev->addr_len;
@@ -488,7 +450,7 @@
 	{
 		case SHAPER_SET_DEV:
 		{
-			struct net_device *them=__dev_get_by_name(ss->ss_name);
+			struct net_device *them=__dev_get_by_name(&init_net, ss->ss_name);
 			if(them==NULL)
 				return -ENODEV;
 			if(sh->dev)
@@ -532,14 +494,11 @@
 	 *	Set up the shaper.
 	 */
 
-	SET_MODULE_OWNER(dev);
-
 	shaper_init_priv(dev);
 
 	dev->open		= shaper_open;
 	dev->stop		= shaper_close;
 	dev->hard_start_xmit 	= shaper_start_xmit;
-	dev->get_stats 		= shaper_get_stats;
 	dev->set_multicast_list = NULL;
 
 	/*
@@ -550,12 +509,6 @@
 	 *	Handlers for when we attach to a device.
 	 */
 
-	dev->hard_header 	= shaper_header;
-	dev->rebuild_header 	= shaper_rebuild_header;
-#if 0
-	dev->hard_header_cache	= shaper_cache;
-	dev->header_cache_update= shaper_cache_update;
-#endif
 	dev->neigh_setup	= shaper_neigh_setup_dev;
 	dev->do_ioctl		= shaper_ioctl;
 	dev->hard_header_len	= 0;
@@ -600,10 +553,9 @@
 		return -ENODEV;
 
 	alloc_size = sizeof(*dev) * shapers;
-	devs = kmalloc(alloc_size, GFP_KERNEL);
+	devs = kzalloc(alloc_size, GFP_KERNEL);
 	if (!devs)
 		return -ENOMEM;
-	memset(devs, 0, alloc_size);
 
 	for (i = 0; i < shapers; i++) {
 
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index ec2ad9f..7200883 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -47,24 +47,13 @@
 #define PHY_ID_ANY		0x1f
 #define MII_REG_ANY		0x1f
 
-#ifdef CONFIG_SIS190_NAPI
-#define NAPI_SUFFIX	"-NAPI"
-#else
-#define NAPI_SUFFIX	""
-#endif
-
-#define DRV_VERSION		"1.2" NAPI_SUFFIX
+#define DRV_VERSION		"1.2"
 #define DRV_NAME		"sis190"
 #define SIS190_DRIVER_NAME	DRV_NAME " Gigabit Ethernet driver " DRV_VERSION
 #define PFX DRV_NAME ": "
 
-#ifdef CONFIG_SIS190_NAPI
-#define sis190_rx_skb			netif_receive_skb
-#define sis190_rx_quota(count, quota)	min(count, quota)
-#else
 #define sis190_rx_skb			netif_rx
 #define sis190_rx_quota(count, quota)	count
-#endif
 
 #define MAC_ADDR_LEN		6
 
@@ -281,7 +270,6 @@
 	void __iomem *mmio_addr;
 	struct pci_dev *pci_dev;
 	struct net_device *dev;
-	struct net_device_stats stats;
 	spinlock_t lock;
 	u32 rx_buf_sz;
 	u32 cur_rx;
@@ -580,7 +568,7 @@
 static int sis190_rx_interrupt(struct net_device *dev,
 			       struct sis190_private *tp, void __iomem *ioaddr)
 {
-	struct net_device_stats *stats = &tp->stats;
+	struct net_device_stats *stats = &dev->stats;
 	u32 rx_left, cur_rx = tp->cur_rx;
 	u32 delta, count;
 
@@ -694,8 +682,8 @@
 
 		skb = tp->Tx_skbuff[entry];
 
-		tp->stats.tx_packets++;
-		tp->stats.tx_bytes += skb->len;
+		dev->stats.tx_packets++;
+		dev->stats.tx_bytes += skb->len;
 
 		sis190_unmap_tx_skb(tp->pci_dev, skb, txd);
 		tp->Tx_skbuff[entry] = NULL;
@@ -1091,7 +1079,7 @@
 		tp->Tx_skbuff[i] = NULL;
 		dev_kfree_skb(skb);
 
-		tp->stats.tx_dropped++;
+		tp->dev->stats.tx_dropped++;
 	}
 	tp->cur_tx = tp->dirty_tx = 0;
 }
@@ -1115,10 +1103,8 @@
 
 		synchronize_irq(dev->irq);
 
-		if (!poll_locked) {
-			netif_poll_disable(dev);
+		if (!poll_locked)
 			poll_locked++;
-		}
 
 		synchronize_sched();
 
@@ -1137,8 +1123,6 @@
 
 	free_irq(dev->irq, dev);
 
-	netif_poll_enable(dev);
-
 	pci_free_consistent(pdev, TX_RING_BYTES, tp->TxDescRing, tp->tx_dma);
 	pci_free_consistent(pdev, RX_RING_BYTES, tp->RxDescRing, tp->rx_dma);
 
@@ -1158,7 +1142,7 @@
 
 	if (unlikely(skb->len < ETH_ZLEN)) {
 		if (skb_padto(skb, ETH_ZLEN)) {
-			tp->stats.tx_dropped++;
+			dev->stats.tx_dropped++;
 			goto out;
 		}
 		len = ETH_ZLEN;
@@ -1211,13 +1195,6 @@
 	return NETDEV_TX_OK;
 }
 
-static struct net_device_stats *sis190_get_stats(struct net_device *dev)
-{
-	struct sis190_private *tp = netdev_priv(dev);
-
-	return &tp->stats;
-}
-
 static void sis190_free_phy(struct list_head *first_phy)
 {
 	struct sis190_phy *cur, *next;
@@ -1436,7 +1413,6 @@
 		goto err_out_0;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	tp = netdev_priv(dev);
@@ -1593,6 +1569,9 @@
 		  pci_name(pdev));
 
 	isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0965, NULL);
+	if (!isa_bridge)
+		isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0966, NULL);
+
 	if (!isa_bridge) {
 		net_probe(tp, KERN_INFO "%s: Can not find ISA bridge.\n",
 			  pci_name(pdev));
@@ -1780,6 +1759,7 @@
 	struct net_device *dev;
 	void __iomem *ioaddr;
 	int rc;
+	DECLARE_MAC_BUF(mac);
 
 	if (!printed_version) {
 		net_drv(&debug, KERN_INFO SIS190_DRIVER_NAME " loaded.\n");
@@ -1808,7 +1788,6 @@
 	dev->open = sis190_open;
 	dev->stop = sis190_close;
 	dev->do_ioctl = sis190_ioctl;
-	dev->get_stats = sis190_get_stats;
 	dev->tx_timeout = sis190_tx_timeout;
 	dev->watchdog_timeo = SIS190_TX_TIMEOUT;
 	dev->hard_start_xmit = sis190_start_xmit;
@@ -1831,12 +1810,9 @@
 		goto err_remove_mii;
 
 	net_probe(tp, KERN_INFO "%s: %s at %p (IRQ: %d), "
-	       "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
-	       pci_name(pdev), sis_chip_info[ent->driver_data].name,
-	       ioaddr, dev->irq,
-	       dev->dev_addr[0], dev->dev_addr[1],
-	       dev->dev_addr[2], dev->dev_addr[3],
-	       dev->dev_addr[4], dev->dev_addr[5]);
+		  "%s\n",
+		  pci_name(pdev), sis_chip_info[ent->driver_data].name,
+		  ioaddr, dev->irq, print_mac(mac, dev->dev_addr));
 
 	net_probe(tp, KERN_INFO "%s: %s mode.\n", dev->name,
 		  (tp->features & F_HAS_RGMII) ? "RGMII" : "GMII");
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 7c6e480..0857d2c 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -158,7 +158,6 @@
 } BufferDesc;
 
 struct sis900_private {
-	struct net_device_stats stats;
 	struct pci_dev * pci_dev;
 
 	spinlock_t lock;
@@ -221,7 +220,6 @@
 static irqreturn_t sis900_interrupt(int irq, void *dev_instance);
 static int sis900_close(struct net_device *net_dev);
 static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd);
-static struct net_device_stats *sis900_get_stats(struct net_device *net_dev);
 static u16 sis900_mcast_bitnr(u8 *addr, u8 revision);
 static void set_rx_mode(struct net_device *net_dev);
 static void sis900_reset(struct net_device *net_dev);
@@ -406,6 +404,7 @@
 	int i, ret;
 	const char *card_name = card_names[pci_id->driver_data];
 	const char *dev_name = pci_name(pci_dev);
+	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -430,7 +429,6 @@
 	net_dev = alloc_etherdev(sizeof(struct sis900_private));
 	if (!net_dev)
 		return -ENOMEM;
-	SET_MODULE_OWNER(net_dev);
 	SET_NETDEV_DEV(net_dev, &pci_dev->dev);
 
 	/* We do a request_region() to register /proc/ioports info. */
@@ -467,7 +465,6 @@
 	net_dev->open = &sis900_open;
 	net_dev->hard_start_xmit = &sis900_start_xmit;
 	net_dev->stop = &sis900_close;
-	net_dev->get_stats = &sis900_get_stats;
 	net_dev->set_config = &sis900_set_config;
 	net_dev->set_multicast_list = &set_rx_mode;
 	net_dev->do_ioctl = &mii_ioctl;
@@ -537,11 +534,9 @@
 		goto err_unmap_rx;
 
 	/* print some information about our NIC */
-	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, ", net_dev->name,
-	       card_name, ioaddr, net_dev->irq);
-	for (i = 0; i < 5; i++)
-		printk("%2.2x:", (u8)net_dev->dev_addr[i]);
-	printk("%2.2x.\n", net_dev->dev_addr[i]);
+	printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %s\n",
+	       net_dev->name, card_name, ioaddr, net_dev->irq,
+	       print_mac(mac, net_dev->dev_addr));
 
 	/* Detect Wake on Lan support */
 	ret = (inl(net_dev->base_addr + CFGPMC) & PMESP) >> 27;
@@ -1543,7 +1538,7 @@
 			sis_priv->tx_skbuff[i] = NULL;
 			sis_priv->tx_ring[i].cmdsts = 0;
 			sis_priv->tx_ring[i].bufptr = 0;
-			sis_priv->stats.tx_dropped++;
+			net_dev->stats.tx_dropped++;
 		}
 	}
 	sis_priv->tx_full = 0;
@@ -1740,15 +1735,15 @@
 				printk(KERN_DEBUG "%s: Corrupted packet "
 				       "received, buffer status = 0x%8.8x/%d.\n",
 				       net_dev->name, rx_status, data_size);
-			sis_priv->stats.rx_errors++;
+			net_dev->stats.rx_errors++;
 			if (rx_status & OVERRUN)
-				sis_priv->stats.rx_over_errors++;
+				net_dev->stats.rx_over_errors++;
 			if (rx_status & (TOOLONG|RUNT))
-				sis_priv->stats.rx_length_errors++;
+				net_dev->stats.rx_length_errors++;
 			if (rx_status & (RXISERR | FAERR))
-				sis_priv->stats.rx_frame_errors++;
+				net_dev->stats.rx_frame_errors++;
 			if (rx_status & CRCERR)
-				sis_priv->stats.rx_crc_errors++;
+				net_dev->stats.rx_crc_errors++;
 			/* reset buffer descriptor state */
 			sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
 		} else {
@@ -1769,7 +1764,7 @@
 				 * in the rx ring
 				 */
 				skb = sis_priv->rx_skbuff[entry];
-				sis_priv->stats.rx_dropped++;
+				net_dev->stats.rx_dropped++;
 				goto refill_rx_ring;
 			}	
 
@@ -1794,10 +1789,10 @@
 
 			/* some network statistics */
 			if ((rx_status & BCAST) == MCAST)
-				sis_priv->stats.multicast++;
+				net_dev->stats.multicast++;
 			net_dev->last_rx = jiffies;
-			sis_priv->stats.rx_bytes += rx_size;
-			sis_priv->stats.rx_packets++;
+			net_dev->stats.rx_bytes += rx_size;
+			net_dev->stats.rx_packets++;
 			sis_priv->dirty_rx++;
 refill_rx_ring:
 			sis_priv->rx_skbuff[entry] = skb;
@@ -1828,7 +1823,7 @@
 					printk(KERN_INFO "%s: Memory squeeze,"
 						"deferring packet.\n",
 						net_dev->name);
-				sis_priv->stats.rx_dropped++;
+				net_dev->stats.rx_dropped++;
 				break;
 			}
 			sis_priv->rx_skbuff[entry] = skb;
@@ -1879,20 +1874,20 @@
 				printk(KERN_DEBUG "%s: Transmit "
 				       "error, Tx status %8.8x.\n",
 				       net_dev->name, tx_status);
-			sis_priv->stats.tx_errors++;
+			net_dev->stats.tx_errors++;
 			if (tx_status & UNDERRUN)
-				sis_priv->stats.tx_fifo_errors++;
+				net_dev->stats.tx_fifo_errors++;
 			if (tx_status & ABORT)
-				sis_priv->stats.tx_aborted_errors++;
+				net_dev->stats.tx_aborted_errors++;
 			if (tx_status & NOCARRIER)
-				sis_priv->stats.tx_carrier_errors++;
+				net_dev->stats.tx_carrier_errors++;
 			if (tx_status & OWCOLL)
-				sis_priv->stats.tx_window_errors++;
+				net_dev->stats.tx_window_errors++;
 		} else {
 			/* packet successfully transmitted */
-			sis_priv->stats.collisions += (tx_status & COLCNT) >> 16;
-			sis_priv->stats.tx_bytes += tx_status & DSIZE;
-			sis_priv->stats.tx_packets++;
+			net_dev->stats.collisions += (tx_status & COLCNT) >> 16;
+			net_dev->stats.tx_bytes += tx_status & DSIZE;
+			net_dev->stats.tx_packets++;
 		}
 		/* Free the original skb. */
 		skb = sis_priv->tx_skbuff[entry];
@@ -2139,21 +2134,6 @@
 }
 
 /**
- *	sis900_get_stats - Get sis900 read/write statistics
- *	@net_dev: the net device to get statistics for
- *
- *	get tx/rx statistics for sis900
- */
-
-static struct net_device_stats *
-sis900_get_stats(struct net_device *net_dev)
-{
-	struct sis900_private *sis_priv = net_dev->priv;
-
-	return &sis_priv->stats;
-}
-
-/**
  *	sis900_set_config - Set media type by net_device.set_config
  *	@dev: the net device for media type change
  *	@map: ifmap passed by ifconfig
diff --git a/drivers/net/sk98lin/Makefile b/drivers/net/sk98lin/Makefile
new file mode 100644
index 0000000..afd900d
--- /dev/null
+++ b/drivers/net/sk98lin/Makefile
@@ -0,0 +1,87 @@
+#
+# Makefile for the SysKonnect SK-98xx device driver.
+#
+
+
+#
+# Standalone driver params
+# SKPARAM += -DSK_KERNEL_24
+# SKPARAM += -DSK_KERNEL_24_26
+# SKPARAM += -DSK_KERNEL_26
+# SKPARAM += -DSK_KERNEL_22_24
+
+obj-$(CONFIG_SK98LIN) += sk98lin.o
+sk98lin-objs    :=	\
+		skge.o		\
+		skethtool.o	\
+		skdim.o		\
+		skaddr.o	\
+		skgehwt.o	\
+		skgeinit.o	\
+		skgepnmi.o	\
+		skgesirq.o	\
+		ski2c.o		\
+		sklm80.o	\
+		skqueue.o	\
+		skrlmt.o	\
+		sktimer.o	\
+		skvpd.o		\
+		skxmac2.o
+
+# DBGDEF =  \
+# -DDEBUG
+
+ifdef DEBUG
+DBGDEF +=  \
+-DSK_DEBUG_CHKMOD=0x00000000L \
+-DSK_DEBUG_CHKCAT=0x00000000L
+endif
+
+
+# **** possible debug modules for SK_DEBUG_CHKMOD *****************
+# SK_DBGMOD_MERR        0x00000001L     /* general module error indication */
+# SK_DBGMOD_HWM         0x00000002L     /* Hardware init module */
+# SK_DBGMOD_RLMT        0x00000004L     /* RLMT module */
+# SK_DBGMOD_VPD         0x00000008L     /* VPD module */
+# SK_DBGMOD_I2C         0x00000010L     /* I2C module */
+# SK_DBGMOD_PNMI        0x00000020L     /* PNMI module */
+# SK_DBGMOD_CSUM        0x00000040L     /* CSUM module */
+# SK_DBGMOD_ADDR        0x00000080L     /* ADDR module */
+# SK_DBGMOD_DRV         0x00010000L     /* DRV module */
+
+# **** possible debug categories for SK_DEBUG_CHKCAT **************
+# *** common modules ***
+# SK_DBGCAT_INIT        0x00000001L     module/driver initialization
+# SK_DBGCAT_CTRL        0x00000002L     controlling: add/rmv MCA/MAC and other controls (IOCTL)
+# SK_DBGCAT_ERR         0x00000004L     error handling paths
+# SK_DBGCAT_TX          0x00000008L     transmit path
+# SK_DBGCAT_RX          0x00000010L     receive path
+# SK_DBGCAT_IRQ         0x00000020L     general IRQ handling
+# SK_DBGCAT_QUEUE       0x00000040L     any queue management
+# SK_DBGCAT_DUMP        0x00000080L     large data output e.g. hex dump
+# SK_DBGCAT_FATAL       0x00000100L     large data output e.g. hex dump
+
+# *** driver (file skge.c) ***
+# SK_DBGCAT_DRV_ENTRY           0x00010000      entry points
+# SK_DBGCAT_DRV_???             0x00020000      not used
+# SK_DBGCAT_DRV_MCA             0x00040000      multicast
+# SK_DBGCAT_DRV_TX_PROGRESS     0x00080000      tx path
+# SK_DBGCAT_DRV_RX_PROGRESS     0x00100000      rx path
+# SK_DBGCAT_DRV_PROGRESS        0x00200000      general runtime
+# SK_DBGCAT_DRV_???             0x00400000      not used
+# SK_DBGCAT_DRV_PROM            0x00800000      promiscuous mode
+# SK_DBGCAT_DRV_TX_FRAME        0x01000000      display tx frames
+# SK_DBGCAT_DRV_ERROR           0x02000000      error conditions
+# SK_DBGCAT_DRV_INT_SRC         0x04000000      interrupts sources
+# SK_DBGCAT_DRV_EVENT           0x08000000      driver events
+
+EXTRA_CFLAGS += -Idrivers/net/sk98lin -DSK_DIAG_SUPPORT -DGENESIS -DYUKON $(DBGDEF) $(SKPARAM)
+
+clean:
+	rm -f core *.o *.a *.s
+
+
+
+
+
+
diff --git a/drivers/net/sk98lin/h/lm80.h b/drivers/net/sk98lin/h/lm80.h
new file mode 100644
index 0000000..4e2dbbf
--- /dev/null
+++ b/drivers/net/sk98lin/h/lm80.h
@@ -0,0 +1,179 @@
+/******************************************************************************
+ *
+ * Name:	lm80.h	
+ * Project:	Gigabit Ethernet Adapters, Common Modules
+ * Version:	$Revision: 1.6 $
+ * Date:	$Date: 2003/05/13 17:26:52 $
+ * Purpose:	Contains all defines for the LM80 Chip
+ *		(National Semiconductor).
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_LM80_H
+#define __INC_LM80_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif	/* __cplusplus */
+
+/* defines ********************************************************************/
+
+/*
+ * LM80 register definition
+ *
+ * All registers are 8 bit wide
+ */
+#define LM80_CFG			0x00	/* Configuration Register */
+#define LM80_ISRC_1			0x01	/* Interrupt Status Register 1 */
+#define LM80_ISRC_2			0x02	/* Interrupt Status Register 2 */
+#define LM80_IMSK_1			0x03	/* Interrupt Mask Register 1 */
+#define LM80_IMSK_2			0x04	/* Interrupt Mask Register 2 */
+#define LM80_FAN_CTRL		0x05	/* Fan Devisor/RST#/OS# Register */
+#define LM80_TEMP_CTRL		0x06	/* OS# Config, Temp Res. Reg */
+	/* 0x07 - 0x1f reserved	*/
+	/* current values */
+#define LM80_VT0_IN			0x20	/* current Voltage 0 value */
+#define LM80_VT1_IN			0x21	/* current Voltage 1 value */
+#define LM80_VT2_IN			0x22	/* current Voltage 2 value */
+#define LM80_VT3_IN			0x23	/* current Voltage 3 value */
+#define LM80_VT4_IN			0x24	/* current Voltage 4 value */
+#define LM80_VT5_IN			0x25	/* current Voltage 5 value */
+#define LM80_VT6_IN			0x26	/* current Voltage 6 value */
+#define LM80_TEMP_IN		0x27	/* current Temperature value */
+#define LM80_FAN1_IN		0x28	/* current Fan 1 count */
+#define LM80_FAN2_IN		0x29	/* current Fan 2 count */
+	/* limit values */
+#define LM80_VT0_HIGH_LIM	0x2a	/* high limit val for Voltage 0 */
+#define LM80_VT0_LOW_LIM	0x2b	/* low limit val for Voltage 0 */
+#define LM80_VT1_HIGH_LIM	0x2c	/* high limit val for Voltage 1 */
+#define LM80_VT1_LOW_LIM	0x2d	/* low limit val for Voltage 1 */
+#define LM80_VT2_HIGH_LIM	0x2e	/* high limit val for Voltage 2 */
+#define LM80_VT2_LOW_LIM	0x2f	/* low limit val for Voltage 2 */
+#define LM80_VT3_HIGH_LIM	0x30	/* high limit val for Voltage 3 */
+#define LM80_VT3_LOW_LIM	0x31	/* low limit val for Voltage 3 */
+#define LM80_VT4_HIGH_LIM	0x32	/* high limit val for Voltage 4 */
+#define LM80_VT4_LOW_LIM	0x33	/* low limit val for Voltage 4 */
+#define LM80_VT5_HIGH_LIM	0x34	/* high limit val for Voltage 5 */
+#define LM80_VT5_LOW_LIM	0x35	/* low limit val for Voltage 5 */
+#define LM80_VT6_HIGH_LIM	0x36	/* high limit val for Voltage 6 */
+#define LM80_VT6_LOW_LIM	0x37	/* low limit val for Voltage 6 */
+#define LM80_THOT_LIM_UP	0x38	/* hot temperature limit (high) */
+#define LM80_THOT_LIM_LO	0x39	/* hot temperature limit (low) */
+#define LM80_TOS_LIM_UP		0x3a	/* OS temperature limit (high) */
+#define LM80_TOS_LIM_LO		0x3b	/* OS temperature limit (low) */
+#define LM80_FAN1_COUNT_LIM	0x3c	/* Fan 1 count limit (high) */
+#define LM80_FAN2_COUNT_LIM	0x3d	/* Fan 2 count limit (low) */
+	/* 0x3e - 0x3f reserved	*/
+
+/*
+ * LM80 bit definitions
+ */
+
+/*	LM80_CFG		Configuration Register */
+#define LM80_CFG_START		(1<<0)	/* start monitoring operation */
+#define LM80_CFG_INT_ENA	(1<<1)	/* enables the INT# Interrupt output */
+#define LM80_CFG_INT_POL	(1<<2)	/* INT# pol: 0 act low, 1 act high */
+#define LM80_CFG_INT_CLR	(1<<3)	/* disables INT#/RST_OUT#/OS# outputs */
+#define LM80_CFG_RESET		(1<<4)	/* signals a reset */
+#define LM80_CFG_CHASS_CLR	(1<<5)	/* clears Chassis Intrusion (CI) pin */
+#define LM80_CFG_GPO		(1<<6)	/* drives the GPO# pin */
+#define LM80_CFG_INIT		(1<<7)	/* restore power on defaults */
+
+/*	LM80_ISRC_1		Interrupt Status Register 1 */
+/*	LM80_IMSK_1		Interrupt Mask Register 1 */
+#define LM80_IS_VT0			(1<<0)	/* limit exceeded for Voltage 0 */
+#define LM80_IS_VT1			(1<<1)	/* limit exceeded for Voltage 1 */
+#define LM80_IS_VT2			(1<<2)	/* limit exceeded for Voltage 2 */
+#define LM80_IS_VT3			(1<<3)	/* limit exceeded for Voltage 3 */
+#define LM80_IS_VT4			(1<<4)	/* limit exceeded for Voltage 4 */
+#define LM80_IS_VT5			(1<<5)	/* limit exceeded for Voltage 5 */
+#define LM80_IS_VT6			(1<<6)	/* limit exceeded for Voltage 6 */
+#define LM80_IS_INT_IN		(1<<7)	/* state of INT_IN# */
+
+/*	LM80_ISRC_2		Interrupt Status Register 2 */
+/*	LM80_IMSK_2		Interrupt Mask Register 2 */
+#define LM80_IS_TEMP		(1<<0)	/* HOT temperature limit exceeded */
+#define LM80_IS_BTI			(1<<1)	/* state of BTI# pin */
+#define LM80_IS_FAN1		(1<<2)	/* count limit exceeded for Fan 1 */
+#define LM80_IS_FAN2		(1<<3)	/* count limit exceeded for Fan 2 */
+#define LM80_IS_CI			(1<<4)	/* Chassis Intrusion occured */
+#define LM80_IS_OS			(1<<5)	/* OS temperature limit exceeded */
+	/* bit 6 and 7 are reserved in LM80_ISRC_2 */
+#define LM80_IS_HT_IRQ_MD	(1<<6)	/* Hot temperature interrupt mode */
+#define LM80_IS_OT_IRQ_MD	(1<<7)	/* OS temperature interrupt mode */
+
+/*	LM80_FAN_CTRL		Fan Devisor/RST#/OS# Register */
+#define LM80_FAN1_MD_SEL	(1<<0)	/* Fan 1 mode select */
+#define LM80_FAN2_MD_SEL	(1<<1)	/* Fan 2 mode select */
+#define LM80_FAN1_PRM_CTL	(3<<2)	/* Fan 1 speed control */
+#define LM80_FAN2_PRM_CTL	(3<<4)	/* Fan 2 speed control */
+#define LM80_FAN_OS_ENA		(1<<6)	/* enable OS mode on RST_OUT#/OS# pins*/
+#define LM80_FAN_RST_ENA	(1<<7)	/* sets RST_OUT#/OS# pins in RST mode */
+
+/*	LM80_TEMP_CTRL		OS# Config, Temp Res. Reg */
+#define LM80_TEMP_OS_STAT	(1<<0)	/* mirrors the state of RST_OUT#/OS# */
+#define LM80_TEMP_OS_POL	(1<<1)	/* select OS# polarity */
+#define LM80_TEMP_OS_MODE	(1<<2)	/* selects Interrupt mode */
+#define LM80_TEMP_RES		(1<<3)	/* selects 9 or 11 bit temp resulution*/
+#define LM80_TEMP_LSB		(0xf<<4)/* 4 LSBs of 11 bit temp data */
+#define LM80_TEMP_LSB_9		(1<<7)	/* LSB of 9 bit temperature data */
+
+	/* 0x07 - 0x1f reserved	*/
+/*	LM80_VT0_IN		current Voltage 0 value */
+/*	LM80_VT1_IN		current Voltage 1 value */
+/*	LM80_VT2_IN		current Voltage 2 value */
+/*	LM80_VT3_IN		current Voltage 3 value */
+/*	LM80_VT4_IN		current Voltage 4 value */
+/*	LM80_VT5_IN		current Voltage 5 value */
+/*	LM80_VT6_IN		current Voltage 6 value */
+/*	LM80_TEMP_IN		current temperature value */
+/*	LM80_FAN1_IN		current Fan 1 count */
+/*	LM80_FAN2_IN		current Fan 2 count */
+/*	LM80_VT0_HIGH_LIM	high limit val for Voltage 0 */
+/*	LM80_VT0_LOW_LIM	low limit val for Voltage 0 */
+/*	LM80_VT1_HIGH_LIM	high limit val for Voltage 1 */
+/*	LM80_VT1_LOW_LIM	low limit val for Voltage 1 */
+/*	LM80_VT2_HIGH_LIM	high limit val for Voltage 2 */
+/*	LM80_VT2_LOW_LIM	low limit val for Voltage 2 */
+/*	LM80_VT3_HIGH_LIM	high limit val for Voltage 3 */
+/*	LM80_VT3_LOW_LIM	low limit val for Voltage 3 */
+/*	LM80_VT4_HIGH_LIM	high limit val for Voltage 4 */
+/*	LM80_VT4_LOW_LIM	low limit val for Voltage 4 */
+/*	LM80_VT5_HIGH_LIM	high limit val for Voltage 5 */
+/*	LM80_VT5_LOW_LIM	low limit val for Voltage 5 */
+/*	LM80_VT6_HIGH_LIM	high limit val for Voltage 6 */
+/*	LM80_VT6_LOW_LIM	low limit val for Voltage 6 */
+/*	LM80_THOT_LIM_UP	hot temperature limit (high) */
+/*	LM80_THOT_LIM_LO	hot temperature limit (low) */
+/*	LM80_TOS_LIM_UP		OS temperature limit (high) */
+/*	LM80_TOS_LIM_LO		OS temperature limit (low) */
+/*	LM80_FAN1_COUNT_LIM	Fan 1 count limit (high) */
+/*	LM80_FAN2_COUNT_LIM	Fan 2 count limit (low) */
+	/* 0x3e - 0x3f reserved	*/
+
+#define LM80_ADDR		0x28	/* LM80 default addr */
+
+/* typedefs *******************************************************************/
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_LM80_H */
diff --git a/drivers/net/sk98lin/h/skaddr.h b/drivers/net/sk98lin/h/skaddr.h
new file mode 100644
index 0000000..423ad06
--- /dev/null
+++ b/drivers/net/sk98lin/h/skaddr.h
@@ -0,0 +1,285 @@
+/******************************************************************************
+ *
+ * Name:	skaddr.h
+ * Project:	Gigabit Ethernet Adapters, ADDR-Modul
+ * Version:	$Revision: 1.29 $
+ * Date:	$Date: 2003/05/13 16:57:24 $
+ * Purpose:	Header file for Address Management (MC, UC, Prom).
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module is intended to manage multicast addresses and promiscuous mode
+ * on GEnesis adapters.
+ *
+ * Include File Hierarchy:
+ *
+ *	"skdrv1st.h"
+ *	...
+ *	"sktypes.h"
+ *	"skqueue.h"
+ *	"skaddr.h"
+ *	...
+ *	"skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKADDR_H
+#define __INC_SKADDR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif	/* cplusplus */
+
+/* defines ********************************************************************/
+
+#define SK_MAC_ADDR_LEN				6	/* Length of MAC address. */
+#define	SK_MAX_ADDRS				14	/* #Addrs for exact match. */
+
+/* ----- Common return values ----- */
+
+#define SK_ADDR_SUCCESS				0	/* Function returned successfully. */
+#define SK_ADDR_ILLEGAL_PORT			100	/* Port number too high. */
+#define SK_ADDR_TOO_EARLY			101	/* Function called too early. */
+
+/* ----- Clear/Add flag bits ----- */
+
+#define SK_ADDR_PERMANENT			1	/* RLMT Address */
+
+/* ----- Additional Clear flag bits ----- */
+
+#define SK_MC_SW_ONLY				2	/* Do not update HW when clearing. */
+
+/* ----- Override flag bits ----- */
+
+#define SK_ADDR_LOGICAL_ADDRESS		0
+#define SK_ADDR_VIRTUAL_ADDRESS		(SK_ADDR_LOGICAL_ADDRESS)	/* old */
+#define SK_ADDR_PHYSICAL_ADDRESS	1
+#define SK_ADDR_CLEAR_LOGICAL		2
+#define SK_ADDR_SET_LOGICAL			4
+
+/* ----- Override return values ----- */
+
+#define SK_ADDR_OVERRIDE_SUCCESS	(SK_ADDR_SUCCESS)
+#define SK_ADDR_DUPLICATE_ADDRESS	1
+#define SK_ADDR_MULTICAST_ADDRESS	2
+
+/* ----- Partitioning of excact match table ----- */
+
+#define SK_ADDR_EXACT_MATCHES		16	/* #Exact match entries. */
+
+#define SK_ADDR_FIRST_MATCH_RLMT	1
+#define SK_ADDR_LAST_MATCH_RLMT		2
+#define SK_ADDR_FIRST_MATCH_DRV		3
+#define SK_ADDR_LAST_MATCH_DRV		(SK_ADDR_EXACT_MATCHES - 1)
+
+/* ----- SkAddrMcAdd/SkAddrMcUpdate return values ----- */
+
+#define SK_MC_FILTERING_EXACT		0	/* Exact filtering. */
+#define SK_MC_FILTERING_INEXACT		1	/* Inexact filtering. */
+
+/* ----- Additional SkAddrMcAdd return values ----- */
+
+#define SK_MC_ILLEGAL_ADDRESS		2	/* Illegal address. */
+#define SK_MC_ILLEGAL_PORT			3	/* Illegal port (not the active one). */
+#define SK_MC_RLMT_OVERFLOW			4	/* Too many RLMT mc addresses. */
+
+/* Promiscuous mode bits ----- */
+
+#define SK_PROM_MODE_NONE			0	/* Normal receive. */
+#define SK_PROM_MODE_LLC			1	/* Receive all LLC frames. */
+#define SK_PROM_MODE_ALL_MC			2	/* Receive all multicast frames. */
+/* #define SK_PROM_MODE_NON_LLC		4 */	/* Receive all non-LLC frames. */
+
+/* Macros */
+
+#ifdef OLD_STUFF
+#ifndef SK_ADDR_EQUAL
+/*
+ * "&" instead of "&&" allows better optimization on IA-64.
+ * The replacement is safe here, as all bytes exist.
+ */
+#ifndef SK_ADDR_DWORD_COMPARE
+#define SK_ADDR_EQUAL(A1,A2)	( \
+	(((SK_U8 *)(A1))[5] == ((SK_U8 *)(A2))[5]) & \
+	(((SK_U8 *)(A1))[4] == ((SK_U8 *)(A2))[4]) & \
+	(((SK_U8 *)(A1))[3] == ((SK_U8 *)(A2))[3]) & \
+	(((SK_U8 *)(A1))[2] == ((SK_U8 *)(A2))[2]) & \
+	(((SK_U8 *)(A1))[1] == ((SK_U8 *)(A2))[1]) & \
+	(((SK_U8 *)(A1))[0] == ((SK_U8 *)(A2))[0]))
+#else	/* SK_ADDR_DWORD_COMPARE */
+#define SK_ADDR_EQUAL(A1,A2)	( \
+	(*(SK_U32 *)&(((SK_U8 *)(A1))[2]) == *(SK_U32 *)&(((SK_U8 *)(A2))[2])) & \
+	(*(SK_U32 *)&(((SK_U8 *)(A1))[0]) == *(SK_U32 *)&(((SK_U8 *)(A2))[0])))
+#endif	/* SK_ADDR_DWORD_COMPARE */
+#endif	/* SK_ADDR_EQUAL */
+#endif /* 0 */
+
+#ifndef SK_ADDR_EQUAL
+#ifndef SK_ADDR_DWORD_COMPARE
+#define SK_ADDR_EQUAL(A1,A2)	( \
+	(((SK_U8 SK_FAR *)(A1))[5] == ((SK_U8 SK_FAR *)(A2))[5]) & \
+	(((SK_U8 SK_FAR *)(A1))[4] == ((SK_U8 SK_FAR *)(A2))[4]) & \
+	(((SK_U8 SK_FAR *)(A1))[3] == ((SK_U8 SK_FAR *)(A2))[3]) & \
+	(((SK_U8 SK_FAR *)(A1))[2] == ((SK_U8 SK_FAR *)(A2))[2]) & \
+	(((SK_U8 SK_FAR *)(A1))[1] == ((SK_U8 SK_FAR *)(A2))[1]) & \
+	(((SK_U8 SK_FAR *)(A1))[0] == ((SK_U8 SK_FAR *)(A2))[0]))
+#else	/* SK_ADDR_DWORD_COMPARE */
+#define SK_ADDR_EQUAL(A1,A2)	( \
+	(*(SK_U16 SK_FAR *)&(((SK_U8 SK_FAR *)(A1))[4]) == \
+	*(SK_U16 SK_FAR *)&(((SK_U8 SK_FAR *)(A2))[4])) && \
+	(*(SK_U32 SK_FAR *)&(((SK_U8 SK_FAR *)(A1))[0]) == \
+	*(SK_U32 SK_FAR *)&(((SK_U8 SK_FAR *)(A2))[0])))
+#endif	/* SK_ADDR_DWORD_COMPARE */
+#endif	/* SK_ADDR_EQUAL */
+
+/* typedefs *******************************************************************/
+
+typedef struct s_MacAddr {
+	SK_U8	a[SK_MAC_ADDR_LEN];
+} SK_MAC_ADDR;
+
+
+/* SK_FILTER is used to ensure alignment of the filter. */
+typedef union s_InexactFilter {
+	SK_U8	Bytes[8];
+	SK_U64	Val;	/* Dummy entry for alignment only. */
+} SK_FILTER64;
+
+
+typedef struct s_AddrNet SK_ADDR_NET;
+
+
+typedef struct s_AddrPort {
+
+/* ----- Public part (read-only) ----- */
+
+	SK_MAC_ADDR	CurrentMacAddress;	/* Current physical MAC Address. */
+	SK_MAC_ADDR	PermanentMacAddress;	/* Permanent physical MAC Address. */
+	int		PromMode;		/* Promiscuous Mode. */
+
+/* ----- Private part ----- */
+
+	SK_MAC_ADDR	PreviousMacAddress;	/* Prev. phys. MAC Address. */
+	SK_BOOL		CurrentMacAddressSet;	/* CurrentMacAddress is set. */
+	SK_U8		Align01;
+
+	SK_U32		FirstExactMatchRlmt;
+	SK_U32		NextExactMatchRlmt;
+	SK_U32		FirstExactMatchDrv;
+	SK_U32		NextExactMatchDrv;
+	SK_MAC_ADDR	Exact[SK_ADDR_EXACT_MATCHES];
+	SK_FILTER64	InexactFilter;			/* For 64-bit hash register. */
+	SK_FILTER64	InexactRlmtFilter;		/* For 64-bit hash register. */
+	SK_FILTER64	InexactDrvFilter;		/* For 64-bit hash register. */
+} SK_ADDR_PORT;
+
+
+struct s_AddrNet {
+/* ----- Public part (read-only) ----- */
+
+	SK_MAC_ADDR		CurrentMacAddress;	/* Logical MAC Address. */
+	SK_MAC_ADDR		PermanentMacAddress;	/* Logical MAC Address. */
+
+/* ----- Private part ----- */
+
+	SK_U32			ActivePort;		/* View of module ADDR. */
+	SK_BOOL			CurrentMacAddressSet;	/* CurrentMacAddress is set. */
+	SK_U8			Align01;
+	SK_U16			Align02;
+};
+
+
+typedef struct s_Addr {
+
+/* ----- Public part (read-only) ----- */
+
+	SK_ADDR_NET		Net[SK_MAX_NETS];
+	SK_ADDR_PORT	Port[SK_MAX_MACS];
+
+/* ----- Private part ----- */
+} SK_ADDR;
+
+/* function prototypes ********************************************************/
+
+#ifndef SK_KR_PROTO
+
+/* Functions provided by SkAddr */
+
+/* ANSI/C++ compliant function prototypes */
+
+extern	int	SkAddrInit(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int	Level);
+
+extern	int	SkAddrMcClear(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber,
+	int	Flags);
+
+extern	int	SkAddrMcAdd(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	SK_U32		PortNumber,
+	SK_MAC_ADDR	*pMc,
+	int		Flags);
+
+extern	int	SkAddrMcUpdate(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber);
+
+extern	int	SkAddrOverride(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	SK_U32		PortNumber,
+	SK_MAC_ADDR	SK_FAR *pNewAddr,
+	int		Flags);
+
+extern	int	SkAddrPromiscuousChange(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	PortNumber,
+	int	NewPromMode);
+
+#ifndef SK_SLIM
+extern	int	SkAddrSwap(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	FromPortNumber,
+	SK_U32	ToPortNumber);
+#endif
+
+#else	/* defined(SK_KR_PROTO)) */
+
+/* Non-ANSI/C++ compliant function prototypes */
+
+#error KR-style prototypes are not yet provided.
+
+#endif	/* defined(SK_KR_PROTO)) */
+
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_SKADDR_H */
diff --git a/drivers/net/sk98lin/h/skcsum.h b/drivers/net/sk98lin/h/skcsum.h
new file mode 100644
index 0000000..6e256bd
--- /dev/null
+++ b/drivers/net/sk98lin/h/skcsum.h
@@ -0,0 +1,213 @@
+/******************************************************************************
+ *
+ * Name:	skcsum.h
+ * Project:	GEnesis - SysKonnect SK-NET Gigabit Ethernet (SK-98xx)
+ * Version:	$Revision: 1.10 $
+ * Date:	$Date: 2003/08/20 13:59:57 $
+ * Purpose:	Store/verify Internet checksum in send/receive packets.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2001 SysKonnect GmbH.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * Public header file for the "GEnesis" common module "CSUM".
+ *
+ * "GEnesis" is an abbreviation of "Gigabit Ethernet Network System in Silicon"
+ * and is the code name of this SysKonnect project.
+ *
+ * Compilation Options:
+ *
+ *	SK_USE_CSUM - Define if CSUM is to be used. Otherwise, CSUM will be an
+ *	empty module.
+ *
+ *	SKCS_OVERWRITE_PROTO - Define to overwrite the default protocol id
+ *	definitions. In this case, all SKCS_PROTO_xxx definitions must be made
+ *	external.
+ *
+ *	SKCS_OVERWRITE_STATUS - Define to overwrite the default return status
+ *	definitions. In this case, all SKCS_STATUS_xxx definitions must be made
+ *	external.
+ *
+ * Include File Hierarchy:
+ *
+ *	"h/skcsum.h"
+ *	 "h/sktypes.h"
+ *	 "h/skqueue.h"
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKCSUM_H
+#define __INC_SKCSUM_H
+
+#include "h/sktypes.h"
+#include "h/skqueue.h"
+
+/* defines ********************************************************************/
+
+/*
+ * Define the default bit flags for 'SKCS_PACKET_INFO.ProtocolFlags'  if no user
+ * overwrite.
+ */
+#ifndef SKCS_OVERWRITE_PROTO	/* User overwrite? */
+#define SKCS_PROTO_IP	0x1	/* IP (Internet Protocol version 4) */
+#define SKCS_PROTO_TCP	0x2	/* TCP (Transmission Control Protocol) */
+#define SKCS_PROTO_UDP	0x4	/* UDP (User Datagram Protocol) */
+
+/* Indices for protocol statistics. */
+#define SKCS_PROTO_STATS_IP	0
+#define SKCS_PROTO_STATS_UDP	1
+#define SKCS_PROTO_STATS_TCP	2
+#define SKCS_NUM_PROTOCOLS	3	/* Number of supported protocols. */
+#endif	/* !SKCS_OVERWRITE_PROTO */
+
+/*
+ * Define the default SKCS_STATUS type and values if no user overwrite.
+ *
+ *	SKCS_STATUS_UNKNOWN_IP_VERSION - Not an IP v4 frame.
+ *	SKCS_STATUS_IP_CSUM_ERROR - IP checksum error.
+ *	SKCS_STATUS_IP_CSUM_ERROR_TCP - IP checksum error in TCP frame.
+ *	SKCS_STATUS_IP_CSUM_ERROR_UDP - IP checksum error in UDP frame
+ *	SKCS_STATUS_IP_FRAGMENT - IP fragment (IP checksum ok).
+ *	SKCS_STATUS_IP_CSUM_OK - IP checksum ok (not a TCP or UDP frame).
+ *	SKCS_STATUS_TCP_CSUM_ERROR - TCP checksum error (IP checksum ok).
+ *	SKCS_STATUS_UDP_CSUM_ERROR - UDP checksum error (IP checksum ok).
+ *	SKCS_STATUS_TCP_CSUM_OK - IP and TCP checksum ok.
+ *	SKCS_STATUS_UDP_CSUM_OK - IP and UDP checksum ok.
+ *	SKCS_STATUS_IP_CSUM_OK_NO_UDP - IP checksum OK and no UDP checksum. 
+ */
+#ifndef SKCS_OVERWRITE_STATUS	/* User overwrite? */
+#define SKCS_STATUS	int	/* Define status type. */
+
+#define SKCS_STATUS_UNKNOWN_IP_VERSION	1
+#define SKCS_STATUS_IP_CSUM_ERROR		2
+#define SKCS_STATUS_IP_FRAGMENT			3
+#define SKCS_STATUS_IP_CSUM_OK			4
+#define SKCS_STATUS_TCP_CSUM_ERROR		5
+#define SKCS_STATUS_UDP_CSUM_ERROR		6
+#define SKCS_STATUS_TCP_CSUM_OK			7
+#define SKCS_STATUS_UDP_CSUM_OK			8
+/* needed for Microsoft */
+#define SKCS_STATUS_IP_CSUM_ERROR_UDP	9
+#define SKCS_STATUS_IP_CSUM_ERROR_TCP	10
+/* UDP checksum may be omitted */
+#define SKCS_STATUS_IP_CSUM_OK_NO_UDP	11
+#endif	/* !SKCS_OVERWRITE_STATUS */
+
+/* Clear protocol statistics event. */
+#define SK_CSUM_EVENT_CLEAR_PROTO_STATS	1
+
+/*
+ * Add two values in one's complement.
+ *
+ * Note: One of the two input values may be "longer" than 16-bit, but then the
+ * resulting sum may be 17 bits long. In this case, add zero to the result using
+ * SKCS_OC_ADD() again.
+ *
+ *	Result = Value1 + Value2
+ */
+#define SKCS_OC_ADD(Result, Value1, Value2) {				\
+	unsigned long Sum;						\
+									\
+	Sum = (unsigned long) (Value1) + (unsigned long) (Value2);	\
+	/* Add-in any carry. */						\
+	(Result) = (Sum & 0xffff) + (Sum >> 16);			\
+}
+
+/*
+ * Subtract two values in one's complement.
+ *
+ *	Result = Value1 - Value2
+ */
+#define SKCS_OC_SUB(Result, Value1, Value2)	\
+	SKCS_OC_ADD((Result), (Value1), ~(Value2) & 0xffff)
+
+/* typedefs *******************************************************************/
+
+/*
+ * SKCS_PROTO_STATS - The CSUM protocol statistics structure.
+ *
+ * There is one instance of this structure for each protocol supported.
+ */
+typedef struct s_CsProtocolStatistics {
+	SK_U64 RxOkCts;		/* Receive checksum ok. */
+	SK_U64 RxUnableCts;	/* Unable to verify receive checksum. */
+	SK_U64 RxErrCts;	/* Receive checksum error. */
+	SK_U64 TxOkCts;		/* Transmit checksum ok. */
+	SK_U64 TxUnableCts;	/* Unable to calculate checksum in hw. */
+} SKCS_PROTO_STATS;
+
+/*
+ * s_Csum - The CSUM module context structure.
+ */
+typedef struct s_Csum {
+	/* Enabled receive SK_PROTO_XXX bit flags. */
+	unsigned ReceiveFlags[SK_MAX_NETS];
+#ifdef TX_CSUM
+	unsigned TransmitFlags[SK_MAX_NETS];
+#endif /* TX_CSUM */
+
+	/* The protocol statistics structure; one per supported protocol. */
+	SKCS_PROTO_STATS ProtoStats[SK_MAX_NETS][SKCS_NUM_PROTOCOLS];
+} SK_CSUM;
+
+/*
+ * SKCS_PACKET_INFO - The packet information structure.
+ */
+typedef struct s_CsPacketInfo {
+	/* Bit field specifiying the desired/found protocols. */
+	unsigned ProtocolFlags;
+
+	/* Length of complete IP header, including any option fields. */
+	unsigned IpHeaderLength;
+
+	/* IP header checksum. */
+	unsigned IpHeaderChecksum;
+
+	/* TCP/UDP pseudo header checksum. */
+	unsigned PseudoHeaderChecksum;
+} SKCS_PACKET_INFO;
+
+/* function prototypes ********************************************************/
+
+#ifndef SK_CS_CALCULATE_CHECKSUM
+extern unsigned SkCsCalculateChecksum(
+	void		*pData,
+	unsigned	Length);
+#endif /* SK_CS_CALCULATE_CHECKSUM */
+
+extern int SkCsEvent(
+	SK_AC		*pAc,
+	SK_IOC		Ioc,
+	SK_U32		Event,
+	SK_EVPARA	Param);
+
+extern SKCS_STATUS SkCsGetReceiveInfo(
+	SK_AC		*pAc,
+	void		*pIpHeader,
+	unsigned	Checksum1,
+	unsigned	Checksum2,
+	int			NetNumber);
+
+extern void SkCsSetReceiveFlags(
+	SK_AC		*pAc,
+	unsigned	ReceiveFlags,
+	unsigned	*pChecksum1Offset,
+	unsigned	*pChecksum2Offset,
+	int			NetNumber);
+
+#endif	/* __INC_SKCSUM_H */
diff --git a/drivers/net/sk98lin/h/skdebug.h b/drivers/net/sk98lin/h/skdebug.h
new file mode 100644
index 0000000..3cba171
--- /dev/null
+++ b/drivers/net/sk98lin/h/skdebug.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ *
+ * Name:	skdebug.h
+ * Project:	Gigabit Ethernet Adapters, Common Modules
+ * Version:	$Revision: 1.14 $
+ * Date:	$Date: 2003/05/13 17:26:00 $
+ * Purpose:	SK specific DEBUG support
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKDEBUG_H
+#define __INC_SKDEBUG_H
+
+#ifdef	DEBUG
+#ifndef SK_DBG_MSG
+#define SK_DBG_MSG(pAC,comp,cat,arg) \
+		if ( ((comp) & SK_DBG_CHKMOD(pAC)) && 	\
+		      ((cat) & SK_DBG_CHKCAT(pAC)) ) { 	\
+			SK_DBG_PRINTF arg ;		\
+		}
+#endif
+#else
+#define SK_DBG_MSG(pAC,comp,lev,arg)
+#endif
+
+/* PLS NOTE:
+ * =========
+ * Due to any restrictions of kernel printf routines do not use other
+ * format identifiers as: %x %d %c %s .
+ * Never use any combined format identifiers such as: %lx %ld in your
+ * printf - argument (arg) because some OS specific kernel printfs may
+ * only support some basic identifiers.
+ */
+
+/* Debug modules */
+
+#define SK_DBGMOD_MERR	0x00000001L	/* general module error indication */
+#define SK_DBGMOD_HWM	0x00000002L	/* Hardware init module */
+#define SK_DBGMOD_RLMT	0x00000004L	/* RLMT module */
+#define SK_DBGMOD_VPD	0x00000008L	/* VPD module */
+#define SK_DBGMOD_I2C	0x00000010L	/* I2C module */
+#define SK_DBGMOD_PNMI	0x00000020L	/* PNMI module */
+#define SK_DBGMOD_CSUM	0x00000040L	/* CSUM module */
+#define SK_DBGMOD_ADDR	0x00000080L	/* ADDR module */
+#define SK_DBGMOD_PECP	0x00000100L	/* PECP module */
+#define SK_DBGMOD_POWM	0x00000200L	/* Power Management module */
+
+/* Debug events */
+
+#define SK_DBGCAT_INIT	0x00000001L	/* module/driver initialization */
+#define SK_DBGCAT_CTRL	0x00000002L	/* controlling devices */
+#define SK_DBGCAT_ERR	0x00000004L	/* error handling paths */
+#define SK_DBGCAT_TX	0x00000008L	/* transmit path */
+#define SK_DBGCAT_RX	0x00000010L	/* receive path */
+#define SK_DBGCAT_IRQ	0x00000020L	/* general IRQ handling */
+#define SK_DBGCAT_QUEUE	0x00000040L	/* any queue management */
+#define SK_DBGCAT_DUMP	0x00000080L	/* large data output e.g. hex dump */
+#define SK_DBGCAT_FATAL	0x00000100L	/* fatal error */
+
+#endif	/* __INC_SKDEBUG_H */
diff --git a/drivers/net/sk98lin/h/skdrv1st.h b/drivers/net/sk98lin/h/skdrv1st.h
new file mode 100644
index 0000000..91b8d4f
--- /dev/null
+++ b/drivers/net/sk98lin/h/skdrv1st.h
@@ -0,0 +1,188 @@
+/******************************************************************************
+ *
+ * Name:	skdrv1st.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.4 $
+ * Date:	$Date: 2003/11/12 14:28:14 $
+ * Purpose:	First header file for driver and all other modules
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the first include file of the driver, which includes all
+ * neccessary system header files and some of the GEnesis header files.
+ * It also defines some basic items.
+ *
+ * Include File Hierarchy:
+ *
+ *	see skge.c
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKDRV1ST_H
+#define __INC_SKDRV1ST_H
+
+typedef struct s_AC	SK_AC;
+
+/* Set card versions */
+#define SK_FAR
+
+/* override some default functions with optimized linux functions */
+
+#define SK_PNMI_STORE_U16(p,v)		memcpy((char*)(p),(char*)&(v),2)
+#define SK_PNMI_STORE_U32(p,v)		memcpy((char*)(p),(char*)&(v),4)
+#define SK_PNMI_STORE_U64(p,v)		memcpy((char*)(p),(char*)&(v),8)
+#define SK_PNMI_READ_U16(p,v)		memcpy((char*)&(v),(char*)(p),2)
+#define SK_PNMI_READ_U32(p,v)		memcpy((char*)&(v),(char*)(p),4)
+#define SK_PNMI_READ_U64(p,v)		memcpy((char*)&(v),(char*)(p),8)
+
+#define SK_ADDR_EQUAL(a1,a2)		(!memcmp(a1,a2,6))
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/bitops.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <net/checksum.h>
+
+#define SK_CS_CALCULATE_CHECKSUM
+#ifndef CONFIG_X86_64
+#define SkCsCalculateChecksum(p,l)	((~ip_compute_csum(p, l)) & 0xffff)
+#else
+#define SkCsCalculateChecksum(p,l)	((~ip_fast_csum(p, l)) & 0xffff)
+#endif
+
+#include	"h/sktypes.h"
+#include	"h/skerror.h"
+#include	"h/skdebug.h"
+#include	"h/lm80.h"
+#include	"h/xmac_ii.h"
+
+#ifdef __LITTLE_ENDIAN
+#define SK_LITTLE_ENDIAN
+#else
+#define SK_BIG_ENDIAN
+#endif
+
+#define SK_NET_DEVICE	net_device
+
+
+/* we use gethrtime(), return unit: nanoseconds */
+#define SK_TICKS_PER_SEC	100
+
+#define	SK_MEM_MAPPED_IO
+
+// #define SK_RLMT_SLOW_LOOKAHEAD
+
+#define SK_MAX_MACS		2
+#define SK_MAX_NETS		2
+
+#define SK_IOC			char __iomem *
+
+typedef struct s_DrvRlmtMbuf SK_MBUF;
+
+#define	SK_CONST64	INT64_C
+#define	SK_CONSTU64	UINT64_C
+
+#define SK_MEMCPY(dest,src,size)	memcpy(dest,src,size)
+#define SK_MEMCMP(s1,s2,size)		memcmp(s1,s2,size)
+#define SK_MEMSET(dest,val,size)	memset(dest,val,size)
+#define SK_STRLEN(pStr)			strlen((char*)(pStr))
+#define SK_STRNCPY(pDest,pSrc,size)	strncpy((char*)(pDest),(char*)(pSrc),size)
+#define SK_STRCMP(pStr1,pStr2)		strcmp((char*)(pStr1),(char*)(pStr2))
+
+/* macros to access the adapter */
+#define SK_OUT8(b,a,v)		writeb((v), ((b)+(a)))	
+#define SK_OUT16(b,a,v)		writew((v), ((b)+(a)))	
+#define SK_OUT32(b,a,v)		writel((v), ((b)+(a)))	
+#define SK_IN8(b,a,pv)		(*(pv) = readb((b)+(a)))
+#define SK_IN16(b,a,pv)		(*(pv) = readw((b)+(a)))
+#define SK_IN32(b,a,pv)		(*(pv) = readl((b)+(a)))
+
+#define int8_t		char
+#define int16_t		short
+#define int32_t		long
+#define int64_t		long long
+#define uint8_t		u_char
+#define uint16_t	u_short
+#define uint32_t	u_long
+#define uint64_t	unsigned long long
+#define t_scalar_t	int
+#define t_uscalar_t	unsigned int
+#define uintptr_t	unsigned long
+
+#define __CONCAT__(A,B) A##B
+
+#define INT32_C(a)		__CONCAT__(a,L)
+#define INT64_C(a)		__CONCAT__(a,LL)
+#define UINT32_C(a)		__CONCAT__(a,UL)
+#define UINT64_C(a)		__CONCAT__(a,ULL)
+
+#ifdef DEBUG
+#define SK_DBG_PRINTF		printk
+#ifndef SK_DEBUG_CHKMOD
+#define SK_DEBUG_CHKMOD		0
+#endif
+#ifndef SK_DEBUG_CHKCAT
+#define SK_DEBUG_CHKCAT		0
+#endif
+/* those come from the makefile */
+#define SK_DBG_CHKMOD(pAC)	(SK_DEBUG_CHKMOD)
+#define SK_DBG_CHKCAT(pAC)	(SK_DEBUG_CHKCAT)
+
+extern void SkDbgPrintf(const char *format,...);
+
+#define SK_DBGMOD_DRV			0x00010000
+
+/**** possible driver debug categories ********************************/
+#define SK_DBGCAT_DRV_ENTRY		0x00010000
+#define SK_DBGCAT_DRV_SAP		0x00020000
+#define SK_DBGCAT_DRV_MCA		0x00040000
+#define SK_DBGCAT_DRV_TX_PROGRESS	0x00080000
+#define SK_DBGCAT_DRV_RX_PROGRESS	0x00100000
+#define SK_DBGCAT_DRV_PROGRESS		0x00200000
+#define SK_DBGCAT_DRV_MSG		0x00400000
+#define SK_DBGCAT_DRV_PROM		0x00800000
+#define SK_DBGCAT_DRV_TX_FRAME		0x01000000
+#define SK_DBGCAT_DRV_ERROR		0x02000000
+#define SK_DBGCAT_DRV_INT_SRC		0x04000000
+#define SK_DBGCAT_DRV_EVENT		0x08000000
+
+#endif
+
+#define SK_ERR_LOG		SkErrorLog
+
+extern void SkErrorLog(SK_AC*, int, int, char*);
+
+#endif
+
diff --git a/drivers/net/sk98lin/h/skdrv2nd.h b/drivers/net/sk98lin/h/skdrv2nd.h
new file mode 100644
index 0000000..3fa6717
--- /dev/null
+++ b/drivers/net/sk98lin/h/skdrv2nd.h
@@ -0,0 +1,447 @@
+/******************************************************************************
+ *
+ * Name:	skdrv2nd.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.10 $
+ * Date:	$Date: 2003/12/11 16:04:45 $
+ * Purpose:	Second header file for driver and all other modules
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the second include file of the driver, which includes all other
+ * neccessary files and defines all structures and constants used by the
+ * driver and the common modules.
+ *
+ * Include File Hierarchy:
+ *
+ *	see skge.c
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKDRV2ND_H
+#define __INC_SKDRV2ND_H
+
+#include "h/skqueue.h"
+#include "h/skgehwt.h"
+#include "h/sktimer.h"
+#include "h/ski2c.h"
+#include "h/skgepnmi.h"
+#include "h/skvpd.h"
+#include "h/skgehw.h"
+#include "h/skgeinit.h"
+#include "h/skaddr.h"
+#include "h/skgesirq.h"
+#include "h/skcsum.h"
+#include "h/skrlmt.h"
+#include "h/skgedrv.h"
+
+
+extern SK_MBUF		*SkDrvAllocRlmtMbuf(SK_AC*, SK_IOC, unsigned);
+extern void		SkDrvFreeRlmtMbuf(SK_AC*, SK_IOC, SK_MBUF*);
+extern SK_U64		SkOsGetTime(SK_AC*);
+extern int		SkPciReadCfgDWord(SK_AC*, int, SK_U32*);
+extern int		SkPciReadCfgWord(SK_AC*, int, SK_U16*);
+extern int		SkPciReadCfgByte(SK_AC*, int, SK_U8*);
+extern int		SkPciWriteCfgWord(SK_AC*, int, SK_U16);
+extern int		SkPciWriteCfgByte(SK_AC*, int, SK_U8);
+extern int		SkDrvEvent(SK_AC*, SK_IOC IoC, SK_U32, SK_EVPARA);
+
+#ifdef SK_DIAG_SUPPORT
+extern int		SkDrvEnterDiagMode(SK_AC *pAc);
+extern int		SkDrvLeaveDiagMode(SK_AC *pAc);
+#endif
+
+struct s_DrvRlmtMbuf {
+	SK_MBUF		*pNext;		/* Pointer to next RLMT Mbuf. */
+	SK_U8		*pData;		/* Data buffer (virtually contig.). */
+	unsigned	Size;		/* Data buffer size. */
+	unsigned	Length;		/* Length of packet (<= Size). */
+	SK_U32		PortIdx;	/* Receiving/transmitting port. */
+#ifdef SK_RLMT_MBUF_PRIVATE
+	SK_RLMT_MBUF	Rlmt;		/* Private part for RLMT. */
+#endif  /* SK_RLMT_MBUF_PRIVATE */
+	struct sk_buff	*pOs;		/* Pointer to message block */
+};
+
+
+/*
+ * Time macros
+ */
+#if SK_TICKS_PER_SEC == 100
+#define SK_PNMI_HUNDREDS_SEC(t)	(t)
+#else
+#define SK_PNMI_HUNDREDS_SEC(t)	((((unsigned long)t) * 100) / \
+										(SK_TICKS_PER_SEC))
+#endif
+
+/*
+ * New SkOsGetTime
+ */
+#define SkOsGetTimeCurrent(pAC, pUsec) {\
+	struct timeval t;\
+	do_gettimeofday(&t);\
+	*pUsec = ((((t.tv_sec) * 1000000L)+t.tv_usec)/10000);\
+}
+
+
+/*
+ * ioctl definitions
+ */
+#define		SK_IOCTL_BASE		(SIOCDEVPRIVATE)
+#define		SK_IOCTL_GETMIB		(SK_IOCTL_BASE + 0)
+#define		SK_IOCTL_SETMIB		(SK_IOCTL_BASE + 1)
+#define		SK_IOCTL_PRESETMIB	(SK_IOCTL_BASE + 2)
+#define		SK_IOCTL_GEN		(SK_IOCTL_BASE + 3)
+#define		SK_IOCTL_DIAG		(SK_IOCTL_BASE + 4)
+
+typedef struct s_IOCTL	SK_GE_IOCTL;
+
+struct s_IOCTL {
+	char __user *	pData;
+	unsigned int	Len;
+};
+
+
+/*
+ * define sizes of descriptor rings in bytes
+ */
+
+#define		TX_RING_SIZE	(8*1024)
+#define		RX_RING_SIZE	(24*1024)
+
+/*
+ * Buffer size for ethernet packets
+ */
+#define	ETH_BUF_SIZE	1540
+#define	ETH_MAX_MTU	1514
+#define ETH_MIN_MTU	60
+#define ETH_MULTICAST_BIT	0x01
+#define SK_JUMBO_MTU	9000
+
+/*
+ * transmit priority selects the queue: LOW=asynchron, HIGH=synchron
+ */
+#define TX_PRIO_LOW	0
+#define TX_PRIO_HIGH	1
+
+/*
+ * alignment of rx/tx descriptors
+ */
+#define DESCR_ALIGN	64
+
+/*
+ * definitions for pnmi. TODO
+ */
+#define SK_DRIVER_RESET(pAC, IoC)	0
+#define SK_DRIVER_SENDEVENT(pAC, IoC)	0
+#define SK_DRIVER_SELFTEST(pAC, IoC)	0
+/* For get mtu you must add an own function */
+#define SK_DRIVER_GET_MTU(pAc,IoC,i)	0
+#define SK_DRIVER_SET_MTU(pAc,IoC,i,v)	0
+#define SK_DRIVER_PRESET_MTU(pAc,IoC,i,v)	0
+
+/*
+** Interim definition of SK_DRV_TIMER placed in this file until 
+** common modules have been finalized
+*/
+#define SK_DRV_TIMER			11 
+#define	SK_DRV_MODERATION_TIMER		1
+#define SK_DRV_MODERATION_TIMER_LENGTH  1000000  /* 1 second */
+#define SK_DRV_RX_CLEANUP_TIMER		2
+#define SK_DRV_RX_CLEANUP_TIMER_LENGTH	1000000	 /* 100 millisecs */
+
+/*
+** Definitions regarding transmitting frames 
+** any calculating any checksum.
+*/
+#define C_LEN_ETHERMAC_HEADER_DEST_ADDR 6
+#define C_LEN_ETHERMAC_HEADER_SRC_ADDR  6
+#define C_LEN_ETHERMAC_HEADER_LENTYPE   2
+#define C_LEN_ETHERMAC_HEADER           ( (C_LEN_ETHERMAC_HEADER_DEST_ADDR) + \
+                                          (C_LEN_ETHERMAC_HEADER_SRC_ADDR)  + \
+                                          (C_LEN_ETHERMAC_HEADER_LENTYPE) )
+
+#define C_LEN_ETHERMTU_MINSIZE          46
+#define C_LEN_ETHERMTU_MAXSIZE_STD      1500
+#define C_LEN_ETHERMTU_MAXSIZE_JUMBO    9000
+
+#define C_LEN_ETHERNET_MINSIZE          ( (C_LEN_ETHERMAC_HEADER) + \
+                                          (C_LEN_ETHERMTU_MINSIZE) )
+
+#define C_OFFSET_IPHEADER               C_LEN_ETHERMAC_HEADER
+#define C_OFFSET_IPHEADER_IPPROTO       9
+#define C_OFFSET_TCPHEADER_TCPCS        16
+#define C_OFFSET_UDPHEADER_UDPCS        6
+
+#define C_OFFSET_IPPROTO                ( (C_LEN_ETHERMAC_HEADER) + \
+                                          (C_OFFSET_IPHEADER_IPPROTO) )
+
+#define C_PROTO_ID_UDP                  17       /* refer to RFC 790 or Stevens'   */
+#define C_PROTO_ID_TCP                  6        /* TCP/IP illustrated for details */
+
+/* TX and RX descriptors *****************************************************/
+
+typedef struct s_RxD RXD; /* the receive descriptor */
+
+struct s_RxD {
+	volatile SK_U32	RBControl;	/* Receive Buffer Control */
+	SK_U32		VNextRxd;	/* Next receive descriptor,low dword */
+	SK_U32		VDataLow;	/* Receive buffer Addr, low dword */
+	SK_U32		VDataHigh;	/* Receive buffer Addr, high dword */
+	SK_U32		FrameStat;	/* Receive Frame Status word */
+	SK_U32		TimeStamp;	/* Time stamp from XMAC */
+	SK_U32		TcpSums;	/* TCP Sum 2 / TCP Sum 1 */
+	SK_U32		TcpSumStarts;	/* TCP Sum Start 2 / TCP Sum Start 1 */
+	RXD		*pNextRxd;	/* Pointer to next Rxd */
+	struct sk_buff	*pMBuf;		/* Pointer to Linux' socket buffer */
+};
+
+typedef struct s_TxD TXD; /* the transmit descriptor */
+
+struct s_TxD {
+	volatile SK_U32	TBControl;	/* Transmit Buffer Control */
+	SK_U32		VNextTxd;	/* Next transmit descriptor,low dword */
+	SK_U32		VDataLow;	/* Transmit Buffer Addr, low dword */
+	SK_U32		VDataHigh;	/* Transmit Buffer Addr, high dword */
+	SK_U32		FrameStat;	/* Transmit Frame Status Word */
+	SK_U32		TcpSumOfs;	/* Reserved / TCP Sum Offset */
+	SK_U16		TcpSumSt;	/* TCP Sum Start */
+	SK_U16		TcpSumWr;	/* TCP Sum Write */
+	SK_U32		TcpReserved;	/* not used */
+	TXD		*pNextTxd;	/* Pointer to next Txd */
+	struct sk_buff	*pMBuf;		/* Pointer to Linux' socket buffer */
+};
+
+/* Used interrupt bits in the interrupts source register *********************/
+
+#define DRIVER_IRQS	((IS_IRQ_SW)   | \
+			(IS_R1_F)      |(IS_R2_F)  | \
+			(IS_XS1_F)     |(IS_XA1_F) | \
+			(IS_XS2_F)     |(IS_XA2_F))
+
+#define SPECIAL_IRQS	((IS_HW_ERR)   |(IS_I2C_READY)  | \
+			(IS_EXT_REG)   |(IS_TIMINT)     | \
+			(IS_PA_TO_RX1) |(IS_PA_TO_RX2)  | \
+			(IS_PA_TO_TX1) |(IS_PA_TO_TX2)  | \
+			(IS_MAC1)      |(IS_LNK_SYNC_M1)| \
+			(IS_MAC2)      |(IS_LNK_SYNC_M2)| \
+			(IS_R1_C)      |(IS_R2_C)       | \
+			(IS_XS1_C)     |(IS_XA1_C)      | \
+			(IS_XS2_C)     |(IS_XA2_C))
+
+#define IRQ_MASK	((IS_IRQ_SW)   | \
+			(IS_R1_B)      |(IS_R1_F)     |(IS_R2_B) |(IS_R2_F) | \
+			(IS_XS1_B)     |(IS_XS1_F)    |(IS_XA1_B)|(IS_XA1_F)| \
+			(IS_XS2_B)     |(IS_XS2_F)    |(IS_XA2_B)|(IS_XA2_F)| \
+			(IS_HW_ERR)    |(IS_I2C_READY)| \
+			(IS_EXT_REG)   |(IS_TIMINT)   | \
+			(IS_PA_TO_RX1) |(IS_PA_TO_RX2)| \
+			(IS_PA_TO_TX1) |(IS_PA_TO_TX2)| \
+			(IS_MAC1)      |(IS_MAC2)     | \
+			(IS_R1_C)      |(IS_R2_C)     | \
+			(IS_XS1_C)     |(IS_XA1_C)    | \
+			(IS_XS2_C)     |(IS_XA2_C))
+
+#define IRQ_HWE_MASK	(IS_ERR_MSK) /* enable all HW irqs */
+
+typedef struct s_DevNet DEV_NET;
+
+struct s_DevNet {
+	int             PortNr;
+	int             NetNr;
+	SK_AC   *pAC;
+};  
+
+typedef struct s_TxPort		TX_PORT;
+
+struct s_TxPort {
+	/* the transmit descriptor rings */
+	caddr_t		pTxDescrRing;	/* descriptor area memory */
+	SK_U64		VTxDescrRing;	/* descr. area bus virt. addr. */
+	TXD		*pTxdRingHead;	/* Head of Tx rings */
+	TXD		*pTxdRingTail;	/* Tail of Tx rings */
+	TXD		*pTxdRingPrev;	/* descriptor sent previously */
+	int		TxdRingFree;	/* # of free entrys */
+	spinlock_t	TxDesRingLock;	/* serialize descriptor accesses */
+	SK_IOC		HwAddr;		/* bmu registers address */
+	int		PortIndex;	/* index number of port (0 or 1) */
+};
+
+typedef struct s_RxPort		RX_PORT;
+
+struct s_RxPort {
+	/* the receive descriptor rings */
+	caddr_t		pRxDescrRing;	/* descriptor area memory */
+	SK_U64		VRxDescrRing;   /* descr. area bus virt. addr. */
+	RXD		*pRxdRingHead;	/* Head of Rx rings */
+	RXD		*pRxdRingTail;	/* Tail of Rx rings */
+	RXD		*pRxdRingPrev;	/* descriptor given to BMU previously */
+	int		RxdRingFree;	/* # of free entrys */
+	int		RxCsum;		/* use receive checksum hardware */
+	spinlock_t	RxDesRingLock;	/* serialize descriptor accesses */
+	int		RxFillLimit;	/* limit for buffers in ring */
+	SK_IOC		HwAddr;		/* bmu registers address */
+	int		PortIndex;	/* index number of port (0 or 1) */
+};
+
+/* Definitions needed for interrupt moderation *******************************/
+
+#define IRQ_EOF_AS_TX     ((IS_XA1_F)     | (IS_XA2_F))
+#define IRQ_EOF_SY_TX     ((IS_XS1_F)     | (IS_XS2_F))
+#define IRQ_MASK_TX_ONLY  ((IRQ_EOF_AS_TX)| (IRQ_EOF_SY_TX))
+#define IRQ_MASK_RX_ONLY  ((IS_R1_F)      | (IS_R2_F))
+#define IRQ_MASK_SP_ONLY  (SPECIAL_IRQS)
+#define IRQ_MASK_TX_RX    ((IRQ_MASK_TX_ONLY)| (IRQ_MASK_RX_ONLY))
+#define IRQ_MASK_SP_RX    ((SPECIAL_IRQS)    | (IRQ_MASK_RX_ONLY))
+#define IRQ_MASK_SP_TX    ((SPECIAL_IRQS)    | (IRQ_MASK_TX_ONLY))
+#define IRQ_MASK_RX_TX_SP ((SPECIAL_IRQS)    | (IRQ_MASK_TX_RX))
+
+#define C_INT_MOD_NONE                 1
+#define C_INT_MOD_STATIC               2
+#define C_INT_MOD_DYNAMIC              4
+
+#define C_CLK_FREQ_GENESIS      53215000 /* shorter: 53.125 MHz  */
+#define C_CLK_FREQ_YUKON        78215000 /* shorter: 78.125 MHz  */
+
+#define C_INTS_PER_SEC_DEFAULT      2000 
+#define C_INT_MOD_ENABLE_PERCENTAGE   50 /* if higher 50% enable */
+#define C_INT_MOD_DISABLE_PERCENTAGE  50 /* if lower 50% disable */
+#define C_INT_MOD_IPS_LOWER_RANGE     30
+#define C_INT_MOD_IPS_UPPER_RANGE     40000
+
+
+typedef struct s_DynIrqModInfo  DIM_INFO;
+struct s_DynIrqModInfo {
+	unsigned long   PrevTimeVal;
+	unsigned int    PrevSysLoad;
+	unsigned int    PrevUsedTime;
+	unsigned int    PrevTotalTime;
+	int             PrevUsedDescrRatio;
+	int             NbrProcessedDescr;
+        SK_U64          PrevPort0RxIntrCts;
+        SK_U64          PrevPort1RxIntrCts;
+        SK_U64          PrevPort0TxIntrCts;
+        SK_U64          PrevPort1TxIntrCts;
+	SK_BOOL         ModJustEnabled;     /* Moderation just enabled yes/no */
+
+	int             MaxModIntsPerSec;            /* Moderation Threshold */
+	int             MaxModIntsPerSecUpperLimit;  /* Upper limit for DIM  */
+	int             MaxModIntsPerSecLowerLimit;  /* Lower limit for DIM  */
+
+	long            MaskIrqModeration;   /* ModIrqType (eg. 'TxRx')      */
+	SK_BOOL         DisplayStats;        /* Stats yes/no                 */
+	SK_BOOL         AutoSizing;          /* Resize DIM-timer on/off      */
+	int             IntModTypeSelect;    /* EnableIntMod (eg. 'dynamic') */
+
+	SK_TIMER        ModTimer; /* just some timer */
+};
+
+typedef struct s_PerStrm	PER_STRM;
+
+#define SK_ALLOC_IRQ	0x00000001
+
+#ifdef SK_DIAG_SUPPORT
+#define	DIAG_ACTIVE		1
+#define	DIAG_NOTACTIVE		0
+#endif
+
+/****************************************************************************
+ * Per board structure / Adapter Context structure:
+ *	Allocated within attach(9e) and freed within detach(9e).
+ *	Contains all 'per device' necessary handles, flags, locks etc.:
+ */
+struct s_AC  {
+	SK_GEINIT	GIni;		/* GE init struct */
+	SK_PNMI		Pnmi;		/* PNMI data struct */
+	SK_VPD		vpd;		/* vpd data struct */
+	SK_QUEUE	Event;		/* Event queue */
+	SK_HWT		Hwt;		/* Hardware Timer control struct */
+	SK_TIMCTRL	Tim;		/* Software Timer control struct */
+	SK_I2C		I2c;		/* I2C relevant data structure */
+	SK_ADDR		Addr;		/* for Address module */
+	SK_CSUM		Csum;		/* for checksum module */
+	SK_RLMT		Rlmt;		/* for rlmt module */
+	spinlock_t	SlowPathLock;	/* Normal IRQ lock */
+	struct timer_list BlinkTimer;	/* for LED blinking */
+	int		LedsOn;
+	SK_PNMI_STRUCT_DATA PnmiStruct;	/* structure to get all Pnmi-Data */
+	int			RlmtMode;	/* link check mode to set */
+	int			RlmtNets;	/* Number of nets */
+	
+	SK_IOC		IoBase;		/* register set of adapter */
+	int		BoardLevel;	/* level of active hw init (0-2) */
+
+	SK_U32		AllocFlag;	/* flag allocation of resources */
+	struct pci_dev	*PciDev;	/* for access to pci config space */
+	struct SK_NET_DEVICE	*dev[2];	/* pointer to device struct */
+
+	int		RxBufSize;	/* length of receive buffers */
+        struct net_device_stats stats;	/* linux 'netstat -i' statistics */
+	int		Index;		/* internal board index number */
+
+	/* adapter RAM sizes for queues of active port */
+	int		RxQueueSize;	/* memory used for receive queue */
+	int		TxSQueueSize;	/* memory used for sync. tx queue */
+	int		TxAQueueSize;	/* memory used for async. tx queue */
+
+	int		PromiscCount;	/* promiscuous mode counter  */
+	int		AllMultiCount;  /* allmulticast mode counter */
+	int		MulticCount;	/* number of different MC    */
+					/*  addresses for this board */
+					/*  (may be more than HW can)*/
+
+	int		HWRevision;	/* Hardware revision */
+	int		ActivePort;	/* the active XMAC port */
+	int		MaxPorts;		/* number of activated ports */
+	int		TxDescrPerRing;	/* # of descriptors per tx ring */
+	int		RxDescrPerRing;	/* # of descriptors per rx ring */
+
+	caddr_t		pDescrMem;	/* Pointer to the descriptor area */
+	dma_addr_t	pDescrMemDMA;	/* PCI DMA address of area */
+
+	/* the port structures with descriptor rings */
+	TX_PORT		TxPort[SK_MAX_MACS][2];
+	RX_PORT		RxPort[SK_MAX_MACS];
+
+	SK_BOOL		CheckQueue;	/* check event queue soon */
+	SK_TIMER        DrvCleanupTimer;/* to check for pending descriptors */
+	DIM_INFO        DynIrqModInfo;  /* all data related to DIM */
+
+	/* Only for tests */
+	int		PortDown;
+	int		ChipsetType;	/*  Chipset family type 
+					 *  0 == Genesis family support
+					 *  1 == Yukon family support
+					 */
+#ifdef SK_DIAG_SUPPORT
+	SK_U32		DiagModeActive;		/* is diag active?	*/
+	SK_BOOL		DiagFlowCtrl;		/* for control purposes	*/
+	SK_PNMI_STRUCT_DATA PnmiBackup;		/* backup structure for all Pnmi-Data */
+	SK_BOOL         WasIfUp[SK_MAX_MACS];   /* for OpenClose while 
+						 * DIAG is busy with NIC 
+						 */
+#endif
+
+};
+
+
+#endif /* __INC_SKDRV2ND_H */
+
diff --git a/drivers/net/sk98lin/h/skerror.h b/drivers/net/sk98lin/h/skerror.h
new file mode 100644
index 0000000..da062f7
--- /dev/null
+++ b/drivers/net/sk98lin/h/skerror.h
@@ -0,0 +1,55 @@
+/******************************************************************************
+ *
+ * Name:	skerror.h
+ * Project:	Gigabit Ethernet Adapters, Common Modules
+ * Version:	$Revision: 1.7 $
+ * Date:	$Date: 2003/05/13 17:25:13 $
+ * Purpose:	SK specific Error log support
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+#ifndef _INC_SKERROR_H_
+#define _INC_SKERROR_H_
+
+/*
+ * Define Error Classes
+ */
+#define	SK_ERRCL_OTHER		(0)		/* Other error */
+#define	SK_ERRCL_CONFIG		(1L<<0)	/* Configuration error */
+#define	SK_ERRCL_INIT		(1L<<1)	/* Initialization error */
+#define	SK_ERRCL_NORES		(1L<<2)	/* Out of Resources error */
+#define	SK_ERRCL_SW			(1L<<3)	/* Internal Software error */
+#define	SK_ERRCL_HW			(1L<<4)	/* Hardware Failure */
+#define	SK_ERRCL_COMM		(1L<<5)	/* Communication error */
+
+
+/*
+ * Define Error Code Bases
+ */
+#define	SK_ERRBASE_RLMT		 100	/* Base Error number for RLMT */
+#define	SK_ERRBASE_HWINIT	 200	/* Base Error number for HWInit */
+#define	SK_ERRBASE_VPD		 300	/* Base Error number for VPD */
+#define	SK_ERRBASE_PNMI		 400	/* Base Error number for PNMI */
+#define	SK_ERRBASE_CSUM		 500	/* Base Error number for Checksum */
+#define	SK_ERRBASE_SIRQ		 600	/* Base Error number for Special IRQ */
+#define	SK_ERRBASE_I2C		 700	/* Base Error number for I2C module */
+#define	SK_ERRBASE_QUEUE	 800	/* Base Error number for Scheduler */
+#define	SK_ERRBASE_ADDR		 900	/* Base Error number for Address module */
+#define SK_ERRBASE_PECP		1000    /* Base Error number for PECP */
+#define	SK_ERRBASE_DRV		1100	/* Base Error number for Driver */
+
+#endif	/* _INC_SKERROR_H_ */
diff --git a/drivers/net/sk98lin/h/skgedrv.h b/drivers/net/sk98lin/h/skgedrv.h
new file mode 100644
index 0000000..44fd4c3
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgedrv.h
@@ -0,0 +1,51 @@
+/******************************************************************************
+ *
+ * Name:	skgedrv.h
+ * Project:	Gigabit Ethernet Adapters, Common Modules
+ * Version:	$Revision: 1.10 $
+ * Date:	$Date: 2003/07/04 12:25:01 $
+ * Purpose:	Interface with the driver
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKGEDRV_H_
+#define __INC_SKGEDRV_H_
+
+/* defines ********************************************************************/
+
+/*
+ * Define the driver events.
+ * Usually the events are defined by the destination module.
+ * In case of the driver we put the definition of the events here.
+ */
+#define SK_DRV_PORT_RESET		 1	/* The port needs to be reset */
+#define SK_DRV_NET_UP   		 2	/* The net is operational */
+#define SK_DRV_NET_DOWN			 3	/* The net is down */
+#define SK_DRV_SWITCH_SOFT		 4	/* Ports switch with both links connected */
+#define SK_DRV_SWITCH_HARD		 5	/* Port switch due to link failure */
+#define SK_DRV_RLMT_SEND		 6	/* Send a RLMT packet */
+#define SK_DRV_ADAP_FAIL		 7	/* The whole adapter fails */
+#define SK_DRV_PORT_FAIL		 8	/* One port fails */
+#define SK_DRV_SWITCH_INTERN	 9	/* Port switch by the driver itself */
+#define SK_DRV_POWER_DOWN		10	/* Power down mode */
+#define SK_DRV_TIMER			11	/* Timer for free use */
+#ifdef SK_NO_RLMT
+#define SK_DRV_LINK_UP  		12	/* Link Up event for driver */
+#define SK_DRV_LINK_DOWN		13	/* Link Down event for driver */
+#endif
+#define SK_DRV_DOWNSHIFT_DET	14	/* Downshift 4-Pair / 2-Pair (YUKON only) */
+#endif /* __INC_SKGEDRV_H_ */
diff --git a/drivers/net/sk98lin/h/skgehw.h b/drivers/net/sk98lin/h/skgehw.h
new file mode 100644
index 0000000..f6282b7
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgehw.h
@@ -0,0 +1,2126 @@
+/******************************************************************************
+ *
+ * Name:	skgehw.h
+ * Project:	Gigabit Ethernet Adapters, Common Modules
+ * Version:	$Revision: 1.56 $
+ * Date:	$Date: 2003/09/23 09:01:00 $
+ * Purpose:	Defines and Macros for the Gigabit Ethernet Adapter Product Family
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKGEHW_H
+#define __INC_SKGEHW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif	/* __cplusplus */
+
+/* defines ********************************************************************/
+
+#define BIT_31		(1UL << 31)
+#define BIT_30		(1L << 30)
+#define BIT_29		(1L << 29)
+#define BIT_28		(1L << 28)
+#define BIT_27		(1L << 27)
+#define BIT_26		(1L << 26)
+#define BIT_25		(1L << 25)
+#define BIT_24		(1L << 24)
+#define BIT_23		(1L << 23)
+#define BIT_22		(1L << 22)
+#define BIT_21		(1L << 21)
+#define BIT_20		(1L << 20)
+#define BIT_19		(1L << 19)
+#define BIT_18		(1L << 18)
+#define BIT_17		(1L << 17)
+#define BIT_16		(1L << 16)
+#define BIT_15		(1L << 15)
+#define BIT_14		(1L << 14)
+#define BIT_13		(1L << 13)
+#define BIT_12		(1L << 12)
+#define BIT_11		(1L << 11)
+#define BIT_10		(1L << 10)
+#define BIT_9		(1L << 9)
+#define BIT_8		(1L << 8)
+#define BIT_7		(1L << 7)
+#define BIT_6		(1L << 6)
+#define BIT_5		(1L << 5)
+#define BIT_4		(1L << 4)
+#define BIT_3		(1L << 3)
+#define BIT_2		(1L << 2)
+#define BIT_1		(1L << 1)
+#define BIT_0		1L
+
+#define BIT_15S		(1U << 15)
+#define BIT_14S		(1 << 14)
+#define BIT_13S		(1 << 13)
+#define BIT_12S		(1 << 12)
+#define BIT_11S		(1 << 11)
+#define BIT_10S		(1 << 10)
+#define BIT_9S		(1 << 9)
+#define BIT_8S		(1 << 8)
+#define BIT_7S 		(1 << 7)
+#define BIT_6S		(1 << 6)
+#define BIT_5S		(1 << 5)
+#define BIT_4S		(1 << 4)
+#define BIT_3S		(1 << 3)
+#define BIT_2S		(1 << 2)
+#define BIT_1S		(1 << 1)
+#define BIT_0S		1
+
+#define SHIFT31(x)	((x) << 31)
+#define SHIFT30(x)	((x) << 30)
+#define SHIFT29(x)	((x) << 29)
+#define SHIFT28(x)	((x) << 28)
+#define SHIFT27(x)	((x) << 27)
+#define SHIFT26(x)	((x) << 26)
+#define SHIFT25(x)	((x) << 25)
+#define SHIFT24(x)	((x) << 24)
+#define SHIFT23(x)	((x) << 23)
+#define SHIFT22(x)	((x) << 22)
+#define SHIFT21(x)	((x) << 21)
+#define SHIFT20(x)	((x) << 20)
+#define SHIFT19(x)	((x) << 19)
+#define SHIFT18(x)	((x) << 18)
+#define SHIFT17(x)	((x) << 17)
+#define SHIFT16(x)	((x) << 16)
+#define SHIFT15(x)	((x) << 15)
+#define SHIFT14(x)	((x) << 14)
+#define SHIFT13(x)	((x) << 13)
+#define SHIFT12(x)	((x) << 12)
+#define SHIFT11(x)	((x) << 11)
+#define SHIFT10(x)	((x) << 10)
+#define SHIFT9(x)	((x) << 9)
+#define SHIFT8(x)	((x) << 8)
+#define SHIFT7(x)	((x) << 7)
+#define SHIFT6(x)	((x) << 6)
+#define SHIFT5(x)	((x) << 5)
+#define SHIFT4(x)	((x) << 4)
+#define SHIFT3(x)	((x) << 3)
+#define SHIFT2(x)	((x) << 2)
+#define SHIFT1(x)	((x) << 1)
+#define SHIFT0(x)	((x) << 0)
+
+/*
+ * Configuration Space header
+ * Since this module is used for different OS', those may be
+ * duplicate on some of them (e.g. Linux). But to keep the
+ * common source, we have to live with this...
+ */
+#define PCI_VENDOR_ID	0x00	/* 16 bit	Vendor ID */
+#define PCI_DEVICE_ID	0x02	/* 16 bit	Device ID */
+#define PCI_COMMAND		0x04	/* 16 bit	Command */
+#define PCI_STATUS		0x06	/* 16 bit	Status */
+#define PCI_REV_ID		0x08	/*  8 bit	Revision ID */
+#define PCI_CLASS_CODE	0x09	/* 24 bit	Class Code */
+#define PCI_CACHE_LSZ	0x0c	/*  8 bit	Cache Line Size */
+#define PCI_LAT_TIM		0x0d	/*  8 bit	Latency Timer */
+#define PCI_HEADER_T	0x0e	/*  8 bit	Header Type */
+#define PCI_BIST		0x0f	/*  8 bit	Built-in selftest */
+#define PCI_BASE_1ST	0x10	/* 32 bit	1st Base address */
+#define PCI_BASE_2ND	0x14	/* 32 bit	2nd Base address */
+	/* Byte 0x18..0x2b:	reserved */
+#define PCI_SUB_VID		0x2c	/* 16 bit	Subsystem Vendor ID */
+#define PCI_SUB_ID		0x2e	/* 16 bit	Subsystem ID */
+#define PCI_BASE_ROM	0x30	/* 32 bit	Expansion ROM Base Address */
+#define PCI_CAP_PTR		0x34	/*  8 bit 	Capabilities Ptr */
+	/* Byte 0x35..0x3b:	reserved */
+#define PCI_IRQ_LINE	0x3c	/*  8 bit	Interrupt Line */
+#define PCI_IRQ_PIN		0x3d	/*  8 bit	Interrupt Pin */
+#define PCI_MIN_GNT		0x3e	/*  8 bit	Min_Gnt */
+#define PCI_MAX_LAT		0x3f	/*  8 bit	Max_Lat */
+	/* Device Dependent Region */
+#define PCI_OUR_REG_1	0x40	/* 32 bit 	Our Register 1 */
+#define PCI_OUR_REG_2	0x44	/* 32 bit 	Our Register 2 */
+	/* Power Management Region */
+#define PCI_PM_CAP_ID	0x48	/*  8 bit 	Power Management Cap. ID */
+#define PCI_PM_NITEM	0x49	/*  8 bit 	Next Item Ptr */
+#define PCI_PM_CAP_REG	0x4a	/* 16 bit 	Power Management Capabilities */
+#define PCI_PM_CTL_STS	0x4c	/* 16 bit 	Power Manag. Control/Status */
+	/* Byte 0x4e:	reserved */
+#define PCI_PM_DAT_REG	0x4f	/*  8 bit 	Power Manag. Data Register */
+	/* VPD Region */
+#define PCI_VPD_CAP_ID	0x50	/*  8 bit 	VPD Cap. ID */
+#define PCI_VPD_NITEM	0x51	/*  8 bit 	Next Item Ptr */
+#define PCI_VPD_ADR_REG	0x52	/* 16 bit 	VPD Address Register */
+#define PCI_VPD_DAT_REG	0x54	/* 32 bit 	VPD Data Register */
+	/* Byte 0x58..0x59:	reserved */
+#define PCI_SER_LD_CTRL	0x5a	/* 16 bit 	SEEPROM Loader Ctrl (YUKON only) */
+	/* Byte 0x5c..0xff:	reserved */
+
+/*
+ * I2C Address (PCI Config)
+ *
+ * Note: The temperature and voltage sensors are relocated on a different
+ *	 I2C bus.
+ */
+#define I2C_ADDR_VPD	0xa0	/* I2C address for the VPD EEPROM */
+
+/*
+ * Define Bits and Values of the registers
+ */
+/*	PCI_COMMAND	16 bit	Command */
+								/* Bit 15..11:	reserved */
+#define PCI_INT_DIS		BIT_10S		/* Interrupt INTx# disable (PCI 2.3) */
+#define PCI_FBTEN		BIT_9S		/* Fast Back-To-Back enable */
+#define PCI_SERREN		BIT_8S		/* SERR enable */
+#define PCI_ADSTEP		BIT_7S		/* Address Stepping */
+#define PCI_PERREN		BIT_6S		/* Parity Report Response enable */
+#define PCI_VGA_SNOOP	BIT_5S		/* VGA palette snoop */
+#define PCI_MWIEN		BIT_4S		/* Memory write an inv cycl ena */
+#define PCI_SCYCEN		BIT_3S		/* Special Cycle enable */
+#define PCI_BMEN		BIT_2S		/* Bus Master enable */
+#define PCI_MEMEN		BIT_1S		/* Memory Space Access enable */
+#define PCI_IOEN		BIT_0S		/* I/O Space Access enable */
+
+#define PCI_COMMAND_VAL	(PCI_FBTEN | PCI_SERREN | PCI_PERREN | PCI_MWIEN |\
+						 PCI_BMEN | PCI_MEMEN | PCI_IOEN)
+
+/*	PCI_STATUS	16 bit	Status */
+#define PCI_PERR		BIT_15S		/* Parity Error */
+#define PCI_SERR		BIT_14S		/* Signaled SERR */
+#define PCI_RMABORT		BIT_13S		/* Received Master Abort */
+#define PCI_RTABORT		BIT_12S		/* Received Target Abort */
+								/* Bit 11:	reserved */
+#define PCI_DEVSEL		(3<<9)		/* Bit 10.. 9:	DEVSEL Timing */
+#define PCI_DEV_FAST	(0<<9)		/*		fast */
+#define PCI_DEV_MEDIUM	(1<<9)		/*		medium */
+#define PCI_DEV_SLOW	(2<<9)		/*		slow */
+#define PCI_DATAPERR	BIT_8S		/* DATA Parity error detected */
+#define PCI_FB2BCAP		BIT_7S		/* Fast Back-to-Back Capability */
+#define PCI_UDF			BIT_6S		/* User Defined Features */
+#define PCI_66MHZCAP	BIT_5S		/* 66 MHz PCI bus clock capable */
+#define PCI_NEWCAP		BIT_4S		/* New cap. list implemented */
+#define PCI_INT_STAT	BIT_3S		/* Interrupt INTx# Status (PCI 2.3) */
+								/* Bit  2.. 0:	reserved */
+
+#define PCI_ERRBITS	(PCI_PERR | PCI_SERR | PCI_RMABORT | PCI_RTABORT |\
+			PCI_DATAPERR)
+
+/*	PCI_CLASS_CODE	24 bit	Class Code */
+/*	Byte 2:		Base Class		(02) */
+/*	Byte 1:		SubClass		(00) */
+/*	Byte 0:		Programming Interface	(00) */
+
+/*	PCI_CACHE_LSZ	8 bit	Cache Line Size */
+/*	Possible values: 0,2,4,8,16,32,64,128	*/
+
+/*	PCI_HEADER_T	8 bit	Header Type */
+#define PCI_HD_MF_DEV	BIT_7S	/* 0= single, 1= multi-func dev */
+#define PCI_HD_TYPE		0x7f	/* Bit 6..0:	Header Layout 0= normal */
+
+/*	PCI_BIST	8 bit	Built-in selftest */
+/*	Built-in Self test not supported (optional) */
+
+/*	PCI_BASE_1ST	32 bit	1st Base address */
+#define PCI_MEMSIZE		0x4000L		/* use 16 kB Memory Base */
+#define PCI_MEMBASE_MSK 0xffffc000L	/* Bit 31..14:	Memory Base Address */
+#define PCI_MEMSIZE_MSK 0x00003ff0L	/* Bit 13.. 4:	Memory Size Req. */
+#define PCI_PREFEN		BIT_3		/* Prefetchable */
+#define PCI_MEM_TYP		(3L<<2)		/* Bit	2.. 1:	Memory Type */
+#define PCI_MEM32BIT	(0L<<1)		/* Base addr anywhere in 32 Bit range */
+#define PCI_MEM1M		(1L<<1)		/* Base addr below 1 MegaByte */
+#define PCI_MEM64BIT	(2L<<1)		/* Base addr anywhere in 64 Bit range */
+#define PCI_MEMSPACE	BIT_0		/* Memory Space Indicator */
+
+/*	PCI_BASE_2ND	32 bit	2nd Base address */
+#define PCI_IOBASE		0xffffff00L	/* Bit 31.. 8:	I/O Base address */
+#define PCI_IOSIZE		0x000000fcL	/* Bit	7.. 2:	I/O Size Requirements */
+									/* Bit	1:	reserved */
+#define PCI_IOSPACE		BIT_0		/* I/O Space Indicator */
+
+/*	PCI_BASE_ROM	32 bit	Expansion ROM Base Address */
+#define PCI_ROMBASE_MSK	0xfffe0000L	/* Bit 31..17:	ROM Base address */
+#define PCI_ROMBASE_SIZ	(0x1cL<<14)	/* Bit 16..14:	Treat as Base or Size */
+#define PCI_ROMSIZE		(0x38L<<11)	/* Bit 13..11:	ROM Size Requirements */
+									/* Bit 10.. 1:	reserved */
+#define PCI_ROMEN		BIT_0		/* Address Decode enable */
+
+/* Device Dependent Region */
+/*	PCI_OUR_REG_1		32 bit	Our Register 1 */
+									/* Bit 31..29:	reserved */
+#define PCI_PHY_COMA	BIT_28		/* Set PHY to Coma Mode (YUKON only) */
+#define PCI_TEST_CAL	BIT_27		/* Test PCI buffer calib. (YUKON only) */
+#define PCI_EN_CAL		BIT_26		/* Enable PCI buffer calib. (YUKON only) */
+#define PCI_VIO			BIT_25		/* PCI I/O Voltage, 0 = 3.3V, 1 = 5V */
+#define PCI_DIS_BOOT	BIT_24		/* Disable BOOT via ROM */
+#define PCI_EN_IO		BIT_23		/* Mapping to I/O space */
+#define PCI_EN_FPROM	BIT_22		/* Enable FLASH mapping to memory */
+									/*		1 = Map Flash to memory */
+									/*		0 = Disable addr. dec */
+#define PCI_PAGESIZE	(3L<<20)	/* Bit 21..20:	FLASH Page Size	*/
+#define PCI_PAGE_16		(0L<<20)	/*		16 k pages	*/
+#define PCI_PAGE_32K	(1L<<20)	/*		32 k pages	*/
+#define PCI_PAGE_64K	(2L<<20)	/*		64 k pages	*/
+#define PCI_PAGE_128K	(3L<<20)	/*		128 k pages	*/
+									/* Bit 19:	reserved	*/
+#define PCI_PAGEREG		(7L<<16)	/* Bit 18..16:	Page Register	*/
+#define PCI_NOTAR		BIT_15		/* No turnaround cycle */
+#define PCI_FORCE_BE	BIT_14		/* Assert all BEs on MR */
+#define PCI_DIS_MRL		BIT_13		/* Disable Mem Read Line */
+#define PCI_DIS_MRM		BIT_12		/* Disable Mem Read Multiple */
+#define PCI_DIS_MWI		BIT_11		/* Disable Mem Write & Invalidate */
+#define PCI_DISC_CLS	BIT_10		/* Disc: cacheLsz bound */
+#define PCI_BURST_DIS	BIT_9		/* Burst Disable */
+#define PCI_DIS_PCI_CLK	BIT_8		/* Disable PCI clock driving */
+#define PCI_SKEW_DAS	(0xfL<<4)	/* Bit	7.. 4:	Skew Ctrl, DAS Ext */
+#define PCI_SKEW_BASE	0xfL		/* Bit	3.. 0:	Skew Ctrl, Base	*/
+
+
+/*	PCI_OUR_REG_2		32 bit	Our Register 2 */
+#define PCI_VPD_WR_THR	(0xffL<<24)	/* Bit 31..24:	VPD Write Threshold */
+#define PCI_DEV_SEL		(0x7fL<<17)	/* Bit 23..17:	EEPROM Device Select */
+#define PCI_VPD_ROM_SZ	(7L<<14)	/* Bit 16..14:	VPD ROM Size	*/
+									/* Bit 13..12:	reserved	*/
+#define PCI_PATCH_DIR	(0xfL<<8)	/* Bit 11.. 8:	Ext Patches dir 3..0 */
+#define PCI_PATCH_DIR_3	BIT_11
+#define PCI_PATCH_DIR_2	BIT_10
+#define PCI_PATCH_DIR_1	BIT_9
+#define PCI_PATCH_DIR_0	BIT_8
+#define PCI_EXT_PATCHS	(0xfL<<4)	/* Bit	7.. 4:	Extended Patches 3..0 */
+#define PCI_EXT_PATCH_3	BIT_7
+#define PCI_EXT_PATCH_2	BIT_6
+#define PCI_EXT_PATCH_1	BIT_5
+#define PCI_EXT_PATCH_0	BIT_4
+#define PCI_EN_DUMMY_RD	BIT_3		/* Enable Dummy Read */
+#define PCI_REV_DESC	BIT_2		/* Reverse Desc. Bytes */
+									/* Bit	1:	reserved */
+#define PCI_USEDATA64	BIT_0		/* Use 64Bit Data bus ext */
+
+
+/* Power Management Region */
+/*	PCI_PM_CAP_REG		16 bit	Power Management Capabilities */
+#define PCI_PME_SUP_MSK	(0x1f<<11)	/* Bit 15..11:	PM Event Support Mask */
+#define PCI_PME_D3C_SUP	BIT_15S		/* PME from D3cold Support (if Vaux) */
+#define PCI_PME_D3H_SUP	BIT_14S		/* PME from D3hot Support */
+#define PCI_PME_D2_SUP	BIT_13S		/* PME from D2 Support */
+#define PCI_PME_D1_SUP	BIT_12S		/* PME from D1 Support */
+#define PCI_PME_D0_SUP	BIT_11S		/* PME from D0 Support */
+#define PCI_PM_D2_SUP	BIT_10S		/* D2 Support in 33 MHz mode */
+#define PCI_PM_D1_SUP	BIT_9S		/* D1 Support */
+									/* Bit	8.. 6:	reserved */
+#define PCI_PM_DSI		BIT_5S		/* Device Specific Initialization */
+#define PCI_PM_APS		BIT_4S		/* Auxialiary Power Source */
+#define PCI_PME_CLOCK	BIT_3S		/* PM Event Clock */
+#define PCI_PM_VER_MSK		7		/* Bit	2.. 0:	PM PCI Spec. version */
+
+/*	PCI_PM_CTL_STS		16 bit	Power Management Control/Status */
+#define PCI_PME_STATUS	BIT_15S		/* PME Status (YUKON only) */
+#define PCI_PM_DAT_SCL	(3<<13)		/* Bit 14..13:	Data Reg. scaling factor */
+#define PCI_PM_DAT_SEL	(0xf<<9)	/* Bit 12.. 9:	PM data selector field */
+#define PCI_PME_EN		BIT_8S		/* Enable PME# generation (YUKON only) */
+									/* Bit	7.. 2:	reserved */
+#define PCI_PM_STATE_MSK	3		/* Bit	1.. 0:	Power Management State */
+
+#define PCI_PM_STATE_D0		0		/* D0:	Operational (default) */
+#define PCI_PM_STATE_D1		1		/* D1:	(YUKON only) */
+#define PCI_PM_STATE_D2		2		/* D2:	(YUKON only) */
+#define PCI_PM_STATE_D3 	3		/* D3:	HOT, Power Down and Reset */
+
+/* VPD Region */
+/*	PCI_VPD_ADR_REG		16 bit	VPD Address Register */
+#define PCI_VPD_FLAG	BIT_15S		/* starts VPD rd/wr cycle */
+#define PCI_VPD_ADR_MSK	0x7fffL		/* Bit 14.. 0:	VPD address mask */
+
+/*	Control Register File (Address Map) */
+
+/*
+ *	Bank 0
+ */
+#define B0_RAP			0x0000	/*  8 bit	Register Address Port */
+	/* 0x0001 - 0x0003:	reserved */
+#define B0_CTST			0x0004	/* 16 bit	Control/Status register */
+#define B0_LED			0x0006	/*  8 Bit	LED register */
+#define B0_POWER_CTRL	0x0007	/*  8 Bit	Power Control reg (YUKON only) */
+#define B0_ISRC			0x0008	/* 32 bit	Interrupt Source Register */
+#define B0_IMSK			0x000c	/* 32 bit	Interrupt Mask Register */
+#define B0_HWE_ISRC		0x0010	/* 32 bit	HW Error Interrupt Src Reg */
+#define B0_HWE_IMSK		0x0014	/* 32 bit	HW Error Interrupt Mask Reg */
+#define B0_SP_ISRC		0x0018	/* 32 bit	Special Interrupt Source Reg */
+	/* 0x001c:		reserved */
+
+/* B0 XMAC 1 registers (GENESIS only) */
+#define B0_XM1_IMSK		0x0020	/* 16 bit r/w	XMAC 1 Interrupt Mask Register*/
+	/* 0x0022 - 0x0027:	reserved */
+#define B0_XM1_ISRC		0x0028	/* 16 bit ro	XMAC 1 Interrupt Status Reg */
+	/* 0x002a - 0x002f:	reserved */
+#define B0_XM1_PHY_ADDR 0x0030	/* 16 bit r/w	XMAC 1 PHY Address Register */
+	/* 0x0032 - 0x0033:	reserved */
+#define B0_XM1_PHY_DATA 0x0034	/* 16 bit r/w	XMAC 1 PHY Data Register */
+	/* 0x0036 - 0x003f:	reserved */
+
+/* B0 XMAC 2 registers (GENESIS only) */
+#define B0_XM2_IMSK		0x0040	/* 16 bit r/w	XMAC 2 Interrupt Mask Register*/
+	/* 0x0042 - 0x0047:	reserved */
+#define B0_XM2_ISRC		0x0048	/* 16 bit ro	XMAC 2 Interrupt Status Reg */
+	/* 0x004a - 0x004f:	reserved */
+#define B0_XM2_PHY_ADDR 0x0050	/* 16 bit r/w	XMAC 2 PHY Address Register */
+	/* 0x0052 - 0x0053:	reserved */
+#define B0_XM2_PHY_DATA 0x0054	/* 16 bit r/w	XMAC 2 PHY Data Register */
+	/* 0x0056 - 0x005f:	reserved */
+
+/* BMU Control Status Registers */
+#define B0_R1_CSR		0x0060	/* 32 bit	BMU Ctrl/Stat Rx Queue 1 */
+#define B0_R2_CSR		0x0064	/* 32 bit	BMU Ctrl/Stat Rx Queue 2 */
+#define B0_XS1_CSR		0x0068	/* 32 bit	BMU Ctrl/Stat Sync Tx Queue 1 */
+#define B0_XA1_CSR		0x006c	/* 32 bit	BMU Ctrl/Stat Async Tx Queue 1*/
+#define B0_XS2_CSR		0x0070	/* 32 bit	BMU Ctrl/Stat Sync Tx Queue 2 */
+#define B0_XA2_CSR		0x0074	/* 32 bit	BMU Ctrl/Stat Async Tx Queue 2*/
+	/* 0x0078 - 0x007f:	reserved */
+
+/*
+ *	Bank 1
+ *	- completely empty (this is the RAP Block window)
+ *	Note: if RAP = 1 this page is reserved
+ */
+
+/*
+ *	Bank 2
+ */
+/* NA reg = 48 bit Network Address Register, 3x16 or 8x8 bit readable */
+#define B2_MAC_1		0x0100	/* NA reg	 MAC Address 1 */
+	/* 0x0106 - 0x0107:	reserved */
+#define B2_MAC_2		0x0108	/* NA reg	 MAC Address 2 */
+	/* 0x010e - 0x010f:	reserved */
+#define B2_MAC_3		0x0110	/* NA reg	 MAC Address 3 */
+	/* 0x0116 - 0x0117:	reserved */
+#define B2_CONN_TYP		0x0118	/*  8 bit	Connector type */
+#define B2_PMD_TYP		0x0119	/*  8 bit	PMD type */
+#define B2_MAC_CFG		0x011a	/*  8 bit	MAC Configuration / Chip Revision */
+#define B2_CHIP_ID		0x011b	/*  8 bit 	Chip Identification Number */
+	/* Eprom registers are currently of no use */
+#define B2_E_0			0x011c	/*  8 bit	EPROM Byte 0 (ext. SRAM size */
+#define B2_E_1			0x011d	/*  8 bit	EPROM Byte 1 (PHY type) */
+#define B2_E_2			0x011e	/*  8 bit	EPROM Byte 2 */
+#define B2_E_3			0x011f	/*  8 bit	EPROM Byte 3 */
+#define B2_FAR			0x0120	/* 32 bit	Flash-Prom Addr Reg/Cnt */
+#define B2_FDP			0x0124	/*  8 bit	Flash-Prom Data Port */
+	/* 0x0125 - 0x0127:	reserved */
+#define B2_LD_CTRL		0x0128	/*  8 bit	EPROM loader control register */
+#define B2_LD_TEST		0x0129	/*  8 bit	EPROM loader test register */
+	/* 0x012a - 0x012f:	reserved */
+#define B2_TI_INI		0x0130	/* 32 bit	Timer Init Value */
+#define B2_TI_VAL		0x0134	/* 32 bit	Timer Value */
+#define B2_TI_CTRL		0x0138	/*  8 bit	Timer Control */
+#define B2_TI_TEST		0x0139	/*  8 Bit	Timer Test */
+	/* 0x013a - 0x013f:	reserved */
+#define B2_IRQM_INI		0x0140	/* 32 bit	IRQ Moderation Timer Init Reg.*/
+#define B2_IRQM_VAL		0x0144	/* 32 bit	IRQ Moderation Timer Value */
+#define B2_IRQM_CTRL	0x0148	/*  8 bit	IRQ Moderation Timer Control */
+#define B2_IRQM_TEST	0x0149	/*  8 bit	IRQ Moderation Timer Test */
+#define B2_IRQM_MSK 	0x014c	/* 32 bit	IRQ Moderation Mask */
+#define B2_IRQM_HWE_MSK 0x0150	/* 32 bit	IRQ Moderation HW Error Mask */
+	/* 0x0154 - 0x0157:	reserved */
+#define B2_TST_CTRL1	0x0158	/*  8 bit	Test Control Register 1 */
+#define B2_TST_CTRL2	0x0159	/*  8 bit	Test Control Register 2 */
+	/* 0x015a - 0x015b:	reserved */
+#define B2_GP_IO		0x015c	/* 32 bit	General Purpose I/O Register */
+#define B2_I2C_CTRL		0x0160	/* 32 bit	I2C HW Control Register */
+#define B2_I2C_DATA		0x0164	/* 32 bit	I2C HW Data Register */
+#define B2_I2C_IRQ		0x0168	/* 32 bit	I2C HW IRQ Register */
+#define B2_I2C_SW		0x016c	/* 32 bit	I2C SW Port Register */
+
+/* Blink Source Counter (GENESIS only) */
+#define B2_BSC_INI		0x0170	/* 32 bit	Blink Source Counter Init Val */
+#define B2_BSC_VAL		0x0174	/* 32 bit	Blink Source Counter Value */
+#define B2_BSC_CTRL		0x0178	/*  8 bit	Blink Source Counter Control */
+#define B2_BSC_STAT		0x0179	/*  8 bit	Blink Source Counter Status */
+#define B2_BSC_TST		0x017a	/* 16 bit	Blink Source Counter Test Reg */
+	/* 0x017c - 0x017f:	reserved */
+
+/*
+ *	Bank 3
+ */
+/* RAM Random Registers */
+#define B3_RAM_ADDR		0x0180	/* 32 bit	RAM Address, to read or write */
+#define B3_RAM_DATA_LO	0x0184	/* 32 bit	RAM Data Word (low dWord) */
+#define B3_RAM_DATA_HI	0x0188	/* 32 bit	RAM Data Word (high dWord) */
+	/* 0x018c - 0x018f:	reserved */
+
+/* RAM Interface Registers */
+/*
+ * The HW-Spec. calls this registers Timeout Value 0..11. But this names are
+ * not usable in SW. Please notice these are NOT real timeouts, these are
+ * the number of qWords transferred continuously.
+ */
+#define B3_RI_WTO_R1	0x0190	/*  8 bit	WR Timeout Queue R1		(TO0) */
+#define B3_RI_WTO_XA1	0x0191	/*  8 bit	WR Timeout Queue XA1	(TO1) */
+#define B3_RI_WTO_XS1	0x0192	/*  8 bit	WR Timeout Queue XS1	(TO2) */
+#define B3_RI_RTO_R1	0x0193	/*  8 bit	RD Timeout Queue R1		(TO3) */
+#define B3_RI_RTO_XA1	0x0194	/*  8 bit	RD Timeout Queue XA1	(TO4) */
+#define B3_RI_RTO_XS1	0x0195	/*  8 bit	RD Timeout Queue XS1	(TO5) */
+#define B3_RI_WTO_R2	0x0196	/*  8 bit	WR Timeout Queue R2		(TO6) */
+#define B3_RI_WTO_XA2	0x0197	/*  8 bit	WR Timeout Queue XA2	(TO7) */
+#define B3_RI_WTO_XS2	0x0198	/*  8 bit	WR Timeout Queue XS2	(TO8) */
+#define B3_RI_RTO_R2	0x0199	/*  8 bit	RD Timeout Queue R2		(TO9) */
+#define B3_RI_RTO_XA2	0x019a	/*  8 bit	RD Timeout Queue XA2	(TO10)*/
+#define B3_RI_RTO_XS2	0x019b	/*  8 bit	RD Timeout Queue XS2	(TO11)*/
+#define B3_RI_TO_VAL	0x019c	/*  8 bit	Current Timeout Count Val */
+	/* 0x019d - 0x019f:	reserved */
+#define B3_RI_CTRL		0x01a0	/* 16 bit	RAM Interface Control Register */
+#define B3_RI_TEST		0x01a2	/*  8 bit	RAM Interface Test Register */
+	/* 0x01a3 - 0x01af:	reserved */
+
+/* MAC Arbiter Registers (GENESIS only) */
+/* these are the no. of qWord transferred continuously and NOT real timeouts */
+#define B3_MA_TOINI_RX1	0x01b0	/*  8 bit	Timeout Init Val Rx Path MAC 1 */
+#define B3_MA_TOINI_RX2	0x01b1	/*  8 bit	Timeout Init Val Rx Path MAC 2 */
+#define B3_MA_TOINI_TX1	0x01b2	/*  8 bit	Timeout Init Val Tx Path MAC 1 */
+#define B3_MA_TOINI_TX2	0x01b3	/*  8 bit	Timeout Init Val Tx Path MAC 2 */
+#define B3_MA_TOVAL_RX1	0x01b4	/*  8 bit	Timeout Value Rx Path MAC 1 */
+#define B3_MA_TOVAL_RX2	0x01b5	/*  8 bit	Timeout Value Rx Path MAC 1 */
+#define B3_MA_TOVAL_TX1	0x01b6	/*  8 bit	Timeout Value Tx Path MAC 2 */
+#define B3_MA_TOVAL_TX2	0x01b7	/*  8 bit	Timeout Value Tx Path MAC 2 */
+#define B3_MA_TO_CTRL	0x01b8	/* 16 bit	MAC Arbiter Timeout Ctrl Reg */
+#define B3_MA_TO_TEST	0x01ba	/* 16 bit	MAC Arbiter Timeout Test Reg */
+	/* 0x01bc - 0x01bf:	reserved */
+#define B3_MA_RCINI_RX1	0x01c0	/*  8 bit	Recovery Init Val Rx Path MAC 1 */
+#define B3_MA_RCINI_RX2	0x01c1	/*  8 bit	Recovery Init Val Rx Path MAC 2 */
+#define B3_MA_RCINI_TX1	0x01c2	/*  8 bit	Recovery Init Val Tx Path MAC 1 */
+#define B3_MA_RCINI_TX2	0x01c3	/*  8 bit	Recovery Init Val Tx Path MAC 2 */
+#define B3_MA_RCVAL_RX1	0x01c4	/*  8 bit	Recovery Value Rx Path MAC 1 */
+#define B3_MA_RCVAL_RX2	0x01c5	/*  8 bit	Recovery Value Rx Path MAC 1 */
+#define B3_MA_RCVAL_TX1	0x01c6	/*  8 bit	Recovery Value Tx Path MAC 2 */
+#define B3_MA_RCVAL_TX2	0x01c7	/*  8 bit	Recovery Value Tx Path MAC 2 */
+#define B3_MA_RC_CTRL	0x01c8	/* 16 bit	MAC Arbiter Recovery Ctrl Reg */
+#define B3_MA_RC_TEST	0x01ca	/* 16 bit	MAC Arbiter Recovery Test Reg */
+	/* 0x01cc - 0x01cf:	reserved */
+
+/* Packet Arbiter Registers (GENESIS only) */
+/* these are real timeouts */
+#define B3_PA_TOINI_RX1	0x01d0	/* 16 bit	Timeout Init Val Rx Path MAC 1 */
+	/* 0x01d2 - 0x01d3:	reserved */
+#define B3_PA_TOINI_RX2	0x01d4	/* 16 bit	Timeout Init Val Rx Path MAC 2 */
+	/* 0x01d6 - 0x01d7:	reserved */
+#define B3_PA_TOINI_TX1	0x01d8	/* 16 bit	Timeout Init Val Tx Path MAC 1 */
+	/* 0x01da - 0x01db:	reserved */
+#define B3_PA_TOINI_TX2	0x01dc	/* 16 bit	Timeout Init Val Tx Path MAC 2 */
+	/* 0x01de - 0x01df:	reserved */
+#define B3_PA_TOVAL_RX1	0x01e0	/* 16 bit	Timeout Val Rx Path MAC 1 */
+	/* 0x01e2 - 0x01e3:	reserved */
+#define B3_PA_TOVAL_RX2	0x01e4	/* 16 bit	Timeout Val Rx Path MAC 2 */
+	/* 0x01e6 - 0x01e7:	reserved */
+#define B3_PA_TOVAL_TX1	0x01e8	/* 16 bit	Timeout Val Tx Path MAC 1 */
+	/* 0x01ea - 0x01eb:	reserved */
+#define B3_PA_TOVAL_TX2	0x01ec	/* 16 bit	Timeout Val Tx Path MAC 2 */
+	/* 0x01ee - 0x01ef:	reserved */
+#define B3_PA_CTRL	0x01f0	/* 16 bit	Packet Arbiter Ctrl Register */
+#define B3_PA_TEST	0x01f2	/* 16 bit	Packet Arbiter Test Register */
+	/* 0x01f4 - 0x01ff:	reserved */
+
+/*
+ *	Bank 4 - 5
+ */
+/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+#define TXA_ITI_INI		0x0200	/* 32 bit	Tx Arb Interval Timer Init Val*/
+#define TXA_ITI_VAL		0x0204	/* 32 bit	Tx Arb Interval Timer Value */
+#define TXA_LIM_INI		0x0208	/* 32 bit	Tx Arb Limit Counter Init Val */
+#define TXA_LIM_VAL		0x020c	/* 32 bit	Tx Arb Limit Counter Value */
+#define TXA_CTRL		0x0210	/*  8 bit	Tx Arbiter Control Register */
+#define TXA_TEST		0x0211	/*  8 bit	Tx Arbiter Test Register */
+#define TXA_STAT		0x0212	/*  8 bit	Tx Arbiter Status Register */
+	/* 0x0213 - 0x027f:	reserved */
+	/* 0x0280 - 0x0292:	MAC 2 */
+	/* 0x0213 - 0x027f:	reserved */
+
+/*
+ *	Bank 6
+ */
+/* External registers (GENESIS only) */
+#define B6_EXT_REG		0x0300
+
+/*
+ *	Bank 7
+ */
+/* This is a copy of the Configuration register file (lower half) */
+#define B7_CFG_SPC		0x0380
+
+/*
+ *	Bank 8 - 15
+ */
+/* Receive and Transmit Queue Registers, use Q_ADDR() to access */
+#define B8_Q_REGS		0x0400
+
+/* Queue Register Offsets, use Q_ADDR() to access */
+#define Q_D		0x00	/* 8*32	bit	Current Descriptor */
+#define Q_DA_L	0x20	/* 32 bit	Current Descriptor Address Low dWord */
+#define Q_DA_H	0x24	/* 32 bit	Current Descriptor Address High dWord */
+#define Q_AC_L	0x28	/* 32 bit	Current Address Counter Low dWord */
+#define Q_AC_H	0x2c	/* 32 bit	Current Address Counter High dWord */
+#define Q_BC	0x30	/* 32 bit	Current Byte Counter */
+#define Q_CSR	0x34	/* 32 bit	BMU Control/Status Register */
+#define Q_F		0x38	/* 32 bit	Flag Register */
+#define Q_T1	0x3c	/* 32 bit	Test Register 1 */
+#define Q_T1_TR	0x3c	/*  8 bit	Test Register 1 Transfer SM */
+#define Q_T1_WR	0x3d	/*  8 bit	Test Register 1 Write Descriptor SM */
+#define Q_T1_RD	0x3e	/*  8 bit	Test Register 1 Read Descriptor SM */
+#define Q_T1_SV	0x3f	/*  8 bit	Test Register 1 Supervisor SM */
+#define Q_T2	0x40	/* 32 bit	Test Register 2	*/
+#define Q_T3	0x44	/* 32 bit	Test Register 3	*/
+	/* 0x48 - 0x7f:	reserved */
+
+/*
+ *	Bank 16 - 23
+ */
+/* RAM Buffer Registers */
+#define B16_RAM_REGS	0x0800
+
+/* RAM Buffer Register Offsets, use RB_ADDR() to access */
+#define RB_START		0x00	/* 32 bit	RAM Buffer Start Address */
+#define RB_END			0x04	/* 32 bit	RAM Buffer End Address */
+#define RB_WP			0x08	/* 32 bit	RAM Buffer Write Pointer */
+#define RB_RP			0x0c	/* 32 bit	RAM Buffer Read Pointer */
+#define RB_RX_UTPP		0x10	/* 32 bit	Rx Upper Threshold, Pause Pack */
+#define RB_RX_LTPP		0x14	/* 32 bit	Rx Lower Threshold, Pause Pack */
+#define RB_RX_UTHP		0x18	/* 32 bit	Rx Upper Threshold, High Prio */
+#define RB_RX_LTHP		0x1c	/* 32 bit	Rx Lower Threshold, High Prio */
+	/* 0x10 - 0x1f:	reserved at Tx RAM Buffer Registers */
+#define RB_PC			0x20	/* 32 bit	RAM Buffer Packet Counter */
+#define RB_LEV			0x24	/* 32 bit	RAM Buffer Level Register */
+#define RB_CTRL			0x28	/*  8 bit	RAM Buffer Control Register */
+#define RB_TST1			0x29	/*  8 bit	RAM Buffer Test Register 1 */
+#define RB_TST2			0x2A	/*  8 bit	RAM Buffer Test Register 2 */
+	/* 0x2c - 0x7f:	reserved */
+
+/*
+ *	Bank 24
+ */
+/*
+ * Receive MAC FIFO, Receive LED, and Link_Sync regs (GENESIS only)
+ * use MR_ADDR() to access
+ */
+#define RX_MFF_EA		0x0c00	/* 32 bit	Receive MAC FIFO End Address */
+#define RX_MFF_WP		0x0c04	/* 32 bit 	Receive MAC FIFO Write Pointer */
+	/* 0x0c08 - 0x0c0b:	reserved */
+#define RX_MFF_RP		0x0c0c	/* 32 bit	Receive MAC FIFO Read Pointer */
+#define RX_MFF_PC		0x0c10	/* 32 bit	Receive MAC FIFO Packet Cnt */
+#define RX_MFF_LEV		0x0c14	/* 32 bit	Receive MAC FIFO Level */
+#define RX_MFF_CTRL1	0x0c18	/* 16 bit	Receive MAC FIFO Control Reg 1*/
+#define RX_MFF_STAT_TO	0x0c1a	/*  8 bit	Receive MAC Status Timeout */
+#define RX_MFF_TIST_TO	0x0c1b	/*  8 bit	Receive MAC Time Stamp Timeout */
+#define RX_MFF_CTRL2	0x0c1c	/*  8 bit	Receive MAC FIFO Control Reg 2*/
+#define RX_MFF_TST1		0x0c1d	/*  8 bit	Receive MAC FIFO Test Reg 1 */
+#define RX_MFF_TST2		0x0c1e	/*  8 bit	Receive MAC FIFO Test Reg 2 */
+	/* 0x0c1f:	reserved */
+#define RX_LED_INI		0x0c20	/* 32 bit	Receive LED Cnt Init Value */
+#define RX_LED_VAL		0x0c24	/* 32 bit	Receive LED Cnt Current Value */
+#define RX_LED_CTRL		0x0c28	/*  8 bit	Receive LED Cnt Control Reg */
+#define RX_LED_TST		0x0c29	/*  8 bit	Receive LED Cnt Test Register */
+	/* 0x0c2a - 0x0c2f:	reserved */
+#define LNK_SYNC_INI	0x0c30	/* 32 bit	Link Sync Cnt Init Value */
+#define LNK_SYNC_VAL	0x0c34	/* 32 bit	Link Sync Cnt Current Value */
+#define LNK_SYNC_CTRL	0x0c38	/*  8 bit	Link Sync Cnt Control Register */
+#define LNK_SYNC_TST	0x0c39	/*  8 bit	Link Sync Cnt Test Register */
+	/* 0x0c3a - 0x0c3b:	reserved */
+#define LNK_LED_REG		0x0c3c	/*  8 bit	Link LED Register */
+	/* 0x0c3d - 0x0c3f:	reserved */
+
+/* Receive GMAC FIFO (YUKON only), use MR_ADDR() to access */
+#define RX_GMF_EA		0x0c40	/* 32 bit	Rx GMAC FIFO End Address */
+#define RX_GMF_AF_THR	0x0c44	/* 32 bit	Rx GMAC FIFO Almost Full Thresh. */
+#define RX_GMF_CTRL_T	0x0c48	/* 32 bit	Rx GMAC FIFO Control/Test */
+#define RX_GMF_FL_MSK	0x0c4c	/* 32 bit	Rx GMAC FIFO Flush Mask */
+#define RX_GMF_FL_THR	0x0c50	/* 32 bit	Rx GMAC FIFO Flush Threshold */
+	/* 0x0c54 - 0x0c5f:	reserved */
+#define RX_GMF_WP		0x0c60	/* 32 bit 	Rx GMAC FIFO Write Pointer */
+	/* 0x0c64 - 0x0c67:	reserved */
+#define RX_GMF_WLEV		0x0c68	/* 32 bit 	Rx GMAC FIFO Write Level */
+	/* 0x0c6c - 0x0c6f:	reserved */
+#define RX_GMF_RP		0x0c70	/* 32 bit 	Rx GMAC FIFO Read Pointer */
+	/* 0x0c74 - 0x0c77:	reserved */
+#define RX_GMF_RLEV		0x0c78	/* 32 bit 	Rx GMAC FIFO Read Level */
+	/* 0x0c7c - 0x0c7f:	reserved */
+
+/*
+ *	Bank 25
+ */
+	/* 0x0c80 - 0x0cbf:	MAC 2 */
+	/* 0x0cc0 - 0x0cff:	reserved */
+
+/*
+ *	Bank 26
+ */
+/*
+ * Transmit MAC FIFO and Transmit LED Registers (GENESIS only),
+ * use MR_ADDR() to access
+ */
+#define TX_MFF_EA		0x0d00	/* 32 bit	Transmit MAC FIFO End Address */
+#define TX_MFF_WP		0x0d04	/* 32 bit 	Transmit MAC FIFO WR Pointer */
+#define TX_MFF_WSP		0x0d08	/* 32 bit	Transmit MAC FIFO WR Shadow Ptr */
+#define TX_MFF_RP		0x0d0c	/* 32 bit	Transmit MAC FIFO RD Pointer */
+#define TX_MFF_PC		0x0d10	/* 32 bit	Transmit MAC FIFO Packet Cnt */
+#define TX_MFF_LEV		0x0d14	/* 32 bit	Transmit MAC FIFO Level */
+#define TX_MFF_CTRL1	0x0d18	/* 16 bit	Transmit MAC FIFO Ctrl Reg 1 */
+#define TX_MFF_WAF		0x0d1a	/*  8 bit	Transmit MAC Wait after flush */
+	/* 0x0c1b:	reserved */
+#define TX_MFF_CTRL2	0x0d1c	/*  8 bit	Transmit MAC FIFO Ctrl Reg 2 */
+#define TX_MFF_TST1		0x0d1d	/*  8 bit	Transmit MAC FIFO Test Reg 1 */
+#define TX_MFF_TST2		0x0d1e	/*  8 bit	Transmit MAC FIFO Test Reg 2 */
+	/* 0x0d1f:	reserved */
+#define TX_LED_INI		0x0d20	/* 32 bit	Transmit LED Cnt Init Value */
+#define TX_LED_VAL		0x0d24	/* 32 bit	Transmit LED Cnt Current Val */
+#define TX_LED_CTRL		0x0d28	/*  8 bit	Transmit LED Cnt Control Reg */
+#define TX_LED_TST		0x0d29	/*  8 bit	Transmit LED Cnt Test Reg */
+	/* 0x0d2a - 0x0d3f:	reserved */
+
+/* Transmit GMAC FIFO (YUKON only), use MR_ADDR() to access */
+#define TX_GMF_EA		0x0d40	/* 32 bit	Tx GMAC FIFO End Address */
+#define TX_GMF_AE_THR	0x0d44	/* 32 bit	Tx GMAC FIFO Almost Empty Thresh.*/
+#define TX_GMF_CTRL_T	0x0d48	/* 32 bit	Tx GMAC FIFO Control/Test */
+	/* 0x0d4c - 0x0d5f:	reserved */
+#define TX_GMF_WP		0x0d60	/* 32 bit 	Tx GMAC FIFO Write Pointer */
+#define TX_GMF_WSP		0x0d64	/* 32 bit 	Tx GMAC FIFO Write Shadow Ptr. */
+#define TX_GMF_WLEV		0x0d68	/* 32 bit 	Tx GMAC FIFO Write Level */
+	/* 0x0d6c - 0x0d6f:	reserved */
+#define TX_GMF_RP		0x0d70	/* 32 bit 	Tx GMAC FIFO Read Pointer */
+#define TX_GMF_RSTP		0x0d74	/* 32 bit 	Tx GMAC FIFO Restart Pointer */
+#define TX_GMF_RLEV		0x0d78	/* 32 bit 	Tx GMAC FIFO Read Level */
+	/* 0x0d7c - 0x0d7f:	reserved */
+
+/*
+ *	Bank 27
+ */
+	/* 0x0d80 - 0x0dbf:	MAC 2 */
+	/* 0x0daa - 0x0dff:	reserved */
+
+/*
+ *	Bank 28
+ */
+/* Descriptor Poll Timer Registers */
+#define B28_DPT_INI		0x0e00	/* 24 bit	Descriptor Poll Timer Init Val */
+#define B28_DPT_VAL		0x0e04	/* 24 bit	Descriptor Poll Timer Curr Val */
+#define B28_DPT_CTRL	0x0e08	/*  8 bit	Descriptor Poll Timer Ctrl Reg */
+	/* 0x0e09:	reserved */
+#define B28_DPT_TST		0x0e0a	/*  8 bit	Descriptor Poll Timer Test Reg */
+	/* 0x0e0b:	reserved */
+
+/* Time Stamp Timer Registers (YUKON only) */
+	/* 0x0e10:	reserved */
+#define GMAC_TI_ST_VAL	0x0e14	/* 32 bit	Time Stamp Timer Curr Val */
+#define GMAC_TI_ST_CTRL	0x0e18	/*  8 bit	Time Stamp Timer Ctrl Reg */
+	/* 0x0e19:	reserved */
+#define GMAC_TI_ST_TST	0x0e1a	/*  8 bit	Time Stamp Timer Test Reg */
+	/* 0x0e1b - 0x0e7f:	reserved */
+
+/*
+ *	Bank 29
+ */
+	/* 0x0e80 - 0x0efc:	reserved */
+
+/*
+ *	Bank 30
+ */
+/* GMAC and GPHY Control Registers (YUKON only) */
+#define GMAC_CTRL		0x0f00	/* 32 bit	GMAC Control Reg */
+#define GPHY_CTRL		0x0f04	/* 32 bit	GPHY Control Reg */
+#define GMAC_IRQ_SRC	0x0f08	/*  8 bit	GMAC Interrupt Source Reg */
+	/* 0x0f09 - 0x0f0b:	reserved */
+#define GMAC_IRQ_MSK	0x0f0c	/*  8 bit	GMAC Interrupt Mask Reg */
+	/* 0x0f0d - 0x0f0f:	reserved */
+#define GMAC_LINK_CTRL	0x0f10	/* 16 bit	Link Control Reg */
+	/* 0x0f14 - 0x0f1f:	reserved */
+
+/* Wake-up Frame Pattern Match Control Registers (YUKON only) */
+
+#define WOL_REG_OFFS	0x20	/* HW-Bug: Address is + 0x20 against spec. */
+
+#define WOL_CTRL_STAT	0x0f20	/* 16 bit	WOL Control/Status Reg */
+#define WOL_MATCH_CTL	0x0f22	/*  8 bit	WOL Match Control Reg */
+#define WOL_MATCH_RES	0x0f23	/*  8 bit	WOL Match Result Reg */
+#define WOL_MAC_ADDR_LO	0x0f24	/* 32 bit	WOL MAC Address Low */
+#define WOL_MAC_ADDR_HI	0x0f28	/* 16 bit	WOL MAC Address High */
+#define WOL_PATT_RPTR	0x0f2c	/*  8 bit	WOL Pattern Read Ptr */
+
+/* use this macro to access above registers */
+#define WOL_REG(Reg)	((Reg) + (pAC->GIni.GIWolOffs))
+
+
+/* WOL Pattern Length Registers (YUKON only) */
+
+#define WOL_PATT_LEN_LO	0x0f30		/* 32 bit	WOL Pattern Length 3..0 */
+#define WOL_PATT_LEN_HI	0x0f34		/* 24 bit	WOL Pattern Length 6..4 */
+
+/* WOL Pattern Counter Registers (YUKON only) */
+
+#define WOL_PATT_CNT_0	0x0f38		/* 32 bit	WOL Pattern Counter 3..0 */
+#define WOL_PATT_CNT_4	0x0f3c		/* 24 bit	WOL Pattern Counter 6..4 */
+	/* 0x0f40 - 0x0f7f:	reserved */
+
+/*
+ *	Bank 31
+ */
+/* 0x0f80 - 0x0fff:	reserved */
+
+/*
+ *	Bank 32	- 33
+ */
+#define WOL_PATT_RAM_1	0x1000	/*  WOL Pattern RAM Link 1 */
+
+/*
+ *	Bank 0x22 - 0x3f
+ */
+/* 0x1100 - 0x1fff:	reserved */
+
+/*
+ *	Bank 0x40 - 0x4f
+ */
+#define BASE_XMAC_1		0x2000	/* XMAC 1 registers */
+
+/*
+ *	Bank 0x50 - 0x5f
+ */
+
+#define BASE_GMAC_1		0x2800	/* GMAC 1 registers */
+
+/*
+ *	Bank 0x60 - 0x6f
+ */
+#define BASE_XMAC_2		0x3000	/* XMAC 2 registers */
+
+/*
+ *	Bank 0x70 - 0x7f
+ */
+#define BASE_GMAC_2		0x3800	/* GMAC 2 registers */
+
+/*
+ *	Control Register Bit Definitions:
+ */
+/*	B0_RAP		8 bit	Register Address Port */
+								/* Bit 7:	reserved */
+#define RAP_RAP			0x3f	/* Bit 6..0:	0 = block 0,..,6f = block 6f */
+
+/*	B0_CTST			16 bit	Control/Status register */
+								/* Bit 15..14:	reserved */
+#define CS_CLK_RUN_HOT	BIT_13S		/* CLK_RUN hot m. (YUKON-Lite only) */
+#define CS_CLK_RUN_RST	BIT_12S		/* CLK_RUN reset  (YUKON-Lite only) */
+#define CS_CLK_RUN_ENA	BIT_11S		/* CLK_RUN enable (YUKON-Lite only) */
+#define CS_VAUX_AVAIL	BIT_10S		/* VAUX available (YUKON only) */
+#define CS_BUS_CLOCK	BIT_9S		/* Bus Clock 0/1 = 33/66 MHz */
+#define CS_BUS_SLOT_SZ	BIT_8S		/* Slot Size 0/1 = 32/64 bit slot */
+#define CS_ST_SW_IRQ	BIT_7S		/* Set IRQ SW Request */
+#define CS_CL_SW_IRQ	BIT_6S		/* Clear IRQ SW Request */
+#define CS_STOP_DONE	BIT_5S		/* Stop Master is finished */
+#define CS_STOP_MAST	BIT_4S		/* Command Bit to stop the master */
+#define CS_MRST_CLR		BIT_3S		/* Clear Master reset	*/
+#define CS_MRST_SET		BIT_2S		/* Set Master reset	*/
+#define CS_RST_CLR		BIT_1S		/* Clear Software reset	*/
+#define CS_RST_SET		BIT_0S		/* Set   Software reset	*/
+
+/*	B0_LED			 8 Bit	LED register */
+								/* Bit  7.. 2:	reserved */
+#define LED_STAT_ON		BIT_1S		/* Status LED on	*/
+#define LED_STAT_OFF	BIT_0S		/* Status LED off	*/
+
+/*	B0_POWER_CTRL	 8 Bit	Power Control reg (YUKON only) */
+#define PC_VAUX_ENA		BIT_7		/* Switch VAUX Enable  */
+#define PC_VAUX_DIS		BIT_6       /* Switch VAUX Disable */
+#define PC_VCC_ENA		BIT_5       /* Switch VCC Enable  */
+#define PC_VCC_DIS		BIT_4       /* Switch VCC Disable */
+#define PC_VAUX_ON		BIT_3       /* Switch VAUX On  */
+#define PC_VAUX_OFF		BIT_2       /* Switch VAUX Off */
+#define PC_VCC_ON		BIT_1       /* Switch VCC On  */
+#define PC_VCC_OFF		BIT_0       /* Switch VCC Off */
+
+/*	B0_ISRC			32 bit	Interrupt Source Register */
+/*	B0_IMSK			32 bit	Interrupt Mask Register */
+/*	B0_SP_ISRC		32 bit	Special Interrupt Source Reg */
+/*	B2_IRQM_MSK 	32 bit	IRQ Moderation Mask */
+#define IS_ALL_MSK		0xbfffffffUL	/* All Interrupt bits */
+#define IS_HW_ERR		BIT_31		/* Interrupt HW Error */
+								/* Bit 30:	reserved */
+#define IS_PA_TO_RX1	BIT_29		/* Packet Arb Timeout Rx1 */
+#define IS_PA_TO_RX2	BIT_28		/* Packet Arb Timeout Rx2 */
+#define IS_PA_TO_TX1	BIT_27		/* Packet Arb Timeout Tx1 */
+#define IS_PA_TO_TX2	BIT_26		/* Packet Arb Timeout Tx2 */
+#define IS_I2C_READY	BIT_25		/* IRQ on end of I2C Tx */
+#define IS_IRQ_SW		BIT_24		/* SW forced IRQ	*/
+#define IS_EXT_REG		BIT_23		/* IRQ from LM80 or PHY (GENESIS only) */
+									/* IRQ from PHY (YUKON only) */
+#define IS_TIMINT		BIT_22		/* IRQ from Timer	*/
+#define IS_MAC1			BIT_21		/* IRQ from MAC 1	*/
+#define IS_LNK_SYNC_M1	BIT_20		/* Link Sync Cnt wrap MAC 1 */
+#define IS_MAC2			BIT_19		/* IRQ from MAC 2	*/
+#define IS_LNK_SYNC_M2	BIT_18		/* Link Sync Cnt wrap MAC 2 */
+/* Receive Queue 1 */
+#define IS_R1_B			BIT_17		/* Q_R1 End of Buffer */
+#define IS_R1_F			BIT_16		/* Q_R1 End of Frame */
+#define IS_R1_C			BIT_15		/* Q_R1 Encoding Error */
+/* Receive Queue 2 */
+#define IS_R2_B			BIT_14		/* Q_R2 End of Buffer */
+#define IS_R2_F			BIT_13		/* Q_R2 End of Frame */
+#define IS_R2_C			BIT_12		/* Q_R2 Encoding Error */
+/* Synchronous Transmit Queue 1 */
+#define IS_XS1_B		BIT_11		/* Q_XS1 End of Buffer */
+#define IS_XS1_F		BIT_10		/* Q_XS1 End of Frame */
+#define IS_XS1_C		BIT_9		/* Q_XS1 Encoding Error */
+/* Asynchronous Transmit Queue 1 */
+#define IS_XA1_B		BIT_8		/* Q_XA1 End of Buffer */
+#define IS_XA1_F		BIT_7		/* Q_XA1 End of Frame */
+#define IS_XA1_C		BIT_6		/* Q_XA1 Encoding Error */
+/* Synchronous Transmit Queue 2 */
+#define IS_XS2_B		BIT_5		/* Q_XS2 End of Buffer */
+#define IS_XS2_F		BIT_4		/* Q_XS2 End of Frame */
+#define IS_XS2_C		BIT_3		/* Q_XS2 Encoding Error */
+/* Asynchronous Transmit Queue 2 */
+#define IS_XA2_B		BIT_2		/* Q_XA2 End of Buffer */
+#define IS_XA2_F		BIT_1		/* Q_XA2 End of Frame */
+#define IS_XA2_C		BIT_0		/* Q_XA2 Encoding Error */
+
+
+/*	B0_HWE_ISRC		32 bit	HW Error Interrupt Src Reg */
+/*	B0_HWE_IMSK		32 bit	HW Error Interrupt Mask Reg */
+/*	B2_IRQM_HWE_MSK	32 bit	IRQ Moderation HW Error Mask */
+#define IS_ERR_MSK		0x00000fffL	/* 		All Error bits */
+								/* Bit 31..14:	reserved */
+#define IS_IRQ_TIST_OV	BIT_13	/* Time Stamp Timer Overflow (YUKON only) */
+#define IS_IRQ_SENSOR	BIT_12	/* IRQ from Sensor (YUKON only) */
+#define IS_IRQ_MST_ERR	BIT_11	/* IRQ master error detected */
+#define IS_IRQ_STAT		BIT_10	/* IRQ status exception */
+#define IS_NO_STAT_M1	BIT_9	/* No Rx Status from MAC 1 */
+#define IS_NO_STAT_M2	BIT_8	/* No Rx Status from MAC 2 */
+#define IS_NO_TIST_M1	BIT_7	/* No Time Stamp from MAC 1 */
+#define IS_NO_TIST_M2	BIT_6	/* No Time Stamp from MAC 2 */
+#define IS_RAM_RD_PAR	BIT_5	/* RAM Read  Parity Error */
+#define IS_RAM_WR_PAR	BIT_4	/* RAM Write Parity Error */
+#define IS_M1_PAR_ERR	BIT_3	/* MAC 1 Parity Error */
+#define IS_M2_PAR_ERR	BIT_2	/* MAC 2 Parity Error */
+#define IS_R1_PAR_ERR	BIT_1	/* Queue R1 Parity Error */
+#define IS_R2_PAR_ERR	BIT_0	/* Queue R2 Parity Error */
+
+/*	B2_CONN_TYP		 8 bit	Connector type */
+/*	B2_PMD_TYP		 8 bit	PMD type */
+/*	Values of connector and PMD type comply to SysKonnect internal std */
+
+/*	B2_MAC_CFG		 8 bit	MAC Configuration / Chip Revision */
+#define CFG_CHIP_R_MSK	(0xf<<4)	/* Bit 7.. 4: Chip Revision */
+									/* Bit 3.. 2:	reserved */
+#define CFG_DIS_M2_CLK	BIT_1S		/* Disable Clock for 2nd MAC */
+#define CFG_SNG_MAC		BIT_0S		/* MAC Config: 0=2 MACs / 1=1 MAC*/
+
+/*	B2_CHIP_ID		 8 bit 	Chip Identification Number */
+#define CHIP_ID_GENESIS		0x0a	/* Chip ID for GENESIS */
+#define CHIP_ID_YUKON		0xb0	/* Chip ID for YUKON */
+#define CHIP_ID_YUKON_LITE	0xb1	/* Chip ID for YUKON-Lite (Rev. A1-A3) */
+#define CHIP_ID_YUKON_LP	0xb2	/* Chip ID for YUKON-LP */
+
+#define CHIP_REV_YU_LITE_A1	3		/* Chip Rev. for YUKON-Lite A1,A2 */
+#define CHIP_REV_YU_LITE_A3	7		/* Chip Rev. for YUKON-Lite A3 */
+
+/*	B2_FAR			32 bit	Flash-Prom Addr Reg/Cnt */
+#define FAR_ADDR		0x1ffffL	/* Bit 16.. 0:	FPROM Address mask */
+
+/*	B2_LD_CTRL		 8 bit	EPROM loader control register */
+/*	Bits are currently reserved */
+
+/*	B2_LD_TEST		 8 bit	EPROM loader test register */
+								/* Bit 7.. 4:	reserved */
+#define LD_T_ON			BIT_3S	/* Loader Test mode on */
+#define LD_T_OFF		BIT_2S	/* Loader Test mode off */
+#define LD_T_STEP		BIT_1S	/* Decrement FPROM addr. Counter */
+#define LD_START		BIT_0S	/* Start loading FPROM */
+
+/*
+ *	Timer Section
+ */
+/*	B2_TI_CTRL		 8 bit	Timer control */
+/*	B2_IRQM_CTRL	 8 bit	IRQ Moderation Timer Control */
+								/* Bit 7.. 3:	reserved */
+#define TIM_START		BIT_2S	/* Start Timer */
+#define TIM_STOP		BIT_1S	/* Stop  Timer */
+#define TIM_CLR_IRQ		BIT_0S	/* Clear Timer IRQ (!IRQM) */
+
+/*	B2_TI_TEST		 8 Bit	Timer Test */
+/*	B2_IRQM_TEST	 8 bit	IRQ Moderation Timer Test */
+/*	B28_DPT_TST		 8 bit	Descriptor Poll Timer Test Reg */
+								/* Bit 7.. 3:	reserved */
+#define TIM_T_ON		BIT_2S	/* Test mode on */
+#define TIM_T_OFF		BIT_1S	/* Test mode off */
+#define TIM_T_STEP		BIT_0S	/* Test step */
+
+/*	B28_DPT_INI	32 bit	Descriptor Poll Timer Init Val */
+/*	B28_DPT_VAL	32 bit	Descriptor Poll Timer Curr Val */
+								/* Bit 31..24:	reserved */
+#define DPT_MSK		0x00ffffffL	/* Bit 23.. 0:	Desc Poll Timer Bits */
+
+/*	B28_DPT_CTRL	 8 bit	Descriptor Poll Timer Ctrl Reg */
+								/* Bit  7.. 2:	reserved */
+#define DPT_START		BIT_1S	/* Start Descriptor Poll Timer */
+#define DPT_STOP		BIT_0S	/* Stop  Descriptor Poll Timer */
+
+/*	B2_E_3			 8 bit 	lower 4 bits used for HW self test result */
+#define B2_E3_RES_MASK	0x0f
+
+/*	B2_TST_CTRL1	 8 bit	Test Control Register 1 */
+#define TST_FRC_DPERR_MR	BIT_7S	/* force DATAPERR on MST RD */
+#define TST_FRC_DPERR_MW	BIT_6S	/* force DATAPERR on MST WR */
+#define TST_FRC_DPERR_TR	BIT_5S	/* force DATAPERR on TRG RD */
+#define TST_FRC_DPERR_TW	BIT_4S	/* force DATAPERR on TRG WR */
+#define TST_FRC_APERR_M		BIT_3S	/* force ADDRPERR on MST */
+#define TST_FRC_APERR_T		BIT_2S	/* force ADDRPERR on TRG */
+#define TST_CFG_WRITE_ON	BIT_1S	/* Enable  Config Reg WR */
+#define TST_CFG_WRITE_OFF	BIT_0S	/* Disable Config Reg WR */
+
+/*	B2_TST_CTRL2	 8 bit	Test Control Register 2 */
+									/* Bit 7.. 4:	reserved */
+			/* force the following error on the next master read/write	*/
+#define TST_FRC_DPERR_MR64	BIT_3S	/* DataPERR RD 64	*/
+#define TST_FRC_DPERR_MW64	BIT_2S	/* DataPERR WR 64	*/
+#define TST_FRC_APERR_1M64	BIT_1S	/* AddrPERR on 1. phase */
+#define TST_FRC_APERR_2M64	BIT_0S	/* AddrPERR on 2. phase */
+
+/*	B2_GP_IO		32 bit	General Purpose I/O Register */
+							/* Bit 31..26:	reserved */
+#define GP_DIR_9	BIT_25	/* IO_9 direct, 0=In/1=Out */
+#define GP_DIR_8	BIT_24	/* IO_8 direct, 0=In/1=Out */
+#define GP_DIR_7	BIT_23	/* IO_7 direct, 0=In/1=Out */
+#define GP_DIR_6	BIT_22	/* IO_6 direct, 0=In/1=Out */
+#define GP_DIR_5	BIT_21	/* IO_5 direct, 0=In/1=Out */
+#define GP_DIR_4	BIT_20	/* IO_4 direct, 0=In/1=Out */
+#define GP_DIR_3	BIT_19	/* IO_3 direct, 0=In/1=Out */
+#define GP_DIR_2	BIT_18	/* IO_2 direct, 0=In/1=Out */
+#define GP_DIR_1	BIT_17	/* IO_1 direct, 0=In/1=Out */
+#define GP_DIR_0	BIT_16	/* IO_0 direct, 0=In/1=Out */
+						/* Bit 15..10:	reserved */
+#define GP_IO_9		BIT_9	/* IO_9 pin */
+#define GP_IO_8		BIT_8	/* IO_8 pin */
+#define GP_IO_7		BIT_7	/* IO_7 pin */
+#define GP_IO_6		BIT_6	/* IO_6 pin */
+#define GP_IO_5		BIT_5	/* IO_5 pin */
+#define GP_IO_4		BIT_4	/* IO_4 pin */
+#define GP_IO_3		BIT_3	/* IO_3 pin */
+#define GP_IO_2		BIT_2	/* IO_2 pin */
+#define GP_IO_1		BIT_1	/* IO_1 pin */
+#define GP_IO_0		BIT_0	/* IO_0 pin */
+
+/*	B2_I2C_CTRL		32 bit	I2C HW Control Register */
+#define I2C_FLAG		BIT_31		/* Start read/write if WR */
+#define I2C_ADDR		(0x7fffL<<16)	/* Bit 30..16:	Addr to be RD/WR */
+#define I2C_DEV_SEL		(0x7fL<<9)		/* Bit 15.. 9:	I2C Device Select */
+								/* Bit	8.. 5:	reserved	*/
+#define I2C_BURST_LEN	BIT_4		/* Burst Len, 1/4 bytes */
+#define I2C_DEV_SIZE	(7<<1)		/* Bit	3.. 1:	I2C Device Size	*/
+#define I2C_025K_DEV	(0<<1)		/*		0: 256 Bytes or smal. */
+#define I2C_05K_DEV		(1<<1)		/* 		1: 512	Bytes	*/
+#define I2C_1K_DEV		(2<<1)		/*		2: 1024 Bytes	*/
+#define I2C_2K_DEV		(3<<1)		/*		3: 2048	Bytes	*/
+#define I2C_4K_DEV		(4<<1)		/*		4: 4096 Bytes	*/
+#define I2C_8K_DEV		(5<<1)		/*		5: 8192 Bytes	*/
+#define I2C_16K_DEV		(6<<1)		/*		6: 16384 Bytes	*/
+#define I2C_32K_DEV		(7<<1)		/*		7: 32768 Bytes	*/
+#define I2C_STOP		BIT_0		/* Interrupt I2C transfer */
+
+/*	B2_I2C_IRQ		32 bit	I2C HW IRQ Register */
+								/* Bit 31.. 1	reserved */
+#define I2C_CLR_IRQ		BIT_0	/* Clear I2C IRQ */
+
+/*	B2_I2C_SW		32 bit (8 bit access)	I2C HW SW Port Register */
+								/* Bit  7.. 3:	reserved */
+#define I2C_DATA_DIR	BIT_2S		/* direction of I2C_DATA */
+#define I2C_DATA		BIT_1S		/* I2C Data Port	*/
+#define I2C_CLK			BIT_0S		/* I2C Clock Port	*/
+
+/*
+ * I2C Address
+ */
+#define I2C_SENS_ADDR	LM80_ADDR	/* I2C Sensor Address, (Volt and Temp)*/
+
+
+/*	B2_BSC_CTRL		 8 bit	Blink Source Counter Control */
+							/* Bit  7.. 2:	reserved */
+#define BSC_START	BIT_1S		/* Start Blink Source Counter */
+#define BSC_STOP	BIT_0S		/* Stop  Blink Source Counter */
+
+/*	B2_BSC_STAT		 8 bit	Blink Source Counter Status */
+							/* Bit  7.. 1:	reserved */
+#define BSC_SRC		BIT_0S		/* Blink Source, 0=Off / 1=On */
+
+/*	B2_BSC_TST		16 bit	Blink Source Counter Test Reg */
+#define BSC_T_ON	BIT_2S		/* Test mode on */
+#define BSC_T_OFF	BIT_1S		/* Test mode off */
+#define BSC_T_STEP	BIT_0S		/* Test step */
+
+
+/*	B3_RAM_ADDR		32 bit	RAM Address, to read or write */
+					/* Bit 31..19:	reserved */
+#define RAM_ADR_RAN	0x0007ffffL	/* Bit 18.. 0:	RAM Address Range */
+
+/* RAM Interface Registers */
+/*	B3_RI_CTRL		16 bit	RAM Iface Control Register */
+								/* Bit 15..10:	reserved */
+#define RI_CLR_RD_PERR	BIT_9S	/* Clear IRQ RAM Read Parity Err */
+#define RI_CLR_WR_PERR	BIT_8S	/* Clear IRQ RAM Write Parity Err*/
+								/* Bit	7.. 2:	reserved */
+#define RI_RST_CLR		BIT_1S	/* Clear RAM Interface Reset */
+#define RI_RST_SET		BIT_0S	/* Set   RAM Interface Reset */
+
+/*	B3_RI_TEST		 8 bit	RAM Iface Test Register */
+								/* Bit 15.. 4:	reserved */
+#define RI_T_EV			BIT_3S	/* Timeout Event occured */
+#define RI_T_ON			BIT_2S	/* Timeout Timer Test On */
+#define RI_T_OFF		BIT_1S	/* Timeout Timer Test Off */
+#define RI_T_STEP		BIT_0S	/* Timeout Timer Step */
+
+/* MAC Arbiter Registers */
+/*	B3_MA_TO_CTRL	16 bit	MAC Arbiter Timeout Ctrl Reg */
+								/* Bit 15.. 4:	reserved */
+#define MA_FOE_ON		BIT_3S	/* XMAC Fast Output Enable ON */
+#define MA_FOE_OFF		BIT_2S	/* XMAC Fast Output Enable OFF */
+#define MA_RST_CLR		BIT_1S	/* Clear MAC Arbiter Reset */
+#define MA_RST_SET		BIT_0S	/* Set   MAC Arbiter Reset */
+
+/*	B3_MA_RC_CTRL	16 bit	MAC Arbiter Recovery Ctrl Reg */
+								/* Bit 15.. 8:	reserved */
+#define MA_ENA_REC_TX2	BIT_7S	/* Enable  Recovery Timer TX2 */
+#define MA_DIS_REC_TX2	BIT_6S	/* Disable Recovery Timer TX2 */
+#define MA_ENA_REC_TX1	BIT_5S	/* Enable  Recovery Timer TX1 */
+#define MA_DIS_REC_TX1	BIT_4S	/* Disable Recovery Timer TX1 */
+#define MA_ENA_REC_RX2	BIT_3S	/* Enable  Recovery Timer RX2 */
+#define MA_DIS_REC_RX2	BIT_2S	/* Disable Recovery Timer RX2 */
+#define MA_ENA_REC_RX1	BIT_1S	/* Enable  Recovery Timer RX1 */
+#define MA_DIS_REC_RX1	BIT_0S	/* Disable Recovery Timer RX1 */
+
+/* Packet Arbiter Registers */
+/*	B3_PA_CTRL		16 bit	Packet Arbiter Ctrl Register */
+								/* Bit 15..14:	reserved */
+#define PA_CLR_TO_TX2	BIT_13S	/* Clear IRQ Packet Timeout TX2 */
+#define PA_CLR_TO_TX1	BIT_12S	/* Clear IRQ Packet Timeout TX1 */
+#define PA_CLR_TO_RX2	BIT_11S	/* Clear IRQ Packet Timeout RX2 */
+#define PA_CLR_TO_RX1	BIT_10S	/* Clear IRQ Packet Timeout RX1 */
+#define PA_ENA_TO_TX2	BIT_9S	/* Enable  Timeout Timer TX2 */
+#define PA_DIS_TO_TX2	BIT_8S	/* Disable Timeout Timer TX2 */
+#define PA_ENA_TO_TX1	BIT_7S	/* Enable  Timeout Timer TX1 */
+#define PA_DIS_TO_TX1	BIT_6S	/* Disable Timeout Timer TX1 */
+#define PA_ENA_TO_RX2	BIT_5S	/* Enable  Timeout Timer RX2 */
+#define PA_DIS_TO_RX2	BIT_4S	/* Disable Timeout Timer RX2 */
+#define PA_ENA_TO_RX1	BIT_3S	/* Enable  Timeout Timer RX1 */
+#define PA_DIS_TO_RX1	BIT_2S	/* Disable Timeout Timer RX1 */
+#define PA_RST_CLR		BIT_1S	/* Clear MAC Arbiter Reset */
+#define PA_RST_SET		BIT_0S	/* Set   MAC Arbiter Reset */
+
+#define PA_ENA_TO_ALL	(PA_ENA_TO_RX1 | PA_ENA_TO_RX2 |\
+						PA_ENA_TO_TX1 | PA_ENA_TO_TX2)
+
+/* Rx/Tx Path related Arbiter Test Registers */
+/*	B3_MA_TO_TEST	16 bit	MAC Arbiter Timeout Test Reg */
+/*	B3_MA_RC_TEST	16 bit	MAC Arbiter Recovery Test Reg */
+/*	B3_PA_TEST		16 bit	Packet Arbiter Test Register */
+/*			Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */
+#define TX2_T_EV	BIT_15S		/* TX2 Timeout/Recv Event occured */
+#define TX2_T_ON	BIT_14S		/* TX2 Timeout/Recv Timer Test On */
+#define TX2_T_OFF	BIT_13S		/* TX2 Timeout/Recv Timer Tst Off */
+#define TX2_T_STEP	BIT_12S		/* TX2 Timeout/Recv Timer Step */
+#define TX1_T_EV	BIT_11S		/* TX1 Timeout/Recv Event occured */
+#define TX1_T_ON	BIT_10S		/* TX1 Timeout/Recv Timer Test On */
+#define TX1_T_OFF	BIT_9S		/* TX1 Timeout/Recv Timer Tst Off */
+#define TX1_T_STEP	BIT_8S		/* TX1 Timeout/Recv Timer Step */
+#define RX2_T_EV	BIT_7S		/* RX2 Timeout/Recv Event occured */
+#define RX2_T_ON	BIT_6S		/* RX2 Timeout/Recv Timer Test On */
+#define RX2_T_OFF	BIT_5S		/* RX2 Timeout/Recv Timer Tst Off */
+#define RX2_T_STEP	BIT_4S		/* RX2 Timeout/Recv Timer Step */
+#define RX1_T_EV	BIT_3S		/* RX1 Timeout/Recv Event occured */
+#define RX1_T_ON	BIT_2S		/* RX1 Timeout/Recv Timer Test On */
+#define RX1_T_OFF	BIT_1S		/* RX1 Timeout/Recv Timer Tst Off */
+#define RX1_T_STEP	BIT_0S		/* RX1 Timeout/Recv Timer Step */
+
+
+/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+/*	TXA_ITI_INI		32 bit	Tx Arb Interval Timer Init Val */
+/*	TXA_ITI_VAL		32 bit	Tx Arb Interval Timer Value */
+/*	TXA_LIM_INI		32 bit	Tx Arb Limit Counter Init Val */
+/*	TXA_LIM_VAL		32 bit	Tx Arb Limit Counter Value */
+								/* Bit 31..24:	reserved */
+#define TXA_MAX_VAL	0x00ffffffUL/* Bit 23.. 0:	Max TXA Timer/Cnt Val */
+
+/*	TXA_CTRL		 8 bit	Tx Arbiter Control Register */
+#define TXA_ENA_FSYNC	BIT_7S	/* Enable  force of sync Tx queue */
+#define TXA_DIS_FSYNC	BIT_6S	/* Disable force of sync Tx queue */
+#define TXA_ENA_ALLOC	BIT_5S	/* Enable  alloc of free bandwidth */
+#define TXA_DIS_ALLOC	BIT_4S	/* Disable alloc of free bandwidth */
+#define TXA_START_RC	BIT_3S	/* Start sync Rate Control */
+#define TXA_STOP_RC		BIT_2S	/* Stop  sync Rate Control */
+#define TXA_ENA_ARB		BIT_1S	/* Enable  Tx Arbiter */
+#define TXA_DIS_ARB		BIT_0S	/* Disable Tx Arbiter */
+
+/*	TXA_TEST		 8 bit	Tx Arbiter Test Register */
+								/* Bit 7.. 6:	reserved */
+#define TXA_INT_T_ON	BIT_5S	/* Tx Arb Interval Timer Test On */
+#define TXA_INT_T_OFF	BIT_4S	/* Tx Arb Interval Timer Test Off */
+#define TXA_INT_T_STEP	BIT_3S	/* Tx Arb Interval Timer Step */
+#define TXA_LIM_T_ON	BIT_2S	/* Tx Arb Limit Timer Test On */
+#define TXA_LIM_T_OFF	BIT_1S	/* Tx Arb Limit Timer Test Off */
+#define TXA_LIM_T_STEP	BIT_0S	/* Tx Arb Limit Timer Step */
+
+/*	TXA_STAT		 8 bit	Tx Arbiter Status Register */
+								/* Bit 7.. 1:	reserved */
+#define TXA_PRIO_XS		BIT_0S	/* sync queue has prio to send */
+
+/*	Q_BC			32 bit	Current Byte Counter */
+								/* Bit 31..16:	reserved */
+#define BC_MAX			0xffff	/* Bit 15.. 0:	Byte counter */
+
+/* BMU Control Status Registers */
+/*	B0_R1_CSR		32 bit	BMU Ctrl/Stat Rx Queue 1 */
+/*	B0_R2_CSR		32 bit	BMU Ctrl/Stat Rx Queue 2 */
+/*	B0_XA1_CSR		32 bit	BMU Ctrl/Stat Sync Tx Queue 1 */
+/*	B0_XS1_CSR		32 bit	BMU Ctrl/Stat Async Tx Queue 1 */
+/*	B0_XA2_CSR		32 bit	BMU Ctrl/Stat Sync Tx Queue 2 */
+/*	B0_XS2_CSR		32 bit	BMU Ctrl/Stat Async Tx Queue 2 */
+/*	Q_CSR			32 bit	BMU Control/Status Register */
+								/* Bit 31..25:	reserved */
+#define CSR_SV_IDLE		BIT_24		/* BMU SM Idle */
+								/* Bit 23..22:	reserved */
+#define CSR_DESC_CLR	BIT_21		/* Clear Reset for Descr */
+#define CSR_DESC_SET	BIT_20		/* Set   Reset for Descr */
+#define CSR_FIFO_CLR	BIT_19		/* Clear Reset for FIFO */
+#define CSR_FIFO_SET	BIT_18		/* Set   Reset for FIFO */
+#define CSR_HPI_RUN		BIT_17		/* Release HPI SM */
+#define CSR_HPI_RST		BIT_16		/* Reset   HPI SM to Idle */
+#define CSR_SV_RUN		BIT_15		/* Release Supervisor SM */
+#define CSR_SV_RST		BIT_14		/* Reset   Supervisor SM */
+#define CSR_DREAD_RUN	BIT_13		/* Release Descr Read SM */
+#define CSR_DREAD_RST	BIT_12		/* Reset   Descr Read SM */
+#define CSR_DWRITE_RUN	BIT_11		/* Release Descr Write SM */
+#define CSR_DWRITE_RST	BIT_10		/* Reset   Descr Write SM */
+#define CSR_TRANS_RUN	BIT_9		/* Release Transfer SM */
+#define CSR_TRANS_RST	BIT_8		/* Reset   Transfer SM */
+#define CSR_ENA_POL		BIT_7		/* Enable  Descr Polling */
+#define CSR_DIS_POL		BIT_6		/* Disable Descr Polling */
+#define CSR_STOP		BIT_5		/* Stop  Rx/Tx Queue */
+#define CSR_START		BIT_4		/* Start Rx/Tx Queue */
+#define CSR_IRQ_CL_P	BIT_3		/* (Rx)	Clear Parity IRQ */
+#define CSR_IRQ_CL_B	BIT_2		/* Clear EOB IRQ */
+#define CSR_IRQ_CL_F	BIT_1		/* Clear EOF IRQ */
+#define CSR_IRQ_CL_C	BIT_0		/* Clear ERR IRQ */
+
+#define CSR_SET_RESET	(CSR_DESC_SET | CSR_FIFO_SET | CSR_HPI_RST |\
+						CSR_SV_RST | CSR_DREAD_RST | CSR_DWRITE_RST |\
+						CSR_TRANS_RST)
+#define CSR_CLR_RESET	(CSR_DESC_CLR | CSR_FIFO_CLR | CSR_HPI_RUN |\
+						CSR_SV_RUN | CSR_DREAD_RUN | CSR_DWRITE_RUN |\
+						CSR_TRANS_RUN)
+
+/*	Q_F				32 bit	Flag Register */
+									/* Bit 31..28:	reserved */
+#define F_ALM_FULL		BIT_27		/* Rx FIFO: almost full */
+#define F_EMPTY			BIT_27		/* Tx FIFO: empty flag */
+#define F_FIFO_EOF		BIT_26		/* Tag (EOF Flag) bit in FIFO */
+#define F_WM_REACHED	BIT_25		/* Watermark reached */
+									/* reserved */
+#define F_FIFO_LEVEL	(0x1fL<<16)	/* Bit 23..16:	# of Qwords in FIFO */
+									/* Bit 15..11: 	reserved */
+#define F_WATER_MARK	0x0007ffL	/* Bit 10.. 0:	Watermark */
+
+/*	Q_T1			32 bit	Test Register 1 */
+/*		Holds four State Machine control Bytes */
+#define SM_CTRL_SV_MSK	(0xffL<<24)	/* Bit 31..24:	Control Supervisor SM */
+#define SM_CTRL_RD_MSK	(0xffL<<16)	/* Bit 23..16:	Control Read Desc SM */
+#define SM_CTRL_WR_MSK	(0xffL<<8)	/* Bit 15.. 8:	Control Write Desc SM */
+#define SM_CTRL_TR_MSK	0xffL		/* Bit	7.. 0:	Control Transfer SM */
+
+/*	Q_T1_TR			 8 bit	Test Register 1 Transfer SM */
+/*	Q_T1_WR			 8 bit	Test Register 1 Write Descriptor SM */
+/*	Q_T1_RD			 8 bit	Test Register 1 Read Descriptor SM */
+/*	Q_T1_SV			 8 bit	Test Register 1 Supervisor SM */
+
+/* The control status byte of each machine looks like ... */
+#define SM_STATE		0xf0	/* Bit 7.. 4:	State which shall be loaded */
+#define SM_LOAD			BIT_3S	/* Load the SM with SM_STATE */
+#define SM_TEST_ON		BIT_2S	/* Switch on SM Test Mode */
+#define SM_TEST_OFF		BIT_1S	/* Go off the Test Mode */
+#define SM_STEP			BIT_0S	/* Step the State Machine */
+/* The encoding of the states is not supported by the Diagnostics Tool */
+
+/*	Q_T2			32 bit	Test Register 2	*/
+								/* Bit 31.. 8:	reserved */
+#define T2_AC_T_ON		BIT_7	/* Address Counter Test Mode on */
+#define T2_AC_T_OFF		BIT_6	/* Address Counter Test Mode off */
+#define T2_BC_T_ON		BIT_5	/* Byte Counter Test Mode on */
+#define T2_BC_T_OFF		BIT_4	/* Byte Counter Test Mode off */
+#define T2_STEP04		BIT_3	/* Inc AC/Dec BC by 4 */
+#define T2_STEP03		BIT_2	/* Inc AC/Dec BC by 3 */
+#define T2_STEP02		BIT_1	/* Inc AC/Dec BC by 2 */
+#define T2_STEP01		BIT_0	/* Inc AC/Dec BC by 1 */
+
+/*	Q_T3			32 bit	Test Register 3	*/
+								/* Bit 31.. 7:	reserved */
+#define T3_MUX_MSK		(7<<4)	/* Bit  6.. 4:	Mux Position */
+								/* Bit  3:	reserved */
+#define T3_VRAM_MSK		7		/* Bit  2.. 0:	Virtual RAM Buffer Address */
+
+/* RAM Buffer Register Offsets, use RB_ADDR(Queue, Offs) to access */
+/*	RB_START		32 bit	RAM Buffer Start Address */
+/*	RB_END			32 bit	RAM Buffer End Address */
+/*	RB_WP			32 bit	RAM Buffer Write Pointer */
+/*	RB_RP			32 bit	RAM Buffer Read Pointer */
+/*	RB_RX_UTPP		32 bit	Rx Upper Threshold, Pause Pack */
+/*	RB_RX_LTPP		32 bit	Rx Lower Threshold, Pause Pack */
+/*	RB_RX_UTHP		32 bit	Rx Upper Threshold, High Prio */
+/*	RB_RX_LTHP		32 bit	Rx Lower Threshold, High Prio */
+/*	RB_PC			32 bit	RAM Buffer Packet Counter */
+/*	RB_LEV			32 bit	RAM Buffer Level Register */
+				/* Bit 31..19:	reserved */
+#define RB_MSK	0x0007ffff	/* Bit 18.. 0:	RAM Buffer Pointer Bits */
+
+/*	RB_TST2			 8 bit	RAM Buffer Test Register 2 */
+								/* Bit 7.. 4:	reserved */
+#define RB_PC_DEC		BIT_3S	/* Packet Counter Decrem */
+#define RB_PC_T_ON		BIT_2S	/* Packet Counter Test On */
+#define RB_PC_T_OFF		BIT_1S	/* Packet Counter Tst Off */
+#define RB_PC_INC		BIT_0S	/* Packet Counter Increm */
+
+/*	RB_TST1			 8 bit	RAM Buffer Test Register 1 */
+							/* Bit 7:	reserved */
+#define RB_WP_T_ON		BIT_6S	/* Write Pointer Test On */
+#define RB_WP_T_OFF		BIT_5S	/* Write Pointer Test Off */
+#define RB_WP_INC		BIT_4S	/* Write Pointer Increm */
+								/* Bit 3:	reserved */
+#define RB_RP_T_ON		BIT_2S	/* Read Pointer Test On */
+#define RB_RP_T_OFF		BIT_1S	/* Read Pointer Test Off */
+#define RB_RP_DEC		BIT_0S	/* Read Pointer Decrement */
+
+/*	RB_CTRL			 8 bit	RAM Buffer Control Register */
+								/* Bit 7.. 6:	reserved */
+#define RB_ENA_STFWD	BIT_5S	/* Enable  Store & Forward */
+#define RB_DIS_STFWD	BIT_4S	/* Disable Store & Forward */
+#define RB_ENA_OP_MD	BIT_3S	/* Enable  Operation Mode */
+#define RB_DIS_OP_MD	BIT_2S	/* Disable Operation Mode */
+#define RB_RST_CLR		BIT_1S	/* Clear RAM Buf STM Reset */
+#define RB_RST_SET		BIT_0S	/* Set   RAM Buf STM Reset */
+
+
+/* Receive and Transmit MAC FIFO Registers (GENESIS only) */
+
+/*	RX_MFF_EA		32 bit	Receive MAC FIFO End Address */
+/*	RX_MFF_WP		32 bit 	Receive MAC FIFO Write Pointer */
+/*	RX_MFF_RP		32 bit	Receive MAC FIFO Read Pointer */
+/*	RX_MFF_PC		32 bit	Receive MAC FIFO Packet Counter */
+/*	RX_MFF_LEV		32 bit	Receive MAC FIFO Level */
+/*	TX_MFF_EA		32 bit	Transmit MAC FIFO End Address */
+/*	TX_MFF_WP		32 bit 	Transmit MAC FIFO Write Pointer */
+/*	TX_MFF_WSP		32 bit	Transmit MAC FIFO WR Shadow Pointer */
+/*	TX_MFF_RP		32 bit	Transmit MAC FIFO Read Pointer */
+/*	TX_MFF_PC		32 bit	Transmit MAC FIFO Packet Cnt */
+/*	TX_MFF_LEV		32 bit	Transmit MAC FIFO Level */
+								/* Bit 31.. 6:	reserved */
+#define MFF_MSK			0x007fL	/* Bit	5.. 0:	MAC FIFO Address/Ptr Bits */
+
+/*	RX_MFF_CTRL1	16 bit	Receive MAC FIFO Control Reg 1 */
+								/* Bit 15..14:	reserved */
+#define MFF_ENA_RDY_PAT	BIT_13S		/* Enable  Ready Patch */
+#define MFF_DIS_RDY_PAT	BIT_12S		/* Disable Ready Patch */
+#define MFF_ENA_TIM_PAT	BIT_11S		/* Enable  Timing Patch */
+#define MFF_DIS_TIM_PAT	BIT_10S		/* Disable Timing Patch */
+#define MFF_ENA_ALM_FUL	BIT_9S		/* Enable  AlmostFull Sign */
+#define MFF_DIS_ALM_FUL	BIT_8S		/* Disable AlmostFull Sign */
+#define MFF_ENA_PAUSE	BIT_7S		/* Enable  Pause Signaling */
+#define MFF_DIS_PAUSE	BIT_6S		/* Disable Pause Signaling */
+#define MFF_ENA_FLUSH	BIT_5S		/* Enable  Frame Flushing */
+#define MFF_DIS_FLUSH	BIT_4S		/* Disable Frame Flushing */
+#define MFF_ENA_TIST	BIT_3S		/* Enable  Time Stamp Gener */
+#define MFF_DIS_TIST	BIT_2S		/* Disable Time Stamp Gener */
+#define MFF_CLR_INTIST	BIT_1S		/* Clear IRQ No Time Stamp */
+#define MFF_CLR_INSTAT	BIT_0S		/* Clear IRQ No Status */
+
+#define MFF_RX_CTRL_DEF MFF_ENA_TIM_PAT
+
+/*	TX_MFF_CTRL1	16 bit	Transmit MAC FIFO Control Reg 1 */
+#define MFF_CLR_PERR	BIT_15S		/* Clear Parity Error IRQ */
+								/* Bit 14:	reserved */
+#define MFF_ENA_PKT_REC	BIT_13S		/* Enable  Packet Recovery */
+#define MFF_DIS_PKT_REC BIT_12S		/* Disable Packet Recovery */
+/*	MFF_ENA_TIM_PAT	 (see RX_MFF_CTRL1) Bit 11:	Enable  Timing Patch */
+/*	MFF_DIS_TIM_PAT	 (see RX_MFF_CTRL1) Bit 10:	Disable Timing Patch */
+/*	MFF_ENA_ALM_FUL	 (see RX_MFF_CTRL1) Bit	 9:	Enable  Almost Full Sign */
+/*	MFF_DIS_ALM_FUL	 (see RX_MFF_CTRL1) Bit	 8:	Disable Almost Full Sign */
+#define MFF_ENA_W4E		BIT_7S		/* Enable  Wait for Empty */
+#define MFF_DIS_W4E		BIT_6S		/* Disable Wait for Empty */
+/*	MFF_ENA_FLUSH	 (see RX_MFF_CTRL1) Bit	 5:	Enable  Frame Flushing */
+/*	MFF_DIS_FLUSH	 (see RX_MFF_CTRL1) Bit	 4:	Disable Frame Flushing */
+#define MFF_ENA_LOOPB	BIT_3S		/* Enable  Loopback */
+#define MFF_DIS_LOOPB	BIT_2S		/* Disable Loopback */
+#define MFF_CLR_MAC_RST	BIT_1S		/* Clear XMAC Reset */
+#define MFF_SET_MAC_RST	BIT_0S		/* Set   XMAC Reset */
+
+#define MFF_TX_CTRL_DEF	(MFF_ENA_PKT_REC | MFF_ENA_TIM_PAT | MFF_ENA_FLUSH)
+
+/*	RX_MFF_TST2	 	 8 bit	Receive MAC FIFO Test Register 2 */
+/*	TX_MFF_TST2	 	 8 bit	Transmit MAC FIFO Test Register 2 */
+								/* Bit 7:	reserved */
+#define MFF_WSP_T_ON	BIT_6S	/* Tx: Write Shadow Ptr TestOn */
+#define MFF_WSP_T_OFF	BIT_5S	/* Tx: Write Shadow Ptr TstOff */
+#define MFF_WSP_INC		BIT_4S	/* Tx: Write Shadow Ptr Increment */
+#define MFF_PC_DEC		BIT_3S	/* Packet Counter Decrement */
+#define MFF_PC_T_ON		BIT_2S	/* Packet Counter Test On */
+#define MFF_PC_T_OFF	BIT_1S	/* Packet Counter Test Off */
+#define MFF_PC_INC		BIT_0S	/* Packet Counter Increment */
+
+/*	RX_MFF_TST1	 	 8 bit	Receive MAC FIFO Test Register 1 */
+/*	TX_MFF_TST1	 	 8 bit	Transmit MAC FIFO Test Register 1 */
+					/* Bit 7:	reserved */
+#define MFF_WP_T_ON		BIT_6S	/* Write Pointer Test On */
+#define MFF_WP_T_OFF	BIT_5S	/* Write Pointer Test Off */
+#define MFF_WP_INC		BIT_4S	/* Write Pointer Increm */
+							/* Bit 3:	reserved */
+#define MFF_RP_T_ON		BIT_2S	/* Read Pointer Test On */
+#define MFF_RP_T_OFF	BIT_1S	/* Read Pointer Test Off */
+#define MFF_RP_DEC		BIT_0S	/* Read Pointer Decrement */
+
+/*	RX_MFF_CTRL2	 8 bit	Receive MAC FIFO Control Reg 2 */
+/*	TX_MFF_CTRL2	 8 bit	Transmit MAC FIFO Control Reg 2 */
+								/* Bit 7..4:	reserved */
+#define MFF_ENA_OP_MD	BIT_3S	/* Enable  Operation Mode */
+#define MFF_DIS_OP_MD	BIT_2S	/* Disable Operation Mode */
+#define MFF_RST_CLR		BIT_1S	/* Clear MAC FIFO Reset */
+#define MFF_RST_SET		BIT_0S	/* Set   MAC FIFO Reset */
+
+
+/*	Link LED Counter Registers (GENESIS only) */
+
+/*	RX_LED_CTRL		 8 bit	Receive LED Cnt Control Reg */
+/*	TX_LED_CTRL		 8 bit	Transmit LED Cnt Control Reg */
+/*	LNK_SYNC_CTRL	 8 bit	Link Sync Cnt Control Register */
+							/* Bit 7.. 3:	reserved */
+#define LED_START		BIT_2S	/* Start Timer */
+#define LED_STOP		BIT_1S	/* Stop Timer */
+#define LED_STATE		BIT_0S	/* Rx/Tx: LED State, 1=LED on */
+#define LED_CLR_IRQ		BIT_0S	/* Lnk: 	Clear Link IRQ */
+
+/*	RX_LED_TST		 8 bit	Receive LED Cnt Test Register */
+/*	TX_LED_TST		 8 bit	Transmit LED Cnt Test Register */
+/*	LNK_SYNC_TST	 8 bit	Link Sync Cnt Test Register */
+							/* Bit 7.. 3:	reserved */
+#define LED_T_ON		BIT_2S	/* LED Counter Test mode On */
+#define LED_T_OFF		BIT_1S	/* LED Counter Test mode Off */
+#define LED_T_STEP		BIT_0S	/* LED Counter Step */
+
+/*	LNK_LED_REG	 	 8 bit	Link LED Register */
+								/* Bit 7.. 6:	reserved */
+#define LED_BLK_ON		BIT_5S	/* Link LED Blinking On */
+#define LED_BLK_OFF		BIT_4S	/* Link LED Blinking Off */
+#define LED_SYNC_ON		BIT_3S	/* Use Sync Wire to switch LED */
+#define LED_SYNC_OFF	BIT_2S	/* Disable Sync Wire Input */
+#define LED_ON			BIT_1S	/* switch LED on */
+#define LED_OFF			BIT_0S	/* switch LED off */
+
+/*	Receive and Transmit GMAC FIFO Registers (YUKON only) */
+
+/*	RX_GMF_EA		32 bit	Rx GMAC FIFO End Address */
+/*	RX_GMF_AF_THR	32 bit	Rx GMAC FIFO Almost Full Thresh. */
+/*	RX_GMF_WP		32 bit 	Rx GMAC FIFO Write Pointer */
+/*	RX_GMF_WLEV		32 bit 	Rx GMAC FIFO Write Level */
+/*	RX_GMF_RP		32 bit 	Rx GMAC FIFO Read Pointer */
+/*	RX_GMF_RLEV		32 bit 	Rx GMAC FIFO Read Level */
+/*	TX_GMF_EA		32 bit	Tx GMAC FIFO End Address */
+/*	TX_GMF_AE_THR	32 bit	Tx GMAC FIFO Almost Empty Thresh.*/
+/*	TX_GMF_WP		32 bit 	Tx GMAC FIFO Write Pointer */
+/*	TX_GMF_WSP		32 bit 	Tx GMAC FIFO Write Shadow Ptr. */
+/*	TX_GMF_WLEV		32 bit 	Tx GMAC FIFO Write Level */
+/*	TX_GMF_RP		32 bit 	Tx GMAC FIFO Read Pointer */
+/*	TX_GMF_RSTP		32 bit 	Tx GMAC FIFO Restart Pointer */
+/*	TX_GMF_RLEV		32 bit 	Tx GMAC FIFO Read Level */
+
+/*	RX_GMF_CTRL_T	32 bit	Rx GMAC FIFO Control/Test */
+						/* Bits 31..15:	reserved */
+#define GMF_WP_TST_ON	BIT_14		/* Write Pointer Test On */
+#define GMF_WP_TST_OFF	BIT_13		/* Write Pointer Test Off */
+#define GMF_WP_STEP		BIT_12		/* Write Pointer Step/Increment */
+						/* Bit 11:	reserved */
+#define GMF_RP_TST_ON	BIT_10		/* Read Pointer Test On */
+#define GMF_RP_TST_OFF	BIT_9		/* Read Pointer Test Off */
+#define GMF_RP_STEP		BIT_8		/* Read Pointer Step/Increment */
+#define GMF_RX_F_FL_ON	BIT_7		/* Rx FIFO Flush Mode On */
+#define GMF_RX_F_FL_OFF	BIT_6		/* Rx FIFO Flush Mode Off */
+#define GMF_CLI_RX_FO	BIT_5		/* Clear IRQ Rx FIFO Overrun */
+#define GMF_CLI_RX_FC	BIT_4		/* Clear IRQ Rx Frame Complete */
+#define GMF_OPER_ON		BIT_3		/* Operational Mode On */
+#define GMF_OPER_OFF	BIT_2		/* Operational Mode Off */
+#define GMF_RST_CLR		BIT_1		/* Clear GMAC FIFO Reset */
+#define GMF_RST_SET		BIT_0		/* Set   GMAC FIFO Reset */
+
+/*	TX_GMF_CTRL_T	32 bit	Tx GMAC FIFO Control/Test */
+						/* Bits 31..19:	reserved */
+#define GMF_WSP_TST_ON	BIT_18		/* Write Shadow Pointer Test On */
+#define GMF_WSP_TST_OFF	BIT_17		/* Write Shadow Pointer Test Off */
+#define GMF_WSP_STEP	BIT_16		/* Write Shadow Pointer Step/Increment */
+						/* Bits 15..7: same as for RX_GMF_CTRL_T */
+#define GMF_CLI_TX_FU	BIT_6		/* Clear IRQ Tx FIFO Underrun */
+#define GMF_CLI_TX_FC	BIT_5		/* Clear IRQ Tx Frame Complete */
+#define GMF_CLI_TX_PE	BIT_4		/* Clear IRQ Tx Parity Error */
+						/* Bits 3..0: same as for RX_GMF_CTRL_T */
+
+#define GMF_RX_CTRL_DEF		(GMF_OPER_ON | GMF_RX_F_FL_ON)
+#define GMF_TX_CTRL_DEF		GMF_OPER_ON
+
+#define RX_GMF_FL_THR_DEF	0x0a	/* Rx GMAC FIFO Flush Threshold default */
+
+/*	GMAC_TI_ST_CTRL	 8 bit	Time Stamp Timer Ctrl Reg (YUKON only) */
+								/* Bit 7.. 3:	reserved */
+#define GMT_ST_START	BIT_2S		/* Start Time Stamp Timer */
+#define GMT_ST_STOP		BIT_1S		/* Stop  Time Stamp Timer */
+#define GMT_ST_CLR_IRQ	BIT_0S		/* Clear Time Stamp Timer IRQ */
+
+/*	GMAC_CTRL		32 bit	GMAC Control Reg (YUKON only) */
+						/* Bits 31.. 8:	reserved */
+#define GMC_H_BURST_ON	BIT_7		/* Half Duplex Burst Mode On */
+#define GMC_H_BURST_OFF	BIT_6		/* Half Duplex Burst Mode Off */
+#define GMC_F_LOOPB_ON	BIT_5		/* FIFO Loopback On */
+#define GMC_F_LOOPB_OFF	BIT_4		/* FIFO Loopback Off */
+#define GMC_PAUSE_ON	BIT_3		/* Pause On */
+#define GMC_PAUSE_OFF	BIT_2		/* Pause Off */
+#define GMC_RST_CLR		BIT_1		/* Clear GMAC Reset */
+#define GMC_RST_SET		BIT_0		/* Set   GMAC Reset */
+
+/*	GPHY_CTRL		32 bit	GPHY Control Reg (YUKON only) */
+						/* Bits 31..29:	reserved */
+#define GPC_SEL_BDT		BIT_28	/* Select Bi-Dir. Transfer for MDC/MDIO */
+#define GPC_INT_POL_HI	BIT_27	/* IRQ Polarity is Active HIGH */
+#define GPC_75_OHM		BIT_26	/* Use 75 Ohm Termination instead of 50 */
+#define GPC_DIS_FC		BIT_25	/* Disable Automatic Fiber/Copper Detection */
+#define GPC_DIS_SLEEP	BIT_24	/* Disable Energy Detect */
+#define GPC_HWCFG_M_3	BIT_23	/* HWCFG_MODE[3] */
+#define GPC_HWCFG_M_2	BIT_22	/* HWCFG_MODE[2] */
+#define GPC_HWCFG_M_1	BIT_21	/* HWCFG_MODE[1] */
+#define GPC_HWCFG_M_0	BIT_20	/* HWCFG_MODE[0] */
+#define GPC_ANEG_0		BIT_19	/* ANEG[0] */
+#define GPC_ENA_XC		BIT_18	/* Enable MDI crossover */
+#define GPC_DIS_125		BIT_17	/* Disable 125 MHz clock */
+#define GPC_ANEG_3		BIT_16	/* ANEG[3] */
+#define GPC_ANEG_2		BIT_15	/* ANEG[2] */
+#define GPC_ANEG_1		BIT_14	/* ANEG[1] */
+#define GPC_ENA_PAUSE	BIT_13	/* Enable Pause (SYM_OR_REM) */
+#define GPC_PHYADDR_4	BIT_12	/* Bit 4 of Phy Addr */
+#define GPC_PHYADDR_3	BIT_11	/* Bit 3 of Phy Addr */
+#define GPC_PHYADDR_2	BIT_10	/* Bit 2 of Phy Addr */
+#define GPC_PHYADDR_1	BIT_9	/* Bit 1 of Phy Addr */
+#define GPC_PHYADDR_0	BIT_8	/* Bit 0 of Phy Addr */
+						/* Bits  7..2:	reserved */
+#define GPC_RST_CLR		BIT_1	/* Clear GPHY Reset */
+#define GPC_RST_SET		BIT_0	/* Set   GPHY Reset */
+
+#define GPC_HWCFG_GMII_COP	(GPC_HWCFG_M_3 | GPC_HWCFG_M_2 | \
+							 GPC_HWCFG_M_1 | GPC_HWCFG_M_0)
+
+#define GPC_HWCFG_GMII_FIB	(				 GPC_HWCFG_M_2 | \
+							 GPC_HWCFG_M_1 | GPC_HWCFG_M_0)
+
+#define GPC_ANEG_ADV_ALL_M	(GPC_ANEG_3 | GPC_ANEG_2 | \
+							 GPC_ANEG_1 | GPC_ANEG_0)
+
+/* forced speed and duplex mode (don't mix with other ANEG bits) */
+#define GPC_FRC10MBIT_HALF	0
+#define GPC_FRC10MBIT_FULL	GPC_ANEG_0
+#define GPC_FRC100MBIT_HALF	GPC_ANEG_1
+#define GPC_FRC100MBIT_FULL	(GPC_ANEG_0 | GPC_ANEG_1)
+
+/* auto-negotiation with limited advertised speeds */
+/* mix only with master/slave settings (for copper) */
+#define GPC_ADV_1000_HALF	GPC_ANEG_2
+#define GPC_ADV_1000_FULL	GPC_ANEG_3
+#define GPC_ADV_ALL			(GPC_ANEG_2 | GPC_ANEG_3)
+
+/* master/slave settings */
+/* only for copper with 1000 Mbps */
+#define GPC_FORCE_MASTER	0
+#define GPC_FORCE_SLAVE		GPC_ANEG_0
+#define GPC_PREF_MASTER		GPC_ANEG_1
+#define GPC_PREF_SLAVE		(GPC_ANEG_1 | GPC_ANEG_0)
+
+/*	GMAC_IRQ_SRC	 8 bit	GMAC Interrupt Source Reg (YUKON only) */
+/*	GMAC_IRQ_MSK	 8 bit	GMAC Interrupt Mask   Reg (YUKON only) */
+#define GM_IS_TX_CO_OV	BIT_5		/* Transmit Counter Overflow IRQ */
+#define GM_IS_RX_CO_OV	BIT_4		/* Receive Counter Overflow IRQ */
+#define GM_IS_TX_FF_UR	BIT_3		/* Transmit FIFO Underrun */
+#define GM_IS_TX_COMPL	BIT_2		/* Frame Transmission Complete */
+#define GM_IS_RX_FF_OR	BIT_1		/* Receive FIFO Overrun */
+#define GM_IS_RX_COMPL	BIT_0		/* Frame Reception Complete */
+
+#define GMAC_DEF_MSK	(GM_IS_TX_CO_OV | GM_IS_RX_CO_OV | \
+						GM_IS_TX_FF_UR)
+
+/*	GMAC_LINK_CTRL	16 bit	GMAC Link Control Reg (YUKON only) */
+						/* Bits 15.. 2:	reserved */
+#define GMLC_RST_CLR	BIT_1S		/* Clear GMAC Link Reset */
+#define GMLC_RST_SET	BIT_0S		/* Set   GMAC Link Reset */
+
+
+/*	WOL_CTRL_STAT	16 bit	WOL Control/Status Reg */
+#define WOL_CTL_LINK_CHG_OCC			BIT_15S
+#define WOL_CTL_MAGIC_PKT_OCC			BIT_14S
+#define WOL_CTL_PATTERN_OCC				BIT_13S
+
+#define WOL_CTL_CLEAR_RESULT			BIT_12S
+
+#define WOL_CTL_ENA_PME_ON_LINK_CHG		BIT_11S
+#define WOL_CTL_DIS_PME_ON_LINK_CHG		BIT_10S
+#define WOL_CTL_ENA_PME_ON_MAGIC_PKT	BIT_9S
+#define WOL_CTL_DIS_PME_ON_MAGIC_PKT	BIT_8S
+#define WOL_CTL_ENA_PME_ON_PATTERN		BIT_7S
+#define WOL_CTL_DIS_PME_ON_PATTERN		BIT_6S
+
+#define WOL_CTL_ENA_LINK_CHG_UNIT		BIT_5S
+#define WOL_CTL_DIS_LINK_CHG_UNIT		BIT_4S
+#define WOL_CTL_ENA_MAGIC_PKT_UNIT		BIT_3S
+#define WOL_CTL_DIS_MAGIC_PKT_UNIT		BIT_2S
+#define WOL_CTL_ENA_PATTERN_UNIT		BIT_1S
+#define WOL_CTL_DIS_PATTERN_UNIT		BIT_0S
+
+#define WOL_CTL_DEFAULT				\
+	(WOL_CTL_DIS_PME_ON_LINK_CHG |	\
+	WOL_CTL_DIS_PME_ON_PATTERN |	\
+	WOL_CTL_DIS_PME_ON_MAGIC_PKT |	\
+	WOL_CTL_DIS_LINK_CHG_UNIT |		\
+	WOL_CTL_DIS_PATTERN_UNIT |		\
+	WOL_CTL_DIS_MAGIC_PKT_UNIT)
+
+/*	WOL_MATCH_CTL	 8 bit	WOL Match Control Reg */
+#define WOL_CTL_PATT_ENA(x)				(BIT_0 << (x))
+
+#define SK_NUM_WOL_PATTERN		7
+#define SK_PATTERN_PER_WORD		4
+#define SK_BITMASK_PATTERN		7
+#define SK_POW_PATTERN_LENGTH	128
+
+#define WOL_LENGTH_MSK		0x7f
+#define WOL_LENGTH_SHIFT	8
+
+
+/* Receive and Transmit Descriptors ******************************************/
+
+/* Transmit Descriptor struct */
+typedef	struct s_HwTxd {
+	SK_U32 volatile	TxCtrl;	/* Transmit Buffer Control Field */
+	SK_U32	TxNext;			/* Physical Address Pointer to the next TxD */
+	SK_U32	TxAdrLo;		/* Physical Tx Buffer Address lower dword */
+	SK_U32	TxAdrHi;		/* Physical Tx Buffer Address upper dword */
+	SK_U32	TxStat;			/* Transmit Frame Status Word */
+#ifndef	SK_USE_REV_DESC
+	SK_U16	TxTcpOffs;		/* TCP Checksum Calculation Start Value */
+	SK_U16	TxRes1;			/* 16 bit reserved field */
+	SK_U16	TxTcpWp;		/* TCP Checksum Write Position */
+	SK_U16	TxTcpSp;		/* TCP Checksum Calculation Start Position */
+#else	/* SK_USE_REV_DESC */
+	SK_U16	TxRes1;			/* 16 bit reserved field */
+	SK_U16	TxTcpOffs;		/* TCP Checksum Calculation Start Value */
+	SK_U16	TxTcpSp;		/* TCP Checksum Calculation Start Position */
+	SK_U16	TxTcpWp;		/* TCP Checksum Write Position */
+#endif	/* SK_USE_REV_DESC */
+	SK_U32  TxRes2;			/* 32 bit reserved field */
+} SK_HWTXD;
+
+/* Receive Descriptor struct */
+typedef	struct s_HwRxd {
+	SK_U32 volatile RxCtrl;	/* Receive Buffer Control Field */
+	SK_U32	RxNext;			/* Physical Address Pointer to the next RxD */
+	SK_U32	RxAdrLo;		/* Physical Rx Buffer Address lower dword */
+	SK_U32	RxAdrHi;		/* Physical Rx Buffer Address upper dword */
+	SK_U32	RxStat;			/* Receive Frame Status Word */
+	SK_U32	RxTiSt;			/* Receive Time Stamp (from XMAC on GENESIS) */
+#ifndef	SK_USE_REV_DESC
+	SK_U16	RxTcpSum1;		/* TCP Checksum 1 */
+	SK_U16	RxTcpSum2;		/* TCP Checksum 2 */
+	SK_U16	RxTcpSp1;		/* TCP Checksum Calculation Start Position 1 */
+	SK_U16	RxTcpSp2;		/* TCP Checksum Calculation Start Position 2 */
+#else	/* SK_USE_REV_DESC */
+	SK_U16	RxTcpSum2;		/* TCP Checksum 2 */
+	SK_U16	RxTcpSum1;		/* TCP Checksum 1 */
+	SK_U16	RxTcpSp2;		/* TCP Checksum Calculation Start Position 2 */
+	SK_U16	RxTcpSp1;		/* TCP Checksum Calculation Start Position 1 */
+#endif	/* SK_USE_REV_DESC */
+} SK_HWRXD;
+
+/*
+ * Drivers which use the reverse descriptor feature (PCI_OUR_REG_2)
+ * should set the define SK_USE_REV_DESC.
+ * Structures are 'normaly' not endianess dependent. But in
+ * this case the SK_U16 fields are bound to bit positions inside the
+ * descriptor. RxTcpSum1 e.g. must start at bit 0 within the 6.th DWord.
+ * The bit positions inside a DWord are of course endianess dependent and
+ * swaps if the DWord is swapped by the hardware.
+ */
+
+
+/* Descriptor Bit Definition */
+/*	TxCtrl		Transmit Buffer Control Field */
+/*	RxCtrl		Receive  Buffer Control Field */
+#define BMU_OWN			BIT_31	/* OWN bit: 0=host/1=BMU */
+#define BMU_STF			BIT_30	/* Start of Frame */
+#define BMU_EOF			BIT_29	/* End of Frame */
+#define BMU_IRQ_EOB		BIT_28	/* Req "End of Buffer" IRQ */
+#define BMU_IRQ_EOF		BIT_27	/* Req "End of Frame" IRQ */
+/* TxCtrl specific bits */
+#define BMU_STFWD		BIT_26	/* (Tx)	Store & Forward Frame */
+#define BMU_NO_FCS		BIT_25	/* (Tx) Disable MAC FCS (CRC) generation */
+#define BMU_SW			BIT_24	/* (Tx)	1 bit res. for SW use */
+/* RxCtrl specific bits */
+#define BMU_DEV_0		BIT_26	/* (Rx)	Transfer data to Dev0 */
+#define BMU_STAT_VAL	BIT_25	/* (Rx)	Rx Status Valid */
+#define BMU_TIST_VAL	BIT_24	/* (Rx)	Rx TimeStamp Valid */
+								/* Bit 23..16:	BMU Check Opcodes */
+#define BMU_CHECK		(0x55L<<16)	/* Default BMU check */
+#define BMU_TCP_CHECK	(0x56L<<16)	/* Descr with TCP ext */
+#define BMU_UDP_CHECK	(0x57L<<16)	/* Descr with UDP ext (YUKON only) */
+#define BMU_BBC			0xffffL	/* Bit 15.. 0:	Buffer Byte Counter */
+
+/*	TxStat		Transmit Frame Status Word */
+/*	RxStat		Receive Frame Status Word */
+/*
+ *Note: TxStat is reserved for ASIC loopback mode only
+ *
+ *	The Bits of the Status words are defined in xmac_ii.h
+ *	(see XMR_FS bits)
+ */
+
+/* macros ********************************************************************/
+
+/* Receive and Transmit Queues */
+#define Q_R1	0x0000		/* Receive Queue 1 */
+#define Q_R2	0x0080		/* Receive Queue 2 */
+#define Q_XS1	0x0200		/* Synchronous Transmit Queue 1 */
+#define Q_XA1	0x0280		/* Asynchronous Transmit Queue 1 */
+#define Q_XS2	0x0300		/* Synchronous Transmit Queue 2 */
+#define Q_XA2	0x0380		/* Asynchronous Transmit Queue 2 */
+
+/*
+ *	Macro Q_ADDR()
+ *
+ *	Use this macro to access the Receive and Transmit Queue Registers.
+ *
+ * para:
+ *	Queue	Queue to access.
+ *				Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2
+ *	Offs	Queue register offset.
+ *				Values: Q_D, Q_DA_L ... Q_T2, Q_T3
+ *
+ * usage	SK_IN32(pAC, Q_ADDR(Q_R2, Q_BC), pVal)
+ */
+#define Q_ADDR(Queue, Offs)	(B8_Q_REGS + (Queue) + (Offs))
+
+/*
+ *	Macro RB_ADDR()
+ *
+ *	Use this macro to access the RAM Buffer Registers.
+ *
+ * para:
+ *	Queue	Queue to access.
+ *				Values: Q_R1, Q_R2, Q_XS1, Q_XA1, Q_XS2, and Q_XA2
+ *	Offs	Queue register offset.
+ *				Values: RB_START, RB_END ... RB_LEV, RB_CTRL
+ *
+ * usage	SK_IN32(pAC, RB_ADDR(Q_R2, RB_RP), pVal)
+ */
+#define RB_ADDR(Queue, Offs)	(B16_RAM_REGS + (Queue) + (Offs))
+
+
+/* MAC Related Registers */
+#define MAC_1		0	/* belongs to the port near the slot */
+#define MAC_2		1	/* belongs to the port far away from the slot */
+
+/*
+ *	Macro MR_ADDR()
+ *
+ *	Use this macro to access a MAC Related Registers inside the ASIC.
+ *
+ * para:
+ *	Mac		MAC to access.
+ *				Values: MAC_1, MAC_2
+ *	Offs	MAC register offset.
+ *				Values: RX_MFF_EA, RX_MFF_WP ... LNK_LED_REG,
+ *						TX_MFF_EA, TX_MFF_WP ... TX_LED_TST
+ *
+ * usage	SK_IN32(pAC, MR_ADDR(MAC_1, TX_MFF_EA), pVal)
+ */
+#define MR_ADDR(Mac, Offs)	(((Mac) << 7) + (Offs))
+
+#ifdef	SK_LITTLE_ENDIAN
+#define XM_WORD_LO	0
+#define XM_WORD_HI	1
+#else	/* !SK_LITTLE_ENDIAN */
+#define XM_WORD_LO	1
+#define XM_WORD_HI	0
+#endif	/* !SK_LITTLE_ENDIAN */
+
+
+/*
+ * macros to access the XMAC (GENESIS only)
+ *
+ * XM_IN16(),		to read a 16 bit register (e.g. XM_MMU_CMD)
+ * XM_OUT16(),		to write a 16 bit register (e.g. XM_MMU_CMD)
+ * XM_IN32(),		to read a 32 bit register (e.g. XM_TX_EV_CNT)
+ * XM_OUT32(),		to write a 32 bit register (e.g. XM_TX_EV_CNT)
+ * XM_INADDR(),		to read a network address register (e.g. XM_SRC_CHK)
+ * XM_OUTADDR(),	to write a network address register (e.g. XM_SRC_CHK)
+ * XM_INHASH(),		to read the XM_HSM_CHK register
+ * XM_OUTHASH()		to write the XM_HSM_CHK register
+ *
+ * para:
+ *	Mac		XMAC to access		values: MAC_1 or MAC_2
+ *	IoC		I/O context needed for SK I/O macros
+ *	Reg		XMAC Register to read or write
+ *	(p)Val	Value or pointer to the value which should be read or written
+ *
+ * usage:	XM_OUT16(IoC, MAC_1, XM_MMU_CMD, Value);
+ */
+
+#define XMA(Mac, Reg)									\
+	((BASE_XMAC_1 + (Mac) * (BASE_XMAC_2 - BASE_XMAC_1)) | ((Reg) << 1))
+
+#define XM_IN16(IoC, Mac, Reg, pVal)					\
+	SK_IN16((IoC), XMA((Mac), (Reg)), (pVal))
+
+#define XM_OUT16(IoC, Mac, Reg, Val)					\
+	SK_OUT16((IoC), XMA((Mac), (Reg)), (Val))
+
+#define XM_IN32(IoC, Mac, Reg, pVal) {					\
+	SK_IN16((IoC), XMA((Mac), (Reg)),					\
+		(SK_U16 SK_FAR*)&((SK_U16 SK_FAR*)(pVal))[XM_WORD_LO]);		\
+	SK_IN16((IoC), XMA((Mac), (Reg+2)),					\
+		(SK_U16 SK_FAR*)&((SK_U16 SK_FAR*)(pVal))[XM_WORD_HI]);		\
+}
+
+#define XM_OUT32(IoC, Mac, Reg, Val) {										\
+	SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16)((Val) & 0xffffL));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)(((Val) >> 16) & 0xffffL));\
+}
+
+/* Remember: we are always writing to / reading from LITTLE ENDIAN memory */
+
+#define XM_INADDR(IoC, Mac, Reg, pVal) {				\
+	SK_U16	Word;										\
+	SK_U8	*pByte;										\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_IN16((IoC), XMA((Mac), (Reg)), &Word);			\
+	pByte[0] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[1] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word);			\
+	pByte[2] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[3] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word);			\
+	pByte[4] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[5] = (SK_U8)((Word >> 8) & 0x00ff);			\
+}
+
+#define XM_OUTADDR(IoC, Mac, Reg, pVal) {				\
+	SK_U8	SK_FAR *pByte;								\
+	pByte = (SK_U8 SK_FAR *)&((SK_U8 SK_FAR *)(pVal))[0];	\
+	SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16)			\
+		(((SK_U16)(pByte[0]) & 0x00ff) |				\
+		(((SK_U16)(pByte[1]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)		\
+		(((SK_U16)(pByte[2]) & 0x00ff) |				\
+		(((SK_U16)(pByte[3]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16)		\
+		(((SK_U16)(pByte[4]) & 0x00ff) |				\
+		(((SK_U16)(pByte[5]) << 8) & 0xff00)));			\
+}
+
+#define XM_INHASH(IoC, Mac, Reg, pVal) {				\
+	SK_U16	Word;										\
+	SK_U8	SK_FAR *pByte;								\
+	pByte = (SK_U8 SK_FAR *)&((SK_U8 SK_FAR *)(pVal))[0];	\
+	SK_IN16((IoC), XMA((Mac), (Reg)), &Word);			\
+	pByte[0] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[1] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), XMA((Mac), (Reg+2)), &Word);			\
+	pByte[2] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[3] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), XMA((Mac), (Reg+4)), &Word);			\
+	pByte[4] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[5] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), XMA((Mac), (Reg+6)), &Word);			\
+	pByte[6] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[7] = (SK_U8)((Word >> 8) & 0x00ff);			\
+}
+
+#define XM_OUTHASH(IoC, Mac, Reg, pVal) {				\
+	SK_U8	SK_FAR *pByte;								\
+	pByte = (SK_U8 SK_FAR *)&((SK_U8 SK_FAR *)(pVal))[0];	\
+	SK_OUT16((IoC), XMA((Mac), (Reg)), (SK_U16)			\
+		(((SK_U16)(pByte[0]) & 0x00ff)|					\
+		(((SK_U16)(pByte[1]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+2)), (SK_U16)		\
+		(((SK_U16)(pByte[2]) & 0x00ff)|					\
+		(((SK_U16)(pByte[3]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+4)), (SK_U16)		\
+		(((SK_U16)(pByte[4]) & 0x00ff)|					\
+		(((SK_U16)(pByte[5]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), XMA((Mac), (Reg+6)), (SK_U16)		\
+		(((SK_U16)(pByte[6]) & 0x00ff)|					\
+		(((SK_U16)(pByte[7]) << 8) & 0xff00)));			\
+}
+
+/*
+ * macros to access the GMAC (YUKON only)
+ *
+ * GM_IN16(),		to read  a 16 bit register (e.g. GM_GP_STAT)
+ * GM_OUT16(),		to write a 16 bit register (e.g. GM_GP_CTRL)
+ * GM_IN32(),		to read  a 32 bit register (e.g. GM_)
+ * GM_OUT32(),		to write a 32 bit register (e.g. GM_)
+ * GM_INADDR(),		to read  a network address register (e.g. GM_SRC_ADDR_1L)
+ * GM_OUTADDR(),	to write a network address register (e.g. GM_SRC_ADDR_2L)
+ * GM_INHASH(),		to read  the GM_MC_ADDR_H1 register
+ * GM_OUTHASH()		to write the GM_MC_ADDR_H1 register
+ *
+ * para:
+ *	Mac		GMAC to access		values: MAC_1 or MAC_2
+ *	IoC		I/O context needed for SK I/O macros
+ *	Reg		GMAC Register to read or write
+ *	(p)Val	Value or pointer to the value which should be read or written
+ *
+ * usage:	GM_OUT16(IoC, MAC_1, GM_GP_CTRL, Value);
+ */
+
+#define GMA(Mac, Reg)									\
+	((BASE_GMAC_1 + (Mac) * (BASE_GMAC_2 - BASE_GMAC_1)) | (Reg))
+
+#define GM_IN16(IoC, Mac, Reg, pVal)					\
+	SK_IN16((IoC), GMA((Mac), (Reg)), (pVal))
+
+#define GM_OUT16(IoC, Mac, Reg, Val)					\
+	SK_OUT16((IoC), GMA((Mac), (Reg)), (Val))
+
+#define GM_IN32(IoC, Mac, Reg, pVal) {					\
+	SK_IN16((IoC), GMA((Mac), (Reg)),					\
+		(SK_U16 SK_FAR*)&((SK_U16 SK_FAR*)(pVal))[XM_WORD_LO]);		\
+	SK_IN16((IoC), GMA((Mac), (Reg+4)),					\
+		(SK_U16 SK_FAR*)&((SK_U16 SK_FAR*)(pVal))[XM_WORD_HI]);		\
+}
+
+#define GM_OUT32(IoC, Mac, Reg, Val) {										\
+	SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16)((Val) & 0xffffL));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16)(((Val) >> 16) & 0xffffL));\
+}
+
+#define GM_INADDR(IoC, Mac, Reg, pVal) {				\
+	SK_U16	Word;										\
+	SK_U8	*pByte;										\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_IN16((IoC), GMA((Mac), (Reg)), &Word);			\
+	pByte[0] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[1] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), GMA((Mac), (Reg+4)), &Word);			\
+	pByte[2] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[3] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), GMA((Mac), (Reg+8)), &Word);			\
+	pByte[4] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[5] = (SK_U8)((Word >> 8) & 0x00ff);			\
+}
+
+#define GM_OUTADDR(IoC, Mac, Reg, pVal) {				\
+	SK_U8	SK_FAR *pByte;								\
+	pByte = (SK_U8 SK_FAR *)&((SK_U8 SK_FAR *)(pVal))[0];	\
+	SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16)			\
+		(((SK_U16)(pByte[0]) & 0x00ff) |				\
+		(((SK_U16)(pByte[1]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16)		\
+		(((SK_U16)(pByte[2]) & 0x00ff) |				\
+		(((SK_U16)(pByte[3]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+8)), (SK_U16)		\
+		(((SK_U16)(pByte[4]) & 0x00ff) |				\
+		(((SK_U16)(pByte[5]) << 8) & 0xff00)));			\
+}
+
+#define GM_INHASH(IoC, Mac, Reg, pVal) {				\
+	SK_U16	Word;										\
+	SK_U8	*pByte;										\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_IN16((IoC), GMA((Mac), (Reg)), &Word);			\
+	pByte[0] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[1] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), GMA((Mac), (Reg+4)), &Word);			\
+	pByte[2] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[3] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), GMA((Mac), (Reg+8)), &Word);			\
+	pByte[4] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[5] = (SK_U8)((Word >> 8) & 0x00ff);			\
+	SK_IN16((IoC), GMA((Mac), (Reg+12)), &Word);		\
+	pByte[6] = (SK_U8)(Word  & 0x00ff);					\
+	pByte[7] = (SK_U8)((Word >> 8) & 0x00ff);			\
+}
+
+#define GM_OUTHASH(IoC, Mac, Reg, pVal) {				\
+	SK_U8	*pByte;										\
+	pByte = (SK_U8 *)&((SK_U8 *)(pVal))[0];				\
+	SK_OUT16((IoC), GMA((Mac), (Reg)), (SK_U16)			\
+		(((SK_U16)(pByte[0]) & 0x00ff)|					\
+		(((SK_U16)(pByte[1]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+4)), (SK_U16)		\
+		(((SK_U16)(pByte[2]) & 0x00ff)|					\
+		(((SK_U16)(pByte[3]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+8)), (SK_U16)		\
+		(((SK_U16)(pByte[4]) & 0x00ff)|					\
+		(((SK_U16)(pByte[5]) << 8) & 0xff00)));			\
+	SK_OUT16((IoC), GMA((Mac), (Reg+12)), (SK_U16)		\
+		(((SK_U16)(pByte[6]) & 0x00ff)|					\
+		(((SK_U16)(pByte[7]) << 8) & 0xff00)));			\
+}
+
+/*
+ * Different MAC Types
+ */
+#define SK_MAC_XMAC		0	/* Xaqti XMAC II */
+#define SK_MAC_GMAC		1	/* Marvell GMAC */
+
+/*
+ * Different PHY Types
+ */
+#define SK_PHY_XMAC			0	/* integrated in XMAC II */
+#define SK_PHY_BCOM			1	/* Broadcom BCM5400 */
+#define SK_PHY_LONE			2	/* Level One LXT1000 */
+#define SK_PHY_NAT			3	/* National DP83891 */
+#define SK_PHY_MARV_COPPER	4	/* Marvell 88E1011S */
+#define SK_PHY_MARV_FIBER	5	/* Marvell 88E1011S working on fiber */
+
+/*
+ * PHY addresses (bits 12..8 of PHY address reg)
+ */
+#define PHY_ADDR_XMAC	(0<<8)
+#define PHY_ADDR_BCOM	(1<<8)
+#define PHY_ADDR_LONE	(3<<8)
+#define PHY_ADDR_NAT	(0<<8)
+
+/* GPHY address (bits 15..11 of SMI control reg) */
+#define PHY_ADDR_MARV	0
+
+/*
+ * macros to access the PHY
+ *
+ * PHY_READ()		read a 16 bit value from the PHY
+ * PHY_WRITE()		write a 16 bit value to the PHY
+ *
+ * para:
+ * 	IoC		I/O context needed for SK I/O macros
+ * 	pPort	Pointer to port struct for PhyAddr
+ * 	Mac		XMAC to access		values: MAC_1 or MAC_2
+ * 	PhyReg	PHY Register to read or write
+ * 	(p)Val	Value or pointer to the value which should be read or
+ *			written.
+ *
+ * usage:	PHY_READ(IoC, pPort, MAC_1, PHY_CTRL, Value);
+ * Warning: a PHY_READ on an uninitialized PHY (PHY still in reset) never
+ *          comes back. This is checked in DEBUG mode.
+ */
+#ifndef DEBUG
+#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) {						\
+	SK_U16 Mmu;  														\
+																		\
+	XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr);	\
+	XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));							\
+	if ((pPort)->PhyType != SK_PHY_XMAC) {								\
+		do {  															\
+			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);					\
+		} while ((Mmu & XM_MMU_PHY_RDY) == 0);							\
+		XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));						\
+	}  																	\
+}
+#else
+#define PHY_READ(IoC, pPort, Mac, PhyReg, pVal) {						\
+	SK_U16 Mmu;  														\
+	int __i = 0;														\
+																		\
+	XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr);	\
+	XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));							\
+	if ((pPort)->PhyType != SK_PHY_XMAC) {								\
+		do {  															\
+			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);					\
+			__i++;														\
+			if (__i > 100000) {											\
+				SK_DBG_PRINTF("*****************************\n");		\
+				SK_DBG_PRINTF("PHY_READ on uninitialized PHY\n");		\
+				SK_DBG_PRINTF("*****************************\n");		\
+				break;													\
+			}															\
+		} while ((Mmu & XM_MMU_PHY_RDY) == 0);							\
+		XM_IN16((IoC), (Mac), XM_PHY_DATA, (pVal));						\
+	}  																	\
+}
+#endif /* DEBUG */
+
+#define PHY_WRITE(IoC, pPort, Mac, PhyReg, Val) {						\
+	SK_U16 Mmu;															\
+																		\
+	if ((pPort)->PhyType != SK_PHY_XMAC) {								\
+		do {  															\
+			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);					\
+		} while ((Mmu & XM_MMU_PHY_BUSY) != 0);							\
+	}  																	\
+	XM_OUT16((IoC), (Mac), XM_PHY_ADDR, (PhyReg) | (pPort)->PhyAddr);	\
+	XM_OUT16((IoC), (Mac), XM_PHY_DATA, (Val));							\
+	if ((pPort)->PhyType != SK_PHY_XMAC) {								\
+		do {  															\
+			XM_IN16((IoC), (Mac), XM_MMU_CMD, &Mmu);					\
+		} while ((Mmu & XM_MMU_PHY_BUSY) != 0);							\
+	}  																	\
+}
+
+/*
+ *	Macro PCI_C()
+ *
+ *	Use this macro to access PCI config register from the I/O space.
+ *
+ * para:
+ *	Addr	PCI configuration register to access.
+ *			Values:	PCI_VENDOR_ID ... PCI_VPD_ADR_REG,
+ *
+ * usage	SK_IN16(pAC, PCI_C(PCI_VENDOR_ID), pVal);
+ */
+#define PCI_C(Addr)	(B7_CFG_SPC + (Addr))	/* PCI Config Space */
+
+/*
+ *	Macro SK_HW_ADDR(Base, Addr)
+ *
+ *	Calculates the effective HW address
+ *
+ * para:
+ *	Base	I/O or memory base address
+ *	Addr	Address offset
+ *
+ * usage:	May be used in SK_INxx and SK_OUTxx macros
+ *		#define SK_IN8(pAC, Addr, pVal) ...\
+ *			*pVal = (SK_U8)inp(SK_HW_ADDR(pAC->Hw.Iop, Addr)))
+ */
+#ifdef SK_MEM_MAPPED_IO
+#define SK_HW_ADDR(Base, Addr)	((Base) + (Addr))
+#else  /* SK_MEM_MAPPED_IO */
+#define SK_HW_ADDR(Base, Addr)	\
+			((Base) + (((Addr) & 0x7f) | (((Addr) >> 7 > 0) ? 0x80 : 0)))
+#endif /* SK_MEM_MAPPED_IO */
+
+#define SZ_LONG	(sizeof(SK_U32))
+
+/*
+ *	Macro SK_HWAC_LINK_LED()
+ *
+ *	Use this macro to set the link LED mode.
+ * para:
+ *	pAC		Pointer to adapter context struct
+ *	IoC		I/O context needed for SK I/O macros
+ *  Port	Port number
+ *	Mode	Mode to set for this LED
+ */
+#define SK_HWAC_LINK_LED(pAC, IoC, Port, Mode) \
+	SK_OUT8(IoC, MR_ADDR(Port, LNK_LED_REG), Mode);
+
+
+/* typedefs *******************************************************************/
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_SKGEHW_H */
diff --git a/drivers/net/sk98lin/h/skgehwt.h b/drivers/net/sk98lin/h/skgehwt.h
new file mode 100644
index 0000000..e6b0016
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgehwt.h
@@ -0,0 +1,48 @@
+/******************************************************************************
+ *
+ * Name:	skhwt.h
+ * Project:	Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version:	$Revision: 1.7 $
+ * Date:	$Date: 2003/09/16 12:55:08 $
+ * Purpose:	Defines for the hardware timer functions
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/*
+ * SKGEHWT.H	contains all defines and types for the timer functions
+ */
+
+#ifndef	_SKGEHWT_H_
+#define _SKGEHWT_H_
+
+/*
+ * SK Hardware Timer
+ * - needed wherever the HWT module is used
+ * - use in Adapters context name pAC->Hwt
+ */
+typedef	struct s_Hwt {
+	SK_U32		TStart;	/* HWT start */
+	SK_U32		TStop;	/* HWT stop */
+	int		TActive;	/* HWT: flag : active/inactive */
+} SK_HWT;
+
+extern void SkHwtInit(SK_AC *pAC, SK_IOC Ioc);
+extern void SkHwtStart(SK_AC *pAC, SK_IOC Ioc, SK_U32 Time);
+extern void SkHwtStop(SK_AC *pAC, SK_IOC Ioc);
+extern SK_U32 SkHwtRead(SK_AC *pAC, SK_IOC Ioc);
+extern void SkHwtIsr(SK_AC *pAC, SK_IOC Ioc);
+#endif	/* _SKGEHWT_H_ */
diff --git a/drivers/net/sk98lin/h/skgei2c.h b/drivers/net/sk98lin/h/skgei2c.h
new file mode 100644
index 0000000..d9b6f6d
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgei2c.h
@@ -0,0 +1,210 @@
+/******************************************************************************
+ *
+ * Name:	skgei2c.h
+ * Project:	Gigabit Ethernet Adapters, TWSI-Module
+ * Version:	$Revision: 1.25 $
+ * Date:	$Date: 2003/10/20 09:06:05 $
+ * Purpose:	Special defines for TWSI
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/*
+ * SKGEI2C.H	contains all SK-98xx specific defines for the TWSI handling
+ */
+
+#ifndef _INC_SKGEI2C_H_
+#define _INC_SKGEI2C_H_
+
+/*
+ * Macros to access the B2_I2C_CTRL
+ */
+#define SK_I2C_CTL(IoC, flag, dev, dev_size, reg, burst) \
+	SK_OUT32(IoC, B2_I2C_CTRL,\
+		(flag ? 0x80000000UL : 0x0L) | \
+		(((SK_U32)reg << 16) & I2C_ADDR) | \
+		(((SK_U32)dev << 9) & I2C_DEV_SEL) | \
+		(dev_size & I2C_DEV_SIZE) | \
+		((burst << 4) & I2C_BURST_LEN))
+
+#define SK_I2C_STOP(IoC) {				\
+	SK_U32	I2cCtrl;				\
+	SK_IN32(IoC, B2_I2C_CTRL, &I2cCtrl);		\
+	SK_OUT32(IoC, B2_I2C_CTRL, I2cCtrl | I2C_STOP);	\
+}
+
+#define SK_I2C_GET_CTL(IoC, pI2cCtrl)	SK_IN32(IoC, B2_I2C_CTRL, pI2cCtrl)
+
+/*
+ * Macros to access the TWSI SW Registers
+ */
+#define SK_I2C_SET_BIT(IoC, SetBits) {			\
+	SK_U8	OrgBits;				\
+	SK_IN8(IoC, B2_I2C_SW, &OrgBits);		\
+	SK_OUT8(IoC, B2_I2C_SW, OrgBits | (SK_U8)(SetBits));	\
+}
+
+#define SK_I2C_CLR_BIT(IoC, ClrBits) {			\
+	SK_U8	OrgBits;				\
+	SK_IN8(IoC, B2_I2C_SW, &OrgBits);		\
+	SK_OUT8(IoC, B2_I2C_SW, OrgBits & ~((SK_U8)(ClrBits)));	\
+}
+
+#define SK_I2C_GET_SW(IoC, pI2cSw)	SK_IN8(IoC, B2_I2C_SW, pI2cSw)
+
+/*
+ * define the possible sensor states
+ */
+#define	SK_SEN_IDLE		0	/* Idle: sensor not read */
+#define	SK_SEN_VALUE	1	/* Value Read cycle */
+#define	SK_SEN_VALEXT	2	/* Extended Value Read cycle */
+
+/*
+ * Conversion factor to convert read Voltage sensor to milli Volt
+ * Conversion factor to convert read Temperature sensor to 10th degree Celsius
+ */
+#define	SK_LM80_VT_LSB		22	/* 22mV LSB resolution */
+#define	SK_LM80_TEMP_LSB	10	/* 1 degree LSB resolution */
+#define	SK_LM80_TEMPEXT_LSB	 5	/* 0.5 degree LSB resolution for ext. val. */
+
+/*
+ * formula: counter = (22500*60)/(rpm * divisor * pulses/2)
+ * assuming: 6500rpm, 4 pulses, divisor 1
+ */
+#define SK_LM80_FAN_FAKTOR	((22500L*60)/(1*2))
+
+/*
+ * Define sensor management data
+ * Maximum is reached on Genesis copper dual port and Yukon-64
+ * Board specific maximum is in pAC->I2c.MaxSens
+ */
+#define	SK_MAX_SENSORS	8	/* maximal no. of installed sensors */
+#define	SK_MIN_SENSORS	5	/* minimal no. of installed sensors */
+
+/*
+ * To watch the state machine (SM) use the timer in two ways
+ * instead of one as hitherto
+ */
+#define	SK_TIMER_WATCH_SM		0	/* Watch the SM to finish in a spec. time */
+#define	SK_TIMER_NEW_GAUGING	1	/* Start a new gauging when timer expires */
+
+/*
+ * Defines for the individual thresholds
+ */
+
+/* Temperature sensor */
+#define	SK_SEN_TEMP_HIGH_ERR	800	/* Temperature High Err  Threshold */
+#define	SK_SEN_TEMP_HIGH_WARN	700	/* Temperature High Warn Threshold */
+#define	SK_SEN_TEMP_LOW_WARN	100	/* Temperature Low  Warn Threshold */
+#define	SK_SEN_TEMP_LOW_ERR		  0	/* Temperature Low  Err  Threshold */
+
+/* VCC which should be 5 V */
+#define	SK_SEN_PCI_5V_HIGH_ERR		5588	/* Voltage PCI High Err  Threshold */
+#define	SK_SEN_PCI_5V_HIGH_WARN		5346	/* Voltage PCI High Warn Threshold */
+#define	SK_SEN_PCI_5V_LOW_WARN		4664	/* Voltage PCI Low  Warn Threshold */
+#define	SK_SEN_PCI_5V_LOW_ERR		4422	/* Voltage PCI Low  Err  Threshold */
+
+/*
+ * VIO may be 5 V or 3.3 V. Initialization takes two parts:
+ * 1. Initialize lowest lower limit and highest higher limit.
+ * 2. After the first value is read correct the upper or the lower limit to
+ *    the appropriate C constant.
+ *
+ * Warning limits are +-5% of the exepected voltage.
+ * Error limits are +-10% of the expected voltage.
+ */
+
+/* Bug fix AF: 16.Aug.2001: Correct the init base of LM80 sensor */
+
+#define	SK_SEN_PCI_IO_5V_HIGH_ERR	5566	/* + 10% V PCI-IO High Err Threshold */
+#define	SK_SEN_PCI_IO_5V_HIGH_WARN	5324	/* +  5% V PCI-IO High Warn Threshold */
+					/*		5000	mVolt */
+#define	SK_SEN_PCI_IO_5V_LOW_WARN	4686	/* -  5% V PCI-IO Low Warn Threshold */
+#define	SK_SEN_PCI_IO_5V_LOW_ERR	4444	/* - 10% V PCI-IO Low Err Threshold */
+
+#define	SK_SEN_PCI_IO_RANGE_LIMITER	4000	/* 4000 mV range delimiter */
+
+/* correction values for the second pass */
+#define	SK_SEN_PCI_IO_3V3_HIGH_ERR	3850	/* + 15% V PCI-IO High Err Threshold */
+#define	SK_SEN_PCI_IO_3V3_HIGH_WARN	3674	/* + 10% V PCI-IO High Warn Threshold */
+					/*		3300	mVolt */
+#define	SK_SEN_PCI_IO_3V3_LOW_WARN	2926	/* - 10% V PCI-IO Low Warn Threshold */
+#define	SK_SEN_PCI_IO_3V3_LOW_ERR	2772	/* - 15% V PCI-IO Low Err  Threshold */
+
+/*
+ * VDD voltage
+ */
+#define	SK_SEN_VDD_HIGH_ERR		3630	/* Voltage ASIC High Err  Threshold */
+#define	SK_SEN_VDD_HIGH_WARN	3476	/* Voltage ASIC High Warn Threshold */
+#define	SK_SEN_VDD_LOW_WARN		3146	/* Voltage ASIC Low  Warn Threshold */
+#define	SK_SEN_VDD_LOW_ERR		2970	/* Voltage ASIC Low  Err  Threshold */
+
+/*
+ * PHY PLL 3V3 voltage
+ */
+#define	SK_SEN_PLL_3V3_HIGH_ERR		3630	/* Voltage PMA High Err  Threshold */
+#define	SK_SEN_PLL_3V3_HIGH_WARN	3476	/* Voltage PMA High Warn Threshold */
+#define	SK_SEN_PLL_3V3_LOW_WARN		3146	/* Voltage PMA Low  Warn Threshold */
+#define	SK_SEN_PLL_3V3_LOW_ERR		2970	/* Voltage PMA Low  Err  Threshold */
+
+/*
+ * VAUX (YUKON only)
+ */
+#define	SK_SEN_VAUX_3V3_HIGH_ERR	3630	/* Voltage VAUX High Err Threshold */
+#define	SK_SEN_VAUX_3V3_HIGH_WARN	3476	/* Voltage VAUX High Warn Threshold */
+#define	SK_SEN_VAUX_3V3_LOW_WARN	3146	/* Voltage VAUX Low Warn Threshold */
+#define	SK_SEN_VAUX_3V3_LOW_ERR		2970	/* Voltage VAUX Low Err Threshold */
+#define	SK_SEN_VAUX_0V_WARN_ERR		   0	/* if VAUX not present */
+#define	SK_SEN_VAUX_RANGE_LIMITER	1000	/* 1000 mV range delimiter */
+
+/*
+ * PHY 2V5 voltage
+ */
+#define	SK_SEN_PHY_2V5_HIGH_ERR		2750	/* Voltage PHY High Err Threshold */
+#define	SK_SEN_PHY_2V5_HIGH_WARN	2640	/* Voltage PHY High Warn Threshold */
+#define	SK_SEN_PHY_2V5_LOW_WARN		2376	/* Voltage PHY Low Warn Threshold */
+#define	SK_SEN_PHY_2V5_LOW_ERR		2222	/* Voltage PHY Low Err Threshold */
+
+/*
+ * ASIC Core 1V5 voltage (YUKON only)
+ */
+#define	SK_SEN_CORE_1V5_HIGH_ERR	1650	/* Voltage ASIC Core High Err Threshold */
+#define	SK_SEN_CORE_1V5_HIGH_WARN	1575	/* Voltage ASIC Core High Warn Threshold */
+#define	SK_SEN_CORE_1V5_LOW_WARN	1425	/* Voltage ASIC Core Low Warn Threshold */
+#define	SK_SEN_CORE_1V5_LOW_ERR 	1350	/* Voltage ASIC Core Low Err Threshold */
+
+/*
+ * FAN 1 speed
+ */
+/* assuming: 6500rpm +-15%, 4 pulses,
+ * warning at:	80 %
+ * error at:	70 %
+ * no upper limit
+ */
+#define	SK_SEN_FAN_HIGH_ERR		20000	/* FAN Speed High Err Threshold */
+#define	SK_SEN_FAN_HIGH_WARN	20000	/* FAN Speed High Warn Threshold */
+#define	SK_SEN_FAN_LOW_WARN		 5200	/* FAN Speed Low Warn Threshold */
+#define	SK_SEN_FAN_LOW_ERR		 4550	/* FAN Speed Low Err Threshold */
+
+/*
+ * Some Voltages need dynamic thresholds
+ */
+#define	SK_SEN_DYN_INIT_NONE		 0  /* No dynamic init of thresholds */
+#define	SK_SEN_DYN_INIT_PCI_IO		10  /* Init PCI-IO with new thresholds */
+#define	SK_SEN_DYN_INIT_VAUX		11  /* Init VAUX with new thresholds */
+
+extern	int SkLm80ReadSensor(SK_AC *pAC, SK_IOC IoC, SK_SENSOR *pSen);
+#endif	/* n_INC_SKGEI2C_H */
diff --git a/drivers/net/sk98lin/h/skgeinit.h b/drivers/net/sk98lin/h/skgeinit.h
new file mode 100644
index 0000000..143e635
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgeinit.h
@@ -0,0 +1,797 @@
+/******************************************************************************
+ *
+ * Name:	skgeinit.h
+ * Project:	Gigabit Ethernet Adapters, Common Modules
+ * Version:	$Revision: 1.83 $
+ * Date:	$Date: 2003/09/16 14:07:37 $
+ * Purpose:	Structures and prototypes for the GE Init Module
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKGEINIT_H_
+#define __INC_SKGEINIT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif	/* __cplusplus */
+
+/* defines ********************************************************************/
+
+#define SK_TEST_VAL		0x11335577UL
+
+/* modifying Link LED behaviour (used with SkGeLinkLED()) */
+#define SK_LNK_OFF		LED_OFF
+#define SK_LNK_ON		(LED_ON | LED_BLK_OFF | LED_SYNC_OFF)
+#define SK_LNK_BLINK	(LED_ON | LED_BLK_ON  | LED_SYNC_ON)
+#define SK_LNK_PERM		(LED_ON | LED_BLK_OFF | LED_SYNC_ON)
+#define SK_LNK_TST		(LED_ON | LED_BLK_ON  | LED_SYNC_OFF)
+
+/* parameter 'Mode' when calling SK_HWAC_LINK_LED() */
+#define SK_LED_OFF		LED_OFF
+#define SK_LED_ACTIVE	(LED_ON | LED_BLK_OFF | LED_SYNC_OFF)
+#define SK_LED_STANDBY	(LED_ON | LED_BLK_ON  | LED_SYNC_OFF)
+
+/* addressing LED Registers in SkGeXmitLED() */
+#define XMIT_LED_INI	0
+#define XMIT_LED_CNT	(RX_LED_VAL - RX_LED_INI)
+#define XMIT_LED_CTRL	(RX_LED_CTRL- RX_LED_INI)
+#define XMIT_LED_TST	(RX_LED_TST - RX_LED_INI)
+
+/* parameter 'Mode' when calling SkGeXmitLED() */
+#define SK_LED_DIS	0
+#define SK_LED_ENA	1
+#define SK_LED_TST	2
+
+/* Counter and Timer constants, for a host clock of 62.5 MHz */
+#define SK_XMIT_DUR		0x002faf08UL	/*  50 ms */
+#define SK_BLK_DUR		0x01dcd650UL	/* 500 ms */
+
+#define SK_DPOLL_DEF	0x00ee6b28UL	/* 250 ms at 62.5 MHz */
+
+#define SK_DPOLL_MAX	0x00ffffffUL	/* 268 ms at 62.5 MHz */
+										/* 215 ms at 78.12 MHz */
+
+#define SK_FACT_62		100			/* is given in percent */
+#define SK_FACT_53		 85         /* on GENESIS:	53.12 MHz */
+#define SK_FACT_78		125			/* on YUKON:	78.12 MHz */
+
+/* Timeout values */
+#define SK_MAC_TO_53	72			/* MAC arbiter timeout */
+#define SK_PKT_TO_53	0x2000		/* Packet arbiter timeout */
+#define SK_PKT_TO_MAX	0xffff		/* Maximum value */
+#define SK_RI_TO_53		36			/* RAM interface timeout */
+
+#define SK_PHY_ACC_TO	600000		/* PHY access timeout */
+
+/* RAM Buffer High Pause Threshold values */
+#define SK_RB_ULPP		( 8 * 1024)	/* Upper Level in kB/8 */
+#define SK_RB_LLPP_S	(10 * 1024)	/* Lower Level for small Queues */
+#define SK_RB_LLPP_B	(16 * 1024)	/* Lower Level for big Queues */
+
+#ifndef SK_BMU_RX_WM
+#define SK_BMU_RX_WM	0x600		/* BMU Rx Watermark */
+#endif
+#ifndef SK_BMU_TX_WM
+#define SK_BMU_TX_WM	0x600		/* BMU Tx Watermark */
+#endif
+
+/* XMAC II Rx High Watermark */
+#define SK_XM_RX_HI_WM	0x05aa		/* 1450 */
+
+/* XMAC II Tx Threshold */
+#define SK_XM_THR_REDL	0x01fb		/* .. for redundant link usage */
+#define SK_XM_THR_SL	0x01fb		/* .. for single link adapters */
+#define SK_XM_THR_MULL	0x01fb		/* .. for multiple link usage */
+#define SK_XM_THR_JUMBO	0x03fc		/* .. for jumbo frame usage */
+
+/* values for GIPortUsage */
+#define SK_RED_LINK		1		/* redundant link usage */
+#define SK_MUL_LINK		2		/* multiple link usage */
+#define SK_JUMBO_LINK	3		/* driver uses jumbo frames */
+
+/* Minimum RAM Buffer Rx Queue Size */
+#define SK_MIN_RXQ_SIZE	16		/* 16 kB */
+
+/* Minimum RAM Buffer Tx Queue Size */
+#define SK_MIN_TXQ_SIZE	16		/* 16 kB */
+
+/* Queue Size units */
+#define QZ_UNITS		0x7
+#define QZ_STEP			8
+
+/* Percentage of queue size from whole memory */
+/* 80 % for receive */
+#define RAM_QUOTA_RX	80L
+/* 0% for sync transfer */
+#define	RAM_QUOTA_SYNC	0L
+/* the rest (20%) is taken for async transfer */
+
+/* Get the rounded queue size in Bytes in 8k steps */
+#define ROUND_QUEUE_SIZE(SizeInBytes)					\
+	((((unsigned long) (SizeInBytes) + (QZ_STEP*1024L)-1) / 1024) &	\
+	~(QZ_STEP-1))
+
+/* Get the rounded queue size in KBytes in 8k steps */
+#define ROUND_QUEUE_SIZE_KB(Kilobytes) \
+	ROUND_QUEUE_SIZE((Kilobytes) * 1024L)
+
+/* Types of RAM Buffer Queues */
+#define SK_RX_SRAM_Q	1	/* small receive queue */
+#define SK_RX_BRAM_Q	2	/* big receive queue */
+#define SK_TX_RAM_Q		3	/* small or big transmit queue */
+
+/* parameter 'Dir' when calling SkGeStopPort() */
+#define SK_STOP_TX	1	/* Stops the transmit path, resets the XMAC */
+#define SK_STOP_RX	2	/* Stops the receive path */
+#define SK_STOP_ALL	3	/* Stops Rx and Tx path, resets the XMAC */
+
+/* parameter 'RstMode' when calling SkGeStopPort() */
+#define SK_SOFT_RST	1	/* perform a software reset */
+#define SK_HARD_RST	2	/* perform a hardware reset */
+
+/* Init Levels */
+#define SK_INIT_DATA	0	/* Init level 0: init data structures */
+#define SK_INIT_IO		1	/* Init level 1: init with IOs */
+#define SK_INIT_RUN		2	/* Init level 2: init for run time */
+
+/* Link Mode Parameter */
+#define SK_LMODE_HALF		1	/* Half Duplex Mode */
+#define SK_LMODE_FULL		2	/* Full Duplex Mode */
+#define SK_LMODE_AUTOHALF	3	/* AutoHalf Duplex Mode */
+#define SK_LMODE_AUTOFULL	4	/* AutoFull Duplex Mode */
+#define SK_LMODE_AUTOBOTH	5	/* AutoBoth Duplex Mode */
+#define SK_LMODE_AUTOSENSE	6	/* configured mode auto sensing */
+#define SK_LMODE_INDETERMINATED	7	/* indeterminated */
+
+/* Auto-negotiation timeout in 100ms granularity */
+#define SK_AND_MAX_TO		6	/* Wait 600 msec before link comes up */
+
+/* Auto-negotiation error codes */
+#define SK_AND_OK			0	/* no error */
+#define SK_AND_OTHER		1	/* other error than below */
+#define SK_AND_DUP_CAP		2	/* Duplex capabilities error */
+
+
+/* Link Speed Capabilities */
+#define SK_LSPEED_CAP_AUTO			(1<<0)	/* Automatic resolution */
+#define SK_LSPEED_CAP_10MBPS		(1<<1)	/* 10 Mbps */
+#define SK_LSPEED_CAP_100MBPS		(1<<2)	/* 100 Mbps */
+#define SK_LSPEED_CAP_1000MBPS		(1<<3)	/* 1000 Mbps */
+#define SK_LSPEED_CAP_INDETERMINATED (1<<4) /* indeterminated */
+
+/* Link Speed Parameter */
+#define SK_LSPEED_AUTO				1	/* Automatic resolution */
+#define SK_LSPEED_10MBPS			2	/* 10 Mbps */
+#define SK_LSPEED_100MBPS			3	/* 100 Mbps */
+#define SK_LSPEED_1000MBPS			4	/* 1000 Mbps */
+#define SK_LSPEED_INDETERMINATED	5	/* indeterminated */
+
+/* Link Speed Current State */
+#define SK_LSPEED_STAT_UNKNOWN		1
+#define SK_LSPEED_STAT_10MBPS		2
+#define SK_LSPEED_STAT_100MBPS 		3
+#define SK_LSPEED_STAT_1000MBPS		4
+#define SK_LSPEED_STAT_INDETERMINATED 5
+
+
+/* Link Capability Parameter */
+#define SK_LMODE_CAP_HALF		(1<<0)	/* Half Duplex Mode */
+#define SK_LMODE_CAP_FULL		(1<<1)	/* Full Duplex Mode */
+#define SK_LMODE_CAP_AUTOHALF	(1<<2)	/* AutoHalf Duplex Mode */
+#define SK_LMODE_CAP_AUTOFULL	(1<<3)	/* AutoFull Duplex Mode */
+#define SK_LMODE_CAP_INDETERMINATED (1<<4) /* indeterminated */
+
+/* Link Mode Current State */
+#define SK_LMODE_STAT_UNKNOWN	1	/* Unknown Duplex Mode */
+#define SK_LMODE_STAT_HALF		2	/* Half Duplex Mode */
+#define SK_LMODE_STAT_FULL		3	/* Full Duplex Mode */
+#define SK_LMODE_STAT_AUTOHALF	4	/* Half Duplex Mode obtained by Auto-Neg */
+#define SK_LMODE_STAT_AUTOFULL	5	/* Full Duplex Mode obtained by Auto-Neg */
+#define SK_LMODE_STAT_INDETERMINATED 6	/* indeterminated */
+
+/* Flow Control Mode Parameter (and capabilities) */
+#define SK_FLOW_MODE_NONE		1	/* No Flow-Control */
+#define SK_FLOW_MODE_LOC_SEND	2	/* Local station sends PAUSE */
+#define SK_FLOW_MODE_SYMMETRIC	3	/* Both stations may send PAUSE */
+#define SK_FLOW_MODE_SYM_OR_REM	4	/* Both stations may send PAUSE or
+					 * just the remote station may send PAUSE
+					 */
+#define SK_FLOW_MODE_INDETERMINATED 5	/* indeterminated */
+
+/* Flow Control Status Parameter */
+#define SK_FLOW_STAT_NONE		1	/* No Flow Control */
+#define SK_FLOW_STAT_REM_SEND	2	/* Remote Station sends PAUSE */
+#define SK_FLOW_STAT_LOC_SEND	3	/* Local station sends PAUSE */
+#define SK_FLOW_STAT_SYMMETRIC	4	/* Both station may send PAUSE */
+#define SK_FLOW_STAT_INDETERMINATED 5	/* indeterminated */
+
+/* Master/Slave Mode Capabilities */
+#define SK_MS_CAP_AUTO		(1<<0)	/* Automatic resolution */
+#define SK_MS_CAP_MASTER	(1<<1)	/* This station is master */
+#define SK_MS_CAP_SLAVE		(1<<2)	/* This station is slave */
+#define SK_MS_CAP_INDETERMINATED (1<<3)	/* indeterminated */
+
+/* Set Master/Slave Mode Parameter (and capabilities) */
+#define SK_MS_MODE_AUTO		1	/* Automatic resolution */
+#define SK_MS_MODE_MASTER	2	/* This station is master */
+#define SK_MS_MODE_SLAVE	3	/* This station is slave */
+#define SK_MS_MODE_INDETERMINATED 4	/* indeterminated */
+
+/* Master/Slave Status Parameter */
+#define SK_MS_STAT_UNSET	1	/* The M/S status is not set */
+#define SK_MS_STAT_MASTER	2	/* This station is master */
+#define SK_MS_STAT_SLAVE	3	/* This station is slave */
+#define SK_MS_STAT_FAULT	4	/* M/S resolution failed */
+#define SK_MS_STAT_INDETERMINATED 5	/* indeterminated */
+
+/* parameter 'Mode' when calling SkXmSetRxCmd() */
+#define SK_STRIP_FCS_ON		(1<<0)	/* Enable  FCS stripping of Rx frames */
+#define SK_STRIP_FCS_OFF	(1<<1)	/* Disable FCS stripping of Rx frames */
+#define SK_STRIP_PAD_ON		(1<<2)	/* Enable  pad byte stripping of Rx fr */
+#define SK_STRIP_PAD_OFF	(1<<3)	/* Disable pad byte stripping of Rx fr */
+#define SK_LENERR_OK_ON		(1<<4)	/* Don't chk fr for in range len error */
+#define SK_LENERR_OK_OFF	(1<<5)	/* Check frames for in range len error */
+#define SK_BIG_PK_OK_ON		(1<<6)	/* Don't set Rx Error bit for big frames */
+#define SK_BIG_PK_OK_OFF	(1<<7)	/* Set Rx Error bit for big frames */
+#define SK_SELF_RX_ON		(1<<8)	/* Enable  Rx of own packets */
+#define SK_SELF_RX_OFF		(1<<9)	/* Disable Rx of own packets */
+
+/* parameter 'Para' when calling SkMacSetRxTxEn() */
+#define SK_MAC_LOOPB_ON		(1<<0)	/* Enable  MAC Loopback Mode */
+#define SK_MAC_LOOPB_OFF	(1<<1)	/* Disable MAC Loopback Mode */
+#define SK_PHY_LOOPB_ON		(1<<2)	/* Enable  PHY Loopback Mode */
+#define SK_PHY_LOOPB_OFF	(1<<3)	/* Disable PHY Loopback Mode */
+#define SK_PHY_FULLD_ON		(1<<4)	/* Enable  GMII Full Duplex */
+#define SK_PHY_FULLD_OFF	(1<<5)	/* Disable GMII Full Duplex */
+
+/* States of PState */
+#define SK_PRT_RESET	0	/* the port is reset */
+#define SK_PRT_STOP		1	/* the port is stopped (similar to SW reset) */
+#define SK_PRT_INIT		2	/* the port is initialized */
+#define SK_PRT_RUN		3	/* the port has an active link */
+
+/* PHY power down modes */
+#define PHY_PM_OPERATIONAL_MODE		0	/* PHY operational mode */
+#define PHY_PM_DEEP_SLEEP			1	/* coma mode --> minimal power */
+#define PHY_PM_IEEE_POWER_DOWN		2	/* IEEE 22.2.4.1.5 compl. power down */
+#define PHY_PM_ENERGY_DETECT		3	/* energy detect */
+#define PHY_PM_ENERGY_DETECT_PLUS	4	/* energy detect plus */
+
+/* Default receive frame limit for Workaround of XMAC Errata */
+#define SK_DEF_RX_WA_LIM	SK_CONSTU64(100)
+
+/* values for GILedBlinkCtrl (LED Blink Control) */
+#define SK_ACT_LED_BLINK	(1<<0)	/* Active LED blinking */
+#define SK_DUP_LED_NORMAL	(1<<1)	/* Duplex LED normal */
+#define SK_LED_LINK100_ON	(1<<2)	/* Link 100M LED on */
+
+/* Link Partner Status */
+#define SK_LIPA_UNKNOWN	0	/* Link partner is in unknown state */
+#define SK_LIPA_MANUAL	1	/* Link partner is in detected manual state */
+#define SK_LIPA_AUTO	2	/* Link partner is in auto-negotiation state */
+
+/* Maximum Restarts before restart is ignored (3Com WA) */
+#define SK_MAX_LRESTART	3	/* Max. 3 times the link is restarted */
+
+/* Max. Auto-neg. timeouts before link detection in sense mode is reset */
+#define SK_MAX_ANEG_TO	10	/* Max. 10 times the sense mode is reset */
+
+/* structures *****************************************************************/
+
+/*
+ * MAC specific functions
+ */
+typedef struct s_GeMacFunc {
+	int  (*pFnMacUpdateStats)(SK_AC *pAC, SK_IOC IoC, unsigned int Port);
+	int  (*pFnMacStatistic)(SK_AC *pAC, SK_IOC IoC, unsigned int Port,
+							SK_U16 StatAddr, SK_U32 SK_FAR *pVal);
+	int  (*pFnMacResetCounter)(SK_AC *pAC, SK_IOC IoC, unsigned int Port);
+	int  (*pFnMacOverflow)(SK_AC *pAC, SK_IOC IoC, unsigned int Port,
+						   SK_U16 IStatus, SK_U64 SK_FAR *pVal);
+} SK_GEMACFUNC;
+
+/*
+ * Port Structure
+ */
+typedef	struct s_GePort {
+#ifndef SK_DIAG
+	SK_TIMER	PWaTimer;	/* Workaround Timer */
+	SK_TIMER	HalfDupChkTimer;
+#endif /* SK_DIAG */
+	SK_U32	PPrevShorts;	/* Previous Short Counter checking */
+	SK_U32	PPrevFcs;		/* Previous FCS Error Counter checking */
+	SK_U64	PPrevRx;		/* Previous RxOk Counter checking */
+	SK_U64	PRxLim;			/* Previous RxOk Counter checking */
+	SK_U64	LastOctets;		/* For half duplex hang check */
+	int		PLinkResCt;		/* Link Restart Counter */
+	int		PAutoNegTimeOut;/* Auto-negotiation timeout current value */
+	int		PAutoNegTOCt;	/* Auto-negotiation Timeout Counter */
+	int		PRxQSize;		/* Port Rx Queue Size in kB */
+	int		PXSQSize;		/* Port Synchronous  Transmit Queue Size in kB */
+	int		PXAQSize;		/* Port Asynchronous Transmit Queue Size in kB */
+	SK_U32	PRxQRamStart;	/* Receive Queue RAM Buffer Start Address */
+	SK_U32	PRxQRamEnd;		/* Receive Queue RAM Buffer End Address */
+	SK_U32	PXsQRamStart;	/* Sync Tx Queue RAM Buffer Start Address */
+	SK_U32	PXsQRamEnd;		/* Sync Tx Queue RAM Buffer End Address */
+	SK_U32	PXaQRamStart;	/* Async Tx Queue RAM Buffer Start Address */
+	SK_U32	PXaQRamEnd;		/* Async Tx Queue RAM Buffer End Address */
+	SK_U32	PRxOverCnt;		/* Receive Overflow Counter */
+	int		PRxQOff;		/* Rx Queue Address Offset */
+	int		PXsQOff;		/* Synchronous Tx Queue Address Offset */
+	int		PXaQOff;		/* Asynchronous Tx Queue Address Offset */
+	int		PhyType;		/* PHY used on this port */
+	int		PState;			/* Port status (reset, stop, init, run) */
+	SK_U16	PhyId1;			/* PHY Id1 on this port */
+	SK_U16	PhyAddr;		/* MDIO/MDC PHY address */
+	SK_U16	PIsave;			/* Saved Interrupt status word */
+	SK_U16	PSsave;			/* Saved PHY status word */
+	SK_U16	PGmANegAdv;		/* Saved GPhy AutoNegAdvertisment register */
+	SK_BOOL	PHWLinkUp;		/* The hardware Link is up (wiring) */
+	SK_BOOL	PLinkBroken;	/* Is Link broken ? */
+	SK_BOOL	PCheckPar;		/* Do we check for parity errors ? */
+	SK_BOOL	HalfDupTimerActive;
+	SK_U8	PLinkCap;		/* Link Capabilities */
+	SK_U8	PLinkModeConf;	/* Link Mode configured */
+	SK_U8	PLinkMode;		/* Link Mode currently used */
+	SK_U8	PLinkModeStatus;/* Link Mode Status */
+	SK_U8	PLinkSpeedCap;	/* Link Speed Capabilities(10/100/1000 Mbps) */
+	SK_U8	PLinkSpeed;		/* configured Link Speed (10/100/1000 Mbps) */
+	SK_U8	PLinkSpeedUsed;	/* current Link Speed (10/100/1000 Mbps) */
+	SK_U8	PFlowCtrlCap;	/* Flow Control Capabilities */
+	SK_U8	PFlowCtrlMode;	/* Flow Control Mode */
+	SK_U8	PFlowCtrlStatus;/* Flow Control Status */
+	SK_U8	PMSCap;			/* Master/Slave Capabilities */
+	SK_U8	PMSMode;		/* Master/Slave Mode */
+	SK_U8	PMSStatus;		/* Master/Slave Status */
+	SK_BOOL	PAutoNegFail;	/* Auto-negotiation fail flag */
+	SK_U8	PLipaAutoNeg;	/* Auto-negotiation possible with Link Partner */
+	SK_U8	PCableLen;		/* Cable Length */
+	SK_U8	PMdiPairLen[4];	/* MDI[0..3] Pair Length */
+	SK_U8	PMdiPairSts[4];	/* MDI[0..3] Pair Diagnostic Status */
+	SK_U8	PPhyPowerState;	/* PHY current power state */
+	int		PMacColThres;	/* MAC Collision Threshold */
+	int		PMacJamLen;		/* MAC Jam length */
+	int		PMacJamIpgVal;	/* MAC Jam IPG */
+	int		PMacJamIpgData;	/* MAC IPG Jam to Data */
+	int		PMacIpgData;	/* MAC Data IPG */
+	SK_BOOL PMacLimit4;		/* reset collision counter and backoff algorithm */
+} SK_GEPORT;
+
+/*
+ * Gigabit Ethernet Initialization Struct
+ * (has to be included in the adapter context)
+ */
+typedef	struct s_GeInit {
+	int			GIChipId;		/* Chip Identification Number */
+	int			GIChipRev;		/* Chip Revision Number */
+	SK_U8		GIPciHwRev;		/* PCI HW Revision Number */
+	SK_BOOL		GIGenesis;		/* Genesis adapter ? */
+	SK_BOOL		GIYukon;		/* YUKON-A1/Bx chip */
+	SK_BOOL		GIYukonLite;	/* YUKON-Lite chip */
+	SK_BOOL		GICopperType;	/* Copper Type adapter ? */
+	SK_BOOL		GIPciSlot64;	/* 64-bit PCI Slot */
+	SK_BOOL		GIPciClock66;	/* 66 MHz PCI Clock */
+	SK_BOOL		GIVauxAvail;	/* VAUX available (YUKON) */
+	SK_BOOL		GIYukon32Bit;	/* 32-Bit YUKON adapter */
+	SK_U16		GILedBlinkCtrl;	/* LED Blink Control */
+	int			GIMacsFound;	/* Number of MACs found on this adapter */
+	int			GIMacType;		/* MAC Type used on this adapter */
+	int			GIHstClkFact;	/* Host Clock Factor (62.5 / HstClk * 100) */
+	int			GIPortUsage;	/* Driver Port Usage */
+	int			GILevel;		/* Initialization Level completed */
+	int			GIRamSize;		/* The RAM size of the adapter in kB */
+	int			GIWolOffs;		/* WOL Register Offset (HW-Bug in Rev. A) */
+	SK_U32		GIRamOffs;		/* RAM Address Offset for addr calculation */
+	SK_U32		GIPollTimerVal;	/* Descr. Poll Timer Init Val (HstClk ticks) */
+	SK_U32		GIValIrqMask;	/* Value for Interrupt Mask */
+	SK_U32		GITimeStampCnt;	/* Time Stamp High Counter (YUKON only) */
+	SK_GEPORT	GP[SK_MAX_MACS];/* Port Dependent Information */
+	SK_GEMACFUNC GIFunc;		/* MAC depedent functions */
+} SK_GEINIT;
+
+/*
+ * Error numbers and messages for skxmac2.c and skgeinit.c
+ */
+#define SKERR_HWI_E001		(SK_ERRBASE_HWINIT)
+#define SKERR_HWI_E001MSG	"SkXmClrExactAddr() has got illegal parameters"
+#define SKERR_HWI_E002		(SKERR_HWI_E001+1)
+#define SKERR_HWI_E002MSG	"SkGeInit(): Level 1 call missing"
+#define SKERR_HWI_E003		(SKERR_HWI_E002+1)
+#define SKERR_HWI_E003MSG	"SkGeInit() called with illegal init Level"
+#define SKERR_HWI_E004		(SKERR_HWI_E003+1)
+#define SKERR_HWI_E004MSG	"SkGeInitPort(): Queue Size illegal configured"
+#define SKERR_HWI_E005		(SKERR_HWI_E004+1)
+#define SKERR_HWI_E005MSG	"SkGeInitPort(): cannot init running ports"
+#define SKERR_HWI_E006		(SKERR_HWI_E005+1)
+#define SKERR_HWI_E006MSG	"SkGeMacInit(): PState does not match HW state"
+#define SKERR_HWI_E007		(SKERR_HWI_E006+1)
+#define SKERR_HWI_E007MSG	"SkXmInitDupMd() called with invalid Dup Mode"
+#define SKERR_HWI_E008		(SKERR_HWI_E007+1)
+#define SKERR_HWI_E008MSG	"SkXmSetRxCmd() called with invalid Mode"
+#define SKERR_HWI_E009		(SKERR_HWI_E008+1)
+#define SKERR_HWI_E009MSG	"SkGeCfgSync() called although PXSQSize zero"
+#define SKERR_HWI_E010		(SKERR_HWI_E009+1)
+#define SKERR_HWI_E010MSG	"SkGeCfgSync() called with invalid parameters"
+#define SKERR_HWI_E011		(SKERR_HWI_E010+1)
+#define SKERR_HWI_E011MSG	"SkGeInitPort(): Receive Queue Size too small"
+#define SKERR_HWI_E012		(SKERR_HWI_E011+1)
+#define SKERR_HWI_E012MSG	"SkGeInitPort(): invalid Queue Size specified"
+#define SKERR_HWI_E013		(SKERR_HWI_E012+1)
+#define SKERR_HWI_E013MSG	"SkGeInitPort(): cfg changed for running queue"
+#define SKERR_HWI_E014		(SKERR_HWI_E013+1)
+#define SKERR_HWI_E014MSG	"SkGeInitPort(): unknown GIPortUsage specified"
+#define SKERR_HWI_E015		(SKERR_HWI_E014+1)
+#define SKERR_HWI_E015MSG	"Illegal Link mode parameter"
+#define SKERR_HWI_E016		(SKERR_HWI_E015+1)
+#define SKERR_HWI_E016MSG	"Illegal Flow control mode parameter"
+#define SKERR_HWI_E017		(SKERR_HWI_E016+1)
+#define SKERR_HWI_E017MSG	"Illegal value specified for GIPollTimerVal"
+#define SKERR_HWI_E018		(SKERR_HWI_E017+1)
+#define SKERR_HWI_E018MSG	"FATAL: SkGeStopPort() does not terminate (Tx)"
+#define SKERR_HWI_E019		(SKERR_HWI_E018+1)
+#define SKERR_HWI_E019MSG	"Illegal Speed parameter"
+#define SKERR_HWI_E020		(SKERR_HWI_E019+1)
+#define SKERR_HWI_E020MSG	"Illegal Master/Slave parameter"
+#define SKERR_HWI_E021		(SKERR_HWI_E020+1)
+#define	SKERR_HWI_E021MSG	"MacUpdateStats(): cannot update statistic counter"
+#define	SKERR_HWI_E022		(SKERR_HWI_E021+1)
+#define	SKERR_HWI_E022MSG	"MacStatistic(): illegal statistic base address"
+#define SKERR_HWI_E023		(SKERR_HWI_E022+1)
+#define SKERR_HWI_E023MSG	"SkGeInitPort(): Transmit Queue Size too small"
+#define SKERR_HWI_E024		(SKERR_HWI_E023+1)
+#define SKERR_HWI_E024MSG	"FATAL: SkGeStopPort() does not terminate (Rx)"
+#define SKERR_HWI_E025		(SKERR_HWI_E024+1)
+#define SKERR_HWI_E025MSG	""
+
+/* function prototypes ********************************************************/
+
+#ifndef	SK_KR_PROTO
+
+/*
+ * public functions in skgeinit.c
+ */
+extern void	SkGePollTxD(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL PollTxD);
+
+extern void	SkGeYellowLED(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		State);
+
+extern int	SkGeCfgSync(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_U32	IntTime,
+	SK_U32	LimCount,
+	int		SyncMode);
+
+extern void	SkGeLoadLnkSyncCnt(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_U32	CntVal);
+
+extern void	SkGeStopPort(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Dir,
+	int		RstMode);
+
+extern int	SkGeInit(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Level);
+
+extern void	SkGeDeInit(
+	SK_AC	*pAC,
+	SK_IOC	IoC);
+
+extern int	SkGeInitPort(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkGeXmitLED(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Led,
+	int		Mode);
+
+extern int	SkGeInitAssignRamToQueues(
+	SK_AC	*pAC,
+	int		ActivePort,
+	SK_BOOL	DualNet);
+
+/*
+ * public functions in skxmac2.c
+ */
+extern void SkMacRxTxDisable(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkMacSoftRst(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkMacHardRst(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkXmInitMac(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkGmInitMac(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void SkMacInitPhy(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	DoLoop);
+
+extern void SkMacIrqDisable(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkMacFlushTxFifo(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkMacIrq(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern int	SkMacAutoNegDone(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkMacAutoNegLipaPhy(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_U16	IStatus);
+
+extern int  SkMacRxTxEnable(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port);
+
+extern void	SkMacPromiscMode(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	Enable);
+
+extern void	SkMacHashing(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	Enable);
+
+extern void	SkXmPhyRead(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	SK_FAR *pVal);
+
+extern void	SkXmPhyWrite(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	Val);
+
+extern void	SkGmPhyRead(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	SK_FAR *pVal);
+
+extern void	SkGmPhyWrite(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	Val);
+
+extern void	SkXmClrExactAddr(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		StartNum,
+	int		StopNum);
+
+extern void	SkXmAutoNegLipaXmac(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_U16	IStatus);
+
+extern int SkXmUpdateStats(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port);
+
+extern int SkGmUpdateStats(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port);
+
+extern int SkXmMacStatistic(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port,
+	SK_U16	StatAddr,
+	SK_U32	SK_FAR *pVal);
+
+extern int SkGmMacStatistic(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port,
+	SK_U16	StatAddr,
+	SK_U32	SK_FAR *pVal);
+
+extern int SkXmResetCounter(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port);
+
+extern int SkGmResetCounter(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port);
+
+extern int SkXmOverflowStatus(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port,
+	SK_U16  IStatus,
+	SK_U64	SK_FAR *pStatus);
+
+extern int SkGmOverflowStatus(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	unsigned int Port,
+	SK_U16	MacStatus,
+	SK_U64	SK_FAR *pStatus);
+
+extern int SkGmCableDiagStatus(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	StartTest);
+
+#ifdef SK_DIAG
+extern void	SkGePhyRead(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	*pVal);
+
+extern void	SkGePhyWrite(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Addr,
+	SK_U16	Val);
+
+extern void	SkMacSetRxCmd(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	int		Mode);
+extern void	SkMacCrcGener(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	Enable);
+extern void	SkMacTimeStamp(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	Enable);
+extern void	SkXmSendCont(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Port,
+	SK_BOOL	Enable);
+#endif /* SK_DIAG */
+
+#else	/* SK_KR_PROTO */
+
+/*
+ * public functions in skgeinit.c
+ */
+extern void	SkGePollTxD();
+extern void	SkGeYellowLED();
+extern int	SkGeCfgSync();
+extern void	SkGeLoadLnkSyncCnt();
+extern void	SkGeStopPort();
+extern int	SkGeInit();
+extern void	SkGeDeInit();
+extern int	SkGeInitPort();
+extern void	SkGeXmitLED();
+extern int	SkGeInitAssignRamToQueues();
+
+/*
+ * public functions in skxmac2.c
+ */
+extern void SkMacRxTxDisable();
+extern void	SkMacSoftRst();
+extern void	SkMacHardRst();
+extern void SkMacInitPhy();
+extern int  SkMacRxTxEnable();
+extern void SkMacPromiscMode();
+extern void SkMacHashing();
+extern void SkMacIrqDisable();
+extern void	SkMacFlushTxFifo();
+extern void	SkMacIrq();
+extern int	SkMacAutoNegDone();
+extern void	SkMacAutoNegLipaPhy();
+extern void	SkXmInitMac();
+extern void	SkXmPhyRead();
+extern void	SkXmPhyWrite();
+extern void	SkGmInitMac();
+extern void	SkGmPhyRead();
+extern void	SkGmPhyWrite();
+extern void	SkXmClrExactAddr();
+extern void	SkXmAutoNegLipaXmac();
+extern int	SkXmUpdateStats();
+extern int	SkGmUpdateStats();
+extern int	SkXmMacStatistic();
+extern int	SkGmMacStatistic();
+extern int	SkXmResetCounter();
+extern int	SkGmResetCounter();
+extern int	SkXmOverflowStatus();
+extern int	SkGmOverflowStatus();
+extern int	SkGmCableDiagStatus();
+
+#ifdef SK_DIAG
+extern void	SkGePhyRead();
+extern void	SkGePhyWrite();
+extern void	SkMacSetRxCmd();
+extern void	SkMacCrcGener();
+extern void	SkMacTimeStamp();
+extern void	SkXmSendCont();
+#endif /* SK_DIAG */
+
+#endif	/* SK_KR_PROTO */
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_SKGEINIT_H_ */
diff --git a/drivers/net/sk98lin/h/skgepnm2.h b/drivers/net/sk98lin/h/skgepnm2.h
new file mode 100644
index 0000000..ddd304f
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgepnm2.h
@@ -0,0 +1,334 @@
+/*****************************************************************************
+ *
+ * Name:	skgepnm2.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.36 $
+ * Date:	$Date: 2003/05/23 12:45:13 $
+ * Purpose:	Defines for Private Network Management Interface
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+#ifndef _SKGEPNM2_H_
+#define _SKGEPNM2_H_
+
+/*
+ * General definitions
+ */
+#define SK_PNMI_CHIPSET_XMAC	1	/* XMAC11800FP */
+#define SK_PNMI_CHIPSET_YUKON	2	/* YUKON */
+
+#define	SK_PNMI_BUS_PCI		1	/* PCI bus*/
+
+/*
+ * Actions
+ */
+#define SK_PNMI_ACT_IDLE		1
+#define SK_PNMI_ACT_RESET		2
+#define SK_PNMI_ACT_SELFTEST	3
+#define SK_PNMI_ACT_RESETCNT	4
+
+/*
+ * VPD releated defines
+ */
+
+#define SK_PNMI_VPD_RW		1
+#define SK_PNMI_VPD_RO		2
+
+#define SK_PNMI_VPD_OK			0
+#define SK_PNMI_VPD_NOTFOUND	1
+#define SK_PNMI_VPD_CUT			2
+#define SK_PNMI_VPD_TIMEOUT		3
+#define SK_PNMI_VPD_FULL		4
+#define SK_PNMI_VPD_NOWRITE		5
+#define SK_PNMI_VPD_FATAL		6
+
+#define SK_PNMI_VPD_IGNORE	0
+#define SK_PNMI_VPD_CREATE	1
+#define SK_PNMI_VPD_DELETE	2
+
+
+/*
+ * RLMT related defines
+ */
+#define SK_PNMI_DEF_RLMT_CHG_THRES	240	/* 4 changes per minute */
+
+
+/*
+ * VCT internal status values
+ */
+#define SK_PNMI_VCT_PENDING	32
+#define SK_PNMI_VCT_TEST_DONE	64
+#define SK_PNMI_VCT_LINK	128
+
+/*
+ * Internal table definitions
+ */
+#define SK_PNMI_GET		0
+#define SK_PNMI_PRESET	1
+#define SK_PNMI_SET		2
+
+#define SK_PNMI_RO		0
+#define SK_PNMI_RW		1
+#define SK_PNMI_WO		2
+
+typedef struct s_OidTabEntry {
+	SK_U32			Id;
+	SK_U32			InstanceNo;
+	unsigned int	StructSize;
+	unsigned int	Offset;
+	int				Access;
+	int				(* Func)(SK_AC *pAc, SK_IOC pIo, int action,
+							 SK_U32 Id, char* pBuf, unsigned int* pLen,
+							 SK_U32 Instance, unsigned int TableIndex,
+							 SK_U32 NetNumber);
+	SK_U16			Param;
+} SK_PNMI_TAB_ENTRY;
+
+
+/*
+ * Trap lengths
+ */
+#define SK_PNMI_TRAP_SIMPLE_LEN			17
+#define SK_PNMI_TRAP_SENSOR_LEN_BASE	46
+#define SK_PNMI_TRAP_RLMT_CHANGE_LEN	23
+#define SK_PNMI_TRAP_RLMT_PORT_LEN		23
+
+/*
+ * Number of MAC types supported
+ */
+#define SK_PNMI_MAC_TYPES	(SK_MAC_GMAC + 1)
+
+/*
+ * MAC statistic data list (overall set for MAC types used)
+ */
+enum SK_MACSTATS {
+	SK_PNMI_HTX				= 0,
+	SK_PNMI_HTX_OCTET,
+	SK_PNMI_HTX_OCTETHIGH 	= SK_PNMI_HTX_OCTET,
+	SK_PNMI_HTX_OCTETLOW,
+	SK_PNMI_HTX_BROADCAST,
+	SK_PNMI_HTX_MULTICAST,
+	SK_PNMI_HTX_UNICAST,
+	SK_PNMI_HTX_BURST,
+	SK_PNMI_HTX_PMACC,
+	SK_PNMI_HTX_MACC,
+	SK_PNMI_HTX_COL,
+	SK_PNMI_HTX_SINGLE_COL,
+	SK_PNMI_HTX_MULTI_COL,
+	SK_PNMI_HTX_EXCESS_COL,
+	SK_PNMI_HTX_LATE_COL,
+	SK_PNMI_HTX_DEFFERAL,
+	SK_PNMI_HTX_EXCESS_DEF,
+	SK_PNMI_HTX_UNDERRUN,
+	SK_PNMI_HTX_CARRIER,
+	SK_PNMI_HTX_UTILUNDER,
+	SK_PNMI_HTX_UTILOVER,
+	SK_PNMI_HTX_64,
+	SK_PNMI_HTX_127,
+	SK_PNMI_HTX_255,
+	SK_PNMI_HTX_511,
+	SK_PNMI_HTX_1023,
+	SK_PNMI_HTX_MAX,
+	SK_PNMI_HTX_LONGFRAMES,
+	SK_PNMI_HTX_SYNC,
+	SK_PNMI_HTX_SYNC_OCTET,
+	SK_PNMI_HTX_RESERVED,
+	
+	SK_PNMI_HRX,
+	SK_PNMI_HRX_OCTET,
+	SK_PNMI_HRX_OCTETHIGH	= SK_PNMI_HRX_OCTET,
+	SK_PNMI_HRX_OCTETLOW,
+	SK_PNMI_HRX_BADOCTET,
+	SK_PNMI_HRX_BADOCTETHIGH = SK_PNMI_HRX_BADOCTET,
+	SK_PNMI_HRX_BADOCTETLOW,
+	SK_PNMI_HRX_BROADCAST,
+	SK_PNMI_HRX_MULTICAST,
+	SK_PNMI_HRX_UNICAST,
+	SK_PNMI_HRX_PMACC,
+	SK_PNMI_HRX_MACC,
+	SK_PNMI_HRX_PMACC_ERR,
+	SK_PNMI_HRX_MACC_UNKWN,
+	SK_PNMI_HRX_BURST,
+	SK_PNMI_HRX_MISSED,
+	SK_PNMI_HRX_FRAMING,
+	SK_PNMI_HRX_UNDERSIZE,
+	SK_PNMI_HRX_OVERFLOW,
+	SK_PNMI_HRX_JABBER,
+	SK_PNMI_HRX_CARRIER,
+	SK_PNMI_HRX_IRLENGTH,
+	SK_PNMI_HRX_SYMBOL,
+	SK_PNMI_HRX_SHORTS,
+	SK_PNMI_HRX_RUNT,
+	SK_PNMI_HRX_TOO_LONG,
+	SK_PNMI_HRX_FCS,
+	SK_PNMI_HRX_CEXT,
+	SK_PNMI_HRX_UTILUNDER,
+	SK_PNMI_HRX_UTILOVER,
+	SK_PNMI_HRX_64,
+	SK_PNMI_HRX_127,
+	SK_PNMI_HRX_255,
+	SK_PNMI_HRX_511,
+	SK_PNMI_HRX_1023,
+	SK_PNMI_HRX_MAX,
+	SK_PNMI_HRX_LONGFRAMES,
+	
+	SK_PNMI_HRX_RESERVED,
+	
+	SK_PNMI_MAX_IDX		/* NOTE: Ensure SK_PNMI_CNT_NO is set to this value */
+};
+
+/*
+ * MAC specific data
+ */
+typedef struct s_PnmiStatAddr {
+	SK_U16		Reg;		/* MAC register containing the value */
+	SK_BOOL		GetOffset;	/* TRUE: Offset managed by PNMI (call GetStatVal())*/
+} SK_PNMI_STATADDR;
+
+
+/*
+ * SK_PNMI_STRUCT_DATA copy offset evaluation macros
+ */
+#define SK_PNMI_OFF(e)		((SK_U32)(SK_UPTR)&(((SK_PNMI_STRUCT_DATA *)0)->e))
+#define SK_PNMI_MAI_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_STRUCT_DATA *)0)->e))
+#define SK_PNMI_VPD_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_VPD *)0)->e))
+#define SK_PNMI_SEN_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_SENSOR *)0)->e))
+#define SK_PNMI_CHK_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_CHECKSUM *)0)->e))
+#define SK_PNMI_STA_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_STAT *)0)->e))
+#define SK_PNMI_CNF_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_CONF *)0)->e))
+#define SK_PNMI_RLM_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_RLMT *)0)->e))
+#define SK_PNMI_MON_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_RLMT_MONITOR *)0)->e))
+#define SK_PNMI_TRP_OFF(e)	((SK_U32)(SK_UPTR)&(((SK_PNMI_TRAP *)0)->e))
+
+#define SK_PNMI_SET_STAT(b,s,o)	{SK_U32	Val32; char *pVal; \
+					Val32 = (s); \
+					pVal = (char *)(b) + ((SK_U32)(SK_UPTR) \
+						&(((SK_PNMI_STRUCT_DATA *)0)-> \
+						ReturnStatus.ErrorStatus)); \
+					SK_PNMI_STORE_U32(pVal, Val32); \
+					Val32 = (o); \
+					pVal = (char *)(b) + ((SK_U32)(SK_UPTR) \
+						&(((SK_PNMI_STRUCT_DATA *)0)-> \
+						ReturnStatus.ErrorOffset)); \
+					SK_PNMI_STORE_U32(pVal, Val32);}
+
+/*
+ * Time macros
+ */
+#ifndef SK_PNMI_HUNDREDS_SEC
+#if SK_TICKS_PER_SEC == 100
+#define SK_PNMI_HUNDREDS_SEC(t)	(t)
+#else
+#define SK_PNMI_HUNDREDS_SEC(t)	(((t) * 100) / (SK_TICKS_PER_SEC))
+#endif /* !SK_TICKS_PER_SEC */
+#endif /* !SK_PNMI_HUNDREDS_SEC */
+
+/*
+ * Macros to work around alignment problems
+ */
+#ifndef SK_PNMI_STORE_U16
+#define SK_PNMI_STORE_U16(p,v)	{*(char *)(p) = *((char *)&(v)); \
+					*((char *)(p) + 1) = \
+						*(((char *)&(v)) + 1);}
+#endif
+
+#ifndef SK_PNMI_STORE_U32
+#define SK_PNMI_STORE_U32(p,v)	{*(char *)(p) = *((char *)&(v)); \
+					*((char *)(p) + 1) = \
+						*(((char *)&(v)) + 1); \
+					*((char *)(p) + 2) = \
+						*(((char *)&(v)) + 2); \
+					*((char *)(p) + 3) = \
+						*(((char *)&(v)) + 3);}
+#endif
+
+#ifndef SK_PNMI_STORE_U64
+#define SK_PNMI_STORE_U64(p,v)	{*(char *)(p) = *((char *)&(v)); \
+					*((char *)(p) + 1) = \
+						*(((char *)&(v)) + 1); \
+					*((char *)(p) + 2) = \
+						*(((char *)&(v)) + 2); \
+					*((char *)(p) + 3) = \
+						*(((char *)&(v)) + 3); \
+					*((char *)(p) + 4) = \
+						*(((char *)&(v)) + 4); \
+					*((char *)(p) + 5) = \
+						*(((char *)&(v)) + 5); \
+					*((char *)(p) + 6) = \
+						*(((char *)&(v)) + 6); \
+					*((char *)(p) + 7) = \
+						*(((char *)&(v)) + 7);}
+#endif
+
+#ifndef SK_PNMI_READ_U16
+#define SK_PNMI_READ_U16(p,v)	{*((char *)&(v)) = *(char *)(p); \
+					*(((char *)&(v)) + 1) = \
+						*((char *)(p) + 1);}
+#endif
+
+#ifndef SK_PNMI_READ_U32
+#define SK_PNMI_READ_U32(p,v)	{*((char *)&(v)) = *(char *)(p); \
+					*(((char *)&(v)) + 1) = \
+						*((char *)(p) + 1); \
+					*(((char *)&(v)) + 2) = \
+						*((char *)(p) + 2); \
+					*(((char *)&(v)) + 3) = \
+						*((char *)(p) + 3);}
+#endif
+
+#ifndef SK_PNMI_READ_U64
+#define SK_PNMI_READ_U64(p,v)	{*((char *)&(v)) = *(char *)(p); \
+					*(((char *)&(v)) + 1) = \
+						*((char *)(p) + 1); \
+					*(((char *)&(v)) + 2) = \
+						*((char *)(p) + 2); \
+					*(((char *)&(v)) + 3) = \
+						*((char *)(p) + 3); \
+					*(((char *)&(v)) + 4) = \
+						*((char *)(p) + 4); \
+					*(((char *)&(v)) + 5) = \
+						*((char *)(p) + 5); \
+					*(((char *)&(v)) + 6) = \
+						*((char *)(p) + 6); \
+					*(((char *)&(v)) + 7) = \
+						*((char *)(p) + 7);}
+#endif
+
+/*
+ * Macros for Debug
+ */
+#ifdef DEBUG
+
+#define SK_PNMI_CHECKFLAGS(vSt)	{if (pAC->Pnmi.MacUpdatedFlag > 0 || \
+					pAC->Pnmi.RlmtUpdatedFlag > 0 || \
+					pAC->Pnmi.SirqUpdatedFlag > 0) { \
+						SK_DBG_MSG(pAC, \
+						SK_DBGMOD_PNMI, \
+						SK_DBGCAT_CTRL,	\
+						("PNMI: ERR: %s MacUFlag=%d, RlmtUFlag=%d, SirqUFlag=%d\n", \
+						vSt, \
+						pAC->Pnmi.MacUpdatedFlag, \
+						pAC->Pnmi.RlmtUpdatedFlag, \
+						pAC->Pnmi.SirqUpdatedFlag))}}
+
+#else	/* !DEBUG */
+
+#define SK_PNMI_CHECKFLAGS(vSt)	/* Nothing */
+
+#endif	/* !DEBUG */
+
+#endif	/* _SKGEPNM2_H_ */
diff --git a/drivers/net/sk98lin/h/skgepnmi.h b/drivers/net/sk98lin/h/skgepnmi.h
new file mode 100644
index 0000000..1ed214c
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgepnmi.h
@@ -0,0 +1,962 @@
+/*****************************************************************************
+ *
+ * Name:	skgepnmi.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.62 $
+ * Date:	$Date: 2003/08/15 12:31:52 $
+ * Purpose:	Defines for Private Network Management Interface
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+#ifndef _SKGEPNMI_H_
+#define _SKGEPNMI_H_
+
+/*
+ * Include dependencies
+ */
+#include "h/sktypes.h"
+#include "h/skerror.h"
+#include "h/sktimer.h"
+#include "h/ski2c.h"
+#include "h/skaddr.h"
+#include "h/skrlmt.h"
+#include "h/skvpd.h"
+
+/*
+ * Management Database Version
+ */
+#define SK_PNMI_MDB_VERSION		0x00030001	/* 3.1 */
+
+
+/*
+ * Event definitions
+ */
+#define SK_PNMI_EVT_SIRQ_OVERFLOW		1	/* Counter overflow */
+#define SK_PNMI_EVT_SEN_WAR_LOW			2	/* Lower war thres exceeded */
+#define SK_PNMI_EVT_SEN_WAR_UPP			3	/* Upper war thres exceeded */
+#define SK_PNMI_EVT_SEN_ERR_LOW			4	/* Lower err thres exceeded */
+#define SK_PNMI_EVT_SEN_ERR_UPP			5	/* Upper err thres exceeded */
+#define SK_PNMI_EVT_CHG_EST_TIMER		6	/* Timer event for RLMT Chg */
+#define SK_PNMI_EVT_UTILIZATION_TIMER	7	/* Timer event for Utiliza. */
+#define SK_PNMI_EVT_CLEAR_COUNTER		8	/* Clear statistic counters */
+#define SK_PNMI_EVT_XMAC_RESET			9	/* XMAC will be reset */
+
+#define SK_PNMI_EVT_RLMT_PORT_UP		10	/* Port came logically up */
+#define SK_PNMI_EVT_RLMT_PORT_DOWN		11	/* Port went logically down */
+#define SK_PNMI_EVT_RLMT_SEGMENTATION	13	/* Two SP root bridges found */
+#define SK_PNMI_EVT_RLMT_ACTIVE_DOWN	14	/* Port went logically down */
+#define SK_PNMI_EVT_RLMT_ACTIVE_UP		15	/* Port came logically up */
+#define SK_PNMI_EVT_RLMT_SET_NETS		16	/* 1. Parameter is number of nets
+												1 = single net; 2 = dual net */
+#define SK_PNMI_EVT_VCT_RESET		17	/* VCT port reset timer event started with SET. */
+
+
+/*
+ * Return values
+ */
+#define SK_PNMI_ERR_OK				0
+#define SK_PNMI_ERR_GENERAL			1
+#define SK_PNMI_ERR_TOO_SHORT		2
+#define SK_PNMI_ERR_BAD_VALUE		3
+#define SK_PNMI_ERR_READ_ONLY		4
+#define SK_PNMI_ERR_UNKNOWN_OID		5
+#define SK_PNMI_ERR_UNKNOWN_INST	6
+#define SK_PNMI_ERR_UNKNOWN_NET 	7
+#define SK_PNMI_ERR_NOT_SUPPORTED	10
+
+
+/*
+ * Return values of driver reset function SK_DRIVER_RESET() and
+ * driver event function SK_DRIVER_EVENT()
+ */
+#define SK_PNMI_ERR_OK			0
+#define SK_PNMI_ERR_FAIL		1
+
+
+/*
+ * Return values of driver test function SK_DRIVER_SELFTEST()
+ */
+#define SK_PNMI_TST_UNKNOWN		(1 << 0)
+#define SK_PNMI_TST_TRANCEIVER		(1 << 1)
+#define SK_PNMI_TST_ASIC		(1 << 2)
+#define SK_PNMI_TST_SENSOR		(1 << 3)
+#define SK_PNMI_TST_POWERMGMT		(1 << 4)
+#define SK_PNMI_TST_PCI			(1 << 5)
+#define SK_PNMI_TST_MAC			(1 << 6)
+
+
+/*
+ * RLMT specific definitions
+ */
+#define SK_PNMI_RLMT_STATUS_STANDBY	1
+#define SK_PNMI_RLMT_STATUS_ACTIVE	2
+#define SK_PNMI_RLMT_STATUS_ERROR	3
+
+#define SK_PNMI_RLMT_LSTAT_PHY_DOWN	1
+#define SK_PNMI_RLMT_LSTAT_AUTONEG	2
+#define SK_PNMI_RLMT_LSTAT_LOG_DOWN	3
+#define SK_PNMI_RLMT_LSTAT_LOG_UP	4
+#define SK_PNMI_RLMT_LSTAT_INDETERMINATED 5
+
+#define SK_PNMI_RLMT_MODE_CHK_LINK	(SK_RLMT_CHECK_LINK)
+#define SK_PNMI_RLMT_MODE_CHK_RX	(SK_RLMT_CHECK_LOC_LINK)
+#define SK_PNMI_RLMT_MODE_CHK_SPT	(SK_RLMT_CHECK_SEG)
+/* #define SK_PNMI_RLMT_MODE_CHK_EX */
+
+/*
+ * OID definition
+ */
+#ifndef _NDIS_	/* Check, whether NDIS already included OIDs */
+
+#define OID_GEN_XMIT_OK					0x00020101
+#define OID_GEN_RCV_OK					0x00020102
+#define OID_GEN_XMIT_ERROR				0x00020103
+#define OID_GEN_RCV_ERROR				0x00020104
+#define OID_GEN_RCV_NO_BUFFER			0x00020105
+
+/* #define OID_GEN_DIRECTED_BYTES_XMIT	0x00020201 */
+#define OID_GEN_DIRECTED_FRAMES_XMIT	0x00020202
+/* #define OID_GEN_MULTICAST_BYTES_XMIT	0x00020203 */
+#define OID_GEN_MULTICAST_FRAMES_XMIT	0x00020204
+/* #define OID_GEN_BROADCAST_BYTES_XMIT	0x00020205 */
+#define OID_GEN_BROADCAST_FRAMES_XMIT	0x00020206
+/* #define OID_GEN_DIRECTED_BYTES_RCV	0x00020207 */
+#define OID_GEN_DIRECTED_FRAMES_RCV		0x00020208
+/* #define OID_GEN_MULTICAST_BYTES_RCV	0x00020209 */
+#define OID_GEN_MULTICAST_FRAMES_RCV	0x0002020A
+/* #define OID_GEN_BROADCAST_BYTES_RCV	0x0002020B */
+#define OID_GEN_BROADCAST_FRAMES_RCV	0x0002020C
+#define OID_GEN_RCV_CRC_ERROR			0x0002020D
+#define OID_GEN_TRANSMIT_QUEUE_LENGTH	0x0002020E
+
+#define OID_802_3_PERMANENT_ADDRESS		0x01010101
+#define OID_802_3_CURRENT_ADDRESS		0x01010102
+/* #define OID_802_3_MULTICAST_LIST		0x01010103 */
+/* #define OID_802_3_MAXIMUM_LIST_SIZE	0x01010104 */
+/* #define OID_802_3_MAC_OPTIONS		0x01010105 */
+			
+#define OID_802_3_RCV_ERROR_ALIGNMENT	0x01020101
+#define OID_802_3_XMIT_ONE_COLLISION	0x01020102
+#define OID_802_3_XMIT_MORE_COLLISIONS	0x01020103
+#define OID_802_3_XMIT_DEFERRED			0x01020201
+#define OID_802_3_XMIT_MAX_COLLISIONS	0x01020202
+#define OID_802_3_RCV_OVERRUN			0x01020203
+#define OID_802_3_XMIT_UNDERRUN			0x01020204
+#define OID_802_3_XMIT_TIMES_CRS_LOST	0x01020206
+#define OID_802_3_XMIT_LATE_COLLISIONS	0x01020207
+
+/*
+ * PnP and PM OIDs
+ */
+#ifdef SK_POWER_MGMT
+#define OID_PNP_CAPABILITIES			0xFD010100
+#define OID_PNP_SET_POWER				0xFD010101
+#define OID_PNP_QUERY_POWER				0xFD010102
+#define OID_PNP_ADD_WAKE_UP_PATTERN		0xFD010103
+#define OID_PNP_REMOVE_WAKE_UP_PATTERN	0xFD010104
+#define OID_PNP_ENABLE_WAKE_UP			0xFD010106
+#endif /* SK_POWER_MGMT */
+
+#endif /* _NDIS_ */
+
+#define OID_SKGE_MDB_VERSION			0xFF010100
+#define OID_SKGE_SUPPORTED_LIST			0xFF010101
+#define OID_SKGE_VPD_FREE_BYTES			0xFF010102
+#define OID_SKGE_VPD_ENTRIES_LIST		0xFF010103
+#define OID_SKGE_VPD_ENTRIES_NUMBER		0xFF010104
+#define OID_SKGE_VPD_KEY				0xFF010105
+#define OID_SKGE_VPD_VALUE				0xFF010106
+#define OID_SKGE_VPD_ACCESS				0xFF010107
+#define OID_SKGE_VPD_ACTION				0xFF010108
+			
+#define OID_SKGE_PORT_NUMBER			0xFF010110
+#define OID_SKGE_DEVICE_TYPE			0xFF010111
+#define OID_SKGE_DRIVER_DESCR			0xFF010112
+#define OID_SKGE_DRIVER_VERSION			0xFF010113
+#define OID_SKGE_HW_DESCR				0xFF010114
+#define OID_SKGE_HW_VERSION				0xFF010115
+#define OID_SKGE_CHIPSET				0xFF010116
+#define OID_SKGE_ACTION					0xFF010117
+#define OID_SKGE_RESULT					0xFF010118
+#define OID_SKGE_BUS_TYPE				0xFF010119
+#define OID_SKGE_BUS_SPEED				0xFF01011A
+#define OID_SKGE_BUS_WIDTH				0xFF01011B
+/* 0xFF01011C unused */
+#define OID_SKGE_DIAG_ACTION			0xFF01011D
+#define OID_SKGE_DIAG_RESULT			0xFF01011E
+#define OID_SKGE_MTU					0xFF01011F
+#define OID_SKGE_PHYS_CUR_ADDR			0xFF010120
+#define OID_SKGE_PHYS_FAC_ADDR			0xFF010121
+#define OID_SKGE_PMD					0xFF010122
+#define OID_SKGE_CONNECTOR				0xFF010123
+#define OID_SKGE_LINK_CAP				0xFF010124
+#define OID_SKGE_LINK_MODE				0xFF010125
+#define OID_SKGE_LINK_MODE_STATUS		0xFF010126
+#define OID_SKGE_LINK_STATUS			0xFF010127
+#define OID_SKGE_FLOWCTRL_CAP			0xFF010128
+#define OID_SKGE_FLOWCTRL_MODE			0xFF010129
+#define OID_SKGE_FLOWCTRL_STATUS		0xFF01012A
+#define OID_SKGE_PHY_OPERATION_CAP		0xFF01012B
+#define OID_SKGE_PHY_OPERATION_MODE		0xFF01012C
+#define OID_SKGE_PHY_OPERATION_STATUS	0xFF01012D
+#define OID_SKGE_MULTICAST_LIST			0xFF01012E
+#define OID_SKGE_CURRENT_PACKET_FILTER	0xFF01012F
+
+#define OID_SKGE_TRAP					0xFF010130
+#define OID_SKGE_TRAP_NUMBER			0xFF010131
+
+#define OID_SKGE_RLMT_MODE				0xFF010140
+#define OID_SKGE_RLMT_PORT_NUMBER		0xFF010141
+#define OID_SKGE_RLMT_PORT_ACTIVE		0xFF010142
+#define OID_SKGE_RLMT_PORT_PREFERRED	0xFF010143
+#define OID_SKGE_INTERMEDIATE_SUPPORT	0xFF010160
+
+#define OID_SKGE_SPEED_CAP				0xFF010170
+#define OID_SKGE_SPEED_MODE				0xFF010171
+#define OID_SKGE_SPEED_STATUS			0xFF010172
+
+#define OID_SKGE_BOARDLEVEL				0xFF010180
+
+#define OID_SKGE_SENSOR_NUMBER			0xFF020100			
+#define OID_SKGE_SENSOR_INDEX			0xFF020101
+#define OID_SKGE_SENSOR_DESCR			0xFF020102
+#define OID_SKGE_SENSOR_TYPE			0xFF020103
+#define OID_SKGE_SENSOR_VALUE			0xFF020104
+#define OID_SKGE_SENSOR_WAR_THRES_LOW	0xFF020105
+#define OID_SKGE_SENSOR_WAR_THRES_UPP	0xFF020106
+#define OID_SKGE_SENSOR_ERR_THRES_LOW	0xFF020107
+#define OID_SKGE_SENSOR_ERR_THRES_UPP	0xFF020108
+#define OID_SKGE_SENSOR_STATUS			0xFF020109
+#define OID_SKGE_SENSOR_WAR_CTS			0xFF02010A
+#define OID_SKGE_SENSOR_ERR_CTS			0xFF02010B
+#define OID_SKGE_SENSOR_WAR_TIME		0xFF02010C
+#define OID_SKGE_SENSOR_ERR_TIME		0xFF02010D
+
+#define OID_SKGE_CHKSM_NUMBER			0xFF020110
+#define OID_SKGE_CHKSM_RX_OK_CTS		0xFF020111
+#define OID_SKGE_CHKSM_RX_UNABLE_CTS	0xFF020112
+#define OID_SKGE_CHKSM_RX_ERR_CTS		0xFF020113
+#define OID_SKGE_CHKSM_TX_OK_CTS		0xFF020114
+#define OID_SKGE_CHKSM_TX_UNABLE_CTS	0xFF020115
+
+#define OID_SKGE_STAT_TX				0xFF020120
+#define OID_SKGE_STAT_TX_OCTETS			0xFF020121
+#define OID_SKGE_STAT_TX_BROADCAST		0xFF020122
+#define OID_SKGE_STAT_TX_MULTICAST		0xFF020123
+#define OID_SKGE_STAT_TX_UNICAST		0xFF020124
+#define OID_SKGE_STAT_TX_LONGFRAMES		0xFF020125
+#define OID_SKGE_STAT_TX_BURST			0xFF020126
+#define OID_SKGE_STAT_TX_PFLOWC			0xFF020127
+#define OID_SKGE_STAT_TX_FLOWC			0xFF020128
+#define OID_SKGE_STAT_TX_SINGLE_COL		0xFF020129
+#define OID_SKGE_STAT_TX_MULTI_COL		0xFF02012A
+#define OID_SKGE_STAT_TX_EXCESS_COL		0xFF02012B
+#define OID_SKGE_STAT_TX_LATE_COL		0xFF02012C
+#define OID_SKGE_STAT_TX_DEFFERAL		0xFF02012D
+#define OID_SKGE_STAT_TX_EXCESS_DEF		0xFF02012E
+#define OID_SKGE_STAT_TX_UNDERRUN		0xFF02012F
+#define OID_SKGE_STAT_TX_CARRIER		0xFF020130
+/* #define OID_SKGE_STAT_TX_UTIL		0xFF020131 */
+#define OID_SKGE_STAT_TX_64				0xFF020132
+#define OID_SKGE_STAT_TX_127			0xFF020133
+#define OID_SKGE_STAT_TX_255			0xFF020134
+#define OID_SKGE_STAT_TX_511			0xFF020135
+#define OID_SKGE_STAT_TX_1023			0xFF020136
+#define OID_SKGE_STAT_TX_MAX			0xFF020137
+#define OID_SKGE_STAT_TX_SYNC			0xFF020138
+#define OID_SKGE_STAT_TX_SYNC_OCTETS	0xFF020139
+#define OID_SKGE_STAT_RX				0xFF02013A
+#define OID_SKGE_STAT_RX_OCTETS			0xFF02013B
+#define OID_SKGE_STAT_RX_BROADCAST		0xFF02013C
+#define OID_SKGE_STAT_RX_MULTICAST		0xFF02013D
+#define OID_SKGE_STAT_RX_UNICAST		0xFF02013E
+#define OID_SKGE_STAT_RX_PFLOWC			0xFF02013F
+#define OID_SKGE_STAT_RX_FLOWC			0xFF020140
+#define OID_SKGE_STAT_RX_PFLOWC_ERR		0xFF020141
+#define OID_SKGE_STAT_RX_FLOWC_UNKWN	0xFF020142
+#define OID_SKGE_STAT_RX_BURST			0xFF020143
+#define OID_SKGE_STAT_RX_MISSED			0xFF020144
+#define OID_SKGE_STAT_RX_FRAMING		0xFF020145
+#define OID_SKGE_STAT_RX_OVERFLOW		0xFF020146
+#define OID_SKGE_STAT_RX_JABBER			0xFF020147
+#define OID_SKGE_STAT_RX_CARRIER		0xFF020148
+#define OID_SKGE_STAT_RX_IR_LENGTH		0xFF020149
+#define OID_SKGE_STAT_RX_SYMBOL			0xFF02014A
+#define OID_SKGE_STAT_RX_SHORTS			0xFF02014B
+#define OID_SKGE_STAT_RX_RUNT			0xFF02014C
+#define OID_SKGE_STAT_RX_CEXT			0xFF02014D
+#define OID_SKGE_STAT_RX_TOO_LONG		0xFF02014E
+#define OID_SKGE_STAT_RX_FCS			0xFF02014F
+/* #define OID_SKGE_STAT_RX_UTIL		0xFF020150 */
+#define OID_SKGE_STAT_RX_64				0xFF020151
+#define OID_SKGE_STAT_RX_127			0xFF020152
+#define OID_SKGE_STAT_RX_255			0xFF020153
+#define OID_SKGE_STAT_RX_511			0xFF020154
+#define OID_SKGE_STAT_RX_1023			0xFF020155
+#define OID_SKGE_STAT_RX_MAX			0xFF020156
+#define OID_SKGE_STAT_RX_LONGFRAMES		0xFF020157
+
+#define OID_SKGE_RLMT_CHANGE_CTS		0xFF020160
+#define OID_SKGE_RLMT_CHANGE_TIME		0xFF020161
+#define OID_SKGE_RLMT_CHANGE_ESTIM		0xFF020162
+#define OID_SKGE_RLMT_CHANGE_THRES		0xFF020163
+
+#define OID_SKGE_RLMT_PORT_INDEX		0xFF020164
+#define OID_SKGE_RLMT_STATUS			0xFF020165
+#define OID_SKGE_RLMT_TX_HELLO_CTS		0xFF020166
+#define OID_SKGE_RLMT_RX_HELLO_CTS		0xFF020167
+#define OID_SKGE_RLMT_TX_SP_REQ_CTS		0xFF020168
+#define OID_SKGE_RLMT_RX_SP_CTS			0xFF020169
+
+#define OID_SKGE_RLMT_MONITOR_NUMBER	0xFF010150
+#define OID_SKGE_RLMT_MONITOR_INDEX		0xFF010151
+#define OID_SKGE_RLMT_MONITOR_ADDR		0xFF010152
+#define OID_SKGE_RLMT_MONITOR_ERRS		0xFF010153
+#define OID_SKGE_RLMT_MONITOR_TIMESTAMP	0xFF010154
+#define OID_SKGE_RLMT_MONITOR_ADMIN		0xFF010155
+
+#define OID_SKGE_TX_SW_QUEUE_LEN		0xFF020170
+#define OID_SKGE_TX_SW_QUEUE_MAX		0xFF020171
+#define OID_SKGE_TX_RETRY				0xFF020172
+#define OID_SKGE_RX_INTR_CTS			0xFF020173
+#define OID_SKGE_TX_INTR_CTS			0xFF020174
+#define OID_SKGE_RX_NO_BUF_CTS			0xFF020175
+#define OID_SKGE_TX_NO_BUF_CTS			0xFF020176
+#define OID_SKGE_TX_USED_DESCR_NO		0xFF020177
+#define OID_SKGE_RX_DELIVERED_CTS		0xFF020178
+#define OID_SKGE_RX_OCTETS_DELIV_CTS	0xFF020179
+#define OID_SKGE_RX_HW_ERROR_CTS		0xFF02017A
+#define OID_SKGE_TX_HW_ERROR_CTS		0xFF02017B
+#define OID_SKGE_IN_ERRORS_CTS			0xFF02017C
+#define OID_SKGE_OUT_ERROR_CTS			0xFF02017D
+#define OID_SKGE_ERR_RECOVERY_CTS		0xFF02017E
+#define OID_SKGE_SYSUPTIME				0xFF02017F
+
+#define OID_SKGE_ALL_DATA				0xFF020190
+
+/* Defines for VCT. */
+#define OID_SKGE_VCT_GET				0xFF020200
+#define OID_SKGE_VCT_SET				0xFF020201
+#define OID_SKGE_VCT_STATUS				0xFF020202
+
+#ifdef SK_DIAG_SUPPORT
+/* Defines for driver DIAG mode. */
+#define OID_SKGE_DIAG_MODE				0xFF020204
+#endif /* SK_DIAG_SUPPORT */
+
+/* New OIDs */
+#define OID_SKGE_DRIVER_RELDATE			0xFF020210
+#define OID_SKGE_DRIVER_FILENAME		0xFF020211
+#define OID_SKGE_CHIPID					0xFF020212
+#define OID_SKGE_RAMSIZE				0xFF020213
+#define OID_SKGE_VAUXAVAIL				0xFF020214
+#define OID_SKGE_PHY_TYPE				0xFF020215
+#define OID_SKGE_PHY_LP_MODE			0xFF020216
+
+/* VCT struct to store a backup copy of VCT data after a port reset. */
+typedef struct s_PnmiVct {
+	SK_U8			VctStatus;
+	SK_U8			PCableLen;
+	SK_U32			PMdiPairLen[4];
+	SK_U8			PMdiPairSts[4];
+} SK_PNMI_VCT;
+
+
+/* VCT status values (to be given to CPA via OID_SKGE_VCT_STATUS). */
+#define SK_PNMI_VCT_NONE		0
+#define SK_PNMI_VCT_OLD_VCT_DATA	1
+#define SK_PNMI_VCT_NEW_VCT_DATA	2
+#define SK_PNMI_VCT_OLD_DSP_DATA	4
+#define SK_PNMI_VCT_NEW_DSP_DATA	8
+#define SK_PNMI_VCT_RUNNING		16
+
+
+/* VCT cable test status. */
+#define SK_PNMI_VCT_NORMAL_CABLE		0
+#define SK_PNMI_VCT_SHORT_CABLE			1
+#define SK_PNMI_VCT_OPEN_CABLE			2
+#define SK_PNMI_VCT_TEST_FAIL			3
+#define SK_PNMI_VCT_IMPEDANCE_MISMATCH		4
+
+#define	OID_SKGE_TRAP_SEN_WAR_LOW		500
+#define OID_SKGE_TRAP_SEN_WAR_UPP		501
+#define	OID_SKGE_TRAP_SEN_ERR_LOW		502
+#define OID_SKGE_TRAP_SEN_ERR_UPP		503
+#define OID_SKGE_TRAP_RLMT_CHANGE_THRES	520
+#define OID_SKGE_TRAP_RLMT_CHANGE_PORT	521
+#define OID_SKGE_TRAP_RLMT_PORT_DOWN	522
+#define OID_SKGE_TRAP_RLMT_PORT_UP		523
+#define OID_SKGE_TRAP_RLMT_SEGMENTATION	524
+
+#ifdef SK_DIAG_SUPPORT
+/* Defines for driver DIAG mode. */
+#define SK_DIAG_ATTACHED	2
+#define SK_DIAG_RUNNING		1
+#define SK_DIAG_IDLE		0
+#endif /* SK_DIAG_SUPPORT */
+
+/*
+ * Generic PNMI IOCTL subcommand definitions.
+ */
+#define	SK_GET_SINGLE_VAR		1
+#define	SK_SET_SINGLE_VAR		2
+#define	SK_PRESET_SINGLE_VAR	3
+#define	SK_GET_FULL_MIB			4
+#define	SK_SET_FULL_MIB			5
+#define	SK_PRESET_FULL_MIB		6
+
+
+/*
+ * Define error numbers and messages for syslog
+ */
+#define SK_PNMI_ERR001		(SK_ERRBASE_PNMI + 1)
+#define SK_PNMI_ERR001MSG	"SkPnmiGetStruct: Unknown OID"
+#define SK_PNMI_ERR002		(SK_ERRBASE_PNMI + 2)
+#define SK_PNMI_ERR002MSG	"SkPnmiGetStruct: Cannot read VPD keys"
+#define SK_PNMI_ERR003		(SK_ERRBASE_PNMI + 3)
+#define SK_PNMI_ERR003MSG	"OidStruct: Called with wrong OID"
+#define SK_PNMI_ERR004		(SK_ERRBASE_PNMI + 4)
+#define SK_PNMI_ERR004MSG	"OidStruct: Called with wrong action"
+#define SK_PNMI_ERR005		(SK_ERRBASE_PNMI + 5)
+#define SK_PNMI_ERR005MSG	"Perform: Cannot reset driver"
+#define SK_PNMI_ERR006		(SK_ERRBASE_PNMI + 6)
+#define SK_PNMI_ERR006MSG	"Perform: Unknown OID action command"
+#define SK_PNMI_ERR007		(SK_ERRBASE_PNMI + 7)
+#define SK_PNMI_ERR007MSG	"General: Driver description not initialized"
+#define SK_PNMI_ERR008		(SK_ERRBASE_PNMI + 8)
+#define SK_PNMI_ERR008MSG	"Addr: Tried to get unknown OID"
+#define SK_PNMI_ERR009		(SK_ERRBASE_PNMI + 9)
+#define SK_PNMI_ERR009MSG	"Addr: Unknown OID"
+#define SK_PNMI_ERR010		(SK_ERRBASE_PNMI + 10)
+#define SK_PNMI_ERR010MSG	"CsumStat: Unknown OID"
+#define SK_PNMI_ERR011		(SK_ERRBASE_PNMI + 11)
+#define SK_PNMI_ERR011MSG	"SensorStat: Sensor descr string too long"
+#define SK_PNMI_ERR012		(SK_ERRBASE_PNMI + 12)
+#define SK_PNMI_ERR012MSG	"SensorStat: Unknown OID"
+#define SK_PNMI_ERR013		(SK_ERRBASE_PNMI + 13)
+#define SK_PNMI_ERR013MSG	""
+#define SK_PNMI_ERR014		(SK_ERRBASE_PNMI + 14)
+#define SK_PNMI_ERR014MSG	"Vpd: Cannot read VPD keys"
+#define SK_PNMI_ERR015		(SK_ERRBASE_PNMI + 15)
+#define SK_PNMI_ERR015MSG	"Vpd: Internal array for VPD keys to small"
+#define SK_PNMI_ERR016		(SK_ERRBASE_PNMI + 16)
+#define SK_PNMI_ERR016MSG	"Vpd: Key string too long"
+#define SK_PNMI_ERR017		(SK_ERRBASE_PNMI + 17)
+#define SK_PNMI_ERR017MSG	"Vpd: Invalid VPD status pointer"
+#define SK_PNMI_ERR018		(SK_ERRBASE_PNMI + 18)
+#define SK_PNMI_ERR018MSG	"Vpd: VPD data not valid"
+#define SK_PNMI_ERR019		(SK_ERRBASE_PNMI + 19)
+#define SK_PNMI_ERR019MSG	"Vpd: VPD entries list string too long"
+#define SK_PNMI_ERR021		(SK_ERRBASE_PNMI + 21)
+#define SK_PNMI_ERR021MSG	"Vpd: VPD data string too long"
+#define SK_PNMI_ERR022		(SK_ERRBASE_PNMI + 22)
+#define SK_PNMI_ERR022MSG	"Vpd: VPD data string too long should be errored before"
+#define SK_PNMI_ERR023		(SK_ERRBASE_PNMI + 23)
+#define SK_PNMI_ERR023MSG	"Vpd: Unknown OID in get action"
+#define SK_PNMI_ERR024		(SK_ERRBASE_PNMI + 24)
+#define SK_PNMI_ERR024MSG	"Vpd: Unknown OID in preset/set action"
+#define SK_PNMI_ERR025		(SK_ERRBASE_PNMI + 25)
+#define SK_PNMI_ERR025MSG	"Vpd: Cannot write VPD after modify entry"
+#define SK_PNMI_ERR026		(SK_ERRBASE_PNMI + 26)
+#define SK_PNMI_ERR026MSG	"Vpd: Cannot update VPD"
+#define SK_PNMI_ERR027		(SK_ERRBASE_PNMI + 27)
+#define SK_PNMI_ERR027MSG	"Vpd: Cannot delete VPD entry"
+#define SK_PNMI_ERR028		(SK_ERRBASE_PNMI + 28)
+#define SK_PNMI_ERR028MSG	"Vpd: Cannot update VPD after delete entry"
+#define SK_PNMI_ERR029		(SK_ERRBASE_PNMI + 29)
+#define SK_PNMI_ERR029MSG	"General: Driver description string too long"
+#define SK_PNMI_ERR030		(SK_ERRBASE_PNMI + 30)
+#define SK_PNMI_ERR030MSG	"General: Driver version not initialized"
+#define SK_PNMI_ERR031		(SK_ERRBASE_PNMI + 31)
+#define SK_PNMI_ERR031MSG	"General: Driver version string too long"
+#define SK_PNMI_ERR032		(SK_ERRBASE_PNMI + 32)
+#define SK_PNMI_ERR032MSG	"General: Cannot read VPD Name for HW descr"
+#define SK_PNMI_ERR033		(SK_ERRBASE_PNMI + 33)
+#define SK_PNMI_ERR033MSG	"General: HW description string too long"
+#define SK_PNMI_ERR034		(SK_ERRBASE_PNMI + 34)
+#define SK_PNMI_ERR034MSG	"General: Unknown OID"
+#define SK_PNMI_ERR035		(SK_ERRBASE_PNMI + 35)
+#define SK_PNMI_ERR035MSG	"Rlmt: Unknown OID"
+#define SK_PNMI_ERR036		(SK_ERRBASE_PNMI + 36)
+#define SK_PNMI_ERR036MSG	""
+#define SK_PNMI_ERR037		(SK_ERRBASE_PNMI + 37)
+#define SK_PNMI_ERR037MSG	"Rlmt: SK_RLMT_MODE_CHANGE event return not 0"
+#define SK_PNMI_ERR038		(SK_ERRBASE_PNMI + 38)
+#define SK_PNMI_ERR038MSG	"Rlmt: SK_RLMT_PREFPORT_CHANGE event return not 0"
+#define SK_PNMI_ERR039		(SK_ERRBASE_PNMI + 39)
+#define SK_PNMI_ERR039MSG	"RlmtStat: Unknown OID"
+#define SK_PNMI_ERR040		(SK_ERRBASE_PNMI + 40)
+#define SK_PNMI_ERR040MSG	"PowerManagement: Unknown OID"
+#define SK_PNMI_ERR041		(SK_ERRBASE_PNMI + 41)
+#define SK_PNMI_ERR041MSG	"MacPrivateConf: Unknown OID"
+#define SK_PNMI_ERR042		(SK_ERRBASE_PNMI + 42)
+#define SK_PNMI_ERR042MSG	"MacPrivateConf: SK_HWEV_SET_ROLE returned not 0"
+#define SK_PNMI_ERR043		(SK_ERRBASE_PNMI + 43)
+#define SK_PNMI_ERR043MSG	"MacPrivateConf: SK_HWEV_SET_LMODE returned not 0"
+#define SK_PNMI_ERR044		(SK_ERRBASE_PNMI + 44)
+#define SK_PNMI_ERR044MSG	"MacPrivateConf: SK_HWEV_SET_FLOWMODE returned not 0"
+#define SK_PNMI_ERR045		(SK_ERRBASE_PNMI + 45)
+#define SK_PNMI_ERR045MSG	"MacPrivateConf: SK_HWEV_SET_SPEED returned not 0"
+#define SK_PNMI_ERR046		(SK_ERRBASE_PNMI + 46)
+#define SK_PNMI_ERR046MSG	"Monitor: Unknown OID"
+#define SK_PNMI_ERR047		(SK_ERRBASE_PNMI + 47)
+#define SK_PNMI_ERR047MSG	"SirqUpdate: Event function returns not 0"
+#define SK_PNMI_ERR048		(SK_ERRBASE_PNMI + 48)
+#define SK_PNMI_ERR048MSG	"RlmtUpdate: Event function returns not 0"
+#define SK_PNMI_ERR049		(SK_ERRBASE_PNMI + 49)
+#define SK_PNMI_ERR049MSG	"SkPnmiInit: Invalid size of 'CounterOffset' struct!!"
+#define SK_PNMI_ERR050		(SK_ERRBASE_PNMI + 50)
+#define SK_PNMI_ERR050MSG	"SkPnmiInit: Invalid size of 'StatAddr' table!!"
+#define SK_PNMI_ERR051		(SK_ERRBASE_PNMI + 51)
+#define SK_PNMI_ERR051MSG	"SkPnmiEvent: Port switch suspicious"
+#define SK_PNMI_ERR052		(SK_ERRBASE_PNMI + 52)
+#define SK_PNMI_ERR052MSG	""
+#define SK_PNMI_ERR053		(SK_ERRBASE_PNMI + 53)
+#define SK_PNMI_ERR053MSG	"General: Driver release date not initialized"
+#define SK_PNMI_ERR054		(SK_ERRBASE_PNMI + 54)
+#define SK_PNMI_ERR054MSG	"General: Driver release date string too long"
+#define SK_PNMI_ERR055		(SK_ERRBASE_PNMI + 55)
+#define SK_PNMI_ERR055MSG	"General: Driver file name not initialized"
+#define SK_PNMI_ERR056		(SK_ERRBASE_PNMI + 56)
+#define SK_PNMI_ERR056MSG	"General: Driver file name string too long"
+
+/*
+ * Management counter macros called by the driver
+ */
+#define SK_PNMI_SET_DRIVER_DESCR(pAC,v)	((pAC)->Pnmi.pDriverDescription = \
+	(char *)(v))
+
+#define SK_PNMI_SET_DRIVER_VER(pAC,v)	((pAC)->Pnmi.pDriverVersion = \
+	(char *)(v))
+
+#define SK_PNMI_SET_DRIVER_RELDATE(pAC,v)	((pAC)->Pnmi.pDriverReleaseDate = \
+	(char *)(v))
+
+#define SK_PNMI_SET_DRIVER_FILENAME(pAC,v)	((pAC)->Pnmi.pDriverFileName = \
+	(char *)(v))
+
+#define SK_PNMI_CNT_TX_QUEUE_LEN(pAC,v,p) \
+	{ \
+		(pAC)->Pnmi.Port[p].TxSwQueueLen = (SK_U64)(v); \
+		if ((pAC)->Pnmi.Port[p].TxSwQueueLen > (pAC)->Pnmi.Port[p].TxSwQueueMax) { \
+			(pAC)->Pnmi.Port[p].TxSwQueueMax = (pAC)->Pnmi.Port[p].TxSwQueueLen; \
+		} \
+	}
+#define SK_PNMI_CNT_TX_RETRY(pAC,p)	(((pAC)->Pnmi.Port[p].TxRetryCts)++)
+#define SK_PNMI_CNT_RX_INTR(pAC,p)	(((pAC)->Pnmi.Port[p].RxIntrCts)++)
+#define SK_PNMI_CNT_TX_INTR(pAC,p)	(((pAC)->Pnmi.Port[p].TxIntrCts)++)
+#define SK_PNMI_CNT_NO_RX_BUF(pAC,p)	(((pAC)->Pnmi.Port[p].RxNoBufCts)++)
+#define SK_PNMI_CNT_NO_TX_BUF(pAC,p)	(((pAC)->Pnmi.Port[p].TxNoBufCts)++)
+#define SK_PNMI_CNT_USED_TX_DESCR(pAC,v,p) \
+	((pAC)->Pnmi.Port[p].TxUsedDescrNo=(SK_U64)(v));
+#define SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,v,p) \
+	{ \
+		((pAC)->Pnmi.Port[p].RxDeliveredCts)++; \
+		(pAC)->Pnmi.Port[p].RxOctetsDeliveredCts += (SK_U64)(v); \
+	}
+#define SK_PNMI_CNT_ERR_RECOVERY(pAC,p)	(((pAC)->Pnmi.Port[p].ErrRecoveryCts)++);
+
+#define SK_PNMI_CNT_SYNC_OCTETS(pAC,p,v) \
+	{ \
+		if ((p) < SK_MAX_MACS) { \
+			((pAC)->Pnmi.Port[p].StatSyncCts)++; \
+			(pAC)->Pnmi.Port[p].StatSyncOctetsCts += (SK_U64)(v); \
+		} \
+	}
+
+#define SK_PNMI_CNT_RX_LONGFRAMES(pAC,p) \
+	{ \
+		if ((p) < SK_MAX_MACS) { \
+			((pAC)->Pnmi.Port[p].StatRxLongFrameCts++); \
+		} \
+	}
+
+#define SK_PNMI_CNT_RX_FRAMETOOLONG(pAC,p) \
+	{ \
+		if ((p) < SK_MAX_MACS) { \
+			((pAC)->Pnmi.Port[p].StatRxFrameTooLongCts++); \
+		} \
+	}
+
+#define SK_PNMI_CNT_RX_PMACC_ERR(pAC,p) \
+	{ \
+		if ((p) < SK_MAX_MACS) { \
+			((pAC)->Pnmi.Port[p].StatRxPMaccErr++); \
+		} \
+	}
+
+/*
+ * Conversion Macros
+ */
+#define SK_PNMI_PORT_INST2LOG(i)	((unsigned int)(i) - 1)
+#define SK_PNMI_PORT_LOG2INST(l)	((unsigned int)(l) + 1)
+#define SK_PNMI_PORT_PHYS2LOG(p)	((unsigned int)(p) + 1)
+#define SK_PNMI_PORT_LOG2PHYS(pAC,l)	((unsigned int)(l) - 1)
+#define SK_PNMI_PORT_PHYS2INST(pAC,p)	\
+	(pAC->Pnmi.DualNetActiveFlag ? 2 : ((unsigned int)(p) + 2))
+#define SK_PNMI_PORT_INST2PHYS(pAC,i)	((unsigned int)(i) - 2)
+
+/*
+ * Structure definition for SkPnmiGetStruct and SkPnmiSetStruct
+ */
+#define SK_PNMI_VPD_KEY_SIZE	5
+#define SK_PNMI_VPD_BUFSIZE		(VPD_SIZE)
+#define SK_PNMI_VPD_ENTRIES		(VPD_SIZE / 4)
+#define SK_PNMI_VPD_DATALEN		128 /*  Number of data bytes */
+
+#define SK_PNMI_MULTICAST_LISTLEN	64
+#define SK_PNMI_SENSOR_ENTRIES		(SK_MAX_SENSORS)
+#define SK_PNMI_CHECKSUM_ENTRIES	3
+#define SK_PNMI_MAC_ENTRIES			(SK_MAX_MACS + 1)
+#define SK_PNMI_MONITOR_ENTRIES		20
+#define SK_PNMI_TRAP_ENTRIES		10
+#define SK_PNMI_TRAPLEN				128
+#define SK_PNMI_STRINGLEN1			80
+#define SK_PNMI_STRINGLEN2			25
+#define SK_PNMI_TRAP_QUEUE_LEN		512
+
+typedef struct s_PnmiVpd {
+	char			VpdKey[SK_PNMI_VPD_KEY_SIZE];
+	char			VpdValue[SK_PNMI_VPD_DATALEN];
+	SK_U8			VpdAccess;
+	SK_U8			VpdAction;
+} SK_PNMI_VPD;
+
+typedef struct s_PnmiSensor {
+	SK_U8			SensorIndex;
+	char			SensorDescr[SK_PNMI_STRINGLEN2];
+	SK_U8			SensorType;
+	SK_U32			SensorValue;
+	SK_U32			SensorWarningThresholdLow;
+	SK_U32			SensorWarningThresholdHigh;
+	SK_U32			SensorErrorThresholdLow;
+	SK_U32			SensorErrorThresholdHigh;
+	SK_U8			SensorStatus;
+	SK_U64			SensorWarningCts;
+	SK_U64			SensorErrorCts;
+	SK_U64			SensorWarningTimestamp;
+	SK_U64			SensorErrorTimestamp;
+} SK_PNMI_SENSOR;
+
+typedef struct s_PnmiChecksum {
+	SK_U64			ChecksumRxOkCts;
+	SK_U64			ChecksumRxUnableCts;
+	SK_U64			ChecksumRxErrCts;
+	SK_U64			ChecksumTxOkCts;
+	SK_U64			ChecksumTxUnableCts;
+} SK_PNMI_CHECKSUM;
+
+typedef struct s_PnmiStat {
+	SK_U64			StatTxOkCts;
+	SK_U64			StatTxOctetsOkCts;
+	SK_U64			StatTxBroadcastOkCts;
+	SK_U64			StatTxMulticastOkCts;
+	SK_U64			StatTxUnicastOkCts;
+	SK_U64			StatTxLongFramesCts;
+	SK_U64			StatTxBurstCts;
+	SK_U64			StatTxPauseMacCtrlCts;
+	SK_U64			StatTxMacCtrlCts;
+	SK_U64			StatTxSingleCollisionCts;
+	SK_U64			StatTxMultipleCollisionCts;
+	SK_U64			StatTxExcessiveCollisionCts;
+	SK_U64			StatTxLateCollisionCts;
+	SK_U64			StatTxDeferralCts;
+	SK_U64			StatTxExcessiveDeferralCts;
+	SK_U64			StatTxFifoUnderrunCts;
+	SK_U64			StatTxCarrierCts;
+	SK_U64			Dummy1; /* StatTxUtilization */
+	SK_U64			StatTx64Cts;
+	SK_U64			StatTx127Cts;
+	SK_U64			StatTx255Cts;
+	SK_U64			StatTx511Cts;
+	SK_U64			StatTx1023Cts;
+	SK_U64			StatTxMaxCts;
+	SK_U64			StatTxSyncCts;
+	SK_U64			StatTxSyncOctetsCts;
+	SK_U64			StatRxOkCts;
+	SK_U64			StatRxOctetsOkCts;
+	SK_U64			StatRxBroadcastOkCts;
+	SK_U64			StatRxMulticastOkCts;
+	SK_U64			StatRxUnicastOkCts;
+	SK_U64			StatRxLongFramesCts;
+	SK_U64			StatRxPauseMacCtrlCts;
+	SK_U64			StatRxMacCtrlCts;
+	SK_U64			StatRxPauseMacCtrlErrorCts;
+	SK_U64			StatRxMacCtrlUnknownCts;
+	SK_U64			StatRxBurstCts;
+	SK_U64			StatRxMissedCts;
+	SK_U64			StatRxFramingCts;
+	SK_U64			StatRxFifoOverflowCts;
+	SK_U64			StatRxJabberCts;
+	SK_U64			StatRxCarrierCts;
+	SK_U64			StatRxIRLengthCts;
+	SK_U64			StatRxSymbolCts;
+	SK_U64			StatRxShortsCts;
+	SK_U64			StatRxRuntCts;
+	SK_U64			StatRxCextCts;
+	SK_U64			StatRxTooLongCts;
+	SK_U64			StatRxFcsCts;
+	SK_U64			Dummy2; /* StatRxUtilization */
+	SK_U64			StatRx64Cts;
+	SK_U64			StatRx127Cts;
+	SK_U64			StatRx255Cts;
+	SK_U64			StatRx511Cts;
+	SK_U64			StatRx1023Cts;
+	SK_U64			StatRxMaxCts;
+} SK_PNMI_STAT;
+
+typedef struct s_PnmiConf {
+	char			ConfMacCurrentAddr[6];
+	char			ConfMacFactoryAddr[6];
+	SK_U8			ConfPMD;
+	SK_U8			ConfConnector;
+	SK_U32			ConfPhyType;
+	SK_U32			ConfPhyMode;
+	SK_U8			ConfLinkCapability;
+	SK_U8			ConfLinkMode;
+	SK_U8			ConfLinkModeStatus;
+	SK_U8			ConfLinkStatus;
+	SK_U8			ConfFlowCtrlCapability;
+	SK_U8			ConfFlowCtrlMode;
+	SK_U8			ConfFlowCtrlStatus;
+	SK_U8			ConfPhyOperationCapability;
+	SK_U8			ConfPhyOperationMode;
+	SK_U8			ConfPhyOperationStatus;
+	SK_U8			ConfSpeedCapability;
+	SK_U8			ConfSpeedMode;
+	SK_U8			ConfSpeedStatus;
+} SK_PNMI_CONF;
+
+typedef struct s_PnmiRlmt {
+	SK_U32			RlmtIndex;
+	SK_U32			RlmtStatus;
+	SK_U64			RlmtTxHelloCts;
+	SK_U64			RlmtRxHelloCts;
+	SK_U64			RlmtTxSpHelloReqCts;
+	SK_U64			RlmtRxSpHelloCts;
+} SK_PNMI_RLMT;
+
+typedef struct s_PnmiRlmtMonitor {
+	SK_U32			RlmtMonitorIndex;
+	char			RlmtMonitorAddr[6];
+	SK_U64			RlmtMonitorErrorCts;
+	SK_U64			RlmtMonitorTimestamp;
+	SK_U8			RlmtMonitorAdmin;
+} SK_PNMI_RLMT_MONITOR;
+
+typedef struct s_PnmiRequestStatus {
+	SK_U32			ErrorStatus;
+	SK_U32			ErrorOffset;
+} SK_PNMI_REQUEST_STATUS;
+
+typedef struct s_PnmiStrucData {
+	SK_U32			MgmtDBVersion;
+	SK_PNMI_REQUEST_STATUS	ReturnStatus;
+	SK_U32			VpdFreeBytes;
+	char			VpdEntriesList[SK_PNMI_VPD_ENTRIES * SK_PNMI_VPD_KEY_SIZE];
+	SK_U32			VpdEntriesNumber;
+	SK_PNMI_VPD		Vpd[SK_PNMI_VPD_ENTRIES];
+	SK_U32			PortNumber;
+	SK_U32			DeviceType;
+	char			DriverDescr[SK_PNMI_STRINGLEN1];
+	char			DriverVersion[SK_PNMI_STRINGLEN2];
+	char			DriverReleaseDate[SK_PNMI_STRINGLEN1];
+	char			DriverFileName[SK_PNMI_STRINGLEN1];
+	char			HwDescr[SK_PNMI_STRINGLEN1];
+	char			HwVersion[SK_PNMI_STRINGLEN2];
+	SK_U16			Chipset;
+	SK_U32			ChipId;
+	SK_U8			VauxAvail;
+	SK_U32			RamSize;
+	SK_U32			MtuSize;
+	SK_U32			Action;
+	SK_U32			TestResult;
+	SK_U8			BusType;
+	SK_U8			BusSpeed;
+	SK_U8			BusWidth;
+	SK_U8			SensorNumber;
+	SK_PNMI_SENSOR	Sensor[SK_PNMI_SENSOR_ENTRIES];
+	SK_U8			ChecksumNumber;
+	SK_PNMI_CHECKSUM	Checksum[SK_PNMI_CHECKSUM_ENTRIES];
+	SK_PNMI_STAT	Stat[SK_PNMI_MAC_ENTRIES];
+	SK_PNMI_CONF	Conf[SK_PNMI_MAC_ENTRIES];
+	SK_U8			RlmtMode;
+	SK_U32			RlmtPortNumber;
+	SK_U8			RlmtPortActive;
+	SK_U8			RlmtPortPreferred;
+	SK_U64			RlmtChangeCts;
+	SK_U64			RlmtChangeTime;
+	SK_U64			RlmtChangeEstimate;
+	SK_U64			RlmtChangeThreshold;
+	SK_PNMI_RLMT	Rlmt[SK_MAX_MACS];
+	SK_U32			RlmtMonitorNumber;
+	SK_PNMI_RLMT_MONITOR	RlmtMonitor[SK_PNMI_MONITOR_ENTRIES];
+	SK_U32			TrapNumber;
+	SK_U8			Trap[SK_PNMI_TRAP_QUEUE_LEN];
+	SK_U64			TxSwQueueLen;
+	SK_U64			TxSwQueueMax;
+	SK_U64			TxRetryCts;
+	SK_U64			RxIntrCts;
+	SK_U64			TxIntrCts;
+	SK_U64			RxNoBufCts;
+	SK_U64			TxNoBufCts;
+	SK_U64			TxUsedDescrNo;
+	SK_U64			RxDeliveredCts;
+	SK_U64			RxOctetsDeliveredCts;
+	SK_U64			RxHwErrorsCts;
+	SK_U64			TxHwErrorsCts;
+	SK_U64			InErrorsCts;
+	SK_U64			OutErrorsCts;
+	SK_U64			ErrRecoveryCts;
+	SK_U64			SysUpTime;
+} SK_PNMI_STRUCT_DATA;
+
+#define SK_PNMI_STRUCT_SIZE	(sizeof(SK_PNMI_STRUCT_DATA))
+#define SK_PNMI_MIN_STRUCT_SIZE	((unsigned int)(SK_UPTR)\
+				 &(((SK_PNMI_STRUCT_DATA *)0)->VpdFreeBytes))
+														/*
+														 * ReturnStatus field
+														 * must be located
+														 * before VpdFreeBytes
+														 */
+
+/*
+ * Various definitions
+ */
+#define SK_PNMI_MAX_PROTOS		3
+
+#define SK_PNMI_CNT_NO			66	/* Must have the value of the enum
+									 * SK_PNMI_MAX_IDX. Define SK_PNMI_CHECK
+									 * for check while init phase 1
+									 */
+
+/*
+ * Estimate data structure
+ */
+typedef struct s_PnmiEstimate {
+	unsigned int	EstValueIndex;
+	SK_U64			EstValue[7];
+	SK_U64			Estimate;
+	SK_TIMER		EstTimer;
+} SK_PNMI_ESTIMATE;
+
+
+/*
+ * VCT timer data structure
+ */
+typedef struct s_VctTimer {
+	SK_TIMER		VctTimer;
+} SK_PNMI_VCT_TIMER;
+
+
+/*
+ * PNMI specific adapter context structure
+ */
+typedef struct s_PnmiPort {
+	SK_U64			StatSyncCts;
+	SK_U64			StatSyncOctetsCts;
+	SK_U64			StatRxLongFrameCts;
+	SK_U64			StatRxFrameTooLongCts;
+	SK_U64			StatRxPMaccErr;
+	SK_U64			TxSwQueueLen;
+	SK_U64			TxSwQueueMax;
+	SK_U64			TxRetryCts;
+	SK_U64			RxIntrCts;
+	SK_U64			TxIntrCts;
+	SK_U64			RxNoBufCts;
+	SK_U64			TxNoBufCts;
+	SK_U64			TxUsedDescrNo;
+	SK_U64			RxDeliveredCts;
+	SK_U64			RxOctetsDeliveredCts;
+	SK_U64			RxHwErrorsCts;
+	SK_U64			TxHwErrorsCts;
+	SK_U64			InErrorsCts;
+	SK_U64			OutErrorsCts;
+	SK_U64			ErrRecoveryCts;
+	SK_U64			RxShortZeroMark;
+	SK_U64			CounterOffset[SK_PNMI_CNT_NO];
+	SK_U32			CounterHigh[SK_PNMI_CNT_NO];
+	SK_BOOL			ActiveFlag;
+	SK_U8			Align[3];
+} SK_PNMI_PORT;
+
+
+typedef struct s_PnmiData {
+	SK_PNMI_PORT	Port	[SK_MAX_MACS];
+	SK_PNMI_PORT	BufPort	[SK_MAX_MACS]; /* 2002-09-13 pweber  */
+	SK_U64			VirtualCounterOffset[SK_PNMI_CNT_NO];
+	SK_U32			TestResult;
+	char			HwVersion[10];
+	SK_U16			Align01;
+
+	char			*pDriverDescription;
+	char			*pDriverVersion;
+	char			*pDriverReleaseDate;
+	char			*pDriverFileName;
+
+	int				MacUpdatedFlag;
+	int				RlmtUpdatedFlag;
+	int				SirqUpdatedFlag;
+
+	SK_U64			RlmtChangeCts;
+	SK_U64			RlmtChangeTime;
+	SK_PNMI_ESTIMATE	RlmtChangeEstimate;
+	SK_U64			RlmtChangeThreshold;
+
+	SK_U64			StartUpTime;
+	SK_U32			DeviceType;
+	char			PciBusSpeed;
+	char			PciBusWidth;
+	char			Chipset;
+	char			PMD;
+	char			Connector;
+	SK_BOOL			DualNetActiveFlag;
+	SK_U16			Align02;
+
+	char			TrapBuf[SK_PNMI_TRAP_QUEUE_LEN];
+	unsigned int	TrapBufFree;
+	unsigned int	TrapQueueBeg;
+	unsigned int	TrapQueueEnd;
+	unsigned int	TrapBufPad;
+	unsigned int	TrapUnique;
+	SK_U8		VctStatus[SK_MAX_MACS];
+	SK_PNMI_VCT	VctBackup[SK_MAX_MACS];
+	SK_PNMI_VCT_TIMER VctTimeout[SK_MAX_MACS];
+#ifdef SK_DIAG_SUPPORT
+	SK_U32			DiagAttached;
+#endif /* SK_DIAG_SUPPORT */
+} SK_PNMI;
+
+
+/*
+ * Function prototypes
+ */
+extern int SkPnmiInit(SK_AC *pAC, SK_IOC IoC, int Level);
+extern int SkPnmiSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void* pBuf,
+	unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
+extern int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void* pBuf,
+	unsigned int *pLen, SK_U32 NetIndex);
+extern int SkPnmiPreSetStruct(SK_AC *pAC, SK_IOC IoC, void* pBuf,
+	unsigned int *pLen, SK_U32 NetIndex);
+extern int SkPnmiSetStruct(SK_AC *pAC, SK_IOC IoC, void* pBuf,
+	unsigned int *pLen, SK_U32 NetIndex);
+extern int SkPnmiEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event,
+	SK_EVPARA Param);
+extern int SkPnmiGenIoctl(SK_AC *pAC, SK_IOC IoC, void * pBuf,
+	unsigned int * pLen, SK_U32 NetIndex);
+
+#endif
diff --git a/drivers/net/sk98lin/h/skgesirq.h b/drivers/net/sk98lin/h/skgesirq.h
new file mode 100644
index 0000000..3eec627
--- /dev/null
+++ b/drivers/net/sk98lin/h/skgesirq.h
@@ -0,0 +1,110 @@
+/******************************************************************************
+ *
+ * Name:	skgesirq.h
+ * Project:	Gigabit Ethernet Adapters, Common Modules
+ * Version:	$Revision: 1.30 $
+ * Date:	$Date: 2003/07/04 12:34:13 $
+ * Purpose:	SK specific Gigabit Ethernet special IRQ functions
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+#ifndef _INC_SKGESIRQ_H_
+#define _INC_SKGESIRQ_H_
+
+/* Define return codes of SkGePortCheckUp and CheckShort */
+#define	SK_HW_PS_NONE		0	/* No action needed */
+#define	SK_HW_PS_RESTART	1	/* Restart needed */
+#define	SK_HW_PS_LINK		2	/* Link Up actions needed */
+
+/*
+ * Define the Event the special IRQ/INI module can handle
+ */
+#define SK_HWEV_WATIM			1	/* Timeout for WA Errata #2 XMAC */
+#define SK_HWEV_PORT_START		2	/* Port Start Event by RLMT */
+#define SK_HWEV_PORT_STOP		3	/* Port Stop Event by RLMT */
+#define SK_HWEV_CLEAR_STAT		4	/* Clear Statistics by PNMI */
+#define SK_HWEV_UPDATE_STAT		5	/* Update Statistics by PNMI */
+#define SK_HWEV_SET_LMODE		6	/* Set Link Mode by PNMI */
+#define SK_HWEV_SET_FLOWMODE	7	/* Set Flow Control Mode by PNMI */
+#define SK_HWEV_SET_ROLE		8	/* Set Master/Slave (Role) by PNMI */
+#define SK_HWEV_SET_SPEED		9	/* Set Link Speed by PNMI */
+#define SK_HWEV_HALFDUP_CHK		10	/* Half Duplex Hangup Workaround */
+
+#define SK_WA_ACT_TIME		(5000000UL)	/* 5 sec */
+#define SK_WA_INA_TIME		(100000UL)	/* 100 msec */
+
+#define SK_HALFDUP_CHK_TIME	(10000UL)	/* 10 msec */
+
+/*
+ * Define the error numbers and messages
+ */
+#define SKERR_SIRQ_E001		(SK_ERRBASE_SIRQ+0)
+#define SKERR_SIRQ_E001MSG	"Unknown event"
+#define SKERR_SIRQ_E002		(SKERR_SIRQ_E001+1)
+#define SKERR_SIRQ_E002MSG	"Packet timeout RX1"
+#define SKERR_SIRQ_E003		(SKERR_SIRQ_E002+1)
+#define SKERR_SIRQ_E003MSG	"Packet timeout RX2"
+#define SKERR_SIRQ_E004		(SKERR_SIRQ_E003+1)
+#define SKERR_SIRQ_E004MSG	"MAC 1 not correctly initialized"
+#define SKERR_SIRQ_E005		(SKERR_SIRQ_E004+1)
+#define SKERR_SIRQ_E005MSG	"MAC 2 not correctly initialized"
+#define SKERR_SIRQ_E006		(SKERR_SIRQ_E005+1)
+#define SKERR_SIRQ_E006MSG	"CHECK failure R1"
+#define SKERR_SIRQ_E007		(SKERR_SIRQ_E006+1)
+#define SKERR_SIRQ_E007MSG	"CHECK failure R2"
+#define SKERR_SIRQ_E008		(SKERR_SIRQ_E007+1)
+#define SKERR_SIRQ_E008MSG	"CHECK failure XS1"
+#define SKERR_SIRQ_E009		(SKERR_SIRQ_E008+1)
+#define SKERR_SIRQ_E009MSG	"CHECK failure XA1"
+#define SKERR_SIRQ_E010		(SKERR_SIRQ_E009+1)
+#define SKERR_SIRQ_E010MSG	"CHECK failure XS2"
+#define SKERR_SIRQ_E011		(SKERR_SIRQ_E010+1)
+#define SKERR_SIRQ_E011MSG	"CHECK failure XA2"
+#define SKERR_SIRQ_E012		(SKERR_SIRQ_E011+1)
+#define SKERR_SIRQ_E012MSG	"unexpected IRQ Master error"
+#define SKERR_SIRQ_E013		(SKERR_SIRQ_E012+1)
+#define SKERR_SIRQ_E013MSG	"unexpected IRQ Status error"
+#define SKERR_SIRQ_E014		(SKERR_SIRQ_E013+1)
+#define SKERR_SIRQ_E014MSG	"Parity error on RAM (read)"
+#define SKERR_SIRQ_E015		(SKERR_SIRQ_E014+1)
+#define SKERR_SIRQ_E015MSG	"Parity error on RAM (write)"
+#define SKERR_SIRQ_E016		(SKERR_SIRQ_E015+1)
+#define SKERR_SIRQ_E016MSG	"Parity error MAC 1"
+#define SKERR_SIRQ_E017		(SKERR_SIRQ_E016+1)
+#define SKERR_SIRQ_E017MSG	"Parity error MAC 2"
+#define SKERR_SIRQ_E018		(SKERR_SIRQ_E017+1)
+#define SKERR_SIRQ_E018MSG	"Parity error RX 1"
+#define SKERR_SIRQ_E019		(SKERR_SIRQ_E018+1)
+#define SKERR_SIRQ_E019MSG	"Parity error RX 2"
+#define SKERR_SIRQ_E020		(SKERR_SIRQ_E019+1)
+#define SKERR_SIRQ_E020MSG	"MAC transmit FIFO underrun"
+#define SKERR_SIRQ_E021		(SKERR_SIRQ_E020+1)
+#define SKERR_SIRQ_E021MSG	"Spurious TWSI interrupt"
+#define SKERR_SIRQ_E022		(SKERR_SIRQ_E021+1)
+#define SKERR_SIRQ_E022MSG	"Cable pair swap error"
+#define SKERR_SIRQ_E023		(SKERR_SIRQ_E022+1)
+#define SKERR_SIRQ_E023MSG	"Auto-negotiation error"
+#define SKERR_SIRQ_E024		(SKERR_SIRQ_E023+1)
+#define SKERR_SIRQ_E024MSG	"FIFO overflow error"
+#define SKERR_SIRQ_E025		(SKERR_SIRQ_E024+1)
+#define SKERR_SIRQ_E025MSG	"2 Pair Downshift detected"
+
+extern void SkGeSirqIsr(SK_AC *pAC, SK_IOC IoC, SK_U32 Istatus);
+extern int  SkGeSirqEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Para);
+extern void SkHWLinkDown(SK_AC *pAC, SK_IOC IoC, int Port);
+
+#endif	/* _INC_SKGESIRQ_H_ */
diff --git a/drivers/net/sk98lin/h/ski2c.h b/drivers/net/sk98lin/h/ski2c.h
new file mode 100644
index 0000000..6a63f4a
--- /dev/null
+++ b/drivers/net/sk98lin/h/ski2c.h
@@ -0,0 +1,174 @@
+/******************************************************************************
+ *
+ * Name:	ski2c.h
+ * Project:	Gigabit Ethernet Adapters, TWSI-Module
+ * Version:	$Revision: 1.35 $
+ * Date:	$Date: 2003/10/20 09:06:30 $
+ * Purpose:	Defines to access Voltage and Temperature Sensor
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/*
+ * SKI2C.H	contains all I2C specific defines
+ */
+
+#ifndef _SKI2C_H_
+#define _SKI2C_H_
+
+typedef struct  s_Sensor SK_SENSOR;
+
+#include "h/skgei2c.h"
+
+/*
+ * Define the I2C events.
+ */
+#define SK_I2CEV_IRQ	1	/* IRQ happened Event */
+#define SK_I2CEV_TIM	2	/* Timeout event */
+#define SK_I2CEV_CLEAR	3	/* Clear MIB Values */
+
+/*
+ * Define READ and WRITE Constants.
+ */
+#define I2C_READ	0
+#define I2C_WRITE	1
+#define I2C_BURST	1
+#define I2C_SINGLE	0
+
+#define SKERR_I2C_E001		(SK_ERRBASE_I2C+0)
+#define SKERR_I2C_E001MSG	"Sensor index unknown"
+#define SKERR_I2C_E002		(SKERR_I2C_E001+1)
+#define SKERR_I2C_E002MSG	"TWSI: transfer does not complete"
+#define SKERR_I2C_E003		(SKERR_I2C_E002+1)
+#define SKERR_I2C_E003MSG	"LM80: NAK on device send"
+#define SKERR_I2C_E004		(SKERR_I2C_E003+1)
+#define SKERR_I2C_E004MSG	"LM80: NAK on register send"
+#define SKERR_I2C_E005		(SKERR_I2C_E004+1)
+#define SKERR_I2C_E005MSG	"LM80: NAK on device (2) send"
+#define SKERR_I2C_E006		(SKERR_I2C_E005+1)
+#define SKERR_I2C_E006MSG	"Unknown event"
+#define SKERR_I2C_E007		(SKERR_I2C_E006+1)
+#define SKERR_I2C_E007MSG	"LM80 read out of state"
+#define SKERR_I2C_E008		(SKERR_I2C_E007+1)
+#define SKERR_I2C_E008MSG	"Unexpected sensor read completed"
+#define SKERR_I2C_E009		(SKERR_I2C_E008+1)
+#define SKERR_I2C_E009MSG	"WARNING: temperature sensor out of range"
+#define SKERR_I2C_E010		(SKERR_I2C_E009+1)
+#define SKERR_I2C_E010MSG	"WARNING: voltage sensor out of range"
+#define SKERR_I2C_E011		(SKERR_I2C_E010+1)
+#define SKERR_I2C_E011MSG	"ERROR: temperature sensor out of range"
+#define SKERR_I2C_E012		(SKERR_I2C_E011+1)
+#define SKERR_I2C_E012MSG	"ERROR: voltage sensor out of range"
+#define SKERR_I2C_E013		(SKERR_I2C_E012+1)
+#define SKERR_I2C_E013MSG	"ERROR: couldn't init sensor"
+#define SKERR_I2C_E014		(SKERR_I2C_E013+1)
+#define SKERR_I2C_E014MSG	"WARNING: fan sensor out of range"
+#define SKERR_I2C_E015		(SKERR_I2C_E014+1)
+#define SKERR_I2C_E015MSG	"ERROR: fan sensor out of range"
+#define SKERR_I2C_E016		(SKERR_I2C_E015+1)
+#define SKERR_I2C_E016MSG	"TWSI: active transfer does not complete"
+
+/*
+ * Define Timeout values
+ */
+#define SK_I2C_TIM_LONG		2000000L	/* 2 seconds */
+#define SK_I2C_TIM_SHORT	 100000L	/* 100 milliseconds */
+#define SK_I2C_TIM_WATCH	1000000L	/* 1 second */
+
+/*
+ * Define trap and error log hold times
+ */
+#ifndef	SK_SEN_ERR_TR_HOLD
+#define SK_SEN_ERR_TR_HOLD		(4*SK_TICKS_PER_SEC)
+#endif
+#ifndef	SK_SEN_ERR_LOG_HOLD
+#define SK_SEN_ERR_LOG_HOLD		(60*SK_TICKS_PER_SEC)
+#endif
+#ifndef	SK_SEN_WARN_TR_HOLD
+#define SK_SEN_WARN_TR_HOLD		(15*SK_TICKS_PER_SEC)
+#endif
+#ifndef	SK_SEN_WARN_LOG_HOLD
+#define SK_SEN_WARN_LOG_HOLD	(15*60*SK_TICKS_PER_SEC)
+#endif
+
+/*
+ * Defines for SenType
+ */
+#define SK_SEN_UNKNOWN	0
+#define SK_SEN_TEMP		1
+#define SK_SEN_VOLT		2
+#define SK_SEN_FAN		3
+
+/*
+ * Define for the SenErrorFlag
+ */
+#define SK_SEN_ERR_NOT_PRESENT	0	/* Error Flag: Sensor not present */
+#define SK_SEN_ERR_OK			1	/* Error Flag: O.K. */
+#define SK_SEN_ERR_WARN			2	/* Error Flag: Warning */
+#define SK_SEN_ERR_ERR			3	/* Error Flag: Error */
+#define SK_SEN_ERR_FAULTY		4	/* Error Flag: Faulty */
+
+/*
+ * Define the Sensor struct
+ */
+struct	s_Sensor {
+	char	*SenDesc;			/* Description */
+	int		SenType;			/* Voltage or Temperature */
+	SK_I32	SenValue;			/* Current value of the sensor */
+	SK_I32	SenThreErrHigh;		/* High error Threshhold of this sensor */
+	SK_I32	SenThreWarnHigh;	/* High warning Threshhold of this sensor */
+	SK_I32	SenThreErrLow;		/* Lower error Threshold of the sensor */
+	SK_I32	SenThreWarnLow;		/* Lower warning Threshold of the sensor */
+	int		SenErrFlag;			/* Sensor indicated an error */
+	SK_BOOL	SenInit;			/* Is sensor initialized ? */
+	SK_U64	SenErrCts;			/* Error trap counter */
+	SK_U64	SenWarnCts;			/* Warning trap counter */
+	SK_U64	SenBegErrTS;		/* Begin error timestamp */
+	SK_U64	SenBegWarnTS;		/* Begin warning timestamp */
+	SK_U64	SenLastErrTrapTS;	/* Last error trap timestamp */
+	SK_U64	SenLastErrLogTS;	/* Last error log timestamp */
+	SK_U64	SenLastWarnTrapTS;	/* Last warning trap timestamp */
+	SK_U64	SenLastWarnLogTS;	/* Last warning log timestamp */
+	int		SenState;			/* Sensor State (see HW specific include) */
+	int		(*SenRead)(SK_AC *pAC, SK_IOC IoC, struct s_Sensor *pSen);
+								/* Sensors read function */
+	SK_U16	SenReg;				/* Register Address for this sensor */
+	SK_U8	SenDev;				/* Device Selection for this sensor */
+};
+
+typedef	struct	s_I2c {
+	SK_SENSOR	SenTable[SK_MAX_SENSORS];	/* Sensor Table */
+	int			CurrSens;	/* Which sensor is currently queried */
+	int			MaxSens;	/* Max. number of sensors */
+	int			TimerMode;	/* Use the timer also to watch the state machine */
+	int			InitLevel;	/* Initialized Level */
+#ifndef SK_DIAG
+	int			DummyReads;	/* Number of non-checked dummy reads */
+	SK_TIMER	SenTimer;	/* Sensors timer */
+#endif /* !SK_DIAG */
+} SK_I2C;
+
+extern int SkI2cInit(SK_AC *pAC, SK_IOC IoC, int Level);
+#ifdef SK_DIAG
+extern	SK_U32 SkI2cRead(SK_AC *pAC, SK_IOC IoC, int Dev, int Size, int Reg,
+						 int Burst);
+#else /* !SK_DIAG */
+extern int SkI2cEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Para);
+extern void SkI2cWaitIrq(SK_AC *pAC, SK_IOC IoC);
+extern void SkI2cIsr(SK_AC *pAC, SK_IOC IoC);
+#endif /* !SK_DIAG */
+#endif /* n_SKI2C_H */
+
diff --git a/drivers/net/sk98lin/h/skqueue.h b/drivers/net/sk98lin/h/skqueue.h
new file mode 100644
index 0000000..2ec40d4
--- /dev/null
+++ b/drivers/net/sk98lin/h/skqueue.h
@@ -0,0 +1,94 @@
+/******************************************************************************
+ *
+ * Name:	skqueue.h
+ * Project:	Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version:	$Revision: 1.16 $
+ * Date:	$Date: 2003/09/16 12:50:32 $
+ * Purpose:	Defines for the Event queue
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/*
+ * SKQUEUE.H	contains all defines and types for the event queue
+ */
+
+#ifndef _SKQUEUE_H_
+#define _SKQUEUE_H_
+
+
+/*
+ * define the event classes to be served
+ */
+#define	SKGE_DRV	1	/* Driver Event Class */
+#define	SKGE_RLMT	2	/* RLMT Event Class */
+#define	SKGE_I2C	3	/* I2C Event Class */
+#define	SKGE_PNMI	4	/* PNMI Event Class */
+#define	SKGE_CSUM	5	/* Checksum Event Class */
+#define	SKGE_HWAC	6	/* Hardware Access Event Class */
+
+#define	SKGE_SWT	9	/* Software Timer Event Class */
+#define	SKGE_LACP	10	/* LACP Aggregation Event Class */
+#define	SKGE_RSF	11	/* RSF Aggregation Event Class */
+#define	SKGE_MARKER	12	/* MARKER Aggregation Event Class */
+#define	SKGE_FD		13	/* FD Distributor Event Class */
+
+/*
+ * define event queue as circular buffer
+ */
+#define SK_MAX_EVENT	64
+
+/*
+ * Parameter union for the Para stuff
+ */
+typedef	union u_EvPara {
+	void	*pParaPtr;	/* Parameter Pointer */
+	SK_U64	Para64;		/* Parameter 64bit version */
+	SK_U32	Para32[2];	/* Parameter Array of 32bit parameters */
+} SK_EVPARA;
+
+/*
+ * Event Queue
+ *	skqueue.c
+ * events are class/value pairs
+ *	class	is addressee, e.g. RLMT, PNMI etc.
+ *	value	is command, e.g. line state change, ring op change etc.
+ */
+typedef	struct s_EventElem {
+	SK_U32		Class;			/* Event class */
+	SK_U32		Event;			/* Event value */
+	SK_EVPARA	Para;			/* Event parameter */
+} SK_EVENTELEM;
+
+typedef	struct s_Queue {
+	SK_EVENTELEM	EvQueue[SK_MAX_EVENT];
+	SK_EVENTELEM	*EvPut;
+	SK_EVENTELEM	*EvGet;
+} SK_QUEUE;
+
+extern	void SkEventInit(SK_AC *pAC, SK_IOC Ioc, int Level);
+extern	void SkEventQueue(SK_AC *pAC, SK_U32 Class, SK_U32 Event,
+	SK_EVPARA Para);
+extern	int SkEventDispatcher(SK_AC *pAC, SK_IOC Ioc);
+
+
+/* Define Error Numbers and messages */
+#define	SKERR_Q_E001	(SK_ERRBASE_QUEUE+0)
+#define	SKERR_Q_E001MSG	"Event queue overflow"
+#define	SKERR_Q_E002	(SKERR_Q_E001+1)
+#define	SKERR_Q_E002MSG	"Undefined event class"
+#endif	/* _SKQUEUE_H_ */
+
diff --git a/drivers/net/sk98lin/h/skrlmt.h b/drivers/net/sk98lin/h/skrlmt.h
new file mode 100644
index 0000000..ca75dfd
--- /dev/null
+++ b/drivers/net/sk98lin/h/skrlmt.h
@@ -0,0 +1,438 @@
+/******************************************************************************
+ *
+ * Name:	skrlmt.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.37 $
+ * Date:	$Date: 2003/04/15 09:43:43 $
+ * Purpose:	Header file for Redundant Link ManagemenT.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This is the header file for Redundant Link ManagemenT.
+ *
+ * Include File Hierarchy:
+ *
+ *	"skdrv1st.h"
+ *	...
+ *	"sktypes.h"
+ *	"skqueue.h"
+ *	"skaddr.h"
+ *	"skrlmt.h"
+ *	...
+ *	"skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKRLMT_H
+#define __INC_SKRLMT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif	/* cplusplus */
+
+/* defines ********************************************************************/
+
+#define	SK_RLMT_NET_DOWN_TEMP	1	/* NET_DOWN due to last port down. */
+#define	SK_RLMT_NET_DOWN_FINAL	2	/* NET_DOWN due to RLMT_STOP. */
+
+/* ----- Default queue sizes - must be multiples of 8 KB ----- */
+
+/* Less than 8 KB free in RX queue => pause frames. */
+#define SK_RLMT_STANDBY_QRXSIZE	128	/* Size of rx standby queue in KB. */
+#define SK_RLMT_STANDBY_QXASIZE	32	/* Size of async standby queue in KB. */
+#define SK_RLMT_STANDBY_QXSSIZE	0	/* Size of sync standby queue in KB. */
+
+#define SK_RLMT_MAX_TX_BUF_SIZE	60	/* Maximum RLMT transmit size. */
+
+/* ----- PORT states ----- */
+
+#define SK_RLMT_PS_INIT			0	/* Port state: Init. */
+#define SK_RLMT_PS_LINK_DOWN	1	/* Port state: Link down. */
+#define SK_RLMT_PS_DOWN			2	/* Port state: Port down. */
+#define SK_RLMT_PS_GOING_UP		3	/* Port state: Going up. */
+#define SK_RLMT_PS_UP			4	/* Port state: Up. */
+
+/* ----- RLMT states ----- */
+
+#define SK_RLMT_RS_INIT			0	/* RLMT state: Init. */
+#define SK_RLMT_RS_NET_DOWN		1	/* RLMT state: Net down. */
+#define SK_RLMT_RS_NET_UP		2	/* RLMT state: Net up. */
+
+/* ----- PORT events ----- */
+
+#define SK_RLMT_LINK_UP			1001	/* Link came up. */
+#define SK_RLMT_LINK_DOWN		1002	/* Link went down. */
+#define SK_RLMT_PORT_ADDR		1003	/* Port address changed. */
+
+/* ----- RLMT events ----- */
+
+#define SK_RLMT_START			2001	/* Start RLMT. */
+#define SK_RLMT_STOP			2002	/* Stop RLMT. */
+#define SK_RLMT_PACKET_RECEIVED	2003	/* Packet was received for RLMT. */
+#define SK_RLMT_STATS_CLEAR		2004	/* Clear statistics. */
+#define SK_RLMT_STATS_UPDATE	2005	/* Update statistics. */
+#define SK_RLMT_PREFPORT_CHANGE	2006	/* Change preferred port. */
+#define SK_RLMT_MODE_CHANGE		2007	/* New RlmtMode. */
+#define SK_RLMT_SET_NETS		2008	/* Number of Nets (1 or 2). */
+
+/* ----- RLMT mode bits ----- */
+
+/*
+ * CAUTION:	These defines are private to RLMT.
+ *			Please use the RLMT mode defines below.
+ */
+
+#define SK_RLMT_CHECK_LINK		  1		/* Check Link. */
+#define SK_RLMT_CHECK_LOC_LINK	  2		/* Check other link on same adapter. */
+#define SK_RLMT_CHECK_SEG		  4		/* Check segmentation. */
+
+#ifndef RLMT_CHECK_REMOTE
+#define SK_RLMT_CHECK_OTHERS	SK_RLMT_CHECK_LOC_LINK
+#else	/* RLMT_CHECK_REMOTE */
+#define SK_RLMT_CHECK_REM_LINK	  8		/* Check link(s) on other adapter(s). */
+#define SK_RLMT_MAX_REMOTE_PORTS_CHECKED	3
+#define SK_RLMT_CHECK_OTHERS	\
+		(SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_REM_LINK)
+#endif	/* RLMT_CHECK_REMOTE */
+
+#ifndef SK_RLMT_ENABLE_TRANSPARENT
+#define SK_RLMT_TRANSPARENT		  0		/* RLMT transparent - inactive. */
+#else	/* SK_RLMT_ENABLE_TRANSPARENT */
+#define SK_RLMT_TRANSPARENT		128		/* RLMT transparent. */
+#endif	/* SK_RLMT_ENABLE_TRANSPARENT */
+
+/* ----- RLMT modes ----- */
+
+/* Check Link State. */
+#define SK_RLMT_MODE_CLS	(SK_RLMT_CHECK_LINK)
+
+/* Check Local Ports: check other links on the same adapter. */
+#define SK_RLMT_MODE_CLP	(SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK)
+
+/* Check Local Ports and Segmentation Status. */
+#define SK_RLMT_MODE_CLPSS	\
+		(SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_SEG)
+
+#ifdef RLMT_CHECK_REMOTE
+/* Check Local and Remote Ports: check links (local or remote). */
+	Name of define TBD!
+#define SK_RLMT_MODE_CRP	\
+		(SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | SK_RLMT_CHECK_REM_LINK)
+
+/* Check Local and Remote Ports and Segmentation Status. */
+	Name of define TBD!
+#define SK_RLMT_MODE_CRPSS	\
+		(SK_RLMT_CHECK_LINK | SK_RLMT_CHECK_LOC_LINK | \
+		SK_RLMT_CHECK_REM_LINK | SK_RLMT_CHECK_SEG)
+#endif	/* RLMT_CHECK_REMOTE */
+
+/* ----- RLMT lookahead result bits ----- */
+
+#define SK_RLMT_RX_RLMT			1	/* Give packet to RLMT. */
+#define SK_RLMT_RX_PROTOCOL		2	/* Give packet to protocol. */
+
+/* Macros */
+
+#if 0
+SK_AC		*pAC		/* adapter context */
+SK_U32		PortNum		/* receiving port */
+unsigned	PktLen		/* received packet's length */
+SK_BOOL		IsBc		/* Flag: packet is broadcast */
+unsigned	*pOffset	/* offs. of bytes to present to SK_RLMT_LOOKAHEAD */
+unsigned	*pNumBytes	/* #Bytes to present to SK_RLMT_LOOKAHEAD */
+#endif	/* 0 */
+
+#define SK_RLMT_PRE_LOOKAHEAD(pAC,PortNum,PktLen,IsBc,pOffset,pNumBytes) { \
+	SK_AC	*_pAC; \
+	SK_U32	_PortNum; \
+	_pAC = (pAC); \
+	_PortNum = (SK_U32)(PortNum); \
+	/* _pAC->Rlmt.Port[_PortNum].PacketsRx++; */ \
+	_pAC->Rlmt.Port[_PortNum].PacketsPerTimeSlot++; \
+    if (_pAC->Rlmt.RlmtOff) { \
+		*(pNumBytes) = 0; \
+    } \
+    else {\
+        if ((_pAC->Rlmt.Port[_PortNum].Net->RlmtMode & SK_RLMT_TRANSPARENT) != 0) { \
+    		*(pNumBytes) = 0; \
+    	} \
+    	else if (IsBc) { \
+    		if (_pAC->Rlmt.Port[_PortNum].Net->RlmtMode != SK_RLMT_MODE_CLS) { \
+    			*(pNumBytes) = 6; \
+    			*(pOffset) = 6; \
+    		} \
+    		else { \
+    			*(pNumBytes) = 0; \
+    		} \
+    	} \
+    	else { \
+    		if ((PktLen) > SK_RLMT_MAX_TX_BUF_SIZE) { \
+    			/* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
+    			*(pNumBytes) = 0; \
+    		} \
+    		else { \
+    			*(pNumBytes) = 6; \
+    			*(pOffset) = 0; \
+    		} \
+    	} \
+    } \
+}
+
+#if 0
+SK_AC		*pAC		/* adapter context */
+SK_U32		PortNum		/* receiving port */
+SK_U8		*pLaPacket,	/* received packet's data (points to pOffset) */
+SK_BOOL		IsBc		/* Flag: packet is broadcast */
+SK_BOOL		IsMc		/* Flag: packet is multicast */
+unsigned	*pForRlmt	/* Result: bits SK_RLMT_RX_RLMT, SK_RLMT_RX_PROTOCOL */
+SK_RLMT_LOOKAHEAD() expects *pNumBytes from
+packet offset *pOffset (s.a.) at *pLaPacket.
+
+If you use SK_RLMT_LOOKAHEAD in a path where you already know if the packet is
+BC, MC, or UC, you should use constants for IsBc and IsMc, so that your compiler
+can trash unneeded parts of the if construction.
+#endif	/* 0 */
+
+#define SK_RLMT_LOOKAHEAD(pAC,PortNum,pLaPacket,IsBc,IsMc,pForRlmt) { \
+	SK_AC	*_pAC; \
+	SK_U32	_PortNum; \
+	SK_U8	*_pLaPacket; \
+	_pAC = (pAC); \
+	_PortNum = (SK_U32)(PortNum); \
+	_pLaPacket = (SK_U8 *)(pLaPacket); \
+	if (IsBc) {\
+		if (!SK_ADDR_EQUAL(_pLaPacket, _pAC->Addr.Net[_pAC->Rlmt.Port[ \
+			_PortNum].Net->NetNumber].CurrentMacAddress.a)) { \
+			_pAC->Rlmt.Port[_PortNum].BcTimeStamp = SkOsGetTime(_pAC); \
+			_pAC->Rlmt.CheckSwitch = SK_TRUE; \
+		} \
+		/* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
+		*(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+	} \
+	else if (IsMc) { \
+		if (SK_ADDR_EQUAL(_pLaPacket, BridgeMcAddr.a)) { \
+			_pAC->Rlmt.Port[_PortNum].BpduPacketsPerTimeSlot++; \
+			if (_pAC->Rlmt.Port[_PortNum].Net->RlmtMode & SK_RLMT_CHECK_SEG) { \
+				*(pForRlmt) = SK_RLMT_RX_RLMT | SK_RLMT_RX_PROTOCOL; \
+			} \
+			else { \
+				*(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+			} \
+		} \
+		else if (SK_ADDR_EQUAL(_pLaPacket, SkRlmtMcAddr.a)) { \
+			*(pForRlmt) = SK_RLMT_RX_RLMT; \
+		} \
+		else { \
+			/* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
+			*(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+		} \
+	} \
+	else { \
+		if (SK_ADDR_EQUAL( \
+			_pLaPacket, \
+			_pAC->Addr.Port[_PortNum].CurrentMacAddress.a)) { \
+			*(pForRlmt) = SK_RLMT_RX_RLMT; \
+		} \
+		else { \
+			/* _pAC->Rlmt.Port[_PortNum].DataPacketsPerTimeSlot++; */ \
+			*(pForRlmt) = SK_RLMT_RX_PROTOCOL; \
+		} \
+	} \
+}
+
+#ifdef SK_RLMT_FAST_LOOKAHEAD
+Error: SK_RLMT_FAST_LOOKAHEAD no longer used. Use new macros for lookahead.
+#endif	/* SK_RLMT_FAST_LOOKAHEAD */
+#ifdef SK_RLMT_SLOW_LOOKAHEAD
+Error: SK_RLMT_SLOW_LOOKAHEAD no longer used. Use new macros for lookahead.
+#endif	/* SK_RLMT_SLOW_LOOKAHEAD */
+
+/* typedefs *******************************************************************/
+
+#ifdef SK_RLMT_MBUF_PRIVATE
+typedef struct s_RlmtMbuf {
+	some content
+} SK_RLMT_MBUF;
+#endif	/* SK_RLMT_MBUF_PRIVATE */
+
+
+#ifdef SK_LA_INFO
+typedef struct s_Rlmt_PacketInfo {
+	unsigned	PacketLength;			/* Length of packet. */
+	unsigned	PacketType;				/* Directed/Multicast/Broadcast. */
+} SK_RLMT_PINFO;
+#endif	/* SK_LA_INFO */
+
+
+typedef struct s_RootId {
+	SK_U8		Id[8];					/* Root Bridge Id. */
+} SK_RLMT_ROOT_ID;
+
+
+typedef struct s_port {
+	SK_MAC_ADDR	CheckAddr;
+	SK_BOOL		SuspectTx;
+} SK_PORT_CHECK;
+
+
+typedef struct s_RlmtNet SK_RLMT_NET;
+
+
+typedef struct s_RlmtPort {
+
+/* ----- Public part (read-only) ----- */
+
+	SK_U8			PortState;				/* Current state of this port. */
+
+	/* For PNMI */
+	SK_BOOL			LinkDown;
+	SK_BOOL			PortDown;
+	SK_U8			Align01;
+
+	SK_U32			PortNumber;				/* Number of port on adapter. */
+	SK_RLMT_NET *	Net;					/* Net port belongs to. */
+
+	SK_U64			TxHelloCts;
+	SK_U64			RxHelloCts;
+	SK_U64			TxSpHelloReqCts;
+	SK_U64			RxSpHelloCts;
+
+/* ----- Private part ----- */
+
+/*	SK_U64			PacketsRx; */				/* Total packets received. */
+	SK_U32			PacketsPerTimeSlot;		/* Packets rxed between TOs. */
+/*	SK_U32			DataPacketsPerTimeSlot; */	/* Data packets ... */
+	SK_U32			BpduPacketsPerTimeSlot;	/* BPDU packets rxed in TS. */
+	SK_U64			BcTimeStamp;			/* Time of last BC receive. */
+	SK_U64			GuTimeStamp;			/* Time of entering GOING_UP. */
+
+	SK_TIMER		UpTimer;				/* Timer struct Link/Port up. */
+	SK_TIMER		DownRxTimer;			/* Timer struct down rx. */
+	SK_TIMER		DownTxTimer;			/* Timer struct down tx. */
+
+	SK_U32			CheckingState;			/* Checking State. */
+
+	SK_ADDR_PORT *	AddrPort;
+
+	SK_U8			Random[4];				/* Random value. */
+	unsigned		PortsChecked;			/* #ports checked. */
+	unsigned		PortsSuspect;			/* #ports checked that are s. */
+	SK_PORT_CHECK	PortCheck[1];
+/*	SK_PORT_CHECK	PortCheck[SK_MAX_MACS - 1]; */
+
+	SK_BOOL			PortStarted;			/* Port is started. */
+	SK_BOOL			PortNoRx;				/* NoRx for >= 1 time slot. */
+	SK_BOOL			RootIdSet;
+	SK_RLMT_ROOT_ID	Root;					/* Root Bridge Id. */
+} SK_RLMT_PORT;
+
+
+struct s_RlmtNet {
+
+/* ----- Public part (read-only) ----- */
+
+	SK_U32			NetNumber;			/* Number of net. */
+
+	SK_RLMT_PORT *	Port[SK_MAX_MACS];	/* Ports that belong to this net. */
+	SK_U32			NumPorts;			/* Number of ports. */
+	SK_U32			PrefPort;			/* Preferred port. */
+
+	/* For PNMI */
+
+	SK_U32			ChgBcPrio;			/* Change Priority of last broadcast received */
+	SK_U32			RlmtMode;			/* Check ... */
+	SK_U32			ActivePort;			/* Active port. */
+	SK_U32			Preference;		/* 0xFFFFFFFF: Automatic. */
+
+	SK_U8			RlmtState;			/* Current RLMT state. */
+
+/* ----- Private part ----- */
+	SK_BOOL			RootIdSet;
+	SK_U16			Align01;
+
+	int				LinksUp;			/* #Links up. */
+	int				PortsUp;			/* #Ports up. */
+	SK_U32			TimeoutValue;		/* RLMT timeout value. */
+
+	SK_U32			CheckingState;		/* Checking State. */
+	SK_RLMT_ROOT_ID	Root;				/* Root Bridge Id. */
+
+	SK_TIMER		LocTimer;			/* Timer struct. */
+	SK_TIMER		SegTimer;			/* Timer struct. */
+};
+
+
+typedef struct s_Rlmt {
+
+/* ----- Public part (read-only) ----- */
+
+	SK_U32			NumNets;			/* Number of nets. */
+	SK_U32			NetsStarted;		/* Number of nets started. */
+	SK_RLMT_NET		Net[SK_MAX_NETS];	/* Array of available nets. */
+	SK_RLMT_PORT	Port[SK_MAX_MACS];	/* Array of available ports. */
+
+/* ----- Private part ----- */
+	SK_BOOL			CheckSwitch;
+	SK_BOOL			RlmtOff;            /* set to zero if the Mac addresses 
+                                           are equal or the second one 
+                                           is zero */
+	SK_U16			Align01;
+
+} SK_RLMT;
+
+
+extern	SK_MAC_ADDR	BridgeMcAddr;
+extern	SK_MAC_ADDR	SkRlmtMcAddr;
+
+/* function prototypes ********************************************************/
+
+
+#ifndef SK_KR_PROTO
+
+/* Functions provided by SkRlmt */
+
+/* ANSI/C++ compliant function prototypes */
+
+extern	void	SkRlmtInit(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	int		Level);
+
+extern	int	SkRlmtEvent(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	SK_U32		Event,
+	SK_EVPARA	Para);
+
+#else	/* defined(SK_KR_PROTO) */
+
+/* Non-ANSI/C++ compliant function prototypes */
+
+#error KR-style function prototypes are not yet provided.
+
+#endif	/* defined(SK_KR_PROTO)) */
+
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_SKRLMT_H */
diff --git a/drivers/net/sk98lin/h/sktimer.h b/drivers/net/sk98lin/h/sktimer.h
new file mode 100644
index 0000000..04e6d7c
--- /dev/null
+++ b/drivers/net/sk98lin/h/sktimer.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ * Name:	sktimer.h
+ * Project:	Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version:	$Revision: 1.11 $
+ * Date:	$Date: 2003/09/16 12:58:18 $
+ * Purpose:	Defines for the timer functions
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/*
+ * SKTIMER.H	contains all defines and types for the timer functions
+ */
+
+#ifndef	_SKTIMER_H_
+#define _SKTIMER_H_
+
+#include "h/skqueue.h"
+
+/*
+ * SK timer
+ * - needed wherever a timer is used. Put this in your data structure
+ *   wherever you want.
+ */
+typedef	struct s_Timer SK_TIMER;
+
+struct s_Timer {
+	SK_TIMER	*TmNext;	/* linked list */
+	SK_U32		TmClass;	/* Timer Event class */
+	SK_U32		TmEvent;	/* Timer Event value */
+	SK_EVPARA	TmPara;		/* Timer Event parameter */
+	SK_U32		TmDelta;	/* delta time */
+	int			TmActive;	/* flag: active/inactive */
+};
+
+/*
+ * Timer control struct.
+ * - use in Adapters context name pAC->Tim
+ */
+typedef	struct s_TimCtrl {
+	SK_TIMER	*StQueue;	/* Head of Timer queue */
+} SK_TIMCTRL;
+
+extern void SkTimerInit(SK_AC *pAC, SK_IOC Ioc, int Level);
+extern void SkTimerStop(SK_AC *pAC, SK_IOC Ioc, SK_TIMER *pTimer);
+extern void SkTimerStart(SK_AC *pAC, SK_IOC Ioc, SK_TIMER *pTimer,
+	SK_U32 Time, SK_U32 Class, SK_U32 Event, SK_EVPARA Para);
+extern void SkTimerDone(SK_AC *pAC, SK_IOC Ioc);
+#endif	/* _SKTIMER_H_ */
diff --git a/drivers/net/sk98lin/h/sktypes.h b/drivers/net/sk98lin/h/sktypes.h
new file mode 100644
index 0000000..40edc96
--- /dev/null
+++ b/drivers/net/sk98lin/h/sktypes.h
@@ -0,0 +1,69 @@
+/******************************************************************************
+ *
+ * Name:	sktypes.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.2 $
+ * Date:	$Date: 2003/10/07 08:16:51 $
+ * Purpose:	Define data types for Linux
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+ 
+/******************************************************************************
+ *
+ * Description:
+ *
+ * In this file, all data types that are needed by the common modules
+ * are mapped to Linux data types.
+ * 
+ *
+ * Include File Hierarchy:
+ *
+ *
+ ******************************************************************************/
+
+#ifndef __INC_SKTYPES_H
+#define __INC_SKTYPES_H
+
+
+/* defines *******************************************************************/
+
+/*
+ * Data types with a specific size. 'I' = signed, 'U' = unsigned.
+ */
+#define SK_I8	s8
+#define SK_U8	u8
+#define SK_I16	s16
+#define SK_U16	u16
+#define SK_I32	s32
+#define SK_U32	u32
+#define SK_I64	s64
+#define SK_U64	u64
+
+#define SK_UPTR	ulong		/* casting pointer <-> integral */
+
+/*
+* Boolean type.
+*/
+#define SK_BOOL		SK_U8
+#define SK_FALSE	0
+#define SK_TRUE		(!SK_FALSE)
+
+/* typedefs *******************************************************************/
+
+/* function prototypes ********************************************************/
+
+#endif	/* __INC_SKTYPES_H */
diff --git a/drivers/net/sk98lin/h/skversion.h b/drivers/net/sk98lin/h/skversion.h
new file mode 100644
index 0000000..a1a7294
--- /dev/null
+++ b/drivers/net/sk98lin/h/skversion.h
@@ -0,0 +1,38 @@
+/******************************************************************************
+ *
+ * Name:	version.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.5 $
+ * Date:	$Date: 2003/10/07 08:16:51 $
+ * Purpose:	SK specific Error log support
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+#ifdef	lint
+static const char SysKonnectFileId[] = "@(#) (C) SysKonnect GmbH.";
+static const char SysKonnectBuildNumber[] =
+	"@(#)SK-BUILD: 6.23 PL: 01"; 
+#endif	/* !defined(lint) */
+
+#define BOOT_STRING	"sk98lin: Network Device Driver v6.23\n" \
+			"(C)Copyright 1999-2004 Marvell(R)."
+
+#define VER_STRING	"6.23"
+#define DRIVER_FILE_NAME	"sk98lin"
+#define DRIVER_REL_DATE		"Feb-13-2004"
+
+
diff --git a/drivers/net/sk98lin/h/skvpd.h b/drivers/net/sk98lin/h/skvpd.h
new file mode 100644
index 0000000..fdd9e48
--- /dev/null
+++ b/drivers/net/sk98lin/h/skvpd.h
@@ -0,0 +1,248 @@
+/******************************************************************************
+ *
+ * Name:	skvpd.h
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.15 $
+ * Date:	$Date: 2003/01/13 10:39:38 $
+ * Purpose:	Defines and Macros for VPD handling
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/*
+ * skvpd.h	contains Diagnostic specific defines for VPD handling
+ */
+
+#ifndef __INC_SKVPD_H_
+#define __INC_SKVPD_H_
+
+/*
+ * Define Resource Type Identifiers and VPD keywords
+ */
+#define	RES_ID		0x82	/* Resource Type ID String (Product Name) */
+#define RES_VPD_R	0x90	/* start of VPD read only area */
+#define RES_VPD_W	0x91	/* start of VPD read/write area */
+#define RES_END		0x78	/* Resource Type End Tag */
+
+#ifndef VPD_NAME
+#define VPD_NAME	"Name"	/* Product Name, VPD name of RES_ID */
+#endif	/* VPD_NAME */
+#define VPD_PN		"PN"	/* Adapter Part Number */
+#define	VPD_EC		"EC"	/* Adapter Engineering Level */
+#define VPD_MN		"MN"	/* Manufacture ID */
+#define VPD_SN		"SN"	/* Serial Number */
+#define VPD_CP		"CP"	/* Extended Capability */
+#define VPD_RV		"RV"	/* Checksum and Reserved */
+#define	VPD_YA		"YA"	/* Asset Tag Identifier */
+#define VPD_VL		"VL"	/* First Error Log Message (SK specific) */
+#define VPD_VF		"VF"	/* Second Error Log Message (SK specific) */
+#define VPD_RW		"RW"	/* Remaining Read / Write Area */
+
+/* 'type' values for vpd_setup_para() */
+#define VPD_RO_KEY	1	/* RO keys are "PN", "EC", "MN", "SN", "RV" */
+#define VPD_RW_KEY	2	/* RW keys are "Yx", "Vx", and "RW" */
+
+/* 'op' values for vpd_setup_para() */
+#define	ADD_KEY		1	/* add the key at the pos "RV" or "RW" */
+#define OWR_KEY		2	/* overwrite key if already exists */
+
+/*
+ * Define READ and WRITE Constants.
+ */
+
+#define VPD_DEV_ID_GENESIS 	0x4300
+
+#define	VPD_SIZE_YUKON		256
+#define	VPD_SIZE_GENESIS	512
+#define	VPD_SIZE			512
+#define VPD_READ	0x0000
+#define VPD_WRITE	0x8000
+
+#define VPD_STOP(pAC,IoC)	VPD_OUT16(pAC,IoC,PCI_VPD_ADR_REG,VPD_WRITE)
+
+#define VPD_GET_RES_LEN(p)	((unsigned int) \
+					(* (SK_U8 *)&(p)[1]) |\
+					((* (SK_U8 *)&(p)[2]) << 8))
+#define VPD_GET_VPD_LEN(p)	((unsigned int)(* (SK_U8 *)&(p)[2]))
+#define VPD_GET_VAL(p)		((char *)&(p)[3])
+
+#define VPD_MAX_LEN	50
+
+/* VPD status */
+	/* bit 7..1 reserved */
+#define VPD_VALID	(1<<0)	/* VPD data buffer, vpd_free_ro, */
+							/* and vpd_free_rw valid	 */
+
+/*
+ * VPD structs
+ */
+typedef	struct s_vpd_status {
+	unsigned short	Align01;			/* Alignment */
+	unsigned short	vpd_status;			/* VPD status, description see above */
+	int				vpd_free_ro;		/* unused bytes in read only area */
+	int				vpd_free_rw;		/* bytes available in read/write area */
+} SK_VPD_STATUS;
+
+typedef	struct s_vpd {
+	SK_VPD_STATUS	v;					/* VPD status structure */
+	char			vpd_buf[VPD_SIZE];	/* VPD buffer */
+	int				rom_size;			/* VPD ROM Size from PCI_OUR_REG_2 */
+	int				vpd_size;			/* saved VPD-size */
+} SK_VPD;
+
+typedef	struct s_vpd_para {
+	unsigned int	p_len;	/* parameter length */
+	char			*p_val;	/* points to the value */
+} SK_VPD_PARA;
+
+/*
+ * structure of Large Resource Type Identifiers
+ */
+
+/* was removed because of alignment problems */
+
+/*
+ * structure of VPD keywords
+ */
+typedef	struct s_vpd_key {
+	char			p_key[2];	/* 2 bytes ID string */
+	unsigned char	p_len;		/* 1 byte length */
+	char			p_val;		/* start of the value string */
+} SK_VPD_KEY;
+
+
+/*
+ * System specific VPD macros
+ */
+#ifndef SKDIAG
+#ifndef VPD_DO_IO
+#define VPD_OUT8(pAC,IoC,Addr,Val)	(void)SkPciWriteCfgByte(pAC,Addr,Val)
+#define VPD_OUT16(pAC,IoC,Addr,Val)	(void)SkPciWriteCfgWord(pAC,Addr,Val)
+#define VPD_IN8(pAC,IoC,Addr,pVal)	(void)SkPciReadCfgByte(pAC,Addr,pVal)
+#define VPD_IN16(pAC,IoC,Addr,pVal)	(void)SkPciReadCfgWord(pAC,Addr,pVal)
+#define VPD_IN32(pAC,IoC,Addr,pVal)	(void)SkPciReadCfgDWord(pAC,Addr,pVal)
+#else	/* VPD_DO_IO */
+#define VPD_OUT8(pAC,IoC,Addr,Val)	SK_OUT8(IoC,PCI_C(Addr),Val)
+#define VPD_OUT16(pAC,IoC,Addr,Val)	SK_OUT16(IoC,PCI_C(Addr),Val)
+#define VPD_IN8(pAC,IoC,Addr,pVal)	SK_IN8(IoC,PCI_C(Addr),pVal)
+#define VPD_IN16(pAC,IoC,Addr,pVal)	SK_IN16(IoC,PCI_C(Addr),pVal)
+#define VPD_IN32(pAC,IoC,Addr,pVal)	SK_IN32(IoC,PCI_C(Addr),pVal)
+#endif	/* VPD_DO_IO */
+#else	/* SKDIAG */
+#define VPD_OUT8(pAC,Ioc,Addr,Val) {			\
+		if ((pAC)->DgT.DgUseCfgCycle)			\
+			SkPciWriteCfgByte(pAC,Addr,Val);	\
+		else									\
+			SK_OUT8(pAC,PCI_C(Addr),Val);		\
+		}
+#define VPD_OUT16(pAC,Ioc,Addr,Val) {			\
+		if ((pAC)->DgT.DgUseCfgCycle)			\
+			SkPciWriteCfgWord(pAC,Addr,Val);	\
+		else						\
+			SK_OUT16(pAC,PCI_C(Addr),Val);		\
+		}
+#define VPD_IN8(pAC,Ioc,Addr,pVal) {			\
+		if ((pAC)->DgT.DgUseCfgCycle) 			\
+			SkPciReadCfgByte(pAC,Addr,pVal);	\
+		else						\
+			SK_IN8(pAC,PCI_C(Addr),pVal); 		\
+		}
+#define VPD_IN16(pAC,Ioc,Addr,pVal) {			\
+		if ((pAC)->DgT.DgUseCfgCycle) 			\
+			SkPciReadCfgWord(pAC,Addr,pVal);	\
+		else						\
+			SK_IN16(pAC,PCI_C(Addr),pVal); 		\
+		}
+#define VPD_IN32(pAC,Ioc,Addr,pVal) {			\
+		if ((pAC)->DgT.DgUseCfgCycle)			\
+			SkPciReadCfgDWord(pAC,Addr,pVal);	\
+		else						\
+			SK_IN32(pAC,PCI_C(Addr),pVal);		\
+		}
+#endif	/* nSKDIAG */
+
+/* function prototypes ********************************************************/
+
+#ifndef	SK_KR_PROTO
+#ifdef SKDIAG
+extern SK_U32	VpdReadDWord(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	int			addr);
+#endif	/* SKDIAG */
+
+extern SK_VPD_STATUS	*VpdStat(
+	SK_AC		*pAC,
+	SK_IOC		IoC);
+
+extern int	VpdKeys(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	char		*buf,
+	int			*len,
+	int			*elements);
+
+extern int	VpdRead(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	const char	*key,
+	char		*buf,
+	int			*len);
+
+extern SK_BOOL	VpdMayWrite(
+	char		*key);
+
+extern int	VpdWrite(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	const char	*key,
+	const char	*buf);
+
+extern int	VpdDelete(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	char		*key);
+
+extern int	VpdUpdate(
+	SK_AC		*pAC,
+	SK_IOC		IoC);
+
+#ifdef	SKDIAG
+extern int	VpdReadBlock(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	char		*buf,
+	int			addr,
+	int			len);
+
+extern int	VpdWriteBlock(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	char		*buf,
+	int			addr,
+	int			len);
+#endif	/* SKDIAG */
+#else	/* SK_KR_PROTO */
+extern SK_U32	VpdReadDWord();
+extern SK_VPD_STATUS	*VpdStat();
+extern int	VpdKeys();
+extern int	VpdRead();
+extern SK_BOOL	VpdMayWrite();
+extern int	VpdWrite();
+extern int	VpdDelete();
+extern int	VpdUpdate();
+#endif	/* SK_KR_PROTO */
+
+#endif	/* __INC_SKVPD_H_ */
diff --git a/drivers/net/sk98lin/h/xmac_ii.h b/drivers/net/sk98lin/h/xmac_ii.h
new file mode 100644
index 0000000..7f8e6d0
--- /dev/null
+++ b/drivers/net/sk98lin/h/xmac_ii.h
@@ -0,0 +1,1579 @@
+/******************************************************************************
+ *
+ * Name:	xmac_ii.h
+ * Project:	Gigabit Ethernet Adapters, Common Modules
+ * Version:	$Revision: 1.52 $
+ * Date:	$Date: 2003/10/02 16:35:50 $
+ * Purpose:	Defines and Macros for Gigabit Ethernet Controller
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+#ifndef __INC_XMAC_H
+#define __INC_XMAC_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif	/* __cplusplus */
+
+/* defines ********************************************************************/
+
+/*
+ * XMAC II registers
+ *
+ * The XMAC registers are 16 or 32 bits wide.
+ * The XMACs host processor interface is set to 16 bit mode,
+ * therefore ALL registers will be addressed with 16 bit accesses.
+ *
+ * The following macros are provided to access the XMAC registers
+ * XM_IN16(), XM_OUT16, XM_IN32(), XM_OUT32(), XM_INADR(), XM_OUTADR(),
+ * XM_INHASH(), and XM_OUTHASH().
+ * The macros are defined in SkGeHw.h.
+ *
+ * Note:	NA reg	= Network Address e.g DA, SA etc.
+ *
+ */
+#define XM_MMU_CMD		0x0000	/* 16 bit r/w	MMU Command Register */
+	/* 0x0004:		reserved */
+#define XM_POFF			0x0008	/* 32 bit r/w	Packet Offset Register */
+#define XM_BURST		0x000c	/* 32 bit r/w	Burst Register for half duplex*/
+#define XM_1L_VLAN_TAG	0x0010	/* 16 bit r/w	One Level VLAN Tag ID */
+#define XM_2L_VLAN_TAG	0x0014	/* 16 bit r/w	Two Level VLAN Tag ID */
+	/* 0x0018 - 0x001e:	reserved */
+#define XM_TX_CMD		0x0020	/* 16 bit r/w	Transmit Command Register */
+#define XM_TX_RT_LIM	0x0024	/* 16 bit r/w	Transmit Retry Limit Register */
+#define XM_TX_STIME		0x0028	/* 16 bit r/w	Transmit Slottime Register */
+#define XM_TX_IPG		0x002c	/* 16 bit r/w	Transmit Inter Packet Gap */
+#define XM_RX_CMD		0x0030	/* 16 bit r/w	Receive Command Register */
+#define XM_PHY_ADDR		0x0034	/* 16 bit r/w	PHY Address Register */
+#define XM_PHY_DATA		0x0038	/* 16 bit r/w	PHY Data Register */
+	/* 0x003c: 		reserved */
+#define XM_GP_PORT		0x0040	/* 32 bit r/w	General Purpose Port Register */
+#define XM_IMSK			0x0044	/* 16 bit r/w	Interrupt Mask Register */
+#define XM_ISRC			0x0048	/* 16 bit r/o	Interrupt Status Register */
+#define XM_HW_CFG		0x004c	/* 16 bit r/w	Hardware Config Register */
+	/* 0x0050 - 0x005e:	reserved */
+#define XM_TX_LO_WM		0x0060	/* 16 bit r/w	Tx FIFO Low Water Mark */
+#define XM_TX_HI_WM		0x0062	/* 16 bit r/w	Tx FIFO High Water Mark */
+#define XM_TX_THR		0x0064	/* 16 bit r/w	Tx Request Threshold */
+#define XM_HT_THR		0x0066	/* 16 bit r/w	Host Request Threshold */
+#define XM_PAUSE_DA		0x0068	/* NA reg r/w	Pause Destination Address */
+	/* 0x006e: 		reserved */
+#define XM_CTL_PARA		0x0070	/* 32 bit r/w	Control Parameter Register */
+#define XM_MAC_OPCODE	0x0074	/* 16 bit r/w	Opcode for MAC control frames */
+#define XM_MAC_PTIME	0x0076	/* 16 bit r/w	Pause time for MAC ctrl frames*/
+#define XM_TX_STAT		0x0078	/* 32 bit r/o	Tx Status LIFO Register */
+
+	/* 0x0080 - 0x00fc:	16 NA reg r/w	Exact Match Address Registers */
+	/* 				use the XM_EXM() macro to address */
+#define XM_EXM_START	0x0080	/* r/w	Start Address of the EXM Regs */
+
+	/*
+	 * XM_EXM(Reg)
+	 *
+	 * returns the XMAC address offset of specified Exact Match Addr Reg
+	 *
+	 * para:	Reg	EXM register to addr	(0 .. 15)
+	 *
+	 * usage:	XM_INADDR(IoC, MAC_1, XM_EXM(i), &val[i]);
+	 */
+#define XM_EXM(Reg)	(XM_EXM_START + ((Reg) << 3))
+
+#define XM_SRC_CHK		0x0100	/* NA reg r/w	Source Check Address Register */
+#define XM_SA			0x0108	/* NA reg r/w	Station Address Register */
+#define XM_HSM			0x0110	/* 64 bit r/w	Hash Match Address Registers */
+#define XM_RX_LO_WM		0x0118	/* 16 bit r/w	Receive Low Water Mark */
+#define XM_RX_HI_WM		0x011a	/* 16 bit r/w	Receive High Water Mark */
+#define XM_RX_THR		0x011c	/* 32 bit r/w	Receive Request Threshold */
+#define XM_DEV_ID		0x0120	/* 32 bit r/o	Device ID Register */
+#define XM_MODE			0x0124	/* 32 bit r/w	Mode Register */
+#define XM_LSA			0x0128	/* NA reg r/o	Last Source Register */
+	/* 0x012e:		reserved */
+#define XM_TS_READ		0x0130	/* 32 bit r/o	Time Stamp Read Register */
+#define XM_TS_LOAD		0x0134	/* 32 bit r/o	Time Stamp Load Value */
+	/* 0x0138 - 0x01fe:	reserved */
+#define XM_STAT_CMD	0x0200	/* 16 bit r/w	Statistics Command Register */
+#define XM_RX_CNT_EV	0x0204	/* 32 bit r/o	Rx Counter Event Register */
+#define XM_TX_CNT_EV	0x0208	/* 32 bit r/o	Tx Counter Event Register */
+#define XM_RX_EV_MSK	0x020c	/* 32 bit r/w	Rx Counter Event Mask */
+#define XM_TX_EV_MSK	0x0210	/* 32 bit r/w	Tx Counter Event Mask */
+	/* 0x0204 - 0x027e:	reserved */
+#define XM_TXF_OK		0x0280	/* 32 bit r/o	Frames Transmitted OK Conuter */
+#define XM_TXO_OK_HI	0x0284	/* 32 bit r/o	Octets Transmitted OK High Cnt*/
+#define XM_TXO_OK_LO	0x0288	/* 32 bit r/o	Octets Transmitted OK Low Cnt */
+#define XM_TXF_BC_OK	0x028c	/* 32 bit r/o	Broadcast Frames Xmitted OK */
+#define XM_TXF_MC_OK	0x0290	/* 32 bit r/o	Multicast Frames Xmitted OK */
+#define XM_TXF_UC_OK	0x0294	/* 32 bit r/o	Unicast Frames Xmitted OK */
+#define XM_TXF_LONG		0x0298	/* 32 bit r/o	Tx Long Frame Counter */
+#define XM_TXE_BURST	0x029c	/* 32 bit r/o	Tx Burst Event Counter */
+#define XM_TXF_MPAUSE	0x02a0	/* 32 bit r/o	Tx Pause MAC Ctrl Frame Cnt */
+#define XM_TXF_MCTRL	0x02a4	/* 32 bit r/o	Tx MAC Ctrl Frame Counter */
+#define XM_TXF_SNG_COL	0x02a8	/* 32 bit r/o	Tx Single Collision Counter */
+#define XM_TXF_MUL_COL	0x02ac	/* 32 bit r/o	Tx Multiple Collision Counter */
+#define XM_TXF_ABO_COL	0x02b0	/* 32 bit r/o	Tx aborted due to Exces. Col. */
+#define XM_TXF_LAT_COL	0x02b4	/* 32 bit r/o	Tx Late Collision Counter */
+#define XM_TXF_DEF		0x02b8	/* 32 bit r/o	Tx Deferred Frame Counter */
+#define XM_TXF_EX_DEF	0x02bc	/* 32 bit r/o	Tx Excessive Deferall Counter */
+#define XM_TXE_FIFO_UR	0x02c0	/* 32 bit r/o	Tx FIFO Underrun Event Cnt */
+#define XM_TXE_CS_ERR	0x02c4	/* 32 bit r/o	Tx Carrier Sense Error Cnt */
+#define XM_TXP_UTIL		0x02c8	/* 32 bit r/o	Tx Utilization in % */
+	/* 0x02cc - 0x02ce:	reserved */
+#define XM_TXF_64B		0x02d0	/* 32 bit r/o	64 Byte Tx Frame Counter */
+#define XM_TXF_127B		0x02d4	/* 32 bit r/o	65-127 Byte Tx Frame Counter */
+#define XM_TXF_255B		0x02d8	/* 32 bit r/o	128-255 Byte Tx Frame Counter */
+#define XM_TXF_511B		0x02dc	/* 32 bit r/o	256-511 Byte Tx Frame Counter */
+#define XM_TXF_1023B	0x02e0	/* 32 bit r/o	512-1023 Byte Tx Frame Counter*/
+#define XM_TXF_MAX_SZ	0x02e4	/* 32 bit r/o	1024-MaxSize Byte Tx Frame Cnt*/
+	/* 0x02e8 - 0x02fe:	reserved */
+#define XM_RXF_OK		0x0300	/* 32 bit r/o	Frames Received OK */
+#define XM_RXO_OK_HI	0x0304	/* 32 bit r/o	Octets Received OK High Cnt */
+#define XM_RXO_OK_LO	0x0308	/* 32 bit r/o	Octets Received OK Low Counter*/
+#define XM_RXF_BC_OK	0x030c	/* 32 bit r/o	Broadcast Frames Received OK */
+#define XM_RXF_MC_OK	0x0310	/* 32 bit r/o	Multicast Frames Received OK */
+#define XM_RXF_UC_OK	0x0314	/* 32 bit r/o	Unicast Frames Received OK */
+#define XM_RXF_MPAUSE	0x0318	/* 32 bit r/o	Rx Pause MAC Ctrl Frame Cnt */
+#define XM_RXF_MCTRL	0x031c	/* 32 bit r/o	Rx MAC Ctrl Frame Counter */
+#define XM_RXF_INV_MP	0x0320	/* 32 bit r/o	Rx invalid Pause Frame Cnt */
+#define XM_RXF_INV_MOC	0x0324	/* 32 bit r/o	Rx Frames with inv. MAC Opcode*/
+#define XM_RXE_BURST	0x0328	/* 32 bit r/o	Rx Burst Event Counter */
+#define XM_RXE_FMISS	0x032c	/* 32 bit r/o	Rx Missed Frames Event Cnt */
+#define XM_RXF_FRA_ERR	0x0330	/* 32 bit r/o	Rx Framing Error Counter */
+#define XM_RXE_FIFO_OV	0x0334	/* 32 bit r/o	Rx FIFO overflow Event Cnt */
+#define XM_RXF_JAB_PKT	0x0338	/* 32 bit r/o	Rx Jabber Packet Frame Cnt */
+#define XM_RXE_CAR_ERR	0x033c	/* 32 bit r/o	Rx Carrier Event Error Cnt */
+#define XM_RXF_LEN_ERR	0x0340	/* 32 bit r/o	Rx in Range Length Error */
+#define XM_RXE_SYM_ERR	0x0344	/* 32 bit r/o	Rx Symbol Error Counter */
+#define XM_RXE_SHT_ERR	0x0348	/* 32 bit r/o	Rx Short Event Error Cnt */
+#define XM_RXE_RUNT		0x034c	/* 32 bit r/o	Rx Runt Event Counter */
+#define XM_RXF_LNG_ERR	0x0350	/* 32 bit r/o	Rx Frame too Long Error Cnt */
+#define XM_RXF_FCS_ERR	0x0354	/* 32 bit r/o	Rx Frame Check Seq. Error Cnt */
+	/* 0x0358 - 0x035a:	reserved */
+#define XM_RXF_CEX_ERR	0x035c	/* 32 bit r/o	Rx Carrier Ext Error Frame Cnt*/
+#define XM_RXP_UTIL		0x0360	/* 32 bit r/o	Rx Utilization in % */
+	/* 0x0364 - 0x0366:	reserved */
+#define XM_RXF_64B		0x0368	/* 32 bit r/o	64 Byte Rx Frame Counter */
+#define XM_RXF_127B		0x036c	/* 32 bit r/o	65-127 Byte Rx Frame Counter */
+#define XM_RXF_255B		0x0370	/* 32 bit r/o	128-255 Byte Rx Frame Counter */
+#define XM_RXF_511B		0x0374	/* 32 bit r/o	256-511 Byte Rx Frame Counter */
+#define XM_RXF_1023B	0x0378	/* 32 bit r/o	512-1023 Byte Rx Frame Counter*/
+#define XM_RXF_MAX_SZ	0x037c	/* 32 bit r/o	1024-MaxSize Byte Rx Frame Cnt*/
+	/* 0x02e8 - 0x02fe:	reserved */
+
+
+/*----------------------------------------------------------------------------*/
+/*
+ * XMAC Bit Definitions
+ *
+ * If the bit access behaviour differs from the register access behaviour
+ * (r/w, r/o) this is documented after the bit number.
+ * The following bit access behaviours are used:
+ *	(sc)	self clearing
+ *	(ro)	read only
+ */
+
+/*	XM_MMU_CMD	16 bit r/w	MMU Command Register */
+								/* Bit 15..13:	reserved */
+#define XM_MMU_PHY_RDY	(1<<12)	/* Bit 12:	PHY Read Ready */
+#define XM_MMU_PHY_BUSY	(1<<11)	/* Bit 11:	PHY Busy */
+#define XM_MMU_IGN_PF	(1<<10)	/* Bit 10:	Ignore Pause Frame */
+#define XM_MMU_MAC_LB	(1<<9)	/* Bit  9:	Enable MAC Loopback */
+								/* Bit  8:	reserved */
+#define XM_MMU_FRC_COL	(1<<7)	/* Bit  7:	Force Collision */
+#define XM_MMU_SIM_COL	(1<<6)	/* Bit  6:	Simulate Collision */
+#define XM_MMU_NO_PRE	(1<<5)	/* Bit  5:	No MDIO Preamble */
+#define XM_MMU_GMII_FD	(1<<4)	/* Bit  4:	GMII uses Full Duplex */
+#define XM_MMU_RAT_CTRL	(1<<3)	/* Bit  3:	Enable Rate Control */
+#define XM_MMU_GMII_LOOP (1<<2)	/* Bit  2:	PHY is in Loopback Mode */
+#define XM_MMU_ENA_RX	(1<<1)	/* Bit  1:	Enable Receiver */
+#define XM_MMU_ENA_TX	(1<<0)	/* Bit  0:	Enable Transmitter */
+
+
+/*	XM_TX_CMD	16 bit r/w	Transmit Command Register */
+								/* Bit 15..7:	reserved */
+#define XM_TX_BK2BK		(1<<6)	/* Bit  6:	Ignor Carrier Sense (Tx Bk2Bk)*/
+#define XM_TX_ENC_BYP	(1<<5)	/* Bit  5:	Set Encoder in Bypass Mode */
+#define XM_TX_SAM_LINE	(1<<4)	/* Bit  4: (sc)	Start utilization calculation */
+#define XM_TX_NO_GIG_MD	(1<<3)	/* Bit  3:	Disable Carrier Extension */
+#define XM_TX_NO_PRE	(1<<2)	/* Bit  2:	Disable Preamble Generation */
+#define XM_TX_NO_CRC	(1<<1)	/* Bit  1:	Disable CRC Generation */
+#define XM_TX_AUTO_PAD	(1<<0)	/* Bit  0:	Enable Automatic Padding */
+
+
+/*	XM_TX_RT_LIM	16 bit r/w	Transmit Retry Limit Register */
+								/* Bit 15..5:	reserved */
+#define XM_RT_LIM_MSK	0x1f	/* Bit  4..0:	Tx Retry Limit */
+
+
+/*	XM_TX_STIME	16 bit r/w	Transmit Slottime Register */
+								/* Bit 15..7:	reserved */
+#define XM_STIME_MSK	0x7f	/* Bit  6..0:	Tx Slottime bits */
+
+
+/*	XM_TX_IPG	16 bit r/w	Transmit Inter Packet Gap */
+								/* Bit 15..8:	reserved */
+#define XM_IPG_MSK		0xff	/* Bit  7..0:	IPG value bits */
+
+
+/*	XM_RX_CMD	16 bit r/w	Receive Command Register */
+								/* Bit 15..9:	reserved */
+#define XM_RX_LENERR_OK (1<<8)	/* Bit  8	don't set Rx Err bit for */
+								/*		inrange error packets */
+#define XM_RX_BIG_PK_OK	(1<<7)	/* Bit  7	don't set Rx Err bit for */
+								/*		jumbo packets */
+#define XM_RX_IPG_CAP	(1<<6)	/* Bit  6	repl. type field with IPG */
+#define XM_RX_TP_MD		(1<<5)	/* Bit  5:	Enable transparent Mode */
+#define XM_RX_STRIP_FCS	(1<<4)	/* Bit  4:	Enable FCS Stripping */
+#define XM_RX_SELF_RX	(1<<3)	/* Bit  3: 	Enable Rx of own packets */
+#define XM_RX_SAM_LINE	(1<<2)	/* Bit  2: (sc)	Start utilization calculation */
+#define XM_RX_STRIP_PAD	(1<<1)	/* Bit  1:	Strip pad bytes of Rx frames */
+#define XM_RX_DIS_CEXT	(1<<0)	/* Bit  0:	Disable carrier ext. check */
+
+
+/*	XM_PHY_ADDR	16 bit r/w	PHY Address Register */
+								/* Bit 15..5:	reserved */
+#define XM_PHY_ADDR_SZ	0x1f	/* Bit  4..0:	PHY Address bits */
+
+
+/*	XM_GP_PORT	32 bit r/w	General Purpose Port Register */
+								/* Bit 31..7:	reserved */
+#define XM_GP_ANIP		(1L<<6)	/* Bit  6: (ro)	Auto-Neg. in progress */
+#define XM_GP_FRC_INT	(1L<<5)	/* Bit  5: (sc)	Force Interrupt */
+								/* Bit  4:	reserved */
+#define XM_GP_RES_MAC	(1L<<3)	/* Bit  3: (sc)	Reset MAC and FIFOs */
+#define XM_GP_RES_STAT	(1L<<2)	/* Bit  2: (sc)	Reset the statistics module */
+								/* Bit  1:	reserved */
+#define XM_GP_INP_ASS	(1L<<0)	/* Bit  0: (ro) GP Input Pin asserted */
+
+
+/*	XM_IMSK		16 bit r/w	Interrupt Mask Register */
+/*	XM_ISRC		16 bit r/o	Interrupt Status Register */
+								/* Bit 15:	reserved */
+#define XM_IS_LNK_AE	(1<<14) /* Bit 14:	Link Asynchronous Event */
+#define XM_IS_TX_ABORT	(1<<13) /* Bit 13:	Transmit Abort, late Col. etc */
+#define XM_IS_FRC_INT	(1<<12) /* Bit 12:	Force INT bit set in GP */
+#define XM_IS_INP_ASS	(1<<11)	/* Bit 11:	Input Asserted, GP bit 0 set */
+#define XM_IS_LIPA_RC	(1<<10)	/* Bit 10:	Link Partner requests config */
+#define XM_IS_RX_PAGE	(1<<9)	/* Bit  9:	Page Received */
+#define XM_IS_TX_PAGE	(1<<8)	/* Bit  8:	Next Page Loaded for Transmit */
+#define XM_IS_AND		(1<<7)	/* Bit  7:	Auto-Negotiation Done */
+#define XM_IS_TSC_OV	(1<<6)	/* Bit  6:	Time Stamp Counter Overflow */
+#define XM_IS_RXC_OV	(1<<5)	/* Bit  5:	Rx Counter Event Overflow */
+#define XM_IS_TXC_OV	(1<<4)	/* Bit  4:	Tx Counter Event Overflow */
+#define XM_IS_RXF_OV	(1<<3)	/* Bit  3:	Receive FIFO Overflow */
+#define XM_IS_TXF_UR	(1<<2)	/* Bit  2:	Transmit FIFO Underrun */
+#define XM_IS_TX_COMP	(1<<1)	/* Bit  1:	Frame Tx Complete */
+#define XM_IS_RX_COMP	(1<<0)	/* Bit  0:	Frame Rx Complete */
+
+#define XM_DEF_MSK	(~(XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE |\
+			XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV | XM_IS_TXF_UR))
+
+
+/*	XM_HW_CFG	16 bit r/w	Hardware Config Register */
+								/* Bit 15.. 4:	reserved */
+#define XM_HW_GEN_EOP	(1<<3)	/* Bit  3:	generate End of Packet pulse */
+#define XM_HW_COM4SIG	(1<<2)	/* Bit  2:	use Comma Detect for Sig. Det.*/
+								/* Bit  1:	reserved */
+#define XM_HW_GMII_MD	(1<<0)	/* Bit  0:	GMII Interface selected */
+
+
+/*	XM_TX_LO_WM	16 bit r/w	Tx FIFO Low Water Mark */
+/*	XM_TX_HI_WM	16 bit r/w	Tx FIFO High Water Mark */
+								/* Bit 15..10	reserved */
+#define XM_TX_WM_MSK	0x01ff	/* Bit  9.. 0	Tx FIFO Watermark bits */
+
+/*	XM_TX_THR	16 bit r/w	Tx Request Threshold */
+/*	XM_HT_THR	16 bit r/w	Host Request Threshold */
+/*	XM_RX_THR	16 bit r/w	Rx Request Threshold */
+								/* Bit 15..11	reserved */
+#define XM_THR_MSK		0x03ff	/* Bit 10.. 0	Rx/Tx Request Threshold bits */
+
+
+/*	XM_TX_STAT	32 bit r/o	Tx Status LIFO Register */
+#define XM_ST_VALID		(1UL<<31)	/* Bit 31:	Status Valid */
+#define XM_ST_BYTE_CNT	(0x3fffL<<17)	/* Bit 30..17:	Tx frame Length */
+#define XM_ST_RETRY_CNT	(0x1fL<<12)	/* Bit 16..12:	Retry Count */
+#define XM_ST_EX_COL	(1L<<11)	/* Bit 11:	Excessive Collisions */
+#define XM_ST_EX_DEF	(1L<<10)	/* Bit 10:	Excessive Deferral */
+#define XM_ST_BURST		(1L<<9)		/* Bit  9:	p. xmitted in burst md*/
+#define XM_ST_DEFER		(1L<<8)		/* Bit  8:	packet was defered */
+#define XM_ST_BC		(1L<<7)		/* Bit  7:	Broadcast packet */
+#define XM_ST_MC		(1L<<6)		/* Bit  6:	Multicast packet */
+#define XM_ST_UC		(1L<<5)		/* Bit  5:	Unicast packet */
+#define XM_ST_TX_UR		(1L<<4)		/* Bit  4:	FIFO Underrun occured */
+#define XM_ST_CS_ERR	(1L<<3)		/* Bit  3:	Carrier Sense Error */
+#define XM_ST_LAT_COL	(1L<<2)		/* Bit  2:	Late Collision Error */
+#define XM_ST_MUL_COL	(1L<<1)		/* Bit  1:	Multiple Collisions */
+#define XM_ST_SGN_COL	(1L<<0)		/* Bit  0:	Single Collision */
+
+/*	XM_RX_LO_WM	16 bit r/w	Receive Low Water Mark */
+/*	XM_RX_HI_WM	16 bit r/w	Receive High Water Mark */
+									/* Bit 15..11:	reserved */
+#define XM_RX_WM_MSK	0x03ff		/* Bit 11.. 0:	Rx FIFO Watermark bits */
+
+
+/*	XM_DEV_ID	32 bit r/o	Device ID Register */
+#define XM_DEV_OUI	(0x00ffffffUL<<8)	/* Bit 31..8:	Device OUI */
+#define XM_DEV_REV	(0x07L << 5)		/* Bit  7..5:	Chip Rev Num */
+
+
+/*	XM_MODE		32 bit r/w	Mode Register */
+									/* Bit 31..27:	reserved */
+#define XM_MD_ENA_REJ	(1L<<26)	/* Bit 26:	Enable Frame Reject */
+#define XM_MD_SPOE_E	(1L<<25)	/* Bit 25:	Send Pause on Edge */
+									/* 		extern generated */
+#define XM_MD_TX_REP	(1L<<24)	/* Bit 24:	Transmit Repeater Mode */
+#define XM_MD_SPOFF_I	(1L<<23)	/* Bit 23:	Send Pause on FIFO full */
+									/*		intern generated */
+#define XM_MD_LE_STW	(1L<<22)	/* Bit 22:	Rx Stat Word in Little Endian */
+#define XM_MD_TX_CONT	(1L<<21)	/* Bit 21:	Send Continuous */
+#define XM_MD_TX_PAUSE	(1L<<20)	/* Bit 20: (sc)	Send Pause Frame */
+#define XM_MD_ATS		(1L<<19)	/* Bit 19:	Append Time Stamp */
+#define XM_MD_SPOL_I	(1L<<18)	/* Bit 18:	Send Pause on Low */
+									/*		intern generated */
+#define XM_MD_SPOH_I	(1L<<17)	/* Bit 17:	Send Pause on High */
+									/*		intern generated */
+#define XM_MD_CAP		(1L<<16)	/* Bit 16:	Check Address Pair */
+#define XM_MD_ENA_HASH	(1L<<15)	/* Bit 15:	Enable Hashing */
+#define XM_MD_CSA		(1L<<14)	/* Bit 14:	Check Station Address */
+#define XM_MD_CAA		(1L<<13)	/* Bit 13:	Check Address Array */
+#define XM_MD_RX_MCTRL	(1L<<12)	/* Bit 12:	Rx MAC Control Frame */
+#define XM_MD_RX_RUNT	(1L<<11)	/* Bit 11:	Rx Runt Frames */
+#define XM_MD_RX_IRLE	(1L<<10)	/* Bit 10:	Rx in Range Len Err Frame */
+#define XM_MD_RX_LONG	(1L<<9)		/* Bit  9:	Rx Long Frame */
+#define XM_MD_RX_CRCE	(1L<<8)		/* Bit  8:	Rx CRC Error Frame */
+#define XM_MD_RX_ERR	(1L<<7)		/* Bit  7:	Rx Error Frame */
+#define XM_MD_DIS_UC	(1L<<6)		/* Bit  6:	Disable Rx Unicast */
+#define XM_MD_DIS_MC	(1L<<5)		/* Bit  5:	Disable Rx Multicast */
+#define XM_MD_DIS_BC	(1L<<4)		/* Bit  4:	Disable Rx Broadcast */
+#define XM_MD_ENA_PROM	(1L<<3)		/* Bit  3:	Enable Promiscuous */
+#define XM_MD_ENA_BE	(1L<<2)		/* Bit  2:	Enable Big Endian */
+#define XM_MD_FTF		(1L<<1)		/* Bit  1: (sc)	Flush Tx FIFO */
+#define XM_MD_FRF		(1L<<0)		/* Bit  0: (sc)	Flush Rx FIFO */
+
+#define XM_PAUSE_MODE	(XM_MD_SPOE_E | XM_MD_SPOL_I | XM_MD_SPOH_I)
+#define XM_DEF_MODE		(XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\
+				XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA | XM_MD_CAA)
+
+/*	XM_STAT_CMD	16 bit r/w	Statistics Command Register */
+								/* Bit 16..6:	reserved */
+#define XM_SC_SNP_RXC	(1<<5)	/* Bit  5: (sc)	Snap Rx Counters */
+#define XM_SC_SNP_TXC	(1<<4)	/* Bit  4: (sc)	Snap Tx Counters */
+#define XM_SC_CP_RXC	(1<<3)	/* Bit  3: 	Copy Rx Counters Continuously */
+#define XM_SC_CP_TXC	(1<<2)	/* Bit  2:	Copy Tx Counters Continuously */
+#define XM_SC_CLR_RXC	(1<<1)	/* Bit  1: (sc)	Clear Rx Counters */
+#define XM_SC_CLR_TXC	(1<<0)	/* Bit  0: (sc) Clear Tx Counters */
+
+
+/*	XM_RX_CNT_EV	32 bit r/o	Rx Counter Event Register */
+/*	XM_RX_EV_MSK	32 bit r/w	Rx Counter Event Mask */
+#define XMR_MAX_SZ_OV	(1UL<<31)	/* Bit 31:	1024-MaxSize Rx Cnt Ov*/
+#define XMR_1023B_OV	(1L<<30)	/* Bit 30:	512-1023Byte Rx Cnt Ov*/
+#define XMR_511B_OV		(1L<<29)	/* Bit 29:	256-511 Byte Rx Cnt Ov*/
+#define XMR_255B_OV		(1L<<28)	/* Bit 28:	128-255 Byte Rx Cnt Ov*/
+#define XMR_127B_OV		(1L<<27)	/* Bit 27:	65-127 Byte Rx Cnt Ov */
+#define XMR_64B_OV		(1L<<26)	/* Bit 26:	64 Byte Rx Cnt Ov */
+#define XMR_UTIL_OV		(1L<<25)	/* Bit 25:	Rx Util Cnt Overflow */
+#define XMR_UTIL_UR		(1L<<24)	/* Bit 24:	Rx Util Cnt Underrun */
+#define XMR_CEX_ERR_OV	(1L<<23)	/* Bit 23:	CEXT Err Cnt Ov */
+									/* Bit 22:	reserved */
+#define XMR_FCS_ERR_OV	(1L<<21)	/* Bit 21:	Rx FCS Error Cnt Ov */
+#define XMR_LNG_ERR_OV	(1L<<20)	/* Bit 20:	Rx too Long Err Cnt Ov*/
+#define XMR_RUNT_OV		(1L<<19)	/* Bit 19:	Runt Event Cnt Ov */
+#define XMR_SHT_ERR_OV	(1L<<18)	/* Bit 18:	Rx Short Ev Err Cnt Ov*/
+#define XMR_SYM_ERR_OV	(1L<<17)	/* Bit 17:	Rx Sym Err Cnt Ov */
+									/* Bit 16:	reserved */
+#define XMR_CAR_ERR_OV	(1L<<15)	/* Bit 15:	Rx Carr Ev Err Cnt Ov */
+#define XMR_JAB_PKT_OV	(1L<<14)	/* Bit 14:	Rx Jabb Packet Cnt Ov */
+#define XMR_FIFO_OV		(1L<<13)	/* Bit 13:	Rx FIFO Ov Ev Cnt Ov */
+#define XMR_FRA_ERR_OV	(1L<<12)	/* Bit 12:	Rx Framing Err Cnt Ov */
+#define XMR_FMISS_OV	(1L<<11)	/* Bit 11:	Rx Missed Ev Cnt Ov */
+#define XMR_BURST		(1L<<10)	/* Bit 10:	Rx Burst Event Cnt Ov */
+#define XMR_INV_MOC		(1L<<9)		/* Bit  9:	Rx with inv. MAC OC Ov*/
+#define XMR_INV_MP		(1L<<8)		/* Bit  8:	Rx inv Pause Frame Ov */
+#define XMR_MCTRL_OV	(1L<<7)		/* Bit  7:	Rx MAC Ctrl-F Cnt Ov */
+#define XMR_MPAUSE_OV	(1L<<6)		/* Bit  6:	Rx Pause MAC Ctrl-F Ov*/
+#define XMR_UC_OK_OV	(1L<<5)		/* Bit  5:	Rx Unicast Frame CntOv*/
+#define XMR_MC_OK_OV	(1L<<4)		/* Bit  4:	Rx Multicast Cnt Ov */
+#define XMR_BC_OK_OV	(1L<<3)		/* Bit  3:	Rx Broadcast Cnt Ov */
+#define XMR_OK_LO_OV	(1L<<2)		/* Bit  2:	Octets Rx OK Low CntOv*/
+#define XMR_OK_HI_OV	(1L<<1)		/* Bit  1:	Octets Rx OK Hi Cnt Ov*/
+#define XMR_OK_OV		(1L<<0)		/* Bit  0:	Frames Received Ok Ov */
+
+#define XMR_DEF_MSK		(XMR_OK_LO_OV | XMR_OK_HI_OV)
+
+/*	XM_TX_CNT_EV	32 bit r/o	Tx Counter Event Register */
+/*	XM_TX_EV_MSK	32 bit r/w	Tx Counter Event Mask */
+									/* Bit 31..26:	reserved */
+#define XMT_MAX_SZ_OV	(1L<<25)	/* Bit 25:	1024-MaxSize Tx Cnt Ov*/
+#define XMT_1023B_OV	(1L<<24)	/* Bit 24:	512-1023Byte Tx Cnt Ov*/
+#define XMT_511B_OV		(1L<<23)	/* Bit 23:	256-511 Byte Tx Cnt Ov*/
+#define XMT_255B_OV		(1L<<22)	/* Bit 22:	128-255 Byte Tx Cnt Ov*/
+#define XMT_127B_OV		(1L<<21)	/* Bit 21:	65-127 Byte Tx Cnt Ov */
+#define XMT_64B_OV		(1L<<20)	/* Bit 20:	64 Byte Tx Cnt Ov */
+#define XMT_UTIL_OV		(1L<<19)	/* Bit 19:	Tx Util Cnt Overflow */
+#define XMT_UTIL_UR		(1L<<18)	/* Bit 18:	Tx Util Cnt Underrun */
+#define XMT_CS_ERR_OV	(1L<<17)	/* Bit 17:	Tx Carr Sen Err Cnt Ov*/
+#define XMT_FIFO_UR_OV	(1L<<16)	/* Bit 16:	Tx FIFO Ur Ev Cnt Ov */
+#define XMT_EX_DEF_OV	(1L<<15)	/* Bit 15:	Tx Ex Deferall Cnt Ov */
+#define XMT_DEF			(1L<<14)	/* Bit 14:	Tx Deferred Cnt Ov */
+#define XMT_LAT_COL_OV	(1L<<13)	/* Bit 13:	Tx Late Col Cnt Ov */
+#define XMT_ABO_COL_OV	(1L<<12)	/* Bit 12:	Tx abo dueto Ex Col Ov*/
+#define XMT_MUL_COL_OV	(1L<<11)	/* Bit 11:	Tx Mult Col Cnt Ov */
+#define XMT_SNG_COL		(1L<<10)	/* Bit 10:	Tx Single Col Cnt Ov */
+#define XMT_MCTRL_OV	(1L<<9)		/* Bit  9:	Tx MAC Ctrl Counter Ov*/
+#define XMT_MPAUSE		(1L<<8)		/* Bit  8:	Tx Pause MAC Ctrl-F Ov*/
+#define XMT_BURST		(1L<<7)		/* Bit  7:	Tx Burst Event Cnt Ov */
+#define XMT_LONG		(1L<<6)		/* Bit  6:	Tx Long Frame Cnt Ov */
+#define XMT_UC_OK_OV	(1L<<5)		/* Bit  5:	Tx Unicast Cnt Ov */
+#define XMT_MC_OK_OV	(1L<<4)		/* Bit  4:	Tx Multicast Cnt Ov */
+#define XMT_BC_OK_OV	(1L<<3)		/* Bit  3:	Tx Broadcast Cnt Ov */
+#define XMT_OK_LO_OV	(1L<<2)		/* Bit  2:	Octets Tx OK Low CntOv*/
+#define XMT_OK_HI_OV	(1L<<1)		/* Bit  1:	Octets Tx OK Hi Cnt Ov*/
+#define XMT_OK_OV		(1L<<0)		/* Bit  0:	Frames Tx Ok Ov */
+
+#define XMT_DEF_MSK		(XMT_OK_LO_OV | XMT_OK_HI_OV)
+
+/*
+ * Receive Frame Status Encoding
+ */
+#define XMR_FS_LEN	(0x3fffUL<<18)	/* Bit 31..18:	Rx Frame Length */
+#define XMR_FS_2L_VLAN	(1L<<17)	/* Bit 17:	tagged wh 2Lev VLAN ID*/
+#define XMR_FS_1L_VLAN	(1L<<16)	/* Bit 16:	tagged wh 1Lev VLAN ID*/
+#define XMR_FS_BC		(1L<<15)	/* Bit 15:	Broadcast Frame */
+#define XMR_FS_MC		(1L<<14)	/* Bit 14:	Multicast Frame */
+#define XMR_FS_UC		(1L<<13)	/* Bit 13:	Unicast Frame */
+									/* Bit 12:	reserved */
+#define XMR_FS_BURST	(1L<<11)	/* Bit 11:	Burst Mode */
+#define XMR_FS_CEX_ERR	(1L<<10)	/* Bit 10:	Carrier Ext. Error */
+#define XMR_FS_802_3	(1L<<9)		/* Bit  9:	802.3 Frame */
+#define XMR_FS_COL_ERR	(1L<<8)		/* Bit  8:	Collision Error */
+#define XMR_FS_CAR_ERR	(1L<<7)		/* Bit  7:	Carrier Event Error */
+#define XMR_FS_LEN_ERR	(1L<<6)		/* Bit  6:	In-Range Length Error */
+#define XMR_FS_FRA_ERR	(1L<<5)		/* Bit  5:	Framing Error */
+#define XMR_FS_RUNT		(1L<<4)		/* Bit  4:	Runt Frame */
+#define XMR_FS_LNG_ERR	(1L<<3)		/* Bit  3:	Giant (Jumbo) Frame */
+#define XMR_FS_FCS_ERR	(1L<<2)		/* Bit  2:	Frame Check Sequ Err */
+#define XMR_FS_ERR		(1L<<1)		/* Bit  1:	Frame Error */
+#define XMR_FS_MCTRL	(1L<<0)		/* Bit  0:	MAC Control Packet */
+
+/*
+ * XMR_FS_ERR will be set if
+ *	XMR_FS_FCS_ERR, XMR_FS_LNG_ERR, XMR_FS_RUNT,
+ *	XMR_FS_FRA_ERR, XMR_FS_LEN_ERR, or XMR_FS_CEX_ERR
+ * is set. XMR_FS_LNG_ERR and XMR_FS_LEN_ERR will issue
+ * XMR_FS_ERR unless the corresponding bit in the Receive Command
+ * Register is set.
+ */
+#define XMR_FS_ANY_ERR	XMR_FS_ERR
+
+/*----------------------------------------------------------------------------*/
+/*
+ * XMAC-PHY Registers, indirect addressed over the XMAC
+ */
+#define PHY_XMAC_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define PHY_XMAC_STAT		0x01	/* 16 bit r/w	PHY Status Register */
+#define PHY_XMAC_ID0		0x02	/* 16 bit r/o	PHY ID0 Register */
+#define PHY_XMAC_ID1		0x03	/* 16 bit r/o	PHY ID1 Register */
+#define PHY_XMAC_AUNE_ADV	0x04	/* 16 bit r/w	Auto-Neg. Advertisement */
+#define PHY_XMAC_AUNE_LP	0x05	/* 16 bit r/o	Link Partner Abi Reg */
+#define PHY_XMAC_AUNE_EXP	0x06	/* 16 bit r/o	Auto-Neg. Expansion Reg */
+#define PHY_XMAC_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define PHY_XMAC_NEPG_LP	0x08	/* 16 bit r/o	Next Page Link Partner */
+	/* 0x09 - 0x0e:		reserved */
+#define PHY_XMAC_EXT_STAT	0x0f	/* 16 bit r/o	Ext Status Register */
+#define PHY_XMAC_RES_ABI	0x10	/* 16 bit r/o	PHY Resolved Ability */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Broadcom-PHY Registers, indirect addressed over XMAC
+ */
+#define PHY_BCOM_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define PHY_BCOM_STAT		0x01	/* 16 bit r/o	PHY Status Register */
+#define PHY_BCOM_ID0		0x02	/* 16 bit r/o	PHY ID0 Register */
+#define PHY_BCOM_ID1		0x03	/* 16 bit r/o	PHY ID1 Register */
+#define PHY_BCOM_AUNE_ADV	0x04	/* 16 bit r/w	Auto-Neg. Advertisement */
+#define PHY_BCOM_AUNE_LP	0x05	/* 16 bit r/o	Link Part Ability Reg */
+#define PHY_BCOM_AUNE_EXP	0x06	/* 16 bit r/o	Auto-Neg. Expansion Reg */
+#define PHY_BCOM_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define PHY_BCOM_NEPG_LP	0x08	/* 16 bit r/o	Next Page Link Partner */
+	/* Broadcom-specific registers */
+#define PHY_BCOM_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Ctrl Reg */
+#define PHY_BCOM_1000T_STAT	0x0a	/* 16 bit r/o	1000Base-T Status Reg */
+	/* 0x0b - 0x0e:		reserved */
+#define PHY_BCOM_EXT_STAT	0x0f	/* 16 bit r/o	Extended Status Reg */
+#define PHY_BCOM_P_EXT_CTRL	0x10	/* 16 bit r/w	PHY Extended Ctrl Reg */
+#define PHY_BCOM_P_EXT_STAT	0x11	/* 16 bit r/o	PHY Extended Stat Reg */
+#define PHY_BCOM_RE_CTR		0x12	/* 16 bit r/w	Receive Error Counter */
+#define PHY_BCOM_FC_CTR		0x13	/* 16 bit r/w	False Carrier Sense Cnt */
+#define PHY_BCOM_RNO_CTR	0x14	/* 16 bit r/w	Receiver NOT_OK Cnt */
+	/* 0x15 - 0x17:		reserved */
+#define PHY_BCOM_AUX_CTRL	0x18	/* 16 bit r/w	Auxiliary Control Reg */
+#define PHY_BCOM_AUX_STAT	0x19	/* 16 bit r/o	Auxiliary Stat Summary */
+#define PHY_BCOM_INT_STAT	0x1a	/* 16 bit r/o	Interrupt Status Reg */
+#define PHY_BCOM_INT_MASK	0x1b	/* 16 bit r/w	Interrupt Mask Reg */
+	/* 0x1c:		reserved */
+	/* 0x1d - 0x1f:		test registers */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Marvel-PHY Registers, indirect addressed over GMAC
+ */
+#define PHY_MARV_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define PHY_MARV_STAT		0x01	/* 16 bit r/o	PHY Status Register */
+#define PHY_MARV_ID0		0x02	/* 16 bit r/o	PHY ID0 Register */
+#define PHY_MARV_ID1		0x03	/* 16 bit r/o	PHY ID1 Register */
+#define PHY_MARV_AUNE_ADV	0x04	/* 16 bit r/w	Auto-Neg. Advertisement */
+#define PHY_MARV_AUNE_LP	0x05	/* 16 bit r/o	Link Part Ability Reg */
+#define PHY_MARV_AUNE_EXP	0x06	/* 16 bit r/o	Auto-Neg. Expansion Reg */
+#define PHY_MARV_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define PHY_MARV_NEPG_LP	0x08	/* 16 bit r/o	Next Page Link Partner */
+	/* Marvel-specific registers */
+#define PHY_MARV_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Ctrl Reg */
+#define PHY_MARV_1000T_STAT	0x0a	/* 16 bit r/o	1000Base-T Status Reg */
+	/* 0x0b - 0x0e:		reserved */
+#define PHY_MARV_EXT_STAT	0x0f	/* 16 bit r/o	Extended Status Reg */
+#define PHY_MARV_PHY_CTRL	0x10	/* 16 bit r/w	PHY Specific Ctrl Reg */
+#define PHY_MARV_PHY_STAT	0x11	/* 16 bit r/o	PHY Specific Stat Reg */
+#define PHY_MARV_INT_MASK	0x12	/* 16 bit r/w	Interrupt Mask Reg */
+#define PHY_MARV_INT_STAT	0x13	/* 16 bit r/o	Interrupt Status Reg */
+#define PHY_MARV_EXT_CTRL	0x14	/* 16 bit r/w	Ext. PHY Specific Ctrl */
+#define PHY_MARV_RXE_CNT	0x15	/* 16 bit r/w	Receive Error Counter */
+#define PHY_MARV_EXT_ADR	0x16	/* 16 bit r/w	Ext. Ad. for Cable Diag. */
+	/* 0x17:		reserved */
+#define PHY_MARV_LED_CTRL	0x18	/* 16 bit r/w	LED Control Reg */
+#define PHY_MARV_LED_OVER	0x19	/* 16 bit r/w	Manual LED Override Reg */
+#define PHY_MARV_EXT_CTRL_2	0x1a	/* 16 bit r/w	Ext. PHY Specific Ctrl 2 */
+#define PHY_MARV_EXT_P_STAT	0x1b	/* 16 bit r/w	Ext. PHY Spec. Stat Reg */
+#define PHY_MARV_CABLE_DIAG	0x1c	/* 16 bit r/o	Cable Diagnostic Reg */
+	/* 0x1d - 0x1f:		reserved */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * Level One-PHY Registers, indirect addressed over XMAC
+ */
+#define PHY_LONE_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define PHY_LONE_STAT		0x01	/* 16 bit r/o	PHY Status Register */
+#define PHY_LONE_ID0		0x02	/* 16 bit r/o	PHY ID0 Register */
+#define PHY_LONE_ID1		0x03	/* 16 bit r/o	PHY ID1 Register */
+#define PHY_LONE_AUNE_ADV	0x04	/* 16 bit r/w	Auto-Neg. Advertisement */
+#define PHY_LONE_AUNE_LP	0x05	/* 16 bit r/o	Link Part Ability Reg */
+#define PHY_LONE_AUNE_EXP	0x06	/* 16 bit r/o	Auto-Neg. Expansion Reg */
+#define PHY_LONE_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define PHY_LONE_NEPG_LP	0x08	/* 16 bit r/o	Next Page Link Partner */
+	/* Level One-specific registers */
+#define PHY_LONE_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Control Reg*/
+#define PHY_LONE_1000T_STAT	0x0a	/* 16 bit r/o	1000Base-T Status Reg */
+	/* 0x0b -0x0e:		reserved */
+#define PHY_LONE_EXT_STAT	0x0f	/* 16 bit r/o	Extended Status Reg */
+#define PHY_LONE_PORT_CFG	0x10	/* 16 bit r/w	Port Configuration Reg*/
+#define PHY_LONE_Q_STAT		0x11	/* 16 bit r/o	Quick Status Reg */
+#define PHY_LONE_INT_ENAB	0x12	/* 16 bit r/w	Interrupt Enable Reg */
+#define PHY_LONE_INT_STAT	0x13	/* 16 bit r/o	Interrupt Status Reg */
+#define PHY_LONE_LED_CFG	0x14	/* 16 bit r/w	LED Configuration Reg */
+#define PHY_LONE_PORT_CTRL	0x15	/* 16 bit r/w	Port Control Reg */
+#define PHY_LONE_CIM		0x16	/* 16 bit r/o	CIM Reg */
+	/* 0x17 -0x1c:		reserved */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * National-PHY Registers, indirect addressed over XMAC
+ */
+#define PHY_NAT_CTRL		0x00	/* 16 bit r/w	PHY Control Register */
+#define PHY_NAT_STAT		0x01	/* 16 bit r/w	PHY Status Register */
+#define PHY_NAT_ID0			0x02	/* 16 bit r/o	PHY ID0 Register */
+#define PHY_NAT_ID1			0x03	/* 16 bit r/o	PHY ID1 Register */
+#define PHY_NAT_AUNE_ADV	0x04	/* 16 bit r/w	Auto-Neg. Advertisement */
+#define PHY_NAT_AUNE_LP		0x05	/* 16 bit r/o	Link Partner Ability Reg */
+#define PHY_NAT_AUNE_EXP	0x06	/* 16 bit r/o	Auto-Neg. Expansion Reg */
+#define PHY_NAT_NEPG		0x07	/* 16 bit r/w	Next Page Register */
+#define PHY_NAT_NEPG_LP		0x08	/* 16 bit r/o	Next Page Link Partner Reg */
+	/* National-specific registers */
+#define PHY_NAT_1000T_CTRL	0x09	/* 16 bit r/w	1000Base-T Control Reg */
+#define PHY_NAT_1000T_STAT	0x0a	/* 16 bit r/o	1000Base-T Status Reg */
+	/* 0x0b -0x0e:		reserved */
+#define PHY_NAT_EXT_STAT	0x0f	/* 16 bit r/o	Extended Status Register */
+#define PHY_NAT_EXT_CTRL1	0x10	/* 16 bit r/o	Extended Control Reg1 */
+#define PHY_NAT_Q_STAT1		0x11	/* 16 bit r/o	Quick Status Reg1 */
+#define PHY_NAT_10B_OP		0x12	/* 16 bit r/o	10Base-T Operations Reg */
+#define PHY_NAT_EXT_CTRL2	0x13	/* 16 bit r/o	Extended Control Reg1 */
+#define PHY_NAT_Q_STAT2		0x14	/* 16 bit r/o	Quick Status Reg2 */
+	/* 0x15 -0x18:		reserved */
+#define PHY_NAT_PHY_ADDR	0x19	/* 16 bit r/o	PHY Address Register */
+
+
+/*----------------------------------------------------------------------------*/
+
+/*
+ * PHY bit definitions
+ * Bits defined as PHY_X_..., PHY_B_..., PHY_L_... or PHY_N_... are
+ * XMAC/Broadcom/LevelOne/National/Marvell-specific.
+ * All other are general.
+ */
+
+/*****  PHY_XMAC_CTRL	16 bit r/w	PHY Control Register *****/
+/*****  PHY_BCOM_CTRL	16 bit r/w	PHY Control Register *****/
+/*****  PHY_MARV_CTRL	16 bit r/w	PHY Status Register *****/
+/*****  PHY_LONE_CTRL	16 bit r/w	PHY Control Register *****/
+#define PHY_CT_RESET	(1<<15)	/* Bit 15: (sc)	clear all PHY related regs */
+#define PHY_CT_LOOP		(1<<14)	/* Bit 14:	enable Loopback over PHY */
+#define PHY_CT_SPS_LSB	(1<<13) /* Bit 13: (BC,L1) Speed select, lower bit */
+#define PHY_CT_ANE		(1<<12)	/* Bit 12:	Auto-Negotiation Enabled */
+#define PHY_CT_PDOWN	(1<<11)	/* Bit 11: (BC,L1) Power Down Mode */
+#define PHY_CT_ISOL		(1<<10)	/* Bit 10: (BC,L1) Isolate Mode */
+#define PHY_CT_RE_CFG	(1<<9)	/* Bit  9: (sc) Restart Auto-Negotiation */
+#define PHY_CT_DUP_MD	(1<<8)	/* Bit  8:	Duplex Mode */
+#define PHY_CT_COL_TST	(1<<7)	/* Bit  7: (BC,L1) Collision Test enabled */
+#define PHY_CT_SPS_MSB	(1<<6)	/* Bit  6: (BC,L1) Speed select, upper bit */
+								/* Bit  5..0:	reserved */
+
+#define PHY_CT_SP1000	PHY_CT_SPS_MSB	/* enable speed of 1000 Mbps */
+#define PHY_CT_SP100	PHY_CT_SPS_LSB	/* enable speed of  100 Mbps */
+#define PHY_CT_SP10		(0)				/* enable speed of   10 Mbps */
+
+
+/*****  PHY_XMAC_STAT	16 bit r/w	PHY Status Register *****/
+/*****  PHY_BCOM_STAT	16 bit r/w	PHY Status Register *****/
+/*****  PHY_MARV_STAT	16 bit r/w	PHY Status Register *****/
+/*****  PHY_LONE_STAT	16 bit r/w	PHY Status Register *****/
+								/* Bit 15..9:	reserved */
+				/*	(BC/L1) 100/10 Mbps cap bits ignored*/
+#define PHY_ST_EXT_ST	(1<<8)	/* Bit  8:	Extended Status Present */
+								/* Bit  7:	reserved */
+#define PHY_ST_PRE_SUP	(1<<6)	/* Bit  6: (BC/L1) preamble suppression */
+#define PHY_ST_AN_OVER	(1<<5)	/* Bit  5:	Auto-Negotiation Over */
+#define PHY_ST_REM_FLT	(1<<4)	/* Bit  4:	Remote Fault Condition Occured */
+#define PHY_ST_AN_CAP	(1<<3)	/* Bit  3:	Auto-Negotiation Capability */
+#define PHY_ST_LSYNC	(1<<2)	/* Bit  2:	Link Synchronized */
+#define PHY_ST_JAB_DET	(1<<1)	/* Bit  1: (BC/L1) Jabber Detected */
+#define PHY_ST_EXT_REG	(1<<0)	/* Bit  0:	Extended Register available */
+
+
+/*****	PHY_XMAC_ID1		16 bit r/o	PHY ID1 Register */
+/*****	PHY_BCOM_ID1		16 bit r/o	PHY ID1 Register */
+/*****	PHY_MARV_ID1		16 bit r/o	PHY ID1 Register */
+/*****	PHY_LONE_ID1		16 bit r/o	PHY ID1 Register */
+#define PHY_I1_OUI_MSK	(0x3f<<10)	/* Bit 15..10:	Organization Unique ID */
+#define PHY_I1_MOD_NUM	(0x3f<<4)	/* Bit  9.. 4:	Model Number */
+#define PHY_I1_REV_MSK	0x0f		/* Bit  3.. 0:	Revision Number */
+
+/* different Broadcom PHY Ids */
+#define PHY_BCOM_ID1_A1		0x6041
+#define PHY_BCOM_ID1_B2		0x6043
+#define PHY_BCOM_ID1_C0		0x6044
+#define PHY_BCOM_ID1_C5		0x6047
+
+
+/*****  PHY_XMAC_AUNE_ADV	16 bit r/w	Auto-Negotiation Advertisement *****/
+/*****  PHY_XMAC_AUNE_LP	16 bit r/o	Link Partner Ability Reg *****/
+#define PHY_AN_NXT_PG	(1<<15)	/* Bit 15:	Request Next Page */
+#define PHY_X_AN_ACK	(1<<14)	/* Bit 14: (ro)	Acknowledge Received */
+#define PHY_X_AN_RFB	(3<<12)	/* Bit 13..12:	Remote Fault Bits */
+								/* Bit 11.. 9:	reserved */
+#define PHY_X_AN_PAUSE	(3<<7)	/* Bit  8.. 7:	Pause Bits */
+#define PHY_X_AN_HD		(1<<6)	/* Bit  6:	Half Duplex */
+#define PHY_X_AN_FD		(1<<5)	/* Bit  5:	Full Duplex */
+								/* Bit  4.. 0:	reserved */
+
+/*****  PHY_BCOM_AUNE_ADV	16 bit r/w	Auto-Negotiation Advertisement *****/
+/*****  PHY_BCOM_AUNE_LP	16 bit r/o	Link Partner Ability Reg *****/
+/*	PHY_AN_NXT_PG		(see XMAC) Bit 15:	Request Next Page */
+								/* Bit 14:	reserved */
+#define PHY_B_AN_RF		(1<<13)	/* Bit 13:	Remote Fault */
+								/* Bit 12:	reserved */
+#define PHY_B_AN_ASP	(1<<11)	/* Bit 11:	Asymmetric Pause */
+#define PHY_B_AN_PC		(1<<10)	/* Bit 10:	Pause Capable */
+								/* Bit  9..5:	100/10 BT cap bits ingnored */
+#define PHY_B_AN_SEL	0x1f	/* Bit 4..0:	Selector Field, 00001=Ethernet*/
+
+/*****  PHY_LONE_AUNE_ADV	16 bit r/w	Auto-Negotiation Advertisement *****/
+/*****  PHY_LONE_AUNE_LP	16 bit r/o	Link Partner Ability Reg *****/
+/*	PHY_AN_NXT_PG		(see XMAC) Bit 15:	Request Next Page */
+								/* Bit 14:	reserved */
+#define PHY_L_AN_RF		(1<<13)	/* Bit 13:	Remote Fault */
+								/* Bit 12:	reserved */
+#define PHY_L_AN_ASP	(1<<11)	/* Bit 11:	Asymmetric Pause */
+#define PHY_L_AN_PC		(1<<10)	/* Bit 10:	Pause Capable */
+								/* Bit  9..5:	100/10 BT cap bits ingnored */
+#define PHY_L_AN_SEL	0x1f	/* Bit 4..0:	Selector Field, 00001=Ethernet*/
+
+/*****  PHY_NAT_AUNE_ADV	16 bit r/w	Auto-Negotiation Advertisement *****/
+/*****  PHY_NAT_AUNE_LP		16 bit r/o	Link Partner Ability Reg *****/
+/*	PHY_AN_NXT_PG		(see XMAC) Bit 15:	Request Next Page */
+								/* Bit 14:	reserved */
+#define PHY_N_AN_RF		(1<<13)	/* Bit 13:	Remote Fault */
+								/* Bit 12:	reserved */
+#define PHY_N_AN_100F	(1<<11)	/* Bit 11:	100Base-T2 FD Support */
+#define PHY_N_AN_100H	(1<<10)	/* Bit 10:	100Base-T2 HD Support */
+								/* Bit  9..5:	100/10 BT cap bits ingnored */
+#define PHY_N_AN_SEL	0x1f	/* Bit 4..0:	Selector Field, 00001=Ethernet*/
+
+/* field type definition for PHY_x_AN_SEL */
+#define PHY_SEL_TYPE	0x01	/* 00001 = Ethernet */
+
+/*****  PHY_XMAC_AUNE_EXP	16 bit r/o	Auto-Negotiation Expansion Reg *****/
+								/* Bit 15..4:	reserved */
+#define PHY_ANE_LP_NP	(1<<3)	/* Bit  3:	Link Partner can Next Page */
+#define PHY_ANE_LOC_NP	(1<<2)	/* Bit  2:	Local PHY can Next Page */
+#define PHY_ANE_RX_PG	(1<<1)	/* Bit  1:	Page Received */
+								/* Bit  0:	reserved */
+
+/*****  PHY_BCOM_AUNE_EXP	16 bit r/o	Auto-Negotiation Expansion Reg *****/
+/*****  PHY_LONE_AUNE_EXP	16 bit r/o	Auto-Negotiation Expansion Reg *****/
+/*****  PHY_MARV_AUNE_EXP	16 bit r/o	Auto-Negotiation Expansion Reg *****/
+								/* Bit 15..5:	reserved */
+#define PHY_ANE_PAR_DF	(1<<4)	/* Bit  4:	Parallel Detection Fault */
+/*	PHY_ANE_LP_NP		(see XMAC) Bit  3:	Link Partner can Next Page */
+/*	PHY_ANE_LOC_NP		(see XMAC) Bit  2:	Local PHY can Next Page */
+/*	PHY_ANE_RX_PG		(see XMAC) Bit  1:	Page Received */
+#define PHY_ANE_LP_CAP	(1<<0)	/* Bit  0:	Link Partner Auto-Neg. Cap. */ 	
+
+/*****  PHY_XMAC_NEPG		16 bit r/w	Next Page Register *****/
+/*****  PHY_BCOM_NEPG		16 bit r/w	Next Page Register *****/
+/*****  PHY_LONE_NEPG		16 bit r/w	Next Page Register *****/
+/*****  PHY_XMAC_NEPG_LP	16 bit r/o	Next Page Link Partner *****/
+/*****  PHY_BCOM_NEPG_LP	16 bit r/o	Next Page Link Partner *****/
+/*****  PHY_LONE_NEPG_LP	16 bit r/o	Next Page Link Partner *****/
+#define PHY_NP_MORE		(1<<15)	/* Bit 15:	More, Next Pages to follow */
+#define PHY_NP_ACK1		(1<<14)	/* Bit 14: (ro)	Ack1, for receiving a message */
+#define PHY_NP_MSG_VAL	(1<<13)	/* Bit 13:	Message Page valid */
+#define PHY_NP_ACK2		(1<<12)	/* Bit 12:	Ack2, comply with msg content */
+#define PHY_NP_TOG		(1<<11)	/* Bit 11:	Toggle Bit, ensure sync */
+#define PHY_NP_MSG		0x07ff	/* Bit 10..0:	Message from/to Link Partner */
+
+/*
+ * XMAC-Specific
+ */
+/*****  PHY_XMAC_EXT_STAT	16 bit r/w	Extended Status Register *****/
+#define PHY_X_EX_FD		(1<<15)	/* Bit 15:	Device Supports Full Duplex */
+#define PHY_X_EX_HD		(1<<14)	/* Bit 14:	Device Supports Half Duplex */
+								/* Bit 13..0:	reserved */
+
+/*****  PHY_XMAC_RES_ABI	16 bit r/o	PHY Resolved Ability *****/
+								/* Bit 15..9:	reserved */
+#define PHY_X_RS_PAUSE	(3<<7)	/* Bit  8..7:	selected Pause Mode */
+#define PHY_X_RS_HD		(1<<6)	/* Bit  6:	Half Duplex Mode selected */
+#define PHY_X_RS_FD		(1<<5)	/* Bit  5:	Full Duplex Mode selected */
+#define PHY_X_RS_ABLMIS (1<<4)	/* Bit  4:	duplex or pause cap mismatch */
+#define PHY_X_RS_PAUMIS (1<<3)	/* Bit  3:	pause capability mismatch */
+								/* Bit  2..0:	reserved */
+/*
+ * Remote Fault Bits (PHY_X_AN_RFB) encoding
+ */
+#define X_RFB_OK		(0<<12)	/* Bit 13..12	No errors, Link OK */
+#define X_RFB_LF		(1<<12)	/* Bit 13..12	Link Failure */
+#define X_RFB_OFF		(2<<12)	/* Bit 13..12	Offline */
+#define X_RFB_AN_ERR	(3<<12)	/* Bit 13..12	Auto-Negotiation Error */
+
+/*
+ * Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding
+ */
+#define PHY_X_P_NO_PAUSE	(0<<7)	/* Bit  8..7:	no Pause Mode */
+#define PHY_X_P_SYM_MD		(1<<7)	/* Bit  8..7:	symmetric Pause Mode */
+#define PHY_X_P_ASYM_MD		(2<<7)	/* Bit  8..7:	asymmetric Pause Mode */
+#define PHY_X_P_BOTH_MD		(3<<7)	/* Bit  8..7:	both Pause Mode */
+
+
+/*
+ * Broadcom-Specific
+ */
+/*****  PHY_BCOM_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+#define PHY_B_1000C_TEST	(7<<13)	/* Bit 15..13:	Test Modes */
+#define PHY_B_1000C_MSE		(1<<12)	/* Bit 12:	Master/Slave Enable */
+#define PHY_B_1000C_MSC		(1<<11)	/* Bit 11:	M/S Configuration */
+#define PHY_B_1000C_RD		(1<<10)	/* Bit 10:	Repeater/DTE */
+#define PHY_B_1000C_AFD		(1<<9)	/* Bit  9:	Advertise Full Duplex */
+#define PHY_B_1000C_AHD		(1<<8)	/* Bit  8:	Advertise Half Duplex */
+									/* Bit  7..0:	reserved */
+
+/*****  PHY_BCOM_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+/*****  PHY_MARV_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+#define PHY_B_1000S_MSF		(1<<15)	/* Bit 15:	Master/Slave Fault */
+#define PHY_B_1000S_MSR		(1<<14)	/* Bit 14:	Master/Slave Result */
+#define PHY_B_1000S_LRS		(1<<13)	/* Bit 13:	Local Receiver Status */
+#define PHY_B_1000S_RRS		(1<<12)	/* Bit 12:	Remote Receiver Status */
+#define PHY_B_1000S_LP_FD	(1<<11)	/* Bit 11:	Link Partner can FD */
+#define PHY_B_1000S_LP_HD	(1<<10)	/* Bit 10:	Link Partner can HD */
+									/* Bit  9..8:	reserved */
+#define PHY_B_1000S_IEC		0xff	/* Bit  7..0:	Idle Error Count */
+
+/*****  PHY_BCOM_EXT_STAT	16 bit r/o	Extended Status Register *****/
+#define PHY_B_ES_X_FD_CAP	(1<<15)	/* Bit 15:	1000Base-X FD capable */
+#define PHY_B_ES_X_HD_CAP	(1<<14)	/* Bit 14:	1000Base-X HD capable */
+#define PHY_B_ES_T_FD_CAP	(1<<13)	/* Bit 13:	1000Base-T FD capable */
+#define PHY_B_ES_T_HD_CAP	(1<<12)	/* Bit 12:	1000Base-T HD capable */
+									/* Bit 11..0:	reserved */
+
+/*****  PHY_BCOM_P_EXT_CTRL	16 bit r/w	PHY Extended Control Reg *****/
+#define PHY_B_PEC_MAC_PHY	(1<<15)	/* Bit 15:	10BIT/GMI-Interface */
+#define PHY_B_PEC_DIS_CROSS	(1<<14)	/* Bit 14:	Disable MDI Crossover */
+#define PHY_B_PEC_TX_DIS	(1<<13)	/* Bit 13:	Tx output Disabled */
+#define PHY_B_PEC_INT_DIS	(1<<12)	/* Bit 12:	Interrupts Disabled */
+#define PHY_B_PEC_F_INT		(1<<11)	/* Bit 11:	Force Interrupt */
+#define PHY_B_PEC_BY_45		(1<<10)	/* Bit 10:	Bypass 4B5B-Decoder */
+#define PHY_B_PEC_BY_SCR	(1<<9)	/* Bit  9:	Bypass Scrambler */
+#define PHY_B_PEC_BY_MLT3	(1<<8)	/* Bit  8:	Bypass MLT3 Encoder */
+#define PHY_B_PEC_BY_RXA	(1<<7)	/* Bit  7:	Bypass Rx Alignm. */
+#define PHY_B_PEC_RES_SCR	(1<<6)	/* Bit  6:	Reset Scrambler */
+#define PHY_B_PEC_EN_LTR	(1<<5)	/* Bit  5:	Ena LED Traffic Mode */
+#define PHY_B_PEC_LED_ON	(1<<4)	/* Bit  4:	Force LED's on */
+#define PHY_B_PEC_LED_OFF	(1<<3)	/* Bit  3:	Force LED's off */
+#define PHY_B_PEC_EX_IPG	(1<<2)	/* Bit  2:	Extend Tx IPG Mode */
+#define PHY_B_PEC_3_LED		(1<<1)	/* Bit  1:	Three Link LED mode */
+#define PHY_B_PEC_HIGH_LA	(1<<0)	/* Bit  0:	GMII FIFO Elasticy */
+
+/*****  PHY_BCOM_P_EXT_STAT	16 bit r/o	PHY Extended Status Reg *****/
+									/* Bit 15..14:	reserved */
+#define PHY_B_PES_CROSS_STAT	(1<<13)	/* Bit 13:	MDI Crossover Status */
+#define PHY_B_PES_INT_STAT	(1<<12)	/* Bit 12:	Interrupt Status */
+#define PHY_B_PES_RRS		(1<<11)	/* Bit 11:	Remote Receiver Stat. */
+#define PHY_B_PES_LRS		(1<<10)	/* Bit 10:	Local Receiver Stat. */
+#define PHY_B_PES_LOCKED	(1<<9)	/* Bit  9:	Locked */
+#define PHY_B_PES_LS		(1<<8)	/* Bit  8:	Link Status */
+#define PHY_B_PES_RF		(1<<7)	/* Bit  7:	Remote Fault */
+#define PHY_B_PES_CE_ER		(1<<6)	/* Bit  6:	Carrier Ext Error */
+#define PHY_B_PES_BAD_SSD	(1<<5)	/* Bit  5:	Bad SSD */
+#define PHY_B_PES_BAD_ESD	(1<<4)	/* Bit  4:	Bad ESD */
+#define PHY_B_PES_RX_ER		(1<<3)	/* Bit  3:	Receive Error */
+#define PHY_B_PES_TX_ER		(1<<2)	/* Bit  2:	Transmit Error */
+#define PHY_B_PES_LOCK_ER	(1<<1)	/* Bit  1:	Lock Error */
+#define PHY_B_PES_MLT3_ER	(1<<0)	/* Bit  0:	MLT3 code Error */
+
+/*****  PHY_BCOM_FC_CTR		16 bit r/w	False Carrier Counter *****/
+									/* Bit 15..8:	reserved */
+#define PHY_B_FC_CTR		0xff	/* Bit  7..0:	False Carrier Counter */
+
+/*****  PHY_BCOM_RNO_CTR	16 bit r/w	Receive NOT_OK Counter *****/
+#define PHY_B_RC_LOC_MSK	0xff00	/* Bit 15..8:	Local Rx NOT_OK cnt */
+#define PHY_B_RC_REM_MSK	0x00ff	/* Bit  7..0:	Remote Rx NOT_OK cnt */
+
+/*****  PHY_BCOM_AUX_CTRL	16 bit r/w	Auxiliary Control Reg *****/
+#define PHY_B_AC_L_SQE		(1<<15)	/* Bit 15:	Low Squelch */
+#define PHY_B_AC_LONG_PACK	(1<<14)	/* Bit 14:	Rx Long Packets */
+#define PHY_B_AC_ER_CTRL	(3<<12)	/* Bit 13..12:	Edgerate Control */
+									/* Bit 11:	reserved */
+#define PHY_B_AC_TX_TST		(1<<10) /* Bit 10:	Tx test bit, always 1 */
+									/* Bit  9.. 8:	reserved */
+#define PHY_B_AC_DIS_PRF	(1<<7)	/* Bit  7:	dis part resp filter */
+									/* Bit  6:	reserved */
+#define PHY_B_AC_DIS_PM		(1<<5)	/* Bit  5:	dis power management */
+									/* Bit  4:	reserved */
+#define PHY_B_AC_DIAG		(1<<3)	/* Bit  3:	Diagnostic Mode */
+									/* Bit  2.. 0:	reserved */
+
+/*****  PHY_BCOM_AUX_STAT	16 bit r/o	Auxiliary Status Reg *****/
+#define PHY_B_AS_AN_C		(1<<15)	/* Bit 15:	AutoNeg complete */
+#define PHY_B_AS_AN_CA		(1<<14)	/* Bit 14:	AN Complete Ack */
+#define PHY_B_AS_ANACK_D	(1<<13)	/* Bit 13:	AN Ack Detect */
+#define PHY_B_AS_ANAB_D		(1<<12)	/* Bit 12:	AN Ability Detect */
+#define PHY_B_AS_NPW		(1<<11)	/* Bit 11:	AN Next Page Wait */
+#define PHY_B_AS_AN_RES_MSK	(7<<8)	/* Bit 10..8:	AN HDC */
+#define PHY_B_AS_PDF		(1<<7)	/* Bit  7:	Parallel Detect. Fault */
+#define PHY_B_AS_RF			(1<<6)	/* Bit  6:	Remote Fault */
+#define PHY_B_AS_ANP_R		(1<<5)	/* Bit  5:	AN Page Received */
+#define PHY_B_AS_LP_ANAB	(1<<4)	/* Bit  4:	LP AN Ability */
+#define PHY_B_AS_LP_NPAB	(1<<3)	/* Bit  3:	LP Next Page Ability */
+#define PHY_B_AS_LS			(1<<2)	/* Bit  2:	Link Status */
+#define PHY_B_AS_PRR		(1<<1)	/* Bit  1:	Pause Resolution-Rx */
+#define PHY_B_AS_PRT		(1<<0)	/* Bit  0:	Pause Resolution-Tx */
+
+#define PHY_B_AS_PAUSE_MSK	(PHY_B_AS_PRR | PHY_B_AS_PRT)
+
+/*****  PHY_BCOM_INT_STAT	16 bit r/o	Interrupt Status Reg *****/
+/*****  PHY_BCOM_INT_MASK	16 bit r/w	Interrupt Mask Reg *****/
+									/* Bit 15:	reserved */
+#define PHY_B_IS_PSE		(1<<14)	/* Bit 14:	Pair Swap Error */
+#define PHY_B_IS_MDXI_SC	(1<<13)	/* Bit 13:	MDIX Status Change */
+#define PHY_B_IS_HCT		(1<<12)	/* Bit 12:	counter above 32k */
+#define PHY_B_IS_LCT		(1<<11)	/* Bit 11:	counter above 128 */
+#define PHY_B_IS_AN_PR		(1<<10)	/* Bit 10:	Page Received */
+#define PHY_B_IS_NO_HDCL	(1<<9)	/* Bit  9:	No HCD Link */
+#define PHY_B_IS_NO_HDC		(1<<8)	/* Bit  8:	No HCD */
+#define PHY_B_IS_NEG_USHDC	(1<<7)	/* Bit  7:	Negotiated Unsup. HCD */
+#define PHY_B_IS_SCR_S_ER	(1<<6)	/* Bit  6:	Scrambler Sync Error */
+#define PHY_B_IS_RRS_CHANGE	(1<<5)	/* Bit  5:	Remote Rx Stat Change */
+#define PHY_B_IS_LRS_CHANGE	(1<<4)	/* Bit  4:	Local Rx Stat Change */
+#define PHY_B_IS_DUP_CHANGE	(1<<3)	/* Bit  3:	Duplex Mode Change */
+#define PHY_B_IS_LSP_CHANGE	(1<<2)	/* Bit  2:	Link Speed Change */
+#define PHY_B_IS_LST_CHANGE	(1<<1)	/* Bit  1:	Link Status Changed */
+#define PHY_B_IS_CRC_ER		(1<<0)	/* Bit  0:	CRC Error */
+
+#define PHY_B_DEF_MSK	(~(PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE))
+
+/* Pause Bits (PHY_B_AN_ASP and PHY_B_AN_PC) encoding */
+#define PHY_B_P_NO_PAUSE	(0<<10)	/* Bit 11..10:	no Pause Mode */
+#define PHY_B_P_SYM_MD		(1<<10)	/* Bit 11..10:	symmetric Pause Mode */
+#define PHY_B_P_ASYM_MD		(2<<10)	/* Bit 11..10:	asymmetric Pause Mode */
+#define PHY_B_P_BOTH_MD		(3<<10)	/* Bit 11..10:	both Pause Mode */
+
+/*
+ * Resolved Duplex mode and Capabilities (Aux Status Summary Reg)
+ */
+#define PHY_B_RES_1000FD	(7<<8)	/* Bit 10..8:	1000Base-T Full Dup. */
+#define PHY_B_RES_1000HD	(6<<8)	/* Bit 10..8:	1000Base-T Half Dup. */
+/* others: 100/10: invalid for us */
+
+/*
+ * Level One-Specific
+ */
+/*****  PHY_LONE_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+#define PHY_L_1000C_TEST	(7<<13)	/* Bit 15..13:	Test Modes */
+#define PHY_L_1000C_MSE		(1<<12)	/* Bit 12:	Master/Slave Enable */
+#define PHY_L_1000C_MSC		(1<<11)	/* Bit 11:	M/S Configuration */
+#define PHY_L_1000C_RD		(1<<10)	/* Bit 10:	Repeater/DTE */
+#define PHY_L_1000C_AFD		(1<<9)	/* Bit  9:	Advertise Full Duplex */
+#define PHY_L_1000C_AHD		(1<<8)	/* Bit  8:	Advertise Half Duplex */
+									/* Bit  7..0:	reserved */
+
+/*****  PHY_LONE_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+#define PHY_L_1000S_MSF		(1<<15)	/* Bit 15:	Master/Slave Fault */
+#define PHY_L_1000S_MSR		(1<<14)	/* Bit 14:	Master/Slave Result */
+#define PHY_L_1000S_LRS		(1<<13)	/* Bit 13:	Local Receiver Status */
+#define PHY_L_1000S_RRS		(1<<12)	/* Bit 12:	Remote Receiver Status */
+#define PHY_L_1000S_LP_FD	(1<<11)	/* Bit 11:	Link Partner can FD */
+#define PHY_L_1000S_LP_HD	(1<<10)	/* Bit 10:	Link Partner can HD */
+									/* Bit  9..8:	reserved */
+#define PHY_B_1000S_IEC		0xff	/* Bit  7..0:	Idle Error Count */
+
+/*****  PHY_LONE_EXT_STAT	16 bit r/o	Extended Status Register *****/
+#define PHY_L_ES_X_FD_CAP	(1<<15)	/* Bit 15:	1000Base-X FD capable */
+#define PHY_L_ES_X_HD_CAP	(1<<14)	/* Bit 14:	1000Base-X HD capable */
+#define PHY_L_ES_T_FD_CAP	(1<<13)	/* Bit 13:	1000Base-T FD capable */
+#define PHY_L_ES_T_HD_CAP	(1<<12)	/* Bit 12:	1000Base-T HD capable */
+									/* Bit 11..0:	reserved */
+
+/*****  PHY_LONE_PORT_CFG	16 bit r/w	Port Configuration Reg *****/
+#define PHY_L_PC_REP_MODE	(1<<15)	/* Bit 15:	Repeater Mode */
+									/* Bit 14:	reserved */
+#define PHY_L_PC_TX_DIS		(1<<13)	/* Bit 13:	Tx output Disabled */
+#define PHY_L_PC_BY_SCR		(1<<12)	/* Bit 12:	Bypass Scrambler */
+#define PHY_L_PC_BY_45		(1<<11)	/* Bit 11:	Bypass 4B5B-Decoder */
+#define PHY_L_PC_JAB_DIS	(1<<10)	/* Bit 10:	Jabber Disabled */
+#define PHY_L_PC_SQE		(1<<9)	/* Bit  9:	Enable Heartbeat */
+#define PHY_L_PC_TP_LOOP	(1<<8)	/* Bit  8:	TP Loopback */
+#define PHY_L_PC_SSS		(1<<7)	/* Bit  7:	Smart Speed Selection */
+#define PHY_L_PC_FIFO_SIZE	(1<<6)	/* Bit  6:	FIFO Size */
+#define PHY_L_PC_PRE_EN		(1<<5)	/* Bit  5:	Preamble Enable */
+#define PHY_L_PC_CIM		(1<<4)	/* Bit  4:	Carrier Integrity Mon */
+#define PHY_L_PC_10_SER		(1<<3)	/* Bit  3:	Use Serial Output */
+#define PHY_L_PC_ANISOL		(1<<2)	/* Bit  2:	Unisolate Port */
+#define PHY_L_PC_TEN_BIT	(1<<1)	/* Bit  1:	10bit iface mode on */
+#define PHY_L_PC_ALTCLOCK	(1<<0)	/* Bit  0: (ro)	ALTCLOCK Mode on */
+
+/*****  PHY_LONE_Q_STAT		16 bit r/o	Quick Status Reg *****/
+#define PHY_L_QS_D_RATE		(3<<14)	/* Bit 15..14:	Data Rate */
+#define PHY_L_QS_TX_STAT	(1<<13)	/* Bit 13:	Transmitting */
+#define PHY_L_QS_RX_STAT	(1<<12)	/* Bit 12:	Receiving */
+#define PHY_L_QS_COL_STAT	(1<<11)	/* Bit 11:	Collision */
+#define PHY_L_QS_L_STAT		(1<<10)	/* Bit 10:	Link is up */
+#define PHY_L_QS_DUP_MOD	(1<<9)	/* Bit  9:	Full/Half Duplex */
+#define PHY_L_QS_AN			(1<<8)	/* Bit  8:	AutoNeg is On */
+#define PHY_L_QS_AN_C		(1<<7)	/* Bit  7:	AN is Complete */
+#define PHY_L_QS_LLE		(7<<4)	/* Bit  6:	Line Length Estim. */
+#define PHY_L_QS_PAUSE		(1<<3)	/* Bit  3:	LP advertised Pause */
+#define PHY_L_QS_AS_PAUSE	(1<<2)	/* Bit  2:	LP adv. asym. Pause */
+#define PHY_L_QS_ISOLATE	(1<<1)	/* Bit  1:	CIM Isolated */
+#define PHY_L_QS_EVENT		(1<<0)	/* Bit  0:	Event has occurred */
+
+/*****  PHY_LONE_INT_ENAB	16 bit r/w	Interrupt Enable Reg *****/
+/*****  PHY_LONE_INT_STAT	16 bit r/o	Interrupt Status Reg *****/
+									/* Bit 15..14:	reserved */
+#define PHY_L_IS_AN_F		(1<<13)	/* Bit 13:	Auto-Negotiation fault */
+									/* Bit 12:	not described */
+#define PHY_L_IS_CROSS		(1<<11)	/* Bit 11:	Crossover used */
+#define PHY_L_IS_POL		(1<<10)	/* Bit 10:	Polarity correct. used */
+#define PHY_L_IS_SS			(1<<9)	/* Bit  9:	Smart Speed Downgrade */
+#define PHY_L_IS_CFULL		(1<<8)	/* Bit  8:	Counter Full */
+#define PHY_L_IS_AN_C		(1<<7)	/* Bit  7:	AutoNeg Complete */
+#define PHY_L_IS_SPEED		(1<<6)	/* Bit  6:	Speed Changed */
+#define PHY_L_IS_DUP		(1<<5)	/* Bit  5:	Duplex Changed */
+#define PHY_L_IS_LS			(1<<4)	/* Bit  4:	Link Status Changed */
+#define PHY_L_IS_ISOL		(1<<3)	/* Bit  3:	Isolate Occured */
+#define PHY_L_IS_MDINT		(1<<2)	/* Bit  2: (ro)	STAT: MII Int Pending */
+#define PHY_L_IS_INTEN		(1<<1)	/* Bit  1:	ENAB: Enable IRQs */
+#define PHY_L_IS_FORCE		(1<<0)	/* Bit  0:	ENAB: Force Interrupt */
+
+/* int. mask */
+#define PHY_L_DEF_MSK		(PHY_L_IS_LS | PHY_L_IS_ISOL | PHY_L_IS_INTEN)
+
+/*****  PHY_LONE_LED_CFG	16 bit r/w	LED Configuration Reg *****/
+#define PHY_L_LC_LEDC		(3<<14)	/* Bit 15..14:	Col/Blink/On/Off */
+#define PHY_L_LC_LEDR		(3<<12)	/* Bit 13..12:	Rx/Blink/On/Off */
+#define PHY_L_LC_LEDT		(3<<10)	/* Bit 11..10:	Tx/Blink/On/Off */
+#define PHY_L_LC_LEDG		(3<<8)	/* Bit  9..8:	Giga/Blink/On/Off */
+#define PHY_L_LC_LEDS		(3<<6)	/* Bit  7..6:	10-100/Blink/On/Off */
+#define PHY_L_LC_LEDL		(3<<4)	/* Bit  5..4:	Link/Blink/On/Off */
+#define PHY_L_LC_LEDF		(3<<2)	/* Bit  3..2:	Duplex/Blink/On/Off */
+#define PHY_L_LC_PSTRECH	(1<<1)	/* Bit  1:	Strech LED Pulses */
+#define PHY_L_LC_FREQ		(1<<0)	/* Bit  0:	30/100 ms */
+
+/*****  PHY_LONE_PORT_CTRL	16 bit r/w	Port Control Reg *****/
+#define PHY_L_PC_TX_TCLK	(1<<15)	/* Bit 15:	Enable TX_TCLK */
+									/* Bit 14:	reserved */
+#define PHY_L_PC_ALT_NP		(1<<13)	/* Bit 14:	Alternate Next Page */
+#define PHY_L_PC_GMII_ALT	(1<<12)	/* Bit 13:	Alternate GMII driver */
+									/* Bit 11:	reserved */
+#define PHY_L_PC_TEN_CRS	(1<<10)	/* Bit 10:	Extend CRS*/
+									/* Bit  9..0:	not described */
+
+/*****  PHY_LONE_CIM		16 bit r/o	CIM Reg *****/
+#define PHY_L_CIM_ISOL		(255<<8)/* Bit 15..8:	Isolate Count */
+#define PHY_L_CIM_FALSE_CAR	(255<<0)/* Bit  7..0:	False Carrier Count */
+
+
+/*
+ * Pause Bits (PHY_L_AN_ASP and PHY_L_AN_PC) encoding
+ */
+#define PHY_L_P_NO_PAUSE	(0<<10)	/* Bit 11..10:	no Pause Mode */
+#define PHY_L_P_SYM_MD		(1<<10)	/* Bit 11..10:	symmetric Pause Mode */
+#define PHY_L_P_ASYM_MD		(2<<10)	/* Bit 11..10:	asymmetric Pause Mode */
+#define PHY_L_P_BOTH_MD		(3<<10)	/* Bit 11..10:	both Pause Mode */
+
+
+/*
+ * National-Specific
+ */
+/*****  PHY_NAT_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+#define PHY_N_1000C_TEST	(7<<13)	/* Bit 15..13:	Test Modes */
+#define PHY_N_1000C_MSE		(1<<12)	/* Bit 12:	Master/Slave Enable */
+#define PHY_N_1000C_MSC		(1<<11)	/* Bit 11:	M/S Configuration */
+#define PHY_N_1000C_RD		(1<<10)	/* Bit 10:	Repeater/DTE */
+#define PHY_N_1000C_AFD		(1<<9)	/* Bit  9:	Advertise Full Duplex */
+#define PHY_N_1000C_AHD		(1<<8)	/* Bit  8:	Advertise Half Duplex */
+#define PHY_N_1000C_APC		(1<<7)	/* Bit  7:	Asymmetric Pause Cap. */
+									/* Bit  6..0:	reserved */
+
+/*****  PHY_NAT_1000T_STAT	16 bit r/o	1000Base-T Status Reg *****/
+#define PHY_N_1000S_MSF		(1<<15)	/* Bit 15:	Master/Slave Fault */
+#define PHY_N_1000S_MSR		(1<<14)	/* Bit 14:	Master/Slave Result */
+#define PHY_N_1000S_LRS		(1<<13)	/* Bit 13:	Local Receiver Status */
+#define PHY_N_1000S_RRS		(1<<12)	/* Bit 12:	Remote Receiver Status*/
+#define PHY_N_1000S_LP_FD	(1<<11)	/* Bit 11:	Link Partner can FD */
+#define PHY_N_1000S_LP_HD	(1<<10)	/* Bit 10:	Link Partner can HD */
+#define PHY_N_1000C_LP_APC	(1<<9)	/* Bit  9:	LP Asym. Pause Cap. */
+									/* Bit  8:	reserved */
+#define PHY_N_1000S_IEC		0xff	/* Bit  7..0:	Idle Error Count */
+
+/*****  PHY_NAT_EXT_STAT	16 bit r/o	Extended Status Register *****/
+#define PHY_N_ES_X_FD_CAP	(1<<15)	/* Bit 15:	1000Base-X FD capable */
+#define PHY_N_ES_X_HD_CAP	(1<<14)	/* Bit 14:	1000Base-X HD capable */
+#define PHY_N_ES_T_FD_CAP	(1<<13)	/* Bit 13:	1000Base-T FD capable */
+#define PHY_N_ES_T_HD_CAP	(1<<12)	/* Bit 12:	1000Base-T HD capable */
+									/* Bit 11..0:	reserved */
+
+/* todo: those are still missing */
+/*****  PHY_NAT_EXT_CTRL1	16 bit r/o	Extended Control Reg1 *****/
+/*****  PHY_NAT_Q_STAT1		16 bit r/o	Quick Status Reg1 *****/
+/*****  PHY_NAT_10B_OP		16 bit r/o	10Base-T Operations Reg *****/
+/*****  PHY_NAT_EXT_CTRL2	16 bit r/o	Extended Control Reg1 *****/
+/*****  PHY_NAT_Q_STAT2		16 bit r/o	Quick Status Reg2 *****/
+/*****  PHY_NAT_PHY_ADDR	16 bit r/o	PHY Address Register *****/
+
+/*
+ * Marvell-Specific
+ */
+/*****  PHY_MARV_AUNE_ADV	16 bit r/w	Auto-Negotiation Advertisement *****/
+/*****  PHY_MARV_AUNE_LP	16 bit r/w	Link Part Ability Reg *****/
+#define PHY_M_AN_NXT_PG		BIT_15	/* Request Next Page */
+#define PHY_M_AN_ACK		BIT_14	/* (ro)	Acknowledge Received */
+#define PHY_M_AN_RF			BIT_13	/* Remote Fault */
+									/* Bit 12:	reserved */
+#define PHY_M_AN_ASP		BIT_11	/* Asymmetric Pause */
+#define PHY_M_AN_PC			BIT_10	/* MAC Pause implemented */
+#define PHY_M_AN_100_FD		BIT_8	/* Advertise 100Base-TX Full Duplex */
+#define PHY_M_AN_100_HD		BIT_7	/* Advertise 100Base-TX Half Duplex */
+#define PHY_M_AN_10_FD		BIT_6	/* Advertise 10Base-TX Full Duplex */
+#define PHY_M_AN_10_HD		BIT_5	/* Advertise 10Base-TX Half Duplex */
+
+/* special defines for FIBER (88E1011S only) */
+#define PHY_M_AN_ASP_X		BIT_8	/* Asymmetric Pause */
+#define PHY_M_AN_PC_X		BIT_7	/* MAC Pause implemented */
+#define PHY_M_AN_1000X_AHD	BIT_6	/* Advertise 10000Base-X Half Duplex */
+#define PHY_M_AN_1000X_AFD	BIT_5	/* Advertise 10000Base-X Full Duplex */
+
+/* Pause Bits (PHY_M_AN_ASP_X and PHY_M_AN_PC_X) encoding */
+#define PHY_M_P_NO_PAUSE_X	(0<<7)	/* Bit  8.. 7:	no Pause Mode */
+#define PHY_M_P_SYM_MD_X	(1<<7)	/* Bit  8.. 7:	symmetric Pause Mode */
+#define PHY_M_P_ASYM_MD_X	(2<<7)	/* Bit  8.. 7:	asymmetric Pause Mode */
+#define PHY_M_P_BOTH_MD_X	(3<<7)	/* Bit  8.. 7:	both Pause Mode */
+
+/*****  PHY_MARV_1000T_CTRL	16 bit r/w	1000Base-T Control Reg *****/
+#define PHY_M_1000C_TEST	(7<<13)	/* Bit 15..13:	Test Modes */
+#define PHY_M_1000C_MSE		(1<<12)	/* Bit 12:	Manual Master/Slave Enable */
+#define PHY_M_1000C_MSC		(1<<11)	/* Bit 11:	M/S Configuration (1=Master) */
+#define PHY_M_1000C_MPD		(1<<10)	/* Bit 10:	Multi-Port Device */
+#define PHY_M_1000C_AFD		(1<<9)	/* Bit  9:	Advertise Full Duplex */
+#define PHY_M_1000C_AHD		(1<<8)	/* Bit  8:	Advertise Half Duplex */
+									/* Bit  7..0:	reserved */
+
+/*****  PHY_MARV_PHY_CTRL	16 bit r/w	PHY Specific Ctrl Reg *****/
+#define PHY_M_PC_TX_FFD_MSK	(3<<14)	/* Bit 15..14:	Tx FIFO Depth Mask */
+#define PHY_M_PC_RX_FFD_MSK	(3<<12)	/* Bit 13..12:	Rx FIFO Depth Mask */
+#define PHY_M_PC_ASS_CRS_TX	(1<<11)	/* Bit 11:	Assert CRS on Transmit */
+#define PHY_M_PC_FL_GOOD	(1<<10)	/* Bit 10:	Force Link Good */
+#define PHY_M_PC_EN_DET_MSK	(3<<8)	/* Bit  9.. 8:	Energy Detect Mask */
+#define PHY_M_PC_ENA_EXT_D	(1<<7)	/* Bit  7:	Enable Ext. Distance (10BT) */
+#define PHY_M_PC_MDIX_MSK	(3<<5)	/* Bit  6.. 5:	MDI/MDIX Config. Mask */
+#define PHY_M_PC_DIS_125CLK	(1<<4)	/* Bit  4:	Disable 125 CLK */
+#define PHY_M_PC_MAC_POW_UP	(1<<3)	/* Bit  3:	MAC Power up */
+#define PHY_M_PC_SQE_T_ENA	(1<<2)	/* Bit  2:	SQE Test Enabled */
+#define PHY_M_PC_POL_R_DIS	(1<<1)	/* Bit  1:	Polarity Reversal Disabled */
+#define PHY_M_PC_DIS_JABBER	(1<<0)	/* Bit  0:	Disable Jabber */
+
+#define PHY_M_PC_EN_DET			SHIFT8(2)	/* Energy Detect (Mode 1) */
+#define PHY_M_PC_EN_DET_PLUS	SHIFT8(3)	/* Energy Detect Plus (Mode 2) */
+
+#define PHY_M_PC_MDI_XMODE(x)	SHIFT5(x)	
+#define PHY_M_PC_MAN_MDI	0    	/* 00 = Manual MDI configuration */
+#define PHY_M_PC_MAN_MDIX	1		/* 01 = Manual MDIX configuration */
+#define PHY_M_PC_ENA_AUTO	3		/* 11 = Enable Automatic Crossover */
+
+/*****  PHY_MARV_PHY_STAT	16 bit r/o	PHY Specific Status Reg *****/
+#define PHY_M_PS_SPEED_MSK	(3<<14)	/* Bit 15..14:	Speed Mask */
+#define PHY_M_PS_SPEED_1000	(1<<15)	/*       10 = 1000 Mbps */
+#define PHY_M_PS_SPEED_100	(1<<14)	/*       01 =  100 Mbps */
+#define PHY_M_PS_SPEED_10	0		/*       00 =   10 Mbps */
+#define PHY_M_PS_FULL_DUP	(1<<13)	/* Bit 13:	Full Duplex */
+#define PHY_M_PS_PAGE_REC	(1<<12)	/* Bit 12:	Page Received */
+#define PHY_M_PS_SPDUP_RES	(1<<11)	/* Bit 11:	Speed & Duplex Resolved */
+#define PHY_M_PS_LINK_UP	(1<<10)	/* Bit 10:	Link Up */
+#define PHY_M_PS_CABLE_MSK	(3<<7)	/* Bit  9.. 7:	Cable Length Mask */
+#define PHY_M_PS_MDI_X_STAT	(1<<6)	/* Bit  6:	MDI Crossover Stat (1=MDIX) */
+#define PHY_M_PS_DOWNS_STAT	(1<<5)	/* Bit  5:	Downshift Status (1=downsh.) */
+#define PHY_M_PS_ENDET_STAT	(1<<4)	/* Bit  4:	Energy Detect Status (1=act) */
+#define PHY_M_PS_TX_P_EN	(1<<3)	/* Bit  3:	Tx Pause Enabled */
+#define PHY_M_PS_RX_P_EN	(1<<2)	/* Bit  2:	Rx Pause Enabled */
+#define PHY_M_PS_POL_REV	(1<<1)	/* Bit  1:	Polarity Reversed */
+#define PHY_M_PC_JABBER		(1<<0)	/* Bit  0:	Jabber */
+
+#define PHY_M_PS_PAUSE_MSK	(PHY_M_PS_TX_P_EN | PHY_M_PS_RX_P_EN)
+
+/*****  PHY_MARV_INT_MASK	16 bit r/w	Interrupt Mask Reg *****/
+/*****  PHY_MARV_INT_STAT	16 bit r/o	Interrupt Status Reg *****/
+#define PHY_M_IS_AN_ERROR	(1<<15)	/* Bit 15:	Auto-Negotiation Error */
+#define PHY_M_IS_LSP_CHANGE	(1<<14)	/* Bit 14:	Link Speed Changed */
+#define PHY_M_IS_DUP_CHANGE	(1<<13)	/* Bit 13:	Duplex Mode Changed */
+#define PHY_M_IS_AN_PR		(1<<12)	/* Bit 12:	Page Received */
+#define PHY_M_IS_AN_COMPL	(1<<11)	/* Bit 11:	Auto-Negotiation Completed */
+#define PHY_M_IS_LST_CHANGE	(1<<10)	/* Bit 10:	Link Status Changed */
+#define PHY_M_IS_SYMB_ERROR	(1<<9)	/* Bit  9:	Symbol Error */
+#define PHY_M_IS_FALSE_CARR	(1<<8)	/* Bit  8:	False Carrier */
+#define PHY_M_IS_FIFO_ERROR	(1<<7)	/* Bit  7:	FIFO Overflow/Underrun Error */
+#define PHY_M_IS_MDI_CHANGE	(1<<6)	/* Bit  6:	MDI Crossover Changed */
+#define PHY_M_IS_DOWNSH_DET	(1<<5)	/* Bit  5:	Downshift Detected */
+#define PHY_M_IS_END_CHANGE	(1<<4)	/* Bit  4:	Energy Detect Changed */
+									/* Bit  3..2:	reserved */
+#define PHY_M_IS_POL_CHANGE	(1<<1)	/* Bit  1:	Polarity Changed */
+#define PHY_M_IS_JABBER		(1<<0)	/* Bit  0:	Jabber */
+
+#define PHY_M_DEF_MSK		(PHY_M_IS_AN_ERROR | PHY_M_IS_AN_PR | \
+							PHY_M_IS_LST_CHANGE | PHY_M_IS_FIFO_ERROR)
+
+/*****  PHY_MARV_EXT_CTRL	16 bit r/w	Ext. PHY Specific Ctrl *****/
+#define PHY_M_EC_M_DSC_MSK	(3<<10)	/* Bit 11..10:	Master downshift counter */
+#define PHY_M_EC_S_DSC_MSK	(3<<8)	/* Bit  9.. 8:	Slave  downshift counter */
+#define PHY_M_EC_MAC_S_MSK	(7<<4)	/* Bit  6.. 4:	Def. MAC interface speed */
+#define PHY_M_EC_FIB_AN_ENA	(1<<3)	/* Bit  3:	Fiber Auto-Neg. Enable */
+
+#define PHY_M_EC_M_DSC(x)		SHIFT10(x)	/* 00=1x; 01=2x; 10=3x; 11=4x */
+#define PHY_M_EC_S_DSC(x)		SHIFT8(x)	/* 00=dis; 01=1x; 10=2x; 11=3x */
+#define PHY_M_EC_MAC_S(x)		SHIFT4(x)	/* 01X=0; 110=2.5; 111=25 (MHz) */
+
+#define MAC_TX_CLK_0_MHZ	2
+#define MAC_TX_CLK_2_5_MHZ	6
+#define MAC_TX_CLK_25_MHZ	7
+
+/*****  PHY_MARV_LED_CTRL	16 bit r/w	LED Control Reg *****/
+#define PHY_M_LEDC_DIS_LED	(1<<15)	/* Bit 15:	Disable LED */
+#define PHY_M_LEDC_PULS_MSK	(7<<12)	/* Bit 14..12:  Pulse Stretch Mask */
+#define PHY_M_LEDC_F_INT	(1<<11)	/* Bit 11:	Force Interrupt */
+#define PHY_M_LEDC_BL_R_MSK	(7<<8)	/* Bit 10.. 8:  Blink Rate Mask */
+									/* Bit  7.. 5:	reserved */
+#define PHY_M_LEDC_LINK_MSK	(3<<3)	/* Bit  4.. 3:	Link Control Mask */
+#define PHY_M_LEDC_DP_CTRL	(1<<2)	/* Bit  2:	Duplex Control */
+#define PHY_M_LEDC_RX_CTRL	(1<<1)	/* Bit  1:	Rx activity / Link */
+#define PHY_M_LEDC_TX_CTRL	(1<<0)	/* Bit  0:	Tx activity / Link */
+
+#define PHY_M_LED_PULS_DUR(x)	SHIFT12(x)	/* Pulse Stretch Duration */
+
+#define	PULS_NO_STR		0		/* no pulse stretching */
+#define	PULS_21MS		1		/* 21 ms to 42 ms */
+#define PULS_42MS		2		/* 42 ms to 84 ms */
+#define PULS_84MS		3		/* 84 ms to 170 ms */
+#define PULS_170MS		4		/* 170 ms to 340 ms */
+#define PULS_340MS		5		/* 340 ms to 670 ms */
+#define PULS_670MS		6		/* 670 ms to 1.3 s */
+#define PULS_1300MS		7		/* 1.3 s to 2.7 s */
+
+#define PHY_M_LED_BLINK_RT(x)	SHIFT8(x)	/* Blink Rate */
+
+#define BLINK_42MS		0		/* 42 ms */
+#define BLINK_84MS		1		/* 84 ms */
+#define BLINK_170MS		2		/* 170 ms */
+#define BLINK_340MS		3		/* 340 ms */
+#define BLINK_670MS		4		/* 670 ms */
+								/* values 5 - 7: reserved */
+
+/*****  PHY_MARV_LED_OVER	16 bit r/w	Manual LED Override Reg *****/
+#define PHY_M_LED_MO_DUP(x)		SHIFT10(x)	/* Bit 11..10:  Duplex */
+#define PHY_M_LED_MO_10(x)		SHIFT8(x)	/* Bit  9.. 8:  Link 10 */
+#define PHY_M_LED_MO_100(x)		SHIFT6(x)	/* Bit  7.. 6:  Link 100 */
+#define PHY_M_LED_MO_1000(x)	SHIFT4(x)	/* Bit  5.. 4:  Link 1000 */
+#define PHY_M_LED_MO_RX(x)		SHIFT2(x)	/* Bit  3.. 2:  Rx */
+#define PHY_M_LED_MO_TX(x)		SHIFT0(x)	/* Bit  1.. 0:  Tx */
+
+#define MO_LED_NORM			0
+#define MO_LED_BLINK		1
+#define MO_LED_OFF			2
+#define MO_LED_ON			3
+
+/*****  PHY_MARV_EXT_CTRL_2	16 bit r/w	Ext. PHY Specific Ctrl 2 *****/
+									/* Bit 15.. 7:	reserved */
+#define PHY_M_EC2_FI_IMPED	(1<<6)	/* Bit  6:	Fiber Input  Impedance */
+#define PHY_M_EC2_FO_IMPED	(1<<5)	/* Bit  5:	Fiber Output Impedance */
+#define PHY_M_EC2_FO_M_CLK	(1<<4)	/* Bit  4:	Fiber Mode Clock Enable */
+#define PHY_M_EC2_FO_BOOST	(1<<3)	/* Bit  3:	Fiber Output Boost */
+#define PHY_M_EC2_FO_AM_MSK	7		/* Bit  2.. 0:	Fiber Output Amplitude */
+
+/*****	PHY_MARV_EXT_P_STAT 16 bit r/w	Ext. PHY Specific Status *****/
+#define PHY_M_FC_AUTO_SEL	(1<<15)	/* Bit 15:	Fiber/Copper Auto Sel. dis. */
+#define PHY_M_FC_AN_REG_ACC (1<<14) /* Bit 14:	Fiber/Copper Autoneg. reg acc */
+#define PHY_M_FC_RESULUTION (1<<13)	/* Bit 13:	Fiber/Copper Resulution */
+#define PHY_M_SER_IF_AN_BP  (1<<12) /* Bit 12:	Ser IF autoneg. bypass enable */
+#define PHY_M_SER_IF_BP_ST	(1<<11) /* Bit 11:	Ser IF autoneg. bypass status */
+#define PHY_M_IRQ_POLARITY	(1<<10) /* Bit 10:	IRQ polarity */
+									/* Bit 9..4: reserved */
+#define PHY_M_UNDOC1		(1<< 7) /* undocumented bit !! */
+#define PHY_M_MODE_MASK		(0xf<<0)/* Bit 3..0: copy of HWCFG MODE[3:0] */
+
+
+/*****  PHY_MARV_CABLE_DIAG	16 bit r/o	Cable Diagnostic Reg *****/
+#define PHY_M_CABD_ENA_TEST	(1<<15)	/* Bit 15:	Enable Test */
+#define PHY_M_CABD_STAT_MSK	(3<<13)	/* Bit 14..13:	Status */
+									/* Bit 12.. 8:	reserved */
+#define PHY_M_CABD_DIST_MSK	0xff	/* Bit  7.. 0:	Distance */
+
+/* values for Cable Diagnostic Status (11=fail; 00=OK; 10=open; 01=short) */
+#define CABD_STAT_NORMAL	0
+#define CABD_STAT_SHORT		1
+#define CABD_STAT_OPEN		2
+#define CABD_STAT_FAIL		3
+
+
+/*
+ * GMAC registers
+ *
+ * The GMAC registers are 16 or 32 bits wide.
+ * The GMACs host processor interface is 16 bits wide,
+ * therefore ALL registers will be addressed with 16 bit accesses.
+ *
+ * The following macros are provided to access the GMAC registers
+ * GM_IN16(), GM_OUT16, GM_IN32(), GM_OUT32(), GM_INADR(), GM_OUTADR(),
+ * GM_INHASH(), and GM_OUTHASH().
+ * The macros are defined in SkGeHw.h.
+ *
+ * Note:	NA reg	= Network Address e.g DA, SA etc.
+ *
+ */
+
+/* Port Registers */
+#define GM_GP_STAT		0x0000		/* 16 bit r/o	General Purpose Status */
+#define GM_GP_CTRL		0x0004		/* 16 bit r/w	General Purpose Control */
+#define GM_TX_CTRL		0x0008		/* 16 bit r/w	Transmit Control Reg. */
+#define GM_RX_CTRL		0x000c		/* 16 bit r/w	Receive Control Reg. */
+#define GM_TX_FLOW_CTRL	0x0010		/* 16 bit r/w	Transmit Flow-Control */
+#define GM_TX_PARAM		0x0014		/* 16 bit r/w	Transmit Parameter Reg. */
+#define GM_SERIAL_MODE	0x0018		/* 16 bit r/w	Serial Mode Register */
+
+/* Source Address Registers */
+#define GM_SRC_ADDR_1L	0x001c		/* 16 bit r/w	Source Address 1 (low) */
+#define GM_SRC_ADDR_1M	0x0020		/* 16 bit r/w	Source Address 1 (middle) */
+#define GM_SRC_ADDR_1H	0x0024		/* 16 bit r/w	Source Address 1 (high) */
+#define GM_SRC_ADDR_2L	0x0028		/* 16 bit r/w	Source Address 2 (low) */
+#define GM_SRC_ADDR_2M	0x002c		/* 16 bit r/w	Source Address 2 (middle) */
+#define GM_SRC_ADDR_2H	0x0030		/* 16 bit r/w	Source Address 2 (high) */
+
+/* Multicast Address Hash Registers */
+#define GM_MC_ADDR_H1	0x0034		/* 16 bit r/w	Multicast Address Hash 1 */
+#define GM_MC_ADDR_H2	0x0038		/* 16 bit r/w	Multicast Address Hash 2 */
+#define GM_MC_ADDR_H3	0x003c		/* 16 bit r/w	Multicast Address Hash 3 */
+#define GM_MC_ADDR_H4	0x0040		/* 16 bit r/w	Multicast Address Hash 4 */
+
+/* Interrupt Source Registers */
+#define GM_TX_IRQ_SRC	0x0044		/* 16 bit r/o	Tx Overflow IRQ Source */
+#define GM_RX_IRQ_SRC	0x0048		/* 16 bit r/o	Rx Overflow IRQ Source */
+#define GM_TR_IRQ_SRC	0x004c		/* 16 bit r/o	Tx/Rx Over. IRQ Source */
+
+/* Interrupt Mask Registers */
+#define GM_TX_IRQ_MSK	0x0050		/* 16 bit r/w	Tx Overflow IRQ Mask */
+#define GM_RX_IRQ_MSK	0x0054		/* 16 bit r/w	Rx Overflow IRQ Mask */
+#define GM_TR_IRQ_MSK	0x0058		/* 16 bit r/w	Tx/Rx Over. IRQ Mask */
+
+/* Serial Management Interface (SMI) Registers */
+#define GM_SMI_CTRL		0x0080		/* 16 bit r/w	SMI Control Register */
+#define GM_SMI_DATA		0x0084		/* 16 bit r/w	SMI Data Register */
+#define GM_PHY_ADDR		0x0088		/* 16 bit r/w	GPHY Address Register */
+
+/* MIB Counters */
+#define GM_MIB_CNT_BASE	0x0100		/* Base Address of MIB Counters */
+#define GM_MIB_CNT_SIZE	44			/* Number of MIB Counters */
+
+/*
+ * MIB Counters base address definitions (low word) -
+ * use offset 4 for access to high word	(32 bit r/o)
+ */
+#define GM_RXF_UC_OK \
+			(GM_MIB_CNT_BASE + 0)	/* Unicast Frames Received OK */
+#define GM_RXF_BC_OK \
+			(GM_MIB_CNT_BASE + 8)	/* Broadcast Frames Received OK */
+#define GM_RXF_MPAUSE \
+			(GM_MIB_CNT_BASE + 16)	/* Pause MAC Ctrl Frames Received */
+#define GM_RXF_MC_OK \
+			(GM_MIB_CNT_BASE + 24)	/* Multicast Frames Received OK */
+#define GM_RXF_FCS_ERR \
+			(GM_MIB_CNT_BASE + 32)	/* Rx Frame Check Seq. Error */
+	/* GM_MIB_CNT_BASE + 40:	reserved */
+#define GM_RXO_OK_LO \
+			(GM_MIB_CNT_BASE + 48)	/* Octets Received OK Low */
+#define GM_RXO_OK_HI \
+			(GM_MIB_CNT_BASE + 56)	/* Octets Received OK High */
+#define GM_RXO_ERR_LO \
+			(GM_MIB_CNT_BASE + 64)	/* Octets Received Invalid Low */
+#define GM_RXO_ERR_HI \
+			(GM_MIB_CNT_BASE + 72)	/* Octets Received Invalid High */
+#define GM_RXF_SHT \
+			(GM_MIB_CNT_BASE + 80)	/* Frames <64 Byte Received OK */
+#define GM_RXE_FRAG \
+			(GM_MIB_CNT_BASE + 88)	/* Frames <64 Byte Received with FCS Err */
+#define GM_RXF_64B \
+			(GM_MIB_CNT_BASE + 96)	/* 64 Byte Rx Frame */
+#define GM_RXF_127B \
+			(GM_MIB_CNT_BASE + 104)	/* 65-127 Byte Rx Frame */
+#define GM_RXF_255B \
+			(GM_MIB_CNT_BASE + 112)	/* 128-255 Byte Rx Frame */
+#define GM_RXF_511B \
+			(GM_MIB_CNT_BASE + 120)	/* 256-511 Byte Rx Frame */
+#define GM_RXF_1023B \
+			(GM_MIB_CNT_BASE + 128)	/* 512-1023 Byte Rx Frame */
+#define GM_RXF_1518B \
+			(GM_MIB_CNT_BASE + 136)	/* 1024-1518 Byte Rx Frame */
+#define GM_RXF_MAX_SZ \
+			(GM_MIB_CNT_BASE + 144)	/* 1519-MaxSize Byte Rx Frame */
+#define GM_RXF_LNG_ERR \
+			(GM_MIB_CNT_BASE + 152)	/* Rx Frame too Long Error */
+#define GM_RXF_JAB_PKT \
+			(GM_MIB_CNT_BASE + 160)	/* Rx Jabber Packet Frame */
+	/* GM_MIB_CNT_BASE + 168:	reserved */
+#define GM_RXE_FIFO_OV \
+			(GM_MIB_CNT_BASE + 176)	/* Rx FIFO overflow Event */
+	/* GM_MIB_CNT_BASE + 184:	reserved */
+#define GM_TXF_UC_OK \
+			(GM_MIB_CNT_BASE + 192)	/* Unicast Frames Xmitted OK */
+#define GM_TXF_BC_OK \
+			(GM_MIB_CNT_BASE + 200)	/* Broadcast Frames Xmitted OK */
+#define GM_TXF_MPAUSE \
+			(GM_MIB_CNT_BASE + 208)	/* Pause MAC Ctrl Frames Xmitted */
+#define GM_TXF_MC_OK \
+			(GM_MIB_CNT_BASE + 216)	/* Multicast Frames Xmitted OK */
+#define GM_TXO_OK_LO \
+			(GM_MIB_CNT_BASE + 224)	/* Octets Transmitted OK Low */
+#define GM_TXO_OK_HI \
+			(GM_MIB_CNT_BASE + 232)	/* Octets Transmitted OK High */
+#define GM_TXF_64B \
+			(GM_MIB_CNT_BASE + 240)	/* 64 Byte Tx Frame */
+#define GM_TXF_127B \
+			(GM_MIB_CNT_BASE + 248)	/* 65-127 Byte Tx Frame */
+#define GM_TXF_255B \
+			(GM_MIB_CNT_BASE + 256)	/* 128-255 Byte Tx Frame */
+#define GM_TXF_511B \
+			(GM_MIB_CNT_BASE + 264)	/* 256-511 Byte Tx Frame */
+#define GM_TXF_1023B \
+			(GM_MIB_CNT_BASE + 272)	/* 512-1023 Byte Tx Frame */
+#define GM_TXF_1518B \
+			(GM_MIB_CNT_BASE + 280)	/* 1024-1518 Byte Tx Frame */
+#define GM_TXF_MAX_SZ \
+			(GM_MIB_CNT_BASE + 288)	/* 1519-MaxSize Byte Tx Frame */
+	/* GM_MIB_CNT_BASE + 296:	reserved */
+#define GM_TXF_COL \
+			(GM_MIB_CNT_BASE + 304)	/* Tx Collision */
+#define GM_TXF_LAT_COL \
+			(GM_MIB_CNT_BASE + 312)	/* Tx Late Collision */
+#define GM_TXF_ABO_COL \
+			(GM_MIB_CNT_BASE + 320)	/* Tx aborted due to Exces. Col. */
+#define GM_TXF_MUL_COL \
+			(GM_MIB_CNT_BASE + 328)	/* Tx Multiple Collision */
+#define GM_TXF_SNG_COL \
+			(GM_MIB_CNT_BASE + 336)	/* Tx Single Collision */
+#define GM_TXE_FIFO_UR \
+			(GM_MIB_CNT_BASE + 344)	/* Tx FIFO Underrun Event */
+
+/*----------------------------------------------------------------------------*/
+/*
+ * GMAC Bit Definitions
+ *
+ * If the bit access behaviour differs from the register access behaviour
+ * (r/w, r/o) this is documented after the bit number.
+ * The following bit access behaviours are used:
+ *	(sc)	self clearing
+ *	(r/o)	read only
+ */
+
+/*	GM_GP_STAT	16 bit r/o	General Purpose Status Register */
+#define GM_GPSR_SPEED		(1<<15) /* Bit 15:	Port Speed (1 = 100 Mbps) */
+#define GM_GPSR_DUPLEX		(1<<14) /* Bit 14:	Duplex Mode (1 = Full) */
+#define GM_GPSR_FC_TX_DIS	(1<<13) /* Bit 13:	Tx Flow-Control Mode Disabled */
+#define GM_GPSR_LINK_UP		(1<<12)	/* Bit 12:	Link Up Status */
+#define GM_GPSR_PAUSE		(1<<11)	/* Bit 11:	Pause State */
+#define GM_GPSR_TX_ACTIVE	(1<<10)	/* Bit 10:	Tx in Progress */
+#define GM_GPSR_EXC_COL		(1<<9)	/* Bit  9:	Excessive Collisions Occured */
+#define GM_GPSR_LAT_COL		(1<<8)	/* Bit  8:	Late Collisions Occured */
+								/* Bit  7..6:	reserved */
+#define GM_GPSR_PHY_ST_CH	(1<<5)	/* Bit  5:	PHY Status Change */
+#define GM_GPSR_GIG_SPEED	(1<<4)	/* Bit  4:	Gigabit Speed (1 = 1000 Mbps) */
+#define GM_GPSR_PART_MODE	(1<<3)	/* Bit  3:	Partition mode */
+#define GM_GPSR_FC_RX_DIS	(1<<2)	/* Bit  2:	Rx Flow-Control Mode Disabled */
+#define GM_GPSR_PROM_EN		(1<<1)	/* Bit  1:	Promiscuous Mode Enabled */
+								/* Bit  0:	reserved */
+	
+/*	GM_GP_CTRL	16 bit r/w	General Purpose Control Register */
+								/* Bit 15:	reserved */
+#define GM_GPCR_PROM_ENA	(1<<14)	/* Bit 14:	Enable Promiscuous Mode */
+#define GM_GPCR_FC_TX_DIS	(1<<13) /* Bit 13:	Disable Tx Flow-Control Mode */
+#define GM_GPCR_TX_ENA		(1<<12) /* Bit 12:	Enable Transmit */
+#define GM_GPCR_RX_ENA		(1<<11) /* Bit 11:	Enable Receive */
+#define GM_GPCR_BURST_ENA	(1<<10)	/* Bit 10:	Enable Burst Mode */
+#define GM_GPCR_LOOP_ENA	(1<<9)	/* Bit  9:	Enable MAC Loopback Mode */
+#define GM_GPCR_PART_ENA	(1<<8)	/* Bit  8:	Enable Partition Mode */
+#define GM_GPCR_GIGS_ENA	(1<<7)	/* Bit  7:	Gigabit Speed (1000 Mbps) */
+#define GM_GPCR_FL_PASS		(1<<6)	/* Bit  6:	Force Link Pass */
+#define GM_GPCR_DUP_FULL	(1<<5)	/* Bit  5:	Full Duplex Mode */
+#define GM_GPCR_FC_RX_DIS	(1<<4)	/* Bit  4:	Disable Rx Flow-Control Mode */
+#define GM_GPCR_SPEED_100	(1<<3)  /* Bit  3:	Port Speed 100 Mbps */
+#define GM_GPCR_AU_DUP_DIS	(1<<2)	/* Bit  2:	Disable Auto-Update Duplex */
+#define GM_GPCR_AU_FCT_DIS	(1<<1)	/* Bit  1:	Disable Auto-Update Flow-C. */
+#define GM_GPCR_AU_SPD_DIS	(1<<0)	/* Bit  0:	Disable Auto-Update Speed */
+
+#define GM_GPCR_SPEED_1000	(GM_GPCR_GIGS_ENA | GM_GPCR_SPEED_100)
+#define GM_GPCR_AU_ALL_DIS	(GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS |\
+							 GM_GPCR_AU_SPD_DIS)
+	
+/*	GM_TX_CTRL				16 bit r/w	Transmit Control Register */
+#define GM_TXCR_FORCE_JAM	(1<<15)	/* Bit 15:	Force Jam / Flow-Control */
+#define GM_TXCR_CRC_DIS		(1<<14)	/* Bit 14:	Disable insertion of CRC */
+#define GM_TXCR_PAD_DIS		(1<<13)	/* Bit 13:	Disable padding of packets */
+#define GM_TXCR_COL_THR_MSK	(7<<10)	/* Bit 12..10:	Collision Threshold */
+
+#define TX_COL_THR(x)		(SHIFT10(x) & GM_TXCR_COL_THR_MSK)
+
+#define TX_COL_DEF			0x04
+	
+/*	GM_RX_CTRL				16 bit r/w	Receive Control Register */
+#define GM_RXCR_UCF_ENA		(1<<15)	/* Bit 15:	Enable Unicast filtering */
+#define GM_RXCR_MCF_ENA		(1<<14)	/* Bit 14:	Enable Multicast filtering */
+#define GM_RXCR_CRC_DIS		(1<<13)	/* Bit 13:	Remove 4-byte CRC */
+#define GM_RXCR_PASS_FC		(1<<12)	/* Bit 12:	Pass FC packets to FIFO */
+	
+/*	GM_TX_PARAM				16 bit r/w	Transmit Parameter Register */
+#define GM_TXPA_JAMLEN_MSK	(0x03<<14)	/* Bit 15..14:	Jam Length */
+#define GM_TXPA_JAMIPG_MSK	(0x1f<<9)	/* Bit 13..9:	Jam IPG */
+#define GM_TXPA_JAMDAT_MSK	(0x1f<<4)	/* Bit  8..4:	IPG Jam to Data */
+								/* Bit  3..0:	reserved */
+
+#define TX_JAM_LEN_VAL(x)	(SHIFT14(x) & GM_TXPA_JAMLEN_MSK)
+#define TX_JAM_IPG_VAL(x)	(SHIFT9(x) & GM_TXPA_JAMIPG_MSK)
+#define TX_IPG_JAM_DATA(x)	(SHIFT4(x) & GM_TXPA_JAMDAT_MSK)
+
+#define TX_JAM_LEN_DEF		0x03
+#define TX_JAM_IPG_DEF		0x0b
+#define TX_IPG_JAM_DEF		0x1c
+
+/*	GM_SERIAL_MODE			16 bit r/w	Serial Mode Register */
+#define GM_SMOD_DATABL_MSK	(0x1f<<11)	/* Bit 15..11:	Data Blinder (r/o) */
+#define GM_SMOD_LIMIT_4		(1<<10)	/* Bit 10:	4 consecutive Tx trials */
+#define GM_SMOD_VLAN_ENA	(1<<9)	/* Bit  9:	Enable VLAN  (Max. Frame Len) */
+#define GM_SMOD_JUMBO_ENA	(1<<8)	/* Bit  8:	Enable Jumbo (Max. Frame Len) */
+								/* Bit  7..5:	reserved */
+#define GM_SMOD_IPG_MSK		0x1f	/* Bit 4..0:	Inter-Packet Gap (IPG) */
+	
+#define DATA_BLIND_VAL(x)	(SHIFT11(x) & GM_SMOD_DATABL_MSK)
+#define DATA_BLIND_DEF		0x04
+
+#define IPG_DATA_VAL(x)		(x & GM_SMOD_IPG_MSK)
+#define IPG_DATA_DEF		0x1e
+
+/*	GM_SMI_CTRL				16 bit r/w	SMI Control Register */
+#define GM_SMI_CT_PHY_A_MSK	(0x1f<<11)	/* Bit 15..11:	PHY Device Address */
+#define GM_SMI_CT_REG_A_MSK	(0x1f<<6)	/* Bit 10.. 6:	PHY Register Address */
+#define GM_SMI_CT_OP_RD		(1<<5)	/* Bit  5:	OpCode Read (0=Write)*/
+#define GM_SMI_CT_RD_VAL	(1<<4)	/* Bit  4:	Read Valid (Read completed) */
+#define GM_SMI_CT_BUSY		(1<<3)	/* Bit  3:	Busy (Operation in progress) */
+								/* Bit   2..0:	reserved */
+	
+#define GM_SMI_CT_PHY_AD(x)	(SHIFT11(x) & GM_SMI_CT_PHY_A_MSK)
+#define GM_SMI_CT_REG_AD(x)	(SHIFT6(x) & GM_SMI_CT_REG_A_MSK)
+
+	/*	GM_PHY_ADDR				16 bit r/w	GPHY Address Register */
+								/* Bit  15..6:	reserved */
+#define GM_PAR_MIB_CLR		(1<<5)	/* Bit  5:	Set MIB Clear Counter Mode */
+#define GM_PAR_MIB_TST		(1<<4)	/* Bit  4:	MIB Load Counter (Test Mode) */
+								/* Bit   3..0:	reserved */
+	
+/* Receive Frame Status Encoding */
+#define GMR_FS_LEN	(0xffffUL<<16)	/* Bit 31..16:	Rx Frame Length */
+								/* Bit  15..14:	reserved */
+#define GMR_FS_VLAN		(1L<<13)	/* Bit 13:	VLAN Packet */
+#define GMR_FS_JABBER	(1L<<12)	/* Bit 12:	Jabber Packet */
+#define GMR_FS_UN_SIZE	(1L<<11)	/* Bit 11:	Undersize Packet */
+#define GMR_FS_MC		(1L<<10)	/* Bit 10:	Multicast Packet */
+#define GMR_FS_BC		(1L<<9)		/* Bit  9:	Broadcast Packet */
+#define GMR_FS_RX_OK	(1L<<8)		/* Bit  8:	Receive OK (Good Packet) */
+#define GMR_FS_GOOD_FC	(1L<<7)		/* Bit  7:	Good Flow-Control Packet */
+#define GMR_FS_BAD_FC	(1L<<6)		/* Bit  6:	Bad  Flow-Control Packet */
+#define GMR_FS_MII_ERR	(1L<<5)		/* Bit  5:	MII Error */
+#define GMR_FS_LONG_ERR	(1L<<4)		/* Bit  4:	Too Long Packet */
+#define GMR_FS_FRAGMENT	(1L<<3)		/* Bit  3:	Fragment */
+								/* Bit  2:	reserved */
+#define GMR_FS_CRC_ERR	(1L<<1)		/* Bit  1:	CRC Error */
+#define GMR_FS_RX_FF_OV	(1L<<0)		/* Bit  0:	Rx FIFO Overflow */
+
+/*
+ * GMR_FS_ANY_ERR (analogous to XMR_FS_ANY_ERR)
+ */
+#define GMR_FS_ANY_ERR	(GMR_FS_CRC_ERR | \
+			GMR_FS_LONG_ERR | \
+			GMR_FS_MII_ERR | \
+			GMR_FS_BAD_FC | \
+			GMR_FS_GOOD_FC | \
+			GMR_FS_JABBER)
+
+/* Rx GMAC FIFO Flush Mask (default) */
+#define RX_FF_FL_DEF_MSK	(GMR_FS_CRC_ERR | \
+			GMR_FS_RX_FF_OV | \
+			GMR_FS_MII_ERR | \
+			GMR_FS_BAD_FC | \
+			GMR_FS_GOOD_FC | \
+			GMR_FS_UN_SIZE | \
+			GMR_FS_JABBER)
+
+/* typedefs *******************************************************************/
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
+#endif	/* __INC_XMAC_H */
diff --git a/drivers/net/sk98lin/skaddr.c b/drivers/net/sk98lin/skaddr.c
new file mode 100644
index 0000000..6e6c56a
--- /dev/null
+++ b/drivers/net/sk98lin/skaddr.c
@@ -0,0 +1,1788 @@
+/******************************************************************************
+ *
+ * Name:	skaddr.c
+ * Project:	Gigabit Ethernet Adapters, ADDR-Module
+ * Version:	$Revision: 1.52 $
+ * Date:	$Date: 2003/06/02 13:46:15 $
+ * Purpose:	Manage Addresses (Multicast and Unicast) and Promiscuous Mode.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module is intended to manage multicast addresses, address override,
+ * and promiscuous mode on GEnesis and Yukon adapters.
+ *
+ * Address Layout:
+ *	port address:		physical MAC address
+ *	1st exact match:	logical MAC address (GEnesis only)
+ *	2nd exact match:	RLMT multicast (GEnesis only)
+ *	exact match 3-13:	OS-specific multicasts (GEnesis only)
+ *
+ * Include File Hierarchy:
+ *
+ *	"skdrv1st.h"
+ *	"skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+	"@(#) $Id: skaddr.c,v 1.52 2003/06/02 13:46:15 tschilli Exp $ (C) Marvell.";
+#endif /* DEBUG ||!LINT || !SK_SLIM */
+
+#define __SKADDR_C
+
+#ifdef __cplusplus
+extern "C" {
+#endif	/* cplusplus */
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* defines ********************************************************************/
+
+
+#define XMAC_POLY	0xEDB88320UL	/* CRC32-Poly - XMAC: Little Endian */
+#define GMAC_POLY	0x04C11DB7L	/* CRC16-Poly - GMAC: Little Endian */
+#define HASH_BITS	6				/* #bits in hash */
+#define	SK_MC_BIT	0x01
+
+/* Error numbers and messages. */
+
+#define SKERR_ADDR_E001		(SK_ERRBASE_ADDR + 0)
+#define SKERR_ADDR_E001MSG	"Bad Flags."
+#define SKERR_ADDR_E002		(SKERR_ADDR_E001 + 1)
+#define SKERR_ADDR_E002MSG	"New Error."
+
+/* typedefs *******************************************************************/
+
+/* None. */
+
+/* global variables ***********************************************************/
+
+/* 64-bit hash values with all bits set. */
+
+static const SK_U16	OnesHash[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
+
+/* local variables ************************************************************/
+
+#ifdef DEBUG
+static int	Next0[SK_MAX_MACS] = {0};
+#endif	/* DEBUG */
+
+static int SkAddrGmacMcAdd(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
+			   SK_MAC_ADDR *pMc, int Flags);
+static int SkAddrGmacMcClear(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
+			     int Flags);
+static int SkAddrGmacMcUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber);
+static int SkAddrGmacPromiscuousChange(SK_AC *pAC, SK_IOC IoC,
+				       SK_U32 PortNumber, int NewPromMode);
+static int SkAddrXmacMcAdd(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
+			   SK_MAC_ADDR *pMc, int Flags);
+static int SkAddrXmacMcClear(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber,
+			     int Flags);
+static int SkAddrXmacMcUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber);
+static int SkAddrXmacPromiscuousChange(SK_AC *pAC, SK_IOC IoC,
+				       SK_U32 PortNumber, int NewPromMode);
+
+/* functions ******************************************************************/
+
+/******************************************************************************
+ *
+ *	SkAddrInit - initialize data, set state to init
+ *
+ * Description:
+ *
+ *	SK_INIT_DATA
+ *	============
+ *
+ *	This routine clears the multicast tables and resets promiscuous mode.
+ *	Some entries are reserved for the "logical MAC address", the
+ *	SK-RLMT multicast address, and the BPDU multicast address.
+ *
+ *
+ *	SK_INIT_IO
+ *	==========
+ *
+ *	All permanent MAC addresses are read from EPROM.
+ *	If the current MAC addresses are not already set in software,
+ *	they are set to the values of the permanent addresses.
+ *	The current addresses are written to the corresponding MAC.
+ *
+ *
+ *	SK_INIT_RUN
+ *	===========
+ *
+ *	Nothing.
+ *
+ * Context:
+ *	init, pageable
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ */
+int	SkAddrInit(
+SK_AC	*pAC,	/* the adapter context */
+SK_IOC	IoC,	/* I/O context */
+int		Level)	/* initialization level */
+{
+	int			j;
+	SK_U32		i;
+	SK_U8		*InAddr;
+	SK_U16		*OutAddr;
+	SK_ADDR_PORT	*pAPort;
+
+	switch (Level) {
+	case SK_INIT_DATA:
+		SK_MEMSET((char *) &pAC->Addr, (SK_U8) 0,
+            (SK_U16) sizeof(SK_ADDR));
+
+		for (i = 0; i < SK_MAX_MACS; i++) {
+			pAPort = &pAC->Addr.Port[i];
+			pAPort->PromMode = SK_PROM_MODE_NONE;
+			
+			pAPort->FirstExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
+			pAPort->FirstExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
+			pAPort->NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
+			pAPort->NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
+		}
+#ifdef xDEBUG
+		for (i = 0; i < SK_MAX_MACS; i++) {
+			if (pAC->Addr.Port[i].NextExactMatchRlmt <
+				SK_ADDR_FIRST_MATCH_RLMT) {
+				Next0[i] |= 4;
+			}
+		}
+#endif	/* DEBUG */
+		/* pAC->Addr.InitDone = SK_INIT_DATA; */
+		break;
+
+    case SK_INIT_IO:
+#ifndef SK_NO_RLMT
+		for (i = 0; i < SK_MAX_NETS; i++) {
+			pAC->Addr.Net[i].ActivePort = pAC->Rlmt.Net[i].ActivePort;
+		}
+#endif /* !SK_NO_RLMT */
+#ifdef xDEBUG
+		for (i = 0; i < SK_MAX_MACS; i++) {
+			if (pAC->Addr.Port[i].NextExactMatchRlmt <
+				SK_ADDR_FIRST_MATCH_RLMT) {
+				Next0[i] |= 8;
+			}
+		}
+#endif	/* DEBUG */
+		
+		/* Read permanent logical MAC address from Control Register File. */
+		for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+			InAddr = (SK_U8 *) &pAC->Addr.Net[0].PermanentMacAddress.a[j];
+			SK_IN8(IoC, B2_MAC_1 + j, InAddr);
+		}
+
+		if (!pAC->Addr.Net[0].CurrentMacAddressSet) {
+			/* Set the current logical MAC address to the permanent one. */
+			pAC->Addr.Net[0].CurrentMacAddress =
+				pAC->Addr.Net[0].PermanentMacAddress;
+			pAC->Addr.Net[0].CurrentMacAddressSet = SK_TRUE;
+		}
+
+		/* Set the current logical MAC address. */
+		pAC->Addr.Port[pAC->Addr.Net[0].ActivePort].Exact[0] =
+			pAC->Addr.Net[0].CurrentMacAddress;
+#if SK_MAX_NETS > 1
+		/* Set logical MAC address for net 2 to (log | 3). */
+		if (!pAC->Addr.Net[1].CurrentMacAddressSet) {
+			pAC->Addr.Net[1].PermanentMacAddress =
+				pAC->Addr.Net[0].PermanentMacAddress;
+			pAC->Addr.Net[1].PermanentMacAddress.a[5] |= 3;
+			/* Set the current logical MAC address to the permanent one. */
+			pAC->Addr.Net[1].CurrentMacAddress =
+				pAC->Addr.Net[1].PermanentMacAddress;
+			pAC->Addr.Net[1].CurrentMacAddressSet = SK_TRUE;
+		}
+#endif	/* SK_MAX_NETS > 1 */
+
+#ifdef DEBUG
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+				("Permanent MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n",
+					i,
+					pAC->Addr.Net[i].PermanentMacAddress.a[0],
+					pAC->Addr.Net[i].PermanentMacAddress.a[1],
+					pAC->Addr.Net[i].PermanentMacAddress.a[2],
+					pAC->Addr.Net[i].PermanentMacAddress.a[3],
+					pAC->Addr.Net[i].PermanentMacAddress.a[4],
+					pAC->Addr.Net[i].PermanentMacAddress.a[5]))
+			
+			SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+				("Logical MAC Address (Net%d): %02X %02X %02X %02X %02X %02X\n",
+					i,
+					pAC->Addr.Net[i].CurrentMacAddress.a[0],
+					pAC->Addr.Net[i].CurrentMacAddress.a[1],
+					pAC->Addr.Net[i].CurrentMacAddress.a[2],
+					pAC->Addr.Net[i].CurrentMacAddress.a[3],
+					pAC->Addr.Net[i].CurrentMacAddress.a[4],
+					pAC->Addr.Net[i].CurrentMacAddress.a[5]))
+		}
+#endif	/* DEBUG */
+
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+			pAPort = &pAC->Addr.Port[i];
+
+			/* Read permanent port addresses from Control Register File. */
+			for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+				InAddr = (SK_U8 *) &pAPort->PermanentMacAddress.a[j];
+				SK_IN8(IoC, B2_MAC_2 + 8 * i + j, InAddr);
+			}
+
+			if (!pAPort->CurrentMacAddressSet) {
+				/*
+				 * Set the current and previous physical MAC address
+				 * of this port to its permanent MAC address.
+				 */
+				pAPort->CurrentMacAddress = pAPort->PermanentMacAddress;
+				pAPort->PreviousMacAddress = pAPort->PermanentMacAddress;
+				pAPort->CurrentMacAddressSet = SK_TRUE;
+			}
+
+			/* Set port's current physical MAC address. */
+			OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
+#ifdef GENESIS
+			if (pAC->GIni.GIGenesis) {
+				XM_OUTADDR(IoC, i, XM_SA, OutAddr);
+			}
+#endif /* GENESIS */
+#ifdef YUKON
+			if (!pAC->GIni.GIGenesis) {
+				GM_OUTADDR(IoC, i, GM_SRC_ADDR_1L, OutAddr);
+			}
+#endif /* YUKON */
+#ifdef DEBUG
+			SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+				("SkAddrInit: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+					pAPort->PermanentMacAddress.a[0],
+					pAPort->PermanentMacAddress.a[1],
+					pAPort->PermanentMacAddress.a[2],
+					pAPort->PermanentMacAddress.a[3],
+					pAPort->PermanentMacAddress.a[4],
+					pAPort->PermanentMacAddress.a[5]))
+			
+			SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_INIT,
+				("SkAddrInit: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+					pAPort->CurrentMacAddress.a[0],
+					pAPort->CurrentMacAddress.a[1],
+					pAPort->CurrentMacAddress.a[2],
+					pAPort->CurrentMacAddress.a[3],
+					pAPort->CurrentMacAddress.a[4],
+					pAPort->CurrentMacAddress.a[5]))
+#endif /* DEBUG */
+		}
+		/* pAC->Addr.InitDone = SK_INIT_IO; */
+		break;
+
+	case SK_INIT_RUN:
+#ifdef xDEBUG
+		for (i = 0; i < SK_MAX_MACS; i++) {
+			if (pAC->Addr.Port[i].NextExactMatchRlmt <
+				SK_ADDR_FIRST_MATCH_RLMT) {
+				Next0[i] |= 16;
+			}
+		}
+#endif	/* DEBUG */
+
+		/* pAC->Addr.InitDone = SK_INIT_RUN; */
+		break;
+
+	default:	/* error */
+		break;
+	}
+
+	return (SK_ADDR_SUCCESS);
+	
+}	/* SkAddrInit */
+
+#ifndef SK_SLIM
+
+/******************************************************************************
+ *
+ *	SkAddrMcClear - clear the multicast table
+ *
+ * Description:
+ *	This routine clears the multicast table.
+ *
+ *	If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
+ *	immediately.
+ *
+ *	It calls either SkAddrXmacMcClear or SkAddrGmacMcClear, according
+ *	to the adapter in use. The real work is done there.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
+ *	may be called after SK_INIT_IO without limitation
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrMcClear(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortNumber,	/* Index of affected port */
+int		Flags)		/* permanent/non-perm, sw-only */
+{
+	int ReturnCode;
+	
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+	
+	if (pAC->GIni.GIGenesis) {
+		ReturnCode = SkAddrXmacMcClear(pAC, IoC, PortNumber, Flags);
+	}
+	else {
+		ReturnCode = SkAddrGmacMcClear(pAC, IoC, PortNumber, Flags);
+	}
+
+	return (ReturnCode);
+
+}	/* SkAddrMcClear */
+
+#endif /* !SK_SLIM */
+
+#ifndef SK_SLIM
+
+/******************************************************************************
+ *
+ *	SkAddrXmacMcClear - clear the multicast table
+ *
+ * Description:
+ *	This routine clears the multicast table
+ *	(either entry 2 or entries 3-16 and InexactFilter) of the given port.
+ *	If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
+ *	immediately.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
+ *	may be called after SK_INIT_IO without limitation
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+static int	SkAddrXmacMcClear(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortNumber,	/* Index of affected port */
+int		Flags)		/* permanent/non-perm, sw-only */
+{
+	int i;
+
+	if (Flags & SK_ADDR_PERMANENT) {	/* permanent => RLMT */
+
+		/* Clear RLMT multicast addresses. */
+		pAC->Addr.Port[PortNumber].NextExactMatchRlmt = SK_ADDR_FIRST_MATCH_RLMT;
+	}
+	else {	/* not permanent => DRV */
+
+		/* Clear InexactFilter */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
+		}
+
+		/* Clear DRV multicast addresses. */
+
+		pAC->Addr.Port[PortNumber].NextExactMatchDrv = SK_ADDR_FIRST_MATCH_DRV;
+	}
+
+	if (!(Flags & SK_MC_SW_ONLY)) {
+		(void) SkAddrXmacMcUpdate(pAC, IoC, PortNumber);
+	}
+
+	return (SK_ADDR_SUCCESS);
+	
+}	/* SkAddrXmacMcClear */
+
+#endif /* !SK_SLIM */
+
+#ifndef SK_SLIM
+
+/******************************************************************************
+ *
+ *	SkAddrGmacMcClear - clear the multicast table
+ *
+ * Description:
+ *	This routine clears the multicast hashing table (InexactFilter)
+ *	(either the RLMT or the driver bits) of the given port.
+ *
+ *	If not suppressed by Flag SK_MC_SW_ONLY, the hardware is updated
+ *	immediately.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called starting with SK_INIT_DATA with flag SK_MC_SW_ONLY
+ *	may be called after SK_INIT_IO without limitation
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+static int	SkAddrGmacMcClear(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortNumber,	/* Index of affected port */
+int		Flags)		/* permanent/non-perm, sw-only */
+{
+	int i;
+
+#ifdef DEBUG
+	SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("GMAC InexactFilter (not cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n",
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7]))
+#endif	/* DEBUG */
+
+	/* Clear InexactFilter */
+	for (i = 0; i < 8; i++) {
+		pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
+	}
+	
+	if (Flags & SK_ADDR_PERMANENT) {	/* permanent => RLMT */
+		
+		/* Copy DRV bits to InexactFilter. */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+				pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i];
+			
+			/* Clear InexactRlmtFilter. */
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i] = 0;
+
+		}		
+	}
+	else {	/* not permanent => DRV */
+		
+		/* Copy RLMT bits to InexactFilter. */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+				pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i];
+			
+			/* Clear InexactDrvFilter. */
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i] = 0;
+		}
+	}
+	
+#ifdef DEBUG
+	SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("GMAC InexactFilter (cleared): %02X %02X %02X %02X %02X %02X %02X %02X\n",
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[1],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[2],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[3],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[4],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[5],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[6],
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[7]))
+#endif	/* DEBUG */
+	
+	if (!(Flags & SK_MC_SW_ONLY)) {
+		(void) SkAddrGmacMcUpdate(pAC, IoC, PortNumber);
+	}
+	
+	return (SK_ADDR_SUCCESS);
+
+}	/* SkAddrGmacMcClear */
+
+#ifndef SK_ADDR_CHEAT
+
+/******************************************************************************
+ *
+ *	SkXmacMcHash - hash multicast address
+ *
+ * Description:
+ *	This routine computes the hash value for a multicast address.
+ *	A CRC32 algorithm is used.
+ *
+ * Notes:
+ *	The code was adapted from the XaQti data sheet.
+ *
+ * Context:
+ *	runtime, pageable
+ *
+ * Returns:
+ *	Hash value of multicast address.
+ */
+static SK_U32 SkXmacMcHash(
+unsigned char *pMc)	/* Multicast address */
+{
+	SK_U32 Idx;
+	SK_U32 Bit;
+	SK_U32 Data;
+	SK_U32 Crc;
+
+	Crc = 0xFFFFFFFFUL;
+	for (Idx = 0; Idx < SK_MAC_ADDR_LEN; Idx++) {
+		Data = *pMc++;
+		for (Bit = 0; Bit < 8; Bit++, Data >>= 1) {
+			Crc = (Crc >> 1) ^ (((Crc ^ Data) & 1) ? XMAC_POLY : 0);
+		}
+	}
+
+	return (Crc & ((1 << HASH_BITS) - 1));
+
+}	/* SkXmacMcHash */
+
+
+/******************************************************************************
+ *
+ *	SkGmacMcHash - hash multicast address
+ *
+ * Description:
+ *	This routine computes the hash value for a multicast address.
+ *	A CRC16 algorithm is used.
+ *
+ * Notes:
+ *
+ *
+ * Context:
+ *	runtime, pageable
+ *
+ * Returns:
+ *	Hash value of multicast address.
+ */
+static SK_U32 SkGmacMcHash(
+unsigned char *pMc)	/* Multicast address */
+{
+	SK_U32 Data;
+	SK_U32 TmpData;
+	SK_U32 Crc;
+	int Byte;
+	int Bit;
+
+	Crc = 0xFFFFFFFFUL;
+	for (Byte = 0; Byte < 6; Byte++) {
+		/* Get next byte. */
+		Data = (SK_U32) pMc[Byte];
+		
+		/* Change bit order in byte. */
+		TmpData = Data;
+		for (Bit = 0; Bit < 8; Bit++) {
+			if (TmpData & 1L) {
+				Data |=  1L << (7 - Bit);
+			}
+			else {
+				Data &= ~(1L << (7 - Bit));
+			}
+			TmpData >>= 1;
+		}
+		
+		Crc ^= (Data << 24);
+		for (Bit = 0; Bit < 8; Bit++) {
+			if (Crc & 0x80000000) {
+				Crc = (Crc << 1) ^ GMAC_POLY;
+			}
+			else {
+				Crc <<= 1;
+			}
+		}
+	}
+	
+	return (Crc & ((1 << HASH_BITS) - 1));
+
+}	/* SkGmacMcHash */
+
+#endif	/* !SK_ADDR_CHEAT */
+
+/******************************************************************************
+ *
+ *	SkAddrMcAdd - add a multicast address to a port
+ *
+ * Description:
+ *	This routine enables reception for a given address on the given port.
+ *
+ *	It calls either SkAddrXmacMcAdd or SkAddrGmacMcAdd, according to the
+ *	adapter in use. The real work is done there.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_DATA
+ *
+ * Returns:
+ *	SK_MC_FILTERING_EXACT
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_MC_ILLEGAL_ADDRESS
+ *	SK_MC_ILLEGAL_PORT
+ *	SK_MC_RLMT_OVERFLOW
+ */
+int	SkAddrMcAdd(
+SK_AC		*pAC,		/* adapter context */
+SK_IOC		IoC,		/* I/O context */
+SK_U32		PortNumber,	/* Port Number */
+SK_MAC_ADDR	*pMc,		/* multicast address to be added */
+int			Flags)		/* permanent/non-permanent */
+{
+	int ReturnCode;
+	
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+	
+	if (pAC->GIni.GIGenesis) {
+		ReturnCode = SkAddrXmacMcAdd(pAC, IoC, PortNumber, pMc, Flags);
+	}
+	else {
+		ReturnCode = SkAddrGmacMcAdd(pAC, IoC, PortNumber, pMc, Flags);
+	}
+
+	return (ReturnCode);
+
+}	/* SkAddrMcAdd */
+
+
+/******************************************************************************
+ *
+ *	SkAddrXmacMcAdd - add a multicast address to a port
+ *
+ * Description:
+ *	This routine enables reception for a given address on the given port.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ *	The multicast bit is only checked if there are no free exact match
+ *	entries.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_DATA
+ *
+ * Returns:
+ *	SK_MC_FILTERING_EXACT
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_MC_ILLEGAL_ADDRESS
+ *	SK_MC_RLMT_OVERFLOW
+ */
+static int	SkAddrXmacMcAdd(
+SK_AC		*pAC,		/* adapter context */
+SK_IOC		IoC,		/* I/O context */
+SK_U32		PortNumber,	/* Port Number */
+SK_MAC_ADDR	*pMc,		/* multicast address to be added */
+int		Flags)		/* permanent/non-permanent */
+{
+	int	i;
+	SK_U8	Inexact;
+#ifndef SK_ADDR_CHEAT
+	SK_U32 HashBit;
+#endif	/* !defined(SK_ADDR_CHEAT) */
+
+	if (Flags & SK_ADDR_PERMANENT) {	/* permanent => RLMT */
+#ifdef xDEBUG
+		if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt <
+			SK_ADDR_FIRST_MATCH_RLMT) {
+			Next0[PortNumber] |= 1;
+			return (SK_MC_RLMT_OVERFLOW);
+		}
+#endif	/* DEBUG */
+		
+		if (pAC->Addr.Port[PortNumber].NextExactMatchRlmt >
+			SK_ADDR_LAST_MATCH_RLMT) {
+			return (SK_MC_RLMT_OVERFLOW);
+		}
+
+		/* Set a RLMT multicast address. */
+
+		pAC->Addr.Port[PortNumber].Exact[
+			pAC->Addr.Port[PortNumber].NextExactMatchRlmt++] = *pMc;
+
+		return (SK_MC_FILTERING_EXACT);
+	}
+
+#ifdef xDEBUG
+	if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <
+		SK_ADDR_FIRST_MATCH_DRV) {
+			Next0[PortNumber] |= 2;
+		return (SK_MC_RLMT_OVERFLOW);
+	}
+#endif	/* DEBUG */
+	
+	if (pAC->Addr.Port[PortNumber].NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
+
+		/* Set exact match entry. */
+		pAC->Addr.Port[PortNumber].Exact[
+			pAC->Addr.Port[PortNumber].NextExactMatchDrv++] = *pMc;
+
+		/* Clear InexactFilter */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0;
+		}
+	}
+	else {
+		if (!(pMc->a[0] & SK_MC_BIT)) {
+			/* Hashing only possible with multicast addresses */
+			return (SK_MC_ILLEGAL_ADDRESS);
+		}
+#ifndef SK_ADDR_CHEAT
+		/* Compute hash value of address. */
+		HashBit = 63 - SkXmacMcHash(&pMc->a[0]);
+
+		/* Add bit to InexactFilter. */
+		pAC->Addr.Port[PortNumber].InexactFilter.Bytes[HashBit / 8] |=
+			1 << (HashBit % 8);
+#else	/* SK_ADDR_CHEAT */
+		/* Set all bits in InexactFilter. */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF;
+		}
+#endif	/* SK_ADDR_CHEAT */
+	}
+
+	for (Inexact = 0, i = 0; i < 8; i++) {
+		Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
+	}
+
+	if (Inexact == 0 && pAC->Addr.Port[PortNumber].PromMode == 0) {
+		return (SK_MC_FILTERING_EXACT);
+	}
+	else {
+		return (SK_MC_FILTERING_INEXACT);
+	}
+
+}	/* SkAddrXmacMcAdd */
+
+
+/******************************************************************************
+ *
+ *	SkAddrGmacMcAdd - add a multicast address to a port
+ *
+ * Description:
+ *	This routine enables reception for a given address on the given port.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_DATA
+ *
+ * Returns:
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_MC_ILLEGAL_ADDRESS
+ */
+static int	SkAddrGmacMcAdd(
+SK_AC		*pAC,		/* adapter context */
+SK_IOC		IoC,		/* I/O context */
+SK_U32		PortNumber,	/* Port Number */
+SK_MAC_ADDR	*pMc,		/* multicast address to be added */
+int		Flags)		/* permanent/non-permanent */
+{
+	int	i;
+#ifndef SK_ADDR_CHEAT
+	SK_U32 HashBit;
+#endif	/* !defined(SK_ADDR_CHEAT) */
+		
+	if (!(pMc->a[0] & SK_MC_BIT)) {
+		/* Hashing only possible with multicast addresses */
+		return (SK_MC_ILLEGAL_ADDRESS);
+	}
+	
+#ifndef SK_ADDR_CHEAT
+	
+	/* Compute hash value of address. */
+	HashBit = SkGmacMcHash(&pMc->a[0]);
+	
+	if (Flags & SK_ADDR_PERMANENT) {	/* permanent => RLMT */
+		
+		/* Add bit to InexactRlmtFilter. */
+		pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[HashBit / 8] |=
+			1 << (HashBit % 8);
+		
+		/* Copy bit to InexactFilter. */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+				pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[i];
+		}
+#ifdef DEBUG
+		SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("GMAC InexactRlmtFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n",
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[0],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[1],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[2],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[3],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[4],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[5],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[6],
+			pAC->Addr.Port[PortNumber].InexactRlmtFilter.Bytes[7]))
+#endif	/* DEBUG */
+	}
+	else {	/* not permanent => DRV */
+		
+		/* Add bit to InexactDrvFilter. */
+		pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[HashBit / 8] |=
+			1 << (HashBit % 8);
+		
+		/* Copy bit to InexactFilter. */
+		for (i = 0; i < 8; i++) {
+			pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] |=
+				pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[i];
+		}
+#ifdef DEBUG
+		SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("GMAC InexactDrvFilter: %02X %02X %02X %02X %02X %02X %02X %02X\n",
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[0],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[1],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[2],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[3],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[4],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[5],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[6],
+			pAC->Addr.Port[PortNumber].InexactDrvFilter.Bytes[7]))
+#endif	/* DEBUG */
+	}
+	
+#else	/* SK_ADDR_CHEAT */
+	
+	/* Set all bits in InexactFilter. */
+	for (i = 0; i < 8; i++) {
+		pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i] = 0xFF;
+	}
+#endif	/* SK_ADDR_CHEAT */
+		
+	return (SK_MC_FILTERING_INEXACT);
+	
+}	/* SkAddrGmacMcAdd */
+
+#endif /* !SK_SLIM */
+
+/******************************************************************************
+ *
+ *	SkAddrMcUpdate - update the HW MC address table and set the MAC address
+ *
+ * Description:
+ *	This routine enables reception of the addresses contained in a local
+ *	table for a given port.
+ *	It also programs the port's current physical MAC address.
+ *
+ *	It calls either SkAddrXmacMcUpdate or SkAddrGmacMcUpdate, according
+ *	to the adapter in use. The real work is done there.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_MC_FILTERING_EXACT
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrMcUpdate(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortNumber)	/* Port Number */
+{
+	int ReturnCode = 0;
+#if (!defined(SK_SLIM) || defined(DEBUG))
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+#endif /* !SK_SLIM || DEBUG */
+
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+		ReturnCode = SkAddrXmacMcUpdate(pAC, IoC, PortNumber);
+	}
+#endif /* GENESIS */
+#ifdef YUKON
+	if (!pAC->GIni.GIGenesis) {
+		ReturnCode = SkAddrGmacMcUpdate(pAC, IoC, PortNumber);
+	}
+#endif /* YUKON */
+	return (ReturnCode);
+
+}	/* SkAddrMcUpdate */
+
+
+#ifdef GENESIS
+
+/******************************************************************************
+ *
+ *	SkAddrXmacMcUpdate - update the HW MC address table and set the MAC address
+ *
+ * Description:
+ *	This routine enables reception of the addresses contained in a local
+ *	table for a given port.
+ *	It also programs the port's current physical MAC address.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_MC_FILTERING_EXACT
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+static int	SkAddrXmacMcUpdate(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortNumber)	/* Port Number */
+{
+	SK_U32		i;
+	SK_U8		Inexact;
+	SK_U16		*OutAddr;
+	SK_ADDR_PORT	*pAPort;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("SkAddrXmacMcUpdate on Port %u.\n", PortNumber))
+	
+	pAPort = &pAC->Addr.Port[PortNumber];
+
+#ifdef DEBUG
+	SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
+#endif /* DEBUG */
+
+	/* Start with 0 to also program the logical MAC address. */
+	for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
+		/* Set exact match address i on XMAC */
+		OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0];
+		XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
+	}
+
+	/* Clear other permanent exact match addresses on XMAC */
+	if (pAPort->NextExactMatchRlmt <= SK_ADDR_LAST_MATCH_RLMT) {
+		
+		SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchRlmt,
+			SK_ADDR_LAST_MATCH_RLMT);
+	}
+
+	for (i = pAPort->FirstExactMatchDrv; i < pAPort->NextExactMatchDrv; i++) {
+		OutAddr = (SK_U16 *) &pAPort->Exact[i].a[0];
+		XM_OUTADDR(IoC, PortNumber, XM_EXM(i), OutAddr);
+	}
+
+	/* Clear other non-permanent exact match addresses on XMAC */
+	if (pAPort->NextExactMatchDrv <= SK_ADDR_LAST_MATCH_DRV) {
+		
+		SkXmClrExactAddr(pAC, IoC, PortNumber, pAPort->NextExactMatchDrv,
+			SK_ADDR_LAST_MATCH_DRV);
+	}
+
+	for (Inexact = 0, i = 0; i < 8; i++) {
+		Inexact |= pAPort->InexactFilter.Bytes[i];
+	}
+
+	if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {
+		
+		/* Set all bits in 64-bit hash register. */
+		XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
+		
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+	}
+	else if (Inexact != 0) {
+		
+		/* Set 64-bit hash register to InexactFilter. */
+		XM_OUTHASH(IoC, PortNumber, XM_HSM, &pAPort->InexactFilter.Bytes[0]);
+		
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+	}
+	else {
+		/* Disable Hashing */
+		SkMacHashing(pAC, IoC, (int) PortNumber, SK_FALSE);
+	}
+
+	if (pAPort->PromMode != SK_PROM_MODE_NONE) {
+		(void) SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
+	}
+
+	/* Set port's current physical MAC address. */
+	OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
+	
+	XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
+
+#ifdef xDEBUG
+	for (i = 0; i < pAPort->NextExactMatchRlmt; i++) {
+		SK_U8		InAddr8[6];
+		SK_U16		*InAddr;
+
+		/* Get exact match address i from port PortNumber. */
+		InAddr = (SK_U16 *) &InAddr8[0];
+		
+		XM_INADDR(IoC, PortNumber, XM_EXM(i), InAddr);
+		
+		SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+			("SkAddrXmacMcUpdate: MC address %d on Port %u: ",
+			 "%02x %02x %02x %02x %02x %02x -- %02x %02x %02x %02x %02x %02x\n",
+				i,
+				PortNumber,
+				InAddr8[0],
+				InAddr8[1],
+				InAddr8[2],
+				InAddr8[3],
+				InAddr8[4],
+				InAddr8[5],
+				pAPort->Exact[i].a[0],
+				pAPort->Exact[i].a[1],
+				pAPort->Exact[i].a[2],
+				pAPort->Exact[i].a[3],
+				pAPort->Exact[i].a[4],
+				pAPort->Exact[i].a[5]))
+	}
+#endif /* DEBUG */
+
+	/* Determine return value. */
+	if (Inexact == 0 && pAPort->PromMode == 0) {
+		return (SK_MC_FILTERING_EXACT);
+	}
+	else {
+		return (SK_MC_FILTERING_INEXACT);
+	}
+	
+}	/* SkAddrXmacMcUpdate */
+
+#endif  /* GENESIS */
+
+#ifdef YUKON
+
+/******************************************************************************
+ *
+ *	SkAddrGmacMcUpdate - update the HW MC address table and set the MAC address
+ *
+ * Description:
+ *	This routine enables reception of the addresses contained in a local
+ *	table for a given port.
+ *	It also programs the port's current physical MAC address.
+ *
+ * Notes:
+ *	The return code is only valid for SK_PROM_MODE_NONE.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_MC_FILTERING_EXACT
+ *	SK_MC_FILTERING_INEXACT
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+static int	SkAddrGmacMcUpdate(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* I/O context */
+SK_U32	PortNumber)	/* Port Number */
+{
+#ifndef SK_SLIM
+	SK_U32		i;
+	SK_U8		Inexact;
+#endif	/* not SK_SLIM */
+	SK_U16		*OutAddr;
+	SK_ADDR_PORT	*pAPort;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("SkAddrGmacMcUpdate on Port %u.\n", PortNumber))
+	
+	pAPort = &pAC->Addr.Port[PortNumber];
+
+#ifdef DEBUG
+	SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("Next0 on Port %d: %d\n", PortNumber, Next0[PortNumber]))
+#endif /* DEBUG */
+	
+#ifndef SK_SLIM
+	for (Inexact = 0, i = 0; i < 8; i++) {
+		Inexact |= pAPort->InexactFilter.Bytes[i];
+	}
+	
+	/* Set 64-bit hash register to InexactFilter. */
+	GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1,
+		&pAPort->InexactFilter.Bytes[0]);
+	
+	if (pAPort->PromMode & SK_PROM_MODE_ALL_MC) {				
+		
+		/* Set all bits in 64-bit hash register. */
+		GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
+		
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+	}
+	else {	
+		/* Enable Hashing. */
+		SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+	}
+	
+	if (pAPort->PromMode != SK_PROM_MODE_NONE) {
+		(void) SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
+	}
+#else /* SK_SLIM */
+
+	/* Set all bits in 64-bit hash register. */
+	GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
+
+	/* Enable Hashing */
+	SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+	
+	(void) SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, pAPort->PromMode);
+	
+#endif /* SK_SLIM */
+	
+	/* Set port's current physical MAC address. */
+	OutAddr = (SK_U16 *) &pAPort->CurrentMacAddress.a[0];
+	GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr);
+	
+	/* Set port's current logical MAC address. */
+	OutAddr = (SK_U16 *) &pAPort->Exact[0].a[0];
+	GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_2L, OutAddr);
+	
+#ifdef DEBUG
+	SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("SkAddrGmacMcUpdate: Permanent Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+			pAPort->Exact[0].a[0],
+			pAPort->Exact[0].a[1],
+			pAPort->Exact[0].a[2],
+			pAPort->Exact[0].a[3],
+			pAPort->Exact[0].a[4],
+			pAPort->Exact[0].a[5]))
+	
+	SK_DBG_MSG(pAC, SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+		("SkAddrGmacMcUpdate: Physical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+			pAPort->CurrentMacAddress.a[0],
+			pAPort->CurrentMacAddress.a[1],
+			pAPort->CurrentMacAddress.a[2],
+			pAPort->CurrentMacAddress.a[3],
+			pAPort->CurrentMacAddress.a[4],
+			pAPort->CurrentMacAddress.a[5]))
+#endif /* DEBUG */
+	
+#ifndef SK_SLIM
+	/* Determine return value. */
+	if (Inexact == 0 && pAPort->PromMode == 0) {
+		return (SK_MC_FILTERING_EXACT);
+	}
+	else {
+		return (SK_MC_FILTERING_INEXACT);
+	}
+#else /* SK_SLIM */
+	return (SK_MC_FILTERING_INEXACT);
+#endif /* SK_SLIM */
+	
+}	/* SkAddrGmacMcUpdate */
+
+#endif /* YUKON */
+
+#ifndef SK_NO_MAO
+
+/******************************************************************************
+ *
+ *	SkAddrOverride - override a port's MAC address
+ *
+ * Description:
+ *	This routine overrides the MAC address of one port.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS if successful.
+ *	SK_ADDR_DUPLICATE_ADDRESS if duplicate MAC address.
+ *	SK_ADDR_MULTICAST_ADDRESS if multicast or broadcast address.
+ *	SK_ADDR_TOO_EARLY if SK_INIT_IO was not executed before.
+ */
+int	SkAddrOverride(
+SK_AC		*pAC,				/* adapter context */
+SK_IOC		IoC,				/* I/O context */
+SK_U32		PortNumber,			/* Port Number */
+SK_MAC_ADDR	SK_FAR *pNewAddr,	/* new MAC address */
+int			Flags)				/* logical/physical MAC address */
+{
+#ifndef SK_NO_RLMT
+	SK_EVPARA	Para;
+#endif /* !SK_NO_RLMT */
+	SK_U32		NetNumber;
+	SK_U32		i;
+	SK_U16		SK_FAR *OutAddr;
+
+#ifndef SK_NO_RLMT
+	NetNumber = pAC->Rlmt.Port[PortNumber].Net->NetNumber;
+#else
+	NetNumber = 0;
+#endif /* SK_NO_RLMT */
+#if (!defined(SK_SLIM) || defined(DEBUG))
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+#endif /* !SK_SLIM || DEBUG */
+	if (pNewAddr != NULL && (pNewAddr->a[0] & SK_MC_BIT) != 0) {
+		return (SK_ADDR_MULTICAST_ADDRESS);
+	}
+
+	if (!pAC->Addr.Net[NetNumber].CurrentMacAddressSet) {
+		return (SK_ADDR_TOO_EARLY);
+	}
+
+	if (Flags & SK_ADDR_SET_LOGICAL) {	/* Activate logical MAC address. */
+		/* Parameter *pNewAddr is ignored. */
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+				return (SK_ADDR_TOO_EARLY);
+			}
+		}
+#ifndef SK_NO_RLMT
+		/* Set PortNumber to number of net's active port. */
+		PortNumber = pAC->Rlmt.Net[NetNumber].
+			Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
+#endif /* !SK_NO_RLMT */
+		pAC->Addr.Port[PortNumber].Exact[0] =
+			pAC->Addr.Net[NetNumber].CurrentMacAddress;
+
+		/* Write address to first exact match entry of active port. */
+		(void) SkAddrMcUpdate(pAC, IoC, PortNumber);
+	}
+	else if (Flags & SK_ADDR_CLEAR_LOGICAL) {
+		/* Deactivate logical MAC address. */
+		/* Parameter *pNewAddr is ignored. */
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+				return (SK_ADDR_TOO_EARLY);
+			}
+		}
+#ifndef SK_NO_RLMT
+		/* Set PortNumber to number of net's active port. */
+		PortNumber = pAC->Rlmt.Net[NetNumber].
+			Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
+#endif /* !SK_NO_RLMT */
+		for (i = 0; i < SK_MAC_ADDR_LEN; i++ ) {
+			pAC->Addr.Port[PortNumber].Exact[0].a[i] = 0;
+		}
+
+		/* Write address to first exact match entry of active port. */
+		(void) SkAddrMcUpdate(pAC, IoC, PortNumber);
+	}
+	else if (Flags & SK_ADDR_PHYSICAL_ADDRESS) {	/* Physical MAC address. */
+		if (SK_ADDR_EQUAL(pNewAddr->a,
+			pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
+			return (SK_ADDR_DUPLICATE_ADDRESS);
+		}
+
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+				return (SK_ADDR_TOO_EARLY);
+			}
+
+			if (SK_ADDR_EQUAL(pNewAddr->a,
+				pAC->Addr.Port[i].CurrentMacAddress.a)) {
+				if (i == PortNumber) {
+					return (SK_ADDR_SUCCESS);
+				}
+				else {
+					return (SK_ADDR_DUPLICATE_ADDRESS);
+				}
+			}
+		}
+
+		pAC->Addr.Port[PortNumber].PreviousMacAddress =
+			pAC->Addr.Port[PortNumber].CurrentMacAddress;
+		pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr;
+
+		/* Change port's physical MAC address. */
+		OutAddr = (SK_U16 SK_FAR *) pNewAddr;
+#ifdef GENESIS
+		if (pAC->GIni.GIGenesis) {
+			XM_OUTADDR(IoC, PortNumber, XM_SA, OutAddr);
+		}
+#endif /* GENESIS */
+#ifdef YUKON
+		if (!pAC->GIni.GIGenesis) {
+			GM_OUTADDR(IoC, PortNumber, GM_SRC_ADDR_1L, OutAddr);
+		}
+#endif /* YUKON */
+
+#ifndef SK_NO_RLMT
+		/* Report address change to RLMT. */
+		Para.Para32[0] = PortNumber;
+		Para.Para32[0] = -1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para);
+#endif /* !SK_NO_RLMT */
+	}
+	else {	/* Logical MAC address. */
+		if (SK_ADDR_EQUAL(pNewAddr->a,
+			pAC->Addr.Net[NetNumber].CurrentMacAddress.a)) {
+			return (SK_ADDR_SUCCESS);
+		}
+		
+		for (i = 0; i < (SK_U32) pAC->GIni.GIMacsFound; i++) {
+			if (!pAC->Addr.Port[i].CurrentMacAddressSet) {
+				return (SK_ADDR_TOO_EARLY);
+			}
+
+			if (SK_ADDR_EQUAL(pNewAddr->a,
+				pAC->Addr.Port[i].CurrentMacAddress.a)) {
+				return (SK_ADDR_DUPLICATE_ADDRESS);
+			}
+		}
+		
+		/*
+		 * In case that the physical and the logical MAC addresses are equal
+		 * we must also change the physical MAC address here.
+		 * In this case we have an adapter which initially was programmed with
+		 * two identical MAC addresses.
+		 */
+		if (SK_ADDR_EQUAL(pAC->Addr.Port[PortNumber].CurrentMacAddress.a,
+				pAC->Addr.Port[PortNumber].Exact[0].a)) {
+			
+			pAC->Addr.Port[PortNumber].PreviousMacAddress =
+				pAC->Addr.Port[PortNumber].CurrentMacAddress;
+			pAC->Addr.Port[PortNumber].CurrentMacAddress = *pNewAddr;
+			
+#ifndef SK_NO_RLMT
+			/* Report address change to RLMT. */
+			Para.Para32[0] = PortNumber;
+			Para.Para32[0] = -1;
+			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_PORT_ADDR, Para);
+#endif /* !SK_NO_RLMT */
+		}
+		
+#ifndef SK_NO_RLMT
+		/* Set PortNumber to number of net's active port. */
+		PortNumber = pAC->Rlmt.Net[NetNumber].
+			Port[pAC->Addr.Net[NetNumber].ActivePort]->PortNumber;
+#endif /* !SK_NO_RLMT */
+		pAC->Addr.Net[NetNumber].CurrentMacAddress = *pNewAddr;
+		pAC->Addr.Port[PortNumber].Exact[0] = *pNewAddr;
+#ifdef DEBUG
+		SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+			("SkAddrOverride: Permanent MAC Address: %02X %02X %02X %02X %02X %02X\n",
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[0],
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[1],
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[2],
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[3],
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[4],
+				pAC->Addr.Net[NetNumber].PermanentMacAddress.a[5]))
+		
+		SK_DBG_MSG(pAC,SK_DBGMOD_ADDR, SK_DBGCAT_CTRL,
+			("SkAddrOverride: New logical MAC Address: %02X %02X %02X %02X %02X %02X\n",
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[0],
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[1],
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[2],
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[3],
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[4],
+				pAC->Addr.Net[NetNumber].CurrentMacAddress.a[5]))
+#endif /* DEBUG */
+
+        /* Write address to first exact match entry of active port. */
+		(void) SkAddrMcUpdate(pAC, IoC, PortNumber);
+	}
+
+	return (SK_ADDR_SUCCESS);
+	
+}	/* SkAddrOverride */
+
+
+#endif /* SK_NO_MAO */
+
+/******************************************************************************
+ *
+ *	SkAddrPromiscuousChange - set promiscuous mode for given port
+ *
+ * Description:
+ *	This routine manages promiscuous mode:
+ *	- none
+ *	- all LLC frames
+ *	- all MC frames
+ *
+ *	It calls either SkAddrXmacPromiscuousChange or
+ *	SkAddrGmacPromiscuousChange, according to the adapter in use.
+ *	The real work is done there.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrPromiscuousChange(
+SK_AC	*pAC,			/* adapter context */
+SK_IOC	IoC,			/* I/O context */
+SK_U32	PortNumber,		/* port whose promiscuous mode changes */
+int		NewPromMode)	/* new promiscuous mode */
+{
+	int ReturnCode = 0;
+#if (!defined(SK_SLIM) || defined(DEBUG))
+	if (PortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+#endif /* !SK_SLIM || DEBUG */
+
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+		ReturnCode =
+			SkAddrXmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode);
+	}
+#endif /* GENESIS */
+#ifdef YUKON
+	if (!pAC->GIni.GIGenesis) {
+		ReturnCode =
+			SkAddrGmacPromiscuousChange(pAC, IoC, PortNumber, NewPromMode);
+	}
+#endif /* YUKON */
+
+	return (ReturnCode);
+
+}	/* SkAddrPromiscuousChange */
+
+#ifdef GENESIS
+
+/******************************************************************************
+ *
+ *	SkAddrXmacPromiscuousChange - set promiscuous mode for given port
+ *
+ * Description:
+ *	This routine manages promiscuous mode:
+ *	- none
+ *	- all LLC frames
+ *	- all MC frames
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+static int	SkAddrXmacPromiscuousChange(
+SK_AC	*pAC,			/* adapter context */
+SK_IOC	IoC,			/* I/O context */
+SK_U32	PortNumber,		/* port whose promiscuous mode changes */
+int		NewPromMode)	/* new promiscuous mode */
+{
+	int			i;
+	SK_BOOL		InexactModeBit;
+	SK_U8		Inexact;
+	SK_U8		HwInexact;
+	SK_FILTER64	HwInexactFilter;
+	SK_U16		LoMode;		/* Lower 16 bits of XMAC Mode Register. */
+	int			CurPromMode = SK_PROM_MODE_NONE;
+
+	/* Read CurPromMode from Hardware. */
+	XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
+
+	if ((LoMode & XM_MD_ENA_PROM) != 0) {
+		/* Promiscuous mode! */
+		CurPromMode |= SK_PROM_MODE_LLC;
+	}
+	
+	for (Inexact = 0xFF, i = 0; i < 8; i++) {
+		Inexact &= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
+	}
+	if (Inexact == 0xFF) {
+		CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
+	}
+	else {
+		/* Get InexactModeBit (bit XM_MD_ENA_HASH in mode register) */
+		XM_IN16(IoC, PortNumber, XM_MODE, &LoMode);
+		
+		InexactModeBit = (LoMode & XM_MD_ENA_HASH) != 0;
+
+		/* Read 64-bit hash register from XMAC */
+		XM_INHASH(IoC, PortNumber, XM_HSM, &HwInexactFilter.Bytes[0]);
+
+		for (HwInexact = 0xFF, i = 0; i < 8; i++) {
+			HwInexact &= HwInexactFilter.Bytes[i];
+		}
+
+		if (InexactModeBit && (HwInexact == 0xFF)) {
+			CurPromMode |= SK_PROM_MODE_ALL_MC;
+		}
+	}
+
+	pAC->Addr.Port[PortNumber].PromMode = NewPromMode;
+
+	if (NewPromMode == CurPromMode) {
+		return (SK_ADDR_SUCCESS);
+	}
+
+	if ((NewPromMode & SK_PROM_MODE_ALL_MC) &&
+		!(CurPromMode & SK_PROM_MODE_ALL_MC)) {	/* All MC. */
+		
+		/* Set all bits in 64-bit hash register. */
+		XM_OUTHASH(IoC, PortNumber, XM_HSM, &OnesHash);
+
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+	}
+	else if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
+		!(NewPromMode & SK_PROM_MODE_ALL_MC)) {	/* Norm MC. */
+		for (Inexact = 0, i = 0; i < 8; i++) {
+			Inexact |= pAC->Addr.Port[PortNumber].InexactFilter.Bytes[i];
+		}
+		if (Inexact == 0) {
+			/* Disable Hashing */
+			SkMacHashing(pAC, IoC, (int) PortNumber, SK_FALSE);
+		}
+		else {
+			/* Set 64-bit hash register to InexactFilter. */
+			XM_OUTHASH(IoC, PortNumber, XM_HSM,
+				&pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
+
+			/* Enable Hashing */
+			SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+		}
+	}
+
+	if ((NewPromMode & SK_PROM_MODE_LLC) &&
+		!(CurPromMode & SK_PROM_MODE_LLC)) {	/* Prom. LLC */
+		/* Set the MAC in Promiscuous Mode */
+		SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_TRUE);
+	}
+	else if ((CurPromMode & SK_PROM_MODE_LLC) &&
+		!(NewPromMode & SK_PROM_MODE_LLC)) {	/* Norm. LLC. */
+		/* Clear Promiscuous Mode */
+		SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_FALSE);
+	}
+	
+	return (SK_ADDR_SUCCESS);
+	
+}	/* SkAddrXmacPromiscuousChange */
+
+#endif /* GENESIS */
+
+#ifdef YUKON
+
+/******************************************************************************
+ *
+ *	SkAddrGmacPromiscuousChange - set promiscuous mode for given port
+ *
+ * Description:
+ *	This routine manages promiscuous mode:
+ *	- none
+ *	- all LLC frames
+ *	- all MC frames
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+static int	SkAddrGmacPromiscuousChange(
+SK_AC	*pAC,			/* adapter context */
+SK_IOC	IoC,			/* I/O context */
+SK_U32	PortNumber,		/* port whose promiscuous mode changes */
+int		NewPromMode)	/* new promiscuous mode */
+{
+	SK_U16		ReceiveControl;	/* GMAC Receive Control Register */
+	int		CurPromMode = SK_PROM_MODE_NONE;
+
+	/* Read CurPromMode from Hardware. */
+	GM_IN16(IoC, PortNumber, GM_RX_CTRL, &ReceiveControl);
+
+	if ((ReceiveControl & (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA)) == 0) {
+		/* Promiscuous mode! */
+		CurPromMode |= SK_PROM_MODE_LLC;
+	}
+
+	if ((ReceiveControl & GM_RXCR_MCF_ENA) == 0) {
+		/* All Multicast mode! */
+		CurPromMode |= (pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_ALL_MC);
+	}
+
+	pAC->Addr.Port[PortNumber].PromMode = NewPromMode;
+
+	if (NewPromMode == CurPromMode) {
+		return (SK_ADDR_SUCCESS);
+	}
+	
+	if ((NewPromMode & SK_PROM_MODE_ALL_MC) &&
+		!(CurPromMode & SK_PROM_MODE_ALL_MC)) {	/* All MC */
+		
+		/* Set all bits in 64-bit hash register. */
+		GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1, &OnesHash);
+		
+		/* Enable Hashing */
+		SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+	}
+	
+	if ((CurPromMode & SK_PROM_MODE_ALL_MC) &&
+		!(NewPromMode & SK_PROM_MODE_ALL_MC)) {	/* Norm. MC */
+
+		/* Set 64-bit hash register to InexactFilter. */
+		GM_OUTHASH(IoC, PortNumber, GM_MC_ADDR_H1,
+			&pAC->Addr.Port[PortNumber].InexactFilter.Bytes[0]);
+
+		/* Enable Hashing. */
+		SkMacHashing(pAC, IoC, (int) PortNumber, SK_TRUE);
+	}
+
+	if ((NewPromMode & SK_PROM_MODE_LLC) &&
+		!(CurPromMode & SK_PROM_MODE_LLC)) {	/* Prom. LLC */
+		
+		/* Set the MAC to Promiscuous Mode. */
+		SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_TRUE);
+	}
+	else if ((CurPromMode & SK_PROM_MODE_LLC) &&
+		!(NewPromMode & SK_PROM_MODE_LLC)) {	/* Norm. LLC */
+		
+		/* Clear Promiscuous Mode. */
+		SkMacPromiscMode(pAC, IoC, (int) PortNumber, SK_FALSE);
+	}
+
+	return (SK_ADDR_SUCCESS);
+	
+}	/* SkAddrGmacPromiscuousChange */
+
+#endif /* YUKON */
+
+#ifndef SK_SLIM
+
+/******************************************************************************
+ *
+ *	SkAddrSwap - swap address info
+ *
+ * Description:
+ *	This routine swaps address info of two ports.
+ *
+ * Context:
+ *	runtime, pageable
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	SK_ADDR_SUCCESS
+ *	SK_ADDR_ILLEGAL_PORT
+ */
+int	SkAddrSwap(
+SK_AC	*pAC,			/* adapter context */
+SK_IOC	IoC,			/* I/O context */
+SK_U32	FromPortNumber,		/* Port1 Index */
+SK_U32	ToPortNumber)		/* Port2 Index */
+{
+	int			i;
+	SK_U8		Byte;
+	SK_MAC_ADDR	MacAddr;
+	SK_U32		DWord;
+
+	if (FromPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	if (ToPortNumber >= (SK_U32) pAC->GIni.GIMacsFound) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	if (pAC->Rlmt.Port[FromPortNumber].Net != pAC->Rlmt.Port[ToPortNumber].Net) {
+		return (SK_ADDR_ILLEGAL_PORT);
+	}
+
+	/*
+	 * Swap:
+	 * - Exact Match Entries (GEnesis and Yukon)
+	 *   Yukon uses first entry for the logical MAC
+	 *   address (stored in the second GMAC register).
+	 * - FirstExactMatchRlmt (GEnesis only)
+	 * - NextExactMatchRlmt (GEnesis only)
+	 * - FirstExactMatchDrv (GEnesis only)
+	 * - NextExactMatchDrv (GEnesis only)
+	 * - 64-bit filter (InexactFilter)
+	 * - Promiscuous Mode
+	 * of ports.
+	 */
+
+	for (i = 0; i < SK_ADDR_EXACT_MATCHES; i++) {
+		MacAddr = pAC->Addr.Port[FromPortNumber].Exact[i];
+		pAC->Addr.Port[FromPortNumber].Exact[i] =
+			pAC->Addr.Port[ToPortNumber].Exact[i];
+		pAC->Addr.Port[ToPortNumber].Exact[i] = MacAddr;
+	}
+
+	for (i = 0; i < 8; i++) {
+		Byte = pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i];
+		pAC->Addr.Port[FromPortNumber].InexactFilter.Bytes[i] =
+			pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i];
+		pAC->Addr.Port[ToPortNumber].InexactFilter.Bytes[i] = Byte;
+	}
+	
+	i = pAC->Addr.Port[FromPortNumber].PromMode;
+	pAC->Addr.Port[FromPortNumber].PromMode = pAC->Addr.Port[ToPortNumber].PromMode;
+	pAC->Addr.Port[ToPortNumber].PromMode = i;
+	
+	if (pAC->GIni.GIGenesis) {
+		DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt;
+		pAC->Addr.Port[FromPortNumber].FirstExactMatchRlmt =
+			pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt;
+		pAC->Addr.Port[ToPortNumber].FirstExactMatchRlmt = DWord;
+		
+		DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt;
+		pAC->Addr.Port[FromPortNumber].NextExactMatchRlmt =
+			pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt;
+		pAC->Addr.Port[ToPortNumber].NextExactMatchRlmt = DWord;
+		
+		DWord = pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv;
+		pAC->Addr.Port[FromPortNumber].FirstExactMatchDrv =
+			pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv;
+		pAC->Addr.Port[ToPortNumber].FirstExactMatchDrv = DWord;
+		
+		DWord = pAC->Addr.Port[FromPortNumber].NextExactMatchDrv;
+		pAC->Addr.Port[FromPortNumber].NextExactMatchDrv =
+			pAC->Addr.Port[ToPortNumber].NextExactMatchDrv;
+		pAC->Addr.Port[ToPortNumber].NextExactMatchDrv = DWord;
+	}
+	
+	/* CAUTION: Solution works if only ports of one adapter are in use. */
+	for (i = 0; (SK_U32) i < pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].
+		Net->NetNumber].NumPorts; i++) {
+		if (pAC->Rlmt.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
+			Port[i]->PortNumber == ToPortNumber) {
+			pAC->Addr.Net[pAC->Rlmt.Port[ToPortNumber].Net->NetNumber].
+				ActivePort = i;
+			/* 20001207 RA: Was "ToPortNumber;". */
+		}
+	}
+	
+	(void) SkAddrMcUpdate(pAC, IoC, FromPortNumber);
+	(void) SkAddrMcUpdate(pAC, IoC, ToPortNumber);
+
+	return (SK_ADDR_SUCCESS);
+	
+}	/* SkAddrSwap */
+
+#endif /* !SK_SLIM */
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
+
diff --git a/drivers/net/sk98lin/skdim.c b/drivers/net/sk98lin/skdim.c
new file mode 100644
index 0000000..37ce03f
--- /dev/null
+++ b/drivers/net/sk98lin/skdim.c
@@ -0,0 +1,742 @@
+/******************************************************************************
+ *
+ * Name:	skdim.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.5 $
+ * Date:	$Date: 2003/11/28 12:55:40 $
+ * Purpose:	All functions to maintain interrupt moderation
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module is intended to manage the dynamic interrupt moderation on both   
+ * GEnesis and Yukon adapters.
+ *
+ * Include File Hierarchy:
+ *
+ *	"skdrv1st.h"
+ *	"skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef	lint
+static const char SysKonnectFileId[] =
+	"@(#) $Id: skdim.c,v 1.5 2003/11/28 12:55:40 rroesler Exp $ (C) SysKonnect.";
+#endif
+
+#define __SKADDR_C
+
+#ifdef __cplusplus
+#error C++ is not yet supported.
+extern "C" {
+#endif
+
+/*******************************************************************************
+**
+** Includes
+**
+*******************************************************************************/
+
+#ifndef __INC_SKDRV1ST_H
+#include "h/skdrv1st.h"
+#endif
+
+#ifndef __INC_SKDRV2ND_H
+#include "h/skdrv2nd.h"
+#endif
+
+#include	<linux/kernel_stat.h>
+
+/*******************************************************************************
+**
+** Defines
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Typedefs
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Local function prototypes 
+**
+*******************************************************************************/
+
+static unsigned int GetCurrentSystemLoad(SK_AC *pAC);
+static SK_U64       GetIsrCalls(SK_AC *pAC);
+static SK_BOOL      IsIntModEnabled(SK_AC *pAC);
+static void         SetCurrIntCtr(SK_AC *pAC);
+static void         EnableIntMod(SK_AC *pAC); 
+static void         DisableIntMod(SK_AC *pAC);
+static void         ResizeDimTimerDuration(SK_AC *pAC);
+static void         DisplaySelectedModerationType(SK_AC *pAC);
+static void         DisplaySelectedModerationMask(SK_AC *pAC);
+static void         DisplayDescrRatio(SK_AC *pAC);
+
+/*******************************************************************************
+**
+** Global variables
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Local variables
+**
+*******************************************************************************/
+
+/*******************************************************************************
+**
+** Global functions 
+**
+*******************************************************************************/
+
+/*******************************************************************************
+** Function     : SkDimModerate
+** Description  : Called in every ISR to check if moderation is to be applied
+**                or not for the current number of interrupts
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : void (!)
+** Notes        : -
+*******************************************************************************/
+
+void 
+SkDimModerate(SK_AC *pAC) {
+    unsigned int CurrSysLoad    = 0;  /* expressed in percent */
+    unsigned int LoadIncrease   = 0;  /* expressed in percent */
+    SK_U64       ThresholdInts  = 0;
+    SK_U64       IsrCallsPerSec = 0;
+
+#define M_DIMINFO pAC->DynIrqModInfo
+
+    if (!IsIntModEnabled(pAC)) {
+        if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) {
+            CurrSysLoad = GetCurrentSystemLoad(pAC);
+            if (CurrSysLoad > 75) {
+                    /* 
+                    ** More than 75% total system load! Enable the moderation 
+                    ** to shield the system against too many interrupts.
+                    */
+                    EnableIntMod(pAC);
+            } else if (CurrSysLoad > M_DIMINFO.PrevSysLoad) {
+                LoadIncrease = (CurrSysLoad - M_DIMINFO.PrevSysLoad);
+                if (LoadIncrease > ((M_DIMINFO.PrevSysLoad *
+                                         C_INT_MOD_ENABLE_PERCENTAGE) / 100)) {
+                    if (CurrSysLoad > 10) {
+                        /* 
+                        ** More than 50% increase with respect to the 
+                        ** previous load of the system. Most likely this 
+                        ** is due to our ISR-proc...
+                        */
+                        EnableIntMod(pAC);
+                    }
+                }
+            } else {
+                /*
+                ** Neither too much system load at all nor too much increase
+                ** with respect to the previous system load. Hence, we can leave
+                ** the ISR-handling like it is without enabling moderation.
+                */
+            }
+            M_DIMINFO.PrevSysLoad = CurrSysLoad;
+        }   
+    } else {
+        if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) {
+            ThresholdInts  = ((M_DIMINFO.MaxModIntsPerSec *
+                                   C_INT_MOD_DISABLE_PERCENTAGE) / 100);
+            IsrCallsPerSec = GetIsrCalls(pAC);
+            if (IsrCallsPerSec <= ThresholdInts) {
+                /* 
+                ** The number of interrupts within the last second is 
+                ** lower than the disable_percentage of the desried 
+                ** maxrate. Therefore we can disable the moderation.
+                */
+                DisableIntMod(pAC);
+                M_DIMINFO.MaxModIntsPerSec = 
+                   (M_DIMINFO.MaxModIntsPerSecUpperLimit +
+                    M_DIMINFO.MaxModIntsPerSecLowerLimit) / 2;
+            } else {
+                /*
+                ** The number of interrupts per sec is the same as expected.
+                ** Evalulate the descriptor-ratio. If it has changed, a resize 
+                ** in the moderation timer might be useful
+                */
+                if (M_DIMINFO.AutoSizing) {
+                    ResizeDimTimerDuration(pAC);
+                }
+            }
+        }
+    }
+
+    /*
+    ** Some information to the log...
+    */
+    if (M_DIMINFO.DisplayStats) {
+        DisplaySelectedModerationType(pAC);
+        DisplaySelectedModerationMask(pAC);
+        DisplayDescrRatio(pAC);
+    }
+
+    M_DIMINFO.NbrProcessedDescr = 0; 
+    SetCurrIntCtr(pAC);
+}
+
+/*******************************************************************************
+** Function     : SkDimStartModerationTimer
+** Description  : Starts the audit-timer for the dynamic interrupt moderation
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : void (!)
+** Notes        : -
+*******************************************************************************/
+
+void 
+SkDimStartModerationTimer(SK_AC *pAC) {
+    SK_EVPARA    EventParam;   /* Event struct for timer event */
+ 
+    SK_MEMSET((char *) &EventParam, 0, sizeof(EventParam));
+    EventParam.Para32[0] = SK_DRV_MODERATION_TIMER;
+    SkTimerStart(pAC, pAC->IoBase, &pAC->DynIrqModInfo.ModTimer,
+                 SK_DRV_MODERATION_TIMER_LENGTH,
+                 SKGE_DRV, SK_DRV_TIMER, EventParam);
+}
+
+/*******************************************************************************
+** Function     : SkDimEnableModerationIfNeeded
+** Description  : Either enables or disables moderation
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : void (!)
+** Notes        : This function is called when a particular adapter is opened
+**                There is no Disable function, because when all interrupts 
+**                might be disable, the moderation timer has no meaning at all
+******************************************************************************/
+
+void
+SkDimEnableModerationIfNeeded(SK_AC *pAC) {
+
+    if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_STATIC) {
+        EnableIntMod(pAC);   /* notification print in this function */
+    } else if (M_DIMINFO.IntModTypeSelect == C_INT_MOD_DYNAMIC) {
+        SkDimStartModerationTimer(pAC);
+        if (M_DIMINFO.DisplayStats) {
+            printk("Dynamic moderation has been enabled\n");
+        }
+    } else {
+        if (M_DIMINFO.DisplayStats) {
+            printk("No moderation has been enabled\n");
+        }
+    }
+}
+
+/*******************************************************************************
+** Function     : SkDimDisplayModerationSettings
+** Description  : Displays the current settings regarding interrupt moderation
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : void (!)
+** Notes        : -
+*******************************************************************************/
+
+void 
+SkDimDisplayModerationSettings(SK_AC *pAC) {
+    DisplaySelectedModerationType(pAC);
+    DisplaySelectedModerationMask(pAC);
+}
+
+/*******************************************************************************
+**
+** Local functions 
+**
+*******************************************************************************/
+
+/*******************************************************************************
+** Function     : GetCurrentSystemLoad
+** Description  : Retrieves the current system load of the system. This load
+**                is evaluated for all processors within the system.
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : unsigned int: load expressed in percentage
+** Notes        : The possible range being returned is from 0 up to 100.
+**                Whereas 0 means 'no load at all' and 100 'system fully loaded'
+**                It is impossible to determine what actually causes the system
+**                to be in 100%, but maybe that is due to too much interrupts.
+*******************************************************************************/
+
+static unsigned int
+GetCurrentSystemLoad(SK_AC *pAC) {
+	unsigned long jif         = jiffies;
+	unsigned int  UserTime    = 0;
+	unsigned int  SystemTime  = 0;
+	unsigned int  NiceTime    = 0;
+	unsigned int  IdleTime    = 0;
+	unsigned int  TotalTime   = 0;
+	unsigned int  UsedTime    = 0;
+	unsigned int  SystemLoad  = 0;
+
+	/* unsigned int  NbrCpu      = 0; */
+
+	/*
+	** The following lines have been commented out, because
+	** from kernel 2.5.44 onwards, the kernel-owned structure
+	**
+	**      struct kernel_stat kstat
+	**
+	** is not marked as an exported symbol in the file
+	**
+	**      kernel/ksyms.c 
+	**
+	** As a consequence, using this driver as KLM is not possible
+	** and any access of the structure kernel_stat via the 
+	** dedicated macros kstat_cpu(i).cpustat.xxx is to be avoided.
+	**
+	** The kstat-information might be added again in future 
+	** versions of the 2.5.xx kernel, but for the time being, 
+	** number of interrupts will serve as indication how much 
+	** load we currently have... 
+	**
+	** for (NbrCpu = 0; NbrCpu < num_online_cpus(); NbrCpu++) {
+	**	UserTime   = UserTime   + kstat_cpu(NbrCpu).cpustat.user;
+	**	NiceTime   = NiceTime   + kstat_cpu(NbrCpu).cpustat.nice;
+	**	SystemTime = SystemTime + kstat_cpu(NbrCpu).cpustat.system;
+	** }
+	*/
+	SK_U64 ThresholdInts  = 0;
+	SK_U64 IsrCallsPerSec = 0;
+
+	ThresholdInts  = ((M_DIMINFO.MaxModIntsPerSec *
+			   C_INT_MOD_ENABLE_PERCENTAGE) + 100);
+	IsrCallsPerSec = GetIsrCalls(pAC);
+	if (IsrCallsPerSec >= ThresholdInts) {
+	    /*
+	    ** We do not know how much the real CPU-load is!
+	    ** Return 80% as a default in order to activate DIM
+	    */
+	    SystemLoad = 80;
+	    return (SystemLoad);  
+	} 
+
+	UsedTime  = UserTime + NiceTime + SystemTime;
+
+	IdleTime  = jif * num_online_cpus() - UsedTime;
+	TotalTime = UsedTime + IdleTime;
+
+	SystemLoad = ( 100 * (UsedTime  - M_DIMINFO.PrevUsedTime) ) /
+						(TotalTime - M_DIMINFO.PrevTotalTime);
+
+	if (M_DIMINFO.DisplayStats) {
+		printk("Current system load is: %u\n", SystemLoad);
+	}
+
+	M_DIMINFO.PrevTotalTime = TotalTime;
+	M_DIMINFO.PrevUsedTime  = UsedTime;
+
+	return (SystemLoad);
+}
+
+/*******************************************************************************
+** Function     : GetIsrCalls
+** Description  : Depending on the selected moderation mask, this function will
+**                return the number of interrupts handled in the previous time-
+**                frame. This evaluated number is based on the current number 
+**                of interrupts stored in PNMI-context and the previous stored 
+**                interrupts.
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : int:   the number of interrupts being executed in the last
+**                       timeframe
+** Notes        : It makes only sense to call this function, when dynamic 
+**                interrupt moderation is applied
+*******************************************************************************/
+
+static SK_U64
+GetIsrCalls(SK_AC *pAC) {
+    SK_U64   RxPort0IntDiff = 0;
+    SK_U64   RxPort1IntDiff = 0;
+    SK_U64   TxPort0IntDiff = 0;
+    SK_U64   TxPort1IntDiff = 0;
+
+    if (pAC->DynIrqModInfo.MaskIrqModeration == IRQ_MASK_TX_ONLY) {
+        if (pAC->GIni.GIMacsFound == 2) {
+            TxPort1IntDiff = pAC->Pnmi.Port[1].TxIntrCts - 
+                             pAC->DynIrqModInfo.PrevPort1TxIntrCts;
+        }
+        TxPort0IntDiff = pAC->Pnmi.Port[0].TxIntrCts - 
+                         pAC->DynIrqModInfo.PrevPort0TxIntrCts;
+    } else if (pAC->DynIrqModInfo.MaskIrqModeration == IRQ_MASK_RX_ONLY) {
+        if (pAC->GIni.GIMacsFound == 2) {
+            RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts - 
+                             pAC->DynIrqModInfo.PrevPort1RxIntrCts;
+        }
+        RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts - 
+                         pAC->DynIrqModInfo.PrevPort0RxIntrCts;
+    } else {
+        if (pAC->GIni.GIMacsFound == 2) {
+            RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts - 
+                             pAC->DynIrqModInfo.PrevPort1RxIntrCts;
+            TxPort1IntDiff = pAC->Pnmi.Port[1].TxIntrCts - 
+                             pAC->DynIrqModInfo.PrevPort1TxIntrCts;
+        } 
+        RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts - 
+                         pAC->DynIrqModInfo.PrevPort0RxIntrCts;
+        TxPort0IntDiff = pAC->Pnmi.Port[0].TxIntrCts - 
+                         pAC->DynIrqModInfo.PrevPort0TxIntrCts;
+    }
+
+    return (RxPort0IntDiff + RxPort1IntDiff + TxPort0IntDiff + TxPort1IntDiff);
+}
+
+/*******************************************************************************
+** Function     : GetRxCalls
+** Description  : This function will return the number of times a receive inter-
+**                rupt was processed. This is needed to evaluate any resizing 
+**                factor.
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : SK_U64: the number of RX-ints being processed
+** Notes        : It makes only sense to call this function, when dynamic 
+**                interrupt moderation is applied
+*******************************************************************************/
+
+static SK_U64
+GetRxCalls(SK_AC *pAC) {
+    SK_U64   RxPort0IntDiff = 0;
+    SK_U64   RxPort1IntDiff = 0;
+
+    if (pAC->GIni.GIMacsFound == 2) {
+        RxPort1IntDiff = pAC->Pnmi.Port[1].RxIntrCts - 
+                         pAC->DynIrqModInfo.PrevPort1RxIntrCts;
+    }
+    RxPort0IntDiff = pAC->Pnmi.Port[0].RxIntrCts - 
+                     pAC->DynIrqModInfo.PrevPort0RxIntrCts;
+
+    return (RxPort0IntDiff + RxPort1IntDiff);
+}
+
+/*******************************************************************************
+** Function     : SetCurrIntCtr
+** Description  : Will store the current number orf occured interrupts in the 
+**                adapter context. This is needed to evaluated the number of 
+**                interrupts within a current timeframe.
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : void (!)
+** Notes        : -
+*******************************************************************************/
+
+static void
+SetCurrIntCtr(SK_AC *pAC) {
+    if (pAC->GIni.GIMacsFound == 2) {
+        pAC->DynIrqModInfo.PrevPort1RxIntrCts = pAC->Pnmi.Port[1].RxIntrCts;
+        pAC->DynIrqModInfo.PrevPort1TxIntrCts = pAC->Pnmi.Port[1].TxIntrCts;
+    } 
+    pAC->DynIrqModInfo.PrevPort0RxIntrCts = pAC->Pnmi.Port[0].RxIntrCts;
+    pAC->DynIrqModInfo.PrevPort0TxIntrCts = pAC->Pnmi.Port[0].TxIntrCts;
+}
+
+/*******************************************************************************
+** Function     : IsIntModEnabled()
+** Description  : Retrieves the current value of the interrupts moderation
+**                command register. Its content determines whether any 
+**                moderation is running or not.
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : SK_TRUE  : if mod timer running
+**                SK_FALSE : if no moderation is being performed
+** Notes        : -
+*******************************************************************************/
+
+static SK_BOOL
+IsIntModEnabled(SK_AC *pAC) {
+    unsigned long CtrCmd;
+
+    SK_IN32(pAC->IoBase, B2_IRQM_CTRL, &CtrCmd);
+    if ((CtrCmd & TIM_START) == TIM_START) {
+       return SK_TRUE;
+    } else {
+       return SK_FALSE;
+    }
+}
+
+/*******************************************************************************
+** Function     : EnableIntMod()
+** Description  : Enables the interrupt moderation using the values stored in
+**                in the pAC->DynIntMod data structure
+** Programmer   : Ralph Roesler
+** Last Modified: 22-mar-03
+** Returns      : -
+** Notes        : -
+*******************************************************************************/
+
+static void
+EnableIntMod(SK_AC *pAC) {
+    unsigned long ModBase;
+
+    if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+       ModBase = C_CLK_FREQ_GENESIS / pAC->DynIrqModInfo.MaxModIntsPerSec;
+    } else {
+       ModBase = C_CLK_FREQ_YUKON / pAC->DynIrqModInfo.MaxModIntsPerSec;
+    }
+
+    SK_OUT32(pAC->IoBase, B2_IRQM_INI,  ModBase);
+    SK_OUT32(pAC->IoBase, B2_IRQM_MSK,  pAC->DynIrqModInfo.MaskIrqModeration);
+    SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_START);
+    if (M_DIMINFO.DisplayStats) {
+        printk("Enabled interrupt moderation (%i ints/sec)\n",
+               M_DIMINFO.MaxModIntsPerSec);
+    }
+}
+
+/*******************************************************************************
+** Function     : DisableIntMod()
+** Description  : Disables the interrupt moderation independent of what inter-
+**                rupts are running or not
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : -
+** Notes        : -
+*******************************************************************************/
+
+static void 
+DisableIntMod(SK_AC *pAC) {
+
+    SK_OUT32(pAC->IoBase, B2_IRQM_CTRL, TIM_STOP);
+    if (M_DIMINFO.DisplayStats) {
+        printk("Disabled interrupt moderation\n");
+    }
+} 
+
+/*******************************************************************************
+** Function     : ResizeDimTimerDuration();
+** Description  : Checks the current used descriptor ratio and resizes the 
+**                duration timer (longer/smaller) if possible. 
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : -
+** Notes        : There are both maximum and minimum timer duration value. 
+**                This function assumes that interrupt moderation is already
+**                enabled!
+*******************************************************************************/
+
+static void 
+ResizeDimTimerDuration(SK_AC *pAC) {
+    SK_BOOL IncreaseTimerDuration;
+    int     TotalMaxNbrDescr;
+    int     UsedDescrRatio;
+    int     RatioDiffAbs;
+    int     RatioDiffRel;
+    int     NewMaxModIntsPerSec;
+    int     ModAdjValue;
+    long    ModBase;
+
+    /*
+    ** Check first if we are allowed to perform any modification
+    */
+    if (IsIntModEnabled(pAC)) { 
+        if (M_DIMINFO.IntModTypeSelect != C_INT_MOD_DYNAMIC) {
+            return; 
+        } else {
+            if (M_DIMINFO.ModJustEnabled) {
+                M_DIMINFO.ModJustEnabled = SK_FALSE;
+                return;
+            }
+        }
+    }
+
+    /*
+    ** If we got until here, we have to evaluate the amount of the
+    ** descriptor ratio change...
+    */
+    TotalMaxNbrDescr = pAC->RxDescrPerRing * GetRxCalls(pAC);
+    UsedDescrRatio   = (M_DIMINFO.NbrProcessedDescr * 100) / TotalMaxNbrDescr;
+
+    if (UsedDescrRatio > M_DIMINFO.PrevUsedDescrRatio) {
+        RatioDiffAbs = (UsedDescrRatio - M_DIMINFO.PrevUsedDescrRatio);
+        RatioDiffRel = (RatioDiffAbs * 100) / UsedDescrRatio;
+        M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio;
+        IncreaseTimerDuration = SK_FALSE;  /* in other words: DECREASE */
+    } else if (UsedDescrRatio < M_DIMINFO.PrevUsedDescrRatio) {
+        RatioDiffAbs = (M_DIMINFO.PrevUsedDescrRatio - UsedDescrRatio);
+        RatioDiffRel = (RatioDiffAbs * 100) / M_DIMINFO.PrevUsedDescrRatio;
+        M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio;
+        IncreaseTimerDuration = SK_TRUE;   /* in other words: INCREASE */
+    } else {
+        RatioDiffAbs = (M_DIMINFO.PrevUsedDescrRatio - UsedDescrRatio);
+        RatioDiffRel = (RatioDiffAbs * 100) / M_DIMINFO.PrevUsedDescrRatio;
+        M_DIMINFO.PrevUsedDescrRatio = UsedDescrRatio;
+        IncreaseTimerDuration = SK_TRUE;   /* in other words: INCREASE */
+    }
+
+    /*
+    ** Now we can determine the change in percent
+    */
+    if ((RatioDiffRel >= 0) && (RatioDiffRel <= 5) ) {
+       ModAdjValue = 1;  /*  1% change - maybe some other value in future */
+    } else if ((RatioDiffRel > 5) && (RatioDiffRel <= 10) ) {
+       ModAdjValue = 1;  /*  1% change - maybe some other value in future */
+    } else if ((RatioDiffRel > 10) && (RatioDiffRel <= 15) ) {
+       ModAdjValue = 1;  /*  1% change - maybe some other value in future */
+    } else {
+       ModAdjValue = 1;  /*  1% change - maybe some other value in future */
+    }
+
+    if (IncreaseTimerDuration) {
+       NewMaxModIntsPerSec =  M_DIMINFO.MaxModIntsPerSec +
+                             (M_DIMINFO.MaxModIntsPerSec * ModAdjValue) / 100;
+    } else {
+       NewMaxModIntsPerSec =  M_DIMINFO.MaxModIntsPerSec -
+                             (M_DIMINFO.MaxModIntsPerSec * ModAdjValue) / 100;
+    }
+
+    /* 
+    ** Check if we exceed boundaries...
+    */
+    if ( (NewMaxModIntsPerSec > M_DIMINFO.MaxModIntsPerSecUpperLimit) ||
+         (NewMaxModIntsPerSec < M_DIMINFO.MaxModIntsPerSecLowerLimit)) {
+        if (M_DIMINFO.DisplayStats) {
+            printk("Cannot change ModTim from %i to %i ints/sec\n",
+                   M_DIMINFO.MaxModIntsPerSec, NewMaxModIntsPerSec);
+        }
+        return;
+    } else {
+        if (M_DIMINFO.DisplayStats) {
+            printk("Resized ModTim from %i to %i ints/sec\n",
+                   M_DIMINFO.MaxModIntsPerSec, NewMaxModIntsPerSec);
+        }
+    }
+
+    M_DIMINFO.MaxModIntsPerSec = NewMaxModIntsPerSec;
+
+    if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+        ModBase = C_CLK_FREQ_GENESIS / pAC->DynIrqModInfo.MaxModIntsPerSec;
+    } else {
+        ModBase = C_CLK_FREQ_YUKON / pAC->DynIrqModInfo.MaxModIntsPerSec;
+    }
+
+    /* 
+    ** We do not need to touch any other registers
+    */
+    SK_OUT32(pAC->IoBase, B2_IRQM_INI, ModBase);
+} 
+
+/*******************************************************************************
+** Function     : DisplaySelectedModerationType()
+** Description  : Displays what type of moderation we have
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : void!
+** Notes        : -
+*******************************************************************************/
+
+static void
+DisplaySelectedModerationType(SK_AC *pAC) {
+
+    if (pAC->DynIrqModInfo.DisplayStats) {
+        if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_STATIC) {
+             printk("Static int moderation runs with %i INTS/sec\n",
+                    pAC->DynIrqModInfo.MaxModIntsPerSec);
+        } else if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_DYNAMIC) {
+             if (IsIntModEnabled(pAC)) {
+                printk("Dynamic int moderation runs with %i INTS/sec\n",
+                       pAC->DynIrqModInfo.MaxModIntsPerSec);
+             } else {
+                printk("Dynamic int moderation currently not applied\n");
+             }
+        } else {
+             printk("No interrupt moderation selected!\n");
+        }
+    }
+}
+
+/*******************************************************************************
+** Function     : DisplaySelectedModerationMask()
+** Description  : Displays what interrupts are moderated
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : void!
+** Notes        : -
+*******************************************************************************/
+
+static void
+DisplaySelectedModerationMask(SK_AC *pAC) {
+
+    if (pAC->DynIrqModInfo.DisplayStats) {
+        if (pAC->DynIrqModInfo.IntModTypeSelect != C_INT_MOD_NONE) {
+            switch (pAC->DynIrqModInfo.MaskIrqModeration) {
+                case IRQ_MASK_TX_ONLY: 
+                   printk("Only Tx-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_RX_ONLY: 
+                   printk("Only Rx-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_SP_ONLY: 
+                   printk("Only special-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_TX_RX: 
+                   printk("Tx- and Rx-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_SP_RX: 
+                   printk("Special- and Rx-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_SP_TX: 
+                   printk("Special- and Tx-interrupts are moderated\n");
+                   break;
+                case IRQ_MASK_RX_TX_SP:
+                   printk("All Rx-, Tx and special-interrupts are moderated\n");
+                   break;
+                default:
+                   printk("Don't know what is moderated\n");
+                   break;
+            }
+        } else {
+            printk("No specific interrupts masked for moderation\n");
+        }
+    } 
+}
+
+/*******************************************************************************
+** Function     : DisplayDescrRatio
+** Description  : Like the name states...
+** Programmer   : Ralph Roesler
+** Last Modified: 23-mar-03
+** Returns      : void!
+** Notes        : -
+*******************************************************************************/
+
+static void
+DisplayDescrRatio(SK_AC *pAC) {
+    int TotalMaxNbrDescr = 0;
+
+    if (pAC->DynIrqModInfo.DisplayStats) {
+        TotalMaxNbrDescr = pAC->RxDescrPerRing * GetRxCalls(pAC);
+        printk("Ratio descriptors: %i/%i\n",
+               M_DIMINFO.NbrProcessedDescr, TotalMaxNbrDescr);
+    }
+}
+
+/*******************************************************************************
+**
+** End of file
+**
+*******************************************************************************/
diff --git a/drivers/net/sk98lin/skethtool.c b/drivers/net/sk98lin/skethtool.c
new file mode 100644
index 0000000..5a6da89
--- /dev/null
+++ b/drivers/net/sk98lin/skethtool.c
@@ -0,0 +1,627 @@
+/******************************************************************************
+ *
+ * Name:        skethtool.c
+ * Project:     GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:     $Revision: 1.7 $
+ * Date:        $Date: 2004/09/29 13:32:07 $
+ * Purpose:     All functions regarding ethtool handling
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2004 Marvell.
+ *
+ *	Driver for Marvell Yukon/2 chipset and SysKonnect Gigabit Ethernet 
+ *      Server Adapters.
+ *
+ *	Author: Ralph Roesler (rroesler@syskonnect.de)
+ *	        Mirko Lindner (mlindner@syskonnect.de)
+ *
+ *	Address all question to: linux@syskonnect.de
+ *
+ *	The technical manual for the adapters is available from SysKonnect's
+ *	web pages: www.syskonnect.com
+ *	
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	The information in this file is provided "AS IS" without warranty.
+ *
+ *****************************************************************************/
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+#include "h/skversion.h"
+
+#include <linux/ethtool.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+
+/******************************************************************************
+ *
+ * Defines
+ *
+ *****************************************************************************/
+
+#define SUPP_COPPER_ALL (SUPPORTED_10baseT_Half  | SUPPORTED_10baseT_Full  | \
+                         SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
+                         SUPPORTED_1000baseT_Half| SUPPORTED_1000baseT_Full| \
+                         SUPPORTED_TP)
+
+#define ADV_COPPER_ALL  (ADVERTISED_10baseT_Half  | ADVERTISED_10baseT_Full  | \
+                         ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
+                         ADVERTISED_1000baseT_Half| ADVERTISED_1000baseT_Full| \
+                         ADVERTISED_TP)
+
+#define SUPP_FIBRE_ALL  (SUPPORTED_1000baseT_Full | \
+                         SUPPORTED_FIBRE          | \
+                         SUPPORTED_Autoneg)
+
+#define ADV_FIBRE_ALL   (ADVERTISED_1000baseT_Full | \
+                         ADVERTISED_FIBRE          | \
+                         ADVERTISED_Autoneg)
+
+
+/******************************************************************************
+ *
+ * Local Functions
+ *
+ *****************************************************************************/
+
+/*****************************************************************************
+ *
+ * 	getSettings - retrieves the current settings of the selected adapter
+ *
+ * Description:
+ *	The current configuration of the selected adapter is returned.
+ *	This configuration involves a)speed, b)duplex and c)autoneg plus
+ *	a number of other variables.
+ *
+ * Returns:    always 0
+ *
+ */
+static int getSettings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	const DEV_NET *pNet = netdev_priv(dev);
+	int port = pNet->PortNr;
+	const SK_AC *pAC = pNet->pAC;
+	const SK_GEPORT *pPort = &pAC->GIni.GP[port];
+
+	static int DuplexAutoNegConfMap[9][3]= {
+		{ -1                     , -1         , -1              },
+		{ 0                      , -1         , -1              },
+		{ SK_LMODE_HALF          , DUPLEX_HALF, AUTONEG_DISABLE },
+		{ SK_LMODE_FULL          , DUPLEX_FULL, AUTONEG_DISABLE },
+		{ SK_LMODE_AUTOHALF      , DUPLEX_HALF, AUTONEG_ENABLE  },
+		{ SK_LMODE_AUTOFULL      , DUPLEX_FULL, AUTONEG_ENABLE  },
+		{ SK_LMODE_AUTOBOTH      , DUPLEX_FULL, AUTONEG_ENABLE  },
+		{ SK_LMODE_AUTOSENSE     , -1         , -1              },
+		{ SK_LMODE_INDETERMINATED, -1         , -1              }
+	};
+	static int SpeedConfMap[6][2] = {
+		{ 0                       , -1         },
+		{ SK_LSPEED_AUTO          , -1         },
+		{ SK_LSPEED_10MBPS        , SPEED_10   },
+		{ SK_LSPEED_100MBPS       , SPEED_100  },
+		{ SK_LSPEED_1000MBPS      , SPEED_1000 },
+		{ SK_LSPEED_INDETERMINATED, -1         }
+	};
+	static int AdvSpeedMap[6][2] = {
+		{ 0                       , -1         },
+		{ SK_LSPEED_AUTO          , -1         },
+		{ SK_LSPEED_10MBPS        , ADVERTISED_10baseT_Half   | ADVERTISED_10baseT_Full },
+		{ SK_LSPEED_100MBPS       , ADVERTISED_100baseT_Half  | ADVERTISED_100baseT_Full },
+		{ SK_LSPEED_1000MBPS      , ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full},
+		{ SK_LSPEED_INDETERMINATED, -1         }
+	};
+
+	ecmd->phy_address = port;
+	ecmd->speed       = SpeedConfMap[pPort->PLinkSpeedUsed][1];
+	ecmd->duplex      = DuplexAutoNegConfMap[pPort->PLinkModeStatus][1];
+	ecmd->autoneg     = DuplexAutoNegConfMap[pPort->PLinkModeStatus][2];
+	ecmd->transceiver = XCVR_INTERNAL;
+
+	if (pAC->GIni.GICopperType) {
+		ecmd->port        = PORT_TP;
+		ecmd->supported   = (SUPP_COPPER_ALL|SUPPORTED_Autoneg);
+		if (pAC->GIni.GIGenesis) {
+			ecmd->supported &= ~(SUPPORTED_10baseT_Half);
+			ecmd->supported &= ~(SUPPORTED_10baseT_Full);
+			ecmd->supported &= ~(SUPPORTED_100baseT_Half);
+			ecmd->supported &= ~(SUPPORTED_100baseT_Full);
+		} else {
+			if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+				ecmd->supported &= ~(SUPPORTED_1000baseT_Half);
+			} 
+#ifdef CHIP_ID_YUKON_FE
+			if (pAC->GIni.GIChipId == CHIP_ID_YUKON_FE) {
+				ecmd->supported &= ~(SUPPORTED_1000baseT_Half);
+				ecmd->supported &= ~(SUPPORTED_1000baseT_Full);
+			}
+#endif
+		}
+		if (pAC->GIni.GP[0].PLinkSpeed != SK_LSPEED_AUTO) {
+			ecmd->advertising = AdvSpeedMap[pPort->PLinkSpeed][1];
+			if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+				ecmd->advertising &= ~(SUPPORTED_1000baseT_Half);
+			} 
+		} else {
+			ecmd->advertising = ecmd->supported;
+		}
+
+		if (ecmd->autoneg == AUTONEG_ENABLE) 
+			ecmd->advertising |= ADVERTISED_Autoneg;
+	} else {
+		ecmd->port        = PORT_FIBRE;
+		ecmd->supported   = SUPP_FIBRE_ALL;
+		ecmd->advertising = ADV_FIBRE_ALL;
+	}
+	return 0;
+}
+
+/*
+ * MIB infrastructure uses instance value starting at 1
+ * based on board and port.
+ */
+static inline u32 pnmiInstance(const DEV_NET *pNet)
+{
+	return 1 + (pNet->pAC->RlmtNets == 2) + pNet->PortNr;
+}
+
+/*****************************************************************************
+ *
+ *	setSettings - configures the settings of a selected adapter
+ *
+ * Description:
+ *	Possible settings that may be altered are a)speed, b)duplex or 
+ *	c)autonegotiation.
+ *
+ * Returns:
+ *	0:	everything fine, no error
+ *	<0:	the return value is the error code of the failure 
+ */
+static int setSettings(struct net_device *dev, struct ethtool_cmd *ecmd)
+{
+	DEV_NET *pNet = netdev_priv(dev);
+	SK_AC *pAC = pNet->pAC;
+	u32 instance;
+	char buf[4];
+	int len = 1;
+
+	if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100 
+	    && ecmd->speed != SPEED_1000)
+		return -EINVAL;
+
+	if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
+		return -EINVAL;
+
+	if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
+		return -EINVAL;
+
+	if (ecmd->autoneg == AUTONEG_DISABLE)
+		*buf = (ecmd->duplex == DUPLEX_FULL) 
+			? SK_LMODE_FULL : SK_LMODE_HALF;
+	else
+		*buf = (ecmd->duplex == DUPLEX_FULL) 
+			? SK_LMODE_AUTOFULL : SK_LMODE_AUTOHALF;
+	
+	instance = pnmiInstance(pNet);
+	if (SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_LINK_MODE, 
+			   &buf, &len, instance, pNet->NetNr) != SK_PNMI_ERR_OK)
+		return -EINVAL;
+
+	switch(ecmd->speed) {
+	case SPEED_1000:
+		*buf = SK_LSPEED_1000MBPS;
+		break;
+	case SPEED_100:
+		*buf = SK_LSPEED_100MBPS;
+		break;
+	case SPEED_10:
+		*buf = SK_LSPEED_10MBPS;
+	}
+
+	if (SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_SPEED_MODE, 
+			 &buf, &len, instance, pNet->NetNr) != SK_PNMI_ERR_OK)
+		return -EINVAL;
+
+	return 0;
+}
+
+/*****************************************************************************
+ *
+ * 	getDriverInfo - returns generic driver and adapter information
+ *
+ * Description:
+ *	Generic driver information is returned via this function, such as
+ *	the name of the driver, its version and and firmware version.
+ *	In addition to this, the location of the selected adapter is 
+ *	returned as a bus info string (e.g. '01:05.0').
+ *	
+ * Returns:	N/A
+ *
+ */
+static void getDriverInfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	const DEV_NET	*pNet = netdev_priv(dev);
+	const SK_AC *pAC = pNet->pAC;
+	char vers[32];
+
+	snprintf(vers, sizeof(vers)-1, VER_STRING "(v%d.%d)",
+		(pAC->GIni.GIPciHwRev >> 4) & 0xf, pAC->GIni.GIPciHwRev & 0xf);
+
+	strlcpy(info->driver, DRIVER_FILE_NAME, sizeof(info->driver));
+	strcpy(info->version, vers);
+	strcpy(info->fw_version, "N/A");
+	strlcpy(info->bus_info, pci_name(pAC->PciDev), ETHTOOL_BUSINFO_LEN);
+}
+
+/*
+ * Ethtool statistics support.
+ */
+static const char StringsStats[][ETH_GSTRING_LEN] = {
+	"rx_packets",	"tx_packets",
+	"rx_bytes",	"tx_bytes",
+	"rx_errors",	"tx_errors",	
+	"rx_dropped",	"tx_dropped",
+	"multicasts",	"collisions",	
+	"rx_length_errors",		"rx_buffer_overflow_errors",
+	"rx_crc_errors",		"rx_frame_errors",
+	"rx_too_short_errors",		"rx_too_long_errors",
+	"rx_carrier_extension_errors",	"rx_symbol_errors",
+	"rx_llc_mac_size_errors",	"rx_carrier_errors",	
+	"rx_jabber_errors",		"rx_missed_errors",
+	"tx_abort_collision_errors",	"tx_carrier_errors",
+	"tx_buffer_underrun_errors",	"tx_heartbeat_errors",
+	"tx_window_errors",
+};
+
+static int getStatsCount(struct net_device *dev)
+{
+	return ARRAY_SIZE(StringsStats);
+}
+
+static void getStrings(struct net_device *dev, u32 stringset, u8 *data)
+{
+	switch(stringset) {
+	case ETH_SS_STATS:
+		memcpy(data, *StringsStats, sizeof(StringsStats));
+		break;
+	}
+}
+
+static void getEthtoolStats(struct net_device *dev,
+			    struct ethtool_stats *stats, u64 *data)
+{
+	const DEV_NET	*pNet = netdev_priv(dev);
+	const SK_AC *pAC = pNet->pAC;
+	const SK_PNMI_STRUCT_DATA *pPnmiStruct = &pAC->PnmiStruct;
+
+	*data++ = pPnmiStruct->Stat[0].StatRxOkCts;
+	*data++ = pPnmiStruct->Stat[0].StatTxOkCts;
+	*data++ = pPnmiStruct->Stat[0].StatRxOctetsOkCts;
+	*data++ = pPnmiStruct->Stat[0].StatTxOctetsOkCts;
+	*data++ = pPnmiStruct->InErrorsCts;
+	*data++ = pPnmiStruct->Stat[0].StatTxSingleCollisionCts;
+	*data++ = pPnmiStruct->RxNoBufCts;
+	*data++ = pPnmiStruct->TxNoBufCts;
+	*data++ = pPnmiStruct->Stat[0].StatRxMulticastOkCts;
+	*data++ = pPnmiStruct->Stat[0].StatTxSingleCollisionCts;
+	*data++ = pPnmiStruct->Stat[0].StatRxRuntCts;
+	*data++ = pPnmiStruct->Stat[0].StatRxFifoOverflowCts;
+	*data++ = pPnmiStruct->Stat[0].StatRxFcsCts;
+	*data++ = pPnmiStruct->Stat[0].StatRxFramingCts;
+	*data++ = pPnmiStruct->Stat[0].StatRxShortsCts;
+	*data++ = pPnmiStruct->Stat[0].StatRxTooLongCts;
+	*data++ = pPnmiStruct->Stat[0].StatRxCextCts;
+	*data++ = pPnmiStruct->Stat[0].StatRxSymbolCts;
+	*data++ = pPnmiStruct->Stat[0].StatRxIRLengthCts;
+	*data++ = pPnmiStruct->Stat[0].StatRxCarrierCts;
+	*data++ = pPnmiStruct->Stat[0].StatRxJabberCts;
+	*data++ = pPnmiStruct->Stat[0].StatRxMissedCts;
+	*data++ = pAC->stats.tx_aborted_errors;
+	*data++ = pPnmiStruct->Stat[0].StatTxCarrierCts;
+	*data++ = pPnmiStruct->Stat[0].StatTxFifoUnderrunCts;
+	*data++ = pPnmiStruct->Stat[0].StatTxCarrierCts;
+	*data++ = pAC->stats.tx_window_errors;
+}
+
+
+/*****************************************************************************
+ *
+ * 	toggleLeds - Changes the LED state of an adapter
+ *
+ * Description:
+ *	This function changes the current state of all LEDs of an adapter so
+ *	that it can be located by a user. 
+ *
+ * Returns:	N/A
+ *
+ */
+static void toggleLeds(DEV_NET *pNet, int on)
+{
+	SK_AC *pAC = pNet->pAC;
+	int port = pNet->PortNr;
+	void __iomem *io = pAC->IoBase;
+
+	if (pAC->GIni.GIGenesis) {
+		SK_OUT8(io, MR_ADDR(port,LNK_LED_REG), 
+			on ? SK_LNK_ON : SK_LNK_OFF);
+		SkGeYellowLED(pAC, io, 
+			      on ? (LED_ON >> 1) : (LED_OFF >> 1));
+		SkGeXmitLED(pAC, io, MR_ADDR(port,RX_LED_INI),
+			    on ? SK_LED_TST : SK_LED_DIS);
+
+		if (pAC->GIni.GP[port].PhyType == SK_PHY_BCOM)
+			SkXmPhyWrite(pAC, io, port, PHY_BCOM_P_EXT_CTRL, 
+				     on ? PHY_B_PEC_LED_ON : PHY_B_PEC_LED_OFF);
+		else if (pAC->GIni.GP[port].PhyType == SK_PHY_LONE)
+			SkXmPhyWrite(pAC, io, port, PHY_LONE_LED_CFG,
+				     on ? 0x0800 : PHY_L_LC_LEDT);
+		else
+			SkGeXmitLED(pAC, io, MR_ADDR(port,TX_LED_INI),
+				    on ? SK_LED_TST : SK_LED_DIS);
+	} else {
+		const u16 YukLedOn = (PHY_M_LED_MO_DUP(MO_LED_ON)  |
+				      PHY_M_LED_MO_10(MO_LED_ON)   |
+				      PHY_M_LED_MO_100(MO_LED_ON)  |
+				      PHY_M_LED_MO_1000(MO_LED_ON) | 
+				      PHY_M_LED_MO_RX(MO_LED_ON));
+		const u16  YukLedOff = (PHY_M_LED_MO_DUP(MO_LED_OFF)  |
+					PHY_M_LED_MO_10(MO_LED_OFF)   |
+					PHY_M_LED_MO_100(MO_LED_OFF)  |
+					PHY_M_LED_MO_1000(MO_LED_OFF) | 
+					PHY_M_LED_MO_RX(MO_LED_OFF));
+	
+
+		SkGmPhyWrite(pAC,io,port,PHY_MARV_LED_CTRL,0);
+		SkGmPhyWrite(pAC,io,port,PHY_MARV_LED_OVER, 
+			     on ? YukLedOn : YukLedOff);
+	}
+}
+
+/*****************************************************************************
+ *
+ * 	skGeBlinkTimer - Changes the LED state of an adapter
+ *
+ * Description:
+ *	This function changes the current state of all LEDs of an adapter so
+ *	that it can be located by a user. If the requested time interval for
+ *	this test has elapsed, this function cleans up everything that was 
+ *	temporarily setup during the locate NIC test. This involves of course
+ *	also closing or opening any adapter so that the initial board state 
+ *	is recovered.
+ *
+ * Returns:	N/A
+ *
+ */
+void SkGeBlinkTimer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *) data;
+	DEV_NET *pNet = netdev_priv(dev);
+	SK_AC *pAC = pNet->pAC;
+
+	toggleLeds(pNet, pAC->LedsOn);
+
+	pAC->LedsOn = !pAC->LedsOn;
+	mod_timer(&pAC->BlinkTimer, jiffies + HZ/4);
+}
+
+/*****************************************************************************
+ *
+ * 	locateDevice - start the locate NIC feature of the elected adapter 
+ *
+ * Description:
+ *	This function is used if the user want to locate a particular NIC.
+ *	All LEDs are regularly switched on and off, so the NIC can easily
+ *	be identified.
+ *
+ * Returns:	
+ *	==0:	everything fine, no error, locateNIC test was started
+ *	!=0:	one locateNIC test runs already
+ *
+ */
+static int locateDevice(struct net_device *dev, u32 data)
+{
+	DEV_NET *pNet = netdev_priv(dev);
+	SK_AC *pAC = pNet->pAC;
+
+	if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
+		data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
+
+	/* start blinking */
+	pAC->LedsOn = 0;
+	mod_timer(&pAC->BlinkTimer, jiffies);
+	msleep_interruptible(data * 1000);
+	del_timer_sync(&pAC->BlinkTimer);
+	toggleLeds(pNet, 0);
+
+	return 0;
+}
+
+/*****************************************************************************
+ *
+ * 	getPauseParams - retrieves the pause parameters
+ *
+ * Description:
+ *	All current pause parameters of a selected adapter are placed 
+ *	in the passed ethtool_pauseparam structure and are returned.
+ *
+ * Returns:	N/A
+ *
+ */
+static void getPauseParams(struct net_device *dev, struct ethtool_pauseparam *epause) 
+{
+	DEV_NET	*pNet = netdev_priv(dev);
+	SK_AC *pAC = pNet->pAC;
+	SK_GEPORT *pPort = &pAC->GIni.GP[pNet->PortNr];
+
+	epause->rx_pause = (pPort->PFlowCtrlMode == SK_FLOW_MODE_SYMMETRIC) ||
+		  (pPort->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM);
+
+	epause->tx_pause = epause->rx_pause || (pPort->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND);
+	epause->autoneg = epause->rx_pause || epause->tx_pause;
+}
+
+/*****************************************************************************
+ *
+ *	setPauseParams - configures the pause parameters of an adapter
+ *
+ * Description:
+ *	This function sets the Rx or Tx pause parameters 
+ *
+ * Returns:
+ *	==0:	everything fine, no error
+ *	!=0:	the return value is the error code of the failure 
+ */
+static int setPauseParams(struct net_device *dev , struct ethtool_pauseparam *epause)
+{
+	DEV_NET	*pNet = netdev_priv(dev);
+	SK_AC *pAC = pNet->pAC;
+	SK_GEPORT *pPort = &pAC->GIni.GP[pNet->PortNr];
+	u32	instance = pnmiInstance(pNet);
+	struct ethtool_pauseparam old;
+	u8	oldspeed = pPort->PLinkSpeedUsed;
+	char	buf[4];
+	int	len = 1;
+	int ret;
+
+	/*
+	** we have to determine the current settings to see if 
+	** the operator requested any modification of the flow 
+	** control parameters...
+	*/
+	getPauseParams(dev, &old);
+
+	/*
+	** perform modifications regarding the changes 
+	** requested by the operator
+	*/
+	if (epause->autoneg != old.autoneg) 
+		*buf = epause->autoneg ? SK_FLOW_MODE_NONE : SK_FLOW_MODE_SYMMETRIC;
+	else {
+		if (epause->rx_pause && epause->tx_pause) 
+			*buf = SK_FLOW_MODE_SYMMETRIC;
+		else if (epause->rx_pause && !epause->tx_pause)
+			*buf =  SK_FLOW_MODE_SYM_OR_REM;
+		else if (!epause->rx_pause && epause->tx_pause)
+			*buf =  SK_FLOW_MODE_LOC_SEND;
+		else
+			*buf = SK_FLOW_MODE_NONE;
+	}
+
+	ret = SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_FLOWCTRL_MODE,
+			 &buf, &len, instance, pNet->NetNr);
+
+	if (ret != SK_PNMI_ERR_OK) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_CTRL,
+			   ("ethtool (sk98lin): error changing rx/tx pause (%i)\n", ret));
+		goto err;
+	}
+
+	/*
+	** It may be that autoneg has been disabled! Therefore
+	** set the speed to the previously used value...
+	*/
+	if (!epause->autoneg) {
+		len = 1;
+		ret = SkPnmiSetVar(pAC, pAC->IoBase, OID_SKGE_SPEED_MODE, 
+				   &oldspeed, &len, instance, pNet->NetNr);
+		if (ret != SK_PNMI_ERR_OK) 
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_CTRL,
+				   ("ethtool (sk98lin): error setting speed (%i)\n", ret));
+	}
+ err:
+        return ret ? -EIO : 0;
+}
+
+/* Only Yukon supports checksum offload. */
+static int setScatterGather(struct net_device *dev, u32 data)
+{
+	DEV_NET *pNet = netdev_priv(dev);
+	SK_AC *pAC = pNet->pAC;
+
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
+		return -EOPNOTSUPP;
+	return ethtool_op_set_sg(dev, data);
+}
+
+static int setTxCsum(struct net_device *dev, u32 data)
+{
+	DEV_NET *pNet = netdev_priv(dev);
+	SK_AC *pAC = pNet->pAC;
+
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
+		return -EOPNOTSUPP;
+
+	return ethtool_op_set_tx_csum(dev, data);
+}
+
+static u32 getRxCsum(struct net_device *dev)
+{
+	DEV_NET *pNet = netdev_priv(dev);
+	SK_AC *pAC = pNet->pAC;
+
+	return pAC->RxPort[pNet->PortNr].RxCsum;
+}
+
+static int setRxCsum(struct net_device *dev, u32 data)
+{
+	DEV_NET *pNet = netdev_priv(dev);
+	SK_AC *pAC = pNet->pAC;
+
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS)
+		return -EOPNOTSUPP;
+
+	pAC->RxPort[pNet->PortNr].RxCsum = data != 0;
+	return 0;
+}
+
+static int getRegsLen(struct net_device *dev)
+{
+	return 0x4000;
+}
+
+/*
+ * Returns copy of whole control register region
+ * Note: skip RAM address register because accessing it will
+ * 	 cause bus hangs!
+ */
+static void getRegs(struct net_device *dev, struct ethtool_regs *regs,
+			  void *p)
+{
+	DEV_NET *pNet = netdev_priv(dev);
+	const void __iomem *io = pNet->pAC->IoBase;
+
+	regs->version = 1;
+	memset(p, 0, regs->len);
+	memcpy_fromio(p, io, B3_RAM_ADDR);
+
+	memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1,
+		      regs->len - B3_RI_WTO_R1);
+}
+
+const struct ethtool_ops SkGeEthtoolOps = {
+	.get_settings		= getSettings,
+	.set_settings		= setSettings,
+	.get_drvinfo		= getDriverInfo,
+	.get_strings		= getStrings,
+	.get_stats_count	= getStatsCount,
+	.get_ethtool_stats	= getEthtoolStats,
+	.phys_id		= locateDevice,
+	.get_pauseparam		= getPauseParams,
+	.set_pauseparam		= setPauseParams,
+	.get_link		= ethtool_op_get_link,
+	.get_sg			= ethtool_op_get_sg,
+	.set_sg			= setScatterGather,
+	.get_tx_csum		= ethtool_op_get_tx_csum,
+	.set_tx_csum		= setTxCsum,
+	.get_rx_csum		= getRxCsum,
+	.set_rx_csum		= setRxCsum,
+	.get_regs		= getRegs,
+	.get_regs_len		= getRegsLen,
+};
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
new file mode 100644
index 0000000..20890e4
--- /dev/null
+++ b/drivers/net/sk98lin/skge.c
@@ -0,0 +1,5218 @@
+/******************************************************************************
+ *
+ * Name:	skge.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.45 $
+ * Date:       	$Date: 2004/02/12 14:41:02 $
+ * Purpose:	The main driver source module
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	Driver for Marvell Yukon chipset and SysKonnect Gigabit Ethernet 
+ *      Server Adapters.
+ *
+ *	Created 10-Feb-1999, based on Linux' acenic.c, 3c59x.c and
+ *	SysKonnects GEnesis Solaris driver
+ *	Author: Christoph Goos (cgoos@syskonnect.de)
+ *	        Mirko Lindner (mlindner@syskonnect.de)
+ *
+ *	Address all question to: linux@syskonnect.de
+ *
+ *	The technical manual for the adapters is available from SysKonnect's
+ *	web pages: www.syskonnect.com
+ *	Goto "Support" and search Knowledge Base for "manual".
+ *	
+ *	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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Possible compiler options (#define xxx / -Dxxx):
+ *
+ *	debugging can be enable by changing SK_DEBUG_CHKMOD and
+ *	SK_DEBUG_CHKCAT in makefile (described there).
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ *	This is the main module of the Linux GE driver.
+ *	
+ *	All source files except skge.c, skdrv1st.h, skdrv2nd.h and sktypes.h
+ *	are part of SysKonnect's COMMON MODULES for the SK-98xx adapters.
+ *	Those are used for drivers on multiple OS', so some thing may seem
+ *	unnecessary complicated on Linux. Please do not try to 'clean up'
+ *	them without VERY good reasons, because this will make it more
+ *	difficult to keep the Linux driver in synchronisation with the
+ *	other versions.
+ *
+ * Include file hierarchy:
+ *
+ *	<linux/module.h>
+ *
+ *	"h/skdrv1st.h"
+ *		<linux/types.h>
+ *		<linux/kernel.h>
+ *		<linux/string.h>
+ *		<linux/errno.h>
+ *		<linux/ioport.h>
+ *		<linux/slab.h>
+ *		<linux/interrupt.h>
+ *		<linux/pci.h>
+ *		<linux/bitops.h>
+ *		<asm/byteorder.h>
+ *		<asm/io.h>
+ *		<linux/netdevice.h>
+ *		<linux/etherdevice.h>
+ *		<linux/skbuff.h>
+ *	    those three depending on kernel version used:
+ *		<linux/bios32.h>
+ *		<linux/init.h>
+ *		<asm/uaccess.h>
+ *		<net/checksum.h>
+ *
+ *		"h/skerror.h"
+ *		"h/skdebug.h"
+ *		"h/sktypes.h"
+ *		"h/lm80.h"
+ *		"h/xmac_ii.h"
+ *
+ *      "h/skdrv2nd.h"
+ *		"h/skqueue.h"
+ *		"h/skgehwt.h"
+ *		"h/sktimer.h"
+ *		"h/ski2c.h"
+ *		"h/skgepnmi.h"
+ *		"h/skvpd.h"
+ *		"h/skgehw.h"
+ *		"h/skgeinit.h"
+ *		"h/skaddr.h"
+ *		"h/skgesirq.h"
+ *		"h/skrlmt.h"
+ *
+ ******************************************************************************/
+
+#include	"h/skversion.h"
+
+#include	<linux/in.h>
+#include	<linux/module.h>
+#include	<linux/moduleparam.h>
+#include	<linux/init.h>
+#include	<linux/dma-mapping.h>
+#include	<linux/ip.h>
+#include	<linux/mii.h>
+#include	<linux/mm.h>
+
+#include	"h/skdrv1st.h"
+#include	"h/skdrv2nd.h"
+
+/*******************************************************************************
+ *
+ * Defines
+ *
+ ******************************************************************************/
+
+/* for debuging on x86 only */
+/* #define BREAKPOINT() asm(" int $3"); */
+
+/* use the transmit hw checksum driver functionality */
+#define USE_SK_TX_CHECKSUM
+
+/* use the receive hw checksum driver functionality */
+#define USE_SK_RX_CHECKSUM
+
+/* use the scatter-gather functionality with sendfile() */
+#define SK_ZEROCOPY
+
+/* use of a transmit complete interrupt */
+#define USE_TX_COMPLETE
+
+/*
+ * threshold for copying small receive frames
+ * set to 0 to avoid copying, set to 9001 to copy all frames
+ */
+#define SK_COPY_THRESHOLD	50
+
+/* number of adapters that can be configured via command line params */
+#define SK_MAX_CARD_PARAM	16
+
+
+
+/*
+ * use those defines for a compile-in version of the driver instead
+ * of command line parameters
+ */
+// #define LINK_SPEED_A	{"Auto", }
+// #define LINK_SPEED_B	{"Auto", }
+// #define AUTO_NEG_A	{"Sense", }
+// #define AUTO_NEG_B	{"Sense", }
+// #define DUP_CAP_A	{"Both", }
+// #define DUP_CAP_B	{"Both", }
+// #define FLOW_CTRL_A	{"SymOrRem", }
+// #define FLOW_CTRL_B	{"SymOrRem", }
+// #define ROLE_A	{"Auto", }
+// #define ROLE_B	{"Auto", }
+// #define PREF_PORT	{"A", }
+// #define CON_TYPE 	{"Auto", }
+// #define RLMT_MODE	{"CheckLinkState", }
+
+#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb)
+#define DEV_KFREE_SKB_IRQ(skb) dev_kfree_skb_irq(skb)
+#define DEV_KFREE_SKB_ANY(skb) dev_kfree_skb_any(skb)
+
+
+/* Set blink mode*/
+#define OEM_CONFIG_VALUE (	SK_ACT_LED_BLINK | \
+				SK_DUP_LED_NORMAL | \
+				SK_LED_LINK100_ON)
+
+
+/* Isr return value */
+#define SkIsrRetVar	irqreturn_t
+#define SkIsrRetNone	IRQ_NONE
+#define SkIsrRetHandled	IRQ_HANDLED
+
+
+/*******************************************************************************
+ *
+ * Local Function Prototypes
+ *
+ ******************************************************************************/
+
+static void	FreeResources(struct SK_NET_DEVICE *dev);
+static int	SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC);
+static SK_BOOL	BoardAllocMem(SK_AC *pAC);
+static void	BoardFreeMem(SK_AC *pAC);
+static void	BoardInitMem(SK_AC *pAC);
+static void	SetupRing(SK_AC*, void*, uintptr_t, RXD**, RXD**, RXD**, int*, SK_BOOL);
+static SkIsrRetVar	SkGeIsr(int irq, void *dev_id);
+static SkIsrRetVar	SkGeIsrOnePort(int irq, void *dev_id);
+static int	SkGeOpen(struct SK_NET_DEVICE *dev);
+static int	SkGeClose(struct SK_NET_DEVICE *dev);
+static int	SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev);
+static int	SkGeSetMacAddr(struct SK_NET_DEVICE *dev, void *p);
+static void	SkGeSetRxMode(struct SK_NET_DEVICE *dev);
+static struct	net_device_stats *SkGeStats(struct SK_NET_DEVICE *dev);
+static int	SkGeIoctl(struct SK_NET_DEVICE *dev, struct ifreq *rq, int cmd);
+static void	GetConfiguration(SK_AC*);
+static int	XmitFrame(SK_AC*, TX_PORT*, struct sk_buff*);
+static void	FreeTxDescriptors(SK_AC*pAC, TX_PORT*);
+static void	FillRxRing(SK_AC*, RX_PORT*);
+static SK_BOOL	FillRxDescriptor(SK_AC*, RX_PORT*);
+static void	ReceiveIrq(SK_AC*, RX_PORT*, SK_BOOL);
+static void	ClearAndStartRx(SK_AC*, int);
+static void	ClearTxIrq(SK_AC*, int, int);
+static void	ClearRxRing(SK_AC*, RX_PORT*);
+static void	ClearTxRing(SK_AC*, TX_PORT*);
+static int	SkGeChangeMtu(struct SK_NET_DEVICE *dev, int new_mtu);
+static void	PortReInitBmu(SK_AC*, int);
+static int	SkGeIocMib(DEV_NET*, unsigned int, int);
+static int	SkGeInitPCI(SK_AC *pAC);
+static void	StartDrvCleanupTimer(SK_AC *pAC);
+static void	StopDrvCleanupTimer(SK_AC *pAC);
+static int	XmitFrameSG(SK_AC*, TX_PORT*, struct sk_buff*);
+
+#ifdef SK_DIAG_SUPPORT
+static SK_U32   ParseDeviceNbrFromSlotName(const char *SlotName);
+static int      SkDrvInitAdapter(SK_AC *pAC, int devNbr);
+static int      SkDrvDeInitAdapter(SK_AC *pAC, int devNbr);
+#endif
+
+/*******************************************************************************
+ *
+ * Extern Function Prototypes
+ *
+ ******************************************************************************/
+extern void SkDimEnableModerationIfNeeded(SK_AC *pAC);	
+extern void SkDimDisplayModerationSettings(SK_AC *pAC);
+extern void SkDimStartModerationTimer(SK_AC *pAC);
+extern void SkDimModerate(SK_AC *pAC);
+extern void SkGeBlinkTimer(unsigned long data);
+
+#ifdef DEBUG
+static void	DumpMsg(struct sk_buff*, char*);
+static void	DumpData(char*, int);
+static void	DumpLong(char*, int);
+#endif
+
+/* global variables *********************************************************/
+static SK_BOOL DoPrintInterfaceChange = SK_TRUE;
+extern const struct ethtool_ops SkGeEthtoolOps;
+
+/* local variables **********************************************************/
+static uintptr_t TxQueueAddr[SK_MAX_MACS][2] = {{0x680, 0x600},{0x780, 0x700}};
+static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480};
+
+/*****************************************************************************
+ *
+ *	SkPciWriteCfgDWord - write a 32 bit value to pci config space
+ *
+ * Description:
+ *	This routine writes a 32 bit value to the pci configuration
+ *	space.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+static inline int SkPciWriteCfgDWord(
+SK_AC *pAC,	/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U32 Val)		/* pointer to store the read value */
+{
+	pci_write_config_dword(pAC->PciDev, PciAddr, Val);
+	return(0);
+} /* SkPciWriteCfgDWord */
+
+/*****************************************************************************
+ *
+ * 	SkGeInitPCI - Init the PCI resources
+ *
+ * Description:
+ *	This function initialize the PCI resources and IO
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+static __devinit int SkGeInitPCI(SK_AC *pAC)
+{
+	struct SK_NET_DEVICE *dev = pAC->dev[0];
+	struct pci_dev *pdev = pAC->PciDev;
+	int retval;
+
+	dev->mem_start = pci_resource_start (pdev, 0);
+	pci_set_master(pdev);
+
+	retval = pci_request_regions(pdev, "sk98lin");
+	if (retval)
+		goto out;
+
+#ifdef SK_BIG_ENDIAN
+	/*
+	 * On big endian machines, we use the adapter's aibility of
+	 * reading the descriptors as big endian.
+	 */
+	{
+		SK_U32		our2;
+		SkPciReadCfgDWord(pAC, PCI_OUR_REG_2, &our2);
+		our2 |= PCI_REV_DESC;
+		SkPciWriteCfgDWord(pAC, PCI_OUR_REG_2, our2);
+	}
+#endif
+
+	/*
+	 * Remap the regs into kernel space.
+	 */
+	pAC->IoBase = ioremap_nocache(dev->mem_start, 0x4000);
+	if (!pAC->IoBase) {
+		retval = -EIO;
+		goto out_release;
+	}
+
+	return 0;
+
+ out_release:
+	pci_release_regions(pdev);
+ out:
+	return retval;
+}
+
+
+/*****************************************************************************
+ *
+ * 	FreeResources - release resources allocated for adapter
+ *
+ * Description:
+ *	This function releases the IRQ, unmaps the IO and
+ *	frees the desriptor ring.
+ *
+ * Returns: N/A
+ *	
+ */
+static void FreeResources(struct SK_NET_DEVICE *dev)
+{
+SK_U32 AllocFlag;
+DEV_NET		*pNet;
+SK_AC		*pAC;
+
+	pNet = netdev_priv(dev);
+	pAC = pNet->pAC;
+	AllocFlag = pAC->AllocFlag;
+	if (pAC->PciDev) {
+		pci_release_regions(pAC->PciDev);
+	}
+	if (AllocFlag & SK_ALLOC_IRQ) {
+		free_irq(dev->irq, dev);
+	}
+	if (pAC->IoBase) {
+		iounmap(pAC->IoBase);
+	}
+	if (pAC->pDescrMem) {
+		BoardFreeMem(pAC);
+	}
+	
+} /* FreeResources */
+
+MODULE_AUTHOR("Mirko Lindner <mlindner@syskonnect.de>");
+MODULE_DESCRIPTION("SysKonnect SK-NET Gigabit Ethernet SK-98xx driver");
+MODULE_LICENSE("GPL");
+
+#ifdef LINK_SPEED_A
+static char *Speed_A[SK_MAX_CARD_PARAM] = LINK_SPEED;
+#else
+static char *Speed_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef LINK_SPEED_B
+static char *Speed_B[SK_MAX_CARD_PARAM] = LINK_SPEED;
+#else
+static char *Speed_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef AUTO_NEG_A
+static char *AutoNeg_A[SK_MAX_CARD_PARAM] = AUTO_NEG_A;
+#else
+static char *AutoNeg_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef DUP_CAP_A
+static char *DupCap_A[SK_MAX_CARD_PARAM] = DUP_CAP_A;
+#else
+static char *DupCap_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef FLOW_CTRL_A
+static char *FlowCtrl_A[SK_MAX_CARD_PARAM] = FLOW_CTRL_A;
+#else
+static char *FlowCtrl_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef ROLE_A
+static char *Role_A[SK_MAX_CARD_PARAM] = ROLE_A;
+#else
+static char *Role_A[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef AUTO_NEG_B
+static char *AutoNeg_B[SK_MAX_CARD_PARAM] = AUTO_NEG_B;
+#else
+static char *AutoNeg_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef DUP_CAP_B
+static char *DupCap_B[SK_MAX_CARD_PARAM] = DUP_CAP_B;
+#else
+static char *DupCap_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef FLOW_CTRL_B
+static char *FlowCtrl_B[SK_MAX_CARD_PARAM] = FLOW_CTRL_B;
+#else
+static char *FlowCtrl_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef ROLE_B
+static char *Role_B[SK_MAX_CARD_PARAM] = ROLE_B;
+#else
+static char *Role_B[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef CON_TYPE
+static char *ConType[SK_MAX_CARD_PARAM] = CON_TYPE;
+#else
+static char *ConType[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef PREF_PORT
+static char *PrefPort[SK_MAX_CARD_PARAM] = PREF_PORT;
+#else
+static char *PrefPort[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+#ifdef RLMT_MODE
+static char *RlmtMode[SK_MAX_CARD_PARAM] = RLMT_MODE;
+#else
+static char *RlmtMode[SK_MAX_CARD_PARAM] = {"", };
+#endif
+
+static int   IntsPerSec[SK_MAX_CARD_PARAM];
+static char *Moderation[SK_MAX_CARD_PARAM];
+static char *ModerationMask[SK_MAX_CARD_PARAM];
+static char *AutoSizing[SK_MAX_CARD_PARAM];
+static char *Stats[SK_MAX_CARD_PARAM];
+
+module_param_array(Speed_A, charp, NULL, 0);
+module_param_array(Speed_B, charp, NULL, 0);
+module_param_array(AutoNeg_A, charp, NULL, 0);
+module_param_array(AutoNeg_B, charp, NULL, 0);
+module_param_array(DupCap_A, charp, NULL, 0);
+module_param_array(DupCap_B, charp, NULL, 0);
+module_param_array(FlowCtrl_A, charp, NULL, 0);
+module_param_array(FlowCtrl_B, charp, NULL, 0);
+module_param_array(Role_A, charp, NULL, 0);
+module_param_array(Role_B, charp, NULL, 0);
+module_param_array(ConType, charp, NULL, 0);
+module_param_array(PrefPort, charp, NULL, 0);
+module_param_array(RlmtMode, charp, NULL, 0);
+/* used for interrupt moderation */
+module_param_array(IntsPerSec, int, NULL, 0);
+module_param_array(Moderation, charp, NULL, 0);
+module_param_array(Stats, charp, NULL, 0);
+module_param_array(ModerationMask, charp, NULL, 0);
+module_param_array(AutoSizing, charp, NULL, 0);
+
+/*****************************************************************************
+ *
+ * 	SkGeBoardInit - do level 0 and 1 initialization
+ *
+ * Description:
+ *	This function prepares the board hardware for running. The desriptor
+ *	ring is set up, the IRQ is allocated and the configuration settings
+ *	are examined.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+static int __devinit SkGeBoardInit(struct SK_NET_DEVICE *dev, SK_AC *pAC)
+{
+short	i;
+unsigned long Flags;
+char	*DescrString = "sk98lin: Driver for Linux"; /* this is given to PNMI */
+char	*VerStr	= VER_STRING;
+int	Ret;			/* return code of request_irq */
+SK_BOOL	DualNet;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("IoBase: %08lX\n", (unsigned long)pAC->IoBase));
+	for (i=0; i<SK_MAX_MACS; i++) {
+		pAC->TxPort[i][0].HwAddr = pAC->IoBase + TxQueueAddr[i][0];
+		pAC->TxPort[i][0].PortIndex = i;
+		pAC->RxPort[i].HwAddr = pAC->IoBase + RxQueueAddr[i];
+		pAC->RxPort[i].PortIndex = i;
+	}
+
+	/* Initialize the mutexes */
+	for (i=0; i<SK_MAX_MACS; i++) {
+		spin_lock_init(&pAC->TxPort[i][0].TxDesRingLock);
+		spin_lock_init(&pAC->RxPort[i].RxDesRingLock);
+	}
+	spin_lock_init(&pAC->SlowPathLock);
+
+	/* setup phy_id blink timer */
+	pAC->BlinkTimer.function = SkGeBlinkTimer;
+	pAC->BlinkTimer.data = (unsigned long) dev;
+	init_timer(&pAC->BlinkTimer);
+
+	/* level 0 init common modules here */
+	
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	/* Does a RESET on board ...*/
+	if (SkGeInit(pAC, pAC->IoBase, SK_INIT_DATA) != 0) {
+		printk("HWInit (0) failed.\n");
+		spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+		return -EIO;
+	}
+	SkI2cInit(  pAC, pAC->IoBase, SK_INIT_DATA);
+	SkEventInit(pAC, pAC->IoBase, SK_INIT_DATA);
+	SkPnmiInit( pAC, pAC->IoBase, SK_INIT_DATA);
+	SkAddrInit( pAC, pAC->IoBase, SK_INIT_DATA);
+	SkRlmtInit( pAC, pAC->IoBase, SK_INIT_DATA);
+	SkTimerInit(pAC, pAC->IoBase, SK_INIT_DATA);
+
+	pAC->BoardLevel = SK_INIT_DATA;
+	pAC->RxBufSize  = ETH_BUF_SIZE;
+
+	SK_PNMI_SET_DRIVER_DESCR(pAC, DescrString);
+	SK_PNMI_SET_DRIVER_VER(pAC, VerStr);
+
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+	/* level 1 init common modules here (HW init) */
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	if (SkGeInit(pAC, pAC->IoBase, SK_INIT_IO) != 0) {
+		printk("sk98lin: HWInit (1) failed.\n");
+		spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+		return -EIO;
+	}
+	SkI2cInit(  pAC, pAC->IoBase, SK_INIT_IO);
+	SkEventInit(pAC, pAC->IoBase, SK_INIT_IO);
+	SkPnmiInit( pAC, pAC->IoBase, SK_INIT_IO);
+	SkAddrInit( pAC, pAC->IoBase, SK_INIT_IO);
+	SkRlmtInit( pAC, pAC->IoBase, SK_INIT_IO);
+	SkTimerInit(pAC, pAC->IoBase, SK_INIT_IO);
+
+	/* Set chipset type support */
+	pAC->ChipsetType = 0;
+	if ((pAC->GIni.GIChipId == CHIP_ID_YUKON) ||
+		(pAC->GIni.GIChipId == CHIP_ID_YUKON_LITE)) {
+		pAC->ChipsetType = 1;
+	}
+
+	GetConfiguration(pAC);
+	if (pAC->RlmtNets == 2) {
+		pAC->GIni.GIPortUsage = SK_MUL_LINK;
+	}
+
+	pAC->BoardLevel = SK_INIT_IO;
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+	if (pAC->GIni.GIMacsFound == 2) {
+		 Ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev);
+	} else if (pAC->GIni.GIMacsFound == 1) {
+		Ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED,
+			"sk98lin", dev);
+	} else {
+		printk(KERN_WARNING "sk98lin: Illegal number of ports: %d\n",
+		       pAC->GIni.GIMacsFound);
+		return -EIO;
+	}
+
+	if (Ret) {
+		printk(KERN_WARNING "sk98lin: Requested IRQ %d is busy.\n",
+		       dev->irq);
+		return Ret;
+	}
+	pAC->AllocFlag |= SK_ALLOC_IRQ;
+
+	/* Alloc memory for this board (Mem for RxD/TxD) : */
+	if(!BoardAllocMem(pAC)) {
+		printk("No memory for descriptor rings.\n");
+		return -ENOMEM;
+	}
+
+	BoardInitMem(pAC);
+	/* tschilling: New common function with minimum size check. */
+	DualNet = SK_FALSE;
+	if (pAC->RlmtNets == 2) {
+		DualNet = SK_TRUE;
+	}
+	
+	if (SkGeInitAssignRamToQueues(
+		pAC,
+		pAC->ActivePort,
+		DualNet)) {
+		BoardFreeMem(pAC);
+		printk("sk98lin: SkGeInitAssignRamToQueues failed.\n");
+		return -EIO;
+	}
+
+	return (0);
+} /* SkGeBoardInit */
+
+
+/*****************************************************************************
+ *
+ * 	BoardAllocMem - allocate the memory for the descriptor rings
+ *
+ * Description:
+ *	This function allocates the memory for all descriptor rings.
+ *	Each ring is aligned for the desriptor alignment and no ring
+ *	has a 4 GByte boundary in it (because the upper 32 bit must
+ *	be constant for all descriptiors in one rings).
+ *
+ * Returns:
+ *	SK_TRUE, if all memory could be allocated
+ *	SK_FALSE, if not
+ */
+static __devinit SK_BOOL BoardAllocMem(SK_AC	*pAC)
+{
+caddr_t		pDescrMem;	/* pointer to descriptor memory area */
+size_t		AllocLength;	/* length of complete descriptor area */
+int		i;		/* loop counter */
+unsigned long	BusAddr;
+
+	
+	/* rings plus one for alignment (do not cross 4 GB boundary) */
+	/* RX_RING_SIZE is assumed bigger than TX_RING_SIZE */
+#if (BITS_PER_LONG == 32)
+	AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + 8;
+#else
+	AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound
+		+ RX_RING_SIZE + 8;
+#endif
+
+	pDescrMem = pci_alloc_consistent(pAC->PciDev, AllocLength,
+					 &pAC->pDescrMemDMA);
+
+	if (pDescrMem == NULL) {
+		return (SK_FALSE);
+	}
+	pAC->pDescrMem = pDescrMem;
+	BusAddr = (unsigned long) pAC->pDescrMemDMA;
+
+	/* Descriptors need 8 byte alignment, and this is ensured
+	 * by pci_alloc_consistent.
+	 */
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+			("TX%d/A: pDescrMem: %lX,   PhysDescrMem: %lX\n",
+			i, (unsigned long) pDescrMem,
+			BusAddr));
+		pAC->TxPort[i][0].pTxDescrRing = pDescrMem;
+		pAC->TxPort[i][0].VTxDescrRing = BusAddr;
+		pDescrMem += TX_RING_SIZE;
+		BusAddr += TX_RING_SIZE;
+	
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+			("RX%d: pDescrMem: %lX,   PhysDescrMem: %lX\n",
+			i, (unsigned long) pDescrMem,
+			(unsigned long)BusAddr));
+		pAC->RxPort[i].pRxDescrRing = pDescrMem;
+		pAC->RxPort[i].VRxDescrRing = BusAddr;
+		pDescrMem += RX_RING_SIZE;
+		BusAddr += RX_RING_SIZE;
+	} /* for */
+	
+	return (SK_TRUE);
+} /* BoardAllocMem */
+
+
+/****************************************************************************
+ *
+ *	BoardFreeMem - reverse of BoardAllocMem
+ *
+ * Description:
+ *	Free all memory allocated in BoardAllocMem: adapter context,
+ *	descriptor rings, locks.
+ *
+ * Returns:	N/A
+ */
+static void BoardFreeMem(
+SK_AC		*pAC)
+{
+size_t		AllocLength;	/* length of complete descriptor area */
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("BoardFreeMem\n"));
+#if (BITS_PER_LONG == 32)
+	AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound + 8;
+#else
+	AllocLength = (RX_RING_SIZE + TX_RING_SIZE) * pAC->GIni.GIMacsFound
+		+ RX_RING_SIZE + 8;
+#endif
+
+	pci_free_consistent(pAC->PciDev, AllocLength,
+			    pAC->pDescrMem, pAC->pDescrMemDMA);
+	pAC->pDescrMem = NULL;
+} /* BoardFreeMem */
+
+
+/*****************************************************************************
+ *
+ * 	BoardInitMem - initiate the descriptor rings
+ *
+ * Description:
+ *	This function sets the descriptor rings up in memory.
+ *	The adapter is initialized with the descriptor start addresses.
+ *
+ * Returns:	N/A
+ */
+static __devinit void BoardInitMem(SK_AC *pAC)
+{
+int	i;		/* loop counter */
+int	RxDescrSize;	/* the size of a rx descriptor rounded up to alignment*/
+int	TxDescrSize;	/* the size of a tx descriptor rounded up to alignment*/
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("BoardInitMem\n"));
+
+	RxDescrSize = (((sizeof(RXD) - 1) / DESCR_ALIGN) + 1) * DESCR_ALIGN;
+	pAC->RxDescrPerRing = RX_RING_SIZE / RxDescrSize;
+	TxDescrSize = (((sizeof(TXD) - 1) / DESCR_ALIGN) + 1) * DESCR_ALIGN;
+	pAC->TxDescrPerRing = TX_RING_SIZE / RxDescrSize;
+	
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		SetupRing(
+			pAC,
+			pAC->TxPort[i][0].pTxDescrRing,
+			pAC->TxPort[i][0].VTxDescrRing,
+			(RXD**)&pAC->TxPort[i][0].pTxdRingHead,
+			(RXD**)&pAC->TxPort[i][0].pTxdRingTail,
+			(RXD**)&pAC->TxPort[i][0].pTxdRingPrev,
+			&pAC->TxPort[i][0].TxdRingFree,
+			SK_TRUE);
+		SetupRing(
+			pAC,
+			pAC->RxPort[i].pRxDescrRing,
+			pAC->RxPort[i].VRxDescrRing,
+			&pAC->RxPort[i].pRxdRingHead,
+			&pAC->RxPort[i].pRxdRingTail,
+			&pAC->RxPort[i].pRxdRingPrev,
+			&pAC->RxPort[i].RxdRingFree,
+			SK_FALSE);
+	}
+} /* BoardInitMem */
+
+
+/*****************************************************************************
+ *
+ * 	SetupRing - create one descriptor ring
+ *
+ * Description:
+ *	This function creates one descriptor ring in the given memory area.
+ *	The head, tail and number of free descriptors in the ring are set.
+ *
+ * Returns:
+ *	none
+ */
+static void SetupRing(
+SK_AC		*pAC,
+void		*pMemArea,	/* a pointer to the memory area for the ring */
+uintptr_t	VMemArea,	/* the virtual bus address of the memory area */
+RXD		**ppRingHead,	/* address where the head should be written */
+RXD		**ppRingTail,	/* address where the tail should be written */
+RXD		**ppRingPrev,	/* address where the tail should be written */
+int		*pRingFree,	/* address where the # of free descr. goes */
+SK_BOOL		IsTx)		/* flag: is this a tx ring */
+{
+int	i;		/* loop counter */
+int	DescrSize;	/* the size of a descriptor rounded up to alignment*/
+int	DescrNum;	/* number of descriptors per ring */
+RXD	*pDescr;	/* pointer to a descriptor (receive or transmit) */
+RXD	*pNextDescr;	/* pointer to the next descriptor */
+RXD	*pPrevDescr;	/* pointer to the previous descriptor */
+uintptr_t VNextDescr;	/* the virtual bus address of the next descriptor */
+
+	if (IsTx == SK_TRUE) {
+		DescrSize = (((sizeof(TXD) - 1) / DESCR_ALIGN) + 1) *
+			DESCR_ALIGN;
+		DescrNum = TX_RING_SIZE / DescrSize;
+	} else {
+		DescrSize = (((sizeof(RXD) - 1) / DESCR_ALIGN) + 1) *
+			DESCR_ALIGN;
+		DescrNum = RX_RING_SIZE / DescrSize;
+	}
+	
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS,
+		("Descriptor size: %d   Descriptor Number: %d\n",
+		DescrSize,DescrNum));
+	
+	pDescr = (RXD*) pMemArea;
+	pPrevDescr = NULL;
+	pNextDescr = (RXD*) (((char*)pDescr) + DescrSize);
+	VNextDescr = VMemArea + DescrSize;
+	for(i=0; i<DescrNum; i++) {
+		/* set the pointers right */
+		pDescr->VNextRxd = VNextDescr & 0xffffffffULL;
+		pDescr->pNextRxd = pNextDescr;
+		if (!IsTx) pDescr->TcpSumStarts = ETH_HLEN << 16 | ETH_HLEN;
+
+		/* advance one step */
+		pPrevDescr = pDescr;
+		pDescr = pNextDescr;
+		pNextDescr = (RXD*) (((char*)pDescr) + DescrSize);
+		VNextDescr += DescrSize;
+	}
+	pPrevDescr->pNextRxd = (RXD*) pMemArea;
+	pPrevDescr->VNextRxd = VMemArea;
+	pDescr = (RXD*) pMemArea;
+	*ppRingHead = (RXD*) pMemArea;
+	*ppRingTail = *ppRingHead;
+	*ppRingPrev = pPrevDescr;
+	*pRingFree = DescrNum;
+} /* SetupRing */
+
+
+/*****************************************************************************
+ *
+ * 	PortReInitBmu - re-initiate the descriptor rings for one port
+ *
+ * Description:
+ *	This function reinitializes the descriptor rings of one port
+ *	in memory. The port must be stopped before.
+ *	The HW is initialized with the descriptor start addresses.
+ *
+ * Returns:
+ *	none
+ */
+static void PortReInitBmu(
+SK_AC	*pAC,		/* pointer to adapter context */
+int	PortIndex)	/* index of the port for which to re-init */
+{
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("PortReInitBmu "));
+
+	/* set address of first descriptor of ring in BMU */
+	SK_OUT32(pAC->IoBase, TxQueueAddr[PortIndex][TX_PRIO_LOW]+ Q_DA_L,
+		(uint32_t)(((caddr_t)
+		(pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxdRingHead) -
+		pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxDescrRing +
+		pAC->TxPort[PortIndex][TX_PRIO_LOW].VTxDescrRing) &
+		0xFFFFFFFF));
+	SK_OUT32(pAC->IoBase, TxQueueAddr[PortIndex][TX_PRIO_LOW]+ Q_DA_H,
+		(uint32_t)(((caddr_t)
+		(pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxdRingHead) -
+		pAC->TxPort[PortIndex][TX_PRIO_LOW].pTxDescrRing +
+		pAC->TxPort[PortIndex][TX_PRIO_LOW].VTxDescrRing) >> 32));
+	SK_OUT32(pAC->IoBase, RxQueueAddr[PortIndex]+Q_DA_L,
+		(uint32_t)(((caddr_t)(pAC->RxPort[PortIndex].pRxdRingHead) -
+		pAC->RxPort[PortIndex].pRxDescrRing +
+		pAC->RxPort[PortIndex].VRxDescrRing) & 0xFFFFFFFF));
+	SK_OUT32(pAC->IoBase, RxQueueAddr[PortIndex]+Q_DA_H,
+		(uint32_t)(((caddr_t)(pAC->RxPort[PortIndex].pRxdRingHead) -
+		pAC->RxPort[PortIndex].pRxDescrRing +
+		pAC->RxPort[PortIndex].VRxDescrRing) >> 32));
+} /* PortReInitBmu */
+
+
+/****************************************************************************
+ *
+ *	SkGeIsr - handle adapter interrupts
+ *
+ * Description:
+ *	The interrupt routine is called when the network adapter
+ *	generates an interrupt. It may also be called if another device
+ *	shares this interrupt vector with the driver.
+ *
+ * Returns: N/A
+ *
+ */
+static SkIsrRetVar SkGeIsr(int irq, void *dev_id)
+{
+struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id;
+DEV_NET		*pNet;
+SK_AC		*pAC;
+SK_U32		IntSrc;		/* interrupts source register contents */	
+
+	pNet = netdev_priv(dev);
+	pAC = pNet->pAC;
+	
+	/*
+	 * Check and process if its our interrupt
+	 */
+	SK_IN32(pAC->IoBase, B0_SP_ISRC, &IntSrc);
+	if (IntSrc == 0) {
+		return SkIsrRetNone;
+	}
+
+	while (((IntSrc & IRQ_MASK) & ~SPECIAL_IRQS) != 0) {
+#if 0 /* software irq currently not used */
+		if (IntSrc & IS_IRQ_SW) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("Software IRQ\n"));
+		}
+#endif
+		if (IntSrc & IS_R1_F) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF RX1 IRQ\n"));
+			ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+			SK_PNMI_CNT_RX_INTR(pAC, 0);
+		}
+		if (IntSrc & IS_R2_F) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF RX2 IRQ\n"));
+			ReceiveIrq(pAC, &pAC->RxPort[1], SK_TRUE);
+			SK_PNMI_CNT_RX_INTR(pAC, 1);
+		}
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+		if (IntSrc & IS_XA1_F) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF AS TX1 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC, 0);
+			spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+			FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]);
+			spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+		}
+		if (IntSrc & IS_XA2_F) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF AS TX2 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC, 1);
+			spin_lock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock);
+			FreeTxDescriptors(pAC, &pAC->TxPort[1][TX_PRIO_LOW]);
+			spin_unlock(&pAC->TxPort[1][TX_PRIO_LOW].TxDesRingLock);
+		}
+#if 0 /* only if sync. queues used */
+		if (IntSrc & IS_XS1_F) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF SY TX1 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC, 1);
+			spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+			FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH);
+			spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+			ClearTxIrq(pAC, 0, TX_PRIO_HIGH);
+		}
+		if (IntSrc & IS_XS2_F) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF SY TX2 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC, 1);
+			spin_lock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock);
+			FreeTxDescriptors(pAC, 1, TX_PRIO_HIGH);
+			spin_unlock(&pAC->TxPort[1][TX_PRIO_HIGH].TxDesRingLock);
+			ClearTxIrq(pAC, 1, TX_PRIO_HIGH);
+		}
+#endif
+#endif
+
+		/* do all IO at once */
+		if (IntSrc & IS_R1_F)
+			ClearAndStartRx(pAC, 0);
+		if (IntSrc & IS_R2_F)
+			ClearAndStartRx(pAC, 1);
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+		if (IntSrc & IS_XA1_F)
+			ClearTxIrq(pAC, 0, TX_PRIO_LOW);
+		if (IntSrc & IS_XA2_F)
+			ClearTxIrq(pAC, 1, TX_PRIO_LOW);
+#endif
+		SK_IN32(pAC->IoBase, B0_ISRC, &IntSrc);
+	} /* while (IntSrc & IRQ_MASK != 0) */
+
+	IntSrc &= pAC->GIni.GIValIrqMask;
+	if ((IntSrc & SPECIAL_IRQS) || pAC->CheckQueue) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC,
+			("SPECIAL IRQ DP-Cards => %x\n", IntSrc));
+		pAC->CheckQueue = SK_FALSE;
+		spin_lock(&pAC->SlowPathLock);
+		if (IntSrc & SPECIAL_IRQS)
+			SkGeSirqIsr(pAC, pAC->IoBase, IntSrc);
+
+		SkEventDispatcher(pAC, pAC->IoBase);
+		spin_unlock(&pAC->SlowPathLock);
+	}
+	/*
+	 * do it all again is case we cleared an interrupt that
+	 * came in after handling the ring (OUTs may be delayed
+	 * in hardware buffers, but are through after IN)
+	 *
+	 * rroesler: has been commented out and shifted to
+	 *           SkGeDrvEvent(), because it is timer
+	 *           guarded now
+	 *
+	ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+	ReceiveIrq(pAC, &pAC->RxPort[1], SK_TRUE);
+	 */
+
+	if (pAC->CheckQueue) {
+		pAC->CheckQueue = SK_FALSE;
+		spin_lock(&pAC->SlowPathLock);
+		SkEventDispatcher(pAC, pAC->IoBase);
+		spin_unlock(&pAC->SlowPathLock);
+	}
+
+	/* IRQ is processed - Enable IRQs again*/
+	SK_OUT32(pAC->IoBase, B0_IMSK, pAC->GIni.GIValIrqMask);
+
+		return SkIsrRetHandled;
+} /* SkGeIsr */
+
+
+/****************************************************************************
+ *
+ *	SkGeIsrOnePort - handle adapter interrupts for single port adapter
+ *
+ * Description:
+ *	The interrupt routine is called when the network adapter
+ *	generates an interrupt. It may also be called if another device
+ *	shares this interrupt vector with the driver.
+ *	This is the same as above, but handles only one port.
+ *
+ * Returns: N/A
+ *
+ */
+static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id)
+{
+struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id;
+DEV_NET		*pNet;
+SK_AC		*pAC;
+SK_U32		IntSrc;		/* interrupts source register contents */	
+
+	pNet = netdev_priv(dev);
+	pAC = pNet->pAC;
+	
+	/*
+	 * Check and process if its our interrupt
+	 */
+	SK_IN32(pAC->IoBase, B0_SP_ISRC, &IntSrc);
+	if (IntSrc == 0) {
+		return SkIsrRetNone;
+	}
+	
+	while (((IntSrc & IRQ_MASK) & ~SPECIAL_IRQS) != 0) {
+#if 0 /* software irq currently not used */
+		if (IntSrc & IS_IRQ_SW) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("Software IRQ\n"));
+		}
+#endif
+		if (IntSrc & IS_R1_F) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF RX1 IRQ\n"));
+			ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+			SK_PNMI_CNT_RX_INTR(pAC, 0);
+		}
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+		if (IntSrc & IS_XA1_F) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF AS TX1 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC, 0);
+			spin_lock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+			FreeTxDescriptors(pAC, &pAC->TxPort[0][TX_PRIO_LOW]);
+			spin_unlock(&pAC->TxPort[0][TX_PRIO_LOW].TxDesRingLock);
+		}
+#if 0 /* only if sync. queues used */
+		if (IntSrc & IS_XS1_F) {
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_INT_SRC,
+				("EOF SY TX1 IRQ\n"));
+			SK_PNMI_CNT_TX_INTR(pAC, 0);
+			spin_lock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+			FreeTxDescriptors(pAC, 0, TX_PRIO_HIGH);
+			spin_unlock(&pAC->TxPort[0][TX_PRIO_HIGH].TxDesRingLock);
+			ClearTxIrq(pAC, 0, TX_PRIO_HIGH);
+		}
+#endif
+#endif
+
+		/* do all IO at once */
+		if (IntSrc & IS_R1_F)
+			ClearAndStartRx(pAC, 0);
+#ifdef USE_TX_COMPLETE /* only if tx complete interrupt used */
+		if (IntSrc & IS_XA1_F)
+			ClearTxIrq(pAC, 0, TX_PRIO_LOW);
+#endif
+		SK_IN32(pAC->IoBase, B0_ISRC, &IntSrc);
+	} /* while (IntSrc & IRQ_MASK != 0) */
+	
+	IntSrc &= pAC->GIni.GIValIrqMask;
+	if ((IntSrc & SPECIAL_IRQS) || pAC->CheckQueue) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_INT_SRC,
+			("SPECIAL IRQ SP-Cards => %x\n", IntSrc));
+		pAC->CheckQueue = SK_FALSE;
+		spin_lock(&pAC->SlowPathLock);
+		if (IntSrc & SPECIAL_IRQS)
+			SkGeSirqIsr(pAC, pAC->IoBase, IntSrc);
+
+		SkEventDispatcher(pAC, pAC->IoBase);
+		spin_unlock(&pAC->SlowPathLock);
+	}
+	/*
+	 * do it all again is case we cleared an interrupt that
+	 * came in after handling the ring (OUTs may be delayed
+	 * in hardware buffers, but are through after IN)
+	 *
+	 * rroesler: has been commented out and shifted to
+	 *           SkGeDrvEvent(), because it is timer
+	 *           guarded now
+	 *
+	ReceiveIrq(pAC, &pAC->RxPort[0], SK_TRUE);
+	 */
+
+	/* IRQ is processed - Enable IRQs again*/
+	SK_OUT32(pAC->IoBase, B0_IMSK, pAC->GIni.GIValIrqMask);
+
+		return SkIsrRetHandled;
+} /* SkGeIsrOnePort */
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/****************************************************************************
+ *
+ * 	SkGePollController - polling receive, for netconsole
+ *
+ * Description:
+ *	Polling receive - used by netconsole and other diagnostic tools
+ *	to allow network i/o with interrupts disabled.
+ *
+ * Returns: N/A
+ */
+static void SkGePollController(struct net_device *dev)
+{
+	disable_irq(dev->irq);
+	SkGeIsr(dev->irq, dev);
+	enable_irq(dev->irq);
+}
+#endif
+
+/****************************************************************************
+ *
+ *	SkGeOpen - handle start of initialized adapter
+ *
+ * Description:
+ *	This function starts the initialized adapter.
+ *	The board level variable is set and the adapter is
+ *	brought to full functionality.
+ *	The device flags are set for operation.
+ *	Do all necessary level 2 initialization, enable interrupts and
+ *	give start command to RLMT.
+ *
+ * Returns:
+ *	0 on success
+ *	!= 0 on error
+ */
+static int SkGeOpen(
+struct SK_NET_DEVICE	*dev)
+{
+	DEV_NET			*pNet;
+	SK_AC			*pAC;
+	unsigned long	Flags;		/* for spin lock */
+	int				i;
+	SK_EVPARA		EvPara;		/* an event parameter union */
+
+	pNet = netdev_priv(dev);
+	pAC = pNet->pAC;
+	
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeOpen: pAC=0x%lX:\n", (unsigned long)pAC));
+
+#ifdef SK_DIAG_SUPPORT
+	if (pAC->DiagModeActive == DIAG_ACTIVE) {
+		if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) {
+			return (-1);   /* still in use by diag; deny actions */
+		} 
+	}
+#endif
+
+	/* Set blink mode */
+	if ((pAC->PciDev->vendor == 0x1186) || (pAC->PciDev->vendor == 0x11ab ))
+		pAC->GIni.GILedBlinkCtrl = OEM_CONFIG_VALUE;
+
+	if (pAC->BoardLevel == SK_INIT_DATA) {
+		/* level 1 init common modules here */
+		if (SkGeInit(pAC, pAC->IoBase, SK_INIT_IO) != 0) {
+			printk("%s: HWInit (1) failed.\n", pAC->dev[pNet->PortNr]->name);
+			return (-1);
+		}
+		SkI2cInit	(pAC, pAC->IoBase, SK_INIT_IO);
+		SkEventInit	(pAC, pAC->IoBase, SK_INIT_IO);
+		SkPnmiInit	(pAC, pAC->IoBase, SK_INIT_IO);
+		SkAddrInit	(pAC, pAC->IoBase, SK_INIT_IO);
+		SkRlmtInit	(pAC, pAC->IoBase, SK_INIT_IO);
+		SkTimerInit	(pAC, pAC->IoBase, SK_INIT_IO);
+		pAC->BoardLevel = SK_INIT_IO;
+	}
+
+	if (pAC->BoardLevel != SK_INIT_RUN) {
+		/* tschilling: Level 2 init modules here, check return value. */
+		if (SkGeInit(pAC, pAC->IoBase, SK_INIT_RUN) != 0) {
+			printk("%s: HWInit (2) failed.\n", pAC->dev[pNet->PortNr]->name);
+			return (-1);
+		}
+		SkI2cInit	(pAC, pAC->IoBase, SK_INIT_RUN);
+		SkEventInit	(pAC, pAC->IoBase, SK_INIT_RUN);
+		SkPnmiInit	(pAC, pAC->IoBase, SK_INIT_RUN);
+		SkAddrInit	(pAC, pAC->IoBase, SK_INIT_RUN);
+		SkRlmtInit	(pAC, pAC->IoBase, SK_INIT_RUN);
+		SkTimerInit	(pAC, pAC->IoBase, SK_INIT_RUN);
+		pAC->BoardLevel = SK_INIT_RUN;
+	}
+
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		/* Enable transmit descriptor polling. */
+		SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE);
+		FillRxRing(pAC, &pAC->RxPort[i]);
+	}
+	SkGeYellowLED(pAC, pAC->IoBase, 1);
+
+	StartDrvCleanupTimer(pAC);
+	SkDimEnableModerationIfNeeded(pAC);	
+	SkDimDisplayModerationSettings(pAC);
+
+	pAC->GIni.GIValIrqMask &= IRQ_MASK;
+
+	/* enable Interrupts */
+	SK_OUT32(pAC->IoBase, B0_IMSK, pAC->GIni.GIValIrqMask);
+	SK_OUT32(pAC->IoBase, B0_HWE_IMSK, IRQ_HWE_MASK);
+
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+
+	if ((pAC->RlmtMode != 0) && (pAC->MaxPorts == 0)) {
+		EvPara.Para32[0] = pAC->RlmtNets;
+		EvPara.Para32[1] = -1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_SET_NETS,
+			EvPara);
+		EvPara.Para32[0] = pAC->RlmtMode;
+		EvPara.Para32[1] = 0;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_MODE_CHANGE,
+			EvPara);
+	}
+
+	EvPara.Para32[0] = pNet->NetNr;
+	EvPara.Para32[1] = -1;
+	SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+	SkEventDispatcher(pAC, pAC->IoBase);
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+	pAC->MaxPorts++;
+
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeOpen suceeded\n"));
+
+	return (0);
+} /* SkGeOpen */
+
+
+/****************************************************************************
+ *
+ *	SkGeClose - Stop initialized adapter
+ *
+ * Description:
+ *	Close initialized adapter.
+ *
+ * Returns:
+ *	0 - on success
+ *	error code - on error
+ */
+static int SkGeClose(
+struct SK_NET_DEVICE	*dev)
+{
+	DEV_NET		*pNet;
+	DEV_NET		*newPtrNet;
+	SK_AC		*pAC;
+
+	unsigned long	Flags;		/* for spin lock */
+	int		i;
+	int		PortIdx;
+	SK_EVPARA	EvPara;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeClose: pAC=0x%lX ", (unsigned long)pAC));
+
+	pNet = netdev_priv(dev);
+	pAC = pNet->pAC;
+
+#ifdef SK_DIAG_SUPPORT
+	if (pAC->DiagModeActive == DIAG_ACTIVE) {
+		if (pAC->DiagFlowCtrl == SK_FALSE) {
+			/* 
+			** notify that the interface which has been closed
+			** by operator interaction must not be started up 
+			** again when the DIAG has finished. 
+			*/
+			newPtrNet = netdev_priv(pAC->dev[0]);
+			if (newPtrNet == pNet) {
+				pAC->WasIfUp[0] = SK_FALSE;
+			} else {
+				pAC->WasIfUp[1] = SK_FALSE;
+			}
+			return 0; /* return to system everything is fine... */
+		} else {
+			pAC->DiagFlowCtrl = SK_FALSE;
+		}
+	}
+#endif
+
+	netif_stop_queue(dev);
+
+	if (pAC->RlmtNets == 1)
+		PortIdx = pAC->ActivePort;
+	else
+		PortIdx = pNet->NetNr;
+
+        StopDrvCleanupTimer(pAC);
+
+	/*
+	 * Clear multicast table, promiscuous mode ....
+	 */
+	SkAddrMcClear(pAC, pAC->IoBase, PortIdx, 0);
+	SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
+		SK_PROM_MODE_NONE);
+
+	if (pAC->MaxPorts == 1) {
+		spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+		/* disable interrupts */
+		SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+		EvPara.Para32[0] = pNet->NetNr;
+		EvPara.Para32[1] = -1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+		SkEventDispatcher(pAC, pAC->IoBase);
+		SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+		/* stop the hardware */
+		SkGeDeInit(pAC, pAC->IoBase);
+		pAC->BoardLevel = SK_INIT_DATA;
+		spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	} else {
+
+		spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+		EvPara.Para32[0] = pNet->NetNr;
+		EvPara.Para32[1] = -1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+		SkPnmiEvent(pAC, pAC->IoBase, SK_PNMI_EVT_XMAC_RESET, EvPara);
+		SkEventDispatcher(pAC, pAC->IoBase);
+		spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+		
+		/* Stop port */
+		spin_lock_irqsave(&pAC->TxPort[pNet->PortNr]
+			[TX_PRIO_LOW].TxDesRingLock, Flags);
+		SkGeStopPort(pAC, pAC->IoBase, pNet->PortNr,
+			SK_STOP_ALL, SK_HARD_RST);
+		spin_unlock_irqrestore(&pAC->TxPort[pNet->PortNr]
+			[TX_PRIO_LOW].TxDesRingLock, Flags);
+	}
+
+	if (pAC->RlmtNets == 1) {
+		/* clear all descriptor rings */
+		for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+			ReceiveIrq(pAC, &pAC->RxPort[i], SK_TRUE);
+			ClearRxRing(pAC, &pAC->RxPort[i]);
+			ClearTxRing(pAC, &pAC->TxPort[i][TX_PRIO_LOW]);
+		}
+	} else {
+		/* clear port descriptor rings */
+		ReceiveIrq(pAC, &pAC->RxPort[pNet->PortNr], SK_TRUE);
+		ClearRxRing(pAC, &pAC->RxPort[pNet->PortNr]);
+		ClearTxRing(pAC, &pAC->TxPort[pNet->PortNr][TX_PRIO_LOW]);
+	}
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeClose: done "));
+
+	SK_MEMSET(&(pAC->PnmiBackup), 0, sizeof(SK_PNMI_STRUCT_DATA));
+	SK_MEMCPY(&(pAC->PnmiBackup), &(pAC->PnmiStruct), 
+			sizeof(SK_PNMI_STRUCT_DATA));
+
+	pAC->MaxPorts--;
+
+	return (0);
+} /* SkGeClose */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeXmit - Linux frame transmit function
+ *
+ * Description:
+ *	The system calls this function to send frames onto the wire.
+ *	It puts the frame in the tx descriptor ring. If the ring is
+ *	full then, the 'tbusy' flag is set.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ * WARNING: returning 1 in 'tbusy' case caused system crashes (double
+ *	allocated skb's) !!!
+ */
+static int SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev)
+{
+DEV_NET		*pNet;
+SK_AC		*pAC;
+int			Rc;	/* return code of XmitFrame */
+
+	pNet = netdev_priv(dev);
+	pAC = pNet->pAC;
+
+	if ((!skb_shinfo(skb)->nr_frags) ||
+		(pAC->GIni.GIChipId == CHIP_ID_GENESIS)) {
+		/* Don't activate scatter-gather and hardware checksum */
+
+		if (pAC->RlmtNets == 2)
+			Rc = XmitFrame(
+				pAC,
+				&pAC->TxPort[pNet->PortNr][TX_PRIO_LOW],
+				skb);
+		else
+			Rc = XmitFrame(
+				pAC,
+				&pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW],
+				skb);
+	} else {
+		/* scatter-gather and hardware TCP checksumming anabled*/
+		if (pAC->RlmtNets == 2)
+			Rc = XmitFrameSG(
+				pAC,
+				&pAC->TxPort[pNet->PortNr][TX_PRIO_LOW],
+				skb);
+		else
+			Rc = XmitFrameSG(
+				pAC,
+				&pAC->TxPort[pAC->ActivePort][TX_PRIO_LOW],
+				skb);
+	}
+
+	/* Transmitter out of resources? */
+	if (Rc <= 0) {
+		netif_stop_queue(dev);
+	}
+
+	/* If not taken, give buffer ownership back to the
+	 * queueing layer.
+	 */
+	if (Rc < 0)
+		return (1);
+
+	dev->trans_start = jiffies;
+	return (0);
+} /* SkGeXmit */
+
+
+/*****************************************************************************
+ *
+ * 	XmitFrame - fill one socket buffer into the transmit ring
+ *
+ * Description:
+ *	This function puts a message into the transmit descriptor ring
+ *	if there is a descriptors left.
+ *	Linux skb's consist of only one continuous buffer.
+ *	The first step locks the ring. It is held locked
+ *	all time to avoid problems with SWITCH_../PORT_RESET.
+ *	Then the descriptoris allocated.
+ *	The second part is linking the buffer to the descriptor.
+ *	At the very last, the Control field of the descriptor
+ *	is made valid for the BMU and a start TX command is given
+ *	if necessary.
+ *
+ * Returns:
+ *	> 0 - on succes: the number of bytes in the message
+ *	= 0 - on resource shortage: this frame sent or dropped, now
+ *		the ring is full ( -> set tbusy)
+ *	< 0 - on failure: other problems ( -> return failure to upper layers)
+ */
+static int XmitFrame(
+SK_AC 		*pAC,		/* pointer to adapter context           */
+TX_PORT		*pTxPort,	/* pointer to struct of port to send to */
+struct sk_buff	*pMessage)	/* pointer to send-message              */
+{
+	TXD		*pTxd;		/* the rxd to fill */
+	TXD		*pOldTxd;
+	unsigned long	 Flags;
+	SK_U64		 PhysAddr;
+	int		 BytesSend = pMessage->len;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_TX_PROGRESS, ("X"));
+
+	spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
+#ifndef USE_TX_COMPLETE
+	FreeTxDescriptors(pAC, pTxPort);
+#endif
+	if (pTxPort->TxdRingFree == 0) {
+		/* 
+		** no enough free descriptors in ring at the moment.
+		** Maybe free'ing some old one help?
+		*/
+		FreeTxDescriptors(pAC, pTxPort);
+		if (pTxPort->TxdRingFree == 0) {
+			spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+			SK_PNMI_CNT_NO_TX_BUF(pAC, pTxPort->PortIndex);
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_TX_PROGRESS,
+				("XmitFrame failed\n"));
+			/* 
+			** the desired message can not be sent
+			** Because tbusy seems to be set, the message 
+			** should not be freed here. It will be used 
+			** by the scheduler of the ethernet handler 
+			*/
+			return (-1);
+		}
+	}
+
+	/*
+	** If the passed socket buffer is of smaller MTU-size than 60,
+	** copy everything into new buffer and fill all bytes between
+	** the original packet end and the new packet end of 60 with 0x00.
+	** This is to resolve faulty padding by the HW with 0xaa bytes.
+	*/
+	if (BytesSend < C_LEN_ETHERNET_MINSIZE) {
+		if (skb_padto(pMessage, C_LEN_ETHERNET_MINSIZE)) {
+			spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+			return 0;
+		}
+		pMessage->len = C_LEN_ETHERNET_MINSIZE;
+	}
+
+	/* 
+	** advance head counter behind descriptor needed for this frame, 
+	** so that needed descriptor is reserved from that on. The next
+	** action will be to add the passed buffer to the TX-descriptor
+	*/
+	pTxd = pTxPort->pTxdRingHead;
+	pTxPort->pTxdRingHead = pTxd->pNextTxd;
+	pTxPort->TxdRingFree--;
+
+#ifdef SK_DUMP_TX
+	DumpMsg(pMessage, "XmitFrame");
+#endif
+
+	/* 
+	** First step is to map the data to be sent via the adapter onto
+	** the DMA memory. Kernel 2.2 uses virt_to_bus(), but kernels 2.4
+	** and 2.6 need to use pci_map_page() for that mapping.
+	*/
+	PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+					virt_to_page(pMessage->data),
+					((unsigned long) pMessage->data & ~PAGE_MASK),
+					pMessage->len,
+					PCI_DMA_TODEVICE);
+	pTxd->VDataLow  = (SK_U32) (PhysAddr & 0xffffffff);
+	pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+	pTxd->pMBuf     = pMessage;
+
+	if (pMessage->ip_summed == CHECKSUM_PARTIAL) {
+		u16 hdrlen = skb_transport_offset(pMessage);
+		u16 offset = hdrlen + pMessage->csum_offset;
+
+		if ((ipip_hdr(pMessage)->protocol == IPPROTO_UDP) &&
+			(pAC->GIni.GIChipRev == 0) &&
+			(pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
+			pTxd->TBControl = BMU_TCP_CHECK;
+		} else {
+			pTxd->TBControl = BMU_UDP_CHECK;
+		}
+
+		pTxd->TcpSumOfs = 0;
+		pTxd->TcpSumSt  = hdrlen;
+		pTxd->TcpSumWr  = offset;
+
+		pTxd->TBControl |= BMU_OWN | BMU_STF | 
+				   BMU_SW  | BMU_EOF |
+#ifdef USE_TX_COMPLETE
+				   BMU_IRQ_EOF |
+#endif
+				   pMessage->len;
+        } else {
+		pTxd->TBControl = BMU_OWN | BMU_STF | BMU_CHECK | 
+				  BMU_SW  | BMU_EOF |
+#ifdef USE_TX_COMPLETE
+				   BMU_IRQ_EOF |
+#endif
+			pMessage->len;
+	}
+
+	/* 
+	** If previous descriptor already done, give TX start cmd 
+	*/
+	pOldTxd = xchg(&pTxPort->pTxdRingPrev, pTxd);
+	if ((pOldTxd->TBControl & BMU_OWN) == 0) {
+		SK_OUT8(pTxPort->HwAddr, Q_CSR, CSR_START);
+	}	
+
+	/* 
+	** after releasing the lock, the skb may immediately be free'd 
+	*/
+	spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+	if (pTxPort->TxdRingFree != 0) {
+		return (BytesSend);
+	} else {
+		return (0);
+	}
+
+} /* XmitFrame */
+
+/*****************************************************************************
+ *
+ * 	XmitFrameSG - fill one socket buffer into the transmit ring
+ *                (use SG and TCP/UDP hardware checksumming)
+ *
+ * Description:
+ *	This function puts a message into the transmit descriptor ring
+ *	if there is a descriptors left.
+ *
+ * Returns:
+ *	> 0 - on succes: the number of bytes in the message
+ *	= 0 - on resource shortage: this frame sent or dropped, now
+ *		the ring is full ( -> set tbusy)
+ *	< 0 - on failure: other problems ( -> return failure to upper layers)
+ */
+static int XmitFrameSG(
+SK_AC 		*pAC,		/* pointer to adapter context           */
+TX_PORT		*pTxPort,	/* pointer to struct of port to send to */
+struct sk_buff	*pMessage)	/* pointer to send-message              */
+{
+
+	TXD		*pTxd;
+	TXD		*pTxdFst;
+	TXD		*pTxdLst;
+	int 	 	 CurrFrag;
+	int		 BytesSend;
+	skb_frag_t	*sk_frag;
+	SK_U64		 PhysAddr;
+	unsigned long	 Flags;
+	SK_U32		 Control;
+
+	spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
+#ifndef USE_TX_COMPLETE
+	FreeTxDescriptors(pAC, pTxPort);
+#endif
+	if ((skb_shinfo(pMessage)->nr_frags +1) > pTxPort->TxdRingFree) {
+		FreeTxDescriptors(pAC, pTxPort);
+		if ((skb_shinfo(pMessage)->nr_frags + 1) > pTxPort->TxdRingFree) {
+			spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+			SK_PNMI_CNT_NO_TX_BUF(pAC, pTxPort->PortIndex);
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_TX_PROGRESS,
+				("XmitFrameSG failed - Ring full\n"));
+				/* this message can not be sent now */
+			return(-1);
+		}
+	}
+
+	pTxd      = pTxPort->pTxdRingHead;
+	pTxdFst   = pTxd;
+	pTxdLst   = pTxd;
+	BytesSend = 0;
+
+	/* 
+	** Map the first fragment (header) into the DMA-space
+	*/
+	PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+			virt_to_page(pMessage->data),
+			((unsigned long) pMessage->data & ~PAGE_MASK),
+			skb_headlen(pMessage),
+			PCI_DMA_TODEVICE);
+
+	pTxd->VDataLow  = (SK_U32) (PhysAddr & 0xffffffff);
+	pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+
+	/* 
+	** Does the HW need to evaluate checksum for TCP or UDP packets? 
+	*/
+	if (pMessage->ip_summed == CHECKSUM_PARTIAL) {
+		u16 hdrlen = skb_transport_offset(pMessage);
+		u16 offset = hdrlen + pMessage->csum_offset;
+
+		Control = BMU_STFWD;
+
+		/* 
+		** We have to use the opcode for tcp here,  because the
+		** opcode for udp is not working in the hardware yet 
+		** (Revision 2.0)
+		*/
+		if ((ipip_hdr(pMessage)->protocol == IPPROTO_UDP) &&
+			(pAC->GIni.GIChipRev == 0) &&
+			(pAC->GIni.GIChipId == CHIP_ID_YUKON)) {
+			Control |= BMU_TCP_CHECK;
+		} else {
+			Control |= BMU_UDP_CHECK;
+		}
+
+		pTxd->TcpSumOfs = 0;
+		pTxd->TcpSumSt  = hdrlen;
+		pTxd->TcpSumWr  = offset;
+	} else
+		Control = BMU_CHECK | BMU_SW;
+
+	pTxd->TBControl = BMU_STF | Control | skb_headlen(pMessage);
+
+	pTxd = pTxd->pNextTxd;
+	pTxPort->TxdRingFree--;
+	BytesSend += skb_headlen(pMessage);
+
+	/* 
+	** Browse over all SG fragments and map each of them into the DMA space
+	*/
+	for (CurrFrag = 0; CurrFrag < skb_shinfo(pMessage)->nr_frags; CurrFrag++) {
+		sk_frag = &skb_shinfo(pMessage)->frags[CurrFrag];
+		/* 
+		** we already have the proper value in entry
+		*/
+		PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+						 sk_frag->page,
+						 sk_frag->page_offset,
+						 sk_frag->size,
+						 PCI_DMA_TODEVICE);
+
+		pTxd->VDataLow  = (SK_U32) (PhysAddr & 0xffffffff);
+		pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+		pTxd->pMBuf     = pMessage;
+		
+		pTxd->TBControl = Control | BMU_OWN | sk_frag->size;
+
+		/* 
+		** Do we have the last fragment? 
+		*/
+		if( (CurrFrag+1) == skb_shinfo(pMessage)->nr_frags )  {
+#ifdef USE_TX_COMPLETE
+			pTxd->TBControl |= BMU_EOF | BMU_IRQ_EOF;
+#else
+			pTxd->TBControl |= BMU_EOF;
+#endif
+			pTxdFst->TBControl |= BMU_OWN | BMU_SW;
+		}
+		pTxdLst = pTxd;
+		pTxd    = pTxd->pNextTxd;
+		pTxPort->TxdRingFree--;
+		BytesSend += sk_frag->size;
+	}
+
+	/* 
+	** If previous descriptor already done, give TX start cmd 
+	*/
+	if ((pTxPort->pTxdRingPrev->TBControl & BMU_OWN) == 0) {
+		SK_OUT8(pTxPort->HwAddr, Q_CSR, CSR_START);
+	}
+
+	pTxPort->pTxdRingPrev = pTxdLst;
+	pTxPort->pTxdRingHead = pTxd;
+
+	spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+
+	if (pTxPort->TxdRingFree > 0) {
+		return (BytesSend);
+	} else {
+		return (0);
+	}
+}
+
+/*****************************************************************************
+ *
+ * 	FreeTxDescriptors - release descriptors from the descriptor ring
+ *
+ * Description:
+ *	This function releases descriptors from a transmit ring if they
+ *	have been sent by the BMU.
+ *	If a descriptors is sent, it can be freed and the message can
+ *	be freed, too.
+ *	The SOFTWARE controllable bit is used to prevent running around a
+ *	completely free ring for ever. If this bit is no set in the
+ *	frame (by XmitFrame), this frame has never been sent or is
+ *	already freed.
+ *	The Tx descriptor ring lock must be held while calling this function !!!
+ *
+ * Returns:
+ *	none
+ */
+static void FreeTxDescriptors(
+SK_AC	*pAC,		/* pointer to the adapter context */
+TX_PORT	*pTxPort)	/* pointer to destination port structure */
+{
+TXD	*pTxd;		/* pointer to the checked descriptor */
+TXD	*pNewTail;	/* pointer to 'end' of the ring */
+SK_U32	Control;	/* TBControl field of descriptor */
+SK_U64	PhysAddr;	/* address of DMA mapping */
+
+	pNewTail = pTxPort->pTxdRingTail;
+	pTxd     = pNewTail;
+	/*
+	** loop forever; exits if BMU_SW bit not set in start frame
+	** or BMU_OWN bit set in any frame
+	*/
+	while (1) {
+		Control = pTxd->TBControl;
+		if ((Control & BMU_SW) == 0) {
+			/*
+			** software controllable bit is set in first
+			** fragment when given to BMU. Not set means that
+			** this fragment was never sent or is already
+			** freed ( -> ring completely free now).
+			*/
+			pTxPort->pTxdRingTail = pTxd;
+			netif_wake_queue(pAC->dev[pTxPort->PortIndex]);
+			return;
+		}
+		if (Control & BMU_OWN) {
+			pTxPort->pTxdRingTail = pTxd;
+			if (pTxPort->TxdRingFree > 0) {
+				netif_wake_queue(pAC->dev[pTxPort->PortIndex]);
+			}
+			return;
+		}
+		
+		/* 
+		** release the DMA mapping, because until not unmapped
+		** this buffer is considered being under control of the
+		** adapter card!
+		*/
+		PhysAddr = ((SK_U64) pTxd->VDataHigh) << (SK_U64) 32;
+		PhysAddr |= (SK_U64) pTxd->VDataLow;
+		pci_unmap_page(pAC->PciDev, PhysAddr,
+				 pTxd->pMBuf->len,
+				 PCI_DMA_TODEVICE);
+
+		if (Control & BMU_EOF)
+			DEV_KFREE_SKB_ANY(pTxd->pMBuf);	/* free message */
+
+		pTxPort->TxdRingFree++;
+		pTxd->TBControl &= ~BMU_SW;
+		pTxd = pTxd->pNextTxd; /* point behind fragment with EOF */
+	} /* while(forever) */
+} /* FreeTxDescriptors */
+
+/*****************************************************************************
+ *
+ * 	FillRxRing - fill the receive ring with valid descriptors
+ *
+ * Description:
+ *	This function fills the receive ring descriptors with data
+ *	segments and makes them valid for the BMU.
+ *	The active ring is filled completely, if possible.
+ *	The non-active ring is filled only partial to save memory.
+ *
+ * Description of rx ring structure:
+ *	head - points to the descriptor which will be used next by the BMU
+ *	tail - points to the next descriptor to give to the BMU
+ *	
+ * Returns:	N/A
+ */
+static void FillRxRing(
+SK_AC		*pAC,		/* pointer to the adapter context */
+RX_PORT		*pRxPort)	/* ptr to port struct for which the ring
+				   should be filled */
+{
+unsigned long	Flags;
+
+	spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags);
+	while (pRxPort->RxdRingFree > pRxPort->RxFillLimit) {
+		if(!FillRxDescriptor(pAC, pRxPort))
+			break;
+	}
+	spin_unlock_irqrestore(&pRxPort->RxDesRingLock, Flags);
+} /* FillRxRing */
+
+
+/*****************************************************************************
+ *
+ * 	FillRxDescriptor - fill one buffer into the receive ring
+ *
+ * Description:
+ *	The function allocates a new receive buffer and
+ *	puts it into the next descriptor.
+ *
+ * Returns:
+ *	SK_TRUE - a buffer was added to the ring
+ *	SK_FALSE - a buffer could not be added
+ */
+static SK_BOOL FillRxDescriptor(
+SK_AC		*pAC,		/* pointer to the adapter context struct */
+RX_PORT		*pRxPort)	/* ptr to port struct of ring to fill */
+{
+struct sk_buff	*pMsgBlock;	/* pointer to a new message block */
+RXD		*pRxd;		/* the rxd to fill */
+SK_U16		Length;		/* data fragment length */
+SK_U64		PhysAddr;	/* physical address of a rx buffer */
+
+	pMsgBlock = alloc_skb(pAC->RxBufSize, GFP_ATOMIC);
+	if (pMsgBlock == NULL) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+			SK_DBGCAT_DRV_ENTRY,
+			("%s: Allocation of rx buffer failed !\n",
+			pAC->dev[pRxPort->PortIndex]->name));
+		SK_PNMI_CNT_NO_RX_BUF(pAC, pRxPort->PortIndex);
+		return(SK_FALSE);
+	}
+	skb_reserve(pMsgBlock, 2); /* to align IP frames */
+	/* skb allocated ok, so add buffer */
+	pRxd = pRxPort->pRxdRingTail;
+	pRxPort->pRxdRingTail = pRxd->pNextRxd;
+	pRxPort->RxdRingFree--;
+	Length = pAC->RxBufSize;
+	PhysAddr = (SK_U64) pci_map_page(pAC->PciDev,
+		virt_to_page(pMsgBlock->data),
+		((unsigned long) pMsgBlock->data &
+		~PAGE_MASK),
+		pAC->RxBufSize - 2,
+		PCI_DMA_FROMDEVICE);
+
+	pRxd->VDataLow  = (SK_U32) (PhysAddr & 0xffffffff);
+	pRxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
+	pRxd->pMBuf     = pMsgBlock;
+	pRxd->RBControl = BMU_OWN       | 
+			  BMU_STF       | 
+			  BMU_IRQ_EOF   | 
+			  BMU_TCP_CHECK | 
+			  Length;
+	return (SK_TRUE);
+
+} /* FillRxDescriptor */
+
+
+/*****************************************************************************
+ *
+ * 	ReQueueRxBuffer - fill one buffer back into the receive ring
+ *
+ * Description:
+ *	Fill a given buffer back into the rx ring. The buffer
+ *	has been previously allocated and aligned, and its phys.
+ *	address calculated, so this is no more necessary.
+ *
+ * Returns: N/A
+ */
+static void ReQueueRxBuffer(
+SK_AC		*pAC,		/* pointer to the adapter context struct */
+RX_PORT		*pRxPort,	/* ptr to port struct of ring to fill */
+struct sk_buff	*pMsg,		/* pointer to the buffer */
+SK_U32		PhysHigh,	/* phys address high dword */
+SK_U32		PhysLow)	/* phys address low dword */
+{
+RXD		*pRxd;		/* the rxd to fill */
+SK_U16		Length;		/* data fragment length */
+
+	pRxd = pRxPort->pRxdRingTail;
+	pRxPort->pRxdRingTail = pRxd->pNextRxd;
+	pRxPort->RxdRingFree--;
+	Length = pAC->RxBufSize;
+
+	pRxd->VDataLow  = PhysLow;
+	pRxd->VDataHigh = PhysHigh;
+	pRxd->pMBuf     = pMsg;
+	pRxd->RBControl = BMU_OWN       | 
+			  BMU_STF       |
+			  BMU_IRQ_EOF   | 
+			  BMU_TCP_CHECK | 
+			  Length;
+	return;
+} /* ReQueueRxBuffer */
+
+/*****************************************************************************
+ *
+ * 	ReceiveIrq - handle a receive IRQ
+ *
+ * Description:
+ *	This function is called when a receive IRQ is set.
+ *	It walks the receive descriptor ring and sends up all
+ *	frames that are complete.
+ *
+ * Returns:	N/A
+ */
+static void ReceiveIrq(
+	SK_AC		*pAC,			/* pointer to adapter context */
+	RX_PORT		*pRxPort,		/* pointer to receive port struct */
+	SK_BOOL		SlowPathLock)	/* indicates if SlowPathLock is needed */
+{
+RXD				*pRxd;			/* pointer to receive descriptors */
+SK_U32			Control;		/* control field of descriptor */
+struct sk_buff	*pMsg;			/* pointer to message holding frame */
+struct sk_buff	*pNewMsg;		/* pointer to a new message for copying frame */
+int				FrameLength;	/* total length of received frame */
+SK_MBUF			*pRlmtMbuf;		/* ptr to a buffer for giving a frame to rlmt */
+SK_EVPARA		EvPara;			/* an event parameter union */	
+unsigned long	Flags;			/* for spin lock */
+int				PortIndex = pRxPort->PortIndex;
+unsigned int	Offset;
+unsigned int	NumBytes;
+unsigned int	ForRlmt;
+SK_BOOL			IsBc;
+SK_BOOL			IsMc;
+SK_BOOL  IsBadFrame; 			/* Bad frame */
+
+SK_U32			FrameStat;
+SK_U64			PhysAddr;
+
+rx_start:	
+	/* do forever; exit if BMU_OWN found */
+	for ( pRxd = pRxPort->pRxdRingHead ;
+		  pRxPort->RxdRingFree < pAC->RxDescrPerRing ;
+		  pRxd = pRxd->pNextRxd,
+		  pRxPort->pRxdRingHead = pRxd,
+		  pRxPort->RxdRingFree ++) {
+
+		/*
+		 * For a better understanding of this loop
+		 * Go through every descriptor beginning at the head
+		 * Please note: the ring might be completely received so the OWN bit
+		 * set is not a good crirteria to leave that loop.
+		 * Therefore the RingFree counter is used.
+		 * On entry of this loop pRxd is a pointer to the Rxd that needs
+		 * to be checked next.
+		 */
+
+		Control = pRxd->RBControl;
+	
+		/* check if this descriptor is ready */
+		if ((Control & BMU_OWN) != 0) {
+			/* this descriptor is not yet ready */
+			/* This is the usual end of the loop */
+			/* We don't need to start the ring again */
+			FillRxRing(pAC, pRxPort);
+			return;
+		}
+                pAC->DynIrqModInfo.NbrProcessedDescr++;
+
+		/* get length of frame and check it */
+		FrameLength = Control & BMU_BBC;
+		if (FrameLength > pAC->RxBufSize) {
+			goto rx_failed;
+		}
+
+		/* check for STF and EOF */
+		if ((Control & (BMU_STF | BMU_EOF)) != (BMU_STF | BMU_EOF)) {
+			goto rx_failed;
+		}
+
+		/* here we have a complete frame in the ring */
+		pMsg = pRxd->pMBuf;
+
+		FrameStat = pRxd->FrameStat;
+
+		/* check for frame length mismatch */
+#define XMR_FS_LEN_SHIFT        18
+#define GMR_FS_LEN_SHIFT        16
+		if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+			if (FrameLength != (SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT)) {
+				SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+					SK_DBGCAT_DRV_RX_PROGRESS,
+					("skge: Frame length mismatch (%u/%u).\n",
+					FrameLength,
+					(SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT)));
+				goto rx_failed;
+			}
+		}
+		else {
+			if (FrameLength != (SK_U32) (FrameStat >> GMR_FS_LEN_SHIFT)) {
+				SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+					SK_DBGCAT_DRV_RX_PROGRESS,
+					("skge: Frame length mismatch (%u/%u).\n",
+					FrameLength,
+					(SK_U32) (FrameStat >> XMR_FS_LEN_SHIFT)));
+				goto rx_failed;
+			}
+		}
+
+		/* Set Rx Status */
+		if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+			IsBc = (FrameStat & XMR_FS_BC) != 0;
+			IsMc = (FrameStat & XMR_FS_MC) != 0;
+			IsBadFrame = (FrameStat &
+				(XMR_FS_ANY_ERR | XMR_FS_2L_VLAN)) != 0;
+		} else {
+			IsBc = (FrameStat & GMR_FS_BC) != 0;
+			IsMc = (FrameStat & GMR_FS_MC) != 0;
+			IsBadFrame = (((FrameStat & GMR_FS_ANY_ERR) != 0) ||
+							((FrameStat & GMR_FS_RX_OK) == 0));
+		}
+
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0,
+			("Received frame of length %d on port %d\n",
+			FrameLength, PortIndex));
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 0,
+			("Number of free rx descriptors: %d\n",
+			pRxPort->RxdRingFree));
+/* DumpMsg(pMsg, "Rx");	*/
+
+		if ((Control & BMU_STAT_VAL) != BMU_STAT_VAL || (IsBadFrame)) {
+#if 0
+			(FrameStat & (XMR_FS_ANY_ERR | XMR_FS_2L_VLAN)) != 0) {
+#endif
+			/* there is a receive error in this frame */
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_RX_PROGRESS,
+				("skge: Error in received frame, dropped!\n"
+				"Control: %x\nRxStat: %x\n",
+				Control, FrameStat));
+
+			ReQueueRxBuffer(pAC, pRxPort, pMsg,
+				pRxd->VDataHigh, pRxd->VDataLow);
+
+			continue;
+		}
+
+		/*
+		 * if short frame then copy data to reduce memory waste
+		 */
+		if ((FrameLength < SK_COPY_THRESHOLD) &&
+			((pNewMsg = alloc_skb(FrameLength+2, GFP_ATOMIC)) != NULL)) {
+			/*
+			 * Short frame detected and allocation successfull
+			 */
+			/* use new skb and copy data */
+			skb_reserve(pNewMsg, 2);
+			skb_put(pNewMsg, FrameLength);
+			PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+			PhysAddr |= (SK_U64) pRxd->VDataLow;
+
+			pci_dma_sync_single_for_cpu(pAC->PciDev,
+						    (dma_addr_t) PhysAddr,
+						    FrameLength,
+						    PCI_DMA_FROMDEVICE);
+			skb_copy_to_linear_data(pNewMsg, pMsg, FrameLength);
+
+			pci_dma_sync_single_for_device(pAC->PciDev,
+						       (dma_addr_t) PhysAddr,
+						       FrameLength,
+						       PCI_DMA_FROMDEVICE);
+			ReQueueRxBuffer(pAC, pRxPort, pMsg,
+				pRxd->VDataHigh, pRxd->VDataLow);
+
+			pMsg = pNewMsg;
+
+		}
+		else {
+			/*
+			 * if large frame, or SKB allocation failed, pass
+			 * the SKB directly to the networking
+			 */
+
+			PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+			PhysAddr |= (SK_U64) pRxd->VDataLow;
+
+			/* release the DMA mapping */
+			pci_unmap_single(pAC->PciDev,
+					 PhysAddr,
+					 pAC->RxBufSize - 2,
+					 PCI_DMA_FROMDEVICE);
+
+			/* set length in message */
+			skb_put(pMsg, FrameLength);
+		} /* frame > SK_COPY_TRESHOLD */
+
+#ifdef USE_SK_RX_CHECKSUM
+		pMsg->csum = pRxd->TcpSums & 0xffff;
+		pMsg->ip_summed = CHECKSUM_COMPLETE;
+#else
+		pMsg->ip_summed = CHECKSUM_NONE;
+#endif
+
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV,	1,("V"));
+		ForRlmt = SK_RLMT_RX_PROTOCOL;
+#if 0
+		IsBc = (FrameStat & XMR_FS_BC)==XMR_FS_BC;
+#endif
+		SK_RLMT_PRE_LOOKAHEAD(pAC, PortIndex, FrameLength,
+			IsBc, &Offset, &NumBytes);
+		if (NumBytes != 0) {
+#if 0
+			IsMc = (FrameStat & XMR_FS_MC)==XMR_FS_MC;
+#endif
+			SK_RLMT_LOOKAHEAD(pAC, PortIndex,
+				&pMsg->data[Offset],
+				IsBc, IsMc, &ForRlmt);
+		}
+		if (ForRlmt == SK_RLMT_RX_PROTOCOL) {
+					SK_DBG_MSG(NULL, SK_DBGMOD_DRV,	1,("W"));
+			/* send up only frames from active port */
+			if ((PortIndex == pAC->ActivePort) ||
+				(pAC->RlmtNets == 2)) {
+				/* frame for upper layer */
+				SK_DBG_MSG(NULL, SK_DBGMOD_DRV, 1,("U"));
+#ifdef xDEBUG
+				DumpMsg(pMsg, "Rx");
+#endif
+				SK_PNMI_CNT_RX_OCTETS_DELIVERED(pAC,
+					FrameLength, pRxPort->PortIndex);
+
+				pMsg->protocol = eth_type_trans(pMsg,
+					pAC->dev[pRxPort->PortIndex]);
+				netif_rx(pMsg);
+				pAC->dev[pRxPort->PortIndex]->last_rx = jiffies;
+			}
+			else {
+				/* drop frame */
+				SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+					SK_DBGCAT_DRV_RX_PROGRESS,
+					("D"));
+				DEV_KFREE_SKB(pMsg);
+			}
+			
+		} /* if not for rlmt */
+		else {
+			/* packet for rlmt */
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+				SK_DBGCAT_DRV_RX_PROGRESS, ("R"));
+			pRlmtMbuf = SkDrvAllocRlmtMbuf(pAC,
+				pAC->IoBase, FrameLength);
+			if (pRlmtMbuf != NULL) {
+				pRlmtMbuf->pNext = NULL;
+				pRlmtMbuf->Length = FrameLength;
+				pRlmtMbuf->PortIdx = PortIndex;
+				EvPara.pParaPtr = pRlmtMbuf;
+				memcpy((char*)(pRlmtMbuf->pData),
+					   (char*)(pMsg->data),
+					   FrameLength);
+
+				/* SlowPathLock needed? */
+				if (SlowPathLock == SK_TRUE) {
+					spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+					SkEventQueue(pAC, SKGE_RLMT,
+						SK_RLMT_PACKET_RECEIVED,
+						EvPara);
+					pAC->CheckQueue = SK_TRUE;
+					spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+				} else {
+					SkEventQueue(pAC, SKGE_RLMT,
+						SK_RLMT_PACKET_RECEIVED,
+						EvPara);
+					pAC->CheckQueue = SK_TRUE;
+				}
+
+				SK_DBG_MSG(NULL, SK_DBGMOD_DRV,
+					SK_DBGCAT_DRV_RX_PROGRESS,
+					("Q"));
+			}
+			if ((pAC->dev[pRxPort->PortIndex]->flags &
+				(IFF_PROMISC | IFF_ALLMULTI)) != 0 ||
+				(ForRlmt & SK_RLMT_RX_PROTOCOL) ==
+				SK_RLMT_RX_PROTOCOL) {
+				pMsg->protocol = eth_type_trans(pMsg,
+					pAC->dev[pRxPort->PortIndex]);
+				netif_rx(pMsg);
+				pAC->dev[pRxPort->PortIndex]->last_rx = jiffies;
+			}
+			else {
+				DEV_KFREE_SKB(pMsg);
+			}
+
+		} /* if packet for rlmt */
+	} /* for ... scanning the RXD ring */
+
+	/* RXD ring is empty -> fill and restart */
+	FillRxRing(pAC, pRxPort);
+	/* do not start if called from Close */
+	if (pAC->BoardLevel > SK_INIT_DATA) {
+		ClearAndStartRx(pAC, PortIndex);
+	}
+	return;
+
+rx_failed:
+	/* remove error frame */
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ERROR,
+		("Schrottdescriptor, length: 0x%x\n", FrameLength));
+
+	/* release the DMA mapping */
+
+	PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+	PhysAddr |= (SK_U64) pRxd->VDataLow;
+	pci_unmap_page(pAC->PciDev,
+			 PhysAddr,
+			 pAC->RxBufSize - 2,
+			 PCI_DMA_FROMDEVICE);
+	DEV_KFREE_SKB_IRQ(pRxd->pMBuf);
+	pRxd->pMBuf = NULL;
+	pRxPort->RxdRingFree++;
+	pRxPort->pRxdRingHead = pRxd->pNextRxd;
+	goto rx_start;
+
+} /* ReceiveIrq */
+
+
+/*****************************************************************************
+ *
+ * 	ClearAndStartRx - give a start receive command to BMU, clear IRQ
+ *
+ * Description:
+ *	This function sends a start command and a clear interrupt
+ *	command for one receive queue to the BMU.
+ *
+ * Returns: N/A
+ *	none
+ */
+static void ClearAndStartRx(
+SK_AC	*pAC,		/* pointer to the adapter context */
+int	PortIndex)	/* index of the receive port (XMAC) */
+{
+	SK_OUT8(pAC->IoBase,
+		RxQueueAddr[PortIndex]+Q_CSR,
+		CSR_START | CSR_IRQ_CL_F);
+} /* ClearAndStartRx */
+
+
+/*****************************************************************************
+ *
+ * 	ClearTxIrq - give a clear transmit IRQ command to BMU
+ *
+ * Description:
+ *	This function sends a clear tx IRQ command for one
+ *	transmit queue to the BMU.
+ *
+ * Returns: N/A
+ */
+static void ClearTxIrq(
+SK_AC	*pAC,		/* pointer to the adapter context */
+int	PortIndex,	/* index of the transmit port (XMAC) */
+int	Prio)		/* priority or normal queue */
+{
+	SK_OUT8(pAC->IoBase, 
+		TxQueueAddr[PortIndex][Prio]+Q_CSR,
+		CSR_IRQ_CL_F);
+} /* ClearTxIrq */
+
+
+/*****************************************************************************
+ *
+ * 	ClearRxRing - remove all buffers from the receive ring
+ *
+ * Description:
+ *	This function removes all receive buffers from the ring.
+ *	The receive BMU must be stopped before calling this function.
+ *
+ * Returns: N/A
+ */
+static void ClearRxRing(
+SK_AC	*pAC,		/* pointer to adapter context */
+RX_PORT	*pRxPort)	/* pointer to rx port struct */
+{
+RXD		*pRxd;	/* pointer to the current descriptor */
+unsigned long	Flags;
+SK_U64		PhysAddr;
+
+	if (pRxPort->RxdRingFree == pAC->RxDescrPerRing) {
+		return;
+	}
+	spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags);
+	pRxd = pRxPort->pRxdRingHead;
+	do {
+		if (pRxd->pMBuf != NULL) {
+
+			PhysAddr = ((SK_U64) pRxd->VDataHigh) << (SK_U64)32;
+			PhysAddr |= (SK_U64) pRxd->VDataLow;
+			pci_unmap_page(pAC->PciDev,
+					 PhysAddr,
+					 pAC->RxBufSize - 2,
+					 PCI_DMA_FROMDEVICE);
+			DEV_KFREE_SKB(pRxd->pMBuf);
+			pRxd->pMBuf = NULL;
+		}
+		pRxd->RBControl &= BMU_OWN;
+		pRxd = pRxd->pNextRxd;
+		pRxPort->RxdRingFree++;
+	} while (pRxd != pRxPort->pRxdRingTail);
+	pRxPort->pRxdRingTail = pRxPort->pRxdRingHead;
+	spin_unlock_irqrestore(&pRxPort->RxDesRingLock, Flags);
+} /* ClearRxRing */
+
+/*****************************************************************************
+ *
+ *	ClearTxRing - remove all buffers from the transmit ring
+ *
+ * Description:
+ *	This function removes all transmit buffers from the ring.
+ *	The transmit BMU must be stopped before calling this function
+ *	and transmitting at the upper level must be disabled.
+ *	The BMU own bit of all descriptors is cleared, the rest is
+ *	done by calling FreeTxDescriptors.
+ *
+ * Returns: N/A
+ */
+static void ClearTxRing(
+SK_AC	*pAC,		/* pointer to adapter context */
+TX_PORT	*pTxPort)	/* pointer to tx prt struct */
+{
+TXD		*pTxd;		/* pointer to the current descriptor */
+int		i;
+unsigned long	Flags;
+
+	spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
+	pTxd = pTxPort->pTxdRingHead;
+	for (i=0; i<pAC->TxDescrPerRing; i++) {
+		pTxd->TBControl &= ~BMU_OWN;
+		pTxd = pTxd->pNextTxd;
+	}
+	FreeTxDescriptors(pAC, pTxPort);
+	spin_unlock_irqrestore(&pTxPort->TxDesRingLock, Flags);
+} /* ClearTxRing */
+
+/*****************************************************************************
+ *
+ * 	SkGeSetMacAddr - Set the hardware MAC address
+ *
+ * Description:
+ *	This function sets the MAC address used by the adapter.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+static int SkGeSetMacAddr(struct SK_NET_DEVICE *dev, void *p)
+{
+
+DEV_NET *pNet = netdev_priv(dev);
+SK_AC	*pAC = pNet->pAC;
+
+struct sockaddr	*addr = p;
+unsigned long	Flags;
+	
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeSetMacAddr starts now...\n"));
+	if(netif_running(dev))
+		return -EBUSY;
+
+	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
+	
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+
+	if (pAC->RlmtNets == 2)
+		SkAddrOverride(pAC, pAC->IoBase, pNet->NetNr,
+			(SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS);
+	else
+		SkAddrOverride(pAC, pAC->IoBase, pAC->ActivePort,
+			(SK_MAC_ADDR*)dev->dev_addr, SK_ADDR_VIRTUAL_ADDRESS);
+
+	
+	
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	return 0;
+} /* SkGeSetMacAddr */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeSetRxMode - set receive mode
+ *
+ * Description:
+ *	This function sets the receive mode of an adapter. The adapter
+ *	supports promiscuous mode, allmulticast mode and a number of
+ *	multicast addresses. If more multicast addresses the available
+ *	are selected, a hash function in the hardware is used.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+static void SkGeSetRxMode(struct SK_NET_DEVICE *dev)
+{
+
+DEV_NET		*pNet;
+SK_AC		*pAC;
+
+struct dev_mc_list	*pMcList;
+int			i;
+int			PortIdx;
+unsigned long		Flags;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeSetRxMode starts now... "));
+
+	pNet = netdev_priv(dev);
+	pAC = pNet->pAC;
+	if (pAC->RlmtNets == 1)
+		PortIdx = pAC->ActivePort;
+	else
+		PortIdx = pNet->NetNr;
+
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	if (dev->flags & IFF_PROMISC) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+			("PROMISCUOUS mode\n"));
+		SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
+			SK_PROM_MODE_LLC);
+	} else if (dev->flags & IFF_ALLMULTI) {
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+			("ALLMULTI mode\n"));
+		SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
+			SK_PROM_MODE_ALL_MC);
+	} else {
+		SkAddrPromiscuousChange(pAC, pAC->IoBase, PortIdx,
+			SK_PROM_MODE_NONE);
+		SkAddrMcClear(pAC, pAC->IoBase, PortIdx, 0);
+
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+			("Number of MC entries: %d ", dev->mc_count));
+		
+		pMcList = dev->mc_list;
+		for (i=0; i<dev->mc_count; i++, pMcList = pMcList->next) {
+			SkAddrMcAdd(pAC, pAC->IoBase, PortIdx,
+				(SK_MAC_ADDR*)pMcList->dmi_addr, 0);
+			SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_MCA,
+				("%02x:%02x:%02x:%02x:%02x:%02x\n",
+				pMcList->dmi_addr[0],
+				pMcList->dmi_addr[1],
+				pMcList->dmi_addr[2],
+				pMcList->dmi_addr[3],
+				pMcList->dmi_addr[4],
+				pMcList->dmi_addr[5]));
+		}
+		SkAddrMcUpdate(pAC, pAC->IoBase, PortIdx);
+	}
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	
+	return;
+} /* SkGeSetRxMode */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeChangeMtu - set the MTU to another value
+ *
+ * Description:
+ *	This function sets is called whenever the MTU size is changed
+ *	(ifconfig mtu xxx dev ethX). If the MTU is bigger than standard
+ *	ethernet MTU size, long frame support is activated.
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+static int SkGeChangeMtu(struct SK_NET_DEVICE *dev, int NewMtu)
+{
+DEV_NET		*pNet;
+struct net_device *pOtherDev;
+SK_AC		*pAC;
+unsigned long	Flags;
+int		i;
+SK_EVPARA 	EvPara;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeChangeMtu starts now...\n"));
+
+	pNet = netdev_priv(dev);
+	pAC  = pNet->pAC;
+
+	if ((NewMtu < 68) || (NewMtu > SK_JUMBO_MTU)) {
+		return -EINVAL;
+	}
+
+	if(pAC->BoardLevel != SK_INIT_RUN) {
+		return -EINVAL;
+	}
+
+#ifdef SK_DIAG_SUPPORT
+	if (pAC->DiagModeActive == DIAG_ACTIVE) {
+		if (pAC->DiagFlowCtrl == SK_FALSE) {
+			return -1; /* still in use, deny any actions of MTU */
+		} else {
+			pAC->DiagFlowCtrl = SK_FALSE;
+		}
+	}
+#endif
+
+	pOtherDev = pAC->dev[1 - pNet->NetNr];
+
+	if ( netif_running(pOtherDev) && (pOtherDev->mtu > 1500)
+	     && (NewMtu <= 1500))
+		return 0;
+
+	pAC->RxBufSize = NewMtu + 32;
+	dev->mtu = NewMtu;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("New MTU: %d\n", NewMtu));
+
+	/* 
+	** Prevent any reconfiguration while changing the MTU 
+	** by disabling any interrupts 
+	*/
+	SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+
+	/* 
+	** Notify RLMT that any ports are to be stopped
+	*/
+	EvPara.Para32[0] =  0;
+	EvPara.Para32[1] = -1;
+	if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+		EvPara.Para32[0] =  1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+	} else {
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+	}
+
+	/*
+	** After calling the SkEventDispatcher(), RLMT is aware about
+	** the stopped ports -> configuration can take place!
+	*/
+	SkEventDispatcher(pAC, pAC->IoBase);
+
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		spin_lock(&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock);
+		netif_stop_queue(pAC->dev[i]);
+
+	}
+
+	/*
+	** Depending on the desired MTU size change, a different number of 
+	** RX buffers need to be allocated
+	*/
+	if (NewMtu > 1500) {
+	    /* 
+	    ** Use less rx buffers 
+	    */
+	    for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+		    pAC->RxPort[i].RxFillLimit =  pAC->RxDescrPerRing -
+						 (pAC->RxDescrPerRing / 4);
+		} else {
+		    if (i == pAC->ActivePort) {
+			pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - 
+						    (pAC->RxDescrPerRing / 4);
+		    } else {
+			pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing - 
+						    (pAC->RxDescrPerRing / 10);
+		    }
+		}
+	    }
+	} else {
+	    /* 
+	    ** Use the normal amount of rx buffers 
+	    */
+	    for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+		    pAC->RxPort[i].RxFillLimit = 1;
+		} else {
+		    if (i == pAC->ActivePort) {
+			pAC->RxPort[i].RxFillLimit = 1;
+		    } else {
+			pAC->RxPort[i].RxFillLimit = pAC->RxDescrPerRing -
+						    (pAC->RxDescrPerRing / 4);
+		    }
+		}
+	    }
+	}
+	
+	SkGeDeInit(pAC, pAC->IoBase);
+
+	/*
+	** enable/disable hardware support for long frames
+	*/
+	if (NewMtu > 1500) {
+// pAC->JumboActivated = SK_TRUE; /* is never set back !!! */
+		pAC->GIni.GIPortUsage = SK_JUMBO_LINK;
+	} else {
+	    if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+		pAC->GIni.GIPortUsage = SK_MUL_LINK;
+	    } else {
+		pAC->GIni.GIPortUsage = SK_RED_LINK;
+	    }
+	}
+
+	SkGeInit(   pAC, pAC->IoBase, SK_INIT_IO);
+	SkI2cInit(  pAC, pAC->IoBase, SK_INIT_IO);
+	SkEventInit(pAC, pAC->IoBase, SK_INIT_IO);
+	SkPnmiInit( pAC, pAC->IoBase, SK_INIT_IO);
+	SkAddrInit( pAC, pAC->IoBase, SK_INIT_IO);
+	SkRlmtInit( pAC, pAC->IoBase, SK_INIT_IO);
+	SkTimerInit(pAC, pAC->IoBase, SK_INIT_IO);
+	
+	/*
+	** tschilling:
+	** Speed and others are set back to default in level 1 init!
+	*/
+	GetConfiguration(pAC);
+	
+	SkGeInit(   pAC, pAC->IoBase, SK_INIT_RUN);
+	SkI2cInit(  pAC, pAC->IoBase, SK_INIT_RUN);
+	SkEventInit(pAC, pAC->IoBase, SK_INIT_RUN);
+	SkPnmiInit( pAC, pAC->IoBase, SK_INIT_RUN);
+	SkAddrInit( pAC, pAC->IoBase, SK_INIT_RUN);
+	SkRlmtInit( pAC, pAC->IoBase, SK_INIT_RUN);
+	SkTimerInit(pAC, pAC->IoBase, SK_INIT_RUN);
+
+	/*
+	** clear and reinit the rx rings here
+	*/
+	for (i=0; i<pAC->GIni.GIMacsFound; i++) {
+		ReceiveIrq(pAC, &pAC->RxPort[i], SK_TRUE);
+		ClearRxRing(pAC, &pAC->RxPort[i]);
+		FillRxRing(pAC, &pAC->RxPort[i]);
+
+		/* 
+		** Enable transmit descriptor polling
+		*/
+		SkGePollTxD(pAC, pAC->IoBase, i, SK_TRUE);
+		FillRxRing(pAC, &pAC->RxPort[i]);
+	};
+
+	SkGeYellowLED(pAC, pAC->IoBase, 1);
+	SkDimEnableModerationIfNeeded(pAC);	
+	SkDimDisplayModerationSettings(pAC);
+
+	netif_start_queue(pAC->dev[pNet->PortNr]);
+	for (i=pAC->GIni.GIMacsFound-1; i>=0; i--) {
+		spin_unlock(&pAC->TxPort[i][TX_PRIO_LOW].TxDesRingLock);
+	}
+
+	/* 
+	** Enable Interrupts again 
+	*/
+	SK_OUT32(pAC->IoBase, B0_IMSK, pAC->GIni.GIValIrqMask);
+	SK_OUT32(pAC->IoBase, B0_HWE_IMSK, IRQ_HWE_MASK);
+
+	SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+	SkEventDispatcher(pAC, pAC->IoBase);
+
+	/* 
+	** Notify RLMT about the changing and restarting one (or more) ports
+	*/
+	if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+		EvPara.Para32[0] = pAC->RlmtNets;
+		EvPara.Para32[1] = -1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_SET_NETS, EvPara);
+		EvPara.Para32[0] = pNet->PortNr;
+		EvPara.Para32[1] = -1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+			
+		if (netif_running(pOtherDev)) {
+			DEV_NET *pOtherNet = netdev_priv(pOtherDev);
+			EvPara.Para32[0] = pOtherNet->PortNr;
+			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+		}
+	} else {
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_START, EvPara);
+	}
+
+	SkEventDispatcher(pAC, pAC->IoBase);
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	
+	/*
+	** While testing this driver with latest kernel 2.5 (2.5.70), it 
+	** seems as if upper layers have a problem to handle a successful
+	** return value of '0'. If such a zero is returned, the complete 
+	** system hangs for several minutes (!), which is in acceptable.
+	**
+	** Currently it is not clear, what the exact reason for this problem
+	** is. The implemented workaround for 2.5 is to return the desired 
+	** new MTU size if all needed changes for the new MTU size where 
+	** performed. In kernels 2.2 and 2.4, a zero value is returned,
+	** which indicates the successful change of the mtu-size.
+	*/
+	return NewMtu;
+
+} /* SkGeChangeMtu */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeStats - return ethernet device statistics
+ *
+ * Description:
+ *	This function return statistic data about the ethernet device
+ *	to the operating system.
+ *
+ * Returns:
+ *	pointer to the statistic structure.
+ */
+static struct net_device_stats *SkGeStats(struct SK_NET_DEVICE *dev)
+{
+DEV_NET *pNet = netdev_priv(dev);
+SK_AC	*pAC = pNet->pAC;
+SK_PNMI_STRUCT_DATA *pPnmiStruct;       /* structure for all Pnmi-Data */
+SK_PNMI_STAT    *pPnmiStat;             /* pointer to virtual XMAC stat. data */
+SK_PNMI_CONF    *pPnmiConf;             /* pointer to virtual link config. */
+unsigned int    Size;                   /* size of pnmi struct */
+unsigned long	Flags;			/* for spin lock */
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeStats starts now...\n"));
+	pPnmiStruct = &pAC->PnmiStruct;
+
+#ifdef SK_DIAG_SUPPORT
+        if ((pAC->DiagModeActive == DIAG_NOTACTIVE) &&
+                (pAC->BoardLevel == SK_INIT_RUN)) {
+#endif
+        SK_MEMSET(pPnmiStruct, 0, sizeof(SK_PNMI_STRUCT_DATA));
+        spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+        Size = SK_PNMI_STRUCT_SIZE;
+		SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size, pNet->NetNr);
+        spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+#ifdef SK_DIAG_SUPPORT
+	}
+#endif
+
+        pPnmiStat = &pPnmiStruct->Stat[0];
+        pPnmiConf = &pPnmiStruct->Conf[0];
+
+	pAC->stats.rx_packets = (SK_U32) pPnmiStruct->RxDeliveredCts & 0xFFFFFFFF;
+	pAC->stats.tx_packets = (SK_U32) pPnmiStat->StatTxOkCts & 0xFFFFFFFF;
+	pAC->stats.rx_bytes = (SK_U32) pPnmiStruct->RxOctetsDeliveredCts;
+	pAC->stats.tx_bytes = (SK_U32) pPnmiStat->StatTxOctetsOkCts;
+	
+        if (dev->mtu <= 1500) {
+                pAC->stats.rx_errors = (SK_U32) pPnmiStruct->InErrorsCts & 0xFFFFFFFF;
+        } else {
+                pAC->stats.rx_errors = (SK_U32) ((pPnmiStruct->InErrorsCts -
+                        pPnmiStat->StatRxTooLongCts) & 0xFFFFFFFF);
+	}
+
+
+	if (pAC->GIni.GP[0].PhyType == SK_PHY_XMAC && pAC->HWRevision < 12)
+		pAC->stats.rx_errors = pAC->stats.rx_errors - pPnmiStat->StatRxShortsCts;
+
+	pAC->stats.tx_errors = (SK_U32) pPnmiStat->StatTxSingleCollisionCts & 0xFFFFFFFF;
+	pAC->stats.rx_dropped = (SK_U32) pPnmiStruct->RxNoBufCts & 0xFFFFFFFF;
+	pAC->stats.tx_dropped = (SK_U32) pPnmiStruct->TxNoBufCts & 0xFFFFFFFF;
+	pAC->stats.multicast = (SK_U32) pPnmiStat->StatRxMulticastOkCts & 0xFFFFFFFF;
+	pAC->stats.collisions = (SK_U32) pPnmiStat->StatTxSingleCollisionCts & 0xFFFFFFFF;
+
+	/* detailed rx_errors: */
+	pAC->stats.rx_length_errors = (SK_U32) pPnmiStat->StatRxRuntCts & 0xFFFFFFFF;
+	pAC->stats.rx_over_errors = (SK_U32) pPnmiStat->StatRxFifoOverflowCts & 0xFFFFFFFF;
+	pAC->stats.rx_crc_errors = (SK_U32) pPnmiStat->StatRxFcsCts & 0xFFFFFFFF;
+	pAC->stats.rx_frame_errors = (SK_U32) pPnmiStat->StatRxFramingCts & 0xFFFFFFFF;
+	pAC->stats.rx_fifo_errors = (SK_U32) pPnmiStat->StatRxFifoOverflowCts & 0xFFFFFFFF;
+	pAC->stats.rx_missed_errors = (SK_U32) pPnmiStat->StatRxMissedCts & 0xFFFFFFFF;
+
+	/* detailed tx_errors */
+	pAC->stats.tx_aborted_errors = (SK_U32) 0;
+	pAC->stats.tx_carrier_errors = (SK_U32) pPnmiStat->StatTxCarrierCts & 0xFFFFFFFF;
+	pAC->stats.tx_fifo_errors = (SK_U32) pPnmiStat->StatTxFifoUnderrunCts & 0xFFFFFFFF;
+	pAC->stats.tx_heartbeat_errors = (SK_U32) pPnmiStat->StatTxCarrierCts & 0xFFFFFFFF;
+	pAC->stats.tx_window_errors = (SK_U32) 0;
+
+	return(&pAC->stats);
+} /* SkGeStats */
+
+/*
+ * Basic MII register access
+ */
+static int SkGeMiiIoctl(struct net_device *dev,
+			struct mii_ioctl_data *data, int cmd)
+{
+	DEV_NET *pNet = netdev_priv(dev);
+	SK_AC *pAC = pNet->pAC;
+	SK_IOC IoC = pAC->IoBase;
+	int Port = pNet->PortNr;
+	SK_GEPORT *pPrt = &pAC->GIni.GP[Port];
+	unsigned long Flags;
+	int err = 0;
+	int reg = data->reg_num & 0x1f;
+	SK_U16 val = data->val_in;
+
+	if (!netif_running(dev))
+		return -ENODEV;	/* Phy still in reset */
+
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	switch(cmd) {
+	case SIOCGMIIPHY:
+		data->phy_id = pPrt->PhyAddr;
+
+		/* fallthru */
+	case SIOCGMIIREG:
+		if (pAC->GIni.GIGenesis)
+			SkXmPhyRead(pAC, IoC, Port, reg, &val);
+		else
+			SkGmPhyRead(pAC, IoC, Port, reg, &val);
+
+		data->val_out = val;
+		break;
+
+	case SIOCSMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			err = -EPERM;
+
+		else if (pAC->GIni.GIGenesis)
+			SkXmPhyWrite(pAC, IoC, Port, reg, val);
+		else
+			SkGmPhyWrite(pAC, IoC, Port, reg, val);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+	}
+        spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	return err;
+}
+
+
+/*****************************************************************************
+ *
+ * 	SkGeIoctl - IO-control function
+ *
+ * Description:
+ *	This function is called if an ioctl is issued on the device.
+ *	There are three subfunction for reading, writing and test-writing
+ *	the private MIB data structure (useful for SysKonnect-internal tools).
+ *
+ * Returns:
+ *	0, if everything is ok
+ *	!=0, on error
+ */
+static int SkGeIoctl(struct SK_NET_DEVICE *dev, struct ifreq *rq, int cmd)
+{
+DEV_NET		*pNet;
+SK_AC		*pAC;
+void		*pMemBuf;
+struct pci_dev  *pdev = NULL;
+SK_GE_IOCTL	Ioctl;
+unsigned int	Err = 0;
+int		Size = 0;
+int             Ret = 0;
+unsigned int	Length = 0;
+int		HeaderLength = sizeof(SK_U32) + sizeof(SK_U32);
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeIoctl starts now...\n"));
+
+	pNet = netdev_priv(dev);
+	pAC = pNet->pAC;
+	
+	if (cmd == SIOCGMIIPHY || cmd == SIOCSMIIREG || cmd == SIOCGMIIREG)
+	    return SkGeMiiIoctl(dev, if_mii(rq), cmd);
+
+	if(copy_from_user(&Ioctl, rq->ifr_data, sizeof(SK_GE_IOCTL))) {
+		return -EFAULT;
+	}
+
+	switch(cmd) {
+	case SK_IOCTL_SETMIB:
+	case SK_IOCTL_PRESETMIB:
+		if (!capable(CAP_NET_ADMIN)) return -EPERM;
+ 	case SK_IOCTL_GETMIB:
+		if(copy_from_user(&pAC->PnmiStruct, Ioctl.pData,
+			Ioctl.Len<sizeof(pAC->PnmiStruct)?
+			Ioctl.Len : sizeof(pAC->PnmiStruct))) {
+			return -EFAULT;
+		}
+		Size = SkGeIocMib(pNet, Ioctl.Len, cmd);
+		if(copy_to_user(Ioctl.pData, &pAC->PnmiStruct,
+			Ioctl.Len<Size? Ioctl.Len : Size)) {
+			return -EFAULT;
+		}
+		Ioctl.Len = Size;
+		if(copy_to_user(rq->ifr_data, &Ioctl, sizeof(SK_GE_IOCTL))) {
+			return -EFAULT;
+		}
+		break;
+	case SK_IOCTL_GEN:
+		if (Ioctl.Len < (sizeof(pAC->PnmiStruct) + HeaderLength)) {
+			Length = Ioctl.Len;
+		} else {
+			Length = sizeof(pAC->PnmiStruct) + HeaderLength;
+		}
+		if (NULL == (pMemBuf = kmalloc(Length, GFP_KERNEL))) {
+			return -ENOMEM;
+		}
+		if(copy_from_user(pMemBuf, Ioctl.pData, Length)) {
+			Err = -EFAULT;
+			goto fault_gen;
+		}
+		if ((Ret = SkPnmiGenIoctl(pAC, pAC->IoBase, pMemBuf, &Length, 0)) < 0) {
+			Err = -EFAULT;
+			goto fault_gen;
+		}
+		if(copy_to_user(Ioctl.pData, pMemBuf, Length) ) {
+			Err = -EFAULT;
+			goto fault_gen;
+		}
+		Ioctl.Len = Length;
+		if(copy_to_user(rq->ifr_data, &Ioctl, sizeof(SK_GE_IOCTL))) {
+			Err = -EFAULT;
+			goto fault_gen;
+		}
+fault_gen:
+		kfree(pMemBuf); /* cleanup everything */
+		break;
+#ifdef SK_DIAG_SUPPORT
+       case SK_IOCTL_DIAG:
+		if (!capable(CAP_NET_ADMIN)) return -EPERM;
+		if (Ioctl.Len < (sizeof(pAC->PnmiStruct) + HeaderLength)) {
+			Length = Ioctl.Len;
+		} else {
+			Length = sizeof(pAC->PnmiStruct) + HeaderLength;
+		}
+		if (NULL == (pMemBuf = kmalloc(Length, GFP_KERNEL))) {
+			return -ENOMEM;
+		}
+		if(copy_from_user(pMemBuf, Ioctl.pData, Length)) {
+			Err = -EFAULT;
+			goto fault_diag;
+		}
+		pdev = pAC->PciDev;
+		Length = 3 * sizeof(SK_U32);  /* Error, Bus and Device */
+		/* 
+		** While coding this new IOCTL interface, only a few lines of code
+		** are to to be added. Therefore no dedicated function has been 
+		** added. If more functionality is added, a separate function 
+		** should be used...
+		*/
+		* ((SK_U32 *)pMemBuf) = 0;
+		* ((SK_U32 *)pMemBuf + 1) = pdev->bus->number;
+		* ((SK_U32 *)pMemBuf + 2) = ParseDeviceNbrFromSlotName(pci_name(pdev));
+		if(copy_to_user(Ioctl.pData, pMemBuf, Length) ) {
+			Err = -EFAULT;
+			goto fault_diag;
+		}
+		Ioctl.Len = Length;
+		if(copy_to_user(rq->ifr_data, &Ioctl, sizeof(SK_GE_IOCTL))) {
+			Err = -EFAULT;
+			goto fault_diag;
+		}
+fault_diag:
+		kfree(pMemBuf); /* cleanup everything */
+		break;
+#endif
+	default:
+		Err = -EOPNOTSUPP;
+	}
+
+	return(Err);
+
+} /* SkGeIoctl */
+
+
+/*****************************************************************************
+ *
+ * 	SkGeIocMib - handle a GetMib, SetMib- or PresetMib-ioctl message
+ *
+ * Description:
+ *	This function reads/writes the MIB data using PNMI (Private Network
+ *	Management Interface).
+ *	The destination for the data must be provided with the
+ *	ioctl call and is given to the driver in the form of
+ *	a user space address.
+ *	Copying from the user-provided data area into kernel messages
+ *	and back is done by copy_from_user and copy_to_user calls in
+ *	SkGeIoctl.
+ *
+ * Returns:
+ *	returned size from PNMI call
+ */
+static int SkGeIocMib(
+DEV_NET		*pNet,	/* pointer to the adapter context */
+unsigned int	Size,	/* length of ioctl data */
+int		mode)	/* flag for set/preset */
+{
+unsigned long	Flags;	/* for spin lock */
+SK_AC		*pAC;
+
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("SkGeIocMib starts now...\n"));
+	pAC = pNet->pAC;
+	/* access MIB */
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	switch(mode) {
+	case SK_IOCTL_GETMIB:
+		SkPnmiGetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size,
+			pNet->NetNr);
+		break;
+	case SK_IOCTL_PRESETMIB:
+		SkPnmiPreSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size,
+			pNet->NetNr);
+		break;
+	case SK_IOCTL_SETMIB:
+		SkPnmiSetStruct(pAC, pAC->IoBase, &pAC->PnmiStruct, &Size,
+			pNet->NetNr);
+		break;
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
+		("MIB data access succeeded\n"));
+	return (Size);
+} /* SkGeIocMib */
+
+
+/*****************************************************************************
+ *
+ * 	GetConfiguration - read configuration information
+ *
+ * Description:
+ *	This function reads per-adapter configuration information from
+ *	the options provided on the command line.
+ *
+ * Returns:
+ *	none
+ */
+static void GetConfiguration(
+SK_AC	*pAC)	/* pointer to the adapter context structure */
+{
+SK_I32	Port;		/* preferred port */
+SK_BOOL	AutoSet;
+SK_BOOL DupSet;
+int	LinkSpeed          = SK_LSPEED_AUTO;	/* Link speed */
+int	AutoNeg            = 1;			/* autoneg off (0) or on (1) */
+int	DuplexCap          = 0;			/* 0=both,1=full,2=half */
+int	FlowCtrl           = SK_FLOW_MODE_SYM_OR_REM;	/* FlowControl  */
+int	MSMode             = SK_MS_MODE_AUTO;	/* master/slave mode    */
+
+SK_BOOL IsConTypeDefined   = SK_TRUE;
+SK_BOOL IsLinkSpeedDefined = SK_TRUE;
+SK_BOOL IsFlowCtrlDefined  = SK_TRUE;
+SK_BOOL IsRoleDefined      = SK_TRUE;
+SK_BOOL IsModeDefined      = SK_TRUE;
+/*
+ *	The two parameters AutoNeg. and DuplexCap. map to one configuration
+ *	parameter. The mapping is described by this table:
+ *	DuplexCap ->	|	both	|	full	|	half	|
+ *	AutoNeg		|		|		|		|
+ *	-----------------------------------------------------------------
+ *	Off		|    illegal	|	Full	|	Half	|
+ *	-----------------------------------------------------------------
+ *	On		|   AutoBoth	|   AutoFull	|   AutoHalf	|
+ *	-----------------------------------------------------------------
+ *	Sense		|   AutoSense	|   AutoSense	|   AutoSense	|
+ */
+int	Capabilities[3][3] =
+		{ {                -1, SK_LMODE_FULL     , SK_LMODE_HALF     },
+		  {SK_LMODE_AUTOBOTH , SK_LMODE_AUTOFULL , SK_LMODE_AUTOHALF },
+		  {SK_LMODE_AUTOSENSE, SK_LMODE_AUTOSENSE, SK_LMODE_AUTOSENSE} };
+
+#define DC_BOTH	0
+#define DC_FULL 1
+#define DC_HALF 2
+#define AN_OFF	0
+#define AN_ON	1
+#define AN_SENS	2
+#define M_CurrPort pAC->GIni.GP[Port]
+
+
+	/*
+	** Set the default values first for both ports!
+	*/
+	for (Port = 0; Port < SK_MAX_MACS; Port++) {
+		M_CurrPort.PLinkModeConf = Capabilities[AN_ON][DC_BOTH];
+		M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM;
+		M_CurrPort.PMSMode       = SK_MS_MODE_AUTO;
+		M_CurrPort.PLinkSpeed    = SK_LSPEED_AUTO;
+	}
+
+	/*
+	** Check merged parameter ConType. If it has not been used,
+	** verify any other parameter (e.g. AutoNeg) and use default values. 
+	**
+	** Stating both ConType and other lowlevel link parameters is also
+	** possible. If this is the case, the passed ConType-parameter is 
+	** overwritten by the lowlevel link parameter.
+	**
+	** The following settings are used for a merged ConType-parameter:
+	**
+	** ConType   DupCap   AutoNeg   FlowCtrl      Role      Speed
+	** -------   ------   -------   --------   ----------   -----
+	**  Auto      Both      On      SymOrRem      Auto       Auto
+	**  100FD     Full      Off       None      <ignored>    100
+	**  100HD     Half      Off       None      <ignored>    100
+	**  10FD      Full      Off       None      <ignored>    10
+	**  10HD      Half      Off       None      <ignored>    10
+	** 
+	** This ConType parameter is used for all ports of the adapter!
+	*/
+        if ( (ConType != NULL)                && 
+	     (pAC->Index < SK_MAX_CARD_PARAM) &&
+	     (ConType[pAC->Index] != NULL) ) {
+
+			/* Check chipset family */
+			if ((!pAC->ChipsetType) && 
+				(strcmp(ConType[pAC->Index],"Auto")!=0) &&
+				(strcmp(ConType[pAC->Index],"")!=0)) {
+				/* Set the speed parameter back */
+					printk("sk98lin: Illegal value \"%s\" " 
+							"for ConType."
+							" Using Auto.\n", 
+							ConType[pAC->Index]);
+
+					sprintf(ConType[pAC->Index], "Auto");	
+			}
+
+				if (strcmp(ConType[pAC->Index],"")==0) {
+			IsConTypeDefined = SK_FALSE; /* No ConType defined */
+				} else if (strcmp(ConType[pAC->Index],"Auto")==0) {
+		    for (Port = 0; Port < SK_MAX_MACS; Port++) {
+			M_CurrPort.PLinkModeConf = Capabilities[AN_ON][DC_BOTH];
+			M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_SYM_OR_REM;
+			M_CurrPort.PMSMode       = SK_MS_MODE_AUTO;
+			M_CurrPort.PLinkSpeed    = SK_LSPEED_AUTO;
+		    }
+                } else if (strcmp(ConType[pAC->Index],"100FD")==0) {
+		    for (Port = 0; Port < SK_MAX_MACS; Port++) {
+			M_CurrPort.PLinkModeConf = Capabilities[AN_OFF][DC_FULL];
+			M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_NONE;
+			M_CurrPort.PMSMode       = SK_MS_MODE_AUTO;
+			M_CurrPort.PLinkSpeed    = SK_LSPEED_100MBPS;
+		    }
+                } else if (strcmp(ConType[pAC->Index],"100HD")==0) {
+		    for (Port = 0; Port < SK_MAX_MACS; Port++) {
+			M_CurrPort.PLinkModeConf = Capabilities[AN_OFF][DC_HALF];
+			M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_NONE;
+			M_CurrPort.PMSMode       = SK_MS_MODE_AUTO;
+			M_CurrPort.PLinkSpeed    = SK_LSPEED_100MBPS;
+		    }
+                } else if (strcmp(ConType[pAC->Index],"10FD")==0) {
+		    for (Port = 0; Port < SK_MAX_MACS; Port++) {
+			M_CurrPort.PLinkModeConf = Capabilities[AN_OFF][DC_FULL];
+			M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_NONE;
+			M_CurrPort.PMSMode       = SK_MS_MODE_AUTO;
+			M_CurrPort.PLinkSpeed    = SK_LSPEED_10MBPS;
+		    }
+                } else if (strcmp(ConType[pAC->Index],"10HD")==0) {
+		    for (Port = 0; Port < SK_MAX_MACS; Port++) {
+			M_CurrPort.PLinkModeConf = Capabilities[AN_OFF][DC_HALF];
+			M_CurrPort.PFlowCtrlMode = SK_FLOW_MODE_NONE;
+			M_CurrPort.PMSMode       = SK_MS_MODE_AUTO;
+			M_CurrPort.PLinkSpeed    = SK_LSPEED_10MBPS;
+		    }
+                } else { 
+		    printk("sk98lin: Illegal value \"%s\" for ConType\n", 
+			ConType[pAC->Index]);
+		    IsConTypeDefined = SK_FALSE; /* Wrong ConType defined */
+		}
+        } else {
+	    IsConTypeDefined = SK_FALSE; /* No ConType defined */
+	}
+
+	/*
+	** Parse any parameter settings for port A:
+	** a) any LinkSpeed stated?
+	*/
+	if (Speed_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		Speed_A[pAC->Index] != NULL) {
+		if (strcmp(Speed_A[pAC->Index],"")==0) {
+		    IsLinkSpeedDefined = SK_FALSE;
+		} else if (strcmp(Speed_A[pAC->Index],"Auto")==0) {
+		    LinkSpeed = SK_LSPEED_AUTO;
+		} else if (strcmp(Speed_A[pAC->Index],"10")==0) {
+		    LinkSpeed = SK_LSPEED_10MBPS;
+		} else if (strcmp(Speed_A[pAC->Index],"100")==0) {
+		    LinkSpeed = SK_LSPEED_100MBPS;
+		} else if (strcmp(Speed_A[pAC->Index],"1000")==0) {
+		    LinkSpeed = SK_LSPEED_1000MBPS;
+		} else {
+		    printk("sk98lin: Illegal value \"%s\" for Speed_A\n",
+			Speed_A[pAC->Index]);
+		    IsLinkSpeedDefined = SK_FALSE;
+		}
+	} else {
+	    IsLinkSpeedDefined = SK_FALSE;
+	}
+
+	/* 
+	** Check speed parameter: 
+	**    Only copper type adapter and GE V2 cards 
+	*/
+	if (((!pAC->ChipsetType) || (pAC->GIni.GICopperType != SK_TRUE)) &&
+		((LinkSpeed != SK_LSPEED_AUTO) &&
+		(LinkSpeed != SK_LSPEED_1000MBPS))) {
+		printk("sk98lin: Illegal value for Speed_A. "
+			"Not a copper card or GE V2 card\n    Using "
+			"speed 1000\n");
+		LinkSpeed = SK_LSPEED_1000MBPS;
+	}
+	
+	/*	
+	** Decide whether to set new config value if somethig valid has
+	** been received.
+	*/
+	if (IsLinkSpeedDefined) {
+		pAC->GIni.GP[0].PLinkSpeed = LinkSpeed;
+	} 
+
+	/* 
+	** b) Any Autonegotiation and DuplexCapabilities set?
+	**    Please note that both belong together...
+	*/
+	AutoNeg = AN_ON; /* tschilling: Default: Autonegotiation on! */
+	AutoSet = SK_FALSE;
+	if (AutoNeg_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		AutoNeg_A[pAC->Index] != NULL) {
+		AutoSet = SK_TRUE;
+		if (strcmp(AutoNeg_A[pAC->Index],"")==0) {
+		    AutoSet = SK_FALSE;
+		} else if (strcmp(AutoNeg_A[pAC->Index],"On")==0) {
+		    AutoNeg = AN_ON;
+		} else if (strcmp(AutoNeg_A[pAC->Index],"Off")==0) {
+		    AutoNeg = AN_OFF;
+		} else if (strcmp(AutoNeg_A[pAC->Index],"Sense")==0) {
+		    AutoNeg = AN_SENS;
+		} else {
+		    printk("sk98lin: Illegal value \"%s\" for AutoNeg_A\n",
+			AutoNeg_A[pAC->Index]);
+		}
+	}
+
+	DuplexCap = DC_BOTH;
+	DupSet    = SK_FALSE;
+	if (DupCap_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		DupCap_A[pAC->Index] != NULL) {
+		DupSet = SK_TRUE;
+		if (strcmp(DupCap_A[pAC->Index],"")==0) {
+		    DupSet = SK_FALSE;
+		} else if (strcmp(DupCap_A[pAC->Index],"Both")==0) {
+		    DuplexCap = DC_BOTH;
+		} else if (strcmp(DupCap_A[pAC->Index],"Full")==0) {
+		    DuplexCap = DC_FULL;
+		} else if (strcmp(DupCap_A[pAC->Index],"Half")==0) {
+		    DuplexCap = DC_HALF;
+		} else {
+		    printk("sk98lin: Illegal value \"%s\" for DupCap_A\n",
+			DupCap_A[pAC->Index]);
+		}
+	}
+
+	/* 
+	** Check for illegal combinations 
+	*/
+	if ((LinkSpeed == SK_LSPEED_1000MBPS) &&
+		((DuplexCap == SK_LMODE_STAT_AUTOHALF) ||
+		(DuplexCap == SK_LMODE_STAT_HALF)) &&
+		(pAC->ChipsetType)) {
+		    printk("sk98lin: Half Duplex not possible with Gigabit speed!\n"
+					"    Using Full Duplex.\n");
+				DuplexCap = DC_FULL;
+	}
+
+	if ( AutoSet && AutoNeg==AN_SENS && DupSet) {
+		printk("sk98lin, Port A: DuplexCapabilities"
+			" ignored using Sense mode\n");
+	}
+
+	if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){
+		printk("sk98lin: Port A: Illegal combination"
+			" of values AutoNeg. and DuplexCap.\n    Using "
+			"Full Duplex\n");
+		DuplexCap = DC_FULL;
+	}
+
+	if (AutoSet && AutoNeg==AN_OFF && !DupSet) {
+		DuplexCap = DC_FULL;
+	}
+	
+	if (!AutoSet && DupSet) {
+		printk("sk98lin: Port A: Duplex setting not"
+			" possible in\n    default AutoNegotiation mode"
+			" (Sense).\n    Using AutoNegotiation On\n");
+		AutoNeg = AN_ON;
+	}
+	
+	/* 
+	** set the desired mode 
+	*/
+	if (AutoSet || DupSet) {
+	    pAC->GIni.GP[0].PLinkModeConf = Capabilities[AutoNeg][DuplexCap];
+	}
+	
+	/* 
+	** c) Any Flowcontrol-parameter set?
+	*/
+	if (FlowCtrl_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		FlowCtrl_A[pAC->Index] != NULL) {
+		if (strcmp(FlowCtrl_A[pAC->Index],"") == 0) {
+		    IsFlowCtrlDefined = SK_FALSE;
+		} else if (strcmp(FlowCtrl_A[pAC->Index],"SymOrRem") == 0) {
+		    FlowCtrl = SK_FLOW_MODE_SYM_OR_REM;
+		} else if (strcmp(FlowCtrl_A[pAC->Index],"Sym")==0) {
+		    FlowCtrl = SK_FLOW_MODE_SYMMETRIC;
+		} else if (strcmp(FlowCtrl_A[pAC->Index],"LocSend")==0) {
+		    FlowCtrl = SK_FLOW_MODE_LOC_SEND;
+		} else if (strcmp(FlowCtrl_A[pAC->Index],"None")==0) {
+		    FlowCtrl = SK_FLOW_MODE_NONE;
+		} else {
+		    printk("sk98lin: Illegal value \"%s\" for FlowCtrl_A\n",
+                        FlowCtrl_A[pAC->Index]);
+		    IsFlowCtrlDefined = SK_FALSE;
+		}
+	} else {
+	   IsFlowCtrlDefined = SK_FALSE;
+	}
+
+	if (IsFlowCtrlDefined) {
+	    if ((AutoNeg == AN_OFF) && (FlowCtrl != SK_FLOW_MODE_NONE)) {
+		printk("sk98lin: Port A: FlowControl"
+			" impossible without AutoNegotiation,"
+			" disabled\n");
+		FlowCtrl = SK_FLOW_MODE_NONE;
+	    }
+	    pAC->GIni.GP[0].PFlowCtrlMode = FlowCtrl;
+	}
+
+	/*
+	** d) What is with the RoleParameter?
+	*/
+	if (Role_A != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		Role_A[pAC->Index] != NULL) {
+		if (strcmp(Role_A[pAC->Index],"")==0) {
+		   IsRoleDefined = SK_FALSE;
+		} else if (strcmp(Role_A[pAC->Index],"Auto")==0) {
+		    MSMode = SK_MS_MODE_AUTO;
+		} else if (strcmp(Role_A[pAC->Index],"Master")==0) {
+		    MSMode = SK_MS_MODE_MASTER;
+		} else if (strcmp(Role_A[pAC->Index],"Slave")==0) {
+		    MSMode = SK_MS_MODE_SLAVE;
+		} else {
+		    printk("sk98lin: Illegal value \"%s\" for Role_A\n",
+			Role_A[pAC->Index]);
+		    IsRoleDefined = SK_FALSE;
+		}
+	} else {
+	   IsRoleDefined = SK_FALSE;
+	}
+
+	if (IsRoleDefined == SK_TRUE) {
+	    pAC->GIni.GP[0].PMSMode = MSMode;
+	}
+	
+
+	
+	/* 
+	** Parse any parameter settings for port B:
+	** a) any LinkSpeed stated?
+	*/
+	IsConTypeDefined   = SK_TRUE;
+	IsLinkSpeedDefined = SK_TRUE;
+	IsFlowCtrlDefined  = SK_TRUE;
+	IsModeDefined      = SK_TRUE;
+
+	if (Speed_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		Speed_B[pAC->Index] != NULL) {
+		if (strcmp(Speed_B[pAC->Index],"")==0) {
+		    IsLinkSpeedDefined = SK_FALSE;
+		} else if (strcmp(Speed_B[pAC->Index],"Auto")==0) {
+		    LinkSpeed = SK_LSPEED_AUTO;
+		} else if (strcmp(Speed_B[pAC->Index],"10")==0) {
+		    LinkSpeed = SK_LSPEED_10MBPS;
+		} else if (strcmp(Speed_B[pAC->Index],"100")==0) {
+		    LinkSpeed = SK_LSPEED_100MBPS;
+		} else if (strcmp(Speed_B[pAC->Index],"1000")==0) {
+		    LinkSpeed = SK_LSPEED_1000MBPS;
+		} else {
+		    printk("sk98lin: Illegal value \"%s\" for Speed_B\n",
+			Speed_B[pAC->Index]);
+		    IsLinkSpeedDefined = SK_FALSE;
+		}
+	} else {
+	    IsLinkSpeedDefined = SK_FALSE;
+	}
+
+	/* 
+	** Check speed parameter:
+	**    Only copper type adapter and GE V2 cards 
+	*/
+	if (((!pAC->ChipsetType) || (pAC->GIni.GICopperType != SK_TRUE)) &&
+		((LinkSpeed != SK_LSPEED_AUTO) &&
+		(LinkSpeed != SK_LSPEED_1000MBPS))) {
+		printk("sk98lin: Illegal value for Speed_B. "
+			"Not a copper card or GE V2 card\n    Using "
+			"speed 1000\n");
+		LinkSpeed = SK_LSPEED_1000MBPS;
+	}
+
+	/*      
+	** Decide whether to set new config value if somethig valid has
+	** been received.
+	*/
+        if (IsLinkSpeedDefined) {
+	    pAC->GIni.GP[1].PLinkSpeed = LinkSpeed;
+	}
+
+	/* 
+	** b) Any Autonegotiation and DuplexCapabilities set?
+	**    Please note that both belong together...
+	*/
+	AutoNeg = AN_SENS; /* default: do auto Sense */
+	AutoSet = SK_FALSE;
+	if (AutoNeg_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		AutoNeg_B[pAC->Index] != NULL) {
+		AutoSet = SK_TRUE;
+		if (strcmp(AutoNeg_B[pAC->Index],"")==0) {
+		    AutoSet = SK_FALSE;
+		} else if (strcmp(AutoNeg_B[pAC->Index],"On")==0) {
+		    AutoNeg = AN_ON;
+		} else if (strcmp(AutoNeg_B[pAC->Index],"Off")==0) {
+		    AutoNeg = AN_OFF;
+		} else if (strcmp(AutoNeg_B[pAC->Index],"Sense")==0) {
+		    AutoNeg = AN_SENS;
+		} else {
+		    printk("sk98lin: Illegal value \"%s\" for AutoNeg_B\n",
+			AutoNeg_B[pAC->Index]);
+		}
+	}
+
+	DuplexCap = DC_BOTH;
+	DupSet    = SK_FALSE;
+	if (DupCap_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		DupCap_B[pAC->Index] != NULL) {
+		DupSet = SK_TRUE;
+		if (strcmp(DupCap_B[pAC->Index],"")==0) {
+		    DupSet = SK_FALSE;
+		} else if (strcmp(DupCap_B[pAC->Index],"Both")==0) {
+		    DuplexCap = DC_BOTH;
+		} else if (strcmp(DupCap_B[pAC->Index],"Full")==0) {
+		    DuplexCap = DC_FULL;
+		} else if (strcmp(DupCap_B[pAC->Index],"Half")==0) {
+		    DuplexCap = DC_HALF;
+		} else {
+		    printk("sk98lin: Illegal value \"%s\" for DupCap_B\n",
+			DupCap_B[pAC->Index]);
+		}
+	}
+
+	
+	/* 
+	** Check for illegal combinations 
+	*/
+	if ((LinkSpeed == SK_LSPEED_1000MBPS) &&
+		((DuplexCap == SK_LMODE_STAT_AUTOHALF) ||
+		(DuplexCap == SK_LMODE_STAT_HALF)) &&
+		(pAC->ChipsetType)) {
+		    printk("sk98lin: Half Duplex not possible with Gigabit speed!\n"
+					"    Using Full Duplex.\n");
+				DuplexCap = DC_FULL;
+	}
+
+	if (AutoSet && AutoNeg==AN_SENS && DupSet) {
+		printk("sk98lin, Port B: DuplexCapabilities"
+			" ignored using Sense mode\n");
+	}
+
+	if (AutoSet && AutoNeg==AN_OFF && DupSet && DuplexCap==DC_BOTH){
+		printk("sk98lin: Port B: Illegal combination"
+			" of values AutoNeg. and DuplexCap.\n    Using "
+			"Full Duplex\n");
+		DuplexCap = DC_FULL;
+	}
+
+	if (AutoSet && AutoNeg==AN_OFF && !DupSet) {
+		DuplexCap = DC_FULL;
+	}
+	
+	if (!AutoSet && DupSet) {
+		printk("sk98lin: Port B: Duplex setting not"
+			" possible in\n    default AutoNegotiation mode"
+			" (Sense).\n    Using AutoNegotiation On\n");
+		AutoNeg = AN_ON;
+	}
+
+	/* 
+	** set the desired mode 
+	*/
+	if (AutoSet || DupSet) {
+	    pAC->GIni.GP[1].PLinkModeConf = Capabilities[AutoNeg][DuplexCap];
+	}
+
+	/*
+	** c) Any FlowCtrl parameter set?
+	*/
+	if (FlowCtrl_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		FlowCtrl_B[pAC->Index] != NULL) {
+		if (strcmp(FlowCtrl_B[pAC->Index],"") == 0) {
+		    IsFlowCtrlDefined = SK_FALSE;
+		} else if (strcmp(FlowCtrl_B[pAC->Index],"SymOrRem") == 0) {
+		    FlowCtrl = SK_FLOW_MODE_SYM_OR_REM;
+		} else if (strcmp(FlowCtrl_B[pAC->Index],"Sym")==0) {
+		    FlowCtrl = SK_FLOW_MODE_SYMMETRIC;
+		} else if (strcmp(FlowCtrl_B[pAC->Index],"LocSend")==0) {
+		    FlowCtrl = SK_FLOW_MODE_LOC_SEND;
+		} else if (strcmp(FlowCtrl_B[pAC->Index],"None")==0) {
+		    FlowCtrl = SK_FLOW_MODE_NONE;
+		} else {
+		    printk("sk98lin: Illegal value \"%s\" for FlowCtrl_B\n",
+			FlowCtrl_B[pAC->Index]);
+		    IsFlowCtrlDefined = SK_FALSE;
+		}
+	} else {
+		IsFlowCtrlDefined = SK_FALSE;
+	}
+
+	if (IsFlowCtrlDefined) {
+	    if ((AutoNeg == AN_OFF) && (FlowCtrl != SK_FLOW_MODE_NONE)) {
+		printk("sk98lin: Port B: FlowControl"
+			" impossible without AutoNegotiation,"
+			" disabled\n");
+		FlowCtrl = SK_FLOW_MODE_NONE;
+	    }
+	    pAC->GIni.GP[1].PFlowCtrlMode = FlowCtrl;
+	}
+
+	/*
+	** d) What is the RoleParameter?
+	*/
+	if (Role_B != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		Role_B[pAC->Index] != NULL) {
+		if (strcmp(Role_B[pAC->Index],"")==0) {
+		    IsRoleDefined = SK_FALSE;
+		} else if (strcmp(Role_B[pAC->Index],"Auto")==0) {
+		    MSMode = SK_MS_MODE_AUTO;
+		} else if (strcmp(Role_B[pAC->Index],"Master")==0) {
+		    MSMode = SK_MS_MODE_MASTER;
+		} else if (strcmp(Role_B[pAC->Index],"Slave")==0) {
+		    MSMode = SK_MS_MODE_SLAVE;
+		} else {
+		    printk("sk98lin: Illegal value \"%s\" for Role_B\n",
+			Role_B[pAC->Index]);
+		    IsRoleDefined = SK_FALSE;
+		}
+	} else {
+	    IsRoleDefined = SK_FALSE;
+	}
+
+	if (IsRoleDefined) {
+	    pAC->GIni.GP[1].PMSMode = MSMode;
+	}
+	
+	/*
+	** Evaluate settings for both ports
+	*/
+	pAC->ActivePort = 0;
+	if (PrefPort != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		PrefPort[pAC->Index] != NULL) {
+		if (strcmp(PrefPort[pAC->Index],"") == 0) { /* Auto */
+			pAC->ActivePort             =  0;
+			pAC->Rlmt.Net[0].Preference = -1; /* auto */
+			pAC->Rlmt.Net[0].PrefPort   =  0;
+		} else if (strcmp(PrefPort[pAC->Index],"A") == 0) {
+			/*
+			** do not set ActivePort here, thus a port
+			** switch is issued after net up.
+			*/
+			Port                        = 0;
+			pAC->Rlmt.Net[0].Preference = Port;
+			pAC->Rlmt.Net[0].PrefPort   = Port;
+		} else if (strcmp(PrefPort[pAC->Index],"B") == 0) {
+			/*
+			** do not set ActivePort here, thus a port
+			** switch is issued after net up.
+			*/
+			if (pAC->GIni.GIMacsFound == 1) {
+				printk("sk98lin: Illegal value \"B\" for PrefPort.\n"
+					"      Port B not available on single port adapters.\n");
+
+				pAC->ActivePort             =  0;
+				pAC->Rlmt.Net[0].Preference = -1; /* auto */
+				pAC->Rlmt.Net[0].PrefPort   =  0;
+			} else {
+				Port                        = 1;
+				pAC->Rlmt.Net[0].Preference = Port;
+				pAC->Rlmt.Net[0].PrefPort   = Port;
+			}
+		} else {
+		    printk("sk98lin: Illegal value \"%s\" for PrefPort\n",
+			PrefPort[pAC->Index]);
+		}
+	}
+
+	pAC->RlmtNets = 1;
+
+	if (RlmtMode != NULL && pAC->Index<SK_MAX_CARD_PARAM &&
+		RlmtMode[pAC->Index] != NULL) {
+		if (strcmp(RlmtMode[pAC->Index], "") == 0) {
+			pAC->RlmtMode = 0;
+		} else if (strcmp(RlmtMode[pAC->Index], "CheckLinkState") == 0) {
+			pAC->RlmtMode = SK_RLMT_CHECK_LINK;
+		} else if (strcmp(RlmtMode[pAC->Index], "CheckLocalPort") == 0) {
+			pAC->RlmtMode = SK_RLMT_CHECK_LINK |
+					SK_RLMT_CHECK_LOC_LINK;
+		} else if (strcmp(RlmtMode[pAC->Index], "CheckSeg") == 0) {
+			pAC->RlmtMode = SK_RLMT_CHECK_LINK     |
+					SK_RLMT_CHECK_LOC_LINK |
+					SK_RLMT_CHECK_SEG;
+		} else if ((strcmp(RlmtMode[pAC->Index], "DualNet") == 0) &&
+			(pAC->GIni.GIMacsFound == 2)) {
+			pAC->RlmtMode = SK_RLMT_CHECK_LINK;
+			pAC->RlmtNets = 2;
+		} else {
+		    printk("sk98lin: Illegal value \"%s\" for"
+			" RlmtMode, using default\n", 
+			RlmtMode[pAC->Index]);
+			pAC->RlmtMode = 0;
+		}
+	} else {
+		pAC->RlmtMode = 0;
+	}
+	
+	/*
+	** Check the interrupt moderation parameters
+	*/
+	if (Moderation[pAC->Index] != NULL) {
+		if (strcmp(Moderation[pAC->Index], "") == 0) {
+			pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE;
+		} else if (strcmp(Moderation[pAC->Index], "Static") == 0) {
+			pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_STATIC;
+		} else if (strcmp(Moderation[pAC->Index], "Dynamic") == 0) {
+			pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_DYNAMIC;
+		} else if (strcmp(Moderation[pAC->Index], "None") == 0) {
+			pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE;
+		} else {
+	   		printk("sk98lin: Illegal value \"%s\" for Moderation.\n"
+				"      Disable interrupt moderation.\n",
+				Moderation[pAC->Index]);
+			pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE;
+		}
+	} else {
+		pAC->DynIrqModInfo.IntModTypeSelect = C_INT_MOD_NONE;
+	}
+
+	if (Stats[pAC->Index] != NULL) {
+		if (strcmp(Stats[pAC->Index], "Yes") == 0) {
+			pAC->DynIrqModInfo.DisplayStats = SK_TRUE;
+		} else {
+			pAC->DynIrqModInfo.DisplayStats = SK_FALSE;
+		}
+	} else {
+		pAC->DynIrqModInfo.DisplayStats = SK_FALSE;
+	}
+
+	if (ModerationMask[pAC->Index] != NULL) {
+		if (strcmp(ModerationMask[pAC->Index], "Rx") == 0) {
+			pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_ONLY;
+		} else if (strcmp(ModerationMask[pAC->Index], "Tx") == 0) {
+			pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_ONLY;
+		} else if (strcmp(ModerationMask[pAC->Index], "Sp") == 0) {
+			pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_ONLY;
+		} else if (strcmp(ModerationMask[pAC->Index], "RxSp") == 0) {
+			pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_RX;
+		} else if (strcmp(ModerationMask[pAC->Index], "SpRx") == 0) {
+			pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_RX;
+		} else if (strcmp(ModerationMask[pAC->Index], "RxTx") == 0) {
+			pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX;
+		} else if (strcmp(ModerationMask[pAC->Index], "TxRx") == 0) {
+			pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX;
+		} else if (strcmp(ModerationMask[pAC->Index], "TxSp") == 0) {
+			pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_TX;
+		} else if (strcmp(ModerationMask[pAC->Index], "SpTx") == 0) {
+			pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_SP_TX;
+		} else if (strcmp(ModerationMask[pAC->Index], "RxTxSp") == 0) {
+			pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+		} else if (strcmp(ModerationMask[pAC->Index], "RxSpTx") == 0) {
+			pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+		} else if (strcmp(ModerationMask[pAC->Index], "TxRxSp") == 0) {
+			pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+		} else if (strcmp(ModerationMask[pAC->Index], "TxSpRx") == 0) {
+			pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+		} else if (strcmp(ModerationMask[pAC->Index], "SpTxRx") == 0) {
+			pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+		} else if (strcmp(ModerationMask[pAC->Index], "SpRxTx") == 0) {
+			pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_TX_SP;
+		} else { /* some rubbish */
+			pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_RX_ONLY;
+		}
+	} else {  /* operator has stated nothing */
+		pAC->DynIrqModInfo.MaskIrqModeration = IRQ_MASK_TX_RX;
+	}
+
+	if (AutoSizing[pAC->Index] != NULL) {
+		if (strcmp(AutoSizing[pAC->Index], "On") == 0) {
+			pAC->DynIrqModInfo.AutoSizing = SK_FALSE;
+		} else {
+			pAC->DynIrqModInfo.AutoSizing = SK_FALSE;
+		}
+	} else {  /* operator has stated nothing */
+		pAC->DynIrqModInfo.AutoSizing = SK_FALSE;
+	}
+
+	if (IntsPerSec[pAC->Index] != 0) {
+		if ((IntsPerSec[pAC->Index]< C_INT_MOD_IPS_LOWER_RANGE) || 
+			(IntsPerSec[pAC->Index] > C_INT_MOD_IPS_UPPER_RANGE)) {
+	   		printk("sk98lin: Illegal value \"%d\" for IntsPerSec. (Range: %d - %d)\n"
+				"      Using default value of %i.\n", 
+				IntsPerSec[pAC->Index],
+				C_INT_MOD_IPS_LOWER_RANGE,
+				C_INT_MOD_IPS_UPPER_RANGE,
+				C_INTS_PER_SEC_DEFAULT);
+			pAC->DynIrqModInfo.MaxModIntsPerSec = C_INTS_PER_SEC_DEFAULT;
+		} else {
+			pAC->DynIrqModInfo.MaxModIntsPerSec = IntsPerSec[pAC->Index];
+		}
+	} else {
+		pAC->DynIrqModInfo.MaxModIntsPerSec = C_INTS_PER_SEC_DEFAULT;
+	}
+
+	/*
+	** Evaluate upper and lower moderation threshold
+	*/
+	pAC->DynIrqModInfo.MaxModIntsPerSecUpperLimit =
+		pAC->DynIrqModInfo.MaxModIntsPerSec +
+		(pAC->DynIrqModInfo.MaxModIntsPerSec / 2);
+
+	pAC->DynIrqModInfo.MaxModIntsPerSecLowerLimit =
+		pAC->DynIrqModInfo.MaxModIntsPerSec -
+		(pAC->DynIrqModInfo.MaxModIntsPerSec / 2);
+
+	pAC->DynIrqModInfo.PrevTimeVal = jiffies;  /* initial value */
+
+
+} /* GetConfiguration */
+
+
+/*****************************************************************************
+ *
+ * 	ProductStr - return a adapter identification string from vpd
+ *
+ * Description:
+ *	This function reads the product name string from the vpd area
+ *	and puts it the field pAC->DeviceString.
+ *
+ * Returns: N/A
+ */
+static inline int ProductStr(
+	SK_AC	*pAC,		/* pointer to adapter context */
+	char    *DeviceStr,	/* result string */
+	int      StrLen		/* length of the string */
+)
+{
+char	Keyword[] = VPD_NAME;	/* vpd productname identifier */
+int	ReturnCode;		/* return code from vpd_read */
+unsigned long Flags;
+
+	spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+	ReturnCode = VpdRead(pAC, pAC->IoBase, Keyword, DeviceStr, &StrLen);
+	spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+
+	return ReturnCode;
+} /* ProductStr */
+
+/*****************************************************************************
+ *
+ *      StartDrvCleanupTimer - Start timer to check for descriptors which
+ *                             might be placed in descriptor ring, but
+ *                             havent been handled up to now
+ *
+ * Description:
+ *      This function requests a HW-timer fo the Yukon card. The actions to
+ *      perform when this timer expires, are located in the SkDrvEvent().
+ *
+ * Returns: N/A
+ */
+static void
+StartDrvCleanupTimer(SK_AC *pAC) {
+    SK_EVPARA    EventParam;   /* Event struct for timer event */
+
+    SK_MEMSET((char *) &EventParam, 0, sizeof(EventParam));
+    EventParam.Para32[0] = SK_DRV_RX_CLEANUP_TIMER;
+    SkTimerStart(pAC, pAC->IoBase, &pAC->DrvCleanupTimer,
+                 SK_DRV_RX_CLEANUP_TIMER_LENGTH,
+                 SKGE_DRV, SK_DRV_TIMER, EventParam);
+}
+
+/*****************************************************************************
+ *
+ *      StopDrvCleanupTimer - Stop timer to check for descriptors
+ *
+ * Description:
+ *      This function requests a HW-timer fo the Yukon card. The actions to
+ *      perform when this timer expires, are located in the SkDrvEvent().
+ *
+ * Returns: N/A
+ */
+static void
+StopDrvCleanupTimer(SK_AC *pAC) {
+    SkTimerStop(pAC, pAC->IoBase, &pAC->DrvCleanupTimer);
+    SK_MEMSET((char *) &pAC->DrvCleanupTimer, 0, sizeof(SK_TIMER));
+}
+
+/****************************************************************************/
+/* functions for common modules *********************************************/
+/****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ *	SkDrvAllocRlmtMbuf - allocate an RLMT mbuf
+ *
+ * Description:
+ *	This routine returns an RLMT mbuf or NULL. The RLMT Mbuf structure
+ *	is embedded into a socket buff data area.
+ *
+ * Context:
+ *	runtime
+ *
+ * Returns:
+ *	NULL or pointer to Mbuf.
+ */
+SK_MBUF *SkDrvAllocRlmtMbuf(
+SK_AC		*pAC,		/* pointer to adapter context */
+SK_IOC		IoC,		/* the IO-context */
+unsigned	BufferSize)	/* size of the requested buffer */
+{
+SK_MBUF		*pRlmtMbuf;	/* pointer to a new rlmt-mbuf structure */
+struct sk_buff	*pMsgBlock;	/* pointer to a new message block */
+
+	pMsgBlock = alloc_skb(BufferSize + sizeof(SK_MBUF), GFP_ATOMIC);
+	if (pMsgBlock == NULL) {
+		return (NULL);
+	}
+	pRlmtMbuf = (SK_MBUF*) pMsgBlock->data;
+	skb_reserve(pMsgBlock, sizeof(SK_MBUF));
+	pRlmtMbuf->pNext = NULL;
+	pRlmtMbuf->pOs = pMsgBlock;
+	pRlmtMbuf->pData = pMsgBlock->data;	/* Data buffer. */
+	pRlmtMbuf->Size = BufferSize;		/* Data buffer size. */
+	pRlmtMbuf->Length = 0;		/* Length of packet (<= Size). */
+	return (pRlmtMbuf);
+
+} /* SkDrvAllocRlmtMbuf */
+
+
+/*****************************************************************************
+ *
+ *	SkDrvFreeRlmtMbuf - free an RLMT mbuf
+ *
+ * Description:
+ *	This routine frees one or more RLMT mbuf(s).
+ *
+ * Context:
+ *	runtime
+ *
+ * Returns:
+ *	Nothing
+ */
+void  SkDrvFreeRlmtMbuf(
+SK_AC		*pAC,		/* pointer to adapter context */
+SK_IOC		IoC,		/* the IO-context */
+SK_MBUF		*pMbuf)		/* size of the requested buffer */
+{
+SK_MBUF		*pFreeMbuf;
+SK_MBUF		*pNextMbuf;
+
+	pFreeMbuf = pMbuf;
+	do {
+		pNextMbuf = pFreeMbuf->pNext;
+		DEV_KFREE_SKB_ANY(pFreeMbuf->pOs);
+		pFreeMbuf = pNextMbuf;
+	} while ( pFreeMbuf != NULL );
+} /* SkDrvFreeRlmtMbuf */
+
+
+/*****************************************************************************
+ *
+ *	SkOsGetTime - provide a time value
+ *
+ * Description:
+ *	This routine provides a time value. The unit is 1/HZ (defined by Linux).
+ *	It is not used for absolute time, but only for time differences.
+ *
+ *
+ * Returns:
+ *	Time value
+ */
+SK_U64 SkOsGetTime(SK_AC *pAC)
+{
+	SK_U64	PrivateJiffies;
+	SkOsGetTimeCurrent(pAC, &PrivateJiffies);
+	return PrivateJiffies;
+} /* SkOsGetTime */
+
+
+/*****************************************************************************
+ *
+ *	SkPciReadCfgDWord - read a 32 bit value from pci config space
+ *
+ * Description:
+ *	This routine reads a 32 bit value from the pci configuration
+ *	space.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+int SkPciReadCfgDWord(
+SK_AC *pAC,		/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U32 *pVal)		/* pointer to store the read value */
+{
+	pci_read_config_dword(pAC->PciDev, PciAddr, pVal);
+	return(0);
+} /* SkPciReadCfgDWord */
+
+
+/*****************************************************************************
+ *
+ *	SkPciReadCfgWord - read a 16 bit value from pci config space
+ *
+ * Description:
+ *	This routine reads a 16 bit value from the pci configuration
+ *	space.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+int SkPciReadCfgWord(
+SK_AC *pAC,	/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U16 *pVal)		/* pointer to store the read value */
+{
+	pci_read_config_word(pAC->PciDev, PciAddr, pVal);
+	return(0);
+} /* SkPciReadCfgWord */
+
+
+/*****************************************************************************
+ *
+ *	SkPciReadCfgByte - read a 8 bit value from pci config space
+ *
+ * Description:
+ *	This routine reads a 8 bit value from the pci configuration
+ *	space.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+int SkPciReadCfgByte(
+SK_AC *pAC,	/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U8 *pVal)		/* pointer to store the read value */
+{
+	pci_read_config_byte(pAC->PciDev, PciAddr, pVal);
+	return(0);
+} /* SkPciReadCfgByte */
+
+
+/*****************************************************************************
+ *
+ *	SkPciWriteCfgWord - write a 16 bit value to pci config space
+ *
+ * Description:
+ *	This routine writes a 16 bit value to the pci configuration
+ *	space. The flag PciConfigUp indicates whether the config space
+ *	is accesible or must be set up first.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+int SkPciWriteCfgWord(
+SK_AC *pAC,	/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U16 Val)		/* pointer to store the read value */
+{
+	pci_write_config_word(pAC->PciDev, PciAddr, Val);
+	return(0);
+} /* SkPciWriteCfgWord */
+
+
+/*****************************************************************************
+ *
+ *	SkPciWriteCfgWord - write a 8 bit value to pci config space
+ *
+ * Description:
+ *	This routine writes a 8 bit value to the pci configuration
+ *	space. The flag PciConfigUp indicates whether the config space
+ *	is accesible or must be set up first.
+ *
+ * Returns:
+ *	0 - indicate everything worked ok.
+ *	!= 0 - error indication
+ */
+int SkPciWriteCfgByte(
+SK_AC *pAC,	/* Adapter Control structure pointer */
+int PciAddr,		/* PCI register address */
+SK_U8 Val)		/* pointer to store the read value */
+{
+	pci_write_config_byte(pAC->PciDev, PciAddr, Val);
+	return(0);
+} /* SkPciWriteCfgByte */
+
+
+/*****************************************************************************
+ *
+ *	SkDrvEvent - handle driver events
+ *
+ * Description:
+ *	This function handles events from all modules directed to the driver
+ *
+ * Context:
+ *	Is called under protection of slow path lock.
+ *
+ * Returns:
+ *	0 if everything ok
+ *	< 0  on error
+ *	
+ */
+int SkDrvEvent(
+SK_AC *pAC,		/* pointer to adapter context */
+SK_IOC IoC,		/* io-context */
+SK_U32 Event,		/* event-id */
+SK_EVPARA Param)	/* event-parameter */
+{
+SK_MBUF		*pRlmtMbuf;	/* pointer to a rlmt-mbuf structure */
+struct sk_buff	*pMsg;		/* pointer to a message block */
+int		FromPort;	/* the port from which we switch away */
+int		ToPort;		/* the port we switch to */
+SK_EVPARA	NewPara;	/* parameter for further events */
+int		Stat;
+unsigned long	Flags;
+SK_BOOL		DualNet;
+
+	switch (Event) {
+	case SK_DRV_ADAP_FAIL:
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("ADAPTER FAIL EVENT\n"));
+		printk("%s: Adapter failed.\n", pAC->dev[0]->name);
+		/* disable interrupts */
+		SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+		/* cgoos */
+		break;
+	case SK_DRV_PORT_FAIL:
+		FromPort = Param.Para32[0];
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("PORT FAIL EVENT, Port: %d\n", FromPort));
+		if (FromPort == 0) {
+			printk("%s: Port A failed.\n", pAC->dev[0]->name);
+		} else {
+			printk("%s: Port B failed.\n", pAC->dev[1]->name);
+		}
+		/* cgoos */
+		break;
+	case SK_DRV_PORT_RESET:	 /* SK_U32 PortIdx */
+		/* action list 4 */
+		FromPort = Param.Para32[0];
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("PORT RESET EVENT, Port: %d ", FromPort));
+		NewPara.Para64 = FromPort;
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara);
+		spin_lock_irqsave(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+
+		SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_HARD_RST);
+		netif_carrier_off(pAC->dev[Param.Para32[0]]);
+		spin_unlock_irqrestore(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+		
+		/* clear rx ring from received frames */
+		ReceiveIrq(pAC, &pAC->RxPort[FromPort], SK_FALSE);
+		
+		ClearTxRing(pAC, &pAC->TxPort[FromPort][TX_PRIO_LOW]);
+		spin_lock_irqsave(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+		
+		/* tschilling: Handling of return value inserted. */
+		if (SkGeInitPort(pAC, IoC, FromPort)) {
+			if (FromPort == 0) {
+				printk("%s: SkGeInitPort A failed.\n", pAC->dev[0]->name);
+			} else {
+				printk("%s: SkGeInitPort B failed.\n", pAC->dev[1]->name);
+			}
+		}
+		SkAddrMcUpdate(pAC,IoC, FromPort);
+		PortReInitBmu(pAC, FromPort);
+		SkGePollTxD(pAC, IoC, FromPort, SK_TRUE);
+		ClearAndStartRx(pAC, FromPort);
+		spin_unlock_irqrestore(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+		break;
+	case SK_DRV_NET_UP:	 /* SK_U32 PortIdx */
+	{	struct net_device *dev = pAC->dev[Param.Para32[0]];
+		/* action list 5 */
+		FromPort = Param.Para32[0];
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("NET UP EVENT, Port: %d ", Param.Para32[0]));
+		/* Mac update */
+		SkAddrMcUpdate(pAC,IoC, FromPort);
+
+		if (DoPrintInterfaceChange) {
+		printk("%s: network connection up using"
+			" port %c\n", pAC->dev[Param.Para32[0]]->name, 'A'+Param.Para32[0]);
+
+		/* tschilling: Values changed according to LinkSpeedUsed. */
+		Stat = pAC->GIni.GP[FromPort].PLinkSpeedUsed;
+		if (Stat == SK_LSPEED_STAT_10MBPS) {
+			printk("    speed:           10\n");
+		} else if (Stat == SK_LSPEED_STAT_100MBPS) {
+			printk("    speed:           100\n");
+		} else if (Stat == SK_LSPEED_STAT_1000MBPS) {
+			printk("    speed:           1000\n");
+		} else {
+			printk("    speed:           unknown\n");
+		}
+
+
+		Stat = pAC->GIni.GP[FromPort].PLinkModeStatus;
+		if (Stat == SK_LMODE_STAT_AUTOHALF ||
+			Stat == SK_LMODE_STAT_AUTOFULL) {
+			printk("    autonegotiation: yes\n");
+		}
+		else {
+			printk("    autonegotiation: no\n");
+		}
+		if (Stat == SK_LMODE_STAT_AUTOHALF ||
+			Stat == SK_LMODE_STAT_HALF) {
+			printk("    duplex mode:     half\n");
+		}
+		else {
+			printk("    duplex mode:     full\n");
+		}
+		Stat = pAC->GIni.GP[FromPort].PFlowCtrlStatus;
+		if (Stat == SK_FLOW_STAT_REM_SEND ) {
+			printk("    flowctrl:        remote send\n");
+		}
+		else if (Stat == SK_FLOW_STAT_LOC_SEND ){
+			printk("    flowctrl:        local send\n");
+		}
+		else if (Stat == SK_FLOW_STAT_SYMMETRIC ){
+			printk("    flowctrl:        symmetric\n");
+		}
+		else {
+			printk("    flowctrl:        none\n");
+		}
+		
+		/* tschilling: Check against CopperType now. */
+		if ((pAC->GIni.GICopperType == SK_TRUE) &&
+			(pAC->GIni.GP[FromPort].PLinkSpeedUsed ==
+			SK_LSPEED_STAT_1000MBPS)) {
+			Stat = pAC->GIni.GP[FromPort].PMSStatus;
+			if (Stat == SK_MS_STAT_MASTER ) {
+				printk("    role:            master\n");
+			}
+			else if (Stat == SK_MS_STAT_SLAVE ) {
+				printk("    role:            slave\n");
+			}
+			else {
+				printk("    role:            ???\n");
+			}
+		}
+
+		/* 
+		   Display dim (dynamic interrupt moderation) 
+		   informations
+		 */
+		if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_STATIC)
+			printk("    irq moderation:  static (%d ints/sec)\n",
+					pAC->DynIrqModInfo.MaxModIntsPerSec);
+		else if (pAC->DynIrqModInfo.IntModTypeSelect == C_INT_MOD_DYNAMIC)
+			printk("    irq moderation:  dynamic (%d ints/sec)\n",
+					pAC->DynIrqModInfo.MaxModIntsPerSec);
+		else
+			printk("    irq moderation:  disabled\n");
+
+
+		printk("    scatter-gather:  %s\n",
+		       (dev->features & NETIF_F_SG) ? "enabled" : "disabled");
+		printk("    tx-checksum:     %s\n",
+		       (dev->features & NETIF_F_IP_CSUM) ? "enabled" : "disabled");
+		printk("    rx-checksum:     %s\n",
+		       pAC->RxPort[Param.Para32[0]].RxCsum ? "enabled" : "disabled");
+
+		} else {
+                        DoPrintInterfaceChange = SK_TRUE;
+                }
+	
+		if ((Param.Para32[0] != pAC->ActivePort) &&
+			(pAC->RlmtNets == 1)) {
+			NewPara.Para32[0] = pAC->ActivePort;
+			NewPara.Para32[1] = Param.Para32[0];
+			SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_INTERN,
+				NewPara);
+		}
+
+		/* Inform the world that link protocol is up. */
+		netif_carrier_on(dev);
+		break;
+	}
+	case SK_DRV_NET_DOWN:	 /* SK_U32 Reason */
+		/* action list 7 */
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("NET DOWN EVENT "));
+		if (DoPrintInterfaceChange) {
+			printk("%s: network connection down\n", 
+				pAC->dev[Param.Para32[1]]->name);
+		} else {
+			DoPrintInterfaceChange = SK_TRUE;
+		}
+		netif_carrier_off(pAC->dev[Param.Para32[1]]);
+		break;
+	case SK_DRV_SWITCH_HARD: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("PORT SWITCH HARD "));
+	case SK_DRV_SWITCH_SOFT: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
+	/* action list 6 */
+		printk("%s: switching to port %c\n", pAC->dev[0]->name,
+			'A'+Param.Para32[1]);
+	case SK_DRV_SWITCH_INTERN: /* SK_U32 FromPortIdx SK_U32 ToPortIdx */
+		FromPort = Param.Para32[0];
+		ToPort = Param.Para32[1];
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("PORT SWITCH EVENT, From: %d  To: %d (Pref %d) ",
+			FromPort, ToPort, pAC->Rlmt.Net[0].PrefPort));
+		NewPara.Para64 = FromPort;
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara);
+		NewPara.Para64 = ToPort;
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_XMAC_RESET, NewPara);
+		spin_lock_irqsave(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+		spin_lock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock);
+		SkGeStopPort(pAC, IoC, FromPort, SK_STOP_ALL, SK_SOFT_RST);
+		SkGeStopPort(pAC, IoC, ToPort, SK_STOP_ALL, SK_SOFT_RST);
+		spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock);
+		spin_unlock_irqrestore(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+
+		ReceiveIrq(pAC, &pAC->RxPort[FromPort], SK_FALSE); /* clears rx ring */
+		ReceiveIrq(pAC, &pAC->RxPort[ToPort], SK_FALSE); /* clears rx ring */
+		
+		ClearTxRing(pAC, &pAC->TxPort[FromPort][TX_PRIO_LOW]);
+		ClearTxRing(pAC, &pAC->TxPort[ToPort][TX_PRIO_LOW]);
+		spin_lock_irqsave(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+		spin_lock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock);
+		pAC->ActivePort = ToPort;
+#if 0
+		SetQueueSizes(pAC);
+#else
+		/* tschilling: New common function with minimum size check. */
+		DualNet = SK_FALSE;
+		if (pAC->RlmtNets == 2) {
+			DualNet = SK_TRUE;
+		}
+		
+		if (SkGeInitAssignRamToQueues(
+			pAC,
+			pAC->ActivePort,
+			DualNet)) {
+			spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock);
+			spin_unlock_irqrestore(
+				&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+				Flags);
+			printk("SkGeInitAssignRamToQueues failed.\n");
+			break;
+		}
+#endif
+		/* tschilling: Handling of return values inserted. */
+		if (SkGeInitPort(pAC, IoC, FromPort) ||
+			SkGeInitPort(pAC, IoC, ToPort)) {
+			printk("%s: SkGeInitPort failed.\n", pAC->dev[0]->name);
+		}
+		if (Event == SK_DRV_SWITCH_SOFT) {
+			SkMacRxTxEnable(pAC, IoC, FromPort);
+		}
+		SkMacRxTxEnable(pAC, IoC, ToPort);
+		SkAddrSwap(pAC, IoC, FromPort, ToPort);
+		SkAddrMcUpdate(pAC, IoC, FromPort);
+		SkAddrMcUpdate(pAC, IoC, ToPort);
+		PortReInitBmu(pAC, FromPort);
+		PortReInitBmu(pAC, ToPort);
+		SkGePollTxD(pAC, IoC, FromPort, SK_TRUE);
+		SkGePollTxD(pAC, IoC, ToPort, SK_TRUE);
+		ClearAndStartRx(pAC, FromPort);
+		ClearAndStartRx(pAC, ToPort);
+		spin_unlock(&pAC->TxPort[ToPort][TX_PRIO_LOW].TxDesRingLock);
+		spin_unlock_irqrestore(
+			&pAC->TxPort[FromPort][TX_PRIO_LOW].TxDesRingLock,
+			Flags);
+		break;
+	case SK_DRV_RLMT_SEND:	 /* SK_MBUF *pMb */
+		SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+			("RLS "));
+		pRlmtMbuf = (SK_MBUF*) Param.pParaPtr;
+		pMsg = (struct sk_buff*) pRlmtMbuf->pOs;
+		skb_put(pMsg, pRlmtMbuf->Length);
+		if (XmitFrame(pAC, &pAC->TxPort[pRlmtMbuf->PortIdx][TX_PRIO_LOW],
+			pMsg) < 0)
+
+			DEV_KFREE_SKB_ANY(pMsg);
+		break;
+	case SK_DRV_TIMER:
+		if (Param.Para32[0] == SK_DRV_MODERATION_TIMER) {
+			/*
+			** expiration of the moderation timer implies that
+			** dynamic moderation is to be applied
+			*/
+			SkDimStartModerationTimer(pAC);
+			SkDimModerate(pAC);
+                        if (pAC->DynIrqModInfo.DisplayStats) {
+			    SkDimDisplayModerationSettings(pAC);
+                        }
+                } else if (Param.Para32[0] == SK_DRV_RX_CLEANUP_TIMER) {
+			/*
+			** check if we need to check for descriptors which
+			** haven't been handled the last millisecs
+			*/
+			StartDrvCleanupTimer(pAC);
+			if (pAC->GIni.GIMacsFound == 2) {
+				ReceiveIrq(pAC, &pAC->RxPort[1], SK_FALSE);
+			}
+			ReceiveIrq(pAC, &pAC->RxPort[0], SK_FALSE);
+		} else {
+			printk("Expiration of unknown timer\n");
+		}
+		break;
+	default:
+		break;
+	}
+	SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_EVENT,
+		("END EVENT "));
+	
+	return (0);
+} /* SkDrvEvent */
+
+
+/*****************************************************************************
+ *
+ *	SkErrorLog - log errors
+ *
+ * Description:
+ *	This function logs errors to the system buffer and to the console
+ *
+ * Returns:
+ *	0 if everything ok
+ *	< 0  on error
+ *	
+ */
+void SkErrorLog(
+SK_AC	*pAC,
+int	ErrClass,
+int	ErrNum,
+char	*pErrorMsg)
+{
+char	ClassStr[80];
+
+	switch (ErrClass) {
+	case SK_ERRCL_OTHER:
+		strcpy(ClassStr, "Other error");
+		break;
+	case SK_ERRCL_CONFIG:
+		strcpy(ClassStr, "Configuration error");
+		break;
+	case SK_ERRCL_INIT:
+		strcpy(ClassStr, "Initialization error");
+		break;
+	case SK_ERRCL_NORES:
+		strcpy(ClassStr, "Out of resources error");
+		break;
+	case SK_ERRCL_SW:
+		strcpy(ClassStr, "internal Software error");
+		break;
+	case SK_ERRCL_HW:
+		strcpy(ClassStr, "Hardware failure");
+		break;
+	case SK_ERRCL_COMM:
+		strcpy(ClassStr, "Communication error");
+		break;
+	}
+	printk(KERN_INFO "%s: -- ERROR --\n        Class:  %s\n"
+		"        Nr:  0x%x\n        Msg:  %s\n", pAC->dev[0]->name,
+		ClassStr, ErrNum, pErrorMsg);
+
+} /* SkErrorLog */
+
+#ifdef SK_DIAG_SUPPORT
+
+/*****************************************************************************
+ *
+ *	SkDrvEnterDiagMode - handles DIAG attach request
+ *
+ * Description:
+ *	Notify the kernel to NOT access the card any longer due to DIAG
+ *	Deinitialize the Card
+ *
+ * Returns:
+ *	int
+ */
+int SkDrvEnterDiagMode(
+SK_AC   *pAc)   /* pointer to adapter context */
+{
+	DEV_NET *pNet = netdev_priv(pAc->dev[0]);
+	SK_AC   *pAC  = pNet->pAC;
+
+	SK_MEMCPY(&(pAc->PnmiBackup), &(pAc->PnmiStruct), 
+			sizeof(SK_PNMI_STRUCT_DATA));
+
+	pAC->DiagModeActive = DIAG_ACTIVE;
+	if (pAC->BoardLevel > SK_INIT_DATA) {
+		if (netif_running(pAC->dev[0])) {
+			pAC->WasIfUp[0] = SK_TRUE;
+			pAC->DiagFlowCtrl = SK_TRUE; /* for SkGeClose      */
+			DoPrintInterfaceChange = SK_FALSE;
+			SkDrvDeInitAdapter(pAC, 0);  /* performs SkGeClose */
+		} else {
+			pAC->WasIfUp[0] = SK_FALSE;
+		}
+		if (pNet != netdev_priv(pAC->dev[1])) {
+			pNet = netdev_priv(pAC->dev[1]);
+			if (netif_running(pAC->dev[1])) {
+				pAC->WasIfUp[1] = SK_TRUE;
+				pAC->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */
+				DoPrintInterfaceChange = SK_FALSE;
+				SkDrvDeInitAdapter(pAC, 1);  /* do SkGeClose  */
+			} else {
+				pAC->WasIfUp[1] = SK_FALSE;
+			}
+		}
+		pAC->BoardLevel = SK_INIT_DATA;
+	}
+	return(0);
+}
+
+/*****************************************************************************
+ *
+ *	SkDrvLeaveDiagMode - handles DIAG detach request
+ *
+ * Description:
+ *	Notify the kernel to may access the card again after use by DIAG
+ *	Initialize the Card
+ *
+ * Returns:
+ * 	int
+ */
+int SkDrvLeaveDiagMode(
+SK_AC   *pAc)   /* pointer to adapter control context */
+{ 
+	SK_MEMCPY(&(pAc->PnmiStruct), &(pAc->PnmiBackup), 
+			sizeof(SK_PNMI_STRUCT_DATA));
+	pAc->DiagModeActive    = DIAG_NOTACTIVE;
+	pAc->Pnmi.DiagAttached = SK_DIAG_IDLE;
+        if (pAc->WasIfUp[0] == SK_TRUE) {
+                pAc->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */
+		DoPrintInterfaceChange = SK_FALSE;
+                SkDrvInitAdapter(pAc, 0);    /* first device  */
+        }
+        if (pAc->WasIfUp[1] == SK_TRUE) {
+                pAc->DiagFlowCtrl = SK_TRUE; /* for SkGeClose */
+		DoPrintInterfaceChange = SK_FALSE;
+                SkDrvInitAdapter(pAc, 1);    /* second device */
+        }
+	return(0);
+}
+
+/*****************************************************************************
+ *
+ *	ParseDeviceNbrFromSlotName - Evaluate PCI device number
+ *
+ * Description:
+ * 	This function parses the PCI slot name information string and will
+ *	retrieve the devcie number out of it. The slot_name maintianed by
+ *	linux is in the form of '02:0a.0', whereas the first two characters 
+ *	represent the bus number in hex (in the sample above this is 
+ *	pci bus 0x02) and the next two characters the device number (0x0a).
+ *
+ * Returns:
+ *	SK_U32: The device number from the PCI slot name
+ */ 
+
+static SK_U32 ParseDeviceNbrFromSlotName(
+const char *SlotName)   /* pointer to pci slot name eg. '02:0a.0' */
+{
+	char	*CurrCharPos	= (char *) SlotName;
+	int	FirstNibble	= -1;
+	int	SecondNibble	= -1;
+	SK_U32	Result		=  0;
+
+	while (*CurrCharPos != '\0') {
+		if (*CurrCharPos == ':') { 
+			while (*CurrCharPos != '.') {
+				CurrCharPos++;  
+				if (	(*CurrCharPos >= '0') && 
+					(*CurrCharPos <= '9')) {
+					if (FirstNibble == -1) {
+						/* dec. value for '0' */
+						FirstNibble = *CurrCharPos - 48;
+					} else {
+						SecondNibble = *CurrCharPos - 48;
+					}  
+				} else if (	(*CurrCharPos >= 'a') && 
+						(*CurrCharPos <= 'f')  ) {
+					if (FirstNibble == -1) {
+						FirstNibble = *CurrCharPos - 87; 
+					} else {
+						SecondNibble = *CurrCharPos - 87; 
+					}
+				} else {
+					Result = 0;
+				}
+			}
+
+			Result = FirstNibble;
+			Result = Result << 4; /* first nibble is higher one */
+			Result = Result | SecondNibble;
+		}
+		CurrCharPos++;   /* next character */
+	}
+	return (Result);
+}
+
+/****************************************************************************
+ *
+ *	SkDrvDeInitAdapter - deinitialize adapter (this function is only 
+ *				called if Diag attaches to that card)
+ *
+ * Description:
+ *	Close initialized adapter.
+ *
+ * Returns:
+ *	0 - on success
+ *	error code - on error
+ */
+static int SkDrvDeInitAdapter(
+SK_AC   *pAC,		/* pointer to adapter context   */
+int      devNbr)	/* what device is to be handled */
+{
+	struct SK_NET_DEVICE *dev;
+
+	dev = pAC->dev[devNbr];
+
+	/* On Linux 2.6 the network driver does NOT mess with reference
+	** counts.  The driver MUST be able to be unloaded at any time
+	** due to the possibility of hotplug.
+	*/
+	if (SkGeClose(dev) != 0) {
+		return (-1);
+	}
+	return (0);
+
+} /* SkDrvDeInitAdapter() */
+
+/****************************************************************************
+ *
+ *	SkDrvInitAdapter - Initialize adapter (this function is only 
+ *				called if Diag deattaches from that card)
+ *
+ * Description:
+ *	Close initialized adapter.
+ *
+ * Returns:
+ *	0 - on success
+ *	error code - on error
+ */
+static int SkDrvInitAdapter(
+SK_AC   *pAC,		/* pointer to adapter context   */
+int      devNbr)	/* what device is to be handled */
+{
+	struct SK_NET_DEVICE *dev;
+
+	dev = pAC->dev[devNbr];
+
+	if (SkGeOpen(dev) != 0) {
+		return (-1);
+	}
+
+	/*
+	** Use correct MTU size and indicate to kernel TX queue can be started
+	*/ 
+	if (SkGeChangeMtu(dev, dev->mtu) != 0) {
+		return (-1);
+	} 
+	return (0);
+
+} /* SkDrvInitAdapter */
+
+#endif
+
+#ifdef DEBUG
+/****************************************************************************/
+/* "debug only" section *****************************************************/
+/****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ *	DumpMsg - print a frame
+ *
+ * Description:
+ *	This function prints frames to the system logfile/to the console.
+ *
+ * Returns: N/A
+ *	
+ */
+static void DumpMsg(struct sk_buff *skb, char *str)
+{
+	int	msglen;
+
+	if (skb == NULL) {
+		printk("DumpMsg(): NULL-Message\n");
+		return;
+	}
+
+	if (skb->data == NULL) {
+		printk("DumpMsg(): Message empty\n");
+		return;
+	}
+
+	msglen = skb->len;
+	if (msglen > 64)
+		msglen = 64;
+
+	printk("--- Begin of message from %s , len %d (from %d) ----\n", str, msglen, skb->len);
+
+	DumpData((char *)skb->data, msglen);
+
+	printk("------- End of message ---------\n");
+} /* DumpMsg */
+
+
+
+/*****************************************************************************
+ *
+ *	DumpData - print a data area
+ *
+ * Description:
+ *	This function prints a area of data to the system logfile/to the
+ *	console.
+ *
+ * Returns: N/A
+ *	
+ */
+static void DumpData(char *p, int size)
+{
+register int    i;
+int	haddr, addr;
+char	hex_buffer[180];
+char	asc_buffer[180];
+char	HEXCHAR[] = "0123456789ABCDEF";
+
+	addr = 0;
+	haddr = 0;
+	hex_buffer[0] = 0;
+	asc_buffer[0] = 0;
+	for (i=0; i < size; ) {
+		if (*p >= '0' && *p <='z')
+			asc_buffer[addr] = *p;
+		else
+			asc_buffer[addr] = '.';
+		addr++;
+		asc_buffer[addr] = 0;
+		hex_buffer[haddr] = HEXCHAR[(*p & 0xf0) >> 4];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[*p & 0x0f];
+		haddr++;
+		hex_buffer[haddr] = ' ';
+		haddr++;
+		hex_buffer[haddr] = 0;
+		p++;
+		i++;
+		if (i%16 == 0) {
+			printk("%s  %s\n", hex_buffer, asc_buffer);
+			addr = 0;
+			haddr = 0;
+		}
+	}
+} /* DumpData */
+
+
+/*****************************************************************************
+ *
+ *	DumpLong - print a data area as long values
+ *
+ * Description:
+ *	This function prints a area of data to the system logfile/to the
+ *	console.
+ *
+ * Returns: N/A
+ *	
+ */
+static void DumpLong(char *pc, int size)
+{
+register int    i;
+int	haddr, addr;
+char	hex_buffer[180];
+char	asc_buffer[180];
+char	HEXCHAR[] = "0123456789ABCDEF";
+long	*p;
+int	l;
+
+	addr = 0;
+	haddr = 0;
+	hex_buffer[0] = 0;
+	asc_buffer[0] = 0;
+	p = (long*) pc;
+	for (i=0; i < size; ) {
+		l = (long) *p;
+		hex_buffer[haddr] = HEXCHAR[(l >> 28) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 24) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 20) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 16) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 12) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 8) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[(l >> 4) & 0xf];
+		haddr++;
+		hex_buffer[haddr] = HEXCHAR[l & 0x0f];
+		haddr++;
+		hex_buffer[haddr] = ' ';
+		haddr++;
+		hex_buffer[haddr] = 0;
+		p++;
+		i++;
+		if (i%8 == 0) {
+			printk("%4x %s\n", (i-8)*4, hex_buffer);
+			haddr = 0;
+		}
+	}
+	printk("------------------------\n");
+} /* DumpLong */
+
+#endif
+
+static int __devinit skge_probe_one(struct pci_dev *pdev,
+		const struct pci_device_id *ent)
+{
+	SK_AC			*pAC;
+	DEV_NET			*pNet = NULL;
+	struct net_device	*dev = NULL;
+	static int boards_found = 0;
+	int error = -ENODEV;
+	int using_dac = 0;
+	char DeviceStr[80];
+
+	if (pci_enable_device(pdev))
+		goto out;
+ 
+	/* Configure DMA attributes. */
+	if (sizeof(dma_addr_t) > sizeof(u32) &&
+	    !(error = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) {
+		using_dac = 1;
+		error = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+		if (error < 0) {
+			printk(KERN_ERR "sk98lin %s unable to obtain 64 bit DMA "
+			       "for consistent allocations\n", pci_name(pdev));
+			goto out_disable_device;
+		}
+	} else {
+		error = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+		if (error) {
+			printk(KERN_ERR "sk98lin %s no usable DMA configuration\n",
+			       pci_name(pdev));
+			goto out_disable_device;
+		}
+	}
+
+ 	error = -ENOMEM;
+ 	dev = alloc_etherdev(sizeof(DEV_NET));
+ 	if (!dev) {
+		printk(KERN_ERR "sk98lin: unable to allocate etherdev "
+		       "structure!\n");
+		goto out_disable_device;
+	}
+
+	pNet = netdev_priv(dev);
+	pNet->pAC = kzalloc(sizeof(SK_AC), GFP_KERNEL);
+	if (!pNet->pAC) {
+		printk(KERN_ERR "sk98lin: unable to allocate adapter "
+		       "structure!\n");
+		goto out_free_netdev;
+	}
+
+	pAC = pNet->pAC;
+	pAC->PciDev = pdev;
+
+	pAC->dev[0] = dev;
+	pAC->dev[1] = dev;
+	pAC->CheckQueue = SK_FALSE;
+
+	dev->irq = pdev->irq;
+
+	error = SkGeInitPCI(pAC);
+	if (error) {
+		printk(KERN_ERR "sk98lin: PCI setup failed: %i\n", error);
+		goto out_free_netdev;
+	}
+
+	dev->open =		&SkGeOpen;
+	dev->stop =		&SkGeClose;
+	dev->hard_start_xmit =	&SkGeXmit;
+	dev->get_stats =	&SkGeStats;
+	dev->set_multicast_list = &SkGeSetRxMode;
+	dev->set_mac_address =	&SkGeSetMacAddr;
+	dev->do_ioctl =		&SkGeIoctl;
+	dev->change_mtu =	&SkGeChangeMtu;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	dev->poll_controller =	&SkGePollController;
+#endif
+	SET_NETDEV_DEV(dev, &pdev->dev);
+	SET_ETHTOOL_OPS(dev, &SkGeEthtoolOps);
+
+	/* Use only if yukon hardware */
+	if (pAC->ChipsetType) {
+#ifdef USE_SK_TX_CHECKSUM
+		dev->features |= NETIF_F_IP_CSUM;
+#endif
+#ifdef SK_ZEROCOPY
+		dev->features |= NETIF_F_SG;
+#endif
+#ifdef USE_SK_RX_CHECKSUM
+		pAC->RxPort[0].RxCsum = 1;
+#endif
+	}
+
+	if (using_dac)
+		dev->features |= NETIF_F_HIGHDMA;
+
+	pAC->Index = boards_found++;
+
+	error = SkGeBoardInit(dev, pAC);
+	if (error)
+		goto out_free_netdev;
+
+	/* Read Adapter name from VPD */
+	if (ProductStr(pAC, DeviceStr, sizeof(DeviceStr)) != 0) {
+		error = -EIO;
+		printk(KERN_ERR "sk98lin: Could not read VPD data.\n");
+		goto out_free_resources;
+	}
+
+	/* Register net device */
+	error = register_netdev(dev);
+	if (error) {
+		printk(KERN_ERR "sk98lin: Could not register device.\n");
+		goto out_free_resources;
+	}
+
+	/* Print adapter specific string from vpd */
+	printk("%s: %s\n", dev->name, DeviceStr);
+
+	/* Print configuration settings */
+	printk("      PrefPort:%c  RlmtMode:%s\n",
+		'A' + pAC->Rlmt.Net[0].Port[pAC->Rlmt.Net[0].PrefPort]->PortNumber,
+		(pAC->RlmtMode==0)  ? "Check Link State" :
+		((pAC->RlmtMode==1) ? "Check Link State" :
+		((pAC->RlmtMode==3) ? "Check Local Port" :
+		((pAC->RlmtMode==7) ? "Check Segmentation" :
+		((pAC->RlmtMode==17) ? "Dual Check Link State" :"Error")))));
+
+	SkGeYellowLED(pAC, pAC->IoBase, 1);
+
+	memcpy(&dev->dev_addr, &pAC->Addr.Net[0].CurrentMacAddress, 6);
+	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+	pNet->PortNr = 0;
+	pNet->NetNr  = 0;
+
+	boards_found++;
+
+	pci_set_drvdata(pdev, dev);
+
+	/* More then one port found */
+	if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) {
+		dev = alloc_etherdev(sizeof(DEV_NET));
+		if (!dev) {
+			printk(KERN_ERR "sk98lin: unable to allocate etherdev "
+				"structure!\n");
+			goto single_port;
+		}
+
+		pNet          = netdev_priv(dev);
+		pNet->PortNr  = 1;
+		pNet->NetNr   = 1;
+		pNet->pAC     = pAC;
+
+		dev->open               = &SkGeOpen;
+		dev->stop               = &SkGeClose;
+		dev->hard_start_xmit    = &SkGeXmit;
+		dev->get_stats          = &SkGeStats;
+		dev->set_multicast_list = &SkGeSetRxMode;
+		dev->set_mac_address    = &SkGeSetMacAddr;
+		dev->do_ioctl           = &SkGeIoctl;
+		dev->change_mtu         = &SkGeChangeMtu;
+		SET_NETDEV_DEV(dev, &pdev->dev);
+		SET_ETHTOOL_OPS(dev, &SkGeEthtoolOps);
+
+		if (pAC->ChipsetType) {
+#ifdef USE_SK_TX_CHECKSUM
+			dev->features |= NETIF_F_IP_CSUM;
+#endif
+#ifdef SK_ZEROCOPY
+			dev->features |= NETIF_F_SG;
+#endif
+#ifdef USE_SK_RX_CHECKSUM
+			pAC->RxPort[1].RxCsum = 1;
+#endif
+		}
+
+		if (using_dac)
+			dev->features |= NETIF_F_HIGHDMA;
+
+		error = register_netdev(dev);
+		if (error) {
+			printk(KERN_ERR "sk98lin: Could not register device"
+			       " for second port. (%d)\n", error);
+			free_netdev(dev);
+			goto single_port;
+		}
+
+		pAC->dev[1]   = dev;
+		memcpy(&dev->dev_addr,
+		       &pAC->Addr.Net[1].CurrentMacAddress, 6);
+		memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+		printk("%s: %s\n", dev->name, DeviceStr);
+		printk("      PrefPort:B  RlmtMode:Dual Check Link State\n");
+	}
+
+single_port:
+
+	/* Save the hardware revision */
+	pAC->HWRevision = (((pAC->GIni.GIPciHwRev >> 4) & 0x0F)*10) +
+		(pAC->GIni.GIPciHwRev & 0x0F);
+
+	/* Set driver globals */
+	pAC->Pnmi.pDriverFileName    = DRIVER_FILE_NAME;
+	pAC->Pnmi.pDriverReleaseDate = DRIVER_REL_DATE;
+
+	memset(&pAC->PnmiBackup, 0, sizeof(SK_PNMI_STRUCT_DATA));
+	memcpy(&pAC->PnmiBackup, &pAC->PnmiStruct, sizeof(SK_PNMI_STRUCT_DATA));
+
+	return 0;
+
+ out_free_resources:
+	FreeResources(dev);
+ out_free_netdev:
+	free_netdev(dev);
+ out_disable_device:
+	pci_disable_device(pdev);
+ out:
+	return error;
+}
+
+static void __devexit skge_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	DEV_NET *pNet = netdev_priv(dev);
+	SK_AC *pAC = pNet->pAC;
+	struct net_device *otherdev = pAC->dev[1];
+
+	unregister_netdev(dev);
+
+	SkGeYellowLED(pAC, pAC->IoBase, 0);
+
+	if (pAC->BoardLevel == SK_INIT_RUN) {
+		SK_EVPARA EvPara;
+		unsigned long Flags;
+
+		/* board is still alive */
+		spin_lock_irqsave(&pAC->SlowPathLock, Flags);
+		EvPara.Para32[0] = 0;
+		EvPara.Para32[1] = -1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+		EvPara.Para32[0] = 1;
+		EvPara.Para32[1] = -1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STOP, EvPara);
+		SkEventDispatcher(pAC, pAC->IoBase);
+		/* disable interrupts */
+		SK_OUT32(pAC->IoBase, B0_IMSK, 0);
+		SkGeDeInit(pAC, pAC->IoBase);
+		spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
+		pAC->BoardLevel = SK_INIT_DATA;
+		/* We do NOT check here, if IRQ was pending, of course*/
+	}
+
+	if (pAC->BoardLevel == SK_INIT_IO) {
+		/* board is still alive */
+		SkGeDeInit(pAC, pAC->IoBase);
+		pAC->BoardLevel = SK_INIT_DATA;
+	}
+
+	FreeResources(dev);
+	free_netdev(dev);
+	if (otherdev != dev)
+		free_netdev(otherdev);
+	kfree(pAC);
+}
+
+#ifdef CONFIG_PM
+static int skge_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	DEV_NET *pNet = netdev_priv(dev);
+	SK_AC *pAC = pNet->pAC;
+	struct net_device *otherdev = pAC->dev[1];
+
+	if (netif_running(dev)) {
+		netif_carrier_off(dev);
+		DoPrintInterfaceChange = SK_FALSE;
+		SkDrvDeInitAdapter(pAC, 0);  /* performs SkGeClose */
+		netif_device_detach(dev);
+	}
+	if (otherdev != dev) {
+		if (netif_running(otherdev)) {
+			netif_carrier_off(otherdev);
+			DoPrintInterfaceChange = SK_FALSE;
+			SkDrvDeInitAdapter(pAC, 1);  /* performs SkGeClose */
+			netif_device_detach(otherdev);
+		}
+	}
+
+	pci_save_state(pdev);
+	pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+	if (pAC->AllocFlag & SK_ALLOC_IRQ) {
+		free_irq(dev->irq, dev);
+	}
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+	return 0;
+}
+
+static int skge_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	DEV_NET *pNet = netdev_priv(dev);
+	SK_AC *pAC = pNet->pAC;
+	struct net_device *otherdev = pAC->dev[1];
+	int ret;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+	ret = pci_enable_device(pdev);
+	if (ret) {
+		printk(KERN_WARNING "sk98lin: unable to enable device %s "
+				"in resume\n", dev->name);
+		goto err_out;
+	}
+	pci_set_master(pdev);
+	if (pAC->GIni.GIMacsFound == 2)
+		ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev);
+	else
+		ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED, "sk98lin", dev);
+	if (ret) {
+		printk(KERN_WARNING "sk98lin: unable to acquire IRQ %d\n", dev->irq);
+		ret = -EBUSY;
+		goto err_out_disable_pdev;
+	}
+
+	netif_device_attach(dev);
+	if (netif_running(dev)) {
+		DoPrintInterfaceChange = SK_FALSE;
+		SkDrvInitAdapter(pAC, 0);    /* first device  */
+	}
+	if (otherdev != dev) {
+		netif_device_attach(otherdev);
+		if (netif_running(otherdev)) {
+			DoPrintInterfaceChange = SK_FALSE;
+			SkDrvInitAdapter(pAC, 1);    /* second device  */
+		}
+	}
+
+	return 0;
+
+err_out_disable_pdev:
+	pci_disable_device(pdev);
+err_out:
+	pAC->AllocFlag &= ~SK_ALLOC_IRQ;
+	dev->irq = 0;
+	return ret;
+}
+#else
+#define skge_suspend NULL
+#define skge_resume NULL
+#endif
+
+static struct pci_device_id skge_pci_tbl[] = {
+#ifdef SK98LIN_ALL_DEVICES
+	{ PCI_VENDOR_ID_3COM, 0x1700, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_3COM, 0x80eb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+#endif
+#ifdef GENESIS
+	/* Generic SysKonnect SK-98xx Gigabit Ethernet Server Adapter */	
+	{ PCI_VENDOR_ID_SYSKONNECT, 0x4300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+#endif
+	/* Generic SysKonnect SK-98xx V2.0 Gigabit Ethernet Adapter */	
+	{ PCI_VENDOR_ID_SYSKONNECT, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+#ifdef SK98LIN_ALL_DEVICES
+/* DLink card does not have valid VPD so this driver gags
+ *	{ PCI_VENDOR_ID_DLINK, 0x4c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ */
+	{ PCI_VENDOR_ID_MARVELL, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_MARVELL, 0x5005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_CNET, 0x434e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015, },
+	{ PCI_VENDOR_ID_LINKSYS, 0x1064, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+#endif
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, skge_pci_tbl);
+
+static struct pci_driver skge_driver = {
+	.name		= "sk98lin",
+	.id_table	= skge_pci_tbl,
+	.probe		= skge_probe_one,
+	.remove		= __devexit_p(skge_remove_one),
+	.suspend	= skge_suspend,
+	.resume		= skge_resume,
+};
+
+static int __init skge_init(void)
+{
+	printk(KERN_NOTICE "sk98lin: driver has been replaced by the skge driver"
+	       " and is scheduled for removal\n");
+
+	return pci_register_driver(&skge_driver);
+}
+
+static void __exit skge_exit(void)
+{
+	pci_unregister_driver(&skge_driver);
+}
+
+module_init(skge_init);
+module_exit(skge_exit);
diff --git a/drivers/net/sk98lin/skgehwt.c b/drivers/net/sk98lin/skgehwt.c
new file mode 100644
index 0000000..db67099
--- /dev/null
+++ b/drivers/net/sk98lin/skgehwt.c
@@ -0,0 +1,171 @@
+/******************************************************************************
+ *
+ * Name:	skgehwt.c
+ * Project:	Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version:	$Revision: 1.15 $
+ * Date:	$Date: 2003/09/16 13:41:23 $
+ * Purpose:	Hardware Timer
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/*
+ *	Event queue and dispatcher
+ */
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+	"@(#) $Id: skgehwt.c,v 1.15 2003/09/16 13:41:23 rschmidt Exp $ (C) Marvell.";
+#endif
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+ *   Hardware Timer function queue management.
+ */
+intro()
+{}
+#endif
+
+/*
+ * Prototypes of local functions.
+ */
+#define	SK_HWT_MAX	(65000)
+
+/* correction factor */
+#define	SK_HWT_FAC	(1000 * (SK_U32)pAC->GIni.GIHstClkFact / 100)
+
+/*
+ * Initialize hardware timer.
+ *
+ * Must be called during init level 1.
+ */
+void	SkHwtInit(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	Ioc)	/* IoContext */
+{
+	pAC->Hwt.TStart = 0 ;
+	pAC->Hwt.TStop	= 0 ;
+	pAC->Hwt.TActive = SK_FALSE;
+
+	SkHwtStop(pAC, Ioc);
+}
+
+/*
+ *
+ * Start hardware timer (clock ticks are 16us).
+ *
+ */
+void	SkHwtStart(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	Ioc,	/* IoContext */
+SK_U32	Time)	/* Time in units of 16us to load the timer with. */
+{
+	SK_U32	Cnt;
+
+	if (Time > SK_HWT_MAX)
+		Time = SK_HWT_MAX;
+
+	pAC->Hwt.TStart = Time;
+	pAC->Hwt.TStop = 0L;
+
+	Cnt = Time;
+
+	/*
+	 * if time < 16 us
+	 *	time = 16 us
+	 */
+	if (!Cnt) {
+		Cnt++;
+	}
+
+	SK_OUT32(Ioc, B2_TI_INI, Cnt * SK_HWT_FAC);
+	
+	SK_OUT16(Ioc, B2_TI_CTRL, TIM_START);	/* Start timer. */
+
+	pAC->Hwt.TActive = SK_TRUE;
+}
+
+/*
+ * Stop hardware timer.
+ * and clear the timer IRQ
+ */
+void	SkHwtStop(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	Ioc)	/* IoContext */
+{
+	SK_OUT16(Ioc, B2_TI_CTRL, TIM_STOP);
+	
+	SK_OUT16(Ioc, B2_TI_CTRL, TIM_CLR_IRQ);
+
+	pAC->Hwt.TActive = SK_FALSE;
+}
+
+
+/*
+ *	Stop hardware timer and read time elapsed since last start.
+ *
+ * returns
+ *	The elapsed time since last start in units of 16us.
+ *
+ */
+SK_U32	SkHwtRead(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	Ioc)	/* IoContext */
+{
+	SK_U32	TRead;
+	SK_U32	IStatus;
+
+	if (pAC->Hwt.TActive) {
+		
+		SkHwtStop(pAC, Ioc);
+
+		SK_IN32(Ioc, B2_TI_VAL, &TRead);
+		TRead /= SK_HWT_FAC;
+
+		SK_IN32(Ioc, B0_ISRC, &IStatus);
+
+		/* Check if timer expired (or wraped around) */
+		if ((TRead > pAC->Hwt.TStart) || (IStatus & IS_TIMINT)) {
+			
+			SkHwtStop(pAC, Ioc);
+			
+			pAC->Hwt.TStop = pAC->Hwt.TStart;
+		}
+		else {
+			
+			pAC->Hwt.TStop = pAC->Hwt.TStart - TRead;
+		}
+	}
+	return(pAC->Hwt.TStop);
+}
+
+/*
+ * interrupt source= timer
+ */
+void	SkHwtIsr(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	Ioc)	/* IoContext */
+{
+	SkHwtStop(pAC, Ioc);
+	
+	pAC->Hwt.TStop = pAC->Hwt.TStart;
+	
+	SkTimerDone(pAC, Ioc);
+}
+
+/* End of file */
diff --git a/drivers/net/sk98lin/skgeinit.c b/drivers/net/sk98lin/skgeinit.c
new file mode 100644
index 0000000..67f1d6a
--- /dev/null
+++ b/drivers/net/sk98lin/skgeinit.c
@@ -0,0 +1,2005 @@
+/******************************************************************************
+ *
+ * Name:	skgeinit.c
+ * Project:	Gigabit Ethernet Adapters, Common Modules
+ * Version:	$Revision: 1.97 $
+ * Date:	$Date: 2003/10/02 16:45:31 $
+ * Purpose:	Contains functions to initialize the adapter
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* global variables ***********************************************************/
+
+/* local variables ************************************************************/
+
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+	"@(#) $Id: skgeinit.c,v 1.97 2003/10/02 16:45:31 rschmidt Exp $ (C) Marvell.";
+#endif
+
+struct s_QOffTab {
+	int	RxQOff;		/* Receive Queue Address Offset */
+	int	XsQOff;		/* Sync Tx Queue Address Offset */
+	int	XaQOff;		/* Async Tx Queue Address Offset */
+};
+static struct s_QOffTab QOffTab[] = {
+	{Q_R1, Q_XS1, Q_XA1}, {Q_R2, Q_XS2, Q_XA2}
+};
+
+struct s_Config {
+	char	ScanString[8];
+	SK_U32	Value;
+};
+
+static struct s_Config OemConfig = {
+	{'O','E','M','_','C','o','n','f'},
+#ifdef SK_OEM_CONFIG
+	OEM_CONFIG_VALUE,
+#else
+	0,
+#endif
+};
+
+/******************************************************************************
+ *
+ *	SkGePollTxD() - Enable / Disable Descriptor Polling of TxD Rings
+ *
+ * Description:
+ *	Enable or disable the descriptor polling of the transmit descriptor
+ *	ring(s) (TxD) for port 'Port'.
+ *	The new configuration is *not* saved over any SkGeStopPort() and
+ *	SkGeInitPort() calls.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGePollTxD(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL PollTxD)	/* SK_TRUE (enable pol.), SK_FALSE (disable pol.) */
+{
+	SK_GEPORT *pPrt;
+	SK_U32	DWord;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	DWord = (SK_U32)(PollTxD ? CSR_ENA_POL : CSR_DIS_POL);
+
+	if (pPrt->PXSQSize != 0) {
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), DWord);
+	}
+	
+	if (pPrt->PXAQSize != 0) {
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), DWord);
+	}
+}	/* SkGePollTxD */
+
+
+/******************************************************************************
+ *
+ *	SkGeYellowLED() - Switch the yellow LED on or off.
+ *
+ * Description:
+ *	Switch the yellow LED on or off.
+ *
+ * Note:
+ *	This function may be called any time after SkGeInit(Level 1).
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGeYellowLED(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		State)		/* yellow LED state, 0 = OFF, 0 != ON */
+{
+	if (State == 0) {
+		/* Switch yellow LED OFF */
+		SK_OUT8(IoC, B0_LED, LED_STAT_OFF);
+	}
+	else {
+		/* Switch yellow LED ON */
+		SK_OUT8(IoC, B0_LED, LED_STAT_ON);
+	}
+}	/* SkGeYellowLED */
+
+
+#if (!defined(SK_SLIM) || defined(GENESIS))
+/******************************************************************************
+ *
+ *	SkGeXmitLED() - Modify the Operational Mode of a transmission LED.
+ *
+ * Description:
+ *	The Rx or Tx LED which is specified by 'Led' will be
+ *	enabled, disabled or switched on in test mode.
+ *
+ * Note:
+ *	'Led' must contain the address offset of the LEDs INI register.
+ *
+ * Usage:
+ *	SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA);
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGeXmitLED(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Led,		/* offset to the LED Init Value register */
+int		Mode)		/* Mode may be SK_LED_DIS, SK_LED_ENA, SK_LED_TST */
+{
+	SK_U32	LedIni;
+
+	switch (Mode) {
+	case SK_LED_ENA:
+		LedIni = SK_XMIT_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100;
+		SK_OUT32(IoC, Led + XMIT_LED_INI, LedIni);
+		SK_OUT8(IoC, Led + XMIT_LED_CTRL, LED_START);
+		break;
+	case SK_LED_TST:
+		SK_OUT8(IoC, Led + XMIT_LED_TST, LED_T_ON);
+		SK_OUT32(IoC, Led + XMIT_LED_CNT, 100);
+		SK_OUT8(IoC, Led + XMIT_LED_CTRL, LED_START);
+		break;
+	case SK_LED_DIS:
+	default:
+		/*
+		 * Do NOT stop the LED Timer here. The LED might be
+		 * in on state. But it needs to go off.
+		 */
+		SK_OUT32(IoC, Led + XMIT_LED_CNT, 0);
+		SK_OUT8(IoC, Led + XMIT_LED_TST, LED_T_OFF);
+		break;
+	}
+			
+	/*
+	 * 1000BT: The Transmit LED is driven by the PHY.
+	 * But the default LED configuration is used for
+	 * Level One and Broadcom PHYs.
+	 * (Broadcom: It may be that PHY_B_PEC_EN_LTR has to be set.)
+	 * (In this case it has to be added here. But we will see. XXX)
+	 */
+}	/* SkGeXmitLED */
+#endif	/* !SK_SLIM || GENESIS */
+
+
+/******************************************************************************
+ *
+ *	DoCalcAddr() - Calculates the start and the end address of a queue.
+ *
+ * Description:
+ *	This function calculates the start and the end address of a queue.
+ *  Afterwards the 'StartVal' is incremented to the next start position.
+ *	If the port is already initialized the calculated values
+ *	will be checked against the configured values and an
+ *	error will be returned, if they are not equal.
+ *	If the port is not initialized the values will be written to
+ *	*StartAdr and *EndAddr.
+ *
+ * Returns:
+ *	0:	success
+ *	1:	configuration error
+ */
+static int DoCalcAddr(
+SK_AC		*pAC, 				/* adapter context */
+SK_GEPORT	SK_FAR *pPrt,		/* port index */
+int			QuSize,				/* size of the queue to configure in kB */
+SK_U32		SK_FAR *StartVal,	/* start value for address calculation */
+SK_U32		SK_FAR *QuStartAddr,/* start addr to calculate */
+SK_U32		SK_FAR *QuEndAddr)	/* end address to calculate */
+{
+	SK_U32	EndVal;
+	SK_U32	NextStart;
+	int		Rtv;
+
+	Rtv = 0;
+	if (QuSize == 0) {
+		EndVal = *StartVal;
+		NextStart = EndVal;
+	}
+	else {
+		EndVal = *StartVal + ((SK_U32)QuSize * 1024) - 1;
+		NextStart = EndVal + 1;
+	}
+
+	if (pPrt->PState >= SK_PRT_INIT) {
+		if (*StartVal != *QuStartAddr || EndVal != *QuEndAddr) {
+			Rtv = 1;
+		}
+	}
+	else {
+		*QuStartAddr = *StartVal;
+		*QuEndAddr = EndVal;
+	}
+
+	*StartVal = NextStart;
+	return(Rtv);
+}	/* DoCalcAddr */
+
+/******************************************************************************
+ *
+ *	SkGeInitAssignRamToQueues() - allocate default queue sizes
+ *
+ * Description:
+ *	This function assigns the memory to the different queues and ports.
+ *	When DualNet is set to SK_TRUE all ports get the same amount of memory.
+ *  Otherwise the first port gets most of the memory and all the
+ *	other ports just the required minimum.
+ *	This function can only be called when pAC->GIni.GIRamSize and
+ *	pAC->GIni.GIMacsFound have been initialized, usually this happens
+ *	at init level 1
+ *
+ * Returns:
+ *	0 - ok
+ *	1 - invalid input values
+ *	2 - not enough memory
+ */
+
+int SkGeInitAssignRamToQueues(
+SK_AC	*pAC,			/* Adapter context */
+int		ActivePort,		/* Active Port in RLMT mode */
+SK_BOOL	DualNet)		/* adapter context */
+{
+	int	i;
+	int	UsedKilobytes;			/* memory already assigned */
+	int	ActivePortKilobytes;	/* memory available for active port */
+	SK_GEPORT *pGePort;
+
+	UsedKilobytes = 0;
+
+	if (ActivePort >= pAC->GIni.GIMacsFound) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+			("SkGeInitAssignRamToQueues: ActivePort (%d) invalid\n",
+			ActivePort));
+		return(1);
+	}
+	if (((pAC->GIni.GIMacsFound * (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE)) +
+		((RAM_QUOTA_SYNC == 0) ? 0 : SK_MIN_TXQ_SIZE)) > pAC->GIni.GIRamSize) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+			("SkGeInitAssignRamToQueues: Not enough memory (%d)\n",
+			 pAC->GIni.GIRamSize));
+		return(2);
+	}
+
+	if (DualNet) {
+		/* every port gets the same amount of memory */
+		ActivePortKilobytes = pAC->GIni.GIRamSize / pAC->GIni.GIMacsFound;
+		for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+
+			pGePort = &pAC->GIni.GP[i];
+			
+			/* take away the minimum memory for active queues */
+			ActivePortKilobytes -= (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE);
+
+			/* receive queue gets the minimum + 80% of the rest */
+			pGePort->PRxQSize = (int) (ROUND_QUEUE_SIZE_KB((
+				ActivePortKilobytes * (unsigned long) RAM_QUOTA_RX) / 100))
+				+ SK_MIN_RXQ_SIZE;
+
+			ActivePortKilobytes -= (pGePort->PRxQSize - SK_MIN_RXQ_SIZE);
+
+			/* synchronous transmit queue */
+			pGePort->PXSQSize = 0;
+
+			/* asynchronous transmit queue */
+			pGePort->PXAQSize = (int) ROUND_QUEUE_SIZE_KB(ActivePortKilobytes +
+				SK_MIN_TXQ_SIZE);
+		}
+	}
+	else {	
+		/* Rlmt Mode or single link adapter */
+
+		/* Set standby queue size defaults for all standby ports */
+		for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+
+			if (i != ActivePort) {
+				pGePort = &pAC->GIni.GP[i];
+
+				pGePort->PRxQSize = SK_MIN_RXQ_SIZE;
+				pGePort->PXAQSize = SK_MIN_TXQ_SIZE;
+				pGePort->PXSQSize = 0;
+
+				/* Count used RAM */
+				UsedKilobytes += pGePort->PRxQSize + pGePort->PXAQSize;
+			}
+		}
+		/* what's left? */
+		ActivePortKilobytes = pAC->GIni.GIRamSize - UsedKilobytes;
+
+		/* assign it to the active port */
+		/* first take away the minimum memory */
+		ActivePortKilobytes -= (SK_MIN_RXQ_SIZE + SK_MIN_TXQ_SIZE);
+		pGePort = &pAC->GIni.GP[ActivePort];
+
+		/* receive queue get's the minimum + 80% of the rest */
+		pGePort->PRxQSize = (int) (ROUND_QUEUE_SIZE_KB((ActivePortKilobytes *
+			(unsigned long) RAM_QUOTA_RX) / 100)) + SK_MIN_RXQ_SIZE;
+
+		ActivePortKilobytes -= (pGePort->PRxQSize - SK_MIN_RXQ_SIZE);
+
+		/* synchronous transmit queue */
+		pGePort->PXSQSize = 0;
+
+		/* asynchronous transmit queue */
+		pGePort->PXAQSize = (int) ROUND_QUEUE_SIZE_KB(ActivePortKilobytes) +
+			SK_MIN_TXQ_SIZE;
+	}
+#ifdef VCPU
+	VCPUprintf(0, "PRxQSize=%u, PXSQSize=%u, PXAQSize=%u\n",
+		pGePort->PRxQSize, pGePort->PXSQSize, pGePort->PXAQSize);
+#endif /* VCPU */
+
+	return(0);
+}	/* SkGeInitAssignRamToQueues */
+
+/******************************************************************************
+ *
+ *	SkGeCheckQSize() - Checks the Adapters Queue Size Configuration
+ *
+ * Description:
+ *	This function verifies the Queue Size Configuration specified
+ *	in the variables PRxQSize, PXSQSize, and PXAQSize of all
+ *	used ports.
+ *	This requirements must be fullfilled to have a valid configuration:
+ *		- The size of all queues must not exceed GIRamSize.
+ *		- The queue sizes must be specified in units of 8 kB.
+ *		- The size of Rx queues of available ports must not be
+ *		  smaller than 16 kB.
+ *		- The size of at least one Tx queue (synch. or asynch.)
+ *        of available ports must not be smaller than 16 kB
+ *        when Jumbo Frames are used.
+ *		- The RAM start and end addresses must not be changed
+ *		  for ports which are already initialized.
+ *	Furthermore SkGeCheckQSize() defines the Start and End Addresses
+ *  of all ports and stores them into the HWAC port	structure.
+ *
+ * Returns:
+ *	0:	Queue Size Configuration valid
+ *	1:	Queue Size Configuration invalid
+ */
+static int SkGeCheckQSize(
+SK_AC	 *pAC,		/* adapter context */
+int		 Port)		/* port index */
+{
+	SK_GEPORT *pPrt;
+	int	i;
+	int	Rtv;
+	int	Rtv2;
+	SK_U32	StartAddr;
+#ifndef SK_SLIM
+	int	UsedMem;	/* total memory used (max. found ports) */
+#endif	
+
+	Rtv = 0;
+	
+#ifndef SK_SLIM
+
+	UsedMem = 0;
+	for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+		pPrt = &pAC->GIni.GP[i];
+
+		if ((pPrt->PRxQSize & QZ_UNITS) != 0 ||
+			(pPrt->PXSQSize & QZ_UNITS) != 0 ||
+			(pPrt->PXAQSize & QZ_UNITS) != 0) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG);
+			return(1);
+		}
+
+		if (i == Port && pPrt->PRxQSize < SK_MIN_RXQ_SIZE) {
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E011, SKERR_HWI_E011MSG);
+			return(1);
+		}
+		
+		/*
+		 * the size of at least one Tx queue (synch. or asynch.) has to be > 0.
+		 * if Jumbo Frames are used, this size has to be >= 16 kB.
+		 */
+		if ((i == Port && pPrt->PXSQSize == 0 && pPrt->PXAQSize == 0) ||
+			(pAC->GIni.GIPortUsage == SK_JUMBO_LINK &&
+            ((pPrt->PXSQSize > 0 && pPrt->PXSQSize < SK_MIN_TXQ_SIZE) ||
+			 (pPrt->PXAQSize > 0 && pPrt->PXAQSize < SK_MIN_TXQ_SIZE)))) {
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E023, SKERR_HWI_E023MSG);
+				return(1);
+		}
+		
+		UsedMem += pPrt->PRxQSize + pPrt->PXSQSize + pPrt->PXAQSize;
+	}
+	
+	if (UsedMem > pAC->GIni.GIRamSize) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E012, SKERR_HWI_E012MSG);
+		return(1);
+	}
+#endif	/* !SK_SLIM */
+
+	/* Now start address calculation */
+	StartAddr = pAC->GIni.GIRamOffs;
+	for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+		pPrt = &pAC->GIni.GP[i];
+
+		/* Calculate/Check values for the receive queue */
+		Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PRxQSize, &StartAddr,
+			&pPrt->PRxQRamStart, &pPrt->PRxQRamEnd);
+		Rtv |= Rtv2;
+
+		/* Calculate/Check values for the synchronous Tx queue */
+		Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXSQSize, &StartAddr,
+			&pPrt->PXsQRamStart, &pPrt->PXsQRamEnd);
+		Rtv |= Rtv2;
+
+		/* Calculate/Check values for the asynchronous Tx queue */
+		Rtv2 = DoCalcAddr(pAC, pPrt, pPrt->PXAQSize, &StartAddr,
+			&pPrt->PXaQRamStart, &pPrt->PXaQRamEnd);
+		Rtv |= Rtv2;
+
+		if (Rtv) {
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E013, SKERR_HWI_E013MSG);
+			return(1);
+		}
+	}
+
+	return(0);
+}	/* SkGeCheckQSize */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *	SkGeInitMacArb() - Initialize the MAC Arbiter
+ *
+ * Description:
+ *	This function initializes the MAC Arbiter.
+ *	It must not be called if there is still an
+ *	initialized or active port.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInitMacArb(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	/* release local reset */
+	SK_OUT16(IoC, B3_MA_TO_CTRL, MA_RST_CLR);
+
+	/* configure timeout values */
+	SK_OUT8(IoC, B3_MA_TOINI_RX1, SK_MAC_TO_53);
+	SK_OUT8(IoC, B3_MA_TOINI_RX2, SK_MAC_TO_53);
+	SK_OUT8(IoC, B3_MA_TOINI_TX1, SK_MAC_TO_53);
+	SK_OUT8(IoC, B3_MA_TOINI_TX2, SK_MAC_TO_53);
+
+	SK_OUT8(IoC, B3_MA_RCINI_RX1, 0);
+	SK_OUT8(IoC, B3_MA_RCINI_RX2, 0);
+	SK_OUT8(IoC, B3_MA_RCINI_TX1, 0);
+	SK_OUT8(IoC, B3_MA_RCINI_TX2, 0);
+
+	/* recovery values are needed for XMAC II Rev. B2 only */
+	/* Fast Output Enable Mode was intended to use with Rev. B2, but now? */
+
+	/*
+	 * There is no start or enable button to push, therefore
+	 * the MAC arbiter is configured and enabled now.
+	 */
+}	/* SkGeInitMacArb */
+
+
+/******************************************************************************
+ *
+ *	SkGeInitPktArb() - Initialize the Packet Arbiter
+ *
+ * Description:
+ *	This function initializes the Packet Arbiter.
+ *	It must not be called if there is still an
+ *	initialized or active port.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInitPktArb(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	/* release local reset */
+	SK_OUT16(IoC, B3_PA_CTRL, PA_RST_CLR);
+
+	/* configure timeout values */
+	SK_OUT16(IoC, B3_PA_TOINI_RX1, SK_PKT_TO_MAX);
+	SK_OUT16(IoC, B3_PA_TOINI_RX2, SK_PKT_TO_MAX);
+	SK_OUT16(IoC, B3_PA_TOINI_TX1, SK_PKT_TO_MAX);
+	SK_OUT16(IoC, B3_PA_TOINI_TX2, SK_PKT_TO_MAX);
+
+	/*
+	 * enable timeout timers if jumbo frames not used
+	 * NOTE: the packet arbiter timeout interrupt is needed for
+	 * half duplex hangup workaround
+	 */
+	if (pAC->GIni.GIPortUsage != SK_JUMBO_LINK) {
+		if (pAC->GIni.GIMacsFound == 1) {
+			SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1);
+		}
+		else {
+			SK_OUT16(IoC, B3_PA_CTRL, PA_ENA_TO_TX1 | PA_ENA_TO_TX2);
+		}
+	}
+}	/* SkGeInitPktArb */
+#endif /* GENESIS */
+
+
+/******************************************************************************
+ *
+ *	SkGeInitMacFifo() - Initialize the MAC FIFOs
+ *
+ * Description:
+ *	Initialize all MAC FIFOs of the specified port
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInitMacFifo(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_U16	Word;
+#ifdef VCPU
+	SK_U32	DWord;
+#endif /* VCPU */
+	/*
+	 * For each FIFO:
+	 *	- release local reset
+	 *	- use default value for MAC FIFO size
+	 *	- setup defaults for the control register
+	 *	- enable the FIFO
+	 */
+	
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+		/* Configure Rx MAC FIFO */
+		SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_CLR);
+		SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_RX_CTRL_DEF);
+		SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_ENA_OP_MD);
+	
+		/* Configure Tx MAC FIFO */
+		SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_CLR);
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
+		SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_ENA_OP_MD);
+	
+		/* Enable frame flushing if jumbo frames used */
+		if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+			SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_FLUSH);
+		}
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		/* set Rx GMAC FIFO Flush Mask */
+		SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_MSK), (SK_U16)RX_FF_FL_DEF_MSK);
+		
+		Word = (SK_U16)GMF_RX_CTRL_DEF;
+
+		/* disable Rx GMAC FIFO Flush for YUKON-Lite Rev. A0 only */
+		if (pAC->GIni.GIYukonLite && pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+
+			Word &= ~GMF_RX_F_FL_ON;
+		}
+		
+		/* Configure Rx MAC FIFO */
+		SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_RST_CLR);
+		SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), Word);
+		
+		/* set Rx GMAC FIFO Flush Threshold (default: 0x0a -> 56 bytes) */
+		SK_OUT16(IoC, MR_ADDR(Port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF);
+		
+		/* Configure Tx MAC FIFO */
+		SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_RST_CLR);
+		SK_OUT16(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U16)GMF_TX_CTRL_DEF);
+		
+#ifdef VCPU
+		SK_IN32(IoC, MR_ADDR(Port, RX_GMF_AF_THR), &DWord);
+		SK_IN32(IoC, MR_ADDR(Port, TX_GMF_AE_THR), &DWord);
+#endif /* VCPU */
+		
+		/* set Tx GMAC FIFO Almost Empty Threshold */
+/*		SK_OUT32(IoC, MR_ADDR(Port, TX_GMF_AE_THR), 0); */
+	}
+#endif /* YUKON */
+
+}	/* SkGeInitMacFifo */
+
+#ifdef	SK_LNK_SYNC_CNT
+/******************************************************************************
+ *
+ *	SkGeLoadLnkSyncCnt() - Load the Link Sync Counter and starts counting
+ *
+ * Description:
+ *	This function starts the Link Sync Counter of the specified
+ *	port and enables the generation of an Link Sync IRQ.
+ *	The Link Sync Counter may be used to detect an active link,
+ *	if autonegotiation is not used.
+ *
+ * Note:
+ *	o To ensure receiving the Link Sync Event the LinkSyncCounter
+ *	  should be initialized BEFORE clearing the XMAC's reset!
+ *	o Enable IS_LNK_SYNC_M1 and IS_LNK_SYNC_M2 after calling this
+ *	  function.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGeLoadLnkSyncCnt(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_U32	CntVal)		/* Counter value */
+{
+	SK_U32	OrgIMsk;
+	SK_U32	NewIMsk;
+	SK_U32	ISrc;
+	SK_BOOL	IrqPend;
+
+	/* stop counter */
+	SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_STOP);
+
+	/*
+	 * ASIC problem:
+	 * Each time starting the Link Sync Counter an IRQ is generated
+	 * by the adapter. See problem report entry from 21.07.98
+	 *
+	 * Workaround:	Disable Link Sync IRQ and clear the unexpeced IRQ
+	 *		if no IRQ is already pending.
+	 */
+	IrqPend = SK_FALSE;
+	SK_IN32(IoC, B0_ISRC, &ISrc);
+	SK_IN32(IoC, B0_IMSK, &OrgIMsk);
+	if (Port == MAC_1) {
+		NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M1;
+		if ((ISrc & IS_LNK_SYNC_M1) != 0) {
+			IrqPend = SK_TRUE;
+		}
+	}
+	else {
+		NewIMsk = OrgIMsk & ~IS_LNK_SYNC_M2;
+		if ((ISrc & IS_LNK_SYNC_M2) != 0) {
+			IrqPend = SK_TRUE;
+		}
+	}
+	if (!IrqPend) {
+		SK_OUT32(IoC, B0_IMSK, NewIMsk);
+	}
+
+	/* load counter */
+	SK_OUT32(IoC, MR_ADDR(Port, LNK_SYNC_INI), CntVal);
+
+	/* start counter */
+	SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_START);
+
+	if (!IrqPend) {
+		/* clear the unexpected IRQ, and restore the interrupt mask */
+		SK_OUT8(IoC, MR_ADDR(Port, LNK_SYNC_CTRL), LED_CLR_IRQ);
+		SK_OUT32(IoC, B0_IMSK, OrgIMsk);
+	}
+}	/* SkGeLoadLnkSyncCnt*/
+#endif	/* SK_LNK_SYNC_CNT */
+
+#if defined(SK_DIAG) || defined(SK_CFG_SYNC)
+/******************************************************************************
+ *
+ *	SkGeCfgSync() - Configure synchronous bandwidth for this port.
+ *
+ * Description:
+ *	This function may be used to configure synchronous bandwidth
+ *	to the specified port. This may be done any time after
+ *	initializing the port. The configuration values are NOT saved
+ *	in the HWAC port structure and will be overwritten any
+ *	time when stopping and starting the port.
+ *	Any values for the synchronous configuration will be ignored
+ *	if the size of the synchronous queue is zero!
+ *
+ *	The default configuration for the synchronous service is
+ *	TXA_ENA_FSYNC. This means if the size of
+ *	the synchronous queue is unequal zero but no specific
+ *	synchronous bandwidth is configured, the synchronous queue
+ *	will always have the 'unlimited' transmit priority!
+ *
+ *	This mode will be restored if the synchronous bandwidth is
+ *	deallocated ('IntTime' = 0 and 'LimCount' = 0).
+ *
+ * Returns:
+ *	0:	success
+ *	1:	parameter configuration error
+ *	2:	try to configure quality of service although no
+ *		synchronous queue is configured
+ */
+int SkGeCfgSync(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_U32	IntTime,	/* Interval Timer Value in units of 8ns */
+SK_U32	LimCount,	/* Number of bytes to transfer during IntTime */
+int		SyncMode)	/* Sync Mode: TXA_ENA_ALLOC | TXA_DIS_ALLOC | 0 */
+{
+	int Rtv;
+
+	Rtv = 0;
+
+	/* check the parameters */
+	if (LimCount > IntTime ||
+		(LimCount == 0 && IntTime != 0) ||
+		(LimCount != 0 && IntTime == 0)) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG);
+		return(1);
+	}
+	
+	if (pAC->GIni.GP[Port].PXSQSize == 0) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E009, SKERR_HWI_E009MSG);
+		return(2);
+	}
+	
+	/* calculate register values */
+	IntTime = (IntTime / 2) * pAC->GIni.GIHstClkFact / 100;
+	LimCount = LimCount / 8;
+	
+	if (IntTime > TXA_MAX_VAL || LimCount > TXA_MAX_VAL) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E010, SKERR_HWI_E010MSG);
+		return(1);
+	}
+
+	/*
+	 * - Enable 'Force Sync' to ensure the synchronous queue
+	 *   has the priority while configuring the new values.
+	 * - Also 'disable alloc' to ensure the settings complies
+	 *   to the SyncMode parameter.
+	 * - Disable 'Rate Control' to configure the new values.
+	 * - write IntTime and LimCount
+	 * - start 'Rate Control' and disable 'Force Sync'
+	 *   if Interval Timer or Limit Counter not zero.
+	 */
+	SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
+		TXA_ENA_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
+	
+	SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), IntTime);
+	SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), LimCount);
+	
+	SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
+		(SK_U8)(SyncMode & (TXA_ENA_ALLOC | TXA_DIS_ALLOC)));
+	
+	if (IntTime != 0 || LimCount != 0) {
+		SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_DIS_FSYNC | TXA_START_RC);
+	}
+
+	return(0);
+}	/* SkGeCfgSync */
+#endif /* SK_DIAG || SK_CFG_SYNC*/
+
+
+/******************************************************************************
+ *
+ *	DoInitRamQueue() - Initialize the RAM Buffer Address of a single Queue
+ *
+ * Desccription:
+ *	If the queue is used, enable and initialize it.
+ *	Make sure the queue is still reset, if it is not used.
+ *
+ * Returns:
+ *	nothing
+ */
+static void DoInitRamQueue(
+SK_AC	*pAC,			/* adapter context */
+SK_IOC	IoC,			/* IO context */
+int		QuIoOffs,		/* Queue IO Address Offset */
+SK_U32	QuStartAddr,	/* Queue Start Address */
+SK_U32	QuEndAddr,		/* Queue End Address */
+int		QuType)			/* Queue Type (SK_RX_SRAM_Q|SK_RX_BRAM_Q|SK_TX_RAM_Q) */
+{
+	SK_U32	RxUpThresVal;
+	SK_U32	RxLoThresVal;
+
+	if (QuStartAddr != QuEndAddr) {
+		/* calculate thresholds, assume we have a big Rx queue */
+		RxUpThresVal = (QuEndAddr + 1 - QuStartAddr - SK_RB_ULPP) / 8;
+		RxLoThresVal = (QuEndAddr + 1 - QuStartAddr - SK_RB_LLPP_B)/8;
+
+		/* build HW address format */
+		QuStartAddr = QuStartAddr / 8;
+		QuEndAddr = QuEndAddr / 8;
+
+		/* release local reset */
+		SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_RST_CLR);
+
+		/* configure addresses */
+		SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_START), QuStartAddr);
+		SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_END), QuEndAddr);
+		SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_WP), QuStartAddr);
+		SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RP), QuStartAddr);
+
+		switch (QuType) {
+		case SK_RX_SRAM_Q:
+			/* configure threshold for small Rx Queue */
+			RxLoThresVal += (SK_RB_LLPP_B - SK_RB_LLPP_S) / 8;
+
+			/* continue with SK_RX_BRAM_Q */
+		case SK_RX_BRAM_Q:
+			/* write threshold for Rx Queue */
+
+			SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RX_UTPP), RxUpThresVal);
+			SK_OUT32(IoC, RB_ADDR(QuIoOffs, RB_RX_LTPP), RxLoThresVal);
+
+			/* the high priority threshold not used */
+			break;
+		case SK_TX_RAM_Q:
+			/*
+			 * Do NOT use Store & Forward under normal operation due to
+			 * performance optimization (GENESIS only).
+			 * But if Jumbo Frames are configured (XMAC Tx FIFO is only 4 kB)
+			 * or YUKON is used ((GMAC Tx FIFO is only 1 kB)
+			 * we NEED Store & Forward of the RAM buffer.
+			 */
+			if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK ||
+				pAC->GIni.GIYukon) {
+				/* enable Store & Forward Mode for the Tx Side */
+				SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_ENA_STFWD);
+			}
+			break;
+		}
+
+		/* set queue operational */
+		SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_ENA_OP_MD);
+	}
+	else {
+		/* ensure the queue is still disabled */
+		SK_OUT8(IoC, RB_ADDR(QuIoOffs, RB_CTRL), RB_RST_SET);
+	}
+}	/* DoInitRamQueue */
+
+
+/******************************************************************************
+ *
+ *	SkGeInitRamBufs() - Initialize the RAM Buffer Queues
+ *
+ * Description:
+ *	Initialize all RAM Buffer Queues of the specified port
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInitRamBufs(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT *pPrt;
+	int RxQType;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PRxQSize == SK_MIN_RXQ_SIZE) {
+		RxQType = SK_RX_SRAM_Q; 	/* small Rx Queue */
+	}
+	else {
+		RxQType = SK_RX_BRAM_Q;		/* big Rx Queue */
+	}
+
+	DoInitRamQueue(pAC, IoC, pPrt->PRxQOff, pPrt->PRxQRamStart,
+		pPrt->PRxQRamEnd, RxQType);
+	
+	DoInitRamQueue(pAC, IoC, pPrt->PXsQOff, pPrt->PXsQRamStart,
+		pPrt->PXsQRamEnd, SK_TX_RAM_Q);
+	
+	DoInitRamQueue(pAC, IoC, pPrt->PXaQOff, pPrt->PXaQRamStart,
+		pPrt->PXaQRamEnd, SK_TX_RAM_Q);
+
+}	/* SkGeInitRamBufs */
+
+
+/******************************************************************************
+ *
+ *	SkGeInitRamIface() - Initialize the RAM Interface
+ *
+ * Description:
+ *	This function initializes the Adapters RAM Interface.
+ *
+ * Note:
+ *	This function is used in the diagnostics.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInitRamIface(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	/* release local reset */
+	SK_OUT16(IoC, B3_RI_CTRL, RI_RST_CLR);
+
+	/* configure timeout values */
+	SK_OUT8(IoC, B3_RI_WTO_R1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_WTO_XA1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_WTO_XS1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_R1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_XA1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_XS1, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_WTO_R2, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_WTO_XA2, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_WTO_XS2, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_R2, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_XA2, SK_RI_TO_53);
+	SK_OUT8(IoC, B3_RI_RTO_XS2, SK_RI_TO_53);
+
+}	/* SkGeInitRamIface */
+
+
+/******************************************************************************
+ *
+ *	SkGeInitBmu() - Initialize the BMU state machines
+ *
+ * Description:
+ *	Initialize all BMU state machines of the specified port
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInitBmu(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U32		RxWm;
+	SK_U32		TxWm;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	RxWm = SK_BMU_RX_WM;
+	TxWm = SK_BMU_TX_WM;
+	
+	if (!pAC->GIni.GIPciSlot64 && !pAC->GIni.GIPciClock66) {
+		/* for better performance */
+		RxWm /= 2;
+		TxWm /= 2;
+	}
+
+	/* Rx Queue: Release all local resets and set the watermark */
+	SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_CLR_RESET);
+	SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_F), RxWm);
+
+	/*
+	 * Tx Queue: Release all local resets if the queue is used !
+	 * 		set watermark
+	 */
+	if (pPrt->PXSQSize != 0) {
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_CLR_RESET);
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_F), TxWm);
+	}
+	
+	if (pPrt->PXAQSize != 0) {
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_CLR_RESET);
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_F), TxWm);
+	}
+	/*
+	 * Do NOT enable the descriptor poll timers here, because
+	 * the descriptor addresses are not specified yet.
+	 */
+}	/* SkGeInitBmu */
+
+
+/******************************************************************************
+ *
+ *	TestStopBit() -	Test the stop bit of the queue
+ *
+ * Description:
+ *	Stopping a queue is not as simple as it seems to be.
+ *	If descriptor polling is enabled, it may happen
+ *	that RX/TX stop is done and SV idle is NOT set.
+ *	In this case we have to issue another stop command.
+ *
+ * Returns:
+ *	The queues control status register
+ */
+static SK_U32 TestStopBit(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO Context */
+int		QuIoOffs)	/* Queue IO Address Offset */
+{
+	SK_U32	QuCsr;	/* CSR contents */
+
+	SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr);
+	
+	if ((QuCsr & (CSR_STOP | CSR_SV_IDLE)) == 0) {
+		/* Stop Descriptor overridden by start command */
+		SK_OUT32(IoC, Q_ADDR(QuIoOffs, Q_CSR), CSR_STOP);
+
+		SK_IN32(IoC, Q_ADDR(QuIoOffs, Q_CSR), &QuCsr);
+	}
+	
+	return(QuCsr);
+}	/* TestStopBit */
+
+
+/******************************************************************************
+ *
+ *	SkGeStopPort() - Stop the Rx/Tx activity of the port 'Port'.
+ *
+ * Description:
+ *	After calling this function the descriptor rings and Rx and Tx
+ *	queues of this port may be reconfigured.
+ *
+ *	It is possible to stop the receive and transmit path separate or
+ *	both together.
+ *
+ *	Dir =	SK_STOP_TX 	Stops the transmit path only and resets the MAC.
+ *				The receive queue is still active and
+ *				the pending Rx frames may be still transferred
+ *				into the RxD.
+ *		SK_STOP_RX	Stop the receive path. The tansmit path
+ *				has to be stopped once before.
+ *		SK_STOP_ALL	SK_STOP_TX + SK_STOP_RX
+ *
+ *	RstMode = SK_SOFT_RST	Resets the MAC. The PHY is still alive.
+ *			SK_HARD_RST	Resets the MAC and the PHY.
+ *
+ * Example:
+ *	1) A Link Down event was signaled for a port. Therefore the activity
+ *	of this port should be stopped and a hardware reset should be issued
+ *	to enable the workaround of XMAC Errata #2. But the received frames
+ *	should not be discarded.
+ *		...
+ *		SkGeStopPort(pAC, IoC, Port, SK_STOP_TX, SK_HARD_RST);
+ *		(transfer all pending Rx frames)
+ *		SkGeStopPort(pAC, IoC, Port, SK_STOP_RX, SK_HARD_RST);
+ *		...
+ *
+ *	2) An event was issued which request the driver to switch
+ *	the 'virtual active' link to an other already active port
+ *	as soon as possible. The frames in the receive queue of this
+ *	port may be lost. But the PHY must not be reset during this
+ *	event.
+ *		...
+ *		SkGeStopPort(pAC, IoC, Port, SK_STOP_ALL, SK_SOFT_RST);
+ *		...
+ *
+ * Extended Description:
+ *	If SK_STOP_TX is set,
+ *		o disable the MAC's receive and transmitter to prevent
+ *		  from sending incomplete frames
+ *		o stop the port's transmit queues before terminating the
+ *		  BMUs to prevent from performing incomplete PCI cycles
+ *		  on the PCI bus
+ *		- The network Rx and Tx activity and PCI Tx transfer is
+ *		  disabled now.
+ *		o reset the MAC depending on the RstMode
+ *		o Stop Interval Timer and Limit Counter of Tx Arbiter,
+ *		  also disable Force Sync bit and Enable Alloc bit.
+ *		o perform a local reset of the port's Tx path
+ *			- reset the PCI FIFO of the async Tx queue
+ *			- reset the PCI FIFO of the sync Tx queue
+ *			- reset the RAM Buffer async Tx queue
+ *			- reset the RAM Buffer sync Tx queue
+ *			- reset the MAC Tx FIFO
+ *		o switch Link and Tx LED off, stop the LED counters
+ *
+ *	If SK_STOP_RX is set,
+ *		o stop the port's receive queue
+ *		- The path data transfer activity is fully stopped now.
+ *		o perform a local reset of the port's Rx path
+ *			- reset the PCI FIFO of the Rx queue
+ *			- reset the RAM Buffer receive queue
+ *			- reset the MAC Rx FIFO
+ *		o switch Rx LED off, stop the LED counter
+ *
+ *	If all ports are stopped,
+ *		o reset the RAM Interface.
+ *
+ * Notes:
+ *	o This function may be called during the driver states RESET_PORT and
+ *	  SWITCH_PORT.
+ */
+void SkGeStopPort(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* I/O context */
+int		Port,	/* port to stop (MAC_1 + n) */
+int		Dir,	/* Direction to Stop (SK_STOP_RX, SK_STOP_TX, SK_STOP_ALL) */
+int		RstMode)/* Reset Mode (SK_SOFT_RST, SK_HARD_RST) */
+{
+#ifndef SK_DIAG
+	SK_EVPARA Para;
+#endif /* !SK_DIAG */
+	SK_GEPORT *pPrt;
+	SK_U32	DWord;
+	SK_U32	XsCsr;
+	SK_U32	XaCsr;
+	SK_U64	ToutStart;
+	int		i;
+	int		ToutCnt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if ((Dir & SK_STOP_TX) != 0) {
+		/* disable receiver and transmitter */
+		SkMacRxTxDisable(pAC, IoC, Port);
+		
+		/* stop both transmit queues */
+		/*
+		 * If the BMU is in the reset state CSR_STOP will terminate
+		 * immediately.
+		 */
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_STOP);
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_STOP);
+
+		ToutStart = SkOsGetTime(pAC);
+		ToutCnt = 0;
+		do {
+			/*
+			 * Clear packet arbiter timeout to make sure
+			 * this loop will terminate.
+			 */
+			SK_OUT16(IoC, B3_PA_CTRL, (SK_U16)((Port == MAC_1) ?
+				PA_CLR_TO_TX1 : PA_CLR_TO_TX2));
+
+			/*
+			 * If the transfer stucks at the MAC the STOP command will not
+			 * terminate if we don't flush the XMAC's transmit FIFO !
+			 */
+			SkMacFlushTxFifo(pAC, IoC, Port);
+
+			XsCsr = TestStopBit(pAC, IoC, pPrt->PXsQOff);
+			XaCsr = TestStopBit(pAC, IoC, pPrt->PXaQOff);
+
+			if (SkOsGetTime(pAC) - ToutStart > (SK_TICKS_PER_SEC / 18)) {
+				/*
+				 * Timeout of 1/18 second reached.
+				 * This needs to be checked at 1/18 sec only.
+				 */
+				ToutCnt++;
+				if (ToutCnt > 1) {
+					/* Might be a problem when the driver event handler
+					 * calls StopPort again. XXX.
+					 */
+
+					/* Fatal Error, Loop aborted */
+					SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E018,
+						SKERR_HWI_E018MSG);
+#ifndef SK_DIAG
+					Para.Para64 = Port;
+					SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+#endif /* !SK_DIAG */
+					return;
+				}
+				/*
+				 * Cache incoherency workaround: Assume a start command
+				 * has been lost while sending the frame.
+				 */
+				ToutStart = SkOsGetTime(pAC);
+
+				if ((XsCsr & CSR_STOP) != 0) {
+					SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_START);
+				}
+				if ((XaCsr & CSR_STOP) != 0) {
+					SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_START);
+				}
+			}
+
+			/*
+			 * Because of the ASIC problem report entry from 21.08.1998 it is
+			 * required to wait until CSR_STOP is reset and CSR_SV_IDLE is set.
+			 */
+		} while ((XsCsr & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE ||
+				 (XaCsr & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE);
+
+		/* Reset the MAC depending on the RstMode */
+		if (RstMode == SK_SOFT_RST) {
+			SkMacSoftRst(pAC, IoC, Port);
+		}
+		else {
+			SkMacHardRst(pAC, IoC, Port);
+		}
+ 		
+		/* Disable Force Sync bit and Enable Alloc bit */
+		SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL),
+			TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
+		
+		/* Stop Interval Timer and Limit Counter of Tx Arbiter */
+		SK_OUT32(IoC, MR_ADDR(Port, TXA_ITI_INI), 0L);
+		SK_OUT32(IoC, MR_ADDR(Port, TXA_LIM_INI), 0L);
+
+		/* Perform a local reset of the port's Tx path */
+
+		/* Reset the PCI FIFO of the async Tx queue */
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXaQOff, Q_CSR), CSR_SET_RESET);
+		/* Reset the PCI FIFO of the sync Tx queue */
+		SK_OUT32(IoC, Q_ADDR(pPrt->PXsQOff, Q_CSR), CSR_SET_RESET);
+		/* Reset the RAM Buffer async Tx queue */
+		SK_OUT8(IoC, RB_ADDR(pPrt->PXaQOff, RB_CTRL), RB_RST_SET);
+		/* Reset the RAM Buffer sync Tx queue */
+		SK_OUT8(IoC, RB_ADDR(pPrt->PXsQOff, RB_CTRL), RB_RST_SET);
+		
+		/* Reset Tx MAC FIFO */
+#ifdef GENESIS
+		if (pAC->GIni.GIGenesis) {
+			/* Note: MFF_RST_SET does NOT reset the XMAC ! */
+			SK_OUT8(IoC, MR_ADDR(Port, TX_MFF_CTRL2), MFF_RST_SET);
+
+			/* switch Link and Tx LED off, stop the LED counters */
+			/* Link LED is switched off by the RLMT and the Diag itself */
+			SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_DIS);
+		}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+		if (pAC->GIni.GIYukon) {
+			/* Reset TX MAC FIFO */
+			SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_RST_SET);
+		}
+#endif /* YUKON */
+	}
+
+	if ((Dir & SK_STOP_RX) != 0) {
+		/*
+		 * The RX Stop Command will not terminate if no buffers
+		 * are queued in the RxD ring. But it will always reach
+		 * the Idle state. Therefore we can use this feature to
+		 * stop the transfer of received packets.
+		 */
+		/* stop the port's receive queue */
+		SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_STOP);
+		
+		i = 100;
+		do {
+			/*
+			 * Clear packet arbiter timeout to make sure
+			 * this loop will terminate
+			 */
+			SK_OUT16(IoC, B3_PA_CTRL, (SK_U16)((Port == MAC_1) ?
+				PA_CLR_TO_RX1 : PA_CLR_TO_RX2));
+
+			DWord = TestStopBit(pAC, IoC, pPrt->PRxQOff);
+
+			/* timeout if i==0 (bug fix for #10748) */
+			if (--i == 0) {
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E024,
+					SKERR_HWI_E024MSG);
+				break;
+			}
+			/*
+			 * because of the ASIC problem report entry from 21.08.98
+			 * it is required to wait until CSR_STOP is reset and
+			 * CSR_SV_IDLE is set.
+			 */
+		} while ((DWord & (CSR_STOP | CSR_SV_IDLE)) != CSR_SV_IDLE);
+
+		/* The path data transfer activity is fully stopped now */
+
+		/* Perform a local reset of the port's Rx path */
+
+		 /*	Reset the PCI FIFO of the Rx queue */
+		SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), CSR_SET_RESET);
+		/* Reset the RAM Buffer receive queue */
+		SK_OUT8(IoC, RB_ADDR(pPrt->PRxQOff, RB_CTRL), RB_RST_SET);
+
+		/* Reset Rx MAC FIFO */
+#ifdef GENESIS
+		if (pAC->GIni.GIGenesis) {
+			
+			SK_OUT8(IoC, MR_ADDR(Port, RX_MFF_CTRL2), MFF_RST_SET);
+
+			/* switch Rx LED off, stop the LED counter */
+			SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_DIS);
+		}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+		if (pAC->GIni.GIYukon) {
+			/* Reset Rx MAC FIFO */
+			SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_RST_SET);
+		}
+#endif /* YUKON */
+	}
+}	/* SkGeStopPort */
+
+
+/******************************************************************************
+ *
+ *	SkGeInit0() - Level 0 Initialization
+ *
+ * Description:
+ *	- Initialize the BMU address offsets
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInit0(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	int i;
+	SK_GEPORT *pPrt;
+
+	for (i = 0; i < SK_MAX_MACS; i++) {
+		pPrt = &pAC->GIni.GP[i];
+
+		pPrt->PState = SK_PRT_RESET;
+		pPrt->PRxQOff = QOffTab[i].RxQOff;
+		pPrt->PXsQOff = QOffTab[i].XsQOff;
+		pPrt->PXaQOff = QOffTab[i].XaQOff;
+		pPrt->PCheckPar = SK_FALSE;
+		pPrt->PIsave = 0;
+		pPrt->PPrevShorts = 0;
+		pPrt->PLinkResCt = 0;
+		pPrt->PAutoNegTOCt = 0;
+		pPrt->PPrevRx = 0;
+		pPrt->PPrevFcs = 0;
+		pPrt->PRxLim = SK_DEF_RX_WA_LIM;
+		pPrt->PLinkMode = (SK_U8)SK_LMODE_AUTOFULL;
+		pPrt->PLinkSpeedCap = (SK_U8)SK_LSPEED_CAP_1000MBPS;
+		pPrt->PLinkSpeed = (SK_U8)SK_LSPEED_1000MBPS;
+		pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_UNKNOWN;
+		pPrt->PLinkModeConf = (SK_U8)SK_LMODE_AUTOSENSE;
+		pPrt->PFlowCtrlMode = (SK_U8)SK_FLOW_MODE_SYM_OR_REM;
+		pPrt->PLinkCap = (SK_U8)(SK_LMODE_CAP_HALF | SK_LMODE_CAP_FULL |
+			SK_LMODE_CAP_AUTOHALF | SK_LMODE_CAP_AUTOFULL);
+		pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN;
+		pPrt->PFlowCtrlCap = (SK_U8)SK_FLOW_MODE_SYM_OR_REM;
+		pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE;
+		pPrt->PMSCap = 0;
+		pPrt->PMSMode = (SK_U8)SK_MS_MODE_AUTO;
+		pPrt->PMSStatus = (SK_U8)SK_MS_STAT_UNSET;
+		pPrt->PLipaAutoNeg = (SK_U8)SK_LIPA_UNKNOWN;
+		pPrt->PAutoNegFail = SK_FALSE;
+		pPrt->PHWLinkUp = SK_FALSE;
+		pPrt->PLinkBroken = SK_TRUE; /* See WA code */
+		pPrt->PPhyPowerState = PHY_PM_OPERATIONAL_MODE;
+		pPrt->PMacColThres = TX_COL_DEF;
+		pPrt->PMacJamLen = TX_JAM_LEN_DEF;
+		pPrt->PMacJamIpgVal	= TX_JAM_IPG_DEF;
+		pPrt->PMacJamIpgData = TX_IPG_JAM_DEF;
+		pPrt->PMacIpgData = IPG_DATA_DEF;
+		pPrt->PMacLimit4 = SK_FALSE;
+	}
+
+	pAC->GIni.GIPortUsage = SK_RED_LINK;
+	pAC->GIni.GILedBlinkCtrl = (SK_U16)OemConfig.Value;
+	pAC->GIni.GIValIrqMask = IS_ALL_MSK;
+
+}	/* SkGeInit0*/
+
+
+/******************************************************************************
+ *
+ *	SkGeInit1() - Level 1 Initialization
+ *
+ * Description:
+ *	o Do a software reset.
+ *	o Clear all reset bits.
+ *	o Verify that the detected hardware is present.
+ *	  Return an error if not.
+ *	o Get the hardware configuration
+ *		+ Read the number of MACs/Ports.
+ *		+ Read the RAM size.
+ *		+ Read the PCI Revision Id.
+ *		+ Find out the adapters host clock speed
+ *		+ Read and check the PHY type
+ *
+ * Returns:
+ *	0:	success
+ *	5:	Unexpected PHY type detected
+ *	6:	HW self test failed
+ */
+static int SkGeInit1(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	SK_U8	Byte;
+	SK_U16	Word;
+	SK_U16	CtrlStat;
+	SK_U32	DWord;
+	int	RetVal;
+	int	i;
+
+	RetVal = 0;
+
+	/* save CLK_RUN bits (YUKON-Lite) */
+	SK_IN16(IoC, B0_CTST, &CtrlStat);
+
+	/* do the SW-reset */
+	SK_OUT8(IoC, B0_CTST, CS_RST_SET);
+
+	/* release the SW-reset */
+	SK_OUT8(IoC, B0_CTST, CS_RST_CLR);
+
+	/* reset all error bits in the PCI STATUS register */
+	/*
+	 * Note: PCI Cfg cycles cannot be used, because they are not
+	 *		 available on some platforms after 'boot time'.
+	 */
+	SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
+	
+	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+	SK_OUT16(IoC, PCI_C(PCI_STATUS), (SK_U16)(Word | PCI_ERRBITS));
+	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+	/* release Master Reset */
+	SK_OUT8(IoC, B0_CTST, CS_MRST_CLR);
+
+#ifdef CLK_RUN
+	CtrlStat |= CS_CLK_RUN_ENA;
+#endif /* CLK_RUN */
+
+	/* restore CLK_RUN bits */
+	SK_OUT16(IoC, B0_CTST, (SK_U16)(CtrlStat &
+		(CS_CLK_RUN_HOT | CS_CLK_RUN_RST | CS_CLK_RUN_ENA)));
+
+	/* read Chip Identification Number */
+	SK_IN8(IoC, B2_CHIP_ID, &Byte);
+	pAC->GIni.GIChipId = Byte;
+	
+	/* read number of MACs */
+	SK_IN8(IoC, B2_MAC_CFG, &Byte);
+	pAC->GIni.GIMacsFound = (Byte & CFG_SNG_MAC) ? 1 : 2;
+	
+	/* get Chip Revision Number */
+	pAC->GIni.GIChipRev = (SK_U8)((Byte & CFG_CHIP_R_MSK) >> 4);
+
+	/* get diff. PCI parameters */
+	SK_IN16(IoC, B0_CTST, &CtrlStat);
+	
+	/* read the adapters RAM size */
+	SK_IN8(IoC, B2_E_0, &Byte);
+	
+	pAC->GIni.GIGenesis = SK_FALSE;
+	pAC->GIni.GIYukon = SK_FALSE;
+	pAC->GIni.GIYukonLite = SK_FALSE;
+
+#ifdef GENESIS
+	if (pAC->GIni.GIChipId == CHIP_ID_GENESIS) {
+
+		pAC->GIni.GIGenesis = SK_TRUE;
+
+		if (Byte == (SK_U8)3) {						
+			/* special case: 4 x 64k x 36, offset = 0x80000 */
+			pAC->GIni.GIRamSize = 1024;
+			pAC->GIni.GIRamOffs = (SK_U32)512 * 1024;
+		}
+		else {
+			pAC->GIni.GIRamSize = (int)Byte * 512;
+			pAC->GIni.GIRamOffs = 0;
+		}
+		/* all GE adapters work with 53.125 MHz host clock */
+		pAC->GIni.GIHstClkFact = SK_FACT_53;
+		
+		/* set Descr. Poll Timer Init Value to 250 ms */
+		pAC->GIni.GIPollTimerVal =
+			SK_DPOLL_DEF * (SK_U32)pAC->GIni.GIHstClkFact / 100;
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIChipId != CHIP_ID_GENESIS) {
+		
+		pAC->GIni.GIYukon = SK_TRUE;
+		
+		pAC->GIni.GIRamSize = (Byte == (SK_U8)0) ? 128 : (int)Byte * 4;
+		
+		pAC->GIni.GIRamOffs = 0;
+		
+		/* WA for chip Rev. A */
+		pAC->GIni.GIWolOffs = (pAC->GIni.GIChipId == CHIP_ID_YUKON &&
+			pAC->GIni.GIChipRev == 0) ? WOL_REG_OFFS : 0;
+		
+		/* get PM Capabilities of PCI config space */
+		SK_IN16(IoC, PCI_C(PCI_PM_CAP_REG), &Word);
+
+		/* check if VAUX is available */
+		if (((CtrlStat & CS_VAUX_AVAIL) != 0) &&
+			/* check also if PME from D3cold is set */
+			((Word & PCI_PME_D3C_SUP) != 0)) {
+			/* set entry in GE init struct */
+			pAC->GIni.GIVauxAvail = SK_TRUE;
+		}
+		
+		if (pAC->GIni.GIChipId == CHIP_ID_YUKON_LITE) {
+			/* this is Rev. A1 */
+			pAC->GIni.GIYukonLite = SK_TRUE;
+		}
+		else {
+			/* save Flash-Address Register */
+			SK_IN32(IoC, B2_FAR, &DWord);
+
+			/* test Flash-Address Register */
+			SK_OUT8(IoC, B2_FAR + 3, 0xff);
+			SK_IN8(IoC, B2_FAR + 3, &Byte);
+
+			if (Byte != 0) {
+				/* this is Rev. A0 */
+				pAC->GIni.GIYukonLite = SK_TRUE;
+
+				/* restore Flash-Address Register */
+				SK_OUT32(IoC, B2_FAR, DWord);
+			}
+		}
+
+		/* switch power to VCC (WA for VAUX problem) */
+		SK_OUT8(IoC, B0_POWER_CTRL, (SK_U8)(PC_VAUX_ENA | PC_VCC_ENA |
+			PC_VAUX_OFF | PC_VCC_ON));
+
+		/* read the Interrupt source */
+		SK_IN32(IoC, B0_ISRC, &DWord);
+		
+		if ((DWord & IS_HW_ERR) != 0) {
+			/* read the HW Error Interrupt source */
+			SK_IN32(IoC, B0_HWE_ISRC, &DWord);
+			
+			if ((DWord & IS_IRQ_SENSOR) != 0) {
+				/* disable HW Error IRQ */
+				pAC->GIni.GIValIrqMask &= ~IS_HW_ERR;
+			}
+		}
+		
+		for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+			/* set GMAC Link Control reset */
+			SK_OUT16(IoC, MR_ADDR(i, GMAC_LINK_CTRL), GMLC_RST_SET);
+
+			/* clear GMAC Link Control reset */
+			SK_OUT16(IoC, MR_ADDR(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
+		}
+		/* all YU chips work with 78.125 MHz host clock */
+		pAC->GIni.GIHstClkFact = SK_FACT_78;
+		
+		pAC->GIni.GIPollTimerVal = SK_DPOLL_MAX;	/* 215 ms */
+	}
+#endif /* YUKON */
+
+	/* check if 64-bit PCI Slot is present */
+	pAC->GIni.GIPciSlot64 = (SK_BOOL)((CtrlStat & CS_BUS_SLOT_SZ) != 0);
+	
+	/* check if 66 MHz PCI Clock is active */
+	pAC->GIni.GIPciClock66 = (SK_BOOL)((CtrlStat & CS_BUS_CLOCK) != 0);
+
+	/* read PCI HW Revision Id. */
+	SK_IN8(IoC, PCI_C(PCI_REV_ID), &Byte);
+	pAC->GIni.GIPciHwRev = Byte;
+
+	/* read the PMD type */
+	SK_IN8(IoC, B2_PMD_TYP, &Byte);
+	pAC->GIni.GICopperType = (SK_U8)(Byte == 'T');
+
+	/* read the PHY type */
+	SK_IN8(IoC, B2_E_1, &Byte);
+
+	Byte &= 0x0f;	/* the PHY type is stored in the lower nibble */
+	for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+		
+#ifdef GENESIS
+		if (pAC->GIni.GIGenesis) {
+			switch (Byte) {
+			case SK_PHY_XMAC:
+				pAC->GIni.GP[i].PhyAddr = PHY_ADDR_XMAC;
+				break;
+			case SK_PHY_BCOM:
+				pAC->GIni.GP[i].PhyAddr = PHY_ADDR_BCOM;
+				pAC->GIni.GP[i].PMSCap = (SK_U8)(SK_MS_CAP_AUTO |
+					SK_MS_CAP_MASTER | SK_MS_CAP_SLAVE);
+				break;
+#ifdef OTHER_PHY
+			case SK_PHY_LONE:
+				pAC->GIni.GP[i].PhyAddr = PHY_ADDR_LONE;
+				break;
+			case SK_PHY_NAT:
+				pAC->GIni.GP[i].PhyAddr = PHY_ADDR_NAT;
+				break;
+#endif /* OTHER_PHY */
+			default:
+				/* ERROR: unexpected PHY type detected */
+				RetVal = 5;
+				break;
+			}
+		}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+		if (pAC->GIni.GIYukon) {
+			
+			if (Byte < (SK_U8)SK_PHY_MARV_COPPER) {
+				/* if this field is not initialized */
+				Byte = (SK_U8)SK_PHY_MARV_COPPER;
+				
+				pAC->GIni.GICopperType = SK_TRUE;
+			}
+			
+			pAC->GIni.GP[i].PhyAddr = PHY_ADDR_MARV;
+			
+			if (pAC->GIni.GICopperType) {
+
+				pAC->GIni.GP[i].PLinkSpeedCap = (SK_U8)(SK_LSPEED_CAP_AUTO |
+					SK_LSPEED_CAP_10MBPS | SK_LSPEED_CAP_100MBPS |
+					SK_LSPEED_CAP_1000MBPS);
+				
+				pAC->GIni.GP[i].PLinkSpeed = (SK_U8)SK_LSPEED_AUTO;
+				
+				pAC->GIni.GP[i].PMSCap = (SK_U8)(SK_MS_CAP_AUTO |
+					SK_MS_CAP_MASTER | SK_MS_CAP_SLAVE);
+			}
+			else {
+				Byte = (SK_U8)SK_PHY_MARV_FIBER;
+			}
+		}
+#endif /* YUKON */
+		
+		pAC->GIni.GP[i].PhyType = (int)Byte;
+		
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+			("PHY type: %d  PHY addr: %04x\n", Byte,
+			pAC->GIni.GP[i].PhyAddr));
+	}
+	
+	/* get MAC Type & set function pointers dependent on */
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+		
+		pAC->GIni.GIMacType = SK_MAC_XMAC;
+
+		pAC->GIni.GIFunc.pFnMacUpdateStats	= SkXmUpdateStats;
+		pAC->GIni.GIFunc.pFnMacStatistic	= SkXmMacStatistic;
+		pAC->GIni.GIFunc.pFnMacResetCounter	= SkXmResetCounter;
+		pAC->GIni.GIFunc.pFnMacOverflow		= SkXmOverflowStatus;
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		
+		pAC->GIni.GIMacType = SK_MAC_GMAC;
+
+		pAC->GIni.GIFunc.pFnMacUpdateStats	= SkGmUpdateStats;
+		pAC->GIni.GIFunc.pFnMacStatistic	= SkGmMacStatistic;
+		pAC->GIni.GIFunc.pFnMacResetCounter	= SkGmResetCounter;
+		pAC->GIni.GIFunc.pFnMacOverflow		= SkGmOverflowStatus;
+
+#ifdef SPECIAL_HANDLING
+		if (pAC->GIni.GIChipId == CHIP_ID_YUKON) {
+			/* check HW self test result */
+			SK_IN8(IoC, B2_E_3, &Byte);
+			if (Byte & B2_E3_RES_MASK) {
+				RetVal = 6;
+			}
+		}
+#endif
+	}
+#endif /* YUKON */
+	
+	return(RetVal);
+}	/* SkGeInit1 */
+
+
+/******************************************************************************
+ *
+ *	SkGeInit2() - Level 2 Initialization
+ *
+ * Description:
+ *	- start the Blink Source Counter
+ *	- start the Descriptor Poll Timer
+ *	- configure the MAC-Arbiter
+ *	- configure the Packet-Arbiter
+ *	- enable the Tx Arbiters
+ *	- enable the RAM Interface Arbiter
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGeInit2(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+#ifdef GENESIS
+	SK_U32	DWord;
+#endif /* GENESIS */
+	int		i;
+
+	/* start the Descriptor Poll Timer */
+	if (pAC->GIni.GIPollTimerVal != 0) {
+		if (pAC->GIni.GIPollTimerVal > SK_DPOLL_MAX) {
+			pAC->GIni.GIPollTimerVal = SK_DPOLL_MAX;
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E017, SKERR_HWI_E017MSG);
+		}
+		SK_OUT32(IoC, B28_DPT_INI, pAC->GIni.GIPollTimerVal);
+		SK_OUT8(IoC, B28_DPT_CTRL, DPT_START);
+	}
+
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+		/* start the Blink Source Counter */
+		DWord = SK_BLK_DUR * (SK_U32)pAC->GIni.GIHstClkFact / 100;
+
+		SK_OUT32(IoC, B2_BSC_INI, DWord);
+		SK_OUT8(IoC, B2_BSC_CTRL, BSC_START);
+
+		/*
+		 * Configure the MAC Arbiter and the Packet Arbiter.
+		 * They will be started once and never be stopped.
+		 */
+		SkGeInitMacArb(pAC, IoC);
+
+		SkGeInitPktArb(pAC, IoC);
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		/* start Time Stamp Timer */
+		SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_START);
+	}
+#endif /* YUKON */
+
+	/* enable the Tx Arbiters */
+	for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+		SK_OUT8(IoC, MR_ADDR(i, TXA_CTRL), TXA_ENA_ARB);
+	}
+
+	/* enable the RAM Interface Arbiter */
+	SkGeInitRamIface(pAC, IoC);
+
+}	/* SkGeInit2 */
+
+/******************************************************************************
+ *
+ *	SkGeInit() - Initialize the GE Adapter with the specified level.
+ *
+ * Description:
+ *	Level	0:	Initialize the Module structures.
+ *	Level	1:	Generic Hardware Initialization. The IOP/MemBase pointer has
+ *				to be set before calling this level.
+ *
+ *			o Do a software reset.
+ *			o Clear all reset bits.
+ *			o Verify that the detected hardware is present.
+ *			  Return an error if not.
+ *			o Get the hardware configuration
+ *				+ Set GIMacsFound with the number of MACs.
+ *				+ Store the RAM size in GIRamSize.
+ *				+ Save the PCI Revision ID in GIPciHwRev.
+ *			o return an error
+ *				if Number of MACs > SK_MAX_MACS
+ *
+ *			After returning from Level 0 the adapter
+ *			may be accessed with IO operations.
+ *
+ *	Level	2:	start the Blink Source Counter
+ *
+ * Returns:
+ *	0:	success
+ *	1:	Number of MACs exceeds SK_MAX_MACS	(after level 1)
+ *	2:	Adapter not present or not accessible
+ *	3:	Illegal initialization level
+ *	4:	Initialization Level 1 Call missing
+ *	5:	Unexpected PHY type detected
+ *	6:	HW self test failed
+ */
+int	SkGeInit(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Level)		/* initialization level */
+{
+	int		RetVal;		/* return value */
+	SK_U32	DWord;
+
+	RetVal = 0;
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_INIT,
+		("SkGeInit(Level %d)\n", Level));
+
+	switch (Level) {
+	case SK_INIT_DATA:
+		/* Initialization Level 0 */
+		SkGeInit0(pAC, IoC);
+		pAC->GIni.GILevel = SK_INIT_DATA;
+		break;
+	
+	case SK_INIT_IO:
+		/* Initialization Level 1 */
+		RetVal = SkGeInit1(pAC, IoC);
+		if (RetVal != 0) {
+			break;
+		}
+
+		/* check if the adapter seems to be accessible */
+		SK_OUT32(IoC, B2_IRQM_INI, SK_TEST_VAL);
+		SK_IN32(IoC, B2_IRQM_INI, &DWord);
+		SK_OUT32(IoC, B2_IRQM_INI, 0L);
+		
+		if (DWord != SK_TEST_VAL) {
+			RetVal = 2;
+			break;
+		}
+
+		/* check if the number of GIMacsFound matches SK_MAX_MACS */
+		if (pAC->GIni.GIMacsFound > SK_MAX_MACS) {
+			RetVal = 1;
+			break;
+		}
+
+		/* Level 1 successfully passed */
+		pAC->GIni.GILevel = SK_INIT_IO;
+		break;
+	
+	case SK_INIT_RUN:
+		/* Initialization Level 2 */
+		if (pAC->GIni.GILevel != SK_INIT_IO) {
+#ifndef SK_DIAG
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E002, SKERR_HWI_E002MSG);
+#endif /* !SK_DIAG */
+			RetVal = 4;
+			break;
+		}
+		SkGeInit2(pAC, IoC);
+
+		/* Level 2 successfully passed */
+		pAC->GIni.GILevel = SK_INIT_RUN;
+		break;
+	
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E003, SKERR_HWI_E003MSG);
+		RetVal = 3;
+		break;
+	}
+
+	return(RetVal);
+}	/* SkGeInit */
+
+
+/******************************************************************************
+ *
+ *	SkGeDeInit() - Deinitialize the adapter
+ *
+ * Description:
+ *	All ports of the adapter will be stopped if not already done.
+ *	Do a software reset and switch off all LEDs.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGeDeInit(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC)		/* IO context */
+{
+	int	i;
+	SK_U16	Word;
+
+#if (!defined(SK_SLIM) && !defined(VCPU))
+	/* ensure I2C is ready */
+	SkI2cWaitIrq(pAC, IoC);
+#endif	
+
+	/* stop all current transfer activity */
+	for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+		if (pAC->GIni.GP[i].PState != SK_PRT_STOP &&
+			pAC->GIni.GP[i].PState != SK_PRT_RESET) {
+
+			SkGeStopPort(pAC, IoC, i, SK_STOP_ALL, SK_HARD_RST);
+		}
+	}
+
+	/* Reset all bits in the PCI STATUS register */
+	/*
+	 * Note: PCI Cfg cycles cannot be used, because they are not
+	 *	 available on some platforms after 'boot time'.
+	 */
+	SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
+	
+	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+	SK_OUT16(IoC, PCI_C(PCI_STATUS), (SK_U16)(Word | PCI_ERRBITS));
+	SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+	/* do the reset, all LEDs are switched off now */
+	SK_OUT8(IoC, B0_CTST, CS_RST_SET);
+	
+	pAC->GIni.GILevel = SK_INIT_DATA;
+}	/* SkGeDeInit */
+
+
+/******************************************************************************
+ *
+ *	SkGeInitPort()	Initialize the specified port.
+ *
+ * Description:
+ *	PRxQSize, PXSQSize, and PXAQSize has to be
+ *	configured for the specified port before calling this function.
+ *  The descriptor rings has to be initialized too.
+ *
+ *	o (Re)configure queues of the specified port.
+ *	o configure the MAC of the specified port.
+ *	o put ASIC and MAC(s) in operational mode.
+ *	o initialize Rx/Tx and Sync LED
+ *	o initialize RAM Buffers and MAC FIFOs
+ *
+ *	The port is ready to connect when returning.
+ *
+ * Note:
+ *	The MAC's Rx and Tx state machine is still disabled when returning.
+ *
+ * Returns:
+ *	0:	success
+ *	1:	Queue size initialization error. The configured values
+ *		for PRxQSize, PXSQSize, or PXAQSize are invalid for one
+ *		or more queues. The specified port was NOT initialized.
+ *		An error log entry was generated.
+ *	2:	The port has to be stopped before it can be initialized again.
+ */
+int SkGeInitPort(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port to configure */
+{
+	SK_GEPORT *pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (SkGeCheckQSize(pAC, Port) != 0) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E004, SKERR_HWI_E004MSG);
+		return(1);
+	}
+	
+	if (pPrt->PState == SK_PRT_INIT || pPrt->PState == SK_PRT_RUN) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E005, SKERR_HWI_E005MSG);
+		return(2);
+	}
+
+	/* configuration ok, initialize the Port now */
+
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+		/* initialize Rx, Tx and Link LED */
+		/*
+		 * If 1000BT Phy needs LED initialization than swap
+		 * LED and XMAC initialization order
+		 */
+		SkGeXmitLED(pAC, IoC, MR_ADDR(Port, TX_LED_INI), SK_LED_ENA);
+		SkGeXmitLED(pAC, IoC, MR_ADDR(Port, RX_LED_INI), SK_LED_ENA);
+		/* The Link LED is initialized by RLMT or Diagnostics itself */
+		
+		SkXmInitMac(pAC, IoC, Port);
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+
+		SkGmInitMac(pAC, IoC, Port);
+	}
+#endif /* YUKON */
+	
+	/* do NOT initialize the Link Sync Counter */
+
+	SkGeInitMacFifo(pAC, IoC, Port);
+	
+	SkGeInitRamBufs(pAC, IoC, Port);
+	
+	if (pPrt->PXSQSize != 0) {
+		/* enable Force Sync bit if synchronous queue available */
+		SK_OUT8(IoC, MR_ADDR(Port, TXA_CTRL), TXA_ENA_FSYNC);
+	}
+	
+	SkGeInitBmu(pAC, IoC, Port);
+
+	/* mark port as initialized */
+	pPrt->PState = SK_PRT_INIT;
+
+	return(0);
+}	/* SkGeInitPort */
diff --git a/drivers/net/sk98lin/skgemib.c b/drivers/net/sk98lin/skgemib.c
new file mode 100644
index 0000000..0a6f67a
--- /dev/null
+++ b/drivers/net/sk98lin/skgemib.c
@@ -0,0 +1,1075 @@
+/*****************************************************************************
+ *
+ * Name:	skgemib.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.11 $
+ * Date:	$Date: 2003/09/15 13:38:12 $
+ * Purpose:	Private Network Management Interface Management Database
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/*
+ * PRIVATE OID handler function prototypes
+ */
+PNMI_STATIC int Addr(SK_AC *pAC, SK_IOC IoC, int action,
+	SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int CsumStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int General(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Mac8023Stat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int MacPrivateConf(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int MacPrivateStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Monitor(SK_AC *pAC, SK_IOC IoC, int action,
+	SK_U32 Id, char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int OidStruct(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Perform(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int* pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Rlmt(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int RlmtStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int SensorStat(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Vpd(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC int Vct(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+
+#ifdef SK_POWER_MGMT
+PNMI_STATIC int PowerManagement(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+#endif /* SK_POWER_MGMT */
+
+#ifdef SK_DIAG_SUPPORT
+PNMI_STATIC int DiagActions(SK_AC *pAC, SK_IOC IoC, int action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance,
+	unsigned int TableIndex, SK_U32 NetIndex);
+#endif /* SK_DIAG_SUPPORT */
+
+
+/* defines *******************************************************************/
+#define ID_TABLE_SIZE (sizeof(IdTable)/sizeof(IdTable[0]))
+
+
+/* global variables **********************************************************/
+
+/*
+ * Table to correlate OID with handler function and index to
+ * hardware register stored in StatAddress if applicable.
+ */
+PNMI_STATIC const SK_PNMI_TAB_ENTRY IdTable[] = {
+	{OID_GEN_XMIT_OK,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX},
+	{OID_GEN_RCV_OK,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX},
+	{OID_GEN_XMIT_ERROR,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_GEN_RCV_ERROR,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_GEN_RCV_NO_BUFFER,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_GEN_DIRECTED_FRAMES_XMIT,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_UNICAST},
+	{OID_GEN_MULTICAST_FRAMES_XMIT,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_MULTICAST},
+	{OID_GEN_BROADCAST_FRAMES_XMIT,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_BROADCAST},
+	{OID_GEN_DIRECTED_FRAMES_RCV,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_UNICAST},
+	{OID_GEN_MULTICAST_FRAMES_RCV,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_MULTICAST},
+	{OID_GEN_BROADCAST_FRAMES_RCV,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_BROADCAST},
+	{OID_GEN_RCV_CRC_ERROR,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_FCS},
+	{OID_GEN_TRANSMIT_QUEUE_LENGTH,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_802_3_PERMANENT_ADDRESS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, 0},
+	{OID_802_3_CURRENT_ADDRESS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, 0},
+	{OID_802_3_RCV_ERROR_ALIGNMENT,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_FRAMING},
+	{OID_802_3_XMIT_ONE_COLLISION,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_SINGLE_COL},
+	{OID_802_3_XMIT_MORE_COLLISIONS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_MULTI_COL},
+	{OID_802_3_XMIT_DEFERRED,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_DEFFERAL},
+	{OID_802_3_XMIT_MAX_COLLISIONS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_EXCESS_COL},
+	{OID_802_3_RCV_OVERRUN,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HRX_OVERFLOW},
+	{OID_802_3_XMIT_UNDERRUN,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_UNDERRUN},
+	{OID_802_3_XMIT_TIMES_CRS_LOST,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_CARRIER},
+	{OID_802_3_XMIT_LATE_COLLISIONS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Mac8023Stat, SK_PNMI_HTX_LATE_COL},
+#ifdef SK_POWER_MGMT
+	{OID_PNP_CAPABILITIES,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, PowerManagement, 0},
+	{OID_PNP_SET_POWER,
+		0,
+		0,
+		0,
+		SK_PNMI_WO, PowerManagement, 0},
+	{OID_PNP_QUERY_POWER,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, PowerManagement, 0},
+	{OID_PNP_ADD_WAKE_UP_PATTERN,
+		0,
+		0,
+		0,
+		SK_PNMI_WO, PowerManagement, 0},
+	{OID_PNP_REMOVE_WAKE_UP_PATTERN,
+		0,
+		0,
+		0,
+		SK_PNMI_WO, PowerManagement, 0},
+	{OID_PNP_ENABLE_WAKE_UP,
+		0,
+		0,
+		0,
+		SK_PNMI_RW, PowerManagement, 0},
+#endif /* SK_POWER_MGMT */
+#ifdef SK_DIAG_SUPPORT
+	{OID_SKGE_DIAG_MODE,
+		0,
+		0,
+		0,
+		SK_PNMI_RW, DiagActions, 0},
+#endif /* SK_DIAG_SUPPORT */
+	{OID_SKGE_MDB_VERSION,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(MgmtDBVersion),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_SUPPORTED_LIST,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_ALL_DATA,
+		0,
+		0,
+		0,
+		SK_PNMI_RW, OidStruct, 0},
+	{OID_SKGE_VPD_FREE_BYTES,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(VpdFreeBytes),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_ENTRIES_LIST,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(VpdEntriesList),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_ENTRIES_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(VpdEntriesNumber),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_KEY,
+		SK_PNMI_VPD_ENTRIES,
+		sizeof(SK_PNMI_VPD),
+		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdKey),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_VALUE,
+		SK_PNMI_VPD_ENTRIES,
+		sizeof(SK_PNMI_VPD),
+		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdValue),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_ACCESS,
+		SK_PNMI_VPD_ENTRIES,
+		sizeof(SK_PNMI_VPD),
+		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdAccess),
+		SK_PNMI_RO, Vpd, 0},
+	{OID_SKGE_VPD_ACTION,
+		SK_PNMI_VPD_ENTRIES,
+		sizeof(SK_PNMI_VPD),
+		SK_PNMI_OFF(Vpd) + SK_PNMI_VPD_OFF(VpdAction),
+		SK_PNMI_RW, Vpd, 0},
+	{OID_SKGE_PORT_NUMBER,		
+		1,
+		0,
+		SK_PNMI_MAI_OFF(PortNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_DEVICE_TYPE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(DeviceType),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_DRIVER_DESCR,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(DriverDescr),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_DRIVER_VERSION,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(DriverVersion),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_DRIVER_RELDATE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(DriverReleaseDate),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_DRIVER_FILENAME,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(DriverFileName),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_HW_DESCR,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(HwDescr),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_HW_VERSION,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(HwVersion),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_CHIPSET,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(Chipset),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_CHIPID,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(ChipId),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RAMSIZE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RamSize),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_VAUXAVAIL,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(VauxAvail),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_ACTION,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(Action),
+		SK_PNMI_RW, Perform, 0},
+	{OID_SKGE_RESULT,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TestResult),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_BUS_TYPE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(BusType),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_BUS_SPEED,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(BusSpeed),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_BUS_WIDTH,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(BusWidth),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_SW_QUEUE_LEN,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxSwQueueLen),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_SW_QUEUE_MAX,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxSwQueueMax),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_RETRY,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxRetryCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_INTR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxIntrCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_INTR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxIntrCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_NO_BUF_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxNoBufCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_NO_BUF_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxNoBufCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_USED_DESCR_NO,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxUsedDescrNo),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_DELIVERED_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxDeliveredCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_OCTETS_DELIV_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxOctetsDeliveredCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RX_HW_ERROR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RxHwErrorsCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TX_HW_ERROR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TxHwErrorsCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_IN_ERRORS_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(InErrorsCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_OUT_ERROR_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(OutErrorsCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_ERR_RECOVERY_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(ErrRecoveryCts),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_SYSUPTIME,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(SysUpTime),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_SENSOR_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(SensorNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_SENSOR_INDEX,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorIndex),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_DESCR,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorDescr),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_TYPE,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorType),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_VALUE,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorValue),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_WAR_THRES_LOW,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningThresholdLow),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_WAR_THRES_UPP,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningThresholdHigh),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_ERR_THRES_LOW,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorThresholdLow),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_ERR_THRES_UPP,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorThresholdHigh),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_STATUS,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorStatus),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_WAR_CTS,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningCts),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_ERR_CTS,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorCts),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_WAR_TIME,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorWarningTimestamp),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_SENSOR_ERR_TIME,
+		SK_PNMI_SENSOR_ENTRIES,
+		sizeof(SK_PNMI_SENSOR),
+		SK_PNMI_OFF(Sensor) + SK_PNMI_SEN_OFF(SensorErrorTimestamp),
+		SK_PNMI_RO, SensorStat, 0},
+	{OID_SKGE_CHKSM_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(ChecksumNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_CHKSM_RX_OK_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxOkCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_CHKSM_RX_UNABLE_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxUnableCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_CHKSM_RX_ERR_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumRxErrCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_CHKSM_TX_OK_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumTxOkCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_CHKSM_TX_UNABLE_CTS,
+		SKCS_NUM_PROTOCOLS,
+		sizeof(SK_PNMI_CHECKSUM),
+		SK_PNMI_OFF(Checksum) + SK_PNMI_CHK_OFF(ChecksumTxUnableCts),
+		SK_PNMI_RO, CsumStat, 0},
+	{OID_SKGE_STAT_TX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX},
+	{OID_SKGE_STAT_TX_OCTETS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxOctetsOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_OCTET},
+	{OID_SKGE_STAT_TX_BROADCAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxBroadcastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_BROADCAST},
+	{OID_SKGE_STAT_TX_MULTICAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMulticastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MULTICAST},
+	{OID_SKGE_STAT_TX_UNICAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxUnicastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_UNICAST},
+	{OID_SKGE_STAT_TX_LONGFRAMES,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxLongFramesCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_LONGFRAMES},
+	{OID_SKGE_STAT_TX_BURST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxBurstCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_BURST},
+	{OID_SKGE_STAT_TX_PFLOWC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxPauseMacCtrlCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_PMACC},
+	{OID_SKGE_STAT_TX_FLOWC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMacCtrlCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MACC},
+	{OID_SKGE_STAT_TX_SINGLE_COL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSingleCollisionCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SINGLE_COL},
+	{OID_SKGE_STAT_TX_MULTI_COL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMultipleCollisionCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MULTI_COL},
+	{OID_SKGE_STAT_TX_EXCESS_COL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxExcessiveCollisionCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_EXCESS_COL},
+	{OID_SKGE_STAT_TX_LATE_COL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxLateCollisionCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_LATE_COL},
+	{OID_SKGE_STAT_TX_DEFFERAL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxDeferralCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_DEFFERAL},
+	{OID_SKGE_STAT_TX_EXCESS_DEF,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxExcessiveDeferralCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_EXCESS_DEF},
+	{OID_SKGE_STAT_TX_UNDERRUN,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxFifoUnderrunCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_UNDERRUN},
+	{OID_SKGE_STAT_TX_CARRIER,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxCarrierCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_CARRIER},
+/*	{OID_SKGE_STAT_TX_UTIL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxUtilization),
+		SK_PNMI_RO, MacPrivateStat, (SK_U16)(-1)}, */
+	{OID_SKGE_STAT_TX_64,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx64Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_64},
+	{OID_SKGE_STAT_TX_127,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx127Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_127},
+	{OID_SKGE_STAT_TX_255,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx255Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_255},
+	{OID_SKGE_STAT_TX_511,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx511Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_511},
+	{OID_SKGE_STAT_TX_1023,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTx1023Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_1023},
+	{OID_SKGE_STAT_TX_MAX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxMaxCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_MAX},
+	{OID_SKGE_STAT_TX_SYNC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSyncCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SYNC},
+	{OID_SKGE_STAT_TX_SYNC_OCTETS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatTxSyncOctetsCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HTX_SYNC_OCTET},
+	{OID_SKGE_STAT_RX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX},
+	{OID_SKGE_STAT_RX_OCTETS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxOctetsOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_OCTET},
+	{OID_SKGE_STAT_RX_BROADCAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxBroadcastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_BROADCAST},
+	{OID_SKGE_STAT_RX_MULTICAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMulticastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MULTICAST},
+	{OID_SKGE_STAT_RX_UNICAST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxUnicastOkCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_UNICAST},
+	{OID_SKGE_STAT_RX_LONGFRAMES,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxLongFramesCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_LONGFRAMES},
+	{OID_SKGE_STAT_RX_PFLOWC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxPauseMacCtrlCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_PMACC},
+	{OID_SKGE_STAT_RX_FLOWC,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMacCtrlCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MACC},
+	{OID_SKGE_STAT_RX_PFLOWC_ERR,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxPauseMacCtrlErrorCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_PMACC_ERR},
+	{OID_SKGE_STAT_RX_FLOWC_UNKWN,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMacCtrlUnknownCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MACC_UNKWN},
+	{OID_SKGE_STAT_RX_BURST,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxBurstCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_BURST},
+	{OID_SKGE_STAT_RX_MISSED,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMissedCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MISSED},
+	{OID_SKGE_STAT_RX_FRAMING,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFramingCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_FRAMING},
+	{OID_SKGE_STAT_RX_OVERFLOW,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFifoOverflowCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_OVERFLOW},
+	{OID_SKGE_STAT_RX_JABBER,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxJabberCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_JABBER},
+	{OID_SKGE_STAT_RX_CARRIER,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxCarrierCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_CARRIER},
+	{OID_SKGE_STAT_RX_IR_LENGTH,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxIRLengthCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_IRLENGTH},
+	{OID_SKGE_STAT_RX_SYMBOL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxSymbolCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_SYMBOL},
+	{OID_SKGE_STAT_RX_SHORTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxShortsCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_SHORTS},
+	{OID_SKGE_STAT_RX_RUNT,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxRuntCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_RUNT},
+	{OID_SKGE_STAT_RX_CEXT,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxCextCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_CEXT},
+	{OID_SKGE_STAT_RX_TOO_LONG,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxTooLongCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_TOO_LONG},
+	{OID_SKGE_STAT_RX_FCS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxFcsCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_FCS},
+/*	{OID_SKGE_STAT_RX_UTIL,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxUtilization),
+		SK_PNMI_RO, MacPrivateStat, (SK_U16)(-1)}, */
+	{OID_SKGE_STAT_RX_64,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx64Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_64},
+	{OID_SKGE_STAT_RX_127,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx127Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_127},
+	{OID_SKGE_STAT_RX_255,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx255Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_255},
+	{OID_SKGE_STAT_RX_511,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx511Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_511},
+	{OID_SKGE_STAT_RX_1023,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRx1023Cts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_1023},
+	{OID_SKGE_STAT_RX_MAX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_STAT),
+		SK_PNMI_OFF(Stat) + SK_PNMI_STA_OFF(StatRxMaxCts),
+		SK_PNMI_RO, MacPrivateStat, SK_PNMI_HRX_MAX},
+	{OID_SKGE_PHYS_CUR_ADDR,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfMacCurrentAddr),
+		SK_PNMI_RW, Addr, 0},
+	{OID_SKGE_PHYS_FAC_ADDR,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfMacFactoryAddr),
+		SK_PNMI_RO, Addr, 0},
+	{OID_SKGE_PMD,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPMD),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_CONNECTOR,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfConnector),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_PHY_TYPE,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyType),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_LINK_CAP,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkCapability),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_LINK_MODE,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkMode),
+		SK_PNMI_RW, MacPrivateConf, 0},
+	{OID_SKGE_LINK_MODE_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkModeStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_LINK_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfLinkStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_FLOWCTRL_CAP,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlCapability),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_FLOWCTRL_MODE,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlMode),
+		SK_PNMI_RW, MacPrivateConf, 0},
+	{OID_SKGE_FLOWCTRL_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfFlowCtrlStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_PHY_OPERATION_CAP,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationCapability),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_PHY_OPERATION_MODE,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationMode),
+		SK_PNMI_RW, MacPrivateConf, 0},
+	{OID_SKGE_PHY_OPERATION_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyOperationStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_SPEED_CAP,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedCapability),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_SPEED_MODE,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedMode),
+		SK_PNMI_RW, MacPrivateConf, 0},
+	{OID_SKGE_SPEED_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_CONF),
+		SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfSpeedStatus),
+		SK_PNMI_RO, MacPrivateConf, 0},
+	{OID_SKGE_TRAP,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(Trap),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_TRAP_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(TrapNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RLMT_MODE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtMode),
+		SK_PNMI_RW, Rlmt, 0},
+	{OID_SKGE_RLMT_PORT_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtPortNumber),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_PORT_ACTIVE,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtPortActive),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_PORT_PREFERRED,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtPortPreferred),
+		SK_PNMI_RW, Rlmt, 0},
+	{OID_SKGE_RLMT_CHANGE_CTS,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtChangeCts),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_CHANGE_TIME,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtChangeTime),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_CHANGE_ESTIM,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtChangeEstimate),
+		SK_PNMI_RO, Rlmt, 0},
+	{OID_SKGE_RLMT_CHANGE_THRES,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtChangeThreshold),
+		SK_PNMI_RW, Rlmt, 0},
+	{OID_SKGE_RLMT_PORT_INDEX,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtIndex),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_STATUS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtStatus),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_TX_HELLO_CTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtTxHelloCts),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_RX_HELLO_CTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtRxHelloCts),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_TX_SP_REQ_CTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtTxSpHelloReqCts),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_RX_SP_CTS,
+		SK_PNMI_MAC_ENTRIES,
+		sizeof(SK_PNMI_RLMT),
+		SK_PNMI_OFF(Rlmt) + SK_PNMI_RLM_OFF(RlmtRxSpHelloCts),
+		SK_PNMI_RO, RlmtStat, 0},
+	{OID_SKGE_RLMT_MONITOR_NUMBER,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(RlmtMonitorNumber),
+		SK_PNMI_RO, General, 0},
+	{OID_SKGE_RLMT_MONITOR_INDEX,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorIndex),
+		SK_PNMI_RO, Monitor, 0},
+	{OID_SKGE_RLMT_MONITOR_ADDR,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorAddr),
+		SK_PNMI_RO, Monitor, 0},
+	{OID_SKGE_RLMT_MONITOR_ERRS,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorErrorCts),
+		SK_PNMI_RO, Monitor, 0},
+	{OID_SKGE_RLMT_MONITOR_TIMESTAMP,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorTimestamp),
+		SK_PNMI_RO, Monitor, 0},
+	{OID_SKGE_RLMT_MONITOR_ADMIN,
+		SK_PNMI_MONITOR_ENTRIES,
+		sizeof(SK_PNMI_RLMT_MONITOR),
+		SK_PNMI_OFF(RlmtMonitor) + SK_PNMI_MON_OFF(RlmtMonitorAdmin),
+		SK_PNMI_RW, Monitor, 0},
+	{OID_SKGE_MTU,
+		1,
+		0,
+		SK_PNMI_MAI_OFF(MtuSize),
+		SK_PNMI_RW, MacPrivateConf, 0},
+	{OID_SKGE_VCT_GET,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Vct, 0},
+	{OID_SKGE_VCT_SET,
+		0,
+		0,
+		0,
+		SK_PNMI_WO, Vct, 0},
+	{OID_SKGE_VCT_STATUS,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, Vct, 0},
+	{OID_SKGE_BOARDLEVEL,
+		0,
+		0,
+		0,
+		SK_PNMI_RO, General, 0},
+};
+
diff --git a/drivers/net/sk98lin/skgepnmi.c b/drivers/net/sk98lin/skgepnmi.c
new file mode 100644
index 0000000..b36dd9a
--- /dev/null
+++ b/drivers/net/sk98lin/skgepnmi.c
@@ -0,0 +1,8210 @@
+/*****************************************************************************
+ *
+ * Name:	skgepnmi.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.111 $
+ * Date:	$Date: 2003/09/15 13:35:35 $
+ * Purpose:	Private Network Management Interface
+ *
+ ****************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+
+#ifndef _lint
+static const char SysKonnectFileId[] =
+	"@(#) $Id: skgepnmi.c,v 1.111 2003/09/15 13:35:35 tschilli Exp $ (C) Marvell.";
+#endif /* !_lint */
+
+#include "h/skdrv1st.h"
+#include "h/sktypes.h"
+#include "h/xmac_ii.h"
+#include "h/skdebug.h"
+#include "h/skqueue.h"
+#include "h/skgepnmi.h"
+#include "h/skgesirq.h"
+#include "h/skcsum.h"
+#include "h/skvpd.h"
+#include "h/skgehw.h"
+#include "h/skgeinit.h"
+#include "h/skdrv2nd.h"
+#include "h/skgepnm2.h"
+#ifdef SK_POWER_MGMT
+#include "h/skgepmgt.h"
+#endif
+/* defines *******************************************************************/
+
+#ifndef DEBUG
+#define PNMI_STATIC	static
+#else	/* DEBUG */
+#define PNMI_STATIC
+#endif /* DEBUG */
+
+/*
+ * Public Function prototypes
+ */
+int SkPnmiInit(SK_AC *pAC, SK_IOC IoC, int level);
+int SkPnmiSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf,
+	unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
+int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf,
+	unsigned int *pLen, SK_U32 NetIndex);
+int SkPnmiPreSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf,
+	unsigned int *pLen, SK_U32 NetIndex);
+int SkPnmiSetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf,
+	unsigned int *pLen, SK_U32 NetIndex);
+int SkPnmiEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Param);
+int SkPnmiGenIoctl(SK_AC *pAC, SK_IOC IoC, void * pBuf,
+	unsigned int * pLen, SK_U32 NetIndex);
+
+
+/*
+ * Private Function prototypes
+ */
+
+PNMI_STATIC SK_U8 CalculateLinkModeStatus(SK_AC *pAC, SK_IOC IoC, unsigned int
+	PhysPortIndex);
+PNMI_STATIC SK_U8 CalculateLinkStatus(SK_AC *pAC, SK_IOC IoC, unsigned int
+	PhysPortIndex);
+PNMI_STATIC void CopyMac(char *pDst, SK_MAC_ADDR *pMac);
+PNMI_STATIC void CopyTrapQueue(SK_AC *pAC, char *pDstBuf);
+PNMI_STATIC SK_U64 GetPhysStatVal(SK_AC *pAC, SK_IOC IoC,
+	unsigned int PhysPortIndex, unsigned int StatIndex);
+PNMI_STATIC SK_U64 GetStatVal(SK_AC *pAC, SK_IOC IoC, unsigned int LogPortIndex,
+	unsigned int StatIndex, SK_U32 NetIndex);
+PNMI_STATIC char* GetTrapEntry(SK_AC *pAC, SK_U32 TrapId, unsigned int Size);
+PNMI_STATIC void GetTrapQueueLen(SK_AC *pAC, unsigned int *pLen,
+	unsigned int *pEntries);
+PNMI_STATIC int GetVpdKeyArr(SK_AC *pAC, SK_IOC IoC, char *pKeyArr,
+	unsigned int KeyArrLen, unsigned int *pKeyNo);
+PNMI_STATIC int LookupId(SK_U32 Id);
+PNMI_STATIC int MacUpdate(SK_AC *pAC, SK_IOC IoC, unsigned int FirstMac,
+	unsigned int LastMac);
+PNMI_STATIC int PnmiStruct(SK_AC *pAC, SK_IOC IoC, int Action, char *pBuf,
+	unsigned int *pLen, SK_U32 NetIndex);
+PNMI_STATIC int PnmiVar(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id,
+	char *pBuf, unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex);
+PNMI_STATIC void QueueRlmtNewMacTrap(SK_AC *pAC, unsigned int ActiveMac);
+PNMI_STATIC void QueueRlmtPortTrap(SK_AC *pAC, SK_U32 TrapId,
+	unsigned int PortIndex);
+PNMI_STATIC void QueueSensorTrap(SK_AC *pAC, SK_U32 TrapId,
+	unsigned int SensorIndex);
+PNMI_STATIC void QueueSimpleTrap(SK_AC *pAC, SK_U32 TrapId);
+PNMI_STATIC void ResetCounter(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex);
+PNMI_STATIC int RlmtUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 NetIndex);
+PNMI_STATIC int SirqUpdate(SK_AC *pAC, SK_IOC IoC);
+PNMI_STATIC void VirtualConf(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, char *pBuf);
+PNMI_STATIC int Vct(SK_AC *pAC, SK_IOC IoC, int Action, SK_U32 Id, char *pBuf,
+	unsigned int *pLen, SK_U32 Instance, unsigned int TableIndex, SK_U32 NetIndex);
+PNMI_STATIC void CheckVctStatus(SK_AC *, SK_IOC, char *, SK_U32, SK_U32);
+
+/*
+ * Table to correlate OID with handler function and index to
+ * hardware register stored in StatAddress if applicable.
+ */
+#include "skgemib.c"
+
+/* global variables **********************************************************/
+
+/*
+ * Overflow status register bit table and corresponding counter
+ * dependent on MAC type - the number relates to the size of overflow
+ * mask returned by the pFnMacOverflow function
+ */
+PNMI_STATIC const SK_U16 StatOvrflwBit[][SK_PNMI_MAC_TYPES] = {
+/* Bit0  */	{ SK_PNMI_HTX, 				SK_PNMI_HTX_UNICAST},
+/* Bit1  */	{ SK_PNMI_HTX_OCTETHIGH, 	SK_PNMI_HTX_BROADCAST},
+/* Bit2  */	{ SK_PNMI_HTX_OCTETLOW, 	SK_PNMI_HTX_PMACC},
+/* Bit3  */	{ SK_PNMI_HTX_BROADCAST, 	SK_PNMI_HTX_MULTICAST},
+/* Bit4  */	{ SK_PNMI_HTX_MULTICAST, 	SK_PNMI_HTX_OCTETLOW},
+/* Bit5  */	{ SK_PNMI_HTX_UNICAST, 		SK_PNMI_HTX_OCTETHIGH},
+/* Bit6  */	{ SK_PNMI_HTX_LONGFRAMES, 	SK_PNMI_HTX_64},
+/* Bit7  */	{ SK_PNMI_HTX_BURST, 		SK_PNMI_HTX_127},
+/* Bit8  */	{ SK_PNMI_HTX_PMACC, 		SK_PNMI_HTX_255},
+/* Bit9  */	{ SK_PNMI_HTX_MACC, 		SK_PNMI_HTX_511},
+/* Bit10 */	{ SK_PNMI_HTX_SINGLE_COL, 	SK_PNMI_HTX_1023},
+/* Bit11 */	{ SK_PNMI_HTX_MULTI_COL, 	SK_PNMI_HTX_MAX},
+/* Bit12 */	{ SK_PNMI_HTX_EXCESS_COL, 	SK_PNMI_HTX_LONGFRAMES},
+/* Bit13 */	{ SK_PNMI_HTX_LATE_COL, 	SK_PNMI_HTX_RESERVED},
+/* Bit14 */	{ SK_PNMI_HTX_DEFFERAL, 	SK_PNMI_HTX_COL},
+/* Bit15 */	{ SK_PNMI_HTX_EXCESS_DEF, 	SK_PNMI_HTX_LATE_COL},
+/* Bit16 */	{ SK_PNMI_HTX_UNDERRUN, 	SK_PNMI_HTX_EXCESS_COL},
+/* Bit17 */	{ SK_PNMI_HTX_CARRIER, 		SK_PNMI_HTX_MULTI_COL},
+/* Bit18 */	{ SK_PNMI_HTX_UTILUNDER, 	SK_PNMI_HTX_SINGLE_COL},
+/* Bit19 */	{ SK_PNMI_HTX_UTILOVER, 	SK_PNMI_HTX_UNDERRUN},
+/* Bit20 */	{ SK_PNMI_HTX_64, 			SK_PNMI_HTX_RESERVED},
+/* Bit21 */	{ SK_PNMI_HTX_127, 			SK_PNMI_HTX_RESERVED},
+/* Bit22 */	{ SK_PNMI_HTX_255, 			SK_PNMI_HTX_RESERVED},
+/* Bit23 */	{ SK_PNMI_HTX_511, 			SK_PNMI_HTX_RESERVED},
+/* Bit24 */	{ SK_PNMI_HTX_1023, 		SK_PNMI_HTX_RESERVED},
+/* Bit25 */	{ SK_PNMI_HTX_MAX, 			SK_PNMI_HTX_RESERVED},
+/* Bit26 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit27 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit28 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit29 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit30 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit31 */	{ SK_PNMI_HTX_RESERVED, 	SK_PNMI_HTX_RESERVED},
+/* Bit32 */	{ SK_PNMI_HRX, 				SK_PNMI_HRX_UNICAST},
+/* Bit33 */	{ SK_PNMI_HRX_OCTETHIGH, 	SK_PNMI_HRX_BROADCAST},
+/* Bit34 */	{ SK_PNMI_HRX_OCTETLOW, 	SK_PNMI_HRX_PMACC},
+/* Bit35 */	{ SK_PNMI_HRX_BROADCAST, 	SK_PNMI_HRX_MULTICAST},
+/* Bit36 */	{ SK_PNMI_HRX_MULTICAST, 	SK_PNMI_HRX_FCS},
+/* Bit37 */	{ SK_PNMI_HRX_UNICAST, 		SK_PNMI_HRX_RESERVED},
+/* Bit38 */	{ SK_PNMI_HRX_PMACC, 		SK_PNMI_HRX_OCTETLOW},
+/* Bit39 */	{ SK_PNMI_HRX_MACC, 		SK_PNMI_HRX_OCTETHIGH},
+/* Bit40 */	{ SK_PNMI_HRX_PMACC_ERR, 	SK_PNMI_HRX_BADOCTETLOW},
+/* Bit41 */	{ SK_PNMI_HRX_MACC_UNKWN,	SK_PNMI_HRX_BADOCTETHIGH},
+/* Bit42 */	{ SK_PNMI_HRX_BURST, 		SK_PNMI_HRX_UNDERSIZE},
+/* Bit43 */	{ SK_PNMI_HRX_MISSED, 		SK_PNMI_HRX_RUNT},
+/* Bit44 */	{ SK_PNMI_HRX_FRAMING, 		SK_PNMI_HRX_64},
+/* Bit45 */	{ SK_PNMI_HRX_OVERFLOW, 	SK_PNMI_HRX_127},
+/* Bit46 */	{ SK_PNMI_HRX_JABBER, 		SK_PNMI_HRX_255},
+/* Bit47 */	{ SK_PNMI_HRX_CARRIER, 		SK_PNMI_HRX_511},
+/* Bit48 */	{ SK_PNMI_HRX_IRLENGTH, 	SK_PNMI_HRX_1023},
+/* Bit49 */	{ SK_PNMI_HRX_SYMBOL, 		SK_PNMI_HRX_MAX},
+/* Bit50 */	{ SK_PNMI_HRX_SHORTS, 		SK_PNMI_HRX_LONGFRAMES},
+/* Bit51 */	{ SK_PNMI_HRX_RUNT, 		SK_PNMI_HRX_TOO_LONG},
+/* Bit52 */	{ SK_PNMI_HRX_TOO_LONG, 	SK_PNMI_HRX_JABBER},
+/* Bit53 */	{ SK_PNMI_HRX_FCS, 			SK_PNMI_HRX_RESERVED},
+/* Bit54 */	{ SK_PNMI_HRX_RESERVED, 	SK_PNMI_HRX_OVERFLOW},
+/* Bit55 */	{ SK_PNMI_HRX_CEXT, 		SK_PNMI_HRX_RESERVED},
+/* Bit56 */	{ SK_PNMI_HRX_UTILUNDER, 	SK_PNMI_HRX_RESERVED},
+/* Bit57 */	{ SK_PNMI_HRX_UTILOVER, 	SK_PNMI_HRX_RESERVED},
+/* Bit58 */	{ SK_PNMI_HRX_64, 			SK_PNMI_HRX_RESERVED},
+/* Bit59 */	{ SK_PNMI_HRX_127, 			SK_PNMI_HRX_RESERVED},
+/* Bit60 */	{ SK_PNMI_HRX_255, 			SK_PNMI_HRX_RESERVED},
+/* Bit61 */	{ SK_PNMI_HRX_511, 			SK_PNMI_HRX_RESERVED},
+/* Bit62 */	{ SK_PNMI_HRX_1023, 		SK_PNMI_HRX_RESERVED},
+/* Bit63 */	{ SK_PNMI_HRX_MAX, 			SK_PNMI_HRX_RESERVED}
+};
+
+/*
+ * Table for hardware register saving on resets and port switches
+ */
+PNMI_STATIC const SK_PNMI_STATADDR StatAddr[SK_PNMI_MAX_IDX][SK_PNMI_MAC_TYPES] = {
+	/* SK_PNMI_HTX */
+	{{XM_TXF_OK, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_OCTETHIGH */
+	{{XM_TXO_OK_HI, SK_TRUE}, {GM_TXO_OK_HI, SK_TRUE}},
+	/* SK_PNMI_HTX_OCTETLOW */
+	{{XM_TXO_OK_LO, SK_FALSE}, {GM_TXO_OK_LO, SK_FALSE}},
+	/* SK_PNMI_HTX_BROADCAST */
+	{{XM_TXF_BC_OK, SK_TRUE}, {GM_TXF_BC_OK, SK_TRUE}},
+	/* SK_PNMI_HTX_MULTICAST */
+	{{XM_TXF_MC_OK, SK_TRUE}, {GM_TXF_MC_OK, SK_TRUE}},
+	/* SK_PNMI_HTX_UNICAST */
+	{{XM_TXF_UC_OK, SK_TRUE}, {GM_TXF_UC_OK, SK_TRUE}},
+	/* SK_PNMI_HTX_BURST */
+	{{XM_TXE_BURST, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_PMACC */
+	{{XM_TXF_MPAUSE, SK_TRUE}, {GM_TXF_MPAUSE, SK_TRUE}},
+	/* SK_PNMI_HTX_MACC */
+	{{XM_TXF_MCTRL, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_COL */
+	{{0, SK_FALSE}, {GM_TXF_COL, SK_TRUE}},
+	/* SK_PNMI_HTX_SINGLE_COL */
+	{{XM_TXF_SNG_COL, SK_TRUE}, {GM_TXF_SNG_COL, SK_TRUE}},
+	/* SK_PNMI_HTX_MULTI_COL */
+	{{XM_TXF_MUL_COL, SK_TRUE}, {GM_TXF_MUL_COL, SK_TRUE}},
+	/* SK_PNMI_HTX_EXCESS_COL */
+	{{XM_TXF_ABO_COL, SK_TRUE}, {GM_TXF_ABO_COL, SK_TRUE}},
+	/* SK_PNMI_HTX_LATE_COL */
+	{{XM_TXF_LAT_COL, SK_TRUE}, {GM_TXF_LAT_COL, SK_TRUE}},
+	/* SK_PNMI_HTX_DEFFERAL */
+	{{XM_TXF_DEF, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_EXCESS_DEF */
+	{{XM_TXF_EX_DEF, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_UNDERRUN */
+	{{XM_TXE_FIFO_UR, SK_TRUE}, {GM_TXE_FIFO_UR, SK_TRUE}},
+	/* SK_PNMI_HTX_CARRIER */
+	{{XM_TXE_CS_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_UTILUNDER */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_UTILOVER */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_64 */
+	{{XM_TXF_64B, SK_TRUE}, {GM_TXF_64B, SK_TRUE}},
+	/* SK_PNMI_HTX_127 */
+	{{XM_TXF_127B, SK_TRUE}, {GM_TXF_127B, SK_TRUE}},
+	/* SK_PNMI_HTX_255 */
+	{{XM_TXF_255B, SK_TRUE}, {GM_TXF_255B, SK_TRUE}},
+	/* SK_PNMI_HTX_511 */
+	{{XM_TXF_511B, SK_TRUE}, {GM_TXF_511B, SK_TRUE}},
+	/* SK_PNMI_HTX_1023 */
+	{{XM_TXF_1023B, SK_TRUE}, {GM_TXF_1023B, SK_TRUE}},
+	/* SK_PNMI_HTX_MAX */
+	{{XM_TXF_MAX_SZ, SK_TRUE}, {GM_TXF_1518B, SK_TRUE}},
+	/* SK_PNMI_HTX_LONGFRAMES  */
+	{{XM_TXF_LONG, SK_TRUE}, {GM_TXF_MAX_SZ, SK_TRUE}},
+	/* SK_PNMI_HTX_SYNC */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_SYNC_OCTET */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HTX_RESERVED */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX */
+	{{XM_RXF_OK, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_OCTETHIGH */
+	{{XM_RXO_OK_HI, SK_TRUE}, {GM_RXO_OK_HI, SK_TRUE}},
+	/* SK_PNMI_HRX_OCTETLOW */
+	{{XM_RXO_OK_LO, SK_FALSE}, {GM_RXO_OK_LO, SK_FALSE}},
+	/* SK_PNMI_HRX_BADOCTETHIGH */
+	{{0, SK_FALSE}, {GM_RXO_ERR_HI, SK_TRUE}},
+	/* SK_PNMI_HRX_BADOCTETLOW */
+	{{0, SK_FALSE}, {GM_RXO_ERR_LO, SK_TRUE}},
+	/* SK_PNMI_HRX_BROADCAST */
+	{{XM_RXF_BC_OK, SK_TRUE}, {GM_RXF_BC_OK, SK_TRUE}},
+	/* SK_PNMI_HRX_MULTICAST */
+	{{XM_RXF_MC_OK, SK_TRUE}, {GM_RXF_MC_OK, SK_TRUE}},
+	/* SK_PNMI_HRX_UNICAST */
+	{{XM_RXF_UC_OK, SK_TRUE}, {GM_RXF_UC_OK, SK_TRUE}},
+	/* SK_PNMI_HRX_PMACC */
+	{{XM_RXF_MPAUSE, SK_TRUE}, {GM_RXF_MPAUSE, SK_TRUE}},
+	/* SK_PNMI_HRX_MACC */
+	{{XM_RXF_MCTRL, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_PMACC_ERR */
+	{{XM_RXF_INV_MP, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_MACC_UNKWN */
+	{{XM_RXF_INV_MOC, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_BURST */
+	{{XM_RXE_BURST, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_MISSED */
+	{{XM_RXE_FMISS, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_FRAMING */
+	{{XM_RXF_FRA_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_UNDERSIZE */
+	{{0, SK_FALSE}, {GM_RXF_SHT, SK_TRUE}},
+	/* SK_PNMI_HRX_OVERFLOW */
+	{{XM_RXE_FIFO_OV, SK_TRUE}, {GM_RXE_FIFO_OV, SK_TRUE}},
+	/* SK_PNMI_HRX_JABBER */
+	{{XM_RXF_JAB_PKT, SK_TRUE}, {GM_RXF_JAB_PKT, SK_TRUE}},
+	/* SK_PNMI_HRX_CARRIER */
+	{{XM_RXE_CAR_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_IRLENGTH */
+	{{XM_RXF_LEN_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_SYMBOL */
+	{{XM_RXE_SYM_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_SHORTS */
+	{{XM_RXE_SHT_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_RUNT */
+	{{XM_RXE_RUNT, SK_TRUE}, {GM_RXE_FRAG, SK_TRUE}},
+	/* SK_PNMI_HRX_TOO_LONG */
+	{{XM_RXF_LNG_ERR, SK_TRUE}, {GM_RXF_LNG_ERR, SK_TRUE}},
+	/* SK_PNMI_HRX_FCS */
+	{{XM_RXF_FCS_ERR, SK_TRUE}, {GM_RXF_FCS_ERR, SK_TRUE}},
+	/* SK_PNMI_HRX_CEXT */
+	{{XM_RXF_CEX_ERR, SK_TRUE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_UTILUNDER */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_UTILOVER */
+	{{0, SK_FALSE}, {0, SK_FALSE}},
+	/* SK_PNMI_HRX_64 */
+	{{XM_RXF_64B, SK_TRUE}, {GM_RXF_64B, SK_TRUE}},
+	/* SK_PNMI_HRX_127 */
+	{{XM_RXF_127B, SK_TRUE}, {GM_RXF_127B, SK_TRUE}},
+	/* SK_PNMI_HRX_255 */
+	{{XM_RXF_255B, SK_TRUE}, {GM_RXF_255B, SK_TRUE}},
+	/* SK_PNMI_HRX_511 */
+	{{XM_RXF_511B, SK_TRUE}, {GM_RXF_511B, SK_TRUE}},
+	/* SK_PNMI_HRX_1023 */
+	{{XM_RXF_1023B, SK_TRUE}, {GM_RXF_1023B, SK_TRUE}},
+	/* SK_PNMI_HRX_MAX */
+	{{XM_RXF_MAX_SZ, SK_TRUE}, {GM_RXF_1518B, SK_TRUE}},
+	/* SK_PNMI_HRX_LONGFRAMES */
+	{{0, SK_FALSE}, {GM_RXF_MAX_SZ, SK_TRUE}},
+	/* SK_PNMI_HRX_RESERVED */
+	{{0, SK_FALSE}, {0, SK_FALSE}}
+};
+
+
+/*****************************************************************************
+ *
+ * Public functions
+ *
+ */
+
+/*****************************************************************************
+ *
+ * SkPnmiInit - Init function of PNMI
+ *
+ * Description:
+ *	SK_INIT_DATA: Initialises the data structures
+ *	SK_INIT_IO:   Resets the XMAC statistics, determines the device and
+ *	              connector type.
+ *	SK_INIT_RUN:  Starts a timer event for port switch per hour
+ *	              calculation.
+ *
+ * Returns:
+ *	Always 0
+ */
+int SkPnmiInit(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Level)		/* Initialization level */
+{
+	unsigned int	PortMax;	/* Number of ports */
+	unsigned int	PortIndex;	/* Current port index in loop */
+	SK_U16		Val16;		/* Multiple purpose 16 bit variable */
+	SK_U8		Val8;		/* Mulitple purpose 8 bit variable */
+	SK_EVPARA	EventParam;	/* Event struct for timer event */
+	SK_PNMI_VCT	*pVctBackupData;
+
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiInit: Called, level=%d\n", Level));
+
+	switch (Level) {
+
+	case SK_INIT_DATA:
+		SK_MEMSET((char *)&pAC->Pnmi, 0, sizeof(pAC->Pnmi));
+		pAC->Pnmi.TrapBufFree = SK_PNMI_TRAP_QUEUE_LEN;
+		pAC->Pnmi.StartUpTime = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+		pAC->Pnmi.RlmtChangeThreshold = SK_PNMI_DEF_RLMT_CHG_THRES;
+		for (PortIndex = 0; PortIndex < SK_MAX_MACS; PortIndex ++) {
+
+			pAC->Pnmi.Port[PortIndex].ActiveFlag = SK_FALSE;
+			pAC->Pnmi.DualNetActiveFlag = SK_FALSE;
+		}
+
+#ifdef SK_PNMI_CHECK
+		if (SK_PNMI_MAX_IDX != SK_PNMI_CNT_NO) {
+			
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR049, SK_PNMI_ERR049MSG);
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL,
+					   ("CounterOffset struct size (%d) differs from"
+						"SK_PNMI_MAX_IDX (%d)\n",
+						SK_PNMI_CNT_NO, SK_PNMI_MAX_IDX));
+		}
+
+		if (SK_PNMI_MAX_IDX !=
+			(sizeof(StatAddr) / (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES))) {
+			
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR050, SK_PNMI_ERR050MSG);
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_INIT | SK_DBGCAT_FATAL,
+					   ("StatAddr table size (%d) differs from "
+						"SK_PNMI_MAX_IDX (%d)\n",
+						(sizeof(StatAddr) /
+						 (sizeof(SK_PNMI_STATADDR) * SK_PNMI_MAC_TYPES)),
+						 SK_PNMI_MAX_IDX));
+		}
+#endif /* SK_PNMI_CHECK */
+		break;
+
+	case SK_INIT_IO:
+		/*
+		 * Reset MAC counters
+		 */
+		PortMax = pAC->GIni.GIMacsFound;
+
+		for (PortIndex = 0; PortIndex < PortMax; PortIndex ++) {
+
+			pAC->GIni.GIFunc.pFnMacResetCounter(pAC, IoC, PortIndex);
+		}
+		
+		/* Initialize DSP variables for Vct() to 0xff => Never written! */		
+		for (PortIndex = 0; PortIndex < PortMax; PortIndex ++) {
+			pAC->GIni.GP[PortIndex].PCableLen = 0xff;
+			pVctBackupData = &pAC->Pnmi.VctBackup[PortIndex];
+			pVctBackupData->PCableLen = 0xff;
+		}
+		
+		/*
+		 * Get pci bus speed
+		 */
+		SK_IN16(IoC, B0_CTST, &Val16);
+		if ((Val16 & CS_BUS_CLOCK) == 0) {
+
+			pAC->Pnmi.PciBusSpeed = 33;
+		}
+		else {
+			pAC->Pnmi.PciBusSpeed = 66;
+		}
+
+		/*
+		 * Get pci bus width
+		 */
+		SK_IN16(IoC, B0_CTST, &Val16);
+		if ((Val16 & CS_BUS_SLOT_SZ) == 0) {
+
+			pAC->Pnmi.PciBusWidth = 32;
+		}
+		else {
+			pAC->Pnmi.PciBusWidth = 64;
+		}
+
+		/*
+		 * Get chipset
+		 */
+		switch (pAC->GIni.GIChipId) {
+		case CHIP_ID_GENESIS:
+			pAC->Pnmi.Chipset = SK_PNMI_CHIPSET_XMAC;
+			break;
+
+		case CHIP_ID_YUKON:
+			pAC->Pnmi.Chipset = SK_PNMI_CHIPSET_YUKON;
+			break;
+
+		default:
+			break;
+		}
+
+		/*
+		 * Get PMD and DeviceType
+		 */
+		SK_IN8(IoC, B2_PMD_TYP, &Val8);
+		switch (Val8) {
+		case 'S':
+			pAC->Pnmi.PMD = 3;
+			if (pAC->GIni.GIMacsFound > 1) {
+
+				pAC->Pnmi.DeviceType = 0x00020002;
+			}
+			else {
+				pAC->Pnmi.DeviceType = 0x00020001;
+			}
+			break;
+
+		case 'L':
+			pAC->Pnmi.PMD = 2;
+			if (pAC->GIni.GIMacsFound > 1) {
+
+				pAC->Pnmi.DeviceType = 0x00020004;
+			}
+			else {
+				pAC->Pnmi.DeviceType = 0x00020003;
+			}
+			break;
+
+		case 'C':
+			pAC->Pnmi.PMD = 4;
+			if (pAC->GIni.GIMacsFound > 1) {
+
+				pAC->Pnmi.DeviceType = 0x00020006;
+			}
+			else {
+				pAC->Pnmi.DeviceType = 0x00020005;
+			}
+			break;
+
+		case 'T':
+			pAC->Pnmi.PMD = 5;
+			if (pAC->GIni.GIMacsFound > 1) {
+
+				pAC->Pnmi.DeviceType = 0x00020008;
+			}
+			else {
+				pAC->Pnmi.DeviceType = 0x00020007;
+			}
+			break;
+
+		default :
+			pAC->Pnmi.PMD = 1;
+			pAC->Pnmi.DeviceType = 0;
+			break;
+		}
+
+		/*
+		 * Get connector
+		 */
+		SK_IN8(IoC, B2_CONN_TYP, &Val8);
+		switch (Val8) {
+		case 'C':
+			pAC->Pnmi.Connector = 2;
+			break;
+
+		case 'D':
+			pAC->Pnmi.Connector = 3;
+			break;
+
+		case 'F':
+			pAC->Pnmi.Connector = 4;
+			break;
+
+		case 'J':
+			pAC->Pnmi.Connector = 5;
+			break;
+
+		case 'V':
+			pAC->Pnmi.Connector = 6;
+			break;
+
+		default:
+			pAC->Pnmi.Connector = 1;
+			break;
+		}
+		break;
+
+	case SK_INIT_RUN:
+		/*
+		 * Start timer for RLMT change counter
+		 */
+		SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+		SkTimerStart(pAC, IoC, &pAC->Pnmi.RlmtChangeEstimate.EstTimer,
+			28125000, SKGE_PNMI, SK_PNMI_EVT_CHG_EST_TIMER,
+			EventParam);
+		break;
+
+	default:
+		break; /* Nothing todo */
+	}
+
+	return (0);
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiGetVar - Retrieves the value of a single OID
+ *
+ * Description:
+ *	Calls a general sub-function for all this stuff. If the instance
+ *	-1 is passed, the values of all instances are returned in an
+ *	array of values.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to take
+ *	                         the data.
+ *	SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+static int SkPnmiGetVar(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 Id,		/* Object ID that is to be processed */
+void *pBuf,		/* Buffer to which the management data will be copied */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiGetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
+			Id, *pLen, Instance, NetIndex));
+
+	return (PnmiVar(pAC, IoC, SK_PNMI_GET, Id, (char *)pBuf, pLen,
+		Instance, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiPreSetVar - Presets the value of a single OID
+ *
+ * Description:
+ *	Calls a general sub-function for all this stuff. The preset does
+ *	the same as a set, but returns just before finally setting the
+ *	new value. This is useful to check if a set might be successfull.
+ *	If the instance -1 is passed, an array of values is supposed and
+ *	all instances of the OID will be set.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+static int SkPnmiPreSetVar(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 Id,		/* Object ID that is to be processed */
+void *pBuf,		/* Buffer to which the management data will be copied */
+unsigned int *pLen,	/* Total length of management data */
+SK_U32 Instance,	/* Instance (1..n) that is to be set or -1 */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiPreSetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
+			Id, *pLen, Instance, NetIndex));
+
+
+	return (PnmiVar(pAC, IoC, SK_PNMI_PRESET, Id, (char *)pBuf, pLen,
+		Instance, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiSetVar - Sets the value of a single OID
+ *
+ * Description:
+ *	Calls a general sub-function for all this stuff. The preset does
+ *	the same as a set, but returns just before finally setting the
+ *	new value. This is useful to check if a set might be successfull.
+ *	If the instance -1 is passed, an array of values is supposed and
+ *	all instances of the OID will be set.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+int SkPnmiSetVar(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 Id,		/* Object ID that is to be processed */
+void *pBuf,		/* Buffer to which the management data will be copied */
+unsigned int *pLen,	/* Total length of management data */
+SK_U32 Instance,	/* Instance (1..n) that is to be set or -1 */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiSetVar: Called, Id=0x%x, BufLen=%d, Instance=%d, NetIndex=%d\n",
+			Id, *pLen, Instance, NetIndex));
+
+	return (PnmiVar(pAC, IoC, SK_PNMI_SET, Id, (char *)pBuf, pLen,
+		Instance, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiGetStruct - Retrieves the management database in SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ *	Runs through the IdTable, queries the single OIDs and stores the
+ *	returned data into the management database structure
+ *	SK_PNMI_STRUCT_DATA. The offset of the OID in the structure
+ *	is stored in the IdTable. The return value of the function will also
+ *	be stored in SK_PNMI_STRUCT_DATA if the passed buffer has the
+ *	minimum size of SK_PNMI_MIN_STRUCT_SIZE.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to take
+ *	                         the data.
+ *	SK_PNMI_ERR_UNKNOWN_NET  The requested NetIndex doesn't exist
+ */
+int SkPnmiGetStruct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+void *pBuf,		/* Buffer to which the management data will be copied. */
+unsigned int *pLen,	/* Length of buffer */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	int		Ret;
+	unsigned int	TableIndex;
+	unsigned int	DstOffset;
+	unsigned int	InstanceNo;
+	unsigned int	InstanceCnt;
+	SK_U32		Instance;
+	unsigned int	TmpLen;
+	char		KeyArr[SK_PNMI_VPD_ENTRIES][SK_PNMI_VPD_KEY_SIZE];
+
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiGetStruct: Called, BufLen=%d, NetIndex=%d\n",
+			*pLen, NetIndex));
+
+	if (*pLen < SK_PNMI_STRUCT_SIZE) {
+
+		if (*pLen >= SK_PNMI_MIN_STRUCT_SIZE) {
+
+			SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_TOO_SHORT,
+				(SK_U32)(-1));
+		}
+
+		*pLen = SK_PNMI_STRUCT_SIZE;
+		return (SK_PNMI_ERR_TOO_SHORT);
+	}
+
+    /*
+     * Check NetIndex
+     */
+	if (NetIndex >= pAC->Rlmt.NumNets) {
+		return (SK_PNMI_ERR_UNKNOWN_NET);
+	}
+
+	/* Update statistic */
+	SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On call");
+
+	if ((Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1)) !=
+		SK_PNMI_ERR_OK) {
+
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (Ret);
+	}
+
+	if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
+
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (Ret);
+	}
+
+	if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (Ret);
+	}
+
+	/*
+	 * Increment semaphores to indicate that an update was
+	 * already done
+	 */
+	pAC->Pnmi.MacUpdatedFlag ++;
+	pAC->Pnmi.RlmtUpdatedFlag ++;
+	pAC->Pnmi.SirqUpdatedFlag ++;
+
+	/* Get vpd keys for instance calculation */
+	Ret = GetVpdKeyArr(pAC, IoC, &KeyArr[0][0], sizeof(KeyArr), &TmpLen);
+	if (Ret != SK_PNMI_ERR_OK) {
+
+		pAC->Pnmi.MacUpdatedFlag --;
+		pAC->Pnmi.RlmtUpdatedFlag --;
+		pAC->Pnmi.SirqUpdatedFlag --;
+
+		SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	/* Retrieve values */
+	SK_MEMSET((char *)pBuf, 0, SK_PNMI_STRUCT_SIZE);
+	for (TableIndex = 0; TableIndex < ID_TABLE_SIZE; TableIndex ++) {
+
+		InstanceNo = IdTable[TableIndex].InstanceNo;
+		for (InstanceCnt = 1; InstanceCnt <= InstanceNo;
+			InstanceCnt ++) {
+
+			DstOffset = IdTable[TableIndex].Offset +
+				(InstanceCnt - 1) *
+				IdTable[TableIndex].StructSize;
+
+			/*
+			 * For the VPD the instance is not an index number
+			 * but the key itself. Determin with the instance
+			 * counter the VPD key to be used.
+			 */
+			if (IdTable[TableIndex].Id == OID_SKGE_VPD_KEY ||
+				IdTable[TableIndex].Id == OID_SKGE_VPD_VALUE ||
+				IdTable[TableIndex].Id == OID_SKGE_VPD_ACCESS ||
+				IdTable[TableIndex].Id == OID_SKGE_VPD_ACTION) {
+
+				SK_STRNCPY((char *)&Instance, KeyArr[InstanceCnt - 1], 4);
+			}
+			else {
+				Instance = (SK_U32)InstanceCnt;
+			}
+
+			TmpLen = *pLen - DstOffset;
+			Ret = IdTable[TableIndex].Func(pAC, IoC, SK_PNMI_GET,
+				IdTable[TableIndex].Id, (char *)pBuf +
+				DstOffset, &TmpLen, Instance, TableIndex, NetIndex);
+
+			/*
+			 * An unknown instance error means that we reached
+			 * the last instance of that variable. Proceed with
+			 * the next OID in the table and ignore the return
+			 * code.
+			 */
+			if (Ret == SK_PNMI_ERR_UNKNOWN_INST) {
+
+                break;
+			}
+
+			if (Ret != SK_PNMI_ERR_OK) {
+
+				pAC->Pnmi.MacUpdatedFlag --;
+				pAC->Pnmi.RlmtUpdatedFlag --;
+				pAC->Pnmi.SirqUpdatedFlag --;
+
+				SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
+				SK_PNMI_SET_STAT(pBuf, Ret, DstOffset);
+				*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+				return (Ret);
+			}
+		}
+	}
+
+	pAC->Pnmi.MacUpdatedFlag --;
+	pAC->Pnmi.RlmtUpdatedFlag --;
+	pAC->Pnmi.SirqUpdatedFlag --;
+
+	*pLen = SK_PNMI_STRUCT_SIZE;
+	SK_PNMI_CHECKFLAGS("SkPnmiGetStruct: On return");
+	SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_OK, (SK_U32)(-1));
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiPreSetStruct - Presets the management database in SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ *	Calls a general sub-function for all this set stuff. The preset does
+ *	the same as a set, but returns just before finally setting the
+ *	new value. This is useful to check if a set might be successfull.
+ *	The sub-function runs through the IdTable, checks which OIDs are able
+ *	to set, and calls the handler function of the OID to perform the
+ *	preset. The return value of the function will also be stored in
+ *	SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
+ *	SK_PNMI_MIN_STRUCT_SIZE.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ */
+int SkPnmiPreSetStruct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+void *pBuf,		/* Buffer which contains the data to be set */
+unsigned int *pLen,	/* Length of buffer */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiPreSetStruct: Called, BufLen=%d, NetIndex=%d\n",
+			*pLen, NetIndex));
+
+	return (PnmiStruct(pAC, IoC, SK_PNMI_PRESET, (char *)pBuf,
+    					pLen, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiSetStruct - Sets the management database in SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ *	Calls a general sub-function for all this set stuff. The return value
+ *	of the function will also be stored in SK_PNMI_STRUCT_DATA if the
+ *	passed buffer has the minimum size of SK_PNMI_MIN_STRUCT_SIZE.
+ *	The sub-function runs through the IdTable, checks which OIDs are able
+ *	to set, and calls the handler function of the OID to perform the
+ *	set. The return value of the function will also be stored in
+ *	SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
+ *	SK_PNMI_MIN_STRUCT_SIZE.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ */
+int SkPnmiSetStruct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+void *pBuf,		/* Buffer which contains the data to be set */
+unsigned int *pLen,	/* Length of buffer */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+		("PNMI: SkPnmiSetStruct: Called, BufLen=%d, NetIndex=%d\n",
+			*pLen, NetIndex));
+
+	return (PnmiStruct(pAC, IoC, SK_PNMI_SET, (char *)pBuf,
+    					pLen, NetIndex));
+}
+
+/*****************************************************************************
+ *
+ * SkPnmiEvent - Event handler
+ *
+ * Description:
+ *	Handles the following events:
+ *	SK_PNMI_EVT_SIRQ_OVERFLOW     When a hardware counter overflows an
+ *	                              interrupt will be generated which is
+ *	                              first handled by SIRQ which generates a
+ *	                              this event. The event increments the
+ *	                              upper 32 bit of the 64 bit counter.
+ *	SK_PNMI_EVT_SEN_XXX           The event is generated by the I2C module
+ *	                              when a sensor reports a warning or
+ *	                              error. The event will store a trap
+ *	                              message in the trap buffer.
+ *	SK_PNMI_EVT_CHG_EST_TIMER     The timer event was initiated by this
+ *	                              module and is used to calculate the
+ *	                              port switches per hour.
+ *	SK_PNMI_EVT_CLEAR_COUNTER     The event clears all counters and
+ *	                              timestamps.
+ *	SK_PNMI_EVT_XMAC_RESET        The event is generated by the driver
+ *	                              before a hard reset of the XMAC is
+ *	                              performed. All counters will be saved
+ *	                              and added to the hardware counter
+ *	                              values after reset to grant continuous
+ *	                              counter values.
+ *	SK_PNMI_EVT_RLMT_PORT_UP      Generated by RLMT to notify that a port
+ *	                              went logically up. A trap message will
+ *	                              be stored to the trap buffer.
+ *	SK_PNMI_EVT_RLMT_PORT_DOWN    Generated by RLMT to notify that a port
+ *	                              went logically down. A trap message will
+ *	                              be stored to the trap buffer.
+ *	SK_PNMI_EVT_RLMT_SEGMENTATION Generated by RLMT to notify that two
+ *	                              spanning tree root bridges were
+ *	                              detected. A trap message will be stored
+ *	                              to the trap buffer.
+ *	SK_PNMI_EVT_RLMT_ACTIVE_DOWN  Notifies PNMI that an active port went
+ *	                              down. PNMI will not further add the
+ *	                              statistic values to the virtual port.
+ *	SK_PNMI_EVT_RLMT_ACTIVE_UP    Notifies PNMI that a port went up and
+ *	                              is now an active port. PNMI will now
+ *	                              add the statistic data of this port to
+ *	                              the virtual port.
+ *	SK_PNMI_EVT_RLMT_SET_NETS     Notifies PNMI about the net mode. The first parameter
+ *	                              contains the number of nets. 1 means single net, 2 means
+ *	                              dual net. The second parameter is -1
+ *
+ * Returns:
+ *	Always 0
+ */
+int SkPnmiEvent(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 Event,		/* Event-Id */
+SK_EVPARA Param)	/* Event dependent parameter */
+{
+	unsigned int	PhysPortIndex;
+    unsigned int	MaxNetNumber;
+	int			CounterIndex;
+	int			Ret;
+	SK_U16		MacStatus;
+	SK_U64		OverflowStatus;
+	SK_U64		Mask;
+	int			MacType;
+	SK_U64		Value;
+	SK_U32		Val32;
+	SK_U16		Register;
+	SK_EVPARA	EventParam;
+	SK_U64		NewestValue;
+	SK_U64		OldestValue;
+	SK_U64		Delta;
+	SK_PNMI_ESTIMATE *pEst;
+	SK_U32		NetIndex;
+	SK_GEPORT	*pPrt;
+	SK_PNMI_VCT	*pVctBackupData;
+	SK_U32		RetCode;
+	int		i;
+	SK_U32		CableLength;
+
+
+#ifdef DEBUG
+	if (Event != SK_PNMI_EVT_XMAC_RESET) {
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+			("PNMI: SkPnmiEvent: Called, Event=0x%x, Param=0x%x\n",
+			(unsigned int)Event, (unsigned int)Param.Para64));
+	}
+#endif /* DEBUG */
+	SK_PNMI_CHECKFLAGS("SkPnmiEvent: On call");
+
+	MacType = pAC->GIni.GIMacType;
+	
+	switch (Event) {
+
+	case SK_PNMI_EVT_SIRQ_OVERFLOW:
+		PhysPortIndex = (int)Param.Para32[0];
+		MacStatus = (SK_U16)Param.Para32[1];
+#ifdef DEBUG
+		if (PhysPortIndex >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SIRQ_OVERFLOW parameter"
+				 " wrong, PhysPortIndex=0x%x\n",
+				PhysPortIndex));
+			return (0);
+		}
+#endif /* DEBUG */
+		OverflowStatus = 0;
+
+		/*
+		 * Check which source caused an overflow interrupt.
+		 */
+		if ((pAC->GIni.GIFunc.pFnMacOverflow(pAC, IoC, PhysPortIndex,
+				MacStatus, &OverflowStatus) != 0) ||
+			(OverflowStatus == 0)) {
+
+			SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+			return (0);
+		}
+
+		/*
+		 * Check the overflow status register and increment
+		 * the upper dword of corresponding counter.
+		 */
+		for (CounterIndex = 0; CounterIndex < sizeof(Mask) * 8;
+			CounterIndex ++) {
+
+			Mask = (SK_U64)1 << CounterIndex;
+			if ((OverflowStatus & Mask) == 0) {
+
+				continue;
+			}
+
+			switch (StatOvrflwBit[CounterIndex][MacType]) {
+
+			case SK_PNMI_HTX_UTILUNDER:
+			case SK_PNMI_HTX_UTILOVER:
+				if (MacType == SK_MAC_XMAC) {
+					XM_IN16(IoC, PhysPortIndex, XM_TX_CMD, &Register);
+					Register |= XM_TX_SAM_LINE;
+					XM_OUT16(IoC, PhysPortIndex, XM_TX_CMD, Register);
+				}
+				break;
+
+			case SK_PNMI_HRX_UTILUNDER:
+			case SK_PNMI_HRX_UTILOVER:
+				if (MacType == SK_MAC_XMAC) {
+					XM_IN16(IoC, PhysPortIndex, XM_RX_CMD, &Register);
+					Register |= XM_RX_SAM_LINE;
+					XM_OUT16(IoC, PhysPortIndex, XM_RX_CMD, Register);
+				}
+				break;
+
+			case SK_PNMI_HTX_OCTETHIGH:
+			case SK_PNMI_HTX_OCTETLOW:
+			case SK_PNMI_HTX_RESERVED:
+			case SK_PNMI_HRX_OCTETHIGH:
+			case SK_PNMI_HRX_OCTETLOW:
+			case SK_PNMI_HRX_IRLENGTH:
+			case SK_PNMI_HRX_RESERVED:
+			
+			/*
+			 * the following counters aren't be handled (id > 63)
+			 */
+			case SK_PNMI_HTX_SYNC:
+			case SK_PNMI_HTX_SYNC_OCTET:
+				break;
+
+			case SK_PNMI_HRX_LONGFRAMES:
+				if (MacType == SK_MAC_GMAC) {
+					pAC->Pnmi.Port[PhysPortIndex].
+						CounterHigh[CounterIndex] ++;
+				}
+				break;
+
+			default:
+				pAC->Pnmi.Port[PhysPortIndex].
+					CounterHigh[CounterIndex] ++;
+			}
+		}
+		break;
+
+	case SK_PNMI_EVT_SEN_WAR_LOW:
+#ifdef DEBUG
+		if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_WAR_LOW parameter wrong, SensorIndex=%d\n",
+				(unsigned int)Param.Para64));
+			return (0);
+		}
+#endif /* DEBUG */
+
+		/*
+		 * Store a trap message in the trap buffer and generate
+		 * an event for user space applications with the
+		 * SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_WAR_LOW,
+			(unsigned int)Param.Para64);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		break;
+
+	case SK_PNMI_EVT_SEN_WAR_UPP:
+#ifdef DEBUG
+		if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_WAR_UPP parameter wrong, SensorIndex=%d\n",
+				(unsigned int)Param.Para64));
+			return (0);
+		}
+#endif /* DEBUG */
+
+		/*
+		 * Store a trap message in the trap buffer and generate
+		 * an event for user space applications with the
+		 * SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_WAR_UPP,
+			(unsigned int)Param.Para64);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		break;
+
+	case SK_PNMI_EVT_SEN_ERR_LOW:
+#ifdef DEBUG
+		if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_ERR_LOW parameter wrong, SensorIndex=%d\n",
+				(unsigned int)Param.Para64));
+			return (0);
+		}
+#endif /* DEBUG */
+
+		/*
+		 * Store a trap message in the trap buffer and generate
+		 * an event for user space applications with the
+		 * SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_ERR_LOW,
+			(unsigned int)Param.Para64);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		break;
+	
+	case SK_PNMI_EVT_SEN_ERR_UPP:
+#ifdef DEBUG
+		if ((unsigned int)Param.Para64 >= (unsigned int)pAC->I2c.MaxSens) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_SEN_ERR_UPP parameter wrong, SensorIndex=%d\n",
+				(unsigned int)Param.Para64));
+			return (0);
+		}
+#endif /* DEBUG */
+
+		/*
+		 * Store a trap message in the trap buffer and generate
+		 * an event for user space applications with the
+		 * SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueSensorTrap(pAC, OID_SKGE_TRAP_SEN_ERR_UPP,
+			(unsigned int)Param.Para64);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		break;
+
+	case SK_PNMI_EVT_CHG_EST_TIMER:
+		/*
+		 * Calculate port switch average on a per hour basis
+		 *   Time interval for check       : 28125 ms
+		 *   Number of values for average  : 8
+		 *
+		 * Be careful in changing these values, on change check
+		 *   - typedef of SK_PNMI_ESTIMATE (Size of EstValue
+		 *     array one less than value number)
+		 *   - Timer initialization SkTimerStart() in SkPnmiInit
+		 *   - Delta value below must be multiplicated with
+		 *     power of 2
+		 *
+		 */
+		pEst = &pAC->Pnmi.RlmtChangeEstimate;
+		CounterIndex = pEst->EstValueIndex + 1;
+		if (CounterIndex == 7) {
+
+			CounterIndex = 0;
+		}
+		pEst->EstValueIndex = CounterIndex;
+
+		NewestValue = pAC->Pnmi.RlmtChangeCts;
+		OldestValue = pEst->EstValue[CounterIndex];
+		pEst->EstValue[CounterIndex] = NewestValue;
+
+		/*
+		 * Calculate average. Delta stores the number of
+		 * port switches per 28125 * 8 = 225000 ms
+		 */
+		if (NewestValue >= OldestValue) {
+
+			Delta = NewestValue - OldestValue;
+		}
+		else {
+			/* Overflow situation */
+			Delta = (SK_U64)(0 - OldestValue) + NewestValue;
+		}
+
+		/*
+		 * Extrapolate delta to port switches per hour.
+		 *     Estimate = Delta * (3600000 / 225000)
+		 *              = Delta * 16
+		 *              = Delta << 4
+		 */
+		pAC->Pnmi.RlmtChangeEstimate.Estimate = Delta << 4;
+
+		/*
+		 * Check if threshold is exceeded. If the threshold is
+		 * permanently exceeded every 28125 ms an event will be
+		 * generated to remind the user of this condition.
+		 */
+		if ((pAC->Pnmi.RlmtChangeThreshold != 0) &&
+			(pAC->Pnmi.RlmtChangeEstimate.Estimate >=
+			pAC->Pnmi.RlmtChangeThreshold)) {
+
+			QueueSimpleTrap(pAC, OID_SKGE_TRAP_RLMT_CHANGE_THRES);
+			(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		}
+
+		SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+		SkTimerStart(pAC, IoC, &pAC->Pnmi.RlmtChangeEstimate.EstTimer,
+			28125000, SKGE_PNMI, SK_PNMI_EVT_CHG_EST_TIMER,
+			EventParam);
+		break;
+
+	case SK_PNMI_EVT_CLEAR_COUNTER:
+		/*
+		 *  Param.Para32[0] contains the NetIndex (0 ..1).
+		 *  Param.Para32[1] is reserved, contains -1.
+		 */
+		NetIndex = (SK_U32)Param.Para32[0];
+
+#ifdef DEBUG
+		if (NetIndex >= pAC->Rlmt.NumNets) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_CLEAR_COUNTER parameter wrong, NetIndex=%d\n",
+				NetIndex));
+
+			return (0);
+		}
+#endif /* DEBUG */
+
+		/*
+		 * Set all counters and timestamps to zero.
+		 * The according NetIndex is required as a
+		 * parameter of the event.
+		 */
+		ResetCounter(pAC, IoC, NetIndex);
+		break;
+
+	case SK_PNMI_EVT_XMAC_RESET:
+		/*
+		 * To grant continuous counter values store the current
+		 * XMAC statistic values to the entries 1..n of the
+		 * CounterOffset array. XMAC Errata #2
+		 */
+#ifdef DEBUG
+		if ((unsigned int)Param.Para64 >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_XMAC_RESET parameter wrong, PhysPortIndex=%d\n",
+				(unsigned int)Param.Para64));
+			return (0);
+		}
+#endif
+		PhysPortIndex = (unsigned int)Param.Para64;
+
+		/*
+		 * Update XMAC statistic to get fresh values
+		 */
+		Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+		if (Ret != SK_PNMI_ERR_OK) {
+
+			SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+			return (0);
+		}
+		/*
+		 * Increment semaphore to indicate that an update was
+		 * already done
+		 */
+		pAC->Pnmi.MacUpdatedFlag ++;
+
+		for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
+			CounterIndex ++) {
+
+			if (!StatAddr[CounterIndex][MacType].GetOffset) {
+
+				continue;
+			}
+
+			pAC->Pnmi.Port[PhysPortIndex].CounterOffset[CounterIndex] =
+				GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex);
+			
+			pAC->Pnmi.Port[PhysPortIndex].CounterHigh[CounterIndex] = 0;
+		}
+
+		pAC->Pnmi.MacUpdatedFlag --;
+		break;
+
+	case SK_PNMI_EVT_RLMT_PORT_UP:
+		PhysPortIndex = (unsigned int)Param.Para32[0];
+#ifdef DEBUG
+		if (PhysPortIndex >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_UP parameter"
+                 " wrong, PhysPortIndex=%d\n", PhysPortIndex));
+
+			return (0);
+		}
+#endif /* DEBUG */
+
+		/*
+		 * Store a trap message in the trap buffer and generate an event for
+		 * user space applications with the SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_UP, PhysPortIndex);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+
+		/* Bugfix for XMAC errata (#10620)*/
+		if (MacType == SK_MAC_XMAC) {
+			/* Add incremental difference to offset (#10620)*/
+			(void)pAC->GIni.GIFunc.pFnMacStatistic(pAC, IoC, PhysPortIndex,
+				XM_RXE_SHT_ERR, &Val32);
+			
+			Value = (((SK_U64)pAC->Pnmi.Port[PhysPortIndex].
+				 CounterHigh[SK_PNMI_HRX_SHORTS] << 32) | (SK_U64)Val32);
+			pAC->Pnmi.Port[PhysPortIndex].CounterOffset[SK_PNMI_HRX_SHORTS] +=
+				Value - pAC->Pnmi.Port[PhysPortIndex].RxShortZeroMark;
+		}
+		
+		/* Tell VctStatus() that a link was up meanwhile. */
+		pAC->Pnmi.VctStatus[PhysPortIndex] |= SK_PNMI_VCT_LINK;		
+		break;
+
+    case SK_PNMI_EVT_RLMT_PORT_DOWN:
+		PhysPortIndex = (unsigned int)Param.Para32[0];
+
+#ifdef DEBUG
+		if (PhysPortIndex >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_PORT_DOWN parameter"
+                 " wrong, PhysPortIndex=%d\n", PhysPortIndex));
+
+			return (0);
+		}
+#endif /* DEBUG */
+
+		/*
+		 * Store a trap message in the trap buffer and generate an event for
+		 * user space applications with the SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueRlmtPortTrap(pAC, OID_SKGE_TRAP_RLMT_PORT_DOWN, PhysPortIndex);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+
+		/* Bugfix #10620 - get zero level for incremental difference */
+		if (MacType == SK_MAC_XMAC) {
+
+			(void)pAC->GIni.GIFunc.pFnMacStatistic(pAC, IoC, PhysPortIndex,
+				XM_RXE_SHT_ERR, &Val32);
+			
+			pAC->Pnmi.Port[PhysPortIndex].RxShortZeroMark =
+				(((SK_U64)pAC->Pnmi.Port[PhysPortIndex].
+				 CounterHigh[SK_PNMI_HRX_SHORTS] << 32) | (SK_U64)Val32);
+		}
+		break;
+
+	case SK_PNMI_EVT_RLMT_ACTIVE_DOWN:
+		PhysPortIndex = (unsigned int)Param.Para32[0];
+		NetIndex = (SK_U32)Param.Para32[1];
+
+#ifdef DEBUG
+		if (PhysPortIndex >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_DOWN parameter too high, PhysPort=%d\n",
+				PhysPortIndex));
+		}
+
+		if (NetIndex >= pAC->Rlmt.NumNets) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_DOWN parameter too high, NetIndex=%d\n",
+				NetIndex));
+		}
+#endif /* DEBUG */
+
+		/*
+		 * For now, ignore event if NetIndex != 0.
+		 */
+		if (Param.Para32[1] != 0) {
+
+			return (0);
+		}
+
+		/*
+		 * Nothing to do if port is already inactive
+		 */
+		if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+			return (0);
+		}
+
+		/*
+		 * Update statistic counters to calculate new offset for the virtual
+		 * port and increment semaphore to indicate that an update was already
+		 * done.
+		 */
+		if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) !=
+			SK_PNMI_ERR_OK) {
+
+			SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+			return (0);
+		}
+		pAC->Pnmi.MacUpdatedFlag ++;
+
+		/*
+		 * Calculate new counter offset for virtual port to grant continous
+		 * counting on port switches. The virtual port consists of all currently
+		 * active ports. The port down event indicates that a port is removed
+		 * from the virtual port. Therefore add the counter value of the removed
+		 * port to the CounterOffset for the virtual port to grant the same
+		 * counter value.
+		 */
+		for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
+			CounterIndex ++) {
+
+			if (!StatAddr[CounterIndex][MacType].GetOffset) {
+
+				continue;
+			}
+
+			Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex);
+
+			pAC->Pnmi.VirtualCounterOffset[CounterIndex] += Value;
+		}
+
+		/*
+		 * Set port to inactive
+		 */
+		pAC->Pnmi.Port[PhysPortIndex].ActiveFlag = SK_FALSE;
+
+		pAC->Pnmi.MacUpdatedFlag --;
+		break;
+
+	case SK_PNMI_EVT_RLMT_ACTIVE_UP:
+		PhysPortIndex = (unsigned int)Param.Para32[0];
+		NetIndex = (SK_U32)Param.Para32[1];
+
+#ifdef DEBUG
+		if (PhysPortIndex >= SK_MAX_MACS) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_UP parameter too high, PhysPort=%d\n",
+				PhysPortIndex));
+		}
+
+		if (NetIndex >= pAC->Rlmt.NumNets) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_CTRL,
+				("PNMI: ERR: SkPnmiEvent: SK_PNMI_EVT_RLMT_ACTIVE_UP parameter too high, NetIndex=%d\n",
+				NetIndex));
+		}
+#endif /* DEBUG */
+
+		/*
+		 * For now, ignore event if NetIndex != 0.
+		 */
+		if (Param.Para32[1] != 0) {
+
+			return (0);
+		}
+
+		/*
+		 * Nothing to do if port is already active
+		 */
+		if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+			return (0);
+		}
+
+		/*
+		 * Statistic maintenance
+		 */
+		pAC->Pnmi.RlmtChangeCts ++;
+		pAC->Pnmi.RlmtChangeTime = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+
+		/*
+		 * Store a trap message in the trap buffer and generate an event for
+		 * user space applications with the SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueRlmtNewMacTrap(pAC, PhysPortIndex);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+
+		/*
+		 * Update statistic counters to calculate new offset for the virtual
+		 * port and increment semaphore to indicate that an update was
+		 * already done.
+		 */
+		if (MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1) !=
+			SK_PNMI_ERR_OK) {
+
+			SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+			return (0);
+		}
+		pAC->Pnmi.MacUpdatedFlag ++;
+
+		/*
+		 * Calculate new counter offset for virtual port to grant continous
+		 * counting on port switches. A new port is added to the virtual port.
+		 * Therefore substract the counter value of the new port from the
+		 * CounterOffset for the virtual port to grant the same value.
+		 */
+		for (CounterIndex = 0; CounterIndex < SK_PNMI_MAX_IDX;
+			CounterIndex ++) {
+
+			if (!StatAddr[CounterIndex][MacType].GetOffset) {
+
+				continue;
+			}
+
+			Value = GetPhysStatVal(pAC, IoC, PhysPortIndex, CounterIndex);
+
+			pAC->Pnmi.VirtualCounterOffset[CounterIndex] -= Value;
+		}
+
+		/* Set port to active */
+		pAC->Pnmi.Port[PhysPortIndex].ActiveFlag = SK_TRUE;
+
+		pAC->Pnmi.MacUpdatedFlag --;
+		break;
+
+	case SK_PNMI_EVT_RLMT_SEGMENTATION:
+		/*
+		 * Para.Para32[0] contains the NetIndex.
+		 */
+
+		/*
+		 * Store a trap message in the trap buffer and generate an event for
+		 * user space applications with the SK_DRIVER_SENDEVENT macro.
+		 */
+		QueueSimpleTrap(pAC, OID_SKGE_TRAP_RLMT_SEGMENTATION);
+		(void)SK_DRIVER_SENDEVENT(pAC, IoC);
+		break;
+
+    case SK_PNMI_EVT_RLMT_SET_NETS:
+		/*
+		 *  Param.Para32[0] contains the number of Nets.
+		 *  Param.Para32[1] is reserved, contains -1.
+		 */
+	    /*
+    	 * Check number of nets
+		 */
+		MaxNetNumber = pAC->GIni.GIMacsFound;
+		if (((unsigned int)Param.Para32[0] < 1)
+			|| ((unsigned int)Param.Para32[0] > MaxNetNumber)) {
+			return (SK_PNMI_ERR_UNKNOWN_NET);
+		}
+
+        if ((unsigned int)Param.Para32[0] == 1) { /* single net mode */
+        	pAC->Pnmi.DualNetActiveFlag = SK_FALSE;
+        }
+        else { /* dual net mode */
+        	pAC->Pnmi.DualNetActiveFlag = SK_TRUE;
+        }
+        break;
+
+    case SK_PNMI_EVT_VCT_RESET:
+		PhysPortIndex = Param.Para32[0];
+		pPrt = &pAC->GIni.GP[PhysPortIndex];
+		pVctBackupData = &pAC->Pnmi.VctBackup[PhysPortIndex];
+		
+		if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING) {
+			RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_FALSE);
+			if (RetCode == 2) {
+				/*
+				 * VCT test is still running.
+				 * Start VCT timer counter again.
+				 */
+				SK_MEMSET((char *) &Param, 0, sizeof(Param));
+				Param.Para32[0] = PhysPortIndex;
+				Param.Para32[1] = -1;
+				SkTimerStart(pAC, IoC,
+					&pAC->Pnmi.VctTimeout[PhysPortIndex].VctTimer,
+				4000000, SKGE_PNMI, SK_PNMI_EVT_VCT_RESET, Param);
+				break;
+			}
+			pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_PENDING;
+			pAC->Pnmi.VctStatus[PhysPortIndex] |=
+				(SK_PNMI_VCT_NEW_VCT_DATA | SK_PNMI_VCT_TEST_DONE);
+			
+			/* Copy results for later use to PNMI struct. */
+			for (i = 0; i < 4; i++)  {
+				if (pPrt->PMdiPairSts[i] == SK_PNMI_VCT_NORMAL_CABLE) {
+					if ((pPrt->PMdiPairLen[i] > 35) &&
+						(pPrt->PMdiPairLen[i] < 0xff)) {
+						pPrt->PMdiPairSts[i] = SK_PNMI_VCT_IMPEDANCE_MISMATCH;
+					}
+				}
+				if ((pPrt->PMdiPairLen[i] > 35) &&
+					(pPrt->PMdiPairLen[i] != 0xff)) {
+					CableLength = 1000 *
+						(((175 * pPrt->PMdiPairLen[i]) / 210) - 28);
+				}
+				else {
+					CableLength = 0;
+				}
+				pVctBackupData->PMdiPairLen[i] = CableLength;
+				pVctBackupData->PMdiPairSts[i] = pPrt->PMdiPairSts[i];
+			}
+			
+			Param.Para32[0] = PhysPortIndex;
+			Param.Para32[1] = -1;
+			SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Param);
+			SkEventDispatcher(pAC, IoC);
+		}
+		
+		break;
+
+	default:
+		break;
+	}
+
+	SK_PNMI_CHECKFLAGS("SkPnmiEvent: On return");
+	return (0);
+}
+
+
+/******************************************************************************
+ *
+ * Private functions
+ *
+ */
+
+/*****************************************************************************
+ *
+ * PnmiVar - Gets, presets, and sets single OIDs
+ *
+ * Description:
+ *	Looks up the requested OID, calls the corresponding handler
+ *	function, and passes the parameters with the get, preset, or
+ *	set command. The function is called by SkGePnmiGetVar,
+ *	SkGePnmiPreSetVar, or SkGePnmiSetVar.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_XXX. For details have a look at the description of the
+ *	calling functions.
+ *	SK_PNMI_ERR_UNKNOWN_NET  The requested NetIndex doesn't exist
+ */
+PNMI_STATIC int PnmiVar(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* GET/PRESET/SET action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,	/* Total length of pBuf management data  */
+SK_U32 Instance,	/* Instance (1..n) that is to be set or -1 */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	unsigned int	TableIndex;
+	int		Ret;
+
+
+	if ((TableIndex = LookupId(Id)) == (unsigned int)(-1)) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_OID);
+	}
+	
+    /* Check NetIndex */
+	if (NetIndex >= pAC->Rlmt.NumNets) {
+		return (SK_PNMI_ERR_UNKNOWN_NET);
+	}
+
+	SK_PNMI_CHECKFLAGS("PnmiVar: On call");
+
+	Ret = IdTable[TableIndex].Func(pAC, IoC, Action, Id, pBuf, pLen,
+		Instance, TableIndex, NetIndex);
+
+	SK_PNMI_CHECKFLAGS("PnmiVar: On return");
+
+	return (Ret);
+}
+
+/*****************************************************************************
+ *
+ * PnmiStruct - Presets and Sets data in structure SK_PNMI_STRUCT_DATA
+ *
+ * Description:
+ *	The return value of the function will also be stored in
+ *	SK_PNMI_STRUCT_DATA if the passed buffer has the minimum size of
+ *	SK_PNMI_MIN_STRUCT_SIZE. The sub-function runs through the IdTable,
+ *	checks which OIDs are able to set, and calls the handler function of
+ *	the OID to perform the set. The return value of the function will
+ *	also be stored in SK_PNMI_STRUCT_DATA if the passed buffer has the
+ *	minimum size of SK_PNMI_MIN_STRUCT_SIZE. The function is called
+ *	by SkGePnmiPreSetStruct and SkGePnmiSetStruct.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_XXX. The codes are described in the calling functions.
+ *	SK_PNMI_ERR_UNKNOWN_NET  The requested NetIndex doesn't exist
+ */
+PNMI_STATIC int PnmiStruct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int  Action,	/* PRESET/SET action to be performed */
+char *pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,	/* Length of pBuf management data buffer */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	int		Ret;
+	unsigned int	TableIndex;
+	unsigned int	DstOffset;
+	unsigned int	Len;
+	unsigned int	InstanceNo;
+	unsigned int	InstanceCnt;
+	SK_U32		Instance;
+	SK_U32		Id;
+
+
+	/* Check if the passed buffer has the right size */
+	if (*pLen < SK_PNMI_STRUCT_SIZE) {
+
+		/* Check if we can return the error within the buffer */
+		if (*pLen >= SK_PNMI_MIN_STRUCT_SIZE) {
+
+			SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_TOO_SHORT,
+				(SK_U32)(-1));
+		}
+
+		*pLen = SK_PNMI_STRUCT_SIZE;
+		return (SK_PNMI_ERR_TOO_SHORT);
+	}
+	
+    /* Check NetIndex */
+	if (NetIndex >= pAC->Rlmt.NumNets) {
+		return (SK_PNMI_ERR_UNKNOWN_NET);
+	}
+	
+	SK_PNMI_CHECKFLAGS("PnmiStruct: On call");
+
+	/*
+	 * Update the values of RLMT and SIRQ and increment semaphores to
+	 * indicate that an update was already done.
+	 */
+	if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
+
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (Ret);
+	}
+
+	if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+		SK_PNMI_SET_STAT(pBuf, Ret, (SK_U32)(-1));
+		*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+		return (Ret);
+	}
+
+	pAC->Pnmi.RlmtUpdatedFlag ++;
+	pAC->Pnmi.SirqUpdatedFlag ++;
+
+	/* Preset/Set values */
+	for (TableIndex = 0; TableIndex < ID_TABLE_SIZE; TableIndex ++) {
+
+		if ((IdTable[TableIndex].Access != SK_PNMI_RW) &&
+			(IdTable[TableIndex].Access != SK_PNMI_WO)) {
+
+			continue;
+		}
+
+		InstanceNo = IdTable[TableIndex].InstanceNo;
+		Id = IdTable[TableIndex].Id;
+
+		for (InstanceCnt = 1; InstanceCnt <= InstanceNo;
+			InstanceCnt ++) {
+
+			DstOffset = IdTable[TableIndex].Offset +
+				(InstanceCnt - 1) *
+				IdTable[TableIndex].StructSize;
+
+			/*
+			 * Because VPD multiple instance variables are
+			 * not setable we do not need to evaluate VPD
+			 * instances. Have a look to VPD instance
+			 * calculation in SkPnmiGetStruct().
+			 */
+			Instance = (SK_U32)InstanceCnt;
+
+			/*
+			 * Evaluate needed buffer length
+			 */
+			Len = 0;
+			Ret = IdTable[TableIndex].Func(pAC, IoC,
+				SK_PNMI_GET, IdTable[TableIndex].Id,
+				NULL, &Len, Instance, TableIndex, NetIndex);
+
+			if (Ret == SK_PNMI_ERR_UNKNOWN_INST) {
+
+				break;
+			}
+			if (Ret != SK_PNMI_ERR_TOO_SHORT) {
+
+				pAC->Pnmi.RlmtUpdatedFlag --;
+				pAC->Pnmi.SirqUpdatedFlag --;
+
+				SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
+				SK_PNMI_SET_STAT(pBuf,
+					SK_PNMI_ERR_GENERAL, DstOffset);
+				*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			if (Id == OID_SKGE_VPD_ACTION) {
+
+				switch (*(pBuf + DstOffset)) {
+
+				case SK_PNMI_VPD_CREATE:
+					Len = 3 + *(pBuf + DstOffset + 3);
+					break;
+
+				case SK_PNMI_VPD_DELETE:
+					Len = 3;
+					break;
+
+				default:
+					Len = 1;
+					break;
+				}
+			}
+
+			/* Call the OID handler function */
+			Ret = IdTable[TableIndex].Func(pAC, IoC, Action,
+				IdTable[TableIndex].Id, pBuf + DstOffset,
+				&Len, Instance, TableIndex, NetIndex);
+
+			if (Ret != SK_PNMI_ERR_OK) {
+
+				pAC->Pnmi.RlmtUpdatedFlag --;
+				pAC->Pnmi.SirqUpdatedFlag --;
+
+				SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
+				SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_BAD_VALUE,
+					DstOffset);
+				*pLen = SK_PNMI_MIN_STRUCT_SIZE;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+		}
+	}
+
+	pAC->Pnmi.RlmtUpdatedFlag --;
+	pAC->Pnmi.SirqUpdatedFlag --;
+
+	SK_PNMI_CHECKFLAGS("PnmiStruct: On return");
+	SK_PNMI_SET_STAT(pBuf, SK_PNMI_ERR_OK, (SK_U32)(-1));
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * LookupId - Lookup an OID in the IdTable
+ *
+ * Description:
+ *	Scans the IdTable to find the table entry of an OID.
+ *
+ * Returns:
+ *	The table index or -1 if not found.
+ */
+PNMI_STATIC int LookupId(
+SK_U32 Id)		/* Object identifier to be searched */
+{
+	int i;
+
+	for (i = 0; i < ID_TABLE_SIZE; i++) {
+
+		if (IdTable[i].Id == Id) {
+
+			return i;
+		}
+	}
+
+	return (-1);
+}
+
+/*****************************************************************************
+ *
+ * OidStruct - Handler of OID_SKGE_ALL_DATA
+ *
+ * Description:
+ *	This OID performs a Get/Preset/SetStruct call and returns all data
+ *	in a SK_PNMI_STRUCT_DATA structure.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int OidStruct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* GET/PRESET/SET action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,	/* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	if (Id != OID_SKGE_ALL_DATA) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR003,
+			SK_PNMI_ERR003MSG);
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	/*
+	 * Check instance. We only handle single instance variables
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	switch (Action) {
+
+	case SK_PNMI_GET:
+		return (SkPnmiGetStruct(pAC, IoC, pBuf, pLen, NetIndex));
+
+	case SK_PNMI_PRESET:
+		return (SkPnmiPreSetStruct(pAC, IoC, pBuf, pLen, NetIndex));
+
+	case SK_PNMI_SET:
+		return (SkPnmiSetStruct(pAC, IoC, pBuf, pLen, NetIndex));
+	}
+
+	SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR004, SK_PNMI_ERR004MSG);
+
+	*pLen = 0;
+	return (SK_PNMI_ERR_GENERAL);
+}
+
+/*****************************************************************************
+ *
+ * Perform - OID handler of OID_SKGE_ACTION
+ *
+ * Description:
+ *	None.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int Perform(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* GET/PRESET/SET action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,	/* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	int	Ret;
+	SK_U32	ActionOp;
+
+
+	/*
+	 * Check instance. We only handle single instance variables
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	if (*pLen < sizeof(SK_U32)) {
+
+		*pLen = sizeof(SK_U32);
+		return (SK_PNMI_ERR_TOO_SHORT);
+	}
+
+	/* Check if a get should be performed */
+	if (Action == SK_PNMI_GET) {
+
+		/* A get is easy. We always return the same value */
+		ActionOp = (SK_U32)SK_PNMI_ACT_IDLE;
+		SK_PNMI_STORE_U32(pBuf, ActionOp);
+		*pLen = sizeof(SK_U32);
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	/* Continue with PRESET/SET action */
+	if (*pLen > sizeof(SK_U32)) {
+
+		return (SK_PNMI_ERR_BAD_VALUE);
+	}
+
+	/* Check if the command is a known one */
+	SK_PNMI_READ_U32(pBuf, ActionOp);
+	if (*pLen > sizeof(SK_U32) ||
+		(ActionOp != SK_PNMI_ACT_IDLE &&
+		ActionOp != SK_PNMI_ACT_RESET &&
+		ActionOp != SK_PNMI_ACT_SELFTEST &&
+		ActionOp != SK_PNMI_ACT_RESETCNT)) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_BAD_VALUE);
+	}
+
+	/* A preset ends here */
+	if (Action == SK_PNMI_PRESET) {
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	switch (ActionOp) {
+
+	case SK_PNMI_ACT_IDLE:
+		/* Nothing to do */
+		break;
+
+	case SK_PNMI_ACT_RESET:
+		/*
+		 * Perform a driver reset or something that comes near
+		 * to this.
+		 */
+		Ret = SK_DRIVER_RESET(pAC, IoC);
+		if (Ret != 0) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR005,
+				SK_PNMI_ERR005MSG);
+
+			return (SK_PNMI_ERR_GENERAL);
+		}
+		break;
+
+	case SK_PNMI_ACT_SELFTEST:
+		/*
+		 * Perform a driver selftest or something similar to this.
+		 * Currently this feature is not used and will probably
+		 * implemented in another way.
+		 */
+		Ret = SK_DRIVER_SELFTEST(pAC, IoC);
+		pAC->Pnmi.TestResult = Ret;
+		break;
+
+	case SK_PNMI_ACT_RESETCNT:
+		/* Set all counters and timestamps to zero */
+		ResetCounter(pAC, IoC, NetIndex);
+		break;
+
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR006,
+			SK_PNMI_ERR006MSG);
+
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Mac8023Stat - OID handler of OID_GEN_XXX and OID_802_3_XXX
+ *
+ * Description:
+ *	Retrieves the statistic values of the virtual port (logical
+ *	index 0). Only special OIDs of NDIS are handled which consist
+ *	of a 32 bit instead of a 64 bit value. The OIDs are public
+ *	because perhaps some other platform can use them too.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int Mac8023Stat(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* GET/PRESET/SET action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,	/* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex,	/* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	int     Ret;
+	SK_U64  StatVal;
+	SK_U32  StatVal32;
+	SK_BOOL Is64BitReq = SK_FALSE;
+
+	/*
+	 * Only the active Mac is returned
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	/*
+	 * Check action type
+	 */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/* Check length */
+	switch (Id) {
+
+	case OID_802_3_PERMANENT_ADDRESS:
+	case OID_802_3_CURRENT_ADDRESS:
+		if (*pLen < sizeof(SK_MAC_ADDR)) {
+
+			*pLen = sizeof(SK_MAC_ADDR);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	default:
+#ifndef SK_NDIS_64BIT_CTR
+		if (*pLen < sizeof(SK_U32)) {
+			*pLen = sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+
+#else /* SK_NDIS_64BIT_CTR */
+
+		/* for compatibility, at least 32bit are required for OID */
+		if (*pLen < sizeof(SK_U32)) {
+			/*
+			* but indicate handling for 64bit values,
+			* if insufficient space is provided
+			*/
+			*pLen = sizeof(SK_U64);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+
+		Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE;
+#endif /* SK_NDIS_64BIT_CTR */
+		break;
+	}
+
+	/*
+	 * Update all statistics, because we retrieve virtual MAC, which
+	 * consists of multiple physical statistics and increment semaphore
+	 * to indicate that an update was already done.
+	 */
+	Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+	if ( Ret != SK_PNMI_ERR_OK) {
+
+		*pLen = 0;
+		return (Ret);
+	}
+	pAC->Pnmi.MacUpdatedFlag ++;
+
+	/*
+	 * Get value (MAC Index 0 identifies the virtual MAC)
+	 */
+	switch (Id) {
+
+	case OID_802_3_PERMANENT_ADDRESS:
+		CopyMac(pBuf, &pAC->Addr.Net[NetIndex].PermanentMacAddress);
+		*pLen = sizeof(SK_MAC_ADDR);
+		break;
+
+	case OID_802_3_CURRENT_ADDRESS:
+		CopyMac(pBuf, &pAC->Addr.Net[NetIndex].CurrentMacAddress);
+		*pLen = sizeof(SK_MAC_ADDR);
+		break;
+
+	default:
+		StatVal = GetStatVal(pAC, IoC, 0, IdTable[TableIndex].Param, NetIndex);
+
+		/* by default 32bit values are evaluated */
+		if (!Is64BitReq) {
+			StatVal32 = (SK_U32)StatVal;
+			SK_PNMI_STORE_U32(pBuf, StatVal32);
+			*pLen = sizeof(SK_U32);
+		}
+		else {
+			SK_PNMI_STORE_U64(pBuf, StatVal);
+			*pLen = sizeof(SK_U64);
+		}
+		break;
+	}
+
+	pAC->Pnmi.MacUpdatedFlag --;
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * MacPrivateStat - OID handler function of OID_SKGE_STAT_XXX
+ *
+ * Description:
+ *	Retrieves the MAC statistic data.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int MacPrivateStat(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* GET/PRESET/SET action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,	/* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	unsigned int	LogPortMax;
+	unsigned int	LogPortIndex;
+	unsigned int	PhysPortMax;
+	unsigned int	Limit;
+	unsigned int	Offset;
+	int				MacType;
+	int				Ret;
+	SK_U64			StatVal;
+	
+	
+
+	/* Calculate instance if wished. MAC index 0 is the virtual MAC */
+	PhysPortMax = pAC->GIni.GIMacsFound;
+	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+	
+	MacType = pAC->GIni.GIMacType;
+
+	if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
+		LogPortMax--;
+	}
+
+	if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
+		/* Check instance range */
+		if ((Instance < 1) || (Instance > LogPortMax)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+		LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
+		Limit = LogPortIndex + 1;
+	}
+
+	else { /* Instance == (SK_U32)(-1), get all Instances of that OID */
+
+		LogPortIndex = 0;
+		Limit = LogPortMax;
+	}
+
+	/* Check action */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/* Check length */
+	if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U64)) {
+
+		*pLen = (Limit - LogPortIndex) * sizeof(SK_U64);
+		return (SK_PNMI_ERR_TOO_SHORT);
+	}
+
+	/*
+	 * Update MAC statistic and increment semaphore to indicate that
+	 * an update was already done.
+	 */
+	Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+	if (Ret != SK_PNMI_ERR_OK) {
+
+		*pLen = 0;
+		return (Ret);
+	}
+	pAC->Pnmi.MacUpdatedFlag ++;
+
+	/* Get value */
+	Offset = 0;
+	for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+		switch (Id) {
+
+/* XXX not yet implemented due to XMAC problems
+		case OID_SKGE_STAT_TX_UTIL:
+			return (SK_PNMI_ERR_GENERAL);
+*/
+/* XXX not yet implemented due to XMAC problems
+		case OID_SKGE_STAT_RX_UTIL:
+			return (SK_PNMI_ERR_GENERAL);
+*/
+		case OID_SKGE_STAT_RX:
+			if (MacType == SK_MAC_GMAC) {
+				StatVal =
+					GetStatVal(pAC, IoC, LogPortIndex,
+							   SK_PNMI_HRX_BROADCAST, NetIndex) +
+					GetStatVal(pAC, IoC, LogPortIndex,
+							   SK_PNMI_HRX_MULTICAST, NetIndex) +
+					GetStatVal(pAC, IoC, LogPortIndex,
+							   SK_PNMI_HRX_UNICAST, NetIndex) +
+					GetStatVal(pAC, IoC, LogPortIndex,
+							   SK_PNMI_HRX_UNDERSIZE, NetIndex);
+			}
+			else {
+				StatVal = GetStatVal(pAC, IoC, LogPortIndex,
+					IdTable[TableIndex].Param, NetIndex);
+			}
+			break;
+
+		case OID_SKGE_STAT_TX:
+			if (MacType == SK_MAC_GMAC) {
+				StatVal =
+					GetStatVal(pAC, IoC, LogPortIndex,
+							   SK_PNMI_HTX_BROADCAST, NetIndex) +
+					GetStatVal(pAC, IoC, LogPortIndex,
+							   SK_PNMI_HTX_MULTICAST, NetIndex) +
+					GetStatVal(pAC, IoC, LogPortIndex,
+							   SK_PNMI_HTX_UNICAST, NetIndex);
+			}
+			else {
+				StatVal = GetStatVal(pAC, IoC, LogPortIndex,
+					IdTable[TableIndex].Param, NetIndex);
+			}
+			break;
+
+		default:
+			StatVal = GetStatVal(pAC, IoC, LogPortIndex,
+				IdTable[TableIndex].Param, NetIndex);
+		}
+		SK_PNMI_STORE_U64(pBuf + Offset, StatVal);
+
+		Offset += sizeof(SK_U64);
+	}
+	*pLen = Offset;
+
+	pAC->Pnmi.MacUpdatedFlag --;
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Addr - OID handler function of OID_SKGE_PHYS_CUR_ADDR and _FAC_ADDR
+ *
+ * Description:
+ *	Get/Presets/Sets the current and factory MAC address. The MAC
+ *	address of the virtual port, which is reported to the OS, may
+ *	not be changed, but the physical ones. A set to the virtual port
+ *	will be ignored. No error should be reported because otherwise
+ *	a multiple instance set (-1) would always fail.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int Addr(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* GET/PRESET/SET action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,	/* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	int		Ret;
+	unsigned int	LogPortMax;
+	unsigned int	PhysPortMax;
+	unsigned int	LogPortIndex;
+	unsigned int	PhysPortIndex;
+	unsigned int	Limit;
+	unsigned int	Offset = 0;
+
+	/*
+	 * Calculate instance if wished. MAC index 0 is the virtual
+	 * MAC.
+	 */
+	PhysPortMax = pAC->GIni.GIMacsFound;
+	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+
+	if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
+		LogPortMax--;
+	}
+
+	if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
+		/* Check instance range */
+		if ((Instance < 1) || (Instance > LogPortMax)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+		LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
+		Limit = LogPortIndex + 1;
+	}
+	else { /* Instance == (SK_U32)(-1), get all Instances of that OID */
+
+		LogPortIndex = 0;
+		Limit = LogPortMax;
+	}
+
+	/*
+	 * Perform Action
+	 */
+	if (Action == SK_PNMI_GET) {
+
+		/* Check length */
+		if (*pLen < (Limit - LogPortIndex) * 6) {
+
+			*pLen = (Limit - LogPortIndex) * 6;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+
+		/*
+		 * Get value
+		 */
+		for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+			switch (Id) {
+
+			case OID_SKGE_PHYS_CUR_ADDR:
+				if (LogPortIndex == 0) {
+					CopyMac(pBuf + Offset, &pAC->Addr.Net[NetIndex].CurrentMacAddress);
+				}
+				else {
+					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
+
+					CopyMac(pBuf + Offset,
+						&pAC->Addr.Port[PhysPortIndex].CurrentMacAddress);
+				}
+				Offset += 6;
+				break;
+
+			case OID_SKGE_PHYS_FAC_ADDR:
+				if (LogPortIndex == 0) {
+					CopyMac(pBuf + Offset,
+						&pAC->Addr.Net[NetIndex].PermanentMacAddress);
+				}
+				else {
+					PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+						pAC, LogPortIndex);
+
+					CopyMac(pBuf + Offset,
+						&pAC->Addr.Port[PhysPortIndex].PermanentMacAddress);
+				}
+				Offset += 6;
+				break;
+
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR008,
+					SK_PNMI_ERR008MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+		}
+
+		*pLen = Offset;
+	}
+	else {
+		/*
+		 * The logical MAC address may not be changed only
+		 * the physical ones
+		 */
+		if (Id == OID_SKGE_PHYS_FAC_ADDR) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_READ_ONLY);
+		}
+
+		/*
+		 * Only the current address may be changed
+		 */
+		if (Id != OID_SKGE_PHYS_CUR_ADDR) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR009,
+				SK_PNMI_ERR009MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		/* Check length */
+		if (*pLen < (Limit - LogPortIndex) * 6) {
+
+			*pLen = (Limit - LogPortIndex) * 6;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		if (*pLen > (Limit - LogPortIndex) * 6) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE);
+		}
+
+		/*
+		 * Check Action
+		 */
+		if (Action == SK_PNMI_PRESET) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_OK);
+		}
+
+		/*
+		 * Set OID_SKGE_MAC_CUR_ADDR
+		 */
+		for (; LogPortIndex < Limit; LogPortIndex ++, Offset += 6) {
+
+			/*
+			 * A set to virtual port and set of broadcast
+			 * address will be ignored
+			 */
+			if (LogPortIndex == 0 || SK_MEMCMP(pBuf + Offset,
+				"\xff\xff\xff\xff\xff\xff", 6) == 0) {
+
+				continue;
+			}
+
+			PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC,
+				LogPortIndex);
+
+			Ret = SkAddrOverride(pAC, IoC, PhysPortIndex,
+				(SK_MAC_ADDR *)(pBuf + Offset),
+				(LogPortIndex == 0 ? SK_ADDR_VIRTUAL_ADDRESS :
+				SK_ADDR_PHYSICAL_ADDRESS));
+			if (Ret != SK_ADDR_OVERRIDE_SUCCESS) {
+
+				return (SK_PNMI_ERR_GENERAL);
+			}
+		}
+		*pLen = Offset;
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * CsumStat - OID handler function of OID_SKGE_CHKSM_XXX
+ *
+ * Description:
+ *	Retrieves the statistic values of the CSUM module. The CSUM data
+ *	structure must be available in the SK_AC even if the CSUM module
+ *	is not included, because PNMI reads the statistic data from the
+ *	CSUM part of SK_AC directly.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int CsumStat(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* GET/PRESET/SET action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,	/* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	unsigned int	Index;
+	unsigned int	Limit;
+	unsigned int	Offset = 0;
+	SK_U64		StatVal;
+
+
+	/*
+	 * Calculate instance if wished
+	 */
+	if (Instance != (SK_U32)(-1)) {
+
+		if ((Instance < 1) || (Instance > SKCS_NUM_PROTOCOLS)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+		Index = (unsigned int)Instance - 1;
+		Limit = Index + 1;
+	}
+	else {
+		Index = 0;
+		Limit = SKCS_NUM_PROTOCOLS;
+	}
+
+	/*
+	 * Check action
+	 */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/* Check length */
+	if (*pLen < (Limit - Index) * sizeof(SK_U64)) {
+
+		*pLen = (Limit - Index) * sizeof(SK_U64);
+		return (SK_PNMI_ERR_TOO_SHORT);
+	}
+
+	/*
+	 * Get value
+	 */
+	for (; Index < Limit; Index ++) {
+
+		switch (Id) {
+
+		case OID_SKGE_CHKSM_RX_OK_CTS:
+			StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxOkCts;
+			break;
+
+		case OID_SKGE_CHKSM_RX_UNABLE_CTS:
+			StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxUnableCts;
+			break;
+
+		case OID_SKGE_CHKSM_RX_ERR_CTS:
+			StatVal = pAC->Csum.ProtoStats[NetIndex][Index].RxErrCts;
+			break;
+
+		case OID_SKGE_CHKSM_TX_OK_CTS:
+			StatVal = pAC->Csum.ProtoStats[NetIndex][Index].TxOkCts;
+			break;
+
+		case OID_SKGE_CHKSM_TX_UNABLE_CTS:
+			StatVal = pAC->Csum.ProtoStats[NetIndex][Index].TxUnableCts;
+			break;
+
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR010,
+				SK_PNMI_ERR010MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		SK_PNMI_STORE_U64(pBuf + Offset, StatVal);
+		Offset += sizeof(SK_U64);
+	}
+
+	/*
+	 * Store used buffer space
+	 */
+	*pLen = Offset;
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * SensorStat - OID handler function of OID_SKGE_SENSOR_XXX
+ *
+ * Description:
+ *	Retrieves the statistic values of the I2C module, which handles
+ *	the temperature and voltage sensors.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int SensorStat(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* GET/PRESET/SET action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,	/* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	unsigned int	i;
+	unsigned int	Index;
+	unsigned int	Limit;
+	unsigned int	Offset;
+	unsigned int	Len;
+	SK_U32		Val32;
+	SK_U64		Val64;
+
+
+	/*
+	 * Calculate instance if wished
+	 */
+	if ((Instance != (SK_U32)(-1))) {
+
+		if ((Instance < 1) || (Instance > (SK_U32)pAC->I2c.MaxSens)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+
+		Index = (unsigned int)Instance -1;
+		Limit = (unsigned int)Instance;
+	}
+	else {
+		Index = 0;
+		Limit = (unsigned int) pAC->I2c.MaxSens;
+	}
+
+	/*
+	 * Check action
+	 */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/* Check length */
+	switch (Id) {
+
+	case OID_SKGE_SENSOR_VALUE:
+	case OID_SKGE_SENSOR_WAR_THRES_LOW:
+	case OID_SKGE_SENSOR_WAR_THRES_UPP:
+	case OID_SKGE_SENSOR_ERR_THRES_LOW:
+	case OID_SKGE_SENSOR_ERR_THRES_UPP:
+		if (*pLen < (Limit - Index) * sizeof(SK_U32)) {
+
+			*pLen = (Limit - Index) * sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_SENSOR_DESCR:
+		for (Offset = 0, i = Index; i < Limit; i ++) {
+
+			Len = (unsigned int)
+				SK_STRLEN(pAC->I2c.SenTable[i].SenDesc) + 1;
+			if (Len >= SK_PNMI_STRINGLEN2) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR011,
+					SK_PNMI_ERR011MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			Offset += Len;
+		}
+		if (*pLen < Offset) {
+
+			*pLen = Offset;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_SENSOR_INDEX:
+	case OID_SKGE_SENSOR_TYPE:
+	case OID_SKGE_SENSOR_STATUS:
+		if (*pLen < Limit - Index) {
+
+			*pLen = Limit - Index;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_SENSOR_WAR_CTS:
+	case OID_SKGE_SENSOR_WAR_TIME:
+	case OID_SKGE_SENSOR_ERR_CTS:
+	case OID_SKGE_SENSOR_ERR_TIME:
+		if (*pLen < (Limit - Index) * sizeof(SK_U64)) {
+
+			*pLen = (Limit - Index) * sizeof(SK_U64);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR012,
+			SK_PNMI_ERR012MSG);
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+
+	}
+
+	/*
+	 * Get value
+	 */
+	for (Offset = 0; Index < Limit; Index ++) {
+
+		switch (Id) {
+
+		case OID_SKGE_SENSOR_INDEX:
+			*(pBuf + Offset) = (char)Index;
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_SENSOR_DESCR:
+			Len = SK_STRLEN(pAC->I2c.SenTable[Index].SenDesc);
+			SK_MEMCPY(pBuf + Offset + 1,
+				pAC->I2c.SenTable[Index].SenDesc, Len);
+			*(pBuf + Offset) = (char)Len;
+			Offset += Len + 1;
+			break;
+
+		case OID_SKGE_SENSOR_TYPE:
+			*(pBuf + Offset) =
+				(char)pAC->I2c.SenTable[Index].SenType;
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_SENSOR_VALUE:
+			Val32 = (SK_U32)pAC->I2c.SenTable[Index].SenValue;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_SENSOR_WAR_THRES_LOW:
+			Val32 = (SK_U32)pAC->I2c.SenTable[Index].
+				SenThreWarnLow;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_SENSOR_WAR_THRES_UPP:
+			Val32 = (SK_U32)pAC->I2c.SenTable[Index].
+				SenThreWarnHigh;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_SENSOR_ERR_THRES_LOW:
+			Val32 = (SK_U32)pAC->I2c.SenTable[Index].
+				SenThreErrLow;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_SENSOR_ERR_THRES_UPP:
+			Val32 = pAC->I2c.SenTable[Index].SenThreErrHigh;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_SENSOR_STATUS:
+			*(pBuf + Offset) =
+				(char)pAC->I2c.SenTable[Index].SenErrFlag;
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_SENSOR_WAR_CTS:
+			Val64 = pAC->I2c.SenTable[Index].SenWarnCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_SENSOR_ERR_CTS:
+			Val64 = pAC->I2c.SenTable[Index].SenErrCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_SENSOR_WAR_TIME:
+			Val64 = SK_PNMI_HUNDREDS_SEC(pAC->I2c.SenTable[Index].
+				SenBegWarnTS);
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_SENSOR_ERR_TIME:
+			Val64 = SK_PNMI_HUNDREDS_SEC(pAC->I2c.SenTable[Index].
+				SenBegErrTS);
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		default:
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+				("SensorStat: Unknown OID should be handled before"));
+
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	}
+
+	/*
+	 * Store used buffer space
+	 */
+	*pLen = Offset;
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Vpd - OID handler function of OID_SKGE_VPD_XXX
+ *
+ * Description:
+ *	Get/preset/set of VPD data. As instance the name of a VPD key
+ *	can be passed. The Instance parameter is a SK_U32 and can be
+ *	used as a string buffer for the VPD key, because their maximum
+ *	length is 4 byte.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int Vpd(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* GET/PRESET/SET action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,	/* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	SK_VPD_STATUS	*pVpdStatus;
+	unsigned int	BufLen;
+	char		Buf[256];
+	char		KeyArr[SK_PNMI_VPD_ENTRIES][SK_PNMI_VPD_KEY_SIZE];
+	char		KeyStr[SK_PNMI_VPD_KEY_SIZE];
+	unsigned int	KeyNo;
+	unsigned int	Offset;
+	unsigned int	Index;
+	unsigned int	FirstIndex;
+	unsigned int	LastIndex;
+	unsigned int	Len;
+	int		Ret;
+	SK_U32		Val32;
+
+	/*
+	 * Get array of all currently stored VPD keys
+	 */
+	Ret = GetVpdKeyArr(pAC, IoC, &KeyArr[0][0], sizeof(KeyArr), &KeyNo);
+	if (Ret != SK_PNMI_ERR_OK) {
+		*pLen = 0;
+		return (Ret);
+	}
+
+	/*
+	 * If instance is not -1, try to find the requested VPD key for
+	 * the multiple instance variables. The other OIDs as for example
+	 * OID VPD_ACTION are single instance variables and must be
+	 * handled separatly.
+	 */
+	FirstIndex = 0;
+	LastIndex = KeyNo;
+
+	if ((Instance != (SK_U32)(-1))) {
+
+		if (Id == OID_SKGE_VPD_KEY || Id == OID_SKGE_VPD_VALUE ||
+			Id == OID_SKGE_VPD_ACCESS) {
+
+			SK_STRNCPY(KeyStr, (char *)&Instance, 4);
+			KeyStr[4] = 0;
+
+			for (Index = 0; Index < KeyNo; Index ++) {
+
+				if (SK_STRCMP(KeyStr, KeyArr[Index]) == 0) {
+					FirstIndex = Index;
+					LastIndex = Index+1;
+					break;
+				}
+			}
+			if (Index == KeyNo) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_UNKNOWN_INST);
+			}
+		}
+		else if (Instance != 1) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+	}
+
+	/*
+	 * Get value, if a query should be performed
+	 */
+	if (Action == SK_PNMI_GET) {
+
+		switch (Id) {
+
+		case OID_SKGE_VPD_FREE_BYTES:
+			/* Check length of buffer */
+			if (*pLen < sizeof(SK_U32)) {
+
+				*pLen = sizeof(SK_U32);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			/* Get number of free bytes */
+			pVpdStatus = VpdStat(pAC, IoC);
+			if (pVpdStatus == NULL) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR017,
+					SK_PNMI_ERR017MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			if ((pVpdStatus->vpd_status & VPD_VALID) == 0) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR018,
+					SK_PNMI_ERR018MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			
+			Val32 = (SK_U32)pVpdStatus->vpd_free_rw;
+			SK_PNMI_STORE_U32(pBuf, Val32);
+			*pLen = sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_VPD_ENTRIES_LIST:
+			/* Check length */
+			for (Len = 0, Index = 0; Index < KeyNo; Index ++) {
+
+				Len += SK_STRLEN(KeyArr[Index]) + 1;
+			}
+			if (*pLen < Len) {
+
+				*pLen = Len;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+
+			/* Get value */
+			*(pBuf) = (char)Len - 1;
+			for (Offset = 1, Index = 0; Index < KeyNo; Index ++) {
+
+				Len = SK_STRLEN(KeyArr[Index]);
+				SK_MEMCPY(pBuf + Offset, KeyArr[Index], Len);
+
+				Offset += Len;
+
+				if (Index < KeyNo - 1) {
+
+					*(pBuf + Offset) = ' ';
+					Offset ++;
+				}
+			}
+			*pLen = Offset;
+			break;
+
+		case OID_SKGE_VPD_ENTRIES_NUMBER:
+			/* Check length */
+			if (*pLen < sizeof(SK_U32)) {
+
+				*pLen = sizeof(SK_U32);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+
+			Val32 = (SK_U32)KeyNo;
+			SK_PNMI_STORE_U32(pBuf, Val32);
+			*pLen = sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_VPD_KEY:
+			/* Check buffer length, if it is large enough */
+			for (Len = 0, Index = FirstIndex;
+				Index < LastIndex; Index ++) {
+
+				Len += SK_STRLEN(KeyArr[Index]) + 1;
+			}
+			if (*pLen < Len) {
+
+				*pLen = Len;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+
+			/*
+			 * Get the key to an intermediate buffer, because
+			 * we have to prepend a length byte.
+			 */
+			for (Offset = 0, Index = FirstIndex;
+				Index < LastIndex; Index ++) {
+
+				Len = SK_STRLEN(KeyArr[Index]);
+
+				*(pBuf + Offset) = (char)Len;
+				SK_MEMCPY(pBuf + Offset + 1, KeyArr[Index],
+					Len);
+				Offset += Len + 1;
+			}
+			*pLen = Offset;
+			break;
+
+		case OID_SKGE_VPD_VALUE:
+			/* Check the buffer length if it is large enough */
+			for (Offset = 0, Index = FirstIndex;
+				Index < LastIndex; Index ++) {
+
+				BufLen = 256;
+				if (VpdRead(pAC, IoC, KeyArr[Index], Buf,
+					(int *)&BufLen) > 0 ||
+					BufLen >= SK_PNMI_VPD_DATALEN) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR021,
+						SK_PNMI_ERR021MSG);
+
+					return (SK_PNMI_ERR_GENERAL);
+				}
+				Offset += BufLen + 1;
+			}
+			if (*pLen < Offset) {
+
+				*pLen = Offset;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+
+			/*
+			 * Get the value to an intermediate buffer, because
+			 * we have to prepend a length byte.
+			 */
+			for (Offset = 0, Index = FirstIndex;
+				Index < LastIndex; Index ++) {
+
+				BufLen = 256;
+				if (VpdRead(pAC, IoC, KeyArr[Index], Buf,
+					(int *)&BufLen) > 0 ||
+					BufLen >= SK_PNMI_VPD_DATALEN) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR022,
+						SK_PNMI_ERR022MSG);
+
+					*pLen = 0;
+					return (SK_PNMI_ERR_GENERAL);
+				}
+
+				*(pBuf + Offset) = (char)BufLen;
+				SK_MEMCPY(pBuf + Offset + 1, Buf, BufLen);
+				Offset += BufLen + 1;
+			}
+			*pLen = Offset;
+			break;
+
+		case OID_SKGE_VPD_ACCESS:
+			if (*pLen < LastIndex - FirstIndex) {
+
+				*pLen = LastIndex - FirstIndex;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+
+			for (Offset = 0, Index = FirstIndex;
+				Index < LastIndex; Index ++) {
+
+				if (VpdMayWrite(KeyArr[Index])) {
+
+					*(pBuf + Offset) = SK_PNMI_VPD_RW;
+				}
+				else {
+					*(pBuf + Offset) = SK_PNMI_VPD_RO;
+				}
+				Offset ++;
+			}
+			*pLen = Offset;
+			break;
+
+		case OID_SKGE_VPD_ACTION:
+			Offset = LastIndex - FirstIndex;
+			if (*pLen < Offset) {
+
+				*pLen = Offset;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			SK_MEMSET(pBuf, 0, Offset);
+			*pLen = Offset;
+			break;
+
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR023,
+				SK_PNMI_ERR023MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	}
+	else {
+		/* The only OID which can be set is VPD_ACTION */
+		if (Id != OID_SKGE_VPD_ACTION) {
+
+			if (Id == OID_SKGE_VPD_FREE_BYTES ||
+				Id == OID_SKGE_VPD_ENTRIES_LIST ||
+				Id == OID_SKGE_VPD_ENTRIES_NUMBER ||
+				Id == OID_SKGE_VPD_KEY ||
+				Id == OID_SKGE_VPD_VALUE ||
+				Id == OID_SKGE_VPD_ACCESS) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_READ_ONLY);
+			}
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR024,
+				SK_PNMI_ERR024MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		/*
+		 * From this point we handle VPD_ACTION. Check the buffer
+		 * length. It should at least have the size of one byte.
+		 */
+		if (*pLen < 1) {
+
+			*pLen = 1;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+
+		/*
+		 * The first byte contains the VPD action type we should
+		 * perform.
+		 */
+		switch (*pBuf) {
+
+		case SK_PNMI_VPD_IGNORE:
+			/* Nothing to do */
+			break;
+
+		case SK_PNMI_VPD_CREATE:
+			/*
+			 * We have to create a new VPD entry or we modify
+			 * an existing one. Check first the buffer length.
+			 */
+			if (*pLen < 4) {
+
+				*pLen = 4;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			KeyStr[0] = pBuf[1];
+			KeyStr[1] = pBuf[2];
+			KeyStr[2] = 0;
+
+			/*
+			 * Is the entry writable or does it belong to the
+			 * read-only area?
+			 */
+			if (!VpdMayWrite(KeyStr)) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			Offset = (int)pBuf[3] & 0xFF;
+
+			SK_MEMCPY(Buf, pBuf + 4, Offset);
+			Buf[Offset] = 0;
+
+			/* A preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			/* Write the new entry or modify an existing one */
+			Ret = VpdWrite(pAC, IoC, KeyStr, Buf);
+			if (Ret == SK_PNMI_VPD_NOWRITE ) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+			else if (Ret != SK_PNMI_VPD_OK) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR025,
+					SK_PNMI_ERR025MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+
+			/*
+			 * Perform an update of the VPD data. This is
+			 * not mandantory, but just to be sure.
+			 */
+			Ret = VpdUpdate(pAC, IoC);
+			if (Ret != SK_PNMI_VPD_OK) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR026,
+					SK_PNMI_ERR026MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			break;
+
+		case SK_PNMI_VPD_DELETE:
+			/* Check if the buffer size is plausible */
+			if (*pLen < 3) {
+
+				*pLen = 3;
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			if (*pLen > 3) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+			KeyStr[0] = pBuf[1];
+			KeyStr[1] = pBuf[2];
+			KeyStr[2] = 0;
+
+			/* Find the passed key in the array */
+			for (Index = 0; Index < KeyNo; Index ++) {
+
+				if (SK_STRCMP(KeyStr, KeyArr[Index]) == 0) {
+
+					break;
+				}
+			}
+			/*
+			 * If we cannot find the key it is wrong, so we
+			 * return an appropriate error value.
+			 */
+			if (Index == KeyNo) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			/* Ok, you wanted it and you will get it */
+			Ret = VpdDelete(pAC, IoC, KeyStr);
+			if (Ret != SK_PNMI_VPD_OK) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR027,
+					SK_PNMI_ERR027MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+
+			/*
+			 * Perform an update of the VPD data. This is
+			 * not mandantory, but just to be sure.
+			 */
+			Ret = VpdUpdate(pAC, IoC);
+			if (Ret != SK_PNMI_VPD_OK) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR028,
+					SK_PNMI_ERR028MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			break;
+
+		default:
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE);
+		}
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * General - OID handler function of various single instance OIDs
+ *
+ * Description:
+ *	The code is simple. No description necessary.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int General(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* GET/PRESET/SET action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	int		Ret;
+	unsigned int	Index;
+	unsigned int	Len;
+	unsigned int	Offset;
+	unsigned int	Val;
+	SK_U8		Val8;
+	SK_U16		Val16;
+	SK_U32		Val32;
+	SK_U64		Val64;
+	SK_U64		Val64RxHwErrs = 0;
+	SK_U64		Val64TxHwErrs = 0;
+	SK_BOOL		Is64BitReq = SK_FALSE;
+	char		Buf[256];
+	int			MacType;
+
+	/*
+	 * Check instance. We only handle single instance variables.
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	/*
+	 * Check action. We only allow get requests.
+	 */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+	
+	MacType = pAC->GIni.GIMacType;
+	
+	/*
+	 * Check length for the various supported OIDs
+	 */
+	switch (Id) {
+
+	case OID_GEN_XMIT_ERROR:
+	case OID_GEN_RCV_ERROR:
+	case OID_GEN_RCV_NO_BUFFER:
+#ifndef SK_NDIS_64BIT_CTR
+		if (*pLen < sizeof(SK_U32)) {
+			*pLen = sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+
+#else /* SK_NDIS_64BIT_CTR */
+
+		/*
+		 * for compatibility, at least 32bit are required for oid
+		 */
+		if (*pLen < sizeof(SK_U32)) {
+			/*
+			* but indicate handling for 64bit values,
+			* if insufficient space is provided
+			*/
+			*pLen = sizeof(SK_U64);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+
+		Is64BitReq = (*pLen < sizeof(SK_U64)) ? SK_FALSE : SK_TRUE;
+#endif /* SK_NDIS_64BIT_CTR */
+		break;
+
+	case OID_SKGE_PORT_NUMBER:
+	case OID_SKGE_DEVICE_TYPE:
+	case OID_SKGE_RESULT:
+	case OID_SKGE_RLMT_MONITOR_NUMBER:
+	case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+	case OID_SKGE_TRAP_NUMBER:
+	case OID_SKGE_MDB_VERSION:
+	case OID_SKGE_BOARDLEVEL:
+	case OID_SKGE_CHIPID:
+	case OID_SKGE_RAMSIZE:
+		if (*pLen < sizeof(SK_U32)) {
+
+			*pLen = sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_CHIPSET:
+		if (*pLen < sizeof(SK_U16)) {
+
+			*pLen = sizeof(SK_U16);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_BUS_TYPE:
+	case OID_SKGE_BUS_SPEED:
+	case OID_SKGE_BUS_WIDTH:
+	case OID_SKGE_SENSOR_NUMBER:
+	case OID_SKGE_CHKSM_NUMBER:
+	case OID_SKGE_VAUXAVAIL:
+		if (*pLen < sizeof(SK_U8)) {
+
+			*pLen = sizeof(SK_U8);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_TX_SW_QUEUE_LEN:
+	case OID_SKGE_TX_SW_QUEUE_MAX:
+	case OID_SKGE_TX_RETRY:
+	case OID_SKGE_RX_INTR_CTS:
+	case OID_SKGE_TX_INTR_CTS:
+	case OID_SKGE_RX_NO_BUF_CTS:
+	case OID_SKGE_TX_NO_BUF_CTS:
+	case OID_SKGE_TX_USED_DESCR_NO:
+	case OID_SKGE_RX_DELIVERED_CTS:
+	case OID_SKGE_RX_OCTETS_DELIV_CTS:
+	case OID_SKGE_RX_HW_ERROR_CTS:
+	case OID_SKGE_TX_HW_ERROR_CTS:
+	case OID_SKGE_IN_ERRORS_CTS:
+	case OID_SKGE_OUT_ERROR_CTS:
+	case OID_SKGE_ERR_RECOVERY_CTS:
+	case OID_SKGE_SYSUPTIME:
+		if (*pLen < sizeof(SK_U64)) {
+
+			*pLen = sizeof(SK_U64);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	default:
+		/* Checked later */
+		break;
+	}
+
+	/* Update statistic */
+	if (Id == OID_SKGE_RX_HW_ERROR_CTS ||
+		Id == OID_SKGE_TX_HW_ERROR_CTS ||
+		Id == OID_SKGE_IN_ERRORS_CTS ||
+		Id == OID_SKGE_OUT_ERROR_CTS ||
+		Id == OID_GEN_XMIT_ERROR ||
+		Id == OID_GEN_RCV_ERROR) {
+
+		/* Force the XMAC to update its statistic counters and
+		 * Increment semaphore to indicate that an update was
+		 * already done.
+		 */
+		Ret = MacUpdate(pAC, IoC, 0, pAC->GIni.GIMacsFound - 1);
+		if (Ret != SK_PNMI_ERR_OK) {
+
+			*pLen = 0;
+			return (Ret);
+		}
+		pAC->Pnmi.MacUpdatedFlag ++;
+
+		/*
+		 * Some OIDs consist of multiple hardware counters. Those
+		 * values which are contained in all of them will be added
+		 * now.
+		 */
+		switch (Id) {
+
+		case OID_SKGE_RX_HW_ERROR_CTS:
+		case OID_SKGE_IN_ERRORS_CTS:
+		case OID_GEN_RCV_ERROR:
+			Val64RxHwErrs =
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_MISSED, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FRAMING, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_OVERFLOW, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_JABBER, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CARRIER, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_IRLENGTH, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SYMBOL, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_SHORTS, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_RUNT, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_TOO_LONG, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_FCS, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HRX_CEXT, NetIndex);
+	        break;
+
+		case OID_SKGE_TX_HW_ERROR_CTS:
+		case OID_SKGE_OUT_ERROR_CTS:
+		case OID_GEN_XMIT_ERROR:
+			Val64TxHwErrs =
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_EXCESS_COL, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_LATE_COL, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_UNDERRUN, NetIndex) +
+				GetStatVal(pAC, IoC, 0, SK_PNMI_HTX_CARRIER, NetIndex);
+			break;
+		}
+	}
+
+	/*
+	 * Retrieve value
+	 */
+	switch (Id) {
+
+	case OID_SKGE_SUPPORTED_LIST:
+		Len = ID_TABLE_SIZE * sizeof(SK_U32);
+		if (*pLen < Len) {
+
+			*pLen = Len;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		for (Offset = 0, Index = 0; Offset < Len;
+			Offset += sizeof(SK_U32), Index ++) {
+
+			Val32 = (SK_U32)IdTable[Index].Id;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+		}
+		*pLen = Len;
+		break;
+
+	case OID_SKGE_BOARDLEVEL:
+		Val32 = (SK_U32)pAC->GIni.GILevel;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_PORT_NUMBER:
+		Val32 = (SK_U32)pAC->GIni.GIMacsFound;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_DEVICE_TYPE:
+		Val32 = (SK_U32)pAC->Pnmi.DeviceType;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_DRIVER_DESCR:
+		if (pAC->Pnmi.pDriverDescription == NULL) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR007,
+				SK_PNMI_ERR007MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		Len = SK_STRLEN(pAC->Pnmi.pDriverDescription) + 1;
+		if (Len > SK_PNMI_STRINGLEN1) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR029,
+				SK_PNMI_ERR029MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		if (*pLen < Len) {
+
+			*pLen = Len;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		*pBuf = (char)(Len - 1);
+		SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverDescription, Len - 1);
+		*pLen = Len;
+		break;
+
+	case OID_SKGE_DRIVER_VERSION:
+		if (pAC->Pnmi.pDriverVersion == NULL) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030,
+				SK_PNMI_ERR030MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		Len = SK_STRLEN(pAC->Pnmi.pDriverVersion) + 1;
+		if (Len > SK_PNMI_STRINGLEN1) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031,
+				SK_PNMI_ERR031MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		if (*pLen < Len) {
+
+			*pLen = Len;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		*pBuf = (char)(Len - 1);
+		SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverVersion, Len - 1);
+		*pLen = Len;
+		break;
+
+	case OID_SKGE_DRIVER_RELDATE:
+		if (pAC->Pnmi.pDriverReleaseDate == NULL) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030,
+				SK_PNMI_ERR053MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		Len = SK_STRLEN(pAC->Pnmi.pDriverReleaseDate) + 1;
+		if (Len > SK_PNMI_STRINGLEN1) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031,
+				SK_PNMI_ERR054MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		if (*pLen < Len) {
+
+			*pLen = Len;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		*pBuf = (char)(Len - 1);
+		SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverReleaseDate, Len - 1);
+		*pLen = Len;
+		break;
+
+	case OID_SKGE_DRIVER_FILENAME:
+		if (pAC->Pnmi.pDriverFileName == NULL) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR030,
+				SK_PNMI_ERR055MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		Len = SK_STRLEN(pAC->Pnmi.pDriverFileName) + 1;
+		if (Len > SK_PNMI_STRINGLEN1) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR031,
+				SK_PNMI_ERR056MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		if (*pLen < Len) {
+
+			*pLen = Len;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		*pBuf = (char)(Len - 1);
+		SK_MEMCPY(pBuf + 1, pAC->Pnmi.pDriverFileName, Len - 1);
+		*pLen = Len;
+		break;
+
+	case OID_SKGE_HW_DESCR:
+		/*
+		 * The hardware description is located in the VPD. This
+		 * query may move to the initialisation routine. But
+		 * the VPD data is cached and therefore a call here
+		 * will not make much difference.
+		 */
+		Len = 256;
+		if (VpdRead(pAC, IoC, VPD_NAME, Buf, (int *)&Len) > 0) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR032,
+				SK_PNMI_ERR032MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+		Len ++;
+		if (Len > SK_PNMI_STRINGLEN1) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR033,
+				SK_PNMI_ERR033MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+		if (*pLen < Len) {
+
+			*pLen = Len;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		*pBuf = (char)(Len - 1);
+		SK_MEMCPY(pBuf + 1, Buf, Len - 1);
+		*pLen = Len;
+		break;
+
+	case OID_SKGE_HW_VERSION:
+		/* Oh, I love to do some string manipulation */
+		if (*pLen < 5) {
+
+			*pLen = 5;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		Val8 = (SK_U8)pAC->GIni.GIPciHwRev;
+		pBuf[0] = 4;
+		pBuf[1] = 'v';
+		pBuf[2] = (char)(0x30 | ((Val8 >> 4) & 0x0F));
+		pBuf[3] = '.';
+		pBuf[4] = (char)(0x30 | (Val8 & 0x0F));
+		*pLen = 5;
+		break;
+
+	case OID_SKGE_CHIPSET:
+		Val16 = pAC->Pnmi.Chipset;
+		SK_PNMI_STORE_U16(pBuf, Val16);
+		*pLen = sizeof(SK_U16);
+		break;
+
+	case OID_SKGE_CHIPID:
+		Val32 = pAC->GIni.GIChipId;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_RAMSIZE:
+		Val32 = pAC->GIni.GIRamSize;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_VAUXAVAIL:
+		*pBuf = (char) pAC->GIni.GIVauxAvail;
+		*pLen = sizeof(char);
+		break;
+
+	case OID_SKGE_BUS_TYPE:
+		*pBuf = (char) SK_PNMI_BUS_PCI;
+		*pLen = sizeof(char);
+		break;
+
+	case OID_SKGE_BUS_SPEED:
+		*pBuf = pAC->Pnmi.PciBusSpeed;
+		*pLen = sizeof(char);
+		break;
+
+	case OID_SKGE_BUS_WIDTH:
+		*pBuf = pAC->Pnmi.PciBusWidth;
+		*pLen = sizeof(char);
+		break;
+
+	case OID_SKGE_RESULT:
+		Val32 = pAC->Pnmi.TestResult;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_SENSOR_NUMBER:
+		*pBuf = (char)pAC->I2c.MaxSens;
+		*pLen = sizeof(char);
+		break;
+
+	case OID_SKGE_CHKSM_NUMBER:
+		*pBuf = SKCS_NUM_PROTOCOLS;
+		*pLen = sizeof(char);
+		break;
+
+	case OID_SKGE_TRAP_NUMBER:
+		GetTrapQueueLen(pAC, &Len, &Val);
+		Val32 = (SK_U32)Val;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_TRAP:
+		GetTrapQueueLen(pAC, &Len, &Val);
+		if (*pLen < Len) {
+
+			*pLen = Len;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		CopyTrapQueue(pAC, pBuf);
+		*pLen = Len;
+		break;
+
+	case OID_SKGE_RLMT_MONITOR_NUMBER:
+/* XXX Not yet implemented by RLMT therefore we return zero elements */
+		Val32 = 0;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_SKGE_TX_SW_QUEUE_LEN:
+		/* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxSwQueueLen;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxSwQueueLen +
+					pAC->Pnmi.BufPort[1].TxSwQueueLen;
+			}			
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueLen;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].TxSwQueueLen +
+					pAC->Pnmi.Port[1].TxSwQueueLen;
+			}			
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+
+	case OID_SKGE_TX_SW_QUEUE_MAX:
+		/* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxSwQueueMax;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxSwQueueMax +
+					pAC->Pnmi.BufPort[1].TxSwQueueMax;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].TxSwQueueMax;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].TxSwQueueMax +
+					pAC->Pnmi.Port[1].TxSwQueueMax;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_TX_RETRY:
+		/* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxRetryCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxRetryCts +
+					pAC->Pnmi.BufPort[1].TxRetryCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].TxRetryCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].TxRetryCts +
+					pAC->Pnmi.Port[1].TxRetryCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_RX_INTR_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].RxIntrCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].RxIntrCts +
+					pAC->Pnmi.BufPort[1].RxIntrCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].RxIntrCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].RxIntrCts +
+					pAC->Pnmi.Port[1].RxIntrCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_TX_INTR_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxIntrCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxIntrCts +
+					pAC->Pnmi.BufPort[1].TxIntrCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].TxIntrCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].TxIntrCts +
+					pAC->Pnmi.Port[1].TxIntrCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_RX_NO_BUF_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].RxNoBufCts +
+					pAC->Pnmi.BufPort[1].RxNoBufCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].RxNoBufCts +
+					pAC->Pnmi.Port[1].RxNoBufCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_TX_NO_BUF_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxNoBufCts +
+					pAC->Pnmi.BufPort[1].TxNoBufCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].TxNoBufCts +
+					pAC->Pnmi.Port[1].TxNoBufCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_TX_USED_DESCR_NO:
+		/* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].TxUsedDescrNo;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].TxUsedDescrNo +
+					pAC->Pnmi.BufPort[1].TxUsedDescrNo;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].TxUsedDescrNo;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].TxUsedDescrNo +
+					pAC->Pnmi.Port[1].TxUsedDescrNo;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_RX_DELIVERED_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].RxDeliveredCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].RxDeliveredCts +
+					pAC->Pnmi.BufPort[1].RxDeliveredCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].RxDeliveredCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].RxDeliveredCts +
+					pAC->Pnmi.Port[1].RxDeliveredCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_RX_OCTETS_DELIV_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].RxOctetsDeliveredCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].RxOctetsDeliveredCts +
+					pAC->Pnmi.BufPort[1].RxOctetsDeliveredCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].RxOctetsDeliveredCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].RxOctetsDeliveredCts +
+					pAC->Pnmi.Port[1].RxOctetsDeliveredCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_RX_HW_ERROR_CTS:
+		SK_PNMI_STORE_U64(pBuf, Val64RxHwErrs);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_TX_HW_ERROR_CTS:
+		SK_PNMI_STORE_U64(pBuf, Val64TxHwErrs);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_IN_ERRORS_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = Val64RxHwErrs + pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = Val64RxHwErrs +
+					pAC->Pnmi.BufPort[0].RxNoBufCts +
+					pAC->Pnmi.BufPort[1].RxNoBufCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = Val64RxHwErrs +
+					pAC->Pnmi.Port[0].RxNoBufCts +
+					pAC->Pnmi.Port[1].RxNoBufCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_OUT_ERROR_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = Val64TxHwErrs + pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = Val64TxHwErrs +
+					pAC->Pnmi.BufPort[0].TxNoBufCts +
+					pAC->Pnmi.BufPort[1].TxNoBufCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = Val64TxHwErrs +
+					pAC->Pnmi.Port[0].TxNoBufCts +
+					pAC->Pnmi.Port[1].TxNoBufCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_ERR_RECOVERY_CTS:
+		/* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.BufPort[NetIndex].ErrRecoveryCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.BufPort[0].ErrRecoveryCts +
+					pAC->Pnmi.BufPort[1].ErrRecoveryCts;
+			}
+		}
+		else {
+			/* Dual net mode */
+			if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+				Val64 = pAC->Pnmi.Port[NetIndex].ErrRecoveryCts;
+			}
+			/* Single net mode */
+			else {
+				Val64 = pAC->Pnmi.Port[0].ErrRecoveryCts +
+					pAC->Pnmi.Port[1].ErrRecoveryCts;
+			}
+		}
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_SYSUPTIME:
+		Val64 = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+		Val64 -= pAC->Pnmi.StartUpTime;
+		SK_PNMI_STORE_U64(pBuf, Val64);
+		*pLen = sizeof(SK_U64);
+		break;
+
+	case OID_SKGE_MDB_VERSION:
+		Val32 = SK_PNMI_MDB_VERSION;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	case OID_GEN_RCV_ERROR:
+		/* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			Val64 = Val64RxHwErrs + pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+		}
+		else {
+			Val64 = Val64RxHwErrs + pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+		}
+
+		/*
+		 * by default 32bit values are evaluated
+		 */
+		if (!Is64BitReq) {
+			Val32 = (SK_U32)Val64;
+			SK_PNMI_STORE_U32(pBuf, Val32);
+			*pLen = sizeof(SK_U32);
+		}
+		else {
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+		}
+		break;
+
+	case OID_GEN_XMIT_ERROR:
+		/* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			Val64 = Val64TxHwErrs + pAC->Pnmi.BufPort[NetIndex].TxNoBufCts;
+		}
+		else {
+			Val64 = Val64TxHwErrs + pAC->Pnmi.Port[NetIndex].TxNoBufCts;
+		}
+
+		/*
+		 * by default 32bit values are evaluated
+		 */
+		if (!Is64BitReq) {
+			Val32 = (SK_U32)Val64;
+			SK_PNMI_STORE_U32(pBuf, Val32);
+			*pLen = sizeof(SK_U32);
+		}
+		else {
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+		}
+		break;
+
+	case OID_GEN_RCV_NO_BUFFER:
+		/* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+		if (MacType == SK_MAC_XMAC) {
+			Val64 = pAC->Pnmi.BufPort[NetIndex].RxNoBufCts;
+		}
+		else {
+			Val64 = pAC->Pnmi.Port[NetIndex].RxNoBufCts;
+		}
+
+		/*
+		 * by default 32bit values are evaluated
+		 */
+		if (!Is64BitReq) {
+			Val32 = (SK_U32)Val64;
+			SK_PNMI_STORE_U32(pBuf, Val32);
+			*pLen = sizeof(SK_U32);
+		}
+		else {
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+		}
+		break;
+
+	case OID_GEN_TRANSMIT_QUEUE_LENGTH:
+		Val32 = (SK_U32)pAC->Pnmi.Port[NetIndex].TxSwQueueLen;
+		SK_PNMI_STORE_U32(pBuf, Val32);
+		*pLen = sizeof(SK_U32);
+		break;
+
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR034,
+			SK_PNMI_ERR034MSG);
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	if (Id == OID_SKGE_RX_HW_ERROR_CTS ||
+		Id == OID_SKGE_TX_HW_ERROR_CTS ||
+		Id == OID_SKGE_IN_ERRORS_CTS ||
+		Id == OID_SKGE_OUT_ERROR_CTS ||
+		Id == OID_GEN_XMIT_ERROR ||
+		Id == OID_GEN_RCV_ERROR) {
+
+		pAC->Pnmi.MacUpdatedFlag --;
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Rlmt - OID handler function of OID_SKGE_RLMT_XXX single instance.
+ *
+ * Description:
+ *	Get/Presets/Sets the RLMT OIDs.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int Rlmt(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* GET/PRESET/SET action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,	/* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	int		Ret;
+	unsigned int	PhysPortIndex;
+	unsigned int	PhysPortMax;
+	SK_EVPARA	EventParam;
+	SK_U32		Val32;
+	SK_U64		Val64;
+
+
+	/*
+	 * Check instance. Only single instance OIDs are allowed here.
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	/*
+	 * Perform the requested action.
+	 */
+	if (Action == SK_PNMI_GET) {
+
+		/*
+		 * Check if the buffer length is large enough.
+		 */
+
+		switch (Id) {
+
+		case OID_SKGE_RLMT_MODE:
+		case OID_SKGE_RLMT_PORT_ACTIVE:
+		case OID_SKGE_RLMT_PORT_PREFERRED:
+			if (*pLen < sizeof(SK_U8)) {
+
+				*pLen = sizeof(SK_U8);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		case OID_SKGE_RLMT_PORT_NUMBER:
+			if (*pLen < sizeof(SK_U32)) {
+
+				*pLen = sizeof(SK_U32);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_CTS:
+		case OID_SKGE_RLMT_CHANGE_TIME:
+		case OID_SKGE_RLMT_CHANGE_ESTIM:
+		case OID_SKGE_RLMT_CHANGE_THRES:
+			if (*pLen < sizeof(SK_U64)) {
+
+				*pLen = sizeof(SK_U64);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR035,
+				SK_PNMI_ERR035MSG);
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		/*
+		 * Update RLMT statistic and increment semaphores to indicate
+		 * that an update was already done. Maybe RLMT will hold its
+		 * statistic always up to date some time. Then we can
+		 * remove this type of call.
+		 */
+		if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
+
+			*pLen = 0;
+			return (Ret);
+		}
+		pAC->Pnmi.RlmtUpdatedFlag ++;
+
+		/*
+		 * Retrieve Value
+		*/
+		switch (Id) {
+
+		case OID_SKGE_RLMT_MODE:
+			*pBuf = (char)pAC->Rlmt.Net[0].RlmtMode;
+			*pLen = sizeof(char);
+			break;
+
+		case OID_SKGE_RLMT_PORT_NUMBER:
+			Val32 = (SK_U32)pAC->GIni.GIMacsFound;
+			SK_PNMI_STORE_U32(pBuf, Val32);
+			*pLen = sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_RLMT_PORT_ACTIVE:
+			*pBuf = 0;
+			/*
+			 * If multiple ports may become active this OID
+			 * doesn't make sense any more. A new variable in
+			 * the port structure should be created. However,
+			 * for this variable the first active port is
+			 * returned.
+			 */
+			PhysPortMax = pAC->GIni.GIMacsFound;
+
+			for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
+				PhysPortIndex ++) {
+
+				if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+					*pBuf = (char)SK_PNMI_PORT_PHYS2LOG(PhysPortIndex);
+					break;
+				}
+			}
+			*pLen = sizeof(char);
+			break;
+
+		case OID_SKGE_RLMT_PORT_PREFERRED:
+			*pBuf = (char)SK_PNMI_PORT_PHYS2LOG(pAC->Rlmt.Net[NetIndex].Preference);
+			*pLen = sizeof(char);
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_CTS:
+			Val64 = pAC->Pnmi.RlmtChangeCts;
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_TIME:
+			Val64 = pAC->Pnmi.RlmtChangeTime;
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_ESTIM:
+			Val64 = pAC->Pnmi.RlmtChangeEstimate.Estimate;
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_THRES:
+			Val64 = pAC->Pnmi.RlmtChangeThreshold;
+			SK_PNMI_STORE_U64(pBuf, Val64);
+			*pLen = sizeof(SK_U64);
+			break;
+
+		default:
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+				("Rlmt: Unknown OID should be handled before"));
+
+			pAC->Pnmi.RlmtUpdatedFlag --;
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		pAC->Pnmi.RlmtUpdatedFlag --;
+	}
+	else {
+		/* Perform a preset or set */
+		switch (Id) {
+
+		case OID_SKGE_RLMT_MODE:
+			/* Check if the buffer length is plausible */
+			if (*pLen < sizeof(char)) {
+
+				*pLen = sizeof(char);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			/* Check if the value range is correct */
+			if (*pLen != sizeof(char) ||
+				(*pBuf & SK_PNMI_RLMT_MODE_CHK_LINK) == 0 ||
+				*(SK_U8 *)pBuf > 15) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_OK);
+			}
+			/* Send an event to RLMT to change the mode */
+			SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+			EventParam.Para32[0] |= (SK_U32)(*pBuf);
+			EventParam.Para32[1] = 0;
+			if (SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE,
+				EventParam) > 0) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR037,
+					SK_PNMI_ERR037MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			break;
+
+		case OID_SKGE_RLMT_PORT_PREFERRED:
+			/* Check if the buffer length is plausible */
+			if (*pLen < sizeof(char)) {
+
+				*pLen = sizeof(char);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			/* Check if the value range is correct */
+			if (*pLen != sizeof(char) || *(SK_U8 *)pBuf >
+				(SK_U8)pAC->GIni.GIMacsFound) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_OK);
+			}
+
+			/*
+			 * Send an event to RLMT change the preferred port.
+			 * A param of -1 means automatic mode. RLMT will
+			 * make the decision which is the preferred port.
+			 */
+			SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+			EventParam.Para32[0] = (SK_U32)(*pBuf) - 1;
+			EventParam.Para32[1] = NetIndex;
+			if (SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE,
+				EventParam) > 0) {
+
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR038,
+					SK_PNMI_ERR038MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+			break;
+
+		case OID_SKGE_RLMT_CHANGE_THRES:
+			/* Check if the buffer length is plausible */
+			if (*pLen < sizeof(SK_U64)) {
+
+				*pLen = sizeof(SK_U64);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			/*
+			 * There are not many restrictions to the
+			 * value range.
+			 */
+			if (*pLen != sizeof(SK_U64)) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+			/* A preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_OK);
+			}
+			/*
+			 * Store the new threshold, which will be taken
+			 * on the next timer event.
+			 */
+			SK_PNMI_READ_U64(pBuf, Val64);
+			pAC->Pnmi.RlmtChangeThreshold = Val64;
+			break;
+
+		default:
+			/* The other OIDs are not be able for set */
+			*pLen = 0;
+			return (SK_PNMI_ERR_READ_ONLY);
+		}
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * RlmtStat - OID handler function of OID_SKGE_RLMT_XXX multiple instance.
+ *
+ * Description:
+ *	Performs get requests on multiple instance variables.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int RlmtStat(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* GET/PRESET/SET action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,	/* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	unsigned int	PhysPortMax;
+	unsigned int	PhysPortIndex;
+	unsigned int	Limit;
+	unsigned int	Offset;
+	int		Ret;
+	SK_U32		Val32;
+	SK_U64		Val64;
+
+	/*
+	 * Calculate the port indexes from the instance.
+	 */
+	PhysPortMax = pAC->GIni.GIMacsFound;
+
+	if ((Instance != (SK_U32)(-1))) {
+		/* Check instance range */
+		if ((Instance < 1) || (Instance > PhysPortMax)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+
+		/* Single net mode */
+		PhysPortIndex = Instance - 1;
+
+		/* Dual net mode */
+		if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+			PhysPortIndex = NetIndex;
+		}
+
+		/* Both net modes */
+		Limit = PhysPortIndex + 1;
+	}
+	else {
+		/* Single net mode */
+		PhysPortIndex = 0;
+		Limit = PhysPortMax;
+
+		/* Dual net mode */
+		if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+			PhysPortIndex = NetIndex;
+			Limit = PhysPortIndex + 1;
+		}
+	}
+
+	/*
+	 * Currently only get requests are allowed.
+	 */
+	if (Action != SK_PNMI_GET) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/*
+	 * Check if the buffer length is large enough.
+	 */
+	switch (Id) {
+
+	case OID_SKGE_RLMT_PORT_INDEX:
+	case OID_SKGE_RLMT_STATUS:
+		if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U32)) {
+
+			*pLen = (Limit - PhysPortIndex) * sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	case OID_SKGE_RLMT_TX_HELLO_CTS:
+	case OID_SKGE_RLMT_RX_HELLO_CTS:
+	case OID_SKGE_RLMT_TX_SP_REQ_CTS:
+	case OID_SKGE_RLMT_RX_SP_CTS:
+		if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U64)) {
+
+			*pLen = (Limit - PhysPortIndex) * sizeof(SK_U64);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR039,
+			SK_PNMI_ERR039MSG);
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+
+	}
+
+	/*
+	 * Update statistic and increment semaphores to indicate that
+	 * an update was already done.
+	 */
+	if ((Ret = RlmtUpdate(pAC, IoC, NetIndex)) != SK_PNMI_ERR_OK) {
+
+		*pLen = 0;
+		return (Ret);
+	}
+	pAC->Pnmi.RlmtUpdatedFlag ++;
+
+	/*
+	 * Get value
+	 */
+	Offset = 0;
+	for (; PhysPortIndex < Limit; PhysPortIndex ++) {
+
+		switch (Id) {
+
+		case OID_SKGE_RLMT_PORT_INDEX:
+			Val32 = PhysPortIndex;
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_RLMT_STATUS:
+			if (pAC->Rlmt.Port[PhysPortIndex].PortState ==
+				SK_RLMT_PS_INIT ||
+				pAC->Rlmt.Port[PhysPortIndex].PortState ==
+				SK_RLMT_PS_DOWN) {
+
+				Val32 = SK_PNMI_RLMT_STATUS_ERROR;
+			}
+			else if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+				Val32 = SK_PNMI_RLMT_STATUS_ACTIVE;
+			}
+			else {
+				Val32 = SK_PNMI_RLMT_STATUS_STANDBY;
+			}
+			SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+			Offset += sizeof(SK_U32);
+			break;
+
+		case OID_SKGE_RLMT_TX_HELLO_CTS:
+			Val64 = pAC->Rlmt.Port[PhysPortIndex].TxHelloCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_RX_HELLO_CTS:
+			Val64 = pAC->Rlmt.Port[PhysPortIndex].RxHelloCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_TX_SP_REQ_CTS:
+			Val64 = pAC->Rlmt.Port[PhysPortIndex].TxSpHelloReqCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		case OID_SKGE_RLMT_RX_SP_CTS:
+			Val64 = pAC->Rlmt.Port[PhysPortIndex].RxSpHelloCts;
+			SK_PNMI_STORE_U64(pBuf + Offset, Val64);
+			Offset += sizeof(SK_U64);
+			break;
+
+		default:
+			SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+				("RlmtStat: Unknown OID should be errored before"));
+
+			pAC->Pnmi.RlmtUpdatedFlag --;
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	}
+	*pLen = Offset;
+
+	pAC->Pnmi.RlmtUpdatedFlag --;
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * MacPrivateConf - OID handler function of OIDs concerning the configuration
+ *
+ * Description:
+ *	Get/Presets/Sets the OIDs concerning the configuration.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int MacPrivateConf(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* GET/PRESET/SET action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,	/* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	unsigned int	PhysPortMax;
+	unsigned int	PhysPortIndex;
+	unsigned int	LogPortMax;
+	unsigned int	LogPortIndex;
+	unsigned int	Limit;
+	unsigned int	Offset;
+	char		Val8;
+	char 		*pBufPtr;
+	int			Ret;
+	SK_EVPARA	EventParam;
+	SK_U32		Val32;
+
+	/*
+	 * Calculate instance if wished. MAC index 0 is the virtual MAC.
+	 */
+	PhysPortMax = pAC->GIni.GIMacsFound;
+	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+
+	if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) { /* Dual net mode */
+		LogPortMax--;
+	}
+
+	if ((Instance != (SK_U32)(-1))) { /* Only one specific instance is queried */
+		/* Check instance range */
+		if ((Instance < 1) || (Instance > LogPortMax)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+		LogPortIndex = SK_PNMI_PORT_INST2LOG(Instance);
+		Limit = LogPortIndex + 1;
+	}
+
+	else { /* Instance == (SK_U32)(-1), get all Instances of that OID */
+
+		LogPortIndex = 0;
+		Limit = LogPortMax;
+	}
+
+	/*
+	 * Perform action
+	 */
+	if (Action == SK_PNMI_GET) {
+
+		/* Check length */
+		switch (Id) {
+
+		case OID_SKGE_PMD:
+		case OID_SKGE_CONNECTOR:
+		case OID_SKGE_LINK_CAP:
+		case OID_SKGE_LINK_MODE:
+		case OID_SKGE_LINK_MODE_STATUS:
+		case OID_SKGE_LINK_STATUS:
+		case OID_SKGE_FLOWCTRL_CAP:
+		case OID_SKGE_FLOWCTRL_MODE:
+		case OID_SKGE_FLOWCTRL_STATUS:
+		case OID_SKGE_PHY_OPERATION_CAP:
+		case OID_SKGE_PHY_OPERATION_MODE:
+		case OID_SKGE_PHY_OPERATION_STATUS:
+		case OID_SKGE_SPEED_CAP:
+		case OID_SKGE_SPEED_MODE:
+		case OID_SKGE_SPEED_STATUS:
+			if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U8)) {
+
+				*pLen = (Limit - LogPortIndex) * sizeof(SK_U8);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+        case OID_SKGE_MTU:
+        case OID_SKGE_PHY_TYPE:
+			if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U32)) {
+
+				*pLen = (Limit - LogPortIndex) * sizeof(SK_U32);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR041,
+				SK_PNMI_ERR041MSG);
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		/*
+		 * Update statistic and increment semaphore to indicate
+		 * that an update was already done.
+		 */
+		if ((Ret = SirqUpdate(pAC, IoC)) != SK_PNMI_ERR_OK) {
+
+			*pLen = 0;
+			return (Ret);
+		}
+		pAC->Pnmi.SirqUpdatedFlag ++;
+
+		/*
+		 * Get value
+		 */
+		Offset = 0;
+		for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+			pBufPtr = pBuf + Offset;
+			
+			switch (Id) {
+
+			case OID_SKGE_PMD:
+				*pBufPtr = pAC->Pnmi.PMD;
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_CONNECTOR:
+				*pBufPtr = pAC->Pnmi.Connector;
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_PHY_TYPE:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+						continue;
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+						Val32 = pAC->GIni.GP[PhysPortIndex].PhyType;
+						SK_PNMI_STORE_U32(pBufPtr, Val32);
+					}
+				}
+				else { /* DualNetMode */
+					
+					Val32 = pAC->GIni.GP[NetIndex].PhyType;
+					SK_PNMI_STORE_U32(pBufPtr, Val32);
+				}
+				Offset += sizeof(SK_U32);
+				break;
+
+			case OID_SKGE_LINK_CAP:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBufPtr);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkCap;
+					}
+				}
+				else { /* DualNetMode */
+					
+					*pBufPtr = pAC->GIni.GP[NetIndex].PLinkCap;
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_LINK_MODE:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBufPtr);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkModeConf;
+					}
+				}
+				else { /* DualNetMode */
+				
+					*pBufPtr = pAC->GIni.GP[NetIndex].PLinkModeConf;
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_LINK_MODE_STATUS:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBufPtr);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*pBufPtr =
+							CalculateLinkModeStatus(pAC, IoC, PhysPortIndex);
+					}
+				}
+				else { /* DualNetMode */
+					
+					*pBufPtr = CalculateLinkModeStatus(pAC, IoC, NetIndex);
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_LINK_STATUS:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBufPtr);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*pBufPtr = CalculateLinkStatus(pAC, IoC, PhysPortIndex);
+					}
+				}
+				else { /* DualNetMode */
+
+					*pBufPtr = CalculateLinkStatus(pAC, IoC, NetIndex);
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_FLOWCTRL_CAP:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBufPtr);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*pBufPtr = pAC->GIni.GP[PhysPortIndex].PFlowCtrlCap;
+					}
+				}
+				else { /* DualNetMode */
+				
+					*pBufPtr = pAC->GIni.GP[NetIndex].PFlowCtrlCap;
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_FLOWCTRL_MODE:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBufPtr);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*pBufPtr = pAC->GIni.GP[PhysPortIndex].PFlowCtrlMode;
+					}
+				}
+				else { /* DualNetMode */
+
+					*pBufPtr = pAC->GIni.GP[NetIndex].PFlowCtrlMode;
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_FLOWCTRL_STATUS:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBufPtr);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*pBufPtr = pAC->GIni.GP[PhysPortIndex].PFlowCtrlStatus;
+					}
+				}
+				else { /* DualNetMode */
+
+					*pBufPtr = pAC->GIni.GP[NetIndex].PFlowCtrlStatus;
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_PHY_OPERATION_CAP:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBufPtr);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*pBufPtr = pAC->GIni.GP[PhysPortIndex].PMSCap;
+					}
+				}
+				else { /* DualNetMode */
+				
+					*pBufPtr = pAC->GIni.GP[NetIndex].PMSCap;
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_PHY_OPERATION_MODE:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBufPtr);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+
+						*pBufPtr = pAC->GIni.GP[PhysPortIndex].PMSMode;
+					}
+				}
+				else { /* DualNetMode */
+				
+					*pBufPtr = pAC->GIni.GP[NetIndex].PMSMode;
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_PHY_OPERATION_STATUS:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBufPtr);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*pBufPtr = pAC->GIni.GP[PhysPortIndex].PMSStatus;
+					}
+				}
+				else {
+				
+					*pBufPtr = pAC->GIni.GP[NetIndex].PMSStatus;
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_SPEED_CAP:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBufPtr);
+					}
+					else {
+						/* Get value for physical ports */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkSpeedCap;
+					}
+				}
+				else { /* DualNetMode */
+				
+					*pBufPtr = pAC->GIni.GP[NetIndex].PLinkSpeedCap;
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_SPEED_MODE:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBufPtr);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkSpeed;
+					}
+				}
+				else { /* DualNetMode */
+
+					*pBufPtr = pAC->GIni.GP[NetIndex].PLinkSpeed;
+				}
+				Offset += sizeof(char);
+				break;
+
+			case OID_SKGE_SPEED_STATUS:
+				if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */
+					if (LogPortIndex == 0) {
+						/* Get value for virtual port */
+						VirtualConf(pAC, IoC, Id, pBufPtr);
+					}
+					else {
+						/* Get value for physical port */
+						PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(
+							pAC, LogPortIndex);
+	
+						*pBufPtr = pAC->GIni.GP[PhysPortIndex].PLinkSpeedUsed;
+					}
+				}
+				else { /* DualNetMode */
+
+					*pBufPtr = pAC->GIni.GP[NetIndex].PLinkSpeedUsed;
+				}
+				Offset += sizeof(char);
+				break;
+			
+			case OID_SKGE_MTU:
+				Val32 = SK_DRIVER_GET_MTU(pAC, IoC, NetIndex);
+				SK_PNMI_STORE_U32(pBufPtr, Val32);
+				Offset += sizeof(SK_U32);
+				break;
+
+			default:
+				SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+					("MacPrivateConf: Unknown OID should be handled before"));
+
+				pAC->Pnmi.SirqUpdatedFlag --;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+		}
+		*pLen = Offset;
+		pAC->Pnmi.SirqUpdatedFlag --;
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	/*
+	 * From here SET or PRESET action. Check if the passed
+	 * buffer length is plausible.
+	 */
+	switch (Id) {
+
+	case OID_SKGE_LINK_MODE:
+	case OID_SKGE_FLOWCTRL_MODE:
+	case OID_SKGE_PHY_OPERATION_MODE:
+	case OID_SKGE_SPEED_MODE:
+		if (*pLen < Limit - LogPortIndex) {
+
+			*pLen = Limit - LogPortIndex;
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		if (*pLen != Limit - LogPortIndex) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE);
+		}
+		break;
+
+	case OID_SKGE_MTU:
+		if (*pLen < sizeof(SK_U32)) {
+
+			*pLen = sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		if (*pLen != sizeof(SK_U32)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE);
+		}
+		break;
+
+    default:
+		*pLen = 0;
+		return (SK_PNMI_ERR_READ_ONLY);
+	}
+
+	/*
+	 * Perform preset or set
+	 */
+	Offset = 0;
+	for (; LogPortIndex < Limit; LogPortIndex ++) {
+
+		switch (Id) {
+
+		case OID_SKGE_LINK_MODE:
+			/* Check the value range */
+			Val8 = *(pBuf + Offset);
+			if (Val8 == 0) {
+
+				Offset += sizeof(char);
+				break;
+			}
+			if (Val8 < SK_LMODE_HALF ||
+				(LogPortIndex != 0 && Val8 > SK_LMODE_AUTOSENSE) ||
+				(LogPortIndex == 0 && Val8 > SK_LMODE_INDETERMINATED)) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			if (LogPortIndex == 0) {
+
+				/*
+				 * The virtual port consists of all currently
+				 * active ports. Find them and send an event
+				 * with the new link mode to SIRQ.
+				 */
+				for (PhysPortIndex = 0;
+					PhysPortIndex < PhysPortMax;
+					PhysPortIndex ++) {
+
+					if (!pAC->Pnmi.Port[PhysPortIndex].
+						ActiveFlag) {
+
+						continue;
+					}
+
+					EventParam.Para32[0] = PhysPortIndex;
+					EventParam.Para32[1] = (SK_U32)Val8;
+					if (SkGeSirqEvent(pAC, IoC,
+						SK_HWEV_SET_LMODE,
+						EventParam) > 0) {
+
+						SK_ERR_LOG(pAC, SK_ERRCL_SW,
+							SK_PNMI_ERR043,
+							SK_PNMI_ERR043MSG);
+
+						*pLen = 0;
+						return (SK_PNMI_ERR_GENERAL);
+					}
+				}
+			}
+			else {
+				/*
+				 * Send an event with the new link mode to
+				 * the SIRQ module.
+				 */
+				EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+					pAC, LogPortIndex);
+				EventParam.Para32[1] = (SK_U32)Val8;
+				if (SkGeSirqEvent(pAC, IoC, SK_HWEV_SET_LMODE,
+					EventParam) > 0) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR043,
+						SK_PNMI_ERR043MSG);
+
+					*pLen = 0;
+					return (SK_PNMI_ERR_GENERAL);
+				}
+			}
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_FLOWCTRL_MODE:
+			/* Check the value range */
+			Val8 = *(pBuf + Offset);
+			if (Val8 == 0) {
+
+				Offset += sizeof(char);
+				break;
+			}
+			if (Val8 < SK_FLOW_MODE_NONE ||
+				(LogPortIndex != 0 && Val8 > SK_FLOW_MODE_SYM_OR_REM) ||
+				(LogPortIndex == 0 && Val8 > SK_FLOW_MODE_INDETERMINATED)) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			if (LogPortIndex == 0) {
+
+				/*
+				 * The virtual port consists of all currently
+				 * active ports. Find them and send an event
+				 * with the new flow control mode to SIRQ.
+				 */
+				for (PhysPortIndex = 0;
+					PhysPortIndex < PhysPortMax;
+					PhysPortIndex ++) {
+
+					if (!pAC->Pnmi.Port[PhysPortIndex].
+						ActiveFlag) {
+
+						continue;
+					}
+
+					EventParam.Para32[0] = PhysPortIndex;
+					EventParam.Para32[1] = (SK_U32)Val8;
+					if (SkGeSirqEvent(pAC, IoC,
+						SK_HWEV_SET_FLOWMODE,
+						EventParam) > 0) {
+
+						SK_ERR_LOG(pAC, SK_ERRCL_SW,
+							SK_PNMI_ERR044,
+							SK_PNMI_ERR044MSG);
+
+						*pLen = 0;
+						return (SK_PNMI_ERR_GENERAL);
+					}
+				}
+			}
+			else {
+				/*
+				 * Send an event with the new flow control
+				 * mode to the SIRQ module.
+				 */
+				EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+					pAC, LogPortIndex);
+				EventParam.Para32[1] = (SK_U32)Val8;
+				if (SkGeSirqEvent(pAC, IoC,
+					SK_HWEV_SET_FLOWMODE, EventParam)
+					> 0) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR044,
+						SK_PNMI_ERR044MSG);
+
+					*pLen = 0;
+					return (SK_PNMI_ERR_GENERAL);
+				}
+			}
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_PHY_OPERATION_MODE :
+			/* Check the value range */
+			Val8 = *(pBuf + Offset);
+			if (Val8 == 0) {
+				/* mode of this port remains unchanged */
+				Offset += sizeof(char);
+				break;
+			}
+			if (Val8 < SK_MS_MODE_AUTO ||
+				(LogPortIndex != 0 && Val8 > SK_MS_MODE_SLAVE) ||
+				(LogPortIndex == 0 && Val8 > SK_MS_MODE_INDETERMINATED)) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			if (LogPortIndex == 0) {
+
+				/*
+				 * The virtual port consists of all currently
+				 * active ports. Find them and send an event
+				 * with new master/slave (role) mode to SIRQ.
+				 */
+				for (PhysPortIndex = 0;
+					PhysPortIndex < PhysPortMax;
+					PhysPortIndex ++) {
+
+					if (!pAC->Pnmi.Port[PhysPortIndex].
+						ActiveFlag) {
+
+						continue;
+					}
+
+					EventParam.Para32[0] = PhysPortIndex;
+					EventParam.Para32[1] = (SK_U32)Val8;
+					if (SkGeSirqEvent(pAC, IoC,
+						SK_HWEV_SET_ROLE,
+						EventParam) > 0) {
+
+						SK_ERR_LOG(pAC, SK_ERRCL_SW,
+							SK_PNMI_ERR042,
+							SK_PNMI_ERR042MSG);
+
+						*pLen = 0;
+						return (SK_PNMI_ERR_GENERAL);
+					}
+				}
+			}
+			else {
+				/*
+				 * Send an event with the new master/slave
+				 * (role) mode to the SIRQ module.
+				 */
+				EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+					pAC, LogPortIndex);
+				EventParam.Para32[1] = (SK_U32)Val8;
+				if (SkGeSirqEvent(pAC, IoC,
+					SK_HWEV_SET_ROLE, EventParam) > 0) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR042,
+						SK_PNMI_ERR042MSG);
+
+					*pLen = 0;
+					return (SK_PNMI_ERR_GENERAL);
+				}
+			}
+
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_SPEED_MODE:
+			/* Check the value range */
+			Val8 = *(pBuf + Offset);
+			if (Val8 == 0) {
+
+				Offset += sizeof(char);
+				break;
+			}
+			if (Val8 < (SK_LSPEED_AUTO) ||
+				(LogPortIndex != 0 && Val8 > (SK_LSPEED_1000MBPS)) ||
+				(LogPortIndex == 0 && Val8 > (SK_LSPEED_INDETERMINATED))) {
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+
+				return (SK_PNMI_ERR_OK);
+			}
+
+			if (LogPortIndex == 0) {
+
+				/*
+				 * The virtual port consists of all currently
+				 * active ports. Find them and send an event
+				 * with the new flow control mode to SIRQ.
+				 */
+				for (PhysPortIndex = 0;
+					PhysPortIndex < PhysPortMax;
+					PhysPortIndex ++) {
+
+					if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+						continue;
+					}
+
+					EventParam.Para32[0] = PhysPortIndex;
+					EventParam.Para32[1] = (SK_U32)Val8;
+					if (SkGeSirqEvent(pAC, IoC,
+						SK_HWEV_SET_SPEED,
+						EventParam) > 0) {
+
+						SK_ERR_LOG(pAC, SK_ERRCL_SW,
+							SK_PNMI_ERR045,
+							SK_PNMI_ERR045MSG);
+
+						*pLen = 0;
+						return (SK_PNMI_ERR_GENERAL);
+					}
+				}
+			}
+			else {
+				/*
+				 * Send an event with the new flow control
+				 * mode to the SIRQ module.
+				 */
+				EventParam.Para32[0] = SK_PNMI_PORT_LOG2PHYS(
+					pAC, LogPortIndex);
+				EventParam.Para32[1] = (SK_U32)Val8;
+				if (SkGeSirqEvent(pAC, IoC,
+					SK_HWEV_SET_SPEED,
+					EventParam) > 0) {
+
+					SK_ERR_LOG(pAC, SK_ERRCL_SW,
+						SK_PNMI_ERR045,
+						SK_PNMI_ERR045MSG);
+
+					*pLen = 0;
+					return (SK_PNMI_ERR_GENERAL);
+				}
+			}
+			Offset += sizeof(char);
+			break;
+
+		case OID_SKGE_MTU :
+			/* Check the value range */
+			Val32 = *(SK_U32*)(pBuf + Offset);
+			if (Val32 == 0) {
+				/* mtu of this port remains unchanged */
+				Offset += sizeof(SK_U32);
+				break;
+			}
+			if (SK_DRIVER_PRESET_MTU(pAC, IoC, NetIndex, Val32) != 0) {
+				*pLen = 0;
+				return (SK_PNMI_ERR_BAD_VALUE);
+			}
+
+			/* The preset ends here */
+			if (Action == SK_PNMI_PRESET) {
+				return (SK_PNMI_ERR_OK);
+			}
+
+			if (SK_DRIVER_SET_MTU(pAC, IoC, NetIndex, Val32) != 0) {
+				return (SK_PNMI_ERR_GENERAL);
+			}
+
+			Offset += sizeof(SK_U32);
+			break;
+		
+		default:
+            SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR,
+                ("MacPrivateConf: Unknown OID should be handled before set"));
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * Monitor - OID handler function for RLMT_MONITOR_XXX
+ *
+ * Description:
+ *	Because RLMT currently does not support the monitoring of
+ *	remote adapter cards, we return always an empty table.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_BAD_VALUE    The passed value is not in the valid
+ *	                         value range.
+ *	SK_PNMI_ERR_READ_ONLY    The OID is read-only and cannot be set.
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+PNMI_STATIC int Monitor(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* GET/PRESET/SET action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,	/* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	unsigned int	Index;
+	unsigned int	Limit;
+	unsigned int	Offset;
+	unsigned int	Entries;
+
+	
+	/*
+	 * Calculate instance if wished.
+	 */
+	/* XXX Not yet implemented. Return always an empty table. */
+	Entries = 0;
+
+	if ((Instance != (SK_U32)(-1))) {
+
+		if ((Instance < 1) || (Instance > Entries)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+
+		Index = (unsigned int)Instance - 1;
+		Limit = (unsigned int)Instance;
+	}
+	else {
+		Index = 0;
+		Limit = Entries;
+	}
+
+	/*
+	 * Get/Set value
+	*/
+	if (Action == SK_PNMI_GET) {
+
+		for (Offset=0; Index < Limit; Index ++) {
+
+			switch (Id) {
+
+			case OID_SKGE_RLMT_MONITOR_INDEX:
+			case OID_SKGE_RLMT_MONITOR_ADDR:
+			case OID_SKGE_RLMT_MONITOR_ERRS:
+			case OID_SKGE_RLMT_MONITOR_TIMESTAMP:
+			case OID_SKGE_RLMT_MONITOR_ADMIN:
+				break;
+
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR046,
+					SK_PNMI_ERR046MSG);
+
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+		}
+		*pLen = Offset;
+	}
+	else {
+		/* Only MONITOR_ADMIN can be set */
+		if (Id != OID_SKGE_RLMT_MONITOR_ADMIN) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_READ_ONLY);
+		}
+
+		/* Check if the length is plausible */
+		if (*pLen < (Limit - Index)) {
+
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		/* Okay, we have a wide value range */
+		if (*pLen != (Limit - Index)) {
+
+			*pLen = 0;
+			return (SK_PNMI_ERR_BAD_VALUE);
+		}
+/*
+		for (Offset=0; Index < Limit; Index ++) {
+		}
+*/
+/*
+ * XXX Not yet implemented. Return always BAD_VALUE, because the table
+ * is empty.
+ */
+		*pLen = 0;
+		return (SK_PNMI_ERR_BAD_VALUE);
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * VirtualConf - Calculates the values of configuration OIDs for virtual port
+ *
+ * Description:
+ *	We handle here the get of the configuration group OIDs, which are
+ *	a little bit complicated. The virtual port consists of all currently
+ *	active physical ports. If multiple ports are active and configured
+ *	differently we get in some trouble to return a single value. So we
+ *	get the value of the first active port and compare it with that of
+ *	the other active ports. If they are not the same, we return a value
+ *	that indicates that the state is indeterminated.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void VirtualConf(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf)		/* Buffer used for the management data transfer */
+{
+	unsigned int	PhysPortMax;
+	unsigned int	PhysPortIndex;
+	SK_U8		Val8;
+	SK_U32		Val32;
+	SK_BOOL		PortActiveFlag;
+	SK_GEPORT	*pPrt;
+
+	*pBuf = 0;
+	PortActiveFlag = SK_FALSE;
+	PhysPortMax = pAC->GIni.GIMacsFound;
+	
+	for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
+		PhysPortIndex ++) {
+
+		pPrt = &pAC->GIni.GP[PhysPortIndex];
+
+		/* Check if the physical port is active */
+		if (!pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+			continue;
+		}
+
+		PortActiveFlag = SK_TRUE;
+
+		switch (Id) {
+
+		case OID_SKGE_PHY_TYPE:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+				Val32 = pPrt->PhyType;
+				SK_PNMI_STORE_U32(pBuf, Val32);
+				continue;
+			}
+
+		case OID_SKGE_LINK_CAP:
+
+			/*
+			 * Different capabilities should not happen, but
+			 * in the case of the cases OR them all together.
+			 * From a curious point of view the virtual port
+			 * is capable of all found capabilities.
+			 */
+			*pBuf |= pPrt->PLinkCap;
+			break;
+
+		case OID_SKGE_LINK_MODE:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pPrt->PLinkModeConf;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different link
+			 * mode than the first one we return a value that
+			 * indicates that the link mode is indeterminated.
+			 */
+			if (*pBuf != pPrt->PLinkModeConf) {
+
+				*pBuf = SK_LMODE_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_LINK_MODE_STATUS:
+			/* Get the link mode of the physical port */
+			Val8 = CalculateLinkModeStatus(pAC, IoC, PhysPortIndex);
+
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = Val8;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different link
+			 * mode status than the first one we return a value
+			 * that indicates that the link mode status is
+			 * indeterminated.
+			 */
+			if (*pBuf != Val8) {
+
+				*pBuf = SK_LMODE_STAT_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_LINK_STATUS:
+			/* Get the link status of the physical port */
+			Val8 = CalculateLinkStatus(pAC, IoC, PhysPortIndex);
+
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = Val8;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different link
+			 * status than the first one, we return a value
+			 * that indicates that the link status is
+			 * indeterminated.
+			 */
+			if (*pBuf != Val8) {
+
+				*pBuf = SK_PNMI_RLMT_LSTAT_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_FLOWCTRL_CAP:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pPrt->PFlowCtrlCap;
+				continue;
+			}
+
+			/*
+			 * From a curious point of view the virtual port
+			 * is capable of all found capabilities.
+			 */
+			*pBuf |= pPrt->PFlowCtrlCap;
+			break;
+
+		case OID_SKGE_FLOWCTRL_MODE:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pPrt->PFlowCtrlMode;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different flow
+			 * control mode than the first one, we return a value
+			 * that indicates that the mode is indeterminated.
+			 */
+			if (*pBuf != pPrt->PFlowCtrlMode) {
+
+				*pBuf = SK_FLOW_MODE_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_FLOWCTRL_STATUS:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pPrt->PFlowCtrlStatus;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different flow
+			 * control status than the first one, we return a
+			 * value that indicates that the status is
+			 * indeterminated.
+			 */
+			if (*pBuf != pPrt->PFlowCtrlStatus) {
+
+				*pBuf = SK_FLOW_STAT_INDETERMINATED;
+			}
+			break;
+		
+		case OID_SKGE_PHY_OPERATION_CAP:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pPrt->PMSCap;
+				continue;
+			}
+
+			/*
+			 * From a curious point of view the virtual port
+			 * is capable of all found capabilities.
+			 */
+			*pBuf |= pPrt->PMSCap;
+			break;
+
+		case OID_SKGE_PHY_OPERATION_MODE:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pPrt->PMSMode;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different master/
+			 * slave mode than the first one, we return a value
+			 * that indicates that the mode is indeterminated.
+			 */
+			if (*pBuf != pPrt->PMSMode) {
+
+				*pBuf = SK_MS_MODE_INDETERMINATED;
+			}
+			break;
+
+		case OID_SKGE_PHY_OPERATION_STATUS:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pPrt->PMSStatus;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different master/
+			 * slave status than the first one, we return a
+			 * value that indicates that the status is
+			 * indeterminated.
+			 */
+			if (*pBuf != pPrt->PMSStatus) {
+
+				*pBuf = SK_MS_STAT_INDETERMINATED;
+			}
+			break;
+		
+		case OID_SKGE_SPEED_MODE:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pPrt->PLinkSpeed;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different flow
+			 * control mode than the first one, we return a value
+			 * that indicates that the mode is indeterminated.
+			 */
+			if (*pBuf != pPrt->PLinkSpeed) {
+
+				*pBuf = SK_LSPEED_INDETERMINATED;
+			}
+			break;
+		
+		case OID_SKGE_SPEED_STATUS:
+			/* Check if it is the first active port */
+			if (*pBuf == 0) {
+
+				*pBuf = pPrt->PLinkSpeedUsed;
+				continue;
+			}
+
+			/*
+			 * If we find an active port with a different flow
+			 * control status than the first one, we return a
+			 * value that indicates that the status is
+			 * indeterminated.
+			 */
+			if (*pBuf != pPrt->PLinkSpeedUsed) {
+
+				*pBuf = SK_LSPEED_STAT_INDETERMINATED;
+			}
+			break;
+		}
+	}
+
+	/*
+	 * If no port is active return an indeterminated answer
+	 */
+	if (!PortActiveFlag) {
+
+		switch (Id) {
+
+		case OID_SKGE_LINK_CAP:
+			*pBuf = SK_LMODE_CAP_INDETERMINATED;
+			break;
+
+		case OID_SKGE_LINK_MODE:
+			*pBuf = SK_LMODE_INDETERMINATED;
+			break;
+
+		case OID_SKGE_LINK_MODE_STATUS:
+			*pBuf = SK_LMODE_STAT_INDETERMINATED;
+			break;
+
+		case OID_SKGE_LINK_STATUS:
+			*pBuf = SK_PNMI_RLMT_LSTAT_INDETERMINATED;
+			break;
+
+		case OID_SKGE_FLOWCTRL_CAP:
+		case OID_SKGE_FLOWCTRL_MODE:
+			*pBuf = SK_FLOW_MODE_INDETERMINATED;
+			break;
+
+		case OID_SKGE_FLOWCTRL_STATUS:
+			*pBuf = SK_FLOW_STAT_INDETERMINATED;
+			break;
+			
+		case OID_SKGE_PHY_OPERATION_CAP:
+			*pBuf = SK_MS_CAP_INDETERMINATED;
+			break;
+
+		case OID_SKGE_PHY_OPERATION_MODE:
+			*pBuf = SK_MS_MODE_INDETERMINATED;
+			break;
+
+		case OID_SKGE_PHY_OPERATION_STATUS:
+			*pBuf = SK_MS_STAT_INDETERMINATED;
+			break;
+		case OID_SKGE_SPEED_CAP:
+			*pBuf = SK_LSPEED_CAP_INDETERMINATED;
+			break;
+
+		case OID_SKGE_SPEED_MODE:
+			*pBuf = SK_LSPEED_INDETERMINATED;
+			break;
+
+		case OID_SKGE_SPEED_STATUS:
+			*pBuf = SK_LSPEED_STAT_INDETERMINATED;
+			break;
+		}
+	}
+}
+
+/*****************************************************************************
+ *
+ * CalculateLinkStatus - Determins the link status of a physical port
+ *
+ * Description:
+ *	Determins the link status the following way:
+ *	  LSTAT_PHY_DOWN:  Link is down
+ *	  LSTAT_AUTONEG:   Auto-negotiation failed
+ *	  LSTAT_LOG_DOWN:  Link is up but RLMT did not yet put the port
+ *	                   logically up.
+ *	  LSTAT_LOG_UP:    RLMT marked the port as up
+ *
+ * Returns:
+ *	Link status of physical port
+ */
+PNMI_STATIC SK_U8 CalculateLinkStatus(
+SK_AC *pAC,			/* Pointer to adapter context */
+SK_IOC IoC,			/* IO context handle */
+unsigned int PhysPortIndex)	/* Physical port index */
+{
+	SK_U8	Result;
+
+	if (!pAC->GIni.GP[PhysPortIndex].PHWLinkUp) {
+
+		Result = SK_PNMI_RLMT_LSTAT_PHY_DOWN;
+	}
+	else if (pAC->GIni.GP[PhysPortIndex].PAutoNegFail > 0) {
+
+		Result = SK_PNMI_RLMT_LSTAT_AUTONEG;
+				}
+	else if (!pAC->Rlmt.Port[PhysPortIndex].PortDown) {
+
+		Result = SK_PNMI_RLMT_LSTAT_LOG_UP;
+	}
+	else {
+		Result = SK_PNMI_RLMT_LSTAT_LOG_DOWN;
+	}
+
+	return (Result);
+}
+
+/*****************************************************************************
+ *
+ * CalculateLinkModeStatus - Determins the link mode status of a phys. port
+ *
+ * Description:
+ *	The COMMON module only tells us if the mode is half or full duplex.
+ *	But in the decade of auto sensing it is useful for the user to
+ *	know if the mode was negotiated or forced. Therefore we have a
+ *	look to the mode, which was last used by the negotiation process.
+ *
+ * Returns:
+ *	The link mode status
+ */
+PNMI_STATIC SK_U8 CalculateLinkModeStatus(
+SK_AC *pAC,			/* Pointer to adapter context */
+SK_IOC IoC,			/* IO context handle */
+unsigned int PhysPortIndex)	/* Physical port index */
+{
+	SK_U8	Result;
+
+	/* Get the current mode, which can be full or half duplex */
+	Result = pAC->GIni.GP[PhysPortIndex].PLinkModeStatus;
+
+	/* Check if no valid mode could be found (link is down) */
+	if (Result < SK_LMODE_STAT_HALF) {
+
+		Result = SK_LMODE_STAT_UNKNOWN;
+	}
+	else if (pAC->GIni.GP[PhysPortIndex].PLinkMode >= SK_LMODE_AUTOHALF) {
+
+		/*
+		 * Auto-negotiation was used to bring up the link. Change
+		 * the already found duplex status that it indicates
+		 * auto-negotiation was involved.
+		 */
+		if (Result == SK_LMODE_STAT_HALF) {
+
+			Result = SK_LMODE_STAT_AUTOHALF;
+		}
+		else if (Result == SK_LMODE_STAT_FULL) {
+
+			Result = SK_LMODE_STAT_AUTOFULL;
+		}
+	}
+
+	return (Result);
+}
+
+/*****************************************************************************
+ *
+ * GetVpdKeyArr - Obtain an array of VPD keys
+ *
+ * Description:
+ *	Read the VPD keys and build an array of VPD keys, which are
+ *	easy to access.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK	     Task successfully performed.
+ *	SK_PNMI_ERR_GENERAL  Something went wrong.
+ */
+PNMI_STATIC int GetVpdKeyArr(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+char *pKeyArr,		/* Ptr KeyArray */
+unsigned int KeyArrLen,	/* Length of array in bytes */
+unsigned int *pKeyNo)	/* Number of keys */
+{
+	unsigned int		BufKeysLen = SK_PNMI_VPD_BUFSIZE;
+	char			BufKeys[SK_PNMI_VPD_BUFSIZE];
+	unsigned int		StartOffset;
+	unsigned int		Offset;
+	int			Index;
+	int			Ret;
+
+
+	SK_MEMSET(pKeyArr, 0, KeyArrLen);
+
+	/*
+	 * Get VPD key list
+	 */
+	Ret = VpdKeys(pAC, IoC, (char *)&BufKeys, (int *)&BufKeysLen,
+		(int *)pKeyNo);
+	if (Ret > 0) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR014,
+			SK_PNMI_ERR014MSG);
+
+		return (SK_PNMI_ERR_GENERAL);
+	}
+	/* If no keys are available return now */
+	if (*pKeyNo == 0 || BufKeysLen == 0) {
+
+		return (SK_PNMI_ERR_OK);
+	}
+	/*
+	 * If the key list is too long for us trunc it and give a
+	 * errorlog notification. This case should not happen because
+	 * the maximum number of keys is limited due to RAM limitations
+	 */
+	if (*pKeyNo > SK_PNMI_VPD_ENTRIES) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR015,
+			SK_PNMI_ERR015MSG);
+
+		*pKeyNo = SK_PNMI_VPD_ENTRIES;
+	}
+
+	/*
+	 * Now build an array of fixed string length size and copy
+	 * the keys together.
+	 */
+	for (Index = 0, StartOffset = 0, Offset = 0; Offset < BufKeysLen;
+		Offset ++) {
+
+		if (BufKeys[Offset] != 0) {
+
+			continue;
+		}
+
+		if (Offset - StartOffset > SK_PNMI_VPD_KEY_SIZE) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR016,
+				SK_PNMI_ERR016MSG);
+			return (SK_PNMI_ERR_GENERAL);
+		}
+
+		SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_KEY_SIZE,
+			&BufKeys[StartOffset], SK_PNMI_VPD_KEY_SIZE);
+
+		Index ++;
+		StartOffset = Offset + 1;
+	}
+
+	/* Last key not zero terminated? Get it anyway */
+	if (StartOffset < Offset) {
+
+		SK_STRNCPY(pKeyArr + Index * SK_PNMI_VPD_KEY_SIZE,
+			&BufKeys[StartOffset], SK_PNMI_VPD_KEY_SIZE);
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * SirqUpdate - Let the SIRQ update its internal values
+ *
+ * Description:
+ *	Just to be sure that the SIRQ module holds its internal data
+ *	structures up to date, we send an update event before we make
+ *	any access.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK	     Task successfully performed.
+ *	SK_PNMI_ERR_GENERAL  Something went wrong.
+ */
+PNMI_STATIC int SirqUpdate(
+SK_AC *pAC,	/* Pointer to adapter context */
+SK_IOC IoC)	/* IO context handle */
+{
+	SK_EVPARA	EventParam;
+
+
+	/* Was the module already updated during the current PNMI call? */
+	if (pAC->Pnmi.SirqUpdatedFlag > 0) {
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	/* Send an synchronuous update event to the module */
+	SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+	if (SkGeSirqEvent(pAC, IoC, SK_HWEV_UPDATE_STAT, EventParam) > 0) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR047,
+			SK_PNMI_ERR047MSG);
+
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * RlmtUpdate - Let the RLMT update its internal values
+ *
+ * Description:
+ *	Just to be sure that the RLMT module holds its internal data
+ *	structures up to date, we send an update event before we make
+ *	any access.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK	     Task successfully performed.
+ *	SK_PNMI_ERR_GENERAL  Something went wrong.
+ */
+PNMI_STATIC int RlmtUpdate(
+SK_AC *pAC,	/* Pointer to adapter context */
+SK_IOC IoC,	/* IO context handle */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	SK_EVPARA	EventParam;
+
+
+	/* Was the module already updated during the current PNMI call? */
+	if (pAC->Pnmi.RlmtUpdatedFlag > 0) {
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	/* Send an synchronuous update event to the module */
+	SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+	EventParam.Para32[0] = NetIndex;
+	EventParam.Para32[1] = (SK_U32)-1;
+	if (SkRlmtEvent(pAC, IoC, SK_RLMT_STATS_UPDATE, EventParam) > 0) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR048,
+			SK_PNMI_ERR048MSG);
+
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * MacUpdate - Force the XMAC to output the current statistic
+ *
+ * Description:
+ *	The XMAC holds its statistic internally. To obtain the current
+ *	values we must send a command so that the statistic data will
+ *	be written to a predefined memory area on the adapter.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK	     Task successfully performed.
+ *	SK_PNMI_ERR_GENERAL  Something went wrong.
+ */
+PNMI_STATIC int MacUpdate(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+unsigned int FirstMac,	/* Index of the first Mac to be updated */
+unsigned int LastMac)	/* Index of the last Mac to be updated */
+{
+	unsigned int	MacIndex;
+
+	/*
+	 * Were the statistics already updated during the
+	 * current PNMI call?
+	 */
+	if (pAC->Pnmi.MacUpdatedFlag > 0) {
+
+		return (SK_PNMI_ERR_OK);
+	}
+
+	/* Send an update command to all MACs specified */
+	for (MacIndex = FirstMac; MacIndex <= LastMac; MacIndex ++) {
+
+		/*
+		 * 2002-09-13 pweber:	Freeze the current SW counters.
+		 *                      (That should be done as close as
+		 *                      possible to the update of the
+		 *                      HW counters)
+		 */
+		if (pAC->GIni.GIMacType == SK_MAC_XMAC) {
+			pAC->Pnmi.BufPort[MacIndex] = pAC->Pnmi.Port[MacIndex];
+		}
+			
+		/* 2002-09-13 pweber:  Update the HW counter  */
+		if (pAC->GIni.GIFunc.pFnMacUpdateStats(pAC, IoC, MacIndex) != 0) {
+
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	}
+
+	return (SK_PNMI_ERR_OK);
+}
+
+/*****************************************************************************
+ *
+ * GetStatVal - Retrieve an XMAC statistic counter
+ *
+ * Description:
+ *	Retrieves the statistic counter of a virtual or physical port. The
+ *	virtual port is identified by the index 0. It consists of all
+ *	currently active ports. To obtain the counter value for this port
+ *	we must add the statistic counter of all active ports. To grant
+ *	continuous counter values for the virtual port even when port
+ *	switches occur we must additionally add a delta value, which was
+ *	calculated during a SK_PNMI_EVT_RLMT_ACTIVE_UP event.
+ *
+ * Returns:
+ *	Requested statistic value
+ */
+PNMI_STATIC SK_U64 GetStatVal(
+SK_AC *pAC,					/* Pointer to adapter context */
+SK_IOC IoC,					/* IO context handle */
+unsigned int LogPortIndex,	/* Index of the logical Port to be processed */
+unsigned int StatIndex,		/* Index to statistic value */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	unsigned int	PhysPortIndex;
+	unsigned int	PhysPortMax;
+	SK_U64			Val = 0;
+
+
+	if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {	/* Dual net mode */
+
+		PhysPortIndex = NetIndex;
+		
+		Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
+	}
+	else {	/* Single Net mode */
+
+		if (LogPortIndex == 0) {
+
+			PhysPortMax = pAC->GIni.GIMacsFound;
+
+			/* Add counter of all active ports */
+			for (PhysPortIndex = 0; PhysPortIndex < PhysPortMax;
+				PhysPortIndex ++) {
+
+				if (pAC->Pnmi.Port[PhysPortIndex].ActiveFlag) {
+
+					Val += GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
+				}
+			}
+
+			/* Correct value because of port switches */
+			Val += pAC->Pnmi.VirtualCounterOffset[StatIndex];
+		}
+		else {
+			/* Get counter value of physical port */
+			PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex);
+			
+			Val = GetPhysStatVal(pAC, IoC, PhysPortIndex, StatIndex);
+		}
+	}
+	return (Val);
+}
+
+/*****************************************************************************
+ *
+ * GetPhysStatVal - Get counter value for physical port
+ *
+ * Description:
+ *	Builds a 64bit counter value. Except for the octet counters
+ *	the lower 32bit are counted in hardware and the upper 32bit
+ *	in software by monitoring counter overflow interrupts in the
+ *	event handler. To grant continous counter values during XMAC
+ *	resets (caused by a workaround) we must add a delta value.
+ *	The delta was calculated in the event handler when a
+ *	SK_PNMI_EVT_XMAC_RESET was received.
+ *
+ * Returns:
+ *	Counter value
+ */
+PNMI_STATIC SK_U64 GetPhysStatVal(
+SK_AC *pAC,					/* Pointer to adapter context */
+SK_IOC IoC,					/* IO context handle */
+unsigned int PhysPortIndex,	/* Index of the logical Port to be processed */
+unsigned int StatIndex)		/* Index to statistic value */
+{
+	SK_U64	Val = 0;
+	SK_U32	LowVal = 0;
+	SK_U32	HighVal = 0;
+	SK_U16	Word;
+	int		MacType;
+	unsigned int HelpIndex;
+	SK_GEPORT	*pPrt;
+	
+	SK_PNMI_PORT	*pPnmiPrt;
+	SK_GEMACFUNC	*pFnMac;
+	
+	pPrt = &pAC->GIni.GP[PhysPortIndex];
+	
+	MacType = pAC->GIni.GIMacType;
+	
+	/* 2002-09-17 pweber: For XMAC, use the frozen SW counters (BufPort) */
+	if (MacType == SK_MAC_XMAC) {
+		pPnmiPrt = &pAC->Pnmi.BufPort[PhysPortIndex];
+	}
+	else {
+		pPnmiPrt = &pAC->Pnmi.Port[PhysPortIndex];
+	}
+	
+	pFnMac   = &pAC->GIni.GIFunc;
+
+	switch (StatIndex) {
+	case SK_PNMI_HTX:
+		if (MacType == SK_MAC_GMAC) {
+			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+							StatAddr[SK_PNMI_HTX_BROADCAST][MacType].Reg,
+							&LowVal);
+			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+							StatAddr[SK_PNMI_HTX_MULTICAST][MacType].Reg,
+							&HighVal);
+			LowVal += HighVal;
+			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+							StatAddr[SK_PNMI_HTX_UNICAST][MacType].Reg,
+							&HighVal);
+			LowVal += HighVal;
+		}
+		else {
+			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+										  StatAddr[StatIndex][MacType].Reg,
+										  &LowVal);
+		}
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+	
+	case SK_PNMI_HRX:
+		if (MacType == SK_MAC_GMAC) {
+			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+							StatAddr[SK_PNMI_HRX_BROADCAST][MacType].Reg,
+							&LowVal);
+			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+							StatAddr[SK_PNMI_HRX_MULTICAST][MacType].Reg,
+							&HighVal);
+			LowVal += HighVal;
+			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+							StatAddr[SK_PNMI_HRX_UNICAST][MacType].Reg,
+							&HighVal);
+			LowVal += HighVal;
+		}
+		else {
+			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+										  StatAddr[StatIndex][MacType].Reg,
+										  &LowVal);
+		}
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+
+	case SK_PNMI_HTX_OCTET:
+	case SK_PNMI_HRX_OCTET:
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &HighVal);
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex + 1][MacType].Reg,
+									  &LowVal);
+		break;
+
+	case SK_PNMI_HTX_BURST:
+	case SK_PNMI_HTX_EXCESS_DEF:
+	case SK_PNMI_HTX_CARRIER:
+		/* Not supported by GMAC */
+		if (MacType == SK_MAC_GMAC) {
+			return (Val);
+		}
+
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+
+	case SK_PNMI_HTX_MACC:
+		/* GMAC only supports PAUSE MAC control frames */
+		if (MacType == SK_MAC_GMAC) {
+			HelpIndex = SK_PNMI_HTX_PMACC;
+		}
+		else {
+			HelpIndex = StatIndex;
+		}
+		
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+								StatAddr[HelpIndex][MacType].Reg,
+								&LowVal);
+
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+
+	case SK_PNMI_HTX_COL:
+	case SK_PNMI_HRX_UNDERSIZE:
+		/* Not supported by XMAC */
+		if (MacType == SK_MAC_XMAC) {
+			return (Val);
+		}
+
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+
+	case SK_PNMI_HTX_DEFFERAL:
+		/* Not supported by GMAC */
+		if (MacType == SK_MAC_GMAC) {
+			return (Val);
+		}
+		
+		/*
+		 * XMAC counts frames with deferred transmission
+		 * even in full-duplex mode.
+		 *
+		 * In full-duplex mode the counter remains constant!
+		 */
+		if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL) ||
+			(pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL)) {
+
+			LowVal = 0;
+			HighVal = 0;
+		}
+		else {
+			/* Otherwise get contents of hardware register */
+			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+										  StatAddr[StatIndex][MacType].Reg,
+										  &LowVal);
+			HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		}
+		break;
+
+	case SK_PNMI_HRX_BADOCTET:
+		/* Not supported by XMAC */
+		if (MacType == SK_MAC_XMAC) {
+			return (Val);
+		}
+
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &HighVal);
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex + 1][MacType].Reg,
+                                      &LowVal);
+		break;
+
+	case SK_PNMI_HTX_OCTETLOW:
+	case SK_PNMI_HRX_OCTETLOW:
+	case SK_PNMI_HRX_BADOCTETLOW:
+		return (Val);
+
+	case SK_PNMI_HRX_LONGFRAMES:
+		/* For XMAC the SW counter is managed by PNMI */
+		if (MacType == SK_MAC_XMAC) {
+			return (pPnmiPrt->StatRxLongFrameCts);
+		}
+		
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+		
+	case SK_PNMI_HRX_TOO_LONG:
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+								StatAddr[StatIndex][MacType].Reg,
+								&LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		
+		Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);
+
+		if (MacType == SK_MAC_GMAC) {
+			/* For GMAC the SW counter is additionally managed by PNMI */
+			Val += pPnmiPrt->StatRxFrameTooLongCts;
+		}
+		else {
+			/*
+			 * Frames longer than IEEE 802.3 frame max size are counted
+			 * by XMAC in frame_too_long counter even reception of long
+			 * frames was enabled and the frame was correct.
+			 * So correct the value by subtracting RxLongFrame counter.
+			 */
+			Val -= pPnmiPrt->StatRxLongFrameCts;
+		}
+
+		LowVal = (SK_U32)Val;
+		HighVal = (SK_U32)(Val >> 32);
+		break;
+		
+	case SK_PNMI_HRX_SHORTS:
+		/* Not supported by GMAC */
+		if (MacType == SK_MAC_GMAC) {
+			/* GM_RXE_FRAG?? */
+			return (Val);
+		}
+		
+		/*
+		 * XMAC counts short frame errors even if link down (#10620)
+		 *
+		 * If link-down the counter remains constant
+		 */
+		if (pPrt->PLinkModeStatus != SK_LMODE_STAT_UNKNOWN) {
+
+			/* Otherwise get incremental difference */
+			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+										  StatAddr[StatIndex][MacType].Reg,
+										  &LowVal);
+			HighVal = pPnmiPrt->CounterHigh[StatIndex];
+
+			Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);
+			Val -= pPnmiPrt->RxShortZeroMark;
+
+			LowVal = (SK_U32)Val;
+			HighVal = (SK_U32)(Val >> 32);
+		}
+		break;
+
+	case SK_PNMI_HRX_MACC:
+	case SK_PNMI_HRX_MACC_UNKWN:
+	case SK_PNMI_HRX_BURST:
+	case SK_PNMI_HRX_MISSED:
+	case SK_PNMI_HRX_FRAMING:
+	case SK_PNMI_HRX_CARRIER:
+	case SK_PNMI_HRX_IRLENGTH:
+	case SK_PNMI_HRX_SYMBOL:
+	case SK_PNMI_HRX_CEXT:
+		/* Not supported by GMAC */
+		if (MacType == SK_MAC_GMAC) {
+			return (Val);
+		}
+
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+
+	case SK_PNMI_HRX_PMACC_ERR:
+		/* For GMAC the SW counter is managed by PNMI */
+		if (MacType == SK_MAC_GMAC) {
+			return (pPnmiPrt->StatRxPMaccErr);
+		}
+		
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+
+	/* SW counter managed by PNMI */
+	case SK_PNMI_HTX_SYNC:
+		LowVal = (SK_U32)pPnmiPrt->StatSyncCts;
+		HighVal = (SK_U32)(pPnmiPrt->StatSyncCts >> 32);
+		break;
+
+	/* SW counter managed by PNMI */
+	case SK_PNMI_HTX_SYNC_OCTET:
+		LowVal = (SK_U32)pPnmiPrt->StatSyncOctetsCts;
+		HighVal = (SK_U32)(pPnmiPrt->StatSyncOctetsCts >> 32);
+		break;
+
+	case SK_PNMI_HRX_FCS:
+		/*
+		 * Broadcom filters FCS errors and counts it in
+		 * Receive Error Counter register
+		 */
+		if (pPrt->PhyType == SK_PHY_BCOM) {
+			/* do not read while not initialized (PHY_READ hangs!)*/
+			if (pPrt->PState != SK_PRT_RESET) {
+				SkXmPhyRead(pAC, IoC, PhysPortIndex, PHY_BCOM_RE_CTR, &Word);
+				
+				LowVal = Word;
+			}
+			HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		}
+		else {
+			(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+										  StatAddr[StatIndex][MacType].Reg,
+										  &LowVal);
+			HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		}
+		break;
+
+	default:
+		(void)pFnMac->pFnMacStatistic(pAC, IoC, PhysPortIndex,
+									  StatAddr[StatIndex][MacType].Reg,
+									  &LowVal);
+		HighVal = pPnmiPrt->CounterHigh[StatIndex];
+		break;
+	}
+
+	Val = (((SK_U64)HighVal << 32) | (SK_U64)LowVal);
+
+	/* Correct value because of possible XMAC reset. XMAC Errata #2 */
+	Val += pPnmiPrt->CounterOffset[StatIndex];
+
+	return (Val);
+}
+
+/*****************************************************************************
+ *
+ * ResetCounter - Set all counters and timestamps to zero
+ *
+ * Description:
+ *	Notifies other common modules which store statistic data to
+ *	reset their counters and finally reset our own counters.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void ResetCounter(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+SK_U32 NetIndex)
+{
+	unsigned int	PhysPortIndex;
+	SK_EVPARA	EventParam;
+
+
+	SK_MEMSET((char *)&EventParam, 0, sizeof(EventParam));
+
+	/* Notify sensor module */
+	SkEventQueue(pAC, SKGE_I2C, SK_I2CEV_CLEAR, EventParam);
+
+	/* Notify RLMT module */
+	EventParam.Para32[0] = NetIndex;
+	EventParam.Para32[1] = (SK_U32)-1;
+	SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_STATS_CLEAR, EventParam);
+	EventParam.Para32[1] = 0;
+
+	/* Notify SIRQ module */
+	SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_CLEAR_STAT, EventParam);
+
+	/* Notify CSUM module */
+#ifdef SK_USE_CSUM
+	EventParam.Para32[0] = NetIndex;
+	EventParam.Para32[1] = (SK_U32)-1;
+	SkEventQueue(pAC, SKGE_CSUM, SK_CSUM_EVENT_CLEAR_PROTO_STATS,
+		EventParam);
+#endif /* SK_USE_CSUM */
+	
+	/* Clear XMAC statistic */
+	for (PhysPortIndex = 0; PhysPortIndex <
+		(unsigned int)pAC->GIni.GIMacsFound; PhysPortIndex ++) {
+
+		(void)pAC->GIni.GIFunc.pFnMacResetCounter(pAC, IoC, PhysPortIndex);
+
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].CounterHigh,
+			0, sizeof(pAC->Pnmi.Port[PhysPortIndex].CounterHigh));
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+			CounterOffset, 0, sizeof(pAC->Pnmi.Port[
+			PhysPortIndex].CounterOffset));
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].StatSyncCts,
+			0, sizeof(pAC->Pnmi.Port[PhysPortIndex].StatSyncCts));
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+			StatSyncOctetsCts, 0, sizeof(pAC->Pnmi.Port[
+			PhysPortIndex].StatSyncOctetsCts));
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+			StatRxLongFrameCts, 0, sizeof(pAC->Pnmi.Port[
+			PhysPortIndex].StatRxLongFrameCts));
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+				  StatRxFrameTooLongCts, 0, sizeof(pAC->Pnmi.Port[
+			PhysPortIndex].StatRxFrameTooLongCts));
+		SK_MEMSET((char *)&pAC->Pnmi.Port[PhysPortIndex].
+				  StatRxPMaccErr, 0, sizeof(pAC->Pnmi.Port[
+			PhysPortIndex].StatRxPMaccErr));
+	}
+
+	/*
+	 * Clear local statistics
+	 */
+	SK_MEMSET((char *)&pAC->Pnmi.VirtualCounterOffset, 0,
+		  sizeof(pAC->Pnmi.VirtualCounterOffset));
+	pAC->Pnmi.RlmtChangeCts = 0;
+	pAC->Pnmi.RlmtChangeTime = 0;
+	SK_MEMSET((char *)&pAC->Pnmi.RlmtChangeEstimate.EstValue[0], 0,
+		sizeof(pAC->Pnmi.RlmtChangeEstimate.EstValue));
+	pAC->Pnmi.RlmtChangeEstimate.EstValueIndex = 0;
+	pAC->Pnmi.RlmtChangeEstimate.Estimate = 0;
+	pAC->Pnmi.Port[NetIndex].TxSwQueueMax = 0;
+	pAC->Pnmi.Port[NetIndex].TxRetryCts = 0;
+	pAC->Pnmi.Port[NetIndex].RxIntrCts = 0;
+	pAC->Pnmi.Port[NetIndex].TxIntrCts = 0;
+	pAC->Pnmi.Port[NetIndex].RxNoBufCts = 0;
+	pAC->Pnmi.Port[NetIndex].TxNoBufCts = 0;
+	pAC->Pnmi.Port[NetIndex].TxUsedDescrNo = 0;
+	pAC->Pnmi.Port[NetIndex].RxDeliveredCts = 0;
+	pAC->Pnmi.Port[NetIndex].RxOctetsDeliveredCts = 0;
+	pAC->Pnmi.Port[NetIndex].ErrRecoveryCts = 0;
+}
+
+/*****************************************************************************
+ *
+ * GetTrapEntry - Get an entry in the trap buffer
+ *
+ * Description:
+ *	The trap buffer stores various events. A user application somehow
+ *	gets notified that an event occured and retrieves the trap buffer
+ *	contens (or simply polls the buffer). The buffer is organized as
+ *	a ring which stores the newest traps at the beginning. The oldest
+ *	traps are overwritten by the newest ones. Each trap entry has a
+ *	unique number, so that applications may detect new trap entries.
+ *
+ * Returns:
+ *	A pointer to the trap entry
+ */
+PNMI_STATIC char* GetTrapEntry(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_U32 TrapId,		/* SNMP ID of the trap */
+unsigned int Size)	/* Space needed for trap entry */
+{
+	unsigned int		BufPad = pAC->Pnmi.TrapBufPad;
+	unsigned int		BufFree = pAC->Pnmi.TrapBufFree;
+	unsigned int		Beg = pAC->Pnmi.TrapQueueBeg;
+	unsigned int		End = pAC->Pnmi.TrapQueueEnd;
+	char			*pBuf = &pAC->Pnmi.TrapBuf[0];
+	int			Wrap;
+	unsigned int		NeededSpace;
+	unsigned int		EntrySize;
+	SK_U32			Val32;
+	SK_U64			Val64;
+
+
+	/* Last byte of entry will get a copy of the entry length */
+	Size ++;
+
+	/*
+	 * Calculate needed buffer space */
+	if (Beg >= Size) {
+
+		NeededSpace = Size;
+		Wrap = SK_FALSE;
+	}
+	else {
+		NeededSpace = Beg + Size;
+		Wrap = SK_TRUE;
+	}
+
+	/*
+	 * Check if enough buffer space is provided. Otherwise
+	 * free some entries. Leave one byte space between begin
+	 * and end of buffer to make it possible to detect whether
+	 * the buffer is full or empty
+	 */
+	while (BufFree < NeededSpace + 1) {
+
+		if (End == 0) {
+
+			End = SK_PNMI_TRAP_QUEUE_LEN;
+		}
+
+		EntrySize = (unsigned int)*((unsigned char *)pBuf + End - 1);
+		BufFree += EntrySize;
+		End -= EntrySize;
+#ifdef DEBUG
+		SK_MEMSET(pBuf + End, (char)(-1), EntrySize);
+#endif /* DEBUG */
+		if (End == BufPad) {
+#ifdef DEBUG
+			SK_MEMSET(pBuf, (char)(-1), End);
+#endif /* DEBUG */
+			BufFree += End;
+			End = 0;
+			BufPad = 0;
+		}
+	}
+
+	/*
+	 * Insert new entry as first entry. Newest entries are
+	 * stored at the beginning of the queue.
+	 */
+	if (Wrap) {
+
+		BufPad = Beg;
+		Beg = SK_PNMI_TRAP_QUEUE_LEN - Size;
+	}
+	else {
+		Beg = Beg - Size;
+	}
+	BufFree -= NeededSpace;
+
+	/* Save the current offsets */
+	pAC->Pnmi.TrapQueueBeg = Beg;
+	pAC->Pnmi.TrapQueueEnd = End;
+	pAC->Pnmi.TrapBufPad = BufPad;
+	pAC->Pnmi.TrapBufFree = BufFree;
+
+	/* Initialize the trap entry */
+	*(pBuf + Beg + Size - 1) = (char)Size;
+	*(pBuf + Beg) = (char)Size;
+	Val32 = (pAC->Pnmi.TrapUnique) ++;
+	SK_PNMI_STORE_U32(pBuf + Beg + 1, Val32);
+	SK_PNMI_STORE_U32(pBuf + Beg + 1 + sizeof(SK_U32), TrapId);
+	Val64 = SK_PNMI_HUNDREDS_SEC(SkOsGetTime(pAC));
+	SK_PNMI_STORE_U64(pBuf + Beg + 1 + 2 * sizeof(SK_U32), Val64);
+
+	return (pBuf + Beg);
+}
+
+/*****************************************************************************
+ *
+ * CopyTrapQueue - Copies the trap buffer for the TRAP OID
+ *
+ * Description:
+ *	On a query of the TRAP OID the trap buffer contents will be
+ *	copied continuously to the request buffer, which must be large
+ *	enough. No length check is performed.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void CopyTrapQueue(
+SK_AC *pAC,		/* Pointer to adapter context */
+char *pDstBuf)		/* Buffer to which the queued traps will be copied */
+{
+	unsigned int	BufPad = pAC->Pnmi.TrapBufPad;
+	unsigned int	Trap = pAC->Pnmi.TrapQueueBeg;
+	unsigned int	End = pAC->Pnmi.TrapQueueEnd;
+	char		*pBuf = &pAC->Pnmi.TrapBuf[0];
+	unsigned int	Len;
+	unsigned int	DstOff = 0;
+
+
+	while (Trap != End) {
+
+		Len = (unsigned int)*(pBuf + Trap);
+
+		/*
+		 * Last byte containing a copy of the length will
+		 * not be copied.
+		 */
+		*(pDstBuf + DstOff) = (char)(Len - 1);
+		SK_MEMCPY(pDstBuf + DstOff + 1, pBuf + Trap + 1, Len - 2);
+		DstOff += Len - 1;
+
+		Trap += Len;
+		if (Trap == SK_PNMI_TRAP_QUEUE_LEN) {
+
+			Trap = BufPad;
+		}
+	}
+}
+
+/*****************************************************************************
+ *
+ * GetTrapQueueLen - Get the length of the trap buffer
+ *
+ * Description:
+ *	Evaluates the number of currently stored traps and the needed
+ *	buffer size to retrieve them.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void GetTrapQueueLen(
+SK_AC *pAC,		/* Pointer to adapter context */
+unsigned int *pLen,	/* Length in Bytes of all queued traps */
+unsigned int *pEntries)	/* Returns number of trapes stored in queue */
+{
+	unsigned int	BufPad = pAC->Pnmi.TrapBufPad;
+	unsigned int	Trap = pAC->Pnmi.TrapQueueBeg;
+	unsigned int	End = pAC->Pnmi.TrapQueueEnd;
+	char		*pBuf = &pAC->Pnmi.TrapBuf[0];
+	unsigned int	Len;
+	unsigned int	Entries = 0;
+	unsigned int	TotalLen = 0;
+
+
+	while (Trap != End) {
+
+		Len = (unsigned int)*(pBuf + Trap);
+		TotalLen += Len - 1;
+		Entries ++;
+
+		Trap += Len;
+		if (Trap == SK_PNMI_TRAP_QUEUE_LEN) {
+
+			Trap = BufPad;
+		}
+	}
+
+	*pEntries = Entries;
+	*pLen = TotalLen;
+}
+
+/*****************************************************************************
+ *
+ * QueueSimpleTrap - Store a simple trap to the trap buffer
+ *
+ * Description:
+ *	A simple trap is a trap with now additional data. It consists
+ *	simply of a trap code.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void QueueSimpleTrap(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_U32 TrapId)		/* Type of sensor trap */
+{
+	GetTrapEntry(pAC, TrapId, SK_PNMI_TRAP_SIMPLE_LEN);
+}
+
+/*****************************************************************************
+ *
+ * QueueSensorTrap - Stores a sensor trap in the trap buffer
+ *
+ * Description:
+ *	Gets an entry in the trap buffer and fills it with sensor related
+ *	data.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void QueueSensorTrap(
+SK_AC *pAC,			/* Pointer to adapter context */
+SK_U32 TrapId,			/* Type of sensor trap */
+unsigned int SensorIndex)	/* Index of sensor which caused the trap */
+{
+	char		*pBuf;
+	unsigned int	Offset;
+	unsigned int	DescrLen;
+	SK_U32		Val32;
+
+
+	/* Get trap buffer entry */
+	DescrLen = SK_STRLEN(pAC->I2c.SenTable[SensorIndex].SenDesc);
+	pBuf = GetTrapEntry(pAC, TrapId,
+		SK_PNMI_TRAP_SENSOR_LEN_BASE + DescrLen);
+	Offset = SK_PNMI_TRAP_SIMPLE_LEN;
+
+	/* Store additionally sensor trap related data */
+	Val32 = OID_SKGE_SENSOR_INDEX;
+	SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+	*(pBuf + Offset + 4) = 4;
+	Val32 = (SK_U32)SensorIndex;
+	SK_PNMI_STORE_U32(pBuf + Offset + 5, Val32);
+	Offset += 9;
+	
+	Val32 = (SK_U32)OID_SKGE_SENSOR_DESCR;
+	SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+	*(pBuf + Offset + 4) = (char)DescrLen;
+	SK_MEMCPY(pBuf + Offset + 5, pAC->I2c.SenTable[SensorIndex].SenDesc,
+		DescrLen);
+	Offset += DescrLen + 5;
+
+	Val32 = OID_SKGE_SENSOR_TYPE;
+	SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+	*(pBuf + Offset + 4) = 1;
+	*(pBuf + Offset + 5) = (char)pAC->I2c.SenTable[SensorIndex].SenType;
+	Offset += 6;
+
+	Val32 = OID_SKGE_SENSOR_VALUE;
+	SK_PNMI_STORE_U32(pBuf + Offset, Val32);
+	*(pBuf + Offset + 4) = 4;
+	Val32 = (SK_U32)pAC->I2c.SenTable[SensorIndex].SenValue;
+	SK_PNMI_STORE_U32(pBuf + Offset + 5, Val32);
+}
+
+/*****************************************************************************
+ *
+ * QueueRlmtNewMacTrap - Store a port switch trap in the trap buffer
+ *
+ * Description:
+ *	Nothing further to explain.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void QueueRlmtNewMacTrap(
+SK_AC *pAC,		/* Pointer to adapter context */
+unsigned int ActiveMac)	/* Index (0..n) of the currently active port */
+{
+	char	*pBuf;
+	SK_U32	Val32;
+
+
+	pBuf = GetTrapEntry(pAC, OID_SKGE_TRAP_RLMT_CHANGE_PORT,
+		SK_PNMI_TRAP_RLMT_CHANGE_LEN);
+
+	Val32 = OID_SKGE_RLMT_PORT_ACTIVE;
+	SK_PNMI_STORE_U32(pBuf + SK_PNMI_TRAP_SIMPLE_LEN, Val32);
+	*(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 4) = 1;
+	*(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 5) = (char)ActiveMac;
+}
+
+/*****************************************************************************
+ *
+ * QueueRlmtPortTrap - Store port related RLMT trap to trap buffer
+ *
+ * Description:
+ *	Nothing further to explain.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void QueueRlmtPortTrap(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_U32 TrapId,		/* Type of RLMT port trap */
+unsigned int PortIndex)	/* Index of the port, which changed its state */
+{
+	char	*pBuf;
+	SK_U32	Val32;
+
+
+	pBuf = GetTrapEntry(pAC, TrapId, SK_PNMI_TRAP_RLMT_PORT_LEN);
+
+	Val32 = OID_SKGE_RLMT_PORT_INDEX;
+	SK_PNMI_STORE_U32(pBuf + SK_PNMI_TRAP_SIMPLE_LEN, Val32);
+	*(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 4) = 1;
+	*(pBuf + SK_PNMI_TRAP_SIMPLE_LEN + 5) = (char)PortIndex;
+}
+
+/*****************************************************************************
+ *
+ * CopyMac - Copies a MAC address
+ *
+ * Description:
+ *	Nothing further to explain.
+ *
+ * Returns:
+ *	Nothing
+ */
+PNMI_STATIC void CopyMac(
+char *pDst,		/* Pointer to destination buffer */
+SK_MAC_ADDR *pMac)	/* Pointer of Source */
+{
+	int	i;
+
+
+	for (i = 0; i < sizeof(SK_MAC_ADDR); i ++) {
+
+		*(pDst + i) = pMac->a[i];
+	}
+}
+
+#ifdef SK_POWER_MGMT
+/*****************************************************************************
+ *
+ * PowerManagement - OID handler function of PowerManagement OIDs
+ *
+ * Description:
+ *	The code is simple. No description necessary.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                               exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+PNMI_STATIC int PowerManagement(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* Get/PreSet/Set action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer to which to mgmt data will be retrieved */
+unsigned int *pLen,	/* On call: buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode allways zero */
+{
+	
+	SK_U32	RetCode = SK_PNMI_ERR_GENERAL;
+
+	/*
+	 * Check instance. We only handle single instance variables
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+	
+    
+    /* Check length */
+    switch (Id) {
+
+    case OID_PNP_CAPABILITIES:
+        if (*pLen < sizeof(SK_PNP_CAPABILITIES)) {
+
+            *pLen = sizeof(SK_PNP_CAPABILITIES);
+            return (SK_PNMI_ERR_TOO_SHORT);
+        }
+        break;
+
+	case OID_PNP_SET_POWER:
+    case OID_PNP_QUERY_POWER:
+    	if (*pLen < sizeof(SK_DEVICE_POWER_STATE))
+    	{
+    		*pLen = sizeof(SK_DEVICE_POWER_STATE);
+    		return (SK_PNMI_ERR_TOO_SHORT);
+    	}
+        break;
+
+    case OID_PNP_ADD_WAKE_UP_PATTERN:
+    case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+		if (*pLen < sizeof(SK_PM_PACKET_PATTERN)) {
+
+			*pLen = sizeof(SK_PM_PACKET_PATTERN);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+    case OID_PNP_ENABLE_WAKE_UP:
+        if (*pLen < sizeof(SK_U32)) {
+
+            *pLen = sizeof(SK_U32);
+            return (SK_PNMI_ERR_TOO_SHORT);
+        }
+        break;
+    }
+	
+    /*
+	 * Perform action
+	 */
+	if (Action == SK_PNMI_GET) {
+
+		/*
+		 * Get value
+		 */
+		switch (Id) {
+
+		case OID_PNP_CAPABILITIES:
+			RetCode = SkPowerQueryPnPCapabilities(pAC, IoC, pBuf, pLen);
+			break;
+
+		case OID_PNP_QUERY_POWER:
+			/* The Windows DDK describes: An OID_PNP_QUERY_POWER requests
+			 the miniport to indicate whether it can transition its NIC
+			 to the low-power state.
+			 A miniport driver must always return NDIS_STATUS_SUCCESS
+			 to a query of OID_PNP_QUERY_POWER. */
+			*pLen = sizeof(SK_DEVICE_POWER_STATE);
+            RetCode = SK_PNMI_ERR_OK;
+			break;
+
+			/* NDIS handles these OIDs as write-only.
+			 * So in case of get action the buffer with written length = 0
+			 * is returned
+			 */
+		case OID_PNP_SET_POWER:
+		case OID_PNP_ADD_WAKE_UP_PATTERN:
+		case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+			*pLen = 0;	
+            RetCode = SK_PNMI_ERR_NOT_SUPPORTED;
+			break;
+
+		case OID_PNP_ENABLE_WAKE_UP:
+			RetCode = SkPowerGetEnableWakeUp(pAC, IoC, pBuf, pLen);
+			break;
+
+		default:
+			RetCode = SK_PNMI_ERR_GENERAL;
+			break;
+		}
+
+		return (RetCode);
+	}
+	
+
+	/*
+	 * Perform preset or set
+	 */
+	
+	/* POWER module does not support PRESET action */
+	if (Action == SK_PNMI_PRESET) {
+		return (SK_PNMI_ERR_OK);
+	}
+
+	switch (Id) {
+	case OID_PNP_SET_POWER:
+		RetCode = SkPowerSetPower(pAC, IoC, pBuf, pLen);	
+		break;
+
+	case OID_PNP_ADD_WAKE_UP_PATTERN:
+		RetCode = SkPowerAddWakeUpPattern(pAC, IoC, pBuf, pLen);	
+		break;
+		
+	case OID_PNP_REMOVE_WAKE_UP_PATTERN:
+		RetCode = SkPowerRemoveWakeUpPattern(pAC, IoC, pBuf, pLen);	
+		break;
+		
+	case OID_PNP_ENABLE_WAKE_UP:
+		RetCode = SkPowerSetEnableWakeUp(pAC, IoC, pBuf, pLen);
+		break;
+		
+	default:
+		RetCode = SK_PNMI_ERR_READ_ONLY;
+	}
+	
+	return (RetCode);
+}
+#endif /* SK_POWER_MGMT */
+
+#ifdef SK_DIAG_SUPPORT
+/*****************************************************************************
+ *
+ * DiagActions - OID handler function of Diagnostic driver 
+ *
+ * Description:
+ *	The code is simple. No description necessary.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+
+PNMI_STATIC int DiagActions(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* GET/PRESET/SET action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,	/* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (1..n) that is to be queried or -1 */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+
+	SK_U32	DiagStatus;
+	SK_U32	RetCode = SK_PNMI_ERR_GENERAL;
+
+	/*
+	 * Check instance. We only handle single instance variables.
+	 */
+	if (Instance != (SK_U32)(-1) && Instance != 1) {
+
+		*pLen = 0;
+		return (SK_PNMI_ERR_UNKNOWN_INST);
+	}
+
+	/*
+	 * Check length.
+	 */
+	switch (Id) {
+
+	case OID_SKGE_DIAG_MODE:
+		if (*pLen < sizeof(SK_U32)) {
+
+			*pLen = sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SK_PNMI_ERR040, SK_PNMI_ERR040MSG);
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+	}
+
+	/* Perform action. */
+
+	/* GET value. */
+	if (Action == SK_PNMI_GET) {
+
+		switch (Id) {
+
+		case OID_SKGE_DIAG_MODE:
+			DiagStatus = pAC->Pnmi.DiagAttached;
+			SK_PNMI_STORE_U32(pBuf, DiagStatus);
+			*pLen = sizeof(SK_U32);	
+			RetCode = SK_PNMI_ERR_OK;
+			break;
+
+		default:
+			*pLen = 0;	
+			RetCode = SK_PNMI_ERR_GENERAL;
+			break;
+		}
+		return (RetCode); 
+	}
+
+	/* From here SET or PRESET value. */
+	
+	/* PRESET value is not supported. */
+	if (Action == SK_PNMI_PRESET) {
+		return (SK_PNMI_ERR_OK); 
+	}
+
+	/* SET value. */
+	switch (Id) {
+		case OID_SKGE_DIAG_MODE:
+
+			/* Handle the SET. */
+			switch (*pBuf) {
+
+				/* Attach the DIAG to this adapter. */
+				case SK_DIAG_ATTACHED:
+					/* Check if we come from running */
+					if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) {
+
+						RetCode = SkDrvLeaveDiagMode(pAC);
+
+					}
+					else if (pAC->Pnmi.DiagAttached == SK_DIAG_IDLE) {
+
+						RetCode = SK_PNMI_ERR_OK;
+					}	
+					
+					else {
+
+						RetCode = SK_PNMI_ERR_GENERAL;
+
+					}
+					
+					if (RetCode == SK_PNMI_ERR_OK) {
+
+						pAC->Pnmi.DiagAttached = SK_DIAG_ATTACHED;
+					}
+					break;
+
+				/* Enter the DIAG mode in the driver. */
+				case SK_DIAG_RUNNING:
+					RetCode = SK_PNMI_ERR_OK;
+					
+					/*
+					 * If DiagAttached is set, we can tell the driver
+					 * to enter the DIAG mode.
+					 */
+					if (pAC->Pnmi.DiagAttached == SK_DIAG_ATTACHED) {
+						/* If DiagMode is not active, we can enter it. */
+						if (!pAC->DiagModeActive) {
+
+							RetCode = SkDrvEnterDiagMode(pAC); 
+						}
+						else {
+
+							RetCode = SK_PNMI_ERR_GENERAL;
+						}
+					}
+					else {
+
+						RetCode = SK_PNMI_ERR_GENERAL;
+					}
+					
+					if (RetCode == SK_PNMI_ERR_OK) {
+
+						pAC->Pnmi.DiagAttached = SK_DIAG_RUNNING;
+					}
+					break;
+
+				case SK_DIAG_IDLE:
+					/* Check if we come from running */
+					if (pAC->Pnmi.DiagAttached == SK_DIAG_RUNNING) {
+
+						RetCode = SkDrvLeaveDiagMode(pAC);
+
+					}
+					else if (pAC->Pnmi.DiagAttached == SK_DIAG_ATTACHED) {
+
+						RetCode = SK_PNMI_ERR_OK;
+					}	
+					
+					else {
+
+						RetCode = SK_PNMI_ERR_GENERAL;
+
+					}
+
+					if (RetCode == SK_PNMI_ERR_OK) {
+
+						pAC->Pnmi.DiagAttached = SK_DIAG_IDLE;
+					}
+					break;
+
+				default:
+					RetCode = SK_PNMI_ERR_BAD_VALUE;
+					break;
+			}
+			break;
+
+		default:
+			RetCode = SK_PNMI_ERR_GENERAL;
+	}
+
+	if (RetCode == SK_PNMI_ERR_OK) {
+		*pLen = sizeof(SK_U32);
+	}
+	else {
+
+		*pLen = 0;
+	}
+	return (RetCode);
+}
+#endif /* SK_DIAG_SUPPORT */
+
+/*****************************************************************************
+ *
+ * Vct - OID handler function of  OIDs
+ *
+ * Description:
+ *	The code is simple. No description necessary.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was performed successfully.
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured.
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to contain
+ *	                         the correct data (e.g. a 32bit value is
+ *	                         needed, but a 16 bit value was passed).
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter).
+ *	SK_PNMI_ERR_READ_ONLY	 Only the Get action is allowed.
+ *
+ */
+
+PNMI_STATIC int Vct(
+SK_AC *pAC,		/* Pointer to adapter context */
+SK_IOC IoC,		/* IO context handle */
+int Action,		/* GET/PRESET/SET action */
+SK_U32 Id,		/* Object ID that is to be processed */
+char *pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,	/* On call: pBuf buffer length. On return: used buffer */
+SK_U32 Instance,	/* Instance (-1,2..n) that is to be queried */
+unsigned int TableIndex, /* Index to the Id table */
+SK_U32 NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+	SK_GEPORT	*pPrt;
+	SK_PNMI_VCT	*pVctBackupData;
+	SK_U32		LogPortMax;
+	SK_U32		PhysPortMax;
+	SK_U32		PhysPortIndex;
+	SK_U32		Limit;
+	SK_U32		Offset;
+	SK_BOOL		Link;
+	SK_U32		RetCode = SK_PNMI_ERR_GENERAL;
+	int		i;
+	SK_EVPARA	Para;
+	SK_U32		CableLength;
+	
+	/*
+	 * Calculate the port indexes from the instance.
+	 */
+	PhysPortMax = pAC->GIni.GIMacsFound;
+	LogPortMax = SK_PNMI_PORT_PHYS2LOG(PhysPortMax);
+	
+	/* Dual net mode? */
+	if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+		LogPortMax--;
+	}
+	
+	if ((Instance != (SK_U32) (-1))) {
+		/* Check instance range. */
+		if ((Instance < 2) || (Instance > LogPortMax)) {
+			*pLen = 0;
+			return (SK_PNMI_ERR_UNKNOWN_INST);
+		}
+		
+		if (pAC->Pnmi.DualNetActiveFlag == SK_TRUE) {
+			PhysPortIndex = NetIndex;
+		}
+		else {
+			PhysPortIndex = Instance - 2;
+		}
+		Limit = PhysPortIndex + 1;
+	}
+	else {
+		/*
+		 * Instance == (SK_U32) (-1), get all Instances of that OID.
+		 *
+		 * Not implemented yet. May be used in future releases.
+		 */
+		PhysPortIndex = 0;
+		Limit = PhysPortMax;
+	}
+	
+	pPrt = &pAC->GIni.GP[PhysPortIndex];
+	if (pPrt->PHWLinkUp) {
+		Link = SK_TRUE;
+	}
+	else {
+		Link = SK_FALSE;
+	}
+	
+	/* Check MAC type */
+	if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+	}
+	
+	/* Initialize backup data pointer. */
+	pVctBackupData = &pAC->Pnmi.VctBackup[PhysPortIndex];
+	
+	/* Check action type */
+	if (Action == SK_PNMI_GET) {
+		/* Check length */
+		switch (Id) {
+		
+		case OID_SKGE_VCT_GET:
+			if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_PNMI_VCT)) {
+				*pLen = (Limit - PhysPortIndex) * sizeof(SK_PNMI_VCT);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+		
+		case OID_SKGE_VCT_STATUS:
+			if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U8)) {
+				*pLen = (Limit - PhysPortIndex) * sizeof(SK_U8);
+				return (SK_PNMI_ERR_TOO_SHORT);
+			}
+			break;
+		
+		default:
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}	
+		
+		/* Get value */
+		Offset = 0;
+		for (; PhysPortIndex < Limit; PhysPortIndex++) {
+			switch (Id) {
+			
+			case OID_SKGE_VCT_GET:
+				if ((Link == SK_FALSE) &&
+					(pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING)) {
+					RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_FALSE);
+					if (RetCode == 0) {
+						pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_PENDING;
+						pAC->Pnmi.VctStatus[PhysPortIndex] |=
+							(SK_PNMI_VCT_NEW_VCT_DATA | SK_PNMI_VCT_TEST_DONE);
+						
+						/* Copy results for later use to PNMI struct. */
+						for (i = 0; i < 4; i++)  {
+							if (pPrt->PMdiPairSts[i] == SK_PNMI_VCT_NORMAL_CABLE) {
+								if ((pPrt->PMdiPairLen[i] > 35) && (pPrt->PMdiPairLen[i] < 0xff)) {
+									pPrt->PMdiPairSts[i] = SK_PNMI_VCT_IMPEDANCE_MISMATCH;
+								}
+							}
+							if ((pPrt->PMdiPairLen[i] > 35) && (pPrt->PMdiPairLen[i] != 0xff)) {
+								CableLength = 1000 * (((175 * pPrt->PMdiPairLen[i]) / 210) - 28);
+							}
+							else {
+								CableLength = 0;
+							}
+							pVctBackupData->PMdiPairLen[i] = CableLength;
+							pVctBackupData->PMdiPairSts[i] = pPrt->PMdiPairSts[i];
+						}
+
+						Para.Para32[0] = PhysPortIndex;
+						Para.Para32[1] = -1;
+						SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
+						SkEventDispatcher(pAC, IoC);
+					}
+					else {
+						; /* VCT test is running. */
+					}
+				}
+				
+				/* Get all results. */
+				CheckVctStatus(pAC, IoC, pBuf, Offset, PhysPortIndex);
+				Offset += sizeof(SK_U8);
+				*(pBuf + Offset) = pPrt->PCableLen;
+				Offset += sizeof(SK_U8);
+				for (i = 0; i < 4; i++)  {
+					SK_PNMI_STORE_U32((pBuf + Offset), pVctBackupData->PMdiPairLen[i]);
+					Offset += sizeof(SK_U32);
+				}
+				for (i = 0; i < 4; i++)  {
+					*(pBuf + Offset) = pVctBackupData->PMdiPairSts[i];
+					Offset += sizeof(SK_U8);
+				}
+				
+				RetCode = SK_PNMI_ERR_OK;
+				break;
+		
+			case OID_SKGE_VCT_STATUS:
+				CheckVctStatus(pAC, IoC, pBuf, Offset, PhysPortIndex);
+				Offset += sizeof(SK_U8);
+				RetCode = SK_PNMI_ERR_OK;
+				break;
+			
+			default:
+				*pLen = 0;
+				return (SK_PNMI_ERR_GENERAL);
+			}
+		} /* for */
+		*pLen = Offset;
+		return (RetCode);
+	
+	} /* if SK_PNMI_GET */
+	
+	/*
+	 * From here SET or PRESET action. Check if the passed
+	 * buffer length is plausible.
+	 */
+	
+	/* Check length */
+	switch (Id) {
+	case OID_SKGE_VCT_SET:
+		if (*pLen < (Limit - PhysPortIndex) * sizeof(SK_U32)) {
+			*pLen = (Limit - PhysPortIndex) * sizeof(SK_U32);
+			return (SK_PNMI_ERR_TOO_SHORT);
+		}
+		break;
+	
+	default:
+		*pLen = 0;
+		return (SK_PNMI_ERR_GENERAL);
+	}
+	
+	/*
+	 * Perform preset or set.
+	 */
+	
+	/* VCT does not support PRESET action. */
+	if (Action == SK_PNMI_PRESET) {
+		return (SK_PNMI_ERR_OK);
+	}
+	
+	Offset = 0;
+	for (; PhysPortIndex < Limit; PhysPortIndex++) {
+		switch (Id) {
+		case OID_SKGE_VCT_SET: /* Start VCT test. */
+			if (Link == SK_FALSE) {
+				SkGeStopPort(pAC, IoC, PhysPortIndex, SK_STOP_ALL, SK_SOFT_RST);
+				
+				RetCode = SkGmCableDiagStatus(pAC, IoC, PhysPortIndex, SK_TRUE);
+				if (RetCode == 0) { /* RetCode: 0 => Start! */
+					pAC->Pnmi.VctStatus[PhysPortIndex] |= SK_PNMI_VCT_PENDING;
+					pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_NEW_VCT_DATA;
+					pAC->Pnmi.VctStatus[PhysPortIndex] &= ~SK_PNMI_VCT_LINK;
+					
+					/*
+					 * Start VCT timer counter.
+					 */
+					SK_MEMSET((char *) &Para, 0, sizeof(Para));
+					Para.Para32[0] = PhysPortIndex;
+					Para.Para32[1] = -1;
+					SkTimerStart(pAC, IoC, &pAC->Pnmi.VctTimeout[PhysPortIndex].VctTimer,
+						4000000, SKGE_PNMI, SK_PNMI_EVT_VCT_RESET, Para);
+					SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
+					RetCode = SK_PNMI_ERR_OK;
+				}
+				else { /* RetCode: 2 => Running! */
+					SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
+					RetCode = SK_PNMI_ERR_OK;
+				}
+			}
+			else { /* RetCode: 4 => Link! */
+				RetCode = 4;
+				SK_PNMI_STORE_U32((pBuf + Offset), RetCode);
+				RetCode = SK_PNMI_ERR_OK;
+			}
+			Offset += sizeof(SK_U32);
+			break;
+	
+		default:
+			*pLen = 0;
+			return (SK_PNMI_ERR_GENERAL);
+		}
+	} /* for */
+	*pLen = Offset;
+	return (RetCode);
+
+} /* Vct */
+
+
+PNMI_STATIC void CheckVctStatus(
+SK_AC		*pAC,
+SK_IOC		IoC,
+char		*pBuf,
+SK_U32		Offset,
+SK_U32		PhysPortIndex)
+{
+	SK_GEPORT 	*pPrt;
+	SK_PNMI_VCT	*pVctData;
+	SK_U32		RetCode;
+	
+	pPrt = &pAC->GIni.GP[PhysPortIndex];
+	
+	pVctData = (SK_PNMI_VCT *) (pBuf + Offset);
+	pVctData->VctStatus = SK_PNMI_VCT_NONE;
+	
+	if (!pPrt->PHWLinkUp) {
+		
+		/* Was a VCT test ever made before? */
+		if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_TEST_DONE) {
+			if ((pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_LINK)) {
+				pVctData->VctStatus |= SK_PNMI_VCT_OLD_VCT_DATA;
+			}
+			else {
+				pVctData->VctStatus |= SK_PNMI_VCT_NEW_VCT_DATA;
+			}
+		}
+		
+		/* Check VCT test status. */
+		RetCode = SkGmCableDiagStatus(pAC,IoC, PhysPortIndex, SK_FALSE);
+		if (RetCode == 2) { /* VCT test is running. */
+			pVctData->VctStatus |= SK_PNMI_VCT_RUNNING;
+		}
+		else { /* VCT data was copied to pAC here. Check PENDING state. */
+			if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_PENDING) {
+				pVctData->VctStatus |= SK_PNMI_VCT_NEW_VCT_DATA;
+			}
+		}
+		
+		if (pPrt->PCableLen != 0xff) { /* Old DSP value. */
+			pVctData->VctStatus |= SK_PNMI_VCT_OLD_DSP_DATA;
+		}
+	}
+	else {
+		
+		/* Was a VCT test ever made before? */
+		if (pAC->Pnmi.VctStatus[PhysPortIndex] & SK_PNMI_VCT_TEST_DONE) {
+			pVctData->VctStatus &= ~SK_PNMI_VCT_NEW_VCT_DATA;
+			pVctData->VctStatus |= SK_PNMI_VCT_OLD_VCT_DATA;
+		}
+		
+		/* DSP only valid in 100/1000 modes. */
+		if (pAC->GIni.GP[PhysPortIndex].PLinkSpeedUsed !=
+			SK_LSPEED_STAT_10MBPS) {	
+			pVctData->VctStatus |= SK_PNMI_VCT_NEW_DSP_DATA;
+		}
+	}
+} /* CheckVctStatus */
+
+
+/*****************************************************************************
+ *
+ *      SkPnmiGenIoctl - Handles new generic PNMI IOCTL, calls the needed
+ *                       PNMI function depending on the subcommand and
+ *                       returns all data belonging to the complete database
+ *                       or OID request.
+ *
+ * Description:
+ *	Looks up the requested subcommand, calls the corresponding handler
+ *	function and passes all required parameters to it.
+ *	The function is called by the driver. It is needed to handle the new
+ *  generic PNMI IOCTL. This IOCTL is given to the driver and contains both
+ *  the OID and a subcommand to decide what kind of request has to be done.
+ *
+ * Returns:
+ *	SK_PNMI_ERR_OK           The request was successfully performed
+ *	SK_PNMI_ERR_GENERAL      A general severe internal error occured
+ *	SK_PNMI_ERR_TOO_SHORT    The passed buffer is too short to take
+ *	                         the data.
+ *	SK_PNMI_ERR_UNKNOWN_OID  The requested OID is unknown
+ *	SK_PNMI_ERR_UNKNOWN_INST The requested instance of the OID doesn't
+ *                           exist (e.g. port instance 3 on a two port
+ *	                         adapter.
+ */
+int SkPnmiGenIoctl(
+SK_AC		*pAC,		/* Pointer to adapter context struct */
+SK_IOC		IoC,		/* I/O context */
+void		*pBuf,		/* Buffer used for the management data transfer */
+unsigned int *pLen,		/* Length of buffer */
+SK_U32		NetIndex)	/* NetIndex (0..n), in single net mode always zero */
+{
+SK_I32	Mode;			/* Store value of subcommand. */
+SK_U32	Oid;			/* Store value of OID. */
+int		ReturnCode;		/* Store return value to show status of PNMI action. */
+int 	HeaderLength;	/* Length of desired action plus OID. */
+
+	ReturnCode = SK_PNMI_ERR_GENERAL;
+	
+	SK_MEMCPY(&Mode, pBuf, sizeof(SK_I32));
+	SK_MEMCPY(&Oid, (char *) pBuf + sizeof(SK_I32), sizeof(SK_U32));
+	HeaderLength = sizeof(SK_I32) + sizeof(SK_U32);
+	*pLen = *pLen - HeaderLength;
+	SK_MEMCPY((char *) pBuf + sizeof(SK_I32), (char *) pBuf + HeaderLength, *pLen);
+	
+	switch(Mode) {
+	case SK_GET_SINGLE_VAR:
+		ReturnCode = SkPnmiGetVar(pAC, IoC, Oid, 
+				(char *) pBuf + sizeof(SK_I32), pLen,
+				((SK_U32) (-1)), NetIndex);
+		SK_PNMI_STORE_U32(pBuf, ReturnCode);
+		*pLen = *pLen + sizeof(SK_I32);
+		break;
+	case SK_PRESET_SINGLE_VAR:
+		ReturnCode = SkPnmiPreSetVar(pAC, IoC, Oid, 
+				(char *) pBuf + sizeof(SK_I32), pLen,
+				((SK_U32) (-1)), NetIndex);
+		SK_PNMI_STORE_U32(pBuf, ReturnCode);
+		*pLen = *pLen + sizeof(SK_I32);
+		break;
+	case SK_SET_SINGLE_VAR:
+		ReturnCode = SkPnmiSetVar(pAC, IoC, Oid, 
+				(char *) pBuf + sizeof(SK_I32), pLen,
+				((SK_U32) (-1)), NetIndex);
+		SK_PNMI_STORE_U32(pBuf, ReturnCode);
+		*pLen = *pLen + sizeof(SK_I32);
+		break;
+	case SK_GET_FULL_MIB:
+		ReturnCode = SkPnmiGetStruct(pAC, IoC, pBuf, pLen, NetIndex);
+		break;
+	case SK_PRESET_FULL_MIB:
+		ReturnCode = SkPnmiPreSetStruct(pAC, IoC, pBuf, pLen, NetIndex);
+		break;
+	case SK_SET_FULL_MIB:
+		ReturnCode = SkPnmiSetStruct(pAC, IoC, pBuf, pLen, NetIndex);
+		break;
+	default:
+		break;
+	}
+	
+	return (ReturnCode);
+
+} /* SkGeIocGen */
diff --git a/drivers/net/sk98lin/skgesirq.c b/drivers/net/sk98lin/skgesirq.c
new file mode 100644
index 0000000..3e7aa49
--- /dev/null
+++ b/drivers/net/sk98lin/skgesirq.c
@@ -0,0 +1,2229 @@
+/******************************************************************************
+ *
+ * Name:	skgesirq.c
+ * Project:	Gigabit Ethernet Adapters, Common Modules
+ * Version:	$Revision: 1.92 $
+ * Date:	$Date: 2003/09/16 14:37:07 $
+ * Purpose:	Special IRQ module
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/*
+ *	Special Interrupt handler
+ *
+ *	The following abstract should show how this module is included
+ *	in the driver path:
+ *
+ *	In the ISR of the driver the bits for frame transmission complete and
+ *	for receive complete are checked and handled by the driver itself.
+ *	The bits of the slow path mask are checked after that and then the
+ *	entry into the so-called "slow path" is prepared. It is an implementors
+ *	decision whether this is executed directly or just scheduled by
+ *	disabling the mask. In the interrupt service routine some events may be
+ *	generated, so it would be a good idea to call the EventDispatcher
+ *	right after this ISR.
+ *
+ *	The Interrupt source register of the adapter is NOT read by this module.
+ *  SO if the drivers implementor needs a while loop around the
+ *	slow data paths interrupt bits, he needs to call the SkGeSirqIsr() for
+ *	each loop entered.
+ *
+ *	However, the MAC Interrupt status registers are read in a while loop.
+ *
+ */
+
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+	"@(#) $Id: skgesirq.c,v 1.92 2003/09/16 14:37:07 rschmidt Exp $ (C) Marvell.";
+#endif
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#ifndef SK_SLIM
+#include "h/skgepnmi.h"		/* PNMI Definitions */
+#include "h/skrlmt.h"		/* RLMT Definitions */
+#endif
+#include "h/skdrv2nd.h"		/* Adapter Control and Driver specific Def. */
+
+/* local function prototypes */
+#ifdef GENESIS
+static int	SkGePortCheckUpXmac(SK_AC*, SK_IOC, int, SK_BOOL);
+static int	SkGePortCheckUpBcom(SK_AC*, SK_IOC, int, SK_BOOL);
+static void	SkPhyIsrBcom(SK_AC*, SK_IOC, int, SK_U16);
+#endif /* GENESIS */
+#ifdef YUKON
+static int	SkGePortCheckUpGmac(SK_AC*, SK_IOC, int, SK_BOOL);
+static void	SkPhyIsrGmac(SK_AC*, SK_IOC, int, SK_U16);
+#endif /* YUKON */
+#ifdef OTHER_PHY
+static int	SkGePortCheckUpLone(SK_AC*, SK_IOC, int, SK_BOOL);
+static int	SkGePortCheckUpNat(SK_AC*, SK_IOC, int, SK_BOOL);
+static void	SkPhyIsrLone(SK_AC*, SK_IOC, int, SK_U16);
+#endif /* OTHER_PHY */
+
+#ifdef GENESIS
+/*
+ * array of Rx counter from XMAC which are checked
+ * in AutoSense mode to check whether a link is not able to auto-negotiate.
+ */
+static const SK_U16 SkGeRxRegs[]= {
+	XM_RXF_64B,
+	XM_RXF_127B,
+	XM_RXF_255B,
+	XM_RXF_511B,
+	XM_RXF_1023B,
+	XM_RXF_MAX_SZ
+} ;
+#endif /* GENESIS */
+
+#ifdef __C2MAN__
+/*
+ *	Special IRQ function
+ *
+ *	General Description:
+ *
+ */
+intro()
+{}
+#endif
+
+/******************************************************************************
+ *
+ *	SkHWInitDefSense() - Default Autosensing mode initialization
+ *
+ * Description: sets the PLinkMode for HWInit
+ *
+ * Returns: N/A
+ */
+static void SkHWInitDefSense(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	pPrt->PAutoNegTimeOut = 0;
+
+	if (pPrt->PLinkModeConf != SK_LMODE_AUTOSENSE) {
+		pPrt->PLinkMode = pPrt->PLinkModeConf;
+		return;
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+		("AutoSensing: First mode %d on Port %d\n",
+		(int)SK_LMODE_AUTOFULL, Port));
+
+	pPrt->PLinkMode = (SK_U8)SK_LMODE_AUTOFULL;
+
+	return;
+}	/* SkHWInitDefSense */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *	SkHWSenseGetNext() - Get Next Autosensing Mode
+ *
+ * Description: gets the appropriate next mode
+ *
+ * Note:
+ *
+ */
+static SK_U8 SkHWSenseGetNext(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	pPrt->PAutoNegTimeOut = 0;
+
+    if (pPrt->PLinkModeConf != (SK_U8)SK_LMODE_AUTOSENSE) {
+		/* Leave all as configured */
+		return(pPrt->PLinkModeConf);
+	}
+
+    if (pPrt->PLinkMode == (SK_U8)SK_LMODE_AUTOFULL) {
+		/* Return next mode AUTOBOTH */
+        return ((SK_U8)SK_LMODE_AUTOBOTH);
+	}
+
+	/* Return default autofull */
+    return ((SK_U8)SK_LMODE_AUTOFULL);
+}	/* SkHWSenseGetNext */
+
+
+/******************************************************************************
+ *
+ *	SkHWSenseSetNext() - Autosensing Set next mode
+ *
+ * Description:	sets the appropriate next mode
+ *
+ * Returns: N/A
+ */
+static void SkHWSenseSetNext(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_U8	NewMode)	/* New Mode to be written in sense mode */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	pPrt->PAutoNegTimeOut = 0;
+
+    if (pPrt->PLinkModeConf != (SK_U8)SK_LMODE_AUTOSENSE) {
+		return;
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+		("AutoSensing: next mode %d on Port %d\n",
+		(int)NewMode, Port));
+
+	pPrt->PLinkMode = NewMode;
+
+	return;
+}	/* SkHWSenseSetNext */
+#endif /* GENESIS */
+
+
+/******************************************************************************
+ *
+ *	SkHWLinkDown() - Link Down handling
+ *
+ * Description: handles the hardware link down signal
+ *
+ * Returns: N/A
+ */
+void SkHWLinkDown(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Disable all MAC interrupts */
+	SkMacIrqDisable(pAC, IoC, Port);
+
+	/* Disable Receiver and Transmitter */
+	SkMacRxTxDisable(pAC, IoC, Port);
+	
+	/* Init default sense mode */
+	SkHWInitDefSense(pAC, IoC, Port);
+
+	if (pPrt->PHWLinkUp == SK_FALSE) {
+		return;
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+		("Link down Port %d\n", Port));
+
+	/* Set Link to DOWN */
+	pPrt->PHWLinkUp = SK_FALSE;
+
+	/* Reset Port stati */
+    pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN;
+    pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE;
+	pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_INDETERMINATED;
+
+	/* Re-init Phy especially when the AutoSense default is set now */
+	SkMacInitPhy(pAC, IoC, Port, SK_FALSE);
+
+	/* GP0: used for workaround of Rev. C Errata 2 */
+
+	/* Do NOT signal to RLMT */
+
+	/* Do NOT start the timer here */
+}	/* SkHWLinkDown */
+
+
+/******************************************************************************
+ *
+ *	SkHWLinkUp() - Link Up handling
+ *
+ * Description: handles the hardware link up signal
+ *
+ * Returns: N/A
+ */
+static void SkHWLinkUp(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PHWLinkUp) {
+		/* We do NOT need to proceed on active link */
+		return;
+	}
+
+	pPrt->PHWLinkUp = SK_TRUE;
+	pPrt->PAutoNegFail = SK_FALSE;
+    pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN;
+
+    if (pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOHALF &&
+        pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOFULL &&
+        pPrt->PLinkMode != (SK_U8)SK_LMODE_AUTOBOTH) {
+		/* Link is up and no Auto-negotiation should be done */
+
+		/* Link speed should be the configured one */
+		switch (pPrt->PLinkSpeed) {
+		case SK_LSPEED_AUTO:
+			/* default is 1000 Mbps */
+		case SK_LSPEED_1000MBPS:
+			pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS;
+			break;
+		case SK_LSPEED_100MBPS:
+			pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_100MBPS;
+			break;
+		case SK_LSPEED_10MBPS:
+			pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_10MBPS;
+			break;
+		}
+
+		/* Set Link Mode Status */
+		if (pPrt->PLinkMode == SK_LMODE_FULL) {
+			pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_FULL;
+		}
+		else {
+            pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_HALF;
+		}
+
+		/* No flow control without auto-negotiation */
+        pPrt->PFlowCtrlStatus = (SK_U8)SK_FLOW_STAT_NONE;
+
+		/* enable Rx/Tx */
+        (void)SkMacRxTxEnable(pAC, IoC, Port);
+	}
+}	/* SkHWLinkUp */
+
+
+/******************************************************************************
+ *
+ *	SkMacParity() - MAC parity workaround
+ *
+ * Description: handles MAC parity errors correctly
+ *
+ * Returns: N/A
+ */
+static void SkMacParity(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index of the port failed */
+{
+	SK_EVPARA	Para;
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	SK_U32		TxMax;		/* Tx Max Size Counter */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Clear IRQ Tx Parity Error */
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_PERR);
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		/* HW-Bug #8: cleared by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE */
+		SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T),
+			(SK_U8)((pAC->GIni.GIChipId == CHIP_ID_YUKON &&
+			pAC->GIni.GIChipRev == 0) ? GMF_CLI_TX_FC : GMF_CLI_TX_PE));
+	}
+#endif /* YUKON */
+	
+	if (pPrt->PCheckPar) {
+
+		if (Port == MAC_1) {
+			SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E016, SKERR_SIRQ_E016MSG);
+		}
+		else {
+			SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E017, SKERR_SIRQ_E017MSG);
+		}
+		Para.Para64 = Port;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		
+		Para.Para32[0] = Port;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+
+		return;
+	}
+
+	/* Check whether frames with a size of 1k were sent */
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+		/* Snap statistic counters */
+		(void)SkXmUpdateStats(pAC, IoC, Port);
+		
+		(void)SkXmMacStatistic(pAC, IoC, Port, XM_TXF_MAX_SZ, &TxMax);
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+
+		(void)SkGmMacStatistic(pAC, IoC, Port, GM_TXF_1518B, &TxMax);
+	}
+#endif /* YUKON */
+	
+	if (TxMax > 0) {
+		/* From now on check the parity */
+		pPrt->PCheckPar = SK_TRUE;
+	}
+}	/* SkMacParity */
+
+
+/******************************************************************************
+ *
+ *	SkGeHwErr() - Hardware Error service routine
+ *
+ * Description: handles all HW Error interrupts
+ *
+ * Returns: N/A
+ */
+static void SkGeHwErr(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+SK_U32	HwStatus)	/* Interrupt status word */
+{
+	SK_EVPARA	Para;
+	SK_U16		Word;
+
+	if ((HwStatus & (IS_IRQ_MST_ERR | IS_IRQ_STAT)) != 0) {
+		/* PCI Errors occured */
+		if ((HwStatus & IS_IRQ_STAT) != 0) {
+			SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E013, SKERR_SIRQ_E013MSG);
+		}
+		else {
+			SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E012, SKERR_SIRQ_E012MSG);
+		}
+
+		/* Reset all bits in the PCI STATUS register */
+		SK_IN16(IoC, PCI_C(PCI_STATUS), &Word);
+		
+		SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+        SK_OUT16(IoC, PCI_C(PCI_STATUS), (SK_U16)(Word | PCI_ERRBITS));
+		SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+		Para.Para64 = 0;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
+	}
+
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+
+		if ((HwStatus & IS_NO_STAT_M1) != 0) {
+			/* Ignore it */
+			/* This situation is also indicated in the descriptor */
+			SK_OUT16(IoC, MR_ADDR(MAC_1, RX_MFF_CTRL1), MFF_CLR_INSTAT);
+		}
+
+		if ((HwStatus & IS_NO_STAT_M2) != 0) {
+			/* Ignore it */
+			/* This situation is also indicated in the descriptor */
+			SK_OUT16(IoC, MR_ADDR(MAC_2, RX_MFF_CTRL1), MFF_CLR_INSTAT);
+		}
+
+		if ((HwStatus & IS_NO_TIST_M1) != 0) {
+			/* Ignore it */
+			/* This situation is also indicated in the descriptor */
+			SK_OUT16(IoC, MR_ADDR(MAC_1, RX_MFF_CTRL1), MFF_CLR_INTIST);
+		}
+
+		if ((HwStatus & IS_NO_TIST_M2) != 0) {
+			/* Ignore it */
+			/* This situation is also indicated in the descriptor */
+			SK_OUT16(IoC, MR_ADDR(MAC_2, RX_MFF_CTRL1), MFF_CLR_INTIST);
+		}
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		/* This is necessary only for Rx timing measurements */
+		if ((HwStatus & IS_IRQ_TIST_OV) != 0) {
+			/* increment Time Stamp Timer counter (high) */
+			pAC->GIni.GITimeStampCnt++;
+
+			/* Clear Time Stamp Timer IRQ */
+			SK_OUT8(IoC, GMAC_TI_ST_CTRL, (SK_U8)GMT_ST_CLR_IRQ);
+		}
+
+		if ((HwStatus & IS_IRQ_SENSOR) != 0) {
+			/* no sensors on 32-bit Yukon */
+			if (pAC->GIni.GIYukon32Bit) {
+				/* disable HW Error IRQ */
+				pAC->GIni.GIValIrqMask &= ~IS_HW_ERR;
+			}
+		}
+	}
+#endif /* YUKON */
+
+	if ((HwStatus & IS_RAM_RD_PAR) != 0) {
+		SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_RD_PERR);
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E014, SKERR_SIRQ_E014MSG);
+		Para.Para64 = 0;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
+	}
+
+	if ((HwStatus & IS_RAM_WR_PAR) != 0) {
+		SK_OUT16(IoC, B3_RI_CTRL, RI_CLR_WR_PERR);
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E015, SKERR_SIRQ_E015MSG);
+		Para.Para64 = 0;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_ADAP_FAIL, Para);
+	}
+
+	if ((HwStatus & IS_M1_PAR_ERR) != 0) {
+		SkMacParity(pAC, IoC, MAC_1);
+	}
+
+	if ((HwStatus & IS_M2_PAR_ERR) != 0) {
+		SkMacParity(pAC, IoC, MAC_2);
+	}
+
+	if ((HwStatus & IS_R1_PAR_ERR) != 0) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_P);
+
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E018, SKERR_SIRQ_E018MSG);
+		Para.Para64 = MAC_1;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		
+		Para.Para32[0] = MAC_1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+	if ((HwStatus & IS_R2_PAR_ERR) != 0) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_P);
+
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E019, SKERR_SIRQ_E019MSG);
+		Para.Para64 = MAC_2;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		
+		Para.Para32[0] = MAC_2;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+}	/* SkGeHwErr */
+
+
+/******************************************************************************
+ *
+ *	SkGeSirqIsr() - Special Interrupt Service Routine
+ *
+ * Description: handles all non data transfer specific interrupts (slow path)
+ *
+ * Returns: N/A
+ */
+void SkGeSirqIsr(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+SK_U32	Istatus)	/* Interrupt status word */
+{
+	SK_EVPARA	Para;
+	SK_U32		RegVal32;	/* Read register value */
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	SK_U16 		PhyInt;
+	int			i;
+
+	if (((Istatus & IS_HW_ERR) & pAC->GIni.GIValIrqMask) != 0) {
+		/* read the HW Error Interrupt source */
+		SK_IN32(IoC, B0_HWE_ISRC, &RegVal32);
+		
+		SkGeHwErr(pAC, IoC, RegVal32);
+	}
+
+	/*
+	 * Packet Timeout interrupts
+	 */
+	/* Check whether MACs are correctly initialized */
+	if (((Istatus & (IS_PA_TO_RX1 | IS_PA_TO_TX1)) != 0) &&
+		pAC->GIni.GP[MAC_1].PState == SK_PRT_RESET) {
+		/* MAC 1 was not initialized but Packet timeout occured */
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E004,
+			SKERR_SIRQ_E004MSG);
+	}
+
+	if (((Istatus & (IS_PA_TO_RX2 | IS_PA_TO_TX2)) != 0) &&
+	    pAC->GIni.GP[MAC_2].PState == SK_PRT_RESET) {
+		/* MAC 2 was not initialized but Packet timeout occured */
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E005,
+			SKERR_SIRQ_E005MSG);
+	}
+
+	if ((Istatus & IS_PA_TO_RX1) != 0) {
+		/* Means network is filling us up */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E002,
+			SKERR_SIRQ_E002MSG);
+		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX1);
+	}
+
+	if ((Istatus & IS_PA_TO_RX2) != 0) {
+		/* Means network is filling us up */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E003,
+			SKERR_SIRQ_E003MSG);
+		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_RX2);
+	}
+
+	if ((Istatus & IS_PA_TO_TX1) != 0) {
+		
+		pPrt = &pAC->GIni.GP[0];
+
+		/* May be a normal situation in a server with a slow network */
+		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX1);
+
+#ifdef GENESIS
+		if (pAC->GIni.GIGenesis) {
+			/*
+			 * workaround: if in half duplex mode, check for Tx hangup.
+			 * Read number of TX'ed bytes, wait for 10 ms, then compare
+			 * the number with current value. If nothing changed, we assume
+			 * that Tx is hanging and do a FIFO flush (see event routine).
+			 */
+			if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
+				pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) &&
+				!pPrt->HalfDupTimerActive) {
+				/*
+				 * many more pack. arb. timeouts may come in between,
+				 * we ignore those
+				 */
+				pPrt->HalfDupTimerActive = SK_TRUE;
+				/* Snap statistic counters */
+				(void)SkXmUpdateStats(pAC, IoC, 0);
+
+				(void)SkXmMacStatistic(pAC, IoC, 0, XM_TXO_OK_HI, &RegVal32);
+
+				pPrt->LastOctets = (SK_U64)RegVal32 << 32;
+				
+				(void)SkXmMacStatistic(pAC, IoC, 0, XM_TXO_OK_LO, &RegVal32);
+
+				pPrt->LastOctets += RegVal32;
+				
+				Para.Para32[0] = 0;
+				SkTimerStart(pAC, IoC, &pPrt->HalfDupChkTimer, SK_HALFDUP_CHK_TIME,
+					SKGE_HWAC, SK_HWEV_HALFDUP_CHK, Para);
+			}
+		}
+#endif /* GENESIS */
+	}
+
+	if ((Istatus & IS_PA_TO_TX2) != 0) {
+		
+		pPrt = &pAC->GIni.GP[1];
+
+		/* May be a normal situation in a server with a slow network */
+		SK_OUT16(IoC, B3_PA_CTRL, PA_CLR_TO_TX2);
+
+#ifdef GENESIS
+		if (pAC->GIni.GIGenesis) {
+			/* workaround: see above */
+			if ((pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
+				 pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) &&
+				!pPrt->HalfDupTimerActive) {
+				pPrt->HalfDupTimerActive = SK_TRUE;
+				/* Snap statistic counters */
+				(void)SkXmUpdateStats(pAC, IoC, 1);
+
+				(void)SkXmMacStatistic(pAC, IoC, 1, XM_TXO_OK_HI, &RegVal32);
+
+				pPrt->LastOctets = (SK_U64)RegVal32 << 32;
+				
+				(void)SkXmMacStatistic(pAC, IoC, 1, XM_TXO_OK_LO, &RegVal32);
+
+				pPrt->LastOctets += RegVal32;
+				
+				Para.Para32[0] = 1;
+				SkTimerStart(pAC, IoC, &pPrt->HalfDupChkTimer, SK_HALFDUP_CHK_TIME,
+					SKGE_HWAC, SK_HWEV_HALFDUP_CHK, Para);
+			}
+		}
+#endif /* GENESIS */
+	}
+
+	/* Check interrupts of the particular queues */
+	if ((Istatus & IS_R1_C) != 0) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_R1_CSR, CSR_IRQ_CL_C);
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E006,
+			SKERR_SIRQ_E006MSG);
+		Para.Para64 = MAC_1;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		Para.Para32[0] = MAC_1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+	if ((Istatus & IS_R2_C) != 0) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_R2_CSR, CSR_IRQ_CL_C);
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E007,
+			SKERR_SIRQ_E007MSG);
+		Para.Para64 = MAC_2;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		Para.Para32[0] = MAC_2;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+	if ((Istatus & IS_XS1_C) != 0) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_XS1_CSR, CSR_IRQ_CL_C);
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E008,
+			SKERR_SIRQ_E008MSG);
+		Para.Para64 = MAC_1;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		Para.Para32[0] = MAC_1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+	if ((Istatus & IS_XA1_C) != 0) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_XA1_CSR, CSR_IRQ_CL_C);
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E009,
+			SKERR_SIRQ_E009MSG);
+		Para.Para64 = MAC_1;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		Para.Para32[0] = MAC_1;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+	if ((Istatus & IS_XS2_C) != 0) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_XS2_CSR, CSR_IRQ_CL_C);
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E010,
+			SKERR_SIRQ_E010MSG);
+		Para.Para64 = MAC_2;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		Para.Para32[0] = MAC_2;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+	if ((Istatus & IS_XA2_C) != 0) {
+		/* Clear IRQ */
+		SK_OUT32(IoC, B0_XA2_CSR, CSR_IRQ_CL_C);
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_SIRQ_E011,
+			SKERR_SIRQ_E011MSG);
+		Para.Para64 = MAC_2;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_FAIL, Para);
+		Para.Para32[0] = MAC_2;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+	/* External reg interrupt */
+	if ((Istatus & IS_EXT_REG) != 0) {
+		/* Test IRQs from PHY */
+		for (i = 0; i < pAC->GIni.GIMacsFound; i++) {
+			
+			pPrt = &pAC->GIni.GP[i];
+			
+			if (pPrt->PState == SK_PRT_RESET) {
+				continue;
+			}
+			
+#ifdef GENESIS
+			if (pAC->GIni.GIGenesis) {
+				
+				switch (pPrt->PhyType) {
+				
+				case SK_PHY_XMAC:
+					break;
+				
+				case SK_PHY_BCOM:
+					SkXmPhyRead(pAC, IoC, i, PHY_BCOM_INT_STAT, &PhyInt);
+	
+					if ((PhyInt & ~PHY_B_DEF_MSK) != 0) {
+						SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+							("Port %d Bcom Int: 0x%04X\n",
+							i, PhyInt));
+						SkPhyIsrBcom(pAC, IoC, i, PhyInt);
+					}
+					break;
+#ifdef OTHER_PHY
+				case SK_PHY_LONE:
+					SkXmPhyRead(pAC, IoC, i, PHY_LONE_INT_STAT, &PhyInt);
+					
+					if ((PhyInt & PHY_L_DEF_MSK) != 0) {
+						SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+							("Port %d Lone Int: %x\n",
+							i, PhyInt));
+						SkPhyIsrLone(pAC, IoC, i, PhyInt);
+					}
+					break;
+#endif /* OTHER_PHY */
+				}
+			}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+			if (pAC->GIni.GIYukon) {
+				/* Read PHY Interrupt Status */
+				SkGmPhyRead(pAC, IoC, i, PHY_MARV_INT_STAT, &PhyInt);
+
+				if ((PhyInt & PHY_M_DEF_MSK) != 0) {
+					SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+						("Port %d Marv Int: 0x%04X\n",
+						i, PhyInt));
+					SkPhyIsrGmac(pAC, IoC, i, PhyInt);
+				}
+			}
+#endif /* YUKON */
+		}
+	}
+
+	/* I2C Ready interrupt */
+	if ((Istatus & IS_I2C_READY) != 0) {
+#ifdef SK_SLIM
+        SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
+#else		
+		SkI2cIsr(pAC, IoC);
+#endif		
+	}
+
+	/* SW forced interrupt */
+	if ((Istatus & IS_IRQ_SW) != 0) {
+		/* clear the software IRQ */
+		SK_OUT8(IoC, B0_CTST, CS_CL_SW_IRQ);
+	}
+
+	if ((Istatus & IS_LNK_SYNC_M1) != 0) {
+		/*
+		 * We do NOT need the Link Sync interrupt, because it shows
+		 * us only a link going down.
+		 */
+		/* clear interrupt */
+		SK_OUT8(IoC, MR_ADDR(MAC_1, LNK_SYNC_CTRL), LED_CLR_IRQ);
+	}
+
+	/* Check MAC after link sync counter */
+	if ((Istatus & IS_MAC1) != 0) {
+		/* IRQ from MAC 1 */
+		SkMacIrq(pAC, IoC, MAC_1);
+	}
+
+	if ((Istatus & IS_LNK_SYNC_M2) != 0) {
+		/*
+		 * We do NOT need the Link Sync interrupt, because it shows
+		 * us only a link going down.
+		 */
+		/* clear interrupt */
+		SK_OUT8(IoC, MR_ADDR(MAC_2, LNK_SYNC_CTRL), LED_CLR_IRQ);
+	}
+
+	/* Check MAC after link sync counter */
+	if ((Istatus & IS_MAC2) != 0) {
+		/* IRQ from MAC 2 */
+		SkMacIrq(pAC, IoC, MAC_2);
+	}
+
+	/* Timer interrupt (served last) */
+	if ((Istatus & IS_TIMINT) != 0) {
+		/* check for HW Errors */
+		if (((Istatus & IS_HW_ERR) & ~pAC->GIni.GIValIrqMask) != 0) {
+			/* read the HW Error Interrupt source */
+			SK_IN32(IoC, B0_HWE_ISRC, &RegVal32);
+
+			SkGeHwErr(pAC, IoC, RegVal32);
+		}
+
+		SkHwtIsr(pAC, IoC);
+	}
+
+}	/* SkGeSirqIsr */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkGePortCheckShorts() - Implementing XMAC Workaround Errata # 2
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ */
+static int SkGePortCheckShorts(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO Context */
+int		Port)		/* Which port should be checked */
+{
+	SK_U32		Shorts;			/* Short Event Counter */
+	SK_U32		CheckShorts;	/* Check value for Short Event Counter */
+	SK_U64		RxCts;			/* Rx Counter (packets on network) */
+	SK_U32		RxTmp;			/* Rx temp. Counter */
+	SK_U32		FcsErrCts;		/* FCS Error Counter */
+	SK_GEPORT	*pPrt;			/* GIni Port struct pointer */
+	int			Rtv;			/* Return value */
+	int			i;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Default: no action */
+	Rtv = SK_HW_PS_NONE;
+
+	(void)SkXmUpdateStats(pAC, IoC, Port);
+
+	/* Extra precaution: check for short Event counter */
+	(void)SkXmMacStatistic(pAC, IoC, Port, XM_RXE_SHT_ERR, &Shorts);
+
+	/*
+	 * Read Rx counters (packets seen on the network and not necessarily
+	 * really received.
+	 */
+	RxCts = 0;
+
+	for (i = 0; i < sizeof(SkGeRxRegs)/sizeof(SkGeRxRegs[0]); i++) {
+		
+		(void)SkXmMacStatistic(pAC, IoC, Port, SkGeRxRegs[i], &RxTmp);
+		
+		RxCts += (SK_U64)RxTmp;
+	}
+
+	/* On default: check shorts against zero */
+	CheckShorts = 0;
+
+	/* Extra precaution on active links */
+	if (pPrt->PHWLinkUp) {
+		/* Reset Link Restart counter */
+		pPrt->PLinkResCt = 0;
+		pPrt->PAutoNegTOCt = 0;
+
+		/* If link is up check for 2 */
+		CheckShorts = 2;
+
+		(void)SkXmMacStatistic(pAC, IoC, Port, XM_RXF_FCS_ERR, &FcsErrCts);
+		
+		if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+		    pPrt->PLipaAutoNeg == SK_LIPA_UNKNOWN &&
+		    (pPrt->PLinkMode == SK_LMODE_HALF ||
+			 pPrt->PLinkMode == SK_LMODE_FULL)) {
+			/*
+			 * This is autosensing and we are in the fallback
+			 * manual full/half duplex mode.
+			 */
+			if (RxCts == pPrt->PPrevRx) {
+				/* Nothing received, restart link */
+				pPrt->PPrevFcs = FcsErrCts;
+				pPrt->PPrevShorts = Shorts;
+				
+				return(SK_HW_PS_RESTART);
+			}
+			else {
+				pPrt->PLipaAutoNeg = SK_LIPA_MANUAL;
+			}
+		}
+
+		if (((RxCts - pPrt->PPrevRx) > pPrt->PRxLim) ||
+		    (!(FcsErrCts - pPrt->PPrevFcs))) {
+			/*
+			 * Note: The compare with zero above has to be done the way shown,
+			 * otherwise the Linux driver will have a problem.
+			 */
+			/*
+			 * We received a bunch of frames or no CRC error occured on the
+			 * network -> ok.
+			 */
+			pPrt->PPrevRx = RxCts;
+			pPrt->PPrevFcs = FcsErrCts;
+			pPrt->PPrevShorts = Shorts;
+
+			return(SK_HW_PS_NONE);
+		}
+
+		pPrt->PPrevFcs = FcsErrCts;
+	}
+
+
+	if ((Shorts - pPrt->PPrevShorts) > CheckShorts) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+			("Short Event Count Restart Port %d \n", Port));
+		Rtv = SK_HW_PS_RESTART;
+	}
+
+	pPrt->PPrevShorts = Shorts;
+	pPrt->PPrevRx = RxCts;
+
+	return(Rtv);
+}	/* SkGePortCheckShorts */
+#endif /* GENESIS */
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckUp() - Check if the link is up
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ *	2	Link came up
+ */
+static int SkGePortCheckUp(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO Context */
+int		Port)		/* Which port should be checked */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	SK_BOOL		AutoNeg;	/* Is Auto-negotiation used ? */
+	int			Rtv;		/* Return value */
+
+	Rtv = SK_HW_PS_NONE;
+	
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+		AutoNeg = SK_FALSE;
+	}
+	else {
+		AutoNeg = SK_TRUE;
+	}
+
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+
+		switch (pPrt->PhyType) {
+		
+		case SK_PHY_XMAC:
+			Rtv = SkGePortCheckUpXmac(pAC, IoC, Port, AutoNeg);
+			break;
+		case SK_PHY_BCOM:
+			Rtv = SkGePortCheckUpBcom(pAC, IoC, Port, AutoNeg);
+			break;
+#ifdef OTHER_PHY
+		case SK_PHY_LONE:
+			Rtv = SkGePortCheckUpLone(pAC, IoC, Port, AutoNeg);
+			break;
+		case SK_PHY_NAT:
+			Rtv = SkGePortCheckUpNat(pAC, IoC, Port, AutoNeg);
+			break;
+#endif /* OTHER_PHY */
+		}
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		
+		Rtv = SkGePortCheckUpGmac(pAC, IoC, Port, AutoNeg);
+	}
+#endif /* YUKON */
+
+	return(Rtv);	
+}	/* SkGePortCheckUp */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ * SkGePortCheckUpXmac() - Implementing of the Workaround Errata # 2
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ *	2	Link came up
+ */
+static int SkGePortCheckUpXmac(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO Context */
+int		Port,		/* Which port should be checked */
+SK_BOOL	AutoNeg)	/* Is Auto-negotiation used ? */
+{
+	SK_U32		Shorts;		/* Short Event Counter */
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	int			Done;
+	SK_U32		GpReg;		/* General Purpose register value */
+	SK_U16		Isrc;		/* Interrupt source register */
+	SK_U16		IsrcSum;	/* Interrupt source register sum */
+	SK_U16		LpAb;		/* Link Partner Ability */
+	SK_U16		ResAb;		/* Resolved Ability */
+	SK_U16		ExtStat;	/* Extended Status Register */
+	SK_U8		NextMode;	/* Next AutoSensing Mode */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PHWLinkUp) {
+		if (pPrt->PhyType != SK_PHY_XMAC) {
+			return(SK_HW_PS_NONE);
+		}
+		else {
+			return(SkGePortCheckShorts(pAC, IoC, Port));
+		}
+	}
+
+	IsrcSum = pPrt->PIsave;
+	pPrt->PIsave = 0;
+
+	/* Now wait for each port's link */
+	if (pPrt->PLinkBroken) {
+		/* Link was broken */
+		XM_IN32(IoC, Port, XM_GP_PORT, &GpReg);
+
+		if ((GpReg & XM_GP_INP_ASS) == 0) {
+			/* The Link is in sync */
+			XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+			IsrcSum |= Isrc;
+			SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum);
+			
+			if ((Isrc & XM_IS_INP_ASS) == 0) {
+				/* It has been in sync since last time */
+				/* Restart the PORT */
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+					("Link in sync Restart Port %d\n", Port));
+
+				(void)SkXmUpdateStats(pAC, IoC, Port);
+
+				/* We now need to reinitialize the PrevShorts counter */
+				(void)SkXmMacStatistic(pAC, IoC, Port, XM_RXE_SHT_ERR, &Shorts);
+				pPrt->PPrevShorts = Shorts;
+
+				pPrt->PLinkBroken = SK_FALSE;
+
+				/*
+				 * Link Restart Workaround:
+				 *  it may be possible that the other Link side
+				 *  restarts its link as well an we detect
+				 *  another LinkBroken. To prevent this
+				 *  happening we check for a maximum number
+				 *  of consecutive restart. If those happens,
+				 *  we do NOT restart the active link and
+				 *  check whether the link is now o.k.
+				 */
+				pPrt->PLinkResCt++;
+				
+				pPrt->PAutoNegTimeOut = 0;
+
+				if (pPrt->PLinkResCt < SK_MAX_LRESTART) {
+					return(SK_HW_PS_RESTART);
+				}
+
+				pPrt->PLinkResCt = 0;
+				
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+					("Do NOT restart on Port %d %x %x\n", Port, Isrc, IsrcSum));
+			}
+			else {
+				pPrt->PIsave = (SK_U16)(IsrcSum & XM_IS_AND);
+				
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+					("Save Sync/nosync Port %d %x %x\n", Port, Isrc, IsrcSum));
+
+				/* Do nothing more if link is broken */
+				return(SK_HW_PS_NONE);
+			}
+		}
+		else {
+			/* Do nothing more if link is broken */
+			return(SK_HW_PS_NONE);
+		}
+
+	}
+	else {
+		/* Link was not broken, check if it is */
+		XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+		IsrcSum |= Isrc;
+		if ((Isrc & XM_IS_INP_ASS) != 0) {
+			XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+			IsrcSum |= Isrc;
+			if ((Isrc & XM_IS_INP_ASS) != 0) {
+				XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+				IsrcSum |= Isrc;
+				if ((Isrc & XM_IS_INP_ASS) != 0) {
+					pPrt->PLinkBroken = SK_TRUE;
+					/* Re-Init Link partner Autoneg flag */
+					pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN;
+					SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+						("Link broken Port %d\n", Port));
+
+					/* Cable removed-> reinit sense mode */
+					SkHWInitDefSense(pAC, IoC, Port);
+
+					return(SK_HW_PS_RESTART);
+				}
+			}
+		}
+		else {
+			SkXmAutoNegLipaXmac(pAC, IoC, Port, Isrc);
+			
+			if (SkGePortCheckShorts(pAC, IoC, Port) == SK_HW_PS_RESTART) {
+				return(SK_HW_PS_RESTART);
+			}
+		}
+	}
+
+	/*
+	 * here we usually can check whether the link is in sync and
+	 * auto-negotiation is done.
+	 */
+	XM_IN32(IoC, Port, XM_GP_PORT, &GpReg);
+	XM_IN16(IoC, Port, XM_ISRC, &Isrc);
+	IsrcSum |= Isrc;
+
+	SkXmAutoNegLipaXmac(pAC, IoC, Port, IsrcSum);
+	
+	if ((GpReg & XM_GP_INP_ASS) != 0 || (IsrcSum & XM_IS_INP_ASS) != 0) {
+		if ((GpReg & XM_GP_INP_ASS) == 0) {
+			/* Save Auto-negotiation Done interrupt only if link is in sync */
+			pPrt->PIsave = (SK_U16)(IsrcSum & XM_IS_AND);
+		}
+#ifdef DEBUG
+		if ((pPrt->PIsave & XM_IS_AND) != 0) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("AutoNeg done rescheduled Port %d\n", Port));
+		}
+#endif /* DEBUG */
+		return(SK_HW_PS_NONE);
+	}
+
+	if (AutoNeg) {
+		if ((IsrcSum & XM_IS_AND) != 0) {
+			SkHWLinkUp(pAC, IoC, Port);
+			Done = SkMacAutoNegDone(pAC, IoC, Port);
+			if (Done != SK_AND_OK) {
+				/* Get PHY parameters, for debugging only */
+				SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_LP, &LpAb);
+				SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_RES_ABI, &ResAb);
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+					("AutoNeg FAIL Port %d (LpAb %x, ResAb %x)\n",
+					 Port, LpAb, ResAb));
+					
+				/* Try next possible mode */
+				NextMode = SkHWSenseGetNext(pAC, IoC, Port);
+				SkHWLinkDown(pAC, IoC, Port);
+				if (Done == SK_AND_DUP_CAP) {
+					/* GoTo next mode */
+					SkHWSenseSetNext(pAC, IoC, Port, NextMode);
+				}
+
+				return(SK_HW_PS_RESTART);
+			}
+			/*
+			 * Dummy Read extended status to prevent extra link down/ups
+			 * (clear Page Received bit if set)
+			 */
+			SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_EXP, &ExtStat);
+			
+			return(SK_HW_PS_LINK);
+		}
+		
+		/* AutoNeg not done, but HW link is up. Check for timeouts */
+		pPrt->PAutoNegTimeOut++;
+		if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
+			/* Increase the Timeout counter */
+			pPrt->PAutoNegTOCt++;
+
+			/* Timeout occured */
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+				("AutoNeg timeout Port %d\n", Port));
+			if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+				pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
+				/* Set Link manually up */
+				SkHWSenseSetNext(pAC, IoC, Port, SK_LMODE_FULL);
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+					("Set manual full duplex Port %d\n", Port));
+			}
+
+			if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+				pPrt->PLipaAutoNeg == SK_LIPA_AUTO &&
+				pPrt->PAutoNegTOCt >= SK_MAX_ANEG_TO) {
+				/*
+				 * This is rather complicated.
+				 * we need to check here whether the LIPA_AUTO
+				 * we saw before is false alert. We saw at one
+				 * switch ( SR8800) that on boot time it sends
+				 * just one auto-neg packet and does no further
+				 * auto-negotiation.
+				 * Solution: we restart the autosensing after
+				 * a few timeouts.
+				 */
+				pPrt->PAutoNegTOCt = 0;
+				pPrt->PLipaAutoNeg = SK_LIPA_UNKNOWN;
+				SkHWInitDefSense(pAC, IoC, Port);
+			}
+
+			/* Do the restart */
+			return(SK_HW_PS_RESTART);
+		}
+	}
+	else {
+		/* Link is up and we don't need more */
+#ifdef DEBUG
+		if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("ERROR: Lipa auto detected on port %d\n", Port));
+		}
+#endif /* DEBUG */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+			("Link sync(GP), Port %d\n", Port));
+		SkHWLinkUp(pAC, IoC, Port);
+		
+		/*
+		 * Link sync (GP) and so assume a good connection. But if not received
+		 * a bunch of frames received in a time slot (maybe broken tx cable)
+		 * the port is restart.
+		 */
+		return(SK_HW_PS_LINK);
+	}
+
+	return(SK_HW_PS_NONE);
+}	/* SkGePortCheckUpXmac */
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckUpBcom() - Check if the link is up on Bcom PHY
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ *	2	Link came up
+ */
+static int SkGePortCheckUpBcom(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO Context */
+int		Port,		/* Which port should be checked */
+SK_BOOL	AutoNeg)	/* Is Auto-negotiation used ? */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	int			Done;
+	SK_U16		Isrc;		/* Interrupt source register */
+	SK_U16		PhyStat;	/* Phy Status Register */
+	SK_U16		ResAb;		/* Master/Slave resolution */
+	SK_U16		Ctrl;		/* Broadcom control flags */
+#ifdef DEBUG
+	SK_U16		LpAb;
+	SK_U16		ExtStat;
+#endif /* DEBUG */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Check for No HCD Link events (#10523) */
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &Isrc);
+
+#ifdef xDEBUG
+	if ((Isrc & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) ==
+		(PHY_B_IS_SCR_S_ER | PHY_B_IS_RRS_CHANGE | PHY_B_IS_LRS_CHANGE)) {
+
+		SK_U32	Stat1, Stat2, Stat3;
+
+		Stat1 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_MASK, &Stat1);
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"CheckUp1 - Stat: %x, Mask: %x",
+			(void *)Isrc,
+			(void *)Stat1);
+
+		Stat1 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Stat1);
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &Stat2);
+		Stat1 = Stat1 << 16 | Stat2;
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, &Stat2);
+		Stat3 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &Stat3);
+		Stat2 = Stat2 << 16 | Stat3;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"Ctrl/Stat: %x, AN Adv/LP: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+
+		Stat1 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_EXP, &Stat1);
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_EXT_STAT, &Stat2);
+		Stat1 = Stat1 << 16 | Stat2;
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, &Stat2);
+		Stat3 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &Stat3);
+		Stat2 = Stat2 << 16 | Stat3;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"AN Exp/IEEE Ext: %x, 1000T Ctrl/Stat: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+
+		Stat1 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, &Stat1);
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_STAT, &Stat2);
+		Stat1 = Stat1 << 16 | Stat2;
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Stat2);
+		Stat3 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &Stat3);
+		Stat2 = Stat2 << 16 | Stat3;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"PHY Ext Ctrl/Stat: %x, Aux Ctrl/Stat: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+	}
+#endif /* DEBUG */
+
+	if ((Isrc & (PHY_B_IS_NO_HDCL /* | PHY_B_IS_NO_HDC */)) != 0) {
+		/*
+		 * Workaround BCom Errata:
+		 *	enable and disable loopback mode if "NO HCD" occurs.
+		 */
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Ctrl);
+		SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL,
+			(SK_U16)(Ctrl | PHY_CT_LOOP));
+		SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL,
+			(SK_U16)(Ctrl & ~PHY_CT_LOOP));
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("No HCD Link event, Port %d\n", Port));
+#ifdef xDEBUG
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"No HCD link event, port %d.",
+			(void *)Port,
+			(void *)NULL);
+#endif /* DEBUG */
+	}
+
+	/* Not obsolete: link status bit is latched to 0 and autoclearing! */
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
+
+	if (pPrt->PHWLinkUp) {
+		return(SK_HW_PS_NONE);
+	}
+
+#ifdef xDEBUG
+	{
+		SK_U32	Stat1, Stat2, Stat3;
+
+		Stat1 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_MASK, &Stat1);
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"CheckUp1a - Stat: %x, Mask: %x",
+			(void *)Isrc,
+			(void *)Stat1);
+
+		Stat1 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_CTRL, &Stat1);
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
+		Stat1 = Stat1 << 16 | PhyStat;
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, &Stat2);
+		Stat3 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &Stat3);
+		Stat2 = Stat2 << 16 | Stat3;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"Ctrl/Stat: %x, AN Adv/LP: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+
+		Stat1 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_EXP, &Stat1);
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_EXT_STAT, &Stat2);
+		Stat1 = Stat1 << 16 | Stat2;
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, &Stat2);
+		Stat3 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
+		Stat2 = Stat2 << 16 | ResAb;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"AN Exp/IEEE Ext: %x, 1000T Ctrl/Stat: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+
+		Stat1 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, &Stat1);
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_P_EXT_STAT, &Stat2);
+		Stat1 = Stat1 << 16 | Stat2;
+		Stat2 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Stat2);
+		Stat3 = 0;
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &Stat3);
+		Stat2 = Stat2 << 16 | Stat3;
+		CMSMPrintString(
+			pAC->pConfigTable,
+			MSG_TYPE_RUNTIME_INFO,
+			"PHY Ext Ctrl/Stat: %x, Aux Ctrl/Stat: %x",
+			(void *)Stat1,
+			(void *)Stat2);
+	}
+#endif /* DEBUG */
+
+	/*
+	 * Here we usually can check whether the link is in sync and
+	 * auto-negotiation is done.
+	 */
+
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_STAT, &PhyStat);
+
+	SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
+	
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("CheckUp Port %d, PhyStat: 0x%04X\n", Port, PhyStat));
+
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
+
+	if ((ResAb & PHY_B_1000S_MSF) != 0) {
+		/* Error */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("Master/Slave Fault port %d\n", Port));
+		
+		pPrt->PAutoNegFail = SK_TRUE;
+		pPrt->PMSStatus = SK_MS_STAT_FAULT;
+		
+		return(SK_HW_PS_RESTART);
+	}
+
+	if ((PhyStat & PHY_ST_LSYNC) == 0) {
+		return(SK_HW_PS_NONE);
+	}
+	
+	pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+		SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
+	
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Port %d, ResAb: 0x%04X\n", Port, ResAb));
+
+	if (AutoNeg) {
+		if ((PhyStat & PHY_ST_AN_OVER) != 0) {
+			
+			SkHWLinkUp(pAC, IoC, Port);
+			
+			Done = SkMacAutoNegDone(pAC, IoC, Port);
+			
+			if (Done != SK_AND_OK) {
+#ifdef DEBUG
+				/* Get PHY parameters, for debugging only */
+				SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &LpAb);
+				SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ExtStat);
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+					("AutoNeg FAIL Port %d (LpAb %x, 1000TStat %x)\n",
+					Port, LpAb, ExtStat));
+#endif /* DEBUG */
+				return(SK_HW_PS_RESTART);
+			}
+			else {
+#ifdef xDEBUG
+				/* Dummy read ISR to prevent extra link downs/ups */
+				SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &ExtStat);
+
+				if ((ExtStat & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) != 0) {
+					CMSMPrintString(
+						pAC->pConfigTable,
+						MSG_TYPE_RUNTIME_INFO,
+						"CheckUp2 - Stat: %x",
+						(void *)ExtStat,
+						(void *)NULL);
+				}
+#endif /* DEBUG */
+				return(SK_HW_PS_LINK);
+			}
+		}
+	}
+	else {	/* !AutoNeg */
+		/* Link is up and we don't need more. */
+#ifdef DEBUG
+		if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("ERROR: Lipa auto detected on port %d\n", Port));
+		}
+#endif /* DEBUG */
+
+#ifdef xDEBUG
+		/* Dummy read ISR to prevent extra link downs/ups */
+		SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_INT_STAT, &ExtStat);
+
+		if ((ExtStat & ~(PHY_B_IS_HCT | PHY_B_IS_LCT)) != 0) {
+			CMSMPrintString(
+				pAC->pConfigTable,
+				MSG_TYPE_RUNTIME_INFO,
+				"CheckUp3 - Stat: %x",
+				(void *)ExtStat,
+				(void *)NULL);
+		}
+#endif /* DEBUG */
+		
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+			("Link sync(GP), Port %d\n", Port));
+		SkHWLinkUp(pAC, IoC, Port);
+		
+		return(SK_HW_PS_LINK);
+	}
+
+	return(SK_HW_PS_NONE);
+}	/* SkGePortCheckUpBcom */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ * SkGePortCheckUpGmac() - Check if the link is up on Marvell PHY
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ *	2	Link came up
+ */
+static int SkGePortCheckUpGmac(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO Context */
+int		Port,		/* Which port should be checked */
+SK_BOOL	AutoNeg)	/* Is Auto-negotiation used ? */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	int			Done;
+	SK_U16		PhyIsrc;	/* PHY Interrupt source */
+	SK_U16		PhyStat;	/* PPY Status */
+	SK_U16		PhySpecStat;/* PHY Specific Status */
+	SK_U16		ResAb;		/* Master/Slave resolution */
+	SK_EVPARA	Para;
+#ifdef DEBUG
+	SK_U16		Word;		/* I/O helper */
+#endif /* DEBUG */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PHWLinkUp) {
+		return(SK_HW_PS_NONE);
+	}
+
+	/* Read PHY Status */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat);
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("CheckUp Port %d, PhyStat: 0x%04X\n", Port, PhyStat));
+
+	/* Read PHY Interrupt Status */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_INT_STAT, &PhyIsrc);
+
+	if ((PhyIsrc & PHY_M_IS_AN_COMPL) != 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("Auto-Negotiation Completed, PhyIsrc: 0x%04X\n", PhyIsrc));
+	}
+
+	if ((PhyIsrc & PHY_M_IS_LSP_CHANGE) != 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("Link Speed Changed, PhyIsrc: 0x%04X\n", PhyIsrc));
+	}
+
+	SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
+	
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_STAT, &ResAb);
+
+	if ((ResAb & PHY_B_1000S_MSF) != 0) {
+		/* Error */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("Master/Slave Fault port %d\n", Port));
+		
+		pPrt->PAutoNegFail = SK_TRUE;
+		pPrt->PMSStatus = SK_MS_STAT_FAULT;
+		
+		return(SK_HW_PS_RESTART);
+	}
+
+	/* Read PHY Specific Status */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &PhySpecStat);
+	
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Phy1000BT: 0x%04X, PhySpecStat: 0x%04X\n", ResAb, PhySpecStat));
+
+#ifdef DEBUG
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_EXP, &Word);
+
+	if ((PhyIsrc & PHY_M_IS_AN_PR) != 0 || (Word & PHY_ANE_RX_PG) != 0 ||
+		(PhySpecStat & PHY_M_PS_PAGE_REC) != 0)  {
+		/* Read PHY Next Page Link Partner */
+		SkGmPhyRead(pAC, IoC, Port, PHY_MARV_NEPG_LP, &Word);
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("Page Received, NextPage: 0x%04X\n", Word));
+	}
+#endif /* DEBUG */
+
+	if ((PhySpecStat & PHY_M_PS_LINK_UP) == 0) {
+		return(SK_HW_PS_NONE);
+	}
+	
+	if ((PhySpecStat & PHY_M_PS_DOWNS_STAT) != 0 ||
+		(PhyIsrc & PHY_M_IS_DOWNSH_DET) != 0) {
+		/* Downshift detected */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E025, SKERR_SIRQ_E025MSG);
+		
+		Para.Para64 = Port;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_DOWNSHIFT_DET, Para);
+		
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("Downshift detected, PhyIsrc: 0x%04X\n", PhyIsrc));
+	}
+
+	pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+		SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
+	
+	pPrt->PCableLen = (SK_U8)((PhySpecStat & PHY_M_PS_CABLE_MSK) >> 7);
+	
+	if (AutoNeg) {
+		/* Auto-Negotiation Over ? */
+		if ((PhyStat & PHY_ST_AN_OVER) != 0) {
+			
+			SkHWLinkUp(pAC, IoC, Port);
+			
+			Done = SkMacAutoNegDone(pAC, IoC, Port);
+			
+			if (Done != SK_AND_OK) {
+				return(SK_HW_PS_RESTART);
+			}
+			
+			return(SK_HW_PS_LINK);
+		}
+	}
+	else {	/* !AutoNeg */
+		/* Link is up and we don't need more */
+#ifdef DEBUG
+		if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("ERROR: Lipa auto detected on port %d\n", Port));
+		}
+#endif /* DEBUG */
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+			("Link sync, Port %d\n", Port));
+		SkHWLinkUp(pAC, IoC, Port);
+		
+		return(SK_HW_PS_LINK);
+	}
+
+	return(SK_HW_PS_NONE);
+}	/* SkGePortCheckUpGmac */
+#endif /* YUKON */
+
+
+#ifdef OTHER_PHY
+/******************************************************************************
+ *
+ * SkGePortCheckUpLone() - Check if the link is up on Level One PHY
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ *	2	Link came up
+ */
+static int SkGePortCheckUpLone(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO Context */
+int		Port,		/* Which port should be checked */
+SK_BOOL	AutoNeg)	/* Is Auto-negotiation used ? */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	int			Done;
+	SK_U16		Isrc;		/* Interrupt source register */
+	SK_U16		LpAb;		/* Link Partner Ability */
+	SK_U16		ExtStat;	/* Extended Status Register */
+	SK_U16		PhyStat;	/* Phy Status Register */
+	SK_U16		StatSum;
+	SK_U8		NextMode;	/* Next AutoSensing Mode */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PHWLinkUp) {
+		return(SK_HW_PS_NONE);
+	}
+
+	StatSum = pPrt->PIsave;
+	pPrt->PIsave = 0;
+
+	/*
+	 * here we usually can check whether the link is in sync and
+	 * auto-negotiation is done.
+	 */
+	SkXmPhyRead(pAC, IoC, Port, PHY_LONE_STAT, &PhyStat);
+	StatSum |= PhyStat;
+
+	SkMacAutoNegLipaPhy(pAC, IoC, Port, PhyStat);
+	
+	if ((PhyStat & PHY_ST_LSYNC) == 0) {
+		/* Save Auto-negotiation Done bit */
+		pPrt->PIsave = (SK_U16)(StatSum & PHY_ST_AN_OVER);
+#ifdef DEBUG
+		if ((pPrt->PIsave & PHY_ST_AN_OVER) != 0) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("AutoNeg done rescheduled Port %d\n", Port));
+		}
+#endif /* DEBUG */
+		return(SK_HW_PS_NONE);
+	}
+
+	if (AutoNeg) {
+		if ((StatSum & PHY_ST_AN_OVER) != 0) {
+			SkHWLinkUp(pAC, IoC, Port);
+			Done = SkMacAutoNegDone(pAC, IoC, Port);
+			if (Done != SK_AND_OK) {
+				/* Get PHY parameters, for debugging only */
+				SkXmPhyRead(pAC, IoC, Port, PHY_LONE_AUNE_LP, &LpAb);
+				SkXmPhyRead(pAC, IoC, Port, PHY_LONE_1000T_STAT, &ExtStat);
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+					("AutoNeg FAIL Port %d (LpAb %x, 1000TStat %x)\n",
+					 Port, LpAb, ExtStat));
+					
+				/* Try next possible mode */
+				NextMode = SkHWSenseGetNext(pAC, IoC, Port);
+				SkHWLinkDown(pAC, IoC, Port);
+				if (Done == SK_AND_DUP_CAP) {
+					/* GoTo next mode */
+					SkHWSenseSetNext(pAC, IoC, Port, NextMode);
+				}
+
+				return(SK_HW_PS_RESTART);
+
+			}
+			else {
+				/*
+				 * Dummy Read interrupt status to prevent
+				 * extra link down/ups
+				 */
+				SkXmPhyRead(pAC, IoC, Port, PHY_LONE_INT_STAT, &ExtStat);
+				return(SK_HW_PS_LINK);
+			}
+		}
+		
+		/* AutoNeg not done, but HW link is up. Check for timeouts */
+		pPrt->PAutoNegTimeOut++;
+		if (pPrt->PAutoNegTimeOut >= SK_AND_MAX_TO) {
+			/* Timeout occured */
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+				("AutoNeg timeout Port %d\n", Port));
+			if (pPrt->PLinkModeConf == SK_LMODE_AUTOSENSE &&
+				pPrt->PLipaAutoNeg != SK_LIPA_AUTO) {
+				/* Set Link manually up */
+				SkHWSenseSetNext(pAC, IoC, Port, SK_LMODE_FULL);
+				SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+					("Set manual full duplex Port %d\n", Port));
+			}
+
+			/* Do the restart */
+			return(SK_HW_PS_RESTART);
+		}
+	}
+	else {
+		/* Link is up and we don't need more */
+#ifdef DEBUG
+		if (pPrt->PLipaAutoNeg == SK_LIPA_AUTO) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+				("ERROR: Lipa auto detected on port %d\n", Port));
+		}
+#endif /* DEBUG */
+
+		/*
+		 * Dummy Read interrupt status to prevent
+		 * extra link down/ups
+		 */
+		SkXmPhyRead(pAC, IoC, Port, PHY_LONE_INT_STAT, &ExtStat);
+		
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+			("Link sync(GP), Port %d\n", Port));
+		SkHWLinkUp(pAC, IoC, Port);
+		
+		return(SK_HW_PS_LINK);
+	}
+
+	return(SK_HW_PS_NONE);
+}	/* SkGePortCheckUpLone */
+
+
+/******************************************************************************
+ *
+ * SkGePortCheckUpNat() - Check if the link is up on National PHY
+ *
+ * return:
+ *	0	o.k. nothing needed
+ *	1	Restart needed on this port
+ *	2	Link came up
+ */
+static int SkGePortCheckUpNat(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO Context */
+int		Port,		/* Which port should be checked */
+SK_BOOL	AutoNeg)	/* Is Auto-negotiation used ? */
+{
+	/* todo: National */
+	return(SK_HW_PS_NONE);
+}	/* SkGePortCheckUpNat */
+#endif /* OTHER_PHY */
+
+
+/******************************************************************************
+ *
+ *	SkGeSirqEvent() - Event Service Routine
+ *
+ * Description:
+ *
+ * Notes:
+ */
+int	SkGeSirqEvent(
+SK_AC		*pAC,		/* Adapter Context */
+SK_IOC		IoC,		/* Io Context */
+SK_U32		Event,		/* Module specific Event */
+SK_EVPARA	Para)		/* Event specific Parameter */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	SK_U32		Port;
+	SK_U32		Val32;
+	int			PortStat;
+	SK_U8		Val8;
+#ifdef GENESIS
+	SK_U64		Octets;
+#endif /* GENESIS */
+
+	Port = Para.Para32[0];
+	pPrt = &pAC->GIni.GP[Port];
+
+	switch (Event) {
+	case SK_HWEV_WATIM:
+		if (pPrt->PState == SK_PRT_RESET) {
+		
+			PortStat = SK_HW_PS_NONE;
+		}
+		else {
+			/* Check whether port came up */
+			PortStat = SkGePortCheckUp(pAC, IoC, (int)Port);
+		}
+
+		switch (PortStat) {
+		case SK_HW_PS_RESTART:
+			if (pPrt->PHWLinkUp) {
+				/* Set Link to down */
+				SkHWLinkDown(pAC, IoC, (int)Port);
+
+				/*
+				 * Signal directly to RLMT to ensure correct
+				 * sequence of SWITCH and RESET event.
+				 */
+				SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
+			}
+
+			/* Restart needed */
+			SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
+			break;
+
+		case SK_HW_PS_LINK:
+			/* Signal to RLMT */
+			SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_UP, Para);
+			break;
+		}
+		
+		/* Start again the check Timer */
+		if (pPrt->PHWLinkUp) {
+			Val32 = SK_WA_ACT_TIME;
+		}
+		else {
+			Val32 = SK_WA_INA_TIME;
+		}
+
+		/* Todo: still needed for non-XMAC PHYs??? */
+		/* Start workaround Errata #2 timer */
+		SkTimerStart(pAC, IoC, &pPrt->PWaTimer, Val32,
+			SKGE_HWAC, SK_HWEV_WATIM, Para);
+		break;
+
+	case SK_HWEV_PORT_START:
+		if (pPrt->PHWLinkUp) {
+			/*
+			 * Signal directly to RLMT to ensure correct
+			 * sequence of SWITCH and RESET event.
+			 */
+			SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
+		}
+
+		SkHWLinkDown(pAC, IoC, (int)Port);
+
+		/* Schedule Port RESET */
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_PORT_RESET, Para);
+
+		/* Start workaround Errata #2 timer */
+		SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME,
+			SKGE_HWAC, SK_HWEV_WATIM, Para);
+		break;
+
+	case SK_HWEV_PORT_STOP:
+		if (pPrt->PHWLinkUp) {
+			/*
+			 * Signal directly to RLMT to ensure correct
+			 * sequence of SWITCH and RESET event.
+			 */
+			SkRlmtEvent(pAC, IoC, SK_RLMT_LINK_DOWN, Para);
+		}
+
+		/* Stop Workaround Timer */
+		SkTimerStop(pAC, IoC, &pPrt->PWaTimer);
+
+		SkHWLinkDown(pAC, IoC, (int)Port);
+		break;
+
+	case SK_HWEV_UPDATE_STAT:
+		/* We do NOT need to update any statistics */
+		break;
+
+	case SK_HWEV_CLEAR_STAT:
+		/* We do NOT need to clear any statistics */
+		for (Port = 0; Port < (SK_U32)pAC->GIni.GIMacsFound; Port++) {
+			pPrt->PPrevRx = 0;
+			pPrt->PPrevFcs = 0;
+			pPrt->PPrevShorts = 0;
+		}
+		break;
+
+	case SK_HWEV_SET_LMODE:
+		Val8 = (SK_U8)Para.Para32[1];
+		if (pPrt->PLinkModeConf != Val8) {
+			/* Set New link mode */
+			pPrt->PLinkModeConf = Val8;
+
+			/* Restart Port */
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+		}
+		break;
+
+	case SK_HWEV_SET_FLOWMODE:
+		Val8 = (SK_U8)Para.Para32[1];
+		if (pPrt->PFlowCtrlMode != Val8) {
+			/* Set New Flow Control mode */
+			pPrt->PFlowCtrlMode = Val8;
+
+			/* Restart Port */
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+		}
+		break;
+
+	case SK_HWEV_SET_ROLE:
+		/* not possible for fiber */
+		if (!pAC->GIni.GICopperType) {
+			break;
+		}
+		Val8 = (SK_U8)Para.Para32[1];
+		if (pPrt->PMSMode != Val8) {
+			/* Set New Role (Master/Slave) mode */
+			pPrt->PMSMode = Val8;
+
+			/* Restart Port */
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+		}
+		break;
+
+	case SK_HWEV_SET_SPEED:
+		if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
+			break;
+		}
+		Val8 = (SK_U8)Para.Para32[1];
+		if (pPrt->PLinkSpeed != Val8) {
+			/* Set New Speed parameter */
+			pPrt->PLinkSpeed = Val8;
+
+			/* Restart Port */
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para);
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+		}
+		break;
+
+#ifdef GENESIS
+	case SK_HWEV_HALFDUP_CHK:
+		if (pAC->GIni.GIGenesis) {
+			/*
+			 * half duplex hangup workaround.
+			 * See packet arbiter timeout interrupt for description
+			 */
+			pPrt->HalfDupTimerActive = SK_FALSE;
+			if (pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF ||
+				pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) {
+				/* Snap statistic counters */
+				(void)SkXmUpdateStats(pAC, IoC, Port);
+
+				(void)SkXmMacStatistic(pAC, IoC, Port, XM_TXO_OK_HI, &Val32);
+
+				Octets = (SK_U64)Val32 << 32;
+				
+				(void)SkXmMacStatistic(pAC, IoC, Port, XM_TXO_OK_LO, &Val32);
+
+				Octets += Val32;
+				
+				if (pPrt->LastOctets == Octets) {
+					/* Tx hanging, a FIFO flush restarts it */
+					SkMacFlushTxFifo(pAC, IoC, Port);
+				}
+			}
+		}
+		break;
+#endif /* GENESIS */
+	
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_SIRQ_E001, SKERR_SIRQ_E001MSG);
+		break;
+	}
+
+	return(0);
+}	/* SkGeSirqEvent */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *	SkPhyIsrBcom() - PHY interrupt service routine
+ *
+ * Description: handles all interrupts from BCom PHY
+ *
+ * Returns: N/A
+ */
+static void SkPhyIsrBcom(
+SK_AC		*pAC,		/* Adapter Context */
+SK_IOC		IoC,		/* Io Context */
+int			Port,		/* Port Num = PHY Num */
+SK_U16		IStatus)	/* Interrupt Status */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	SK_EVPARA	Para;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if ((IStatus & PHY_B_IS_PSE) != 0) {
+		/* Incorrectable pair swap error */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW | SK_ERRCL_INIT, SKERR_SIRQ_E022,
+			SKERR_SIRQ_E022MSG);
+	}
+	
+	if ((IStatus & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) != 0) {
+
+		SkHWLinkDown(pAC, IoC, Port);
+
+		Para.Para32[0] = (SK_U32)Port;
+		/* Signal to RLMT */
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+
+		/* Start workaround Errata #2 timer */
+		SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME,
+			SKGE_HWAC, SK_HWEV_WATIM, Para);
+	}
+
+}	/* SkPhyIsrBcom */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ *	SkPhyIsrGmac() - PHY interrupt service routine
+ *
+ * Description: handles all interrupts from Marvell PHY
+ *
+ * Returns: N/A
+ */
+static void SkPhyIsrGmac(
+SK_AC		*pAC,		/* Adapter Context */
+SK_IOC		IoC,		/* Io Context */
+int			Port,		/* Port Num = PHY Num */
+SK_U16		IStatus)	/* Interrupt Status */
+{
+	SK_GEPORT	*pPrt;		/* GIni Port struct pointer */
+	SK_EVPARA	Para;
+	SK_U16		Word;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if ((IStatus & (PHY_M_IS_AN_PR | PHY_M_IS_LST_CHANGE)) != 0) {
+
+		SkHWLinkDown(pAC, IoC, Port);
+
+		SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_ADV, &Word);
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("AutoNeg.Adv: 0x%04X\n", Word));
+		
+		/* Set Auto-negotiation advertisement */
+		if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM) {
+			/* restore Asymmetric Pause bit */
+			SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_AUNE_ADV,
+				(SK_U16)(Word | PHY_M_AN_ASP));
+		}
+		
+		Para.Para32[0] = (SK_U32)Port;
+		/* Signal to RLMT */
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+	
+	if ((IStatus & PHY_M_IS_AN_ERROR) != 0) {
+		/* Auto-Negotiation Error */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E023, SKERR_SIRQ_E023MSG);
+	}
+	
+	if ((IStatus & PHY_M_IS_FIFO_ERROR) != 0) {
+		/* FIFO Overflow/Underrun Error */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E024, SKERR_SIRQ_E024MSG);
+	}
+	
+}	/* SkPhyIsrGmac */
+#endif /* YUKON */
+
+
+#ifdef OTHER_PHY
+/******************************************************************************
+ *
+ *	SkPhyIsrLone() - PHY interrupt service routine
+ *
+ * Description: handles all interrupts from LONE PHY
+ *
+ * Returns: N/A
+ */
+static void SkPhyIsrLone(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* Io Context */
+int		Port,		/* Port Num = PHY Num */
+SK_U16	IStatus)	/* Interrupt Status */
+{
+	SK_EVPARA	Para;
+
+	if (IStatus & (PHY_L_IS_DUP | PHY_L_IS_ISOL)) {
+		
+		SkHWLinkDown(pAC, IoC, Port);
+
+		Para.Para32[0] = (SK_U32)Port;
+		/* Signal to RLMT */
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+	}
+
+}	/* SkPhyIsrLone */
+#endif /* OTHER_PHY */
+
+/* End of File */
diff --git a/drivers/net/sk98lin/ski2c.c b/drivers/net/sk98lin/ski2c.c
new file mode 100644
index 0000000..79bf57c
--- /dev/null
+++ b/drivers/net/sk98lin/ski2c.c
@@ -0,0 +1,1296 @@
+/******************************************************************************
+ *
+ * Name:	ski2c.c
+ * Project:	Gigabit Ethernet Adapters, TWSI-Module
+ * Version:	$Revision: 1.59 $
+ * Date:	$Date: 2003/10/20 09:07:25 $
+ * Purpose:	Functions to access Voltage and Temperature Sensor
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/*
+ *	I2C Protocol
+ */
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+	"@(#) $Id: ski2c.c,v 1.59 2003/10/20 09:07:25 rschmidt Exp $ (C) Marvell. ";
+#endif
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#include "h/lm80.h"
+#include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+	I2C protocol implementation.
+
+	General Description:
+
+	The I2C protocol is used for the temperature sensors and for
+	the serial EEPROM which hold the configuration.
+
+	This file covers functions that allow to read write and do
+	some bulk requests a specified I2C address.
+
+	The Genesis has 2 I2C buses. One for the EEPROM which holds
+	the VPD Data and one for temperature and voltage sensor.
+	The following picture shows the I2C buses, I2C devices and
+	their control registers.
+
+	Note: The VPD functions are in skvpd.c
+.
+.	PCI Config I2C Bus for VPD Data:
+.
+.		      +------------+
+.		      | VPD EEPROM |
+.		      +------------+
+.			     |
+.			     | <-- I2C
+.			     |
+.		 +-----------+-----------+
+.		 |			 |
+.	+-----------------+	+-----------------+
+.	| PCI_VPD_ADR_REG |	| PCI_VPD_DAT_REG |
+.	+-----------------+	+-----------------+
+.
+.
+.	I2C Bus for LM80 sensor:
+.
+.			+-----------------+
+.			| Temperature and |
+.			| Voltage Sensor  |
+.			| 	LM80	  |
+.			+-----------------+
+.				|
+.				|
+.			I2C --> |
+.				|
+.			     +----+
+.	     +-------------->| OR |<--+
+.	     |		     +----+   |
+.     +------+------+		      |
+.     |		    |		      |
+. +--------+	+--------+	+----------+
+. | B2_I2C |	| B2_I2C |	|  B2_I2C  |
+. | _CTRL  |	| _DATA  |	|   _SW    |
+. +--------+	+--------+	+----------+
+.
+	The I2C bus may be driven by the B2_I2C_SW or by the B2_I2C_CTRL
+	and B2_I2C_DATA registers.
+	For driver software it is recommended to use the I2C control and
+	data register, because I2C bus timing is done by the ASIC and
+	an interrupt may be received when the I2C request is completed.
+
+	Clock Rate Timing:			MIN	MAX	generated by
+		VPD EEPROM:			50 kHz	100 kHz		HW
+		LM80 over I2C Ctrl/Data reg.	50 kHz	100 kHz		HW
+		LM80 over B2_I2C_SW register	0	400 kHz		SW
+
+	Note:	The clock generated by the hardware is dependend on the
+		PCI clock. If the PCI bus clock is 33 MHz, the I2C/VPD
+		clock is 50 kHz.
+ */
+intro()
+{}
+#endif
+
+#ifdef SK_DIAG
+/*
+ * I2C Fast Mode timing values used by the LM80.
+ * If new devices are added to the I2C bus the timing values have to be checked.
+ */
+#ifndef I2C_SLOW_TIMING
+#define	T_CLK_LOW			1300L	/* clock low time in ns */
+#define	T_CLK_HIGH		 	 600L	/* clock high time in ns */
+#define T_DATA_IN_SETUP		 100L	/* data in Set-up Time */
+#define T_START_HOLD		 600L	/* start condition hold time */
+#define T_START_SETUP		 600L	/* start condition Set-up time */
+#define	T_STOP_SETUP		 600L	/* stop condition Set-up time */
+#define T_BUS_IDLE			1300L	/* time the bus must free after Tx */
+#define	T_CLK_2_DATA_OUT	 900L	/* max. clock low to data output valid */
+#else	/* I2C_SLOW_TIMING */
+/* I2C Standard Mode Timing */
+#define	T_CLK_LOW			4700L	/* clock low time in ns */
+#define	T_CLK_HIGH			4000L	/* clock high time in ns */
+#define T_DATA_IN_SETUP		 250L	/* data in Set-up Time */
+#define T_START_HOLD		4000L	/* start condition hold time */
+#define T_START_SETUP		4700L	/* start condition Set-up time */
+#define	T_STOP_SETUP		4000L	/* stop condition Set-up time */
+#define T_BUS_IDLE			4700L	/* time the bus must free after Tx */
+#endif	/* !I2C_SLOW_TIMING */
+
+#define NS2BCLK(x)	(((x)*125)/10000)
+
+/*
+ * I2C Wire Operations
+ *
+ * About I2C_CLK_LOW():
+ *
+ * The Data Direction bit (I2C_DATA_DIR) has to be set to input when setting
+ * clock to low, to prevent the ASIC and the I2C data client from driving the
+ * serial data line simultaneously (ASIC: last bit of a byte = '1', I2C client
+ * send an 'ACK'). See also Concentrator Bugreport No. 10192.
+ */
+#define I2C_DATA_HIGH(IoC)	SK_I2C_SET_BIT(IoC, I2C_DATA)
+#define	I2C_DATA_LOW(IoC)	SK_I2C_CLR_BIT(IoC, I2C_DATA)
+#define	I2C_DATA_OUT(IoC)	SK_I2C_SET_BIT(IoC, I2C_DATA_DIR)
+#define	I2C_DATA_IN(IoC)	SK_I2C_CLR_BIT(IoC, I2C_DATA_DIR | I2C_DATA)
+#define	I2C_CLK_HIGH(IoC)	SK_I2C_SET_BIT(IoC, I2C_CLK)
+#define	I2C_CLK_LOW(IoC)	SK_I2C_CLR_BIT(IoC, I2C_CLK | I2C_DATA_DIR)
+#define	I2C_START_COND(IoC)	SK_I2C_CLR_BIT(IoC, I2C_CLK)
+
+#define NS2CLKT(x)	((x*125L)/10000)
+
+/*--------------- I2C Interface Register Functions --------------- */
+
+/*
+ * sending one bit
+ */
+void SkI2cSndBit(
+SK_IOC	IoC,	/* I/O Context */
+SK_U8	Bit)	/* Bit to send */
+{
+	I2C_DATA_OUT(IoC);
+	if (Bit) {
+		I2C_DATA_HIGH(IoC);
+	}
+	else {
+		I2C_DATA_LOW(IoC);
+	}
+	SkDgWaitTime(IoC, NS2BCLK(T_DATA_IN_SETUP));
+	I2C_CLK_HIGH(IoC);
+	SkDgWaitTime(IoC, NS2BCLK(T_CLK_HIGH));
+	I2C_CLK_LOW(IoC);
+}	/* SkI2cSndBit*/
+
+
+/*
+ * Signal a start to the I2C Bus.
+ *
+ * A start is signaled when data goes to low in a high clock cycle.
+ *
+ * Ends with Clock Low.
+ *
+ * Status: not tested
+ */
+void SkI2cStart(
+SK_IOC	IoC)	/* I/O Context */
+{
+	/* Init data and Clock to output lines */
+	/* Set Data high */
+	I2C_DATA_OUT(IoC);
+	I2C_DATA_HIGH(IoC);
+	/* Set Clock high */
+	I2C_CLK_HIGH(IoC);
+
+	SkDgWaitTime(IoC, NS2BCLK(T_START_SETUP));
+
+	/* Set Data Low */
+	I2C_DATA_LOW(IoC);
+
+	SkDgWaitTime(IoC, NS2BCLK(T_START_HOLD));
+
+	/* Clock low without Data to Input */
+	I2C_START_COND(IoC);
+
+	SkDgWaitTime(IoC, NS2BCLK(T_CLK_LOW));
+}	/* SkI2cStart */
+
+
+void SkI2cStop(
+SK_IOC	IoC)	/* I/O Context */
+{
+	/* Init data and Clock to output lines */
+	/* Set Data low */
+	I2C_DATA_OUT(IoC);
+	I2C_DATA_LOW(IoC);
+
+	SkDgWaitTime(IoC, NS2BCLK(T_CLK_2_DATA_OUT));
+
+	/* Set Clock high */
+	I2C_CLK_HIGH(IoC);
+
+	SkDgWaitTime(IoC, NS2BCLK(T_STOP_SETUP));
+
+	/*
+	 * Set Data High:	Do it by setting the Data Line to Input.
+	 *			Because of a pull up resistor the Data Line
+	 *			floods to high.
+	 */
+	I2C_DATA_IN(IoC);
+
+	/*
+	 *	When I2C activity is stopped
+	 *	 o	DATA should be set to input and
+	 *	 o	CLOCK should be set to high!
+	 */
+	SkDgWaitTime(IoC, NS2BCLK(T_BUS_IDLE));
+}	/* SkI2cStop */
+
+
+/*
+ * Receive just one bit via the I2C bus.
+ *
+ * Note:	Clock must be set to LOW before calling this function.
+ *
+ * Returns The received bit.
+ */
+int SkI2cRcvBit(
+SK_IOC	IoC)	/* I/O Context */
+{
+	int	Bit;
+	SK_U8	I2cSwCtrl;
+
+	/* Init data as input line */
+	I2C_DATA_IN(IoC);
+
+	SkDgWaitTime(IoC, NS2BCLK(T_CLK_2_DATA_OUT));
+
+	I2C_CLK_HIGH(IoC);
+
+	SkDgWaitTime(IoC, NS2BCLK(T_CLK_HIGH));
+
+	SK_I2C_GET_SW(IoC, &I2cSwCtrl);
+	
+	Bit = (I2cSwCtrl & I2C_DATA) ? 1 : 0;
+
+	I2C_CLK_LOW(IoC);
+	SkDgWaitTime(IoC, NS2BCLK(T_CLK_LOW-T_CLK_2_DATA_OUT));
+
+	return(Bit);
+}	/* SkI2cRcvBit */
+
+
+/*
+ * Receive an ACK.
+ *
+ * returns	0 If acknowledged
+ *		1 in case of an error
+ */
+int SkI2cRcvAck(
+SK_IOC	IoC)	/* I/O Context */
+{
+	/*
+	 * Received bit must be zero.
+	 */
+	return(SkI2cRcvBit(IoC) != 0);
+}	/* SkI2cRcvAck */
+
+
+/*
+ * Send an NACK.
+ */
+void SkI2cSndNAck(
+SK_IOC	IoC)	/* I/O Context */
+{
+	/*
+	 * Received bit must be zero.
+	 */
+	SkI2cSndBit(IoC, 1);
+}	/* SkI2cSndNAck */
+
+
+/*
+ * Send an ACK.
+ */
+void SkI2cSndAck(
+SK_IOC IoC)	/* I/O Context */
+{
+	/*
+	 * Received bit must be zero.
+	 */
+	SkI2cSndBit(IoC, 0);
+}	/* SkI2cSndAck */
+
+
+/*
+ * Send one byte to the I2C device and wait for ACK.
+ *
+ * Return acknowleged status.
+ */
+int SkI2cSndByte(
+SK_IOC	IoC,	/* I/O Context */
+int		Byte)	/* byte to send */
+{
+	int	i;
+
+	for (i = 0; i < 8; i++) {
+		if (Byte & (1<<(7-i))) {
+			SkI2cSndBit(IoC, 1);
+		}
+		else {
+			SkI2cSndBit(IoC, 0);
+		}
+	}
+
+	return(SkI2cRcvAck(IoC));
+}	/* SkI2cSndByte */
+
+
+/*
+ * Receive one byte and ack it.
+ *
+ * Return byte.
+ */
+int SkI2cRcvByte(
+SK_IOC	IoC,	/* I/O Context */
+int		Last)	/* Last Byte Flag */
+{
+	int	i;
+	int	Byte = 0;
+
+	for (i = 0; i < 8; i++) {
+		Byte <<= 1;
+		Byte |= SkI2cRcvBit(IoC);
+	}
+
+	if (Last) {
+		SkI2cSndNAck(IoC);
+	}
+	else {
+		SkI2cSndAck(IoC);
+	}
+
+	return(Byte);
+}	/* SkI2cRcvByte */
+
+
+/*
+ * Start dialog and send device address
+ *
+ * Return 0 if acknowleged, 1 in case of an error
+ */
+int	SkI2cSndDev(
+SK_IOC	IoC,	/* I/O Context */
+int		Addr,	/* Device Address */
+int		Rw)		/* Read / Write Flag */
+{
+	SkI2cStart(IoC);
+	Rw = ~Rw;
+	Rw &= I2C_WRITE;
+	return(SkI2cSndByte(IoC, (Addr<<1) | Rw));
+}	/* SkI2cSndDev */
+
+#endif /* SK_DIAG */
+
+/*----------------- I2C CTRL Register Functions ----------*/
+
+/*
+ * waits for a completion of an I2C transfer
+ *
+ * returns	0:	success, transfer completes
+ *			1:	error,	 transfer does not complete, I2C transfer
+ *						 killed, wait loop terminated.
+ */
+static int	SkI2cWait(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* I/O Context */
+int		Event)	/* complete event to wait for (I2C_READ or I2C_WRITE) */
+{
+	SK_U64	StartTime;
+	SK_U64	CurrentTime;
+	SK_U32	I2cCtrl;
+
+	StartTime = SkOsGetTime(pAC);
+	
+	do {
+		CurrentTime = SkOsGetTime(pAC);
+
+		if (CurrentTime - StartTime > SK_TICKS_PER_SEC / 8) {
+			
+			SK_I2C_STOP(IoC);
+#ifndef SK_DIAG
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E002, SKERR_I2C_E002MSG);
+#endif /* !SK_DIAG */
+			return(1);
+		}
+		
+		SK_I2C_GET_CTL(IoC, &I2cCtrl);
+
+#ifdef xYUKON_DBG
+		printf("StartTime=%lu, CurrentTime=%lu\n",
+			StartTime, CurrentTime);
+		if (kbhit()) {
+			return(1);
+		}
+#endif /* YUKON_DBG */
+	
+	} while ((I2cCtrl & I2C_FLAG) == (SK_U32)Event << 31);
+
+	return(0);
+}	/* SkI2cWait */
+
+
+/*
+ * waits for a completion of an I2C transfer
+ *
+ * Returns
+ *	Nothing
+ */
+void SkI2cWaitIrq(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC)	/* I/O Context */
+{
+	SK_SENSOR	*pSen;
+	SK_U64		StartTime;
+	SK_U32		IrqSrc;
+
+	pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+
+	if (pSen->SenState == SK_SEN_IDLE) {
+		return;
+	}
+
+	StartTime = SkOsGetTime(pAC);
+	
+	do {
+		if (SkOsGetTime(pAC) - StartTime > SK_TICKS_PER_SEC / 8) {
+			
+			SK_I2C_STOP(IoC);
+#ifndef SK_DIAG
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E016, SKERR_I2C_E016MSG);
+#endif /* !SK_DIAG */
+			return;
+		}
+		
+		SK_IN32(IoC, B0_ISRC, &IrqSrc);
+
+	} while ((IrqSrc & IS_I2C_READY) == 0);
+
+	pSen->SenState = SK_SEN_IDLE;
+	return;
+}	/* SkI2cWaitIrq */
+
+/*
+ * writes a single byte or 4 bytes into the I2C device
+ *
+ * returns	0:	success
+ *			1:	error
+ */
+static int SkI2cWrite(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	I2cData,	/* I2C Data to write */
+int		I2cDev,		/* I2C Device Address */
+int		I2cDevSize, /* I2C Device Size (e.g. I2C_025K_DEV or I2C_2K_DEV) */
+int		I2cReg,		/* I2C Device Register Address */
+int		I2cBurst)	/* I2C Burst Flag */
+{
+	SK_OUT32(IoC, B2_I2C_DATA, I2cData);
+	
+	SK_I2C_CTL(IoC, I2C_WRITE, I2cDev, I2cDevSize, I2cReg, I2cBurst);
+	
+	return(SkI2cWait(pAC, IoC, I2C_WRITE));
+}	/* SkI2cWrite*/
+
+
+#ifdef	SK_DIAG
+/*
+ * reads a single byte or 4 bytes from the I2C device
+ *
+ * returns	the word read
+ */
+SK_U32 SkI2cRead(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		I2cDev,		/* I2C Device Address */
+int		I2cDevSize, /* I2C Device Size (e.g. I2C_025K_DEV or I2C_2K_DEV) */
+int		I2cReg,		/* I2C Device Register Address */
+int		I2cBurst)	/* I2C Burst Flag */
+{
+	SK_U32	Data;
+
+	SK_OUT32(IoC, B2_I2C_DATA, 0);
+	SK_I2C_CTL(IoC, I2C_READ, I2cDev, I2cDevSize, I2cReg, I2cBurst);
+	
+	if (SkI2cWait(pAC, IoC, I2C_READ) != 0) {
+		w_print("%s\n", SKERR_I2C_E002MSG);
+	}
+	
+	SK_IN32(IoC, B2_I2C_DATA, &Data);
+	
+	return(Data);
+}	/* SkI2cRead */
+#endif /* SK_DIAG */
+
+
+/*
+ * read a sensor's value
+ *
+ * This function reads a sensor's value from the I2C sensor chip. The sensor
+ * is defined by its index into the sensors database in the struct pAC points
+ * to.
+ * Returns
+ *		1 if the read is completed
+ *		0 if the read must be continued (I2C Bus still allocated)
+ */
+static int	SkI2cReadSensor(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_SENSOR	*pSen)	/* Sensor to be read */
+{
+    if (pSen->SenRead != NULL) {
+        return((*pSen->SenRead)(pAC, IoC, pSen));
+    }
+	else {
+        return(0); /* no success */
+	}
+}	/* SkI2cReadSensor */
+
+/*
+ * Do the Init state 0 initialization
+ */
+static int SkI2cInit0(
+SK_AC	*pAC)	/* Adapter Context */
+{
+	int	i;
+
+	/* Begin with first sensor */
+	pAC->I2c.CurrSens = 0;
+	
+	/* Begin with timeout control for state machine */
+	pAC->I2c.TimerMode = SK_TIMER_WATCH_SM;
+	
+	/* Set sensor number to zero */
+	pAC->I2c.MaxSens = 0;
+
+#ifndef SK_DIAG
+	/* Initialize Number of Dummy Reads */
+	pAC->I2c.DummyReads = SK_MAX_SENSORS;
+#endif
+
+	for (i = 0; i < SK_MAX_SENSORS; i++) {
+		pAC->I2c.SenTable[i].SenDesc = "unknown";
+		pAC->I2c.SenTable[i].SenType = SK_SEN_UNKNOWN;
+		pAC->I2c.SenTable[i].SenThreErrHigh = 0;
+		pAC->I2c.SenTable[i].SenThreErrLow = 0;
+		pAC->I2c.SenTable[i].SenThreWarnHigh = 0;
+		pAC->I2c.SenTable[i].SenThreWarnLow = 0;
+		pAC->I2c.SenTable[i].SenReg = LM80_FAN2_IN;
+		pAC->I2c.SenTable[i].SenInit = SK_SEN_DYN_INIT_NONE;
+		pAC->I2c.SenTable[i].SenValue = 0;
+		pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_NOT_PRESENT;
+		pAC->I2c.SenTable[i].SenErrCts = 0;
+		pAC->I2c.SenTable[i].SenBegErrTS = 0;
+		pAC->I2c.SenTable[i].SenState = SK_SEN_IDLE;
+		pAC->I2c.SenTable[i].SenRead = NULL;
+		pAC->I2c.SenTable[i].SenDev = 0;
+	}
+
+	/* Now we are "INIT data"ed */
+	pAC->I2c.InitLevel = SK_INIT_DATA;
+	return(0);
+}	/* SkI2cInit0*/
+
+
+/*
+ * Do the init state 1 initialization
+ *
+ * initialize the following register of the LM80:
+ * Configuration register:
+ * - START, noINT, activeLOW, noINT#Clear, noRESET, noCI, noGPO#, noINIT
+ *
+ * Interrupt Mask Register 1:
+ * - all interrupts are Disabled (0xff)
+ *
+ * Interrupt Mask Register 2:
+ * - all interrupts are Disabled (0xff) Interrupt modi doesn't matter.
+ *
+ * Fan Divisor/RST_OUT register:
+ * - Divisors set to 1 (bits 00), all others 0s.
+ *
+ * OS# Configuration/Temperature resolution Register:
+ * - all 0s
+ *
+ */
+static int SkI2cInit1(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC)	/* I/O Context */
+{
+    int i;
+    SK_U8 I2cSwCtrl;
+	SK_GEPORT *pPrt;	/* GIni Port struct pointer */
+
+	if (pAC->I2c.InitLevel != SK_INIT_DATA) {
+		/* ReInit not needed in I2C module */
+		return(0);
+	}
+
+    /* Set the Direction of I2C-Data Pin to IN */
+    SK_I2C_CLR_BIT(IoC, I2C_DATA_DIR | I2C_DATA);
+    /* Check for 32-Bit Yukon with Low at I2C-Data Pin */
+	SK_I2C_GET_SW(IoC, &I2cSwCtrl);
+
+	if ((I2cSwCtrl & I2C_DATA) == 0) {
+		/* this is a 32-Bit board */
+		pAC->GIni.GIYukon32Bit = SK_TRUE;
+        return(0);
+    }
+
+	/* Check for 64 Bit Yukon without sensors */
+	if (SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_CFG, 0) != 0) {
+        return(0);
+    }
+
+	(void)SkI2cWrite(pAC, IoC, 0xffUL, LM80_ADDR, I2C_025K_DEV, LM80_IMSK_1, 0);
+	
+	(void)SkI2cWrite(pAC, IoC, 0xffUL, LM80_ADDR, I2C_025K_DEV, LM80_IMSK_2, 0);
+	
+	(void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_FAN_CTRL, 0);
+	
+	(void)SkI2cWrite(pAC, IoC, 0, LM80_ADDR, I2C_025K_DEV, LM80_TEMP_CTRL, 0);
+	
+	(void)SkI2cWrite(pAC, IoC, (SK_U32)LM80_CFG_START, LM80_ADDR, I2C_025K_DEV,
+		LM80_CFG, 0);
+	
+	/*
+	 * MaxSens has to be updated here, because PhyType is not
+	 * set when performing Init Level 0
+	 */
+    pAC->I2c.MaxSens = 5;
+	
+	pPrt = &pAC->GIni.GP[0];
+	
+	if (pAC->GIni.GIGenesis) {
+		if (pPrt->PhyType == SK_PHY_BCOM) {
+			if (pAC->GIni.GIMacsFound == 1) {
+				pAC->I2c.MaxSens += 1;
+			}
+			else {
+				pAC->I2c.MaxSens += 3;
+			}
+		}
+	}
+	else {
+		pAC->I2c.MaxSens += 3;
+	}
+	
+	for (i = 0; i < pAC->I2c.MaxSens; i++) {
+		switch (i) {
+		case 0:
+			pAC->I2c.SenTable[i].SenDesc = "Temperature";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_TEMP;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_TEMP_HIGH_ERR;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_TEMP_HIGH_WARN;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_TEMP_LOW_WARN;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_TEMP_LOW_ERR;
+			pAC->I2c.SenTable[i].SenReg = LM80_TEMP_IN;
+			break;
+		case 1:
+			pAC->I2c.SenTable[i].SenDesc = "Voltage PCI";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PCI_5V_HIGH_ERR;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PCI_5V_HIGH_WARN;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PCI_5V_LOW_WARN;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PCI_5V_LOW_ERR;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT0_IN;
+			break;
+		case 2:
+			pAC->I2c.SenTable[i].SenDesc = "Voltage PCI-IO";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PCI_IO_5V_HIGH_ERR;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PCI_IO_5V_HIGH_WARN;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PCI_IO_3V3_LOW_WARN;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PCI_IO_3V3_LOW_ERR;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT1_IN;
+			pAC->I2c.SenTable[i].SenInit = SK_SEN_DYN_INIT_PCI_IO;
+			break;
+		case 3:
+			pAC->I2c.SenTable[i].SenDesc = "Voltage ASIC";
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_VDD_HIGH_ERR;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_VDD_HIGH_WARN;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VDD_LOW_WARN;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VDD_LOW_ERR;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT2_IN;
+			break;
+		case 4:
+			if (pAC->GIni.GIGenesis) {
+				if (pPrt->PhyType == SK_PHY_BCOM) {
+					pAC->I2c.SenTable[i].SenDesc = "Voltage PHY A PLL";
+					pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR;
+					pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN;
+					pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN;
+					pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR;
+				}
+				else {
+					pAC->I2c.SenTable[i].SenDesc = "Voltage PMA";
+					pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR;
+					pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN;
+					pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN;
+					pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR;
+				}
+			}
+			else {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage VAUX";
+				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_VAUX_3V3_HIGH_ERR;
+				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_VAUX_3V3_HIGH_WARN;
+				if (pAC->GIni.GIVauxAvail) {
+					pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VAUX_3V3_LOW_WARN;
+					pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VAUX_3V3_LOW_ERR;
+				}
+				else {
+					pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_VAUX_0V_WARN_ERR;
+					pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_VAUX_0V_WARN_ERR;
+				}
+			}
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT3_IN;
+			break;
+		case 5:
+			if (pAC->GIni.GIGenesis) {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 2V5";
+				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PHY_2V5_HIGH_ERR;
+				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PHY_2V5_HIGH_WARN;
+				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PHY_2V5_LOW_WARN;
+				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PHY_2V5_LOW_ERR;
+			}
+			else {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage Core 1V5";
+				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_CORE_1V5_HIGH_ERR;
+				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_CORE_1V5_HIGH_WARN;
+				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_CORE_1V5_LOW_WARN;
+				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_CORE_1V5_LOW_ERR;
+			}
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT4_IN;
+			break;
+		case 6:
+			if (pAC->GIni.GIGenesis) {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage PHY B PLL";
+			}
+			else {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 3V3";
+			}
+			pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+			pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PLL_3V3_HIGH_ERR;
+			pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PLL_3V3_HIGH_WARN;
+			pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PLL_3V3_LOW_WARN;
+			pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PLL_3V3_LOW_ERR;
+			pAC->I2c.SenTable[i].SenReg = LM80_VT5_IN;
+			break;
+		case 7:
+			if (pAC->GIni.GIGenesis) {
+				pAC->I2c.SenTable[i].SenDesc = "Speed Fan";
+				pAC->I2c.SenTable[i].SenType = SK_SEN_FAN;
+				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_FAN_HIGH_ERR;
+				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_FAN_HIGH_WARN;
+				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_FAN_LOW_WARN;
+				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_FAN_LOW_ERR;
+				pAC->I2c.SenTable[i].SenReg = LM80_FAN2_IN;
+			}
+			else {
+				pAC->I2c.SenTable[i].SenDesc = "Voltage PHY 2V5";
+				pAC->I2c.SenTable[i].SenType = SK_SEN_VOLT;
+				pAC->I2c.SenTable[i].SenThreErrHigh = SK_SEN_PHY_2V5_HIGH_ERR;
+				pAC->I2c.SenTable[i].SenThreWarnHigh = SK_SEN_PHY_2V5_HIGH_WARN;
+				pAC->I2c.SenTable[i].SenThreWarnLow = SK_SEN_PHY_2V5_LOW_WARN;
+				pAC->I2c.SenTable[i].SenThreErrLow = SK_SEN_PHY_2V5_LOW_ERR;
+				pAC->I2c.SenTable[i].SenReg = LM80_VT6_IN;
+			}
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_INIT | SK_ERRCL_SW,
+				SKERR_I2C_E001, SKERR_I2C_E001MSG);
+			break;
+		}
+
+		pAC->I2c.SenTable[i].SenValue = 0;
+		pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK;
+		pAC->I2c.SenTable[i].SenErrCts = 0;
+		pAC->I2c.SenTable[i].SenBegErrTS = 0;
+		pAC->I2c.SenTable[i].SenState = SK_SEN_IDLE;
+		pAC->I2c.SenTable[i].SenRead = SkLm80ReadSensor;
+		pAC->I2c.SenTable[i].SenDev = LM80_ADDR;
+	}
+
+#ifndef SK_DIAG
+	pAC->I2c.DummyReads = pAC->I2c.MaxSens;
+#endif /* !SK_DIAG */
+	
+	/* Clear I2C IRQ */
+	SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
+	
+	/* Now we are I/O initialized */
+	pAC->I2c.InitLevel = SK_INIT_IO;
+	return(0);
+}	/* SkI2cInit1 */
+
+
+/*
+ * Init level 2: Start first sensor read.
+ */
+static int SkI2cInit2(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC)	/* I/O Context */
+{
+	int		ReadComplete;
+	SK_SENSOR	*pSen;
+
+	if (pAC->I2c.InitLevel != SK_INIT_IO) {
+		/* ReInit not needed in I2C module */
+		/* Init0 and Init2 not permitted */
+		return(0);
+	}
+
+	pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+	ReadComplete = SkI2cReadSensor(pAC, IoC, pSen);
+
+	if (ReadComplete) {
+		SK_ERR_LOG(pAC, SK_ERRCL_INIT, SKERR_I2C_E008, SKERR_I2C_E008MSG);
+	}
+
+	/* Now we are correctly initialized */
+	pAC->I2c.InitLevel = SK_INIT_RUN;
+
+	return(0);
+}	/* SkI2cInit2*/
+
+
+/*
+ * Initialize I2C devices
+ *
+ * Get the first voltage value and discard it.
+ * Go into temperature read mode. A default pointer is not set.
+ *
+ * The things to be done depend on the init level in the parameter list:
+ * Level 0:
+ *	Initialize only the data structures. Do NOT access hardware.
+ * Level 1:
+ *	Initialize hardware through SK_IN / SK_OUT commands. Do NOT use interrupts.
+ * Level 2:
+ *	Everything is possible. Interrupts may be used from now on.
+ *
+ * return:
+ *	0 = success
+ *	other = error.
+ */
+int	SkI2cInit(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* I/O Context needed in levels 1 and 2 */
+int		Level)	/* Init Level */
+{
+
+	switch (Level) {
+	case SK_INIT_DATA:
+		return(SkI2cInit0(pAC));
+	case SK_INIT_IO:
+		return(SkI2cInit1(pAC, IoC));
+	case SK_INIT_RUN:
+		return(SkI2cInit2(pAC, IoC));
+	default:
+		break;
+	}
+
+	return(0);
+}	/* SkI2cInit */
+
+
+#ifndef SK_DIAG
+
+/*
+ * Interrupt service function for the I2C Interface
+ *
+ * Clears the Interrupt source
+ *
+ * Reads the register and check it for sending a trap.
+ *
+ * Starts the timer if necessary.
+ */
+void SkI2cIsr(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC)	/* I/O Context */
+{
+	SK_EVPARA	Para;
+
+	/* Clear I2C IRQ */
+	SK_OUT32(IoC, B2_I2C_IRQ, I2C_CLR_IRQ);
+
+	Para.Para64 = 0;
+	SkEventQueue(pAC, SKGE_I2C, SK_I2CEV_IRQ, Para);
+}	/* SkI2cIsr */
+
+
+/*
+ * Check this sensors Value against the threshold and send events.
+ */
+static void SkI2cCheckSensor(
+SK_AC		*pAC,	/* Adapter Context */
+SK_SENSOR	*pSen)
+{
+	SK_EVPARA	ParaLocal;
+	SK_BOOL		TooHigh;	/* Is sensor too high? */
+	SK_BOOL		TooLow;		/* Is sensor too low? */
+	SK_U64		CurrTime;	/* Current Time */
+	SK_BOOL		DoTrapSend;	/* We need to send a trap */
+	SK_BOOL		DoErrLog;	/* We need to log the error */
+	SK_BOOL		IsError;	/* We need to log the error */
+
+	/* Check Dummy Reads first */
+	if (pAC->I2c.DummyReads > 0) {
+		pAC->I2c.DummyReads--;
+		return;
+	}
+
+	/* Get the current time */
+	CurrTime = SkOsGetTime(pAC);
+
+	/* Set para to the most useful setting: The current sensor. */
+	ParaLocal.Para64 = (SK_U64)pAC->I2c.CurrSens;
+
+	/* Check the Value against the thresholds. First: Error Thresholds */
+	TooHigh = (pSen->SenValue > pSen->SenThreErrHigh);
+	TooLow = (pSen->SenValue < pSen->SenThreErrLow);
+		
+	IsError = SK_FALSE;
+	if (TooHigh || TooLow) {
+		/* Error condition is satisfied */
+		DoTrapSend = SK_TRUE;
+		DoErrLog = SK_TRUE;
+
+		/* Now error condition is satisfied */
+		IsError = SK_TRUE;
+
+		if (pSen->SenErrFlag == SK_SEN_ERR_ERR) {
+			/* This state is the former one */
+
+			/* So check first whether we have to send a trap */
+			if (pSen->SenLastErrTrapTS + SK_SEN_ERR_TR_HOLD >
+			    CurrTime) {
+				/*
+				 * Do NOT send the Trap. The hold back time
+				 * has to run out first.
+				 */
+				DoTrapSend = SK_FALSE;
+			}
+
+			/* Check now whether we have to log an Error */
+			if (pSen->SenLastErrLogTS + SK_SEN_ERR_LOG_HOLD >
+			    CurrTime) {
+				/*
+				 * Do NOT log the error. The hold back time
+				 * has to run out first.
+				 */
+				DoErrLog = SK_FALSE;
+			}
+		}
+		else {
+			/* We came from a different state -> Set Begin Time Stamp */
+			pSen->SenBegErrTS = CurrTime;
+			pSen->SenErrFlag = SK_SEN_ERR_ERR;
+		}
+
+		if (DoTrapSend) {
+			/* Set current Time */
+			pSen->SenLastErrTrapTS = CurrTime;
+			pSen->SenErrCts++;
+
+			/* Queue PNMI Event */
+			SkEventQueue(pAC, SKGE_PNMI, (TooHigh ?
+				SK_PNMI_EVT_SEN_ERR_UPP :
+				SK_PNMI_EVT_SEN_ERR_LOW),
+				ParaLocal);
+		}
+
+		if (DoErrLog) {
+			/* Set current Time */
+			pSen->SenLastErrLogTS = CurrTime;
+
+			if (pSen->SenType == SK_SEN_TEMP) {
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E011, SKERR_I2C_E011MSG);
+			}
+			else if (pSen->SenType == SK_SEN_VOLT) {
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E012, SKERR_I2C_E012MSG);
+			}
+			else {
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E015, SKERR_I2C_E015MSG);
+			}
+		}
+	}
+
+	/* Check the Value against the thresholds */
+	/* 2nd: Warning thresholds */
+	TooHigh = (pSen->SenValue > pSen->SenThreWarnHigh);
+	TooLow = (pSen->SenValue < pSen->SenThreWarnLow);
+		
+	if (!IsError && (TooHigh || TooLow)) {
+		/* Error condition is satisfied */
+		DoTrapSend = SK_TRUE;
+		DoErrLog = SK_TRUE;
+
+		if (pSen->SenErrFlag == SK_SEN_ERR_WARN) {
+			/* This state is the former one */
+
+			/* So check first whether we have to send a trap */
+			if (pSen->SenLastWarnTrapTS + SK_SEN_WARN_TR_HOLD > CurrTime) {
+				/*
+				 * Do NOT send the Trap. The hold back time
+				 * has to run out first.
+				 */
+				DoTrapSend = SK_FALSE;
+			}
+
+			/* Check now whether we have to log an Error */
+			if (pSen->SenLastWarnLogTS + SK_SEN_WARN_LOG_HOLD > CurrTime) {
+				/*
+				 * Do NOT log the error. The hold back time
+				 * has to run out first.
+				 */
+				DoErrLog = SK_FALSE;
+			}
+		}
+		else {
+			/* We came from a different state -> Set Begin Time Stamp */
+			pSen->SenBegWarnTS = CurrTime;
+			pSen->SenErrFlag = SK_SEN_ERR_WARN;
+		}
+
+		if (DoTrapSend) {
+			/* Set current Time */
+			pSen->SenLastWarnTrapTS = CurrTime;
+			pSen->SenWarnCts++;
+
+			/* Queue PNMI Event */
+			SkEventQueue(pAC, SKGE_PNMI, (TooHigh ?
+				SK_PNMI_EVT_SEN_WAR_UPP :
+				SK_PNMI_EVT_SEN_WAR_LOW),
+				ParaLocal);
+		}
+
+		if (DoErrLog) {
+			/* Set current Time */
+			pSen->SenLastWarnLogTS = CurrTime;
+
+			if (pSen->SenType == SK_SEN_TEMP) {
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E009, SKERR_I2C_E009MSG);
+			}
+			else if (pSen->SenType == SK_SEN_VOLT) {
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E010, SKERR_I2C_E010MSG);
+			}
+			else {
+				SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E014, SKERR_I2C_E014MSG);
+			}
+		}
+	}
+
+	/* Check for NO error at all */
+	if (!IsError && !TooHigh && !TooLow) {
+		/* Set o.k. Status if no error and no warning condition */
+		pSen->SenErrFlag = SK_SEN_ERR_OK;
+	}
+
+	/* End of check against the thresholds */
+
+	/* Bug fix AF: 16.Aug.2001: Correct the init base
+	 * of LM80 sensor.
+	 */
+	if (pSen->SenInit == SK_SEN_DYN_INIT_PCI_IO) {
+
+        pSen->SenInit = SK_SEN_DYN_INIT_NONE;
+
+		if (pSen->SenValue > SK_SEN_PCI_IO_RANGE_LIMITER) {
+			/* 5V PCI-IO Voltage */
+			pSen->SenThreWarnLow = SK_SEN_PCI_IO_5V_LOW_WARN;
+			pSen->SenThreErrLow = SK_SEN_PCI_IO_5V_LOW_ERR;
+		}
+		else {
+			/* 3.3V PCI-IO Voltage */
+			pSen->SenThreWarnHigh = SK_SEN_PCI_IO_3V3_HIGH_WARN;
+			pSen->SenThreErrHigh = SK_SEN_PCI_IO_3V3_HIGH_ERR;
+		}
+	}
+	
+#ifdef TEST_ONLY
+    /* Dynamic thresholds also for VAUX of LM80 sensor */
+	if (pSen->SenInit == SK_SEN_DYN_INIT_VAUX) {
+
+        pSen->SenInit = SK_SEN_DYN_INIT_NONE;
+
+		/* 3.3V VAUX Voltage */
+		if (pSen->SenValue > SK_SEN_VAUX_RANGE_LIMITER) {
+			pSen->SenThreWarnLow = SK_SEN_VAUX_3V3_LOW_WARN;
+			pSen->SenThreErrLow = SK_SEN_VAUX_3V3_LOW_ERR;
+		}
+		/* 0V VAUX Voltage */
+		else {
+			pSen->SenThreWarnHigh = SK_SEN_VAUX_0V_WARN_ERR;
+			pSen->SenThreErrHigh = SK_SEN_VAUX_0V_WARN_ERR;
+		}
+	}
+
+	/*
+	 * Check initialization state:
+	 * The VIO Thresholds need adaption
+	 */
+	if (!pSen->SenInit && pSen->SenReg == LM80_VT1_IN &&
+	     pSen->SenValue > SK_SEN_WARNLOW2C &&
+	     pSen->SenValue < SK_SEN_WARNHIGH2) {
+		pSen->SenThreErrLow = SK_SEN_ERRLOW2C;
+		pSen->SenThreWarnLow = SK_SEN_WARNLOW2C;
+		pSen->SenInit = SK_TRUE;
+	}
+
+	if (!pSen->SenInit && pSen->SenReg == LM80_VT1_IN &&
+	     pSen->SenValue > SK_SEN_WARNLOW2 &&
+	     pSen->SenValue < SK_SEN_WARNHIGH2C) {
+		pSen->SenThreErrHigh = SK_SEN_ERRHIGH2C;
+		pSen->SenThreWarnHigh = SK_SEN_WARNHIGH2C;
+		pSen->SenInit = SK_TRUE;
+	}
+#endif
+
+	if (pSen->SenInit != SK_SEN_DYN_INIT_NONE) {
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_I2C_E013, SKERR_I2C_E013MSG);
+	}
+}	/* SkI2cCheckSensor */
+
+
+/*
+ * The only Event to be served is the timeout event
+ *
+ */
+int	SkI2cEvent(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_U32		Event,	/* Module specific Event */
+SK_EVPARA	Para)	/* Event specific Parameter */
+{
+	int			ReadComplete;
+	SK_SENSOR	*pSen;
+	SK_U32		Time;
+	SK_EVPARA	ParaLocal;
+	int			i;
+
+	/* New case: no sensors */
+	if (pAC->I2c.MaxSens == 0) {
+		return(0);
+	}
+
+	switch (Event) {
+	case SK_I2CEV_IRQ:
+		pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+		ReadComplete = SkI2cReadSensor(pAC, IoC, pSen);
+
+		if (ReadComplete) {
+			/* Check sensor against defined thresholds */
+			SkI2cCheckSensor(pAC, pSen);
+
+			/* Increment Current sensor and set appropriate Timeout */
+			pAC->I2c.CurrSens++;
+			if (pAC->I2c.CurrSens >= pAC->I2c.MaxSens) {
+				pAC->I2c.CurrSens = 0;
+				Time = SK_I2C_TIM_LONG;
+			}
+			else {
+				Time = SK_I2C_TIM_SHORT;
+			}
+
+			/* Start Timer */
+			ParaLocal.Para64 = (SK_U64)0;
+
+			pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING;
+			
+			SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time,
+				SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+		}
+        else {
+			/* Start Timer */
+			ParaLocal.Para64 = (SK_U64)0;
+
+			pAC->I2c.TimerMode = SK_TIMER_WATCH_SM;
+
+            SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, SK_I2C_TIM_WATCH,
+				SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+		}
+		break;
+	case SK_I2CEV_TIM:
+		if (pAC->I2c.TimerMode == SK_TIMER_NEW_GAUGING) {
+
+			ParaLocal.Para64 = (SK_U64)0;
+			SkTimerStop(pAC, IoC, &pAC->I2c.SenTimer);
+
+			pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+			ReadComplete = SkI2cReadSensor(pAC, IoC, pSen);
+
+			if (ReadComplete) {
+				/* Check sensor against defined thresholds */
+				SkI2cCheckSensor(pAC, pSen);
+
+				/* Increment Current sensor and set appropriate Timeout */
+				pAC->I2c.CurrSens++;
+				if (pAC->I2c.CurrSens == pAC->I2c.MaxSens) {
+					pAC->I2c.CurrSens = 0;
+					Time = SK_I2C_TIM_LONG;
+				}
+				else {
+					Time = SK_I2C_TIM_SHORT;
+				}
+
+				/* Start Timer */
+				ParaLocal.Para64 = (SK_U64)0;
+
+				pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING;
+
+				SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time,
+					SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+			}
+		}
+		else {
+			pSen = &pAC->I2c.SenTable[pAC->I2c.CurrSens];
+			pSen->SenErrFlag = SK_SEN_ERR_FAULTY;
+			SK_I2C_STOP(IoC);
+
+			/* Increment Current sensor and set appropriate Timeout */
+			pAC->I2c.CurrSens++;
+			if (pAC->I2c.CurrSens == pAC->I2c.MaxSens) {
+				pAC->I2c.CurrSens = 0;
+				Time = SK_I2C_TIM_LONG;
+			}
+			else {
+				Time = SK_I2C_TIM_SHORT;
+			}
+
+			/* Start Timer */
+			ParaLocal.Para64 = (SK_U64)0;
+
+			pAC->I2c.TimerMode = SK_TIMER_NEW_GAUGING;
+
+			SkTimerStart(pAC, IoC, &pAC->I2c.SenTimer, Time,
+				SKGE_I2C, SK_I2CEV_TIM, ParaLocal);
+		}
+		break;
+	case SK_I2CEV_CLEAR:
+		for (i = 0; i < SK_MAX_SENSORS; i++) {
+			pAC->I2c.SenTable[i].SenErrFlag = SK_SEN_ERR_OK;
+			pAC->I2c.SenTable[i].SenErrCts = 0;
+			pAC->I2c.SenTable[i].SenWarnCts = 0;
+			pAC->I2c.SenTable[i].SenBegErrTS = 0;
+			pAC->I2c.SenTable[i].SenBegWarnTS = 0;
+			pAC->I2c.SenTable[i].SenLastErrTrapTS = (SK_U64)0;
+			pAC->I2c.SenTable[i].SenLastErrLogTS = (SK_U64)0;
+			pAC->I2c.SenTable[i].SenLastWarnTrapTS = (SK_U64)0;
+			pAC->I2c.SenTable[i].SenLastWarnLogTS = (SK_U64)0;
+		}
+		break;
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E006, SKERR_I2C_E006MSG);
+	}
+
+	return(0);
+}	/* SkI2cEvent*/
+
+#endif /* !SK_DIAG */
diff --git a/drivers/net/sk98lin/sklm80.c b/drivers/net/sk98lin/sklm80.c
new file mode 100644
index 0000000..a204f5b
--- /dev/null
+++ b/drivers/net/sk98lin/sklm80.c
@@ -0,0 +1,141 @@
+/******************************************************************************
+ *
+ * Name:	sklm80.c
+ * Project:	Gigabit Ethernet Adapters, TWSI-Module
+ * Version:	$Revision: 1.22 $
+ * Date:	$Date: 2003/10/20 09:08:21 $
+ * Purpose:	Functions to access Voltage and Temperature Sensor (LM80)
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/*
+	LM80 functions
+*/
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+	"@(#) $Id: sklm80.c,v 1.22 2003/10/20 09:08:21 rschmidt Exp $ (C) Marvell. ";
+#endif
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#include "h/lm80.h"
+#include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
+
+#define	BREAK_OR_WAIT(pAC,IoC,Event)	break
+
+/*
+ * read a sensors value (LM80 specific)
+ *
+ * This function reads a sensors value from the I2C sensor chip LM80.
+ * The sensor is defined by its index into the sensors database in the struct
+ * pAC points to.
+ *
+ * Returns	1 if the read is completed
+ *		0 if the read must be continued (I2C Bus still allocated)
+ */
+int SkLm80ReadSensor(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context needed in level 1 and 2 */
+SK_SENSOR	*pSen)	/* Sensor to be read */
+{
+	SK_I32		Value;
+
+	switch (pSen->SenState) {
+	case SK_SEN_IDLE:
+		/* Send address to ADDR register */
+		SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, I2C_025K_DEV, pSen->SenReg, 0);
+
+		pSen->SenState = SK_SEN_VALUE ;
+		BREAK_OR_WAIT(pAC, IoC, I2C_READ);
+	
+	case SK_SEN_VALUE:
+		/* Read value from data register */
+		SK_IN32(IoC, B2_I2C_DATA, ((SK_U32 *)&Value));
+		
+		Value &= 0xff; /* only least significant byte is valid */
+
+		/* Do NOT check the Value against the thresholds */
+		/* Checking is done in the calling instance */
+
+		if (pSen->SenType == SK_SEN_VOLT) {
+			/* Voltage sensor */
+			pSen->SenValue = Value * SK_LM80_VT_LSB;
+			pSen->SenState = SK_SEN_IDLE ;
+			return(1);
+		}
+
+		if (pSen->SenType == SK_SEN_FAN) {
+			if (Value != 0 && Value != 0xff) {
+				/* Fan speed counter */
+				pSen->SenValue = SK_LM80_FAN_FAKTOR/Value;
+			}
+			else {
+				/* Indicate Fan error */
+				pSen->SenValue = 0;
+			}
+			pSen->SenState = SK_SEN_IDLE ;
+			return(1);
+		}
+
+		/* First: correct the value: it might be negative */
+		if ((Value & 0x80) != 0) {
+			/* Value is negative */
+			Value = Value - 256;
+		}
+
+		/* We have a temperature sensor and need to get the signed extension.
+		 * For now we get the extension from the last reading, so in the normal
+		 * case we won't see flickering temperatures.
+		 */
+		pSen->SenValue = (Value * SK_LM80_TEMP_LSB) +
+			(pSen->SenValue % SK_LM80_TEMP_LSB);
+
+		/* Send address to ADDR register */
+		SK_I2C_CTL(IoC, I2C_READ, pSen->SenDev, I2C_025K_DEV, LM80_TEMP_CTRL, 0);
+
+		pSen->SenState = SK_SEN_VALEXT ;
+		BREAK_OR_WAIT(pAC, IoC, I2C_READ);
+	
+	case SK_SEN_VALEXT:
+		/* Read value from data register */
+		SK_IN32(IoC, B2_I2C_DATA, ((SK_U32 *)&Value));
+		Value &= LM80_TEMP_LSB_9; /* only bit 7 is valid */
+
+		/* cut the LSB bit */
+		pSen->SenValue = ((pSen->SenValue / SK_LM80_TEMP_LSB) *
+			SK_LM80_TEMP_LSB);
+
+		if (pSen->SenValue < 0) {
+			/* Value negative: The bit value must be subtracted */
+			pSen->SenValue -= ((Value >> 7) * SK_LM80_TEMPEXT_LSB);
+		}
+		else {
+			/* Value positive: The bit value must be added */
+			pSen->SenValue += ((Value >> 7) * SK_LM80_TEMPEXT_LSB);
+		}
+
+		pSen->SenState = SK_SEN_IDLE ;
+		return(1);
+	
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_I2C_E007, SKERR_I2C_E007MSG);
+		return(1);
+	}
+
+	/* Not completed */
+	return(0);
+}
+
diff --git a/drivers/net/sk98lin/skqueue.c b/drivers/net/sk98lin/skqueue.c
new file mode 100644
index 0000000..0275b4f
--- /dev/null
+++ b/drivers/net/sk98lin/skqueue.c
@@ -0,0 +1,179 @@
+/******************************************************************************
+ *
+ * Name:	skqueue.c
+ * Project:	Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version:	$Revision: 1.20 $
+ * Date:	$Date: 2003/09/16 13:44:00 $
+ * Purpose:	Management of an event queue.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+
+/*
+ *	Event queue and dispatcher
+ */
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+	"@(#) $Id: skqueue.c,v 1.20 2003/09/16 13:44:00 rschmidt Exp $ (C) Marvell.";
+#endif
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#include "h/skqueue.h"		/* Queue Definitions */
+#include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+	Event queue management.
+
+	General Description:
+
+ */
+intro()
+{}
+#endif
+
+#define PRINTF(a,b,c)
+
+/*
+ * init event queue management
+ *
+ * Must be called during init level 0.
+ */
+void	SkEventInit(
+SK_AC	*pAC,	/* Adapter context */
+SK_IOC	Ioc,	/* IO context */
+int		Level)	/* Init level */
+{
+	switch (Level) {
+	case SK_INIT_DATA:
+		pAC->Event.EvPut = pAC->Event.EvGet = pAC->Event.EvQueue;
+		break;
+	default:
+		break;
+	}
+}
+
+/*
+ * add event to queue
+ */
+void	SkEventQueue(
+SK_AC		*pAC,	/* Adapters context */
+SK_U32		Class,	/* Event Class */
+SK_U32		Event,	/* Event to be queued */
+SK_EVPARA	Para)	/* Event parameter */
+{
+	pAC->Event.EvPut->Class = Class;
+	pAC->Event.EvPut->Event = Event;
+	pAC->Event.EvPut->Para = Para;
+	
+	if (++pAC->Event.EvPut == &pAC->Event.EvQueue[SK_MAX_EVENT])
+		pAC->Event.EvPut = pAC->Event.EvQueue;
+
+	if (pAC->Event.EvPut == pAC->Event.EvGet) {
+		SK_ERR_LOG(pAC, SK_ERRCL_NORES, SKERR_Q_E001, SKERR_Q_E001MSG);
+	}
+}
+
+/*
+ * event dispatcher
+ *	while event queue is not empty
+ *		get event from queue
+ *		send command to state machine
+ *	end
+ *	return error reported by individual Event function
+ *		0 if no error occured.
+ */
+int	SkEventDispatcher(
+SK_AC	*pAC,	/* Adapters Context */
+SK_IOC	Ioc)	/* Io context */
+{
+	SK_EVENTELEM	*pEv;	/* pointer into queue */
+	SK_U32			Class;
+	int			Rtv;
+
+	pEv = pAC->Event.EvGet;
+	
+	PRINTF("dispatch get %x put %x\n", pEv, pAC->Event.ev_put);
+	
+	while (pEv != pAC->Event.EvPut) {
+		PRINTF("dispatch Class %d Event %d\n", pEv->Class, pEv->Event);
+
+		switch (Class = pEv->Class) {
+#ifndef SK_USE_LAC_EV
+#ifndef SK_SLIM
+		case SKGE_RLMT:		/* RLMT Event */
+			Rtv = SkRlmtEvent(pAC, Ioc, pEv->Event, pEv->Para);
+			break;
+		case SKGE_I2C:		/* I2C Event */
+			Rtv = SkI2cEvent(pAC, Ioc, pEv->Event, pEv->Para);
+			break;
+		case SKGE_PNMI:		/* PNMI Event */
+			Rtv = SkPnmiEvent(pAC, Ioc, pEv->Event, pEv->Para);
+			break;
+#endif	/* not SK_SLIM */
+#endif	/* not SK_USE_LAC_EV */
+		case SKGE_DRV:		/* Driver Event */
+			Rtv = SkDrvEvent(pAC, Ioc, pEv->Event, pEv->Para);
+			break;
+#ifndef SK_USE_SW_TIMER
+		case SKGE_HWAC:
+			Rtv = SkGeSirqEvent(pAC, Ioc, pEv->Event, pEv->Para);
+			break;
+#else /* !SK_USE_SW_TIMER */
+        case SKGE_SWT :
+			Rtv = SkSwtEvent(pAC, Ioc, pEv->Event, pEv->Para);
+			break;
+#endif /* !SK_USE_SW_TIMER */
+#ifdef SK_USE_LAC_EV
+		case SKGE_LACP :
+			Rtv = SkLacpEvent(pAC, Ioc, pEv->Event, pEv->Para);
+			break;
+		case SKGE_RSF :
+			Rtv = SkRsfEvent(pAC, Ioc, pEv->Event, pEv->Para);
+			break;
+		case SKGE_MARKER :
+			Rtv = SkMarkerEvent(pAC, Ioc, pEv->Event, pEv->Para);
+			break;
+		case SKGE_FD :
+			Rtv = SkFdEvent(pAC, Ioc, pEv->Event, pEv->Para);
+			break;
+#endif /* SK_USE_LAC_EV */
+#ifdef	SK_USE_CSUM
+		case SKGE_CSUM :
+			Rtv = SkCsEvent(pAC, Ioc, pEv->Event, pEv->Para);
+			break;
+#endif	/* SK_USE_CSUM */
+		default :
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_Q_E002, SKERR_Q_E002MSG);
+			Rtv = 0;
+		}
+
+		if (Rtv != 0) {
+			return(Rtv);
+		}
+
+		if (++pEv == &pAC->Event.EvQueue[SK_MAX_EVENT])
+			pEv = pAC->Event.EvQueue;
+
+		/* Renew get: it is used in queue_events to detect overruns */
+		pAC->Event.EvGet = pEv;
+	}
+
+	return(0);
+}
+
+/* End of file */
diff --git a/drivers/net/sk98lin/skrlmt.c b/drivers/net/sk98lin/skrlmt.c
new file mode 100644
index 0000000..be8d1cc
--- /dev/null
+++ b/drivers/net/sk98lin/skrlmt.c
@@ -0,0 +1,3257 @@
+/******************************************************************************
+ *
+ * Name:	skrlmt.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.69 $
+ * Date:	$Date: 2003/04/15 09:39:22 $
+ * Purpose:	Manage links on SK-NET Adapters, esp. redundant ones.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Description:
+ *
+ * This module contains code for Link ManagemenT (LMT) of SK-NET Adapters.
+ * It is mainly intended for adapters with more than one link.
+ * For such adapters, this module realizes Redundant Link ManagemenT (RLMT).
+ *
+ * Include File Hierarchy:
+ *
+ *	"skdrv1st.h"
+ *	"skdrv2nd.h"
+ *
+ ******************************************************************************/
+
+#ifndef	lint
+static const char SysKonnectFileId[] =
+	"@(#) $Id: skrlmt.c,v 1.69 2003/04/15 09:39:22 tschilli Exp $ (C) Marvell.";
+#endif	/* !defined(lint) */
+
+#define __SKRLMT_C
+
+#ifdef __cplusplus
+extern "C" {
+#endif	/* cplusplus */
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* defines ********************************************************************/
+
+#ifndef SK_HWAC_LINK_LED
+#define SK_HWAC_LINK_LED(a,b,c,d)
+#endif	/* !defined(SK_HWAC_LINK_LED) */
+
+#ifndef DEBUG
+#define RLMT_STATIC	static
+#else	/* DEBUG */
+#define RLMT_STATIC
+
+#ifndef SK_LITTLE_ENDIAN
+/* First 32 bits */
+#define OFFS_LO32	1
+
+/* Second 32 bits */
+#define OFFS_HI32	0
+#else	/* SK_LITTLE_ENDIAN */
+/* First 32 bits */
+#define OFFS_LO32	0
+
+/* Second 32 bits */
+#define OFFS_HI32	1
+#endif	/* SK_LITTLE_ENDIAN */
+
+#endif	/* DEBUG */
+
+/* ----- Private timeout values ----- */
+
+#define SK_RLMT_MIN_TO_VAL			   125000	/* 1/8 sec. */
+#define SK_RLMT_DEF_TO_VAL			  1000000	/* 1 sec. */
+#define SK_RLMT_PORTDOWN_TIM_VAL	   900000	/* another 0.9 sec. */
+#define SK_RLMT_PORTSTART_TIM_VAL	   100000	/* 0.1 sec. */
+#define SK_RLMT_PORTUP_TIM_VAL		  2500000	/* 2.5 sec. */
+#define SK_RLMT_SEG_TO_VAL			900000000	/* 15 min. */
+
+/* Assume tick counter increment is 1 - may be set OS-dependent. */
+#ifndef SK_TICK_INCR
+#define SK_TICK_INCR	SK_CONSTU64(1)
+#endif	/* !defined(SK_TICK_INCR) */
+
+/*
+ * Amount that a time stamp must be later to be recognized as "substantially
+ * later". This is about 1/128 sec, but above 1 tick counter increment.
+ */
+#define SK_RLMT_BC_DELTA		(1 + ((SK_TICKS_PER_SEC >> 7) > SK_TICK_INCR ? \
+									(SK_TICKS_PER_SEC >> 7) : SK_TICK_INCR))
+
+/* ----- Private RLMT defaults ----- */
+
+#define SK_RLMT_DEF_PREF_PORT	0					/* "Lower" port. */
+#define SK_RLMT_DEF_MODE 		SK_RLMT_CHECK_LINK	/* Default RLMT Mode. */
+
+/* ----- Private RLMT checking states ----- */
+
+#define SK_RLMT_RCS_SEG			1		/* RLMT Check State: check seg. */
+#define SK_RLMT_RCS_START_SEG	2		/* RLMT Check State: start check seg. */
+#define SK_RLMT_RCS_SEND_SEG	4		/* RLMT Check State: send BPDU packet */
+#define SK_RLMT_RCS_REPORT_SEG	8		/* RLMT Check State: report seg. */
+
+/* ----- Private PORT checking states ----- */
+
+#define SK_RLMT_PCS_TX			1		/* Port Check State: check tx. */
+#define SK_RLMT_PCS_RX			2		/* Port Check State: check rx. */
+
+/* ----- Private PORT events ----- */
+
+/* Note: Update simulation when changing these. */
+#define SK_RLMT_PORTSTART_TIM	1100	/* Port start timeout. */
+#define SK_RLMT_PORTUP_TIM		1101	/* Port can now go up. */
+#define SK_RLMT_PORTDOWN_RX_TIM	1102	/* Port did not receive once ... */
+#define SK_RLMT_PORTDOWN		1103	/* Port went down. */
+#define SK_RLMT_PORTDOWN_TX_TIM	1104	/* Partner did not receive ... */
+
+/* ----- Private RLMT events ----- */
+
+/* Note: Update simulation when changing these. */
+#define SK_RLMT_TIM				2100	/* RLMT timeout. */
+#define SK_RLMT_SEG_TIM			2101	/* RLMT segmentation check timeout. */
+
+#define TO_SHORTEN(tim)	((tim) / 2)
+
+/* Error numbers and messages. */
+#define SKERR_RLMT_E001		(SK_ERRBASE_RLMT + 0)
+#define SKERR_RLMT_E001_MSG	"No Packet."
+#define SKERR_RLMT_E002		(SKERR_RLMT_E001 + 1)
+#define SKERR_RLMT_E002_MSG	"Short Packet."
+#define SKERR_RLMT_E003		(SKERR_RLMT_E002 + 1)
+#define SKERR_RLMT_E003_MSG	"Unknown RLMT event."
+#define SKERR_RLMT_E004		(SKERR_RLMT_E003 + 1)
+#define SKERR_RLMT_E004_MSG	"PortsUp incorrect."
+#define SKERR_RLMT_E005		(SKERR_RLMT_E004 + 1)
+#define SKERR_RLMT_E005_MSG	\
+ "Net seems to be segmented (different root bridges are reported on the ports)."
+#define SKERR_RLMT_E006		(SKERR_RLMT_E005 + 1)
+#define SKERR_RLMT_E006_MSG	"Duplicate MAC Address detected."
+#define SKERR_RLMT_E007		(SKERR_RLMT_E006 + 1)
+#define SKERR_RLMT_E007_MSG	"LinksUp incorrect."
+#define SKERR_RLMT_E008		(SKERR_RLMT_E007 + 1)
+#define SKERR_RLMT_E008_MSG	"Port not started but link came up."
+#define SKERR_RLMT_E009		(SKERR_RLMT_E008 + 1)
+#define SKERR_RLMT_E009_MSG	"Corrected illegal setting of Preferred Port."
+#define SKERR_RLMT_E010		(SKERR_RLMT_E009 + 1)
+#define SKERR_RLMT_E010_MSG	"Ignored illegal Preferred Port."
+
+/* LLC field values. */
+#define LLC_COMMAND_RESPONSE_BIT		1
+#define LLC_TEST_COMMAND				0xE3
+#define LLC_UI							0x03
+
+/* RLMT Packet fields. */
+#define	SK_RLMT_DSAP					0
+#define	SK_RLMT_SSAP					0
+#define SK_RLMT_CTRL					(LLC_TEST_COMMAND)
+#define SK_RLMT_INDICATOR0				0x53	/* S */
+#define SK_RLMT_INDICATOR1				0x4B	/* K */
+#define SK_RLMT_INDICATOR2				0x2D	/* - */
+#define SK_RLMT_INDICATOR3				0x52	/* R */
+#define SK_RLMT_INDICATOR4				0x4C	/* L */
+#define SK_RLMT_INDICATOR5				0x4D	/* M */
+#define SK_RLMT_INDICATOR6				0x54	/* T */
+#define SK_RLMT_PACKET_VERSION			0
+
+/* RLMT SPT Flag values. */
+#define	SK_RLMT_SPT_FLAG_CHANGE			0x01
+#define	SK_RLMT_SPT_FLAG_CHANGE_ACK		0x80
+
+/* RLMT SPT Packet fields. */
+#define	SK_RLMT_SPT_DSAP				0x42
+#define	SK_RLMT_SPT_SSAP				0x42
+#define SK_RLMT_SPT_CTRL				(LLC_UI)
+#define	SK_RLMT_SPT_PROTOCOL_ID0		0x00
+#define	SK_RLMT_SPT_PROTOCOL_ID1		0x00
+#define	SK_RLMT_SPT_PROTOCOL_VERSION_ID	0x00
+#define	SK_RLMT_SPT_BPDU_TYPE			0x00
+#define	SK_RLMT_SPT_FLAGS				0x00	/* ?? */
+#define	SK_RLMT_SPT_ROOT_ID0			0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_ROOT_ID1			0xFF	/* Lowest possible priority. */
+
+/* Remaining 6 bytes will be the current port address. */
+#define	SK_RLMT_SPT_ROOT_PATH_COST0		0x00
+#define	SK_RLMT_SPT_ROOT_PATH_COST1		0x00
+#define	SK_RLMT_SPT_ROOT_PATH_COST2		0x00
+#define	SK_RLMT_SPT_ROOT_PATH_COST3		0x00
+#define	SK_RLMT_SPT_BRIDGE_ID0			0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_BRIDGE_ID1			0xFF	/* Lowest possible priority. */
+
+/* Remaining 6 bytes will be the current port address. */
+#define	SK_RLMT_SPT_PORT_ID0			0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_PORT_ID1			0xFF	/* Lowest possible priority. */
+#define	SK_RLMT_SPT_MSG_AGE0			0x00
+#define	SK_RLMT_SPT_MSG_AGE1			0x00
+#define	SK_RLMT_SPT_MAX_AGE0			0x00
+#define	SK_RLMT_SPT_MAX_AGE1			0xFF
+#define	SK_RLMT_SPT_HELLO_TIME0			0x00
+#define	SK_RLMT_SPT_HELLO_TIME1			0xFF
+#define	SK_RLMT_SPT_FWD_DELAY0			0x00
+#define	SK_RLMT_SPT_FWD_DELAY1			0x40
+
+/* Size defines. */
+#define SK_RLMT_MIN_PACKET_SIZE			34
+#define SK_RLMT_MAX_PACKET_SIZE			(SK_RLMT_MAX_TX_BUF_SIZE)
+#define SK_PACKET_DATA_LEN				(SK_RLMT_MAX_PACKET_SIZE - \
+										SK_RLMT_MIN_PACKET_SIZE)
+
+/* ----- RLMT packet types ----- */
+#define SK_PACKET_ANNOUNCE				1	/* Port announcement. */
+#define SK_PACKET_ALIVE					2	/* Alive packet to port. */
+#define SK_PACKET_ADDR_CHANGED			3	/* Port address changed. */
+#define SK_PACKET_CHECK_TX				4	/* Check your tx line. */
+
+#ifdef SK_LITTLE_ENDIAN
+#define SK_U16_TO_NETWORK_ORDER(Val,Addr) { \
+	SK_U8	*_Addr = (SK_U8*)(Addr); \
+	SK_U16	_Val = (SK_U16)(Val); \
+	*_Addr++ = (SK_U8)(_Val >> 8); \
+	*_Addr = (SK_U8)(_Val & 0xFF); \
+}
+#endif	/* SK_LITTLE_ENDIAN */
+
+#ifdef SK_BIG_ENDIAN
+#define SK_U16_TO_NETWORK_ORDER(Val,Addr) (*(SK_U16*)(Addr) = (SK_U16)(Val))
+#endif	/* SK_BIG_ENDIAN */
+
+#define AUTONEG_FAILED	SK_FALSE
+#define AUTONEG_SUCCESS	SK_TRUE
+
+
+/* typedefs *******************************************************************/
+
+/* RLMT packet.  Length: SK_RLMT_MAX_PACKET_SIZE (60) bytes. */
+typedef struct s_RlmtPacket {
+	SK_U8	DstAddr[SK_MAC_ADDR_LEN];
+	SK_U8	SrcAddr[SK_MAC_ADDR_LEN];
+	SK_U8	TypeLen[2];
+	SK_U8	DSap;
+	SK_U8	SSap;
+	SK_U8	Ctrl;
+	SK_U8	Indicator[7];
+	SK_U8	RlmtPacketType[2];
+	SK_U8	Align1[2];
+	SK_U8	Random[4];				/* Random value of requesting(!) station. */
+	SK_U8	RlmtPacketVersion[2];	/* RLMT Packet version. */
+	SK_U8	Data[SK_PACKET_DATA_LEN];
+} SK_RLMT_PACKET;
+
+typedef struct s_SpTreeRlmtPacket {
+	SK_U8	DstAddr[SK_MAC_ADDR_LEN];
+	SK_U8	SrcAddr[SK_MAC_ADDR_LEN];
+	SK_U8	TypeLen[2];
+	SK_U8	DSap;
+	SK_U8	SSap;
+	SK_U8	Ctrl;
+	SK_U8	ProtocolId[2];
+	SK_U8	ProtocolVersionId;
+	SK_U8	BpduType;
+	SK_U8	Flags;
+	SK_U8	RootId[8];
+	SK_U8	RootPathCost[4];
+	SK_U8	BridgeId[8];
+	SK_U8	PortId[2];
+	SK_U8	MessageAge[2];
+	SK_U8	MaxAge[2];
+	SK_U8	HelloTime[2];
+	SK_U8	ForwardDelay[2];
+} SK_SPTREE_PACKET;
+
+/* global variables ***********************************************************/
+
+SK_MAC_ADDR	SkRlmtMcAddr =	{{0x01,  0x00,  0x5A,  0x52,  0x4C,  0x4D}};
+SK_MAC_ADDR	BridgeMcAddr =	{{0x01,  0x80,  0xC2,  0x00,  0x00,  0x00}};
+
+/* local variables ************************************************************/
+
+/* None. */
+
+/* functions ******************************************************************/
+
+RLMT_STATIC void	SkRlmtCheckSwitch(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	NetIdx);
+RLMT_STATIC void	SkRlmtCheckSeg(
+	SK_AC	*pAC,
+	SK_IOC	IoC,
+	SK_U32	NetIdx);
+RLMT_STATIC void	SkRlmtEvtSetNets(
+	SK_AC		*pAC,
+	SK_IOC		IoC,
+	SK_EVPARA	Para);
+
+/******************************************************************************
+ *
+ *	SkRlmtInit - initialize data, set state to init
+ *
+ * Description:
+ *
+ *	SK_INIT_DATA
+ *	============
+ *
+ *	This routine initializes all RLMT-related variables to a known state.
+ *	The initial state is SK_RLMT_RS_INIT.
+ *	All ports are initialized to SK_RLMT_PS_INIT.
+ *
+ *
+ *	SK_INIT_IO
+ *	==========
+ *
+ *	Nothing.
+ *
+ *
+ *	SK_INIT_RUN
+ *	===========
+ *
+ *	Determine the adapter's random value.
+ *	Set the hw registers, the "logical MAC address", the
+ *	RLMT multicast address, and eventually the BPDU multicast address.
+ *
+ * Context:
+ *	init, pageable
+ *
+ * Returns:
+ *	Nothing.
+ */
+void	SkRlmtInit(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* I/O Context */
+int		Level)	/* Initialization Level */
+{
+	SK_U32		i, j;
+	SK_U64		Random;
+	SK_EVPARA	Para;
+    SK_MAC_ADDR		VirtualMacAddress;
+    SK_MAC_ADDR		PhysicalAMacAddress;
+    SK_BOOL		VirtualMacAddressSet;
+    SK_BOOL		PhysicalAMacAddressSet;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT,
+		("RLMT Init level %d.\n", Level))
+
+	switch (Level) {
+	case SK_INIT_DATA:	/* Initialize data structures. */
+		SK_MEMSET((char *)&pAC->Rlmt, 0, sizeof(SK_RLMT));
+
+		for (i = 0; i < SK_MAX_MACS; i++) {
+			pAC->Rlmt.Port[i].PortState = SK_RLMT_PS_INIT;
+			pAC->Rlmt.Port[i].LinkDown = SK_TRUE;
+			pAC->Rlmt.Port[i].PortDown = SK_TRUE;
+			pAC->Rlmt.Port[i].PortStarted = SK_FALSE;
+			pAC->Rlmt.Port[i].PortNoRx = SK_FALSE;
+			pAC->Rlmt.Port[i].RootIdSet = SK_FALSE;
+			pAC->Rlmt.Port[i].PortNumber = i;
+			pAC->Rlmt.Port[i].Net = &pAC->Rlmt.Net[0];
+			pAC->Rlmt.Port[i].AddrPort = &pAC->Addr.Port[i];
+		}
+
+		pAC->Rlmt.NumNets = 1;
+		for (i = 0; i < SK_MAX_NETS; i++) {
+			pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
+			pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
+			pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
+			pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;	  /* Automatic. */
+			/* Just assuming. */
+			pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
+			pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
+			pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
+			pAC->Rlmt.Net[i].NetNumber = i;
+		}
+
+		pAC->Rlmt.Net[0].Port[0] = &pAC->Rlmt.Port[0];
+		pAC->Rlmt.Net[0].Port[1] = &pAC->Rlmt.Port[1];
+#if SK_MAX_NETS > 1
+		pAC->Rlmt.Net[1].Port[0] = &pAC->Rlmt.Port[1];
+#endif	/* SK_MAX_NETS > 1 */
+		break;
+
+	case SK_INIT_IO:	/* GIMacsFound first available here. */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_INIT,
+			("RLMT: %d MACs were detected.\n", pAC->GIni.GIMacsFound))
+
+		pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound;
+
+		/* Initialize HW registers? */
+		if (pAC->GIni.GIMacsFound == 1) {
+			Para.Para32[0] = SK_RLMT_MODE_CLS;
+			Para.Para32[1] = 0;
+			(void)SkRlmtEvent(pAC, IoC, SK_RLMT_MODE_CHANGE, Para);
+		}
+		break;
+
+	case SK_INIT_RUN:
+		/* Ensure RLMT is set to one net. */
+		if (pAC->Rlmt.NumNets > 1) {
+			Para.Para32[0] = 1;
+			Para.Para32[1] = -1;
+			SkRlmtEvtSetNets(pAC, IoC, Para);
+		}
+
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			Random = SkOsGetTime(pAC);
+			*(SK_U32*)&pAC->Rlmt.Port[i].Random = *(SK_U32*)&Random;
+
+			for (j = 0; j < 4; j++) {
+				pAC->Rlmt.Port[i].Random[j] ^= pAC->Rlmt.Port[i].AddrPort->
+					CurrentMacAddress.a[SK_MAC_ADDR_LEN - 1 - j];
+			}
+
+			(void)SkAddrMcClear(pAC, IoC, i, SK_ADDR_PERMANENT | SK_MC_SW_ONLY);
+			
+			/* Add RLMT MC address. */
+			(void)SkAddrMcAdd(pAC, IoC, i, &SkRlmtMcAddr, SK_ADDR_PERMANENT);
+
+			if (pAC->Rlmt.Net[0].RlmtMode & SK_RLMT_CHECK_SEG) {
+				/* Add BPDU MC address. */
+				(void)SkAddrMcAdd(pAC, IoC, i, &BridgeMcAddr, SK_ADDR_PERMANENT);
+			}
+
+			(void)SkAddrMcUpdate(pAC, IoC, i);
+		}
+
+    	VirtualMacAddressSet = SK_FALSE;
+		/* Read virtual MAC address from Control Register File. */
+		for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+			
+            SK_IN8(IoC, B2_MAC_1 + j, &VirtualMacAddress.a[j]);
+            VirtualMacAddressSet |= VirtualMacAddress.a[j];
+		}
+    	
+        PhysicalAMacAddressSet = SK_FALSE;
+		/* Read physical MAC address for MAC A from Control Register File. */
+		for (j = 0; j < SK_MAC_ADDR_LEN; j++) {
+			
+            SK_IN8(IoC, B2_MAC_2 + j, &PhysicalAMacAddress.a[j]);
+            PhysicalAMacAddressSet |= PhysicalAMacAddress.a[j];
+		}
+
+        /* check if the two mac addresses contain reasonable values */
+        if (!VirtualMacAddressSet || !PhysicalAMacAddressSet) {
+
+            pAC->Rlmt.RlmtOff = SK_TRUE;
+        }
+
+        /* if the two mac addresses are equal switch off the RLMT_PRE_LOOKAHEAD
+           and the RLMT_LOOKAHEAD macros */
+        else if (SK_ADDR_EQUAL(PhysicalAMacAddress.a, VirtualMacAddress.a)) {
+
+            pAC->Rlmt.RlmtOff = SK_TRUE;
+        }
+		else {
+			pAC->Rlmt.RlmtOff = SK_FALSE;
+		}
+		break;
+
+	default:	/* error */
+		break;
+	}
+	return;
+}	/* SkRlmtInit */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtBuildCheckChain - build the check chain
+ *
+ * Description:
+ *	This routine builds the local check chain:
+ *	- Each port that is up checks the next port.
+ *	- The last port that is up checks the first port that is up.
+ *
+ * Notes:
+ *	- Currently only local ports are considered when building the chain.
+ *	- Currently the SuspectState is just reset;
+ *	  it would be better to save it ...
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtBuildCheckChain(
+SK_AC	*pAC,	/* Adapter Context */
+SK_U32	NetIdx)	/* Net Number */
+{
+	SK_U32			i;
+	SK_U32			NumMacsUp;
+	SK_RLMT_PORT *	FirstMacUp;
+	SK_RLMT_PORT *	PrevMacUp;
+
+	FirstMacUp	= NULL;
+	PrevMacUp	= NULL;
+	
+	if (!(pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) {
+		for (i = 0; i < pAC->Rlmt.Net[i].NumPorts; i++) {
+			pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0;
+		}
+		return;	/* Done. */
+	}
+			
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SkRlmtBuildCheckChain.\n"))
+
+	NumMacsUp = 0;
+
+	for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
+		pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked = 0;
+		pAC->Rlmt.Net[NetIdx].Port[i]->PortsSuspect = 0;
+		pAC->Rlmt.Net[NetIdx].Port[i]->CheckingState &=
+			~(SK_RLMT_PCS_RX | SK_RLMT_PCS_TX);
+
+		/*
+		 * If more than two links are detected we should consider
+		 * checking at least two other ports:
+		 * 1. the next port that is not LinkDown and
+		 * 2. the next port that is not PortDown.
+		 */
+		if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) {
+			if (NumMacsUp == 0) {
+				FirstMacUp = pAC->Rlmt.Net[NetIdx].Port[i];
+			}
+			else {
+				PrevMacUp->PortCheck[
+					pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked].CheckAddr =
+					pAC->Rlmt.Net[NetIdx].Port[i]->AddrPort->CurrentMacAddress;
+				PrevMacUp->PortCheck[
+					PrevMacUp->PortsChecked].SuspectTx = SK_FALSE;
+				PrevMacUp->PortsChecked++;
+			}
+			PrevMacUp = pAC->Rlmt.Net[NetIdx].Port[i];
+			NumMacsUp++;
+		}
+	}
+
+	if (NumMacsUp > 1) {
+		PrevMacUp->PortCheck[PrevMacUp->PortsChecked].CheckAddr =
+			FirstMacUp->AddrPort->CurrentMacAddress;
+		PrevMacUp->PortCheck[PrevMacUp->PortsChecked].SuspectTx =
+			SK_FALSE;
+		PrevMacUp->PortsChecked++;
+	}
+
+#ifdef DEBUG
+	for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Port %d checks %d other ports: %2X.\n", i,
+				pAC->Rlmt.Net[NetIdx].Port[i]->PortsChecked,
+				pAC->Rlmt.Net[NetIdx].Port[i]->PortCheck[0].CheckAddr.a[5]))
+	}
+#endif	/* DEBUG */
+
+	return;
+}	/* SkRlmtBuildCheckChain */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtBuildPacket - build an RLMT packet
+ *
+ * Description:
+ *	This routine sets up an RLMT packet.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	NULL or pointer to RLMT mbuf
+ */
+RLMT_STATIC SK_MBUF	*SkRlmtBuildPacket(
+SK_AC		*pAC,		/* Adapter Context */
+SK_IOC		IoC,		/* I/O Context */
+SK_U32		PortNumber,	/* Sending port */
+SK_U16		PacketType,	/* RLMT packet type */
+SK_MAC_ADDR	*SrcAddr,	/* Source address */
+SK_MAC_ADDR	*DestAddr)	/* Destination address */
+{
+	int		i;
+	SK_U16		Length;
+	SK_MBUF		*pMb;
+	SK_RLMT_PACKET	*pPacket;
+
+#ifdef DEBUG
+	SK_U8	CheckSrc  = 0;
+	SK_U8	CheckDest = 0;
+	
+	for (i = 0; i < SK_MAC_ADDR_LEN; ++i) {
+		CheckSrc  |= SrcAddr->a[i];
+		CheckDest |= DestAddr->a[i];
+	}
+
+	if ((CheckSrc == 0) || (CheckDest == 0)) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_ERR,
+			("SkRlmtBuildPacket: Invalid %s%saddr.\n",
+			 (CheckSrc == 0 ? "Src" : ""), (CheckDest == 0 ? "Dest" : "")))
+	}
+#endif
+
+	if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) != NULL) {
+		pPacket = (SK_RLMT_PACKET*)pMb->pData;
+		for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+			pPacket->DstAddr[i] = DestAddr->a[i];
+			pPacket->SrcAddr[i] = SrcAddr->a[i];
+		}
+		pPacket->DSap = SK_RLMT_DSAP;
+		pPacket->SSap = SK_RLMT_SSAP;
+		pPacket->Ctrl = SK_RLMT_CTRL;
+		pPacket->Indicator[0] = SK_RLMT_INDICATOR0;
+		pPacket->Indicator[1] = SK_RLMT_INDICATOR1;
+		pPacket->Indicator[2] = SK_RLMT_INDICATOR2;
+		pPacket->Indicator[3] = SK_RLMT_INDICATOR3;
+		pPacket->Indicator[4] = SK_RLMT_INDICATOR4;
+		pPacket->Indicator[5] = SK_RLMT_INDICATOR5;
+		pPacket->Indicator[6] = SK_RLMT_INDICATOR6;
+
+		SK_U16_TO_NETWORK_ORDER(PacketType, &pPacket->RlmtPacketType[0]);
+
+		for (i = 0; i < 4; i++) {
+			pPacket->Random[i] = pAC->Rlmt.Port[PortNumber].Random[i];
+		}
+		
+		SK_U16_TO_NETWORK_ORDER(
+			SK_RLMT_PACKET_VERSION, &pPacket->RlmtPacketVersion[0]);
+
+		for (i = 0; i < SK_PACKET_DATA_LEN; i++) {
+			pPacket->Data[i] = 0x00;
+		}
+
+		Length = SK_RLMT_MAX_PACKET_SIZE;	/* Or smaller. */
+		pMb->Length = Length;
+		pMb->PortIdx = PortNumber;
+		Length -= 14;
+		SK_U16_TO_NETWORK_ORDER(Length, &pPacket->TypeLen[0]);
+
+		if (PacketType == SK_PACKET_ALIVE) {
+			pAC->Rlmt.Port[PortNumber].TxHelloCts++;
+		}
+	}
+
+	return (pMb);
+}	/* SkRlmtBuildPacket */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtBuildSpanningTreePacket - build spanning tree check packet
+ *
+ * Description:
+ *	This routine sets up a BPDU packet for spanning tree check.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	NULL or pointer to RLMT mbuf
+ */
+RLMT_STATIC SK_MBUF	*SkRlmtBuildSpanningTreePacket(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	PortNumber)	/* Sending port */
+{
+	unsigned			i;
+	SK_U16				Length;
+	SK_MBUF				*pMb;
+	SK_SPTREE_PACKET	*pSPacket;
+
+	if ((pMb = SkDrvAllocRlmtMbuf(pAC, IoC, SK_RLMT_MAX_PACKET_SIZE)) !=
+		NULL) {
+		pSPacket = (SK_SPTREE_PACKET*)pMb->pData;
+		for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+			pSPacket->DstAddr[i] = BridgeMcAddr.a[i];
+			pSPacket->SrcAddr[i] =
+				pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i];
+		}
+		pSPacket->DSap = SK_RLMT_SPT_DSAP;
+		pSPacket->SSap = SK_RLMT_SPT_SSAP;
+		pSPacket->Ctrl = SK_RLMT_SPT_CTRL;
+
+		pSPacket->ProtocolId[0] = SK_RLMT_SPT_PROTOCOL_ID0;
+		pSPacket->ProtocolId[1] = SK_RLMT_SPT_PROTOCOL_ID1;
+		pSPacket->ProtocolVersionId = SK_RLMT_SPT_PROTOCOL_VERSION_ID;
+		pSPacket->BpduType = SK_RLMT_SPT_BPDU_TYPE;
+		pSPacket->Flags = SK_RLMT_SPT_FLAGS;
+		pSPacket->RootId[0] = SK_RLMT_SPT_ROOT_ID0;
+		pSPacket->RootId[1] = SK_RLMT_SPT_ROOT_ID1;
+		pSPacket->RootPathCost[0] = SK_RLMT_SPT_ROOT_PATH_COST0;
+		pSPacket->RootPathCost[1] = SK_RLMT_SPT_ROOT_PATH_COST1;
+		pSPacket->RootPathCost[2] = SK_RLMT_SPT_ROOT_PATH_COST2;
+		pSPacket->RootPathCost[3] = SK_RLMT_SPT_ROOT_PATH_COST3;
+		pSPacket->BridgeId[0] = SK_RLMT_SPT_BRIDGE_ID0;
+		pSPacket->BridgeId[1] = SK_RLMT_SPT_BRIDGE_ID1;
+
+		/*
+		 * Use logical MAC address as bridge ID and filter these packets
+		 * on receive.
+		 */
+		for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+			pSPacket->BridgeId[i + 2] = pSPacket->RootId[i + 2] =
+				pAC->Addr.Net[pAC->Rlmt.Port[PortNumber].Net->NetNumber].
+					CurrentMacAddress.a[i];
+		}
+		pSPacket->PortId[0] = SK_RLMT_SPT_PORT_ID0;
+		pSPacket->PortId[1] = SK_RLMT_SPT_PORT_ID1;
+		pSPacket->MessageAge[0] = SK_RLMT_SPT_MSG_AGE0;
+		pSPacket->MessageAge[1] = SK_RLMT_SPT_MSG_AGE1;
+		pSPacket->MaxAge[0] = SK_RLMT_SPT_MAX_AGE0;
+		pSPacket->MaxAge[1] = SK_RLMT_SPT_MAX_AGE1;
+		pSPacket->HelloTime[0] = SK_RLMT_SPT_HELLO_TIME0;
+		pSPacket->HelloTime[1] = SK_RLMT_SPT_HELLO_TIME1;
+		pSPacket->ForwardDelay[0] = SK_RLMT_SPT_FWD_DELAY0;
+		pSPacket->ForwardDelay[1] = SK_RLMT_SPT_FWD_DELAY1;
+
+		Length = SK_RLMT_MAX_PACKET_SIZE;	/* Or smaller. */
+		pMb->Length = Length;
+		pMb->PortIdx = PortNumber;
+		Length -= 14;
+		SK_U16_TO_NETWORK_ORDER(Length, &pSPacket->TypeLen[0]);
+
+		pAC->Rlmt.Port[PortNumber].TxSpHelloReqCts++;
+	}
+
+	return (pMb);
+}	/* SkRlmtBuildSpanningTreePacket */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSend - build and send check packets
+ *
+ * Description:
+ *	Depending on the RLMT state and the checking state, several packets
+ *	are sent through the indicated port.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing.
+ */
+RLMT_STATIC void	SkRlmtSend(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	PortNumber)	/* Sending port */
+{
+	unsigned	j;
+	SK_EVPARA	Para;
+	SK_RLMT_PORT	*pRPort;
+
+	pRPort = &pAC->Rlmt.Port[PortNumber];
+	if (pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
+		if (pRPort->CheckingState & (SK_RLMT_PCS_TX | SK_RLMT_PCS_RX)) {
+			/* Port is suspicious. Send the RLMT packet to the RLMT mc addr. */
+			if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
+				SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
+				&SkRlmtMcAddr)) != NULL) {
+				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+			}
+		}
+		else {
+			/*
+			 * Send a directed RLMT packet to all ports that are
+			 * checked by the indicated port.
+			 */
+			for (j = 0; j < pRPort->PortsChecked; j++) {
+				if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
+					SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
+					&pRPort->PortCheck[j].CheckAddr)) != NULL) {
+					SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+				}
+			}
+		}
+	}
+
+	if ((pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) &&
+		(pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEND_SEG)) {
+		/*
+		 * Send a BPDU packet to make a connected switch tell us
+		 * the correct root bridge.
+		 */
+		if ((Para.pParaPtr =
+			SkRlmtBuildSpanningTreePacket(pAC, IoC, PortNumber)) != NULL) {
+			pAC->Rlmt.Port[PortNumber].Net->CheckingState &= ~SK_RLMT_RCS_SEND_SEG;
+			pRPort->RootIdSet = SK_FALSE;
+
+			SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_TX,
+				("SkRlmtSend: BPDU Packet on Port %u.\n", PortNumber))
+		}
+	}
+	return;
+}	/* SkRlmtSend */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtPortReceives - check if port is (going) down and bring it up
+ *
+ * Description:
+ *	This routine checks if a port who received a non-BPDU packet
+ *	needs to go up or needs to be stopped going down.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing.
+ */
+RLMT_STATIC void	SkRlmtPortReceives(
+SK_AC	*pAC,			/* Adapter Context */
+SK_IOC	IoC,			/* I/O Context */
+SK_U32	PortNumber)		/* Port to check */
+{
+	SK_RLMT_PORT	*pRPort;
+	SK_EVPARA		Para;
+
+	pRPort = &pAC->Rlmt.Port[PortNumber];
+	pRPort->PortNoRx = SK_FALSE;
+
+	if ((pRPort->PortState == SK_RLMT_PS_DOWN) &&
+		!(pRPort->CheckingState & SK_RLMT_PCS_TX)) {
+		/*
+		 * Port is marked down (rx), but received a non-BPDU packet.
+		 * Bring it up.
+		 */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+			("SkRlmtPacketReceive: Received on PortDown.\n"))
+
+		pRPort->PortState = SK_RLMT_PS_GOING_UP;
+		pRPort->GuTimeStamp = SkOsGetTime(pAC);
+		Para.Para32[0] = PortNumber;
+		Para.Para32[1] = (SK_U32)-1;
+		SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL,
+			SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para);
+		pRPort->CheckingState &= ~SK_RLMT_PCS_RX;
+		/* pAC->Rlmt.CheckSwitch = SK_TRUE; */
+		SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+	}	/* PortDown && !SuspectTx */
+	else if (pRPort->CheckingState & SK_RLMT_PCS_RX) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+			("SkRlmtPacketReceive: Stop bringing port down.\n"))
+		SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
+		pRPort->CheckingState &= ~SK_RLMT_PCS_RX;
+		/* pAC->Rlmt.CheckSwitch = SK_TRUE; */
+		SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+	}	/* PortGoingDown */
+
+	return;
+}	/* SkRlmtPortReceives */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtPacketReceive - receive a packet for closer examination
+ *
+ * Description:
+ *	This routine examines a packet more closely than SK_RLMT_LOOKAHEAD.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing.
+ */
+RLMT_STATIC void	SkRlmtPacketReceive(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* I/O Context */
+SK_MBUF	*pMb)	/* Received packet */
+{
+#ifdef xDEBUG
+	extern	void DumpData(char *p, int size);
+#endif	/* DEBUG */
+	int					i;
+	unsigned			j;
+	SK_U16				PacketType;
+	SK_U32				PortNumber;
+	SK_ADDR_PORT		*pAPort;
+	SK_RLMT_PORT		*pRPort;
+	SK_RLMT_PACKET		*pRPacket;
+	SK_SPTREE_PACKET	*pSPacket;
+	SK_EVPARA			Para;
+
+	PortNumber	= pMb->PortIdx;
+	pAPort = &pAC->Addr.Port[PortNumber];
+	pRPort = &pAC->Rlmt.Port[PortNumber];
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+		("SkRlmtPacketReceive: PortNumber == %d.\n", PortNumber))
+
+	pRPacket = (SK_RLMT_PACKET*)pMb->pData;
+	pSPacket = (SK_SPTREE_PACKET*)pRPacket;
+
+#ifdef xDEBUG
+	DumpData((char *)pRPacket, 32);
+#endif	/* DEBUG */
+
+	if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) != 0) {
+		SkRlmtPortReceives(pAC, IoC, PortNumber);
+	}
+	
+	/* Check destination address. */
+
+	if (!SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->DstAddr) &&
+		!SK_ADDR_EQUAL(SkRlmtMcAddr.a, pRPacket->DstAddr) &&
+		!SK_ADDR_EQUAL(BridgeMcAddr.a, pRPacket->DstAddr)) {
+
+		/* Not sent to current MAC or registered MC address => Trash it. */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+			("SkRlmtPacketReceive: Not for me.\n"))
+
+		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+		return;
+	}
+	else if (SK_ADDR_EQUAL(pAPort->CurrentMacAddress.a, pRPacket->SrcAddr)) {
+
+		/*
+		 * Was sent by same port (may happen during port switching
+		 * or in case of duplicate MAC addresses).
+		 */
+
+		/*
+		 * Check for duplicate address here:
+		 * If Packet.Random != My.Random => DupAddr.
+		 */
+		for (i = 3; i >= 0; i--) {
+			if (pRPort->Random[i] != pRPacket->Random[i]) {
+				break;
+			}
+		}
+
+		/*
+		 * CAUTION: Do not check for duplicate MAC address in RLMT Alive Reply
+		 * packets (they have the LLC_COMMAND_RESPONSE_BIT set in
+		 * pRPacket->SSap).
+		 */
+		if (i >= 0 && pRPacket->DSap == SK_RLMT_DSAP &&
+			pRPacket->Ctrl == SK_RLMT_CTRL &&
+			pRPacket->SSap == SK_RLMT_SSAP &&
+			pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 &&
+			pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 &&
+			pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 &&
+			pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 &&
+			pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 &&
+			pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 &&
+			pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Duplicate MAC Address.\n"))
+
+			/* Error Log entry. */
+			SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E006, SKERR_RLMT_E006_MSG);
+		}
+		else {
+			/* Simply trash it. */
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Sent by me.\n"))
+		}
+
+		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+		return;
+	}
+
+	/* Check SuspectTx entries. */
+	if (pRPort->PortsSuspect > 0) {
+		for (j = 0; j < pRPort->PortsChecked; j++) {
+			if (pRPort->PortCheck[j].SuspectTx &&
+				SK_ADDR_EQUAL(
+					pRPacket->SrcAddr, pRPort->PortCheck[j].CheckAddr.a)) {
+				pRPort->PortCheck[j].SuspectTx = SK_FALSE;
+				pRPort->PortsSuspect--;
+				break;
+			}
+		}
+	}
+
+	/* Determine type of packet. */
+	if (pRPacket->DSap == SK_RLMT_DSAP &&
+		pRPacket->Ctrl == SK_RLMT_CTRL &&
+		(pRPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SSAP &&
+		pRPacket->Indicator[0] == SK_RLMT_INDICATOR0 &&
+		pRPacket->Indicator[1] == SK_RLMT_INDICATOR1 &&
+		pRPacket->Indicator[2] == SK_RLMT_INDICATOR2 &&
+		pRPacket->Indicator[3] == SK_RLMT_INDICATOR3 &&
+		pRPacket->Indicator[4] == SK_RLMT_INDICATOR4 &&
+		pRPacket->Indicator[5] == SK_RLMT_INDICATOR5 &&
+		pRPacket->Indicator[6] == SK_RLMT_INDICATOR6) {
+
+		/* It's an RLMT packet. */
+		PacketType = (SK_U16)((pRPacket->RlmtPacketType[0] << 8) |
+			pRPacket->RlmtPacketType[1]);
+
+		switch (PacketType) {
+		case SK_PACKET_ANNOUNCE:	/* Not yet used. */
+#if 0
+			/* Build the check chain. */
+			SkRlmtBuildCheckChain(pAC);
+#endif	/* 0 */
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Announce.\n"))
+
+			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+			break;
+
+		case SK_PACKET_ALIVE:
+			if (pRPacket->SSap & LLC_COMMAND_RESPONSE_BIT) {
+				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+					("SkRlmtPacketReceive: Alive Reply.\n"))
+
+				if (!(pAC->Addr.Port[PortNumber].PromMode & SK_PROM_MODE_LLC) ||
+					SK_ADDR_EQUAL(
+						pRPacket->DstAddr, pAPort->CurrentMacAddress.a)) {
+					/* Obviously we could send something. */
+					if (pRPort->CheckingState & SK_RLMT_PCS_TX) {
+						pRPort->CheckingState &=  ~SK_RLMT_PCS_TX;
+						SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+					}
+
+					if ((pRPort->PortState == SK_RLMT_PS_DOWN) &&
+						!(pRPort->CheckingState & SK_RLMT_PCS_RX)) {
+						pRPort->PortState = SK_RLMT_PS_GOING_UP;
+						pRPort->GuTimeStamp = SkOsGetTime(pAC);
+
+						SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+
+						Para.Para32[0] = PortNumber;
+						Para.Para32[1] = (SK_U32)-1;
+						SkTimerStart(pAC, IoC, &pRPort->UpTimer,
+							SK_RLMT_PORTUP_TIM_VAL, SKGE_RLMT,
+							SK_RLMT_PORTUP_TIM, Para);
+					}
+				}
+
+				/* Mark sending port as alive? */
+				SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+			}
+			else {	/* Alive Request Packet. */
+				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+					("SkRlmtPacketReceive: Alive Request.\n"))
+
+				pRPort->RxHelloCts++;
+
+				/* Answer. */
+				for (i = 0; i < SK_MAC_ADDR_LEN; i++) {
+					pRPacket->DstAddr[i] = pRPacket->SrcAddr[i];
+					pRPacket->SrcAddr[i] =
+						pAC->Addr.Port[PortNumber].CurrentMacAddress.a[i];
+				}
+				pRPacket->SSap |= LLC_COMMAND_RESPONSE_BIT;
+
+				Para.pParaPtr = pMb;
+				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+			}
+			break;
+
+		case SK_PACKET_CHECK_TX:
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Check your tx line.\n"))
+
+			/* A port checking us requests us to check our tx line. */
+			pRPort->CheckingState |= SK_RLMT_PCS_TX;
+
+			/* Start PortDownTx timer. */
+			Para.Para32[0] = PortNumber;
+			Para.Para32[1] = (SK_U32)-1;
+			SkTimerStart(pAC, IoC, &pRPort->DownTxTimer,
+				SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT,
+				SK_RLMT_PORTDOWN_TX_TIM, Para);
+
+			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+
+			if ((Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, PortNumber,
+				SK_PACKET_ALIVE, &pAC->Addr.Port[PortNumber].CurrentMacAddress,
+				&SkRlmtMcAddr)) != NULL) {
+				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+			}
+			break;
+
+		case SK_PACKET_ADDR_CHANGED:
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Address Change.\n"))
+
+			/* Build the check chain. */
+			SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
+			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+			break;
+
+		default:
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+				("SkRlmtPacketReceive: Unknown RLMT packet.\n"))
+
+			/* RA;:;: ??? */
+			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+		}
+	}
+	else if (pSPacket->DSap == SK_RLMT_SPT_DSAP &&
+		pSPacket->Ctrl == SK_RLMT_SPT_CTRL &&
+		(pSPacket->SSap & ~LLC_COMMAND_RESPONSE_BIT) == SK_RLMT_SPT_SSAP) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+			("SkRlmtPacketReceive: BPDU Packet.\n"))
+
+		/* Spanning Tree packet. */
+		pRPort->RxSpHelloCts++;
+
+		if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pAC->Addr.Net[pAC->Rlmt.
+			Port[PortNumber].Net->NetNumber].CurrentMacAddress.a[0])) {
+			/*
+			 * Check segmentation if a new root bridge is set and
+			 * the segmentation check is not currently running.
+			 */
+			if (!SK_ADDR_EQUAL(&pSPacket->RootId[2], &pRPort->Root.Id[2]) &&
+				(pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) &&
+				(pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG)
+				!= 0 && (pAC->Rlmt.Port[PortNumber].Net->CheckingState &
+				SK_RLMT_RCS_SEG) == 0) {
+				pAC->Rlmt.Port[PortNumber].Net->CheckingState |=
+					SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG;
+			}
+
+			/* Store tree view of this port. */
+			for (i = 0; i < 8; i++) {
+				pRPort->Root.Id[i] = pSPacket->RootId[i];
+			}
+			pRPort->RootIdSet = SK_TRUE;
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP,
+				("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
+					PortNumber,
+					pRPort->Root.Id[0], pRPort->Root.Id[1],
+					pRPort->Root.Id[2], pRPort->Root.Id[3],
+					pRPort->Root.Id[4], pRPort->Root.Id[5],
+					pRPort->Root.Id[6], pRPort->Root.Id[7]))
+		}
+
+		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+		if ((pAC->Rlmt.Port[PortNumber].Net->CheckingState &
+			SK_RLMT_RCS_REPORT_SEG) != 0) {
+			SkRlmtCheckSeg(pAC, IoC, pAC->Rlmt.Port[PortNumber].Net->NetNumber);
+		}
+	}
+	else {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_RX,
+			("SkRlmtPacketReceive: Unknown Packet Type.\n"))
+
+		/* Unknown packet. */
+		SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+	}
+	return;
+}	/* SkRlmtPacketReceive */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtCheckPort - check if a port works
+ *
+ * Description:
+ *	This routine checks if a port whose link is up received something
+ *	and if it seems to transmit successfully.
+ *
+ *	# PortState: PsInit, PsLinkDown, PsDown, PsGoingUp, PsUp
+ *	# PortCheckingState (Bitfield): ChkTx, ChkRx, ChkSeg
+ *	# RlmtCheckingState (Bitfield): ChkSeg, StartChkSeg, ReportSeg
+ *
+ *	if (Rx - RxBpdu == 0) {	# No rx.
+ *		if (state == PsUp) {
+ *			PortCheckingState |= ChkRx
+ *		}
+ *		if (ModeCheckSeg && (Timeout ==
+ *			TO_SHORTEN(RLMT_DEFAULT_TIMEOUT))) {
+ *			RlmtCheckingState |= ChkSeg)
+ *			PortCheckingState |= ChkSeg
+ *		}
+ *		NewTimeout = TO_SHORTEN(Timeout)
+ *		if (NewTimeout < RLMT_MIN_TIMEOUT) {
+ *			NewTimeout = RLMT_MIN_TIMEOUT
+ *			PortState = PsDown
+ *			...
+ *		}
+ *	}
+ *	else {	# something was received
+ *		# Set counter to 0 at LinkDown?
+ *		#   No - rx may be reported after LinkDown ???
+ *		PortCheckingState &= ~ChkRx
+ *		NewTimeout = RLMT_DEFAULT_TIMEOUT
+ *		if (RxAck == 0) {
+ *			possible reasons:
+ *			is my tx line bad? --
+ *				send RLMT multicast and report
+ *				back internally? (only possible
+ *				between ports on same adapter)
+ *		}
+ *		if (RxChk == 0) {
+ *			possible reasons:
+ *			- tx line of port set to check me
+ *			  maybe bad
+ *			- no other port/adapter available or set
+ *			  to check me
+ *			- adapter checking me has a longer
+ *			  timeout
+ *			??? anything that can be done here?
+ *		}
+ *	}
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	New timeout value.
+ */
+RLMT_STATIC SK_U32	SkRlmtCheckPort(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	PortNumber)	/* Port to check */
+{
+	unsigned		i;
+	SK_U32			NewTimeout;
+	SK_RLMT_PORT	*pRPort;
+	SK_EVPARA		Para;
+
+	pRPort = &pAC->Rlmt.Port[PortNumber];
+
+	if ((pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot) == 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SkRlmtCheckPort %d: No (%d) receives in last time slot.\n",
+				PortNumber, pRPort->PacketsPerTimeSlot))
+
+		/*
+		 * Check segmentation if there was no receive at least twice
+		 * in a row (PortNoRx is already set) and the segmentation
+		 * check is not currently running.
+		 */
+
+		if (pRPort->PortNoRx && (pAC->Rlmt.Port[PortNumber].Net->LinksUp > 1) &&
+			(pAC->Rlmt.Port[PortNumber].Net->RlmtMode & SK_RLMT_CHECK_SEG) &&
+			!(pAC->Rlmt.Port[PortNumber].Net->CheckingState & SK_RLMT_RCS_SEG)) {
+			pAC->Rlmt.Port[PortNumber].Net->CheckingState |=
+				SK_RLMT_RCS_START_SEG | SK_RLMT_RCS_SEND_SEG;
+		}
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SkRlmtCheckPort: PortsSuspect %d, PcsRx %d.\n",
+				pRPort->PortsSuspect, pRPort->CheckingState & SK_RLMT_PCS_RX))
+
+		if (pRPort->PortState != SK_RLMT_PS_DOWN) {
+			NewTimeout = TO_SHORTEN(pAC->Rlmt.Port[PortNumber].Net->TimeoutValue);
+			if (NewTimeout < SK_RLMT_MIN_TO_VAL) {
+				NewTimeout = SK_RLMT_MIN_TO_VAL;
+			}
+
+			if (!(pRPort->CheckingState & SK_RLMT_PCS_RX)) {
+				Para.Para32[0] = PortNumber;
+				pRPort->CheckingState |= SK_RLMT_PCS_RX;
+
+				/*
+				 * What shall we do if the port checked by this one receives
+				 * our request frames?  What's bad - our rx line or his tx line?
+				 */
+				Para.Para32[1] = (SK_U32)-1;
+				SkTimerStart(pAC, IoC, &pRPort->DownRxTimer,
+					SK_RLMT_PORTDOWN_TIM_VAL, SKGE_RLMT,
+					SK_RLMT_PORTDOWN_RX_TIM, Para);
+
+				for (i = 0; i < pRPort->PortsChecked; i++) {
+					if (pRPort->PortCheck[i].SuspectTx) {
+						continue;
+					}
+					pRPort->PortCheck[i].SuspectTx = SK_TRUE;
+					pRPort->PortsSuspect++;
+					if ((Para.pParaPtr =
+						SkRlmtBuildPacket(pAC, IoC, PortNumber, SK_PACKET_CHECK_TX,
+							&pAC->Addr.Port[PortNumber].CurrentMacAddress,
+							&pRPort->PortCheck[i].CheckAddr)) != NULL) {
+						SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+					}
+				}
+			}
+		}
+		else {	/* PortDown -- or all partners suspect. */
+			NewTimeout = SK_RLMT_DEF_TO_VAL;
+		}
+		pRPort->PortNoRx = SK_TRUE;
+	}
+	else {	/* A non-BPDU packet was received. */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SkRlmtCheckPort %d: %d (%d) receives in last time slot.\n",
+				PortNumber,
+				pRPort->PacketsPerTimeSlot - pRPort->BpduPacketsPerTimeSlot,
+				pRPort->PacketsPerTimeSlot))
+		
+		SkRlmtPortReceives(pAC, IoC, PortNumber);
+		if (pAC->Rlmt.CheckSwitch) {
+			SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+		}
+
+		NewTimeout = SK_RLMT_DEF_TO_VAL;
+	}
+
+	return (NewTimeout);
+}	/* SkRlmtCheckPort */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSelectBcRx - select new active port, criteria 1 (CLP)
+ *
+ * Description:
+ *	This routine selects the port that received a broadcast frame
+ *	substantially later than all other ports.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	SK_BOOL
+ */
+RLMT_STATIC SK_BOOL	SkRlmtSelectBcRx(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	Active,		/* Active port */
+SK_U32	PrefPort,	/* Preferred port */
+SK_U32	*pSelect)	/* New active port */
+{
+	SK_U64		BcTimeStamp;
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+	BcTimeStamp = 0;	/* Not totally necessary, but feeling better. */
+	PortFound = SK_FALSE;
+	
+	/* Select port with the latest TimeStamp. */
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("TimeStamp Port %d (Down: %d, NoRx: %d): %08x %08x.\n",
+				i,
+   				pAC->Rlmt.Port[i].PortDown, pAC->Rlmt.Port[i].PortNoRx,
+				*((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_HI32),
+				*((SK_U32*)(&pAC->Rlmt.Port[i].BcTimeStamp) + OFFS_LO32)))
+
+		if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx) {
+			if (!PortFound || pAC->Rlmt.Port[i].BcTimeStamp > BcTimeStamp) {
+				BcTimeStamp = pAC->Rlmt.Port[i].BcTimeStamp;
+				*pSelect = i;
+				PortFound = SK_TRUE;
+			}
+		}
+	}
+
+	if (PortFound) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Port %d received the last broadcast.\n", *pSelect))
+
+		/* Look if another port's time stamp is similar. */
+		for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+			if (i == *pSelect) {
+				continue;
+			}
+			if (!pAC->Rlmt.Port[i].PortDown && !pAC->Rlmt.Port[i].PortNoRx &&
+				(pAC->Rlmt.Port[i].BcTimeStamp >
+				 BcTimeStamp - SK_RLMT_BC_DELTA ||
+				pAC->Rlmt.Port[i].BcTimeStamp +
+				 SK_RLMT_BC_DELTA > BcTimeStamp)) {
+				PortFound = SK_FALSE;
+				
+				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+					("Port %d received a broadcast at a similar time.\n", i))
+				break;
+			}
+		}
+	}
+
+#ifdef DEBUG
+	if (PortFound) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SELECT_BCRX found Port %d receiving the substantially "
+			 "latest broadcast (%u).\n",
+				*pSelect,
+				BcTimeStamp - pAC->Rlmt.Port[1 - *pSelect].BcTimeStamp))
+	}
+#endif	/* DEBUG */
+
+	return (PortFound);
+}	/* SkRlmtSelectBcRx */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSelectNotSuspect - select new active port, criteria 2 (CLP)
+ *
+ * Description:
+ *	This routine selects a good port (it is PortUp && !SuspectRx).
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	SK_BOOL
+ */
+RLMT_STATIC SK_BOOL	SkRlmtSelectNotSuspect(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	Active,		/* Active port */
+SK_U32	PrefPort,	/* Preferred port */
+SK_U32	*pSelect)	/* New active port */
+{
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+	PortFound = SK_FALSE;
+
+	/* Select first port that is PortUp && !SuspectRx. */
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		if (!pAC->Rlmt.Port[i].PortDown &&
+			!(pAC->Rlmt.Port[i].CheckingState & SK_RLMT_PCS_RX)) {
+			*pSelect = i;
+			if (!pAC->Rlmt.Port[Active].PortDown &&
+				!(pAC->Rlmt.Port[Active].CheckingState & SK_RLMT_PCS_RX)) {
+				*pSelect = Active;
+			}
+			if (!pAC->Rlmt.Port[PrefPort].PortDown &&
+				!(pAC->Rlmt.Port[PrefPort].CheckingState & SK_RLMT_PCS_RX)) {
+				*pSelect = PrefPort;
+			}
+			PortFound = SK_TRUE;
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+				("SK_RLMT_SELECT_NOTSUSPECT found Port %d up and not check RX.\n",
+					*pSelect))
+			break;
+		}
+	}
+	return (PortFound);
+}	/* SkRlmtSelectNotSuspect */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSelectUp - select new active port, criteria 3, 4 (CLP)
+ *
+ * Description:
+ *	This routine selects a port that is up.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	SK_BOOL
+ */
+RLMT_STATIC SK_BOOL	SkRlmtSelectUp(
+SK_AC	*pAC,			/* Adapter Context */
+SK_IOC	IoC,			/* I/O Context */
+SK_U32	Active,			/* Active port */
+SK_U32	PrefPort,		/* Preferred port */
+SK_U32	*pSelect,		/* New active port */
+SK_BOOL	AutoNegDone)	/* Successfully auto-negotiated? */
+{
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+	PortFound = SK_FALSE;
+
+	/* Select first port that is PortUp. */
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_UP &&
+			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+			*pSelect = i;
+			if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_UP &&
+				pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) {
+				*pSelect = Active;
+			}
+			if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_UP &&
+				pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) {
+				*pSelect = PrefPort;
+			}
+			PortFound = SK_TRUE;
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+				("SK_RLMT_SELECT_UP found Port %d up.\n", *pSelect))
+			break;
+		}
+	}
+	return (PortFound);
+}	/* SkRlmtSelectUp */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSelectGoingUp - select new active port, criteria 5, 6 (CLP)
+ *
+ * Description:
+ *	This routine selects the port that is going up for the longest time.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	SK_BOOL
+ */
+RLMT_STATIC SK_BOOL	SkRlmtSelectGoingUp(
+SK_AC	*pAC,			/* Adapter Context */
+SK_IOC	IoC,			/* I/O Context */
+SK_U32	Active,			/* Active port */
+SK_U32	PrefPort,		/* Preferred port */
+SK_U32	*pSelect,		/* New active port */
+SK_BOOL	AutoNegDone)	/* Successfully auto-negotiated? */
+{
+	SK_U64		GuTimeStamp;
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+	GuTimeStamp = 0;
+	PortFound = SK_FALSE;
+
+	/* Select port that is PortGoingUp for the longest time. */
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP &&
+			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+			GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp;
+			*pSelect = i;
+			PortFound = SK_TRUE;
+			break;
+		}
+	}
+
+	if (!PortFound) {
+		return (SK_FALSE);
+	}
+
+	for (i = *pSelect + 1; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_GOING_UP &&
+			pAC->Rlmt.Port[i].GuTimeStamp < GuTimeStamp &&
+			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+			GuTimeStamp = pAC->Rlmt.Port[i].GuTimeStamp;
+			*pSelect = i;
+		}
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_SELECT_GOINGUP found Port %d going up.\n", *pSelect))
+	return (SK_TRUE);
+}	/* SkRlmtSelectGoingUp */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtSelectDown - select new active port, criteria 7, 8 (CLP)
+ *
+ * Description:
+ *	This routine selects a port that is down.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	SK_BOOL
+ */
+RLMT_STATIC SK_BOOL	SkRlmtSelectDown(
+SK_AC	*pAC,			/* Adapter Context */
+SK_IOC	IoC,			/* I/O Context */
+SK_U32	Active,			/* Active port */
+SK_U32	PrefPort,		/* Preferred port */
+SK_U32	*pSelect,		/* New active port */
+SK_BOOL	AutoNegDone)	/* Successfully auto-negotiated? */
+{
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+	PortFound = SK_FALSE;
+
+	/* Select first port that is PortDown. */
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		if (pAC->Rlmt.Port[i].PortState == SK_RLMT_PS_DOWN &&
+			pAC->GIni.GP[i].PAutoNegFail != AutoNegDone) {
+			*pSelect = i;
+			if (pAC->Rlmt.Port[Active].PortState == SK_RLMT_PS_DOWN &&
+				pAC->GIni.GP[Active].PAutoNegFail != AutoNegDone) {
+				*pSelect = Active;
+			}
+			if (pAC->Rlmt.Port[PrefPort].PortState == SK_RLMT_PS_DOWN &&
+				pAC->GIni.GP[PrefPort].PAutoNegFail != AutoNegDone) {
+				*pSelect = PrefPort;
+			}
+			PortFound = SK_TRUE;
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+				("SK_RLMT_SELECT_DOWN found Port %d down.\n", *pSelect))
+			break;
+		}
+	}
+	return (PortFound);
+}	/* SkRlmtSelectDown */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtCheckSwitch - select new active port and switch to it
+ *
+ * Description:
+ *	This routine decides which port should be the active one and queues
+ *	port switching if necessary.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing.
+ */
+RLMT_STATIC void	SkRlmtCheckSwitch(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* I/O Context */
+SK_U32	NetIdx)	/* Net index */
+{
+	SK_EVPARA	Para;
+	SK_U32		Active;
+	SK_U32		PrefPort;
+	SK_U32		i;
+	SK_BOOL		PortFound;
+
+	Active = pAC->Rlmt.Net[NetIdx].ActivePort;	/* Index of active port. */
+	PrefPort = pAC->Rlmt.Net[NetIdx].PrefPort;	/* Index of preferred port. */
+	PortFound = SK_FALSE;
+	pAC->Rlmt.CheckSwitch = SK_FALSE;
+
+#if 0	/* RW 2001/10/18 - active port becomes always prefered one */
+	if (pAC->Rlmt.Net[NetIdx].Preference == 0xFFFFFFFF) { /* Automatic */
+		/* disable auto-fail back */
+		PrefPort = Active;
+	}
+#endif
+
+	if (pAC->Rlmt.Net[NetIdx].LinksUp == 0) {
+		/* Last link went down - shut down the net. */
+		pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_DOWN;
+		Para.Para32[0] = SK_RLMT_NET_DOWN_TEMP;
+		Para.Para32[1] = NetIdx;
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para);
+
+		Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
+			Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber;
+		Para.Para32[1] = NetIdx;
+		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para);
+		return;
+	}	/* pAC->Rlmt.LinksUp == 0 */
+	else if (pAC->Rlmt.Net[NetIdx].LinksUp == 1 &&
+		pAC->Rlmt.Net[NetIdx].RlmtState == SK_RLMT_RS_NET_DOWN) {
+		/* First link came up - get the net up. */
+		pAC->Rlmt.Net[NetIdx].RlmtState = SK_RLMT_RS_NET_UP;
+
+		/*
+		 * If pAC->Rlmt.ActivePort != Para.Para32[0],
+		 * the DRV switches to the port that came up.
+		 */
+		for (i = 0; i < pAC->Rlmt.Net[NetIdx].NumPorts; i++) {
+			if (!pAC->Rlmt.Net[NetIdx].Port[i]->LinkDown) {
+				if (!pAC->Rlmt.Net[NetIdx].Port[Active]->LinkDown) {
+					i = Active;
+				}
+				if (!pAC->Rlmt.Net[NetIdx].Port[PrefPort]->LinkDown) {
+					i = PrefPort;
+				}
+				PortFound = SK_TRUE;
+				break;
+			}
+		}
+
+		if (PortFound) {
+			Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber;
+			Para.Para32[1] = NetIdx;
+			SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para);
+
+			pAC->Rlmt.Net[NetIdx].ActivePort = i;
+			Para.Para32[0] = pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber;
+			Para.Para32[1] = NetIdx;
+			SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_UP, Para);
+
+			if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
+				(Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC,
+				pAC->Rlmt.Net[NetIdx].Port[i]->PortNumber,
+				SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx].
+				CurrentMacAddress, &SkRlmtMcAddr)) != NULL) {
+				/*
+				 * Send announce packet to RLMT multicast address to force
+				 * switches to learn the new location of the logical MAC address.
+				 */
+				SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+			}
+		}
+		else {
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E007, SKERR_RLMT_E007_MSG);
+		}
+
+		return;
+	}	/* LinksUp == 1 && RlmtState == SK_RLMT_RS_NET_DOWN */
+	else {	/* Cannot be reached in dual-net mode. */
+		Para.Para32[0] = Active;
+
+		/*
+		 * Preselection:
+		 *	If RLMT Mode != CheckLinkState
+		 *		select port that received a broadcast frame substantially later
+		 *		than all other ports
+		 *	else select first port that is not SuspectRx
+		 *	else select first port that is PortUp
+		 *	else select port that is PortGoingUp for the longest time
+		 *	else select first port that is PortDown
+		 *	else stop.
+		 *
+		 * For the preselected port:
+		 *	If ActivePort is equal in quality, select ActivePort.
+		 *
+		 *	If PrefPort is equal in quality, select PrefPort.
+		 *
+		 *	If ActivePort != SelectedPort,
+		 *		If old ActivePort is LinkDown,
+		 *			SwitchHard
+		 *		else
+		 *			SwitchSoft
+		 */
+		/* check of ChgBcPrio flag added */
+		if ((pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) &&
+			(!pAC->Rlmt.Net[0].ChgBcPrio)) {
+			
+			if (!PortFound) {
+				PortFound = SkRlmtSelectBcRx(
+					pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+			}
+
+			if (!PortFound) {
+				PortFound = SkRlmtSelectNotSuspect(
+					pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+			}
+		}	/* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
+
+		/* with changed priority for last broadcast received */
+		if ((pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) &&
+			(pAC->Rlmt.Net[0].ChgBcPrio)) {
+			if (!PortFound) {
+				PortFound = SkRlmtSelectNotSuspect(
+					pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+			}
+
+			if (!PortFound) {
+				PortFound = SkRlmtSelectBcRx(
+					pAC, IoC, Active, PrefPort, &Para.Para32[1]);
+			}
+		}	/* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
+
+		if (!PortFound) {
+			PortFound = SkRlmtSelectUp(
+				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
+		}
+
+		if (!PortFound) {
+			PortFound = SkRlmtSelectUp(
+				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
+		}
+
+		if (!PortFound) {
+			PortFound = SkRlmtSelectGoingUp(
+				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
+		}
+
+		if (!PortFound) {
+			PortFound = SkRlmtSelectGoingUp(
+				pAC, IoC, Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
+		}
+
+		if (pAC->Rlmt.Net[0].RlmtMode != SK_RLMT_MODE_CLS) {
+			if (!PortFound) {
+				PortFound = SkRlmtSelectDown(pAC, IoC,
+					Active, PrefPort, &Para.Para32[1], AUTONEG_SUCCESS);
+			}
+
+			if (!PortFound) {
+				PortFound = SkRlmtSelectDown(pAC, IoC,
+					Active, PrefPort, &Para.Para32[1], AUTONEG_FAILED);
+			}
+		}	/* pAC->Rlmt.RlmtMode != SK_RLMT_MODE_CLS */
+
+		if (PortFound) {
+
+			if (Para.Para32[1] != Active) {
+				SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+					("Active: %d, Para1: %d.\n", Active, Para.Para32[1]))
+				pAC->Rlmt.Net[NetIdx].ActivePort = Para.Para32[1];
+				Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
+					Port[Para.Para32[0]]->PortNumber;
+				Para.Para32[1] = pAC->Rlmt.Net[NetIdx].
+					Port[Para.Para32[1]]->PortNumber;
+				SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[1], SK_LED_ACTIVE);
+				if (pAC->Rlmt.Port[Active].LinkDown) {
+					SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_HARD, Para);
+				}
+				else {
+					SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY);
+					SkEventQueue(pAC, SKGE_DRV, SK_DRV_SWITCH_SOFT, Para);
+				}
+				Para.Para32[1] = NetIdx;
+				Para.Para32[0] =
+					pAC->Rlmt.Net[NetIdx].Port[Para.Para32[0]]->PortNumber;
+				SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_DOWN, Para);
+				Para.Para32[0] = pAC->Rlmt.Net[NetIdx].
+					Port[pAC->Rlmt.Net[NetIdx].ActivePort]->PortNumber;
+				SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_ACTIVE_UP, Para);
+				if ((pAC->Rlmt.Net[NetIdx].RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
+					(Para.pParaPtr = SkRlmtBuildPacket(pAC, IoC, Para.Para32[0],
+					SK_PACKET_ANNOUNCE, &pAC->Addr.Net[NetIdx].CurrentMacAddress,
+					&SkRlmtMcAddr)) != NULL) {
+					/*
+					 * Send announce packet to RLMT multicast address to force
+					 * switches to learn the new location of the logical
+					 * MAC address.
+					 */
+					SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para);
+				}	/* (Para.pParaPtr = SkRlmtBuildPacket(...)) != NULL */
+			}	/* Para.Para32[1] != Active */
+		}	/* PortFound */
+		else {
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E004, SKERR_RLMT_E004_MSG);
+		}
+	}	/* LinksUp > 1 || LinksUp == 1 && RlmtState != SK_RLMT_RS_NET_DOWN */
+	return;
+}	/* SkRlmtCheckSwitch */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtCheckSeg - Report if segmentation is detected
+ *
+ * Description:
+ *	This routine checks if the ports see different root bridges and reports
+ *	segmentation in such a case.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing.
+ */
+RLMT_STATIC void	SkRlmtCheckSeg(
+SK_AC	*pAC,	/* Adapter Context */
+SK_IOC	IoC,	/* I/O Context */
+SK_U32	NetIdx)	/* Net number */
+{
+	SK_EVPARA	Para;
+	SK_RLMT_NET	*pNet;
+	SK_U32		i, j;
+	SK_BOOL		Equal;
+
+	pNet = &pAC->Rlmt.Net[NetIdx];
+	pNet->RootIdSet = SK_FALSE;
+	Equal = SK_TRUE;
+
+	for (i = 0; i < pNet->NumPorts; i++) {
+		if (pNet->Port[i]->LinkDown || !pNet->Port[i]->RootIdSet) {
+			continue;
+		}
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_DUMP,
+			("Root ID %d: %02x %02x %02x %02x %02x %02x %02x %02x.\n", i,
+				pNet->Port[i]->Root.Id[0], pNet->Port[i]->Root.Id[1],
+				pNet->Port[i]->Root.Id[2], pNet->Port[i]->Root.Id[3],
+				pNet->Port[i]->Root.Id[4], pNet->Port[i]->Root.Id[5],
+				pNet->Port[i]->Root.Id[6], pNet->Port[i]->Root.Id[7]))
+
+		if (!pNet->RootIdSet) {
+			pNet->Root = pNet->Port[i]->Root;
+			pNet->RootIdSet = SK_TRUE;
+			continue;
+		}
+
+		for (j = 0; j < 8; j ++) {
+			Equal &= pNet->Port[i]->Root.Id[j] == pNet->Root.Id[j];
+			if (!Equal) {
+				break;
+			}
+		}
+		
+		if (!Equal) {
+			SK_ERR_LOG(pAC, SK_ERRCL_COMM, SKERR_RLMT_E005, SKERR_RLMT_E005_MSG);
+			Para.Para32[0] = NetIdx;
+			Para.Para32[1] = (SK_U32)-1;
+			SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SEGMENTATION, Para);
+
+			pNet->CheckingState &= ~SK_RLMT_RCS_REPORT_SEG;
+
+			/* 2000-03-06 RA: New. */
+			Para.Para32[0] = NetIdx;
+			Para.Para32[1] = (SK_U32)-1;
+			SkTimerStart(pAC, IoC, &pNet->SegTimer, SK_RLMT_SEG_TO_VAL,
+				SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
+			break;
+		}
+	}	/* for (i = 0; i < pNet->NumPorts; i++) */
+
+	/* 2000-03-06 RA: Moved here. */
+	/* Segmentation check not running anymore. */
+	pNet->CheckingState &= ~SK_RLMT_RCS_SEG;
+
+}	/* SkRlmtCheckSeg */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtPortStart - initialize port variables and start port
+ *
+ * Description:
+ *	This routine initializes a port's variables and issues a PORT_START
+ *	to the HWAC module.  This handles retries if the start fails or the
+ *	link eventually goes down.
+ *
+ * Context:
+ *	runtime, pageable?
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtPortStart(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+SK_U32	PortNumber)	/* Port number */
+{
+	SK_EVPARA	Para;
+
+	pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_LINK_DOWN;
+	pAC->Rlmt.Port[PortNumber].PortStarted = SK_TRUE;
+	pAC->Rlmt.Port[PortNumber].LinkDown = SK_TRUE;
+	pAC->Rlmt.Port[PortNumber].PortDown = SK_TRUE;
+	pAC->Rlmt.Port[PortNumber].CheckingState = 0;
+	pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE;
+	Para.Para32[0] = PortNumber;
+	Para.Para32[1] = (SK_U32)-1;
+	SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_START, Para);
+}	/* SkRlmtPortStart */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtPortStartTim - PORT_START_TIM
+ *
+ * Description:
+ *	This routine handles PORT_START_TIM events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtPortStartTim(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */
+{
+	SK_U32			i;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTSTART_TIMEOUT Port %d Event BEGIN.\n", Para.Para32[0]))
+
+		if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTSTART_TIMEOUT Event EMPTY.\n"))
+		return;
+	}
+
+	/*
+	 * Used to start non-preferred ports if the preferred one
+	 * does not come up.
+	 * This timeout needs only be set when starting the first
+	 * (preferred) port.
+	 */
+	if (pAC->Rlmt.Port[Para.Para32[0]].LinkDown) {
+		/* PORT_START failed. */
+		for (i = 0; i < pAC->Rlmt.Port[Para.Para32[0]].Net->NumPorts; i++) {
+			if (!pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortStarted) {
+				SkRlmtPortStart(pAC, IoC,
+					pAC->Rlmt.Port[Para.Para32[0]].Net->Port[i]->PortNumber);
+			}
+		}
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTSTART_TIMEOUT Event END.\n"))
+}	/* SkRlmtEvtPortStartTim */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtLinkUp - LINK_UP
+ *
+ * Description:
+ *	This routine handles LLINK_UP events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtLinkUp(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 Undefined */
+{
+	SK_U32			i;
+	SK_RLMT_PORT	*pRPort;
+	SK_EVPARA		Para2;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_LINK_UP Port %d Event BEGIN.\n", Para.Para32[0]))
+
+	pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+	if (!pRPort->PortStarted) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E008, SKERR_RLMT_E008_MSG);
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+				("SK_RLMT_LINK_UP Event EMPTY.\n"))
+		return;
+	}
+
+	if (!pRPort->LinkDown) {
+		/* RA;:;: Any better solution? */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_LINK_UP Event EMPTY.\n"))
+		return;
+	}
+
+	SkTimerStop(pAC, IoC, &pRPort->UpTimer);
+	SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
+	SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+
+	/* Do something if timer already fired? */
+
+	pRPort->LinkDown = SK_FALSE;
+	pRPort->PortState = SK_RLMT_PS_GOING_UP;
+	pRPort->GuTimeStamp = SkOsGetTime(pAC);
+	pRPort->BcTimeStamp = 0;
+	pRPort->Net->LinksUp++;
+	if (pRPort->Net->LinksUp == 1) {
+		SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_ACTIVE);
+	}
+	else {
+		SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_STANDBY);
+	}
+
+	for (i = 0; i < pRPort->Net->NumPorts; i++) {
+		if (!pRPort->Net->Port[i]->PortStarted) {
+			SkRlmtPortStart(pAC, IoC, pRPort->Net->Port[i]->PortNumber);
+		}
+	}
+
+	SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+
+	if (pRPort->Net->LinksUp >= 2) {
+		if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) {
+			/* Build the check chain. */
+			SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
+		}
+	}
+
+	/* If the first link comes up, start the periodical RLMT timeout. */
+	if (pRPort->Net->NumPorts > 1 && pRPort->Net->LinksUp == 1 &&
+		(pRPort->Net->RlmtMode & SK_RLMT_CHECK_OTHERS) != 0) {
+		Para2.Para32[0] = pRPort->Net->NetNumber;
+		Para2.Para32[1] = (SK_U32)-1;
+		SkTimerStart(pAC, IoC, &pRPort->Net->LocTimer,
+			pRPort->Net->TimeoutValue, SKGE_RLMT, SK_RLMT_TIM, Para2);
+	}
+
+	Para2 = Para;
+	Para2.Para32[1] = (SK_U32)-1;
+	SkTimerStart(pAC, IoC, &pRPort->UpTimer, SK_RLMT_PORTUP_TIM_VAL,
+		SKGE_RLMT, SK_RLMT_PORTUP_TIM, Para2);
+	
+	/* Later: if (pAC->Rlmt.RlmtMode & SK_RLMT_CHECK_LOC_LINK) && */
+	if ((pRPort->Net->RlmtMode & SK_RLMT_TRANSPARENT) == 0 &&
+		(pRPort->Net->RlmtMode & SK_RLMT_CHECK_LINK) != 0 &&
+		(Para2.pParaPtr =
+			SkRlmtBuildPacket(pAC, IoC, Para.Para32[0], SK_PACKET_ANNOUNCE,
+			&pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress, &SkRlmtMcAddr)
+		) != NULL) {
+		/* Send "new" packet to RLMT multicast address. */
+		SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
+	}
+
+	if (pRPort->Net->RlmtMode & SK_RLMT_CHECK_SEG) {
+		if ((Para2.pParaPtr =
+			SkRlmtBuildSpanningTreePacket(pAC, IoC, Para.Para32[0])) != NULL) {
+			pAC->Rlmt.Port[Para.Para32[0]].RootIdSet = SK_FALSE;
+			pRPort->Net->CheckingState |=
+				SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG;
+
+			SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
+
+			Para.Para32[1] = (SK_U32)-1;
+			SkTimerStart(pAC, IoC, &pRPort->Net->SegTimer,
+				SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
+		}
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_LINK_UP Event END.\n"))
+}	/* SkRlmtEvtLinkUp */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtPortUpTim - PORT_UP_TIM
+ *
+ * Description:
+ *	This routine handles PORT_UP_TIM events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtPortUpTim(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */
+{
+	SK_RLMT_PORT	*pRPort;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTUP_TIM Port %d Event BEGIN.\n", Para.Para32[0]))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTUP_TIM Event EMPTY.\n"))
+		return;
+	}
+
+	pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+	if (pRPort->LinkDown || (pRPort->PortState == SK_RLMT_PS_UP)) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTUP_TIM Port %d Event EMPTY.\n", Para.Para32[0]))
+		return;
+	}
+
+	pRPort->PortDown = SK_FALSE;
+	pRPort->PortState = SK_RLMT_PS_UP;
+	pRPort->Net->PortsUp++;
+	if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) {
+		if (pAC->Rlmt.NumNets <= 1) {
+			SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+		}
+		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_UP, Para);
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTUP_TIM Event END.\n"))
+}	/* SkRlmtEvtPortUpTim */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtPortDownTim - PORT_DOWN_*
+ *
+ * Description:
+ *	This routine handles PORT_DOWN_* events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtPortDownX(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_U32		Event,	/* Event code */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */
+{
+	SK_RLMT_PORT	*pRPort;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTDOWN* Port %d Event (%d) BEGIN.\n",
+			Para.Para32[0], Event))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTDOWN* Event EMPTY.\n"))
+		return;
+	}
+
+	pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+	if (!pRPort->PortStarted || (Event == SK_RLMT_PORTDOWN_TX_TIM &&
+		!(pRPort->CheckingState & SK_RLMT_PCS_TX))) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORTDOWN* Event (%d) EMPTY.\n", Event))
+		return;
+	}
+	
+	/* Stop port's timers. */
+	SkTimerStop(pAC, IoC, &pRPort->UpTimer);
+	SkTimerStop(pAC, IoC, &pRPort->DownRxTimer);
+	SkTimerStop(pAC, IoC, &pRPort->DownTxTimer);
+
+	if (pRPort->PortState != SK_RLMT_PS_LINK_DOWN) {
+		pRPort->PortState = SK_RLMT_PS_DOWN;
+	}
+
+	if (!pRPort->PortDown) {
+		pRPort->Net->PortsUp--;
+		pRPort->PortDown = SK_TRUE;
+		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_PORT_DOWN, Para);
+	}
+
+	pRPort->PacketsPerTimeSlot = 0;
+	/* pRPort->DataPacketsPerTimeSlot = 0; */
+	pRPort->BpduPacketsPerTimeSlot = 0;
+	pRPort->BcTimeStamp = 0;
+
+	/*
+	 * RA;:;: To be checked:
+	 * - actions at RLMT_STOP: We should not switch anymore.
+	 */
+	if (pRPort->Net->RlmtState != SK_RLMT_RS_INIT) {
+		if (Para.Para32[0] ==
+			pRPort->Net->Port[pRPort->Net->ActivePort]->PortNumber) {
+			/* Active Port went down. */
+			SkRlmtCheckSwitch(pAC, IoC, pRPort->Net->NetNumber);
+		}
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORTDOWN* Event (%d) END.\n", Event))
+}	/* SkRlmtEvtPortDownX */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtLinkDown - LINK_DOWN
+ *
+ * Description:
+ *	This routine handles LINK_DOWN events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtLinkDown(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 Undefined */
+{
+	SK_RLMT_PORT	*pRPort;
+
+	pRPort = &pAC->Rlmt.Port[Para.Para32[0]];
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_LINK_DOWN Port %d Event BEGIN.\n", Para.Para32[0]))
+
+	if (!pAC->Rlmt.Port[Para.Para32[0]].LinkDown) {
+		pRPort->Net->LinksUp--;
+		pRPort->LinkDown = SK_TRUE;
+		pRPort->PortState = SK_RLMT_PS_LINK_DOWN;
+		SK_HWAC_LINK_LED(pAC, IoC, Para.Para32[0], SK_LED_OFF);
+
+		if ((pRPort->Net->RlmtMode & SK_RLMT_CHECK_LOC_LINK) != 0) {
+			/* Build the check chain. */
+			SkRlmtBuildCheckChain(pAC, pRPort->Net->NetNumber);
+		}
+
+		/* Ensure that port is marked down. */
+		Para.Para32[1] = -1;
+		(void)SkRlmtEvent(pAC, IoC, SK_RLMT_PORTDOWN, Para);
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_LINK_DOWN Event END.\n"))
+}	/* SkRlmtEvtLinkDown */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtPortAddr - PORT_ADDR
+ *
+ * Description:
+ *	This routine handles PORT_ADDR events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtPortAddr(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortNumber; SK_U32 -1 */
+{
+	SK_U32			i, j;
+	SK_RLMT_PORT	*pRPort;
+	SK_MAC_ADDR		*pOldMacAddr;
+	SK_MAC_ADDR		*pNewMacAddr;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PORT_ADDR Port %d Event BEGIN.\n", Para.Para32[0]))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORT_ADDR Event EMPTY.\n"))
+		return;
+	}
+
+	/* Port's physical MAC address changed. */
+	pOldMacAddr = &pAC->Addr.Port[Para.Para32[0]].PreviousMacAddress;
+	pNewMacAddr = &pAC->Addr.Port[Para.Para32[0]].CurrentMacAddress;
+
+	/*
+	 * NOTE: This is not scalable for solutions where ports are
+	 *	 checked remotely.  There, we need to send an RLMT
+	 *	 address change packet - and how do we ensure delivery?
+	 */
+	for (i = 0; i < (SK_U32)pAC->GIni.GIMacsFound; i++) {
+		pRPort = &pAC->Rlmt.Port[i];
+		for (j = 0; j < pRPort->PortsChecked; j++) {
+			if (SK_ADDR_EQUAL(
+				pRPort->PortCheck[j].CheckAddr.a, pOldMacAddr->a)) {
+				pRPort->PortCheck[j].CheckAddr = *pNewMacAddr;
+			}
+		}
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PORT_ADDR Event END.\n"))
+}	/* SkRlmtEvtPortAddr */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtStart - START
+ *
+ * Description:
+ *	This routine handles START events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtStart(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+	SK_EVPARA	Para2;
+	SK_U32		PortIdx;
+	SK_U32		PortNumber;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_START Net %d Event BEGIN.\n", Para.Para32[0]))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_START Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[0]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_START Event EMPTY.\n"))
+		return;
+	}
+
+	if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState != SK_RLMT_RS_INIT) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_START Event EMPTY.\n"))
+		return;
+	}
+
+	if (pAC->Rlmt.NetsStarted >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("All nets should have been started.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_START Event EMPTY.\n"))
+		return;
+	}
+
+	if (pAC->Rlmt.Net[Para.Para32[0]].PrefPort >=
+		pAC->Rlmt.Net[Para.Para32[0]].NumPorts) {
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E009, SKERR_RLMT_E009_MSG);
+
+		/* Change PrefPort to internal default. */
+		Para2.Para32[0] = 0xFFFFFFFF;
+		Para2.Para32[1] = Para.Para32[0];
+		(void)SkRlmtEvent(pAC, IoC, SK_RLMT_PREFPORT_CHANGE, Para2);
+	}
+
+	PortIdx = pAC->Rlmt.Net[Para.Para32[0]].PrefPort;
+	PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[PortIdx]->PortNumber;
+
+	pAC->Rlmt.Net[Para.Para32[0]].LinksUp = 0;
+	pAC->Rlmt.Net[Para.Para32[0]].PortsUp = 0;
+	pAC->Rlmt.Net[Para.Para32[0]].CheckingState = 0;
+	pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_NET_DOWN;
+
+	/* Start preferred port. */
+	SkRlmtPortStart(pAC, IoC, PortNumber);
+
+	/* Start Timer (for first port only). */
+	Para2.Para32[0] = PortNumber;
+	Para2.Para32[1] = (SK_U32)-1;
+	SkTimerStart(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer,
+		SK_RLMT_PORTSTART_TIM_VAL, SKGE_RLMT, SK_RLMT_PORTSTART_TIM, Para2);
+
+	pAC->Rlmt.NetsStarted++;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_START Event END.\n"))
+}	/* SkRlmtEvtStart */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtStop - STOP
+ *
+ * Description:
+ *	This routine handles STOP events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtStop(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+	SK_EVPARA	Para2;
+	SK_U32		PortNumber;
+	SK_U32		i;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STOP Net %d Event BEGIN.\n", Para.Para32[0]))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STOP Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[0]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STOP Event EMPTY.\n"))
+		return;
+	}
+
+	if (pAC->Rlmt.Net[Para.Para32[0]].RlmtState == SK_RLMT_RS_INIT) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STOP Event EMPTY.\n"))
+		return;
+	}
+
+	if (pAC->Rlmt.NetsStarted == 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("All nets are stopped.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STOP Event EMPTY.\n"))
+		return;
+	}
+
+	/* Stop RLMT timers. */
+	SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer);
+	SkTimerStop(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer);
+
+	/* Stop net. */
+	pAC->Rlmt.Net[Para.Para32[0]].RlmtState = SK_RLMT_RS_INIT;
+	pAC->Rlmt.Net[Para.Para32[0]].RootIdSet = SK_FALSE;
+	Para2.Para32[0] = SK_RLMT_NET_DOWN_FINAL;
+	Para2.Para32[1] = Para.Para32[0];			/* Net# */
+	SkEventQueue(pAC, SKGE_DRV, SK_DRV_NET_DOWN, Para2);
+
+	/* Stop ports. */
+	for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+		PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber;
+		if (pAC->Rlmt.Port[PortNumber].PortState != SK_RLMT_PS_INIT) {
+			SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].UpTimer);
+			SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownRxTimer);
+			SkTimerStop(pAC, IoC, &pAC->Rlmt.Port[PortNumber].DownTxTimer);
+
+			pAC->Rlmt.Port[PortNumber].PortState = SK_RLMT_PS_INIT;
+			pAC->Rlmt.Port[PortNumber].RootIdSet = SK_FALSE;
+			pAC->Rlmt.Port[PortNumber].PortStarted = SK_FALSE;
+			Para2.Para32[0] = PortNumber;
+			Para2.Para32[1] = (SK_U32)-1;
+			SkEventQueue(pAC, SKGE_HWAC, SK_HWEV_PORT_STOP, Para2);
+		}
+	}
+
+	pAC->Rlmt.NetsStarted--;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STOP Event END.\n"))
+}	/* SkRlmtEvtStop */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtTim - TIM
+ *
+ * Description:
+ *	This routine handles TIM events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtTim(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+	SK_RLMT_PORT	*pRPort;
+	SK_U32			Timeout;
+	SK_U32			NewTimeout;
+	SK_U32			PortNumber;
+	SK_U32			i;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_TIM Event BEGIN.\n"))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_TIM Event EMPTY.\n"))
+		return;
+	}
+
+	if ((pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_OTHERS) == 0 ||
+		pAC->Rlmt.Net[Para.Para32[0]].LinksUp == 0) {
+		/* Mode changed or all links down: No more link checking. */
+		return;
+	}
+
+#if 0
+	pAC->Rlmt.SwitchCheckCounter--;
+	if (pAC->Rlmt.SwitchCheckCounter == 0) {
+		pAC->Rlmt.SwitchCheckCounter;
+	}
+#endif	/* 0 */
+
+	NewTimeout = SK_RLMT_DEF_TO_VAL;
+	for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+		PortNumber = pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber;
+		pRPort = &pAC->Rlmt.Port[PortNumber];
+		if (!pRPort->LinkDown) {
+			Timeout = SkRlmtCheckPort(pAC, IoC, PortNumber);
+			if (Timeout < NewTimeout) {
+				NewTimeout = Timeout;
+			}
+
+			/*
+			 * These counters should be set to 0 for all ports before the
+			 * first frame is sent in the next loop.
+			 */
+			pRPort->PacketsPerTimeSlot = 0;
+			/* pRPort->DataPacketsPerTimeSlot = 0; */
+			pRPort->BpduPacketsPerTimeSlot = 0;
+		}
+	}
+	pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue = NewTimeout;
+
+	if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1) {
+		/*
+		 * If checking remote ports, also send packets if
+		 *   (LinksUp == 1) &&
+		 *   this port checks at least one (remote) port.
+		 */
+
+		/*
+		 * Must be new loop, as SkRlmtCheckPort can request to
+		 * check segmentation when e.g. checking the last port.
+		 */
+		for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+			if (!pAC->Rlmt.Net[Para.Para32[0]].Port[i]->LinkDown) {
+				SkRlmtSend(pAC, IoC,
+					pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber);
+			}
+		}
+	}
+
+	SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].LocTimer,
+		pAC->Rlmt.Net[Para.Para32[0]].TimeoutValue, SKGE_RLMT, SK_RLMT_TIM,
+		Para);
+
+	if (pAC->Rlmt.Net[Para.Para32[0]].LinksUp > 1 &&
+		(pAC->Rlmt.Net[Para.Para32[0]].RlmtMode & SK_RLMT_CHECK_SEG) &&
+		(pAC->Rlmt.Net[Para.Para32[0]].CheckingState & SK_RLMT_RCS_START_SEG)) {
+		SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[0]].SegTimer,
+			SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para);
+		pAC->Rlmt.Net[Para.Para32[0]].CheckingState &= ~SK_RLMT_RCS_START_SEG;
+		pAC->Rlmt.Net[Para.Para32[0]].CheckingState |=
+			SK_RLMT_RCS_SEG | SK_RLMT_RCS_REPORT_SEG;
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_TIM Event END.\n"))
+}	/* SkRlmtEvtTim */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtSegTim - SEG_TIM
+ *
+ * Description:
+ *	This routine handles SEG_TIM events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtSegTim(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+#ifdef xDEBUG
+	int j;
+#endif	/* DEBUG */
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_SEG_TIM Event BEGIN.\n"))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SEG_TIM Event EMPTY.\n"))
+		return;
+	}
+
+#ifdef xDEBUG
+	for (j = 0; j < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; j++) {
+		SK_ADDR_PORT	*pAPort;
+		SK_U32			k;
+		SK_U16			*InAddr;
+		SK_U8			InAddr8[6];
+
+		InAddr = (SK_U16 *)&InAddr8[0];
+		pAPort = pAC->Rlmt.Net[Para.Para32[0]].Port[j]->AddrPort;
+		for (k = 0; k < pAPort->NextExactMatchRlmt; k++) {
+			/* Get exact match address k from port j. */
+			XM_INADDR(IoC, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber,
+				XM_EXM(k), InAddr);
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+				("MC address %d on Port %u: %02x %02x %02x %02x %02x %02x --  %02x %02x %02x %02x %02x %02x.\n",
+					k, pAC->Rlmt.Net[Para.Para32[0]].Port[j]->PortNumber,
+					InAddr8[0], InAddr8[1], InAddr8[2],
+					InAddr8[3], InAddr8[4], InAddr8[5],
+					pAPort->Exact[k].a[0], pAPort->Exact[k].a[1],
+					pAPort->Exact[k].a[2], pAPort->Exact[k].a[3],
+					pAPort->Exact[k].a[4], pAPort->Exact[k].a[5]))
+		}
+	}
+#endif	/* xDEBUG */
+				
+	SkRlmtCheckSeg(pAC, IoC, Para.Para32[0]);
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SEG_TIM Event END.\n"))
+}	/* SkRlmtEvtSegTim */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtPacketRx - PACKET_RECEIVED
+ *
+ * Description:
+ *	This routine handles PACKET_RECEIVED events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtPacketRx(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_MBUF *pMb */
+{
+	SK_MBUF	*pMb;
+	SK_MBUF	*pNextMb;
+	SK_U32	NetNumber;
+
+	
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PACKET_RECEIVED Event BEGIN.\n"))
+
+	/* Should we ignore frames during port switching? */
+
+#ifdef DEBUG
+	pMb = Para.pParaPtr;
+	if (pMb == NULL) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL, ("No mbuf.\n"))
+	}
+	else if (pMb->pNext != NULL) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("More than one mbuf or pMb->pNext not set.\n"))
+	}
+#endif	/* DEBUG */
+
+	for (pMb = Para.pParaPtr; pMb != NULL; pMb = pNextMb) {
+		pNextMb = pMb->pNext;
+		pMb->pNext = NULL;
+
+		NetNumber = pAC->Rlmt.Port[pMb->PortIdx].Net->NetNumber;
+		if (pAC->Rlmt.Net[NetNumber].RlmtState == SK_RLMT_RS_INIT) {
+			SkDrvFreeRlmtMbuf(pAC, IoC, pMb);
+		}
+		else {
+			SkRlmtPacketReceive(pAC, IoC, pMb);
+		}
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PACKET_RECEIVED Event END.\n"))
+}	/* SkRlmtEvtPacketRx */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtStatsClear - STATS_CLEAR
+ *
+ * Description:
+ *	This routine handles STATS_CLEAR events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtStatsClear(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+	SK_U32			i;
+	SK_RLMT_PORT	*pRPort;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STATS_CLEAR Event BEGIN.\n"))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STATS_CLEAR Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[0]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STATS_CLEAR Event EMPTY.\n"))
+		return;
+	}
+
+	/* Clear statistics for logical and physical ports. */
+	for (i = 0; i < pAC->Rlmt.Net[Para.Para32[0]].NumPorts; i++) {
+		pRPort =
+			&pAC->Rlmt.Port[pAC->Rlmt.Net[Para.Para32[0]].Port[i]->PortNumber];
+		pRPort->TxHelloCts = 0;
+		pRPort->RxHelloCts = 0;
+		pRPort->TxSpHelloReqCts = 0;
+		pRPort->RxSpHelloCts = 0;
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STATS_CLEAR Event END.\n"))
+}	/* SkRlmtEvtStatsClear */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtStatsUpdate - STATS_UPDATE
+ *
+ * Description:
+ *	This routine handles STATS_UPDATE events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtStatsUpdate(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NetNumber; SK_U32 -1 */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STATS_UPDATE Event BEGIN.\n"))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STATS_UPDATE Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[0]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_STATS_UPDATE Event EMPTY.\n"))
+		return;
+	}
+
+	/* Update statistics - currently always up-to-date. */
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_STATS_UPDATE Event END.\n"))
+}	/* SkRlmtEvtStatsUpdate */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtPrefportChange - PREFPORT_CHANGE
+ *
+ * Description:
+ *	This routine handles PREFPORT_CHANGE events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtPrefportChange(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 PortIndex; SK_U32 NetNumber */
+{
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PREFPORT_CHANGE to Port %d Event BEGIN.\n", Para.Para32[0]))
+
+	if (Para.Para32[1] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[1]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n"))
+		return;
+	}
+
+	/* 0xFFFFFFFF == auto-mode. */
+	if (Para.Para32[0] == 0xFFFFFFFF) {
+		pAC->Rlmt.Net[Para.Para32[1]].PrefPort = SK_RLMT_DEF_PREF_PORT;
+	}
+	else {
+		if (Para.Para32[0] >= pAC->Rlmt.Net[Para.Para32[1]].NumPorts) {
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E010, SKERR_RLMT_E010_MSG);
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+				("SK_RLMT_PREFPORT_CHANGE Event EMPTY.\n"))
+			return;
+		}
+
+		pAC->Rlmt.Net[Para.Para32[1]].PrefPort = Para.Para32[0];
+	}
+
+	pAC->Rlmt.Net[Para.Para32[1]].Preference = Para.Para32[0];
+
+	if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) {
+		SkRlmtCheckSwitch(pAC, IoC, Para.Para32[1]);
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_PREFPORT_CHANGE Event END.\n"))
+}	/* SkRlmtEvtPrefportChange */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtSetNets - SET_NETS
+ *
+ * Description:
+ *	This routine handles SET_NETS events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtSetNets(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NumNets; SK_U32 -1 */
+{
+	int i;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_SET_NETS Event BEGIN.\n"))
+
+	if (Para.Para32[1] != (SK_U32)-1) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad Parameter.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SET_NETS Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] == 0 || Para.Para32[0] > SK_MAX_NETS ||
+		Para.Para32[0] > (SK_U32)pAC->GIni.GIMacsFound) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad number of nets: %d.\n", Para.Para32[0]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SET_NETS Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] == pAC->Rlmt.NumNets) {	/* No change. */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SET_NETS Event EMPTY.\n"))
+		return;
+	}
+
+	/* Entering and leaving dual mode only allowed while nets are stopped. */
+	if (pAC->Rlmt.NetsStarted > 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Changing dual mode only allowed while all nets are stopped.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SET_NETS Event EMPTY.\n"))
+		return;
+	}
+
+	if (Para.Para32[0] == 1) {
+		if (pAC->Rlmt.NumNets > 1) {
+			/* Clear logical MAC addr from second net's active port. */
+			(void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr.
+				Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_CLEAR_LOGICAL);
+			pAC->Rlmt.Net[1].NumPorts = 0;
+		}
+
+		pAC->Rlmt.NumNets = Para.Para32[0];
+		for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) {
+			pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
+			pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
+			pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;	  /* "Automatic" */
+			pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
+			/* Just assuming. */
+			pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
+			pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
+			pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
+			pAC->Rlmt.Net[i].NetNumber = i;
+		}
+
+		pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[0];
+		pAC->Rlmt.Net[0].NumPorts = pAC->GIni.GIMacsFound;
+
+		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para);
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("RLMT: Changed to one net with two ports.\n"))
+	}
+	else if (Para.Para32[0] == 2) {
+		pAC->Rlmt.Port[1].Net= &pAC->Rlmt.Net[1];
+		pAC->Rlmt.Net[1].NumPorts = pAC->GIni.GIMacsFound - 1;
+		pAC->Rlmt.Net[0].NumPorts =
+			pAC->GIni.GIMacsFound - pAC->Rlmt.Net[1].NumPorts;
+		
+		pAC->Rlmt.NumNets = Para.Para32[0];
+		for (i = 0; (SK_U32)i < pAC->Rlmt.NumNets; i++) {
+			pAC->Rlmt.Net[i].RlmtState = SK_RLMT_RS_INIT;
+			pAC->Rlmt.Net[i].RootIdSet = SK_FALSE;
+			pAC->Rlmt.Net[i].Preference = 0xFFFFFFFF;	  /* "Automatic" */
+			pAC->Rlmt.Net[i].PrefPort = SK_RLMT_DEF_PREF_PORT;
+			/* Just assuming. */
+			pAC->Rlmt.Net[i].ActivePort = pAC->Rlmt.Net[i].PrefPort;
+			pAC->Rlmt.Net[i].RlmtMode = SK_RLMT_DEF_MODE;
+			pAC->Rlmt.Net[i].TimeoutValue = SK_RLMT_DEF_TO_VAL;
+
+			pAC->Rlmt.Net[i].NetNumber = i;
+		}
+
+		/* Set logical MAC addr on second net's active port. */
+		(void)SkAddrOverride(pAC, IoC, pAC->Rlmt.Net[1].Port[pAC->Addr.
+			Net[1].ActivePort]->PortNumber, NULL, SK_ADDR_SET_LOGICAL);
+
+		SkEventQueue(pAC, SKGE_PNMI, SK_PNMI_EVT_RLMT_SET_NETS, Para);
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("RLMT: Changed to two nets with one port each.\n"))
+	}
+	else {
+		/* Not implemented for more than two nets. */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SetNets not implemented for more than two nets.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_SET_NETS Event EMPTY.\n"))
+		return;
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_SET_NETS Event END.\n"))
+}	/* SkRlmtSetNets */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvtModeChange - MODE_CHANGE
+ *
+ * Description:
+ *	This routine handles MODE_CHANGE events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	Nothing
+ */
+RLMT_STATIC void	SkRlmtEvtModeChange(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_EVPARA	Para)	/* SK_U32 NewMode; SK_U32 NetNumber */
+{
+	SK_EVPARA	Para2;
+	SK_U32		i;
+	SK_U32		PrevRlmtMode;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+		("SK_RLMT_MODE_CHANGE Event BEGIN.\n"))
+
+	if (Para.Para32[1] >= pAC->Rlmt.NumNets) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Bad NetNumber %d.\n", Para.Para32[1]))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_MODE_CHANGE Event EMPTY.\n"))
+		return;
+	}
+
+	Para.Para32[0] |= SK_RLMT_CHECK_LINK;
+
+	if ((pAC->Rlmt.Net[Para.Para32[1]].NumPorts == 1) &&
+		Para.Para32[0] != SK_RLMT_MODE_CLS) {
+		pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = SK_RLMT_MODE_CLS;
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Forced RLMT mode to CLS on single port net.\n"))
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_MODE_CHANGE Event EMPTY.\n"))
+		return;
+	}
+
+	/* Update RLMT mode. */
+	PrevRlmtMode = pAC->Rlmt.Net[Para.Para32[1]].RlmtMode;
+	pAC->Rlmt.Net[Para.Para32[1]].RlmtMode = Para.Para32[0];
+
+	if ((PrevRlmtMode & SK_RLMT_CHECK_LOC_LINK) !=
+		(pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_LOC_LINK)) {
+		/* SK_RLMT_CHECK_LOC_LINK bit changed. */
+		if ((PrevRlmtMode & SK_RLMT_CHECK_OTHERS) == 0 &&
+			pAC->Rlmt.Net[Para.Para32[1]].NumPorts > 1 &&
+			pAC->Rlmt.Net[Para.Para32[1]].PortsUp >= 1) {
+			/* 20001207 RA: Was "PortsUp == 1". */
+			Para2.Para32[0] = Para.Para32[1];
+			Para2.Para32[1] = (SK_U32)-1;
+			SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].LocTimer,
+				pAC->Rlmt.Net[Para.Para32[1]].TimeoutValue,
+				SKGE_RLMT, SK_RLMT_TIM, Para2);
+		}
+	}
+
+	if ((PrevRlmtMode & SK_RLMT_CHECK_SEG) !=
+		(pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG)) {
+		/* SK_RLMT_CHECK_SEG bit changed. */
+		for (i = 0; i < pAC->Rlmt.Net[Para.Para32[1]].NumPorts; i++) {
+			(void)SkAddrMcClear(pAC, IoC,
+				pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
+				SK_ADDR_PERMANENT | SK_MC_SW_ONLY);
+
+			/* Add RLMT MC address. */
+			(void)SkAddrMcAdd(pAC, IoC,
+				pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
+				&SkRlmtMcAddr, SK_ADDR_PERMANENT);
+
+			if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode &
+				SK_RLMT_CHECK_SEG) != 0) {
+				/* Add BPDU MC address. */
+				(void)SkAddrMcAdd(pAC, IoC,
+					pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber,
+					&BridgeMcAddr, SK_ADDR_PERMANENT);
+
+				if (pAC->Rlmt.Net[Para.Para32[1]].RlmtState != SK_RLMT_RS_INIT) {
+					if (!pAC->Rlmt.Net[Para.Para32[1]].Port[i]->LinkDown &&
+						(Para2.pParaPtr = SkRlmtBuildSpanningTreePacket(
+						pAC, IoC, i)) != NULL) {
+						pAC->Rlmt.Net[Para.Para32[1]].Port[i]->RootIdSet =
+							SK_FALSE;
+						SkEventQueue(pAC, SKGE_DRV, SK_DRV_RLMT_SEND, Para2);
+					}
+				}
+			}
+			(void)SkAddrMcUpdate(pAC, IoC,
+				pAC->Rlmt.Net[Para.Para32[1]].Port[i]->PortNumber);
+		}	/* for ... */
+
+		if ((pAC->Rlmt.Net[Para.Para32[1]].RlmtMode & SK_RLMT_CHECK_SEG) != 0) {
+			Para2.Para32[0] = Para.Para32[1];
+			Para2.Para32[1] = (SK_U32)-1;
+			SkTimerStart(pAC, IoC, &pAC->Rlmt.Net[Para.Para32[1]].SegTimer,
+				SK_RLMT_SEG_TO_VAL, SKGE_RLMT, SK_RLMT_SEG_TIM, Para2);
+		}
+	}	/* SK_RLMT_CHECK_SEG bit changed. */
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("SK_RLMT_MODE_CHANGE Event END.\n"))
+}	/* SkRlmtEvtModeChange */
+
+
+/******************************************************************************
+ *
+ *	SkRlmtEvent - a PORT- or an RLMT-specific event happened
+ *
+ * Description:
+ *	This routine calls subroutines to handle PORT- and RLMT-specific events.
+ *
+ * Context:
+ *	runtime, pageable?
+ *	may be called after SK_INIT_IO
+ *
+ * Returns:
+ *	0
+ */
+int	SkRlmtEvent(
+SK_AC		*pAC,	/* Adapter Context */
+SK_IOC		IoC,	/* I/O Context */
+SK_U32		Event,	/* Event code */
+SK_EVPARA	Para)	/* Event-specific parameter */
+{
+	switch (Event) {
+	
+	/* ----- PORT events ----- */
+
+	case SK_RLMT_PORTSTART_TIM:	/* From RLMT via TIME. */
+		SkRlmtEvtPortStartTim(pAC, IoC, Para);
+		break;
+	case SK_RLMT_LINK_UP:		/* From SIRQ. */
+		SkRlmtEvtLinkUp(pAC, IoC, Para);
+		break;
+	case SK_RLMT_PORTUP_TIM:	/* From RLMT via TIME. */
+		SkRlmtEvtPortUpTim(pAC, IoC, Para);
+		break;
+	case SK_RLMT_PORTDOWN:			/* From RLMT. */
+	case SK_RLMT_PORTDOWN_RX_TIM:	/* From RLMT via TIME. */
+	case SK_RLMT_PORTDOWN_TX_TIM:	/* From RLMT via TIME. */
+		SkRlmtEvtPortDownX(pAC, IoC, Event, Para);
+		break;
+	case SK_RLMT_LINK_DOWN:		/* From SIRQ. */
+		SkRlmtEvtLinkDown(pAC, IoC, Para);
+		break;
+	case SK_RLMT_PORT_ADDR:		/* From ADDR. */
+		SkRlmtEvtPortAddr(pAC, IoC, Para);
+		break;
+
+	/* ----- RLMT events ----- */
+
+	case SK_RLMT_START:		/* From DRV. */
+		SkRlmtEvtStart(pAC, IoC, Para);
+		break;
+	case SK_RLMT_STOP:		/* From DRV. */
+		SkRlmtEvtStop(pAC, IoC, Para);
+		break;
+	case SK_RLMT_TIM:		/* From RLMT via TIME. */
+		SkRlmtEvtTim(pAC, IoC, Para);
+		break;
+	case SK_RLMT_SEG_TIM:
+		SkRlmtEvtSegTim(pAC, IoC, Para);
+		break;
+	case SK_RLMT_PACKET_RECEIVED:	/* From DRV. */
+		SkRlmtEvtPacketRx(pAC, IoC, Para);
+		break;
+	case SK_RLMT_STATS_CLEAR:	/* From PNMI. */
+		SkRlmtEvtStatsClear(pAC, IoC, Para);
+		break;
+	case SK_RLMT_STATS_UPDATE:	/* From PNMI. */
+		SkRlmtEvtStatsUpdate(pAC, IoC, Para);
+		break;
+	case SK_RLMT_PREFPORT_CHANGE:	/* From PNMI. */
+		SkRlmtEvtPrefportChange(pAC, IoC, Para);
+		break;
+	case SK_RLMT_MODE_CHANGE:	/* From PNMI. */
+		SkRlmtEvtModeChange(pAC, IoC, Para);
+		break;
+	case SK_RLMT_SET_NETS:	/* From DRV. */
+		SkRlmtEvtSetNets(pAC, IoC, Para);
+		break;
+
+	/* ----- Unknown events ----- */
+
+	default:	/* Create error log entry. */
+		SK_DBG_MSG(pAC, SK_DBGMOD_RLMT, SK_DBGCAT_CTRL,
+			("Unknown RLMT Event %d.\n", Event))
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_RLMT_E003, SKERR_RLMT_E003_MSG);
+		break;
+	}	/* switch() */
+
+	return (0);
+}	/* SkRlmtEvent */
+
+#ifdef __cplusplus
+}
+#endif	/* __cplusplus */
diff --git a/drivers/net/sk98lin/sktimer.c b/drivers/net/sk98lin/sktimer.c
new file mode 100644
index 0000000..4e46295
--- /dev/null
+++ b/drivers/net/sk98lin/sktimer.c
@@ -0,0 +1,250 @@
+/******************************************************************************
+ *
+ * Name:	sktimer.c
+ * Project:	Gigabit Ethernet Adapters, Event Scheduler Module
+ * Version:	$Revision: 1.14 $
+ * Date:	$Date: 2003/09/16 13:46:51 $
+ * Purpose:	High level timer functions.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect GmbH.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+
+/*
+ *	Event queue and dispatcher
+ */
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+	"@(#) $Id: sktimer.c,v 1.14 2003/09/16 13:46:51 rschmidt Exp $ (C) Marvell.";
+#endif
+
+#include "h/skdrv1st.h"		/* Driver Specific Definitions */
+#include "h/skdrv2nd.h"		/* Adapter Control- and Driver specific Def. */
+
+#ifdef __C2MAN__
+/*
+	Event queue management.
+
+	General Description:
+
+ */
+intro()
+{}
+#endif
+
+
+/* Forward declaration */
+static void timer_done(SK_AC *pAC,SK_IOC Ioc,int Restart);
+
+
+/*
+ * Inits the software timer
+ *
+ * needs to be called during Init level 1.
+ */
+void	SkTimerInit(
+SK_AC	*pAC,		/* Adapters context */
+SK_IOC	Ioc,		/* IoContext */
+int		Level)		/* Init Level */
+{
+	switch (Level) {
+	case SK_INIT_DATA:
+		pAC->Tim.StQueue = NULL;
+		break;
+	case SK_INIT_IO:
+		SkHwtInit(pAC, Ioc);
+		SkTimerDone(pAC, Ioc);
+		break;
+	default:
+		break;
+	}
+}
+
+/*
+ * Stops a high level timer
+ * - If a timer is not in the queue the function returns normally, too.
+ */
+void	SkTimerStop(
+SK_AC		*pAC,		/* Adapters context */
+SK_IOC		Ioc,		/* IoContext */
+SK_TIMER	*pTimer)	/* Timer Pointer to be started */
+{
+	SK_TIMER	**ppTimPrev;
+	SK_TIMER	*pTm;
+
+	/*
+	 * remove timer from queue
+	 */
+	pTimer->TmActive = SK_FALSE;
+	
+	if (pAC->Tim.StQueue == pTimer && !pTimer->TmNext) {
+		SkHwtStop(pAC, Ioc);
+	}
+	
+	for (ppTimPrev = &pAC->Tim.StQueue; (pTm = *ppTimPrev);
+		ppTimPrev = &pTm->TmNext ) {
+		
+		if (pTm == pTimer) {
+			/*
+			 * Timer found in queue
+			 * - dequeue it and
+			 * - correct delta of the next timer
+			 */
+			*ppTimPrev = pTm->TmNext;
+
+			if (pTm->TmNext) {
+				/* correct delta of next timer in queue */
+				pTm->TmNext->TmDelta += pTm->TmDelta;
+			}
+			return;
+		}
+	}
+}
+
+/*
+ * Start a high level software timer
+ */
+void	SkTimerStart(
+SK_AC		*pAC,		/* Adapters context */
+SK_IOC		Ioc,		/* IoContext */
+SK_TIMER	*pTimer,	/* Timer Pointer to be started */
+SK_U32		Time,		/* Time value */
+SK_U32		Class,		/* Event Class for this timer */
+SK_U32		Event,		/* Event Value for this timer */
+SK_EVPARA	Para)		/* Event Parameter for this timer */
+{
+	SK_TIMER	**ppTimPrev;
+	SK_TIMER	*pTm;
+	SK_U32		Delta;
+
+	Time /= 16;		/* input is uS, clock ticks are 16uS */
+	
+	if (!Time)
+		Time = 1;
+
+	SkTimerStop(pAC, Ioc, pTimer);
+
+	pTimer->TmClass = Class;
+	pTimer->TmEvent = Event;
+	pTimer->TmPara = Para;
+	pTimer->TmActive = SK_TRUE;
+
+	if (!pAC->Tim.StQueue) {
+		/* First Timer to be started */
+		pAC->Tim.StQueue = pTimer;
+		pTimer->TmNext = NULL;
+		pTimer->TmDelta = Time;
+		
+		SkHwtStart(pAC, Ioc, Time);
+		
+		return;
+	}
+
+	/*
+	 * timer correction
+	 */
+	timer_done(pAC, Ioc, 0);
+
+	/*
+	 * find position in queue
+	 */
+	Delta = 0;
+	for (ppTimPrev = &pAC->Tim.StQueue; (pTm = *ppTimPrev);
+		ppTimPrev = &pTm->TmNext ) {
+		
+		if (Delta + pTm->TmDelta > Time) {
+			/* Position found */
+			/* Here the timer needs to be inserted. */
+			break;
+		}
+		Delta += pTm->TmDelta;
+	}
+
+	/* insert in queue */
+	*ppTimPrev = pTimer;
+	pTimer->TmNext = pTm;
+	pTimer->TmDelta = Time - Delta;
+
+	if (pTm) {
+		/* There is a next timer
+		 * -> correct its Delta value.
+		 */
+		pTm->TmDelta -= pTimer->TmDelta;
+	}
+
+	/* restart with first */
+	SkHwtStart(pAC, Ioc, pAC->Tim.StQueue->TmDelta);
+}
+
+
+void	SkTimerDone(
+SK_AC	*pAC,		/* Adapters context */
+SK_IOC	Ioc)		/* IoContext */
+{
+	timer_done(pAC, Ioc, 1);
+}
+
+
+static void	timer_done(
+SK_AC	*pAC,		/* Adapters context */
+SK_IOC	Ioc,		/* IoContext */
+int		Restart)	/* Do we need to restart the Hardware timer ? */
+{
+	SK_U32		Delta;
+	SK_TIMER	*pTm;
+	SK_TIMER	*pTComp;	/* Timer completed now now */
+	SK_TIMER	**ppLast;	/* Next field of Last timer to be deq */
+	int		Done = 0;
+
+	Delta = SkHwtRead(pAC, Ioc);
+	
+	ppLast = &pAC->Tim.StQueue;
+	pTm = pAC->Tim.StQueue;
+	while (pTm && !Done) {
+		if (Delta >= pTm->TmDelta) {
+			/* Timer ran out */
+			pTm->TmActive = SK_FALSE;
+			Delta -= pTm->TmDelta;
+			ppLast = &pTm->TmNext;
+			pTm = pTm->TmNext;
+		}
+		else {
+			/* We found the first timer that did not run out */
+			pTm->TmDelta -= Delta;
+			Delta = 0;
+			Done = 1;
+		}
+	}
+	*ppLast = NULL;
+	/*
+	 * pTm points to the first Timer that did not run out.
+	 * StQueue points to the first Timer that run out.
+	 */
+
+	for ( pTComp = pAC->Tim.StQueue; pTComp; pTComp = pTComp->TmNext) {
+		SkEventQueue(pAC,pTComp->TmClass, pTComp->TmEvent, pTComp->TmPara);
+	}
+
+	/* Set head of timer queue to the first timer that did not run out */
+	pAC->Tim.StQueue = pTm;
+
+	if (Restart && pAC->Tim.StQueue) {
+		/* Restart HW timer */
+		SkHwtStart(pAC, Ioc, pAC->Tim.StQueue->TmDelta);
+	}
+}
+
+/* End of file */
diff --git a/drivers/net/sk98lin/skvpd.c b/drivers/net/sk98lin/skvpd.c
new file mode 100644
index 0000000..1e662aa
--- /dev/null
+++ b/drivers/net/sk98lin/skvpd.c
@@ -0,0 +1,1091 @@
+/******************************************************************************
+ *
+ * Name:	skvpd.c
+ * Project:	GEnesis, PCI Gigabit Ethernet Adapter
+ * Version:	$Revision: 1.37 $
+ * Date:	$Date: 2003/01/13 10:42:45 $
+ * Purpose:	Shared software to read and write VPD data
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2003 SysKonnect GmbH.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+/*
+	Please refer skvpd.txt for information how to include this module
+ */
+static const char SysKonnectFileId[] =
+	"@(#)$Id: skvpd.c,v 1.37 2003/01/13 10:42:45 rschmidt Exp $ (C) SK";
+
+#include "h/skdrv1st.h"
+#include "h/sktypes.h"
+#include "h/skdebug.h"
+#include "h/skdrv2nd.h"
+
+/*
+ * Static functions
+ */
+#ifndef SK_KR_PROTO
+static SK_VPD_PARA	*vpd_find_para(
+	SK_AC	*pAC,
+	const char	*key,
+	SK_VPD_PARA *p);
+#else	/* SK_KR_PROTO */
+static SK_VPD_PARA	*vpd_find_para();
+#endif	/* SK_KR_PROTO */
+
+/*
+ * waits for a completion of a VPD transfer
+ * The VPD transfer must complete within SK_TICKS_PER_SEC/16
+ *
+ * returns	0:	success, transfer completes
+ *		error	exit(9) with a error message
+ */
+static int VpdWait(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC,	/* IO Context */
+int		event)	/* event to wait for (VPD_READ / VPD_write) completion*/
+{
+	SK_U64	start_time;
+	SK_U16	state;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD wait for %s\n", event?"Write":"Read"));
+	start_time = SkOsGetTime(pAC);
+	do {
+		if (SkOsGetTime(pAC) - start_time > SK_TICKS_PER_SEC) {
+
+			/* Bug fix AF: Thu Mar 28 2002
+			 * Do not call: VPD_STOP(pAC, IoC);
+			 * A pending VPD read cycle can not be aborted by writing
+			 * VPD_WRITE to the PCI_VPD_ADR_REG (VPD address register).
+			 * Although the write threshold in the OUR-register protects
+			 * VPD read only space from being overwritten this does not
+			 * protect a VPD read from being `converted` into a VPD write
+			 * operation (on the fly). As a consequence the VPD_STOP would
+			 * delete VPD read only data. In case of any problems with the
+			 * I2C bus we exit the loop here. The I2C read operation can
+			 * not be aborted except by a reset (->LR).
+			 */
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_FATAL | SK_DBGCAT_ERR,
+				("ERROR:VPD wait timeout\n"));
+			return(1);
+		}
+		
+		VPD_IN16(pAC, IoC, PCI_VPD_ADR_REG, &state);
+		
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+			("state = %x, event %x\n",state,event));
+	} while((int)(state & PCI_VPD_FLAG) == event);
+
+	return(0);
+}
+
+#ifdef SKDIAG
+
+/*
+ * Read the dword at address 'addr' from the VPD EEPROM.
+ *
+ * Needed Time:	MIN 1,3 ms	MAX 2,6 ms
+ *
+ * Note: The DWord is returned in the endianess of the machine the routine
+ *       is running on.
+ *
+ * Returns the data read.
+ */
+SK_U32 VpdReadDWord(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC,	/* IO Context */
+int		addr)	/* VPD address */
+{
+	SK_U32	Rtv;
+
+	/* start VPD read */
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD read dword at 0x%x\n",addr));
+	addr &= ~VPD_WRITE;		/* ensure the R/W bit is set to read */
+
+	VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, (SK_U16)addr);
+
+	/* ignore return code here */
+	(void)VpdWait(pAC, IoC, VPD_READ);
+
+	/* Don't swap here, it's a data stream of bytes */
+	Rtv = 0;
+
+	VPD_IN32(pAC, IoC, PCI_VPD_DAT_REG, &Rtv);
+	
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD read dword data = 0x%x\n",Rtv));
+	return(Rtv);
+}
+
+#endif	/* SKDIAG */
+
+/*
+ *	Read one Stream of 'len' bytes of VPD data, starting at 'addr' from
+ *	or to the I2C EEPROM.
+ *
+ * Returns number of bytes read / written.
+ */
+static int VpdWriteStream(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC,	/* IO Context */
+char	*buf,	/* data buffer */
+int		Addr,	/* VPD start address */
+int		Len)	/* number of bytes to read / to write */
+{
+	int		i;
+	int		j;
+	SK_U16	AdrReg;
+	int		Rtv;
+	SK_U8	* pComp;	/* Compare pointer */
+	SK_U8	Data;		/* Input Data for Compare */
+
+	/* Init Compare Pointer */
+	pComp = (SK_U8 *) buf;
+
+	for (i = 0; i < Len; i++, buf++) {
+		if ((i%sizeof(SK_U32)) == 0) {
+			/*
+			 * At the begin of each cycle read the Data Reg
+			 * So it is initialized even if only a few bytes
+			 * are written.
+			 */
+			AdrReg = (SK_U16) Addr;
+			AdrReg &= ~VPD_WRITE;	/* READ operation */
+
+			VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg);
+
+			/* Wait for termination */
+			Rtv = VpdWait(pAC, IoC, VPD_READ);
+			if (Rtv != 0) {
+				return(i);
+			}
+		}
+
+		/* Write current Byte */
+		VPD_OUT8(pAC, IoC, PCI_VPD_DAT_REG + (i%sizeof(SK_U32)),
+				*(SK_U8*)buf);
+
+		if (((i%sizeof(SK_U32)) == 3) || (i == (Len - 1))) {
+			/* New Address needs to be written to VPD_ADDR reg */
+			AdrReg = (SK_U16) Addr;
+			Addr += sizeof(SK_U32);
+			AdrReg |= VPD_WRITE;	/* WRITE operation */
+
+			VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg);
+
+			/* Wait for termination */
+			Rtv = VpdWait(pAC, IoC, VPD_WRITE);
+			if (Rtv != 0) {
+				SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+					("Write Timed Out\n"));
+				return(i - (i%sizeof(SK_U32)));
+			}
+
+			/*
+			 * Now re-read to verify
+			 */
+			AdrReg &= ~VPD_WRITE;	/* READ operation */
+
+			VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg);
+
+			/* Wait for termination */
+			Rtv = VpdWait(pAC, IoC, VPD_READ);
+			if (Rtv != 0) {
+				SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+					("Verify Timed Out\n"));
+				return(i - (i%sizeof(SK_U32)));
+			}
+
+			for (j = 0; j <= (int)(i%sizeof(SK_U32)); j++, pComp++) {
+				
+				VPD_IN8(pAC, IoC, PCI_VPD_DAT_REG + j, &Data);
+				
+				if (Data != *pComp) {
+					/* Verify Error */
+					SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+						("WriteStream Verify Error\n"));
+					return(i - (i%sizeof(SK_U32)) + j);
+				}
+			}
+		}
+	}
+
+	return(Len);
+}
+	
+
+/*
+ *	Read one Stream of 'len' bytes of VPD data, starting at 'addr' from
+ *	or to the I2C EEPROM.
+ *
+ * Returns number of bytes read / written.
+ */
+static int VpdReadStream(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC,	/* IO Context */
+char	*buf,	/* data buffer */
+int		Addr,	/* VPD start address */
+int		Len)	/* number of bytes to read / to write */
+{
+	int		i;
+	SK_U16	AdrReg;
+	int		Rtv;
+
+	for (i = 0; i < Len; i++, buf++) {
+		if ((i%sizeof(SK_U32)) == 0) {
+			/* New Address needs to be written to VPD_ADDR reg */
+			AdrReg = (SK_U16) Addr;
+			Addr += sizeof(SK_U32);
+			AdrReg &= ~VPD_WRITE;	/* READ operation */
+
+			VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, AdrReg);
+
+			/* Wait for termination */
+			Rtv = VpdWait(pAC, IoC, VPD_READ);
+			if (Rtv != 0) {
+				return(i);
+			}
+		}
+		VPD_IN8(pAC, IoC, PCI_VPD_DAT_REG + (i%sizeof(SK_U32)),
+			(SK_U8 *)buf);
+	}
+
+	return(Len);
+}
+
+/*
+ *	Read ore writes 'len' bytes of VPD data, starting at 'addr' from
+ *	or to the I2C EEPROM.
+ *
+ * Returns number of bytes read / written.
+ */
+static int VpdTransferBlock(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC,	/* IO Context */
+char	*buf,	/* data buffer */
+int		addr,	/* VPD start address */
+int		len,	/* number of bytes to read / to write */
+int		dir)	/* transfer direction may be VPD_READ or VPD_WRITE */
+{
+	int		Rtv;	/* Return value */
+	int		vpd_rom_size;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD %s block, addr = 0x%x, len = %d\n",
+		dir ? "write" : "read", addr, len));
+
+	if (len == 0)
+		return(0);
+
+	vpd_rom_size = pAC->vpd.rom_size;
+	
+	if (addr > vpd_rom_size - 4) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Address error: 0x%x, exp. < 0x%x\n",
+			addr, vpd_rom_size - 4));
+		return(0);
+	}
+	
+	if (addr + len > vpd_rom_size) {
+		len = vpd_rom_size - addr;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("Warning: len was cut to %d\n", len));
+	}
+
+	if (dir == VPD_READ) {
+		Rtv = VpdReadStream(pAC, IoC, buf, addr, len);
+	}
+	else {
+		Rtv = VpdWriteStream(pAC, IoC, buf, addr, len);
+	}
+
+	return(Rtv);
+}
+
+#ifdef SKDIAG
+
+/*
+ *	Read 'len' bytes of VPD data, starting at 'addr'.
+ *
+ * Returns number of bytes read.
+ */
+int VpdReadBlock(
+SK_AC	*pAC,	/* pAC pointer */
+SK_IOC	IoC,	/* IO Context */
+char	*buf,	/* buffer were the data should be stored */
+int		addr,	/* start reading at the VPD address */
+int		len)	/* number of bytes to read */
+{
+	return(VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_READ));
+}
+
+/*
+ *	Write 'len' bytes of *but to the VPD EEPROM, starting at 'addr'.
+ *
+ * Returns number of bytes writes.
+ */
+int VpdWriteBlock(
+SK_AC	*pAC,	/* pAC pointer */
+SK_IOC	IoC,	/* IO Context */
+char	*buf,	/* buffer, holds the data to write */
+int		addr,	/* start writing at the VPD address */
+int		len)	/* number of bytes to write */
+{
+	return(VpdTransferBlock(pAC, IoC, buf, addr, len, VPD_WRITE));
+}
+#endif	/* SKDIAG */
+
+/*
+ * (re)initialize the VPD buffer
+ *
+ * Reads the VPD data from the EEPROM into the VPD buffer.
+ * Get the remaining read only and read / write space.
+ *
+ * return	0:	success
+ *		1:	fatal VPD error
+ */
+static int VpdInit(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC)	/* IO Context */
+{
+	SK_VPD_PARA *r, rp;	/* RW or RV */
+	int		i;
+	unsigned char	x;
+	int		vpd_size;
+	SK_U16	dev_id;
+	SK_U32	our_reg2;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_INIT, ("VpdInit .. "));
+	
+	VPD_IN16(pAC, IoC, PCI_DEVICE_ID, &dev_id);
+	
+	VPD_IN32(pAC, IoC, PCI_OUR_REG_2, &our_reg2);
+	
+	pAC->vpd.rom_size = 256 << ((our_reg2 & PCI_VPD_ROM_SZ) >> 14);
+	
+	/*
+	 * this function might get used before the hardware is initialized
+	 * therefore we cannot always trust in GIChipId
+	 */
+	if (((pAC->vpd.v.vpd_status & VPD_VALID) == 0 &&
+		dev_id != VPD_DEV_ID_GENESIS) ||
+		((pAC->vpd.v.vpd_status & VPD_VALID) != 0 &&
+		!pAC->GIni.GIGenesis)) {
+
+		/* for Yukon the VPD size is always 256 */
+		vpd_size = VPD_SIZE_YUKON;
+	}
+	else {
+		/* Genesis uses the maximum ROM size up to 512 for VPD */
+		if (pAC->vpd.rom_size > VPD_SIZE_GENESIS) {
+			vpd_size = VPD_SIZE_GENESIS;
+		}
+		else {
+			vpd_size = pAC->vpd.rom_size;
+		}
+	}
+
+	/* read the VPD data into the VPD buffer */
+	if (VpdTransferBlock(pAC, IoC, pAC->vpd.vpd_buf, 0, vpd_size, VPD_READ)
+		!= vpd_size) {
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("Block Read Error\n"));
+		return(1);
+	}
+	
+	pAC->vpd.vpd_size = vpd_size;
+
+	/* Asus K8V Se Deluxe bugfix. Correct VPD content */
+	/* MBo April 2004 */
+	if (((unsigned char)pAC->vpd.vpd_buf[0x3f] == 0x38) &&
+	    ((unsigned char)pAC->vpd.vpd_buf[0x40] == 0x3c) &&
+	    ((unsigned char)pAC->vpd.vpd_buf[0x41] == 0x45)) {
+		printk("sk98lin: Asus mainboard with buggy VPD? "
+				"Correcting data.\n");
+		pAC->vpd.vpd_buf[0x40] = 0x38;
+	}
+
+
+	/* find the end tag of the RO area */
+	if (!(r = vpd_find_para(pAC, VPD_RV, &rp))) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Encoding Error: RV Tag not found\n"));
+		return(1);
+	}
+	
+	if (r->p_val + r->p_len > pAC->vpd.vpd_buf + vpd_size/2) {
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Encoding Error: Invalid VPD struct size\n"));
+		return(1);
+	}
+	pAC->vpd.v.vpd_free_ro = r->p_len - 1;
+
+	/* test the checksum */
+	for (i = 0, x = 0; (unsigned)i <= (unsigned)vpd_size/2 - r->p_len; i++) {
+		x += pAC->vpd.vpd_buf[i];
+	}
+	
+	if (x != 0) {
+		/* checksum error */
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("VPD Checksum Error\n"));
+		return(1);
+	}
+
+	/* find and check the end tag of the RW area */
+	if (!(r = vpd_find_para(pAC, VPD_RW, &rp))) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Encoding Error: RV Tag not found\n"));
+		return(1);
+	}
+	
+	if (r->p_val < pAC->vpd.vpd_buf + vpd_size/2) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Encoding Error: Invalid VPD struct size\n"));
+		return(1);
+	}
+	pAC->vpd.v.vpd_free_rw = r->p_len;
+
+	/* everything seems to be ok */
+	if (pAC->GIni.GIChipId != 0) {
+		pAC->vpd.v.vpd_status |= VPD_VALID;
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_INIT,
+		("done. Free RO = %d, Free RW = %d\n",
+		pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw));
+
+	return(0);
+}
+
+/*
+ *	find the Keyword 'key' in the VPD buffer and fills the
+ *	parameter struct 'p' with it's values
+ *
+ * returns	*p	success
+ *		0:	parameter was not found or VPD encoding error
+ */
+static SK_VPD_PARA *vpd_find_para(
+SK_AC		*pAC,	/* common data base */
+const char	*key,	/* keyword to find (e.g. "MN") */
+SK_VPD_PARA *p)		/* parameter description struct */
+{
+	char *v	;	/* points to VPD buffer */
+	int max;	/* Maximum Number of Iterations */
+
+	v = pAC->vpd.vpd_buf;
+	max = 128;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD find para %s .. ",key));
+
+	/* check mandatory resource type ID string (Product Name) */
+	if (*v != (char)RES_ID) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Error: 0x%x missing\n", RES_ID));
+		return NULL;
+	}
+
+	if (strcmp(key, VPD_NAME) == 0) {
+		p->p_len = VPD_GET_RES_LEN(v);
+		p->p_val = VPD_GET_VAL(v);
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+			("found, len = %d\n", p->p_len));
+		return(p);
+	}
+
+	v += 3 + VPD_GET_RES_LEN(v) + 3;
+	for (;; ) {
+		if (SK_MEMCMP(key,v,2) == 0) {
+			p->p_len = VPD_GET_VPD_LEN(v);
+			p->p_val = VPD_GET_VAL(v);
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+				("found, len = %d\n",p->p_len));
+			return(p);
+		}
+
+		/* exit when reaching the "RW" Tag or the maximum of itera. */
+		max--;
+		if (SK_MEMCMP(VPD_RW,v,2) == 0 || max == 0) {
+			break;
+		}
+
+		if (SK_MEMCMP(VPD_RV,v,2) == 0) {
+			v += 3 + VPD_GET_VPD_LEN(v) + 3;	/* skip VPD-W */
+		}
+		else {
+			v += 3 + VPD_GET_VPD_LEN(v);
+		}
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+			("scanning '%c%c' len = %d\n",v[0],v[1],v[2]));
+	}
+
+#ifdef DEBUG
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, ("not found\n"));
+	if (max == 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Key/Len Encoding error\n"));
+	}
+#endif /* DEBUG */
+	return NULL;
+}
+
+/*
+ *	Move 'n' bytes. Begin with the last byte if 'n' is > 0,
+ *	Start with the last byte if n is < 0.
+ *
+ * returns nothing
+ */
+static void vpd_move_para(
+char	*start,		/* start of memory block */
+char	*end,		/* end of memory block to move */
+int		n)			/* number of bytes the memory block has to be moved */
+{
+	char *p;
+	int i;		/* number of byte copied */
+
+	if (n == 0)
+		return;
+
+	i = (int) (end - start + 1);
+	if (n < 0) {
+		p = start + n;
+		while (i != 0) {
+			*p++ = *start++;
+			i--;
+		}
+	}
+	else {
+		p = end + n;
+		while (i != 0) {
+			*p-- = *end--;
+			i--;
+		}
+	}
+}
+
+/*
+ *	setup the VPD keyword 'key' at 'ip'.
+ *
+ * returns nothing
+ */
+static void vpd_insert_key(
+const char	*key,	/* keyword to insert */
+const char	*buf,	/* buffer with the keyword value */
+int		len,		/* length of the value string */
+char	*ip)		/* inseration point */
+{
+	SK_VPD_KEY *p;
+
+	p = (SK_VPD_KEY *) ip;
+	p->p_key[0] = key[0];
+	p->p_key[1] = key[1];
+	p->p_len = (unsigned char) len;
+	SK_MEMCPY(&p->p_val,buf,len);
+}
+
+/*
+ *	Setup the VPD end tag "RV" / "RW".
+ *	Also correct the remaining space variables vpd_free_ro / vpd_free_rw.
+ *
+ * returns	0:	success
+ *		1:	encoding error
+ */
+static int vpd_mod_endtag(
+SK_AC	*pAC,		/* common data base */
+char	*etp)		/* end pointer input position */
+{
+	SK_VPD_KEY *p;
+	unsigned char	x;
+	int	i;
+	int	vpd_size;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD modify endtag at 0x%x = '%c%c'\n",etp,etp[0],etp[1]));
+
+	vpd_size = pAC->vpd.vpd_size;
+
+	p = (SK_VPD_KEY *) etp;
+
+	if (p->p_key[0] != 'R' || (p->p_key[1] != 'V' && p->p_key[1] != 'W')) {
+		/* something wrong here, encoding error */
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR | SK_DBGCAT_FATAL,
+			("Encoding Error: invalid end tag\n"));
+		return(1);
+	}
+	if (etp > pAC->vpd.vpd_buf + vpd_size/2) {
+		/* create "RW" tag */
+		p->p_len = (unsigned char)(pAC->vpd.vpd_buf+vpd_size-etp-3-1);
+		pAC->vpd.v.vpd_free_rw = (int) p->p_len;
+		i = pAC->vpd.v.vpd_free_rw;
+		etp += 3;
+	}
+	else {
+		/* create "RV" tag */
+		p->p_len = (unsigned char)(pAC->vpd.vpd_buf+vpd_size/2-etp-3);
+		pAC->vpd.v.vpd_free_ro = (int) p->p_len - 1;
+
+		/* setup checksum */
+		for (i = 0, x = 0; i < vpd_size/2 - p->p_len; i++) {
+			x += pAC->vpd.vpd_buf[i];
+		}
+		p->p_val = (char) 0 - x;
+		i = pAC->vpd.v.vpd_free_ro;
+		etp += 4;
+	}
+	while (i) {
+		*etp++ = 0x00;
+		i--;
+	}
+
+	return(0);
+}
+
+/*
+ *	Insert a VPD keyword into the VPD buffer.
+ *
+ *	The keyword 'key' is inserted at the position 'ip' in the
+ *	VPD buffer.
+ *	The keywords behind the input position will
+ *	be moved. The VPD end tag "RV" or "RW" is generated again.
+ *
+ * returns	0:	success
+ *		2:	value string was cut
+ *		4:	VPD full, keyword was not written
+ *		6:	fatal VPD error
+ *
+ */
+static int	VpdSetupPara(
+SK_AC	*pAC,		/* common data base */
+const char	*key,	/* keyword to insert */
+const char	*buf,	/* buffer with the keyword value */
+int		len,		/* length of the keyword value */
+int		type,		/* VPD_RO_KEY or VPD_RW_KEY */
+int		op)			/* operation to do: ADD_KEY or OWR_KEY */
+{
+	SK_VPD_PARA vp;
+	char	*etp;		/* end tag position */
+	int	free;		/* remaining space in selected area */
+	char	*ip;		/* input position inside the VPD buffer */
+	int	rtv;		/* return code */
+	int	head;		/* additional haeder bytes to move */
+	int	found;		/* additinoal bytes if the keyword was found */
+	int vpd_size;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("VPD setup para key = %s, val = %s\n",key,buf));
+	
+	vpd_size = pAC->vpd.vpd_size;
+
+	rtv = 0;
+	ip = NULL;
+	if (type == VPD_RW_KEY) {
+		/* end tag is "RW" */
+		free = pAC->vpd.v.vpd_free_rw;
+		etp = pAC->vpd.vpd_buf + (vpd_size - free - 1 - 3);
+	}
+	else {
+		/* end tag is "RV" */
+		free = pAC->vpd.v.vpd_free_ro;
+		etp = pAC->vpd.vpd_buf + (vpd_size/2 - free - 4);
+	}
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+		("Free RO = %d, Free RW = %d\n",
+		pAC->vpd.v.vpd_free_ro, pAC->vpd.v.vpd_free_rw));
+
+	head = 0;
+	found = 0;
+	if (op == OWR_KEY) {
+		if (vpd_find_para(pAC, key, &vp)) {
+			found = 3;
+			ip = vp.p_val - 3;
+			free += vp.p_len + 3;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+				("Overwrite Key\n"));
+		}
+		else {
+			op = ADD_KEY;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL,
+				("Add Key\n"));
+		}
+	}
+	if (op == ADD_KEY) {
+		ip = etp;
+		vp.p_len = 0;
+		head = 3;
+	}
+
+	if (len + 3 > free) {
+		if (free < 7) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("VPD Buffer Overflow, keyword not written\n"));
+			return(4);
+		}
+		/* cut it again */
+		len = free - 3;
+		rtv = 2;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("VPD Buffer Full, Keyword was cut\n"));
+	}
+
+	vpd_move_para(ip + vp.p_len + found, etp+2, len-vp.p_len+head);
+	vpd_insert_key(key, buf, len, ip);
+	if (vpd_mod_endtag(pAC, etp + len - vp.p_len + head)) {
+		pAC->vpd.v.vpd_status &= ~VPD_VALID;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("VPD Encoding Error\n"));
+		return(6);
+	}
+
+	return(rtv);
+}
+
+
+/*
+ *	Read the contents of the VPD EEPROM and copy it to the
+ *	VPD buffer if not already done.
+ *
+ * return:	A pointer to the vpd_status structure. The structure contains
+ *		this fields.
+ */
+SK_VPD_STATUS *VpdStat(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC)	/* IO Context */
+{
+	if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+		(void)VpdInit(pAC, IoC);
+	}
+	return(&pAC->vpd.v);
+}
+
+
+/*
+ *	Read the contents of the VPD EEPROM and copy it to the VPD
+ *	buffer if not already done.
+ *	Scan the VPD buffer for VPD keywords and create the VPD
+ *	keyword list by copying the keywords to 'buf', all after
+ *	each other and terminated with a '\0'.
+ *
+ * Exceptions:	o The Resource Type ID String (product name) is called "Name"
+ *		o The VPD end tags 'RV' and 'RW' are not listed
+ *
+ *	The number of copied keywords is counted in 'elements'.
+ *
+ * returns	0:	success
+ *		2:	buffer overfull, one or more keywords are missing
+ *		6:	fatal VPD error
+ *
+ *	example values after returning:
+ *
+ *		buf =	"Name\0PN\0EC\0MN\0SN\0CP\0VF\0VL\0YA\0"
+ *		*len =		30
+ *		*elements =	 9
+ */
+int VpdKeys(
+SK_AC	*pAC,		/* common data base */
+SK_IOC	IoC,		/* IO Context */
+char	*buf,		/* buffer where to copy the keywords */
+int		*len,		/* buffer length */
+int		*elements)	/* number of keywords returned */
+{
+	char *v;
+	int n;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("list VPD keys .. "));
+	*elements = 0;
+	if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+		if (VpdInit(pAC, IoC) != 0) {
+			*len = 0;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("VPD Init Error, terminated\n"));
+			return(6);
+		}
+	}
+
+	if ((signed)strlen(VPD_NAME) + 1 <= *len) {
+		v = pAC->vpd.vpd_buf;
+		strcpy(buf,VPD_NAME);
+		n = strlen(VPD_NAME) + 1;
+		buf += n;
+		*elements = 1;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX,
+			("'%c%c' ",v[0],v[1]));
+	}
+	else {
+		*len = 0;
+		SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_ERR,
+			("buffer overflow\n"));
+		return(2);
+	}
+
+	v += 3 + VPD_GET_RES_LEN(v) + 3;
+	for (;; ) {
+		/* exit when reaching the "RW" Tag */
+		if (SK_MEMCMP(VPD_RW,v,2) == 0) {
+			break;
+		}
+
+		if (SK_MEMCMP(VPD_RV,v,2) == 0) {
+			v += 3 + VPD_GET_VPD_LEN(v) + 3;	/* skip VPD-W */
+			continue;
+		}
+
+		if (n+3 <= *len) {
+			SK_MEMCPY(buf,v,2);
+			buf += 2;
+			*buf++ = '\0';
+			n += 3;
+			v += 3 + VPD_GET_VPD_LEN(v);
+			*elements += 1;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX,
+				("'%c%c' ",v[0],v[1]));
+		}
+		else {
+			*len = n;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("buffer overflow\n"));
+			return(2);
+		}
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("\n"));
+	*len = n;
+	return(0);
+}
+
+
+/*
+ *	Read the contents of the VPD EEPROM and copy it to the
+ *	VPD buffer if not already done. Search for the VPD keyword
+ *	'key' and copy its value to 'buf'. Add a terminating '\0'.
+ *	If the value does not fit into the buffer cut it after
+ *	'len' - 1 bytes.
+ *
+ * returns	0:	success
+ *		1:	keyword not found
+ *		2:	value string was cut
+ *		3:	VPD transfer timeout
+ *		6:	fatal VPD error
+ */
+int VpdRead(
+SK_AC		*pAC,	/* common data base */
+SK_IOC		IoC,	/* IO Context */
+const char	*key,	/* keyword to read (e.g. "MN") */
+char		*buf,	/* buffer where to copy the keyword value */
+int			*len)	/* buffer length */
+{
+	SK_VPD_PARA *p, vp;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX, ("VPD read %s .. ", key));
+	if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+		if (VpdInit(pAC, IoC) != 0) {
+			*len = 0;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("VPD init error\n"));
+			return(6);
+		}
+	}
+
+	if ((p = vpd_find_para(pAC, key, &vp)) != NULL) {
+		if (p->p_len > (*(unsigned *)len)-1) {
+			p->p_len = *len - 1;
+		}
+		SK_MEMCPY(buf, p->p_val, p->p_len);
+		buf[p->p_len] = '\0';
+		*len = p->p_len;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_RX,
+			("%c%c%c%c.., len = %d\n",
+			buf[0],buf[1],buf[2],buf[3],*len));
+	}
+	else {
+		*len = 0;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, ("not found\n"));
+		return(1);
+	}
+	return(0);
+}
+
+
+/*
+ *	Check whether a given key may be written
+ *
+ * returns
+ *	SK_TRUE		Yes it may be written
+ *	SK_FALSE	No it may be written
+ */
+SK_BOOL VpdMayWrite(
+char	*key)	/* keyword to write (allowed values "Yx", "Vx") */
+{
+	if ((*key != 'Y' && *key != 'V') ||
+		key[1] < '0' || key[1] > 'Z' ||
+		(key[1] > '9' && key[1] < 'A') || strlen(key) != 2) {
+
+		return(SK_FALSE);
+	}
+	return(SK_TRUE);
+}
+
+/*
+ *	Read the contents of the VPD EEPROM and copy it to the VPD
+ *	buffer if not already done. Insert/overwrite the keyword 'key'
+ *	in the VPD buffer. Cut the keyword value if it does not fit
+ *	into the VPD read / write area.
+ *
+ * returns	0:	success
+ *		2:	value string was cut
+ *		3:	VPD transfer timeout
+ *		4:	VPD full, keyword was not written
+ *		5:	keyword cannot be written
+ *		6:	fatal VPD error
+ */
+int VpdWrite(
+SK_AC		*pAC,	/* common data base */
+SK_IOC		IoC,	/* IO Context */
+const char	*key,	/* keyword to write (allowed values "Yx", "Vx") */
+const char	*buf)	/* buffer where the keyword value can be read from */
+{
+	int len;		/* length of the keyword to write */
+	int rtv;		/* return code */
+	int rtv2;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX,
+		("VPD write %s = %s\n",key,buf));
+
+	if ((*key != 'Y' && *key != 'V') ||
+		key[1] < '0' || key[1] > 'Z' ||
+		(key[1] > '9' && key[1] < 'A') || strlen(key) != 2) {
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("illegal key tag, keyword not written\n"));
+		return(5);
+	}
+
+	if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+		if (VpdInit(pAC, IoC) != 0) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("VPD init error\n"));
+			return(6);
+		}
+	}
+
+	rtv = 0;
+	len = strlen(buf);
+	if (len > VPD_MAX_LEN) {
+		/* cut it */
+		len = VPD_MAX_LEN;
+		rtv = 2;
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("keyword too long, cut after %d bytes\n",VPD_MAX_LEN));
+	}
+	if ((rtv2 = VpdSetupPara(pAC, key, buf, len, VPD_RW_KEY, OWR_KEY)) != 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("VPD write error\n"));
+		return(rtv2);
+	}
+
+	return(rtv);
+}
+
+/*
+ *	Read the contents of the VPD EEPROM and copy it to the
+ *	VPD buffer if not already done. Remove the VPD keyword
+ *	'key' from the VPD buffer.
+ *	Only the keywords in the read/write area can be deleted.
+ *	Keywords in the read only area cannot be deleted.
+ *
+ * returns	0:	success, keyword was removed
+ *		1:	keyword not found
+ *		5:	keyword cannot be deleted
+ *		6:	fatal VPD error
+ */
+int VpdDelete(
+SK_AC	*pAC,	/* common data base */
+SK_IOC	IoC,	/* IO Context */
+char	*key)	/* keyword to read (e.g. "MN") */
+{
+	SK_VPD_PARA *p, vp;
+	char *etp;
+	int	vpd_size;
+
+	vpd_size = pAC->vpd.vpd_size;
+
+	SK_DBG_MSG(pAC,SK_DBGMOD_VPD,SK_DBGCAT_TX,("VPD delete key %s\n",key));
+	if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) {
+		if (VpdInit(pAC, IoC) != 0) {
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("VPD init error\n"));
+			return(6);
+		}
+	}
+
+	if ((p = vpd_find_para(pAC, key, &vp)) != NULL) {
+		if (p->p_val < pAC->vpd.vpd_buf + vpd_size/2) {
+			/* try to delete read only keyword */
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("cannot delete RO keyword\n"));
+			return(5);
+		}
+
+		etp = pAC->vpd.vpd_buf + (vpd_size-pAC->vpd.v.vpd_free_rw-1-3);
+
+		vpd_move_para(vp.p_val+vp.p_len, etp+2,
+			- ((int)(vp.p_len + 3)));
+		if (vpd_mod_endtag(pAC, etp - vp.p_len - 3)) {
+			pAC->vpd.v.vpd_status &= ~VPD_VALID;
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("VPD encoding error\n"));
+			return(6);
+		}
+	}
+	else {
+		SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+			("keyword not found\n"));
+		return(1);
+	}
+
+	return(0);
+}
+
+/*
+ *	If the VPD buffer contains valid data write the VPD
+ *	read/write area back to the VPD EEPROM.
+ *
+ * returns	0:	success
+ *		3:	VPD transfer timeout
+ */
+int VpdUpdate(
+SK_AC	*pAC,	/* Adapters context */
+SK_IOC	IoC)	/* IO Context */
+{
+	int vpd_size;
+
+	vpd_size = pAC->vpd.vpd_size;
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("VPD update .. "));
+	if ((pAC->vpd.v.vpd_status & VPD_VALID) != 0) {
+		if (VpdTransferBlock(pAC, IoC, pAC->vpd.vpd_buf + vpd_size/2,
+			vpd_size/2, vpd_size/2, VPD_WRITE) != vpd_size/2) {
+
+			SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR,
+				("transfer timed out\n"));
+			return(3);
+		}
+	}
+	SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("done\n"));
+	return(0);
+}
+
diff --git a/drivers/net/sk98lin/skxmac2.c b/drivers/net/sk98lin/skxmac2.c
new file mode 100644
index 0000000..b4e7502
--- /dev/null
+++ b/drivers/net/sk98lin/skxmac2.c
@@ -0,0 +1,4160 @@
+/******************************************************************************
+ *
+ * Name:	skxmac2.c
+ * Project:	Gigabit Ethernet Adapters, Common Modules
+ * Version:	$Revision: 1.102 $
+ * Date:	$Date: 2003/10/02 16:53:58 $
+ * Purpose:	Contains functions to initialize the MACs and PHYs
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ *	(C)Copyright 1998-2002 SysKonnect.
+ *	(C)Copyright 2002-2003 Marvell.
+ *
+ *	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.
+ *
+ ******************************************************************************/
+
+#include "h/skdrv1st.h"
+#include "h/skdrv2nd.h"
+
+/* typedefs *******************************************************************/
+
+/* BCOM PHY magic pattern list */
+typedef struct s_PhyHack {
+	int		PhyReg;		/* Phy register */
+	SK_U16	PhyVal;		/* Value to write */
+} BCOM_HACK;
+
+/* local variables ************************************************************/
+
+#if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
+static const char SysKonnectFileId[] =
+	"@(#) $Id: skxmac2.c,v 1.102 2003/10/02 16:53:58 rschmidt Exp $ (C) Marvell.";
+#endif
+
+#ifdef GENESIS
+static BCOM_HACK BcomRegA1Hack[] = {
+ { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 }, { 0x17, 0x0013 },
+ { 0x15, 0x0404 }, { 0x17, 0x8006 }, { 0x15, 0x0132 }, { 0x17, 0x8006 },
+ { 0x15, 0x0232 }, { 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 },
+ { 0, 0 }
+};
+static BCOM_HACK BcomRegC0Hack[] = {
+ { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1204 }, { 0x17, 0x0013 },
+ { 0x15, 0x0A04 }, { 0x18, 0x0420 },
+ { 0, 0 }
+};
+#endif
+
+/* function prototypes ********************************************************/
+#ifdef GENESIS
+static void	SkXmInitPhyXmac(SK_AC*, SK_IOC, int, SK_BOOL);
+static void	SkXmInitPhyBcom(SK_AC*, SK_IOC, int, SK_BOOL);
+static int	SkXmAutoNegDoneXmac(SK_AC*, SK_IOC, int);
+static int	SkXmAutoNegDoneBcom(SK_AC*, SK_IOC, int);
+#endif /* GENESIS */
+#ifdef YUKON
+static void	SkGmInitPhyMarv(SK_AC*, SK_IOC, int, SK_BOOL);
+static int	SkGmAutoNegDoneMarv(SK_AC*, SK_IOC, int);
+#endif /* YUKON */
+#ifdef OTHER_PHY
+static void	SkXmInitPhyLone(SK_AC*, SK_IOC, int, SK_BOOL);
+static void	SkXmInitPhyNat (SK_AC*, SK_IOC, int, SK_BOOL);
+static int	SkXmAutoNegDoneLone(SK_AC*, SK_IOC, int);
+static int	SkXmAutoNegDoneNat (SK_AC*, SK_IOC, int);
+#endif /* OTHER_PHY */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *	SkXmPhyRead() - Read from XMAC PHY register
+ *
+ * Description:	reads a 16-bit word from XMAC PHY or ext. PHY
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmPhyRead(
+SK_AC	*pAC,			/* Adapter Context */
+SK_IOC	IoC,			/* I/O Context */
+int		Port,			/* Port Index (MAC_1 + n) */
+int		PhyReg,			/* Register Address (Offset) */
+SK_U16	SK_FAR *pVal)	/* Pointer to Value */
+{
+	SK_U16		Mmu;
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+	
+	/* write the PHY register's address */
+	XM_OUT16(IoC, Port, XM_PHY_ADDR, PhyReg | pPrt->PhyAddr);
+	
+	/* get the PHY register's value */
+	XM_IN16(IoC, Port, XM_PHY_DATA, pVal);
+	
+	if (pPrt->PhyType != SK_PHY_XMAC) {
+		do {
+			XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
+			/* wait until 'Ready' is set */
+		} while ((Mmu & XM_MMU_PHY_RDY) == 0);
+
+		/* get the PHY register's value */
+		XM_IN16(IoC, Port, XM_PHY_DATA, pVal);
+	}
+}	/* SkXmPhyRead */
+
+
+/******************************************************************************
+ *
+ *	SkXmPhyWrite() - Write to XMAC PHY register
+ *
+ * Description:	writes a 16-bit word to XMAC PHY or ext. PHY
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmPhyWrite(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		PhyReg,		/* Register Address (Offset) */
+SK_U16	Val)		/* Value */
+{
+	SK_U16		Mmu;
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+	
+	if (pPrt->PhyType != SK_PHY_XMAC) {
+		do {
+			XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
+			/* wait until 'Busy' is cleared */
+		} while ((Mmu & XM_MMU_PHY_BUSY) != 0);
+	}
+	
+	/* write the PHY register's address */
+	XM_OUT16(IoC, Port, XM_PHY_ADDR, PhyReg | pPrt->PhyAddr);
+	
+	/* write the PHY register's value */
+	XM_OUT16(IoC, Port, XM_PHY_DATA, Val);
+	
+	if (pPrt->PhyType != SK_PHY_XMAC) {
+		do {
+			XM_IN16(IoC, Port, XM_MMU_CMD, &Mmu);
+			/* wait until 'Busy' is cleared */
+		} while ((Mmu & XM_MMU_PHY_BUSY) != 0);
+	}
+}	/* SkXmPhyWrite */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ *	SkGmPhyRead() - Read from GPHY register
+ *
+ * Description:	reads a 16-bit word from GPHY through MDIO
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGmPhyRead(
+SK_AC	*pAC,			/* Adapter Context */
+SK_IOC	IoC,			/* I/O Context */
+int		Port,			/* Port Index (MAC_1 + n) */
+int		PhyReg,			/* Register Address (Offset) */
+SK_U16	SK_FAR *pVal)	/* Pointer to Value */
+{
+	SK_U16	Ctrl;
+	SK_GEPORT	*pPrt;
+#ifdef VCPU
+	u_long SimCyle;
+	u_long SimLowTime;
+	
+	VCPUgetTime(&SimCyle, &SimLowTime);
+	VCPUprintf(0, "SkGmPhyRead(%u), SimCyle=%u, SimLowTime=%u\n",
+		PhyReg, SimCyle, SimLowTime);
+#endif /* VCPU */
+	
+	pPrt = &pAC->GIni.GP[Port];
+	
+	/* set PHY-Register offset and 'Read' OpCode (= 1) */
+	*pVal = (SK_U16)(GM_SMI_CT_PHY_AD(pPrt->PhyAddr) |
+		GM_SMI_CT_REG_AD(PhyReg) | GM_SMI_CT_OP_RD);
+
+	GM_OUT16(IoC, Port, GM_SMI_CTRL, *pVal);
+
+	GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+	
+	/* additional check for MDC/MDIO activity */
+	if ((Ctrl & GM_SMI_CT_BUSY) == 0) {
+		*pVal = 0;
+		return;
+	}
+
+	*pVal |= GM_SMI_CT_BUSY;
+	
+	do {
+#ifdef VCPU
+		VCPUwaitTime(1000);
+#endif /* VCPU */
+
+		GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+
+	/* wait until 'ReadValid' is set */
+	} while (Ctrl == *pVal);
+	
+	/* get the PHY register's value */
+	GM_IN16(IoC, Port, GM_SMI_DATA, pVal);
+
+#ifdef VCPU
+	VCPUgetTime(&SimCyle, &SimLowTime);
+	VCPUprintf(0, "VCPUgetTime(), SimCyle=%u, SimLowTime=%u\n",
+		SimCyle, SimLowTime);
+#endif /* VCPU */
+
+}	/* SkGmPhyRead */
+
+
+/******************************************************************************
+ *
+ *	SkGmPhyWrite() - Write to GPHY register
+ *
+ * Description:	writes a 16-bit word to GPHY through MDIO
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGmPhyWrite(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		PhyReg,		/* Register Address (Offset) */
+SK_U16	Val)		/* Value */
+{
+	SK_U16	Ctrl;
+	SK_GEPORT	*pPrt;
+#ifdef VCPU
+	SK_U32	DWord;
+	u_long	SimCyle;
+	u_long	SimLowTime;
+	
+	VCPUgetTime(&SimCyle, &SimLowTime);
+	VCPUprintf(0, "SkGmPhyWrite(Reg=%u, Val=0x%04x), SimCyle=%u, SimLowTime=%u\n",
+		PhyReg, Val, SimCyle, SimLowTime);
+#endif /* VCPU */
+	
+	pPrt = &pAC->GIni.GP[Port];
+	
+	/* write the PHY register's value */
+	GM_OUT16(IoC, Port, GM_SMI_DATA, Val);
+	
+	/* set PHY-Register offset and 'Write' OpCode (= 0) */
+	Val = GM_SMI_CT_PHY_AD(pPrt->PhyAddr) | GM_SMI_CT_REG_AD(PhyReg);
+
+	GM_OUT16(IoC, Port, GM_SMI_CTRL, Val);
+
+	GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+	
+	/* additional check for MDC/MDIO activity */
+	if ((Ctrl & GM_SMI_CT_BUSY) == 0) {
+		return;
+	}
+	
+	Val |= GM_SMI_CT_BUSY;
+
+	do {
+#ifdef VCPU
+		/* read Timer value */
+		SK_IN32(IoC, B2_TI_VAL, &DWord);
+
+		VCPUwaitTime(1000);
+#endif /* VCPU */
+
+		GM_IN16(IoC, Port, GM_SMI_CTRL, &Ctrl);
+
+	/* wait until 'Busy' is cleared */
+	} while (Ctrl == Val);
+	
+#ifdef VCPU
+	VCPUgetTime(&SimCyle, &SimLowTime);
+	VCPUprintf(0, "VCPUgetTime(), SimCyle=%u, SimLowTime=%u\n",
+		SimCyle, SimLowTime);
+#endif /* VCPU */
+
+}	/* SkGmPhyWrite */
+#endif /* YUKON */
+
+
+#ifdef SK_DIAG
+/******************************************************************************
+ *
+ *	SkGePhyRead() - Read from PHY register
+ *
+ * Description:	calls a read PHY routine dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGePhyRead(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		PhyReg,		/* Register Address (Offset) */
+SK_U16	*pVal)		/* Pointer to Value */
+{
+	void (*r_func)(SK_AC *pAC, SK_IOC IoC, int Port, int Reg, SK_U16 *pVal);
+
+	if (pAC->GIni.GIGenesis) {
+		r_func = SkXmPhyRead;
+	}
+	else {
+		r_func = SkGmPhyRead;
+	}
+	
+	r_func(pAC, IoC, Port, PhyReg, pVal);
+}	/* SkGePhyRead */
+
+
+/******************************************************************************
+ *
+ *	SkGePhyWrite() - Write to PHY register
+ *
+ * Description:	calls a write PHY routine dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGePhyWrite(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* I/O Context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		PhyReg,		/* Register Address (Offset) */
+SK_U16	Val)		/* Value */
+{
+	void (*w_func)(SK_AC *pAC, SK_IOC IoC, int Port, int Reg, SK_U16 Val);
+
+	if (pAC->GIni.GIGenesis) {
+		w_func = SkXmPhyWrite;
+	}
+	else {
+		w_func = SkGmPhyWrite;
+	}
+	
+	w_func(pAC, IoC, Port, PhyReg, Val);
+}	/* SkGePhyWrite */
+#endif /* SK_DIAG */
+
+
+/******************************************************************************
+ *
+ *	SkMacPromiscMode() - Enable / Disable Promiscuous Mode
+ *
+ * Description:
+ *   enables / disables promiscuous mode by setting Mode Register (XMAC) or
+ *   Receive Control Register (GMAC) dep. on board type   	
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacPromiscMode(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port,	/* Port Index (MAC_1 + n) */
+SK_BOOL	Enable)	/* Enable / Disable */
+{
+#ifdef YUKON
+	SK_U16	RcReg;
+#endif
+#ifdef GENESIS
+	SK_U32	MdReg;
+#endif	
+
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+		
+		XM_IN32(IoC, Port, XM_MODE, &MdReg);
+		/* enable or disable promiscuous mode */
+		if (Enable) {
+			MdReg |= XM_MD_ENA_PROM;
+		}
+		else {
+			MdReg &= ~XM_MD_ENA_PROM;
+		}
+		/* setup Mode Register */
+		XM_OUT32(IoC, Port, XM_MODE, MdReg);
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		
+		GM_IN16(IoC, Port, GM_RX_CTRL, &RcReg);
+		
+		/* enable or disable unicast and multicast filtering */
+		if (Enable) {
+			RcReg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
+		}
+		else {
+			RcReg |= (GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
+		}
+		/* setup Receive Control Register */
+		GM_OUT16(IoC, Port, GM_RX_CTRL, RcReg);
+	}
+#endif /* YUKON */
+
+}	/* SkMacPromiscMode*/
+
+
+/******************************************************************************
+ *
+ *	SkMacHashing() - Enable / Disable Hashing
+ *
+ * Description:
+ *   enables / disables hashing by setting Mode Register (XMAC) or
+ *   Receive Control Register (GMAC) dep. on board type		
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacHashing(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port,	/* Port Index (MAC_1 + n) */
+SK_BOOL	Enable)	/* Enable / Disable */
+{
+#ifdef YUKON
+	SK_U16	RcReg;
+#endif	
+#ifdef GENESIS
+	SK_U32	MdReg;
+#endif
+
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+		
+		XM_IN32(IoC, Port, XM_MODE, &MdReg);
+		/* enable or disable hashing */
+		if (Enable) {
+			MdReg |= XM_MD_ENA_HASH;
+		}
+		else {
+			MdReg &= ~XM_MD_ENA_HASH;
+		}
+		/* setup Mode Register */
+		XM_OUT32(IoC, Port, XM_MODE, MdReg);
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		
+		GM_IN16(IoC, Port, GM_RX_CTRL, &RcReg);
+		
+		/* enable or disable multicast filtering */
+		if (Enable) {
+			RcReg |= GM_RXCR_MCF_ENA;
+		}
+		else {
+			RcReg &= ~GM_RXCR_MCF_ENA;
+		}
+		/* setup Receive Control Register */
+		GM_OUT16(IoC, Port, GM_RX_CTRL, RcReg);
+	}
+#endif /* YUKON */
+
+}	/* SkMacHashing*/
+
+
+#ifdef SK_DIAG
+/******************************************************************************
+ *
+ *	SkXmSetRxCmd() - Modify the value of the XMAC's Rx Command Register
+ *
+ * Description:
+ *	The features
+ *	 - FCS stripping,					SK_STRIP_FCS_ON/OFF
+ *	 - pad byte stripping,				SK_STRIP_PAD_ON/OFF
+ *	 - don't set XMR_FS_ERR in status	SK_LENERR_OK_ON/OFF
+ *	   for inrange length error frames
+ *	 - don't set XMR_FS_ERR in status	SK_BIG_PK_OK_ON/OFF
+ *	   for frames > 1514 bytes
+ *   - enable Rx of own packets         SK_SELF_RX_ON/OFF
+ *
+ *	for incoming packets may be enabled/disabled by this function.
+ *	Additional modes may be added later.
+ *	Multiple modes can be enabled/disabled at the same time.
+ *	The new configuration is written to the Rx Command register immediately.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmSetRxCmd(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		Mode)		/* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF,
+					   SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */
+{
+	SK_U16	OldRxCmd;
+	SK_U16	RxCmd;
+
+	XM_IN16(IoC, Port, XM_RX_CMD, &OldRxCmd);
+
+	RxCmd = OldRxCmd;
+	
+	switch (Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) {
+	case SK_STRIP_FCS_ON:
+		RxCmd |= XM_RX_STRIP_FCS;
+		break;
+	case SK_STRIP_FCS_OFF:
+		RxCmd &= ~XM_RX_STRIP_FCS;
+		break;
+	}
+
+	switch (Mode & (SK_STRIP_PAD_ON | SK_STRIP_PAD_OFF)) {
+	case SK_STRIP_PAD_ON:
+		RxCmd |= XM_RX_STRIP_PAD;
+		break;
+	case SK_STRIP_PAD_OFF:
+		RxCmd &= ~XM_RX_STRIP_PAD;
+		break;
+	}
+
+	switch (Mode & (SK_LENERR_OK_ON | SK_LENERR_OK_OFF)) {
+	case SK_LENERR_OK_ON:
+		RxCmd |= XM_RX_LENERR_OK;
+		break;
+	case SK_LENERR_OK_OFF:
+		RxCmd &= ~XM_RX_LENERR_OK;
+		break;
+	}
+
+	switch (Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) {
+	case SK_BIG_PK_OK_ON:
+		RxCmd |= XM_RX_BIG_PK_OK;
+		break;
+	case SK_BIG_PK_OK_OFF:
+		RxCmd &= ~XM_RX_BIG_PK_OK;
+		break;
+	}
+
+	switch (Mode & (SK_SELF_RX_ON | SK_SELF_RX_OFF)) {
+	case SK_SELF_RX_ON:
+		RxCmd |= XM_RX_SELF_RX;
+		break;
+	case SK_SELF_RX_OFF:
+		RxCmd &= ~XM_RX_SELF_RX;
+		break;
+	}
+
+	/* Write the new mode to the Rx command register if required */
+	if (OldRxCmd != RxCmd) {
+		XM_OUT16(IoC, Port, XM_RX_CMD, RxCmd);
+	}
+}	/* SkXmSetRxCmd */
+
+
+/******************************************************************************
+ *
+ *	SkGmSetRxCmd() - Modify the value of the GMAC's Rx Control Register
+ *
+ * Description:
+ *	The features
+ *	 - FCS (CRC) stripping,				SK_STRIP_FCS_ON/OFF
+ *	 - don't set GMR_FS_LONG_ERR		SK_BIG_PK_OK_ON/OFF
+ *	   for frames > 1514 bytes
+ *   - enable Rx of own packets         SK_SELF_RX_ON/OFF
+ *
+ *	for incoming packets may be enabled/disabled by this function.
+ *	Additional modes may be added later.
+ *	Multiple modes can be enabled/disabled at the same time.
+ *	The new configuration is written to the Rx Command register immediately.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGmSetRxCmd(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		Mode)		/* Mode is SK_STRIP_FCS_ON/OFF, SK_STRIP_PAD_ON/OFF,
+					   SK_LENERR_OK_ON/OFF, or SK_BIG_PK_OK_ON/OFF */
+{
+	SK_U16	OldRxCmd;
+	SK_U16	RxCmd;
+
+	if ((Mode & (SK_STRIP_FCS_ON | SK_STRIP_FCS_OFF)) != 0) {
+		
+		GM_IN16(IoC, Port, GM_RX_CTRL, &OldRxCmd);
+
+		RxCmd = OldRxCmd;
+
+		if ((Mode & SK_STRIP_FCS_ON) != 0) {
+			RxCmd |= GM_RXCR_CRC_DIS;
+		}
+		else {
+			RxCmd &= ~GM_RXCR_CRC_DIS;
+		}
+		/* Write the new mode to the Rx control register if required */
+		if (OldRxCmd != RxCmd) {
+			GM_OUT16(IoC, Port, GM_RX_CTRL, RxCmd);
+		}
+	}
+
+	if ((Mode & (SK_BIG_PK_OK_ON | SK_BIG_PK_OK_OFF)) != 0) {
+		
+		GM_IN16(IoC, Port, GM_SERIAL_MODE, &OldRxCmd);
+
+		RxCmd = OldRxCmd;
+
+		if ((Mode & SK_BIG_PK_OK_ON) != 0) {
+			RxCmd |= GM_SMOD_JUMBO_ENA;
+		}
+		else {
+			RxCmd &= ~GM_SMOD_JUMBO_ENA;
+		}
+		/* Write the new mode to the Rx control register if required */
+		if (OldRxCmd != RxCmd) {
+			GM_OUT16(IoC, Port, GM_SERIAL_MODE, RxCmd);
+		}
+	}
+}	/* SkGmSetRxCmd */
+
+
+/******************************************************************************
+ *
+ *	SkMacSetRxCmd() - Modify the value of the MAC's Rx Control Register
+ *
+ * Description:	modifies the MAC's Rx Control reg. dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacSetRxCmd(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		Mode)		/* Rx Mode */
+{
+	if (pAC->GIni.GIGenesis) {
+		
+		SkXmSetRxCmd(pAC, IoC, Port, Mode);
+	}
+	else {
+		
+		SkGmSetRxCmd(pAC, IoC, Port, Mode);
+	}
+
+}	/* SkMacSetRxCmd */
+
+
+/******************************************************************************
+ *
+ *	SkMacCrcGener() - Enable / Disable CRC Generation
+ *
+ * Description:	enables / disables CRC generation dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacCrcGener(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port,	/* Port Index (MAC_1 + n) */
+SK_BOOL	Enable)	/* Enable / Disable */
+{
+	SK_U16	Word;
+
+	if (pAC->GIni.GIGenesis) {
+		
+		XM_IN16(IoC, Port, XM_TX_CMD, &Word);
+
+		if (Enable) {
+			Word &= ~XM_TX_NO_CRC;
+		}
+		else {
+			Word |= XM_TX_NO_CRC;
+		}
+		/* setup Tx Command Register */
+		XM_OUT16(IoC, Port, XM_TX_CMD, Word);
+	}
+	else {
+		
+		GM_IN16(IoC, Port, GM_TX_CTRL, &Word);
+		
+		if (Enable) {
+			Word &= ~GM_TXCR_CRC_DIS;
+		}
+		else {
+			Word |= GM_TXCR_CRC_DIS;
+		}
+		/* setup Tx Control Register */
+		GM_OUT16(IoC, Port, GM_TX_CTRL, Word);
+	}
+
+}	/* SkMacCrcGener*/
+
+#endif /* SK_DIAG */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *	SkXmClrExactAddr() - Clear Exact Match Address Registers
+ *
+ * Description:
+ *	All Exact Match Address registers of the XMAC 'Port' will be
+ *	cleared starting with 'StartNum' up to (and including) the
+ *	Exact Match address number of 'StopNum'.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmClrExactAddr(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+int		StartNum,	/* Begin with this Address Register Index (0..15) */
+int		StopNum)	/* Stop after finished with this Register Idx (0..15) */
+{
+	int		i;
+	SK_U16	ZeroAddr[3] = {0x0000, 0x0000, 0x0000};
+
+	if ((unsigned)StartNum > 15 || (unsigned)StopNum > 15 ||
+		StartNum > StopNum) {
+
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E001, SKERR_HWI_E001MSG);
+		return;
+	}
+
+	for (i = StartNum; i <= StopNum; i++) {
+		XM_OUTADDR(IoC, Port, XM_EXM(i), &ZeroAddr[0]);
+	}
+}	/* SkXmClrExactAddr */
+#endif /* GENESIS */
+
+
+/******************************************************************************
+ *
+ *	SkMacFlushTxFifo() - Flush the MAC's transmit FIFO
+ *
+ * Description:
+ *	Flush the transmit FIFO of the MAC specified by the index 'Port'
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacFlushTxFifo(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+#ifdef GENESIS
+	SK_U32	MdReg;
+
+	if (pAC->GIni.GIGenesis) {
+		
+		XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+		XM_OUT32(IoC, Port, XM_MODE, MdReg | XM_MD_FTF);
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		/* no way to flush the FIFO we have to issue a reset */
+		/* TBD */
+	}
+#endif /* YUKON */
+
+}	/* SkMacFlushTxFifo */
+
+
+/******************************************************************************
+ *
+ *	SkMacFlushRxFifo() - Flush the MAC's receive FIFO
+ *
+ * Description:
+ *	Flush the receive FIFO of the MAC specified by the index 'Port'
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkMacFlushRxFifo(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+#ifdef GENESIS
+	SK_U32	MdReg;
+
+	if (pAC->GIni.GIGenesis) {
+
+		XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+		XM_OUT32(IoC, Port, XM_MODE, MdReg | XM_MD_FRF);
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		/* no way to flush the FIFO we have to issue a reset */
+		/* TBD */
+	}
+#endif /* YUKON */
+
+}	/* SkMacFlushRxFifo */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *	SkXmSoftRst() - Do a XMAC software reset
+ *
+ * Description:
+ *	The PHY registers should not be destroyed during this
+ *	kind of software reset. Therefore the XMAC Software Reset
+ *	(XM_GP_RES_MAC bit in XM_GP_PORT) must not be used!
+ *
+ *	The software reset is done by
+ *		- disabling the Rx and Tx state machine,
+ *		- resetting the statistics module,
+ *		- clear all other significant XMAC Mode,
+ *		  Command, and Control Registers
+ *		- clearing the Hash Register and the
+ *		  Exact Match Address registers, and
+ *		- flushing the XMAC's Rx and Tx FIFOs.
+ *
+ * Note:
+ *	Another requirement when stopping the XMAC is to
+ *	avoid sending corrupted frames on the network.
+ *	Disabling the Tx state machine will NOT interrupt
+ *	the currently transmitted frame. But we must take care
+ *	that the Tx FIFO is cleared AFTER the current frame
+ *	is complete sent to the network.
+ *
+ *	It takes about 12ns to send a frame with 1538 bytes.
+ *	One PCI clock goes at least 15ns (66MHz). Therefore
+ *	after reading XM_GP_PORT back, we are sure that the
+ *	transmitter is disabled AND idle. And this means
+ *	we may flush the transmit FIFO now.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmSoftRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U16	ZeroAddr[4] = {0x0000, 0x0000, 0x0000, 0x0000};
+	
+	/* reset the statistics module */
+	XM_OUT32(IoC, Port, XM_GP_PORT, XM_GP_RES_STAT);
+
+	/* disable all XMAC IRQs */
+	XM_OUT16(IoC, Port, XM_IMSK, 0xffff);
+	
+	XM_OUT32(IoC, Port, XM_MODE, 0);		/* clear Mode Reg */
+	
+	XM_OUT16(IoC, Port, XM_TX_CMD, 0);		/* reset TX CMD Reg */
+	XM_OUT16(IoC, Port, XM_RX_CMD, 0);		/* reset RX CMD Reg */
+	
+	/* disable all PHY IRQs */
+	switch (pAC->GIni.GP[Port].PhyType) {
+	case SK_PHY_BCOM:
+			SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, 0xffff);
+			break;
+#ifdef OTHER_PHY
+		case SK_PHY_LONE:
+			SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, 0);
+			break;
+		case SK_PHY_NAT:
+			/* todo: National
+			 SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, 0xffff); */
+			break;
+#endif /* OTHER_PHY */
+	}
+
+	/* clear the Hash Register */
+	XM_OUTHASH(IoC, Port, XM_HSM, &ZeroAddr);
+
+	/* clear the Exact Match Address registers */
+	SkXmClrExactAddr(pAC, IoC, Port, 0, 15);
+	
+	/* clear the Source Check Address registers */
+	XM_OUTHASH(IoC, Port, XM_SRC_CHK, &ZeroAddr);
+
+}	/* SkXmSoftRst */
+
+
+/******************************************************************************
+ *
+ *	SkXmHardRst() - Do a XMAC hardware reset
+ *
+ * Description:
+ *	The XMAC of the specified 'Port' and all connected devices
+ *	(PHY and SERDES) will receive a reset signal on its *Reset pins.
+ *	External PHYs must be reset by clearing a bit in the GPIO register
+ *  (Timing requirements: Broadcom: 400ns, Level One: none, National: 80ns).
+ *
+ * ATTENTION:
+ * 	It is absolutely necessary to reset the SW_RST Bit first
+ *	before calling this function.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmHardRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U32	Reg;
+	int		i;
+	int		TOut;
+	SK_U16	Word;
+
+	for (i = 0; i < 4; i++) {
+		/* TX_MFF_CTRL1 has 32 bits, but only the lowest 16 bits are used */
+		SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
+
+		TOut = 0;
+		do {
+			if (TOut++ > 10000) {
+				/*
+				 * Adapter seems to be in RESET state.
+				 * Registers cannot be written.
+				 */
+				return;
+			}
+
+			SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
+			
+			SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &Word);
+		
+		} while ((Word & MFF_SET_MAC_RST) == 0);
+	}
+
+	/* For external PHYs there must be special handling */
+	if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) {
+		
+		SK_IN32(IoC, B2_GP_IO, &Reg);
+		
+		if (Port == 0) {
+			Reg |= GP_DIR_0; 	/* set to output */
+			Reg &= ~GP_IO_0;	/* set PHY reset (active low) */
+		}
+		else {
+			Reg |= GP_DIR_2;	/* set to output */
+			Reg &= ~GP_IO_2;	/* set PHY reset (active low) */
+		}
+		/* reset external PHY */
+		SK_OUT32(IoC, B2_GP_IO, Reg);
+
+		/* short delay */
+		SK_IN32(IoC, B2_GP_IO, &Reg);
+	}
+}	/* SkXmHardRst */
+
+
+/******************************************************************************
+ *
+ *	SkXmClearRst() - Release the PHY & XMAC reset
+ *
+ * Description:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmClearRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U32	DWord;
+	
+	/* clear HW reset */
+	SK_OUT16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
+
+	if (pAC->GIni.GP[Port].PhyType != SK_PHY_XMAC) {
+
+		SK_IN32(IoC, B2_GP_IO, &DWord);
+
+		if (Port == 0) {
+			DWord |= (GP_DIR_0 | GP_IO_0); /* set to output */
+		}
+		else {
+			DWord |= (GP_DIR_2 | GP_IO_2); /* set to output */
+		}
+		/* Clear PHY reset */
+		SK_OUT32(IoC, B2_GP_IO, DWord);
+
+		/* Enable GMII interface */
+		XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_GMII_MD);
+	}
+}	/* SkXmClearRst */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ *	SkGmSoftRst() - Do a GMAC software reset
+ *
+ * Description:
+ *	The GPHY registers should not be destroyed during this
+ *	kind of software reset.
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGmSoftRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U16	EmptyHash[4] = {0x0000, 0x0000, 0x0000, 0x0000};
+	SK_U16  RxCtrl;
+
+	/* reset the statistics module */
+
+	/* disable all GMAC IRQs */
+	SK_OUT8(IoC, GMAC_IRQ_MSK, 0);
+	
+	/* disable all PHY IRQs */
+	SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, 0);
+	
+	/* clear the Hash Register */
+	GM_OUTHASH(IoC, Port, GM_MC_ADDR_H1, EmptyHash);
+
+	/* Enable Unicast and Multicast filtering */
+	GM_IN16(IoC, Port, GM_RX_CTRL, &RxCtrl);
+	
+	GM_OUT16(IoC, Port, GM_RX_CTRL,
+		(SK_U16)(RxCtrl | GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA));
+
+}	/* SkGmSoftRst */
+
+
+/******************************************************************************
+ *
+ *	SkGmHardRst() - Do a GMAC hardware reset
+ *
+ * Description:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGmHardRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U32	DWord;
+	
+	/* WA code for COMA mode */
+	if (pAC->GIni.GIYukonLite &&
+		pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) {
+		
+		SK_IN32(IoC, B2_GP_IO, &DWord);
+
+		DWord |= (GP_DIR_9 | GP_IO_9);
+
+		/* set PHY reset */
+		SK_OUT32(IoC, B2_GP_IO, DWord);
+	}
+
+	/* set GPHY Control reset */
+	SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), GPC_RST_SET);
+
+	/* set GMAC Control reset */
+	SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET);
+
+}	/* SkGmHardRst */
+
+
+/******************************************************************************
+ *
+ *	SkGmClearRst() - Release the GPHY & GMAC reset
+ *
+ * Description:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGmClearRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U32	DWord;
+	
+#ifdef XXX
+		/* clear GMAC Control reset */
+		SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_CLR);
+
+		/* set GMAC Control reset */
+		SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_RST_SET);
+#endif /* XXX */
+
+	/* WA code for COMA mode */
+	if (pAC->GIni.GIYukonLite &&
+		pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) {
+		
+		SK_IN32(IoC, B2_GP_IO, &DWord);
+
+		DWord |= GP_DIR_9;		/* set to output */
+		DWord &= ~GP_IO_9;		/* clear PHY reset (active high) */
+
+		/* clear PHY reset */
+		SK_OUT32(IoC, B2_GP_IO, DWord);
+	}
+
+	/* set HWCFG_MODE */
+	DWord = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP |
+		GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE |
+		(pAC->GIni.GICopperType ? GPC_HWCFG_GMII_COP :
+		GPC_HWCFG_GMII_FIB);
+
+	/* set GPHY Control reset */
+	SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_SET);
+
+	/* release GPHY Control reset */
+	SK_OUT32(IoC, MR_ADDR(Port, GPHY_CTRL), DWord | GPC_RST_CLR);
+
+#ifdef VCPU
+	VCpuWait(9000);
+#endif /* VCPU */
+
+	/* clear GMAC Control reset */
+	SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR);
+
+#ifdef VCPU
+	VCpuWait(2000);
+	
+	SK_IN32(IoC, MR_ADDR(Port, GPHY_CTRL), &DWord);
+			
+	SK_IN32(IoC, B0_ISRC, &DWord);
+#endif /* VCPU */
+
+}	/* SkGmClearRst */
+#endif /* YUKON */
+
+
+/******************************************************************************
+ *
+ *	SkMacSoftRst() - Do a MAC software reset
+ *
+ * Description:	calls a MAC software reset routine dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacSoftRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* disable receiver and transmitter */
+	SkMacRxTxDisable(pAC, IoC, Port);
+
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+		
+		SkXmSoftRst(pAC, IoC, Port);
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		
+		SkGmSoftRst(pAC, IoC, Port);
+	}
+#endif /* YUKON */
+
+	/* flush the MAC's Rx and Tx FIFOs */
+	SkMacFlushTxFifo(pAC, IoC, Port);
+	
+	SkMacFlushRxFifo(pAC, IoC, Port);
+
+	pPrt->PState = SK_PRT_STOP;
+
+}	/* SkMacSoftRst */
+
+
+/******************************************************************************
+ *
+ *	SkMacHardRst() - Do a MAC hardware reset
+ *
+ * Description:	calls a MAC hardware reset routine dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacHardRst(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port)	/* Port Index (MAC_1 + n) */
+{
+	
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+		
+		SkXmHardRst(pAC, IoC, Port);
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		
+		SkGmHardRst(pAC, IoC, Port);
+	}
+#endif /* YUKON */
+
+	pAC->GIni.GP[Port].PState = SK_PRT_RESET;
+
+}	/* SkMacHardRst */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *	SkXmInitMac() - Initialize the XMAC II
+ *
+ * Description:
+ *	Initialize the XMAC of the specified port.
+ *	The XMAC must be reset or stopped before calling this function.
+ *
+ * Note:
+ *	The XMAC's Rx and Tx state machine is still disabled when returning.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmInitMac(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	int			i;
+	SK_U16		SWord;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PState == SK_PRT_STOP) {
+		/* Port State: SK_PRT_STOP */
+		/* Verify that the reset bit is cleared */
+		SK_IN16(IoC, MR_ADDR(Port, TX_MFF_CTRL1), &SWord);
+
+		if ((SWord & MFF_SET_MAC_RST) != 0) {
+			/* PState does not match HW state */
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006, SKERR_HWI_E006MSG);
+			/* Correct it */
+			pPrt->PState = SK_PRT_RESET;
+		}
+	}
+
+	if (pPrt->PState == SK_PRT_RESET) {
+
+		SkXmClearRst(pAC, IoC, Port);
+
+		if (pPrt->PhyType != SK_PHY_XMAC) {
+			/* read Id from external PHY (all have the same address) */
+			SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_ID1, &pPrt->PhyId1);
+
+			/*
+			 * Optimize MDIO transfer by suppressing preamble.
+			 * Must be done AFTER first access to BCOM chip.
+			 */
+			XM_IN16(IoC, Port, XM_MMU_CMD, &SWord);
+			
+			XM_OUT16(IoC, Port, XM_MMU_CMD, SWord | XM_MMU_NO_PRE);
+
+			if (pPrt->PhyId1 == PHY_BCOM_ID1_C0) {
+				/*
+				 * Workaround BCOM Errata for the C0 type.
+				 * Write magic patterns to reserved registers.
+				 */
+				i = 0;
+				while (BcomRegC0Hack[i].PhyReg != 0) {
+					SkXmPhyWrite(pAC, IoC, Port, BcomRegC0Hack[i].PhyReg,
+						BcomRegC0Hack[i].PhyVal);
+					i++;
+				}
+			}
+			else if (pPrt->PhyId1 == PHY_BCOM_ID1_A1) {
+				/*
+				 * Workaround BCOM Errata for the A1 type.
+				 * Write magic patterns to reserved registers.
+				 */
+				i = 0;
+				while (BcomRegA1Hack[i].PhyReg != 0) {
+					SkXmPhyWrite(pAC, IoC, Port, BcomRegA1Hack[i].PhyReg,
+						BcomRegA1Hack[i].PhyVal);
+					i++;
+				}
+			}
+
+			/*
+			 * Workaround BCOM Errata (#10523) for all BCom PHYs.
+			 * Disable Power Management after reset.
+			 */
+			SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &SWord);
+			
+			SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
+				(SK_U16)(SWord | PHY_B_AC_DIS_PM));
+
+			/* PHY LED initialization is done in SkGeXmitLED() */
+		}
+
+		/* Dummy read the Interrupt source register */
+		XM_IN16(IoC, Port, XM_ISRC, &SWord);
+		
+		/*
+		 * The auto-negotiation process starts immediately after
+		 * clearing the reset. The auto-negotiation process should be
+		 * started by the SIRQ, therefore stop it here immediately.
+		 */
+		SkMacInitPhy(pAC, IoC, Port, SK_FALSE);
+
+#ifdef TEST_ONLY
+		/* temp. code: enable signal detect */
+		/* WARNING: do not override GMII setting above */
+		XM_OUT16(IoC, Port, XM_HW_CFG, XM_HW_COM4SIG);
+#endif
+	}
+
+	/*
+	 * configure the XMACs Station Address
+	 * B2_MAC_2 = xx xx xx xx xx x1 is programmed to XMAC A
+	 * B2_MAC_3 = xx xx xx xx xx x2 is programmed to XMAC B
+	 */
+	for (i = 0; i < 3; i++) {
+		/*
+		 * The following 2 statements are together endianess
+		 * independent. Remember this when changing.
+		 */
+		SK_IN16(IoC, (B2_MAC_2 + Port * 8 + i * 2), &SWord);
+		
+		XM_OUT16(IoC, Port, (XM_SA + i * 2), SWord);
+	}
+
+	/* Tx Inter Packet Gap (XM_TX_IPG):	use default */
+	/* Tx High Water Mark (XM_TX_HI_WM):	use default */
+	/* Tx Low Water Mark (XM_TX_LO_WM):	use default */
+	/* Host Request Threshold (XM_HT_THR):	use default */
+	/* Rx Request Threshold (XM_RX_THR):	use default */
+	/* Rx Low Water Mark (XM_RX_LO_WM):	use default */
+
+	/* configure Rx High Water Mark (XM_RX_HI_WM) */
+	XM_OUT16(IoC, Port, XM_RX_HI_WM, SK_XM_RX_HI_WM);
+
+	/* Configure Tx Request Threshold */
+	SWord = SK_XM_THR_SL;				/* for single port */
+
+	if (pAC->GIni.GIMacsFound > 1) {
+		switch (pAC->GIni.GIPortUsage) {
+		case SK_RED_LINK:
+			SWord = SK_XM_THR_REDL;		/* redundant link */
+			break;
+		case SK_MUL_LINK:
+			SWord = SK_XM_THR_MULL;		/* load balancing */
+			break;
+		case SK_JUMBO_LINK:
+			SWord = SK_XM_THR_JUMBO;	/* jumbo frames */
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E014, SKERR_HWI_E014MSG);
+			break;
+		}
+	}
+	XM_OUT16(IoC, Port, XM_TX_THR, SWord);
+
+	/* setup register defaults for the Tx Command Register */
+	XM_OUT16(IoC, Port, XM_TX_CMD, XM_TX_AUTO_PAD);
+
+	/* setup register defaults for the Rx Command Register */
+	SWord = XM_RX_STRIP_FCS | XM_RX_LENERR_OK;
+
+	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+		SWord |= XM_RX_BIG_PK_OK;
+	}
+
+	if (pPrt->PLinkMode == SK_LMODE_HALF) {
+		/*
+		 * If in manual half duplex mode the other side might be in
+		 * full duplex mode, so ignore if a carrier extension is not seen
+		 * on frames received
+		 */
+		SWord |= XM_RX_DIS_CEXT;
+	}
+	
+	XM_OUT16(IoC, Port, XM_RX_CMD, SWord);
+
+	/*
+	 * setup register defaults for the Mode Register
+	 *	- Don't strip error frames to avoid Store & Forward
+	 *	  on the Rx side.
+	 *	- Enable 'Check Station Address' bit
+	 *	- Enable 'Check Address Array' bit
+	 */
+	XM_OUT32(IoC, Port, XM_MODE, XM_DEF_MODE);
+
+	/*
+	 * Initialize the Receive Counter Event Mask (XM_RX_EV_MSK)
+	 *	- Enable all bits excepting 'Octets Rx OK Low CntOv'
+	 *	  and 'Octets Rx OK Hi Cnt Ov'.
+	 */
+	XM_OUT32(IoC, Port, XM_RX_EV_MSK, XMR_DEF_MSK);
+
+	/*
+	 * Initialize the Transmit Counter Event Mask (XM_TX_EV_MSK)
+	 *	- Enable all bits excepting 'Octets Tx OK Low CntOv'
+	 *	  and 'Octets Tx OK Hi Cnt Ov'.
+	 */
+	XM_OUT32(IoC, Port, XM_TX_EV_MSK, XMT_DEF_MSK);
+
+	/*
+	 * Do NOT init XMAC interrupt mask here.
+	 * All interrupts remain disable until link comes up!
+	 */
+
+	/*
+	 * Any additional configuration changes may be done now.
+	 * The last action is to enable the Rx and Tx state machine.
+	 * This should be done after the auto-negotiation process
+	 * has been completed successfully.
+	 */
+}	/* SkXmInitMac */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ *	SkGmInitMac() - Initialize the GMAC
+ *
+ * Description:
+ *	Initialize the GMAC of the specified port.
+ *	The GMAC must be reset or stopped before calling this function.
+ *
+ * Note:
+ *	The GMAC's Rx and Tx state machine is still disabled when returning.
+ *
+ * Returns:
+ *	nothing
+ */
+void SkGmInitMac(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	int			i;
+	SK_U16		SWord;
+	SK_U32		DWord;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PState == SK_PRT_STOP) {
+		/* Port State: SK_PRT_STOP */
+		/* Verify that the reset bit is cleared */
+		SK_IN32(IoC, MR_ADDR(Port, GMAC_CTRL), &DWord);
+		
+		if ((DWord & GMC_RST_SET) != 0) {
+			/* PState does not match HW state */
+			SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E006, SKERR_HWI_E006MSG);
+			/* Correct it */
+			pPrt->PState = SK_PRT_RESET;
+		}
+	}
+
+	if (pPrt->PState == SK_PRT_RESET) {
+		
+		SkGmHardRst(pAC, IoC, Port);
+
+		SkGmClearRst(pAC, IoC, Port);
+		
+		/* Auto-negotiation ? */
+		if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+			/* Auto-negotiation disabled */
+
+			/* get General Purpose Control */
+			GM_IN16(IoC, Port, GM_GP_CTRL, &SWord);
+
+			/* disable auto-update for speed, duplex and flow-control */
+			SWord |= GM_GPCR_AU_ALL_DIS;
+			
+			/* setup General Purpose Control Register */
+			GM_OUT16(IoC, Port, GM_GP_CTRL, SWord);
+			
+			SWord = GM_GPCR_AU_ALL_DIS;
+		}
+		else {
+			SWord = 0;
+		}
+
+		/* speed settings */
+		switch (pPrt->PLinkSpeed) {
+		case SK_LSPEED_AUTO:
+		case SK_LSPEED_1000MBPS:
+			SWord |= GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100;
+			break;
+		case SK_LSPEED_100MBPS:
+			SWord |= GM_GPCR_SPEED_100;
+			break;
+		case SK_LSPEED_10MBPS:
+			break;
+		}
+
+		/* duplex settings */
+		if (pPrt->PLinkMode != SK_LMODE_HALF) {
+			/* set full duplex */
+			SWord |= GM_GPCR_DUP_FULL;
+		}
+
+		/* flow-control settings */
+		switch (pPrt->PFlowCtrlMode) {
+		case SK_FLOW_MODE_NONE:
+			/* set Pause Off */
+			SK_OUT32(IoC, MR_ADDR(Port, GMAC_CTRL), GMC_PAUSE_OFF);
+			/* disable Tx & Rx flow-control */
+			SWord |= GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
+			break;
+		case SK_FLOW_MODE_LOC_SEND:
+			/* disable Rx flow-control */
+			SWord |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
+			break;
+		case SK_FLOW_MODE_SYMMETRIC:
+		case SK_FLOW_MODE_SYM_OR_REM:
+			/* enable Tx & Rx flow-control */
+			break;
+		}
+
+		/* setup General Purpose Control Register */
+		GM_OUT16(IoC, Port, GM_GP_CTRL, SWord);
+
+		/* dummy read the Interrupt Source Register */
+		SK_IN16(IoC, GMAC_IRQ_SRC, &SWord);
+		
+#ifndef VCPU
+		/* read Id from PHY */
+		SkGmPhyRead(pAC, IoC, Port, PHY_MARV_ID1, &pPrt->PhyId1);
+		
+		SkGmInitPhyMarv(pAC, IoC, Port, SK_FALSE);
+#endif /* VCPU */
+	}
+
+	(void)SkGmResetCounter(pAC, IoC, Port);
+
+	/* setup Transmit Control Register */
+	GM_OUT16(IoC, Port, GM_TX_CTRL, TX_COL_THR(pPrt->PMacColThres));
+
+	/* setup Receive Control Register */
+	GM_OUT16(IoC, Port, GM_RX_CTRL, GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA |
+		GM_RXCR_CRC_DIS);
+
+	/* setup Transmit Flow Control Register */
+	GM_OUT16(IoC, Port, GM_TX_FLOW_CTRL, 0xffff);
+
+	/* setup Transmit Parameter Register */
+#ifdef VCPU
+	GM_IN16(IoC, Port, GM_TX_PARAM, &SWord);
+#endif /* VCPU */
+
+    SWord = TX_JAM_LEN_VAL(pPrt->PMacJamLen) |
+			TX_JAM_IPG_VAL(pPrt->PMacJamIpgVal) |
+			TX_IPG_JAM_DATA(pPrt->PMacJamIpgData);
+	
+	GM_OUT16(IoC, Port, GM_TX_PARAM, SWord);
+
+	/* configure the Serial Mode Register */
+#ifdef VCPU
+	GM_IN16(IoC, Port, GM_SERIAL_MODE, &SWord);
+#endif /* VCPU */
+	
+	SWord = GM_SMOD_VLAN_ENA | IPG_DATA_VAL(pPrt->PMacIpgData);
+
+	if (pPrt->PMacLimit4) {
+		/* reset of collision counter after 4 consecutive collisions */
+		SWord |= GM_SMOD_LIMIT_4;
+	}
+
+	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+		/* enable jumbo mode (Max. Frame Length = 9018) */
+		SWord |= GM_SMOD_JUMBO_ENA;
+	}
+	
+	GM_OUT16(IoC, Port, GM_SERIAL_MODE, SWord);
+	
+	/*
+	 * configure the GMACs Station Addresses
+	 * in PROM you can find our addresses at:
+	 * B2_MAC_1 = xx xx xx xx xx x0 virtual address
+	 * B2_MAC_2 = xx xx xx xx xx x1 is programmed to GMAC A
+	 * B2_MAC_3 = xx xx xx xx xx x2 is reserved for DualPort
+	 */
+
+	for (i = 0; i < 3; i++) {
+		/*
+		 * The following 2 statements are together endianess
+		 * independent. Remember this when changing.
+		 */
+		/* physical address: will be used for pause frames */
+		SK_IN16(IoC, (B2_MAC_2 + Port * 8 + i * 2), &SWord);
+
+#ifdef WA_DEV_16
+		/* WA for deviation #16 */
+		if (pAC->GIni.GIChipId == CHIP_ID_YUKON && pAC->GIni.GIChipRev == 0) {
+			/* swap the address bytes */
+			SWord = ((SWord & 0xff00) >> 8)	| ((SWord & 0x00ff) << 8);
+
+			/* write to register in reversed order */
+			GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + (2 - i) * 4), SWord);
+		}
+		else {
+			GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + i * 4), SWord);
+		}
+#else		
+		GM_OUT16(IoC, Port, (GM_SRC_ADDR_1L + i * 4), SWord);
+#endif /* WA_DEV_16 */
+		
+		/* virtual address: will be used for data */
+		SK_IN16(IoC, (B2_MAC_1 + Port * 8 + i * 2), &SWord);
+
+		GM_OUT16(IoC, Port, (GM_SRC_ADDR_2L + i * 4), SWord);
+		
+		/* reset Multicast filtering Hash registers 1-3 */
+		GM_OUT16(IoC, Port, GM_MC_ADDR_H1 + 4*i, 0);
+	}
+
+	/* reset Multicast filtering Hash register 4 */
+	GM_OUT16(IoC, Port, GM_MC_ADDR_H4, 0);
+
+	/* enable interrupt mask for counter overflows */
+	GM_OUT16(IoC, Port, GM_TX_IRQ_MSK, 0);
+	GM_OUT16(IoC, Port, GM_RX_IRQ_MSK, 0);
+	GM_OUT16(IoC, Port, GM_TR_IRQ_MSK, 0);
+
+#if defined(SK_DIAG) || defined(DEBUG)
+	/* read General Purpose Status */
+	GM_IN16(IoC, Port, GM_GP_STAT, &SWord);
+	
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("MAC Stat Reg.=0x%04X\n", SWord));
+#endif /* SK_DIAG || DEBUG */
+
+#ifdef SK_DIAG
+	c_print("MAC Stat Reg=0x%04X\n", SWord);
+#endif /* SK_DIAG */
+
+}	/* SkGmInitMac */
+#endif /* YUKON */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *	SkXmInitDupMd() - Initialize the XMACs Duplex Mode
+ *
+ * Description:
+ *	This function initializes the XMACs Duplex Mode.
+ *	It should be called after successfully finishing
+ *	the Auto-negotiation Process
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmInitDupMd(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	switch (pAC->GIni.GP[Port].PLinkModeStatus) {
+	case SK_LMODE_STAT_AUTOHALF:
+	case SK_LMODE_STAT_HALF:
+		/* Configuration Actions for Half Duplex Mode */
+		/*
+		 * XM_BURST = default value. We are probable not quick
+		 * 	enough at the 'XMAC' bus to burst 8kB.
+		 *	The XMAC stops bursting if no transmit frames
+		 *	are available or the burst limit is exceeded.
+		 */
+		/* XM_TX_RT_LIM = default value (15) */
+		/* XM_TX_STIME = default value (0xff = 4096 bit times) */
+		break;
+	case SK_LMODE_STAT_AUTOFULL:
+	case SK_LMODE_STAT_FULL:
+		/* Configuration Actions for Full Duplex Mode */
+		/*
+		 * The duplex mode is configured by the PHY,
+		 * therefore it seems to be that there is nothing
+		 * to do here.
+		 */
+		break;
+	case SK_LMODE_STAT_UNKNOWN:
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E007, SKERR_HWI_E007MSG);
+		break;
+	}
+}	/* SkXmInitDupMd */
+
+
+/******************************************************************************
+ *
+ *	SkXmInitPauseMd() - initialize the Pause Mode to be used for this port
+ *
+ * Description:
+ *	This function initializes the Pause Mode which should
+ *	be used for this port.
+ *	It should be called after successfully finishing
+ *	the Auto-negotiation Process
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmInitPauseMd(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U32		DWord;
+	SK_U16		Word;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+	
+	if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_NONE ||
+		pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) {
+
+		/* Disable Pause Frame Reception */
+		Word |= XM_MMU_IGN_PF;
+	}
+	else {
+		/*
+		 * enabling pause frame reception is required for 1000BT
+		 * because the XMAC is not reset if the link is going down
+		 */
+		/* Enable Pause Frame Reception */
+		Word &= ~XM_MMU_IGN_PF;
+	}	
+	
+	XM_OUT16(IoC, Port, XM_MMU_CMD, Word);
+
+	XM_IN32(IoC, Port, XM_MODE, &DWord);
+
+	if (pPrt->PFlowCtrlStatus == SK_FLOW_STAT_SYMMETRIC ||
+		pPrt->PFlowCtrlStatus == SK_FLOW_STAT_LOC_SEND) {
+
+		/*
+		 * Configure Pause Frame Generation
+		 * Use internal and external Pause Frame Generation.
+		 * Sending pause frames is edge triggered.
+		 * Send a Pause frame with the maximum pause time if
+		 * internal oder external FIFO full condition occurs.
+		 * Send a zero pause time frame to re-start transmission.
+		 */
+
+		/* XM_PAUSE_DA = '010000C28001' (default) */
+
+		/* XM_MAC_PTIME = 0xffff (maximum) */
+		/* remember this value is defined in big endian (!) */
+		XM_OUT16(IoC, Port, XM_MAC_PTIME, 0xffff);
+
+		/* Set Pause Mode in Mode Register */
+		DWord |= XM_PAUSE_MODE;
+
+		/* Set Pause Mode in MAC Rx FIFO */
+		SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_ENA_PAUSE);
+	}
+	else {
+		/*
+		 * disable pause frame generation is required for 1000BT
+		 * because the XMAC is not reset if the link is going down
+		 */
+		/* Disable Pause Mode in Mode Register */
+		DWord &= ~XM_PAUSE_MODE;
+
+		/* Disable Pause Mode in MAC Rx FIFO */
+		SK_OUT16(IoC, MR_ADDR(Port, RX_MFF_CTRL1), MFF_DIS_PAUSE);
+	}
+	
+	XM_OUT32(IoC, Port, XM_MODE, DWord);
+}	/* SkXmInitPauseMd*/
+
+
+/******************************************************************************
+ *
+ *	SkXmInitPhyXmac() - Initialize the XMAC Phy registers
+ *
+ * Description:	initializes all the XMACs Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmInitPhyXmac(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LoopBack be set-up? */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Ctrl;
+
+	pPrt = &pAC->GIni.GP[Port];
+	Ctrl = 0;
+	
+	/* Auto-negotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyXmac: no auto-negotiation Port %d\n", Port));
+		/* Set DuplexMode in Config register */
+		if (pPrt->PLinkMode == SK_LMODE_FULL) {
+			Ctrl |= PHY_CT_DUP_MD;
+		}
+
+		/*
+		 * Do NOT enable Auto-negotiation here. This would hold
+		 * the link down because no IDLEs are transmitted
+		 */
+	}
+	else {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyXmac: with auto-negotiation Port %d\n", Port));
+		/* Set Auto-negotiation advertisement */
+
+		/* Set Full/half duplex capabilities */
+		switch (pPrt->PLinkMode) {
+		case SK_LMODE_AUTOHALF:
+			Ctrl |= PHY_X_AN_HD;
+			break;
+		case SK_LMODE_AUTOFULL:
+			Ctrl |= PHY_X_AN_FD;
+			break;
+		case SK_LMODE_AUTOBOTH:
+			Ctrl |= PHY_X_AN_FD | PHY_X_AN_HD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+				SKERR_HWI_E015MSG);
+		}
+
+		/* Set Flow-control capabilities */
+		switch (pPrt->PFlowCtrlMode) {
+		case SK_FLOW_MODE_NONE:
+			Ctrl |= PHY_X_P_NO_PAUSE;
+			break;
+		case SK_FLOW_MODE_LOC_SEND:
+			Ctrl |= PHY_X_P_ASYM_MD;
+			break;
+		case SK_FLOW_MODE_SYMMETRIC:
+			Ctrl |= PHY_X_P_SYM_MD;
+			break;
+		case SK_FLOW_MODE_SYM_OR_REM:
+			Ctrl |= PHY_X_P_BOTH_MD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+				SKERR_HWI_E016MSG);
+		}
+
+		/* Write AutoNeg Advertisement Register */
+		SkXmPhyWrite(pAC, IoC, Port, PHY_XMAC_AUNE_ADV, Ctrl);
+
+		/* Restart Auto-negotiation */
+		Ctrl = PHY_CT_ANE | PHY_CT_RE_CFG;
+	}
+
+	if (DoLoop) {
+		/* Set the Phy Loopback bit, too */
+		Ctrl |= PHY_CT_LOOP;
+	}
+
+	/* Write to the Phy control register */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_XMAC_CTRL, Ctrl);
+}	/* SkXmInitPhyXmac */
+
+
+/******************************************************************************
+ *
+ *	SkXmInitPhyBcom() - Initialize the Broadcom Phy registers
+ *
+ * Description:	initializes all the Broadcom Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmInitPhyBcom(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LoopBack be set-up? */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Ctrl1;
+	SK_U16		Ctrl2;
+	SK_U16		Ctrl3;
+	SK_U16		Ctrl4;
+	SK_U16		Ctrl5;
+
+	Ctrl1 = PHY_CT_SP1000;
+	Ctrl2 = 0;
+	Ctrl3 = PHY_SEL_TYPE;
+	Ctrl4 = PHY_B_PEC_EN_LTR;
+	Ctrl5 = PHY_B_AC_TX_TST;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* manually Master/Slave ? */
+	if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
+		Ctrl2 |= PHY_B_1000C_MSE;
+		
+		if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
+			Ctrl2 |= PHY_B_1000C_MSC;
+		}
+	}
+	/* Auto-negotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyBcom: no auto-negotiation Port %d\n", Port));
+		/* Set DuplexMode in Config register */
+		if (pPrt->PLinkMode == SK_LMODE_FULL) {
+			Ctrl1 |= PHY_CT_DUP_MD;
+		}
+
+		/* Determine Master/Slave manually if not already done */
+		if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
+			Ctrl2 |= PHY_B_1000C_MSE;	/* set it to Slave */
+		}
+
+		/*
+		 * Do NOT enable Auto-negotiation here. This would hold
+		 * the link down because no IDLES are transmitted
+		 */
+	}
+	else {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyBcom: with auto-negotiation Port %d\n", Port));
+		/* Set Auto-negotiation advertisement */
+
+		/*
+		 * Workaround BCOM Errata #1 for the C5 type.
+		 * 1000Base-T Link Acquisition Failure in Slave Mode
+		 * Set Repeater/DTE bit 10 of the 1000Base-T Control Register
+		 */
+		Ctrl2 |= PHY_B_1000C_RD;
+		
+		 /* Set Full/half duplex capabilities */
+		switch (pPrt->PLinkMode) {
+		case SK_LMODE_AUTOHALF:
+			Ctrl2 |= PHY_B_1000C_AHD;
+			break;
+		case SK_LMODE_AUTOFULL:
+			Ctrl2 |= PHY_B_1000C_AFD;
+			break;
+		case SK_LMODE_AUTOBOTH:
+			Ctrl2 |= PHY_B_1000C_AFD | PHY_B_1000C_AHD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+				SKERR_HWI_E015MSG);
+		}
+
+		/* Set Flow-control capabilities */
+		switch (pPrt->PFlowCtrlMode) {
+		case SK_FLOW_MODE_NONE:
+			Ctrl3 |= PHY_B_P_NO_PAUSE;
+			break;
+		case SK_FLOW_MODE_LOC_SEND:
+			Ctrl3 |= PHY_B_P_ASYM_MD;
+			break;
+		case SK_FLOW_MODE_SYMMETRIC:
+			Ctrl3 |= PHY_B_P_SYM_MD;
+			break;
+		case SK_FLOW_MODE_SYM_OR_REM:
+			Ctrl3 |= PHY_B_P_BOTH_MD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+				SKERR_HWI_E016MSG);
+		}
+
+		/* Restart Auto-negotiation */
+		Ctrl1 |= PHY_CT_ANE | PHY_CT_RE_CFG;
+	}
+	
+	/* Initialize LED register here? */
+	/* No. Please do it in SkDgXmitLed() (if required) and swap
+	   init order of LEDs and XMAC. (MAl) */
+	
+	/* Write 1000Base-T Control Register */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_1000T_CTRL, Ctrl2);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Set 1000B-T Ctrl Reg=0x%04X\n", Ctrl2));
+	
+	/* Write AutoNeg Advertisement Register */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUNE_ADV, Ctrl3);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Set Auto-Neg.Adv.Reg=0x%04X\n", Ctrl3));
+	
+	if (DoLoop) {
+		/* Set the Phy Loopback bit, too */
+		Ctrl1 |= PHY_CT_LOOP;
+	}
+
+	if (pAC->GIni.GIPortUsage == SK_JUMBO_LINK) {
+		/* configure FIFO to high latency for transmission of ext. packets */
+		Ctrl4 |= PHY_B_PEC_HIGH_LA;
+
+		/* configure reception of extended packets */
+		Ctrl5 |= PHY_B_AC_LONG_PACK;
+
+		SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, Ctrl5);
+	}
+
+	/* Configure LED Traffic Mode and Jumbo Frame usage if specified */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_P_EXT_CTRL, Ctrl4);
+	
+	/* Write to the Phy control register */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_CTRL, Ctrl1);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Control Reg=0x%04X\n", Ctrl1));
+}	/* SkXmInitPhyBcom */
+#endif /* GENESIS */
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ *	SkGmInitPhyMarv() - Initialize the Marvell Phy registers
+ *
+ * Description:	initializes all the Marvell Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGmInitPhyMarv(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LoopBack be set-up? */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		PhyCtrl;
+	SK_U16		C1000BaseT;
+	SK_U16		AutoNegAdv;
+	SK_U16		ExtPhyCtrl;
+	SK_U16		LedCtrl;
+	SK_BOOL		AutoNeg;
+#if defined(SK_DIAG) || defined(DEBUG)
+	SK_U16		PhyStat;
+	SK_U16		PhyStat1;
+	SK_U16		PhySpecStat;
+#endif /* SK_DIAG || DEBUG */
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Auto-negotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+		AutoNeg = SK_FALSE;
+	}
+	else {
+		AutoNeg = SK_TRUE;
+	}
+	
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("InitPhyMarv: Port %d, auto-negotiation %s\n",
+		 Port, AutoNeg ? "ON" : "OFF"));
+
+#ifdef VCPU
+	VCPUprintf(0, "SkGmInitPhyMarv(), Port=%u, DoLoop=%u\n",
+		Port, DoLoop);
+#else /* VCPU */
+	if (DoLoop) {
+		/* Set 'MAC Power up'-bit, set Manual MDI configuration */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL,
+			PHY_M_PC_MAC_POW_UP);
+	}
+	else if (AutoNeg && pPrt->PLinkSpeed == SK_LSPEED_AUTO) {
+		/* Read Ext. PHY Specific Control */
+		SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl);
+		
+		ExtPhyCtrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
+			PHY_M_EC_MAC_S_MSK);
+		
+		ExtPhyCtrl |= PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ) |
+			PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1);
+	
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL, ExtPhyCtrl);
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("Set Ext. PHY Ctrl=0x%04X\n", ExtPhyCtrl));
+	}
+
+	/* Read PHY Control */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl);
+
+	if (!AutoNeg) {
+		/* Disable Auto-negotiation */
+		PhyCtrl &= ~PHY_CT_ANE;
+	}
+
+	PhyCtrl |= PHY_CT_RESET;
+	/* Assert software reset */
+	SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl);
+#endif /* VCPU */
+
+	PhyCtrl = 0 /* PHY_CT_COL_TST */;
+	C1000BaseT = 0;
+	AutoNegAdv = PHY_SEL_TYPE;
+
+	/* manually Master/Slave ? */
+	if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
+		/* enable Manual Master/Slave */
+		C1000BaseT |= PHY_M_1000C_MSE;
+		
+		if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
+			C1000BaseT |= PHY_M_1000C_MSC;	/* set it to Master */
+		}
+	}
+	
+	/* Auto-negotiation ? */
+	if (!AutoNeg) {
+		
+		if (pPrt->PLinkMode == SK_LMODE_FULL) {
+			/* Set Full Duplex Mode */
+			PhyCtrl |= PHY_CT_DUP_MD;
+		}
+
+		/* Set Master/Slave manually if not already done */
+		if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
+			C1000BaseT |= PHY_M_1000C_MSE;	/* set it to Slave */
+		}
+
+		/* Set Speed */
+		switch (pPrt->PLinkSpeed) {
+		case SK_LSPEED_AUTO:
+		case SK_LSPEED_1000MBPS:
+			PhyCtrl |= PHY_CT_SP1000;
+			break;
+		case SK_LSPEED_100MBPS:
+			PhyCtrl |= PHY_CT_SP100;
+			break;
+		case SK_LSPEED_10MBPS:
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E019,
+				SKERR_HWI_E019MSG);
+		}
+
+		if (!DoLoop) {
+			PhyCtrl |= PHY_CT_RESET;
+		}
+	}
+	else {
+		/* Set Auto-negotiation advertisement */
+		
+		if (pAC->GIni.GICopperType) {
+			/* Set Speed capabilities */
+			switch (pPrt->PLinkSpeed) {
+			case SK_LSPEED_AUTO:
+				C1000BaseT |= PHY_M_1000C_AHD | PHY_M_1000C_AFD;
+				AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD |
+					PHY_M_AN_10_FD | PHY_M_AN_10_HD;
+				break;
+			case SK_LSPEED_1000MBPS:
+				C1000BaseT |= PHY_M_1000C_AHD | PHY_M_1000C_AFD;
+				break;
+			case SK_LSPEED_100MBPS:
+				AutoNegAdv |= PHY_M_AN_100_FD | PHY_M_AN_100_HD |
+					/* advertise 10Base-T also */
+					PHY_M_AN_10_FD | PHY_M_AN_10_HD;
+				break;
+			case SK_LSPEED_10MBPS:
+				AutoNegAdv |= PHY_M_AN_10_FD | PHY_M_AN_10_HD;
+				break;
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E019,
+					SKERR_HWI_E019MSG);
+			}
+
+			/* Set Full/half duplex capabilities */
+			switch (pPrt->PLinkMode) {
+			case SK_LMODE_AUTOHALF:
+				C1000BaseT &= ~PHY_M_1000C_AFD;
+				AutoNegAdv &= ~(PHY_M_AN_100_FD | PHY_M_AN_10_FD);
+				break;
+			case SK_LMODE_AUTOFULL:
+				C1000BaseT &= ~PHY_M_1000C_AHD;
+				AutoNegAdv &= ~(PHY_M_AN_100_HD | PHY_M_AN_10_HD);
+				break;
+			case SK_LMODE_AUTOBOTH:
+				break;
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+					SKERR_HWI_E015MSG);
+			}
+			
+			/* Set Flow-control capabilities */
+			switch (pPrt->PFlowCtrlMode) {
+			case SK_FLOW_MODE_NONE:
+				AutoNegAdv |= PHY_B_P_NO_PAUSE;
+				break;
+			case SK_FLOW_MODE_LOC_SEND:
+				AutoNegAdv |= PHY_B_P_ASYM_MD;
+				break;
+			case SK_FLOW_MODE_SYMMETRIC:
+				AutoNegAdv |= PHY_B_P_SYM_MD;
+				break;
+			case SK_FLOW_MODE_SYM_OR_REM:
+				AutoNegAdv |= PHY_B_P_BOTH_MD;
+				break;
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+					SKERR_HWI_E016MSG);
+			}
+		}
+		else {	/* special defines for FIBER (88E1011S only) */
+			
+			/* Set Full/half duplex capabilities */
+			switch (pPrt->PLinkMode) {
+			case SK_LMODE_AUTOHALF:
+				AutoNegAdv |= PHY_M_AN_1000X_AHD;
+				break;
+			case SK_LMODE_AUTOFULL:
+				AutoNegAdv |= PHY_M_AN_1000X_AFD;
+				break;
+			case SK_LMODE_AUTOBOTH:
+				AutoNegAdv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD;
+				break;
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+					SKERR_HWI_E015MSG);
+			}
+			
+			/* Set Flow-control capabilities */
+			switch (pPrt->PFlowCtrlMode) {
+			case SK_FLOW_MODE_NONE:
+				AutoNegAdv |= PHY_M_P_NO_PAUSE_X;
+				break;
+			case SK_FLOW_MODE_LOC_SEND:
+				AutoNegAdv |= PHY_M_P_ASYM_MD_X;
+				break;
+			case SK_FLOW_MODE_SYMMETRIC:
+				AutoNegAdv |= PHY_M_P_SYM_MD_X;
+				break;
+			case SK_FLOW_MODE_SYM_OR_REM:
+				AutoNegAdv |= PHY_M_P_BOTH_MD_X;
+				break;
+			default:
+				SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+					SKERR_HWI_E016MSG);
+			}
+		}
+
+		if (!DoLoop) {
+			/* Restart Auto-negotiation */
+			PhyCtrl |= PHY_CT_ANE | PHY_CT_RE_CFG;
+		}
+	}
+	
+#ifdef VCPU
+	/*
+	 * E-mail from Gu Lin (08-03-2002):
+	 */
+	
+	/* Program PHY register 30 as 16'h0708 for simulation speed up */
+	SkGmPhyWrite(pAC, IoC, Port, 30, 0x0700 /* 0x0708 */);
+	
+	VCpuWait(2000);
+
+#else /* VCPU */
+	
+	/* Write 1000Base-T Control Register */
+	SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_1000T_CTRL, C1000BaseT);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Set 1000B-T Ctrl =0x%04X\n", C1000BaseT));
+	
+	/* Write AutoNeg Advertisement Register */
+	SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_AUNE_ADV, AutoNegAdv);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Set Auto-Neg.Adv.=0x%04X\n", AutoNegAdv));
+#endif /* VCPU */
+	
+	if (DoLoop) {
+		/* Set the PHY Loopback bit */
+		PhyCtrl |= PHY_CT_LOOP;
+
+#ifdef XXX
+		/* Program PHY register 16 as 16'h0400 to force link good */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, PHY_M_PC_FL_GOOD);
+#endif /* XXX */
+
+#ifndef VCPU
+		if (pPrt->PLinkSpeed != SK_LSPEED_AUTO) {
+			/* Write Ext. PHY Specific Control */
+			SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_CTRL,
+				(SK_U16)((pPrt->PLinkSpeed + 2) << 4));
+		}
+#endif /* VCPU */
+	}
+#ifdef TEST_ONLY
+	else if (pPrt->PLinkSpeed == SK_LSPEED_10MBPS) {
+			/* Write PHY Specific Control */
+			SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL,
+				PHY_M_PC_EN_DET_MSK);
+	}
+#endif
+
+	/* Write to the PHY Control register */
+	SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, PhyCtrl);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Set PHY Ctrl Reg.=0x%04X\n", PhyCtrl));
+
+#ifdef VCPU
+	VCpuWait(2000);
+#else
+
+	LedCtrl = PHY_M_LED_PULS_DUR(PULS_170MS) | PHY_M_LED_BLINK_RT(BLINK_84MS);
+
+	if ((pAC->GIni.GILedBlinkCtrl & SK_ACT_LED_BLINK) != 0) {
+		LedCtrl |= PHY_M_LEDC_RX_CTRL | PHY_M_LEDC_TX_CTRL;
+	}
+
+	if ((pAC->GIni.GILedBlinkCtrl & SK_DUP_LED_NORMAL) != 0) {
+		LedCtrl |= PHY_M_LEDC_DP_CTRL;
+	}
+	
+	SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_CTRL, LedCtrl);
+
+	if ((pAC->GIni.GILedBlinkCtrl & SK_LED_LINK100_ON) != 0) {
+		/* only in forced 100 Mbps mode */
+		if (!AutoNeg && pPrt->PLinkSpeed == SK_LSPEED_100MBPS) {
+
+			SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_LED_OVER,
+				PHY_M_LED_MO_100(MO_LED_ON));
+		}
+	}
+
+#ifdef SK_DIAG
+	c_print("Set PHY Ctrl=0x%04X\n", PhyCtrl);
+	c_print("Set 1000 B-T=0x%04X\n", C1000BaseT);
+	c_print("Set Auto-Neg=0x%04X\n", AutoNegAdv);
+	c_print("Set Ext Ctrl=0x%04X\n", ExtPhyCtrl);
+#endif /* SK_DIAG */
+
+#if defined(SK_DIAG) || defined(DEBUG)
+	/* Read PHY Control */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &PhyCtrl);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Ctrl Reg.=0x%04X\n", PhyCtrl));
+	
+	/* Read 1000Base-T Control Register */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_CTRL, &C1000BaseT);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("1000B-T Ctrl =0x%04X\n", C1000BaseT));
+	
+	/* Read AutoNeg Advertisement Register */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_ADV, &AutoNegAdv);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Auto-Neg.Adv.=0x%04X\n", AutoNegAdv));
+	
+	/* Read Ext. PHY Specific Control */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_EXT_CTRL, &ExtPhyCtrl);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Ext. PHY Ctrl=0x%04X\n", ExtPhyCtrl));
+	
+	/* Read PHY Status */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Stat Reg.=0x%04X\n", PhyStat));
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_STAT, &PhyStat1);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Stat Reg.=0x%04X\n", PhyStat1));
+	
+	/* Read PHY Specific Status */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &PhySpecStat);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Spec Stat=0x%04X\n", PhySpecStat));
+#endif /* SK_DIAG || DEBUG */
+
+#ifdef SK_DIAG
+	c_print("PHY Ctrl Reg=0x%04X\n", PhyCtrl);
+	c_print("PHY 1000 Reg=0x%04X\n", C1000BaseT);
+	c_print("PHY AnAd Reg=0x%04X\n", AutoNegAdv);
+	c_print("Ext Ctrl Reg=0x%04X\n", ExtPhyCtrl);
+	c_print("PHY Stat Reg=0x%04X\n", PhyStat);
+	c_print("PHY Stat Reg=0x%04X\n", PhyStat1);
+	c_print("PHY Spec Reg=0x%04X\n", PhySpecStat);
+#endif /* SK_DIAG */
+
+#endif /* VCPU */
+
+}	/* SkGmInitPhyMarv */
+#endif /* YUKON */
+
+
+#ifdef OTHER_PHY
+/******************************************************************************
+ *
+ *	SkXmInitPhyLone() - Initialize the Level One Phy registers
+ *
+ * Description:	initializes all the Level One Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmInitPhyLone(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LoopBack be set-up? */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Ctrl1;
+	SK_U16		Ctrl2;
+	SK_U16		Ctrl3;
+
+	Ctrl1 = PHY_CT_SP1000;
+	Ctrl2 = 0;
+	Ctrl3 = PHY_SEL_TYPE;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* manually Master/Slave ? */
+	if (pPrt->PMSMode != SK_MS_MODE_AUTO) {
+		Ctrl2 |= PHY_L_1000C_MSE;
+		
+		if (pPrt->PMSMode == SK_MS_MODE_MASTER) {
+			Ctrl2 |= PHY_L_1000C_MSC;
+		}
+	}
+	/* Auto-negotiation ? */
+	if (pPrt->PLinkMode == SK_LMODE_HALF || pPrt->PLinkMode == SK_LMODE_FULL) {
+		/*
+		 * level one spec say: "1000 Mbps: manual mode not allowed"
+		 * but lets see what happens...
+		 */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyLone: no auto-negotiation Port %d\n", Port));
+		/* Set DuplexMode in Config register */
+		if (pPrt->PLinkMode == SK_LMODE_FULL) {
+			Ctrl1 |= PHY_CT_DUP_MD;
+		}
+
+		/* Determine Master/Slave manually if not already done */
+		if (pPrt->PMSMode == SK_MS_MODE_AUTO) {
+			Ctrl2 |= PHY_L_1000C_MSE;	/* set it to Slave */
+		}
+
+		/*
+		 * Do NOT enable Auto-negotiation here. This would hold
+		 * the link down because no IDLES are transmitted
+		 */
+	}
+	else {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("InitPhyLone: with auto-negotiation Port %d\n", Port));
+		/* Set Auto-negotiation advertisement */
+
+		/* Set Full/half duplex capabilities */
+		switch (pPrt->PLinkMode) {
+		case SK_LMODE_AUTOHALF:
+			Ctrl2 |= PHY_L_1000C_AHD;
+			break;
+		case SK_LMODE_AUTOFULL:
+			Ctrl2 |= PHY_L_1000C_AFD;
+			break;
+		case SK_LMODE_AUTOBOTH:
+			Ctrl2 |= PHY_L_1000C_AFD | PHY_L_1000C_AHD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E015,
+				SKERR_HWI_E015MSG);
+		}
+
+		/* Set Flow-control capabilities */
+		switch (pPrt->PFlowCtrlMode) {
+		case SK_FLOW_MODE_NONE:
+			Ctrl3 |= PHY_L_P_NO_PAUSE;
+			break;
+		case SK_FLOW_MODE_LOC_SEND:
+			Ctrl3 |= PHY_L_P_ASYM_MD;
+			break;
+		case SK_FLOW_MODE_SYMMETRIC:
+			Ctrl3 |= PHY_L_P_SYM_MD;
+			break;
+		case SK_FLOW_MODE_SYM_OR_REM:
+			Ctrl3 |= PHY_L_P_BOTH_MD;
+			break;
+		default:
+			SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+				SKERR_HWI_E016MSG);
+		}
+
+		/* Restart Auto-negotiation */
+		Ctrl1 = PHY_CT_ANE | PHY_CT_RE_CFG;
+	}
+	
+	/* Write 1000Base-T Control Register */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_1000T_CTRL, Ctrl2);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("1000B-T Ctrl Reg=0x%04X\n", Ctrl2));
+	
+	/* Write AutoNeg Advertisement Register */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_AUNE_ADV, Ctrl3);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Auto-Neg.Adv.Reg=0x%04X\n", Ctrl3));
+
+	if (DoLoop) {
+		/* Set the Phy Loopback bit, too */
+		Ctrl1 |= PHY_CT_LOOP;
+	}
+
+	/* Write to the Phy control register */
+	SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_CTRL, Ctrl1);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Control Reg=0x%04X\n", Ctrl1));
+}	/* SkXmInitPhyLone */
+
+
+/******************************************************************************
+ *
+ *	SkXmInitPhyNat() - Initialize the National Phy registers
+ *
+ * Description:	initializes all the National Phy registers
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmInitPhyNat(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LoopBack be set-up? */
+{
+/* todo: National */
+}	/* SkXmInitPhyNat */
+#endif /* OTHER_PHY */
+
+
+/******************************************************************************
+ *
+ *	SkMacInitPhy() - Initialize the PHY registers
+ *
+ * Description:	calls the Init PHY routines dep. on board type
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacInitPhy(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	DoLoop)		/* Should a Phy LoopBack be set-up? */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+		
+		switch (pPrt->PhyType) {
+		case SK_PHY_XMAC:
+			SkXmInitPhyXmac(pAC, IoC, Port, DoLoop);
+			break;
+		case SK_PHY_BCOM:
+			SkXmInitPhyBcom(pAC, IoC, Port, DoLoop);
+			break;
+#ifdef OTHER_PHY
+		case SK_PHY_LONE:
+			SkXmInitPhyLone(pAC, IoC, Port, DoLoop);
+			break;
+		case SK_PHY_NAT:
+			SkXmInitPhyNat(pAC, IoC, Port, DoLoop);
+			break;
+#endif /* OTHER_PHY */
+		}
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		
+		SkGmInitPhyMarv(pAC, IoC, Port, DoLoop);
+	}
+#endif /* YUKON */
+
+}	/* SkMacInitPhy */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *	SkXmAutoNegDoneXmac() - Auto-negotiation handling
+ *
+ * Description:
+ *	This function handles the auto-negotiation if the Done bit is set.
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+static int SkXmAutoNegDoneXmac(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		ResAb;		/* Resolved Ability */
+	SK_U16		LPAb;		/* Link Partner Ability */
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("AutoNegDoneXmac, Port %d\n", Port));
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Get PHY parameters */
+	SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_AUNE_LP, &LPAb);
+	SkXmPhyRead(pAC, IoC, Port, PHY_XMAC_RES_ABI, &ResAb);
+
+	if ((LPAb & PHY_X_AN_RFB) != 0) {
+		/* At least one of the remote fault bit is set */
+		/* Error */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("AutoNegFail: Remote fault bit set Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE;
+		return(SK_AND_OTHER);
+	}
+
+	/* Check Duplex mismatch */
+	if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_FD) {
+		pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL;
+	}
+	else if ((ResAb & (PHY_X_RS_HD | PHY_X_RS_FD)) == PHY_X_RS_HD) {
+		pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF;
+	}
+	else {
+		/* Error */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("AutoNegFail: Duplex mode mismatch Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE;
+		return(SK_AND_DUP_CAP);
+	}
+
+	/* Check PAUSE mismatch */
+	/* We are NOT using chapter 4.23 of the Xaqti manual */
+	/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+	if ((pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYMMETRIC ||
+	     pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM) &&
+	    (LPAb & PHY_X_P_SYM_MD) != 0) {
+		/* Symmetric PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+	}
+	else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_SYM_OR_REM &&
+		   (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) {
+		/* Enable PAUSE receive, disable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+	}
+	else if (pPrt->PFlowCtrlMode == SK_FLOW_MODE_LOC_SEND &&
+		   (LPAb & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) {
+		/* Disable PAUSE receive, enable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+	}
+	else {
+		/* PAUSE mismatch -> no PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+	}
+	pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS;
+
+	return(SK_AND_OK);
+}	/* SkXmAutoNegDoneXmac */
+
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegDoneBcom() - Auto-negotiation handling
+ *
+ * Description:
+ *	This function handles the auto-negotiation if the Done bit is set.
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+static int SkXmAutoNegDoneBcom(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		LPAb;		/* Link Partner Ability */
+	SK_U16		AuxStat;	/* Auxiliary Status */
+
+#ifdef TEST_ONLY
+01-Sep-2000 RA;:;:
+	SK_U16		ResAb;		/* Resolved Ability */
+#endif	/* 0 */
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("AutoNegDoneBcom, Port %d\n", Port));
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Get PHY parameters */
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUNE_LP, &LPAb);
+#ifdef TEST_ONLY
+01-Sep-2000 RA;:;:
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_1000T_STAT, &ResAb);
+#endif	/* 0 */
+	
+	SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_STAT, &AuxStat);
+
+	if ((LPAb & PHY_B_AN_RF) != 0) {
+		/* Remote fault bit is set: Error */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("AutoNegFail: Remote fault bit set Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE;
+		return(SK_AND_OTHER);
+	}
+
+	/* Check Duplex mismatch */
+	if ((AuxStat & PHY_B_AS_AN_RES_MSK) == PHY_B_RES_1000FD) {
+		pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL;
+	}
+	else if ((AuxStat & PHY_B_AS_AN_RES_MSK) == PHY_B_RES_1000HD) {
+		pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF;
+	}
+	else {
+		/* Error */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("AutoNegFail: Duplex mode mismatch Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE;
+		return(SK_AND_DUP_CAP);
+	}
+	
+#ifdef TEST_ONLY
+01-Sep-2000 RA;:;:
+	/* Check Master/Slave resolution */
+	if ((ResAb & PHY_B_1000S_MSF) != 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("Master/Slave Fault Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE;
+		pPrt->PMSStatus = SK_MS_STAT_FAULT;
+		return(SK_AND_OTHER);
+	}
+	
+	pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+		SK_MS_STAT_MASTER : SK_MS_STAT_SLAVE;
+#endif	/* 0 */
+
+	/* Check PAUSE mismatch ??? */
+	/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+	if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PAUSE_MSK) {
+		/* Symmetric PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+	}
+	else if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PRR) {
+		/* Enable PAUSE receive, disable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+	}
+	else if ((AuxStat & PHY_B_AS_PAUSE_MSK) == PHY_B_AS_PRT) {
+		/* Disable PAUSE receive, enable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+	}
+	else {
+		/* PAUSE mismatch -> no PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+	}
+	pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS;
+
+	return(SK_AND_OK);
+}	/* SkXmAutoNegDoneBcom */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ *	SkGmAutoNegDoneMarv() - Auto-negotiation handling
+ *
+ * Description:
+ *	This function handles the auto-negotiation if the Done bit is set.
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+static int SkGmAutoNegDoneMarv(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		LPAb;		/* Link Partner Ability */
+	SK_U16		ResAb;		/* Resolved Ability */
+	SK_U16		AuxStat;	/* Auxiliary Status */
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("AutoNegDoneMarv, Port %d\n", Port));
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Get PHY parameters */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_AUNE_LP, &LPAb);
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("Link P.Abil.=0x%04X\n", LPAb));
+	
+	if ((LPAb & PHY_M_AN_RF) != 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("AutoNegFail: Remote fault bit set Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE;
+		return(SK_AND_OTHER);
+	}
+
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_1000T_STAT, &ResAb);
+	
+	/* Check Master/Slave resolution */
+	if ((ResAb & PHY_B_1000S_MSF) != 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("Master/Slave Fault Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE;
+		pPrt->PMSStatus = SK_MS_STAT_FAULT;
+		return(SK_AND_OTHER);
+	}
+	
+	pPrt->PMSStatus = ((ResAb & PHY_B_1000S_MSR) != 0) ?
+		(SK_U8)SK_MS_STAT_MASTER : (SK_U8)SK_MS_STAT_SLAVE;
+	
+	/* Read PHY Specific Status */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_STAT, &AuxStat);
+	
+	/* Check Speed & Duplex resolved */
+	if ((AuxStat & PHY_M_PS_SPDUP_RES) == 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("AutoNegFail: Speed & Duplex not resolved, Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE;
+		pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_UNKNOWN;
+		return(SK_AND_DUP_CAP);
+	}
+	
+	if ((AuxStat & PHY_M_PS_FULL_DUP) != 0) {
+		pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL;
+	}
+	else {
+		pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF;
+	}
+	
+	/* Check PAUSE mismatch ??? */
+	/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+	if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_PAUSE_MSK) {
+		/* Symmetric PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+	}
+	else if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_RX_P_EN) {
+		/* Enable PAUSE receive, disable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+	}
+	else if ((AuxStat & PHY_M_PS_PAUSE_MSK) == PHY_M_PS_TX_P_EN) {
+		/* Disable PAUSE receive, enable PAUSE transmit */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+	}
+	else {
+		/* PAUSE mismatch -> no PAUSE */
+		pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+	}
+	
+	/* set used link speed */
+	switch ((unsigned)(AuxStat & PHY_M_PS_SPEED_MSK)) {
+	case (unsigned)PHY_M_PS_SPEED_1000:
+		pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_1000MBPS;
+		break;
+	case PHY_M_PS_SPEED_100:
+		pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_100MBPS;
+		break;
+	default:
+		pPrt->PLinkSpeedUsed = (SK_U8)SK_LSPEED_STAT_10MBPS;
+	}
+
+	return(SK_AND_OK);
+}	/* SkGmAutoNegDoneMarv */
+#endif /* YUKON */
+
+
+#ifdef OTHER_PHY
+/******************************************************************************
+ *
+ *	SkXmAutoNegDoneLone() - Auto-negotiation handling
+ *
+ * Description:
+ *	This function handles the auto-negotiation if the Done bit is set.
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+static int SkXmAutoNegDoneLone(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		ResAb;		/* Resolved Ability */
+	SK_U16		LPAb;		/* Link Partner Ability */
+	SK_U16		QuickStat;	/* Auxiliary Status */
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("AutoNegDoneLone, Port %d\n", Port));
+	pPrt = &pAC->GIni.GP[Port];
+
+	/* Get PHY parameters */
+	SkXmPhyRead(pAC, IoC, Port, PHY_LONE_AUNE_LP, &LPAb);
+	SkXmPhyRead(pAC, IoC, Port, PHY_LONE_1000T_STAT, &ResAb);
+	SkXmPhyRead(pAC, IoC, Port, PHY_LONE_Q_STAT, &QuickStat);
+
+	if ((LPAb & PHY_L_AN_RF) != 0) {
+		/* Remote fault bit is set */
+		/* Error */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("AutoNegFail: Remote fault bit set Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE;
+		return(SK_AND_OTHER);
+	}
+
+	/* Check Duplex mismatch */
+	if ((QuickStat & PHY_L_QS_DUP_MOD) != 0) {
+		pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOFULL;
+	}
+	else {
+		pPrt->PLinkModeStatus = (SK_U8)SK_LMODE_STAT_AUTOHALF;
+	}
+	
+	/* Check Master/Slave resolution */
+	if ((ResAb & PHY_L_1000S_MSF) != 0) {
+		/* Error */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("Master/Slave Fault Port %d\n", Port));
+		pPrt->PAutoNegFail = SK_TRUE;
+		pPrt->PMSStatus = SK_MS_STAT_FAULT;
+		return(SK_AND_OTHER);
+	}
+	else if (ResAb & PHY_L_1000S_MSR) {
+		pPrt->PMSStatus = SK_MS_STAT_MASTER;
+	}
+	else {
+		pPrt->PMSStatus = SK_MS_STAT_SLAVE;
+	}
+
+	/* Check PAUSE mismatch */
+	/* We are using IEEE 802.3z/D5.0 Table 37-4 */
+	/* we must manually resolve the abilities here */
+	pPrt->PFlowCtrlStatus = SK_FLOW_STAT_NONE;
+	
+	switch (pPrt->PFlowCtrlMode) {
+	case SK_FLOW_MODE_NONE:
+		/* default */
+		break;
+	case SK_FLOW_MODE_LOC_SEND:
+		if ((QuickStat & (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) ==
+			(PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) {
+			/* Disable PAUSE receive, enable PAUSE transmit */
+			pPrt->PFlowCtrlStatus = SK_FLOW_STAT_LOC_SEND;
+		}
+		break;
+	case SK_FLOW_MODE_SYMMETRIC:
+		if ((QuickStat & PHY_L_QS_PAUSE) != 0) {
+			/* Symmetric PAUSE */
+			pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+		}
+		break;
+	case SK_FLOW_MODE_SYM_OR_REM:
+		if ((QuickStat & (PHY_L_QS_PAUSE | PHY_L_QS_AS_PAUSE)) ==
+			PHY_L_QS_AS_PAUSE) {
+			/* Enable PAUSE receive, disable PAUSE transmit */
+			pPrt->PFlowCtrlStatus = SK_FLOW_STAT_REM_SEND;
+		}
+		else if ((QuickStat & PHY_L_QS_PAUSE) != 0) {
+			/* Symmetric PAUSE */
+			pPrt->PFlowCtrlStatus = SK_FLOW_STAT_SYMMETRIC;
+		}
+		break;
+	default:
+		SK_ERR_LOG(pAC, SK_ERRCL_SW | SK_ERRCL_INIT, SKERR_HWI_E016,
+			SKERR_HWI_E016MSG);
+	}
+	
+	return(SK_AND_OK);
+}	/* SkXmAutoNegDoneLone */
+
+
+/******************************************************************************
+ *
+ *	SkXmAutoNegDoneNat() - Auto-negotiation handling
+ *
+ * Description:
+ *	This function handles the auto-negotiation if the Done bit is set.
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+static int SkXmAutoNegDoneNat(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+/* todo: National */
+	return(SK_AND_OK);
+}	/* SkXmAutoNegDoneNat */
+#endif /* OTHER_PHY */
+
+
+/******************************************************************************
+ *
+ *	SkMacAutoNegDone() - Auto-negotiation handling
+ *
+ * Description:	calls the auto-negotiation done routines dep. on board type
+ *
+ * Returns:
+ *	SK_AND_OK	o.k.
+ *	SK_AND_DUP_CAP 	Duplex capability error happened
+ *	SK_AND_OTHER 	Other error happened
+ */
+int	SkMacAutoNegDone(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	int	Rtv;
+
+	Rtv = SK_AND_OK;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+		
+		switch (pPrt->PhyType) {
+		
+		case SK_PHY_XMAC:
+			Rtv = SkXmAutoNegDoneXmac(pAC, IoC, Port);
+			break;
+		case SK_PHY_BCOM:
+			Rtv = SkXmAutoNegDoneBcom(pAC, IoC, Port);
+			break;
+#ifdef OTHER_PHY
+		case SK_PHY_LONE:
+			Rtv = SkXmAutoNegDoneLone(pAC, IoC, Port);
+			break;
+		case SK_PHY_NAT:
+			Rtv = SkXmAutoNegDoneNat(pAC, IoC, Port);
+			break;
+#endif /* OTHER_PHY */
+		default:
+			return(SK_AND_OTHER);
+		}
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		
+		Rtv = SkGmAutoNegDoneMarv(pAC, IoC, Port);
+	}
+#endif /* YUKON */
+	
+	if (Rtv != SK_AND_OK) {
+		return(Rtv);
+	}
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("AutoNeg done Port %d\n", Port));
+	
+	/* We checked everything and may now enable the link */
+	pPrt->PAutoNegFail = SK_FALSE;
+
+	SkMacRxTxEnable(pAC, IoC, Port);
+	
+	return(SK_AND_OK);
+}	/* SkMacAutoNegDone */
+
+
+/******************************************************************************
+ *
+ *	SkMacRxTxEnable() - Enable Rx/Tx activity if port is up
+ *
+ * Description:	enables Rx/Tx dep. on board type
+ *
+ * Returns:
+ *	0	o.k.
+ *	!= 0	Error happened
+ */
+int SkMacRxTxEnable(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		Reg;		/* 16-bit register value */
+	SK_U16		IntMask;	/* MAC interrupt mask */
+#ifdef GENESIS
+	SK_U16		SWord;
+#endif
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (!pPrt->PHWLinkUp) {
+		/* The Hardware link is NOT up */
+		return(0);
+	}
+
+	if ((pPrt->PLinkMode == SK_LMODE_AUTOHALF ||
+	     pPrt->PLinkMode == SK_LMODE_AUTOFULL ||
+	     pPrt->PLinkMode == SK_LMODE_AUTOBOTH) &&
+	     pPrt->PAutoNegFail) {
+		/* Auto-negotiation is not done or failed */
+		return(0);
+	}
+
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+		/* set Duplex Mode and Pause Mode */
+		SkXmInitDupMd(pAC, IoC, Port);
+		
+		SkXmInitPauseMd(pAC, IoC, Port);
+	
+		/*
+		 * Initialize the Interrupt Mask Register. Default IRQs are...
+		 *	- Link Asynchronous Event
+		 *	- Link Partner requests config
+		 *	- Auto Negotiation Done
+		 *	- Rx Counter Event Overflow
+		 *	- Tx Counter Event Overflow
+		 *	- Transmit FIFO Underrun
+		 */
+		IntMask = XM_DEF_MSK;
+
+#ifdef DEBUG
+		/* add IRQ for Receive FIFO Overflow */
+		IntMask &= ~XM_IS_RXF_OV;
+#endif /* DEBUG */
+		
+		if (pPrt->PhyType != SK_PHY_XMAC) {
+			/* disable GP0 interrupt bit */
+			IntMask |= XM_IS_INP_ASS;
+		}
+		XM_OUT16(IoC, Port, XM_IMSK, IntMask);
+	
+		/* get MMU Command Reg. */
+		XM_IN16(IoC, Port, XM_MMU_CMD, &Reg);
+		
+		if (pPrt->PhyType != SK_PHY_XMAC &&
+			(pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL ||
+			 pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL)) {
+			/* set to Full Duplex */
+			Reg |= XM_MMU_GMII_FD;
+		}
+		
+		switch (pPrt->PhyType) {
+		case SK_PHY_BCOM:
+			/*
+			 * Workaround BCOM Errata (#10523) for all BCom Phys
+			 * Enable Power Management after link up
+			 */
+			SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &SWord);
+			SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
+				(SK_U16)(SWord & ~PHY_B_AC_DIS_PM));
+            SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK,
+				(SK_U16)PHY_B_DEF_MSK);
+			break;
+#ifdef OTHER_PHY
+		case SK_PHY_LONE:
+			SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, PHY_L_DEF_MSK);
+			break;
+		case SK_PHY_NAT:
+			/* todo National:
+			SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, PHY_N_DEF_MSK); */
+			/* no interrupts possible from National ??? */
+			break;
+#endif /* OTHER_PHY */
+		}
+		
+		/* enable Rx/Tx */
+		XM_OUT16(IoC, Port, XM_MMU_CMD, Reg | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		/*
+		 * Initialize the Interrupt Mask Register. Default IRQs are...
+		 *	- Rx Counter Event Overflow
+		 *	- Tx Counter Event Overflow
+		 *	- Transmit FIFO Underrun
+		 */
+		IntMask = GMAC_DEF_MSK;
+
+#ifdef DEBUG
+		/* add IRQ for Receive FIFO Overrun */
+		IntMask |= GM_IS_RX_FF_OR;
+#endif /* DEBUG */
+		
+		SK_OUT8(IoC, GMAC_IRQ_MSK, (SK_U8)IntMask);
+		
+		/* get General Purpose Control */
+		GM_IN16(IoC, Port, GM_GP_CTRL, &Reg);
+		
+		if (pPrt->PLinkModeStatus == SK_LMODE_STAT_FULL ||
+			pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOFULL) {
+			/* set to Full Duplex */
+			Reg |= GM_GPCR_DUP_FULL;
+		}
+		
+		/* enable Rx/Tx */
+        GM_OUT16(IoC, Port, GM_GP_CTRL, (SK_U16)(Reg | GM_GPCR_RX_ENA |
+			GM_GPCR_TX_ENA));
+
+#ifndef VCPU
+		/* Enable all PHY interrupts */
+        SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK,
+			(SK_U16)PHY_M_DEF_MSK);
+#endif /* VCPU */
+	}
+#endif /* YUKON */
+					
+	return(0);
+
+}	/* SkMacRxTxEnable */
+
+
+/******************************************************************************
+ *
+ *	SkMacRxTxDisable() - Disable Receiver and Transmitter
+ *
+ * Description:	disables Rx/Tx dep. on board type
+ *
+ * Returns: N/A
+ */
+void SkMacRxTxDisable(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_U16	Word;
+
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+		
+		XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+		
+		XM_OUT16(IoC, Port, XM_MMU_CMD, Word & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
+	
+		/* dummy read to ensure writing */
+		XM_IN16(IoC, Port, XM_MMU_CMD, &Word);
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		
+		GM_IN16(IoC, Port, GM_GP_CTRL, &Word);
+
+        GM_OUT16(IoC, Port, GM_GP_CTRL, (SK_U16)(Word & ~(GM_GPCR_RX_ENA |
+			GM_GPCR_TX_ENA)));
+
+		/* dummy read to ensure writing */
+		GM_IN16(IoC, Port, GM_GP_CTRL, &Word);
+	}
+#endif /* YUKON */
+
+}	/* SkMacRxTxDisable */
+
+
+/******************************************************************************
+ *
+ *	SkMacIrqDisable() - Disable IRQ from MAC
+ *
+ * Description:	sets the IRQ-mask to disable IRQ dep. on board type
+ *
+ * Returns: N/A
+ */
+void SkMacIrqDisable(
+SK_AC	*pAC,		/* Adapter Context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+#ifdef GENESIS
+	SK_U16		Word;
+#endif
+
+	pPrt = &pAC->GIni.GP[Port];
+
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+		
+		/* disable all XMAC IRQs */
+		XM_OUT16(IoC, Port, XM_IMSK, 0xffff);	
+		
+		/* Disable all PHY interrupts */
+		switch (pPrt->PhyType) {
+			case SK_PHY_BCOM:
+				/* Make sure that PHY is initialized */
+				if (pPrt->PState != SK_PRT_RESET) {
+					/* NOT allowed if BCOM is in RESET state */
+					/* Workaround BCOM Errata (#10523) all BCom */
+					/* Disable Power Management if link is down */
+					SkXmPhyRead(pAC, IoC, Port, PHY_BCOM_AUX_CTRL, &Word);
+					SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_AUX_CTRL,
+						(SK_U16)(Word | PHY_B_AC_DIS_PM));
+					SkXmPhyWrite(pAC, IoC, Port, PHY_BCOM_INT_MASK, 0xffff);
+				}
+				break;
+#ifdef OTHER_PHY
+			case SK_PHY_LONE:
+				SkXmPhyWrite(pAC, IoC, Port, PHY_LONE_INT_ENAB, 0);
+				break;
+			case SK_PHY_NAT:
+				/* todo: National
+				SkXmPhyWrite(pAC, IoC, Port, PHY_NAT_INT_MASK, 0xffff); */
+				break;
+#endif /* OTHER_PHY */
+		}
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		/* disable all GMAC IRQs */
+		SK_OUT8(IoC, GMAC_IRQ_MSK, 0);
+		
+#ifndef VCPU
+		/* Disable all PHY interrupts */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_INT_MASK, 0);
+#endif /* VCPU */
+	}
+#endif /* YUKON */
+
+}	/* SkMacIrqDisable */
+
+
+#ifdef SK_DIAG
+/******************************************************************************
+ *
+ *	SkXmSendCont() - Enable / Disable Send Continuous Mode
+ *
+ * Description:	enable / disable Send Continuous Mode on XMAC
+ *
+ * Returns:
+ *	nothing
+ */
+void SkXmSendCont(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port,	/* Port Index (MAC_1 + n) */
+SK_BOOL	Enable)	/* Enable / Disable */
+{
+	SK_U32	MdReg;
+
+	XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+	if (Enable) {
+		MdReg |= XM_MD_TX_CONT;
+	}
+	else {
+		MdReg &= ~XM_MD_TX_CONT;
+	}
+	/* setup Mode Register */
+	XM_OUT32(IoC, Port, XM_MODE, MdReg);
+
+}	/* SkXmSendCont */
+
+
+/******************************************************************************
+ *
+ *	SkMacTimeStamp() - Enable / Disable Time Stamp
+ *
+ * Description:	enable / disable Time Stamp generation for Rx packets
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacTimeStamp(
+SK_AC	*pAC,	/* adapter context */
+SK_IOC	IoC,	/* IO context */
+int		Port,	/* Port Index (MAC_1 + n) */
+SK_BOOL	Enable)	/* Enable / Disable */
+{
+	SK_U32	MdReg;
+	SK_U8	TimeCtrl;
+
+	if (pAC->GIni.GIGenesis) {
+
+		XM_IN32(IoC, Port, XM_MODE, &MdReg);
+
+		if (Enable) {
+			MdReg |= XM_MD_ATS;
+		}
+		else {
+			MdReg &= ~XM_MD_ATS;
+		}
+		/* setup Mode Register */
+		XM_OUT32(IoC, Port, XM_MODE, MdReg);
+	}
+	else {
+		if (Enable) {
+			TimeCtrl = GMT_ST_START | GMT_ST_CLR_IRQ;
+		}
+		else {
+			TimeCtrl = GMT_ST_STOP | GMT_ST_CLR_IRQ;
+		}
+		/* Start/Stop Time Stamp Timer */
+		SK_OUT8(IoC, GMAC_TI_ST_CTRL, TimeCtrl);
+	}
+
+}	/* SkMacTimeStamp*/
+
+#else /* !SK_DIAG */
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *	SkXmAutoNegLipaXmac() - Decides whether Link Partner could do auto-neg
+ *
+ *	This function analyses the Interrupt status word. If any of the
+ *	Auto-negotiating interrupt bits are set, the PLipaAutoNeg variable
+ *	is set true.
+ */
+void SkXmAutoNegLipaXmac(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_U16	IStatus)	/* Interrupt Status word to analyse */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
+		(IStatus & (XM_IS_LIPA_RC | XM_IS_RX_PAGE | XM_IS_AND)) != 0) {
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("AutoNegLipa: AutoNeg detected on Port %d, IStatus=0x%04X\n",
+			Port, IStatus));
+		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
+	}
+}	/* SkXmAutoNegLipaXmac */
+#endif /* GENESIS */
+
+
+/******************************************************************************
+ *
+ *	SkMacAutoNegLipaPhy() - Decides whether Link Partner could do auto-neg
+ *
+ *	This function analyses the PHY status word.
+ *  If any of the Auto-negotiating bits are set, the PLipaAutoNeg variable
+ *	is set true.
+ */
+void SkMacAutoNegLipaPhy(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_U16	PhyStat)	/* PHY Status word to analyse */
+{
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PLipaAutoNeg != SK_LIPA_AUTO &&
+		(PhyStat & PHY_ST_AN_OVER) != 0) {
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("AutoNegLipa: AutoNeg detected on Port %d, PhyStat=0x%04X\n",
+			Port, PhyStat));
+		pPrt->PLipaAutoNeg = SK_LIPA_AUTO;
+	}
+}	/* SkMacAutoNegLipaPhy */
+
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *	SkXmIrq() - Interrupt Service Routine
+ *
+ * Description:	services an Interrupt Request of the XMAC
+ *
+ * Note:
+ *	With an external PHY, some interrupt bits are not meaningfull any more:
+ *	- LinkAsyncEvent (bit #14)              XM_IS_LNK_AE
+ *	- LinkPartnerReqConfig (bit #10)	XM_IS_LIPA_RC
+ *	- Page Received (bit #9)		XM_IS_RX_PAGE
+ *	- NextPageLoadedForXmt (bit #8)		XM_IS_TX_PAGE
+ *	- AutoNegDone (bit #7)			XM_IS_AND
+ *	Also probably not valid any more is the GP0 input bit:
+ *	- GPRegisterBit0set			XM_IS_INP_ASS
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkXmIrq(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_EVPARA	Para;
+	SK_U16		IStatus;	/* Interrupt status read from the XMAC */
+	SK_U16		IStatus2;
+#ifdef SK_SLIM
+    SK_U64      OverflowStatus;
+#endif	
+
+	pPrt = &pAC->GIni.GP[Port];
+	
+	XM_IN16(IoC, Port, XM_ISRC, &IStatus);
+	
+	/* LinkPartner Auto-negable? */
+	if (pPrt->PhyType == SK_PHY_XMAC) {
+		SkXmAutoNegLipaXmac(pAC, IoC, Port, IStatus);
+	}
+	else {
+		/* mask bits that are not used with ext. PHY */
+		IStatus &= ~(XM_IS_LNK_AE | XM_IS_LIPA_RC |
+			XM_IS_RX_PAGE | XM_IS_TX_PAGE |
+			XM_IS_AND | XM_IS_INP_ASS);
+	}
+	
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+		("XmacIrq Port %d Isr 0x%04X\n", Port, IStatus));
+
+	if (!pPrt->PHWLinkUp) {
+		/* Spurious XMAC interrupt */
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+			("SkXmIrq: spurious interrupt on Port %d\n", Port));
+		return;
+	}
+
+	if ((IStatus & XM_IS_INP_ASS) != 0) {
+		/* Reread ISR Register if link is not in sync */
+		XM_IN16(IoC, Port, XM_ISRC, &IStatus2);
+
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+			("SkXmIrq: Link async. Double check Port %d 0x%04X 0x%04X\n",
+			 Port, IStatus, IStatus2));
+		IStatus &= ~XM_IS_INP_ASS;
+		IStatus |= IStatus2;
+	}
+
+	if ((IStatus & XM_IS_LNK_AE) != 0) {
+		/* not used, GP0 is used instead */
+	}
+
+	if ((IStatus & XM_IS_TX_ABORT) != 0) {
+		/* not used */
+	}
+
+	if ((IStatus & XM_IS_FRC_INT) != 0) {
+		/* not used, use ASIC IRQ instead if needed */
+	}
+
+	if ((IStatus & (XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE)) != 0) {
+		SkHWLinkDown(pAC, IoC, Port);
+
+		/* Signal to RLMT */
+		Para.Para32[0] = (SK_U32)Port;
+		SkEventQueue(pAC, SKGE_RLMT, SK_RLMT_LINK_DOWN, Para);
+
+		/* Start workaround Errata #2 timer */
+		SkTimerStart(pAC, IoC, &pPrt->PWaTimer, SK_WA_INA_TIME,
+			SKGE_HWAC, SK_HWEV_WATIM, Para);
+	}
+
+	if ((IStatus & XM_IS_RX_PAGE) != 0) {
+		/* not used */
+	}
+
+	if ((IStatus & XM_IS_TX_PAGE) != 0) {
+		/* not used */
+	}
+
+	if ((IStatus & XM_IS_AND) != 0) {
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+			("SkXmIrq: AND on link that is up Port %d\n", Port));
+	}
+
+	if ((IStatus & XM_IS_TSC_OV) != 0) {
+		/* not used */
+	}
+
+	/* Combined Tx & Rx Counter Overflow SIRQ Event */
+	if ((IStatus & (XM_IS_RXC_OV | XM_IS_TXC_OV)) != 0) {
+#ifdef SK_SLIM
+		SkXmOverflowStatus(pAC, IoC, Port, IStatus, &OverflowStatus);
+#else
+		Para.Para32[0] = (SK_U32)Port;
+		Para.Para32[1] = (SK_U32)IStatus;
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para);
+#endif /* SK_SLIM */
+	}
+
+	if ((IStatus & XM_IS_RXF_OV) != 0) {
+		/* normal situation -> no effect */
+#ifdef DEBUG
+		pPrt->PRxOverCnt++;
+#endif /* DEBUG */
+	}
+
+	if ((IStatus & XM_IS_TXF_UR) != 0) {
+		/* may NOT happen -> error log */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E020, SKERR_SIRQ_E020MSG);
+	}
+
+	if ((IStatus & XM_IS_TX_COMP) != 0) {
+		/* not served here */
+	}
+
+	if ((IStatus & XM_IS_RX_COMP) != 0) {
+		/* not served here */
+	}
+}	/* SkXmIrq */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ *	SkGmIrq() - Interrupt Service Routine
+ *
+ * Description:	services an Interrupt Request of the GMAC
+ *
+ * Note:
+ *
+ * Returns:
+ *	nothing
+ */
+static void SkGmIrq(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U8		IStatus;	/* Interrupt status */
+#ifdef SK_SLIM
+    SK_U64      OverflowStatus;
+#else
+	SK_EVPARA	Para;
+#endif	
+
+	pPrt = &pAC->GIni.GP[Port];
+	
+	SK_IN8(IoC, GMAC_IRQ_SRC, &IStatus);
+	
+#ifdef XXX
+	/* LinkPartner Auto-negable? */
+	SkMacAutoNegLipaPhy(pAC, IoC, Port, IStatus);
+#endif /* XXX */
+	
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_IRQ,
+		("GmacIrq Port %d Isr 0x%04X\n", Port, IStatus));
+
+	/* Combined Tx & Rx Counter Overflow SIRQ Event */
+	if (IStatus & (GM_IS_RX_CO_OV | GM_IS_TX_CO_OV)) {
+		/* these IRQs will be cleared by reading GMACs register */
+#ifdef SK_SLIM
+        SkGmOverflowStatus(pAC, IoC, Port, IStatus, &OverflowStatus);
+#else
+		Para.Para32[0] = (SK_U32)Port;
+		Para.Para32[1] = (SK_U32)IStatus;
+		SkPnmiEvent(pAC, IoC, SK_PNMI_EVT_SIRQ_OVERFLOW, Para);
+#endif		
+	}
+
+	if (IStatus & GM_IS_RX_FF_OR) {
+		/* clear GMAC Rx FIFO Overrun IRQ */
+		SK_OUT8(IoC, MR_ADDR(Port, RX_GMF_CTRL_T), (SK_U8)GMF_CLI_RX_FO);
+#ifdef DEBUG
+		pPrt->PRxOverCnt++;
+#endif /* DEBUG */
+	}
+
+	if (IStatus & GM_IS_TX_FF_UR) {
+		/* clear GMAC Tx FIFO Underrun IRQ */
+		SK_OUT8(IoC, MR_ADDR(Port, TX_GMF_CTRL_T), (SK_U8)GMF_CLI_TX_FU);
+		/* may NOT happen -> error log */
+		SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_SIRQ_E020, SKERR_SIRQ_E020MSG);
+	}
+
+	if (IStatus & GM_IS_TX_COMPL) {
+		/* not served here */
+	}
+
+	if (IStatus & GM_IS_RX_COMPL) {
+		/* not served here */
+	}
+}	/* SkGmIrq */
+#endif /* YUKON */
+
+
+/******************************************************************************
+ *
+ *	SkMacIrq() - Interrupt Service Routine for MAC
+ *
+ * Description:	calls the Interrupt Service Routine dep. on board type
+ *
+ * Returns:
+ *	nothing
+ */
+void SkMacIrq(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+int		Port)		/* Port Index (MAC_1 + n) */
+{
+#ifdef GENESIS
+	if (pAC->GIni.GIGenesis) {
+		/* IRQ from XMAC */
+		SkXmIrq(pAC, IoC, Port);
+	}
+#endif /* GENESIS */
+	
+#ifdef YUKON
+	if (pAC->GIni.GIYukon) {
+		/* IRQ from GMAC */
+		SkGmIrq(pAC, IoC, Port);
+	}
+#endif /* YUKON */
+
+}	/* SkMacIrq */
+
+#endif /* !SK_DIAG */
+
+#ifdef GENESIS
+/******************************************************************************
+ *
+ *	SkXmUpdateStats() - Force the XMAC to output the current statistic
+ *
+ * Description:
+ *	The XMAC holds its statistic internally. To obtain the current
+ *	values a command must be sent so that the statistic data will
+ *	be written to a predefined memory area on the adapter.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkXmUpdateStats(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_GEPORT	*pPrt;
+	SK_U16		StatReg;
+	int			WaitIndex;
+
+	pPrt = &pAC->GIni.GP[Port];
+	WaitIndex = 0;
+
+	/* Send an update command to XMAC specified */
+	XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_SNP_TXC | XM_SC_SNP_RXC);
+
+	/*
+	 * It is an auto-clearing register. If the command bits
+	 * went to zero again, the statistics are transferred.
+	 * Normally the command should be executed immediately.
+	 * But just to be sure we execute a loop.
+	 */
+	do {
+
+		XM_IN16(IoC, Port, XM_STAT_CMD, &StatReg);
+		
+		if (++WaitIndex > 10) {
+
+			SK_ERR_LOG(pAC, SK_ERRCL_HW, SKERR_HWI_E021, SKERR_HWI_E021MSG);
+
+			return(1);
+		}
+	} while ((StatReg & (XM_SC_SNP_TXC | XM_SC_SNP_RXC)) != 0);
+	
+	return(0);
+}	/* SkXmUpdateStats */
+
+
+/******************************************************************************
+ *
+ *	SkXmMacStatistic() - Get XMAC counter value
+ *
+ * Description:
+ *	Gets the 32bit counter value. Except for the octet counters
+ *	the lower 32bit are counted in hardware and the upper 32bit
+ *	must be counted in software by monitoring counter overflow interrupts.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkXmMacStatistic(
+SK_AC	*pAC,			/* adapter context */
+SK_IOC	IoC,			/* IO context */
+unsigned int Port,		/* Port Index (MAC_1 + n) */
+SK_U16	StatAddr,		/* MIB counter base address */
+SK_U32	SK_FAR *pVal)	/* ptr to return statistic value */
+{
+	if ((StatAddr < XM_TXF_OK) || (StatAddr > XM_RXF_MAX_SZ)) {
+		
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E022, SKERR_HWI_E022MSG);
+		
+		return(1);
+	}
+	
+	XM_IN32(IoC, Port, StatAddr, pVal);
+
+	return(0);
+}	/* SkXmMacStatistic */
+
+
+/******************************************************************************
+ *
+ *	SkXmResetCounter() - Clear MAC statistic counter
+ *
+ * Description:
+ *	Force the XMAC to clear its statistic counter.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkXmResetCounter(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port)	/* Port Index (MAC_1 + n) */
+{
+	XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+	/* Clear two times according to Errata #3 */
+	XM_OUT16(IoC, Port, XM_STAT_CMD, XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+
+	return(0);
+}	/* SkXmResetCounter */
+
+
+/******************************************************************************
+ *
+ *	SkXmOverflowStatus() - Gets the status of counter overflow interrupt
+ *
+ * Description:
+ *	Checks the source causing an counter overflow interrupt. On success the
+ *	resulting counter overflow status is written to <pStatus>, whereas the
+ *	upper dword stores the XMAC ReceiveCounterEvent register and the lower
+ *	dword the XMAC TransmitCounterEvent register.
+ *
+ * Note:
+ *	For XMAC the interrupt source is a self-clearing register, so the source
+ *	must be checked only once. SIRQ module does another check to be sure
+ *	that no interrupt get lost during process time.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkXmOverflowStatus(
+SK_AC	*pAC,				/* adapter context */
+SK_IOC	IoC,				/* IO context */
+unsigned int Port,			/* Port Index (MAC_1 + n) */
+SK_U16	IStatus,			/* Interupt Status from MAC */
+SK_U64	SK_FAR *pStatus)	/* ptr for return overflow status value */
+{
+	SK_U64	Status;	/* Overflow status */
+	SK_U32	RegVal;
+
+	Status = 0;
+
+	if ((IStatus & XM_IS_RXC_OV) != 0) {
+
+		XM_IN32(IoC, Port, XM_RX_CNT_EV, &RegVal);
+		Status |= (SK_U64)RegVal << 32;
+	}
+	
+	if ((IStatus & XM_IS_TXC_OV) != 0) {
+
+		XM_IN32(IoC, Port, XM_TX_CNT_EV, &RegVal);
+		Status |= (SK_U64)RegVal;
+	}
+
+	*pStatus = Status;
+
+	return(0);
+}	/* SkXmOverflowStatus */
+#endif /* GENESIS */
+
+
+#ifdef YUKON
+/******************************************************************************
+ *
+ *	SkGmUpdateStats() - Force the GMAC to output the current statistic
+ *
+ * Description:
+ *	Empty function for GMAC. Statistic data is accessible in direct way.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkGmUpdateStats(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port)	/* Port Index (MAC_1 + n) */
+{
+	return(0);
+}
+
+
+/******************************************************************************
+ *
+ *	SkGmMacStatistic() - Get GMAC counter value
+ *
+ * Description:
+ *	Gets the 32bit counter value. Except for the octet counters
+ *	the lower 32bit are counted in hardware and the upper 32bit
+ *	must be counted in software by monitoring counter overflow interrupts.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkGmMacStatistic(
+SK_AC	*pAC,			/* adapter context */
+SK_IOC	IoC,			/* IO context */
+unsigned int Port,		/* Port Index (MAC_1 + n) */
+SK_U16	StatAddr,		/* MIB counter base address */
+SK_U32	SK_FAR *pVal)	/* ptr to return statistic value */
+{
+
+	if ((StatAddr < GM_RXF_UC_OK) || (StatAddr > GM_TXE_FIFO_UR)) {
+		
+		SK_ERR_LOG(pAC, SK_ERRCL_SW, SKERR_HWI_E022, SKERR_HWI_E022MSG);
+		
+		SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+			("SkGmMacStat: wrong MIB counter 0x%04X\n", StatAddr));
+		return(1);
+	}
+		
+	GM_IN32(IoC, Port, StatAddr, pVal);
+
+	return(0);
+}	/* SkGmMacStatistic */
+
+
+/******************************************************************************
+ *
+ *	SkGmResetCounter() - Clear MAC statistic counter
+ *
+ * Description:
+ *	Force GMAC to clear its statistic counter.
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkGmResetCounter(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,		/* IO context */
+unsigned int Port)	/* Port Index (MAC_1 + n) */
+{
+	SK_U16	Reg;	/* Phy Address Register */
+	SK_U16	Word;
+	int		i;
+
+	GM_IN16(IoC, Port, GM_PHY_ADDR, &Reg);
+
+	/* set MIB Clear Counter Mode */
+	GM_OUT16(IoC, Port, GM_PHY_ADDR, Reg | GM_PAR_MIB_CLR);
+	
+	/* read all MIB Counters with Clear Mode set */
+	for (i = 0; i < GM_MIB_CNT_SIZE; i++) {
+		/* the reset is performed only when the lower 16 bits are read */
+		GM_IN16(IoC, Port, GM_MIB_CNT_BASE + 8*i, &Word);
+	}
+	
+	/* clear MIB Clear Counter Mode */
+	GM_OUT16(IoC, Port, GM_PHY_ADDR, Reg);
+	
+	return(0);
+}	/* SkGmResetCounter */
+
+
+/******************************************************************************
+ *
+ *	SkGmOverflowStatus() - Gets the status of counter overflow interrupt
+ *
+ * Description:
+ *	Checks the source causing an counter overflow interrupt. On success the
+ *	resulting counter overflow status is written to <pStatus>, whereas the
+ *	the following bit coding is used:
+ *	63:56 - unused
+ *	55:48 - TxRx interrupt register bit7:0
+ *	32:47 - Rx interrupt register
+ *	31:24 - unused
+ *	23:16 - TxRx interrupt register bit15:8
+ *	15:0  - Tx interrupt register
+ *
+ * Returns:
+ *	0:  success
+ *	1:  something went wrong
+ */
+int SkGmOverflowStatus(
+SK_AC	*pAC,				/* adapter context */
+SK_IOC	IoC,				/* IO context */
+unsigned int Port,			/* Port Index (MAC_1 + n) */
+SK_U16	IStatus,			/* Interupt Status from MAC */
+SK_U64	SK_FAR *pStatus)	/* ptr for return overflow status value */
+{
+	SK_U64	Status;		/* Overflow status */
+	SK_U16	RegVal;
+
+	Status = 0;
+
+	if ((IStatus & GM_IS_RX_CO_OV) != 0) {
+		/* this register is self-clearing after read */
+		GM_IN16(IoC, Port, GM_RX_IRQ_SRC, &RegVal);
+		Status |= (SK_U64)RegVal << 32;
+	}
+	
+	if ((IStatus & GM_IS_TX_CO_OV) != 0) {
+		/* this register is self-clearing after read */
+		GM_IN16(IoC, Port, GM_TX_IRQ_SRC, &RegVal);
+		Status |= (SK_U64)RegVal;
+	}
+	
+	/* this register is self-clearing after read */
+	GM_IN16(IoC, Port, GM_TR_IRQ_SRC, &RegVal);
+	/* Rx overflow interrupt register bits (LoByte)*/
+	Status |= (SK_U64)((SK_U8)RegVal) << 48;
+	/* Tx overflow interrupt register bits (HiByte)*/
+	Status |= (SK_U64)(RegVal >> 8) << 16;
+
+	*pStatus = Status;
+
+	return(0);
+}	/* SkGmOverflowStatus */
+
+
+#ifndef SK_SLIM
+/******************************************************************************
+ *
+ *	SkGmCableDiagStatus() - Starts / Gets status of cable diagnostic test
+ *
+ * Description:
+ *  starts the cable diagnostic test if 'StartTest' is true
+ *  gets the results if 'StartTest' is true
+ *
+ * NOTE:	this test is meaningful only when link is down
+ *	
+ * Returns:
+ *	0:  success
+ *	1:	no YUKON copper
+ *	2:	test in progress
+ */
+int SkGmCableDiagStatus(
+SK_AC	*pAC,		/* adapter context */
+SK_IOC	IoC,   		/* IO context */
+int		Port,		/* Port Index (MAC_1 + n) */
+SK_BOOL	StartTest)	/* flag for start / get result */
+{
+	int		i;
+	SK_U16	RegVal;
+	SK_GEPORT	*pPrt;
+
+	pPrt = &pAC->GIni.GP[Port];
+
+	if (pPrt->PhyType != SK_PHY_MARV_COPPER) {
+		
+		return(1);
+	}
+
+	if (StartTest) {
+		/* only start the cable test */
+		if ((pPrt->PhyId1 & PHY_I1_REV_MSK) < 4) {
+			/* apply TDR workaround from Marvell */
+			SkGmPhyWrite(pAC, IoC, Port, 29, 0x001e);
+			
+			SkGmPhyWrite(pAC, IoC, Port, 30, 0xcc00);
+			SkGmPhyWrite(pAC, IoC, Port, 30, 0xc800);
+			SkGmPhyWrite(pAC, IoC, Port, 30, 0xc400);
+			SkGmPhyWrite(pAC, IoC, Port, 30, 0xc000);
+			SkGmPhyWrite(pAC, IoC, Port, 30, 0xc100);
+		}
+
+		/* set address to 0 for MDI[0] */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, 0);
+
+		/* Read Cable Diagnostic Reg */
+		SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);
+
+		/* start Cable Diagnostic Test */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CABLE_DIAG,
+			(SK_U16)(RegVal | PHY_M_CABD_ENA_TEST));
+	
+		return(0);
+	}
+	
+	/* Read Cable Diagnostic Reg */
+	SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);
+
+	SK_DBG_MSG(pAC, SK_DBGMOD_HWM, SK_DBGCAT_CTRL,
+		("PHY Cable Diag.=0x%04X\n", RegVal));
+
+	if ((RegVal & PHY_M_CABD_ENA_TEST) != 0) {
+		/* test is running */
+		return(2);
+	}
+
+	/* get the test results */
+	for (i = 0; i < 4; i++)  {
+		/* set address to i for MDI[i] */
+		SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_EXT_ADR, (SK_U16)i);
+
+		/* get Cable Diagnostic values */
+		SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CABLE_DIAG, &RegVal);
+
+		pPrt->PMdiPairLen[i] = (SK_U8)(RegVal & PHY_M_CABD_DIST_MSK);
+
+		pPrt->PMdiPairSts[i] = (SK_U8)((RegVal & PHY_M_CABD_STAT_MSK) >> 13);
+	}
+
+	return(0);
+}	/* SkGmCableDiagStatus */
+#endif /* !SK_SLIM */
+#endif /* YUKON */
+
+/* End of file */
diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c
index 4fe624b..c77cc14 100644
--- a/drivers/net/skfp/drvfbi.c
+++ b/drivers/net/skfp/drvfbi.c
@@ -43,25 +43,6 @@
 /*
  * valid configuration values are:
  */
-#ifdef	ISA
-const int opt_ints[] = {8,	3, 4, 5, 9, 10, 11, 12, 15} ;
-const int opt_iops[] = {8,
-	0x100, 0x120, 0x180, 0x1a0, 0x220, 0x240, 0x320, 0x340};
-const int opt_dmas[] = {4,	3, 5, 6, 7} ;
-const int opt_eproms[] = {15,	0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce,
-			0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ;
-#endif
-#ifdef	EISA
-const int opt_ints[] = {5, 9, 10, 11} ;
-const int opt_dmas[] = {0, 5, 6, 7} ;
-const int opt_eproms[] = {0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce,
-				0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc} ;
-#endif
-
-#ifdef	MCA
-int	opt_ints[] = {3, 11, 10, 9} ;			/* FM1 */
-int	opt_eproms[] = {0, 0xc4, 0xc8, 0xcc, 0xd0, 0xd4, 0xd8, 0xdc} ;
-#endif	/* MCA */
 
 /*
  *	xPOS_ID:xxxx
@@ -78,17 +59,9 @@
  */
 #ifndef MULT_OEM
 #ifndef	OEM_CONCEPT
-#ifndef MCA
 const u_char oem_id[] = "xPOS_ID:xxxx" ;
-#else
-const u_char oem_id[] = "xPOSID1:xxxx" ;	/* FM1 card id. */
-#endif
 #else	/* OEM_CONCEPT */
-#ifndef MCA
 const u_char oem_id[] = OEM_ID ;
-#else
-const u_char oem_id[] = OEM_ID1 ;	/* FM1 card id. */
-#endif	/* MCA */
 #endif	/* OEM_CONCEPT */
 #define	ID_BYTE0	8
 #define	OEMID(smc,i)	oem_id[ID_BYTE0 + i]
@@ -109,23 +82,6 @@
 /* Prototype of a local function. */
 static void smt_stop_watchdog(struct s_smc *smc);
 
-#ifdef MCA
-static int read_card_id() ;
-static void DisableSlotAccess() ;
-static void EnableSlotAccess() ;
-#ifdef AIX
-extern int attach_POS_addr() ;
-extern int detach_POS_addr() ;
-extern u_char read_POS() ;
-extern void write_POS() ;
-extern int AIX_vpdReadByte() ;
-#else
-#define	read_POS(smc,a1,a2)	((u_char) inp(a1))
-#define	write_POS(smc,a1,a2,a3)	outp((a1),(a3))
-#endif
-#endif	/* MCA */
-
-
 /*
  * FDDI card reset
  */
@@ -139,51 +95,6 @@
 
 	smt_stop_watchdog(smc) ;
 
-#ifdef	ISA
-	outpw(CSR_A,0) ;			/* reset for all chips */
-	for (i = 10 ; i ; i--)			/* delay for PLC's */
-		(void)inpw(ISR_A) ;
-	OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(2)) ;
-					/* counter 2, mode 2 */
-	OUT_82c54_TIMER(2,97) ;		/* LSB */
-	OUT_82c54_TIMER(2,0) ;		/* MSB ( 15.6 us ) */
-	outpw(CSR_A,CS_CRESET) ;
-#endif
-#ifdef	EISA
-	outpw(CSR_A,0) ;			/* reset for all chips */
-	for (i = 10 ; i ; i--)			/* delay for PLC's */
-		(void)inpw(ISR_A) ;
-	outpw(CSR_A,CS_CRESET) ;
-	smc->hw.led = (2<<6) ;
-	outpw(CSR_A,CS_CRESET | smc->hw.led) ;
-#endif
-#ifdef	MCA
-	outp(ADDR(CARD_DIS),0) ;		/* reset for all chips */
-	for (i = 10 ; i ; i--)			/* delay for PLC's */
-		(void)inpw(ISR_A) ;
-	outp(ADDR(CARD_EN),0) ;
-	/* first I/O after reset must not be a access to FORMAC or PLC */
-
-	/*
-	 * bus timeout (MCA)
-	 */
-	OUT_82c54_TIMER(3,COUNT(2) | RW_OP(3) | TMODE(3)) ;
-					/* counter 2, mode 3 */
-	OUT_82c54_TIMER(2,(2*24)) ;	/* 3.9 us * 2 square wave */
-	OUT_82c54_TIMER(2,0) ;		/* MSB */
-
-	/* POS 102 indicated an activ Check Line or Buss Error monitoring */
-	if (inpw(CSA_A) & (POS_EN_CHKINT | POS_EN_BUS_ERR)) {
-		outp(ADDR(IRQ_CHCK_EN),0) ;
-	}
-
-	if (!((i = inpw(CSR_A)) & CS_SAS)) {
-		if (!(i & CS_BYSTAT)) {
-			outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */
-		}
-	}
-	outpw(LEDR_A,LED_1) ;	/* yellow */
-#endif	/* MCA */
 #ifdef	PCI
 	/*
 	 * make sure no transfer activity is pending
@@ -253,15 +164,7 @@
 {
 	smt_stop_watchdog(smc) ;
 	smc->hw.mac_ring_is_up = 0 ;		/* ring down */
-#ifdef	ISA
-	outpw(CSR_A,0) ;			/* reset for all chips */
-#endif
-#ifdef	EISA
-	outpw(CSR_A,0) ;			/* reset for all chips */
-#endif
-#ifdef	MCA
-	outp(ADDR(CARD_DIS),0) ;		/* reset for all chips */
-#endif
+
 #ifdef	PCI
 	/*
 	 * make sure no transfer activity is pending
@@ -284,60 +187,6 @@
 {
 	int	restart_tx = 0 ;
 again:
-#ifndef PCI
-#ifndef ISA
-/*
- * FORMAC+ bug modified the queue pointer if many read/write accesses happens!?
- */
-	if (stl & (FM_SPCEPDS  |	/* parit/coding err. syn.q.*/
-		   FM_SPCEPDA0 |	/* parit/coding err. a.q.0 */
-		   FM_SPCEPDA1 |	/* parit/coding err. a.q.1 */
-		   FM_SPCEPDA2)) {	/* parit/coding err. a.q.2 */
-		SMT_PANIC(smc,SMT_E0132, SMT_E0132_MSG) ;
-	}
-	if (stl & (FM_STBURS  |	/* tx buffer underrun syn.q.*/
-		   FM_STBURA0 |	/* tx buffer underrun a.q.0 */
-		   FM_STBURA1 |	/* tx buffer underrun a.q.1 */
-		   FM_STBURA2)) {	/* tx buffer underrun a.q.2 */
-		SMT_PANIC(smc,SMT_E0133, SMT_E0133_MSG) ;
-	}
-#endif
-	if ( (stu & (FM_SXMTABT |		/* transmit abort */
-#ifdef	SYNC
-		     FM_STXABRS |	/* syn. tx abort */
-#endif	/* SYNC */
-		     FM_STXABRA0)) ||	/* asyn. tx abort */
-	     (stl & (FM_SQLCKS |		/* lock for syn. q. */
-		     FM_SQLCKA0)) ) {	/* lock for asyn. q. */
-		formac_tx_restart(smc) ;		/* init tx */
-		restart_tx = 1 ;
-		stu = inpw(FM_A(FM_ST1U)) ;
-		stl = inpw(FM_A(FM_ST1L)) ;
-		stu &= ~ (FM_STECFRMA0 | FM_STEFRMA0 | FM_STEFRMS) ;
-		if (stu || stl)
-			goto again ;
-	}
-
-#ifndef	SYNC
-	if (stu & (FM_STECFRMA0 | /* end of chain asyn tx */
-		   FM_STEFRMA0)) { /* end of frame asyn tx */
-		/* free tx_queue */
-		smc->hw.n_a_send = 0 ;
-		if (++smc->hw.fp.tx_free < smc->hw.fp.tx_max) {
-			start_next_send(smc);
-		}
-		restart_tx = 1 ;
-	}
-#else	/* SYNC */
-	if (stu & (FM_STEFRMA0 |	/* end of asyn tx */
-		    FM_STEFRMS)) {	/* end of sync tx */
-		restart_tx = 1 ;
-	}
-#endif	/* SYNC */
-	if (restart_tx)
-		llc_restart_tx(smc) ;
-}
-#else	/* PCI */
 
 	/*
 	 * parity error: note encoding error is not possible in tag mode
@@ -378,7 +227,7 @@
 	if (restart_tx)
 		llc_restart_tx(smc) ;
 }
-#endif	/* PCI */
+
 /*
  * interrupt source= plc1
  * this function is called in nwfbisr.asm
@@ -387,10 +236,6 @@
 {
 	u_short	st = inpw(PLC(PB,PL_INTR_EVENT)) ;
 
-#if	(defined(ISA) || defined(EISA))
-	/* reset PLC Int. bits */
-	outpw(PLC1_I,inpw(PLC1_I)) ;
-#endif
 	plc_irq(smc,PB,st) ;
 }
 
@@ -402,10 +247,6 @@
 {
 	u_short	st = inpw(PLC(PA,PL_INTR_EVENT)) ;
 
-#if	(defined(ISA) || defined(EISA))
-	/* reset PLC Int. bits */
-	outpw(PLC2_I,inpw(PLC2_I)) ;
-#endif
 	plc_irq(smc,PA,st) ;
 }
 
@@ -446,43 +287,15 @@
 	char PmdType ;
 	int	i ;
 
-#if	(defined(ISA) || defined(MCA))
-	for (i = 0; i < 4 ;i++) {	/* read mac address from board */
-		smc->hw.fddi_phys_addr.a[i] =
-			bitrev8(inpw(PR_A(i+SA_MAC)));
-	}
-	for (i = 4; i < 6; i++) {
-		smc->hw.fddi_phys_addr.a[i] =
-			bitrev8(inpw(PR_A(i+SA_MAC+PRA_OFF)));
-	}
-#endif
-#ifdef	EISA
-	/*
-	 * Note: We get trouble on an Alpha machine if we make a inpw()
-	 * instead of inp()
-	 */
-	for (i = 0; i < 4 ;i++) {	/* read mac address from board */
-		smc->hw.fddi_phys_addr.a[i] =
-			bitrev8(inp(PR_A(i+SA_MAC)));
-	}
-	for (i = 4; i < 6; i++) {
-		smc->hw.fddi_phys_addr.a[i] =
-			bitrev8(inp(PR_A(i+SA_MAC+PRA_OFF)));
-	}
-#endif
 #ifdef	PCI
 	for (i = 0; i < 6; i++) {	/* read mac address from board */
 		smc->hw.fddi_phys_addr.a[i] =
 			bitrev8(inp(ADDR(B2_MAC_0+i)));
 	}
 #endif
-#ifndef	PCI
-	ConnectorType = inpw(PR_A(SA_PMD_TYPE)) & 0xff ;
-	PmdType = inpw(PR_A(SA_PMD_TYPE+1)) & 0xff ;
-#else
+
 	ConnectorType = inp(ADDR(B2_CONN_TYP)) ;
 	PmdType = inp(ADDR(B2_PMD_TYP)) ;
-#endif
 
 	smc->y[PA].pmd_type[PMD_SK_CONN] =
 	smc->y[PB].pmd_type[PMD_SK_CONN] = ConnectorType ;
@@ -512,20 +325,12 @@
 	card_start(smc) ;
 	read_address(smc,mac_addr) ;
 
-#ifndef	PCI
-	if (inpw(CSR_A) & CS_SAS)
-#else
 	if (!(inp(ADDR(B0_DAS)) & DAS_AVAIL))
-#endif
 		smc->s.sas = SMT_SAS ;	/* Single att. station */
 	else
 		smc->s.sas = SMT_DAS ;	/* Dual att. station */
 
-#ifndef	PCI
-	if (inpw(CSR_A) & CS_BYSTAT)
-#else
 	if (!(inp(ADDR(B0_DAS)) & DAS_BYP_ST))
-#endif
 		smc->mib.fddiSMTBypassPresent = 0 ;
 		/* without opt. bypass */
 	else
@@ -538,42 +343,12 @@
  */
 void sm_pm_bypass_req(struct s_smc *smc, int mode)
 {
-#if	(defined(ISA) || defined(EISA))
-	int csra_v ;
-#endif
-
 	DB_ECMN(1,"ECM : sm_pm_bypass_req(%s)\n",(mode == BP_INSERT) ?
 					"BP_INSERT" : "BP_DEINSERT",0) ;
 
 	if (smc->s.sas != SMT_DAS)
 		return ;
 
-#if	(defined(ISA) || defined(EISA))
-
-	csra_v = inpw(CSR_A) & ~CS_BYPASS ;
-#ifdef	EISA
-	csra_v |= smc->hw.led ;
-#endif
-
-	switch(mode) {
-	case BP_INSERT :
-		outpw(CSR_A,csra_v | CS_BYPASS) ;
-		break ;
-	case BP_DEINSERT :
-		outpw(CSR_A,csra_v) ;
-		break ;
-	}
-#endif	/* ISA / EISA */
-#ifdef	MCA
-	switch(mode) {
-	case BP_INSERT :
-		outp(ADDR(BYPASS(STAT_INS)),0) ;/* insert station */
-		break ;
-	case BP_DEINSERT :
-		outp(ADDR(BYPASS(STAT_BYP)),0) ;	/* bypass station */
-		break ;
-	}
-#endif
 #ifdef	PCI
 	switch(mode) {
 	case BP_INSERT :
@@ -591,31 +366,14 @@
  */
 int sm_pm_bypass_present(struct s_smc *smc)
 {
-#ifndef	PCI
-	return(	(inpw(CSR_A) & CS_BYSTAT) ? FALSE : TRUE ) ;
-#else
 	return(	(inp(ADDR(B0_DAS)) & DAS_BYP_ST) ? TRUE: FALSE) ;
-#endif
 }
 
 void plc_clear_irq(struct s_smc *smc, int p)
 {
 	SK_UNUSED(p) ;
 
-#if	(defined(ISA) || defined(EISA))
-	switch (p) {
-	case PA :
-		/* reset PLC Int. bits */
-		outpw(PLC2_I,inpw(PLC2_I)) ;
-		break ;
-	case PB :
-		/* reset PLC Int. bits */
-		outpw(PLC1_I,inpw(PLC1_I)) ;
-		break ;
-	}
-#else
 	SK_UNUSED(smc) ;
-#endif
 }
 
 
@@ -645,51 +403,6 @@
 	phy = &smc->y[PB] ;
 	mib_b = phy->mib ;
 
-#ifdef	EISA
-	/* Ring up = yellow led OFF*/
-	if (led_event == LED_Y_ON) {
-		smc->hw.led |= CS_LED_1 ;
-	}
-	else if (led_event == LED_Y_OFF) {
-		smc->hw.led &= ~CS_LED_1 ;
-	}
-	else {
-		/* Link at Port A or B = green led ON */
-		if (mib_a->fddiPORTPCMState == PC8_ACTIVE ||
-		    mib_b->fddiPORTPCMState == PC8_ACTIVE) {
-			smc->hw.led |= CS_LED_0 ;
-		}
-		else {
-			smc->hw.led &= ~CS_LED_0 ;
-		}
-	}
-#endif
-#ifdef	MCA
-	led_state = inpw(LEDR_A) ;
-	
-	/* Ring up = yellow led OFF*/
-	if (led_event == LED_Y_ON) {
-		led_state |= LED_1 ;
-	}
-	else if (led_event == LED_Y_OFF) {
-		led_state &= ~LED_1 ;
-	}
-	else {
-                led_state &= ~(LED_2|LED_0) ;
-
-		/* Link at Port A = green led A ON */
-		if (mib_a->fddiPORTPCMState == PC8_ACTIVE) {	
-			led_state |= LED_2 ;
-		}
-		
-		/* Link at Port B/S = green led B ON */
-		if (mib_b->fddiPORTPCMState == PC8_ACTIVE) {
-			led_state |= LED_0 ;
-		}
-	}
-
-        outpw(LEDR_A, led_state) ;
-#endif	/* MCA */
 #ifdef	PCI
         led_state = 0 ;
 	
@@ -824,446 +537,6 @@
 }
 #endif	/* MULT_OEM */
 
-
-#ifdef	MCA
-/************************
- *
- * BEGIN_MANUAL_ENTRY()
- *
- *	exist_board
- *
- *	Check if an MCA board is present in the specified slot.
- *
- *	int exist_board(
- *		struct s_smc *smc,
- *		int slot) ;
- * In
- *	smc - A pointer to the SMT Context struct.
- *
- *	slot - The number of the slot to inspect.
- * Out
- *	0 = No adapter present.
- *	1 = Found FM1 adapter.
- *
- * Pseudo
- *      Read MCA ID
- *	for all valid OEM_IDs
- *		compare with ID read
- *		if equal, return 1
- *	return(0
- *
- * Note
- *	The smc pointer must be valid now.
- *
- * END_MANUAL_ENTRY()
- *
- ************************/
-#define LONG_CARD_ID(lo, hi)	((((hi) & 0xff) << 8) | ((lo) & 0xff))
-int exist_board(struct s_smc *smc, int slot)
-{
-#ifdef MULT_OEM
-	SK_LOC_DECL(u_char,id[2]) ;
-	int idi ;
-#endif	/* MULT_OEM */
-
-	/* No longer valid. */
-	if (smc == NULL)
-		return(0) ;
-
-#ifndef MULT_OEM
-	if (read_card_id(smc, slot)
-		== LONG_CARD_ID(OEMID(smc,0), OEMID(smc,1)))
-		return (1) ;	/* Found FM adapter. */
-
-#else	/* MULT_OEM */
-	idi = read_card_id(smc, slot) ;
-	id[0] = idi & 0xff ;
-	id[1] = idi >> 8 ;
-
-        smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
-	for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
-		if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
-			continue ;
-
-		if (is_equal_num(&id[0],&OEMID(smc,0),2))
-			return (1) ;
-	}
-#endif	/* MULT_OEM */
-	return (0) ;	/* No adapter found. */
-}
-
-/************************
- *
- *	read_card_id
- *
- *	Read the MCA card id from the specified slot.
- * In
- *	smc - A pointer to the SMT Context struct.
- *	CAVEAT: This pointer may be NULL and *must not* be used within this
- *	function. It's only purpose is for drivers that need some information
- *	for the inp() and outp() macros.
- *
- *	slot - The number of the slot for which the card id is returned.
- * Out
- *	Returns the card id read from the specified slot. If an illegal slot
- *	number is specified, the function returns zero.
- *
- ************************/
-static int read_card_id(struct s_smc *smc, int slot)
-/* struct s_smc *smc ;	Do not use. */
-{
-	int card_id ;
-
-	SK_UNUSED(smc) ;	/* Make LINT happy. */
-	if ((slot < 1) || (slot > 15))	/* max 16 slots, 0 = motherboard */
-		return (0) ;	/* Illegal slot number specified. */
-
-	EnableSlotAccess(smc, slot) ;
-
-	card_id = ((read_POS(smc,POS_ID_HIGH,slot - 1) & 0xff) << 8) |
-				(read_POS(smc,POS_ID_LOW,slot - 1) & 0xff) ;
-
-	DisableSlotAccess(smc) ;
-
-	return (card_id) ;
-}
-
-/************************
- *
- * BEGIN_MANUAL_ENTRY()
- *
- *	get_board_para
- *
- *	Get adapter configuration information. Fill all board specific
- *	parameters within the 'smc' structure.
- *
- *	int get_board_para(
- *		struct s_smc *smc,
- *		int slot) ;
- * In
- *	smc - A pointer to the SMT Context struct, to which this function will
- *	write some adapter configuration data.
- *
- *	slot - The number of the slot, in which the adapter is installed.
- * Out
- *	0 = No adapter present.
- *	1 = Ok.
- *	2 = Adapter present, but card enable bit not set.
- *
- * END_MANUAL_ENTRY()
- *
- ************************/
-int get_board_para(struct s_smc *smc, int slot)
-{
-	int val ;
-	int i ;
-
-	/* Check if adapter present & get type of adapter. */
-	switch (exist_board(smc, slot)) {
-	case 0:	/* Adapter not present. */
-		return (0) ;
-	case 1:	/* FM Rev. 1 */
-		smc->hw.rev = FM1_REV ;
-		smc->hw.VFullRead = 0x0a ;
-		smc->hw.VFullWrite = 0x05 ;
-		smc->hw.DmaWriteExtraBytes = 8 ;	/* 2 extra words. */
-		break ;
-	}
-	smc->hw.slot = slot ;
-
-	EnableSlotAccess(smc, slot) ;
-
-	if (!(read_POS(smc,POS_102, slot - 1) & POS_CARD_EN)) {
-		DisableSlotAccess(smc) ;
-		return (2) ;	/* Card enable bit not set. */
-	}
-
-	val = read_POS(smc,POS_104, slot - 1) ;	/* I/O, IRQ */
-
-#ifndef MEM_MAPPED_IO	/* is defined by the operating system */
-	i = val & POS_IOSEL ;	/* I/O base addr. (0x0200 .. 0xfe00) */
-	smc->hw.iop = (i + 1) * 0x0400 - 0x200 ;
-#endif
-	i = ((val & POS_IRQSEL) >> 6) & 0x03 ;	/* IRQ <0, 1> */
-	smc->hw.irq = opt_ints[i] ;
-
-	/* FPROM base addr. */
-	i = ((read_POS(smc,POS_103, slot - 1) & POS_MSEL) >> 4) & 0x07 ;
-	smc->hw.eprom = opt_eproms[i] ;
-
-	DisableSlotAccess(smc) ;
-
-	/* before this, the smc->hw.iop must be set !!! */
-	smc->hw.slot_32 = inpw(CSF_A) & SLOT_32 ;
-
-	return (1) ;
-}
-
-/* Enable access to specified MCA slot. */
-static void EnableSlotAccess(struct s_smc *smc, int slot)
-{
-	SK_UNUSED(slot) ;
-
-#ifndef AIX
-	SK_UNUSED(smc) ;
-
-	/* System mode. */
-	outp(POS_SYS_SETUP, POS_SYSTEM) ;
-
-	/* Select slot. */
-	outp(POS_CHANNEL_POS, POS_CHANNEL_BIT | (slot-1)) ;
-#else
-	attach_POS_addr (smc) ;
-#endif
-}
-
-/* Disable access to MCA slot formerly enabled via EnableSlotAccess(). */
-static void DisableSlotAccess(struct s_smc *smc)
-{
-#ifndef AIX
-	SK_UNUSED(smc) ;
-
-	outp(POS_CHANNEL_POS, 0) ;
-#else
-	detach_POS_addr (smc) ;
-#endif
-}
-#endif	/* MCA */
-
-#ifdef	EISA
-#ifndef	MEM_MAPPED_IO
-#define	SADDR(slot)	(((slot)<<12)&0xf000)
-#else	/* MEM_MAPPED_IO */
-#define	SADDR(slot)	(smc->hw.iop)
-#endif	/* MEM_MAPPED_IO */
-
-/************************
- *
- * BEGIN_MANUAL_ENTRY()
- *
- *	exist_board
- *
- *	Check if an EISA board is present in the specified slot.
- *
- *	int exist_board(
- *		struct s_smc *smc,
- *		int slot) ;
- * In
- *	smc - A pointer to the SMT Context struct.
- *
- *	slot - The number of the slot to inspect.
- * Out
- *	0 = No adapter present.
- *	1 = Found adapter.
- *
- * Pseudo
- *      Read EISA ID
- *	for all valid OEM_IDs
- *		compare with ID read
- *		if equal, return 1
- *	return(0
- *
- * Note
- *	The smc pointer must be valid now.
- *
- ************************/
-int exist_board(struct s_smc *smc, int slot)
-{
-	int i ;
-#ifdef MULT_OEM
-	SK_LOC_DECL(u_char,id[4]) ;
-#endif	/* MULT_OEM */
-
-	/* No longer valid. */
-	if (smc == NULL)
-		return(0);
-
-	SK_UNUSED(slot) ;
-
-#ifndef MULT_OEM
-	for (i = 0 ; i < 4 ; i++) {
-		if (inp(SADDR(slot)+PRA(i)) != OEMID(smc,i))
-			return(0) ;
-	}
-	return(1) ;
-#else	/* MULT_OEM */
-	for (i = 0 ; i < 4 ; i++)
-		id[i] = inp(SADDR(slot)+PRA(i)) ;
-
-	smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
-
-	for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
-		if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
-			continue ;
-
-		if (is_equal_num(&id[0],&OEMID(smc,0),4))
-			return (1) ;
-	}
-	return (0) ;	/* No adapter found. */
-#endif	/* MULT_OEM */
-}
-
-
-int get_board_para(struct s_smc *smc, int slot)
-{
-	int	i ;
-
-	if (!exist_board(smc,slot))
-		return(0) ;
-
-	smc->hw.slot = slot ;
-#ifndef	MEM_MAPPED_IO		/* if defined by the operating system */
-	smc->hw.iop = SADDR(slot) ;
-#endif
-
-	if (!(inp(C0_A(0))&CFG_CARD_EN)) {
-		return(2) ;			/* CFG_CARD_EN bit not set! */
-	}
-
-	smc->hw.irq = opt_ints[(inp(C1_A(0)) & CFG_IRQ_SEL)] ;
-	smc->hw.dma = opt_dmas[((inp(C1_A(0)) & CFG_DRQ_SEL)>>3)] ;
-
-	if ((i = inp(C2_A(0)) & CFG_EPROM_SEL) != 0x0f)
-		smc->hw.eprom = opt_eproms[i] ;
-	else
-		smc->hw.eprom = 0 ;
-
-	smc->hw.DmaWriteExtraBytes = 8 ;
-
-	return(1) ;
-}
-#endif	/* EISA */
-
-#ifdef	ISA
-#ifndef MULT_OEM
-const u_char sklogo[6] = SKLOGO_STR ;
-#define	SIZE_SKLOGO(smc)	sizeof(sklogo)
-#define	SKLOGO(smc,i)		sklogo[i]
-#else	/* MULT_OEM */
-#define	SIZE_SKLOGO(smc)	smc->hw.oem_id->oi_logo_len
-#define	SKLOGO(smc,i)		smc->hw.oem_id->oi_logo[i]
-#endif	/* MULT_OEM */
-
-
-int exist_board(struct s_smc *smc, HW_PTR port)
-{
-	int	i ;
-#ifdef MULT_OEM
-	int	bytes_read ;
-	u_char	board_logo[15] ;
-	SK_LOC_DECL(u_char,id[4]) ;
-#endif	/* MULT_OEM */
-
-	/* No longer valid. */
-	if (smc == NULL)
-		return(0);
-
-	SK_UNUSED(smc) ;
-#ifndef MULT_OEM
-	for (i = SADDRL ; i < (signed) (SADDRL+SIZE_SKLOGO(smc)) ; i++) {
-		if ((u_char)inpw((PRA(i)+port)) != SKLOGO(smc,i-SADDRL)) {
-			return(0) ;
-		}
-	}
-
-	/* check MAC address (S&K or other) */
-	for (i = 0 ; i < 3 ; i++) {
-		if ((u_char)inpw((PRA(i)+port)) != OEMID(smc,i))
-			return(0) ;
-	}
-	return(1) ;
-#else	/* MULT_OEM */
-        smc->hw.oem_id = (struct s_oem_ids *)  &oem_ids[0] ;
-	board_logo[0] = (u_char)inpw((PRA(SADDRL)+port)) ;
-	bytes_read = 1 ;
-
-	for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
-		if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
-			continue ;
-
-		/* Test all read bytes with current OEM_entry */
-		/* for (i=0; (i<bytes_read) && (i < SIZE_SKLOGO(smc)); i++) { */
-		for (i = 0; i < bytes_read; i++) {
-			if (board_logo[i] != SKLOGO(smc,i))
-				break ;
-		}
-
-		/* If mismatch, switch to next OEM entry */
-		if ((board_logo[i] != SKLOGO(smc,i)) && (i < bytes_read))
-			continue ;
-
-		--i ;
-		while (bytes_read < SIZE_SKLOGO(smc)) {
-			//   inpw next byte SK_Logo
-			i++ ;
-			board_logo[i] = (u_char)inpw((PRA(SADDRL+i)+port)) ;
-			bytes_read++ ;
-			if (board_logo[i] != SKLOGO(smc,i))
-				break ;
-		}
-
-		for (i = 0 ; i < 3 ; i++)
-			id[i] = (u_char)inpw((PRA(i)+port)) ;
-
-		if ((board_logo[i] == SKLOGO(smc,i))
-			&& (bytes_read == SIZE_SKLOGO(smc))) {
-
-			if (is_equal_num(&id[0],&OEMID(smc,0),3))
-				return(1);
-		}
-	}	/* for */
-	return(0) ;
-#endif	/* MULT_OEM */
-}
-
-int get_board_para(struct s_smc *smc, int slot)
-{
-	SK_UNUSED(smc) ;
-	SK_UNUSED(slot) ;
-	return(0) ;	/* for ISA not supported */
-}
-#endif	/* ISA */
-
-#ifdef PCI
-#ifdef USE_BIOS_FUN
-int exist_board(struct s_smc *smc, int slot)
-{
-	u_short dev_id ;
-	u_short ven_id ;
-	int found ; 
-	int i ;
-
-	found = FALSE ;		/* make sure we returned with adatper not found*/
-				/* if an empty oemids.h was included */
-
-#ifdef MULT_OEM
-        smc->hw.oem_id = (struct s_oem_ids *) &oem_ids[0] ;
-	for (; smc->hw.oem_id->oi_status != OI_STAT_LAST; smc->hw.oem_id++) {
-		if (smc->hw.oem_id->oi_status < smc->hw.oem_min_status)
-			continue ;
-#endif
-		ven_id = OEMID(smc,0) + (OEMID(smc,1) << 8) ; 
-		dev_id = OEMID(smc,2) + (OEMID(smc,3) << 8) ; 
-		for (i = 0; i < slot; i++) {
-			if (pci_find_device(i,&smc->hw.pci_handle,
-				dev_id,ven_id) != 0) {
-
-				found = FALSE ;
-			} else {
-				found = TRUE ;
-			}
-		}
-		if (found) {
-			return(1) ;	/* adapter was found */
-		}
-#ifdef MULT_OEM
-	}
-#endif
-	return(0) ;	/* adapter was not found */
-}
-#endif	/* PCI */
-#endif	/* USE_BIOS_FUNC */
-
 void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr)
 {
 	int i ;
diff --git a/drivers/net/skfp/h/mbuf.h b/drivers/net/skfp/h/mbuf.h
index b339d1f..f2aadcd 100644
--- a/drivers/net/skfp/h/mbuf.h
+++ b/drivers/net/skfp/h/mbuf.h
@@ -15,11 +15,7 @@
 #ifndef	_MBUF_
 #define _MBUF_
 
-#ifndef PCI
-#define M_SIZE	4550
-#else
 #define M_SIZE	4504
-#endif
 
 #ifndef MAX_MBUF
 #define MAX_MBUF	4
diff --git a/drivers/net/skfp/h/skfbi.h b/drivers/net/skfp/h/skfbi.h
index ba347d6..c1ba26c 100644
--- a/drivers/net/skfp/h/skfbi.h
+++ b/drivers/net/skfp/h/skfbi.h
@@ -15,797 +15,11 @@
 #ifndef	_SKFBI_H_
 #define	_SKFBI_H_
 
-#ifdef SYNC
-#define exist_board_far			exist_board
-#define get_board_para_far		get_board_para
-#endif
-
 /*
- * physical address offset + IO-Port base address
- */
-#ifndef	PCI
-#define	ADDR(a)	((a)+smc->hw.iop)
-#define	ADDRS(smc,a) ((a)+(smc)->hw.iop)
-#endif
-
-/*
- * FDDI-Fx (x := {I(SA), E(ISA), M(CA), P(CI)})
+ * FDDI-Fx (x := {I(SA), P(CI)})
  *	address calculation & function defines
  */
 
-#ifdef	EISA
-
-/*
- * Configuration PROM:	 !! all 8-Bit IO's !!
- *					    |<-	  MAC-Address	 ->|
- *	/-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/
- * val:	  |PROD_ID0..3|	   | free      |    |00|00|5A|40|    |nn|mm|00|00|
- *	/-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-//-+--+--+--+--+-/
- * IO-	  ^	      ^	   ^		    ^		     ^
- * port	0C80	    0C83  0C88		   0C90		    0C98
- *	  |	       \
- *	  |		\
- *	  |		 \______________________________________________
- * EISA Expansion Board Product ID:					\
- * BIT:	  |7 6 5 4 3 2 1 0|						 \
- *	  | PROD_ID0	  | PROD_ID1	  | PROD_ID2	  | PROD_ID3	  |
- *	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *	  |0| MAN_C0  | MAN_C1	| MAN_C2  | PROD1 | PROD0 | REV1  | REV0  |
- *	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *	   ^=reserved			  | product numb. | revision numb |
- * MAN_Cx = compressed manufacterer code (x:=0..2)
- *	ASCII : 'A'..'Z' : 0x41..0x5A -> compr.(c-0x40) : 0x01..0x1A (5Bits!)
- */
-
-#ifndef	MULT_OEM
-#ifndef	OEM_CONCEPT
-#define	MAN_C0		('S'-0x40)
-#define	MAN_C1		('K'-0x40)
-#define	MAN_C2		('D'-0x40)
-#define	PROD_ID0	(u_char)((MAN_C0<<2) | (MAN_C1>>3))
-#define	PROD_ID1	(u_char)(((MAN_C1<<5) & 0xff) | MAN_C2)
-#define	PROD_ID2	(u_char)(1)	/* prod. nr. */
-#define	PROD_ID3	(u_char)(0)	/* rev. nr. */
-
-#ifndef	OEM_USER_DATA
-#define	OEM_USER_DATA	"SK-NET FDDI V2.0 Userdata"
-#endif
-#else	/*  OEM_CONCEPT */
-
-/* MAN_C(0|1|2) no longer present (ra). */
-#define	PROD_ID0	(u_char)OEM_PROD_ID0
-#define	PROD_ID1	(u_char)OEM_PROD_ID1
-#define	PROD_ID2	(u_char)OEM_PROD_ID2
-#define	PROD_ID3	(u_char)OEM_PROD_ID3
-#endif	/* OEM_CONCEPT */
-
-#define	SKLOGO		PROD_ID0, PROD_ID1, PROD_ID2, PROD_ID3
-#endif	/* MULT_OEM */
-
-#define	SADDRL	(0)		/* start address SKLOGO */
-#define	SA_MAC	(0x10)		/* start addr. MAC_AD within the PROM */
-#define	PRA_OFF	(4)
-#define SA_PMD_TYPE	(8)	/* start addr. PMD-Type */
-
-#define	SKFDDI_PSZ	32		/* address PROM size */
-
-/*
- * address transmission from logical to physical offset address on board
- */
-#define FMA(a)	(0x0400|((a)<<1))	/* FORMAC+ (r/w) */
-#define P1A(a)	(0x0800|((a)<<1))	/* PLC1 (r/w) */
-#define P2A(a)	(0x0840|((a)<<1))	/* PLC2 (r/w) */
-#define TIA(a)	(0x0880|((a)<<1))	/* Timer (r/w) */
-#define PRA(a)	(0x0c80| (a))		/* configuration PROM */
-#define	C0A(a)	(0x0c84| (a))		/* config. RAM */
-#define	C1A(a)	(0x0ca0| (a))		/* IRQ-, DMA-nr., EPROM type */
-#define	C2A(a)	(0x0ca4| (a))		/* EPROM and PAGE selector */
-
-#define	CONF	C0A(0)			/* config RAM (card enable bit port) */
-#define PGRA	C2A(0)			/* Flash page register */
-#define	CDID	PRA(0)			/* Card ID I/O port addr. offset */
-
-
-/*
- * physical address offset + slot specific IO-Port base address
- */
-#define FM_A(a)	(FMA(a)+smc->hw.iop)	/* FORMAC Plus physical addr */
-#define P1_A(a)	(P1A(a)+smc->hw.iop)	/* PLC1 (r/w) */
-#define P2_A(a)	(P2A(a)+smc->hw.iop)	/* PLC2 (r/w) */
-#define TI_A(a)	(TIA(a)+smc->hw.iop)	/* Timer (r/w) */
-#define PR_A(a)	(PRA(a)+smc->hw.iop)	/* config. PROM */
-#define C0_A(a)	(C0A(a)+smc->hw.iop)	/* config. RAM */
-#define C1_A(a)	(C1A(a)+smc->hw.iop)	/* config. RAM */
-#define C2_A(a)	(C2A(a)+smc->hw.iop)	/* config. RAM */
-
-
-#define	CSRA	0x0008		/* control/status register address (r/w) */
-#define	ISRA	0x0008		/* int. source register address (upper 8Bits) */
-#define PLC1I	0x001a		/* clear PLC1 interrupt (write only) */
-#define PLC2I	0x0020		/* clear PLC2 interrupt (write only) */
-#define CSFA	0x001c		/* control/status FIFO BUSY flags (read only) */
-#define RQAA	0x001c		/* Request reg. (write only) */
-#define WCTA	0x001e		/* word counter (r/w) */
-#define	FFLAG	0x005e		/* FLAG/V_FULL (FIFO almost full, write only)*/
-
-#define	CSR_A	(CSRA+smc->hw.iop)	/* control/status register address (r/w) */
-#ifdef UNIX
-#define	CSR_AS(smc)	(CSRA+(smc)->hw.iop)	/* control/status register address (r/w) */
-#endif
-#define	ISR_A	(ISRA+smc->hw.iop)	/* int. source register address (upper 8Bits) */
-#define PLC1_I	(PLC1I+smc->hw.iop)	/* clear PLC1 internupt (write only) */
-#define PLC2_I	(PLC2I+smc->hw.iop)	/* clear PLC2 interrupt (write only) */
-#define CSF_A	(CSFA+smc->hw.iop)	/* control/status FIFO BUSY flags (r/w) */
-#define RQA_A	(RQAA+smc->hw.iop)	/* Request reg. (write only) */
-#define WCT_A	(WCTA+smc->hw.iop)	/* word counter (r/w) */
-#define	FFLAG_A	(FFLAG+smc->hw.iop)	/* FLAG/V_FULL (FIFO almost full, write only)*/
-
-/*
- * control/status register CSRA	bits
- */
-/* write */
-#define CS_CRESET	0x01		/* Card reset (0=reset) */
-#define	CS_RESET_FIFO	0x02		/* FIFO reset (0=reset) */
-#define	CS_IMSK		0x04		/* enable IRQ (1=enable, 0=disable) */
-#define	CS_EN_IRQ_TC	0x08		/* enable IRQ from transfer counter */
-#define CS_BYPASS	0x20		/* bypass switch (0=remove, 1=insert)*/
-#define CS_LED_0	0x40		/* switch LED 0 */
-#define	CS_LED_1	0x80		/* switch LED 1 */
-/* read */
-#define	CS_BYSTAT	0x40		/* 0=Bypass exist, 1= ..not */
-#define	CS_SAS		0x80		/* single attachement station (=1) */
-
-/*
- * control/status register CSFA bits (FIFO)
- */
-#define	CSF_MUX0	0x01
-#define	CSF_MUX1	0x02
-#define	CSF_HSREQ0	0x04
-#define	CSF_HSREQ1	0x08
-#define	CSF_HSREQ2	0x10
-#define	CSF_BUSY_DMA	0x40
-#define	CSF_BUSY_FIFO	0x80
-
-/*
- * Interrupt source register ISRA (upper 8 data bits) read only & low activ.
- */
-#define IS_MINTR1	0x0100		/* FORMAC ST1U/L & ~IMSK1U/L*/
-#define IS_MINTR2	0x0200		/* FORMAC ST2U/L & ~IMSK2U/L*/
-#define IS_PLINT1	0x0400		/* PLC1 */
-#define IS_PLINT2	0x0800		/* PLC2 */
-#define IS_TIMINT	0x1000		/* Timer 82C54-2 */
-#define	IS_TC		0x2000		/* transf. counter */
-
-#define	ALL_IRSR (IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT|IS_TC)
-
-/*
- * CONFIG<0> RAM (C0_A())
- */
-#define	CFG_CARD_EN	0x01		/* card enable */
-
-/*
- * CONFIG<1> RAM (C1_A())
- */
-#define	CFG_IRQ_SEL	0x03		/* IRQ select (4 nr.) */
-#define	CFG_IRQ_TT	0x04		/* IRQ trigger type (LEVEL/EDGE) */
-#define	CFG_DRQ_SEL	0x18		/* DMA requ. (4 nr.) */
-#define	CFG_BOOT_EN	0x20		/* 0=BOOT-, 1=Application Software */
-#define	CFG_PROG_EN	0x40		/* V_Prog for FLASH_PROM (1=on) */
-
-/*
- * CONFIG<2> RAM (C2_A())
- */
-#define	CFG_EPROM_SEL	0x0f		/* FPROM start address selection */
-#define	CFG_PAGE	0xf0		/* FPROM page selection */
-
-
-#define	READ_PROM(a)	((u_char)inp(a))
-#define	GET_PAGE(i)	outp(C2_A(0),((int)(i)<<4) | (inp(C2_A(0)) & ~CFG_PAGE))
-#define	FPROM_SW()	(inp(C1_A(0)) & CFG_BOOT_EN)
-
-#define	MAX_PAGES	16		/* 16 pages */
-#define	MAX_FADDR	0x2000		/* 8K per page */
-#define	VPP_ON()	outp(C1_A(0),inp(C1_A(0)) |  CFG_PROG_EN)
-#define	VPP_OFF()	outp(C1_A(0),inp(C1_A(0)) & ~CFG_PROG_EN)
-
-#define	DMA_BUSY()	(inpw(CSF_A) & CSF_BUSY_DMA)
-#define FIFO_BUSY()	(inpw(CSF_A) & CSF_BUSY_FIFO)
-#define	DMA_FIFO_BUSY()	(inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO))
-#define	BUS_CHECK()
-
-#ifdef UNISYS
-/* For UNISYS use another macro with drv_usecewait function */
-#define CHECK_DMA() {u_long k = 1000000; \
-		while (k && (DMA_BUSY())) { k--; drv_usecwait(20); } \
-		if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
-#else
-#define CHECK_DMA() {u_long k = 1000000 ;\
-		while (k && (DMA_BUSY())) k-- ;\
-		if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
-#endif
-
-#define CHECK_FIFO() {u_long k = 1000000 ;\
-		while (k && (FIFO_BUSY())) k-- ;\
-		if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; }
-
-#define CHECK_DMA_FIFO() {u_long k = 1000000 ;\
-		while (k && (DMA_FIFO_BUSY())) k-- ;\
-		if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; }
-
-#define	GET_ISR()	~inpw(ISR_A)
-#define CHECK_ISR()	~inpw(ISR_A)
-
-#ifndef UNIX
-#ifndef	WINNT
-#define	CLI_FBI()	outpw(CSR_A,(inpw(CSR_A)&\
-			(CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led)
-#else	/* WINNT */
-#define CLI_FBI()	outpw(CSR_A,(l_inpw(CSR_A)&\
-			(CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|smc->hw.led)
-#endif	/* WINNT */
-#else	/* UNIX */
-#define	CLI_FBI(smc)	outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\
-			(CS_CRESET|CS_BYPASS))|CS_RESET_FIFO|(smc)->hw.led)
-#endif
-
-#ifndef UNIX
-#define	STI_FBI()	outpw(CSR_A,(inpw(CSR_A)&\
-		(CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|smc->hw.led)
-#else
-#define	STI_FBI(smc)	outpw(CSR_AS(smc),(inpw(CSR_AS(smc))&\
-		(CS_CRESET|CS_BYPASS|CS_RESET_FIFO))|CS_IMSK|(smc)->hw.led)
-#endif
-
-/* EISA DMA Controller */
-#define DMA_WRITE_SINGLE_MASK_BIT_M	0x0a	/* Master DMA Controller */
-#define DMA_WRITE_SINGLE_MASK_BIT_S	0xd4	/* Slave DMA Controller */
-#define DMA_CLEAR_BYTE_POINTER_M	0x0c
-#define DMA_CLEAR_BYTE_POINTER_S	0xd8
-
-#endif	/* EISA */
-
-#ifdef	MCA
-
-/*
- * POS Register:	 !! all I/O's are 8-Bit !!
- */
-#define	POS_SYS_SETUP	0x94	/* system setup register */
-#define	POS_SYSTEM	0xff	/* system mode */
-
-#define	POS_CHANNEL_POS	0x96	/* register slot ID */
-#define	POS_CHANNEL_BIT	0x08	/* mask for -"- */
-
-#define	POS_BASE	0x100	/* POS base address */
-#define	POS_ID_LOW	POS_BASE	/* card ID low */
-#define	POS_ID_HIGH	(POS_BASE+1)	/* card ID high */
-#define	POS_102		(POS_BASE+2)	/* card en., arbitration level .. */
-#define	POS_103		(POS_BASE+3)	/* FPROM addr, page */
-#define	POS_104		(POS_BASE+4)	/* I/O, IRQ */
-#define	POS_105		(POS_BASE+5)	/* POS_CHCK */
-#define	POS_106		(POS_BASE+6)	/* to read VPD */
-#define	POS_107		(POS_BASE+7)	/* added without function */
-
-/* FM1 card IDs */
-#define	FM1_CARD_ID0	0x83
-#define	FM1_CARD_ID1	0
-
-#define	FM1_IBM_ID0	0x9c
-#define	FM1_IBM_ID1	0x8f
-
-
-/* FM2 card IDs */
-#define	FM2_CARD_ID0	0xab
-#define	FM2_CARD_ID1	0
-
-#define	FM2_IBM_ID0	0x7e
-#define	FM2_IBM_ID1	0x8f
-
-/* Board revision. */
-#define FM1_REV		0
-#define FM2_REV		1
-
-#define	MAX_SLOT	8
-
-/*
- * POS_102
- */
-#define	POS_CARD_EN	0x01	/* card enable =1 */
-#define	POS_SDAT_EN	0x02	/* enable 32-bit streaming data mode */
-#define	POS_EN_CHKINT	0x04	/* enable int. from check line asserted */
-#define	POS_EN_BUS_ERR	0x08	/* enable int. on invalid busmaster transf. */
-#define	POS_FAIRNESS	0x10	/* fairnes on =1 */
-/* attention: arbitration level used with bit 0 POS 105 */
-#define	POS_LARBIT	0xe0	/* arbitration level	(0,0,0)->level = 0x8
-							(1,1,1)->level = 0xf */
-/*
- * POS_103
- */
-#define	POS_PAGE	0x07	/* FPROM page selection */
-#define	POS_BOOT_EN	0x08	/* boot PROM enable =1 */
-#define	POS_MSEL	0x70	/* memory start address for FPROM mapping */
-#define	PROG_EN		0x80	/* FM1: Vpp prog on/off */
-#define	POS_SDR		0x80	/* FM2: Streaming data bit */
-
-/*
- * POS_104
- */
-#define	POS_IOSEL	0x3f	/* selected I/O base address */
-#define	POS_IRQSEL	0xc0	/* selected interrupt */
-
-/*
- * POS_105
- */
-#define	POS_CHCK	0x80
-#define POS_SYNC_ERR	0x20	/* FM2: synchronous error reporting	*/
-#define POS_PAR_DATA	0x10	/* FM2: data parity enable bit	*/
-#define POS_PAR_ADDR	0x08	/* FM2: address parity enable bit	*/
-#define	POS_IRQHSEL	0x02	/* FM2: Highest bit for IRQ_selection	*/
-#define POS_HARBIT	0x01	/* Highest bit in Bus arbitration selection */
-
-#define	SA_MAC	(0)		/* start addr. MAC_AD within the PROM	*/
-#define	PRA_OFF	(0)
-#define SA_PMD_TYPE	(8)	/* start addr. PMD-Type	*/
-
-/*
- * address transmission from logical to physical offset address on board
- */
-#define	FMA(a)	(0x0100|((a)<<1))	/* FORMAC+ (r/w) */
-#define	P2(a)	(0x00c0|((a)<<1))	/* PLC2 (r/w) (DAS) */
-#define	P1(a)	(0x0080|((a)<<1))	/* PLC1 (r/w) */
-#define	TI(a)	(0x0060|((a)<<1))	/* Timer (r/w) */
-#define	PR(a)	(0x0040|((a)<<1))	/* configuration PROM */
-#define	CS(a)	(0x0020| (a))		/* control/status */
-#define	FF(a)	(0x0010|((a)<<1))	/* FIFO ASIC */
-#define	CT(a)	(0x0000|((a)<<1))	/* counter */
-
-/*
- * counter
- */
-#define	ACLA	CT(0)		/* address counter low */
-#define	ACHA	CT(1)		/* address counter high */
-#define	BCN	CT(2)		/* byte counter */
-#define	MUX	CT(3)		/* MUX-register */
-#define	WCN	CT(0x08)	/* word counter */
-#define	FFLG	CT(0x09)	/* FIFO Flags */
-
-/*
- * test/control register (FM2 only)
- */
-#define CNT_TST	0x018		/* Counter test control register */
-#define CNT_STP 0x01a		/* Counter test step reg. (8 Bit) */
-
-/*
- * CS register (read only)
- */
-#define	CSRA	CS(0)		/* control/status register address */
-#define	CSFA	CS(2)		/* control/status FIFO BUSY ...	 */
-#define	ISRA	CS(4)		/* first int. source register address */
-#define	ISR2	CS(6)		/* second int. source register address */
-#define	LEDR	CS(0x0c)	/* LED register r/w */
-#define	CSIL	CS(0x10)	/* I/O mapped POS_ID_low (100) */
-#define	CSIH	CS(0x12)	/*	- " - POS_ID_HIGH (101) */
-#define	CSA	CS(0x14)	/*	- " - POS_102 */
-#define	CSM	CS(0x0e)	/*	- " - POS_103 */
-#define	CSM_FM1	CS(0x16)	/*	- " - POS_103 (copy in FM1) */
-#define	CSI	CS(0x18)	/*	- " - POS_104 */
-#define	CSS	CS(0x1a)	/*	- " - POS_105 */
-#define	CSP_06	CS(0x1c)	/*	- " - POS_106 */
-#define	WDOG_ST		0x1c	/* Watchdog status (FM2 only)	*/
-#define	WDOG_EN		0x1c	/* Watchdog enabling (FM2 only, 8Bit)	*/
-#define	WDOG_DIS	0x1e	/* Watchdog disabling (FM2 only, 8Bit)	*/
-
-#define PGRA	CSM		/* Flash page register */
-
-
-#define	WCTA	FF(0)		/* word counter */
-#define	FFLAG	FF(1)		/* FLAG/V_FULL (FIFO almost full, write only)*/
-
-/*
- * Timer register (FM2 only)
- */
-#define RTM_CNT		0x28		/* RTM Counter */
-#define TI_DIV		0x60		/* Timer Prescaler */
-#define TI_CH1		0x62		/* Timer channel 1 counter */
-#define TI_STOP		0x64		/* Stop timer on channel 1 */
-#define TI_STRT		0x66		/* Start timer on channel 1 */
-#define TI_INI2		0x68		/* Timer: Bus master preemption */
-#define TI_CNT2		0x6a		/* Timer */
-#define TI_INI3		0x6c		/* Timer: Streaming data */
-#define TI_CNT3		0x6e		/* Timer */
-#define WDOG_LO		0x70		/* Watchdog counter low */
-#define WDOG_HI		0x72		/* Watchdog counter high */
-#define RTM_PRE		0x74		/* restr. token prescaler */
-#define RTM_TIM		0x76		/* restr. token timer */
-
-/*
- * Recommended Timeout values (for FM2 timer only)
- */
-#define TOUT_BM_PRE	188		/* 3.76 usec	*/
-#define TOUT_S_DAT	374		/* 7.48 usec	*/
-
-/*
- * CS register (write only)
- */
-#define	HSR(p)	CS(0x18|(p))	/* Host request register */
-
-#define	RTM_PUT		0x36		/* restr. token counter write */
-#define	RTM_GET		0x28		/*	- " -	clear */
-#define	RTM_CLEAR	0x34		/*	- " -	read */
-
-/*
- * BCN	Bit definitions
- */
-#define BCN_BUSY	0x8000		/* DMA Busy flag */
-#define BCN_AZERO	0x4000		/* Almost zero flag (BCN < 4) */
-#define BCN_STREAM	0x2000		/* Allow streaming data (BCN >= 8) */
-
-/*
- * WCN	Bit definitions
- */
-#define WCN_ZERO	0x2000		/* Zero flag (counted to zero) */
-#define WCN_AZERO	0x1000		/* Almost zero flag (BCN < 4) */
-
-/*
- * CNT_TST	Bit definitions
- */
-#define CNT_MODE	0x01		/* Go into test mode */
-#define	CNT_D32		0x02		/* 16/32 BIT test mode */
-
-/*
- * FIFO Flag		FIFO Flags/Vfull register
- */
-#define FF_VFULL	0x003f		/* V_full value mask */
-#define FFLG_FULL	0x2000		/* FULL flag */
-#define FFLG_A_FULL	0x1000		/* Almost full flag */
-#define FFLG_VFULL	0x0800		/* V_full Flag */
-#define FFLG_A_EMP	0x0400		/* almost empty flag */
-#define FFLG_EMP	0x0200		/* empty flag */
-#define FFLG_T_EMP	0x0100		/* totally empty flag */
-
-/*
- * WDOG		Watchdog status register
- */
-#define WDOG_ALM	0x01		/* Watchdog alarm Bit */
-#define WDOG_ACT	0x02		/* Watchdog active Bit */
-
-/*
- * CS(0)	CONTROLS
- */
-#define	CS_CRESET	0x0001
-#define	FIFO_RST	0x0002
-#define	CS_IMSK		0x0004
-#define	EN_IRQ_CHCK	0x0008
-#define	EN_IRQ_TOKEN	0x0010
-#define	EN_IRQ_TC	0x0020
-#define	TOKEN_STATUS	0x0040
-#define	RTM_CHANGE	0x0080
-
-#define	CS_SAS		0x0100
-#define	CS_BYSTAT	0x0200	/* bypass connected (0=conn.) */
-#define	CS_BYPASS	0x0400	/* bypass on/off indication */
-
-/*
- * CS(2)	FIFOSTAT
- */
-#define	HSREQ		0x0007
-#define	BIGDIR		0x0008
-#define	CSF_BUSY_FIFO	0x0010
-#define	CSF_BUSY_DMA	0x0020
-#define	SLOT_32		0x0040
-
-#define	LED_0		0x0001
-#define	LED_1		0x0002
-#define	LED_2		0x0100
-
-#define	MAX_PAGES	8		/* pages */
-#define	MAX_FADDR	0x4000		/* 16K per page */
-
-/*
- *	IRQ = ISRA || ISR2 ;
- *
- *	ISRA = IRQ_OTH_EN && (IS_LAN | IS_BUS) ;
- *	ISR2 = IRQ_TC_EN && IS_TC ;
- *
- *	IS_LAN = (IS_MINTR1 | IS_MINTR2 | IS_PLINT1 | IS_PLINT2 | IS_TIMINT) ||
- *		 (IRQ_EN_TOKEN && IS_TOKEN) ;
- *	IS_BUS = IRQ_CHCK_EN && (IS_BUSERR | IS_CHCK_L) ;
- */
-/*
- *	ISRA	!!! activ high !!!
- */
-#define	IS_MINTR1	0x0001		/* FORMAC ST1U/L & ~IMSK1U/L*/
-#define	IS_MINTR2	0x0002		/* FORMAC ST2U/L & ~IMSK2U/L*/
-#define	IS_PLINT1	0x0004		/* PLC1 */
-#define	IS_PLINT2	0x0008		/* PLC2 */
-#define	IS_TIMINT	0x0010		/* Timer 82C54-2 */
-#define	IS_TOKEN	0x0020		/* restrictet token monitoring */
-#define	IS_CHCK_L	0x0040		/* check line asserted */
-#define	IS_BUSERR	0x0080		/* bus error */
-/*
- *	ISR2
- */
-#define	IS_TC		0x0001		/* terminal count irq */
-#define IS_SFDBKRTN	0x0002		/* selected feedback return */
-#define IS_D16		0x0004		/* DS16 */
-#define	IS_D32		0x0008		/* DS32 */
-#define IS_DPEI		0x0010		/* Data Parity Indication */
-
-#define	ALL_IRSR	0x00ff
-
-#define	FM_A(a)	ADDR(FMA(a))	/* FORMAC Plus physical addr */
-#define	P1_A(a)	ADDR(P1(a))	/* PLC1 (r/w) */
-#define	P2_A(a)	ADDR(P2(a))	/* PLC2 (r/w) (DAS) */
-#define	TI_A(a)	ADDR(TI(a))	/* Timer (r/w) FM1 only! */
-#define	PR_A(a)	ADDR(PR(a))	/* config. PROM */
-#define	CS_A(a)	ADDR(CS(a))	/* control/status */
-
-#define	ISR1_A	ADDR(ISRA)	/* first int. source register address */
-#define	ISR2_A	ADDR(ISR2)	/* second	-"-	 */
-#define	CSR_A	ADDR(CSRA)	/* control/status register address */
-#define	CSF_A	ADDR(CSFA)	/* control/status FIFO BUSY flags (r/w) */
-
-#define	CSIL_A	ADDR(CSIL)	/* I/O mapped POS_ID_low (102) */
-#define	CSIH_A	ADDR(CSIH)	/*	- " - POS_ID_HIGH (101) */
-#define	CSA_A	ADDR(CSA)	/*	- " - POS_102 */
-#define	CSI_A	ADDR(CSI)	/*	- " - POS_104 */
-#define	CSM_A	ADDR(CSM)	/*	- " - POS_103 */
-#define	CSM_FM1_A	ADDR(CSM_FM1)	/*	- " - POS_103 (2nd copy, FM1) */
-#define	CSP_06_A	ADDR(CSP_06)	/*	- " - POS_106 */
-
-#define	WCT_A	ADDR(WCTA)	/* word counter (r/w) */
-#define	FFLAG_A	ADDR(FFLAG)	/* FLAG/V_FULL (FIFO almost full, write only)*/
-
-#define	ACL_A	ADDR(ACLA)	/* address counter low */
-#define	ACH_A	ADDR(ACHA)	/* address counter high */
-#define	BCN_A	ADDR(BCN)	/* byte counter */
-#define	MUX_A	ADDR(MUX)	/* MUX-register */
-
-#define	ISR_A	ADDR(ISRA)	/* Interrupt Source Register */
-#define	FIFO_RESET_A	ADDR(FIFO_RESET)	/* reset the FIFO */
-#define	FIFO_EN_A	ADDR(FIFO_EN)		/* enable the FIFO */
-
-#define WDOG_EN_A	ADDR(WDOG_EN)		/* reset and start the WDOG */
-#define WDOG_DIS_A	ADDR(WDOG_DIS)		/* disable the WDOG */
-/*
- * all control reg. (read!) are 8 bit (except PAGE_RG_A and LEDR_A)
- */
-#define	HSR_A(p)	ADDR(HSR(p))	/* Host request register */
-
-#define	STAT_BYP	0		/* bypass station */
-#define	STAT_INS	2		/* insert station */
-#define	BYPASS(o)	CS(0x10|(o))	/* o=STAT_BYP || STAT_INS */
-
-#define	IRQ_TC_EN	CS(0x0b)	/* enable/disable IRQ on TC */
-#define	IRQ_TC_DIS	CS(0x0a)
-#define	IRQ_TOKEN_EN	CS(9)		/* enable/disable IRQ on restr. Token */
-#define	IRQ_TOKEN_DIS	CS(8)
-#define	IRQ_CHCK_EN	CS(7)		/*	-"-	IRQ after CHCK line */
-#define	IRQ_CHCK_DIS	CS(6)
-#define	IRQ_OTH_EN	CS(5)		/*	-"-	other IRQ's */
-#define	IRQ_OTH_DIS	CS(4)
-#define	FIFO_EN		CS(3)		/* disable (reset), enable FIFO */
-#define	FIFO_RESET	CS(2)
-#define	CARD_EN		CS(1)		/* disable (reset), enable card */
-#define	CARD_DIS	CS(0)
-
-#define	LEDR_A		ADDR(LEDR)	/* D0=green, D1=yellow, D8=L2 */
-#define	PAGE_RG_A	ADDR(CSM)	/* D<2..0> */
-#define	IRQ_CHCK_EN_A	ADDR(IRQ_CHCK_EN)
-#define IRQ_CHCK_DIS_A	ADDR(IRQ_CHCK_DIS)
-
-#define	GET_PAGE(bank)	outpw(PAGE_RG_A,(inpw(PAGE_RG_A) &\
-				(~POS_PAGE)) |(int) (bank))
-#define	VPP_ON()	if (smc->hw.rev == FM1_REV) {	\
-				outpw(PAGE_RG_A,	\
-				(inpw(PAGE_RG_A) & POS_PAGE) | PROG_EN); \
-			}
-#define	VPP_OFF()	if (smc->hw.rev == FM1_REV) {	\
-				outpw(PAGE_RG_A,(inpw(PAGE_RG_A) & POS_PAGE)); \
-			}
-
-#define	SKFDDI_PSZ	16		/* address PROM size */
-
-#define	READ_PROM(a)	((u_char)inp(a))
-
-#define	GET_ISR()	~inpw(ISR1_A)
-#ifndef	TCI
-#define	CHECK_ISR()	~inpw(ISR1_A)
-#define	CHECK_ISR_SMP(iop)	~inpw((iop)+ISRA)
-#else
-#define	CHECK_ISR()		(~inpw(ISR1_A) | ~inpw(ISR2_A))
-#define	CHECK_ISR_SMP(iop)	(~inpw((iop)+ISRA) | ~inpw((iop)+ISR2))
-#endif
-
-#define	DMA_BUSY()	(inpw(CSF_A) & CSF_BUSY_DMA)
-#define	FIFO_BUSY()	(inpw(CSF_A) & CSF_BUSY_FIFO)
-#define	DMA_FIFO_BUSY()	(inpw(CSF_A) & (CSF_BUSY_DMA | CSF_BUSY_FIFO))
-#define	BUS_CHECK() {	int i ; \
-			if ((i = GET_ISR()) & IS_BUSERR) \
-				SMT_PANIC(smc,HWM_E0020,HWM_E0020_MSG) ; \
-			if (i & IS_CHCK_L) \
-				SMT_PANIC(smc,HWM_E0014,HWM_E0014_MSG) ; \
-		}
-
-#define	CHECK_DMA() {	u_long k = 10000 ; \
-		 while (k && (DMA_BUSY())) { \
-			k-- ; \
-			BUS_CHECK() ; \
-		 } \
-		 if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
-
-#define	CHECK_FIFO() {u_long k = 1000000 ;\
-		 while (k && (FIFO_BUSY())) k-- ;\
-		 if (!k) SMT_PANIC(smc,HWM_E0019,HWM_E0019_MSG) ; }
-
-#define	CHECK_DMA_FIFO() {u_long k = 1000000 ;\
-		 while (k && (DMA_FIFO_BUSY())) { \
-			k-- ;\
-			BUS_CHECK() ; \
-		 } \
-		 if (!k) SMT_PANIC(smc,HWM_E0004,HWM_E0004_MSG) ; }
-
-#ifndef UNIX
-#define	CLI_FBI()	outp(ADDR(IRQ_OTH_DIS),0)
-#else
-#define	CLI_FBI(smc)	outp(ADDRS((smc),IRQ_OTH_DIS),0)
-#endif
-
-#ifndef	TCI
-#define	CLI_FBI_SMP(iop)	outp((iop)+IRQ_OTH_DIS,0)
-#else
-#define	CLI_FBI_SMP(iop)	outp((iop)+IRQ_OTH_DIS,0) ;\
-				outp((iop)+IRQ_TC_DIS,0)
-#endif
-
-#ifndef UNIX
-#define	STI_FBI()	outp(ADDR(IRQ_OTH_EN),0)
-#else
-#define	STI_FBI(smc)	outp(ADDRS((smc),IRQ_OTH_EN),0)
-#endif
-
-/*
- * Terminal count primitives
- */
-#define CLI_TCI(smc)	outp(ADDRS((smc),IRQ_TC_DIS),0)
-#define STI_TCI(smc)	outp(ADDRS((smc),IRQ_TC_EN),0)
-#define CHECK_TC(smc,k)	{(k) = 10000 ;\
-	while ((k) && (~inpw(ISR2_A) & IS_TC)) (k)-- ;\
-	if (!k) SMT_PANIC(smc,HWM_E0018,HWM_E0018_MSG) ; }
-
-#endif	/* MCA */
-
-#ifdef	ISA
-
-/*
- * address transmission from logic NPADDR6-0 to physical offset address on board
- */
-#define FMA(a)	(0x8000|(((a)&0x07)<<1)|(((a)&0x78)<<7))  /* FORMAC+ (r/w) */
-#define PRA(a)	(0x1000|(((a)&0x07)<<1)|(((a)&0x18)<<7))  /* PROM (read only)*/
-#define P1A(a)	(0x4000|(((a)&0x07)<<1)|(((a)&0x18)<<7))  /* PLC1 (r/w) */
-#define P2A(a)	(0x5000|(((a)&0x07)<<1)|(((a)&0x18)<<7))  /* PLC2 (r/w) */
-#define TIA(a)	(0x6000|(((a)&0x03)<<1))		  /* Timer (r/w) */
-
-#define	ISRA	0x0000		/* int. source register address (read only) */
-#define	ACLA	0x0000		/* address counter low address (write only) */
-#define	ACHA	0x0002		/* address counter high address (write only) */
-#define	TRCA	0x0004		/* transfer counter address (write only) */
-#define	PGRA	0x0006		/* page register address (write only) */
-#define RQAA	0x2000		/* Request reg. (write only) */
-#define	CSRA	0x3000		/* control/status register address (r/w) */
-
-/*
- * physical address offset + IO-Port base address
- */
-#define FM_A(a)	(FMA(a)+smc->hw.iop)	/* FORMAC Plus physical addr */
-#define PR_A(a)	(PRA(a)+smc->hw.iop)	/* PROM (read only)*/
-#define P1_A(a)	(P1A(a)+smc->hw.iop)	/* PLC1 (r/w) */
-#define P2_A(a)	(P2A(a)+smc->hw.iop)	/* PLC2 (r/w) */
-#define TI_A(a)	(TIA(a)+smc->hw.iop)	/* Timer (r/w) */
-
-#define	ISR_A	(0x0000+smc->hw.iop) /* int. source register address (read only) */
-#define	ACL_A	(0x0000+smc->hw.iop) /* address counter low address (write only) */
-#define	ACH_A	(0x0002+smc->hw.iop) /* address counter high address (write only)*/
-#define	TRC_A	(0x0004+smc->hw.iop) /* transfer counter address (write only) */
-#define	PGR_A	(0x0006+smc->hw.iop) /* page register address (write only) */
-#define RQA_A	(0x2000+smc->hw.iop) /* Request reg. (write only) */
-#define	CSR_A	(0x3000+smc->hw.iop) /* control/status register address (r/w) */
-#ifdef UNIX
-#define	CSR_AS(smc) (0x3000+(smc)->hw.iop) /* control/status register address */
-#endif
-#define	PLC1_I	(0x3400+smc->hw.iop) /* clear PLC1 interrupt bit */
-#define	PLC2_I	(0x3800+smc->hw.iop) /* clear PLC2 interrupt bit */
-
-#ifndef	MULT_OEM
-#ifndef	OEM_CONCEPT
-#define	SKLOGO_STR	"SKFDDI"
-#else	/* OEM_CONCEPT */
-#define	SKLOGO_STR	OEM_FDDI_LOGO
-#endif	/* OEM_CONCEPT */
-#endif  /* MULT_OEM */
-#define	SADDRL	(24)		/* start address SKLOGO */
-#define	SA_MAC	(0)		/* start addr. MAC_AD within the PROM */
-#define	PRA_OFF	(0)
-#define SA_PMD_TYPE	(8)	/* start addr. PMD-Type */
-
-#define	CDID	(PRA(SADDRL))	/* Card ID int/O port addr. offset */
-#define	NEXT_CDID	((PRA(SADDRL+1)) - CDID)
-
-#define	SKFDDI_PSZ	32		/* address PROM size */
-
-#define	READ_PROM(a)	((u_char)inpw(a))
-#define	GET_PAGE(i)	outpw(PGR_A,(int)(i))
-
-#define	MAX_PAGES	16		/* 16 pages */
-#define	MAX_FADDR	0x2000		/* 8K per page */
-#define	VPP_OFF()	outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS)))
-#define	VPP_ON()	outpw(CSR_A,(inpw(CSR_A) & (CS_CRESET|CS_BYPASS)) | \
-				CS_VPPSW)
-
-/*
- * control/status register CSRA	bits (log. addr: 0x3000)
- */
-/* write */
-#define CS_CRESET	0x01		/* Card reset (0=reset) */
-#define	CS_IMSK		0x02		/* enable IRQ (1=enable, 0=disable) */
-#define CS_RESINT1	0x04		/* PLINT1 reset */
-#define	CS_VPPSW	0x10		/* 12V power switch (0=off, 1=on) */
-#define CS_BYPASS	0x20		/* bypass switch (0=remove, 1=insert)*/
-#define CS_RESINT2	0x40		/* PLINT2 reset */
-/* read */
-#define	CS_BUSY		0x04		/* master transfer activ (=1) */
-#define	CS_SW_EPROM	0x08		/* 0=Application Soft. 1=BOOT-EPROM */
-#define	CS_BYSTAT	0x40		/* 0=Bypass exist, 1= ..not */
-#define	CS_SAS		0x80		/* single attachement station (=1) */
-
-/*
- * Interrupt source register ISRA (log. addr: 0x0000) read only & low activ.
- */
-#define IS_MINTR1	0x01		/* FORMAC ST1U/L && ~IMSK1U/L*/
-#define IS_MINTR2	0x02		/* FORMAC ST2U/L && ~IMSK2U/L*/
-#define IS_PLINT1	0x04		/* PLC1 */
-#define IS_PLINT2	0x08		/* PLC2 */
-#define IS_TIMINT	0x10		/* Timer 82C54-2 */
-
-#define	ALL_IRSR	(IS_MINTR1|IS_MINTR2|IS_PLINT1|IS_PLINT2|IS_TIMINT)
-
-#define	FPROM_SW()	(inpw(CSR_A)&CS_SW_EPROM)
-#define	DMA_BUSY()	(inpw(CSR_A)&CS_BUSY)
-#define CHECK_FIFO()
-#define	BUS_CHECK()
-
-/*
- * set Host Request register (wr.)
- */
-#define SET_HRQ(qup)	outpw(RQA_A+((qup)<<1),0)
-
-#ifndef UNIX
-#ifndef WINNT
-#define	CLI_FBI()	outpw(CSR_A,(inpw(CSR_A)&(CS_CRESET|CS_BYPASS|CS_VPPSW)))
-#else
-#define	CLI_FBI()	outpw(CSR_A,(l_inpw(CSR_A) & \
-				(CS_CRESET|CS_BYPASS|CS_VPPSW)))
-#endif
-#else
-#define	CLI_FBI(smc)	outpw(CSR_AS(smc),(inpw(CSR_AS(smc))& \
-						(CS_CRESET|CS_BYPASS|CS_VPPSW)))
-#endif
-
-#ifndef UNIX
-#define	STI_FBI()	outpw(CSR_A,(inpw(CSR_A) & \
-				(CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK)
-#else
-#define	STI_FBI(smc)	outpw(CSR_AS(smc),(inpw(CSR_AS(smc)) & \
-				(CS_CRESET|CS_BYPASS|CS_VPPSW)) | CS_IMSK)
-#endif
-
-#define CHECK_DMA()	{unsigned k = 10000 ;\
-			while (k && (DMA_BUSY())) k-- ;\
-			if (!k) SMT_PANIC(smc,HWM_E0003,HWM_E0003_MSG) ; }
-
-#define	GET_ISR()	~inpw(ISR_A)
-
-#endif	/* ISA */
-
 /*--------------------------------------------------------------------------*/
 #ifdef	PCI
 
diff --git a/drivers/net/skfp/h/skfbiinc.h b/drivers/net/skfp/h/skfbiinc.h
index 79d55ad..ac2d719 100644
--- a/drivers/net/skfp/h/skfbiinc.h
+++ b/drivers/net/skfp/h/skfbiinc.h
@@ -22,32 +22,6 @@
  */
 #define ERR_FLAGS (FS_MSRABT | FS_SEAC2 | FS_SFRMERR | FS_SFRMTY1)
 
-#ifdef	ISA
-#define DMA_BUSY_CHECK	CSRA
-#define	IMASK_FAST	(IS_PLINT1 | IS_PLINT2 | IS_TIMINT)
-#define	HRQR		(RQAA+(RQ_RRQ<<1))
-#define	HRQW		(RQAA+(RQ_WA2<<1))
-#define	HRQA0		(RQAA+(RQ_WA0<<1))
-#define HRQSQ		(RQAA+(RQ_WSQ<<1))
-#endif
-
-#ifdef	EISA
-#define	DMA_BUSY_CHECK	CSRA
-#define DMA_HIGH_WORD	0x0400
-#define DMA_MASK_M	0x0a
-#define DMA_MODE_M	0x0b
-#define DMA_BYTE_PTR_M	0x0c
-#define DMA_MASK_S	0x0d4
-#define DMA_MODE_S	0x0d6
-#define DMA_BYTE_PTR_S	0x0d8
-#define	IMASK_FAST	(IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TC)
-#endif	/* EISA */
-
-#ifdef	MCA
-#define	IMASK_FAST	(IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \
-			 IS_CHCK_L | IS_BUSERR)
-#endif
-
 #ifdef PCI
 #define	IMASK_FAST	(IS_PLINT1 | IS_PLINT2 | IS_TIMINT | IS_TOKEN | \
 			 IS_MINTR2 | IS_MINTR3 | IS_R1_P | \
diff --git a/drivers/net/skfp/h/targethw.h b/drivers/net/skfp/h/targethw.h
index 22c4923..626dc72 100644
--- a/drivers/net/skfp/h/targethw.h
+++ b/drivers/net/skfp/h/targethw.h
@@ -53,11 +53,6 @@
 	u_char 	oi_sub_id[4] ;		/* sub id bytes, representation as */
 					/* defined by hardware,		*/
 #endif
-#ifdef ISA
-	u_char	oi_logo_len ;		/* the length of the adapter logo */	
-	u_char	oi_logo[6] ;		/* the adapter logo		*/
-	u_char	oi_reserved1 ;
-#endif	/* ISA */
 } ;
 #endif	/* MULT_OEM */
 
@@ -70,43 +65,17 @@
 	short	dma ;			/* DMA channel */
 	short	irq ;			/* IRQ level */
 	short	eprom ;			/* FLASH prom */
-#ifndef	PCI
-	short	DmaWriteExtraBytes ;	/* add bytes for DMA write */
-#endif
 
 #ifndef SYNC
 	u_short	n_a_send ;		/* pending send requests */
 #endif
 
-#if	(defined(EISA) || defined(MCA) || defined(PCI))
+#if	defined(PCI)
 	short	slot ;			/* slot number */
 	short   max_slots ;		/* maximum number of slots */
-#endif
-
-#if	(defined(PCI) || defined(MCA))
 	short	wdog_used ;		/* TRUE if the watch dog is used */
 #endif
 
-#ifdef	MCA
-	short	slot_32 ;		/* 32bit slot (1) or 16bit slot (0) */
-	short	rev ;			/* Board revision (FMx_REV). */
-	short	VFullRead ;		/* V_full value for DMA read */
-	short	VFullWrite ;		/* V_full value for DMA write */
-#endif
-
-#ifdef	EISA
-	short	led ;			/* LED for FE card */
-
-	short	dma_rmode ;		/* read mode */
-	short	dma_wmode ;		/* write mode */
-	short	dma_emode ;		/* extend mode */
-
-	/* DMA controller channel dependent io addresses */
-	u_short dma_base_word_count ;
-	u_short dma_base_address ;
-	u_short dma_base_address_page ;
-#endif
-
 #ifdef	PCI
 	u_short	pci_handle ;		/* handle to access the BIOS func */
 	u_long	is_imask ;		/* int maske for the int source reg */
diff --git a/drivers/net/skfp/hwt.c b/drivers/net/skfp/hwt.c
index e01f8a0..0531514 100644
--- a/drivers/net/skfp/hwt.c
+++ b/drivers/net/skfp/hwt.c
@@ -77,25 +77,10 @@
 	 */
 	if (!cnt)
 		cnt++ ;
-#ifndef	PCI
-	/*
-	 * 6.25MHz -> CLK0 : T0 (cnt0 = 16us)	-> OUT0
-	 *    OUT0 -> CLK1 : T1 (cnt1)	OUT1	-> ISRA(IS_TIMINT)
-	 */
-	OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ;	/* counter 1, mode 0 */
-	OUT_82c54_TIMER(1,cnt & 0xff) ;		/* LSB */
-	OUT_82c54_TIMER(1,(cnt>>8) & 0xff) ;	/* MSB */
-	/*
-	 * start timer by switching counter 0 to mode 3
-	 *	T0 resolution 16 us (CLK0=0.16us)
-	 */
-	OUT_82c54_TIMER(3,0<<6 | 3<<4 | 3<<1) ;	/* counter 0, mode 3 */
-	OUT_82c54_TIMER(0,100) ;		/* LSB */
-	OUT_82c54_TIMER(0,0) ;			/* MSB */
-#else	/* PCI */
+
 	outpd(ADDR(B2_TI_INI), (u_long) cnt * 200) ;	/* Load timer value. */
 	outpw(ADDR(B2_TI_CRTL), TIM_START) ;		/* Start timer. */
-#endif	/* PCI */
+
 	smc->hw.timer_activ = TRUE ;
 }
 
@@ -115,15 +100,8 @@
  ************************/
 void hwt_stop(struct s_smc *smc)
 {
-#ifndef PCI
-	/* stop counter 0 by switching to mode 0 */
-	OUT_82c54_TIMER(3,0<<6 | 3<<4 | 0<<1) ;	/* counter 0, mode 0 */
-	OUT_82c54_TIMER(0,0) ;			/* LSB */
-	OUT_82c54_TIMER(0,0) ;			/* MSB */
-#else	/* PCI */
 	outpw(ADDR(B2_TI_CRTL), TIM_STOP) ;
 	outpw(ADDR(B2_TI_CRTL), TIM_CL_IRQ) ;
-#endif	/* PCI */
 
 	smc->hw.timer_activ = FALSE ;
 }
@@ -168,11 +146,6 @@
 void hwt_restart(struct s_smc *smc)
 {
 	hwt_stop(smc) ;
-#ifndef	PCI
-	OUT_82c54_TIMER(3,1<<6 | 3<<4 | 0<<1) ;	/* counter 1, mode 0 */
-	OUT_82c54_TIMER(1,1 ) ;			/* LSB */
-	OUT_82c54_TIMER(1,0 ) ;			/* MSB */
-#endif
 }
 
 /************************
@@ -191,21 +164,12 @@
 u_long hwt_read(struct s_smc *smc)
 {
 	u_short	tr ;
-#ifndef	PCI
-	u_short	is ;
-#else
 	u_long	is ;
-#endif
 
 	if (smc->hw.timer_activ) {
 		hwt_stop(smc) ;
-#ifndef	PCI
-		OUT_82c54_TIMER(3,1<<6) ;	/* latch command */
-		tr = IN_82c54_TIMER(1) & 0xff ;
-		tr += (IN_82c54_TIMER(1) & 0xff)<<8 ;
-#else	/* PCI */
 		tr = (u_short)((inpd(ADDR(B2_TI_VAL))/200) & 0xffff) ;
-#endif	/* PCI */
+
 		is = GET_ISR() ;
 		/* Check if timer expired (or wraparound). */
 		if ((tr > smc->hw.t_start) || (is & IS_TIMINT)) {
diff --git a/drivers/net/skfp/pmf.c b/drivers/net/skfp/pmf.c
index efc639c..ea85de9 100644
--- a/drivers/net/skfp/pmf.c
+++ b/drivers/net/skfp/pmf.c
@@ -575,7 +575,7 @@
 	int		sp_len ;
 
 	/*
-	 * skip if errror
+	 * skip if error
 	 */
 	if (pcon->pc_err)
 		return ;
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index a7ef6c8..7cf9b9f 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -260,9 +260,7 @@
 	dev->set_multicast_list = &skfp_ctl_set_multicast_list;
 	dev->set_mac_address = &skfp_ctl_set_mac_address;
 	dev->do_ioctl = &skfp_ioctl;
-	dev->header_cache_update = NULL;	/* not supported */
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	/* Initialize board structure with bus-specific info */
diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c
index 75afc1f..ced2c8f 100644
--- a/drivers/net/skfp/smt.c
+++ b/drivers/net/skfp/smt.c
@@ -1654,7 +1654,7 @@
 	{ SMT_P4053,	0,	SWAP_SMT_P4053			} ,
 } ;
 
-#define N_SMT_PLEN	(sizeof(smt_pdef)/sizeof(smt_pdef[0]))
+#define N_SMT_PLEN	ARRAY_SIZE(smt_pdef)
 
 int smt_check_para(struct s_smc *smc, struct smt_header	*sm,
 		   const u_short list[])
diff --git a/drivers/net/skfp/srf.c b/drivers/net/skfp/srf.c
index 16573ac..6caf713 100644
--- a/drivers/net/skfp/srf.c
+++ b/drivers/net/skfp/srf.c
@@ -43,7 +43,7 @@
 static void smt_send_srf(struct s_smc *smc);
 static struct s_srf_evc *smt_get_evc(struct s_smc *smc, int code, int index);
 
-#define MAX_EVCS	(sizeof(smc->evcs)/sizeof(smc->evcs[0]))
+#define MAX_EVCS	ARRAY_SIZE(smc->evcs)
 
 struct evc_init {
 	u_char code ;
@@ -67,7 +67,7 @@
 	{ SMT_EVENT_PORT_PATH_CHANGE,		INDEX_PORT,NUMPHYS,SMT_P4053 } ,
 } ;
 
-#define MAX_INIT_EVC	(sizeof(evc_inits)/sizeof(evc_inits[0]))
+#define MAX_INIT_EVC	ARRAY_SIZE(evc_inits)
 
 void smt_init_evc(struct s_smc *smc)
 {
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 7766929..2aae9fe 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -410,9 +410,14 @@
 	{ "rx_fcs_error",	XM_RXF_FCS_ERR, GM_RXF_FCS_ERR },
 };
 
-static int skge_get_stats_count(struct net_device *dev)
+static int skge_get_sset_count(struct net_device *dev, int sset)
 {
-	return ARRAY_SIZE(skge_stats);
+	switch (sset) {
+	case ETH_SS_STATS:
+		return ARRAY_SIZE(skge_stats);
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void skge_get_ethtool_stats(struct net_device *dev,
@@ -811,17 +816,14 @@
 	.set_pauseparam = skge_set_pauseparam,
 	.get_coalesce	= skge_get_coalesce,
 	.set_coalesce	= skge_set_coalesce,
-	.get_sg		= ethtool_op_get_sg,
 	.set_sg		= skge_set_sg,
-	.get_tx_csum	= ethtool_op_get_tx_csum,
 	.set_tx_csum	= skge_set_tx_csum,
 	.get_rx_csum	= skge_get_rx_csum,
 	.set_rx_csum	= skge_set_rx_csum,
 	.get_strings	= skge_get_strings,
 	.phys_id	= skge_phys_id,
-	.get_stats_count = skge_get_stats_count,
+	.get_sset_count = skge_get_sset_count,
 	.get_ethtool_stats = skge_get_ethtool_stats,
-	.get_perm_addr	= ethtool_op_get_perm_addr,
 };
 
 /*
@@ -2529,7 +2531,7 @@
 	skge_write32(hw, B0_IMSK, hw->intr_mask);
 	spin_unlock_irq(&hw->hw_lock);
 
-	netif_poll_enable(dev);
+	napi_enable(&skge->napi);
 	return 0;
 
  free_rx_ring:
@@ -2559,7 +2561,7 @@
 	if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)
 		del_timer_sync(&skge->link_timer);
 
-	netif_poll_disable(dev);
+	napi_disable(&skge->napi);
 	netif_carrier_off(dev);
 
 	spin_lock_irq(&hw->hw_lock);
@@ -3045,14 +3047,13 @@
 	}
 }
 
-static int skge_poll(struct net_device *dev, int *budget)
+static int skge_poll(struct napi_struct *napi, int to_do)
 {
-	struct skge_port *skge = netdev_priv(dev);
+	struct skge_port *skge = container_of(napi, struct skge_port, napi);
+	struct net_device *dev = skge->netdev;
 	struct skge_hw *hw = skge->hw;
 	struct skge_ring *ring = &skge->rx_ring;
 	struct skge_element *e;
-	unsigned long flags;
-	int to_do = min(dev->quota, *budget);
 	int work_done = 0;
 
 	skge_tx_done(dev);
@@ -3083,20 +3084,16 @@
 	wmb();
 	skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_START);
 
-	*budget -= work_done;
-	dev->quota -= work_done;
+	if (work_done < to_do) {
+		spin_lock_irq(&hw->hw_lock);
+		__netif_rx_complete(dev, napi);
+		hw->intr_mask |= napimask[skge->port];
+		skge_write32(hw, B0_IMSK, hw->intr_mask);
+		skge_read32(hw, B0_IMSK);
+		spin_unlock_irq(&hw->hw_lock);
+	}
 
-	if (work_done >=  to_do)
-		return 1; /* not done */
-
-	spin_lock_irqsave(&hw->hw_lock, flags);
-	__netif_rx_complete(dev);
-	hw->intr_mask |= napimask[skge->port];
-  	skge_write32(hw, B0_IMSK, hw->intr_mask);
-	skge_read32(hw, B0_IMSK);
-	spin_unlock_irqrestore(&hw->hw_lock, flags);
-
-	return 0;
+	return work_done;
 }
 
 /* Parity errors seem to happen when Genesis is connected to a switch
@@ -3253,8 +3250,9 @@
 	}
 
 	if (status & (IS_XA1_F|IS_R1_F)) {
+		struct skge_port *skge = netdev_priv(hw->dev[0]);
 		hw->intr_mask &= ~(IS_XA1_F|IS_R1_F);
-		netif_rx_schedule(hw->dev[0]);
+		netif_rx_schedule(hw->dev[0], &skge->napi);
 	}
 
 	if (status & IS_PA_TO_TX1)
@@ -3272,13 +3270,14 @@
 		skge_mac_intr(hw, 0);
 
 	if (hw->dev[1]) {
+		struct skge_port *skge = netdev_priv(hw->dev[1]);
+
 		if (status & (IS_XA2_F|IS_R2_F)) {
 			hw->intr_mask &= ~(IS_XA2_F|IS_R2_F);
-			netif_rx_schedule(hw->dev[1]);
+			netif_rx_schedule(hw->dev[1], &skge->napi);
 		}
 
 		if (status & IS_PA_TO_RX2) {
-			struct skge_port *skge = netdev_priv(hw->dev[1]);
 			++skge->net_stats.rx_over_errors;
 			skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX2);
 		}
@@ -3553,7 +3552,6 @@
 		return NULL;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &hw->pdev->dev);
 	dev->open = skge_up;
 	dev->stop = skge_down;
@@ -3570,8 +3568,6 @@
 	SET_ETHTOOL_OPS(dev, &skge_ethtool_ops);
 	dev->tx_timeout = skge_tx_timeout;
 	dev->watchdog_timeo = TX_WATCHDOG;
-	dev->poll = skge_poll;
-	dev->weight = NAPI_WEIGHT;
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = skge_netpoll;
 #endif
@@ -3581,6 +3577,7 @@
 		dev->features |= NETIF_F_HIGHDMA;
 
 	skge = netdev_priv(dev);
+	netif_napi_add(dev, &skge->napi, skge_poll, NAPI_WEIGHT);
 	skge->netdev = dev;
 	skge->hw = hw;
 	skge->msg_enable = netif_msg_init(debug, default_msg);
@@ -3624,12 +3621,11 @@
 static void __devinit skge_show_addr(struct net_device *dev)
 {
 	const struct skge_port *skge = netdev_priv(dev);
+	DECLARE_MAC_BUF(mac);
 
 	if (netif_msg_probe(skge))
-		printk(KERN_INFO PFX "%s: addr %02x:%02x:%02x:%02x:%02x:%02x\n",
-		       dev->name,
-		       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-		       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+		printk(KERN_INFO PFX "%s: addr %s\n",
+		       dev->name, print_mac(mac, dev->dev_addr));
 }
 
 static int __devinit skge_probe(struct pci_dev *pdev,
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index edd7146..1a57bdd 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -1351,8 +1351,6 @@
 	PHY_M_PC_EN_DET_PLUS	= 3<<8, /* Energy Detect Plus (Mode 2) */
 };
 
-#define PHY_M_PC_MDI_XMODE(x)	((((u16)(x)<<5) & PHY_M_PC_MDIX_MSK)
-
 enum {
 	PHY_M_PC_MAN_MDI	= 0, /* 00 = Manual MDI configuration */
 	PHY_M_PC_MAN_MDIX	= 1, /* 01 = Manual MDIX configuration */
@@ -2448,6 +2446,7 @@
 struct skge_port {
 	struct skge_hw	     *hw;
 	struct net_device    *netdev;
+	struct napi_struct   napi;
 	int		     port;
 	u32		     msg_enable;
 
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index a2f3215..68f728f 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -31,6 +31,7 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/pci.h>
+#include <linux/aer.h>
 #include <linux/ip.h>
 #include <net/ip.h>
 #include <linux/tcp.h>
@@ -51,7 +52,7 @@
 #include "sky2.h"
 
 #define DRV_NAME		"sky2"
-#define DRV_VERSION		"1.16"
+#define DRV_VERSION		"1.19"
 #define PFX			DRV_NAME " "
 
 /*
@@ -99,10 +100,6 @@
 module_param(disable_msi, int, 0);
 MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
 
-static int idle_timeout = 100;
-module_param(idle_timeout, int, 0);
-MODULE_PARM_DESC(idle_timeout, "Watchdog timer for lost interrupts (ms)");
-
 static const struct pci_device_id sky2_id_table[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, /* SK-9Sxx */
 	{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, /* SK-9Exx */
@@ -122,12 +119,15 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4351) }, /* 88E8036 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4352) }, /* 88E8038 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4353) }, /* 88E8039 */
+	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4354) }, /* 88E8040 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4356) }, /* 88EC033 */
+	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x435A) }, /* 88E8048 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4360) }, /* 88E8052 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) }, /* 88E8050 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) }, /* 88E8053 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4363) }, /* 88E8055 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4364) }, /* 88E8056 */
+	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4365) }, /* 88E8070 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */
 	{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */
@@ -151,8 +151,11 @@
 	"Extreme",	/* 0xb5 */
 	"EC",		/* 0xb6 */
 	"FE",		/* 0xb7 */
+	"FE+",		/* 0xb8 */
 };
 
+static void sky2_set_multicast(struct net_device *dev);
+
 /* Access to external PHY */
 static int gm_phy_write(struct sky2_hw *hw, unsigned port, u16 reg, u16 val)
 {
@@ -219,25 +222,30 @@
 	else
 		sky2_write8(hw, B2_Y2_CLK_GATE, 0);
 
-	if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
+	if (hw->flags & SKY2_HW_ADV_POWER_CTL) {
+		struct pci_dev *pdev = hw->pdev;
 		u32 reg;
 
-		reg = sky2_pci_read32(hw, PCI_DEV_REG4);
+		pci_write_config_dword(pdev, PCI_DEV_REG3, 0);
+
+		pci_read_config_dword(pdev, PCI_DEV_REG4, &reg);
 		/* set all bits to 0 except bits 15..12 and 8 */
 		reg &= P_ASPM_CONTROL_MSK;
-		sky2_pci_write32(hw, PCI_DEV_REG4, reg);
+		pci_write_config_dword(pdev, PCI_DEV_REG4, reg);
 
-		reg = sky2_pci_read32(hw, PCI_DEV_REG5);
+		pci_read_config_dword(pdev, PCI_DEV_REG5, &reg);
 		/* set all bits to 0 except bits 28 & 27 */
 		reg &= P_CTL_TIM_VMAIN_AV_MSK;
-		sky2_pci_write32(hw, PCI_DEV_REG5, reg);
+		pci_write_config_dword(pdev, PCI_DEV_REG5, reg);
 
-		sky2_pci_write32(hw, PCI_CFG_REG_1, 0);
+		pci_write_config_dword(pdev, PCI_CFG_REG_1, 0);
 
 		/* Enable workaround for dev 4.107 on Yukon-Ultra & Extreme */
 		reg = sky2_read32(hw, B2_GP_IO);
 		reg |= GLB_GPIO_STAT_RACE_DIS;
 		sky2_write32(hw, B2_GP_IO, reg);
+
+		sky2_read32(hw, B2_GP_IO);
 	}
 }
 
@@ -288,10 +296,10 @@
 
 /* flow control to advertise bits when using 1000BaseX */
 static const u16 fiber_fc_adv[] = {
-	[FC_BOTH] = PHY_M_P_BOTH_MD_X,
+	[FC_NONE] = PHY_M_P_NO_PAUSE_X,
 	[FC_TX]   = PHY_M_P_ASYM_MD_X,
 	[FC_RX]	  = PHY_M_P_SYM_MD_X,
-	[FC_NONE] = PHY_M_P_NO_PAUSE_X,
+	[FC_BOTH] = PHY_M_P_BOTH_MD_X,
 };
 
 /* flow control to GMA disable bits */
@@ -308,10 +316,8 @@
 	struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
 	u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg;
 
-	if (sky2->autoneg == AUTONEG_ENABLE
-	    && !(hw->chip_id == CHIP_ID_YUKON_XL
-		 || hw->chip_id == CHIP_ID_YUKON_EC_U
-		 || hw->chip_id == CHIP_ID_YUKON_EX)) {
+	if (sky2->autoneg == AUTONEG_ENABLE &&
+	    !(hw->flags & SKY2_HW_NEWER_PHY)) {
 		u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
 
 		ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
@@ -331,9 +337,19 @@
 
 	ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
 	if (sky2_is_copper(hw)) {
-		if (hw->chip_id == CHIP_ID_YUKON_FE) {
+		if (!(hw->flags & SKY2_HW_GIGABIT)) {
 			/* enable automatic crossover */
 			ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO) >> 1;
+
+			if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
+			    hw->chip_rev == CHIP_REV_YU_FE2_A0) {
+				u16 spec;
+
+				/* Enable Class A driver for FE+ A0 */
+				spec = gm_phy_read(hw, port, PHY_MARV_FE_SPEC_2);
+				spec |= PHY_M_FESC_SEL_CL_A;
+				gm_phy_write(hw, port, PHY_MARV_FE_SPEC_2, spec);
+			}
 		} else {
 			/* disable energy detect */
 			ctrl &= ~PHY_M_PC_EN_DET_MSK;
@@ -343,9 +359,7 @@
 
 			/* downshift on PHY 88E1112 and 88E1149 is changed */
 			if (sky2->autoneg == AUTONEG_ENABLE
-			    && (hw->chip_id == CHIP_ID_YUKON_XL
-				|| hw->chip_id == CHIP_ID_YUKON_EC_U
-				|| hw->chip_id == CHIP_ID_YUKON_EX)) {
+			    && (hw->flags & SKY2_HW_NEWER_PHY)) {
 				/* set downshift counter to 3x and enable downshift */
 				ctrl &= ~PHY_M_PC_DSC_MSK;
 				ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA;
@@ -361,7 +375,7 @@
 	gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
 
 	/* special setup for PHY 88E1112 Fiber */
-	if (hw->chip_id == CHIP_ID_YUKON_XL && !sky2_is_copper(hw)) {
+	if (hw->chip_id == CHIP_ID_YUKON_XL && (hw->flags & SKY2_HW_FIBRE_PHY)) {
 		pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
 
 		/* Fiber: select 1000BASE-X only mode MAC Specific Ctrl Reg. */
@@ -452,7 +466,7 @@
 
 	gma_write16(hw, port, GM_GP_CTRL, reg);
 
-	if (hw->chip_id != CHIP_ID_YUKON_FE)
+	if (hw->flags & SKY2_HW_GIGABIT)
 		gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
 
 	gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv);
@@ -476,6 +490,23 @@
 		gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, ctrl);
 		break;
 
+	case CHIP_ID_YUKON_FE_P:
+		/* Enable Link Partner Next Page */
+		ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+		ctrl |= PHY_M_PC_ENA_LIP_NP;
+
+		/* disable Energy Detect and enable scrambler */
+		ctrl &= ~(PHY_M_PC_ENA_ENE_DT | PHY_M_PC_DIS_SCRAMB);
+		gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+
+		/* set LED2 -> ACT, LED1 -> LINK, LED0 -> SPEED */
+		ctrl = PHY_M_FELP_LED2_CTRL(LED_PAR_CTRL_ACT_BL) |
+			PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_LINK) |
+			PHY_M_FELP_LED0_CTRL(LED_PAR_CTRL_SPEED);
+
+		gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR, ctrl);
+		break;
+
 	case CHIP_ID_YUKON_XL:
 		pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
 
@@ -545,7 +576,13 @@
 
 		/* set page register to 0 */
 		gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 0);
+	} else if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
+		   hw->chip_rev == CHIP_REV_YU_FE2_A0) {
+		/* apply workaround for integrated resistors calibration */
+		gm_phy_write(hw, port, PHY_MARV_PAGE_ADDR, 17);
+		gm_phy_write(hw, port, PHY_MARV_PAGE_DATA, 0x3f60);
 	} else if (hw->chip_id != CHIP_ID_YUKON_EX) {
+		/* no effect on Yukon-XL */
 		gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
 
 		if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) {
@@ -567,25 +604,24 @@
 
 static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff)
 {
+	struct pci_dev *pdev = hw->pdev;
 	u32 reg1;
-	static const u32 phy_power[]
-		= { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD };
+	static const u32 phy_power[] = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD };
+	static const u32 coma_mode[] = { PCI_Y2_PHY1_COMA, PCI_Y2_PHY2_COMA };
 
-	/* looks like this XL is back asswards .. */
-	if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
-		onoff = !onoff;
-
-	sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
-	reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+	pci_read_config_dword(pdev, PCI_DEV_REG1, &reg1);
+	/* Turn on/off phy power saving */
 	if (onoff)
-		/* Turn off phy power saving */
 		reg1 &= ~phy_power[port];
 	else
 		reg1 |= phy_power[port];
 
-	sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
-	sky2_pci_read32(hw, PCI_DEV_REG1);
-	sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+	if (onoff && hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+		reg1 |= coma_mode[port];
+
+	pci_write_config_dword(pdev, PCI_DEV_REG1, reg1);
+	pci_read_config_dword(pdev, PCI_DEV_REG1, &reg1);
+
 	udelay(100);
 }
 
@@ -653,11 +689,9 @@
 	sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl);
 
 	/* Turn on legacy PCI-Express PME mode */
-	sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
-	reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+	pci_read_config_dword(hw->pdev, PCI_DEV_REG1, &reg1);
 	reg1 |= PCI_Y2_PME_LEGACY;
-	sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
-	sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+	pci_write_config_dword(hw->pdev, PCI_DEV_REG1, reg1);
 
 	/* block receiver */
 	sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
@@ -666,25 +700,25 @@
 
 static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port)
 {
-	if (hw->chip_id == CHIP_ID_YUKON_EX && hw->chip_rev != CHIP_REV_YU_EX_A0) {
+	struct net_device *dev = hw->dev[port];
+
+	if (dev->mtu <= ETH_DATA_LEN)
 		sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
-			     TX_STFW_ENA |
-			     (hw->dev[port]->mtu > ETH_DATA_LEN) ? TX_JUMBO_ENA : TX_JUMBO_DIS);
-	} else {
-		if (hw->dev[port]->mtu > ETH_DATA_LEN) {
-			/* set Tx GMAC FIFO Almost Empty Threshold */
-			sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
-				     (ECU_JUMBO_WM << 16) | ECU_AE_THR);
+			     TX_JUMBO_DIS | TX_STFW_ENA);
 
-			sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
-				     TX_JUMBO_ENA | TX_STFW_DIS);
+	else if (hw->chip_id != CHIP_ID_YUKON_EC_U)
+		sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+			     TX_STFW_ENA | TX_JUMBO_ENA);
+	else {
+		/* set Tx GMAC FIFO Almost Empty Threshold */
+		sky2_write32(hw, SK_REG(port, TX_GMF_AE_THR),
+			     (ECU_JUMBO_WM << 16) | ECU_AE_THR);
 
-			/* Can't do offload because of lack of store/forward */
-			hw->dev[port]->features &= ~(NETIF_F_TSO | NETIF_F_SG
-						     | NETIF_F_ALL_CSUM);
-		} else
-			sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
-				     TX_JUMBO_DIS | TX_STFW_ENA);
+		sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+			     TX_JUMBO_ENA | TX_STFW_DIS);
+
+		/* Can't do offload because of lack of store/forward */
+		dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | NETIF_F_ALL_CSUM);
 	}
 }
 
@@ -692,11 +726,12 @@
 {
 	struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
 	u16 reg;
+	u32 rx_reg;
 	int i;
 	const u8 *addr = hw->dev[port]->dev_addr;
 
-	sky2_write32(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET);
-	sky2_write32(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
+	sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET);
+	sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
 
 	sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
 
@@ -768,23 +803,30 @@
 
 	/* Configure Rx MAC FIFO */
 	sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
-	reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
-	if (hw->chip_id == CHIP_ID_YUKON_EX)
-		reg |= GMF_RX_OVER_ON;
+	rx_reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
+	if (hw->chip_id == CHIP_ID_YUKON_EX ||
+	    hw->chip_id == CHIP_ID_YUKON_FE_P)
+		rx_reg |= GMF_RX_OVER_ON;
 
-	sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), reg);
+	sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), rx_reg);
 
 	/* Flush Rx MAC FIFO on any flow control or error */
 	sky2_write16(hw, SK_REG(port, RX_GMF_FL_MSK), GMR_FS_ANY_ERR);
 
 	/* Set threshold to 0xa (64 bytes) + 1 to workaround pause bug  */
-	sky2_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF+1);
+	reg = RX_GMF_FL_THR_DEF + 1;
+	/* Another magic mystery workaround from sk98lin */
+	if (hw->chip_id == CHIP_ID_YUKON_FE_P &&
+	    hw->chip_rev == CHIP_REV_YU_FE2_A0)
+		reg = 0x178;
+	sky2_write16(hw, SK_REG(port, RX_GMF_FL_THR), reg);
 
 	/* Configure Tx MAC FIFO */
 	sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
 	sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
 
-	if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
+	/* On chips without ram buffer, pause is controled by MAC level */
+	if (sky2_read8(hw, B2_E_0) == 0) {
 		sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
 		sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
 
@@ -867,6 +909,20 @@
 	return le;
 }
 
+static void tx_init(struct sky2_port *sky2)
+{
+	struct sky2_tx_le *le;
+
+	sky2->tx_prod = sky2->tx_cons = 0;
+	sky2->tx_tcpsum = 0;
+	sky2->tx_last_mss = 0;
+
+	le = get_tx_le(sky2);
+	le->addr = 0;
+	le->opcode = OP_ADDR64 | HW_OWNER;
+	sky2->tx_addr64 = 0;
+}
+
 static inline struct tx_ring_info *tx_le_re(struct sky2_port *sky2,
 					    struct sky2_tx_le *le)
 {
@@ -963,19 +1019,15 @@
  */
 static void rx_set_checksum(struct sky2_port *sky2)
 {
-	struct sky2_rx_le *le;
+	struct sky2_rx_le *le = sky2_next_rx(sky2);
 
-	if (sky2->hw->chip_id != CHIP_ID_YUKON_EX) {
-		le = sky2_next_rx(sky2);
-		le->addr = cpu_to_le32((ETH_HLEN << 16) | ETH_HLEN);
-		le->ctrl = 0;
-		le->opcode = OP_TCPSTART | HW_OWNER;
+	le->addr = cpu_to_le32((ETH_HLEN << 16) | ETH_HLEN);
+	le->ctrl = 0;
+	le->opcode = OP_TCPSTART | HW_OWNER;
 
-		sky2_write32(sky2->hw,
-			     Q_ADDR(rxqaddr[sky2->port], Q_CSR),
-			     sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
-	}
-
+	sky2_write32(sky2->hw,
+		     Q_ADDR(rxqaddr[sky2->port], Q_CSR),
+		     sky2->rx_csum ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
 }
 
 /*
@@ -1077,7 +1129,7 @@
 	u16 port = sky2->port;
 
 	netif_tx_lock_bh(dev);
-	netif_poll_disable(sky2->hw->dev[0]);
+	napi_disable(&hw->napi);
 
 	sky2->vlgrp = grp;
 	if (grp) {
@@ -1092,7 +1144,7 @@
 			     TX_VLAN_TAG_OFF);
 	}
 
-	netif_poll_enable(sky2->hw->dev[0]);
+	napi_enable(&hw->napi);
 	netif_tx_unlock_bh(dev);
 }
 #endif
@@ -1171,7 +1223,8 @@
 
 	sky2_prefetch_init(hw, rxq, sky2->rx_le_map, RX_LE_SIZE - 1);
 
-	rx_set_checksum(sky2);
+	if (!(hw->flags & SKY2_HW_NEW_LE))
+		rx_set_checksum(sky2);
 
 	/* Space needed for frame data + headers rounded up */
 	size = roundup(sky2->netdev->mtu + ETH_HLEN + VLAN_HLEN, 8);
@@ -1242,7 +1295,7 @@
 	struct sky2_port *sky2 = netdev_priv(dev);
 	struct sky2_hw *hw = sky2->hw;
 	unsigned port = sky2->port;
-	u32 ramsize, imask;
+	u32 imask, ramsize;
 	int cap, err = -ENOMEM;
 	struct net_device *otherdev = hw->dev[sky2->port^1];
 
@@ -1255,9 +1308,9 @@
  		struct sky2_port *osky2 = netdev_priv(otherdev);
  		u16 cmd;
 
- 		cmd = sky2_pci_read16(hw, cap + PCI_X_CMD);
+		pci_read_config_word(hw->pdev, cap + PCI_X_CMD, &cmd);
  		cmd &= ~PCI_X_CMD_MAX_SPLIT;
- 		sky2_pci_write16(hw, cap + PCI_X_CMD, cmd);
+		pci_write_config_word(hw->pdev, cap + PCI_X_CMD, cmd);
 
  		sky2->rx_csum = 0;
  		osky2->rx_csum = 0;
@@ -1280,7 +1333,8 @@
 				GFP_KERNEL);
 	if (!sky2->tx_ring)
 		goto err_out;
-	sky2->tx_prod = sky2->tx_cons = 0;
+
+	tx_init(sky2);
 
 	sky2->rx_le = pci_alloc_consistent(hw->pdev, RX_LE_BYTES,
 					   &sky2->rx_le_map);
@@ -1299,11 +1353,10 @@
 
 	/* Register is number of 4K blocks on internal RAM buffer. */
 	ramsize = sky2_read8(hw, B2_E_0) * 4;
-	printk(KERN_INFO PFX "%s: ram buffer %dK\n", dev->name, ramsize);
-
 	if (ramsize > 0) {
 		u32 rxspace;
 
+		pr_debug(PFX "%s: ram buffer %dK\n", dev->name, ramsize);
 		if (ramsize < 16)
 			rxspace = ramsize / 2;
 		else
@@ -1331,9 +1384,13 @@
 	sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map,
 			   TX_RING_SIZE - 1);
 
+	napi_enable(&hw->napi);
+
 	err = sky2_rx_start(sky2);
-	if (err)
+	if (err) {
+		napi_disable(&hw->napi);
 		goto err_out;
+	}
 
 	/* Enable interrupts from phy/mac for port */
 	imask = sky2_read32(hw, B0_IMSK);
@@ -1432,13 +1489,15 @@
 	/* Check for TCP Segmentation Offload */
 	mss = skb_shinfo(skb)->gso_size;
 	if (mss != 0) {
-		if (hw->chip_id != CHIP_ID_YUKON_EX)
+
+		if (!(hw->flags & SKY2_HW_NEW_LE))
 			mss += ETH_HLEN + ip_hdrlen(skb) + tcp_hdrlen(skb);
 
   		if (mss != sky2->tx_last_mss) {
   			le = get_tx_le(sky2);
   			le->addr = cpu_to_le32(mss);
- 			if (hw->chip_id == CHIP_ID_YUKON_EX)
+
+			if (hw->flags & SKY2_HW_NEW_LE)
 				le->opcode = OP_MSS | HW_OWNER;
 			else
 				le->opcode = OP_LRGLEN | HW_OWNER;
@@ -1464,8 +1523,7 @@
 	/* Handle TCP checksum offload */
 	if (skb->ip_summed == CHECKSUM_PARTIAL) {
 		/* On Yukon EX (some versions) encoding change. */
- 		if (hw->chip_id == CHIP_ID_YUKON_EX
-		    && hw->chip_rev != CHIP_REV_YU_EX_B0)
+ 		if (hw->flags & SKY2_HW_AUTO_TX_SUM)
  			ctrl |= CALSUM;	/* auto checksum */
 		else {
 			const unsigned offset = skb_transport_offset(skb);
@@ -1577,8 +1635,8 @@
 				printk(KERN_DEBUG "%s: tx done %u\n",
 				       dev->name, idx);
 
-			sky2->net_stats.tx_packets++;
-			sky2->net_stats.tx_bytes += re->skb->len;
+			dev->stats.tx_packets++;
+			dev->stats.tx_bytes += re->skb->len;
 
 			dev_kfree_skb_any(re->skb);
 			sky2->tx_next = RING_NEXT(idx, TX_RING_SIZE);
@@ -1621,6 +1679,8 @@
 	/* Stop more packets from being queued */
 	netif_stop_queue(dev);
 
+	napi_disable(&hw->napi);
+
 	/* Disable port IRQ */
 	imask = sky2_read32(hw, B0_IMSK);
 	imask &= ~portirq_msk[port];
@@ -1701,11 +1761,15 @@
 
 static u16 sky2_phy_speed(const struct sky2_hw *hw, u16 aux)
 {
-	if (!sky2_is_copper(hw))
+	if (hw->flags & SKY2_HW_FIBRE_PHY)
 		return SPEED_1000;
 
-	if (hw->chip_id == CHIP_ID_YUKON_FE)
-		return (aux & PHY_M_PS_SPEED_100) ? SPEED_100 : SPEED_10;
+	if (!(hw->flags & SKY2_HW_GIGABIT)) {
+		if (aux & PHY_M_PS_SPEED_100)
+			return SPEED_100;
+		else
+			return SPEED_10;
+	}
 
 	switch (aux & PHY_M_PS_SPEED_MSK) {
 	case PHY_M_PS_SPEED_1000:
@@ -1738,13 +1802,13 @@
 
 	netif_carrier_on(sky2->netdev);
 
+	mod_timer(&hw->watchdog_timer, jiffies + 1);
+
 	/* Turn on link LED */
 	sky2_write8(hw, SK_REG(port, LNK_LED_REG),
 		    LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF);
 
-	if (hw->chip_id == CHIP_ID_YUKON_XL
-	    || hw->chip_id == CHIP_ID_YUKON_EC_U
-	    || hw->chip_id == CHIP_ID_YUKON_EX) {
+	if (hw->flags & SKY2_HW_NEWER_PHY) {
 		u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
 		u16 led = PHY_M_LEDC_LOS_CTRL(1);	/* link active */
 
@@ -1831,7 +1895,7 @@
 	/* Since the pause result bits seem to in different positions on
 	 * different chips. look at registers.
 	 */
-	if (!sky2_is_copper(hw)) {
+	if (hw->flags & SKY2_HW_FIBRE_PHY) {
 		/* Shift for bits in fiber PHY */
 		advert &= ~(ADVERTISE_PAUSE_CAP|ADVERTISE_PAUSE_ASYM);
 		lpa &= ~(LPA_PAUSE_CAP|LPA_PAUSE_ASYM);
@@ -1942,7 +2006,9 @@
 	if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
 		return -EINVAL;
 
-	if (new_mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_FE)
+	if (new_mtu > ETH_DATA_LEN &&
+	    (hw->chip_id == CHIP_ID_YUKON_FE ||
+	     hw->chip_id == CHIP_ID_YUKON_FE_P))
 		return -EINVAL;
 
 	if (!netif_running(dev)) {
@@ -1955,11 +2021,11 @@
 
 	dev->trans_start = jiffies;	/* prevent tx timeout */
 	netif_stop_queue(dev);
-	netif_poll_disable(hw->dev[0]);
+	napi_disable(&hw->napi);
 
 	synchronize_irq(hw->pdev->irq);
 
-	if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)
+	if (sky2_read8(hw, B2_E_0) == 0)
 		sky2_set_tx_stfwd(hw, port);
 
 	ctl = gma_read16(hw, port, GM_GP_CTRL);
@@ -1982,12 +2048,16 @@
 	err = sky2_rx_start(sky2);
 	sky2_write32(hw, B0_IMSK, imask);
 
+	/* Unconditionally re-enable NAPI because even if we
+	 * call dev_close() that will do a napi_disable().
+	 */
+	napi_enable(&hw->napi);
+
 	if (err)
 		dev_close(dev);
 	else {
 		gma_write16(hw, port, GM_GP_CTRL, ctl);
 
-		netif_poll_enable(hw->dev[0]);
 		netif_wake_queue(dev);
 	}
 
@@ -2087,6 +2157,13 @@
  	struct sky2_port *sky2 = netdev_priv(dev);
 	struct rx_ring_info *re = sky2->rx_ring + sky2->rx_next;
 	struct sk_buff *skb = NULL;
+	u16 count = (status & GMR_FS_LEN) >> 16;
+
+#ifdef SKY2_VLAN_TAG_USED
+	/* Account for vlan tag */
+	if (sky2->vlgrp && (status & GMR_FS_VLAN))
+		count -= VLAN_HLEN;
+#endif
 
 	if (unlikely(netif_msg_rx_status(sky2)))
 		printk(KERN_DEBUG PFX "%s: rx slot %u status 0x%x len %d\n",
@@ -2095,15 +2172,26 @@
 	sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending;
 	prefetch(sky2->rx_ring + sky2->rx_next);
 
+	/* This chip has hardware problems that generates bogus status.
+	 * So do only marginal checking and expect higher level protocols
+	 * to handle crap frames.
+	 */
+	if (sky2->hw->chip_id == CHIP_ID_YUKON_FE_P &&
+	    sky2->hw->chip_rev == CHIP_REV_YU_FE2_A0 &&
+	    length != count)
+		goto okay;
+
 	if (status & GMR_FS_ANY_ERR)
 		goto error;
 
 	if (!(status & GMR_FS_RX_OK))
 		goto resubmit;
 
-	if (status >> 16 != length)
-		goto len_mismatch;
+	/* if length reported by DMA does not match PHY, packet was truncated */
+	if (length != count)
+		goto len_error;
 
+okay:
 	if (length < copybreak)
 		skb = receive_copy(sky2, re, length);
 	else
@@ -2113,15 +2201,19 @@
 
 	return skb;
 
-len_mismatch:
+len_error:
 	/* Truncation of overlength packets
 	   causes PHY length to not match MAC length */
-	++sky2->net_stats.rx_length_errors;
+	++dev->stats.rx_length_errors;
+	if (netif_msg_rx_err(sky2) && net_ratelimit())
+		pr_info(PFX "%s: rx length error: status %#x length %d\n",
+			dev->name, status, length);
+	goto resubmit;
 
 error:
-	++sky2->net_stats.rx_errors;
+	++dev->stats.rx_errors;
 	if (status & GMR_FS_RX_FF_OV) {
-		sky2->net_stats.rx_over_errors++;
+		dev->stats.rx_over_errors++;
 		goto resubmit;
 	}
 
@@ -2130,11 +2222,11 @@
 		       dev->name, status, length);
 
 	if (status & (GMR_FS_LONG_ERR | GMR_FS_UN_SIZE))
-		sky2->net_stats.rx_length_errors++;
+		dev->stats.rx_length_errors++;
 	if (status & GMR_FS_FRAGMENT)
-		sky2->net_stats.rx_frame_errors++;
+		dev->stats.rx_frame_errors++;
 	if (status & GMR_FS_CRC_ERR)
-		sky2->net_stats.rx_crc_errors++;
+		dev->stats.rx_crc_errors++;
 
 	goto resubmit;
 }
@@ -2152,15 +2244,13 @@
 }
 
 /* Process status response ring */
-static int sky2_status_intr(struct sky2_hw *hw, int to_do)
+static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
 {
 	int work_done = 0;
 	unsigned rx[2] = { 0, 0 };
-	u16 hwidx = sky2_read16(hw, STAT_PUT_IDX);
 
 	rmb();
-
-	while (hw->st_idx != hwidx) {
+	do {
 		struct sky2_port *sky2;
 		struct sky2_status_le *le  = hw->st_le + hw->st_idx;
 		unsigned port = le->css & CSS_LINK_BIT;
@@ -2181,12 +2271,12 @@
 			++rx[port];
 			skb = sky2_receive(dev, length, status);
 			if (unlikely(!skb)) {
-				sky2->net_stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 				break;
 			}
 
 			/* This chip reports checksum status differently */
-			if (hw->chip_id == CHIP_ID_YUKON_EX) {
+			if (hw->flags & SKY2_HW_NEW_LE) {
 				if (sky2->rx_csum &&
 				    (le->css & (CSS_ISIPV4 | CSS_ISIPV6)) &&
 				    (le->css & CSS_TCPUDPCSOK))
@@ -2196,8 +2286,8 @@
 			}
 
 			skb->protocol = eth_type_trans(skb, dev);
-			sky2->net_stats.rx_packets++;
-			sky2->net_stats.rx_bytes += skb->len;
+			dev->stats.rx_packets++;
+			dev->stats.rx_bytes += skb->len;
 			dev->last_rx = jiffies;
 
 #ifdef SKY2_VLAN_TAG_USED
@@ -2227,8 +2317,14 @@
 			if (!sky2->rx_csum)
 				break;
 
-			if (hw->chip_id == CHIP_ID_YUKON_EX)
+			/* If this happens then driver assuming wrong format */
+			if (unlikely(hw->flags & SKY2_HW_NEW_LE)) {
+				if (net_ratelimit())
+					printk(KERN_NOTICE "%s: unexpected"
+					       " checksum status\n",
+					       dev->name);
 				break;
+			}
 
 			/* Both checksum counters are programmed to start at
 			 * the same offset, so unless there is a problem they
@@ -2265,7 +2361,7 @@
 				printk(KERN_WARNING PFX
 				       "unknown status opcode 0x%x\n", le->opcode);
 		}
-	}
+	} while (hw->st_idx != idx);
 
 	/* Fully processed status ring so clear irq */
 	sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
@@ -2326,7 +2422,11 @@
 
 static void sky2_hw_intr(struct sky2_hw *hw)
 {
+	struct pci_dev *pdev = hw->pdev;
 	u32 status = sky2_read32(hw, B0_HWE_ISRC);
+	u32 hwmsk = sky2_read32(hw, B0_HWE_IMSK);
+
+	status &= hwmsk;
 
 	if (status & Y2_IS_TIST_OV)
 		sky2_write8(hw, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ);
@@ -2334,38 +2434,24 @@
 	if (status & (Y2_IS_MST_ERR | Y2_IS_IRQ_STAT)) {
 		u16 pci_err;
 
-		pci_err = sky2_pci_read16(hw, PCI_STATUS);
+		pci_read_config_word(pdev, PCI_STATUS, &pci_err);
 		if (net_ratelimit())
-			dev_err(&hw->pdev->dev, "PCI hardware error (0x%x)\n",
+			dev_err(&pdev->dev, "PCI hardware error (0x%x)\n",
 			        pci_err);
 
-		sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
-		sky2_pci_write16(hw, PCI_STATUS,
-				 pci_err | PCI_STATUS_ERROR_BITS);
-		sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+		pci_write_config_word(pdev, PCI_STATUS,
+				      pci_err | PCI_STATUS_ERROR_BITS);
 	}
 
 	if (status & Y2_IS_PCI_EXP) {
 		/* PCI-Express uncorrectable Error occurred */
-		u32 pex_err;
+		int pos = pci_find_aer_capability(hw->pdev);
+		u32 err;
 
-		pex_err = sky2_pci_read32(hw, PEX_UNC_ERR_STAT);
-
+		pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_STATUS, &err);
 		if (net_ratelimit())
-			dev_err(&hw->pdev->dev, "PCI Express error (0x%x)\n",
-				pex_err);
-
-		/* clear the interrupt */
-		sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
-		sky2_pci_write32(hw, PEX_UNC_ERR_STAT,
-				       0xffffffffUL);
-		sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
-
-		if (pex_err & PEX_FATAL_ERRORS) {
-			u32 hwmsk = sky2_read32(hw, B0_HWE_IMSK);
-			hwmsk &= ~Y2_IS_PCI_EXP;
-			sky2_write32(hw, B0_HWE_IMSK, hwmsk);
-		}
+			dev_err(&pdev->dev, "PCI Express error (0x%x)\n", err);
+		pci_cleanup_aer_uncorrect_error_status(pdev);
 	}
 
 	if (status & Y2_HWE_L1_MASK)
@@ -2392,12 +2478,12 @@
 		gma_read16(hw, port, GM_TX_IRQ_SRC);
 
 	if (status & GM_IS_RX_FF_OR) {
-		++sky2->net_stats.rx_fifo_errors;
+		++dev->stats.rx_fifo_errors;
 		sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_CLI_RX_FO);
 	}
 
 	if (status & GM_IS_TX_FF_UR) {
-		++sky2->net_stats.tx_fifo_errors;
+		++dev->stats.tx_fifo_errors;
 		sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_CLI_TX_FU);
 	}
 }
@@ -2420,25 +2506,69 @@
 	sky2_write32(hw, Q_ADDR(q, Q_CSR), BMU_CLR_IRQ_CHK);
 }
 
-/* If idle then force a fake soft NAPI poll once a second
- * to work around cases where sharing an edge triggered interrupt.
- */
-static inline void sky2_idle_start(struct sky2_hw *hw)
+static int sky2_rx_hung(struct net_device *dev)
 {
-	if (idle_timeout > 0)
-		mod_timer(&hw->idle_timer,
-			  jiffies + msecs_to_jiffies(idle_timeout));
+	struct sky2_port *sky2 = netdev_priv(dev);
+	struct sky2_hw *hw = sky2->hw;
+	unsigned port = sky2->port;
+	unsigned rxq = rxqaddr[port];
+	u32 mac_rp = sky2_read32(hw, SK_REG(port, RX_GMF_RP));
+	u8 mac_lev = sky2_read8(hw, SK_REG(port, RX_GMF_RLEV));
+	u8 fifo_rp = sky2_read8(hw, Q_ADDR(rxq, Q_RP));
+	u8 fifo_lev = sky2_read8(hw, Q_ADDR(rxq, Q_RL));
+
+	/* If idle and MAC or PCI is stuck */
+	if (sky2->check.last == dev->last_rx &&
+	    ((mac_rp == sky2->check.mac_rp &&
+	      mac_lev != 0 && mac_lev >= sky2->check.mac_lev) ||
+	     /* Check if the PCI RX hang */
+	     (fifo_rp == sky2->check.fifo_rp &&
+	      fifo_lev != 0 && fifo_lev >= sky2->check.fifo_lev))) {
+		printk(KERN_DEBUG PFX "%s: hung mac %d:%d fifo %d (%d:%d)\n",
+		       dev->name, mac_lev, mac_rp, fifo_lev, fifo_rp,
+		       sky2_read8(hw, Q_ADDR(rxq, Q_WP)));
+		return 1;
+	} else {
+		sky2->check.last = dev->last_rx;
+		sky2->check.mac_rp = mac_rp;
+		sky2->check.mac_lev = mac_lev;
+		sky2->check.fifo_rp = fifo_rp;
+		sky2->check.fifo_lev = fifo_lev;
+		return 0;
+	}
 }
 
-static void sky2_idle(unsigned long arg)
+static void sky2_watchdog(unsigned long arg)
 {
 	struct sky2_hw *hw = (struct sky2_hw *) arg;
-	struct net_device *dev = hw->dev[0];
 
-	if (__netif_rx_schedule_prep(dev))
-		__netif_rx_schedule(dev);
+	/* Check for lost IRQ once a second */
+	if (sky2_read32(hw, B0_ISRC)) {
+		napi_schedule(&hw->napi);
+	} else {
+		int i, active = 0;
 
-	mod_timer(&hw->idle_timer, jiffies + msecs_to_jiffies(idle_timeout));
+		for (i = 0; i < hw->ports; i++) {
+			struct net_device *dev = hw->dev[i];
+			if (!netif_running(dev))
+				continue;
+			++active;
+
+			/* For chips with Rx FIFO, check if stuck */
+			if ((hw->flags & SKY2_HW_FIFO_HANG_CHECK) &&
+			     sky2_rx_hung(dev)) {
+				pr_info(PFX "%s: receiver hang detected\n",
+					dev->name);
+				schedule_work(&hw->restart_work);
+				return;
+			}
+		}
+
+		if (active == 0)
+			return;
+	}
+
+	mod_timer(&hw->watchdog_timer, round_jiffies(jiffies + HZ));
 }
 
 /* Hardware/software error handling */
@@ -2469,11 +2599,12 @@
 		sky2_le_error(hw, 1, Q_XA2, TX_RING_SIZE);
 }
 
-static int sky2_poll(struct net_device *dev0, int *budget)
+static int sky2_poll(struct napi_struct *napi, int work_limit)
 {
-	struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw;
-	int work_done;
+	struct sky2_hw *hw = container_of(napi, struct sky2_hw, napi);
 	u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
+	int work_done = 0;
+	u16 idx;
 
 	if (unlikely(status & Y2_IS_ERROR))
 		sky2_err_intr(hw, status);
@@ -2484,13 +2615,12 @@
 	if (status & Y2_IS_IRQ_PHY2)
 		sky2_phy_intr(hw, 1);
 
-	work_done = sky2_status_intr(hw, min(dev0->quota, *budget));
-	*budget -= work_done;
-	dev0->quota -= work_done;
+	while ((idx = sky2_read16(hw, STAT_PUT_IDX)) != hw->st_idx) {
+		work_done += sky2_status_intr(hw, work_limit - work_done, idx);
 
-	/* More work? */
- 	if (hw->st_idx != sky2_read16(hw, STAT_PUT_IDX))
-		return 1;
+		if (work_done >= work_limit)
+			goto done;
+	}
 
 	/* Bug/Errata workaround?
 	 * Need to kick the TX irq moderation timer.
@@ -2499,16 +2629,16 @@
 		sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP);
 		sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
 	}
-	netif_rx_complete(dev0);
-
+	napi_complete(napi);
 	sky2_read32(hw, B0_Y2_SP_LISR);
-	return 0;
+done:
+
+	return work_done;
 }
 
 static irqreturn_t sky2_intr(int irq, void *dev_id)
 {
 	struct sky2_hw *hw = dev_id;
-	struct net_device *dev0 = hw->dev[0];
 	u32 status;
 
 	/* Reading this mask interrupts as side effect */
@@ -2517,8 +2647,8 @@
 		return IRQ_NONE;
 
 	prefetch(&hw->st_le[hw->st_idx]);
-	if (likely(__netif_rx_schedule_prep(dev0)))
-		__netif_rx_schedule(dev0);
+
+	napi_schedule(&hw->napi);
 
 	return IRQ_HANDLED;
 }
@@ -2527,25 +2657,31 @@
 static void sky2_netpoll(struct net_device *dev)
 {
 	struct sky2_port *sky2 = netdev_priv(dev);
-	struct net_device *dev0 = sky2->hw->dev[0];
 
-	if (netif_running(dev) && __netif_rx_schedule_prep(dev0))
-		__netif_rx_schedule(dev0);
+	napi_schedule(&sky2->hw->napi);
 }
 #endif
 
 /* Chip internal frequency for clock calculations */
-static inline u32 sky2_mhz(const struct sky2_hw *hw)
+static u32 sky2_mhz(const struct sky2_hw *hw)
 {
 	switch (hw->chip_id) {
 	case CHIP_ID_YUKON_EC:
 	case CHIP_ID_YUKON_EC_U:
 	case CHIP_ID_YUKON_EX:
-		return 125;	/* 125 Mhz */
+		return 125;
+
 	case CHIP_ID_YUKON_FE:
-		return 100;	/* 100 Mhz */
-	default:		/* YUKON_XL */
-		return 156;	/* 156 Mhz */
+		return 100;
+
+	case CHIP_ID_YUKON_FE_P:
+		return 50;
+
+	case CHIP_ID_YUKON_XL:
+		return 156;
+
+	default:
+		BUG();
 	}
 }
 
@@ -2562,31 +2698,74 @@
 
 static int __devinit sky2_init(struct sky2_hw *hw)
 {
+	int rc;
 	u8 t8;
 
-	/* Enable all clocks */
-	sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+	/* Enable all clocks and check for bad PCI access */
+	rc = pci_write_config_dword(hw->pdev, PCI_DEV_REG3, 0);
+	if (rc)
+		return rc;
 
 	sky2_write8(hw, B0_CTST, CS_RST_CLR);
 
 	hw->chip_id = sky2_read8(hw, B2_CHIP_ID);
-	if (hw->chip_id < CHIP_ID_YUKON_XL || hw->chip_id > CHIP_ID_YUKON_FE) {
+	hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
+
+	switch(hw->chip_id) {
+	case CHIP_ID_YUKON_XL:
+		hw->flags = SKY2_HW_GIGABIT
+			| SKY2_HW_NEWER_PHY;
+		if (hw->chip_rev < 3)
+			hw->flags |= SKY2_HW_FIFO_HANG_CHECK;
+
+		break;
+
+	case CHIP_ID_YUKON_EC_U:
+		hw->flags = SKY2_HW_GIGABIT
+			| SKY2_HW_NEWER_PHY
+			| SKY2_HW_ADV_POWER_CTL;
+		break;
+
+	case CHIP_ID_YUKON_EX:
+		hw->flags = SKY2_HW_GIGABIT
+			| SKY2_HW_NEWER_PHY
+			| SKY2_HW_NEW_LE
+			| SKY2_HW_ADV_POWER_CTL;
+
+		/* New transmit checksum */
+		if (hw->chip_rev != CHIP_REV_YU_EX_B0)
+			hw->flags |= SKY2_HW_AUTO_TX_SUM;
+		break;
+
+	case CHIP_ID_YUKON_EC:
+		/* This rev is really old, and requires untested workarounds */
+		if (hw->chip_rev == CHIP_REV_YU_EC_A1) {
+			dev_err(&hw->pdev->dev, "unsupported revision Yukon-EC rev A1\n");
+			return -EOPNOTSUPP;
+		}
+		hw->flags = SKY2_HW_GIGABIT | SKY2_HW_FIFO_HANG_CHECK;
+		break;
+
+	case CHIP_ID_YUKON_FE:
+		break;
+
+	case CHIP_ID_YUKON_FE_P:
+		hw->flags = SKY2_HW_NEWER_PHY
+			| SKY2_HW_NEW_LE
+			| SKY2_HW_AUTO_TX_SUM
+			| SKY2_HW_ADV_POWER_CTL;
+		break;
+	default:
 		dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n",
 			hw->chip_id);
 		return -EOPNOTSUPP;
 	}
 
-	hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
-
-	/* This rev is really old, and requires untested workarounds */
-	if (hw->chip_id == CHIP_ID_YUKON_EC && hw->chip_rev == CHIP_REV_YU_EC_A1) {
-		dev_err(&hw->pdev->dev, "unsupported revision Yukon-%s (0x%x) rev %d\n",
-			yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
-			hw->chip_id, hw->chip_rev);
-		return -EOPNOTSUPP;
-	}
-
 	hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
+	if (hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P')
+		hw->flags |= SKY2_HW_FIBRE_PHY;
+
+
 	hw->ports = 1;
 	t8 = sky2_read8(hw, B2_Y2_HW_RES);
 	if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
@@ -2599,8 +2778,10 @@
 
 static void sky2_reset(struct sky2_hw *hw)
 {
+	struct pci_dev *pdev = hw->pdev;
 	u16 status;
-	int i;
+	int i, cap;
+	u32 hwe_mask = Y2_HWE_ALL_MASK;
 
 	/* disable ASF */
 	if (hw->chip_id == CHIP_ID_YUKON_EX) {
@@ -2617,18 +2798,25 @@
 	sky2_write8(hw, B0_CTST, CS_RST_CLR);
 
 	/* clear PCI errors, if any */
-	status = sky2_pci_read16(hw, PCI_STATUS);
-
-	sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
-	sky2_pci_write16(hw, PCI_STATUS, status | PCI_STATUS_ERROR_BITS);
-
+	pci_read_config_word(pdev, PCI_STATUS, &status);
+	status |= PCI_STATUS_ERROR_BITS;
+	pci_write_config_word(pdev, PCI_STATUS, status);
 
 	sky2_write8(hw, B0_CTST, CS_MRST_CLR);
 
-	/* clear any PEX errors */
-	if (pci_find_capability(hw->pdev, PCI_CAP_ID_EXP))
-		sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL);
+	cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+	if (cap) {
+		/* Check for advanced error reporting */
+		pci_cleanup_aer_uncorrect_error_status(pdev);
+		pci_cleanup_aer_correct_error_status(pdev);
 
+		/* If error bit is stuck on ignore it */
+		if (sky2_read32(hw, B0_HWE_ISRC) & Y2_IS_PCI_EXP)
+			dev_info(&pdev->dev, "ignoring stuck error report bit\n");
+
+		else if (pci_enable_pcie_error_reporting(pdev))
+			hwe_mask |= Y2_IS_PCI_EXP;
+	}
 
 	sky2_power_on(hw);
 
@@ -2642,8 +2830,6 @@
 				     | GMC_BYP_RETR_ON);
 	}
 
-	sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
-
 	/* Clear I2C IRQ noise */
 	sky2_write32(hw, B2_I2C_IRQ, 1);
 
@@ -2682,7 +2868,7 @@
 		sky2_write8(hw, RAM_BUFFER(i, B3_RI_RTO_XS2), SK_RI_TO_53);
 	}
 
-	sky2_write32(hw, B0_HWE_IMSK, Y2_HWE_ALL_MASK);
+	sky2_write32(hw, B0_HWE_IMSK, hwe_mask);
 
 	for (i = 0; i < hw->ports; i++)
 		sky2_gmac_reset(hw, i);
@@ -2726,14 +2912,10 @@
 	struct net_device *dev;
 	int i, err;
 
-	del_timer_sync(&hw->idle_timer);
-
 	rtnl_lock();
 	sky2_write32(hw, B0_IMSK, 0);
 	sky2_read32(hw, B0_IMSK);
 
-	netif_poll_disable(hw->dev[0]);
-
 	for (i = 0; i < hw->ports; i++) {
 		dev = hw->dev[i];
 		if (netif_running(dev))
@@ -2742,7 +2924,6 @@
 
 	sky2_reset(hw);
 	sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
-	netif_poll_enable(hw->dev[0]);
 
 	for (i = 0; i < hw->ports; i++) {
 		dev = hw->dev[i];
@@ -2756,8 +2937,6 @@
 		}
 	}
 
-	sky2_idle_start(hw);
-
 	rtnl_unlock();
 }
 
@@ -2784,7 +2963,9 @@
 
 	sky2->wol = wol->wolopts;
 
-	if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX)
+	if (hw->chip_id == CHIP_ID_YUKON_EC_U ||
+	    hw->chip_id == CHIP_ID_YUKON_EX ||
+	    hw->chip_id == CHIP_ID_YUKON_FE_P)
 		sky2_write32(hw, B0_CTST, sky2->wol
 			     ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF);
 
@@ -2802,7 +2983,7 @@
 			| SUPPORTED_100baseT_Full
 			| SUPPORTED_Autoneg | SUPPORTED_TP;
 
-		if (hw->chip_id != CHIP_ID_YUKON_FE)
+		if (hw->flags & SKY2_HW_GIGABIT)
 			modes |= SUPPORTED_1000baseT_Half
 				| SUPPORTED_1000baseT_Full;
 		return modes;
@@ -2822,13 +3003,6 @@
 	ecmd->supported = sky2_supported_modes(hw);
 	ecmd->phy_address = PHY_ADDR_MARV;
 	if (sky2_is_copper(hw)) {
-		ecmd->supported = SUPPORTED_10baseT_Half
-		    | SUPPORTED_10baseT_Full
-		    | SUPPORTED_100baseT_Half
-		    | SUPPORTED_100baseT_Full
-		    | SUPPORTED_1000baseT_Half
-		    | SUPPORTED_1000baseT_Full
-		    | SUPPORTED_Autoneg | SUPPORTED_TP;
 		ecmd->port = PORT_TP;
 		ecmd->speed = sky2->speed;
 	} else {
@@ -2895,8 +3069,10 @@
 	sky2->autoneg = ecmd->autoneg;
 	sky2->advertising = ecmd->advertising;
 
-	if (netif_running(dev))
+	if (netif_running(dev)) {
 		sky2_phy_reinit(sky2);
+		sky2_set_multicast(dev);
+	}
 
 	return 0;
 }
@@ -2989,6 +3165,7 @@
 		return -EINVAL;
 
 	sky2_phy_reinit(sky2);
+	sky2_set_multicast(dev);
 
 	return 0;
 }
@@ -3014,9 +3191,14 @@
 	sky2->msg_enable = value;
 }
 
-static int sky2_get_stats_count(struct net_device *dev)
+static int sky2_get_sset_count(struct net_device *dev, int sset)
 {
-	return ARRAY_SIZE(sky2_stats);
+	switch (sset) {
+	case ETH_SS_STATS:
+		return ARRAY_SIZE(sky2_stats);
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void sky2_get_ethtool_stats(struct net_device *dev,
@@ -3040,12 +3222,6 @@
 	}
 }
 
-static struct net_device_stats *sky2_get_stats(struct net_device *dev)
-{
-	struct sky2_port *sky2 = netdev_priv(dev);
-	return &sky2->net_stats;
-}
-
 static int sky2_set_mac_address(struct net_device *dev, void *p)
 {
 	struct sky2_port *sky2 = netdev_priv(dev);
@@ -3386,20 +3562,64 @@
 {
 	const struct sky2_port *sky2 = netdev_priv(dev);
 	const void __iomem *io = sky2->hw->regs;
+	unsigned int b;
 
 	regs->version = 1;
-	memset(p, 0, regs->len);
 
-	memcpy_fromio(p, io, B3_RAM_ADDR);
+	for (b = 0; b < 128; b++) {
+		/* This complicated switch statement is to make sure and
+		 * only access regions that are unreserved.
+		 * Some blocks are only valid on dual port cards.
+		 * and block 3 has some special diagnostic registers that
+		 * are poison.
+		 */
+		switch (b) {
+		case 3:
+			/* skip diagnostic ram region */
+			memcpy_fromio(p + 0x10, io + 0x10, 128 - 0x10);
+			break;
 
-	/* skip diagnostic ram region */
-	memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1, 0x2000 - B3_RI_WTO_R1);
+		/* dual port cards only */
+		case 5:		/* Tx Arbiter 2 */
+		case 9: 	/* RX2 */
+		case 14 ... 15:	/* TX2 */
+		case 17: case 19: /* Ram Buffer 2 */
+		case 22 ... 23: /* Tx Ram Buffer 2 */
+		case 25: 	/* Rx MAC Fifo 1 */
+		case 27: 	/* Tx MAC Fifo 2 */
+		case 31:	/* GPHY 2 */
+		case 40 ... 47: /* Pattern Ram 2 */
+		case 52: case 54: /* TCP Segmentation 2 */
+		case 112 ... 116: /* GMAC 2 */
+			if (sky2->hw->ports == 1)
+				goto reserved;
+			/* fall through */
+		case 0:		/* Control */
+		case 2:		/* Mac address */
+		case 4:		/* Tx Arbiter 1 */
+		case 7:		/* PCI express reg */
+		case 8:		/* RX1 */
+		case 12 ... 13: /* TX1 */
+		case 16: case 18:/* Rx Ram Buffer 1 */
+		case 20 ... 21: /* Tx Ram Buffer 1 */
+		case 24: 	/* Rx MAC Fifo 1 */
+		case 26: 	/* Tx MAC Fifo 1 */
+		case 28 ... 29: /* Descriptor and status unit */
+		case 30:	/* GPHY 1*/
+		case 32 ... 39: /* Pattern Ram 1 */
+		case 48: case 50: /* TCP Segmentation 1 */
+		case 56 ... 60:	/* PCI space */
+		case 80 ... 84:	/* GMAC 1 */
+			memcpy_fromio(p, io, 128);
+			break;
+		default:
+reserved:
+			memset(p, 0, 128);
+		}
 
-	/* copy GMAC registers */
-	memcpy_fromio(p + BASE_GMAC_1, io + BASE_GMAC_1, 0x1000);
-	if (sky2->hw->ports > 1)
-		memcpy_fromio(p + BASE_GMAC_2, io + BASE_GMAC_2, 0x1000);
-
+		p += 128;
+		io += 128;
+	}
 }
 
 /* In order to do Jumbo packets on these chips, need to turn off the
@@ -3435,26 +3655,31 @@
 	struct sky2_port *sky2 = netdev_priv(dev);
 	u16 reg2;
 
-	reg2 = sky2_pci_read32(sky2->hw, PCI_DEV_REG2);
+	pci_read_config_word(sky2->hw->pdev, PCI_DEV_REG2, &reg2);
 	return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8);
 }
 
-static u32 sky2_vpd_read(struct sky2_hw *hw, int cap, u16 offset)
+static u32 sky2_vpd_read(struct pci_dev *pdev, int cap, u16 offset)
 {
-	sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset);
+	u32 val;
 
-	while (!(sky2_pci_read16(hw, cap + PCI_VPD_ADDR) & PCI_VPD_ADDR_F))
-			cpu_relax();
-	return sky2_pci_read32(hw, cap + PCI_VPD_DATA);
+	pci_write_config_word(pdev, cap + PCI_VPD_ADDR, offset);
+
+	do {
+		pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset);
+	} while (!(offset & PCI_VPD_ADDR_F));
+
+	pci_read_config_dword(pdev, cap + PCI_VPD_DATA, &val);
+	return val;
 }
 
-static void sky2_vpd_write(struct sky2_hw *hw, int cap, u16 offset, u32 val)
+static void sky2_vpd_write(struct pci_dev *pdev, int cap, u16 offset, u32 val)
 {
-	sky2_pci_write32(hw, cap + PCI_VPD_DATA, val);
-	sky2_pci_write16(hw, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F);
+	pci_write_config_word(pdev, cap + PCI_VPD_DATA, val);
+	pci_write_config_dword(pdev, cap + PCI_VPD_ADDR, offset | PCI_VPD_ADDR_F);
 	do {
-		cpu_relax();
-	} while (sky2_pci_read16(hw, cap + PCI_VPD_ADDR) & PCI_VPD_ADDR_F);
+		pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset);
+	} while (offset & PCI_VPD_ADDR_F);
 }
 
 static int sky2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
@@ -3471,7 +3696,7 @@
 	eeprom->magic = SKY2_EEPROM_MAGIC;
 
 	while (length > 0) {
-		u32 val = sky2_vpd_read(sky2->hw, cap, offset);
+		u32 val = sky2_vpd_read(sky2->hw->pdev, cap, offset);
 		int n = min_t(int, length, sizeof(val));
 
 		memcpy(data, &val, n);
@@ -3501,10 +3726,10 @@
 		int n = min_t(int, length, sizeof(val));
 
 		if (n < sizeof(val))
-			val = sky2_vpd_read(sky2->hw, cap, offset);
+			val = sky2_vpd_read(sky2->hw->pdev, cap, offset);
 		memcpy(&val, data, n);
 
-		sky2_vpd_write(sky2->hw, cap, offset, val);
+		sky2_vpd_write(sky2->hw->pdev, cap, offset, val);
 
 		length -= n;
 		data += n;
@@ -3529,11 +3754,8 @@
 	.get_eeprom_len	= sky2_get_eeprom_len,
 	.get_eeprom	= sky2_get_eeprom,
 	.set_eeprom	= sky2_set_eeprom,
-	.get_sg 	= ethtool_op_get_sg,
 	.set_sg 	= ethtool_op_set_sg,
-	.get_tx_csum	= ethtool_op_get_tx_csum,
 	.set_tx_csum	= sky2_set_tx_csum,
-	.get_tso	= ethtool_op_get_tso,
 	.set_tso	= sky2_set_tso,
 	.get_rx_csum	= sky2_get_rx_csum,
 	.set_rx_csum	= sky2_set_rx_csum,
@@ -3545,9 +3767,8 @@
 	.get_pauseparam = sky2_get_pauseparam,
 	.set_pauseparam = sky2_set_pauseparam,
 	.phys_id	= sky2_phys_id,
-	.get_stats_count = sky2_get_stats_count,
+	.get_sset_count = sky2_get_sset_count,
 	.get_ethtool_stats = sky2_get_ethtool_stats,
-	.get_perm_addr	= ethtool_op_get_perm_addr,
 };
 
 #ifdef CONFIG_SKY2_DEBUG
@@ -3558,7 +3779,7 @@
 {
 	struct net_device *dev = seq->private;
 	const struct sky2_port *sky2 = netdev_priv(dev);
-	const struct sky2_hw *hw = sky2->hw;
+	struct sky2_hw *hw = sky2->hw;
 	unsigned port = sky2->port;
 	unsigned idx, last;
 	int sop;
@@ -3571,7 +3792,7 @@
 		   sky2_read32(hw, B0_IMSK),
 		   sky2_read32(hw, B0_Y2_SP_ICR));
 
-	netif_poll_disable(hw->dev[0]);
+	napi_disable(&hw->napi);
 	last = sky2_read16(hw, STAT_PUT_IDX);
 
 	if (hw->st_idx == last)
@@ -3641,7 +3862,7 @@
 		   last = sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_PUT_IDX)),
 		   sky2_read16(hw, Y2_QADDR(rxqaddr[port], PREF_UNIT_LAST_IDX)));
 
-	netif_poll_enable(hw->dev[0]);
+	napi_enable(&hw->napi);
 	return 0;
 }
 
@@ -3666,42 +3887,34 @@
 			     unsigned long event, void *ptr)
 {
 	struct net_device *dev = ptr;
+	struct sky2_port *sky2 = netdev_priv(dev);
 
-	if (dev->open == sky2_up) {
-		struct sky2_port *sky2 = netdev_priv(dev);
+	if (dev->open != sky2_up || !sky2_debug)
+		return NOTIFY_DONE;
 
-		switch(event) {
-		case NETDEV_CHANGENAME:
-			if (!netif_running(dev))
-				break;
-			/* fallthrough */
-		case NETDEV_DOWN:
-		case NETDEV_GOING_DOWN:
-			if (sky2->debugfs) {
-				printk(KERN_DEBUG PFX "%s: remove debugfs\n",
-				       dev->name);
-				debugfs_remove(sky2->debugfs);
-				sky2->debugfs = NULL;
-			}
-
-			if (event != NETDEV_CHANGENAME)
-				break;
-			/* fallthrough for changename */
-		case NETDEV_UP:
-			if (sky2_debug) {
-				struct dentry *d;
-				d = debugfs_create_file(dev->name, S_IRUGO,
-							sky2_debug, dev,
-							&sky2_debug_fops);
-				if (d == NULL || IS_ERR(d))
-					printk(KERN_INFO PFX
-					       "%s: debugfs create failed\n",
-					       dev->name);
-				else
-					sky2->debugfs = d;
-			}
-			break;
+	switch(event) {
+	case NETDEV_CHANGENAME:
+		if (sky2->debugfs) {
+			sky2->debugfs = debugfs_rename(sky2_debug, sky2->debugfs,
+						       sky2_debug, dev->name);
 		}
+		break;
+
+	case NETDEV_GOING_DOWN:
+		if (sky2->debugfs) {
+			printk(KERN_DEBUG PFX "%s: remove debugfs\n",
+			       dev->name);
+			debugfs_remove(sky2->debugfs);
+			sky2->debugfs = NULL;
+		}
+		break;
+
+	case NETDEV_UP:
+		sky2->debugfs = debugfs_create_file(dev->name, S_IRUGO,
+						    sky2_debug, dev,
+						    &sky2_debug_fops);
+		if (IS_ERR(sky2->debugfs))
+			sky2->debugfs = NULL;
 	}
 
 	return NOTIFY_DONE;
@@ -3752,29 +3965,20 @@
 		return NULL;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &hw->pdev->dev);
 	dev->irq = hw->pdev->irq;
 	dev->open = sky2_up;
 	dev->stop = sky2_down;
 	dev->do_ioctl = sky2_ioctl;
 	dev->hard_start_xmit = sky2_xmit_frame;
-	dev->get_stats = sky2_get_stats;
 	dev->set_multicast_list = sky2_set_multicast;
 	dev->set_mac_address = sky2_set_mac_address;
 	dev->change_mtu = sky2_change_mtu;
 	SET_ETHTOOL_OPS(dev, &sky2_ethtool_ops);
 	dev->tx_timeout = sky2_tx_timeout;
 	dev->watchdog_timeo = TX_WATCHDOG;
-	if (port == 0)
-		dev->poll = sky2_poll;
-	dev->weight = NAPI_WEIGHT;
 #ifdef CONFIG_NET_POLL_CONTROLLER
-	/* Network console (only works on port 0)
-	 * because netpoll makes assumptions about NAPI
-	 */
-	if (port == 0)
-		dev->poll_controller = sky2_netpoll;
+	dev->poll_controller = sky2_netpoll;
 #endif
 
 	sky2 = netdev_priv(dev);
@@ -3805,8 +4009,12 @@
 		dev->features |= NETIF_F_HIGHDMA;
 
 #ifdef SKY2_VLAN_TAG_USED
-	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-	dev->vlan_rx_register = sky2_vlan_rx_register;
+	/* The workaround for FE+ status conflicts with VLAN tag detection. */
+	if (!(sky2->hw->chip_id == CHIP_ID_YUKON_FE_P &&
+	      sky2->hw->chip_rev == CHIP_REV_YU_FE2_A0)) {
+		dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+		dev->vlan_rx_register = sky2_vlan_rx_register;
+	}
 #endif
 
 	/* read the mac address */
@@ -3819,12 +4027,11 @@
 static void __devinit sky2_show_addr(struct net_device *dev)
 {
 	const struct sky2_port *sky2 = netdev_priv(dev);
+	DECLARE_MAC_BUF(mac);
 
 	if (netif_msg_probe(sky2))
-		printk(KERN_INFO PFX "%s: addr %02x:%02x:%02x:%02x:%02x:%02x\n",
-		       dev->name,
-		       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-		       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+		printk(KERN_INFO PFX "%s: addr %s\n",
+		       dev->name, print_mac(mac, dev->dev_addr));
 }
 
 /* Handle software interrupt used during MSI test */
@@ -3837,7 +4044,7 @@
 		return IRQ_NONE;
 
 	if (status & Y2_IS_IRQ_SW) {
-		hw->msi = 1;
+		hw->flags |= SKY2_HW_USE_MSI;
 		wake_up(&hw->msi_wait);
 		sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ);
 	}
@@ -3865,9 +4072,9 @@
 	sky2_write8(hw, B0_CTST, CS_ST_SW_IRQ);
 	sky2_read8(hw, B0_CTST);
 
-	wait_event_timeout(hw->msi_wait, hw->msi, HZ/10);
+	wait_event_timeout(hw->msi_wait, (hw->flags & SKY2_HW_USE_MSI), HZ/10);
 
-	if (!hw->msi) {
+	if (!(hw->flags & SKY2_HW_USE_MSI)) {
 		/* MSI test failed, go back to INTx mode */
 		dev_info(&pdev->dev, "No interrupt generated using MSI, "
 			 "switching to INTx mode.\n");
@@ -3957,15 +4164,14 @@
 	 */
 	{
 		u32 reg;
-		reg = sky2_pci_read32(hw, PCI_DEV_REG2);
+		pci_read_config_dword(pdev,PCI_DEV_REG2, &reg);
 		reg &= ~PCI_REV_DESC;
-		sky2_pci_write32(hw, PCI_DEV_REG2, reg);
+		pci_write_config_dword(pdev, PCI_DEV_REG2, reg);
 	}
 #endif
 
 	/* ring for status responses */
-	hw->st_le = pci_alloc_consistent(hw->pdev, STATUS_LE_BYTES,
-					 &hw->st_dma);
+	hw->st_le = pci_alloc_consistent(pdev, STATUS_LE_BYTES, &hw->st_dma);
 	if (!hw->st_le)
 		goto err_out_iounmap;
 
@@ -3985,6 +4191,7 @@
 		err = -ENOMEM;
 		goto err_out_free_pci;
 	}
+	netif_napi_add(dev, &hw->napi, sky2_poll, NAPI_WEIGHT);
 
 	if (!disable_msi && pci_enable_msi(pdev) == 0) {
 		err = sky2_test_msi(hw);
@@ -4000,7 +4207,8 @@
 		goto err_out_free_netdev;
 	}
 
-	err = request_irq(pdev->irq,  sky2_intr, hw->msi ? 0 : IRQF_SHARED,
+	err = request_irq(pdev->irq, sky2_intr,
+			  (hw->flags & SKY2_HW_USE_MSI) ? 0 : IRQF_SHARED,
 			  dev->name, hw);
 	if (err) {
 		dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq);
@@ -4025,24 +4233,22 @@
 			sky2_show_addr(dev1);
 	}
 
-	setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw);
+	setup_timer(&hw->watchdog_timer, sky2_watchdog, (unsigned long) hw);
 	INIT_WORK(&hw->restart_work, sky2_restart);
 
-	sky2_idle_start(hw);
-
 	pci_set_drvdata(pdev, hw);
 
 	return 0;
 
 err_out_unregister:
-	if (hw->msi)
+	if (hw->flags & SKY2_HW_USE_MSI)
 		pci_disable_msi(pdev);
 	unregister_netdev(dev);
 err_out_free_netdev:
 	free_netdev(dev);
 err_out_free_pci:
 	sky2_write8(hw, B0_CTST, CS_RST_SET);
-	pci_free_consistent(hw->pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma);
+	pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma);
 err_out_iounmap:
 	iounmap(hw->regs);
 err_out_free_hw:
@@ -4064,7 +4270,7 @@
 	if (!hw)
 		return;
 
-	del_timer_sync(&hw->idle_timer);
+	del_timer_sync(&hw->watchdog_timer);
 
 	flush_scheduled_work();
 
@@ -4084,7 +4290,7 @@
 	sky2_read8(hw, B0_CTST);
 
 	free_irq(pdev->irq, hw);
-	if (hw->msi)
+	if (hw->flags & SKY2_HW_USE_MSI)
 		pci_disable_msi(pdev);
 	pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma);
 	pci_release_regions(pdev);
@@ -4108,9 +4314,6 @@
 	if (!hw)
 		return 0;
 
-	del_timer_sync(&hw->idle_timer);
-	netif_poll_disable(hw->dev[0]);
-
 	for (i = 0; i < hw->ports; i++) {
 		struct net_device *dev = hw->dev[i];
 		struct sky2_port *sky2 = netdev_priv(dev);
@@ -4153,8 +4356,10 @@
 	pci_enable_wake(pdev, PCI_D0, 0);
 
 	/* Re-enable all clocks */
-	if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U)
-		sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+	if (hw->chip_id == CHIP_ID_YUKON_EX ||
+	    hw->chip_id == CHIP_ID_YUKON_EC_U ||
+	    hw->chip_id == CHIP_ID_YUKON_FE_P)
+		pci_write_config_dword(pdev, PCI_DEV_REG3, 0);
 
 	sky2_reset(hw);
 
@@ -4170,11 +4375,11 @@
 				dev_close(dev);
 				goto out;
 			}
+
+			sky2_set_multicast(dev);
 		}
 	}
 
-	netif_poll_enable(hw->dev[0]);
-	sky2_idle_start(hw);
 	return 0;
 out:
 	dev_err(&pdev->dev, "resume failed (%d)\n", err);
@@ -4191,8 +4396,7 @@
 	if (!hw)
 		return;
 
-	del_timer_sync(&hw->idle_timer);
-	netif_poll_disable(hw->dev[0]);
+	napi_disable(&hw->napi);
 
 	for (i = 0; i < hw->ports; i++) {
 		struct net_device *dev = hw->dev[i];
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index dce4d27..49ee264 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -18,14 +18,6 @@
 	PCI_CFG_REG_1	= 0x94,
 };
 
-enum {
-	PEX_DEV_CAP	= 0xe4,
-	PEX_DEV_CTRL	= 0xe8,
-	PEX_DEV_STA	= 0xea,
-	PEX_LNK_STAT	= 0xf2,
-	PEX_UNC_ERR_STAT= 0x104,
-};
-
 /* Yukon-2 */
 enum pci_dev_reg_1 {
 	PCI_Y2_PIG_ENA	 = 1<<31, /* Enable Plug-in-Go (YUKON-2) */
@@ -151,38 +143,6 @@
 			       PCI_STATUS_REC_TARGET_ABORT | \
 			       PCI_STATUS_PARITY)
 
-enum pex_dev_ctrl {
-	PEX_DC_MAX_RRS_MSK	= 7<<12, /* Bit 14..12:	Max. Read Request Size */
-	PEX_DC_EN_NO_SNOOP	= 1<<11,/* Enable No Snoop */
-	PEX_DC_EN_AUX_POW	= 1<<10,/* Enable AUX Power */
-	PEX_DC_EN_PHANTOM	= 1<<9,	/* Enable Phantom Functions */
-	PEX_DC_EN_EXT_TAG	= 1<<8,	/* Enable Extended Tag Field */
-	PEX_DC_MAX_PLS_MSK	= 7<<5,	/* Bit  7.. 5:	Max. Payload Size Mask */
-	PEX_DC_EN_REL_ORD	= 1<<4,	/* Enable Relaxed Ordering */
-	PEX_DC_EN_UNS_RQ_RP	= 1<<3,	/* Enable Unsupported Request Reporting */
-	PEX_DC_EN_FAT_ER_RP	= 1<<2,	/* Enable Fatal Error Reporting */
-	PEX_DC_EN_NFA_ER_RP	= 1<<1,	/* Enable Non-Fatal Error Reporting */
-	PEX_DC_EN_COR_ER_RP	= 1<<0,	/* Enable Correctable Error Reporting */
-};
-#define  PEX_DC_MAX_RD_RQ_SIZE(x) (((x)<<12) & PEX_DC_MAX_RRS_MSK)
-
-/* PEX_UNC_ERR_STAT	 PEX Uncorrectable Errors Status Register (Yukon-2) */
-enum pex_err {
-	PEX_UNSUP_REQ 	= 1<<20, /* Unsupported Request Error */
-
-	PEX_MALFOR_TLP	= 1<<18, /* Malformed TLP */
-
-	PEX_UNEXP_COMP	= 1<<16, /* Unexpected Completion */
-
-	PEX_COMP_TO	= 1<<14, /* Completion Timeout */
-	PEX_FLOW_CTRL_P	= 1<<13, /* Flow Control Protocol Error */
-	PEX_POIS_TLP	= 1<<12, /* Poisoned TLP */
-
-	PEX_DATA_LINK_P = 1<<4,	/* Data Link Protocol Error */
-	PEX_FATAL_ERRORS= (PEX_MALFOR_TLP | PEX_FLOW_CTRL_P | PEX_DATA_LINK_P),
-};
-
-
 enum csr_regs {
 	B0_RAP		= 0x0000,
 	B0_CTST		= 0x0004,
@@ -419,7 +379,6 @@
 			  Y2_IS_PAR_RX2 | Y2_IS_TCP_TXS2| Y2_IS_TCP_TXA2,
 
 	Y2_HWE_ALL_MASK	= Y2_IS_TIST_OV | Y2_IS_MST_ERR | Y2_IS_IRQ_STAT |
-			  Y2_IS_PCI_EXP |
 			  Y2_HWE_L1_MASK | Y2_HWE_L2_MASK,
 };
 
@@ -470,18 +429,24 @@
 	CHIP_ID_YUKON_EX   = 0xb5, /* Chip ID for YUKON-2 Extreme */
 	CHIP_ID_YUKON_EC   = 0xb6, /* Chip ID for YUKON-2 EC */
  	CHIP_ID_YUKON_FE   = 0xb7, /* Chip ID for YUKON-2 FE */
-
+ 	CHIP_ID_YUKON_FE_P = 0xb8, /* Chip ID for YUKON-2 FE+ */
+};
+enum yukon_ec_rev {
 	CHIP_REV_YU_EC_A1    = 0,  /* Chip Rev. for Yukon-EC A1/A0 */
 	CHIP_REV_YU_EC_A2    = 1,  /* Chip Rev. for Yukon-EC A2 */
 	CHIP_REV_YU_EC_A3    = 2,  /* Chip Rev. for Yukon-EC A3 */
-
+};
+enum yukon_ec_u_rev {
 	CHIP_REV_YU_EC_U_A0  = 1,
 	CHIP_REV_YU_EC_U_A1  = 2,
 	CHIP_REV_YU_EC_U_B0  = 3,
-
+};
+enum yukon_fe_rev {
 	CHIP_REV_YU_FE_A1    = 1,
 	CHIP_REV_YU_FE_A2    = 2,
-
+};
+enum yukon_fe_p_rev {
+	CHIP_REV_YU_FE2_A0   = 0,
 };
 enum yukon_ex_rev {
 	CHIP_REV_YU_EX_A0    = 1,
@@ -1668,7 +1633,7 @@
 
 /* Receive Frame Status Encoding */
 enum {
-	GMR_FS_LEN	= 0xffff<<16, /* Bit 31..16:	Rx Frame Length */
+	GMR_FS_LEN	= 0x7fff<<16, /* Bit 30..16:	Rx Frame Length */
 	GMR_FS_VLAN	= 1<<13, /* VLAN Packet */
 	GMR_FS_JABBER	= 1<<12, /* Jabber Packet */
 	GMR_FS_UN_SIZE	= 1<<11, /* Undersize Packet */
@@ -1729,6 +1694,10 @@
 	GMF_RX_CTRL_DEF	= GMF_OPER_ON | GMF_RX_F_FL_ON,
 };
 
+/*	TX_GMF_EA		32 bit	Tx GMAC FIFO End Address */
+enum {
+	TX_DYN_WM_ENA	= 3,	/* Yukon-FE+ specific */
+};
 
 /*	TX_GMF_CTRL_T	32 bit	Tx GMAC FIFO Control/Test */
 enum {
@@ -1840,6 +1809,28 @@
 
 /*	GPHY_CTRL		32 bit	GPHY Control Reg (YUKON only) */
 enum {
+	GPC_TX_PAUSE	= 1<<30, /* Tx pause enabled (ro) */
+	GPC_RX_PAUSE	= 1<<29, /* Rx pause enabled (ro) */
+	GPC_SPEED	= 3<<27, /* PHY speed (ro) */
+	GPC_LINK	= 1<<26, /* Link up (ro) */
+	GPC_DUPLEX	= 1<<25, /* Duplex (ro) */
+	GPC_CLOCK	= 1<<24, /* 125Mhz clock stable (ro) */
+
+	GPC_PDOWN	= 1<<23, /* Internal regulator 2.5 power down */
+	GPC_TSTMODE	= 1<<22, /* Test mode */
+	GPC_REG18	= 1<<21, /* Reg18 Power down */
+	GPC_REG12SEL	= 3<<19, /* Reg12 power setting */
+	GPC_REG18SEL	= 3<<17, /* Reg18 power setting */
+	GPC_SPILOCK	= 1<<16, /* SPI lock (ASF) */
+
+	GPC_LEDMUX	= 3<<14, /* LED Mux */
+	GPC_INTPOL	= 1<<13, /* Interrupt polarity */
+	GPC_DETECT	= 1<<12, /* Energy detect */
+	GPC_1000HD	= 1<<11, /* Enable 1000Mbit HD */
+	GPC_SLAVE	= 1<<10, /* Slave mode */
+	GPC_PAUSE	= 1<<9, /* Pause enable */
+	GPC_LEDCTL	= 3<<6, /* GPHY Leds */
+
 	GPC_RST_CLR	= 1<<1,	/* Clear GPHY Reset */
 	GPC_RST_SET	= 1<<0,	/* Set   GPHY Reset */
 };
@@ -2017,6 +2008,14 @@
 	u16		     rx_tag;
 	struct vlan_group    *vlgrp;
 #endif
+	struct {
+		unsigned long last;
+		u32	mac_rp;
+		u8	mac_lev;
+		u8	fifo_rp;
+		u8	fifo_lev;
+	} check;
+
 
 	dma_addr_t	     rx_le_map;
 	dma_addr_t	     tx_le_map;
@@ -2032,14 +2031,22 @@
 #ifdef CONFIG_SKY2_DEBUG
 	struct dentry	     *debugfs;
 #endif
-	struct net_device_stats net_stats;
-
 };
 
 struct sky2_hw {
 	void __iomem  	     *regs;
 	struct pci_dev	     *pdev;
+	struct napi_struct   napi;
 	struct net_device    *dev[2];
+	unsigned long	     flags;
+#define SKY2_HW_USE_MSI		0x00000001
+#define SKY2_HW_FIBRE_PHY	0x00000002
+#define SKY2_HW_GIGABIT		0x00000004
+#define SKY2_HW_NEWER_PHY	0x00000008
+#define SKY2_HW_FIFO_HANG_CHECK	0x00000010
+#define SKY2_HW_NEW_LE		0x00000020	/* new LSOv2 format */
+#define SKY2_HW_AUTO_TX_SUM	0x00000040	/* new IP decode for Tx */
+#define SKY2_HW_ADV_POWER_CTL	0x00000080	/* additional PHY power regs */
 
 	u8	     	     chip_id;
 	u8		     chip_rev;
@@ -2050,15 +2057,14 @@
 	u32		     st_idx;
 	dma_addr_t   	     st_dma;
 
-	struct timer_list    idle_timer;
+	struct timer_list    watchdog_timer;
 	struct work_struct   restart_work;
-	int		     msi;
 	wait_queue_head_t    msi_wait;
 };
 
 static inline int sky2_is_copper(const struct sky2_hw *hw)
 {
-	return !(hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P');
+	return !(hw->flags & SKY2_HW_FIBRE_PHY);
 }
 
 /* Register accessor for memory mapped device */
@@ -2121,25 +2127,4 @@
 	gma_write16(hw, port, reg+4,(u16) addr[2] | ((u16) addr[3] << 8));
 	gma_write16(hw, port, reg+8,(u16) addr[4] | ((u16) addr[5] << 8));
 }
-
-/* PCI config space access */
-static inline u32 sky2_pci_read32(const struct sky2_hw *hw, unsigned reg)
-{
-	return sky2_read32(hw, Y2_CFG_SPC + reg);
-}
-
-static inline u16 sky2_pci_read16(const struct sky2_hw *hw, unsigned reg)
-{
-	return sky2_read16(hw, Y2_CFG_SPC + reg);
-}
-
-static inline void sky2_pci_write32(struct sky2_hw *hw, unsigned reg, u32 val)
-{
-	sky2_write32(hw, Y2_CFG_SPC + reg, val);
-}
-
-static inline void sky2_pci_write16(struct sky2_hw *hw, unsigned reg, u16 val)
-{
-	sky2_write16(hw, Y2_CFG_SPC + reg, val);
-}
 #endif
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 65bd20f..335b7cc 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -639,8 +639,6 @@
 	dev->addr_len		= 0;
 	dev->tx_queue_len	= 10;
 
-	SET_MODULE_OWNER(dev);
-
 	/* New-style flags. */
 	dev->flags		= IFF_NOARP|IFF_POINTOPOINT|IFF_MULTICAST;
 }
@@ -957,7 +955,7 @@
   *			STANDARD SLIP ENCAPSULATION		  	 *
   ************************************************************************/
 
-int
+static int
 slip_esc(unsigned char *s, unsigned char *d, int len)
 {
 	unsigned char *ptr = d;
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index ae1ae34..d6abb68 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -196,6 +196,7 @@
 	int tirq = 0;
 	int base_addr = ultra_io[ultra_found];
 	int irq = ultra_irq[ultra_found];
+	DECLARE_MAC_BUF(mac);
 
 	if (base_addr || irq) {
 		printk(KERN_INFO "Probing for SMC MCA adapter");
@@ -264,7 +265,6 @@
 	if(!dev)
 		return -ENODEV;
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, gen_dev);
 	mca_device_set_name(mca_dev, smc_mca_adapter_names[adapter]);
 	mca_device_set_claim(mca_dev, 1);
@@ -331,10 +331,11 @@
 	reg4 = inb(ioaddr + 4) & 0x7f;
 	outb(reg4, ioaddr + 4);
 
-	printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x,", slot + 1, ioaddr);
-
 	for (i = 0; i < 6; i++)
-		printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
+		dev->dev_addr[i] = inb(ioaddr + 8 + i);
+
+	printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x, %s",
+	       slot + 1, ioaddr, print_mac(mac, dev->dev_addr));
 
 	/* Switch from the station address to the alternate register set
 	 * and read the useful registers there.
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index a52b22d..00d6cf1 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -142,8 +142,6 @@
 	int base_addr = dev->base_addr;
 	int irq = dev->irq;
 
-	SET_MODULE_OWNER(dev);
-
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = &ultra_poll;
 #endif
@@ -200,6 +198,7 @@
 	unsigned char num_pages, irqreg, addr, piomode;
 	unsigned char idreg = inb(ioaddr + 7);
 	unsigned char reg4 = inb(ioaddr + 4) & 0x7f;
+	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, ULTRA_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -226,10 +225,11 @@
 
 	model_name = (idreg & 0xF0) == 0x20 ? "SMC Ultra" : "SMC EtherEZ";
 
-	printk("%s: %s at %#3x,", dev->name, model_name, ioaddr);
-
 	for (i = 0; i < 6; i++)
-		printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
+		dev->dev_addr[i] = inb(ioaddr + 8 + i);
+
+	printk("%s: %s at %#3x, %s", dev->name, model_name,
+	       ioaddr, print_mac(mac, dev->dev_addr));
 
 	/* Switch from the station address to the alternate register set and
 	   read the useful registers there. */
diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
index 88a30e5..a5a91ac 100644
--- a/drivers/net/smc-ultra32.c
+++ b/drivers/net/smc-ultra32.c
@@ -132,8 +132,6 @@
 		netdev_boot_setup_check(dev);
 	}
 
-	SET_MODULE_OWNER(dev);
-
 	irq = dev->irq;
 
 	/* EISA spec allows for up to 16 slots, but 8 is typical. */
@@ -165,6 +163,7 @@
 	unsigned char idreg;
 	unsigned char reg4;
 	const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"};
+	DECLARE_MAC_BUF(mac);
 
 	if (!request_region(ioaddr, ULTRA32_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -205,10 +204,11 @@
 
 	model_name = "SMC Ultra32";
 
-	printk("%s: %s at 0x%X,", dev->name, model_name, ioaddr);
-
 	for (i = 0; i < 6; i++)
-		printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
+		dev->dev_addr[i] = inb(ioaddr + 8 + i);
+
+	printk("%s: %s at 0x%X, %s",
+	       dev->name, model_name, ioaddr, print_mac(mac, dev->dev_addr));
 
 	/* Switch from the station address to the alternate register set and
 	   read the useful registers there. */
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index db43e42..7c60df4 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -115,13 +115,6 @@
 	 */
 	struct sk_buff *pending_tx_skb;
 
-	/*
-	 * these are things that the kernel wants me to keep, so users
-	 * can find out semi-useless statistics of how well the card is
-	 * performing
-	 */
-	struct net_device_stats stats;
-
 	/* version/revision of the SMC911x chip */
 	u16 version;
 	u16 revision;
@@ -315,8 +308,8 @@
 	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++;
+		dev->stats.tx_errors++;
+		dev->stats.tx_aborted_errors++;
 	}
 }
 
@@ -449,14 +442,14 @@
 	pkt_len = (status & RX_STS_PKT_LEN_) >> 16;
 	if (status & RX_STS_ES_) {
 		/* Deal with a bad packet */
-		lp->stats.rx_errors++;
+		dev->stats.rx_errors++;
 		if (status & RX_STS_CRC_ERR_)
-			lp->stats.rx_crc_errors++;
+			dev->stats.rx_crc_errors++;
 		else {
 			if (status & RX_STS_LEN_ERR_)
-				lp->stats.rx_length_errors++;
+				dev->stats.rx_length_errors++;
 			if (status & RX_STS_MCAST_)
-				lp->stats.multicast++;
+				dev->stats.multicast++;
 		}
 		/* Remove the bad packet data from the RX FIFO */
 		smc911x_drop_pkt(dev);
@@ -467,7 +460,7 @@
 		if (unlikely(skb == NULL)) {
 			PRINTK( "%s: Low memory, rcvd packet dropped.\n",
 				dev->name);
-			lp->stats.rx_dropped++;
+			dev->stats.rx_dropped++;
 			smc911x_drop_pkt(dev);
 			return;
 		}
@@ -503,8 +496,8 @@
 		dev->last_rx = jiffies;
 		skb->protocol = eth_type_trans(skb, dev);
 		netif_rx(skb);
-		lp->stats.rx_packets++;
-		lp->stats.rx_bytes += pkt_len-4;
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += pkt_len-4;
 #endif
 	}
 }
@@ -616,8 +609,8 @@
 		printk("%s: No Tx free space %d < %d\n",
 			dev->name, free, skb->len);
 		lp->pending_tx_skb = NULL;
-		lp->stats.tx_errors++;
-		lp->stats.tx_dropped++;
+		dev->stats.tx_errors++;
+		dev->stats.tx_dropped++;
 		dev_kfree_skb(skb);
 		return 0;
 	}
@@ -667,8 +660,8 @@
 			dev->name,
 			(SMC_GET_TX_FIFO_INF() & TX_FIFO_INF_TSUSED_) >> 16);
 		tx_status = SMC_GET_TX_STS_FIFO();
-		lp->stats.tx_packets++;
-		lp->stats.tx_bytes+=tx_status>>16;
+		dev->stats.tx_packets++;
+		dev->stats.tx_bytes+=tx_status>>16;
 		DBG(SMC_DEBUG_TX, "%s: Tx FIFO tag 0x%04x status 0x%04x\n",
 			dev->name, (tx_status & 0xffff0000) >> 16,
 			tx_status & 0x0000ffff);
@@ -676,22 +669,22 @@
 		 * full-duplex mode */
 		if ((tx_status & TX_STS_ES_) && !(lp->ctl_rfduplx &&
 		    !(tx_status & 0x00000306))) {
-			lp->stats.tx_errors++;
+			dev->stats.tx_errors++;
 		}
 		if (tx_status & TX_STS_MANY_COLL_) {
-			lp->stats.collisions+=16;
-			lp->stats.tx_aborted_errors++;
+			dev->stats.collisions+=16;
+			dev->stats.tx_aborted_errors++;
 		} else {
-			lp->stats.collisions+=(tx_status & TX_STS_COLL_CNT_) >> 3;
+			dev->stats.collisions+=(tx_status & TX_STS_COLL_CNT_) >> 3;
 		}
 		/* carrier error only has meaning for half-duplex communication */
 		if ((tx_status & (TX_STS_LOC_ | TX_STS_NO_CARR_)) &&
 		    !lp->ctl_rfduplx) {
-			lp->stats.tx_carrier_errors++;
+			dev->stats.tx_carrier_errors++;
 		}
 		if (tx_status & TX_STS_LATE_COLL_) {
-			lp->stats.collisions++;
-			lp->stats.tx_aborted_errors++;
+			dev->stats.collisions++;
+			dev->stats.tx_aborted_errors++;
 		}
 	}
 }
@@ -1121,11 +1114,11 @@
 		/* Handle various error conditions */
 		if (status & INT_STS_RXE_) {
 			SMC_ACK_INT(INT_STS_RXE_);
-			lp->stats.rx_errors++;
+			dev->stats.rx_errors++;
 		}
 		if (status & INT_STS_RXDFH_INT_) {
 			SMC_ACK_INT(INT_STS_RXDFH_INT_);
-			lp->stats.rx_dropped+=SMC_GET_RX_DROP();
+			dev->stats.rx_dropped+=SMC_GET_RX_DROP();
 		 }
 		/* Undocumented interrupt-what is the right thing to do here? */
 		if (status & INT_STS_RXDF_INT_) {
@@ -1140,8 +1133,8 @@
 				cr &= ~MAC_CR_RXEN_;
 				SMC_SET_MAC_CR(cr);
 				DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name);
-				lp->stats.rx_errors++;
-				lp->stats.rx_fifo_errors++;
+				dev->stats.rx_errors++;
+				dev->stats.rx_fifo_errors++;
 			}
 			SMC_ACK_INT(INT_STS_RDFL_);
 		}
@@ -1152,8 +1145,8 @@
 				SMC_SET_MAC_CR(cr);
 				rx_overrun=1;
 				DBG(SMC_DEBUG_RX, "%s: RX overrun\n", dev->name);
-				lp->stats.rx_errors++;
-				lp->stats.rx_fifo_errors++;
+				dev->stats.rx_errors++;
+				dev->stats.rx_fifo_errors++;
 			}
 			SMC_ACK_INT(INT_STS_RDFO_);
 		}
@@ -1307,8 +1300,8 @@
 	dev->last_rx = jiffies;
 	skb->protocol = eth_type_trans(skb, dev);
 	netif_rx(skb);
-	lp->stats.rx_packets++;
-	lp->stats.rx_bytes += skb->len;
+	dev->stats.rx_packets++;
+	dev->stats.rx_bytes += skb->len;
 
 	spin_lock_irqsave(&lp->lock, flags);
 	pkts = (SMC_GET_RX_FIFO_INF() & RX_FIFO_INF_RXSUSED_) >> 16;
@@ -1568,19 +1561,6 @@
 }
 
 /*
- * Get the current statistics.
- * This may be called with the card open or closed.
- */
-static struct net_device_stats *smc911x_query_statistics(struct net_device *dev)
-{
-	struct smc911x_local *lp = netdev_priv(dev);
-	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __FUNCTION__);
-
-
-	return &lp->stats;
-}
-
-/*
  * Ethtool support
  */
 static int
@@ -2056,7 +2036,6 @@
 	dev->hard_start_xmit = smc911x_hard_start_xmit;
 	dev->tx_timeout = smc911x_timeout;
 	dev->watchdog_timeo = msecs_to_jiffies(watchdog);
-	dev->get_stats = smc911x_query_statistics;
 	dev->set_multicast_list = smc911x_set_multicast_list;
 	dev->ethtool_ops = &smc911x_ethtool_ops;
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2084,7 +2063,7 @@
 
 	/* Grab the IRQ */
 	retval = request_irq(dev->irq, &smc911x_interrupt,
-			IRQF_SHARED | IRQF_TRIGGER_FALLING, dev->name, dev);
+			IRQF_SHARED | SMC_IRQ_SENSE, dev->name, dev);
 	if (retval)
 		goto err_out;
 
@@ -2181,7 +2160,6 @@
 		ret = -ENOMEM;
 		goto release_1;
 	}
-	SET_MODULE_OWNER(ndev);
 	SET_NETDEV_DEV(ndev, &pdev->dev);
 
 	ndev->dma = (unsigned char)-1;
diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h
index 962a710..16a0edc 100644
--- a/drivers/net/smc911x.h
+++ b/drivers/net/smc911x.h
@@ -36,6 +36,12 @@
   #define SMC_USE_PXA_DMA	1
   #define SMC_USE_16BIT		0
   #define SMC_USE_32BIT		1
+  #define SMC_IRQ_SENSE		IRQF_TRIGGER_FALLING
+#elif CONFIG_SH_MAGIC_PANEL_R2
+  #define SMC_USE_SH_DMA	0
+  #define SMC_USE_16BIT		0
+  #define SMC_USE_32BIT		1
+  #define SMC_IRQ_SENSE		IRQF_TRIGGER_LOW
 #endif
 
 
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index 36c1eba..cb2698d 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -191,13 +191,6 @@
 /* store this information for the driver.. */
 struct smc_local {
 	/*
- 	   these are things that the kernel wants me to keep, so users
-	   can find out semi-useless statistics of how well the card is
-	   performing
- 	*/
-	struct net_device_stats stats;
-
-	/*
 	   If I have to wait until memory is available to send
 	   a packet, I will store the skbuff here, until I get the
 	   desired memory.  Then, I'll send it out and free it.
@@ -249,12 +242,6 @@
 static int smc_close(struct net_device *dev);
 
 /*
- . This routine allows the proc file system to query the driver's
- . statistics.
-*/
-static struct net_device_stats * smc_query_statistics( struct net_device *dev);
-
-/*
  . Finally, a call to set promiscuous mode ( for TCPDUMP and related
  . programs ) and multicast modes.
 */
@@ -514,7 +501,7 @@
 
 	if ( lp->saved_skb) {
 		/* THIS SHOULD NEVER HAPPEN. */
-		lp->stats.tx_aborted_errors++;
+		dev->stats.tx_aborted_errors++;
 		printk(CARDNAME": Bad Craziness - sent packet while busy.\n" );
 		return 1;
 	}
@@ -744,8 +731,6 @@
 		irq = dev->irq;
 	}
 
-	SET_MODULE_OWNER(dev);
-
 	if (io > 0x1ff) {	/* Check a single specified location. */
 		err = smc_probe(dev, io);
 	} else if (io != 0) {	/* Don't probe at all. */
@@ -891,6 +876,8 @@
 	word memory_info_register;
 	word memory_cfg_register;
 
+	DECLARE_MAC_BUF(mac);
+
 	/* Grab the region so that no one else tries to probe our ioports. */
 	if (!request_region(ioaddr, SMC_IO_EXTENT, DRV_NAME))
 		return -EBUSY;
@@ -1046,10 +1033,7 @@
 	/*
 	 . Print the Ethernet address
 	*/
-	printk("ADDR: ");
-	for (i = 0; i < 5; i++)
-		printk("%2.2x:", dev->dev_addr[i] );
-	printk("%2.2x \n", dev->dev_addr[5] );
+	printk("ADDR: %s\n", print_mac(mac, dev->dev_addr));
 
 	/* set the private data to zero by default */
 	memset(dev->priv, 0, sizeof(struct smc_local));
@@ -1067,7 +1051,6 @@
 	dev->hard_start_xmit    	= smc_wait_to_send_packet;
 	dev->tx_timeout		    	= smc_timeout;
 	dev->watchdog_timeo		= HZ/20;
-	dev->get_stats			= smc_query_statistics;
 	dev->set_multicast_list 	= smc_set_multicast_list;
 
 	return 0;
@@ -1201,7 +1184,6 @@
 */
 static void smc_rcv(struct net_device *dev)
 {
-	struct smc_local *lp = netdev_priv(dev);
 	int 	ioaddr = dev->base_addr;
 	int 	packet_number;
 	word	status;
@@ -1245,13 +1227,13 @@
 
 		/* set multicast stats */
 		if ( status & RS_MULTICAST )
-			lp->stats.multicast++;
+			dev->stats.multicast++;
 
 		skb = dev_alloc_skb( packet_length + 5);
 
 		if ( skb == NULL ) {
 			printk(KERN_NOTICE CARDNAME ": Low memory, packet dropped.\n");
-			lp->stats.rx_dropped++;
+			dev->stats.rx_dropped++;
 			goto done;
 		}
 
@@ -1291,16 +1273,16 @@
 		skb->protocol = eth_type_trans(skb, dev );
 		netif_rx(skb);
 		dev->last_rx = jiffies;
-		lp->stats.rx_packets++;
-		lp->stats.rx_bytes += packet_length;
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += packet_length;
 	} else {
 		/* error ... */
-		lp->stats.rx_errors++;
+		dev->stats.rx_errors++;
 
-		if ( status & RS_ALGNERR )  lp->stats.rx_frame_errors++;
+		if ( status & RS_ALGNERR )  dev->stats.rx_frame_errors++;
 		if ( status & (RS_TOOSHORT | RS_TOOLONG ) )
-			lp->stats.rx_length_errors++;
-		if ( status & RS_BADCRC)	lp->stats.rx_crc_errors++;
+			dev->stats.rx_length_errors++;
+		if ( status & RS_BADCRC)	dev->stats.rx_crc_errors++;
 	}
 
 done:
@@ -1348,12 +1330,12 @@
 	tx_status = inw( ioaddr + DATA_1 );
 	PRINTK3((CARDNAME": TX DONE STATUS: %4x \n", tx_status ));
 
-	lp->stats.tx_errors++;
-	if ( tx_status & TS_LOSTCAR ) lp->stats.tx_carrier_errors++;
+	dev->stats.tx_errors++;
+	if ( tx_status & TS_LOSTCAR ) dev->stats.tx_carrier_errors++;
 	if ( tx_status & TS_LATCOL  ) {
 		printk(KERN_DEBUG CARDNAME
 			": Late collision occurred on last xmit.\n");
-		lp->stats.tx_window_errors++;
+		dev->stats.tx_window_errors++;
 	}
 #if 0
 		if ( tx_status & TS_16COL ) { ... }
@@ -1448,10 +1430,10 @@
 			SMC_SELECT_BANK( 0 );
 			card_stats = inw( ioaddr + COUNTER );
 			/* single collisions */
-			lp->stats.collisions += card_stats & 0xF;
+			dev->stats.collisions += card_stats & 0xF;
 			card_stats >>= 4;
 			/* multiple collisions */
-			lp->stats.collisions += card_stats & 0xF;
+			dev->stats.collisions += card_stats & 0xF;
 
 			/* these are for when linux supports these statistics */
 
@@ -1460,7 +1442,7 @@
 				": TX_BUFFER_EMPTY handled\n"));
 			outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT );
 			mask &= ~IM_TX_EMPTY_INT;
-			lp->stats.tx_packets += lp->packets_waiting;
+			dev->stats.tx_packets += lp->packets_waiting;
 			lp->packets_waiting = 0;
 
 		} else if (status & IM_ALLOC_INT ) {
@@ -1479,8 +1461,8 @@
 
 			PRINTK2((CARDNAME": Handoff done successfully.\n"));
 		} else if (status & IM_RX_OVRN_INT ) {
-			lp->stats.rx_errors++;
-			lp->stats.rx_fifo_errors++;
+			dev->stats.rx_errors++;
+			dev->stats.rx_fifo_errors++;
 			outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT );
 		} else if (status & IM_EPH_INT ) {
 			PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT \n"));
@@ -1523,16 +1505,6 @@
 	return 0;
 }
 
-/*------------------------------------------------------------
- . Get the current statistics.
- . This may be called with the card open or closed.
- .-------------------------------------------------------------*/
-static struct net_device_stats* smc_query_statistics(struct net_device *dev) {
-	struct smc_local *lp = netdev_priv(dev);
-
-	return &lp->stats;
-}
-
 /*-----------------------------------------------------------
  . smc_set_multicast_list
  .
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 01cc3c7..24e610e 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -183,13 +183,6 @@
 	struct sk_buff *pending_tx_skb;
 	struct tasklet_struct tx_task;
 
- 	/*
-	 * these are things that the kernel wants me to keep, so users
-	 * can find out semi-useless statistics of how well the card is
-	 * performing
-	 */
-	struct net_device_stats stats;
-
 	/* version/revision of the SMC91x chip */
 	int	version;
 
@@ -332,8 +325,8 @@
 	/* free any pending tx skb */
 	if (pending_skb) {
 		dev_kfree_skb(pending_skb);
-		lp->stats.tx_errors++;
-		lp->stats.tx_aborted_errors++;
+		dev->stats.tx_errors++;
+		dev->stats.tx_aborted_errors++;
 	}
 
 	/*
@@ -512,13 +505,13 @@
 		}
 		SMC_WAIT_MMU_BUSY();
 		SMC_SET_MMU_CMD(MC_RELEASE);
-		lp->stats.rx_errors++;
+		dev->stats.rx_errors++;
 		if (status & RS_ALGNERR)
-			lp->stats.rx_frame_errors++;
+			dev->stats.rx_frame_errors++;
 		if (status & (RS_TOOSHORT | RS_TOOLONG))
-			lp->stats.rx_length_errors++;
+			dev->stats.rx_length_errors++;
 		if (status & RS_BADCRC)
-			lp->stats.rx_crc_errors++;
+			dev->stats.rx_crc_errors++;
 	} else {
 		struct sk_buff *skb;
 		unsigned char *data;
@@ -526,7 +519,7 @@
 
 		/* set multicast stats */
 		if (status & RS_MULTICAST)
-			lp->stats.multicast++;
+			dev->stats.multicast++;
 
 		/*
 		 * Actual payload is packet_len - 6 (or 5 if odd byte).
@@ -542,7 +535,7 @@
 				dev->name);
 			SMC_WAIT_MMU_BUSY();
 			SMC_SET_MMU_CMD(MC_RELEASE);
-			lp->stats.rx_dropped++;
+			dev->stats.rx_dropped++;
 			return;
 		}
 
@@ -570,8 +563,8 @@
 		dev->last_rx = jiffies;
 		skb->protocol = eth_type_trans(skb, dev);
 		netif_rx(skb);
-		lp->stats.rx_packets++;
-		lp->stats.rx_bytes += data_len;
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += data_len;
 	}
 }
 
@@ -644,8 +637,8 @@
 	packet_no = SMC_GET_AR();
 	if (unlikely(packet_no & AR_FAILED)) {
 		printk("%s: Memory allocation failed.\n", dev->name);
-		lp->stats.tx_errors++;
-		lp->stats.tx_fifo_errors++;
+		dev->stats.tx_errors++;
+		dev->stats.tx_fifo_errors++;
 		smc_special_unlock(&lp->lock);
 		goto done;
 	}
@@ -688,8 +681,8 @@
 	smc_special_unlock(&lp->lock);
 
 	dev->trans_start = jiffies;
-	lp->stats.tx_packets++;
-	lp->stats.tx_bytes += len;
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += len;
 
 	SMC_ENABLE_INT(IM_TX_INT | IM_TX_EMPTY_INT);
 
@@ -729,8 +722,8 @@
 	numPages = ((skb->len & ~1) + (6 - 1)) >> 8;
 	if (unlikely(numPages > 7)) {
 		printk("%s: Far too big packet error.\n", dev->name);
-		lp->stats.tx_errors++;
-		lp->stats.tx_dropped++;
+		dev->stats.tx_errors++;
+		dev->stats.tx_dropped++;
 		dev_kfree_skb(skb);
 		return 0;
 	}
@@ -803,17 +796,17 @@
 		dev->name, tx_status, packet_no);
 
 	if (!(tx_status & ES_TX_SUC))
-		lp->stats.tx_errors++;
+		dev->stats.tx_errors++;
 
 	if (tx_status & ES_LOSTCARR)
-		lp->stats.tx_carrier_errors++;
+		dev->stats.tx_carrier_errors++;
 
 	if (tx_status & (ES_LATCOL | ES_16COL)) {
 		PRINTK("%s: %s occurred on last xmit\n", dev->name,
 		       (tx_status & ES_LATCOL) ?
 			"late collision" : "too many collisions");
-		lp->stats.tx_window_errors++;
-		if (!(lp->stats.tx_window_errors & 63) && net_ratelimit()) {
+		dev->stats.tx_window_errors++;
+		if (!(dev->stats.tx_window_errors & 63) && net_ratelimit()) {
 			printk(KERN_INFO "%s: unexpectedly large number of "
 			       "bad collisions. Please check duplex "
 			       "setting.\n", dev->name);
@@ -1347,19 +1340,19 @@
 			SMC_SELECT_BANK(2);
 
 			/* single collisions */
-			lp->stats.collisions += card_stats & 0xF;
+			dev->stats.collisions += card_stats & 0xF;
 			card_stats >>= 4;
 
 			/* multiple collisions */
-			lp->stats.collisions += card_stats & 0xF;
+			dev->stats.collisions += card_stats & 0xF;
 		} else if (status & IM_RX_OVRN_INT) {
 			DBG(1, "%s: RX overrun (EPH_ST 0x%04x)\n", dev->name,
 			       ({ int eph_st; SMC_SELECT_BANK(0);
 				  eph_st = SMC_GET_EPH_STATUS();
 				  SMC_SELECT_BANK(2); eph_st; }) );
 			SMC_ACK_INT(IM_RX_OVRN_INT);
-			lp->stats.rx_errors++;
-			lp->stats.rx_fifo_errors++;
+			dev->stats.rx_errors++;
+			dev->stats.rx_fifo_errors++;
 		} else if (status & IM_EPH_INT) {
 			smc_eph_interrupt(dev);
 		} else if (status & IM_MDINT) {
@@ -1628,19 +1621,6 @@
 }
 
 /*
- * Get the current statistics.
- * This may be called with the card open or closed.
- */
-static struct net_device_stats *smc_query_statistics(struct net_device *dev)
-{
-	struct smc_local *lp = netdev_priv(dev);
-
-	DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
-
-	return &lp->stats;
-}
-
-/*
  * Ethtool support
  */
 static int
@@ -1842,9 +1822,10 @@
 {
 	struct smc_local *lp = netdev_priv(dev);
 	static int version_printed = 0;
-	int i, retval;
+	int retval;
 	unsigned int val, revision_register;
 	const char *version_string;
+	DECLARE_MAC_BUF(mac);
 
 	DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);
 
@@ -1965,7 +1946,6 @@
 	dev->hard_start_xmit = smc_hard_start_xmit;
 	dev->tx_timeout = smc_timeout;
 	dev->watchdog_timeo = msecs_to_jiffies(watchdog);
-	dev->get_stats = smc_query_statistics;
 	dev->set_multicast_list = smc_set_multicast_list;
 	dev->ethtool_ops = &smc_ethtool_ops;
 #ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2035,10 +2015,8 @@
 			       "set using ifconfig\n", dev->name);
 		} else {
 			/* Print the Ethernet address */
-			printk("%s: Ethernet addr: ", dev->name);
-			for (i = 0; i < 5; i++)
-				printk("%2.2x:", dev->dev_addr[i]);
-			printk("%2.2x\n", dev->dev_addr[5]);
+			printk("%s: Ethernet addr: %s\n",
+			       dev->name, print_mac(mac, dev->dev_addr));
 		}
 
 		if (lp->phy_type == 0) {
@@ -2212,7 +2190,6 @@
 		ret = -ENOMEM;
 		goto out_release_io;
 	}
-	SET_MODULE_OWNER(ndev);
 	SET_NETDEV_DEV(ndev, &pdev->dev);
 
 	ndev->dma = (unsigned char)-1;
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index f842944..af9e6bf 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -284,6 +284,7 @@
 #elif   defined(CONFIG_SUPERH)
 
 #ifdef CONFIG_SOLUTION_ENGINE
+#define SMC_IRQ_FLAGS		(0)
 #define SMC_CAN_USE_8BIT       0
 #define SMC_CAN_USE_16BIT      1
 #define SMC_CAN_USE_32BIT      0
@@ -299,7 +300,7 @@
 
 #define SMC_CAN_USE_8BIT       1
 #define SMC_CAN_USE_16BIT      1
-#define SMC_CAN_USE_32BIT      1
+#define SMC_CAN_USE_32BIT      0
 
 #define SMC_inb(a, r)          inb((a) + (r))
 #define SMC_inw(a, r)          inw((a) + (r))
@@ -310,8 +311,6 @@
 
 #endif  /* BOARDS */
 
-#define set_irq_type(irq, type) do {} while (0)
-
 #elif   defined(CONFIG_M32R)
 
 #define SMC_CAN_USE_8BIT	0
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 590b12c..fab055f 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -795,6 +795,7 @@
 static int
 spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
 {
+	struct net_device *dev = card->netdev;
 	struct spider_net_descr_chain *chain = &card->tx_chain;
 	struct spider_net_descr *descr;
 	struct spider_net_hw_descr *hwdescr;
@@ -815,8 +816,8 @@
 		status = spider_net_get_descr_status(hwdescr);
 		switch (status) {
 		case SPIDER_NET_DESCR_COMPLETE:
-			card->netdev_stats.tx_packets++;
-			card->netdev_stats.tx_bytes += descr->skb->len;
+			dev->stats.tx_packets++;
+			dev->stats.tx_bytes += descr->skb->len;
 			break;
 
 		case SPIDER_NET_DESCR_CARDOWNED:
@@ -835,11 +836,11 @@
 			if (netif_msg_tx_err(card))
 				dev_err(&card->netdev->dev, "forcing end of tx descriptor "
 				       "with status x%02x\n", status);
-			card->netdev_stats.tx_errors++;
+			dev->stats.tx_errors++;
 			break;
 
 		default:
-			card->netdev_stats.tx_dropped++;
+			dev->stats.tx_dropped++;
 			if (!brutal) {
 				spin_unlock_irqrestore(&chain->lock, flags);
 				return 1;
@@ -919,7 +920,7 @@
 	spider_net_release_tx_chain(card, 0);
 
 	if (spider_net_prepare_tx_descr(card, skb) != 0) {
-		card->netdev_stats.tx_dropped++;
+		netdev->stats.tx_dropped++;
 		netif_stop_queue(netdev);
 		return NETDEV_TX_BUSY;
 	}
@@ -979,16 +980,12 @@
 spider_net_pass_skb_up(struct spider_net_descr *descr,
 		       struct spider_net_card *card)
 {
-	struct spider_net_hw_descr *hwdescr= descr->hwdescr;
-	struct sk_buff *skb;
-	struct net_device *netdev;
-	u32 data_status, data_error;
+	struct spider_net_hw_descr *hwdescr = descr->hwdescr;
+	struct sk_buff *skb = descr->skb;
+	struct net_device *netdev = card->netdev;
+	u32 data_status = hwdescr->data_status;
+	u32 data_error = hwdescr->data_error;
 
-	data_status = hwdescr->data_status;
-	data_error = hwdescr->data_error;
-	netdev = card->netdev;
-
-	skb = descr->skb;
 	skb_put(skb, hwdescr->valid_size);
 
 	/* the card seems to add 2 bytes of junk in front
@@ -1015,8 +1012,8 @@
 	}
 
 	/* update netdevice statistics */
-	card->netdev_stats.rx_packets++;
-	card->netdev_stats.rx_bytes += skb->len;
+	netdev->stats.rx_packets++;
+	netdev->stats.rx_bytes += skb->len;
 
 	/* pass skb up to stack */
 	netif_receive_skb(skb);
@@ -1184,6 +1181,7 @@
 static int
 spider_net_decode_one_descr(struct spider_net_card *card)
 {
+	struct net_device *dev = card->netdev;
 	struct spider_net_descr_chain *chain = &card->rx_chain;
 	struct spider_net_descr *descr = chain->tail;
 	struct spider_net_hw_descr *hwdescr = descr->hwdescr;
@@ -1210,9 +1208,9 @@
 	     (status == SPIDER_NET_DESCR_PROTECTION_ERROR) ||
 	     (status == SPIDER_NET_DESCR_FORCE_END) ) {
 		if (netif_msg_rx_err(card))
-			dev_err(&card->netdev->dev,
+			dev_err(&dev->dev,
 			       "dropping RX descriptor with state %d\n", status);
-		card->netdev_stats.rx_dropped++;
+		dev->stats.rx_dropped++;
 		goto bad_desc;
 	}
 
@@ -1278,34 +1276,26 @@
  * (using netif_receive_skb). If all/enough packets are up, the driver
  * reenables interrupts and returns 0. If not, 1 is returned.
  */
-static int
-spider_net_poll(struct net_device *netdev, int *budget)
+static int spider_net_poll(struct napi_struct *napi, int budget)
 {
-	struct spider_net_card *card = netdev_priv(netdev);
-	int packets_to_do, packets_done = 0;
-	int no_more_packets = 0;
+	struct spider_net_card *card = container_of(napi, struct spider_net_card, napi);
+	struct net_device *netdev = card->netdev;
+	int packets_done = 0;
 
-	packets_to_do = min(*budget, netdev->quota);
-
-	while (packets_to_do) {
-		if (spider_net_decode_one_descr(card)) {
-			packets_done++;
-			packets_to_do--;
-		} else {
-			/* no more packets for the stack */
-			no_more_packets = 1;
+	while (packets_done < budget) {
+		if (!spider_net_decode_one_descr(card))
 			break;
-		}
+
+		packets_done++;
 	}
 
 	if ((packets_done == 0) && (card->num_rx_ints != 0)) {
-		no_more_packets = spider_net_resync_tail_ptr(card);
+		if (!spider_net_resync_tail_ptr(card))
+			packets_done = budget;
 		spider_net_resync_head_ptr(card);
 	}
 	card->num_rx_ints = 0;
 
-	netdev->quota -= packets_done;
-	*budget -= packets_done;
 	spider_net_refill_rx_chain(card);
 	spider_net_enable_rxdmac(card);
 
@@ -1313,28 +1303,13 @@
 
 	/* if all packets are in the stack, enable interrupts and return 0 */
 	/* if not, return 1 */
-	if (no_more_packets) {
-		netif_rx_complete(netdev);
+	if (packets_done < budget) {
+		netif_rx_complete(netdev, napi);
 		spider_net_rx_irq_on(card);
 		card->ignore_rx_ramfull = 0;
-		return 0;
 	}
 
-	return 1;
-}
-
-/**
- * spider_net_get_stats - get interface statistics
- * @netdev: interface device structure
- *
- * returns the interface statistics residing in the spider_net_card struct
- */
-static struct net_device_stats *
-spider_net_get_stats(struct net_device *netdev)
-{
-	struct spider_net_card *card = netdev_priv(netdev);
-	struct net_device_stats *stats = &card->netdev_stats;
-	return stats;
+	return packets_done;
 }
 
 /**
@@ -1441,17 +1416,14 @@
 spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
 {
 	u32 error_reg1, error_reg2;
-	u32 mask_reg1, mask_reg2;
 	u32 i;
 	int show_error = 1;
 
 	error_reg1 = spider_net_read_reg(card, SPIDER_NET_GHIINT1STS);
 	error_reg2 = spider_net_read_reg(card, SPIDER_NET_GHIINT2STS);
-	mask_reg1 = spider_net_read_reg(card, SPIDER_NET_GHIINT1MSK);
-	mask_reg2 = spider_net_read_reg(card,SPIDER_NET_GHIINT2MSK);
 
-	error_reg1 &= mask_reg1;
-	error_reg2 &= mask_reg2;
+	error_reg1 &= SPIDER_NET_INT1_MASK_VALUE;
+	error_reg2 &= SPIDER_NET_INT2_MASK_VALUE;
 
 	/* check GHIINT0STS ************************************/
 	if (status_reg)
@@ -1563,7 +1535,8 @@
 			spider_net_refill_rx_chain(card);
 			spider_net_enable_rxdmac(card);
 			card->num_rx_ints ++;
-			netif_rx_schedule(card->netdev);
+			netif_rx_schedule(card->netdev,
+					  &card->napi);
 		}
 		show_error = 0;
 		break;
@@ -1583,7 +1556,8 @@
 		spider_net_refill_rx_chain(card);
 		spider_net_enable_rxdmac(card);
 		card->num_rx_ints ++;
-		netif_rx_schedule(card->netdev);
+		netif_rx_schedule(card->netdev,
+				  &card->napi);
 		show_error = 0;
 		break;
 
@@ -1597,7 +1571,8 @@
 		spider_net_refill_rx_chain(card);
 		spider_net_enable_rxdmac(card);
 		card->num_rx_ints ++;
-		netif_rx_schedule(card->netdev);
+		netif_rx_schedule(card->netdev,
+				  &card->napi);
 		show_error = 0;
 		break;
 
@@ -1679,22 +1654,21 @@
 {
 	struct net_device *netdev = ptr;
 	struct spider_net_card *card = netdev_priv(netdev);
-	u32 status_reg, mask_reg;
+	u32 status_reg;
 
 	status_reg = spider_net_read_reg(card, SPIDER_NET_GHIINT0STS);
-	mask_reg = spider_net_read_reg(card, SPIDER_NET_GHIINT0MSK);
-	status_reg &= mask_reg;
+	status_reg &= SPIDER_NET_INT0_MASK_VALUE;
 
 	if (!status_reg)
 		return IRQ_NONE;
 
 	if (status_reg & SPIDER_NET_RXINT ) {
 		spider_net_rx_irq_off(card);
-		netif_rx_schedule(netdev);
+		netif_rx_schedule(netdev, &card->napi);
 		card->num_rx_ints ++;
 	}
 	if (status_reg & SPIDER_NET_TXINT)
-		netif_rx_schedule(netdev);
+		netif_rx_schedule(netdev, &card->napi);
 
 	if (status_reg & SPIDER_NET_LINKINT)
 		spider_net_link_reset(netdev);
@@ -2038,7 +2012,7 @@
 
 	netif_start_queue(netdev);
 	netif_carrier_on(netdev);
-	netif_poll_enable(netdev);
+	napi_enable(&card->napi);
 
 	spider_net_enable_interrupts(card);
 
@@ -2208,7 +2182,7 @@
 {
 	struct spider_net_card *card = netdev_priv(netdev);
 
-	netif_poll_disable(netdev);
+	napi_disable(&card->napi);
 	netif_carrier_off(netdev);
 	netif_stop_queue(netdev);
 	del_timer_sync(&card->tx_timer);
@@ -2300,7 +2274,6 @@
 	netdev->open = &spider_net_open;
 	netdev->stop = &spider_net_stop;
 	netdev->hard_start_xmit = &spider_net_xmit;
-	netdev->get_stats = &spider_net_get_stats;
 	netdev->set_multicast_list = &spider_net_set_multi;
 	netdev->set_mac_address = &spider_net_set_mac;
 	netdev->change_mtu = &spider_net_change_mtu;
@@ -2308,9 +2281,6 @@
 	/* tx watchdog */
 	netdev->tx_timeout = &spider_net_tx_timeout;
 	netdev->watchdog_timeo = SPIDER_NET_WATCHDOG_TIMEOUT;
-	/* NAPI */
-	netdev->poll = &spider_net_poll;
-	netdev->weight = SPIDER_NET_NAPI_WEIGHT;
 	/* HW VLAN */
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	/* poll controller */
@@ -2337,7 +2307,6 @@
 	struct sockaddr addr;
 	const u8 *mac;
 
-	SET_MODULE_OWNER(netdev);
 	SET_NETDEV_DEV(netdev, &card->pdev->dev);
 
 	pci_set_drvdata(card->pdev, netdev);
@@ -2355,6 +2324,9 @@
 
 	card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;
 
+	netif_napi_add(netdev, &card->napi,
+		       spider_net_poll, SPIDER_NET_NAPI_WEIGHT);
+
 	spider_net_setup_netdev_ops(netdev);
 
 	netdev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX;
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
index dbbdb8c..a897bee 100644
--- a/drivers/net/spider_net.h
+++ b/drivers/net/spider_net.h
@@ -466,6 +466,8 @@
 	struct pci_dev *pdev;
 	struct mii_phy phy;
 
+	struct napi_struct napi;
+
 	int medium;
 
 	void __iomem *regs;
@@ -485,7 +487,6 @@
 
 	/* for ethtool */
 	int msg_enable;
-	struct net_device_stats netdev_stats;
 	struct spider_net_extra_stats spider_stats;
 	struct spider_net_options options;
 
diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c
index d940474..85691d2 100644
--- a/drivers/net/spider_net_ethtool.c
+++ b/drivers/net/spider_net_ethtool.c
@@ -28,8 +28,6 @@
 #include "spider_net.h"
 
 
-#define SPIDER_NET_NUM_STATS 13
-
 static struct {
 	const char str[ETH_GSTRING_LEN];
 } ethtool_stats_keys[] = {
@@ -147,9 +145,14 @@
 	ering->rx_pending = card->rx_chain.num_desc;
 }
 
-static int spider_net_get_stats_count(struct net_device *netdev)
+static int spider_net_get_sset_count(struct net_device *netdev, int sset)
 {
-	return SPIDER_NET_NUM_STATS;
+	switch (sset) {
+	case ETH_SS_STATS:
+		return ARRAY_SIZE(ethtool_stats_keys);
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void spider_net_get_ethtool_stats(struct net_device *netdev,
@@ -157,13 +160,13 @@
 {
 	struct spider_net_card *card = netdev->priv;
 
-	data[0] = card->netdev_stats.tx_packets;
-	data[1] = card->netdev_stats.tx_bytes;
-	data[2] = card->netdev_stats.rx_packets;
-	data[3] = card->netdev_stats.rx_bytes;
-	data[4] = card->netdev_stats.tx_errors;
-	data[5] = card->netdev_stats.tx_dropped;
-	data[6] = card->netdev_stats.rx_dropped;
+	data[0] = netdev->stats.tx_packets;
+	data[1] = netdev->stats.tx_bytes;
+	data[2] = netdev->stats.rx_packets;
+	data[3] = netdev->stats.rx_bytes;
+	data[4] = netdev->stats.tx_errors;
+	data[5] = netdev->stats.tx_dropped;
+	data[6] = netdev->stats.rx_dropped;
 	data[7] = card->spider_stats.rx_desc_error;
 	data[8] = card->spider_stats.tx_timeouts;
 	data[9] = card->spider_stats.alloc_rx_skb_error;
@@ -188,11 +191,10 @@
 	.nway_reset		= spider_net_ethtool_nway_reset,
 	.get_rx_csum		= spider_net_ethtool_get_rx_csum,
 	.set_rx_csum		= spider_net_ethtool_set_rx_csum,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
 	.set_tx_csum		= ethtool_op_set_tx_csum,
 	.get_ringparam          = spider_net_ethtool_get_ringparam,
 	.get_strings		= spider_net_get_strings,
-	.get_stats_count	= spider_net_get_stats_count,
+	.get_sset_count		= spider_net_get_sset_count,
 	.get_ethtool_stats	= spider_net_get_ethtool_stats,
 };
 
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 8b64786..bcc430b 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -155,7 +155,7 @@
 #if (defined(__i386__) && defined(CONFIG_HIGHMEM64G)) || defined(__x86_64__) || defined (__ia64__) || defined(__alpha__) || defined(__mips64__) || (defined(__mips__) && defined(CONFIG_HIGHMEM) && defined(CONFIG_64BIT_PHYS_ADDR))
 /* 64-bit dma_addr_t */
 #define ADDR_64BITS	/* This chip uses 64 bit addresses. */
-#define netdrv_addr_t u64
+#define netdrv_addr_t __le64
 #define cpu_to_dma(x) cpu_to_le64(x)
 #define dma_to_cpu(x) le64_to_cpu(x)
 #define RX_DESC_Q_ADDR_SIZE RxDescQAddr64bit
@@ -164,7 +164,7 @@
 #define TX_COMPL_Q_ADDR_SIZE TxComplQAddr64bit
 #define RX_DESC_ADDR_SIZE RxDescAddr64bit
 #else  /* 32-bit dma_addr_t */
-#define netdrv_addr_t u32
+#define netdrv_addr_t __le32
 #define cpu_to_dma(x) cpu_to_le32(x)
 #define dma_to_cpu(x) le32_to_cpu(x)
 #define RX_DESC_Q_ADDR_SIZE RxDescQAddr32bit
@@ -178,16 +178,13 @@
 #define skb_num_frags(skb) (skb_shinfo(skb)->nr_frags + 1)
 
 #ifdef HAVE_NETDEV_POLL
-#define init_poll(dev) \
-do { \
-	dev->poll = &netdev_poll; \
-	dev->weight = max_interrupt_work; \
-} while (0)
-#define netdev_rx(dev, ioaddr) \
+#define init_poll(dev, np) \
+	netif_napi_add(dev, &np->napi, netdev_poll, max_interrupt_work)
+#define netdev_rx(dev, np, ioaddr) \
 do { \
 	u32 intr_enable; \
-	if (netif_rx_schedule_prep(dev)) { \
-		__netif_rx_schedule(dev); \
+	if (netif_rx_schedule_prep(dev, &np->napi)) { \
+		__netif_rx_schedule(dev, &np->napi); \
 		intr_enable = readl(ioaddr + IntrEnable); \
 		intr_enable &= ~(IntrRxDone | IntrRxEmpty); \
 		writel(intr_enable, ioaddr + IntrEnable); \
@@ -204,12 +201,12 @@
 } while (0)
 #define netdev_receive_skb(skb) netif_receive_skb(skb)
 #define vlan_netdev_receive_skb(skb, vlgrp, vlid) vlan_hwaccel_receive_skb(skb, vlgrp, vlid)
-static int	netdev_poll(struct net_device *dev, int *budget);
+static int	netdev_poll(struct napi_struct *napi, int budget);
 #else  /* not HAVE_NETDEV_POLL */
-#define init_poll(dev)
+#define init_poll(dev, np)
 #define netdev_receive_skb(skb) netif_rx(skb)
 #define vlan_netdev_receive_skb(skb, vlgrp, vlid) vlan_hwaccel_rx(skb, vlgrp, vlid)
-#define netdev_rx(dev, ioaddr) \
+#define netdev_rx(dev, np, ioaddr) \
 do { \
 	int quota = np->dirty_rx + RX_RING_SIZE - np->cur_rx; \
 	__netdev_rx(dev, &quota);\
@@ -497,7 +494,7 @@
 
 /* The Rx and Tx buffer descriptors. */
 struct starfire_rx_desc {
-	dma_addr_t rxaddr;
+	netdrv_addr_t rxaddr;
 };
 enum rx_desc_bits {
 	RxDescValid=1, RxDescEndRing=2,
@@ -505,25 +502,25 @@
 
 /* Completion queue entry. */
 struct short_rx_done_desc {
-	u32 status;			/* Low 16 bits is length. */
+	__le32 status;			/* Low 16 bits is length. */
 };
 struct basic_rx_done_desc {
-	u32 status;			/* Low 16 bits is length. */
-	u16 vlanid;
-	u16 status2;
+	__le32 status;			/* Low 16 bits is length. */
+	__le16 vlanid;
+	__le16 status2;
 };
 struct csum_rx_done_desc {
-	u32 status;			/* Low 16 bits is length. */
-	u16 csum;			/* Partial checksum */
-	u16 status2;
+	__le32 status;			/* Low 16 bits is length. */
+	__le16 csum;			/* Partial checksum */
+	__le16 status2;
 };
 struct full_rx_done_desc {
-	u32 status;			/* Low 16 bits is length. */
-	u16 status3;
-	u16 status2;
-	u16 vlanid;
-	u16 csum;			/* partial checksum */
-	u32 timestamp;
+	__le32 status;			/* Low 16 bits is length. */
+	__le16 status3;
+	__le16 status2;
+	__le16 vlanid;
+	__le16 csum;			/* partial checksum */
+	__le32 timestamp;
 };
 /* XXX: this is ugly and I'm not sure it's worth the trouble -Ion */
 #ifdef VLAN_SUPPORT
@@ -540,15 +537,15 @@
 
 /* Type 1 Tx descriptor. */
 struct starfire_tx_desc_1 {
-	u32 status;			/* Upper bits are status, lower 16 length. */
-	u32 addr;
+	__le32 status;			/* Upper bits are status, lower 16 length. */
+	__le32 addr;
 };
 
 /* Type 2 Tx descriptor. */
 struct starfire_tx_desc_2 {
-	u32 status;			/* Upper bits are status, lower 16 length. */
-	u32 reserved;
-	u64 addr;
+	__le32 status;			/* Upper bits are status, lower 16 length. */
+	__le32 reserved;
+	__le64 addr;
 };
 
 #ifdef ADDR_64BITS
@@ -566,9 +563,9 @@
 	TxRingWrap=0x04000000, TxCalTCP=0x02000000,
 };
 struct tx_done_desc {
-	u32 status;			/* timestamp, index. */
+	__le32 status;			/* timestamp, index. */
 #if 0
-	u32 intrstatus;			/* interrupt status */
+	__le32 intrstatus;		/* interrupt status */
 #endif
 };
 
@@ -599,6 +596,8 @@
 	struct tx_done_desc *tx_done_q;
 	dma_addr_t tx_done_q_dma;
 	unsigned int tx_done;
+	struct napi_struct napi;
+	struct net_device *dev;
 	struct net_device_stats stats;
 	struct pci_dev *pci_dev;
 #ifdef VLAN_SUPPORT
@@ -695,6 +694,7 @@
 	void __iomem *base;
 	int drv_flags, io_size;
 	int boguscnt;
+	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -720,7 +720,6 @@
 		printk(KERN_ERR DRV_NAME " %d: cannot alloc etherdev, aborting\n", card_idx);
 		return -ENOMEM;
 	}
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	irq = pdev->irq;
@@ -791,6 +790,7 @@
 	dev->irq = irq;
 
 	np = netdev_priv(dev);
+	np->dev = dev;
 	np->base = base;
 	spin_lock_init(&np->lock);
 	pci_set_drvdata(pdev, dev);
@@ -851,7 +851,7 @@
 	dev->hard_start_xmit = &start_tx;
 	dev->tx_timeout = tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
-	init_poll(dev);
+	init_poll(dev, np);
 	dev->stop = &netdev_close;
 	dev->get_stats = &get_stats;
 	dev->set_multicast_list = &set_rx_mode;
@@ -864,11 +864,9 @@
 	if (register_netdev(dev))
 		goto err_out_cleardev;
 
-	printk(KERN_INFO "%s: %s at %p, ",
-		   dev->name, netdrv_tbl[chip_idx].name, base);
-	for (i = 0; i < 5; i++)
-		printk("%2.2x:", dev->dev_addr[i]);
-	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+	printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",
+	       dev->name, netdrv_tbl[chip_idx].name, base,
+	       print_mac(mac, dev->dev_addr), irq);
 
 	if (drv_flags & CanHaveMII) {
 		int phy, phy_idx = 0;
@@ -965,7 +963,7 @@
 		       dev->name, dev->irq);
 
 	/* Allocate the various queues. */
-	if (np->queue_mem == 0) {
+	if (!np->queue_mem) {
 		tx_done_q_size = ((sizeof(struct tx_done_desc) * DONE_Q_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN;
 		rx_done_q_size = ((sizeof(rx_done_desc) * DONE_Q_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN;
 		tx_ring_size = ((sizeof(starfire_tx_desc) * TX_RING_SIZE + QUEUE_ALIGN - 1) / QUEUE_ALIGN) * QUEUE_ALIGN;
@@ -1038,11 +1036,11 @@
 	writew(0, ioaddr + PerfFilterTable + 4);
 	writew(0, ioaddr + PerfFilterTable + 8);
 	for (i = 1; i < 16; i++) {
-		u16 *eaddrs = (u16 *)dev->dev_addr;
+		__be16 *eaddrs = (__be16 *)dev->dev_addr;
 		void __iomem *setup_frm = ioaddr + PerfFilterTable + i * 16;
-		writew(cpu_to_be16(eaddrs[2]), setup_frm); setup_frm += 4;
-		writew(cpu_to_be16(eaddrs[1]), setup_frm); setup_frm += 4;
-		writew(cpu_to_be16(eaddrs[0]), setup_frm); setup_frm += 8;
+		writew(be16_to_cpu(eaddrs[2]), setup_frm); setup_frm += 4;
+		writew(be16_to_cpu(eaddrs[1]), setup_frm); setup_frm += 4;
+		writew(be16_to_cpu(eaddrs[0]), setup_frm); setup_frm += 8;
 	}
 
 	/* Initialize other registers. */
@@ -1056,6 +1054,9 @@
 
 	writel(np->intr_timer_ctrl, ioaddr + IntrTimerCtrl);
 
+#ifdef HAVE_NETDEV_POLL
+	napi_enable(&np->napi);
+#endif
 	netif_start_queue(dev);
 
 	if (debug > 1)
@@ -1330,7 +1331,7 @@
 		handled = 1;
 
 		if (intr_status & (IntrRxDone | IntrRxEmpty))
-			netdev_rx(dev, ioaddr);
+			netdev_rx(dev, np, ioaddr);
 
 		/* Scavenge the skbuff list based on the Tx-done queue.
 		   There are redundant checks here that may be cleaned up
@@ -1470,13 +1471,16 @@
 		}
 #ifndef final_version			/* Remove after testing. */
 		/* You will want this info for the initial debug. */
-		if (debug > 5)
-			printk(KERN_DEBUG "  Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
-			       "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x.\n",
-			       skb->data[0], skb->data[1], skb->data[2], skb->data[3],
-			       skb->data[4], skb->data[5], skb->data[6], skb->data[7],
-			       skb->data[8], skb->data[9], skb->data[10],
-			       skb->data[11], skb->data[12], skb->data[13]);
+		if (debug > 5) {
+			DECLARE_MAC_BUF(mac);
+			DECLARE_MAC_BUF(mac2);
+
+			printk(KERN_DEBUG "  Rx data %s %s"
+			       " %2.2x%2.2x.\n",
+			       print_mac(mac, &skb->data[0]),
+			       print_mac(mac2, &skb->data[6]),
+			       skb->data[12], skb->data[13]);
+		}
 #endif
 
 		skb->protocol = eth_type_trans(skb, dev);
@@ -1531,36 +1535,35 @@
 
 
 #ifdef HAVE_NETDEV_POLL
-static int netdev_poll(struct net_device *dev, int *budget)
+static int netdev_poll(struct napi_struct *napi, int budget)
 {
+	struct netdev_private *np = container_of(napi, struct netdev_private, napi);
+	struct net_device *dev = np->dev;
 	u32 intr_status;
-	struct netdev_private *np = netdev_priv(dev);
 	void __iomem *ioaddr = np->base;
-	int retcode = 0, quota = dev->quota;
+	int quota = budget;
 
 	do {
 		writel(IntrRxDone | IntrRxEmpty, ioaddr + IntrClear);
 
-		retcode = __netdev_rx(dev, &quota);
-		*budget -= (dev->quota - quota);
-		dev->quota = quota;
-		if (retcode)
+		if (__netdev_rx(dev, &quota))
 			goto out;
 
 		intr_status = readl(ioaddr + IntrStatus);
 	} while (intr_status & (IntrRxDone | IntrRxEmpty));
 
-	netif_rx_complete(dev);
+	netif_rx_complete(dev, napi);
 	intr_status = readl(ioaddr + IntrEnable);
 	intr_status |= IntrRxDone | IntrRxEmpty;
 	writel(intr_status, ioaddr + IntrEnable);
 
  out:
 	if (debug > 5)
-		printk(KERN_DEBUG "  exiting netdev_poll(): %d.\n", retcode);
+		printk(KERN_DEBUG "  exiting netdev_poll(): %d.\n",
+		       budget - quota);
 
 	/* Restart Rx engine if stopped. */
-	return retcode;
+	return budget - quota;
 }
 #endif /* HAVE_NETDEV_POLL */
 
@@ -1764,26 +1767,26 @@
 	} else if (dev->mc_count <= 14) {
 		/* Use the 16 element perfect filter, skip first two entries. */
 		void __iomem *filter_addr = ioaddr + PerfFilterTable + 2 * 16;
-		u16 *eaddrs;
+		__be16 *eaddrs;
 		for (i = 2, mclist = dev->mc_list; mclist && i < dev->mc_count + 2;
 		     i++, mclist = mclist->next) {
-			eaddrs = (u16 *)mclist->dmi_addr;
-			writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 4;
-			writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4;
-			writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 8;
+			eaddrs = (__be16 *)mclist->dmi_addr;
+			writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 4;
+			writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4;
+			writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 8;
 		}
-		eaddrs = (u16 *)dev->dev_addr;
+		eaddrs = (__be16 *)dev->dev_addr;
 		while (i++ < 16) {
-			writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 4;
-			writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4;
-			writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 8;
+			writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 4;
+			writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4;
+			writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 8;
 		}
 		rx_mode |= AcceptBroadcast|PerfectFilter;
 	} else {
 		/* Must use a multicast hash table. */
 		void __iomem *filter_addr;
-		u16 *eaddrs;
-		u16 mc_filter[32] __attribute__ ((aligned(sizeof(long))));	/* Multicast hash filter */
+		__be16 *eaddrs;
+		__le16 mc_filter[32] __attribute__ ((aligned(sizeof(long))));	/* Multicast hash filter */
 
 		memset(mc_filter, 0, sizeof(mc_filter));
 		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
@@ -1791,17 +1794,17 @@
 			/* The chip uses the upper 9 CRC bits
 			   as index into the hash table */
 			int bit_nr = ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 23;
-			__u32 *fptr = (__u32 *) &mc_filter[(bit_nr >> 4) & ~1];
+			__le32 *fptr = (__le32 *) &mc_filter[(bit_nr >> 4) & ~1];
 
 			*fptr |= cpu_to_le32(1 << (bit_nr & 31));
 		}
 		/* Clear the perfect filter list, skip first two entries. */
 		filter_addr = ioaddr + PerfFilterTable + 2 * 16;
-		eaddrs = (u16 *)dev->dev_addr;
+		eaddrs = (__be16 *)dev->dev_addr;
 		for (i = 2; i < 16; i++) {
-			writew(cpu_to_be16(eaddrs[0]), filter_addr); filter_addr += 4;
-			writew(cpu_to_be16(eaddrs[1]), filter_addr); filter_addr += 4;
-			writew(cpu_to_be16(eaddrs[2]), filter_addr); filter_addr += 8;
+			writew(be16_to_cpu(eaddrs[0]), filter_addr); filter_addr += 4;
+			writew(be16_to_cpu(eaddrs[1]), filter_addr); filter_addr += 4;
+			writew(be16_to_cpu(eaddrs[2]), filter_addr); filter_addr += 8;
 		}
 		for (filter_addr = ioaddr + HashTable, i = 0; i < 32; filter_addr+= 16, i++)
 			writew(mc_filter[i], filter_addr);
@@ -1904,6 +1907,9 @@
 	int i;
 
 	netif_stop_queue(dev);
+#ifdef HAVE_NETDEV_POLL
+	napi_disable(&np->napi);
+#endif
 
 	if (debug > 1) {
 		printk(KERN_DEBUG "%s: Shutting down ethercard, Intr status %#8.8x.\n",
diff --git a/drivers/net/stnic.c b/drivers/net/stnic.c
index e6f9042..b65be5d 100644
--- a/drivers/net/stnic.c
+++ b/drivers/net/stnic.c
@@ -112,7 +112,6 @@
   dev = alloc_ei_netdev();
   if (!dev)
   	return -ENOMEM;
-  SET_MODULE_OWNER(dev);
 
 #ifdef CONFIG_SH_STANDARD_BIOS
   sh_bios_get_node_addr (stnic_eadr);
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
index b77ab6e..9b2a7f7 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/sun3_82586.c
@@ -311,7 +311,6 @@
 		sprintf(dev->name, "eth%d", unit);
 		netdev_boot_setup_check(dev);
 	}
-	SET_MODULE_OWNER(dev);
 
 	dev->irq = IE_IRQ;
 	dev->base_addr = ioaddr;
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index f1548c0..f8d4613 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -152,7 +152,6 @@
 	struct lance_memory	*mem;
      	int new_rx, new_tx;	/* The next free ring entry */
 	int old_tx, old_rx;     /* ring entry to be processed */
-	struct net_device_stats stats;
 /* These two must be longs for set_bit() */
 	long	    tx_full;
 	long	    lock;
@@ -241,7 +240,6 @@
 static irqreturn_t lance_interrupt( int irq, void *dev_id);
 static int lance_rx( struct net_device *dev );
 static int lance_close( struct net_device *dev );
-static struct net_device_stats *lance_get_stats( struct net_device *dev );
 static void set_multicast_list( struct net_device *dev );
 
 /************************* End of Prototypes **************************/
@@ -274,7 +272,6 @@
 		sprintf(dev->name, "eth%d", unit);
 		netdev_boot_setup_check(dev);
 	}
-	SET_MODULE_OWNER(dev);
 
 	if (!lance_probe(dev))
 		goto out;
@@ -303,6 +300,7 @@
 	static int 		did_version;
 	volatile unsigned short *ioaddr_probe;
 	unsigned short tmp1, tmp2;
+	DECLARE_MAC_BUF(mac);
 
 #ifdef CONFIG_SUN3
 	ioaddr = (unsigned long)ioremap(LANCE_OBIO, PAGE_SIZE);
@@ -378,8 +376,7 @@
 	MEM->init.hwaddr[4] = dev->dev_addr[5];
 	MEM->init.hwaddr[5] = dev->dev_addr[4];
 
-	for( i = 0; i < 6; ++i )
-		printk( "%02x%s", dev->dev_addr[i], (i < 5) ? ":" : "\n" );
+	printk("%s\n", print_mac(mac, dev->dev_addr));
 
 	MEM->init.mode = 0x0000;
 	MEM->init.filter[0] = 0x00000000;
@@ -402,15 +399,12 @@
 	dev->open = &lance_open;
 	dev->hard_start_xmit = &lance_start_xmit;
 	dev->stop = &lance_close;
-	dev->get_stats = &lance_get_stats;
 	dev->set_multicast_list = &set_multicast_list;
 	dev->set_mac_address = NULL;
 //	KLUDGE -- REMOVE ME
 	set_bit(__LINK_STATE_PRESENT, &dev->state);
 
 
-	memset( &lp->stats, 0, sizeof(lp->stats) );
-
 	return 1;
 }
 
@@ -535,7 +529,7 @@
 		 * little endian mode.
 		 */
 		REGA(CSR3) = CSR3_BSWP;
-		lp->stats.tx_errors++;
+		dev->stats.tx_errors++;
 
 		if(lance_debug >= 2) {
 			int i;
@@ -596,17 +590,12 @@
 	/* Fill in a Tx ring entry */
 #if 0
 	if (lance_debug >= 2) {
-		u_char *p;
-		int i;
-		printk( "%s: TX pkt %d type 0x%04x from ", dev->name,
-			lp->new_tx, ((u_short *)skb->data)[6]);
-		for( p = &((u_char *)skb->data)[6], i = 0; i < 6; i++ )
-			printk("%02x%s", *p++, i != 5 ? ":" : "" );
-		printk(" to ");
-		for( p = (u_char *)skb->data, i = 0; i < 6; i++ )
-			printk("%02x%s", *p++, i != 5 ? ":" : "" );
-		printk(" data at 0x%08x len %d\n", (int)skb->data,
-		       (int)skb->len );
+		printk( "%s: TX pkt %d type 0x%04x"
+			" from %s to %s"
+			" data at 0x%08x len %d\n",
+			dev->name, lp->new_tx, ((u_short *)skb->data)[6],
+			DEV_ADDR(&skb->data[6]), DEV_ADDR(skb->data),
+			(int)skb->data, (int)skb->len );
 	}
 #endif
 	/* We're not prepared for the int until the last flags are set/reset.
@@ -635,7 +624,7 @@
 
 	head->flag = TMD1_OWN_CHIP | TMD1_ENP | TMD1_STP;
 	lp->new_tx = (lp->new_tx + 1) & TX_RING_MOD_MASK;
-	lp->stats.tx_bytes += skb->len;
+	dev->stats.tx_bytes += skb->len;
 
 	/* Trigger an immediate send poll. */
 	REGA(CSR0) = CSR0_INEA | CSR0_TDMD | CSR0_STRT;
@@ -713,12 +702,12 @@
 
 			if (head->flag & TMD1_ERR) {
 				int status = head->misc;
-				lp->stats.tx_errors++;
-				if (status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
-				if (status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
-				if (status & TMD3_LCOL) lp->stats.tx_window_errors++;
+				dev->stats.tx_errors++;
+				if (status & TMD3_RTRY) dev->stats.tx_aborted_errors++;
+				if (status & TMD3_LCAR) dev->stats.tx_carrier_errors++;
+				if (status & TMD3_LCOL) dev->stats.tx_window_errors++;
 				if (status & (TMD3_UFLO | TMD3_BUFF)) {
-					lp->stats.tx_fifo_errors++;
+					dev->stats.tx_fifo_errors++;
 					printk("%s: Tx FIFO error\n",
 					       dev->name);
 					REGA(CSR0) = CSR0_STOP;
@@ -731,9 +720,9 @@
 
 				head->flag &= ~(TMD1_ENP | TMD1_STP);
 				if(head->flag & (TMD1_ONE | TMD1_MORE))
-					lp->stats.collisions++;
+					dev->stats.collisions++;
 
-				lp->stats.tx_packets++;
+				dev->stats.tx_packets++;
 				DPRINTK(3, ("cleared tx ring %d\n", old_tx));
 			}
 			old_tx = (old_tx +1) & TX_RING_MOD_MASK;
@@ -753,8 +742,8 @@
 		lance_rx( dev );
 
 	/* Log misc errors. */
-	if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */
-	if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */
+	if (csr0 & CSR0_BABL) dev->stats.tx_errors++; /* Tx babble. */
+	if (csr0 & CSR0_MISS) dev->stats.rx_errors++; /* Missed a Rx frame. */
 	if (csr0 & CSR0_MERR) {
 		DPRINTK( 1, ( "%s: Bus master arbitration failure (?!?), "
 			      "status %04x.\n", dev->name, csr0 ));
@@ -800,11 +789,11 @@
 			   full-sized buffers it's possible for a jabber packet to use two
 			   buffers, with only the last correctly noting the error. */
 			if (status & RMD1_ENP)	/* Only count a general error at the */
-				lp->stats.rx_errors++; /* end of a packet.*/
-			if (status & RMD1_FRAM) lp->stats.rx_frame_errors++;
-			if (status & RMD1_OFLO) lp->stats.rx_over_errors++;
-			if (status & RMD1_CRC) lp->stats.rx_crc_errors++;
-			if (status & RMD1_BUFF) lp->stats.rx_fifo_errors++;
+				dev->stats.rx_errors++; /* end of a packet.*/
+			if (status & RMD1_FRAM) dev->stats.rx_frame_errors++;
+			if (status & RMD1_OFLO) dev->stats.rx_over_errors++;
+			if (status & RMD1_CRC) dev->stats.rx_crc_errors++;
+			if (status & RMD1_BUFF) dev->stats.rx_fifo_errors++;
 			head->flag &= (RMD1_ENP|RMD1_STP);
 		} else {
 			/* Malloc up new buffer, compatible with net-3. */
@@ -814,7 +803,7 @@
 
 			if (pkt_len < 60) {
 				printk( "%s: Runt packet!\n", dev->name );
-				lp->stats.rx_errors++;
+				dev->stats.rx_errors++;
 			}
 			else {
 				skb = dev_alloc_skb( pkt_len+2 );
@@ -822,7 +811,7 @@
 					DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n",
 						      dev->name ));
 
-					lp->stats.rx_dropped++;
+					dev->stats.rx_dropped++;
 					head->msg_length = 0;
 					head->flag |= RMD1_OWN_CHIP;
 					lp->new_rx = (lp->new_rx+1) &
@@ -831,13 +820,14 @@
 
 #if 0
 				if (lance_debug >= 3) {
-					u_char *data = PKTBUF_ADDR(head), *p;
-					printk( "%s: RX pkt %d type 0x%04x from ", dev->name, entry, ((u_short *)data)[6]);
-					for( p = &data[6], i = 0; i < 6; i++ )
-						printk("%02x%s", *p++, i != 5 ? ":" : "" );
-					printk(" to ");
-					for( p = data, i = 0; i < 6; i++ )
-						printk("%02x%s", *p++, i != 5 ? ":" : "" );
+					u_char *data = PKTBUF_ADDR(head);
+					DECLARE_MAC_BUF(mac);
+					DECLARE_MAC_BUF(mac2)
+					printk("%s: RX pkt %d type 0x%04x"
+					       " from %s to %s",
+					       dev->name, lp->new_tx, ((u_short *)data)[6],
+					       print_mac(mac, &data[6]), print_mac(mac2, data));
+
 					printk(" data %02x %02x %02x %02x %02x %02x %02x %02x "
 					       "len %d at %08x\n",
 					       data[15], data[16], data[17], data[18],
@@ -860,8 +850,8 @@
 				skb->protocol = eth_type_trans( skb, dev );
 				netif_rx( skb );
 				dev->last_rx = jiffies;
-				lp->stats.rx_packets++;
-				lp->stats.rx_bytes += pkt_len;
+				dev->stats.rx_packets++;
+				dev->stats.rx_bytes += pkt_len;
 			}
 		}
 
@@ -898,14 +888,6 @@
 }
 
 
-static struct net_device_stats *lance_get_stats( struct net_device *dev )
-{
-	struct lance_private *lp = netdev_priv(dev);
-
-	return &lp->stats;
-}
-
-
 /* Set or clear the multicast filter for this adaptor.
    num_addrs == -1		Promiscuous mode, receive all packets
    num_addrs == 0		Normal mode, clear multicast list
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index b3e0158..fe3ac6f 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -1082,12 +1082,12 @@
 	struct bigmac *bp;
 	u8 bsizes, bsizes_more;
 	int i;
+	DECLARE_MAC_BUF(mac);
 
 	/* Get a new device struct for this interface. */
 	dev = alloc_etherdev(sizeof(struct bigmac));
 	if (!dev)
 		return -ENOMEM;
-	SET_MODULE_OWNER(dev);
 
 	if (version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
@@ -1227,11 +1227,8 @@
 
 	dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp);
 
-	printk(KERN_INFO "%s: BigMAC 100baseT Ethernet ", dev->name);
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", dev->dev_addr[i],
-		       i == 5 ? ' ' : ':');
-	printk("\n");
+	printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %s\n",
+	       dev->name, print_mac(mac, dev->dev_addr));
 
 	return 0;
 
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index af0c983..ff98f5d 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -466,8 +466,8 @@
 #else
 	int bar = 1;
 #endif
-	int phy, phy_idx = 0;
-
+	int phy, phy_end, phy_idx = 0;
+	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -485,7 +485,6 @@
 	dev = alloc_etherdev(sizeof(*np));
 	if (!dev)
 		return -ENOMEM;
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	if (pci_request_regions(pdev, DRV_NAME))
@@ -547,19 +546,25 @@
 	if (i)
 		goto err_out_unmap_rx;
 
-	printk(KERN_INFO "%s: %s at %p, ",
-		   dev->name, pci_id_tbl[chip_idx].name, ioaddr);
-	for (i = 0; i < 5; i++)
-			printk("%2.2x:", dev->dev_addr[i]);
-	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+	printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",
+	       dev->name, pci_id_tbl[chip_idx].name, ioaddr,
+	       print_mac(mac, dev->dev_addr), irq);
 
 	np->phys[0] = 1;		/* Default setting */
 	np->mii_preamble_required++;
+
 	/*
 	 * It seems some phys doesn't deal well with address 0 being accessed
-	 * first, so leave address zero to the end of the loop (32 & 31).
+	 * first
 	 */
-	for (phy = 1; phy <= 32 && phy_idx < MII_CNT; phy++) {
+	if (sundance_pci_tbl[np->chip_id].device == 0x0200) {
+		phy = 0;
+		phy_end = 31;
+	} else {
+		phy = 1;
+		phy_end = 32;	/* wraps to zero, due to 'phy & 0x1f' */
+	}
+	for (; phy <= phy_end && phy_idx < MII_CNT; phy++) {
 		int phyx = phy & 0x1f;
 		int mii_status = mdio_read(dev, phyx, MII_BMSR);
 		if (mii_status != 0xffff  &&  mii_status != 0x0000) {
@@ -1586,7 +1591,6 @@
 	.get_link = get_link,
 	.get_msglevel = get_msglevel,
 	.set_msglevel = set_msglevel,
-	.get_perm_addr = ethtool_op_get_perm_addr,
 };
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 4328038..53b8344 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -19,7 +19,7 @@
  *
  *    gem_change_mtu() and gem_set_multicast() are called with a read_lock()
  *    help by net/core/dev.c, thus they can't schedule. That means they can't
- *    call netif_poll_disable() neither, thus force gem_poll() to keep a spinlock
+ *    call napi_disable() neither, thus force gem_poll() to keep a spinlock
  *    where it could have been dropped. change_mtu especially would love also to
  *    be able to msleep instead of horrid locked delays when resetting the HW,
  *    but that read_lock() makes it impossible, unless I defer it's action to
@@ -878,19 +878,20 @@
 	return work_done;
 }
 
-static int gem_poll(struct net_device *dev, int *budget)
+static int gem_poll(struct napi_struct *napi, int budget)
 {
-	struct gem *gp = dev->priv;
+	struct gem *gp = container_of(napi, struct gem, napi);
+	struct net_device *dev = gp->dev;
 	unsigned long flags;
+	int work_done;
 
 	/*
 	 * NAPI locking nightmare: See comment at head of driver
 	 */
 	spin_lock_irqsave(&gp->lock, flags);
 
+	work_done = 0;
 	do {
-		int work_to_do, work_done;
-
 		/* Handle anomalies */
 		if (gp->status & GREG_STAT_ABNORMAL) {
 			if (gem_abnormal_irq(dev, gp, gp->status))
@@ -906,29 +907,25 @@
 
 		/* Run RX thread. We don't use any locking here,
 		 * code willing to do bad things - like cleaning the
-		 * rx ring - must call netif_poll_disable(), which
+		 * rx ring - must call napi_disable(), which
 		 * schedule_timeout()'s if polling is already disabled.
 		 */
-		work_to_do = min(*budget, dev->quota);
+		work_done += gem_rx(gp, budget);
 
-		work_done = gem_rx(gp, work_to_do);
-
-		*budget -= work_done;
-		dev->quota -= work_done;
-
-		if (work_done >= work_to_do)
-			return 1;
+		if (work_done >= budget)
+			return work_done;
 
 		spin_lock_irqsave(&gp->lock, flags);
 
 		gp->status = readl(gp->regs + GREG_STAT);
 	} while (gp->status & GREG_STAT_NAPI);
 
-	__netif_rx_complete(dev);
+	__netif_rx_complete(dev, napi);
 	gem_enable_ints(gp);
 
 	spin_unlock_irqrestore(&gp->lock, flags);
-	return 0;
+
+	return work_done;
 }
 
 static irqreturn_t gem_interrupt(int irq, void *dev_id)
@@ -946,17 +943,17 @@
 
 	spin_lock_irqsave(&gp->lock, flags);
 
-	if (netif_rx_schedule_prep(dev)) {
+	if (netif_rx_schedule_prep(dev, &gp->napi)) {
 		u32 gem_status = readl(gp->regs + GREG_STAT);
 
 		if (gem_status == 0) {
-			netif_poll_enable(dev);
+			napi_enable(&gp->napi);
 			spin_unlock_irqrestore(&gp->lock, flags);
 			return IRQ_NONE;
 		}
 		gp->status = gem_status;
 		gem_disable_ints(gp);
-		__netif_rx_schedule(dev);
+		__netif_rx_schedule(dev, &gp->napi);
 	}
 
 	spin_unlock_irqrestore(&gp->lock, flags);
@@ -2284,7 +2281,7 @@
 
 	mutex_lock(&gp->pm_mutex);
 
-	netif_poll_disable(gp->dev);
+	napi_disable(&gp->napi);
 
 	spin_lock_irq(&gp->lock);
 	spin_lock(&gp->tx_lock);
@@ -2307,7 +2304,7 @@
 	spin_unlock(&gp->tx_lock);
 	spin_unlock_irq(&gp->lock);
 
-	netif_poll_enable(gp->dev);
+	napi_enable(&gp->napi);
 
 	mutex_unlock(&gp->pm_mutex);
 }
@@ -2324,6 +2321,8 @@
 	if (!gp->asleep)
 		rc = gem_do_start(dev);
 	gp->opened = (rc == 0);
+	if (gp->opened)
+		napi_enable(&gp->napi);
 
 	mutex_unlock(&gp->pm_mutex);
 
@@ -2334,9 +2333,7 @@
 {
 	struct gem *gp = dev->priv;
 
-	/* Note: we don't need to call netif_poll_disable() here because
-	 * our caller (dev_close) already did it for us
-	 */
+	napi_disable(&gp->napi);
 
 	mutex_lock(&gp->pm_mutex);
 
@@ -2358,7 +2355,7 @@
 
 	mutex_lock(&gp->pm_mutex);
 
-	netif_poll_disable(dev);
+	napi_disable(&gp->napi);
 
 	printk(KERN_INFO "%s: suspending, WakeOnLan %s\n",
 	       dev->name,
@@ -2482,7 +2479,7 @@
 	spin_unlock(&gp->tx_lock);
 	spin_unlock_irqrestore(&gp->lock, flags);
 
-	netif_poll_enable(dev);
+	napi_enable(&gp->napi);
 
 	mutex_unlock(&gp->pm_mutex);
 
@@ -2968,7 +2965,8 @@
 	unsigned long gemreg_base, gemreg_len;
 	struct net_device *dev;
 	struct gem *gp;
-	int i, err, pci_using_dac;
+	int err, pci_using_dac;
+	DECLARE_MAC_BUF(mac);
 
 	if (gem_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
@@ -3026,7 +3024,6 @@
 		err = -ENOMEM;
 		goto err_disable_device;
 	}
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	gp = dev->priv;
@@ -3121,8 +3118,7 @@
 	dev->get_stats = gem_get_stats;
 	dev->set_multicast_list = gem_set_multicast;
 	dev->do_ioctl = gem_ioctl;
-	dev->poll = gem_poll;
-	dev->weight = 64;
+	netif_napi_add(dev, &gp->napi, gem_poll, 64);
 	dev->ethtool_ops = &gem_ethtool_ops;
 	dev->tx_timeout = gem_tx_timeout;
 	dev->watchdog_timeo = 5 * HZ;
@@ -3154,12 +3150,9 @@
 		goto err_out_free_consistent;
 	}
 
-	printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ",
-	       dev->name);
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", dev->dev_addr[i],
-		       i == 5 ? ' ' : ':');
-	printk("\n");
+	printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet "
+	       "%s\n",
+	       dev->name, print_mac(mac, dev->dev_addr));
 
 	if (gp->phy_type == phy_mii_mdio0 ||
      	    gp->phy_type == phy_mii_mdio1)
diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h
index 58cf87c..76d760a 100644
--- a/drivers/net/sungem.h
+++ b/drivers/net/sungem.h
@@ -993,6 +993,7 @@
 	u32			msg_enable;
 	u32			status;
 
+	struct napi_struct	napi;
 	struct net_device_stats net_stats;
 
 	int			tx_fifo_sz;
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index 8b35f13..120c8af 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -2664,6 +2664,7 @@
 	struct net_device *dev;
 	int i, qfe_slot = -1;
 	int err = -ENODEV;
+	DECLARE_MAC_BUF(mac);
 
 	if (is_qfe) {
 		qp = quattro_sbus_find(sdev);
@@ -2680,7 +2681,6 @@
 	dev = alloc_etherdev(sizeof(struct happy_meal));
 	if (!dev)
 		goto err_out;
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
 
 	if (hme_version_printed++ == 0)
@@ -2851,10 +2851,7 @@
 		printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ",
 		       dev->name);
 
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c",
-		       dev->dev_addr[i], i == 5 ? ' ' : ':');
-	printk("\n");
+	printk("%s\n", print_mac(mac, dev->dev_addr));
 
 	return 0;
 
@@ -2989,6 +2986,7 @@
 	int i, qfe_slot = -1;
 	char prom_name[64];
 	int err;
+	DECLARE_MAC_BUF(mac);
 
 	/* Now make sure pci_dev cookie is there. */
 #ifdef CONFIG_SPARC
@@ -3022,7 +3020,6 @@
 	err = -ENOMEM;
 	if (!dev)
 		goto err_out;
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	if (hme_version_printed++ == 0)
@@ -3203,10 +3200,7 @@
 		printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ",
 		       dev->name);
 
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? ' ' : ':');
-
-	printk("\n");
+	printk("%s\n", print_mac(mac, dev->dev_addr));
 
 	return 0;
 
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 053b7cb..26ade68 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -99,8 +99,7 @@
 #include <asm/byteorder.h>	/* Used by the checksum routines */
 #include <asm/idprom.h>
 #include <asm/sbus.h>
-#include <asm/openprom.h>
-#include <asm/oplib.h>
+#include <asm/prom.h>
 #include <asm/auxio.h>		/* For tpe-link-test? setting */
 #include <asm/irq.h>
 
@@ -249,7 +248,6 @@
 	int		rx_new, tx_new;
 	int		rx_old, tx_old;
 
-	struct net_device_stats	stats;
 	struct sbus_dma *ledma;	/* If set this points to ledma	*/
 	char		tpe;		/* cable-selection is TPE	*/
 	char		auto_select;	/* cable-selection by carrier	*/
@@ -520,17 +518,17 @@
 
 		/* We got an incomplete frame? */
 		if ((bits & LE_R1_POK) != LE_R1_POK) {
-			lp->stats.rx_over_errors++;
-			lp->stats.rx_errors++;
+			dev->stats.rx_over_errors++;
+			dev->stats.rx_errors++;
 		} else if (bits & LE_R1_ERR) {
 			/* Count only the end frame as a rx error,
 			 * not the beginning
 			 */
-			if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
-			if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
-			if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
-			if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
-			if (bits & LE_R1_EOP) lp->stats.rx_errors++;
+			if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++;
+			if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++;
+			if (bits & LE_R1_OFL) dev->stats.rx_over_errors++;
+			if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++;
+			if (bits & LE_R1_EOP) dev->stats.rx_errors++;
 		} else {
 			len = (rd->mblength & 0xfff) - 4;
 			skb = dev_alloc_skb(len + 2);
@@ -538,14 +536,14 @@
 			if (skb == NULL) {
 				printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n",
 				       dev->name);
-				lp->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 				rd->mblength = 0;
 				rd->rmd1_bits = LE_R1_OWN;
 				lp->rx_new = RX_NEXT(entry);
 				return;
 			}
 
-			lp->stats.rx_bytes += len;
+			dev->stats.rx_bytes += len;
 
 			skb_reserve(skb, 2);		/* 16 byte align */
 			skb_put(skb, len);		/* make room */
@@ -555,7 +553,7 @@
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
 			dev->last_rx = jiffies;
-			lp->stats.rx_packets++;
+			dev->stats.rx_packets++;
 		}
 
 		/* Return the packet to the pool */
@@ -587,12 +585,12 @@
 		if (bits & LE_T1_ERR) {
 			u16 status = td->misc;
 
-			lp->stats.tx_errors++;
-			if (status & LE_T3_RTY)  lp->stats.tx_aborted_errors++;
-			if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+			dev->stats.tx_errors++;
+			if (status & LE_T3_RTY)  dev->stats.tx_aborted_errors++;
+			if (status & LE_T3_LCOL) dev->stats.tx_window_errors++;
 
 			if (status & LE_T3_CLOS) {
-				lp->stats.tx_carrier_errors++;
+				dev->stats.tx_carrier_errors++;
 				if (lp->auto_select) {
 					lp->tpe = 1 - lp->tpe;
 					printk(KERN_NOTICE "%s: Carrier Lost, trying %s\n",
@@ -609,7 +607,7 @@
 			 * transmitter, restart the adapter.
 			 */
 			if (status & (LE_T3_BUF|LE_T3_UFL)) {
-				lp->stats.tx_fifo_errors++;
+				dev->stats.tx_fifo_errors++;
 
 				printk(KERN_ERR "%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
 				       dev->name);
@@ -627,13 +625,13 @@
 
 			/* One collision before packet was sent. */
 			if (bits & LE_T1_EONE)
-				lp->stats.collisions++;
+				dev->stats.collisions++;
 
 			/* More than one collision, be optimistic. */
 			if (bits & LE_T1_EMORE)
-				lp->stats.collisions += 2;
+				dev->stats.collisions += 2;
 
-			lp->stats.tx_packets++;
+			dev->stats.tx_packets++;
 		}
 
 		j = TX_NEXT(j);
@@ -693,17 +691,17 @@
 
 		/* We got an incomplete frame? */
 		if ((bits & LE_R1_POK) != LE_R1_POK) {
-			lp->stats.rx_over_errors++;
-			lp->stats.rx_errors++;
+			dev->stats.rx_over_errors++;
+			dev->stats.rx_errors++;
 		} else if (bits & LE_R1_ERR) {
 			/* Count only the end frame as a rx error,
 			 * not the beginning
 			 */
-			if (bits & LE_R1_BUF) lp->stats.rx_fifo_errors++;
-			if (bits & LE_R1_CRC) lp->stats.rx_crc_errors++;
-			if (bits & LE_R1_OFL) lp->stats.rx_over_errors++;
-			if (bits & LE_R1_FRA) lp->stats.rx_frame_errors++;
-			if (bits & LE_R1_EOP) lp->stats.rx_errors++;
+			if (bits & LE_R1_BUF) dev->stats.rx_fifo_errors++;
+			if (bits & LE_R1_CRC) dev->stats.rx_crc_errors++;
+			if (bits & LE_R1_OFL) dev->stats.rx_over_errors++;
+			if (bits & LE_R1_FRA) dev->stats.rx_frame_errors++;
+			if (bits & LE_R1_EOP) dev->stats.rx_errors++;
 		} else {
 			len = (sbus_readw(&rd->mblength) & 0xfff) - 4;
 			skb = dev_alloc_skb(len + 2);
@@ -711,14 +709,14 @@
 			if (skb == NULL) {
 				printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n",
 				       dev->name);
-				lp->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 				sbus_writew(0, &rd->mblength);
 				sbus_writeb(LE_R1_OWN, &rd->rmd1_bits);
 				lp->rx_new = RX_NEXT(entry);
 				return;
 			}
 
-			lp->stats.rx_bytes += len;
+			dev->stats.rx_bytes += len;
 
 			skb_reserve (skb, 2);		/* 16 byte align */
 			skb_put(skb, len);		/* make room */
@@ -726,7 +724,7 @@
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
 			dev->last_rx = jiffies;
-			lp->stats.rx_packets++;
+			dev->stats.rx_packets++;
 		}
 
 		/* Return the packet to the pool */
@@ -758,12 +756,12 @@
 		if (bits & LE_T1_ERR) {
 			u16 status = sbus_readw(&td->misc);
 
-			lp->stats.tx_errors++;
-			if (status & LE_T3_RTY)  lp->stats.tx_aborted_errors++;
-			if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
+			dev->stats.tx_errors++;
+			if (status & LE_T3_RTY)  dev->stats.tx_aborted_errors++;
+			if (status & LE_T3_LCOL) dev->stats.tx_window_errors++;
 
 			if (status & LE_T3_CLOS) {
-				lp->stats.tx_carrier_errors++;
+				dev->stats.tx_carrier_errors++;
 				if (lp->auto_select) {
 					lp->tpe = 1 - lp->tpe;
 					printk(KERN_NOTICE "%s: Carrier Lost, trying %s\n",
@@ -780,7 +778,7 @@
 			 * transmitter, restart the adapter.
 			 */
 			if (status & (LE_T3_BUF|LE_T3_UFL)) {
-				lp->stats.tx_fifo_errors++;
+				dev->stats.tx_fifo_errors++;
 
 				printk(KERN_ERR "%s: Tx: ERR_BUF|ERR_UFL, restarting\n",
 				       dev->name);
@@ -798,13 +796,13 @@
 
 			/* One collision before packet was sent. */
 			if (bits & LE_T1_EONE)
-				lp->stats.collisions++;
+				dev->stats.collisions++;
 
 			/* More than one collision, be optimistic. */
 			if (bits & LE_T1_EMORE)
-				lp->stats.collisions += 2;
+				dev->stats.collisions += 2;
 
-			lp->stats.tx_packets++;
+			dev->stats.tx_packets++;
 		}
 
 		j = TX_NEXT(j);
@@ -845,10 +843,10 @@
 		lp->tx(dev);
 
 	if (csr0 & LE_C0_BABL)
-		lp->stats.tx_errors++;
+		dev->stats.tx_errors++;
 
 	if (csr0 & LE_C0_MISS)
-		lp->stats.rx_errors++;
+		dev->stats.rx_errors++;
 
 	if (csr0 & LE_C0_MERR) {
 		if (lp->dregs) {
@@ -1128,7 +1126,7 @@
 
 	spin_lock_irq(&lp->lock);
 
-	lp->stats.tx_bytes += len;
+	dev->stats.tx_bytes += len;
 
 	entry = lp->tx_new & TX_RING_MOD_MASK;
 	if (lp->pio_buffer) {
@@ -1171,13 +1169,6 @@
 	return 0;
 }
 
-static struct net_device_stats *lance_get_stats(struct net_device *dev)
-{
-	struct lance_private *lp = netdev_priv(dev);
-
-	return &lp->stats;
-}
-
 /* taken from the depca driver */
 static void lance_load_multicast(struct net_device *dev)
 {
@@ -1326,16 +1317,17 @@
 					   struct sbus_dev *lebuffer)
 {
 	static unsigned version_printed;
+	struct device_node *dp = sdev->ofdev.node;
 	struct net_device *dev;
 	struct lance_private *lp;
 	int    i;
+	DECLARE_MAC_BUF(mac);
 
 	dev = alloc_etherdev(sizeof(struct lance_private) + 8);
 	if (!dev)
 		return -ENOMEM;
 
 	lp = netdev_priv(dev);
-	memset(lp, 0, sizeof(*lp));
 
 	if (sparc_lance_debug && version_printed++ == 0)
 		printk (KERN_INFO "%s", version);
@@ -1389,54 +1381,46 @@
 		lp->rx = lance_rx_dvma;
 		lp->tx = lance_tx_dvma;
 	}
-	lp->busmaster_regval = prom_getintdefault(sdev->prom_node,
-						  "busmaster-regval",
-						  (LE_C3_BSWP | LE_C3_ACON |
-						   LE_C3_BCON));
+	lp->busmaster_regval = of_getintprop_default(dp,  "busmaster-regval",
+						     (LE_C3_BSWP |
+						      LE_C3_ACON |
+						      LE_C3_BCON));
 
 	lp->name = lancestr;
 	lp->ledma = ledma;
 
 	lp->burst_sizes = 0;
 	if (lp->ledma) {
-		char prop[6];
+		struct device_node *ledma_dp = ledma->sdev->ofdev.node;
+		const char *prop;
 		unsigned int sbmask;
 		u32 csr;
 
 		/* Find burst-size property for ledma */
-		lp->burst_sizes = prom_getintdefault(ledma->sdev->prom_node,
-						     "burst-sizes", 0);
+		lp->burst_sizes = of_getintprop_default(ledma_dp,
+							"burst-sizes", 0);
 
 		/* ledma may be capable of fast bursts, but sbus may not. */
-		sbmask = prom_getintdefault(ledma->sdev->bus->prom_node,
-					    "burst-sizes", DMA_BURSTBITS);
+		sbmask = of_getintprop_default(ledma_dp, "burst-sizes",
+					       DMA_BURSTBITS);
 		lp->burst_sizes &= sbmask;
 
 		/* Get the cable-selection property */
-		memset(prop, 0, sizeof(prop));
-		prom_getstring(ledma->sdev->prom_node, "cable-selection",
-			       prop, sizeof(prop));
-		if (prop[0] == 0) {
-			int topnd, nd;
+		prop = of_get_property(ledma_dp, "cable-selection", NULL);
+		if (!prop || prop[0] == '\0') {
+			struct device_node *nd;
 
-			printk(KERN_INFO "SunLance: using auto-carrier-detection.\n");
+			printk(KERN_INFO "SunLance: using "
+			       "auto-carrier-detection.\n");
 
-			/* Is this found at /options .attributes in all
-			 * Prom versions? XXX
-			 */
-			topnd = prom_getchild(prom_root_node);
-
-			nd = prom_searchsiblings(topnd, "options");
+			nd = of_find_node_by_path("/options");
 			if (!nd)
 				goto no_link_test;
 
-			if (!prom_node_has_property(nd, "tpe-link-test?"))
+			prop = of_get_property(nd, "tpe-link-test?", NULL);
+			if (!prop)
 				goto no_link_test;
 
-			memset(prop, 0, sizeof(prop));
-			prom_getstring(nd, "tpe-link-test?", prop,
-				       sizeof(prop));
-
 			if (strcmp(prop, "true")) {
 				printk(KERN_NOTICE "SunLance: warning: overriding option "
 				       "'tpe-link-test?'\n");
@@ -1466,14 +1450,12 @@
 		lp->dregs = NULL;
 
 	lp->dev = dev;
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
 	dev->open = &lance_open;
 	dev->stop = &lance_close;
 	dev->hard_start_xmit = &lance_start_xmit;
 	dev->tx_timeout = &lance_tx_timeout;
 	dev->watchdog_timeo = 5*HZ;
-	dev->get_stats = &lance_get_stats;
 	dev->set_multicast_list = &lance_set_multicast;
 	dev->ethtool_ops = &sparc_lance_ethtool_ops;
 
@@ -1497,12 +1479,8 @@
 
 	dev_set_drvdata(&sdev->ofdev.dev, lp);
 
-	printk(KERN_INFO "%s: LANCE ", dev->name);
-
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", dev->dev_addr[i],
-		       i == 5 ? ' ': ':');
-	printk("\n");
+	printk(KERN_INFO "%s: LANCE %s\n",
+	       dev->name, print_mac(mac, dev->dev_addr));
 
 	return 0;
 
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index 1b65ae8..ff23c64 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -260,31 +260,31 @@
 
 	if (qe_status & CREG_STAT_EDEFER) {
 		printk(KERN_ERR "%s: Excessive transmit defers.\n", dev->name);
-		qep->net_stats.tx_errors++;
+		dev->stats.tx_errors++;
 	}
 
 	if (qe_status & CREG_STAT_CLOSS) {
 		printk(KERN_ERR "%s: Carrier lost, link down?\n", dev->name);
-		qep->net_stats.tx_errors++;
-		qep->net_stats.tx_carrier_errors++;
+		dev->stats.tx_errors++;
+		dev->stats.tx_carrier_errors++;
 	}
 
 	if (qe_status & CREG_STAT_ERETRIES) {
 		printk(KERN_ERR "%s: Excessive transmit retries (more than 16).\n", dev->name);
-		qep->net_stats.tx_errors++;
+		dev->stats.tx_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if (qe_status & CREG_STAT_LCOLL) {
 		printk(KERN_ERR "%s: Late transmit collision.\n", dev->name);
-		qep->net_stats.tx_errors++;
-		qep->net_stats.collisions++;
+		dev->stats.tx_errors++;
+		dev->stats.collisions++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if (qe_status & CREG_STAT_FUFLOW) {
 		printk(KERN_ERR "%s: Transmit fifo underflow, driver bug.\n", dev->name);
-		qep->net_stats.tx_errors++;
+		dev->stats.tx_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
@@ -297,104 +297,104 @@
 	}
 
 	if (qe_status & CREG_STAT_CCOFLOW) {
-		qep->net_stats.tx_errors += 256;
-		qep->net_stats.collisions += 256;
+		dev->stats.tx_errors += 256;
+		dev->stats.collisions += 256;
 	}
 
 	if (qe_status & CREG_STAT_TXDERROR) {
 		printk(KERN_ERR "%s: Transmit descriptor is bogus, driver bug.\n", dev->name);
-		qep->net_stats.tx_errors++;
-		qep->net_stats.tx_aborted_errors++;
+		dev->stats.tx_errors++;
+		dev->stats.tx_aborted_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if (qe_status & CREG_STAT_TXLERR) {
 		printk(KERN_ERR "%s: Transmit late error.\n", dev->name);
-		qep->net_stats.tx_errors++;
+		dev->stats.tx_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if (qe_status & CREG_STAT_TXPERR) {
 		printk(KERN_ERR "%s: Transmit DMA parity error.\n", dev->name);
-		qep->net_stats.tx_errors++;
-		qep->net_stats.tx_aborted_errors++;
+		dev->stats.tx_errors++;
+		dev->stats.tx_aborted_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if (qe_status & CREG_STAT_TXSERR) {
 		printk(KERN_ERR "%s: Transmit DMA sbus error ack.\n", dev->name);
-		qep->net_stats.tx_errors++;
-		qep->net_stats.tx_aborted_errors++;
+		dev->stats.tx_errors++;
+		dev->stats.tx_aborted_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if (qe_status & CREG_STAT_RCCOFLOW) {
-		qep->net_stats.rx_errors += 256;
-		qep->net_stats.collisions += 256;
+		dev->stats.rx_errors += 256;
+		dev->stats.collisions += 256;
 	}
 
 	if (qe_status & CREG_STAT_RUOFLOW) {
-		qep->net_stats.rx_errors += 256;
-		qep->net_stats.rx_over_errors += 256;
+		dev->stats.rx_errors += 256;
+		dev->stats.rx_over_errors += 256;
 	}
 
 	if (qe_status & CREG_STAT_MCOFLOW) {
-		qep->net_stats.rx_errors += 256;
-		qep->net_stats.rx_missed_errors += 256;
+		dev->stats.rx_errors += 256;
+		dev->stats.rx_missed_errors += 256;
 	}
 
 	if (qe_status & CREG_STAT_RXFOFLOW) {
 		printk(KERN_ERR "%s: Receive fifo overflow.\n", dev->name);
-		qep->net_stats.rx_errors++;
-		qep->net_stats.rx_over_errors++;
+		dev->stats.rx_errors++;
+		dev->stats.rx_over_errors++;
 	}
 
 	if (qe_status & CREG_STAT_RLCOLL) {
 		printk(KERN_ERR "%s: Late receive collision.\n", dev->name);
-		qep->net_stats.rx_errors++;
-		qep->net_stats.collisions++;
+		dev->stats.rx_errors++;
+		dev->stats.collisions++;
 	}
 
 	if (qe_status & CREG_STAT_FCOFLOW) {
-		qep->net_stats.rx_errors += 256;
-		qep->net_stats.rx_frame_errors += 256;
+		dev->stats.rx_errors += 256;
+		dev->stats.rx_frame_errors += 256;
 	}
 
 	if (qe_status & CREG_STAT_CECOFLOW) {
-		qep->net_stats.rx_errors += 256;
-		qep->net_stats.rx_crc_errors += 256;
+		dev->stats.rx_errors += 256;
+		dev->stats.rx_crc_errors += 256;
 	}
 
 	if (qe_status & CREG_STAT_RXDROP) {
 		printk(KERN_ERR "%s: Receive packet dropped.\n", dev->name);
-		qep->net_stats.rx_errors++;
-		qep->net_stats.rx_dropped++;
-		qep->net_stats.rx_missed_errors++;
+		dev->stats.rx_errors++;
+		dev->stats.rx_dropped++;
+		dev->stats.rx_missed_errors++;
 	}
 
 	if (qe_status & CREG_STAT_RXSMALL) {
 		printk(KERN_ERR "%s: Receive buffer too small, driver bug.\n", dev->name);
-		qep->net_stats.rx_errors++;
-		qep->net_stats.rx_length_errors++;
+		dev->stats.rx_errors++;
+		dev->stats.rx_length_errors++;
 	}
 
 	if (qe_status & CREG_STAT_RXLERR) {
 		printk(KERN_ERR "%s: Receive late error.\n", dev->name);
-		qep->net_stats.rx_errors++;
+		dev->stats.rx_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if (qe_status & CREG_STAT_RXPERR) {
 		printk(KERN_ERR "%s: Receive DMA parity error.\n", dev->name);
-		qep->net_stats.rx_errors++;
-		qep->net_stats.rx_missed_errors++;
+		dev->stats.rx_errors++;
+		dev->stats.rx_missed_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
 	if (qe_status & CREG_STAT_RXSERR) {
 		printk(KERN_ERR "%s: Receive DMA sbus error ack.\n", dev->name);
-		qep->net_stats.rx_errors++;
-		qep->net_stats.rx_missed_errors++;
+		dev->stats.rx_errors++;
+		dev->stats.rx_missed_errors++;
 		mace_hwbug_workaround = 1;
 	}
 
@@ -409,6 +409,7 @@
 static void qe_rx(struct sunqe *qep)
 {
 	struct qe_rxd *rxbase = &qep->qe_block->qe_rxd[0];
+	struct net_device *dev = qep->dev;
 	struct qe_rxd *this;
 	struct sunqe_buffers *qbufs = qep->buffers;
 	__u32 qbufs_dvma = qep->buffers_dvma;
@@ -428,14 +429,14 @@
 
 		/* Check for errors. */
 		if (len < ETH_ZLEN) {
-			qep->net_stats.rx_errors++;
-			qep->net_stats.rx_length_errors++;
-			qep->net_stats.rx_dropped++;
+			dev->stats.rx_errors++;
+			dev->stats.rx_length_errors++;
+			dev->stats.rx_dropped++;
 		} else {
 			skb = dev_alloc_skb(len + 2);
 			if (skb == NULL) {
 				drops++;
-				qep->net_stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 			} else {
 				skb_reserve(skb, 2);
 				skb_put(skb, len);
@@ -444,8 +445,8 @@
 				skb->protocol = eth_type_trans(skb, qep->dev);
 				netif_rx(skb);
 				qep->dev->last_rx = jiffies;
-				qep->net_stats.rx_packets++;
-				qep->net_stats.rx_bytes += len;
+				dev->stats.rx_packets++;
+				dev->stats.rx_bytes += len;
 			}
 		}
 		end_rxd->rx_addr = this_qbuf_dvma;
@@ -603,8 +604,8 @@
 	dev->trans_start = jiffies;
 	sbus_writel(CREG_CTRL_TWAKEUP, qep->qcregs + CREG_CTRL);
 
-	qep->net_stats.tx_packets++;
-	qep->net_stats.tx_bytes += len;
+	dev->stats.tx_packets++;
+	dev->stats.tx_bytes += len;
 
 	if (TX_BUFFS_AVAIL(qep) <= 0) {
 		/* Halt the net queue and enable tx interrupts.
@@ -622,13 +623,6 @@
 	return 0;
 }
 
-static struct net_device_stats *qe_get_stats(struct net_device *dev)
-{
-	struct sunqe *qep = (struct sunqe *) dev->priv;
-
-	return &qep->net_stats;
-}
-
 static void qe_set_multicast(struct net_device *dev)
 {
 	struct sunqe *qep = (struct sunqe *) dev->priv;
@@ -898,13 +892,11 @@
 	/* Stop this QE. */
 	qe_stop(qe);
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
 
 	dev->open = qe_open;
 	dev->stop = qe_close;
 	dev->hard_start_xmit = qe_start_xmit;
-	dev->get_stats = qe_get_stats;
 	dev->set_multicast_list = qe_set_multicast;
 	dev->tx_timeout = qe_tx_timeout;
 	dev->watchdog_timeo = 5*HZ;
diff --git a/drivers/net/sunqe.h b/drivers/net/sunqe.h
index af34f36..347c8dd 100644
--- a/drivers/net/sunqe.h
+++ b/drivers/net/sunqe.h
@@ -342,7 +342,6 @@
 	__u32				buffers_dvma;	/* DVMA visible address.       */
 	struct sunqec			*parent;
 	u8				mconfig;	/* Base MACE mconfig value     */
-	struct net_device_stats		net_stats;	/* Statistical counters        */
 	struct sbus_dev			*qe_sdev;	/* QE's SBUS device struct     */
 	struct net_device		*dev;		/* QE's netdevice struct       */
 	int				channel;	/* Who am I?                   */
diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c
index 8a667c1..ff1028a 100644
--- a/drivers/net/sunvnet.c
+++ b/drivers/net/sunvnet.c
@@ -12,6 +12,7 @@
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
 #include <linux/etherdevice.h>
+#include <linux/mutex.h>
 
 #include <asm/vio.h>
 #include <asm/ldc.h>
@@ -458,6 +459,22 @@
 	return 0;
 }
 
+static int handle_mcast(struct vnet_port *port, void *msgbuf)
+{
+	struct vio_net_mcast_info *pkt = msgbuf;
+
+	if (pkt->tag.stype != VIO_SUBTYPE_ACK)
+		printk(KERN_ERR PFX "%s: Got unexpected MCAST reply "
+		       "[%02x:%02x:%04x:%08x]\n",
+		       port->vp->dev->name,
+		       pkt->tag.type,
+		       pkt->tag.stype,
+		       pkt->tag.stype_env,
+		       pkt->tag.sid);
+
+	return 0;
+}
+
 static void maybe_tx_wakeup(struct vnet *vp)
 {
 	struct net_device *dev = vp->dev;
@@ -497,6 +514,8 @@
 		vio_link_state_change(vio, event);
 		spin_unlock_irqrestore(&vio->lock, flags);
 
+		if (event == LDC_EVENT_RESET)
+			vio_port_up(vio);
 		return;
 	}
 
@@ -541,7 +560,10 @@
 				err = vnet_nack(port, &msgbuf);
 			}
 		} else if (msgbuf.tag.type == VIO_TYPE_CTRL) {
-			err = vio_control_pkt_engine(vio, &msgbuf);
+			if (msgbuf.tag.stype_env == VNET_MCAST_INFO)
+				err = handle_mcast(port, &msgbuf);
+			else
+				err = vio_control_pkt_engine(vio, &msgbuf);
 			if (err)
 				break;
 		} else {
@@ -728,9 +750,122 @@
 	return 0;
 }
 
+static struct vnet_mcast_entry *__vnet_mc_find(struct vnet *vp, u8 *addr)
+{
+	struct vnet_mcast_entry *m;
+
+	for (m = vp->mcast_list; m; m = m->next) {
+		if (!memcmp(m->addr, addr, ETH_ALEN))
+			return m;
+	}
+	return NULL;
+}
+
+static void __update_mc_list(struct vnet *vp, struct net_device *dev)
+{
+	struct dev_addr_list *p;
+
+	for (p = dev->mc_list; p; p = p->next) {
+		struct vnet_mcast_entry *m;
+
+		m = __vnet_mc_find(vp, p->dmi_addr);
+		if (m) {
+			m->hit = 1;
+			continue;
+		}
+
+		if (!m) {
+			m = kzalloc(sizeof(*m), GFP_ATOMIC);
+			if (!m)
+				continue;
+			memcpy(m->addr, p->dmi_addr, ETH_ALEN);
+			m->hit = 1;
+
+			m->next = vp->mcast_list;
+			vp->mcast_list = m;
+		}
+	}
+}
+
+static void __send_mc_list(struct vnet *vp, struct vnet_port *port)
+{
+	struct vio_net_mcast_info info;
+	struct vnet_mcast_entry *m, **pp;
+	int n_addrs;
+
+	memset(&info, 0, sizeof(info));
+
+	info.tag.type = VIO_TYPE_CTRL;
+	info.tag.stype = VIO_SUBTYPE_INFO;
+	info.tag.stype_env = VNET_MCAST_INFO;
+	info.tag.sid = vio_send_sid(&port->vio);
+	info.set = 1;
+
+	n_addrs = 0;
+	for (m = vp->mcast_list; m; m = m->next) {
+		if (m->sent)
+			continue;
+		m->sent = 1;
+		memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
+		       m->addr, ETH_ALEN);
+		if (++n_addrs == VNET_NUM_MCAST) {
+			info.count = n_addrs;
+
+			(void) vio_ldc_send(&port->vio, &info,
+					    sizeof(info));
+			n_addrs = 0;
+		}
+	}
+	if (n_addrs) {
+		info.count = n_addrs;
+		(void) vio_ldc_send(&port->vio, &info, sizeof(info));
+	}
+
+	info.set = 0;
+
+	n_addrs = 0;
+	pp = &vp->mcast_list;
+	while ((m = *pp) != NULL) {
+		if (m->hit) {
+			m->hit = 0;
+			pp = &m->next;
+			continue;
+		}
+
+		memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
+		       m->addr, ETH_ALEN);
+		if (++n_addrs == VNET_NUM_MCAST) {
+			info.count = n_addrs;
+			(void) vio_ldc_send(&port->vio, &info,
+					    sizeof(info));
+			n_addrs = 0;
+		}
+
+		*pp = m->next;
+		kfree(m);
+	}
+	if (n_addrs) {
+		info.count = n_addrs;
+		(void) vio_ldc_send(&port->vio, &info, sizeof(info));
+	}
+}
+
 static void vnet_set_rx_mode(struct net_device *dev)
 {
-	/* XXX Implement multicast support XXX */
+	struct vnet *vp = netdev_priv(dev);
+	struct vnet_port *port;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vp->lock, flags);
+	if (!list_empty(&vp->port_list)) {
+		port = list_entry(vp->port_list.next, struct vnet_port, list);
+
+		if (port->switch_port) {
+			__update_mc_list(vp, dev);
+			__send_mc_list(vp, port);
+		}
+	}
+	spin_unlock_irqrestore(&vp->lock, flags);
 }
 
 static int vnet_change_mtu(struct net_device *dev, int new_mtu)
@@ -771,7 +906,6 @@
 	.get_msglevel		= vnet_get_msglevel,
 	.set_msglevel		= vnet_set_msglevel,
 	.get_link		= ethtool_op_get_link,
-	.get_perm_addr		= ethtool_op_get_perm_addr,
 };
 
 static void vnet_port_free_tx_bufs(struct vnet_port *port)
@@ -875,6 +1009,115 @@
 	return err;
 }
 
+static LIST_HEAD(vnet_list);
+static DEFINE_MUTEX(vnet_list_mutex);
+
+static struct vnet * __devinit vnet_new(const u64 *local_mac)
+{
+	struct net_device *dev;
+	struct vnet *vp;
+	int err, i;
+
+	dev = alloc_etherdev(sizeof(*vp));
+	if (!dev) {
+		printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	for (i = 0; i < ETH_ALEN; i++)
+		dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff;
+
+	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
+
+	vp = netdev_priv(dev);
+
+	spin_lock_init(&vp->lock);
+	vp->dev = dev;
+
+	INIT_LIST_HEAD(&vp->port_list);
+	for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
+		INIT_HLIST_HEAD(&vp->port_hash[i]);
+	INIT_LIST_HEAD(&vp->list);
+	vp->local_mac = *local_mac;
+
+	dev->open = vnet_open;
+	dev->stop = vnet_close;
+	dev->set_multicast_list = vnet_set_rx_mode;
+	dev->set_mac_address = vnet_set_mac_addr;
+	dev->tx_timeout = vnet_tx_timeout;
+	dev->ethtool_ops = &vnet_ethtool_ops;
+	dev->watchdog_timeo = VNET_TX_TIMEOUT;
+	dev->change_mtu = vnet_change_mtu;
+	dev->hard_start_xmit = vnet_start_xmit;
+
+	err = register_netdev(dev);
+	if (err) {
+		printk(KERN_ERR PFX "Cannot register net device, "
+		       "aborting.\n");
+		goto err_out_free_dev;
+	}
+
+	printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
+
+	for (i = 0; i < 6; i++)
+		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+
+	list_add(&vp->list, &vnet_list);
+
+	return vp;
+
+err_out_free_dev:
+	free_netdev(dev);
+
+	return ERR_PTR(err);
+}
+
+static struct vnet * __devinit vnet_find_or_create(const u64 *local_mac)
+{
+	struct vnet *iter, *vp;
+
+	mutex_lock(&vnet_list_mutex);
+	vp = NULL;
+	list_for_each_entry(iter, &vnet_list, list) {
+		if (iter->local_mac == *local_mac) {
+			vp = iter;
+			break;
+		}
+	}
+	if (!vp)
+		vp = vnet_new(local_mac);
+	mutex_unlock(&vnet_list_mutex);
+
+	return vp;
+}
+
+static const char *local_mac_prop = "local-mac-address";
+
+static struct vnet * __devinit vnet_find_parent(struct mdesc_handle *hp,
+						u64 port_node)
+{
+	const u64 *local_mac = NULL;
+	u64 a;
+
+	mdesc_for_each_arc(a, hp, port_node, MDESC_ARC_TYPE_BACK) {
+		u64 target = mdesc_arc_target(hp, a);
+		const char *name;
+
+		name = mdesc_get_property(hp, target, "name", NULL);
+		if (!name || strcmp(name, "network"))
+			continue;
+
+		local_mac = mdesc_get_property(hp, target,
+					       local_mac_prop, NULL);
+		if (local_mac)
+			break;
+	}
+	if (!local_mac)
+		return ERR_PTR(-ENODEV);
+
+	return vnet_find_or_create(local_mac);
+}
+
 static struct ldc_channel_config vnet_ldc_cfg = {
 	.event		= vnet_event,
 	.mtu		= 64,
@@ -887,6 +1130,14 @@
 	.handshake_complete	= vnet_handshake_complete,
 };
 
+static void print_version(void)
+{
+	static int version_printed;
+
+	if (version_printed++ == 0)
+		printk(KERN_INFO "%s", version);
+}
+
 const char *remote_macaddr_prop = "remote-mac-address";
 
 static int __devinit vnet_port_probe(struct vio_dev *vdev,
@@ -899,14 +1150,17 @@
 	const u64 *rmac;
 	int len, i, err, switch_port;
 
-	vp = dev_get_drvdata(vdev->dev.parent);
-	if (!vp) {
-		printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
-		return -ENODEV;
-	}
+	print_version();
 
 	hp = mdesc_grab();
 
+	vp = vnet_find_parent(hp, vdev->mp);
+	if (IS_ERR(vp)) {
+		printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
+		err = PTR_ERR(vp);
+		goto err_out_put_mdesc;
+	}
+
 	rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len);
 	err = -ENODEV;
 	if (!rmac) {
@@ -947,6 +1201,7 @@
 	switch_port = 0;
 	if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL)
 		switch_port = 1;
+	port->switch_port = switch_port;
 
 	spin_lock_irqsave(&vp->lock, flags);
 	if (switch_port)
@@ -1013,7 +1268,7 @@
 	},
 	{},
 };
-MODULE_DEVICE_TABLE(vio, vnet_match);
+MODULE_DEVICE_TABLE(vio, vnet_port_match);
 
 static struct vio_driver vnet_port_driver = {
 	.id_table	= vnet_port_match,
@@ -1025,139 +1280,14 @@
 	}
 };
 
-const char *local_mac_prop = "local-mac-address";
-
-static int __devinit vnet_probe(struct vio_dev *vdev,
-				const struct vio_device_id *id)
-{
-	static int vnet_version_printed;
-	struct mdesc_handle *hp;
-	struct net_device *dev;
-	struct vnet *vp;
-	const u64 *mac;
-	int err, i, len;
-
-	if (vnet_version_printed++ == 0)
-		printk(KERN_INFO "%s", version);
-
-	hp = mdesc_grab();
-
-	mac = mdesc_get_property(hp, vdev->mp, local_mac_prop, &len);
-	if (!mac) {
-		printk(KERN_ERR PFX "vnet lacks %s property.\n",
-		       local_mac_prop);
-		err = -ENODEV;
-		goto err_out;
-	}
-
-	dev = alloc_etherdev(sizeof(*vp));
-	if (!dev) {
-		printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
-		err = -ENOMEM;
-		goto err_out;
-	}
-
-	for (i = 0; i < ETH_ALEN; i++)
-		dev->dev_addr[i] = (*mac >> (5 - i) * 8) & 0xff;
-
-	memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
-
-	SET_NETDEV_DEV(dev, &vdev->dev);
-
-	vp = netdev_priv(dev);
-
-	spin_lock_init(&vp->lock);
-	vp->dev = dev;
-	vp->vdev = vdev;
-
-	INIT_LIST_HEAD(&vp->port_list);
-	for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
-		INIT_HLIST_HEAD(&vp->port_hash[i]);
-
-	dev->open = vnet_open;
-	dev->stop = vnet_close;
-	dev->set_multicast_list = vnet_set_rx_mode;
-	dev->set_mac_address = vnet_set_mac_addr;
-	dev->tx_timeout = vnet_tx_timeout;
-	dev->ethtool_ops = &vnet_ethtool_ops;
-	dev->watchdog_timeo = VNET_TX_TIMEOUT;
-	dev->change_mtu = vnet_change_mtu;
-	dev->hard_start_xmit = vnet_start_xmit;
-
-	err = register_netdev(dev);
-	if (err) {
-		printk(KERN_ERR PFX "Cannot register net device, "
-		       "aborting.\n");
-		goto err_out_free_dev;
-	}
-
-	printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
-
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
-
-	dev_set_drvdata(&vdev->dev, vp);
-
-	mdesc_release(hp);
-
-	return 0;
-
-err_out_free_dev:
-	free_netdev(dev);
-
-err_out:
-	mdesc_release(hp);
-	return err;
-}
-
-static int vnet_remove(struct vio_dev *vdev)
-{
-
-	struct vnet *vp = dev_get_drvdata(&vdev->dev);
-
-	if (vp) {
-		/* XXX unregister port, or at least check XXX */
-		unregister_netdevice(vp->dev);
-		dev_set_drvdata(&vdev->dev, NULL);
-	}
-	return 0;
-}
-
-static struct vio_device_id vnet_match[] = {
-	{
-		.type = "network",
-	},
-	{},
-};
-MODULE_DEVICE_TABLE(vio, vnet_match);
-
-static struct vio_driver vnet_driver = {
-	.id_table	= vnet_match,
-	.probe		= vnet_probe,
-	.remove		= vnet_remove,
-	.driver		= {
-		.name	= "vnet",
-		.owner	= THIS_MODULE,
-	}
-};
-
 static int __init vnet_init(void)
 {
-	int err = vio_register_driver(&vnet_driver);
-
-	if (!err) {
-		err = vio_register_driver(&vnet_port_driver);
-		if (err)
-			vio_unregister_driver(&vnet_driver);
-	}
-
-	return err;
+	return vio_register_driver(&vnet_port_driver);
 }
 
 static void __exit vnet_exit(void)
 {
 	vio_unregister_driver(&vnet_port_driver);
-	vio_unregister_driver(&vnet_driver);
 }
 
 module_init(vnet_init);
diff --git a/drivers/net/sunvnet.h b/drivers/net/sunvnet.h
index 1c88730..d347a5b 100644
--- a/drivers/net/sunvnet.h
+++ b/drivers/net/sunvnet.h
@@ -30,6 +30,8 @@
 
 	struct hlist_node	hash;
 	u8			raddr[ETH_ALEN];
+	u8			switch_port;
+	u8			__pad;
 
 	struct vnet		*vp;
 
@@ -53,6 +55,13 @@
 	return val & (VNET_PORT_HASH_MASK);
 }
 
+struct vnet_mcast_entry {
+	u8			addr[ETH_ALEN];
+	u8			sent;
+	u8			hit;
+	struct vnet_mcast_entry	*next;
+};
+
 struct vnet {
 	/* Protects port_list and port_hash.  */
 	spinlock_t		lock;
@@ -60,11 +69,15 @@
 	struct net_device	*dev;
 
 	u32			msg_enable;
-	struct vio_dev		*vdev;
 
 	struct list_head	port_list;
 
 	struct hlist_head	port_hash[VNET_PORT_HASH_SIZE];
+
+	struct vnet_mcast_entry	*mcast_list;
+
+	struct list_head	list;
+	u64			local_mac;
 };
 
 #endif /* _SUNVNET_H */
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index 75655ad..a679f43 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -414,6 +414,9 @@
 struct tc35815_local {
 	struct pci_dev *pci_dev;
 
+	struct net_device *dev;
+	struct napi_struct napi;
+
 	/* statistics */
 	struct net_device_stats stats;
 	struct {
@@ -566,7 +569,7 @@
 static irqreturn_t	tc35815_interrupt(int irq, void *dev_id);
 #ifdef TC35815_NAPI
 static int	tc35815_rx(struct net_device *dev, int limit);
-static int	tc35815_poll(struct net_device *dev, int *budget);
+static int	tc35815_poll(struct napi_struct *napi, int budget);
 #else
 static void	tc35815_rx(struct net_device *dev);
 #endif
@@ -626,7 +629,7 @@
 	return -ENODEV;
 }
 #else
-static int __devinit tc35815_read_plat_dev_addr(struct device *dev)
+static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev)
 {
 	return -ENODEV;
 }
@@ -682,9 +685,9 @@
 		dev_err(&pdev->dev, "unable to alloc new ethernet\n");
 		return -ENOMEM;
 	}
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 	lp = dev->priv;
+	lp->dev = dev;
 
 	/* enable device (incl. PCI PM wakeup), and bus-mastering */
 	rc = pci_enable_device (pdev);
@@ -738,8 +741,7 @@
 	dev->tx_timeout = tc35815_tx_timeout;
 	dev->watchdog_timeo = TC35815_TX_TIMEOUT;
 #ifdef TC35815_NAPI
-	dev->poll = tc35815_poll;
-	dev->weight = NAPI_WEIGHT;
+	netif_napi_add(dev, &lp->napi, tc35815_poll, NAPI_WEIGHT);
 #endif
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = tc35815_poll_controller;
@@ -748,8 +750,6 @@
 	dev->irq = pdev->irq;
 	dev->base_addr = (unsigned long) ioaddr;
 
-	/* dev->priv/lp zeroed and aligned in alloc_etherdev */
-	lp = dev->priv;
 	spin_lock_init(&lp->lock);
 	lp->pci_dev = pdev;
 	lp->boardtype = ent->driver_data;
@@ -1237,6 +1237,10 @@
 		return -EAGAIN;
 	}
 
+#ifdef TC35815_NAPI
+	napi_enable(&lp->napi);
+#endif
+
 	/* Reset the hardware here. Don't forget to set the station address. */
 	spin_lock_irq(&lp->lock);
 	tc35815_chip_init(dev);
@@ -1436,6 +1440,7 @@
 static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
 {
 	struct net_device *dev = dev_id;
+	struct tc35815_local *lp = netdev_priv(dev);
 	struct tc35815_regs __iomem *tr =
 		(struct tc35815_regs __iomem *)dev->base_addr;
 #ifdef TC35815_NAPI
@@ -1444,8 +1449,8 @@
 	if (!(dmactl & DMA_IntMask)) {
 		/* disable interrupts */
 		tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl);
-		if (netif_rx_schedule_prep(dev))
-			__netif_rx_schedule(dev);
+		if (netif_rx_schedule_prep(dev, &lp->napi))
+			__netif_rx_schedule(dev, &lp->napi);
 		else {
 			printk(KERN_ERR "%s: interrupt taken in poll\n",
 			       dev->name);
@@ -1726,13 +1731,12 @@
 }
 
 #ifdef TC35815_NAPI
-static int
-tc35815_poll(struct net_device *dev, int *budget)
+static int tc35815_poll(struct napi_struct *napi, int budget)
 {
-	struct tc35815_local *lp = dev->priv;
+	struct tc35815_local *lp = container_of(napi, struct tc35815_local, napi);
+	struct net_device *dev = lp->dev;
 	struct tc35815_regs __iomem *tr =
 		(struct tc35815_regs __iomem *)dev->base_addr;
-	int limit = min(*budget, dev->quota);
 	int received = 0, handled;
 	u32 status;
 
@@ -1744,23 +1748,19 @@
 		handled = tc35815_do_interrupt(dev, status, limit);
 		if (handled >= 0) {
 			received += handled;
-			limit -= handled;
-			if (limit <= 0)
+			if (received >= budget)
 				break;
 		}
 		status = tc_readl(&tr->Int_Src);
 	} while (status);
 	spin_unlock(&lp->lock);
 
-	dev->quota -= received;
-	*budget -= received;
-	if (limit <= 0)
-		return 1;
-
-	netif_rx_complete(dev);
-	/* enable interrupts */
-	tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl);
-	return 0;
+	if (received < budget) {
+		netif_rx_complete(dev, napi);
+		/* enable interrupts */
+		tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl);
+	}
+	return received;
 }
 #endif
 
@@ -1949,7 +1949,11 @@
 tc35815_close(struct net_device *dev)
 {
 	struct tc35815_local *lp = dev->priv;
+
 	netif_stop_queue(dev);
+#ifdef TC35815_NAPI
+	napi_disable(&lp->napi);
+#endif
 
 	/* Flush the Tx and disable Rx here. */
 
@@ -2158,10 +2162,16 @@
 	lp->msg_enable = datum;
 }
 
-static int tc35815_get_stats_count(struct net_device *dev)
+static int tc35815_get_sset_count(struct net_device *dev, int sset)
 {
 	struct tc35815_local *lp = dev->priv;
-	return sizeof(lp->lstats) / sizeof(int);
+
+	switch (sset) {
+	case ETH_SS_STATS:
+		return sizeof(lp->lstats) / sizeof(int);
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data)
@@ -2196,9 +2206,8 @@
 	.get_msglevel		= tc35815_get_msglevel,
 	.set_msglevel		= tc35815_set_msglevel,
 	.get_strings		= tc35815_get_strings,
-	.get_stats_count	= tc35815_get_stats_count,
+	.get_sset_count		= tc35815_get_sset_count,
 	.get_ethtool_stats	= tc35815_get_ethtool_stats,
-	.get_perm_addr		= ethtool_op_get_perm_addr,
 };
 
 static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
new file mode 100644
index 0000000..8d04654
--- /dev/null
+++ b/drivers/net/tehuti.c
@@ -0,0 +1,2506 @@
+/*
+ * Tehuti Networks(R) Network Driver
+ * ethtool interface implementation
+ * Copyright (C) 2007 Tehuti Networks Ltd. All rights reserved
+ *
+ * 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.
+ */
+
+/*
+ * RX HW/SW interaction overview
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * There are 2 types of RX communication channels betwean driver and NIC.
+ * 1) RX Free Fifo - RXF - holds descriptors of empty buffers to accept incoming
+ * traffic. This Fifo is filled by SW and is readen by HW. Each descriptor holds
+ * info about buffer's location, size and ID. An ID field is used to identify a
+ * buffer when it's returned with data via RXD Fifo (see below)
+ * 2) RX Data Fifo - RXD - holds descriptors of full buffers. This Fifo is
+ * filled by HW and is readen by SW. Each descriptor holds status and ID.
+ * HW pops descriptor from RXF Fifo, stores ID, fills buffer with incoming data,
+ * via dma moves it into host memory, builds new RXD descriptor with same ID,
+ * pushes it into RXD Fifo and raises interrupt to indicate new RX data.
+ *
+ * Current NIC configuration (registers + firmware) makes NIC use 2 RXF Fifos.
+ * One holds 1.5K packets and another - 26K packets. Depending on incoming
+ * packet size, HW desides on a RXF Fifo to pop buffer from. When packet is
+ * filled with data, HW builds new RXD descriptor for it and push it into single
+ * RXD Fifo.
+ *
+ * RX SW Data Structures
+ * ~~~~~~~~~~~~~~~~~~~~~
+ * skb db - used to keep track of all skbs owned by SW and their dma addresses.
+ * For RX case, ownership lasts from allocating new empty skb for RXF until
+ * accepting full skb from RXD and passing it to OS. Each RXF Fifo has its own
+ * skb db. Implemented as array with bitmask.
+ * fifo - keeps info about fifo's size and location, relevant HW registers,
+ * usage and skb db. Each RXD and RXF Fifo has its own fifo structure.
+ * Implemented as simple struct.
+ *
+ * RX SW Execution Flow
+ * ~~~~~~~~~~~~~~~~~~~~
+ * Upon initialization (ifconfig up) driver creates RX fifos and initializes
+ * relevant registers. At the end of init phase, driver enables interrupts.
+ * NIC sees that there is no RXF buffers and raises
+ * RD_INTR interrupt, isr fills skbs and Rx begins.
+ * Driver has two receive operation modes:
+ *    NAPI - interrupt-driven mixed with polling
+ *    interrupt-driven only
+ *
+ * Interrupt-driven only flow is following. When buffer is ready, HW raises
+ * interrupt and isr is called. isr collects all available packets
+ * (bdx_rx_receive), refills skbs (bdx_rx_alloc_skbs) and exit.
+
+ * Rx buffer allocation note
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Driver cares to feed such amount of RxF descriptors that respective amount of
+ * RxD descriptors can not fill entire RxD fifo. The main reason is lack of
+ * overflow check in Bordeaux for RxD fifo free/used size.
+ * FIXME: this is NOT fully implemented, more work should be done
+ *
+ */
+
+#include "tehuti.h"
+#include "tehuti_fw.h"
+
+static struct pci_device_id __devinitdata bdx_pci_tbl[] = {
+	{0x1FC9, 0x3009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x1FC9, 0x3010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x1FC9, 0x3014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0}
+};
+
+MODULE_DEVICE_TABLE(pci, bdx_pci_tbl);
+
+/* Definitions needed by ISR or NAPI functions */
+static void bdx_rx_alloc_skbs(struct bdx_priv *priv, struct rxf_fifo *f);
+static void bdx_tx_cleanup(struct bdx_priv *priv);
+static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget);
+
+/* Definitions needed by FW loading */
+static void bdx_tx_push_desc_safe(struct bdx_priv *priv, void *data, int size);
+
+/* Definitions needed by hw_start */
+static int bdx_tx_init(struct bdx_priv *priv);
+static int bdx_rx_init(struct bdx_priv *priv);
+
+/* Definitions needed by bdx_close */
+static void bdx_rx_free(struct bdx_priv *priv);
+static void bdx_tx_free(struct bdx_priv *priv);
+
+/* Definitions needed by bdx_probe */
+static void bdx_ethtool_ops(struct net_device *netdev);
+
+/*************************************************************************
+ *    Print Info                                                         *
+ *************************************************************************/
+
+static void print_hw_id(struct pci_dev *pdev)
+{
+	struct pci_nic *nic = pci_get_drvdata(pdev);
+	u16 pci_link_status = 0;
+	u16 pci_ctrl = 0;
+
+	pci_read_config_word(pdev, PCI_LINK_STATUS_REG, &pci_link_status);
+	pci_read_config_word(pdev, PCI_DEV_CTRL_REG, &pci_ctrl);
+
+	printk(KERN_INFO "tehuti: %s%s\n", BDX_NIC_NAME,
+	       nic->port_num == 1 ? "" : ", 2-Port");
+	printk(KERN_INFO
+	       "tehuti: srom 0x%x fpga %d build %u lane# %d"
+	       " max_pl 0x%x mrrs 0x%x\n",
+	       readl(nic->regs + SROM_VER), readl(nic->regs + FPGA_VER) & 0xFFF,
+	       readl(nic->regs + FPGA_SEED),
+	       GET_LINK_STATUS_LANES(pci_link_status),
+	       GET_DEV_CTRL_MAXPL(pci_ctrl), GET_DEV_CTRL_MRRS(pci_ctrl));
+}
+
+static void print_fw_id(struct pci_nic *nic)
+{
+	printk(KERN_INFO "tehuti: fw 0x%x\n", readl(nic->regs + FW_VER));
+}
+
+static void print_eth_id(struct net_device *ndev)
+{
+	printk(KERN_INFO "%s: %s, Port %c\n", ndev->name, BDX_NIC_NAME,
+	       (ndev->if_port == 0) ? 'A' : 'B');
+
+}
+
+/*************************************************************************
+ *    Code                                                               *
+ *************************************************************************/
+
+#define bdx_enable_interrupts(priv)	\
+	do { WRITE_REG(priv, regIMR, IR_RUN); } while (0)
+#define bdx_disable_interrupts(priv)	\
+	do { WRITE_REG(priv, regIMR, 0); } while (0)
+
+/* bdx_fifo_init
+ * create TX/RX descriptor fifo for host-NIC communication.
+ * 1K extra space is allocated at the end of the fifo to simplify
+ * processing of descriptors that wraps around fifo's end
+ * @priv - NIC private structure
+ * @f - fifo to initialize
+ * @fsz_type - fifo size type: 0-4KB, 1-8KB, 2-16KB, 3-32KB
+ * @reg_XXX - offsets of registers relative to base address
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ */
+static int
+bdx_fifo_init(struct bdx_priv *priv, struct fifo *f, int fsz_type,
+	      u16 reg_CFG0, u16 reg_CFG1, u16 reg_RPTR, u16 reg_WPTR)
+{
+	u16 memsz = FIFO_SIZE * (1 << fsz_type);
+
+	memset(f, 0, sizeof(struct fifo));
+	/* pci_alloc_consistent gives us 4k-aligned memory */
+	f->va = pci_alloc_consistent(priv->pdev,
+				     memsz + FIFO_EXTRA_SPACE, &f->da);
+	if (!f->va) {
+		ERR("pci_alloc_consistent failed\n");
+		RET(-ENOMEM);
+	}
+	f->reg_CFG0 = reg_CFG0;
+	f->reg_CFG1 = reg_CFG1;
+	f->reg_RPTR = reg_RPTR;
+	f->reg_WPTR = reg_WPTR;
+	f->rptr = 0;
+	f->wptr = 0;
+	f->memsz = memsz;
+	f->size_mask = memsz - 1;
+	WRITE_REG(priv, reg_CFG0, (u32) ((f->da & TX_RX_CFG0_BASE) | fsz_type));
+	WRITE_REG(priv, reg_CFG1, H32_64(f->da));
+
+	RET(0);
+}
+
+/* bdx_fifo_free - free all resources used by fifo
+ * @priv - NIC private structure
+ * @f - fifo to release
+ */
+static void bdx_fifo_free(struct bdx_priv *priv, struct fifo *f)
+{
+	ENTER;
+	if (f->va) {
+		pci_free_consistent(priv->pdev,
+				    f->memsz + FIFO_EXTRA_SPACE, f->va, f->da);
+		f->va = NULL;
+	}
+	RET();
+}
+
+/*
+ * bdx_link_changed - notifies OS about hw link state.
+ * @bdx_priv - hw adapter structure
+ */
+static void bdx_link_changed(struct bdx_priv *priv)
+{
+	u32 link = READ_REG(priv, regMAC_LNK_STAT) & MAC_LINK_STAT;
+
+	if (!link) {
+		if (netif_carrier_ok(priv->ndev)) {
+			netif_stop_queue(priv->ndev);
+			netif_carrier_off(priv->ndev);
+			ERR("%s: Link Down\n", priv->ndev->name);
+		}
+	} else {
+		if (!netif_carrier_ok(priv->ndev)) {
+			netif_wake_queue(priv->ndev);
+			netif_carrier_on(priv->ndev);
+			ERR("%s: Link Up\n", priv->ndev->name);
+		}
+	}
+}
+
+static void bdx_isr_extra(struct bdx_priv *priv, u32 isr)
+{
+	if (isr & IR_RX_FREE_0) {
+		bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0);
+		DBG("RX_FREE_0\n");
+	}
+
+	if (isr & IR_LNKCHG0)
+		bdx_link_changed(priv);
+
+	if (isr & IR_PCIE_LINK)
+		ERR("%s: PCI-E Link Fault\n", priv->ndev->name);
+
+	if (isr & IR_PCIE_TOUT)
+		ERR("%s: PCI-E Time Out\n", priv->ndev->name);
+
+}
+
+/* bdx_isr - Interrupt Service Routine for Bordeaux NIC
+ * @irq - interrupt number
+ * @ndev - network device
+ * @regs - CPU registers
+ *
+ * Return IRQ_NONE if it was not our interrupt, IRQ_HANDLED - otherwise
+ *
+ * It reads ISR register to know interrupt reasons, and proceed them one by one.
+ * Reasons of interest are:
+ *    RX_DESC - new packet has arrived and RXD fifo holds its descriptor
+ *    RX_FREE - number of free Rx buffers in RXF fifo gets low
+ *    TX_FREE - packet was transmited and RXF fifo holds its descriptor
+ */
+
+static irqreturn_t bdx_isr_napi(int irq, void *dev)
+{
+	struct net_device *ndev = dev;
+	struct bdx_priv *priv = ndev->priv;
+	u32 isr;
+
+	ENTER;
+	isr = (READ_REG(priv, regISR) & IR_RUN);
+	if (unlikely(!isr)) {
+		bdx_enable_interrupts(priv);
+		return IRQ_NONE;	/* Not our interrupt */
+	}
+
+	if (isr & IR_EXTRA)
+		bdx_isr_extra(priv, isr);
+
+	if (isr & (IR_RX_DESC_0 | IR_TX_FREE_0)) {
+		if (likely(netif_rx_schedule_prep(ndev, &priv->napi))) {
+			__netif_rx_schedule(ndev, &priv->napi);
+			RET(IRQ_HANDLED);
+		} else {
+			/* NOTE: we get here if intr has slipped into window
+			 * between these lines in bdx_poll:
+			 *    bdx_enable_interrupts(priv);
+			 *    return 0;
+			 * currently intrs are disabled (since we read ISR),
+			 * and we have failed to register next poll.
+			 * so we read the regs to trigger chip
+			 * and allow further interupts. */
+			READ_REG(priv, regTXF_WPTR_0);
+			READ_REG(priv, regRXD_WPTR_0);
+		}
+	}
+
+	bdx_enable_interrupts(priv);
+	RET(IRQ_HANDLED);
+}
+
+static int bdx_poll(struct napi_struct *napi, int budget)
+{
+	struct bdx_priv *priv = container_of(napi, struct bdx_priv, napi);
+	struct net_device *dev = priv->ndev;
+	int work_done;
+
+	ENTER;
+	bdx_tx_cleanup(priv);
+	work_done = bdx_rx_receive(priv, &priv->rxd_fifo0, budget);
+	if ((work_done < budget) ||
+	    (priv->napi_stop++ >= 30)) {
+		DBG("rx poll is done. backing to isr-driven\n");
+
+		/* from time to time we exit to let NAPI layer release
+		 * device lock and allow waiting tasks (eg rmmod) to advance) */
+		priv->napi_stop = 0;
+
+		netif_rx_complete(dev, napi);
+		bdx_enable_interrupts(priv);
+	}
+	return work_done;
+}
+
+/* bdx_fw_load - loads firmware to NIC
+ * @priv - NIC private structure
+ * Firmware is loaded via TXD fifo, so it must be initialized first.
+ * Firware must be loaded once per NIC not per PCI device provided by NIC (NIC
+ * can have few of them). So all drivers use semaphore register to choose one
+ * that will actually load FW to NIC.
+ */
+
+static int bdx_fw_load(struct bdx_priv *priv)
+{
+	int master, i;
+
+	ENTER;
+	master = READ_REG(priv, regINIT_SEMAPHORE);
+	if (!READ_REG(priv, regINIT_STATUS) && master) {
+		bdx_tx_push_desc_safe(priv, s_firmLoad, sizeof(s_firmLoad));
+		mdelay(100);
+	}
+	for (i = 0; i < 200; i++) {
+		if (READ_REG(priv, regINIT_STATUS))
+			break;
+		mdelay(2);
+	}
+	if (master)
+		WRITE_REG(priv, regINIT_SEMAPHORE, 1);
+
+	if (i == 200) {
+		ERR("%s: firmware loading failed\n", priv->ndev->name);
+		DBG("VPC = 0x%x VIC = 0x%x INIT_STATUS = 0x%x i=%d\n",
+		    READ_REG(priv, regVPC),
+		    READ_REG(priv, regVIC), READ_REG(priv, regINIT_STATUS), i);
+		RET(-EIO);
+	} else {
+		DBG("%s: firmware loading success\n", priv->ndev->name);
+		RET(0);
+	}
+}
+
+static void bdx_restore_mac(struct net_device *ndev, struct bdx_priv *priv)
+{
+	u32 val;
+
+	ENTER;
+	DBG("mac0=%x mac1=%x mac2=%x\n",
+	    READ_REG(priv, regUNC_MAC0_A),
+	    READ_REG(priv, regUNC_MAC1_A), READ_REG(priv, regUNC_MAC2_A));
+
+	val = (ndev->dev_addr[0] << 8) | (ndev->dev_addr[1]);
+	WRITE_REG(priv, regUNC_MAC2_A, val);
+	val = (ndev->dev_addr[2] << 8) | (ndev->dev_addr[3]);
+	WRITE_REG(priv, regUNC_MAC1_A, val);
+	val = (ndev->dev_addr[4] << 8) | (ndev->dev_addr[5]);
+	WRITE_REG(priv, regUNC_MAC0_A, val);
+
+	DBG("mac0=%x mac1=%x mac2=%x\n",
+	    READ_REG(priv, regUNC_MAC0_A),
+	    READ_REG(priv, regUNC_MAC1_A), READ_REG(priv, regUNC_MAC2_A));
+	RET();
+}
+
+/* bdx_hw_start - inits registers and starts HW's Rx and Tx engines
+ * @priv - NIC private structure
+ */
+static int bdx_hw_start(struct bdx_priv *priv)
+{
+	int rc = -EIO;
+	struct net_device *ndev = priv->ndev;
+
+	ENTER;
+	bdx_link_changed(priv);
+
+	/* 10G overall max length (vlan, eth&ip header, ip payload, crc) */
+	WRITE_REG(priv, regFRM_LENGTH, 0X3FE0);
+	WRITE_REG(priv, regPAUSE_QUANT, 0x96);
+	WRITE_REG(priv, regRX_FIFO_SECTION, 0x800010);
+	WRITE_REG(priv, regTX_FIFO_SECTION, 0xE00010);
+	WRITE_REG(priv, regRX_FULLNESS, 0);
+	WRITE_REG(priv, regTX_FULLNESS, 0);
+	WRITE_REG(priv, regCTRLST,
+		  regCTRLST_BASE | regCTRLST_RX_ENA | regCTRLST_TX_ENA);
+
+	WRITE_REG(priv, regVGLB, 0);
+	WRITE_REG(priv, regMAX_FRAME_A,
+		  priv->rxf_fifo0.m.pktsz & MAX_FRAME_AB_VAL);
+
+	DBG("RDINTCM=%08x\n", priv->rdintcm);	/*NOTE: test script uses this */
+	WRITE_REG(priv, regRDINTCM0, priv->rdintcm);
+	WRITE_REG(priv, regRDINTCM2, 0);	/*cpu_to_le32(rcm.val)); */
+
+	DBG("TDINTCM=%08x\n", priv->tdintcm);	/*NOTE: test script uses this */
+	WRITE_REG(priv, regTDINTCM0, priv->tdintcm);	/* old val = 0x300064 */
+
+	/* Enable timer interrupt once in 2 secs. */
+	/*WRITE_REG(priv, regGTMR0, ((GTMR_SEC * 2) & GTMR_DATA)); */
+	bdx_restore_mac(priv->ndev, priv);
+
+	WRITE_REG(priv, regGMAC_RXF_A, GMAC_RX_FILTER_OSEN |
+		  GMAC_RX_FILTER_AM | GMAC_RX_FILTER_AB);
+
+#define BDX_IRQ_TYPE	((priv->nic->irq_type == IRQ_MSI)?0:IRQF_SHARED)
+	if ((rc = request_irq(priv->pdev->irq, &bdx_isr_napi, BDX_IRQ_TYPE,
+			 ndev->name, ndev)))
+		goto err_irq;
+	bdx_enable_interrupts(priv);
+
+	RET(0);
+
+err_irq:
+	RET(rc);
+}
+
+static void bdx_hw_stop(struct bdx_priv *priv)
+{
+	ENTER;
+	bdx_disable_interrupts(priv);
+	free_irq(priv->pdev->irq, priv->ndev);
+
+	netif_carrier_off(priv->ndev);
+	netif_stop_queue(priv->ndev);
+
+	RET();
+}
+
+static int bdx_hw_reset_direct(void __iomem *regs)
+{
+	u32 val, i;
+	ENTER;
+
+	/* reset sequences: read, write 1, read, write 0 */
+	val = readl(regs + regCLKPLL);
+	writel((val | CLKPLL_SFTRST) + 0x8, regs + regCLKPLL);
+	udelay(50);
+	val = readl(regs + regCLKPLL);
+	writel(val & ~CLKPLL_SFTRST, regs + regCLKPLL);
+
+	/* check that the PLLs are locked and reset ended */
+	for (i = 0; i < 70; i++, mdelay(10))
+		if ((readl(regs + regCLKPLL) & CLKPLL_LKD) == CLKPLL_LKD) {
+			/* do any PCI-E read transaction */
+			readl(regs + regRXD_CFG0_0);
+			return 0;
+		}
+	ERR("tehuti: HW reset failed\n");
+	return 1;		/* failure */
+}
+
+static int bdx_hw_reset(struct bdx_priv *priv)
+{
+	u32 val, i;
+	ENTER;
+
+	if (priv->port == 0) {
+		/* reset sequences: read, write 1, read, write 0 */
+		val = READ_REG(priv, regCLKPLL);
+		WRITE_REG(priv, regCLKPLL, (val | CLKPLL_SFTRST) + 0x8);
+		udelay(50);
+		val = READ_REG(priv, regCLKPLL);
+		WRITE_REG(priv, regCLKPLL, val & ~CLKPLL_SFTRST);
+	}
+	/* check that the PLLs are locked and reset ended */
+	for (i = 0; i < 70; i++, mdelay(10))
+		if ((READ_REG(priv, regCLKPLL) & CLKPLL_LKD) == CLKPLL_LKD) {
+			/* do any PCI-E read transaction */
+			READ_REG(priv, regRXD_CFG0_0);
+			return 0;
+		}
+	ERR("tehuti: HW reset failed\n");
+	return 1;		/* failure */
+}
+
+static int bdx_sw_reset(struct bdx_priv *priv)
+{
+	int i;
+
+	ENTER;
+	/* 1. load MAC (obsolete) */
+	/* 2. disable Rx (and Tx) */
+	WRITE_REG(priv, regGMAC_RXF_A, 0);
+	mdelay(100);
+	/* 3. disable port */
+	WRITE_REG(priv, regDIS_PORT, 1);
+	/* 4. disable queue */
+	WRITE_REG(priv, regDIS_QU, 1);
+	/* 5. wait until hw is disabled */
+	for (i = 0; i < 50; i++) {
+		if (READ_REG(priv, regRST_PORT) & 1)
+			break;
+		mdelay(10);
+	}
+	if (i == 50)
+		ERR("%s: SW reset timeout. continuing anyway\n",
+		    priv->ndev->name);
+
+	/* 6. disable intrs */
+	WRITE_REG(priv, regRDINTCM0, 0);
+	WRITE_REG(priv, regTDINTCM0, 0);
+	WRITE_REG(priv, regIMR, 0);
+	READ_REG(priv, regISR);
+
+	/* 7. reset queue */
+	WRITE_REG(priv, regRST_QU, 1);
+	/* 8. reset port */
+	WRITE_REG(priv, regRST_PORT, 1);
+	/* 9. zero all read and write pointers */
+	for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10)
+		DBG("%x = %x\n", i, READ_REG(priv, i) & TXF_WPTR_WR_PTR);
+	for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10)
+		WRITE_REG(priv, i, 0);
+	/* 10. unseet port disable */
+	WRITE_REG(priv, regDIS_PORT, 0);
+	/* 11. unset queue disable */
+	WRITE_REG(priv, regDIS_QU, 0);
+	/* 12. unset queue reset */
+	WRITE_REG(priv, regRST_QU, 0);
+	/* 13. unset port reset */
+	WRITE_REG(priv, regRST_PORT, 0);
+	/* 14. enable Rx */
+	/* skiped. will be done later */
+	/* 15. save MAC (obsolete) */
+	for (i = regTXD_WPTR_0; i <= regTXF_RPTR_3; i += 0x10)
+		DBG("%x = %x\n", i, READ_REG(priv, i) & TXF_WPTR_WR_PTR);
+
+	RET(0);
+}
+
+/* bdx_reset - performs right type of reset depending on hw type */
+static int bdx_reset(struct bdx_priv *priv)
+{
+	ENTER;
+	RET((priv->pdev->device == 0x3009)
+	    ? bdx_hw_reset(priv)
+	    : bdx_sw_reset(priv));
+}
+
+/**
+ * bdx_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the drivers control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+static int bdx_close(struct net_device *ndev)
+{
+	struct bdx_priv *priv = NULL;
+
+	ENTER;
+	priv = ndev->priv;
+
+	napi_disable(&priv->napi);
+
+	bdx_reset(priv);
+	bdx_hw_stop(priv);
+	bdx_rx_free(priv);
+	bdx_tx_free(priv);
+	RET(0);
+}
+
+/**
+ * bdx_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+static int bdx_open(struct net_device *ndev)
+{
+	struct bdx_priv *priv;
+	int rc;
+
+	ENTER;
+	priv = ndev->priv;
+	bdx_reset(priv);
+	if (netif_running(ndev))
+		netif_stop_queue(priv->ndev);
+
+	if ((rc = bdx_tx_init(priv)))
+		goto err;
+
+	if ((rc = bdx_rx_init(priv)))
+		goto err;
+
+	if ((rc = bdx_fw_load(priv)))
+		goto err;
+
+	bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0);
+
+	if ((rc = bdx_hw_start(priv)))
+		goto err;
+
+	napi_enable(&priv->napi);
+
+	print_fw_id(priv->nic);
+
+	RET(0);
+
+err:
+	bdx_close(ndev);
+	RET(rc);
+}
+
+static void __init bdx_firmware_endianess(void)
+{
+	int i;
+	for (i = 0; i < sizeof(s_firmLoad) / sizeof(u32); i++)
+		s_firmLoad[i] = CPU_CHIP_SWAP32(s_firmLoad[i]);
+}
+
+static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd)
+{
+	struct bdx_priv *priv = ndev->priv;
+	u32 data[3];
+	int error;
+
+	ENTER;
+
+	DBG("jiffies=%ld cmd=%d\n", jiffies, cmd);
+	if (cmd != SIOCDEVPRIVATE) {
+		error = copy_from_user(data, ifr->ifr_data, sizeof(data));
+		if (error) {
+			ERR("cant copy from user\n");
+			RET(error);
+		}
+		DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]);
+	}
+
+	switch (data[0]) {
+
+	case BDX_OP_READ:
+		data[2] = READ_REG(priv, data[1]);
+		DBG("read_reg(0x%x)=0x%x (dec %d)\n", data[1], data[2],
+		    data[2]);
+		error = copy_to_user(ifr->ifr_data, data, sizeof(data));
+		if (error)
+			RET(error);
+		break;
+
+	case BDX_OP_WRITE:
+		WRITE_REG(priv, data[1], data[2]);
+		DBG("write_reg(0x%x, 0x%x)\n", data[1], data[2]);
+		break;
+
+	default:
+		RET(-EOPNOTSUPP);
+	}
+	return 0;
+}
+
+static int bdx_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
+{
+	ENTER;
+	if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15))
+		RET(bdx_ioctl_priv(ndev, ifr, cmd));
+	else
+		RET(-EOPNOTSUPP);
+}
+
+/*
+ * __bdx_vlan_rx_vid - private helper for adding/killing VLAN vid
+ *                     by passing VLAN filter table to hardware
+ * @ndev network device
+ * @vid  VLAN vid
+ * @op   add or kill operation
+ */
+static void __bdx_vlan_rx_vid(struct net_device *ndev, uint16_t vid, int enable)
+{
+	struct bdx_priv *priv = ndev->priv;
+	u32 reg, bit, val;
+
+	ENTER;
+	DBG2("vid=%d value=%d\n", (int)vid, enable);
+	if (unlikely(vid >= 4096)) {
+		ERR("tehuti: invalid VID: %u (> 4096)\n", vid);
+		RET();
+	}
+	reg = regVLAN_0 + (vid / 32) * 4;
+	bit = 1 << vid % 32;
+	val = READ_REG(priv, reg);
+	DBG2("reg=%x, val=%x, bit=%d\n", reg, val, bit);
+	if (enable)
+		val |= bit;
+	else
+		val &= ~bit;
+	DBG2("new val %x\n", val);
+	WRITE_REG(priv, reg, val);
+	RET();
+}
+
+/*
+ * bdx_vlan_rx_add_vid - kernel hook for adding VLAN vid to hw filtering table
+ * @ndev network device
+ * @vid  VLAN vid to add
+ */
+static void bdx_vlan_rx_add_vid(struct net_device *ndev, uint16_t vid)
+{
+	__bdx_vlan_rx_vid(ndev, vid, 1);
+}
+
+/*
+ * bdx_vlan_rx_kill_vid - kernel hook for killing VLAN vid in hw filtering table
+ * @ndev network device
+ * @vid  VLAN vid to kill
+ */
+static void bdx_vlan_rx_kill_vid(struct net_device *ndev, unsigned short vid)
+{
+	__bdx_vlan_rx_vid(ndev, vid, 0);
+}
+
+/*
+ * bdx_vlan_rx_register - kernel hook for adding VLAN group
+ * @ndev network device
+ * @grp  VLAN group
+ */
+static void
+bdx_vlan_rx_register(struct net_device *ndev, struct vlan_group *grp)
+{
+	struct bdx_priv *priv = ndev->priv;
+
+	ENTER;
+	DBG("device='%s', group='%p'\n", ndev->name, grp);
+	priv->vlgrp = grp;
+	RET();
+}
+
+/**
+ * bdx_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int bdx_change_mtu(struct net_device *ndev, int new_mtu)
+{
+	ENTER;
+
+	if (new_mtu == ndev->mtu)
+		RET(0);
+
+	/* enforce minimum frame size */
+	if (new_mtu < ETH_ZLEN) {
+		ERR("%s: %s mtu %d is less then minimal %d\n",
+		    BDX_DRV_NAME, ndev->name, new_mtu, ETH_ZLEN);
+		RET(-EINVAL);
+	}
+
+	ndev->mtu = new_mtu;
+	if (netif_running(ndev)) {
+		bdx_close(ndev);
+		bdx_open(ndev);
+	}
+	RET(0);
+}
+
+static void bdx_setmulti(struct net_device *ndev)
+{
+	struct bdx_priv *priv = ndev->priv;
+
+	u32 rxf_val =
+	    GMAC_RX_FILTER_AM | GMAC_RX_FILTER_AB | GMAC_RX_FILTER_OSEN;
+	int i;
+
+	ENTER;
+	/* IMF - imperfect (hash) rx multicat filter */
+	/* PMF - perfect rx multicat filter */
+
+	/* FIXME: RXE(OFF) */
+	if (ndev->flags & IFF_PROMISC) {
+		rxf_val |= GMAC_RX_FILTER_PRM;
+	} else if (ndev->flags & IFF_ALLMULTI) {
+		/* set IMF to accept all multicast frmaes */
+		for (i = 0; i < MAC_MCST_HASH_NUM; i++)
+			WRITE_REG(priv, regRX_MCST_HASH0 + i * 4, ~0);
+	} else if (ndev->mc_count) {
+		u8 hash;
+		struct dev_mc_list *mclist;
+		u32 reg, val;
+
+		/* set IMF to deny all multicast frames */
+		for (i = 0; i < MAC_MCST_HASH_NUM; i++)
+			WRITE_REG(priv, regRX_MCST_HASH0 + i * 4, 0);
+		/* set PMF to deny all multicast frames */
+		for (i = 0; i < MAC_MCST_NUM; i++) {
+			WRITE_REG(priv, regRX_MAC_MCST0 + i * 8, 0);
+			WRITE_REG(priv, regRX_MAC_MCST1 + i * 8, 0);
+		}
+
+		/* use PMF to accept first MAC_MCST_NUM (15) addresses */
+		/* TBD: sort addreses and write them in ascending order
+		 * into RX_MAC_MCST regs. we skip this phase now and accept ALL
+		 * multicast frames throu IMF */
+		mclist = ndev->mc_list;
+
+		/* accept the rest of addresses throu IMF */
+		for (; mclist; mclist = mclist->next) {
+			hash = 0;
+			for (i = 0; i < ETH_ALEN; i++)
+				hash ^= mclist->dmi_addr[i];
+			reg = regRX_MCST_HASH0 + ((hash >> 5) << 2);
+			val = READ_REG(priv, reg);
+			val |= (1 << (hash % 32));
+			WRITE_REG(priv, reg, val);
+		}
+
+	} else {
+		DBG("only own mac %d\n", ndev->mc_count);
+		rxf_val |= GMAC_RX_FILTER_AB;
+	}
+	WRITE_REG(priv, regGMAC_RXF_A, rxf_val);
+	/* enable RX */
+	/* FIXME: RXE(ON) */
+	RET();
+}
+
+static int bdx_set_mac(struct net_device *ndev, void *p)
+{
+	struct bdx_priv *priv = ndev->priv;
+	struct sockaddr *addr = p;
+
+	ENTER;
+	/*
+	   if (netif_running(dev))
+	   return -EBUSY
+	 */
+	memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
+	bdx_restore_mac(ndev, priv);
+	RET(0);
+}
+
+static int bdx_read_mac(struct bdx_priv *priv)
+{
+	u16 macAddress[3], i;
+	ENTER;
+
+	macAddress[2] = READ_REG(priv, regUNC_MAC0_A);
+	macAddress[2] = READ_REG(priv, regUNC_MAC0_A);
+	macAddress[1] = READ_REG(priv, regUNC_MAC1_A);
+	macAddress[1] = READ_REG(priv, regUNC_MAC1_A);
+	macAddress[0] = READ_REG(priv, regUNC_MAC2_A);
+	macAddress[0] = READ_REG(priv, regUNC_MAC2_A);
+	for (i = 0; i < 3; i++) {
+		priv->ndev->dev_addr[i * 2 + 1] = macAddress[i];
+		priv->ndev->dev_addr[i * 2] = macAddress[i] >> 8;
+	}
+	RET(0);
+}
+
+static u64 bdx_read_l2stat(struct bdx_priv *priv, int reg)
+{
+	u64 val;
+
+	val = READ_REG(priv, reg);
+	val |= ((u64) READ_REG(priv, reg + 8)) << 32;
+	return val;
+}
+
+/*Do the statistics-update work*/
+static void bdx_update_stats(struct bdx_priv *priv)
+{
+	struct bdx_stats *stats = &priv->hw_stats;
+	u64 *stats_vector = (u64 *) stats;
+	int i;
+	int addr;
+
+	/*Fill HW structure */
+	addr = 0x7200;
+	/*First 12 statistics - 0x7200 - 0x72B0 */
+	for (i = 0; i < 12; i++) {
+		stats_vector[i] = bdx_read_l2stat(priv, addr);
+		addr += 0x10;
+	}
+	BDX_ASSERT(addr != 0x72C0);
+	/* 0x72C0-0x72E0 RSRV */
+	addr = 0x72F0;
+	for (; i < 16; i++) {
+		stats_vector[i] = bdx_read_l2stat(priv, addr);
+		addr += 0x10;
+	}
+	BDX_ASSERT(addr != 0x7330);
+	/* 0x7330-0x7360 RSRV */
+	addr = 0x7370;
+	for (; i < 19; i++) {
+		stats_vector[i] = bdx_read_l2stat(priv, addr);
+		addr += 0x10;
+	}
+	BDX_ASSERT(addr != 0x73A0);
+	/* 0x73A0-0x73B0 RSRV */
+	addr = 0x73C0;
+	for (; i < 23; i++) {
+		stats_vector[i] = bdx_read_l2stat(priv, addr);
+		addr += 0x10;
+	}
+	BDX_ASSERT(addr != 0x7400);
+	BDX_ASSERT((sizeof(struct bdx_stats) / sizeof(u64)) != i);
+}
+
+static struct net_device_stats *bdx_get_stats(struct net_device *ndev)
+{
+	struct bdx_priv *priv = ndev->priv;
+	struct net_device_stats *net_stat = &priv->net_stats;
+	return net_stat;
+}
+
+static void print_rxdd(struct rxd_desc *rxdd, u32 rxd_val1, u16 len,
+		       u16 rxd_vlan);
+static void print_rxfd(struct rxf_desc *rxfd);
+
+/*************************************************************************
+ *     Rx DB                                                             *
+ *************************************************************************/
+
+static void bdx_rxdb_destroy(struct rxdb *db)
+{
+	if (db)
+		vfree(db);
+}
+
+static struct rxdb *bdx_rxdb_create(int nelem)
+{
+	struct rxdb *db;
+	int i;
+
+	db = vmalloc(sizeof(struct rxdb)
+		     + (nelem * sizeof(int))
+		     + (nelem * sizeof(struct rx_map)));
+	if (likely(db != NULL)) {
+		db->stack = (int *)(db + 1);
+		db->elems = (void *)(db->stack + nelem);
+		db->nelem = nelem;
+		db->top = nelem;
+		for (i = 0; i < nelem; i++)
+			db->stack[i] = nelem - i - 1;	/* to make first allocs
+							   close to db struct*/
+	}
+
+	return db;
+}
+
+static inline int bdx_rxdb_alloc_elem(struct rxdb *db)
+{
+	BDX_ASSERT(db->top <= 0);
+	return db->stack[--(db->top)];
+}
+
+static inline void *bdx_rxdb_addr_elem(struct rxdb *db, int n)
+{
+	BDX_ASSERT((n < 0) || (n >= db->nelem));
+	return db->elems + n;
+}
+
+static inline int bdx_rxdb_available(struct rxdb *db)
+{
+	return db->top;
+}
+
+static inline void bdx_rxdb_free_elem(struct rxdb *db, int n)
+{
+	BDX_ASSERT((n >= db->nelem) || (n < 0));
+	db->stack[(db->top)++] = n;
+}
+
+/*************************************************************************
+ *     Rx Init                                                           *
+ *************************************************************************/
+
+/* bdx_rx_init - initialize RX all related HW and SW resources
+ * @priv - NIC private structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * It creates rxf and rxd fifos, update relevant HW registers, preallocate
+ * skb for rx. It assumes that Rx is desabled in HW
+ * funcs are grouped for better cache usage
+ *
+ * RxD fifo is smaller then RxF fifo by design. Upon high load, RxD will be
+ * filled and packets will be dropped by nic without getting into host or
+ * cousing interrupt. Anyway, in that condition, host has no chance to proccess
+ * all packets, but dropping in nic is cheaper, since it takes 0 cpu cycles
+ */
+
+/* TBD: ensure proper packet size */
+
+static int bdx_rx_init(struct bdx_priv *priv)
+{
+	ENTER;
+
+	if (bdx_fifo_init(priv, &priv->rxd_fifo0.m, priv->rxd_size,
+			  regRXD_CFG0_0, regRXD_CFG1_0,
+			  regRXD_RPTR_0, regRXD_WPTR_0))
+		goto err_mem;
+	if (bdx_fifo_init(priv, &priv->rxf_fifo0.m, priv->rxf_size,
+			  regRXF_CFG0_0, regRXF_CFG1_0,
+			  regRXF_RPTR_0, regRXF_WPTR_0))
+		goto err_mem;
+	if (!
+	    (priv->rxdb =
+	     bdx_rxdb_create(priv->rxf_fifo0.m.memsz /
+			     sizeof(struct rxf_desc))))
+		goto err_mem;
+
+	priv->rxf_fifo0.m.pktsz = priv->ndev->mtu + VLAN_ETH_HLEN;
+	return 0;
+
+err_mem:
+	ERR("%s: %s: Rx init failed\n", BDX_DRV_NAME, priv->ndev->name);
+	return -ENOMEM;
+}
+
+/* bdx_rx_free_skbs - frees and unmaps all skbs allocated for the fifo
+ * @priv - NIC private structure
+ * @f - RXF fifo
+ */
+static void bdx_rx_free_skbs(struct bdx_priv *priv, struct rxf_fifo *f)
+{
+	struct rx_map *dm;
+	struct rxdb *db = priv->rxdb;
+	u16 i;
+
+	ENTER;
+	DBG("total=%d free=%d busy=%d\n", db->nelem, bdx_rxdb_available(db),
+	    db->nelem - bdx_rxdb_available(db));
+	while (bdx_rxdb_available(db) > 0) {
+		i = bdx_rxdb_alloc_elem(db);
+		dm = bdx_rxdb_addr_elem(db, i);
+		dm->dma = 0;
+	}
+	for (i = 0; i < db->nelem; i++) {
+		dm = bdx_rxdb_addr_elem(db, i);
+		if (dm->dma) {
+			pci_unmap_single(priv->pdev,
+					 dm->dma, f->m.pktsz,
+					 PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(dm->skb);
+		}
+	}
+}
+
+/* bdx_rx_free - release all Rx resources
+ * @priv - NIC private structure
+ * It assumes that Rx is desabled in HW
+ */
+static void bdx_rx_free(struct bdx_priv *priv)
+{
+	ENTER;
+	if (priv->rxdb) {
+		bdx_rx_free_skbs(priv, &priv->rxf_fifo0);
+		bdx_rxdb_destroy(priv->rxdb);
+		priv->rxdb = NULL;
+	}
+	bdx_fifo_free(priv, &priv->rxf_fifo0.m);
+	bdx_fifo_free(priv, &priv->rxd_fifo0.m);
+
+	RET();
+}
+
+/*************************************************************************
+ *     Rx Engine                                                         *
+ *************************************************************************/
+
+/* bdx_rx_alloc_skbs - fill rxf fifo with new skbs
+ * @priv - nic's private structure
+ * @f - RXF fifo that needs skbs
+ * It allocates skbs, build rxf descs and push it (rxf descr) into rxf fifo.
+ * skb's virtual and physical addresses are stored in skb db.
+ * To calculate free space, func uses cached values of RPTR and WPTR
+ * When needed, it also updates RPTR and WPTR.
+ */
+
+/* TBD: do not update WPTR if no desc were written */
+
+static void bdx_rx_alloc_skbs(struct bdx_priv *priv, struct rxf_fifo *f)
+{
+	struct sk_buff *skb;
+	struct rxf_desc *rxfd;
+	struct rx_map *dm;
+	int dno, delta, idx;
+	struct rxdb *db = priv->rxdb;
+
+	ENTER;
+	dno = bdx_rxdb_available(db) - 1;
+	while (dno > 0) {
+		if (!(skb = dev_alloc_skb(f->m.pktsz + NET_IP_ALIGN))) {
+			ERR("NO MEM: dev_alloc_skb failed\n");
+			break;
+		}
+		skb->dev = priv->ndev;
+		skb_reserve(skb, NET_IP_ALIGN);
+
+		idx = bdx_rxdb_alloc_elem(db);
+		dm = bdx_rxdb_addr_elem(db, idx);
+		dm->dma = pci_map_single(priv->pdev,
+					 skb->data, f->m.pktsz,
+					 PCI_DMA_FROMDEVICE);
+		dm->skb = skb;
+		rxfd = (struct rxf_desc *)(f->m.va + f->m.wptr);
+		rxfd->info = CPU_CHIP_SWAP32(0x10003);	/* INFO=1 BC=3 */
+		rxfd->va_lo = idx;
+		rxfd->pa_lo = CPU_CHIP_SWAP32(L32_64(dm->dma));
+		rxfd->pa_hi = CPU_CHIP_SWAP32(H32_64(dm->dma));
+		rxfd->len = CPU_CHIP_SWAP32(f->m.pktsz);
+		print_rxfd(rxfd);
+
+		f->m.wptr += sizeof(struct rxf_desc);
+		delta = f->m.wptr - f->m.memsz;
+		if (unlikely(delta >= 0)) {
+			f->m.wptr = delta;
+			if (delta > 0) {
+				memcpy(f->m.va, f->m.va + f->m.memsz, delta);
+				DBG("wrapped descriptor\n");
+			}
+		}
+		dno--;
+	}
+	/*TBD: to do - delayed rxf wptr like in txd */
+	WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR);
+	RET();
+}
+
+static inline void
+NETIF_RX_MUX(struct bdx_priv *priv, u32 rxd_val1, u16 rxd_vlan,
+	     struct sk_buff *skb)
+{
+	ENTER;
+	DBG("rxdd->flags.bits.vtag=%d vlgrp=%p\n", GET_RXD_VTAG(rxd_val1),
+	    priv->vlgrp);
+	if (priv->vlgrp && GET_RXD_VTAG(rxd_val1)) {
+		DBG("%s: vlan rcv vlan '%x' vtag '%x', device name '%s'\n",
+		    priv->ndev->name,
+		    GET_RXD_VLAN_ID(rxd_vlan),
+		    GET_RXD_VTAG(rxd_val1),
+		    vlan_group_get_device(priv->vlgrp,
+					  GET_RXD_VLAN_ID(rxd_vlan))->name);
+		/* NAPI variant of receive functions */
+		vlan_hwaccel_receive_skb(skb, priv->vlgrp,
+					 GET_RXD_VLAN_ID(rxd_vlan));
+	} else {
+		netif_receive_skb(skb);
+	}
+}
+
+static void bdx_recycle_skb(struct bdx_priv *priv, struct rxd_desc *rxdd)
+{
+	struct rxf_desc *rxfd;
+	struct rx_map *dm;
+	struct rxf_fifo *f;
+	struct rxdb *db;
+	struct sk_buff *skb;
+	int delta;
+
+	ENTER;
+	DBG("priv=%p rxdd=%p\n", priv, rxdd);
+	f = &priv->rxf_fifo0;
+	db = priv->rxdb;
+	DBG("db=%p f=%p\n", db, f);
+	dm = bdx_rxdb_addr_elem(db, rxdd->va_lo);
+	DBG("dm=%p\n", dm);
+	skb = dm->skb;
+	rxfd = (struct rxf_desc *)(f->m.va + f->m.wptr);
+	rxfd->info = CPU_CHIP_SWAP32(0x10003);	/* INFO=1 BC=3 */
+	rxfd->va_lo = rxdd->va_lo;
+	rxfd->pa_lo = CPU_CHIP_SWAP32(L32_64(dm->dma));
+	rxfd->pa_hi = CPU_CHIP_SWAP32(H32_64(dm->dma));
+	rxfd->len = CPU_CHIP_SWAP32(f->m.pktsz);
+	print_rxfd(rxfd);
+
+	f->m.wptr += sizeof(struct rxf_desc);
+	delta = f->m.wptr - f->m.memsz;
+	if (unlikely(delta >= 0)) {
+		f->m.wptr = delta;
+		if (delta > 0) {
+			memcpy(f->m.va, f->m.va + f->m.memsz, delta);
+			DBG("wrapped descriptor\n");
+		}
+	}
+	RET();
+}
+
+/* bdx_rx_receive - recieves full packets from RXD fifo and pass them to OS
+ * NOTE: a special treatment is given to non-continous descriptors
+ * that start near the end, wraps around and continue at the beginning. a second
+ * part is copied right after the first, and then descriptor is interpreted as
+ * normal. fifo has an extra space to allow such operations
+ * @priv - nic's private structure
+ * @f - RXF fifo that needs skbs
+ */
+
+/* TBD: replace memcpy func call by explicite inline asm */
+
+static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget)
+{
+	struct sk_buff *skb, *skb2;
+	struct rxd_desc *rxdd;
+	struct rx_map *dm;
+	struct rxf_fifo *rxf_fifo;
+	int tmp_len, size;
+	int done = 0;
+	int max_done = BDX_MAX_RX_DONE;
+	struct rxdb *db = NULL;
+	/* Unmarshalled descriptor - copy of descriptor in host order */
+	u32 rxd_val1;
+	u16 len;
+	u16 rxd_vlan;
+
+	ENTER;
+	max_done = budget;
+
+	priv->ndev->last_rx = jiffies;
+	f->m.wptr = READ_REG(priv, f->m.reg_WPTR) & TXF_WPTR_WR_PTR;
+
+	size = f->m.wptr - f->m.rptr;
+	if (size < 0)
+		size = f->m.memsz + size;	/* size is negative :-) */
+
+	while (size > 0) {
+
+		rxdd = (struct rxd_desc *)(f->m.va + f->m.rptr);
+		rxd_val1 = CPU_CHIP_SWAP32(rxdd->rxd_val1);
+
+		len = CPU_CHIP_SWAP16(rxdd->len);
+
+		rxd_vlan = CPU_CHIP_SWAP16(rxdd->rxd_vlan);
+
+		print_rxdd(rxdd, rxd_val1, len, rxd_vlan);
+
+		tmp_len = GET_RXD_BC(rxd_val1) << 3;
+		BDX_ASSERT(tmp_len <= 0);
+		size -= tmp_len;
+		if (size < 0)	/* test for partially arrived descriptor */
+			break;
+
+		f->m.rptr += tmp_len;
+
+		tmp_len = f->m.rptr - f->m.memsz;
+		if (unlikely(tmp_len >= 0)) {
+			f->m.rptr = tmp_len;
+			if (tmp_len > 0) {
+				DBG("wrapped desc rptr=%d tmp_len=%d\n",
+				    f->m.rptr, tmp_len);
+				memcpy(f->m.va + f->m.memsz, f->m.va, tmp_len);
+			}
+		}
+
+		if (unlikely(GET_RXD_ERR(rxd_val1))) {
+			DBG("rxd_err = 0x%x\n", GET_RXD_ERR(rxd_val1));
+			priv->net_stats.rx_errors++;
+			bdx_recycle_skb(priv, rxdd);
+			continue;
+		}
+
+		rxf_fifo = &priv->rxf_fifo0;
+		db = priv->rxdb;
+		dm = bdx_rxdb_addr_elem(db, rxdd->va_lo);
+		skb = dm->skb;
+
+		if (len < BDX_COPYBREAK &&
+		    (skb2 = dev_alloc_skb(len + NET_IP_ALIGN))) {
+			skb_reserve(skb2, NET_IP_ALIGN);
+			/*skb_put(skb2, len); */
+			pci_dma_sync_single_for_cpu(priv->pdev,
+						    dm->dma, rxf_fifo->m.pktsz,
+						    PCI_DMA_FROMDEVICE);
+			memcpy(skb2->data, skb->data, len);
+			bdx_recycle_skb(priv, rxdd);
+			skb = skb2;
+		} else {
+			pci_unmap_single(priv->pdev,
+					 dm->dma, rxf_fifo->m.pktsz,
+					 PCI_DMA_FROMDEVICE);
+			bdx_rxdb_free_elem(db, rxdd->va_lo);
+		}
+
+		priv->net_stats.rx_bytes += len;
+
+		skb_put(skb, len);
+		skb->dev = priv->ndev;
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+		skb->protocol = eth_type_trans(skb, priv->ndev);
+
+		/* Non-IP packets aren't checksum-offloaded */
+		if (GET_RXD_PKT_ID(rxd_val1) == 0)
+			skb->ip_summed = CHECKSUM_NONE;
+
+		NETIF_RX_MUX(priv, rxd_val1, rxd_vlan, skb);
+
+		if (++done >= max_done)
+			break;
+	}
+
+	priv->net_stats.rx_packets += done;
+
+	/* FIXME: do smth to minimize pci accesses    */
+	WRITE_REG(priv, f->m.reg_RPTR, f->m.rptr & TXF_WPTR_WR_PTR);
+
+	bdx_rx_alloc_skbs(priv, &priv->rxf_fifo0);
+
+	RET(done);
+}
+
+/*************************************************************************
+ * Debug / Temprorary Code                                               *
+ *************************************************************************/
+static void print_rxdd(struct rxd_desc *rxdd, u32 rxd_val1, u16 len,
+		       u16 rxd_vlan)
+{
+	DBG("ERROR: rxdd bc %d rxfq %d to %d type %d err %d rxp %d "
+	    "pkt_id %d vtag %d len %d vlan_id %d cfi %d prio %d "
+	    "va_lo %d va_hi %d\n",
+	    GET_RXD_BC(rxd_val1), GET_RXD_RXFQ(rxd_val1), GET_RXD_TO(rxd_val1),
+	    GET_RXD_TYPE(rxd_val1), GET_RXD_ERR(rxd_val1),
+	    GET_RXD_RXP(rxd_val1), GET_RXD_PKT_ID(rxd_val1),
+	    GET_RXD_VTAG(rxd_val1), len, GET_RXD_VLAN_ID(rxd_vlan),
+	    GET_RXD_CFI(rxd_vlan), GET_RXD_PRIO(rxd_vlan), rxdd->va_lo,
+	    rxdd->va_hi);
+}
+
+static void print_rxfd(struct rxf_desc *rxfd)
+{
+	DBG("=== RxF desc CHIP ORDER/ENDIANESS =============\n"
+	    "info 0x%x va_lo %u pa_lo 0x%x pa_hi 0x%x len 0x%x\n",
+	    rxfd->info, rxfd->va_lo, rxfd->pa_lo, rxfd->pa_hi, rxfd->len);
+}
+
+/*
+ * TX HW/SW interaction overview
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * There are 2 types of TX communication channels betwean driver and NIC.
+ * 1) TX Free Fifo - TXF - holds ack descriptors for sent packets
+ * 2) TX Data Fifo - TXD - holds descriptors of full buffers.
+ *
+ * Currently NIC supports TSO, checksuming and gather DMA
+ * UFO and IP fragmentation is on the way
+ *
+ * RX SW Data Structures
+ * ~~~~~~~~~~~~~~~~~~~~~
+ * txdb - used to keep track of all skbs owned by SW and their dma addresses.
+ * For TX case, ownership lasts from geting packet via hard_xmit and until HW
+ * acknowledges sent by TXF descriptors.
+ * Implemented as cyclic buffer.
+ * fifo - keeps info about fifo's size and location, relevant HW registers,
+ * usage and skb db. Each RXD and RXF Fifo has its own fifo structure.
+ * Implemented as simple struct.
+ *
+ * TX SW Execution Flow
+ * ~~~~~~~~~~~~~~~~~~~~
+ * OS calls driver's hard_xmit method with packet to sent.
+ * Driver creates DMA mappings, builds TXD descriptors and kicks HW
+ * by updating TXD WPTR.
+ * When packet is sent, HW write us TXF descriptor and SW frees original skb.
+ * To prevent TXD fifo overflow without reading HW registers every time,
+ * SW deploys "tx level" technique.
+ * Upon strart up, tx level is initialized to TXD fifo length.
+ * For every sent packet, SW gets its TXD descriptor sizei
+ * (from precalculated array) and substructs it from tx level.
+ * The size is also stored in txdb. When TXF ack arrives, SW fetch size of
+ * original TXD descriptor from txdb and adds it to tx level.
+ * When Tx level drops under some predefined treshhold, the driver
+ * stops the TX queue. When TX level rises above that level,
+ * the tx queue is enabled again.
+ *
+ * This technique avoids eccessive reading of RPTR and WPTR registers.
+ * As our benchmarks shows, it adds 1.5 Gbit/sec to NIS's throuput.
+ */
+
+/*************************************************************************
+ *     Tx DB                                                             *
+ *************************************************************************/
+static inline int bdx_tx_db_size(struct txdb *db)
+{
+	int taken = db->wptr - db->rptr;
+	if (taken < 0)
+		taken = db->size + 1 + taken;	/* (size + 1) equals memsz */
+
+	return db->size - taken;
+}
+
+/* __bdx_tx_ptr_next - helper function, increment read/write pointer + wrap
+ * @d   - tx data base
+ * @ptr - read or write pointer
+ */
+static inline void __bdx_tx_db_ptr_next(struct txdb *db, struct tx_map **pptr)
+{
+	BDX_ASSERT(db == NULL || pptr == NULL);	/* sanity */
+
+	BDX_ASSERT(*pptr != db->rptr &&	/* expect either read */
+		   *pptr != db->wptr);	/* or write pointer */
+
+	BDX_ASSERT(*pptr < db->start ||	/* pointer has to be */
+		   *pptr >= db->end);	/* in range */
+
+	++*pptr;
+	if (unlikely(*pptr == db->end))
+		*pptr = db->start;
+}
+
+/* bdx_tx_db_inc_rptr - increment read pointer
+ * @d   - tx data base
+ */
+static inline void bdx_tx_db_inc_rptr(struct txdb *db)
+{
+	BDX_ASSERT(db->rptr == db->wptr);	/* can't read from empty db */
+	__bdx_tx_db_ptr_next(db, &db->rptr);
+}
+
+/* bdx_tx_db_inc_rptr - increment write pointer
+ * @d   - tx data base
+ */
+static inline void bdx_tx_db_inc_wptr(struct txdb *db)
+{
+	__bdx_tx_db_ptr_next(db, &db->wptr);
+	BDX_ASSERT(db->rptr == db->wptr);	/* we can not get empty db as
+						   a result of write */
+}
+
+/* bdx_tx_db_init - creates and initializes tx db
+ * @d       - tx data base
+ * @sz_type - size of tx fifo
+ * Returns 0 on success, error code otherwise
+ */
+static int bdx_tx_db_init(struct txdb *d, int sz_type)
+{
+	int memsz = FIFO_SIZE * (1 << (sz_type + 1));
+
+	d->start = vmalloc(memsz);
+	if (!d->start)
+		return -ENOMEM;
+
+	/*
+	 * In order to differentiate between db is empty and db is full
+	 * states at least one element should always be empty in order to
+	 * avoid rptr == wptr which means db is empty
+	 */
+	d->size = memsz / sizeof(struct tx_map) - 1;
+	d->end = d->start + d->size + 1;	/* just after last element */
+
+	/* all dbs are created equally empty */
+	d->rptr = d->start;
+	d->wptr = d->start;
+
+	return 0;
+}
+
+/* bdx_tx_db_close - closes tx db and frees all memory
+ * @d - tx data base
+ */
+static void bdx_tx_db_close(struct txdb *d)
+{
+	BDX_ASSERT(d == NULL);
+
+	if (d->start) {
+		vfree(d->start);
+		d->start = NULL;
+	}
+}
+
+/*************************************************************************
+ *     Tx Engine                                                         *
+ *************************************************************************/
+
+/* sizes of tx desc (including padding if needed) as function
+ * of skb's frag number */
+static struct {
+	u16 bytes;
+	u16 qwords;		/* qword = 64 bit */
+} txd_sizes[MAX_SKB_FRAGS + 1];
+
+/* txdb_map_skb - creates and stores dma mappings for skb's data blocks
+ * @priv - NIC private structure
+ * @skb  - socket buffer to map
+ *
+ * It makes dma mappings for skb's data blocks and writes them to PBL of
+ * new tx descriptor. It also stores them in the tx db, so they could be
+ * unmaped after data was sent. It is reponsibility of a caller to make
+ * sure that there is enough space in the tx db. Last element holds pointer
+ * to skb itself and marked with zero length
+ */
+static inline void
+bdx_tx_map_skb(struct bdx_priv *priv, struct sk_buff *skb,
+	       struct txd_desc *txdd)
+{
+	struct txdb *db = &priv->txdb;
+	struct pbl *pbl = &txdd->pbl[0];
+	int nr_frags = skb_shinfo(skb)->nr_frags;
+	int i;
+
+	db->wptr->len = skb->len - skb->data_len;
+	db->wptr->addr.dma = pci_map_single(priv->pdev, skb->data,
+					    db->wptr->len, PCI_DMA_TODEVICE);
+	pbl->len = CPU_CHIP_SWAP32(db->wptr->len);
+	pbl->pa_lo = CPU_CHIP_SWAP32(L32_64(db->wptr->addr.dma));
+	pbl->pa_hi = CPU_CHIP_SWAP32(H32_64(db->wptr->addr.dma));
+	DBG("=== pbl   len: 0x%x ================\n", pbl->len);
+	DBG("=== pbl pa_lo: 0x%x ================\n", pbl->pa_lo);
+	DBG("=== pbl pa_hi: 0x%x ================\n", pbl->pa_hi);
+	bdx_tx_db_inc_wptr(db);
+
+	for (i = 0; i < nr_frags; i++) {
+		struct skb_frag_struct *frag;
+
+		frag = &skb_shinfo(skb)->frags[i];
+		db->wptr->len = frag->size;
+		db->wptr->addr.dma =
+		    pci_map_page(priv->pdev, frag->page, frag->page_offset,
+				 frag->size, PCI_DMA_TODEVICE);
+
+		pbl++;
+		pbl->len = CPU_CHIP_SWAP32(db->wptr->len);
+		pbl->pa_lo = CPU_CHIP_SWAP32(L32_64(db->wptr->addr.dma));
+		pbl->pa_hi = CPU_CHIP_SWAP32(H32_64(db->wptr->addr.dma));
+		bdx_tx_db_inc_wptr(db);
+	}
+
+	/* add skb clean up info. */
+	db->wptr->len = -txd_sizes[nr_frags].bytes;
+	db->wptr->addr.skb = skb;
+	bdx_tx_db_inc_wptr(db);
+}
+
+/* init_txd_sizes - precalculate sizes of descriptors for skbs up to 16 frags
+ * number of frags is used as index to fetch correct descriptors size,
+ * instead of calculating it each time */
+static void __init init_txd_sizes(void)
+{
+	int i, lwords;
+
+	/* 7 - is number of lwords in txd with one phys buffer
+	 * 3 - is number of lwords used for every additional phys buffer */
+	for (i = 0; i < MAX_SKB_FRAGS + 1; i++) {
+		lwords = 7 + (i * 3);
+		if (lwords & 1)
+			lwords++;	/* pad it with 1 lword */
+		txd_sizes[i].qwords = lwords >> 1;
+		txd_sizes[i].bytes = lwords << 2;
+	}
+}
+
+/* bdx_tx_init - initialize all Tx related stuff.
+ * Namely, TXD and TXF fifos, database etc */
+static int bdx_tx_init(struct bdx_priv *priv)
+{
+	if (bdx_fifo_init(priv, &priv->txd_fifo0.m, priv->txd_size,
+			  regTXD_CFG0_0,
+			  regTXD_CFG1_0, regTXD_RPTR_0, regTXD_WPTR_0))
+		goto err_mem;
+	if (bdx_fifo_init(priv, &priv->txf_fifo0.m, priv->txf_size,
+			  regTXF_CFG0_0,
+			  regTXF_CFG1_0, regTXF_RPTR_0, regTXF_WPTR_0))
+		goto err_mem;
+
+	/* The TX db has to keep mappings for all packets sent (on TxD)
+	 * and not yet reclaimed (on TxF) */
+	if (bdx_tx_db_init(&priv->txdb, max(priv->txd_size, priv->txf_size)))
+		goto err_mem;
+
+	priv->tx_level = BDX_MAX_TX_LEVEL;
+#ifdef BDX_DELAY_WPTR
+	priv->tx_update_mark = priv->tx_level - 1024;
+#endif
+	return 0;
+
+err_mem:
+	ERR("tehuti: %s: Tx init failed\n", priv->ndev->name);
+	return -ENOMEM;
+}
+
+/*
+ * bdx_tx_space - calculates avalable space in TX fifo
+ * @priv - NIC private structure
+ * Returns avaliable space in TX fifo in bytes
+ */
+static inline int bdx_tx_space(struct bdx_priv *priv)
+{
+	struct txd_fifo *f = &priv->txd_fifo0;
+	int fsize;
+
+	f->m.rptr = READ_REG(priv, f->m.reg_RPTR) & TXF_WPTR_WR_PTR;
+	fsize = f->m.rptr - f->m.wptr;
+	if (fsize <= 0)
+		fsize = f->m.memsz + fsize;
+	return (fsize);
+}
+
+/* bdx_tx_transmit - send packet to NIC
+ * @skb - packet to send
+ * ndev - network device assigned to NIC
+ * Return codes:
+ * o NETDEV_TX_OK everything ok.
+ * o NETDEV_TX_BUSY Cannot transmit packet, try later
+ *   Usually a bug, means queue start/stop flow control is broken in
+ *   the driver. Note: the driver must NOT put the skb in its DMA ring.
+ * o NETDEV_TX_LOCKED Locking failed, please retry quickly.
+ */
+static int bdx_tx_transmit(struct sk_buff *skb, struct net_device *ndev)
+{
+	struct bdx_priv *priv = ndev->priv;
+	struct txd_fifo *f = &priv->txd_fifo0;
+	int txd_checksum = 7;	/* full checksum */
+	int txd_lgsnd = 0;
+	int txd_vlan_id = 0;
+	int txd_vtag = 0;
+	int txd_mss = 0;
+
+	int nr_frags = skb_shinfo(skb)->nr_frags;
+	struct txd_desc *txdd;
+	int len;
+	unsigned long flags;
+
+	ENTER;
+	local_irq_save(flags);
+	if (!spin_trylock(&priv->tx_lock)) {
+		local_irq_restore(flags);
+		DBG("%s[%s]: TX locked, returning NETDEV_TX_LOCKED\n",
+		    BDX_DRV_NAME, ndev->name);
+		return NETDEV_TX_LOCKED;
+	}
+
+	/* build tx descriptor */
+	BDX_ASSERT(f->m.wptr >= f->m.memsz);	/* started with valid wptr */
+	txdd = (struct txd_desc *)(f->m.va + f->m.wptr);
+	if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL))
+		txd_checksum = 0;
+
+	if (skb_shinfo(skb)->gso_size) {
+		txd_mss = skb_shinfo(skb)->gso_size;
+		txd_lgsnd = 1;
+		DBG("skb %p skb len %d gso size = %d\n", skb, skb->len,
+		    txd_mss);
+	}
+
+	if (vlan_tx_tag_present(skb)) {
+		/*Cut VLAN ID to 12 bits */
+		txd_vlan_id = vlan_tx_tag_get(skb) & BITS_MASK(12);
+		txd_vtag = 1;
+	}
+
+	txdd->length = CPU_CHIP_SWAP16(skb->len);
+	txdd->mss = CPU_CHIP_SWAP16(txd_mss);
+	txdd->txd_val1 =
+	    CPU_CHIP_SWAP32(TXD_W1_VAL
+			    (txd_sizes[nr_frags].qwords, txd_checksum, txd_vtag,
+			     txd_lgsnd, txd_vlan_id));
+	DBG("=== TxD desc =====================\n");
+	DBG("=== w1: 0x%x ================\n", txdd->txd_val1);
+	DBG("=== w2: mss 0x%x len 0x%x\n", txdd->mss, txdd->length);
+
+	bdx_tx_map_skb(priv, skb, txdd);
+
+	/* increment TXD write pointer. In case of
+	   fifo wrapping copy reminder of the descriptor
+	   to the beginning */
+	f->m.wptr += txd_sizes[nr_frags].bytes;
+	len = f->m.wptr - f->m.memsz;
+	if (unlikely(len >= 0)) {
+		f->m.wptr = len;
+		if (len > 0) {
+			BDX_ASSERT(len > f->m.memsz);
+			memcpy(f->m.va, f->m.va + f->m.memsz, len);
+		}
+	}
+	BDX_ASSERT(f->m.wptr >= f->m.memsz);	/* finished with valid wptr */
+
+	priv->tx_level -= txd_sizes[nr_frags].bytes;
+	BDX_ASSERT(priv->tx_level <= 0 || priv->tx_level > BDX_MAX_TX_LEVEL);
+#ifdef BDX_DELAY_WPTR
+	if (priv->tx_level > priv->tx_update_mark) {
+		/* Force memory writes to complete before letting h/w
+		   know there are new descriptors to fetch.
+		   (might be needed on platforms like IA64)
+		   wmb(); */
+		WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR);
+	} else {
+		if (priv->tx_noupd++ > BDX_NO_UPD_PACKETS) {
+			priv->tx_noupd = 0;
+			WRITE_REG(priv, f->m.reg_WPTR,
+				  f->m.wptr & TXF_WPTR_WR_PTR);
+		}
+	}
+#else
+	/* Force memory writes to complete before letting h/w
+	   know there are new descriptors to fetch.
+	   (might be needed on platforms like IA64)
+	   wmb(); */
+	WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR);
+
+#endif
+	ndev->trans_start = jiffies;
+
+	priv->net_stats.tx_packets++;
+	priv->net_stats.tx_bytes += skb->len;
+
+	if (priv->tx_level < BDX_MIN_TX_LEVEL) {
+		DBG("%s: %s: TX Q STOP level %d\n",
+		    BDX_DRV_NAME, ndev->name, priv->tx_level);
+		netif_stop_queue(ndev);
+	}
+
+	spin_unlock_irqrestore(&priv->tx_lock, flags);
+	return NETDEV_TX_OK;
+}
+
+/* bdx_tx_cleanup - clean TXF fifo, run in the context of IRQ.
+ * @priv - bdx adapter
+ * It scans TXF fifo for descriptors, frees DMA mappings and reports to OS
+ * that those packets were sent
+ */
+static void bdx_tx_cleanup(struct bdx_priv *priv)
+{
+	struct txf_fifo *f = &priv->txf_fifo0;
+	struct txdb *db = &priv->txdb;
+	int tx_level = 0;
+
+	ENTER;
+	f->m.wptr = READ_REG(priv, f->m.reg_WPTR) & TXF_WPTR_MASK;
+	BDX_ASSERT(f->m.rptr >= f->m.memsz);	/* started with valid rptr */
+
+	while (f->m.wptr != f->m.rptr) {
+		f->m.rptr += BDX_TXF_DESC_SZ;
+		f->m.rptr &= f->m.size_mask;
+
+		/* unmap all the fragments */
+		/* first has to come tx_maps containing dma */
+		BDX_ASSERT(db->rptr->len == 0);
+		do {
+			BDX_ASSERT(db->rptr->addr.dma == 0);
+			pci_unmap_page(priv->pdev, db->rptr->addr.dma,
+				       db->rptr->len, PCI_DMA_TODEVICE);
+			bdx_tx_db_inc_rptr(db);
+		} while (db->rptr->len > 0);
+		tx_level -= db->rptr->len;	/* '-' koz len is negative */
+
+		/* now should come skb pointer - free it */
+		dev_kfree_skb_irq(db->rptr->addr.skb);
+		bdx_tx_db_inc_rptr(db);
+	}
+
+	/* let h/w know which TXF descriptors were cleaned */
+	BDX_ASSERT((f->m.wptr & TXF_WPTR_WR_PTR) >= f->m.memsz);
+	WRITE_REG(priv, f->m.reg_RPTR, f->m.rptr & TXF_WPTR_WR_PTR);
+
+	/* We reclaimed resources, so in case the Q is stopped by xmit callback,
+	 * we resume the transmition and use tx_lock to synchronize with xmit.*/
+	spin_lock(&priv->tx_lock);
+	priv->tx_level += tx_level;
+	BDX_ASSERT(priv->tx_level <= 0 || priv->tx_level > BDX_MAX_TX_LEVEL);
+#ifdef BDX_DELAY_WPTR
+	if (priv->tx_noupd) {
+		priv->tx_noupd = 0;
+		WRITE_REG(priv, priv->txd_fifo0.m.reg_WPTR,
+			  priv->txd_fifo0.m.wptr & TXF_WPTR_WR_PTR);
+	}
+#endif
+
+	if (unlikely(netif_queue_stopped(priv->ndev)
+		     && netif_carrier_ok(priv->ndev)
+		     && (priv->tx_level >= BDX_MIN_TX_LEVEL))) {
+		DBG("%s: %s: TX Q WAKE level %d\n",
+		    BDX_DRV_NAME, priv->ndev->name, priv->tx_level);
+		netif_wake_queue(priv->ndev);
+	}
+	spin_unlock(&priv->tx_lock);
+}
+
+/* bdx_tx_free_skbs - frees all skbs from TXD fifo.
+ * It gets called when OS stops this dev, eg upon "ifconfig down" or rmmod
+ */
+static void bdx_tx_free_skbs(struct bdx_priv *priv)
+{
+	struct txdb *db = &priv->txdb;
+
+	ENTER;
+	while (db->rptr != db->wptr) {
+		if (likely(db->rptr->len))
+			pci_unmap_page(priv->pdev, db->rptr->addr.dma,
+				       db->rptr->len, PCI_DMA_TODEVICE);
+		else
+			dev_kfree_skb(db->rptr->addr.skb);
+		bdx_tx_db_inc_rptr(db);
+	}
+	RET();
+}
+
+/* bdx_tx_free - frees all Tx resources */
+static void bdx_tx_free(struct bdx_priv *priv)
+{
+	ENTER;
+	bdx_tx_free_skbs(priv);
+	bdx_fifo_free(priv, &priv->txd_fifo0.m);
+	bdx_fifo_free(priv, &priv->txf_fifo0.m);
+	bdx_tx_db_close(&priv->txdb);
+}
+
+/* bdx_tx_push_desc - push descriptor to TxD fifo
+ * @priv - NIC private structure
+ * @data - desc's data
+ * @size - desc's size
+ *
+ * Pushes desc to TxD fifo and overlaps it if needed.
+ * NOTE: this func does not check for available space. this is responsibility
+ *    of the caller. Neither does it check that data size is smaller then
+ *    fifo size.
+ */
+static void bdx_tx_push_desc(struct bdx_priv *priv, void *data, int size)
+{
+	struct txd_fifo *f = &priv->txd_fifo0;
+	int i = f->m.memsz - f->m.wptr;
+
+	if (size == 0)
+		return;
+
+	if (i > size) {
+		memcpy(f->m.va + f->m.wptr, data, size);
+		f->m.wptr += size;
+	} else {
+		memcpy(f->m.va + f->m.wptr, data, i);
+		f->m.wptr = size - i;
+		memcpy(f->m.va, data + i, f->m.wptr);
+	}
+	WRITE_REG(priv, f->m.reg_WPTR, f->m.wptr & TXF_WPTR_WR_PTR);
+}
+
+/* bdx_tx_push_desc_safe - push descriptor to TxD fifo in a safe way
+ * @priv - NIC private structure
+ * @data - desc's data
+ * @size - desc's size
+ *
+ * NOTE: this func does check for available space and, if neccessary, waits for
+ *   NIC to read existing data before writing new one.
+ */
+static void bdx_tx_push_desc_safe(struct bdx_priv *priv, void *data, int size)
+{
+	int timer = 0;
+	ENTER;
+
+	while (size > 0) {
+		/* we substruct 8 because when fifo is full rptr == wptr
+		   which also means that fifo is empty, we can understand
+		   the difference, but could hw do the same ??? :) */
+		int avail = bdx_tx_space(priv) - 8;
+		if (avail <= 0) {
+			if (timer++ > 300) {	/* prevent endless loop */
+				DBG("timeout while writing desc to TxD fifo\n");
+				break;
+			}
+			udelay(50);	/* give hw a chance to clean fifo */
+			continue;
+		}
+		avail = MIN(avail, size);
+		DBG("about to push  %d bytes starting %p size %d\n", avail,
+		    data, size);
+		bdx_tx_push_desc(priv, data, avail);
+		size -= avail;
+		data += avail;
+	}
+	RET();
+}
+
+/**
+ * bdx_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in bdx_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * bdx_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ *
+ * functions and their order used as explained in
+ * /usr/src/linux/Documentation/DMA-{API,mapping}.txt
+ *
+ */
+
+/* TBD: netif_msg should be checked and implemented. I disable it for now */
+static int __devinit
+bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct net_device *ndev;
+	struct bdx_priv *priv;
+	int err, pci_using_dac, port;
+	unsigned long pciaddr;
+	u32 regionSize;
+	struct pci_nic *nic;
+
+	ENTER;
+
+	nic = vmalloc(sizeof(*nic));
+	if (!nic)
+		RET(-ENOMEM);
+
+    /************** pci *****************/
+	if ((err = pci_enable_device(pdev)))	/* it trigers interrupt, dunno why. */
+		RET(err);			/* it's not a problem though */
+
+	if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) &&
+	    !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) {
+		pci_using_dac = 1;
+	} else {
+		if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) ||
+		    (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) {
+			printk(KERN_ERR "tehuti: No usable DMA configuration"
+					", aborting\n");
+			goto err_dma;
+		}
+		pci_using_dac = 0;
+	}
+
+	if ((err = pci_request_regions(pdev, BDX_DRV_NAME)))
+		goto err_dma;
+
+	pci_set_master(pdev);
+
+	pciaddr = pci_resource_start(pdev, 0);
+	if (!pciaddr) {
+		err = -EIO;
+		ERR("tehuti: no MMIO resource\n");
+		goto err_out_res;
+	}
+	if ((regionSize = pci_resource_len(pdev, 0)) < BDX_REGS_SIZE) {
+		err = -EIO;
+		ERR("tehuti: MMIO resource (%x) too small\n", regionSize);
+		goto err_out_res;
+	}
+
+	nic->regs = ioremap(pciaddr, regionSize);
+	if (!nic->regs) {
+		err = -EIO;
+		ERR("tehuti: ioremap failed\n");
+		goto err_out_res;
+	}
+
+	if (pdev->irq < 2) {
+		err = -EIO;
+		ERR("tehuti: invalid irq (%d)\n", pdev->irq);
+		goto err_out_iomap;
+	}
+	pci_set_drvdata(pdev, nic);
+
+	if (pdev->device == 0x3014)
+		nic->port_num = 2;
+	else
+		nic->port_num = 1;
+
+	print_hw_id(pdev);
+
+	bdx_hw_reset_direct(nic->regs);
+
+	nic->irq_type = IRQ_INTX;
+#ifdef BDX_MSI
+	if ((readl(nic->regs + FPGA_VER) & 0xFFF) >= 378) {
+		if ((err = pci_enable_msi(pdev)))
+			ERR("Tehuti: Can't eneble msi. error is %d\n", err);
+		else
+			nic->irq_type = IRQ_MSI;
+	} else
+		DBG("HW does not support MSI\n");
+#endif
+
+    /************** netdev **************/
+	for (port = 0; port < nic->port_num; port++) {
+		if (!(ndev = alloc_etherdev(sizeof(struct bdx_priv)))) {
+			err = -ENOMEM;
+			printk(KERN_ERR "tehuti: alloc_etherdev failed\n");
+			goto err_out_iomap;
+		}
+
+		ndev->open = bdx_open;
+		ndev->stop = bdx_close;
+		ndev->hard_start_xmit = bdx_tx_transmit;
+		ndev->do_ioctl = bdx_ioctl;
+		ndev->set_multicast_list = bdx_setmulti;
+		ndev->get_stats = bdx_get_stats;
+		ndev->change_mtu = bdx_change_mtu;
+		ndev->set_mac_address = bdx_set_mac;
+		ndev->tx_queue_len = BDX_NDEV_TXQ_LEN;
+		ndev->vlan_rx_register = bdx_vlan_rx_register;
+		ndev->vlan_rx_add_vid = bdx_vlan_rx_add_vid;
+		ndev->vlan_rx_kill_vid = bdx_vlan_rx_kill_vid;
+
+		bdx_ethtool_ops(ndev);	/* ethtool interface */
+
+		/* these fields are used for info purposes only
+		 * so we can have them same for all ports of the board */
+		ndev->if_port = port;
+		ndev->base_addr = pciaddr;
+		ndev->mem_start = pciaddr;
+		ndev->mem_end = pciaddr + regionSize;
+		ndev->irq = pdev->irq;
+		ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO
+		    | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
+		    NETIF_F_HW_VLAN_FILTER
+		    /*| NETIF_F_FRAGLIST */
+		    ;
+
+		if (pci_using_dac)
+			ndev->features |= NETIF_F_HIGHDMA;
+
+	/************** priv ****************/
+		priv = nic->priv[port] = ndev->priv;
+
+		memset(priv, 0, sizeof(struct bdx_priv));
+		priv->pBdxRegs = nic->regs + port * 0x8000;
+		priv->port = port;
+		priv->pdev = pdev;
+		priv->ndev = ndev;
+		priv->nic = nic;
+		priv->msg_enable = BDX_DEF_MSG_ENABLE;
+
+		netif_napi_add(ndev, &priv->napi, bdx_poll, 64);
+
+		if ((readl(nic->regs + FPGA_VER) & 0xFFF) == 308) {
+			DBG("HW statistics not supported\n");
+			priv->stats_flag = 0;
+		} else {
+			priv->stats_flag = 1;
+		}
+
+		/* Initialize fifo sizes. */
+		priv->txd_size = 2;
+		priv->txf_size = 2;
+		priv->rxd_size = 2;
+		priv->rxf_size = 3;
+
+		/* Initialize the initial coalescing registers. */
+		priv->rdintcm = INT_REG_VAL(0x20, 1, 4, 12);
+		priv->tdintcm = INT_REG_VAL(0x20, 1, 0, 12);
+
+		/* ndev->xmit_lock spinlock is not used.
+		 * Private priv->tx_lock is used for synchronization
+		 * between transmit and TX irq cleanup.  In addition
+		 * set multicast list callback has to use priv->tx_lock.
+		 */
+#ifdef BDX_LLTX
+		ndev->features |= NETIF_F_LLTX;
+#endif
+		spin_lock_init(&priv->tx_lock);
+
+		/*bdx_hw_reset(priv); */
+		if (bdx_read_mac(priv)) {
+			printk(KERN_ERR "tehuti: load MAC address failed\n");
+			goto err_out_iomap;
+		}
+		SET_NETDEV_DEV(ndev, &pdev->dev);
+		if ((err = register_netdev(ndev))) {
+			printk(KERN_ERR "tehuti: register_netdev failed\n");
+			goto err_out_free;
+		}
+		netif_carrier_off(ndev);
+		netif_stop_queue(ndev);
+
+		print_eth_id(ndev);
+	}
+	RET(0);
+
+err_out_free:
+	free_netdev(ndev);
+err_out_iomap:
+	iounmap(nic->regs);
+err_out_res:
+	pci_release_regions(pdev);
+err_dma:
+	pci_disable_device(pdev);
+	vfree(nic);
+
+	RET(err);
+}
+
+/****************** Ethtool interface *********************/
+/* get strings for tests */
+static const char
+ bdx_test_names[][ETH_GSTRING_LEN] = {
+	"No tests defined"
+};
+
+/* get strings for statistics counters */
+static const char
+ bdx_stat_names[][ETH_GSTRING_LEN] = {
+	"InUCast",		/* 0x7200 */
+	"InMCast",		/* 0x7210 */
+	"InBCast",		/* 0x7220 */
+	"InPkts",		/* 0x7230 */
+	"InErrors",		/* 0x7240 */
+	"InDropped",		/* 0x7250 */
+	"FrameTooLong",		/* 0x7260 */
+	"FrameSequenceErrors",	/* 0x7270 */
+	"InVLAN",		/* 0x7280 */
+	"InDroppedDFE",		/* 0x7290 */
+	"InDroppedIntFull",	/* 0x72A0 */
+	"InFrameAlignErrors",	/* 0x72B0 */
+
+	/* 0x72C0-0x72E0 RSRV */
+
+	"OutUCast",		/* 0x72F0 */
+	"OutMCast",		/* 0x7300 */
+	"OutBCast",		/* 0x7310 */
+	"OutPkts",		/* 0x7320 */
+
+	/* 0x7330-0x7360 RSRV */
+
+	"OutVLAN",		/* 0x7370 */
+	"InUCastOctects",	/* 0x7380 */
+	"OutUCastOctects",	/* 0x7390 */
+
+	/* 0x73A0-0x73B0 RSRV */
+
+	"InBCastOctects",	/* 0x73C0 */
+	"OutBCastOctects",	/* 0x73D0 */
+	"InOctects",		/* 0x73E0 */
+	"OutOctects",		/* 0x73F0 */
+};
+
+/*
+ * bdx_get_settings - get device-specific settings
+ * @netdev
+ * @ecmd
+ */
+static int bdx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+	u32 rdintcm;
+	u32 tdintcm;
+	struct bdx_priv *priv = netdev->priv;
+
+	rdintcm = priv->rdintcm;
+	tdintcm = priv->tdintcm;
+
+	ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
+	ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
+	ecmd->speed = SPEED_10000;
+	ecmd->duplex = DUPLEX_FULL;
+	ecmd->port = PORT_FIBRE;
+	ecmd->transceiver = XCVR_EXTERNAL;	/* what does it mean? */
+	ecmd->autoneg = AUTONEG_DISABLE;
+
+	/* PCK_TH measures in multiples of FIFO bytes
+	   We translate to packets */
+	ecmd->maxtxpkt =
+	    ((GET_PCK_TH(tdintcm) * PCK_TH_MULT) / BDX_TXF_DESC_SZ);
+	ecmd->maxrxpkt =
+	    ((GET_PCK_TH(rdintcm) * PCK_TH_MULT) / sizeof(struct rxf_desc));
+
+	return 0;
+}
+
+/*
+ * bdx_get_drvinfo - report driver information
+ * @netdev
+ * @drvinfo
+ */
+static void
+bdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
+{
+	struct bdx_priv *priv = netdev->priv;
+
+	strncat(drvinfo->driver, BDX_DRV_NAME, sizeof(drvinfo->driver));
+	strncat(drvinfo->version, BDX_DRV_VERSION, sizeof(drvinfo->version));
+	strncat(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+	strncat(drvinfo->bus_info, pci_name(priv->pdev),
+		sizeof(drvinfo->bus_info));
+
+	drvinfo->n_stats = ((priv->stats_flag) ?
+			    (sizeof(bdx_stat_names) / ETH_GSTRING_LEN) : 0);
+	drvinfo->testinfo_len = 0;
+	drvinfo->regdump_len = 0;
+	drvinfo->eedump_len = 0;
+}
+
+/*
+ * bdx_get_rx_csum - report whether receive checksums are turned on or off
+ * @netdev
+ */
+static u32 bdx_get_rx_csum(struct net_device *netdev)
+{
+	return 1;		/* always on */
+}
+
+/*
+ * bdx_get_tx_csum - report whether transmit checksums are turned on or off
+ * @netdev
+ */
+static u32 bdx_get_tx_csum(struct net_device *netdev)
+{
+	return (netdev->features & NETIF_F_IP_CSUM) != 0;
+}
+
+/*
+ * bdx_get_coalesce - get interrupt coalescing parameters
+ * @netdev
+ * @ecoal
+ */
+static int
+bdx_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal)
+{
+	u32 rdintcm;
+	u32 tdintcm;
+	struct bdx_priv *priv = netdev->priv;
+
+	rdintcm = priv->rdintcm;
+	tdintcm = priv->tdintcm;
+
+	/* PCK_TH measures in multiples of FIFO bytes
+	   We translate to packets */
+	ecoal->rx_coalesce_usecs = GET_INT_COAL(rdintcm) * INT_COAL_MULT;
+	ecoal->rx_max_coalesced_frames =
+	    ((GET_PCK_TH(rdintcm) * PCK_TH_MULT) / sizeof(struct rxf_desc));
+
+	ecoal->tx_coalesce_usecs = GET_INT_COAL(tdintcm) * INT_COAL_MULT;
+	ecoal->tx_max_coalesced_frames =
+	    ((GET_PCK_TH(tdintcm) * PCK_TH_MULT) / BDX_TXF_DESC_SZ);
+
+	/* adaptive parameters ignored */
+	return 0;
+}
+
+/*
+ * bdx_set_coalesce - set interrupt coalescing parameters
+ * @netdev
+ * @ecoal
+ */
+static int
+bdx_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal)
+{
+	u32 rdintcm;
+	u32 tdintcm;
+	struct bdx_priv *priv = netdev->priv;
+	int rx_coal;
+	int tx_coal;
+	int rx_max_coal;
+	int tx_max_coal;
+
+	/* Check for valid input */
+	rx_coal = ecoal->rx_coalesce_usecs / INT_COAL_MULT;
+	tx_coal = ecoal->tx_coalesce_usecs / INT_COAL_MULT;
+	rx_max_coal = ecoal->rx_max_coalesced_frames;
+	tx_max_coal = ecoal->tx_max_coalesced_frames;
+
+	/* Translate from packets to multiples of FIFO bytes */
+	rx_max_coal =
+	    (((rx_max_coal * sizeof(struct rxf_desc)) + PCK_TH_MULT - 1)
+	     / PCK_TH_MULT);
+	tx_max_coal =
+	    (((tx_max_coal * BDX_TXF_DESC_SZ) + PCK_TH_MULT - 1)
+	     / PCK_TH_MULT);
+
+	if ((rx_coal > 0x7FFF) || (tx_coal > 0x7FFF)
+	    || (rx_max_coal > 0xF) || (tx_max_coal > 0xF))
+		return -EINVAL;
+
+	rdintcm = INT_REG_VAL(rx_coal, GET_INT_COAL_RC(priv->rdintcm),
+			      GET_RXF_TH(priv->rdintcm), rx_max_coal);
+	tdintcm = INT_REG_VAL(tx_coal, GET_INT_COAL_RC(priv->tdintcm), 0,
+			      tx_max_coal);
+
+	priv->rdintcm = rdintcm;
+	priv->tdintcm = tdintcm;
+
+	WRITE_REG(priv, regRDINTCM0, rdintcm);
+	WRITE_REG(priv, regTDINTCM0, tdintcm);
+
+	return 0;
+}
+
+/* Convert RX fifo size to number of pending packets */
+static inline int bdx_rx_fifo_size_to_packets(int rx_size)
+{
+	return ((FIFO_SIZE * (1 << rx_size)) / sizeof(struct rxf_desc));
+}
+
+/* Convert TX fifo size to number of pending packets */
+static inline int bdx_tx_fifo_size_to_packets(int tx_size)
+{
+	return ((FIFO_SIZE * (1 << tx_size)) / BDX_TXF_DESC_SZ);
+}
+
+/*
+ * bdx_get_ringparam - report ring sizes
+ * @netdev
+ * @ring
+ */
+static void
+bdx_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
+{
+	struct bdx_priv *priv = netdev->priv;
+
+	/*max_pending - the maximum-sized FIFO we allow */
+	ring->rx_max_pending = bdx_rx_fifo_size_to_packets(3);
+	ring->tx_max_pending = bdx_tx_fifo_size_to_packets(3);
+	ring->rx_pending = bdx_rx_fifo_size_to_packets(priv->rxf_size);
+	ring->tx_pending = bdx_tx_fifo_size_to_packets(priv->txd_size);
+}
+
+/*
+ * bdx_set_ringparam - set ring sizes
+ * @netdev
+ * @ring
+ */
+static int
+bdx_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
+{
+	struct bdx_priv *priv = netdev->priv;
+	int rx_size = 0;
+	int tx_size = 0;
+
+	for (; rx_size < 4; rx_size++) {
+		if (bdx_rx_fifo_size_to_packets(rx_size) >= ring->rx_pending)
+			break;
+	}
+	if (rx_size == 4)
+		rx_size = 3;
+
+	for (; tx_size < 4; tx_size++) {
+		if (bdx_tx_fifo_size_to_packets(tx_size) >= ring->tx_pending)
+			break;
+	}
+	if (tx_size == 4)
+		tx_size = 3;
+
+	/*Is there anything to do? */
+	if ((rx_size == priv->rxf_size)
+	    && (tx_size == priv->txd_size))
+		return 0;
+
+	priv->rxf_size = rx_size;
+	if (rx_size > 1)
+		priv->rxd_size = rx_size - 1;
+	else
+		priv->rxd_size = rx_size;
+
+	priv->txf_size = priv->txd_size = tx_size;
+
+	if (netif_running(netdev)) {
+		bdx_close(netdev);
+		bdx_open(netdev);
+	}
+	return 0;
+}
+
+/*
+ * bdx_get_strings - return a set of strings that describe the requested objects
+ * @netdev
+ * @data
+ */
+static void bdx_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
+{
+	switch (stringset) {
+	case ETH_SS_TEST:
+		memcpy(data, *bdx_test_names, sizeof(bdx_test_names));
+		break;
+	case ETH_SS_STATS:
+		memcpy(data, *bdx_stat_names, sizeof(bdx_stat_names));
+		break;
+	}
+}
+
+/*
+ * bdx_get_stats_count - return number of 64bit statistics counters
+ * @netdev
+ */
+static int bdx_get_stats_count(struct net_device *netdev)
+{
+	struct bdx_priv *priv = netdev->priv;
+	BDX_ASSERT(sizeof(bdx_stat_names) / ETH_GSTRING_LEN
+		   != sizeof(struct bdx_stats) / sizeof(u64));
+	return ((priv->stats_flag) ? (sizeof(bdx_stat_names) / ETH_GSTRING_LEN)
+		: 0);
+}
+
+/*
+ * bdx_get_ethtool_stats - return device's hardware L2 statistics
+ * @netdev
+ * @stats
+ * @data
+ */
+static void bdx_get_ethtool_stats(struct net_device *netdev,
+				  struct ethtool_stats *stats, u64 *data)
+{
+	struct bdx_priv *priv = netdev->priv;
+
+	if (priv->stats_flag) {
+
+		/* Update stats from HW */
+		bdx_update_stats(priv);
+
+		/* Copy data to user buffer */
+		memcpy(data, &priv->hw_stats, sizeof(priv->hw_stats));
+	}
+}
+
+/*
+ * bdx_ethtool_ops - ethtool interface implementation
+ * @netdev
+ */
+static void bdx_ethtool_ops(struct net_device *netdev)
+{
+	static struct ethtool_ops bdx_ethtool_ops = {
+		.get_settings = bdx_get_settings,
+		.get_drvinfo = bdx_get_drvinfo,
+		.get_link = ethtool_op_get_link,
+		.get_coalesce = bdx_get_coalesce,
+		.set_coalesce = bdx_set_coalesce,
+		.get_ringparam = bdx_get_ringparam,
+		.set_ringparam = bdx_set_ringparam,
+		.get_rx_csum = bdx_get_rx_csum,
+		.get_tx_csum = bdx_get_tx_csum,
+		.get_sg = ethtool_op_get_sg,
+		.get_tso = ethtool_op_get_tso,
+		.get_strings = bdx_get_strings,
+		.get_stats_count = bdx_get_stats_count,
+		.get_ethtool_stats = bdx_get_ethtool_stats,
+	};
+
+	SET_ETHTOOL_OPS(netdev, &bdx_ethtool_ops);
+}
+
+/**
+ * bdx_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * bdx_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.  The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void __devexit bdx_remove(struct pci_dev *pdev)
+{
+	struct pci_nic *nic = pci_get_drvdata(pdev);
+	struct net_device *ndev;
+	int port;
+
+	for (port = 0; port < nic->port_num; port++) {
+		ndev = nic->priv[port]->ndev;
+		unregister_netdev(ndev);
+		free_netdev(ndev);
+	}
+
+	/*bdx_hw_reset_direct(nic->regs); */
+#ifdef BDX_MSI
+	if (nic->irq_type == IRQ_MSI)
+		pci_disable_msi(pdev);
+#endif
+
+	iounmap(nic->regs);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	vfree(nic);
+
+	RET();
+}
+
+static struct pci_driver bdx_pci_driver = {
+	.name = BDX_DRV_NAME,
+	.id_table = bdx_pci_tbl,
+	.probe = bdx_probe,
+	.remove = __devexit_p(bdx_remove),
+};
+
+/*
+ * print_driver_id - print parameters of the driver build
+ */
+static void __init print_driver_id(void)
+{
+	printk(KERN_INFO "%s: %s, %s\n", BDX_DRV_NAME, BDX_DRV_DESC,
+	       BDX_DRV_VERSION);
+	printk(KERN_INFO "%s: Options: hw_csum %s\n", BDX_DRV_NAME,
+	       BDX_MSI_STRING);
+}
+
+static int __init bdx_module_init(void)
+{
+	ENTER;
+	bdx_firmware_endianess();
+	init_txd_sizes();
+	print_driver_id();
+	RET(pci_register_driver(&bdx_pci_driver));
+}
+
+module_init(bdx_module_init);
+
+static void __exit bdx_module_exit(void)
+{
+	ENTER;
+	pci_unregister_driver(&bdx_pci_driver);
+	RET();
+}
+
+module_exit(bdx_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(BDX_DRV_DESC);
diff --git a/drivers/net/tehuti.h b/drivers/net/tehuti.h
new file mode 100644
index 0000000..efd170f
--- /dev/null
+++ b/drivers/net/tehuti.h
@@ -0,0 +1,564 @@
+/*
+ * Tehuti Networks(R) Network Driver
+ * Copyright (C) 2007 Tehuti Networks Ltd. All rights reserved
+ *
+ * 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.
+ */
+
+#ifndef _TEHUTI_H
+#define _TEHUTI_H
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+#include <linux/uaccess.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/if_vlan.h>
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
+#include <asm/byteorder.h>
+
+/* Compile Time Switches */
+/* start */
+#define BDX_TSO
+#define BDX_LLTX
+#define BDX_DELAY_WPTR
+/* #define BDX_MSI */
+/* end */
+
+#if !defined CONFIG_PCI_MSI
+#   undef BDX_MSI
+#endif
+
+#define BDX_DEF_MSG_ENABLE	(NETIF_MSG_DRV          | \
+				NETIF_MSG_PROBE        | \
+				NETIF_MSG_LINK)
+
+/* ioctl ops */
+#define BDX_OP_READ  1
+#define BDX_OP_WRITE 2
+
+/* RX copy break size */
+#define BDX_COPYBREAK    257
+
+#define DRIVER_AUTHOR     "Tehuti Networks(R)"
+#define BDX_DRV_DESC      "Tehuti Networks(R) Network Driver"
+#define BDX_DRV_NAME      "tehuti"
+#define BDX_NIC_NAME      "Tehuti 10 Giga TOE SmartNIC"
+#define BDX_NIC2PORT_NAME "Tehuti 2-Port 10 Giga TOE SmartNIC"
+#define BDX_DRV_VERSION   "7.29.3"
+
+#ifdef BDX_MSI
+#    define BDX_MSI_STRING "msi "
+#else
+#    define BDX_MSI_STRING ""
+#endif
+
+/* netdev tx queue len for Luxor. default value is, btw, 1000
+ * ifcontig eth1 txqueuelen 3000 - to change it at runtime */
+#define BDX_NDEV_TXQ_LEN 3000
+
+#define FIFO_SIZE  4096
+#define FIFO_EXTRA_SPACE            1024
+
+#define MIN(x, y)  ((x) < (y) ? (x) : (y))
+
+#if BITS_PER_LONG == 64
+#    define H32_64(x)  (u32) ((u64)(x) >> 32)
+#    define L32_64(x)  (u32) ((u64)(x) & 0xffffffff)
+#elif BITS_PER_LONG == 32
+#    define H32_64(x)  0
+#    define L32_64(x)  ((u32) (x))
+#else				/* BITS_PER_LONG == ?? */
+#    error BITS_PER_LONG is undefined. Must be 64 or 32
+#endif				/* BITS_PER_LONG */
+
+#ifdef __BIG_ENDIAN
+#   define CPU_CHIP_SWAP32(x) swab32(x)
+#   define CPU_CHIP_SWAP16(x) swab16(x)
+#else
+#   define CPU_CHIP_SWAP32(x) (x)
+#   define CPU_CHIP_SWAP16(x) (x)
+#endif
+
+#define READ_REG(pp, reg)         readl(pp->pBdxRegs + reg)
+#define WRITE_REG(pp, reg, val)   writel(val, pp->pBdxRegs + reg)
+
+#ifndef DMA_64BIT_MASK
+#   define DMA_64BIT_MASK  0xffffffffffffffffULL
+#endif
+
+#ifndef DMA_32BIT_MASK
+#   define DMA_32BIT_MASK  0x00000000ffffffffULL
+#endif
+
+#ifndef NET_IP_ALIGN
+#   define NET_IP_ALIGN 2
+#endif
+
+#ifndef NETDEV_TX_OK
+#   define NETDEV_TX_OK 0
+#endif
+
+#define LUXOR_MAX_PORT     2
+#define BDX_MAX_RX_DONE    150
+#define BDX_TXF_DESC_SZ    16
+#define BDX_MAX_TX_LEVEL   (priv->txd_fifo0.m.memsz - 16)
+#define BDX_MIN_TX_LEVEL   256
+#define BDX_NO_UPD_PACKETS 40
+
+struct pci_nic {
+	int port_num;
+	void __iomem *regs;
+	int irq_type;
+	struct bdx_priv *priv[LUXOR_MAX_PORT];
+};
+
+enum { IRQ_INTX, IRQ_MSI, IRQ_MSIX };
+
+#define PCK_TH_MULT   128
+#define INT_COAL_MULT 2
+
+#define BITS_MASK(nbits)			((1<<nbits)-1)
+#define GET_BITS_SHIFT(x, nbits, nshift)	(((x)>>nshift)&BITS_MASK(nbits))
+#define BITS_SHIFT_MASK(nbits, nshift)		(BITS_MASK(nbits)<<nshift)
+#define BITS_SHIFT_VAL(x, nbits, nshift)	(((x)&BITS_MASK(nbits))<<nshift)
+#define BITS_SHIFT_CLEAR(x, nbits, nshift)	\
+	((x)&(~BITS_SHIFT_MASK(nbits, nshift)))
+
+#define GET_INT_COAL(x)				GET_BITS_SHIFT(x, 15, 0)
+#define GET_INT_COAL_RC(x)			GET_BITS_SHIFT(x, 1, 15)
+#define GET_RXF_TH(x)				GET_BITS_SHIFT(x, 4, 16)
+#define GET_PCK_TH(x)				GET_BITS_SHIFT(x, 4, 20)
+
+#define INT_REG_VAL(coal, coal_rc, rxf_th, pck_th)	\
+	((coal)|((coal_rc)<<15)|((rxf_th)<<16)|((pck_th)<<20))
+
+struct fifo {
+	dma_addr_t da;		/* physical address of fifo (used by HW) */
+	char *va;		/* virtual address of fifo (used by SW) */
+	u32 rptr, wptr;		/* cached values of RPTR and WPTR registers,
+				   they're 32 bits on both 32 and 64 archs */
+	u16 reg_CFG0, reg_CFG1;
+	u16 reg_RPTR, reg_WPTR;
+	u16 memsz;		/* memory size allocated for fifo */
+	u16 size_mask;
+	u16 pktsz;		/* skb packet size to allocate */
+	u16 rcvno;		/* number of buffers that come from this RXF */
+};
+
+struct txf_fifo {
+	struct fifo m;		/* minimal set of variables used by all fifos */
+};
+
+struct txd_fifo {
+	struct fifo m;		/* minimal set of variables used by all fifos */
+};
+
+struct rxf_fifo {
+	struct fifo m;		/* minimal set of variables used by all fifos */
+};
+
+struct rxd_fifo {
+	struct fifo m;		/* minimal set of variables used by all fifos */
+};
+
+struct rx_map {
+	u64 dma;
+	struct sk_buff *skb;
+};
+
+struct rxdb {
+	int *stack;
+	struct rx_map *elems;
+	int nelem;
+	int top;
+};
+
+union bdx_dma_addr {
+	dma_addr_t dma;
+	struct sk_buff *skb;
+};
+
+/* Entry in the db.
+ * if len == 0 addr is dma
+ * if len != 0 addr is skb */
+struct tx_map {
+	union bdx_dma_addr addr;
+	int len;
+};
+
+/* tx database - implemented as circular fifo buffer*/
+struct txdb {
+	struct tx_map *start;	/* points to the first element */
+	struct tx_map *end;	/* points just AFTER the last element */
+	struct tx_map *rptr;	/* points to the next element to read */
+	struct tx_map *wptr;	/* points to the next element to write */
+	int size;		/* number of elements in the db */
+};
+
+/*Internal stats structure*/
+struct bdx_stats {
+	u64 InUCast;			/* 0x7200 */
+	u64 InMCast;			/* 0x7210 */
+	u64 InBCast;			/* 0x7220 */
+	u64 InPkts;			/* 0x7230 */
+	u64 InErrors;			/* 0x7240 */
+	u64 InDropped;			/* 0x7250 */
+	u64 FrameTooLong;		/* 0x7260 */
+	u64 FrameSequenceErrors;	/* 0x7270 */
+	u64 InVLAN;			/* 0x7280 */
+	u64 InDroppedDFE;		/* 0x7290 */
+	u64 InDroppedIntFull;		/* 0x72A0 */
+	u64 InFrameAlignErrors;		/* 0x72B0 */
+
+	/* 0x72C0-0x72E0 RSRV */
+
+	u64 OutUCast;			/* 0x72F0 */
+	u64 OutMCast;			/* 0x7300 */
+	u64 OutBCast;			/* 0x7310 */
+	u64 OutPkts;			/* 0x7320 */
+
+	/* 0x7330-0x7360 RSRV */
+
+	u64 OutVLAN;			/* 0x7370 */
+	u64 InUCastOctects;		/* 0x7380 */
+	u64 OutUCastOctects;		/* 0x7390 */
+
+	/* 0x73A0-0x73B0 RSRV */
+
+	u64 InBCastOctects;		/* 0x73C0 */
+	u64 OutBCastOctects;		/* 0x73D0 */
+	u64 InOctects;			/* 0x73E0 */
+	u64 OutOctects;			/* 0x73F0 */
+};
+
+struct bdx_priv {
+	void __iomem *pBdxRegs;
+	struct net_device *ndev;
+
+	struct napi_struct napi;
+
+	/* RX FIFOs: 1 for data (full) descs, and 2 for free descs */
+	struct rxd_fifo rxd_fifo0;
+	struct rxf_fifo rxf_fifo0;
+	struct rxdb *rxdb;	/* rx dbs to store skb pointers */
+	int napi_stop;
+	struct vlan_group *vlgrp;
+
+	/* Tx FIFOs: 1 for data desc, 1 for empty (acks) desc */
+	struct txd_fifo txd_fifo0;
+	struct txf_fifo txf_fifo0;
+
+	struct txdb txdb;
+	int tx_level;
+#ifdef BDX_DELAY_WPTR
+	int tx_update_mark;
+	int tx_noupd;
+#endif
+	spinlock_t tx_lock;	/* NETIF_F_LLTX mode */
+
+	/* rarely used */
+	u8 port;
+	u32 msg_enable;
+	int stats_flag;
+	struct bdx_stats hw_stats;
+	struct net_device_stats net_stats;
+	struct pci_dev *pdev;
+
+	struct pci_nic *nic;
+
+	u8 txd_size;
+	u8 txf_size;
+	u8 rxd_size;
+	u8 rxf_size;
+	u32 rdintcm;
+	u32 tdintcm;
+};
+
+/* RX FREE descriptor - 64bit*/
+struct rxf_desc {
+	u32 info;		/* Buffer Count + Info - described below */
+	u32 va_lo;		/* VAdr[31:0] */
+	u32 va_hi;		/* VAdr[63:32] */
+	u32 pa_lo;		/* PAdr[31:0] */
+	u32 pa_hi;		/* PAdr[63:32] */
+	u32 len;		/* Buffer Length */
+};
+
+#define GET_RXD_BC(x)			GET_BITS_SHIFT((x), 5, 0)
+#define GET_RXD_RXFQ(x)			GET_BITS_SHIFT((x), 2, 8)
+#define GET_RXD_TO(x)			GET_BITS_SHIFT((x), 1, 15)
+#define GET_RXD_TYPE(x)			GET_BITS_SHIFT((x), 4, 16)
+#define GET_RXD_ERR(x)			GET_BITS_SHIFT((x), 6, 21)
+#define GET_RXD_RXP(x)			GET_BITS_SHIFT((x), 1, 27)
+#define GET_RXD_PKT_ID(x)		GET_BITS_SHIFT((x), 3, 28)
+#define GET_RXD_VTAG(x)			GET_BITS_SHIFT((x), 1, 31)
+#define GET_RXD_VLAN_ID(x)		GET_BITS_SHIFT((x), 12, 0)
+#define GET_RXD_CFI(x)			GET_BITS_SHIFT((x), 1, 12)
+#define GET_RXD_PRIO(x)			GET_BITS_SHIFT((x), 3, 13)
+
+struct rxd_desc {
+	u32 rxd_val1;
+	u16 len;
+	u16 rxd_vlan;
+	u32 va_lo;
+	u32 va_hi;
+};
+
+/* PBL describes each virtual buffer to be */
+/* transmitted from the host.*/
+struct pbl {
+	u32 pa_lo;
+	u32 pa_hi;
+	u32 len;
+};
+
+/* First word for TXD descriptor. It means: type = 3 for regular Tx packet,
+ * hw_csum = 7 for ip+udp+tcp hw checksums */
+#define TXD_W1_VAL(bc, checksum, vtag, lgsnd, vlan_id)	\
+	((bc) | ((checksum)<<5) | ((vtag)<<8) | \
+	((lgsnd)<<9) | (0x30000) | ((vlan_id)<<20))
+
+struct txd_desc {
+	u32 txd_val1;
+	u16 mss;
+	u16 length;
+	u32 va_lo;
+	u32 va_hi;
+	struct pbl pbl[0];	/* Fragments */
+} __attribute__ ((packed));
+
+/* Register region size */
+#define BDX_REGS_SIZE	  0x1000
+
+/* Registers from 0x0000-0x00fc were remapped to 0x4000-0x40fc */
+#define regTXD_CFG1_0   0x4000
+#define regRXF_CFG1_0   0x4010
+#define regRXD_CFG1_0   0x4020
+#define regTXF_CFG1_0   0x4030
+#define regTXD_CFG0_0   0x4040
+#define regRXF_CFG0_0   0x4050
+#define regRXD_CFG0_0   0x4060
+#define regTXF_CFG0_0   0x4070
+#define regTXD_WPTR_0   0x4080
+#define regRXF_WPTR_0   0x4090
+#define regRXD_WPTR_0   0x40A0
+#define regTXF_WPTR_0   0x40B0
+#define regTXD_RPTR_0   0x40C0
+#define regRXF_RPTR_0   0x40D0
+#define regRXD_RPTR_0   0x40E0
+#define regTXF_RPTR_0   0x40F0
+#define regTXF_RPTR_3   0x40FC
+
+/* hardware versioning */
+#define  FW_VER         0x5010
+#define  SROM_VER       0x5020
+#define  FPGA_VER       0x5030
+#define  FPGA_SEED      0x5040
+
+/* Registers from 0x0100-0x0150 were remapped to 0x5100-0x5150 */
+#define regISR regISR0
+#define regISR0          0x5100
+
+#define regIMR regIMR0
+#define regIMR0          0x5110
+
+#define regRDINTCM0      0x5120
+#define regRDINTCM2      0x5128
+
+#define regTDINTCM0      0x5130
+
+#define regISR_MSK0      0x5140
+
+#define regINIT_SEMAPHORE 0x5170
+#define regINIT_STATUS    0x5180
+
+#define regMAC_LNK_STAT  0x0200
+#define MAC_LINK_STAT    0x4	/* Link state */
+
+#define regGMAC_RXF_A   0x1240
+
+#define regUNC_MAC0_A   0x1250
+#define regUNC_MAC1_A   0x1260
+#define regUNC_MAC2_A   0x1270
+
+#define regVLAN_0       0x1800
+
+#define regMAX_FRAME_A  0x12C0
+
+#define regRX_MAC_MCST0    0x1A80
+#define regRX_MAC_MCST1    0x1A84
+#define MAC_MCST_NUM       15
+#define regRX_MCST_HASH0   0x1A00
+#define MAC_MCST_HASH_NUM  8
+
+#define regVPC                  0x2300
+#define regVIC                  0x2320
+#define regVGLB                 0x2340
+
+#define regCLKPLL               0x5000
+
+/*for 10G only*/
+#define regREVISION        0x6000
+#define regSCRATCH         0x6004
+#define regCTRLST          0x6008
+#define regMAC_ADDR_0      0x600C
+#define regMAC_ADDR_1      0x6010
+#define regFRM_LENGTH      0x6014
+#define regPAUSE_QUANT     0x6018
+#define regRX_FIFO_SECTION 0x601C
+#define regTX_FIFO_SECTION 0x6020
+#define regRX_FULLNESS     0x6024
+#define regTX_FULLNESS     0x6028
+#define regHASHTABLE       0x602C
+#define regMDIO_ST         0x6030
+#define regMDIO_CTL        0x6034
+#define regMDIO_DATA       0x6038
+#define regMDIO_ADDR       0x603C
+
+#define regRST_PORT        0x7000
+#define regDIS_PORT        0x7010
+#define regRST_QU          0x7020
+#define regDIS_QU          0x7030
+
+#define regCTRLST_TX_ENA   0x0001
+#define regCTRLST_RX_ENA   0x0002
+#define regCTRLST_PRM_ENA  0x0010
+#define regCTRLST_PAD_ENA  0x0020
+
+#define regCTRLST_BASE     (regCTRLST_PAD_ENA|regCTRLST_PRM_ENA)
+
+#define regRX_FLT   0x1400
+
+/* TXD TXF RXF RXD  CONFIG 0x0000 --- 0x007c*/
+#define  TX_RX_CFG1_BASE          0xffffffff	/*0-31 */
+#define  TX_RX_CFG0_BASE          0xfffff000	/*31:12 */
+#define  TX_RX_CFG0_RSVD          0x0ffc	/*11:2 */
+#define  TX_RX_CFG0_SIZE          0x0003	/*1:0 */
+
+/*  TXD TXF RXF RXD  WRITE 0x0080 --- 0x00BC */
+#define  TXF_WPTR_WR_PTR        0x7ff8	/*14:3 */
+
+/*  TXD TXF RXF RXD  READ  0x00CO --- 0x00FC */
+#define  TXF_RPTR_RD_PTR        0x7ff8	/*14:3 */
+
+#define TXF_WPTR_MASK 0x7ff0	/* last 4 bits are dropped
+				 * size is rounded to 16 */
+
+/*  regISR 0x0100 */
+/*  regIMR 0x0110 */
+#define  IMR_INPROG   0x80000000	/*31 */
+#define  IR_LNKCHG1   0x10000000	/*28 */
+#define  IR_LNKCHG0   0x08000000	/*27 */
+#define  IR_GPIO      0x04000000	/*26 */
+#define  IR_RFRSH     0x02000000	/*25 */
+#define  IR_RSVD      0x01000000	/*24 */
+#define  IR_SWI       0x00800000	/*23 */
+#define  IR_RX_FREE_3 0x00400000	/*22 */
+#define  IR_RX_FREE_2 0x00200000	/*21 */
+#define  IR_RX_FREE_1 0x00100000	/*20 */
+#define  IR_RX_FREE_0 0x00080000	/*19 */
+#define  IR_TX_FREE_3 0x00040000	/*18 */
+#define  IR_TX_FREE_2 0x00020000	/*17 */
+#define  IR_TX_FREE_1 0x00010000	/*16 */
+#define  IR_TX_FREE_0 0x00008000	/*15 */
+#define  IR_RX_DESC_3 0x00004000	/*14 */
+#define  IR_RX_DESC_2 0x00002000	/*13 */
+#define  IR_RX_DESC_1 0x00001000	/*12 */
+#define  IR_RX_DESC_0 0x00000800	/*11 */
+#define  IR_PSE       0x00000400	/*10 */
+#define  IR_TMR3      0x00000200	/*9 */
+#define  IR_TMR2      0x00000100	/*8 */
+#define  IR_TMR1      0x00000080	/*7 */
+#define  IR_TMR0      0x00000040	/*6 */
+#define  IR_VNT       0x00000020	/*5 */
+#define  IR_RxFL      0x00000010	/*4 */
+#define  IR_SDPERR    0x00000008	/*3 */
+#define  IR_TR        0x00000004	/*2 */
+#define  IR_PCIE_LINK 0x00000002	/*1 */
+#define  IR_PCIE_TOUT 0x00000001	/*0 */
+
+#define  IR_EXTRA (IR_RX_FREE_0 | IR_LNKCHG0 | IR_PSE | \
+    IR_TMR0 | IR_PCIE_LINK | IR_PCIE_TOUT)
+#define  IR_RUN (IR_EXTRA | IR_RX_DESC_0 | IR_TX_FREE_0)
+#define  IR_ALL 0xfdfffff7
+
+#define  IR_LNKCHG0_ofst        27
+
+#define  GMAC_RX_FILTER_OSEN  0x1000	/* shared OS enable */
+#define  GMAC_RX_FILTER_TXFC  0x0400	/* Tx flow control */
+#define  GMAC_RX_FILTER_RSV0  0x0200	/* reserved */
+#define  GMAC_RX_FILTER_FDA   0x0100	/* filter out direct address */
+#define  GMAC_RX_FILTER_AOF   0x0080	/* accept over run */
+#define  GMAC_RX_FILTER_ACF   0x0040	/* accept control frames */
+#define  GMAC_RX_FILTER_ARUNT 0x0020	/* accept under run */
+#define  GMAC_RX_FILTER_ACRC  0x0010	/* accept crc error */
+#define  GMAC_RX_FILTER_AM    0x0008	/* accept multicast */
+#define  GMAC_RX_FILTER_AB    0x0004	/* accept broadcast */
+#define  GMAC_RX_FILTER_PRM   0x0001	/* [0:1] promiscous mode */
+
+#define  MAX_FRAME_AB_VAL       0x3fff	/* 13:0 */
+
+#define  CLKPLL_PLLLKD          0x0200	/*9 */
+#define  CLKPLL_RSTEND          0x0100	/*8 */
+#define  CLKPLL_SFTRST          0x0001	/*0 */
+
+#define  CLKPLL_LKD             (CLKPLL_PLLLKD|CLKPLL_RSTEND)
+
+/*
+ * PCI-E Device Control Register (Offset 0x88)
+ * Source: Luxor Data Sheet, 7.1.3.3.3
+ */
+#define PCI_DEV_CTRL_REG 0x88
+#define GET_DEV_CTRL_MAXPL(x)           GET_BITS_SHIFT(x, 3, 5)
+#define GET_DEV_CTRL_MRRS(x)            GET_BITS_SHIFT(x, 3, 12)
+
+/*
+ * PCI-E Link Status Register (Offset 0x92)
+ * Source: Luxor Data Sheet, 7.1.3.3.7
+ */
+#define PCI_LINK_STATUS_REG 0x92
+#define GET_LINK_STATUS_LANES(x)		GET_BITS_SHIFT(x, 6, 4)
+
+/* Debugging Macros */
+
+#define ERR(fmt, args...) printk(KERN_ERR fmt, ## args)
+#define DBG2(fmt, args...)	\
+	printk(KERN_ERR  "%s:%-5d: " fmt, __FUNCTION__, __LINE__, ## args)
+
+#define BDX_ASSERT(x) BUG_ON(x)
+
+#ifdef DEBUG
+
+#define ENTER          do { \
+	printk(KERN_ERR  "%s:%-5d: ENTER\n", __FUNCTION__, __LINE__); \
+} while (0)
+
+#define RET(args...)   do { \
+	printk(KERN_ERR  "%s:%-5d: RETURN\n", __FUNCTION__, __LINE__); \
+return args; } while (0)
+
+#define DBG(fmt, args...)	\
+	printk(KERN_ERR  "%s:%-5d: " fmt, __FUNCTION__, __LINE__, ## args)
+#else
+#define ENTER         do {  } while (0)
+#define RET(args...)   return args
+#define DBG(fmt, args...)   do {  } while (0)
+#endif
+
+#endif /* _BDX__H */
diff --git a/drivers/net/tehuti_fw.h b/drivers/net/tehuti_fw.h
new file mode 100644
index 0000000..2c603a8
--- /dev/null
+++ b/drivers/net/tehuti_fw.h
@@ -0,0 +1,10712 @@
+/*
+ * Tehuti Networks(R) Network Driver
+ * Copyright (C) 2007 Tehuti Networks Ltd. All rights reserved
+ *
+ * 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.
+ */
+
+/* Loading Firmware */
+/* INT_MEM Ver */
+static u32 s_firmLoad[] = {
+	0x000f0002,
+	0x40718000,
+	0x0000002d,
+	0xc0000000,
+	0x000f0002,
+	0x00718001,
+	0x0000002d,
+	0xc0800000,
+	0x000f0002,
+	0x00718002,
+	0x0000002d,
+	0xc1000000,
+	0x000f0002,
+	0x00718003,
+	0x0000002d,
+	0xc1800000,
+	0x000f0002,
+	0x00718004,
+	0x0000002d,
+	0xc2000000,
+	0x000f0002,
+	0x00718005,
+	0x0000002d,
+	0xc2800000,
+	0x000f0002,
+	0x00718006,
+	0x0000002d,
+	0xc3000000,
+	0x000f0002,
+	0x00718007,
+	0x0000002d,
+	0xc3800000,
+	0x000f0002,
+	0x00718008,
+	0x0000002d,
+	0xc4000000,
+	0x000f0002,
+	0x00718009,
+	0x0000002d,
+	0xc4800000,
+	0x000f0002,
+	0x0071800a,
+	0x0000002d,
+	0xc5000000,
+	0x000f0002,
+	0x0071800b,
+	0x0000002d,
+	0xc5800000,
+	0x000f0002,
+	0x0071800c,
+	0x0000002d,
+	0xc6000000,
+	0x000f0002,
+	0x0071800d,
+	0x0000002d,
+	0xc6800000,
+	0x000f0002,
+	0x0071800e,
+	0x0000002d,
+	0xc7000000,
+	0x000f0002,
+	0x0071800f,
+	0x0000002d,
+	0xc7800000,
+	0x000f0002,
+	0x00718010,
+	0x0000002d,
+	0xc8000000,
+	0x000f0002,
+	0x00718011,
+	0x0000002d,
+	0xc8800000,
+	0x000f0002,
+	0x00718012,
+	0x0000002d,
+	0xc9000000,
+	0x000f0002,
+	0x00718013,
+	0x0000002d,
+	0xc9800000,
+	0x000f0002,
+	0x00718014,
+	0x0000002d,
+	0xca000000,
+	0x000f0002,
+	0x00718015,
+	0x0000002d,
+	0xca800000,
+	0x000f0002,
+	0x00718016,
+	0x0000002d,
+	0xcb000000,
+	0x000f0002,
+	0x00718017,
+	0x0000002d,
+	0xcb800000,
+	0x000f0002,
+	0x00718018,
+	0x0000002d,
+	0xcc000000,
+	0x000f0002,
+	0x00718019,
+	0x0000002d,
+	0xcc800000,
+	0x000f0002,
+	0x0071801a,
+	0x0000002d,
+	0xcd000000,
+	0x000f0002,
+	0x0071801b,
+	0x0000002d,
+	0xcd800000,
+	0x000f0002,
+	0x0071801c,
+	0x0000002d,
+	0xce000000,
+	0x000f0002,
+	0x0071801d,
+	0x0000002d,
+	0xce800000,
+	0x000f0002,
+	0x0071801e,
+	0x0000002d,
+	0xcf000000,
+	0x000f0002,
+	0x0071801f,
+	0x0000002d,
+	0xcf800000,
+	0x000f0002,
+	0x00718020,
+	0x0000002d,
+	0xd0000000,
+	0x000f0002,
+	0x00718021,
+	0x0000002d,
+	0xd0800000,
+	0x000f0002,
+	0x00718022,
+	0x0000002d,
+	0xd1000000,
+	0x000f0002,
+	0x00718023,
+	0x0000002d,
+	0xd1800000,
+	0x000f0002,
+	0x00718024,
+	0x0000002d,
+	0xd2000000,
+	0x000f0002,
+	0x00718025,
+	0x0000002d,
+	0xd2800000,
+	0x000f0002,
+	0x00718026,
+	0x0000002d,
+	0xd3000000,
+	0x000f0002,
+	0x00718027,
+	0x0000002d,
+	0xd3800000,
+	0x000f0002,
+	0x00718028,
+	0x0000002d,
+	0xd4000000,
+	0x000f0002,
+	0x00718029,
+	0x0000002d,
+	0xd4800000,
+	0x000f0002,
+	0x0071802a,
+	0x0000002d,
+	0xd5000000,
+	0x000f0002,
+	0x0071802b,
+	0x0000002d,
+	0xd5800000,
+	0x000f0002,
+	0x0071802c,
+	0x0000002d,
+	0xd6000000,
+	0x000f0002,
+	0x0071802d,
+	0x0000002d,
+	0xd6800000,
+	0x000f0002,
+	0x0071802e,
+	0x0000002d,
+	0xd7000000,
+	0x000f0002,
+	0x0071802f,
+	0x0000002d,
+	0xd7800000,
+	0x000f0002,
+	0x00718030,
+	0x0000002d,
+	0xd8000000,
+	0x000f0002,
+	0x00718031,
+	0x0000002d,
+	0xd8800000,
+	0x000f0002,
+	0x00718032,
+	0x0000002d,
+	0xd9000000,
+	0x000f0002,
+	0x00718033,
+	0x0000002d,
+	0xd9800000,
+	0x000f0002,
+	0x00718034,
+	0x0000002d,
+	0xda000000,
+	0x000f0002,
+	0x00718035,
+	0x0000002d,
+	0xda800000,
+	0x000f0002,
+	0x00718036,
+	0x0000002d,
+	0xdb000000,
+	0x000f0002,
+	0x00718037,
+	0x0000002d,
+	0xdb800000,
+	0x000f0002,
+	0x00718038,
+	0x0000007b,
+	0xdd608000,
+	0x000f0002,
+	0x00718039,
+	0x0000002d,
+	0xdd000000,
+	0x000f0002,
+	0x0071803a,
+	0x0000002d,
+	0xdb800000,
+	0x000f0002,
+	0x0071803b,
+	0x0000002d,
+	0xdd000000,
+	0x000f0002,
+	0x0071803c,
+	0x0000002d,
+	0xdd000000,
+	0x000f0002,
+	0x0071803d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071803e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071803f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718040,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718041,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718042,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718043,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718044,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718045,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718046,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718047,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718048,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718049,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071804a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071804b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071804c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071804d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071804e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071804f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718050,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718051,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718052,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718053,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718054,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718055,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718056,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718057,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718058,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718059,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071805a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071805b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071805c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071805d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071805e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071805f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718060,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718061,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718062,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718063,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718064,
+	0x0000002d,
+	0xdb000000,
+	0x000f0002,
+	0x00718065,
+	0x0000003f,
+	0xdd000104,
+	0x000f0002,
+	0x00718066,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718067,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718068,
+	0x0000003f,
+	0xdd000804,
+	0x000f0002,
+	0x00718069,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071806a,
+	0x0000003f,
+	0xdd003004,
+	0x000f0002,
+	0x0071806b,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071806c,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071806d,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x0071806e,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071806f,
+	0x0000003f,
+	0xdd003d04,
+	0x000f0002,
+	0x00718070,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718071,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718072,
+	0x0000003f,
+	0xdd000704,
+	0x000f0002,
+	0x00718073,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718074,
+	0x0000003f,
+	0xdd002884,
+	0x000f0002,
+	0x00718075,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718076,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718077,
+	0x0000003f,
+	0xdd003704,
+	0x000f0002,
+	0x00718078,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718079,
+	0x0000003f,
+	0xdd002904,
+	0x000f0002,
+	0x0071807a,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071807b,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071807c,
+	0x0000003f,
+	0xdd04aa04,
+	0x000f0002,
+	0x0071807d,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071807e,
+	0x0000003f,
+	0xdd002804,
+	0x000f0002,
+	0x0071807f,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718080,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718081,
+	0x0000003f,
+	0xdd003104,
+	0x000f0002,
+	0x00718082,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718083,
+	0x0000003f,
+	0xdd002b84,
+	0x000f0002,
+	0x00718084,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718085,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718086,
+	0x0000003f,
+	0xdd01e404,
+	0x000f0002,
+	0x00718087,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718088,
+	0x0000003f,
+	0xd7800084,
+	0x000f0002,
+	0x00718089,
+	0x0000003f,
+	0xd7980001,
+	0x000f0002,
+	0x0071808a,
+	0x00000059,
+	0xd78037ef,
+	0x000f0002,
+	0x0071808b,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x0071808c,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x0071808d,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x0071808e,
+	0x0000002d,
+	0xd7d6027f,
+	0x000f0002,
+	0x0071808f,
+	0x00000018,
+	0x17ff0081,
+	0x000f0002,
+	0x00718090,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718091,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718092,
+	0x0000002d,
+	0xd7d800b8,
+	0x000f0002,
+	0x00718093,
+	0x00000018,
+	0x17eb0081,
+	0x000f0002,
+	0x00718094,
+	0x0000003f,
+	0xdd002904,
+	0x000f0002,
+	0x00718095,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718096,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718097,
+	0x0000003f,
+	0xdd04aa84,
+	0x000f0002,
+	0x00718098,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718099,
+	0x0000003f,
+	0xdd002b04,
+	0x000f0002,
+	0x0071809a,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071809b,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071809c,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x0071809d,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071809e,
+	0x0000003f,
+	0xdd002984,
+	0x000f0002,
+	0x0071809f,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x007180a0,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007180a1,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x007180a2,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007180a3,
+	0x0000003f,
+	0xdd002a04,
+	0x000f0002,
+	0x007180a4,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x007180a5,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007180a6,
+	0x0000003f,
+	0xdd009184,
+	0x000f0002,
+	0x007180a7,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007180a8,
+	0x0000003f,
+	0xd6801984,
+	0x000f0002,
+	0x007180a9,
+	0x0000003f,
+	0xd6800001,
+	0x000f0002,
+	0x007180aa,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x007180ab,
+	0x00000018,
+	0x37ff0081,
+	0x000f0002,
+	0x007180ac,
+	0x0000003f,
+	0xdd002b04,
+	0x000f0002,
+	0x007180ad,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x007180ae,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007180af,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x007180b0,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007180b1,
+	0x0000003f,
+	0xdd002a84,
+	0x000f0002,
+	0x007180b2,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x007180b3,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007180b4,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x007180b5,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007180b6,
+	0x0000003f,
+	0xd6800c84,
+	0x000f0002,
+	0x007180b7,
+	0x0000003f,
+	0xd6800001,
+	0x000f0002,
+	0x007180b8,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x007180b9,
+	0x00000018,
+	0x37ff0081,
+	0x000f0002,
+	0x007180ba,
+	0x0000003f,
+	0xdd002a84,
+	0x000f0002,
+	0x007180bb,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x007180bc,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007180bd,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x007180be,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007180bf,
+	0x0000003f,
+	0xd6800f84,
+	0x000f0002,
+	0x007180c0,
+	0x0000003f,
+	0xd6800001,
+	0x000f0002,
+	0x007180c1,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x007180c2,
+	0x00000018,
+	0x37ff0081,
+	0x000f0002,
+	0x007180c3,
+	0x0000003f,
+	0xdd002a04,
+	0x000f0002,
+	0x007180c4,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x007180c5,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007180c6,
+	0x0000003f,
+	0xdd001184,
+	0x000f0002,
+	0x007180c7,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007180c8,
+	0x0000003f,
+	0xdd002884,
+	0x000f0002,
+	0x007180c9,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x007180ca,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007180cb,
+	0x0000003f,
+	0xdd003784,
+	0x000f0002,
+	0x007180cc,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007180cd,
+	0x0000002d,
+	0xd3800000,
+	0x000f0002,
+	0x007180ce,
+	0x0000003f,
+	0xd2003780,
+	0x000f0002,
+	0x007180cf,
+	0x0000003f,
+	0xd1800404,
+	0x000f0002,
+	0x007180d0,
+	0x0000003f,
+	0xd1840001,
+	0x000f0002,
+	0x007180d1,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x007180d2,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x007180d3,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x007180d4,
+	0x0000003f,
+	0xd17fff84,
+	0x000f0002,
+	0x007180d5,
+	0x0000003f,
+	0xd17fff81,
+	0x000f0002,
+	0x007180d6,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x007180d7,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x007180d8,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x007180d9,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x007180da,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x007180db,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x007180dc,
+	0x0000003f,
+	0xd6800784,
+	0x000f0002,
+	0x007180dd,
+	0x0000003f,
+	0xd6800001,
+	0x000f0002,
+	0x007180de,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x007180df,
+	0x00000018,
+	0x37ff0081,
+	0x000f0002,
+	0x007180e0,
+	0x00000049,
+	0xdd003b63,
+	0x000f0002,
+	0x007180e1,
+	0x00000059,
+	0xdd003b76,
+	0x000f0002,
+	0x007180e2,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007180e3,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007180e4,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007180e5,
+	0x0000002d,
+	0xdd06027f,
+	0x000f0002,
+	0x007180e6,
+	0x00000018,
+	0x1d7f3d7a,
+	0x000f0002,
+	0x007180e7,
+	0x00000045,
+	0xdd003139,
+	0x000f0002,
+	0x007180e8,
+	0x00000094,
+	0x000b313b,
+	0x000f0002,
+	0x007180e9,
+	0x00000094,
+	0x0009313d,
+	0x000f0002,
+	0x007180ea,
+	0x00000094,
+	0x0007313f,
+	0x000f0002,
+	0x007180eb,
+	0x00000094,
+	0x00053b76,
+	0x000f0002,
+	0x007180ec,
+	0x00000009,
+	0xc1ed3d7a,
+	0x000f0002,
+	0x007180ed,
+	0x0000003f,
+	0xd200b780,
+	0x000f0002,
+	0x007180ee,
+	0x0000003f,
+	0xdd002884,
+	0x000f0002,
+	0x007180ef,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x007180f0,
+	0x00000069,
+	0xdd003264,
+	0x000f0002,
+	0x007180f1,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007180f2,
+	0x0000003f,
+	0xd6800784,
+	0x000f0002,
+	0x007180f3,
+	0x0000003f,
+	0xd6800001,
+	0x000f0002,
+	0x007180f4,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x007180f5,
+	0x00000018,
+	0x37ff0081,
+	0x000f0002,
+	0x007180f6,
+	0x00000049,
+	0xdd003b63,
+	0x000f0002,
+	0x007180f7,
+	0x00000059,
+	0xdd003b76,
+	0x000f0002,
+	0x007180f8,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007180f9,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007180fa,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007180fb,
+	0x0000002d,
+	0xdd06027f,
+	0x000f0002,
+	0x007180fc,
+	0x00000018,
+	0x1d7f3d7a,
+	0x000f0002,
+	0x007180fd,
+	0x00000045,
+	0xdd00313a,
+	0x000f0002,
+	0x007180fe,
+	0x00000018,
+	0x1d2d3b76,
+	0x000f0002,
+	0x007180ff,
+	0x00000045,
+	0xdd00313c,
+	0x000f0002,
+	0x00718100,
+	0x00000018,
+	0x1d133b76,
+	0x000f0002,
+	0x00718101,
+	0x00000045,
+	0xdd00313e,
+	0x000f0002,
+	0x00718102,
+	0x00000018,
+	0x1d1b3b76,
+	0x000f0002,
+	0x00718103,
+	0x0000003f,
+	0xdd003004,
+	0x000f0002,
+	0x00718104,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718105,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718106,
+	0x0000003f,
+	0xdd000104,
+	0x000f0002,
+	0x00718107,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718108,
+	0x00000009,
+	0xc52d3d7a,
+	0x000f0002,
+	0x00718109,
+	0x00000029,
+	0xd2010064,
+	0x000f0002,
+	0x0071810a,
+	0x0000003f,
+	0xdd002884,
+	0x000f0002,
+	0x0071810b,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071810c,
+	0x00000069,
+	0xdd003264,
+	0x000f0002,
+	0x0071810d,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071810e,
+	0x00000009,
+	0xc2293d7a,
+	0x000f0002,
+	0x0071810f,
+	0x00000029,
+	0xd2000064,
+	0x000f0002,
+	0x00718110,
+	0x0000003f,
+	0xdd002884,
+	0x000f0002,
+	0x00718111,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718112,
+	0x00000069,
+	0xdd003264,
+	0x000f0002,
+	0x00718113,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718114,
+	0x00000049,
+	0xdd003b63,
+	0x000f0002,
+	0x00718115,
+	0x00000059,
+	0xdd003b76,
+	0x000f0002,
+	0x00718116,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718117,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718118,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718119,
+	0x0000002d,
+	0xdd06027f,
+	0x000f0002,
+	0x0071811a,
+	0x00000018,
+	0x1d7f3d7a,
+	0x000f0002,
+	0x0071811b,
+	0x00000045,
+	0xdd00313a,
+	0x000f0002,
+	0x0071811c,
+	0x00000018,
+	0x1d0f3b76,
+	0x000f0002,
+	0x0071811d,
+	0x0000003f,
+	0xdd003004,
+	0x000f0002,
+	0x0071811e,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071811f,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718120,
+	0x0000003f,
+	0xdd000104,
+	0x000f0002,
+	0x00718121,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718122,
+	0x00000009,
+	0xc52d3d7a,
+	0x000f0002,
+	0x00718123,
+	0x0000002d,
+	0xd1080082,
+	0x000f0002,
+	0x00718124,
+	0x00000008,
+	0x23c33d7a,
+	0x000f0002,
+	0x00718125,
+	0x00000049,
+	0xd6003b0a,
+	0x000f0002,
+	0x00718126,
+	0x0000003f,
+	0xd3000004,
+	0x000f0002,
+	0x00718127,
+	0x0000003f,
+	0xd3040001,
+	0x000f0002,
+	0x00718128,
+	0x0000002f,
+	0xd6814085,
+	0x000f0002,
+	0x00718129,
+	0x0000003f,
+	0xd4ffff84,
+	0x000f0002,
+	0x0071812a,
+	0x0000003f,
+	0xd4800781,
+	0x000f0002,
+	0x0071812b,
+	0x0000003f,
+	0xd1ffff84,
+	0x000f0002,
+	0x0071812c,
+	0x0000003f,
+	0xd1800001,
+	0x000f0002,
+	0x0071812d,
+	0x00000049,
+	0xdd003666,
+	0x000f0002,
+	0x0071812e,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x0071812f,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x00718130,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x00718131,
+	0x00000069,
+	0xdd003b69,
+	0x000f0002,
+	0x00718132,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x00718133,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x00718134,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x00718135,
+	0x00000069,
+	0xdd003b69,
+	0x000f0002,
+	0x00718136,
+	0x00000061,
+	0xf600046c,
+	0x000f0002,
+	0x00718137,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x00718138,
+	0x00000018,
+	0x3d6b0081,
+	0x000f0002,
+	0x00718139,
+	0x00000049,
+	0xd600058b,
+	0x000f0002,
+	0x0071813a,
+	0x0000002f,
+	0xd6810106,
+	0x000f0002,
+	0x0071813b,
+	0x0000002d,
+	0xd2000000,
+	0x000f0002,
+	0x0071813c,
+	0x00000021,
+	0xd20000e4,
+	0x000f0002,
+	0x0071813d,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x0071813e,
+	0x0000002d,
+	0xdd06017f,
+	0x000f0002,
+	0x0071813f,
+	0x00000018,
+	0x1d7f3d7a,
+	0x000f0002,
+	0x00718140,
+	0x00000049,
+	0xd800366c,
+	0x000f0002,
+	0x00718141,
+	0x00000069,
+	0xd80033e7,
+	0x000f0002,
+	0x00718142,
+	0x00000069,
+	0xd80033e7,
+	0x000f0002,
+	0x00718143,
+	0x00000069,
+	0xd80037ef,
+	0x000f0002,
+	0x00718144,
+	0x00000031,
+	0xd600016c,
+	0x000f0002,
+	0x00718145,
+	0x0000002d,
+	0xd1000000,
+	0x000f0002,
+	0x00718146,
+	0x00000049,
+	0xd17a33e4,
+	0x000f0002,
+	0x00718147,
+	0x0000002f,
+	0xd1710162,
+	0x000f0002,
+	0x00718148,
+	0x0000002f,
+	0xd1610162,
+	0x000f0002,
+	0x00718149,
+	0x00000049,
+	0xd14033e3,
+	0x000f0002,
+	0x0071814a,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x0071814b,
+	0x0000002d,
+	0xdd06017f,
+	0x000f0002,
+	0x0071814c,
+	0x00000018,
+	0x1d7f3d7a,
+	0x000f0002,
+	0x0071814d,
+	0x00000049,
+	0xd800366c,
+	0x000f0002,
+	0x0071814e,
+	0x00000069,
+	0xd80033e7,
+	0x000f0002,
+	0x0071814f,
+	0x00000069,
+	0xd8003162,
+	0x000f0002,
+	0x00718150,
+	0x00000069,
+	0xd80037ef,
+	0x000f0002,
+	0x00718151,
+	0x00000031,
+	0xd600016c,
+	0x000f0002,
+	0x00718152,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718153,
+	0x0000002d,
+	0xdd06017f,
+	0x000f0002,
+	0x00718154,
+	0x00000018,
+	0x1d7f3d7a,
+	0x000f0002,
+	0x00718155,
+	0x00000049,
+	0xd800366c,
+	0x000f0002,
+	0x00718156,
+	0x00000069,
+	0xd80033e7,
+	0x000f0002,
+	0x00718157,
+	0x00000069,
+	0xd80033e7,
+	0x000f0002,
+	0x00718158,
+	0x00000069,
+	0xd80037ef,
+	0x000f0002,
+	0x00718159,
+	0x00000031,
+	0xd600016c,
+	0x000f0002,
+	0x0071815a,
+	0x0000002d,
+	0xd1000000,
+	0x000f0002,
+	0x0071815b,
+	0x0000002d,
+	0xd16c07e4,
+	0x000f0002,
+	0x0071815c,
+	0x00000049,
+	0xd14033e3,
+	0x000f0002,
+	0x0071815d,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x0071815e,
+	0x0000002d,
+	0xdd06017f,
+	0x000f0002,
+	0x0071815f,
+	0x00000018,
+	0x1d7f3d7a,
+	0x000f0002,
+	0x00718160,
+	0x00000049,
+	0xd800366c,
+	0x000f0002,
+	0x00718161,
+	0x00000069,
+	0xd80033e7,
+	0x000f0002,
+	0x00718162,
+	0x00000069,
+	0xd8003162,
+	0x000f0002,
+	0x00718163,
+	0x00000069,
+	0xd80037ef,
+	0x000f0002,
+	0x00718164,
+	0x00000031,
+	0xd600016c,
+	0x000f0002,
+	0x00718165,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718166,
+	0x0000002d,
+	0xdd06017f,
+	0x000f0002,
+	0x00718167,
+	0x00000018,
+	0x1d7f3d7a,
+	0x000f0002,
+	0x00718168,
+	0x00000049,
+	0xd800366c,
+	0x000f0002,
+	0x00718169,
+	0x00000069,
+	0xd80033e7,
+	0x000f0002,
+	0x0071816a,
+	0x00000069,
+	0xd80033e7,
+	0x000f0002,
+	0x0071816b,
+	0x00000069,
+	0xd80037ef,
+	0x000f0002,
+	0x0071816c,
+	0x00000031,
+	0xd600016c,
+	0x000f0002,
+	0x0071816d,
+	0x0000002d,
+	0xd1000000,
+	0x000f0002,
+	0x0071816e,
+	0x00000049,
+	0xd17833e4,
+	0x000f0002,
+	0x0071816f,
+	0x0000002f,
+	0xd1710162,
+	0x000f0002,
+	0x00718170,
+	0x0000002f,
+	0xd1610162,
+	0x000f0002,
+	0x00718171,
+	0x00000049,
+	0xd14033e3,
+	0x000f0002,
+	0x00718172,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718173,
+	0x0000002d,
+	0xdd06017f,
+	0x000f0002,
+	0x00718174,
+	0x00000018,
+	0x1d7f3d7a,
+	0x000f0002,
+	0x00718175,
+	0x00000049,
+	0xd800366c,
+	0x000f0002,
+	0x00718176,
+	0x00000069,
+	0xd80033e7,
+	0x000f0002,
+	0x00718177,
+	0x00000069,
+	0xd8003162,
+	0x000f0002,
+	0x00718178,
+	0x00000069,
+	0xd80037ef,
+	0x000f0002,
+	0x00718179,
+	0x00000031,
+	0xd600016c,
+	0x000f0002,
+	0x0071817a,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x0071817b,
+	0x0000002d,
+	0xdd06017f,
+	0x000f0002,
+	0x0071817c,
+	0x00000018,
+	0x1d7f3d7a,
+	0x000f0002,
+	0x0071817d,
+	0x00000049,
+	0xd800366c,
+	0x000f0002,
+	0x0071817e,
+	0x00000069,
+	0xd80033e7,
+	0x000f0002,
+	0x0071817f,
+	0x00000069,
+	0xd80033e7,
+	0x000f0002,
+	0x00718180,
+	0x00000069,
+	0xd80037ef,
+	0x000f0002,
+	0x00718181,
+	0x00000031,
+	0xd600016c,
+	0x000f0002,
+	0x00718182,
+	0x0000002d,
+	0xd1000000,
+	0x000f0002,
+	0x00718183,
+	0x0000002d,
+	0xd16807e4,
+	0x000f0002,
+	0x00718184,
+	0x00000049,
+	0xd14033e3,
+	0x000f0002,
+	0x00718185,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718186,
+	0x0000002d,
+	0xdd06017f,
+	0x000f0002,
+	0x00718187,
+	0x00000018,
+	0x1d7f3d7a,
+	0x000f0002,
+	0x00718188,
+	0x00000049,
+	0xd800366c,
+	0x000f0002,
+	0x00718189,
+	0x00000069,
+	0xd80033e7,
+	0x000f0002,
+	0x0071818a,
+	0x00000069,
+	0xd8003162,
+	0x000f0002,
+	0x0071818b,
+	0x00000069,
+	0xd80037ef,
+	0x000f0002,
+	0x0071818c,
+	0x00000031,
+	0xd600016c,
+	0x000f0002,
+	0x0071818d,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x0071818e,
+	0x00000008,
+	0x22790081,
+	0x000f0002,
+	0x0071818f,
+	0x00000049,
+	0xd600060c,
+	0x000f0002,
+	0x00718190,
+	0x0000002f,
+	0xd6810106,
+	0x000f0002,
+	0x00718191,
+	0x0000003f,
+	0xd4800002,
+	0x000f0002,
+	0x00718192,
+	0x0000003f,
+	0xd4800084,
+	0x000f0002,
+	0x00718193,
+	0x0000003f,
+	0xd5000102,
+	0x000f0002,
+	0x00718194,
+	0x0000003f,
+	0xd5000184,
+	0x000f0002,
+	0x00718195,
+	0x0000003f,
+	0xd5800202,
+	0x000f0002,
+	0x00718196,
+	0x0000003f,
+	0xd5800204,
+	0x000f0002,
+	0x00718197,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718198,
+	0x0000002d,
+	0xdd06017f,
+	0x000f0002,
+	0x00718199,
+	0x00000018,
+	0x1d7f3d7a,
+	0x000f0002,
+	0x0071819a,
+	0x00000049,
+	0xd800366c,
+	0x000f0002,
+	0x0071819b,
+	0x00000069,
+	0xd80034e9,
+	0x000f0002,
+	0x0071819c,
+	0x00000069,
+	0xd800356a,
+	0x000f0002,
+	0x0071819d,
+	0x00000069,
+	0xd80037ef,
+	0x000f0002,
+	0x0071819e,
+	0x00000031,
+	0xd600016c,
+	0x000f0002,
+	0x0071819f,
+	0x00000041,
+	0xd48034eb,
+	0x000f0002,
+	0x007181a0,
+	0x00000041,
+	0xd500356b,
+	0x000f0002,
+	0x007181a1,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x007181a2,
+	0x00000018,
+	0x37eb0081,
+	0x000f0002,
+	0x007181a3,
+	0x00000049,
+	0xd6003b0d,
+	0x000f0002,
+	0x007181a4,
+	0x00000049,
+	0xd6803b07,
+	0x000f0002,
+	0x007181a5,
+	0x0000002d,
+	0xd1000000,
+	0x000f0002,
+	0x007181a6,
+	0x00000049,
+	0xdd003666,
+	0x000f0002,
+	0x007181a7,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x007181a8,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x007181a9,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x007181aa,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x007181ab,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x007181ac,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x007181ad,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x007181ae,
+	0x00000069,
+	0xdd003b76,
+	0x000f0002,
+	0x007181af,
+	0x00000061,
+	0xf600046c,
+	0x000f0002,
+	0x007181b0,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x007181b1,
+	0x00000018,
+	0x37eb0081,
+	0x000f0002,
+	0x007181b2,
+	0x00000049,
+	0xd6003b0e,
+	0x000f0002,
+	0x007181b3,
+	0x00000049,
+	0xd6803b08,
+	0x000f0002,
+	0x007181b4,
+	0x00000049,
+	0xd5803b09,
+	0x000f0002,
+	0x007181b5,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007181b6,
+	0x0000002d,
+	0xdd06017f,
+	0x000f0002,
+	0x007181b7,
+	0x00000018,
+	0x1d7f3d7a,
+	0x000f0002,
+	0x007181b8,
+	0x00000049,
+	0xd800366c,
+	0x000f0002,
+	0x007181b9,
+	0x00000069,
+	0xd80035eb,
+	0x000f0002,
+	0x007181ba,
+	0x00000069,
+	0xd80033e7,
+	0x000f0002,
+	0x007181bb,
+	0x00000069,
+	0xd80037ef,
+	0x000f0002,
+	0x007181bc,
+	0x00000041,
+	0xd60007ec,
+	0x000f0002,
+	0x007181bd,
+	0x00000041,
+	0xd580086b,
+	0x000f0002,
+	0x007181be,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x007181bf,
+	0x00000018,
+	0x37ed0081,
+	0x000f0002,
+	0x007181c0,
+	0x0000003f,
+	0xd4ffff80,
+	0x000f0002,
+	0x007181c1,
+	0x0000003f,
+	0xd5020004,
+	0x000f0002,
+	0x007181c2,
+	0x0000003f,
+	0xd5180001,
+	0x000f0002,
+	0x007181c3,
+	0x00000049,
+	0xdd003b6a,
+	0x000f0002,
+	0x007181c4,
+	0x00000069,
+	0xdd003b69,
+	0x000f0002,
+	0x007181c5,
+	0x00000069,
+	0xdd003b69,
+	0x000f0002,
+	0x007181c6,
+	0x00000021,
+	0xd50000ea,
+	0x000f0002,
+	0x007181c7,
+	0x00000049,
+	0xdd0e3b6a,
+	0x000f0002,
+	0x007181c8,
+	0x00000035,
+	0xd104007a,
+	0x000f0002,
+	0x007181c9,
+	0x00000018,
+	0x37f50081,
+	0x000f0002,
+	0x007181ca,
+	0x0000003f,
+	0xd4ffff80,
+	0x000f0002,
+	0x007181cb,
+	0x0000003f,
+	0xd5040004,
+	0x000f0002,
+	0x007181cc,
+	0x0000003f,
+	0xd5180001,
+	0x000f0002,
+	0x007181cd,
+	0x00000069,
+	0xdd003b69,
+	0x000f0002,
+	0x007181ce,
+	0x00000069,
+	0xdd003b69,
+	0x000f0002,
+	0x007181cf,
+	0x00000049,
+	0xdd003b6a,
+	0x000f0002,
+	0x007181d0,
+	0x00000051,
+	0xf50000ea,
+	0x000f0002,
+	0x007181d1,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007181d2,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007181d3,
+	0x00000049,
+	0xdd0e3b6a,
+	0x000f0002,
+	0x007181d4,
+	0x00000035,
+	0xd104807a,
+	0x000f0002,
+	0x007181d5,
+	0x00000018,
+	0x37f50081,
+	0x000f0002,
+	0x007181d6,
+	0x0000003f,
+	0xc77f7f04,
+	0x000f0002,
+	0x007181d7,
+	0x0000003f,
+	0xc77f7f01,
+	0x000f0002,
+	0x007181d8,
+	0x0000003f,
+	0xd6804000,
+	0x000f0002,
+	0x007181d9,
+	0x0000003f,
+	0xd103c000,
+	0x000f0002,
+	0x007181da,
+	0x00000025,
+	0xde2000e2,
+	0x000f0002,
+	0x007181db,
+	0x00000049,
+	0xde80274e,
+	0x000f0002,
+	0x007181dc,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007181dd,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007181de,
+	0x00000035,
+	0xd10000e2,
+	0x000f0002,
+	0x007181df,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x007181e0,
+	0x00000018,
+	0x37f50081,
+	0x000f0002,
+	0x007181e1,
+	0x0000003f,
+	0xdd003004,
+	0x000f0002,
+	0x007181e2,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x007181e3,
+	0x00000069,
+	0xdd001d3a,
+	0x000f0002,
+	0x007181e4,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007181e5,
+	0x0000007d,
+	0xc760a713,
+	0x000f0002,
+	0x007181e6,
+	0x00000031,
+	0xc0800041,
+	0x000f0002,
+	0x007181e7,
+	0x00000031,
+	0xc4000048,
+	0x000f0002,
+	0x007181e8,
+	0x00000031,
+	0xc2800045,
+	0x000f0002,
+	0x007181e9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181ea,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181eb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181ec,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181ed,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181ee,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181ef,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181f0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181f1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181f2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181f3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181f4,
+	0x0000002d,
+	0xdb000000,
+	0x000f0002,
+	0x007181f5,
+	0x0000003f,
+	0xdd003004,
+	0x000f0002,
+	0x007181f6,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x007181f7,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007181f8,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x007181f9,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007181fa,
+	0x0000002d,
+	0xd3800000,
+	0x000f0002,
+	0x007181fb,
+	0x0000003f,
+	0xdd000404,
+	0x000f0002,
+	0x007181fc,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x007181fd,
+	0x00000069,
+	0xdd000a14,
+	0x000f0002,
+	0x007181fe,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x007181ff,
+	0x00000049,
+	0xd1043394,
+	0x000f0002,
+	0x00718200,
+	0x0000003f,
+	0xdd000484,
+	0x000f0002,
+	0x00718201,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718202,
+	0x00000069,
+	0xdd003162,
+	0x000f0002,
+	0x00718203,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718204,
+	0x0000003f,
+	0xdd000504,
+	0x000f0002,
+	0x00718205,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718206,
+	0x00000069,
+	0xdd000a95,
+	0x000f0002,
+	0x00718207,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718208,
+	0x00000049,
+	0xd1043395,
+	0x000f0002,
+	0x00718209,
+	0x0000003f,
+	0xdd000584,
+	0x000f0002,
+	0x0071820a,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071820b,
+	0x00000069,
+	0xdd003162,
+	0x000f0002,
+	0x0071820c,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071820d,
+	0x0000003f,
+	0xdd000604,
+	0x000f0002,
+	0x0071820e,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071820f,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718210,
+	0x0000003f,
+	0xdd000084,
+	0x000f0002,
+	0x00718211,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718212,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x00718213,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718214,
+	0x00000069,
+	0xdd000b16,
+	0x000f0002,
+	0x00718215,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718216,
+	0x0000003f,
+	0xdd001004,
+	0x000f0002,
+	0x00718217,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718218,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718219,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x0071821a,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071821b,
+	0x0000003f,
+	0xdd001084,
+	0x000f0002,
+	0x0071821c,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071821d,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071821e,
+	0x0000003f,
+	0xdd018004,
+	0x000f0002,
+	0x0071821f,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718220,
+	0x0000003f,
+	0xdd001104,
+	0x000f0002,
+	0x00718221,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718222,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718223,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x00718224,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718225,
+	0x0000003f,
+	0xdd001184,
+	0x000f0002,
+	0x00718226,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718227,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718228,
+	0x0000003f,
+	0xdd160004,
+	0x000f0002,
+	0x00718229,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071822a,
+	0x0000003f,
+	0xdd001204,
+	0x000f0002,
+	0x0071822b,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071822c,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071822d,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x0071822e,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071822f,
+	0x0000003f,
+	0xdd001284,
+	0x000f0002,
+	0x00718230,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718231,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718232,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x00718233,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718234,
+	0x0000003f,
+	0xdd001304,
+	0x000f0002,
+	0x00718235,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718236,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718237,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x00718238,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718239,
+	0x0000003f,
+	0xdd001384,
+	0x000f0002,
+	0x0071823a,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071823b,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071823c,
+	0x0000003f,
+	0xdd050004,
+	0x000f0002,
+	0x0071823d,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071823e,
+	0x0000003f,
+	0xdd002004,
+	0x000f0002,
+	0x0071823f,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718240,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718241,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x00718242,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718243,
+	0x0000003f,
+	0xdd002084,
+	0x000f0002,
+	0x00718244,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718245,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718246,
+	0x0000003f,
+	0xdd019004,
+	0x000f0002,
+	0x00718247,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718248,
+	0x0000003f,
+	0xdd002104,
+	0x000f0002,
+	0x00718249,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071824a,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071824b,
+	0x0000003f,
+	0xdd000084,
+	0x000f0002,
+	0x0071824c,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071824d,
+	0x0000003f,
+	0xdd002184,
+	0x000f0002,
+	0x0071824e,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071824f,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718250,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x00718251,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718252,
+	0x0000003f,
+	0xdd002204,
+	0x000f0002,
+	0x00718253,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718254,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718255,
+	0x0000003f,
+	0xdd000284,
+	0x000f0002,
+	0x00718256,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718257,
+	0x0000003f,
+	0xdd002284,
+	0x000f0002,
+	0x00718258,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718259,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071825a,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x0071825b,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071825c,
+	0x0000003f,
+	0xdd002304,
+	0x000f0002,
+	0x0071825d,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071825e,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071825f,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x00718260,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718261,
+	0x0000003f,
+	0xdd001804,
+	0x000f0002,
+	0x00718262,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718263,
+	0x00000069,
+	0xdd000b97,
+	0x000f0002,
+	0x00718264,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718265,
+	0x00000049,
+	0xd1043397,
+	0x000f0002,
+	0x00718266,
+	0x0000003f,
+	0xdd001884,
+	0x000f0002,
+	0x00718267,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718268,
+	0x00000069,
+	0xdd003162,
+	0x000f0002,
+	0x00718269,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071826a,
+	0x0000003f,
+	0xdd001904,
+	0x000f0002,
+	0x0071826b,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071826c,
+	0x00000069,
+	0xdd000c18,
+	0x000f0002,
+	0x0071826d,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071826e,
+	0x00000049,
+	0xd1043398,
+	0x000f0002,
+	0x0071826f,
+	0x0000003f,
+	0xdd001984,
+	0x000f0002,
+	0x00718270,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718271,
+	0x00000069,
+	0xdd003162,
+	0x000f0002,
+	0x00718272,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718273,
+	0x0000003f,
+	0xdd001a04,
+	0x000f0002,
+	0x00718274,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718275,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718276,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x00718277,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718278,
+	0x0000003f,
+	0xdd001a84,
+	0x000f0002,
+	0x00718279,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071827a,
+	0x00000069,
+	0xdd000b16,
+	0x000f0002,
+	0x0071827b,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071827c,
+	0x0000003f,
+	0xdd001c04,
+	0x000f0002,
+	0x0071827d,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071827e,
+	0x00000069,
+	0xdd000c99,
+	0x000f0002,
+	0x0071827f,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718280,
+	0x0000003f,
+	0xdd001c84,
+	0x000f0002,
+	0x00718281,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718282,
+	0x00000069,
+	0xdd000d1a,
+	0x000f0002,
+	0x00718283,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718284,
+	0x0000003f,
+	0xdd001d04,
+	0x000f0002,
+	0x00718285,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718286,
+	0x00000069,
+	0xdd000d9b,
+	0x000f0002,
+	0x00718287,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718288,
+	0x00000049,
+	0xd104339b,
+	0x000f0002,
+	0x00718289,
+	0x0000003f,
+	0xdd001d84,
+	0x000f0002,
+	0x0071828a,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071828b,
+	0x00000069,
+	0xdd003162,
+	0x000f0002,
+	0x0071828c,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x0071828d,
+	0x0000003f,
+	0xdd001e04,
+	0x000f0002,
+	0x0071828e,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071828f,
+	0x00000069,
+	0xdd000e1c,
+	0x000f0002,
+	0x00718290,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718291,
+	0x0000003f,
+	0xdd000104,
+	0x000f0002,
+	0x00718292,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x00718293,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718294,
+	0x0000003f,
+	0xdd000f04,
+	0x000f0002,
+	0x00718295,
+	0x00000069,
+	0xdd003d7a,
+	0x000f0002,
+	0x00718296,
+	0x0000007d,
+	0xc760a713,
+	0x000f0002,
+	0x00718297,
+	0x00000031,
+	0xc0800041,
+	0x000f0002,
+	0x00718298,
+	0x00000031,
+	0xc4000048,
+	0x000f0002,
+	0x00718299,
+	0x00000031,
+	0xc2800045,
+	0x000f0002,
+	0x0071829a,
+	0x00000031,
+	0xd680006d,
+/* BRDX_INIT_SDRAM */
+	0x000f000f,
+	0x00700064,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000040,
+	0x00000100,
+	0x00000400,
+	0x00000064,
+	0x00000054,
+	0x00000000,
+	0x00002400,
+	0x00002800,
+	0x00000400,
+	0x00002880,
+	0x00000180,
+	0x00000003,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000051,
+	0x0000017d,
+	0x00000008,
+	0x00000051,
+	0x0000005d,
+	0x00000000,
+	0x00000009,
+	0x00005000,
+	0x00000000,
+	0x00000000,
+/* BRDX_INIT */
+	0x000f000f,
+	0x007001f4,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000040,
+	0x00000100,
+	0x00000400,
+	0x00000064,
+	0x00000054,
+	0x00000000,
+	0x00002400,
+	0x00002800,
+	0x00000400,
+	0x00002880,
+	0x00000180,
+	0x00000003,
+	0x00000000,
+	0x00000000,
+	0x00000000,
+	0x00000051,
+	0x0000017d,
+	0x00000008,
+	0x00000051,
+	0x0000005d,
+	0x00000000,
+	0x00000009,
+	0x00005000,
+	0x00000000,
+	0x00000000,
+/* ZERO_INIT */
+	0x000f0002,
+	0x00700000,
+	0x00000001,
+	0x00000000,
+/* ZERO_INIT */
+	0x000f0002,
+	0x00700000,
+	0x00000001,
+	0x00000000,
+/* Loading operational Firmware */
+	0x000f0002,
+	0x00718000,
+	0x00000025,
+	0xdd0e0002,
+	0x000f0002,
+	0x00718001,
+	0x00000004,
+	0x01d13b76,
+	0x000f0002,
+	0x00718002,
+	0x00000025,
+	0xdd0e0082,
+	0x000f0002,
+	0x00718003,
+	0x00000004,
+	0x02893b76,
+	0x000f0002,
+	0x00718004,
+	0x00000025,
+	0xdd0e0102,
+	0x000f0002,
+	0x00718005,
+	0x00000004,
+	0x02853b76,
+	0x000f0002,
+	0x00718006,
+	0x00000025,
+	0xdd0e0182,
+	0x000f0002,
+	0x00718007,
+	0x00000004,
+	0x03fd3b76,
+	0x000f0002,
+	0x00718008,
+	0x00000009,
+	0xcf813b76,
+	0x000f0002,
+	0x00718009,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071800a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071800b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071800c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071800d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071800e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071800f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718010,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718011,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718012,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718013,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718014,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718015,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718016,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718017,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718018,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718019,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071801a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071801b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071801c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071801d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071801e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071801f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718020,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718021,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718022,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718023,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718024,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718025,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718026,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718027,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718028,
+	0x00000049,
+	0xc0003b00,
+	0x000f0002,
+	0x00718029,
+	0x00000049,
+	0xc0803b02,
+	0x000f0002,
+	0x0071802a,
+	0x00000049,
+	0xc1003b03,
+	0x000f0002,
+	0x0071802b,
+	0x00000049,
+	0xc1803b04,
+	0x000f0002,
+	0x0071802c,
+	0x00000029,
+	0xdf600076,
+	0x000f0002,
+	0x0071802d,
+	0x00000049,
+	0xdf443b7d,
+	0x000f0002,
+	0x0071802e,
+	0x00000079,
+	0xfd609076,
+	0x000f0002,
+	0x0071802f,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718030,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718031,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718032,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718033,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718034,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718035,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718036,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718037,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718038,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718039,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071803a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071803b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071803c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071803d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071803e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071803f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718040,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718041,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718042,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718043,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718044,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718045,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718046,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718047,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718048,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718049,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071804a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071804b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071804c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071804d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071804e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071804f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718050,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718051,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718052,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718053,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718054,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718055,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718056,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718057,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718058,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718059,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071805a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071805b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071805c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071805d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071805e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071805f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718060,
+	0x0000003f,
+	0xdf000003,
+	0x000f0002,
+	0x00718061,
+	0x0000002d,
+	0xdde00f81,
+	0x000f0002,
+	0x00718062,
+	0x0000003f,
+	0xdd800283,
+	0x000f0002,
+	0x00718063,
+	0x0000002d,
+	0xdd040180,
+	0x000f0002,
+	0x00718064,
+	0x0000007d,
+	0xfd150080,
+	0x000f0002,
+	0x00718065,
+	0x0000007a,
+	0x10203b76,
+	0x000f0002,
+	0x00718066,
+	0x0000007a,
+	0x30207b76,
+	0x000f0002,
+	0x00718067,
+	0x00000021,
+	0xd0240060,
+	0x000f0002,
+	0x00718068,
+	0x0000003f,
+	0xdd000104,
+	0x000f0002,
+	0x00718069,
+	0x0000003f,
+	0xdd400281,
+	0x000f0002,
+	0x0071806a,
+	0x00000079,
+	0xdd31bb03,
+	0x000f0002,
+	0x0071806b,
+	0x00000079,
+	0xdd31fb04,
+	0x000f0002,
+	0x0071806c,
+	0x00000079,
+	0xdd31bb76,
+	0x000f0002,
+	0x0071806d,
+	0x00000079,
+	0xdd31fb76,
+	0x000f0002,
+	0x0071806e,
+	0x00000079,
+	0xfd210101,
+	0x000f0002,
+	0x0071806f,
+	0x0000007d,
+	0xfd2b4081,
+	0x000f0002,
+	0x00718070,
+	0x00000040,
+	0x3d003002,
+	0x000f0002,
+	0x00718071,
+	0x00000048,
+	0x1d003b02,
+	0x000f0002,
+	0x00718072,
+	0x00000079,
+	0xdd217b76,
+	0x000f0002,
+	0x00718073,
+	0x0000002d,
+	0xdd04057f,
+	0x000f0002,
+	0x00718074,
+	0x00000018,
+	0x3d7f3b76,
+	0x000f0002,
+	0x00718075,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718076,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718077,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718078,
+	0x00000021,
+	0xe3371f76,
+	0x000f0002,
+	0x00718079,
+	0x00000049,
+	0xdd003b79,
+	0x000f0002,
+	0x0071807a,
+	0x00000079,
+	0xdd21bb76,
+	0x000f0002,
+	0x0071807b,
+	0x00000049,
+	0xdd003b79,
+	0x000f0002,
+	0x0071807c,
+	0x00000079,
+	0xdd21bb76,
+	0x000f0002,
+	0x0071807d,
+	0x00000049,
+	0xdd003b79,
+	0x000f0002,
+	0x0071807e,
+	0x00000079,
+	0xdd21bb76,
+	0x000f0002,
+	0x0071807f,
+	0x00000079,
+	0xfd609076,
+	0x000f0002,
+	0x00718080,
+	0x00000079,
+	0xdd21fb76,
+	0x000f0002,
+	0x00718081,
+	0x0000003f,
+	0xdf000083,
+	0x000f0002,
+	0x00718082,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718083,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718084,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718085,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718086,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718087,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718088,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718089,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071808a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071808b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071808c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071808d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071808e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071808f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718090,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718091,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718092,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718093,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718094,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718095,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718096,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718097,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718098,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718099,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071809a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071809b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071809c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071809d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071809e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071809f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007180a0,
+	0x0000002d,
+	0xd0080803,
+	0x000f0002,
+	0x007180a1,
+	0x00000008,
+	0x21b5fb76,
+	0x000f0002,
+	0x007180a2,
+	0x00000079,
+	0xdd010081,
+	0x000f0002,
+	0x007180a3,
+	0x00000079,
+	0xdd018102,
+	0x000f0002,
+	0x007180a4,
+	0x0000007d,
+	0xfd018083,
+	0x000f0002,
+	0x007180a5,
+	0x00000079,
+	0xd0903b76,
+	0x000f0002,
+	0x007180a6,
+	0x00000049,
+	0xd0583b7a,
+	0x000f0002,
+	0x007180a7,
+	0x00000049,
+	0xd2043b00,
+	0x000f0002,
+	0x007180a8,
+	0x0000003d,
+	0xdd400003,
+	0x000f0002,
+	0x007180a9,
+	0x00000024,
+	0x32000264,
+	0x000f0002,
+	0x007180aa,
+	0x0000003d,
+	0xdd7ff803,
+	0x000f0002,
+	0x007180ab,
+	0x00000029,
+	0xd020017a,
+	0x000f0002,
+	0x007180ac,
+	0x00000049,
+	0xd0a43b0e,
+	0x000f0002,
+	0x007180ad,
+	0x0000002d,
+	0xdd0442ff,
+	0x000f0002,
+	0x007180ae,
+	0x00000018,
+	0x3d7f3b76,
+	0x000f0002,
+	0x007180af,
+	0x0000002d,
+	0xdd060082,
+	0x000f0002,
+	0x007180b0,
+	0x00000038,
+	0x300001e0,
+	0x000f0002,
+	0x007180b1,
+	0x00000039,
+	0xd0000160,
+	0x000f0002,
+	0x007180b2,
+	0x00000079,
+	0xd1b13b7c,
+	0x000f0002,
+	0x007180b3,
+	0x0000002d,
+	0xdde00fe3,
+	0x000f0002,
+	0x007180b4,
+	0x00000049,
+	0xd08030e4,
+	0x000f0002,
+	0x007180b5,
+	0x00000079,
+	0xdd317b7c,
+	0x000f0002,
+	0x007180b6,
+	0x00000079,
+	0xdd313b7c,
+	0x000f0002,
+	0x007180b7,
+	0x0000007d,
+	0xfd374082,
+	0x000f0002,
+	0x007180b8,
+	0x00000008,
+	0x017d3b76,
+	0x000f0002,
+	0x007180b9,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007180ba,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007180bb,
+	0x00000049,
+	0xdd000387,
+	0x000f0002,
+	0x007180bc,
+	0x00000079,
+	0xdd310408,
+	0x000f0002,
+	0x007180bd,
+	0x00000079,
+	0xdd317d7a,
+	0x000f0002,
+	0x007180be,
+	0x00000049,
+	0xd3003b7c,
+	0x000f0002,
+	0x007180bf,
+	0x00000079,
+	0xd381bb7c,
+	0x000f0002,
+	0x007180c0,
+	0x0000007f,
+	0xd101b27c,
+	0x000f0002,
+	0x007180c1,
+	0x00000048,
+	0x51003264,
+	0x000f0002,
+	0x007180c2,
+	0x0000003d,
+	0xdd400003,
+	0x000f0002,
+	0x007180c3,
+	0x00000008,
+	0x01953162,
+	0x000f0002,
+	0x007180c4,
+	0x00000021,
+	0xd3000666,
+	0x000f0002,
+	0x007180c5,
+	0x00000020,
+	0x538000e7,
+	0x000f0002,
+	0x007180c6,
+	0x0000003f,
+	0xdd000800,
+	0x000f0002,
+	0x007180c7,
+	0x00000079,
+	0xdd01b366,
+	0x000f0002,
+	0x007180c8,
+	0x00000079,
+	0xdd01b3e7,
+	0x000f0002,
+	0x007180c9,
+	0x00000075,
+	0xf1018662,
+	0x000f0002,
+	0x007180ca,
+	0x00000075,
+	0xd201b164,
+	0x000f0002,
+	0x007180cb,
+	0x00000078,
+	0x1d007b76,
+	0x000f0002,
+	0x007180cc,
+	0x00000025,
+	0xdd0001e3,
+	0x000f0002,
+	0x007180cd,
+	0x00000008,
+	0x01b13162,
+	0x000f0002,
+	0x007180ce,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007180cf,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007180d0,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007180d1,
+	0x00000021,
+	0xe3379f63,
+	0x000f0002,
+	0x007180d2,
+	0x00000049,
+	0xd3003b7c,
+	0x000f0002,
+	0x007180d3,
+	0x00000079,
+	0xd381bb7c,
+	0x000f0002,
+	0x007180d4,
+	0x0000007f,
+	0xd101b27c,
+	0x000f0002,
+	0x007180d5,
+	0x00000048,
+	0x51003264,
+	0x000f0002,
+	0x007180d6,
+	0x00000075,
+	0xd201b164,
+	0x000f0002,
+	0x007180d7,
+	0x00000078,
+	0x1d007b76,
+	0x000f0002,
+	0x007180d8,
+	0x0000003f,
+	0xdd000004,
+	0x000f0002,
+	0x007180d9,
+	0x00000079,
+	0xdd01c081,
+	0x000f0002,
+	0x007180da,
+	0x00000079,
+	0xfd609076,
+	0x000f0002,
+	0x007180db,
+	0x0000002d,
+	0xdd080803,
+	0x000f0002,
+	0x007180dc,
+	0x00000078,
+	0x3d01c081,
+	0x000f0002,
+	0x007180dd,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007180de,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007180df,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007180e0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007180e1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007180e2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007180e3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007180e4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007180e5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007180e6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007180e7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007180e8,
+	0x00000049,
+	0xd18e3b03,
+	0x000f0002,
+	0x007180e9,
+	0x0000002f,
+	0xd18100e3,
+	0x000f0002,
+	0x007180ea,
+	0x0000003f,
+	0xd1801803,
+	0x000f0002,
+	0x007180eb,
+	0x00000049,
+	0xd1043b03,
+	0x000f0002,
+	0x007180ec,
+	0x0000003f,
+	0xdd800203,
+	0x000f0002,
+	0x007180ed,
+	0x00000049,
+	0xd2043b02,
+	0x000f0002,
+	0x007180ee,
+	0x00000049,
+	0xd2843b00,
+	0x000f0002,
+	0x007180ef,
+	0x00000025,
+	0xdd0000e2,
+	0x000f0002,
+	0x007180f0,
+	0x00000094,
+	0x00134162,
+	0x000f0002,
+	0x007180f1,
+	0x00000094,
+	0x000b4362,
+	0x000f0002,
+	0x007180f2,
+	0x00000094,
+	0x001548e2,
+	0x000f0002,
+	0x007180f3,
+	0x00000094,
+	0x001b4962,
+	0x000f0002,
+	0x007180f4,
+	0x00000094,
+	0x002f4076,
+	0x000f0002,
+	0x007180f5,
+	0x00000009,
+	0xcf813d7a,
+	0x000f0002,
+	0x007180f6,
+	0x0000001d,
+	0xfd2b80e5,
+	0x000f0002,
+	0x007180f7,
+	0x00000030,
+	0x31838063,
+	0x000f0002,
+	0x007180f8,
+	0x00000030,
+	0x11828063,
+	0x000f0002,
+	0x007180f9,
+	0x0000001d,
+	0xfd2580e5,
+	0x000f0002,
+	0x007180fa,
+	0x00000030,
+	0x31830063,
+	0x000f0002,
+	0x007180fb,
+	0x00000030,
+	0x11820063,
+	0x000f0002,
+	0x007180fc,
+	0x0000002f,
+	0xd18100e3,
+	0x000f0002,
+	0x007180fd,
+	0x0000001d,
+	0xfd0980e5,
+	0x000f0002,
+	0x007180fe,
+	0x00000030,
+	0x3183d363,
+	0x000f0002,
+	0x007180ff,
+	0x00000030,
+	0x1183d263,
+	0x000f0002,
+	0x00718100,
+	0x0000002f,
+	0xd18100e3,
+	0x000f0002,
+	0x00718101,
+	0x0000003f,
+	0xd6800184,
+	0x000f0002,
+	0x00718102,
+	0x0000003f,
+	0xd6800001,
+	0x000f0002,
+	0x00718103,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x00718104,
+	0x00000018,
+	0x37ff0081,
+	0x000f0002,
+	0x00718105,
+	0x00000025,
+	0xd2000264,
+	0x000f0002,
+	0x00718106,
+	0x00000018,
+	0x7d77fd7a,
+	0x000f0002,
+	0x00718107,
+	0x00000049,
+	0xde203b63,
+	0x000f0002,
+	0x00718108,
+	0x00000049,
+	0xde803b79,
+	0x000f0002,
+	0x00718109,
+	0x00000021,
+	0xd18000e3,
+	0x000f0002,
+	0x0071810a,
+	0x00000009,
+	0xcf813d7a,
+	0x000f0002,
+	0x0071810b,
+	0x00000049,
+	0xdd0031e3,
+	0x000f0002,
+	0x0071810c,
+	0x00000069,
+	0xdd0e3b78,
+	0x000f0002,
+	0x0071810d,
+	0x00000061,
+	0xdd003b76,
+	0x000f0002,
+	0x0071810e,
+	0x0000003f,
+	0xdd000184,
+	0x000f0002,
+	0x0071810f,
+	0x0000003f,
+	0xdd000001,
+	0x000f0002,
+	0x00718110,
+	0x00000035,
+	0xdd0000fa,
+	0x000f0002,
+	0x00718111,
+	0x00000018,
+	0x3b7f3b76,
+	0x000f0002,
+	0x00718112,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718113,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718114,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x00718115,
+	0x00000021,
+	0xd18000e3,
+	0x000f0002,
+	0x00718116,
+	0x00000069,
+	0xdd043b79,
+	0x000f0002,
+	0x00718117,
+	0x00000061,
+	0xf18000e3,
+	0x000f0002,
+	0x00718118,
+	0x0000003f,
+	0xd6800184,
+	0x000f0002,
+	0x00718119,
+	0x0000003f,
+	0xd6800001,
+	0x000f0002,
+	0x0071811a,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x0071811b,
+	0x00000018,
+	0x37ff0081,
+	0x000f0002,
+	0x0071811c,
+	0x00000025,
+	0xd2000264,
+	0x000f0002,
+	0x0071811d,
+	0x00000098,
+	0x605dbb76,
+	0x000f0002,
+	0x0071811e,
+	0x00000009,
+	0xcf813d7a,
+	0x000f0002,
+	0x0071811f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718120,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718121,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718122,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718123,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718124,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718125,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718126,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718127,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718128,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718129,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071812a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071812b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071812c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071812d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071812e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071812f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718130,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718131,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718132,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718133,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718134,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718135,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718136,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718137,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718138,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718139,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071813a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071813b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071813c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071813d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071813e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071813f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718140,
+	0x00000049,
+	0xd4083b01,
+	0x000f0002,
+	0x00718141,
+	0x00000009,
+	0xc28b3d7a,
+	0x000f0002,
+	0x00718142,
+	0x0000003f,
+	0xd4000380,
+	0x000f0002,
+	0x00718143,
+	0x00000009,
+	0xc28b3d7a,
+	0x000f0002,
+	0x00718144,
+	0x00000049,
+	0xd40e3b03,
+	0x000f0002,
+	0x00718145,
+	0x0000003f,
+	0xd6420000,
+	0x000f0002,
+	0x00718146,
+	0x0000002f,
+	0xd2814080,
+	0x000f0002,
+	0x00718147,
+	0x0000002d,
+	0xd2840365,
+	0x000f0002,
+	0x00718148,
+	0x0000003f,
+	0xd6800080,
+	0x000f0002,
+	0x00718149,
+	0x0000003f,
+	0xdd040004,
+	0x000f0002,
+	0x0071814a,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x0071814b,
+	0x00000069,
+	0xdd003b6d,
+	0x000f0002,
+	0x0071814c,
+	0x00000069,
+	0xdd003b6d,
+	0x000f0002,
+	0x0071814d,
+	0x00000031,
+	0xd303d265,
+	0x000f0002,
+	0x0071814e,
+	0x00000049,
+	0xde403b66,
+	0x000f0002,
+	0x0071814f,
+	0x0000003f,
+	0xd6800184,
+	0x000f0002,
+	0x00718150,
+	0x0000003f,
+	0xd6800001,
+	0x000f0002,
+	0x00718151,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x00718152,
+	0x00000018,
+	0x37ff0081,
+	0x000f0002,
+	0x00718153,
+	0x00000049,
+	0xd5803b7e,
+	0x000f0002,
+	0x00718154,
+	0x00000021,
+	0xde4000e6,
+	0x000f0002,
+	0x00718155,
+	0x0000003f,
+	0xd6800184,
+	0x000f0002,
+	0x00718156,
+	0x0000003f,
+	0xd6800001,
+	0x000f0002,
+	0x00718157,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x00718158,
+	0x00000018,
+	0x37ff0081,
+	0x000f0002,
+	0x00718159,
+	0x00000049,
+	0xd5003b7e,
+	0x000f0002,
+	0x0071815a,
+	0x00000079,
+	0xdd013b76,
+	0x000f0002,
+	0x0071815b,
+	0x0000002d,
+	0xdd04407f,
+	0x000f0002,
+	0x0071815c,
+	0x00000018,
+	0x3d7f3b76,
+	0x000f0002,
+	0x0071815d,
+	0x00000079,
+	0xdd01bb76,
+	0x000f0002,
+	0x0071815e,
+	0x00000075,
+	0xfd0180e8,
+	0x000f0002,
+	0x0071815f,
+	0x00000094,
+	0x00154168,
+	0x000f0002,
+	0x00718160,
+	0x00000094,
+	0x002544e8,
+	0x000f0002,
+	0x00718161,
+	0x00000094,
+	0x002341e8,
+	0x000f0002,
+	0x00718162,
+	0x00000094,
+	0x00174568,
+	0x000f0002,
+	0x00718163,
+	0x00000094,
+	0x00154268,
+	0x000f0002,
+	0x00718164,
+	0x00000094,
+	0x002742e8,
+	0x000f0002,
+	0x00718165,
+	0x00000094,
+	0x002d4368,
+	0x000f0002,
+	0x00718166,
+	0x00000094,
+	0x002d4468,
+	0x000f0002,
+	0x00718167,
+	0x00000094,
+	0x003343e8,
+	0x000f0002,
+	0x00718168,
+	0x00000004,
+	0x03973b76,
+	0x000f0002,
+	0x00718169,
+	0x0000000d,
+	0xe30dc165,
+	0x000f0002,
+	0x0071816a,
+	0x00000030,
+	0x32030076,
+	0x000f0002,
+	0x0071816b,
+	0x00000030,
+	0x12020076,
+	0x000f0002,
+	0x0071816c,
+	0x0000003f,
+	0xd4800000,
+	0x000f0002,
+	0x0071816d,
+	0x0000003f,
+	0xd1808000,
+	0x000f0002,
+	0x0071816e,
+	0x0000000d,
+	0xe33fc165,
+	0x000f0002,
+	0x0071816f,
+	0x00000030,
+	0x32046076,
+	0x000f0002,
+	0x00718170,
+	0x00000030,
+	0x12044076,
+	0x000f0002,
+	0x00718171,
+	0x0000003f,
+	0xd4828000,
+	0x000f0002,
+	0x00718172,
+	0x0000003f,
+	0xd1808000,
+	0x000f0002,
+	0x00718173,
+	0x0000000d,
+	0xe33fc165,
+	0x000f0002,
+	0x00718174,
+	0x00000030,
+	0x32042076,
+	0x000f0002,
+	0x00718175,
+	0x00000030,
+	0x12040076,
+	0x000f0002,
+	0x00718176,
+	0x0000003f,
+	0xd4820000,
+	0x000f0002,
+	0x00718177,
+	0x0000000d,
+	0xe363c165,
+	0x000f0002,
+	0x00718178,
+	0x00000030,
+	0x32032076,
+	0x000f0002,
+	0x00718179,
+	0x00000030,
+	0x12030076,
+	0x000f0002,
+	0x0071817a,
+	0x0000003f,
+	0xd4830000,
+	0x000f0002,
+	0x0071817b,
+	0x00000049,
+	0xd2803b76,
+	0x000f0002,
+	0x0071817c,
+	0x0000000d,
+	0xe30dc165,
+	0x000f0002,
+	0x0071817d,
+	0x00000030,
+	0x32038076,
+	0x000f0002,
+	0x0071817e,
+	0x00000030,
+	0x12028076,
+	0x000f0002,
+	0x0071817f,
+	0x0000003f,
+	0xd4810000,
+	0x000f0002,
+	0x00718180,
+	0x0000003f,
+	0xd6020000,
+	0x000f0002,
+	0x00718181,
+	0x0000003f,
+	0xd1810000,
+	0x000f0002,
+	0x00718182,
+	0x0000000d,
+	0xe33fc165,
+	0x000f0002,
+	0x00718183,
+	0x00000030,
+	0x32042076,
+	0x000f0002,
+	0x00718184,
+	0x00000030,
+	0x12040076,
+	0x000f0002,
+	0x00718185,
+	0x0000003f,
+	0xd4820000,
+	0x000f0002,
+	0x00718186,
+	0x00000041,
+	0xd48034eb,
+	0x000f0002,
+	0x00718187,
+	0x00000079,
+	0xdd01bb6a,
+	0x000f0002,
+	0x00718188,
+	0x00000079,
+	0xdd01bb76,
+	0x000f0002,
+	0x00718189,
+	0x0000003f,
+	0xd2001803,
+	0x000f0002,
+	0x0071818a,
+	0x0000003f,
+	0xd1810000,
+	0x000f0002,
+	0x0071818b,
+	0x00000075,
+	0xfd018063,
+	0x000f0002,
+	0x0071818c,
+	0x00000098,
+	0x80693b64,
+	0x000f0002,
+	0x0071818d,
+	0x00000051,
+	0xf20000e4,
+	0x000f0002,
+	0x0071818e,
+	0x0000003f,
+	0xd6800184,
+	0x000f0002,
+	0x0071818f,
+	0x0000003f,
+	0xd6800001,
+	0x000f0002,
+	0x00718190,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x00718191,
+	0x00000018,
+	0x37ff0081,
+	0x000f0002,
+	0x00718192,
+	0x0000002d,
+	0xdd04407f,
+	0x000f0002,
+	0x00718193,
+	0x00000018,
+	0x3d7f3b76,
+	0x000f0002,
+	0x00718194,
+	0x00000049,
+	0xd3c03b38,
+	0x000f0002,
+	0x00718195,
+	0x00000049,
+	0xdd003b64,
+	0x000f0002,
+	0x00718196,
+	0x00000051,
+	0xf20000e4,
+	0x000f0002,
+	0x00718197,
+	0x0000003f,
+	0xd6800184,
+	0x000f0002,
+	0x00718198,
+	0x0000003f,
+	0xd6800001,
+	0x000f0002,
+	0x00718199,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x0071819a,
+	0x00000018,
+	0x37ff0081,
+	0x000f0002,
+	0x0071819b,
+	0x00000049,
+	0xd3a03b38,
+	0x000f0002,
+	0x0071819c,
+	0x00000019,
+	0xdd61bb76,
+	0x000f0002,
+	0x0071819d,
+	0x00000049,
+	0xdd003b67,
+	0x000f0002,
+	0x0071819e,
+	0x00000075,
+	0xf1818263,
+	0x000f0002,
+	0x0071819f,
+	0x00000041,
+	0xd48034eb,
+	0x000f0002,
+	0x007181a0,
+	0x00000079,
+	0xdd01bb6a,
+	0x000f0002,
+	0x007181a1,
+	0x00000079,
+	0xdd01bb76,
+	0x000f0002,
+	0x007181a2,
+	0x0000003f,
+	0xd2001803,
+	0x000f0002,
+	0x007181a3,
+	0x0000003f,
+	0xd1808000,
+	0x000f0002,
+	0x007181a4,
+	0x00000075,
+	0xfd018063,
+	0x000f0002,
+	0x007181a5,
+	0x00000098,
+	0x80373b64,
+	0x000f0002,
+	0x007181a6,
+	0x00000051,
+	0xf20000e4,
+	0x000f0002,
+	0x007181a7,
+	0x0000003f,
+	0xd6800184,
+	0x000f0002,
+	0x007181a8,
+	0x0000003f,
+	0xd6800001,
+	0x000f0002,
+	0x007181a9,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x007181aa,
+	0x00000018,
+	0x37ff0081,
+	0x000f0002,
+	0x007181ab,
+	0x0000002d,
+	0xdd04407f,
+	0x000f0002,
+	0x007181ac,
+	0x00000018,
+	0x3d7f3b76,
+	0x000f0002,
+	0x007181ad,
+	0x00000049,
+	0xd3803b38,
+	0x000f0002,
+	0x007181ae,
+	0x00000019,
+	0xdd6fbb76,
+	0x000f0002,
+	0x007181af,
+	0x00000049,
+	0xdd003b67,
+	0x000f0002,
+	0x007181b0,
+	0x00000075,
+	0xf1818263,
+	0x000f0002,
+	0x007181b1,
+	0x00000041,
+	0xd48034eb,
+	0x000f0002,
+	0x007181b2,
+	0x00000079,
+	0xdd01bb6a,
+	0x000f0002,
+	0x007181b3,
+	0x00000079,
+	0xdd01bb63,
+	0x000f0002,
+	0x007181b4,
+	0x00000075,
+	0xfd018063,
+	0x000f0002,
+	0x007181b5,
+	0x00000098,
+	0x80173b64,
+	0x000f0002,
+	0x007181b6,
+	0x00000049,
+	0xde403b64,
+	0x000f0002,
+	0x007181b7,
+	0x0000003f,
+	0xd6800184,
+	0x000f0002,
+	0x007181b8,
+	0x0000003f,
+	0xd6800001,
+	0x000f0002,
+	0x007181b9,
+	0x00000035,
+	0xd68000ed,
+	0x000f0002,
+	0x007181ba,
+	0x00000018,
+	0x37ff0081,
+	0x000f0002,
+	0x007181bb,
+	0x0000002d,
+	0xdd04407f,
+	0x000f0002,
+	0x007181bc,
+	0x00000018,
+	0x3d7f3b76,
+	0x000f0002,
+	0x007181bd,
+	0x00000021,
+	0xd20000e4,
+	0x000f0002,
+	0x007181be,
+	0x00000019,
+	0xd3ef7b7e,
+	0x000f0002,
+	0x007181bf,
+	0x00000075,
+	0xf1818263,
+	0x000f0002,
+	0x007181c0,
+	0x0000003f,
+	0xd6800000,
+	0x000f0002,
+	0x007181c1,
+	0x0000003f,
+	0xdd040004,
+	0x000f0002,
+	0x007181c2,
+	0x0000003f,
+	0xdd180001,
+	0x000f0002,
+	0x007181c3,
+	0x00000069,
+	0xdd003b6d,
+	0x000f0002,
+	0x007181c4,
+	0x00000069,
+	0xdd003b6d,
+	0x000f0002,
+	0x007181c5,
+	0x0000003f,
+	0xdd000000,
+	0x000f0002,
+	0x007181c6,
+	0x0000002d,
+	0xdd540180,
+	0x000f0002,
+	0x007181c7,
+	0x00000079,
+	0xf3e08076,
+	0x000f0002,
+	0x007181c8,
+	0x00000049,
+	0xd600367a,
+	0x000f0002,
+	0x007181c9,
+	0x00000079,
+	0xdd01fb76,
+	0x000f0002,
+	0x007181ca,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007181cb,
+	0x00000049,
+	0xdd003b03,
+	0x000f0002,
+	0x007181cc,
+	0x00000059,
+	0xfd003b76,
+	0x000f0002,
+	0x007181cd,
+	0x0000003f,
+	0xdd801c03,
+	0x000f0002,
+	0x007181ce,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007181cf,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007181d0,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007181d1,
+	0x0000002d,
+	0xdd06027f,
+	0x000f0002,
+	0x007181d2,
+	0x00000018,
+	0x1d7f3d7a,
+	0x000f0002,
+	0x007181d3,
+	0x00000031,
+	0xd483886b,
+	0x000f0002,
+	0x007181d4,
+	0x00000079,
+	0xdd01bb6a,
+	0x000f0002,
+	0x007181d5,
+	0x00000079,
+	0xf1819076,
+	0x000f0002,
+	0x007181d6,
+	0x00000075,
+	0xfd018063,
+	0x000f0002,
+	0x007181d7,
+	0x00000098,
+	0x8053bb76,
+	0x000f0002,
+	0x007181d8,
+	0x00000019,
+	0xdd7f7b79,
+	0x000f0002,
+	0x007181d9,
+	0x00000075,
+	0xf1818263,
+	0x000f0002,
+	0x007181da,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181db,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181dc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181dd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181de,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181df,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181e0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181e1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181e2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181e3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181e4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181e5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181e6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181e7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181e8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181e9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181ea,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181eb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181ec,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181ed,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181ee,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181ef,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181f0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181f1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181f2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181f3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181f4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181f5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181f6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181f7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181f8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181f9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181fa,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181fb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181fc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181fd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007181fe,
+	0x0000003f,
+	0xdd800203,
+	0x000f0002,
+	0x007181ff,
+	0x00000049,
+	0xd1843b02,
+	0x000f0002,
+	0x00718200,
+	0x00000049,
+	0xdd003b03,
+	0x000f0002,
+	0x00718201,
+	0x00000069,
+	0xdd003b7a,
+	0x000f0002,
+	0x00718202,
+	0x00000049,
+	0xdd003b79,
+	0x000f0002,
+	0x00718203,
+	0x00000065,
+	0xf1800263,
+	0x000f0002,
+	0x00718204,
+	0x00000018,
+	0x7d7d3b76,
+	0x000f0002,
+	0x00718205,
+	0x00000009,
+	0xcf813d7a,
+	0x000f0002,
+	0x00718206,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718207,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718208,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718209,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071820a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071820b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071820c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071820d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071820e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071820f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718210,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718211,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718212,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718213,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718214,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718215,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718216,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718217,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718218,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718219,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071821a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071821b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071821c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071821d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071821e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071821f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718220,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718221,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718222,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718223,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718224,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718225,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718226,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718227,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718228,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718229,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071822a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071822b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071822c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071822d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071822e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071822f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718230,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718231,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718232,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718233,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718234,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718235,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718236,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718237,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718238,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718239,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071823a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071823b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071823c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071823d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071823e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071823f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718240,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718241,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718242,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718243,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718244,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718245,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718246,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718247,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718248,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718249,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071824a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071824b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071824c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071824d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071824e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071824f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718250,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718251,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718252,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718253,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718254,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718255,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718256,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718257,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718258,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718259,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071825a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071825b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071825c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071825d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071825e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071825f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718260,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718261,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718262,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718263,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718264,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718265,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718266,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718267,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718268,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718269,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071826a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071826b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071826c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071826d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071826e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071826f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718270,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718271,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718272,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718273,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718274,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718275,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718276,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718277,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718278,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718279,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071827a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071827b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071827c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071827d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071827e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071827f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718280,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718281,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718282,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718283,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718284,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718285,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718286,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718287,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718288,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718289,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071828a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071828b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071828c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071828d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071828e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071828f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718290,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718291,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718292,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718293,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718294,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718295,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718296,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718297,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718298,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718299,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071829a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071829b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071829c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071829d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071829e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071829f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182a0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182a1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182a2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182a3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182a4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182a5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182a6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182a7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182a8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182a9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182aa,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182ab,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182ac,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182ad,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182ae,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182af,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182b0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182b1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182b2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182b3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182b4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182b5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182b6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182b7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182b8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182b9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182ba,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182bb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182bc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182bd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182be,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182bf,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182c0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182c1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182c2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182c3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182c4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182c5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182c6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182c7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182c8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182c9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182ca,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182cb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182cc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182cd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182ce,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182cf,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182d0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182d1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182d2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182d3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182d4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182d5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182d6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182d7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182d8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182d9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182da,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182db,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182dc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182dd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182de,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182df,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182e0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182e1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182e2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182e3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182e4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182e5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182e6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182e7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182e8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182e9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182ea,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182eb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182ec,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182ed,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182ee,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182ef,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182f0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182f1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182f2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182f3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182f4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182f5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182f6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182f7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182f8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182f9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182fa,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182fb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182fc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182fd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182fe,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007182ff,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718300,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718301,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718302,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718303,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718304,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718305,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718306,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718307,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718308,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718309,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071830a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071830b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071830c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071830d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071830e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071830f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718310,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718311,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718312,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718313,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718314,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718315,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718316,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718317,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718318,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718319,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071831a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071831b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071831c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071831d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071831e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071831f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718320,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718321,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718322,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718323,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718324,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718325,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718326,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718327,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718328,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718329,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071832a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071832b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071832c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071832d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071832e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071832f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718330,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718331,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718332,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718333,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718334,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718335,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718336,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718337,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718338,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718339,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071833a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071833b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071833c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071833d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071833e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071833f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718340,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718341,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718342,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718343,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718344,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718345,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718346,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718347,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718348,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718349,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071834a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071834b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071834c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071834d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071834e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071834f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718350,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718351,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718352,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718353,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718354,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718355,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718356,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718357,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718358,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718359,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071835a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071835b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071835c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071835d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071835e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071835f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718360,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718361,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718362,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718363,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718364,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718365,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718366,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718367,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718368,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718369,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071836a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071836b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071836c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071836d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071836e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071836f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718370,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718371,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718372,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718373,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718374,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718375,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718376,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718377,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718378,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718379,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071837a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071837b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071837c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071837d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071837e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071837f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718380,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718381,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718382,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718383,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718384,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718385,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718386,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718387,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718388,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718389,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071838a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071838b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071838c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071838d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071838e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071838f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718390,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718391,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718392,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718393,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718394,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718395,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718396,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718397,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718398,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718399,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071839a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071839b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071839c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071839d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071839e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071839f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183a0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183a1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183a2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183a3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183a4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183a5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183a6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183a7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183a8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183a9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183aa,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183ab,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183ac,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183ad,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183ae,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183af,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183b0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183b1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183b2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183b3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183b4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183b5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183b6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183b7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183b8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183b9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183ba,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183bb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183bc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183bd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183be,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183bf,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183c0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183c1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183c2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183c3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183c4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183c5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183c6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183c7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183c8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183c9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183ca,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183cb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183cc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183cd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183ce,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183cf,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183d0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183d1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183d2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183d3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183d4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183d5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183d6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183d7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183d8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183d9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183da,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183db,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183dc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183dd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183de,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183df,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183e0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183e1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183e2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183e3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183e4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183e5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183e6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183e7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183e8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183e9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183ea,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183eb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183ec,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183ed,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183ee,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183ef,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183f0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183f1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183f2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183f3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183f4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183f5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183f6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183f7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183f8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183f9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183fa,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183fb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183fc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183fd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183fe,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007183ff,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718400,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718401,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718402,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718403,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718404,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718405,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718406,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718407,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718408,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718409,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071840a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071840b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071840c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071840d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071840e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071840f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718410,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718411,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718412,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718413,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718414,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718415,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718416,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718417,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718418,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718419,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071841a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071841b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071841c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071841d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071841e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071841f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718420,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718421,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718422,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718423,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718424,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718425,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718426,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718427,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718428,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718429,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071842a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071842b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071842c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071842d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071842e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071842f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718430,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718431,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718432,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718433,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718434,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718435,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718436,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718437,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718438,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718439,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071843a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071843b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071843c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071843d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071843e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071843f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718440,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718441,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718442,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718443,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718444,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718445,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718446,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718447,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718448,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718449,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071844a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071844b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071844c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071844d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071844e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071844f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718450,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718451,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718452,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718453,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718454,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718455,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718456,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718457,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718458,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718459,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071845a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071845b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071845c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071845d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071845e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071845f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718460,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718461,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718462,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718463,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718464,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718465,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718466,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718467,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718468,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718469,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071846a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071846b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071846c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071846d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071846e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071846f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718470,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718471,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718472,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718473,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718474,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718475,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718476,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718477,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718478,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718479,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071847a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071847b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071847c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071847d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071847e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071847f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718480,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718481,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718482,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718483,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718484,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718485,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718486,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718487,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718488,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718489,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071848a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071848b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071848c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071848d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071848e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071848f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718490,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718491,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718492,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718493,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718494,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718495,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718496,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718497,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718498,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718499,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071849a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071849b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071849c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071849d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071849e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071849f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184a0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184a1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184a2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184a3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184a4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184a5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184a6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184a7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184a8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184a9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184aa,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184ab,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184ac,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184ad,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184ae,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184af,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184b0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184b1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184b2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184b3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184b4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184b5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184b6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184b7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184b8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184b9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184ba,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184bb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184bc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184bd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184be,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184bf,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184c0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184c1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184c2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184c3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184c4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184c5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184c6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184c7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184c8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184c9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184ca,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184cb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184cc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184cd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184ce,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184cf,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184d0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184d1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184d2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184d3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184d4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184d5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184d6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184d7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184d8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184d9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184da,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184db,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184dc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184dd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184de,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184df,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184e0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184e1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184e2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184e3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184e4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184e5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184e6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184e7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184e8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184e9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184ea,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184eb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184ec,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184ed,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184ee,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184ef,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184f0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184f1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184f2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184f3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184f4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184f5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184f6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184f7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184f8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184f9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184fa,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184fb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184fc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184fd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184fe,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007184ff,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718500,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718501,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718502,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718503,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718504,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718505,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718506,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718507,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718508,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718509,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071850a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071850b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071850c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071850d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071850e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071850f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718510,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718511,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718512,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718513,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718514,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718515,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718516,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718517,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718518,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718519,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071851a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071851b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071851c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071851d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071851e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071851f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718520,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718521,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718522,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718523,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718524,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718525,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718526,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718527,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718528,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718529,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071852a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071852b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071852c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071852d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071852e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071852f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718530,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718531,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718532,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718533,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718534,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718535,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718536,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718537,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718538,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718539,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071853a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071853b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071853c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071853d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071853e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071853f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718540,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718541,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718542,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718543,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718544,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718545,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718546,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718547,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718548,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718549,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071854a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071854b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071854c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071854d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071854e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071854f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718550,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718551,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718552,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718553,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718554,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718555,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718556,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718557,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718558,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718559,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071855a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071855b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071855c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071855d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071855e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071855f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718560,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718561,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718562,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718563,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718564,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718565,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718566,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718567,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718568,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718569,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071856a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071856b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071856c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071856d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071856e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071856f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718570,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718571,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718572,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718573,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718574,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718575,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718576,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718577,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718578,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718579,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071857a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071857b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071857c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071857d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071857e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071857f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718580,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718581,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718582,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718583,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718584,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718585,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718586,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718587,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718588,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718589,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071858a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071858b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071858c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071858d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071858e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071858f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718590,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718591,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718592,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718593,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718594,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718595,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718596,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718597,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718598,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718599,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071859a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071859b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071859c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071859d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071859e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071859f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185a0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185a1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185a2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185a3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185a4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185a5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185a6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185a7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185a8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185a9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185aa,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185ab,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185ac,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185ad,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185ae,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185af,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185b0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185b1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185b2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185b3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185b4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185b5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185b6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185b7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185b8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185b9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185ba,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185bb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185bc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185bd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185be,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185bf,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185c0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185c1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185c2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185c3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185c4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185c5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185c6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185c7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185c8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185c9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185ca,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185cb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185cc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185cd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185ce,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185cf,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185d0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185d1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185d2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185d3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185d4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185d5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185d6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185d7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185d8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185d9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185da,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185db,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185dc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185dd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185de,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185df,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185e0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185e1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185e2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185e3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185e4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185e5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185e6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185e7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185e8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185e9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185ea,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185eb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185ec,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185ed,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185ee,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185ef,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185f0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185f1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185f2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185f3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185f4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185f5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185f6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185f7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185f8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185f9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185fa,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185fb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185fc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185fd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185fe,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007185ff,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718600,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718601,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718602,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718603,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718604,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718605,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718606,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718607,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718608,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718609,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071860a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071860b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071860c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071860d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071860e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071860f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718610,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718611,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718612,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718613,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718614,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718615,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718616,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718617,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718618,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718619,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071861a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071861b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071861c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071861d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071861e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071861f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718620,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718621,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718622,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718623,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718624,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718625,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718626,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718627,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718628,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718629,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071862a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071862b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071862c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071862d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071862e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071862f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718630,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718631,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718632,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718633,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718634,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718635,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718636,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718637,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718638,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718639,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071863a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071863b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071863c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071863d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071863e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071863f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718640,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718641,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718642,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718643,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718644,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718645,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718646,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718647,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718648,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718649,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071864a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071864b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071864c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071864d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071864e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071864f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718650,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718651,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718652,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718653,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718654,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718655,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718656,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718657,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718658,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718659,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071865a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071865b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071865c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071865d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071865e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071865f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718660,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718661,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718662,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718663,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718664,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718665,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718666,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718667,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718668,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718669,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071866a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071866b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071866c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071866d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071866e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071866f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718670,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718671,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718672,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718673,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718674,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718675,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718676,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718677,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718678,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718679,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071867a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071867b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071867c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071867d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071867e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071867f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718680,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718681,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718682,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718683,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718684,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718685,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718686,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718687,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718688,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718689,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071868a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071868b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071868c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071868d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071868e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071868f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718690,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718691,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718692,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718693,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718694,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718695,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718696,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718697,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718698,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718699,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071869a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071869b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071869c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071869d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071869e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071869f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186a0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186a1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186a2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186a3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186a4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186a5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186a6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186a7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186a8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186a9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186aa,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186ab,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186ac,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186ad,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186ae,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186af,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186b0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186b1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186b2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186b3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186b4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186b5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186b6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186b7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186b8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186b9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186ba,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186bb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186bc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186bd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186be,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186bf,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186c0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186c1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186c2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186c3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186c4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186c5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186c6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186c7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186c8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186c9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186ca,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186cb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186cc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186cd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186ce,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186cf,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186d0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186d1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186d2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186d3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186d4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186d5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186d6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186d7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186d8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186d9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186da,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186db,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186dc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186dd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186de,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186df,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186e0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186e1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186e2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186e3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186e4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186e5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186e6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186e7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186e8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186e9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186ea,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186eb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186ec,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186ed,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186ee,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186ef,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186f0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186f1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186f2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186f3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186f4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186f5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186f6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186f7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186f8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186f9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186fa,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186fb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186fc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186fd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186fe,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007186ff,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718700,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718701,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718702,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718703,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718704,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718705,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718706,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718707,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718708,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718709,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071870a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071870b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071870c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071870d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071870e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071870f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718710,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718711,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718712,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718713,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718714,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718715,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718716,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718717,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718718,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718719,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071871a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071871b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071871c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071871d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071871e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071871f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718720,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718721,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718722,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718723,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718724,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718725,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718726,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718727,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718728,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718729,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071872a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071872b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071872c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071872d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071872e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071872f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718730,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718731,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718732,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718733,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718734,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718735,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718736,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718737,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718738,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718739,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071873a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071873b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071873c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071873d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071873e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071873f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718740,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718741,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718742,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718743,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718744,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718745,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718746,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718747,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718748,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718749,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071874a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071874b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071874c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071874d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071874e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071874f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718750,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718751,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718752,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718753,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718754,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718755,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718756,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718757,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718758,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718759,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071875a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071875b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071875c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071875d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071875e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071875f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718760,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718761,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718762,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718763,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718764,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718765,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718766,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718767,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718768,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718769,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071876a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071876b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071876c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071876d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071876e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071876f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718770,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718771,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718772,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718773,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718774,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718775,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718776,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718777,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718778,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718779,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071877a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071877b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071877c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071877d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071877e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071877f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718780,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718781,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718782,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718783,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718784,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718785,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718786,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718787,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718788,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718789,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071878a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071878b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071878c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071878d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071878e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071878f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718790,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718791,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718792,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718793,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718794,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718795,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718796,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718797,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718798,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x00718799,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071879a,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071879b,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071879c,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071879d,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071879e,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x0071879f,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187a0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187a1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187a2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187a3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187a4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187a5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187a6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187a7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187a8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187a9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187aa,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187ab,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187ac,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187ad,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187ae,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187af,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187b0,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187b1,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187b2,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187b3,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187b4,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187b5,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187b6,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187b7,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187b8,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187b9,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187ba,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187bb,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187bc,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187bd,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187be,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187bf,
+	0x00000000,
+	0x00000000,
+	0x000f0002,
+	0x007187c0,
+	0x00000079,
+	0xfd609076,
+	0x000f0002,
+	0x007187c1,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007187c2,
+	0x0000003d,
+	0xf780006f,
+	0x000f0002,
+	0x007187c3,
+	0x0000003d,
+	0xf780006f,
+/* FINISH INIT Descriptor */
+	0x000f0002,
+	0x807187c4,
+	0x0000003d,
+	0xf780006f,
+};
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 5ee1476..30b1cca 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -64,8 +64,8 @@
 
 #define DRV_MODULE_NAME		"tg3"
 #define PFX DRV_MODULE_NAME	": "
-#define DRV_MODULE_VERSION	"3.78"
-#define DRV_MODULE_RELDATE	"July 11, 2007"
+#define DRV_MODULE_VERSION	"3.83"
+#define DRV_MODULE_RELDATE	"October 10, 2007"
 
 #define TG3_DEF_MAC_MODE	0
 #define TG3_DEF_RX_MODE		0
@@ -198,6 +198,10 @@
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906)},
 	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5784)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5764)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)},
+	{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)},
 	{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
 	{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)},
 	{PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)},
@@ -312,6 +316,16 @@
 	return (readl(tp->regs + off));
 }
 
+static void tg3_ape_write32(struct tg3 *tp, u32 off, u32 val)
+{
+	writel(val, tp->aperegs + off);
+}
+
+static u32 tg3_ape_read32(struct tg3 *tp, u32 off)
+{
+	return (readl(tp->aperegs + off));
+}
+
 static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
 {
 	unsigned long flags;
@@ -498,6 +512,73 @@
 	spin_unlock_irqrestore(&tp->indirect_lock, flags);
 }
 
+static void tg3_ape_lock_init(struct tg3 *tp)
+{
+	int i;
+
+	/* Make sure the driver hasn't any stale locks. */
+	for (i = 0; i < 8; i++)
+		tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + 4 * i,
+				APE_LOCK_GRANT_DRIVER);
+}
+
+static int tg3_ape_lock(struct tg3 *tp, int locknum)
+{
+	int i, off;
+	int ret = 0;
+	u32 status;
+
+	if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+		return 0;
+
+	switch (locknum) {
+		case TG3_APE_LOCK_MEM:
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	off = 4 * locknum;
+
+	tg3_ape_write32(tp, TG3_APE_LOCK_REQ + off, APE_LOCK_REQ_DRIVER);
+
+	/* Wait for up to 1 millisecond to acquire lock. */
+	for (i = 0; i < 100; i++) {
+		status = tg3_ape_read32(tp, TG3_APE_LOCK_GRANT + off);
+		if (status == APE_LOCK_GRANT_DRIVER)
+			break;
+		udelay(10);
+	}
+
+	if (status != APE_LOCK_GRANT_DRIVER) {
+		/* Revoke the lock request. */
+		tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off,
+				APE_LOCK_GRANT_DRIVER);
+
+		ret = -EBUSY;
+	}
+
+	return ret;
+}
+
+static void tg3_ape_unlock(struct tg3 *tp, int locknum)
+{
+	int off;
+
+	if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+		return;
+
+	switch (locknum) {
+		case TG3_APE_LOCK_MEM:
+			break;
+		default:
+			return;
+	}
+
+	off = 4 * locknum;
+	tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off, APE_LOCK_GRANT_DRIVER);
+}
+
 static void tg3_disable_ints(struct tg3 *tp)
 {
 	tw32(TG3PCI_MISC_HOST_CTRL,
@@ -574,7 +655,7 @@
 static inline void tg3_netif_stop(struct tg3 *tp)
 {
 	tp->dev->trans_start = jiffies;	/* prevent tx timeout */
-	netif_poll_disable(tp->dev);
+	napi_disable(&tp->napi);
 	netif_tx_disable(tp->dev);
 }
 
@@ -585,7 +666,7 @@
 	 * so long as all callers are assured to have free tx slots
 	 * (such as after tg3_init_hw)
 	 */
-	netif_poll_enable(tp->dev);
+	napi_enable(&tp->napi);
 	tp->hw_status->status |= SD_STATUS_UPDATED;
 	tg3_enable_ints(tp);
 }
@@ -595,7 +676,8 @@
 	u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL);
 	u32 orig_clock_ctrl;
 
-	if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
+	if ((tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) ||
+	    (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
 		return;
 
 	orig_clock_ctrl = clock_ctrl;
@@ -1400,6 +1482,7 @@
 		tw32_wait_f(TG3PCI_CLOCK_CTRL, base_val | CLOCK_CTRL_ALTCLK |
 			    CLOCK_CTRL_PWRDOWN_PLL133, 40);
 	} else if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
+		   (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) ||
 		   (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)) {
 		/* do nothing */
 	} else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
@@ -1444,7 +1527,8 @@
 	}
 
 	if (!(tp->tg3_flags & TG3_FLAG_WOL_ENABLE) &&
-	    !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
+	    !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
+	    !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
 		tg3_power_down_phy(tp);
 
 	tg3_frob_aux_power(tp);
@@ -3471,11 +3555,9 @@
 	return received;
 }
 
-static int tg3_poll(struct net_device *netdev, int *budget)
+static int tg3_poll_work(struct tg3 *tp, int work_done, int budget)
 {
-	struct tg3 *tp = netdev_priv(netdev);
 	struct tg3_hw_status *sblk = tp->hw_status;
-	int done;
 
 	/* handle link change and other phy events */
 	if (!(tp->tg3_flags &
@@ -3493,44 +3575,59 @@
 	/* run TX completion thread */
 	if (sblk->idx[0].tx_consumer != tp->tx_cons) {
 		tg3_tx(tp);
-		if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING)) {
-			netif_rx_complete(netdev);
-			schedule_work(&tp->reset_task);
-			return 0;
-		}
+		if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING))
+			return work_done;
 	}
 
 	/* run RX thread, within the bounds set by NAPI.
 	 * All RX "locking" is done by ensuring outside
-	 * code synchronizes with dev->poll()
+	 * code synchronizes with tg3->napi.poll()
 	 */
-	if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr) {
-		int orig_budget = *budget;
-		int work_done;
+	if (sblk->idx[0].rx_producer != tp->rx_rcb_ptr)
+		work_done += tg3_rx(tp, budget - work_done);
 
-		if (orig_budget > netdev->quota)
-			orig_budget = netdev->quota;
+	return work_done;
+}
 
-		work_done = tg3_rx(tp, orig_budget);
+static int tg3_poll(struct napi_struct *napi, int budget)
+{
+	struct tg3 *tp = container_of(napi, struct tg3, napi);
+	int work_done = 0;
+	struct tg3_hw_status *sblk = tp->hw_status;
 
-		*budget -= work_done;
-		netdev->quota -= work_done;
+	while (1) {
+		work_done = tg3_poll_work(tp, work_done, budget);
+
+		if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING))
+			goto tx_recovery;
+
+		if (unlikely(work_done >= budget))
+			break;
+
+		if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
+			/* tp->last_tag is used in tg3_restart_ints() below
+			 * to tell the hw how much work has been processed,
+			 * so we must read it before checking for more work.
+			 */
+			tp->last_tag = sblk->status_tag;
+			rmb();
+		} else
+			sblk->status &= ~SD_STATUS_UPDATED;
+
+		if (likely(!tg3_has_work(tp))) {
+			netif_rx_complete(tp->dev, napi);
+			tg3_restart_ints(tp);
+			break;
+		}
 	}
 
-	if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
-		tp->last_tag = sblk->status_tag;
-		rmb();
-	} else
-		sblk->status &= ~SD_STATUS_UPDATED;
+	return work_done;
 
-	/* if no more work, tell net stack and NIC we're done */
-	done = !tg3_has_work(tp);
-	if (done) {
-		netif_rx_complete(netdev);
-		tg3_restart_ints(tp);
-	}
-
-	return (done ? 0 : 1);
+tx_recovery:
+	/* work_done is guaranteed to be less than budget. */
+	netif_rx_complete(tp->dev, napi);
+	schedule_work(&tp->reset_task);
+	return work_done;
 }
 
 static void tg3_irq_quiesce(struct tg3 *tp)
@@ -3577,7 +3674,7 @@
 	prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
 
 	if (likely(!tg3_irq_sync(tp)))
-		netif_rx_schedule(dev);		/* schedule NAPI poll */
+		netif_rx_schedule(dev, &tp->napi);
 
 	return IRQ_HANDLED;
 }
@@ -3602,7 +3699,7 @@
 	 */
 	tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
 	if (likely(!tg3_irq_sync(tp)))
-		netif_rx_schedule(dev);		/* schedule NAPI poll */
+		netif_rx_schedule(dev, &tp->napi);
 
 	return IRQ_RETVAL(1);
 }
@@ -3644,7 +3741,7 @@
 	sblk->status &= ~SD_STATUS_UPDATED;
 	if (likely(tg3_has_work(tp))) {
 		prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
-		netif_rx_schedule(dev);		/* schedule NAPI poll */
+		netif_rx_schedule(dev, &tp->napi);
 	} else {
 		/* No work, shared interrupt perhaps?  re-enable
 		 * interrupts, and flush that PCI write
@@ -3690,7 +3787,7 @@
 	tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
 	if (tg3_irq_sync(tp))
 		goto out;
-	if (netif_rx_schedule_prep(dev)) {
+	if (netif_rx_schedule_prep(dev, &tp->napi)) {
 		prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
 		/* Update last_tag to mark that this status has been
 		 * seen. Because interrupt may be shared, we may be
@@ -3698,7 +3795,7 @@
 		 * if tg3_poll() is not scheduled.
 		 */
 		tp->last_tag = sblk->status_tag;
-		__netif_rx_schedule(dev);
+		__netif_rx_schedule(dev, &tp->napi);
 	}
 out:
 	return IRQ_RETVAL(handled);
@@ -3737,7 +3834,7 @@
 		tg3_full_unlock(tp);
 		del_timer_sync(&tp->timer);
 		tp->irq_sync = 0;
-		netif_poll_enable(tp->dev);
+		napi_enable(&tp->napi);
 		dev_close(tp->dev);
 		tg3_full_lock(tp, 0);
 	}
@@ -3932,7 +4029,7 @@
 	len = skb_headlen(skb);
 
 	/* We are running in BH disabled context with netif_tx_lock
-	 * and TX reclaim runs via tp->poll inside of a software
+	 * and TX reclaim runs via tp->napi.poll inside of a software
 	 * interrupt.  Furthermore, IRQ processing runs lockless so we have
 	 * no IRQ context deadlocks to worry about either.  Rejoice!
 	 */
@@ -4087,7 +4184,7 @@
 	len = skb_headlen(skb);
 
 	/* We are running in BH disabled context with netif_tx_lock
-	 * and TX reclaim runs via tp->poll inside of a software
+	 * and TX reclaim runs via tp->napi.poll inside of a software
 	 * interrupt.  Furthermore, IRQ processing runs lockless so we have
 	 * no IRQ context deadlocks to worry about either.  Rejoice!
 	 */
@@ -4732,6 +4829,80 @@
 	}
 }
 
+static void tg3_ape_send_event(struct tg3 *tp, u32 event)
+{
+	int i;
+	u32 apedata;
+
+	apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG);
+	if (apedata != APE_SEG_SIG_MAGIC)
+		return;
+
+	apedata = tg3_ape_read32(tp, TG3_APE_FW_STATUS);
+	if (apedata != APE_FW_STATUS_READY)
+		return;
+
+	/* Wait for up to 1 millisecond for APE to service previous event. */
+	for (i = 0; i < 10; i++) {
+		if (tg3_ape_lock(tp, TG3_APE_LOCK_MEM))
+			return;
+
+		apedata = tg3_ape_read32(tp, TG3_APE_EVENT_STATUS);
+
+		if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
+			tg3_ape_write32(tp, TG3_APE_EVENT_STATUS,
+					event | APE_EVENT_STATUS_EVENT_PENDING);
+
+		tg3_ape_unlock(tp, TG3_APE_LOCK_MEM);
+
+		if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
+			break;
+
+		udelay(100);
+	}
+
+	if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
+		tg3_ape_write32(tp, TG3_APE_EVENT, APE_EVENT_1);
+}
+
+static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
+{
+	u32 event;
+	u32 apedata;
+
+	if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+		return;
+
+	switch (kind) {
+		case RESET_KIND_INIT:
+			tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG,
+					APE_HOST_SEG_SIG_MAGIC);
+			tg3_ape_write32(tp, TG3_APE_HOST_SEG_LEN,
+					APE_HOST_SEG_LEN_MAGIC);
+			apedata = tg3_ape_read32(tp, TG3_APE_HOST_INIT_COUNT);
+			tg3_ape_write32(tp, TG3_APE_HOST_INIT_COUNT, ++apedata);
+			tg3_ape_write32(tp, TG3_APE_HOST_DRIVER_ID,
+					APE_HOST_DRIVER_ID_MAGIC);
+			tg3_ape_write32(tp, TG3_APE_HOST_BEHAVIOR,
+					APE_HOST_BEHAV_NO_PHYLOCK);
+
+			event = APE_EVENT_STATUS_STATE_START;
+			break;
+		case RESET_KIND_SHUTDOWN:
+			event = APE_EVENT_STATUS_STATE_UNLOAD;
+			break;
+		case RESET_KIND_SUSPEND:
+			event = APE_EVENT_STATUS_STATE_SUSPEND;
+			break;
+		default:
+			return;
+	}
+
+	event |= APE_EVENT_STATUS_DRIVER_EVNT | APE_EVENT_STATUS_STATE_CHNGE;
+
+	tg3_ape_send_event(tp, event);
+}
+
 /* tp->lock is held. */
 static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
 {
@@ -4759,6 +4930,10 @@
 			break;
 		};
 	}
+
+	if (kind == RESET_KIND_INIT ||
+	    kind == RESET_KIND_SUSPEND)
+		tg3_ape_driver_state_change(tp, kind);
 }
 
 /* tp->lock is held. */
@@ -4780,6 +4955,9 @@
 			break;
 		};
 	}
+
+	if (kind == RESET_KIND_SHUTDOWN)
+		tg3_ape_driver_state_change(tp, kind);
 }
 
 /* tp->lock is held. */
@@ -4847,6 +5025,68 @@
 	return 0;
 }
 
+/* Save PCI command register before chip reset */
+static void tg3_save_pci_state(struct tg3 *tp)
+{
+	u32 val;
+
+	pci_read_config_dword(tp->pdev, TG3PCI_COMMAND, &val);
+	tp->pci_cmd = val;
+}
+
+/* Restore PCI state after chip reset */
+static void tg3_restore_pci_state(struct tg3 *tp)
+{
+	u32 val;
+
+	/* Re-enable indirect register accesses. */
+	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
+			       tp->misc_host_ctrl);
+
+	/* Set MAX PCI retry to zero. */
+	val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
+	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
+		val |= PCISTATE_RETRY_SAME_DMA;
+	/* Allow reads and writes to the APE register and memory space. */
+	if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+		val |= PCISTATE_ALLOW_APE_CTLSPC_WR |
+		       PCISTATE_ALLOW_APE_SHMEM_WR;
+	pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
+
+	pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd);
+
+	/* Make sure PCI-X relaxed ordering bit is clear. */
+	if (tp->pcix_cap) {
+		u16 pcix_cmd;
+
+		pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
+				     &pcix_cmd);
+		pcix_cmd &= ~PCI_X_CMD_ERO;
+		pci_write_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
+				      pcix_cmd);
+	}
+
+	if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
+
+		/* Chip reset on 5780 will reset MSI enable bit,
+		 * so need to restore it.
+		 */
+		if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+			u16 ctrl;
+
+			pci_read_config_word(tp->pdev,
+					     tp->msi_cap + PCI_MSI_FLAGS,
+					     &ctrl);
+			pci_write_config_word(tp->pdev,
+					      tp->msi_cap + PCI_MSI_FLAGS,
+					      ctrl | PCI_MSI_FLAGS_ENABLE);
+			val = tr32(MSGINT_MODE);
+			tw32(MSGINT_MODE, val | MSGINT_MODE_ENABLE);
+		}
+	}
+}
+
 static void tg3_stop_fw(struct tg3 *);
 
 /* tp->lock is held. */
@@ -4863,9 +5103,17 @@
 	 */
 	tp->nvram_lock_cnt = 0;
 
+	/* GRC_MISC_CFG core clock reset will clear the memory
+	 * enable bit in PCI register 4 and the MSI enable bit
+	 * on some chips, so we save relevant registers here.
+	 */
+	tg3_save_pci_state(tp);
+
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
 		tw32(GRC_FASTBOOT_PC, 0);
 
 	/*
@@ -4961,50 +5209,14 @@
 		pci_write_config_dword(tp->pdev, 0xd8, 0xf5000);
 	}
 
-	/* Re-enable indirect register accesses. */
-	pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,
-			       tp->misc_host_ctrl);
-
-	/* Set MAX PCI retry to zero. */
-	val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
-	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
-	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
-		val |= PCISTATE_RETRY_SAME_DMA;
-	pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
-
-	pci_restore_state(tp->pdev);
+	tg3_restore_pci_state(tp);
 
 	tp->tg3_flags &= ~TG3_FLAG_CHIP_RESETTING;
 
-	/* Make sure PCI-X relaxed ordering bit is clear. */
-	pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val);
-	val &= ~PCIX_CAPS_RELAXED_ORDERING;
-	pci_write_config_dword(tp->pdev, TG3PCI_X_CAPS, val);
-
-	if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
-		u32 val;
-
-		/* Chip reset on 5780 will reset MSI enable bit,
-		 * so need to restore it.
-		 */
-		if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
-			u16 ctrl;
-
-			pci_read_config_word(tp->pdev,
-					     tp->msi_cap + PCI_MSI_FLAGS,
-					     &ctrl);
-			pci_write_config_word(tp->pdev,
-					      tp->msi_cap + PCI_MSI_FLAGS,
-					      ctrl | PCI_MSI_FLAGS_ENABLE);
-			val = tr32(MSGINT_MODE);
-			tw32(MSGINT_MODE, val | MSGINT_MODE_ENABLE);
-		}
-
+	val = 0;
+	if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
 		val = tr32(MEMARB_MODE);
-		tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
-
-	} else
-		tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
+	tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
 
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A3) {
 		tg3_stop_fw(tp);
@@ -5014,7 +5226,7 @@
 	tw32(GRC_MODE, tp->grc_mode);
 
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A0) {
-		u32 val = tr32(0xc4);
+		val = tr32(0xc4);
 
 		tw32(0xc4, val | (1 << 15));
 	}
@@ -5043,7 +5255,7 @@
 
 	if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
 	    tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) {
-		u32 val = tr32(0x7c00);
+		val = tr32(0x7c00);
 
 		tw32(0x7c00, val | (1 << 25));
 	}
@@ -5069,7 +5281,8 @@
 /* tp->lock is held. */
 static void tg3_stop_fw(struct tg3 *tp)
 {
-	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+	if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
+	   !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
 		u32 val;
 		int i;
 
@@ -6126,14 +6339,22 @@
 
 	tg3_write_sig_legacy(tp, RESET_KIND_INIT);
 
+	if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0) {
+		val = tr32(TG3_CPMU_CTRL);
+		val &= ~(CPMU_CTRL_LINK_AWARE_MODE | CPMU_CTRL_LINK_IDLE_MODE);
+		tw32(TG3_CPMU_CTRL, val);
+	}
+
 	/* This works around an issue with Athlon chipsets on
 	 * B3 tigon3 silicon.  This bit has no effect on any
 	 * other revision.  But do not set this on PCI Express
-	 * chips.
+	 * chips and don't even touch the clocks if the CPMU is present.
 	 */
-	if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
-		tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT;
-	tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
+	if (!(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)) {
+		if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
+			tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT;
+		tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
+	}
 
 	if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
 	    (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) {
@@ -6142,6 +6363,16 @@
 		tw32(TG3PCI_PCISTATE, val);
 	}
 
+	if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+		/* Allow reads and writes to the
+		 * APE register and memory space.
+		 */
+		val = tr32(TG3PCI_PCISTATE);
+		val |= PCISTATE_ALLOW_APE_CTLSPC_WR |
+		       PCISTATE_ALLOW_APE_SHMEM_WR;
+		tw32(TG3PCI_PCISTATE, val);
+	}
+
 	if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_BX) {
 		/* Enable some hw fixes.  */
 		val = tr32(TG3PCI_MSI_DATA);
@@ -6158,10 +6389,13 @@
 	if (err)
 		return err;
 
-	/* This value is determined during the probe time DMA
-	 * engine test, tg3_test_dma.
-	 */
-	tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) {
+		/* This value is determined during the probe time DMA
+		 * engine test, tg3_test_dma.
+		 */
+		tw32(TG3PCI_DMA_RW_CTRL, tp->dma_rwctrl);
+	}
 
 	tp->grc_mode &= ~(GRC_MODE_HOST_SENDBDS |
 			  GRC_MODE_4X_NIC_SEND_RINGS |
@@ -6395,6 +6629,11 @@
 		      RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
 		      RDMAC_MODE_LNGREAD_ENAB);
 
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
+		rdmac_mode |= RDMAC_MODE_BD_SBD_CRPT_ENAB |
+			      RDMAC_MODE_MBUF_RBD_CRPT_ENAB |
+			      RDMAC_MODE_MBUF_SBD_CRPT_ENAB;
+
 	/* If statement applies to 5705 and 5750 PCI devices only */
 	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
 	     tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) ||
@@ -6556,22 +6795,28 @@
 
 	/* Enable host coalescing bug fix */
 	if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) ||
-	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787))
+	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) ||
+	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) ||
+	    (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761))
 		val |= (1 << 29);
 
 	tw32_f(WDMAC_MODE, val);
 	udelay(40);
 
-	if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) {
-		val = tr32(TG3PCI_X_CAPS);
+	if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) {
+		u16 pcix_cmd;
+
+		pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
+				     &pcix_cmd);
 		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) {
-			val &= ~PCIX_CAPS_BURST_MASK;
-			val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT);
+			pcix_cmd &= ~PCI_X_CMD_MAX_READ;
+			pcix_cmd |= PCI_X_CMD_READ_2K;
 		} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
-			val &= ~(PCIX_CAPS_SPLIT_MASK | PCIX_CAPS_BURST_MASK);
-			val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT);
+			pcix_cmd &= ~(PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ);
+			pcix_cmd |= PCI_X_CMD_READ_2K;
 		}
-		tw32(TG3PCI_X_CAPS, val);
+		pci_write_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
+				      pcix_cmd);
 	}
 
 	tw32_f(RDMAC_MODE, rdmac_mode);
@@ -6580,7 +6825,13 @@
 	tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE);
 	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
 		tw32(MBFREE_MODE, MBFREE_MODE_ENABLE);
-	tw32(SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+		tw32(SNDDATAC_MODE,
+		     SNDDATAC_MODE_ENABLE | SNDDATAC_MODE_CDELAY);
+	else
+		tw32(SNDDATAC_MODE, SNDDATAC_MODE_ENABLE);
+
 	tw32(SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE);
 	tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB);
 	tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ);
@@ -6607,7 +6858,8 @@
 	udelay(100);
 
 	tp->rx_mode = RX_MODE_ENABLE;
-	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
 		tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE;
 
 	tw32_f(MAC_RX_MODE, tp->rx_mode);
@@ -6737,6 +6989,11 @@
 		break;
 	};
 
+	if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+		/* Write our heartbeat update interval to APE. */
+		tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS,
+				APE_HOST_HEARTBEAT_INT_DISABLE);
+
 	tg3_write_sig_post_reset(tp, RESET_KIND_INIT);
 
 	return 0;
@@ -7104,6 +7361,10 @@
 		} else if (pci_enable_msi(tp->pdev) == 0) {
 			u32 msi_mode;
 
+			/* Hardware bug - MSI won't work if INTX disabled. */
+			if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
+				pci_intx(tp->pdev, 1);
+
 			msi_mode = tr32(MSGINT_MODE);
 			tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE);
 			tp->tg3_flags2 |= TG3_FLG2_USING_MSI;
@@ -7120,6 +7381,8 @@
 		return err;
 	}
 
+	napi_enable(&tp->napi);
+
 	tg3_full_lock(tp, 0);
 
 	err = tg3_init_hw(tp, 1);
@@ -7147,6 +7410,7 @@
 	tg3_full_unlock(tp);
 
 	if (err) {
+		napi_disable(&tp->napi);
 		free_irq(tp->pdev->irq, dev);
 		if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
 			pci_disable_msi(tp->pdev);
@@ -7172,6 +7436,8 @@
 
 			tg3_full_unlock(tp);
 
+			napi_disable(&tp->napi);
+
 			return err;
 		}
 
@@ -7433,6 +7699,7 @@
 {
 	struct tg3 *tp = netdev_priv(dev);
 
+	napi_disable(&tp->napi);
 	cancel_work_sync(&tp->reset_task);
 
 	netif_stop_queue(dev);
@@ -7968,7 +8235,7 @@
 	buf = data;
 	if (b_offset || odd_len) {
 		buf = kmalloc(len, GFP_KERNEL);
-		if (buf == 0)
+		if (!buf)
 			return -ENOMEM;
 		if (b_offset)
 			memcpy(buf, &start, 4);
@@ -8048,7 +8315,8 @@
 
 	tp->link_config.autoneg = cmd->autoneg;
 	if (cmd->autoneg == AUTONEG_ENABLE) {
-		tp->link_config.advertising = cmd->advertising;
+		tp->link_config.advertising = (cmd->advertising |
+					      ADVERTISED_Autoneg);
 		tp->link_config.speed = SPEED_INVALID;
 		tp->link_config.duplex = DUPLEX_INVALID;
 	} else {
@@ -8136,10 +8404,12 @@
 	}
 	if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
 	    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) {
-		if (value)
+		if (value) {
 			dev->features |= NETIF_F_TSO6;
-		else
-			dev->features &= ~NETIF_F_TSO6;
+			if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+				dev->features |= NETIF_F_TSO_ECN;
+		} else
+			dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN);
 	}
 	return ethtool_op_set_tso(dev, value);
 }
@@ -8317,7 +8587,9 @@
   	}
 
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
 		ethtool_op_set_tx_ipv6_csum(dev, data);
 	else
 		ethtool_op_set_tx_csum(dev, data);
@@ -8325,14 +8597,16 @@
 	return 0;
 }
 
-static int tg3_get_stats_count (struct net_device *dev)
+static int tg3_get_sset_count (struct net_device *dev, int sset)
 {
-	return TG3_NUM_STATS;
-}
-
-static int tg3_get_test_count (struct net_device *dev)
-{
-	return TG3_NUM_TEST;
+	switch (sset) {
+	case ETH_SS_TEST:
+		return TG3_NUM_TEST;
+	case ETH_SS_STATS:
+		return TG3_NUM_STATS;
+	default:
+		return -EOPNOTSUPP;
+	}
 }
 
 static void tg3_get_strings (struct net_device *dev, u32 stringset, u8 *buf)
@@ -8397,7 +8671,7 @@
 static int tg3_test_nvram(struct tg3 *tp)
 {
 	u32 *buf, csum, magic;
-	int i, j, err = 0, size;
+	int i, j, k, err = 0, size;
 
 	if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
 		return -EIO;
@@ -8451,7 +8725,6 @@
 		u8 data[NVRAM_SELFBOOT_DATA_SIZE];
 	       	u8 parity[NVRAM_SELFBOOT_DATA_SIZE];
 		u8 *buf8 = (u8 *) buf;
-		int j, k;
 
 		/* Separate the parity bits and the data bytes.  */
 		for (i = 0, j = 0, k = 0; i < NVRAM_SELFBOOT_HW_SIZE; i++) {
@@ -8812,7 +9085,9 @@
 
 	if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
 		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
 			mem_tbl = mem_tbl_5755;
 		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
 			mem_tbl = mem_tbl_5906;
@@ -9009,6 +9284,7 @@
 static int tg3_test_loopback(struct tg3 *tp)
 {
 	int err = 0;
+	u32 cpmuctrl = 0;
 
 	if (!netif_running(tp->dev))
 		return TG3_LOOPBACK_FAILED;
@@ -9017,8 +9293,40 @@
 	if (err)
 		return TG3_LOOPBACK_FAILED;
 
+	if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) {
+		int i;
+		u32 status;
+
+		tw32(TG3_CPMU_MUTEX_REQ, CPMU_MUTEX_REQ_DRIVER);
+
+		/* Wait for up to 40 microseconds to acquire lock. */
+		for (i = 0; i < 4; i++) {
+			status = tr32(TG3_CPMU_MUTEX_GNT);
+			if (status == CPMU_MUTEX_GNT_DRIVER)
+				break;
+			udelay(10);
+		}
+
+		if (status != CPMU_MUTEX_GNT_DRIVER)
+			return TG3_LOOPBACK_FAILED;
+
+		cpmuctrl = tr32(TG3_CPMU_CTRL);
+
+		/* Turn off power management based on link speed. */
+		tw32(TG3_CPMU_CTRL,
+		     cpmuctrl & ~CPMU_CTRL_LINK_SPEED_MODE);
+	}
+
 	if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK))
 		err |= TG3_MAC_LOOPBACK_FAILED;
+
+	if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) {
+		tw32(TG3_CPMU_CTRL, cpmuctrl);
+
+		/* Release the mutex */
+		tw32(TG3_CPMU_MUTEX_GNT, CPMU_MUTEX_GNT_DRIVER);
+	}
+
 	if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
 		if (tg3_run_loopback(tp, TG3_PHY_LOOPBACK))
 			err |= TG3_PHY_LOOPBACK_FAILED;
@@ -9257,21 +9565,16 @@
 	.set_pauseparam		= tg3_set_pauseparam,
 	.get_rx_csum		= tg3_get_rx_csum,
 	.set_rx_csum		= tg3_set_rx_csum,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
 	.set_tx_csum		= tg3_set_tx_csum,
-	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
-	.get_tso		= ethtool_op_get_tso,
 	.set_tso		= tg3_set_tso,
-	.self_test_count	= tg3_get_test_count,
 	.self_test		= tg3_self_test,
 	.get_strings		= tg3_get_strings,
 	.phys_id		= tg3_phys_id,
-	.get_stats_count	= tg3_get_stats_count,
 	.get_ethtool_stats	= tg3_get_ethtool_stats,
 	.get_coalesce		= tg3_get_coalesce,
 	.set_coalesce		= tg3_set_coalesce,
-	.get_perm_addr		= ethtool_op_get_perm_addr,
+	.get_sset_count		= tg3_get_sset_count,
 };
 
 static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
@@ -9529,6 +9832,81 @@
 	}
 }
 
+static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp)
+{
+	u32 nvcfg1, protect = 0;
+
+	nvcfg1 = tr32(NVRAM_CFG1);
+
+	/* NVRAM protection for TPM */
+	if (nvcfg1 & (1 << 27)) {
+		tp->tg3_flags2 |= TG3_FLG2_PROTECTED_NVRAM;
+		protect = 1;
+	}
+
+	nvcfg1 &= NVRAM_CFG1_5752VENDOR_MASK;
+	switch (nvcfg1) {
+		case FLASH_5761VENDOR_ATMEL_ADB021D:
+		case FLASH_5761VENDOR_ATMEL_ADB041D:
+		case FLASH_5761VENDOR_ATMEL_ADB081D:
+		case FLASH_5761VENDOR_ATMEL_ADB161D:
+		case FLASH_5761VENDOR_ATMEL_MDB021D:
+		case FLASH_5761VENDOR_ATMEL_MDB041D:
+		case FLASH_5761VENDOR_ATMEL_MDB081D:
+		case FLASH_5761VENDOR_ATMEL_MDB161D:
+			tp->nvram_jedecnum = JEDEC_ATMEL;
+			tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+			tp->tg3_flags2 |= TG3_FLG2_FLASH;
+			tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS;
+			tp->nvram_pagesize = 256;
+			break;
+		case FLASH_5761VENDOR_ST_A_M45PE20:
+		case FLASH_5761VENDOR_ST_A_M45PE40:
+		case FLASH_5761VENDOR_ST_A_M45PE80:
+		case FLASH_5761VENDOR_ST_A_M45PE16:
+		case FLASH_5761VENDOR_ST_M_M45PE20:
+		case FLASH_5761VENDOR_ST_M_M45PE40:
+		case FLASH_5761VENDOR_ST_M_M45PE80:
+		case FLASH_5761VENDOR_ST_M_M45PE16:
+			tp->nvram_jedecnum = JEDEC_ST;
+			tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+			tp->tg3_flags2 |= TG3_FLG2_FLASH;
+			tp->nvram_pagesize = 256;
+			break;
+	}
+
+	if (protect) {
+		tp->nvram_size = tr32(NVRAM_ADDR_LOCKOUT);
+	} else {
+		switch (nvcfg1) {
+			case FLASH_5761VENDOR_ATMEL_ADB161D:
+			case FLASH_5761VENDOR_ATMEL_MDB161D:
+			case FLASH_5761VENDOR_ST_A_M45PE16:
+			case FLASH_5761VENDOR_ST_M_M45PE16:
+				tp->nvram_size = 0x100000;
+				break;
+			case FLASH_5761VENDOR_ATMEL_ADB081D:
+			case FLASH_5761VENDOR_ATMEL_MDB081D:
+			case FLASH_5761VENDOR_ST_A_M45PE80:
+			case FLASH_5761VENDOR_ST_M_M45PE80:
+				tp->nvram_size = 0x80000;
+				break;
+			case FLASH_5761VENDOR_ATMEL_ADB041D:
+			case FLASH_5761VENDOR_ATMEL_MDB041D:
+			case FLASH_5761VENDOR_ST_A_M45PE40:
+			case FLASH_5761VENDOR_ST_M_M45PE40:
+				tp->nvram_size = 0x40000;
+				break;
+			case FLASH_5761VENDOR_ATMEL_ADB021D:
+			case FLASH_5761VENDOR_ATMEL_MDB021D:
+			case FLASH_5761VENDOR_ST_A_M45PE20:
+			case FLASH_5761VENDOR_ST_M_M45PE20:
+				tp->nvram_size = 0x20000;
+				break;
+		}
+	}
+}
+
 static void __devinit tg3_get_5906_nvram_info(struct tg3 *tp)
 {
 	tp->nvram_jedecnum = JEDEC_ATMEL;
@@ -9568,8 +9946,11 @@
 			tg3_get_5752_nvram_info(tp);
 		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
 			tg3_get_5755_nvram_info(tp);
-		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+			 GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
 			tg3_get_5787_nvram_info(tp);
+		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+			tg3_get_5761_nvram_info(tp);
 		else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
 			tg3_get_5906_nvram_info(tp);
 		else
@@ -9647,6 +10028,7 @@
 	if ((tp->tg3_flags & TG3_FLAG_NVRAM) &&
 	    (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
 	    (tp->tg3_flags2 & TG3_FLG2_FLASH) &&
+	   !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) &&
 	    (tp->nvram_jedecnum == JEDEC_ATMEL))
 
 		addr = ((addr / tp->nvram_pagesize) <<
@@ -9661,6 +10043,7 @@
 	if ((tp->tg3_flags & TG3_FLAG_NVRAM) &&
 	    (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
 	    (tp->tg3_flags2 & TG3_FLG2_FLASH) &&
+	   !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) &&
 	    (tp->nvram_jedecnum == JEDEC_ATMEL))
 
 		addr = ((addr >> ATMEL_AT45DB0X1B_PAGE_POS) *
@@ -9881,6 +10264,8 @@
 		if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) &&
 		    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755) &&
 		    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) &&
+		    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) &&
+		    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) &&
 		    (tp->nvram_jedecnum == JEDEC_ST) &&
 		    (nvram_cmd & NVRAM_CMD_FIRST)) {
 
@@ -10051,8 +10436,12 @@
 			tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT;
 			tp->tg3_flags2 |= TG3_FLG2_IS_NIC;
 		}
-		if (tr32(VCPU_CFGSHDW) & VCPU_CFGSHDW_ASPM_DBNC)
+		val = tr32(VCPU_CFGSHDW);
+		if (val & VCPU_CFGSHDW_ASPM_DBNC)
 			tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND;
+		if ((val & VCPU_CFGSHDW_WOL_ENABLE) &&
+		    (val & VCPU_CFGSHDW_WOL_MAGPKT))
+			tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
 		return;
 	}
 
@@ -10169,10 +10558,16 @@
 			if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
 				tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE;
 		}
+		if (nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE)
+			tp->tg3_flags3 |= TG3_FLG3_ENABLE_APE;
 		if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES &&
 		    !(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL))
 			tp->tg3_flags &= ~TG3_FLAG_WOL_CAP;
 
+		if (tp->tg3_flags & TG3_FLAG_WOL_CAP &&
+		    nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)
+			tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
+
 		if (cfg2 & (1 << 17))
 			tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING;
 
@@ -10201,7 +10596,8 @@
 	 * firwmare access to the PHY hardware.
 	 */
 	err = 0;
-	if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+	if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
+	    (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
 		hw_phy_id = hw_phy_id_masked = PHY_ID_INVALID;
 	} else {
 		/* Now read the physical PHY_ID from the chip and verify
@@ -10248,6 +10644,7 @@
 	}
 
 	if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) &&
+	    !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) &&
 	    !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
 		u32 bmsr, adv_reg, tg3_ctrl, mask;
 
@@ -10499,6 +10896,13 @@
 
 	tp->pci_chip_rev_id = (misc_ctrl_reg >>
 			       MISC_HOST_CTRL_CHIPREV_SHIFT);
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_USE_PROD_ID_REG) {
+		u32 prod_id_asic_rev;
+
+		pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV,
+				      &prod_id_asic_rev);
+		tp->pci_chip_rev_id = prod_id_asic_rev & PROD_ID_ASIC_REV_MASK;
+	}
 
 	/* Wrong chip ID in 5752 A0. This code can be removed later
 	 * as A0 is not in production.
@@ -10618,6 +11022,8 @@
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
 	    (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
 		tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
@@ -10637,6 +11043,8 @@
 
 		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
 		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
 		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
 			tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
 			tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
@@ -10654,6 +11062,8 @@
 	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
 	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755 &&
 	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
+	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 &&
 	    GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
 		tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE;
 
@@ -10694,10 +11104,20 @@
 				       cacheline_sz_reg);
 	}
 
+	if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
+	    (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
+		tp->pcix_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_PCIX);
+		if (!tp->pcix_cap) {
+			printk(KERN_ERR PFX "Cannot find PCI-X "
+					    "capability, aborting.\n");
+			return -EIO;
+		}
+	}
+
 	pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
 			      &pci_state_reg);
 
-	if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) {
+	if (tp->pcix_cap && (pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) {
 		tp->tg3_flags |= TG3_FLAG_PCIX_MODE;
 
 		/* If this is a 5700 BX chipset, and we are in PCI-X
@@ -10708,7 +11128,6 @@
 		 */
 		if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) {
 			u32 pm_reg;
-			u16 pci_cmd;
 
 			tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
 
@@ -10716,11 +11135,13 @@
 			 * space registers clobbered due to this bug.
 			 * So explicitly force the chip into D0 here.
 			 */
-			pci_read_config_dword(tp->pdev, TG3PCI_PM_CTRL_STAT,
+			pci_read_config_dword(tp->pdev,
+					      tp->pm_cap + PCI_PM_CTRL,
 					      &pm_reg);
 			pm_reg &= ~PCI_PM_CTRL_STATE_MASK;
 			pm_reg |= PCI_PM_CTRL_PME_ENABLE | 0 /* D0 */;
-			pci_write_config_dword(tp->pdev, TG3PCI_PM_CTRL_STAT,
+			pci_write_config_dword(tp->pdev,
+					       tp->pm_cap + PCI_PM_CTRL,
 					       pm_reg);
 
 			/* Also, force SERR#/PERR# in PCI command. */
@@ -10818,6 +11239,20 @@
 	 */
 	tg3_get_eeprom_hw_cfg(tp);
 
+	if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+		/* Allow reads and writes to the
+		 * APE register and memory space.
+		 */
+		pci_state_reg |= PCISTATE_ALLOW_APE_CTLSPC_WR |
+				 PCISTATE_ALLOW_APE_SHMEM_WR;
+		pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE,
+				       pci_state_reg);
+	}
+
+	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+		tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT;
+
 	/* Set up tp->grc_local_ctrl before calling tg3_set_power_state().
 	 * GPIO1 driven high will bring 5700's external PHY out of reset.
 	 * It is also used as eeprom write protect on LOMs.
@@ -10884,7 +11319,9 @@
 
 	if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
 		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) {
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
 			if (tp->pdev->device != PCI_DEVICE_ID_TIGON3_5756 &&
 			    tp->pdev->device != PCI_DEVICE_ID_TIGON3_5722)
 				tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
@@ -11027,6 +11464,8 @@
 	 */
 	if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
 		tp->dev->hard_start_xmit = tg3_start_xmit;
 	else
@@ -11047,11 +11486,6 @@
 	    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
 		tp->rx_std_max_post = 8;
 
-	/* By default, disable wake-on-lan.  User can change this
-	 * using ETHTOOL_SWOL.
-	 */
-	tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
-
 	if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND)
 		tp->pwrmgmt_thresh = tr32(PCIE_PWR_MGMT_THRESH) &
 				     PCIE_PWR_MGMT_L1_THRESH_MSK;
@@ -11648,8 +12082,10 @@
 	case PHY_ID_BCM5780:	return "5780";
 	case PHY_ID_BCM5755:	return "5755";
 	case PHY_ID_BCM5787:	return "5787";
+	case PHY_ID_BCM5784:	return "5784";
 	case PHY_ID_BCM5756:	return "5722/5756";
 	case PHY_ID_BCM5906:	return "5906";
+	case PHY_ID_BCM5761:	return "5761";
 	case PHY_ID_BCM8002:	return "8002/serdes";
 	case 0:			return "serdes";
 	default:		return "unknown";
@@ -11807,7 +12243,6 @@
 		goto err_out_free_res;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 #if TG3_VLAN_TAG_USED
@@ -11854,7 +12289,7 @@
 	INIT_WORK(&tp->reset_task, tg3_reset_task);
 
 	tp->regs = ioremap_nocache(tg3reg_base, tg3reg_len);
-	if (tp->regs == 0UL) {
+	if (!tp->regs) {
 		printk(KERN_ERR PFX "Cannot map device registers, "
 		       "aborting.\n");
 		err = -ENOMEM;
@@ -11874,9 +12309,8 @@
 	dev->set_mac_address = tg3_set_mac_addr;
 	dev->do_ioctl = tg3_ioctl;
 	dev->tx_timeout = tg3_tx_timeout;
-	dev->poll = tg3_poll;
+	netif_napi_add(dev, &tp->napi, tg3_poll, 64);
 	dev->ethtool_ops = &tg3_ethtool_ops;
-	dev->weight = 64;
 	dev->watchdog_timeo = TG3_TX_TIMEOUT;
 	dev->change_mtu = tg3_change_mtu;
 	dev->irq = pdev->irq;
@@ -11954,6 +12388,8 @@
 		if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
 		    (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906))
 			dev->features |= NETIF_F_TSO6;
+		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+			dev->features |= NETIF_F_TSO_ECN;
 	}
 
 
@@ -11978,7 +12414,6 @@
 	 */
 	if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) ||
 	    (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
-		pci_save_state(tp->pdev);
 		tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
 		tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
 	}
@@ -11995,7 +12430,9 @@
 	if ((tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) == 0) {
 		dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
 		if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
-		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
+		    GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
 			dev->features |= NETIF_F_IPV6_CSUM;
 
 		tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
@@ -12007,11 +12444,27 @@
 
 	tg3_init_coal(tp);
 
-	/* Now that we have fully setup the chip, save away a snapshot
-	 * of the PCI config space.  We need to restore this after
-	 * GRC_MISC_CFG core clock resets and some resume events.
-	 */
-	pci_save_state(tp->pdev);
+	if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+		if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
+			printk(KERN_ERR PFX "Cannot find proper PCI device "
+			       "base address for APE, aborting.\n");
+			err = -ENODEV;
+			goto err_out_iounmap;
+		}
+
+		tg3reg_base = pci_resource_start(pdev, 2);
+		tg3reg_len = pci_resource_len(pdev, 2);
+
+		tp->aperegs = ioremap_nocache(tg3reg_base, tg3reg_len);
+		if (tp->aperegs == 0UL) {
+			printk(KERN_ERR PFX "Cannot map APE registers, "
+			       "aborting.\n");
+			err = -ENOMEM;
+			goto err_out_iounmap;
+		}
+
+		tg3_ape_lock_init(tp);
+	}
 
 	pci_set_drvdata(pdev, dev);
 
@@ -12019,7 +12472,7 @@
 	if (err) {
 		printk(KERN_ERR PFX "Cannot register net device, "
 		       "aborting.\n");
-		goto err_out_iounmap;
+		goto err_out_apeunmap;
 	}
 
 	printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (%s) %s Ethernet ",
@@ -12052,6 +12505,12 @@
 
 	return 0;
 
+err_out_apeunmap:
+	if (tp->aperegs) {
+		iounmap(tp->aperegs);
+		tp->aperegs = NULL;
+	}
+
 err_out_iounmap:
 	if (tp->regs) {
 		iounmap(tp->regs);
@@ -12079,6 +12538,10 @@
 
 		flush_scheduled_work();
 		unregister_netdev(dev);
+		if (tp->aperegs) {
+			iounmap(tp->aperegs);
+			tp->aperegs = NULL;
+		}
 		if (tp->regs) {
 			iounmap(tp->regs);
 			tp->regs = NULL;
@@ -12096,6 +12559,12 @@
 	struct tg3 *tp = netdev_priv(dev);
 	int err;
 
+	/* PCI register 4 needs to be saved whether netif_running() or not.
+	 * MSI address and data need to be saved if using MSI and
+	 * netif_running().
+	 */
+	pci_save_state(pdev);
+
 	if (!netif_running(dev))
 		return 0;
 
@@ -12115,9 +12584,6 @@
 	tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
 	tg3_full_unlock(tp);
 
-	/* Save MSI address and data for resume.  */
-	pci_save_state(pdev);
-
 	err = tg3_set_power_state(tp, pci_choose_state(pdev, state));
 	if (err) {
 		tg3_full_lock(tp, 0);
@@ -12145,15 +12611,20 @@
 	struct tg3 *tp = netdev_priv(dev);
 	int err;
 
+	pci_restore_state(tp->pdev);
+
 	if (!netif_running(dev))
 		return 0;
 
-	pci_restore_state(tp->pdev);
-
 	err = tg3_set_power_state(tp, PCI_D0);
 	if (err)
 		return err;
 
+	/* Hardware bug - MSI won't work if INTX disabled. */
+	if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) &&
+	    (tp->tg3_flags2 & TG3_FLG2_USING_MSI))
+		pci_intx(tp->pdev, 1);
+
 	netif_device_attach(dev);
 
 	tg3_full_lock(tp, 0);
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index d84e75e..6dbdad2 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -57,32 +57,7 @@
 #define TG3PCI_IRQ_PIN			0x0000003d
 #define TG3PCI_MIN_GNT			0x0000003e
 #define TG3PCI_MAX_LAT			0x0000003f
-#define TG3PCI_X_CAPS			0x00000040
-#define  PCIX_CAPS_RELAXED_ORDERING	 0x00020000
-#define  PCIX_CAPS_SPLIT_MASK		 0x00700000
-#define  PCIX_CAPS_SPLIT_SHIFT		 20
-#define  PCIX_CAPS_BURST_MASK		 0x000c0000
-#define  PCIX_CAPS_BURST_SHIFT		 18
-#define  PCIX_CAPS_MAX_BURST_CPIOB	 2
-#define TG3PCI_PM_CAP_PTR		0x00000041
-#define TG3PCI_X_COMMAND		0x00000042
-#define TG3PCI_X_STATUS			0x00000044
-#define TG3PCI_PM_CAP_ID		0x00000048
-#define TG3PCI_VPD_CAP_PTR		0x00000049
-#define TG3PCI_PM_CAPS			0x0000004a
-#define TG3PCI_PM_CTRL_STAT		0x0000004c
-#define TG3PCI_BR_SUPP_EXT		0x0000004e
-#define TG3PCI_PM_DATA			0x0000004f
-#define TG3PCI_VPD_CAP_ID		0x00000050
-#define TG3PCI_MSI_CAP_PTR		0x00000051
-#define TG3PCI_VPD_ADDR_FLAG		0x00000052
-#define  VPD_ADDR_FLAG_WRITE		0x00008000
-#define TG3PCI_VPD_DATA			0x00000054
-#define TG3PCI_MSI_CAP_ID		0x00000058
-#define TG3PCI_NXT_CAP_PTR		0x00000059
-#define TG3PCI_MSI_CTRL			0x0000005a
-#define TG3PCI_MSI_ADDR_LOW		0x0000005c
-#define TG3PCI_MSI_ADDR_HIGH		0x00000060
+/* 0x40 --> 0x64 unused */
 #define TG3PCI_MSI_DATA			0x00000064
 /* 0x66 --> 0x68 unused */
 #define TG3PCI_MISC_HOST_CTRL		0x00000068
@@ -133,6 +108,7 @@
 #define  CHIPREV_ID_5752_A1		 0x6001
 #define  CHIPREV_ID_5714_A2		 0x9002
 #define  CHIPREV_ID_5906_A1		 0xc001
+#define  CHIPREV_ID_5784_A0		 0x5784000
 #define  GET_ASIC_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 12)
 #define   ASIC_REV_5700			 0x07
 #define   ASIC_REV_5701			 0x00
@@ -146,6 +122,9 @@
 #define   ASIC_REV_5755			 0x0a
 #define   ASIC_REV_5787			 0x0b
 #define   ASIC_REV_5906			 0x0c
+#define   ASIC_REV_USE_PROD_ID_REG	 0x0f
+#define   ASIC_REV_5784			 0x5784
+#define   ASIC_REV_5761			 0x5761
 #define  GET_CHIP_REV(CHIP_REV_ID)	((CHIP_REV_ID) >> 8)
 #define   CHIPREV_5700_AX		 0x70
 #define   CHIPREV_5700_BX		 0x71
@@ -213,6 +192,8 @@
 #define  PCISTATE_ROM_RETRY_ENABLE	 0x00000040
 #define  PCISTATE_FLAT_VIEW		 0x00000100
 #define  PCISTATE_RETRY_SAME_DMA	 0x00002000
+#define  PCISTATE_ALLOW_APE_CTLSPC_WR	 0x00010000
+#define  PCISTATE_ALLOW_APE_SHMEM_WR	 0x00020000
 #define TG3PCI_CLOCK_CTRL		0x00000074
 #define  CLOCK_CTRL_CORECLK_DISABLE	 0x00000200
 #define  CLOCK_CTRL_RXCLK_DISABLE	 0x00000400
@@ -239,7 +220,9 @@
 #define TG3PCI_DUAL_MAC_CTRL		0x000000b8
 #define  DUAL_MAC_CTRL_CH_MASK		 0x00000003
 #define  DUAL_MAC_CTRL_ID		 0x00000004
-/* 0xbc --> 0x100 unused */
+#define TG3PCI_PRODID_ASICREV		0x000000bc
+#define  PROD_ID_ASIC_REV_MASK		 0x0fffffff
+/* 0xc0 --> 0x100 unused */
 
 /* 0x100 --> 0x200 unused */
 
@@ -683,6 +666,7 @@
 #define SNDDATAC_MODE			0x00001000
 #define  SNDDATAC_MODE_RESET		 0x00000001
 #define  SNDDATAC_MODE_ENABLE		 0x00000002
+#define  SNDDATAC_MODE_CDELAY		 0x00000010
 /* 0x1004 --> 0x1400 unused */
 
 /* Send BD ring selector */
@@ -865,7 +849,20 @@
 #define  RCVLSC_MODE_ATTN_ENABLE	 0x00000004
 #define RCVLSC_STATUS			0x00003404
 #define  RCVLSC_STATUS_ERROR_ATTN	 0x00000004
-/* 0x3408 --> 0x3800 unused */
+/* 0x3408 --> 0x3600 unused */
+
+/* CPMU registers */
+#define TG3_CPMU_CTRL			0x00003600
+#define  CPMU_CTRL_LINK_IDLE_MODE	 0x00000200
+#define  CPMU_CTRL_LINK_AWARE_MODE	 0x00000400
+#define  CPMU_CTRL_LINK_SPEED_MODE	 0x00004000
+/* 0x3604 --> 0x365c unused */
+
+#define TG3_CPMU_MUTEX_REQ		0x0000365c
+#define  CPMU_MUTEX_REQ_DRIVER		 0x00001000
+#define TG3_CPMU_MUTEX_GNT		0x00003660
+#define  CPMU_MUTEX_GNT_DRIVER		 0x00001000
+/* 0x3664 --> 0x3800 unused */
 
 /* Mbuf cluster free registers */
 #define MBFREE_MODE			0x00003800
@@ -1045,7 +1042,10 @@
 #define  RDMAC_MODE_FIFOOREAD_ENAB	 0x00000100
 #define  RDMAC_MODE_LNGREAD_ENAB	 0x00000200
 #define  RDMAC_MODE_SPLIT_ENABLE	 0x00000800
+#define  RDMAC_MODE_BD_SBD_CRPT_ENAB	 0x00000800
 #define  RDMAC_MODE_SPLIT_RESET		 0x00001000
+#define  RDMAC_MODE_MBUF_RBD_CRPT_ENAB	 0x00001000
+#define  RDMAC_MODE_MBUF_SBD_CRPT_ENAB	 0x00002000
 #define  RDMAC_MODE_FIFO_SIZE_128	 0x00020000
 #define  RDMAC_MODE_FIFO_LONG_BURST	 0x00030000
 #define RDMAC_STATUS			0x00004804
@@ -1151,6 +1151,8 @@
 #define  VCPU_STATUS_DRV_RESET		 0x08000000
 
 #define VCPU_CFGSHDW			0x00005104
+#define  VCPU_CFGSHDW_WOL_ENABLE	 0x00000001
+#define  VCPU_CFGSHDW_WOL_MAGPKT	 0x00000004
 #define  VCPU_CFGSHDW_ASPM_DBNC		 0x00001000
 
 /* Mailboxes */
@@ -1474,6 +1476,22 @@
 #define  FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ	 0x03000002
 #define  FLASH_5787VENDOR_MICRO_EEPROM_64KHZ	 0x03000000
 #define  FLASH_5787VENDOR_MICRO_EEPROM_376KHZ	 0x02000000
+#define  FLASH_5761VENDOR_ATMEL_MDB021D	 0x00800003
+#define  FLASH_5761VENDOR_ATMEL_MDB041D	 0x00800000
+#define  FLASH_5761VENDOR_ATMEL_MDB081D	 0x00800002
+#define  FLASH_5761VENDOR_ATMEL_MDB161D	 0x00800001
+#define  FLASH_5761VENDOR_ATMEL_ADB021D	 0x00000003
+#define  FLASH_5761VENDOR_ATMEL_ADB041D	 0x00000000
+#define  FLASH_5761VENDOR_ATMEL_ADB081D	 0x00000002
+#define  FLASH_5761VENDOR_ATMEL_ADB161D	 0x00000001
+#define  FLASH_5761VENDOR_ST_M_M45PE20	 0x02800001
+#define  FLASH_5761VENDOR_ST_M_M45PE40	 0x02800000
+#define  FLASH_5761VENDOR_ST_M_M45PE80	 0x02800002
+#define  FLASH_5761VENDOR_ST_M_M45PE16	 0x02800003
+#define  FLASH_5761VENDOR_ST_A_M45PE20	 0x02000001
+#define  FLASH_5761VENDOR_ST_A_M45PE40	 0x02000000
+#define  FLASH_5761VENDOR_ST_A_M45PE80	 0x02000002
+#define  FLASH_5761VENDOR_ST_A_M45PE16	 0x02000003
 #define  NVRAM_CFG1_5752PAGE_SIZE_MASK	 0x70000000
 #define  FLASH_5752PAGE_SIZE_256	 0x00000000
 #define  FLASH_5752PAGE_SIZE_512	 0x10000000
@@ -1504,9 +1522,11 @@
 #define  ACCESS_ENABLE			 0x00000001
 #define  ACCESS_WR_ENABLE		 0x00000002
 #define NVRAM_WRITE1			0x00007028
-/* 0x702c --> 0x7400 unused */
+/* 0x702c unused */
 
-/* 0x7400 --> 0x7c00 unused */
+#define NVRAM_ADDR_LOCKOUT		0x00007030
+/* 0x7034 --> 0x7c00 unused */
+
 #define PCIE_TRANSACTION_CFG		0x00007c04
 #define PCIE_TRANS_CFG_1SHOT_MSI	 0x20000000
 #define PCIE_TRANS_CFG_LOM		 0x00000020
@@ -1552,6 +1572,7 @@
 #define  NIC_SRAM_DATA_CFG_MINI_PCI		 0x00001000
 #define  NIC_SRAM_DATA_CFG_FIBER_WOL		 0x00004000
 #define  NIC_SRAM_DATA_CFG_NO_GPIO2		 0x00100000
+#define  NIC_SRAM_DATA_CFG_APE_ENABLE		 0x00200000
 
 #define NIC_SRAM_DATA_VER			0x00000b5c
 #define  NIC_SRAM_DATA_VER_SHIFT		 16
@@ -1680,6 +1701,47 @@
 #define MII_TG3_TEST1_TRIM_EN		0x0010
 #define MII_TG3_TEST1_CRC_EN		0x8000
 
+/* APE registers.  Accessible through BAR1 */
+#define TG3_APE_EVENT			0x000c
+#define  APE_EVENT_1			 0x00000001
+#define TG3_APE_LOCK_REQ		0x002c
+#define  APE_LOCK_REQ_DRIVER		 0x00001000
+#define TG3_APE_LOCK_GRANT		0x004c
+#define  APE_LOCK_GRANT_DRIVER		 0x00001000
+#define TG3_APE_SEG_SIG			0x4000
+#define  APE_SEG_SIG_MAGIC		 0x41504521
+
+/* APE shared memory.  Accessible through BAR1 */
+#define TG3_APE_FW_STATUS		0x400c
+#define  APE_FW_STATUS_READY		 0x00000100
+#define TG3_APE_HOST_SEG_SIG		0x4200
+#define  APE_HOST_SEG_SIG_MAGIC		 0x484f5354
+#define TG3_APE_HOST_SEG_LEN		0x4204
+#define  APE_HOST_SEG_LEN_MAGIC		 0x0000001c
+#define TG3_APE_HOST_INIT_COUNT		0x4208
+#define TG3_APE_HOST_DRIVER_ID		0x420c
+#define  APE_HOST_DRIVER_ID_MAGIC	 0xf0035100
+#define TG3_APE_HOST_BEHAVIOR		0x4210
+#define  APE_HOST_BEHAV_NO_PHYLOCK	 0x00000001
+#define TG3_APE_HOST_HEARTBEAT_INT_MS	0x4214
+#define  APE_HOST_HEARTBEAT_INT_DISABLE	 0
+#define  APE_HOST_HEARTBEAT_INT_5SEC	 5000
+#define TG3_APE_HOST_HEARTBEAT_COUNT	0x4218
+
+#define TG3_APE_EVENT_STATUS		0x4300
+
+#define  APE_EVENT_STATUS_DRIVER_EVNT	 0x00000010
+#define  APE_EVENT_STATUS_STATE_CHNGE	 0x00000500
+#define  APE_EVENT_STATUS_STATE_START	 0x00010000
+#define  APE_EVENT_STATUS_STATE_UNLOAD	 0x00020000
+#define  APE_EVENT_STATUS_STATE_WOL	 0x00030000
+#define  APE_EVENT_STATUS_STATE_SUSPEND	 0x00040000
+#define  APE_EVENT_STATUS_EVENT_PENDING	 0x80000000
+
+/* APE convenience enumerations. */
+#define TG3_APE_LOCK_MEM                4
+
+
 /* There are two ways to manage the TX descriptors on the tigon3.
  * Either the descriptors are in host DMA'able memory, or they
  * exist only in the cards on-chip SRAM.  All 16 send bds are under
@@ -2155,6 +2217,7 @@
 	void				(*write32_mbox) (struct tg3 *, u32,
 							 u32);
 	void __iomem			*regs;
+	void __iomem			*aperegs;
 	struct net_device		*dev;
 	struct pci_dev			*pdev;
 
@@ -2176,6 +2239,7 @@
 	dma_addr_t			tx_desc_mapping;
 
 	/* begin "rx thread" cacheline section */
+	struct napi_struct		napi;
 	void				(*write32_rx_mbox) (struct tg3 *, u32,
 							    u32);
 	u32				rx_rcb_ptr;
@@ -2237,7 +2301,7 @@
 #define TG3_FLAG_JUMBO_RING_ENABLE	0x00800000
 #define TG3_FLAG_10_100_ONLY		0x01000000
 #define TG3_FLAG_PAUSE_AUTONEG		0x02000000
-
+#define TG3_FLAG_CPMU_PRESENT		0x04000000
 #define TG3_FLAG_40BIT_DMA_BUG		0x08000000
 #define TG3_FLAG_BROKEN_CHECKSUMS	0x10000000
 #define TG3_FLAG_SUPPORT_MSI		0x20000000
@@ -2279,6 +2343,9 @@
 #define TG3_FLG2_PHY_JITTER_BUG		0x20000000
 #define TG3_FLG2_NO_FWARE_REPORTED	0x40000000
 #define TG3_FLG2_PHY_ADJUST_TRIM	0x80000000
+	u32				tg3_flags3;
+#define TG3_FLG3_NO_NVRAM_ADDR_TRANS	0x00000001
+#define TG3_FLG3_ENABLE_APE		0x00000002
 
 	struct timer_list		timer;
 	u16				timer_counter;
@@ -2309,7 +2376,7 @@
 	u32				pwrmgmt_thresh;
 
 	/* PCI block */
-	u16				pci_chip_rev_id;
+	u32				pci_chip_rev_id;
 	u8				pci_cacheline_sz;
 	u8				pci_lat_timer;
 	u8				pci_hdr_type;
@@ -2317,6 +2384,7 @@
 
 	int				pm_cap;
 	int				msi_cap;
+	int				pcix_cap;
 
 	/* PHY info */
 	u32				phy_id;
@@ -2335,6 +2403,8 @@
 #define PHY_ID_BCM5755			0xbc050cc0
 #define PHY_ID_BCM5787			0xbc050ce0
 #define PHY_ID_BCM5756			0xbc050ed0
+#define PHY_ID_BCM5784			0xbc050fa0
+#define PHY_ID_BCM5761			0xbc050fd0
 #define PHY_ID_BCM5906			0xdc00ac40
 #define PHY_ID_BCM8002			0x60010140
 #define PHY_ID_INVALID			0xffffffff
@@ -2345,6 +2415,7 @@
 #define PHY_REV_BCM5411_X0		0x1 /* Found on Netgear GA302T */
 
 	u32				led_ctrl;
+	u32				pci_cmd;
 
 	char				board_part_number[24];
 	char				fw_ver[16];
@@ -2363,7 +2434,8 @@
 	 (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \
 	 (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \
 	 (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \
-	 (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM8002)
+	 (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM5761 || \
+	 (X) == PHY_ID_BCM8002)
 
 	struct tg3_hw_stats		*hw_stats;
 	dma_addr_t			stats_mapping;
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 74eb121..c99ce74 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -556,7 +556,6 @@
 		rc = -ENOMEM;
 		goto err_out_regions;
 	}
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	priv = netdev_priv(dev);
diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
index 9f1b6ab..7224d36 100644
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -156,7 +156,7 @@
 static void print_tx_state(struct net_device *dev)
 {
 
-	struct xl_private *xl_priv = (struct xl_private *)dev->priv ; 
+	struct xl_private *xl_priv = netdev_priv(dev);
 	struct xl_tx_desc *txd ; 
 	u8 __iomem *xl_mmio = xl_priv->xl_mmio ; 
 	int i ; 
@@ -179,7 +179,7 @@
 static void print_rx_state(struct net_device *dev)
 {
 
-	struct xl_private *xl_priv = (struct xl_private *)dev->priv ; 
+	struct xl_private *xl_priv = netdev_priv(dev);
 	struct xl_rx_desc *rxd ; 
 	u8 __iomem *xl_mmio = xl_priv->xl_mmio ; 
 	int i ; 
@@ -213,7 +213,7 @@
 
 static u16 xl_ee_read(struct net_device *dev, int ee_addr)
 { 
-    	struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+	struct xl_private *xl_priv = netdev_priv(dev);
 	u8 __iomem *xl_mmio = xl_priv->xl_mmio ; 
 
 	/* Wait for EEProm to not be busy */
@@ -245,7 +245,7 @@
 
 static void  xl_ee_write(struct net_device *dev, int ee_addr, u16 ee_value) 
 {
-    	struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+	struct xl_private *xl_priv = netdev_priv(dev);
 	u8 __iomem *xl_mmio = xl_priv->xl_mmio ; 
 
 	/* Wait for EEProm to not be busy */
@@ -305,11 +305,11 @@
 		pci_release_regions(pdev) ; 
 		return -ENOMEM ; 
 	} 
-	xl_priv = dev->priv ; 
+	xl_priv = netdev_priv(dev);
 
 #if XL_DEBUG  
 	printk("pci_device: %p, dev:%p, dev->priv: %p, ba[0]: %10x, ba[1]:%10x\n", 
-		pdev, dev, dev->priv, (unsigned int)pdev->resource[0].start, (unsigned int)pdev->resource[1].start) ;  
+		pdev, dev, netdev_priv(dev), (unsigned int)pdev->resource[0].start, (unsigned int)pdev->resource[1].start);
 #endif 
 
 	dev->irq=pdev->irq;
@@ -344,7 +344,6 @@
 	dev->set_multicast_list=&xl_set_rx_mode;
 	dev->get_stats=&xl_get_stats ;
 	dev->set_mac_address=&xl_set_mac_address ; 
-	SET_MODULE_OWNER(dev); 
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	pci_set_drvdata(pdev,dev) ; 
@@ -365,7 +364,7 @@
 
 static int __devinit xl_init(struct net_device *dev) 
 {
-    	struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+	struct xl_private *xl_priv = netdev_priv(dev);
 
 	printk(KERN_INFO "%s \n", version);
 	printk(KERN_INFO "%s: I/O at %hx, MMIO at %p, using irq %d\n",
@@ -385,7 +384,7 @@
 
 static int xl_hw_reset(struct net_device *dev) 
 { 
-    	struct xl_private *xl_priv = (struct xl_private *)dev->priv ;
+	struct xl_private *xl_priv = netdev_priv(dev);
 	u8 __iomem *xl_mmio = xl_priv->xl_mmio ; 
 	unsigned long t ; 
 	u16 i ; 
@@ -568,7 +567,7 @@
 
 static int xl_open(struct net_device *dev) 
 {
-	struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+	struct xl_private *xl_priv=netdev_priv(dev);
 	u8 __iomem *xl_mmio = xl_priv->xl_mmio ; 
 	u8 i ; 
 	u16 hwaddr[3] ; /* Should be u8[6] but we get word return values */
@@ -641,14 +640,14 @@
 	 * Now to set up the Rx and Tx buffer structures
 	 */
 	/* These MUST be on 8 byte boundaries */
-	xl_priv->xl_tx_ring = kmalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL) ; 
+	xl_priv->xl_tx_ring = kzalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL);
 	if (xl_priv->xl_tx_ring == NULL) {
 		printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n",
 				     dev->name);
 		free_irq(dev->irq,dev);
 		return -ENOMEM;
 	}
-	xl_priv->xl_rx_ring = kmalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL) ; 
+	xl_priv->xl_rx_ring = kzalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL);
 	if (xl_priv->xl_tx_ring == NULL) {
 		printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n",
 				     dev->name);
@@ -656,8 +655,6 @@
 		kfree(xl_priv->xl_tx_ring);
 		return -ENOMEM;
 	}
-	memset(xl_priv->xl_tx_ring,0,sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) ; 
-	memset(xl_priv->xl_rx_ring,0,sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) ; 
 
 	 /* Setup Rx Ring */
 	 for (i=0 ; i < XL_RX_RING_SIZE ; i++) { 
@@ -726,7 +723,7 @@
 
 static int xl_open_hw(struct net_device *dev) 
 { 
-	struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+	struct xl_private *xl_priv=netdev_priv(dev);
 	u8 __iomem *xl_mmio = xl_priv->xl_mmio ; 
 	u16 vsoff ;
 	char ver_str[33];  
@@ -875,7 +872,7 @@
 
 static void adv_rx_ring(struct net_device *dev) /* Advance rx_ring, cut down on bloat in xl_rx */ 
 {
-	struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+	struct xl_private *xl_priv=netdev_priv(dev);
 	int prev_ring_loc ; 
 
 	prev_ring_loc = (xl_priv->rx_ring_tail + XL_RX_RING_SIZE - 1) & (XL_RX_RING_SIZE - 1);
@@ -890,7 +887,7 @@
 
 static void xl_rx(struct net_device *dev)
 {
-	struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+	struct xl_private *xl_priv=netdev_priv(dev);
 	u8 __iomem * xl_mmio = xl_priv->xl_mmio ; 
 	struct sk_buff *skb, *skb2 ; 
 	int frame_length = 0, copy_len = 0  ; 	
@@ -997,7 +994,7 @@
 
 static void xl_reset(struct net_device *dev) 
 {
-	struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+	struct xl_private *xl_priv=netdev_priv(dev);
 	u8 __iomem * xl_mmio = xl_priv->xl_mmio ; 
 	unsigned long t; 
 
@@ -1020,7 +1017,7 @@
 
 static void xl_freemem(struct net_device *dev) 
 {
-	struct xl_private *xl_priv=(struct xl_private *)dev->priv ; 
+	struct xl_private *xl_priv=netdev_priv(dev);
 	int i ; 
 
 	for (i=0;i<XL_RX_RING_SIZE;i++) {
@@ -1044,15 +1041,10 @@
 static irqreturn_t xl_interrupt(int irq, void *dev_id) 
 {
 	struct net_device *dev = (struct net_device *)dev_id;
- 	struct xl_private *xl_priv =(struct xl_private *)dev->priv;
+	struct xl_private *xl_priv =netdev_priv(dev);
 	u8 __iomem * xl_mmio = xl_priv->xl_mmio ; 
 	u16 intstatus, macstatus  ;
 
-	if (!dev) { 
-		printk(KERN_WARNING "Device structure dead, aaahhhh !\n") ;
-		return IRQ_NONE; 
-	}
-
 	intstatus = readw(xl_mmio + MMIO_INTSTATUS) ;  
 
 	if (!(intstatus & 1)) /* We didn't generate the interrupt */
@@ -1171,7 +1163,7 @@
 	
 static int xl_xmit(struct sk_buff *skb, struct net_device *dev) 
 {
-	struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+	struct xl_private *xl_priv=netdev_priv(dev);
 	struct xl_tx_desc *txd ; 
 	int tx_head, tx_tail, tx_prev ; 
 	unsigned long flags ; 	
@@ -1232,7 +1224,7 @@
 
 static void xl_dn_comp(struct net_device *dev) 
 {
-	struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+	struct xl_private *xl_priv=netdev_priv(dev);
 	u8 __iomem * xl_mmio = xl_priv->xl_mmio ; 
 	struct xl_tx_desc *txd ; 
 
@@ -1268,7 +1260,7 @@
 
 static int xl_close(struct net_device *dev) 
 {
-	struct xl_private *xl_priv = (struct xl_private *) dev->priv ; 
+	struct xl_private *xl_priv = netdev_priv(dev);
 	u8 __iomem * xl_mmio = xl_priv->xl_mmio ; 
 	unsigned long t ; 
 
@@ -1366,7 +1358,7 @@
 
 static void xl_set_rx_mode(struct net_device *dev) 
 {
-	struct xl_private *xl_priv = (struct xl_private *) dev->priv ; 
+	struct xl_private *xl_priv = netdev_priv(dev);
 	struct dev_mc_list *dmi ; 
 	unsigned char dev_mc_address[4] ; 
 	u16 options ; 
@@ -1407,7 +1399,7 @@
 
 static void xl_srb_bh(struct net_device *dev) 
 { 
-	struct xl_private *xl_priv = (struct xl_private *) dev->priv ; 
+	struct xl_private *xl_priv = netdev_priv(dev);
 	u8 __iomem * xl_mmio = xl_priv->xl_mmio ; 
 	u8 srb_cmd, ret_code ; 
 	int i ; 
@@ -1476,14 +1468,14 @@
 
 static struct net_device_stats * xl_get_stats(struct net_device *dev)
 {
-	struct xl_private *xl_priv = (struct xl_private *) dev->priv ;
+	struct xl_private *xl_priv = netdev_priv(dev);
 	return (struct net_device_stats *) &xl_priv->xl_stats; 
 }
 
 static int xl_set_mac_address (struct net_device *dev, void *addr) 
 {
 	struct sockaddr *saddr = addr ; 
-	struct xl_private *xl_priv = (struct xl_private *)dev->priv ; 
+	struct xl_private *xl_priv = netdev_priv(dev);
 
 	if (netif_running(dev)) { 
 		printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; 
@@ -1504,7 +1496,7 @@
 
 static void xl_arb_cmd(struct net_device *dev)
 {
-	struct xl_private *xl_priv = (struct xl_private *) dev->priv;
+	struct xl_private *xl_priv = netdev_priv(dev);
 	u8 __iomem * xl_mmio = xl_priv->xl_mmio ; 
 	u8 arb_cmd ; 
 	u16 lan_status, lan_status_diff ; 
@@ -1632,7 +1624,7 @@
 
 static void xl_asb_cmd(struct net_device *dev)
 {
-	struct xl_private *xl_priv = (struct xl_private *) dev->priv ; 
+	struct xl_private *xl_priv = netdev_priv(dev);
 	u8 __iomem * xl_mmio = xl_priv->xl_mmio ; 
 
 	if (xl_priv->asb_queued == 1) 
@@ -1663,7 +1655,7 @@
  */
 static void xl_asb_bh(struct net_device *dev) 
 {
-	struct xl_private *xl_priv = (struct xl_private *) dev->priv ; 
+	struct xl_private *xl_priv = netdev_priv(dev);
 	u8 __iomem * xl_mmio = xl_priv->xl_mmio ; 
 	u8 ret_code ; 
 
@@ -1691,7 +1683,7 @@
 
 static void xl_srb_cmd(struct net_device *dev, int srb_cmd) 
 {
-	struct xl_private *xl_priv = (struct xl_private *) dev->priv ; 
+	struct xl_private *xl_priv = netdev_priv(dev);
 	u8 __iomem * xl_mmio = xl_priv->xl_mmio ; 
 
 	switch (srb_cmd) { 
@@ -1748,7 +1740,7 @@
 
 static void xl_wait_misr_flags(struct net_device *dev) 
 {
-	struct xl_private *xl_priv = (struct xl_private *) dev->priv ; 
+	struct xl_private *xl_priv = netdev_priv(dev);
 	u8 __iomem * xl_mmio = xl_priv->xl_mmio ; 
 	
 	int i  ; 
@@ -1773,7 +1765,7 @@
 
 static int xl_change_mtu(struct net_device *dev, int mtu) 
 {
-	struct xl_private *xl_priv = (struct xl_private *) dev->priv;
+	struct xl_private *xl_priv = netdev_priv(dev);
 	u16 max_mtu ; 
 
 	if (xl_priv->xl_ring_speed == 4)
@@ -1795,7 +1787,7 @@
 static void __devexit xl_remove_one (struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct xl_private *xl_priv=(struct xl_private *)dev->priv;
+	struct xl_private *xl_priv=netdev_priv(dev);
 	
 	unregister_netdev(dev);
 	iounmap(xl_priv->xl_mmio) ; 
diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c
index 1bdd3be..124cfd4 100644
--- a/drivers/net/tokenring/abyss.c
+++ b/drivers/net/tokenring/abyss.c
@@ -97,8 +97,9 @@
 	static int versionprinted;
 	struct net_device *dev;
 	struct net_local *tp;
-	int i, ret, pci_irq_line;
+	int ret, pci_irq_line;
 	unsigned long pci_ioaddr;
+	DECLARE_MAC_BUF(mac);
 	
 	if (versionprinted++ == 0)
 		printk("%s", version);
@@ -116,8 +117,6 @@
 	if (!dev)
 		return -ENOMEM;
 
-	SET_MODULE_OWNER(dev);
-
 	if (!request_region(pci_ioaddr, ABYSS_IO_EXTENT, dev->name)) {
 		ret = -EBUSY;
 		goto err_out_trdev;
@@ -147,12 +146,9 @@
 	}
 
 	abyss_read_eeprom(dev);
-		
-	printk("%s:    Ring Station Address: ", dev->name);
-	printk("%2.2x", dev->dev_addr[0]);
-	for (i = 1; i < 6; i++)
-		printk(":%2.2x", dev->dev_addr[i]);
-	printk("\n");
+
+	printk("%s:    Ring Station Address: %s\n",
+	       dev->name, print_mac(mac, dev->dev_addr));
 
 	tp = netdev_priv(dev);
 	tp->setnselout = abyss_setnselout_pins;
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 1e8958e..e494c63 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -116,9 +116,6 @@
 #define ENABLE_PAGING 1		
 #endif
 
-#define FALSE 0
-#define TRUE (!FALSE)
-
 /* changes the output format of driver initialization */
 #define TR_VERBOSE	0
 
@@ -327,7 +324,7 @@
 	release_region(dev->base_addr, IBMTR_IO_EXTENT);
 
 	{ 
-		struct tok_info *ti = (struct tok_info *) dev->priv;
+		struct tok_info *ti = netdev_priv(dev);
 		iounmap(ti->mmio);
 		iounmap(ti->sram_virt);
 	}
@@ -384,7 +381,7 @@
 
 	unsigned char segment, intr=0, irq=0, i, j, cardpresent=NOTOK, temp=0;
 	void __iomem * t_mmio = NULL;
-	struct tok_info *ti = dev->priv;
+	struct tok_info *ti = netdev_priv(dev);
 	void __iomem *cd_chanid;
 	unsigned char *tchanid, ctemp;
 #ifndef PCMCIA
@@ -392,6 +389,7 @@
         unsigned long timeout;
 	static int version_printed;
 #endif
+	DECLARE_MAC_BUF(mac);
 
 	/*    Query the adapter PIO base port which will return
 	 *    indication of where MMIO was placed. We also have a
@@ -705,9 +703,8 @@
 		channel_def[cardpresent - 1], adapter_def(ti->adapter_type));
 	DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n",
 			irq, PIOaddr, ti->mapped_ram_size / 2);
-	DPRINTK("Hardware address : %02X:%02X:%02X:%02X:%02X:%02X\n",
-		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+	DPRINTK("Hardware address : %s\n",
+		print_mac(mac, dev->dev_addr));
 	if (ti->page_mask)
 		DPRINTK("Shared RAM paging enabled. "
 			"Page size: %uK Shared Ram size %dK\n",
@@ -823,7 +820,7 @@
 
 static int __devinit trdev_init(struct net_device *dev)
 {
-	struct tok_info *ti = (struct tok_info *) dev->priv;
+	struct tok_info *ti = netdev_priv(dev);
 
 	SET_PAGE(ti->srb_page);
         ti->open_failure = NO    ;
@@ -846,7 +843,7 @@
 	unsigned long i;
 
 	PIOaddr = dev->base_addr;
-	ti = (struct tok_info *) dev->priv;
+	ti = netdev_priv(dev);
 	/* Special processing for first interrupt after reset */
 	ti->do_tok_int = FIRST_INT;
 	/* Reset adapter */
@@ -868,7 +865,7 @@
 /*****************************************************************************/
 static int tok_open(struct net_device *dev)
 {
-	struct tok_info *ti = (struct tok_info *) dev->priv;
+	struct tok_info *ti = netdev_priv(dev);
 	int i;
 
 	/*the case we were left in a failure state during a previous open */
@@ -927,7 +924,7 @@
 	struct tok_info *ti;
 	int i;
 
-	ti = (struct tok_info *) dev->priv;
+	ti = netdev_priv(dev);
 	SET_PAGE(ti->init_srb_page); 
 	writeb(~SRB_RESP_INT, ti->mmio + ACA_OFFSET + ACA_RESET + ISRP_ODD);
 	for (i = 0; i < sizeof(struct dir_open_adapter); i++)
@@ -962,7 +959,7 @@
 static void open_sap(unsigned char type, struct net_device *dev)
 {
 	int i;
-	struct tok_info *ti = (struct tok_info *) dev->priv;
+	struct tok_info *ti = netdev_priv(dev);
 
 	SET_PAGE(ti->srb_page);
 	for (i = 0; i < sizeof(struct dlc_open_sap); i++)
@@ -986,7 +983,7 @@
 
 static void tok_set_multicast_list(struct net_device *dev)
 {
-	struct tok_info *ti = (struct tok_info *) dev->priv;
+	struct tok_info *ti = netdev_priv(dev);
 	struct dev_mc_list *mclist;
 	unsigned char address[4];
 
@@ -1029,7 +1026,7 @@
 {
 	struct tok_info *ti;
 	unsigned long flags;
-	ti = (struct tok_info *) dev->priv;
+	ti = netdev_priv(dev);
 
         netif_stop_queue(dev);
 
@@ -1051,7 +1048,7 @@
 
 static int tok_close(struct net_device *dev)
 {
-	struct tok_info *ti = (struct tok_info *) dev->priv;
+	struct tok_info *ti = netdev_priv(dev);
 
 	/* Important for PCMCIA hot unplug, otherwise, we'll pull the card, */
 	/* unloading the module from memory, and then if a timer pops, ouch */
@@ -1094,7 +1091,7 @@
 
 static void dir_open_adapter (struct net_device *dev)
 {
-        struct tok_info *ti = (struct tok_info *) dev->priv;
+        struct tok_info *ti = netdev_priv(dev);
         unsigned char ret_code;
         __u16 err;
 
@@ -1179,7 +1176,7 @@
 #if TR_VERBOSE
 	DPRINTK("Int from tok_driver, dev : %p irq%d\n", dev,irq);
 #endif
-	ti = (struct tok_info *) dev->priv;
+	ti = netdev_priv(dev);
 	if (ti->sram_phys & 1)
 		return IRQ_NONE;         /* PCMCIA card extraction flag */
 	spin_lock(&(ti->lock));
@@ -1498,7 +1495,7 @@
 	struct tok_info *ti;
         unsigned char init_status; /*BMS 12/2000*/
 
-	ti = (struct tok_info *) dev->priv;
+	ti = netdev_priv(dev);
 
 	ti->do_tok_int = NOT_FIRST;
 
@@ -1542,7 +1539,7 @@
 	ti->ring_speed = init_status & 0x01 ? 16 : 4;
 	DPRINTK("Initial interrupt : %d Mbps, shared RAM base %08x.\n",
 				ti->ring_speed, (unsigned int)dev->mem_start);
-	ti->auto_speedsave=readb(ti->init_srb+INIT_STATUS_2_OFST)&4?TRUE:FALSE;
+	ti->auto_speedsave = (readb(ti->init_srb+INIT_STATUS_2_OFST) & 4) != 0;
 
         if (ti->open_mode == MANUAL)	wake_up(&ti->wait_for_reset);
 	else				tok_open_adapter((unsigned long)dev);
@@ -1560,7 +1557,7 @@
 
 static void tr_tx(struct net_device *dev)
 {
-	struct tok_info *ti = (struct tok_info *) dev->priv;
+	struct tok_info *ti = netdev_priv(dev);
 	struct trh_hdr *trhdr = (struct trh_hdr *) ti->current_skb->data;
 	unsigned int hdr_len;
 	__u32 dhb=0,dhb_base;
@@ -1674,7 +1671,7 @@
 
 static void tr_rx(struct net_device *dev)
 {
-	struct tok_info *ti = (struct tok_info *) dev->priv;
+	struct tok_info *ti = netdev_priv(dev);
 	__u32 rbuffer;
 	void __iomem *rbuf, *rbufdata, *llc;
 	__u8 rbuffer_page = 0;
@@ -1742,18 +1739,20 @@
 	if (!IPv4_p) {
 
 		void __iomem *trhhdr = rbuf + offsetof(struct rec_buf, data);
-
+		u8 saddr[6];
+		u8 daddr[6];
+		DECLARE_MAC_BUF(mac);
+		DECLARE_MAC_BUF(mac2);
+		int i;
+		for (i = 0 ; i < 6 ; i++)
+			saddr[i] = readb(trhhdr + SADDR_OFST + i);
+		for (i = 0 ; i < 6 ; i++)
+			daddr[i] = readb(trhhdr + DADDR_OFST + i);
 		DPRINTK("Probably non-IP frame received.\n");
 		DPRINTK("ssap: %02X dsap: %02X "
-			"saddr: %02X:%02X:%02X:%02X:%02X:%02X "
-			"daddr: %02X:%02X:%02X:%02X:%02X:%02X\n",
+			"saddr: %s daddr: %$s\n",
 			readb(llc + SSAP_OFST), readb(llc + DSAP_OFST),
-			readb(trhhdr+SADDR_OFST), readb(trhhdr+ SADDR_OFST+1),
-			readb(trhhdr+SADDR_OFST+2), readb(trhhdr+SADDR_OFST+3),
-			readb(trhhdr+SADDR_OFST+4), readb(trhhdr+SADDR_OFST+5),
-			readb(trhhdr+DADDR_OFST), readb(trhhdr+DADDR_OFST + 1),
-			readb(trhhdr+DADDR_OFST+2), readb(trhhdr+DADDR_OFST+3),
-			readb(trhhdr+DADDR_OFST+4), readb(trhhdr+DADDR_OFST+5));
+			print_mac(mac, saddr), print_mac(mac2, daddr));
 	}
 #endif
 
@@ -1846,7 +1845,7 @@
 void tok_rerun(unsigned long dev_addr){
 
 	struct net_device *dev = (struct net_device *)dev_addr;
-	struct tok_info *ti = (struct tok_info *) dev->priv;
+	struct tok_info *ti = netdev_priv(dev);
 
 	if ( ti->open_action == RESTART){
 		ti->do_tok_int = FIRST_INT;
@@ -1868,7 +1867,7 @@
 {
 	struct tok_info *ti;
 
-	ti = (struct tok_info *) dev->priv;
+	ti = netdev_priv(dev);
 
 	ti->readlog_pending = 0;
 	SET_PAGE(ti->srb_page);
@@ -1891,7 +1890,7 @@
 {
 
 	struct tok_info *toki;
-	toki = (struct tok_info *) dev->priv;
+	toki = netdev_priv(dev);
 	return (struct net_device_stats *) &toki->tr_stats;
 }
 
@@ -1899,7 +1898,7 @@
 
 static int ibmtr_change_mtu(struct net_device *dev, int mtu)
 {
-	struct tok_info *ti = (struct tok_info *) dev->priv;
+	struct tok_info *ti = netdev_priv(dev);
 
 	if (ti->ring_speed == 16 && mtu > ti->maxmtu16)
 		return -EINVAL;
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index 5d849c0..47d84cd 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -123,6 +123,7 @@
 #include <linux/bitops.h>
 #include <linux/jiffies.h>
 
+#include <net/net_namespace.h>
 #include <net/checksum.h>
 
 #include <asm/io.h>
@@ -244,13 +245,12 @@
 		return -ENOMEM;
 	}
 
-	SET_MODULE_OWNER(dev);
-	streamer_priv = dev->priv;
+	streamer_priv = netdev_priv(dev);
 
 #if STREAMER_NETWORK_MONITOR
 #ifdef CONFIG_PROC_FS
 	if (!dev_streamer)
-		create_proc_read_entry("net/streamer_tr", 0, 0,
+		create_proc_read_entry("streamer_tr", 0, init_net.proc_net,
 					streamer_proc_info, NULL); 
 	streamer_priv->next = dev_streamer;
 	dev_streamer = streamer_priv;
@@ -404,7 +404,7 @@
 		return;
 	}
 
-	streamer_priv=dev->priv;
+	streamer_priv=netdev_priv(dev);
 	if (streamer_priv == NULL) {
 		printk(KERN_ERR "lanstreamer::streamer_remove_one, ERROR dev->priv is NULL\n");
 		return;
@@ -423,7 +423,7 @@
 			}
 		}
 		if (!dev_streamer)
-			remove_proc_entry("net/streamer_tr", NULL);
+			remove_proc_entry("streamer_tr", init_net.proc_net);
 	}
 #endif
 #endif
@@ -447,8 +447,11 @@
 	unsigned int uaa_addr;
 	struct sk_buff *skb = NULL;
 	__u16 misr;
+#if STREAMER_DEBUG
+	DECLARE_MAC_BUF(mac);
+#endif
 
-	streamer_priv = (struct streamer_private *) dev->priv;
+	streamer_priv = netdev_priv(dev);
 	streamer_mmio = streamer_priv->streamer_mmio;
 
 	writew(readw(streamer_mmio + BCTL) | BCTL_SOFTRESET, streamer_mmio + BCTL);
@@ -575,11 +578,8 @@
 			dev->dev_addr[i+1]= addr & 0xff;
 		}
 #if STREAMER_DEBUG
-		printk("Adapter address: ");
-		for (i = 0; i < 6; i++) {
-			printk("%02x:", dev->dev_addr[i]);
-		}
-		printk("\n");
+		printk("Adapter address: %s\n",
+		       print_mac(mac, dev->dev_addr));
 #endif
 	}
 	return 0;
@@ -587,7 +587,7 @@
 
 static int streamer_open(struct net_device *dev)
 {
-	struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
+	struct streamer_private *streamer_priv = netdev_priv(dev);
 	__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
 	unsigned long flags;
 	char open_error[255];
@@ -904,7 +904,7 @@
 static void streamer_rx(struct net_device *dev)
 {
 	struct streamer_private *streamer_priv =
-	    (struct streamer_private *) dev->priv;
+	    netdev_priv(dev);
 	__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
 	struct streamer_rx_desc *rx_desc;
 	int rx_ring_last_received, length, frame_length, buffer_cnt = 0;
@@ -1029,7 +1029,7 @@
 {
 	struct net_device *dev = (struct net_device *) dev_id;
 	struct streamer_private *streamer_priv =
-	    (struct streamer_private *) dev->priv;
+	    netdev_priv(dev);
 	__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
 	__u16 sisr;
 	__u16 misr;
@@ -1152,7 +1152,7 @@
 static int streamer_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	struct streamer_private *streamer_priv =
-	    (struct streamer_private *) dev->priv;
+	    netdev_priv(dev);
 	__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
 	unsigned long flags ;
 
@@ -1203,7 +1203,7 @@
 static int streamer_close(struct net_device *dev)
 {
 	struct streamer_private *streamer_priv =
-	    (struct streamer_private *) dev->priv;
+	    netdev_priv(dev);
 	__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
 	unsigned long flags;
 	int i;
@@ -1269,7 +1269,7 @@
 static void streamer_set_rx_mode(struct net_device *dev)
 {
 	struct streamer_private *streamer_priv =
-	    (struct streamer_private *) dev->priv;
+	    netdev_priv(dev);
 	__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
 	__u8 options = 0;
 	struct dev_mc_list *dmi;
@@ -1328,7 +1328,7 @@
 
 static void streamer_srb_bh(struct net_device *dev)
 {
-	struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
+	struct streamer_private *streamer_priv = netdev_priv(dev);
 	__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
 	__u16 srb_word;
 
@@ -1493,14 +1493,14 @@
 static struct net_device_stats *streamer_get_stats(struct net_device *dev)
 {
 	struct streamer_private *streamer_priv;
-	streamer_priv = (struct streamer_private *) dev->priv;
+	streamer_priv = netdev_priv(dev);
 	return (struct net_device_stats *) &streamer_priv->streamer_stats;
 }
 
 static int streamer_set_mac_address(struct net_device *dev, void *addr)
 {
 	struct sockaddr *saddr = addr;
-	struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
+	struct streamer_private *streamer_priv = netdev_priv(dev);
 
 	if (netif_running(dev)) 
 	{
@@ -1525,7 +1525,7 @@
 static void streamer_arb_cmd(struct net_device *dev)
 {
 	struct streamer_private *streamer_priv =
-	    (struct streamer_private *) dev->priv;
+	    netdev_priv(dev);
 	__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
 	__u8 header_len;
 	__u16 frame_len, buffer_len;
@@ -1539,6 +1539,7 @@
 
 #if STREAMER_NETWORK_MONITOR
 	struct trh_hdr *mac_hdr;
+	DECLARE_MAC_BUF(mac);
 #endif
 
 	writew(streamer_priv->arb, streamer_mmio + LAPA);
@@ -1611,15 +1612,11 @@
 		       dev->name);
 		mac_hdr = tr_hdr(mac_frame);
 		printk(KERN_WARNING
-		       "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n",
-		       dev->name, mac_hdr->daddr[0], mac_hdr->daddr[1],
-		       mac_hdr->daddr[2], mac_hdr->daddr[3],
-		       mac_hdr->daddr[4], mac_hdr->daddr[5]);
+		       "%s: MAC Frame Dest. Addr: %s\n",
+		       dev->name, print_mac(mac, mac_hdr->daddr));
 		printk(KERN_WARNING
-		       "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n",
-		       dev->name, mac_hdr->saddr[0], mac_hdr->saddr[1],
-		       mac_hdr->saddr[2], mac_hdr->saddr[3],
-		       mac_hdr->saddr[4], mac_hdr->saddr[5]);
+		       "%s: MAC Frame Srce. Addr: %s\n",
+		       dev->name, DEV->ADDR6(mac_hdr->saddr));
 #endif
 		netif_rx(mac_frame);
 
@@ -1740,7 +1737,7 @@
 static void streamer_asb_bh(struct net_device *dev)
 {
 	struct streamer_private *streamer_priv =
-	    (struct streamer_private *) dev->priv;
+	    netdev_priv(dev);
 	__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
 
 	if (streamer_priv->asb_queued == 1) 
@@ -1784,7 +1781,7 @@
 static int streamer_change_mtu(struct net_device *dev, int mtu)
 {
 	struct streamer_private *streamer_priv =
-	    (struct streamer_private *) dev->priv;
+	    netdev_priv(dev);
 	__u16 max_mtu;
 
 	if (streamer_priv->streamer_ring_speed == 4)
@@ -1848,12 +1845,14 @@
 static int sprintf_info(char *buffer, struct net_device *dev)
 {
 	struct streamer_private *streamer_priv =
-	    (struct streamer_private *) dev->priv;
+	    netdev_priv(dev);
 	__u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
 	struct streamer_adapter_addr_table sat;
 	struct streamer_parameters_table spt;
 	int size = 0;
 	int i;
+	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mac2);
 
 	writew(streamer_priv->streamer_addr_table_addr, streamer_mmio + LAPA);
 	for (i = 0; i < 14; i += 2) {
@@ -1875,37 +1874,30 @@
 	size = sprintf(buffer, "\n%6s: Adapter Address   : Node Address      : Functional Addr\n", dev->name);
 
 	size += sprintf(buffer + size,
-		    "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x\n",
-		    dev->name, dev->dev_addr[0], dev->dev_addr[1],
-		    dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4],
-		    dev->dev_addr[5], sat.node_addr[0], sat.node_addr[1],
-		    sat.node_addr[2], sat.node_addr[3], sat.node_addr[4],
-		    sat.node_addr[5], sat.func_addr[0], sat.func_addr[1],
-		    sat.func_addr[2], sat.func_addr[3]);
+			"%6s: %s : %s : %02x:%02x:%02x:%02x\n",
+			dev->name, print_mac(mac, dev->dev_addr),
+			print_mac(mac2, sat.node_addr),
+			sat.func_addr[0], sat.func_addr[1],
+			sat.func_addr[2], sat.func_addr[3]);
 
 	size += sprintf(buffer + size, "\n%6s: Token Ring Parameters Table:\n", dev->name);
 
 	size += sprintf(buffer + size, "%6s: Physical Addr : Up Node Address   : Poll Address      : AccPri : Auth Src : Att Code :\n", dev->name);
 
 	size += sprintf(buffer + size,
-		    "%6s: %02x:%02x:%02x:%02x   : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %04x   : %04x     :  %04x    :\n",
+		    "%6s: %02x:%02x:%02x:%02x   : %s : %s : %04x   : %04x     :  %04x    :\n",
 		    dev->name, spt.phys_addr[0], spt.phys_addr[1],
 		    spt.phys_addr[2], spt.phys_addr[3],
-		    spt.up_node_addr[0], spt.up_node_addr[1],
-		    spt.up_node_addr[2], spt.up_node_addr[3],
-		    spt.up_node_addr[4], spt.up_node_addr[4],
-		    spt.poll_addr[0], spt.poll_addr[1], spt.poll_addr[2],
-		    spt.poll_addr[3], spt.poll_addr[4], spt.poll_addr[5],
+		    print_mac(mac, spt.up_node_addr),
+		    print_mac(mac2, spt.poll_addr),
 		    ntohs(spt.acc_priority), ntohs(spt.auth_source_class),
 		    ntohs(spt.att_code));
 
 	size += sprintf(buffer + size, "%6s: Source Address    : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", dev->name);
 
 	size += sprintf(buffer + size,
-		    "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %04x  : %04x   : %04x   : %04x   : %04x    :     %04x     : \n",
-		    dev->name, spt.source_addr[0], spt.source_addr[1],
-		    spt.source_addr[2], spt.source_addr[3],
-		    spt.source_addr[4], spt.source_addr[5],
+		    "%6s: %s : %04x  : %04x   : %04x   : %04x   : %04x    :     %04x     : \n",
+		    dev->name, print_mac(mac, spt.source_addr),
 		    ntohs(spt.beacon_type), ntohs(spt.major_vector),
 		    ntohs(spt.lan_status), ntohs(spt.local_ring),
 		    ntohs(spt.mon_error), ntohs(spt.frame_correl));
@@ -1914,14 +1906,12 @@
 		    dev->name);
 
 	size += sprintf(buffer + size,
-		    "%6s:                :  %02x  :  %02x  : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x    : \n",
+		    "%6s:                :  %02x  :  %02x  : %s : %02x:%02x:%02x:%02x    : \n",
 		    dev->name, ntohs(spt.beacon_transmit),
-		    ntohs(spt.beacon_receive), spt.beacon_naun[0],
-		    spt.beacon_naun[1], spt.beacon_naun[2],
-		    spt.beacon_naun[3], spt.beacon_naun[4],
-		    spt.beacon_naun[5], spt.beacon_phys[0],
-		    spt.beacon_phys[1], spt.beacon_phys[2],
-		    spt.beacon_phys[3]);
+		    ntohs(spt.beacon_receive),
+		    print_mac(mac, spt.beacon_naun),
+		    spt.beacon_phys[0], spt.beacon_phys[1],
+		    spt.beacon_phys[2], spt.beacon_phys[3]);
 	return size;
 }
 #endif
diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c
index f8f4d74..5a41513 100644
--- a/drivers/net/tokenring/madgemc.c
+++ b/drivers/net/tokenring/madgemc.c
@@ -151,7 +151,8 @@
 	struct net_local *tp;
 	struct card_info *card;
 	struct mca_device *mdev = to_mca_device(device);
-	int ret = 0, i = 0;
+	int ret = 0;
+	DECLARE_MAC_BUF(mac);
 
 	if (versionprinted++ == 0)
 		printk("%s", version);
@@ -168,7 +169,6 @@
 		goto getout;
 	}
 
-	SET_MODULE_OWNER(dev);
 	dev->dma = 0;
 
 	card = kmalloc(sizeof(struct card_info), GFP_KERNEL);
@@ -323,11 +323,8 @@
 	mca_device_set_name(mdev, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME);
 	mca_set_adapter_procfn(mdev->slot, madgemc_mcaproc, dev);
 
-	printk("%s:     Ring Station Address: ", dev->name);
-	printk("%2.2x", dev->dev_addr[0]);
-	for (i = 1; i < 6; i++)
-		printk(":%2.2x", dev->dev_addr[i]);
-	printk("\n");
+	printk("%s:     Ring Station Address: %s\n",
+	       dev->name, print_mac(mac, dev->dev_addr));
 
 	if (tmsdev_init(dev, device)) {
 		printk("%s: unable to get memory for dev->priv.\n", 
@@ -690,14 +687,14 @@
 static int madgemc_mcaproc(char *buf, int slot, void *d) 
 {	
 	struct net_device *dev = (struct net_device *)d;
-	struct net_local *tp = dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	struct card_info *curcard = tp->tmspriv;
 	int len = 0;
+	DECLARE_MAC_BUF(mac);
 	
 	len += sprintf(buf+len, "-------\n");
 	if (curcard) {
 		struct net_local *tp = netdev_priv(dev);
-		int i;
 		
 		len += sprintf(buf+len, "Card Revision: %d\n", curcard->cardrev);
 		len += sprintf(buf+len, "RAM Size: %dkb\n", curcard->ramsize);
@@ -717,11 +714,8 @@
 		}
 		len += sprintf(buf+len, " (%s)\n", (curcard->fairness)?"Unfair":"Fair");
 		
-		len += sprintf(buf+len, "Ring Station Address: ");
-		len += sprintf(buf+len, "%2.2x", dev->dev_addr[0]);
-		for (i = 1; i < 6; i++)
-			len += sprintf(buf+len, " %2.2x", dev->dev_addr[i]);
-		len += sprintf(buf+len, "\n");
+		len += sprintf(buf+len, "Ring Station Address: %s\n",
+			       print_mac(mac, dev->dev_addr));
 	} else 
 		len += sprintf(buf+len, "Card not configured\n");
 
@@ -736,7 +730,7 @@
 
 	BUG_ON(!dev);
 
-	tp = dev->priv;
+	tp = netdev_priv(dev);
 	card = tp->tmspriv;
 	kfree(card);
 	tp->tmspriv = NULL;
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index 09b3cfb..74c1f0f 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -102,6 +102,7 @@
 #include <linux/jiffies.h>
 
 #include <net/checksum.h>
+#include <net/net_namespace.h>
 
 #include <asm/io.h>
 #include <asm/system.h>
@@ -219,14 +220,14 @@
 		goto op_release_dev;
 	}
 
-	olympic_priv = dev->priv ;
+	olympic_priv = netdev_priv(dev) ;
 	
 	spin_lock_init(&olympic_priv->olympic_lock) ; 
 
 	init_waitqueue_head(&olympic_priv->srb_wait);
 	init_waitqueue_head(&olympic_priv->trb_wait);
 #if OLYMPIC_DEBUG  
-	printk(KERN_INFO "pci_device: %p, dev:%p, dev->priv: %p\n", pdev, dev, dev->priv);
+	printk(KERN_INFO "pci_device: %p, dev:%p, dev->priv: %p\n", pdev, dev, netdev_priv(dev));
 #endif
 	dev->irq=pdev->irq;
 	dev->base_addr=pci_resource_start(pdev, 0);
@@ -260,7 +261,6 @@
 	dev->set_multicast_list=&olympic_set_rx_mode;
 	dev->get_stats=&olympic_get_stats ;
 	dev->set_mac_address=&olympic_set_mac_address ;  
-	SET_MODULE_OWNER(dev) ; 
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	pci_set_drvdata(pdev,dev) ; 
@@ -268,9 +268,9 @@
 	printk("Olympic: %s registered as: %s\n",olympic_priv->olympic_card_name,dev->name);
 	if (olympic_priv->olympic_network_monitor) { /* Must go after register_netdev as we need the device name */ 
 		char proc_name[20] ; 
-		strcpy(proc_name,"net/olympic_") ; 
+		strcpy(proc_name,"olympic_") ;
 		strcat(proc_name,dev->name) ; 
-		create_proc_read_entry(proc_name,0,NULL,olympic_proc_info,(void *)dev) ; 
+		create_proc_read_entry(proc_name,0,init_net.proc_net,olympic_proc_info,(void *)dev) ;
 		printk("Olympic: Network Monitor information: /proc/%s\n",proc_name); 
 	}
 	return  0 ;
@@ -297,7 +297,7 @@
 	unsigned long t; 
 	unsigned int uaa_addr;
 
-    	olympic_priv=(struct olympic_private *)dev->priv;
+	olympic_priv=netdev_priv(dev);
 	olympic_mmio=olympic_priv->olympic_mmio;
 
 	printk("%s \n", version);
@@ -418,14 +418,15 @@
 	writel(uaa_addr,olympic_mmio+LAPA);
 	adapter_addr=olympic_priv->olympic_lap + (uaa_addr & (~0xf800));
 
-#if OLYMPIC_DEBUG
-	printk("adapter address: %02x:%02x:%02x:%02x:%02x:%02x\n",
-			readb(adapter_addr), readb(adapter_addr+1),readb(adapter_addr+2),
-			readb(adapter_addr+3),readb(adapter_addr+4),readb(adapter_addr+5));
-#endif
-
 	memcpy_fromio(&dev->dev_addr[0], adapter_addr,6);
 
+#if OLYMPIC_DEBUG
+ {
+	DECLARE_MAC_BUF(mac);
+	printk("adapter address: %s\n", print_mac(mac, dev->dev_addr));
+ }
+#endif
+
 	olympic_priv->olympic_addr_table_addr = swab16(readw(init_srb + 12)); 
 	olympic_priv->olympic_parms_addr = swab16(readw(init_srb + 14)); 
 
@@ -435,11 +436,12 @@
 
 static int olympic_open(struct net_device *dev) 
 {
-	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	struct olympic_private *olympic_priv=netdev_priv(dev);
 	u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*init_srb;
 	unsigned long flags, t;
 	int i, open_finished = 1 ;
 	u8 resp, err;
+	DECLARE_MAC_BUF(mac);
 
 	DECLARE_WAITQUEUE(wait,current) ; 
 
@@ -567,14 +569,8 @@
 			goto out;
 
 		case 0x32:
-			printk(KERN_WARNING "%s: Invalid LAA: %02x:%02x:%02x:%02x:%02x:%02x\n",
-				dev->name, 
-				olympic_priv->olympic_laa[0],
-				olympic_priv->olympic_laa[1],
-				olympic_priv->olympic_laa[2],
-				olympic_priv->olympic_laa[3],
-				olympic_priv->olympic_laa[4],
-				olympic_priv->olympic_laa[5]) ; 
+			printk(KERN_WARNING "%s: Invalid LAA: %s\n",
+			       dev->name, print_mac(mac, olympic_priv->olympic_laa));
 			goto out;
 
 		default:
@@ -704,30 +700,26 @@
 #endif
 
 	if (olympic_priv->olympic_network_monitor) { 
-		u8 __iomem *oat ; 
-		u8 __iomem *opt ; 
-		oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
-		opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
+		u8 __iomem *oat;
+		u8 __iomem *opt;
+		int i;
+		u8 addr[6];
+		DECLARE_MAC_BUF(mac);
+		oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr);
+		opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr);
 
-		printk("%s: Node Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, 
-			readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), 
-			readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1),
-			readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2),
-			readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3),
-			readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4),
-			readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5));
+		for (i = 0; i < 6; i++)
+			addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+i);
+		printk("%s: Node Address: %s\n",dev->name, print_mac(mac, addr));
 		printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name, 
 			readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), 
 			readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
 			readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
 			readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3));
-		printk("%s: NAUN Address: %02x:%02x:%02x:%02x:%02x:%02x\n",dev->name, 
-			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)),
-			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1),
-			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2),
-			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3),
-			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4),
-			readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5));
+
+		for (i = 0; i < 6; i++)
+			addr[i] = readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+i);
+		printk("%s: NAUN Address: %s\n",dev->name, print_mac(mac, addr));
 	}
 	
 	netif_start_queue(dev);
@@ -755,7 +747,7 @@
  */
 static void olympic_rx(struct net_device *dev)
 {
-	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	struct olympic_private *olympic_priv=netdev_priv(dev);
 	u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio;
 	struct olympic_rx_status *rx_status;
 	struct olympic_rx_desc *rx_desc ; 
@@ -897,7 +889,7 @@
 
 static void olympic_freemem(struct net_device *dev) 
 { 
-	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	struct olympic_private *olympic_priv=netdev_priv(dev);
 	int i;
 			
 	for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) {
@@ -930,7 +922,7 @@
 static irqreturn_t olympic_interrupt(int irq, void *dev_id) 
 {
 	struct net_device *dev= (struct net_device *)dev_id;
-	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	struct olympic_private *olympic_priv=netdev_priv(dev);
 	u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio;
 	u32 sisr;
 	u8 __iomem *adapter_check_area ; 
@@ -1046,7 +1038,7 @@
 
 static int olympic_xmit(struct sk_buff *skb, struct net_device *dev) 
 {
-	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	struct olympic_private *olympic_priv=netdev_priv(dev);
 	u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio;
 	unsigned long flags ; 
 
@@ -1077,7 +1069,7 @@
 
 static int olympic_close(struct net_device *dev) 
 {
-	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	struct olympic_private *olympic_priv=netdev_priv(dev);
 	u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*srb;
 	unsigned long t,flags;
 
@@ -1147,7 +1139,7 @@
 
 static void olympic_set_rx_mode(struct net_device *dev) 
 {
-	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
+	struct olympic_private *olympic_priv = netdev_priv(dev);
    	u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ; 
 	u8 options = 0; 
 	u8 __iomem *srb;
@@ -1215,7 +1207,7 @@
 
 static void olympic_srb_bh(struct net_device *dev) 
 { 
-	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
+	struct olympic_private *olympic_priv = netdev_priv(dev);
    	u8 __iomem *olympic_mmio = olympic_priv->olympic_mmio ; 
 	u8 __iomem *srb;
 
@@ -1361,14 +1353,14 @@
 static struct net_device_stats * olympic_get_stats(struct net_device *dev)
 {
 	struct olympic_private *olympic_priv ;
-	olympic_priv=(struct olympic_private *) dev->priv;
+	olympic_priv=netdev_priv(dev);
 	return (struct net_device_stats *) &olympic_priv->olympic_stats; 
 }
 
 static int olympic_set_mac_address (struct net_device *dev, void *addr) 
 {
 	struct sockaddr *saddr = addr ; 
-	struct olympic_private *olympic_priv = (struct olympic_private *)dev->priv ; 
+	struct olympic_private *olympic_priv = netdev_priv(dev);
 
 	if (netif_running(dev)) { 
 		printk(KERN_WARNING "%s: Cannot set mac/laa address while card is open\n", dev->name) ; 
@@ -1389,7 +1381,7 @@
 
 static void olympic_arb_cmd(struct net_device *dev)
 {
-	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv;
+	struct olympic_private *olympic_priv = netdev_priv(dev);
 	u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio;
 	u8 __iomem *arb_block, *asb_block, *srb  ; 
 	u8 header_len ; 
@@ -1445,11 +1437,14 @@
 		mac_frame->protocol = tr_type_trans(mac_frame, dev);
 
 		if (olympic_priv->olympic_network_monitor) { 
-			struct trh_hdr *mac_hdr ; 
-			printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name) ;
+			struct trh_hdr *mac_hdr;
+			DECLARE_MAC_BUF(mac);
+			printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name);
 			mac_hdr = tr_hdr(mac_frame);
-			printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->daddr[0], mac_hdr->daddr[1], mac_hdr->daddr[2], mac_hdr->daddr[3], mac_hdr->daddr[4], mac_hdr->daddr[5]) ; 
-			printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %02x:%02x:%02x:%02x:%02x:%02x \n", dev->name , mac_hdr->saddr[0], mac_hdr->saddr[1], mac_hdr->saddr[2], mac_hdr->saddr[3], mac_hdr->saddr[4], mac_hdr->saddr[5]) ; 
+			printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %s\n",
+			       dev->name, print_mac(mac, mac_hdr->daddr));
+			printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %s\n",
+			       dev->name, print_mac(mac, mac_hdr->saddr));
 		}
 		netif_rx(mac_frame);
 		dev->last_rx = jiffies;
@@ -1575,7 +1570,7 @@
 
 static void olympic_asb_bh(struct net_device *dev) 
 {
-	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ; 
+	struct olympic_private *olympic_priv = netdev_priv(dev);
 	u8 __iomem *arb_block, *asb_block ; 
 
 	arb_block = (olympic_priv->olympic_lap + olympic_priv->arb) ; 
@@ -1615,7 +1610,7 @@
  
 static int olympic_change_mtu(struct net_device *dev, int mtu) 
 {
-	struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv;
+	struct olympic_private *olympic_priv = netdev_priv(dev);
 	u16 max_mtu ; 
 
 	if (olympic_priv->olympic_ring_speed == 4)
@@ -1637,33 +1632,31 @@
 static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
 {
 	struct net_device *dev = (struct net_device *)data ; 
-	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	struct olympic_private *olympic_priv=netdev_priv(dev);
 	u8 __iomem *oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ; 
 	u8 __iomem *opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ; 
 	int size = 0 ; 
 	int len=0;
 	off_t begin=0;
 	off_t pos=0;
-	
+	u8 addr[6];
+	u8 addr2[6];
+	int i;
+	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mac2);
+
 	size = sprintf(buffer, 
 		"IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapter %s\n",dev->name);
 	size += sprintf(buffer+size, "\n%6s: Adapter Address   : Node Address      : Functional Addr\n",
  	   dev->name); 
 
-	size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x\n",
+	for (i = 0 ; i < 6 ; i++)
+		addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr) + i);
+
+	size += sprintf(buffer+size, "%6s: %s : %s : %02x:%02x:%02x:%02x\n",
 	   dev->name,
-           dev->dev_addr[0],
-	   dev->dev_addr[1],
-	   dev->dev_addr[2],
- 	   dev->dev_addr[3],
-	   dev->dev_addr[4],
-	   dev->dev_addr[5],
-	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)), 
-	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+1),
-	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+2),
-	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+3),
-	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+4),
-	   readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+5),
+	   print_mac(mac, dev->dev_addr),
+	   print_mac(mac2, addr),
 	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), 
 	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1),
 	   readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
@@ -1673,25 +1666,20 @@
 
 	size += sprintf(buffer+size, "%6s: Physical Addr : Up Node Address   : Poll Address      : AccPri : Auth Src : Att Code :\n",
 	  dev->name) ; 
-	   
-	size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x   : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x:%02x:%02x : %04x   : %04x     :  %04x    :\n",
+
+	for (i = 0 ; i < 6 ; i++)
+		addr[i] = readb(opt+offsetof(struct olympic_parameters_table, up_node_addr) + i);
+	for (i = 0 ; i < 6 ; i++)
+		addr2[i] =  readb(opt+offsetof(struct olympic_parameters_table, poll_addr) + i);
+
+	size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x   : %s : %s : %04x   : %04x     :  %04x    :\n",
 	  dev->name,
 	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)),
 	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+1),
 	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+2),
 	  readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+3),
-	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)),
-	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+1),
-	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+2),
-	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+3),
-	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+4),
-	  readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+5),
-	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)),
-	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+1),
-	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+2),
-	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+3),
-	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+4),
-	  readb(opt+offsetof(struct olympic_parameters_table, poll_addr)+5),
+	  print_mac(mac, addr),
+	  print_mac(mac2, addr2),
 	  swab16(readw(opt+offsetof(struct olympic_parameters_table, acc_priority))),
 	  swab16(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))),
 	  swab16(readw(opt+offsetof(struct olympic_parameters_table, att_code))));
@@ -1699,14 +1687,11 @@
 	size += sprintf(buffer+size, "%6s: Source Address    : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n",
 	  dev->name) ; 
 	
-	size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x:%02x:%02x : %04x  : %04x   : %04x   : %04x   : %04x    :     %04x     : \n",
+	for (i = 0 ; i < 6 ; i++)
+		addr[i] = readb(opt+offsetof(struct olympic_parameters_table, source_addr) + i);
+	size += sprintf(buffer+size, "%6s: %s : %04x  : %04x   : %04x   : %04x   : %04x    :     %04x     : \n",
 	  dev->name,
-	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)),
-	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+1),
-	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+2),
-	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+3),
-	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+4),
-	  readb(opt+offsetof(struct olympic_parameters_table, source_addr)+5),
+	  print_mac(mac, addr),
 	  swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))),
 	  swab16(readw(opt+offsetof(struct olympic_parameters_table, major_vector))),
 	  swab16(readw(opt+offsetof(struct olympic_parameters_table, lan_status))),
@@ -1717,16 +1702,13 @@
 	size += sprintf(buffer+size, "%6s: Beacon Details :  Tx  :  Rx  : NAUN Node Address : NAUN Node Phys : \n",
 	  dev->name) ; 
 
-	size += sprintf(buffer+size, "%6s:                :  %02x  :  %02x  : %02x:%02x:%02x:%02x:%02x:%02x : %02x:%02x:%02x:%02x    : \n",
+	for (i = 0 ; i < 6 ; i++)
+		addr[i] = readb(opt+offsetof(struct olympic_parameters_table, beacon_naun) + i);
+	size += sprintf(buffer+size, "%6s:                :  %02x  :  %02x  : %s : %02x:%02x:%02x:%02x    : \n",
 	  dev->name,
 	  swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))),
 	  swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))),
-	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)),
-	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+1),
-	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+2),
-	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+3),
-	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+4),
-	  readb(opt+offsetof(struct olympic_parameters_table, beacon_naun)+5),
+	  print_mac(mac, addr),
 	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)),
 	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+1),
 	  readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2),
@@ -1748,13 +1730,13 @@
 static void __devexit olympic_remove_one(struct pci_dev *pdev) 
 {
 	struct net_device *dev = pci_get_drvdata(pdev) ; 
-	struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
+	struct olympic_private *olympic_priv=netdev_priv(dev);
 
 	if (olympic_priv->olympic_network_monitor) { 
 		char proc_name[20] ; 
-		strcpy(proc_name,"net/olympic_") ; 
+		strcpy(proc_name,"olympic_") ;
 		strcat(proc_name,dev->name) ;
-		remove_proc_entry(proc_name,NULL); 
+		remove_proc_entry(proc_name,init_net.proc_net);
 	}
 	unregister_netdev(dev) ; 
 	iounmap(olympic_priv->olympic_mmio) ; 
diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c
index cb7dbb6..ca6b659 100644
--- a/drivers/net/tokenring/proteon.c
+++ b/drivers/net/tokenring/proteon.c
@@ -122,11 +122,11 @@
         static int versionprinted;
 	const unsigned *port;
 	int j,err = 0;
+	DECLARE_MAC_BUF(mac);
 
 	if (!dev)
 		return -ENOMEM;
 
-	SET_MODULE_OWNER(dev);
 	if (dev->base_addr)	/* probe specific location */
 		err = proteon_probe1(dev, dev->base_addr);
 	else {
@@ -153,11 +153,8 @@
 		
 	proteon_read_eeprom(dev);
 
-	printk(KERN_DEBUG "proteon.c:    Ring Station Address: ");
-	printk("%2.2x", dev->dev_addr[0]);
-	for (j = 1; j < 6; j++)
-		printk(":%2.2x", dev->dev_addr[j]);
-	printk("\n");
+	printk(KERN_DEBUG "proteon.c:    Ring Station Address: %s\n",
+	       print_mac(mac, dev->dev_addr));
 		
 	tp = netdev_priv(dev);
 	tp->setnselout = proteon_setnselout_pins;
diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c
index 33afea3..32e8d5a 100644
--- a/drivers/net/tokenring/skisa.c
+++ b/drivers/net/tokenring/skisa.c
@@ -139,11 +139,11 @@
         static int versionprinted;
 	const unsigned *port;
 	int j, err = 0;
+	DECLARE_MAC_BUF(mac);
 
 	if (!dev)
 		return -ENOMEM;
 
-	SET_MODULE_OWNER(dev);
 	if (dev->base_addr)	/* probe specific location */
 		err = sk_isa_probe1(dev, dev->base_addr);
 	else {
@@ -170,11 +170,8 @@
 		
 	sk_isa_read_eeprom(dev);
 
-	printk(KERN_DEBUG "skisa.c:    Ring Station Address: ");
-	printk("%2.2x", dev->dev_addr[0]);
-	for (j = 1; j < 6; j++)
-		printk(":%2.2x", dev->dev_addr[j]);
-	printk("\n");
+	printk(KERN_DEBUG "skisa.c:    Ring Station Address: %s\n",
+	       print_mac(mac, dev->dev_addr));
 		
 	tp = netdev_priv(dev);
 	tp->setnselout = sk_isa_setnselout_pins;
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index f83bb5c..93da3a3 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -3583,8 +3583,6 @@
 	if (!dev)
 		return ERR_PTR(-ENOMEM);
 
-	SET_MODULE_OWNER(dev);
-
 	if (unit >= 0) {
 		sprintf(dev->name, "tr%d", unit);
 		netdev_boot_setup_check(dev);
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index 12bd2940..d5fa36d 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -2124,7 +2124,7 @@
 		/* Get the frame size (Byte swap for Intel).
 		 * Do this early (see workaround comment below)
 		 */
-		Length = be16_to_cpu((unsigned short)rpl->FrameSize);
+		Length = be16_to_cpu(rpl->FrameSize);
 
 		/* Check if the Frame_Start, Frame_End and
 		 * Frame_Complete bits are set.
@@ -2140,7 +2140,7 @@
 			 * Length2 is there because there have also been
 			 * cases where the FrameSize was partially written
 			 */
-			Length2 = be16_to_cpu((unsigned short)rpl->FrameSize);
+			Length2 = be16_to_cpu(rpl->FrameSize);
 
 			if(Length == 0 || Length != Length2)
 			{
diff --git a/drivers/net/tokenring/tms380tr.h b/drivers/net/tokenring/tms380tr.h
index 2a16078..7daf74e 100644
--- a/drivers/net/tokenring/tms380tr.h
+++ b/drivers/net/tokenring/tms380tr.h
@@ -476,13 +476,13 @@
 				 * bytes = 0xC000
 				 */
 	u_int32_t FunctAddr;	/* High order bytes = 0xC000 */
-	u_int16_t RxListSize;	/* RPL size: 0 (=26), 14, 20 or
+	__be16 RxListSize;	/* RPL size: 0 (=26), 14, 20 or
 				 * 26 bytes read by the adapter.
 				 * (Depending on the number of 
 				 * fragments/list)
 				 */
-	u_int16_t TxListSize;	/* TPL size */
-	u_int16_t BufSize;	/* Is automatically rounded up to the
+	__be16 TxListSize;	/* TPL size */
+	__be16 BufSize;		/* Is automatically rounded up to the
 				 * nearest nK boundary.
 				 */
 	u_int16_t FullDuplex;
@@ -580,14 +580,14 @@
 /*--------------------- Send and Receive definitions -------------------*/
 #pragma pack(1)
 typedef struct {
-	u_int16_t DataCount;	/* Value 0, even and odd values are
+	__be16 DataCount;	/* Value 0, even and odd values are
 				 * permitted; value is unaltered most
 				 * significant bit set: following
 				 * fragments last fragment: most
 				 * significant bit is not evaluated.
 				 * (???)
 				 */
-	u_int32_t DataAddr;	/* Pointer to frame data fragment;
+	__be32 DataAddr;	/* Pointer to frame data fragment;
 				 * even or odd.
 				 */
 } Fragment;
@@ -679,7 +679,7 @@
 typedef struct s_TPL TPL;
 
 struct s_TPL {	/* Transmit Parameter List (align on even word boundaries) */
-	u_int32_t NextTPLAddr;		/* Pointer to next TPL in chain; if
+	__be32 NextTPLAddr;		/* Pointer to next TPL in chain; if
 					 * pointer is odd: this is the last
 					 * TPL. Pointing to itself can cause
 					 * problems!
@@ -689,7 +689,7 @@
 					 * significant bit first! Set by the
 					 * adapter: CSTAT_COMPLETE status.
 					 */
-	u_int16_t FrameSize;		/* Number of bytes to be transmitted
+	__be16 FrameSize;		/* Number of bytes to be transmitted
 					 * as a frame including AC/FC,
 					 * Destination, Source, Routing field
 					 * not including CRC, FS, End Delimiter
@@ -1020,7 +1020,7 @@
 #pragma pack(1)
 typedef struct s_RPL RPL;
 struct s_RPL {	/* Receive Parameter List */
-	u_int32_t NextRPLAddr;		/* Pointer to next RPL in chain
+	__be32 NextRPLAddr;		/* Pointer to next RPL in chain
 					 * (normalized = physical 32 bit
 					 * address) if pointer is odd: this
 					 * is last RPL. Pointing to itself can
@@ -1031,7 +1031,7 @@
 					 * adapter in lists that start or end
 					 * a frame.
 					 */
-	volatile u_int16_t FrameSize;	 /* Number of bytes received as a
+	volatile __be16 FrameSize;	 /* Number of bytes received as a
 					 * frame including AC/FC, Destination,
 					 * Source, Routing field not including 
 					 * CRC, FS (Frame Status), End Delimiter
diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c
index 3b2f00b..1c18f78 100644
--- a/drivers/net/tokenring/tmspci.c
+++ b/drivers/net/tokenring/tmspci.c
@@ -96,10 +96,11 @@
 	static int versionprinted;
 	struct net_device *dev;
 	struct net_local *tp;
-	int i, ret;
+	int ret;
 	unsigned int pci_irq_line;
 	unsigned long pci_ioaddr;
 	struct card_info *cardinfo = &card_info_table[ent->driver_data];
+	DECLARE_MAC_BUF(mac);
 
 	if (versionprinted++ == 0)
 		printk("%s", version);
@@ -115,7 +116,6 @@
 	dev = alloc_trdev(sizeof(struct net_local));
 	if (!dev)
 		return -ENOMEM;
-	SET_MODULE_OWNER(dev);
 
 	if (!request_region(pci_ioaddr, TMS_PCI_IO_EXTENT, dev->name)) {
 		ret = -EBUSY;
@@ -137,11 +137,8 @@
 		
 	tms_pci_read_eeprom(dev);
 
-	printk("%s:    Ring Station Address: ", dev->name);
-	printk("%2.2x", dev->dev_addr[0]);
-	for (i = 1; i < 6; i++)
-		printk(":%2.2x", dev->dev_addr[i]);
-	printk("\n");
+	printk("%s:    Ring Station Address: %s\n",
+	       dev->name, print_mac(mac, dev->dev_addr));
 		
 	ret = tmsdev_init(dev, &pdev->dev);
 	if (ret) {
@@ -149,7 +146,7 @@
 		goto err_out_irq;
 	}
 
-	tp = dev->priv;
+	tp = netdev_priv(dev);
 	tp->setnselout = tms_pci_setnselout_pins;
 		
 	tp->sifreadb = tms_pci_sifreadb;
@@ -210,7 +207,7 @@
 static unsigned short tms_pci_setnselout_pins(struct net_device *dev)
 {
 	unsigned short val = 0;
-	struct net_local *tp = dev->priv;
+	struct net_local *tp = netdev_priv(dev);
 	struct card_info *cardinfo = tp->tmspriv;
   
 	if(tp->DataRate == SPEED_4)
diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c
index 1aabc91..df10af7 100644
--- a/drivers/net/tsi108_eth.c
+++ b/drivers/net/tsi108_eth.c
@@ -47,7 +47,6 @@
 #include <linux/rtnetlink.h>
 #include <linux/timer.h>
 #include <linux/platform_device.h>
-#include <linux/etherdevice.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -79,6 +78,9 @@
 	void  __iomem *regs;	/* Base of normal regs */
 	void  __iomem *phyregs;	/* Base of register bank used for PHY access */
 
+	struct net_device *dev;
+	struct napi_struct napi;
+
 	unsigned int phy;		/* Index of PHY for this interface */
 	unsigned int irq_num;
 	unsigned int id;
@@ -837,13 +839,13 @@
 	return done;
 }
 
-static int tsi108_poll(struct net_device *dev, int *budget)
+static int tsi108_poll(struct napi_struct *napi, int budget)
 {
-	struct tsi108_prv_data *data = netdev_priv(dev);
+	struct tsi108_prv_data *data = container_of(napi, struct tsi108_prv_data, napi);
+	struct net_device *dev = data->dev;
 	u32 estat = TSI_READ(TSI108_EC_RXESTAT);
 	u32 intstat = TSI_READ(TSI108_EC_INTSTAT);
-	int total_budget = min(*budget, dev->quota);
-	int num_received = 0, num_filled = 0, budget_used;
+	int num_received = 0, num_filled = 0;
 
 	intstat &= TSI108_INT_RXQUEUE0 | TSI108_INT_RXTHRESH |
 	    TSI108_INT_RXOVERRUN | TSI108_INT_RXERROR | TSI108_INT_RXWAIT;
@@ -852,7 +854,7 @@
 	TSI_WRITE(TSI108_EC_INTSTAT, intstat);
 
 	if (data->rxpending || (estat & TSI108_EC_RXESTAT_Q0_DESCINT))
-		num_received = tsi108_complete_rx(dev, total_budget);
+		num_received = tsi108_complete_rx(dev, budget);
 
 	/* This should normally fill no more slots than the number of
 	 * packets received in tsi108_complete_rx().  The exception
@@ -867,7 +869,7 @@
 	 */
 
 	if (data->rxfree < TSI108_RXRING_LEN)
-		num_filled = tsi108_refill_rx(dev, total_budget * 2);
+		num_filled = tsi108_refill_rx(dev, budget * 2);
 
 	if (intstat & TSI108_INT_RXERROR) {
 		u32 err = TSI_READ(TSI108_EC_RXERR);
@@ -890,14 +892,9 @@
 		spin_unlock_irq(&data->misclock);
 	}
 
-	budget_used = max(num_received, num_filled / 2);
-
-	*budget -= budget_used;
-	dev->quota -= budget_used;
-
-	if (budget_used != total_budget) {
+	if (num_received < budget) {
 		data->rxpending = 0;
-		netif_rx_complete(dev);
+		netif_rx_complete(dev, napi);
 
 		TSI_WRITE(TSI108_EC_INTMASK,
 				     TSI_READ(TSI108_EC_INTMASK)
@@ -906,14 +903,11 @@
 					 TSI108_INT_RXOVERRUN |
 					 TSI108_INT_RXERROR |
 					 TSI108_INT_RXWAIT));
-
-		/* IRQs are level-triggered, so no need to re-check */
-		return 0;
 	} else {
 		data->rxpending = 1;
 	}
 
-	return 1;
+	return num_received;
 }
 
 static void tsi108_rx_int(struct net_device *dev)
@@ -931,7 +925,7 @@
 	 * from tsi108_check_rxring().
 	 */
 
-	if (netif_rx_schedule_prep(dev)) {
+	if (netif_rx_schedule_prep(dev, &data->napi)) {
 		/* Mask, rather than ack, the receive interrupts.  The ack
 		 * will happen in tsi108_poll().
 		 */
@@ -942,7 +936,7 @@
 				     | TSI108_INT_RXTHRESH |
 				     TSI108_INT_RXOVERRUN | TSI108_INT_RXERROR |
 				     TSI108_INT_RXWAIT);
-		__netif_rx_schedule(dev);
+		__netif_rx_schedule(dev, &data->napi);
 	} else {
 		if (!netif_running(dev)) {
 			/* This can happen if an interrupt occurs while the
@@ -1401,6 +1395,8 @@
 	TSI_WRITE(TSI108_EC_TXQ_PTRLOW, data->txdma);
 	tsi108_init_phy(dev);
 
+	napi_enable(&data->napi);
+
 	setup_timer(&data->timer, tsi108_timed_checker, (unsigned long)dev);
 	mod_timer(&data->timer, jiffies + 1);
 
@@ -1425,6 +1421,7 @@
 	struct tsi108_prv_data *data = netdev_priv(dev);
 
 	netif_stop_queue(dev);
+	napi_disable(&data->napi);
 
 	del_timer_sync(&data->timer);
 
@@ -1543,6 +1540,7 @@
 	struct tsi108_prv_data *data = NULL;
 	hw_info *einfo;
 	int err = 0;
+	DECLARE_MAC_BUF(mac);
 
 	einfo = pdev->dev.platform_data;
 
@@ -1562,6 +1560,7 @@
 
 	printk("tsi108_eth%d: probe...\n", pdev->id);
 	data = netdev_priv(dev);
+	data->dev = dev;
 
 	pr_debug("tsi108_eth%d:regs:phyresgs:phy:irq_num=0x%x:0x%x:0x%x:0x%x\n",
 			pdev->id, einfo->regs, einfo->phyregs,
@@ -1597,9 +1596,8 @@
 	dev->set_mac_address = tsi108_set_mac;
 	dev->set_multicast_list = tsi108_set_rx_mode;
 	dev->get_stats = tsi108_get_stats;
-	dev->poll = tsi108_poll;
+	netif_napi_add(dev, &data->napi, tsi108_poll, 64);
 	dev->do_ioctl = tsi108_do_ioctl;
-	dev->weight = 64;  /* 64 is more suitable for GigE interface - klai */
 
 	/* Apparently, the Linux networking code won't use scatter-gather
 	 * if the hardware doesn't do checksums.  However, it's faster
@@ -1610,7 +1608,6 @@
 	 */
 
 	dev->features = NETIF_F_HIGHDMA;
-	SET_MODULE_OWNER(dev);
 
 	spin_lock_init(&data->txlock);
 	spin_lock_init(&data->misclock);
@@ -1632,10 +1629,8 @@
 		goto register_fail;
 	}
 
-	printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: "
-	       "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
-	       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-	       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+	printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: %s\n"
+	       dev->name, print_mac(mac, dev->dev_addr));
 #ifdef DEBUG
 	data->msg_enable = DEBUG;
 	dump_eth_one(dev);
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index d380e0b..77d9dd7 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -264,10 +264,10 @@
 } __attribute__((packed));
 
 struct de_desc {
-	u32			opts1;
-	u32			opts2;
-	u32			addr1;
-	u32			addr2;
+	__le32			opts1;
+	__le32			opts2;
+	__le32			addr1;
+	__le32			addr2;
 };
 
 struct media_info {
@@ -1670,8 +1670,6 @@
 
 static const struct ethtool_ops de_ethtool_ops = {
 	.get_link		= ethtool_op_get_link,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.get_sg			= ethtool_op_get_sg,
 	.get_drvinfo		= de_get_drvinfo,
 	.get_regs_len		= de_get_regs_len,
 	.get_settings		= de_get_settings,
@@ -1773,8 +1771,8 @@
 
 	/* download entire eeprom */
 	for (i = 0; i < DE_EEPROM_WORDS; i++)
-		((u16 *)ee_data)[i] =
-			le16_to_cpu(tulip_read_eeprom(de->regs, i, ee_addr_size));
+		((__le16 *)ee_data)[i] =
+			cpu_to_le16(tulip_read_eeprom(de->regs, i, ee_addr_size));
 
 	/* DEC now has a specification but early board makers
 	   just put the address in the first EEPROM locations. */
@@ -1931,6 +1929,7 @@
 	void __iomem *regs;
 	unsigned long pciaddr;
 	static int board_idx = -1;
+	DECLARE_MAC_BUF(mac);
 
 	board_idx++;
 
@@ -1944,7 +1943,6 @@
 	if (!dev)
 		return -ENOMEM;
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 	dev->open = de_open;
 	dev->stop = de_close;
@@ -2045,15 +2043,11 @@
 		goto err_out_iomap;
 
 	/* print info about board and interface just registered */
-	printk (KERN_INFO "%s: %s at 0x%lx, "
-		"%02x:%02x:%02x:%02x:%02x:%02x, "
-		"IRQ %d\n",
+	printk (KERN_INFO "%s: %s at 0x%lx, %s, IRQ %d\n",
 		dev->name,
 		de->de21040 ? "21040" : "21041",
 		dev->base_addr,
-		dev->dev_addr[0], dev->dev_addr[1],
-		dev->dev_addr[2], dev->dev_addr[3],
-		dev->dev_addr[4], dev->dev_addr[5],
+		print_mac(mac, dev->dev_addr),
 		dev->irq);
 
 	pci_set_drvdata(pdev, dev);
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 0990289..9b9cd83 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -482,7 +482,7 @@
 static char version[] __devinitdata = "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.com\n";
 
 #define c_char const char
-#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((u_short *)(a)))
+#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((__le16 *)(a)))
 
 /*
 ** MII Information
@@ -756,10 +756,10 @@
                                         /* Multiple of 4 for DC21040  */
                                         /* Allows 512 byte alignment  */
 struct de4x5_desc {
-    volatile s32 status;
-    u32 des1;
-    u32 buf;
-    u32 next;
+    volatile __le32 status;
+    __le32 des1;
+    __le32 buf;
+    __le32 next;
     DESC_ALIGN
 };
 
@@ -1088,6 +1088,7 @@
     struct de4x5_private *lp = netdev_priv(dev);
     struct pci_dev *pdev = NULL;
     int i, status=0;
+    DECLARE_MAC_BUF(mac);
 
     gendev->driver_data = dev;
 
@@ -1123,12 +1124,8 @@
     dev->base_addr = iobase;
     printk ("%s: %s at 0x%04lx", gendev->bus_id, name, iobase);
 
-    printk(", h/w address ");
     status = get_hw_addr(dev);
-    for (i = 0; i < ETH_ALEN - 1; i++) {     /* get the ethernet addr. */
-	printk("%2.2x:", dev->dev_addr[i]);
-    }
-    printk("%2.2x,\n", dev->dev_addr[i]);
+    printk(", h/w address %s\n", print_mac(mac, dev->dev_addr));
 
     if (status != 0) {
 	printk("      which has an Ethernet PROM CRC error.\n");
@@ -1261,7 +1258,6 @@
     }
 
     /* The DE4X5-specific entries in the device structure. */
-    SET_MODULE_OWNER(dev);
     SET_NETDEV_DEV(dev, gendev);
     dev->open = &de4x5_open;
     dev->hard_start_xmit = &de4x5_queue_pkt;
@@ -3946,7 +3942,7 @@
 static int
 EISA_signature(char *name, struct device *device)
 {
-    int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *);
+    int i, status = 0, siglen = ARRAY_SIZE(de4x5_signatures);
     struct eisa_device *edev;
 
     *name = '\0';
@@ -3967,7 +3963,7 @@
 static int
 PCI_signature(char *name, struct de4x5_private *lp)
 {
-    int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *);
+    int i, status = 0, siglen = ARRAY_SIZE(de4x5_signatures);
 
     if (lp->chipset == DC21040) {
 	strcpy(name, "DE434/5");
@@ -5073,7 +5069,7 @@
 {
     struct de4x5_private *lp = netdev_priv(dev);
     u_long iobase = dev->base_addr;
-    int i, j, k, n, limit=sizeof(phy_info)/sizeof(struct phy_table);
+    int i, j, k, n, limit=ARRAY_SIZE(phy_info);
     int id;
 
     lp->active = 0;
@@ -5469,19 +5465,16 @@
 de4x5_dbg_srom(struct de4x5_srom *p)
 {
     int i;
+    DECLARE_MAC_BUF(mac);
 
     if (de4x5_debug & DEBUG_SROM) {
 	printk("Sub-system Vendor ID: %04x\n", *((u_short *)p->sub_vendor_id));
 	printk("Sub-system ID:        %04x\n", *((u_short *)p->sub_system_id));
 	printk("ID Block CRC:         %02x\n", (u_char)(p->id_block_crc));
 	printk("SROM version:         %02x\n", (u_char)(p->version));
-	printk("# controllers:         %02x\n", (u_char)(p->num_controllers));
+	printk("# controllers:        %02x\n", (u_char)(p->num_controllers));
 
-	printk("Hardware Address:     ");
-	for (i=0;i<ETH_ALEN-1;i++) {
-	    printk("%02x:", (u_char)*(p->ieee_addr+i));
-	}
-	printk("%02x\n", (u_char)*(p->ieee_addr+i));
+	printk("Hardware Address:     %s\n", print_mac(mac, p->ieee_addr));
 	printk("CRC checksum:         %04x\n", (u_short)(p->chksum));
 	for (i=0; i<64; i++) {
 	    printk("%3d %04x\n", i<<1, (u_short)*((u_short *)p+i));
@@ -5495,21 +5488,12 @@
 de4x5_dbg_rx(struct sk_buff *skb, int len)
 {
     int i, j;
+    DECLARE_MAC_BUF(mac);
+    DECLARE_MAC_BUF(mac2);
 
     if (de4x5_debug & DEBUG_RX) {
-	printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n",
-	       (u_char)skb->data[0],
-	       (u_char)skb->data[1],
-	       (u_char)skb->data[2],
-	       (u_char)skb->data[3],
-	       (u_char)skb->data[4],
-	       (u_char)skb->data[5],
-	       (u_char)skb->data[6],
-	       (u_char)skb->data[7],
-	       (u_char)skb->data[8],
-	       (u_char)skb->data[9],
-	       (u_char)skb->data[10],
-	       (u_char)skb->data[11],
+	printk("R: %s <- %s len/SAP:%02x%02x [%d]\n",
+	       print_mac(mac, skb->data), print_mac(mac2, &skb->data[6]),
 	       (u_char)skb->data[12],
 	       (u_char)skb->data[13],
 	       len);
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index dab74fe..ca90566 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -362,6 +362,7 @@
 	struct net_device *dev;
 	u32 pci_pmr;
 	int i, err;
+	DECLARE_MAC_BUF(mac);
 
 	DMFE_DBUG(0, "dmfe_init_one()", 0);
 
@@ -372,7 +373,6 @@
 	dev = alloc_etherdev(sizeof(*db));
 	if (dev == NULL)
 		return -ENOMEM;
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
@@ -471,13 +471,13 @@
 	if (err)
 		goto err_out_res;
 
-	printk(KERN_INFO "%s: Davicom DM%04lx at pci%s,",
-		dev->name,
-		ent->driver_data >> 16,
-		pci_name(pdev));
-	for (i = 0; i < 6; i++)
-		printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
-	printk(", irq %d.\n", dev->irq);
+	printk(KERN_INFO "%s: Davicom DM%04lx at pci%s, "
+	       "%s, irq %d.\n",
+	       dev->name,
+	       ent->driver_data >> 16,
+	       pci_name(pdev),
+	       print_mac(mac, dev->dev_addr),
+	       dev->irq);
 
 	pci_set_master(pdev);
 
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index 53efd66..3653314 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -103,28 +103,29 @@
 void oom_timer(unsigned long data)
 {
         struct net_device *dev = (struct net_device *)data;
-	netif_rx_schedule(dev);
+	struct tulip_private *tp = netdev_priv(dev);
+	netif_rx_schedule(dev, &tp->napi);
 }
 
-int tulip_poll(struct net_device *dev, int *budget)
+int tulip_poll(struct napi_struct *napi, int budget)
 {
-	struct tulip_private *tp = netdev_priv(dev);
+	struct tulip_private *tp = container_of(napi, struct tulip_private, napi);
+	struct net_device *dev = tp->dev;
 	int entry = tp->cur_rx % RX_RING_SIZE;
-	int rx_work_limit = *budget;
+	int work_done = 0;
+#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
 	int received = 0;
+#endif
 
 	if (!netif_running(dev))
 		goto done;
 
-	if (rx_work_limit > dev->quota)
-		rx_work_limit = dev->quota;
-
 #ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
 
 /* that one buffer is needed for mit activation; or might be a
    bug in the ring buffer code; check later -- JHS*/
 
-        if (rx_work_limit >=RX_RING_SIZE) rx_work_limit--;
+        if (budget >=RX_RING_SIZE) budget--;
 #endif
 
 	if (tulip_debug > 4)
@@ -144,14 +145,13 @@
                while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
                        s32 status = le32_to_cpu(tp->rx_ring[entry].status);
 
-
                        if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx)
                                break;
 
                        if (tulip_debug > 5)
                                printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
                                       dev->name, entry, status);
-                       if (--rx_work_limit < 0)
+		       if (work_done++ >= budget)
                                goto not_done;
 
                        if ((status & 0x38008300) != 0x0300) {
@@ -238,7 +238,9 @@
                                tp->stats.rx_packets++;
                                tp->stats.rx_bytes += pkt_len;
                        }
-                       received++;
+#ifdef CONFIG_TULIP_NAPI_HW_MITIGATION
+		       received++;
+#endif
 
                        entry = (++tp->cur_rx) % RX_RING_SIZE;
                        if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/4)
@@ -296,17 +298,15 @@
 
 #endif /* CONFIG_TULIP_NAPI_HW_MITIGATION */
 
-         dev->quota -= received;
-         *budget -= received;
-
          tulip_refill_rx(dev);
 
          /* If RX ring is not full we are out of memory. */
-         if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom;
+         if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
+		 goto oom;
 
          /* Remove us from polling list and enable RX intr. */
 
-         netif_rx_complete(dev);
+         netif_rx_complete(dev, napi);
          iowrite32(tulip_tbl[tp->chip_id].valid_intrs, tp->base_addr+CSR7);
 
          /* The last op happens after poll completion. Which means the following:
@@ -320,28 +320,20 @@
           * processed irqs. But it must not result in losing events.
           */
 
-         return 0;
+         return work_done;
 
  not_done:
-         if (!received) {
-
-                 received = dev->quota; /* Not to happen */
-         }
-         dev->quota -= received;
-         *budget -= received;
-
          if (tp->cur_rx - tp->dirty_rx > RX_RING_SIZE/2 ||
              tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
                  tulip_refill_rx(dev);
 
-         if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL) goto oom;
+         if (tp->rx_buffers[tp->dirty_rx % RX_RING_SIZE].skb == NULL)
+		 goto oom;
 
-         return 1;
-
+         return work_done;
 
  oom:    /* Executed with RX ints disabled */
 
-
          /* Start timer, stop polling, but do not enable rx interrupts. */
          mod_timer(&tp->oom_timer, jiffies+1);
 
@@ -350,9 +342,9 @@
           * before we did netif_rx_complete(). See? We would lose it. */
 
          /* remove ourselves from the polling list */
-         netif_rx_complete(dev);
+         netif_rx_complete(dev, napi);
 
-         return 0;
+         return work_done;
 }
 
 #else /* CONFIG_TULIP_NAPI */
@@ -534,7 +526,7 @@
 			rxd++;
 			/* Mask RX intrs and add the device to poll list. */
 			iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7);
-			netif_rx_schedule(dev);
+			netif_rx_schedule(dev, &tp->napi);
 
 			if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass)))
                                break;
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 16f26a8..3f69f53 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -178,18 +178,18 @@
 
 /* The Tulip Rx and Tx buffer descriptors. */
 struct tulip_rx_desc {
-	s32 status;
-	s32 length;
-	u32 buffer1;
-	u32 buffer2;
+	__le32 status;
+	__le32 length;
+	__le32 buffer1;
+	__le32 buffer2;
 };
 
 
 struct tulip_tx_desc {
-	s32 status;
-	s32 length;
-	u32 buffer1;
-	u32 buffer2;		/* We use only buffer 1.  */
+	__le32 status;
+	__le32 length;
+	__le32 buffer1;
+	__le32 buffer2;		/* We use only buffer 1.  */
 };
 
 
@@ -353,6 +353,7 @@
 	int chip_id;
 	int revision;
 	int flags;
+	struct napi_struct napi;
 	struct net_device_stats stats;
 	struct timer_list timer;	/* Media selection timer. */
 	struct timer_list oom_timer;    /* Out of memory timer. */
@@ -429,7 +430,7 @@
 irqreturn_t tulip_interrupt(int irq, void *dev_instance);
 int tulip_refill_rx(struct net_device *dev);
 #ifdef CONFIG_TULIP_NAPI
-int tulip_poll(struct net_device *dev, int *budget);
+int tulip_poll(struct napi_struct *napi, int budget);
 #endif
 
 
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index f87d769..ee08292 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -294,6 +294,10 @@
 	int next_tick = 3*HZ;
 	int i;
 
+#ifdef CONFIG_TULIP_NAPI
+	napi_enable(&tp->napi);
+#endif
+
 	/* Wake the chip from sleep/snooze mode. */
 	tulip_set_power_state (tp, 0, 0);
 
@@ -322,8 +326,8 @@
 	tp->dirty_rx = tp->dirty_tx = 0;
 
 	if (tp->flags & MC_HASH_ONLY) {
-		u32 addr_low = le32_to_cpu(get_unaligned((u32 *)dev->dev_addr));
-		u32 addr_high = le16_to_cpu(get_unaligned((u16 *)(dev->dev_addr+4)));
+		u32 addr_low = le32_to_cpu(get_unaligned((__le32 *)dev->dev_addr));
+		u32 addr_high = le16_to_cpu(get_unaligned((__le16 *)(dev->dev_addr+4)));
 		if (tp->chip_id == AX88140) {
 			iowrite32(0, ioaddr + CSR13);
 			iowrite32(addr_low,  ioaddr + CSR14);
@@ -728,6 +732,10 @@
 
 	flush_scheduled_work();
 
+#ifdef CONFIG_TULIP_NAPI
+	napi_disable(&tp->napi);
+#endif
+
 	del_timer_sync (&tp->timer);
 #ifdef CONFIG_TULIP_NAPI
 	del_timer_sync (&tp->oom_timer);
@@ -1043,12 +1051,11 @@
 				filterbit &= 0x3f;
 				mc_filter[filterbit >> 5] |= 1 << (filterbit & 31);
 				if (tulip_debug > 2) {
-					printk(KERN_INFO "%s: Added filter for %2.2x:%2.2x:%2.2x:"
-						   "%2.2x:%2.2x:%2.2x  %8.8x bit %d.\n", dev->name,
-						   mclist->dmi_addr[0], mclist->dmi_addr[1],
-						   mclist->dmi_addr[2], mclist->dmi_addr[3],
-						   mclist->dmi_addr[4], mclist->dmi_addr[5],
-						   ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit);
+					DECLARE_MAC_BUF(mac);
+					printk(KERN_INFO "%s: Added filter for %s"
+					       "  %8.8x bit %d.\n",
+					       dev->name, print_mac(mac, mclist->dmi_addr),
+					       ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit);
 				}
 			}
 			if (mc_filter[0] == tp->mc_filter[0]  &&
@@ -1248,6 +1255,7 @@
 	const char *chip_name = tulip_tbl[chip_idx].chip_name;
 	unsigned int eeprom_missing = 0;
 	unsigned int force_csr0 = 0;
+	DECLARE_MAC_BUF(mac);
 
 #ifndef MODULE
 	static int did_version;		/* Already printed version info. */
@@ -1337,7 +1345,6 @@
 		return -ENOMEM;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 	if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) {
 		printk (KERN_ERR PFX "%s: I/O region (0x%llx@0x%llx) too small, "
@@ -1436,13 +1443,13 @@
 			do
 				value = ioread32(ioaddr + CSR9);
 			while (value < 0  && --boguscnt > 0);
-			put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i);
+			put_unaligned(cpu_to_le16(value), ((__le16*)dev->dev_addr) + i);
 			sum += value & 0xffff;
 		}
 	} else if (chip_idx == COMET) {
 		/* No need to read the EEPROM. */
-		put_unaligned(cpu_to_le32(ioread32(ioaddr + 0xA4)), (u32 *)dev->dev_addr);
-		put_unaligned(cpu_to_le16(ioread32(ioaddr + 0xA8)), (u16 *)(dev->dev_addr + 4));
+		put_unaligned(cpu_to_le32(ioread32(ioaddr + 0xA4)), (__le32 *)dev->dev_addr);
+		put_unaligned(cpu_to_le16(ioread32(ioaddr + 0xA8)), (__le16 *)(dev->dev_addr + 4));
 		for (i = 0; i < 6; i ++)
 			sum += dev->dev_addr[i];
 	} else {
@@ -1471,14 +1478,6 @@
 			sa_offset = 2;		/* Grrr, damn Matrox boards. */
 			multiport_cnt = 4;
 		}
-#ifdef CONFIG_DDB5477
-               if ((pdev->bus->number == 0) && (PCI_SLOT(pdev->devfn) == 4)) {
-                       /* DDB5477 MAC address in first EEPROM locations. */
-                       sa_offset = 0;
-                       /* No media table either */
-                       tp->flags &= ~HAS_MEDIA_TABLE;
-               }
-#endif
 #ifdef CONFIG_MIPS_COBALT
                if ((pdev->bus->number == 0) &&
                    ((PCI_SLOT(pdev->devfn) == 7) ||
@@ -1614,8 +1613,7 @@
 	dev->tx_timeout = tulip_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 #ifdef CONFIG_TULIP_NAPI
-	dev->poll = tulip_poll;
-	dev->weight = 16;
+	netif_napi_add(dev, &tp->napi, tulip_poll, 16);
 #endif
 	dev->stop = tulip_close;
 	dev->get_stats = tulip_get_stats;
@@ -1641,8 +1639,7 @@
 
 	if (eeprom_missing)
 		printk(" EEPROM not present,");
-	for (i = 0; i < 6; i++)
-		printk("%c%2.2X", i ? ':' : ' ', dev->dev_addr[i]);
+	printk(" %s", print_mac(mac, dev->dev_addr));
 	printk(", IRQ %d.\n", irq);
 
         if (tp->chip_id == PNIC2)
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index ca2548e..76e5561 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -112,13 +112,13 @@
 
 /* Structure/enum declaration ------------------------------- */
 struct tx_desc {
-        u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
+        __le32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
         char *tx_buf_ptr;               /* Data for us */
         struct tx_desc *next_tx_desc;
 } __attribute__(( aligned(32) ));
 
 struct rx_desc {
-	u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */
+	__le32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */
 	struct sk_buff *rx_skb_ptr;	/* Data for us */
 	struct rx_desc *next_rx_desc;
 } __attribute__(( aligned(32) ));
@@ -258,6 +258,7 @@
 	struct uli526x_board_info *db;	/* board information structure */
 	struct net_device *dev;
 	int i, err;
+	DECLARE_MAC_BUF(mac);
 
 	ULI526X_DBUG(0, "uli526x_init_one()", 0);
 
@@ -268,7 +269,6 @@
 	dev = alloc_etherdev(sizeof(*db));
 	if (dev == NULL)
 		return -ENOMEM;
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
@@ -344,7 +344,7 @@
 
 	/* read 64 word srom data */
 	for (i = 0; i < 64; i++)
-		((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i));
+		((__le16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i));
 
 	/* Set Node address */
 	if(((u16 *) db->srom)[0] == 0xffff || ((u16 *) db->srom)[0] == 0)		/* SROM absent, so read MAC address from ID Table */
@@ -373,11 +373,9 @@
 	if (err)
 		goto err_out_res;
 
-	printk(KERN_INFO "%s: ULi M%04lx at pci%s,",dev->name,ent->driver_data >> 16,pci_name(pdev));
-
-	for (i = 0; i < 6; i++)
-		printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
-	printk(", irq %d.\n", dev->irq);
+	printk(KERN_INFO "%s: ULi M%04lx at pci%s, %s, irq %d.\n",
+	       dev->name,ent->driver_data >> 16,pci_name(pdev),
+	       print_mac(mac, dev->dev_addr), dev->irq);
 
 	pci_set_master(pdev);
 
@@ -666,11 +664,6 @@
 	unsigned long ioaddr = dev->base_addr;
 	unsigned long flags;
 
-	if (!dev) {
-		ULI526X_DBUG(1, "uli526x_interrupt() without DEVICE arg", 0);
-		return IRQ_NONE;
-	}
-
 	spin_lock_irqsave(&db->lock, flags);
 	outl(0, ioaddr + DCR7);
 
@@ -1110,19 +1103,15 @@
 
 
 /*
- *	Dynamic reset the ULI526X board
  *	Stop ULI526X board
  *	Free Tx/Rx allocated memory
- *	Reset ULI526X board
- *	Re-initialize ULI526X board
+ *	Init system variable
  */
 
-static void uli526x_dynamic_reset(struct net_device *dev)
+static void uli526x_reset_prepare(struct net_device *dev)
 {
 	struct uli526x_board_info *db = netdev_priv(dev);
 
-	ULI526X_DBUG(0, "uli526x_dynamic_reset()", 0);
-
 	/* Sopt MAC controller */
 	db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);	/* Disable Tx/Rx */
 	update_cr6(db->cr6_data, dev->base_addr);
@@ -1141,6 +1130,22 @@
 	db->link_failed = 1;
 	db->init=1;
 	db->wait_reset = 0;
+}
+
+
+/*
+ *	Dynamic reset the ULI526X board
+ *	Stop ULI526X board
+ *	Free Tx/Rx allocated memory
+ *	Reset ULI526X board
+ *	Re-initialize ULI526X board
+ */
+
+static void uli526x_dynamic_reset(struct net_device *dev)
+{
+	ULI526X_DBUG(0, "uli526x_dynamic_reset()", 0);
+
+	uli526x_reset_prepare(dev);
 
 	/* Re-initialize ULI526X board */
 	uli526x_init(dev);
@@ -1150,6 +1155,88 @@
 }
 
 
+#ifdef CONFIG_PM
+
+/*
+ *	Suspend the interface.
+ */
+
+static int uli526x_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	pci_power_t power_state;
+	int err;
+
+	ULI526X_DBUG(0, "uli526x_suspend", 0);
+
+	if (!netdev_priv(dev))
+		return 0;
+
+	pci_save_state(pdev);
+
+	if (!netif_running(dev))
+		return 0;
+
+	netif_device_detach(dev);
+	uli526x_reset_prepare(dev);
+
+	power_state = pci_choose_state(pdev, state);
+	pci_enable_wake(pdev, power_state, 0);
+	err = pci_set_power_state(pdev, power_state);
+	if (err) {
+		netif_device_attach(dev);
+		/* Re-initialize ULI526X board */
+		uli526x_init(dev);
+		/* Restart upper layer interface */
+		netif_wake_queue(dev);
+	}
+
+	return err;
+}
+
+/*
+ *	Resume the interface.
+ */
+
+static int uli526x_resume(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+	int err;
+
+	ULI526X_DBUG(0, "uli526x_resume", 0);
+
+	if (!netdev_priv(dev))
+		return 0;
+
+	pci_restore_state(pdev);
+
+	if (!netif_running(dev))
+		return 0;
+
+	err = pci_set_power_state(pdev, PCI_D0);
+	if (err) {
+		printk(KERN_WARNING "%s: Could not put device into D0\n",
+			dev->name);
+		return err;
+	}
+
+	netif_device_attach(dev);
+	/* Re-initialize ULI526X board */
+	uli526x_init(dev);
+	/* Restart upper layer interface */
+	netif_wake_queue(dev);
+
+	return 0;
+}
+
+#else /* !CONFIG_PM */
+
+#define uli526x_suspend	NULL
+#define uli526x_resume	NULL
+
+#endif /* !CONFIG_PM */
+
+
 /*
  *	free all allocated rx buffer
  */
@@ -1512,7 +1599,6 @@
 			case ULI526X_100MFD: phy_reg = 0x2100; break;
 			}
 			phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
-       			phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id);
 		}
 	}
 }
@@ -1689,6 +1775,8 @@
 	.id_table	= uli526x_pci_tbl,
 	.probe		= uli526x_init_one,
 	.remove		= __devexit_p(uli526x_remove_one),
+	.suspend	= uli526x_suspend,
+	.resume		= uli526x_resume,
 };
 
 MODULE_AUTHOR("Peer Chen, peer.chen@uli.com.tw");
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 5824f6a..3c8e3b6 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -354,6 +354,7 @@
 	int irq;
 	int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
 	void __iomem *ioaddr;
+	DECLARE_MAC_BUF(mac);
 
 	i = pci_enable_device(pdev);
 	if (i) return i;
@@ -370,7 +371,6 @@
 	dev = alloc_etherdev(sizeof(*np));
 	if (!dev)
 		return -ENOMEM;
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	if (pci_request_regions(pdev, DRV_NAME))
@@ -381,7 +381,7 @@
 		goto err_out_free_res;
 
 	for (i = 0; i < 3; i++)
-		((u16 *)dev->dev_addr)[i] = le16_to_cpu(eeprom_read(ioaddr, i));
+		((__le16 *)dev->dev_addr)[i] = cpu_to_le16(eeprom_read(ioaddr, i));
 
 	/* Reset the chip to erase previous misconfiguration.
 	   No hold time required! */
@@ -434,11 +434,9 @@
 	if (i)
 		goto err_out_cleardev;
 
-	printk(KERN_INFO "%s: %s at %p, ",
-		   dev->name, pci_id_tbl[chip_idx].name, ioaddr);
-	for (i = 0; i < 5; i++)
-			printk("%2.2x:", dev->dev_addr[i]);
-	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+	printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n",
+	       dev->name, pci_id_tbl[chip_idx].name, ioaddr,
+	       print_mac(mac, dev->dev_addr), irq);
 
 	if (np->drv_flags & CanHaveMII) {
 		int phy, phy_idx = 0;
@@ -1246,16 +1244,16 @@
 			}
 #ifndef final_version				/* Remove after testing. */
 			/* You will want this info for the initial debug. */
-			if (debug > 5)
-				printk(KERN_DEBUG "  Rx data %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:"
-					   "%2.2x %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x %2.2x%2.2x "
-					   "%d.%d.%d.%d.\n",
-					   skb->data[0], skb->data[1], skb->data[2], skb->data[3],
-					   skb->data[4], skb->data[5], skb->data[6], skb->data[7],
-					   skb->data[8], skb->data[9], skb->data[10],
-					   skb->data[11], skb->data[12], skb->data[13],
-					   skb->data[14], skb->data[15], skb->data[16],
-					   skb->data[17]);
+			if (debug > 5) {
+				DECLARE_MAC_BUF(mac);
+				DECLARE_MAC_BUF(mac2);
+
+				printk(KERN_DEBUG "  Rx data %s %s"
+				       " %2.2x%2.2x %d.%d.%d.%d.\n",
+				       print_mac(mac, &skb->data[0]), print_mac(mac2, &skb->data[6]),
+				       skb->data[12], skb->data[13],
+				       skb->data[14], skb->data[15], skb->data[16], skb->data[17]);
+			}
 #endif
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
@@ -1452,8 +1450,6 @@
 	.get_link		= netdev_get_link,
 	.get_msglevel		= netdev_get_msglevel,
 	.set_msglevel		= netdev_set_msglevel,
-	.get_sg			= ethtool_op_get_sg,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
 };
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index 16a54e6..70befe3 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -252,7 +252,6 @@
 		goto tx_buf_fail;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 
@@ -271,7 +270,6 @@
 	dev->hard_start_xmit = &xircom_start_xmit;
 	dev->stop = &xircom_close;
 	dev->get_stats = &xircom_get_stats;
-	dev->priv = private;
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	dev->poll_controller = &xircom_poll_controller;
 #endif
@@ -1076,6 +1074,7 @@
 	unsigned char j, tuple, link, data_id, data_count;
 	unsigned long flags;
 	int i;
+	DECLARE_MAC_BUF(mac);
 
 	enter("read_mac_address");
 
@@ -1105,11 +1104,7 @@
 		}
 	}
 	spin_unlock_irqrestore(&card->lock, flags);
-#ifdef DEBUG
-	for (i = 0; i < 6; i++)
-		printk("%c%2.2X", i ? ':' : ' ', card->dev->dev_addr[i]);
-	printk("\n");
-#endif
+	pr_debug(" %s\n", print_mac(mac, card->dev->dev_addr));
 	leave("read_mac_address");
 }
 
diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c
index fc439f3..c3f8e30 100644
--- a/drivers/net/tulip/xircom_tulip_cb.c
+++ b/drivers/net/tulip/xircom_tulip_cb.c
@@ -547,7 +547,6 @@
 		printk (KERN_ERR DRV_NAME "%d: cannot alloc etherdev, aborting\n", board_idx);
 		return -ENOMEM;
 	}
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	dev->base_addr = ioaddr;
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 62b2b30..1f76446 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -62,6 +62,7 @@
 #include <linux/if_ether.h>
 #include <linux/if_tun.h>
 #include <linux/crc32.h>
+#include <net/net_namespace.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -109,7 +110,7 @@
 
 			/* We won't see all dropped packets individually, so overrun
 			 * error is more appropriate. */
-			tun->stats.tx_fifo_errors++;
+			dev->stats.tx_fifo_errors++;
 		} else {
 			/* Single queue mode.
 			 * Driver handles dropping of all packets itself. */
@@ -128,7 +129,7 @@
 	return 0;
 
 drop:
-	tun->stats.tx_dropped++;
+	dev->stats.tx_dropped++;
 	kfree_skb(skb);
 	return 0;
 }
@@ -158,23 +159,28 @@
 	struct tun_struct *tun = netdev_priv(dev);
 	const struct dev_mc_list *mclist;
 	int i;
+	DECLARE_MAC_BUF(mac);
 	DBG(KERN_DEBUG "%s: tun_net_mclist: mc_count %d\n",
 			dev->name, dev->mc_count);
 	memset(tun->chr_filter, 0, sizeof tun->chr_filter);
 	for (i = 0, mclist = dev->mc_list; i < dev->mc_count && mclist != NULL;
 			i++, mclist = mclist->next) {
 		add_multi(tun->net_filter, mclist->dmi_addr);
-		DBG(KERN_DEBUG "%s: tun_net_mclist: %x:%x:%x:%x:%x:%x\n",
-				dev->name,
-				mclist->dmi_addr[0], mclist->dmi_addr[1], mclist->dmi_addr[2],
-				mclist->dmi_addr[3], mclist->dmi_addr[4], mclist->dmi_addr[5]);
+		DBG(KERN_DEBUG "%s: tun_net_mclist: %s\n",
+		    dev->name, print_mac(mac, mclist->dmi_addr));
 	}
 }
 
-static struct net_device_stats *tun_net_stats(struct net_device *dev)
+#define MIN_MTU 68
+#define MAX_MTU 65535
+
+static int
+tun_net_change_mtu(struct net_device *dev, int new_mtu)
 {
-	struct tun_struct *tun = netdev_priv(dev);
-	return &tun->stats;
+	if (new_mtu < MIN_MTU || new_mtu + dev->hard_header_len > MAX_MTU)
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
 }
 
 /* Initialize net device. */
@@ -188,6 +194,7 @@
 		dev->hard_header_len = 0;
 		dev->addr_len = 0;
 		dev->mtu = 1500;
+		dev->change_mtu = tun_net_change_mtu;
 
 		/* Zero header length */
 		dev->type = ARPHRD_NONE;
@@ -200,6 +207,7 @@
 		dev->set_multicast_list = tun_net_mclist;
 
 		ether_setup(dev);
+		dev->change_mtu = tun_net_change_mtu;
 
 		/* random address already created for us by tun_set_iff, use it */
 		memcpy(dev->dev_addr, tun->dev_addr, min(sizeof(tun->dev_addr), sizeof(dev->dev_addr)) );
@@ -249,14 +257,14 @@
 		align = NET_IP_ALIGN;
 
 	if (!(skb = alloc_skb(len + align, GFP_KERNEL))) {
-		tun->stats.rx_dropped++;
+		tun->dev->stats.rx_dropped++;
 		return -ENOMEM;
 	}
 
 	if (align)
 		skb_reserve(skb, align);
 	if (memcpy_fromiovec(skb_put(skb, len), iv, len)) {
-		tun->stats.rx_dropped++;
+		tun->dev->stats.rx_dropped++;
 		kfree_skb(skb);
 		return -EFAULT;
 	}
@@ -278,8 +286,8 @@
 	netif_rx_ni(skb);
 	tun->dev->last_rx = jiffies;
 
-	tun->stats.rx_packets++;
-	tun->stats.rx_bytes += len;
+	tun->dev->stats.rx_packets++;
+	tun->dev->stats.rx_bytes += len;
 
 	return count;
 }
@@ -335,8 +343,8 @@
 	skb_copy_datagram_iovec(skb, 0, iv, len);
 	total += len;
 
-	tun->stats.tx_packets++;
-	tun->stats.tx_bytes += len;
+	tun->dev->stats.tx_packets++;
+	tun->dev->stats.tx_bytes += len;
 
 	return total;
 }
@@ -349,6 +357,7 @@
 	DECLARE_WAITQUEUE(wait, current);
 	struct sk_buff *skb;
 	ssize_t len, ret = 0;
+	DECLARE_MAC_BUF(mac);
 
 	if (!tun)
 		return -EBADFD;
@@ -403,16 +412,14 @@
 				  (addr[0] == 0x33 && addr[1] == 0x33)) &&
 				 ((tun->if_flags & IFF_ALLMULTI) ||
 				  (tun->chr_filter[bit_nr >> 5] & (1 << (bit_nr & 31)))))) {
-			DBG(KERN_DEBUG "%s: tun_chr_readv: accepted: %x:%x:%x:%x:%x:%x\n",
-					tun->dev->name, addr[0], addr[1], addr[2],
-					addr[3], addr[4], addr[5]);
+			DBG(KERN_DEBUG "%s: tun_chr_readv: accepted: %s\n",
+					tun->dev->name, print_mac(mac, addr));
 			ret = tun_put_user(tun, skb, (struct iovec *) iv, len);
 			kfree_skb(skb);
 			break;
 		} else {
-			DBG(KERN_DEBUG "%s: tun_chr_readv: rejected: %x:%x:%x:%x:%x:%x\n",
-					tun->dev->name, addr[0], addr[1], addr[2],
-					addr[3], addr[4], addr[5]);
+			DBG(KERN_DEBUG "%s: tun_chr_readv: rejected: %s\n",
+					tun->dev->name, print_mac(mac, addr));
 			kfree_skb(skb);
 			continue;
 		}
@@ -434,11 +441,9 @@
 	tun->owner = -1;
 	tun->group = -1;
 
-	SET_MODULE_OWNER(dev);
 	dev->open = tun_net_open;
 	dev->hard_start_xmit = tun_net_xmit;
 	dev->stop = tun_net_close;
-	dev->get_stats = tun_net_stats;
 	dev->ethtool_ops = &tun_ethtool_ops;
 	dev->destructor = free_netdev;
 }
@@ -475,7 +480,7 @@
 		     !capable(CAP_NET_ADMIN))
 			return -EPERM;
 	}
-	else if (__dev_get_by_name(ifr->ifr_name))
+	else if (__dev_get_by_name(&init_net, ifr->ifr_name))
 		return -EINVAL;
 	else {
 		char *name;
@@ -557,6 +562,7 @@
 	struct tun_struct *tun = file->private_data;
 	void __user* argp = (void __user*)arg;
 	struct ifreq ifr;
+	DECLARE_MAC_BUF(mac);
 
 	if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89)
 		if (copy_from_user(&ifr, argp, sizeof ifr))
@@ -685,22 +691,16 @@
 		/** Add the specified group to the character device's multicast filter
 		 * list. */
 		add_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data);
-		DBG(KERN_DEBUG "%s: add multi: %x:%x:%x:%x:%x:%x\n",
-				tun->dev->name,
-				(u8)ifr.ifr_hwaddr.sa_data[0], (u8)ifr.ifr_hwaddr.sa_data[1],
-				(u8)ifr.ifr_hwaddr.sa_data[2], (u8)ifr.ifr_hwaddr.sa_data[3],
-				(u8)ifr.ifr_hwaddr.sa_data[4], (u8)ifr.ifr_hwaddr.sa_data[5]);
+		DBG(KERN_DEBUG "%s: add multi: %s\n",
+		    tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data));
 		return 0;
 
 	case SIOCDELMULTI:
 		/** Remove the specified group from the character device's multicast
 		 * filter list. */
 		del_multi(tun->chr_filter, ifr.ifr_hwaddr.sa_data);
-		DBG(KERN_DEBUG "%s: del multi: %x:%x:%x:%x:%x:%x\n",
-				tun->dev->name,
-				(u8)ifr.ifr_hwaddr.sa_data[0], (u8)ifr.ifr_hwaddr.sa_data[1],
-				(u8)ifr.ifr_hwaddr.sa_data[2], (u8)ifr.ifr_hwaddr.sa_data[3],
-				(u8)ifr.ifr_hwaddr.sa_data[4], (u8)ifr.ifr_hwaddr.sa_data[5]);
+		DBG(KERN_DEBUG "%s: del multi: %s\n",
+		    tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data));
 		return 0;
 
 	default:
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 0358720..72e5e9b 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -284,6 +284,7 @@
 	struct basic_ring	rxLoRing;
 	struct pci_dev *	pdev;
 	struct net_device *	dev;
+	struct napi_struct	napi;
 	spinlock_t		state_lock;
 	struct vlan_group *	vlgrp;
 	struct basic_ring	rxHiRing;
@@ -299,9 +300,9 @@
 	const char *		name;
 	struct typhoon_shared *	shared;
 	dma_addr_t		shared_dma;
-	u16			xcvr_select;
-	u16			wol_events;
-	u32			offload;
+	__le16			xcvr_select;
+	__le16			wol_events;
+	__le32			offload;
 
 	/* unused stuff (future use) */
 	int			capabilities;
@@ -827,7 +828,7 @@
 		first_txd->processFlags |=
 		    TYPHOON_TX_PF_INSERT_VLAN | TYPHOON_TX_PF_VLAN_PRIORITY;
 		first_txd->processFlags |=
-		    cpu_to_le32(htons(vlan_tx_tag_get(skb)) <<
+		    cpu_to_le32(ntohs(vlan_tx_tag_get(skb)) <<
 				TYPHOON_TX_PF_VLAN_TAG_SHIFT);
 	}
 
@@ -919,7 +920,7 @@
 	struct typhoon *tp = netdev_priv(dev);
 	struct cmd_desc xp_cmd;
 	u32 mc_filter[2];
-	u16 filter;
+	__le16 filter;
 
 	filter = TYPHOON_RX_FILTER_DIRECTED | TYPHOON_RX_FILTER_BROADCAST;
 	if(dev->flags & IFF_PROMISC) {
@@ -1130,7 +1131,7 @@
 {
 	struct typhoon *tp = netdev_priv(dev);
 	struct cmd_desc xp_cmd;
-	int xcvr;
+	__le16 xcvr;
 	int err;
 
 	err = -EINVAL;
@@ -1235,11 +1236,8 @@
 	.set_wol		= typhoon_set_wol,
 	.get_link		= ethtool_op_get_link,
 	.get_rx_csum		= typhoon_get_rx_csum,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
 	.set_tx_csum		= ethtool_op_set_tx_csum,
-	.get_sg			= ethtool_op_get_sg,
 	.set_sg			= ethtool_op_set_sg,
-	.get_tso		= ethtool_op_get_tso,
 	.set_tso		= ethtool_op_set_tso,
 	.get_ringparam		= typhoon_get_ringparam,
 };
@@ -1538,7 +1536,7 @@
 
 static u32
 typhoon_clean_tx(struct typhoon *tp, struct transmit_ring *txRing,
-			volatile u32 * index)
+			volatile __le32 * index)
 {
 	u32 lastRead = txRing->lastRead;
 	struct tx_desc *tx;
@@ -1574,7 +1572,7 @@
 
 static void
 typhoon_tx_complete(struct typhoon *tp, struct transmit_ring *txRing,
-			volatile u32 * index)
+			volatile __le32 * index)
 {
 	u32 lastRead;
 	int numDesc = MAX_SKB_FRAGS + 1;
@@ -1664,8 +1662,8 @@
 }
 
 static int
-typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile u32 * ready,
-	   volatile u32 * cleared, int budget)
+typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile __le32 * ready,
+	   volatile __le32 * cleared, int budget)
 {
 	struct rx_desc *rx;
 	struct sk_buff *skb, *new_skb;
@@ -1675,7 +1673,7 @@
 	u32 rxaddr;
 	int pkt_len;
 	u32 idx;
-	u32 csum_bits;
+	__le32 csum_bits;
 	int received;
 
 	received = 0;
@@ -1759,12 +1757,12 @@
 }
 
 static int
-typhoon_poll(struct net_device *dev, int *total_budget)
+typhoon_poll(struct napi_struct *napi, int budget)
 {
-	struct typhoon *tp = netdev_priv(dev);
+	struct typhoon *tp = container_of(napi, struct typhoon, napi);
+	struct net_device *dev = tp->dev;
 	struct typhoon_indexes *indexes = tp->indexes;
-	int orig_budget = *total_budget;
-	int budget, work_done, done;
+	int work_done;
 
 	rmb();
 	if(!tp->awaiting_resp && indexes->respReady != indexes->respCleared)
@@ -1773,30 +1771,16 @@
 	if(le32_to_cpu(indexes->txLoCleared) != tp->txLoRing.lastRead)
 		typhoon_tx_complete(tp, &tp->txLoRing, &indexes->txLoCleared);
 
-	if(orig_budget > dev->quota)
-		orig_budget = dev->quota;
-
-	budget = orig_budget;
 	work_done = 0;
-	done = 1;
 
 	if(indexes->rxHiCleared != indexes->rxHiReady) {
-		work_done = typhoon_rx(tp, &tp->rxHiRing, &indexes->rxHiReady,
+		work_done += typhoon_rx(tp, &tp->rxHiRing, &indexes->rxHiReady,
 			   		&indexes->rxHiCleared, budget);
-		budget -= work_done;
 	}
 
 	if(indexes->rxLoCleared != indexes->rxLoReady) {
 		work_done += typhoon_rx(tp, &tp->rxLoRing, &indexes->rxLoReady,
-			   		&indexes->rxLoCleared, budget);
-	}
-
-	if(work_done) {
-		*total_budget -= work_done;
-		dev->quota -= work_done;
-
-		if(work_done >= orig_budget)
-			done = 0;
+					&indexes->rxLoCleared, budget - work_done);
 	}
 
 	if(le32_to_cpu(indexes->rxBuffCleared) == tp->rxBuffRing.lastWrite) {
@@ -1804,14 +1788,14 @@
 		typhoon_fill_free_ring(tp);
 	}
 
-	if(done) {
-		netif_rx_complete(dev);
+	if (work_done < budget) {
+		netif_rx_complete(dev, napi);
 		iowrite32(TYPHOON_INTR_NONE,
 				tp->ioaddr + TYPHOON_REG_INTR_MASK);
 		typhoon_post_pci_writes(tp->ioaddr);
 	}
 
-	return (done ? 0 : 1);
+	return work_done;
 }
 
 static irqreturn_t
@@ -1828,10 +1812,10 @@
 
 	iowrite32(intr_status, ioaddr + TYPHOON_REG_INTR_STATUS);
 
-	if(netif_rx_schedule_prep(dev)) {
+	if (netif_rx_schedule_prep(dev, &tp->napi)) {
 		iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
 		typhoon_post_pci_writes(ioaddr);
-		__netif_rx_schedule(dev);
+		__netif_rx_schedule(dev, &tp->napi);
 	} else {
 		printk(KERN_ERR "%s: Error, poll already scheduled\n",
                        dev->name);
@@ -1856,7 +1840,7 @@
 }
 
 static int
-typhoon_sleep(struct typhoon *tp, pci_power_t state, u16 events)
+typhoon_sleep(struct typhoon *tp, pci_power_t state, __le16 events)
 {
 	struct pci_dev *pdev = tp->pdev;
 	void __iomem *ioaddr = tp->ioaddr;
@@ -1944,8 +1928,8 @@
 		goto error_out;
 
 	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_MAC_ADDRESS);
-	xp_cmd.parm1 = cpu_to_le16(ntohs(*(u16 *)&dev->dev_addr[0]));
-	xp_cmd.parm2 = cpu_to_le32(ntohl(*(u32 *)&dev->dev_addr[2]));
+	xp_cmd.parm1 = cpu_to_le16(ntohs(*(__be16 *)&dev->dev_addr[0]));
+	xp_cmd.parm2 = cpu_to_le32(ntohl(*(__be32 *)&dev->dev_addr[2]));
 	err = typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL);
 	if(err < 0)
 		goto error_out;
@@ -2119,9 +2103,13 @@
 	if(err < 0)
 		goto out_sleep;
 
+	napi_enable(&tp->napi);
+
 	err = typhoon_start_runtime(tp);
-	if(err < 0)
+	if(err < 0) {
+		napi_disable(&tp->napi);
 		goto out_irq;
+	}
 
 	netif_start_queue(dev);
 	return 0;
@@ -2150,6 +2138,7 @@
 	struct typhoon *tp = netdev_priv(dev);
 
 	netif_stop_queue(dev);
+	napi_disable(&tp->napi);
 
 	if(typhoon_stop_runtime(tp, WaitSleep) < 0)
 		printk(KERN_ERR "%s: unable to stop runtime\n", dev->name);
@@ -2240,8 +2229,8 @@
 	}
 
 	INIT_COMMAND_NO_RESPONSE(&xp_cmd, TYPHOON_CMD_SET_MAC_ADDRESS);
-	xp_cmd.parm1 = cpu_to_le16(ntohs(*(u16 *)&dev->dev_addr[0]));
-	xp_cmd.parm2 = cpu_to_le32(ntohl(*(u32 *)&dev->dev_addr[2]));
+	xp_cmd.parm1 = cpu_to_le16(ntohs(*(__be16 *)&dev->dev_addr[0]));
+	xp_cmd.parm2 = cpu_to_le32(ntohl(*(__be32 *)&dev->dev_addr[2]));
 	if(typhoon_issue_command(tp, 1, &xp_cmd, 0, NULL) < 0) {
 		printk(KERN_ERR "%s: unable to set mac address in suspend\n",
 				dev->name);
@@ -2327,8 +2316,8 @@
 	dma_addr_t shared_dma;
 	struct cmd_desc xp_cmd;
 	struct resp_desc xp_resp[3];
-	int i;
 	int err = 0;
+	DECLARE_MAC_BUF(mac);
 
 	if(!did_version++)
 		printk(KERN_INFO "%s", version);
@@ -2340,7 +2329,6 @@
 		err = -ENOMEM;
 		goto error_out;
 	}
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	err = pci_enable_device(pdev);
@@ -2477,8 +2465,8 @@
 		goto error_out_reset;
 	}
 
-	*(u16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp[0].parm1));
-	*(u32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2));
+	*(__be16 *)&dev->dev_addr[0] = htons(le16_to_cpu(xp_resp[0].parm1));
+	*(__be32 *)&dev->dev_addr[2] = htonl(le32_to_cpu(xp_resp[0].parm2));
 
 	if(!is_valid_ether_addr(dev->dev_addr)) {
 		printk(ERR_PFX "%s: Could not obtain valid ethernet address, "
@@ -2521,8 +2509,7 @@
 	dev->stop		= typhoon_close;
 	dev->set_multicast_list	= typhoon_set_rx_mode;
 	dev->tx_timeout		= typhoon_tx_timeout;
-	dev->poll		= typhoon_poll;
-	dev->weight		= 16;
+	netif_napi_add(dev, &tp->napi, typhoon_poll, 16);
 	dev->watchdog_timeo	= TX_TIMEOUT;
 	dev->get_stats		= typhoon_get_stats;
 	dev->set_mac_address	= typhoon_set_mac_address;
@@ -2545,13 +2532,11 @@
 
 	pci_set_drvdata(pdev, dev);
 
-	printk(KERN_INFO "%s: %s at %s 0x%llx, ",
+	printk(KERN_INFO "%s: %s at %s 0x%llx, %s\n",
 	       dev->name, typhoon_card_info[card_id].name,
 	       use_mmio ? "MMIO" : "IO",
-	       (unsigned long long)pci_resource_start(pdev, use_mmio));
-	for(i = 0; i < 5; i++)
-		printk("%2.2x:", dev->dev_addr[i]);
-	printk("%2.2x\n", dev->dev_addr[i]);
+	       (unsigned long long)pci_resource_start(pdev, use_mmio),
+	       print_mac(mac, dev->dev_addr));
 
 	/* xp_resp still contains the response to the READ_VERSIONS command.
 	 * For debugging, let the user know what version he has.
diff --git a/drivers/net/typhoon.h b/drivers/net/typhoon.h
index 2f14a05..19df208 100644
--- a/drivers/net/typhoon.h
+++ b/drivers/net/typhoon.h
@@ -64,19 +64,19 @@
  */
 struct typhoon_indexes {
 	/* The first four are written by the host, and read by the NIC */
-	volatile u32 rxHiCleared;
-	volatile u32 rxLoCleared;
-	volatile u32 rxBuffReady;
-	volatile u32 respCleared;
+	volatile __le32 rxHiCleared;
+	volatile __le32 rxLoCleared;
+	volatile __le32 rxBuffReady;
+	volatile __le32 respCleared;
 
 	/* The remaining are written by the NIC, and read by the host */
-	volatile u32 txLoCleared;
-	volatile u32 txHiCleared;
-	volatile u32 rxLoReady;
-	volatile u32 rxBuffCleared;
-	volatile u32 cmdCleared;
-	volatile u32 respReady;
-	volatile u32 rxHiReady;
+	volatile __le32 txLoCleared;
+	volatile __le32 txHiCleared;
+	volatile __le32 rxLoReady;
+	volatile __u32 rxBuffCleared;	/* AV: really? */
+	volatile __le32 cmdCleared;
+	volatile __le32 respReady;
+	volatile __le32 rxHiReady;
 } __attribute__ ((packed));
 
 /* The host<->Typhoon interface
@@ -100,31 +100,31 @@
  * be zero.
  */
 struct typhoon_interface {
-	u32 ringIndex;
-	u32 ringIndexHi;
-	u32 txLoAddr;
-	u32 txLoAddrHi;
-	u32 txLoSize;
-	u32 txHiAddr;
-	u32 txHiAddrHi;
-	u32 txHiSize;
-	u32 rxLoAddr;
-	u32 rxLoAddrHi;
-	u32 rxLoSize;
-	u32 rxBuffAddr;
-	u32 rxBuffAddrHi;
-	u32 rxBuffSize;
-	u32 cmdAddr;
-	u32 cmdAddrHi;
-	u32 cmdSize;
-	u32 respAddr;
-	u32 respAddrHi;
-	u32 respSize;
-	u32 zeroAddr;
-	u32 zeroAddrHi;
-	u32 rxHiAddr;
-	u32 rxHiAddrHi;
-	u32 rxHiSize;
+	__le32 ringIndex;
+	__le32 ringIndexHi;
+	__le32 txLoAddr;
+	__le32 txLoAddrHi;
+	__le32 txLoSize;
+	__le32 txHiAddr;
+	__le32 txHiAddrHi;
+	__le32 txHiSize;
+	__le32 rxLoAddr;
+	__le32 rxLoAddrHi;
+	__le32 rxLoSize;
+	__le32 rxBuffAddr;
+	__le32 rxBuffAddrHi;
+	__le32 rxBuffSize;
+	__le32 cmdAddr;
+	__le32 cmdAddrHi;
+	__le32 cmdSize;
+	__le32 respAddr;
+	__le32 respAddrHi;
+	__le32 respSize;
+	__le32 zeroAddr;
+	__le32 zeroAddrHi;
+	__le32 rxHiAddr;
+	__le32 rxHiAddrHi;
+	__le32 rxHiSize;
 } __attribute__ ((packed));
 
 /* The Typhoon transmit/fragment descriptor
@@ -165,10 +165,10 @@
 #define TYPHOON_RX_ERROR	0x40
 #define TYPHOON_DESC_VALID	0x80
 	u8  numDesc;
-	u16 len;
+	__le16 len;
 	u32 addr;
 	u32 addrHi;
-	u32 processFlags;
+	__le32 processFlags;
 #define TYPHOON_TX_PF_NO_CRC		__constant_cpu_to_le32(0x00000001)
 #define TYPHOON_TX_PF_IP_CHKSUM		__constant_cpu_to_le32(0x00000002)
 #define TYPHOON_TX_PF_TCP_CHKSUM	__constant_cpu_to_le32(0x00000004)
@@ -197,12 +197,12 @@
 struct tcpopt_desc {
 	u8  flags;
 	u8  numDesc;
-	u16 mss_flags;
+	__le16 mss_flags;
 #define TYPHOON_TSO_FIRST		__constant_cpu_to_le16(0x1000)
 #define TYPHOON_TSO_LAST		__constant_cpu_to_le16(0x2000)
-	u32 respAddrLo;
-	u32 bytesTx;
-	u32 status;
+	__le32 respAddrLo;
+	__le32 bytesTx;
+	__le32 status;
 } __attribute__ ((packed));
 
 /* The IPSEC Offload descriptor
@@ -216,12 +216,12 @@
 struct ipsec_desc {
 	u8  flags;
 	u8  numDesc;
-	u16 ipsecFlags;
+	__le16 ipsecFlags;
 #define TYPHOON_IPSEC_GEN_IV	__constant_cpu_to_le16(0x0000)
 #define TYPHOON_IPSEC_USE_IV	__constant_cpu_to_le16(0x0001)
-	u32 sa1;
-	u32 sa2;
-	u32 reserved;
+	__le32 sa1;
+	__le32 sa2;
+	__le32 reserved;
 } __attribute__ ((packed));
 
 /* The Typhoon receive descriptor (Updated by NIC)
@@ -239,10 +239,10 @@
 struct rx_desc {
 	u8  flags;
 	u8  numDesc;
-	u16 frameLen;
+	__le16 frameLen;
 	u32 addr;
 	u32 addrHi;
-	u32 rxStatus;
+	__le32 rxStatus;
 #define TYPHOON_RX_ERR_INTERNAL		__constant_cpu_to_le32(0x00000000)
 #define TYPHOON_RX_ERR_FIFO_UNDERRUN	__constant_cpu_to_le32(0x00000001)
 #define TYPHOON_RX_ERR_BAD_SSD		__constant_cpu_to_le32(0x00000002)
@@ -264,10 +264,10 @@
 #define TYPHOON_RX_IP_CHK_GOOD		__constant_cpu_to_le32(0x00000100)
 #define TYPHOON_RX_TCP_CHK_GOOD		__constant_cpu_to_le32(0x00000200)
 #define TYPHOON_RX_UDP_CHK_GOOD		__constant_cpu_to_le32(0x00000400)
-	u16 filterResults;
+	__le16 filterResults;
 #define TYPHOON_RX_FILTER_MASK		__constant_cpu_to_le16(0x7fff)
 #define TYPHOON_RX_FILTERED		__constant_cpu_to_le16(0x8000)
-	u16 ipsecResults;
+	__le16 ipsecResults;
 #define TYPHOON_RX_OUTER_AH_GOOD	__constant_cpu_to_le16(0x0001)
 #define TYPHOON_RX_OUTER_ESP_GOOD	__constant_cpu_to_le16(0x0002)
 #define TYPHOON_RX_INNER_AH_GOOD	__constant_cpu_to_le16(0x0004)
@@ -278,7 +278,7 @@
 #define TYPHOON_RX_INNER_ESP_FAIL	__constant_cpu_to_le16(0x0080)
 #define TYPHOON_RX_UNKNOWN_SA		__constant_cpu_to_le16(0x0100)
 #define TYPHOON_RX_ESP_FORMAT_ERR	__constant_cpu_to_le16(0x0200)
-	u32 vlanTag;
+	__be32 vlanTag;
 } __attribute__ ((packed));
 
 /* The Typhoon free buffer descriptor, used to give a buffer to the NIC
@@ -292,8 +292,8 @@
  * from the NIC
  */
 struct rx_free {
-	u32 physAddr;
-	u32 physAddrHi;
+	__le32 physAddr;
+	__le32 physAddrHi;
 	u32 virtAddr;
 	u32 virtAddrHi;
 } __attribute__ ((packed));
@@ -312,7 +312,7 @@
 struct cmd_desc {
 	u8  flags;
 	u8  numDesc;
-	u16 cmd;
+	__le16 cmd;
 #define TYPHOON_CMD_TX_ENABLE		__constant_cpu_to_le16(0x0001)
 #define TYPHOON_CMD_TX_DISABLE		__constant_cpu_to_le16(0x0002)
 #define TYPHOON_CMD_RX_ENABLE		__constant_cpu_to_le16(0x0003)
@@ -339,9 +339,9 @@
 #define TYPHOON_CMD_GET_IPSEC_ENABLE	__constant_cpu_to_le16(0x0067)
 #define TYPHOON_CMD_GET_CMD_LVL		__constant_cpu_to_le16(0x0069)
 	u16 seqNo;
-	u16 parm1;
-	u32 parm2;
-	u32 parm3;
+	__le16 parm1;
+	__le32 parm2;
+	__le32 parm3;
 } __attribute__ ((packed));
 
 /* The Typhoon response descriptor, see command descriptor for details
@@ -349,11 +349,11 @@
 struct resp_desc {
 	u8  flags;
 	u8  numDesc;
-	u16 cmd;
-	u16 seqNo;
-	u16 parm1;
-	u32 parm2;
-	u32 parm3;
+	__le16 cmd;
+	__le16 seqNo;
+	__le16 parm1;
+	__le32 parm2;
+	__le32 parm3;
 } __attribute__ ((packed));
 
 #define INIT_COMMAND_NO_RESPONSE(x, command)				\
@@ -386,31 +386,31 @@
 struct stats_resp {
 	u8  flags;
 	u8  numDesc;
-	u16 cmd;
-	u16 seqNo;
-	u16 unused;
-	u32 txPackets;
-	u64 txBytes;
-	u32 txDeferred;
-	u32 txLateCollisions;
-	u32 txCollisions;
-	u32 txCarrierLost;
-	u32 txMultipleCollisions;
-	u32 txExcessiveCollisions;
-	u32 txFifoUnderruns;
-	u32 txMulticastTxOverflows;
-	u32 txFiltered;
-	u32 rxPacketsGood;
-	u64 rxBytesGood;
-	u32 rxFifoOverruns;
-	u32 BadSSD;
-	u32 rxCrcErrors;
-	u32 rxOversized;
-	u32 rxBroadcast;
-	u32 rxMulticast;
-	u32 rxOverflow;
-	u32 rxFiltered;
-	u32 linkStatus;
+	__le16 cmd;
+	__le16 seqNo;
+	__le16 unused;
+	__le32 txPackets;
+	__le64 txBytes;
+	__le32 txDeferred;
+	__le32 txLateCollisions;
+	__le32 txCollisions;
+	__le32 txCarrierLost;
+	__le32 txMultipleCollisions;
+	__le32 txExcessiveCollisions;
+	__le32 txFifoUnderruns;
+	__le32 txMulticastTxOverflows;
+	__le32 txFiltered;
+	__le32 rxPacketsGood;
+	__le64 rxBytesGood;
+	__le32 rxFifoOverruns;
+	__le32 BadSSD;
+	__le32 rxCrcErrors;
+	__le32 rxOversized;
+	__le32 rxBroadcast;
+	__le32 rxMulticast;
+	__le32 rxOverflow;
+	__le32 rxFiltered;
+	__le32 linkStatus;
 #define TYPHOON_LINK_STAT_MASK		__constant_cpu_to_le32(0x00000001)
 #define TYPHOON_LINK_GOOD		__constant_cpu_to_le32(0x00000001)
 #define TYPHOON_LINK_BAD		__constant_cpu_to_le32(0x00000000)
@@ -420,8 +420,8 @@
 #define TYPHOON_LINK_DUPLEX_MASK	__constant_cpu_to_le32(0x00000004)
 #define TYPHOON_LINK_FULL_DUPLEX	__constant_cpu_to_le32(0x00000004)
 #define TYPHOON_LINK_HALF_DUPLEX	__constant_cpu_to_le32(0x00000000)
-	u32 unused2;
-	u32 unused3;
+	__le32 unused2;
+	__le32 unused3;
 } __attribute__ ((packed));
 
 /* TYPHOON_CMD_XCVR_SELECT xcvr values (resp.parm1)
@@ -509,17 +509,17 @@
  */
 struct typhoon_file_header {
 	u8  tag[8];
-	u32 version;
-	u32 numSections;
-	u32 startAddr;
-	u32 hmacDigest[5];
+	__le32 version;
+	__le32 numSections;
+	__le32 startAddr;
+	__le32 hmacDigest[5];
 } __attribute__ ((packed));
 
 struct typhoon_section_header {
-	u32 len;
+	__le32 len;
 	u16 checksum;
 	u16 reserved;
-	u32 startAddr;
+	__le32 startAddr;
 } __attribute__ ((packed));
 
 /* The Typhoon Register offsets
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index e4736a3..d00e7d4 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -43,10 +43,6 @@
 
 #undef DEBUG
 
-#define DRV_DESC "QE UCC Gigabit Ethernet Controller"
-#define DRV_NAME "ucc_geth"
-#define DRV_VERSION "1.1"
-
 #define ugeth_printk(level, format, arg...)  \
         printk(level format "\n", ## arg)
 
@@ -64,9 +60,19 @@
 #else
 #define ugeth_vdbg(fmt, args...) do { } while (0)
 #endif				/* UGETH_VERBOSE_DEBUG */
+#define UGETH_MSG_DEFAULT	(NETIF_MSG_IFUP << 1 ) - 1
 
+void uec_set_ethtool_ops(struct net_device *netdev);
+	
 static DEFINE_SPINLOCK(ugeth_lock);
 
+static struct {
+	u32 msg_enable;
+} debug = { -1 };
+
+module_param_named(debug, debug.msg_enable, int, 0);
+MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 0xffff=all)");
+
 static struct ucc_geth_info ugeth_primary_info = {
 	.uf_info = {
 		    .bd_mem_part = MEM_PART_SYSTEM,
@@ -104,6 +110,7 @@
 	.maxRetransmission = 0xf,
 	.collisionWindow = 0x37,
 	.receiveFlowControl = 1,
+	.transmitFlowControl = 1,
 	.maxGroupAddrInHash = 4,
 	.maxIndAddrInHash = 4,
 	.prel = 7,
@@ -139,7 +146,9 @@
 	.numStationAddresses = UCC_GETH_NUM_OF_STATION_ADDRESSES_1,
 	.largestexternallookupkeysize =
 	    QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE,
-	.statisticsMode = UCC_GETH_STATISTICS_GATHERING_MODE_NONE,
+	.statisticsMode = UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE |
+		UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX |
+		UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX,
 	.vlanOperationTagged = UCC_GETH_VLAN_OPERATION_TAGGED_NOP,
 	.vlanOperationNonTagged = UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP,
 	.rxQoSMode = UCC_GETH_QOS_MODE_DEFAULT,
@@ -281,7 +290,8 @@
 
 	for (i = 0; i < num_entries; i++) {
 		if ((snum = qe_get_snum()) < 0) {
-			ugeth_err("fill_init_enet_entries: Can not get SNUM.");
+			if (netif_msg_ifup(ugeth))
+				ugeth_err("fill_init_enet_entries: Can not get SNUM.");
 			return snum;
 		}
 		if ((i == 0) && skip_page_for_first_entry)
@@ -291,8 +301,8 @@
 			init_enet_offset =
 			    qe_muram_alloc(thread_size, thread_alignment);
 			if (IS_ERR_VALUE(init_enet_offset)) {
-				ugeth_err
-		("fill_init_enet_entries: Can not allocate DPRAM memory.");
+				if (netif_msg_ifup(ugeth))
+					ugeth_err("fill_init_enet_entries: Can not allocate DPRAM memory.");
 				qe_put_snum((u8) snum);
 				return -ENOMEM;
 			}
@@ -1200,7 +1210,7 @@
 	return 0;
 }
 
-static int init_flow_control_params(u32 automatic_flow_control_mode,
+int init_flow_control_params(u32 automatic_flow_control_mode,
 				    int rx_flow_control_enable,
 				    int tx_flow_control_enable,
 				    u16 pause_period,
@@ -1486,9 +1496,9 @@
 
 	ret_val = init_preamble_length(ug_info->prel, &ug_regs->maccfg2);
 	if (ret_val != 0) {
-		ugeth_err
-		    ("%s: Preamble length must be between 3 and 7 inclusive.",
-		     __FUNCTION__);
+		if (netif_msg_probe(ugeth))
+			ugeth_err("%s: Preamble length must be between 3 and 7 inclusive.",
+			     __FUNCTION__);
 		return ret_val;
 	}
 
@@ -1726,7 +1736,8 @@
 
 	/* check if the UCC number is in range. */
 	if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) {
-		ugeth_err("%s: ucc_num out of range.", __FUNCTION__);
+		if (netif_msg_probe(ugeth))
+			ugeth_err("%s: ucc_num out of range.", __FUNCTION__);
 		return -EINVAL;
 	}
 
@@ -1754,7 +1765,8 @@
 
 	/* check if the UCC number is in range. */
 	if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) {
-		ugeth_err("%s: ucc_num out of range.", __FUNCTION__);
+		if (netif_msg_probe(ugeth))
+			ugeth_err("%s: ucc_num out of range.", __FUNCTION__);
 		return -EINVAL;
 	}
 
@@ -2136,7 +2148,7 @@
 		for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) {
 			if (ugeth->tx_skbuff[i][j]) {
 				dma_unmap_single(NULL,
-						 ((qe_bd_t *)bd)->buf,
+						 ((struct qe_bd *)bd)->buf,
 						 (in_be32((u32 *)bd) &
 						  BD_LENGTH_MASK),
 						 DMA_TO_DEVICE);
@@ -2306,7 +2318,9 @@
 
 	if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) ||
 	      (uf_info->bd_mem_part == MEM_PART_MURAM))) {
-		ugeth_err("%s: Bad memory partition value.", __FUNCTION__);
+		if (netif_msg_probe(ugeth))
+			ugeth_err("%s: Bad memory partition value.",
+					__FUNCTION__);
 		return -EINVAL;
 	}
 
@@ -2315,9 +2329,10 @@
 		if ((ug_info->bdRingLenRx[i] < UCC_GETH_RX_BD_RING_SIZE_MIN) ||
 		    (ug_info->bdRingLenRx[i] %
 		     UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT)) {
-			ugeth_err
-			    ("%s: Rx BD ring length must be multiple of 4,"
-				" no smaller than 8.", __FUNCTION__);
+			if (netif_msg_probe(ugeth))
+				ugeth_err
+				    ("%s: Rx BD ring length must be multiple of 4, no smaller than 8.",
+					__FUNCTION__);
 			return -EINVAL;
 		}
 	}
@@ -2325,9 +2340,10 @@
 	/* Tx BD lengths */
 	for (i = 0; i < ug_info->numQueuesTx; i++) {
 		if (ug_info->bdRingLenTx[i] < UCC_GETH_TX_BD_RING_SIZE_MIN) {
-			ugeth_err
-			    ("%s: Tx BD ring length must be no smaller than 2.",
-			     __FUNCTION__);
+			if (netif_msg_probe(ugeth))
+				ugeth_err
+				    ("%s: Tx BD ring length must be no smaller than 2.",
+				     __FUNCTION__);
 			return -EINVAL;
 		}
 	}
@@ -2335,31 +2351,35 @@
 	/* mrblr */
 	if ((uf_info->max_rx_buf_length == 0) ||
 	    (uf_info->max_rx_buf_length % UCC_GETH_MRBLR_ALIGNMENT)) {
-		ugeth_err
-		    ("%s: max_rx_buf_length must be non-zero multiple of 128.",
-		     __FUNCTION__);
+		if (netif_msg_probe(ugeth))
+			ugeth_err
+			    ("%s: max_rx_buf_length must be non-zero multiple of 128.",
+			     __FUNCTION__);
 		return -EINVAL;
 	}
 
 	/* num Tx queues */
 	if (ug_info->numQueuesTx > NUM_TX_QUEUES) {
-		ugeth_err("%s: number of tx queues too large.", __FUNCTION__);
+		if (netif_msg_probe(ugeth))
+			ugeth_err("%s: number of tx queues too large.", __FUNCTION__);
 		return -EINVAL;
 	}
 
 	/* num Rx queues */
 	if (ug_info->numQueuesRx > NUM_RX_QUEUES) {
-		ugeth_err("%s: number of rx queues too large.", __FUNCTION__);
+		if (netif_msg_probe(ugeth))
+			ugeth_err("%s: number of rx queues too large.", __FUNCTION__);
 		return -EINVAL;
 	}
 
 	/* l2qt */
 	for (i = 0; i < UCC_GETH_VLAN_PRIORITY_MAX; i++) {
 		if (ug_info->l2qt[i] >= ug_info->numQueuesRx) {
-			ugeth_err
-			    ("%s: VLAN priority table entry must not be"
-				" larger than number of Rx queues.",
-			     __FUNCTION__);
+			if (netif_msg_probe(ugeth))
+				ugeth_err
+				    ("%s: VLAN priority table entry must not be"
+					" larger than number of Rx queues.",
+				     __FUNCTION__);
 			return -EINVAL;
 		}
 	}
@@ -2367,26 +2387,29 @@
 	/* l3qt */
 	for (i = 0; i < UCC_GETH_IP_PRIORITY_MAX; i++) {
 		if (ug_info->l3qt[i] >= ug_info->numQueuesRx) {
-			ugeth_err
-			    ("%s: IP priority table entry must not be"
-				" larger than number of Rx queues.",
-			     __FUNCTION__);
+			if (netif_msg_probe(ugeth))
+				ugeth_err
+				    ("%s: IP priority table entry must not be"
+					" larger than number of Rx queues.",
+				     __FUNCTION__);
 			return -EINVAL;
 		}
 	}
 
 	if (ug_info->cam && !ug_info->ecamptr) {
-		ugeth_err("%s: If cam mode is chosen, must supply cam ptr.",
-			  __FUNCTION__);
+		if (netif_msg_probe(ugeth))
+			ugeth_err("%s: If cam mode is chosen, must supply cam ptr.",
+				  __FUNCTION__);
 		return -EINVAL;
 	}
 
 	if ((ug_info->numStationAddresses !=
 	     UCC_GETH_NUM_OF_STATION_ADDRESSES_1)
 	    && ug_info->rxExtendedFiltering) {
-		ugeth_err("%s: Number of station addresses greater than 1 "
-			  "not allowed in extended parsing mode.",
-			  __FUNCTION__);
+		if (netif_msg_probe(ugeth))
+			ugeth_err("%s: Number of station addresses greater than 1 "
+				  "not allowed in extended parsing mode.",
+				  __FUNCTION__);
 		return -EINVAL;
 	}
 
@@ -2399,7 +2422,8 @@
 		uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i);
 	/* Initialize the general fast UCC block. */
 	if (ucc_fast_init(uf_info, &ugeth->uccf)) {
-		ugeth_err("%s: Failed to init uccf.", __FUNCTION__);
+		if (netif_msg_probe(ugeth))
+			ugeth_err("%s: Failed to init uccf.", __FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -2452,7 +2476,9 @@
 		numThreadsRxNumerical = 8;
 		break;
 	default:
-		ugeth_err("%s: Bad number of Rx threads value.", __FUNCTION__);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err("%s: Bad number of Rx threads value.",
+				       	__FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return -EINVAL;
 		break;
@@ -2475,7 +2501,9 @@
 		numThreadsTxNumerical = 8;
 		break;
 	default:
-		ugeth_err("%s: Bad number of Tx threads value.", __FUNCTION__);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err("%s: Bad number of Tx threads value.",
+				       	__FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return -EINVAL;
 		break;
@@ -2507,7 +2535,7 @@
 	/* For more details see the hardware spec.           */
 	init_flow_control_params(ug_info->aufc,
 				 ug_info->receiveFlowControl,
-				 1,
+				 ug_info->transmitFlowControl,
 				 ug_info->pausePeriod,
 				 ug_info->extensionField,
 				 &uf_regs->upsmr,
@@ -2527,8 +2555,9 @@
 					      ug_info->backToBackInterFrameGap,
 					      &ug_regs->ipgifg);
 	if (ret_val != 0) {
-		ugeth_err("%s: IPGIFG initialization parameter too large.",
-			  __FUNCTION__);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err("%s: IPGIFG initialization parameter too large.",
+				  __FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return ret_val;
 	}
@@ -2544,7 +2573,8 @@
 					  ug_info->collisionWindow,
 					  &ug_regs->hafdup);
 	if (ret_val != 0) {
-		ugeth_err("%s: Half Duplex initialization parameter too large.",
+		if (netif_msg_ifup(ugeth))
+			ugeth_err("%s: Half Duplex initialization parameter too large.",
 			  __FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return ret_val;
@@ -2597,9 +2627,10 @@
 							 tx_bd_ring_offset[j]);
 		}
 		if (!ugeth->p_tx_bd_ring[j]) {
-			ugeth_err
-			    ("%s: Can not allocate memory for Tx bd rings.",
-			     __FUNCTION__);
+			if (netif_msg_ifup(ugeth))
+				ugeth_err
+				    ("%s: Can not allocate memory for Tx bd rings.",
+				     __FUNCTION__);
 			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
@@ -2632,9 +2663,10 @@
 							 rx_bd_ring_offset[j]);
 		}
 		if (!ugeth->p_rx_bd_ring[j]) {
-			ugeth_err
-			    ("%s: Can not allocate memory for Rx bd rings.",
-			     __FUNCTION__);
+			if (netif_msg_ifup(ugeth))
+				ugeth_err
+				    ("%s: Can not allocate memory for Rx bd rings.",
+				     __FUNCTION__);
 			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
@@ -2648,8 +2680,9 @@
 					      GFP_KERNEL);
 
 		if (ugeth->tx_skbuff[j] == NULL) {
-			ugeth_err("%s: Could not allocate tx_skbuff",
-				  __FUNCTION__);
+			if (netif_msg_ifup(ugeth))
+				ugeth_err("%s: Could not allocate tx_skbuff",
+					  __FUNCTION__);
 			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
@@ -2679,8 +2712,9 @@
 					      GFP_KERNEL);
 
 		if (ugeth->rx_skbuff[j] == NULL) {
-			ugeth_err("%s: Could not allocate rx_skbuff",
-				  __FUNCTION__);
+			if (netif_msg_ifup(ugeth))
+				ugeth_err("%s: Could not allocate rx_skbuff",
+					  __FUNCTION__);
 			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
@@ -2711,9 +2745,10 @@
 	    qe_muram_alloc(sizeof(struct ucc_geth_tx_global_pram),
 			   UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT);
 	if (IS_ERR_VALUE(ugeth->tx_glbl_pram_offset)) {
-		ugeth_err
-		    ("%s: Can not allocate DPRAM memory for p_tx_glbl_pram.",
-		     __FUNCTION__);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err
+			    ("%s: Can not allocate DPRAM memory for p_tx_glbl_pram.",
+			     __FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -2733,9 +2768,10 @@
 			   32 * (numThreadsTxNumerical == 1),
 			   UCC_GETH_THREAD_DATA_ALIGNMENT);
 	if (IS_ERR_VALUE(ugeth->thread_dat_tx_offset)) {
-		ugeth_err
-		    ("%s: Can not allocate DPRAM memory for p_thread_data_tx.",
-		     __FUNCTION__);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err
+			    ("%s: Can not allocate DPRAM memory for p_thread_data_tx.",
+			     __FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -2761,9 +2797,10 @@
 			   sizeof(struct ucc_geth_send_queue_qd),
 			   UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT);
 	if (IS_ERR_VALUE(ugeth->send_q_mem_reg_offset)) {
-		ugeth_err
-		    ("%s: Can not allocate DPRAM memory for p_send_q_mem_reg.",
-		     __FUNCTION__);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err
+			    ("%s: Can not allocate DPRAM memory for p_send_q_mem_reg.",
+			     __FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -2804,9 +2841,10 @@
 		    qe_muram_alloc(sizeof(struct ucc_geth_scheduler),
 				   UCC_GETH_SCHEDULER_ALIGNMENT);
 		if (IS_ERR_VALUE(ugeth->scheduler_offset)) {
-			ugeth_err
-			 ("%s: Can not allocate DPRAM memory for p_scheduler.",
-			     __FUNCTION__);
+			if (netif_msg_ifup(ugeth))
+				ugeth_err
+				 ("%s: Can not allocate DPRAM memory for p_scheduler.",
+				     __FUNCTION__);
 			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
@@ -2852,9 +2890,11 @@
 				   (struct ucc_geth_tx_firmware_statistics_pram),
 				   UCC_GETH_TX_STATISTICS_ALIGNMENT);
 		if (IS_ERR_VALUE(ugeth->tx_fw_statistics_pram_offset)) {
-			ugeth_err
-			    ("%s: Can not allocate DPRAM memory for"
-				" p_tx_fw_statistics_pram.", __FUNCTION__);
+			if (netif_msg_ifup(ugeth))
+				ugeth_err
+				    ("%s: Can not allocate DPRAM memory for"
+					" p_tx_fw_statistics_pram.",
+				       	__FUNCTION__);
 			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
@@ -2879,7 +2919,7 @@
 	test = in_be16(&ugeth->p_tx_glbl_pram->temoder);
 
 	/* Function code register value to be used later */
-	function_code = QE_BMR_BYTE_ORDER_BO_MOT | UCC_FAST_FUNCTION_CODE_GBL;
+	function_code = UCC_BMR_BO_BE | UCC_BMR_GBL;
 	/* Required for QE */
 
 	/* function code register */
@@ -2891,9 +2931,10 @@
 	    qe_muram_alloc(sizeof(struct ucc_geth_rx_global_pram),
 			   UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT);
 	if (IS_ERR_VALUE(ugeth->rx_glbl_pram_offset)) {
-		ugeth_err
-		    ("%s: Can not allocate DPRAM memory for p_rx_glbl_pram.",
-		     __FUNCTION__);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err
+			    ("%s: Can not allocate DPRAM memory for p_rx_glbl_pram.",
+			     __FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -2912,9 +2953,10 @@
 			   sizeof(struct ucc_geth_thread_data_rx),
 			   UCC_GETH_THREAD_DATA_ALIGNMENT);
 	if (IS_ERR_VALUE(ugeth->thread_dat_rx_offset)) {
-		ugeth_err
-		    ("%s: Can not allocate DPRAM memory for p_thread_data_rx.",
-		     __FUNCTION__);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err
+			    ("%s: Can not allocate DPRAM memory for p_thread_data_rx.",
+			     __FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -2935,9 +2977,10 @@
 				   (struct ucc_geth_rx_firmware_statistics_pram),
 				   UCC_GETH_RX_STATISTICS_ALIGNMENT);
 		if (IS_ERR_VALUE(ugeth->rx_fw_statistics_pram_offset)) {
-			ugeth_err
-				("%s: Can not allocate DPRAM memory for"
-				" p_rx_fw_statistics_pram.", __FUNCTION__);
+			if (netif_msg_ifup(ugeth))
+				ugeth_err
+					("%s: Can not allocate DPRAM memory for"
+					" p_rx_fw_statistics_pram.", __FUNCTION__);
 			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
@@ -2957,9 +3000,10 @@
 			   sizeof(struct ucc_geth_rx_interrupt_coalescing_entry)
 			   + 4, UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT);
 	if (IS_ERR_VALUE(ugeth->rx_irq_coalescing_tbl_offset)) {
-		ugeth_err
-		    ("%s: Can not allocate DPRAM memory for"
-			" p_rx_irq_coalescing_tbl.", __FUNCTION__);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err
+			    ("%s: Can not allocate DPRAM memory for"
+				" p_rx_irq_coalescing_tbl.", __FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -3025,9 +3069,10 @@
 			    sizeof(struct ucc_geth_rx_prefetched_bds)),
 			   UCC_GETH_RX_BD_QUEUES_ALIGNMENT);
 	if (IS_ERR_VALUE(ugeth->rx_bd_qs_tbl_offset)) {
-		ugeth_err
-		    ("%s: Can not allocate DPRAM memory for p_rx_bd_qs_tbl.",
-		     __FUNCTION__);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err
+			    ("%s: Can not allocate DPRAM memory for p_rx_bd_qs_tbl.",
+			     __FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -3102,8 +3147,9 @@
 	/* initialize extended filtering */
 	if (ug_info->rxExtendedFiltering) {
 		if (!ug_info->extendedFilteringChainPointer) {
-			ugeth_err("%s: Null Extended Filtering Chain Pointer.",
-				  __FUNCTION__);
+			if (netif_msg_ifup(ugeth))
+				ugeth_err("%s: Null Extended Filtering Chain Pointer.",
+					  __FUNCTION__);
 			ucc_geth_memclean(ugeth);
 			return -EINVAL;
 		}
@@ -3114,9 +3160,10 @@
 		    qe_muram_alloc(sizeof(struct ucc_geth_exf_global_pram),
 		UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT);
 		if (IS_ERR_VALUE(ugeth->exf_glbl_param_offset)) {
-			ugeth_err
-				("%s: Can not allocate DPRAM memory for"
-				" p_exf_glbl_param.", __FUNCTION__);
+			if (netif_msg_ifup(ugeth))
+				ugeth_err
+					("%s: Can not allocate DPRAM memory for"
+					" p_exf_glbl_param.", __FUNCTION__);
 			ucc_geth_memclean(ugeth);
 			return -ENOMEM;
 		}
@@ -3161,9 +3208,10 @@
 	 */
 	if (!(ugeth->p_init_enet_param_shadow =
 	      kmalloc(sizeof(struct ucc_geth_init_pram), GFP_KERNEL))) {
-		ugeth_err
-		    ("%s: Can not allocate memory for"
-			" p_UccInitEnetParamShadows.", __FUNCTION__);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err
+			    ("%s: Can not allocate memory for"
+				" p_UccInitEnetParamShadows.", __FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -3196,8 +3244,9 @@
 		QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES)
 	    && (ug_info->largestexternallookupkeysize !=
 		QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES)) {
-		ugeth_err("%s: Invalid largest External Lookup Key Size.",
-			  __FUNCTION__);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err("%s: Invalid largest External Lookup Key Size.",
+				  __FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return -EINVAL;
 	}
@@ -3222,8 +3271,9 @@
 		/* Rx needs one extra for terminator */
 		, size, UCC_GETH_THREAD_RX_PRAM_ALIGNMENT,
 		ug_info->riscRx, 1)) != 0) {
-			ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
-				__FUNCTION__);
+		if (netif_msg_ifup(ugeth))
+				ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
+					__FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return ret_val;
 	}
@@ -3237,8 +3287,9 @@
 				    sizeof(struct ucc_geth_thread_tx_pram),
 				    UCC_GETH_THREAD_TX_PRAM_ALIGNMENT,
 				    ug_info->riscTx, 0)) != 0) {
-		ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
-			  __FUNCTION__);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
+				  __FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return ret_val;
 	}
@@ -3246,8 +3297,9 @@
 	/* Load Rx bds with buffers */
 	for (i = 0; i < ug_info->numQueuesRx; i++) {
 		if ((ret_val = rx_bd_buffer_set(ugeth, (u8) i)) != 0) {
-			ugeth_err("%s: Can not fill Rx bds with buffers.",
-				  __FUNCTION__);
+			if (netif_msg_ifup(ugeth))
+				ugeth_err("%s: Can not fill Rx bds with buffers.",
+					  __FUNCTION__);
 			ucc_geth_memclean(ugeth);
 			return ret_val;
 		}
@@ -3256,9 +3308,10 @@
 	/* Allocate InitEnet command parameter structure */
 	init_enet_pram_offset = qe_muram_alloc(sizeof(struct ucc_geth_init_pram), 4);
 	if (IS_ERR_VALUE(init_enet_pram_offset)) {
-		ugeth_err
-		    ("%s: Can not allocate DPRAM memory for p_init_enet_pram.",
-		     __FUNCTION__);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err
+			    ("%s: Can not allocate DPRAM memory for p_init_enet_pram.",
+			     __FUNCTION__);
 		ucc_geth_memclean(ugeth);
 		return -ENOMEM;
 	}
@@ -3297,14 +3350,6 @@
 	return 0;
 }
 
-/* returns a net_device_stats structure pointer */
-static struct net_device_stats *ucc_geth_get_stats(struct net_device *dev)
-{
-	struct ucc_geth_private *ugeth = netdev_priv(dev);
-
-	return &(ugeth->stats);
-}
-
 /* ucc_geth_timeout gets called when a packet has not been
  * transmitted after a set amount of time.
  * For now, assume that clearing out all the structures, and
@@ -3315,7 +3360,7 @@
 
 	ugeth_vdbg("%s: IN", __FUNCTION__);
 
-	ugeth->stats.tx_errors++;
+	dev->stats.tx_errors++;
 
 	ugeth_dump_regs(ugeth);
 
@@ -3343,7 +3388,7 @@
 
 	spin_lock_irq(&ugeth->lock);
 
-	ugeth->stats.tx_bytes += skb->len;
+	dev->stats.tx_bytes += skb->len;
 
 	/* Start from the next BD that should be filled */
 	bd = ugeth->txBd[txQ];
@@ -3428,15 +3473,16 @@
 		if (!skb ||
 		    (!(bd_status & (R_F | R_L))) ||
 		    (bd_status & R_ERRORS_FATAL)) {
-			ugeth_vdbg("%s, %d: ERROR!!! skb - 0x%08x",
-				   __FUNCTION__, __LINE__, (u32) skb);
+			if (netif_msg_rx_err(ugeth))
+				ugeth_err("%s, %d: ERROR!!! skb - 0x%08x",
+					   __FUNCTION__, __LINE__, (u32) skb);
 			if (skb)
 				dev_kfree_skb_any(skb);
 
 			ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL;
-			ugeth->stats.rx_dropped++;
+			dev->stats.rx_dropped++;
 		} else {
-			ugeth->stats.rx_packets++;
+			dev->stats.rx_packets++;
 			howmany++;
 
 			/* Prep the skb for the packet */
@@ -3445,7 +3491,7 @@
 			/* Tell the skb what kind of packet this is */
 			skb->protocol = eth_type_trans(skb, ugeth->dev);
 
-			ugeth->stats.rx_bytes += length;
+			dev->stats.rx_bytes += length;
 			/* Send the packet up the stack */
 #ifdef CONFIG_UGETH_NAPI
 			netif_receive_skb(skb);
@@ -3458,8 +3504,9 @@
 
 		skb = get_new_skb(ugeth, bd);
 		if (!skb) {
-			ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__);
-			ugeth->stats.rx_dropped++;
+			if (netif_msg_rx_err(ugeth))
+				ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__);
+			dev->stats.rx_dropped++;
 			break;
 		}
 
@@ -3501,7 +3548,7 @@
 		if ((bd == ugeth->txBd[txQ]) && (netif_queue_stopped(dev) == 0))
 			break;
 
-		ugeth->stats.tx_packets++;
+		dev->stats.tx_packets++;
 
 		/* Free the sk buffer associated with this TxBD */
 		dev_kfree_skb_irq(ugeth->
@@ -3527,41 +3574,31 @@
 }
 
 #ifdef CONFIG_UGETH_NAPI
-static int ucc_geth_poll(struct net_device *dev, int *budget)
+static int ucc_geth_poll(struct napi_struct *napi, int budget)
 {
-	struct ucc_geth_private *ugeth = netdev_priv(dev);
+	struct ucc_geth_private *ugeth = container_of(napi, struct ucc_geth_private, napi);
+	struct net_device *dev = ugeth->dev;
 	struct ucc_geth_info *ug_info;
-	struct ucc_fast_private *uccf;
-	int howmany;
-	u8 i;
-	int rx_work_limit;
-	register u32 uccm;
+	int howmany, i;
 
 	ug_info = ugeth->ug_info;
 
-	rx_work_limit = *budget;
-	if (rx_work_limit > dev->quota)
-		rx_work_limit = dev->quota;
-
 	howmany = 0;
+	for (i = 0; i < ug_info->numQueuesRx; i++)
+		howmany += ucc_geth_rx(ugeth, i, budget - howmany);
 
-	for (i = 0; i < ug_info->numQueuesRx; i++) {
-		howmany += ucc_geth_rx(ugeth, i, rx_work_limit);
-	}
+	if (howmany < budget) {
+		struct ucc_fast_private *uccf;
+		u32 uccm;
 
-	dev->quota -= howmany;
-	rx_work_limit -= howmany;
-	*budget -= howmany;
-
-	if (rx_work_limit > 0) {
-		netif_rx_complete(dev);
+		netif_rx_complete(dev, napi);
 		uccf = ugeth->uccf;
 		uccm = in_be32(uccf->p_uccm);
 		uccm |= UCCE_RX_EVENTS;
 		out_be32(uccf->p_uccm, uccm);
 	}
 
-	return (rx_work_limit > 0) ? 0 : 1;
+	return howmany;
 }
 #endif				/* CONFIG_UGETH_NAPI */
 
@@ -3596,10 +3633,10 @@
 	/* check for receive events that require processing */
 	if (ucce & UCCE_RX_EVENTS) {
 #ifdef CONFIG_UGETH_NAPI
-		if (netif_rx_schedule_prep(dev)) {
-		uccm &= ~UCCE_RX_EVENTS;
+		if (netif_rx_schedule_prep(dev, &ugeth->napi)) {
+			uccm &= ~UCCE_RX_EVENTS;
 			out_be32(uccf->p_uccm, uccm);
-			__netif_rx_schedule(dev);
+			__netif_rx_schedule(dev, &ugeth->napi);
 		}
 #else
 		rx_mask = UCCE_RXBF_SINGLE_MASK;
@@ -3628,10 +3665,10 @@
 	/* Errors and other events */
 	if (ucce & UCCE_OTHER) {
 		if (ucce & UCCE_BSY) {
-			ugeth->stats.rx_errors++;
+			dev->stats.rx_errors++;
 		}
 		if (ucce & UCCE_TXE) {
-			ugeth->stats.tx_errors++;
+			dev->stats.tx_errors++;
 		}
 	}
 
@@ -3649,29 +3686,36 @@
 
 	/* Test station address */
 	if (dev->dev_addr[0] & ENET_GROUP_ADDR) {
-		ugeth_err("%s: Multicast address used for station address"
-			  " - is this what you wanted?", __FUNCTION__);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err("%s: Multicast address used for station address"
+				  " - is this what you wanted?", __FUNCTION__);
 		return -EINVAL;
 	}
 
 	err = ucc_struct_init(ugeth);
 	if (err) {
-		ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name);
 		return err;
 	}
 
+#ifdef CONFIG_UGETH_NAPI
+	napi_enable(&ugeth->napi);
+#endif
 	err = ucc_geth_startup(ugeth);
 	if (err) {
-		ugeth_err("%s: Cannot configure net device, aborting.",
-			  dev->name);
-		return err;
+		if (netif_msg_ifup(ugeth))
+			ugeth_err("%s: Cannot configure net device, aborting.",
+				  dev->name);
+		goto out_err;
 	}
 
 	err = adjust_enet_interface(ugeth);
 	if (err) {
-		ugeth_err("%s: Cannot configure net device, aborting.",
-			  dev->name);
-		return err;
+		if (netif_msg_ifup(ugeth))
+			ugeth_err("%s: Cannot configure net device, aborting.",
+				  dev->name);
+		goto out_err;
 	}
 
 	/*       Set MACSTNADDR1, MACSTNADDR2                */
@@ -3687,8 +3731,9 @@
 
 	err = init_phy(dev);
 	if (err) {
-		ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name);
-		return err;
+		if (netif_msg_ifup(ugeth))
+			ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name);
+		goto out_err;
 	}
 
 	phy_start(ugeth->phydev);
@@ -3697,22 +3742,30 @@
 	    request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0,
 			"UCC Geth", dev);
 	if (err) {
-		ugeth_err("%s: Cannot get IRQ for net device, aborting.",
-			  dev->name);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err("%s: Cannot get IRQ for net device, aborting.",
+				  dev->name);
 		ucc_geth_stop(ugeth);
-		return err;
+		goto out_err;
 	}
 
 	err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
 	if (err) {
-		ugeth_err("%s: Cannot enable net device, aborting.", dev->name);
+		if (netif_msg_ifup(ugeth))
+			ugeth_err("%s: Cannot enable net device, aborting.", dev->name);
 		ucc_geth_stop(ugeth);
-		return err;
+		goto out_err;
 	}
 
 	netif_start_queue(dev);
 
 	return err;
+
+out_err:
+#ifdef CONFIG_UGETH_NAPI
+	napi_disable(&ugeth->napi);
+#endif
+	return err;
 }
 
 /* Stops the kernel queue, and halts the controller */
@@ -3722,6 +3775,10 @@
 
 	ugeth_vdbg("%s: IN", __FUNCTION__);
 
+#ifdef CONFIG_UGETH_NAPI
+	napi_disable(&ugeth->napi);
+#endif
+
 	ucc_geth_stop(ugeth);
 
 	phy_disconnect(ugeth->phydev);
@@ -3732,8 +3789,6 @@
 	return 0;
 }
 
-const struct ethtool_ops ucc_geth_ethtool_ops = { };
-
 static phy_interface_t to_phy_interface(const char *phy_connection_type)
 {
 	if (strcasecmp(phy_connection_type, "mii") == 0)
@@ -3790,6 +3845,13 @@
 		return -ENODEV;
 
 	ug_info = &ugeth_info[ucc_num];
+	if (ug_info == NULL) {
+		if (netif_msg_probe(&debug))
+			ugeth_err("%s: [%d] Missing additional data!",
+				       	__FUNCTION__, ucc_num);
+		return -ENODEV;
+	}
+
 	ug_info->uf_info.ucc_num = ucc_num;
 
 	prop = of_get_property(np, "rx-clock", NULL);
@@ -3868,15 +3930,10 @@
 
 	ug_info->mdio_bus = res.start;
 
-	printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n",
-		ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs,
-		ug_info->uf_info.irq);
-
-	if (ug_info == NULL) {
-		ugeth_err("%s: [%d] Missing additional data!", __FUNCTION__,
-			  ucc_num);
-		return -ENODEV;
-	}
+	if (netif_msg_probe(&debug))
+		printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n",
+			ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs,
+			ug_info->uf_info.irq);
 
 	/* Create an ethernet device instance */
 	dev = alloc_etherdev(sizeof(*ugeth));
@@ -3892,33 +3949,31 @@
 	/* Set the dev->base_addr to the gfar reg region */
 	dev->base_addr = (unsigned long)(ug_info->uf_info.regs);
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, device);
 
 	/* Fill in the dev structure */
+	uec_set_ethtool_ops(dev);
 	dev->open = ucc_geth_open;
 	dev->hard_start_xmit = ucc_geth_start_xmit;
 	dev->tx_timeout = ucc_geth_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 #ifdef CONFIG_UGETH_NAPI
-	dev->poll = ucc_geth_poll;
-	dev->weight = UCC_GETH_DEV_WEIGHT;
+	netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT);
 #endif				/* CONFIG_UGETH_NAPI */
 	dev->stop = ucc_geth_close;
-	dev->get_stats = ucc_geth_get_stats;
 //    dev->change_mtu = ucc_geth_change_mtu;
 	dev->mtu = 1500;
 	dev->set_multicast_list = ucc_geth_set_multi;
-	dev->ethtool_ops = &ucc_geth_ethtool_ops;
 
-	ugeth->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
+	ugeth->msg_enable = netif_msg_init(debug.msg_enable, UGETH_MSG_DEFAULT);
 	ugeth->phy_interface = phy_interface;
 	ugeth->max_speed = max_speed;
 
 	err = register_netdev(dev);
 	if (err) {
-		ugeth_err("%s: Cannot register net device, aborting.",
-			  dev->name);
+		if (netif_msg_probe(ugeth))
+			ugeth_err("%s: Cannot register net device, aborting.",
+				  dev->name);
 		free_netdev(dev);
 		return err;
 	}
@@ -3972,7 +4027,8 @@
 	if (ret)
 		return ret;
 
-	printk(KERN_INFO "ucc_geth: " DRV_DESC "\n");
+	if (netif_msg_drv(&debug))
+		printk(KERN_INFO "ucc_geth: " DRV_DESC "\n");
 	for (i = 0; i < 8; i++)
 		memcpy(&(ugeth_info[i]), &ugeth_primary_info,
 		       sizeof(ugeth_primary_info));
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index a29e1c3..4fb95b3 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -30,6 +30,10 @@
 
 #include "ucc_geth_mii.h"
 
+#define DRV_DESC "QE UCC Gigabit Ethernet Controller"
+#define DRV_NAME "ucc_geth"
+#define DRV_VERSION "1.1"
+
 #define NUM_TX_QUEUES                   8
 #define NUM_RX_QUEUES                   8
 #define NUM_BDS_IN_PREFETCHED_BDS       4
@@ -40,6 +44,7 @@
 
 struct ucc_geth {
 	struct ucc_fast uccf;
+	u8 res0[0x100 - sizeof(struct ucc_fast)];
 
 	u32 maccfg1;		/* mac configuration reg. 1 */
 	u32 maccfg2;		/* mac configuration reg. 2 */
@@ -896,6 +901,7 @@
 #define UCC_GETH_TX_VTAG_TABLE_ENTRY_MAX        8
 #define UCC_GETH_RX_BD_RING_SIZE_MIN            8
 #define UCC_GETH_TX_BD_RING_SIZE_MIN            2
+#define UCC_GETH_BD_RING_SIZE_MAX		0xffff
 
 #define UCC_GETH_SIZE_OF_BD                     QE_SIZEOF_BD
 
@@ -1135,6 +1141,7 @@
 	int bro;
 	int ecm;
 	int receiveFlowControl;
+	int transmitFlowControl;
 	u8 maxGroupAddrInHash;
 	u8 maxIndAddrInHash;
 	u8 prel;
@@ -1178,7 +1185,7 @@
 	struct ucc_geth_info *ug_info;
 	struct ucc_fast_private *uccf;
 	struct net_device *dev;
-	struct net_device_stats stats;	/* linux network statistics */
+	struct napi_struct napi;
 	struct ucc_geth *ug_regs;
 	struct ucc_geth_init_pram *p_init_enet_param_shadow;
 	struct ucc_geth_exf_global_pram *p_exf_glbl_param;
diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c
new file mode 100644
index 0000000..9a9622c
--- /dev/null
+++ b/drivers/net/ucc_geth_ethtool.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Description: QE UCC Gigabit Ethernet Ethtool API Set
+ *
+ * Author: Li Yang <leoli@freescale.com>
+ *
+ * Limitation: 
+ * Can only get/set setttings of the first queue.
+ * Need to re-open the interface manually after changing some paramters.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/fsl_devices.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/types.h>
+#include <asm/uaccess.h>
+
+#include "ucc_geth.h"
+#include "ucc_geth_mii.h"
+
+static char hw_stat_gstrings[][ETH_GSTRING_LEN] = {
+	"tx-64-frames",
+	"tx-65-127-frames",
+	"tx-128-255-frames",
+	"rx-64-frames",
+	"rx-65-127-frames",
+	"rx-128-255-frames",
+	"tx-bytes-ok",
+	"tx-pause-frames",
+	"tx-multicast-frames",
+	"tx-broadcast-frames",
+	"rx-frames",
+	"rx-bytes-ok",
+	"rx-bytes-all",
+	"rx-multicast-frames",
+	"rx-broadcast-frames",
+	"stats-counter-carry",
+	"stats-counter-mask",
+	"rx-dropped-frames",
+};
+
+static char tx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
+	"tx-single-collision",
+	"tx-multiple-collision",
+	"tx-late-collsion",
+	"tx-aborted-frames",
+	"tx-lost-frames",
+	"tx-carrier-sense-errors",
+	"tx-frames-ok",
+	"tx-excessive-differ-frames",
+	"tx-256-511-frames",
+	"tx-1024-1518-frames",
+	"tx-jumbo-frames",
+};
+
+static char rx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
+	"rx-crc-errors",
+	"rx-alignment-errors",
+	"rx-in-range-length-errors",
+	"rx-out-of-range-length-errors",
+	"rx-too-long-frames",
+	"rx-runt",
+	"rx-very-long-event",
+	"rx-symbol-errors",
+	"rx-busy-drop-frames",
+	"reserved",
+	"reserved",
+	"rx-mismatch-drop-frames",
+	"rx-small-than-64",
+	"rx-256-511-frames",
+	"rx-512-1023-frames",
+	"rx-1024-1518-frames",
+	"rx-jumbo-frames",
+	"rx-mac-error-loss",
+	"rx-pause-frames",
+	"reserved",
+	"rx-vlan-removed",
+	"rx-vlan-replaced",
+	"rx-vlan-inserted",
+	"rx-ip-checksum-errors",
+};
+
+#define UEC_HW_STATS_LEN ARRAY_SIZE(hw_stat_gstrings)
+#define UEC_TX_FW_STATS_LEN ARRAY_SIZE(tx_fw_stat_gstrings)
+#define UEC_RX_FW_STATS_LEN ARRAY_SIZE(rx_fw_stat_gstrings)
+
+extern int init_flow_control_params(u32 automatic_flow_control_mode,
+		int rx_flow_control_enable,
+		int tx_flow_control_enable, u16 pause_period,
+		u16 extension_field, volatile u32 *upsmr_register,
+		volatile u32 *uempr_register, volatile u32 *maccfg1_register);
+
+static int
+uec_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+	struct ucc_geth_private *ugeth = netdev_priv(netdev);
+	struct phy_device *phydev = ugeth->phydev;
+	struct ucc_geth_info *ug_info = ugeth->ug_info;
+
+	if (!phydev)
+		return -ENODEV;
+
+	ecmd->maxtxpkt = 1;
+	ecmd->maxrxpkt = ug_info->interruptcoalescingmaxvalue[0];
+
+	return phy_ethtool_gset(phydev, ecmd);
+}
+
+static int
+uec_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+	struct ucc_geth_private *ugeth = netdev_priv(netdev);
+	struct phy_device *phydev = ugeth->phydev;
+
+	if (!phydev)
+		return -ENODEV;
+
+	return phy_ethtool_sset(phydev, ecmd);
+}
+
+static void
+uec_get_pauseparam(struct net_device *netdev,
+                     struct ethtool_pauseparam *pause)
+{
+	struct ucc_geth_private *ugeth = netdev_priv(netdev);
+
+	pause->autoneg = ugeth->phydev->autoneg;
+
+	if (ugeth->ug_info->receiveFlowControl)
+		pause->rx_pause = 1;
+	if (ugeth->ug_info->transmitFlowControl)
+		pause->tx_pause = 1;
+}
+
+static int
+uec_set_pauseparam(struct net_device *netdev,
+                     struct ethtool_pauseparam *pause)
+{
+	struct ucc_geth_private *ugeth = netdev_priv(netdev);
+	int ret = 0;
+
+	ugeth->ug_info->receiveFlowControl = pause->rx_pause;
+	ugeth->ug_info->transmitFlowControl = pause->tx_pause;
+	
+	if (ugeth->phydev->autoneg) {
+		if (netif_running(netdev)) {
+			/* FIXME: automatically restart */
+			printk(KERN_INFO
+				"Please re-open the interface.\n");
+		}
+	} else {
+		struct ucc_geth_info *ug_info = ugeth->ug_info;
+
+		ret = init_flow_control_params(ug_info->aufc,
+					ug_info->receiveFlowControl,
+					ug_info->transmitFlowControl,
+					ug_info->pausePeriod,
+					ug_info->extensionField,
+					&ugeth->uccf->uf_regs->upsmr,
+					&ugeth->ug_regs->uempr,
+					&ugeth->ug_regs->maccfg1);
+	}
+
+	return ret;
+}
+
+static uint32_t
+uec_get_msglevel(struct net_device *netdev)
+{
+	struct ucc_geth_private *ugeth = netdev_priv(netdev);
+	return ugeth->msg_enable;
+}
+
+static void
+uec_set_msglevel(struct net_device *netdev, uint32_t data)
+{
+	struct ucc_geth_private *ugeth = netdev_priv(netdev);
+	ugeth->msg_enable = data;
+}
+
+static int
+uec_get_regs_len(struct net_device *netdev)
+{
+	return sizeof(struct ucc_geth);
+}
+
+static void
+uec_get_regs(struct net_device *netdev,
+               struct ethtool_regs *regs, void *p)
+{
+	int i;
+	struct ucc_geth_private *ugeth = netdev_priv(netdev);
+	u32 __iomem *ug_regs = (u32 __iomem *)ugeth->ug_regs;
+	u32 *buff = p;
+
+	for (i = 0; i < sizeof(struct ucc_geth) / sizeof(u32); i++)
+		buff[i] = in_be32(&ug_regs[i]);
+}
+
+static void
+uec_get_ringparam(struct net_device *netdev,
+                    struct ethtool_ringparam *ring)
+{
+	struct ucc_geth_private *ugeth = netdev_priv(netdev);
+	struct ucc_geth_info *ug_info = ugeth->ug_info;
+	int queue = 0;
+
+	ring->rx_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
+	ring->rx_mini_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
+	ring->rx_jumbo_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
+	ring->tx_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
+
+	ring->rx_pending = ug_info->bdRingLenRx[queue];
+	ring->rx_mini_pending = ug_info->bdRingLenRx[queue];
+	ring->rx_jumbo_pending = ug_info->bdRingLenRx[queue];
+	ring->tx_pending = ug_info->bdRingLenTx[queue];
+}
+
+static int
+uec_set_ringparam(struct net_device *netdev,
+                    struct ethtool_ringparam *ring)
+{
+	struct ucc_geth_private *ugeth = netdev_priv(netdev);
+	struct ucc_geth_info *ug_info = ugeth->ug_info;
+	int queue = 0, ret = 0;
+
+	if (ring->rx_pending < UCC_GETH_RX_BD_RING_SIZE_MIN) {
+		printk("%s: RxBD ring size must be no smaller than %d.\n",
+			       	netdev->name, UCC_GETH_RX_BD_RING_SIZE_MIN);
+		return -EINVAL;
+	}
+	if (ring->rx_pending % UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT) {
+		printk("%s: RxBD ring size must be multiple of %d.\n",
+			netdev->name, UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT);
+		return -EINVAL;
+	}
+	if (ring->tx_pending < UCC_GETH_TX_BD_RING_SIZE_MIN) {
+		printk("%s: TxBD ring size must be no smaller than %d.\n",
+				netdev->name, UCC_GETH_TX_BD_RING_SIZE_MIN);
+		return -EINVAL;
+	}
+
+	ug_info->bdRingLenRx[queue] = ring->rx_pending;
+	ug_info->bdRingLenTx[queue] = ring->tx_pending;
+
+	if (netif_running(netdev)) {
+		/* FIXME: restart automatically */
+		printk(KERN_INFO
+			"Please re-open the interface.\n");
+	}
+
+	return ret;
+}
+
+static int uec_get_sset_count(struct net_device *netdev, int sset)
+{
+	struct ucc_geth_private *ugeth = netdev_priv(netdev);
+	u32 stats_mode = ugeth->ug_info->statisticsMode;
+	int len = 0;
+
+	switch (sset) {
+	case ETH_SS_STATS:
+		if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE)
+			len += UEC_HW_STATS_LEN;
+		if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX)
+			len += UEC_TX_FW_STATS_LEN;
+		if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
+			len += UEC_RX_FW_STATS_LEN;
+
+		return len;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static void uec_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
+{
+	struct ucc_geth_private *ugeth = netdev_priv(netdev);
+	u32 stats_mode = ugeth->ug_info->statisticsMode;
+
+	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) {
+		memcpy(buf, hw_stat_gstrings, UEC_HW_STATS_LEN *
+			       	ETH_GSTRING_LEN);
+		buf += UEC_HW_STATS_LEN * ETH_GSTRING_LEN;
+	}
+	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
+		memcpy(buf, tx_fw_stat_gstrings, UEC_TX_FW_STATS_LEN *
+			       	ETH_GSTRING_LEN);
+		buf += UEC_TX_FW_STATS_LEN * ETH_GSTRING_LEN;
+	}
+	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
+		memcpy(buf, tx_fw_stat_gstrings, UEC_RX_FW_STATS_LEN *
+			       	ETH_GSTRING_LEN);
+}
+
+static void uec_get_ethtool_stats(struct net_device *netdev,
+		struct ethtool_stats *stats, uint64_t *data)
+{
+	struct ucc_geth_private *ugeth = netdev_priv(netdev);
+	u32 stats_mode = ugeth->ug_info->statisticsMode;
+	u32 __iomem *base;
+	int i, j = 0;
+
+	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) {
+		base = (u32 __iomem *)&ugeth->ug_regs->tx64;
+		for (i = 0; i < UEC_HW_STATS_LEN; i++)
+			data[j++] = (u64)in_be32(&base[i]);
+	}
+	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
+		base = (u32 __iomem *)ugeth->p_tx_fw_statistics_pram;
+		for (i = 0; i < UEC_TX_FW_STATS_LEN; i++)
+			data[j++] = (u64)in_be32(&base[i]);
+	}
+	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) {
+		base = (u32 __iomem *)ugeth->p_rx_fw_statistics_pram;
+		for (i = 0; i < UEC_RX_FW_STATS_LEN; i++)
+			data[j++] = (u64)in_be32(&base[i]);
+	}
+}
+
+static int uec_nway_reset(struct net_device *netdev)
+{
+	struct ucc_geth_private *ugeth = netdev_priv(netdev);
+
+	return phy_start_aneg(ugeth->phydev);
+}
+
+/* Report driver information */
+static void
+uec_get_drvinfo(struct net_device *netdev,
+                       struct ethtool_drvinfo *drvinfo)
+{
+	strncpy(drvinfo->driver, DRV_NAME, 32);
+	strncpy(drvinfo->version, DRV_VERSION, 32);
+	strncpy(drvinfo->fw_version, "N/A", 32);
+	strncpy(drvinfo->bus_info, "QUICC ENGINE", 32);
+	drvinfo->eedump_len = 0;
+	drvinfo->regdump_len = uec_get_regs_len(netdev);
+}
+
+static const struct ethtool_ops uec_ethtool_ops = {
+	.get_settings           = uec_get_settings,
+	.set_settings           = uec_set_settings,
+	.get_drvinfo            = uec_get_drvinfo,
+	.get_regs_len           = uec_get_regs_len,
+	.get_regs               = uec_get_regs,
+	.get_msglevel           = uec_get_msglevel,
+	.set_msglevel           = uec_set_msglevel,
+	.nway_reset             = uec_nway_reset,
+	.get_link               = ethtool_op_get_link,
+	.get_ringparam          = uec_get_ringparam,
+	.set_ringparam          = uec_set_ringparam,
+	.get_pauseparam         = uec_get_pauseparam,
+	.set_pauseparam         = uec_set_pauseparam,
+	.set_sg                 = ethtool_op_set_sg,
+	.get_sset_count		= uec_get_sset_count,
+	.get_strings            = uec_get_strings,
+	.get_ethtool_stats      = uec_get_ethtool_stats,
+};
+
+void uec_set_ethtool_ops(struct net_device *netdev)
+{
+	SET_ETHTOOL_OPS(netdev, &uec_ethtool_ops);
+}
diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c
index 7bcb82f..df884f0 100644
--- a/drivers/net/ucc_geth_mii.c
+++ b/drivers/net/ucc_geth_mii.c
@@ -32,7 +32,6 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <asm/ocp.h>
 #include <linux/crc32.h>
 #include <linux/mii.h>
 #include <linux/phy.h>
@@ -54,8 +53,8 @@
 #define vdbg(format, arg...) do {} while(0)
 #endif
 
-#define DRV_DESC "QE UCC Ethernet Controller MII Bus"
-#define DRV_NAME "fsl-uec_mdio"
+#define MII_DRV_DESC "QE UCC Ethernet Controller MII Bus"
+#define MII_DRV_NAME "fsl-uec_mdio"
 
 /* Write value to the PHY for this device to the register at regnum, */
 /* waiting until the write is done before it returns.  All PHY */
@@ -261,7 +260,7 @@
 };
 
 static struct of_platform_driver uec_mdio_driver = {
-	.name	= DRV_NAME,
+	.name	= MII_DRV_NAME,
 	.probe	= uec_mdio_probe,
 	.remove	= uec_mdio_remove,
 	.match_table	= uec_mdio_match,
@@ -272,7 +271,8 @@
 	return of_register_platform_driver(&uec_mdio_driver);
 }
 
-void __exit uec_mdio_exit(void)
+/* called from __init ucc_geth_init, therefore can not be __exit */
+void uec_mdio_exit(void)
 {
 	of_unregister_platform_driver(&uec_mdio_driver);
 }
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 6d95cac..61daa09 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -1474,6 +1474,7 @@
 	.suspend =	usbnet_suspend,
 	.resume =	usbnet_resume,
 	.disconnect =	usbnet_disconnect,
+	.supports_autosuspend = 1,
 };
 
 static int __init asix_init(void)
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index 16c7a0e..a2de32f 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -405,7 +405,7 @@
 	dev->net->ethtool_ops = &dm9601_ethtool_ops;
 	dev->net->hard_header_len += DM_TX_OVERHEAD;
 	dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
-	dev->rx_urb_size = dev->net->mtu + DM_RX_OVERHEAD;
+	dev->rx_urb_size = dev->net->mtu + ETH_HLEN + DM_RX_OVERHEAD;
 
 	dev->mii.dev = dev->net;
 	dev->mii.mdio_read = dm9601_mdio_read;
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index 524dc5f..58a53a6 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -1152,8 +1152,6 @@
 
 	INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl);
 
-	SET_MODULE_OWNER(netdev);
-
 	usb_set_intfdata(intf, kaweth);
 
 #if 0
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c
index a05fd97..d1ed68a 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -768,11 +768,13 @@
 static void write_bulk_callback(struct urb *urb)
 {
 	pegasus_t *pegasus = urb->context;
-	struct net_device *net = pegasus->net;
+	struct net_device *net;
 
 	if (!pegasus)
 		return;
 
+	net = pegasus->net;
+
 	if (!netif_device_present(net) || !netif_running(net))
 		return;
 
@@ -1295,6 +1297,7 @@
 	pegasus_t *pegasus;
 	int dev_index = id - pegasus_ids;
 	int res = -ENOMEM;
+	DECLARE_MAC_BUF(mac);
 
 	usb_get_dev(dev);
 	net = alloc_etherdev(sizeof(struct pegasus));
@@ -1304,7 +1307,6 @@
 	}
 
 	pegasus = netdev_priv(net);
-	memset(pegasus, 0, sizeof (struct pegasus));
 	pegasus->dev_index = dev_index;
 	init_waitqueue_head(&pegasus->ctrl_wait);
 
@@ -1320,7 +1322,6 @@
 	pegasus->intf = intf;
 	pegasus->usb = dev;
 	pegasus->net = net;
-	SET_MODULE_OWNER(net);
 	net->open = pegasus_open;
 	net->stop = pegasus_close;
 	net->watchdog_timeo = PEGASUS_TX_TIMEOUT;
@@ -1367,12 +1368,10 @@
 	queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
 				CARRIER_CHECK_DELAY);
 
-	dev_info(&intf->dev, "%s, %s, %02x:%02x:%02x:%02x:%02x:%02x\n",
-		net->name,
-		usb_dev_id[dev_index].name,
-		net->dev_addr [0], net->dev_addr [1],
-		net->dev_addr [2], net->dev_addr [3],
-		net->dev_addr [4], net->dev_addr [5]);
+	dev_info(&intf->dev, "%s, %s, %s\n",
+		 net->name,
+		 usb_dev_id[dev_index].name,
+		 print_mac(mac, net->dev_addr));
 	return 0;
 
 out3:
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index fa598f0..33cbc30 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -905,7 +905,6 @@
 	}
 
 	dev = netdev_priv(netdev);
-	memset(dev, 0, sizeof(rtl8150_t));
 
 	dev->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL);
 	if (!dev->intr_buff) {
@@ -918,7 +917,6 @@
 	
 	dev->udev = udev;
 	dev->netdev = netdev;
-	SET_MODULE_OWNER(netdev);
 	netdev->open = rtl8150_open;
 	netdev->stop = rtl8150_close;
 	netdev->do_ioctl = rtl8150_ioctl;
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 37bf4f2..acd5f1c 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -590,6 +590,7 @@
 	dev->flags = 0;
 	del_timer_sync (&dev->delay);
 	tasklet_kill (&dev->bh);
+	usb_autopm_put_interface(dev->intf);
 
 	return 0;
 }
@@ -603,9 +604,19 @@
 static int usbnet_open (struct net_device *net)
 {
 	struct usbnet		*dev = netdev_priv(net);
-	int			retval = 0;
+	int			retval;
 	struct driver_info	*info = dev->driver_info;
 
+	if ((retval = usb_autopm_get_interface(dev->intf)) < 0) {
+		if (netif_msg_ifup (dev))
+			devinfo (dev,
+				"resumption fail (%d) usbnet usb-%s-%s, %s",
+				retval,
+				dev->udev->bus->bus_name, dev->udev->devpath,
+			info->description);
+		goto done_nopm;
+	}
+
 	// put into "known safe" state
 	if (info->reset && (retval = info->reset (dev)) < 0) {
 		if (netif_msg_ifup (dev))
@@ -659,7 +670,10 @@
 
 	// delay posting reads until we're fully open
 	tasklet_schedule (&dev->bh);
+	return retval;
 done:
+	usb_autopm_put_interface(dev->intf);
+done_nopm:
 	return retval;
 }
 
@@ -1120,6 +1134,7 @@
 	struct usb_device		*xdev;
 	int				status;
 	const char			*name;
+	DECLARE_MAC_BUF(mac);
 
 	name = udev->dev.driver->name;
 	info = (struct driver_info *) prod->driver_info;
@@ -1143,6 +1158,7 @@
 
 	dev = netdev_priv(net);
 	dev->udev = xdev;
+	dev->intf = udev;
 	dev->driver_info = info;
 	dev->driver_name = name;
 	dev->msg_enable = netif_msg_init (msg_level, NETIF_MSG_DRV
@@ -1158,7 +1174,6 @@
 	init_timer (&dev->delay);
 	mutex_init (&dev->phy_mutex);
 
-	SET_MODULE_OWNER (net);
 	dev->net = net;
 	strcpy (net->name, "usb%d");
 	memcpy (net->dev_addr, node_id, sizeof node_id);
@@ -1227,14 +1242,11 @@
 	if (status)
 		goto out3;
 	if (netif_msg_probe (dev))
-		devinfo (dev, "register '%s' at usb-%s-%s, %s, "
-				"%02x:%02x:%02x:%02x:%02x:%02x",
+		devinfo (dev, "register '%s' at usb-%s-%s, %s, %s",
 			udev->dev.driver->name,
 			xdev->bus->bus_name, xdev->devpath,
 			dev->driver_info->description,
-			net->dev_addr [0], net->dev_addr [1],
-			net->dev_addr [2], net->dev_addr [3],
-			net->dev_addr [4], net->dev_addr [5]);
+			print_mac(mac, net->dev_addr));
 
 	// ok, it's ready to go.
 	usb_set_intfdata (udev, dev);
@@ -1267,12 +1279,18 @@
 	struct usbnet		*dev = usb_get_intfdata(intf);
 
 	if (!dev->suspend_count++) {
-		/* accelerate emptying of the rx and queues, to avoid
+		/*
+		 * accelerate emptying of the rx and queues, to avoid
 		 * having everything error out.
 		 */
 		netif_device_detach (dev->net);
 		(void) unlink_urbs (dev, &dev->rxq);
 		(void) unlink_urbs (dev, &dev->txq);
+		/*
+		 * reattach so runtime management can use and
+		 * wake the device
+		 */
+		netif_device_attach (dev->net);
 	}
 	return 0;
 }
@@ -1282,10 +1300,9 @@
 {
 	struct usbnet		*dev = usb_get_intfdata(intf);
 
-	if (!--dev->suspend_count) {
-		netif_device_attach (dev->net);
+	if (!--dev->suspend_count)
 		tasklet_schedule (&dev->bh);
-	}
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(usbnet_resume);
diff --git a/drivers/net/usb/usbnet.h b/drivers/net/usb/usbnet.h
index a6c5820..1fae434 100644
--- a/drivers/net/usb/usbnet.h
+++ b/drivers/net/usb/usbnet.h
@@ -28,6 +28,7 @@
 struct usbnet {
 	/* housekeeping */
 	struct usb_device	*udev;
+	struct usb_interface	*intf;
 	struct driver_info	*driver_info;
 	const char		*driver_name;
 	wait_queue_head_t	*wait;
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
new file mode 100644
index 0000000..fdd1e03
--- /dev/null
+++ b/drivers/net/veth.c
@@ -0,0 +1,482 @@
+/*
+ *  drivers/net/veth.c
+ *
+ *  Copyright (C) 2007 OpenVZ http://openvz.org, SWsoft Inc
+ *
+ * Author: Pavel Emelianov <xemul@openvz.org>
+ * Ethtool interface from: Eric W. Biederman <ebiederm@xmission.com>
+ *
+ */
+
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/etherdevice.h>
+
+#include <net/dst.h>
+#include <net/xfrm.h>
+#include <net/veth.h>
+
+#define DRV_NAME	"veth"
+#define DRV_VERSION	"1.0"
+
+struct veth_net_stats {
+	unsigned long	rx_packets;
+	unsigned long	tx_packets;
+	unsigned long	rx_bytes;
+	unsigned long	tx_bytes;
+	unsigned long	tx_dropped;
+};
+
+struct veth_priv {
+	struct net_device *peer;
+	struct net_device *dev;
+	struct list_head list;
+	struct veth_net_stats *stats;
+	unsigned ip_summed;
+};
+
+static LIST_HEAD(veth_list);
+
+/*
+ * ethtool interface
+ */
+
+static struct {
+	const char string[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+	{ "peer_ifindex" },
+};
+
+static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+	cmd->supported		= 0;
+	cmd->advertising	= 0;
+	cmd->speed		= SPEED_10000;
+	cmd->duplex		= DUPLEX_FULL;
+	cmd->port		= PORT_TP;
+	cmd->phy_address	= 0;
+	cmd->transceiver	= XCVR_INTERNAL;
+	cmd->autoneg		= AUTONEG_DISABLE;
+	cmd->maxtxpkt		= 0;
+	cmd->maxrxpkt		= 0;
+	return 0;
+}
+
+static void veth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+	strcpy(info->driver, DRV_NAME);
+	strcpy(info->version, DRV_VERSION);
+	strcpy(info->fw_version, "N/A");
+}
+
+static void veth_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
+{
+	switch(stringset) {
+	case ETH_SS_STATS:
+		memcpy(buf, &ethtool_stats_keys, sizeof(ethtool_stats_keys));
+		break;
+	}
+}
+
+static int veth_get_sset_count(struct net_device *dev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_STATS:
+		return ARRAY_SIZE(ethtool_stats_keys);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static void veth_get_ethtool_stats(struct net_device *dev,
+		struct ethtool_stats *stats, u64 *data)
+{
+	struct veth_priv *priv;
+
+	priv = netdev_priv(dev);
+	data[0] = priv->peer->ifindex;
+}
+
+static u32 veth_get_rx_csum(struct net_device *dev)
+{
+	struct veth_priv *priv;
+
+	priv = netdev_priv(dev);
+	return priv->ip_summed == CHECKSUM_UNNECESSARY;
+}
+
+static int veth_set_rx_csum(struct net_device *dev, u32 data)
+{
+	struct veth_priv *priv;
+
+	priv = netdev_priv(dev);
+	priv->ip_summed = data ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
+	return 0;
+}
+
+static u32 veth_get_tx_csum(struct net_device *dev)
+{
+	return (dev->features & NETIF_F_NO_CSUM) != 0;
+}
+
+static int veth_set_tx_csum(struct net_device *dev, u32 data)
+{
+	if (data)
+		dev->features |= NETIF_F_NO_CSUM;
+	else
+		dev->features &= ~NETIF_F_NO_CSUM;
+	return 0;
+}
+
+static struct ethtool_ops veth_ethtool_ops = {
+	.get_settings		= veth_get_settings,
+	.get_drvinfo		= veth_get_drvinfo,
+	.get_link		= ethtool_op_get_link,
+	.get_rx_csum		= veth_get_rx_csum,
+	.set_rx_csum		= veth_set_rx_csum,
+	.get_tx_csum		= veth_get_tx_csum,
+	.set_tx_csum		= veth_set_tx_csum,
+	.get_sg			= ethtool_op_get_sg,
+	.set_sg			= ethtool_op_set_sg,
+	.get_strings		= veth_get_strings,
+	.get_sset_count		= veth_get_sset_count,
+	.get_ethtool_stats	= veth_get_ethtool_stats,
+};
+
+/*
+ * xmit
+ */
+
+static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct net_device *rcv = NULL;
+	struct veth_priv *priv, *rcv_priv;
+	struct veth_net_stats *stats;
+	int length, cpu;
+
+	skb_orphan(skb);
+
+	priv = netdev_priv(dev);
+	rcv = priv->peer;
+	rcv_priv = netdev_priv(rcv);
+
+	cpu = smp_processor_id();
+	stats = per_cpu_ptr(priv->stats, cpu);
+
+	if (!(rcv->flags & IFF_UP))
+		goto outf;
+
+	skb->pkt_type = PACKET_HOST;
+	skb->protocol = eth_type_trans(skb, rcv);
+	if (dev->features & NETIF_F_NO_CSUM)
+		skb->ip_summed = rcv_priv->ip_summed;
+
+	dst_release(skb->dst);
+	skb->dst = NULL;
+	skb->mark = 0;
+	secpath_reset(skb);
+	nf_reset(skb);
+
+	length = skb->len;
+
+	stats->tx_bytes += length;
+	stats->tx_packets++;
+
+	stats = per_cpu_ptr(rcv_priv->stats, cpu);
+	stats->rx_bytes += length;
+	stats->rx_packets++;
+
+	netif_rx(skb);
+	return 0;
+
+outf:
+	kfree_skb(skb);
+	stats->tx_dropped++;
+	return 0;
+}
+
+/*
+ * general routines
+ */
+
+static struct net_device_stats *veth_get_stats(struct net_device *dev)
+{
+	struct veth_priv *priv;
+	struct net_device_stats *dev_stats;
+	int cpu;
+	struct veth_net_stats *stats;
+
+	priv = netdev_priv(dev);
+	dev_stats = &dev->stats;
+
+	dev_stats->rx_packets = 0;
+	dev_stats->tx_packets = 0;
+	dev_stats->rx_bytes = 0;
+	dev_stats->tx_bytes = 0;
+	dev_stats->tx_dropped = 0;
+
+	for_each_online_cpu(cpu) {
+		stats = per_cpu_ptr(priv->stats, cpu);
+
+		dev_stats->rx_packets += stats->rx_packets;
+		dev_stats->tx_packets += stats->tx_packets;
+		dev_stats->rx_bytes += stats->rx_bytes;
+		dev_stats->tx_bytes += stats->tx_bytes;
+		dev_stats->tx_dropped += stats->tx_dropped;
+	}
+
+	return dev_stats;
+}
+
+static int veth_open(struct net_device *dev)
+{
+	struct veth_priv *priv;
+
+	priv = netdev_priv(dev);
+	if (priv->peer == NULL)
+		return -ENOTCONN;
+
+	if (priv->peer->flags & IFF_UP) {
+		netif_carrier_on(dev);
+		netif_carrier_on(priv->peer);
+	}
+	return 0;
+}
+
+static int veth_close(struct net_device *dev)
+{
+	struct veth_priv *priv;
+
+	if (netif_carrier_ok(dev)) {
+		priv = netdev_priv(dev);
+		netif_carrier_off(dev);
+		netif_carrier_off(priv->peer);
+	}
+	return 0;
+}
+
+static int veth_dev_init(struct net_device *dev)
+{
+	struct veth_net_stats *stats;
+	struct veth_priv *priv;
+
+	stats = alloc_percpu(struct veth_net_stats);
+	if (stats == NULL)
+		return -ENOMEM;
+
+	priv = netdev_priv(dev);
+	priv->stats = stats;
+	return 0;
+}
+
+static void veth_dev_free(struct net_device *dev)
+{
+	struct veth_priv *priv;
+
+	priv = netdev_priv(dev);
+	free_percpu(priv->stats);
+	free_netdev(dev);
+}
+
+static void veth_setup(struct net_device *dev)
+{
+	ether_setup(dev);
+
+	dev->hard_start_xmit = veth_xmit;
+	dev->get_stats = veth_get_stats;
+	dev->open = veth_open;
+	dev->stop = veth_close;
+	dev->ethtool_ops = &veth_ethtool_ops;
+	dev->features |= NETIF_F_LLTX;
+	dev->init = veth_dev_init;
+	dev->destructor = veth_dev_free;
+}
+
+/*
+ * netlink interface
+ */
+
+static int veth_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+	if (tb[IFLA_ADDRESS]) {
+		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
+			return -EINVAL;
+		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
+			return -EADDRNOTAVAIL;
+	}
+	return 0;
+}
+
+static struct rtnl_link_ops veth_link_ops;
+
+static int veth_newlink(struct net_device *dev,
+			 struct nlattr *tb[], struct nlattr *data[])
+{
+	int err;
+	struct net_device *peer;
+	struct veth_priv *priv;
+	char ifname[IFNAMSIZ];
+	struct nlattr *peer_tb[IFLA_MAX + 1], **tbp;
+
+	/*
+	 * create and register peer first
+	 *
+	 * struct ifinfomsg is at the head of VETH_INFO_PEER, but we
+	 * skip it since no info from it is useful yet
+	 */
+
+	if (data != NULL && data[VETH_INFO_PEER] != NULL) {
+		struct nlattr *nla_peer;
+
+		nla_peer = data[VETH_INFO_PEER];
+		err = nla_parse(peer_tb, IFLA_MAX,
+				nla_data(nla_peer) + sizeof(struct ifinfomsg),
+				nla_len(nla_peer) - sizeof(struct ifinfomsg),
+				ifla_policy);
+		if (err < 0)
+			return err;
+
+		err = veth_validate(peer_tb, NULL);
+		if (err < 0)
+			return err;
+
+		tbp = peer_tb;
+	} else
+		tbp = tb;
+
+	if (tbp[IFLA_IFNAME])
+		nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ);
+	else
+		snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d");
+
+	peer = rtnl_create_link(dev->nd_net, ifname, &veth_link_ops, tbp);
+	if (IS_ERR(peer))
+		return PTR_ERR(peer);
+
+	if (tbp[IFLA_ADDRESS] == NULL)
+		random_ether_addr(peer->dev_addr);
+
+	err = register_netdevice(peer);
+	if (err < 0)
+		goto err_register_peer;
+
+	netif_carrier_off(peer);
+
+	/*
+	 * register dev last
+	 *
+	 * note, that since we've registered new device the dev's name
+	 * should be re-allocated
+	 */
+
+	if (tb[IFLA_ADDRESS] == NULL)
+		random_ether_addr(dev->dev_addr);
+
+	if (tb[IFLA_IFNAME])
+		nla_strlcpy(dev->name, tb[IFLA_IFNAME], IFNAMSIZ);
+	else
+		snprintf(dev->name, IFNAMSIZ, DRV_NAME "%%d");
+
+	if (strchr(dev->name, '%')) {
+		err = dev_alloc_name(dev, dev->name);
+		if (err < 0)
+			goto err_alloc_name;
+	}
+
+	err = register_netdevice(dev);
+	if (err < 0)
+		goto err_register_dev;
+
+	netif_carrier_off(dev);
+
+	/*
+	 * tie the deviced together
+	 */
+
+	priv = netdev_priv(dev);
+	priv->dev = dev;
+	priv->peer = peer;
+	list_add(&priv->list, &veth_list);
+
+	priv = netdev_priv(peer);
+	priv->dev = peer;
+	priv->peer = dev;
+	INIT_LIST_HEAD(&priv->list);
+	return 0;
+
+err_register_dev:
+	/* nothing to do */
+err_alloc_name:
+	unregister_netdevice(peer);
+	return err;
+
+err_register_peer:
+	free_netdev(peer);
+	return err;
+}
+
+static void veth_dellink(struct net_device *dev)
+{
+	struct veth_priv *priv;
+	struct net_device *peer;
+
+	priv = netdev_priv(dev);
+	peer = priv->peer;
+
+	if (!list_empty(&priv->list))
+		list_del(&priv->list);
+
+	priv = netdev_priv(peer);
+	if (!list_empty(&priv->list))
+		list_del(&priv->list);
+
+	unregister_netdevice(dev);
+	unregister_netdevice(peer);
+}
+
+static const struct nla_policy veth_policy[VETH_INFO_MAX + 1];
+
+static struct rtnl_link_ops veth_link_ops = {
+	.kind		= DRV_NAME,
+	.priv_size	= sizeof(struct veth_priv),
+	.setup		= veth_setup,
+	.validate	= veth_validate,
+	.newlink	= veth_newlink,
+	.dellink	= veth_dellink,
+	.policy		= veth_policy,
+	.maxtype	= VETH_INFO_MAX,
+};
+
+/*
+ * init/fini
+ */
+
+static __init int veth_init(void)
+{
+	return rtnl_link_register(&veth_link_ops);
+}
+
+static __exit void veth_exit(void)
+{
+	struct veth_priv *priv, *next;
+
+	rtnl_lock();
+	/*
+	 * cannot trust __rtnl_link_unregister() to unregister all
+	 * devices, as each ->dellink call will remove two devices
+	 * from the list at once.
+	 */
+	list_for_each_entry_safe(priv, next, &veth_list, list)
+		veth_dellink(priv->dev);
+
+	__rtnl_link_unregister(&veth_link_ops);
+	rtnl_unlock();
+}
+
+module_init(veth_init);
+module_exit(veth_exit);
+
+MODULE_DESCRIPTION("Virtual Ethernet Tunnel");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS_RTNL_LINK(DRV_NAME);
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index f51c2c1..07263cd 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -42,7 +42,13 @@
 
 /* Set the copy breakpoint for the copy-only-tiny-frames scheme.
    Setting to > 1518 effectively disables this feature. */
+#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \
+       || defined(CONFIG_SPARC) || defined(__ia64__) \
+       || defined(__sh__) || defined(__mips__)
+static int rx_copybreak = 1518;
+#else
 static int rx_copybreak;
+#endif
 
 /* Work-around for broken BIOSes: they are unable to get the chip back out of
    power state D3 so PXE booting fails. bootparam(7): via-rhine.avoid_D3=1 */
@@ -329,16 +335,16 @@
 
 /* The Rx and Tx buffer descriptors. */
 struct rx_desc {
-	s32 rx_status;
-	u32 desc_length; /* Chain flag, Buffer/frame length */
-	u32 addr;
-	u32 next_desc;
+	__le32 rx_status;
+	__le32 desc_length; /* Chain flag, Buffer/frame length */
+	__le32 addr;
+	__le32 next_desc;
 };
 struct tx_desc {
-	s32 tx_status;
-	u32 desc_length; /* Chain flag, Tx Config, Frame length */
-	u32 addr;
-	u32 next_desc;
+	__le32 tx_status;
+	__le32 desc_length; /* Chain flag, Tx Config, Frame length */
+	__le32 addr;
+	__le32 next_desc;
 };
 
 /* Initial value for tx_desc.desc_length, Buffer size goes to bits 0-10 */
@@ -383,6 +389,8 @@
 
 	struct pci_dev *pdev;
 	long pioaddr;
+	struct net_device *dev;
+	struct napi_struct napi;
 	struct net_device_stats stats;
 	spinlock_t lock;
 
@@ -576,28 +584,25 @@
 #endif
 
 #ifdef CONFIG_VIA_RHINE_NAPI
-static int rhine_napipoll(struct net_device *dev, int *budget)
+static int rhine_napipoll(struct napi_struct *napi, int budget)
 {
-	struct rhine_private *rp = netdev_priv(dev);
+	struct rhine_private *rp = container_of(napi, struct rhine_private, napi);
+	struct net_device *dev = rp->dev;
 	void __iomem *ioaddr = rp->base;
-	int done, limit = min(dev->quota, *budget);
+	int work_done;
 
-	done = rhine_rx(dev, limit);
-	*budget -= done;
-	dev->quota -= done;
+	work_done = rhine_rx(dev, budget);
 
-	if (done < limit) {
-		netif_rx_complete(dev);
+	if (work_done < budget) {
+		netif_rx_complete(dev, napi);
 
 		iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
 			  IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
 			  IntrTxDone | IntrTxError | IntrTxUnderrun |
 			  IntrPCIErr | IntrStatsMax | IntrLinkChange,
 			  ioaddr + IntrEnable);
-		return 0;
 	}
-	else
-		return 1;
+	return work_done;
 }
 #endif
 
@@ -633,6 +638,7 @@
 #else
 	int bar = 0;
 #endif
+	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -697,10 +703,10 @@
 		printk(KERN_ERR "alloc_etherdev failed\n");
 		goto err_out;
 	}
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	rp = netdev_priv(dev);
+	rp->dev = dev;
 	rp->quirks = quirks;
 	rp->pioaddr = pioaddr;
 	rp->pdev = pdev;
@@ -779,8 +785,7 @@
 	dev->poll_controller = rhine_poll;
 #endif
 #ifdef CONFIG_VIA_RHINE_NAPI
-	dev->poll = rhine_napipoll;
-	dev->weight = 64;
+	netif_napi_add(dev, &rp->napi, rhine_napipoll, 64);
 #endif
 	if (rp->quirks & rqRhineI)
 		dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
@@ -790,18 +795,14 @@
 	if (rc)
 		goto err_out_unmap;
 
-	printk(KERN_INFO "%s: VIA %s at 0x%lx, ",
+	printk(KERN_INFO "%s: VIA %s at 0x%lx, %s, IRQ %d.\n",
 	       dev->name, name,
 #ifdef USE_MMIO
-		memaddr
+	       memaddr,
 #else
-		(long)ioaddr
+	       (long)ioaddr,
 #endif
-		 );
-
-	for (i = 0; i < 5; i++)
-		printk("%2.2x:", dev->dev_addr[i]);
-	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], pdev->irq);
+	       print_mac(mac, dev->dev_addr), pdev->irq);
 
 	pci_set_drvdata(pdev, dev);
 
@@ -1055,7 +1056,9 @@
 
 	rhine_set_rx_mode(dev);
 
-	netif_poll_enable(dev);
+#ifdef CONFIG_VIA_RHINE_NAPI
+	napi_enable(&rp->napi);
+#endif
 
 	/* Enable interrupts by setting the interrupt mask. */
 	iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
@@ -1190,6 +1193,10 @@
 	/* protect against concurrent rx interrupts */
 	disable_irq(rp->pdev->irq);
 
+#ifdef CONFIG_VIA_RHINE_NAPI
+	napi_disable(&rp->napi);
+#endif
+
 	spin_lock(&rp->lock);
 
 	/* clear all descriptors */
@@ -1318,7 +1325,7 @@
 				  IntrPCIErr | IntrStatsMax | IntrLinkChange,
 				  ioaddr + IntrEnable);
 
-			netif_rx_schedule(dev);
+			netif_rx_schedule(dev, &rp->napi);
 #else
 			rhine_rx(dev, RX_RING_SIZE);
 #endif
@@ -1803,9 +1810,6 @@
 	.set_msglevel		= netdev_set_msglevel,
 	.get_wol		= rhine_get_wol,
 	.set_wol		= rhine_set_wol,
-	.get_sg			= ethtool_op_get_sg,
-	.get_tx_csum		= ethtool_op_get_tx_csum,
-	.get_perm_addr		= ethtool_op_get_perm_addr,
 };
 
 static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
@@ -1832,7 +1836,9 @@
 	spin_lock_irq(&rp->lock);
 
 	netif_stop_queue(dev);
-	netif_poll_disable(dev);
+#ifdef CONFIG_VIA_RHINE_NAPI
+	napi_disable(&rp->napi);
+#endif
 
 	if (debug > 1)
 		printk(KERN_DEBUG "%s: Shutting down ethercard, "
@@ -1931,6 +1937,9 @@
 	if (!netif_running(dev))
 		return 0;
 
+#ifdef CONFIG_VIA_RHINE_NAPI
+	napi_disable(&rp->napi);
+#endif
 	netif_device_detach(dev);
 	pci_save_state(pdev);
 
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index f331843..4ae0579 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -72,6 +72,7 @@
 #include <linux/mii.h>
 #include <linux/in.h>
 #include <linux/if_arp.h>
+#include <linux/if_vlan.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
@@ -84,6 +85,163 @@
 static int velocity_nics = 0;
 static int msglevel = MSG_LEVEL_INFO;
 
+/**
+ *	mac_get_cam_mask	-	Read a CAM mask
+ *	@regs: register block for this velocity
+ *	@mask: buffer to store mask
+ *
+ *	Fetch the mask bits of the selected CAM and store them into the
+ *	provided mask buffer.
+ */
+
+static void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+{
+	int i;
+
+	/* Select CAM mask */
+	BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+	writeb(0, &regs->CAMADDR);
+
+	/* read mask */
+	for (i = 0; i < 8; i++)
+		*mask++ = readb(&(regs->MARCAM[i]));
+
+	/* disable CAMEN */
+	writeb(0, &regs->CAMADDR);
+
+	/* Select mar */
+	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+}
+
+
+/**
+ *	mac_set_cam_mask	-	Set a CAM mask
+ *	@regs: register block for this velocity
+ *	@mask: CAM mask to load
+ *
+ *	Store a new mask into a CAM
+ */
+
+static void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+{
+	int i;
+	/* Select CAM mask */
+	BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+	writeb(CAMADDR_CAMEN, &regs->CAMADDR);
+
+	for (i = 0; i < 8; i++) {
+		writeb(*mask++, &(regs->MARCAM[i]));
+	}
+	/* disable CAMEN */
+	writeb(0, &regs->CAMADDR);
+
+	/* Select mar */
+	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+}
+
+static void mac_set_vlan_cam_mask(struct mac_regs __iomem * regs, u8 * mask)
+{
+	int i;
+	/* Select CAM mask */
+	BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+	writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, &regs->CAMADDR);
+
+	for (i = 0; i < 8; i++) {
+		writeb(*mask++, &(regs->MARCAM[i]));
+	}
+	/* disable CAMEN */
+	writeb(0, &regs->CAMADDR);
+
+	/* Select mar */
+	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+}
+
+/**
+ *	mac_set_cam	-	set CAM data
+ *	@regs: register block of this velocity
+ *	@idx: Cam index
+ *	@addr: 2 or 6 bytes of CAM data
+ *
+ *	Load an address or vlan tag into a CAM
+ */
+
+static void mac_set_cam(struct mac_regs __iomem * regs, int idx, const u8 *addr)
+{
+	int i;
+
+	/* Select CAM mask */
+	BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+	idx &= (64 - 1);
+
+	writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
+
+	for (i = 0; i < 6; i++) {
+		writeb(*addr++, &(regs->MARCAM[i]));
+	}
+	BYTE_REG_BITS_ON(CAMCR_CAMWR, &regs->CAMCR);
+
+	udelay(10);
+
+	writeb(0, &regs->CAMADDR);
+
+	/* Select mar */
+	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+}
+
+static void mac_set_vlan_cam(struct mac_regs __iomem * regs, int idx,
+			     const u8 *addr)
+{
+
+	/* Select CAM mask */
+	BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+
+	idx &= (64 - 1);
+
+	writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, &regs->CAMADDR);
+	writew(*((u16 *) addr), &regs->MARCAM[0]);
+
+	BYTE_REG_BITS_ON(CAMCR_CAMWR, &regs->CAMCR);
+
+	udelay(10);
+
+	writeb(0, &regs->CAMADDR);
+
+	/* Select mar */
+	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
+}
+
+
+/**
+ *	mac_wol_reset	-	reset WOL after exiting low power
+ *	@regs: register block of this velocity
+ *
+ *	Called after we drop out of wake on lan mode in order to
+ *	reset the Wake on lan features. This function doesn't restore
+ *	the rest of the logic from the result of sleep/wakeup
+ */
+
+static void mac_wol_reset(struct mac_regs __iomem * regs)
+{
+
+	/* Turn off SWPTAG right after leaving power mode */
+	BYTE_REG_BITS_OFF(STICKHW_SWPTAG, &regs->STICKHW);
+	/* clear sticky bits */
+	BYTE_REG_BITS_OFF((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
+
+	BYTE_REG_BITS_OFF(CHIPGCR_FCGMII, &regs->CHIPGCR);
+	BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
+	/* disable force PME-enable */
+	writeb(WOLCFG_PMEOVR, &regs->WOLCFGClr);
+	/* disable power-event config bit */
+	writew(0xFFFF, &regs->WOLCRClr);
+	/* clear power status */
+	writew(0xFFFF, &regs->WOLSRClr);
+}
 
 static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
 static const struct ethtool_ops velocity_ethtool_ops;
@@ -111,15 +269,6 @@
 #define TX_DESC_DEF     64
 VELOCITY_PARAM(TxDescriptors, "Number of transmit descriptors");
 
-#define VLAN_ID_MIN     0
-#define VLAN_ID_MAX     4095
-#define VLAN_ID_DEF     0
-/* VID_setting[] is used for setting the VID of NIC.
-   0: default VID.
-   1-4094: other VIDs.
-*/
-VELOCITY_PARAM(VID_setting, "802.1Q VLAN ID");
-
 #define RX_THRESH_MIN   0
 #define RX_THRESH_MAX   3
 #define RX_THRESH_DEF   0
@@ -147,13 +296,6 @@
 */
 VELOCITY_PARAM(DMA_length, "DMA length");
 
-#define TAGGING_DEF     0
-/* enable_tagging[] is used for enabling 802.1Q VID tagging.
-   0: disable VID seeting(default).
-   1: enable VID setting.
-*/
-VELOCITY_PARAM(enable_tagging, "Enable 802.1Q tagging");
-
 #define IP_ALIG_DEF     0
 /* IP_byte_align[] is used for IP header DWORD byte aligned
    0: indicate the IP header won't be DWORD byte aligned.(Default) .
@@ -324,7 +466,7 @@
  *	a pointer a static string valid while the driver is loaded.
  */
 
-static char __devinit *get_chip_name(enum chip_type chip_id)
+static const char __devinit *get_chip_name(enum chip_type chip_id)
 {
 	int i;
 	for (i = 0; chip_info_table[i].name != NULL; i++)
@@ -442,8 +584,7 @@
 	velocity_set_int_opt(&opts->DMA_length, DMA_length[index], DMA_LENGTH_MIN, DMA_LENGTH_MAX, DMA_LENGTH_DEF, "DMA_length", devname);
 	velocity_set_int_opt(&opts->numrx, RxDescriptors[index], RX_DESC_MIN, RX_DESC_MAX, RX_DESC_DEF, "RxDescriptors", devname);
 	velocity_set_int_opt(&opts->numtx, TxDescriptors[index], TX_DESC_MIN, TX_DESC_MAX, TX_DESC_DEF, "TxDescriptors", devname);
-	velocity_set_int_opt(&opts->vid, VID_setting[index], VLAN_ID_MIN, VLAN_ID_MAX, VLAN_ID_DEF, "VID_setting", devname);
-	velocity_set_bool_opt(&opts->flags, enable_tagging[index], TAGGING_DEF, VELOCITY_FLAGS_TAGGING, "enable_tagging", devname);
+
 	velocity_set_bool_opt(&opts->flags, txcsum_offload[index], TX_CSUM_DEF, VELOCITY_FLAGS_TX_CSUM, "txcsum_offload", devname);
 	velocity_set_int_opt(&opts->flow_cntl, flow_control[index], FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, "flow_control", devname);
 	velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname);
@@ -465,6 +606,7 @@
 static void velocity_init_cam_filter(struct velocity_info *vptr)
 {
 	struct mac_regs __iomem * regs = vptr->mac_regs;
+	unsigned short vid;
 
 	/* Turn on MCFG_PQEN, turn off MCFG_RTGOPT */
 	WORD_REG_BITS_SET(MCFG_PQEN, MCFG_RTGOPT, &regs->MCFG);
@@ -473,27 +615,52 @@
 	/* Disable all CAMs */
 	memset(vptr->vCAMmask, 0, sizeof(u8) * 8);
 	memset(vptr->mCAMmask, 0, sizeof(u8) * 8);
-	mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM);
-	mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
+	mac_set_vlan_cam_mask(regs, vptr->vCAMmask);
+	mac_set_cam_mask(regs, vptr->mCAMmask);
 
 	/* Enable first VCAM */
-	if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
-		/* If Tagging option is enabled and VLAN ID is not zero, then
-		   turn on MCFG_RTGOPT also */
-		if (vptr->options.vid != 0)
-			WORD_REG_BITS_ON(MCFG_RTGOPT, &regs->MCFG);
+	if (vptr->vlgrp) {
+		for (vid = 0; vid < VLAN_VID_MASK; vid++) {
+			if (vlan_group_get_device(vptr->vlgrp, vid)) {
+				/* If Tagging option is enabled and
+				   VLAN ID is not zero, then
+				   turn on MCFG_RTGOPT also */
+				if (vid != 0)
+					WORD_REG_BITS_ON(MCFG_RTGOPT, &regs->MCFG);
 
-		mac_set_cam(regs, 0, (u8 *) & (vptr->options.vid), VELOCITY_VLAN_ID_CAM);
+				mac_set_vlan_cam(regs, 0, (u8 *) &vid);
+			}
+		}
 		vptr->vCAMmask[0] |= 1;
-		mac_set_cam_mask(regs, vptr->vCAMmask, VELOCITY_VLAN_ID_CAM);
+		mac_set_vlan_cam_mask(regs, vptr->vCAMmask);
 	} else {
 		u16 temp = 0;
-		mac_set_cam(regs, 0, (u8 *) &temp, VELOCITY_VLAN_ID_CAM);
+		mac_set_vlan_cam(regs, 0, (u8 *) &temp);
 		temp = 1;
-		mac_set_cam_mask(regs, (u8 *) &temp, VELOCITY_VLAN_ID_CAM);
+		mac_set_vlan_cam_mask(regs, (u8 *) &temp);
 	}
 }
 
+static void velocity_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+{
+	struct velocity_info *vptr = netdev_priv(dev);
+
+        spin_lock_irq(&vptr->lock);
+	velocity_init_cam_filter(vptr);
+        spin_unlock_irq(&vptr->lock);
+}
+
+static void velocity_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+	struct velocity_info *vptr = netdev_priv(dev);
+
+        spin_lock_irq(&vptr->lock);
+	vlan_group_set_device(vptr->vlgrp, vid, NULL);
+	velocity_init_cam_filter(vptr);
+        spin_unlock_irq(&vptr->lock);
+}
+
+
 /**
  *	velocity_rx_reset	-	handle a receive reset
  *	@vptr: velocity we are resetting
@@ -712,7 +879,6 @@
 
 	/* Chain it all together */
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 	vptr = netdev_priv(dev);
 
@@ -791,13 +957,17 @@
 	dev->do_ioctl = velocity_ioctl;
 	dev->ethtool_ops = &velocity_ethtool_ops;
 	dev->change_mtu = velocity_change_mtu;
+
+	dev->vlan_rx_add_vid = velocity_vlan_rx_add_vid;
+	dev->vlan_rx_kill_vid = velocity_vlan_rx_kill_vid;
+
 #ifdef  VELOCITY_ZERO_COPY_SUPPORT
 	dev->features |= NETIF_F_SG;
 #endif
+	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER;
 
-	if (vptr->flags & VELOCITY_FLAGS_TX_CSUM) {
+	if (vptr->flags & VELOCITY_FLAGS_TX_CSUM)
 		dev->features |= NETIF_F_IP_CSUM;
-	}
 
 	ret = register_netdev(dev);
 	if (ret < 0)
@@ -1071,14 +1241,12 @@
 
 static int velocity_init_rd_ring(struct velocity_info *vptr)
 {
-	int ret = -ENOMEM;
-	unsigned int rsize = sizeof(struct velocity_rd_info) *
-					vptr->options.numrx;
+	int ret;
 
-	vptr->rd_info = kmalloc(rsize, GFP_KERNEL);
-	if(vptr->rd_info == NULL)
-		goto out;
-	memset(vptr->rd_info, 0, rsize);
+	vptr->rd_info = kcalloc(vptr->options.numrx,
+				sizeof(struct velocity_rd_info), GFP_KERNEL);
+	if (!vptr->rd_info)
+		return -ENOMEM;
 
 	vptr->rd_filled = vptr->rd_dirty = vptr->rd_curr = 0;
 
@@ -1088,7 +1256,7 @@
 			"%s: failed to allocate RX buffer.\n", vptr->dev->name);
 		velocity_free_rd_ring(vptr);
 	}
-out:
+
 	return ret;
 }
 
@@ -1142,21 +1310,19 @@
 	dma_addr_t curr;
 	struct tx_desc *td;
 	struct velocity_td_info *td_info;
-	unsigned int tsize = sizeof(struct velocity_td_info) *
-					vptr->options.numtx;
 
 	/* Init the TD ring entries */
 	for (j = 0; j < vptr->num_txq; j++) {
 		curr = vptr->td_pool_dma[j];
 
-		vptr->td_infos[j] = kmalloc(tsize, GFP_KERNEL);
-		if(vptr->td_infos[j] == NULL)
-		{
+		vptr->td_infos[j] = kcalloc(vptr->options.numtx,
+					    sizeof(struct velocity_td_info),
+					    GFP_KERNEL);
+		if (!vptr->td_infos[j])	{
 			while(--j >= 0)
 				kfree(vptr->td_infos[j]);
 			return -ENOMEM;
 		}
-		memset(vptr->td_infos[j], 0, tsize);
 
 		for (i = 0; i < vptr->options.numtx; i++, curr += sizeof(struct tx_desc)) {
 			td = &(vptr->td_rings[j][i]);
@@ -1613,7 +1779,7 @@
 	if (status & ISR_TXSTLI) {
 		struct mac_regs __iomem * regs = vptr->mac_regs;
 
-		printk(KERN_ERR "TD structure errror TDindex=%hx\n", readw(&regs->TDIdx[0]));
+		printk(KERN_ERR "TD structure error TDindex=%hx\n", readw(&regs->TDIdx[0]));
 		BYTE_REG_BITS_ON(TXESR_TDSTR, &regs->TXESR);
 		writew(TRDCSR_RUN, &regs->TDCSRClr);
 		netif_stop_queue(vptr->dev);
@@ -1994,8 +2160,8 @@
 		td_ptr->tdesc1.CMDZ = 2;
 	}
 
-	if (vptr->flags & VELOCITY_FLAGS_TAGGING) {
-		td_ptr->tdesc1.pqinf.VID = (vptr->options.vid & 0xfff);
+	if (vptr->vlgrp && vlan_tx_tag_present(skb)) {
+		td_ptr->tdesc1.pqinf.VID = vlan_tx_tag_get(skb);
 		td_ptr->tdesc1.pqinf.priority = 0;
 		td_ptr->tdesc1.pqinf.CFI = 0;
 		td_ptr->tdesc1.TCR |= TCR0_VETAG;
@@ -2121,14 +2287,14 @@
 		rx_mode = (RCR_AM | RCR_AB);
 	} else {
 		int offset = MCAM_SIZE - vptr->multicast_limit;
-		mac_get_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
+		mac_get_cam_mask(regs, vptr->mCAMmask);
 
 		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) {
-			mac_set_cam(regs, i + offset, mclist->dmi_addr, VELOCITY_MULTICAST_CAM);
+			mac_set_cam(regs, i + offset, mclist->dmi_addr);
 			vptr->mCAMmask[(offset + i) / 8] |= 1 << ((offset + i) & 7);
 		}
 
-		mac_set_cam_mask(regs, vptr->mCAMmask, VELOCITY_MULTICAST_CAM);
+		mac_set_cam_mask(regs, vptr->mCAMmask);
 		rx_mode = (RCR_AM | RCR_AB);
 	}
 	if (dev->mtu > 1500)
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index b9e114d..aa91796 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -1173,7 +1173,7 @@
 
 struct velocity_info_tbl {
 	enum chip_type chip_id;
-	char *name;
+	const char *name;
 	int txqueue;
 	u32 flags;
 };
@@ -1194,14 +1194,6 @@
 #define mac_disable_int(regs)       	writel(CR0_GINTMSK1,&((regs)->CR0Clr))
 #define mac_enable_int(regs)    	writel(CR0_GINTMSK1,&((regs)->CR0Set))
 
-#define mac_hw_mibs_read(regs, MIBs) {\
-	int i;\
-	BYTE_REG_BITS_ON(MIBCR_MPTRINI,&((regs)->MIBCR));\
-	for (i=0;i<HW_MIB_SIZE;i++) {\
-		(MIBs)[i]=readl(&((regs)->MIBData));\
-	}\
-}
-
 #define mac_set_dma_length(regs, n) {\
 	BYTE_REG_BITS_SET((n),0x07,&((regs)->DCFG));\
 }
@@ -1226,195 +1218,17 @@
 	writew(TRDCSR_WAK<<(n*4),&((regs)->TDCSRSet));\
 }
 
-#define mac_eeprom_reload(regs) {\
-	int i=0;\
-	BYTE_REG_BITS_ON(EECSR_RELOAD,&((regs)->EECSR));\
-	do {\
-		udelay(10);\
-		if (i++>0x1000) {\
-			break;\
-		}\
-	}while (BYTE_REG_BITS_IS_ON(EECSR_RELOAD,&((regs)->EECSR)));\
+static inline void mac_eeprom_reload(struct mac_regs __iomem * regs) {
+	int i=0;
+
+	BYTE_REG_BITS_ON(EECSR_RELOAD,&(regs->EECSR));
+	do {
+		udelay(10);
+		if (i++>0x1000)
+			break;
+	} while (BYTE_REG_BITS_IS_ON(EECSR_RELOAD,&(regs->EECSR)));
 }
 
-enum velocity_cam_type {
-	VELOCITY_VLAN_ID_CAM = 0,
-	VELOCITY_MULTICAST_CAM
-};
-
-/**
- *	mac_get_cam_mask	-	Read a CAM mask
- *	@regs: register block for this velocity
- *	@mask: buffer to store mask
- *	@cam_type: CAM to fetch
- *
- *	Fetch the mask bits of the selected CAM and store them into the
- *	provided mask buffer.
- */
-
-static inline void mac_get_cam_mask(struct mac_regs __iomem * regs, u8 * mask, enum velocity_cam_type cam_type)
-{
-	int i;
-	/* Select CAM mask */
-	BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
-	if (cam_type == VELOCITY_VLAN_ID_CAM)
-		writeb(CAMADDR_VCAMSL, &regs->CAMADDR);
-	else
-		writeb(0, &regs->CAMADDR);
-
-	/* read mask */
-	for (i = 0; i < 8; i++)
-		*mask++ = readb(&(regs->MARCAM[i]));
-
-	/* disable CAMEN */
-	writeb(0, &regs->CAMADDR);
-
-	/* Select mar */
-	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
-}
-
-/**
- *	mac_set_cam_mask	-	Set a CAM mask
- *	@regs: register block for this velocity
- *	@mask: CAM mask to load
- *	@cam_type: CAM to store
- *
- *	Store a new mask into a CAM
- */
-
-static inline void mac_set_cam_mask(struct mac_regs __iomem * regs, u8 * mask, enum velocity_cam_type cam_type)
-{
-	int i;
-	/* Select CAM mask */
-	BYTE_REG_BITS_SET(CAMCR_PS_CAM_MASK, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
-	if (cam_type == VELOCITY_VLAN_ID_CAM)
-		writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL, &regs->CAMADDR);
-	else
-		writeb(CAMADDR_CAMEN, &regs->CAMADDR);
-
-	for (i = 0; i < 8; i++) {
-		writeb(*mask++, &(regs->MARCAM[i]));
-	}
-	/* disable CAMEN */
-	writeb(0, &regs->CAMADDR);
-
-	/* Select mar */
-	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-}
-
-/**
- *	mac_set_cam	-	set CAM data
- *	@regs: register block of this velocity
- *	@idx: Cam index
- *	@addr: 2 or 6 bytes of CAM data
- *	@cam_type: CAM to load
- *
- *	Load an address or vlan tag into a CAM
- */
-
-static inline void mac_set_cam(struct mac_regs __iomem * regs, int idx, u8 *addr, enum velocity_cam_type cam_type)
-{
-	int i;
-
-	/* Select CAM mask */
-	BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
-	idx &= (64 - 1);
-
-	if (cam_type == VELOCITY_VLAN_ID_CAM)
-		writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, &regs->CAMADDR);
-	else
-		writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
-
-	if (cam_type == VELOCITY_VLAN_ID_CAM)
-		writew(*((u16 *) addr), &regs->MARCAM[0]);
-	else {
-		for (i = 0; i < 6; i++) {
-			writeb(*addr++, &(regs->MARCAM[i]));
-		}
-	}
-	BYTE_REG_BITS_ON(CAMCR_CAMWR, &regs->CAMCR);
-
-	udelay(10);
-
-	writeb(0, &regs->CAMADDR);
-
-	/* Select mar */
-	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-}
-
-/**
- *	mac_get_cam	-	fetch CAM data
- *	@regs: register block of this velocity
- *	@idx: Cam index
- *	@addr: buffer to hold up to 6 bytes of CAM data
- *	@cam_type: CAM to load
- *
- *	Load an address or vlan tag from a CAM into the buffer provided by
- *	the caller. VLAN tags are 2 bytes the address cam entries are 6.
- */
-
-static inline void mac_get_cam(struct mac_regs __iomem * regs, int idx, u8 *addr, enum velocity_cam_type cam_type)
-{
-	int i;
-
-	/* Select CAM mask */
-	BYTE_REG_BITS_SET(CAMCR_PS_CAM_DATA, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-
-	idx &= (64 - 1);
-
-	if (cam_type == VELOCITY_VLAN_ID_CAM)
-		writeb(CAMADDR_CAMEN | CAMADDR_VCAMSL | idx, &regs->CAMADDR);
-	else
-		writeb(CAMADDR_CAMEN | idx, &regs->CAMADDR);
-
-	BYTE_REG_BITS_ON(CAMCR_CAMRD, &regs->CAMCR);
-
-	udelay(10);
-
-	if (cam_type == VELOCITY_VLAN_ID_CAM)
-		*((u16 *) addr) = readw(&(regs->MARCAM[0]));
-	else
-		for (i = 0; i < 6; i++, addr++)
-			*((u8 *) addr) = readb(&(regs->MARCAM[i]));
-
-	writeb(0, &regs->CAMADDR);
-
-	/* Select mar */
-	BYTE_REG_BITS_SET(CAMCR_PS_MAR, CAMCR_PS1 | CAMCR_PS0, &regs->CAMCR);
-}
-
-/**
- *	mac_wol_reset	-	reset WOL after exiting low power
- *	@regs: register block of this velocity
- *
- *	Called after we drop out of wake on lan mode in order to
- *	reset the Wake on lan features. This function doesn't restore
- *	the rest of the logic from the result of sleep/wakeup
- */
-
-static inline void mac_wol_reset(struct mac_regs __iomem * regs)
-{
-
-	/* Turn off SWPTAG right after leaving power mode */
-	BYTE_REG_BITS_OFF(STICKHW_SWPTAG, &regs->STICKHW);
-	/* clear sticky bits */
-	BYTE_REG_BITS_OFF((STICKHW_DS1 | STICKHW_DS0), &regs->STICKHW);
-
-	BYTE_REG_BITS_OFF(CHIPGCR_FCGMII, &regs->CHIPGCR);
-	BYTE_REG_BITS_OFF(CHIPGCR_FCMODE, &regs->CHIPGCR);
-	/* disable force PME-enable */
-	writeb(WOLCFG_PMEOVR, &regs->WOLCFGClr);
-	/* disable power-event config bit */
-	writew(0xFFFF, &regs->WOLCRClr);
-	/* clear power status */
-	writew(0xFFFF, &regs->WOLSRClr);
-}
-
-
 /*
  * Header for WOL definitions. Used to compute hashes
  */
@@ -1701,7 +1515,7 @@
 	int numrx;			/* Number of RX descriptors */
 	int numtx;			/* Number of TX descriptors */
 	enum speed_opt spd_dpx;		/* Media link mode */
-	int vid;			/* vlan id */
+
 	int DMA_length;			/* DMA length */
 	int rx_thresh;			/* RX_THRESH */
 	int flow_cntl;
@@ -1727,6 +1541,7 @@
 	dma_addr_t tx_bufs_dma;
 	u8 *tx_bufs;
 
+	struct vlan_group    *vlgrp;
 	u8 ip_addr[4];
 	enum chip_type chip_id;
 
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c
index 6b63b35..c4c8eab 100644
--- a/drivers/net/wan/c101.c
+++ b/drivers/net/wan/c101.c
@@ -315,12 +315,11 @@
 		return -ENODEV;
 	}
 
-	card = kmalloc(sizeof(card_t), GFP_KERNEL);
+	card = kzalloc(sizeof(card_t), GFP_KERNEL);
 	if (card == NULL) {
 		printk(KERN_ERR "c101: unable to allocate memory\n");
 		return -ENOBUFS;
 	}
-	memset(card, 0, sizeof(card_t));
 
 	card->dev = alloc_hdlcdev(card);
 	if (!card->dev) {
@@ -364,7 +363,6 @@
 	hdlc = dev_to_hdlc(dev);
 
 	spin_lock_init(&card->lock);
-	SET_MODULE_OWNER(dev);
 	dev->irq = irq;
 	dev->mem_start = winbase;
 	dev->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1;
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 9ef49ce..26058b4 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -572,13 +572,11 @@
 	sprintf(cosa->name, "cosa%d", cosa->num);
 
 	/* Initialize the per-channel data */
-	cosa->chan = kmalloc(sizeof(struct channel_data)*cosa->nchannels,
-			     GFP_KERNEL);
+	cosa->chan = kcalloc(cosa->nchannels, sizeof(struct channel_data), GFP_KERNEL);
 	if (!cosa->chan) {
 	        err = -ENOMEM;
 		goto err_out3;
 	}
-	memset(cosa->chan, 0, sizeof(struct channel_data)*cosa->nchannels);
 	for (i=0; i<cosa->nchannels; i++) {
 		cosa->chan[i].cosa = cosa;
 		cosa->chan[i].num = i;
diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c
index 6e5f1c8..a0e8611 100644
--- a/drivers/net/wan/cycx_main.c
+++ b/drivers/net/wan/cycx_main.c
@@ -113,12 +113,10 @@
 	/* Verify number of cards and allocate adapter data space */
 	cycx_ncards = min_t(int, cycx_ncards, CYCX_MAX_CARDS);
 	cycx_ncards = max_t(int, cycx_ncards, 1);
-	cycx_card_array = kmalloc(sizeof(struct cycx_device) * cycx_ncards,
-				  GFP_KERNEL);
+	cycx_card_array = kcalloc(cycx_ncards, sizeof(struct cycx_device), GFP_KERNEL);
 	if (!cycx_card_array)
 		goto out;
 
-	memset(cycx_card_array, 0, sizeof(struct cycx_device) * cycx_ncards);
 
 	/* Register adapters with WAN router */
 	for (cnt = 0; cnt < cycx_ncards; ++cnt) {
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
index 016b3ff..8a1778c 100644
--- a/drivers/net/wan/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
@@ -131,14 +131,15 @@
 	   cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev);
 
 /* Network device interface */
-static int cycx_netdevice_init(struct net_device *dev),
-	   cycx_netdevice_open(struct net_device *dev),
-	   cycx_netdevice_stop(struct net_device *dev),
-	   cycx_netdevice_hard_header(struct sk_buff *skb,
-				     struct net_device *dev, u16 type,
-				     void *daddr, void *saddr, unsigned len),
-	   cycx_netdevice_rebuild_header(struct sk_buff *skb),
-	   cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
+static int cycx_netdevice_init(struct net_device *dev);
+static int cycx_netdevice_open(struct net_device *dev);
+static int cycx_netdevice_stop(struct net_device *dev);
+static int cycx_netdevice_hard_header(struct sk_buff *skb,
+				      struct net_device *dev, u16 type,
+				      const void *daddr, const void *saddr,
+				      unsigned len);
+static int cycx_netdevice_rebuild_header(struct sk_buff *skb);
+static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
 					  struct net_device *dev);
 
 static struct net_device_stats *
@@ -376,11 +377,10 @@
 	}
 
 	/* allocate and initialize private data */
-	chan = kmalloc(sizeof(struct cycx_x25_channel), GFP_KERNEL);
+	chan = kzalloc(sizeof(struct cycx_x25_channel), GFP_KERNEL);
 	if (!chan)
 		return -ENOMEM;
 
-	memset(chan, 0, sizeof(*chan));
 	strcpy(chan->name, conf->name);
 	chan->card = card;
 	chan->link = conf->port;
@@ -469,7 +469,14 @@
 	return 0;
 }
 
+
 /* Network Device Interface */
+
+static const struct header_ops cycx_header_ops = {
+	.create = cycx_netdevice_hard_header,
+	.rebuild = cycx_netdevice_rebuild_header,
+};
+
 /* Initialize Linux network interface.
  *
  * This routine is called only once for each interface, during Linux network
@@ -484,8 +491,8 @@
 	/* Initialize device driver entry points */
 	dev->open		= cycx_netdevice_open;
 	dev->stop		= cycx_netdevice_stop;
-	dev->hard_header	= cycx_netdevice_hard_header;
-	dev->rebuild_header	= cycx_netdevice_rebuild_header;
+	dev->header_ops		= &cycx_header_ops;
+
 	dev->hard_start_xmit	= cycx_netdevice_hard_start_xmit;
 	dev->get_stats		= cycx_netdevice_get_stats;
 
@@ -509,7 +516,6 @@
 
 	/* Set transmit buffer queue length */
 	dev->tx_queue_len	= 10;
-	SET_MODULE_OWNER(dev);
 
 	/* Initialize socket buffers */
 	cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
@@ -556,7 +562,8 @@
  * Return:	media header length. */
 static int cycx_netdevice_hard_header(struct sk_buff *skb,
 				      struct net_device *dev, u16 type,
-				      void *daddr, void *saddr, unsigned len)
+				      const void *daddr, const void *saddr,
+				      unsigned len)
 {
 	skb->protocol = type;
 
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 66be20c..96b2324 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -66,8 +66,8 @@
  */
 
 static int dlci_header(struct sk_buff *skb, struct net_device *dev, 
-                           unsigned short type, void *daddr, void *saddr, 
-                           unsigned len)
+		       unsigned short type, const void *daddr,
+		       const void *saddr, unsigned len)
 {
 	struct frhdr		hdr;
 	struct dlci_local	*dlp;
@@ -361,7 +361,7 @@
 
 
 	/* validate slave device */
-	slave = dev_get_by_name(dlci->devname);
+	slave = dev_get_by_name(&init_net, dlci->devname);
 	if (!slave)
 		return -ENODEV;
 
@@ -427,7 +427,7 @@
 	int			err;
 
 	/* validate slave device */
-	master = __dev_get_by_name(dlci->devname);
+	master = __dev_get_by_name(&init_net, dlci->devname);
 	if (!master)
 		return(-ENODEV);
 
@@ -485,6 +485,10 @@
 	return(err);
 }
 
+static const struct header_ops dlci_header_ops = {
+	.create	= dlci_header,
+};
+
 static void dlci_setup(struct net_device *dev)
 {
 	struct dlci_local *dlp = dev->priv;
@@ -494,7 +498,7 @@
 	dev->stop		= dlci_close;
 	dev->do_ioctl		= dlci_dev_ioctl;
 	dev->hard_start_xmit	= dlci_transmit;
-	dev->hard_header	= dlci_header;
+	dev->header_ops		= &dlci_header_ops;
 	dev->get_stats		= dlci_get_stats;
 	dev->change_mtu		= dlci_change_mtu;
 	dev->destructor		= free_netdev;
@@ -513,6 +517,9 @@
 {
 	struct net_device *dev = (struct net_device *) ptr;
 
+	if (dev->nd_net != &init_net)
+		return NOTIFY_DONE;
+
 	if (event == NETDEV_UNREGISTER) {
 		struct dlci_local *dlp;
 
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index dca0244..33dc713 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -890,12 +890,11 @@
 	struct dscc4_dev_priv *root;
 	int i, ret = -ENOMEM;
 
-	root = kmalloc(dev_per_card*sizeof(*root), GFP_KERNEL);
+	root = kcalloc(dev_per_card, sizeof(*root), GFP_KERNEL);
 	if (!root) {
 		printk(KERN_ERR "%s: can't allocate data\n", DRV_NAME);
 		goto err_out;
 	}
-	memset(root, 0, dev_per_card*sizeof(*root));
 
 	for (i = 0; i < dev_per_card; i++) {
 		root[i].dev = alloc_hdlcdev(root + i);
@@ -903,12 +902,11 @@
 			goto err_free_dev;
 	}
 
-	ppriv = kmalloc(sizeof(*ppriv), GFP_KERNEL);
+	ppriv = kzalloc(sizeof(*ppriv), GFP_KERNEL);
 	if (!ppriv) {
 		printk(KERN_ERR "%s: can't allocate private data\n", DRV_NAME);
 		goto err_free_dev;
 	}
-	memset(ppriv, 0, sizeof(struct dscc4_pci_priv));
 
 	ppriv->root = root;
 	spin_lock_init(&ppriv->lock);
@@ -927,7 +925,6 @@
 	        d->do_ioctl = dscc4_ioctl;
 		d->tx_timeout = dscc4_tx_timeout;
 		d->watchdog_timeo = TX_TIMEOUT;
-		SET_MODULE_OWNER(d);
 		SET_NETDEV_DEV(d, &pdev->dev);
 
 		dpriv->dev_id = i;
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 58a53b6..12dae8e 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -2476,13 +2476,12 @@
 	}
 
 	/* Allocate driver private data */
-	card = kmalloc(sizeof (struct fst_card_info), GFP_KERNEL);
+	card = kzalloc(sizeof (struct fst_card_info), GFP_KERNEL);
 	if (card == NULL) {
 		printk_err("FarSync card found but insufficient memory for"
 			   " driver storage\n");
 		return -ENOMEM;
 	}
-	memset(card, 0, sizeof (struct fst_card_info));
 
 	/* Try to enable the device */
 	if ((err = pci_enable_device(pdev)) != 0) {
diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c
index 65ad2e2..d553e6f 100644
--- a/drivers/net/wan/hdlc.c
+++ b/drivers/net/wan/hdlc.c
@@ -36,6 +36,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/notifier.h>
 #include <linux/hdlc.h>
+#include <net/net_namespace.h>
 
 
 static const char* version = "HDLC support module revision 1.21";
@@ -66,6 +67,12 @@
 		    struct packet_type *p, struct net_device *orig_dev)
 {
 	struct hdlc_device_desc *desc = dev_to_desc(dev);
+
+	if (dev->nd_net != &init_net) {
+		kfree_skb(skb);
+		return 0;
+	}
+
 	if (desc->netif_rx)
 		return desc->netif_rx(skb);
 
@@ -102,6 +109,9 @@
 	unsigned long flags;
 	int on;
  
+	if (dev->nd_net != &init_net)
+		return NOTIFY_DONE;
+
 	if (dev->get_stats != hdlc_get_stats)
 		return NOTIFY_DONE; /* not an HDLC device */
  
@@ -222,6 +232,8 @@
 	return -EINVAL;
 }
 
+static const struct header_ops hdlc_null_ops;
+
 static void hdlc_setup_dev(struct net_device *dev)
 {
 	/* Re-init all variables changed by HDLC protocol drivers,
@@ -233,13 +245,9 @@
 	dev->type		 = ARPHRD_RAWHDLC;
 	dev->hard_header_len	 = 16;
 	dev->addr_len		 = 0;
-	dev->hard_header	 = NULL;
-	dev->rebuild_header	 = NULL;
-	dev->set_mac_address	 = NULL;
-	dev->hard_header_cache	 = NULL;
-	dev->header_cache_update = NULL;
+	dev->header_ops		 = &hdlc_null_ops;
+
 	dev->change_mtu		 = hdlc_change_mtu;
-	dev->hard_header_parse	 = NULL;
 }
 
 static void hdlc_setup(struct net_device *dev)
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index 9ec6cf2..038a6e7 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -74,7 +74,7 @@
 
 
 static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
-			     u16 type, void *daddr, void *saddr,
+			     u16 type, const void *daddr, const void *saddr,
 			     unsigned int len)
 {
 	struct hdlc_header *data;
@@ -309,7 +309,6 @@
 }
 
 
-
 static struct hdlc_proto proto = {
 	.start		= cisco_start,
 	.stop		= cisco_stop,
@@ -317,7 +316,10 @@
 	.ioctl		= cisco_ioctl,
 	.module		= THIS_MODULE,
 };
- 
+
+static const struct header_ops cisco_header_ops = {
+	.create = cisco_hard_header,
+};
  
 static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
 {
@@ -365,7 +367,7 @@
 
 		memcpy(&state(hdlc)->settings, &new_settings, size);
 		dev->hard_start_xmit = hdlc->xmit;
-		dev->hard_header = cisco_hard_header;
+		dev->header_ops = &cisco_header_ops;
 		dev->type = ARPHRD_CISCO;
 		netif_dormant_on(dev);
 		return 0;
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index 15b6e07..071a64c 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -212,14 +212,13 @@
 		pvc_p = &(*pvc_p)->next;
 	}
 
-	pvc = kmalloc(sizeof(pvc_device), GFP_ATOMIC);
+	pvc = kzalloc(sizeof(pvc_device), GFP_ATOMIC);
 #ifdef DEBUG_PVC
 	printk(KERN_DEBUG "add_pvc: allocated pvc %p, frad %p\n", pvc, dev);
 #endif
 	if (!pvc)
 		return NULL;
 
-	memset(pvc, 0, sizeof(pvc_device));
 	pvc->dlci = dlci;
 	pvc->frad = dev;
 	pvc->next = *pvc_p;	/* Put it in the chain */
diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
index 4591437..3caeb52 100644
--- a/drivers/net/wan/hdlc_ppp.c
+++ b/drivers/net/wan/hdlc_ppp.c
@@ -73,7 +73,7 @@
 
 	sppp_close(dev);
 	sppp_detach(dev);
-	dev->rebuild_header = NULL;
+
 	dev->change_mtu = state(hdlc)->old_change_mtu;
 	dev->mtu = HDLC_MAX_MTU;
 	dev->hard_header_len = 16;
diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c
index 9ba3e4e..83dbc92 100644
--- a/drivers/net/wan/hostess_sv11.c
+++ b/drivers/net/wan/hostess_sv11.c
@@ -231,19 +231,16 @@
 		return NULL;
 	}
 	
-	sv = kmalloc(sizeof(struct sv11_device), GFP_KERNEL);
+	sv = kzalloc(sizeof(struct sv11_device), GFP_KERNEL);
 	if(!sv)
 		goto fail3;
 			
-	memset(sv, 0, sizeof(*sv));
 	sv->if_ptr=&sv->netdev;
 	
 	sv->netdev.dev = alloc_netdev(0, "hdlc%d", sv11_setup);
 	if(!sv->netdev.dev)
 		goto fail2;
 
-	SET_MODULE_OWNER(sv->netdev.dev);
-
 	dev=&sv->sync;
 	
 	/*
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index 6c302e9..fb37b80 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -91,6 +91,9 @@
 	int len, err;
 	struct lapbethdev *lapbeth;
 
+	if (dev->nd_net != &init_net)
+		goto drop;
+
 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
 		return NET_RX_DROP;
 
@@ -213,7 +216,7 @@
 
 	skb->dev = dev = lapbeth->ethdev;
 
-	dev->hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
+	dev_hard_header(skb, dev, ETH_P_DEC, bcast_addr, NULL, 0);
 
 	dev_queue_xmit(skb);
 }
@@ -326,7 +329,6 @@
 	dev->hard_header_len = 3;
 	dev->mtu             = 1000;
 	dev->addr_len        = 0;
-	SET_MODULE_OWNER(dev);
 }
 
 /*
@@ -391,6 +393,9 @@
 	struct lapbethdev *lapbeth;
 	struct net_device *dev = ptr;
 
+	if (dev->nd_net != &init_net)
+		return NOTIFY_DONE;
+
 	if (!dev_is_ethdev(dev))
 		return NOTIFY_DONE;
 
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index ae132c1..5ea8772 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -883,7 +883,6 @@
     dev->base_addr = pci_resource_start(pdev, 0);
     dev->irq = pdev->irq;
 
-    SET_MODULE_OWNER(dev);
     SET_NETDEV_DEV(dev, &pdev->dev);
 
     /*
diff --git a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c
index 31e17995..426c067 100644
--- a/drivers/net/wan/lmc/lmc_proto.c
+++ b/drivers/net/wan/lmc/lmc_proto.c
@@ -111,7 +111,7 @@
              * They set a few basics because they don't use sync_ppp
              */
             dev->flags |= IFF_POINTOPOINT;
-            dev->hard_header = NULL;
+
             dev->hard_header_len = 0;
             dev->addr_len = 0;
         }
diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c
index 5c322df..0a566b0 100644
--- a/drivers/net/wan/n2.c
+++ b/drivers/net/wan/n2.c
@@ -351,12 +351,11 @@
 		return -ENODEV;
 	}
 
-	card = kmalloc(sizeof(card_t), GFP_KERNEL);
+	card = kzalloc(sizeof(card_t), GFP_KERNEL);
 	if (card == NULL) {
 		printk(KERN_ERR "n2: unable to allocate memory\n");
 		return -ENOBUFS;
 	}
-	memset(card, 0, sizeof(card_t));
 
 	card->ports[0].dev = alloc_hdlcdev(&card->ports[0]);
 	card->ports[1].dev = alloc_hdlcdev(&card->ports[1]);
@@ -460,7 +459,6 @@
 			port->log_node = 1;
 
 		spin_lock_init(&port->lock);
-		SET_MODULE_OWNER(dev);
 		dev->irq = irq;
 		dev->mem_start = winbase;
 		dev->mem_end = winbase + USE_WINDOWSIZE - 1;
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
index 5d8c78e..99fee2f 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -3456,7 +3456,7 @@
 	if ((err = pci_enable_device(pdev)) < 0)
 		return err;
 
-	card = kmalloc(sizeof(pc300_t), GFP_KERNEL);
+	card = kzalloc(sizeof(pc300_t), GFP_KERNEL);
 	if (card == NULL) {
 		printk("PC300 found at RAM 0x%016llx, "
 		       "but could not allocate card structure.\n",
@@ -3464,7 +3464,6 @@
 		err = -ENOMEM;
 		goto err_disable_dev;
 	}
-	memset(card, 0, sizeof(pc300_t));
 
 	err = -ENODEV;
 
diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c
index dfbd3b0..bf1b015 100644
--- a/drivers/net/wan/pc300too.c
+++ b/drivers/net/wan/pc300too.c
@@ -334,14 +334,13 @@
 		return i;
 	}
 
-	card = kmalloc(sizeof(card_t), GFP_KERNEL);
+	card = kzalloc(sizeof(card_t), GFP_KERNEL);
 	if (card == NULL) {
 		printk(KERN_ERR "pc300: unable to allocate memory\n");
 		pci_release_regions(pdev);
 		pci_disable_device(pdev);
 		return -ENOBUFS;
 	}
-	memset(card, 0, sizeof(card_t));
 	pci_set_drvdata(pdev, card);
 
 	if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 ||
@@ -469,7 +468,6 @@
 		port->phy_node = i;
 
 		spin_lock_init(&port->lock);
-		SET_MODULE_OWNER(dev);
 		dev->irq = card->irq;
 		dev->mem_start = ramphys;
 		dev->mem_end = ramphys + ramsize - 1;
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c
index 7f720de..b595b64e 100644
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -312,14 +312,13 @@
 		return i;
 	}
 
-	card = kmalloc(sizeof(card_t), GFP_KERNEL);
+	card = kzalloc(sizeof(card_t), GFP_KERNEL);
 	if (card == NULL) {
 		printk(KERN_ERR "pci200syn: unable to allocate memory\n");
 		pci_release_regions(pdev);
 		pci_disable_device(pdev);
 		return -ENOBUFS;
 	}
-	memset(card, 0, sizeof(card_t));
 	pci_set_drvdata(pdev, card);
 	card->ports[0].dev = alloc_hdlcdev(&card->ports[0]);
 	card->ports[1].dev = alloc_hdlcdev(&card->ports[1]);
@@ -416,7 +415,6 @@
 		port->phy_node = i;
 
 		spin_lock_init(&port->lock);
-		SET_MODULE_OWNER(dev);
 		dev->irq = card->irq;
 		dev->mem_start = ramphys;
 		dev->mem_end = ramphys + ramsize - 1;
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index 1cc18e7..76db40d 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -54,6 +54,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 
+#include <net/net_namespace.h>
 #include <net/arp.h>
 
 #include <asm/io.h>
@@ -215,8 +216,6 @@
 	dev->get_stats		= &sbni_get_stats;
 	dev->set_multicast_list	= &set_multicast_list;
 	dev->do_ioctl		= &sbni_ioctl;
-
-	SET_MODULE_OWNER( dev );
 }
 
 int __init sbni_probe(int unit)
@@ -1361,7 +1360,7 @@
 
 		if (copy_from_user( slave_name, ifr->ifr_data, sizeof slave_name ))
 			return -EFAULT;
-		slave_dev = dev_get_by_name( slave_name );
+		slave_dev = dev_get_by_name(&init_net, slave_name );
 		if( !slave_dev  ||  !(slave_dev->flags & IFF_UP) ) {
 			printk( KERN_ERR "%s: trying to enslave non-active "
 				"device %s\n", dev->name, slave_name );
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index 6a485f0..b39a541 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -1196,10 +1196,9 @@
 		
 	if (read)
 	{	
-		temp = kmalloc(mem.len, GFP_KERNEL);
+		temp = kzalloc(mem.len, GFP_KERNEL);
 		if (!temp)
 			return(-ENOMEM);
-		memset(temp, 0, mem.len);
 		sdla_read(dev, mem.addr, temp, mem.len);
 		if(copy_to_user(mem.data, temp, mem.len))
 		{
@@ -1604,7 +1603,6 @@
 
 	netdev_boot_setup_check(dev);
 
-	SET_MODULE_OWNER(dev);
 	dev->flags		= 0;
 	dev->type		= 0xFFFF;
 	dev->hard_header_len	= 0;
diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c
index 1313581..11276bf 100644
--- a/drivers/net/wan/sealevel.c
+++ b/drivers/net/wan/sealevel.c
@@ -270,11 +270,10 @@
 		return NULL;
 	}
 	
-	b = kmalloc(sizeof(struct slvl_board), GFP_KERNEL);
+	b = kzalloc(sizeof(struct slvl_board), GFP_KERNEL);
 	if(!b)
 		goto fail3;
 
-	memset(b, 0, sizeof(*b));
 	if (!(b->dev[0]= slvl_alloc(iobase, irq)))
 		goto fail2;
 
diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
index 67fc67c..232ecba 100644
--- a/drivers/net/wan/syncppp.c
+++ b/drivers/net/wan/syncppp.c
@@ -51,6 +51,7 @@
 #include <linux/spinlock.h>
 #include <linux/rcupdate.h>
 
+#include <net/net_namespace.h>
 #include <net/syncppp.h>
 
 #include <asm/byteorder.h>
@@ -358,8 +359,10 @@
  *	Handle transmit packets.
  */
  
-static int sppp_hard_header(struct sk_buff *skb, struct net_device *dev, __u16 type,
-		void *daddr, void *saddr, unsigned int len)
+static int sppp_hard_header(struct sk_buff *skb,
+			    struct net_device *dev, __u16 type,
+			    const void *daddr, const void *saddr,
+			    unsigned int len)
 {
 	struct sppp *sp = (struct sppp *)sppp_of(dev);
 	struct ppp_header *h;
@@ -391,10 +394,9 @@
 	return sizeof(struct ppp_header);
 }
 
-static int sppp_rebuild_header(struct sk_buff *skb)
-{
-	return 0;
-}
+static const struct header_ops sppp_header_ops = {
+	.create = sppp_hard_header,
+};
 
 /*
  * Send keepalive packets, every 10 seconds.
@@ -1097,8 +1099,8 @@
 	 *	hard_start_xmit.
 	 */
 	 
-	dev->hard_header = sppp_hard_header;
-	dev->rebuild_header = sppp_rebuild_header;
+	dev->header_ops = &sppp_header_ops;
+
 	dev->tx_queue_len = 10;
 	dev->type = ARPHRD_HDLC;
 	dev->addr_len = 0;
@@ -1114,8 +1116,6 @@
 	dev->stop = sppp_close;
 #endif	
 	dev->change_mtu = sppp_change_mtu;
-	dev->hard_header_cache = NULL;
-	dev->header_cache_update = NULL;
 	dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP;
 }
 
@@ -1445,6 +1445,11 @@
 
 static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev)
 {
+	if (dev->nd_net != &init_net) {
+		kfree_skb(skb);
+		return 0;
+	}
+
 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
 		return NET_RX_DROP;
 	sppp_input(dev,skb);
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index c7360157..8e320b7 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -599,7 +599,7 @@
 	}
 
 	alloc_size = sizeof(card_t) + ports * sizeof(port_t);
-	card = kmalloc(alloc_size, GFP_KERNEL);
+	card = kzalloc(alloc_size, GFP_KERNEL);
 	if (card == NULL) {
 		printk(KERN_ERR "wanXL %s: unable to allocate memory\n",
 		       pci_name(pdev));
@@ -607,7 +607,6 @@
 		pci_disable_device(pdev);
 		return -ENOBUFS;
 	}
-	memset(card, 0, alloc_size);
 
 	pci_set_drvdata(pdev, card);
 	card->pdev = pdev;
@@ -780,7 +779,6 @@
 		port->dev = dev;
 		hdlc = dev_to_hdlc(dev);
 		spin_lock_init(&port->lock);
-		SET_MODULE_OWNER(dev);
 		dev->tx_queue_len = 50;
 		dev->do_ioctl = wanxl_ioctl;
 		dev->open = wanxl_open;
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 1c9edd9..c48b1cc 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -786,14 +786,12 @@
 	printk(KERN_INFO "X.25 async: version 0.00 ALPHA "
 			"(dynamic channels, max=%d).\n", x25_asy_maxdev );
 
-	x25_asy_devs = kmalloc(sizeof(struct net_device *)*x25_asy_maxdev, 
-			       GFP_KERNEL);
+	x25_asy_devs = kcalloc(x25_asy_maxdev, sizeof(struct net_device*), GFP_KERNEL);
 	if (!x25_asy_devs) {
 		printk(KERN_WARNING "X25 async: Can't allocate x25_asy_ctrls[] "
 				"array! Uaargh! (-> No X.25 available)\n");
 		return -ENOMEM;
 	}
-	memset(x25_asy_devs, 0, sizeof(struct net_device *)*x25_asy_maxdev); 
 
 	return tty_register_ldisc(N_X25, &x25_ldisc);
 }
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index a032681..fa14255 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -93,8 +93,6 @@
 	int mem_start = dev->mem_start;
 	int mem_end = dev->mem_end;
 
-	SET_MODULE_OWNER(dev);
-
 	if (base_addr > 0x1ff) {	/* Check a user specified location. */
 		r = request_region(base_addr, WD_IO_EXTENT, "wd-probe");
 		if ( r == NULL)
@@ -158,6 +156,7 @@
 	int word16 = 0;				/* 0 = 8 bit, 1 = 16 bit */
 	const char *model_name;
 	static unsigned version_printed;
+	DECLARE_MAC_BUF(mac);
 
 	for (i = 0; i < 8; i++)
 		checksum += inb(ioaddr + 8 + i);
@@ -176,9 +175,11 @@
 	if (ei_debug  &&  version_printed++ == 0)
 		printk(version);
 
-	printk("%s: WD80x3 at %#3x,", dev->name, ioaddr);
 	for (i = 0; i < 6; i++)
-		printk(" %2.2X", dev->dev_addr[i] = inb(ioaddr + 8 + i));
+		dev->dev_addr[i] = inb(ioaddr + 8 + i);
+
+	printk("%s: WD80x3 at %#3x, %s",
+	       dev->name, ioaddr, print_mac(mac, dev->dev_addr));
 
 	/* The following PureData probe code was contributed by
 	   Mike Jagdis <jaggy@purplet.demon.co.uk>. Puredata does software
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index ae27af0..5a6fdfd 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -63,11 +63,6 @@
 	  a Radio LAN (wireless Ethernet-like Local Area Network) using the
 	  radio frequencies 900 MHz and 2.4 GHz.
 
-	  This driver support the ISA version of the WaveLAN card.  A separate
-	  driver for the PCMCIA (PC-card) hardware is available in David
-	  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
-	  for location).
-
 	  If you want to use an ISA WaveLAN card under Linux, say Y and read
 	  the Ethernet-HOWTO, available from
 	  <http://www.tldp.org/docs.html#howto>. Some more specific
@@ -280,6 +275,13 @@
 	---help---
 	  A driver for Marvell Libertas 8388 USB devices.
 
+config LIBERTAS_CS
+	tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards"
+	depends on LIBERTAS && PCMCIA && EXPERIMENTAL
+	select FW_LOADER
+	---help---
+	  A driver for Marvell Libertas 8385 CompactFlash devices.
+
 config LIBERTAS_DEBUG
 	bool "Enable full debugging output in the Libertas module."
 	depends on LIBERTAS
@@ -379,30 +381,6 @@
 	  common.  Some of the built-in wireless adaptors in laptops are of
 	  this variety.
 
-config ATMEL
-      tristate "Atmel at76c50x chipset  802.11b support"
-      depends on (PCI || PCMCIA) && WLAN_80211
-      select WIRELESS_EXT
-      select FW_LOADER
-      select CRC32
-       ---help---
-        A driver 802.11b wireless cards based on the Atmel fast-vnet
-        chips. This driver supports standard Linux wireless extensions. 
- 
-        Many  cards based on this chipset do not have flash memory
-        and need their firmware loaded at start-up. If yours is 
-        one of these, you will need to provide a firmware image
-        to be loaded into the card by the driver. The Atmel
-        firmware package can be downloaded from
-        <http://www.thekelleys.org.uk/atmel>
-
-config PCI_ATMEL
-      tristate "Atmel at76c506 PCI cards"
-      depends on ATMEL && PCI
-       ---help---
-        Enable support for PCI and mini-PCI cards containing the
-        Atmel at76c506 chip.
-
 config PCMCIA_HERMES
 	tristate "Hermes PCMCIA card support"
 	depends on PCMCIA && HERMES
@@ -414,12 +392,7 @@
 	  such as the Linksys, D-Link and Farallon Skyline.  It should also
 	  work on Symbol cards such as the 3Com AirConnect and Ericsson WLAN.
 
-	  To use your PC-cards, you will need supporting software from David
-	  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
-	  for location).  You also want to check out the PCMCIA-HOWTO,
-	  available from <http://www.tldp.org/docs.html#howto>.
-
-	  You will also very likely also need the Wireless Tools in order to
+	  You will very likely need the Wireless Tools in order to
 	  configure your card and that /etc/pcmcia/wireless.opts works:
 	  <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>.
 
@@ -437,6 +410,40 @@
 	  for downloading Symbol firmware are available at
 	  <http://sourceforge.net/projects/orinoco/>
 
+config ATMEL
+      tristate "Atmel at76c50x chipset  802.11b support"
+      depends on (PCI || PCMCIA) && WLAN_80211
+      select WIRELESS_EXT
+      select FW_LOADER
+      select CRC32
+       ---help---
+        A driver 802.11b wireless cards based on the Atmel fast-vnet
+        chips. This driver supports standard Linux wireless extensions.
+
+        Many  cards based on this chipset do not have flash memory
+        and need their firmware loaded at start-up. If yours is
+        one of these, you will need to provide a firmware image
+        to be loaded into the card by the driver. The Atmel
+        firmware package can be downloaded from
+        <http://www.thekelleys.org.uk/atmel>
+
+config PCI_ATMEL
+      tristate "Atmel at76c506 PCI cards"
+      depends on ATMEL && PCI
+       ---help---
+        Enable support for PCI and mini-PCI cards containing the
+        Atmel at76c506 chip.
+
+config PCMCIA_ATMEL
+	tristate "Atmel at76c502/at76c504 PCMCIA cards"
+	depends on ATMEL && PCMCIA
+	select WIRELESS_EXT
+	select FW_LOADER
+	select CRC32
+	---help---
+	  Enable support for PCMCIA cards containing the
+	  Atmel at76c502 and at76c504 chips.
+
 config AIRO_CS
 	tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards"
 	depends on PCMCIA && (BROKEN || !M32R) && WLAN_80211
@@ -457,21 +464,6 @@
 	  and Cisco proprietary API, so both the Linux Wireless Tools and the
 	  Cisco Linux utilities can be used to configure the card.
 
-	  To use your PC-cards, you will need supporting software from David
-	  Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
-	  for location).  You also want to check out the PCMCIA-HOWTO,
-	  available from <http://www.tldp.org/docs.html#howto>.
-
-config PCMCIA_ATMEL
-	tristate "Atmel at76c502/at76c504 PCMCIA cards"
-	depends on ATMEL && PCMCIA
-	select WIRELESS_EXT
-	select FW_LOADER
-	select CRC32
-	---help---
-	  Enable support for PCMCIA cards containing the
-	  Atmel at76c502 and at76c504 chips.
-
 config PCMCIA_WL3501
       tristate "Planet WL3501 PCMCIA cards"
       depends on EXPERIMENTAL && PCMCIA && WLAN_80211
@@ -558,8 +550,52 @@
 
 	  Thanks to Realtek for their support!
 
+config ADM8211
+	tristate "ADMtek ADM8211 support"
+	depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL
+	select CRC32
+	select EEPROM_93CX6
+	---help---
+	  This driver is for ADM8211A, ADM8211B, and ADM8211C based cards.
+	  These are PCI/mini-PCI/Cardbus 802.11b chips found in cards such as:
+
+	  Xterasys Cardbus XN-2411b
+	  Blitz NetWave Point PC
+	  TrendNet 221pc
+	  Belkin F5D6001
+	  SMC 2635W
+	  Linksys WPC11 v1
+	  Fiberline FL-WL-200X
+	  3com Office Connect (3CRSHPW796)
+	  Corega WLPCIB-11
+	  SMC 2602W V2 EU
+	  D-Link DWL-520 Revision C
+
+	  However, some of these cards have been replaced with other chips
+	  like the RTL8180L (Xterasys Cardbus XN-2411b, Belkin F5D6001) or
+	  the Ralink RT2400 (SMC2635W) without a model number change.
+
+	  Thanks to Infineon-ADMtek for their support of this driver.
+
+config P54_COMMON
+	tristate "Softmac Prism54 support"
+	depends on MAC80211 && WLAN_80211 && FW_LOADER && EXPERIMENTAL
+
+config P54_USB
+	tristate "Prism54 USB support"
+	depends on P54_COMMON && USB
+	select CRC32
+
+config P54_PCI
+	tristate "Prism54 PCI support"
+	depends on P54_COMMON && PCI
+
+source "drivers/net/wireless/iwlwifi/Kconfig"
 source "drivers/net/wireless/hostap/Kconfig"
 source "drivers/net/wireless/bcm43xx/Kconfig"
+source "drivers/net/wireless/b43/Kconfig"
+source "drivers/net/wireless/b43legacy/Kconfig"
 source "drivers/net/wireless/zd1211rw/Kconfig"
+source "drivers/net/wireless/rt2x00/Kconfig"
 
 endmenu
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index ef35bc6..6f32b53 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -36,6 +36,8 @@
 
 obj-$(CONFIG_HOSTAP)		+= hostap/
 obj-$(CONFIG_BCM43XX)		+= bcm43xx/
+obj-$(CONFIG_B43)		+= b43/
+obj-$(CONFIG_B43LEGACY)		+= b43legacy/
 obj-$(CONFIG_ZD1211RW)		+= zd1211rw/
 
 # 16-bit wireless PCMCIA client drivers
@@ -43,7 +45,16 @@
 obj-$(CONFIG_PCMCIA_WL3501)	+= wl3501_cs.o
 
 obj-$(CONFIG_USB_ZD1201)	+= zd1201.o
-obj-$(CONFIG_LIBERTAS_USB)     += libertas/
+obj-$(CONFIG_LIBERTAS)		+= libertas/
 
 rtl8187-objs		:= rtl8187_dev.o rtl8187_rtl8225.o
 obj-$(CONFIG_RTL8187)	+= rtl8187.o
+
+obj-$(CONFIG_ADM8211)	+= adm8211.o
+
+obj-$(CONFIG_IWLWIFI)	+= iwlwifi/
+obj-$(CONFIG_RT2X00)	+= rt2x00/
+
+obj-$(CONFIG_P54_COMMON)	+= p54common.o
+obj-$(CONFIG_P54_USB)		+= p54usb.o
+obj-$(CONFIG_P54_PCI)		+= p54pci.o
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
new file mode 100644
index 0000000..5bf7913
--- /dev/null
+++ b/drivers/net/wireless/adm8211.c
@@ -0,0 +1,2053 @@
+
+/*
+ * Linux device driver for ADMtek ADM8211 (IEEE 802.11b MAC/BBP)
+ *
+ * Copyright (c) 2003, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2007, Michael Wu <flamingice@sourmilk.net>
+ * Some parts copyright (c) 2003 by David Young <dyoung@pobox.com>
+ * and used with permission.
+ *
+ * Much thanks to Infineon-ADMtek for their support of this driver.
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/if.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/crc32.h>
+#include <linux/eeprom_93cx6.h>
+#include <net/mac80211.h>
+
+#include "adm8211.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_AUTHOR("Jouni Malinen <j@w1.fi>");
+MODULE_DESCRIPTION("Driver for IEEE 802.11b wireless cards based on ADMtek ADM8211");
+MODULE_SUPPORTED_DEVICE("ADM8211");
+MODULE_LICENSE("GPL");
+
+static unsigned int tx_ring_size __read_mostly = 16;
+static unsigned int rx_ring_size __read_mostly = 16;
+
+module_param(tx_ring_size, uint, 0);
+module_param(rx_ring_size, uint, 0);
+
+static struct pci_device_id adm8211_pci_id_table[] __devinitdata = {
+	/* ADMtek ADM8211 */
+	{ PCI_DEVICE(0x10B7, 0x6000) }, /* 3Com 3CRSHPW796 */
+	{ PCI_DEVICE(0x1200, 0x8201) }, /* ? */
+	{ PCI_DEVICE(0x1317, 0x8201) }, /* ADM8211A */
+	{ PCI_DEVICE(0x1317, 0x8211) }, /* ADM8211B/C */
+	{ 0 }
+};
+
+static void adm8211_eeprom_register_read(struct eeprom_93cx6 *eeprom)
+{
+	struct adm8211_priv *priv = eeprom->data;
+	u32 reg = ADM8211_CSR_READ(SPR);
+
+	eeprom->reg_data_in = reg & ADM8211_SPR_SDI;
+	eeprom->reg_data_out = reg & ADM8211_SPR_SDO;
+	eeprom->reg_data_clock = reg & ADM8211_SPR_SCLK;
+	eeprom->reg_chip_select = reg & ADM8211_SPR_SCS;
+}
+
+static void adm8211_eeprom_register_write(struct eeprom_93cx6 *eeprom)
+{
+	struct adm8211_priv *priv = eeprom->data;
+	u32 reg = 0x4000 | ADM8211_SPR_SRS;
+
+	if (eeprom->reg_data_in)
+		reg |= ADM8211_SPR_SDI;
+	if (eeprom->reg_data_out)
+		reg |= ADM8211_SPR_SDO;
+	if (eeprom->reg_data_clock)
+		reg |= ADM8211_SPR_SCLK;
+	if (eeprom->reg_chip_select)
+		reg |= ADM8211_SPR_SCS;
+
+	ADM8211_CSR_WRITE(SPR, reg);
+	ADM8211_CSR_READ(SPR);		/* eeprom_delay */
+}
+
+static int adm8211_read_eeprom(struct ieee80211_hw *dev)
+{
+	struct adm8211_priv *priv = dev->priv;
+	unsigned int words, i;
+	struct ieee80211_chan_range chan_range;
+	u16 cr49;
+	struct eeprom_93cx6 eeprom = {
+		.data		= priv,
+		.register_read	= adm8211_eeprom_register_read,
+		.register_write	= adm8211_eeprom_register_write
+	};
+
+	if (ADM8211_CSR_READ(CSR_TEST0) & ADM8211_CSR_TEST0_EPTYP) {
+		/* 256 * 16-bit = 512 bytes */
+		eeprom.width = PCI_EEPROM_WIDTH_93C66;
+		words = 256;
+	} else {
+		/* 64 * 16-bit = 128 bytes */
+		eeprom.width = PCI_EEPROM_WIDTH_93C46;
+		words = 64;
+	}
+
+	priv->eeprom_len = words * 2;
+	priv->eeprom = kmalloc(priv->eeprom_len, GFP_KERNEL);
+	if (!priv->eeprom)
+		return -ENOMEM;
+
+	eeprom_93cx6_multiread(&eeprom, 0, (__le16 __force *)priv->eeprom, words);
+
+	cr49 = le16_to_cpu(priv->eeprom->cr49);
+	priv->rf_type = (cr49 >> 3) & 0x7;
+	switch (priv->rf_type) {
+	case ADM8211_TYPE_INTERSIL:
+	case ADM8211_TYPE_RFMD:
+	case ADM8211_TYPE_MARVEL:
+	case ADM8211_TYPE_AIROHA:
+	case ADM8211_TYPE_ADMTEK:
+		break;
+
+	default:
+		if (priv->pdev->revision < ADM8211_REV_CA)
+			priv->rf_type = ADM8211_TYPE_RFMD;
+		else
+			priv->rf_type = ADM8211_TYPE_AIROHA;
+
+		printk(KERN_WARNING "%s (adm8211): Unknown RFtype %d\n",
+		       pci_name(priv->pdev), (cr49 >> 3) & 0x7);
+	}
+
+	priv->bbp_type = cr49 & 0x7;
+	switch (priv->bbp_type) {
+	case ADM8211_TYPE_INTERSIL:
+	case ADM8211_TYPE_RFMD:
+	case ADM8211_TYPE_MARVEL:
+	case ADM8211_TYPE_AIROHA:
+	case ADM8211_TYPE_ADMTEK:
+		break;
+	default:
+		if (priv->pdev->revision < ADM8211_REV_CA)
+			priv->bbp_type = ADM8211_TYPE_RFMD;
+		else
+			priv->bbp_type = ADM8211_TYPE_ADMTEK;
+
+		printk(KERN_WARNING "%s (adm8211): Unknown BBPtype: %d\n",
+		       pci_name(priv->pdev), cr49 >> 3);
+	}
+
+	if (priv->eeprom->country_code >= ARRAY_SIZE(cranges)) {
+		printk(KERN_WARNING "%s (adm8211): Invalid country code (%d)\n",
+		       pci_name(priv->pdev), priv->eeprom->country_code);
+
+		chan_range = cranges[2];
+	} else
+		chan_range = cranges[priv->eeprom->country_code];
+
+	printk(KERN_DEBUG "%s (adm8211): Channel range: %d - %d\n",
+	       pci_name(priv->pdev), (int)chan_range.min, (int)chan_range.max);
+
+	priv->modes[0].num_channels = chan_range.max - chan_range.min + 1;
+	priv->modes[0].channels = priv->channels;
+
+	memcpy(priv->channels, adm8211_channels, sizeof(adm8211_channels));
+
+	for (i = 1; i <= ARRAY_SIZE(adm8211_channels); i++)
+		if (i >= chan_range.min && i <= chan_range.max)
+			priv->channels[i - 1].flag =
+				IEEE80211_CHAN_W_SCAN |
+				IEEE80211_CHAN_W_ACTIVE_SCAN |
+				IEEE80211_CHAN_W_IBSS;
+
+	switch (priv->eeprom->specific_bbptype) {
+	case ADM8211_BBP_RFMD3000:
+	case ADM8211_BBP_RFMD3002:
+	case ADM8211_BBP_ADM8011:
+		priv->specific_bbptype = priv->eeprom->specific_bbptype;
+		break;
+
+	default:
+		if (priv->pdev->revision < ADM8211_REV_CA)
+			priv->specific_bbptype = ADM8211_BBP_RFMD3000;
+		else
+			priv->specific_bbptype = ADM8211_BBP_ADM8011;
+
+		printk(KERN_WARNING "%s (adm8211): Unknown specific BBP: %d\n",
+		       pci_name(priv->pdev), priv->eeprom->specific_bbptype);
+	}
+
+	switch (priv->eeprom->specific_rftype) {
+	case ADM8211_RFMD2948:
+	case ADM8211_RFMD2958:
+	case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+	case ADM8211_MAX2820:
+	case ADM8211_AL2210L:
+		priv->transceiver_type = priv->eeprom->specific_rftype;
+		break;
+
+	default:
+		if (priv->pdev->revision == ADM8211_REV_BA)
+			priv->transceiver_type = ADM8211_RFMD2958_RF3000_CONTROL_POWER;
+		else if (priv->pdev->revision == ADM8211_REV_CA)
+			priv->transceiver_type = ADM8211_AL2210L;
+		else if (priv->pdev->revision == ADM8211_REV_AB)
+			priv->transceiver_type = ADM8211_RFMD2948;
+
+		printk(KERN_WARNING "%s (adm8211): Unknown transceiver: %d\n",
+		       pci_name(priv->pdev), priv->eeprom->specific_rftype);
+
+		break;
+	}
+
+	printk(KERN_DEBUG "%s (adm8211): RFtype=%d BBPtype=%d Specific BBP=%d "
+               "Transceiver=%d\n", pci_name(priv->pdev), priv->rf_type,
+	       priv->bbp_type, priv->specific_bbptype, priv->transceiver_type);
+
+	return 0;
+}
+
+static inline void adm8211_write_sram(struct ieee80211_hw *dev,
+				      u32 addr, u32 data)
+{
+	struct adm8211_priv *priv = dev->priv;
+
+	ADM8211_CSR_WRITE(WEPCTL, addr | ADM8211_WEPCTL_TABLE_WR |
+			  (priv->pdev->revision < ADM8211_REV_BA ?
+			   0 : ADM8211_WEPCTL_SEL_WEPTABLE ));
+	ADM8211_CSR_READ(WEPCTL);
+	msleep(1);
+
+	ADM8211_CSR_WRITE(WESK, data);
+	ADM8211_CSR_READ(WESK);
+	msleep(1);
+}
+
+static void adm8211_write_sram_bytes(struct ieee80211_hw *dev,
+				     unsigned int addr, u8 *buf,
+				     unsigned int len)
+{
+	struct adm8211_priv *priv = dev->priv;
+	u32 reg = ADM8211_CSR_READ(WEPCTL);
+	unsigned int i;
+
+	if (priv->pdev->revision < ADM8211_REV_BA) {
+		for (i = 0; i < len; i += 2) {
+			u16 val = buf[i] | (buf[i + 1] << 8);
+			adm8211_write_sram(dev, addr + i / 2, val);
+		}
+	} else {
+		for (i = 0; i < len; i += 4) {
+			u32 val = (buf[i + 0] << 0 ) | (buf[i + 1] << 8 ) |
+				  (buf[i + 2] << 16) | (buf[i + 3] << 24);
+			adm8211_write_sram(dev, addr + i / 4, val);
+		}
+	}
+
+	ADM8211_CSR_WRITE(WEPCTL, reg);
+}
+
+static void adm8211_clear_sram(struct ieee80211_hw *dev)
+{
+	struct adm8211_priv *priv = dev->priv;
+	u32 reg = ADM8211_CSR_READ(WEPCTL);
+	unsigned int addr;
+
+	for (addr = 0; addr < ADM8211_SRAM_SIZE; addr++)
+		adm8211_write_sram(dev, addr, 0);
+
+	ADM8211_CSR_WRITE(WEPCTL, reg);
+}
+
+static int adm8211_get_stats(struct ieee80211_hw *dev,
+			     struct ieee80211_low_level_stats *stats)
+{
+	struct adm8211_priv *priv = dev->priv;
+
+	memcpy(stats, &priv->stats, sizeof(*stats));
+
+	return 0;
+}
+
+static int adm8211_get_tx_stats(struct ieee80211_hw *dev,
+				struct ieee80211_tx_queue_stats *stats)
+{
+	struct adm8211_priv *priv = dev->priv;
+	struct ieee80211_tx_queue_stats_data *data = &stats->data[0];
+
+	data->len = priv->cur_tx - priv->dirty_tx;
+	data->limit = priv->tx_ring_size - 2;
+	data->count = priv->dirty_tx;
+
+	return 0;
+}
+
+static void adm8211_interrupt_tci(struct ieee80211_hw *dev)
+{
+	struct adm8211_priv *priv = dev->priv;
+	unsigned int dirty_tx;
+
+	spin_lock(&priv->lock);
+
+	for (dirty_tx = priv->dirty_tx; priv->cur_tx - dirty_tx; dirty_tx++) {
+		unsigned int entry = dirty_tx % priv->tx_ring_size;
+		u32 status = le32_to_cpu(priv->tx_ring[entry].status);
+		struct ieee80211_tx_status tx_status;
+		struct adm8211_tx_ring_info *info;
+		struct sk_buff *skb;
+
+		if (status & TDES0_CONTROL_OWN ||
+		    !(status & TDES0_CONTROL_DONE))
+			break;
+
+		info = &priv->tx_buffers[entry];
+		skb = info->skb;
+
+		/* TODO: check TDES0_STATUS_TUF and TDES0_STATUS_TRO */
+
+		pci_unmap_single(priv->pdev, info->mapping,
+				 info->skb->len, PCI_DMA_TODEVICE);
+
+		memset(&tx_status, 0, sizeof(tx_status));
+		skb_pull(skb, sizeof(struct adm8211_tx_hdr));
+		memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen);
+		memcpy(&tx_status.control, &info->tx_control,
+		       sizeof(tx_status.control));
+		if (!(tx_status.control.flags & IEEE80211_TXCTL_NO_ACK)) {
+			if (status & TDES0_STATUS_ES)
+				tx_status.excessive_retries = 1;
+			else
+				tx_status.flags |= IEEE80211_TX_STATUS_ACK;
+		}
+		ieee80211_tx_status_irqsafe(dev, skb, &tx_status);
+
+		info->skb = NULL;
+	}
+
+	if (priv->cur_tx - dirty_tx < priv->tx_ring_size - 2)
+		ieee80211_wake_queue(dev, 0);
+
+	priv->dirty_tx = dirty_tx;
+	spin_unlock(&priv->lock);
+}
+
+
+static void adm8211_interrupt_rci(struct ieee80211_hw *dev)
+{
+	struct adm8211_priv *priv = dev->priv;
+	unsigned int entry = priv->cur_rx % priv->rx_ring_size;
+	u32 status;
+	unsigned int pktlen;
+	struct sk_buff *skb, *newskb;
+	unsigned int limit = priv->rx_ring_size;
+	static const u8 rate_tbl[] = {10, 20, 55, 110, 220};
+	u8 rssi, rate;
+
+	while (!(priv->rx_ring[entry].status & cpu_to_le32(RDES0_STATUS_OWN))) {
+		if (!limit--)
+			break;
+
+		status = le32_to_cpu(priv->rx_ring[entry].status);
+		rate = (status & RDES0_STATUS_RXDR) >> 12;
+		rssi = le32_to_cpu(priv->rx_ring[entry].length) &
+			RDES1_STATUS_RSSI;
+
+		pktlen = status & RDES0_STATUS_FL;
+		if (pktlen > RX_PKT_SIZE) {
+			if (net_ratelimit())
+				printk(KERN_DEBUG "%s: frame too long (%d)\n",
+				       wiphy_name(dev->wiphy), pktlen);
+			pktlen = RX_PKT_SIZE;
+		}
+
+		if (!priv->soft_rx_crc && status & RDES0_STATUS_ES) {
+			skb = NULL; /* old buffer will be reused */
+			/* TODO: update RX error stats */
+			/* TODO: check RDES0_STATUS_CRC*E */
+		} else if (pktlen < RX_COPY_BREAK) {
+			skb = dev_alloc_skb(pktlen);
+			if (skb) {
+				pci_dma_sync_single_for_cpu(
+					priv->pdev,
+					priv->rx_buffers[entry].mapping,
+					pktlen, PCI_DMA_FROMDEVICE);
+				memcpy(skb_put(skb, pktlen),
+				       skb_tail_pointer(priv->rx_buffers[entry].skb),
+				       pktlen);
+				pci_dma_sync_single_for_device(
+					priv->pdev,
+					priv->rx_buffers[entry].mapping,
+					RX_PKT_SIZE, PCI_DMA_FROMDEVICE);
+			}
+		} else {
+			newskb = dev_alloc_skb(RX_PKT_SIZE);
+			if (newskb) {
+				skb = priv->rx_buffers[entry].skb;
+				skb_put(skb, pktlen);
+				pci_unmap_single(
+					priv->pdev,
+					priv->rx_buffers[entry].mapping,
+					RX_PKT_SIZE, PCI_DMA_FROMDEVICE);
+				priv->rx_buffers[entry].skb = newskb;
+				priv->rx_buffers[entry].mapping =
+					pci_map_single(priv->pdev,
+						       skb_tail_pointer(newskb),
+						       RX_PKT_SIZE,
+						       PCI_DMA_FROMDEVICE);
+			} else {
+				skb = NULL;
+				/* TODO: update rx dropped stats */
+			}
+
+			priv->rx_ring[entry].buffer1 =
+				cpu_to_le32(priv->rx_buffers[entry].mapping);
+		}
+
+		priv->rx_ring[entry].status = cpu_to_le32(RDES0_STATUS_OWN |
+							  RDES0_STATUS_SQL);
+		priv->rx_ring[entry].length =
+			cpu_to_le32(RX_PKT_SIZE |
+				    (entry == priv->rx_ring_size - 1 ?
+				     RDES1_CONTROL_RER : 0));
+
+		if (skb) {
+			struct ieee80211_rx_status rx_status = {0};
+
+			if (priv->pdev->revision < ADM8211_REV_CA)
+				rx_status.ssi = rssi;
+			else
+				rx_status.ssi = 100 - rssi;
+
+			if (rate <= 4)
+				rx_status.rate = rate_tbl[rate];
+
+			rx_status.channel = priv->channel;
+			rx_status.freq = adm8211_channels[priv->channel - 1].freq;
+			rx_status.phymode = MODE_IEEE80211B;
+
+			ieee80211_rx_irqsafe(dev, skb, &rx_status);
+		}
+
+		entry = (++priv->cur_rx) % priv->rx_ring_size;
+	}
+
+	/* TODO: check LPC and update stats? */
+}
+
+
+static irqreturn_t adm8211_interrupt(int irq, void *dev_id)
+{
+#define ADM8211_INT(x)							   \
+do {									   \
+	if (unlikely(stsr & ADM8211_STSR_ ## x))			   \
+		printk(KERN_DEBUG "%s: " #x "\n", wiphy_name(dev->wiphy)); \
+} while (0)
+
+	struct ieee80211_hw *dev = dev_id;
+	struct adm8211_priv *priv = dev->priv;
+	u32 stsr = ADM8211_CSR_READ(STSR);
+	ADM8211_CSR_WRITE(STSR, stsr);
+	if (stsr == 0xffffffff)
+		return IRQ_HANDLED;
+
+	if (!(stsr & (ADM8211_STSR_NISS | ADM8211_STSR_AISS)))
+		return IRQ_HANDLED;
+
+	if (stsr & ADM8211_STSR_RCI)
+		adm8211_interrupt_rci(dev);
+	if (stsr & ADM8211_STSR_TCI)
+		adm8211_interrupt_tci(dev);
+
+	/*ADM8211_INT(LinkOn);*/
+	/*ADM8211_INT(LinkOff);*/
+
+	ADM8211_INT(PCF);
+	ADM8211_INT(BCNTC);
+	ADM8211_INT(GPINT);
+	ADM8211_INT(ATIMTC);
+	ADM8211_INT(TSFTF);
+	ADM8211_INT(TSCZ);
+	ADM8211_INT(SQL);
+	ADM8211_INT(WEPTD);
+	ADM8211_INT(ATIME);
+	/*ADM8211_INT(TBTT);*/
+	ADM8211_INT(TEIS);
+	ADM8211_INT(FBE);
+	ADM8211_INT(REIS);
+	ADM8211_INT(GPTT);
+	ADM8211_INT(RPS);
+	ADM8211_INT(RDU);
+	ADM8211_INT(TUF);
+	/*ADM8211_INT(TRT);*/
+	/*ADM8211_INT(TLT);*/
+	/*ADM8211_INT(TDU);*/
+	ADM8211_INT(TPS);
+
+	return IRQ_HANDLED;
+
+#undef ADM8211_INT
+}
+
+#define WRITE_SYN(name,v_mask,v_shift,a_mask,a_shift,bits,prewrite,postwrite)\
+static void adm8211_rf_write_syn_ ## name (struct ieee80211_hw *dev,	     \
+					   u16 addr, u32 value) {	     \
+	struct adm8211_priv *priv = dev->priv;				     \
+	unsigned int i;							     \
+	u32 reg, bitbuf;						     \
+									     \
+	value &= v_mask;						     \
+	addr &= a_mask;							     \
+	bitbuf = (value << v_shift) | (addr << a_shift);		     \
+									     \
+	ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_IF_SELECT_1);		     \
+	ADM8211_CSR_READ(SYNRF);					     \
+	ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_IF_SELECT_0);		     \
+	ADM8211_CSR_READ(SYNRF);					     \
+									     \
+	if (prewrite) {							     \
+		ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_WRITE_SYNDATA_0);     \
+		ADM8211_CSR_READ(SYNRF);				     \
+	}								     \
+									     \
+	for (i = 0; i <= bits; i++) {					     \
+		if (bitbuf & (1 << (bits - i)))				     \
+			reg = ADM8211_SYNRF_WRITE_SYNDATA_1;		     \
+		else							     \
+			reg = ADM8211_SYNRF_WRITE_SYNDATA_0;		     \
+									     \
+		ADM8211_CSR_WRITE(SYNRF, reg);				     \
+		ADM8211_CSR_READ(SYNRF);				     \
+									     \
+		ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_WRITE_CLOCK_1); \
+		ADM8211_CSR_READ(SYNRF);				     \
+		ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_WRITE_CLOCK_0); \
+		ADM8211_CSR_READ(SYNRF);				     \
+	}								     \
+									     \
+	if (postwrite == 1) {						     \
+		ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_IF_SELECT_0);   \
+		ADM8211_CSR_READ(SYNRF);				     \
+	}								     \
+	if (postwrite == 2) {						     \
+		ADM8211_CSR_WRITE(SYNRF, reg | ADM8211_SYNRF_IF_SELECT_1);   \
+		ADM8211_CSR_READ(SYNRF);				     \
+	}								     \
+									     \
+	ADM8211_CSR_WRITE(SYNRF, 0);					     \
+	ADM8211_CSR_READ(SYNRF);					     \
+}
+
+WRITE_SYN(max2820,  0x00FFF, 0, 0x0F, 12, 15, 1, 1)
+WRITE_SYN(al2210l,  0xFFFFF, 4, 0x0F,  0, 23, 1, 1)
+WRITE_SYN(rfmd2958, 0x3FFFF, 0, 0x1F, 18, 23, 0, 1)
+WRITE_SYN(rfmd2948, 0x0FFFF, 4, 0x0F,  0, 21, 0, 2)
+
+#undef WRITE_SYN
+
+static int adm8211_write_bbp(struct ieee80211_hw *dev, u8 addr, u8 data)
+{
+	struct adm8211_priv *priv = dev->priv;
+	unsigned int timeout;
+	u32 reg;
+
+	timeout = 10;
+	while (timeout > 0) {
+		reg = ADM8211_CSR_READ(BBPCTL);
+		if (!(reg & (ADM8211_BBPCTL_WR | ADM8211_BBPCTL_RD)))
+			break;
+		timeout--;
+		msleep(2);
+	}
+
+	if (timeout == 0) {
+		printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed"
+		       " prewrite (reg=0x%08x)\n",
+		       wiphy_name(dev->wiphy), addr, data, reg);
+		return -ETIMEDOUT;
+	}
+
+	switch (priv->bbp_type) {
+	case ADM8211_TYPE_INTERSIL:
+		reg = ADM8211_BBPCTL_MMISEL;	/* three wire interface */
+		break;
+	case ADM8211_TYPE_RFMD:
+		reg = (0x20 << 24) | ADM8211_BBPCTL_TXCE | ADM8211_BBPCTL_CCAP |
+		      (0x01 << 18);
+		break;
+	case ADM8211_TYPE_ADMTEK:
+		reg = (0x20 << 24) | ADM8211_BBPCTL_TXCE | ADM8211_BBPCTL_CCAP |
+		      (0x05 << 18);
+		break;
+	}
+	reg |= ADM8211_BBPCTL_WR | (addr << 8) | data;
+
+	ADM8211_CSR_WRITE(BBPCTL, reg);
+
+	timeout = 10;
+	while (timeout > 0) {
+		reg = ADM8211_CSR_READ(BBPCTL);
+		if (!(reg & ADM8211_BBPCTL_WR))
+			break;
+		timeout--;
+		msleep(2);
+	}
+
+	if (timeout == 0) {
+		ADM8211_CSR_WRITE(BBPCTL, ADM8211_CSR_READ(BBPCTL) &
+				  ~ADM8211_BBPCTL_WR);
+		printk(KERN_DEBUG "%s: adm8211_write_bbp(%d,%d) failed"
+		       " postwrite (reg=0x%08x)\n",
+		       wiphy_name(dev->wiphy), addr, data, reg);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int adm8211_rf_set_channel(struct ieee80211_hw *dev, unsigned int chan)
+{
+	static const u32 adm8211_rfmd2958_reg5[] =
+		{0x22BD, 0x22D2, 0x22E8, 0x22FE, 0x2314, 0x232A, 0x2340,
+		 0x2355, 0x236B, 0x2381, 0x2397, 0x23AD, 0x23C2, 0x23F7};
+	static const u32 adm8211_rfmd2958_reg6[] =
+		{0x05D17, 0x3A2E8, 0x2E8BA, 0x22E8B, 0x1745D, 0x0BA2E, 0x00000,
+		 0x345D1, 0x28BA2, 0x1D174, 0x11745, 0x05D17, 0x3A2E8, 0x11745};
+
+	struct adm8211_priv *priv = dev->priv;
+	u8 ant_power = priv->ant_power > 0x3F ?
+		priv->eeprom->antenna_power[chan - 1] : priv->ant_power;
+	u8 tx_power = priv->tx_power > 0x3F ?
+		priv->eeprom->tx_power[chan - 1] : priv->tx_power;
+	u8 lpf_cutoff = priv->lpf_cutoff == 0xFF ?
+		priv->eeprom->lpf_cutoff[chan - 1] : priv->lpf_cutoff;
+	u8 lnags_thresh = priv->lnags_threshold == 0xFF ?
+		priv->eeprom->lnags_threshold[chan - 1] : priv->lnags_threshold;
+	u32 reg;
+
+	ADM8211_IDLE();
+
+	/* Program synthesizer to new channel */
+	switch (priv->transceiver_type) {
+	case ADM8211_RFMD2958:
+	case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+		adm8211_rf_write_syn_rfmd2958(dev, 0x00, 0x04007);
+		adm8211_rf_write_syn_rfmd2958(dev, 0x02, 0x00033);
+
+		adm8211_rf_write_syn_rfmd2958(dev, 0x05,
+			adm8211_rfmd2958_reg5[chan - 1]);
+		adm8211_rf_write_syn_rfmd2958(dev, 0x06,
+			adm8211_rfmd2958_reg6[chan - 1]);
+		break;
+
+	case ADM8211_RFMD2948:
+		adm8211_rf_write_syn_rfmd2948(dev, SI4126_MAIN_CONF,
+					      SI4126_MAIN_XINDIV2);
+		adm8211_rf_write_syn_rfmd2948(dev, SI4126_POWERDOWN,
+					      SI4126_POWERDOWN_PDIB |
+					      SI4126_POWERDOWN_PDRB);
+		adm8211_rf_write_syn_rfmd2948(dev, SI4126_PHASE_DET_GAIN, 0);
+		adm8211_rf_write_syn_rfmd2948(dev, SI4126_RF2_N_DIV,
+					      (chan == 14 ?
+					       2110 : (2033 + (chan * 5))));
+		adm8211_rf_write_syn_rfmd2948(dev, SI4126_IF_N_DIV, 1496);
+		adm8211_rf_write_syn_rfmd2948(dev, SI4126_RF2_R_DIV, 44);
+		adm8211_rf_write_syn_rfmd2948(dev, SI4126_IF_R_DIV, 44);
+		break;
+
+	case ADM8211_MAX2820:
+		adm8211_rf_write_syn_max2820(dev, 0x3,
+			(chan == 14 ? 0x054 : (0x7 + (chan * 5))));
+		break;
+
+	case ADM8211_AL2210L:
+		adm8211_rf_write_syn_al2210l(dev, 0x0,
+			(chan == 14 ? 0x229B4 : (0x22967 + (chan * 5))));
+		break;
+
+	default:
+		printk(KERN_DEBUG "%s: unsupported transceiver type %d\n",
+		       wiphy_name(dev->wiphy), priv->transceiver_type);
+		break;
+	}
+
+	/* write BBP regs */
+	if (priv->bbp_type == ADM8211_TYPE_RFMD) {
+
+	/* SMC 2635W specific? adm8211b doesn't use the 2948 though.. */
+	/* TODO: remove if SMC 2635W doesn't need this */
+	if (priv->transceiver_type == ADM8211_RFMD2948) {
+		reg = ADM8211_CSR_READ(GPIO);
+		reg &= 0xfffc0000;
+		reg |= ADM8211_CSR_GPIO_EN0;
+		if (chan != 14)
+			reg |= ADM8211_CSR_GPIO_O0;
+		ADM8211_CSR_WRITE(GPIO, reg);
+	}
+
+	if (priv->transceiver_type == ADM8211_RFMD2958) {
+		/* set PCNT2 */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x0B, 0x07100);
+		/* set PCNT1 P_DESIRED/MID_BIAS */
+		reg = le16_to_cpu(priv->eeprom->cr49);
+		reg >>= 13;
+		reg <<= 15;
+		reg |= ant_power << 9;
+		adm8211_rf_write_syn_rfmd2958(dev, 0x0A, reg);
+		/* set TXRX TX_GAIN */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x09, 0x00050 |
+			(priv->pdev->revision < ADM8211_REV_CA ? tx_power : 0));
+	} else {
+		reg = ADM8211_CSR_READ(PLCPHD);
+		reg &= 0xff00ffff;
+		reg |= tx_power << 18;
+		ADM8211_CSR_WRITE(PLCPHD, reg);
+	}
+
+	ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_SELRF |
+			  ADM8211_SYNRF_PE1 | ADM8211_SYNRF_PHYRST);
+	ADM8211_CSR_READ(SYNRF);
+	msleep(30);
+
+	/* RF3000 BBP */
+	if (priv->transceiver_type != ADM8211_RFMD2958)
+		adm8211_write_bbp(dev, RF3000_TX_VAR_GAIN__TX_LEN_EXT,
+				  tx_power<<2);
+	adm8211_write_bbp(dev, RF3000_LOW_GAIN_CALIB, lpf_cutoff);
+	adm8211_write_bbp(dev, RF3000_HIGH_GAIN_CALIB, lnags_thresh);
+	adm8211_write_bbp(dev, 0x1c, priv->pdev->revision == ADM8211_REV_BA ?
+				     priv->eeprom->cr28 : 0);
+	adm8211_write_bbp(dev, 0x1d, priv->eeprom->cr29);
+
+	ADM8211_CSR_WRITE(SYNRF, 0);
+
+	/* Nothing to do for ADMtek BBP */
+	} else if (priv->bbp_type != ADM8211_TYPE_ADMTEK)
+		printk(KERN_DEBUG "%s: unsupported BBP type %d\n",
+		       wiphy_name(dev->wiphy), priv->bbp_type);
+
+	ADM8211_RESTORE();
+
+	/* update current channel for adhoc (and maybe AP mode) */
+	reg = ADM8211_CSR_READ(CAP0);
+	reg &= ~0xF;
+	reg |= chan;
+	ADM8211_CSR_WRITE(CAP0, reg);
+
+	return 0;
+}
+
+static void adm8211_update_mode(struct ieee80211_hw *dev)
+{
+	struct adm8211_priv *priv = dev->priv;
+
+	ADM8211_IDLE();
+
+	priv->soft_rx_crc = 0;
+	switch (priv->mode) {
+	case IEEE80211_IF_TYPE_STA:
+		priv->nar &= ~(ADM8211_NAR_PR | ADM8211_NAR_EA);
+		priv->nar |= ADM8211_NAR_ST | ADM8211_NAR_SR;
+		break;
+	case IEEE80211_IF_TYPE_IBSS:
+		priv->nar &= ~ADM8211_NAR_PR;
+		priv->nar |= ADM8211_NAR_EA | ADM8211_NAR_ST | ADM8211_NAR_SR;
+
+		/* don't trust the error bits on rev 0x20 and up in adhoc */
+		if (priv->pdev->revision >= ADM8211_REV_BA)
+			priv->soft_rx_crc = 1;
+		break;
+	case IEEE80211_IF_TYPE_MNTR:
+		priv->nar &= ~(ADM8211_NAR_EA | ADM8211_NAR_ST);
+		priv->nar |= ADM8211_NAR_PR | ADM8211_NAR_SR;
+		break;
+	}
+
+	ADM8211_RESTORE();
+}
+
+static void adm8211_hw_init_syn(struct ieee80211_hw *dev)
+{
+	struct adm8211_priv *priv = dev->priv;
+
+	switch (priv->transceiver_type) {
+	case ADM8211_RFMD2958:
+	case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+		/* comments taken from ADMtek vendor driver */
+
+		/* Reset RF2958 after power on */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x1F, 0x00000);
+		/* Initialize RF VCO Core Bias to maximum */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x0C, 0x3001F);
+		/* Initialize IF PLL */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x01, 0x29C03);
+		/* Initialize IF PLL Coarse Tuning */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x03, 0x1FF6F);
+		/* Initialize RF PLL */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x04, 0x29403);
+		/* Initialize RF PLL Coarse Tuning */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x07, 0x1456F);
+		/* Initialize TX gain and filter BW (R9) */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x09,
+			(priv->transceiver_type == ADM8211_RFMD2958 ?
+			 0x10050 : 0x00050));
+		/* Initialize CAL register */
+		adm8211_rf_write_syn_rfmd2958(dev, 0x08, 0x3FFF8);
+		break;
+
+	case ADM8211_MAX2820:
+		adm8211_rf_write_syn_max2820(dev, 0x1, 0x01E);
+		adm8211_rf_write_syn_max2820(dev, 0x2, 0x001);
+		adm8211_rf_write_syn_max2820(dev, 0x3, 0x054);
+		adm8211_rf_write_syn_max2820(dev, 0x4, 0x310);
+		adm8211_rf_write_syn_max2820(dev, 0x5, 0x000);
+		break;
+
+	case ADM8211_AL2210L:
+		adm8211_rf_write_syn_al2210l(dev, 0x0, 0x0196C);
+		adm8211_rf_write_syn_al2210l(dev, 0x1, 0x007CB);
+		adm8211_rf_write_syn_al2210l(dev, 0x2, 0x3582F);
+		adm8211_rf_write_syn_al2210l(dev, 0x3, 0x010A9);
+		adm8211_rf_write_syn_al2210l(dev, 0x4, 0x77280);
+		adm8211_rf_write_syn_al2210l(dev, 0x5, 0x45641);
+		adm8211_rf_write_syn_al2210l(dev, 0x6, 0xEA130);
+		adm8211_rf_write_syn_al2210l(dev, 0x7, 0x80000);
+		adm8211_rf_write_syn_al2210l(dev, 0x8, 0x7850F);
+		adm8211_rf_write_syn_al2210l(dev, 0x9, 0xF900C);
+		adm8211_rf_write_syn_al2210l(dev, 0xA, 0x00000);
+		adm8211_rf_write_syn_al2210l(dev, 0xB, 0x00000);
+		break;
+
+	case ADM8211_RFMD2948:
+	default:
+		break;
+	}
+}
+
+static int adm8211_hw_init_bbp(struct ieee80211_hw *dev)
+{
+	struct adm8211_priv *priv = dev->priv;
+	u32 reg;
+
+	/* write addresses */
+	if (priv->bbp_type == ADM8211_TYPE_INTERSIL) {
+		ADM8211_CSR_WRITE(MMIWA,  0x100E0C0A);
+		ADM8211_CSR_WRITE(MMIRD0, 0x00007C7E);
+		ADM8211_CSR_WRITE(MMIRD1, 0x00100000);
+	} else if (priv->bbp_type == ADM8211_TYPE_RFMD ||
+		   priv->bbp_type == ADM8211_TYPE_ADMTEK) {
+		/* check specific BBP type */
+		switch (priv->specific_bbptype) {
+		case ADM8211_BBP_RFMD3000:
+		case ADM8211_BBP_RFMD3002:
+			ADM8211_CSR_WRITE(MMIWA,  0x00009101);
+			ADM8211_CSR_WRITE(MMIRD0, 0x00000301);
+			break;
+
+		case ADM8211_BBP_ADM8011:
+			ADM8211_CSR_WRITE(MMIWA,  0x00008903);
+			ADM8211_CSR_WRITE(MMIRD0, 0x00001716);
+
+			reg = ADM8211_CSR_READ(BBPCTL);
+			reg &= ~ADM8211_BBPCTL_TYPE;
+			reg |= 0x5 << 18;
+			ADM8211_CSR_WRITE(BBPCTL, reg);
+			break;
+		}
+
+		switch (priv->pdev->revision) {
+		case ADM8211_REV_CA:
+			if (priv->transceiver_type == ADM8211_RFMD2958 ||
+			    priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER ||
+			    priv->transceiver_type == ADM8211_RFMD2948)
+				ADM8211_CSR_WRITE(SYNCTL, 0x1 << 22);
+			else if (priv->transceiver_type == ADM8211_MAX2820 ||
+				 priv->transceiver_type == ADM8211_AL2210L)
+				ADM8211_CSR_WRITE(SYNCTL, 0x3 << 22);
+			break;
+
+		case ADM8211_REV_BA:
+			reg  = ADM8211_CSR_READ(MMIRD1);
+			reg &= 0x0000FFFF;
+			reg |= 0x7e100000;
+			ADM8211_CSR_WRITE(MMIRD1, reg);
+			break;
+
+		case ADM8211_REV_AB:
+		case ADM8211_REV_AF:
+		default:
+			ADM8211_CSR_WRITE(MMIRD1, 0x7e100000);
+			break;
+		}
+
+		/* For RFMD */
+		ADM8211_CSR_WRITE(MACTEST, 0x800);
+	}
+
+	adm8211_hw_init_syn(dev);
+
+	/* Set RF Power control IF pin to PE1+PHYRST# */
+	ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_SELRF |
+			  ADM8211_SYNRF_PE1 | ADM8211_SYNRF_PHYRST);
+	ADM8211_CSR_READ(SYNRF);
+	msleep(20);
+
+	/* write BBP regs */
+	if (priv->bbp_type == ADM8211_TYPE_RFMD) {
+		/* RF3000 BBP */
+		/* another set:
+		 * 11: c8
+		 * 14: 14
+		 * 15: 50 (chan 1..13; chan 14: d0)
+		 * 1c: 00
+		 * 1d: 84
+		 */
+		adm8211_write_bbp(dev, RF3000_CCA_CTRL, 0x80);
+		/* antenna selection: diversity */
+		adm8211_write_bbp(dev, RF3000_DIVERSITY__RSSI, 0x80);
+		adm8211_write_bbp(dev, RF3000_TX_VAR_GAIN__TX_LEN_EXT, 0x74);
+		adm8211_write_bbp(dev, RF3000_LOW_GAIN_CALIB, 0x38);
+		adm8211_write_bbp(dev, RF3000_HIGH_GAIN_CALIB, 0x40);
+
+		if (priv->eeprom->major_version < 2) {
+			adm8211_write_bbp(dev, 0x1c, 0x00);
+			adm8211_write_bbp(dev, 0x1d, 0x80);
+		} else {
+			if (priv->pdev->revision == ADM8211_REV_BA)
+				adm8211_write_bbp(dev, 0x1c, priv->eeprom->cr28);
+			else
+				adm8211_write_bbp(dev, 0x1c, 0x00);
+
+			adm8211_write_bbp(dev, 0x1d, priv->eeprom->cr29);
+		}
+	} else if (priv->bbp_type == ADM8211_TYPE_ADMTEK) {
+		/* reset baseband */
+		adm8211_write_bbp(dev, 0x00, 0xFF);
+		/* antenna selection: diversity */
+		adm8211_write_bbp(dev, 0x07, 0x0A);
+
+		/* TODO: find documentation for this */
+		switch (priv->transceiver_type) {
+		case ADM8211_RFMD2958:
+		case ADM8211_RFMD2958_RF3000_CONTROL_POWER:
+			adm8211_write_bbp(dev, 0x00, 0x00);
+			adm8211_write_bbp(dev, 0x01, 0x00);
+			adm8211_write_bbp(dev, 0x02, 0x00);
+			adm8211_write_bbp(dev, 0x03, 0x00);
+			adm8211_write_bbp(dev, 0x06, 0x0f);
+			adm8211_write_bbp(dev, 0x09, 0x00);
+			adm8211_write_bbp(dev, 0x0a, 0x00);
+			adm8211_write_bbp(dev, 0x0b, 0x00);
+			adm8211_write_bbp(dev, 0x0c, 0x00);
+			adm8211_write_bbp(dev, 0x0f, 0xAA);
+			adm8211_write_bbp(dev, 0x10, 0x8c);
+			adm8211_write_bbp(dev, 0x11, 0x43);
+			adm8211_write_bbp(dev, 0x18, 0x40);
+			adm8211_write_bbp(dev, 0x20, 0x23);
+			adm8211_write_bbp(dev, 0x21, 0x02);
+			adm8211_write_bbp(dev, 0x22, 0x28);
+			adm8211_write_bbp(dev, 0x23, 0x30);
+			adm8211_write_bbp(dev, 0x24, 0x2d);
+			adm8211_write_bbp(dev, 0x28, 0x35);
+			adm8211_write_bbp(dev, 0x2a, 0x8c);
+			adm8211_write_bbp(dev, 0x2b, 0x81);
+			adm8211_write_bbp(dev, 0x2c, 0x44);
+			adm8211_write_bbp(dev, 0x2d, 0x0A);
+			adm8211_write_bbp(dev, 0x29, 0x40);
+			adm8211_write_bbp(dev, 0x60, 0x08);
+			adm8211_write_bbp(dev, 0x64, 0x01);
+			break;
+
+		case ADM8211_MAX2820:
+			adm8211_write_bbp(dev, 0x00, 0x00);
+			adm8211_write_bbp(dev, 0x01, 0x00);
+			adm8211_write_bbp(dev, 0x02, 0x00);
+			adm8211_write_bbp(dev, 0x03, 0x00);
+			adm8211_write_bbp(dev, 0x06, 0x0f);
+			adm8211_write_bbp(dev, 0x09, 0x05);
+			adm8211_write_bbp(dev, 0x0a, 0x02);
+			adm8211_write_bbp(dev, 0x0b, 0x00);
+			adm8211_write_bbp(dev, 0x0c, 0x0f);
+			adm8211_write_bbp(dev, 0x0f, 0x55);
+			adm8211_write_bbp(dev, 0x10, 0x8d);
+			adm8211_write_bbp(dev, 0x11, 0x43);
+			adm8211_write_bbp(dev, 0x18, 0x4a);
+			adm8211_write_bbp(dev, 0x20, 0x20);
+			adm8211_write_bbp(dev, 0x21, 0x02);
+			adm8211_write_bbp(dev, 0x22, 0x23);
+			adm8211_write_bbp(dev, 0x23, 0x30);
+			adm8211_write_bbp(dev, 0x24, 0x2d);
+			adm8211_write_bbp(dev, 0x2a, 0x8c);
+			adm8211_write_bbp(dev, 0x2b, 0x81);
+			adm8211_write_bbp(dev, 0x2c, 0x44);
+			adm8211_write_bbp(dev, 0x29, 0x4a);
+			adm8211_write_bbp(dev, 0x60, 0x2b);
+			adm8211_write_bbp(dev, 0x64, 0x01);
+			break;
+
+		case ADM8211_AL2210L:
+			adm8211_write_bbp(dev, 0x00, 0x00);
+			adm8211_write_bbp(dev, 0x01, 0x00);
+			adm8211_write_bbp(dev, 0x02, 0x00);
+			adm8211_write_bbp(dev, 0x03, 0x00);
+			adm8211_write_bbp(dev, 0x06, 0x0f);
+			adm8211_write_bbp(dev, 0x07, 0x05);
+			adm8211_write_bbp(dev, 0x08, 0x03);
+			adm8211_write_bbp(dev, 0x09, 0x00);
+			adm8211_write_bbp(dev, 0x0a, 0x00);
+			adm8211_write_bbp(dev, 0x0b, 0x00);
+			adm8211_write_bbp(dev, 0x0c, 0x10);
+			adm8211_write_bbp(dev, 0x0f, 0x55);
+			adm8211_write_bbp(dev, 0x10, 0x8d);
+			adm8211_write_bbp(dev, 0x11, 0x43);
+			adm8211_write_bbp(dev, 0x18, 0x4a);
+			adm8211_write_bbp(dev, 0x20, 0x20);
+			adm8211_write_bbp(dev, 0x21, 0x02);
+			adm8211_write_bbp(dev, 0x22, 0x23);
+			adm8211_write_bbp(dev, 0x23, 0x30);
+			adm8211_write_bbp(dev, 0x24, 0x2d);
+			adm8211_write_bbp(dev, 0x2a, 0xaa);
+			adm8211_write_bbp(dev, 0x2b, 0x81);
+			adm8211_write_bbp(dev, 0x2c, 0x44);
+			adm8211_write_bbp(dev, 0x29, 0xfa);
+			adm8211_write_bbp(dev, 0x60, 0x2d);
+			adm8211_write_bbp(dev, 0x64, 0x01);
+			break;
+
+		case ADM8211_RFMD2948:
+			break;
+
+		default:
+			printk(KERN_DEBUG "%s: unsupported transceiver %d\n",
+			       wiphy_name(dev->wiphy), priv->transceiver_type);
+			break;
+		}
+	} else
+		printk(KERN_DEBUG "%s: unsupported BBP %d\n",
+		       wiphy_name(dev->wiphy), priv->bbp_type);
+
+	ADM8211_CSR_WRITE(SYNRF, 0);
+
+	/* Set RF CAL control source to MAC control */
+	reg = ADM8211_CSR_READ(SYNCTL);
+	reg |= ADM8211_SYNCTL_SELCAL;
+	ADM8211_CSR_WRITE(SYNCTL, reg);
+
+	return 0;
+}
+
+/* configures hw beacons/probe responses */
+static int adm8211_set_rate(struct ieee80211_hw *dev)
+{
+	struct adm8211_priv *priv = dev->priv;
+	u32 reg;
+	int i = 0;
+	u8 rate_buf[12] = {0};
+
+	/* write supported rates */
+	if (priv->pdev->revision != ADM8211_REV_BA) {
+		rate_buf[0] = ARRAY_SIZE(adm8211_rates);
+		for (i = 0; i < ARRAY_SIZE(adm8211_rates); i++)
+			rate_buf[i + 1] = (adm8211_rates[i].rate / 5) | 0x80;
+	} else {
+		/* workaround for rev BA specific bug */
+		rate_buf[0] = 0x04;
+		rate_buf[1] = 0x82;
+		rate_buf[2] = 0x04;
+		rate_buf[3] = 0x0b;
+		rate_buf[4] = 0x16;
+	}
+
+	adm8211_write_sram_bytes(dev, ADM8211_SRAM_SUPP_RATE, rate_buf,
+				 ARRAY_SIZE(adm8211_rates) + 1);
+
+	reg = ADM8211_CSR_READ(PLCPHD) & 0x00FFFFFF; /* keep bits 0-23 */
+	reg |= 1 << 15;	/* short preamble */
+	reg |= 110 << 24;
+	ADM8211_CSR_WRITE(PLCPHD, reg);
+
+	/* MTMLT   = 512 TU (max TX MSDU lifetime)
+	 * BCNTSIG = plcp_signal (beacon, probe resp, and atim TX rate)
+	 * SRTYLIM = 224 (short retry limit, TX header value is default) */
+	ADM8211_CSR_WRITE(TXLMT, (512 << 16) | (110 << 8) | (224 << 0));
+
+	return 0;
+}
+
+static void adm8211_hw_init(struct ieee80211_hw *dev)
+{
+	struct adm8211_priv *priv = dev->priv;
+	u32 reg;
+	u8 cline;
+
+	reg = le32_to_cpu(ADM8211_CSR_READ(PAR));
+	reg |= ADM8211_PAR_MRLE | ADM8211_PAR_MRME;
+	reg &= ~(ADM8211_PAR_BAR | ADM8211_PAR_CAL);
+
+	if (!pci_set_mwi(priv->pdev)) {
+		reg |= 0x1 << 24;
+		pci_read_config_byte(priv->pdev, PCI_CACHE_LINE_SIZE, &cline);
+
+		switch (cline) {
+		case  0x8: reg |= (0x1 << 14);
+			   break;
+		case 0x16: reg |= (0x2 << 14);
+			   break;
+		case 0x32: reg |= (0x3 << 14);
+			   break;
+		  default: reg |= (0x0 << 14);
+			   break;
+		}
+	}
+
+	ADM8211_CSR_WRITE(PAR, reg);
+
+	reg = ADM8211_CSR_READ(CSR_TEST1);
+	reg &= ~(0xF << 28);
+	reg |= (1 << 28) | (1 << 31);
+	ADM8211_CSR_WRITE(CSR_TEST1, reg);
+
+	/* lose link after 4 lost beacons */
+	reg = (0x04 << 21) | ADM8211_WCSR_TSFTWE | ADM8211_WCSR_LSOE;
+	ADM8211_CSR_WRITE(WCSR, reg);
+
+	/* Disable APM, enable receive FIFO threshold, and set drain receive
+	 * threshold to store-and-forward */
+	reg = ADM8211_CSR_READ(CMDR);
+	reg &= ~(ADM8211_CMDR_APM | ADM8211_CMDR_DRT);
+	reg |= ADM8211_CMDR_RTE | ADM8211_CMDR_DRT_SF;
+	ADM8211_CSR_WRITE(CMDR, reg);
+
+	adm8211_set_rate(dev);
+
+	/* 4-bit values:
+	 * PWR1UP   = 8 * 2 ms
+	 * PWR0PAPE = 8 us or 5 us
+	 * PWR1PAPE = 1 us or 3 us
+	 * PWR0TRSW = 5 us
+	 * PWR1TRSW = 12 us
+	 * PWR0PE2  = 13 us
+	 * PWR1PE2  = 1 us
+	 * PWR0TXPE = 8 or 6 */
+	if (priv->pdev->revision < ADM8211_REV_CA)
+		ADM8211_CSR_WRITE(TOFS2, 0x8815cd18);
+	else
+		ADM8211_CSR_WRITE(TOFS2, 0x8535cd16);
+
+	/* Enable store and forward for transmit */
+	priv->nar = ADM8211_NAR_SF | ADM8211_NAR_PB;
+	ADM8211_CSR_WRITE(NAR, priv->nar);
+
+	/* Reset RF */
+	ADM8211_CSR_WRITE(SYNRF, ADM8211_SYNRF_RADIO);
+	ADM8211_CSR_READ(SYNRF);
+	msleep(10);
+	ADM8211_CSR_WRITE(SYNRF, 0);
+	ADM8211_CSR_READ(SYNRF);
+	msleep(5);
+
+	/* Set CFP Max Duration to 0x10 TU */
+	reg = ADM8211_CSR_READ(CFPP);
+	reg &= ~(0xffff << 8);
+	reg |= 0x0010 << 8;
+	ADM8211_CSR_WRITE(CFPP, reg);
+
+	/* USCNT = 0x16 (number of system clocks, 22 MHz, in 1us
+	 * TUCNT = 0x3ff - Tu counter 1024 us  */
+	ADM8211_CSR_WRITE(TOFS0, (0x16 << 24) | 0x3ff);
+
+	/* SLOT=20 us, SIFS=110 cycles of 22 MHz (5 us),
+	 * DIFS=50 us, EIFS=100 us */
+	if (priv->pdev->revision < ADM8211_REV_CA)
+		ADM8211_CSR_WRITE(IFST, (20 << 23) | (110 << 15) |
+					(50 << 9)  | 100);
+	else
+		ADM8211_CSR_WRITE(IFST, (20 << 23) | (24 << 15) |
+					(50 << 9)  | 100);
+
+	/* PCNT = 1 (MAC idle time awake/sleep, unit S)
+	 * RMRD = 2346 * 8 + 1 us (max RX duration)  */
+	ADM8211_CSR_WRITE(RMD, (1 << 16) | 18769);
+
+	/* MART=65535 us, MIRT=256 us, TSFTOFST=0 us */
+	ADM8211_CSR_WRITE(RSPT, 0xffffff00);
+
+	/* Initialize BBP (and SYN) */
+	adm8211_hw_init_bbp(dev);
+
+	/* make sure interrupts are off */
+	ADM8211_CSR_WRITE(IER, 0);
+
+	/* ACK interrupts */
+	ADM8211_CSR_WRITE(STSR, ADM8211_CSR_READ(STSR));
+
+	/* Setup WEP (turns it off for now) */
+	reg = ADM8211_CSR_READ(MACTEST);
+	reg &= ~(7 << 20);
+	ADM8211_CSR_WRITE(MACTEST, reg);
+
+	reg = ADM8211_CSR_READ(WEPCTL);
+	reg &= ~ADM8211_WEPCTL_WEPENABLE;
+	reg |= ADM8211_WEPCTL_WEPRXBYP;
+	ADM8211_CSR_WRITE(WEPCTL, reg);
+
+	/* Clear the missed-packet counter. */
+	ADM8211_CSR_READ(LPC);
+}
+
+static int adm8211_hw_reset(struct ieee80211_hw *dev)
+{
+	struct adm8211_priv *priv = dev->priv;
+	u32 reg, tmp;
+	int timeout = 100;
+
+	/* Power-on issue */
+	/* TODO: check if this is necessary */
+	ADM8211_CSR_WRITE(FRCTL, 0);
+
+	/* Reset the chip */
+	tmp = ADM8211_CSR_READ(PAR);
+	ADM8211_CSR_WRITE(PAR, ADM8211_PAR_SWR);
+
+	while ((ADM8211_CSR_READ(PAR) & ADM8211_PAR_SWR) && timeout--)
+		msleep(50);
+
+	if (timeout <= 0)
+		return -ETIMEDOUT;
+
+	ADM8211_CSR_WRITE(PAR, tmp);
+
+	if (priv->pdev->revision == ADM8211_REV_BA &&
+	    (priv->transceiver_type == ADM8211_RFMD2958_RF3000_CONTROL_POWER ||
+	     priv->transceiver_type == ADM8211_RFMD2958)) {
+		reg = ADM8211_CSR_READ(CSR_TEST1);
+		reg |= (1 << 4) | (1 << 5);
+		ADM8211_CSR_WRITE(CSR_TEST1, reg);
+	} else if (priv->pdev->revision == ADM8211_REV_CA) {
+		reg = ADM8211_CSR_READ(CSR_TEST1);
+		reg &= ~((1 << 4) | (1 << 5));
+		ADM8211_CSR_WRITE(CSR_TEST1, reg);
+	}
+
+	ADM8211_CSR_WRITE(FRCTL, 0);
+
+	reg = ADM8211_CSR_READ(CSR_TEST0);
+	reg |= ADM8211_CSR_TEST0_EPRLD;	/* EEPROM Recall */
+	ADM8211_CSR_WRITE(CSR_TEST0, reg);
+
+	adm8211_clear_sram(dev);
+
+	return 0;
+}
+
+static u64 adm8211_get_tsft(struct ieee80211_hw *dev)
+{
+	struct adm8211_priv *priv = dev->priv;
+	u32 tsftl;
+	u64 tsft;
+
+	tsftl = ADM8211_CSR_READ(TSFTL);
+	tsft = ADM8211_CSR_READ(TSFTH);
+	tsft <<= 32;
+	tsft |= tsftl;
+
+	return tsft;
+}
+
+static void adm8211_set_interval(struct ieee80211_hw *dev,
+				 unsigned short bi, unsigned short li)
+{
+	struct adm8211_priv *priv = dev->priv;
+	u32 reg;
+
+	/* BP (beacon interval) = data->beacon_interval
+	 * LI (listen interval) = data->listen_interval (in beacon intervals) */
+	reg = (bi << 16) | li;
+	ADM8211_CSR_WRITE(BPLI, reg);
+}
+
+static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid)
+{
+	struct adm8211_priv *priv = dev->priv;
+	u32 reg;
+
+	ADM8211_CSR_WRITE(BSSID0, le32_to_cpu(*(__le32 *)bssid));
+	reg = ADM8211_CSR_READ(ABDA1);
+	reg &= 0x0000ffff;
+	reg |= (bssid[4] << 16) | (bssid[5] << 24);
+	ADM8211_CSR_WRITE(ABDA1, reg);
+}
+
+static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len)
+{
+	struct adm8211_priv *priv = dev->priv;
+	u8 buf[36];
+
+	if (ssid_len > 32)
+		return -EINVAL;
+
+	memset(buf, 0, sizeof(buf));
+	buf[0] = ssid_len;
+	memcpy(buf + 1, ssid, ssid_len);
+	adm8211_write_sram_bytes(dev, ADM8211_SRAM_SSID, buf, 33);
+	/* TODO: configure beacon for adhoc? */
+	return 0;
+}
+
+static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+{
+	struct adm8211_priv *priv = dev->priv;
+
+	if (conf->channel != priv->channel) {
+		priv->channel = conf->channel;
+		adm8211_rf_set_channel(dev, priv->channel);
+	}
+
+	return 0;
+}
+
+static int adm8211_config_interface(struct ieee80211_hw *dev, int if_id,
+				    struct ieee80211_if_conf *conf)
+{
+	struct adm8211_priv *priv = dev->priv;
+
+	if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) {
+		adm8211_set_bssid(dev, conf->bssid);
+		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+	}
+
+	if (conf->ssid_len != priv->ssid_len ||
+	    memcmp(conf->ssid, priv->ssid, conf->ssid_len)) {
+		adm8211_set_ssid(dev, conf->ssid, conf->ssid_len);
+		priv->ssid_len = conf->ssid_len;
+		memcpy(priv->ssid, conf->ssid, conf->ssid_len);
+	}
+
+	return 0;
+}
+
+static void adm8211_configure_filter(struct ieee80211_hw *dev,
+				     unsigned int changed_flags,
+				     unsigned int *total_flags,
+				     int mc_count, struct dev_mc_list *mclist)
+{
+	static const u8 bcast[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+	struct adm8211_priv *priv = dev->priv;
+	unsigned int bit_nr, new_flags;
+	u32 mc_filter[2];
+	int i;
+
+	new_flags = 0;
+
+	if (*total_flags & FIF_PROMISC_IN_BSS) {
+		new_flags |= FIF_PROMISC_IN_BSS;
+		priv->nar |= ADM8211_NAR_PR;
+		priv->nar &= ~ADM8211_NAR_MM;
+		mc_filter[1] = mc_filter[0] = ~0;
+	} else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32)) {
+		new_flags |= FIF_ALLMULTI;
+		priv->nar &= ~ADM8211_NAR_PR;
+		priv->nar |= ADM8211_NAR_MM;
+		mc_filter[1] = mc_filter[0] = ~0;
+	} else {
+		priv->nar &= ~(ADM8211_NAR_MM | ADM8211_NAR_PR);
+		mc_filter[1] = mc_filter[0] = 0;
+		for (i = 0; i < mc_count; i++) {
+			if (!mclist)
+				break;
+			bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+
+			bit_nr &= 0x3F;
+			mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+			mclist = mclist->next;
+		}
+	}
+
+	ADM8211_IDLE_RX();
+
+	ADM8211_CSR_WRITE(MAR0, mc_filter[0]);
+	ADM8211_CSR_WRITE(MAR1, mc_filter[1]);
+	ADM8211_CSR_READ(NAR);
+
+	if (priv->nar & ADM8211_NAR_PR)
+		dev->flags |= IEEE80211_HW_RX_INCLUDES_FCS;
+	else
+		dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
+
+	if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+		adm8211_set_bssid(dev, bcast);
+	else
+		adm8211_set_bssid(dev, priv->bssid);
+
+	ADM8211_RESTORE();
+
+	*total_flags = new_flags;
+}
+
+static int adm8211_add_interface(struct ieee80211_hw *dev,
+				 struct ieee80211_if_init_conf *conf)
+{
+	struct adm8211_priv *priv = dev->priv;
+	if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+		return -EOPNOTSUPP;
+
+	switch (conf->type) {
+	case IEEE80211_IF_TYPE_STA:
+		priv->mode = conf->type;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	ADM8211_IDLE();
+
+	ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)conf->mac_addr));
+	ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(conf->mac_addr + 4)));
+
+	adm8211_update_mode(dev);
+
+	ADM8211_RESTORE();
+
+	return 0;
+}
+
+static void adm8211_remove_interface(struct ieee80211_hw *dev,
+				     struct ieee80211_if_init_conf *conf)
+{
+	struct adm8211_priv *priv = dev->priv;
+	priv->mode = IEEE80211_IF_TYPE_MNTR;
+}
+
+static int adm8211_init_rings(struct ieee80211_hw *dev)
+{
+	struct adm8211_priv *priv = dev->priv;
+	struct adm8211_desc *desc = NULL;
+	struct adm8211_rx_ring_info *rx_info;
+	struct adm8211_tx_ring_info *tx_info;
+	unsigned int i;
+
+	for (i = 0; i < priv->rx_ring_size; i++) {
+		desc = &priv->rx_ring[i];
+		desc->status = 0;
+		desc->length = cpu_to_le32(RX_PKT_SIZE);
+		priv->rx_buffers[i].skb = NULL;
+	}
+	/* Mark the end of RX ring; hw returns to base address after this
+	 * descriptor */
+	desc->length |= cpu_to_le32(RDES1_CONTROL_RER);
+
+	for (i = 0; i < priv->rx_ring_size; i++) {
+		desc = &priv->rx_ring[i];
+		rx_info = &priv->rx_buffers[i];
+
+		rx_info->skb = dev_alloc_skb(RX_PKT_SIZE);
+		if (rx_info->skb == NULL)
+			break;
+		rx_info->mapping = pci_map_single(priv->pdev,
+						  skb_tail_pointer(rx_info->skb),
+						  RX_PKT_SIZE,
+						  PCI_DMA_FROMDEVICE);
+		desc->buffer1 = cpu_to_le32(rx_info->mapping);
+		desc->status = cpu_to_le32(RDES0_STATUS_OWN | RDES0_STATUS_SQL);
+	}
+
+	/* Setup TX ring. TX buffers descriptors will be filled in as needed */
+	for (i = 0; i < priv->tx_ring_size; i++) {
+		desc = &priv->tx_ring[i];
+		tx_info = &priv->tx_buffers[i];
+
+		tx_info->skb = NULL;
+		tx_info->mapping = 0;
+		desc->status = 0;
+	}
+	desc->length = cpu_to_le32(TDES1_CONTROL_TER);
+
+	priv->cur_rx = priv->cur_tx = priv->dirty_tx = 0;
+	ADM8211_CSR_WRITE(RDB, priv->rx_ring_dma);
+	ADM8211_CSR_WRITE(TDBD, priv->tx_ring_dma);
+
+	return 0;
+}
+
+static void adm8211_free_rings(struct ieee80211_hw *dev)
+{
+	struct adm8211_priv *priv = dev->priv;
+	unsigned int i;
+
+	for (i = 0; i < priv->rx_ring_size; i++) {
+		if (!priv->rx_buffers[i].skb)
+			continue;
+
+		pci_unmap_single(
+			priv->pdev,
+			priv->rx_buffers[i].mapping,
+			RX_PKT_SIZE, PCI_DMA_FROMDEVICE);
+
+		dev_kfree_skb(priv->rx_buffers[i].skb);
+	}
+
+	for (i = 0; i < priv->tx_ring_size; i++) {
+		if (!priv->tx_buffers[i].skb)
+			continue;
+
+		pci_unmap_single(priv->pdev,
+				 priv->tx_buffers[i].mapping,
+				 priv->tx_buffers[i].skb->len,
+				 PCI_DMA_TODEVICE);
+
+		dev_kfree_skb(priv->tx_buffers[i].skb);
+	}
+}
+
+static int adm8211_start(struct ieee80211_hw *dev)
+{
+	struct adm8211_priv *priv = dev->priv;
+	int retval;
+
+	/* Power up MAC and RF chips */
+	retval = adm8211_hw_reset(dev);
+	if (retval) {
+		printk(KERN_ERR "%s: hardware reset failed\n",
+		       wiphy_name(dev->wiphy));
+		goto fail;
+	}
+
+	retval = adm8211_init_rings(dev);
+	if (retval) {
+		printk(KERN_ERR "%s: failed to initialize rings\n",
+		       wiphy_name(dev->wiphy));
+		goto fail;
+	}
+
+	/* Init hardware */
+	adm8211_hw_init(dev);
+	adm8211_rf_set_channel(dev, priv->channel);
+
+	retval = request_irq(priv->pdev->irq, &adm8211_interrupt,
+			     IRQF_SHARED, "adm8211", dev);
+	if (retval) {
+		printk(KERN_ERR "%s: failed to register IRQ handler\n",
+		       wiphy_name(dev->wiphy));
+		goto fail;
+	}
+
+	ADM8211_CSR_WRITE(IER, ADM8211_IER_NIE | ADM8211_IER_AIE |
+			       ADM8211_IER_RCIE | ADM8211_IER_TCIE |
+			       ADM8211_IER_TDUIE | ADM8211_IER_GPTIE);
+	priv->mode = IEEE80211_IF_TYPE_MNTR;
+	adm8211_update_mode(dev);
+	ADM8211_CSR_WRITE(RDR, 0);
+
+	adm8211_set_interval(dev, 100, 10);
+	return 0;
+
+fail:
+	return retval;
+}
+
+static void adm8211_stop(struct ieee80211_hw *dev)
+{
+	struct adm8211_priv *priv = dev->priv;
+
+	priv->mode = IEEE80211_IF_TYPE_INVALID;
+	priv->nar = 0;
+	ADM8211_CSR_WRITE(NAR, 0);
+	ADM8211_CSR_WRITE(IER, 0);
+	ADM8211_CSR_READ(NAR);
+
+	free_irq(priv->pdev->irq, dev);
+
+	adm8211_free_rings(dev);
+}
+
+static void adm8211_calc_durations(int *dur, int *plcp, size_t payload_len, int len,
+				   int plcp_signal, int short_preamble)
+{
+	/* Alternative calculation from NetBSD: */
+
+/* IEEE 802.11b durations for DSSS PHY in microseconds */
+#define IEEE80211_DUR_DS_LONG_PREAMBLE	144
+#define IEEE80211_DUR_DS_SHORT_PREAMBLE	72
+#define IEEE80211_DUR_DS_FAST_PLCPHDR	24
+#define IEEE80211_DUR_DS_SLOW_PLCPHDR	48
+#define IEEE80211_DUR_DS_SLOW_ACK	112
+#define IEEE80211_DUR_DS_FAST_ACK	56
+#define IEEE80211_DUR_DS_SLOW_CTS	112
+#define IEEE80211_DUR_DS_FAST_CTS	56
+#define IEEE80211_DUR_DS_SLOT		20
+#define IEEE80211_DUR_DS_SIFS		10
+
+	int remainder;
+
+	*dur = (80 * (24 + payload_len) + plcp_signal - 1)
+		/ plcp_signal;
+
+	if (plcp_signal <= PLCP_SIGNAL_2M)
+		/* 1-2Mbps WLAN: send ACK/CTS at 1Mbps */
+		*dur += 3 * (IEEE80211_DUR_DS_SIFS +
+			     IEEE80211_DUR_DS_SHORT_PREAMBLE +
+			     IEEE80211_DUR_DS_FAST_PLCPHDR) +
+			     IEEE80211_DUR_DS_SLOW_CTS + IEEE80211_DUR_DS_SLOW_ACK;
+	else
+		/* 5-11Mbps WLAN: send ACK/CTS at 2Mbps */
+		*dur += 3 * (IEEE80211_DUR_DS_SIFS +
+			     IEEE80211_DUR_DS_SHORT_PREAMBLE +
+			     IEEE80211_DUR_DS_FAST_PLCPHDR) +
+			     IEEE80211_DUR_DS_FAST_CTS + IEEE80211_DUR_DS_FAST_ACK;
+
+	/* lengthen duration if long preamble */
+	if (!short_preamble)
+		*dur +=	3 * (IEEE80211_DUR_DS_LONG_PREAMBLE -
+			     IEEE80211_DUR_DS_SHORT_PREAMBLE) +
+			3 * (IEEE80211_DUR_DS_SLOW_PLCPHDR -
+			     IEEE80211_DUR_DS_FAST_PLCPHDR);
+
+
+	*plcp = (80 * len) / plcp_signal;
+	remainder = (80 * len) % plcp_signal;
+	if (plcp_signal == PLCP_SIGNAL_11M &&
+	    remainder <= 30 && remainder > 0)
+		*plcp = (*plcp | 0x8000) + 1;
+	else if (remainder)
+		(*plcp)++;
+}
+
+/* Transmit skb w/adm8211_tx_hdr (802.11 header created by hardware) */
+static void adm8211_tx_raw(struct ieee80211_hw *dev, struct sk_buff *skb,
+			   u16 plcp_signal,
+			   struct ieee80211_tx_control *control,
+			   size_t hdrlen)
+{
+	struct adm8211_priv *priv = dev->priv;
+	unsigned long flags;
+	dma_addr_t mapping;
+	unsigned int entry;
+	u32 flag;
+
+	mapping = pci_map_single(priv->pdev, skb->data, skb->len,
+				 PCI_DMA_TODEVICE);
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (priv->cur_tx - priv->dirty_tx == priv->tx_ring_size / 2)
+		flag = TDES1_CONTROL_IC | TDES1_CONTROL_LS | TDES1_CONTROL_FS;
+	else
+		flag = TDES1_CONTROL_LS | TDES1_CONTROL_FS;
+
+	if (priv->cur_tx - priv->dirty_tx == priv->tx_ring_size - 2)
+		ieee80211_stop_queue(dev, 0);
+
+	entry = priv->cur_tx % priv->tx_ring_size;
+
+	priv->tx_buffers[entry].skb = skb;
+	priv->tx_buffers[entry].mapping = mapping;
+	memcpy(&priv->tx_buffers[entry].tx_control, control, sizeof(*control));
+	priv->tx_buffers[entry].hdrlen = hdrlen;
+	priv->tx_ring[entry].buffer1 = cpu_to_le32(mapping);
+
+	if (entry == priv->tx_ring_size - 1)
+		flag |= TDES1_CONTROL_TER;
+	priv->tx_ring[entry].length = cpu_to_le32(flag | skb->len);
+
+	/* Set TX rate (SIGNAL field in PLCP PPDU format) */
+	flag = TDES0_CONTROL_OWN | (plcp_signal << 20) | 8 /* ? */;
+	priv->tx_ring[entry].status = cpu_to_le32(flag);
+
+	priv->cur_tx++;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	/* Trigger transmit poll */
+	ADM8211_CSR_WRITE(TDR, 0);
+}
+
+/* Put adm8211_tx_hdr on skb and transmit */
+static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
+		      struct ieee80211_tx_control *control)
+{
+	struct adm8211_tx_hdr *txhdr;
+	u16 fc;
+	size_t payload_len, hdrlen;
+	int plcp, dur, len, plcp_signal, short_preamble;
+	struct ieee80211_hdr *hdr;
+
+	if (control->tx_rate < 0) {
+		short_preamble = 1;
+		plcp_signal = -control->tx_rate;
+	} else {
+		short_preamble = 0;
+		plcp_signal = control->tx_rate;
+	}
+
+	hdr = (struct ieee80211_hdr *)skb->data;
+	fc = le16_to_cpu(hdr->frame_control) & ~IEEE80211_FCTL_PROTECTED;
+	hdrlen = ieee80211_get_hdrlen(fc);
+	memcpy(skb->cb, skb->data, hdrlen);
+	hdr = (struct ieee80211_hdr *)skb->cb;
+	skb_pull(skb, hdrlen);
+	payload_len = skb->len;
+
+	txhdr = (struct adm8211_tx_hdr *) skb_push(skb, sizeof(*txhdr));
+	memset(txhdr, 0, sizeof(*txhdr));
+	memcpy(txhdr->da, ieee80211_get_DA(hdr), ETH_ALEN);
+	txhdr->signal = plcp_signal;
+	txhdr->frame_body_size = cpu_to_le16(payload_len);
+	txhdr->frame_control = hdr->frame_control;
+
+	len = hdrlen + payload_len + FCS_LEN;
+	if (fc & IEEE80211_FCTL_PROTECTED)
+		len += 8;
+
+	txhdr->frag = cpu_to_le16(0x0FFF);
+	adm8211_calc_durations(&dur, &plcp, payload_len,
+			       len, plcp_signal, short_preamble);
+	txhdr->plcp_frag_head_len = cpu_to_le16(plcp);
+	txhdr->plcp_frag_tail_len = cpu_to_le16(plcp);
+	txhdr->dur_frag_head = cpu_to_le16(dur);
+	txhdr->dur_frag_tail = cpu_to_le16(dur);
+
+	txhdr->header_control = cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_EXTEND_HEADER);
+
+	if (short_preamble)
+		txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE);
+
+	if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+		txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS);
+
+	if (fc & IEEE80211_FCTL_PROTECTED)
+		txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE);
+
+	txhdr->retry_limit = control->retry_limit;
+
+	adm8211_tx_raw(dev, skb, plcp_signal, control, hdrlen);
+
+	return NETDEV_TX_OK;
+}
+
+static int adm8211_alloc_rings(struct ieee80211_hw *dev)
+{
+	struct adm8211_priv *priv = dev->priv;
+	unsigned int ring_size;
+
+	priv->rx_buffers = kmalloc(sizeof(*priv->rx_buffers) * priv->rx_ring_size +
+				   sizeof(*priv->tx_buffers) * priv->tx_ring_size, GFP_KERNEL);
+	if (!priv->rx_buffers)
+		return -ENOMEM;
+
+	priv->tx_buffers = (void *)priv->rx_buffers +
+			   sizeof(*priv->rx_buffers) * priv->rx_ring_size;
+
+	/* Allocate TX/RX descriptors */
+	ring_size = sizeof(struct adm8211_desc) * priv->rx_ring_size +
+		    sizeof(struct adm8211_desc) * priv->tx_ring_size;
+	priv->rx_ring = pci_alloc_consistent(priv->pdev, ring_size,
+					     &priv->rx_ring_dma);
+
+	if (!priv->rx_ring) {
+		kfree(priv->rx_buffers);
+		priv->rx_buffers = NULL;
+		priv->tx_buffers = NULL;
+		return -ENOMEM;
+	}
+
+	priv->tx_ring = (struct adm8211_desc *)(priv->rx_ring +
+						priv->rx_ring_size);
+	priv->tx_ring_dma = priv->rx_ring_dma +
+			    sizeof(struct adm8211_desc) * priv->rx_ring_size;
+
+	return 0;
+}
+
+static const struct ieee80211_ops adm8211_ops = {
+	.tx			= adm8211_tx,
+	.start			= adm8211_start,
+	.stop			= adm8211_stop,
+	.add_interface		= adm8211_add_interface,
+	.remove_interface	= adm8211_remove_interface,
+	.config			= adm8211_config,
+	.config_interface	= adm8211_config_interface,
+	.configure_filter	= adm8211_configure_filter,
+	.get_stats		= adm8211_get_stats,
+	.get_tx_stats		= adm8211_get_tx_stats,
+	.get_tsf		= adm8211_get_tsft
+};
+
+static int __devinit adm8211_probe(struct pci_dev *pdev,
+				   const struct pci_device_id *id)
+{
+	struct ieee80211_hw *dev;
+	struct adm8211_priv *priv;
+	unsigned long mem_addr, mem_len;
+	unsigned int io_addr, io_len;
+	int err;
+	u32 reg;
+	u8 perm_addr[ETH_ALEN];
+	DECLARE_MAC_BUF(mac);
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR "%s (adm8211): Cannot enable new PCI device\n",
+		       pci_name(pdev));
+		return err;
+	}
+
+	io_addr = pci_resource_start(pdev, 0);
+	io_len = pci_resource_len(pdev, 0);
+	mem_addr = pci_resource_start(pdev, 1);
+	mem_len = pci_resource_len(pdev, 1);
+	if (io_len < 256 || mem_len < 1024) {
+		printk(KERN_ERR "%s (adm8211): Too short PCI resources\n",
+		       pci_name(pdev));
+		goto err_disable_pdev;
+	}
+
+
+	/* check signature */
+	pci_read_config_dword(pdev, 0x80 /* CR32 */, &reg);
+	if (reg != ADM8211_SIG1 && reg != ADM8211_SIG2) {
+		printk(KERN_ERR "%s (adm8211): Invalid signature (0x%x)\n",
+		       pci_name(pdev), reg);
+		goto err_disable_pdev;
+	}
+
+	err = pci_request_regions(pdev, "adm8211");
+	if (err) {
+		printk(KERN_ERR "%s (adm8211): Cannot obtain PCI resources\n",
+		       pci_name(pdev));
+		return err; /* someone else grabbed it? don't disable it */
+	}
+
+	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
+	    pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+		printk(KERN_ERR "%s (adm8211): No suitable DMA available\n",
+		       pci_name(pdev));
+		goto err_free_reg;
+	}
+
+	pci_set_master(pdev);
+
+	dev = ieee80211_alloc_hw(sizeof(*priv), &adm8211_ops);
+	if (!dev) {
+		printk(KERN_ERR "%s (adm8211): ieee80211 alloc failed\n",
+		       pci_name(pdev));
+		err = -ENOMEM;
+		goto err_free_reg;
+	}
+	priv = dev->priv;
+	priv->pdev = pdev;
+
+	spin_lock_init(&priv->lock);
+
+	SET_IEEE80211_DEV(dev, &pdev->dev);
+
+	pci_set_drvdata(pdev, dev);
+
+	priv->map = pci_iomap(pdev, 1, mem_len);
+	if (!priv->map)
+		priv->map = pci_iomap(pdev, 0, io_len);
+
+	if (!priv->map) {
+		printk(KERN_ERR "%s (adm8211): Cannot map device memory\n",
+		       pci_name(pdev));
+		goto err_free_dev;
+	}
+
+	priv->rx_ring_size = rx_ring_size;
+	priv->tx_ring_size = tx_ring_size;
+
+	if (adm8211_alloc_rings(dev)) {
+		printk(KERN_ERR "%s (adm8211): Cannot allocate TX/RX ring\n",
+		       pci_name(pdev));
+		goto err_iounmap;
+	}
+
+	*(u32 *)perm_addr = le32_to_cpu((__force __le32)ADM8211_CSR_READ(PAR0));
+	*(u16 *)&perm_addr[4] =
+		le16_to_cpu((__force __le16)ADM8211_CSR_READ(PAR1) & 0xFFFF);
+
+	if (!is_valid_ether_addr(perm_addr)) {
+		printk(KERN_WARNING "%s (adm8211): Invalid hwaddr in EEPROM!\n",
+		       pci_name(pdev));
+		random_ether_addr(perm_addr);
+	}
+	SET_IEEE80211_PERM_ADDR(dev, perm_addr);
+
+	dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr);
+	dev->flags = IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED;
+	/* IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */
+
+	dev->channel_change_time = 1000;
+	dev->max_rssi = 100;	/* FIXME: find better value */
+
+	priv->modes[0].mode = MODE_IEEE80211B;
+	/* channel info filled in by adm8211_read_eeprom */
+	memcpy(priv->rates, adm8211_rates, sizeof(adm8211_rates));
+	priv->modes[0].num_rates = ARRAY_SIZE(adm8211_rates);
+	priv->modes[0].rates = priv->rates;
+
+	dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */
+
+	priv->retry_limit = 3;
+	priv->ant_power = 0x40;
+	priv->tx_power = 0x40;
+	priv->lpf_cutoff = 0xFF;
+	priv->lnags_threshold = 0xFF;
+	priv->mode = IEEE80211_IF_TYPE_INVALID;
+
+	/* Power-on issue. EEPROM won't read correctly without */
+	if (pdev->revision >= ADM8211_REV_BA) {
+		ADM8211_CSR_WRITE(FRCTL, 0);
+		ADM8211_CSR_READ(FRCTL);
+		ADM8211_CSR_WRITE(FRCTL, 1);
+		ADM8211_CSR_READ(FRCTL);
+		msleep(100);
+	}
+
+	err = adm8211_read_eeprom(dev);
+	if (err) {
+		printk(KERN_ERR "%s (adm8211): Can't alloc eeprom buffer\n",
+		       pci_name(pdev));
+		goto err_free_desc;
+	}
+
+	priv->channel = priv->modes[0].channels[0].chan;
+
+	err = ieee80211_register_hwmode(dev, &priv->modes[0]);
+	if (err) {
+		printk(KERN_ERR "%s (adm8211): Can't register hwmode\n",
+		       pci_name(pdev));
+		goto err_free_desc;
+	}
+
+	err = ieee80211_register_hw(dev);
+	if (err) {
+		printk(KERN_ERR "%s (adm8211): Cannot register device\n",
+		       pci_name(pdev));
+		goto err_free_desc;
+	}
+
+	printk(KERN_INFO "%s: hwaddr %s, Rev 0x%02x\n",
+	       wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
+	       pdev->revision);
+
+	return 0;
+
+ err_free_desc:
+	pci_free_consistent(pdev,
+			    sizeof(struct adm8211_desc) * priv->rx_ring_size +
+			    sizeof(struct adm8211_desc) * priv->tx_ring_size,
+			    priv->rx_ring, priv->rx_ring_dma);
+	kfree(priv->rx_buffers);
+
+ err_iounmap:
+	pci_iounmap(pdev, priv->map);
+
+ err_free_dev:
+	pci_set_drvdata(pdev, NULL);
+	ieee80211_free_hw(dev);
+
+ err_free_reg:
+	pci_release_regions(pdev);
+
+ err_disable_pdev:
+	pci_disable_device(pdev);
+	return err;
+}
+
+
+static void __devexit adm8211_remove(struct pci_dev *pdev)
+{
+	struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+	struct adm8211_priv *priv;
+
+	if (!dev)
+		return;
+
+	ieee80211_unregister_hw(dev);
+
+	priv = dev->priv;
+
+	pci_free_consistent(pdev,
+			    sizeof(struct adm8211_desc) * priv->rx_ring_size +
+			    sizeof(struct adm8211_desc) * priv->tx_ring_size,
+			    priv->rx_ring, priv->rx_ring_dma);
+
+	kfree(priv->rx_buffers);
+	kfree(priv->eeprom);
+	pci_iounmap(pdev, priv->map);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	ieee80211_free_hw(dev);
+}
+
+
+#ifdef CONFIG_PM
+static int adm8211_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+	struct adm8211_priv *priv = dev->priv;
+
+	if (priv->mode != IEEE80211_IF_TYPE_INVALID) {
+		ieee80211_stop_queues(dev);
+		adm8211_stop(dev);
+	}
+
+	pci_save_state(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+	return 0;
+}
+
+static int adm8211_resume(struct pci_dev *pdev)
+{
+	struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+	struct adm8211_priv *priv = dev->priv;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	if (priv->mode != IEEE80211_IF_TYPE_INVALID) {
+		adm8211_start(dev);
+		ieee80211_start_queues(dev);
+	}
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+
+MODULE_DEVICE_TABLE(pci, adm8211_pci_id_table);
+
+/* TODO: implement enable_wake */
+static struct pci_driver adm8211_driver = {
+	.name		= "adm8211",
+	.id_table	= adm8211_pci_id_table,
+	.probe		= adm8211_probe,
+	.remove		= __devexit_p(adm8211_remove),
+#ifdef CONFIG_PM
+	.suspend	= adm8211_suspend,
+	.resume		= adm8211_resume,
+#endif /* CONFIG_PM */
+};
+
+
+
+static int __init adm8211_init(void)
+{
+	return pci_register_driver(&adm8211_driver);
+}
+
+
+static void __exit adm8211_exit(void)
+{
+	pci_unregister_driver(&adm8211_driver);
+}
+
+
+module_init(adm8211_init);
+module_exit(adm8211_exit);
diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h
new file mode 100644
index 0000000..ef326fe
--- /dev/null
+++ b/drivers/net/wireless/adm8211.h
@@ -0,0 +1,656 @@
+#ifndef ADM8211_H
+#define ADM8211_H
+
+/* ADM8211 Registers */
+
+/* CR32 (SIG) signature */
+#define ADM8211_SIG1		0x82011317 /* ADM8211A */
+#define ADM8211_SIG2		0x82111317 /* ADM8211B/ADM8211C */
+
+#define ADM8211_CSR_READ(r) ioread32(&priv->map->r)
+#define ADM8211_CSR_WRITE(r, val) iowrite32((val), &priv->map->r)
+
+/* CSR (Host Control and Status Registers) */
+struct adm8211_csr {
+	__le32 PAR;		/* 0x00 CSR0 */
+	__le32 FRCTL;		/* 0x04 CSR0A */
+	__le32 TDR;		/* 0x08 CSR1 */
+	__le32 WTDP;		/* 0x0C CSR1A */
+	__le32 RDR;		/* 0x10 CSR2 */
+	__le32 WRDP;		/* 0x14 CSR2A */
+	__le32 RDB;		/* 0x18 CSR3 */
+	__le32 TDBH;		/* 0x1C CSR3A */
+	__le32 TDBD;		/* 0x20 CSR4 */
+	__le32 TDBP;		/* 0x24 CSR4A */
+	__le32 STSR;		/* 0x28 CSR5 */
+	__le32 TDBB;		/* 0x2C CSR5A */
+	__le32 NAR;		/* 0x30 CSR6 */
+	__le32 CSR6A;		/* reserved */
+	__le32 IER;		/* 0x38 CSR7 */
+	__le32 TKIPSCEP;	/* 0x3C CSR7A */
+	__le32 LPC;		/* 0x40 CSR8 */
+	__le32 CSR_TEST1;	/* 0x44 CSR8A */
+	__le32 SPR;		/* 0x48 CSR9 */
+	__le32 CSR_TEST0;	/* 0x4C CSR9A */
+	__le32 WCSR;		/* 0x50 CSR10 */
+	__le32 WPDR;		/* 0x54 CSR10A */
+	__le32 GPTMR;		/* 0x58 CSR11 */
+	__le32 GPIO;		/* 0x5C CSR11A */
+	__le32 BBPCTL;		/* 0x60 CSR12 */
+	__le32 SYNCTL;		/* 0x64 CSR12A */
+	__le32 PLCPHD;		/* 0x68 CSR13 */
+	__le32 MMIWA;		/* 0x6C CSR13A */
+	__le32 MMIRD0;		/* 0x70 CSR14 */
+	__le32 MMIRD1;		/* 0x74 CSR14A */
+	__le32 TXBR;		/* 0x78 CSR15 */
+	__le32 SYNDATA;		/* 0x7C CSR15A */
+	__le32 ALCS;		/* 0x80 CSR16 */
+	__le32 TOFS2;		/* 0x84 CSR17 */
+	__le32 CMDR;		/* 0x88 CSR18 */
+	__le32 PCIC;		/* 0x8C CSR19 */
+	__le32 PMCSR;		/* 0x90 CSR20 */
+	__le32 PAR0;		/* 0x94 CSR21 */
+	__le32 PAR1;		/* 0x98 CSR22 */
+	__le32 MAR0;		/* 0x9C CSR23 */
+	__le32 MAR1;		/* 0xA0 CSR24 */
+	__le32 ATIMDA0;		/* 0xA4 CSR25 */
+	__le32 ABDA1;		/* 0xA8 CSR26 */
+	__le32 BSSID0;		/* 0xAC CSR27 */
+	__le32 TXLMT;		/* 0xB0 CSR28 */
+	__le32 MIBCNT;		/* 0xB4 CSR29 */
+	__le32 BCNT;		/* 0xB8 CSR30 */
+	__le32 TSFTH;		/* 0xBC CSR31 */
+	__le32 TSC;		/* 0xC0 CSR32 */
+	__le32 SYNRF;		/* 0xC4 CSR33 */
+	__le32 BPLI;		/* 0xC8 CSR34 */
+	__le32 CAP0;		/* 0xCC CSR35 */
+	__le32 CAP1;		/* 0xD0 CSR36 */
+	__le32 RMD;		/* 0xD4 CSR37 */
+	__le32 CFPP;		/* 0xD8 CSR38 */
+	__le32 TOFS0;		/* 0xDC CSR39 */
+	__le32 TOFS1;		/* 0xE0 CSR40 */
+	__le32 IFST;		/* 0xE4 CSR41 */
+	__le32 RSPT;		/* 0xE8 CSR42 */
+	__le32 TSFTL;		/* 0xEC CSR43 */
+	__le32 WEPCTL;		/* 0xF0 CSR44 */
+	__le32 WESK;		/* 0xF4 CSR45 */
+	__le32 WEPCNT;		/* 0xF8 CSR46 */
+	__le32 MACTEST;		/* 0xFC CSR47 */
+	__le32 FER;		/* 0x100 */
+	__le32 FEMR;		/* 0x104 */
+	__le32 FPSR;		/* 0x108 */
+	__le32 FFER;		/* 0x10C */
+} __attribute__ ((packed));
+
+/* CSR0 - PAR (PCI Address Register) */
+#define ADM8211_PAR_MWIE	(1 << 24)
+#define ADM8211_PAR_MRLE	(1 << 23)
+#define ADM8211_PAR_MRME	(1 << 21)
+#define ADM8211_PAR_RAP		((1 << 18) | (1 << 17))
+#define ADM8211_PAR_CAL		((1 << 15) | (1 << 14))
+#define ADM8211_PAR_PBL		0x00003f00
+#define ADM8211_PAR_BLE		(1 << 7)
+#define ADM8211_PAR_DSL		0x0000007c
+#define ADM8211_PAR_BAR		(1 << 1)
+#define ADM8211_PAR_SWR		(1 << 0)
+
+/* CSR1 - FRCTL (Frame Control Register) */
+#define ADM8211_FRCTL_PWRMGT	(1 << 31)
+#define ADM8211_FRCTL_MAXPSP	(1 << 27)
+#define ADM8211_FRCTL_DRVPRSP	(1 << 26)
+#define ADM8211_FRCTL_DRVBCON	(1 << 25)
+#define ADM8211_FRCTL_AID	0x0000ffff
+#define ADM8211_FRCTL_AID_ON	0x0000c000
+
+/* CSR5 - STSR (Status Register) */
+#define ADM8211_STSR_PCF	(1 << 31)
+#define ADM8211_STSR_BCNTC	(1 << 30)
+#define ADM8211_STSR_GPINT	(1 << 29)
+#define ADM8211_STSR_LinkOff	(1 << 28)
+#define ADM8211_STSR_ATIMTC	(1 << 27)
+#define ADM8211_STSR_TSFTF	(1 << 26)
+#define ADM8211_STSR_TSCZ	(1 << 25)
+#define ADM8211_STSR_LinkOn	(1 << 24)
+#define ADM8211_STSR_SQL	(1 << 23)
+#define ADM8211_STSR_WEPTD	(1 << 22)
+#define ADM8211_STSR_ATIME	(1 << 21)
+#define ADM8211_STSR_TBTT	(1 << 20)
+#define ADM8211_STSR_NISS	(1 << 16)
+#define ADM8211_STSR_AISS	(1 << 15)
+#define ADM8211_STSR_TEIS	(1 << 14)
+#define ADM8211_STSR_FBE	(1 << 13)
+#define ADM8211_STSR_REIS	(1 << 12)
+#define ADM8211_STSR_GPTT	(1 << 11)
+#define ADM8211_STSR_RPS	(1 << 8)
+#define ADM8211_STSR_RDU	(1 << 7)
+#define ADM8211_STSR_RCI	(1 << 6)
+#define ADM8211_STSR_TUF	(1 << 5)
+#define ADM8211_STSR_TRT	(1 << 4)
+#define ADM8211_STSR_TLT	(1 << 3)
+#define ADM8211_STSR_TDU	(1 << 2)
+#define ADM8211_STSR_TPS	(1 << 1)
+#define ADM8211_STSR_TCI	(1 << 0)
+
+/* CSR6 - NAR (Network Access Register) */
+#define ADM8211_NAR_TXCF	(1 << 31)
+#define ADM8211_NAR_HF		(1 << 30)
+#define ADM8211_NAR_UTR		(1 << 29)
+#define ADM8211_NAR_SQ		(1 << 28)
+#define ADM8211_NAR_CFP		(1 << 27)
+#define ADM8211_NAR_SF		(1 << 21)
+#define ADM8211_NAR_TR		((1 << 15) | (1 << 14))
+#define ADM8211_NAR_ST		(1 << 13)
+#define ADM8211_NAR_OM		((1 << 11) | (1 << 10))
+#define ADM8211_NAR_MM		(1 << 7)
+#define ADM8211_NAR_PR		(1 << 6)
+#define ADM8211_NAR_EA		(1 << 5)
+#define ADM8211_NAR_PB		(1 << 3)
+#define ADM8211_NAR_STPDMA	(1 << 2)
+#define ADM8211_NAR_SR		(1 << 1)
+#define ADM8211_NAR_CTX		(1 << 0)
+
+#define ADM8211_IDLE() 							   \
+do { 									   \
+	if (priv->nar & (ADM8211_NAR_SR | ADM8211_NAR_ST)) {		   \
+		ADM8211_CSR_WRITE(NAR, priv->nar &			   \
+				       ~(ADM8211_NAR_SR | ADM8211_NAR_ST));\
+		ADM8211_CSR_READ(NAR);					   \
+		msleep(20);						   \
+	}								   \
+} while (0)
+
+#define ADM8211_IDLE_RX() 						\
+do {									\
+	if (priv->nar & ADM8211_NAR_SR) {				\
+		ADM8211_CSR_WRITE(NAR, priv->nar & ~ADM8211_NAR_SR);	\
+		ADM8211_CSR_READ(NAR);					\
+		mdelay(20);						\
+	}								\
+} while (0)
+
+#define ADM8211_RESTORE()					\
+do {								\
+	if (priv->nar & (ADM8211_NAR_SR | ADM8211_NAR_ST))	\
+		ADM8211_CSR_WRITE(NAR, priv->nar);		\
+} while (0)
+
+/* CSR7 - IER (Interrupt Enable Register) */
+#define ADM8211_IER_PCFIE	(1 << 31)
+#define ADM8211_IER_BCNTCIE	(1 << 30)
+#define ADM8211_IER_GPIE	(1 << 29)
+#define ADM8211_IER_LinkOffIE	(1 << 28)
+#define ADM8211_IER_ATIMTCIE	(1 << 27)
+#define ADM8211_IER_TSFTFIE	(1 << 26)
+#define ADM8211_IER_TSCZE	(1 << 25)
+#define ADM8211_IER_LinkOnIE	(1 << 24)
+#define ADM8211_IER_SQLIE	(1 << 23)
+#define ADM8211_IER_WEPIE	(1 << 22)
+#define ADM8211_IER_ATIMEIE	(1 << 21)
+#define ADM8211_IER_TBTTIE	(1 << 20)
+#define ADM8211_IER_NIE		(1 << 16)
+#define ADM8211_IER_AIE		(1 << 15)
+#define ADM8211_IER_TEIE	(1 << 14)
+#define ADM8211_IER_FBEIE	(1 << 13)
+#define ADM8211_IER_REIE	(1 << 12)
+#define ADM8211_IER_GPTIE	(1 << 11)
+#define ADM8211_IER_RSIE	(1 << 8)
+#define ADM8211_IER_RUIE	(1 << 7)
+#define ADM8211_IER_RCIE	(1 << 6)
+#define ADM8211_IER_TUIE	(1 << 5)
+#define ADM8211_IER_TRTIE	(1 << 4)
+#define ADM8211_IER_TLTTIE	(1 << 3)
+#define ADM8211_IER_TDUIE	(1 << 2)
+#define ADM8211_IER_TPSIE	(1 << 1)
+#define ADM8211_IER_TCIE	(1 << 0)
+
+/* CSR9 - SPR (Serial Port Register) */
+#define ADM8211_SPR_SRS		(1 << 11)
+#define ADM8211_SPR_SDO		(1 << 3)
+#define ADM8211_SPR_SDI		(1 << 2)
+#define ADM8211_SPR_SCLK	(1 << 1)
+#define ADM8211_SPR_SCS		(1 << 0)
+
+/* CSR9A - CSR_TEST0 */
+#define ADM8211_CSR_TEST0_EPNE	(1 << 18)
+#define ADM8211_CSR_TEST0_EPSNM	(1 << 17)
+#define ADM8211_CSR_TEST0_EPTYP	(1 << 16)
+#define ADM8211_CSR_TEST0_EPRLD	(1 << 15)
+
+/* CSR10 - WCSR (Wake-up Control/Status Register) */
+#define ADM8211_WCSR_CRCT	(1 << 30)
+#define ADM8211_WCSR_TSFTWE	(1 << 20)
+#define ADM8211_WCSR_TIMWE	(1 << 19)
+#define ADM8211_WCSR_ATIMWE	(1 << 18)
+#define ADM8211_WCSR_KEYWE	(1 << 17)
+#define ADM8211_WCSR_MPRE	(1 << 9)
+#define ADM8211_WCSR_LSOE	(1 << 8)
+#define ADM8211_WCSR_KEYUP	(1 << 6)
+#define ADM8211_WCSR_TSFTW	(1 << 5)
+#define ADM8211_WCSR_TIMW	(1 << 4)
+#define ADM8211_WCSR_ATIMW	(1 << 3)
+#define ADM8211_WCSR_MPR	(1 << 1)
+#define ADM8211_WCSR_LSO	(1 << 0)
+
+/* CSR11A - GPIO */
+#define ADM8211_CSR_GPIO_EN5	(1 << 17)
+#define ADM8211_CSR_GPIO_EN4	(1 << 16)
+#define ADM8211_CSR_GPIO_EN3	(1 << 15)
+#define ADM8211_CSR_GPIO_EN2	(1 << 14)
+#define ADM8211_CSR_GPIO_EN1	(1 << 13)
+#define ADM8211_CSR_GPIO_EN0	(1 << 12)
+#define ADM8211_CSR_GPIO_O5	(1 << 11)
+#define ADM8211_CSR_GPIO_O4	(1 << 10)
+#define ADM8211_CSR_GPIO_O3	(1 << 9)
+#define ADM8211_CSR_GPIO_O2	(1 << 8)
+#define ADM8211_CSR_GPIO_O1	(1 << 7)
+#define ADM8211_CSR_GPIO_O0	(1 << 6)
+#define ADM8211_CSR_GPIO_IN	0x0000003f
+
+/* CSR12 - BBPCTL (BBP Control port) */
+#define ADM8211_BBPCTL_MMISEL	(1 << 31)
+#define ADM8211_BBPCTL_SPICADD  (0x7F << 24)
+#define ADM8211_BBPCTL_RF3000	(0x20 << 24)
+#define ADM8211_BBPCTL_TXCE	(1 << 23)
+#define ADM8211_BBPCTL_RXCE	(1 << 22)
+#define ADM8211_BBPCTL_CCAP	(1 << 21)
+#define ADM8211_BBPCTL_TYPE	0x001c0000
+#define ADM8211_BBPCTL_WR	(1 << 17)
+#define ADM8211_BBPCTL_RD	(1 << 16)
+#define ADM8211_BBPCTL_ADDR	0x0000ff00
+#define ADM8211_BBPCTL_DATA	0x000000ff
+
+/* CSR12A - SYNCTL (Synthesizer Control port) */
+#define ADM8211_SYNCTL_WR	(1 << 31)
+#define ADM8211_SYNCTL_RD	(1 << 30)
+#define ADM8211_SYNCTL_CS0	(1 << 29)
+#define ADM8211_SYNCTL_CS1	(1 << 28)
+#define ADM8211_SYNCTL_CAL	(1 << 27)
+#define ADM8211_SYNCTL_SELCAL	(1 << 26)
+#define ADM8211_SYNCTL_RFtype	((1 << 24) || (1 << 23) || (1 << 22))
+#define ADM8211_SYNCTL_RFMD	(1 << 22)
+#define ADM8211_SYNCTL_GENERAL	(0x7 << 22)
+/* SYNCTL 21:0 Data (Si4126: 18-bit data, 4-bit address) */
+
+/* CSR18 - CMDR (Command Register) */
+#define ADM8211_CMDR_PM		(1 << 19)
+#define ADM8211_CMDR_APM	(1 << 18)
+#define ADM8211_CMDR_RTE	(1 << 4)
+#define ADM8211_CMDR_DRT	((1 << 3) | (1 << 2))
+#define ADM8211_CMDR_DRT_8DW	(0x0 << 2)
+#define ADM8211_CMDR_DRT_16DW	(0x1 << 2)
+#define ADM8211_CMDR_DRT_SF	(0x2 << 2)
+
+/* CSR33 - SYNRF (SYNRF direct control) */
+#define ADM8211_SYNRF_SELSYN	(1 << 31)
+#define ADM8211_SYNRF_SELRF	(1 << 30)
+#define ADM8211_SYNRF_LERF	(1 << 29)
+#define ADM8211_SYNRF_LEIF	(1 << 28)
+#define ADM8211_SYNRF_SYNCLK	(1 << 27)
+#define ADM8211_SYNRF_SYNDATA	(1 << 26)
+#define ADM8211_SYNRF_PE1	(1 << 25)
+#define ADM8211_SYNRF_PE2	(1 << 24)
+#define ADM8211_SYNRF_PA_PE	(1 << 23)
+#define ADM8211_SYNRF_TR_SW	(1 << 22)
+#define ADM8211_SYNRF_TR_SWN	(1 << 21)
+#define ADM8211_SYNRF_RADIO	(1 << 20)
+#define ADM8211_SYNRF_CAL_EN	(1 << 19)
+#define ADM8211_SYNRF_PHYRST	(1 << 18)
+
+#define ADM8211_SYNRF_IF_SELECT_0 	(1 << 31)
+#define ADM8211_SYNRF_IF_SELECT_1 	((1 << 31) | (1 << 28))
+#define ADM8211_SYNRF_WRITE_SYNDATA_0	(1 << 31)
+#define ADM8211_SYNRF_WRITE_SYNDATA_1	((1 << 31) | (1 << 26))
+#define ADM8211_SYNRF_WRITE_CLOCK_0	(1 << 31)
+#define ADM8211_SYNRF_WRITE_CLOCK_1	((1 << 31) | (1 << 27))
+
+/* CSR44 - WEPCTL (WEP Control) */
+#define ADM8211_WEPCTL_WEPENABLE   (1 << 31)
+#define ADM8211_WEPCTL_WPAENABLE   (1 << 30)
+#define ADM8211_WEPCTL_CURRENT_TABLE (1 << 29)
+#define ADM8211_WEPCTL_TABLE_WR	(1 << 28)
+#define ADM8211_WEPCTL_TABLE_RD	(1 << 27)
+#define ADM8211_WEPCTL_WEPRXBYP	(1 << 25)
+#define ADM8211_WEPCTL_SEL_WEPTABLE (1 << 23)
+#define ADM8211_WEPCTL_ADDR	(0x000001ff)
+
+/* CSR45 - WESK (Data Entry for Share/Individual Key) */
+#define ADM8211_WESK_DATA	(0x0000ffff)
+
+/* FER (Function Event Register) */
+#define ADM8211_FER_INTR_EV_ENT	(1 << 15)
+
+
+/* Si4126 RF Synthesizer - Control Registers */
+#define SI4126_MAIN_CONF	0
+#define SI4126_PHASE_DET_GAIN	1
+#define SI4126_POWERDOWN	2
+#define SI4126_RF1_N_DIV	3 /* only Si4136 */
+#define SI4126_RF2_N_DIV	4
+#define SI4126_IF_N_DIV		5
+#define SI4126_RF1_R_DIV	6 /* only Si4136 */
+#define SI4126_RF2_R_DIV	7
+#define SI4126_IF_R_DIV		8
+
+/* Main Configuration */
+#define SI4126_MAIN_XINDIV2	(1 << 6)
+#define SI4126_MAIN_IFDIV	((1 << 11) | (1 << 10))
+/* Powerdown */
+#define SI4126_POWERDOWN_PDIB	(1 << 1)
+#define SI4126_POWERDOWN_PDRB	(1 << 0)
+
+
+/* RF3000 BBP - Control Port Registers */
+/* 0x00 - reserved */
+#define RF3000_MODEM_CTRL__RX_STATUS 0x01
+#define RF3000_CCA_CTRL 0x02
+#define RF3000_DIVERSITY__RSSI 0x03
+#define RF3000_RX_SIGNAL_FIELD 0x04
+#define RF3000_RX_LEN_MSB 0x05
+#define RF3000_RX_LEN_LSB 0x06
+#define RF3000_RX_SERVICE_FIELD 0x07
+#define RF3000_TX_VAR_GAIN__TX_LEN_EXT 0x11
+#define RF3000_TX_LEN_MSB 0x12
+#define RF3000_TX_LEN_LSB 0x13
+#define RF3000_LOW_GAIN_CALIB 0x14
+#define RF3000_HIGH_GAIN_CALIB 0x15
+
+/* ADM8211 revisions */
+#define ADM8211_REV_AB 0x11
+#define ADM8211_REV_AF 0x15
+#define ADM8211_REV_BA 0x20
+#define ADM8211_REV_CA 0x30
+
+struct adm8211_desc {
+	__le32 status;
+	__le32 length;
+	__le32 buffer1;
+	__le32 buffer2;
+};
+
+#define RDES0_STATUS_OWN	(1 << 31)
+#define RDES0_STATUS_ES		(1 << 30)
+#define RDES0_STATUS_SQL	(1 << 29)
+#define RDES0_STATUS_DE		(1 << 28)
+#define RDES0_STATUS_FS		(1 << 27)
+#define RDES0_STATUS_LS		(1 << 26)
+#define RDES0_STATUS_PCF	(1 << 25)
+#define RDES0_STATUS_SFDE	(1 << 24)
+#define RDES0_STATUS_SIGE	(1 << 23)
+#define RDES0_STATUS_CRC16E	(1 << 22)
+#define RDES0_STATUS_RXTOE	(1 << 21)
+#define RDES0_STATUS_CRC32E	(1 << 20)
+#define RDES0_STATUS_ICVE	(1 << 19)
+#define RDES0_STATUS_DA1	(1 << 17)
+#define RDES0_STATUS_DA0	(1 << 16)
+#define RDES0_STATUS_RXDR	((1 << 15) | (1 << 14) | (1 << 13) | (1 << 12))
+#define RDES0_STATUS_FL		(0x00000fff)
+
+#define RDES1_CONTROL_RER	(1 << 25)
+#define RDES1_CONTROL_RCH	(1 << 24)
+#define RDES1_CONTROL_RBS2	(0x00fff000)
+#define RDES1_CONTROL_RBS1	(0x00000fff)
+
+#define RDES1_STATUS_RSSI	(0x0000007f)
+
+
+#define TDES0_CONTROL_OWN	(1 << 31)
+#define TDES0_CONTROL_DONE	(1 << 30)
+#define TDES0_CONTROL_TXDR	(0x0ff00000)
+
+#define TDES0_STATUS_OWN	(1 << 31)
+#define TDES0_STATUS_DONE	(1 << 30)
+#define TDES0_STATUS_ES		(1 << 29)
+#define TDES0_STATUS_TLT	(1 << 28)
+#define TDES0_STATUS_TRT	(1 << 27)
+#define TDES0_STATUS_TUF	(1 << 26)
+#define TDES0_STATUS_TRO	(1 << 25)
+#define TDES0_STATUS_SOFBR	(1 << 24)
+#define TDES0_STATUS_ACR	(0x00000fff)
+
+#define TDES1_CONTROL_IC	(1 << 31)
+#define TDES1_CONTROL_LS	(1 << 30)
+#define TDES1_CONTROL_FS	(1 << 29)
+#define TDES1_CONTROL_TER	(1 << 25)
+#define TDES1_CONTROL_TCH	(1 << 24)
+#define TDES1_CONTROL_RBS2	(0x00fff000)
+#define TDES1_CONTROL_RBS1	(0x00000fff)
+
+/* SRAM offsets */
+#define ADM8211_SRAM(x) (priv->pdev->revision < ADM8211_REV_BA ? \
+        ADM8211_SRAM_A_ ## x : ADM8211_SRAM_B_ ## x)
+
+#define ADM8211_SRAM_INDIV_KEY   0x0000
+#define ADM8211_SRAM_A_SHARE_KEY 0x0160
+#define ADM8211_SRAM_B_SHARE_KEY 0x00c0
+
+#define ADM8211_SRAM_A_SSID      0x0180
+#define ADM8211_SRAM_B_SSID      0x00d4
+#define ADM8211_SRAM_SSID ADM8211_SRAM(SSID)
+
+#define ADM8211_SRAM_A_SUPP_RATE 0x0191
+#define ADM8211_SRAM_B_SUPP_RATE 0x00dd
+#define ADM8211_SRAM_SUPP_RATE ADM8211_SRAM(SUPP_RATE)
+
+#define ADM8211_SRAM_A_SIZE      0x0200
+#define ADM8211_SRAM_B_SIZE      0x01c0
+#define ADM8211_SRAM_SIZE ADM8211_SRAM(SIZE)
+
+struct adm8211_rx_ring_info {
+	struct sk_buff *skb;
+	dma_addr_t mapping;
+};
+
+struct adm8211_tx_ring_info {
+	struct sk_buff *skb;
+	dma_addr_t mapping;
+	struct ieee80211_tx_control tx_control;
+	size_t hdrlen;
+};
+
+#define PLCP_SIGNAL_1M		0x0a
+#define PLCP_SIGNAL_2M		0x14
+#define PLCP_SIGNAL_5M5		0x37
+#define PLCP_SIGNAL_11M		0x6e
+
+struct adm8211_tx_hdr {
+	u8 da[6];
+	u8 signal; /* PLCP signal / TX rate in 100 Kbps */
+	u8 service;
+	__le16 frame_body_size;
+	__le16 frame_control;
+	__le16 plcp_frag_tail_len;
+	__le16 plcp_frag_head_len;
+	__le16 dur_frag_tail;
+	__le16 dur_frag_head;
+	u8 addr4[6];
+
+#define ADM8211_TXHDRCTL_SHORT_PREAMBLE		(1 <<  0)
+#define ADM8211_TXHDRCTL_MORE_FRAG		(1 <<  1)
+#define ADM8211_TXHDRCTL_MORE_DATA		(1 <<  2)
+#define ADM8211_TXHDRCTL_FRAG_NO		(1 <<  3) /* ? */
+#define ADM8211_TXHDRCTL_ENABLE_RTS		(1 <<  4)
+#define ADM8211_TXHDRCTL_ENABLE_WEP_ENGINE	(1 <<  5)
+#define ADM8211_TXHDRCTL_ENABLE_EXTEND_HEADER	(1 << 15) /* ? */
+	__le16 header_control;
+	__le16 frag;
+	u8 reserved_0;
+	u8 retry_limit;
+
+	u32 wep2key0;
+	u32 wep2key1;
+	u32 wep2key2;
+	u32 wep2key3;
+
+	u8 keyid;
+	u8 entry_control;	// huh??
+	u16 reserved_1;
+	u32 reserved_2;
+} __attribute__ ((packed));
+
+
+#define RX_COPY_BREAK 128
+#define RX_PKT_SIZE 2500
+
+struct adm8211_eeprom {
+	__le16	signature;		/* 0x00 */
+	u8	major_version;		/* 0x02 */
+	u8	minor_version;		/* 0x03 */
+	u8	reserved_1[4];		/* 0x04 */
+	u8	hwaddr[6];		/* 0x08 */
+	u8	reserved_2[8];		/* 0x1E */
+	__le16	cr49;			/* 0x16 */
+	u8	cr03;			/* 0x18 */
+	u8	cr28;			/* 0x19 */
+	u8	cr29;			/* 0x1A */
+	u8	country_code;		/* 0x1B */
+
+/* specific bbp types */
+#define ADM8211_BBP_RFMD3000	0x00
+#define ADM8211_BBP_RFMD3002	0x01
+#define ADM8211_BBP_ADM8011	0x04
+	u8	specific_bbptype;	/* 0x1C */
+	u8	specific_rftype;	/* 0x1D */
+	u8	reserved_3[2];		/* 0x1E */
+	__le16	device_id;		/* 0x20 */
+	__le16	vendor_id;		/* 0x22 */
+	__le16	subsystem_id;		/* 0x24 */
+	__le16	subsystem_vendor_id;	/* 0x26 */
+	u8	maxlat;			/* 0x28 */
+	u8	mingnt;			/* 0x29 */
+	__le16	cis_pointer_low;	/* 0x2A */
+	__le16	cis_pointer_high;	/* 0x2C */
+	__le16	csr18;			/* 0x2E */
+	u8	reserved_4[16];		/* 0x30 */
+	u8	d1_pwrdara;		/* 0x40 */
+	u8	d0_pwrdara;		/* 0x41 */
+	u8	d3_pwrdara;		/* 0x42 */
+	u8	d2_pwrdara;		/* 0x43 */
+	u8	antenna_power[14];	/* 0x44 */
+	__le16	cis_wordcnt;		/* 0x52 */
+	u8	tx_power[14];		/* 0x54 */
+	u8	lpf_cutoff[14];		/* 0x62 */
+	u8	lnags_threshold[14];	/* 0x70 */
+	__le16	checksum;		/* 0x7E */
+	u8	cis_data[0];		/* 0x80, 384 bytes */
+} __attribute__ ((packed));
+
+static const struct ieee80211_rate adm8211_rates[] = {
+	{ .rate = 10,
+	  .val = 10,
+	  .val2 = -10,
+	  .flags = IEEE80211_RATE_CCK_2 },
+	{ .rate = 20,
+	  .val = 20,
+	  .val2 = -20,
+	  .flags = IEEE80211_RATE_CCK_2 },
+	{ .rate = 55,
+	  .val = 55,
+	  .val2 = -55,
+	  .flags = IEEE80211_RATE_CCK_2 },
+	{ .rate = 110,
+	  .val = 110,
+	  .val2 = -110,
+	  .flags = IEEE80211_RATE_CCK_2 }
+};
+
+struct ieee80211_chan_range {
+	u8 min;
+	u8 max;
+};
+
+static const struct ieee80211_channel adm8211_channels[] = {
+	{ .chan = 1,
+	  .freq = 2412},
+	{ .chan = 2,
+	  .freq = 2417},
+	{ .chan = 3,
+	  .freq = 2422},
+	{ .chan = 4,
+	  .freq = 2427},
+	{ .chan = 5,
+	  .freq = 2432},
+	{ .chan = 6,
+	  .freq = 2437},
+	{ .chan = 7,
+	  .freq = 2442},
+	{ .chan = 8,
+	  .freq = 2447},
+	{ .chan = 9,
+	  .freq = 2452},
+	{ .chan = 10,
+	  .freq = 2457},
+	{ .chan = 11,
+	  .freq = 2462},
+	{ .chan = 12,
+	  .freq = 2467},
+	{ .chan = 13,
+	  .freq = 2472},
+	{ .chan = 14,
+	  .freq = 2484},
+};
+
+struct adm8211_priv {
+	struct pci_dev *pdev;
+	spinlock_t lock;
+	struct adm8211_csr __iomem *map;
+	struct adm8211_desc *rx_ring;
+	struct adm8211_desc *tx_ring;
+	dma_addr_t rx_ring_dma;
+	dma_addr_t tx_ring_dma;
+	struct adm8211_rx_ring_info *rx_buffers;
+	struct adm8211_tx_ring_info *tx_buffers;
+	unsigned int rx_ring_size, tx_ring_size;
+	unsigned int cur_tx, dirty_tx, cur_rx;
+
+	struct ieee80211_low_level_stats stats;
+	struct ieee80211_hw_mode modes[1];
+	struct ieee80211_channel channels[ARRAY_SIZE(adm8211_channels)];
+	struct ieee80211_rate rates[ARRAY_SIZE(adm8211_rates)];
+	int mode;
+
+	int channel;
+	u8 bssid[ETH_ALEN];
+	u8 ssid[32];
+	size_t ssid_len;
+
+	u8 soft_rx_crc;
+	u8 retry_limit;
+
+	u8 ant_power;
+	u8 tx_power;
+	u8 lpf_cutoff;
+	u8 lnags_threshold;
+	struct adm8211_eeprom *eeprom;
+	size_t eeprom_len;
+
+	u32 nar;
+
+#define ADM8211_TYPE_INTERSIL	0x00
+#define ADM8211_TYPE_RFMD	0x01
+#define ADM8211_TYPE_MARVEL	0x02
+#define ADM8211_TYPE_AIROHA	0x03
+#define ADM8211_TYPE_ADMTEK     0x05
+	unsigned int rf_type:3;
+	unsigned int bbp_type:3;
+
+	u8 specific_bbptype;
+	enum {
+		ADM8211_RFMD2948 = 0x0,
+		ADM8211_RFMD2958 = 0x1,
+		ADM8211_RFMD2958_RF3000_CONTROL_POWER = 0x2,
+		ADM8211_MAX2820 = 0x8,
+		ADM8211_AL2210L = 0xC,	/* Airoha */
+	} transceiver_type;
+};
+
+static const struct ieee80211_chan_range cranges[] = {
+	{1,  11},	/* FCC */
+	{1,  11},	/* IC */
+	{1,  13},	/* ETSI */
+	{10, 11},	/* SPAIN */
+	{10, 13},	/* FRANCE */
+	{14, 14},	/* MMK */
+	{1,  14},	/* MMK2 */
+};
+
+#endif /* ADM8211_H */
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index ee1cc14..074055e 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -241,8 +241,8 @@
 
 MODULE_AUTHOR("Benjamin Reed");
 MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \
-                   cards.  Direct support for ISA/PCI/MPI cards and support \
-		   for PCMCIA when used with airo_cs.");
+cards.  Direct support for ISA/PCI/MPI cards and support \
+for PCMCIA when used with airo_cs.");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340/350");
 module_param_array(io, int, NULL, 0);
@@ -2481,7 +2481,7 @@
 
 EXPORT_SYMBOL(stop_airo_card);
 
-static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr)
+static int wll_header_parse(const struct sk_buff *skb, unsigned char *haddr)
 {
 	memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN);
 	return ETH_ALEN;
@@ -2696,14 +2696,13 @@
 	return rc;
 }
 
+static const struct header_ops airo_header_ops = {
+	.parse = wll_header_parse,
+};
+
 static void wifi_setup(struct net_device *dev)
 {
-	dev->hard_header        = NULL;
-	dev->rebuild_header     = NULL;
-	dev->hard_header_cache  = NULL;
-	dev->header_cache_update= NULL;
-
-	dev->hard_header_parse  = wll_header_parse;
+	dev->header_ops = &airo_header_ops;
 	dev->hard_start_xmit = &airo_start_xmit11;
 	dev->get_stats = &airo_get_stats;
 	dev->set_mac_address = &airo_set_mac_address;
@@ -2821,6 +2820,7 @@
 	struct net_device *dev;
 	struct airo_info *ai;
 	int i, rc;
+	DECLARE_MAC_BUF(mac);
 
 	/* Create the network device object. */
 	dev = alloc_netdev(sizeof(*ai), "", ether_setup);
@@ -2870,7 +2870,6 @@
 	dev->base_addr = port;
 
 	SET_NETDEV_DEV(dev, dmdev);
-	SET_MODULE_OWNER(dev);
 
 	reset_card (dev, 1);
 	msleep(400);
@@ -2924,9 +2923,8 @@
 		goto err_out_reg;
 
 	set_bit(FLAG_REGISTERED,&ai->flags);
-	airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x",
-		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
+	airo_print_info(dev->name, "MAC enabled %s",
+			print_mac(mac, dev->dev_addr));
 
 	/* Allocate the transmit buffers */
 	if (probe && !test_bit(FLAG_MPI,&ai->flags))
@@ -2983,6 +2981,7 @@
 {
 	int i;
 	struct airo_info *ai = dev->priv;
+	DECLARE_MAC_BUF(mac);
 
 	if (reset_card (dev, 1))
 		return -1;
@@ -2991,9 +2990,8 @@
 		airo_print_err(dev->name, "MAC could not be enabled");
 		return -1;
 	}
-	airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x",
-			dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-			dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+	airo_print_info(dev->name, "MAC enabled %s",
+			print_mac(mac, dev->dev_addr));
 	/* Allocate the transmit buffers if needed */
 	if (!test_bit(FLAG_MPI,&ai->flags))
 		for( i = 0; i < MAX_FIDS; i++ )
@@ -5427,6 +5425,7 @@
 	int i;
 	char *ptr;
 	APListRid APList_rid;
+	DECLARE_MAC_BUF(mac);
 
 	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
@@ -5450,13 +5449,8 @@
 // We end when we find a zero MAC
 		if ( !*(int*)APList_rid.ap[i] &&
 		     !*(int*)&APList_rid.ap[i][2]) break;
-		ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x\n",
-			       (int)APList_rid.ap[i][0],
-			       (int)APList_rid.ap[i][1],
-			       (int)APList_rid.ap[i][2],
-			       (int)APList_rid.ap[i][3],
-			       (int)APList_rid.ap[i][4],
-			       (int)APList_rid.ap[i][5]);
+		ptr += sprintf(ptr, "%s\n",
+			       print_mac(mac, APList_rid.ap[i]));
 	}
 	if (i==0) ptr += sprintf(ptr, "Not using specific APs\n");
 
@@ -5475,6 +5469,7 @@
 	int rc;
 	/* If doLoseSync is not 1, we won't do a Lose Sync */
 	int doLoseSync = -1;
+	DECLARE_MAC_BUF(mac);
 
 	if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
 		return -ENOMEM;
@@ -5511,13 +5506,8 @@
            we have to add a spin lock... */
 	rc = readBSSListRid(ai, doLoseSync, &BSSList_rid);
 	while(rc == 0 && BSSList_rid.index != 0xffff) {
-		ptr += sprintf(ptr, "%02x:%02x:%02x:%02x:%02x:%02x %*s rssi = %d",
-				(int)BSSList_rid.bssid[0],
-				(int)BSSList_rid.bssid[1],
-				(int)BSSList_rid.bssid[2],
-				(int)BSSList_rid.bssid[3],
-				(int)BSSList_rid.bssid[4],
-				(int)BSSList_rid.bssid[5],
+		ptr += sprintf(ptr, "%s %*s rssi = %d",
+			       print_mac(mac, BSSList_rid.bssid),
 				(int)BSSList_rid.ssidLen,
 				BSSList_rid.ssid,
 				(int)BSSList_rid.dBm);
@@ -7579,9 +7569,9 @@
 
 static const struct iw_handler_def	airo_handler_def =
 {
-	.num_standard	= sizeof(airo_handler)/sizeof(iw_handler),
-	.num_private	= sizeof(airo_private_handler)/sizeof(iw_handler),
-	.num_private_args = sizeof(airo_private_args)/sizeof(struct iw_priv_args),
+	.num_standard	= ARRAY_SIZE(airo_handler),
+	.num_private	= ARRAY_SIZE(airo_private_handler),
+	.num_private_args = ARRAY_SIZE(airo_private_args),
 	.standard	= airo_handler,
 	.private	= airo_private_handler,
 	.private_args	= airo_private_args,
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
index 7d5b8c2..6f7eb9f 100644
--- a/drivers/net/wireless/airport.c
+++ b/drivers/net/wireless/airport.c
@@ -197,7 +197,6 @@
 		return -EBUSY;
 	}
 
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
 
 	macio_set_drvdata(mdev, dev);
diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
index 498e848..dbdfc9e 100644
--- a/drivers/net/wireless/arlan-main.c
+++ b/drivers/net/wireless/arlan-main.c
@@ -1469,10 +1469,10 @@
 					while (dmi)
 					{							if (dmi->dmi_addrlen == 6)
 						{
+							DECLARE_MAC_BUF(mac);
 							if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP)
-								printk(KERN_ERR "%s mcl %2x:%2x:%2x:%2x:%2x:%2x \n", dev->name,
-										 dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
-										 dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]);
+								printk(KERN_ERR "%s mcl %s\n",
+								       dev->name, print_mac(mac, dmi->dmi_addr));
 							for (i = 0; i < 6; i++)
 								if (dmi->dmi_addr[i] != hw_dst_addr[i])
 									break;
@@ -1512,17 +1512,18 @@
 			{
 				char immedDestAddress[6];
 				char immedSrcAddress[6];
+				DECLARE_MAC_BUF(mac);
+				DECLARE_MAC_BUF(mac2);
+				DECLARE_MAC_BUF(mac3);
+				DECLARE_MAC_BUF(mac4);
 				memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6);
 				memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6);
 
-				printk(KERN_WARNING "%s t %2x:%2x:%2x:%2x:%2x:%2x f %2x:%2x:%2x:%2x:%2x:%2x imd %2x:%2x:%2x:%2x:%2x:%2x ims %2x:%2x:%2x:%2x:%2x:%2x\n", dev->name,
-					(unsigned char) skbtmp[0], (unsigned char) skbtmp[1], (unsigned char) skbtmp[2], (unsigned char) skbtmp[3],
-					(unsigned char) skbtmp[4], (unsigned char) skbtmp[5], (unsigned char) skbtmp[6], (unsigned char) skbtmp[7],
-					(unsigned char) skbtmp[8], (unsigned char) skbtmp[9], (unsigned char) skbtmp[10], (unsigned char) skbtmp[11],
-					immedDestAddress[0], immedDestAddress[1], immedDestAddress[2],
-					immedDestAddress[3], immedDestAddress[4], immedDestAddress[5],
-					immedSrcAddress[0], immedSrcAddress[1], immedSrcAddress[2],
-					immedSrcAddress[3], immedSrcAddress[4], immedSrcAddress[5]);
+				printk(KERN_WARNING "%s t %s f %s imd %s ims %s\n",
+				       dev->name, print_mac(mac, skbtmp),
+				       print_mac(mac2, &skbtmp[6]),
+				       print_mac(mac3, immedDestAddress),
+				       print_mac(mac4, immedSrcAddress));
 			}
 			skb->protocol = eth_type_trans(skb, dev);
 			IFDEBUG(ARLAN_DEBUG_HEADER_DUMP)
@@ -1792,8 +1793,6 @@
 	if (!dev)
 		return ERR_PTR(-ENOMEM);
 
-	SET_MODULE_OWNER(dev);
-
 	if (unit >= 0) {
 		sprintf(dev->name, "eth%d", unit);
 		netdev_boot_setup_check(dev);
diff --git a/drivers/net/wireless/arlan-proc.c b/drivers/net/wireless/arlan-proc.c
index 015abd9..c6e70db 100644
--- a/drivers/net/wireless/arlan-proc.c
+++ b/drivers/net/wireless/arlan-proc.c
@@ -435,7 +435,7 @@
 		goto final;
 	}
 	else
-		priva = arlan_device[devnum]->priv;
+		priva = netdev_priv(arlan_device[devnum]);
 
 	if (priva == NULL)
 	{
@@ -654,7 +654,7 @@
 		goto final;
 	}
 	else
-		priva = arlan_device[devnum]->priv;
+		priva = netdev_priv(arlan_device[devnum]);
 	if (priva == NULL)
 	{
 		printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
@@ -688,7 +688,7 @@
 		  goto final;
 	}
 	else
-		priva = arlan_device[devnum]->priv;
+		priva = netdev_priv(arlan_device[devnum]);
 	if (priva == NULL)
 	{
 		printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
@@ -716,7 +716,7 @@
 		  pos += sprintf(arlan_drive_info + pos, "No device found here \n");
 		  goto final;
 	} else
-		priva = arlan_device[devnum]->priv;
+		priva = netdev_priv(arlan_device[devnum]);
 	if (priva == NULL)
 	{
 		printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
@@ -745,7 +745,7 @@
 		goto final;
 	}
 	else
-		priva = arlan_device[devnum]->priv;
+		priva = netdev_priv(arlan_device[devnum]);
 	if (priva == NULL)
 	{
 		printk(KERN_WARNING " Could not find the device private in arlan procsys, bad\n ");
@@ -780,7 +780,7 @@
 	}
 	else if (arlan_device[devnum] != NULL)
 	{
-		  priv = arlan_device[devnum]->priv;
+		  priv = netdev_priv(arlan_device[devnum]);
 
 		  arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_CONF);
 	}
@@ -805,7 +805,7 @@
 	}
 	else if (arlan_device[devnum] != NULL)
 	{
-		priv = arlan_device[devnum]->priv;
+		priv = netdev_priv(arlan_device[devnum]);
 		arlan_command(arlan_device[devnum], ARLAN_COMMAND_CLEAN_AND_RESET);
 
 	} else
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 51a7db5..059ce3f 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -1484,6 +1484,7 @@
 	struct net_device *dev;
 	struct atmel_private *priv;
 	int rc;
+	DECLARE_MAC_BUF(mac);
 
 	/* Create the network device object. */
         dev = alloc_etherdev(sizeof(*priv));
@@ -1598,12 +1599,9 @@
 	if (!ent)
 		printk(KERN_WARNING "atmel: unable to create /proc entry.\n");
 
-	printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
-	       dev->name, DRIVER_MAJOR, DRIVER_MINOR,
-	       dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-	       dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] );
+	printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %s\n",
+	       dev->name, DRIVER_MAJOR, DRIVER_MINOR, print_mac(mac, dev->dev_addr));
 
-	SET_MODULE_OWNER(dev);
 	return dev;
 
 err_out_res:
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
new file mode 100644
index 0000000..e3c573e
--- /dev/null
+++ b/drivers/net/wireless/b43/Kconfig
@@ -0,0 +1,131 @@
+config B43
+	tristate "Broadcom 43xx wireless support (mac80211 stack)"
+	depends on SSB_POSSIBLE && MAC80211 && WLAN_80211
+	select SSB
+	select FW_LOADER
+	select HW_RANDOM
+	---help---
+	  b43 is a driver for the Broadcom 43xx series wireless devices.
+
+	  Check "lspci" for something like
+	  "Broadcom Corporation BCM43XX 802.11 Wireless LAN Controller"
+	  to determine whether you own such a device.
+
+	  This driver supports the new BCM43xx IEEE 802.11G devices, but not
+	  the old IEEE 802.11B devices. Old devices are supported by
+	  the b43legacy driver.
+	  Note that this has nothing to do with the standard that your AccessPoint
+	  supports (A, B, G or a combination).
+	  IEEE 802.11G devices can talk to IEEE 802.11B AccessPoints.
+
+	  It is safe to include both b43 and b43legacy as the underlying glue
+	  layer will automatically load the correct version for your device.
+
+	  This driver uses V4 firmware, which must be installed separately using
+	  b43-fwcutter.
+
+	  This driver can be built as a module (recommended) that will be called "b43".
+	  If unsure, say M.
+
+# Auto-select SSB PCI-HOST support, if possible
+config B43_PCI_AUTOSELECT
+	bool
+	depends on B43 && SSB_PCIHOST_POSSIBLE
+	select SSB_PCIHOST
+	default y
+
+# Auto-select SSB PCICORE driver, if possible
+config B43_PCICORE_AUTOSELECT
+	bool
+	depends on B43 && SSB_DRIVER_PCICORE_POSSIBLE
+	select SSB_DRIVER_PCICORE
+	default y
+
+config B43_PCMCIA
+	bool "Broadcom 43xx PCMCIA device support (EXPERIMENTAL)"
+	depends on B43 && SSB_PCMCIAHOST_POSSIBLE && EXPERIMENTAL
+	select SSB_PCMCIAHOST
+	---help---
+	  Broadcom 43xx PCMCIA device support.
+
+	  Support for 16bit PCMCIA devices.
+	  Please note that most PC-CARD devices are _NOT_ 16bit PCMCIA
+	  devices, but 32bit CardBUS devices. CardBUS devices are supported
+	  out of the box by b43.
+
+	  With this config option you can drive b43 cards in
+	  CompactFlash formfactor in a PCMCIA adaptor.
+	  CF b43 cards can sometimes be found in handheld PCs.
+
+	  It's safe to select Y here, even if you don't have a B43 PCMCIA device.
+
+	  If unsure, say N.
+
+# LED support
+config B43_LEDS
+	bool
+	depends on B43 && MAC80211_LEDS
+	default y
+
+# RFKILL support
+config B43_RFKILL
+	bool
+	depends on B43 && RFKILL && RFKILL_INPUT && INPUT_POLLDEV
+	default y
+
+config B43_DEBUG
+	bool "Broadcom 43xx debugging"
+	depends on B43
+	---help---
+	  Broadcom 43xx debugging messages.
+
+	  Say Y, if you want to find out why the driver does not
+	  work for you.
+
+config B43_DMA
+	bool
+	depends on B43
+config B43_PIO
+	bool
+	depends on B43
+
+choice
+	prompt "Broadcom 43xx data transfer mode"
+	depends on B43
+	default B43_DMA_AND_PIO_MODE
+
+config B43_DMA_AND_PIO_MODE
+	bool "DMA + PIO"
+	select B43_DMA
+	select B43_PIO
+	---help---
+	  Include both, Direct Memory Access (DMA) and Programmed I/O (PIO)
+	  data transfer modes.
+	  The actually used mode is selectable through the module
+	  parameter "pio". If the module parameter is pio=0, DMA is used.
+	  Otherwise PIO is used. DMA is default.
+
+	  If unsure, choose this option.
+
+config B43_DMA_MODE
+	bool "DMA (Direct Memory Access) only"
+	select B43_DMA
+	---help---
+	  Only include Direct Memory Access (DMA).
+	  This reduces the size of the driver module, by omitting the PIO code.
+
+config B43_PIO_MODE
+	bool "PIO (Programmed I/O) only"
+	select B43_PIO
+	---help---
+	  Only include Programmed I/O (PIO).
+	  This reduces the size of the driver module, by omitting the DMA code.
+	  Please note that PIO transfers are slow (compared to DMA).
+
+	  Also note that not all devices of the 43xx series support PIO.
+	  The 4306 (Apple Airport Extreme and others) supports PIO, while
+	  the 4318 is known to _not_ support PIO.
+
+	  Only use PIO, if DMA does not work for you.
+
+endchoice
diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile
new file mode 100644
index 0000000..485e59e
--- /dev/null
+++ b/drivers/net/wireless/b43/Makefile
@@ -0,0 +1,20 @@
+# b43 core
+b43-y				+= main.o
+b43-y				+= tables.o
+b43-y				+= phy.o
+b43-y				+= sysfs.o
+b43-y				+= xmit.o
+b43-y				+= lo.o
+# b43 RFKILL button support
+b43-$(CONFIG_B43_RFKILL)	+= rfkill.o
+# b43 LED support
+b43-$(CONFIG_B43_LEDS)		+= leds.o
+# b43 PCMCIA support
+b43-$(CONFIG_B43_PCMCIA)	+= pcmcia.o
+# b43 debugging
+b43-$(CONFIG_B43_DEBUG)		+= debugfs.o
+# b43 DMA and PIO
+b43-$(CONFIG_B43_DMA)		+= dma.o
+b43-$(CONFIG_B43_PIO)		+= pio.o
+
+obj-$(CONFIG_B43)		+= b43.o
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
new file mode 100644
index 0000000..a28ad23
--- /dev/null
+++ b/drivers/net/wireless/b43/b43.h
@@ -0,0 +1,854 @@
+#ifndef B43_H_
+#define B43_H_
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/hw_random.h>
+#include <linux/ssb/ssb.h>
+#include <net/mac80211.h>
+
+#include "debugfs.h"
+#include "leds.h"
+#include "rfkill.h"
+#include "lo.h"
+#include "phy.h"
+
+#ifdef CONFIG_B43_DEBUG
+# define B43_DEBUG	1
+#else
+# define B43_DEBUG	0
+#endif
+
+#define B43_RX_MAX_SSI			60
+
+/* MMIO offsets */
+#define B43_MMIO_DMA0_REASON		0x20
+#define B43_MMIO_DMA0_IRQ_MASK		0x24
+#define B43_MMIO_DMA1_REASON		0x28
+#define B43_MMIO_DMA1_IRQ_MASK		0x2C
+#define B43_MMIO_DMA2_REASON		0x30
+#define B43_MMIO_DMA2_IRQ_MASK		0x34
+#define B43_MMIO_DMA3_REASON		0x38
+#define B43_MMIO_DMA3_IRQ_MASK		0x3C
+#define B43_MMIO_DMA4_REASON		0x40
+#define B43_MMIO_DMA4_IRQ_MASK		0x44
+#define B43_MMIO_DMA5_REASON		0x48
+#define B43_MMIO_DMA5_IRQ_MASK		0x4C
+#define B43_MMIO_MACCTL			0x120
+#define B43_MMIO_STATUS2_BITFIELD	0x124
+#define B43_MMIO_GEN_IRQ_REASON		0x128
+#define B43_MMIO_GEN_IRQ_MASK		0x12C
+#define B43_MMIO_RAM_CONTROL		0x130
+#define B43_MMIO_RAM_DATA		0x134
+#define B43_MMIO_PS_STATUS		0x140
+#define B43_MMIO_RADIO_HWENABLED_HI	0x158
+#define B43_MMIO_SHM_CONTROL		0x160
+#define B43_MMIO_SHM_DATA		0x164
+#define B43_MMIO_SHM_DATA_UNALIGNED	0x166
+#define B43_MMIO_XMITSTAT_0		0x170
+#define B43_MMIO_XMITSTAT_1		0x174
+#define B43_MMIO_REV3PLUS_TSF_LOW	0x180	/* core rev >= 3 only */
+#define B43_MMIO_REV3PLUS_TSF_HIGH	0x184	/* core rev >= 3 only */
+
+/* 32-bit DMA */
+#define B43_MMIO_DMA32_BASE0		0x200
+#define B43_MMIO_DMA32_BASE1		0x220
+#define B43_MMIO_DMA32_BASE2		0x240
+#define B43_MMIO_DMA32_BASE3		0x260
+#define B43_MMIO_DMA32_BASE4		0x280
+#define B43_MMIO_DMA32_BASE5		0x2A0
+/* 64-bit DMA */
+#define B43_MMIO_DMA64_BASE0		0x200
+#define B43_MMIO_DMA64_BASE1		0x240
+#define B43_MMIO_DMA64_BASE2		0x280
+#define B43_MMIO_DMA64_BASE3		0x2C0
+#define B43_MMIO_DMA64_BASE4		0x300
+#define B43_MMIO_DMA64_BASE5		0x340
+/* PIO */
+#define B43_MMIO_PIO1_BASE		0x300
+#define B43_MMIO_PIO2_BASE		0x310
+#define B43_MMIO_PIO3_BASE		0x320
+#define B43_MMIO_PIO4_BASE		0x330
+
+#define B43_MMIO_PHY_VER		0x3E0
+#define B43_MMIO_PHY_RADIO		0x3E2
+#define B43_MMIO_PHY0			0x3E6
+#define B43_MMIO_ANTENNA		0x3E8
+#define B43_MMIO_CHANNEL		0x3F0
+#define B43_MMIO_CHANNEL_EXT		0x3F4
+#define B43_MMIO_RADIO_CONTROL		0x3F6
+#define B43_MMIO_RADIO_DATA_HIGH	0x3F8
+#define B43_MMIO_RADIO_DATA_LOW		0x3FA
+#define B43_MMIO_PHY_CONTROL		0x3FC
+#define B43_MMIO_PHY_DATA		0x3FE
+#define B43_MMIO_MACFILTER_CONTROL	0x420
+#define B43_MMIO_MACFILTER_DATA		0x422
+#define B43_MMIO_RCMTA_COUNT		0x43C
+#define B43_MMIO_RADIO_HWENABLED_LO	0x49A
+#define B43_MMIO_GPIO_CONTROL		0x49C
+#define B43_MMIO_GPIO_MASK		0x49E
+#define B43_MMIO_TSF_0			0x632	/* core rev < 3 only */
+#define B43_MMIO_TSF_1			0x634	/* core rev < 3 only */
+#define B43_MMIO_TSF_2			0x636	/* core rev < 3 only */
+#define B43_MMIO_TSF_3			0x638	/* core rev < 3 only */
+#define B43_MMIO_RNG			0x65A
+#define B43_MMIO_POWERUP_DELAY		0x6A8
+
+/* SPROM boardflags_lo values */
+#define B43_BFL_BTCOEXIST		0x0001	/* implements Bluetooth coexistance */
+#define B43_BFL_PACTRL			0x0002	/* GPIO 9 controlling the PA */
+#define B43_BFL_AIRLINEMODE		0x0004	/* implements GPIO 13 radio disable indication */
+#define B43_BFL_RSSI			0x0008	/* software calculates nrssi slope. */
+#define B43_BFL_ENETSPI			0x0010	/* has ephy roboswitch spi */
+#define B43_BFL_XTAL_NOSLOW		0x0020	/* no slow clock available */
+#define B43_BFL_CCKHIPWR		0x0040	/* can do high power CCK transmission */
+#define B43_BFL_ENETADM			0x0080	/* has ADMtek switch */
+#define B43_BFL_ENETVLAN		0x0100	/* can do vlan */
+#define B43_BFL_AFTERBURNER		0x0200	/* supports Afterburner mode */
+#define B43_BFL_NOPCI			0x0400	/* leaves PCI floating */
+#define B43_BFL_FEM			0x0800	/* supports the Front End Module */
+#define B43_BFL_EXTLNA			0x1000	/* has an external LNA */
+#define B43_BFL_HGPA			0x2000	/* had high gain PA */
+#define B43_BFL_BTCMOD			0x4000	/* BFL_BTCOEXIST is given in alternate GPIOs */
+#define B43_BFL_ALTIQ			0x8000	/* alternate I/Q settings */
+
+/* GPIO register offset, in both ChipCommon and PCI core. */
+#define B43_GPIO_CONTROL		0x6c
+
+/* SHM Routing */
+enum {
+	B43_SHM_UCODE,		/* Microcode memory */
+	B43_SHM_SHARED,		/* Shared memory */
+	B43_SHM_SCRATCH,	/* Scratch memory */
+	B43_SHM_HW,		/* Internal hardware register */
+	B43_SHM_RCMTA,		/* Receive match transmitter address (rev >= 5 only) */
+};
+/* SHM Routing modifiers */
+#define B43_SHM_AUTOINC_R		0x0200	/* Auto-increment address on read */
+#define B43_SHM_AUTOINC_W		0x0100	/* Auto-increment address on write */
+#define B43_SHM_AUTOINC_RW		(B43_SHM_AUTOINC_R | \
+					 B43_SHM_AUTOINC_W)
+
+/* Misc SHM_SHARED offsets */
+#define B43_SHM_SH_WLCOREREV		0x0016	/* 802.11 core revision */
+#define B43_SHM_SH_PCTLWDPOS		0x0008
+#define B43_SHM_SH_RXPADOFF		0x0034	/* RX Padding data offset (PIO only) */
+#define B43_SHM_SH_PHYVER		0x0050	/* PHY version */
+#define B43_SHM_SH_PHYTYPE		0x0052	/* PHY type */
+#define B43_SHM_SH_ANTSWAP		0x005C	/* Antenna swap threshold */
+#define B43_SHM_SH_HOSTFLO		0x005E	/* Hostflags for ucode options (low) */
+#define B43_SHM_SH_HOSTFHI		0x0060	/* Hostflags for ucode options (high) */
+#define B43_SHM_SH_RFATT		0x0064	/* Current radio attenuation value */
+#define B43_SHM_SH_RADAR		0x0066	/* Radar register */
+#define B43_SHM_SH_PHYTXNOI		0x006E	/* PHY noise directly after TX (lower 8bit only) */
+#define B43_SHM_SH_RFRXSP1		0x0072	/* RF RX SP Register 1 */
+#define B43_SHM_SH_CHAN			0x00A0	/* Current channel (low 8bit only) */
+#define  B43_SHM_SH_CHAN_5GHZ		0x0100	/* Bit set, if 5Ghz channel */
+#define B43_SHM_SH_BCMCFIFOID		0x0108	/* Last posted cookie to the bcast/mcast FIFO */
+/* SHM_SHARED TX FIFO variables */
+#define B43_SHM_SH_SIZE01		0x0098	/* TX FIFO size for FIFO 0 (low) and 1 (high) */
+#define B43_SHM_SH_SIZE23		0x009A	/* TX FIFO size for FIFO 2 and 3 */
+#define B43_SHM_SH_SIZE45		0x009C	/* TX FIFO size for FIFO 4 and 5 */
+#define B43_SHM_SH_SIZE67		0x009E	/* TX FIFO size for FIFO 6 and 7 */
+/* SHM_SHARED background noise */
+#define B43_SHM_SH_JSSI0		0x0088	/* Measure JSSI 0 */
+#define B43_SHM_SH_JSSI1		0x008A	/* Measure JSSI 1 */
+#define B43_SHM_SH_JSSIAUX		0x008C	/* Measure JSSI AUX */
+/* SHM_SHARED crypto engine */
+#define B43_SHM_SH_DEFAULTIV		0x003C	/* Default IV location */
+#define B43_SHM_SH_NRRXTRANS		0x003E	/* # of soft RX transmitter addresses (max 8) */
+#define B43_SHM_SH_KTP			0x0056	/* Key table pointer */
+#define B43_SHM_SH_TKIPTSCTTAK		0x0318
+#define B43_SHM_SH_KEYIDXBLOCK		0x05D4	/* Key index/algorithm block (v4 firmware) */
+#define B43_SHM_SH_PSM			0x05F4	/* PSM transmitter address match block (rev < 5) */
+/* SHM_SHARED WME variables */
+#define B43_SHM_SH_EDCFSTAT		0x000E	/* EDCF status */
+#define B43_SHM_SH_TXFCUR		0x0030	/* TXF current index */
+#define B43_SHM_SH_EDCFQ		0x0240	/* EDCF Q info */
+/* SHM_SHARED powersave mode related */
+#define B43_SHM_SH_SLOTT		0x0010	/* Slot time */
+#define B43_SHM_SH_DTIMPER		0x0012	/* DTIM period */
+#define B43_SHM_SH_NOSLPZNATDTIM	0x004C	/* NOSLPZNAT DTIM */
+/* SHM_SHARED beacon variables */
+#define B43_SHM_SH_BTL0			0x0018	/* Beacon template length 0 */
+#define B43_SHM_SH_BTL1			0x001A	/* Beacon template length 1 */
+#define B43_SHM_SH_BTSFOFF		0x001C	/* Beacon TSF offset */
+#define B43_SHM_SH_TIMBPOS		0x001E	/* TIM B position in beacon */
+#define B43_SHM_SH_SFFBLIM		0x0044	/* Short frame fallback retry limit */
+#define B43_SHM_SH_LFFBLIM		0x0046	/* Long frame fallback retry limit */
+#define B43_SHM_SH_BEACPHYCTL		0x0054	/* Beacon PHY TX control word (see PHY TX control) */
+/* SHM_SHARED ACK/CTS control */
+#define B43_SHM_SH_ACKCTSPHYCTL		0x0022	/* ACK/CTS PHY control word (see PHY TX control) */
+/* SHM_SHARED probe response variables */
+#define B43_SHM_SH_PRSSID		0x0160	/* Probe Response SSID */
+#define B43_SHM_SH_PRSSIDLEN		0x0048	/* Probe Response SSID length */
+#define B43_SHM_SH_PRTLEN		0x004A	/* Probe Response template length */
+#define B43_SHM_SH_PRMAXTIME		0x0074	/* Probe Response max time */
+#define B43_SHM_SH_PRPHYCTL		0x0188	/* Probe Response PHY TX control word */
+/* SHM_SHARED rate tables */
+#define B43_SHM_SH_OFDMDIRECT		0x01C0	/* Pointer to OFDM direct map */
+#define B43_SHM_SH_OFDMBASIC		0x01E0	/* Pointer to OFDM basic rate map */
+#define B43_SHM_SH_CCKDIRECT		0x0200	/* Pointer to CCK direct map */
+#define B43_SHM_SH_CCKBASIC		0x0220	/* Pointer to CCK basic rate map */
+/* SHM_SHARED microcode soft registers */
+#define B43_SHM_SH_UCODEREV		0x0000	/* Microcode revision */
+#define B43_SHM_SH_UCODEPATCH		0x0002	/* Microcode patchlevel */
+#define B43_SHM_SH_UCODEDATE		0x0004	/* Microcode date */
+#define B43_SHM_SH_UCODETIME		0x0006	/* Microcode time */
+#define B43_SHM_SH_UCODESTAT		0x0040	/* Microcode debug status code */
+#define  B43_SHM_SH_UCODESTAT_INVALID	0
+#define  B43_SHM_SH_UCODESTAT_INIT	1
+#define  B43_SHM_SH_UCODESTAT_ACTIVE	2
+#define  B43_SHM_SH_UCODESTAT_SUSP	3	/* suspended */
+#define  B43_SHM_SH_UCODESTAT_SLEEP	4	/* asleep (PS) */
+#define B43_SHM_SH_MAXBFRAMES		0x0080	/* Maximum number of frames in a burst */
+#define B43_SHM_SH_SPUWKUP		0x0094	/* pre-wakeup for synth PU in us */
+#define B43_SHM_SH_PRETBTT		0x0096	/* pre-TBTT in us */
+
+/* SHM_SCRATCH offsets */
+#define B43_SHM_SC_MINCONT		0x0003	/* Minimum contention window */
+#define B43_SHM_SC_MAXCONT		0x0004	/* Maximum contention window */
+#define B43_SHM_SC_CURCONT		0x0005	/* Current contention window */
+#define B43_SHM_SC_SRLIMIT		0x0006	/* Short retry count limit */
+#define B43_SHM_SC_LRLIMIT		0x0007	/* Long retry count limit */
+#define B43_SHM_SC_DTIMC		0x0008	/* Current DTIM count */
+#define B43_SHM_SC_BTL0LEN		0x0015	/* Beacon 0 template length */
+#define B43_SHM_SC_BTL1LEN		0x0016	/* Beacon 1 template length */
+#define B43_SHM_SC_SCFB			0x0017	/* Short frame transmit count threshold for rate fallback */
+#define B43_SHM_SC_LCFB			0x0018	/* Long frame transmit count threshold for rate fallback */
+
+/* Hardware Radio Enable masks */
+#define B43_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16)
+#define B43_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
+
+/* HostFlags. See b43_hf_read/write() */
+#define B43_HF_ANTDIVHELP		0x00000001	/* ucode antenna div helper */
+#define B43_HF_SYMW			0x00000002	/* G-PHY SYM workaround */
+#define B43_HF_RXPULLW			0x00000004	/* RX pullup workaround */
+#define B43_HF_CCKBOOST			0x00000008	/* 4dB CCK power boost (exclusive with OFDM boost) */
+#define B43_HF_BTCOEX			0x00000010	/* Bluetooth coexistance */
+#define B43_HF_GDCW			0x00000020	/* G-PHY DV canceller filter bw workaround */
+#define B43_HF_OFDMPABOOST		0x00000040	/* Enable PA gain boost for OFDM */
+#define B43_HF_ACPR			0x00000080	/* Disable for Japan, channel 14 */
+#define B43_HF_EDCF			0x00000100	/* on if WME and MAC suspended */
+#define B43_HF_TSSIRPSMW		0x00000200	/* TSSI reset PSM ucode workaround */
+#define B43_HF_DSCRQ			0x00000400	/* Disable slow clock request in ucode */
+#define B43_HF_ACIW			0x00000800	/* ACI workaround: shift bits by 2 on PHY CRS */
+#define B43_HF_2060W			0x00001000	/* 2060 radio workaround */
+#define B43_HF_RADARW			0x00002000	/* Radar workaround */
+#define B43_HF_USEDEFKEYS		0x00004000	/* Enable use of default keys */
+#define B43_HF_BT4PRIOCOEX		0x00010000	/* Bluetooth 2-priority coexistance */
+#define B43_HF_FWKUP			0x00020000	/* Fast wake-up ucode */
+#define B43_HF_VCORECALC		0x00040000	/* Force VCO recalculation when powering up synthpu */
+#define B43_HF_PCISCW			0x00080000	/* PCI slow clock workaround */
+#define B43_HF_4318TSSI			0x00200000	/* 4318 TSSI */
+#define B43_HF_FBCMCFIFO		0x00400000	/* Flush bcast/mcast FIFO immediately */
+#define B43_HF_HWPCTL			0x00800000	/* Enable hardwarre power control */
+#define B43_HF_BTCOEXALT		0x01000000	/* Bluetooth coexistance in alternate pins */
+#define B43_HF_TXBTCHECK		0x02000000	/* Bluetooth check during transmission */
+#define B43_HF_SKCFPUP			0x04000000	/* Skip CFP update */
+
+/* MacFilter offsets. */
+#define B43_MACFILTER_SELF		0x0000
+#define B43_MACFILTER_BSSID		0x0003
+
+/* PowerControl */
+#define B43_PCTL_IN			0xB0
+#define B43_PCTL_OUT			0xB4
+#define B43_PCTL_OUTENABLE		0xB8
+#define B43_PCTL_XTAL_POWERUP		0x40
+#define B43_PCTL_PLL_POWERDOWN		0x80
+
+/* PowerControl Clock Modes */
+#define B43_PCTL_CLK_FAST		0x00
+#define B43_PCTL_CLK_SLOW		0x01
+#define B43_PCTL_CLK_DYNAMIC		0x02
+
+#define B43_PCTL_FORCE_SLOW		0x0800
+#define B43_PCTL_FORCE_PLL		0x1000
+#define B43_PCTL_DYN_XTAL		0x2000
+
+/* PHYVersioning */
+#define B43_PHYTYPE_A			0x00
+#define B43_PHYTYPE_B			0x01
+#define B43_PHYTYPE_G			0x02
+
+/* PHYRegisters */
+#define B43_PHY_ILT_A_CTRL		0x0072
+#define B43_PHY_ILT_A_DATA1		0x0073
+#define B43_PHY_ILT_A_DATA2		0x0074
+#define B43_PHY_G_LO_CONTROL		0x0810
+#define B43_PHY_ILT_G_CTRL		0x0472
+#define B43_PHY_ILT_G_DATA1		0x0473
+#define B43_PHY_ILT_G_DATA2		0x0474
+#define B43_PHY_A_PCTL			0x007B
+#define B43_PHY_G_PCTL			0x0029
+#define B43_PHY_A_CRS			0x0029
+#define B43_PHY_RADIO_BITFIELD		0x0401
+#define B43_PHY_G_CRS			0x0429
+#define B43_PHY_NRSSILT_CTRL		0x0803
+#define B43_PHY_NRSSILT_DATA		0x0804
+
+/* RadioRegisters */
+#define B43_RADIOCTL_ID			0x01
+
+/* MAC Control bitfield */
+#define B43_MACCTL_ENABLED		0x00000001	/* MAC Enabled */
+#define B43_MACCTL_PSM_RUN		0x00000002	/* Run Microcode */
+#define B43_MACCTL_PSM_JMP0		0x00000004	/* Microcode jump to 0 */
+#define B43_MACCTL_SHM_ENABLED		0x00000100	/* SHM Enabled */
+#define B43_MACCTL_SHM_UPPER		0x00000200	/* SHM Upper */
+#define B43_MACCTL_IHR_ENABLED		0x00000400	/* IHR Region Enabled */
+#define B43_MACCTL_PSM_DBG		0x00002000	/* Microcode debugging enabled */
+#define B43_MACCTL_GPOUTSMSK		0x0000C000	/* GPOUT Select Mask */
+#define B43_MACCTL_BE			0x00010000	/* Big Endian mode */
+#define B43_MACCTL_INFRA		0x00020000	/* Infrastructure mode */
+#define B43_MACCTL_AP			0x00040000	/* AccessPoint mode */
+#define B43_MACCTL_RADIOLOCK		0x00080000	/* Radio lock */
+#define B43_MACCTL_BEACPROMISC		0x00100000	/* Beacon Promiscuous */
+#define B43_MACCTL_KEEP_BADPLCP		0x00200000	/* Keep frames with bad PLCP */
+#define B43_MACCTL_KEEP_CTL		0x00400000	/* Keep control frames */
+#define B43_MACCTL_KEEP_BAD		0x00800000	/* Keep bad frames (FCS) */
+#define B43_MACCTL_PROMISC		0x01000000	/* Promiscuous mode */
+#define B43_MACCTL_HWPS			0x02000000	/* Hardware Power Saving */
+#define B43_MACCTL_AWAKE		0x04000000	/* Device is awake */
+#define B43_MACCTL_CLOSEDNET		0x08000000	/* Closed net (no SSID bcast) */
+#define B43_MACCTL_TBTTHOLD		0x10000000	/* TBTT Hold */
+#define B43_MACCTL_DISCTXSTAT		0x20000000	/* Discard TX status */
+#define B43_MACCTL_DISCPMQ		0x40000000	/* Discard Power Management Queue */
+#define B43_MACCTL_GMODE		0x80000000	/* G Mode */
+
+/* 802.11 core specific TM State Low flags */
+#define B43_TMSLOW_GMODE		0x20000000	/* G Mode Enable */
+#define B43_TMSLOW_PLLREFSEL		0x00200000	/* PLL Frequency Reference Select */
+#define B43_TMSLOW_MACPHYCLKEN		0x00100000	/* MAC PHY Clock Control Enable (rev >= 5) */
+#define B43_TMSLOW_PHYRESET		0x00080000	/* PHY Reset */
+#define B43_TMSLOW_PHYCLKEN		0x00040000	/* PHY Clock Enable */
+
+/* 802.11 core specific TM State High flags */
+#define B43_TMSHIGH_FCLOCK		0x00040000	/* Fast Clock Available (rev >= 5) */
+#define B43_TMSHIGH_APHY		0x00020000	/* A-PHY available (rev >= 5) */
+#define B43_TMSHIGH_GPHY		0x00010000	/* G-PHY available (rev >= 5) */
+
+/* Generic-Interrupt reasons. */
+#define B43_IRQ_MAC_SUSPENDED		0x00000001
+#define B43_IRQ_BEACON			0x00000002
+#define B43_IRQ_TBTT_INDI		0x00000004
+#define B43_IRQ_BEACON_TX_OK		0x00000008
+#define B43_IRQ_BEACON_CANCEL		0x00000010
+#define B43_IRQ_ATIM_END		0x00000020
+#define B43_IRQ_PMQ			0x00000040
+#define B43_IRQ_PIO_WORKAROUND		0x00000100
+#define B43_IRQ_MAC_TXERR		0x00000200
+#define B43_IRQ_PHY_TXERR		0x00000800
+#define B43_IRQ_PMEVENT			0x00001000
+#define B43_IRQ_TIMER0			0x00002000
+#define B43_IRQ_TIMER1			0x00004000
+#define B43_IRQ_DMA			0x00008000
+#define B43_IRQ_TXFIFO_FLUSH_OK		0x00010000
+#define B43_IRQ_CCA_MEASURE_OK		0x00020000
+#define B43_IRQ_NOISESAMPLE_OK		0x00040000
+#define B43_IRQ_UCODE_DEBUG		0x08000000
+#define B43_IRQ_RFKILL			0x10000000
+#define B43_IRQ_TX_OK			0x20000000
+#define B43_IRQ_PHY_G_CHANGED		0x40000000
+#define B43_IRQ_TIMEOUT			0x80000000
+
+#define B43_IRQ_ALL			0xFFFFFFFF
+#define B43_IRQ_MASKTEMPLATE		(B43_IRQ_MAC_SUSPENDED | \
+					 B43_IRQ_BEACON | \
+					 B43_IRQ_TBTT_INDI | \
+					 B43_IRQ_ATIM_END | \
+					 B43_IRQ_PMQ | \
+					 B43_IRQ_MAC_TXERR | \
+					 B43_IRQ_PHY_TXERR | \
+					 B43_IRQ_DMA | \
+					 B43_IRQ_TXFIFO_FLUSH_OK | \
+					 B43_IRQ_NOISESAMPLE_OK | \
+					 B43_IRQ_UCODE_DEBUG | \
+					 B43_IRQ_RFKILL | \
+					 B43_IRQ_TX_OK)
+
+/* Device specific rate values.
+ * The actual values defined here are (rate_in_mbps * 2).
+ * Some code depends on this. Don't change it. */
+#define B43_CCK_RATE_1MB		0x02
+#define B43_CCK_RATE_2MB		0x04
+#define B43_CCK_RATE_5MB		0x0B
+#define B43_CCK_RATE_11MB		0x16
+#define B43_OFDM_RATE_6MB		0x0C
+#define B43_OFDM_RATE_9MB		0x12
+#define B43_OFDM_RATE_12MB		0x18
+#define B43_OFDM_RATE_18MB		0x24
+#define B43_OFDM_RATE_24MB		0x30
+#define B43_OFDM_RATE_36MB		0x48
+#define B43_OFDM_RATE_48MB		0x60
+#define B43_OFDM_RATE_54MB		0x6C
+/* Convert a b43 rate value to a rate in 100kbps */
+#define B43_RATE_TO_BASE100KBPS(rate)	(((rate) * 10) / 2)
+
+#define B43_DEFAULT_SHORT_RETRY_LIMIT	7
+#define B43_DEFAULT_LONG_RETRY_LIMIT	4
+
+/* Max size of a security key */
+#define B43_SEC_KEYSIZE			16
+/* Security algorithms. */
+enum {
+	B43_SEC_ALGO_NONE = 0,	/* unencrypted, as of TX header. */
+	B43_SEC_ALGO_WEP40,
+	B43_SEC_ALGO_TKIP,
+	B43_SEC_ALGO_AES,
+	B43_SEC_ALGO_WEP104,
+	B43_SEC_ALGO_AES_LEGACY,
+};
+
+struct b43_dmaring;
+struct b43_pioqueue;
+
+/* The firmware file header */
+#define B43_FW_TYPE_UCODE	'u'
+#define B43_FW_TYPE_PCM		'p'
+#define B43_FW_TYPE_IV		'i'
+struct b43_fw_header {
+	/* File type */
+	u8 type;
+	/* File format version */
+	u8 ver;
+	u8 __padding[2];
+	/* Size of the data. For ucode and PCM this is in bytes.
+	 * For IV this is number-of-ivs. */
+	__be32 size;
+} __attribute__((__packed__));
+
+/* Initial Value file format */
+#define B43_IV_OFFSET_MASK	0x7FFF
+#define B43_IV_32BIT		0x8000
+struct b43_iv {
+	__be16 offset_size;
+	union {
+		__be16 d16;
+		__be32 d32;
+	} data __attribute__((__packed__));
+} __attribute__((__packed__));
+
+
+#define B43_PHYMODE(phytype)		(1 << (phytype))
+#define B43_PHYMODE_A			B43_PHYMODE(B43_PHYTYPE_A)
+#define B43_PHYMODE_B			B43_PHYMODE(B43_PHYTYPE_B)
+#define B43_PHYMODE_G			B43_PHYMODE(B43_PHYTYPE_G)
+
+struct b43_phy {
+	/* Possible PHYMODEs on this PHY */
+	u8 possible_phymodes;
+	/* GMODE bit enabled? */
+	bool gmode;
+	/* Possible ieee80211 subsystem hwmodes for this PHY.
+	 * Which mode is selected, depends on thr GMODE enabled bit */
+#define B43_MAX_PHYHWMODES	2
+	struct ieee80211_hw_mode hwmodes[B43_MAX_PHYHWMODES];
+
+	/* Analog Type */
+	u8 analog;
+	/* B43_PHYTYPE_ */
+	u8 type;
+	/* PHY revision number. */
+	u8 rev;
+
+	/* Radio versioning */
+	u16 radio_manuf;	/* Radio manufacturer */
+	u16 radio_ver;		/* Radio version */
+	u8 radio_rev;		/* Radio revision */
+
+	bool locked;		/* Only used in b43_phy_{un}lock() */
+	bool dyn_tssi_tbl;	/* tssi2dbm is kmalloc()ed. */
+
+	/* ACI (adjacent channel interference) flags. */
+	bool aci_enable;
+	bool aci_wlan_automatic;
+	bool aci_hw_rssi;
+
+	/* Radio switched on/off */
+	bool radio_on;
+	struct {
+		/* Values saved when turning the radio off.
+		 * They are needed when turning it on again. */
+		bool valid;
+		u16 rfover;
+		u16 rfoverval;
+	} radio_off_context;
+
+	u16 minlowsig[2];
+	u16 minlowsigpos[2];
+
+	/* TSSI to dBm table in use */
+	const s8 *tssi2dbm;
+	/* Target idle TSSI */
+	int tgt_idle_tssi;
+	/* Current idle TSSI */
+	int cur_idle_tssi;
+
+	/* LocalOscillator control values. */
+	struct b43_txpower_lo_control *lo_control;
+	/* Values from b43_calc_loopback_gain() */
+	s16 max_lb_gain;	/* Maximum Loopback gain in hdB */
+	s16 trsw_rx_gain;	/* TRSW RX gain in hdB */
+	s16 lna_lod_gain;	/* LNA lod */
+	s16 lna_gain;		/* LNA */
+	s16 pga_gain;		/* PGA */
+
+	/* PHY lock for core.rev < 3
+	 * This lock is only used by b43_phy_{un}lock()
+	 */
+	spinlock_t lock;
+
+	/* Desired TX power level (in dBm).
+	 * This is set by the user and adjusted in b43_phy_xmitpower(). */
+	u8 power_level;
+	/* A-PHY TX Power control value. */
+	u16 txpwr_offset;
+
+	/* Current TX power level attenuation control values */
+	struct b43_bbatt bbatt;
+	struct b43_rfatt rfatt;
+	u8 tx_control;		/* B43_TXCTL_XXX */
+#ifdef CONFIG_B43_DEBUG
+	bool manual_txpower_control;	/* Manual TX-power control enabled? */
+#endif
+	/* Hardware Power Control enabled? */
+	bool hardware_power_control;
+
+	/* Current Interference Mitigation mode */
+	int interfmode;
+	/* Stack of saved values from the Interference Mitigation code.
+	 * Each value in the stack is layed out as follows:
+	 * bit 0-11:  offset
+	 * bit 12-15: register ID
+	 * bit 16-32: value
+	 * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
+	 */
+#define B43_INTERFSTACK_SIZE	26
+	u32 interfstack[B43_INTERFSTACK_SIZE];	//FIXME: use a data structure
+
+	/* Saved values from the NRSSI Slope calculation */
+	s16 nrssi[2];
+	s32 nrssislope;
+	/* In memory nrssi lookup table. */
+	s8 nrssi_lt[64];
+
+	/* current channel */
+	u8 channel;
+
+	u16 lofcal;
+
+	u16 initval;		//FIXME rename?
+};
+
+/* Data structures for DMA transmission, per 80211 core. */
+struct b43_dma {
+	struct b43_dmaring *tx_ring0;
+	struct b43_dmaring *tx_ring1;
+	struct b43_dmaring *tx_ring2;
+	struct b43_dmaring *tx_ring3;
+	struct b43_dmaring *tx_ring4;
+	struct b43_dmaring *tx_ring5;
+
+	struct b43_dmaring *rx_ring0;
+	struct b43_dmaring *rx_ring3;	/* only available on core.rev < 5 */
+};
+
+/* Data structures for PIO transmission, per 80211 core. */
+struct b43_pio {
+	struct b43_pioqueue *queue0;
+	struct b43_pioqueue *queue1;
+	struct b43_pioqueue *queue2;
+	struct b43_pioqueue *queue3;
+};
+
+/* Context information for a noise calculation (Link Quality). */
+struct b43_noise_calculation {
+	u8 channel_at_start;
+	bool calculation_running;
+	u8 nr_samples;
+	s8 samples[8][4];
+};
+
+struct b43_stats {
+	u8 link_noise;
+	/* Store the last TX/RX times here for updating the leds. */
+	unsigned long last_tx;
+	unsigned long last_rx;
+};
+
+struct b43_key {
+	/* If keyconf is NULL, this key is disabled.
+	 * keyconf is a cookie. Don't derefenrence it outside of the set_key
+	 * path, because b43 doesn't own it. */
+	struct ieee80211_key_conf *keyconf;
+	u8 algorithm;
+};
+
+struct b43_wldev;
+
+/* Data structure for the WLAN parts (802.11 cores) of the b43 chip. */
+struct b43_wl {
+	/* Pointer to the active wireless device on this chip */
+	struct b43_wldev *current_dev;
+	/* Pointer to the ieee80211 hardware data structure */
+	struct ieee80211_hw *hw;
+
+	spinlock_t irq_lock;
+	struct mutex mutex;
+	spinlock_t leds_lock;
+
+	/* We can only have one operating interface (802.11 core)
+	 * at a time. General information about this interface follows.
+	 */
+
+	/* Opaque ID of the operating interface from the ieee80211
+	 * subsystem. Do not modify.
+	 */
+	int if_id;
+	/* The MAC address of the operating interface. */
+	u8 mac_addr[ETH_ALEN];
+	/* Current BSSID */
+	u8 bssid[ETH_ALEN];
+	/* Interface type. (IEEE80211_IF_TYPE_XXX) */
+	int if_type;
+	/* Is the card operating in AP, STA or IBSS mode? */
+	bool operating;
+	/* filter flags */
+	unsigned int filter_flags;
+	/* Stats about the wireless interface */
+	struct ieee80211_low_level_stats ieee_stats;
+
+	struct hwrng rng;
+	u8 rng_initialized;
+	char rng_name[30 + 1];
+
+	/* The RF-kill button */
+	struct b43_rfkill rfkill;
+
+	/* List of all wireless devices on this chip */
+	struct list_head devlist;
+	u8 nr_devs;
+};
+
+/* Pointers to the firmware data and meta information about it. */
+struct b43_firmware {
+	/* Microcode */
+	const struct firmware *ucode;
+	/* PCM code */
+	const struct firmware *pcm;
+	/* Initial MMIO values for the firmware */
+	const struct firmware *initvals;
+	/* Initial MMIO values for the firmware, band-specific */
+	const struct firmware *initvals_band;
+	/* Firmware revision */
+	u16 rev;
+	/* Firmware patchlevel */
+	u16 patch;
+};
+
+/* Device (802.11 core) initialization status. */
+enum {
+	B43_STAT_UNINIT = 0,	/* Uninitialized. */
+	B43_STAT_INITIALIZED = 1,	/* Initialized, but not started, yet. */
+	B43_STAT_STARTED = 2,	/* Up and running. */
+};
+#define b43_status(wldev)		atomic_read(&(wldev)->__init_status)
+#define b43_set_status(wldev, stat)	do {			\
+		atomic_set(&(wldev)->__init_status, (stat));	\
+		smp_wmb();					\
+					} while (0)
+
+/* XXX---   HOW LOCKING WORKS IN B43   ---XXX
+ *
+ * You should always acquire both, wl->mutex and wl->irq_lock unless:
+ * - You don't need to acquire wl->irq_lock, if the interface is stopped.
+ * - You don't need to acquire wl->mutex in the IRQ handler, IRQ tasklet
+ *   and packet TX path (and _ONLY_ there.)
+ */
+
+/* Data structure for one wireless device (802.11 core) */
+struct b43_wldev {
+	struct ssb_device *dev;
+	struct b43_wl *wl;
+
+	/* The device initialization status.
+	 * Use b43_status() to query. */
+	atomic_t __init_status;
+	/* Saved init status for handling suspend. */
+	int suspend_init_status;
+
+	bool __using_pio;	/* Internal, use b43_using_pio(). */
+	bool bad_frames_preempt;	/* Use "Bad Frames Preemption" (default off) */
+	bool reg124_set_0x4;	/* Some variable to keep track of IRQ stuff. */
+	bool short_preamble;	/* TRUE, if short preamble is enabled. */
+	bool short_slot;	/* TRUE, if short slot timing is enabled. */
+	bool radio_hw_enable;	/* saved state of radio hardware enabled state */
+
+	/* PHY/Radio device. */
+	struct b43_phy phy;
+	union {
+		/* DMA engines. */
+		struct b43_dma dma;
+		/* PIO engines. */
+		struct b43_pio pio;
+	};
+
+	/* Various statistics about the physical device. */
+	struct b43_stats stats;
+
+	/* The device LEDs. */
+	struct b43_led led_tx;
+	struct b43_led led_rx;
+	struct b43_led led_assoc;
+	struct b43_led led_radio;
+
+	/* Reason code of the last interrupt. */
+	u32 irq_reason;
+	u32 dma_reason[6];
+	/* saved irq enable/disable state bitfield. */
+	u32 irq_savedstate;
+	/* Link Quality calculation context. */
+	struct b43_noise_calculation noisecalc;
+	/* if > 0 MAC is suspended. if == 0 MAC is enabled. */
+	int mac_suspended;
+
+	/* Interrupt Service Routine tasklet (bottom-half) */
+	struct tasklet_struct isr_tasklet;
+
+	/* Periodic tasks */
+	struct delayed_work periodic_work;
+	unsigned int periodic_state;
+
+	struct work_struct restart_work;
+
+	/* encryption/decryption */
+	u16 ktp;		/* Key table pointer */
+	u8 max_nr_keys;
+	struct b43_key key[58];
+
+	/* Cached beacon template while uploading the template. */
+	struct sk_buff *cached_beacon;
+
+	/* Firmware data */
+	struct b43_firmware fw;
+
+	/* Devicelist in struct b43_wl (all 802.11 cores) */
+	struct list_head list;
+
+	/* Debugging stuff follows. */
+#ifdef CONFIG_B43_DEBUG
+	struct b43_dfsentry *dfsentry;
+#endif
+};
+
+static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw)
+{
+	return hw->priv;
+}
+
+/* Helper function, which returns a boolean.
+ * TRUE, if PIO is used; FALSE, if DMA is used.
+ */
+#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO)
+static inline int b43_using_pio(struct b43_wldev *dev)
+{
+	return dev->__using_pio;
+}
+#elif defined(CONFIG_B43_DMA)
+static inline int b43_using_pio(struct b43_wldev *dev)
+{
+	return 0;
+}
+#elif defined(CONFIG_B43_PIO)
+static inline int b43_using_pio(struct b43_wldev *dev)
+{
+	return 1;
+}
+#else
+# error "Using neither DMA nor PIO? Confused..."
+#endif
+
+static inline struct b43_wldev *dev_to_b43_wldev(struct device *dev)
+{
+	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+	return ssb_get_drvdata(ssb_dev);
+}
+
+/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */
+static inline int b43_is_mode(struct b43_wl *wl, int type)
+{
+	return (wl->operating && wl->if_type == type);
+}
+
+static inline u16 b43_read16(struct b43_wldev *dev, u16 offset)
+{
+	return ssb_read16(dev->dev, offset);
+}
+
+static inline void b43_write16(struct b43_wldev *dev, u16 offset, u16 value)
+{
+	ssb_write16(dev->dev, offset, value);
+}
+
+static inline u32 b43_read32(struct b43_wldev *dev, u16 offset)
+{
+	return ssb_read32(dev->dev, offset);
+}
+
+static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value)
+{
+	ssb_write32(dev->dev, offset, value);
+}
+
+/* Message printing */
+void b43info(struct b43_wl *wl, const char *fmt, ...)
+    __attribute__ ((format(printf, 2, 3)));
+void b43err(struct b43_wl *wl, const char *fmt, ...)
+    __attribute__ ((format(printf, 2, 3)));
+void b43warn(struct b43_wl *wl, const char *fmt, ...)
+    __attribute__ ((format(printf, 2, 3)));
+#if B43_DEBUG
+void b43dbg(struct b43_wl *wl, const char *fmt, ...)
+    __attribute__ ((format(printf, 2, 3)));
+#else /* DEBUG */
+# define b43dbg(wl, fmt...) do { /* nothing */ } while (0)
+#endif /* DEBUG */
+
+/* A WARN_ON variant that vanishes when b43 debugging is disabled.
+ * This _also_ evaluates the arg with debugging disabled. */
+#if B43_DEBUG
+# define B43_WARN_ON(x)	WARN_ON(x)
+#else
+static inline bool __b43_warn_on_dummy(bool x) { return x; }
+# define B43_WARN_ON(x)	__b43_warn_on_dummy(unlikely(!!(x)))
+#endif
+
+/** Limit a value between two limits */
+#ifdef limit_value
+# undef limit_value
+#endif
+#define limit_value(value, min, max)  \
+	({						\
+		typeof(value) __value = (value);	\
+		typeof(value) __min = (min);		\
+		typeof(value) __max = (max);		\
+		if (__value < __min)			\
+			__value = __min;		\
+		else if (__value > __max)		\
+			__value = __max;		\
+		__value;				\
+	})
+
+/* Convert an integer to a Q5.2 value */
+#define INT_TO_Q52(i)	((i) << 2)
+/* Convert a Q5.2 value to an integer (precision loss!) */
+#define Q52_TO_INT(q52)	((q52) >> 2)
+/* Macros for printing a value in Q5.2 format */
+#define Q52_FMT		"%u.%u"
+#define Q52_ARG(q52)	Q52_TO_INT(q52), ((((q52) & 0x3) * 100) / 4)
+
+#endif /* B43_H_ */
diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c
new file mode 100644
index 0000000..734e70e
--- /dev/null
+++ b/drivers/net/wireless/b43/debugfs.c
@@ -0,0 +1,656 @@
+/*
+
+  Broadcom B43 wireless driver
+
+  debugfs driver debugging code
+
+  Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+
+#include "b43.h"
+#include "main.h"
+#include "debugfs.h"
+#include "dma.h"
+#include "pio.h"
+#include "xmit.h"
+
+
+/* The root directory. */
+static struct dentry *rootdir;
+
+struct b43_debugfs_fops {
+	ssize_t (*read)(struct b43_wldev *dev, char *buf, size_t bufsize);
+	int (*write)(struct b43_wldev *dev, const char *buf, size_t count);
+	struct file_operations fops;
+	/* Offset of struct b43_dfs_file in struct b43_dfsentry */
+	size_t file_struct_offset;
+	/* Take wl->irq_lock before calling read/write? */
+	bool take_irqlock;
+};
+
+static inline
+struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev,
+				       const struct b43_debugfs_fops *dfops)
+{
+	void *p;
+
+	p = dev->dfsentry;
+	p += dfops->file_struct_offset;
+
+	return p;
+}
+
+
+#define fappend(fmt, x...)	\
+	do {							\
+		if (bufsize - count)				\
+			count += snprintf(buf + count,		\
+					  bufsize - count,	\
+					  fmt , ##x);		\
+		else						\
+			printk(KERN_ERR "b43: fappend overflow\n"); \
+	} while (0)
+
+
+/* wl->irq_lock is locked */
+static ssize_t tsf_read_file(struct b43_wldev *dev,
+			     char *buf, size_t bufsize)
+{
+	ssize_t count = 0;
+	u64 tsf;
+
+	b43_tsf_read(dev, &tsf);
+	fappend("0x%08x%08x\n",
+		(unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
+		(unsigned int)(tsf & 0xFFFFFFFFULL));
+
+	return count;
+}
+
+/* wl->irq_lock is locked */
+static int tsf_write_file(struct b43_wldev *dev,
+			  const char *buf, size_t count)
+{
+	u64 tsf;
+
+	if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1)
+		return -EINVAL;
+	b43_tsf_write(dev, tsf);
+
+	return 0;
+}
+
+/* wl->irq_lock is locked */
+static ssize_t ucode_regs_read_file(struct b43_wldev *dev,
+				    char *buf, size_t bufsize)
+{
+	ssize_t count = 0;
+	int i;
+
+	for (i = 0; i < 64; i++) {
+		fappend("r%d = 0x%04x\n", i,
+			b43_shm_read16(dev, B43_SHM_SCRATCH, i));
+	}
+
+	return count;
+}
+
+/* wl->irq_lock is locked */
+static ssize_t shm_read_file(struct b43_wldev *dev,
+			     char *buf, size_t bufsize)
+{
+	ssize_t count = 0;
+	int i;
+	u16 tmp;
+	__le16 *le16buf = (__le16 *)buf;
+
+	for (i = 0; i < 0x1000; i++) {
+		if (bufsize <= 0)
+			break;
+		tmp = b43_shm_read16(dev, B43_SHM_SHARED, 2 * i);
+		le16buf[i] = cpu_to_le16(tmp);
+		count += sizeof(tmp);
+		bufsize -= sizeof(tmp);
+	}
+
+	return count;
+}
+
+static ssize_t txstat_read_file(struct b43_wldev *dev,
+				char *buf, size_t bufsize)
+{
+	struct b43_txstatus_log *log = &dev->dfsentry->txstatlog;
+	ssize_t count = 0;
+	unsigned long flags;
+	int i, idx;
+	struct b43_txstatus *stat;
+
+	spin_lock_irqsave(&log->lock, flags);
+	if (log->end < 0) {
+		fappend("Nothing transmitted, yet\n");
+		goto out_unlock;
+	}
+	fappend("b43 TX status reports:\n\n"
+		"index | cookie | seq | phy_stat | frame_count | "
+		"rts_count | supp_reason | pm_indicated | "
+		"intermediate | for_ampdu | acked\n" "---\n");
+	i = log->end + 1;
+	idx = 0;
+	while (1) {
+		if (i == B43_NR_LOGGED_TXSTATUS)
+			i = 0;
+		stat = &(log->log[i]);
+		if (stat->cookie) {
+			fappend("%03d | "
+				"0x%04X | 0x%04X | 0x%02X | "
+				"0x%X | 0x%X | "
+				"%u | %u | "
+				"%u | %u | %u\n",
+				idx,
+				stat->cookie, stat->seq, stat->phy_stat,
+				stat->frame_count, stat->rts_count,
+				stat->supp_reason, stat->pm_indicated,
+				stat->intermediate, stat->for_ampdu,
+				stat->acked);
+			idx++;
+		}
+		if (i == log->end)
+			break;
+		i++;
+	}
+out_unlock:
+	spin_unlock_irqrestore(&log->lock, flags);
+
+	return count;
+}
+
+static ssize_t txpower_g_read_file(struct b43_wldev *dev,
+				   char *buf, size_t bufsize)
+{
+	ssize_t count = 0;
+
+	if (dev->phy.type != B43_PHYTYPE_G) {
+		fappend("Device is not a G-PHY\n");
+		goto out;
+	}
+	fappend("Control:               %s\n", dev->phy.manual_txpower_control ?
+		"MANUAL" : "AUTOMATIC");
+	fappend("Baseband attenuation:  %u\n", dev->phy.bbatt.att);
+	fappend("Radio attenuation:     %u\n", dev->phy.rfatt.att);
+	fappend("TX Mixer Gain:         %s\n",
+		(dev->phy.tx_control & B43_TXCTL_TXMIX) ? "ON" : "OFF");
+	fappend("PA Gain 2dB:           %s\n",
+		(dev->phy.tx_control & B43_TXCTL_PA2DB) ? "ON" : "OFF");
+	fappend("PA Gain 3dB:           %s\n",
+		(dev->phy.tx_control & B43_TXCTL_PA3DB) ? "ON" : "OFF");
+	fappend("\n\n");
+	fappend("You can write to this file:\n");
+	fappend("Writing \"auto\" enables automatic txpower control.\n");
+	fappend
+	    ("Writing the attenuation values as \"bbatt rfatt txmix pa2db pa3db\" "
+	     "enables manual txpower control.\n");
+	fappend("Example: 5 4 0 0 1\n");
+	fappend("Enables manual control with Baseband attenuation 5, "
+		"Radio attenuation 4, No TX Mixer Gain, "
+		"No PA Gain 2dB, With PA Gain 3dB.\n");
+out:
+	return count;
+}
+
+static int txpower_g_write_file(struct b43_wldev *dev,
+				const char *buf, size_t count)
+{
+	unsigned long phy_flags;
+
+	if (dev->phy.type != B43_PHYTYPE_G)
+		return -ENODEV;
+	if ((count >= 4) && (memcmp(buf, "auto", 4) == 0)) {
+		/* Automatic control */
+		dev->phy.manual_txpower_control = 0;
+		b43_phy_xmitpower(dev);
+	} else {
+		int bbatt = 0, rfatt = 0, txmix = 0, pa2db = 0, pa3db = 0;
+		/* Manual control */
+		if (sscanf(buf, "%d %d %d %d %d", &bbatt, &rfatt,
+			   &txmix, &pa2db, &pa3db) != 5)
+			return -EINVAL;
+		b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
+		dev->phy.manual_txpower_control = 1;
+		dev->phy.bbatt.att = bbatt;
+		dev->phy.rfatt.att = rfatt;
+		dev->phy.tx_control = 0;
+		if (txmix)
+			dev->phy.tx_control |= B43_TXCTL_TXMIX;
+		if (pa2db)
+			dev->phy.tx_control |= B43_TXCTL_PA2DB;
+		if (pa3db)
+			dev->phy.tx_control |= B43_TXCTL_PA3DB;
+		b43_phy_lock(dev, phy_flags);
+		b43_radio_lock(dev);
+		b43_set_txpower_g(dev, &dev->phy.bbatt,
+				  &dev->phy.rfatt, dev->phy.tx_control);
+		b43_radio_unlock(dev);
+		b43_phy_unlock(dev, phy_flags);
+	}
+
+	return 0;
+}
+
+/* wl->irq_lock is locked */
+static int restart_write_file(struct b43_wldev *dev,
+			      const char *buf, size_t count)
+{
+	int err = 0;
+
+	if (count > 0 && buf[0] == '1') {
+		b43_controller_restart(dev, "manually restarted");
+	} else
+		err = -EINVAL;
+
+	return err;
+}
+
+static ssize_t append_lo_table(ssize_t count, char *buf, const size_t bufsize,
+			       struct b43_loctl table[B43_NR_BB][B43_NR_RF])
+{
+	unsigned int i, j;
+	struct b43_loctl *ctl;
+
+	for (i = 0; i < B43_NR_BB; i++) {
+		for (j = 0; j < B43_NR_RF; j++) {
+			ctl = &(table[i][j]);
+			fappend("(bbatt %2u, rfatt %2u)  ->  "
+				"(I %+3d, Q %+3d, Used: %d, Calibrated: %d)\n",
+				i, j, ctl->i, ctl->q,
+				ctl->used,
+				b43_loctl_is_calibrated(ctl));
+		}
+	}
+
+	return count;
+}
+
+static ssize_t loctls_read_file(struct b43_wldev *dev,
+				char *buf, size_t bufsize)
+{
+	ssize_t count = 0;
+	struct b43_txpower_lo_control *lo;
+	int i, err = 0;
+
+	if (dev->phy.type != B43_PHYTYPE_G) {
+		fappend("Device is not a G-PHY\n");
+		err = -ENODEV;
+		goto out;
+	}
+	lo = dev->phy.lo_control;
+	fappend("-- Local Oscillator calibration data --\n\n");
+	fappend("Measured: %d,  Rebuild: %d,  HW-power-control: %d\n",
+		lo->lo_measured,
+		lo->rebuild,
+		dev->phy.hardware_power_control);
+	fappend("TX Bias: 0x%02X,  TX Magn: 0x%02X\n",
+		lo->tx_bias, lo->tx_magn);
+	fappend("Power Vector: 0x%08X%08X\n",
+		(unsigned int)((lo->power_vector & 0xFFFFFFFF00000000ULL) >> 32),
+		(unsigned int)(lo->power_vector & 0x00000000FFFFFFFFULL));
+	fappend("\nControl table WITH PADMIX:\n");
+	count = append_lo_table(count, buf, bufsize, lo->with_padmix);
+	fappend("\nControl table WITHOUT PADMIX:\n");
+	count = append_lo_table(count, buf, bufsize, lo->no_padmix);
+	fappend("\nUsed RF attenuation values:  Value(WithPadmix flag)\n");
+	for (i = 0; i < lo->rfatt_list.len; i++) {
+		fappend("%u(%d), ",
+			lo->rfatt_list.list[i].att,
+			lo->rfatt_list.list[i].with_padmix);
+	}
+	fappend("\n");
+	fappend("\nUsed Baseband attenuation values:\n");
+	for (i = 0; i < lo->bbatt_list.len; i++) {
+		fappend("%u, ",
+			lo->bbatt_list.list[i].att);
+	}
+	fappend("\n");
+
+out:
+	return err ? err : count;
+}
+
+#undef fappend
+
+static int b43_debugfs_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t b43_debugfs_read(struct file *file, char __user *userbuf,
+				size_t count, loff_t *ppos)
+{
+	struct b43_wldev *dev;
+	struct b43_debugfs_fops *dfops;
+	struct b43_dfs_file *dfile;
+	ssize_t ret;
+	char *buf;
+	const size_t bufsize = 1024 * 128;
+	const size_t buforder = get_order(bufsize);
+	int err = 0;
+
+	if (!count)
+		return 0;
+	dev = file->private_data;
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&dev->wl->mutex);
+	if (b43_status(dev) < B43_STAT_INITIALIZED) {
+		err = -ENODEV;
+		goto out_unlock;
+	}
+
+	dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
+	if (!dfops->read) {
+		err = -ENOSYS;
+		goto out_unlock;
+	}
+	dfile = fops_to_dfs_file(dev, dfops);
+
+	if (!dfile->buffer) {
+		buf = (char *)__get_free_pages(GFP_KERNEL, buforder);
+		if (!buf) {
+			err = -ENOMEM;
+			goto out_unlock;
+		}
+		/* Sparse warns about the following memset, because it has a big
+		 * size value. That warning is bogus, so I will ignore it. --mb */
+		memset(buf, 0, bufsize);
+		if (dfops->take_irqlock) {
+			spin_lock_irq(&dev->wl->irq_lock);
+			ret = dfops->read(dev, buf, bufsize);
+			spin_unlock_irq(&dev->wl->irq_lock);
+		} else
+			ret = dfops->read(dev, buf, bufsize);
+		if (ret <= 0) {
+			free_pages((unsigned long)buf, buforder);
+			err = ret;
+			goto out_unlock;
+		}
+		dfile->data_len = ret;
+		dfile->buffer = buf;
+	}
+
+	ret = simple_read_from_buffer(userbuf, count, ppos,
+				      dfile->buffer,
+				      dfile->data_len);
+	if (*ppos >= dfile->data_len) {
+		free_pages((unsigned long)dfile->buffer, buforder);
+		dfile->buffer = NULL;
+		dfile->data_len = 0;
+	}
+out_unlock:
+	mutex_unlock(&dev->wl->mutex);
+
+	return err ? err : ret;
+}
+
+static ssize_t b43_debugfs_write(struct file *file,
+				 const char __user *userbuf,
+				 size_t count, loff_t *ppos)
+{
+	struct b43_wldev *dev;
+	struct b43_debugfs_fops *dfops;
+	char *buf;
+	int err = 0;
+
+	if (!count)
+		return 0;
+	if (count > PAGE_SIZE)
+		return -E2BIG;
+	dev = file->private_data;
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&dev->wl->mutex);
+	if (b43_status(dev) < B43_STAT_INITIALIZED) {
+		err = -ENODEV;
+		goto out_unlock;
+	}
+
+	dfops = container_of(file->f_op, struct b43_debugfs_fops, fops);
+	if (!dfops->write) {
+		err = -ENOSYS;
+		goto out_unlock;
+	}
+
+	buf = (char *)get_zeroed_page(GFP_KERNEL);
+	if (!buf) {
+		err = -ENOMEM;
+		goto out_unlock;
+	}
+	if (copy_from_user(buf, userbuf, count)) {
+		err = -EFAULT;
+		goto out_freepage;
+	}
+	if (dfops->take_irqlock) {
+		spin_lock_irq(&dev->wl->irq_lock);
+		err = dfops->write(dev, buf, count);
+		spin_unlock_irq(&dev->wl->irq_lock);
+	} else
+		err = dfops->write(dev, buf, count);
+	if (err)
+		goto out_freepage;
+
+out_freepage:
+	free_page((unsigned long)buf);
+out_unlock:
+	mutex_unlock(&dev->wl->mutex);
+
+	return err ? err : count;
+}
+
+
+#define B43_DEBUGFS_FOPS(name, _read, _write, _take_irqlock)	\
+	static struct b43_debugfs_fops fops_##name = {		\
+		.read	= _read,				\
+		.write	= _write,				\
+		.fops	= {					\
+			.open	= b43_debugfs_open,		\
+			.read	= b43_debugfs_read,		\
+			.write	= b43_debugfs_write,		\
+		},						\
+		.file_struct_offset = offsetof(struct b43_dfsentry, \
+					       file_##name),	\
+		.take_irqlock	= _take_irqlock,		\
+	}
+
+B43_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1);
+B43_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1);
+B43_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1);
+B43_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
+B43_DEBUGFS_FOPS(txpower_g, txpower_g_read_file, txpower_g_write_file, 0);
+B43_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
+B43_DEBUGFS_FOPS(loctls, loctls_read_file, NULL, 0);
+
+
+int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
+{
+	return !!(dev->dfsentry && dev->dfsentry->dyn_debug[feature]);
+}
+
+static void b43_remove_dynamic_debug(struct b43_wldev *dev)
+{
+	struct b43_dfsentry *e = dev->dfsentry;
+	int i;
+
+	for (i = 0; i < __B43_NR_DYNDBG; i++)
+		debugfs_remove(e->dyn_debug_dentries[i]);
+}
+
+static void b43_add_dynamic_debug(struct b43_wldev *dev)
+{
+	struct b43_dfsentry *e = dev->dfsentry;
+	struct dentry *d;
+
+#define add_dyn_dbg(name, id, initstate) do {		\
+	e->dyn_debug[id] = (initstate);			\
+	d = debugfs_create_bool(name, 0600, e->subdir,	\
+				&(e->dyn_debug[id]));	\
+	if (!IS_ERR(d))					\
+		e->dyn_debug_dentries[id] = d;		\
+				} while (0)
+
+	add_dyn_dbg("debug_xmitpower", B43_DBG_XMITPOWER, 0);
+	add_dyn_dbg("debug_dmaoverflow", B43_DBG_DMAOVERFLOW, 0);
+	add_dyn_dbg("debug_dmaverbose", B43_DBG_DMAVERBOSE, 0);
+	add_dyn_dbg("debug_pwork_fast", B43_DBG_PWORK_FAST, 0);
+	add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0);
+
+#undef add_dyn_dbg
+}
+
+void b43_debugfs_add_device(struct b43_wldev *dev)
+{
+	struct b43_dfsentry *e;
+	struct b43_txstatus_log *log;
+	char devdir[16];
+
+	B43_WARN_ON(!dev);
+	e = kzalloc(sizeof(*e), GFP_KERNEL);
+	if (!e) {
+		b43err(dev->wl, "debugfs: add device OOM\n");
+		return;
+	}
+	e->dev = dev;
+	log = &e->txstatlog;
+	log->log = kcalloc(B43_NR_LOGGED_TXSTATUS,
+			   sizeof(struct b43_txstatus), GFP_KERNEL);
+	if (!log->log) {
+		b43err(dev->wl, "debugfs: add device txstatus OOM\n");
+		kfree(e);
+		return;
+	}
+	log->end = -1;
+	spin_lock_init(&log->lock);
+
+	dev->dfsentry = e;
+
+	snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy));
+	e->subdir = debugfs_create_dir(devdir, rootdir);
+	if (!e->subdir || IS_ERR(e->subdir)) {
+		if (e->subdir == ERR_PTR(-ENODEV)) {
+			b43dbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not "
+			       "enabled in kernel config\n");
+		} else {
+			b43err(dev->wl, "debugfs: cannot create %s directory\n",
+			       devdir);
+		}
+		dev->dfsentry = NULL;
+		kfree(log->log);
+		kfree(e);
+		return;
+	}
+
+#define ADD_FILE(name, mode)	\
+	do {							\
+		struct dentry *d;				\
+		d = debugfs_create_file(__stringify(name),	\
+					mode, e->subdir, dev,	\
+					&fops_##name.fops);	\
+		e->file_##name.dentry = NULL;			\
+		if (!IS_ERR(d))					\
+			e->file_##name.dentry = d;		\
+	} while (0)
+
+
+	ADD_FILE(tsf, 0600);
+	ADD_FILE(ucode_regs, 0400);
+	ADD_FILE(shm, 0400);
+	ADD_FILE(txstat, 0400);
+	ADD_FILE(txpower_g, 0600);
+	ADD_FILE(restart, 0200);
+	ADD_FILE(loctls, 0400);
+
+#undef ADD_FILE
+
+	b43_add_dynamic_debug(dev);
+}
+
+void b43_debugfs_remove_device(struct b43_wldev *dev)
+{
+	struct b43_dfsentry *e;
+
+	if (!dev)
+		return;
+	e = dev->dfsentry;
+	if (!e)
+		return;
+	b43_remove_dynamic_debug(dev);
+
+	debugfs_remove(e->file_tsf.dentry);
+	debugfs_remove(e->file_ucode_regs.dentry);
+	debugfs_remove(e->file_shm.dentry);
+	debugfs_remove(e->file_txstat.dentry);
+	debugfs_remove(e->file_txpower_g.dentry);
+	debugfs_remove(e->file_restart.dentry);
+	debugfs_remove(e->file_loctls.dentry);
+
+	debugfs_remove(e->subdir);
+	kfree(e->txstatlog.log);
+	kfree(e);
+}
+
+void b43_debugfs_log_txstat(struct b43_wldev *dev,
+			    const struct b43_txstatus *status)
+{
+	struct b43_dfsentry *e = dev->dfsentry;
+	struct b43_txstatus_log *log;
+	struct b43_txstatus *cur;
+	int i;
+
+	if (!e)
+		return;
+	log = &e->txstatlog;
+	B43_WARN_ON(!irqs_disabled());
+	spin_lock(&log->lock);
+	i = log->end + 1;
+	if (i == B43_NR_LOGGED_TXSTATUS)
+		i = 0;
+	log->end = i;
+	cur = &(log->log[i]);
+	memcpy(cur, status, sizeof(*cur));
+	spin_unlock(&log->lock);
+}
+
+void b43_debugfs_init(void)
+{
+	rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+	if (IS_ERR(rootdir))
+		rootdir = NULL;
+}
+
+void b43_debugfs_exit(void)
+{
+	debugfs_remove(rootdir);
+}
diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h
new file mode 100644
index 0000000..6eebe858
--- /dev/null
+++ b/drivers/net/wireless/b43/debugfs.h
@@ -0,0 +1,89 @@
+#ifndef B43_DEBUGFS_H_
+#define B43_DEBUGFS_H_
+
+struct b43_wldev;
+struct b43_txstatus;
+
+enum b43_dyndbg {		/* Dynamic debugging features */
+	B43_DBG_XMITPOWER,
+	B43_DBG_DMAOVERFLOW,
+	B43_DBG_DMAVERBOSE,
+	B43_DBG_PWORK_FAST,
+	B43_DBG_PWORK_STOP,
+	__B43_NR_DYNDBG,
+};
+
+#ifdef CONFIG_B43_DEBUG
+
+struct dentry;
+
+#define B43_NR_LOGGED_TXSTATUS	100
+
+struct b43_txstatus_log {
+	struct b43_txstatus *log;
+	int end;
+	spinlock_t lock;
+};
+
+struct b43_dfs_file {
+	struct dentry *dentry;
+	char *buffer;
+	size_t data_len;
+};
+
+struct b43_dfsentry {
+	struct b43_wldev *dev;
+	struct dentry *subdir;
+
+	struct b43_dfs_file file_tsf;
+	struct b43_dfs_file file_ucode_regs;
+	struct b43_dfs_file file_shm;
+	struct b43_dfs_file file_txstat;
+	struct b43_dfs_file file_txpower_g;
+	struct b43_dfs_file file_restart;
+	struct b43_dfs_file file_loctls;
+
+	struct b43_txstatus_log txstatlog;
+
+	/* Enabled/Disabled list for the dynamic debugging features. */
+	u32 dyn_debug[__B43_NR_DYNDBG];
+	/* Dentries for the dynamic debugging entries. */
+	struct dentry *dyn_debug_dentries[__B43_NR_DYNDBG];
+};
+
+int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature);
+
+void b43_debugfs_init(void);
+void b43_debugfs_exit(void);
+void b43_debugfs_add_device(struct b43_wldev *dev);
+void b43_debugfs_remove_device(struct b43_wldev *dev);
+void b43_debugfs_log_txstat(struct b43_wldev *dev,
+			    const struct b43_txstatus *status);
+
+#else /* CONFIG_B43_DEBUG */
+
+static inline int b43_debug(struct b43_wldev *dev, enum b43_dyndbg feature)
+{
+	return 0;
+}
+
+static inline void b43_debugfs_init(void)
+{
+}
+static inline void b43_debugfs_exit(void)
+{
+}
+static inline void b43_debugfs_add_device(struct b43_wldev *dev)
+{
+}
+static inline void b43_debugfs_remove_device(struct b43_wldev *dev)
+{
+}
+static inline void b43_debugfs_log_txstat(struct b43_wldev *dev,
+					  const struct b43_txstatus *status)
+{
+}
+
+#endif /* CONFIG_B43_DEBUG */
+
+#endif /* B43_DEBUGFS_H_ */
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
new file mode 100644
index 0000000..5e8f8ac
--- /dev/null
+++ b/drivers/net/wireless/b43/dma.c
@@ -0,0 +1,1494 @@
+/*
+
+  Broadcom B43 wireless driver
+
+  DMA ringbuffer and descriptor allocation/management
+
+  Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+
+  Some code in this file is derived from the b44.c driver
+  Copyright (C) 2002 David S. Miller
+  Copyright (C) Pekka Pietikainen
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "dma.h"
+#include "main.h"
+#include "debugfs.h"
+#include "xmit.h"
+
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+
+/* 32bit DMA ops. */
+static
+struct b43_dmadesc_generic *op32_idx2desc(struct b43_dmaring *ring,
+					  int slot,
+					  struct b43_dmadesc_meta **meta)
+{
+	struct b43_dmadesc32 *desc;
+
+	*meta = &(ring->meta[slot]);
+	desc = ring->descbase;
+	desc = &(desc[slot]);
+
+	return (struct b43_dmadesc_generic *)desc;
+}
+
+static void op32_fill_descriptor(struct b43_dmaring *ring,
+				 struct b43_dmadesc_generic *desc,
+				 dma_addr_t dmaaddr, u16 bufsize,
+				 int start, int end, int irq)
+{
+	struct b43_dmadesc32 *descbase = ring->descbase;
+	int slot;
+	u32 ctl;
+	u32 addr;
+	u32 addrext;
+
+	slot = (int)(&(desc->dma32) - descbase);
+	B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+
+	addr = (u32) (dmaaddr & ~SSB_DMA_TRANSLATION_MASK);
+	addrext = (u32) (dmaaddr & SSB_DMA_TRANSLATION_MASK)
+	    >> SSB_DMA_TRANSLATION_SHIFT;
+	addr |= ssb_dma_translation(ring->dev->dev);
+	ctl = (bufsize - ring->frameoffset)
+	    & B43_DMA32_DCTL_BYTECNT;
+	if (slot == ring->nr_slots - 1)
+		ctl |= B43_DMA32_DCTL_DTABLEEND;
+	if (start)
+		ctl |= B43_DMA32_DCTL_FRAMESTART;
+	if (end)
+		ctl |= B43_DMA32_DCTL_FRAMEEND;
+	if (irq)
+		ctl |= B43_DMA32_DCTL_IRQ;
+	ctl |= (addrext << B43_DMA32_DCTL_ADDREXT_SHIFT)
+	    & B43_DMA32_DCTL_ADDREXT_MASK;
+
+	desc->dma32.control = cpu_to_le32(ctl);
+	desc->dma32.address = cpu_to_le32(addr);
+}
+
+static void op32_poke_tx(struct b43_dmaring *ring, int slot)
+{
+	b43_dma_write(ring, B43_DMA32_TXINDEX,
+		      (u32) (slot * sizeof(struct b43_dmadesc32)));
+}
+
+static void op32_tx_suspend(struct b43_dmaring *ring)
+{
+	b43_dma_write(ring, B43_DMA32_TXCTL, b43_dma_read(ring, B43_DMA32_TXCTL)
+		      | B43_DMA32_TXSUSPEND);
+}
+
+static void op32_tx_resume(struct b43_dmaring *ring)
+{
+	b43_dma_write(ring, B43_DMA32_TXCTL, b43_dma_read(ring, B43_DMA32_TXCTL)
+		      & ~B43_DMA32_TXSUSPEND);
+}
+
+static int op32_get_current_rxslot(struct b43_dmaring *ring)
+{
+	u32 val;
+
+	val = b43_dma_read(ring, B43_DMA32_RXSTATUS);
+	val &= B43_DMA32_RXDPTR;
+
+	return (val / sizeof(struct b43_dmadesc32));
+}
+
+static void op32_set_current_rxslot(struct b43_dmaring *ring, int slot)
+{
+	b43_dma_write(ring, B43_DMA32_RXINDEX,
+		      (u32) (slot * sizeof(struct b43_dmadesc32)));
+}
+
+static const struct b43_dma_ops dma32_ops = {
+	.idx2desc = op32_idx2desc,
+	.fill_descriptor = op32_fill_descriptor,
+	.poke_tx = op32_poke_tx,
+	.tx_suspend = op32_tx_suspend,
+	.tx_resume = op32_tx_resume,
+	.get_current_rxslot = op32_get_current_rxslot,
+	.set_current_rxslot = op32_set_current_rxslot,
+};
+
+/* 64bit DMA ops. */
+static
+struct b43_dmadesc_generic *op64_idx2desc(struct b43_dmaring *ring,
+					  int slot,
+					  struct b43_dmadesc_meta **meta)
+{
+	struct b43_dmadesc64 *desc;
+
+	*meta = &(ring->meta[slot]);
+	desc = ring->descbase;
+	desc = &(desc[slot]);
+
+	return (struct b43_dmadesc_generic *)desc;
+}
+
+static void op64_fill_descriptor(struct b43_dmaring *ring,
+				 struct b43_dmadesc_generic *desc,
+				 dma_addr_t dmaaddr, u16 bufsize,
+				 int start, int end, int irq)
+{
+	struct b43_dmadesc64 *descbase = ring->descbase;
+	int slot;
+	u32 ctl0 = 0, ctl1 = 0;
+	u32 addrlo, addrhi;
+	u32 addrext;
+
+	slot = (int)(&(desc->dma64) - descbase);
+	B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+
+	addrlo = (u32) (dmaaddr & 0xFFFFFFFF);
+	addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
+	addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
+	    >> SSB_DMA_TRANSLATION_SHIFT;
+	addrhi |= ssb_dma_translation(ring->dev->dev);
+	if (slot == ring->nr_slots - 1)
+		ctl0 |= B43_DMA64_DCTL0_DTABLEEND;
+	if (start)
+		ctl0 |= B43_DMA64_DCTL0_FRAMESTART;
+	if (end)
+		ctl0 |= B43_DMA64_DCTL0_FRAMEEND;
+	if (irq)
+		ctl0 |= B43_DMA64_DCTL0_IRQ;
+	ctl1 |= (bufsize - ring->frameoffset)
+	    & B43_DMA64_DCTL1_BYTECNT;
+	ctl1 |= (addrext << B43_DMA64_DCTL1_ADDREXT_SHIFT)
+	    & B43_DMA64_DCTL1_ADDREXT_MASK;
+
+	desc->dma64.control0 = cpu_to_le32(ctl0);
+	desc->dma64.control1 = cpu_to_le32(ctl1);
+	desc->dma64.address_low = cpu_to_le32(addrlo);
+	desc->dma64.address_high = cpu_to_le32(addrhi);
+}
+
+static void op64_poke_tx(struct b43_dmaring *ring, int slot)
+{
+	b43_dma_write(ring, B43_DMA64_TXINDEX,
+		      (u32) (slot * sizeof(struct b43_dmadesc64)));
+}
+
+static void op64_tx_suspend(struct b43_dmaring *ring)
+{
+	b43_dma_write(ring, B43_DMA64_TXCTL, b43_dma_read(ring, B43_DMA64_TXCTL)
+		      | B43_DMA64_TXSUSPEND);
+}
+
+static void op64_tx_resume(struct b43_dmaring *ring)
+{
+	b43_dma_write(ring, B43_DMA64_TXCTL, b43_dma_read(ring, B43_DMA64_TXCTL)
+		      & ~B43_DMA64_TXSUSPEND);
+}
+
+static int op64_get_current_rxslot(struct b43_dmaring *ring)
+{
+	u32 val;
+
+	val = b43_dma_read(ring, B43_DMA64_RXSTATUS);
+	val &= B43_DMA64_RXSTATDPTR;
+
+	return (val / sizeof(struct b43_dmadesc64));
+}
+
+static void op64_set_current_rxslot(struct b43_dmaring *ring, int slot)
+{
+	b43_dma_write(ring, B43_DMA64_RXINDEX,
+		      (u32) (slot * sizeof(struct b43_dmadesc64)));
+}
+
+static const struct b43_dma_ops dma64_ops = {
+	.idx2desc = op64_idx2desc,
+	.fill_descriptor = op64_fill_descriptor,
+	.poke_tx = op64_poke_tx,
+	.tx_suspend = op64_tx_suspend,
+	.tx_resume = op64_tx_resume,
+	.get_current_rxslot = op64_get_current_rxslot,
+	.set_current_rxslot = op64_set_current_rxslot,
+};
+
+static inline int free_slots(struct b43_dmaring *ring)
+{
+	return (ring->nr_slots - ring->used_slots);
+}
+
+static inline int next_slot(struct b43_dmaring *ring, int slot)
+{
+	B43_WARN_ON(!(slot >= -1 && slot <= ring->nr_slots - 1));
+	if (slot == ring->nr_slots - 1)
+		return 0;
+	return slot + 1;
+}
+
+static inline int prev_slot(struct b43_dmaring *ring, int slot)
+{
+	B43_WARN_ON(!(slot >= 0 && slot <= ring->nr_slots - 1));
+	if (slot == 0)
+		return ring->nr_slots - 1;
+	return slot - 1;
+}
+
+#ifdef CONFIG_B43_DEBUG
+static void update_max_used_slots(struct b43_dmaring *ring,
+				  int current_used_slots)
+{
+	if (current_used_slots <= ring->max_used_slots)
+		return;
+	ring->max_used_slots = current_used_slots;
+	if (b43_debug(ring->dev, B43_DBG_DMAVERBOSE)) {
+		b43dbg(ring->dev->wl,
+		       "max_used_slots increased to %d on %s ring %d\n",
+		       ring->max_used_slots,
+		       ring->tx ? "TX" : "RX", ring->index);
+	}
+}
+#else
+static inline
+    void update_max_used_slots(struct b43_dmaring *ring, int current_used_slots)
+{
+}
+#endif /* DEBUG */
+
+/* Request a slot for usage. */
+static inline int request_slot(struct b43_dmaring *ring)
+{
+	int slot;
+
+	B43_WARN_ON(!ring->tx);
+	B43_WARN_ON(ring->stopped);
+	B43_WARN_ON(free_slots(ring) == 0);
+
+	slot = next_slot(ring, ring->current_slot);
+	ring->current_slot = slot;
+	ring->used_slots++;
+
+	update_max_used_slots(ring, ring->used_slots);
+
+	return slot;
+}
+
+/* Mac80211-queue to b43-ring mapping */
+static struct b43_dmaring *priority_to_txring(struct b43_wldev *dev,
+					      int queue_priority)
+{
+	struct b43_dmaring *ring;
+
+/*FIXME: For now we always run on TX-ring-1 */
+	return dev->dma.tx_ring1;
+
+	/* 0 = highest priority */
+	switch (queue_priority) {
+	default:
+		B43_WARN_ON(1);
+		/* fallthrough */
+	case 0:
+		ring = dev->dma.tx_ring3;
+		break;
+	case 1:
+		ring = dev->dma.tx_ring2;
+		break;
+	case 2:
+		ring = dev->dma.tx_ring1;
+		break;
+	case 3:
+		ring = dev->dma.tx_ring0;
+		break;
+	case 4:
+		ring = dev->dma.tx_ring4;
+		break;
+	case 5:
+		ring = dev->dma.tx_ring5;
+		break;
+	}
+
+	return ring;
+}
+
+/* Bcm43xx-ring to mac80211-queue mapping */
+static inline int txring_to_priority(struct b43_dmaring *ring)
+{
+	static const u8 idx_to_prio[] = { 3, 2, 1, 0, 4, 5, };
+
+/*FIXME: have only one queue, for now */
+	return 0;
+
+	return idx_to_prio[ring->index];
+}
+
+u16 b43_dmacontroller_base(int dma64bit, int controller_idx)
+{
+	static const u16 map64[] = {
+		B43_MMIO_DMA64_BASE0,
+		B43_MMIO_DMA64_BASE1,
+		B43_MMIO_DMA64_BASE2,
+		B43_MMIO_DMA64_BASE3,
+		B43_MMIO_DMA64_BASE4,
+		B43_MMIO_DMA64_BASE5,
+	};
+	static const u16 map32[] = {
+		B43_MMIO_DMA32_BASE0,
+		B43_MMIO_DMA32_BASE1,
+		B43_MMIO_DMA32_BASE2,
+		B43_MMIO_DMA32_BASE3,
+		B43_MMIO_DMA32_BASE4,
+		B43_MMIO_DMA32_BASE5,
+	};
+
+	if (dma64bit) {
+		B43_WARN_ON(!(controller_idx >= 0 &&
+			      controller_idx < ARRAY_SIZE(map64)));
+		return map64[controller_idx];
+	}
+	B43_WARN_ON(!(controller_idx >= 0 &&
+		      controller_idx < ARRAY_SIZE(map32)));
+	return map32[controller_idx];
+}
+
+static inline
+    dma_addr_t map_descbuffer(struct b43_dmaring *ring,
+			      unsigned char *buf, size_t len, int tx)
+{
+	dma_addr_t dmaaddr;
+
+	if (tx) {
+		dmaaddr = dma_map_single(ring->dev->dev->dev,
+					 buf, len, DMA_TO_DEVICE);
+	} else {
+		dmaaddr = dma_map_single(ring->dev->dev->dev,
+					 buf, len, DMA_FROM_DEVICE);
+	}
+
+	return dmaaddr;
+}
+
+static inline
+    void unmap_descbuffer(struct b43_dmaring *ring,
+			  dma_addr_t addr, size_t len, int tx)
+{
+	if (tx) {
+		dma_unmap_single(ring->dev->dev->dev, addr, len, DMA_TO_DEVICE);
+	} else {
+		dma_unmap_single(ring->dev->dev->dev,
+				 addr, len, DMA_FROM_DEVICE);
+	}
+}
+
+static inline
+    void sync_descbuffer_for_cpu(struct b43_dmaring *ring,
+				 dma_addr_t addr, size_t len)
+{
+	B43_WARN_ON(ring->tx);
+	dma_sync_single_for_cpu(ring->dev->dev->dev,
+				addr, len, DMA_FROM_DEVICE);
+}
+
+static inline
+    void sync_descbuffer_for_device(struct b43_dmaring *ring,
+				    dma_addr_t addr, size_t len)
+{
+	B43_WARN_ON(ring->tx);
+	dma_sync_single_for_device(ring->dev->dev->dev,
+				   addr, len, DMA_FROM_DEVICE);
+}
+
+static inline
+    void free_descriptor_buffer(struct b43_dmaring *ring,
+				struct b43_dmadesc_meta *meta)
+{
+	if (meta->skb) {
+		dev_kfree_skb_any(meta->skb);
+		meta->skb = NULL;
+	}
+}
+
+static int alloc_ringmemory(struct b43_dmaring *ring)
+{
+	struct device *dev = ring->dev->dev->dev;
+
+	ring->descbase = dma_alloc_coherent(dev, B43_DMA_RINGMEMSIZE,
+					    &(ring->dmabase), GFP_KERNEL);
+	if (!ring->descbase) {
+		b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
+		return -ENOMEM;
+	}
+	memset(ring->descbase, 0, B43_DMA_RINGMEMSIZE);
+
+	return 0;
+}
+
+static void free_ringmemory(struct b43_dmaring *ring)
+{
+	struct device *dev = ring->dev->dev->dev;
+
+	dma_free_coherent(dev, B43_DMA_RINGMEMSIZE,
+			  ring->descbase, ring->dmabase);
+}
+
+/* Reset the RX DMA channel */
+int b43_dmacontroller_rx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
+{
+	int i;
+	u32 value;
+	u16 offset;
+
+	might_sleep();
+
+	offset = dma64 ? B43_DMA64_RXCTL : B43_DMA32_RXCTL;
+	b43_write32(dev, mmio_base + offset, 0);
+	for (i = 0; i < 10; i++) {
+		offset = dma64 ? B43_DMA64_RXSTATUS : B43_DMA32_RXSTATUS;
+		value = b43_read32(dev, mmio_base + offset);
+		if (dma64) {
+			value &= B43_DMA64_RXSTAT;
+			if (value == B43_DMA64_RXSTAT_DISABLED) {
+				i = -1;
+				break;
+			}
+		} else {
+			value &= B43_DMA32_RXSTATE;
+			if (value == B43_DMA32_RXSTAT_DISABLED) {
+				i = -1;
+				break;
+			}
+		}
+		msleep(1);
+	}
+	if (i != -1) {
+		b43err(dev->wl, "DMA RX reset timed out\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/* Reset the RX DMA channel */
+int b43_dmacontroller_tx_reset(struct b43_wldev *dev, u16 mmio_base, int dma64)
+{
+	int i;
+	u32 value;
+	u16 offset;
+
+	might_sleep();
+
+	for (i = 0; i < 10; i++) {
+		offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
+		value = b43_read32(dev, mmio_base + offset);
+		if (dma64) {
+			value &= B43_DMA64_TXSTAT;
+			if (value == B43_DMA64_TXSTAT_DISABLED ||
+			    value == B43_DMA64_TXSTAT_IDLEWAIT ||
+			    value == B43_DMA64_TXSTAT_STOPPED)
+				break;
+		} else {
+			value &= B43_DMA32_TXSTATE;
+			if (value == B43_DMA32_TXSTAT_DISABLED ||
+			    value == B43_DMA32_TXSTAT_IDLEWAIT ||
+			    value == B43_DMA32_TXSTAT_STOPPED)
+				break;
+		}
+		msleep(1);
+	}
+	offset = dma64 ? B43_DMA64_TXCTL : B43_DMA32_TXCTL;
+	b43_write32(dev, mmio_base + offset, 0);
+	for (i = 0; i < 10; i++) {
+		offset = dma64 ? B43_DMA64_TXSTATUS : B43_DMA32_TXSTATUS;
+		value = b43_read32(dev, mmio_base + offset);
+		if (dma64) {
+			value &= B43_DMA64_TXSTAT;
+			if (value == B43_DMA64_TXSTAT_DISABLED) {
+				i = -1;
+				break;
+			}
+		} else {
+			value &= B43_DMA32_TXSTATE;
+			if (value == B43_DMA32_TXSTAT_DISABLED) {
+				i = -1;
+				break;
+			}
+		}
+		msleep(1);
+	}
+	if (i != -1) {
+		b43err(dev->wl, "DMA TX reset timed out\n");
+		return -ENODEV;
+	}
+	/* ensure the reset is completed. */
+	msleep(1);
+
+	return 0;
+}
+
+static int setup_rx_descbuffer(struct b43_dmaring *ring,
+			       struct b43_dmadesc_generic *desc,
+			       struct b43_dmadesc_meta *meta, gfp_t gfp_flags)
+{
+	struct b43_rxhdr_fw4 *rxhdr;
+	struct b43_hwtxstatus *txstat;
+	dma_addr_t dmaaddr;
+	struct sk_buff *skb;
+
+	B43_WARN_ON(ring->tx);
+
+	skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
+	if (unlikely(!skb))
+		return -ENOMEM;
+	dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
+	if (dma_mapping_error(dmaaddr)) {
+		/* ugh. try to realloc in zone_dma */
+		gfp_flags |= GFP_DMA;
+
+		dev_kfree_skb_any(skb);
+
+		skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
+		if (unlikely(!skb))
+			return -ENOMEM;
+		dmaaddr = map_descbuffer(ring, skb->data,
+					 ring->rx_buffersize, 0);
+	}
+
+	if (dma_mapping_error(dmaaddr)) {
+		dev_kfree_skb_any(skb);
+		return -EIO;
+	}
+
+	meta->skb = skb;
+	meta->dmaaddr = dmaaddr;
+	ring->ops->fill_descriptor(ring, desc, dmaaddr,
+				   ring->rx_buffersize, 0, 0, 0);
+
+	rxhdr = (struct b43_rxhdr_fw4 *)(skb->data);
+	rxhdr->frame_len = 0;
+	txstat = (struct b43_hwtxstatus *)(skb->data);
+	txstat->cookie = 0;
+
+	return 0;
+}
+
+/* Allocate the initial descbuffers.
+ * This is used for an RX ring only.
+ */
+static int alloc_initial_descbuffers(struct b43_dmaring *ring)
+{
+	int i, err = -ENOMEM;
+	struct b43_dmadesc_generic *desc;
+	struct b43_dmadesc_meta *meta;
+
+	for (i = 0; i < ring->nr_slots; i++) {
+		desc = ring->ops->idx2desc(ring, i, &meta);
+
+		err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
+		if (err) {
+			b43err(ring->dev->wl,
+			       "Failed to allocate initial descbuffers\n");
+			goto err_unwind;
+		}
+	}
+	mb();
+	ring->used_slots = ring->nr_slots;
+	err = 0;
+      out:
+	return err;
+
+      err_unwind:
+	for (i--; i >= 0; i--) {
+		desc = ring->ops->idx2desc(ring, i, &meta);
+
+		unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
+		dev_kfree_skb(meta->skb);
+	}
+	goto out;
+}
+
+/* Do initial setup of the DMA controller.
+ * Reset the controller, write the ring busaddress
+ * and switch the "enable" bit on.
+ */
+static int dmacontroller_setup(struct b43_dmaring *ring)
+{
+	int err = 0;
+	u32 value;
+	u32 addrext;
+	u32 trans = ssb_dma_translation(ring->dev->dev);
+
+	if (ring->tx) {
+		if (ring->dma64) {
+			u64 ringbase = (u64) (ring->dmabase);
+
+			addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
+			    >> SSB_DMA_TRANSLATION_SHIFT;
+			value = B43_DMA64_TXENABLE;
+			value |= (addrext << B43_DMA64_TXADDREXT_SHIFT)
+			    & B43_DMA64_TXADDREXT_MASK;
+			b43_dma_write(ring, B43_DMA64_TXCTL, value);
+			b43_dma_write(ring, B43_DMA64_TXRINGLO,
+				      (ringbase & 0xFFFFFFFF));
+			b43_dma_write(ring, B43_DMA64_TXRINGHI,
+				      ((ringbase >> 32) &
+				       ~SSB_DMA_TRANSLATION_MASK)
+				      | trans);
+		} else {
+			u32 ringbase = (u32) (ring->dmabase);
+
+			addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
+			    >> SSB_DMA_TRANSLATION_SHIFT;
+			value = B43_DMA32_TXENABLE;
+			value |= (addrext << B43_DMA32_TXADDREXT_SHIFT)
+			    & B43_DMA32_TXADDREXT_MASK;
+			b43_dma_write(ring, B43_DMA32_TXCTL, value);
+			b43_dma_write(ring, B43_DMA32_TXRING,
+				      (ringbase & ~SSB_DMA_TRANSLATION_MASK)
+				      | trans);
+		}
+	} else {
+		err = alloc_initial_descbuffers(ring);
+		if (err)
+			goto out;
+		if (ring->dma64) {
+			u64 ringbase = (u64) (ring->dmabase);
+
+			addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
+			    >> SSB_DMA_TRANSLATION_SHIFT;
+			value = (ring->frameoffset << B43_DMA64_RXFROFF_SHIFT);
+			value |= B43_DMA64_RXENABLE;
+			value |= (addrext << B43_DMA64_RXADDREXT_SHIFT)
+			    & B43_DMA64_RXADDREXT_MASK;
+			b43_dma_write(ring, B43_DMA64_RXCTL, value);
+			b43_dma_write(ring, B43_DMA64_RXRINGLO,
+				      (ringbase & 0xFFFFFFFF));
+			b43_dma_write(ring, B43_DMA64_RXRINGHI,
+				      ((ringbase >> 32) &
+				       ~SSB_DMA_TRANSLATION_MASK)
+				      | trans);
+			b43_dma_write(ring, B43_DMA64_RXINDEX, 200);
+		} else {
+			u32 ringbase = (u32) (ring->dmabase);
+
+			addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
+			    >> SSB_DMA_TRANSLATION_SHIFT;
+			value = (ring->frameoffset << B43_DMA32_RXFROFF_SHIFT);
+			value |= B43_DMA32_RXENABLE;
+			value |= (addrext << B43_DMA32_RXADDREXT_SHIFT)
+			    & B43_DMA32_RXADDREXT_MASK;
+			b43_dma_write(ring, B43_DMA32_RXCTL, value);
+			b43_dma_write(ring, B43_DMA32_RXRING,
+				      (ringbase & ~SSB_DMA_TRANSLATION_MASK)
+				      | trans);
+			b43_dma_write(ring, B43_DMA32_RXINDEX, 200);
+		}
+	}
+
+      out:
+	return err;
+}
+
+/* Shutdown the DMA controller. */
+static void dmacontroller_cleanup(struct b43_dmaring *ring)
+{
+	if (ring->tx) {
+		b43_dmacontroller_tx_reset(ring->dev, ring->mmio_base,
+					   ring->dma64);
+		if (ring->dma64) {
+			b43_dma_write(ring, B43_DMA64_TXRINGLO, 0);
+			b43_dma_write(ring, B43_DMA64_TXRINGHI, 0);
+		} else
+			b43_dma_write(ring, B43_DMA32_TXRING, 0);
+	} else {
+		b43_dmacontroller_rx_reset(ring->dev, ring->mmio_base,
+					   ring->dma64);
+		if (ring->dma64) {
+			b43_dma_write(ring, B43_DMA64_RXRINGLO, 0);
+			b43_dma_write(ring, B43_DMA64_RXRINGHI, 0);
+		} else
+			b43_dma_write(ring, B43_DMA32_RXRING, 0);
+	}
+}
+
+static void free_all_descbuffers(struct b43_dmaring *ring)
+{
+	struct b43_dmadesc_generic *desc;
+	struct b43_dmadesc_meta *meta;
+	int i;
+
+	if (!ring->used_slots)
+		return;
+	for (i = 0; i < ring->nr_slots; i++) {
+		desc = ring->ops->idx2desc(ring, i, &meta);
+
+		if (!meta->skb) {
+			B43_WARN_ON(!ring->tx);
+			continue;
+		}
+		if (ring->tx) {
+			unmap_descbuffer(ring, meta->dmaaddr,
+					 meta->skb->len, 1);
+		} else {
+			unmap_descbuffer(ring, meta->dmaaddr,
+					 ring->rx_buffersize, 0);
+		}
+		free_descriptor_buffer(ring, meta);
+	}
+}
+
+static u64 supported_dma_mask(struct b43_wldev *dev)
+{
+	u32 tmp;
+	u16 mmio_base;
+
+	tmp = b43_read32(dev, SSB_TMSHIGH);
+	if (tmp & SSB_TMSHIGH_DMA64)
+		return DMA_64BIT_MASK;
+	mmio_base = b43_dmacontroller_base(0, 0);
+	b43_write32(dev, mmio_base + B43_DMA32_TXCTL, B43_DMA32_TXADDREXT_MASK);
+	tmp = b43_read32(dev, mmio_base + B43_DMA32_TXCTL);
+	if (tmp & B43_DMA32_TXADDREXT_MASK)
+		return DMA_32BIT_MASK;
+
+	return DMA_30BIT_MASK;
+}
+
+/* Main initialization function. */
+static
+struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
+				      int controller_index,
+				      int for_tx, int dma64)
+{
+	struct b43_dmaring *ring;
+	int err;
+	int nr_slots;
+	dma_addr_t dma_test;
+
+	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+	if (!ring)
+		goto out;
+
+	nr_slots = B43_RXRING_SLOTS;
+	if (for_tx)
+		nr_slots = B43_TXRING_SLOTS;
+
+	ring->meta = kcalloc(nr_slots, sizeof(struct b43_dmadesc_meta),
+			     GFP_KERNEL);
+	if (!ring->meta)
+		goto err_kfree_ring;
+	if (for_tx) {
+		ring->txhdr_cache = kcalloc(nr_slots,
+					    sizeof(struct b43_txhdr_fw4),
+					    GFP_KERNEL);
+		if (!ring->txhdr_cache)
+			goto err_kfree_meta;
+
+		/* test for ability to dma to txhdr_cache */
+		dma_test = dma_map_single(dev->dev->dev,
+					  ring->txhdr_cache,
+					  sizeof(struct b43_txhdr_fw4),
+					  DMA_TO_DEVICE);
+
+		if (dma_mapping_error(dma_test)) {
+			/* ugh realloc */
+			kfree(ring->txhdr_cache);
+			ring->txhdr_cache = kcalloc(nr_slots,
+						    sizeof(struct
+							   b43_txhdr_fw4),
+						    GFP_KERNEL | GFP_DMA);
+			if (!ring->txhdr_cache)
+				goto err_kfree_meta;
+
+			dma_test = dma_map_single(dev->dev->dev,
+						  ring->txhdr_cache,
+						  sizeof(struct b43_txhdr_fw4),
+						  DMA_TO_DEVICE);
+
+			if (dma_mapping_error(dma_test))
+				goto err_kfree_txhdr_cache;
+		}
+
+		dma_unmap_single(dev->dev->dev,
+				 dma_test, sizeof(struct b43_txhdr_fw4),
+				 DMA_TO_DEVICE);
+	}
+
+	ring->dev = dev;
+	ring->nr_slots = nr_slots;
+	ring->mmio_base = b43_dmacontroller_base(dma64, controller_index);
+	ring->index = controller_index;
+	ring->dma64 = !!dma64;
+	if (dma64)
+		ring->ops = &dma64_ops;
+	else
+		ring->ops = &dma32_ops;
+	if (for_tx) {
+		ring->tx = 1;
+		ring->current_slot = -1;
+	} else {
+		if (ring->index == 0) {
+			ring->rx_buffersize = B43_DMA0_RX_BUFFERSIZE;
+			ring->frameoffset = B43_DMA0_RX_FRAMEOFFSET;
+		} else if (ring->index == 3) {
+			ring->rx_buffersize = B43_DMA3_RX_BUFFERSIZE;
+			ring->frameoffset = B43_DMA3_RX_FRAMEOFFSET;
+		} else
+			B43_WARN_ON(1);
+	}
+	spin_lock_init(&ring->lock);
+#ifdef CONFIG_B43_DEBUG
+	ring->last_injected_overflow = jiffies;
+#endif
+
+	err = alloc_ringmemory(ring);
+	if (err)
+		goto err_kfree_txhdr_cache;
+	err = dmacontroller_setup(ring);
+	if (err)
+		goto err_free_ringmemory;
+
+      out:
+	return ring;
+
+      err_free_ringmemory:
+	free_ringmemory(ring);
+      err_kfree_txhdr_cache:
+	kfree(ring->txhdr_cache);
+      err_kfree_meta:
+	kfree(ring->meta);
+      err_kfree_ring:
+	kfree(ring);
+	ring = NULL;
+	goto out;
+}
+
+/* Main cleanup function. */
+static void b43_destroy_dmaring(struct b43_dmaring *ring)
+{
+	if (!ring)
+		return;
+
+	b43dbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots: %d/%d\n",
+	       (ring->dma64) ? "64" : "32",
+	       ring->mmio_base,
+	       (ring->tx) ? "TX" : "RX", ring->max_used_slots, ring->nr_slots);
+	/* Device IRQs are disabled prior entering this function,
+	 * so no need to take care of concurrency with rx handler stuff.
+	 */
+	dmacontroller_cleanup(ring);
+	free_all_descbuffers(ring);
+	free_ringmemory(ring);
+
+	kfree(ring->txhdr_cache);
+	kfree(ring->meta);
+	kfree(ring);
+}
+
+void b43_dma_free(struct b43_wldev *dev)
+{
+	struct b43_dma *dma;
+
+	if (b43_using_pio(dev))
+		return;
+	dma = &dev->dma;
+
+	b43_destroy_dmaring(dma->rx_ring3);
+	dma->rx_ring3 = NULL;
+	b43_destroy_dmaring(dma->rx_ring0);
+	dma->rx_ring0 = NULL;
+
+	b43_destroy_dmaring(dma->tx_ring5);
+	dma->tx_ring5 = NULL;
+	b43_destroy_dmaring(dma->tx_ring4);
+	dma->tx_ring4 = NULL;
+	b43_destroy_dmaring(dma->tx_ring3);
+	dma->tx_ring3 = NULL;
+	b43_destroy_dmaring(dma->tx_ring2);
+	dma->tx_ring2 = NULL;
+	b43_destroy_dmaring(dma->tx_ring1);
+	dma->tx_ring1 = NULL;
+	b43_destroy_dmaring(dma->tx_ring0);
+	dma->tx_ring0 = NULL;
+}
+
+int b43_dma_init(struct b43_wldev *dev)
+{
+	struct b43_dma *dma = &dev->dma;
+	struct b43_dmaring *ring;
+	int err;
+	u64 dmamask;
+	int dma64 = 0;
+
+	dmamask = supported_dma_mask(dev);
+	if (dmamask == DMA_64BIT_MASK)
+		dma64 = 1;
+
+	err = ssb_dma_set_mask(dev->dev, dmamask);
+	if (err) {
+#ifdef B43_PIO
+		b43warn(dev->wl, "DMA for this device not supported. "
+			"Falling back to PIO\n");
+		dev->__using_pio = 1;
+		return -EAGAIN;
+#else
+		b43err(dev->wl, "DMA for this device not supported and "
+		       "no PIO support compiled in\n");
+		return -EOPNOTSUPP;
+#endif
+	}
+
+	err = -ENOMEM;
+	/* setup TX DMA channels. */
+	ring = b43_setup_dmaring(dev, 0, 1, dma64);
+	if (!ring)
+		goto out;
+	dma->tx_ring0 = ring;
+
+	ring = b43_setup_dmaring(dev, 1, 1, dma64);
+	if (!ring)
+		goto err_destroy_tx0;
+	dma->tx_ring1 = ring;
+
+	ring = b43_setup_dmaring(dev, 2, 1, dma64);
+	if (!ring)
+		goto err_destroy_tx1;
+	dma->tx_ring2 = ring;
+
+	ring = b43_setup_dmaring(dev, 3, 1, dma64);
+	if (!ring)
+		goto err_destroy_tx2;
+	dma->tx_ring3 = ring;
+
+	ring = b43_setup_dmaring(dev, 4, 1, dma64);
+	if (!ring)
+		goto err_destroy_tx3;
+	dma->tx_ring4 = ring;
+
+	ring = b43_setup_dmaring(dev, 5, 1, dma64);
+	if (!ring)
+		goto err_destroy_tx4;
+	dma->tx_ring5 = ring;
+
+	/* setup RX DMA channels. */
+	ring = b43_setup_dmaring(dev, 0, 0, dma64);
+	if (!ring)
+		goto err_destroy_tx5;
+	dma->rx_ring0 = ring;
+
+	if (dev->dev->id.revision < 5) {
+		ring = b43_setup_dmaring(dev, 3, 0, dma64);
+		if (!ring)
+			goto err_destroy_rx0;
+		dma->rx_ring3 = ring;
+	}
+
+	b43dbg(dev->wl, "%d-bit DMA initialized\n",
+	       (dmamask == DMA_64BIT_MASK) ? 64 :
+	       (dmamask == DMA_32BIT_MASK) ? 32 : 30);
+	err = 0;
+      out:
+	return err;
+
+      err_destroy_rx0:
+	b43_destroy_dmaring(dma->rx_ring0);
+	dma->rx_ring0 = NULL;
+      err_destroy_tx5:
+	b43_destroy_dmaring(dma->tx_ring5);
+	dma->tx_ring5 = NULL;
+      err_destroy_tx4:
+	b43_destroy_dmaring(dma->tx_ring4);
+	dma->tx_ring4 = NULL;
+      err_destroy_tx3:
+	b43_destroy_dmaring(dma->tx_ring3);
+	dma->tx_ring3 = NULL;
+      err_destroy_tx2:
+	b43_destroy_dmaring(dma->tx_ring2);
+	dma->tx_ring2 = NULL;
+      err_destroy_tx1:
+	b43_destroy_dmaring(dma->tx_ring1);
+	dma->tx_ring1 = NULL;
+      err_destroy_tx0:
+	b43_destroy_dmaring(dma->tx_ring0);
+	dma->tx_ring0 = NULL;
+	goto out;
+}
+
+/* Generate a cookie for the TX header. */
+static u16 generate_cookie(struct b43_dmaring *ring, int slot)
+{
+	u16 cookie = 0x1000;
+
+	/* Use the upper 4 bits of the cookie as
+	 * DMA controller ID and store the slot number
+	 * in the lower 12 bits.
+	 * Note that the cookie must never be 0, as this
+	 * is a special value used in RX path.
+	 */
+	switch (ring->index) {
+	case 0:
+		cookie = 0xA000;
+		break;
+	case 1:
+		cookie = 0xB000;
+		break;
+	case 2:
+		cookie = 0xC000;
+		break;
+	case 3:
+		cookie = 0xD000;
+		break;
+	case 4:
+		cookie = 0xE000;
+		break;
+	case 5:
+		cookie = 0xF000;
+		break;
+	}
+	B43_WARN_ON(slot & ~0x0FFF);
+	cookie |= (u16) slot;
+
+	return cookie;
+}
+
+/* Inspect a cookie and find out to which controller/slot it belongs. */
+static
+struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
+{
+	struct b43_dma *dma = &dev->dma;
+	struct b43_dmaring *ring = NULL;
+
+	switch (cookie & 0xF000) {
+	case 0xA000:
+		ring = dma->tx_ring0;
+		break;
+	case 0xB000:
+		ring = dma->tx_ring1;
+		break;
+	case 0xC000:
+		ring = dma->tx_ring2;
+		break;
+	case 0xD000:
+		ring = dma->tx_ring3;
+		break;
+	case 0xE000:
+		ring = dma->tx_ring4;
+		break;
+	case 0xF000:
+		ring = dma->tx_ring5;
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+	*slot = (cookie & 0x0FFF);
+	B43_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots));
+
+	return ring;
+}
+
+static int dma_tx_fragment(struct b43_dmaring *ring,
+			   struct sk_buff *skb,
+			   struct ieee80211_tx_control *ctl)
+{
+	const struct b43_dma_ops *ops = ring->ops;
+	u8 *header;
+	int slot;
+	int err;
+	struct b43_dmadesc_generic *desc;
+	struct b43_dmadesc_meta *meta;
+	struct b43_dmadesc_meta *meta_hdr;
+	struct sk_buff *bounce_skb;
+
+#define SLOTS_PER_PACKET  2
+	B43_WARN_ON(skb_shinfo(skb)->nr_frags);
+
+	/* Get a slot for the header. */
+	slot = request_slot(ring);
+	desc = ops->idx2desc(ring, slot, &meta_hdr);
+	memset(meta_hdr, 0, sizeof(*meta_hdr));
+
+	header = &(ring->txhdr_cache[slot * sizeof(struct b43_txhdr_fw4)]);
+	b43_generate_txhdr(ring->dev, header,
+			   skb->data, skb->len, ctl,
+			   generate_cookie(ring, slot));
+
+	meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
+					   sizeof(struct b43_txhdr_fw4), 1);
+	if (dma_mapping_error(meta_hdr->dmaaddr))
+		return -EIO;
+	ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
+			     sizeof(struct b43_txhdr_fw4), 1, 0, 0);
+
+	/* Get a slot for the payload. */
+	slot = request_slot(ring);
+	desc = ops->idx2desc(ring, slot, &meta);
+	memset(meta, 0, sizeof(*meta));
+
+	memcpy(&meta->txstat.control, ctl, sizeof(*ctl));
+	meta->skb = skb;
+	meta->is_last_fragment = 1;
+
+	meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+	/* create a bounce buffer in zone_dma on mapping failure. */
+	if (dma_mapping_error(meta->dmaaddr)) {
+		bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
+		if (!bounce_skb) {
+			err = -ENOMEM;
+			goto out_unmap_hdr;
+		}
+
+		memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
+		dev_kfree_skb_any(skb);
+		skb = bounce_skb;
+		meta->skb = skb;
+		meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+		if (dma_mapping_error(meta->dmaaddr)) {
+			err = -EIO;
+			goto out_free_bounce;
+		}
+	}
+
+	ops->fill_descriptor(ring, desc, meta->dmaaddr, skb->len, 0, 1, 1);
+
+	/* Now transfer the whole frame. */
+	wmb();
+	ops->poke_tx(ring, next_slot(ring, slot));
+	return 0;
+
+      out_free_bounce:
+	dev_kfree_skb_any(skb);
+      out_unmap_hdr:
+	unmap_descbuffer(ring, meta_hdr->dmaaddr,
+			 sizeof(struct b43_txhdr_fw4), 1);
+	return err;
+}
+
+static inline int should_inject_overflow(struct b43_dmaring *ring)
+{
+#ifdef CONFIG_B43_DEBUG
+	if (unlikely(b43_debug(ring->dev, B43_DBG_DMAOVERFLOW))) {
+		/* Check if we should inject another ringbuffer overflow
+		 * to test handling of this situation in the stack. */
+		unsigned long next_overflow;
+
+		next_overflow = ring->last_injected_overflow + HZ;
+		if (time_after(jiffies, next_overflow)) {
+			ring->last_injected_overflow = jiffies;
+			b43dbg(ring->dev->wl,
+			       "Injecting TX ring overflow on "
+			       "DMA controller %d\n", ring->index);
+			return 1;
+		}
+	}
+#endif /* CONFIG_B43_DEBUG */
+	return 0;
+}
+
+int b43_dma_tx(struct b43_wldev *dev,
+	       struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+	struct b43_dmaring *ring;
+	int err = 0;
+	unsigned long flags;
+
+	ring = priority_to_txring(dev, ctl->queue);
+	spin_lock_irqsave(&ring->lock, flags);
+	B43_WARN_ON(!ring->tx);
+	if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
+		b43warn(dev->wl, "DMA queue overflow\n");
+		err = -ENOSPC;
+		goto out_unlock;
+	}
+	/* Check if the queue was stopped in mac80211,
+	 * but we got called nevertheless.
+	 * That would be a mac80211 bug. */
+	B43_WARN_ON(ring->stopped);
+
+	err = dma_tx_fragment(ring, skb, ctl);
+	if (unlikely(err)) {
+		b43err(dev->wl, "DMA tx mapping failure\n");
+		goto out_unlock;
+	}
+	ring->nr_tx_packets++;
+	if ((free_slots(ring) < SLOTS_PER_PACKET) ||
+	    should_inject_overflow(ring)) {
+		/* This TX ring is full. */
+		ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring));
+		ring->stopped = 1;
+		if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
+			b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
+		}
+	}
+      out_unlock:
+	spin_unlock_irqrestore(&ring->lock, flags);
+
+	return err;
+}
+
+void b43_dma_handle_txstatus(struct b43_wldev *dev,
+			     const struct b43_txstatus *status)
+{
+	const struct b43_dma_ops *ops;
+	struct b43_dmaring *ring;
+	struct b43_dmadesc_generic *desc;
+	struct b43_dmadesc_meta *meta;
+	int slot;
+
+	ring = parse_cookie(dev, status->cookie, &slot);
+	if (unlikely(!ring))
+		return;
+	B43_WARN_ON(!irqs_disabled());
+	spin_lock(&ring->lock);
+
+	B43_WARN_ON(!ring->tx);
+	ops = ring->ops;
+	while (1) {
+		B43_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+		desc = ops->idx2desc(ring, slot, &meta);
+
+		if (meta->skb)
+			unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len,
+					 1);
+		else
+			unmap_descbuffer(ring, meta->dmaaddr,
+					 sizeof(struct b43_txhdr_fw4), 1);
+
+		if (meta->is_last_fragment) {
+			B43_WARN_ON(!meta->skb);
+			/* Call back to inform the ieee80211 subsystem about the
+			 * status of the transmission.
+			 * Some fields of txstat are already filled in dma_tx().
+			 */
+			if (status->acked) {
+				meta->txstat.flags |= IEEE80211_TX_STATUS_ACK;
+			} else {
+				if (!(meta->txstat.control.flags
+				      & IEEE80211_TXCTL_NO_ACK))
+					meta->txstat.excessive_retries = 1;
+			}
+			if (status->frame_count == 0) {
+				/* The frame was not transmitted at all. */
+				meta->txstat.retry_count = 0;
+			} else
+				meta->txstat.retry_count = status->frame_count - 1;
+			ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb,
+						    &(meta->txstat));
+			/* skb is freed by ieee80211_tx_status_irqsafe() */
+			meta->skb = NULL;
+		} else {
+			/* No need to call free_descriptor_buffer here, as
+			 * this is only the txhdr, which is not allocated.
+			 */
+			B43_WARN_ON(meta->skb);
+		}
+
+		/* Everything unmapped and free'd. So it's not used anymore. */
+		ring->used_slots--;
+
+		if (meta->is_last_fragment)
+			break;
+		slot = next_slot(ring, slot);
+	}
+	dev->stats.last_tx = jiffies;
+	if (ring->stopped) {
+		B43_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET);
+		ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring));
+		ring->stopped = 0;
+		if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
+			b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index);
+		}
+	}
+
+	spin_unlock(&ring->lock);
+}
+
+void b43_dma_get_tx_stats(struct b43_wldev *dev,
+			  struct ieee80211_tx_queue_stats *stats)
+{
+	const int nr_queues = dev->wl->hw->queues;
+	struct b43_dmaring *ring;
+	struct ieee80211_tx_queue_stats_data *data;
+	unsigned long flags;
+	int i;
+
+	for (i = 0; i < nr_queues; i++) {
+		data = &(stats->data[i]);
+		ring = priority_to_txring(dev, i);
+
+		spin_lock_irqsave(&ring->lock, flags);
+		data->len = ring->used_slots / SLOTS_PER_PACKET;
+		data->limit = ring->nr_slots / SLOTS_PER_PACKET;
+		data->count = ring->nr_tx_packets;
+		spin_unlock_irqrestore(&ring->lock, flags);
+	}
+}
+
+static void dma_rx(struct b43_dmaring *ring, int *slot)
+{
+	const struct b43_dma_ops *ops = ring->ops;
+	struct b43_dmadesc_generic *desc;
+	struct b43_dmadesc_meta *meta;
+	struct b43_rxhdr_fw4 *rxhdr;
+	struct sk_buff *skb;
+	u16 len;
+	int err;
+	dma_addr_t dmaaddr;
+
+	desc = ops->idx2desc(ring, *slot, &meta);
+
+	sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
+	skb = meta->skb;
+
+	if (ring->index == 3) {
+		/* We received an xmit status. */
+		struct b43_hwtxstatus *hw = (struct b43_hwtxstatus *)skb->data;
+		int i = 0;
+
+		while (hw->cookie == 0) {
+			if (i > 100)
+				break;
+			i++;
+			udelay(2);
+			barrier();
+		}
+		b43_handle_hwtxstatus(ring->dev, hw);
+		/* recycle the descriptor buffer. */
+		sync_descbuffer_for_device(ring, meta->dmaaddr,
+					   ring->rx_buffersize);
+
+		return;
+	}
+	rxhdr = (struct b43_rxhdr_fw4 *)skb->data;
+	len = le16_to_cpu(rxhdr->frame_len);
+	if (len == 0) {
+		int i = 0;
+
+		do {
+			udelay(2);
+			barrier();
+			len = le16_to_cpu(rxhdr->frame_len);
+		} while (len == 0 && i++ < 5);
+		if (unlikely(len == 0)) {
+			/* recycle the descriptor buffer. */
+			sync_descbuffer_for_device(ring, meta->dmaaddr,
+						   ring->rx_buffersize);
+			goto drop;
+		}
+	}
+	if (unlikely(len > ring->rx_buffersize)) {
+		/* The data did not fit into one descriptor buffer
+		 * and is split over multiple buffers.
+		 * This should never happen, as we try to allocate buffers
+		 * big enough. So simply ignore this packet.
+		 */
+		int cnt = 0;
+		s32 tmp = len;
+
+		while (1) {
+			desc = ops->idx2desc(ring, *slot, &meta);
+			/* recycle the descriptor buffer. */
+			sync_descbuffer_for_device(ring, meta->dmaaddr,
+						   ring->rx_buffersize);
+			*slot = next_slot(ring, *slot);
+			cnt++;
+			tmp -= ring->rx_buffersize;
+			if (tmp <= 0)
+				break;
+		}
+		b43err(ring->dev->wl, "DMA RX buffer too small "
+		       "(len: %u, buffer: %u, nr-dropped: %d)\n",
+		       len, ring->rx_buffersize, cnt);
+		goto drop;
+	}
+
+	dmaaddr = meta->dmaaddr;
+	err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC);
+	if (unlikely(err)) {
+		b43dbg(ring->dev->wl, "DMA RX: setup_rx_descbuffer() failed\n");
+		sync_descbuffer_for_device(ring, dmaaddr, ring->rx_buffersize);
+		goto drop;
+	}
+
+	unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
+	skb_put(skb, len + ring->frameoffset);
+	skb_pull(skb, ring->frameoffset);
+
+	b43_rx(ring->dev, skb, rxhdr);
+      drop:
+	return;
+}
+
+void b43_dma_rx(struct b43_dmaring *ring)
+{
+	const struct b43_dma_ops *ops = ring->ops;
+	int slot, current_slot;
+	int used_slots = 0;
+
+	B43_WARN_ON(ring->tx);
+	current_slot = ops->get_current_rxslot(ring);
+	B43_WARN_ON(!(current_slot >= 0 && current_slot < ring->nr_slots));
+
+	slot = ring->current_slot;
+	for (; slot != current_slot; slot = next_slot(ring, slot)) {
+		dma_rx(ring, &slot);
+		update_max_used_slots(ring, ++used_slots);
+	}
+	ops->set_current_rxslot(ring, slot);
+	ring->current_slot = slot;
+}
+
+static void b43_dma_tx_suspend_ring(struct b43_dmaring *ring)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ring->lock, flags);
+	B43_WARN_ON(!ring->tx);
+	ring->ops->tx_suspend(ring);
+	spin_unlock_irqrestore(&ring->lock, flags);
+}
+
+static void b43_dma_tx_resume_ring(struct b43_dmaring *ring)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ring->lock, flags);
+	B43_WARN_ON(!ring->tx);
+	ring->ops->tx_resume(ring);
+	spin_unlock_irqrestore(&ring->lock, flags);
+}
+
+void b43_dma_tx_suspend(struct b43_wldev *dev)
+{
+	b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
+	b43_dma_tx_suspend_ring(dev->dma.tx_ring0);
+	b43_dma_tx_suspend_ring(dev->dma.tx_ring1);
+	b43_dma_tx_suspend_ring(dev->dma.tx_ring2);
+	b43_dma_tx_suspend_ring(dev->dma.tx_ring3);
+	b43_dma_tx_suspend_ring(dev->dma.tx_ring4);
+	b43_dma_tx_suspend_ring(dev->dma.tx_ring5);
+}
+
+void b43_dma_tx_resume(struct b43_wldev *dev)
+{
+	b43_dma_tx_resume_ring(dev->dma.tx_ring5);
+	b43_dma_tx_resume_ring(dev->dma.tx_ring4);
+	b43_dma_tx_resume_ring(dev->dma.tx_ring3);
+	b43_dma_tx_resume_ring(dev->dma.tx_ring2);
+	b43_dma_tx_resume_ring(dev->dma.tx_ring1);
+	b43_dma_tx_resume_ring(dev->dma.tx_ring0);
+	b43_power_saving_ctl_bits(dev, 0);
+}
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h
new file mode 100644
index 0000000..3eed185
--- /dev/null
+++ b/drivers/net/wireless/b43/dma.h
@@ -0,0 +1,337 @@
+#ifndef B43_DMA_H_
+#define B43_DMA_H_
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/linkage.h>
+#include <asm/atomic.h>
+
+#include "b43.h"
+
+/* DMA-Interrupt reasons. */
+#define B43_DMAIRQ_FATALMASK	((1 << 10) | (1 << 11) | (1 << 12) \
+					 | (1 << 14) | (1 << 15))
+#define B43_DMAIRQ_NONFATALMASK	(1 << 13)
+#define B43_DMAIRQ_RX_DONE		(1 << 16)
+
+/*** 32-bit DMA Engine. ***/
+
+/* 32-bit DMA controller registers. */
+#define B43_DMA32_TXCTL				0x00
+#define		B43_DMA32_TXENABLE			0x00000001
+#define		B43_DMA32_TXSUSPEND			0x00000002
+#define		B43_DMA32_TXLOOPBACK		0x00000004
+#define		B43_DMA32_TXFLUSH			0x00000010
+#define		B43_DMA32_TXADDREXT_MASK		0x00030000
+#define		B43_DMA32_TXADDREXT_SHIFT		16
+#define B43_DMA32_TXRING				0x04
+#define B43_DMA32_TXINDEX				0x08
+#define B43_DMA32_TXSTATUS				0x0C
+#define		B43_DMA32_TXDPTR			0x00000FFF
+#define		B43_DMA32_TXSTATE			0x0000F000
+#define			B43_DMA32_TXSTAT_DISABLED	0x00000000
+#define			B43_DMA32_TXSTAT_ACTIVE	0x00001000
+#define			B43_DMA32_TXSTAT_IDLEWAIT	0x00002000
+#define			B43_DMA32_TXSTAT_STOPPED	0x00003000
+#define			B43_DMA32_TXSTAT_SUSP	0x00004000
+#define		B43_DMA32_TXERROR			0x000F0000
+#define			B43_DMA32_TXERR_NOERR	0x00000000
+#define			B43_DMA32_TXERR_PROT	0x00010000
+#define			B43_DMA32_TXERR_UNDERRUN	0x00020000
+#define			B43_DMA32_TXERR_BUFREAD	0x00030000
+#define			B43_DMA32_TXERR_DESCREAD	0x00040000
+#define		B43_DMA32_TXACTIVE			0xFFF00000
+#define B43_DMA32_RXCTL				0x10
+#define		B43_DMA32_RXENABLE			0x00000001
+#define		B43_DMA32_RXFROFF_MASK		0x000000FE
+#define		B43_DMA32_RXFROFF_SHIFT		1
+#define		B43_DMA32_RXDIRECTFIFO		0x00000100
+#define		B43_DMA32_RXADDREXT_MASK		0x00030000
+#define		B43_DMA32_RXADDREXT_SHIFT		16
+#define B43_DMA32_RXRING				0x14
+#define B43_DMA32_RXINDEX				0x18
+#define B43_DMA32_RXSTATUS				0x1C
+#define		B43_DMA32_RXDPTR			0x00000FFF
+#define		B43_DMA32_RXSTATE			0x0000F000
+#define			B43_DMA32_RXSTAT_DISABLED	0x00000000
+#define			B43_DMA32_RXSTAT_ACTIVE	0x00001000
+#define			B43_DMA32_RXSTAT_IDLEWAIT	0x00002000
+#define			B43_DMA32_RXSTAT_STOPPED	0x00003000
+#define		B43_DMA32_RXERROR			0x000F0000
+#define			B43_DMA32_RXERR_NOERR	0x00000000
+#define			B43_DMA32_RXERR_PROT	0x00010000
+#define			B43_DMA32_RXERR_OVERFLOW	0x00020000
+#define			B43_DMA32_RXERR_BUFWRITE	0x00030000
+#define			B43_DMA32_RXERR_DESCREAD	0x00040000
+#define		B43_DMA32_RXACTIVE			0xFFF00000
+
+/* 32-bit DMA descriptor. */
+struct b43_dmadesc32 {
+	__le32 control;
+	__le32 address;
+} __attribute__ ((__packed__));
+#define B43_DMA32_DCTL_BYTECNT		0x00001FFF
+#define B43_DMA32_DCTL_ADDREXT_MASK		0x00030000
+#define B43_DMA32_DCTL_ADDREXT_SHIFT	16
+#define B43_DMA32_DCTL_DTABLEEND		0x10000000
+#define B43_DMA32_DCTL_IRQ			0x20000000
+#define B43_DMA32_DCTL_FRAMEEND		0x40000000
+#define B43_DMA32_DCTL_FRAMESTART		0x80000000
+
+/*** 64-bit DMA Engine. ***/
+
+/* 64-bit DMA controller registers. */
+#define B43_DMA64_TXCTL				0x00
+#define		B43_DMA64_TXENABLE			0x00000001
+#define		B43_DMA64_TXSUSPEND			0x00000002
+#define		B43_DMA64_TXLOOPBACK		0x00000004
+#define		B43_DMA64_TXFLUSH			0x00000010
+#define		B43_DMA64_TXADDREXT_MASK		0x00030000
+#define		B43_DMA64_TXADDREXT_SHIFT		16
+#define B43_DMA64_TXINDEX				0x04
+#define B43_DMA64_TXRINGLO				0x08
+#define B43_DMA64_TXRINGHI				0x0C
+#define B43_DMA64_TXSTATUS				0x10
+#define		B43_DMA64_TXSTATDPTR		0x00001FFF
+#define		B43_DMA64_TXSTAT			0xF0000000
+#define			B43_DMA64_TXSTAT_DISABLED	0x00000000
+#define			B43_DMA64_TXSTAT_ACTIVE	0x10000000
+#define			B43_DMA64_TXSTAT_IDLEWAIT	0x20000000
+#define			B43_DMA64_TXSTAT_STOPPED	0x30000000
+#define			B43_DMA64_TXSTAT_SUSP	0x40000000
+#define B43_DMA64_TXERROR				0x14
+#define		B43_DMA64_TXERRDPTR			0x0001FFFF
+#define		B43_DMA64_TXERR			0xF0000000
+#define			B43_DMA64_TXERR_NOERR	0x00000000
+#define			B43_DMA64_TXERR_PROT	0x10000000
+#define			B43_DMA64_TXERR_UNDERRUN	0x20000000
+#define			B43_DMA64_TXERR_TRANSFER	0x30000000
+#define			B43_DMA64_TXERR_DESCREAD	0x40000000
+#define			B43_DMA64_TXERR_CORE	0x50000000
+#define B43_DMA64_RXCTL				0x20
+#define		B43_DMA64_RXENABLE			0x00000001
+#define		B43_DMA64_RXFROFF_MASK		0x000000FE
+#define		B43_DMA64_RXFROFF_SHIFT		1
+#define		B43_DMA64_RXDIRECTFIFO		0x00000100
+#define		B43_DMA64_RXADDREXT_MASK		0x00030000
+#define		B43_DMA64_RXADDREXT_SHIFT		16
+#define B43_DMA64_RXINDEX				0x24
+#define B43_DMA64_RXRINGLO				0x28
+#define B43_DMA64_RXRINGHI				0x2C
+#define B43_DMA64_RXSTATUS				0x30
+#define		B43_DMA64_RXSTATDPTR		0x00001FFF
+#define		B43_DMA64_RXSTAT			0xF0000000
+#define			B43_DMA64_RXSTAT_DISABLED	0x00000000
+#define			B43_DMA64_RXSTAT_ACTIVE	0x10000000
+#define			B43_DMA64_RXSTAT_IDLEWAIT	0x20000000
+#define			B43_DMA64_RXSTAT_STOPPED	0x30000000
+#define			B43_DMA64_RXSTAT_SUSP	0x40000000
+#define B43_DMA64_RXERROR				0x34
+#define		B43_DMA64_RXERRDPTR			0x0001FFFF
+#define		B43_DMA64_RXERR			0xF0000000
+#define			B43_DMA64_RXERR_NOERR	0x00000000
+#define			B43_DMA64_RXERR_PROT	0x10000000
+#define			B43_DMA64_RXERR_UNDERRUN	0x20000000
+#define			B43_DMA64_RXERR_TRANSFER	0x30000000
+#define			B43_DMA64_RXERR_DESCREAD	0x40000000
+#define			B43_DMA64_RXERR_CORE	0x50000000
+
+/* 64-bit DMA descriptor. */
+struct b43_dmadesc64 {
+	__le32 control0;
+	__le32 control1;
+	__le32 address_low;
+	__le32 address_high;
+} __attribute__ ((__packed__));
+#define B43_DMA64_DCTL0_DTABLEEND		0x10000000
+#define B43_DMA64_DCTL0_IRQ			0x20000000
+#define B43_DMA64_DCTL0_FRAMEEND		0x40000000
+#define B43_DMA64_DCTL0_FRAMESTART		0x80000000
+#define B43_DMA64_DCTL1_BYTECNT		0x00001FFF
+#define B43_DMA64_DCTL1_ADDREXT_MASK	0x00030000
+#define B43_DMA64_DCTL1_ADDREXT_SHIFT	16
+
+struct b43_dmadesc_generic {
+	union {
+		struct b43_dmadesc32 dma32;
+		struct b43_dmadesc64 dma64;
+	} __attribute__ ((__packed__));
+} __attribute__ ((__packed__));
+
+/* Misc DMA constants */
+#define B43_DMA_RINGMEMSIZE		PAGE_SIZE
+#define B43_DMA0_RX_FRAMEOFFSET	30
+#define B43_DMA3_RX_FRAMEOFFSET	0
+
+/* DMA engine tuning knobs */
+#define B43_TXRING_SLOTS		128
+#define B43_RXRING_SLOTS		64
+#define B43_DMA0_RX_BUFFERSIZE	(2304 + 100)
+#define B43_DMA3_RX_BUFFERSIZE	16
+
+#ifdef CONFIG_B43_DMA
+
+struct sk_buff;
+struct b43_private;
+struct b43_txstatus;
+
+struct b43_dmadesc_meta {
+	/* The kernel DMA-able buffer. */
+	struct sk_buff *skb;
+	/* DMA base bus-address of the descriptor buffer. */
+	dma_addr_t dmaaddr;
+	/* ieee80211 TX status. Only used once per 802.11 frag. */
+	bool is_last_fragment;
+	struct ieee80211_tx_status txstat;
+};
+
+struct b43_dmaring;
+
+/* Lowlevel DMA operations that differ between 32bit and 64bit DMA. */
+struct b43_dma_ops {
+	struct b43_dmadesc_generic *(*idx2desc) (struct b43_dmaring * ring,
+						 int slot,
+						 struct b43_dmadesc_meta **
+						 meta);
+	void (*fill_descriptor) (struct b43_dmaring * ring,
+				 struct b43_dmadesc_generic * desc,
+				 dma_addr_t dmaaddr, u16 bufsize, int start,
+				 int end, int irq);
+	void (*poke_tx) (struct b43_dmaring * ring, int slot);
+	void (*tx_suspend) (struct b43_dmaring * ring);
+	void (*tx_resume) (struct b43_dmaring * ring);
+	int (*get_current_rxslot) (struct b43_dmaring * ring);
+	void (*set_current_rxslot) (struct b43_dmaring * ring, int slot);
+};
+
+struct b43_dmaring {
+	/* Lowlevel DMA ops. */
+	const struct b43_dma_ops *ops;
+	/* Kernel virtual base address of the ring memory. */
+	void *descbase;
+	/* Meta data about all descriptors. */
+	struct b43_dmadesc_meta *meta;
+	/* Cache of TX headers for each slot.
+	 * This is to avoid an allocation on each TX.
+	 * This is NULL for an RX ring.
+	 */
+	u8 *txhdr_cache;
+	/* (Unadjusted) DMA base bus-address of the ring memory. */
+	dma_addr_t dmabase;
+	/* Number of descriptor slots in the ring. */
+	int nr_slots;
+	/* Number of used descriptor slots. */
+	int used_slots;
+	/* Currently used slot in the ring. */
+	int current_slot;
+	/* Total number of packets sent. Statistics only. */
+	unsigned int nr_tx_packets;
+	/* Frameoffset in octets. */
+	u32 frameoffset;
+	/* Descriptor buffer size. */
+	u16 rx_buffersize;
+	/* The MMIO base register of the DMA controller. */
+	u16 mmio_base;
+	/* DMA controller index number (0-5). */
+	int index;
+	/* Boolean. Is this a TX ring? */
+	bool tx;
+	/* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
+	bool dma64;
+	/* Boolean. Is this ring stopped at ieee80211 level? */
+	bool stopped;
+	/* Lock, only used for TX. */
+	spinlock_t lock;
+	struct b43_wldev *dev;
+#ifdef CONFIG_B43_DEBUG
+	/* Maximum number of used slots. */
+	int max_used_slots;
+	/* Last time we injected a ring overflow. */
+	unsigned long last_injected_overflow;
+#endif				/* CONFIG_B43_DEBUG */
+};
+
+static inline u32 b43_dma_read(struct b43_dmaring *ring, u16 offset)
+{
+	return b43_read32(ring->dev, ring->mmio_base + offset);
+}
+
+static inline
+    void b43_dma_write(struct b43_dmaring *ring, u16 offset, u32 value)
+{
+	b43_write32(ring->dev, ring->mmio_base + offset, value);
+}
+
+int b43_dma_init(struct b43_wldev *dev);
+void b43_dma_free(struct b43_wldev *dev);
+
+int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
+			       u16 dmacontroller_mmio_base, int dma64);
+int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
+			       u16 dmacontroller_mmio_base, int dma64);
+
+u16 b43_dmacontroller_base(int dma64bit, int dmacontroller_idx);
+
+void b43_dma_tx_suspend(struct b43_wldev *dev);
+void b43_dma_tx_resume(struct b43_wldev *dev);
+
+void b43_dma_get_tx_stats(struct b43_wldev *dev,
+			  struct ieee80211_tx_queue_stats *stats);
+
+int b43_dma_tx(struct b43_wldev *dev,
+	       struct sk_buff *skb, struct ieee80211_tx_control *ctl);
+void b43_dma_handle_txstatus(struct b43_wldev *dev,
+			     const struct b43_txstatus *status);
+
+void b43_dma_rx(struct b43_dmaring *ring);
+
+#else /* CONFIG_B43_DMA */
+
+static inline int b43_dma_init(struct b43_wldev *dev)
+{
+	return 0;
+}
+static inline void b43_dma_free(struct b43_wldev *dev)
+{
+}
+static inline
+    int b43_dmacontroller_rx_reset(struct b43_wldev *dev,
+				   u16 dmacontroller_mmio_base, int dma64)
+{
+	return 0;
+}
+static inline
+    int b43_dmacontroller_tx_reset(struct b43_wldev *dev,
+				   u16 dmacontroller_mmio_base, int dma64)
+{
+	return 0;
+}
+static inline
+    void b43_dma_get_tx_stats(struct b43_wldev *dev,
+			      struct ieee80211_tx_queue_stats *stats)
+{
+}
+static inline
+    int b43_dma_tx(struct b43_wldev *dev,
+		   struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+	return 0;
+}
+static inline
+    void b43_dma_handle_txstatus(struct b43_wldev *dev,
+				 const struct b43_txstatus *status)
+{
+}
+static inline void b43_dma_rx(struct b43_dmaring *ring)
+{
+}
+static inline void b43_dma_tx_suspend(struct b43_wldev *dev)
+{
+}
+static inline void b43_dma_tx_resume(struct b43_wldev *dev)
+{
+}
+
+#endif /* CONFIG_B43_DMA */
+#endif /* B43_DMA_H_ */
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c
new file mode 100644
index 0000000..19e5885
--- /dev/null
+++ b/drivers/net/wireless/b43/leds.c
@@ -0,0 +1,235 @@
+/*
+
+  Broadcom B43 wireless driver
+  LED control
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+  Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
+  Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+  Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "leds.h"
+
+
+static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index,
+			    bool activelow)
+{
+	struct b43_wl *wl = dev->wl;
+	unsigned long flags;
+	u16 ctl;
+
+	spin_lock_irqsave(&wl->leds_lock, flags);
+	ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
+	if (activelow)
+		ctl &= ~(1 << led_index);
+	else
+		ctl |= (1 << led_index);
+	b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl);
+	spin_unlock_irqrestore(&wl->leds_lock, flags);
+}
+
+static void b43_led_turn_off(struct b43_wldev *dev, u8 led_index,
+			     bool activelow)
+{
+	struct b43_wl *wl = dev->wl;
+	unsigned long flags;
+	u16 ctl;
+
+	spin_lock_irqsave(&wl->leds_lock, flags);
+	ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
+	if (activelow)
+		ctl |= (1 << led_index);
+	else
+		ctl &= ~(1 << led_index);
+	b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl);
+	spin_unlock_irqrestore(&wl->leds_lock, flags);
+}
+
+/* Callback from the LED subsystem. */
+static void b43_led_brightness_set(struct led_classdev *led_dev,
+				   enum led_brightness brightness)
+{
+	struct b43_led *led = container_of(led_dev, struct b43_led, led_dev);
+	struct b43_wldev *dev = led->dev;
+	bool radio_enabled;
+
+	/* Checking the radio-enabled status here is slightly racy,
+	 * but we want to avoid the locking overhead and we don't care
+	 * whether the LED has the wrong state for a second. */
+	radio_enabled = (dev->phy.radio_on && dev->radio_hw_enable);
+
+	if (brightness == LED_OFF || !radio_enabled)
+		b43_led_turn_off(dev, led->index, led->activelow);
+	else
+		b43_led_turn_on(dev, led->index, led->activelow);
+}
+
+static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
+			    const char *name, char *default_trigger,
+			    u8 led_index, bool activelow)
+{
+	int err;
+
+	b43_led_turn_off(dev, led_index, activelow);
+	if (led->dev)
+		return -EEXIST;
+	if (!default_trigger)
+		return -EINVAL;
+	led->dev = dev;
+	led->index = led_index;
+	led->activelow = activelow;
+	strncpy(led->name, name, sizeof(led->name));
+
+	led->led_dev.name = led->name;
+	led->led_dev.default_trigger = default_trigger;
+	led->led_dev.brightness_set = b43_led_brightness_set;
+
+	err = led_classdev_register(dev->dev->dev, &led->led_dev);
+	if (err) {
+		b43warn(dev->wl, "LEDs: Failed to register %s\n", name);
+		led->dev = NULL;
+		return err;
+	}
+	return 0;
+}
+
+static void b43_unregister_led(struct b43_led *led)
+{
+	if (!led->dev)
+		return;
+	led_classdev_unregister(&led->led_dev);
+	b43_led_turn_off(led->dev, led->index, led->activelow);
+	led->dev = NULL;
+}
+
+static void b43_map_led(struct b43_wldev *dev,
+			u8 led_index,
+			enum b43_led_behaviour behaviour,
+			bool activelow)
+{
+	struct ieee80211_hw *hw = dev->wl->hw;
+	char name[B43_LED_MAX_NAME_LEN + 1];
+
+	/* Map the b43 specific LED behaviour value to the
+	 * generic LED triggers. */
+	switch (behaviour) {
+	case B43_LED_INACTIVE:
+		break;
+	case B43_LED_OFF:
+		b43_led_turn_off(dev, led_index, activelow);
+		break;
+	case B43_LED_ON:
+		b43_led_turn_on(dev, led_index, activelow);
+		break;
+	case B43_LED_ACTIVITY:
+	case B43_LED_TRANSFER:
+	case B43_LED_APTRANSFER:
+		snprintf(name, sizeof(name),
+			 "b43-%s:tx", wiphy_name(hw->wiphy));
+		b43_register_led(dev, &dev->led_tx, name,
+				 ieee80211_get_tx_led_name(hw),
+				 led_index, activelow);
+		snprintf(name, sizeof(name),
+			 "b43-%s:rx", wiphy_name(hw->wiphy));
+		b43_register_led(dev, &dev->led_rx, name,
+				 ieee80211_get_rx_led_name(hw),
+				 led_index, activelow);
+		break;
+	case B43_LED_RADIO_ALL:
+	case B43_LED_RADIO_A:
+	case B43_LED_RADIO_B:
+	case B43_LED_MODE_BG:
+		snprintf(name, sizeof(name),
+			 "b43-%s:radio", wiphy_name(hw->wiphy));
+		b43_register_led(dev, &dev->led_radio, name,
+				 b43_rfkill_led_name(dev),
+				 led_index, activelow);
+		break;
+	case B43_LED_WEIRD:
+	case B43_LED_ASSOC:
+		snprintf(name, sizeof(name),
+			 "b43-%s:assoc", wiphy_name(hw->wiphy));
+		b43_register_led(dev, &dev->led_assoc, name,
+				 ieee80211_get_assoc_led_name(hw),
+				 led_index, activelow);
+		break;
+	default:
+		b43warn(dev->wl, "LEDs: Unknown behaviour 0x%02X\n",
+			behaviour);
+		break;
+	}
+}
+
+void b43_leds_init(struct b43_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+	u8 sprom[4];
+	int i;
+	enum b43_led_behaviour behaviour;
+	bool activelow;
+
+	sprom[0] = bus->sprom.r1.gpio0;
+	sprom[1] = bus->sprom.r1.gpio1;
+	sprom[2] = bus->sprom.r1.gpio2;
+	sprom[3] = bus->sprom.r1.gpio3;
+
+	for (i = 0; i < 4; i++) {
+		if (sprom[i] == 0xFF) {
+			/* There is no LED information in the SPROM
+			 * for this LED. Hardcode it here. */
+			activelow = 0;
+			switch (i) {
+			case 0:
+				behaviour = B43_LED_ACTIVITY;
+				activelow = 1;
+				if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ)
+					behaviour = B43_LED_RADIO_ALL;
+				break;
+			case 1:
+				behaviour = B43_LED_RADIO_B;
+				if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK)
+					behaviour = B43_LED_ASSOC;
+				break;
+			case 2:
+				behaviour = B43_LED_RADIO_A;
+				break;
+			case 3:
+				behaviour = B43_LED_OFF;
+				break;
+			default:
+				B43_WARN_ON(1);
+				return;
+			}
+		} else {
+			behaviour = sprom[i] & B43_LED_BEHAVIOUR;
+			activelow = !!(sprom[i] & B43_LED_ACTIVELOW);
+		}
+		b43_map_led(dev, i, behaviour, activelow);
+	}
+}
+
+void b43_leds_exit(struct b43_wldev *dev)
+{
+	b43_unregister_led(&dev->led_tx);
+	b43_unregister_led(&dev->led_rx);
+	b43_unregister_led(&dev->led_assoc);
+}
diff --git a/drivers/net/wireless/b43/leds.h b/drivers/net/wireless/b43/leds.h
new file mode 100644
index 0000000..b8b1dd5
--- /dev/null
+++ b/drivers/net/wireless/b43/leds.h
@@ -0,0 +1,64 @@
+#ifndef B43_LEDS_H_
+#define B43_LEDS_H_
+
+struct b43_wldev;
+
+#ifdef CONFIG_B43_LEDS
+
+#include <linux/types.h>
+#include <linux/leds.h>
+
+
+#define B43_LED_MAX_NAME_LEN	31
+
+struct b43_led {
+	struct b43_wldev *dev;
+	/* The LED class device */
+	struct led_classdev led_dev;
+	/* The index number of the LED. */
+	u8 index;
+	/* If activelow is true, the LED is ON if the
+	 * bit is switched off. */
+	bool activelow;
+	/* The unique name string for this LED device. */
+	char name[B43_LED_MAX_NAME_LEN + 1];
+};
+
+#define B43_LED_BEHAVIOUR		0x7F
+#define B43_LED_ACTIVELOW		0x80
+/* LED behaviour values */
+enum b43_led_behaviour {
+	B43_LED_OFF,
+	B43_LED_ON,
+	B43_LED_ACTIVITY,
+	B43_LED_RADIO_ALL,
+	B43_LED_RADIO_A,
+	B43_LED_RADIO_B,
+	B43_LED_MODE_BG,
+	B43_LED_TRANSFER,
+	B43_LED_APTRANSFER,
+	B43_LED_WEIRD,		//FIXME
+	B43_LED_ASSOC,
+	B43_LED_INACTIVE,
+};
+
+void b43_leds_init(struct b43_wldev *dev);
+void b43_leds_exit(struct b43_wldev *dev);
+
+
+#else /* CONFIG_B43_LEDS */
+/* LED support disabled */
+
+struct b43_led {
+	/* empty */
+};
+
+static inline void b43_leds_init(struct b43_wldev *dev)
+{
+}
+static inline void b43_leds_exit(struct b43_wldev *dev)
+{
+}
+#endif /* CONFIG_B43_LEDS */
+
+#endif /* B43_LEDS_H_ */
diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c
new file mode 100644
index 0000000..b14a175
--- /dev/null
+++ b/drivers/net/wireless/b43/lo.c
@@ -0,0 +1,1261 @@
+/*
+
+  Broadcom B43 wireless driver
+
+  G PHY LO (LocalOscillator) Measuring and Control routines
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+  Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
+  Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
+  Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "lo.h"
+#include "phy.h"
+#include "main.h"
+
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+
+/* Define to 1 to always calibrate all possible LO control pairs.
+ * This is a workaround until we fix the partial LO calibration optimization. */
+#define B43_CALIB_ALL_LOCTLS	1
+
+
+/* Write the LocalOscillator Control (adjust) value-pair. */
+static void b43_lo_write(struct b43_wldev *dev, struct b43_loctl *control)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 value;
+	u16 reg;
+
+	if (B43_DEBUG) {
+		if (unlikely(abs(control->i) > 16 || abs(control->q) > 16)) {
+			b43dbg(dev->wl, "Invalid LO control pair "
+			       "(I: %d, Q: %d)\n", control->i, control->q);
+			dump_stack();
+			return;
+		}
+	}
+
+	value = (u8) (control->q);
+	value |= ((u8) (control->i)) << 8;
+
+	reg = (phy->type == B43_PHYTYPE_B) ? 0x002F : B43_PHY_LO_CTL;
+	b43_phy_write(dev, reg, value);
+}
+
+static int assert_rfatt_and_bbatt(const struct b43_rfatt *rfatt,
+				  const struct b43_bbatt *bbatt,
+				  struct b43_wldev *dev)
+{
+	int err = 0;
+
+	/* Check the attenuation values against the LO control array sizes. */
+	if (unlikely(rfatt->att >= B43_NR_RF)) {
+		b43err(dev->wl, "rfatt(%u) >= size of LO array\n", rfatt->att);
+		err = -EINVAL;
+	}
+	if (unlikely(bbatt->att >= B43_NR_BB)) {
+		b43err(dev->wl, "bbatt(%u) >= size of LO array\n", bbatt->att);
+		err = -EINVAL;
+	}
+
+	return err;
+}
+
+#if !B43_CALIB_ALL_LOCTLS
+static
+struct b43_loctl *b43_get_lo_g_ctl_nopadmix(struct b43_wldev *dev,
+					    const struct b43_rfatt *rfatt,
+					    const struct b43_bbatt *bbatt)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_txpower_lo_control *lo = phy->lo_control;
+
+	if (assert_rfatt_and_bbatt(rfatt, bbatt, dev))
+		return &(lo->no_padmix[0][0]);	/* Just prevent a crash */
+	return &(lo->no_padmix[bbatt->att][rfatt->att]);
+}
+#endif /* !B43_CALIB_ALL_LOCTLS */
+
+struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev,
+				   const struct b43_rfatt *rfatt,
+				   const struct b43_bbatt *bbatt)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_txpower_lo_control *lo = phy->lo_control;
+
+	if (assert_rfatt_and_bbatt(rfatt, bbatt, dev))
+		return &(lo->no_padmix[0][0]);	/* Just prevent a crash */
+	if (rfatt->with_padmix)
+		return &(lo->with_padmix[bbatt->att][rfatt->att]);
+	return &(lo->no_padmix[bbatt->att][rfatt->att]);
+}
+
+/* Call a function for every possible LO control value-pair. */
+static void b43_call_for_each_loctl(struct b43_wldev *dev,
+				    void (*func) (struct b43_wldev *,
+						  struct b43_loctl *))
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_txpower_lo_control *ctl = phy->lo_control;
+	int i, j;
+
+	for (i = 0; i < B43_NR_BB; i++) {
+		for (j = 0; j < B43_NR_RF; j++)
+			func(dev, &(ctl->with_padmix[i][j]));
+	}
+	for (i = 0; i < B43_NR_BB; i++) {
+		for (j = 0; j < B43_NR_RF; j++)
+			func(dev, &(ctl->no_padmix[i][j]));
+	}
+}
+
+static u16 lo_b_r15_loop(struct b43_wldev *dev)
+{
+	int i;
+	u16 ret = 0;
+
+	for (i = 0; i < 10; i++) {
+		b43_phy_write(dev, 0x0015, 0xAFA0);
+		udelay(1);
+		b43_phy_write(dev, 0x0015, 0xEFA0);
+		udelay(10);
+		b43_phy_write(dev, 0x0015, 0xFFA0);
+		udelay(40);
+		ret += b43_phy_read(dev, 0x002C);
+	}
+
+	return ret;
+}
+
+void b43_lo_b_measure(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 regstack[12] = { 0 };
+	u16 mls;
+	u16 fval;
+	int i, j;
+
+	regstack[0] = b43_phy_read(dev, 0x0015);
+	regstack[1] = b43_radio_read16(dev, 0x0052) & 0xFFF0;
+
+	if (phy->radio_ver == 0x2053) {
+		regstack[2] = b43_phy_read(dev, 0x000A);
+		regstack[3] = b43_phy_read(dev, 0x002A);
+		regstack[4] = b43_phy_read(dev, 0x0035);
+		regstack[5] = b43_phy_read(dev, 0x0003);
+		regstack[6] = b43_phy_read(dev, 0x0001);
+		regstack[7] = b43_phy_read(dev, 0x0030);
+
+		regstack[8] = b43_radio_read16(dev, 0x0043);
+		regstack[9] = b43_radio_read16(dev, 0x007A);
+		regstack[10] = b43_read16(dev, 0x03EC);
+		regstack[11] = b43_radio_read16(dev, 0x0052) & 0x00F0;
+
+		b43_phy_write(dev, 0x0030, 0x00FF);
+		b43_write16(dev, 0x03EC, 0x3F3F);
+		b43_phy_write(dev, 0x0035, regstack[4] & 0xFF7F);
+		b43_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0);
+	}
+	b43_phy_write(dev, 0x0015, 0xB000);
+	b43_phy_write(dev, 0x002B, 0x0004);
+
+	if (phy->radio_ver == 0x2053) {
+		b43_phy_write(dev, 0x002B, 0x0203);
+		b43_phy_write(dev, 0x002A, 0x08A3);
+	}
+
+	phy->minlowsig[0] = 0xFFFF;
+
+	for (i = 0; i < 4; i++) {
+		b43_radio_write16(dev, 0x0052, regstack[1] | i);
+		lo_b_r15_loop(dev);
+	}
+	for (i = 0; i < 10; i++) {
+		b43_radio_write16(dev, 0x0052, regstack[1] | i);
+		mls = lo_b_r15_loop(dev) / 10;
+		if (mls < phy->minlowsig[0]) {
+			phy->minlowsig[0] = mls;
+			phy->minlowsigpos[0] = i;
+		}
+	}
+	b43_radio_write16(dev, 0x0052, regstack[1] | phy->minlowsigpos[0]);
+
+	phy->minlowsig[1] = 0xFFFF;
+
+	for (i = -4; i < 5; i += 2) {
+		for (j = -4; j < 5; j += 2) {
+			if (j < 0)
+				fval = (0x0100 * i) + j + 0x0100;
+			else
+				fval = (0x0100 * i) + j;
+			b43_phy_write(dev, 0x002F, fval);
+			mls = lo_b_r15_loop(dev) / 10;
+			if (mls < phy->minlowsig[1]) {
+				phy->minlowsig[1] = mls;
+				phy->minlowsigpos[1] = fval;
+			}
+		}
+	}
+	phy->minlowsigpos[1] += 0x0101;
+
+	b43_phy_write(dev, 0x002F, phy->minlowsigpos[1]);
+	if (phy->radio_ver == 0x2053) {
+		b43_phy_write(dev, 0x000A, regstack[2]);
+		b43_phy_write(dev, 0x002A, regstack[3]);
+		b43_phy_write(dev, 0x0035, regstack[4]);
+		b43_phy_write(dev, 0x0003, regstack[5]);
+		b43_phy_write(dev, 0x0001, regstack[6]);
+		b43_phy_write(dev, 0x0030, regstack[7]);
+
+		b43_radio_write16(dev, 0x0043, regstack[8]);
+		b43_radio_write16(dev, 0x007A, regstack[9]);
+
+		b43_radio_write16(dev, 0x0052,
+				  (b43_radio_read16(dev, 0x0052) & 0x000F)
+				  | regstack[11]);
+
+		b43_write16(dev, 0x03EC, regstack[10]);
+	}
+	b43_phy_write(dev, 0x0015, regstack[0]);
+}
+
+static u16 lo_measure_feedthrough(struct b43_wldev *dev,
+				  u16 lna, u16 pga, u16 trsw_rx)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 rfover;
+	u16 feedthrough;
+
+	if (phy->gmode) {
+		lna <<= B43_PHY_RFOVERVAL_LNA_SHIFT;
+		pga <<= B43_PHY_RFOVERVAL_PGA_SHIFT;
+
+		B43_WARN_ON(lna & ~B43_PHY_RFOVERVAL_LNA);
+		B43_WARN_ON(pga & ~B43_PHY_RFOVERVAL_PGA);
+/*FIXME This assertion fails		B43_WARN_ON(trsw_rx & ~(B43_PHY_RFOVERVAL_TRSWRX |
+				    B43_PHY_RFOVERVAL_BW));
+*/
+		trsw_rx &= (B43_PHY_RFOVERVAL_TRSWRX | B43_PHY_RFOVERVAL_BW);
+
+		/* Construct the RF Override Value */
+		rfover = B43_PHY_RFOVERVAL_UNK;
+		rfover |= pga;
+		rfover |= lna;
+		rfover |= trsw_rx;
+		if ((dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) &&
+		    phy->rev > 6)
+			rfover |= B43_PHY_RFOVERVAL_EXTLNA;
+
+		b43_phy_write(dev, B43_PHY_PGACTL, 0xE300);
+		b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover);
+		udelay(10);
+		rfover |= B43_PHY_RFOVERVAL_BW_LBW;
+		b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover);
+		udelay(10);
+		rfover |= B43_PHY_RFOVERVAL_BW_LPF;
+		b43_phy_write(dev, B43_PHY_RFOVERVAL, rfover);
+		udelay(10);
+		b43_phy_write(dev, B43_PHY_PGACTL, 0xF300);
+	} else {
+		pga |= B43_PHY_PGACTL_UNKNOWN;
+		b43_phy_write(dev, B43_PHY_PGACTL, pga);
+		udelay(10);
+		pga |= B43_PHY_PGACTL_LOWBANDW;
+		b43_phy_write(dev, B43_PHY_PGACTL, pga);
+		udelay(10);
+		pga |= B43_PHY_PGACTL_LPF;
+		b43_phy_write(dev, B43_PHY_PGACTL, pga);
+	}
+	udelay(21);
+	feedthrough = b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
+
+	/* This is a good place to check if we need to relax a bit,
+	 * as this is the main function called regularly
+	 * in the LO calibration. */
+	cond_resched();
+
+	return feedthrough;
+}
+
+/* TXCTL Register and Value Table.
+ * Returns the "TXCTL Register".
+ * "value" is the "TXCTL Value".
+ * "pad_mix_gain" is the PAD Mixer Gain.
+ */
+static u16 lo_txctl_register_table(struct b43_wldev *dev,
+				   u16 * value, u16 * pad_mix_gain)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 reg, v, padmix;
+
+	if (phy->type == B43_PHYTYPE_B) {
+		v = 0x30;
+		if (phy->radio_rev <= 5) {
+			reg = 0x43;
+			padmix = 0;
+		} else {
+			reg = 0x52;
+			padmix = 5;
+		}
+	} else {
+		if (phy->rev >= 2 && phy->radio_rev == 8) {
+			reg = 0x43;
+			v = 0x10;
+			padmix = 2;
+		} else {
+			reg = 0x52;
+			v = 0x30;
+			padmix = 5;
+		}
+	}
+	if (value)
+		*value = v;
+	if (pad_mix_gain)
+		*pad_mix_gain = padmix;
+
+	return reg;
+}
+
+static void lo_measure_txctl_values(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_txpower_lo_control *lo = phy->lo_control;
+	u16 reg, mask;
+	u16 trsw_rx, pga;
+	u16 radio_pctl_reg;
+
+	static const u8 tx_bias_values[] = {
+		0x09, 0x08, 0x0A, 0x01, 0x00,
+		0x02, 0x05, 0x04, 0x06,
+	};
+	static const u8 tx_magn_values[] = {
+		0x70, 0x40,
+	};
+
+	if (!has_loopback_gain(phy)) {
+		radio_pctl_reg = 6;
+		trsw_rx = 2;
+		pga = 0;
+	} else {
+		int lb_gain;	/* Loopback gain (in dB) */
+
+		trsw_rx = 0;
+		lb_gain = phy->max_lb_gain / 2;
+		if (lb_gain > 10) {
+			radio_pctl_reg = 0;
+			pga = abs(10 - lb_gain) / 6;
+			pga = limit_value(pga, 0, 15);
+		} else {
+			int cmp_val;
+			int tmp;
+
+			pga = 0;
+			cmp_val = 0x24;
+			if ((phy->rev >= 2) &&
+			    (phy->radio_ver == 0x2050) && (phy->radio_rev == 8))
+				cmp_val = 0x3C;
+			tmp = lb_gain;
+			if ((10 - lb_gain) < cmp_val)
+				tmp = (10 - lb_gain);
+			if (tmp < 0)
+				tmp += 6;
+			else
+				tmp += 3;
+			cmp_val /= 4;
+			tmp /= 4;
+			if (tmp >= cmp_val)
+				radio_pctl_reg = cmp_val;
+			else
+				radio_pctl_reg = tmp;
+		}
+	}
+	b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+				      & 0xFFF0) | radio_pctl_reg);
+	b43_phy_set_baseband_attenuation(dev, 2);
+
+	reg = lo_txctl_register_table(dev, &mask, NULL);
+	mask = ~mask;
+	b43_radio_write16(dev, reg, b43_radio_read16(dev, reg)
+			  & mask);
+
+	if (has_tx_magnification(phy)) {
+		int i, j;
+		int feedthrough;
+		int min_feedth = 0xFFFF;
+		u8 tx_magn, tx_bias;
+
+		for (i = 0; i < ARRAY_SIZE(tx_magn_values); i++) {
+			tx_magn = tx_magn_values[i];
+			b43_radio_write16(dev, 0x52,
+					  (b43_radio_read16(dev, 0x52)
+					   & 0xFF0F) | tx_magn);
+			for (j = 0; j < ARRAY_SIZE(tx_bias_values); j++) {
+				tx_bias = tx_bias_values[j];
+				b43_radio_write16(dev, 0x52,
+						  (b43_radio_read16(dev, 0x52)
+						   & 0xFFF0) | tx_bias);
+				feedthrough =
+				    lo_measure_feedthrough(dev, 0, pga,
+							   trsw_rx);
+				if (feedthrough < min_feedth) {
+					lo->tx_bias = tx_bias;
+					lo->tx_magn = tx_magn;
+					min_feedth = feedthrough;
+				}
+				if (lo->tx_bias == 0)
+					break;
+			}
+			b43_radio_write16(dev, 0x52,
+					  (b43_radio_read16(dev, 0x52)
+					   & 0xFF00) | lo->tx_bias | lo->
+					  tx_magn);
+		}
+	} else {
+		lo->tx_magn = 0;
+		lo->tx_bias = 0;
+		b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52)
+				  & 0xFFF0);	/* TX bias == 0 */
+	}
+}
+
+static void lo_read_power_vector(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_txpower_lo_control *lo = phy->lo_control;
+	u16 i;
+	u64 tmp;
+	u64 power_vector = 0;
+	int rf_offset, bb_offset;
+	struct b43_loctl *loctl;
+
+	for (i = 0; i < 8; i += 2) {
+		tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x310 + i);
+		/* Clear the top byte. We get holes in the bitmap... */
+		tmp &= 0xFF;
+		power_vector |= (tmp << (i * 8));
+		/* Clear the vector on the device. */
+		b43_shm_write16(dev, B43_SHM_SHARED, 0x310 + i, 0);
+	}
+
+	if (power_vector)
+		lo->power_vector = power_vector;
+	power_vector = lo->power_vector;
+
+	for (i = 0; i < 64; i++) {
+		if (power_vector & ((u64) 1ULL << i)) {
+			/* Now figure out which b43_loctl corresponds
+			 * to this bit.
+			 */
+			rf_offset = i / lo->rfatt_list.len;
+			bb_offset = i % lo->rfatt_list.len;	//FIXME?
+			loctl =
+			    b43_get_lo_g_ctl(dev,
+					     &lo->rfatt_list.list[rf_offset],
+					     &lo->bbatt_list.list[bb_offset]);
+			/* And mark it as "used", as the device told us
+			 * through the bitmap it is using it.
+			 */
+			loctl->used = 1;
+		}
+	}
+}
+
+/* 802.11/LO/GPHY/MeasuringGains */
+static void lo_measure_gain_values(struct b43_wldev *dev,
+				   s16 max_rx_gain, int use_trsw_rx)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 tmp;
+
+	if (max_rx_gain < 0)
+		max_rx_gain = 0;
+
+	if (has_loopback_gain(phy)) {
+		int trsw_rx = 0;
+		int trsw_rx_gain;
+
+		if (use_trsw_rx) {
+			trsw_rx_gain = phy->trsw_rx_gain / 2;
+			if (max_rx_gain >= trsw_rx_gain) {
+				trsw_rx_gain = max_rx_gain - trsw_rx_gain;
+				trsw_rx = 0x20;
+			}
+		} else
+			trsw_rx_gain = max_rx_gain;
+		if (trsw_rx_gain < 9) {
+			phy->lna_lod_gain = 0;
+		} else {
+			phy->lna_lod_gain = 1;
+			trsw_rx_gain -= 8;
+		}
+		trsw_rx_gain = limit_value(trsw_rx_gain, 0, 0x2D);
+		phy->pga_gain = trsw_rx_gain / 3;
+		if (phy->pga_gain >= 5) {
+			phy->pga_gain -= 5;
+			phy->lna_gain = 2;
+		} else
+			phy->lna_gain = 0;
+	} else {
+		phy->lna_gain = 0;
+		phy->trsw_rx_gain = 0x20;
+		if (max_rx_gain >= 0x14) {
+			phy->lna_lod_gain = 1;
+			phy->pga_gain = 2;
+		} else if (max_rx_gain >= 0x12) {
+			phy->lna_lod_gain = 1;
+			phy->pga_gain = 1;
+		} else if (max_rx_gain >= 0xF) {
+			phy->lna_lod_gain = 1;
+			phy->pga_gain = 0;
+		} else {
+			phy->lna_lod_gain = 0;
+			phy->pga_gain = 0;
+		}
+	}
+
+	tmp = b43_radio_read16(dev, 0x7A);
+	if (phy->lna_lod_gain == 0)
+		tmp &= ~0x0008;
+	else
+		tmp |= 0x0008;
+	b43_radio_write16(dev, 0x7A, tmp);
+}
+
+struct lo_g_saved_values {
+	u8 old_channel;
+
+	/* Core registers */
+	u16 reg_3F4;
+	u16 reg_3E2;
+
+	/* PHY registers */
+	u16 phy_lo_mask;
+	u16 phy_extg_01;
+	u16 phy_dacctl_hwpctl;
+	u16 phy_dacctl;
+	u16 phy_base_14;
+	u16 phy_hpwr_tssictl;
+	u16 phy_analogover;
+	u16 phy_analogoverval;
+	u16 phy_rfover;
+	u16 phy_rfoverval;
+	u16 phy_classctl;
+	u16 phy_base_3E;
+	u16 phy_crs0;
+	u16 phy_pgactl;
+	u16 phy_base_2A;
+	u16 phy_syncctl;
+	u16 phy_base_30;
+	u16 phy_base_06;
+
+	/* Radio registers */
+	u16 radio_43;
+	u16 radio_7A;
+	u16 radio_52;
+};
+
+static void lo_measure_setup(struct b43_wldev *dev,
+			     struct lo_g_saved_values *sav)
+{
+	struct ssb_sprom *sprom = &dev->dev->bus->sprom;
+	struct b43_phy *phy = &dev->phy;
+	struct b43_txpower_lo_control *lo = phy->lo_control;
+	u16 tmp;
+
+	if (b43_has_hardware_pctl(phy)) {
+		sav->phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
+		sav->phy_extg_01 = b43_phy_read(dev, B43_PHY_EXTG(0x01));
+		sav->phy_dacctl_hwpctl = b43_phy_read(dev, B43_PHY_DACCTL);
+		sav->phy_base_14 = b43_phy_read(dev, B43_PHY_BASE(0x14));
+		sav->phy_hpwr_tssictl = b43_phy_read(dev, B43_PHY_HPWR_TSSICTL);
+
+		b43_phy_write(dev, B43_PHY_HPWR_TSSICTL,
+			      b43_phy_read(dev, B43_PHY_HPWR_TSSICTL)
+			      | 0x100);
+		b43_phy_write(dev, B43_PHY_EXTG(0x01),
+			      b43_phy_read(dev, B43_PHY_EXTG(0x01))
+			      | 0x40);
+		b43_phy_write(dev, B43_PHY_DACCTL,
+			      b43_phy_read(dev, B43_PHY_DACCTL)
+			      | 0x40);
+		b43_phy_write(dev, B43_PHY_BASE(0x14),
+			      b43_phy_read(dev, B43_PHY_BASE(0x14))
+			      | 0x200);
+	}
+	if (phy->type == B43_PHYTYPE_B &&
+	    phy->radio_ver == 0x2050 && phy->radio_rev < 6) {
+		b43_phy_write(dev, B43_PHY_BASE(0x16), 0x410);
+		b43_phy_write(dev, B43_PHY_BASE(0x17), 0x820);
+	}
+	if (!lo->rebuild && b43_has_hardware_pctl(phy))
+		lo_read_power_vector(dev);
+	if (phy->rev >= 2) {
+		sav->phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER);
+		sav->phy_analogoverval =
+		    b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
+		sav->phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
+		sav->phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
+		sav->phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL);
+		sav->phy_base_3E = b43_phy_read(dev, B43_PHY_BASE(0x3E));
+		sav->phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
+
+		b43_phy_write(dev, B43_PHY_CLASSCTL,
+			      b43_phy_read(dev, B43_PHY_CLASSCTL)
+			      & 0xFFFC);
+		b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
+			      & 0x7FFF);
+		b43_phy_write(dev, B43_PHY_ANALOGOVER,
+			      b43_phy_read(dev, B43_PHY_ANALOGOVER)
+			      | 0x0003);
+		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+			      b43_phy_read(dev, B43_PHY_ANALOGOVERVAL)
+			      & 0xFFFC);
+		if (phy->type == B43_PHYTYPE_G) {
+			if ((phy->rev >= 7) &&
+			    (sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+				b43_phy_write(dev, B43_PHY_RFOVER, 0x933);
+			} else {
+				b43_phy_write(dev, B43_PHY_RFOVER, 0x133);
+			}
+		} else {
+			b43_phy_write(dev, B43_PHY_RFOVER, 0);
+		}
+		b43_phy_write(dev, B43_PHY_BASE(0x3E), 0);
+	}
+	sav->reg_3F4 = b43_read16(dev, 0x3F4);
+	sav->reg_3E2 = b43_read16(dev, 0x3E2);
+	sav->radio_43 = b43_radio_read16(dev, 0x43);
+	sav->radio_7A = b43_radio_read16(dev, 0x7A);
+	sav->phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
+	sav->phy_base_2A = b43_phy_read(dev, B43_PHY_BASE(0x2A));
+	sav->phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL);
+	sav->phy_dacctl = b43_phy_read(dev, B43_PHY_DACCTL);
+
+	if (!has_tx_magnification(phy)) {
+		sav->radio_52 = b43_radio_read16(dev, 0x52);
+		sav->radio_52 &= 0x00F0;
+	}
+	if (phy->type == B43_PHYTYPE_B) {
+		sav->phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30));
+		sav->phy_base_06 = b43_phy_read(dev, B43_PHY_BASE(0x06));
+		b43_phy_write(dev, B43_PHY_BASE(0x30), 0x00FF);
+		b43_phy_write(dev, B43_PHY_BASE(0x06), 0x3F3F);
+	} else {
+		b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2)
+			    | 0x8000);
+	}
+	b43_write16(dev, 0x3F4, b43_read16(dev, 0x3F4)
+		    & 0xF000);
+
+	tmp =
+	    (phy->type == B43_PHYTYPE_G) ? B43_PHY_LO_MASK : B43_PHY_BASE(0x2E);
+	b43_phy_write(dev, tmp, 0x007F);
+
+	tmp = sav->phy_syncctl;
+	b43_phy_write(dev, B43_PHY_SYNCCTL, tmp & 0xFF7F);
+	tmp = sav->radio_7A;
+	b43_radio_write16(dev, 0x007A, tmp & 0xFFF0);
+
+	b43_phy_write(dev, B43_PHY_BASE(0x2A), 0x8A3);
+	if (phy->type == B43_PHYTYPE_G ||
+	    (phy->type == B43_PHYTYPE_B &&
+	     phy->radio_ver == 0x2050 && phy->radio_rev >= 6)) {
+		b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1003);
+	} else
+		b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x0802);
+	if (phy->rev >= 2)
+		b43_dummy_transmission(dev);
+	b43_radio_selectchannel(dev, 6, 0);
+	b43_radio_read16(dev, 0x51);	/* dummy read */
+	if (phy->type == B43_PHYTYPE_G)
+		b43_phy_write(dev, B43_PHY_BASE(0x2F), 0);
+	if (lo->rebuild)
+		lo_measure_txctl_values(dev);
+	if (phy->type == B43_PHYTYPE_G && phy->rev >= 3) {
+		b43_phy_write(dev, B43_PHY_LO_MASK, 0xC078);
+	} else {
+		if (phy->type == B43_PHYTYPE_B)
+			b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078);
+		else
+			b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
+	}
+}
+
+static void lo_measure_restore(struct b43_wldev *dev,
+			       struct lo_g_saved_values *sav)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_txpower_lo_control *lo = phy->lo_control;
+	u16 tmp;
+
+	if (phy->rev >= 2) {
+		b43_phy_write(dev, B43_PHY_PGACTL, 0xE300);
+		tmp = (phy->pga_gain << 8);
+		b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA0);
+		udelay(5);
+		b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA2);
+		udelay(2);
+		b43_phy_write(dev, B43_PHY_RFOVERVAL, tmp | 0xA3);
+	} else {
+		tmp = (phy->pga_gain | 0xEFA0);
+		b43_phy_write(dev, B43_PHY_PGACTL, tmp);
+	}
+	if (b43_has_hardware_pctl(phy)) {
+		b43_gphy_dc_lt_init(dev);
+	} else {
+		if (lo->rebuild)
+			b43_lo_g_adjust_to(dev, 3, 2, 0);
+		else
+			b43_lo_g_adjust(dev);
+	}
+	if (phy->type == B43_PHYTYPE_G) {
+		if (phy->rev >= 3)
+			b43_phy_write(dev, B43_PHY_BASE(0x2E), 0xC078);
+		else
+			b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8078);
+		if (phy->rev >= 2)
+			b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0202);
+		else
+			b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x0101);
+	}
+	b43_write16(dev, 0x3F4, sav->reg_3F4);
+	b43_phy_write(dev, B43_PHY_PGACTL, sav->phy_pgactl);
+	b43_phy_write(dev, B43_PHY_BASE(0x2A), sav->phy_base_2A);
+	b43_phy_write(dev, B43_PHY_SYNCCTL, sav->phy_syncctl);
+	b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl);
+	b43_radio_write16(dev, 0x43, sav->radio_43);
+	b43_radio_write16(dev, 0x7A, sav->radio_7A);
+	if (!has_tx_magnification(phy)) {
+		tmp = sav->radio_52;
+		b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
+					      & 0xFF0F) | tmp);
+	}
+	b43_write16(dev, 0x3E2, sav->reg_3E2);
+	if (phy->type == B43_PHYTYPE_B &&
+	    phy->radio_ver == 0x2050 && phy->radio_rev <= 5) {
+		b43_phy_write(dev, B43_PHY_BASE(0x30), sav->phy_base_30);
+		b43_phy_write(dev, B43_PHY_BASE(0x06), sav->phy_base_06);
+	}
+	if (phy->rev >= 2) {
+		b43_phy_write(dev, B43_PHY_ANALOGOVER, sav->phy_analogover);
+		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+			      sav->phy_analogoverval);
+		b43_phy_write(dev, B43_PHY_CLASSCTL, sav->phy_classctl);
+		b43_phy_write(dev, B43_PHY_RFOVER, sav->phy_rfover);
+		b43_phy_write(dev, B43_PHY_RFOVERVAL, sav->phy_rfoverval);
+		b43_phy_write(dev, B43_PHY_BASE(0x3E), sav->phy_base_3E);
+		b43_phy_write(dev, B43_PHY_CRS0, sav->phy_crs0);
+	}
+	if (b43_has_hardware_pctl(phy)) {
+		tmp = (sav->phy_lo_mask & 0xBFFF);
+		b43_phy_write(dev, B43_PHY_LO_MASK, tmp);
+		b43_phy_write(dev, B43_PHY_EXTG(0x01), sav->phy_extg_01);
+		b43_phy_write(dev, B43_PHY_DACCTL, sav->phy_dacctl_hwpctl);
+		b43_phy_write(dev, B43_PHY_BASE(0x14), sav->phy_base_14);
+		b43_phy_write(dev, B43_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
+	}
+	b43_radio_selectchannel(dev, sav->old_channel, 1);
+}
+
+struct b43_lo_g_statemachine {
+	int current_state;
+	int nr_measured;
+	int state_val_multiplier;
+	u16 lowest_feedth;
+	struct b43_loctl min_loctl;
+};
+
+/* Loop over each possible value in this state. */
+static int lo_probe_possible_loctls(struct b43_wldev *dev,
+				    struct b43_loctl *probe_loctl,
+				    struct b43_lo_g_statemachine *d)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_txpower_lo_control *lo = phy->lo_control;
+	struct b43_loctl test_loctl;
+	struct b43_loctl orig_loctl;
+	struct b43_loctl prev_loctl = {
+		.i = -100,
+		.q = -100,
+	};
+	int i;
+	int begin, end;
+	int found_lower = 0;
+	u16 feedth;
+
+	static const struct b43_loctl modifiers[] = {
+		{.i = 1,.q = 1,},
+		{.i = 1,.q = 0,},
+		{.i = 1,.q = -1,},
+		{.i = 0,.q = -1,},
+		{.i = -1,.q = -1,},
+		{.i = -1,.q = 0,},
+		{.i = -1,.q = 1,},
+		{.i = 0,.q = 1,},
+	};
+
+	if (d->current_state == 0) {
+		begin = 1;
+		end = 8;
+	} else if (d->current_state % 2 == 0) {
+		begin = d->current_state - 1;
+		end = d->current_state + 1;
+	} else {
+		begin = d->current_state - 2;
+		end = d->current_state + 2;
+	}
+	if (begin < 1)
+		begin += 8;
+	if (end > 8)
+		end -= 8;
+
+	memcpy(&orig_loctl, probe_loctl, sizeof(struct b43_loctl));
+	i = begin;
+	d->current_state = i;
+	while (1) {
+		B43_WARN_ON(!(i >= 1 && i <= 8));
+		memcpy(&test_loctl, &orig_loctl, sizeof(struct b43_loctl));
+		test_loctl.i += modifiers[i - 1].i * d->state_val_multiplier;
+		test_loctl.q += modifiers[i - 1].q * d->state_val_multiplier;
+		if ((test_loctl.i != prev_loctl.i ||
+		     test_loctl.q != prev_loctl.q) &&
+		    (abs(test_loctl.i) <= 16 && abs(test_loctl.q) <= 16)) {
+			b43_lo_write(dev, &test_loctl);
+			feedth = lo_measure_feedthrough(dev, phy->lna_gain,
+							phy->pga_gain,
+							phy->trsw_rx_gain);
+			if (feedth < d->lowest_feedth) {
+				memcpy(probe_loctl, &test_loctl,
+				       sizeof(struct b43_loctl));
+				found_lower = 1;
+				d->lowest_feedth = feedth;
+				if ((d->nr_measured < 2) &&
+				    (!has_loopback_gain(phy) || lo->rebuild))
+					break;
+			}
+		}
+		memcpy(&prev_loctl, &test_loctl, sizeof(prev_loctl));
+		if (i == end)
+			break;
+		if (i == 8)
+			i = 1;
+		else
+			i++;
+		d->current_state = i;
+	}
+
+	return found_lower;
+}
+
+static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
+					 struct b43_loctl *loctl,
+					 int *max_rx_gain)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_txpower_lo_control *lo = phy->lo_control;
+	struct b43_lo_g_statemachine d;
+	u16 feedth;
+	int found_lower;
+	struct b43_loctl probe_loctl;
+	int max_repeat = 1, repeat_cnt = 0;
+
+	d.nr_measured = 0;
+	d.state_val_multiplier = 1;
+	if (has_loopback_gain(phy) && !lo->rebuild)
+		d.state_val_multiplier = 3;
+
+	memcpy(&d.min_loctl, loctl, sizeof(struct b43_loctl));
+	if (has_loopback_gain(phy) && lo->rebuild)
+		max_repeat = 4;
+	do {
+		b43_lo_write(dev, &d.min_loctl);
+		feedth = lo_measure_feedthrough(dev, phy->lna_gain,
+						phy->pga_gain,
+						phy->trsw_rx_gain);
+		if (!lo->rebuild && feedth < 0x258) {
+			if (feedth >= 0x12C)
+				*max_rx_gain += 6;
+			else
+				*max_rx_gain += 3;
+			feedth = lo_measure_feedthrough(dev, phy->lna_gain,
+							phy->pga_gain,
+							phy->trsw_rx_gain);
+		}
+		d.lowest_feedth = feedth;
+
+		d.current_state = 0;
+		do {
+			B43_WARN_ON(!
+				    (d.current_state >= 0
+				     && d.current_state <= 8));
+			memcpy(&probe_loctl, &d.min_loctl,
+			       sizeof(struct b43_loctl));
+			found_lower =
+			    lo_probe_possible_loctls(dev, &probe_loctl, &d);
+			if (!found_lower)
+				break;
+			if ((probe_loctl.i == d.min_loctl.i) &&
+			    (probe_loctl.q == d.min_loctl.q))
+				break;
+			memcpy(&d.min_loctl, &probe_loctl,
+			       sizeof(struct b43_loctl));
+			d.nr_measured++;
+		} while (d.nr_measured < 24);
+		memcpy(loctl, &d.min_loctl, sizeof(struct b43_loctl));
+
+		if (has_loopback_gain(phy)) {
+			if (d.lowest_feedth > 0x1194)
+				*max_rx_gain -= 6;
+			else if (d.lowest_feedth < 0x5DC)
+				*max_rx_gain += 3;
+			if (repeat_cnt == 0) {
+				if (d.lowest_feedth <= 0x5DC) {
+					d.state_val_multiplier = 1;
+					repeat_cnt++;
+				} else
+					d.state_val_multiplier = 2;
+			} else if (repeat_cnt == 2)
+				d.state_val_multiplier = 1;
+		}
+		lo_measure_gain_values(dev, *max_rx_gain,
+				       has_loopback_gain(phy));
+	} while (++repeat_cnt < max_repeat);
+}
+
+#if B43_CALIB_ALL_LOCTLS
+static const struct b43_rfatt b43_full_rfatt_list_items[] = {
+	{ .att = 0, .with_padmix = 0, },
+	{ .att = 1, .with_padmix = 0, },
+	{ .att = 2, .with_padmix = 0, },
+	{ .att = 3, .with_padmix = 0, },
+	{ .att = 4, .with_padmix = 0, },
+	{ .att = 5, .with_padmix = 0, },
+	{ .att = 6, .with_padmix = 0, },
+	{ .att = 7, .with_padmix = 0, },
+	{ .att = 8, .with_padmix = 0, },
+	{ .att = 9, .with_padmix = 0, },
+	{ .att = 10, .with_padmix = 0, },
+	{ .att = 11, .with_padmix = 0, },
+	{ .att = 12, .with_padmix = 0, },
+	{ .att = 13, .with_padmix = 0, },
+	{ .att = 14, .with_padmix = 0, },
+	{ .att = 15, .with_padmix = 0, },
+	{ .att = 0, .with_padmix = 1, },
+	{ .att = 1, .with_padmix = 1, },
+	{ .att = 2, .with_padmix = 1, },
+	{ .att = 3, .with_padmix = 1, },
+	{ .att = 4, .with_padmix = 1, },
+	{ .att = 5, .with_padmix = 1, },
+	{ .att = 6, .with_padmix = 1, },
+	{ .att = 7, .with_padmix = 1, },
+	{ .att = 8, .with_padmix = 1, },
+	{ .att = 9, .with_padmix = 1, },
+	{ .att = 10, .with_padmix = 1, },
+	{ .att = 11, .with_padmix = 1, },
+	{ .att = 12, .with_padmix = 1, },
+	{ .att = 13, .with_padmix = 1, },
+	{ .att = 14, .with_padmix = 1, },
+	{ .att = 15, .with_padmix = 1, },
+};
+static const struct b43_rfatt_list b43_full_rfatt_list = {
+	.list		= b43_full_rfatt_list_items,
+	.len		= ARRAY_SIZE(b43_full_rfatt_list_items),
+};
+
+static const struct b43_bbatt b43_full_bbatt_list_items[] = {
+	{ .att = 0, },
+	{ .att = 1, },
+	{ .att = 2, },
+	{ .att = 3, },
+	{ .att = 4, },
+	{ .att = 5, },
+	{ .att = 6, },
+	{ .att = 7, },
+	{ .att = 8, },
+	{ .att = 9, },
+	{ .att = 10, },
+	{ .att = 11, },
+};
+static const struct b43_bbatt_list b43_full_bbatt_list = {
+	.list		= b43_full_bbatt_list_items,
+	.len		= ARRAY_SIZE(b43_full_bbatt_list_items),
+};
+#endif /* B43_CALIB_ALL_LOCTLS */
+
+static void lo_measure(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_txpower_lo_control *lo = phy->lo_control;
+	struct b43_loctl loctl = {
+		.i = 0,
+		.q = 0,
+	};
+	struct b43_loctl *ploctl;
+	int max_rx_gain;
+	int rfidx, bbidx;
+	const struct b43_bbatt_list *bbatt_list;
+	const struct b43_rfatt_list *rfatt_list;
+
+	/* Values from the "TXCTL Register and Value Table" */
+	u16 txctl_reg;
+	u16 txctl_value;
+	u16 pad_mix_gain;
+
+	bbatt_list = &lo->bbatt_list;
+	rfatt_list = &lo->rfatt_list;
+#if B43_CALIB_ALL_LOCTLS
+	bbatt_list = &b43_full_bbatt_list;
+	rfatt_list = &b43_full_rfatt_list;
+#endif
+
+	txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain);
+
+	for (rfidx = 0; rfidx < rfatt_list->len; rfidx++) {
+
+		b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+					      & 0xFFF0) |
+				  rfatt_list->list[rfidx].att);
+		b43_radio_write16(dev, txctl_reg,
+				  (b43_radio_read16(dev, txctl_reg)
+				   & ~txctl_value)
+				  | (rfatt_list->list[rfidx].with_padmix ?
+				     txctl_value : 0));
+
+		for (bbidx = 0; bbidx < bbatt_list->len; bbidx++) {
+			if (lo->rebuild) {
+#if B43_CALIB_ALL_LOCTLS
+				ploctl = b43_get_lo_g_ctl(dev,
+							  &rfatt_list->list[rfidx],
+							  &bbatt_list->list[bbidx]);
+#else
+				ploctl = b43_get_lo_g_ctl_nopadmix(dev,
+								   &rfatt_list->
+								   list[rfidx],
+								   &bbatt_list->
+								   list[bbidx]);
+#endif
+			} else {
+				ploctl = b43_get_lo_g_ctl(dev,
+							  &rfatt_list->list[rfidx],
+							  &bbatt_list->list[bbidx]);
+				if (!ploctl->used)
+					continue;
+			}
+			memcpy(&loctl, ploctl, sizeof(loctl));
+			loctl.i = 0;
+			loctl.q = 0;
+
+			max_rx_gain = rfatt_list->list[rfidx].att * 2;
+			max_rx_gain += bbatt_list->list[bbidx].att / 2;
+			if (rfatt_list->list[rfidx].with_padmix)
+				max_rx_gain -= pad_mix_gain;
+			if (has_loopback_gain(phy))
+				max_rx_gain += phy->max_lb_gain;
+			lo_measure_gain_values(dev, max_rx_gain,
+					       has_loopback_gain(phy));
+
+			b43_phy_set_baseband_attenuation(dev,
+							 bbatt_list->list[bbidx].att);
+			lo_probe_loctls_statemachine(dev, &loctl, &max_rx_gain);
+			if (phy->type == B43_PHYTYPE_B) {
+				loctl.i++;
+				loctl.q++;
+			}
+			b43_loctl_set_calibrated(&loctl, 1);
+			memcpy(ploctl, &loctl, sizeof(loctl));
+		}
+	}
+}
+
+#if B43_DEBUG
+static void do_validate_loctl(struct b43_wldev *dev, struct b43_loctl *control)
+{
+	const int is_initializing = (b43_status(dev) == B43_STAT_UNINIT);
+	int i = control->i;
+	int q = control->q;
+
+	if (b43_loctl_is_calibrated(control)) {
+		if ((abs(i) > 16) || (abs(q) > 16))
+			goto error;
+	} else {
+		if (control->used)
+			goto error;
+		if (dev->phy.lo_control->rebuild) {
+			control->i = 0;
+			control->q = 0;
+			if ((i != B43_LOCTL_POISON) ||
+			    (q != B43_LOCTL_POISON))
+				goto error;
+		}
+	}
+	if (is_initializing && control->used)
+		goto error;
+
+	return;
+error:
+	b43err(dev->wl, "LO control pair validation failed "
+	       "(I: %d, Q: %d, used %u, calib: %u, initing: %d)\n",
+	       i, q, control->used,
+	       b43_loctl_is_calibrated(control),
+	       is_initializing);
+}
+
+static void validate_all_loctls(struct b43_wldev *dev)
+{
+	b43_call_for_each_loctl(dev, do_validate_loctl);
+}
+
+static void do_reset_calib(struct b43_wldev *dev, struct b43_loctl *control)
+{
+	if (dev->phy.lo_control->rebuild ||
+	    control->used) {
+		b43_loctl_set_calibrated(control, 0);
+		control->i = B43_LOCTL_POISON;
+		control->q = B43_LOCTL_POISON;
+	}
+}
+
+static void reset_all_loctl_calibration_states(struct b43_wldev *dev)
+{
+	b43_call_for_each_loctl(dev, do_reset_calib);
+}
+
+#else /* B43_DEBUG */
+static inline void validate_all_loctls(struct b43_wldev *dev) { }
+static inline void reset_all_loctl_calibration_states(struct b43_wldev *dev) { }
+#endif /* B43_DEBUG */
+
+void b43_lo_g_measure(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct lo_g_saved_values uninitialized_var(sav);
+
+	B43_WARN_ON((phy->type != B43_PHYTYPE_B) &&
+		    (phy->type != B43_PHYTYPE_G));
+
+	sav.old_channel = phy->channel;
+	lo_measure_setup(dev, &sav);
+	reset_all_loctl_calibration_states(dev);
+	lo_measure(dev);
+	lo_measure_restore(dev, &sav);
+
+	validate_all_loctls(dev);
+
+	phy->lo_control->lo_measured = 1;
+	phy->lo_control->rebuild = 0;
+}
+
+#if B43_DEBUG
+static void validate_loctl_calibration(struct b43_wldev *dev,
+				       struct b43_loctl *loctl,
+				       struct b43_rfatt *rfatt,
+				       struct b43_bbatt *bbatt)
+{
+	if (b43_loctl_is_calibrated(loctl))
+		return;
+	if (!dev->phy.lo_control->lo_measured) {
+		/* On init we set the attenuation values before we
+		 * calibrated the LO. I guess that's OK. */
+		return;
+	}
+	b43err(dev->wl, "Adjusting Local Oscillator to an uncalibrated "
+	       "control pair: rfatt=%u,%spadmix bbatt=%u\n",
+	       rfatt->att,
+	       (rfatt->with_padmix) ? "" : "no-",
+	       bbatt->att);
+}
+#else
+static inline void validate_loctl_calibration(struct b43_wldev *dev,
+					      struct b43_loctl *loctl,
+					      struct b43_rfatt *rfatt,
+					      struct b43_bbatt *bbatt)
+{
+}
+#endif
+
+static inline void fixup_rfatt_for_txcontrol(struct b43_rfatt *rf,
+					     u8 tx_control)
+{
+	if (tx_control & B43_TXCTL_TXMIX) {
+		if (rf->att < 5)
+			rf->att = 4;
+	}
+}
+
+void b43_lo_g_adjust(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_rfatt rf;
+	struct b43_loctl *loctl;
+
+	memcpy(&rf, &phy->rfatt, sizeof(rf));
+	fixup_rfatt_for_txcontrol(&rf, phy->tx_control);
+
+	loctl = b43_get_lo_g_ctl(dev, &rf, &phy->bbatt);
+	validate_loctl_calibration(dev, loctl, &rf, &phy->bbatt);
+	b43_lo_write(dev, loctl);
+}
+
+void b43_lo_g_adjust_to(struct b43_wldev *dev,
+			u16 rfatt, u16 bbatt, u16 tx_control)
+{
+	struct b43_rfatt rf;
+	struct b43_bbatt bb;
+	struct b43_loctl *loctl;
+
+	memset(&rf, 0, sizeof(rf));
+	memset(&bb, 0, sizeof(bb));
+	rf.att = rfatt;
+	bb.att = bbatt;
+	fixup_rfatt_for_txcontrol(&rf, tx_control);
+	loctl = b43_get_lo_g_ctl(dev, &rf, &bb);
+	validate_loctl_calibration(dev, loctl, &rf, &bb);
+	b43_lo_write(dev, loctl);
+}
+
+static void do_mark_unused(struct b43_wldev *dev, struct b43_loctl *control)
+{
+	control->used = 0;
+}
+
+void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_txpower_lo_control *lo = phy->lo_control;
+
+	b43_call_for_each_loctl(dev, do_mark_unused);
+	lo->rebuild = 1;
+}
+
+void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_rfatt rf;
+
+	memcpy(&rf, &phy->rfatt, sizeof(rf));
+	fixup_rfatt_for_txcontrol(&rf, phy->tx_control);
+
+	b43_get_lo_g_ctl(dev, &rf, &phy->bbatt)->used = 1;
+}
diff --git a/drivers/net/wireless/b43/lo.h b/drivers/net/wireless/b43/lo.h
new file mode 100644
index 0000000..455615d
--- /dev/null
+++ b/drivers/net/wireless/b43/lo.h
@@ -0,0 +1,112 @@
+#ifndef B43_LO_H_
+#define B43_LO_H_
+
+#include "phy.h"
+
+struct b43_wldev;
+
+/* Local Oscillator control value-pair. */
+struct b43_loctl {
+	/* Control values. */
+	s8 i;
+	s8 q;
+	/* "Used by hardware" flag. */
+	bool used;
+#ifdef CONFIG_B43_DEBUG
+	/* Is this lo-control-array entry calibrated? */
+	bool calibrated;
+#endif
+};
+
+/* Debugging: Poison value for i and q values. */
+#define B43_LOCTL_POISON	111
+
+/* loctl->calibrated debugging mechanism */
+#ifdef CONFIG_B43_DEBUG
+static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl,
+					    bool calibrated)
+{
+	loctl->calibrated = calibrated;
+}
+static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl)
+{
+	return loctl->calibrated;
+}
+#else
+static inline void b43_loctl_set_calibrated(struct b43_loctl *loctl,
+					    bool calibrated)
+{
+}
+static inline bool b43_loctl_is_calibrated(struct b43_loctl *loctl)
+{
+	return 1;
+}
+#endif
+
+/* TX Power LO Control Array.
+ * Value-pairs to adjust the LocalOscillator are stored
+ * in this structure.
+ * There are two different set of values. One for "Flag is Set"
+ * and one for "Flag is Unset".
+ * By "Flag" the flag in struct b43_rfatt is meant.
+ * The Value arrays are two-dimensional. The first index
+ * is the baseband attenuation and the second index
+ * is the radio attenuation.
+ * Use b43_get_lo_g_ctl() to retrieve a value from the lists.
+ */
+struct b43_txpower_lo_control {
+#define B43_NR_BB	12
+#define B43_NR_RF	16
+	/* LO Control values, with PAD Mixer */
+	struct b43_loctl with_padmix[B43_NR_BB][B43_NR_RF];
+	/* LO Control values, without PAD Mixer */
+	struct b43_loctl no_padmix[B43_NR_BB][B43_NR_RF];
+
+	/* Flag to indicate a complete rebuild of the two tables above
+	 * to the LO measuring code. */
+	bool rebuild;
+
+	/* Lists of valid RF and BB attenuation values for this device. */
+	struct b43_rfatt_list rfatt_list;
+	struct b43_bbatt_list bbatt_list;
+
+	/* Current TX Bias value */
+	u8 tx_bias;
+	/* Current TX Magnification Value (if used by the device) */
+	u8 tx_magn;
+
+	/* GPHY LO is measured. */
+	bool lo_measured;
+
+	/* Saved device PowerVector */
+	u64 power_vector;
+};
+
+/* Measure the BPHY Local Oscillator. */
+void b43_lo_b_measure(struct b43_wldev *dev);
+/* Measure the BPHY/GPHY Local Oscillator. */
+void b43_lo_g_measure(struct b43_wldev *dev);
+
+/* Adjust the Local Oscillator to the saved attenuation
+ * and txctl values.
+ */
+void b43_lo_g_adjust(struct b43_wldev *dev);
+/* Adjust to specific values. */
+void b43_lo_g_adjust_to(struct b43_wldev *dev,
+			u16 rfatt, u16 bbatt, u16 tx_control);
+
+/* Mark all possible b43_lo_g_ctl as "unused" */
+void b43_lo_g_ctl_mark_all_unused(struct b43_wldev *dev);
+/* Mark the b43_lo_g_ctl corresponding to the current
+ * attenuation values as used.
+ */
+void b43_lo_g_ctl_mark_cur_used(struct b43_wldev *dev);
+
+/* Get a reference to a LO Control value pair in the
+ * TX Power LO Control Array.
+ */
+struct b43_loctl *b43_get_lo_g_ctl(struct b43_wldev *dev,
+				   const struct b43_rfatt *rfatt,
+				   const struct b43_bbatt *bbatt);
+
+#endif /* B43_LO_H_ */
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
new file mode 100644
index 0000000..c141a26
--- /dev/null
+++ b/drivers/net/wireless/b43/main.c
@@ -0,0 +1,4070 @@
+/*
+
+  Broadcom B43 wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
+  Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+  Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+  Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 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 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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/version.h>
+#include <linux/firmware.h>
+#include <linux/wireless.h>
+#include <linux/workqueue.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <asm/unaligned.h>
+
+#include "b43.h"
+#include "main.h"
+#include "debugfs.h"
+#include "phy.h"
+#include "dma.h"
+#include "pio.h"
+#include "sysfs.h"
+#include "xmit.h"
+#include "sysfs.h"
+#include "lo.h"
+#include "pcmcia.h"
+
+MODULE_DESCRIPTION("Broadcom B43 wireless driver");
+MODULE_AUTHOR("Martin Langer");
+MODULE_AUTHOR("Stefano Brivio");
+MODULE_AUTHOR("Michael Buesch");
+MODULE_LICENSE("GPL");
+
+extern char *nvram_get(char *name);
+
+#if defined(CONFIG_B43_DMA) && defined(CONFIG_B43_PIO)
+static int modparam_pio;
+module_param_named(pio, modparam_pio, int, 0444);
+MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
+#elif defined(CONFIG_B43_DMA)
+# define modparam_pio	0
+#elif defined(CONFIG_B43_PIO)
+# define modparam_pio	1
+#endif
+
+static int modparam_bad_frames_preempt;
+module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
+MODULE_PARM_DESC(bad_frames_preempt,
+		 "enable(1) / disable(0) Bad Frames Preemption");
+
+static int modparam_short_retry = B43_DEFAULT_SHORT_RETRY_LIMIT;
+module_param_named(short_retry, modparam_short_retry, int, 0444);
+MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
+
+static int modparam_long_retry = B43_DEFAULT_LONG_RETRY_LIMIT;
+module_param_named(long_retry, modparam_long_retry, int, 0444);
+MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
+
+static char modparam_fwpostfix[16];
+module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
+MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load.");
+
+static int modparam_hwpctl;
+module_param_named(hwpctl, modparam_hwpctl, int, 0444);
+MODULE_PARM_DESC(hwpctl, "Enable hardware-side power control (default off)");
+
+static int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+
+static const struct ssb_device_id b43_ssb_tbl[] = {
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6),
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 7),
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9),
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10),
+	SSB_DEVTABLE_END
+};
+
+MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl);
+
+/* Channel and ratetables are shared for all devices.
+ * They can't be const, because ieee80211 puts some precalculated
+ * data in there. This data is the same for all devices, so we don't
+ * get concurrency issues */
+#define RATETAB_ENT(_rateid, _flags) \
+	{							\
+		.rate	= B43_RATE_TO_BASE100KBPS(_rateid),	\
+		.val	= (_rateid),				\
+		.val2	= (_rateid),				\
+		.flags	= (_flags),				\
+	}
+static struct ieee80211_rate __b43_ratetable[] = {
+	RATETAB_ENT(B43_CCK_RATE_1MB, IEEE80211_RATE_CCK),
+	RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_CCK_2),
+	RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_CCK_2),
+	RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_CCK_2),
+	RATETAB_ENT(B43_OFDM_RATE_6MB, IEEE80211_RATE_OFDM),
+	RATETAB_ENT(B43_OFDM_RATE_9MB, IEEE80211_RATE_OFDM),
+	RATETAB_ENT(B43_OFDM_RATE_12MB, IEEE80211_RATE_OFDM),
+	RATETAB_ENT(B43_OFDM_RATE_18MB, IEEE80211_RATE_OFDM),
+	RATETAB_ENT(B43_OFDM_RATE_24MB, IEEE80211_RATE_OFDM),
+	RATETAB_ENT(B43_OFDM_RATE_36MB, IEEE80211_RATE_OFDM),
+	RATETAB_ENT(B43_OFDM_RATE_48MB, IEEE80211_RATE_OFDM),
+	RATETAB_ENT(B43_OFDM_RATE_54MB, IEEE80211_RATE_OFDM),
+};
+
+#define b43_a_ratetable		(__b43_ratetable + 4)
+#define b43_a_ratetable_size	8
+#define b43_b_ratetable		(__b43_ratetable + 0)
+#define b43_b_ratetable_size	4
+#define b43_g_ratetable		(__b43_ratetable + 0)
+#define b43_g_ratetable_size	12
+
+#define CHANTAB_ENT(_chanid, _freq) \
+	{							\
+		.chan	= (_chanid),				\
+		.freq	= (_freq),				\
+		.val	= (_chanid),				\
+		.flag	= IEEE80211_CHAN_W_SCAN |		\
+			  IEEE80211_CHAN_W_ACTIVE_SCAN |	\
+			  IEEE80211_CHAN_W_IBSS,		\
+		.power_level	= 0xFF,				\
+		.antenna_max	= 0xFF,				\
+	}
+static struct ieee80211_channel b43_bg_chantable[] = {
+	CHANTAB_ENT(1, 2412),
+	CHANTAB_ENT(2, 2417),
+	CHANTAB_ENT(3, 2422),
+	CHANTAB_ENT(4, 2427),
+	CHANTAB_ENT(5, 2432),
+	CHANTAB_ENT(6, 2437),
+	CHANTAB_ENT(7, 2442),
+	CHANTAB_ENT(8, 2447),
+	CHANTAB_ENT(9, 2452),
+	CHANTAB_ENT(10, 2457),
+	CHANTAB_ENT(11, 2462),
+	CHANTAB_ENT(12, 2467),
+	CHANTAB_ENT(13, 2472),
+	CHANTAB_ENT(14, 2484),
+};
+
+#define b43_bg_chantable_size	ARRAY_SIZE(b43_bg_chantable)
+static struct ieee80211_channel b43_a_chantable[] = {
+	CHANTAB_ENT(36, 5180),
+	CHANTAB_ENT(40, 5200),
+	CHANTAB_ENT(44, 5220),
+	CHANTAB_ENT(48, 5240),
+	CHANTAB_ENT(52, 5260),
+	CHANTAB_ENT(56, 5280),
+	CHANTAB_ENT(60, 5300),
+	CHANTAB_ENT(64, 5320),
+	CHANTAB_ENT(149, 5745),
+	CHANTAB_ENT(153, 5765),
+	CHANTAB_ENT(157, 5785),
+	CHANTAB_ENT(161, 5805),
+	CHANTAB_ENT(165, 5825),
+};
+
+#define b43_a_chantable_size	ARRAY_SIZE(b43_a_chantable)
+
+static void b43_wireless_core_exit(struct b43_wldev *dev);
+static int b43_wireless_core_init(struct b43_wldev *dev);
+static void b43_wireless_core_stop(struct b43_wldev *dev);
+static int b43_wireless_core_start(struct b43_wldev *dev);
+
+static int b43_ratelimit(struct b43_wl *wl)
+{
+	if (!wl || !wl->current_dev)
+		return 1;
+	if (b43_status(wl->current_dev) < B43_STAT_STARTED)
+		return 1;
+	/* We are up and running.
+	 * Ratelimit the messages to avoid DoS over the net. */
+	return net_ratelimit();
+}
+
+void b43info(struct b43_wl *wl, const char *fmt, ...)
+{
+	va_list args;
+
+	if (!b43_ratelimit(wl))
+		return;
+	va_start(args, fmt);
+	printk(KERN_INFO "b43-%s: ",
+	       (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+	vprintk(fmt, args);
+	va_end(args);
+}
+
+void b43err(struct b43_wl *wl, const char *fmt, ...)
+{
+	va_list args;
+
+	if (!b43_ratelimit(wl))
+		return;
+	va_start(args, fmt);
+	printk(KERN_ERR "b43-%s ERROR: ",
+	       (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+	vprintk(fmt, args);
+	va_end(args);
+}
+
+void b43warn(struct b43_wl *wl, const char *fmt, ...)
+{
+	va_list args;
+
+	if (!b43_ratelimit(wl))
+		return;
+	va_start(args, fmt);
+	printk(KERN_WARNING "b43-%s warning: ",
+	       (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+	vprintk(fmt, args);
+	va_end(args);
+}
+
+#if B43_DEBUG
+void b43dbg(struct b43_wl *wl, const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	printk(KERN_DEBUG "b43-%s debug: ",
+	       (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+	vprintk(fmt, args);
+	va_end(args);
+}
+#endif /* DEBUG */
+
+static void b43_ram_write(struct b43_wldev *dev, u16 offset, u32 val)
+{
+	u32 macctl;
+
+	B43_WARN_ON(offset % 4 != 0);
+
+	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	if (macctl & B43_MACCTL_BE)
+		val = swab32(val);
+
+	b43_write32(dev, B43_MMIO_RAM_CONTROL, offset);
+	mmiowb();
+	b43_write32(dev, B43_MMIO_RAM_DATA, val);
+}
+
+static inline
+    void b43_shm_control_word(struct b43_wldev *dev, u16 routing, u16 offset)
+{
+	u32 control;
+
+	/* "offset" is the WORD offset. */
+
+	control = routing;
+	control <<= 16;
+	control |= offset;
+	b43_write32(dev, B43_MMIO_SHM_CONTROL, control);
+}
+
+u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
+{
+	u32 ret;
+
+	if (routing == B43_SHM_SHARED) {
+		B43_WARN_ON(offset & 0x0001);
+		if (offset & 0x0003) {
+			/* Unaligned access */
+			b43_shm_control_word(dev, routing, offset >> 2);
+			ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
+			ret <<= 16;
+			b43_shm_control_word(dev, routing, (offset >> 2) + 1);
+			ret |= b43_read16(dev, B43_MMIO_SHM_DATA);
+
+			return ret;
+		}
+		offset >>= 2;
+	}
+	b43_shm_control_word(dev, routing, offset);
+	ret = b43_read32(dev, B43_MMIO_SHM_DATA);
+
+	return ret;
+}
+
+u16 b43_shm_read16(struct b43_wldev * dev, u16 routing, u16 offset)
+{
+	u16 ret;
+
+	if (routing == B43_SHM_SHARED) {
+		B43_WARN_ON(offset & 0x0001);
+		if (offset & 0x0003) {
+			/* Unaligned access */
+			b43_shm_control_word(dev, routing, offset >> 2);
+			ret = b43_read16(dev, B43_MMIO_SHM_DATA_UNALIGNED);
+
+			return ret;
+		}
+		offset >>= 2;
+	}
+	b43_shm_control_word(dev, routing, offset);
+	ret = b43_read16(dev, B43_MMIO_SHM_DATA);
+
+	return ret;
+}
+
+void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
+{
+	if (routing == B43_SHM_SHARED) {
+		B43_WARN_ON(offset & 0x0001);
+		if (offset & 0x0003) {
+			/* Unaligned access */
+			b43_shm_control_word(dev, routing, offset >> 2);
+			mmiowb();
+			b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED,
+				    (value >> 16) & 0xffff);
+			mmiowb();
+			b43_shm_control_word(dev, routing, (offset >> 2) + 1);
+			mmiowb();
+			b43_write16(dev, B43_MMIO_SHM_DATA, value & 0xffff);
+			return;
+		}
+		offset >>= 2;
+	}
+	b43_shm_control_word(dev, routing, offset);
+	mmiowb();
+	b43_write32(dev, B43_MMIO_SHM_DATA, value);
+}
+
+void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
+{
+	if (routing == B43_SHM_SHARED) {
+		B43_WARN_ON(offset & 0x0001);
+		if (offset & 0x0003) {
+			/* Unaligned access */
+			b43_shm_control_word(dev, routing, offset >> 2);
+			mmiowb();
+			b43_write16(dev, B43_MMIO_SHM_DATA_UNALIGNED, value);
+			return;
+		}
+		offset >>= 2;
+	}
+	b43_shm_control_word(dev, routing, offset);
+	mmiowb();
+	b43_write16(dev, B43_MMIO_SHM_DATA, value);
+}
+
+/* Read HostFlags */
+u32 b43_hf_read(struct b43_wldev * dev)
+{
+	u32 ret;
+
+	ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI);
+	ret <<= 16;
+	ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO);
+
+	return ret;
+}
+
+/* Write HostFlags */
+void b43_hf_write(struct b43_wldev *dev, u32 value)
+{
+	b43_shm_write16(dev, B43_SHM_SHARED,
+			B43_SHM_SH_HOSTFLO, (value & 0x0000FFFF));
+	b43_shm_write16(dev, B43_SHM_SHARED,
+			B43_SHM_SH_HOSTFHI, ((value & 0xFFFF0000) >> 16));
+}
+
+void b43_tsf_read(struct b43_wldev *dev, u64 * tsf)
+{
+	/* We need to be careful. As we read the TSF from multiple
+	 * registers, we should take care of register overflows.
+	 * In theory, the whole tsf read process should be atomic.
+	 * We try to be atomic here, by restaring the read process,
+	 * if any of the high registers changed (overflew).
+	 */
+	if (dev->dev->id.revision >= 3) {
+		u32 low, high, high2;
+
+		do {
+			high = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH);
+			low = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_LOW);
+			high2 = b43_read32(dev, B43_MMIO_REV3PLUS_TSF_HIGH);
+		} while (unlikely(high != high2));
+
+		*tsf = high;
+		*tsf <<= 32;
+		*tsf |= low;
+	} else {
+		u64 tmp;
+		u16 v0, v1, v2, v3;
+		u16 test1, test2, test3;
+
+		do {
+			v3 = b43_read16(dev, B43_MMIO_TSF_3);
+			v2 = b43_read16(dev, B43_MMIO_TSF_2);
+			v1 = b43_read16(dev, B43_MMIO_TSF_1);
+			v0 = b43_read16(dev, B43_MMIO_TSF_0);
+
+			test3 = b43_read16(dev, B43_MMIO_TSF_3);
+			test2 = b43_read16(dev, B43_MMIO_TSF_2);
+			test1 = b43_read16(dev, B43_MMIO_TSF_1);
+		} while (v3 != test3 || v2 != test2 || v1 != test1);
+
+		*tsf = v3;
+		*tsf <<= 48;
+		tmp = v2;
+		tmp <<= 32;
+		*tsf |= tmp;
+		tmp = v1;
+		tmp <<= 16;
+		*tsf |= tmp;
+		*tsf |= v0;
+	}
+}
+
+static void b43_time_lock(struct b43_wldev *dev)
+{
+	u32 macctl;
+
+	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	macctl |= B43_MACCTL_TBTTHOLD;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
+	/* Commit the write */
+	b43_read32(dev, B43_MMIO_MACCTL);
+}
+
+static void b43_time_unlock(struct b43_wldev *dev)
+{
+	u32 macctl;
+
+	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	macctl &= ~B43_MACCTL_TBTTHOLD;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
+	/* Commit the write */
+	b43_read32(dev, B43_MMIO_MACCTL);
+}
+
+static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf)
+{
+	/* Be careful with the in-progress timer.
+	 * First zero out the low register, so we have a full
+	 * register-overflow duration to complete the operation.
+	 */
+	if (dev->dev->id.revision >= 3) {
+		u32 lo = (tsf & 0x00000000FFFFFFFFULL);
+		u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32;
+
+		b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, 0);
+		mmiowb();
+		b43_write32(dev, B43_MMIO_REV3PLUS_TSF_HIGH, hi);
+		mmiowb();
+		b43_write32(dev, B43_MMIO_REV3PLUS_TSF_LOW, lo);
+	} else {
+		u16 v0 = (tsf & 0x000000000000FFFFULL);
+		u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16;
+		u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32;
+		u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48;
+
+		b43_write16(dev, B43_MMIO_TSF_0, 0);
+		mmiowb();
+		b43_write16(dev, B43_MMIO_TSF_3, v3);
+		mmiowb();
+		b43_write16(dev, B43_MMIO_TSF_2, v2);
+		mmiowb();
+		b43_write16(dev, B43_MMIO_TSF_1, v1);
+		mmiowb();
+		b43_write16(dev, B43_MMIO_TSF_0, v0);
+	}
+}
+
+void b43_tsf_write(struct b43_wldev *dev, u64 tsf)
+{
+	b43_time_lock(dev);
+	b43_tsf_write_locked(dev, tsf);
+	b43_time_unlock(dev);
+}
+
+static
+void b43_macfilter_set(struct b43_wldev *dev, u16 offset, const u8 * mac)
+{
+	static const u8 zero_addr[ETH_ALEN] = { 0 };
+	u16 data;
+
+	if (!mac)
+		mac = zero_addr;
+
+	offset |= 0x0020;
+	b43_write16(dev, B43_MMIO_MACFILTER_CONTROL, offset);
+
+	data = mac[0];
+	data |= mac[1] << 8;
+	b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
+	data = mac[2];
+	data |= mac[3] << 8;
+	b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
+	data = mac[4];
+	data |= mac[5] << 8;
+	b43_write16(dev, B43_MMIO_MACFILTER_DATA, data);
+}
+
+static void b43_write_mac_bssid_templates(struct b43_wldev *dev)
+{
+	const u8 *mac;
+	const u8 *bssid;
+	u8 mac_bssid[ETH_ALEN * 2];
+	int i;
+	u32 tmp;
+
+	bssid = dev->wl->bssid;
+	mac = dev->wl->mac_addr;
+
+	b43_macfilter_set(dev, B43_MACFILTER_BSSID, bssid);
+
+	memcpy(mac_bssid, mac, ETH_ALEN);
+	memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
+
+	/* Write our MAC address and BSSID to template ram */
+	for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) {
+		tmp = (u32) (mac_bssid[i + 0]);
+		tmp |= (u32) (mac_bssid[i + 1]) << 8;
+		tmp |= (u32) (mac_bssid[i + 2]) << 16;
+		tmp |= (u32) (mac_bssid[i + 3]) << 24;
+		b43_ram_write(dev, 0x20 + i, tmp);
+	}
+}
+
+static void b43_upload_card_macaddress(struct b43_wldev *dev)
+{
+	b43_write_mac_bssid_templates(dev);
+	b43_macfilter_set(dev, B43_MACFILTER_SELF, dev->wl->mac_addr);
+}
+
+static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time)
+{
+	/* slot_time is in usec. */
+	if (dev->phy.type != B43_PHYTYPE_G)
+		return;
+	b43_write16(dev, 0x684, 510 + slot_time);
+	b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time);
+}
+
+static void b43_short_slot_timing_enable(struct b43_wldev *dev)
+{
+	b43_set_slot_time(dev, 9);
+	dev->short_slot = 1;
+}
+
+static void b43_short_slot_timing_disable(struct b43_wldev *dev)
+{
+	b43_set_slot_time(dev, 20);
+	dev->short_slot = 0;
+}
+
+/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
+ * Returns the _previously_ enabled IRQ mask.
+ */
+static inline u32 b43_interrupt_enable(struct b43_wldev *dev, u32 mask)
+{
+	u32 old_mask;
+
+	old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
+	b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask | mask);
+
+	return old_mask;
+}
+
+/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
+ * Returns the _previously_ enabled IRQ mask.
+ */
+static inline u32 b43_interrupt_disable(struct b43_wldev *dev, u32 mask)
+{
+	u32 old_mask;
+
+	old_mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
+	b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
+
+	return old_mask;
+}
+
+/* Synchronize IRQ top- and bottom-half.
+ * IRQs must be masked before calling this.
+ * This must not be called with the irq_lock held.
+ */
+static void b43_synchronize_irq(struct b43_wldev *dev)
+{
+	synchronize_irq(dev->dev->irq);
+	tasklet_kill(&dev->isr_tasklet);
+}
+
+/* DummyTransmission function, as documented on
+ * http://bcm-specs.sipsolutions.net/DummyTransmission
+ */
+void b43_dummy_transmission(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	unsigned int i, max_loop;
+	u16 value;
+	u32 buffer[5] = {
+		0x00000000,
+		0x00D40000,
+		0x00000000,
+		0x01000000,
+		0x00000000,
+	};
+
+	switch (phy->type) {
+	case B43_PHYTYPE_A:
+		max_loop = 0x1E;
+		buffer[0] = 0x000201CC;
+		break;
+	case B43_PHYTYPE_B:
+	case B43_PHYTYPE_G:
+		max_loop = 0xFA;
+		buffer[0] = 0x000B846E;
+		break;
+	default:
+		B43_WARN_ON(1);
+		return;
+	}
+
+	for (i = 0; i < 5; i++)
+		b43_ram_write(dev, i * 4, buffer[i]);
+
+	/* Commit writes */
+	b43_read32(dev, B43_MMIO_MACCTL);
+
+	b43_write16(dev, 0x0568, 0x0000);
+	b43_write16(dev, 0x07C0, 0x0000);
+	value = ((phy->type == B43_PHYTYPE_A) ? 1 : 0);
+	b43_write16(dev, 0x050C, value);
+	b43_write16(dev, 0x0508, 0x0000);
+	b43_write16(dev, 0x050A, 0x0000);
+	b43_write16(dev, 0x054C, 0x0000);
+	b43_write16(dev, 0x056A, 0x0014);
+	b43_write16(dev, 0x0568, 0x0826);
+	b43_write16(dev, 0x0500, 0x0000);
+	b43_write16(dev, 0x0502, 0x0030);
+
+	if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
+		b43_radio_write16(dev, 0x0051, 0x0017);
+	for (i = 0x00; i < max_loop; i++) {
+		value = b43_read16(dev, 0x050E);
+		if (value & 0x0080)
+			break;
+		udelay(10);
+	}
+	for (i = 0x00; i < 0x0A; i++) {
+		value = b43_read16(dev, 0x050E);
+		if (value & 0x0400)
+			break;
+		udelay(10);
+	}
+	for (i = 0x00; i < 0x0A; i++) {
+		value = b43_read16(dev, 0x0690);
+		if (!(value & 0x0100))
+			break;
+		udelay(10);
+	}
+	if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
+		b43_radio_write16(dev, 0x0051, 0x0037);
+}
+
+static void key_write(struct b43_wldev *dev,
+		      u8 index, u8 algorithm, const u8 * key)
+{
+	unsigned int i;
+	u32 offset;
+	u16 value;
+	u16 kidx;
+
+	/* Key index/algo block */
+	kidx = b43_kidx_to_fw(dev, index);
+	value = ((kidx << 4) | algorithm);
+	b43_shm_write16(dev, B43_SHM_SHARED,
+			B43_SHM_SH_KEYIDXBLOCK + (kidx * 2), value);
+
+	/* Write the key to the Key Table Pointer offset */
+	offset = dev->ktp + (index * B43_SEC_KEYSIZE);
+	for (i = 0; i < B43_SEC_KEYSIZE; i += 2) {
+		value = key[i];
+		value |= (u16) (key[i + 1]) << 8;
+		b43_shm_write16(dev, B43_SHM_SHARED, offset + i, value);
+	}
+}
+
+static void keymac_write(struct b43_wldev *dev, u8 index, const u8 * addr)
+{
+	u32 addrtmp[2] = { 0, 0, };
+	u8 per_sta_keys_start = 8;
+
+	if (b43_new_kidx_api(dev))
+		per_sta_keys_start = 4;
+
+	B43_WARN_ON(index < per_sta_keys_start);
+	/* We have two default TX keys and possibly two default RX keys.
+	 * Physical mac 0 is mapped to physical key 4 or 8, depending
+	 * on the firmware version.
+	 * So we must adjust the index here.
+	 */
+	index -= per_sta_keys_start;
+
+	if (addr) {
+		addrtmp[0] = addr[0];
+		addrtmp[0] |= ((u32) (addr[1]) << 8);
+		addrtmp[0] |= ((u32) (addr[2]) << 16);
+		addrtmp[0] |= ((u32) (addr[3]) << 24);
+		addrtmp[1] = addr[4];
+		addrtmp[1] |= ((u32) (addr[5]) << 8);
+	}
+
+	if (dev->dev->id.revision >= 5) {
+		/* Receive match transmitter address mechanism */
+		b43_shm_write32(dev, B43_SHM_RCMTA,
+				(index * 2) + 0, addrtmp[0]);
+		b43_shm_write16(dev, B43_SHM_RCMTA,
+				(index * 2) + 1, addrtmp[1]);
+	} else {
+		/* RXE (Receive Engine) and
+		 * PSM (Programmable State Machine) mechanism
+		 */
+		if (index < 8) {
+			/* TODO write to RCM 16, 19, 22 and 25 */
+		} else {
+			b43_shm_write32(dev, B43_SHM_SHARED,
+					B43_SHM_SH_PSM + (index * 6) + 0,
+					addrtmp[0]);
+			b43_shm_write16(dev, B43_SHM_SHARED,
+					B43_SHM_SH_PSM + (index * 6) + 4,
+					addrtmp[1]);
+		}
+	}
+}
+
+static void do_key_write(struct b43_wldev *dev,
+			 u8 index, u8 algorithm,
+			 const u8 * key, size_t key_len, const u8 * mac_addr)
+{
+	u8 buf[B43_SEC_KEYSIZE] = { 0, };
+	u8 per_sta_keys_start = 8;
+
+	if (b43_new_kidx_api(dev))
+		per_sta_keys_start = 4;
+
+	B43_WARN_ON(index >= dev->max_nr_keys);
+	B43_WARN_ON(key_len > B43_SEC_KEYSIZE);
+
+	if (index >= per_sta_keys_start)
+		keymac_write(dev, index, NULL);	/* First zero out mac. */
+	if (key)
+		memcpy(buf, key, key_len);
+	key_write(dev, index, algorithm, buf);
+	if (index >= per_sta_keys_start)
+		keymac_write(dev, index, mac_addr);
+
+	dev->key[index].algorithm = algorithm;
+}
+
+static int b43_key_write(struct b43_wldev *dev,
+			 int index, u8 algorithm,
+			 const u8 * key, size_t key_len,
+			 const u8 * mac_addr,
+			 struct ieee80211_key_conf *keyconf)
+{
+	int i;
+	int sta_keys_start;
+
+	if (key_len > B43_SEC_KEYSIZE)
+		return -EINVAL;
+	for (i = 0; i < dev->max_nr_keys; i++) {
+		/* Check that we don't already have this key. */
+		B43_WARN_ON(dev->key[i].keyconf == keyconf);
+	}
+	if (index < 0) {
+		/* Either pairwise key or address is 00:00:00:00:00:00
+		 * for transmit-only keys. Search the index. */
+		if (b43_new_kidx_api(dev))
+			sta_keys_start = 4;
+		else
+			sta_keys_start = 8;
+		for (i = sta_keys_start; i < dev->max_nr_keys; i++) {
+			if (!dev->key[i].keyconf) {
+				/* found empty */
+				index = i;
+				break;
+			}
+		}
+		if (index < 0) {
+			b43err(dev->wl, "Out of hardware key memory\n");
+			return -ENOSPC;
+		}
+	} else
+		B43_WARN_ON(index > 3);
+
+	do_key_write(dev, index, algorithm, key, key_len, mac_addr);
+	if ((index <= 3) && !b43_new_kidx_api(dev)) {
+		/* Default RX key */
+		B43_WARN_ON(mac_addr);
+		do_key_write(dev, index + 4, algorithm, key, key_len, NULL);
+	}
+	keyconf->hw_key_idx = index;
+	dev->key[index].keyconf = keyconf;
+
+	return 0;
+}
+
+static int b43_key_clear(struct b43_wldev *dev, int index)
+{
+	if (B43_WARN_ON((index < 0) || (index >= dev->max_nr_keys)))
+		return -EINVAL;
+	do_key_write(dev, index, B43_SEC_ALGO_NONE,
+		     NULL, B43_SEC_KEYSIZE, NULL);
+	if ((index <= 3) && !b43_new_kidx_api(dev)) {
+		do_key_write(dev, index + 4, B43_SEC_ALGO_NONE,
+			     NULL, B43_SEC_KEYSIZE, NULL);
+	}
+	dev->key[index].keyconf = NULL;
+
+	return 0;
+}
+
+static void b43_clear_keys(struct b43_wldev *dev)
+{
+	int i;
+
+	for (i = 0; i < dev->max_nr_keys; i++)
+		b43_key_clear(dev, i);
+}
+
+void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
+{
+	u32 macctl;
+	u16 ucstat;
+	bool hwps;
+	bool awake;
+	int i;
+
+	B43_WARN_ON((ps_flags & B43_PS_ENABLED) &&
+		    (ps_flags & B43_PS_DISABLED));
+	B43_WARN_ON((ps_flags & B43_PS_AWAKE) && (ps_flags & B43_PS_ASLEEP));
+
+	if (ps_flags & B43_PS_ENABLED) {
+		hwps = 1;
+	} else if (ps_flags & B43_PS_DISABLED) {
+		hwps = 0;
+	} else {
+		//TODO: If powersave is not off and FIXME is not set and we are not in adhoc
+		//      and thus is not an AP and we are associated, set bit 25
+	}
+	if (ps_flags & B43_PS_AWAKE) {
+		awake = 1;
+	} else if (ps_flags & B43_PS_ASLEEP) {
+		awake = 0;
+	} else {
+		//TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
+		//      or we are associated, or FIXME, or the latest PS-Poll packet sent was
+		//      successful, set bit26
+	}
+
+/* FIXME: For now we force awake-on and hwps-off */
+	hwps = 0;
+	awake = 1;
+
+	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	if (hwps)
+		macctl |= B43_MACCTL_HWPS;
+	else
+		macctl &= ~B43_MACCTL_HWPS;
+	if (awake)
+		macctl |= B43_MACCTL_AWAKE;
+	else
+		macctl &= ~B43_MACCTL_AWAKE;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
+	/* Commit write */
+	b43_read32(dev, B43_MMIO_MACCTL);
+	if (awake && dev->dev->id.revision >= 5) {
+		/* Wait for the microcode to wake up. */
+		for (i = 0; i < 100; i++) {
+			ucstat = b43_shm_read16(dev, B43_SHM_SHARED,
+						B43_SHM_SH_UCODESTAT);
+			if (ucstat != B43_SHM_SH_UCODESTAT_SLEEP)
+				break;
+			udelay(10);
+		}
+	}
+}
+
+/* Turn the Analog ON/OFF */
+static void b43_switch_analog(struct b43_wldev *dev, int on)
+{
+	b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4);
+}
+
+void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
+{
+	u32 tmslow;
+	u32 macctl;
+
+	flags |= B43_TMSLOW_PHYCLKEN;
+	flags |= B43_TMSLOW_PHYRESET;
+	ssb_device_enable(dev->dev, flags);
+	msleep(2);		/* Wait for the PLL to turn on. */
+
+	/* Now take the PHY out of Reset again */
+	tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+	tmslow |= SSB_TMSLOW_FGC;
+	tmslow &= ~B43_TMSLOW_PHYRESET;
+	ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+	ssb_read32(dev->dev, SSB_TMSLOW);	/* flush */
+	msleep(1);
+	tmslow &= ~SSB_TMSLOW_FGC;
+	ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+	ssb_read32(dev->dev, SSB_TMSLOW);	/* flush */
+	msleep(1);
+
+	/* Turn Analog ON */
+	b43_switch_analog(dev, 1);
+
+	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	macctl &= ~B43_MACCTL_GMODE;
+	if (flags & B43_TMSLOW_GMODE)
+		macctl |= B43_MACCTL_GMODE;
+	macctl |= B43_MACCTL_IHR_ENABLED;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
+}
+
+static void handle_irq_transmit_status(struct b43_wldev *dev)
+{
+	u32 v0, v1;
+	u16 tmp;
+	struct b43_txstatus stat;
+
+	while (1) {
+		v0 = b43_read32(dev, B43_MMIO_XMITSTAT_0);
+		if (!(v0 & 0x00000001))
+			break;
+		v1 = b43_read32(dev, B43_MMIO_XMITSTAT_1);
+
+		stat.cookie = (v0 >> 16);
+		stat.seq = (v1 & 0x0000FFFF);
+		stat.phy_stat = ((v1 & 0x00FF0000) >> 16);
+		tmp = (v0 & 0x0000FFFF);
+		stat.frame_count = ((tmp & 0xF000) >> 12);
+		stat.rts_count = ((tmp & 0x0F00) >> 8);
+		stat.supp_reason = ((tmp & 0x001C) >> 2);
+		stat.pm_indicated = !!(tmp & 0x0080);
+		stat.intermediate = !!(tmp & 0x0040);
+		stat.for_ampdu = !!(tmp & 0x0020);
+		stat.acked = !!(tmp & 0x0002);
+
+		b43_handle_txstatus(dev, &stat);
+	}
+}
+
+static void drain_txstatus_queue(struct b43_wldev *dev)
+{
+	u32 dummy;
+
+	if (dev->dev->id.revision < 5)
+		return;
+	/* Read all entries from the microcode TXstatus FIFO
+	 * and throw them away.
+	 */
+	while (1) {
+		dummy = b43_read32(dev, B43_MMIO_XMITSTAT_0);
+		if (!(dummy & 0x00000001))
+			break;
+		dummy = b43_read32(dev, B43_MMIO_XMITSTAT_1);
+	}
+}
+
+static u32 b43_jssi_read(struct b43_wldev *dev)
+{
+	u32 val = 0;
+
+	val = b43_shm_read16(dev, B43_SHM_SHARED, 0x08A);
+	val <<= 16;
+	val |= b43_shm_read16(dev, B43_SHM_SHARED, 0x088);
+
+	return val;
+}
+
+static void b43_jssi_write(struct b43_wldev *dev, u32 jssi)
+{
+	b43_shm_write16(dev, B43_SHM_SHARED, 0x088, (jssi & 0x0000FFFF));
+	b43_shm_write16(dev, B43_SHM_SHARED, 0x08A, (jssi & 0xFFFF0000) >> 16);
+}
+
+static void b43_generate_noise_sample(struct b43_wldev *dev)
+{
+	b43_jssi_write(dev, 0x7F7F7F7F);
+	b43_write32(dev, B43_MMIO_STATUS2_BITFIELD,
+		    b43_read32(dev, B43_MMIO_STATUS2_BITFIELD)
+		    | (1 << 4));
+	B43_WARN_ON(dev->noisecalc.channel_at_start != dev->phy.channel);
+}
+
+static void b43_calculate_link_quality(struct b43_wldev *dev)
+{
+	/* Top half of Link Quality calculation. */
+
+	if (dev->noisecalc.calculation_running)
+		return;
+	dev->noisecalc.channel_at_start = dev->phy.channel;
+	dev->noisecalc.calculation_running = 1;
+	dev->noisecalc.nr_samples = 0;
+
+	b43_generate_noise_sample(dev);
+}
+
+static void handle_irq_noise(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 tmp;
+	u8 noise[4];
+	u8 i, j;
+	s32 average;
+
+	/* Bottom half of Link Quality calculation. */
+
+	B43_WARN_ON(!dev->noisecalc.calculation_running);
+	if (dev->noisecalc.channel_at_start != phy->channel)
+		goto drop_calculation;
+	*((__le32 *)noise) = cpu_to_le32(b43_jssi_read(dev));
+	if (noise[0] == 0x7F || noise[1] == 0x7F ||
+	    noise[2] == 0x7F || noise[3] == 0x7F)
+		goto generate_new;
+
+	/* Get the noise samples. */
+	B43_WARN_ON(dev->noisecalc.nr_samples >= 8);
+	i = dev->noisecalc.nr_samples;
+	noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+	noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+	noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+	noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+	dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]];
+	dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
+	dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
+	dev->noisecalc.samples[i][3] = phy->nrssi_lt[noise[3]];
+	dev->noisecalc.nr_samples++;
+	if (dev->noisecalc.nr_samples == 8) {
+		/* Calculate the Link Quality by the noise samples. */
+		average = 0;
+		for (i = 0; i < 8; i++) {
+			for (j = 0; j < 4; j++)
+				average += dev->noisecalc.samples[i][j];
+		}
+		average /= (8 * 4);
+		average *= 125;
+		average += 64;
+		average /= 128;
+		tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x40C);
+		tmp = (tmp / 128) & 0x1F;
+		if (tmp >= 8)
+			average += 2;
+		else
+			average -= 25;
+		if (tmp == 8)
+			average -= 72;
+		else
+			average -= 48;
+
+		dev->stats.link_noise = average;
+	      drop_calculation:
+		dev->noisecalc.calculation_running = 0;
+		return;
+	}
+      generate_new:
+	b43_generate_noise_sample(dev);
+}
+
+static void handle_irq_tbtt_indication(struct b43_wldev *dev)
+{
+	if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) {
+		///TODO: PS TBTT
+	} else {
+		if (1 /*FIXME: the last PSpoll frame was sent successfully */ )
+			b43_power_saving_ctl_bits(dev, 0);
+	}
+	dev->reg124_set_0x4 = 0;
+	if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
+		dev->reg124_set_0x4 = 1;
+}
+
+static void handle_irq_atim_end(struct b43_wldev *dev)
+{
+	if (!dev->reg124_set_0x4 /*FIXME rename this variable */ )
+		return;
+	b43_write32(dev, B43_MMIO_STATUS2_BITFIELD,
+		    b43_read32(dev, B43_MMIO_STATUS2_BITFIELD)
+		    | 0x4);
+}
+
+static void handle_irq_pmq(struct b43_wldev *dev)
+{
+	u32 tmp;
+
+	//TODO: AP mode.
+
+	while (1) {
+		tmp = b43_read32(dev, B43_MMIO_PS_STATUS);
+		if (!(tmp & 0x00000008))
+			break;
+	}
+	/* 16bit write is odd, but correct. */
+	b43_write16(dev, B43_MMIO_PS_STATUS, 0x0002);
+}
+
+static void b43_write_template_common(struct b43_wldev *dev,
+				      const u8 * data, u16 size,
+				      u16 ram_offset,
+				      u16 shm_size_offset, u8 rate)
+{
+	u32 i, tmp;
+	struct b43_plcp_hdr4 plcp;
+
+	plcp.data = 0;
+	b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+	b43_ram_write(dev, ram_offset, le32_to_cpu(plcp.data));
+	ram_offset += sizeof(u32);
+	/* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet.
+	 * So leave the first two bytes of the next write blank.
+	 */
+	tmp = (u32) (data[0]) << 16;
+	tmp |= (u32) (data[1]) << 24;
+	b43_ram_write(dev, ram_offset, tmp);
+	ram_offset += sizeof(u32);
+	for (i = 2; i < size; i += sizeof(u32)) {
+		tmp = (u32) (data[i + 0]);
+		if (i + 1 < size)
+			tmp |= (u32) (data[i + 1]) << 8;
+		if (i + 2 < size)
+			tmp |= (u32) (data[i + 2]) << 16;
+		if (i + 3 < size)
+			tmp |= (u32) (data[i + 3]) << 24;
+		b43_ram_write(dev, ram_offset + i - 2, tmp);
+	}
+	b43_shm_write16(dev, B43_SHM_SHARED, shm_size_offset,
+			size + sizeof(struct b43_plcp_hdr6));
+}
+
+static void b43_write_beacon_template(struct b43_wldev *dev,
+				      u16 ram_offset,
+				      u16 shm_size_offset, u8 rate)
+{
+	int len;
+	const u8 *data;
+
+	B43_WARN_ON(!dev->cached_beacon);
+	len = min((size_t) dev->cached_beacon->len,
+		  0x200 - sizeof(struct b43_plcp_hdr6));
+	data = (const u8 *)(dev->cached_beacon->data);
+	b43_write_template_common(dev, data,
+				  len, ram_offset, shm_size_offset, rate);
+}
+
+static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
+				      u16 shm_offset, u16 size, u8 rate)
+{
+	struct b43_plcp_hdr4 plcp;
+	u32 tmp;
+	__le16 dur;
+
+	plcp.data = 0;
+	b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+	dur = ieee80211_generic_frame_duration(dev->wl->hw,
+					       dev->wl->if_id, size,
+					       B43_RATE_TO_BASE100KBPS(rate));
+	/* Write PLCP in two parts and timing for packet transfer */
+	tmp = le32_to_cpu(plcp.data);
+	b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF);
+	b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 2, tmp >> 16);
+	b43_shm_write16(dev, B43_SHM_SHARED, shm_offset + 6, le16_to_cpu(dur));
+}
+
+/* Instead of using custom probe response template, this function
+ * just patches custom beacon template by:
+ * 1) Changing packet type
+ * 2) Patching duration field
+ * 3) Stripping TIM
+ */
+static u8 *b43_generate_probe_resp(struct b43_wldev *dev,
+				   u16 * dest_size, u8 rate)
+{
+	const u8 *src_data;
+	u8 *dest_data;
+	u16 src_size, elem_size, src_pos, dest_pos;
+	__le16 dur;
+	struct ieee80211_hdr *hdr;
+
+	B43_WARN_ON(!dev->cached_beacon);
+	src_size = dev->cached_beacon->len;
+	src_data = (const u8 *)dev->cached_beacon->data;
+
+	if (unlikely(src_size < 0x24)) {
+		b43dbg(dev->wl, "b43_generate_probe_resp: " "invalid beacon\n");
+		return NULL;
+	}
+
+	dest_data = kmalloc(src_size, GFP_ATOMIC);
+	if (unlikely(!dest_data))
+		return NULL;
+
+	/* 0x24 is offset of first variable-len Information-Element
+	 * in beacon frame.
+	 */
+	memcpy(dest_data, src_data, 0x24);
+	src_pos = dest_pos = 0x24;
+	for (; src_pos < src_size - 2; src_pos += elem_size) {
+		elem_size = src_data[src_pos + 1] + 2;
+		if (src_data[src_pos] != 0x05) {	/* TIM */
+			memcpy(dest_data + dest_pos, src_data + src_pos,
+			       elem_size);
+			dest_pos += elem_size;
+		}
+	}
+	*dest_size = dest_pos;
+	hdr = (struct ieee80211_hdr *)dest_data;
+
+	/* Set the frame control. */
+	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+					 IEEE80211_STYPE_PROBE_RESP);
+	dur = ieee80211_generic_frame_duration(dev->wl->hw,
+					       dev->wl->if_id, *dest_size,
+					       B43_RATE_TO_BASE100KBPS(rate));
+	hdr->duration_id = dur;
+
+	return dest_data;
+}
+
+static void b43_write_probe_resp_template(struct b43_wldev *dev,
+					  u16 ram_offset,
+					  u16 shm_size_offset, u8 rate)
+{
+	u8 *probe_resp_data;
+	u16 size;
+
+	B43_WARN_ON(!dev->cached_beacon);
+	size = dev->cached_beacon->len;
+	probe_resp_data = b43_generate_probe_resp(dev, &size, rate);
+	if (unlikely(!probe_resp_data))
+		return;
+
+	/* Looks like PLCP headers plus packet timings are stored for
+	 * all possible basic rates
+	 */
+	b43_write_probe_resp_plcp(dev, 0x31A, size, B43_CCK_RATE_1MB);
+	b43_write_probe_resp_plcp(dev, 0x32C, size, B43_CCK_RATE_2MB);
+	b43_write_probe_resp_plcp(dev, 0x33E, size, B43_CCK_RATE_5MB);
+	b43_write_probe_resp_plcp(dev, 0x350, size, B43_CCK_RATE_11MB);
+
+	size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6));
+	b43_write_template_common(dev, probe_resp_data,
+				  size, ram_offset, shm_size_offset, rate);
+	kfree(probe_resp_data);
+}
+
+static int b43_refresh_cached_beacon(struct b43_wldev *dev,
+				     struct sk_buff *beacon)
+{
+	if (dev->cached_beacon)
+		kfree_skb(dev->cached_beacon);
+	dev->cached_beacon = beacon;
+
+	return 0;
+}
+
+static void b43_update_templates(struct b43_wldev *dev)
+{
+	u32 status;
+
+	B43_WARN_ON(!dev->cached_beacon);
+
+	b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB);
+	b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB);
+	b43_write_probe_resp_template(dev, 0x268, 0x4A, B43_CCK_RATE_11MB);
+
+	status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD);
+	status |= 0x03;
+	b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
+}
+
+static void b43_refresh_templates(struct b43_wldev *dev, struct sk_buff *beacon)
+{
+	int err;
+
+	err = b43_refresh_cached_beacon(dev, beacon);
+	if (unlikely(err))
+		return;
+	b43_update_templates(dev);
+}
+
+static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len)
+{
+	u32 tmp;
+	u16 i, len;
+
+	len = min((u16) ssid_len, (u16) 0x100);
+	for (i = 0; i < len; i += sizeof(u32)) {
+		tmp = (u32) (ssid[i + 0]);
+		if (i + 1 < len)
+			tmp |= (u32) (ssid[i + 1]) << 8;
+		if (i + 2 < len)
+			tmp |= (u32) (ssid[i + 2]) << 16;
+		if (i + 3 < len)
+			tmp |= (u32) (ssid[i + 3]) << 24;
+		b43_shm_write32(dev, B43_SHM_SHARED, 0x380 + i, tmp);
+	}
+	b43_shm_write16(dev, B43_SHM_SHARED, 0x48, len);
+}
+
+static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
+{
+	b43_time_lock(dev);
+	if (dev->dev->id.revision >= 3) {
+		b43_write32(dev, 0x188, (beacon_int << 16));
+	} else {
+		b43_write16(dev, 0x606, (beacon_int >> 6));
+		b43_write16(dev, 0x610, beacon_int);
+	}
+	b43_time_unlock(dev);
+}
+
+static void handle_irq_beacon(struct b43_wldev *dev)
+{
+	u32 status;
+
+	if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+		return;
+
+	dev->irq_savedstate &= ~B43_IRQ_BEACON;
+	status = b43_read32(dev, B43_MMIO_STATUS2_BITFIELD);
+
+	if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) {
+		/* ACK beacon IRQ. */
+		b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_BEACON);
+		dev->irq_savedstate |= B43_IRQ_BEACON;
+		if (dev->cached_beacon)
+			kfree_skb(dev->cached_beacon);
+		dev->cached_beacon = NULL;
+		return;
+	}
+	if (!(status & 0x1)) {
+		b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB);
+		status |= 0x1;
+		b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
+	}
+	if (!(status & 0x2)) {
+		b43_write_beacon_template(dev, 0x468, 0x1A, B43_CCK_RATE_1MB);
+		status |= 0x2;
+		b43_write32(dev, B43_MMIO_STATUS2_BITFIELD, status);
+	}
+}
+
+static void handle_irq_ucode_debug(struct b43_wldev *dev)
+{
+	//TODO
+}
+
+/* Interrupt handler bottom-half */
+static void b43_interrupt_tasklet(struct b43_wldev *dev)
+{
+	u32 reason;
+	u32 dma_reason[ARRAY_SIZE(dev->dma_reason)];
+	u32 merged_dma_reason = 0;
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->wl->irq_lock, flags);
+
+	B43_WARN_ON(b43_status(dev) != B43_STAT_STARTED);
+
+	reason = dev->irq_reason;
+	for (i = 0; i < ARRAY_SIZE(dma_reason); i++) {
+		dma_reason[i] = dev->dma_reason[i];
+		merged_dma_reason |= dma_reason[i];
+	}
+
+	if (unlikely(reason & B43_IRQ_MAC_TXERR))
+		b43err(dev->wl, "MAC transmission error\n");
+
+	if (unlikely(reason & B43_IRQ_PHY_TXERR))
+		b43err(dev->wl, "PHY transmission error\n");
+
+	if (unlikely(merged_dma_reason & (B43_DMAIRQ_FATALMASK |
+					  B43_DMAIRQ_NONFATALMASK))) {
+		if (merged_dma_reason & B43_DMAIRQ_FATALMASK) {
+			b43err(dev->wl, "Fatal DMA error: "
+			       "0x%08X, 0x%08X, 0x%08X, "
+			       "0x%08X, 0x%08X, 0x%08X\n",
+			       dma_reason[0], dma_reason[1],
+			       dma_reason[2], dma_reason[3],
+			       dma_reason[4], dma_reason[5]);
+			b43_controller_restart(dev, "DMA error");
+			mmiowb();
+			spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+			return;
+		}
+		if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) {
+			b43err(dev->wl, "DMA error: "
+			       "0x%08X, 0x%08X, 0x%08X, "
+			       "0x%08X, 0x%08X, 0x%08X\n",
+			       dma_reason[0], dma_reason[1],
+			       dma_reason[2], dma_reason[3],
+			       dma_reason[4], dma_reason[5]);
+		}
+	}
+
+	if (unlikely(reason & B43_IRQ_UCODE_DEBUG))
+		handle_irq_ucode_debug(dev);
+	if (reason & B43_IRQ_TBTT_INDI)
+		handle_irq_tbtt_indication(dev);
+	if (reason & B43_IRQ_ATIM_END)
+		handle_irq_atim_end(dev);
+	if (reason & B43_IRQ_BEACON)
+		handle_irq_beacon(dev);
+	if (reason & B43_IRQ_PMQ)
+		handle_irq_pmq(dev);
+	if (reason & B43_IRQ_TXFIFO_FLUSH_OK)
+		;/* TODO */
+	if (reason & B43_IRQ_NOISESAMPLE_OK)
+		handle_irq_noise(dev);
+
+	/* Check the DMA reason registers for received data. */
+	if (dma_reason[0] & B43_DMAIRQ_RX_DONE) {
+		if (b43_using_pio(dev))
+			b43_pio_rx(dev->pio.queue0);
+		else
+			b43_dma_rx(dev->dma.rx_ring0);
+	}
+	B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE);
+	B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE);
+	if (dma_reason[3] & B43_DMAIRQ_RX_DONE) {
+		if (b43_using_pio(dev))
+			b43_pio_rx(dev->pio.queue3);
+		else
+			b43_dma_rx(dev->dma.rx_ring3);
+	}
+	B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE);
+	B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE);
+
+	if (reason & B43_IRQ_TX_OK)
+		handle_irq_transmit_status(dev);
+
+	b43_interrupt_enable(dev, dev->irq_savedstate);
+	mmiowb();
+	spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+}
+
+static void pio_irq_workaround(struct b43_wldev *dev, u16 base, int queueidx)
+{
+	u16 rxctl;
+
+	rxctl = b43_read16(dev, base + B43_PIO_RXCTL);
+	if (rxctl & B43_PIO_RXCTL_DATAAVAILABLE)
+		dev->dma_reason[queueidx] |= B43_DMAIRQ_RX_DONE;
+	else
+		dev->dma_reason[queueidx] &= ~B43_DMAIRQ_RX_DONE;
+}
+
+static void b43_interrupt_ack(struct b43_wldev *dev, u32 reason)
+{
+	if (b43_using_pio(dev) &&
+	    (dev->dev->id.revision < 3) &&
+	    (!(reason & B43_IRQ_PIO_WORKAROUND))) {
+		/* Apply a PIO specific workaround to the dma_reasons */
+		pio_irq_workaround(dev, B43_MMIO_PIO1_BASE, 0);
+		pio_irq_workaround(dev, B43_MMIO_PIO2_BASE, 1);
+		pio_irq_workaround(dev, B43_MMIO_PIO3_BASE, 2);
+		pio_irq_workaround(dev, B43_MMIO_PIO4_BASE, 3);
+	}
+
+	b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, reason);
+
+	b43_write32(dev, B43_MMIO_DMA0_REASON, dev->dma_reason[0]);
+	b43_write32(dev, B43_MMIO_DMA1_REASON, dev->dma_reason[1]);
+	b43_write32(dev, B43_MMIO_DMA2_REASON, dev->dma_reason[2]);
+	b43_write32(dev, B43_MMIO_DMA3_REASON, dev->dma_reason[3]);
+	b43_write32(dev, B43_MMIO_DMA4_REASON, dev->dma_reason[4]);
+	b43_write32(dev, B43_MMIO_DMA5_REASON, dev->dma_reason[5]);
+}
+
+/* Interrupt handler top-half */
+static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
+{
+	irqreturn_t ret = IRQ_NONE;
+	struct b43_wldev *dev = dev_id;
+	u32 reason;
+
+	if (!dev)
+		return IRQ_NONE;
+
+	spin_lock(&dev->wl->irq_lock);
+
+	if (b43_status(dev) < B43_STAT_STARTED)
+		goto out;
+	reason = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
+	if (reason == 0xffffffff)	/* shared IRQ */
+		goto out;
+	ret = IRQ_HANDLED;
+	reason &= b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
+	if (!reason)
+		goto out;
+
+	dev->dma_reason[0] = b43_read32(dev, B43_MMIO_DMA0_REASON)
+	    & 0x0001DC00;
+	dev->dma_reason[1] = b43_read32(dev, B43_MMIO_DMA1_REASON)
+	    & 0x0000DC00;
+	dev->dma_reason[2] = b43_read32(dev, B43_MMIO_DMA2_REASON)
+	    & 0x0000DC00;
+	dev->dma_reason[3] = b43_read32(dev, B43_MMIO_DMA3_REASON)
+	    & 0x0001DC00;
+	dev->dma_reason[4] = b43_read32(dev, B43_MMIO_DMA4_REASON)
+	    & 0x0000DC00;
+	dev->dma_reason[5] = b43_read32(dev, B43_MMIO_DMA5_REASON)
+	    & 0x0000DC00;
+
+	b43_interrupt_ack(dev, reason);
+	/* disable all IRQs. They are enabled again in the bottom half. */
+	dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
+	/* save the reason code and call our bottom half. */
+	dev->irq_reason = reason;
+	tasklet_schedule(&dev->isr_tasklet);
+      out:
+	mmiowb();
+	spin_unlock(&dev->wl->irq_lock);
+
+	return ret;
+}
+
+static void b43_release_firmware(struct b43_wldev *dev)
+{
+	release_firmware(dev->fw.ucode);
+	dev->fw.ucode = NULL;
+	release_firmware(dev->fw.pcm);
+	dev->fw.pcm = NULL;
+	release_firmware(dev->fw.initvals);
+	dev->fw.initvals = NULL;
+	release_firmware(dev->fw.initvals_band);
+	dev->fw.initvals_band = NULL;
+}
+
+static void b43_print_fw_helptext(struct b43_wl *wl)
+{
+	b43err(wl, "You must go to "
+	       "http://linuxwireless.org/en/users/Drivers/bcm43xx#devicefirmware "
+	       "and download the correct firmware (version 4).\n");
+}
+
+static int do_request_fw(struct b43_wldev *dev,
+			 const char *name,
+			 const struct firmware **fw)
+{
+	char path[sizeof(modparam_fwpostfix) + 32];
+	struct b43_fw_header *hdr;
+	u32 size;
+	int err;
+
+	if (!name)
+		return 0;
+
+	snprintf(path, ARRAY_SIZE(path),
+		 "b43%s/%s.fw",
+		 modparam_fwpostfix, name);
+	err = request_firmware(fw, path, dev->dev->dev);
+	if (err) {
+		b43err(dev->wl, "Firmware file \"%s\" not found "
+		       "or load failed.\n", path);
+		return err;
+	}
+	if ((*fw)->size < sizeof(struct b43_fw_header))
+		goto err_format;
+	hdr = (struct b43_fw_header *)((*fw)->data);
+	switch (hdr->type) {
+	case B43_FW_TYPE_UCODE:
+	case B43_FW_TYPE_PCM:
+		size = be32_to_cpu(hdr->size);
+		if (size != (*fw)->size - sizeof(struct b43_fw_header))
+			goto err_format;
+		/* fallthrough */
+	case B43_FW_TYPE_IV:
+		if (hdr->ver != 1)
+			goto err_format;
+		break;
+	default:
+		goto err_format;
+	}
+
+	return err;
+
+err_format:
+	b43err(dev->wl, "Firmware file \"%s\" format error.\n", path);
+	return -EPROTO;
+}
+
+static int b43_request_firmware(struct b43_wldev *dev)
+{
+	struct b43_firmware *fw = &dev->fw;
+	const u8 rev = dev->dev->id.revision;
+	const char *filename;
+	u32 tmshigh;
+	int err;
+
+	tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
+	if (!fw->ucode) {
+		if ((rev >= 5) && (rev <= 10))
+			filename = "ucode5";
+		else if ((rev >= 11) && (rev <= 12))
+			filename = "ucode11";
+		else if (rev >= 13)
+			filename = "ucode13";
+		else
+			goto err_no_ucode;
+		err = do_request_fw(dev, filename, &fw->ucode);
+		if (err)
+			goto err_load;
+	}
+	if (!fw->pcm) {
+		if ((rev >= 5) && (rev <= 10))
+			filename = "pcm5";
+		else if (rev >= 11)
+			filename = NULL;
+		else
+			goto err_no_pcm;
+		err = do_request_fw(dev, filename, &fw->pcm);
+		if (err)
+			goto err_load;
+	}
+	if (!fw->initvals) {
+		switch (dev->phy.type) {
+		case B43_PHYTYPE_A:
+			if ((rev >= 5) && (rev <= 10)) {
+				if (tmshigh & B43_TMSHIGH_GPHY)
+					filename = "a0g1initvals5";
+				else
+					filename = "a0g0initvals5";
+			} else
+				goto err_no_initvals;
+			break;
+		case B43_PHYTYPE_G:
+			if ((rev >= 5) && (rev <= 10))
+				filename = "b0g0initvals5";
+			else if (rev >= 13)
+				filename = "lp0initvals13";
+			else
+				goto err_no_initvals;
+			break;
+		default:
+			goto err_no_initvals;
+		}
+		err = do_request_fw(dev, filename, &fw->initvals);
+		if (err)
+			goto err_load;
+	}
+	if (!fw->initvals_band) {
+		switch (dev->phy.type) {
+		case B43_PHYTYPE_A:
+			if ((rev >= 5) && (rev <= 10)) {
+				if (tmshigh & B43_TMSHIGH_GPHY)
+					filename = "a0g1bsinitvals5";
+				else
+					filename = "a0g0bsinitvals5";
+			} else if (rev >= 11)
+				filename = NULL;
+			else
+				goto err_no_initvals;
+			break;
+		case B43_PHYTYPE_G:
+			if ((rev >= 5) && (rev <= 10))
+				filename = "b0g0bsinitvals5";
+			else if (rev >= 11)
+				filename = NULL;
+			else
+				goto err_no_initvals;
+			break;
+		default:
+			goto err_no_initvals;
+		}
+		err = do_request_fw(dev, filename, &fw->initvals_band);
+		if (err)
+			goto err_load;
+	}
+
+	return 0;
+
+err_load:
+	b43_print_fw_helptext(dev->wl);
+	goto error;
+
+err_no_ucode:
+	err = -ENODEV;
+	b43err(dev->wl, "No microcode available for core rev %u\n", rev);
+	goto error;
+
+err_no_pcm:
+	err = -ENODEV;
+	b43err(dev->wl, "No PCM available for core rev %u\n", rev);
+	goto error;
+
+err_no_initvals:
+	err = -ENODEV;
+	b43err(dev->wl, "No Initial Values firmware file for PHY %u, "
+	       "core rev %u\n", dev->phy.type, rev);
+	goto error;
+
+error:
+	b43_release_firmware(dev);
+	return err;
+}
+
+static int b43_upload_microcode(struct b43_wldev *dev)
+{
+	const size_t hdr_len = sizeof(struct b43_fw_header);
+	const __be32 *data;
+	unsigned int i, len;
+	u16 fwrev, fwpatch, fwdate, fwtime;
+	u32 tmp;
+	int err = 0;
+
+	/* Upload Microcode. */
+	data = (__be32 *) (dev->fw.ucode->data + hdr_len);
+	len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32);
+	b43_shm_control_word(dev, B43_SHM_UCODE | B43_SHM_AUTOINC_W, 0x0000);
+	for (i = 0; i < len; i++) {
+		b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
+		udelay(10);
+	}
+
+	if (dev->fw.pcm) {
+		/* Upload PCM data. */
+		data = (__be32 *) (dev->fw.pcm->data + hdr_len);
+		len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32);
+		b43_shm_control_word(dev, B43_SHM_HW, 0x01EA);
+		b43_write32(dev, B43_MMIO_SHM_DATA, 0x00004000);
+		/* No need for autoinc bit in SHM_HW */
+		b43_shm_control_word(dev, B43_SHM_HW, 0x01EB);
+		for (i = 0; i < len; i++) {
+			b43_write32(dev, B43_MMIO_SHM_DATA, be32_to_cpu(data[i]));
+			udelay(10);
+		}
+	}
+
+	b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, B43_IRQ_ALL);
+	b43_write32(dev, B43_MMIO_MACCTL,
+		    B43_MACCTL_PSM_RUN |
+		    B43_MACCTL_IHR_ENABLED | B43_MACCTL_INFRA);
+
+	/* Wait for the microcode to load and respond */
+	i = 0;
+	while (1) {
+		tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
+		if (tmp == B43_IRQ_MAC_SUSPENDED)
+			break;
+		i++;
+		if (i >= 50) {
+			b43err(dev->wl, "Microcode not responding\n");
+			b43_print_fw_helptext(dev->wl);
+			err = -ENODEV;
+			goto out;
+		}
+		udelay(10);
+	}
+	b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);	/* dummy read */
+
+	/* Get and check the revisions. */
+	fwrev = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEREV);
+	fwpatch = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEPATCH);
+	fwdate = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODEDATE);
+	fwtime = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_UCODETIME);
+
+	if (fwrev <= 0x128) {
+		b43err(dev->wl, "YOUR FIRMWARE IS TOO OLD. Firmware from "
+		       "binary drivers older than version 4.x is unsupported. "
+		       "You must upgrade your firmware files.\n");
+		b43_print_fw_helptext(dev->wl);
+		b43_write32(dev, B43_MMIO_MACCTL, 0);
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+	b43dbg(dev->wl, "Loading firmware version %u.%u "
+	       "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n",
+	       fwrev, fwpatch,
+	       (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
+	       (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
+
+	dev->fw.rev = fwrev;
+	dev->fw.patch = fwpatch;
+
+      out:
+	return err;
+}
+
+static int b43_write_initvals(struct b43_wldev *dev,
+			      const struct b43_iv *ivals,
+			      size_t count,
+			      size_t array_size)
+{
+	const struct b43_iv *iv;
+	u16 offset;
+	size_t i;
+	bool bit32;
+
+	BUILD_BUG_ON(sizeof(struct b43_iv) != 6);
+	iv = ivals;
+	for (i = 0; i < count; i++) {
+		if (array_size < sizeof(iv->offset_size))
+			goto err_format;
+		array_size -= sizeof(iv->offset_size);
+		offset = be16_to_cpu(iv->offset_size);
+		bit32 = !!(offset & B43_IV_32BIT);
+		offset &= B43_IV_OFFSET_MASK;
+		if (offset >= 0x1000)
+			goto err_format;
+		if (bit32) {
+			u32 value;
+
+			if (array_size < sizeof(iv->data.d32))
+				goto err_format;
+			array_size -= sizeof(iv->data.d32);
+
+			value = be32_to_cpu(get_unaligned(&iv->data.d32));
+			b43_write32(dev, offset, value);
+
+			iv = (const struct b43_iv *)((const uint8_t *)iv +
+							sizeof(__be16) +
+							sizeof(__be32));
+		} else {
+			u16 value;
+
+			if (array_size < sizeof(iv->data.d16))
+				goto err_format;
+			array_size -= sizeof(iv->data.d16);
+
+			value = be16_to_cpu(iv->data.d16);
+			b43_write16(dev, offset, value);
+
+			iv = (const struct b43_iv *)((const uint8_t *)iv +
+							sizeof(__be16) +
+							sizeof(__be16));
+		}
+	}
+	if (array_size)
+		goto err_format;
+
+	return 0;
+
+err_format:
+	b43err(dev->wl, "Initial Values Firmware file-format error.\n");
+	b43_print_fw_helptext(dev->wl);
+
+	return -EPROTO;
+}
+
+static int b43_upload_initvals(struct b43_wldev *dev)
+{
+	const size_t hdr_len = sizeof(struct b43_fw_header);
+	const struct b43_fw_header *hdr;
+	struct b43_firmware *fw = &dev->fw;
+	const struct b43_iv *ivals;
+	size_t count;
+	int err;
+
+	hdr = (const struct b43_fw_header *)(fw->initvals->data);
+	ivals = (const struct b43_iv *)(fw->initvals->data + hdr_len);
+	count = be32_to_cpu(hdr->size);
+	err = b43_write_initvals(dev, ivals, count,
+				 fw->initvals->size - hdr_len);
+	if (err)
+		goto out;
+	if (fw->initvals_band) {
+		hdr = (const struct b43_fw_header *)(fw->initvals_band->data);
+		ivals = (const struct b43_iv *)(fw->initvals_band->data + hdr_len);
+		count = be32_to_cpu(hdr->size);
+		err = b43_write_initvals(dev, ivals, count,
+					 fw->initvals_band->size - hdr_len);
+		if (err)
+			goto out;
+	}
+out:
+
+	return err;
+}
+
+/* Initialize the GPIOs
+ * http://bcm-specs.sipsolutions.net/GPIO
+ */
+static int b43_gpio_init(struct b43_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+	struct ssb_device *gpiodev, *pcidev = NULL;
+	u32 mask, set;
+
+	b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
+		    & ~B43_MACCTL_GPOUTSMSK);
+
+	b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK)
+		    | 0x000F);
+
+	mask = 0x0000001F;
+	set = 0x0000000F;
+	if (dev->dev->bus->chip_id == 0x4301) {
+		mask |= 0x0060;
+		set |= 0x0060;
+	}
+	if (0 /* FIXME: conditional unknown */ ) {
+		b43_write16(dev, B43_MMIO_GPIO_MASK,
+			    b43_read16(dev, B43_MMIO_GPIO_MASK)
+			    | 0x0100);
+		mask |= 0x0180;
+		set |= 0x0180;
+	}
+	if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL) {
+		b43_write16(dev, B43_MMIO_GPIO_MASK,
+			    b43_read16(dev, B43_MMIO_GPIO_MASK)
+			    | 0x0200);
+		mask |= 0x0200;
+		set |= 0x0200;
+	}
+	if (dev->dev->id.revision >= 2)
+		mask |= 0x0010;	/* FIXME: This is redundant. */
+
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+	pcidev = bus->pcicore.dev;
+#endif
+	gpiodev = bus->chipco.dev ? : pcidev;
+	if (!gpiodev)
+		return 0;
+	ssb_write32(gpiodev, B43_GPIO_CONTROL,
+		    (ssb_read32(gpiodev, B43_GPIO_CONTROL)
+		     & mask) | set);
+
+	return 0;
+}
+
+/* Turn off all GPIO stuff. Call this on module unload, for example. */
+static void b43_gpio_cleanup(struct b43_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+	struct ssb_device *gpiodev, *pcidev = NULL;
+
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+	pcidev = bus->pcicore.dev;
+#endif
+	gpiodev = bus->chipco.dev ? : pcidev;
+	if (!gpiodev)
+		return;
+	ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
+}
+
+/* http://bcm-specs.sipsolutions.net/EnableMac */
+void b43_mac_enable(struct b43_wldev *dev)
+{
+	dev->mac_suspended--;
+	B43_WARN_ON(dev->mac_suspended < 0);
+	B43_WARN_ON(irqs_disabled());
+	if (dev->mac_suspended == 0) {
+		b43_write32(dev, B43_MMIO_MACCTL,
+			    b43_read32(dev, B43_MMIO_MACCTL)
+			    | B43_MACCTL_ENABLED);
+		b43_write32(dev, B43_MMIO_GEN_IRQ_REASON,
+			    B43_IRQ_MAC_SUSPENDED);
+		/* Commit writes */
+		b43_read32(dev, B43_MMIO_MACCTL);
+		b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
+		b43_power_saving_ctl_bits(dev, 0);
+
+		/* Re-enable IRQs. */
+		spin_lock_irq(&dev->wl->irq_lock);
+		b43_interrupt_enable(dev, dev->irq_savedstate);
+		spin_unlock_irq(&dev->wl->irq_lock);
+	}
+}
+
+/* http://bcm-specs.sipsolutions.net/SuspendMAC */
+void b43_mac_suspend(struct b43_wldev *dev)
+{
+	int i;
+	u32 tmp;
+
+	might_sleep();
+	B43_WARN_ON(irqs_disabled());
+	B43_WARN_ON(dev->mac_suspended < 0);
+
+	if (dev->mac_suspended == 0) {
+		/* Mask IRQs before suspending MAC. Otherwise
+		 * the MAC stays busy and won't suspend. */
+		spin_lock_irq(&dev->wl->irq_lock);
+		tmp = b43_interrupt_disable(dev, B43_IRQ_ALL);
+		spin_unlock_irq(&dev->wl->irq_lock);
+		b43_synchronize_irq(dev);
+		dev->irq_savedstate = tmp;
+
+		b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
+		b43_write32(dev, B43_MMIO_MACCTL,
+			    b43_read32(dev, B43_MMIO_MACCTL)
+			    & ~B43_MACCTL_ENABLED);
+		/* force pci to flush the write */
+		b43_read32(dev, B43_MMIO_MACCTL);
+		for (i = 40; i; i--) {
+			tmp = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
+			if (tmp & B43_IRQ_MAC_SUSPENDED)
+				goto out;
+			msleep(1);
+		}
+		b43err(dev->wl, "MAC suspend failed\n");
+	}
+out:
+	dev->mac_suspended++;
+}
+
+static void b43_adjust_opmode(struct b43_wldev *dev)
+{
+	struct b43_wl *wl = dev->wl;
+	u32 ctl;
+	u16 cfp_pretbtt;
+
+	ctl = b43_read32(dev, B43_MMIO_MACCTL);
+	/* Reset status to STA infrastructure mode. */
+	ctl &= ~B43_MACCTL_AP;
+	ctl &= ~B43_MACCTL_KEEP_CTL;
+	ctl &= ~B43_MACCTL_KEEP_BADPLCP;
+	ctl &= ~B43_MACCTL_KEEP_BAD;
+	ctl &= ~B43_MACCTL_PROMISC;
+	ctl &= ~B43_MACCTL_BEACPROMISC;
+	ctl |= B43_MACCTL_INFRA;
+
+	if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
+		ctl |= B43_MACCTL_AP;
+	else if (b43_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
+		ctl &= ~B43_MACCTL_INFRA;
+
+	if (wl->filter_flags & FIF_CONTROL)
+		ctl |= B43_MACCTL_KEEP_CTL;
+	if (wl->filter_flags & FIF_FCSFAIL)
+		ctl |= B43_MACCTL_KEEP_BAD;
+	if (wl->filter_flags & FIF_PLCPFAIL)
+		ctl |= B43_MACCTL_KEEP_BADPLCP;
+	if (wl->filter_flags & FIF_PROMISC_IN_BSS)
+		ctl |= B43_MACCTL_PROMISC;
+	if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
+		ctl |= B43_MACCTL_BEACPROMISC;
+
+	/* Workaround: On old hardware the HW-MAC-address-filter
+	 * doesn't work properly, so always run promisc in filter
+	 * it in software. */
+	if (dev->dev->id.revision <= 4)
+		ctl |= B43_MACCTL_PROMISC;
+
+	b43_write32(dev, B43_MMIO_MACCTL, ctl);
+
+	cfp_pretbtt = 2;
+	if ((ctl & B43_MACCTL_INFRA) && !(ctl & B43_MACCTL_AP)) {
+		if (dev->dev->bus->chip_id == 0x4306 &&
+		    dev->dev->bus->chip_rev == 3)
+			cfp_pretbtt = 100;
+		else
+			cfp_pretbtt = 50;
+	}
+	b43_write16(dev, 0x612, cfp_pretbtt);
+}
+
+static void b43_rate_memory_write(struct b43_wldev *dev, u16 rate, int is_ofdm)
+{
+	u16 offset;
+
+	if (is_ofdm) {
+		offset = 0x480;
+		offset += (b43_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
+	} else {
+		offset = 0x4C0;
+		offset += (b43_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
+	}
+	b43_shm_write16(dev, B43_SHM_SHARED, offset + 0x20,
+			b43_shm_read16(dev, B43_SHM_SHARED, offset));
+}
+
+static void b43_rate_memory_init(struct b43_wldev *dev)
+{
+	switch (dev->phy.type) {
+	case B43_PHYTYPE_A:
+	case B43_PHYTYPE_G:
+		b43_rate_memory_write(dev, B43_OFDM_RATE_6MB, 1);
+		b43_rate_memory_write(dev, B43_OFDM_RATE_12MB, 1);
+		b43_rate_memory_write(dev, B43_OFDM_RATE_18MB, 1);
+		b43_rate_memory_write(dev, B43_OFDM_RATE_24MB, 1);
+		b43_rate_memory_write(dev, B43_OFDM_RATE_36MB, 1);
+		b43_rate_memory_write(dev, B43_OFDM_RATE_48MB, 1);
+		b43_rate_memory_write(dev, B43_OFDM_RATE_54MB, 1);
+		if (dev->phy.type == B43_PHYTYPE_A)
+			break;
+		/* fallthrough */
+	case B43_PHYTYPE_B:
+		b43_rate_memory_write(dev, B43_CCK_RATE_1MB, 0);
+		b43_rate_memory_write(dev, B43_CCK_RATE_2MB, 0);
+		b43_rate_memory_write(dev, B43_CCK_RATE_5MB, 0);
+		b43_rate_memory_write(dev, B43_CCK_RATE_11MB, 0);
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+}
+
+/* Set the TX-Antenna for management frames sent by firmware. */
+static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
+{
+	u16 ant = 0;
+	u16 tmp;
+
+	switch (antenna) {
+	case B43_ANTENNA0:
+		ant |= B43_TX4_PHY_ANT0;
+		break;
+	case B43_ANTENNA1:
+		ant |= B43_TX4_PHY_ANT1;
+		break;
+	case B43_ANTENNA_AUTO:
+		ant |= B43_TX4_PHY_ANTLAST;
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+
+	/* FIXME We also need to set the other flags of the PHY control field somewhere. */
+
+	/* For Beacons */
+	tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
+	tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, tmp);
+	/* For ACK/CTS */
+	tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL);
+	tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL, tmp);
+	/* For Probe Resposes */
+	tmp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL);
+	tmp = (tmp & ~B43_TX4_PHY_ANT) | ant;
+	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRPHYCTL, tmp);
+}
+
+/* This is the opposite of b43_chip_init() */
+static void b43_chip_exit(struct b43_wldev *dev)
+{
+	b43_radio_turn_off(dev, 1);
+	b43_leds_exit(dev);
+	b43_gpio_cleanup(dev);
+	/* firmware is released later */
+}
+
+/* Initialize the chip
+ * http://bcm-specs.sipsolutions.net/ChipInit
+ */
+static int b43_chip_init(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	int err, tmp;
+	u32 value32;
+	u16 value16;
+
+	b43_write32(dev, B43_MMIO_MACCTL,
+		    B43_MACCTL_PSM_JMP0 | B43_MACCTL_IHR_ENABLED);
+
+	err = b43_request_firmware(dev);
+	if (err)
+		goto out;
+	err = b43_upload_microcode(dev);
+	if (err)
+		goto out;	/* firmware is released later */
+
+	err = b43_gpio_init(dev);
+	if (err)
+		goto out;	/* firmware is released later */
+	b43_leds_init(dev);
+
+	err = b43_upload_initvals(dev);
+	if (err)
+		goto err_leds_exit;
+	b43_radio_turn_on(dev);
+
+	b43_write16(dev, 0x03E6, 0x0000);
+	err = b43_phy_init(dev);
+	if (err)
+		goto err_radio_off;
+
+	/* Select initial Interference Mitigation. */
+	tmp = phy->interfmode;
+	phy->interfmode = B43_INTERFMODE_NONE;
+	b43_radio_set_interference_mitigation(dev, tmp);
+
+	b43_set_rx_antenna(dev, B43_ANTENNA_DEFAULT);
+	b43_mgmtframe_txantenna(dev, B43_ANTENNA_DEFAULT);
+
+	if (phy->type == B43_PHYTYPE_B) {
+		value16 = b43_read16(dev, 0x005E);
+		value16 |= 0x0004;
+		b43_write16(dev, 0x005E, value16);
+	}
+	b43_write32(dev, 0x0100, 0x01000000);
+	if (dev->dev->id.revision < 5)
+		b43_write32(dev, 0x010C, 0x01000000);
+
+	b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
+		    & ~B43_MACCTL_INFRA);
+	b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
+		    | B43_MACCTL_INFRA);
+
+	if (b43_using_pio(dev)) {
+		b43_write32(dev, 0x0210, 0x00000100);
+		b43_write32(dev, 0x0230, 0x00000100);
+		b43_write32(dev, 0x0250, 0x00000100);
+		b43_write32(dev, 0x0270, 0x00000100);
+		b43_shm_write16(dev, B43_SHM_SHARED, 0x0034, 0x0000);
+	}
+
+	/* Probe Response Timeout value */
+	/* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
+	b43_shm_write16(dev, B43_SHM_SHARED, 0x0074, 0x0000);
+
+	/* Initially set the wireless operation mode. */
+	b43_adjust_opmode(dev);
+
+	if (dev->dev->id.revision < 3) {
+		b43_write16(dev, 0x060E, 0x0000);
+		b43_write16(dev, 0x0610, 0x8000);
+		b43_write16(dev, 0x0604, 0x0000);
+		b43_write16(dev, 0x0606, 0x0200);
+	} else {
+		b43_write32(dev, 0x0188, 0x80000000);
+		b43_write32(dev, 0x018C, 0x02000000);
+	}
+	b43_write32(dev, B43_MMIO_GEN_IRQ_REASON, 0x00004000);
+	b43_write32(dev, B43_MMIO_DMA0_IRQ_MASK, 0x0001DC00);
+	b43_write32(dev, B43_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
+	b43_write32(dev, B43_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
+	b43_write32(dev, B43_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
+	b43_write32(dev, B43_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
+	b43_write32(dev, B43_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
+
+	value32 = ssb_read32(dev->dev, SSB_TMSLOW);
+	value32 |= 0x00100000;
+	ssb_write32(dev->dev, SSB_TMSLOW, value32);
+
+	b43_write16(dev, B43_MMIO_POWERUP_DELAY,
+		    dev->dev->bus->chipco.fast_pwrup_delay);
+
+	err = 0;
+	b43dbg(dev->wl, "Chip initialized\n");
+out:
+	return err;
+
+err_radio_off:
+	b43_radio_turn_off(dev, 1);
+err_leds_exit:
+	b43_leds_exit(dev);
+	b43_gpio_cleanup(dev);
+	return err;
+}
+
+static void b43_periodic_every120sec(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (phy->type != B43_PHYTYPE_G || phy->rev < 2)
+		return;
+
+	b43_mac_suspend(dev);
+	b43_lo_g_measure(dev);
+	b43_mac_enable(dev);
+	if (b43_has_hardware_pctl(phy))
+		b43_lo_g_ctl_mark_all_unused(dev);
+}
+
+static void b43_periodic_every60sec(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (!b43_has_hardware_pctl(phy))
+		b43_lo_g_ctl_mark_all_unused(dev);
+	if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+		b43_mac_suspend(dev);
+		b43_calc_nrssi_slope(dev);
+		if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 8)) {
+			u8 old_chan = phy->channel;
+
+			/* VCO Calibration */
+			if (old_chan >= 8)
+				b43_radio_selectchannel(dev, 1, 0);
+			else
+				b43_radio_selectchannel(dev, 13, 0);
+			b43_radio_selectchannel(dev, old_chan, 0);
+		}
+		b43_mac_enable(dev);
+	}
+}
+
+static void b43_periodic_every30sec(struct b43_wldev *dev)
+{
+	/* Update device statistics. */
+	b43_calculate_link_quality(dev);
+}
+
+static void b43_periodic_every15sec(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (phy->type == B43_PHYTYPE_G) {
+		//TODO: update_aci_moving_average
+		if (phy->aci_enable && phy->aci_wlan_automatic) {
+			b43_mac_suspend(dev);
+			if (!phy->aci_enable && 1 /*TODO: not scanning? */ ) {
+				if (0 /*TODO: bunch of conditions */ ) {
+					b43_radio_set_interference_mitigation
+					    (dev, B43_INTERFMODE_MANUALWLAN);
+				}
+			} else if (1 /*TODO*/) {
+				/*
+				   if ((aci_average > 1000) && !(b43_radio_aci_scan(dev))) {
+				   b43_radio_set_interference_mitigation(dev,
+				   B43_INTERFMODE_NONE);
+				   }
+				 */
+			}
+			b43_mac_enable(dev);
+		} else if (phy->interfmode == B43_INTERFMODE_NONWLAN &&
+			   phy->rev == 1) {
+			//TODO: implement rev1 workaround
+		}
+	}
+	b43_phy_xmitpower(dev);	//FIXME: unless scanning?
+	//TODO for APHY (temperature?)
+}
+
+static void do_periodic_work(struct b43_wldev *dev)
+{
+	unsigned int state;
+
+	state = dev->periodic_state;
+	if (state % 8 == 0)
+		b43_periodic_every120sec(dev);
+	if (state % 4 == 0)
+		b43_periodic_every60sec(dev);
+	if (state % 2 == 0)
+		b43_periodic_every30sec(dev);
+	b43_periodic_every15sec(dev);
+}
+
+/* Periodic work locking policy:
+ * 	The whole periodic work handler is protected by
+ * 	wl->mutex. If another lock is needed somewhere in the
+ * 	pwork callchain, it's aquired in-place, where it's needed.
+ */
+static void b43_periodic_work_handler(struct work_struct *work)
+{
+	struct b43_wldev *dev = container_of(work, struct b43_wldev,
+					     periodic_work.work);
+	struct b43_wl *wl = dev->wl;
+	unsigned long delay;
+
+	mutex_lock(&wl->mutex);
+
+	if (unlikely(b43_status(dev) != B43_STAT_STARTED))
+		goto out;
+	if (b43_debug(dev, B43_DBG_PWORK_STOP))
+		goto out_requeue;
+
+	do_periodic_work(dev);
+
+	dev->periodic_state++;
+out_requeue:
+	if (b43_debug(dev, B43_DBG_PWORK_FAST))
+		delay = msecs_to_jiffies(50);
+	else
+		delay = round_jiffies(HZ * 15);
+	queue_delayed_work(wl->hw->workqueue, &dev->periodic_work, delay);
+out:
+	mutex_unlock(&wl->mutex);
+}
+
+static void b43_periodic_tasks_setup(struct b43_wldev *dev)
+{
+	struct delayed_work *work = &dev->periodic_work;
+
+	dev->periodic_state = 0;
+	INIT_DELAYED_WORK(work, b43_periodic_work_handler);
+	queue_delayed_work(dev->wl->hw->workqueue, work, 0);
+}
+
+/* Validate access to the chip (SHM) */
+static int b43_validate_chipaccess(struct b43_wldev *dev)
+{
+	u32 value;
+	u32 shm_backup;
+
+	shm_backup = b43_shm_read32(dev, B43_SHM_SHARED, 0);
+	b43_shm_write32(dev, B43_SHM_SHARED, 0, 0xAA5555AA);
+	if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0xAA5555AA)
+		goto error;
+	b43_shm_write32(dev, B43_SHM_SHARED, 0, 0x55AAAA55);
+	if (b43_shm_read32(dev, B43_SHM_SHARED, 0) != 0x55AAAA55)
+		goto error;
+	b43_shm_write32(dev, B43_SHM_SHARED, 0, shm_backup);
+
+	value = b43_read32(dev, B43_MMIO_MACCTL);
+	if ((value | B43_MACCTL_GMODE) !=
+	    (B43_MACCTL_GMODE | B43_MACCTL_IHR_ENABLED))
+		goto error;
+
+	value = b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);
+	if (value)
+		goto error;
+
+	return 0;
+      error:
+	b43err(dev->wl, "Failed to validate the chipaccess\n");
+	return -ENODEV;
+}
+
+static void b43_security_init(struct b43_wldev *dev)
+{
+	dev->max_nr_keys = (dev->dev->id.revision >= 5) ? 58 : 20;
+	B43_WARN_ON(dev->max_nr_keys > ARRAY_SIZE(dev->key));
+	dev->ktp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_KTP);
+	/* KTP is a word address, but we address SHM bytewise.
+	 * So multiply by two.
+	 */
+	dev->ktp *= 2;
+	if (dev->dev->id.revision >= 5) {
+		/* Number of RCMTA address slots */
+		b43_write16(dev, B43_MMIO_RCMTA_COUNT, dev->max_nr_keys - 8);
+	}
+	b43_clear_keys(dev);
+}
+
+static int b43_rng_read(struct hwrng *rng, u32 * data)
+{
+	struct b43_wl *wl = (struct b43_wl *)rng->priv;
+	unsigned long flags;
+
+	/* Don't take wl->mutex here, as it could deadlock with
+	 * hwrng internal locking. It's not needed to take
+	 * wl->mutex here, anyway. */
+
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	*data = b43_read16(wl->current_dev, B43_MMIO_RNG);
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+	return (sizeof(u16));
+}
+
+static void b43_rng_exit(struct b43_wl *wl)
+{
+	if (wl->rng_initialized)
+		hwrng_unregister(&wl->rng);
+}
+
+static int b43_rng_init(struct b43_wl *wl)
+{
+	int err;
+
+	snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name),
+		 "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy));
+	wl->rng.name = wl->rng_name;
+	wl->rng.data_read = b43_rng_read;
+	wl->rng.priv = (unsigned long)wl;
+	wl->rng_initialized = 1;
+	err = hwrng_register(&wl->rng);
+	if (err) {
+		wl->rng_initialized = 0;
+		b43err(wl, "Failed to register the random "
+		       "number generator (%d)\n", err);
+	}
+
+	return err;
+}
+
+static int b43_tx(struct ieee80211_hw *hw,
+		  struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev = wl->current_dev;
+	int err = -ENODEV;
+	unsigned long flags;
+
+	if (unlikely(!dev))
+		goto out;
+	if (unlikely(b43_status(dev) < B43_STAT_STARTED))
+		goto out;
+	/* DMA-TX is done without a global lock. */
+	if (b43_using_pio(dev)) {
+		spin_lock_irqsave(&wl->irq_lock, flags);
+		err = b43_pio_tx(dev, skb, ctl);
+		spin_unlock_irqrestore(&wl->irq_lock, flags);
+	} else
+		err = b43_dma_tx(dev, skb, ctl);
+      out:
+	if (unlikely(err))
+		return NETDEV_TX_BUSY;
+	return NETDEV_TX_OK;
+}
+
+static int b43_conf_tx(struct ieee80211_hw *hw,
+		       int queue,
+		       const struct ieee80211_tx_queue_params *params)
+{
+	return 0;
+}
+
+static int b43_get_tx_stats(struct ieee80211_hw *hw,
+			    struct ieee80211_tx_queue_stats *stats)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev = wl->current_dev;
+	unsigned long flags;
+	int err = -ENODEV;
+
+	if (!dev)
+		goto out;
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	if (likely(b43_status(dev) >= B43_STAT_STARTED)) {
+		if (b43_using_pio(dev))
+			b43_pio_get_tx_stats(dev, stats);
+		else
+			b43_dma_get_tx_stats(dev, stats);
+		err = 0;
+	}
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+      out:
+	return err;
+}
+
+static int b43_get_stats(struct ieee80211_hw *hw,
+			 struct ieee80211_low_level_stats *stats)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	unsigned long flags;
+
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	memcpy(stats, &wl->ieee_stats, sizeof(*stats));
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+	return 0;
+}
+
+static const char *phymode_to_string(unsigned int phymode)
+{
+	switch (phymode) {
+	case B43_PHYMODE_A:
+		return "A";
+	case B43_PHYMODE_B:
+		return "B";
+	case B43_PHYMODE_G:
+		return "G";
+	default:
+		B43_WARN_ON(1);
+	}
+	return "";
+}
+
+static int find_wldev_for_phymode(struct b43_wl *wl,
+				  unsigned int phymode,
+				  struct b43_wldev **dev, bool * gmode)
+{
+	struct b43_wldev *d;
+
+	list_for_each_entry(d, &wl->devlist, list) {
+		if (d->phy.possible_phymodes & phymode) {
+			/* Ok, this device supports the PHY-mode.
+			 * Now figure out how the gmode bit has to be
+			 * set to support it. */
+			if (phymode == B43_PHYMODE_A)
+				*gmode = 0;
+			else
+				*gmode = 1;
+			*dev = d;
+
+			return 0;
+		}
+	}
+
+	return -ESRCH;
+}
+
+static void b43_put_phy_into_reset(struct b43_wldev *dev)
+{
+	struct ssb_device *sdev = dev->dev;
+	u32 tmslow;
+
+	tmslow = ssb_read32(sdev, SSB_TMSLOW);
+	tmslow &= ~B43_TMSLOW_GMODE;
+	tmslow |= B43_TMSLOW_PHYRESET;
+	tmslow |= SSB_TMSLOW_FGC;
+	ssb_write32(sdev, SSB_TMSLOW, tmslow);
+	msleep(1);
+
+	tmslow = ssb_read32(sdev, SSB_TMSLOW);
+	tmslow &= ~SSB_TMSLOW_FGC;
+	tmslow |= B43_TMSLOW_PHYRESET;
+	ssb_write32(sdev, SSB_TMSLOW, tmslow);
+	msleep(1);
+}
+
+/* Expects wl->mutex locked */
+static int b43_switch_phymode(struct b43_wl *wl, unsigned int new_mode)
+{
+	struct b43_wldev *up_dev;
+	struct b43_wldev *down_dev;
+	int err;
+	bool gmode = 0;
+	int prev_status;
+
+	err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode);
+	if (err) {
+		b43err(wl, "Could not find a device for %s-PHY mode\n",
+		       phymode_to_string(new_mode));
+		return err;
+	}
+	if ((up_dev == wl->current_dev) &&
+	    (!!wl->current_dev->phy.gmode == !!gmode)) {
+		/* This device is already running. */
+		return 0;
+	}
+	b43dbg(wl, "Reconfiguring PHYmode to %s-PHY\n",
+	       phymode_to_string(new_mode));
+	down_dev = wl->current_dev;
+
+	prev_status = b43_status(down_dev);
+	/* Shutdown the currently running core. */
+	if (prev_status >= B43_STAT_STARTED)
+		b43_wireless_core_stop(down_dev);
+	if (prev_status >= B43_STAT_INITIALIZED)
+		b43_wireless_core_exit(down_dev);
+
+	if (down_dev != up_dev) {
+		/* We switch to a different core, so we put PHY into
+		 * RESET on the old core. */
+		b43_put_phy_into_reset(down_dev);
+	}
+
+	/* Now start the new core. */
+	up_dev->phy.gmode = gmode;
+	if (prev_status >= B43_STAT_INITIALIZED) {
+		err = b43_wireless_core_init(up_dev);
+		if (err) {
+			b43err(wl, "Fatal: Could not initialize device for "
+			       "newly selected %s-PHY mode\n",
+			       phymode_to_string(new_mode));
+			goto init_failure;
+		}
+	}
+	if (prev_status >= B43_STAT_STARTED) {
+		err = b43_wireless_core_start(up_dev);
+		if (err) {
+			b43err(wl, "Fatal: Coult not start device for "
+			       "newly selected %s-PHY mode\n",
+			       phymode_to_string(new_mode));
+			b43_wireless_core_exit(up_dev);
+			goto init_failure;
+		}
+	}
+	B43_WARN_ON(b43_status(up_dev) != prev_status);
+
+	wl->current_dev = up_dev;
+
+	return 0;
+      init_failure:
+	/* Whoops, failed to init the new core. No core is operating now. */
+	wl->current_dev = NULL;
+	return err;
+}
+
+static int b43_antenna_from_ieee80211(u8 antenna)
+{
+	switch (antenna) {
+	case 0:		/* default/diversity */
+		return B43_ANTENNA_DEFAULT;
+	case 1:		/* Antenna 0 */
+		return B43_ANTENNA0;
+	case 2:		/* Antenna 1 */
+		return B43_ANTENNA1;
+	default:
+		return B43_ANTENNA_DEFAULT;
+	}
+}
+
+static int b43_dev_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev;
+	struct b43_phy *phy;
+	unsigned long flags;
+	unsigned int new_phymode = 0xFFFF;
+	int antenna_tx;
+	int antenna_rx;
+	int err = 0;
+	u32 savedirqs;
+
+	antenna_tx = b43_antenna_from_ieee80211(conf->antenna_sel_tx);
+	antenna_rx = b43_antenna_from_ieee80211(conf->antenna_sel_rx);
+
+	mutex_lock(&wl->mutex);
+
+	/* Switch the PHY mode (if necessary). */
+	switch (conf->phymode) {
+	case MODE_IEEE80211A:
+		new_phymode = B43_PHYMODE_A;
+		break;
+	case MODE_IEEE80211B:
+		new_phymode = B43_PHYMODE_B;
+		break;
+	case MODE_IEEE80211G:
+		new_phymode = B43_PHYMODE_G;
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+	err = b43_switch_phymode(wl, new_phymode);
+	if (err)
+		goto out_unlock_mutex;
+	dev = wl->current_dev;
+	phy = &dev->phy;
+
+	/* Disable IRQs while reconfiguring the device.
+	 * This makes it possible to drop the spinlock throughout
+	 * the reconfiguration process. */
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	if (b43_status(dev) < B43_STAT_STARTED) {
+		spin_unlock_irqrestore(&wl->irq_lock, flags);
+		goto out_unlock_mutex;
+	}
+	savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL);
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+	b43_synchronize_irq(dev);
+
+	/* Switch to the requested channel.
+	 * The firmware takes care of races with the TX handler. */
+	if (conf->channel_val != phy->channel)
+		b43_radio_selectchannel(dev, conf->channel_val, 0);
+
+	/* Enable/Disable ShortSlot timing. */
+	if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) !=
+	    dev->short_slot) {
+		B43_WARN_ON(phy->type != B43_PHYTYPE_G);
+		if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
+			b43_short_slot_timing_enable(dev);
+		else
+			b43_short_slot_timing_disable(dev);
+	}
+
+	/* Adjust the desired TX power level. */
+	if (conf->power_level != 0) {
+		if (conf->power_level != phy->power_level) {
+			phy->power_level = conf->power_level;
+			b43_phy_xmitpower(dev);
+		}
+	}
+
+	/* Antennas for RX and management frame TX. */
+	b43_mgmtframe_txantenna(dev, antenna_tx);
+	b43_set_rx_antenna(dev, antenna_rx);
+
+	/* Update templates for AP mode. */
+	if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP))
+		b43_set_beacon_int(dev, conf->beacon_int);
+
+	if (!!conf->radio_enabled != phy->radio_on) {
+		if (conf->radio_enabled) {
+			b43_radio_turn_on(dev);
+			b43info(dev->wl, "Radio turned on by software\n");
+			if (!dev->radio_hw_enable) {
+				b43info(dev->wl, "The hardware RF-kill button "
+					"still turns the radio physically off. "
+					"Press the button to turn it on.\n");
+			}
+		} else {
+			b43_radio_turn_off(dev, 0);
+			b43info(dev->wl, "Radio turned off by software\n");
+		}
+	}
+
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	b43_interrupt_enable(dev, savedirqs);
+	mmiowb();
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+      out_unlock_mutex:
+	mutex_unlock(&wl->mutex);
+
+	return err;
+}
+
+static int b43_dev_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+			   const u8 *local_addr, const u8 *addr,
+			   struct ieee80211_key_conf *key)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev = wl->current_dev;
+	unsigned long flags;
+	u8 algorithm;
+	u8 index;
+	int err = -EINVAL;
+	DECLARE_MAC_BUF(mac);
+
+	if (modparam_nohwcrypt)
+		return -ENOSPC; /* User disabled HW-crypto */
+
+	if (!dev)
+		return -ENODEV;
+	switch (key->alg) {
+	case ALG_WEP:
+		if (key->keylen == 5)
+			algorithm = B43_SEC_ALGO_WEP40;
+		else
+			algorithm = B43_SEC_ALGO_WEP104;
+		break;
+	case ALG_TKIP:
+		algorithm = B43_SEC_ALGO_TKIP;
+		break;
+	case ALG_CCMP:
+		algorithm = B43_SEC_ALGO_AES;
+		break;
+	default:
+		B43_WARN_ON(1);
+		goto out;
+	}
+
+	index = (u8) (key->keyidx);
+	if (index > 3)
+		goto out;
+
+	mutex_lock(&wl->mutex);
+	spin_lock_irqsave(&wl->irq_lock, flags);
+
+	if (b43_status(dev) < B43_STAT_INITIALIZED) {
+		err = -ENODEV;
+		goto out_unlock;
+	}
+
+	switch (cmd) {
+	case SET_KEY:
+		if (algorithm == B43_SEC_ALGO_TKIP) {
+			/* FIXME: No TKIP hardware encryption for now. */
+			err = -EOPNOTSUPP;
+			goto out_unlock;
+		}
+
+		if (is_broadcast_ether_addr(addr)) {
+			/* addr is FF:FF:FF:FF:FF:FF for default keys */
+			err = b43_key_write(dev, index, algorithm,
+					    key->key, key->keylen, NULL, key);
+		} else {
+			/*
+			 * either pairwise key or address is 00:00:00:00:00:00
+			 * for transmit-only keys
+			 */
+			err = b43_key_write(dev, -1, algorithm,
+					    key->key, key->keylen, addr, key);
+		}
+		if (err)
+			goto out_unlock;
+
+		if (algorithm == B43_SEC_ALGO_WEP40 ||
+		    algorithm == B43_SEC_ALGO_WEP104) {
+			b43_hf_write(dev, b43_hf_read(dev) | B43_HF_USEDEFKEYS);
+		} else {
+			b43_hf_write(dev,
+				     b43_hf_read(dev) & ~B43_HF_USEDEFKEYS);
+		}
+		key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+		break;
+	case DISABLE_KEY: {
+		err = b43_key_clear(dev, key->hw_key_idx);
+		if (err)
+			goto out_unlock;
+		break;
+	}
+	default:
+		B43_WARN_ON(1);
+	}
+out_unlock:
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+	mutex_unlock(&wl->mutex);
+out:
+	if (!err) {
+		b43dbg(wl, "%s hardware based encryption for keyidx: %d, "
+		       "mac: %s\n",
+		       cmd == SET_KEY ? "Using" : "Disabling", key->keyidx,
+		       print_mac(mac, addr));
+	}
+	return err;
+}
+
+static void b43_configure_filter(struct ieee80211_hw *hw,
+				 unsigned int changed, unsigned int *fflags,
+				 int mc_count, struct dev_addr_list *mc_list)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev = wl->current_dev;
+	unsigned long flags;
+
+	if (!dev) {
+		*fflags = 0;
+		return;
+	}
+
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	*fflags &= FIF_PROMISC_IN_BSS |
+		  FIF_ALLMULTI |
+		  FIF_FCSFAIL |
+		  FIF_PLCPFAIL |
+		  FIF_CONTROL |
+		  FIF_OTHER_BSS |
+		  FIF_BCN_PRBRESP_PROMISC;
+
+	changed &= FIF_PROMISC_IN_BSS |
+		   FIF_ALLMULTI |
+		   FIF_FCSFAIL |
+		   FIF_PLCPFAIL |
+		   FIF_CONTROL |
+		   FIF_OTHER_BSS |
+		   FIF_BCN_PRBRESP_PROMISC;
+
+	wl->filter_flags = *fflags;
+
+	if (changed && b43_status(dev) >= B43_STAT_INITIALIZED)
+		b43_adjust_opmode(dev);
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+}
+
+static int b43_config_interface(struct ieee80211_hw *hw,
+				int if_id, struct ieee80211_if_conf *conf)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev = wl->current_dev;
+	unsigned long flags;
+
+	if (!dev)
+		return -ENODEV;
+	mutex_lock(&wl->mutex);
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	B43_WARN_ON(wl->if_id != if_id);
+	if (conf->bssid)
+		memcpy(wl->bssid, conf->bssid, ETH_ALEN);
+	else
+		memset(wl->bssid, 0, ETH_ALEN);
+	if (b43_status(dev) >= B43_STAT_INITIALIZED) {
+		if (b43_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
+			B43_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
+			b43_set_ssid(dev, conf->ssid, conf->ssid_len);
+			if (conf->beacon)
+				b43_refresh_templates(dev, conf->beacon);
+		}
+		b43_write_mac_bssid_templates(dev);
+	}
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+	mutex_unlock(&wl->mutex);
+
+	return 0;
+}
+
+/* Locking: wl->mutex */
+static void b43_wireless_core_stop(struct b43_wldev *dev)
+{
+	struct b43_wl *wl = dev->wl;
+	unsigned long flags;
+
+	if (b43_status(dev) < B43_STAT_STARTED)
+		return;
+	b43_set_status(dev, B43_STAT_INITIALIZED);
+
+	mutex_unlock(&wl->mutex);
+	/* Must unlock as it would otherwise deadlock. No races here.
+	 * Cancel the possibly running self-rearming periodic work. */
+	cancel_delayed_work_sync(&dev->periodic_work);
+	mutex_lock(&wl->mutex);
+
+	ieee80211_stop_queues(wl->hw);	//FIXME this could cause a deadlock, as mac80211 seems buggy.
+
+	/* Disable and sync interrupts. */
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	dev->irq_savedstate = b43_interrupt_disable(dev, B43_IRQ_ALL);
+	b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);	/* flush */
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+	b43_synchronize_irq(dev);
+
+	b43_mac_suspend(dev);
+	free_irq(dev->dev->irq, dev);
+	b43dbg(wl, "Wireless interface stopped\n");
+}
+
+/* Locking: wl->mutex */
+static int b43_wireless_core_start(struct b43_wldev *dev)
+{
+	int err;
+
+	B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED);
+
+	drain_txstatus_queue(dev);
+	err = request_irq(dev->dev->irq, b43_interrupt_handler,
+			  IRQF_SHARED, KBUILD_MODNAME, dev);
+	if (err) {
+		b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq);
+		goto out;
+	}
+
+	/* We are ready to run. */
+	b43_set_status(dev, B43_STAT_STARTED);
+
+	/* Start data flow (TX/RX). */
+	b43_mac_enable(dev);
+	b43_interrupt_enable(dev, dev->irq_savedstate);
+	ieee80211_start_queues(dev->wl->hw);
+
+	/* Start maintainance work */
+	b43_periodic_tasks_setup(dev);
+
+	b43dbg(dev->wl, "Wireless interface started\n");
+      out:
+	return err;
+}
+
+/* Get PHY and RADIO versioning numbers */
+static int b43_phy_versioning(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u32 tmp;
+	u8 analog_type;
+	u8 phy_type;
+	u8 phy_rev;
+	u16 radio_manuf;
+	u16 radio_ver;
+	u16 radio_rev;
+	int unsupported = 0;
+
+	/* Get PHY versioning */
+	tmp = b43_read16(dev, B43_MMIO_PHY_VER);
+	analog_type = (tmp & B43_PHYVER_ANALOG) >> B43_PHYVER_ANALOG_SHIFT;
+	phy_type = (tmp & B43_PHYVER_TYPE) >> B43_PHYVER_TYPE_SHIFT;
+	phy_rev = (tmp & B43_PHYVER_VERSION);
+	switch (phy_type) {
+	case B43_PHYTYPE_A:
+		if (phy_rev >= 4)
+			unsupported = 1;
+		break;
+	case B43_PHYTYPE_B:
+		if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6
+		    && phy_rev != 7)
+			unsupported = 1;
+		break;
+	case B43_PHYTYPE_G:
+		if (phy_rev > 8)
+			unsupported = 1;
+		break;
+	default:
+		unsupported = 1;
+	};
+	if (unsupported) {
+		b43err(dev->wl, "FOUND UNSUPPORTED PHY "
+		       "(Analog %u, Type %u, Revision %u)\n",
+		       analog_type, phy_type, phy_rev);
+		return -EOPNOTSUPP;
+	}
+	b43dbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n",
+	       analog_type, phy_type, phy_rev);
+
+	/* Get RADIO versioning */
+	if (dev->dev->bus->chip_id == 0x4317) {
+		if (dev->dev->bus->chip_rev == 0)
+			tmp = 0x3205017F;
+		else if (dev->dev->bus->chip_rev == 1)
+			tmp = 0x4205017F;
+		else
+			tmp = 0x5205017F;
+	} else {
+		b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
+		tmp = b43_read16(dev, B43_MMIO_RADIO_DATA_HIGH);
+		tmp <<= 16;
+		b43_write16(dev, B43_MMIO_RADIO_CONTROL, B43_RADIOCTL_ID);
+		tmp |= b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+	}
+	radio_manuf = (tmp & 0x00000FFF);
+	radio_ver = (tmp & 0x0FFFF000) >> 12;
+	radio_rev = (tmp & 0xF0000000) >> 28;
+	switch (phy_type) {
+	case B43_PHYTYPE_A:
+		if (radio_ver != 0x2060)
+			unsupported = 1;
+		if (radio_rev != 1)
+			unsupported = 1;
+		if (radio_manuf != 0x17F)
+			unsupported = 1;
+		break;
+	case B43_PHYTYPE_B:
+		if ((radio_ver & 0xFFF0) != 0x2050)
+			unsupported = 1;
+		break;
+	case B43_PHYTYPE_G:
+		if (radio_ver != 0x2050)
+			unsupported = 1;
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+	if (unsupported) {
+		b43err(dev->wl, "FOUND UNSUPPORTED RADIO "
+		       "(Manuf 0x%X, Version 0x%X, Revision %u)\n",
+		       radio_manuf, radio_ver, radio_rev);
+		return -EOPNOTSUPP;
+	}
+	b43dbg(dev->wl, "Found Radio: Manuf 0x%X, Version 0x%X, Revision %u\n",
+	       radio_manuf, radio_ver, radio_rev);
+
+	phy->radio_manuf = radio_manuf;
+	phy->radio_ver = radio_ver;
+	phy->radio_rev = radio_rev;
+
+	phy->analog = analog_type;
+	phy->type = phy_type;
+	phy->rev = phy_rev;
+
+	return 0;
+}
+
+static void setup_struct_phy_for_init(struct b43_wldev *dev,
+				      struct b43_phy *phy)
+{
+	struct b43_txpower_lo_control *lo;
+	int i;
+
+	memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
+	memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
+
+	/* Flags */
+	phy->locked = 0;
+
+	phy->aci_enable = 0;
+	phy->aci_wlan_automatic = 0;
+	phy->aci_hw_rssi = 0;
+
+	phy->radio_off_context.valid = 0;
+
+	lo = phy->lo_control;
+	if (lo) {
+		memset(lo, 0, sizeof(*(phy->lo_control)));
+		lo->rebuild = 1;
+		lo->tx_bias = 0xFF;
+	}
+	phy->max_lb_gain = 0;
+	phy->trsw_rx_gain = 0;
+	phy->txpwr_offset = 0;
+
+	/* NRSSI */
+	phy->nrssislope = 0;
+	for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++)
+		phy->nrssi[i] = -1000;
+	for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++)
+		phy->nrssi_lt[i] = i;
+
+	phy->lofcal = 0xFFFF;
+	phy->initval = 0xFFFF;
+
+	spin_lock_init(&phy->lock);
+	phy->interfmode = B43_INTERFMODE_NONE;
+	phy->channel = 0xFF;
+
+	phy->hardware_power_control = !!modparam_hwpctl;
+}
+
+static void setup_struct_wldev_for_init(struct b43_wldev *dev)
+{
+	/* Flags */
+	dev->reg124_set_0x4 = 0;
+	/* Assume the radio is enabled. If it's not enabled, the state will
+	 * immediately get fixed on the first periodic work run. */
+	dev->radio_hw_enable = 1;
+
+	/* Stats */
+	memset(&dev->stats, 0, sizeof(dev->stats));
+
+	setup_struct_phy_for_init(dev, &dev->phy);
+
+	/* IRQ related flags */
+	dev->irq_reason = 0;
+	memset(dev->dma_reason, 0, sizeof(dev->dma_reason));
+	dev->irq_savedstate = B43_IRQ_MASKTEMPLATE;
+
+	dev->mac_suspended = 1;
+
+	/* Noise calculation context */
+	memset(&dev->noisecalc, 0, sizeof(dev->noisecalc));
+}
+
+static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
+{
+	struct ssb_sprom *sprom = &dev->dev->bus->sprom;
+	u32 hf;
+
+	if (!(sprom->r1.boardflags_lo & B43_BFL_BTCOEXIST))
+		return;
+	if (dev->phy.type != B43_PHYTYPE_B && !dev->phy.gmode)
+		return;
+
+	hf = b43_hf_read(dev);
+	if (sprom->r1.boardflags_lo & B43_BFL_BTCMOD)
+		hf |= B43_HF_BTCOEXALT;
+	else
+		hf |= B43_HF_BTCOEX;
+	b43_hf_write(dev, hf);
+	//TODO
+}
+
+static void b43_bluetooth_coext_disable(struct b43_wldev *dev)
+{				//TODO
+}
+
+static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
+{
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+	struct ssb_bus *bus = dev->dev->bus;
+	u32 tmp;
+
+	if (bus->pcicore.dev &&
+	    bus->pcicore.dev->id.coreid == SSB_DEV_PCI &&
+	    bus->pcicore.dev->id.revision <= 5) {
+		/* IMCFGLO timeouts workaround. */
+		tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
+		tmp &= ~SSB_IMCFGLO_REQTO;
+		tmp &= ~SSB_IMCFGLO_SERTO;
+		switch (bus->bustype) {
+		case SSB_BUSTYPE_PCI:
+		case SSB_BUSTYPE_PCMCIA:
+			tmp |= 0x32;
+			break;
+		case SSB_BUSTYPE_SSB:
+			tmp |= 0x53;
+			break;
+		}
+		ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
+	}
+#endif /* CONFIG_SSB_DRIVER_PCICORE */
+}
+
+/* Shutdown a wireless core */
+/* Locking: wl->mutex */
+static void b43_wireless_core_exit(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	B43_WARN_ON(b43_status(dev) > B43_STAT_INITIALIZED);
+	if (b43_status(dev) != B43_STAT_INITIALIZED)
+		return;
+	b43_set_status(dev, B43_STAT_UNINIT);
+
+	mutex_unlock(&dev->wl->mutex);
+	b43_rfkill_exit(dev);
+	mutex_lock(&dev->wl->mutex);
+
+	b43_rng_exit(dev->wl);
+	b43_pio_free(dev);
+	b43_dma_free(dev);
+	b43_chip_exit(dev);
+	b43_radio_turn_off(dev, 1);
+	b43_switch_analog(dev, 0);
+	if (phy->dyn_tssi_tbl)
+		kfree(phy->tssi2dbm);
+	kfree(phy->lo_control);
+	phy->lo_control = NULL;
+	ssb_device_disable(dev->dev, 0);
+	ssb_bus_may_powerdown(dev->dev->bus);
+}
+
+/* Initialize a wireless core */
+static int b43_wireless_core_init(struct b43_wldev *dev)
+{
+	struct b43_wl *wl = dev->wl;
+	struct ssb_bus *bus = dev->dev->bus;
+	struct ssb_sprom *sprom = &bus->sprom;
+	struct b43_phy *phy = &dev->phy;
+	int err;
+	u32 hf, tmp;
+
+	B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
+
+	err = ssb_bus_powerup(bus, 0);
+	if (err)
+		goto out;
+	if (!ssb_device_is_enabled(dev->dev)) {
+		tmp = phy->gmode ? B43_TMSLOW_GMODE : 0;
+		b43_wireless_core_reset(dev, tmp);
+	}
+
+	if ((phy->type == B43_PHYTYPE_B) || (phy->type == B43_PHYTYPE_G)) {
+		phy->lo_control =
+		    kzalloc(sizeof(*(phy->lo_control)), GFP_KERNEL);
+		if (!phy->lo_control) {
+			err = -ENOMEM;
+			goto err_busdown;
+		}
+	}
+	setup_struct_wldev_for_init(dev);
+
+	err = b43_phy_init_tssi2dbm_table(dev);
+	if (err)
+		goto err_kfree_lo_control;
+
+	/* Enable IRQ routing to this device. */
+	ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
+
+	b43_imcfglo_timeouts_workaround(dev);
+	b43_bluetooth_coext_disable(dev);
+	b43_phy_early_init(dev);
+	err = b43_chip_init(dev);
+	if (err)
+		goto err_kfree_tssitbl;
+	b43_shm_write16(dev, B43_SHM_SHARED,
+			B43_SHM_SH_WLCOREREV, dev->dev->id.revision);
+	hf = b43_hf_read(dev);
+	if (phy->type == B43_PHYTYPE_G) {
+		hf |= B43_HF_SYMW;
+		if (phy->rev == 1)
+			hf |= B43_HF_GDCW;
+		if (sprom->r1.boardflags_lo & B43_BFL_PACTRL)
+			hf |= B43_HF_OFDMPABOOST;
+	} else if (phy->type == B43_PHYTYPE_B) {
+		hf |= B43_HF_SYMW;
+		if (phy->rev >= 2 && phy->radio_ver == 0x2050)
+			hf &= ~B43_HF_GDCW;
+	}
+	b43_hf_write(dev, hf);
+
+	/* Short/Long Retry Limit.
+	 * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
+	 * the chip-internal counter.
+	 */
+	tmp = limit_value(modparam_short_retry, 0, 0xF);
+	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, tmp);
+	tmp = limit_value(modparam_long_retry, 0, 0xF);
+	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, tmp);
+
+	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_SFFBLIM, 3);
+	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_LFFBLIM, 2);
+
+	/* Disable sending probe responses from firmware.
+	 * Setting the MaxTime to one usec will always trigger
+	 * a timeout, so we never send any probe resp.
+	 * A timeout of zero is infinite. */
+	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_PRMAXTIME, 1);
+
+	b43_rate_memory_init(dev);
+
+	/* Minimum Contention Window */
+	if (phy->type == B43_PHYTYPE_B) {
+		b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0x1F);
+	} else {
+		b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MINCONT, 0xF);
+	}
+	/* Maximum Contention Window */
+	b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
+
+	do {
+		if (b43_using_pio(dev)) {
+			err = b43_pio_init(dev);
+		} else {
+			err = b43_dma_init(dev);
+			if (!err)
+				b43_qos_init(dev);
+		}
+	} while (err == -EAGAIN);
+	if (err)
+		goto err_chip_exit;
+
+//FIXME
+#if 1
+	b43_write16(dev, 0x0612, 0x0050);
+	b43_shm_write16(dev, B43_SHM_SHARED, 0x0416, 0x0050);
+	b43_shm_write16(dev, B43_SHM_SHARED, 0x0414, 0x01F4);
+#endif
+
+	b43_bluetooth_coext_enable(dev);
+
+	ssb_bus_powerup(bus, 1);	/* Enable dynamic PCTL */
+	memset(wl->bssid, 0, ETH_ALEN);
+	memset(wl->mac_addr, 0, ETH_ALEN);
+	b43_upload_card_macaddress(dev);
+	b43_security_init(dev);
+	b43_rfkill_init(dev);
+	b43_rng_init(wl);
+
+	b43_set_status(dev, B43_STAT_INITIALIZED);
+
+      out:
+	return err;
+
+      err_chip_exit:
+	b43_chip_exit(dev);
+      err_kfree_tssitbl:
+	if (phy->dyn_tssi_tbl)
+		kfree(phy->tssi2dbm);
+      err_kfree_lo_control:
+	kfree(phy->lo_control);
+	phy->lo_control = NULL;
+      err_busdown:
+	ssb_bus_may_powerdown(bus);
+	B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
+	return err;
+}
+
+static int b43_add_interface(struct ieee80211_hw *hw,
+			     struct ieee80211_if_init_conf *conf)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev;
+	unsigned long flags;
+	int err = -EOPNOTSUPP;
+
+	/* TODO: allow WDS/AP devices to coexist */
+
+	if (conf->type != IEEE80211_IF_TYPE_AP &&
+	    conf->type != IEEE80211_IF_TYPE_STA &&
+	    conf->type != IEEE80211_IF_TYPE_WDS &&
+	    conf->type != IEEE80211_IF_TYPE_IBSS)
+		return -EOPNOTSUPP;
+
+	mutex_lock(&wl->mutex);
+	if (wl->operating)
+		goto out_mutex_unlock;
+
+	b43dbg(wl, "Adding Interface type %d\n", conf->type);
+
+	dev = wl->current_dev;
+	wl->operating = 1;
+	wl->if_id = conf->if_id;
+	wl->if_type = conf->type;
+	memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	b43_adjust_opmode(dev);
+	b43_upload_card_macaddress(dev);
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+	err = 0;
+ out_mutex_unlock:
+	mutex_unlock(&wl->mutex);
+
+	return err;
+}
+
+static void b43_remove_interface(struct ieee80211_hw *hw,
+				 struct ieee80211_if_init_conf *conf)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev = wl->current_dev;
+	unsigned long flags;
+
+	b43dbg(wl, "Removing Interface type %d\n", conf->type);
+
+	mutex_lock(&wl->mutex);
+
+	B43_WARN_ON(!wl->operating);
+	B43_WARN_ON(wl->if_id != conf->if_id);
+
+	wl->operating = 0;
+
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	b43_adjust_opmode(dev);
+	memset(wl->mac_addr, 0, ETH_ALEN);
+	b43_upload_card_macaddress(dev);
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+	mutex_unlock(&wl->mutex);
+}
+
+static int b43_start(struct ieee80211_hw *hw)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev = wl->current_dev;
+	int did_init = 0;
+	int err;
+
+	mutex_lock(&wl->mutex);
+
+	if (b43_status(dev) < B43_STAT_INITIALIZED) {
+		err = b43_wireless_core_init(dev);
+		if (err)
+			goto out_mutex_unlock;
+		did_init = 1;
+	}
+
+	if (b43_status(dev) < B43_STAT_STARTED) {
+		err = b43_wireless_core_start(dev);
+		if (err) {
+			if (did_init)
+				b43_wireless_core_exit(dev);
+			goto out_mutex_unlock;
+		}
+	}
+
+ out_mutex_unlock:
+	mutex_unlock(&wl->mutex);
+
+	return err;
+}
+
+void b43_stop(struct ieee80211_hw *hw)
+{
+	struct b43_wl *wl = hw_to_b43_wl(hw);
+	struct b43_wldev *dev = wl->current_dev;
+
+	mutex_lock(&wl->mutex);
+	if (b43_status(dev) >= B43_STAT_STARTED)
+		b43_wireless_core_stop(dev);
+	b43_wireless_core_exit(dev);
+	mutex_unlock(&wl->mutex);
+}
+
+static const struct ieee80211_ops b43_hw_ops = {
+	.tx = b43_tx,
+	.conf_tx = b43_conf_tx,
+	.add_interface = b43_add_interface,
+	.remove_interface = b43_remove_interface,
+	.config = b43_dev_config,
+	.config_interface = b43_config_interface,
+	.configure_filter = b43_configure_filter,
+	.set_key = b43_dev_set_key,
+	.get_stats = b43_get_stats,
+	.get_tx_stats = b43_get_tx_stats,
+	.start = b43_start,
+	.stop = b43_stop,
+};
+
+/* Hard-reset the chip. Do not call this directly.
+ * Use b43_controller_restart()
+ */
+static void b43_chip_reset(struct work_struct *work)
+{
+	struct b43_wldev *dev =
+	    container_of(work, struct b43_wldev, restart_work);
+	struct b43_wl *wl = dev->wl;
+	int err = 0;
+	int prev_status;
+
+	mutex_lock(&wl->mutex);
+
+	prev_status = b43_status(dev);
+	/* Bring the device down... */
+	if (prev_status >= B43_STAT_STARTED)
+		b43_wireless_core_stop(dev);
+	if (prev_status >= B43_STAT_INITIALIZED)
+		b43_wireless_core_exit(dev);
+
+	/* ...and up again. */
+	if (prev_status >= B43_STAT_INITIALIZED) {
+		err = b43_wireless_core_init(dev);
+		if (err)
+			goto out;
+	}
+	if (prev_status >= B43_STAT_STARTED) {
+		err = b43_wireless_core_start(dev);
+		if (err) {
+			b43_wireless_core_exit(dev);
+			goto out;
+		}
+	}
+      out:
+	mutex_unlock(&wl->mutex);
+	if (err)
+		b43err(wl, "Controller restart FAILED\n");
+	else
+		b43info(wl, "Controller restarted\n");
+}
+
+static int b43_setup_modes(struct b43_wldev *dev,
+			   int have_aphy, int have_bphy, int have_gphy)
+{
+	struct ieee80211_hw *hw = dev->wl->hw;
+	struct ieee80211_hw_mode *mode;
+	struct b43_phy *phy = &dev->phy;
+	int cnt = 0;
+	int err;
+
+/*FIXME: Don't tell ieee80211 about an A-PHY, because we currently don't support A-PHY. */
+	have_aphy = 0;
+
+	phy->possible_phymodes = 0;
+	for (; 1; cnt++) {
+		if (have_aphy) {
+			B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
+			mode = &phy->hwmodes[cnt];
+
+			mode->mode = MODE_IEEE80211A;
+			mode->num_channels = b43_a_chantable_size;
+			mode->channels = b43_a_chantable;
+			mode->num_rates = b43_a_ratetable_size;
+			mode->rates = b43_a_ratetable;
+			err = ieee80211_register_hwmode(hw, mode);
+			if (err)
+				return err;
+
+			phy->possible_phymodes |= B43_PHYMODE_A;
+			have_aphy = 0;
+			continue;
+		}
+		if (have_bphy) {
+			B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
+			mode = &phy->hwmodes[cnt];
+
+			mode->mode = MODE_IEEE80211B;
+			mode->num_channels = b43_bg_chantable_size;
+			mode->channels = b43_bg_chantable;
+			mode->num_rates = b43_b_ratetable_size;
+			mode->rates = b43_b_ratetable;
+			err = ieee80211_register_hwmode(hw, mode);
+			if (err)
+				return err;
+
+			phy->possible_phymodes |= B43_PHYMODE_B;
+			have_bphy = 0;
+			continue;
+		}
+		if (have_gphy) {
+			B43_WARN_ON(cnt >= B43_MAX_PHYHWMODES);
+			mode = &phy->hwmodes[cnt];
+
+			mode->mode = MODE_IEEE80211G;
+			mode->num_channels = b43_bg_chantable_size;
+			mode->channels = b43_bg_chantable;
+			mode->num_rates = b43_g_ratetable_size;
+			mode->rates = b43_g_ratetable;
+			err = ieee80211_register_hwmode(hw, mode);
+			if (err)
+				return err;
+
+			phy->possible_phymodes |= B43_PHYMODE_G;
+			have_gphy = 0;
+			continue;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static void b43_wireless_core_detach(struct b43_wldev *dev)
+{
+	b43_rfkill_free(dev);
+	/* We release firmware that late to not be required to re-request
+	 * is all the time when we reinit the core. */
+	b43_release_firmware(dev);
+}
+
+static int b43_wireless_core_attach(struct b43_wldev *dev)
+{
+	struct b43_wl *wl = dev->wl;
+	struct ssb_bus *bus = dev->dev->bus;
+	struct pci_dev *pdev = bus->host_pci;
+	int err;
+	int have_aphy = 0, have_bphy = 0, have_gphy = 0;
+	u32 tmp;
+
+	/* Do NOT do any device initialization here.
+	 * Do it in wireless_core_init() instead.
+	 * This function is for gathering basic information about the HW, only.
+	 * Also some structs may be set up here. But most likely you want to have
+	 * that in core_init(), too.
+	 */
+
+	err = ssb_bus_powerup(bus, 0);
+	if (err) {
+		b43err(wl, "Bus powerup failed\n");
+		goto out;
+	}
+	/* Get the PHY type. */
+	if (dev->dev->id.revision >= 5) {
+		u32 tmshigh;
+
+		tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
+		have_aphy = !!(tmshigh & B43_TMSHIGH_APHY);
+		have_gphy = !!(tmshigh & B43_TMSHIGH_GPHY);
+		if (!have_aphy && !have_gphy)
+			have_bphy = 1;
+	} else if (dev->dev->id.revision == 4) {
+		have_gphy = 1;
+		have_aphy = 1;
+	} else
+		have_bphy = 1;
+
+	dev->phy.gmode = (have_gphy || have_bphy);
+	tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
+	b43_wireless_core_reset(dev, tmp);
+
+	err = b43_phy_versioning(dev);
+	if (err)
+		goto err_powerdown;
+	/* Check if this device supports multiband. */
+	if (!pdev ||
+	    (pdev->device != 0x4312 &&
+	     pdev->device != 0x4319 && pdev->device != 0x4324)) {
+		/* No multiband support. */
+		have_aphy = 0;
+		have_bphy = 0;
+		have_gphy = 0;
+		switch (dev->phy.type) {
+		case B43_PHYTYPE_A:
+			have_aphy = 1;
+			break;
+		case B43_PHYTYPE_B:
+			have_bphy = 1;
+			break;
+		case B43_PHYTYPE_G:
+			have_gphy = 1;
+			break;
+		default:
+			B43_WARN_ON(1);
+		}
+	}
+	dev->phy.gmode = (have_gphy || have_bphy);
+	tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
+	b43_wireless_core_reset(dev, tmp);
+
+	err = b43_validate_chipaccess(dev);
+	if (err)
+		goto err_powerdown;
+	err = b43_setup_modes(dev, have_aphy, have_bphy, have_gphy);
+	if (err)
+		goto err_powerdown;
+
+	/* Now set some default "current_dev" */
+	if (!wl->current_dev)
+		wl->current_dev = dev;
+	INIT_WORK(&dev->restart_work, b43_chip_reset);
+	b43_rfkill_alloc(dev);
+
+	b43_radio_turn_off(dev, 1);
+	b43_switch_analog(dev, 0);
+	ssb_device_disable(dev->dev, 0);
+	ssb_bus_may_powerdown(bus);
+
+out:
+	return err;
+
+err_powerdown:
+	ssb_bus_may_powerdown(bus);
+	return err;
+}
+
+static void b43_one_core_detach(struct ssb_device *dev)
+{
+	struct b43_wldev *wldev;
+	struct b43_wl *wl;
+
+	wldev = ssb_get_drvdata(dev);
+	wl = wldev->wl;
+	cancel_work_sync(&wldev->restart_work);
+	b43_debugfs_remove_device(wldev);
+	b43_wireless_core_detach(wldev);
+	list_del(&wldev->list);
+	wl->nr_devs--;
+	ssb_set_drvdata(dev, NULL);
+	kfree(wldev);
+}
+
+static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
+{
+	struct b43_wldev *wldev;
+	struct pci_dev *pdev;
+	int err = -ENOMEM;
+
+	if (!list_empty(&wl->devlist)) {
+		/* We are not the first core on this chip. */
+		pdev = dev->bus->host_pci;
+		/* Only special chips support more than one wireless
+		 * core, although some of the other chips have more than
+		 * one wireless core as well. Check for this and
+		 * bail out early.
+		 */
+		if (!pdev ||
+		    ((pdev->device != 0x4321) &&
+		     (pdev->device != 0x4313) && (pdev->device != 0x431A))) {
+			b43dbg(wl, "Ignoring unconnected 802.11 core\n");
+			return -ENODEV;
+		}
+	}
+
+	wldev = kzalloc(sizeof(*wldev), GFP_KERNEL);
+	if (!wldev)
+		goto out;
+
+	wldev->dev = dev;
+	wldev->wl = wl;
+	b43_set_status(wldev, B43_STAT_UNINIT);
+	wldev->bad_frames_preempt = modparam_bad_frames_preempt;
+	tasklet_init(&wldev->isr_tasklet,
+		     (void (*)(unsigned long))b43_interrupt_tasklet,
+		     (unsigned long)wldev);
+	if (modparam_pio)
+		wldev->__using_pio = 1;
+	INIT_LIST_HEAD(&wldev->list);
+
+	err = b43_wireless_core_attach(wldev);
+	if (err)
+		goto err_kfree_wldev;
+
+	list_add(&wldev->list, &wl->devlist);
+	wl->nr_devs++;
+	ssb_set_drvdata(dev, wldev);
+	b43_debugfs_add_device(wldev);
+
+      out:
+	return err;
+
+      err_kfree_wldev:
+	kfree(wldev);
+	return err;
+}
+
+static void b43_sprom_fixup(struct ssb_bus *bus)
+{
+	/* boardflags workarounds */
+	if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
+	    bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74)
+		bus->sprom.r1.boardflags_lo |= B43_BFL_BTCOEXIST;
+	if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
+	    bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40)
+		bus->sprom.r1.boardflags_lo |= B43_BFL_PACTRL;
+
+	/* Handle case when gain is not set in sprom */
+	if (bus->sprom.r1.antenna_gain_a == 0xFF)
+		bus->sprom.r1.antenna_gain_a = 2;
+	if (bus->sprom.r1.antenna_gain_bg == 0xFF)
+		bus->sprom.r1.antenna_gain_bg = 2;
+
+	/* Convert Antennagain values to Q5.2 */
+	bus->sprom.r1.antenna_gain_a <<= 2;
+	bus->sprom.r1.antenna_gain_bg <<= 2;
+}
+
+static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl)
+{
+	struct ieee80211_hw *hw = wl->hw;
+
+	ssb_set_devtypedata(dev, NULL);
+	ieee80211_free_hw(hw);
+}
+
+static int b43_wireless_init(struct ssb_device *dev)
+{
+	struct ssb_sprom *sprom = &dev->bus->sprom;
+	struct ieee80211_hw *hw;
+	struct b43_wl *wl;
+	int err = -ENOMEM;
+
+	b43_sprom_fixup(dev->bus);
+
+	hw = ieee80211_alloc_hw(sizeof(*wl), &b43_hw_ops);
+	if (!hw) {
+		b43err(NULL, "Could not allocate ieee80211 device\n");
+		goto out;
+	}
+
+	/* fill hw info */
+	hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+	hw->max_signal = 100;
+	hw->max_rssi = -110;
+	hw->max_noise = -110;
+	hw->queues = 1;		/* FIXME: hardware has more queues */
+	SET_IEEE80211_DEV(hw, dev->dev);
+	if (is_valid_ether_addr(sprom->r1.et1mac))
+		SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac);
+	else
+		SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac);
+
+	/* Get and initialize struct b43_wl */
+	wl = hw_to_b43_wl(hw);
+	memset(wl, 0, sizeof(*wl));
+	wl->hw = hw;
+	spin_lock_init(&wl->irq_lock);
+	spin_lock_init(&wl->leds_lock);
+	mutex_init(&wl->mutex);
+	INIT_LIST_HEAD(&wl->devlist);
+
+	ssb_set_devtypedata(dev, wl);
+	b43info(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);
+	err = 0;
+      out:
+	return err;
+}
+
+static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
+{
+	struct b43_wl *wl;
+	int err;
+	int first = 0;
+
+	wl = ssb_get_devtypedata(dev);
+	if (!wl) {
+		/* Probing the first core. Must setup common struct b43_wl */
+		first = 1;
+		err = b43_wireless_init(dev);
+		if (err)
+			goto out;
+		wl = ssb_get_devtypedata(dev);
+		B43_WARN_ON(!wl);
+	}
+	err = b43_one_core_attach(dev, wl);
+	if (err)
+		goto err_wireless_exit;
+
+	if (first) {
+		err = ieee80211_register_hw(wl->hw);
+		if (err)
+			goto err_one_core_detach;
+	}
+
+      out:
+	return err;
+
+      err_one_core_detach:
+	b43_one_core_detach(dev);
+      err_wireless_exit:
+	if (first)
+		b43_wireless_exit(dev, wl);
+	return err;
+}
+
+static void b43_remove(struct ssb_device *dev)
+{
+	struct b43_wl *wl = ssb_get_devtypedata(dev);
+	struct b43_wldev *wldev = ssb_get_drvdata(dev);
+
+	B43_WARN_ON(!wl);
+	if (wl->current_dev == wldev)
+		ieee80211_unregister_hw(wl->hw);
+
+	b43_one_core_detach(dev);
+
+	if (list_empty(&wl->devlist)) {
+		/* Last core on the chip unregistered.
+		 * We can destroy common struct b43_wl.
+		 */
+		b43_wireless_exit(dev, wl);
+	}
+}
+
+/* Perform a hardware reset. This can be called from any context. */
+void b43_controller_restart(struct b43_wldev *dev, const char *reason)
+{
+	/* Must avoid requeueing, if we are in shutdown. */
+	if (b43_status(dev) < B43_STAT_INITIALIZED)
+		return;
+	b43info(dev->wl, "Controller RESET (%s) ...\n", reason);
+	queue_work(dev->wl->hw->workqueue, &dev->restart_work);
+}
+
+#ifdef CONFIG_PM
+
+static int b43_suspend(struct ssb_device *dev, pm_message_t state)
+{
+	struct b43_wldev *wldev = ssb_get_drvdata(dev);
+	struct b43_wl *wl = wldev->wl;
+
+	b43dbg(wl, "Suspending...\n");
+
+	mutex_lock(&wl->mutex);
+	wldev->suspend_init_status = b43_status(wldev);
+	if (wldev->suspend_init_status >= B43_STAT_STARTED)
+		b43_wireless_core_stop(wldev);
+	if (wldev->suspend_init_status >= B43_STAT_INITIALIZED)
+		b43_wireless_core_exit(wldev);
+	mutex_unlock(&wl->mutex);
+
+	b43dbg(wl, "Device suspended.\n");
+
+	return 0;
+}
+
+static int b43_resume(struct ssb_device *dev)
+{
+	struct b43_wldev *wldev = ssb_get_drvdata(dev);
+	struct b43_wl *wl = wldev->wl;
+	int err = 0;
+
+	b43dbg(wl, "Resuming...\n");
+
+	mutex_lock(&wl->mutex);
+	if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) {
+		err = b43_wireless_core_init(wldev);
+		if (err) {
+			b43err(wl, "Resume failed at core init\n");
+			goto out;
+		}
+	}
+	if (wldev->suspend_init_status >= B43_STAT_STARTED) {
+		err = b43_wireless_core_start(wldev);
+		if (err) {
+			b43_wireless_core_exit(wldev);
+			b43err(wl, "Resume failed at core start\n");
+			goto out;
+		}
+	}
+	mutex_unlock(&wl->mutex);
+
+	b43dbg(wl, "Device resumed.\n");
+      out:
+	return err;
+}
+
+#else /* CONFIG_PM */
+# define b43_suspend	NULL
+# define b43_resume	NULL
+#endif /* CONFIG_PM */
+
+static struct ssb_driver b43_ssb_driver = {
+	.name		= KBUILD_MODNAME,
+	.id_table	= b43_ssb_tbl,
+	.probe		= b43_probe,
+	.remove		= b43_remove,
+	.suspend	= b43_suspend,
+	.resume		= b43_resume,
+};
+
+static int __init b43_init(void)
+{
+	int err;
+
+	b43_debugfs_init();
+	err = b43_pcmcia_init();
+	if (err)
+		goto err_dfs_exit;
+	err = ssb_driver_register(&b43_ssb_driver);
+	if (err)
+		goto err_pcmcia_exit;
+
+	return err;
+
+err_pcmcia_exit:
+	b43_pcmcia_exit();
+err_dfs_exit:
+	b43_debugfs_exit();
+	return err;
+}
+
+static void __exit b43_exit(void)
+{
+	ssb_driver_unregister(&b43_ssb_driver);
+	b43_pcmcia_exit();
+	b43_debugfs_exit();
+}
+
+module_init(b43_init)
+module_exit(b43_exit)
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h
new file mode 100644
index 0000000..284d17d
--- /dev/null
+++ b/drivers/net/wireless/b43/main.h
@@ -0,0 +1,125 @@
+/*
+
+  Broadcom B43 wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+                     Stefano Brivio <st3@riseup.net>
+                     Michael Buesch <mb@bu3sch.de>
+                     Danny van Dyk <kugelfang@gentoo.org>
+                     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 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 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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef B43_MAIN_H_
+#define B43_MAIN_H_
+
+#include "b43.h"
+
+#define P4D_BYT3S(magic, nr_bytes)	u8 __p4dding##magic[nr_bytes]
+#define P4D_BYTES(line, nr_bytes)	P4D_BYT3S(line, nr_bytes)
+/* Magic helper macro to pad structures. Ignore those above. It's magic. */
+#define PAD_BYTES(nr_bytes)		P4D_BYTES( __LINE__ , (nr_bytes))
+
+/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
+static inline u8 b43_freq_to_channel_a(int freq)
+{
+	return ((freq - 5000) / 5);
+}
+static inline u8 b43_freq_to_channel_bg(int freq)
+{
+	u8 channel;
+
+	if (freq == 2484)
+		channel = 14;
+	else
+		channel = (freq - 2407) / 5;
+
+	return channel;
+}
+static inline u8 b43_freq_to_channel(struct b43_wldev *dev, int freq)
+{
+	if (dev->phy.type == B43_PHYTYPE_A)
+		return b43_freq_to_channel_a(freq);
+	return b43_freq_to_channel_bg(freq);
+}
+
+/* Lightweight function to convert a channel number to a frequency (in Mhz). */
+static inline int b43_channel_to_freq_a(u8 channel)
+{
+	return (5000 + (5 * channel));
+}
+static inline int b43_channel_to_freq_bg(u8 channel)
+{
+	int freq;
+
+	if (channel == 14)
+		freq = 2484;
+	else
+		freq = 2407 + (5 * channel);
+
+	return freq;
+}
+static inline int b43_channel_to_freq(struct b43_wldev *dev, u8 channel)
+{
+	if (dev->phy.type == B43_PHYTYPE_A)
+		return b43_channel_to_freq_a(channel);
+	return b43_channel_to_freq_bg(channel);
+}
+
+static inline int b43_is_cck_rate(int rate)
+{
+	return (rate == B43_CCK_RATE_1MB ||
+		rate == B43_CCK_RATE_2MB ||
+		rate == B43_CCK_RATE_5MB || rate == B43_CCK_RATE_11MB);
+}
+
+static inline int b43_is_ofdm_rate(int rate)
+{
+	return !b43_is_cck_rate(rate);
+}
+
+void b43_tsf_read(struct b43_wldev *dev, u64 * tsf);
+void b43_tsf_write(struct b43_wldev *dev, u64 tsf);
+
+u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset);
+u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset);
+void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value);
+void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value);
+
+u32 b43_hf_read(struct b43_wldev *dev);
+void b43_hf_write(struct b43_wldev *dev, u32 value);
+
+void b43_dummy_transmission(struct b43_wldev *dev);
+
+void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags);
+
+void b43_mac_suspend(struct b43_wldev *dev);
+void b43_mac_enable(struct b43_wldev *dev);
+
+void b43_controller_restart(struct b43_wldev *dev, const char *reason);
+
+#define B43_PS_ENABLED	(1 << 0)	/* Force enable hardware power saving */
+#define B43_PS_DISABLED	(1 << 1)	/* Force disable hardware power saving */
+#define B43_PS_AWAKE	(1 << 2)	/* Force device awake */
+#define B43_PS_ASLEEP	(1 << 3)	/* Force device asleep */
+void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags);
+
+#endif /* B43_MAIN_H_ */
diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c
new file mode 100644
index 0000000..b242a9a
--- /dev/null
+++ b/drivers/net/wireless/b43/pcmcia.c
@@ -0,0 +1,160 @@
+/*
+
+  Broadcom B43 wireless driver
+
+  Copyright (c) 2007 Michael Buesch <mb@bu3sch.de>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "pcmcia.h"
+
+#include <linux/ssb/ssb.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+
+static /*const */ struct pcmcia_device_id b43_pcmcia_tbl[] = {
+	PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
+	PCMCIA_DEVICE_NULL,
+};
+
+MODULE_DEVICE_TABLE(pcmcia, b43_pcmcia_tbl);
+
+#ifdef CONFIG_PM
+static int b43_pcmcia_suspend(struct pcmcia_device *dev)
+{
+	//TODO
+	return 0;
+}
+
+static int b43_pcmcia_resume(struct pcmcia_device *dev)
+{
+	//TODO
+	return 0;
+}
+#else /* CONFIG_PM */
+# define b43_pcmcia_suspend		NULL
+# define b43_pcmcia_resume		NULL
+#endif /* CONFIG_PM */
+
+static int __devinit b43_pcmcia_probe(struct pcmcia_device *dev)
+{
+	struct ssb_bus *ssb;
+	win_req_t win;
+	memreq_t mem;
+	tuple_t tuple;
+	cisparse_t parse;
+	int err = -ENOMEM;
+	int res;
+	unsigned char buf[64];
+
+	ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
+	if (!ssb)
+		goto out;
+
+	err = -ENODEV;
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	tuple.Attributes = 0;
+	tuple.TupleData = buf;
+	tuple.TupleDataMax = sizeof(buf);
+	tuple.TupleOffset = 0;
+
+	res = pcmcia_get_first_tuple(dev, &tuple);
+	if (res != CS_SUCCESS)
+		goto err_kfree_ssb;
+	res = pcmcia_get_tuple_data(dev, &tuple);
+	if (res != CS_SUCCESS)
+		goto err_kfree_ssb;
+	res = pcmcia_parse_tuple(dev, &tuple, &parse);
+	if (res != CS_SUCCESS)
+		goto err_kfree_ssb;
+
+	dev->conf.ConfigBase = parse.config.base;
+	dev->conf.Present = parse.config.rmask[0];
+
+	dev->io.BasePort2 = 0;
+	dev->io.NumPorts2 = 0;
+	dev->io.Attributes2 = 0;
+
+	win.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
+	win.Base = 0;
+	win.Size = SSB_CORE_SIZE;
+	win.AccessSpeed = 1000;
+	res = pcmcia_request_window(&dev, &win, &dev->win);
+	if (res != CS_SUCCESS)
+		goto err_kfree_ssb;
+
+	mem.CardOffset = 0;
+	mem.Page = 0;
+	res = pcmcia_map_mem_page(dev->win, &mem);
+	if (res != CS_SUCCESS)
+		goto err_kfree_ssb;
+
+	res = pcmcia_request_configuration(dev, &dev->conf);
+	if (res != CS_SUCCESS)
+		goto err_disable;
+
+	err = ssb_bus_pcmciabus_register(ssb, dev, win.Base);
+	dev->priv = ssb;
+
+      out:
+	return err;
+      err_disable:
+	pcmcia_disable_device(dev);
+      err_kfree_ssb:
+	kfree(ssb);
+	return err;
+}
+
+static void __devexit b43_pcmcia_remove(struct pcmcia_device *dev)
+{
+	struct ssb_bus *ssb = dev->priv;
+
+	ssb_bus_unregister(ssb);
+	pcmcia_release_window(dev->win);
+	pcmcia_disable_device(dev);
+	kfree(ssb);
+	dev->priv = NULL;
+}
+
+static struct pcmcia_driver b43_pcmcia_driver = {
+	.owner = THIS_MODULE,
+	.drv = {
+		.name = "b43-pcmcia",
+		},
+	.id_table = b43_pcmcia_tbl,
+	.probe = b43_pcmcia_probe,
+	.remove = b43_pcmcia_remove,
+	.suspend = b43_pcmcia_suspend,
+	.resume = b43_pcmcia_resume,
+};
+
+int b43_pcmcia_init(void)
+{
+	return pcmcia_register_driver(&b43_pcmcia_driver);
+}
+
+void b43_pcmcia_exit(void)
+{
+	pcmcia_unregister_driver(&b43_pcmcia_driver);
+}
diff --git a/drivers/net/wireless/b43/pcmcia.h b/drivers/net/wireless/b43/pcmcia.h
new file mode 100644
index 0000000..85f120a
--- /dev/null
+++ b/drivers/net/wireless/b43/pcmcia.h
@@ -0,0 +1,20 @@
+#ifndef B43_PCMCIA_H_
+#define B43_PCMCIA_H_
+
+#ifdef CONFIG_B43_PCMCIA
+
+int b43_pcmcia_init(void);
+void b43_pcmcia_exit(void);
+
+#else /* CONFIG_B43_PCMCIA */
+
+static inline int b43_pcmcia_init(void)
+{
+	return 0;
+}
+static inline void b43_pcmcia_exit(void)
+{
+}
+
+#endif /* CONFIG_B43_PCMCIA */
+#endif /* B43_PCMCIA_H_ */
diff --git a/drivers/net/wireless/b43/phy.c b/drivers/net/wireless/b43/phy.c
new file mode 100644
index 0000000..5f7ffa0
--- /dev/null
+++ b/drivers/net/wireless/b43/phy.c
@@ -0,0 +1,4380 @@
+/*
+
+  Broadcom B43 wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+  Copyright (c) 2005, 2006 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+  Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
+  Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+#include <linux/types.h>
+
+#include "b43.h"
+#include "phy.h"
+#include "main.h"
+#include "tables.h"
+#include "lo.h"
+
+static const s8 b43_tssi2dbm_b_table[] = {
+	0x4D, 0x4C, 0x4B, 0x4A,
+	0x4A, 0x49, 0x48, 0x47,
+	0x47, 0x46, 0x45, 0x45,
+	0x44, 0x43, 0x42, 0x42,
+	0x41, 0x40, 0x3F, 0x3E,
+	0x3D, 0x3C, 0x3B, 0x3A,
+	0x39, 0x38, 0x37, 0x36,
+	0x35, 0x34, 0x32, 0x31,
+	0x30, 0x2F, 0x2D, 0x2C,
+	0x2B, 0x29, 0x28, 0x26,
+	0x25, 0x23, 0x21, 0x1F,
+	0x1D, 0x1A, 0x17, 0x14,
+	0x10, 0x0C, 0x06, 0x00,
+	-7, -7, -7, -7,
+	-7, -7, -7, -7,
+	-7, -7, -7, -7,
+};
+
+static const s8 b43_tssi2dbm_g_table[] = {
+	77, 77, 77, 76,
+	76, 76, 75, 75,
+	74, 74, 73, 73,
+	73, 72, 72, 71,
+	71, 70, 70, 69,
+	68, 68, 67, 67,
+	66, 65, 65, 64,
+	63, 63, 62, 61,
+	60, 59, 58, 57,
+	56, 55, 54, 53,
+	52, 50, 49, 47,
+	45, 43, 40, 37,
+	33, 28, 22, 14,
+	5, -7, -20, -20,
+	-20, -20, -20, -20,
+	-20, -20, -20, -20,
+};
+
+const u8 b43_radio_channel_codes_bg[] = {
+	12, 17, 22, 27,
+	32, 37, 42, 47,
+	52, 57, 62, 67,
+	72, 84,
+};
+
+static void b43_phy_initg(struct b43_wldev *dev);
+
+/* Reverse the bits of a 4bit value.
+ * Example:  1101 is flipped 1011
+ */
+static u16 flip_4bit(u16 value)
+{
+	u16 flipped = 0x0000;
+
+	B43_WARN_ON(value & ~0x000F);
+
+	flipped |= (value & 0x0001) << 3;
+	flipped |= (value & 0x0002) << 1;
+	flipped |= (value & 0x0004) >> 1;
+	flipped |= (value & 0x0008) >> 3;
+
+	return flipped;
+}
+
+static void generate_rfatt_list(struct b43_wldev *dev,
+				struct b43_rfatt_list *list)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	/* APHY.rev < 5 || GPHY.rev < 6 */
+	static const struct b43_rfatt rfatt_0[] = {
+		{.att = 3,.with_padmix = 0,},
+		{.att = 1,.with_padmix = 0,},
+		{.att = 5,.with_padmix = 0,},
+		{.att = 7,.with_padmix = 0,},
+		{.att = 9,.with_padmix = 0,},
+		{.att = 2,.with_padmix = 0,},
+		{.att = 0,.with_padmix = 0,},
+		{.att = 4,.with_padmix = 0,},
+		{.att = 6,.with_padmix = 0,},
+		{.att = 8,.with_padmix = 0,},
+		{.att = 1,.with_padmix = 1,},
+		{.att = 2,.with_padmix = 1,},
+		{.att = 3,.with_padmix = 1,},
+		{.att = 4,.with_padmix = 1,},
+	};
+	/* Radio.rev == 8 && Radio.version == 0x2050 */
+	static const struct b43_rfatt rfatt_1[] = {
+		{.att = 2,.with_padmix = 1,},
+		{.att = 4,.with_padmix = 1,},
+		{.att = 6,.with_padmix = 1,},
+		{.att = 8,.with_padmix = 1,},
+		{.att = 10,.with_padmix = 1,},
+		{.att = 12,.with_padmix = 1,},
+		{.att = 14,.with_padmix = 1,},
+	};
+	/* Otherwise */
+	static const struct b43_rfatt rfatt_2[] = {
+		{.att = 0,.with_padmix = 1,},
+		{.att = 2,.with_padmix = 1,},
+		{.att = 4,.with_padmix = 1,},
+		{.att = 6,.with_padmix = 1,},
+		{.att = 8,.with_padmix = 1,},
+		{.att = 9,.with_padmix = 1,},
+		{.att = 9,.with_padmix = 1,},
+	};
+
+	if ((phy->type == B43_PHYTYPE_A && phy->rev < 5) ||
+	    (phy->type == B43_PHYTYPE_G && phy->rev < 6)) {
+		/* Software pctl */
+		list->list = rfatt_0;
+		list->len = ARRAY_SIZE(rfatt_0);
+		list->min_val = 0;
+		list->max_val = 9;
+		return;
+	}
+	if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
+		/* Hardware pctl */
+		list->list = rfatt_1;
+		list->len = ARRAY_SIZE(rfatt_1);
+		list->min_val = 2;
+		list->max_val = 14;
+		return;
+	}
+	/* Hardware pctl */
+	list->list = rfatt_2;
+	list->len = ARRAY_SIZE(rfatt_2);
+	list->min_val = 0;
+	list->max_val = 9;
+}
+
+static void generate_bbatt_list(struct b43_wldev *dev,
+				struct b43_bbatt_list *list)
+{
+	static const struct b43_bbatt bbatt_0[] = {
+		{.att = 0,},
+		{.att = 1,},
+		{.att = 2,},
+		{.att = 3,},
+		{.att = 4,},
+		{.att = 5,},
+		{.att = 6,},
+		{.att = 7,},
+		{.att = 8,},
+	};
+
+	list->list = bbatt_0;
+	list->len = ARRAY_SIZE(bbatt_0);
+	list->min_val = 0;
+	list->max_val = 8;
+}
+
+bool b43_has_hardware_pctl(struct b43_phy *phy)
+{
+	if (!phy->hardware_power_control)
+		return 0;
+	switch (phy->type) {
+	case B43_PHYTYPE_A:
+		if (phy->rev >= 5)
+			return 1;
+		break;
+	case B43_PHYTYPE_G:
+		if (phy->rev >= 6)
+			return 1;
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+	return 0;
+}
+
+static void b43_shm_clear_tssi(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	switch (phy->type) {
+	case B43_PHYTYPE_A:
+		b43_shm_write16(dev, B43_SHM_SHARED, 0x0068, 0x7F7F);
+		b43_shm_write16(dev, B43_SHM_SHARED, 0x006a, 0x7F7F);
+		break;
+	case B43_PHYTYPE_B:
+	case B43_PHYTYPE_G:
+		b43_shm_write16(dev, B43_SHM_SHARED, 0x0058, 0x7F7F);
+		b43_shm_write16(dev, B43_SHM_SHARED, 0x005a, 0x7F7F);
+		b43_shm_write16(dev, B43_SHM_SHARED, 0x0070, 0x7F7F);
+		b43_shm_write16(dev, B43_SHM_SHARED, 0x0072, 0x7F7F);
+		break;
+	}
+}
+
+void b43_raw_phy_lock(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	B43_WARN_ON(!irqs_disabled());
+
+	/* We had a check for MACCTL==0 here, but I think that doesn't
+	 * make sense, as MACCTL is never 0 when this is called.
+	 *      --mb */
+	B43_WARN_ON(b43_read32(dev, B43_MMIO_MACCTL) == 0);
+
+	if (dev->dev->id.revision < 3) {
+		b43_mac_suspend(dev);
+		spin_lock(&phy->lock);
+	} else {
+		if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+			b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
+	}
+	phy->locked = 1;
+}
+
+void b43_raw_phy_unlock(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	B43_WARN_ON(!irqs_disabled());
+	if (dev->dev->id.revision < 3) {
+		if (phy->locked) {
+			spin_unlock(&phy->lock);
+			b43_mac_enable(dev);
+		}
+	} else {
+		if (!b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+			b43_power_saving_ctl_bits(dev, 0);
+	}
+	phy->locked = 0;
+}
+
+/* Different PHYs require different register routing flags.
+ * This adjusts (and does sanity checks on) the routing flags.
+ */
+static inline u16 adjust_phyreg_for_phytype(struct b43_phy *phy,
+					    u16 offset, struct b43_wldev *dev)
+{
+	if (phy->type == B43_PHYTYPE_A) {
+		/* OFDM registers are base-registers for the A-PHY. */
+		offset &= ~B43_PHYROUTE_OFDM_GPHY;
+	}
+	if (offset & B43_PHYROUTE_EXT_GPHY) {
+		/* Ext-G registers are only available on G-PHYs */
+		if (phy->type != B43_PHYTYPE_G) {
+			b43dbg(dev->wl, "EXT-G PHY access at "
+			       "0x%04X on %u type PHY\n", offset, phy->type);
+		}
+	}
+
+	return offset;
+}
+
+u16 b43_phy_read(struct b43_wldev * dev, u16 offset)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	offset = adjust_phyreg_for_phytype(phy, offset, dev);
+	b43_write16(dev, B43_MMIO_PHY_CONTROL, offset);
+	return b43_read16(dev, B43_MMIO_PHY_DATA);
+}
+
+void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	offset = adjust_phyreg_for_phytype(phy, offset, dev);
+	b43_write16(dev, B43_MMIO_PHY_CONTROL, offset);
+	mmiowb();
+	b43_write16(dev, B43_MMIO_PHY_DATA, val);
+}
+
+static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower);
+
+/* Adjust the transmission power output (G-PHY) */
+void b43_set_txpower_g(struct b43_wldev *dev,
+		       const struct b43_bbatt *bbatt,
+		       const struct b43_rfatt *rfatt, u8 tx_control)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_txpower_lo_control *lo = phy->lo_control;
+	u16 bb, rf;
+	u16 tx_bias, tx_magn;
+
+	bb = bbatt->att;
+	rf = rfatt->att;
+	tx_bias = lo->tx_bias;
+	tx_magn = lo->tx_magn;
+	if (unlikely(tx_bias == 0xFF))
+		tx_bias = 0;
+
+	/* Save the values for later */
+	phy->tx_control = tx_control;
+	memcpy(&phy->rfatt, rfatt, sizeof(*rfatt));
+	memcpy(&phy->bbatt, bbatt, sizeof(*bbatt));
+
+	if (b43_debug(dev, B43_DBG_XMITPOWER)) {
+		b43dbg(dev->wl, "Tuning TX-power to bbatt(%u), "
+		       "rfatt(%u), tx_control(0x%02X), "
+		       "tx_bias(0x%02X), tx_magn(0x%02X)\n",
+		       bb, rf, tx_control, tx_bias, tx_magn);
+	}
+
+	b43_phy_set_baseband_attenuation(dev, bb);
+	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_RFATT, rf);
+	if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
+		b43_radio_write16(dev, 0x43,
+				  (rf & 0x000F) | (tx_control & 0x0070));
+	} else {
+		b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+					      & 0xFFF0) | (rf & 0x000F));
+		b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
+					      & ~0x0070) | (tx_control &
+							    0x0070));
+	}
+	if (has_tx_magnification(phy)) {
+		b43_radio_write16(dev, 0x52, tx_magn | tx_bias);
+	} else {
+		b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
+					      & 0xFFF0) | (tx_bias & 0x000F));
+	}
+	if (phy->type == B43_PHYTYPE_G)
+		b43_lo_g_adjust(dev);
+}
+
+static void default_baseband_attenuation(struct b43_wldev *dev,
+					 struct b43_bbatt *bb)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
+		bb->att = 0;
+	else
+		bb->att = 2;
+}
+
+static void default_radio_attenuation(struct b43_wldev *dev,
+				      struct b43_rfatt *rf)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+	struct b43_phy *phy = &dev->phy;
+
+	rf->with_padmix = 0;
+
+	if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
+	    bus->boardinfo.type == SSB_BOARD_BCM4309G) {
+		if (bus->boardinfo.rev < 0x43) {
+			rf->att = 2;
+			return;
+		} else if (bus->boardinfo.rev < 0x51) {
+			rf->att = 3;
+			return;
+		}
+	}
+
+	if (phy->type == B43_PHYTYPE_A) {
+		rf->att = 0x60;
+		return;
+	}
+
+	switch (phy->radio_ver) {
+	case 0x2053:
+		switch (phy->radio_rev) {
+		case 1:
+			rf->att = 6;
+			return;
+		}
+		break;
+	case 0x2050:
+		switch (phy->radio_rev) {
+		case 0:
+			rf->att = 5;
+			return;
+		case 1:
+			if (phy->type == B43_PHYTYPE_G) {
+				if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
+				    && bus->boardinfo.type == SSB_BOARD_BCM4309G
+				    && bus->boardinfo.rev >= 30)
+					rf->att = 3;
+				else if (bus->boardinfo.vendor ==
+					 SSB_BOARDVENDOR_BCM
+					 && bus->boardinfo.type ==
+					 SSB_BOARD_BU4306)
+					rf->att = 3;
+				else
+					rf->att = 1;
+			} else {
+				if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
+				    && bus->boardinfo.type == SSB_BOARD_BCM4309G
+				    && bus->boardinfo.rev >= 30)
+					rf->att = 7;
+				else
+					rf->att = 6;
+			}
+			return;
+		case 2:
+			if (phy->type == B43_PHYTYPE_G) {
+				if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
+				    && bus->boardinfo.type == SSB_BOARD_BCM4309G
+				    && bus->boardinfo.rev >= 30)
+					rf->att = 3;
+				else if (bus->boardinfo.vendor ==
+					 SSB_BOARDVENDOR_BCM
+					 && bus->boardinfo.type ==
+					 SSB_BOARD_BU4306)
+					rf->att = 5;
+				else if (bus->chip_id == 0x4320)
+					rf->att = 4;
+				else
+					rf->att = 3;
+			} else
+				rf->att = 6;
+			return;
+		case 3:
+			rf->att = 5;
+			return;
+		case 4:
+		case 5:
+			rf->att = 1;
+			return;
+		case 6:
+		case 7:
+			rf->att = 5;
+			return;
+		case 8:
+			rf->att = 0xA;
+			rf->with_padmix = 1;
+			return;
+		case 9:
+		default:
+			rf->att = 5;
+			return;
+		}
+	}
+	rf->att = 5;
+}
+
+static u16 default_tx_control(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (phy->radio_ver != 0x2050)
+		return 0;
+	if (phy->radio_rev == 1)
+		return B43_TXCTL_PA2DB | B43_TXCTL_TXMIX;
+	if (phy->radio_rev < 6)
+		return B43_TXCTL_PA2DB;
+	if (phy->radio_rev == 8)
+		return B43_TXCTL_TXMIX;
+	return 0;
+}
+
+/* This func is called "PHY calibrate" in the specs... */
+void b43_phy_early_init(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_txpower_lo_control *lo = phy->lo_control;
+
+	default_baseband_attenuation(dev, &phy->bbatt);
+	default_radio_attenuation(dev, &phy->rfatt);
+	phy->tx_control = (default_tx_control(dev) << 4);
+
+	/* Commit previous writes */
+	b43_read32(dev, B43_MMIO_MACCTL);
+
+	if (phy->type == B43_PHYTYPE_B || phy->type == B43_PHYTYPE_G) {
+		generate_rfatt_list(dev, &lo->rfatt_list);
+		generate_bbatt_list(dev, &lo->bbatt_list);
+	}
+	if (phy->type == B43_PHYTYPE_G && phy->rev == 1) {
+		/* Workaround: Temporarly disable gmode through the early init
+		 * phase, as the gmode stuff is not needed for phy rev 1 */
+		phy->gmode = 0;
+		b43_wireless_core_reset(dev, 0);
+		b43_phy_initg(dev);
+		phy->gmode = 1;
+		b43_wireless_core_reset(dev, B43_TMSLOW_GMODE);
+	}
+}
+
+/* GPHY_TSSI_Power_Lookup_Table_Init */
+static void b43_gphy_tssi_power_lt_init(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	int i;
+	u16 value;
+
+	for (i = 0; i < 32; i++)
+		b43_ofdmtab_write16(dev, 0x3C20, i, phy->tssi2dbm[i]);
+	for (i = 32; i < 64; i++)
+		b43_ofdmtab_write16(dev, 0x3C00, i - 32, phy->tssi2dbm[i]);
+	for (i = 0; i < 64; i += 2) {
+		value = (u16) phy->tssi2dbm[i];
+		value |= ((u16) phy->tssi2dbm[i + 1]) << 8;
+		b43_phy_write(dev, 0x380 + (i / 2), value);
+	}
+}
+
+/* GPHY_Gain_Lookup_Table_Init */
+static void b43_gphy_gain_lt_init(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_txpower_lo_control *lo = phy->lo_control;
+	u16 nr_written = 0;
+	u16 tmp;
+	u8 rf, bb;
+
+	if (!lo->lo_measured) {
+		b43_phy_write(dev, 0x3FF, 0);
+		return;
+	}
+
+	for (rf = 0; rf < lo->rfatt_list.len; rf++) {
+		for (bb = 0; bb < lo->bbatt_list.len; bb++) {
+			if (nr_written >= 0x40)
+				return;
+			tmp = lo->bbatt_list.list[bb].att;
+			tmp <<= 8;
+			if (phy->radio_rev == 8)
+				tmp |= 0x50;
+			else
+				tmp |= 0x40;
+			tmp |= lo->rfatt_list.list[rf].att;
+			b43_phy_write(dev, 0x3C0 + nr_written, tmp);
+			nr_written++;
+		}
+	}
+}
+
+/* GPHY_DC_Lookup_Table */
+void b43_gphy_dc_lt_init(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct b43_txpower_lo_control *lo = phy->lo_control;
+	struct b43_loctl *loctl0;
+	struct b43_loctl *loctl1;
+	int i;
+	int rf_offset, bb_offset;
+	u16 tmp;
+
+	for (i = 0; i < lo->rfatt_list.len + lo->bbatt_list.len; i += 2) {
+		rf_offset = i / lo->rfatt_list.len;
+		bb_offset = i % lo->rfatt_list.len;
+
+		loctl0 = b43_get_lo_g_ctl(dev, &lo->rfatt_list.list[rf_offset],
+					  &lo->bbatt_list.list[bb_offset]);
+		if (i + 1 < lo->rfatt_list.len * lo->bbatt_list.len) {
+			rf_offset = (i + 1) / lo->rfatt_list.len;
+			bb_offset = (i + 1) % lo->rfatt_list.len;
+
+			loctl1 =
+			    b43_get_lo_g_ctl(dev,
+					     &lo->rfatt_list.list[rf_offset],
+					     &lo->bbatt_list.list[bb_offset]);
+		} else
+			loctl1 = loctl0;
+
+		tmp = ((u16) loctl0->q & 0xF);
+		tmp |= ((u16) loctl0->i & 0xF) << 4;
+		tmp |= ((u16) loctl1->q & 0xF) << 8;
+		tmp |= ((u16) loctl1->i & 0xF) << 12;	//FIXME?
+		b43_phy_write(dev, 0x3A0 + (i / 2), tmp);
+	}
+}
+
+static void hardware_pctl_init_aphy(struct b43_wldev *dev)
+{
+	//TODO
+}
+
+static void hardware_pctl_init_gphy(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	b43_phy_write(dev, 0x0036, (b43_phy_read(dev, 0x0036) & 0xFFC0)
+		      | (phy->tgt_idle_tssi - phy->cur_idle_tssi));
+	b43_phy_write(dev, 0x0478, (b43_phy_read(dev, 0x0478) & 0xFF00)
+		      | (phy->tgt_idle_tssi - phy->cur_idle_tssi));
+	b43_gphy_tssi_power_lt_init(dev);
+	b43_gphy_gain_lt_init(dev);
+	b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) & 0xFFBF);
+	b43_phy_write(dev, 0x0014, 0x0000);
+
+	B43_WARN_ON(phy->rev < 6);
+	b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478)
+		      | 0x0800);
+	b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478)
+		      & 0xFEFF);
+	b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801)
+		      & 0xFFBF);
+
+	b43_gphy_dc_lt_init(dev);
+}
+
+/* HardwarePowerControl init for A and G PHY */
+static void b43_hardware_pctl_init(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (!b43_has_hardware_pctl(phy)) {
+		/* No hardware power control */
+		b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_HWPCTL);
+		return;
+	}
+	/* Init the hwpctl related hardware */
+	switch (phy->type) {
+	case B43_PHYTYPE_A:
+		hardware_pctl_init_aphy(dev);
+		break;
+	case B43_PHYTYPE_G:
+		hardware_pctl_init_gphy(dev);
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+	/* Enable hardware pctl in firmware. */
+	b43_hf_write(dev, b43_hf_read(dev) | B43_HF_HWPCTL);
+}
+
+static void b43_hardware_pctl_early_init(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (!b43_has_hardware_pctl(phy)) {
+		b43_phy_write(dev, 0x047A, 0xC111);
+		return;
+	}
+
+	b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) & 0xFEFF);
+	b43_phy_write(dev, 0x002F, 0x0202);
+	b43_phy_write(dev, 0x047C, b43_phy_read(dev, 0x047C) | 0x0002);
+	b43_phy_write(dev, 0x047A, b43_phy_read(dev, 0x047A) | 0xF000);
+	if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
+		b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A)
+					    & 0xFF0F) | 0x0010);
+		b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D)
+			      | 0x8000);
+		b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E)
+					    & 0xFFC0) | 0x0010);
+		b43_phy_write(dev, 0x002E, 0xC07F);
+		b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
+			      | 0x0400);
+	} else {
+		b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
+			      | 0x0200);
+		b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
+			      | 0x0400);
+		b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D)
+			      & 0x7FFF);
+		b43_phy_write(dev, 0x004F, b43_phy_read(dev, 0x004F)
+			      & 0xFFFE);
+		b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E)
+					    & 0xFFC0) | 0x0010);
+		b43_phy_write(dev, 0x002E, 0xC07F);
+		b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A)
+					    & 0xFF0F) | 0x0010);
+	}
+}
+
+/* Intialize B/G PHY power control
+ * as described in http://bcm-specs.sipsolutions.net/InitPowerControl
+ */
+static void b43_phy_init_pctl(struct b43_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+	struct b43_phy *phy = &dev->phy;
+	struct b43_rfatt old_rfatt;
+	struct b43_bbatt old_bbatt;
+	u8 old_tx_control = 0;
+
+	if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+	    (bus->boardinfo.type == SSB_BOARD_BU4306))
+		return;
+
+	b43_phy_write(dev, 0x0028, 0x8018);
+
+	/* This does something with the Analog... */
+	b43_write16(dev, B43_MMIO_PHY0, b43_read16(dev, B43_MMIO_PHY0)
+		    & 0xFFDF);
+
+	if (phy->type == B43_PHYTYPE_G && !phy->gmode)
+		return;
+	b43_hardware_pctl_early_init(dev);
+	if (phy->cur_idle_tssi == 0) {
+		if (phy->radio_ver == 0x2050 && phy->analog == 0) {
+			b43_radio_write16(dev, 0x0076,
+					  (b43_radio_read16(dev, 0x0076)
+					   & 0x00F7) | 0x0084);
+		} else {
+			struct b43_rfatt rfatt;
+			struct b43_bbatt bbatt;
+
+			memcpy(&old_rfatt, &phy->rfatt, sizeof(old_rfatt));
+			memcpy(&old_bbatt, &phy->bbatt, sizeof(old_bbatt));
+			old_tx_control = phy->tx_control;
+
+			bbatt.att = 11;
+			if (phy->radio_rev == 8) {
+				rfatt.att = 15;
+				rfatt.with_padmix = 1;
+			} else {
+				rfatt.att = 9;
+				rfatt.with_padmix = 0;
+			}
+			b43_set_txpower_g(dev, &bbatt, &rfatt, 0);
+		}
+		b43_dummy_transmission(dev);
+		phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_ITSSI);
+		if (B43_DEBUG) {
+			/* Current-Idle-TSSI sanity check. */
+			if (abs(phy->cur_idle_tssi - phy->tgt_idle_tssi) >= 20) {
+				b43dbg(dev->wl,
+				       "!WARNING! Idle-TSSI phy->cur_idle_tssi "
+				       "measuring failed. (cur=%d, tgt=%d). Disabling TX power "
+				       "adjustment.\n", phy->cur_idle_tssi,
+				       phy->tgt_idle_tssi);
+				phy->cur_idle_tssi = 0;
+			}
+		}
+		if (phy->radio_ver == 0x2050 && phy->analog == 0) {
+			b43_radio_write16(dev, 0x0076,
+					  b43_radio_read16(dev, 0x0076)
+					  & 0xFF7B);
+		} else {
+			b43_set_txpower_g(dev, &old_bbatt,
+					  &old_rfatt, old_tx_control);
+		}
+	}
+	b43_hardware_pctl_init(dev);
+	b43_shm_clear_tssi(dev);
+}
+
+static void b43_phy_agcsetup(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 offset = 0x0000;
+
+	if (phy->rev == 1)
+		offset = 0x4C00;
+
+	b43_ofdmtab_write16(dev, offset, 0, 0x00FE);
+	b43_ofdmtab_write16(dev, offset, 1, 0x000D);
+	b43_ofdmtab_write16(dev, offset, 2, 0x0013);
+	b43_ofdmtab_write16(dev, offset, 3, 0x0019);
+
+	if (phy->rev == 1) {
+		b43_ofdmtab_write16(dev, 0x1800, 0, 0x2710);
+		b43_ofdmtab_write16(dev, 0x1801, 0, 0x9B83);
+		b43_ofdmtab_write16(dev, 0x1802, 0, 0x9B83);
+		b43_ofdmtab_write16(dev, 0x1803, 0, 0x0F8D);
+		b43_phy_write(dev, 0x0455, 0x0004);
+	}
+
+	b43_phy_write(dev, 0x04A5, (b43_phy_read(dev, 0x04A5)
+				    & 0x00FF) | 0x5700);
+	b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A)
+				    & 0xFF80) | 0x000F);
+	b43_phy_write(dev, 0x041A, (b43_phy_read(dev, 0x041A)
+				    & 0xC07F) | 0x2B80);
+	b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
+				    & 0xF0FF) | 0x0300);
+
+	b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A)
+			  | 0x0008);
+
+	b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
+				    & 0xFFF0) | 0x0008);
+	b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
+				    & 0xF0FF) | 0x0600);
+	b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
+				    & 0xF0FF) | 0x0700);
+	b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
+				    & 0xF0FF) | 0x0100);
+
+	if (phy->rev == 1) {
+		b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
+					    & 0xFFF0) | 0x0007);
+	}
+
+	b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488)
+				    & 0xFF00) | 0x001C);
+	b43_phy_write(dev, 0x0488, (b43_phy_read(dev, 0x0488)
+				    & 0xC0FF) | 0x0200);
+	b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496)
+				    & 0xFF00) | 0x001C);
+	b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489)
+				    & 0xFF00) | 0x0020);
+	b43_phy_write(dev, 0x0489, (b43_phy_read(dev, 0x0489)
+				    & 0xC0FF) | 0x0200);
+	b43_phy_write(dev, 0x0482, (b43_phy_read(dev, 0x0482)
+				    & 0xFF00) | 0x002E);
+	b43_phy_write(dev, 0x0496, (b43_phy_read(dev, 0x0496)
+				    & 0x00FF) | 0x1A00);
+	b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481)
+				    & 0xFF00) | 0x0028);
+	b43_phy_write(dev, 0x0481, (b43_phy_read(dev, 0x0481)
+				    & 0x00FF) | 0x2C00);
+
+	if (phy->rev == 1) {
+		b43_phy_write(dev, 0x0430, 0x092B);
+		b43_phy_write(dev, 0x041B, (b43_phy_read(dev, 0x041B)
+					    & 0xFFE1) | 0x0002);
+	} else {
+		b43_phy_write(dev, 0x041B, b43_phy_read(dev, 0x041B)
+			      & 0xFFE1);
+		b43_phy_write(dev, 0x041F, 0x287A);
+		b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420)
+					    & 0xFFF0) | 0x0004);
+	}
+
+	if (phy->rev >= 6) {
+		b43_phy_write(dev, 0x0422, 0x287A);
+		b43_phy_write(dev, 0x0420, (b43_phy_read(dev, 0x0420)
+					    & 0x0FFF) | 0x3000);
+	}
+
+	b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+				    & 0x8080) | 0x7874);
+	b43_phy_write(dev, 0x048E, 0x1C00);
+
+	offset = 0x0800;
+	if (phy->rev == 1) {
+		offset = 0x5400;
+		b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+					    & 0xF0FF) | 0x0600);
+		b43_phy_write(dev, 0x048B, 0x005E);
+		b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
+					    & 0xFF00) | 0x001E);
+		b43_phy_write(dev, 0x048D, 0x0002);
+	}
+	b43_ofdmtab_write16(dev, offset, 0, 0x00);
+	b43_ofdmtab_write16(dev, offset, 1, 0x07);
+	b43_ofdmtab_write16(dev, offset, 2, 0x10);
+	b43_ofdmtab_write16(dev, offset, 3, 0x1C);
+
+	if (phy->rev >= 6) {
+		b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426)
+			      & 0xFFFC);
+		b43_phy_write(dev, 0x0426, b43_phy_read(dev, 0x0426)
+			      & 0xEFFF);
+	}
+}
+
+static void b43_phy_setupg(struct b43_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+	struct b43_phy *phy = &dev->phy;
+	u16 i;
+
+	B43_WARN_ON(phy->type != B43_PHYTYPE_G);
+	if (phy->rev == 1) {
+		b43_phy_write(dev, 0x0406, 0x4F19);
+		b43_phy_write(dev, B43_PHY_G_CRS,
+			      (b43_phy_read(dev, B43_PHY_G_CRS) & 0xFC3F) |
+			      0x0340);
+		b43_phy_write(dev, 0x042C, 0x005A);
+		b43_phy_write(dev, 0x0427, 0x001A);
+
+		for (i = 0; i < B43_TAB_FINEFREQG_SIZE; i++)
+			b43_ofdmtab_write16(dev, 0x5800, i,
+					    b43_tab_finefreqg[i]);
+		for (i = 0; i < B43_TAB_NOISEG1_SIZE; i++)
+			b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg1[i]);
+		for (i = 0; i < B43_TAB_ROTOR_SIZE; i++)
+			b43_ofdmtab_write16(dev, 0x2000, i, b43_tab_rotor[i]);
+	} else {
+		/* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */
+		b43_nrssi_hw_write(dev, 0xBA98, (s16) 0x7654);
+
+		if (phy->rev == 2) {
+			b43_phy_write(dev, 0x04C0, 0x1861);
+			b43_phy_write(dev, 0x04C1, 0x0271);
+		} else if (phy->rev > 2) {
+			b43_phy_write(dev, 0x04C0, 0x0098);
+			b43_phy_write(dev, 0x04C1, 0x0070);
+			b43_phy_write(dev, 0x04C9, 0x0080);
+		}
+		b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x800);
+
+		for (i = 0; i < 64; i++)
+			b43_ofdmtab_write16(dev, 0x4000, i, i);
+		for (i = 0; i < B43_TAB_NOISEG2_SIZE; i++)
+			b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noiseg2[i]);
+	}
+
+	if (phy->rev <= 2)
+		for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
+			b43_ofdmtab_write16(dev, 0x1400, i,
+					    b43_tab_noisescaleg1[i]);
+	else if ((phy->rev >= 7) && (b43_phy_read(dev, 0x0449) & 0x0200))
+		for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
+			b43_ofdmtab_write16(dev, 0x1400, i,
+					    b43_tab_noisescaleg3[i]);
+	else
+		for (i = 0; i < B43_TAB_NOISESCALEG_SIZE; i++)
+			b43_ofdmtab_write16(dev, 0x1400, i,
+					    b43_tab_noisescaleg2[i]);
+
+	if (phy->rev == 2)
+		for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++)
+			b43_ofdmtab_write16(dev, 0x5000, i,
+					    b43_tab_sigmasqr1[i]);
+	else if ((phy->rev > 2) && (phy->rev <= 8))
+		for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++)
+			b43_ofdmtab_write16(dev, 0x5000, i,
+					    b43_tab_sigmasqr2[i]);
+
+	if (phy->rev == 1) {
+		for (i = 0; i < B43_TAB_RETARD_SIZE; i++)
+			b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]);
+		for (i = 4; i < 20; i++)
+			b43_ofdmtab_write16(dev, 0x5400, i, 0x0020);
+		b43_phy_agcsetup(dev);
+
+		if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+		    (bus->boardinfo.type == SSB_BOARD_BU4306) &&
+		    (bus->boardinfo.rev == 0x17))
+			return;
+
+		b43_ofdmtab_write16(dev, 0x5001, 0, 0x0002);
+		b43_ofdmtab_write16(dev, 0x5002, 0, 0x0001);
+	} else {
+		for (i = 0; i < 0x20; i++)
+			b43_ofdmtab_write16(dev, 0x1000, i, 0x0820);
+		b43_phy_agcsetup(dev);
+		b43_phy_read(dev, 0x0400);	/* dummy read */
+		b43_phy_write(dev, 0x0403, 0x1000);
+		b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F);
+		b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014);
+
+		if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+		    (bus->boardinfo.type == SSB_BOARD_BU4306) &&
+		    (bus->boardinfo.rev == 0x17))
+			return;
+
+		b43_ofdmtab_write16(dev, 0x0401, 0, 0x0002);
+		b43_ofdmtab_write16(dev, 0x0402, 0, 0x0001);
+	}
+}
+
+/* Initialize the noisescaletable for APHY */
+static void b43_phy_init_noisescaletbl(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	int i;
+
+	for (i = 0; i < 12; i++) {
+		if (phy->rev == 2)
+			b43_ofdmtab_write16(dev, 0x1400, i, 0x6767);
+		else
+			b43_ofdmtab_write16(dev, 0x1400, i, 0x2323);
+	}
+	if (phy->rev == 2)
+		b43_ofdmtab_write16(dev, 0x1400, i, 0x6700);
+	else
+		b43_ofdmtab_write16(dev, 0x1400, i, 0x2300);
+	for (i = 0; i < 11; i++) {
+		if (phy->rev == 2)
+			b43_ofdmtab_write16(dev, 0x1400, i, 0x6767);
+		else
+			b43_ofdmtab_write16(dev, 0x1400, i, 0x2323);
+	}
+	if (phy->rev == 2)
+		b43_ofdmtab_write16(dev, 0x1400, i, 0x0067);
+	else
+		b43_ofdmtab_write16(dev, 0x1400, i, 0x0023);
+}
+
+static void b43_phy_setupa(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 i;
+
+	B43_WARN_ON(phy->type != B43_PHYTYPE_A);
+	switch (phy->rev) {
+	case 2:
+		b43_phy_write(dev, 0x008E, 0x3800);
+		b43_phy_write(dev, 0x0035, 0x03FF);
+		b43_phy_write(dev, 0x0036, 0x0400);
+
+		b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051);
+
+		b43_phy_write(dev, 0x001C, 0x0FF9);
+		b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F);
+		b43_ofdmtab_write16(dev, 0x3C0C, 0, 0x07BF);
+		b43_radio_write16(dev, 0x0002, 0x07BF);
+
+		b43_phy_write(dev, 0x0024, 0x4680);
+		b43_phy_write(dev, 0x0020, 0x0003);
+		b43_phy_write(dev, 0x001D, 0x0F40);
+		b43_phy_write(dev, 0x001F, 0x1C00);
+
+		b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A)
+					    & 0x00FF) | 0x0400);
+		b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B)
+			      & 0xFBFF);
+		b43_phy_write(dev, 0x008E, 0x58C1);
+
+		b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F);
+		b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F);
+		b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A);
+		b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030);
+		b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A);
+
+		b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013);
+		b43_ofdmtab_write16(dev, 0x0000, 1, 0x0013);
+		b43_ofdmtab_write16(dev, 0x0000, 2, 0x0013);
+		b43_ofdmtab_write16(dev, 0x0000, 3, 0x0013);
+		b43_ofdmtab_write16(dev, 0x0000, 4, 0x0015);
+		b43_ofdmtab_write16(dev, 0x0000, 5, 0x0015);
+		b43_ofdmtab_write16(dev, 0x0000, 6, 0x0019);
+
+		b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003);
+		b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003);
+		b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007);
+
+		for (i = 0; i < 16; i++)
+			b43_ofdmtab_write16(dev, 0x4000, i, (0x8 + i) & 0x000F);
+
+		b43_ofdmtab_write16(dev, 0x3003, 0, 0x1044);
+		b43_ofdmtab_write16(dev, 0x3004, 0, 0x7201);
+		b43_ofdmtab_write16(dev, 0x3006, 0, 0x0040);
+		b43_ofdmtab_write16(dev, 0x3001, 0,
+				    (b43_ofdmtab_read16(dev, 0x3001, 0) &
+				     0x0010) | 0x0008);
+
+		for (i = 0; i < B43_TAB_FINEFREQA_SIZE; i++)
+			b43_ofdmtab_write16(dev, 0x5800, i,
+					    b43_tab_finefreqa[i]);
+		for (i = 0; i < B43_TAB_NOISEA2_SIZE; i++)
+			b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea2[i]);
+		for (i = 0; i < B43_TAB_ROTOR_SIZE; i++)
+			b43_ofdmtab_write32(dev, 0x2000, i, b43_tab_rotor[i]);
+		b43_phy_init_noisescaletbl(dev);
+		for (i = 0; i < B43_TAB_RETARD_SIZE; i++)
+			b43_ofdmtab_write32(dev, 0x2400, i, b43_tab_retard[i]);
+		break;
+	case 3:
+		for (i = 0; i < 64; i++)
+			b43_ofdmtab_write16(dev, 0x4000, i, i);
+
+		b43_ofdmtab_write16(dev, 0x3807, 0, 0x0051);
+
+		b43_phy_write(dev, 0x001C, 0x0FF9);
+		b43_phy_write(dev, 0x0020, b43_phy_read(dev, 0x0020) & 0xFF0F);
+		b43_radio_write16(dev, 0x0002, 0x07BF);
+
+		b43_phy_write(dev, 0x0024, 0x4680);
+		b43_phy_write(dev, 0x0020, 0x0003);
+		b43_phy_write(dev, 0x001D, 0x0F40);
+		b43_phy_write(dev, 0x001F, 0x1C00);
+		b43_phy_write(dev, 0x002A, (b43_phy_read(dev, 0x002A)
+					    & 0x00FF) | 0x0400);
+
+		b43_ofdmtab_write16(dev, 0x3000, 1,
+				    (b43_ofdmtab_read16(dev, 0x3000, 1)
+				     & 0x0010) | 0x0008);
+		for (i = 0; i < B43_TAB_NOISEA3_SIZE; i++) {
+			b43_ofdmtab_write16(dev, 0x1800, i, b43_tab_noisea3[i]);
+		}
+		b43_phy_init_noisescaletbl(dev);
+		for (i = 0; i < B43_TAB_SIGMASQR_SIZE; i++) {
+			b43_ofdmtab_write16(dev, 0x5000, i,
+					    b43_tab_sigmasqr1[i]);
+		}
+
+		b43_phy_write(dev, 0x0003, 0x1808);
+
+		b43_ofdmtab_write16(dev, 0x0803, 0, 0x000F);
+		b43_ofdmtab_write16(dev, 0x0804, 0, 0x001F);
+		b43_ofdmtab_write16(dev, 0x0805, 0, 0x002A);
+		b43_ofdmtab_write16(dev, 0x0805, 0, 0x0030);
+		b43_ofdmtab_write16(dev, 0x0807, 0, 0x003A);
+
+		b43_ofdmtab_write16(dev, 0x0000, 0, 0x0013);
+		b43_ofdmtab_write16(dev, 0x0001, 0, 0x0013);
+		b43_ofdmtab_write16(dev, 0x0002, 0, 0x0013);
+		b43_ofdmtab_write16(dev, 0x0003, 0, 0x0013);
+		b43_ofdmtab_write16(dev, 0x0004, 0, 0x0015);
+		b43_ofdmtab_write16(dev, 0x0005, 0, 0x0015);
+		b43_ofdmtab_write16(dev, 0x0006, 0, 0x0019);
+
+		b43_ofdmtab_write16(dev, 0x0404, 0, 0x0003);
+		b43_ofdmtab_write16(dev, 0x0405, 0, 0x0003);
+		b43_ofdmtab_write16(dev, 0x0406, 0, 0x0007);
+
+		b43_ofdmtab_write16(dev, 0x3C02, 0, 0x000F);
+		b43_ofdmtab_write16(dev, 0x3C03, 0, 0x0014);
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+}
+
+/* Initialize APHY. This is also called for the GPHY in some cases. */
+static void b43_phy_inita(struct b43_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+	struct b43_phy *phy = &dev->phy;
+	u16 tval;
+
+	might_sleep();
+
+	if (phy->type == B43_PHYTYPE_A) {
+		b43_phy_setupa(dev);
+	} else {
+		b43_phy_setupg(dev);
+		if (phy->gmode &&
+		    (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL))
+			b43_phy_write(dev, 0x046E, 0x03CF);
+		return;
+	}
+
+	b43_phy_write(dev, B43_PHY_A_CRS,
+		      (b43_phy_read(dev, B43_PHY_A_CRS) & 0xF83C) | 0x0340);
+	b43_phy_write(dev, 0x0034, 0x0001);
+
+	//TODO: RSSI AGC
+	b43_phy_write(dev, B43_PHY_A_CRS,
+		      b43_phy_read(dev, B43_PHY_A_CRS) | (1 << 14));
+	b43_radio_init2060(dev);
+
+	if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+	    ((bus->boardinfo.type == SSB_BOARD_BU4306) ||
+	     (bus->boardinfo.type == SSB_BOARD_BU4309))) {
+		if (phy->lofcal == 0xFFFF) {
+			//TODO: LOF Cal
+			b43_radio_set_tx_iq(dev);
+		} else
+			b43_radio_write16(dev, 0x001E, phy->lofcal);
+	}
+
+	b43_phy_write(dev, 0x007A, 0xF111);
+
+	if (phy->cur_idle_tssi == 0) {
+		b43_radio_write16(dev, 0x0019, 0x0000);
+		b43_radio_write16(dev, 0x0017, 0x0020);
+
+		tval = b43_ofdmtab_read16(dev, 0x3001, 0);
+		if (phy->rev == 1) {
+			b43_ofdmtab_write16(dev, 0x3001, 0,
+					    (b43_ofdmtab_read16(dev, 0x3001, 0)
+					     & 0xFF87)
+					    | 0x0058);
+		} else {
+			b43_ofdmtab_write16(dev, 0x3001, 0,
+					    (b43_ofdmtab_read16(dev, 0x3001, 0)
+					     & 0xFFC3)
+					    | 0x002C);
+		}
+		b43_dummy_transmission(dev);
+		phy->cur_idle_tssi = b43_phy_read(dev, B43_PHY_A_PCTL);
+		b43_ofdmtab_write16(dev, 0x3001, 0, tval);
+
+		b43_radio_set_txpower_a(dev, 0x0018);
+	}
+	b43_shm_clear_tssi(dev);
+}
+
+static void b43_phy_initb2(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 offset, val;
+
+	b43_write16(dev, 0x03EC, 0x3F22);
+	b43_phy_write(dev, 0x0020, 0x301C);
+	b43_phy_write(dev, 0x0026, 0x0000);
+	b43_phy_write(dev, 0x0030, 0x00C6);
+	b43_phy_write(dev, 0x0088, 0x3E00);
+	val = 0x3C3D;
+	for (offset = 0x0089; offset < 0x00A7; offset++) {
+		b43_phy_write(dev, offset, val);
+		val -= 0x0202;
+	}
+	b43_phy_write(dev, 0x03E4, 0x3000);
+	b43_radio_selectchannel(dev, phy->channel, 0);
+	if (phy->radio_ver != 0x2050) {
+		b43_radio_write16(dev, 0x0075, 0x0080);
+		b43_radio_write16(dev, 0x0079, 0x0081);
+	}
+	b43_radio_write16(dev, 0x0050, 0x0020);
+	b43_radio_write16(dev, 0x0050, 0x0023);
+	if (phy->radio_ver == 0x2050) {
+		b43_radio_write16(dev, 0x0050, 0x0020);
+		b43_radio_write16(dev, 0x005A, 0x0070);
+		b43_radio_write16(dev, 0x005B, 0x007B);
+		b43_radio_write16(dev, 0x005C, 0x00B0);
+		b43_radio_write16(dev, 0x007A, 0x000F);
+		b43_phy_write(dev, 0x0038, 0x0677);
+		b43_radio_init2050(dev);
+	}
+	b43_phy_write(dev, 0x0014, 0x0080);
+	b43_phy_write(dev, 0x0032, 0x00CA);
+	b43_phy_write(dev, 0x0032, 0x00CC);
+	b43_phy_write(dev, 0x0035, 0x07C2);
+	b43_lo_b_measure(dev);
+	b43_phy_write(dev, 0x0026, 0xCC00);
+	if (phy->radio_ver != 0x2050)
+		b43_phy_write(dev, 0x0026, 0xCE00);
+	b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1000);
+	b43_phy_write(dev, 0x002A, 0x88A3);
+	if (phy->radio_ver != 0x2050)
+		b43_phy_write(dev, 0x002A, 0x88C2);
+	b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
+	b43_phy_init_pctl(dev);
+}
+
+static void b43_phy_initb4(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 offset, val;
+
+	b43_write16(dev, 0x03EC, 0x3F22);
+	b43_phy_write(dev, 0x0020, 0x301C);
+	b43_phy_write(dev, 0x0026, 0x0000);
+	b43_phy_write(dev, 0x0030, 0x00C6);
+	b43_phy_write(dev, 0x0088, 0x3E00);
+	val = 0x3C3D;
+	for (offset = 0x0089; offset < 0x00A7; offset++) {
+		b43_phy_write(dev, offset, val);
+		val -= 0x0202;
+	}
+	b43_phy_write(dev, 0x03E4, 0x3000);
+	b43_radio_selectchannel(dev, phy->channel, 0);
+	if (phy->radio_ver != 0x2050) {
+		b43_radio_write16(dev, 0x0075, 0x0080);
+		b43_radio_write16(dev, 0x0079, 0x0081);
+	}
+	b43_radio_write16(dev, 0x0050, 0x0020);
+	b43_radio_write16(dev, 0x0050, 0x0023);
+	if (phy->radio_ver == 0x2050) {
+		b43_radio_write16(dev, 0x0050, 0x0020);
+		b43_radio_write16(dev, 0x005A, 0x0070);
+		b43_radio_write16(dev, 0x005B, 0x007B);
+		b43_radio_write16(dev, 0x005C, 0x00B0);
+		b43_radio_write16(dev, 0x007A, 0x000F);
+		b43_phy_write(dev, 0x0038, 0x0677);
+		b43_radio_init2050(dev);
+	}
+	b43_phy_write(dev, 0x0014, 0x0080);
+	b43_phy_write(dev, 0x0032, 0x00CA);
+	if (phy->radio_ver == 0x2050)
+		b43_phy_write(dev, 0x0032, 0x00E0);
+	b43_phy_write(dev, 0x0035, 0x07C2);
+
+	b43_lo_b_measure(dev);
+
+	b43_phy_write(dev, 0x0026, 0xCC00);
+	if (phy->radio_ver == 0x2050)
+		b43_phy_write(dev, 0x0026, 0xCE00);
+	b43_write16(dev, B43_MMIO_CHANNEL_EXT, 0x1100);
+	b43_phy_write(dev, 0x002A, 0x88A3);
+	if (phy->radio_ver == 0x2050)
+		b43_phy_write(dev, 0x002A, 0x88C2);
+	b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
+	if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+		b43_calc_nrssi_slope(dev);
+		b43_calc_nrssi_threshold(dev);
+	}
+	b43_phy_init_pctl(dev);
+}
+
+static void b43_phy_initb5(struct b43_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+	struct b43_phy *phy = &dev->phy;
+	u16 offset, value;
+	u8 old_channel;
+
+	if (phy->analog == 1) {
+		b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A)
+				  | 0x0050);
+	}
+	if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) &&
+	    (bus->boardinfo.type != SSB_BOARD_BU4306)) {
+		value = 0x2120;
+		for (offset = 0x00A8; offset < 0x00C7; offset++) {
+			b43_phy_write(dev, offset, value);
+			value += 0x202;
+		}
+	}
+	b43_phy_write(dev, 0x0035, (b43_phy_read(dev, 0x0035) & 0xF0FF)
+		      | 0x0700);
+	if (phy->radio_ver == 0x2050)
+		b43_phy_write(dev, 0x0038, 0x0667);
+
+	if (phy->gmode || phy->rev >= 2) {
+		if (phy->radio_ver == 0x2050) {
+			b43_radio_write16(dev, 0x007A,
+					  b43_radio_read16(dev, 0x007A)
+					  | 0x0020);
+			b43_radio_write16(dev, 0x0051,
+					  b43_radio_read16(dev, 0x0051)
+					  | 0x0004);
+		}
+		b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000);
+
+		b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100);
+		b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000);
+
+		b43_phy_write(dev, 0x001C, 0x186A);
+
+		b43_phy_write(dev, 0x0013,
+			      (b43_phy_read(dev, 0x0013) & 0x00FF) | 0x1900);
+		b43_phy_write(dev, 0x0035,
+			      (b43_phy_read(dev, 0x0035) & 0xFFC0) | 0x0064);
+		b43_phy_write(dev, 0x005D,
+			      (b43_phy_read(dev, 0x005D) & 0xFF80) | 0x000A);
+	}
+
+	if (dev->bad_frames_preempt) {
+		b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
+			      b43_phy_read(dev,
+					   B43_PHY_RADIO_BITFIELD) | (1 << 11));
+	}
+
+	if (phy->analog == 1) {
+		b43_phy_write(dev, 0x0026, 0xCE00);
+		b43_phy_write(dev, 0x0021, 0x3763);
+		b43_phy_write(dev, 0x0022, 0x1BC3);
+		b43_phy_write(dev, 0x0023, 0x06F9);
+		b43_phy_write(dev, 0x0024, 0x037E);
+	} else
+		b43_phy_write(dev, 0x0026, 0xCC00);
+	b43_phy_write(dev, 0x0030, 0x00C6);
+	b43_write16(dev, 0x03EC, 0x3F22);
+
+	if (phy->analog == 1)
+		b43_phy_write(dev, 0x0020, 0x3E1C);
+	else
+		b43_phy_write(dev, 0x0020, 0x301C);
+
+	if (phy->analog == 0)
+		b43_write16(dev, 0x03E4, 0x3000);
+
+	old_channel = phy->channel;
+	/* Force to channel 7, even if not supported. */
+	b43_radio_selectchannel(dev, 7, 0);
+
+	if (phy->radio_ver != 0x2050) {
+		b43_radio_write16(dev, 0x0075, 0x0080);
+		b43_radio_write16(dev, 0x0079, 0x0081);
+	}
+
+	b43_radio_write16(dev, 0x0050, 0x0020);
+	b43_radio_write16(dev, 0x0050, 0x0023);
+
+	if (phy->radio_ver == 0x2050) {
+		b43_radio_write16(dev, 0x0050, 0x0020);
+		b43_radio_write16(dev, 0x005A, 0x0070);
+	}
+
+	b43_radio_write16(dev, 0x005B, 0x007B);
+	b43_radio_write16(dev, 0x005C, 0x00B0);
+
+	b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0007);
+
+	b43_radio_selectchannel(dev, old_channel, 0);
+
+	b43_phy_write(dev, 0x0014, 0x0080);
+	b43_phy_write(dev, 0x0032, 0x00CA);
+	b43_phy_write(dev, 0x002A, 0x88A3);
+
+	b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
+
+	if (phy->radio_ver == 0x2050)
+		b43_radio_write16(dev, 0x005D, 0x000D);
+
+	b43_write16(dev, 0x03E4, (b43_read16(dev, 0x03E4) & 0xFFC0) | 0x0004);
+}
+
+static void b43_phy_initb6(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 offset, val;
+	u8 old_channel;
+
+	b43_phy_write(dev, 0x003E, 0x817A);
+	b43_radio_write16(dev, 0x007A,
+			  (b43_radio_read16(dev, 0x007A) | 0x0058));
+	if (phy->radio_rev == 4 || phy->radio_rev == 5) {
+		b43_radio_write16(dev, 0x51, 0x37);
+		b43_radio_write16(dev, 0x52, 0x70);
+		b43_radio_write16(dev, 0x53, 0xB3);
+		b43_radio_write16(dev, 0x54, 0x9B);
+		b43_radio_write16(dev, 0x5A, 0x88);
+		b43_radio_write16(dev, 0x5B, 0x88);
+		b43_radio_write16(dev, 0x5D, 0x88);
+		b43_radio_write16(dev, 0x5E, 0x88);
+		b43_radio_write16(dev, 0x7D, 0x88);
+		b43_hf_write(dev, b43_hf_read(dev)
+			     | B43_HF_TSSIRPSMW);
+	}
+	B43_WARN_ON(phy->radio_rev == 6 || phy->radio_rev == 7);	/* We had code for these revs here... */
+	if (phy->radio_rev == 8) {
+		b43_radio_write16(dev, 0x51, 0);
+		b43_radio_write16(dev, 0x52, 0x40);
+		b43_radio_write16(dev, 0x53, 0xB7);
+		b43_radio_write16(dev, 0x54, 0x98);
+		b43_radio_write16(dev, 0x5A, 0x88);
+		b43_radio_write16(dev, 0x5B, 0x6B);
+		b43_radio_write16(dev, 0x5C, 0x0F);
+		if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_ALTIQ) {
+			b43_radio_write16(dev, 0x5D, 0xFA);
+			b43_radio_write16(dev, 0x5E, 0xD8);
+		} else {
+			b43_radio_write16(dev, 0x5D, 0xF5);
+			b43_radio_write16(dev, 0x5E, 0xB8);
+		}
+		b43_radio_write16(dev, 0x0073, 0x0003);
+		b43_radio_write16(dev, 0x007D, 0x00A8);
+		b43_radio_write16(dev, 0x007C, 0x0001);
+		b43_radio_write16(dev, 0x007E, 0x0008);
+	}
+	val = 0x1E1F;
+	for (offset = 0x0088; offset < 0x0098; offset++) {
+		b43_phy_write(dev, offset, val);
+		val -= 0x0202;
+	}
+	val = 0x3E3F;
+	for (offset = 0x0098; offset < 0x00A8; offset++) {
+		b43_phy_write(dev, offset, val);
+		val -= 0x0202;
+	}
+	val = 0x2120;
+	for (offset = 0x00A8; offset < 0x00C8; offset++) {
+		b43_phy_write(dev, offset, (val & 0x3F3F));
+		val += 0x0202;
+	}
+	if (phy->type == B43_PHYTYPE_G) {
+		b43_radio_write16(dev, 0x007A,
+				  b43_radio_read16(dev, 0x007A) | 0x0020);
+		b43_radio_write16(dev, 0x0051,
+				  b43_radio_read16(dev, 0x0051) | 0x0004);
+		b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100);
+		b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000);
+		b43_phy_write(dev, 0x5B, 0);
+		b43_phy_write(dev, 0x5C, 0);
+	}
+
+	old_channel = phy->channel;
+	if (old_channel >= 8)
+		b43_radio_selectchannel(dev, 1, 0);
+	else
+		b43_radio_selectchannel(dev, 13, 0);
+
+	b43_radio_write16(dev, 0x0050, 0x0020);
+	b43_radio_write16(dev, 0x0050, 0x0023);
+	udelay(40);
+	if (phy->radio_rev < 6 || phy->radio_rev == 8) {
+		b43_radio_write16(dev, 0x7C, (b43_radio_read16(dev, 0x7C)
+					      | 0x0002));
+		b43_radio_write16(dev, 0x50, 0x20);
+	}
+	if (phy->radio_rev <= 2) {
+		b43_radio_write16(dev, 0x7C, 0x20);
+		b43_radio_write16(dev, 0x5A, 0x70);
+		b43_radio_write16(dev, 0x5B, 0x7B);
+		b43_radio_write16(dev, 0x5C, 0xB0);
+	}
+	b43_radio_write16(dev, 0x007A,
+			  (b43_radio_read16(dev, 0x007A) & 0x00F8) | 0x0007);
+
+	b43_radio_selectchannel(dev, old_channel, 0);
+
+	b43_phy_write(dev, 0x0014, 0x0200);
+	if (phy->radio_rev >= 6)
+		b43_phy_write(dev, 0x2A, 0x88C2);
+	else
+		b43_phy_write(dev, 0x2A, 0x8AC0);
+	b43_phy_write(dev, 0x0038, 0x0668);
+	b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt, phy->tx_control);
+	if (phy->radio_rev <= 5) {
+		b43_phy_write(dev, 0x5D, (b43_phy_read(dev, 0x5D)
+					  & 0xFF80) | 0x0003);
+	}
+	if (phy->radio_rev <= 2)
+		b43_radio_write16(dev, 0x005D, 0x000D);
+
+	if (phy->analog == 4) {
+		b43_write16(dev, 0x3E4, 9);
+		b43_phy_write(dev, 0x61, b43_phy_read(dev, 0x61)
+			      & 0x0FFF);
+	} else {
+		b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0)
+			      | 0x0004);
+	}
+	if (phy->type == B43_PHYTYPE_B) {
+		b43_write16(dev, 0x03E6, 0x8140);
+		b43_phy_write(dev, 0x0016, 0x0410);
+		b43_phy_write(dev, 0x0017, 0x0820);
+		b43_phy_write(dev, 0x0062, 0x0007);
+		b43_radio_init2050(dev);
+		b43_lo_g_measure(dev);
+		if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI) {
+			b43_calc_nrssi_slope(dev);
+			b43_calc_nrssi_threshold(dev);
+		}
+		b43_phy_init_pctl(dev);
+	} else if (phy->type == B43_PHYTYPE_G)
+		b43_write16(dev, 0x03E6, 0x0);
+}
+
+static void b43_calc_loopback_gain(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 backup_phy[16] = { 0 };
+	u16 backup_radio[3];
+	u16 backup_bband;
+	u16 i, j, loop_i_max;
+	u16 trsw_rx;
+	u16 loop1_outer_done, loop1_inner_done;
+
+	backup_phy[0] = b43_phy_read(dev, B43_PHY_CRS0);
+	backup_phy[1] = b43_phy_read(dev, B43_PHY_CCKBBANDCFG);
+	backup_phy[2] = b43_phy_read(dev, B43_PHY_RFOVER);
+	backup_phy[3] = b43_phy_read(dev, B43_PHY_RFOVERVAL);
+	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
+		backup_phy[4] = b43_phy_read(dev, B43_PHY_ANALOGOVER);
+		backup_phy[5] = b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
+	}
+	backup_phy[6] = b43_phy_read(dev, B43_PHY_BASE(0x5A));
+	backup_phy[7] = b43_phy_read(dev, B43_PHY_BASE(0x59));
+	backup_phy[8] = b43_phy_read(dev, B43_PHY_BASE(0x58));
+	backup_phy[9] = b43_phy_read(dev, B43_PHY_BASE(0x0A));
+	backup_phy[10] = b43_phy_read(dev, B43_PHY_BASE(0x03));
+	backup_phy[11] = b43_phy_read(dev, B43_PHY_LO_MASK);
+	backup_phy[12] = b43_phy_read(dev, B43_PHY_LO_CTL);
+	backup_phy[13] = b43_phy_read(dev, B43_PHY_BASE(0x2B));
+	backup_phy[14] = b43_phy_read(dev, B43_PHY_PGACTL);
+	backup_phy[15] = b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
+	backup_bband = phy->bbatt.att;
+	backup_radio[0] = b43_radio_read16(dev, 0x52);
+	backup_radio[1] = b43_radio_read16(dev, 0x43);
+	backup_radio[2] = b43_radio_read16(dev, 0x7A);
+
+	b43_phy_write(dev, B43_PHY_CRS0,
+		      b43_phy_read(dev, B43_PHY_CRS0) & 0x3FFF);
+	b43_phy_write(dev, B43_PHY_CCKBBANDCFG,
+		      b43_phy_read(dev, B43_PHY_CCKBBANDCFG) | 0x8000);
+	b43_phy_write(dev, B43_PHY_RFOVER,
+		      b43_phy_read(dev, B43_PHY_RFOVER) | 0x0002);
+	b43_phy_write(dev, B43_PHY_RFOVERVAL,
+		      b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFD);
+	b43_phy_write(dev, B43_PHY_RFOVER,
+		      b43_phy_read(dev, B43_PHY_RFOVER) | 0x0001);
+	b43_phy_write(dev, B43_PHY_RFOVERVAL,
+		      b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFE);
+	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
+		b43_phy_write(dev, B43_PHY_ANALOGOVER,
+			      b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0001);
+		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+			      b43_phy_read(dev,
+					   B43_PHY_ANALOGOVERVAL) & 0xFFFE);
+		b43_phy_write(dev, B43_PHY_ANALOGOVER,
+			      b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0002);
+		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+			      b43_phy_read(dev,
+					   B43_PHY_ANALOGOVERVAL) & 0xFFFD);
+	}
+	b43_phy_write(dev, B43_PHY_RFOVER,
+		      b43_phy_read(dev, B43_PHY_RFOVER) | 0x000C);
+	b43_phy_write(dev, B43_PHY_RFOVERVAL,
+		      b43_phy_read(dev, B43_PHY_RFOVERVAL) | 0x000C);
+	b43_phy_write(dev, B43_PHY_RFOVER,
+		      b43_phy_read(dev, B43_PHY_RFOVER) | 0x0030);
+	b43_phy_write(dev, B43_PHY_RFOVERVAL,
+		      (b43_phy_read(dev, B43_PHY_RFOVERVAL)
+		       & 0xFFCF) | 0x10);
+
+	b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0780);
+	b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
+	b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+
+	b43_phy_write(dev, B43_PHY_BASE(0x0A),
+		      b43_phy_read(dev, B43_PHY_BASE(0x0A)) | 0x2000);
+	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
+		b43_phy_write(dev, B43_PHY_ANALOGOVER,
+			      b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004);
+		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+			      b43_phy_read(dev,
+					   B43_PHY_ANALOGOVERVAL) & 0xFFFB);
+	}
+	b43_phy_write(dev, B43_PHY_BASE(0x03),
+		      (b43_phy_read(dev, B43_PHY_BASE(0x03))
+		       & 0xFF9F) | 0x40);
+
+	if (phy->radio_rev == 8) {
+		b43_radio_write16(dev, 0x43, 0x000F);
+	} else {
+		b43_radio_write16(dev, 0x52, 0);
+		b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+					      & 0xFFF0) | 0x9);
+	}
+	b43_phy_set_baseband_attenuation(dev, 11);
+
+	if (phy->rev >= 3)
+		b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020);
+	else
+		b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
+	b43_phy_write(dev, B43_PHY_LO_CTL, 0);
+
+	b43_phy_write(dev, B43_PHY_BASE(0x2B),
+		      (b43_phy_read(dev, B43_PHY_BASE(0x2B))
+		       & 0xFFC0) | 0x01);
+	b43_phy_write(dev, B43_PHY_BASE(0x2B),
+		      (b43_phy_read(dev, B43_PHY_BASE(0x2B))
+		       & 0xC0FF) | 0x800);
+
+	b43_phy_write(dev, B43_PHY_RFOVER,
+		      b43_phy_read(dev, B43_PHY_RFOVER) | 0x0100);
+	b43_phy_write(dev, B43_PHY_RFOVERVAL,
+		      b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF);
+
+	if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_EXTLNA) {
+		if (phy->rev >= 7) {
+			b43_phy_write(dev, B43_PHY_RFOVER,
+				      b43_phy_read(dev, B43_PHY_RFOVER)
+				      | 0x0800);
+			b43_phy_write(dev, B43_PHY_RFOVERVAL,
+				      b43_phy_read(dev, B43_PHY_RFOVERVAL)
+				      | 0x8000);
+		}
+	}
+	b43_radio_write16(dev, 0x7A, b43_radio_read16(dev, 0x7A)
+			  & 0x00F7);
+
+	j = 0;
+	loop_i_max = (phy->radio_rev == 8) ? 15 : 9;
+	for (i = 0; i < loop_i_max; i++) {
+		for (j = 0; j < 16; j++) {
+			b43_radio_write16(dev, 0x43, i);
+			b43_phy_write(dev, B43_PHY_RFOVERVAL,
+				      (b43_phy_read(dev, B43_PHY_RFOVERVAL)
+				       & 0xF0FF) | (j << 8));
+			b43_phy_write(dev, B43_PHY_PGACTL,
+				      (b43_phy_read(dev, B43_PHY_PGACTL)
+				       & 0x0FFF) | 0xA000);
+			b43_phy_write(dev, B43_PHY_PGACTL,
+				      b43_phy_read(dev, B43_PHY_PGACTL)
+				      | 0xF000);
+			udelay(20);
+			if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
+				goto exit_loop1;
+		}
+	}
+      exit_loop1:
+	loop1_outer_done = i;
+	loop1_inner_done = j;
+	if (j >= 8) {
+		b43_phy_write(dev, B43_PHY_RFOVERVAL,
+			      b43_phy_read(dev, B43_PHY_RFOVERVAL)
+			      | 0x30);
+		trsw_rx = 0x1B;
+		for (j = j - 8; j < 16; j++) {
+			b43_phy_write(dev, B43_PHY_RFOVERVAL,
+				      (b43_phy_read(dev, B43_PHY_RFOVERVAL)
+				       & 0xF0FF) | (j << 8));
+			b43_phy_write(dev, B43_PHY_PGACTL,
+				      (b43_phy_read(dev, B43_PHY_PGACTL)
+				       & 0x0FFF) | 0xA000);
+			b43_phy_write(dev, B43_PHY_PGACTL,
+				      b43_phy_read(dev, B43_PHY_PGACTL)
+				      | 0xF000);
+			udelay(20);
+			trsw_rx -= 3;
+			if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
+				goto exit_loop2;
+		}
+	} else
+		trsw_rx = 0x18;
+      exit_loop2:
+
+	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
+		b43_phy_write(dev, B43_PHY_ANALOGOVER, backup_phy[4]);
+		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, backup_phy[5]);
+	}
+	b43_phy_write(dev, B43_PHY_BASE(0x5A), backup_phy[6]);
+	b43_phy_write(dev, B43_PHY_BASE(0x59), backup_phy[7]);
+	b43_phy_write(dev, B43_PHY_BASE(0x58), backup_phy[8]);
+	b43_phy_write(dev, B43_PHY_BASE(0x0A), backup_phy[9]);
+	b43_phy_write(dev, B43_PHY_BASE(0x03), backup_phy[10]);
+	b43_phy_write(dev, B43_PHY_LO_MASK, backup_phy[11]);
+	b43_phy_write(dev, B43_PHY_LO_CTL, backup_phy[12]);
+	b43_phy_write(dev, B43_PHY_BASE(0x2B), backup_phy[13]);
+	b43_phy_write(dev, B43_PHY_PGACTL, backup_phy[14]);
+
+	b43_phy_set_baseband_attenuation(dev, backup_bband);
+
+	b43_radio_write16(dev, 0x52, backup_radio[0]);
+	b43_radio_write16(dev, 0x43, backup_radio[1]);
+	b43_radio_write16(dev, 0x7A, backup_radio[2]);
+
+	b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2] | 0x0003);
+	udelay(10);
+	b43_phy_write(dev, B43_PHY_RFOVER, backup_phy[2]);
+	b43_phy_write(dev, B43_PHY_RFOVERVAL, backup_phy[3]);
+	b43_phy_write(dev, B43_PHY_CRS0, backup_phy[0]);
+	b43_phy_write(dev, B43_PHY_CCKBBANDCFG, backup_phy[1]);
+
+	phy->max_lb_gain =
+	    ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
+	phy->trsw_rx_gain = trsw_rx * 2;
+}
+
+static void b43_phy_initg(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 tmp;
+
+	if (phy->rev == 1)
+		b43_phy_initb5(dev);
+	else
+		b43_phy_initb6(dev);
+
+	if (phy->rev >= 2 || phy->gmode)
+		b43_phy_inita(dev);
+
+	if (phy->rev >= 2) {
+		b43_phy_write(dev, B43_PHY_ANALOGOVER, 0);
+		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL, 0);
+	}
+	if (phy->rev == 2) {
+		b43_phy_write(dev, B43_PHY_RFOVER, 0);
+		b43_phy_write(dev, B43_PHY_PGACTL, 0xC0);
+	}
+	if (phy->rev > 5) {
+		b43_phy_write(dev, B43_PHY_RFOVER, 0x400);
+		b43_phy_write(dev, B43_PHY_PGACTL, 0xC0);
+	}
+	if (phy->gmode || phy->rev >= 2) {
+		tmp = b43_phy_read(dev, B43_PHY_VERSION_OFDM);
+		tmp &= B43_PHYVER_VERSION;
+		if (tmp == 3 || tmp == 5) {
+			b43_phy_write(dev, B43_PHY_OFDM(0xC2), 0x1816);
+			b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006);
+		}
+		if (tmp == 5) {
+			b43_phy_write(dev, B43_PHY_OFDM(0xCC),
+				      (b43_phy_read(dev, B43_PHY_OFDM(0xCC))
+				       & 0x00FF) | 0x1F00);
+		}
+	}
+	if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
+		b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78);
+	if (phy->radio_rev == 8) {
+		b43_phy_write(dev, B43_PHY_EXTG(0x01),
+			      b43_phy_read(dev, B43_PHY_EXTG(0x01))
+			      | 0x80);
+		b43_phy_write(dev, B43_PHY_OFDM(0x3E),
+			      b43_phy_read(dev, B43_PHY_OFDM(0x3E))
+			      | 0x4);
+	}
+	if (has_loopback_gain(phy))
+		b43_calc_loopback_gain(dev);
+
+	if (phy->radio_rev != 8) {
+		if (phy->initval == 0xFFFF)
+			phy->initval = b43_radio_init2050(dev);
+		else
+			b43_radio_write16(dev, 0x0078, phy->initval);
+	}
+	if (phy->lo_control->tx_bias == 0xFF) {
+		b43_lo_g_measure(dev);
+	} else {
+		if (has_tx_magnification(phy)) {
+			b43_radio_write16(dev, 0x52,
+					  (b43_radio_read16(dev, 0x52) & 0xFF00)
+					  | phy->lo_control->tx_bias | phy->
+					  lo_control->tx_magn);
+		} else {
+			b43_radio_write16(dev, 0x52,
+					  (b43_radio_read16(dev, 0x52) & 0xFFF0)
+					  | phy->lo_control->tx_bias);
+		}
+		if (phy->rev >= 6) {
+			b43_phy_write(dev, B43_PHY_BASE(0x36),
+				      (b43_phy_read(dev, B43_PHY_BASE(0x36))
+				       & 0x0FFF) | (phy->lo_control->
+						    tx_bias << 12));
+		}
+		if (dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_PACTRL)
+			b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x8075);
+		else
+			b43_phy_write(dev, B43_PHY_BASE(0x2E), 0x807F);
+		if (phy->rev < 2)
+			b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x101);
+		else
+			b43_phy_write(dev, B43_PHY_BASE(0x2F), 0x202);
+	}
+	if (phy->gmode || phy->rev >= 2) {
+		b43_lo_g_adjust(dev);
+		b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
+	}
+
+	if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) {
+		/* The specs state to update the NRSSI LT with
+		 * the value 0x7FFFFFFF here. I think that is some weird
+		 * compiler optimization in the original driver.
+		 * Essentially, what we do here is resetting all NRSSI LT
+		 * entries to -32 (see the limit_value() in nrssi_hw_update())
+		 */
+		b43_nrssi_hw_update(dev, 0xFFFF);	//FIXME?
+		b43_calc_nrssi_threshold(dev);
+	} else if (phy->gmode || phy->rev >= 2) {
+		if (phy->nrssi[0] == -1000) {
+			B43_WARN_ON(phy->nrssi[1] != -1000);
+			b43_calc_nrssi_slope(dev);
+		} else
+			b43_calc_nrssi_threshold(dev);
+	}
+	if (phy->radio_rev == 8)
+		b43_phy_write(dev, B43_PHY_EXTG(0x05), 0x3230);
+	b43_phy_init_pctl(dev);
+	/* FIXME: The spec says in the following if, the 0 should be replaced
+	   'if OFDM may not be used in the current locale'
+	   but OFDM is legal everywhere */
+	if ((dev->dev->bus->chip_id == 0x4306
+	     && dev->dev->bus->chip_package == 2) || 0) {
+		b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
+			      & 0xBFFF);
+		b43_phy_write(dev, B43_PHY_OFDM(0xC3),
+			      b43_phy_read(dev, B43_PHY_OFDM(0xC3))
+			      & 0x7FFF);
+	}
+}
+
+/* Set the baseband attenuation value on chip. */
+void b43_phy_set_baseband_attenuation(struct b43_wldev *dev,
+				      u16 baseband_attenuation)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (phy->analog == 0) {
+		b43_write16(dev, B43_MMIO_PHY0, (b43_read16(dev, B43_MMIO_PHY0)
+						 & 0xFFF0) |
+			    baseband_attenuation);
+	} else if (phy->analog > 1) {
+		b43_phy_write(dev, B43_PHY_DACCTL,
+			      (b43_phy_read(dev, B43_PHY_DACCTL)
+			       & 0xFFC3) | (baseband_attenuation << 2));
+	} else {
+		b43_phy_write(dev, B43_PHY_DACCTL,
+			      (b43_phy_read(dev, B43_PHY_DACCTL)
+			       & 0xFF87) | (baseband_attenuation << 3));
+	}
+}
+
+/* http://bcm-specs.sipsolutions.net/EstimatePowerOut
+ * This function converts a TSSI value to dBm in Q5.2
+ */
+static s8 b43_phy_estimate_power_out(struct b43_wldev *dev, s8 tssi)
+{
+	struct b43_phy *phy = &dev->phy;
+	s8 dbm = 0;
+	s32 tmp;
+
+	tmp = (phy->tgt_idle_tssi - phy->cur_idle_tssi + tssi);
+
+	switch (phy->type) {
+	case B43_PHYTYPE_A:
+		tmp += 0x80;
+		tmp = limit_value(tmp, 0x00, 0xFF);
+		dbm = phy->tssi2dbm[tmp];
+		//TODO: There's a FIXME on the specs
+		break;
+	case B43_PHYTYPE_B:
+	case B43_PHYTYPE_G:
+		tmp = limit_value(tmp, 0x00, 0x3F);
+		dbm = phy->tssi2dbm[tmp];
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+
+	return dbm;
+}
+
+void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
+				     int *_bbatt, int *_rfatt)
+{
+	int rfatt = *_rfatt;
+	int bbatt = *_bbatt;
+	struct b43_txpower_lo_control *lo = dev->phy.lo_control;
+
+	/* Get baseband and radio attenuation values into their permitted ranges.
+	 * Radio attenuation affects power level 4 times as much as baseband. */
+
+	/* Range constants */
+	const int rf_min = lo->rfatt_list.min_val;
+	const int rf_max = lo->rfatt_list.max_val;
+	const int bb_min = lo->bbatt_list.min_val;
+	const int bb_max = lo->bbatt_list.max_val;
+
+	while (1) {
+		if (rfatt > rf_max && bbatt > bb_max - 4)
+			break;	/* Can not get it into ranges */
+		if (rfatt < rf_min && bbatt < bb_min + 4)
+			break;	/* Can not get it into ranges */
+		if (bbatt > bb_max && rfatt > rf_max - 1)
+			break;	/* Can not get it into ranges */
+		if (bbatt < bb_min && rfatt < rf_min + 1)
+			break;	/* Can not get it into ranges */
+
+		if (bbatt > bb_max) {
+			bbatt -= 4;
+			rfatt += 1;
+			continue;
+		}
+		if (bbatt < bb_min) {
+			bbatt += 4;
+			rfatt -= 1;
+			continue;
+		}
+		if (rfatt > rf_max) {
+			rfatt -= 1;
+			bbatt += 4;
+			continue;
+		}
+		if (rfatt < rf_min) {
+			rfatt += 1;
+			bbatt -= 4;
+			continue;
+		}
+		break;
+	}
+
+	*_rfatt = limit_value(rfatt, rf_min, rf_max);
+	*_bbatt = limit_value(bbatt, bb_min, bb_max);
+}
+
+/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
+void b43_phy_xmitpower(struct b43_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+	struct b43_phy *phy = &dev->phy;
+
+	if (phy->cur_idle_tssi == 0)
+		return;
+	if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+	    (bus->boardinfo.type == SSB_BOARD_BU4306))
+		return;
+#ifdef CONFIG_B43_DEBUG
+	if (phy->manual_txpower_control)
+		return;
+#endif
+
+	switch (phy->type) {
+	case B43_PHYTYPE_A:{
+
+			//TODO: Nothing for A PHYs yet :-/
+
+			break;
+		}
+	case B43_PHYTYPE_B:
+	case B43_PHYTYPE_G:{
+			u16 tmp;
+			s8 v0, v1, v2, v3;
+			s8 average;
+			int max_pwr;
+			int desired_pwr, estimated_pwr, pwr_adjust;
+			int rfatt_delta, bbatt_delta;
+			int rfatt, bbatt;
+			u8 tx_control;
+			unsigned long phylock_flags;
+
+			tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x0058);
+			v0 = (s8) (tmp & 0x00FF);
+			v1 = (s8) ((tmp & 0xFF00) >> 8);
+			tmp = b43_shm_read16(dev, B43_SHM_SHARED, 0x005A);
+			v2 = (s8) (tmp & 0x00FF);
+			v3 = (s8) ((tmp & 0xFF00) >> 8);
+			tmp = 0;
+
+			if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F
+			    || v3 == 0x7F) {
+				tmp =
+				    b43_shm_read16(dev, B43_SHM_SHARED, 0x0070);
+				v0 = (s8) (tmp & 0x00FF);
+				v1 = (s8) ((tmp & 0xFF00) >> 8);
+				tmp =
+				    b43_shm_read16(dev, B43_SHM_SHARED, 0x0072);
+				v2 = (s8) (tmp & 0x00FF);
+				v3 = (s8) ((tmp & 0xFF00) >> 8);
+				if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F
+				    || v3 == 0x7F)
+					return;
+				v0 = (v0 + 0x20) & 0x3F;
+				v1 = (v1 + 0x20) & 0x3F;
+				v2 = (v2 + 0x20) & 0x3F;
+				v3 = (v3 + 0x20) & 0x3F;
+				tmp = 1;
+			}
+			b43_shm_clear_tssi(dev);
+
+			average = (v0 + v1 + v2 + v3 + 2) / 4;
+
+			if (tmp
+			    && (b43_shm_read16(dev, B43_SHM_SHARED, 0x005E) &
+				0x8))
+				average -= 13;
+
+			estimated_pwr =
+			    b43_phy_estimate_power_out(dev, average);
+
+			max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg;
+			if ((dev->dev->bus->sprom.r1.
+			     boardflags_lo & B43_BFL_PACTRL)
+			    && (phy->type == B43_PHYTYPE_G))
+				max_pwr -= 0x3;
+			if (unlikely(max_pwr <= 0)) {
+				b43warn(dev->wl,
+					"Invalid max-TX-power value in SPROM.\n");
+				max_pwr = 60;	/* fake it */
+				dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr;
+			}
+
+			/*TODO:
+			   max_pwr = min(REG - dev->dev->bus->sprom.antennagain_bgphy - 0x6, max_pwr)
+			   where REG is the max power as per the regulatory domain
+			 */
+
+			/* Get desired power (in Q5.2) */
+			desired_pwr = INT_TO_Q52(phy->power_level);
+			/* And limit it. max_pwr already is Q5.2 */
+			desired_pwr = limit_value(desired_pwr, 0, max_pwr);
+			if (b43_debug(dev, B43_DBG_XMITPOWER)) {
+				b43dbg(dev->wl,
+				       "Current TX power output: " Q52_FMT
+				       " dBm, " "Desired TX power output: "
+				       Q52_FMT " dBm\n", Q52_ARG(estimated_pwr),
+				       Q52_ARG(desired_pwr));
+			}
+
+			/* Calculate the adjustment delta. */
+			pwr_adjust = desired_pwr - estimated_pwr;
+
+			/* RF attenuation delta. */
+			rfatt_delta = ((pwr_adjust + 7) / 8);
+			/* Lower attenuation => Bigger power output. Negate it. */
+			rfatt_delta = -rfatt_delta;
+
+			/* Baseband attenuation delta. */
+			bbatt_delta = pwr_adjust / 2;
+			/* Lower attenuation => Bigger power output. Negate it. */
+			bbatt_delta = -bbatt_delta;
+			/* RF att affects power level 4 times as much as
+			 * Baseband attennuation. Subtract it. */
+			bbatt_delta -= 4 * rfatt_delta;
+
+			/* So do we finally need to adjust something? */
+			if ((rfatt_delta == 0) && (bbatt_delta == 0)) {
+				b43_lo_g_ctl_mark_cur_used(dev);
+				return;
+			}
+
+			/* Calculate the new attenuation values. */
+			bbatt = phy->bbatt.att;
+			bbatt += bbatt_delta;
+			rfatt = phy->rfatt.att;
+			rfatt += rfatt_delta;
+
+			b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
+			tx_control = phy->tx_control;
+			if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
+				if (rfatt <= 1) {
+					if (tx_control == 0) {
+						tx_control =
+						    B43_TXCTL_PA2DB |
+						    B43_TXCTL_TXMIX;
+						rfatt += 2;
+						bbatt += 2;
+					} else if (dev->dev->bus->sprom.r1.
+						   boardflags_lo &
+						   B43_BFL_PACTRL) {
+						bbatt += 4 * (rfatt - 2);
+						rfatt = 2;
+					}
+				} else if (rfatt > 4 && tx_control) {
+					tx_control = 0;
+					if (bbatt < 3) {
+						rfatt -= 3;
+						bbatt += 2;
+					} else {
+						rfatt -= 2;
+						bbatt -= 2;
+					}
+				}
+			}
+			/* Save the control values */
+			phy->tx_control = tx_control;
+			b43_put_attenuation_into_ranges(dev, &bbatt, &rfatt);
+			phy->rfatt.att = rfatt;
+			phy->bbatt.att = bbatt;
+
+			/* Adjust the hardware */
+			b43_phy_lock(dev, phylock_flags);
+			b43_radio_lock(dev);
+			b43_set_txpower_g(dev, &phy->bbatt, &phy->rfatt,
+					  phy->tx_control);
+			b43_lo_g_ctl_mark_cur_used(dev);
+			b43_radio_unlock(dev);
+			b43_phy_unlock(dev, phylock_flags);
+			break;
+		}
+	default:
+		B43_WARN_ON(1);
+	}
+}
+
+static inline s32 b43_tssi2dbm_ad(s32 num, s32 den)
+{
+	if (num < 0)
+		return num / den;
+	else
+		return (num + den / 2) / den;
+}
+
+static inline
+    s8 b43_tssi2dbm_entry(s8 entry[], u8 index, s16 pab0, s16 pab1, s16 pab2)
+{
+	s32 m1, m2, f = 256, q, delta;
+	s8 i = 0;
+
+	m1 = b43_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
+	m2 = max(b43_tssi2dbm_ad(32768 + index * pab2, 256), 1);
+	do {
+		if (i > 15)
+			return -EINVAL;
+		q = b43_tssi2dbm_ad(f * 4096 -
+				    b43_tssi2dbm_ad(m2 * f, 16) * f, 2048);
+		delta = abs(q - f);
+		f = q;
+		i++;
+	} while (delta >= 2);
+	entry[index] = limit_value(b43_tssi2dbm_ad(m1 * f, 8192), -127, 128);
+	return 0;
+}
+
+/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
+int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	s16 pab0, pab1, pab2;
+	u8 idx;
+	s8 *dyn_tssi2dbm;
+
+	if (phy->type == B43_PHYTYPE_A) {
+		pab0 = (s16) (dev->dev->bus->sprom.r1.pa1b0);
+		pab1 = (s16) (dev->dev->bus->sprom.r1.pa1b1);
+		pab2 = (s16) (dev->dev->bus->sprom.r1.pa1b2);
+	} else {
+		pab0 = (s16) (dev->dev->bus->sprom.r1.pa0b0);
+		pab1 = (s16) (dev->dev->bus->sprom.r1.pa0b1);
+		pab2 = (s16) (dev->dev->bus->sprom.r1.pa0b2);
+	}
+
+	if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
+		phy->tgt_idle_tssi = 0x34;
+		phy->tssi2dbm = b43_tssi2dbm_b_table;
+		return 0;
+	}
+
+	if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
+	    pab0 != -1 && pab1 != -1 && pab2 != -1) {
+		/* The pabX values are set in SPROM. Use them. */
+		if (phy->type == B43_PHYTYPE_A) {
+			if ((s8) dev->dev->bus->sprom.r1.itssi_a != 0 &&
+			    (s8) dev->dev->bus->sprom.r1.itssi_a != -1)
+				phy->tgt_idle_tssi =
+				    (s8) (dev->dev->bus->sprom.r1.itssi_a);
+			else
+				phy->tgt_idle_tssi = 62;
+		} else {
+			if ((s8) dev->dev->bus->sprom.r1.itssi_bg != 0 &&
+			    (s8) dev->dev->bus->sprom.r1.itssi_bg != -1)
+				phy->tgt_idle_tssi =
+				    (s8) (dev->dev->bus->sprom.r1.itssi_bg);
+			else
+				phy->tgt_idle_tssi = 62;
+		}
+		dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
+		if (dyn_tssi2dbm == NULL) {
+			b43err(dev->wl, "Could not allocate memory"
+			       "for tssi2dbm table\n");
+			return -ENOMEM;
+		}
+		for (idx = 0; idx < 64; idx++)
+			if (b43_tssi2dbm_entry
+			    (dyn_tssi2dbm, idx, pab0, pab1, pab2)) {
+				phy->tssi2dbm = NULL;
+				b43err(dev->wl, "Could not generate "
+				       "tssi2dBm table\n");
+				kfree(dyn_tssi2dbm);
+				return -ENODEV;
+			}
+		phy->tssi2dbm = dyn_tssi2dbm;
+		phy->dyn_tssi_tbl = 1;
+	} else {
+		/* pabX values not set in SPROM. */
+		switch (phy->type) {
+		case B43_PHYTYPE_A:
+			/* APHY needs a generated table. */
+			phy->tssi2dbm = NULL;
+			b43err(dev->wl, "Could not generate tssi2dBm "
+			       "table (wrong SPROM info)!\n");
+			return -ENODEV;
+		case B43_PHYTYPE_B:
+			phy->tgt_idle_tssi = 0x34;
+			phy->tssi2dbm = b43_tssi2dbm_b_table;
+			break;
+		case B43_PHYTYPE_G:
+			phy->tgt_idle_tssi = 0x34;
+			phy->tssi2dbm = b43_tssi2dbm_g_table;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+int b43_phy_init(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	int err = -ENODEV;
+
+	switch (phy->type) {
+	case B43_PHYTYPE_A:
+		if (phy->rev == 2 || phy->rev == 3) {
+			b43_phy_inita(dev);
+			err = 0;
+		}
+		break;
+	case B43_PHYTYPE_B:
+		switch (phy->rev) {
+		case 2:
+			b43_phy_initb2(dev);
+			err = 0;
+			break;
+		case 4:
+			b43_phy_initb4(dev);
+			err = 0;
+			break;
+		case 5:
+			b43_phy_initb5(dev);
+			err = 0;
+			break;
+		case 6:
+			b43_phy_initb6(dev);
+			err = 0;
+			break;
+		}
+		break;
+	case B43_PHYTYPE_G:
+		b43_phy_initg(dev);
+		err = 0;
+		break;
+	}
+	if (err)
+		b43err(dev->wl, "Unknown PHYTYPE found\n");
+
+	return err;
+}
+
+void b43_set_rx_antenna(struct b43_wldev *dev, int antenna)
+{
+	struct b43_phy *phy = &dev->phy;
+	u32 hf;
+	u16 tmp;
+	int autodiv = 0;
+
+	if (antenna == B43_ANTENNA_AUTO0 || antenna == B43_ANTENNA_AUTO1)
+		autodiv = 1;
+
+	hf = b43_hf_read(dev);
+	hf &= ~B43_HF_ANTDIVHELP;
+	b43_hf_write(dev, hf);
+
+	switch (phy->type) {
+	case B43_PHYTYPE_A:
+	case B43_PHYTYPE_G:
+		tmp = b43_phy_read(dev, B43_PHY_BBANDCFG);
+		tmp &= ~B43_PHY_BBANDCFG_RXANT;
+		tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
+		    << B43_PHY_BBANDCFG_RXANT_SHIFT;
+		b43_phy_write(dev, B43_PHY_BBANDCFG, tmp);
+
+		if (autodiv) {
+			tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
+			if (antenna == B43_ANTENNA_AUTO0)
+				tmp &= ~B43_PHY_ANTDWELL_AUTODIV1;
+			else
+				tmp |= B43_PHY_ANTDWELL_AUTODIV1;
+			b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
+		}
+		if (phy->type == B43_PHYTYPE_G) {
+			tmp = b43_phy_read(dev, B43_PHY_ANTWRSETT);
+			if (autodiv)
+				tmp |= B43_PHY_ANTWRSETT_ARXDIV;
+			else
+				tmp &= ~B43_PHY_ANTWRSETT_ARXDIV;
+			b43_phy_write(dev, B43_PHY_ANTWRSETT, tmp);
+			if (phy->rev >= 2) {
+				tmp = b43_phy_read(dev, B43_PHY_OFDM61);
+				tmp |= B43_PHY_OFDM61_10;
+				b43_phy_write(dev, B43_PHY_OFDM61, tmp);
+
+				tmp =
+				    b43_phy_read(dev, B43_PHY_DIVSRCHGAINBACK);
+				tmp = (tmp & 0xFF00) | 0x15;
+				b43_phy_write(dev, B43_PHY_DIVSRCHGAINBACK,
+					      tmp);
+
+				if (phy->rev == 2) {
+					b43_phy_write(dev, B43_PHY_ADIVRELATED,
+						      8);
+				} else {
+					tmp =
+					    b43_phy_read(dev,
+							 B43_PHY_ADIVRELATED);
+					tmp = (tmp & 0xFF00) | 8;
+					b43_phy_write(dev, B43_PHY_ADIVRELATED,
+						      tmp);
+				}
+			}
+			if (phy->rev >= 6)
+				b43_phy_write(dev, B43_PHY_OFDM9B, 0xDC);
+		} else {
+			if (phy->rev < 3) {
+				tmp = b43_phy_read(dev, B43_PHY_ANTDWELL);
+				tmp = (tmp & 0xFF00) | 0x24;
+				b43_phy_write(dev, B43_PHY_ANTDWELL, tmp);
+			} else {
+				tmp = b43_phy_read(dev, B43_PHY_OFDM61);
+				tmp |= 0x10;
+				b43_phy_write(dev, B43_PHY_OFDM61, tmp);
+				if (phy->analog == 3) {
+					b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
+						      0x1D);
+					b43_phy_write(dev, B43_PHY_ADIVRELATED,
+						      8);
+				} else {
+					b43_phy_write(dev, B43_PHY_CLIPPWRDOWNT,
+						      0x3A);
+					tmp =
+					    b43_phy_read(dev,
+							 B43_PHY_ADIVRELATED);
+					tmp = (tmp & 0xFF00) | 8;
+					b43_phy_write(dev, B43_PHY_ADIVRELATED,
+						      tmp);
+				}
+			}
+		}
+		break;
+	case B43_PHYTYPE_B:
+		tmp = b43_phy_read(dev, B43_PHY_CCKBBANDCFG);
+		tmp &= ~B43_PHY_BBANDCFG_RXANT;
+		tmp |= (autodiv ? B43_ANTENNA_AUTO0 : antenna)
+		    << B43_PHY_BBANDCFG_RXANT_SHIFT;
+		b43_phy_write(dev, B43_PHY_CCKBBANDCFG, tmp);
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+
+	hf |= B43_HF_ANTDIVHELP;
+	b43_hf_write(dev, hf);
+}
+
+/* Get the freq, as it has to be written to the device. */
+static inline u16 channel2freq_bg(u8 channel)
+{
+	B43_WARN_ON(!(channel >= 1 && channel <= 14));
+
+	return b43_radio_channel_codes_bg[channel - 1];
+}
+
+/* Get the freq, as it has to be written to the device. */
+static inline u16 channel2freq_a(u8 channel)
+{
+	B43_WARN_ON(channel > 200);
+
+	return (5000 + 5 * channel);
+}
+
+void b43_radio_lock(struct b43_wldev *dev)
+{
+	u32 macctl;
+
+	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	macctl |= B43_MACCTL_RADIOLOCK;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
+	/* Commit the write and wait for the device
+	 * to exit any radio register access. */
+	b43_read32(dev, B43_MMIO_MACCTL);
+	udelay(10);
+}
+
+void b43_radio_unlock(struct b43_wldev *dev)
+{
+	u32 macctl;
+
+	/* Commit any write */
+	b43_read16(dev, B43_MMIO_PHY_VER);
+	/* unlock */
+	macctl = b43_read32(dev, B43_MMIO_MACCTL);
+	macctl &= ~B43_MACCTL_RADIOLOCK;
+	b43_write32(dev, B43_MMIO_MACCTL, macctl);
+}
+
+u16 b43_radio_read16(struct b43_wldev *dev, u16 offset)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	switch (phy->type) {
+	case B43_PHYTYPE_A:
+		offset |= 0x0040;
+		break;
+	case B43_PHYTYPE_B:
+		if (phy->radio_ver == 0x2053) {
+			if (offset < 0x70)
+				offset += 0x80;
+			else if (offset < 0x80)
+				offset += 0x70;
+		} else if (phy->radio_ver == 0x2050) {
+			offset |= 0x80;
+		} else
+			B43_WARN_ON(1);
+		break;
+	case B43_PHYTYPE_G:
+		offset |= 0x80;
+		break;
+	}
+
+	b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
+	return b43_read16(dev, B43_MMIO_RADIO_DATA_LOW);
+}
+
+void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val)
+{
+	b43_write16(dev, B43_MMIO_RADIO_CONTROL, offset);
+	mmiowb();
+	b43_write16(dev, B43_MMIO_RADIO_DATA_LOW, val);
+}
+
+static void b43_set_all_gains(struct b43_wldev *dev,
+			      s16 first, s16 second, s16 third)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 i;
+	u16 start = 0x08, end = 0x18;
+	u16 tmp;
+	u16 table;
+
+	if (phy->rev <= 1) {
+		start = 0x10;
+		end = 0x20;
+	}
+
+	table = B43_OFDMTAB_GAINX;
+	if (phy->rev <= 1)
+		table = B43_OFDMTAB_GAINX_R1;
+	for (i = 0; i < 4; i++)
+		b43_ofdmtab_write16(dev, table, i, first);
+
+	for (i = start; i < end; i++)
+		b43_ofdmtab_write16(dev, table, i, second);
+
+	if (third != -1) {
+		tmp = ((u16) third << 14) | ((u16) third << 6);
+		b43_phy_write(dev, 0x04A0,
+			      (b43_phy_read(dev, 0x04A0) & 0xBFBF) | tmp);
+		b43_phy_write(dev, 0x04A1,
+			      (b43_phy_read(dev, 0x04A1) & 0xBFBF) | tmp);
+		b43_phy_write(dev, 0x04A2,
+			      (b43_phy_read(dev, 0x04A2) & 0xBFBF) | tmp);
+	}
+	b43_dummy_transmission(dev);
+}
+
+static void b43_set_original_gains(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 i, tmp;
+	u16 table;
+	u16 start = 0x0008, end = 0x0018;
+
+	if (phy->rev <= 1) {
+		start = 0x0010;
+		end = 0x0020;
+	}
+
+	table = B43_OFDMTAB_GAINX;
+	if (phy->rev <= 1)
+		table = B43_OFDMTAB_GAINX_R1;
+	for (i = 0; i < 4; i++) {
+		tmp = (i & 0xFFFC);
+		tmp |= (i & 0x0001) << 1;
+		tmp |= (i & 0x0002) >> 1;
+
+		b43_ofdmtab_write16(dev, table, i, tmp);
+	}
+
+	for (i = start; i < end; i++)
+		b43_ofdmtab_write16(dev, table, i, i - start);
+
+	b43_phy_write(dev, 0x04A0,
+		      (b43_phy_read(dev, 0x04A0) & 0xBFBF) | 0x4040);
+	b43_phy_write(dev, 0x04A1,
+		      (b43_phy_read(dev, 0x04A1) & 0xBFBF) | 0x4040);
+	b43_phy_write(dev, 0x04A2,
+		      (b43_phy_read(dev, 0x04A2) & 0xBFBF) | 0x4000);
+	b43_dummy_transmission(dev);
+}
+
+/* Synthetic PU workaround */
+static void b43_synth_pu_workaround(struct b43_wldev *dev, u8 channel)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	might_sleep();
+
+	if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6) {
+		/* We do not need the workaround. */
+		return;
+	}
+
+	if (channel <= 10) {
+		b43_write16(dev, B43_MMIO_CHANNEL,
+			    channel2freq_bg(channel + 4));
+	} else {
+		b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(1));
+	}
+	msleep(1);
+	b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
+}
+
+u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel)
+{
+	struct b43_phy *phy = &dev->phy;
+	u8 ret = 0;
+	u16 saved, rssi, temp;
+	int i, j = 0;
+
+	saved = b43_phy_read(dev, 0x0403);
+	b43_radio_selectchannel(dev, channel, 0);
+	b43_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);
+	if (phy->aci_hw_rssi)
+		rssi = b43_phy_read(dev, 0x048A) & 0x3F;
+	else
+		rssi = saved & 0x3F;
+	/* clamp temp to signed 5bit */
+	if (rssi > 32)
+		rssi -= 64;
+	for (i = 0; i < 100; i++) {
+		temp = (b43_phy_read(dev, 0x047F) >> 8) & 0x3F;
+		if (temp > 32)
+			temp -= 64;
+		if (temp < rssi)
+			j++;
+		if (j >= 20)
+			ret = 1;
+	}
+	b43_phy_write(dev, 0x0403, saved);
+
+	return ret;
+}
+
+u8 b43_radio_aci_scan(struct b43_wldev * dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u8 ret[13];
+	unsigned int channel = phy->channel;
+	unsigned int i, j, start, end;
+	unsigned long phylock_flags;
+
+	if (!((phy->type == B43_PHYTYPE_G) && (phy->rev > 0)))
+		return 0;
+
+	b43_phy_lock(dev, phylock_flags);
+	b43_radio_lock(dev);
+	b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
+	b43_phy_write(dev, B43_PHY_G_CRS,
+		      b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF);
+	b43_set_all_gains(dev, 3, 8, 1);
+
+	start = (channel - 5 > 0) ? channel - 5 : 1;
+	end = (channel + 5 < 14) ? channel + 5 : 13;
+
+	for (i = start; i <= end; i++) {
+		if (abs(channel - i) > 2)
+			ret[i - 1] = b43_radio_aci_detect(dev, i);
+	}
+	b43_radio_selectchannel(dev, channel, 0);
+	b43_phy_write(dev, 0x0802,
+		      (b43_phy_read(dev, 0x0802) & 0xFFFC) | 0x0003);
+	b43_phy_write(dev, 0x0403, b43_phy_read(dev, 0x0403) & 0xFFF8);
+	b43_phy_write(dev, B43_PHY_G_CRS,
+		      b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000);
+	b43_set_original_gains(dev);
+	for (i = 0; i < 13; i++) {
+		if (!ret[i])
+			continue;
+		end = (i + 5 < 13) ? i + 5 : 13;
+		for (j = i; j < end; j++)
+			ret[j] = 1;
+	}
+	b43_radio_unlock(dev);
+	b43_phy_unlock(dev, phylock_flags);
+
+	return ret[channel - 1];
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val)
+{
+	b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
+	mmiowb();
+	b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val);
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset)
+{
+	u16 val;
+
+	b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset);
+	val = b43_phy_read(dev, B43_PHY_NRSSILT_DATA);
+
+	return (s16) val;
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val)
+{
+	u16 i;
+	s16 tmp;
+
+	for (i = 0; i < 64; i++) {
+		tmp = b43_nrssi_hw_read(dev, i);
+		tmp -= val;
+		tmp = limit_value(tmp, -32, 31);
+		b43_nrssi_hw_write(dev, i, tmp);
+	}
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43_nrssi_mem_update(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	s16 i, delta;
+	s32 tmp;
+
+	delta = 0x1F - phy->nrssi[0];
+	for (i = 0; i < 64; i++) {
+		tmp = (i - delta) * phy->nrssislope;
+		tmp /= 0x10000;
+		tmp += 0x3A;
+		tmp = limit_value(tmp, 0, 0x3F);
+		phy->nrssi_lt[i] = tmp;
+	}
+}
+
+static void b43_calc_nrssi_offset(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 backup[20] = { 0 };
+	s16 v47F;
+	u16 i;
+	u16 saved = 0xFFFF;
+
+	backup[0] = b43_phy_read(dev, 0x0001);
+	backup[1] = b43_phy_read(dev, 0x0811);
+	backup[2] = b43_phy_read(dev, 0x0812);
+	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
+		backup[3] = b43_phy_read(dev, 0x0814);
+		backup[4] = b43_phy_read(dev, 0x0815);
+	}
+	backup[5] = b43_phy_read(dev, 0x005A);
+	backup[6] = b43_phy_read(dev, 0x0059);
+	backup[7] = b43_phy_read(dev, 0x0058);
+	backup[8] = b43_phy_read(dev, 0x000A);
+	backup[9] = b43_phy_read(dev, 0x0003);
+	backup[10] = b43_radio_read16(dev, 0x007A);
+	backup[11] = b43_radio_read16(dev, 0x0043);
+
+	b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) & 0x7FFF);
+	b43_phy_write(dev, 0x0001,
+		      (b43_phy_read(dev, 0x0001) & 0x3FFF) | 0x4000);
+	b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C);
+	b43_phy_write(dev, 0x0812,
+		      (b43_phy_read(dev, 0x0812) & 0xFFF3) | 0x0004);
+	b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & ~(0x1 | 0x2));
+	if (phy->rev >= 6) {
+		backup[12] = b43_phy_read(dev, 0x002E);
+		backup[13] = b43_phy_read(dev, 0x002F);
+		backup[14] = b43_phy_read(dev, 0x080F);
+		backup[15] = b43_phy_read(dev, 0x0810);
+		backup[16] = b43_phy_read(dev, 0x0801);
+		backup[17] = b43_phy_read(dev, 0x0060);
+		backup[18] = b43_phy_read(dev, 0x0014);
+		backup[19] = b43_phy_read(dev, 0x0478);
+
+		b43_phy_write(dev, 0x002E, 0);
+		b43_phy_write(dev, 0x002F, 0);
+		b43_phy_write(dev, 0x080F, 0);
+		b43_phy_write(dev, 0x0810, 0);
+		b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) | 0x0100);
+		b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) | 0x0040);
+		b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) | 0x0040);
+		b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) | 0x0200);
+	}
+	b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0070);
+	b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0080);
+	udelay(30);
+
+	v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+	if (v47F >= 0x20)
+		v47F -= 0x40;
+	if (v47F == 31) {
+		for (i = 7; i >= 4; i--) {
+			b43_radio_write16(dev, 0x007B, i);
+			udelay(20);
+			v47F =
+			    (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+			if (v47F >= 0x20)
+				v47F -= 0x40;
+			if (v47F < 31 && saved == 0xFFFF)
+				saved = i;
+		}
+		if (saved == 0xFFFF)
+			saved = 4;
+	} else {
+		b43_radio_write16(dev, 0x007A,
+				  b43_radio_read16(dev, 0x007A) & 0x007F);
+		if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
+			b43_phy_write(dev, 0x0814,
+				      b43_phy_read(dev, 0x0814) | 0x0001);
+			b43_phy_write(dev, 0x0815,
+				      b43_phy_read(dev, 0x0815) & 0xFFFE);
+		}
+		b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C);
+		b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x000C);
+		b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x0030);
+		b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x0030);
+		b43_phy_write(dev, 0x005A, 0x0480);
+		b43_phy_write(dev, 0x0059, 0x0810);
+		b43_phy_write(dev, 0x0058, 0x000D);
+		if (phy->rev == 0) {
+			b43_phy_write(dev, 0x0003, 0x0122);
+		} else {
+			b43_phy_write(dev, 0x000A, b43_phy_read(dev, 0x000A)
+				      | 0x2000);
+		}
+		if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
+			b43_phy_write(dev, 0x0814,
+				      b43_phy_read(dev, 0x0814) | 0x0004);
+			b43_phy_write(dev, 0x0815,
+				      b43_phy_read(dev, 0x0815) & 0xFFFB);
+		}
+		b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) & 0xFF9F)
+			      | 0x0040);
+		b43_radio_write16(dev, 0x007A,
+				  b43_radio_read16(dev, 0x007A) | 0x000F);
+		b43_set_all_gains(dev, 3, 0, 1);
+		b43_radio_write16(dev, 0x0043, (b43_radio_read16(dev, 0x0043)
+						& 0x00F0) | 0x000F);
+		udelay(30);
+		v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+		if (v47F >= 0x20)
+			v47F -= 0x40;
+		if (v47F == -32) {
+			for (i = 0; i < 4; i++) {
+				b43_radio_write16(dev, 0x007B, i);
+				udelay(20);
+				v47F =
+				    (s16) ((b43_phy_read(dev, 0x047F) >> 8) &
+					   0x003F);
+				if (v47F >= 0x20)
+					v47F -= 0x40;
+				if (v47F > -31 && saved == 0xFFFF)
+					saved = i;
+			}
+			if (saved == 0xFFFF)
+				saved = 3;
+		} else
+			saved = 0;
+	}
+	b43_radio_write16(dev, 0x007B, saved);
+
+	if (phy->rev >= 6) {
+		b43_phy_write(dev, 0x002E, backup[12]);
+		b43_phy_write(dev, 0x002F, backup[13]);
+		b43_phy_write(dev, 0x080F, backup[14]);
+		b43_phy_write(dev, 0x0810, backup[15]);
+	}
+	if (phy->rev != 1) {	/* Not in specs, but needed to prevent PPC machine check */
+		b43_phy_write(dev, 0x0814, backup[3]);
+		b43_phy_write(dev, 0x0815, backup[4]);
+	}
+	b43_phy_write(dev, 0x005A, backup[5]);
+	b43_phy_write(dev, 0x0059, backup[6]);
+	b43_phy_write(dev, 0x0058, backup[7]);
+	b43_phy_write(dev, 0x000A, backup[8]);
+	b43_phy_write(dev, 0x0003, backup[9]);
+	b43_radio_write16(dev, 0x0043, backup[11]);
+	b43_radio_write16(dev, 0x007A, backup[10]);
+	b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x1 | 0x2);
+	b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) | 0x8000);
+	b43_set_original_gains(dev);
+	if (phy->rev >= 6) {
+		b43_phy_write(dev, 0x0801, backup[16]);
+		b43_phy_write(dev, 0x0060, backup[17]);
+		b43_phy_write(dev, 0x0014, backup[18]);
+		b43_phy_write(dev, 0x0478, backup[19]);
+	}
+	b43_phy_write(dev, 0x0001, backup[0]);
+	b43_phy_write(dev, 0x0812, backup[2]);
+	b43_phy_write(dev, 0x0811, backup[1]);
+}
+
+void b43_calc_nrssi_slope(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 backup[18] = { 0 };
+	u16 tmp;
+	s16 nrssi0, nrssi1;
+
+	switch (phy->type) {
+	case B43_PHYTYPE_B:
+		backup[0] = b43_radio_read16(dev, 0x007A);
+		backup[1] = b43_radio_read16(dev, 0x0052);
+		backup[2] = b43_radio_read16(dev, 0x0043);
+		backup[3] = b43_phy_read(dev, 0x0030);
+		backup[4] = b43_phy_read(dev, 0x0026);
+		backup[5] = b43_phy_read(dev, 0x0015);
+		backup[6] = b43_phy_read(dev, 0x002A);
+		backup[7] = b43_phy_read(dev, 0x0020);
+		backup[8] = b43_phy_read(dev, 0x005A);
+		backup[9] = b43_phy_read(dev, 0x0059);
+		backup[10] = b43_phy_read(dev, 0x0058);
+		backup[11] = b43_read16(dev, 0x03E2);
+		backup[12] = b43_read16(dev, 0x03E6);
+		backup[13] = b43_read16(dev, B43_MMIO_CHANNEL_EXT);
+
+		tmp = b43_radio_read16(dev, 0x007A);
+		tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
+		b43_radio_write16(dev, 0x007A, tmp);
+		b43_phy_write(dev, 0x0030, 0x00FF);
+		b43_write16(dev, 0x03EC, 0x7F7F);
+		b43_phy_write(dev, 0x0026, 0x0000);
+		b43_phy_write(dev, 0x0015, b43_phy_read(dev, 0x0015) | 0x0020);
+		b43_phy_write(dev, 0x002A, 0x08A3);
+		b43_radio_write16(dev, 0x007A,
+				  b43_radio_read16(dev, 0x007A) | 0x0080);
+
+		nrssi0 = (s16) b43_phy_read(dev, 0x0027);
+		b43_radio_write16(dev, 0x007A,
+				  b43_radio_read16(dev, 0x007A) & 0x007F);
+		if (phy->rev >= 2) {
+			b43_write16(dev, 0x03E6, 0x0040);
+		} else if (phy->rev == 0) {
+			b43_write16(dev, 0x03E6, 0x0122);
+		} else {
+			b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+				    b43_read16(dev,
+					       B43_MMIO_CHANNEL_EXT) & 0x2000);
+		}
+		b43_phy_write(dev, 0x0020, 0x3F3F);
+		b43_phy_write(dev, 0x0015, 0xF330);
+		b43_radio_write16(dev, 0x005A, 0x0060);
+		b43_radio_write16(dev, 0x0043,
+				  b43_radio_read16(dev, 0x0043) & 0x00F0);
+		b43_phy_write(dev, 0x005A, 0x0480);
+		b43_phy_write(dev, 0x0059, 0x0810);
+		b43_phy_write(dev, 0x0058, 0x000D);
+		udelay(20);
+
+		nrssi1 = (s16) b43_phy_read(dev, 0x0027);
+		b43_phy_write(dev, 0x0030, backup[3]);
+		b43_radio_write16(dev, 0x007A, backup[0]);
+		b43_write16(dev, 0x03E2, backup[11]);
+		b43_phy_write(dev, 0x0026, backup[4]);
+		b43_phy_write(dev, 0x0015, backup[5]);
+		b43_phy_write(dev, 0x002A, backup[6]);
+		b43_synth_pu_workaround(dev, phy->channel);
+		if (phy->rev != 0)
+			b43_write16(dev, 0x03F4, backup[13]);
+
+		b43_phy_write(dev, 0x0020, backup[7]);
+		b43_phy_write(dev, 0x005A, backup[8]);
+		b43_phy_write(dev, 0x0059, backup[9]);
+		b43_phy_write(dev, 0x0058, backup[10]);
+		b43_radio_write16(dev, 0x0052, backup[1]);
+		b43_radio_write16(dev, 0x0043, backup[2]);
+
+		if (nrssi0 == nrssi1)
+			phy->nrssislope = 0x00010000;
+		else
+			phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
+
+		if (nrssi0 <= -4) {
+			phy->nrssi[0] = nrssi0;
+			phy->nrssi[1] = nrssi1;
+		}
+		break;
+	case B43_PHYTYPE_G:
+		if (phy->radio_rev >= 9)
+			return;
+		if (phy->radio_rev == 8)
+			b43_calc_nrssi_offset(dev);
+
+		b43_phy_write(dev, B43_PHY_G_CRS,
+			      b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF);
+		b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
+		backup[7] = b43_read16(dev, 0x03E2);
+		b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000);
+		backup[0] = b43_radio_read16(dev, 0x007A);
+		backup[1] = b43_radio_read16(dev, 0x0052);
+		backup[2] = b43_radio_read16(dev, 0x0043);
+		backup[3] = b43_phy_read(dev, 0x0015);
+		backup[4] = b43_phy_read(dev, 0x005A);
+		backup[5] = b43_phy_read(dev, 0x0059);
+		backup[6] = b43_phy_read(dev, 0x0058);
+		backup[8] = b43_read16(dev, 0x03E6);
+		backup[9] = b43_read16(dev, B43_MMIO_CHANNEL_EXT);
+		if (phy->rev >= 3) {
+			backup[10] = b43_phy_read(dev, 0x002E);
+			backup[11] = b43_phy_read(dev, 0x002F);
+			backup[12] = b43_phy_read(dev, 0x080F);
+			backup[13] = b43_phy_read(dev, B43_PHY_G_LO_CONTROL);
+			backup[14] = b43_phy_read(dev, 0x0801);
+			backup[15] = b43_phy_read(dev, 0x0060);
+			backup[16] = b43_phy_read(dev, 0x0014);
+			backup[17] = b43_phy_read(dev, 0x0478);
+			b43_phy_write(dev, 0x002E, 0);
+			b43_phy_write(dev, B43_PHY_G_LO_CONTROL, 0);
+			switch (phy->rev) {
+			case 4:
+			case 6:
+			case 7:
+				b43_phy_write(dev, 0x0478,
+					      b43_phy_read(dev, 0x0478)
+					      | 0x0100);
+				b43_phy_write(dev, 0x0801,
+					      b43_phy_read(dev, 0x0801)
+					      | 0x0040);
+				break;
+			case 3:
+			case 5:
+				b43_phy_write(dev, 0x0801,
+					      b43_phy_read(dev, 0x0801)
+					      & 0xFFBF);
+				break;
+			}
+			b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060)
+				      | 0x0040);
+			b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014)
+				      | 0x0200);
+		}
+		b43_radio_write16(dev, 0x007A,
+				  b43_radio_read16(dev, 0x007A) | 0x0070);
+		b43_set_all_gains(dev, 0, 8, 0);
+		b43_radio_write16(dev, 0x007A,
+				  b43_radio_read16(dev, 0x007A) & 0x00F7);
+		if (phy->rev >= 2) {
+			b43_phy_write(dev, 0x0811,
+				      (b43_phy_read(dev, 0x0811) & 0xFFCF) |
+				      0x0030);
+			b43_phy_write(dev, 0x0812,
+				      (b43_phy_read(dev, 0x0812) & 0xFFCF) |
+				      0x0010);
+		}
+		b43_radio_write16(dev, 0x007A,
+				  b43_radio_read16(dev, 0x007A) | 0x0080);
+		udelay(20);
+
+		nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+		if (nrssi0 >= 0x0020)
+			nrssi0 -= 0x0040;
+
+		b43_radio_write16(dev, 0x007A,
+				  b43_radio_read16(dev, 0x007A) & 0x007F);
+		if (phy->rev >= 2) {
+			b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003)
+						    & 0xFF9F) | 0x0040);
+		}
+
+		b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+			    b43_read16(dev, B43_MMIO_CHANNEL_EXT)
+			    | 0x2000);
+		b43_radio_write16(dev, 0x007A,
+				  b43_radio_read16(dev, 0x007A) | 0x000F);
+		b43_phy_write(dev, 0x0015, 0xF330);
+		if (phy->rev >= 2) {
+			b43_phy_write(dev, 0x0812,
+				      (b43_phy_read(dev, 0x0812) & 0xFFCF) |
+				      0x0020);
+			b43_phy_write(dev, 0x0811,
+				      (b43_phy_read(dev, 0x0811) & 0xFFCF) |
+				      0x0020);
+		}
+
+		b43_set_all_gains(dev, 3, 0, 1);
+		if (phy->radio_rev == 8) {
+			b43_radio_write16(dev, 0x0043, 0x001F);
+		} else {
+			tmp = b43_radio_read16(dev, 0x0052) & 0xFF0F;
+			b43_radio_write16(dev, 0x0052, tmp | 0x0060);
+			tmp = b43_radio_read16(dev, 0x0043) & 0xFFF0;
+			b43_radio_write16(dev, 0x0043, tmp | 0x0009);
+		}
+		b43_phy_write(dev, 0x005A, 0x0480);
+		b43_phy_write(dev, 0x0059, 0x0810);
+		b43_phy_write(dev, 0x0058, 0x000D);
+		udelay(20);
+		nrssi1 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
+		if (nrssi1 >= 0x0020)
+			nrssi1 -= 0x0040;
+		if (nrssi0 == nrssi1)
+			phy->nrssislope = 0x00010000;
+		else
+			phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
+		if (nrssi0 >= -4) {
+			phy->nrssi[0] = nrssi1;
+			phy->nrssi[1] = nrssi0;
+		}
+		if (phy->rev >= 3) {
+			b43_phy_write(dev, 0x002E, backup[10]);
+			b43_phy_write(dev, 0x002F, backup[11]);
+			b43_phy_write(dev, 0x080F, backup[12]);
+			b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]);
+		}
+		if (phy->rev >= 2) {
+			b43_phy_write(dev, 0x0812,
+				      b43_phy_read(dev, 0x0812) & 0xFFCF);
+			b43_phy_write(dev, 0x0811,
+				      b43_phy_read(dev, 0x0811) & 0xFFCF);
+		}
+
+		b43_radio_write16(dev, 0x007A, backup[0]);
+		b43_radio_write16(dev, 0x0052, backup[1]);
+		b43_radio_write16(dev, 0x0043, backup[2]);
+		b43_write16(dev, 0x03E2, backup[7]);
+		b43_write16(dev, 0x03E6, backup[8]);
+		b43_write16(dev, B43_MMIO_CHANNEL_EXT, backup[9]);
+		b43_phy_write(dev, 0x0015, backup[3]);
+		b43_phy_write(dev, 0x005A, backup[4]);
+		b43_phy_write(dev, 0x0059, backup[5]);
+		b43_phy_write(dev, 0x0058, backup[6]);
+		b43_synth_pu_workaround(dev, phy->channel);
+		b43_phy_write(dev, 0x0802,
+			      b43_phy_read(dev, 0x0802) | (0x0001 | 0x0002));
+		b43_set_original_gains(dev);
+		b43_phy_write(dev, B43_PHY_G_CRS,
+			      b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000);
+		if (phy->rev >= 3) {
+			b43_phy_write(dev, 0x0801, backup[14]);
+			b43_phy_write(dev, 0x0060, backup[15]);
+			b43_phy_write(dev, 0x0014, backup[16]);
+			b43_phy_write(dev, 0x0478, backup[17]);
+		}
+		b43_nrssi_mem_update(dev);
+		b43_calc_nrssi_threshold(dev);
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+}
+
+void b43_calc_nrssi_threshold(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	s32 threshold;
+	s32 a, b;
+	s16 tmp16;
+	u16 tmp_u16;
+
+	switch (phy->type) {
+	case B43_PHYTYPE_B:{
+			if (phy->radio_ver != 0x2050)
+				return;
+			if (!
+			    (dev->dev->bus->sprom.r1.
+			     boardflags_lo & B43_BFL_RSSI))
+				return;
+
+			if (phy->radio_rev >= 6) {
+				threshold =
+				    (phy->nrssi[1] - phy->nrssi[0]) * 32;
+				threshold += 20 * (phy->nrssi[0] + 1);
+				threshold /= 40;
+			} else
+				threshold = phy->nrssi[1] - 5;
+
+			threshold = limit_value(threshold, 0, 0x3E);
+			b43_phy_read(dev, 0x0020);	/* dummy read */
+			b43_phy_write(dev, 0x0020,
+				      (((u16) threshold) << 8) | 0x001C);
+
+			if (phy->radio_rev >= 6) {
+				b43_phy_write(dev, 0x0087, 0x0E0D);
+				b43_phy_write(dev, 0x0086, 0x0C0B);
+				b43_phy_write(dev, 0x0085, 0x0A09);
+				b43_phy_write(dev, 0x0084, 0x0808);
+				b43_phy_write(dev, 0x0083, 0x0808);
+				b43_phy_write(dev, 0x0082, 0x0604);
+				b43_phy_write(dev, 0x0081, 0x0302);
+				b43_phy_write(dev, 0x0080, 0x0100);
+			}
+			break;
+		}
+	case B43_PHYTYPE_G:
+		if (!phy->gmode ||
+		    !(dev->dev->bus->sprom.r1.boardflags_lo & B43_BFL_RSSI)) {
+			tmp16 = b43_nrssi_hw_read(dev, 0x20);
+			if (tmp16 >= 0x20)
+				tmp16 -= 0x40;
+			if (tmp16 < 3) {
+				b43_phy_write(dev, 0x048A,
+					      (b43_phy_read(dev, 0x048A)
+					       & 0xF000) | 0x09EB);
+			} else {
+				b43_phy_write(dev, 0x048A,
+					      (b43_phy_read(dev, 0x048A)
+					       & 0xF000) | 0x0AED);
+			}
+		} else {
+			if (phy->interfmode == B43_INTERFMODE_NONWLAN) {
+				a = 0xE;
+				b = 0xA;
+			} else if (!phy->aci_wlan_automatic && phy->aci_enable) {
+				a = 0x13;
+				b = 0x12;
+			} else {
+				a = 0xE;
+				b = 0x11;
+			}
+
+			a = a * (phy->nrssi[1] - phy->nrssi[0]);
+			a += (phy->nrssi[0] << 6);
+			if (a < 32)
+				a += 31;
+			else
+				a += 32;
+			a = a >> 6;
+			a = limit_value(a, -31, 31);
+
+			b = b * (phy->nrssi[1] - phy->nrssi[0]);
+			b += (phy->nrssi[0] << 6);
+			if (b < 32)
+				b += 31;
+			else
+				b += 32;
+			b = b >> 6;
+			b = limit_value(b, -31, 31);
+
+			tmp_u16 = b43_phy_read(dev, 0x048A) & 0xF000;
+			tmp_u16 |= ((u32) b & 0x0000003F);
+			tmp_u16 |= (((u32) a & 0x0000003F) << 6);
+			b43_phy_write(dev, 0x048A, tmp_u16);
+		}
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+}
+
+/* Stack implementation to save/restore values from the
+ * interference mitigation code.
+ * It is save to restore values in random order.
+ */
+static void _stack_save(u32 * _stackptr, size_t * stackidx,
+			u8 id, u16 offset, u16 value)
+{
+	u32 *stackptr = &(_stackptr[*stackidx]);
+
+	B43_WARN_ON(offset & 0xF000);
+	B43_WARN_ON(id & 0xF0);
+	*stackptr = offset;
+	*stackptr |= ((u32) id) << 12;
+	*stackptr |= ((u32) value) << 16;
+	(*stackidx)++;
+	B43_WARN_ON(*stackidx >= B43_INTERFSTACK_SIZE);
+}
+
+static u16 _stack_restore(u32 * stackptr, u8 id, u16 offset)
+{
+	size_t i;
+
+	B43_WARN_ON(offset & 0xF000);
+	B43_WARN_ON(id & 0xF0);
+	for (i = 0; i < B43_INTERFSTACK_SIZE; i++, stackptr++) {
+		if ((*stackptr & 0x00000FFF) != offset)
+			continue;
+		if (((*stackptr & 0x0000F000) >> 12) != id)
+			continue;
+		return ((*stackptr & 0xFFFF0000) >> 16);
+	}
+	B43_WARN_ON(1);
+
+	return 0;
+}
+
+#define phy_stacksave(offset)					\
+	do {							\
+		_stack_save(stack, &stackidx, 0x1, (offset),	\
+			    b43_phy_read(dev, (offset)));	\
+	} while (0)
+#define phy_stackrestore(offset)				\
+	do {							\
+		b43_phy_write(dev, (offset),		\
+				  _stack_restore(stack, 0x1,	\
+						 (offset)));	\
+	} while (0)
+#define radio_stacksave(offset)						\
+	do {								\
+		_stack_save(stack, &stackidx, 0x2, (offset),		\
+			    b43_radio_read16(dev, (offset)));	\
+	} while (0)
+#define radio_stackrestore(offset)					\
+	do {								\
+		b43_radio_write16(dev, (offset),			\
+				      _stack_restore(stack, 0x2,	\
+						     (offset)));	\
+	} while (0)
+#define ofdmtab_stacksave(table, offset)			\
+	do {							\
+		_stack_save(stack, &stackidx, 0x3, (offset)|(table),	\
+			    b43_ofdmtab_read16(dev, (table), (offset)));	\
+	} while (0)
+#define ofdmtab_stackrestore(table, offset)			\
+	do {							\
+		b43_ofdmtab_write16(dev, (table),	(offset),	\
+				  _stack_restore(stack, 0x3,	\
+						 (offset)|(table)));	\
+	} while (0)
+
+static void
+b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 tmp, flipped;
+	size_t stackidx = 0;
+	u32 *stack = phy->interfstack;
+
+	switch (mode) {
+	case B43_INTERFMODE_NONWLAN:
+		if (phy->rev != 1) {
+			b43_phy_write(dev, 0x042B,
+				      b43_phy_read(dev, 0x042B) | 0x0800);
+			b43_phy_write(dev, B43_PHY_G_CRS,
+				      b43_phy_read(dev,
+						   B43_PHY_G_CRS) & ~0x4000);
+			break;
+		}
+		radio_stacksave(0x0078);
+		tmp = (b43_radio_read16(dev, 0x0078) & 0x001E);
+		flipped = flip_4bit(tmp);
+		if (flipped < 10 && flipped >= 8)
+			flipped = 7;
+		else if (flipped >= 10)
+			flipped -= 3;
+		flipped = flip_4bit(flipped);
+		flipped = (flipped << 1) | 0x0020;
+		b43_radio_write16(dev, 0x0078, flipped);
+
+		b43_calc_nrssi_threshold(dev);
+
+		phy_stacksave(0x0406);
+		b43_phy_write(dev, 0x0406, 0x7E28);
+
+		b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x0800);
+		b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
+			      b43_phy_read(dev,
+					   B43_PHY_RADIO_BITFIELD) | 0x1000);
+
+		phy_stacksave(0x04A0);
+		b43_phy_write(dev, 0x04A0,
+			      (b43_phy_read(dev, 0x04A0) & 0xC0C0) | 0x0008);
+		phy_stacksave(0x04A1);
+		b43_phy_write(dev, 0x04A1,
+			      (b43_phy_read(dev, 0x04A1) & 0xC0C0) | 0x0605);
+		phy_stacksave(0x04A2);
+		b43_phy_write(dev, 0x04A2,
+			      (b43_phy_read(dev, 0x04A2) & 0xC0C0) | 0x0204);
+		phy_stacksave(0x04A8);
+		b43_phy_write(dev, 0x04A8,
+			      (b43_phy_read(dev, 0x04A8) & 0xC0C0) | 0x0803);
+		phy_stacksave(0x04AB);
+		b43_phy_write(dev, 0x04AB,
+			      (b43_phy_read(dev, 0x04AB) & 0xC0C0) | 0x0605);
+
+		phy_stacksave(0x04A7);
+		b43_phy_write(dev, 0x04A7, 0x0002);
+		phy_stacksave(0x04A3);
+		b43_phy_write(dev, 0x04A3, 0x287A);
+		phy_stacksave(0x04A9);
+		b43_phy_write(dev, 0x04A9, 0x2027);
+		phy_stacksave(0x0493);
+		b43_phy_write(dev, 0x0493, 0x32F5);
+		phy_stacksave(0x04AA);
+		b43_phy_write(dev, 0x04AA, 0x2027);
+		phy_stacksave(0x04AC);
+		b43_phy_write(dev, 0x04AC, 0x32F5);
+		break;
+	case B43_INTERFMODE_MANUALWLAN:
+		if (b43_phy_read(dev, 0x0033) & 0x0800)
+			break;
+
+		phy->aci_enable = 1;
+
+		phy_stacksave(B43_PHY_RADIO_BITFIELD);
+		phy_stacksave(B43_PHY_G_CRS);
+		if (phy->rev < 2) {
+			phy_stacksave(0x0406);
+		} else {
+			phy_stacksave(0x04C0);
+			phy_stacksave(0x04C1);
+		}
+		phy_stacksave(0x0033);
+		phy_stacksave(0x04A7);
+		phy_stacksave(0x04A3);
+		phy_stacksave(0x04A9);
+		phy_stacksave(0x04AA);
+		phy_stacksave(0x04AC);
+		phy_stacksave(0x0493);
+		phy_stacksave(0x04A1);
+		phy_stacksave(0x04A0);
+		phy_stacksave(0x04A2);
+		phy_stacksave(0x048A);
+		phy_stacksave(0x04A8);
+		phy_stacksave(0x04AB);
+		if (phy->rev == 2) {
+			phy_stacksave(0x04AD);
+			phy_stacksave(0x04AE);
+		} else if (phy->rev >= 3) {
+			phy_stacksave(0x04AD);
+			phy_stacksave(0x0415);
+			phy_stacksave(0x0416);
+			phy_stacksave(0x0417);
+			ofdmtab_stacksave(0x1A00, 0x2);
+			ofdmtab_stacksave(0x1A00, 0x3);
+		}
+		phy_stacksave(0x042B);
+		phy_stacksave(0x048C);
+
+		b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
+			      b43_phy_read(dev, B43_PHY_RADIO_BITFIELD)
+			      & ~0x1000);
+		b43_phy_write(dev, B43_PHY_G_CRS,
+			      (b43_phy_read(dev, B43_PHY_G_CRS)
+			       & 0xFFFC) | 0x0002);
+
+		b43_phy_write(dev, 0x0033, 0x0800);
+		b43_phy_write(dev, 0x04A3, 0x2027);
+		b43_phy_write(dev, 0x04A9, 0x1CA8);
+		b43_phy_write(dev, 0x0493, 0x287A);
+		b43_phy_write(dev, 0x04AA, 0x1CA8);
+		b43_phy_write(dev, 0x04AC, 0x287A);
+
+		b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
+					    & 0xFFC0) | 0x001A);
+		b43_phy_write(dev, 0x04A7, 0x000D);
+
+		if (phy->rev < 2) {
+			b43_phy_write(dev, 0x0406, 0xFF0D);
+		} else if (phy->rev == 2) {
+			b43_phy_write(dev, 0x04C0, 0xFFFF);
+			b43_phy_write(dev, 0x04C1, 0x00A9);
+		} else {
+			b43_phy_write(dev, 0x04C0, 0x00C1);
+			b43_phy_write(dev, 0x04C1, 0x0059);
+		}
+
+		b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
+					    & 0xC0FF) | 0x1800);
+		b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
+					    & 0xFFC0) | 0x0015);
+		b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+					    & 0xCFFF) | 0x1000);
+		b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+					    & 0xF0FF) | 0x0A00);
+		b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+					    & 0xCFFF) | 0x1000);
+		b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+					    & 0xF0FF) | 0x0800);
+		b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+					    & 0xFFCF) | 0x0010);
+		b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
+					    & 0xFFF0) | 0x0005);
+		b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+					    & 0xFFCF) | 0x0010);
+		b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
+					    & 0xFFF0) | 0x0006);
+		b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
+					    & 0xF0FF) | 0x0800);
+		b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
+					    & 0xF0FF) | 0x0500);
+		b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
+					    & 0xFFF0) | 0x000B);
+
+		if (phy->rev >= 3) {
+			b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A)
+				      & ~0x8000);
+			b43_phy_write(dev, 0x0415, (b43_phy_read(dev, 0x0415)
+						    & 0x8000) | 0x36D8);
+			b43_phy_write(dev, 0x0416, (b43_phy_read(dev, 0x0416)
+						    & 0x8000) | 0x36D8);
+			b43_phy_write(dev, 0x0417, (b43_phy_read(dev, 0x0417)
+						    & 0xFE00) | 0x016D);
+		} else {
+			b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A)
+				      | 0x1000);
+			b43_phy_write(dev, 0x048A, (b43_phy_read(dev, 0x048A)
+						    & 0x9FFF) | 0x2000);
+			b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ACIW);
+		}
+		if (phy->rev >= 2) {
+			b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B)
+				      | 0x0800);
+		}
+		b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
+					    & 0xF0FF) | 0x0200);
+		if (phy->rev == 2) {
+			b43_phy_write(dev, 0x04AE, (b43_phy_read(dev, 0x04AE)
+						    & 0xFF00) | 0x007F);
+			b43_phy_write(dev, 0x04AD, (b43_phy_read(dev, 0x04AD)
+						    & 0x00FF) | 0x1300);
+		} else if (phy->rev >= 6) {
+			b43_ofdmtab_write16(dev, 0x1A00, 0x3, 0x007F);
+			b43_ofdmtab_write16(dev, 0x1A00, 0x2, 0x007F);
+			b43_phy_write(dev, 0x04AD, b43_phy_read(dev, 0x04AD)
+				      & 0x00FF);
+		}
+		b43_calc_nrssi_slope(dev);
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+}
+
+static void
+b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode)
+{
+	struct b43_phy *phy = &dev->phy;
+	u32 *stack = phy->interfstack;
+
+	switch (mode) {
+	case B43_INTERFMODE_NONWLAN:
+		if (phy->rev != 1) {
+			b43_phy_write(dev, 0x042B,
+				      b43_phy_read(dev, 0x042B) & ~0x0800);
+			b43_phy_write(dev, B43_PHY_G_CRS,
+				      b43_phy_read(dev,
+						   B43_PHY_G_CRS) | 0x4000);
+			break;
+		}
+		radio_stackrestore(0x0078);
+		b43_calc_nrssi_threshold(dev);
+		phy_stackrestore(0x0406);
+		b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) & ~0x0800);
+		if (!dev->bad_frames_preempt) {
+			b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
+				      b43_phy_read(dev, B43_PHY_RADIO_BITFIELD)
+				      & ~(1 << 11));
+		}
+		b43_phy_write(dev, B43_PHY_G_CRS,
+			      b43_phy_read(dev, B43_PHY_G_CRS) | 0x4000);
+		phy_stackrestore(0x04A0);
+		phy_stackrestore(0x04A1);
+		phy_stackrestore(0x04A2);
+		phy_stackrestore(0x04A8);
+		phy_stackrestore(0x04AB);
+		phy_stackrestore(0x04A7);
+		phy_stackrestore(0x04A3);
+		phy_stackrestore(0x04A9);
+		phy_stackrestore(0x0493);
+		phy_stackrestore(0x04AA);
+		phy_stackrestore(0x04AC);
+		break;
+	case B43_INTERFMODE_MANUALWLAN:
+		if (!(b43_phy_read(dev, 0x0033) & 0x0800))
+			break;
+
+		phy->aci_enable = 0;
+
+		phy_stackrestore(B43_PHY_RADIO_BITFIELD);
+		phy_stackrestore(B43_PHY_G_CRS);
+		phy_stackrestore(0x0033);
+		phy_stackrestore(0x04A3);
+		phy_stackrestore(0x04A9);
+		phy_stackrestore(0x0493);
+		phy_stackrestore(0x04AA);
+		phy_stackrestore(0x04AC);
+		phy_stackrestore(0x04A0);
+		phy_stackrestore(0x04A7);
+		if (phy->rev >= 2) {
+			phy_stackrestore(0x04C0);
+			phy_stackrestore(0x04C1);
+		} else
+			phy_stackrestore(0x0406);
+		phy_stackrestore(0x04A1);
+		phy_stackrestore(0x04AB);
+		phy_stackrestore(0x04A8);
+		if (phy->rev == 2) {
+			phy_stackrestore(0x04AD);
+			phy_stackrestore(0x04AE);
+		} else if (phy->rev >= 3) {
+			phy_stackrestore(0x04AD);
+			phy_stackrestore(0x0415);
+			phy_stackrestore(0x0416);
+			phy_stackrestore(0x0417);
+			ofdmtab_stackrestore(0x1A00, 0x2);
+			ofdmtab_stackrestore(0x1A00, 0x3);
+		}
+		phy_stackrestore(0x04A2);
+		phy_stackrestore(0x048A);
+		phy_stackrestore(0x042B);
+		phy_stackrestore(0x048C);
+		b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_ACIW);
+		b43_calc_nrssi_slope(dev);
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+}
+
+#undef phy_stacksave
+#undef phy_stackrestore
+#undef radio_stacksave
+#undef radio_stackrestore
+#undef ofdmtab_stacksave
+#undef ofdmtab_stackrestore
+
+int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode)
+{
+	struct b43_phy *phy = &dev->phy;
+	int currentmode;
+
+	if ((phy->type != B43_PHYTYPE_G) || (phy->rev == 0) || (!phy->gmode))
+		return -ENODEV;
+
+	phy->aci_wlan_automatic = 0;
+	switch (mode) {
+	case B43_INTERFMODE_AUTOWLAN:
+		phy->aci_wlan_automatic = 1;
+		if (phy->aci_enable)
+			mode = B43_INTERFMODE_MANUALWLAN;
+		else
+			mode = B43_INTERFMODE_NONE;
+		break;
+	case B43_INTERFMODE_NONE:
+	case B43_INTERFMODE_NONWLAN:
+	case B43_INTERFMODE_MANUALWLAN:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	currentmode = phy->interfmode;
+	if (currentmode == mode)
+		return 0;
+	if (currentmode != B43_INTERFMODE_NONE)
+		b43_radio_interference_mitigation_disable(dev, currentmode);
+
+	if (mode == B43_INTERFMODE_NONE) {
+		phy->aci_enable = 0;
+		phy->aci_hw_rssi = 0;
+	} else
+		b43_radio_interference_mitigation_enable(dev, mode);
+	phy->interfmode = mode;
+
+	return 0;
+}
+
+static u16 b43_radio_core_calibration_value(struct b43_wldev *dev)
+{
+	u16 reg, index, ret;
+
+	static const u8 rcc_table[] = {
+		0x02, 0x03, 0x01, 0x0F,
+		0x06, 0x07, 0x05, 0x0F,
+		0x0A, 0x0B, 0x09, 0x0F,
+		0x0E, 0x0F, 0x0D, 0x0F,
+	};
+
+	reg = b43_radio_read16(dev, 0x60);
+	index = (reg & 0x001E) >> 1;
+	ret = rcc_table[index] << 1;
+	ret |= (reg & 0x0001);
+	ret |= 0x0020;
+
+	return ret;
+}
+
+#define LPD(L, P, D)	(((L) << 2) | ((P) << 1) | ((D) << 0))
+static u16 radio2050_rfover_val(struct b43_wldev *dev,
+				u16 phy_register, unsigned int lpd)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+
+	if (!phy->gmode)
+		return 0;
+
+	if (has_loopback_gain(phy)) {
+		int max_lb_gain = phy->max_lb_gain;
+		u16 extlna;
+		u16 i;
+
+		if (phy->radio_rev == 8)
+			max_lb_gain += 0x3E;
+		else
+			max_lb_gain += 0x26;
+		if (max_lb_gain >= 0x46) {
+			extlna = 0x3000;
+			max_lb_gain -= 0x46;
+		} else if (max_lb_gain >= 0x3A) {
+			extlna = 0x1000;
+			max_lb_gain -= 0x3A;
+		} else if (max_lb_gain >= 0x2E) {
+			extlna = 0x2000;
+			max_lb_gain -= 0x2E;
+		} else {
+			extlna = 0;
+			max_lb_gain -= 0x10;
+		}
+
+		for (i = 0; i < 16; i++) {
+			max_lb_gain -= (i * 6);
+			if (max_lb_gain < 6)
+				break;
+		}
+
+		if ((phy->rev < 7) ||
+		    !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+			if (phy_register == B43_PHY_RFOVER) {
+				return 0x1B3;
+			} else if (phy_register == B43_PHY_RFOVERVAL) {
+				extlna |= (i << 8);
+				switch (lpd) {
+				case LPD(0, 1, 1):
+					return 0x0F92;
+				case LPD(0, 0, 1):
+				case LPD(1, 0, 1):
+					return (0x0092 | extlna);
+				case LPD(1, 0, 0):
+					return (0x0093 | extlna);
+				}
+				B43_WARN_ON(1);
+			}
+			B43_WARN_ON(1);
+		} else {
+			if (phy_register == B43_PHY_RFOVER) {
+				return 0x9B3;
+			} else if (phy_register == B43_PHY_RFOVERVAL) {
+				if (extlna)
+					extlna |= 0x8000;
+				extlna |= (i << 8);
+				switch (lpd) {
+				case LPD(0, 1, 1):
+					return 0x8F92;
+				case LPD(0, 0, 1):
+					return (0x8092 | extlna);
+				case LPD(1, 0, 1):
+					return (0x2092 | extlna);
+				case LPD(1, 0, 0):
+					return (0x2093 | extlna);
+				}
+				B43_WARN_ON(1);
+			}
+			B43_WARN_ON(1);
+		}
+	} else {
+		if ((phy->rev < 7) ||
+		    !(sprom->r1.boardflags_lo & B43_BFL_EXTLNA)) {
+			if (phy_register == B43_PHY_RFOVER) {
+				return 0x1B3;
+			} else if (phy_register == B43_PHY_RFOVERVAL) {
+				switch (lpd) {
+				case LPD(0, 1, 1):
+					return 0x0FB2;
+				case LPD(0, 0, 1):
+					return 0x00B2;
+				case LPD(1, 0, 1):
+					return 0x30B2;
+				case LPD(1, 0, 0):
+					return 0x30B3;
+				}
+				B43_WARN_ON(1);
+			}
+			B43_WARN_ON(1);
+		} else {
+			if (phy_register == B43_PHY_RFOVER) {
+				return 0x9B3;
+			} else if (phy_register == B43_PHY_RFOVERVAL) {
+				switch (lpd) {
+				case LPD(0, 1, 1):
+					return 0x8FB2;
+				case LPD(0, 0, 1):
+					return 0x80B2;
+				case LPD(1, 0, 1):
+					return 0x20B2;
+				case LPD(1, 0, 0):
+					return 0x20B3;
+				}
+				B43_WARN_ON(1);
+			}
+			B43_WARN_ON(1);
+		}
+	}
+	return 0;
+}
+
+struct init2050_saved_values {
+	/* Core registers */
+	u16 reg_3EC;
+	u16 reg_3E6;
+	u16 reg_3F4;
+	/* Radio registers */
+	u16 radio_43;
+	u16 radio_51;
+	u16 radio_52;
+	/* PHY registers */
+	u16 phy_pgactl;
+	u16 phy_base_5A;
+	u16 phy_base_59;
+	u16 phy_base_58;
+	u16 phy_base_30;
+	u16 phy_rfover;
+	u16 phy_rfoverval;
+	u16 phy_analogover;
+	u16 phy_analogoverval;
+	u16 phy_crs0;
+	u16 phy_classctl;
+	u16 phy_lo_mask;
+	u16 phy_lo_ctl;
+	u16 phy_syncctl;
+};
+
+u16 b43_radio_init2050(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	struct init2050_saved_values sav;
+	u16 rcc;
+	u16 radio78;
+	u16 ret;
+	u16 i, j;
+	u32 tmp1 = 0, tmp2 = 0;
+
+	memset(&sav, 0, sizeof(sav));	/* get rid of "may be used uninitialized..." */
+
+	sav.radio_43 = b43_radio_read16(dev, 0x43);
+	sav.radio_51 = b43_radio_read16(dev, 0x51);
+	sav.radio_52 = b43_radio_read16(dev, 0x52);
+	sav.phy_pgactl = b43_phy_read(dev, B43_PHY_PGACTL);
+	sav.phy_base_5A = b43_phy_read(dev, B43_PHY_BASE(0x5A));
+	sav.phy_base_59 = b43_phy_read(dev, B43_PHY_BASE(0x59));
+	sav.phy_base_58 = b43_phy_read(dev, B43_PHY_BASE(0x58));
+
+	if (phy->type == B43_PHYTYPE_B) {
+		sav.phy_base_30 = b43_phy_read(dev, B43_PHY_BASE(0x30));
+		sav.reg_3EC = b43_read16(dev, 0x3EC);
+
+		b43_phy_write(dev, B43_PHY_BASE(0x30), 0xFF);
+		b43_write16(dev, 0x3EC, 0x3F3F);
+	} else if (phy->gmode || phy->rev >= 2) {
+		sav.phy_rfover = b43_phy_read(dev, B43_PHY_RFOVER);
+		sav.phy_rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
+		sav.phy_analogover = b43_phy_read(dev, B43_PHY_ANALOGOVER);
+		sav.phy_analogoverval =
+		    b43_phy_read(dev, B43_PHY_ANALOGOVERVAL);
+		sav.phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
+		sav.phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL);
+
+		b43_phy_write(dev, B43_PHY_ANALOGOVER,
+			      b43_phy_read(dev, B43_PHY_ANALOGOVER)
+			      | 0x0003);
+		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+			      b43_phy_read(dev, B43_PHY_ANALOGOVERVAL)
+			      & 0xFFFC);
+		b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
+			      & 0x7FFF);
+		b43_phy_write(dev, B43_PHY_CLASSCTL,
+			      b43_phy_read(dev, B43_PHY_CLASSCTL)
+			      & 0xFFFC);
+		if (has_loopback_gain(phy)) {
+			sav.phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
+			sav.phy_lo_ctl = b43_phy_read(dev, B43_PHY_LO_CTL);
+
+			if (phy->rev >= 3)
+				b43_phy_write(dev, B43_PHY_LO_MASK, 0xC020);
+			else
+				b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
+			b43_phy_write(dev, B43_PHY_LO_CTL, 0);
+		}
+
+		b43_phy_write(dev, B43_PHY_RFOVERVAL,
+			      radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
+						   LPD(0, 1, 1)));
+		b43_phy_write(dev, B43_PHY_RFOVER,
+			      radio2050_rfover_val(dev, B43_PHY_RFOVER, 0));
+	}
+	b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000);
+
+	sav.phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL);
+	b43_phy_write(dev, B43_PHY_SYNCCTL, b43_phy_read(dev, B43_PHY_SYNCCTL)
+		      & 0xFF7F);
+	sav.reg_3E6 = b43_read16(dev, 0x3E6);
+	sav.reg_3F4 = b43_read16(dev, 0x3F4);
+
+	if (phy->analog == 0) {
+		b43_write16(dev, 0x03E6, 0x0122);
+	} else {
+		if (phy->analog >= 2) {
+			b43_phy_write(dev, B43_PHY_BASE(0x03),
+				      (b43_phy_read(dev, B43_PHY_BASE(0x03))
+				       & 0xFFBF) | 0x40);
+		}
+		b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+			    (b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 0x2000));
+	}
+
+	rcc = b43_radio_core_calibration_value(dev);
+
+	if (phy->type == B43_PHYTYPE_B)
+		b43_radio_write16(dev, 0x78, 0x26);
+	if (phy->gmode || phy->rev >= 2) {
+		b43_phy_write(dev, B43_PHY_RFOVERVAL,
+			      radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
+						   LPD(0, 1, 1)));
+	}
+	b43_phy_write(dev, B43_PHY_PGACTL, 0xBFAF);
+	b43_phy_write(dev, B43_PHY_BASE(0x2B), 0x1403);
+	if (phy->gmode || phy->rev >= 2) {
+		b43_phy_write(dev, B43_PHY_RFOVERVAL,
+			      radio2050_rfover_val(dev, B43_PHY_RFOVERVAL,
+						   LPD(0, 0, 1)));
+	}
+	b43_phy_write(dev, B43_PHY_PGACTL, 0xBFA0);
+	b43_radio_write16(dev, 0x51, b43_radio_read16(dev, 0x51)
+			  | 0x0004);
+	if (phy->radio_rev == 8) {
+		b43_radio_write16(dev, 0x43, 0x1F);
+	} else {
+		b43_radio_write16(dev, 0x52, 0);
+		b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
+					      & 0xFFF0) | 0x0009);
+	}
+	b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+
+	for (i = 0; i < 16; i++) {
+		b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0480);
+		b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
+		b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+		if (phy->gmode || phy->rev >= 2) {
+			b43_phy_write(dev, B43_PHY_RFOVERVAL,
+				      radio2050_rfover_val(dev,
+							   B43_PHY_RFOVERVAL,
+							   LPD(1, 0, 1)));
+		}
+		b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
+		udelay(10);
+		if (phy->gmode || phy->rev >= 2) {
+			b43_phy_write(dev, B43_PHY_RFOVERVAL,
+				      radio2050_rfover_val(dev,
+							   B43_PHY_RFOVERVAL,
+							   LPD(1, 0, 1)));
+		}
+		b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0);
+		udelay(10);
+		if (phy->gmode || phy->rev >= 2) {
+			b43_phy_write(dev, B43_PHY_RFOVERVAL,
+				      radio2050_rfover_val(dev,
+							   B43_PHY_RFOVERVAL,
+							   LPD(1, 0, 0)));
+		}
+		b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
+		udelay(20);
+		tmp1 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
+		b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+		if (phy->gmode || phy->rev >= 2) {
+			b43_phy_write(dev, B43_PHY_RFOVERVAL,
+				      radio2050_rfover_val(dev,
+							   B43_PHY_RFOVERVAL,
+							   LPD(1, 0, 1)));
+		}
+		b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
+	}
+	udelay(10);
+
+	b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+	tmp1++;
+	tmp1 >>= 9;
+
+	for (i = 0; i < 16; i++) {
+		radio78 = ((flip_4bit(i) << 1) | 0x20);
+		b43_radio_write16(dev, 0x78, radio78);
+		udelay(10);
+		for (j = 0; j < 16; j++) {
+			b43_phy_write(dev, B43_PHY_BASE(0x5A), 0x0D80);
+			b43_phy_write(dev, B43_PHY_BASE(0x59), 0xC810);
+			b43_phy_write(dev, B43_PHY_BASE(0x58), 0x000D);
+			if (phy->gmode || phy->rev >= 2) {
+				b43_phy_write(dev, B43_PHY_RFOVERVAL,
+					      radio2050_rfover_val(dev,
+								   B43_PHY_RFOVERVAL,
+								   LPD(1, 0,
+								       1)));
+			}
+			b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
+			udelay(10);
+			if (phy->gmode || phy->rev >= 2) {
+				b43_phy_write(dev, B43_PHY_RFOVERVAL,
+					      radio2050_rfover_val(dev,
+								   B43_PHY_RFOVERVAL,
+								   LPD(1, 0,
+								       1)));
+			}
+			b43_phy_write(dev, B43_PHY_PGACTL, 0xEFB0);
+			udelay(10);
+			if (phy->gmode || phy->rev >= 2) {
+				b43_phy_write(dev, B43_PHY_RFOVERVAL,
+					      radio2050_rfover_val(dev,
+								   B43_PHY_RFOVERVAL,
+								   LPD(1, 0,
+								       0)));
+			}
+			b43_phy_write(dev, B43_PHY_PGACTL, 0xFFF0);
+			udelay(10);
+			tmp2 += b43_phy_read(dev, B43_PHY_LO_LEAKAGE);
+			b43_phy_write(dev, B43_PHY_BASE(0x58), 0);
+			if (phy->gmode || phy->rev >= 2) {
+				b43_phy_write(dev, B43_PHY_RFOVERVAL,
+					      radio2050_rfover_val(dev,
+								   B43_PHY_RFOVERVAL,
+								   LPD(1, 0,
+								       1)));
+			}
+			b43_phy_write(dev, B43_PHY_PGACTL, 0xAFB0);
+		}
+		tmp2++;
+		tmp2 >>= 8;
+		if (tmp1 < tmp2)
+			break;
+	}
+
+	/* Restore the registers */
+	b43_phy_write(dev, B43_PHY_PGACTL, sav.phy_pgactl);
+	b43_radio_write16(dev, 0x51, sav.radio_51);
+	b43_radio_write16(dev, 0x52, sav.radio_52);
+	b43_radio_write16(dev, 0x43, sav.radio_43);
+	b43_phy_write(dev, B43_PHY_BASE(0x5A), sav.phy_base_5A);
+	b43_phy_write(dev, B43_PHY_BASE(0x59), sav.phy_base_59);
+	b43_phy_write(dev, B43_PHY_BASE(0x58), sav.phy_base_58);
+	b43_write16(dev, 0x3E6, sav.reg_3E6);
+	if (phy->analog != 0)
+		b43_write16(dev, 0x3F4, sav.reg_3F4);
+	b43_phy_write(dev, B43_PHY_SYNCCTL, sav.phy_syncctl);
+	b43_synth_pu_workaround(dev, phy->channel);
+	if (phy->type == B43_PHYTYPE_B) {
+		b43_phy_write(dev, B43_PHY_BASE(0x30), sav.phy_base_30);
+		b43_write16(dev, 0x3EC, sav.reg_3EC);
+	} else if (phy->gmode) {
+		b43_write16(dev, B43_MMIO_PHY_RADIO,
+			    b43_read16(dev, B43_MMIO_PHY_RADIO)
+			    & 0x7FFF);
+		b43_phy_write(dev, B43_PHY_RFOVER, sav.phy_rfover);
+		b43_phy_write(dev, B43_PHY_RFOVERVAL, sav.phy_rfoverval);
+		b43_phy_write(dev, B43_PHY_ANALOGOVER, sav.phy_analogover);
+		b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
+			      sav.phy_analogoverval);
+		b43_phy_write(dev, B43_PHY_CRS0, sav.phy_crs0);
+		b43_phy_write(dev, B43_PHY_CLASSCTL, sav.phy_classctl);
+		if (has_loopback_gain(phy)) {
+			b43_phy_write(dev, B43_PHY_LO_MASK, sav.phy_lo_mask);
+			b43_phy_write(dev, B43_PHY_LO_CTL, sav.phy_lo_ctl);
+		}
+	}
+	if (i > 15)
+		ret = radio78;
+	else
+		ret = rcc;
+
+	return ret;
+}
+
+void b43_radio_init2060(struct b43_wldev *dev)
+{
+	int err;
+
+	b43_radio_write16(dev, 0x0004, 0x00C0);
+	b43_radio_write16(dev, 0x0005, 0x0008);
+	b43_radio_write16(dev, 0x0009, 0x0040);
+	b43_radio_write16(dev, 0x0005, 0x00AA);
+	b43_radio_write16(dev, 0x0032, 0x008F);
+	b43_radio_write16(dev, 0x0006, 0x008F);
+	b43_radio_write16(dev, 0x0034, 0x008F);
+	b43_radio_write16(dev, 0x002C, 0x0007);
+	b43_radio_write16(dev, 0x0082, 0x0080);
+	b43_radio_write16(dev, 0x0080, 0x0000);
+	b43_radio_write16(dev, 0x003F, 0x00DA);
+	b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
+	b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010);
+	b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
+	b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
+	msleep(1);		/* delay 400usec */
+
+	b43_radio_write16(dev, 0x0081,
+			  (b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010);
+	msleep(1);		/* delay 400usec */
+
+	b43_radio_write16(dev, 0x0005,
+			  (b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008);
+	b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010);
+	b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
+	b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040);
+	b43_radio_write16(dev, 0x0081,
+			  (b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040);
+	b43_radio_write16(dev, 0x0005,
+			  (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008);
+	b43_phy_write(dev, 0x0063, 0xDDC6);
+	b43_phy_write(dev, 0x0069, 0x07BE);
+	b43_phy_write(dev, 0x006A, 0x0000);
+
+	err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_A, 0);
+	B43_WARN_ON(err);
+
+	msleep(1);
+}
+
+static inline u16 freq_r3A_value(u16 frequency)
+{
+	u16 value;
+
+	if (frequency < 5091)
+		value = 0x0040;
+	else if (frequency < 5321)
+		value = 0x0000;
+	else if (frequency < 5806)
+		value = 0x0080;
+	else
+		value = 0x0040;
+
+	return value;
+}
+
+void b43_radio_set_tx_iq(struct b43_wldev *dev)
+{
+	static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
+	static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
+	u16 tmp = b43_radio_read16(dev, 0x001E);
+	int i, j;
+
+	for (i = 0; i < 5; i++) {
+		for (j = 0; j < 5; j++) {
+			if (tmp == (data_high[i] << 4 | data_low[j])) {
+				b43_phy_write(dev, 0x0069,
+					      (i - j) << 8 | 0x00C0);
+				return;
+			}
+		}
+	}
+}
+
+int b43_radio_selectchannel(struct b43_wldev *dev,
+			    u8 channel, int synthetic_pu_workaround)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 r8, tmp;
+	u16 freq;
+	u16 channelcookie;
+
+	if (channel == 0xFF) {
+		switch (phy->type) {
+		case B43_PHYTYPE_A:
+			channel = B43_DEFAULT_CHANNEL_A;
+			break;
+		case B43_PHYTYPE_B:
+		case B43_PHYTYPE_G:
+			channel = B43_DEFAULT_CHANNEL_BG;
+			break;
+		default:
+			B43_WARN_ON(1);
+		}
+	}
+
+	/* First we set the channel radio code to prevent the
+	 * firmware from sending ghost packets.
+	 */
+	channelcookie = channel;
+	if (phy->type == B43_PHYTYPE_A)
+		channelcookie |= 0x100;
+	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie);
+
+	if (phy->type == B43_PHYTYPE_A) {
+		if (channel > 200)
+			return -EINVAL;
+		freq = channel2freq_a(channel);
+
+		r8 = b43_radio_read16(dev, 0x0008);
+		b43_write16(dev, 0x03F0, freq);
+		b43_radio_write16(dev, 0x0008, r8);
+
+		//TODO: write max channel TX power? to Radio 0x2D
+		tmp = b43_radio_read16(dev, 0x002E);
+		tmp &= 0x0080;
+		//TODO: OR tmp with the Power out estimation for this channel?
+		b43_radio_write16(dev, 0x002E, tmp);
+
+		if (freq >= 4920 && freq <= 5500) {
+			/*
+			 * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F;
+			 *    = (freq * 0.025862069
+			 */
+			r8 = 3 * freq / 116;	/* is equal to r8 = freq * 0.025862 */
+		}
+		b43_radio_write16(dev, 0x0007, (r8 << 4) | r8);
+		b43_radio_write16(dev, 0x0020, (r8 << 4) | r8);
+		b43_radio_write16(dev, 0x0021, (r8 << 4) | r8);
+		b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022)
+						& 0x000F) | (r8 << 4));
+		b43_radio_write16(dev, 0x002A, (r8 << 4));
+		b43_radio_write16(dev, 0x002B, (r8 << 4));
+		b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008)
+						& 0x00F0) | (r8 << 4));
+		b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029)
+						& 0xFF0F) | 0x00B0);
+		b43_radio_write16(dev, 0x0035, 0x00AA);
+		b43_radio_write16(dev, 0x0036, 0x0085);
+		b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A)
+						& 0xFF20) |
+				  freq_r3A_value(freq));
+		b43_radio_write16(dev, 0x003D,
+				  b43_radio_read16(dev, 0x003D) & 0x00FF);
+		b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081)
+						& 0xFF7F) | 0x0080);
+		b43_radio_write16(dev, 0x0035,
+				  b43_radio_read16(dev, 0x0035) & 0xFFEF);
+		b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035)
+						& 0xFFEF) | 0x0010);
+		b43_radio_set_tx_iq(dev);
+		//TODO: TSSI2dbm workaround
+		b43_phy_xmitpower(dev);	//FIXME correct?
+	} else {
+		if ((channel < 1) || (channel > 14))
+			return -EINVAL;
+
+		if (synthetic_pu_workaround)
+			b43_synth_pu_workaround(dev, channel);
+
+		b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
+
+		if (channel == 14) {
+			if (dev->dev->bus->sprom.r1.country_code ==
+			    SSB_SPROM1CCODE_JAPAN)
+				b43_hf_write(dev,
+					     b43_hf_read(dev) & ~B43_HF_ACPR);
+			else
+				b43_hf_write(dev,
+					     b43_hf_read(dev) | B43_HF_ACPR);
+			b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+				    b43_read16(dev, B43_MMIO_CHANNEL_EXT)
+				    | (1 << 11));
+		} else {
+			b43_write16(dev, B43_MMIO_CHANNEL_EXT,
+				    b43_read16(dev, B43_MMIO_CHANNEL_EXT)
+				    & 0xF7BF);
+		}
+	}
+
+	phy->channel = channel;
+	/* Wait for the radio to tune to the channel and stabilize. */
+	msleep(8);
+
+	return 0;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
+static u16 b43_get_txgain_base_band(u16 txpower)
+{
+	u16 ret;
+
+	B43_WARN_ON(txpower > 63);
+
+	if (txpower >= 54)
+		ret = 2;
+	else if (txpower >= 49)
+		ret = 4;
+	else if (txpower >= 44)
+		ret = 5;
+	else
+		ret = 6;
+
+	return ret;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
+static u16 b43_get_txgain_freq_power_amp(u16 txpower)
+{
+	u16 ret;
+
+	B43_WARN_ON(txpower > 63);
+
+	if (txpower >= 32)
+		ret = 0;
+	else if (txpower >= 25)
+		ret = 1;
+	else if (txpower >= 20)
+		ret = 2;
+	else if (txpower >= 12)
+		ret = 3;
+	else
+		ret = 4;
+
+	return ret;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
+static u16 b43_get_txgain_dac(u16 txpower)
+{
+	u16 ret;
+
+	B43_WARN_ON(txpower > 63);
+
+	if (txpower >= 54)
+		ret = txpower - 53;
+	else if (txpower >= 49)
+		ret = txpower - 42;
+	else if (txpower >= 44)
+		ret = txpower - 37;
+	else if (txpower >= 32)
+		ret = txpower - 32;
+	else if (txpower >= 25)
+		ret = txpower - 20;
+	else if (txpower >= 20)
+		ret = txpower - 13;
+	else if (txpower >= 12)
+		ret = txpower - 8;
+	else
+		ret = txpower;
+
+	return ret;
+}
+
+static void b43_radio_set_txpower_a(struct b43_wldev *dev, u16 txpower)
+{
+	struct b43_phy *phy = &dev->phy;
+	u16 pamp, base, dac, t;
+
+	txpower = limit_value(txpower, 0, 63);
+
+	pamp = b43_get_txgain_freq_power_amp(txpower);
+	pamp <<= 5;
+	pamp &= 0x00E0;
+	b43_phy_write(dev, 0x0019, pamp);
+
+	base = b43_get_txgain_base_band(txpower);
+	base &= 0x000F;
+	b43_phy_write(dev, 0x0017, base | 0x0020);
+
+	t = b43_ofdmtab_read16(dev, 0x3000, 1);
+	t &= 0x0007;
+
+	dac = b43_get_txgain_dac(txpower);
+	dac <<= 3;
+	dac |= t;
+
+	b43_ofdmtab_write16(dev, 0x3000, 1, dac);
+
+	phy->txpwr_offset = txpower;
+
+	//TODO: FuncPlaceholder (Adjust BB loft cancel)
+}
+
+void b43_radio_turn_on(struct b43_wldev *dev)
+{
+	struct b43_phy *phy = &dev->phy;
+	int err;
+	u8 channel;
+
+	might_sleep();
+
+	if (phy->radio_on)
+		return;
+
+	switch (phy->type) {
+	case B43_PHYTYPE_A:
+		b43_radio_write16(dev, 0x0004, 0x00C0);
+		b43_radio_write16(dev, 0x0005, 0x0008);
+		b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) & 0xFFF7);
+		b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) & 0xFFF7);
+		b43_radio_init2060(dev);
+		break;
+	case B43_PHYTYPE_B:
+	case B43_PHYTYPE_G:
+		b43_phy_write(dev, 0x0015, 0x8000);
+		b43_phy_write(dev, 0x0015, 0xCC00);
+		b43_phy_write(dev, 0x0015, (phy->gmode ? 0x00C0 : 0x0000));
+		if (phy->radio_off_context.valid) {
+			/* Restore the RFover values. */
+			b43_phy_write(dev, B43_PHY_RFOVER,
+				      phy->radio_off_context.rfover);
+			b43_phy_write(dev, B43_PHY_RFOVERVAL,
+				      phy->radio_off_context.rfoverval);
+			phy->radio_off_context.valid = 0;
+		}
+		channel = phy->channel;
+		err = b43_radio_selectchannel(dev, B43_DEFAULT_CHANNEL_BG, 1);
+		err |= b43_radio_selectchannel(dev, channel, 0);
+		B43_WARN_ON(err);
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+	phy->radio_on = 1;
+}
+
+void b43_radio_turn_off(struct b43_wldev *dev, bool force)
+{
+	struct b43_phy *phy = &dev->phy;
+
+	if (!phy->radio_on && !force)
+		return;
+
+	if (phy->type == B43_PHYTYPE_A) {
+		b43_radio_write16(dev, 0x0004, 0x00FF);
+		b43_radio_write16(dev, 0x0005, 0x00FB);
+		b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008);
+		b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008);
+	}
+	if (phy->type == B43_PHYTYPE_G && dev->dev->id.revision >= 5) {
+		u16 rfover, rfoverval;
+
+		rfover = b43_phy_read(dev, B43_PHY_RFOVER);
+		rfoverval = b43_phy_read(dev, B43_PHY_RFOVERVAL);
+		if (!force) {
+			phy->radio_off_context.rfover = rfover;
+			phy->radio_off_context.rfoverval = rfoverval;
+			phy->radio_off_context.valid = 1;
+		}
+		b43_phy_write(dev, B43_PHY_RFOVER, rfover | 0x008C);
+		b43_phy_write(dev, B43_PHY_RFOVERVAL, rfoverval & 0xFF73);
+	} else
+		b43_phy_write(dev, 0x0015, 0xAA00);
+	phy->radio_on = 0;
+}
diff --git a/drivers/net/wireless/b43/phy.h b/drivers/net/wireless/b43/phy.h
new file mode 100644
index 0000000..c64d745
--- /dev/null
+++ b/drivers/net/wireless/b43/phy.h
@@ -0,0 +1,297 @@
+#ifndef B43_PHY_H_
+#define B43_PHY_H_
+
+#include <linux/types.h>
+
+struct b43_wldev;
+struct b43_phy;
+
+/*** PHY Registers ***/
+
+/* Routing */
+#define B43_PHYROUTE_OFDM_GPHY		0x400
+#define B43_PHYROUTE_EXT_GPHY		0x800
+
+/* Base registers. */
+#define B43_PHY_BASE(reg)		(reg)
+/* OFDM (A) registers of a G-PHY */
+#define B43_PHY_OFDM(reg)		((reg) | B43_PHYROUTE_OFDM_GPHY)
+/* Extended G-PHY registers */
+#define B43_PHY_EXTG(reg)		((reg) | B43_PHYROUTE_EXT_GPHY)
+
+/* OFDM (A) PHY Registers */
+#define B43_PHY_VERSION_OFDM		B43_PHY_OFDM(0x00)	/* Versioning register for A-PHY */
+#define B43_PHY_BBANDCFG		B43_PHY_OFDM(0x01)	/* Baseband config */
+#define  B43_PHY_BBANDCFG_RXANT		0x180	/* RX Antenna selection */
+#define  B43_PHY_BBANDCFG_RXANT_SHIFT	7
+#define B43_PHY_PWRDOWN			B43_PHY_OFDM(0x03)	/* Powerdown */
+#define B43_PHY_CRSTHRES1		B43_PHY_OFDM(0x06)	/* CRS Threshold 1 */
+#define B43_PHY_LNAHPFCTL		B43_PHY_OFDM(0x1C)	/* LNA/HPF control */
+#define B43_PHY_ADIVRELATED		B43_PHY_OFDM(0x27)	/* FIXME rename */
+#define B43_PHY_CRS0			B43_PHY_OFDM(0x29)
+#define B43_PHY_ANTDWELL		B43_PHY_OFDM(0x2B)	/* Antenna dwell */
+#define  B43_PHY_ANTDWELL_AUTODIV1	0x0100	/* Automatic RX diversity start antenna */
+#define B43_PHY_ENCORE			B43_PHY_OFDM(0x49)	/* "Encore" (RangeMax / BroadRange) */
+#define  B43_PHY_ENCORE_EN		0x0200	/* Encore enable */
+#define B43_PHY_LMS			B43_PHY_OFDM(0x55)
+#define B43_PHY_OFDM61			B43_PHY_OFDM(0x61)	/* FIXME rename */
+#define  B43_PHY_OFDM61_10		0x0010	/* FIXME rename */
+#define B43_PHY_IQBAL			B43_PHY_OFDM(0x69)	/* I/Q balance */
+#define B43_PHY_OTABLECTL		B43_PHY_OFDM(0x72)	/* OFDM table control (see below) */
+#define  B43_PHY_OTABLEOFF		0x03FF	/* OFDM table offset (see below) */
+#define  B43_PHY_OTABLENR		0xFC00	/* OFDM table number (see below) */
+#define  B43_PHY_OTABLENR_SHIFT		10
+#define B43_PHY_OTABLEI			B43_PHY_OFDM(0x73)	/* OFDM table data I */
+#define B43_PHY_OTABLEQ			B43_PHY_OFDM(0x74)	/* OFDM table data Q */
+#define B43_PHY_HPWR_TSSICTL		B43_PHY_OFDM(0x78)	/* Hardware power TSSI control */
+#define B43_PHY_NRSSITHRES		B43_PHY_OFDM(0x8A)	/* NRSSI threshold */
+#define B43_PHY_ANTWRSETT		B43_PHY_OFDM(0x8C)	/* Antenna WR settle */
+#define  B43_PHY_ANTWRSETT_ARXDIV	0x2000	/* Automatic RX diversity enabled */
+#define B43_PHY_CLIPPWRDOWNT		B43_PHY_OFDM(0x93)	/* Clip powerdown threshold */
+#define B43_PHY_OFDM9B			B43_PHY_OFDM(0x9B)	/* FIXME rename */
+#define B43_PHY_N1P1GAIN		B43_PHY_OFDM(0xA0)
+#define B43_PHY_P1P2GAIN		B43_PHY_OFDM(0xA1)
+#define B43_PHY_N1N2GAIN		B43_PHY_OFDM(0xA2)
+#define B43_PHY_CLIPTHRES		B43_PHY_OFDM(0xA3)
+#define B43_PHY_CLIPN1P2THRES		B43_PHY_OFDM(0xA4)
+#define B43_PHY_DIVSRCHIDX		B43_PHY_OFDM(0xA8)	/* Divider search gain/index */
+#define B43_PHY_CLIPP2THRES		B43_PHY_OFDM(0xA9)
+#define B43_PHY_CLIPP3THRES		B43_PHY_OFDM(0xAA)
+#define B43_PHY_DIVP1P2GAIN		B43_PHY_OFDM(0xAB)
+#define B43_PHY_DIVSRCHGAINBACK		B43_PHY_OFDM(0xAD)	/* Divider search gain back */
+#define B43_PHY_DIVSRCHGAINCHNG		B43_PHY_OFDM(0xAE)	/* Divider search gain change */
+#define B43_PHY_CRSTHRES1_R1		B43_PHY_OFDM(0xC0)	/* CRS Threshold 1 (rev 1 only) */
+#define B43_PHY_CRSTHRES2_R1		B43_PHY_OFDM(0xC1)	/* CRS Threshold 2 (rev 1 only) */
+#define B43_PHY_TSSIP_LTBASE		B43_PHY_OFDM(0x380)	/* TSSI power lookup table base */
+#define B43_PHY_DC_LTBASE		B43_PHY_OFDM(0x3A0)	/* DC lookup table base */
+#define B43_PHY_GAIN_LTBASE		B43_PHY_OFDM(0x3C0)	/* Gain lookup table base */
+
+/* CCK (B) PHY Registers */
+#define B43_PHY_VERSION_CCK		B43_PHY_BASE(0x00)	/* Versioning register for B-PHY */
+#define B43_PHY_CCKBBANDCFG		B43_PHY_BASE(0x01)	/* Contains antenna 0/1 control bit */
+#define B43_PHY_PGACTL			B43_PHY_BASE(0x15)	/* PGA control */
+#define  B43_PHY_PGACTL_LPF		0x1000	/* Low pass filter (?) */
+#define  B43_PHY_PGACTL_LOWBANDW	0x0040	/* Low bandwidth flag */
+#define  B43_PHY_PGACTL_UNKNOWN		0xEFA0
+#define B43_PHY_FBCTL1			B43_PHY_BASE(0x18)	/* Frequency bandwidth control 1 */
+#define B43_PHY_ITSSI			B43_PHY_BASE(0x29)	/* Idle TSSI */
+#define B43_PHY_LO_LEAKAGE		B43_PHY_BASE(0x2D)	/* Measured LO leakage */
+#define B43_PHY_ENERGY			B43_PHY_BASE(0x33)	/* Energy */
+#define B43_PHY_SYNCCTL			B43_PHY_BASE(0x35)
+#define B43_PHY_FBCTL2			B43_PHY_BASE(0x38)	/* Frequency bandwidth control 2 */
+#define B43_PHY_DACCTL			B43_PHY_BASE(0x60)	/* DAC control */
+#define B43_PHY_RCCALOVER		B43_PHY_BASE(0x78)	/* RC calibration override */
+
+/* Extended G-PHY Registers */
+#define B43_PHY_CLASSCTL		B43_PHY_EXTG(0x02)	/* Classify control */
+#define B43_PHY_GTABCTL			B43_PHY_EXTG(0x03)	/* G-PHY table control (see below) */
+#define  B43_PHY_GTABOFF		0x03FF	/* G-PHY table offset (see below) */
+#define  B43_PHY_GTABNR			0xFC00	/* G-PHY table number (see below) */
+#define  B43_PHY_GTABNR_SHIFT		10
+#define B43_PHY_GTABDATA		B43_PHY_EXTG(0x04)	/* G-PHY table data */
+#define B43_PHY_LO_MASK			B43_PHY_EXTG(0x0F)	/* Local Oscillator control mask */
+#define B43_PHY_LO_CTL			B43_PHY_EXTG(0x10)	/* Local Oscillator control */
+#define B43_PHY_RFOVER			B43_PHY_EXTG(0x11)	/* RF override */
+#define B43_PHY_RFOVERVAL		B43_PHY_EXTG(0x12)	/* RF override value */
+#define  B43_PHY_RFOVERVAL_EXTLNA	0x8000
+#define  B43_PHY_RFOVERVAL_LNA		0x7000
+#define  B43_PHY_RFOVERVAL_LNA_SHIFT	12
+#define  B43_PHY_RFOVERVAL_PGA		0x0F00
+#define  B43_PHY_RFOVERVAL_PGA_SHIFT	8
+#define  B43_PHY_RFOVERVAL_UNK		0x0010	/* Unknown, always set. */
+#define  B43_PHY_RFOVERVAL_TRSWRX	0x00E0
+#define  B43_PHY_RFOVERVAL_BW		0x0003	/* Bandwidth flags */
+#define   B43_PHY_RFOVERVAL_BW_LPF	0x0001	/* Low Pass Filter */
+#define   B43_PHY_RFOVERVAL_BW_LBW	0x0002	/* Low Bandwidth (when set), high when unset */
+#define B43_PHY_ANALOGOVER		B43_PHY_EXTG(0x14)	/* Analog override */
+#define B43_PHY_ANALOGOVERVAL		B43_PHY_EXTG(0x15)	/* Analog override value */
+
+/*** OFDM table numbers ***/
+#define B43_OFDMTAB(number, offset)	(((number) << B43_PHY_OTABLENR_SHIFT) | (offset))
+#define B43_OFDMTAB_AGC1		B43_OFDMTAB(0x00, 0)
+#define B43_OFDMTAB_GAIN0		B43_OFDMTAB(0x00, 0)
+#define B43_OFDMTAB_GAINX		B43_OFDMTAB(0x01, 0)	//TODO rename
+#define B43_OFDMTAB_GAIN1		B43_OFDMTAB(0x01, 4)
+#define B43_OFDMTAB_AGC3		B43_OFDMTAB(0x02, 0)
+#define B43_OFDMTAB_GAIN2		B43_OFDMTAB(0x02, 3)
+#define B43_OFDMTAB_LNAHPFGAIN1		B43_OFDMTAB(0x03, 0)
+#define B43_OFDMTAB_WRSSI		B43_OFDMTAB(0x04, 0)
+#define B43_OFDMTAB_LNAHPFGAIN2		B43_OFDMTAB(0x04, 0)
+#define B43_OFDMTAB_NOISESCALE		B43_OFDMTAB(0x05, 0)
+#define B43_OFDMTAB_AGC2		B43_OFDMTAB(0x06, 0)
+#define B43_OFDMTAB_ROTOR		B43_OFDMTAB(0x08, 0)
+#define B43_OFDMTAB_ADVRETARD		B43_OFDMTAB(0x09, 0)
+#define B43_OFDMTAB_DAC			B43_OFDMTAB(0x0C, 0)
+#define B43_OFDMTAB_DC			B43_OFDMTAB(0x0E, 7)
+#define B43_OFDMTAB_PWRDYN2		B43_OFDMTAB(0x0E, 12)
+#define B43_OFDMTAB_LNAGAIN		B43_OFDMTAB(0x0E, 13)
+//TODO
+#define B43_OFDMTAB_LPFGAIN		B43_OFDMTAB(0x0F, 12)
+#define B43_OFDMTAB_RSSI		B43_OFDMTAB(0x10, 0)
+//TODO
+#define B43_OFDMTAB_AGC1_R1		B43_OFDMTAB(0x13, 0)
+#define B43_OFDMTAB_GAINX_R1		B43_OFDMTAB(0x14, 0)	//TODO rename
+#define B43_OFDMTAB_MINSIGSQ		B43_OFDMTAB(0x14, 1)
+#define B43_OFDMTAB_AGC3_R1		B43_OFDMTAB(0x15, 0)
+#define B43_OFDMTAB_WRSSI_R1		B43_OFDMTAB(0x15, 4)
+#define B43_OFDMTAB_TSSI		B43_OFDMTAB(0x15, 0)
+#define B43_OFDMTAB_DACRFPABB		B43_OFDMTAB(0x16, 0)
+#define B43_OFDMTAB_DACOFF		B43_OFDMTAB(0x17, 0)
+#define B43_OFDMTAB_DCBIAS		B43_OFDMTAB(0x18, 0)
+
+u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset);
+void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
+			 u16 offset, u16 value);
+u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset);
+void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
+			 u16 offset, u32 value);
+
+/*** G-PHY table numbers */
+#define B43_GTAB(number, offset)	(((number) << B43_PHY_GTABNR_SHIFT) | (offset))
+#define B43_GTAB_NRSSI			B43_GTAB(0x00, 0)
+#define B43_GTAB_TRFEMW			B43_GTAB(0x0C, 0x120)
+#define B43_GTAB_ORIGTR			B43_GTAB(0x2E, 0x298)
+
+u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset);	//TODO implement
+void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value);	//TODO implement
+
+#define B43_DEFAULT_CHANNEL_A	36
+#define B43_DEFAULT_CHANNEL_BG	6
+
+enum {
+	B43_ANTENNA0,		/* Antenna 0 */
+	B43_ANTENNA1,		/* Antenna 0 */
+	B43_ANTENNA_AUTO1,	/* Automatic, starting with antenna 1 */
+	B43_ANTENNA_AUTO0,	/* Automatic, starting with antenna 0 */
+
+	B43_ANTENNA_AUTO = B43_ANTENNA_AUTO0,
+	B43_ANTENNA_DEFAULT = B43_ANTENNA_AUTO,
+};
+
+enum {
+	B43_INTERFMODE_NONE,
+	B43_INTERFMODE_NONWLAN,
+	B43_INTERFMODE_MANUALWLAN,
+	B43_INTERFMODE_AUTOWLAN,
+};
+
+/* Masks for the different PHY versioning registers. */
+#define B43_PHYVER_ANALOG		0xF000
+#define B43_PHYVER_ANALOG_SHIFT		12
+#define B43_PHYVER_TYPE			0x0F00
+#define B43_PHYVER_TYPE_SHIFT		8
+#define B43_PHYVER_VERSION		0x00FF
+
+void b43_raw_phy_lock(struct b43_wldev *dev);
+#define b43_phy_lock(dev, flags) \
+	do {					\
+		local_irq_save(flags);		\
+		b43_raw_phy_lock(dev);	\
+	} while (0)
+void b43_raw_phy_unlock(struct b43_wldev *dev);
+#define b43_phy_unlock(dev, flags) \
+	do {					\
+		b43_raw_phy_unlock(dev);	\
+		local_irq_restore(flags);	\
+	} while (0)
+
+u16 b43_phy_read(struct b43_wldev *dev, u16 offset);
+void b43_phy_write(struct b43_wldev *dev, u16 offset, u16 val);
+
+int b43_phy_init_tssi2dbm_table(struct b43_wldev *dev);
+
+void b43_phy_early_init(struct b43_wldev *dev);
+int b43_phy_init(struct b43_wldev *dev);
+
+void b43_set_rx_antenna(struct b43_wldev *dev, int antenna);
+
+void b43_phy_xmitpower(struct b43_wldev *dev);
+void b43_gphy_dc_lt_init(struct b43_wldev *dev);
+
+/* Returns the boolean whether the board has HardwarePowerControl */
+bool b43_has_hardware_pctl(struct b43_phy *phy);
+/* Returns the boolean whether "TX Magnification" is enabled. */
+#define has_tx_magnification(phy) \
+	(((phy)->rev >= 2) &&			\
+	 ((phy)->radio_ver == 0x2050) &&	\
+	 ((phy)->radio_rev == 8))
+/* Card uses the loopback gain stuff */
+#define has_loopback_gain(phy) \
+	(((phy)->rev > 1) || ((phy)->gmode))
+
+/* Radio Attenuation (RF Attenuation) */
+struct b43_rfatt {
+	u8 att;			/* Attenuation value */
+	bool with_padmix;	/* Flag, PAD Mixer enabled. */
+};
+struct b43_rfatt_list {
+	/* Attenuation values list */
+	const struct b43_rfatt *list;
+	u8 len;
+	/* Minimum/Maximum attenuation values */
+	u8 min_val;
+	u8 max_val;
+};
+
+/* Baseband Attenuation */
+struct b43_bbatt {
+	u8 att;			/* Attenuation value */
+};
+struct b43_bbatt_list {
+	/* Attenuation values list */
+	const struct b43_bbatt *list;
+	u8 len;
+	/* Minimum/Maximum attenuation values */
+	u8 min_val;
+	u8 max_val;
+};
+
+/* tx_control bits. */
+#define B43_TXCTL_PA3DB		0x40	/* PA Gain 3dB */
+#define B43_TXCTL_PA2DB		0x20	/* PA Gain 2dB */
+#define B43_TXCTL_TXMIX		0x10	/* TX Mixer Gain */
+
+/* Write BasebandAttenuation value to the device. */
+void b43_phy_set_baseband_attenuation(struct b43_wldev *dev,
+				      u16 baseband_attenuation);
+
+extern const u8 b43_radio_channel_codes_bg[];
+
+void b43_radio_lock(struct b43_wldev *dev);
+void b43_radio_unlock(struct b43_wldev *dev);
+
+u16 b43_radio_read16(struct b43_wldev *dev, u16 offset);
+void b43_radio_write16(struct b43_wldev *dev, u16 offset, u16 val);
+
+u16 b43_radio_init2050(struct b43_wldev *dev);
+void b43_radio_init2060(struct b43_wldev *dev);
+
+void b43_radio_turn_on(struct b43_wldev *dev);
+void b43_radio_turn_off(struct b43_wldev *dev, bool force);
+
+int b43_radio_selectchannel(struct b43_wldev *dev, u8 channel,
+			    int synthetic_pu_workaround);
+
+u8 b43_radio_aci_detect(struct b43_wldev *dev, u8 channel);
+u8 b43_radio_aci_scan(struct b43_wldev *dev);
+
+int b43_radio_set_interference_mitigation(struct b43_wldev *dev, int mode);
+
+void b43_calc_nrssi_slope(struct b43_wldev *dev);
+void b43_calc_nrssi_threshold(struct b43_wldev *dev);
+s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset);
+void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val);
+void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val);
+void b43_nrssi_mem_update(struct b43_wldev *dev);
+
+void b43_radio_set_tx_iq(struct b43_wldev *dev);
+u16 b43_radio_calibrationvalue(struct b43_wldev *dev);
+
+void b43_put_attenuation_into_ranges(struct b43_wldev *dev,
+				     int *_bbatt, int *_rfatt);
+
+void b43_set_txpower_g(struct b43_wldev *dev,
+		       const struct b43_bbatt *bbatt,
+		       const struct b43_rfatt *rfatt, u8 tx_control);
+
+#endif /* B43_PHY_H_ */
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c
new file mode 100644
index 0000000..67752a2
--- /dev/null
+++ b/drivers/net/wireless/b43/pio.c
@@ -0,0 +1,652 @@
+/*
+
+  Broadcom B43 wireless driver
+
+  PIO Transmission
+
+  Copyright (c) 2005 Michael Buesch <mb@bu3sch.de>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "pio.h"
+#include "main.h"
+#include "xmit.h"
+
+#include <linux/delay.h>
+
+static void tx_start(struct b43_pioqueue *queue)
+{
+	b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_INIT);
+}
+
+static void tx_octet(struct b43_pioqueue *queue, u8 octet)
+{
+	if (queue->need_workarounds) {
+		b43_pio_write(queue, B43_PIO_TXDATA, octet);
+		b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO);
+	} else {
+		b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_WRITELO);
+		b43_pio_write(queue, B43_PIO_TXDATA, octet);
+	}
+}
+
+static u16 tx_get_next_word(const u8 * txhdr,
+			    const u8 * packet,
+			    size_t txhdr_size, unsigned int *pos)
+{
+	const u8 *source;
+	unsigned int i = *pos;
+	u16 ret;
+
+	if (i < txhdr_size) {
+		source = txhdr;
+	} else {
+		source = packet;
+		i -= txhdr_size;
+	}
+	ret = le16_to_cpu(*((__le16 *)(source + i)));
+	*pos += 2;
+
+	return ret;
+}
+
+static void tx_data(struct b43_pioqueue *queue,
+		    u8 * txhdr, const u8 * packet, unsigned int octets)
+{
+	u16 data;
+	unsigned int i = 0;
+
+	if (queue->need_workarounds) {
+		data = tx_get_next_word(txhdr, packet,
+					sizeof(struct b43_txhdr_fw4), &i);
+		b43_pio_write(queue, B43_PIO_TXDATA, data);
+	}
+	b43_pio_write(queue, B43_PIO_TXCTL,
+		      B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI);
+	while (i < octets - 1) {
+		data = tx_get_next_word(txhdr, packet,
+					sizeof(struct b43_txhdr_fw4), &i);
+		b43_pio_write(queue, B43_PIO_TXDATA, data);
+	}
+	if (octets % 2)
+		tx_octet(queue,
+			 packet[octets - sizeof(struct b43_txhdr_fw4) - 1]);
+}
+
+static void tx_complete(struct b43_pioqueue *queue, struct sk_buff *skb)
+{
+	if (queue->need_workarounds) {
+		b43_pio_write(queue, B43_PIO_TXDATA, skb->data[skb->len - 1]);
+		b43_pio_write(queue, B43_PIO_TXCTL,
+			      B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_COMPLETE);
+	} else {
+		b43_pio_write(queue, B43_PIO_TXCTL, B43_PIO_TXCTL_COMPLETE);
+	}
+}
+
+static u16 generate_cookie(struct b43_pioqueue *queue,
+			   struct b43_pio_txpacket *packet)
+{
+	u16 cookie = 0x0000;
+	u16 packetindex;
+
+	/* We use the upper 4 bits for the PIO
+	 * controller ID and the lower 12 bits
+	 * for the packet index (in the cache).
+	 */
+	switch (queue->mmio_base) {
+	case B43_MMIO_PIO1_BASE:
+		break;
+	case B43_MMIO_PIO2_BASE:
+		cookie = 0x1000;
+		break;
+	case B43_MMIO_PIO3_BASE:
+		cookie = 0x2000;
+		break;
+	case B43_MMIO_PIO4_BASE:
+		cookie = 0x3000;
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+	packetindex = packet->index;
+	B43_WARN_ON(packetindex & ~0x0FFF);
+	cookie |= (u16) packetindex;
+
+	return cookie;
+}
+
+static
+struct b43_pioqueue *parse_cookie(struct b43_wldev *dev,
+				  u16 cookie, struct b43_pio_txpacket **packet)
+{
+	struct b43_pio *pio = &dev->pio;
+	struct b43_pioqueue *queue = NULL;
+	int packetindex;
+
+	switch (cookie & 0xF000) {
+	case 0x0000:
+		queue = pio->queue0;
+		break;
+	case 0x1000:
+		queue = pio->queue1;
+		break;
+	case 0x2000:
+		queue = pio->queue2;
+		break;
+	case 0x3000:
+		queue = pio->queue3;
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+	packetindex = (cookie & 0x0FFF);
+	B43_WARN_ON(!(packetindex >= 0 && packetindex < B43_PIO_MAXTXPACKETS));
+	*packet = &(queue->tx_packets_cache[packetindex]);
+
+	return queue;
+}
+
+union txhdr_union {
+	struct b43_txhdr_fw4 txhdr_fw4;
+};
+
+static void pio_tx_write_fragment(struct b43_pioqueue *queue,
+				  struct sk_buff *skb,
+				  struct b43_pio_txpacket *packet,
+				  size_t txhdr_size)
+{
+	union txhdr_union txhdr_data;
+	u8 *txhdr = NULL;
+	unsigned int octets;
+
+	txhdr = (u8 *) (&txhdr_data.txhdr_fw4);
+
+	B43_WARN_ON(skb_shinfo(skb)->nr_frags);
+	b43_generate_txhdr(queue->dev,
+			   txhdr, skb->data, skb->len,
+			   &packet->txstat.control,
+			   generate_cookie(queue, packet));
+
+	tx_start(queue);
+	octets = skb->len + txhdr_size;
+	if (queue->need_workarounds)
+		octets--;
+	tx_data(queue, txhdr, (u8 *) skb->data, octets);
+	tx_complete(queue, skb);
+}
+
+static void free_txpacket(struct b43_pio_txpacket *packet)
+{
+	struct b43_pioqueue *queue = packet->queue;
+
+	if (packet->skb)
+		dev_kfree_skb_any(packet->skb);
+	list_move(&packet->list, &queue->txfree);
+	queue->nr_txfree++;
+}
+
+static int pio_tx_packet(struct b43_pio_txpacket *packet)
+{
+	struct b43_pioqueue *queue = packet->queue;
+	struct sk_buff *skb = packet->skb;
+	u16 octets;
+
+	octets = (u16) skb->len + sizeof(struct b43_txhdr_fw4);
+	if (queue->tx_devq_size < octets) {
+		b43warn(queue->dev->wl, "PIO queue too small. "
+			"Dropping packet.\n");
+		/* Drop it silently (return success) */
+		free_txpacket(packet);
+		return 0;
+	}
+	B43_WARN_ON(queue->tx_devq_packets > B43_PIO_MAXTXDEVQPACKETS);
+	B43_WARN_ON(queue->tx_devq_used > queue->tx_devq_size);
+	/* Check if there is sufficient free space on the device
+	 * TX queue. If not, return and let the TX tasklet
+	 * retry later.
+	 */
+	if (queue->tx_devq_packets == B43_PIO_MAXTXDEVQPACKETS)
+		return -EBUSY;
+	if (queue->tx_devq_used + octets > queue->tx_devq_size)
+		return -EBUSY;
+	/* Now poke the device. */
+	pio_tx_write_fragment(queue, skb, packet, sizeof(struct b43_txhdr_fw4));
+
+	/* Account for the packet size.
+	 * (We must not overflow the device TX queue)
+	 */
+	queue->tx_devq_packets++;
+	queue->tx_devq_used += octets;
+
+	/* Transmission started, everything ok, move the
+	 * packet to the txrunning list.
+	 */
+	list_move_tail(&packet->list, &queue->txrunning);
+
+	return 0;
+}
+
+static void tx_tasklet(unsigned long d)
+{
+	struct b43_pioqueue *queue = (struct b43_pioqueue *)d;
+	struct b43_wldev *dev = queue->dev;
+	unsigned long flags;
+	struct b43_pio_txpacket *packet, *tmp_packet;
+	int err;
+	u16 txctl;
+
+	spin_lock_irqsave(&dev->wl->irq_lock, flags);
+	if (queue->tx_frozen)
+		goto out_unlock;
+	txctl = b43_pio_read(queue, B43_PIO_TXCTL);
+	if (txctl & B43_PIO_TXCTL_SUSPEND)
+		goto out_unlock;
+
+	list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
+		/* Try to transmit the packet. This can fail, if
+		 * the device queue is full. In case of failure, the
+		 * packet is left in the txqueue.
+		 * If transmission succeed, the packet is moved to txrunning.
+		 * If it is impossible to transmit the packet, it
+		 * is dropped.
+		 */
+		err = pio_tx_packet(packet);
+		if (err)
+			break;
+	}
+      out_unlock:
+	spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+}
+
+static void setup_txqueues(struct b43_pioqueue *queue)
+{
+	struct b43_pio_txpacket *packet;
+	int i;
+
+	queue->nr_txfree = B43_PIO_MAXTXPACKETS;
+	for (i = 0; i < B43_PIO_MAXTXPACKETS; i++) {
+		packet = &(queue->tx_packets_cache[i]);
+
+		packet->queue = queue;
+		INIT_LIST_HEAD(&packet->list);
+		packet->index = i;
+
+		list_add(&packet->list, &queue->txfree);
+	}
+}
+
+static
+struct b43_pioqueue *b43_setup_pioqueue(struct b43_wldev *dev,
+					u16 pio_mmio_base)
+{
+	struct b43_pioqueue *queue;
+	u16 qsize;
+
+	queue = kzalloc(sizeof(*queue), GFP_KERNEL);
+	if (!queue)
+		goto out;
+
+	queue->dev = dev;
+	queue->mmio_base = pio_mmio_base;
+	queue->need_workarounds = (dev->dev->id.revision < 3);
+
+	INIT_LIST_HEAD(&queue->txfree);
+	INIT_LIST_HEAD(&queue->txqueue);
+	INIT_LIST_HEAD(&queue->txrunning);
+	tasklet_init(&queue->txtask, tx_tasklet, (unsigned long)queue);
+
+	b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
+		    & ~B43_MACCTL_BE);
+
+	qsize = b43_read16(dev, queue->mmio_base + B43_PIO_TXQBUFSIZE);
+	if (qsize == 0) {
+		b43err(dev->wl, "This card does not support PIO "
+		       "operation mode. Please use DMA mode "
+		       "(module parameter pio=0).\n");
+		goto err_freequeue;
+	}
+	if (qsize <= B43_PIO_TXQADJUST) {
+		b43err(dev->wl, "PIO tx device-queue too small (%u)\n", qsize);
+		goto err_freequeue;
+	}
+	qsize -= B43_PIO_TXQADJUST;
+	queue->tx_devq_size = qsize;
+
+	setup_txqueues(queue);
+
+      out:
+	return queue;
+
+      err_freequeue:
+	kfree(queue);
+	queue = NULL;
+	goto out;
+}
+
+static void cancel_transfers(struct b43_pioqueue *queue)
+{
+	struct b43_pio_txpacket *packet, *tmp_packet;
+
+	tasklet_disable(&queue->txtask);
+
+	list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
+	    free_txpacket(packet);
+	list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
+	    free_txpacket(packet);
+}
+
+static void b43_destroy_pioqueue(struct b43_pioqueue *queue)
+{
+	if (!queue)
+		return;
+
+	cancel_transfers(queue);
+	kfree(queue);
+}
+
+void b43_pio_free(struct b43_wldev *dev)
+{
+	struct b43_pio *pio;
+
+	if (!b43_using_pio(dev))
+		return;
+	pio = &dev->pio;
+
+	b43_destroy_pioqueue(pio->queue3);
+	pio->queue3 = NULL;
+	b43_destroy_pioqueue(pio->queue2);
+	pio->queue2 = NULL;
+	b43_destroy_pioqueue(pio->queue1);
+	pio->queue1 = NULL;
+	b43_destroy_pioqueue(pio->queue0);
+	pio->queue0 = NULL;
+}
+
+int b43_pio_init(struct b43_wldev *dev)
+{
+	struct b43_pio *pio = &dev->pio;
+	struct b43_pioqueue *queue;
+	int err = -ENOMEM;
+
+	queue = b43_setup_pioqueue(dev, B43_MMIO_PIO1_BASE);
+	if (!queue)
+		goto out;
+	pio->queue0 = queue;
+
+	queue = b43_setup_pioqueue(dev, B43_MMIO_PIO2_BASE);
+	if (!queue)
+		goto err_destroy0;
+	pio->queue1 = queue;
+
+	queue = b43_setup_pioqueue(dev, B43_MMIO_PIO3_BASE);
+	if (!queue)
+		goto err_destroy1;
+	pio->queue2 = queue;
+
+	queue = b43_setup_pioqueue(dev, B43_MMIO_PIO4_BASE);
+	if (!queue)
+		goto err_destroy2;
+	pio->queue3 = queue;
+
+	if (dev->dev->id.revision < 3)
+		dev->irq_savedstate |= B43_IRQ_PIO_WORKAROUND;
+
+	b43dbg(dev->wl, "PIO initialized\n");
+	err = 0;
+      out:
+	return err;
+
+      err_destroy2:
+	b43_destroy_pioqueue(pio->queue2);
+	pio->queue2 = NULL;
+      err_destroy1:
+	b43_destroy_pioqueue(pio->queue1);
+	pio->queue1 = NULL;
+      err_destroy0:
+	b43_destroy_pioqueue(pio->queue0);
+	pio->queue0 = NULL;
+	goto out;
+}
+
+int b43_pio_tx(struct b43_wldev *dev,
+	       struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+	struct b43_pioqueue *queue = dev->pio.queue1;
+	struct b43_pio_txpacket *packet;
+
+	B43_WARN_ON(queue->tx_suspended);
+	B43_WARN_ON(list_empty(&queue->txfree));
+
+	packet = list_entry(queue->txfree.next, struct b43_pio_txpacket, list);
+	packet->skb = skb;
+
+	memset(&packet->txstat, 0, sizeof(packet->txstat));
+	memcpy(&packet->txstat.control, ctl, sizeof(*ctl));
+
+	list_move_tail(&packet->list, &queue->txqueue);
+	queue->nr_txfree--;
+	queue->nr_tx_packets++;
+	B43_WARN_ON(queue->nr_txfree >= B43_PIO_MAXTXPACKETS);
+
+	tasklet_schedule(&queue->txtask);
+
+	return 0;
+}
+
+void b43_pio_handle_txstatus(struct b43_wldev *dev,
+			     const struct b43_txstatus *status)
+{
+	struct b43_pioqueue *queue;
+	struct b43_pio_txpacket *packet;
+
+	queue = parse_cookie(dev, status->cookie, &packet);
+	if (B43_WARN_ON(!queue))
+		return;
+
+	queue->tx_devq_packets--;
+	queue->tx_devq_used -=
+	    (packet->skb->len + sizeof(struct b43_txhdr_fw4));
+
+	if (status->acked) {
+		packet->txstat.flags |= IEEE80211_TX_STATUS_ACK;
+	} else {
+		if (!(packet->txstat.control.flags & IEEE80211_TXCTL_NO_ACK))
+			packet->txstat.excessive_retries = 1;
+	}
+	if (status->frame_count == 0) {
+		/* The frame was not transmitted at all. */
+		packet->txstat.retry_count = 0;
+	} else
+		packet->txstat.retry_count = status->frame_count - 1;
+	ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb,
+				    &(packet->txstat));
+	packet->skb = NULL;
+
+	free_txpacket(packet);
+	/* If there are packets on the txqueue, poke the tasklet
+	 * to transmit them.
+	 */
+	if (!list_empty(&queue->txqueue))
+		tasklet_schedule(&queue->txtask);
+}
+
+void b43_pio_get_tx_stats(struct b43_wldev *dev,
+			  struct ieee80211_tx_queue_stats *stats)
+{
+	struct b43_pio *pio = &dev->pio;
+	struct b43_pioqueue *queue;
+	struct ieee80211_tx_queue_stats_data *data;
+
+	queue = pio->queue1;
+	data = &(stats->data[0]);
+	data->len = B43_PIO_MAXTXPACKETS - queue->nr_txfree;
+	data->limit = B43_PIO_MAXTXPACKETS;
+	data->count = queue->nr_tx_packets;
+}
+
+static void pio_rx_error(struct b43_pioqueue *queue,
+			 int clear_buffers, const char *error)
+{
+	int i;
+
+	b43err(queue->dev->wl, "PIO RX error: %s\n", error);
+	b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_READY);
+	if (clear_buffers) {
+		B43_WARN_ON(queue->mmio_base != B43_MMIO_PIO1_BASE);
+		for (i = 0; i < 15; i++) {
+			/* Dummy read. */
+			b43_pio_read(queue, B43_PIO_RXDATA);
+		}
+	}
+}
+
+void b43_pio_rx(struct b43_pioqueue *queue)
+{
+	__le16 preamble[21] = { 0 };
+	struct b43_rxhdr_fw4 *rxhdr;
+	u16 tmp, len;
+	u32 macstat;
+	int i, preamble_readwords;
+	struct sk_buff *skb;
+
+	tmp = b43_pio_read(queue, B43_PIO_RXCTL);
+	if (!(tmp & B43_PIO_RXCTL_DATAAVAILABLE))
+		return;
+	b43_pio_write(queue, B43_PIO_RXCTL, B43_PIO_RXCTL_DATAAVAILABLE);
+
+	for (i = 0; i < 10; i++) {
+		tmp = b43_pio_read(queue, B43_PIO_RXCTL);
+		if (tmp & B43_PIO_RXCTL_READY)
+			goto data_ready;
+		udelay(10);
+	}
+	b43dbg(queue->dev->wl, "PIO RX timed out\n");
+	return;
+data_ready:
+
+	len = b43_pio_read(queue, B43_PIO_RXDATA);
+	if (unlikely(len > 0x700)) {
+		pio_rx_error(queue, 0, "len > 0x700");
+		return;
+	}
+	if (unlikely(len == 0 && queue->mmio_base != B43_MMIO_PIO4_BASE)) {
+		pio_rx_error(queue, 0, "len == 0");
+		return;
+	}
+	preamble[0] = cpu_to_le16(len);
+	if (queue->mmio_base == B43_MMIO_PIO4_BASE)
+		preamble_readwords = 14 / sizeof(u16);
+	else
+		preamble_readwords = 18 / sizeof(u16);
+	for (i = 0; i < preamble_readwords; i++) {
+		tmp = b43_pio_read(queue, B43_PIO_RXDATA);
+		preamble[i + 1] = cpu_to_le16(tmp);
+	}
+	rxhdr = (struct b43_rxhdr_fw4 *)preamble;
+	macstat = le32_to_cpu(rxhdr->mac_status);
+	if (macstat & B43_RX_MAC_FCSERR) {
+		pio_rx_error(queue,
+			     (queue->mmio_base == B43_MMIO_PIO1_BASE),
+			     "Frame FCS error");
+		return;
+	}
+	if (queue->mmio_base == B43_MMIO_PIO4_BASE) {
+		/* We received an xmit status. */
+		struct b43_hwtxstatus *hw;
+
+		hw = (struct b43_hwtxstatus *)(preamble + 1);
+		b43_handle_hwtxstatus(queue->dev, hw);
+
+		return;
+	}
+
+	skb = dev_alloc_skb(len);
+	if (unlikely(!skb)) {
+		pio_rx_error(queue, 1, "OOM");
+		return;
+	}
+	skb_put(skb, len);
+	for (i = 0; i < len - 1; i += 2) {
+		tmp = b43_pio_read(queue, B43_PIO_RXDATA);
+		*((__le16 *)(skb->data + i)) = cpu_to_le16(tmp);
+	}
+	if (len % 2) {
+		tmp = b43_pio_read(queue, B43_PIO_RXDATA);
+		skb->data[len - 1] = (tmp & 0x00FF);
+/* The specs say the following is required, but
+ * it is wrong and corrupts the PLCP. If we don't do
+ * this, the PLCP seems to be correct. So ifdef it out for now.
+ */
+#if 0
+		if (rxflags2 & B43_RXHDR_FLAGS2_TYPE2FRAME)
+			skb->data[2] = (tmp & 0xFF00) >> 8;
+		else
+			skb->data[0] = (tmp & 0xFF00) >> 8;
+#endif
+	}
+	b43_rx(queue->dev, skb, rxhdr);
+}
+
+void b43_pio_tx_suspend(struct b43_pioqueue *queue)
+{
+	b43_power_saving_ctl_bits(queue->dev, B43_PS_AWAKE);
+	b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL)
+		      | B43_PIO_TXCTL_SUSPEND);
+}
+
+void b43_pio_tx_resume(struct b43_pioqueue *queue)
+{
+	b43_pio_write(queue, B43_PIO_TXCTL, b43_pio_read(queue, B43_PIO_TXCTL)
+		      & ~B43_PIO_TXCTL_SUSPEND);
+	b43_power_saving_ctl_bits(queue->dev, 0);
+	tasklet_schedule(&queue->txtask);
+}
+
+void b43_pio_freeze_txqueues(struct b43_wldev *dev)
+{
+	struct b43_pio *pio;
+
+	B43_WARN_ON(!b43_using_pio(dev));
+	pio = &dev->pio;
+	pio->queue0->tx_frozen = 1;
+	pio->queue1->tx_frozen = 1;
+	pio->queue2->tx_frozen = 1;
+	pio->queue3->tx_frozen = 1;
+}
+
+void b43_pio_thaw_txqueues(struct b43_wldev *dev)
+{
+	struct b43_pio *pio;
+
+	B43_WARN_ON(!b43_using_pio(dev));
+	pio = &dev->pio;
+	pio->queue0->tx_frozen = 0;
+	pio->queue1->tx_frozen = 0;
+	pio->queue2->tx_frozen = 0;
+	pio->queue3->tx_frozen = 0;
+	if (!list_empty(&pio->queue0->txqueue))
+		tasklet_schedule(&pio->queue0->txtask);
+	if (!list_empty(&pio->queue1->txqueue))
+		tasklet_schedule(&pio->queue1->txtask);
+	if (!list_empty(&pio->queue2->txqueue))
+		tasklet_schedule(&pio->queue2->txtask);
+	if (!list_empty(&pio->queue3->txqueue))
+		tasklet_schedule(&pio->queue3->txtask);
+}
diff --git a/drivers/net/wireless/b43/pio.h b/drivers/net/wireless/b43/pio.h
new file mode 100644
index 0000000..34a44c1
--- /dev/null
+++ b/drivers/net/wireless/b43/pio.h
@@ -0,0 +1,152 @@
+#ifndef B43_PIO_H_
+#define B43_PIO_H_
+
+#include "b43.h"
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+
+#define B43_PIO_TXCTL		0x00
+#define B43_PIO_TXDATA		0x02
+#define B43_PIO_TXQBUFSIZE		0x04
+#define B43_PIO_RXCTL		0x08
+#define B43_PIO_RXDATA		0x0A
+
+#define B43_PIO_TXCTL_WRITELO	(1 << 0)
+#define B43_PIO_TXCTL_WRITEHI	(1 << 1)
+#define B43_PIO_TXCTL_COMPLETE	(1 << 2)
+#define B43_PIO_TXCTL_INIT		(1 << 3)
+#define B43_PIO_TXCTL_SUSPEND	(1 << 7)
+
+#define B43_PIO_RXCTL_DATAAVAILABLE	(1 << 0)
+#define B43_PIO_RXCTL_READY		(1 << 1)
+
+/* PIO constants */
+#define B43_PIO_MAXTXDEVQPACKETS	31
+#define B43_PIO_TXQADJUST		80
+
+/* PIO tuning knobs */
+#define B43_PIO_MAXTXPACKETS	256
+
+#ifdef CONFIG_B43_PIO
+
+struct b43_pioqueue;
+struct b43_xmitstatus;
+
+struct b43_pio_txpacket {
+	struct b43_pioqueue *queue;
+	struct sk_buff *skb;
+	struct ieee80211_tx_status txstat;
+	struct list_head list;
+	u16 index; /* Index in the tx_packets_cache */
+};
+
+struct b43_pioqueue {
+	struct b43_wldev *dev;
+	u16 mmio_base;
+
+	bool tx_suspended;
+	bool tx_frozen;
+	bool need_workarounds;	/* Workarounds needed for core.rev < 3 */
+
+	/* Adjusted size of the device internal TX buffer. */
+	u16 tx_devq_size;
+	/* Used octets of the device internal TX buffer. */
+	u16 tx_devq_used;
+	/* Used packet slots in the device internal TX buffer. */
+	u8 tx_devq_packets;
+	/* Packets from the txfree list can
+	 * be taken on incoming TX requests.
+	 */
+	struct list_head txfree;
+	unsigned int nr_txfree;
+	/* Packets on the txqueue are queued,
+	 * but not completely written to the chip, yet.
+	 */
+	struct list_head txqueue;
+	/* Packets on the txrunning queue are completely
+	 * posted to the device. We are waiting for the txstatus.
+	 */
+	struct list_head txrunning;
+	/* Total number or packets sent.
+	 * (This counter can obviously wrap).
+	 */
+	unsigned int nr_tx_packets;
+	struct tasklet_struct txtask;
+	struct b43_pio_txpacket tx_packets_cache[B43_PIO_MAXTXPACKETS];
+};
+
+static inline u16 b43_pio_read(struct b43_pioqueue *queue, u16 offset)
+{
+	return b43_read16(queue->dev, queue->mmio_base + offset);
+}
+
+static inline
+    void b43_pio_write(struct b43_pioqueue *queue, u16 offset, u16 value)
+{
+	b43_write16(queue->dev, queue->mmio_base + offset, value);
+	mmiowb();
+}
+
+int b43_pio_init(struct b43_wldev *dev);
+void b43_pio_free(struct b43_wldev *dev);
+
+int b43_pio_tx(struct b43_wldev *dev,
+	       struct sk_buff *skb, struct ieee80211_tx_control *ctl);
+void b43_pio_handle_txstatus(struct b43_wldev *dev,
+			     const struct b43_txstatus *status);
+void b43_pio_get_tx_stats(struct b43_wldev *dev,
+			  struct ieee80211_tx_queue_stats *stats);
+void b43_pio_rx(struct b43_pioqueue *queue);
+
+/* Suspend TX queue in hardware. */
+void b43_pio_tx_suspend(struct b43_pioqueue *queue);
+void b43_pio_tx_resume(struct b43_pioqueue *queue);
+/* Suspend (freeze) the TX tasklet (software level). */
+void b43_pio_freeze_txqueues(struct b43_wldev *dev);
+void b43_pio_thaw_txqueues(struct b43_wldev *dev);
+
+#else /* CONFIG_B43_PIO */
+
+static inline int b43_pio_init(struct b43_wldev *dev)
+{
+	return 0;
+}
+static inline void b43_pio_free(struct b43_wldev *dev)
+{
+}
+static inline
+    int b43_pio_tx(struct b43_wldev *dev,
+		   struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+	return 0;
+}
+static inline
+    void b43_pio_handle_txstatus(struct b43_wldev *dev,
+				 const struct b43_txstatus *status)
+{
+}
+static inline
+    void b43_pio_get_tx_stats(struct b43_wldev *dev,
+			      struct ieee80211_tx_queue_stats *stats)
+{
+}
+static inline void b43_pio_rx(struct b43_pioqueue *queue)
+{
+}
+static inline void b43_pio_tx_suspend(struct b43_pioqueue *queue)
+{
+}
+static inline void b43_pio_tx_resume(struct b43_pioqueue *queue)
+{
+}
+static inline void b43_pio_freeze_txqueues(struct b43_wldev *dev)
+{
+}
+static inline void b43_pio_thaw_txqueues(struct b43_wldev *dev)
+{
+}
+
+#endif /* CONFIG_B43_PIO */
+#endif /* B43_PIO_H_ */
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c
new file mode 100644
index 0000000..800e0a6
--- /dev/null
+++ b/drivers/net/wireless/b43/rfkill.c
@@ -0,0 +1,184 @@
+/*
+
+  Broadcom B43 wireless driver
+  RFKILL support
+
+  Copyright (c) 2007 Michael Buesch <mb@bu3sch.de>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "rfkill.h"
+#include "b43.h"
+
+
+/* Returns TRUE, if the radio is enabled in hardware. */
+static bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
+{
+	if (dev->phy.rev >= 3) {
+		if (!(b43_read32(dev, B43_MMIO_RADIO_HWENABLED_HI)
+		      & B43_MMIO_RADIO_HWENABLED_HI_MASK))
+			return 1;
+	} else {
+		if (b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO)
+		    & B43_MMIO_RADIO_HWENABLED_LO_MASK)
+			return 1;
+	}
+	return 0;
+}
+
+/* The poll callback for the hardware button. */
+static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
+{
+	struct b43_wldev *dev = poll_dev->private;
+	struct b43_wl *wl = dev->wl;
+	bool enabled;
+
+	mutex_lock(&wl->mutex);
+	B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED);
+	enabled = b43_is_hw_radio_enabled(dev);
+	if (unlikely(enabled != dev->radio_hw_enable)) {
+		dev->radio_hw_enable = enabled;
+		b43info(wl, "Radio hardware status changed to %s\n",
+			enabled ? "ENABLED" : "DISABLED");
+		mutex_unlock(&wl->mutex);
+		input_report_key(poll_dev->input, KEY_WLAN, enabled);
+	} else
+		mutex_unlock(&wl->mutex);
+}
+
+/* Called when the RFKILL toggled in software.
+ * This is called without locking. */
+static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
+{
+	struct b43_wldev *dev = data;
+	struct b43_wl *wl = dev->wl;
+	int err = 0;
+
+	mutex_lock(&wl->mutex);
+	if (b43_status(dev) < B43_STAT_INITIALIZED)
+		goto out_unlock;
+
+	switch (state) {
+	case RFKILL_STATE_ON:
+		if (!dev->radio_hw_enable) {
+			/* No luck. We can't toggle the hardware RF-kill
+			 * button from software. */
+			err = -EBUSY;
+			goto out_unlock;
+		}
+		if (!dev->phy.radio_on)
+			b43_radio_turn_on(dev);
+		break;
+	case RFKILL_STATE_OFF:
+		if (dev->phy.radio_on)
+			b43_radio_turn_off(dev, 0);
+		break;
+	}
+
+out_unlock:
+	mutex_unlock(&wl->mutex);
+
+	return err;
+}
+
+char * b43_rfkill_led_name(struct b43_wldev *dev)
+{
+	struct b43_wl *wl = dev->wl;
+
+	if (!wl->rfkill.rfkill)
+		return NULL;
+	return rfkill_get_led_name(wl->rfkill.rfkill);
+}
+
+void b43_rfkill_init(struct b43_wldev *dev)
+{
+	struct b43_wl *wl = dev->wl;
+	struct b43_rfkill *rfk = &(wl->rfkill);
+	int err;
+
+	if (rfk->rfkill) {
+		err = rfkill_register(rfk->rfkill);
+		if (err) {
+			b43warn(wl, "Failed to register RF-kill button\n");
+			goto err_free_rfk;
+		}
+	}
+	if (rfk->poll_dev) {
+		err = input_register_polled_device(rfk->poll_dev);
+		if (err) {
+			b43warn(wl, "Failed to register RF-kill polldev\n");
+			goto err_free_polldev;
+		}
+	}
+
+	return;
+err_free_rfk:
+	rfkill_free(rfk->rfkill);
+	rfk->rfkill = NULL;
+err_free_polldev:
+	input_free_polled_device(rfk->poll_dev);
+	rfk->poll_dev = NULL;
+}
+
+void b43_rfkill_exit(struct b43_wldev *dev)
+{
+	struct b43_rfkill *rfk = &(dev->wl->rfkill);
+
+	if (rfk->poll_dev)
+		input_unregister_polled_device(rfk->poll_dev);
+	if (rfk->rfkill)
+		rfkill_unregister(rfk->rfkill);
+}
+
+void b43_rfkill_alloc(struct b43_wldev *dev)
+{
+	struct b43_wl *wl = dev->wl;
+	struct b43_rfkill *rfk = &(wl->rfkill);
+
+	snprintf(rfk->name, sizeof(rfk->name),
+		 "b43-%s", wiphy_name(wl->hw->wiphy));
+
+	rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
+	if (!rfk->rfkill) {
+		b43warn(wl, "Failed to allocate RF-kill button\n");
+		return;
+	}
+	rfk->rfkill->name = rfk->name;
+	rfk->rfkill->state = RFKILL_STATE_ON;
+	rfk->rfkill->data = dev;
+	rfk->rfkill->toggle_radio = b43_rfkill_soft_toggle;
+	rfk->rfkill->user_claim_unsupported = 1;
+
+	rfk->poll_dev = input_allocate_polled_device();
+	if (rfk->poll_dev) {
+		rfk->poll_dev->private = dev;
+		rfk->poll_dev->poll = b43_rfkill_poll;
+		rfk->poll_dev->poll_interval = 1000; /* msecs */
+	} else
+		b43warn(wl, "Failed to allocate RF-kill polldev\n");
+}
+
+void b43_rfkill_free(struct b43_wldev *dev)
+{
+	struct b43_rfkill *rfk = &(dev->wl->rfkill);
+
+	input_free_polled_device(rfk->poll_dev);
+	rfk->poll_dev = NULL;
+	rfkill_free(rfk->rfkill);
+	rfk->rfkill = NULL;
+}
diff --git a/drivers/net/wireless/b43/rfkill.h b/drivers/net/wireless/b43/rfkill.h
new file mode 100644
index 0000000..29544e8
--- /dev/null
+++ b/drivers/net/wireless/b43/rfkill.h
@@ -0,0 +1,58 @@
+#ifndef B43_RFKILL_H_
+#define B43_RFKILL_H_
+
+struct b43_wldev;
+
+
+#ifdef CONFIG_B43_RFKILL
+
+#include <linux/rfkill.h>
+#include <linux/input-polldev.h>
+
+
+struct b43_rfkill {
+	/* The RFKILL subsystem data structure */
+	struct rfkill *rfkill;
+	/* The poll device for the RFKILL input button */
+	struct input_polled_dev *poll_dev;
+	/* The unique name of this rfkill switch */
+	char name[32];
+};
+
+/* All the init functions return void, because we are not interested
+ * in failing the b43 init process when rfkill init failed. */
+void b43_rfkill_alloc(struct b43_wldev *dev);
+void b43_rfkill_free(struct b43_wldev *dev);
+void b43_rfkill_init(struct b43_wldev *dev);
+void b43_rfkill_exit(struct b43_wldev *dev);
+
+char * b43_rfkill_led_name(struct b43_wldev *dev);
+
+
+#else /* CONFIG_B43_RFKILL */
+/* No RFKILL support. */
+
+struct b43_rfkill {
+	/* empty */
+};
+
+static inline void b43_rfkill_alloc(struct b43_wldev *dev)
+{
+}
+static inline void b43_rfkill_free(struct b43_wldev *dev)
+{
+}
+static inline void b43_rfkill_init(struct b43_wldev *dev)
+{
+}
+static inline void b43_rfkill_exit(struct b43_wldev *dev)
+{
+}
+static inline char * b43_rfkill_led_name(struct b43_wldev *dev)
+{
+	return NULL;
+}
+
+#endif /* CONFIG_B43_RFKILL */
+
+#endif /* B43_RFKILL_H_ */
diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c
new file mode 100644
index 0000000..fcb7773
--- /dev/null
+++ b/drivers/net/wireless/b43/sysfs.c
@@ -0,0 +1,235 @@
+/*
+
+  Broadcom B43 wireless driver
+
+  SYSFS support routines
+
+  Copyright (c) 2006 Michael Buesch <mb@bu3sch.de>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "sysfs.h"
+#include "main.h"
+#include "phy.h"
+
+#include <linux/capability.h>
+
+#define GENERIC_FILESIZE	64
+
+static int get_integer(const char *buf, size_t count)
+{
+	char tmp[10 + 1] = { 0 };
+	int ret = -EINVAL;
+
+	if (count == 0)
+		goto out;
+	count = min(count, (size_t) 10);
+	memcpy(tmp, buf, count);
+	ret = simple_strtol(tmp, NULL, 10);
+      out:
+	return ret;
+}
+
+static int get_boolean(const char *buf, size_t count)
+{
+	if (count != 0) {
+		if (buf[0] == '1')
+			return 1;
+		if (buf[0] == '0')
+			return 0;
+		if (count >= 4 && memcmp(buf, "true", 4) == 0)
+			return 1;
+		if (count >= 5 && memcmp(buf, "false", 5) == 0)
+			return 0;
+		if (count >= 3 && memcmp(buf, "yes", 3) == 0)
+			return 1;
+		if (count >= 2 && memcmp(buf, "no", 2) == 0)
+			return 0;
+		if (count >= 2 && memcmp(buf, "on", 2) == 0)
+			return 1;
+		if (count >= 3 && memcmp(buf, "off", 3) == 0)
+			return 0;
+	}
+	return -EINVAL;
+}
+
+static ssize_t b43_attr_interfmode_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct b43_wldev *wldev = dev_to_b43_wldev(dev);
+	ssize_t count = 0;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	mutex_lock(&wldev->wl->mutex);
+
+	switch (wldev->phy.interfmode) {
+	case B43_INTERFMODE_NONE:
+		count =
+		    snprintf(buf, PAGE_SIZE,
+			     "0 (No Interference Mitigation)\n");
+		break;
+	case B43_INTERFMODE_NONWLAN:
+		count =
+		    snprintf(buf, PAGE_SIZE,
+			     "1 (Non-WLAN Interference Mitigation)\n");
+		break;
+	case B43_INTERFMODE_MANUALWLAN:
+		count =
+		    snprintf(buf, PAGE_SIZE,
+			     "2 (WLAN Interference Mitigation)\n");
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+
+	mutex_unlock(&wldev->wl->mutex);
+
+	return count;
+}
+
+static ssize_t b43_attr_interfmode_store(struct device *dev,
+					 struct device_attribute *attr,
+					 const char *buf, size_t count)
+{
+	struct b43_wldev *wldev = dev_to_b43_wldev(dev);
+	unsigned long flags;
+	int err;
+	int mode;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	mode = get_integer(buf, count);
+	switch (mode) {
+	case 0:
+		mode = B43_INTERFMODE_NONE;
+		break;
+	case 1:
+		mode = B43_INTERFMODE_NONWLAN;
+		break;
+	case 2:
+		mode = B43_INTERFMODE_MANUALWLAN;
+		break;
+	case 3:
+		mode = B43_INTERFMODE_AUTOWLAN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mutex_lock(&wldev->wl->mutex);
+	spin_lock_irqsave(&wldev->wl->irq_lock, flags);
+
+	err = b43_radio_set_interference_mitigation(wldev, mode);
+	if (err) {
+		b43err(wldev->wl, "Interference Mitigation not "
+		       "supported by device\n");
+	}
+	mmiowb();
+	spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
+	mutex_unlock(&wldev->wl->mutex);
+
+	return err ? err : count;
+}
+
+static DEVICE_ATTR(interference, 0644,
+		   b43_attr_interfmode_show, b43_attr_interfmode_store);
+
+static ssize_t b43_attr_preamble_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct b43_wldev *wldev = dev_to_b43_wldev(dev);
+	ssize_t count;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	mutex_lock(&wldev->wl->mutex);
+
+	if (wldev->short_preamble)
+		count =
+		    snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
+	else
+		count =
+		    snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
+
+	mutex_unlock(&wldev->wl->mutex);
+
+	return count;
+}
+
+static ssize_t b43_attr_preamble_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count)
+{
+	struct b43_wldev *wldev = dev_to_b43_wldev(dev);
+	unsigned long flags;
+	int value;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	value = get_boolean(buf, count);
+	if (value < 0)
+		return value;
+	mutex_lock(&wldev->wl->mutex);
+	spin_lock_irqsave(&wldev->wl->irq_lock, flags);
+
+	wldev->short_preamble = !!value;
+
+	spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
+	mutex_unlock(&wldev->wl->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(shortpreamble, 0644,
+		   b43_attr_preamble_show, b43_attr_preamble_store);
+
+int b43_sysfs_register(struct b43_wldev *wldev)
+{
+	struct device *dev = wldev->dev->dev;
+	int err;
+
+	B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED);
+
+	err = device_create_file(dev, &dev_attr_interference);
+	if (err)
+		goto out;
+	err = device_create_file(dev, &dev_attr_shortpreamble);
+	if (err)
+		goto err_remove_interfmode;
+
+      out:
+	return err;
+      err_remove_interfmode:
+	device_remove_file(dev, &dev_attr_interference);
+	goto out;
+}
+
+void b43_sysfs_unregister(struct b43_wldev *wldev)
+{
+	struct device *dev = wldev->dev->dev;
+
+	device_remove_file(dev, &dev_attr_shortpreamble);
+	device_remove_file(dev, &dev_attr_interference);
+}
diff --git a/drivers/net/wireless/b43/sysfs.h b/drivers/net/wireless/b43/sysfs.h
new file mode 100644
index 0000000..12bda9e
--- /dev/null
+++ b/drivers/net/wireless/b43/sysfs.h
@@ -0,0 +1,9 @@
+#ifndef B43_SYSFS_H_
+#define B43_SYSFS_H_
+
+struct b43_wldev;
+
+int b43_sysfs_register(struct b43_wldev *dev);
+void b43_sysfs_unregister(struct b43_wldev *dev);
+
+#endif /* B43_SYSFS_H_ */
diff --git a/drivers/net/wireless/b43/tables.c b/drivers/net/wireless/b43/tables.c
new file mode 100644
index 0000000..15a8718
--- /dev/null
+++ b/drivers/net/wireless/b43/tables.c
@@ -0,0 +1,375 @@
+/*
+
+  Broadcom B43 wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+  Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2006, 2006 Michael Buesch <mb@bu3sch.de>
+  Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+  Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "tables.h"
+#include "phy.h"
+
+const u32 b43_tab_rotor[] = {
+	0xFEB93FFD, 0xFEC63FFD,	/* 0 */
+	0xFED23FFD, 0xFEDF3FFD,
+	0xFEEC3FFE, 0xFEF83FFE,
+	0xFF053FFE, 0xFF113FFE,
+	0xFF1E3FFE, 0xFF2A3FFF,	/* 8 */
+	0xFF373FFF, 0xFF443FFF,
+	0xFF503FFF, 0xFF5D3FFF,
+	0xFF693FFF, 0xFF763FFF,
+	0xFF824000, 0xFF8F4000,	/* 16 */
+	0xFF9B4000, 0xFFA84000,
+	0xFFB54000, 0xFFC14000,
+	0xFFCE4000, 0xFFDA4000,
+	0xFFE74000, 0xFFF34000,	/* 24 */
+	0x00004000, 0x000D4000,
+	0x00194000, 0x00264000,
+	0x00324000, 0x003F4000,
+	0x004B4000, 0x00584000,	/* 32 */
+	0x00654000, 0x00714000,
+	0x007E4000, 0x008A3FFF,
+	0x00973FFF, 0x00A33FFF,
+	0x00B03FFF, 0x00BC3FFF,	/* 40 */
+	0x00C93FFF, 0x00D63FFF,
+	0x00E23FFE, 0x00EF3FFE,
+	0x00FB3FFE, 0x01083FFE,
+	0x01143FFE, 0x01213FFD,	/* 48 */
+	0x012E3FFD, 0x013A3FFD,
+	0x01473FFD,
+};
+
+const u32 b43_tab_retard[] = {
+	0xDB93CB87, 0xD666CF64,	/* 0 */
+	0xD1FDD358, 0xCDA6D826,
+	0xCA38DD9F, 0xC729E2B4,
+	0xC469E88E, 0xC26AEE2B,
+	0xC0DEF46C, 0xC073FA62,	/* 8 */
+	0xC01D00D5, 0xC0760743,
+	0xC1560D1E, 0xC2E51369,
+	0xC4ED18FF, 0xC7AC1ED7,
+	0xCB2823B2, 0xCEFA28D9,	/* 16 */
+	0xD2F62D3F, 0xD7BB3197,
+	0xDCE53568, 0xE1FE3875,
+	0xE7D13B35, 0xED663D35,
+	0xF39B3EC4, 0xF98E3FA7,	/* 24 */
+	0x00004000, 0x06723FA7,
+	0x0C653EC4, 0x129A3D35,
+	0x182F3B35, 0x1E023875,
+	0x231B3568, 0x28453197,	/* 32 */
+	0x2D0A2D3F, 0x310628D9,
+	0x34D823B2, 0x38541ED7,
+	0x3B1318FF, 0x3D1B1369,
+	0x3EAA0D1E, 0x3F8A0743,	/* 40 */
+	0x3FE300D5, 0x3F8DFA62,
+	0x3F22F46C, 0x3D96EE2B,
+	0x3B97E88E, 0x38D7E2B4,
+	0x35C8DD9F, 0x325AD826,	/* 48 */
+	0x2E03D358, 0x299ACF64,
+	0x246DCB87,
+};
+
+const u16 b43_tab_finefreqa[] = {
+	0x0082, 0x0082, 0x0102, 0x0182,	/* 0 */
+	0x0202, 0x0282, 0x0302, 0x0382,
+	0x0402, 0x0482, 0x0502, 0x0582,
+	0x05E2, 0x0662, 0x06E2, 0x0762,
+	0x07E2, 0x0842, 0x08C2, 0x0942,	/* 16 */
+	0x09C2, 0x0A22, 0x0AA2, 0x0B02,
+	0x0B82, 0x0BE2, 0x0C62, 0x0CC2,
+	0x0D42, 0x0DA2, 0x0E02, 0x0E62,
+	0x0EE2, 0x0F42, 0x0FA2, 0x1002,	/* 32 */
+	0x1062, 0x10C2, 0x1122, 0x1182,
+	0x11E2, 0x1242, 0x12A2, 0x12E2,
+	0x1342, 0x13A2, 0x1402, 0x1442,
+	0x14A2, 0x14E2, 0x1542, 0x1582,	/* 48 */
+	0x15E2, 0x1622, 0x1662, 0x16C1,
+	0x1701, 0x1741, 0x1781, 0x17E1,
+	0x1821, 0x1861, 0x18A1, 0x18E1,
+	0x1921, 0x1961, 0x19A1, 0x19E1,	/* 64 */
+	0x1A21, 0x1A61, 0x1AA1, 0x1AC1,
+	0x1B01, 0x1B41, 0x1B81, 0x1BA1,
+	0x1BE1, 0x1C21, 0x1C41, 0x1C81,
+	0x1CA1, 0x1CE1, 0x1D01, 0x1D41,	/* 80 */
+	0x1D61, 0x1DA1, 0x1DC1, 0x1E01,
+	0x1E21, 0x1E61, 0x1E81, 0x1EA1,
+	0x1EE1, 0x1F01, 0x1F21, 0x1F41,
+	0x1F81, 0x1FA1, 0x1FC1, 0x1FE1,	/* 96 */
+	0x2001, 0x2041, 0x2061, 0x2081,
+	0x20A1, 0x20C1, 0x20E1, 0x2101,
+	0x2121, 0x2141, 0x2161, 0x2181,
+	0x21A1, 0x21C1, 0x21E1, 0x2201,	/* 112 */
+	0x2221, 0x2241, 0x2261, 0x2281,
+	0x22A1, 0x22C1, 0x22C1, 0x22E1,
+	0x2301, 0x2321, 0x2341, 0x2361,
+	0x2361, 0x2381, 0x23A1, 0x23C1,	/* 128 */
+	0x23E1, 0x23E1, 0x2401, 0x2421,
+	0x2441, 0x2441, 0x2461, 0x2481,
+	0x2481, 0x24A1, 0x24C1, 0x24C1,
+	0x24E1, 0x2501, 0x2501, 0x2521,	/* 144 */
+	0x2541, 0x2541, 0x2561, 0x2561,
+	0x2581, 0x25A1, 0x25A1, 0x25C1,
+	0x25C1, 0x25E1, 0x2601, 0x2601,
+	0x2621, 0x2621, 0x2641, 0x2641,	/* 160 */
+	0x2661, 0x2661, 0x2681, 0x2681,
+	0x26A1, 0x26A1, 0x26C1, 0x26C1,
+	0x26E1, 0x26E1, 0x2701, 0x2701,
+	0x2721, 0x2721, 0x2740, 0x2740,	/* 176 */
+	0x2760, 0x2760, 0x2780, 0x2780,
+	0x2780, 0x27A0, 0x27A0, 0x27C0,
+	0x27C0, 0x27E0, 0x27E0, 0x27E0,
+	0x2800, 0x2800, 0x2820, 0x2820,	/* 192 */
+	0x2820, 0x2840, 0x2840, 0x2840,
+	0x2860, 0x2860, 0x2880, 0x2880,
+	0x2880, 0x28A0, 0x28A0, 0x28A0,
+	0x28C0, 0x28C0, 0x28C0, 0x28E0,	/* 208 */
+	0x28E0, 0x28E0, 0x2900, 0x2900,
+	0x2900, 0x2920, 0x2920, 0x2920,
+	0x2940, 0x2940, 0x2940, 0x2960,
+	0x2960, 0x2960, 0x2960, 0x2980,	/* 224 */
+	0x2980, 0x2980, 0x29A0, 0x29A0,
+	0x29A0, 0x29A0, 0x29C0, 0x29C0,
+	0x29C0, 0x29E0, 0x29E0, 0x29E0,
+	0x29E0, 0x2A00, 0x2A00, 0x2A00,	/* 240 */
+	0x2A00, 0x2A20, 0x2A20, 0x2A20,
+	0x2A20, 0x2A40, 0x2A40, 0x2A40,
+	0x2A40, 0x2A60, 0x2A60, 0x2A60,
+};
+
+const u16 b43_tab_finefreqg[] = {
+	0x0089, 0x02E9, 0x0409, 0x04E9,	/* 0 */
+	0x05A9, 0x0669, 0x0709, 0x0789,
+	0x0829, 0x08A9, 0x0929, 0x0989,
+	0x0A09, 0x0A69, 0x0AC9, 0x0B29,
+	0x0BA9, 0x0BE9, 0x0C49, 0x0CA9,	/* 16 */
+	0x0D09, 0x0D69, 0x0DA9, 0x0E09,
+	0x0E69, 0x0EA9, 0x0F09, 0x0F49,
+	0x0FA9, 0x0FE9, 0x1029, 0x1089,
+	0x10C9, 0x1109, 0x1169, 0x11A9,	/* 32 */
+	0x11E9, 0x1229, 0x1289, 0x12C9,
+	0x1309, 0x1349, 0x1389, 0x13C9,
+	0x1409, 0x1449, 0x14A9, 0x14E9,
+	0x1529, 0x1569, 0x15A9, 0x15E9,	/* 48 */
+	0x1629, 0x1669, 0x16A9, 0x16E8,
+	0x1728, 0x1768, 0x17A8, 0x17E8,
+	0x1828, 0x1868, 0x18A8, 0x18E8,
+	0x1928, 0x1968, 0x19A8, 0x19E8,	/* 64 */
+	0x1A28, 0x1A68, 0x1AA8, 0x1AE8,
+	0x1B28, 0x1B68, 0x1BA8, 0x1BE8,
+	0x1C28, 0x1C68, 0x1CA8, 0x1CE8,
+	0x1D28, 0x1D68, 0x1DC8, 0x1E08,	/* 80 */
+	0x1E48, 0x1E88, 0x1EC8, 0x1F08,
+	0x1F48, 0x1F88, 0x1FE8, 0x2028,
+	0x2068, 0x20A8, 0x2108, 0x2148,
+	0x2188, 0x21C8, 0x2228, 0x2268,	/* 96 */
+	0x22C8, 0x2308, 0x2348, 0x23A8,
+	0x23E8, 0x2448, 0x24A8, 0x24E8,
+	0x2548, 0x25A8, 0x2608, 0x2668,
+	0x26C8, 0x2728, 0x2787, 0x27E7,	/* 112 */
+	0x2847, 0x28C7, 0x2947, 0x29A7,
+	0x2A27, 0x2AC7, 0x2B47, 0x2BE7,
+	0x2CA7, 0x2D67, 0x2E47, 0x2F67,
+	0x3247, 0x3526, 0x3646, 0x3726,	/* 128 */
+	0x3806, 0x38A6, 0x3946, 0x39E6,
+	0x3A66, 0x3AE6, 0x3B66, 0x3BC6,
+	0x3C45, 0x3CA5, 0x3D05, 0x3D85,
+	0x3DE5, 0x3E45, 0x3EA5, 0x3EE5,	/* 144 */
+	0x3F45, 0x3FA5, 0x4005, 0x4045,
+	0x40A5, 0x40E5, 0x4145, 0x4185,
+	0x41E5, 0x4225, 0x4265, 0x42C5,
+	0x4305, 0x4345, 0x43A5, 0x43E5,	/* 160 */
+	0x4424, 0x4464, 0x44C4, 0x4504,
+	0x4544, 0x4584, 0x45C4, 0x4604,
+	0x4644, 0x46A4, 0x46E4, 0x4724,
+	0x4764, 0x47A4, 0x47E4, 0x4824,	/* 176 */
+	0x4864, 0x48A4, 0x48E4, 0x4924,
+	0x4964, 0x49A4, 0x49E4, 0x4A24,
+	0x4A64, 0x4AA4, 0x4AE4, 0x4B23,
+	0x4B63, 0x4BA3, 0x4BE3, 0x4C23,	/* 192 */
+	0x4C63, 0x4CA3, 0x4CE3, 0x4D23,
+	0x4D63, 0x4DA3, 0x4DE3, 0x4E23,
+	0x4E63, 0x4EA3, 0x4EE3, 0x4F23,
+	0x4F63, 0x4FC3, 0x5003, 0x5043,	/* 208 */
+	0x5083, 0x50C3, 0x5103, 0x5143,
+	0x5183, 0x51E2, 0x5222, 0x5262,
+	0x52A2, 0x52E2, 0x5342, 0x5382,
+	0x53C2, 0x5402, 0x5462, 0x54A2,	/* 224 */
+	0x5502, 0x5542, 0x55A2, 0x55E2,
+	0x5642, 0x5682, 0x56E2, 0x5722,
+	0x5782, 0x57E1, 0x5841, 0x58A1,
+	0x5901, 0x5961, 0x59C1, 0x5A21,	/* 240 */
+	0x5AA1, 0x5B01, 0x5B81, 0x5BE1,
+	0x5C61, 0x5D01, 0x5D80, 0x5E20,
+	0x5EE0, 0x5FA0, 0x6080, 0x61C0,
+};
+
+const u16 b43_tab_noisea2[] = {
+	0x0001, 0x0001, 0x0001, 0xFFFE,
+	0xFFFE, 0x3FFF, 0x1000, 0x0393,
+};
+
+const u16 b43_tab_noisea3[] = {
+	0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+	0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+};
+
+const u16 b43_tab_noiseg1[] = {
+	0x013C, 0x01F5, 0x031A, 0x0631,
+	0x0001, 0x0001, 0x0001, 0x0001,
+};
+
+const u16 b43_tab_noiseg2[] = {
+	0x5484, 0x3C40, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+const u16 b43_tab_noisescaleg1[] = {
+	0x6C77, 0x5162, 0x3B40, 0x3335,	/* 0 */
+	0x2F2D, 0x2A2A, 0x2527, 0x1F21,
+	0x1A1D, 0x1719, 0x1616, 0x1414,
+	0x1414, 0x1400, 0x1414, 0x1614,
+	0x1716, 0x1A19, 0x1F1D, 0x2521,	/* 16 */
+	0x2A27, 0x2F2A, 0x332D, 0x3B35,
+	0x5140, 0x6C62, 0x0077,
+};
+
+const u16 b43_tab_noisescaleg2[] = {
+	0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7,	/* 0 */
+	0xB2B0, 0xADAD, 0xA7A9, 0x9FA1,
+	0x969B, 0x9195, 0x8F8F, 0x8A8A,
+	0x8A8A, 0x8A00, 0x8A8A, 0x8F8A,
+	0x918F, 0x9695, 0x9F9B, 0xA7A1,	/* 16 */
+	0xADA9, 0xB2AD, 0xB6B0, 0xBCB7,
+	0xCBC0, 0xD8D4, 0x00DD,
+};
+
+const u16 b43_tab_noisescaleg3[] = {
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,	/* 0 */
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+	0xA4A4, 0xA400, 0xA4A4, 0xA4A4,
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,	/* 16 */
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+	0xA4A4, 0xA4A4, 0x00A4,
+};
+
+const u16 b43_tab_sigmasqr1[] = {
+	0x007A, 0x0075, 0x0071, 0x006C,	/* 0 */
+	0x0067, 0x0063, 0x005E, 0x0059,
+	0x0054, 0x0050, 0x004B, 0x0046,
+	0x0042, 0x003D, 0x003D, 0x003D,
+	0x003D, 0x003D, 0x003D, 0x003D,	/* 16 */
+	0x003D, 0x003D, 0x003D, 0x003D,
+	0x003D, 0x003D, 0x0000, 0x003D,
+	0x003D, 0x003D, 0x003D, 0x003D,
+	0x003D, 0x003D, 0x003D, 0x003D,	/* 32 */
+	0x003D, 0x003D, 0x003D, 0x003D,
+	0x0042, 0x0046, 0x004B, 0x0050,
+	0x0054, 0x0059, 0x005E, 0x0063,
+	0x0067, 0x006C, 0x0071, 0x0075,	/* 48 */
+	0x007A,
+};
+
+const u16 b43_tab_sigmasqr2[] = {
+	0x00DE, 0x00DC, 0x00DA, 0x00D8,	/* 0 */
+	0x00D6, 0x00D4, 0x00D2, 0x00CF,
+	0x00CD, 0x00CA, 0x00C7, 0x00C4,
+	0x00C1, 0x00BE, 0x00BE, 0x00BE,
+	0x00BE, 0x00BE, 0x00BE, 0x00BE,	/* 16 */
+	0x00BE, 0x00BE, 0x00BE, 0x00BE,
+	0x00BE, 0x00BE, 0x0000, 0x00BE,
+	0x00BE, 0x00BE, 0x00BE, 0x00BE,
+	0x00BE, 0x00BE, 0x00BE, 0x00BE,	/* 32 */
+	0x00BE, 0x00BE, 0x00BE, 0x00BE,
+	0x00C1, 0x00C4, 0x00C7, 0x00CA,
+	0x00CD, 0x00CF, 0x00D2, 0x00D4,
+	0x00D6, 0x00D8, 0x00DA, 0x00DC,	/* 48 */
+	0x00DE,
+};
+
+static inline void assert_sizes(void)
+{
+	BUILD_BUG_ON(B43_TAB_ROTOR_SIZE != ARRAY_SIZE(b43_tab_rotor));
+	BUILD_BUG_ON(B43_TAB_RETARD_SIZE != ARRAY_SIZE(b43_tab_retard));
+	BUILD_BUG_ON(B43_TAB_FINEFREQA_SIZE != ARRAY_SIZE(b43_tab_finefreqa));
+	BUILD_BUG_ON(B43_TAB_FINEFREQG_SIZE != ARRAY_SIZE(b43_tab_finefreqg));
+	BUILD_BUG_ON(B43_TAB_NOISEA2_SIZE != ARRAY_SIZE(b43_tab_noisea2));
+	BUILD_BUG_ON(B43_TAB_NOISEA3_SIZE != ARRAY_SIZE(b43_tab_noisea3));
+	BUILD_BUG_ON(B43_TAB_NOISEG1_SIZE != ARRAY_SIZE(b43_tab_noiseg1));
+	BUILD_BUG_ON(B43_TAB_NOISEG2_SIZE != ARRAY_SIZE(b43_tab_noiseg2));
+	BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+		     ARRAY_SIZE(b43_tab_noisescaleg1));
+	BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+		     ARRAY_SIZE(b43_tab_noisescaleg2));
+	BUILD_BUG_ON(B43_TAB_NOISESCALEG_SIZE !=
+		     ARRAY_SIZE(b43_tab_noisescaleg3));
+	BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr1));
+	BUILD_BUG_ON(B43_TAB_SIGMASQR_SIZE != ARRAY_SIZE(b43_tab_sigmasqr2));
+}
+
+u16 b43_ofdmtab_read16(struct b43_wldev *dev, u16 table, u16 offset)
+{
+	assert_sizes();
+
+	b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+	return b43_phy_read(dev, B43_PHY_OTABLEI);
+}
+
+void b43_ofdmtab_write16(struct b43_wldev *dev, u16 table,
+			 u16 offset, u16 value)
+{
+	b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+	b43_phy_write(dev, B43_PHY_OTABLEI, value);
+}
+
+u32 b43_ofdmtab_read32(struct b43_wldev *dev, u16 table, u16 offset)
+{
+	u32 ret;
+
+	b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+	ret = b43_phy_read(dev, B43_PHY_OTABLEQ);
+	ret <<= 16;
+	ret |= b43_phy_read(dev, B43_PHY_OTABLEI);
+
+	return ret;
+}
+
+void b43_ofdmtab_write32(struct b43_wldev *dev, u16 table,
+			 u16 offset, u32 value)
+{
+	b43_phy_write(dev, B43_PHY_OTABLECTL, table + offset);
+	b43_phy_write(dev, B43_PHY_OTABLEI, value);
+	b43_phy_write(dev, B43_PHY_OTABLEQ, (value >> 16));
+}
+
+u16 b43_gtab_read(struct b43_wldev *dev, u16 table, u16 offset)
+{
+	b43_phy_write(dev, B43_PHY_GTABCTL, table + offset);
+	return b43_phy_read(dev, B43_PHY_GTABDATA);
+}
+
+void b43_gtab_write(struct b43_wldev *dev, u16 table, u16 offset, u16 value)
+{
+	b43_phy_write(dev, B43_PHY_GTABCTL, table + offset);
+	b43_phy_write(dev, B43_PHY_GTABDATA, value);
+}
diff --git a/drivers/net/wireless/b43/tables.h b/drivers/net/wireless/b43/tables.h
new file mode 100644
index 0000000..64635d7
--- /dev/null
+++ b/drivers/net/wireless/b43/tables.h
@@ -0,0 +1,28 @@
+#ifndef B43_TABLES_H_
+#define B43_TABLES_H_
+
+#define B43_TAB_ROTOR_SIZE		53
+extern const u32 b43_tab_rotor[];
+#define B43_TAB_RETARD_SIZE		53
+extern const u32 b43_tab_retard[];
+#define B43_TAB_FINEFREQA_SIZE	256
+extern const u16 b43_tab_finefreqa[];
+#define B43_TAB_FINEFREQG_SIZE	256
+extern const u16 b43_tab_finefreqg[];
+#define B43_TAB_NOISEA2_SIZE	8
+extern const u16 b43_tab_noisea2[];
+#define B43_TAB_NOISEA3_SIZE	8
+extern const u16 b43_tab_noisea3[];
+#define B43_TAB_NOISEG1_SIZE	8
+extern const u16 b43_tab_noiseg1[];
+#define B43_TAB_NOISEG2_SIZE	8
+extern const u16 b43_tab_noiseg2[];
+#define B43_TAB_NOISESCALEG_SIZE	27
+extern const u16 b43_tab_noisescaleg1[];
+extern const u16 b43_tab_noisescaleg2[];
+extern const u16 b43_tab_noisescaleg3[];
+#define B43_TAB_SIGMASQR_SIZE	53
+extern const u16 b43_tab_sigmasqr1[];
+extern const u16 b43_tab_sigmasqr2[];
+
+#endif /* B43_TABLES_H_ */
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
new file mode 100644
index 0000000..0bd6f8a
--- /dev/null
+++ b/drivers/net/wireless/b43/xmit.c
@@ -0,0 +1,650 @@
+/*
+
+  Broadcom B43 wireless driver
+
+  Transmission (TX/RX) related functions.
+
+  Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+  Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
+  Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "xmit.h"
+#include "phy.h"
+#include "dma.h"
+#include "pio.h"
+
+/* Extract the bitrate out of a CCK PLCP header. */
+static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp)
+{
+	switch (plcp->raw[0]) {
+	case 0x0A:
+		return B43_CCK_RATE_1MB;
+	case 0x14:
+		return B43_CCK_RATE_2MB;
+	case 0x37:
+		return B43_CCK_RATE_5MB;
+	case 0x6E:
+		return B43_CCK_RATE_11MB;
+	}
+	B43_WARN_ON(1);
+	return 0;
+}
+
+/* Extract the bitrate out of an OFDM PLCP header. */
+static u8 b43_plcp_get_bitrate_ofdm(struct b43_plcp_hdr6 *plcp)
+{
+	switch (plcp->raw[0] & 0xF) {
+	case 0xB:
+		return B43_OFDM_RATE_6MB;
+	case 0xF:
+		return B43_OFDM_RATE_9MB;
+	case 0xA:
+		return B43_OFDM_RATE_12MB;
+	case 0xE:
+		return B43_OFDM_RATE_18MB;
+	case 0x9:
+		return B43_OFDM_RATE_24MB;
+	case 0xD:
+		return B43_OFDM_RATE_36MB;
+	case 0x8:
+		return B43_OFDM_RATE_48MB;
+	case 0xC:
+		return B43_OFDM_RATE_54MB;
+	}
+	B43_WARN_ON(1);
+	return 0;
+}
+
+u8 b43_plcp_get_ratecode_cck(const u8 bitrate)
+{
+	switch (bitrate) {
+	case B43_CCK_RATE_1MB:
+		return 0x0A;
+	case B43_CCK_RATE_2MB:
+		return 0x14;
+	case B43_CCK_RATE_5MB:
+		return 0x37;
+	case B43_CCK_RATE_11MB:
+		return 0x6E;
+	}
+	B43_WARN_ON(1);
+	return 0;
+}
+
+u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate)
+{
+	switch (bitrate) {
+	case B43_OFDM_RATE_6MB:
+		return 0xB;
+	case B43_OFDM_RATE_9MB:
+		return 0xF;
+	case B43_OFDM_RATE_12MB:
+		return 0xA;
+	case B43_OFDM_RATE_18MB:
+		return 0xE;
+	case B43_OFDM_RATE_24MB:
+		return 0x9;
+	case B43_OFDM_RATE_36MB:
+		return 0xD;
+	case B43_OFDM_RATE_48MB:
+		return 0x8;
+	case B43_OFDM_RATE_54MB:
+		return 0xC;
+	}
+	B43_WARN_ON(1);
+	return 0;
+}
+
+void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp,
+			   const u16 octets, const u8 bitrate)
+{
+	__le32 *data = &(plcp->data);
+	__u8 *raw = plcp->raw;
+
+	if (b43_is_ofdm_rate(bitrate)) {
+		u32 d;
+
+		d = b43_plcp_get_ratecode_ofdm(bitrate);
+		B43_WARN_ON(octets & 0xF000);
+		d |= (octets << 5);
+		*data = cpu_to_le32(d);
+	} else {
+		u32 plen;
+
+		plen = octets * 16 / bitrate;
+		if ((octets * 16 % bitrate) > 0) {
+			plen++;
+			if ((bitrate == B43_CCK_RATE_11MB)
+			    && ((octets * 8 % 11) < 4)) {
+				raw[1] = 0x84;
+			} else
+				raw[1] = 0x04;
+		} else
+			raw[1] = 0x04;
+		*data |= cpu_to_le32(plen << 16);
+		raw[0] = b43_plcp_get_ratecode_cck(bitrate);
+	}
+}
+
+static u8 b43_calc_fallback_rate(u8 bitrate)
+{
+	switch (bitrate) {
+	case B43_CCK_RATE_1MB:
+		return B43_CCK_RATE_1MB;
+	case B43_CCK_RATE_2MB:
+		return B43_CCK_RATE_1MB;
+	case B43_CCK_RATE_5MB:
+		return B43_CCK_RATE_2MB;
+	case B43_CCK_RATE_11MB:
+		return B43_CCK_RATE_5MB;
+	case B43_OFDM_RATE_6MB:
+		return B43_CCK_RATE_5MB;
+	case B43_OFDM_RATE_9MB:
+		return B43_OFDM_RATE_6MB;
+	case B43_OFDM_RATE_12MB:
+		return B43_OFDM_RATE_9MB;
+	case B43_OFDM_RATE_18MB:
+		return B43_OFDM_RATE_12MB;
+	case B43_OFDM_RATE_24MB:
+		return B43_OFDM_RATE_18MB;
+	case B43_OFDM_RATE_36MB:
+		return B43_OFDM_RATE_24MB;
+	case B43_OFDM_RATE_48MB:
+		return B43_OFDM_RATE_36MB;
+	case B43_OFDM_RATE_54MB:
+		return B43_OFDM_RATE_48MB;
+	}
+	B43_WARN_ON(1);
+	return 0;
+}
+
+static void generate_txhdr_fw4(struct b43_wldev *dev,
+			       struct b43_txhdr_fw4 *txhdr,
+			       const unsigned char *fragment_data,
+			       unsigned int fragment_len,
+			       const struct ieee80211_tx_control *txctl,
+			       u16 cookie)
+{
+	const struct b43_phy *phy = &dev->phy;
+	const struct ieee80211_hdr *wlhdr =
+	    (const struct ieee80211_hdr *)fragment_data;
+	int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
+	u16 fctl = le16_to_cpu(wlhdr->frame_control);
+	u8 rate, rate_fb;
+	int rate_ofdm, rate_fb_ofdm;
+	unsigned int plcp_fragment_len;
+	u32 mac_ctl = 0;
+	u16 phy_ctl = 0;
+	u8 extra_ft = 0;
+
+	memset(txhdr, 0, sizeof(*txhdr));
+
+	rate = txctl->tx_rate;
+	rate_ofdm = b43_is_ofdm_rate(rate);
+	rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
+	rate_fb_ofdm = b43_is_ofdm_rate(rate_fb);
+
+	if (rate_ofdm)
+		txhdr->phy_rate = b43_plcp_get_ratecode_ofdm(rate);
+	else
+		txhdr->phy_rate = b43_plcp_get_ratecode_cck(rate);
+	txhdr->mac_frame_ctl = wlhdr->frame_control;
+	memcpy(txhdr->tx_receiver, wlhdr->addr1, 6);
+
+	/* Calculate duration for fallback rate */
+	if ((rate_fb == rate) ||
+	    (wlhdr->duration_id & cpu_to_le16(0x8000)) ||
+	    (wlhdr->duration_id == cpu_to_le16(0))) {
+		/* If the fallback rate equals the normal rate or the
+		 * dur_id field contains an AID, CFP magic or 0,
+		 * use the original dur_id field. */
+		txhdr->dur_fb = wlhdr->duration_id;
+	} else {
+		int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb);
+		txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
+								 dev->wl->if_id,
+								 fragment_len,
+								 fbrate_base100kbps);
+	}
+
+	plcp_fragment_len = fragment_len + FCS_LEN;
+	if (use_encryption) {
+		u8 key_idx = (u16) (txctl->key_idx);
+		struct b43_key *key;
+		int wlhdr_len;
+		size_t iv_len;
+
+		B43_WARN_ON(key_idx >= dev->max_nr_keys);
+		key = &(dev->key[key_idx]);
+		B43_WARN_ON(!key->keyconf);
+
+		/* Hardware appends ICV. */
+		plcp_fragment_len += txctl->icv_len;
+
+		key_idx = b43_kidx_to_fw(dev, key_idx);
+		mac_ctl |= (key_idx << B43_TX4_MAC_KEYIDX_SHIFT) &
+			   B43_TX4_MAC_KEYIDX;
+		mac_ctl |= (key->algorithm << B43_TX4_MAC_KEYALG_SHIFT) &
+			   B43_TX4_MAC_KEYALG;
+		wlhdr_len = ieee80211_get_hdrlen(fctl);
+		iv_len = min((size_t) txctl->iv_len,
+			     ARRAY_SIZE(txhdr->iv));
+		memcpy(txhdr->iv, ((u8 *) wlhdr) + wlhdr_len, iv_len);
+	}
+	b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp),
+			      plcp_fragment_len, rate);
+	b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->plcp_fb),
+			      plcp_fragment_len, rate_fb);
+
+	/* Extra Frame Types */
+	if (rate_fb_ofdm)
+		extra_ft |= B43_TX4_EFT_FBOFDM;
+
+	/* Set channel radio code. Note that the micrcode ORs 0x100 to
+	 * this value before comparing it to the value in SHM, if this
+	 * is a 5Ghz packet.
+	 */
+	txhdr->chan_radio_code = phy->channel;
+
+	/* PHY TX Control word */
+	if (rate_ofdm)
+		phy_ctl |= B43_TX4_PHY_OFDM;
+	if (dev->short_preamble)
+		phy_ctl |= B43_TX4_PHY_SHORTPRMBL;
+	switch (txctl->antenna_sel_tx) {
+	case 0:
+		phy_ctl |= B43_TX4_PHY_ANTLAST;
+		break;
+	case 1:
+		phy_ctl |= B43_TX4_PHY_ANT0;
+		break;
+	case 2:
+		phy_ctl |= B43_TX4_PHY_ANT1;
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+
+	/* MAC control */
+	if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
+		mac_ctl |= B43_TX4_MAC_ACK;
+	if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+	      ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
+		mac_ctl |= B43_TX4_MAC_HWSEQ;
+	if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
+		mac_ctl |= B43_TX4_MAC_STMSDU;
+	if (phy->type == B43_PHYTYPE_A)
+		mac_ctl |= B43_TX4_MAC_5GHZ;
+
+	/* Generate the RTS or CTS-to-self frame */
+	if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
+	    (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
+		unsigned int len;
+		struct ieee80211_hdr *hdr;
+		int rts_rate, rts_rate_fb;
+		int rts_rate_ofdm, rts_rate_fb_ofdm;
+
+		rts_rate = txctl->rts_cts_rate;
+		rts_rate_ofdm = b43_is_ofdm_rate(rts_rate);
+		rts_rate_fb = b43_calc_fallback_rate(rts_rate);
+		rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb);
+
+		if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+			ieee80211_ctstoself_get(dev->wl->hw, dev->wl->if_id,
+						fragment_data, fragment_len,
+						txctl,
+						(struct ieee80211_cts *)(txhdr->
+									 rts_frame));
+			mac_ctl |= B43_TX4_MAC_SENDCTS;
+			len = sizeof(struct ieee80211_cts);
+		} else {
+			ieee80211_rts_get(dev->wl->hw, dev->wl->if_id,
+					  fragment_data, fragment_len, txctl,
+					  (struct ieee80211_rts *)(txhdr->
+								   rts_frame));
+			mac_ctl |= B43_TX4_MAC_SENDRTS;
+			len = sizeof(struct ieee80211_rts);
+		}
+		len += FCS_LEN;
+		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
+							       rts_plcp), len,
+				      rts_rate);
+		b43_generate_plcp_hdr((struct b43_plcp_hdr4 *)(&txhdr->
+							       rts_plcp_fb),
+				      len, rts_rate_fb);
+		hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
+		txhdr->rts_dur_fb = hdr->duration_id;
+		if (rts_rate_ofdm) {
+			extra_ft |= B43_TX4_EFT_RTSOFDM;
+			txhdr->phy_rate_rts =
+			    b43_plcp_get_ratecode_ofdm(rts_rate);
+		} else
+			txhdr->phy_rate_rts =
+			    b43_plcp_get_ratecode_cck(rts_rate);
+		if (rts_rate_fb_ofdm)
+			extra_ft |= B43_TX4_EFT_RTSFBOFDM;
+		mac_ctl |= B43_TX4_MAC_LONGFRAME;
+	}
+
+	/* Magic cookie */
+	txhdr->cookie = cpu_to_le16(cookie);
+
+	/* Apply the bitfields */
+	txhdr->mac_ctl = cpu_to_le32(mac_ctl);
+	txhdr->phy_ctl = cpu_to_le16(phy_ctl);
+	txhdr->extra_ft = extra_ft;
+}
+
+void b43_generate_txhdr(struct b43_wldev *dev,
+			u8 * txhdr,
+			const unsigned char *fragment_data,
+			unsigned int fragment_len,
+			const struct ieee80211_tx_control *txctl, u16 cookie)
+{
+	generate_txhdr_fw4(dev, (struct b43_txhdr_fw4 *)txhdr,
+			   fragment_data, fragment_len, txctl, cookie);
+}
+
+static s8 b43_rssi_postprocess(struct b43_wldev *dev,
+			       u8 in_rssi, int ofdm,
+			       int adjust_2053, int adjust_2050)
+{
+	struct b43_phy *phy = &dev->phy;
+	s32 tmp;
+
+	switch (phy->radio_ver) {
+	case 0x2050:
+		if (ofdm) {
+			tmp = in_rssi;
+			if (tmp > 127)
+				tmp -= 256;
+			tmp *= 73;
+			tmp /= 64;
+			if (adjust_2050)
+				tmp += 25;
+			else
+				tmp -= 3;
+		} else {
+			if (dev->dev->bus->sprom.r1.
+			    boardflags_lo & B43_BFL_RSSI) {
+				if (in_rssi > 63)
+					in_rssi = 63;
+				tmp = phy->nrssi_lt[in_rssi];
+				tmp = 31 - tmp;
+				tmp *= -131;
+				tmp /= 128;
+				tmp -= 57;
+			} else {
+				tmp = in_rssi;
+				tmp = 31 - tmp;
+				tmp *= -149;
+				tmp /= 128;
+				tmp -= 68;
+			}
+			if (phy->type == B43_PHYTYPE_G && adjust_2050)
+				tmp += 25;
+		}
+		break;
+	case 0x2060:
+		if (in_rssi > 127)
+			tmp = in_rssi - 256;
+		else
+			tmp = in_rssi;
+		break;
+	default:
+		tmp = in_rssi;
+		tmp -= 11;
+		tmp *= 103;
+		tmp /= 64;
+		if (adjust_2053)
+			tmp -= 109;
+		else
+			tmp -= 83;
+	}
+
+	return (s8) tmp;
+}
+
+//TODO
+#if 0
+static s8 b43_rssinoise_postprocess(struct b43_wldev *dev, u8 in_rssi)
+{
+	struct b43_phy *phy = &dev->phy;
+	s8 ret;
+
+	if (phy->type == B43_PHYTYPE_A) {
+		//TODO: Incomplete specs.
+		ret = 0;
+	} else
+		ret = b43_rssi_postprocess(dev, in_rssi, 0, 1, 1);
+
+	return ret;
+}
+#endif
+
+void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
+{
+	struct ieee80211_rx_status status;
+	struct b43_plcp_hdr6 *plcp;
+	struct ieee80211_hdr *wlhdr;
+	const struct b43_rxhdr_fw4 *rxhdr = _rxhdr;
+	u16 fctl;
+	u16 phystat0, phystat3, chanstat, mactime;
+	u32 macstat;
+	u16 chanid;
+	u8 jssi;
+	int padding;
+
+	memset(&status, 0, sizeof(status));
+
+	/* Get metadata about the frame from the header. */
+	phystat0 = le16_to_cpu(rxhdr->phy_status0);
+	phystat3 = le16_to_cpu(rxhdr->phy_status3);
+	jssi = rxhdr->jssi;
+	macstat = le32_to_cpu(rxhdr->mac_status);
+	mactime = le16_to_cpu(rxhdr->mac_time);
+	chanstat = le16_to_cpu(rxhdr->channel);
+
+	if (macstat & B43_RX_MAC_FCSERR)
+		dev->wl->ieee_stats.dot11FCSErrorCount++;
+	if (macstat & B43_RX_MAC_DECERR) {
+		/* Decryption with the given key failed.
+		 * Drop the packet. We also won't be able to decrypt it with
+		 * the key in software. */
+		goto drop;
+	}
+
+	/* Skip PLCP and padding */
+	padding = (macstat & B43_RX_MAC_PADDING) ? 2 : 0;
+	if (unlikely(skb->len < (sizeof(struct b43_plcp_hdr6) + padding))) {
+		b43dbg(dev->wl, "RX: Packet size underrun (1)\n");
+		goto drop;
+	}
+	plcp = (struct b43_plcp_hdr6 *)(skb->data + padding);
+	skb_pull(skb, sizeof(struct b43_plcp_hdr6) + padding);
+	/* The skb contains the Wireless Header + payload data now */
+	if (unlikely(skb->len < (2 + 2 + 6 /*minimum hdr */  + FCS_LEN))) {
+		b43dbg(dev->wl, "RX: Packet size underrun (2)\n");
+		goto drop;
+	}
+	wlhdr = (struct ieee80211_hdr *)(skb->data);
+	fctl = le16_to_cpu(wlhdr->frame_control);
+	skb_trim(skb, skb->len - FCS_LEN);
+
+	if (macstat & B43_RX_MAC_DEC) {
+		unsigned int keyidx;
+		int wlhdr_len;
+
+		keyidx = ((macstat & B43_RX_MAC_KEYIDX)
+			  >> B43_RX_MAC_KEYIDX_SHIFT);
+		/* We must adjust the key index here. We want the "physical"
+		 * key index, but the ucode passed it slightly different.
+		 */
+		keyidx = b43_kidx_to_raw(dev, keyidx);
+		B43_WARN_ON(keyidx >= dev->max_nr_keys);
+
+		if (dev->key[keyidx].algorithm != B43_SEC_ALGO_NONE) {
+			wlhdr_len = ieee80211_get_hdrlen(fctl);
+			if (unlikely(skb->len < (wlhdr_len + 3))) {
+				b43dbg(dev->wl,
+				       "RX: Packet size underrun (3)\n");
+				goto drop;
+			}
+			status.flag |= RX_FLAG_DECRYPTED;
+		}
+	}
+
+	status.ssi = b43_rssi_postprocess(dev, jssi,
+					  (phystat0 & B43_RX_PHYST0_OFDM),
+					  (phystat0 & B43_RX_PHYST0_GAINCTL),
+					  (phystat3 & B43_RX_PHYST3_TRSTATE));
+	status.noise = dev->stats.link_noise;
+	/* the next line looks wrong, but is what mac80211 wants */
+	status.signal = (jssi * 100) / B43_RX_MAX_SSI;
+	if (phystat0 & B43_RX_PHYST0_OFDM)
+		status.rate = b43_plcp_get_bitrate_ofdm(plcp);
+	else
+		status.rate = b43_plcp_get_bitrate_cck(plcp);
+	status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);
+	status.mactime = mactime;
+
+	chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT;
+	switch (chanstat & B43_RX_CHAN_PHYTYPE) {
+	case B43_PHYTYPE_A:
+		status.phymode = MODE_IEEE80211A;
+		status.freq = chanid;
+		status.channel = b43_freq_to_channel_a(chanid);
+		break;
+	case B43_PHYTYPE_B:
+		status.phymode = MODE_IEEE80211B;
+		status.freq = chanid + 2400;
+		status.channel = b43_freq_to_channel_bg(chanid + 2400);
+		break;
+	case B43_PHYTYPE_G:
+		status.phymode = MODE_IEEE80211G;
+		status.freq = chanid + 2400;
+		status.channel = b43_freq_to_channel_bg(chanid + 2400);
+		break;
+	default:
+		B43_WARN_ON(1);
+	}
+
+	dev->stats.last_rx = jiffies;
+	ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
+
+	return;
+drop:
+	b43dbg(dev->wl, "RX: Packet dropped\n");
+	dev_kfree_skb_any(skb);
+}
+
+void b43_handle_txstatus(struct b43_wldev *dev,
+			 const struct b43_txstatus *status)
+{
+	b43_debugfs_log_txstat(dev, status);
+
+	if (status->intermediate)
+		return;
+	if (status->for_ampdu)
+		return;
+	if (!status->acked)
+		dev->wl->ieee_stats.dot11ACKFailureCount++;
+	if (status->rts_count) {
+		if (status->rts_count == 0xF)	//FIXME
+			dev->wl->ieee_stats.dot11RTSFailureCount++;
+		else
+			dev->wl->ieee_stats.dot11RTSSuccessCount++;
+	}
+
+	if (b43_using_pio(dev))
+		b43_pio_handle_txstatus(dev, status);
+	else
+		b43_dma_handle_txstatus(dev, status);
+}
+
+/* Handle TX status report as received through DMA/PIO queues */
+void b43_handle_hwtxstatus(struct b43_wldev *dev,
+			   const struct b43_hwtxstatus *hw)
+{
+	struct b43_txstatus status;
+	u8 tmp;
+
+	status.cookie = le16_to_cpu(hw->cookie);
+	status.seq = le16_to_cpu(hw->seq);
+	status.phy_stat = hw->phy_stat;
+	tmp = hw->count;
+	status.frame_count = (tmp >> 4);
+	status.rts_count = (tmp & 0x0F);
+	tmp = hw->flags;
+	status.supp_reason = ((tmp & 0x1C) >> 2);
+	status.pm_indicated = !!(tmp & 0x80);
+	status.intermediate = !!(tmp & 0x40);
+	status.for_ampdu = !!(tmp & 0x20);
+	status.acked = !!(tmp & 0x02);
+
+	b43_handle_txstatus(dev, &status);
+}
+
+/* Stop any TX operation on the device (suspend the hardware queues) */
+void b43_tx_suspend(struct b43_wldev *dev)
+{
+	if (b43_using_pio(dev))
+		b43_pio_freeze_txqueues(dev);
+	else
+		b43_dma_tx_suspend(dev);
+}
+
+/* Resume any TX operation on the device (resume the hardware queues) */
+void b43_tx_resume(struct b43_wldev *dev)
+{
+	if (b43_using_pio(dev))
+		b43_pio_thaw_txqueues(dev);
+	else
+		b43_dma_tx_resume(dev);
+}
+
+#if 0
+static void upload_qos_parms(struct b43_wldev *dev,
+			     const u16 * parms, u16 offset)
+{
+	int i;
+
+	for (i = 0; i < B43_NR_QOSPARMS; i++) {
+		b43_shm_write16(dev, B43_SHM_SHARED,
+				offset + (i * 2), parms[i]);
+	}
+}
+#endif
+
+/* Initialize the QoS parameters */
+void b43_qos_init(struct b43_wldev *dev)
+{
+	/* FIXME: This function must probably be called from the mac80211
+	 * config callback. */
+	return;
+
+	b43_hf_write(dev, b43_hf_read(dev) | B43_HF_EDCF);
+	//FIXME kill magic
+	b43_write16(dev, 0x688, b43_read16(dev, 0x688) | 0x4);
+
+	/*TODO: We might need some stack support here to get the values. */
+}
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
new file mode 100644
index 0000000..03bddd2
--- /dev/null
+++ b/drivers/net/wireless/b43/xmit.h
@@ -0,0 +1,250 @@
+#ifndef B43_XMIT_H_
+#define B43_XMIT_H_
+
+#include "main.h"
+
+#define _b43_declare_plcp_hdr(size) \
+	struct b43_plcp_hdr##size {		\
+		union {				\
+			__le32 data;		\
+			__u8 raw[size];		\
+		} __attribute__((__packed__));	\
+	} __attribute__((__packed__))
+
+/* struct b43_plcp_hdr4 */
+_b43_declare_plcp_hdr(4);
+/* struct b43_plcp_hdr6 */
+_b43_declare_plcp_hdr(6);
+
+#undef _b43_declare_plcp_hdr
+
+/* TX header for v4 firmware */
+struct b43_txhdr_fw4 {
+	__le32 mac_ctl;		/* MAC TX control */
+	__le16 mac_frame_ctl;	/* Copy of the FrameControl field */
+	__le16 tx_fes_time_norm;	/* TX FES Time Normal */
+	__le16 phy_ctl;		/* PHY TX control */
+	__le16 phy_ctl_0;	/* Unused */
+	__le16 phy_ctl_1;	/* Unused */
+	__le16 phy_ctl_rts_0;	/* Unused */
+	__le16 phy_ctl_rts_1;	/* Unused */
+	__u8 phy_rate;		/* PHY rate */
+	__u8 phy_rate_rts;	/* PHY rate for RTS/CTS */
+	__u8 extra_ft;		/* Extra Frame Types */
+	__u8 chan_radio_code;	/* Channel Radio Code */
+	__u8 iv[16];		/* Encryption IV */
+	__u8 tx_receiver[6];	/* TX Frame Receiver address */
+	__le16 tx_fes_time_fb;	/* TX FES Time Fallback */
+	struct b43_plcp_hdr6 rts_plcp_fb;	/* RTS fallback PLCP */
+	__le16 rts_dur_fb;	/* RTS fallback duration */
+	struct b43_plcp_hdr6 plcp_fb;	/* Fallback PLCP */
+	__le16 dur_fb;		/* Fallback duration */
+	__le16 mm_dur_time;	/* Unused */
+	__le16 mm_dur_time_fb;	/* Unused */
+	__le32 time_stamp;	/* Timestamp */
+	 PAD_BYTES(2);
+	__le16 cookie;		/* TX frame cookie */
+	__le16 tx_status;	/* TX status */
+	struct b43_plcp_hdr6 rts_plcp;	/* RTS PLCP */
+	__u8 rts_frame[16];	/* The RTS frame (if used) */
+	 PAD_BYTES(2);
+	struct b43_plcp_hdr6 plcp;	/* Main PLCP */
+} __attribute__ ((__packed__));
+
+/* MAC TX control */
+#define B43_TX4_MAC_KEYIDX		0x0FF00000	/* Security key index */
+#define B43_TX4_MAC_KEYIDX_SHIFT	20
+#define B43_TX4_MAC_KEYALG		0x00070000	/* Security key algorithm */
+#define B43_TX4_MAC_KEYALG_SHIFT	16
+#define B43_TX4_MAC_LIFETIME	0x00001000
+#define B43_TX4_MAC_FRAMEBURST	0x00000800
+#define B43_TX4_MAC_SENDCTS		0x00000400
+#define B43_TX4_MAC_AMPDU		0x00000300
+#define B43_TX4_MAC_AMPDU_SHIFT	8
+#define B43_TX4_MAC_5GHZ		0x00000080
+#define B43_TX4_MAC_IGNPMQ		0x00000020
+#define B43_TX4_MAC_HWSEQ		0x00000010	/* Use Hardware Sequence Number */
+#define B43_TX4_MAC_STMSDU		0x00000008	/* Start MSDU */
+#define B43_TX4_MAC_SENDRTS		0x00000004
+#define B43_TX4_MAC_LONGFRAME	0x00000002
+#define B43_TX4_MAC_ACK		0x00000001
+
+/* Extra Frame Types */
+#define B43_TX4_EFT_FBOFDM		0x0001	/* Data frame fallback rate type */
+#define B43_TX4_EFT_RTSOFDM		0x0004	/* RTS/CTS rate type */
+#define B43_TX4_EFT_RTSFBOFDM	0x0010	/* RTS/CTS fallback rate type */
+
+/* PHY TX control word */
+#define B43_TX4_PHY_OFDM		0x0001	/* Data frame rate type */
+#define B43_TX4_PHY_SHORTPRMBL	0x0010	/* Use short preamble */
+#define B43_TX4_PHY_ANT		0x03C0	/* Antenna selection */
+#define  B43_TX4_PHY_ANT0		0x0000	/* Use antenna 0 */
+#define  B43_TX4_PHY_ANT1		0x0100	/* Use antenna 1 */
+#define  B43_TX4_PHY_ANTLAST	0x0300	/* Use last used antenna */
+
+void b43_generate_txhdr(struct b43_wldev *dev,
+			u8 * txhdr,
+			const unsigned char *fragment_data,
+			unsigned int fragment_len,
+			const struct ieee80211_tx_control *txctl, u16 cookie);
+
+/* Transmit Status */
+struct b43_txstatus {
+	u16 cookie;		/* The cookie from the txhdr */
+	u16 seq;		/* Sequence number */
+	u8 phy_stat;		/* PHY TX status */
+	u8 frame_count;		/* Frame transmit count */
+	u8 rts_count;		/* RTS transmit count */
+	u8 supp_reason;		/* Suppression reason */
+	/* flags */
+	u8 pm_indicated;	/* PM mode indicated to AP */
+	u8 intermediate;	/* Intermediate status notification (not final) */
+	u8 for_ampdu;		/* Status is for an AMPDU (afterburner) */
+	u8 acked;		/* Wireless ACK received */
+};
+
+/* txstatus supp_reason values */
+enum {
+	B43_TXST_SUPP_NONE,	/* Not suppressed */
+	B43_TXST_SUPP_PMQ,	/* Suppressed due to PMQ entry */
+	B43_TXST_SUPP_FLUSH,	/* Suppressed due to flush request */
+	B43_TXST_SUPP_PREV,	/* Previous fragment failed */
+	B43_TXST_SUPP_CHAN,	/* Channel mismatch */
+	B43_TXST_SUPP_LIFE,	/* Lifetime expired */
+	B43_TXST_SUPP_UNDER,	/* Buffer underflow */
+	B43_TXST_SUPP_ABNACK,	/* Afterburner NACK */
+};
+
+/* Transmit Status as received through DMA/PIO on old chips */
+struct b43_hwtxstatus {
+	PAD_BYTES(4);
+	__le16 cookie;
+	u8 flags;
+	u8 count;
+	 PAD_BYTES(2);
+	__le16 seq;
+	u8 phy_stat;
+	 PAD_BYTES(1);
+} __attribute__ ((__packed__));
+
+/* Receive header for v4 firmware. */
+struct b43_rxhdr_fw4 {
+	__le16 frame_len;	/* Frame length */
+	 PAD_BYTES(2);
+	__le16 phy_status0;	/* PHY RX Status 0 */
+	__u8 jssi;		/* PHY RX Status 1: JSSI */
+	__u8 sig_qual;		/* PHY RX Status 1: Signal Quality */
+	__le16 phy_status2;	/* PHY RX Status 2 */
+	__le16 phy_status3;	/* PHY RX Status 3 */
+	__le32 mac_status;	/* MAC RX status */
+	__le16 mac_time;
+	__le16 channel;
+} __attribute__ ((__packed__));
+
+/* PHY RX Status 0 */
+#define B43_RX_PHYST0_GAINCTL	0x4000	/* Gain Control */
+#define B43_RX_PHYST0_PLCPHCF	0x0200
+#define B43_RX_PHYST0_PLCPFV	0x0100
+#define B43_RX_PHYST0_SHORTPRMBL	0x0080	/* Received with Short Preamble */
+#define B43_RX_PHYST0_LCRS		0x0040
+#define B43_RX_PHYST0_ANT		0x0020	/* Antenna */
+#define B43_RX_PHYST0_UNSRATE	0x0010
+#define B43_RX_PHYST0_CLIP		0x000C
+#define B43_RX_PHYST0_CLIP_SHIFT	2
+#define B43_RX_PHYST0_FTYPE		0x0003	/* Frame type */
+#define  B43_RX_PHYST0_CCK		0x0000	/* Frame type: CCK */
+#define  B43_RX_PHYST0_OFDM		0x0001	/* Frame type: OFDM */
+#define  B43_RX_PHYST0_PRE_N	0x0002	/* Pre-standard N-PHY frame */
+#define  B43_RX_PHYST0_STD_N	0x0003	/* Standard N-PHY frame */
+
+/* PHY RX Status 2 */
+#define B43_RX_PHYST2_LNAG		0xC000	/* LNA Gain */
+#define B43_RX_PHYST2_LNAG_SHIFT	14
+#define B43_RX_PHYST2_PNAG		0x3C00	/* PNA Gain */
+#define B43_RX_PHYST2_PNAG_SHIFT	10
+#define B43_RX_PHYST2_FOFF		0x03FF	/* F offset */
+
+/* PHY RX Status 3 */
+#define B43_RX_PHYST3_DIGG		0x1800	/* DIG Gain */
+#define B43_RX_PHYST3_DIGG_SHIFT	11
+#define B43_RX_PHYST3_TRSTATE	0x0400	/* TR state */
+
+/* MAC RX Status */
+#define B43_RX_MAC_BEACONSENT	0x00008000	/* Beacon send flag */
+#define B43_RX_MAC_KEYIDX		0x000007E0	/* Key index */
+#define B43_RX_MAC_KEYIDX_SHIFT	5
+#define B43_RX_MAC_DECERR		0x00000010	/* Decrypt error */
+#define B43_RX_MAC_DEC		0x00000008	/* Decryption attempted */
+#define B43_RX_MAC_PADDING		0x00000004	/* Pad bytes present */
+#define B43_RX_MAC_RESP		0x00000002	/* Response frame transmitted */
+#define B43_RX_MAC_FCSERR		0x00000001	/* FCS error */
+
+/* RX channel */
+#define B43_RX_CHAN_GAIN		0xFC00	/* Gain */
+#define B43_RX_CHAN_GAIN_SHIFT	10
+#define B43_RX_CHAN_ID		0x03FC	/* Channel ID */
+#define B43_RX_CHAN_ID_SHIFT	2
+#define B43_RX_CHAN_PHYTYPE		0x0003	/* PHY type */
+
+u8 b43_plcp_get_ratecode_cck(const u8 bitrate);
+u8 b43_plcp_get_ratecode_ofdm(const u8 bitrate);
+
+void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp,
+			   const u16 octets, const u8 bitrate);
+
+void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr);
+
+void b43_handle_txstatus(struct b43_wldev *dev,
+			 const struct b43_txstatus *status);
+
+void b43_handle_hwtxstatus(struct b43_wldev *dev,
+			   const struct b43_hwtxstatus *hw);
+
+void b43_tx_suspend(struct b43_wldev *dev);
+void b43_tx_resume(struct b43_wldev *dev);
+
+#define B43_NR_QOSPARMS		22
+enum {
+	B43_QOSPARM_TXOP = 0,
+	B43_QOSPARM_CWMIN,
+	B43_QOSPARM_CWMAX,
+	B43_QOSPARM_CWCUR,
+	B43_QOSPARM_AIFS,
+	B43_QOSPARM_BSLOTS,
+	B43_QOSPARM_REGGAP,
+	B43_QOSPARM_STATUS,
+};
+void b43_qos_init(struct b43_wldev *dev);
+
+/* Helper functions for converting the key-table index from "firmware-format"
+ * to "raw-format" and back. The firmware API changed for this at some revision.
+ * We need to account for that here. */
+static inline int b43_new_kidx_api(struct b43_wldev *dev)
+{
+	/* FIXME: Not sure the change was at rev 351 */
+	return (dev->fw.rev >= 351);
+}
+static inline u8 b43_kidx_to_fw(struct b43_wldev *dev, u8 raw_kidx)
+{
+	u8 firmware_kidx;
+	if (b43_new_kidx_api(dev)) {
+		firmware_kidx = raw_kidx;
+	} else {
+		if (raw_kidx >= 4)	/* Is per STA key? */
+			firmware_kidx = raw_kidx - 4;
+		else
+			firmware_kidx = raw_kidx;	/* TX default key */
+	}
+	return firmware_kidx;
+}
+static inline u8 b43_kidx_to_raw(struct b43_wldev *dev, u8 firmware_kidx)
+{
+	u8 raw_kidx;
+	if (b43_new_kidx_api(dev))
+		raw_kidx = firmware_kidx;
+	else
+		raw_kidx = firmware_kidx + 4;	/* RX default keys or per STA keys */
+	return raw_kidx;
+}
+
+#endif /* B43_XMIT_H_ */
diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig
new file mode 100644
index 0000000..7e23ec2
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/Kconfig
@@ -0,0 +1,89 @@
+config B43LEGACY
+	tristate "Broadcom 43xx-legacy wireless support (mac80211 stack)"
+	depends on SSB_POSSIBLE && MAC80211 && WLAN_80211
+	select SSB
+	select FW_LOADER
+	select HW_RANDOM
+	---help---
+	  b43legacy is a driver for 802.11b devices from Broadcom (BCM4301 and
+	  BCM4303) and early model 802.11g chips (BCM4306 Ver. 2) used in the
+	  Linksys WPC54G V1 PCMCIA devices.
+
+	  Newer 802.11g and 802.11a devices need b43.
+
+	  It is safe to include both b43 and b43legacy as the underlying glue
+	  layer will automatically load the correct version for your device.
+
+	  This driver uses V3 firmware, which must be installed separately using
+	  b43-fwcutter.
+
+	  This driver can be built as a module (recommended) that will be
+	  called "b43legacy". If unsure, say M.
+
+# Auto-select SSB PCI-HOST support, if possible
+config B43LEGACY_PCI_AUTOSELECT
+	bool
+	depends on B43LEGACY && SSB_PCIHOST_POSSIBLE
+	select SSB_PCIHOST
+	default y
+
+# Auto-select SSB PCICORE driver, if possible
+config B43LEGACY_PCICORE_AUTOSELECT
+	bool
+	depends on B43LEGACY && SSB_DRIVER_PCICORE_POSSIBLE
+	select SSB_DRIVER_PCICORE
+	default y
+
+config B43LEGACY_DEBUG
+	bool "Broadcom 43xx-legacy debugging"
+	depends on B43LEGACY
+	default y
+	---help---
+	  Say Y, because this information will help you get the driver running.
+	  This option generates a minimum of log output.
+
+config B43LEGACY_DMA
+	bool
+	depends on B43LEGACY
+
+config B43LEGACY_PIO
+	bool
+	depends on B43LEGACY
+
+choice
+	prompt "Broadcom 43xx-legacy data transfer mode"
+	depends on B43LEGACY
+	default B43LEGACY_DMA_AND_PIO_MODE
+
+config B43LEGACY_DMA_AND_PIO_MODE
+	bool "DMA + PIO"
+	select B43LEGACY_DMA
+	select B43LEGACY_PIO
+	---help---
+	  Include both, Direct Memory Access (DMA) and Programmed I/O (PIO)
+	  data transfer modes. The mode actually used is selectable through
+	  the module parameter "pio". With pio=0 as a module parameter, the
+	  default DMA is used, otherwise PIO is used.
+
+	  If unsure, choose this option.
+
+config B43LEGACY_DMA_MODE
+	bool "DMA (Direct Memory Access) only"
+	select B43LEGACY_DMA
+	---help---
+	  Only include Direct Memory Access (DMA).
+	  This reduces the size of the driver module, by omitting the PIO code.
+
+config B43LEGACY_PIO_MODE
+	bool "PIO (Programmed I/O) only"
+	select B43LEGACY_PIO
+	---help---
+	  Only include Programmed I/O (PIO).
+	  This reduces the size of the driver module, by omitting the DMA code.
+	  Please note that PIO transfers are slow (compared to DMA).
+
+	  Also note that not all devices of the b43legacy series support PIO.
+
+	  You should use PIO only if DMA does not work for you.
+
+endchoice
diff --git a/drivers/net/wireless/b43legacy/Makefile b/drivers/net/wireless/b43legacy/Makefile
new file mode 100644
index 0000000..ec3a248
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/Makefile
@@ -0,0 +1,14 @@
+obj-$(CONFIG_B43LEGACY) += b43legacy.o
+b43legacy-obj-$(CONFIG_B43LEGACY_DEBUG) += debugfs.o
+
+b43legacy-obj-$(CONFIG_B43LEGACY_DMA) += dma.o
+b43legacy-obj-$(CONFIG_B43LEGACY_PIO) += pio.o
+
+b43legacy-objs := main.o \
+		ilt.o \
+		leds.o \
+		phy.o \
+		radio.o \
+		sysfs.o \
+		xmit.o \
+		$(b43legacy-obj-y)
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
new file mode 100644
index 0000000..afe145c
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -0,0 +1,832 @@
+#ifndef B43legacy_H_
+#define B43legacy_H_
+
+#include <linux/hw_random.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/stringify.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <asm/atomic.h>
+#include <linux/io.h>
+
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_driver_chipcommon.h>
+
+#include <linux/wireless.h>
+#include <net/mac80211.h>
+
+#include "debugfs.h"
+#include "leds.h"
+#include "phy.h"
+
+
+#define B43legacy_IRQWAIT_MAX_RETRIES	100
+
+#define B43legacy_RX_MAX_SSI		60 /* best guess at max ssi */
+
+/* MMIO offsets */
+#define B43legacy_MMIO_DMA0_REASON	0x20
+#define B43legacy_MMIO_DMA0_IRQ_MASK	0x24
+#define B43legacy_MMIO_DMA1_REASON	0x28
+#define B43legacy_MMIO_DMA1_IRQ_MASK	0x2C
+#define B43legacy_MMIO_DMA2_REASON	0x30
+#define B43legacy_MMIO_DMA2_IRQ_MASK	0x34
+#define B43legacy_MMIO_DMA3_REASON	0x38
+#define B43legacy_MMIO_DMA3_IRQ_MASK	0x3C
+#define B43legacy_MMIO_DMA4_REASON	0x40
+#define B43legacy_MMIO_DMA4_IRQ_MASK	0x44
+#define B43legacy_MMIO_DMA5_REASON	0x48
+#define B43legacy_MMIO_DMA5_IRQ_MASK	0x4C
+#define B43legacy_MMIO_MACCTL		0x120
+#define B43legacy_MMIO_STATUS_BITFIELD	0x120
+#define B43legacy_MMIO_STATUS2_BITFIELD	0x124
+#define B43legacy_MMIO_GEN_IRQ_REASON	0x128
+#define B43legacy_MMIO_GEN_IRQ_MASK	0x12C
+#define B43legacy_MMIO_RAM_CONTROL	0x130
+#define B43legacy_MMIO_RAM_DATA		0x134
+#define B43legacy_MMIO_PS_STATUS		0x140
+#define B43legacy_MMIO_RADIO_HWENABLED_HI	0x158
+#define B43legacy_MMIO_SHM_CONTROL	0x160
+#define B43legacy_MMIO_SHM_DATA		0x164
+#define B43legacy_MMIO_SHM_DATA_UNALIGNED	0x166
+#define B43legacy_MMIO_XMITSTAT_0		0x170
+#define B43legacy_MMIO_XMITSTAT_1		0x174
+#define B43legacy_MMIO_REV3PLUS_TSF_LOW	0x180 /* core rev >= 3 only */
+#define B43legacy_MMIO_REV3PLUS_TSF_HIGH	0x184 /* core rev >= 3 only */
+
+/* 32-bit DMA */
+#define B43legacy_MMIO_DMA32_BASE0	0x200
+#define B43legacy_MMIO_DMA32_BASE1	0x220
+#define B43legacy_MMIO_DMA32_BASE2	0x240
+#define B43legacy_MMIO_DMA32_BASE3	0x260
+#define B43legacy_MMIO_DMA32_BASE4	0x280
+#define B43legacy_MMIO_DMA32_BASE5	0x2A0
+/* 64-bit DMA */
+#define B43legacy_MMIO_DMA64_BASE0	0x200
+#define B43legacy_MMIO_DMA64_BASE1	0x240
+#define B43legacy_MMIO_DMA64_BASE2	0x280
+#define B43legacy_MMIO_DMA64_BASE3	0x2C0
+#define B43legacy_MMIO_DMA64_BASE4	0x300
+#define B43legacy_MMIO_DMA64_BASE5	0x340
+/* PIO */
+#define B43legacy_MMIO_PIO1_BASE		0x300
+#define B43legacy_MMIO_PIO2_BASE		0x310
+#define B43legacy_MMIO_PIO3_BASE		0x320
+#define B43legacy_MMIO_PIO4_BASE		0x330
+
+#define B43legacy_MMIO_PHY_VER		0x3E0
+#define B43legacy_MMIO_PHY_RADIO		0x3E2
+#define B43legacy_MMIO_PHY0		0x3E6
+#define B43legacy_MMIO_ANTENNA		0x3E8
+#define B43legacy_MMIO_CHANNEL		0x3F0
+#define B43legacy_MMIO_CHANNEL_EXT	0x3F4
+#define B43legacy_MMIO_RADIO_CONTROL	0x3F6
+#define B43legacy_MMIO_RADIO_DATA_HIGH	0x3F8
+#define B43legacy_MMIO_RADIO_DATA_LOW	0x3FA
+#define B43legacy_MMIO_PHY_CONTROL	0x3FC
+#define B43legacy_MMIO_PHY_DATA		0x3FE
+#define B43legacy_MMIO_MACFILTER_CONTROL	0x420
+#define B43legacy_MMIO_MACFILTER_DATA	0x422
+#define B43legacy_MMIO_RCMTA_COUNT	0x43C /* Receive Match Transmitter Addr */
+#define B43legacy_MMIO_RADIO_HWENABLED_LO	0x49A
+#define B43legacy_MMIO_GPIO_CONTROL	0x49C
+#define B43legacy_MMIO_GPIO_MASK		0x49E
+#define B43legacy_MMIO_TSF_0		0x632 /* core rev < 3 only */
+#define B43legacy_MMIO_TSF_1		0x634 /* core rev < 3 only */
+#define B43legacy_MMIO_TSF_2		0x636 /* core rev < 3 only */
+#define B43legacy_MMIO_TSF_3		0x638 /* core rev < 3 only */
+#define B43legacy_MMIO_RNG		0x65A
+#define B43legacy_MMIO_POWERUP_DELAY	0x6A8
+
+/* SPROM boardflags_lo values */
+#define B43legacy_BFL_PACTRL		0x0002
+#define B43legacy_BFL_RSSI		0x0008
+#define B43legacy_BFL_EXTLNA		0x1000
+
+/* GPIO register offset, in both ChipCommon and PCI core. */
+#define B43legacy_GPIO_CONTROL		0x6c
+
+/* SHM Routing */
+#define	B43legacy_SHM_SHARED		0x0001
+#define	B43legacy_SHM_WIRELESS		0x0002
+#define	B43legacy_SHM_HW		0x0004
+#define	B43legacy_SHM_UCODE		0x0300
+
+/* SHM Routing modifiers */
+#define B43legacy_SHM_AUTOINC_R		0x0200 /* Read Auto-increment */
+#define B43legacy_SHM_AUTOINC_W		0x0100 /* Write Auto-increment */
+#define B43legacy_SHM_AUTOINC_RW	(B43legacy_SHM_AUTOINC_R | \
+					 B43legacy_SHM_AUTOINC_W)
+
+/* Misc SHM_SHARED offsets */
+#define B43legacy_SHM_SH_WLCOREREV	0x0016 /* 802.11 core revision */
+#define B43legacy_SHM_SH_HOSTFLO	0x005E /* Hostflags ucode opts (low) */
+#define B43legacy_SHM_SH_HOSTFHI	0x0060 /* Hostflags ucode opts (high) */
+/* SHM_SHARED crypto engine */
+#define B43legacy_SHM_SH_KEYIDXBLOCK	0x05D4 /* Key index/algorithm block */
+/* SHM_SHARED beacon variables */
+#define B43legacy_SHM_SH_BEACPHYCTL	0x0054 /* Beacon PHY TX control word */
+/* SHM_SHARED ACK/CTS control */
+#define B43legacy_SHM_SH_ACKCTSPHYCTL	0x0022 /* ACK/CTS PHY control word */
+/* SHM_SHARED probe response variables */
+#define B43legacy_SHM_SH_PRPHYCTL	0x0188 /* Probe Resp PHY TX control */
+#define B43legacy_SHM_SH_PRMAXTIME	0x0074 /* Probe Response max time */
+/* SHM_SHARED rate tables */
+/* SHM_SHARED microcode soft registers */
+#define B43legacy_SHM_SH_UCODEREV	0x0000 /* Microcode revision */
+#define B43legacy_SHM_SH_UCODEPATCH	0x0002 /* Microcode patchlevel */
+#define B43legacy_SHM_SH_UCODEDATE	0x0004 /* Microcode date */
+#define B43legacy_SHM_SH_UCODETIME	0x0006 /* Microcode time */
+
+#define B43legacy_UCODEFLAGS_OFFSET     0x005E
+
+/* Hardware Radio Enable masks */
+#define B43legacy_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16)
+#define B43legacy_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
+
+/* HostFlags. See b43legacy_hf_read/write() */
+#define B43legacy_HF_SYMW		0x00000002 /* G-PHY SYM workaround */
+#define B43legacy_HF_GDCW		0x00000020 /* G-PHY DV cancel filter */
+#define B43legacy_HF_OFDMPABOOST	0x00000040 /* Enable PA boost OFDM */
+#define B43legacy_HF_EDCF		0x00000100 /* on if WME/MAC suspended */
+
+/* MacFilter offsets. */
+#define B43legacy_MACFILTER_SELF	0x0000
+#define B43legacy_MACFILTER_BSSID	0x0003
+#define B43legacy_MACFILTER_MAC		0x0010
+
+/* PHYVersioning */
+#define B43legacy_PHYTYPE_B		0x01
+#define B43legacy_PHYTYPE_G		0x02
+
+/* PHYRegisters */
+#define B43legacy_PHY_G_LO_CONTROL	0x0810
+#define B43legacy_PHY_ILT_G_CTRL	0x0472
+#define B43legacy_PHY_ILT_G_DATA1	0x0473
+#define B43legacy_PHY_ILT_G_DATA2	0x0474
+#define B43legacy_PHY_G_PCTL		0x0029
+#define B43legacy_PHY_RADIO_BITFIELD	0x0401
+#define B43legacy_PHY_G_CRS		0x0429
+#define B43legacy_PHY_NRSSILT_CTRL	0x0803
+#define B43legacy_PHY_NRSSILT_DATA	0x0804
+
+/* RadioRegisters */
+#define B43legacy_RADIOCTL_ID		0x01
+
+/* MAC Control bitfield */
+#define B43legacy_MACCTL_IHR_ENABLED	0x00000400 /* IHR Region Enabled */
+#define B43legacy_MACCTL_INFRA		0x00020000 /* Infrastructure mode */
+#define B43legacy_MACCTL_AP		0x00040000 /* AccessPoint mode */
+#define B43legacy_MACCTL_BEACPROMISC	0x00100000 /* Beacon Promiscuous */
+#define B43legacy_MACCTL_KEEP_BADPLCP	0x00200000 /* Keep bad PLCP frames */
+#define B43legacy_MACCTL_KEEP_CTL	0x00400000 /* Keep control frames */
+#define B43legacy_MACCTL_KEEP_BAD	0x00800000 /* Keep bad frames (FCS) */
+#define B43legacy_MACCTL_PROMISC	0x01000000 /* Promiscuous mode */
+#define B43legacy_MACCTL_GMODE		0x80000000 /* G Mode */
+
+/* StatusBitField */
+#define B43legacy_SBF_MAC_ENABLED	0x00000001
+#define B43legacy_SBF_CORE_READY	0x00000004
+#define B43legacy_SBF_400		0x00000400 /*FIXME: fix name*/
+#define B43legacy_SBF_XFER_REG_BYTESWAP	0x00010000
+#define B43legacy_SBF_MODE_NOTADHOC	0x00020000
+#define B43legacy_SBF_MODE_AP		0x00040000
+#define B43legacy_SBF_RADIOREG_LOCK	0x00080000
+#define B43legacy_SBF_MODE_MONITOR	0x00400000
+#define B43legacy_SBF_MODE_PROMISC	0x01000000
+#define B43legacy_SBF_PS1		0x02000000
+#define B43legacy_SBF_PS2		0x04000000
+#define B43legacy_SBF_NO_SSID_BCAST	0x08000000
+#define B43legacy_SBF_TIME_UPDATE	0x10000000
+
+/* 802.11 core specific TM State Low flags */
+#define B43legacy_TMSLOW_GMODE		0x20000000 /* G Mode Enable */
+#define B43legacy_TMSLOW_PLLREFSEL	0x00200000 /* PLL Freq Ref Select */
+#define B43legacy_TMSLOW_MACPHYCLKEN	0x00100000 /* MAC PHY Clock Ctrl Enbl */
+#define B43legacy_TMSLOW_PHYRESET	0x00080000 /* PHY Reset */
+#define B43legacy_TMSLOW_PHYCLKEN	0x00040000 /* PHY Clock Enable */
+
+/* 802.11 core specific TM State High flags */
+#define B43legacy_TMSHIGH_FCLOCK	0x00040000 /* Fast Clock Available */
+#define B43legacy_TMSHIGH_GPHY		0x00010000 /* G-PHY avail (rev >= 5) */
+
+#define B43legacy_UCODEFLAG_AUTODIV       0x0001
+
+/* Generic-Interrupt reasons. */
+#define B43legacy_IRQ_MAC_SUSPENDED	0x00000001
+#define B43legacy_IRQ_BEACON		0x00000002
+#define B43legacy_IRQ_TBTT_INDI		0x00000004 /* Target Beacon Transmit Time */
+#define B43legacy_IRQ_BEACON_TX_OK	0x00000008
+#define B43legacy_IRQ_BEACON_CANCEL	0x00000010
+#define B43legacy_IRQ_ATIM_END		0x00000020
+#define B43legacy_IRQ_PMQ		0x00000040
+#define B43legacy_IRQ_PIO_WORKAROUND	0x00000100
+#define B43legacy_IRQ_MAC_TXERR		0x00000200
+#define B43legacy_IRQ_PHY_TXERR		0x00000800
+#define B43legacy_IRQ_PMEVENT		0x00001000
+#define B43legacy_IRQ_TIMER0		0x00002000
+#define B43legacy_IRQ_TIMER1		0x00004000
+#define B43legacy_IRQ_DMA		0x00008000
+#define B43legacy_IRQ_TXFIFO_FLUSH_OK	0x00010000
+#define B43legacy_IRQ_CCA_MEASURE_OK	0x00020000
+#define B43legacy_IRQ_NOISESAMPLE_OK	0x00040000
+#define B43legacy_IRQ_UCODE_DEBUG	0x08000000
+#define B43legacy_IRQ_RFKILL		0x10000000
+#define B43legacy_IRQ_TX_OK		0x20000000
+#define B43legacy_IRQ_PHY_G_CHANGED	0x40000000
+#define B43legacy_IRQ_TIMEOUT		0x80000000
+
+#define B43legacy_IRQ_ALL		0xFFFFFFFF
+#define B43legacy_IRQ_MASKTEMPLATE	(B43legacy_IRQ_MAC_SUSPENDED |	\
+					 B43legacy_IRQ_BEACON |		\
+					 B43legacy_IRQ_TBTT_INDI |	\
+					 B43legacy_IRQ_ATIM_END |	\
+					 B43legacy_IRQ_PMQ |		\
+					 B43legacy_IRQ_MAC_TXERR |	\
+					 B43legacy_IRQ_PHY_TXERR |	\
+					 B43legacy_IRQ_DMA |		\
+					 B43legacy_IRQ_TXFIFO_FLUSH_OK | \
+					 B43legacy_IRQ_NOISESAMPLE_OK | \
+					 B43legacy_IRQ_UCODE_DEBUG |	\
+					 B43legacy_IRQ_RFKILL |		\
+					 B43legacy_IRQ_TX_OK)
+
+/* Device specific rate values.
+ * The actual values defined here are (rate_in_mbps * 2).
+ * Some code depends on this. Don't change it. */
+#define B43legacy_CCK_RATE_1MB		2
+#define B43legacy_CCK_RATE_2MB		4
+#define B43legacy_CCK_RATE_5MB		11
+#define B43legacy_CCK_RATE_11MB		22
+#define B43legacy_OFDM_RATE_6MB		12
+#define B43legacy_OFDM_RATE_9MB		18
+#define B43legacy_OFDM_RATE_12MB	24
+#define B43legacy_OFDM_RATE_18MB	36
+#define B43legacy_OFDM_RATE_24MB	48
+#define B43legacy_OFDM_RATE_36MB	72
+#define B43legacy_OFDM_RATE_48MB	96
+#define B43legacy_OFDM_RATE_54MB	108
+/* Convert a b43legacy rate value to a rate in 100kbps */
+#define B43legacy_RATE_TO_100KBPS(rate)	(((rate) * 10) / 2)
+
+
+#define B43legacy_DEFAULT_SHORT_RETRY_LIMIT	7
+#define B43legacy_DEFAULT_LONG_RETRY_LIMIT	4
+
+/* Max size of a security key */
+#define B43legacy_SEC_KEYSIZE		16
+/* Security algorithms. */
+enum {
+	B43legacy_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */
+	B43legacy_SEC_ALGO_WEP40,
+	B43legacy_SEC_ALGO_TKIP,
+	B43legacy_SEC_ALGO_AES,
+	B43legacy_SEC_ALGO_WEP104,
+	B43legacy_SEC_ALGO_AES_LEGACY,
+};
+
+/* Core Information Registers */
+#define B43legacy_CIR_BASE                0xf00
+#define B43legacy_CIR_SBTPSFLAG           (B43legacy_CIR_BASE + 0x18)
+#define B43legacy_CIR_SBIMSTATE           (B43legacy_CIR_BASE + 0x90)
+#define B43legacy_CIR_SBINTVEC            (B43legacy_CIR_BASE + 0x94)
+#define B43legacy_CIR_SBTMSTATELOW        (B43legacy_CIR_BASE + 0x98)
+#define B43legacy_CIR_SBTMSTATEHIGH       (B43legacy_CIR_BASE + 0x9c)
+#define B43legacy_CIR_SBIMCONFIGLOW       (B43legacy_CIR_BASE + 0xa8)
+#define B43legacy_CIR_SB_ID_HI            (B43legacy_CIR_BASE + 0xfc)
+
+/* sbtmstatehigh state flags */
+#define B43legacy_SBTMSTATEHIGH_SERROR		0x00000001
+#define B43legacy_SBTMSTATEHIGH_BUSY		0x00000004
+#define B43legacy_SBTMSTATEHIGH_TIMEOUT		0x00000020
+#define B43legacy_SBTMSTATEHIGH_G_PHY_AVAIL	0x00010000
+#define B43legacy_SBTMSTATEHIGH_COREFLAGS	0x1FFF0000
+#define B43legacy_SBTMSTATEHIGH_DMA64BIT	0x10000000
+#define B43legacy_SBTMSTATEHIGH_GATEDCLK	0x20000000
+#define B43legacy_SBTMSTATEHIGH_BISTFAILED	0x40000000
+#define B43legacy_SBTMSTATEHIGH_BISTCOMPLETE	0x80000000
+
+/* sbimstate flags */
+#define B43legacy_SBIMSTATE_IB_ERROR		0x20000
+#define B43legacy_SBIMSTATE_TIMEOUT		0x40000
+
+#define PFX		KBUILD_MODNAME ": "
+#ifdef assert
+# undef assert
+#endif
+#ifdef CONFIG_B43LEGACY_DEBUG
+# define B43legacy_WARN_ON(expr)					\
+	do {								\
+		if (unlikely((expr))) {					\
+			printk(KERN_INFO PFX "Test (%s) failed at:"	\
+					      " %s:%d:%s()\n",		\
+					      #expr, __FILE__,		\
+					      __LINE__, __FUNCTION__);	\
+		}							\
+	} while (0)
+# define B43legacy_BUG_ON(expr)						\
+	do {								\
+		if (unlikely((expr))) {					\
+			printk(KERN_INFO PFX "Test (%s) failed\n",	\
+					      #expr);			\
+			BUG_ON(expr);					\
+		}							\
+	} while (0)
+# define B43legacy_DEBUG	1
+#else
+# define B43legacy_WARN_ON(x)	do { /* nothing */ } while (0)
+# define B43legacy_BUG_ON(x)	do { /* nothing */ } while (0)
+# define B43legacy_DEBUG	0
+#endif
+
+
+struct net_device;
+struct pci_dev;
+struct b43legacy_dmaring;
+struct b43legacy_pioqueue;
+
+/* The firmware file header */
+#define B43legacy_FW_TYPE_UCODE	'u'
+#define B43legacy_FW_TYPE_PCM	'p'
+#define B43legacy_FW_TYPE_IV	'i'
+struct b43legacy_fw_header {
+	/* File type */
+	u8 type;
+	/* File format version */
+	u8 ver;
+	u8 __padding[2];
+	/* Size of the data. For ucode and PCM this is in bytes.
+	 * For IV this is number-of-ivs. */
+	__be32 size;
+} __attribute__((__packed__));
+
+/* Initial Value file format */
+#define B43legacy_IV_OFFSET_MASK	0x7FFF
+#define B43legacy_IV_32BIT		0x8000
+struct b43legacy_iv {
+	__be16 offset_size;
+	union {
+		__be16 d16;
+		__be32 d32;
+	} data __attribute__((__packed__));
+} __attribute__((__packed__));
+
+#define B43legacy_PHYMODE(phytype)	(1 << (phytype))
+#define B43legacy_PHYMODE_B		B43legacy_PHYMODE	\
+					((B43legacy_PHYTYPE_B))
+#define B43legacy_PHYMODE_G		B43legacy_PHYMODE	\
+					((B43legacy_PHYTYPE_G))
+
+/* Value pair to measure the LocalOscillator. */
+struct b43legacy_lopair {
+	s8 low;
+	s8 high;
+	u8 used:1;
+};
+#define B43legacy_LO_COUNT	(14*4)
+
+struct b43legacy_phy {
+	/* Possible PHYMODEs on this PHY */
+	u8 possible_phymodes;
+	/* GMODE bit enabled in MACCTL? */
+	bool gmode;
+	/* Possible ieee80211 subsystem hwmodes for this PHY.
+	 * Which mode is selected, depends on thr GMODE enabled bit */
+#define B43legacy_MAX_PHYHWMODES	2
+	struct ieee80211_hw_mode hwmodes[B43legacy_MAX_PHYHWMODES];
+
+	/* Analog Type */
+	u8 analog;
+	/* B43legacy_PHYTYPE_ */
+	u8 type;
+	/* PHY revision number. */
+	u8 rev;
+
+	u16 antenna_diversity;
+	u16 savedpctlreg;
+	/* Radio versioning */
+	u16 radio_manuf;	/* Radio manufacturer */
+	u16 radio_ver;		/* Radio version */
+	u8 calibrated:1;
+	u8 radio_rev;		/* Radio revision */
+
+	bool locked;		/* Only used in b43legacy_phy_{un}lock() */
+	bool dyn_tssi_tbl;	/* tssi2dbm is kmalloc()ed. */
+
+	/* ACI (adjacent channel interference) flags. */
+	bool aci_enable;
+	bool aci_wlan_automatic;
+	bool aci_hw_rssi;
+
+	/* Radio switched on/off */
+	bool radio_on;
+	struct {
+		/* Values saved when turning the radio off.
+		 * They are needed when turning it on again. */
+		bool valid;
+		u16 rfover;
+		u16 rfoverval;
+	} radio_off_context;
+
+	u16 minlowsig[2];
+	u16 minlowsigpos[2];
+
+	/* LO Measurement Data.
+	 * Use b43legacy_get_lopair() to get a value.
+	 */
+	struct b43legacy_lopair *_lo_pairs;
+	/* TSSI to dBm table in use */
+	const s8 *tssi2dbm;
+	/* idle TSSI value */
+	s8 idle_tssi;
+	/* Target idle TSSI */
+	int tgt_idle_tssi;
+	/* Current idle TSSI */
+	int cur_idle_tssi;
+
+	/* LocalOscillator control values. */
+	struct b43legacy_txpower_lo_control *lo_control;
+	/* Values from b43legacy_calc_loopback_gain() */
+	s16 max_lb_gain;	/* Maximum Loopback gain in hdB */
+	s16 trsw_rx_gain;	/* TRSW RX gain in hdB */
+	s16 lna_lod_gain;	/* LNA lod */
+	s16 lna_gain;		/* LNA */
+	s16 pga_gain;		/* PGA */
+
+	/* PHY lock for core.rev < 3
+	 * This lock is only used by b43legacy_phy_{un}lock()
+	 */
+	spinlock_t lock;
+
+	/* Desired TX power level (in dBm). This is set by the user and
+	 * adjusted in b43legacy_phy_xmitpower(). */
+	u8 power_level;
+
+	/* Values from b43legacy_calc_loopback_gain() */
+	u16 loopback_gain[2];
+
+	/* TX Power control values. */
+	/* B/G PHY */
+	struct {
+		/* Current Radio Attenuation for TXpower recalculation. */
+		u16 rfatt;
+		/* Current Baseband Attenuation for TXpower recalculation. */
+		u16 bbatt;
+		/* Current TXpower control value for TXpower recalculation. */
+		u16 txctl1;
+		u16 txctl2;
+	};
+	/* A PHY */
+	struct {
+		u16 txpwr_offset;
+	};
+
+#ifdef CONFIG_B43LEGACY_DEBUG
+	bool manual_txpower_control; /* Manual TX-power control enabled? */
+#endif
+	/* Current Interference Mitigation mode */
+	int interfmode;
+	/* Stack of saved values from the Interference Mitigation code.
+	 * Each value in the stack is layed out as follows:
+	 * bit 0-11:  offset
+	 * bit 12-15: register ID
+	 * bit 16-32: value
+	 * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT
+	 */
+#define B43legacy_INTERFSTACK_SIZE	26
+	u32 interfstack[B43legacy_INTERFSTACK_SIZE];
+
+	/* Saved values from the NRSSI Slope calculation */
+	s16 nrssi[2];
+	s32 nrssislope;
+	/* In memory nrssi lookup table. */
+	s8 nrssi_lt[64];
+
+	/* current channel */
+	u8 channel;
+
+	u16 lofcal;
+
+	u16 initval;
+};
+
+/* Data structures for DMA transmission, per 80211 core. */
+struct b43legacy_dma {
+	struct b43legacy_dmaring *tx_ring0;
+	struct b43legacy_dmaring *tx_ring1;
+	struct b43legacy_dmaring *tx_ring2;
+	struct b43legacy_dmaring *tx_ring3;
+	struct b43legacy_dmaring *tx_ring4;
+	struct b43legacy_dmaring *tx_ring5;
+
+	struct b43legacy_dmaring *rx_ring0;
+	struct b43legacy_dmaring *rx_ring3; /* only on core.rev < 5 */
+};
+
+/* Data structures for PIO transmission, per 80211 core. */
+struct b43legacy_pio {
+	struct b43legacy_pioqueue *queue0;
+	struct b43legacy_pioqueue *queue1;
+	struct b43legacy_pioqueue *queue2;
+	struct b43legacy_pioqueue *queue3;
+};
+
+/* Context information for a noise calculation (Link Quality). */
+struct b43legacy_noise_calculation {
+	u8 channel_at_start;
+	bool calculation_running;
+	u8 nr_samples;
+	s8 samples[8][4];
+};
+
+struct b43legacy_stats {
+	u8 link_noise;
+	/* Store the last TX/RX times here for updating the leds. */
+	unsigned long last_tx;
+	unsigned long last_rx;
+};
+
+struct b43legacy_key {
+	void *keyconf;
+	bool enabled;
+	u8 algorithm;
+};
+
+struct b43legacy_wldev;
+
+/* Data structure for the WLAN parts (802.11 cores) of the b43legacy chip. */
+struct b43legacy_wl {
+	/* Pointer to the active wireless device on this chip */
+	struct b43legacy_wldev *current_dev;
+	/* Pointer to the ieee80211 hardware data structure */
+	struct ieee80211_hw *hw;
+
+	spinlock_t irq_lock;		/* locks IRQ */
+	struct mutex mutex;		/* locks wireless core state */
+	spinlock_t leds_lock;		/* lock for leds */
+
+	/* We can only have one operating interface (802.11 core)
+	 * at a time. General information about this interface follows.
+	 */
+
+	/* Opaque ID of the operating interface from the ieee80211
+	 * subsystem. Do not modify.
+	 */
+	int if_id;
+	/* MAC address (can be NULL). */
+	u8 mac_addr[ETH_ALEN];
+	/* Current BSSID (can be NULL). */
+	u8 bssid[ETH_ALEN];
+	/* Interface type. (IEEE80211_IF_TYPE_XXX) */
+	int if_type;
+	/* Is the card operating in AP, STA or IBSS mode? */
+	bool operating;
+	/* filter flags */
+	unsigned int filter_flags;
+	/* Stats about the wireless interface */
+	struct ieee80211_low_level_stats ieee_stats;
+
+	struct hwrng rng;
+	u8 rng_initialized;
+	char rng_name[30 + 1];
+
+	/* List of all wireless devices on this chip */
+	struct list_head devlist;
+	u8 nr_devs;
+};
+
+/* Pointers to the firmware data and meta information about it. */
+struct b43legacy_firmware {
+	/* Microcode */
+	const struct firmware *ucode;
+	/* PCM code */
+	const struct firmware *pcm;
+	/* Initial MMIO values for the firmware */
+	const struct firmware *initvals;
+	/* Initial MMIO values for the firmware, band-specific */
+	const struct firmware *initvals_band;
+	/* Firmware revision */
+	u16 rev;
+	/* Firmware patchlevel */
+	u16 patch;
+};
+
+/* Device (802.11 core) initialization status. */
+enum {
+	B43legacy_STAT_UNINIT		= 0, /* Uninitialized. */
+	B43legacy_STAT_INITIALIZED	= 1, /* Initialized, not yet started. */
+	B43legacy_STAT_STARTED	= 2, /* Up and running. */
+};
+#define b43legacy_status(wldev)	atomic_read(&(wldev)->__init_status)
+#define b43legacy_set_status(wldev, stat)	do {		\
+		atomic_set(&(wldev)->__init_status, (stat));	\
+		smp_wmb();					\
+					} while (0)
+
+/* *** ---   HOW LOCKING WORKS IN B43legacy   --- ***
+ *
+ * You should always acquire both, wl->mutex and wl->irq_lock unless:
+ * - You don't need to acquire wl->irq_lock, if the interface is stopped.
+ * - You don't need to acquire wl->mutex in the IRQ handler, IRQ tasklet
+ *   and packet TX path (and _ONLY_ there.)
+ */
+
+/* Data structure for one wireless device (802.11 core) */
+struct b43legacy_wldev {
+	struct ssb_device *dev;
+	struct b43legacy_wl *wl;
+
+	/* The device initialization status.
+	 * Use b43legacy_status() to query. */
+	atomic_t __init_status;
+	/* Saved init status for handling suspend. */
+	int suspend_init_status;
+
+	bool __using_pio;	/* Using pio rather than dma. */
+	bool bad_frames_preempt;/* Use "Bad Frames Preemption". */
+	bool reg124_set_0x4;	/* Variable to keep track of IRQ. */
+	bool short_preamble;	/* TRUE if using short preamble. */
+	bool short_slot;	/* TRUE if using short slot timing. */
+	bool radio_hw_enable;	/* State of radio hardware enable bit. */
+
+	/* PHY/Radio device. */
+	struct b43legacy_phy phy;
+	union {
+		/* DMA engines. */
+		struct b43legacy_dma dma;
+		/* PIO engines. */
+		struct b43legacy_pio pio;
+	};
+
+	/* Various statistics about the physical device. */
+	struct b43legacy_stats stats;
+
+#define B43legacy_NR_LEDS		4
+	struct b43legacy_led leds[B43legacy_NR_LEDS];
+
+	/* Reason code of the last interrupt. */
+	u32 irq_reason;
+	u32 dma_reason[6];
+	/* saved irq enable/disable state bitfield. */
+	u32 irq_savedstate;
+	/* Link Quality calculation context. */
+	struct b43legacy_noise_calculation noisecalc;
+	/* if > 0 MAC is suspended. if == 0 MAC is enabled. */
+	int mac_suspended;
+
+	/* Interrupt Service Routine tasklet (bottom-half) */
+	struct tasklet_struct isr_tasklet;
+
+	/* Periodic tasks */
+	struct delayed_work periodic_work;
+	unsigned int periodic_state;
+
+	struct work_struct restart_work;
+
+	/* encryption/decryption */
+	u16 ktp; /* Key table pointer */
+	u8 max_nr_keys;
+	struct b43legacy_key key[58];
+
+	/* Cached beacon template while uploading the template. */
+	struct sk_buff *cached_beacon;
+
+	/* Firmware data */
+	struct b43legacy_firmware fw;
+
+	/* Devicelist in struct b43legacy_wl (all 802.11 cores) */
+	struct list_head list;
+
+	/* Debugging stuff follows. */
+#ifdef CONFIG_B43LEGACY_DEBUG
+	struct b43legacy_dfsentry *dfsentry;
+#endif
+};
+
+
+static inline
+struct b43legacy_wl *hw_to_b43legacy_wl(struct ieee80211_hw *hw)
+{
+	return hw->priv;
+}
+
+/* Helper function, which returns a boolean.
+ * TRUE, if PIO is used; FALSE, if DMA is used.
+ */
+#if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO)
+static inline
+int b43legacy_using_pio(struct b43legacy_wldev *dev)
+{
+	return dev->__using_pio;
+}
+#elif defined(CONFIG_B43LEGACY_DMA)
+static inline
+int b43legacy_using_pio(struct b43legacy_wldev *dev)
+{
+	return 0;
+}
+#elif defined(CONFIG_B43LEGACY_PIO)
+static inline
+int b43legacy_using_pio(struct b43legacy_wldev *dev)
+{
+	return 1;
+}
+#else
+# error "Using neither DMA nor PIO? Confused..."
+#endif
+
+
+static inline
+struct b43legacy_wldev *dev_to_b43legacy_wldev(struct device *dev)
+{
+	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+	return ssb_get_drvdata(ssb_dev);
+}
+
+/* Is the device operating in a specified mode (IEEE80211_IF_TYPE_XXX). */
+static inline
+int b43legacy_is_mode(struct b43legacy_wl *wl, int type)
+{
+	return (wl->operating &&
+		wl->if_type == type);
+}
+
+static inline
+bool is_bcm_board_vendor(struct b43legacy_wldev *dev)
+{
+	return  (dev->dev->bus->boardinfo.vendor == PCI_VENDOR_ID_BROADCOM);
+}
+
+static inline
+u16 b43legacy_read16(struct b43legacy_wldev *dev, u16 offset)
+{
+	return ssb_read16(dev->dev, offset);
+}
+
+static inline
+void b43legacy_write16(struct b43legacy_wldev *dev, u16 offset, u16 value)
+{
+	ssb_write16(dev->dev, offset, value);
+}
+
+static inline
+u32 b43legacy_read32(struct b43legacy_wldev *dev, u16 offset)
+{
+	return ssb_read32(dev->dev, offset);
+}
+
+static inline
+void b43legacy_write32(struct b43legacy_wldev *dev, u16 offset, u32 value)
+{
+	ssb_write32(dev->dev, offset, value);
+}
+
+static inline
+struct b43legacy_lopair *b43legacy_get_lopair(struct b43legacy_phy *phy,
+					      u16 radio_attenuation,
+					      u16 baseband_attenuation)
+{
+	return phy->_lo_pairs + (radio_attenuation
+			+ 14 * (baseband_attenuation / 2));
+}
+
+
+
+/* Message printing */
+void b43legacyinfo(struct b43legacy_wl *wl, const char *fmt, ...)
+		__attribute__((format(printf, 2, 3)));
+void b43legacyerr(struct b43legacy_wl *wl, const char *fmt, ...)
+		__attribute__((format(printf, 2, 3)));
+void b43legacywarn(struct b43legacy_wl *wl, const char *fmt, ...)
+		__attribute__((format(printf, 2, 3)));
+#if B43legacy_DEBUG
+void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...)
+		__attribute__((format(printf, 2, 3)));
+#else /* DEBUG */
+# define b43legacydbg(wl, fmt...) do { /* nothing */ } while (0)
+#endif /* DEBUG */
+
+
+/** Limit a value between two limits */
+#ifdef limit_value
+# undef limit_value
+#endif
+#define limit_value(value, min, max)  \
+	({						\
+		typeof(value) __value = (value);	\
+		typeof(value) __min = (min);		\
+		typeof(value) __max = (max);		\
+		if (__value < __min)			\
+			__value = __min;		\
+		else if (__value > __max)		\
+			__value = __max;		\
+		__value;				\
+	})
+
+/* Macros for printing a value in Q5.2 format */
+#define Q52_FMT		"%u.%u"
+#define Q52_ARG(q52)	((q52) / 4), (((q52) & 3) * 100 / 4)
+
+#endif /* B43legacy_H_ */
diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c
new file mode 100644
index 0000000..eefa6fb79
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/debugfs.c
@@ -0,0 +1,505 @@
+/*
+
+  Broadcom B43legacy wireless driver
+
+  debugfs driver debugging code
+
+  Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+
+#include "b43legacy.h"
+#include "main.h"
+#include "debugfs.h"
+#include "dma.h"
+#include "pio.h"
+#include "xmit.h"
+
+
+/* The root directory. */
+static struct dentry *rootdir;
+
+struct b43legacy_debugfs_fops {
+	ssize_t (*read)(struct b43legacy_wldev *dev, char *buf, size_t bufsize);
+	int (*write)(struct b43legacy_wldev *dev, const char *buf, size_t count);
+	struct file_operations fops;
+	/* Offset of struct b43legacy_dfs_file in struct b43legacy_dfsentry */
+	size_t file_struct_offset;
+	/* Take wl->irq_lock before calling read/write? */
+	bool take_irqlock;
+};
+
+static inline
+struct b43legacy_dfs_file * fops_to_dfs_file(struct b43legacy_wldev *dev,
+				       const struct b43legacy_debugfs_fops *dfops)
+{
+	void *p;
+
+	p = dev->dfsentry;
+	p += dfops->file_struct_offset;
+
+	return p;
+}
+
+
+#define fappend(fmt, x...)	\
+	do {							\
+		if (bufsize - count)				\
+			count += snprintf(buf + count,		\
+					  bufsize - count,	\
+					  fmt , ##x);		\
+		else						\
+			printk(KERN_ERR "b43legacy: fappend overflow\n"); \
+	} while (0)
+
+
+/* wl->irq_lock is locked */
+static ssize_t tsf_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
+{
+	ssize_t count = 0;
+	u64 tsf;
+
+	b43legacy_tsf_read(dev, &tsf);
+	fappend("0x%08x%08x\n",
+		(unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32),
+		(unsigned int)(tsf & 0xFFFFFFFFULL));
+
+	return count;
+}
+
+/* wl->irq_lock is locked */
+static int tsf_write_file(struct b43legacy_wldev *dev, const char *buf, size_t count)
+{
+	u64 tsf;
+
+	if (sscanf(buf, "%llu", (unsigned long long *)(&tsf)) != 1)
+		return -EINVAL;
+	b43legacy_tsf_write(dev, tsf);
+
+	return 0;
+}
+
+/* wl->irq_lock is locked */
+static ssize_t ucode_regs_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
+{
+	ssize_t count = 0;
+	int i;
+
+	for (i = 0; i < 64; i++) {
+		fappend("r%d = 0x%04x\n", i,
+			b43legacy_shm_read16(dev, B43legacy_SHM_WIRELESS, i));
+	}
+
+	return count;
+}
+
+/* wl->irq_lock is locked */
+static ssize_t shm_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
+{
+	ssize_t count = 0;
+	int i;
+	u16 tmp;
+	__le16 *le16buf = (__le16 *)buf;
+
+	for (i = 0; i < 0x1000; i++) {
+		if (bufsize <= 0)
+			break;
+		tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 2 * i);
+		le16buf[i] = cpu_to_le16(tmp);
+		count += sizeof(tmp);
+		bufsize -= sizeof(tmp);
+	}
+
+	return count;
+}
+
+static ssize_t txstat_read_file(struct b43legacy_wldev *dev, char *buf, size_t bufsize)
+{
+	struct b43legacy_txstatus_log *log = &dev->dfsentry->txstatlog;
+	ssize_t count = 0;
+	unsigned long flags;
+	int i, idx;
+	struct b43legacy_txstatus *stat;
+
+	spin_lock_irqsave(&log->lock, flags);
+	if (log->end < 0) {
+		fappend("Nothing transmitted, yet\n");
+		goto out_unlock;
+	}
+	fappend("b43legacy TX status reports:\n\n"
+		"index | cookie | seq | phy_stat | frame_count | "
+		"rts_count | supp_reason | pm_indicated | "
+		"intermediate | for_ampdu | acked\n" "---\n");
+	i = log->end + 1;
+	idx = 0;
+	while (1) {
+		if (i == B43legacy_NR_LOGGED_TXSTATUS)
+			i = 0;
+		stat = &(log->log[i]);
+		if (stat->cookie) {
+			fappend("%03d | "
+				"0x%04X | 0x%04X | 0x%02X | "
+				"0x%X | 0x%X | "
+				"%u | %u | "
+				"%u | %u | %u\n",
+				idx,
+				stat->cookie, stat->seq, stat->phy_stat,
+				stat->frame_count, stat->rts_count,
+				stat->supp_reason, stat->pm_indicated,
+				stat->intermediate, stat->for_ampdu,
+				stat->acked);
+			idx++;
+		}
+		if (i == log->end)
+			break;
+		i++;
+	}
+out_unlock:
+	spin_unlock_irqrestore(&log->lock, flags);
+
+	return count;
+}
+
+/* wl->irq_lock is locked */
+static int restart_write_file(struct b43legacy_wldev *dev, const char *buf, size_t count)
+{
+	int err = 0;
+
+	if (count > 0 && buf[0] == '1') {
+		b43legacy_controller_restart(dev, "manually restarted");
+	} else
+		err = -EINVAL;
+
+	return err;
+}
+
+#undef fappend
+
+static int b43legacy_debugfs_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf,
+				size_t count, loff_t *ppos)
+{
+	struct b43legacy_wldev *dev;
+	struct b43legacy_debugfs_fops *dfops;
+	struct b43legacy_dfs_file *dfile;
+	ssize_t ret = 0;
+	char *buf;
+	const size_t bufsize = 1024 * 128;
+	const size_t buforder = get_order(bufsize);
+	int err = 0;
+
+	if (!count)
+		return 0;
+	dev = file->private_data;
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&dev->wl->mutex);
+	if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
+		err = -ENODEV;
+		goto out_unlock;
+	}
+
+	dfops = container_of(file->f_op, struct b43legacy_debugfs_fops, fops);
+	if (!dfops->read) {
+		err = -ENOSYS;
+		goto out_unlock;
+	}
+	dfile = fops_to_dfs_file(dev, dfops);
+
+	if (!dfile->buffer) {
+		buf = (char *)__get_free_pages(GFP_KERNEL, buforder);
+		if (!buf) {
+			err = -ENOMEM;
+			goto out_unlock;
+		}
+		memset(buf, 0, bufsize);
+		if (dfops->take_irqlock) {
+			spin_lock_irq(&dev->wl->irq_lock);
+			ret = dfops->read(dev, buf, bufsize);
+			spin_unlock_irq(&dev->wl->irq_lock);
+		} else
+			ret = dfops->read(dev, buf, bufsize);
+		if (ret <= 0) {
+			free_pages((unsigned long)buf, buforder);
+			err = ret;
+			goto out_unlock;
+		}
+		dfile->data_len = ret;
+		dfile->buffer = buf;
+	}
+
+	ret = simple_read_from_buffer(userbuf, count, ppos,
+				      dfile->buffer,
+				      dfile->data_len);
+	if (*ppos >= dfile->data_len) {
+		free_pages((unsigned long)dfile->buffer, buforder);
+		dfile->buffer = NULL;
+		dfile->data_len = 0;
+	}
+out_unlock:
+	mutex_unlock(&dev->wl->mutex);
+
+	return err ? err : ret;
+}
+
+static ssize_t b43legacy_debugfs_write(struct file *file,
+				 const char __user *userbuf,
+				 size_t count, loff_t *ppos)
+{
+	struct b43legacy_wldev *dev;
+	struct b43legacy_debugfs_fops *dfops;
+	char *buf;
+	int err = 0;
+
+	if (!count)
+		return 0;
+	if (count > PAGE_SIZE)
+		return -E2BIG;
+	dev = file->private_data;
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&dev->wl->mutex);
+	if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
+		err = -ENODEV;
+		goto out_unlock;
+	}
+
+	dfops = container_of(file->f_op, struct b43legacy_debugfs_fops, fops);
+	if (!dfops->write) {
+		err = -ENOSYS;
+		goto out_unlock;
+	}
+
+	buf = (char *)get_zeroed_page(GFP_KERNEL);
+	if (!buf) {
+		err = -ENOMEM;
+		goto out_unlock;
+	}
+	if (copy_from_user(buf, userbuf, count)) {
+		err = -EFAULT;
+		goto out_freepage;
+	}
+	if (dfops->take_irqlock) {
+		spin_lock_irq(&dev->wl->irq_lock);
+		err = dfops->write(dev, buf, count);
+		spin_unlock_irq(&dev->wl->irq_lock);
+	} else
+		err = dfops->write(dev, buf, count);
+	if (err)
+		goto out_freepage;
+
+out_freepage:
+	free_page((unsigned long)buf);
+out_unlock:
+	mutex_unlock(&dev->wl->mutex);
+
+	return err ? err : count;
+}
+
+
+#define B43legacy_DEBUGFS_FOPS(name, _read, _write, _take_irqlock)	\
+	static struct b43legacy_debugfs_fops fops_##name = {		\
+		.read	= _read,				\
+		.write	= _write,				\
+		.fops	= {					\
+			.open	= b43legacy_debugfs_open,		\
+			.read	= b43legacy_debugfs_read,		\
+			.write	= b43legacy_debugfs_write,		\
+		},						\
+		.file_struct_offset = offsetof(struct b43legacy_dfsentry, \
+					       file_##name),	\
+		.take_irqlock	= _take_irqlock,		\
+	}
+
+B43legacy_DEBUGFS_FOPS(tsf, tsf_read_file, tsf_write_file, 1);
+B43legacy_DEBUGFS_FOPS(ucode_regs, ucode_regs_read_file, NULL, 1);
+B43legacy_DEBUGFS_FOPS(shm, shm_read_file, NULL, 1);
+B43legacy_DEBUGFS_FOPS(txstat, txstat_read_file, NULL, 0);
+B43legacy_DEBUGFS_FOPS(restart, NULL, restart_write_file, 1);
+
+
+int b43legacy_debug(struct b43legacy_wldev *dev, enum b43legacy_dyndbg feature)
+{
+	return !!(dev->dfsentry && dev->dfsentry->dyn_debug[feature]);
+}
+
+static void b43legacy_remove_dynamic_debug(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_dfsentry *e = dev->dfsentry;
+	int i;
+
+	for (i = 0; i < __B43legacy_NR_DYNDBG; i++)
+		debugfs_remove(e->dyn_debug_dentries[i]);
+}
+
+static void b43legacy_add_dynamic_debug(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_dfsentry *e = dev->dfsentry;
+	struct dentry *d;
+
+#define add_dyn_dbg(name, id, initstate) do {		\
+	e->dyn_debug[id] = (initstate);			\
+	d = debugfs_create_bool(name, 0600, e->subdir,	\
+				&(e->dyn_debug[id]));	\
+	if (!IS_ERR(d))					\
+		e->dyn_debug_dentries[id] = d;		\
+				} while (0)
+
+	add_dyn_dbg("debug_xmitpower", B43legacy_DBG_XMITPOWER, 0);
+	add_dyn_dbg("debug_dmaoverflow", B43legacy_DBG_DMAOVERFLOW, 0);
+	add_dyn_dbg("debug_dmaverbose", B43legacy_DBG_DMAVERBOSE, 0);
+	add_dyn_dbg("debug_pwork_fast", B43legacy_DBG_PWORK_FAST, 0);
+	add_dyn_dbg("debug_pwork_stop", B43legacy_DBG_PWORK_STOP, 0);
+
+#undef add_dyn_dbg
+}
+
+void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_dfsentry *e;
+	struct b43legacy_txstatus_log *log;
+	char devdir[16];
+
+	B43legacy_WARN_ON(!dev);
+	e = kzalloc(sizeof(*e), GFP_KERNEL);
+	if (!e) {
+		b43legacyerr(dev->wl, "debugfs: add device OOM\n");
+		return;
+	}
+	e->dev = dev;
+	log = &e->txstatlog;
+	log->log = kcalloc(B43legacy_NR_LOGGED_TXSTATUS,
+			   sizeof(struct b43legacy_txstatus), GFP_KERNEL);
+	if (!log->log) {
+		b43legacyerr(dev->wl, "debugfs: add device txstatus OOM\n");
+		kfree(e);
+		return;
+	}
+	log->end = -1;
+	spin_lock_init(&log->lock);
+
+	dev->dfsentry = e;
+
+	snprintf(devdir, sizeof(devdir), "%s", wiphy_name(dev->wl->hw->wiphy));
+	e->subdir = debugfs_create_dir(devdir, rootdir);
+	if (!e->subdir || IS_ERR(e->subdir)) {
+		if (e->subdir == ERR_PTR(-ENODEV)) {
+			b43legacydbg(dev->wl, "DebugFS (CONFIG_DEBUG_FS) not "
+			       "enabled in kernel config\n");
+		} else {
+			b43legacyerr(dev->wl, "debugfs: cannot create %s directory\n",
+			       devdir);
+		}
+		dev->dfsentry = NULL;
+		kfree(log->log);
+		kfree(e);
+		return;
+	}
+
+#define ADD_FILE(name, mode)	\
+	do {							\
+		struct dentry *d;				\
+		d = debugfs_create_file(__stringify(name),	\
+					mode, e->subdir, dev,	\
+					&fops_##name.fops);	\
+		e->file_##name.dentry = NULL;			\
+		if (!IS_ERR(d))					\
+			e->file_##name.dentry = d;		\
+	} while (0)
+
+
+	ADD_FILE(tsf, 0600);
+	ADD_FILE(ucode_regs, 0400);
+	ADD_FILE(shm, 0400);
+	ADD_FILE(txstat, 0400);
+	ADD_FILE(restart, 0200);
+
+#undef ADD_FILE
+
+	b43legacy_add_dynamic_debug(dev);
+}
+
+void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_dfsentry *e;
+
+	if (!dev)
+		return;
+	e = dev->dfsentry;
+	if (!e)
+		return;
+	b43legacy_remove_dynamic_debug(dev);
+
+	debugfs_remove(e->file_tsf.dentry);
+	debugfs_remove(e->file_ucode_regs.dentry);
+	debugfs_remove(e->file_shm.dentry);
+	debugfs_remove(e->file_txstat.dentry);
+	debugfs_remove(e->file_restart.dentry);
+
+	debugfs_remove(e->subdir);
+	kfree(e->txstatlog.log);
+	kfree(e);
+}
+
+void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev,
+			    const struct b43legacy_txstatus *status)
+{
+	struct b43legacy_dfsentry *e = dev->dfsentry;
+	struct b43legacy_txstatus_log *log;
+	struct b43legacy_txstatus *cur;
+	int i;
+
+	if (!e)
+		return;
+	log = &e->txstatlog;
+	B43legacy_WARN_ON(!irqs_disabled());
+	spin_lock(&log->lock);
+	i = log->end + 1;
+	if (i == B43legacy_NR_LOGGED_TXSTATUS)
+		i = 0;
+	log->end = i;
+	cur = &(log->log[i]);
+	memcpy(cur, status, sizeof(*cur));
+	spin_unlock(&log->lock);
+}
+
+void b43legacy_debugfs_init(void)
+{
+	rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+	if (IS_ERR(rootdir))
+		rootdir = NULL;
+}
+
+void b43legacy_debugfs_exit(void)
+{
+	debugfs_remove(rootdir);
+}
diff --git a/drivers/net/wireless/b43legacy/debugfs.h b/drivers/net/wireless/b43legacy/debugfs.h
new file mode 100644
index 0000000..ae3b0d0
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/debugfs.h
@@ -0,0 +1,89 @@
+#ifndef B43legacy_DEBUGFS_H_
+#define B43legacy_DEBUGFS_H_
+
+struct b43legacy_wldev;
+struct b43legacy_txstatus;
+
+enum b43legacy_dyndbg { /* Dynamic debugging features */
+	B43legacy_DBG_XMITPOWER,
+	B43legacy_DBG_DMAOVERFLOW,
+	B43legacy_DBG_DMAVERBOSE,
+	B43legacy_DBG_PWORK_FAST,
+	B43legacy_DBG_PWORK_STOP,
+	__B43legacy_NR_DYNDBG,
+};
+
+
+#ifdef CONFIG_B43LEGACY_DEBUG
+
+struct dentry;
+
+#define B43legacy_NR_LOGGED_TXSTATUS	100
+
+struct b43legacy_txstatus_log {
+	struct b43legacy_txstatus *log;
+	int end;
+	spinlock_t lock;	/* lock for debugging */
+};
+
+struct b43legacy_dfs_file {
+	struct dentry *dentry;
+	char *buffer;
+	size_t data_len;
+};
+
+struct b43legacy_dfsentry {
+	struct b43legacy_wldev *dev;
+	struct dentry *subdir;
+
+	struct b43legacy_dfs_file file_tsf;
+	struct b43legacy_dfs_file file_ucode_regs;
+	struct b43legacy_dfs_file file_shm;
+	struct b43legacy_dfs_file file_txstat;
+	struct b43legacy_dfs_file file_txpower_g;
+	struct b43legacy_dfs_file file_restart;
+	struct b43legacy_dfs_file file_loctls;
+
+	struct b43legacy_txstatus_log txstatlog;
+
+	/* Enabled/Disabled list for the dynamic debugging features. */
+	u32 dyn_debug[__B43legacy_NR_DYNDBG];
+	/* Dentries for the dynamic debugging entries. */
+	struct dentry *dyn_debug_dentries[__B43legacy_NR_DYNDBG];
+};
+
+int b43legacy_debug(struct b43legacy_wldev *dev,
+		    enum b43legacy_dyndbg feature);
+
+void b43legacy_debugfs_init(void);
+void b43legacy_debugfs_exit(void);
+void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev);
+void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev);
+void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev,
+				  const struct b43legacy_txstatus *status);
+
+#else /* CONFIG_B43LEGACY_DEBUG*/
+
+static inline
+int b43legacy_debug(struct b43legacy_wldev *dev,
+		    enum b43legacy_dyndbg feature)
+{
+	return 0;
+}
+
+static inline
+void b43legacy_debugfs_init(void) { }
+static inline
+void b43legacy_debugfs_exit(void) { }
+static inline
+void b43legacy_debugfs_add_device(struct b43legacy_wldev *dev) { }
+static inline
+void b43legacy_debugfs_remove_device(struct b43legacy_wldev *dev) { }
+static inline
+void b43legacy_debugfs_log_txstat(struct b43legacy_wldev *dev,
+				  const struct b43legacy_txstatus *status)
+				  { }
+
+#endif /* CONFIG_B43LEGACY_DEBUG*/
+
+#endif /* B43legacy_DEBUGFS_H_ */
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
new file mode 100644
index 0000000..8cb3dc4
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -0,0 +1,1565 @@
+/*
+
+  Broadcom B43legacy wireless driver
+
+  DMA ringbuffer and descriptor allocation/management
+
+  Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+
+  Some code in this file is derived from the b44.c driver
+  Copyright (C) 2002 David S. Miller
+  Copyright (C) Pekka Pietikainen
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43legacy.h"
+#include "dma.h"
+#include "main.h"
+#include "debugfs.h"
+#include "xmit.h"
+
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <net/dst.h>
+
+/* 32bit DMA ops. */
+static
+struct b43legacy_dmadesc_generic *op32_idx2desc(
+					struct b43legacy_dmaring *ring,
+					int slot,
+					struct b43legacy_dmadesc_meta **meta)
+{
+	struct b43legacy_dmadesc32 *desc;
+
+	*meta = &(ring->meta[slot]);
+	desc = ring->descbase;
+	desc = &(desc[slot]);
+
+	return (struct b43legacy_dmadesc_generic *)desc;
+}
+
+static void op32_fill_descriptor(struct b43legacy_dmaring *ring,
+				 struct b43legacy_dmadesc_generic *desc,
+				 dma_addr_t dmaaddr, u16 bufsize,
+				 int start, int end, int irq)
+{
+	struct b43legacy_dmadesc32 *descbase = ring->descbase;
+	int slot;
+	u32 ctl;
+	u32 addr;
+	u32 addrext;
+
+	slot = (int)(&(desc->dma32) - descbase);
+	B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+
+	addr = (u32)(dmaaddr & ~SSB_DMA_TRANSLATION_MASK);
+	addrext = (u32)(dmaaddr & SSB_DMA_TRANSLATION_MASK)
+		   >> SSB_DMA_TRANSLATION_SHIFT;
+	addr |= ssb_dma_translation(ring->dev->dev);
+	ctl = (bufsize - ring->frameoffset)
+	      & B43legacy_DMA32_DCTL_BYTECNT;
+	if (slot == ring->nr_slots - 1)
+		ctl |= B43legacy_DMA32_DCTL_DTABLEEND;
+	if (start)
+		ctl |= B43legacy_DMA32_DCTL_FRAMESTART;
+	if (end)
+		ctl |= B43legacy_DMA32_DCTL_FRAMEEND;
+	if (irq)
+		ctl |= B43legacy_DMA32_DCTL_IRQ;
+	ctl |= (addrext << B43legacy_DMA32_DCTL_ADDREXT_SHIFT)
+	       & B43legacy_DMA32_DCTL_ADDREXT_MASK;
+
+	desc->dma32.control = cpu_to_le32(ctl);
+	desc->dma32.address = cpu_to_le32(addr);
+}
+
+static void op32_poke_tx(struct b43legacy_dmaring *ring, int slot)
+{
+	b43legacy_dma_write(ring, B43legacy_DMA32_TXINDEX,
+			    (u32)(slot * sizeof(struct b43legacy_dmadesc32)));
+}
+
+static void op32_tx_suspend(struct b43legacy_dmaring *ring)
+{
+	b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL,
+			    b43legacy_dma_read(ring, B43legacy_DMA32_TXCTL)
+			    | B43legacy_DMA32_TXSUSPEND);
+}
+
+static void op32_tx_resume(struct b43legacy_dmaring *ring)
+{
+	b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL,
+			    b43legacy_dma_read(ring, B43legacy_DMA32_TXCTL)
+			    & ~B43legacy_DMA32_TXSUSPEND);
+}
+
+static int op32_get_current_rxslot(struct b43legacy_dmaring *ring)
+{
+	u32 val;
+
+	val = b43legacy_dma_read(ring, B43legacy_DMA32_RXSTATUS);
+	val &= B43legacy_DMA32_RXDPTR;
+
+	return (val / sizeof(struct b43legacy_dmadesc32));
+}
+
+static void op32_set_current_rxslot(struct b43legacy_dmaring *ring,
+				    int slot)
+{
+	b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX,
+			    (u32)(slot * sizeof(struct b43legacy_dmadesc32)));
+}
+
+static const struct b43legacy_dma_ops dma32_ops = {
+	.idx2desc		= op32_idx2desc,
+	.fill_descriptor	= op32_fill_descriptor,
+	.poke_tx		= op32_poke_tx,
+	.tx_suspend		= op32_tx_suspend,
+	.tx_resume		= op32_tx_resume,
+	.get_current_rxslot	= op32_get_current_rxslot,
+	.set_current_rxslot	= op32_set_current_rxslot,
+};
+
+/* 64bit DMA ops. */
+static
+struct b43legacy_dmadesc_generic *op64_idx2desc(
+					struct b43legacy_dmaring *ring,
+					int slot,
+					struct b43legacy_dmadesc_meta
+					**meta)
+{
+	struct b43legacy_dmadesc64 *desc;
+
+	*meta = &(ring->meta[slot]);
+	desc = ring->descbase;
+	desc = &(desc[slot]);
+
+	return (struct b43legacy_dmadesc_generic *)desc;
+}
+
+static void op64_fill_descriptor(struct b43legacy_dmaring *ring,
+				 struct b43legacy_dmadesc_generic *desc,
+				 dma_addr_t dmaaddr, u16 bufsize,
+				 int start, int end, int irq)
+{
+	struct b43legacy_dmadesc64 *descbase = ring->descbase;
+	int slot;
+	u32 ctl0 = 0;
+	u32 ctl1 = 0;
+	u32 addrlo;
+	u32 addrhi;
+	u32 addrext;
+
+	slot = (int)(&(desc->dma64) - descbase);
+	B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+
+	addrlo = (u32)(dmaaddr & 0xFFFFFFFF);
+	addrhi = (((u64)dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
+	addrext = (((u64)dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
+		  >> SSB_DMA_TRANSLATION_SHIFT;
+	addrhi |= ssb_dma_translation(ring->dev->dev);
+	if (slot == ring->nr_slots - 1)
+		ctl0 |= B43legacy_DMA64_DCTL0_DTABLEEND;
+	if (start)
+		ctl0 |= B43legacy_DMA64_DCTL0_FRAMESTART;
+	if (end)
+		ctl0 |= B43legacy_DMA64_DCTL0_FRAMEEND;
+	if (irq)
+		ctl0 |= B43legacy_DMA64_DCTL0_IRQ;
+	ctl1 |= (bufsize - ring->frameoffset)
+		& B43legacy_DMA64_DCTL1_BYTECNT;
+	ctl1 |= (addrext << B43legacy_DMA64_DCTL1_ADDREXT_SHIFT)
+		& B43legacy_DMA64_DCTL1_ADDREXT_MASK;
+
+	desc->dma64.control0 = cpu_to_le32(ctl0);
+	desc->dma64.control1 = cpu_to_le32(ctl1);
+	desc->dma64.address_low = cpu_to_le32(addrlo);
+	desc->dma64.address_high = cpu_to_le32(addrhi);
+}
+
+static void op64_poke_tx(struct b43legacy_dmaring *ring, int slot)
+{
+	b43legacy_dma_write(ring, B43legacy_DMA64_TXINDEX,
+			    (u32)(slot * sizeof(struct b43legacy_dmadesc64)));
+}
+
+static void op64_tx_suspend(struct b43legacy_dmaring *ring)
+{
+	b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
+			    b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL)
+			    | B43legacy_DMA64_TXSUSPEND);
+}
+
+static void op64_tx_resume(struct b43legacy_dmaring *ring)
+{
+	b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
+			    b43legacy_dma_read(ring, B43legacy_DMA64_TXCTL)
+			    & ~B43legacy_DMA64_TXSUSPEND);
+}
+
+static int op64_get_current_rxslot(struct b43legacy_dmaring *ring)
+{
+	u32 val;
+
+	val = b43legacy_dma_read(ring, B43legacy_DMA64_RXSTATUS);
+	val &= B43legacy_DMA64_RXSTATDPTR;
+
+	return (val / sizeof(struct b43legacy_dmadesc64));
+}
+
+static void op64_set_current_rxslot(struct b43legacy_dmaring *ring,
+				    int slot)
+{
+	b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX,
+			    (u32)(slot * sizeof(struct b43legacy_dmadesc64)));
+}
+
+static const struct b43legacy_dma_ops dma64_ops = {
+	.idx2desc		= op64_idx2desc,
+	.fill_descriptor	= op64_fill_descriptor,
+	.poke_tx		= op64_poke_tx,
+	.tx_suspend		= op64_tx_suspend,
+	.tx_resume		= op64_tx_resume,
+	.get_current_rxslot	= op64_get_current_rxslot,
+	.set_current_rxslot	= op64_set_current_rxslot,
+};
+
+
+static inline int free_slots(struct b43legacy_dmaring *ring)
+{
+	return (ring->nr_slots - ring->used_slots);
+}
+
+static inline int next_slot(struct b43legacy_dmaring *ring, int slot)
+{
+	B43legacy_WARN_ON(!(slot >= -1 && slot <= ring->nr_slots - 1));
+	if (slot == ring->nr_slots - 1)
+		return 0;
+	return slot + 1;
+}
+
+static inline int prev_slot(struct b43legacy_dmaring *ring, int slot)
+{
+	B43legacy_WARN_ON(!(slot >= 0 && slot <= ring->nr_slots - 1));
+	if (slot == 0)
+		return ring->nr_slots - 1;
+	return slot - 1;
+}
+
+#ifdef CONFIG_B43LEGACY_DEBUG
+static void update_max_used_slots(struct b43legacy_dmaring *ring,
+				  int current_used_slots)
+{
+	if (current_used_slots <= ring->max_used_slots)
+		return;
+	ring->max_used_slots = current_used_slots;
+	if (b43legacy_debug(ring->dev, B43legacy_DBG_DMAVERBOSE))
+		b43legacydbg(ring->dev->wl,
+		       "max_used_slots increased to %d on %s ring %d\n",
+		       ring->max_used_slots,
+		       ring->tx ? "TX" : "RX",
+		       ring->index);
+}
+#else
+static inline
+void update_max_used_slots(struct b43legacy_dmaring *ring,
+			   int current_used_slots)
+{ }
+#endif /* DEBUG */
+
+/* Request a slot for usage. */
+static inline
+int request_slot(struct b43legacy_dmaring *ring)
+{
+	int slot;
+
+	B43legacy_WARN_ON(!ring->tx);
+	B43legacy_WARN_ON(ring->stopped);
+	B43legacy_WARN_ON(free_slots(ring) == 0);
+
+	slot = next_slot(ring, ring->current_slot);
+	ring->current_slot = slot;
+	ring->used_slots++;
+
+	update_max_used_slots(ring, ring->used_slots);
+
+	return slot;
+}
+
+/* Mac80211-queue to b43legacy-ring mapping */
+static struct b43legacy_dmaring *priority_to_txring(
+						struct b43legacy_wldev *dev,
+						int queue_priority)
+{
+	struct b43legacy_dmaring *ring;
+
+/*FIXME: For now we always run on TX-ring-1 */
+return dev->dma.tx_ring1;
+
+	/* 0 = highest priority */
+	switch (queue_priority) {
+	default:
+		B43legacy_WARN_ON(1);
+		/* fallthrough */
+	case 0:
+		ring = dev->dma.tx_ring3;
+		break;
+	case 1:
+		ring = dev->dma.tx_ring2;
+		break;
+	case 2:
+		ring = dev->dma.tx_ring1;
+		break;
+	case 3:
+		ring = dev->dma.tx_ring0;
+		break;
+	case 4:
+		ring = dev->dma.tx_ring4;
+		break;
+	case 5:
+		ring = dev->dma.tx_ring5;
+		break;
+	}
+
+	return ring;
+}
+
+/* Bcm4301-ring to mac80211-queue mapping */
+static inline int txring_to_priority(struct b43legacy_dmaring *ring)
+{
+	static const u8 idx_to_prio[] =
+		{ 3, 2, 1, 0, 4, 5, };
+
+/*FIXME: have only one queue, for now */
+return 0;
+
+	return idx_to_prio[ring->index];
+}
+
+
+u16 b43legacy_dmacontroller_base(int dma64bit, int controller_idx)
+{
+	static const u16 map64[] = {
+		B43legacy_MMIO_DMA64_BASE0,
+		B43legacy_MMIO_DMA64_BASE1,
+		B43legacy_MMIO_DMA64_BASE2,
+		B43legacy_MMIO_DMA64_BASE3,
+		B43legacy_MMIO_DMA64_BASE4,
+		B43legacy_MMIO_DMA64_BASE5,
+	};
+	static const u16 map32[] = {
+		B43legacy_MMIO_DMA32_BASE0,
+		B43legacy_MMIO_DMA32_BASE1,
+		B43legacy_MMIO_DMA32_BASE2,
+		B43legacy_MMIO_DMA32_BASE3,
+		B43legacy_MMIO_DMA32_BASE4,
+		B43legacy_MMIO_DMA32_BASE5,
+	};
+
+	if (dma64bit) {
+		B43legacy_WARN_ON(!(controller_idx >= 0 &&
+				  controller_idx < ARRAY_SIZE(map64)));
+		return map64[controller_idx];
+	}
+	B43legacy_WARN_ON(!(controller_idx >= 0 &&
+			  controller_idx < ARRAY_SIZE(map32)));
+	return map32[controller_idx];
+}
+
+static inline
+dma_addr_t map_descbuffer(struct b43legacy_dmaring *ring,
+			  unsigned char *buf,
+			  size_t len,
+			  int tx)
+{
+	dma_addr_t dmaaddr;
+
+	if (tx)
+		dmaaddr = dma_map_single(ring->dev->dev->dev,
+					 buf, len,
+					 DMA_TO_DEVICE);
+	else
+		dmaaddr = dma_map_single(ring->dev->dev->dev,
+					 buf, len,
+					 DMA_FROM_DEVICE);
+
+	return dmaaddr;
+}
+
+static inline
+void unmap_descbuffer(struct b43legacy_dmaring *ring,
+		      dma_addr_t addr,
+		      size_t len,
+		      int tx)
+{
+	if (tx)
+		dma_unmap_single(ring->dev->dev->dev,
+				 addr, len,
+				 DMA_TO_DEVICE);
+	else
+		dma_unmap_single(ring->dev->dev->dev,
+				 addr, len,
+				 DMA_FROM_DEVICE);
+}
+
+static inline
+void sync_descbuffer_for_cpu(struct b43legacy_dmaring *ring,
+			     dma_addr_t addr,
+			     size_t len)
+{
+	B43legacy_WARN_ON(ring->tx);
+
+	dma_sync_single_for_cpu(ring->dev->dev->dev,
+				addr, len, DMA_FROM_DEVICE);
+}
+
+static inline
+void sync_descbuffer_for_device(struct b43legacy_dmaring *ring,
+				dma_addr_t addr,
+				size_t len)
+{
+	B43legacy_WARN_ON(ring->tx);
+
+	dma_sync_single_for_device(ring->dev->dev->dev,
+				   addr, len, DMA_FROM_DEVICE);
+}
+
+static inline
+void free_descriptor_buffer(struct b43legacy_dmaring *ring,
+			    struct b43legacy_dmadesc_meta *meta,
+			    int irq_context)
+{
+	if (meta->skb) {
+		if (irq_context)
+			dev_kfree_skb_irq(meta->skb);
+		else
+			dev_kfree_skb(meta->skb);
+		meta->skb = NULL;
+	}
+}
+
+static int alloc_ringmemory(struct b43legacy_dmaring *ring)
+{
+	struct device *dev = ring->dev->dev->dev;
+
+	ring->descbase = dma_alloc_coherent(dev, B43legacy_DMA_RINGMEMSIZE,
+					    &(ring->dmabase), GFP_KERNEL);
+	if (!ring->descbase) {
+		b43legacyerr(ring->dev->wl, "DMA ringmemory allocation"
+			     " failed\n");
+		return -ENOMEM;
+	}
+	memset(ring->descbase, 0, B43legacy_DMA_RINGMEMSIZE);
+
+	return 0;
+}
+
+static void free_ringmemory(struct b43legacy_dmaring *ring)
+{
+	struct device *dev = ring->dev->dev->dev;
+
+	dma_free_coherent(dev, B43legacy_DMA_RINGMEMSIZE,
+			  ring->descbase, ring->dmabase);
+}
+
+/* Reset the RX DMA channel */
+int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
+				     u16 mmio_base, int dma64)
+{
+	int i;
+	u32 value;
+	u16 offset;
+
+	might_sleep();
+
+	offset = dma64 ? B43legacy_DMA64_RXCTL : B43legacy_DMA32_RXCTL;
+	b43legacy_write32(dev, mmio_base + offset, 0);
+	for (i = 0; i < 10; i++) {
+		offset = dma64 ? B43legacy_DMA64_RXSTATUS :
+			 B43legacy_DMA32_RXSTATUS;
+		value = b43legacy_read32(dev, mmio_base + offset);
+		if (dma64) {
+			value &= B43legacy_DMA64_RXSTAT;
+			if (value == B43legacy_DMA64_RXSTAT_DISABLED) {
+				i = -1;
+				break;
+			}
+		} else {
+			value &= B43legacy_DMA32_RXSTATE;
+			if (value == B43legacy_DMA32_RXSTAT_DISABLED) {
+				i = -1;
+				break;
+			}
+		}
+		msleep(1);
+	}
+	if (i != -1) {
+		b43legacyerr(dev->wl, "DMA RX reset timed out\n");
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/* Reset the RX DMA channel */
+int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
+				     u16 mmio_base, int dma64)
+{
+	int i;
+	u32 value;
+	u16 offset;
+
+	might_sleep();
+
+	for (i = 0; i < 10; i++) {
+		offset = dma64 ? B43legacy_DMA64_TXSTATUS :
+			 B43legacy_DMA32_TXSTATUS;
+		value = b43legacy_read32(dev, mmio_base + offset);
+		if (dma64) {
+			value &= B43legacy_DMA64_TXSTAT;
+			if (value == B43legacy_DMA64_TXSTAT_DISABLED ||
+			    value == B43legacy_DMA64_TXSTAT_IDLEWAIT ||
+			    value == B43legacy_DMA64_TXSTAT_STOPPED)
+				break;
+		} else {
+			value &= B43legacy_DMA32_TXSTATE;
+			if (value == B43legacy_DMA32_TXSTAT_DISABLED ||
+			    value == B43legacy_DMA32_TXSTAT_IDLEWAIT ||
+			    value == B43legacy_DMA32_TXSTAT_STOPPED)
+				break;
+		}
+		msleep(1);
+	}
+	offset = dma64 ? B43legacy_DMA64_TXCTL : B43legacy_DMA32_TXCTL;
+	b43legacy_write32(dev, mmio_base + offset, 0);
+	for (i = 0; i < 10; i++) {
+		offset = dma64 ? B43legacy_DMA64_TXSTATUS :
+			 B43legacy_DMA32_TXSTATUS;
+		value = b43legacy_read32(dev, mmio_base + offset);
+		if (dma64) {
+			value &= B43legacy_DMA64_TXSTAT;
+			if (value == B43legacy_DMA64_TXSTAT_DISABLED) {
+				i = -1;
+				break;
+			}
+		} else {
+			value &= B43legacy_DMA32_TXSTATE;
+			if (value == B43legacy_DMA32_TXSTAT_DISABLED) {
+				i = -1;
+				break;
+			}
+		}
+		msleep(1);
+	}
+	if (i != -1) {
+		b43legacyerr(dev->wl, "DMA TX reset timed out\n");
+		return -ENODEV;
+	}
+	/* ensure the reset is completed. */
+	msleep(1);
+
+	return 0;
+}
+
+static int setup_rx_descbuffer(struct b43legacy_dmaring *ring,
+			       struct b43legacy_dmadesc_generic *desc,
+			       struct b43legacy_dmadesc_meta *meta,
+			       gfp_t gfp_flags)
+{
+	struct b43legacy_rxhdr_fw3 *rxhdr;
+	struct b43legacy_hwtxstatus *txstat;
+	dma_addr_t dmaaddr;
+	struct sk_buff *skb;
+
+	B43legacy_WARN_ON(ring->tx);
+
+	skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
+	if (unlikely(!skb))
+		return -ENOMEM;
+	dmaaddr = map_descbuffer(ring, skb->data,
+				 ring->rx_buffersize, 0);
+	if (dma_mapping_error(dmaaddr)) {
+		/* ugh. try to realloc in zone_dma */
+		gfp_flags |= GFP_DMA;
+
+		dev_kfree_skb_any(skb);
+
+		skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
+		if (unlikely(!skb))
+			return -ENOMEM;
+		dmaaddr = map_descbuffer(ring, skb->data,
+					 ring->rx_buffersize, 0);
+	}
+
+	if (dma_mapping_error(dmaaddr)) {
+		dev_kfree_skb_any(skb);
+		return -EIO;
+	}
+
+	meta->skb = skb;
+	meta->dmaaddr = dmaaddr;
+	ring->ops->fill_descriptor(ring, desc, dmaaddr,
+				   ring->rx_buffersize, 0, 0, 0);
+
+	rxhdr = (struct b43legacy_rxhdr_fw3 *)(skb->data);
+	rxhdr->frame_len = 0;
+	txstat = (struct b43legacy_hwtxstatus *)(skb->data);
+	txstat->cookie = 0;
+
+	return 0;
+}
+
+/* Allocate the initial descbuffers.
+ * This is used for an RX ring only.
+ */
+static int alloc_initial_descbuffers(struct b43legacy_dmaring *ring)
+{
+	int i;
+	int err = -ENOMEM;
+	struct b43legacy_dmadesc_generic *desc;
+	struct b43legacy_dmadesc_meta *meta;
+
+	for (i = 0; i < ring->nr_slots; i++) {
+		desc = ring->ops->idx2desc(ring, i, &meta);
+
+		err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
+		if (err) {
+			b43legacyerr(ring->dev->wl,
+			       "Failed to allocate initial descbuffers\n");
+			goto err_unwind;
+		}
+	}
+	mb(); /* all descbuffer setup before next line */
+	ring->used_slots = ring->nr_slots;
+	err = 0;
+out:
+	return err;
+
+err_unwind:
+	for (i--; i >= 0; i--) {
+		desc = ring->ops->idx2desc(ring, i, &meta);
+
+		unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
+		dev_kfree_skb(meta->skb);
+	}
+	goto out;
+}
+
+/* Do initial setup of the DMA controller.
+ * Reset the controller, write the ring busaddress
+ * and switch the "enable" bit on.
+ */
+static int dmacontroller_setup(struct b43legacy_dmaring *ring)
+{
+	int err = 0;
+	u32 value;
+	u32 addrext;
+	u32 trans = ssb_dma_translation(ring->dev->dev);
+
+	if (ring->tx) {
+		if (ring->dma64) {
+			u64 ringbase = (u64)(ring->dmabase);
+
+			addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
+				  >> SSB_DMA_TRANSLATION_SHIFT;
+			value = B43legacy_DMA64_TXENABLE;
+			value |= (addrext << B43legacy_DMA64_TXADDREXT_SHIFT)
+				& B43legacy_DMA64_TXADDREXT_MASK;
+			b43legacy_dma_write(ring, B43legacy_DMA64_TXCTL,
+					    value);
+			b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO,
+					    (ringbase & 0xFFFFFFFF));
+			b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI,
+					    ((ringbase >> 32)
+					    & ~SSB_DMA_TRANSLATION_MASK)
+					    | trans);
+		} else {
+			u32 ringbase = (u32)(ring->dmabase);
+
+			addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
+				  >> SSB_DMA_TRANSLATION_SHIFT;
+			value = B43legacy_DMA32_TXENABLE;
+			value |= (addrext << B43legacy_DMA32_TXADDREXT_SHIFT)
+				& B43legacy_DMA32_TXADDREXT_MASK;
+			b43legacy_dma_write(ring, B43legacy_DMA32_TXCTL,
+					    value);
+			b43legacy_dma_write(ring, B43legacy_DMA32_TXRING,
+					    (ringbase &
+					    ~SSB_DMA_TRANSLATION_MASK)
+					    | trans);
+		}
+	} else {
+		err = alloc_initial_descbuffers(ring);
+		if (err)
+			goto out;
+		if (ring->dma64) {
+			u64 ringbase = (u64)(ring->dmabase);
+
+			addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK)
+				  >> SSB_DMA_TRANSLATION_SHIFT;
+			value = (ring->frameoffset <<
+				 B43legacy_DMA64_RXFROFF_SHIFT);
+			value |= B43legacy_DMA64_RXENABLE;
+			value |= (addrext << B43legacy_DMA64_RXADDREXT_SHIFT)
+				& B43legacy_DMA64_RXADDREXT_MASK;
+			b43legacy_dma_write(ring, B43legacy_DMA64_RXCTL,
+					    value);
+			b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO,
+					    (ringbase & 0xFFFFFFFF));
+			b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI,
+					    ((ringbase >> 32) &
+					    ~SSB_DMA_TRANSLATION_MASK) |
+					    trans);
+			b43legacy_dma_write(ring, B43legacy_DMA64_RXINDEX,
+					    200);
+		} else {
+			u32 ringbase = (u32)(ring->dmabase);
+
+			addrext = (ringbase & SSB_DMA_TRANSLATION_MASK)
+				  >> SSB_DMA_TRANSLATION_SHIFT;
+			value = (ring->frameoffset <<
+				 B43legacy_DMA32_RXFROFF_SHIFT);
+			value |= B43legacy_DMA32_RXENABLE;
+			value |= (addrext <<
+				 B43legacy_DMA32_RXADDREXT_SHIFT)
+				 & B43legacy_DMA32_RXADDREXT_MASK;
+			b43legacy_dma_write(ring, B43legacy_DMA32_RXCTL,
+					    value);
+			b43legacy_dma_write(ring, B43legacy_DMA32_RXRING,
+					    (ringbase &
+					    ~SSB_DMA_TRANSLATION_MASK)
+					    | trans);
+			b43legacy_dma_write(ring, B43legacy_DMA32_RXINDEX,
+					    200);
+		}
+	}
+
+out:
+	return err;
+}
+
+/* Shutdown the DMA controller. */
+static void dmacontroller_cleanup(struct b43legacy_dmaring *ring)
+{
+	if (ring->tx) {
+		b43legacy_dmacontroller_tx_reset(ring->dev, ring->mmio_base,
+						 ring->dma64);
+		if (ring->dma64) {
+			b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO, 0);
+			b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI, 0);
+		} else
+			b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0);
+	} else {
+		b43legacy_dmacontroller_rx_reset(ring->dev, ring->mmio_base,
+						 ring->dma64);
+		if (ring->dma64) {
+			b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO, 0);
+			b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI, 0);
+		} else
+			b43legacy_dma_write(ring, B43legacy_DMA32_RXRING, 0);
+	}
+}
+
+static void free_all_descbuffers(struct b43legacy_dmaring *ring)
+{
+	struct b43legacy_dmadesc_generic *desc;
+	struct b43legacy_dmadesc_meta *meta;
+	int i;
+
+	if (!ring->used_slots)
+		return;
+	for (i = 0; i < ring->nr_slots; i++) {
+		desc = ring->ops->idx2desc(ring, i, &meta);
+
+		if (!meta->skb) {
+			B43legacy_WARN_ON(!ring->tx);
+			continue;
+		}
+		if (ring->tx)
+			unmap_descbuffer(ring, meta->dmaaddr,
+					 meta->skb->len, 1);
+		else
+			unmap_descbuffer(ring, meta->dmaaddr,
+					 ring->rx_buffersize, 0);
+		free_descriptor_buffer(ring, meta, 0);
+	}
+}
+
+static u64 supported_dma_mask(struct b43legacy_wldev *dev)
+{
+	u32 tmp;
+	u16 mmio_base;
+
+	tmp = b43legacy_read32(dev, SSB_TMSHIGH);
+	if (tmp & SSB_TMSHIGH_DMA64)
+		return DMA_64BIT_MASK;
+	mmio_base = b43legacy_dmacontroller_base(0, 0);
+	b43legacy_write32(dev,
+			mmio_base + B43legacy_DMA32_TXCTL,
+			B43legacy_DMA32_TXADDREXT_MASK);
+	tmp = b43legacy_read32(dev, mmio_base +
+			       B43legacy_DMA32_TXCTL);
+	if (tmp & B43legacy_DMA32_TXADDREXT_MASK)
+		return DMA_32BIT_MASK;
+
+	return DMA_30BIT_MASK;
+}
+
+/* Main initialization function. */
+static
+struct b43legacy_dmaring *b43legacy_setup_dmaring(
+					struct b43legacy_wldev *dev,
+					int controller_index,
+					int for_tx,
+					int dma64)
+{
+	struct b43legacy_dmaring *ring;
+	int err;
+	int nr_slots;
+	dma_addr_t dma_test;
+
+	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+	if (!ring)
+		goto out;
+
+	nr_slots = B43legacy_RXRING_SLOTS;
+	if (for_tx)
+		nr_slots = B43legacy_TXRING_SLOTS;
+
+	ring->meta = kcalloc(nr_slots, sizeof(struct b43legacy_dmadesc_meta),
+			     GFP_KERNEL);
+	if (!ring->meta)
+		goto err_kfree_ring;
+	if (for_tx) {
+		ring->txhdr_cache = kcalloc(nr_slots,
+					sizeof(struct b43legacy_txhdr_fw3),
+					GFP_KERNEL);
+		if (!ring->txhdr_cache)
+			goto err_kfree_meta;
+
+		/* test for ability to dma to txhdr_cache */
+		dma_test = dma_map_single(dev->dev->dev,
+				ring->txhdr_cache,
+				sizeof(struct b43legacy_txhdr_fw3),
+				DMA_TO_DEVICE);
+
+		if (dma_mapping_error(dma_test)) {
+			/* ugh realloc */
+			kfree(ring->txhdr_cache);
+			ring->txhdr_cache = kcalloc(nr_slots,
+					sizeof(struct b43legacy_txhdr_fw3),
+					GFP_KERNEL | GFP_DMA);
+			if (!ring->txhdr_cache)
+				goto err_kfree_meta;
+
+			dma_test = dma_map_single(dev->dev->dev,
+					ring->txhdr_cache,
+					sizeof(struct b43legacy_txhdr_fw3),
+					DMA_TO_DEVICE);
+
+			if (dma_mapping_error(dma_test))
+				goto err_kfree_txhdr_cache;
+		}
+
+		dma_unmap_single(dev->dev->dev,
+				 dma_test, sizeof(struct b43legacy_txhdr_fw3),
+				 DMA_TO_DEVICE);
+	}
+
+	ring->dev = dev;
+	ring->nr_slots = nr_slots;
+	ring->mmio_base = b43legacy_dmacontroller_base(dma64,
+						       controller_index);
+	ring->index = controller_index;
+	ring->dma64 = !!dma64;
+	if (dma64)
+		ring->ops = &dma64_ops;
+	else
+		ring->ops = &dma32_ops;
+	if (for_tx) {
+		ring->tx = 1;
+		ring->current_slot = -1;
+	} else {
+		if (ring->index == 0) {
+			ring->rx_buffersize = B43legacy_DMA0_RX_BUFFERSIZE;
+			ring->frameoffset = B43legacy_DMA0_RX_FRAMEOFFSET;
+		} else if (ring->index == 3) {
+			ring->rx_buffersize = B43legacy_DMA3_RX_BUFFERSIZE;
+			ring->frameoffset = B43legacy_DMA3_RX_FRAMEOFFSET;
+		} else
+			B43legacy_WARN_ON(1);
+	}
+	spin_lock_init(&ring->lock);
+#ifdef CONFIG_B43LEGACY_DEBUG
+	ring->last_injected_overflow = jiffies;
+#endif
+
+	err = alloc_ringmemory(ring);
+	if (err)
+		goto err_kfree_txhdr_cache;
+	err = dmacontroller_setup(ring);
+	if (err)
+		goto err_free_ringmemory;
+
+out:
+	return ring;
+
+err_free_ringmemory:
+	free_ringmemory(ring);
+err_kfree_txhdr_cache:
+	kfree(ring->txhdr_cache);
+err_kfree_meta:
+	kfree(ring->meta);
+err_kfree_ring:
+	kfree(ring);
+	ring = NULL;
+	goto out;
+}
+
+/* Main cleanup function. */
+static void b43legacy_destroy_dmaring(struct b43legacy_dmaring *ring)
+{
+	if (!ring)
+		return;
+
+	b43legacydbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots:"
+		     " %d/%d\n", (ring->dma64) ? "64" : "32", ring->mmio_base,
+		     (ring->tx) ? "TX" : "RX",
+		     ring->max_used_slots, ring->nr_slots);
+	/* Device IRQs are disabled prior entering this function,
+	 * so no need to take care of concurrency with rx handler stuff.
+	 */
+	dmacontroller_cleanup(ring);
+	free_all_descbuffers(ring);
+	free_ringmemory(ring);
+
+	kfree(ring->txhdr_cache);
+	kfree(ring->meta);
+	kfree(ring);
+}
+
+void b43legacy_dma_free(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_dma *dma;
+
+	if (b43legacy_using_pio(dev))
+		return;
+	dma = &dev->dma;
+
+	b43legacy_destroy_dmaring(dma->rx_ring3);
+	dma->rx_ring3 = NULL;
+	b43legacy_destroy_dmaring(dma->rx_ring0);
+	dma->rx_ring0 = NULL;
+
+	b43legacy_destroy_dmaring(dma->tx_ring5);
+	dma->tx_ring5 = NULL;
+	b43legacy_destroy_dmaring(dma->tx_ring4);
+	dma->tx_ring4 = NULL;
+	b43legacy_destroy_dmaring(dma->tx_ring3);
+	dma->tx_ring3 = NULL;
+	b43legacy_destroy_dmaring(dma->tx_ring2);
+	dma->tx_ring2 = NULL;
+	b43legacy_destroy_dmaring(dma->tx_ring1);
+	dma->tx_ring1 = NULL;
+	b43legacy_destroy_dmaring(dma->tx_ring0);
+	dma->tx_ring0 = NULL;
+}
+
+int b43legacy_dma_init(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_dma *dma = &dev->dma;
+	struct b43legacy_dmaring *ring;
+	int err;
+	u64 dmamask;
+	int dma64 = 0;
+
+	dmamask = supported_dma_mask(dev);
+	if (dmamask == DMA_64BIT_MASK)
+		dma64 = 1;
+
+	err = ssb_dma_set_mask(dev->dev, dmamask);
+	if (err) {
+#ifdef BCM43XX_PIO
+		b43legacywarn(dev->wl, "DMA for this device not supported. "
+			"Falling back to PIO\n");
+		dev->__using_pio = 1;
+		return -EAGAIN;
+#else
+		b43legacyerr(dev->wl, "DMA for this device not supported and "
+		       "no PIO support compiled in\n");
+		return -EOPNOTSUPP;
+#endif
+	}
+
+	err = -ENOMEM;
+	/* setup TX DMA channels. */
+	ring = b43legacy_setup_dmaring(dev, 0, 1, dma64);
+	if (!ring)
+		goto out;
+	dma->tx_ring0 = ring;
+
+	ring = b43legacy_setup_dmaring(dev, 1, 1, dma64);
+	if (!ring)
+		goto err_destroy_tx0;
+	dma->tx_ring1 = ring;
+
+	ring = b43legacy_setup_dmaring(dev, 2, 1, dma64);
+	if (!ring)
+		goto err_destroy_tx1;
+	dma->tx_ring2 = ring;
+
+	ring = b43legacy_setup_dmaring(dev, 3, 1, dma64);
+	if (!ring)
+		goto err_destroy_tx2;
+	dma->tx_ring3 = ring;
+
+	ring = b43legacy_setup_dmaring(dev, 4, 1, dma64);
+	if (!ring)
+		goto err_destroy_tx3;
+	dma->tx_ring4 = ring;
+
+	ring = b43legacy_setup_dmaring(dev, 5, 1, dma64);
+	if (!ring)
+		goto err_destroy_tx4;
+	dma->tx_ring5 = ring;
+
+	/* setup RX DMA channels. */
+	ring = b43legacy_setup_dmaring(dev, 0, 0, dma64);
+	if (!ring)
+		goto err_destroy_tx5;
+	dma->rx_ring0 = ring;
+
+	if (dev->dev->id.revision < 5) {
+		ring = b43legacy_setup_dmaring(dev, 3, 0, dma64);
+		if (!ring)
+			goto err_destroy_rx0;
+		dma->rx_ring3 = ring;
+	}
+
+	b43legacydbg(dev->wl, "%d-bit DMA initialized\n",
+	       (dmamask == DMA_64BIT_MASK) ? 64 :
+	       (dmamask == DMA_32BIT_MASK) ? 32 : 30);
+	err = 0;
+out:
+	return err;
+
+err_destroy_rx0:
+	b43legacy_destroy_dmaring(dma->rx_ring0);
+	dma->rx_ring0 = NULL;
+err_destroy_tx5:
+	b43legacy_destroy_dmaring(dma->tx_ring5);
+	dma->tx_ring5 = NULL;
+err_destroy_tx4:
+	b43legacy_destroy_dmaring(dma->tx_ring4);
+	dma->tx_ring4 = NULL;
+err_destroy_tx3:
+	b43legacy_destroy_dmaring(dma->tx_ring3);
+	dma->tx_ring3 = NULL;
+err_destroy_tx2:
+	b43legacy_destroy_dmaring(dma->tx_ring2);
+	dma->tx_ring2 = NULL;
+err_destroy_tx1:
+	b43legacy_destroy_dmaring(dma->tx_ring1);
+	dma->tx_ring1 = NULL;
+err_destroy_tx0:
+	b43legacy_destroy_dmaring(dma->tx_ring0);
+	dma->tx_ring0 = NULL;
+	goto out;
+}
+
+/* Generate a cookie for the TX header. */
+static u16 generate_cookie(struct b43legacy_dmaring *ring,
+			   int slot)
+{
+	u16 cookie = 0x1000;
+
+	/* Use the upper 4 bits of the cookie as
+	 * DMA controller ID and store the slot number
+	 * in the lower 12 bits.
+	 * Note that the cookie must never be 0, as this
+	 * is a special value used in RX path.
+	 */
+	switch (ring->index) {
+	case 0:
+		cookie = 0xA000;
+		break;
+	case 1:
+		cookie = 0xB000;
+		break;
+	case 2:
+		cookie = 0xC000;
+		break;
+	case 3:
+		cookie = 0xD000;
+		break;
+	case 4:
+		cookie = 0xE000;
+		break;
+	case 5:
+		cookie = 0xF000;
+		break;
+	}
+	B43legacy_WARN_ON(!(((u16)slot & 0xF000) == 0x0000));
+	cookie |= (u16)slot;
+
+	return cookie;
+}
+
+/* Inspect a cookie and find out to which controller/slot it belongs. */
+static
+struct b43legacy_dmaring *parse_cookie(struct b43legacy_wldev *dev,
+				      u16 cookie, int *slot)
+{
+	struct b43legacy_dma *dma = &dev->dma;
+	struct b43legacy_dmaring *ring = NULL;
+
+	switch (cookie & 0xF000) {
+	case 0xA000:
+		ring = dma->tx_ring0;
+		break;
+	case 0xB000:
+		ring = dma->tx_ring1;
+		break;
+	case 0xC000:
+		ring = dma->tx_ring2;
+		break;
+	case 0xD000:
+		ring = dma->tx_ring3;
+		break;
+	case 0xE000:
+		ring = dma->tx_ring4;
+		break;
+	case 0xF000:
+		ring = dma->tx_ring5;
+		break;
+	default:
+		B43legacy_WARN_ON(1);
+	}
+	*slot = (cookie & 0x0FFF);
+	B43legacy_WARN_ON(!(ring && *slot >= 0 && *slot < ring->nr_slots));
+
+	return ring;
+}
+
+static int dma_tx_fragment(struct b43legacy_dmaring *ring,
+			    struct sk_buff *skb,
+			    struct ieee80211_tx_control *ctl)
+{
+	const struct b43legacy_dma_ops *ops = ring->ops;
+	u8 *header;
+	int slot;
+	int err;
+	struct b43legacy_dmadesc_generic *desc;
+	struct b43legacy_dmadesc_meta *meta;
+	struct b43legacy_dmadesc_meta *meta_hdr;
+	struct sk_buff *bounce_skb;
+
+#define SLOTS_PER_PACKET  2
+	B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
+
+	/* Get a slot for the header. */
+	slot = request_slot(ring);
+	desc = ops->idx2desc(ring, slot, &meta_hdr);
+	memset(meta_hdr, 0, sizeof(*meta_hdr));
+
+	header = &(ring->txhdr_cache[slot * sizeof(
+			       struct b43legacy_txhdr_fw3)]);
+	b43legacy_generate_txhdr(ring->dev, header,
+				 skb->data, skb->len, ctl,
+				 generate_cookie(ring, slot));
+
+	meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header,
+				       sizeof(struct b43legacy_txhdr_fw3), 1);
+	if (dma_mapping_error(meta_hdr->dmaaddr))
+		return -EIO;
+	ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr,
+			     sizeof(struct b43legacy_txhdr_fw3), 1, 0, 0);
+
+	/* Get a slot for the payload. */
+	slot = request_slot(ring);
+	desc = ops->idx2desc(ring, slot, &meta);
+	memset(meta, 0, sizeof(*meta));
+
+	memcpy(&meta->txstat.control, ctl, sizeof(*ctl));
+	meta->skb = skb;
+	meta->is_last_fragment = 1;
+
+	meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+	/* create a bounce buffer in zone_dma on mapping failure. */
+	if (dma_mapping_error(meta->dmaaddr)) {
+		bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
+		if (!bounce_skb) {
+			err = -ENOMEM;
+			goto out_unmap_hdr;
+		}
+
+		memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
+		dev_kfree_skb_any(skb);
+		skb = bounce_skb;
+		meta->skb = skb;
+		meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+		if (dma_mapping_error(meta->dmaaddr)) {
+			err = -EIO;
+			goto out_free_bounce;
+		}
+	}
+
+	ops->fill_descriptor(ring, desc, meta->dmaaddr,
+			     skb->len, 0, 1, 1);
+
+	wmb();	/* previous stuff MUST be done */
+	/* Now transfer the whole frame. */
+	ops->poke_tx(ring, next_slot(ring, slot));
+	return 0;
+
+out_free_bounce:
+	dev_kfree_skb_any(skb);
+out_unmap_hdr:
+	unmap_descbuffer(ring, meta_hdr->dmaaddr,
+			 sizeof(struct b43legacy_txhdr_fw3), 1);
+	return err;
+}
+
+static inline
+int should_inject_overflow(struct b43legacy_dmaring *ring)
+{
+#ifdef CONFIG_B43LEGACY_DEBUG
+	if (unlikely(b43legacy_debug(ring->dev,
+				     B43legacy_DBG_DMAOVERFLOW))) {
+		/* Check if we should inject another ringbuffer overflow
+		 * to test handling of this situation in the stack. */
+		unsigned long next_overflow;
+
+		next_overflow = ring->last_injected_overflow + HZ;
+		if (time_after(jiffies, next_overflow)) {
+			ring->last_injected_overflow = jiffies;
+			b43legacydbg(ring->dev->wl,
+			       "Injecting TX ring overflow on "
+			       "DMA controller %d\n", ring->index);
+			return 1;
+		}
+	}
+#endif /* CONFIG_B43LEGACY_DEBUG */
+	return 0;
+}
+
+int b43legacy_dma_tx(struct b43legacy_wldev *dev,
+		     struct sk_buff *skb,
+		     struct ieee80211_tx_control *ctl)
+{
+	struct b43legacy_dmaring *ring;
+	int err = 0;
+	unsigned long flags;
+
+	ring = priority_to_txring(dev, ctl->queue);
+	spin_lock_irqsave(&ring->lock, flags);
+	B43legacy_WARN_ON(!ring->tx);
+	if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
+		b43legacywarn(dev->wl, "DMA queue overflow\n");
+		err = -ENOSPC;
+		goto out_unlock;
+	}
+	/* Check if the queue was stopped in mac80211,
+	 * but we got called nevertheless.
+	 * That would be a mac80211 bug. */
+	B43legacy_BUG_ON(ring->stopped);
+
+	err = dma_tx_fragment(ring, skb, ctl);
+	if (unlikely(err)) {
+		b43legacyerr(dev->wl, "DMA tx mapping failure\n");
+		goto out_unlock;
+	}
+	ring->nr_tx_packets++;
+	if ((free_slots(ring) < SLOTS_PER_PACKET) ||
+	    should_inject_overflow(ring)) {
+		/* This TX ring is full. */
+		ieee80211_stop_queue(dev->wl->hw, txring_to_priority(ring));
+		ring->stopped = 1;
+		if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
+			b43legacydbg(dev->wl, "Stopped TX ring %d\n",
+			       ring->index);
+	}
+out_unlock:
+	spin_unlock_irqrestore(&ring->lock, flags);
+
+	return err;
+}
+
+void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
+				 const struct b43legacy_txstatus *status)
+{
+	const struct b43legacy_dma_ops *ops;
+	struct b43legacy_dmaring *ring;
+	struct b43legacy_dmadesc_generic *desc;
+	struct b43legacy_dmadesc_meta *meta;
+	int slot;
+
+	ring = parse_cookie(dev, status->cookie, &slot);
+	if (unlikely(!ring))
+		return;
+	B43legacy_WARN_ON(!irqs_disabled());
+	spin_lock(&ring->lock);
+
+	B43legacy_WARN_ON(!ring->tx);
+	ops = ring->ops;
+	while (1) {
+		B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
+		desc = ops->idx2desc(ring, slot, &meta);
+
+		if (meta->skb)
+			unmap_descbuffer(ring, meta->dmaaddr,
+					 meta->skb->len, 1);
+		else
+			unmap_descbuffer(ring, meta->dmaaddr,
+					 sizeof(struct b43legacy_txhdr_fw3),
+					 1);
+
+		if (meta->is_last_fragment) {
+			B43legacy_WARN_ON(!meta->skb);
+			/* Call back to inform the ieee80211 subsystem about the
+			 * status of the transmission.
+			 * Some fields of txstat are already filled in dma_tx().
+			 */
+			if (status->acked) {
+				meta->txstat.flags |= IEEE80211_TX_STATUS_ACK;
+			} else {
+				if (!(meta->txstat.control.flags
+				      & IEEE80211_TXCTL_NO_ACK))
+					 meta->txstat.excessive_retries = 1;
+			}
+			if (status->frame_count == 0) {
+				/* The frame was not transmitted at all. */
+				meta->txstat.retry_count = 0;
+			} else
+				meta->txstat.retry_count = status->frame_count
+							   - 1;
+			ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb,
+						    &(meta->txstat));
+			/* skb is freed by ieee80211_tx_status_irqsafe() */
+			meta->skb = NULL;
+		} else {
+			/* No need to call free_descriptor_buffer here, as
+			 * this is only the txhdr, which is not allocated.
+			 */
+			B43legacy_WARN_ON(meta->skb != NULL);
+		}
+
+		/* Everything unmapped and free'd. So it's not used anymore. */
+		ring->used_slots--;
+
+		if (meta->is_last_fragment)
+			break;
+		slot = next_slot(ring, slot);
+	}
+	dev->stats.last_tx = jiffies;
+	if (ring->stopped) {
+		B43legacy_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET);
+		ieee80211_wake_queue(dev->wl->hw, txring_to_priority(ring));
+		ring->stopped = 0;
+		if (b43legacy_debug(dev, B43legacy_DBG_DMAVERBOSE))
+			b43legacydbg(dev->wl, "Woke up TX ring %d\n",
+			       ring->index);
+	}
+
+	spin_unlock(&ring->lock);
+}
+
+void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
+			      struct ieee80211_tx_queue_stats *stats)
+{
+	const int nr_queues = dev->wl->hw->queues;
+	struct b43legacy_dmaring *ring;
+	struct ieee80211_tx_queue_stats_data *data;
+	unsigned long flags;
+	int i;
+
+	for (i = 0; i < nr_queues; i++) {
+		data = &(stats->data[i]);
+		ring = priority_to_txring(dev, i);
+
+		spin_lock_irqsave(&ring->lock, flags);
+		data->len = ring->used_slots / SLOTS_PER_PACKET;
+		data->limit = ring->nr_slots / SLOTS_PER_PACKET;
+		data->count = ring->nr_tx_packets;
+		spin_unlock_irqrestore(&ring->lock, flags);
+	}
+}
+
+static void dma_rx(struct b43legacy_dmaring *ring,
+		   int *slot)
+{
+	const struct b43legacy_dma_ops *ops = ring->ops;
+	struct b43legacy_dmadesc_generic *desc;
+	struct b43legacy_dmadesc_meta *meta;
+	struct b43legacy_rxhdr_fw3 *rxhdr;
+	struct sk_buff *skb;
+	u16 len;
+	int err;
+	dma_addr_t dmaaddr;
+
+	desc = ops->idx2desc(ring, *slot, &meta);
+
+	sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
+	skb = meta->skb;
+
+	if (ring->index == 3) {
+		/* We received an xmit status. */
+		struct b43legacy_hwtxstatus *hw =
+				(struct b43legacy_hwtxstatus *)skb->data;
+		int i = 0;
+
+		while (hw->cookie == 0) {
+			if (i > 100)
+				break;
+			i++;
+			udelay(2);
+			barrier();
+		}
+		b43legacy_handle_hwtxstatus(ring->dev, hw);
+		/* recycle the descriptor buffer. */
+		sync_descbuffer_for_device(ring, meta->dmaaddr,
+					   ring->rx_buffersize);
+
+		return;
+	}
+	rxhdr = (struct b43legacy_rxhdr_fw3 *)skb->data;
+	len = le16_to_cpu(rxhdr->frame_len);
+	if (len == 0) {
+		int i = 0;
+
+		do {
+			udelay(2);
+			barrier();
+			len = le16_to_cpu(rxhdr->frame_len);
+		} while (len == 0 && i++ < 5);
+		if (unlikely(len == 0)) {
+			/* recycle the descriptor buffer. */
+			sync_descbuffer_for_device(ring, meta->dmaaddr,
+						   ring->rx_buffersize);
+			goto drop;
+		}
+	}
+	if (unlikely(len > ring->rx_buffersize)) {
+		/* The data did not fit into one descriptor buffer
+		 * and is split over multiple buffers.
+		 * This should never happen, as we try to allocate buffers
+		 * big enough. So simply ignore this packet.
+		 */
+		int cnt = 0;
+		s32 tmp = len;
+
+		while (1) {
+			desc = ops->idx2desc(ring, *slot, &meta);
+			/* recycle the descriptor buffer. */
+			sync_descbuffer_for_device(ring, meta->dmaaddr,
+						   ring->rx_buffersize);
+			*slot = next_slot(ring, *slot);
+			cnt++;
+			tmp -= ring->rx_buffersize;
+			if (tmp <= 0)
+				break;
+		}
+		b43legacyerr(ring->dev->wl, "DMA RX buffer too small "
+		       "(len: %u, buffer: %u, nr-dropped: %d)\n",
+		       len, ring->rx_buffersize, cnt);
+		goto drop;
+	}
+
+	dmaaddr = meta->dmaaddr;
+	err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC);
+	if (unlikely(err)) {
+		b43legacydbg(ring->dev->wl, "DMA RX: setup_rx_descbuffer()"
+			     " failed\n");
+		sync_descbuffer_for_device(ring, dmaaddr,
+					   ring->rx_buffersize);
+		goto drop;
+	}
+
+	unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
+	skb_put(skb, len + ring->frameoffset);
+	skb_pull(skb, ring->frameoffset);
+
+	b43legacy_rx(ring->dev, skb, rxhdr);
+drop:
+	return;
+}
+
+void b43legacy_dma_rx(struct b43legacy_dmaring *ring)
+{
+	const struct b43legacy_dma_ops *ops = ring->ops;
+	int slot;
+	int current_slot;
+	int used_slots = 0;
+
+	B43legacy_WARN_ON(ring->tx);
+	current_slot = ops->get_current_rxslot(ring);
+	B43legacy_WARN_ON(!(current_slot >= 0 && current_slot <
+			   ring->nr_slots));
+
+	slot = ring->current_slot;
+	for (; slot != current_slot; slot = next_slot(ring, slot)) {
+		dma_rx(ring, &slot);
+		update_max_used_slots(ring, ++used_slots);
+	}
+	ops->set_current_rxslot(ring, slot);
+	ring->current_slot = slot;
+}
+
+static void b43legacy_dma_tx_suspend_ring(struct b43legacy_dmaring *ring)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ring->lock, flags);
+	B43legacy_WARN_ON(!ring->tx);
+	ring->ops->tx_suspend(ring);
+	spin_unlock_irqrestore(&ring->lock, flags);
+}
+
+static void b43legacy_dma_tx_resume_ring(struct b43legacy_dmaring *ring)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ring->lock, flags);
+	B43legacy_WARN_ON(!ring->tx);
+	ring->ops->tx_resume(ring);
+	spin_unlock_irqrestore(&ring->lock, flags);
+}
+
+void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev)
+{
+	b43legacy_power_saving_ctl_bits(dev, -1, 1);
+	b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring0);
+	b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring1);
+	b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring2);
+	b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring3);
+	b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring4);
+	b43legacy_dma_tx_suspend_ring(dev->dma.tx_ring5);
+}
+
+void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev)
+{
+	b43legacy_dma_tx_resume_ring(dev->dma.tx_ring5);
+	b43legacy_dma_tx_resume_ring(dev->dma.tx_ring4);
+	b43legacy_dma_tx_resume_ring(dev->dma.tx_ring3);
+	b43legacy_dma_tx_resume_ring(dev->dma.tx_ring2);
+	b43legacy_dma_tx_resume_ring(dev->dma.tx_ring1);
+	b43legacy_dma_tx_resume_ring(dev->dma.tx_ring0);
+	b43legacy_power_saving_ctl_bits(dev, -1, -1);
+}
diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h
new file mode 100644
index 0000000..26f6ab0
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/dma.h
@@ -0,0 +1,367 @@
+#ifndef B43legacy_DMA_H_
+#define B43legacy_DMA_H_
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/linkage.h>
+#include <asm/atomic.h>
+
+#include "b43legacy.h"
+
+
+/* DMA-Interrupt reasons. */
+#define B43legacy_DMAIRQ_FATALMASK	((1 << 10) | (1 << 11) | (1 << 12) \
+					 | (1 << 14) | (1 << 15))
+#define B43legacy_DMAIRQ_NONFATALMASK	(1 << 13)
+#define B43legacy_DMAIRQ_RX_DONE		(1 << 16)
+
+
+/*** 32-bit DMA Engine. ***/
+
+/* 32-bit DMA controller registers. */
+#define B43legacy_DMA32_TXCTL				0x00
+#define		B43legacy_DMA32_TXENABLE		0x00000001
+#define		B43legacy_DMA32_TXSUSPEND		0x00000002
+#define		B43legacy_DMA32_TXLOOPBACK		0x00000004
+#define		B43legacy_DMA32_TXFLUSH			0x00000010
+#define		B43legacy_DMA32_TXADDREXT_MASK		0x00030000
+#define		B43legacy_DMA32_TXADDREXT_SHIFT		16
+#define B43legacy_DMA32_TXRING				0x04
+#define B43legacy_DMA32_TXINDEX				0x08
+#define B43legacy_DMA32_TXSTATUS			0x0C
+#define		B43legacy_DMA32_TXDPTR			0x00000FFF
+#define		B43legacy_DMA32_TXSTATE			0x0000F000
+#define			B43legacy_DMA32_TXSTAT_DISABLED	0x00000000
+#define			B43legacy_DMA32_TXSTAT_ACTIVE	0x00001000
+#define			B43legacy_DMA32_TXSTAT_IDLEWAIT	0x00002000
+#define			B43legacy_DMA32_TXSTAT_STOPPED	0x00003000
+#define			B43legacy_DMA32_TXSTAT_SUSP	0x00004000
+#define		B43legacy_DMA32_TXERROR			0x000F0000
+#define			B43legacy_DMA32_TXERR_NOERR	0x00000000
+#define			B43legacy_DMA32_TXERR_PROT	0x00010000
+#define			B43legacy_DMA32_TXERR_UNDERRUN	0x00020000
+#define			B43legacy_DMA32_TXERR_BUFREAD	0x00030000
+#define			B43legacy_DMA32_TXERR_DESCREAD	0x00040000
+#define		B43legacy_DMA32_TXACTIVE		0xFFF00000
+#define B43legacy_DMA32_RXCTL				0x10
+#define		B43legacy_DMA32_RXENABLE		0x00000001
+#define		B43legacy_DMA32_RXFROFF_MASK		0x000000FE
+#define		B43legacy_DMA32_RXFROFF_SHIFT		1
+#define		B43legacy_DMA32_RXDIRECTFIFO		0x00000100
+#define		B43legacy_DMA32_RXADDREXT_MASK		0x00030000
+#define		B43legacy_DMA32_RXADDREXT_SHIFT		16
+#define B43legacy_DMA32_RXRING				0x14
+#define B43legacy_DMA32_RXINDEX				0x18
+#define B43legacy_DMA32_RXSTATUS			0x1C
+#define		B43legacy_DMA32_RXDPTR			0x00000FFF
+#define		B43legacy_DMA32_RXSTATE			0x0000F000
+#define			B43legacy_DMA32_RXSTAT_DISABLED	0x00000000
+#define			B43legacy_DMA32_RXSTAT_ACTIVE	0x00001000
+#define			B43legacy_DMA32_RXSTAT_IDLEWAIT	0x00002000
+#define			B43legacy_DMA32_RXSTAT_STOPPED	0x00003000
+#define		B43legacy_DMA32_RXERROR			0x000F0000
+#define			B43legacy_DMA32_RXERR_NOERR	0x00000000
+#define			B43legacy_DMA32_RXERR_PROT	0x00010000
+#define			B43legacy_DMA32_RXERR_OVERFLOW	0x00020000
+#define			B43legacy_DMA32_RXERR_BUFWRITE	0x00030000
+#define			B43legacy_DMA32_RXERR_DESCREAD	0x00040000
+#define		B43legacy_DMA32_RXACTIVE		0xFFF00000
+
+/* 32-bit DMA descriptor. */
+struct b43legacy_dmadesc32 {
+	__le32 control;
+	__le32 address;
+} __attribute__((__packed__));
+#define B43legacy_DMA32_DCTL_BYTECNT		0x00001FFF
+#define B43legacy_DMA32_DCTL_ADDREXT_MASK	0x00030000
+#define B43legacy_DMA32_DCTL_ADDREXT_SHIFT	16
+#define B43legacy_DMA32_DCTL_DTABLEEND		0x10000000
+#define B43legacy_DMA32_DCTL_IRQ		0x20000000
+#define B43legacy_DMA32_DCTL_FRAMEEND		0x40000000
+#define B43legacy_DMA32_DCTL_FRAMESTART		0x80000000
+
+
+
+/*** 64-bit DMA Engine. ***/
+
+/* 64-bit DMA controller registers. */
+#define B43legacy_DMA64_TXCTL				0x00
+#define		B43legacy_DMA64_TXENABLE		0x00000001
+#define		B43legacy_DMA64_TXSUSPEND		0x00000002
+#define		B43legacy_DMA64_TXLOOPBACK		0x00000004
+#define		B43legacy_DMA64_TXFLUSH			0x00000010
+#define		B43legacy_DMA64_TXADDREXT_MASK		0x00030000
+#define		B43legacy_DMA64_TXADDREXT_SHIFT		16
+#define B43legacy_DMA64_TXINDEX				0x04
+#define B43legacy_DMA64_TXRINGLO			0x08
+#define B43legacy_DMA64_TXRINGHI			0x0C
+#define B43legacy_DMA64_TXSTATUS			0x10
+#define		B43legacy_DMA64_TXSTATDPTR		0x00001FFF
+#define		B43legacy_DMA64_TXSTAT			0xF0000000
+#define			B43legacy_DMA64_TXSTAT_DISABLED	0x00000000
+#define			B43legacy_DMA64_TXSTAT_ACTIVE	0x10000000
+#define			B43legacy_DMA64_TXSTAT_IDLEWAIT	0x20000000
+#define			B43legacy_DMA64_TXSTAT_STOPPED	0x30000000
+#define			B43legacy_DMA64_TXSTAT_SUSP	0x40000000
+#define B43legacy_DMA64_TXERROR				0x14
+#define		B43legacy_DMA64_TXERRDPTR		0x0001FFFF
+#define		B43legacy_DMA64_TXERR			0xF0000000
+#define			B43legacy_DMA64_TXERR_NOERR	0x00000000
+#define			B43legacy_DMA64_TXERR_PROT	0x10000000
+#define			B43legacy_DMA64_TXERR_UNDERRUN	0x20000000
+#define			B43legacy_DMA64_TXERR_TRANSFER	0x30000000
+#define			B43legacy_DMA64_TXERR_DESCREAD	0x40000000
+#define			B43legacy_DMA64_TXERR_CORE	0x50000000
+#define B43legacy_DMA64_RXCTL				0x20
+#define		B43legacy_DMA64_RXENABLE		0x00000001
+#define		B43legacy_DMA64_RXFROFF_MASK		0x000000FE
+#define		B43legacy_DMA64_RXFROFF_SHIFT		1
+#define		B43legacy_DMA64_RXDIRECTFIFO		0x00000100
+#define		B43legacy_DMA64_RXADDREXT_MASK		0x00030000
+#define		B43legacy_DMA64_RXADDREXT_SHIFT		16
+#define B43legacy_DMA64_RXINDEX				0x24
+#define B43legacy_DMA64_RXRINGLO			0x28
+#define B43legacy_DMA64_RXRINGHI			0x2C
+#define B43legacy_DMA64_RXSTATUS			0x30
+#define		B43legacy_DMA64_RXSTATDPTR		0x00001FFF
+#define		B43legacy_DMA64_RXSTAT			0xF0000000
+#define			B43legacy_DMA64_RXSTAT_DISABLED	0x00000000
+#define			B43legacy_DMA64_RXSTAT_ACTIVE	0x10000000
+#define			B43legacy_DMA64_RXSTAT_IDLEWAIT	0x20000000
+#define			B43legacy_DMA64_RXSTAT_STOPPED	0x30000000
+#define			B43legacy_DMA64_RXSTAT_SUSP	0x40000000
+#define B43legacy_DMA64_RXERROR				0x34
+#define		B43legacy_DMA64_RXERRDPTR		0x0001FFFF
+#define		B43legacy_DMA64_RXERR			0xF0000000
+#define			B43legacy_DMA64_RXERR_NOERR	0x00000000
+#define			B43legacy_DMA64_RXERR_PROT	0x10000000
+#define			B43legacy_DMA64_RXERR_UNDERRUN	0x20000000
+#define			B43legacy_DMA64_RXERR_TRANSFER	0x30000000
+#define			B43legacy_DMA64_RXERR_DESCREAD	0x40000000
+#define			B43legacy_DMA64_RXERR_CORE	0x50000000
+
+/* 64-bit DMA descriptor. */
+struct b43legacy_dmadesc64 {
+	__le32 control0;
+	__le32 control1;
+	__le32 address_low;
+	__le32 address_high;
+} __attribute__((__packed__));
+#define B43legacy_DMA64_DCTL0_DTABLEEND		0x10000000
+#define B43legacy_DMA64_DCTL0_IRQ		0x20000000
+#define B43legacy_DMA64_DCTL0_FRAMEEND		0x40000000
+#define B43legacy_DMA64_DCTL0_FRAMESTART	0x80000000
+#define B43legacy_DMA64_DCTL1_BYTECNT		0x00001FFF
+#define B43legacy_DMA64_DCTL1_ADDREXT_MASK	0x00030000
+#define B43legacy_DMA64_DCTL1_ADDREXT_SHIFT	16
+
+
+
+struct b43legacy_dmadesc_generic {
+	union {
+		struct b43legacy_dmadesc32 dma32;
+		struct b43legacy_dmadesc64 dma64;
+	} __attribute__((__packed__));
+} __attribute__((__packed__));
+
+
+/* Misc DMA constants */
+#define B43legacy_DMA_RINGMEMSIZE	PAGE_SIZE
+#define B43legacy_DMA0_RX_FRAMEOFFSET	30
+#define B43legacy_DMA3_RX_FRAMEOFFSET	0
+
+
+/* DMA engine tuning knobs */
+#define B43legacy_TXRING_SLOTS		128
+#define B43legacy_RXRING_SLOTS		64
+#define B43legacy_DMA0_RX_BUFFERSIZE	(2304 + 100)
+#define B43legacy_DMA3_RX_BUFFERSIZE	16
+
+
+
+#ifdef CONFIG_B43LEGACY_DMA
+
+
+struct sk_buff;
+struct b43legacy_private;
+struct b43legacy_txstatus;
+
+
+struct b43legacy_dmadesc_meta {
+	/* The kernel DMA-able buffer. */
+	struct sk_buff *skb;
+	/* DMA base bus-address of the descriptor buffer. */
+	dma_addr_t dmaaddr;
+	/* ieee80211 TX status. Only used once per 802.11 frag. */
+	bool is_last_fragment;
+	struct ieee80211_tx_status txstat;
+};
+
+struct b43legacy_dmaring;
+
+/* Lowlevel DMA operations that differ between 32bit and 64bit DMA. */
+struct b43legacy_dma_ops {
+	struct b43legacy_dmadesc_generic * (*idx2desc)
+					   (struct b43legacy_dmaring *ring,
+					   int slot,
+					   struct b43legacy_dmadesc_meta
+					   **meta);
+	void (*fill_descriptor)(struct b43legacy_dmaring *ring,
+				struct b43legacy_dmadesc_generic *desc,
+				dma_addr_t dmaaddr, u16 bufsize,
+				int start, int end, int irq);
+	void (*poke_tx)(struct b43legacy_dmaring *ring, int slot);
+	void (*tx_suspend)(struct b43legacy_dmaring *ring);
+	void (*tx_resume)(struct b43legacy_dmaring *ring);
+	int (*get_current_rxslot)(struct b43legacy_dmaring *ring);
+	void (*set_current_rxslot)(struct b43legacy_dmaring *ring, int slot);
+};
+
+struct b43legacy_dmaring {
+	/* Lowlevel DMA ops. */
+	const struct b43legacy_dma_ops *ops;
+	/* Kernel virtual base address of the ring memory. */
+	void *descbase;
+	/* Meta data about all descriptors. */
+	struct b43legacy_dmadesc_meta *meta;
+	/* Cache of TX headers for each slot.
+	 * This is to avoid an allocation on each TX.
+	 * This is NULL for an RX ring.
+	 */
+	u8 *txhdr_cache;
+	/* (Unadjusted) DMA base bus-address of the ring memory. */
+	dma_addr_t dmabase;
+	/* Number of descriptor slots in the ring. */
+	int nr_slots;
+	/* Number of used descriptor slots. */
+	int used_slots;
+	/* Currently used slot in the ring. */
+	int current_slot;
+	/* Total number of packets sent. Statistics only. */
+	unsigned int nr_tx_packets;
+	/* Frameoffset in octets. */
+	u32 frameoffset;
+	/* Descriptor buffer size. */
+	u16 rx_buffersize;
+	/* The MMIO base register of the DMA controller. */
+	u16 mmio_base;
+	/* DMA controller index number (0-5). */
+	int index;
+	/* Boolean. Is this a TX ring? */
+	bool tx;
+	/* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
+	bool dma64;
+	/* Boolean. Is this ring stopped at ieee80211 level? */
+	bool stopped;
+	/* Lock, only used for TX. */
+	spinlock_t lock;
+	struct b43legacy_wldev *dev;
+#ifdef CONFIG_B43LEGACY_DEBUG
+	/* Maximum number of used slots. */
+	int max_used_slots;
+	/* Last time we injected a ring overflow. */
+	unsigned long last_injected_overflow;
+#endif /* CONFIG_B43LEGACY_DEBUG*/
+};
+
+
+static inline
+u32 b43legacy_dma_read(struct b43legacy_dmaring *ring,
+		       u16 offset)
+{
+	return b43legacy_read32(ring->dev, ring->mmio_base + offset);
+}
+
+static inline
+void b43legacy_dma_write(struct b43legacy_dmaring *ring,
+			 u16 offset, u32 value)
+{
+	b43legacy_write32(ring->dev, ring->mmio_base + offset, value);
+}
+
+
+int b43legacy_dma_init(struct b43legacy_wldev *dev);
+void b43legacy_dma_free(struct b43legacy_wldev *dev);
+
+int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
+				     u16 dmacontroller_mmio_base,
+				     int dma64);
+int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
+				     u16 dmacontroller_mmio_base,
+				     int dma64);
+
+u16 b43legacy_dmacontroller_base(int dma64bit, int dmacontroller_idx);
+
+void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev);
+void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev);
+
+void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
+				struct ieee80211_tx_queue_stats *stats);
+
+int b43legacy_dma_tx(struct b43legacy_wldev *dev,
+		     struct sk_buff *skb,
+		     struct ieee80211_tx_control *ctl);
+void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
+				   const struct b43legacy_txstatus *status);
+
+void b43legacy_dma_rx(struct b43legacy_dmaring *ring);
+
+#else /* CONFIG_B43LEGACY_DMA */
+
+
+static inline
+int b43legacy_dma_init(struct b43legacy_wldev *dev)
+{
+	return 0;
+}
+static inline
+void b43legacy_dma_free(struct b43legacy_wldev *dev)
+{
+}
+static inline
+int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev,
+				     u16 dmacontroller_mmio_base,
+				     int dma64)
+{
+	return 0;
+}
+static inline
+int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev,
+				     u16 dmacontroller_mmio_base,
+				     int dma64)
+{
+	return 0;
+}
+static inline
+void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev,
+				struct ieee80211_tx_queue_stats *stats)
+{
+}
+static inline
+int b43legacy_dma_tx(struct b43legacy_wldev *dev,
+		     struct sk_buff *skb,
+		     struct ieee80211_tx_control *ctl)
+{
+	return 0;
+}
+static inline
+void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
+				   const struct b43legacy_txstatus *status)
+{
+}
+static inline
+void b43legacy_dma_rx(struct b43legacy_dmaring *ring)
+{
+}
+static inline
+void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev)
+{
+}
+static inline
+void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev)
+{
+}
+
+#endif /* CONFIG_B43LEGACY_DMA */
+#endif /* B43legacy_DMA_H_ */
diff --git a/drivers/net/wireless/b43legacy/ilt.c b/drivers/net/wireless/b43legacy/ilt.c
new file mode 100644
index 0000000..247fc78
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/ilt.c
@@ -0,0 +1,336 @@
+/*
+
+  Broadcom B43legacy wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+		     Stefano Brivio <st3@riseup.net>
+		     Michael Buesch <mbuesch@freenet.de>
+		     Danny van Dyk <kugelfang@gentoo.org>
+		     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43legacy.h"
+#include "ilt.h"
+#include "phy.h"
+
+
+/**** Initial Internal Lookup Tables ****/
+
+const u32 b43legacy_ilt_rotor[B43legacy_ILT_ROTOR_SIZE] = {
+	0xFEB93FFD, 0xFEC63FFD, /* 0 */
+	0xFED23FFD, 0xFEDF3FFD,
+	0xFEEC3FFE, 0xFEF83FFE,
+	0xFF053FFE, 0xFF113FFE,
+	0xFF1E3FFE, 0xFF2A3FFF, /* 8 */
+	0xFF373FFF, 0xFF443FFF,
+	0xFF503FFF, 0xFF5D3FFF,
+	0xFF693FFF, 0xFF763FFF,
+	0xFF824000, 0xFF8F4000, /* 16 */
+	0xFF9B4000, 0xFFA84000,
+	0xFFB54000, 0xFFC14000,
+	0xFFCE4000, 0xFFDA4000,
+	0xFFE74000, 0xFFF34000, /* 24 */
+	0x00004000, 0x000D4000,
+	0x00194000, 0x00264000,
+	0x00324000, 0x003F4000,
+	0x004B4000, 0x00584000, /* 32 */
+	0x00654000, 0x00714000,
+	0x007E4000, 0x008A3FFF,
+	0x00973FFF, 0x00A33FFF,
+	0x00B03FFF, 0x00BC3FFF, /* 40 */
+	0x00C93FFF, 0x00D63FFF,
+	0x00E23FFE, 0x00EF3FFE,
+	0x00FB3FFE, 0x01083FFE,
+	0x01143FFE, 0x01213FFD, /* 48 */
+	0x012E3FFD, 0x013A3FFD,
+	0x01473FFD,
+};
+
+const u32 b43legacy_ilt_retard[B43legacy_ILT_RETARD_SIZE] = {
+	0xDB93CB87, 0xD666CF64, /* 0 */
+	0xD1FDD358, 0xCDA6D826,
+	0xCA38DD9F, 0xC729E2B4,
+	0xC469E88E, 0xC26AEE2B,
+	0xC0DEF46C, 0xC073FA62, /* 8 */
+	0xC01D00D5, 0xC0760743,
+	0xC1560D1E, 0xC2E51369,
+	0xC4ED18FF, 0xC7AC1ED7,
+	0xCB2823B2, 0xCEFA28D9, /* 16 */
+	0xD2F62D3F, 0xD7BB3197,
+	0xDCE53568, 0xE1FE3875,
+	0xE7D13B35, 0xED663D35,
+	0xF39B3EC4, 0xF98E3FA7, /* 24 */
+	0x00004000, 0x06723FA7,
+	0x0C653EC4, 0x129A3D35,
+	0x182F3B35, 0x1E023875,
+	0x231B3568, 0x28453197, /* 32 */
+	0x2D0A2D3F, 0x310628D9,
+	0x34D823B2, 0x38541ED7,
+	0x3B1318FF, 0x3D1B1369,
+	0x3EAA0D1E, 0x3F8A0743, /* 40 */
+	0x3FE300D5, 0x3F8DFA62,
+	0x3F22F46C, 0x3D96EE2B,
+	0x3B97E88E, 0x38D7E2B4,
+	0x35C8DD9F, 0x325AD826, /* 48 */
+	0x2E03D358, 0x299ACF64,
+	0x246DCB87,
+};
+
+const u16 b43legacy_ilt_finefreqa[B43legacy_ILT_FINEFREQA_SIZE] = {
+	0x0082, 0x0082, 0x0102, 0x0182, /* 0 */
+	0x0202, 0x0282, 0x0302, 0x0382,
+	0x0402, 0x0482, 0x0502, 0x0582,
+	0x05E2, 0x0662, 0x06E2, 0x0762,
+	0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */
+	0x09C2, 0x0A22, 0x0AA2, 0x0B02,
+	0x0B82, 0x0BE2, 0x0C62, 0x0CC2,
+	0x0D42, 0x0DA2, 0x0E02, 0x0E62,
+	0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */
+	0x1062, 0x10C2, 0x1122, 0x1182,
+	0x11E2, 0x1242, 0x12A2, 0x12E2,
+	0x1342, 0x13A2, 0x1402, 0x1442,
+	0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */
+	0x15E2, 0x1622, 0x1662, 0x16C1,
+	0x1701, 0x1741, 0x1781, 0x17E1,
+	0x1821, 0x1861, 0x18A1, 0x18E1,
+	0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */
+	0x1A21, 0x1A61, 0x1AA1, 0x1AC1,
+	0x1B01, 0x1B41, 0x1B81, 0x1BA1,
+	0x1BE1, 0x1C21, 0x1C41, 0x1C81,
+	0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */
+	0x1D61, 0x1DA1, 0x1DC1, 0x1E01,
+	0x1E21, 0x1E61, 0x1E81, 0x1EA1,
+	0x1EE1, 0x1F01, 0x1F21, 0x1F41,
+	0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */
+	0x2001, 0x2041, 0x2061, 0x2081,
+	0x20A1, 0x20C1, 0x20E1, 0x2101,
+	0x2121, 0x2141, 0x2161, 0x2181,
+	0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */
+	0x2221, 0x2241, 0x2261, 0x2281,
+	0x22A1, 0x22C1, 0x22C1, 0x22E1,
+	0x2301, 0x2321, 0x2341, 0x2361,
+	0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */
+	0x23E1, 0x23E1, 0x2401, 0x2421,
+	0x2441, 0x2441, 0x2461, 0x2481,
+	0x2481, 0x24A1, 0x24C1, 0x24C1,
+	0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */
+	0x2541, 0x2541, 0x2561, 0x2561,
+	0x2581, 0x25A1, 0x25A1, 0x25C1,
+	0x25C1, 0x25E1, 0x2601, 0x2601,
+	0x2621, 0x2621, 0x2641, 0x2641, /* 160 */
+	0x2661, 0x2661, 0x2681, 0x2681,
+	0x26A1, 0x26A1, 0x26C1, 0x26C1,
+	0x26E1, 0x26E1, 0x2701, 0x2701,
+	0x2721, 0x2721, 0x2740, 0x2740, /* 176 */
+	0x2760, 0x2760, 0x2780, 0x2780,
+	0x2780, 0x27A0, 0x27A0, 0x27C0,
+	0x27C0, 0x27E0, 0x27E0, 0x27E0,
+	0x2800, 0x2800, 0x2820, 0x2820, /* 192 */
+	0x2820, 0x2840, 0x2840, 0x2840,
+	0x2860, 0x2860, 0x2880, 0x2880,
+	0x2880, 0x28A0, 0x28A0, 0x28A0,
+	0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */
+	0x28E0, 0x28E0, 0x2900, 0x2900,
+	0x2900, 0x2920, 0x2920, 0x2920,
+	0x2940, 0x2940, 0x2940, 0x2960,
+	0x2960, 0x2960, 0x2960, 0x2980, /* 224 */
+	0x2980, 0x2980, 0x29A0, 0x29A0,
+	0x29A0, 0x29A0, 0x29C0, 0x29C0,
+	0x29C0, 0x29E0, 0x29E0, 0x29E0,
+	0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */
+	0x2A00, 0x2A20, 0x2A20, 0x2A20,
+	0x2A20, 0x2A40, 0x2A40, 0x2A40,
+	0x2A40, 0x2A60, 0x2A60, 0x2A60,
+};
+
+const u16 b43legacy_ilt_finefreqg[B43legacy_ILT_FINEFREQG_SIZE] = {
+	0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */
+	0x05A9, 0x0669, 0x0709, 0x0789,
+	0x0829, 0x08A9, 0x0929, 0x0989,
+	0x0A09, 0x0A69, 0x0AC9, 0x0B29,
+	0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */
+	0x0D09, 0x0D69, 0x0DA9, 0x0E09,
+	0x0E69, 0x0EA9, 0x0F09, 0x0F49,
+	0x0FA9, 0x0FE9, 0x1029, 0x1089,
+	0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */
+	0x11E9, 0x1229, 0x1289, 0x12C9,
+	0x1309, 0x1349, 0x1389, 0x13C9,
+	0x1409, 0x1449, 0x14A9, 0x14E9,
+	0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */
+	0x1629, 0x1669, 0x16A9, 0x16E8,
+	0x1728, 0x1768, 0x17A8, 0x17E8,
+	0x1828, 0x1868, 0x18A8, 0x18E8,
+	0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */
+	0x1A28, 0x1A68, 0x1AA8, 0x1AE8,
+	0x1B28, 0x1B68, 0x1BA8, 0x1BE8,
+	0x1C28, 0x1C68, 0x1CA8, 0x1CE8,
+	0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */
+	0x1E48, 0x1E88, 0x1EC8, 0x1F08,
+	0x1F48, 0x1F88, 0x1FE8, 0x2028,
+	0x2068, 0x20A8, 0x2108, 0x2148,
+	0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */
+	0x22C8, 0x2308, 0x2348, 0x23A8,
+	0x23E8, 0x2448, 0x24A8, 0x24E8,
+	0x2548, 0x25A8, 0x2608, 0x2668,
+	0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */
+	0x2847, 0x28C7, 0x2947, 0x29A7,
+	0x2A27, 0x2AC7, 0x2B47, 0x2BE7,
+	0x2CA7, 0x2D67, 0x2E47, 0x2F67,
+	0x3247, 0x3526, 0x3646, 0x3726, /* 128 */
+	0x3806, 0x38A6, 0x3946, 0x39E6,
+	0x3A66, 0x3AE6, 0x3B66, 0x3BC6,
+	0x3C45, 0x3CA5, 0x3D05, 0x3D85,
+	0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */
+	0x3F45, 0x3FA5, 0x4005, 0x4045,
+	0x40A5, 0x40E5, 0x4145, 0x4185,
+	0x41E5, 0x4225, 0x4265, 0x42C5,
+	0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */
+	0x4424, 0x4464, 0x44C4, 0x4504,
+	0x4544, 0x4584, 0x45C4, 0x4604,
+	0x4644, 0x46A4, 0x46E4, 0x4724,
+	0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */
+	0x4864, 0x48A4, 0x48E4, 0x4924,
+	0x4964, 0x49A4, 0x49E4, 0x4A24,
+	0x4A64, 0x4AA4, 0x4AE4, 0x4B23,
+	0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */
+	0x4C63, 0x4CA3, 0x4CE3, 0x4D23,
+	0x4D63, 0x4DA3, 0x4DE3, 0x4E23,
+	0x4E63, 0x4EA3, 0x4EE3, 0x4F23,
+	0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */
+	0x5083, 0x50C3, 0x5103, 0x5143,
+	0x5183, 0x51E2, 0x5222, 0x5262,
+	0x52A2, 0x52E2, 0x5342, 0x5382,
+	0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */
+	0x5502, 0x5542, 0x55A2, 0x55E2,
+	0x5642, 0x5682, 0x56E2, 0x5722,
+	0x5782, 0x57E1, 0x5841, 0x58A1,
+	0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */
+	0x5AA1, 0x5B01, 0x5B81, 0x5BE1,
+	0x5C61, 0x5D01, 0x5D80, 0x5E20,
+	0x5EE0, 0x5FA0, 0x6080, 0x61C0,
+};
+
+const u16 b43legacy_ilt_noisea2[B43legacy_ILT_NOISEA2_SIZE] = {
+	0x0001, 0x0001, 0x0001, 0xFFFE,
+	0xFFFE, 0x3FFF, 0x1000, 0x0393,
+};
+
+const u16 b43legacy_ilt_noisea3[B43legacy_ILT_NOISEA3_SIZE] = {
+	0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+	0x4C4C, 0x4C4C, 0x4C4C, 0x2D36,
+};
+
+const u16 b43legacy_ilt_noiseg1[B43legacy_ILT_NOISEG1_SIZE] = {
+	0x013C, 0x01F5, 0x031A, 0x0631,
+	0x0001, 0x0001, 0x0001, 0x0001,
+};
+
+const u16 b43legacy_ilt_noiseg2[B43legacy_ILT_NOISEG2_SIZE] = {
+	0x5484, 0x3C40, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+const u16 b43legacy_ilt_noisescaleg1[B43legacy_ILT_NOISESCALEG_SIZE] = {
+	0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */
+	0x2F2D, 0x2A2A, 0x2527, 0x1F21,
+	0x1A1D, 0x1719, 0x1616, 0x1414,
+	0x1414, 0x1400, 0x1414, 0x1614,
+	0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */
+	0x2A27, 0x2F2A, 0x332D, 0x3B35,
+	0x5140, 0x6C62, 0x0077,
+};
+
+const u16 b43legacy_ilt_noisescaleg2[B43legacy_ILT_NOISESCALEG_SIZE] = {
+	0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */
+	0xB2B0, 0xADAD, 0xA7A9, 0x9FA1,
+	0x969B, 0x9195, 0x8F8F, 0x8A8A,
+	0x8A8A, 0x8A00, 0x8A8A, 0x8F8A,
+	0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */
+	0xADA9, 0xB2AD, 0xB6B0, 0xBCB7,
+	0xCBC0, 0xD8D4, 0x00DD,
+};
+
+const u16 b43legacy_ilt_noisescaleg3[B43legacy_ILT_NOISESCALEG_SIZE] = {
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+	0xA4A4, 0xA400, 0xA4A4, 0xA4A4,
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */
+	0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4,
+	0xA4A4, 0xA4A4, 0x00A4,
+};
+
+const u16 b43legacy_ilt_sigmasqr1[B43legacy_ILT_SIGMASQR_SIZE] = {
+	0x007A, 0x0075, 0x0071, 0x006C, /* 0 */
+	0x0067, 0x0063, 0x005E, 0x0059,
+	0x0054, 0x0050, 0x004B, 0x0046,
+	0x0042, 0x003D, 0x003D, 0x003D,
+	0x003D, 0x003D, 0x003D, 0x003D, /* 16 */
+	0x003D, 0x003D, 0x003D, 0x003D,
+	0x003D, 0x003D, 0x0000, 0x003D,
+	0x003D, 0x003D, 0x003D, 0x003D,
+	0x003D, 0x003D, 0x003D, 0x003D, /* 32 */
+	0x003D, 0x003D, 0x003D, 0x003D,
+	0x0042, 0x0046, 0x004B, 0x0050,
+	0x0054, 0x0059, 0x005E, 0x0063,
+	0x0067, 0x006C, 0x0071, 0x0075, /* 48 */
+	0x007A,
+};
+
+const u16 b43legacy_ilt_sigmasqr2[B43legacy_ILT_SIGMASQR_SIZE] = {
+	0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */
+	0x00D6, 0x00D4, 0x00D2, 0x00CF,
+	0x00CD, 0x00CA, 0x00C7, 0x00C4,
+	0x00C1, 0x00BE, 0x00BE, 0x00BE,
+	0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */
+	0x00BE, 0x00BE, 0x00BE, 0x00BE,
+	0x00BE, 0x00BE, 0x0000, 0x00BE,
+	0x00BE, 0x00BE, 0x00BE, 0x00BE,
+	0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */
+	0x00BE, 0x00BE, 0x00BE, 0x00BE,
+	0x00C1, 0x00C4, 0x00C7, 0x00CA,
+	0x00CD, 0x00CF, 0x00D2, 0x00D4,
+	0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */
+	0x00DE,
+};
+
+/**** Helper functions to access the device Internal Lookup Tables ****/
+
+void b43legacy_ilt_write(struct b43legacy_wldev *dev, u16 offset, u16 val)
+{
+	b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset);
+	mmiowb();
+	b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA1, val);
+}
+
+void b43legacy_ilt_write32(struct b43legacy_wldev *dev, u16 offset, u32 val)
+{
+	b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset);
+	mmiowb();
+	b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA2,
+			    (val & 0xFFFF0000) >> 16);
+	b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_DATA1,
+			    val & 0x0000FFFF);
+}
+
+u16 b43legacy_ilt_read(struct b43legacy_wldev *dev, u16 offset)
+{
+	b43legacy_phy_write(dev, B43legacy_PHY_ILT_G_CTRL, offset);
+	return b43legacy_phy_read(dev, B43legacy_PHY_ILT_G_DATA1);
+}
diff --git a/drivers/net/wireless/b43legacy/ilt.h b/drivers/net/wireless/b43legacy/ilt.h
new file mode 100644
index 0000000..48bcf37
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/ilt.h
@@ -0,0 +1,34 @@
+#ifndef B43legacy_ILT_H_
+#define B43legacy_ILT_H_
+
+#define B43legacy_ILT_ROTOR_SIZE	53
+extern const u32 b43legacy_ilt_rotor[B43legacy_ILT_ROTOR_SIZE];
+#define B43legacy_ILT_RETARD_SIZE	53
+extern const u32 b43legacy_ilt_retard[B43legacy_ILT_RETARD_SIZE];
+#define B43legacy_ILT_FINEFREQA_SIZE	256
+extern const u16 b43legacy_ilt_finefreqa[B43legacy_ILT_FINEFREQA_SIZE];
+#define B43legacy_ILT_FINEFREQG_SIZE	256
+extern const u16 b43legacy_ilt_finefreqg[B43legacy_ILT_FINEFREQG_SIZE];
+#define B43legacy_ILT_NOISEA2_SIZE	8
+extern const u16 b43legacy_ilt_noisea2[B43legacy_ILT_NOISEA2_SIZE];
+#define B43legacy_ILT_NOISEA3_SIZE	8
+extern const u16 b43legacy_ilt_noisea3[B43legacy_ILT_NOISEA3_SIZE];
+#define B43legacy_ILT_NOISEG1_SIZE	8
+extern const u16 b43legacy_ilt_noiseg1[B43legacy_ILT_NOISEG1_SIZE];
+#define B43legacy_ILT_NOISEG2_SIZE	8
+extern const u16 b43legacy_ilt_noiseg2[B43legacy_ILT_NOISEG2_SIZE];
+#define B43legacy_ILT_NOISESCALEG_SIZE	27
+extern const u16 b43legacy_ilt_noisescaleg1[B43legacy_ILT_NOISESCALEG_SIZE];
+extern const u16 b43legacy_ilt_noisescaleg2[B43legacy_ILT_NOISESCALEG_SIZE];
+extern const u16 b43legacy_ilt_noisescaleg3[B43legacy_ILT_NOISESCALEG_SIZE];
+#define B43legacy_ILT_SIGMASQR_SIZE	53
+extern const u16 b43legacy_ilt_sigmasqr1[B43legacy_ILT_SIGMASQR_SIZE];
+extern const u16 b43legacy_ilt_sigmasqr2[B43legacy_ILT_SIGMASQR_SIZE];
+
+
+void b43legacy_ilt_write(struct b43legacy_wldev *dev, u16 offset, u16 val);
+void b43legacy_ilt_write32(struct b43legacy_wldev *dev, u16 offset,
+			   u32 val);
+u16 b43legacy_ilt_read(struct b43legacy_wldev *dev, u16 offset);
+
+#endif /* B43legacy_ILT_H_ */
diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c
new file mode 100644
index 0000000..a584ea8
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/leds.c
@@ -0,0 +1,298 @@
+/*
+
+  Broadcom B43legacy wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+		     Stefano Brivio <st3@riseup.net>
+		     Michael Buesch <mb@bu3sch.de>
+		     Danny van Dyk <kugelfang@gentoo.org>
+		     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+  Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "leds.h"
+#include "b43legacy.h"
+#include "main.h"
+
+static void b43legacy_led_changestate(struct b43legacy_led *led)
+{
+	struct b43legacy_wldev *dev = led->dev;
+	const int index = led->index;
+	u16 ledctl;
+
+	B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS));
+	B43legacy_WARN_ON(!led->blink_interval);
+	ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
+	ledctl ^= (1 << index);
+	b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
+}
+
+static void b43legacy_led_blink(unsigned long d)
+{
+	struct b43legacy_led *led = (struct b43legacy_led *)d;
+	struct b43legacy_wldev *dev = led->dev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->wl->leds_lock, flags);
+	if (led->blink_interval) {
+		b43legacy_led_changestate(led);
+		mod_timer(&led->blink_timer, jiffies + led->blink_interval);
+	}
+	spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
+}
+
+static void b43legacy_led_blink_start(struct b43legacy_led *led,
+				      unsigned long interval)
+{
+	if (led->blink_interval)
+		return;
+	led->blink_interval = interval;
+	b43legacy_led_changestate(led);
+	led->blink_timer.expires = jiffies + interval;
+	add_timer(&led->blink_timer);
+}
+
+static void b43legacy_led_blink_stop(struct b43legacy_led *led, int sync)
+{
+	struct b43legacy_wldev *dev = led->dev;
+	const int index = led->index;
+	u16 ledctl;
+
+	if (!led->blink_interval)
+		return;
+	if (unlikely(sync))
+		del_timer_sync(&led->blink_timer);
+	else
+		del_timer(&led->blink_timer);
+	led->blink_interval = 0;
+
+	/* Make sure the LED is turned off. */
+	B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS));
+	ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
+	if (led->activelow)
+		ledctl |= (1 << index);
+	else
+		ledctl &= ~(1 << index);
+	b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
+}
+
+static void b43legacy_led_init_hardcoded(struct b43legacy_wldev *dev,
+					 struct b43legacy_led *led,
+					 int led_index)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+
+	/* This function is called, if the behaviour (and activelow)
+	 * information for a LED is missing in the SPROM.
+	 * We hardcode the behaviour values for various devices here.
+	 * Note that the B43legacy_LED_TEST_XXX behaviour values can
+	 * be used to figure out which led is mapped to which index.
+	 */
+
+	switch (led_index) {
+	case 0:
+		led->behaviour = B43legacy_LED_ACTIVITY;
+		led->activelow = 1;
+		if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ)
+			led->behaviour = B43legacy_LED_RADIO_ALL;
+		break;
+	case 1:
+		led->behaviour = B43legacy_LED_RADIO_B;
+		if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK)
+			led->behaviour = B43legacy_LED_ASSOC;
+		break;
+	case 2:
+		led->behaviour = B43legacy_LED_RADIO_A;
+		break;
+	case 3:
+		led->behaviour = B43legacy_LED_OFF;
+		break;
+	default:
+		B43legacy_BUG_ON(1);
+	}
+}
+
+int b43legacy_leds_init(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_led *led;
+	u8 sprom[4];
+	int i;
+
+	sprom[0] = dev->dev->bus->sprom.r1.gpio0;
+	sprom[1] = dev->dev->bus->sprom.r1.gpio1;
+	sprom[2] = dev->dev->bus->sprom.r1.gpio2;
+	sprom[3] = dev->dev->bus->sprom.r1.gpio3;
+
+	for (i = 0; i < B43legacy_NR_LEDS; i++) {
+		led = &(dev->leds[i]);
+		led->index = i;
+		led->dev = dev;
+		setup_timer(&led->blink_timer,
+			    b43legacy_led_blink,
+			    (unsigned long)led);
+
+		if (sprom[i] == 0xFF)
+			b43legacy_led_init_hardcoded(dev, led, i);
+		else {
+			led->behaviour = sprom[i] & B43legacy_LED_BEHAVIOUR;
+			led->activelow = !!(sprom[i] &
+					   B43legacy_LED_ACTIVELOW);
+		}
+	}
+
+	return 0;
+}
+
+void b43legacy_leds_exit(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_led *led;
+	int i;
+
+	for (i = 0; i < B43legacy_NR_LEDS; i++) {
+		led = &(dev->leds[i]);
+		b43legacy_led_blink_stop(led, 1);
+	}
+	b43legacy_leds_switch_all(dev, 0);
+}
+
+void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity)
+{
+	struct b43legacy_led *led;
+	struct b43legacy_phy *phy = &dev->phy;
+	const int transferring = (jiffies - dev->stats.last_tx)
+				  < B43legacy_LED_XFER_THRES;
+	int i;
+	int turn_on;
+	unsigned long interval = 0;
+	u16 ledctl;
+	unsigned long flags;
+	bool radio_enabled = (phy->radio_on && dev->radio_hw_enable);
+
+	spin_lock_irqsave(&dev->wl->leds_lock, flags);
+	ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
+	for (i = 0; i < B43legacy_NR_LEDS; i++) {
+		led = &(dev->leds[i]);
+
+		turn_on = 0;
+		switch (led->behaviour) {
+		case B43legacy_LED_INACTIVE:
+			continue;
+		case B43legacy_LED_OFF:
+			break;
+		case B43legacy_LED_ON:
+			turn_on = 1;
+			break;
+		case B43legacy_LED_ACTIVITY:
+			turn_on = activity;
+			break;
+		case B43legacy_LED_RADIO_ALL:
+			turn_on = radio_enabled;
+			break;
+		case B43legacy_LED_RADIO_A:
+			break;
+		case B43legacy_LED_RADIO_B:
+			turn_on = radio_enabled;
+			break;
+		case B43legacy_LED_MODE_BG:
+			if (phy->type == B43legacy_PHYTYPE_G && radio_enabled)
+				turn_on = 1;
+			break;
+		case B43legacy_LED_TRANSFER:
+			if (transferring)
+				b43legacy_led_blink_start(led,
+						B43legacy_LEDBLINK_MEDIUM);
+			else
+				b43legacy_led_blink_stop(led, 0);
+			continue;
+		case B43legacy_LED_APTRANSFER:
+			if (b43legacy_is_mode(dev->wl,
+						IEEE80211_IF_TYPE_AP)) {
+				if (transferring) {
+					interval = B43legacy_LEDBLINK_FAST;
+					turn_on = 1;
+				}
+			} else {
+				turn_on = 1;
+				if (transferring)
+					interval = B43legacy_LEDBLINK_FAST;
+				else
+					turn_on = 0;
+			}
+			if (turn_on)
+				b43legacy_led_blink_start(led, interval);
+			else
+				b43legacy_led_blink_stop(led, 0);
+			continue;
+		case B43legacy_LED_WEIRD:
+			break;
+		case B43legacy_LED_ASSOC:
+			turn_on = 1;
+#ifdef CONFIG_B43LEGACY_DEBUG
+		case B43legacy_LED_TEST_BLINKSLOW:
+			b43legacy_led_blink_start(led, B43legacy_LEDBLINK_SLOW);
+			continue;
+		case B43legacy_LED_TEST_BLINKMEDIUM:
+			b43legacy_led_blink_start(led,
+						   B43legacy_LEDBLINK_MEDIUM);
+			continue;
+		case B43legacy_LED_TEST_BLINKFAST:
+			b43legacy_led_blink_start(led, B43legacy_LEDBLINK_FAST);
+			continue;
+#endif /* CONFIG_B43LEGACY_DEBUG */
+		default:
+			B43legacy_BUG_ON(1);
+		};
+
+		if (led->activelow)
+			turn_on = !turn_on;
+		if (turn_on)
+			ledctl |= (1 << i);
+		else
+			ledctl &= ~(1 << i);
+	}
+	b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
+	spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
+}
+
+void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on)
+{
+	struct b43legacy_led *led;
+	u16 ledctl;
+	int i;
+	int bit_on;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->wl->leds_lock, flags);
+	ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL);
+	for (i = 0; i < B43legacy_NR_LEDS; i++) {
+		led = &(dev->leds[i]);
+		if (led->behaviour == B43legacy_LED_INACTIVE)
+			continue;
+		if (on)
+			bit_on = led->activelow ? 0 : 1;
+		else
+			bit_on = led->activelow ? 1 : 0;
+		if (bit_on)
+			ledctl |= (1 << i);
+		else
+			ledctl &= ~(1 << i);
+	}
+	b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl);
+	spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
+}
diff --git a/drivers/net/wireless/b43legacy/leds.h b/drivers/net/wireless/b43legacy/leds.h
new file mode 100644
index 0000000..b989f50
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/leds.h
@@ -0,0 +1,56 @@
+#ifndef B43legacy_LEDS_H_
+#define B43legacy_LEDS_H_
+
+#include <linux/types.h>
+#include <linux/timer.h>
+
+
+struct b43legacy_led {
+	u8 behaviour;
+	bool activelow;
+	/* Index in the "leds" array in b43legacy_wldev */
+	u8 index;
+	struct b43legacy_wldev *dev;
+	struct timer_list blink_timer;
+	unsigned long blink_interval;
+};
+
+/* Delay between state changes when blinking in jiffies */
+#define B43legacy_LEDBLINK_SLOW		(HZ / 1)
+#define B43legacy_LEDBLINK_MEDIUM	(HZ / 4)
+#define B43legacy_LEDBLINK_FAST		(HZ / 8)
+
+#define B43legacy_LED_XFER_THRES	(HZ / 100)
+
+#define B43legacy_LED_BEHAVIOUR		0x7F
+#define B43legacy_LED_ACTIVELOW		0x80
+enum { /* LED behaviour values */
+	B43legacy_LED_OFF,
+	B43legacy_LED_ON,
+	B43legacy_LED_ACTIVITY,
+	B43legacy_LED_RADIO_ALL,
+	B43legacy_LED_RADIO_A,
+	B43legacy_LED_RADIO_B,
+	B43legacy_LED_MODE_BG,
+	B43legacy_LED_TRANSFER,
+	B43legacy_LED_APTRANSFER,
+	B43legacy_LED_WEIRD,
+	B43legacy_LED_ASSOC,
+	B43legacy_LED_INACTIVE,
+
+	/* Behaviour values for testing.
+	 * With these values it is easier to figure out
+	 * the real behaviour of leds, in case the SPROM
+	 * is missing information.
+	 */
+	B43legacy_LED_TEST_BLINKSLOW,
+	B43legacy_LED_TEST_BLINKMEDIUM,
+	B43legacy_LED_TEST_BLINKFAST,
+};
+
+int b43legacy_leds_init(struct b43legacy_wldev *dev);
+void b43legacy_leds_exit(struct b43legacy_wldev *dev);
+void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity);
+void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on);
+
+#endif /* B43legacy_LEDS_H_ */
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
new file mode 100644
index 0000000..f074951
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -0,0 +1,3856 @@
+/*
+ *
+ *  Broadcom B43legacy wireless driver
+ *
+ *  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
+ *  Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+ *  Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+ *  Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ *  Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ *  Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *  Some parts of the code in this file are derived from the ipw2200
+ *  driver  Copyright(c) 2003 - 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 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; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ *  Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/version.h>
+#include <linux/firmware.h>
+#include <linux/wireless.h>
+#include <linux/workqueue.h>
+#include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
+#include <net/dst.h>
+#include <asm/unaligned.h>
+
+#include "b43legacy.h"
+#include "main.h"
+#include "debugfs.h"
+#include "phy.h"
+#include "dma.h"
+#include "pio.h"
+#include "sysfs.h"
+#include "xmit.h"
+#include "radio.h"
+
+
+MODULE_DESCRIPTION("Broadcom B43legacy wireless driver");
+MODULE_AUTHOR("Martin Langer");
+MODULE_AUTHOR("Stefano Brivio");
+MODULE_AUTHOR("Michael Buesch");
+MODULE_LICENSE("GPL");
+
+#if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO)
+static int modparam_pio;
+module_param_named(pio, modparam_pio, int, 0444);
+MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
+#elif defined(CONFIG_B43LEGACY_DMA)
+# define modparam_pio	0
+#elif defined(CONFIG_B43LEGACY_PIO)
+# define modparam_pio	1
+#endif
+
+static int modparam_bad_frames_preempt;
+module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
+MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames"
+		 " Preemption");
+
+static int modparam_short_retry = B43legacy_DEFAULT_SHORT_RETRY_LIMIT;
+module_param_named(short_retry, modparam_short_retry, int, 0444);
+MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)");
+
+static int modparam_long_retry = B43legacy_DEFAULT_LONG_RETRY_LIMIT;
+module_param_named(long_retry, modparam_long_retry, int, 0444);
+MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
+
+static int modparam_noleds;
+module_param_named(noleds, modparam_noleds, int, 0444);
+MODULE_PARM_DESC(noleds, "Turn off all LED activity");
+
+static char modparam_fwpostfix[16];
+module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
+MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load.");
+
+/* The following table supports BCM4301, BCM4303 and BCM4306/2 devices. */
+static const struct ssb_device_id b43legacy_ssb_tbl[] = {
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 2),
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 4),
+	SSB_DEVTABLE_END
+};
+MODULE_DEVICE_TABLE(ssb, b43legacy_ssb_tbl);
+
+
+/* Channel and ratetables are shared for all devices.
+ * They can't be const, because ieee80211 puts some precalculated
+ * data in there. This data is the same for all devices, so we don't
+ * get concurrency issues */
+#define RATETAB_ENT(_rateid, _flags) \
+	{							\
+		.rate	= B43legacy_RATE_TO_100KBPS(_rateid),	\
+		.val	= (_rateid),				\
+		.val2	= (_rateid),				\
+		.flags	= (_flags),				\
+	}
+static struct ieee80211_rate __b43legacy_ratetable[] = {
+	RATETAB_ENT(B43legacy_CCK_RATE_1MB, IEEE80211_RATE_CCK),
+	RATETAB_ENT(B43legacy_CCK_RATE_2MB, IEEE80211_RATE_CCK_2),
+	RATETAB_ENT(B43legacy_CCK_RATE_5MB, IEEE80211_RATE_CCK_2),
+	RATETAB_ENT(B43legacy_CCK_RATE_11MB, IEEE80211_RATE_CCK_2),
+	RATETAB_ENT(B43legacy_OFDM_RATE_6MB, IEEE80211_RATE_OFDM),
+	RATETAB_ENT(B43legacy_OFDM_RATE_9MB, IEEE80211_RATE_OFDM),
+	RATETAB_ENT(B43legacy_OFDM_RATE_12MB, IEEE80211_RATE_OFDM),
+	RATETAB_ENT(B43legacy_OFDM_RATE_18MB, IEEE80211_RATE_OFDM),
+	RATETAB_ENT(B43legacy_OFDM_RATE_24MB, IEEE80211_RATE_OFDM),
+	RATETAB_ENT(B43legacy_OFDM_RATE_36MB, IEEE80211_RATE_OFDM),
+	RATETAB_ENT(B43legacy_OFDM_RATE_48MB, IEEE80211_RATE_OFDM),
+	RATETAB_ENT(B43legacy_OFDM_RATE_54MB, IEEE80211_RATE_OFDM),
+};
+#define b43legacy_a_ratetable		(__b43legacy_ratetable + 4)
+#define b43legacy_a_ratetable_size	8
+#define b43legacy_b_ratetable		(__b43legacy_ratetable + 0)
+#define b43legacy_b_ratetable_size	4
+#define b43legacy_g_ratetable		(__b43legacy_ratetable + 0)
+#define b43legacy_g_ratetable_size	12
+
+#define CHANTAB_ENT(_chanid, _freq) \
+	{							\
+		.chan	= (_chanid),				\
+		.freq	= (_freq),				\
+		.val	= (_chanid),				\
+		.flag	= IEEE80211_CHAN_W_SCAN |		\
+			  IEEE80211_CHAN_W_ACTIVE_SCAN |	\
+			  IEEE80211_CHAN_W_IBSS,		\
+		.power_level	= 0x0A,				\
+		.antenna_max	= 0xFF,				\
+	}
+static struct ieee80211_channel b43legacy_bg_chantable[] = {
+	CHANTAB_ENT(1, 2412),
+	CHANTAB_ENT(2, 2417),
+	CHANTAB_ENT(3, 2422),
+	CHANTAB_ENT(4, 2427),
+	CHANTAB_ENT(5, 2432),
+	CHANTAB_ENT(6, 2437),
+	CHANTAB_ENT(7, 2442),
+	CHANTAB_ENT(8, 2447),
+	CHANTAB_ENT(9, 2452),
+	CHANTAB_ENT(10, 2457),
+	CHANTAB_ENT(11, 2462),
+	CHANTAB_ENT(12, 2467),
+	CHANTAB_ENT(13, 2472),
+	CHANTAB_ENT(14, 2484),
+};
+#define b43legacy_bg_chantable_size	ARRAY_SIZE(b43legacy_bg_chantable)
+
+static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev);
+static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev);
+static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev);
+static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev);
+
+
+static int b43legacy_ratelimit(struct b43legacy_wl *wl)
+{
+	if (!wl || !wl->current_dev)
+		return 1;
+	if (b43legacy_status(wl->current_dev) < B43legacy_STAT_STARTED)
+		return 1;
+	/* We are up and running.
+	 * Ratelimit the messages to avoid DoS over the net. */
+	return net_ratelimit();
+}
+
+void b43legacyinfo(struct b43legacy_wl *wl, const char *fmt, ...)
+{
+	va_list args;
+
+	if (!b43legacy_ratelimit(wl))
+		return;
+	va_start(args, fmt);
+	printk(KERN_INFO "b43legacy-%s: ",
+	       (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+	vprintk(fmt, args);
+	va_end(args);
+}
+
+void b43legacyerr(struct b43legacy_wl *wl, const char *fmt, ...)
+{
+	va_list args;
+
+	if (!b43legacy_ratelimit(wl))
+		return;
+	va_start(args, fmt);
+	printk(KERN_ERR "b43legacy-%s ERROR: ",
+	       (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+	vprintk(fmt, args);
+	va_end(args);
+}
+
+void b43legacywarn(struct b43legacy_wl *wl, const char *fmt, ...)
+{
+	va_list args;
+
+	if (!b43legacy_ratelimit(wl))
+		return;
+	va_start(args, fmt);
+	printk(KERN_WARNING "b43legacy-%s warning: ",
+	       (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+	vprintk(fmt, args);
+	va_end(args);
+}
+
+#if B43legacy_DEBUG
+void b43legacydbg(struct b43legacy_wl *wl, const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	printk(KERN_DEBUG "b43legacy-%s debug: ",
+	       (wl && wl->hw) ? wiphy_name(wl->hw->wiphy) : "wlan");
+	vprintk(fmt, args);
+	va_end(args);
+}
+#endif /* DEBUG */
+
+static void b43legacy_ram_write(struct b43legacy_wldev *dev, u16 offset,
+				u32 val)
+{
+	u32 status;
+
+	B43legacy_WARN_ON(offset % 4 != 0);
+
+	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+	if (status & B43legacy_SBF_XFER_REG_BYTESWAP)
+		val = swab32(val);
+
+	b43legacy_write32(dev, B43legacy_MMIO_RAM_CONTROL, offset);
+	mmiowb();
+	b43legacy_write32(dev, B43legacy_MMIO_RAM_DATA, val);
+}
+
+static inline
+void b43legacy_shm_control_word(struct b43legacy_wldev *dev,
+				u16 routing, u16 offset)
+{
+	u32 control;
+
+	/* "offset" is the WORD offset. */
+
+	control = routing;
+	control <<= 16;
+	control |= offset;
+	b43legacy_write32(dev, B43legacy_MMIO_SHM_CONTROL, control);
+}
+
+u32 b43legacy_shm_read32(struct b43legacy_wldev *dev,
+		       u16 routing, u16 offset)
+{
+	u32 ret;
+
+	if (routing == B43legacy_SHM_SHARED) {
+		B43legacy_WARN_ON((offset & 0x0001) != 0);
+		if (offset & 0x0003) {
+			/* Unaligned access */
+			b43legacy_shm_control_word(dev, routing, offset >> 2);
+			ret = b43legacy_read16(dev,
+				B43legacy_MMIO_SHM_DATA_UNALIGNED);
+			ret <<= 16;
+			b43legacy_shm_control_word(dev, routing,
+						     (offset >> 2) + 1);
+			ret |= b43legacy_read16(dev, B43legacy_MMIO_SHM_DATA);
+
+			return ret;
+		}
+		offset >>= 2;
+	}
+	b43legacy_shm_control_word(dev, routing, offset);
+	ret = b43legacy_read32(dev, B43legacy_MMIO_SHM_DATA);
+
+	return ret;
+}
+
+u16 b43legacy_shm_read16(struct b43legacy_wldev *dev,
+			   u16 routing, u16 offset)
+{
+	u16 ret;
+
+	if (routing == B43legacy_SHM_SHARED) {
+		B43legacy_WARN_ON((offset & 0x0001) != 0);
+		if (offset & 0x0003) {
+			/* Unaligned access */
+			b43legacy_shm_control_word(dev, routing, offset >> 2);
+			ret = b43legacy_read16(dev,
+					     B43legacy_MMIO_SHM_DATA_UNALIGNED);
+
+			return ret;
+		}
+		offset >>= 2;
+	}
+	b43legacy_shm_control_word(dev, routing, offset);
+	ret = b43legacy_read16(dev, B43legacy_MMIO_SHM_DATA);
+
+	return ret;
+}
+
+void b43legacy_shm_write32(struct b43legacy_wldev *dev,
+			   u16 routing, u16 offset,
+			   u32 value)
+{
+	if (routing == B43legacy_SHM_SHARED) {
+		B43legacy_WARN_ON((offset & 0x0001) != 0);
+		if (offset & 0x0003) {
+			/* Unaligned access */
+			b43legacy_shm_control_word(dev, routing, offset >> 2);
+			mmiowb();
+			b43legacy_write16(dev,
+					  B43legacy_MMIO_SHM_DATA_UNALIGNED,
+					  (value >> 16) & 0xffff);
+			mmiowb();
+			b43legacy_shm_control_word(dev, routing,
+						   (offset >> 2) + 1);
+			mmiowb();
+			b43legacy_write16(dev, B43legacy_MMIO_SHM_DATA,
+					  value & 0xffff);
+			return;
+		}
+		offset >>= 2;
+	}
+	b43legacy_shm_control_word(dev, routing, offset);
+	mmiowb();
+	b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA, value);
+}
+
+void b43legacy_shm_write16(struct b43legacy_wldev *dev, u16 routing, u16 offset,
+			   u16 value)
+{
+	if (routing == B43legacy_SHM_SHARED) {
+		B43legacy_WARN_ON((offset & 0x0001) != 0);
+		if (offset & 0x0003) {
+			/* Unaligned access */
+			b43legacy_shm_control_word(dev, routing, offset >> 2);
+			mmiowb();
+			b43legacy_write16(dev,
+					  B43legacy_MMIO_SHM_DATA_UNALIGNED,
+					  value);
+			return;
+		}
+		offset >>= 2;
+	}
+	b43legacy_shm_control_word(dev, routing, offset);
+	mmiowb();
+	b43legacy_write16(dev, B43legacy_MMIO_SHM_DATA, value);
+}
+
+/* Read HostFlags */
+u32 b43legacy_hf_read(struct b43legacy_wldev *dev)
+{
+	u32 ret;
+
+	ret = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+				   B43legacy_SHM_SH_HOSTFHI);
+	ret <<= 16;
+	ret |= b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+				    B43legacy_SHM_SH_HOSTFLO);
+
+	return ret;
+}
+
+/* Write HostFlags */
+void b43legacy_hf_write(struct b43legacy_wldev *dev, u32 value)
+{
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+			      B43legacy_SHM_SH_HOSTFLO,
+			      (value & 0x0000FFFF));
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+			      B43legacy_SHM_SH_HOSTFHI,
+			      ((value & 0xFFFF0000) >> 16));
+}
+
+void b43legacy_tsf_read(struct b43legacy_wldev *dev, u64 *tsf)
+{
+	/* We need to be careful. As we read the TSF from multiple
+	 * registers, we should take care of register overflows.
+	 * In theory, the whole tsf read process should be atomic.
+	 * We try to be atomic here, by restaring the read process,
+	 * if any of the high registers changed (overflew).
+	 */
+	if (dev->dev->id.revision >= 3) {
+		u32 low;
+		u32 high;
+		u32 high2;
+
+		do {
+			high = b43legacy_read32(dev,
+					B43legacy_MMIO_REV3PLUS_TSF_HIGH);
+			low = b43legacy_read32(dev,
+					B43legacy_MMIO_REV3PLUS_TSF_LOW);
+			high2 = b43legacy_read32(dev,
+					B43legacy_MMIO_REV3PLUS_TSF_HIGH);
+		} while (unlikely(high != high2));
+
+		*tsf = high;
+		*tsf <<= 32;
+		*tsf |= low;
+	} else {
+		u64 tmp;
+		u16 v0;
+		u16 v1;
+		u16 v2;
+		u16 v3;
+		u16 test1;
+		u16 test2;
+		u16 test3;
+
+		do {
+			v3 = b43legacy_read16(dev, B43legacy_MMIO_TSF_3);
+			v2 = b43legacy_read16(dev, B43legacy_MMIO_TSF_2);
+			v1 = b43legacy_read16(dev, B43legacy_MMIO_TSF_1);
+			v0 = b43legacy_read16(dev, B43legacy_MMIO_TSF_0);
+
+			test3 = b43legacy_read16(dev, B43legacy_MMIO_TSF_3);
+			test2 = b43legacy_read16(dev, B43legacy_MMIO_TSF_2);
+			test1 = b43legacy_read16(dev, B43legacy_MMIO_TSF_1);
+		} while (v3 != test3 || v2 != test2 || v1 != test1);
+
+		*tsf = v3;
+		*tsf <<= 48;
+		tmp = v2;
+		tmp <<= 32;
+		*tsf |= tmp;
+		tmp = v1;
+		tmp <<= 16;
+		*tsf |= tmp;
+		*tsf |= v0;
+	}
+}
+
+static void b43legacy_time_lock(struct b43legacy_wldev *dev)
+{
+	u32 status;
+
+	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+	status |= B43legacy_SBF_TIME_UPDATE;
+	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+	mmiowb();
+}
+
+static void b43legacy_time_unlock(struct b43legacy_wldev *dev)
+{
+	u32 status;
+
+	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+	status &= ~B43legacy_SBF_TIME_UPDATE;
+	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+}
+
+static void b43legacy_tsf_write_locked(struct b43legacy_wldev *dev, u64 tsf)
+{
+	/* Be careful with the in-progress timer.
+	 * First zero out the low register, so we have a full
+	 * register-overflow duration to complete the operation.
+	 */
+	if (dev->dev->id.revision >= 3) {
+		u32 lo = (tsf & 0x00000000FFFFFFFFULL);
+		u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32;
+
+		b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_LOW, 0);
+		mmiowb();
+		b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_HIGH,
+				    hi);
+		mmiowb();
+		b43legacy_write32(dev, B43legacy_MMIO_REV3PLUS_TSF_LOW,
+				    lo);
+	} else {
+		u16 v0 = (tsf & 0x000000000000FFFFULL);
+		u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16;
+		u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32;
+		u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48;
+
+		b43legacy_write16(dev, B43legacy_MMIO_TSF_0, 0);
+		mmiowb();
+		b43legacy_write16(dev, B43legacy_MMIO_TSF_3, v3);
+		mmiowb();
+		b43legacy_write16(dev, B43legacy_MMIO_TSF_2, v2);
+		mmiowb();
+		b43legacy_write16(dev, B43legacy_MMIO_TSF_1, v1);
+		mmiowb();
+		b43legacy_write16(dev, B43legacy_MMIO_TSF_0, v0);
+	}
+}
+
+void b43legacy_tsf_write(struct b43legacy_wldev *dev, u64 tsf)
+{
+	b43legacy_time_lock(dev);
+	b43legacy_tsf_write_locked(dev, tsf);
+	b43legacy_time_unlock(dev);
+}
+
+static
+void b43legacy_macfilter_set(struct b43legacy_wldev *dev,
+			     u16 offset, const u8 *mac)
+{
+	static const u8 zero_addr[ETH_ALEN] = { 0 };
+	u16 data;
+
+	if (!mac)
+		mac = zero_addr;
+
+	offset |= 0x0020;
+	b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_CONTROL, offset);
+
+	data = mac[0];
+	data |= mac[1] << 8;
+	b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data);
+	data = mac[2];
+	data |= mac[3] << 8;
+	b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data);
+	data = mac[4];
+	data |= mac[5] << 8;
+	b43legacy_write16(dev, B43legacy_MMIO_MACFILTER_DATA, data);
+}
+
+static void b43legacy_write_mac_bssid_templates(struct b43legacy_wldev *dev)
+{
+	static const u8 zero_addr[ETH_ALEN] = { 0 };
+	const u8 *mac = dev->wl->mac_addr;
+	const u8 *bssid = dev->wl->bssid;
+	u8 mac_bssid[ETH_ALEN * 2];
+	int i;
+	u32 tmp;
+
+	if (!bssid)
+		bssid = zero_addr;
+	if (!mac)
+		mac = zero_addr;
+
+	b43legacy_macfilter_set(dev, B43legacy_MACFILTER_BSSID, bssid);
+
+	memcpy(mac_bssid, mac, ETH_ALEN);
+	memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
+
+	/* Write our MAC address and BSSID to template ram */
+	for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) {
+		tmp =  (u32)(mac_bssid[i + 0]);
+		tmp |= (u32)(mac_bssid[i + 1]) << 8;
+		tmp |= (u32)(mac_bssid[i + 2]) << 16;
+		tmp |= (u32)(mac_bssid[i + 3]) << 24;
+		b43legacy_ram_write(dev, 0x20 + i, tmp);
+		b43legacy_ram_write(dev, 0x78 + i, tmp);
+		b43legacy_ram_write(dev, 0x478 + i, tmp);
+	}
+}
+
+static void b43legacy_upload_card_macaddress(struct b43legacy_wldev *dev)
+{
+	b43legacy_write_mac_bssid_templates(dev);
+	b43legacy_macfilter_set(dev, B43legacy_MACFILTER_SELF,
+				dev->wl->mac_addr);
+}
+
+static void b43legacy_set_slot_time(struct b43legacy_wldev *dev,
+				    u16 slot_time)
+{
+	/* slot_time is in usec. */
+	if (dev->phy.type != B43legacy_PHYTYPE_G)
+		return;
+	b43legacy_write16(dev, 0x684, 510 + slot_time);
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0010,
+			      slot_time);
+}
+
+static void b43legacy_short_slot_timing_enable(struct b43legacy_wldev *dev)
+{
+	b43legacy_set_slot_time(dev, 9);
+	dev->short_slot = 1;
+}
+
+static void b43legacy_short_slot_timing_disable(struct b43legacy_wldev *dev)
+{
+	b43legacy_set_slot_time(dev, 20);
+	dev->short_slot = 0;
+}
+
+/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
+ * Returns the _previously_ enabled IRQ mask.
+ */
+static inline u32 b43legacy_interrupt_enable(struct b43legacy_wldev *dev,
+					     u32 mask)
+{
+	u32 old_mask;
+
+	old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
+	b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask |
+			  mask);
+
+	return old_mask;
+}
+
+/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable.
+ * Returns the _previously_ enabled IRQ mask.
+ */
+static inline u32 b43legacy_interrupt_disable(struct b43legacy_wldev *dev,
+					      u32 mask)
+{
+	u32 old_mask;
+
+	old_mask = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
+	b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_MASK, old_mask & ~mask);
+
+	return old_mask;
+}
+
+/* Synchronize IRQ top- and bottom-half.
+ * IRQs must be masked before calling this.
+ * This must not be called with the irq_lock held.
+ */
+static void b43legacy_synchronize_irq(struct b43legacy_wldev *dev)
+{
+	synchronize_irq(dev->dev->irq);
+	tasklet_kill(&dev->isr_tasklet);
+}
+
+/* DummyTransmission function, as documented on
+ * http://bcm-specs.sipsolutions.net/DummyTransmission
+ */
+void b43legacy_dummy_transmission(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	unsigned int i;
+	unsigned int max_loop;
+	u16 value;
+	u32 buffer[5] = {
+		0x00000000,
+		0x00D40000,
+		0x00000000,
+		0x01000000,
+		0x00000000,
+	};
+
+	switch (phy->type) {
+	case B43legacy_PHYTYPE_B:
+	case B43legacy_PHYTYPE_G:
+		max_loop = 0xFA;
+		buffer[0] = 0x000B846E;
+		break;
+	default:
+		B43legacy_BUG_ON(1);
+		return;
+	}
+
+	for (i = 0; i < 5; i++)
+		b43legacy_ram_write(dev, i * 4, buffer[i]);
+
+	/* dummy read follows */
+	b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+
+	b43legacy_write16(dev, 0x0568, 0x0000);
+	b43legacy_write16(dev, 0x07C0, 0x0000);
+	b43legacy_write16(dev, 0x050C, 0x0000);
+	b43legacy_write16(dev, 0x0508, 0x0000);
+	b43legacy_write16(dev, 0x050A, 0x0000);
+	b43legacy_write16(dev, 0x054C, 0x0000);
+	b43legacy_write16(dev, 0x056A, 0x0014);
+	b43legacy_write16(dev, 0x0568, 0x0826);
+	b43legacy_write16(dev, 0x0500, 0x0000);
+	b43legacy_write16(dev, 0x0502, 0x0030);
+
+	if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
+		b43legacy_radio_write16(dev, 0x0051, 0x0017);
+	for (i = 0x00; i < max_loop; i++) {
+		value = b43legacy_read16(dev, 0x050E);
+		if (value & 0x0080)
+			break;
+		udelay(10);
+	}
+	for (i = 0x00; i < 0x0A; i++) {
+		value = b43legacy_read16(dev, 0x050E);
+		if (value & 0x0400)
+			break;
+		udelay(10);
+	}
+	for (i = 0x00; i < 0x0A; i++) {
+		value = b43legacy_read16(dev, 0x0690);
+		if (!(value & 0x0100))
+			break;
+		udelay(10);
+	}
+	if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
+		b43legacy_radio_write16(dev, 0x0051, 0x0037);
+}
+
+/* Turn the Analog ON/OFF */
+static void b43legacy_switch_analog(struct b43legacy_wldev *dev, int on)
+{
+	b43legacy_write16(dev, B43legacy_MMIO_PHY0, on ? 0 : 0xF4);
+}
+
+void b43legacy_wireless_core_reset(struct b43legacy_wldev *dev, u32 flags)
+{
+	u32 tmslow;
+	u32 macctl;
+
+	flags |= B43legacy_TMSLOW_PHYCLKEN;
+	flags |= B43legacy_TMSLOW_PHYRESET;
+	ssb_device_enable(dev->dev, flags);
+	msleep(2); /* Wait for the PLL to turn on. */
+
+	/* Now take the PHY out of Reset again */
+	tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+	tmslow |= SSB_TMSLOW_FGC;
+	tmslow &= ~B43legacy_TMSLOW_PHYRESET;
+	ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+	ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
+	msleep(1);
+	tmslow &= ~SSB_TMSLOW_FGC;
+	ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+	ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
+	msleep(1);
+
+	/* Turn Analog ON */
+	b43legacy_switch_analog(dev, 1);
+
+	macctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+	macctl &= ~B43legacy_MACCTL_GMODE;
+	if (flags & B43legacy_TMSLOW_GMODE) {
+		macctl |= B43legacy_MACCTL_GMODE;
+		dev->phy.gmode = 1;
+	} else
+		dev->phy.gmode = 0;
+	macctl |= B43legacy_MACCTL_IHR_ENABLED;
+	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, macctl);
+}
+
+static void handle_irq_transmit_status(struct b43legacy_wldev *dev)
+{
+	u32 v0;
+	u32 v1;
+	u16 tmp;
+	struct b43legacy_txstatus stat;
+
+	while (1) {
+		v0 = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_0);
+		if (!(v0 & 0x00000001))
+			break;
+		v1 = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_1);
+
+		stat.cookie = (v0 >> 16);
+		stat.seq = (v1 & 0x0000FFFF);
+		stat.phy_stat = ((v1 & 0x00FF0000) >> 16);
+		tmp = (v0 & 0x0000FFFF);
+		stat.frame_count = ((tmp & 0xF000) >> 12);
+		stat.rts_count = ((tmp & 0x0F00) >> 8);
+		stat.supp_reason = ((tmp & 0x001C) >> 2);
+		stat.pm_indicated = !!(tmp & 0x0080);
+		stat.intermediate = !!(tmp & 0x0040);
+		stat.for_ampdu = !!(tmp & 0x0020);
+		stat.acked = !!(tmp & 0x0002);
+
+		b43legacy_handle_txstatus(dev, &stat);
+	}
+}
+
+static void drain_txstatus_queue(struct b43legacy_wldev *dev)
+{
+	u32 dummy;
+
+	if (dev->dev->id.revision < 5)
+		return;
+	/* Read all entries from the microcode TXstatus FIFO
+	 * and throw them away.
+	 */
+	while (1) {
+		dummy = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_0);
+		if (!(dummy & 0x00000001))
+			break;
+		dummy = b43legacy_read32(dev, B43legacy_MMIO_XMITSTAT_1);
+	}
+}
+
+static u32 b43legacy_jssi_read(struct b43legacy_wldev *dev)
+{
+	u32 val = 0;
+
+	val = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x40A);
+	val <<= 16;
+	val |= b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x408);
+
+	return val;
+}
+
+static void b43legacy_jssi_write(struct b43legacy_wldev *dev, u32 jssi)
+{
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x408,
+			      (jssi & 0x0000FFFF));
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x40A,
+			      (jssi & 0xFFFF0000) >> 16);
+}
+
+static void b43legacy_generate_noise_sample(struct b43legacy_wldev *dev)
+{
+	b43legacy_jssi_write(dev, 0x7F7F7F7F);
+	b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+			  b43legacy_read32(dev,
+			  B43legacy_MMIO_STATUS2_BITFIELD)
+			  | (1 << 4));
+	B43legacy_WARN_ON(dev->noisecalc.channel_at_start !=
+			    dev->phy.channel);
+}
+
+static void b43legacy_calculate_link_quality(struct b43legacy_wldev *dev)
+{
+	/* Top half of Link Quality calculation. */
+
+	if (dev->noisecalc.calculation_running)
+		return;
+	dev->noisecalc.channel_at_start = dev->phy.channel;
+	dev->noisecalc.calculation_running = 1;
+	dev->noisecalc.nr_samples = 0;
+
+	b43legacy_generate_noise_sample(dev);
+}
+
+static void handle_irq_noise(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 tmp;
+	u8 noise[4];
+	u8 i;
+	u8 j;
+	s32 average;
+
+	/* Bottom half of Link Quality calculation. */
+
+	B43legacy_WARN_ON(!dev->noisecalc.calculation_running);
+	if (dev->noisecalc.channel_at_start != phy->channel)
+		goto drop_calculation;
+	*((__le32 *)noise) = cpu_to_le32(b43legacy_jssi_read(dev));
+	if (noise[0] == 0x7F || noise[1] == 0x7F ||
+	    noise[2] == 0x7F || noise[3] == 0x7F)
+		goto generate_new;
+
+	/* Get the noise samples. */
+	B43legacy_WARN_ON(dev->noisecalc.nr_samples >= 8);
+	i = dev->noisecalc.nr_samples;
+	noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+	noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+	noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+	noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(phy->nrssi_lt) - 1);
+	dev->noisecalc.samples[i][0] = phy->nrssi_lt[noise[0]];
+	dev->noisecalc.samples[i][1] = phy->nrssi_lt[noise[1]];
+	dev->noisecalc.samples[i][2] = phy->nrssi_lt[noise[2]];
+	dev->noisecalc.samples[i][3] = phy->nrssi_lt[noise[3]];
+	dev->noisecalc.nr_samples++;
+	if (dev->noisecalc.nr_samples == 8) {
+		/* Calculate the Link Quality by the noise samples. */
+		average = 0;
+		for (i = 0; i < 8; i++) {
+			for (j = 0; j < 4; j++)
+				average += dev->noisecalc.samples[i][j];
+		}
+		average /= (8 * 4);
+		average *= 125;
+		average += 64;
+		average /= 128;
+		tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+					     0x40C);
+		tmp = (tmp / 128) & 0x1F;
+		if (tmp >= 8)
+			average += 2;
+		else
+			average -= 25;
+		if (tmp == 8)
+			average -= 72;
+		else
+			average -= 48;
+
+		dev->stats.link_noise = average;
+drop_calculation:
+		dev->noisecalc.calculation_running = 0;
+		return;
+	}
+generate_new:
+	b43legacy_generate_noise_sample(dev);
+}
+
+static void handle_irq_tbtt_indication(struct b43legacy_wldev *dev)
+{
+	if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) {
+		/* TODO: PS TBTT */
+	} else {
+		if (1/*FIXME: the last PSpoll frame was sent successfully */)
+			b43legacy_power_saving_ctl_bits(dev, -1, -1);
+	}
+	dev->reg124_set_0x4 = 0;
+	if (b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_IBSS))
+		dev->reg124_set_0x4 = 1;
+}
+
+static void handle_irq_atim_end(struct b43legacy_wldev *dev)
+{
+	if (!dev->reg124_set_0x4) /*FIXME rename this variable*/
+		return;
+	b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+			  b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD)
+			  | 0x4);
+}
+
+static void handle_irq_pmq(struct b43legacy_wldev *dev)
+{
+	u32 tmp;
+
+	/* TODO: AP mode. */
+
+	while (1) {
+		tmp = b43legacy_read32(dev, B43legacy_MMIO_PS_STATUS);
+		if (!(tmp & 0x00000008))
+			break;
+	}
+	/* 16bit write is odd, but correct. */
+	b43legacy_write16(dev, B43legacy_MMIO_PS_STATUS, 0x0002);
+}
+
+static void b43legacy_write_template_common(struct b43legacy_wldev *dev,
+					    const u8 *data, u16 size,
+					    u16 ram_offset,
+					    u16 shm_size_offset, u8 rate)
+{
+	u32 i;
+	u32 tmp;
+	struct b43legacy_plcp_hdr4 plcp;
+
+	plcp.data = 0;
+	b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+	b43legacy_ram_write(dev, ram_offset, le32_to_cpu(plcp.data));
+	ram_offset += sizeof(u32);
+	/* The PLCP is 6 bytes long, but we only wrote 4 bytes, yet.
+	 * So leave the first two bytes of the next write blank.
+	 */
+	tmp = (u32)(data[0]) << 16;
+	tmp |= (u32)(data[1]) << 24;
+	b43legacy_ram_write(dev, ram_offset, tmp);
+	ram_offset += sizeof(u32);
+	for (i = 2; i < size; i += sizeof(u32)) {
+		tmp = (u32)(data[i + 0]);
+		if (i + 1 < size)
+			tmp |= (u32)(data[i + 1]) << 8;
+		if (i + 2 < size)
+			tmp |= (u32)(data[i + 2]) << 16;
+		if (i + 3 < size)
+			tmp |= (u32)(data[i + 3]) << 24;
+		b43legacy_ram_write(dev, ram_offset + i - 2, tmp);
+	}
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_size_offset,
+			      size + sizeof(struct b43legacy_plcp_hdr6));
+}
+
+static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev,
+					    u16 ram_offset,
+					    u16 shm_size_offset, u8 rate)
+{
+	int len;
+	const u8 *data;
+
+	B43legacy_WARN_ON(!dev->cached_beacon);
+	len = min((size_t)dev->cached_beacon->len,
+		  0x200 - sizeof(struct b43legacy_plcp_hdr6));
+	data = (const u8 *)(dev->cached_beacon->data);
+	b43legacy_write_template_common(dev, data,
+					len, ram_offset,
+					shm_size_offset, rate);
+}
+
+static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev,
+					    u16 shm_offset, u16 size,
+					    u8 rate)
+{
+	struct b43legacy_plcp_hdr4 plcp;
+	u32 tmp;
+	__le16 dur;
+
+	plcp.data = 0;
+	b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate);
+	dur = ieee80211_generic_frame_duration(dev->wl->hw,
+					       dev->wl->if_id,
+					       size,
+					       B43legacy_RATE_TO_100KBPS(rate));
+	/* Write PLCP in two parts and timing for packet transfer */
+	tmp = le32_to_cpu(plcp.data);
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset,
+			      tmp & 0xFFFF);
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset + 2,
+			      tmp >> 16);
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset + 6,
+			      le16_to_cpu(dur));
+}
+
+/* Instead of using custom probe response template, this function
+ * just patches custom beacon template by:
+ * 1) Changing packet type
+ * 2) Patching duration field
+ * 3) Stripping TIM
+ */
+static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev,
+					 u16 *dest_size, u8 rate)
+{
+	const u8 *src_data;
+	u8 *dest_data;
+	u16 src_size;
+	u16 elem_size;
+	u16 src_pos;
+	u16 dest_pos;
+	__le16 dur;
+	struct ieee80211_hdr *hdr;
+
+	B43legacy_WARN_ON(!dev->cached_beacon);
+	src_size = dev->cached_beacon->len;
+	src_data = (const u8 *)dev->cached_beacon->data;
+
+	if (unlikely(src_size < 0x24)) {
+		b43legacydbg(dev->wl, "b43legacy_generate_probe_resp: "
+		       "invalid beacon\n");
+		return NULL;
+	}
+
+	dest_data = kmalloc(src_size, GFP_ATOMIC);
+	if (unlikely(!dest_data))
+		return NULL;
+
+	/* 0x24 is offset of first variable-len Information-Element
+	 * in beacon frame.
+	 */
+	memcpy(dest_data, src_data, 0x24);
+	src_pos = 0x24;
+	dest_pos = 0x24;
+	for (; src_pos < src_size - 2; src_pos += elem_size) {
+		elem_size = src_data[src_pos + 1] + 2;
+		if (src_data[src_pos] != 0x05) { /* TIM */
+			memcpy(dest_data + dest_pos, src_data + src_pos,
+			       elem_size);
+			dest_pos += elem_size;
+		}
+	}
+	*dest_size = dest_pos;
+	hdr = (struct ieee80211_hdr *)dest_data;
+
+	/* Set the frame control. */
+	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+					 IEEE80211_STYPE_PROBE_RESP);
+	dur = ieee80211_generic_frame_duration(dev->wl->hw,
+					       dev->wl->if_id,
+					       *dest_size,
+					       B43legacy_RATE_TO_100KBPS(rate));
+	hdr->duration_id = dur;
+
+	return dest_data;
+}
+
+static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev,
+						u16 ram_offset,
+						u16 shm_size_offset, u8 rate)
+{
+	u8 *probe_resp_data;
+	u16 size;
+
+	B43legacy_WARN_ON(!dev->cached_beacon);
+	size = dev->cached_beacon->len;
+	probe_resp_data = b43legacy_generate_probe_resp(dev, &size, rate);
+	if (unlikely(!probe_resp_data))
+		return;
+
+	/* Looks like PLCP headers plus packet timings are stored for
+	 * all possible basic rates
+	 */
+	b43legacy_write_probe_resp_plcp(dev, 0x31A, size,
+					B43legacy_CCK_RATE_1MB);
+	b43legacy_write_probe_resp_plcp(dev, 0x32C, size,
+					B43legacy_CCK_RATE_2MB);
+	b43legacy_write_probe_resp_plcp(dev, 0x33E, size,
+					B43legacy_CCK_RATE_5MB);
+	b43legacy_write_probe_resp_plcp(dev, 0x350, size,
+					B43legacy_CCK_RATE_11MB);
+
+	size = min((size_t)size,
+		   0x200 - sizeof(struct b43legacy_plcp_hdr6));
+	b43legacy_write_template_common(dev, probe_resp_data,
+					size, ram_offset,
+					shm_size_offset, rate);
+	kfree(probe_resp_data);
+}
+
+static int b43legacy_refresh_cached_beacon(struct b43legacy_wldev *dev,
+					   struct sk_buff *beacon)
+{
+	if (dev->cached_beacon)
+		kfree_skb(dev->cached_beacon);
+	dev->cached_beacon = beacon;
+
+	return 0;
+}
+
+static void b43legacy_update_templates(struct b43legacy_wldev *dev)
+{
+	u32 status;
+
+	B43legacy_WARN_ON(!dev->cached_beacon);
+
+	b43legacy_write_beacon_template(dev, 0x68, 0x18,
+					B43legacy_CCK_RATE_1MB);
+	b43legacy_write_beacon_template(dev, 0x468, 0x1A,
+					B43legacy_CCK_RATE_1MB);
+	b43legacy_write_probe_resp_template(dev, 0x268, 0x4A,
+					    B43legacy_CCK_RATE_11MB);
+
+	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD);
+	status |= 0x03;
+	b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD, status);
+}
+
+static void b43legacy_refresh_templates(struct b43legacy_wldev *dev,
+					struct sk_buff *beacon)
+{
+	int err;
+
+	err = b43legacy_refresh_cached_beacon(dev, beacon);
+	if (unlikely(err))
+		return;
+	b43legacy_update_templates(dev);
+}
+
+static void b43legacy_set_ssid(struct b43legacy_wldev *dev,
+			       const u8 *ssid, u8 ssid_len)
+{
+	u32 tmp;
+	u16 i;
+	u16 len;
+
+	len = min((u16)ssid_len, (u16)0x100);
+	for (i = 0; i < len; i += sizeof(u32)) {
+		tmp = (u32)(ssid[i + 0]);
+		if (i + 1 < len)
+			tmp |= (u32)(ssid[i + 1]) << 8;
+		if (i + 2 < len)
+			tmp |= (u32)(ssid[i + 2]) << 16;
+		if (i + 3 < len)
+			tmp |= (u32)(ssid[i + 3]) << 24;
+		b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+				      0x380 + i, tmp);
+	}
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+			      0x48, len);
+}
+
+static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev,
+				     u16 beacon_int)
+{
+	b43legacy_time_lock(dev);
+	if (dev->dev->id.revision >= 3)
+		b43legacy_write32(dev, 0x188, (beacon_int << 16));
+	else {
+		b43legacy_write16(dev, 0x606, (beacon_int >> 6));
+		b43legacy_write16(dev, 0x610, beacon_int);
+	}
+	b43legacy_time_unlock(dev);
+}
+
+static void handle_irq_beacon(struct b43legacy_wldev *dev)
+{
+	u32 status;
+
+	if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+		return;
+
+	dev->irq_savedstate &= ~B43legacy_IRQ_BEACON;
+	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS2_BITFIELD);
+
+	if (!dev->cached_beacon || ((status & 0x1) && (status & 0x2))) {
+		/* ACK beacon IRQ. */
+		b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
+				  B43legacy_IRQ_BEACON);
+		dev->irq_savedstate |= B43legacy_IRQ_BEACON;
+		if (dev->cached_beacon)
+			kfree_skb(dev->cached_beacon);
+		dev->cached_beacon = NULL;
+		return;
+	}
+	if (!(status & 0x1)) {
+		b43legacy_write_beacon_template(dev, 0x68, 0x18,
+						B43legacy_CCK_RATE_1MB);
+		status |= 0x1;
+		b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+				  status);
+	}
+	if (!(status & 0x2)) {
+		b43legacy_write_beacon_template(dev, 0x468, 0x1A,
+						B43legacy_CCK_RATE_1MB);
+		status |= 0x2;
+		b43legacy_write32(dev, B43legacy_MMIO_STATUS2_BITFIELD,
+				  status);
+	}
+}
+
+static void handle_irq_ucode_debug(struct b43legacy_wldev *dev)
+{
+}
+
+/* Interrupt handler bottom-half */
+static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev)
+{
+	u32 reason;
+	u32 dma_reason[ARRAY_SIZE(dev->dma_reason)];
+	u32 merged_dma_reason = 0;
+	int i;
+	int activity = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->wl->irq_lock, flags);
+
+	B43legacy_WARN_ON(b43legacy_status(dev) <
+			  B43legacy_STAT_INITIALIZED);
+
+	reason = dev->irq_reason;
+	for (i = 0; i < ARRAY_SIZE(dma_reason); i++) {
+		dma_reason[i] = dev->dma_reason[i];
+		merged_dma_reason |= dma_reason[i];
+	}
+
+	if (unlikely(reason & B43legacy_IRQ_MAC_TXERR))
+		b43legacyerr(dev->wl, "MAC transmission error\n");
+
+	if (unlikely(reason & B43legacy_IRQ_PHY_TXERR))
+		b43legacyerr(dev->wl, "PHY transmission error\n");
+
+	if (unlikely(merged_dma_reason & (B43legacy_DMAIRQ_FATALMASK |
+					  B43legacy_DMAIRQ_NONFATALMASK))) {
+		if (merged_dma_reason & B43legacy_DMAIRQ_FATALMASK) {
+			b43legacyerr(dev->wl, "Fatal DMA error: "
+			       "0x%08X, 0x%08X, 0x%08X, "
+			       "0x%08X, 0x%08X, 0x%08X\n",
+			       dma_reason[0], dma_reason[1],
+			       dma_reason[2], dma_reason[3],
+			       dma_reason[4], dma_reason[5]);
+			b43legacy_controller_restart(dev, "DMA error");
+			mmiowb();
+			spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+			return;
+		}
+		if (merged_dma_reason & B43legacy_DMAIRQ_NONFATALMASK)
+			b43legacyerr(dev->wl, "DMA error: "
+			       "0x%08X, 0x%08X, 0x%08X, "
+			       "0x%08X, 0x%08X, 0x%08X\n",
+			       dma_reason[0], dma_reason[1],
+			       dma_reason[2], dma_reason[3],
+			       dma_reason[4], dma_reason[5]);
+	}
+
+	if (unlikely(reason & B43legacy_IRQ_UCODE_DEBUG))
+		handle_irq_ucode_debug(dev);
+	if (reason & B43legacy_IRQ_TBTT_INDI)
+		handle_irq_tbtt_indication(dev);
+	if (reason & B43legacy_IRQ_ATIM_END)
+		handle_irq_atim_end(dev);
+	if (reason & B43legacy_IRQ_BEACON)
+		handle_irq_beacon(dev);
+	if (reason & B43legacy_IRQ_PMQ)
+		handle_irq_pmq(dev);
+	if (reason & B43legacy_IRQ_TXFIFO_FLUSH_OK)
+		;/*TODO*/
+	if (reason & B43legacy_IRQ_NOISESAMPLE_OK)
+		handle_irq_noise(dev);
+
+	/* Check the DMA reason registers for received data. */
+	if (dma_reason[0] & B43legacy_DMAIRQ_RX_DONE) {
+		if (b43legacy_using_pio(dev))
+			b43legacy_pio_rx(dev->pio.queue0);
+		else
+			b43legacy_dma_rx(dev->dma.rx_ring0);
+		/* We intentionally don't set "activity" to 1, here. */
+	}
+	B43legacy_WARN_ON(dma_reason[1] & B43legacy_DMAIRQ_RX_DONE);
+	B43legacy_WARN_ON(dma_reason[2] & B43legacy_DMAIRQ_RX_DONE);
+	if (dma_reason[3] & B43legacy_DMAIRQ_RX_DONE) {
+		if (b43legacy_using_pio(dev))
+			b43legacy_pio_rx(dev->pio.queue3);
+		else
+			b43legacy_dma_rx(dev->dma.rx_ring3);
+		activity = 1;
+	}
+	B43legacy_WARN_ON(dma_reason[4] & B43legacy_DMAIRQ_RX_DONE);
+	B43legacy_WARN_ON(dma_reason[5] & B43legacy_DMAIRQ_RX_DONE);
+
+	if (reason & B43legacy_IRQ_TX_OK) {
+		handle_irq_transmit_status(dev);
+		activity = 1;
+		/* TODO: In AP mode, this also causes sending of powersave
+			 responses. */
+	}
+
+	if (!modparam_noleds)
+		b43legacy_leds_update(dev, activity);
+	b43legacy_interrupt_enable(dev, dev->irq_savedstate);
+	mmiowb();
+	spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+}
+
+static void pio_irq_workaround(struct b43legacy_wldev *dev,
+			       u16 base, int queueidx)
+{
+	u16 rxctl;
+
+	rxctl = b43legacy_read16(dev, base + B43legacy_PIO_RXCTL);
+	if (rxctl & B43legacy_PIO_RXCTL_DATAAVAILABLE)
+		dev->dma_reason[queueidx] |= B43legacy_DMAIRQ_RX_DONE;
+	else
+		dev->dma_reason[queueidx] &= ~B43legacy_DMAIRQ_RX_DONE;
+}
+
+static void b43legacy_interrupt_ack(struct b43legacy_wldev *dev, u32 reason)
+{
+	if (b43legacy_using_pio(dev) &&
+	    (dev->dev->id.revision < 3) &&
+	    (!(reason & B43legacy_IRQ_PIO_WORKAROUND))) {
+		/* Apply a PIO specific workaround to the dma_reasons */
+		pio_irq_workaround(dev, B43legacy_MMIO_PIO1_BASE, 0);
+		pio_irq_workaround(dev, B43legacy_MMIO_PIO2_BASE, 1);
+		pio_irq_workaround(dev, B43legacy_MMIO_PIO3_BASE, 2);
+		pio_irq_workaround(dev, B43legacy_MMIO_PIO4_BASE, 3);
+	}
+
+	b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, reason);
+
+	b43legacy_write32(dev, B43legacy_MMIO_DMA0_REASON,
+			  dev->dma_reason[0]);
+	b43legacy_write32(dev, B43legacy_MMIO_DMA1_REASON,
+			  dev->dma_reason[1]);
+	b43legacy_write32(dev, B43legacy_MMIO_DMA2_REASON,
+			  dev->dma_reason[2]);
+	b43legacy_write32(dev, B43legacy_MMIO_DMA3_REASON,
+			  dev->dma_reason[3]);
+	b43legacy_write32(dev, B43legacy_MMIO_DMA4_REASON,
+			  dev->dma_reason[4]);
+	b43legacy_write32(dev, B43legacy_MMIO_DMA5_REASON,
+			  dev->dma_reason[5]);
+}
+
+/* Interrupt handler top-half */
+static irqreturn_t b43legacy_interrupt_handler(int irq, void *dev_id)
+{
+	irqreturn_t ret = IRQ_NONE;
+	struct b43legacy_wldev *dev = dev_id;
+	u32 reason;
+
+	if (!dev)
+		return IRQ_NONE;
+
+	spin_lock(&dev->wl->irq_lock);
+
+	if (b43legacy_status(dev) < B43legacy_STAT_STARTED)
+		goto out;
+	reason = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+	if (reason == 0xffffffff) /* shared IRQ */
+		goto out;
+	ret = IRQ_HANDLED;
+	reason &= b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK);
+	if (!reason)
+		goto out;
+
+	dev->dma_reason[0] = b43legacy_read32(dev,
+					      B43legacy_MMIO_DMA0_REASON)
+					      & 0x0001DC00;
+	dev->dma_reason[1] = b43legacy_read32(dev,
+					      B43legacy_MMIO_DMA1_REASON)
+					      & 0x0000DC00;
+	dev->dma_reason[2] = b43legacy_read32(dev,
+					      B43legacy_MMIO_DMA2_REASON)
+					      & 0x0000DC00;
+	dev->dma_reason[3] = b43legacy_read32(dev,
+					      B43legacy_MMIO_DMA3_REASON)
+					      & 0x0001DC00;
+	dev->dma_reason[4] = b43legacy_read32(dev,
+					      B43legacy_MMIO_DMA4_REASON)
+					      & 0x0000DC00;
+	dev->dma_reason[5] = b43legacy_read32(dev,
+					      B43legacy_MMIO_DMA5_REASON)
+					      & 0x0000DC00;
+
+	b43legacy_interrupt_ack(dev, reason);
+	/* disable all IRQs. They are enabled again in the bottom half. */
+	dev->irq_savedstate = b43legacy_interrupt_disable(dev,
+							  B43legacy_IRQ_ALL);
+	/* save the reason code and call our bottom half. */
+	dev->irq_reason = reason;
+	tasklet_schedule(&dev->isr_tasklet);
+out:
+	mmiowb();
+	spin_unlock(&dev->wl->irq_lock);
+
+	return ret;
+}
+
+static void b43legacy_release_firmware(struct b43legacy_wldev *dev)
+{
+	release_firmware(dev->fw.ucode);
+	dev->fw.ucode = NULL;
+	release_firmware(dev->fw.pcm);
+	dev->fw.pcm = NULL;
+	release_firmware(dev->fw.initvals);
+	dev->fw.initvals = NULL;
+	release_firmware(dev->fw.initvals_band);
+	dev->fw.initvals_band = NULL;
+}
+
+static void b43legacy_print_fw_helptext(struct b43legacy_wl *wl)
+{
+	b43legacyerr(wl, "You must go to http://linuxwireless.org/en/users/"
+		     "Drivers/bcm43xx#devicefirmware "
+		     "and download the correct firmware (version 3).\n");
+}
+
+static int do_request_fw(struct b43legacy_wldev *dev,
+			 const char *name,
+			 const struct firmware **fw)
+{
+	char path[sizeof(modparam_fwpostfix) + 32];
+	struct b43legacy_fw_header *hdr;
+	u32 size;
+	int err;
+
+	if (!name)
+		return 0;
+
+	snprintf(path, ARRAY_SIZE(path),
+		 "b43legacy%s/%s.fw",
+		 modparam_fwpostfix, name);
+	err = request_firmware(fw, path, dev->dev->dev);
+	if (err) {
+		b43legacyerr(dev->wl, "Firmware file \"%s\" not found "
+		       "or load failed.\n", path);
+		return err;
+	}
+	if ((*fw)->size < sizeof(struct b43legacy_fw_header))
+		goto err_format;
+	hdr = (struct b43legacy_fw_header *)((*fw)->data);
+	switch (hdr->type) {
+	case B43legacy_FW_TYPE_UCODE:
+	case B43legacy_FW_TYPE_PCM:
+		size = be32_to_cpu(hdr->size);
+		if (size != (*fw)->size - sizeof(struct b43legacy_fw_header))
+			goto err_format;
+		/* fallthrough */
+	case B43legacy_FW_TYPE_IV:
+		if (hdr->ver != 1)
+			goto err_format;
+		break;
+	default:
+		goto err_format;
+	}
+
+	return err;
+
+err_format:
+	b43legacyerr(dev->wl, "Firmware file \"%s\" format error.\n", path);
+	return -EPROTO;
+}
+
+static int b43legacy_request_firmware(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_firmware *fw = &dev->fw;
+	const u8 rev = dev->dev->id.revision;
+	const char *filename;
+	u32 tmshigh;
+	int err;
+
+	tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
+	if (!fw->ucode) {
+		if (rev == 2)
+			filename = "ucode2";
+		else if (rev == 4)
+			filename = "ucode4";
+		else
+			filename = "ucode5";
+		err = do_request_fw(dev, filename, &fw->ucode);
+		if (err)
+			goto err_load;
+	}
+	if (!fw->pcm) {
+		if (rev < 5)
+			filename = "pcm4";
+		else
+			filename = "pcm5";
+		err = do_request_fw(dev, filename, &fw->pcm);
+		if (err)
+			goto err_load;
+	}
+	if (!fw->initvals) {
+		switch (dev->phy.type) {
+		case B43legacy_PHYTYPE_G:
+			if ((rev >= 5) && (rev <= 10))
+				filename = "b0g0initvals5";
+			else if (rev == 2 || rev == 4)
+				filename = "b0g0initvals2";
+			else
+				goto err_no_initvals;
+			break;
+		default:
+			goto err_no_initvals;
+		}
+		err = do_request_fw(dev, filename, &fw->initvals);
+		if (err)
+			goto err_load;
+	}
+	if (!fw->initvals_band) {
+		switch (dev->phy.type) {
+		case B43legacy_PHYTYPE_G:
+			if ((rev >= 5) && (rev <= 10))
+				filename = "b0g0bsinitvals5";
+			else if (rev >= 11)
+				filename = NULL;
+			else if (rev == 2 || rev == 4)
+				filename = NULL;
+			else
+				goto err_no_initvals;
+			break;
+		default:
+			goto err_no_initvals;
+		}
+		err = do_request_fw(dev, filename, &fw->initvals_band);
+		if (err)
+			goto err_load;
+	}
+
+	return 0;
+
+err_load:
+	b43legacy_print_fw_helptext(dev->wl);
+	goto error;
+
+err_no_initvals:
+	err = -ENODEV;
+	b43legacyerr(dev->wl, "No Initial Values firmware file for PHY %u, "
+	       "core rev %u\n", dev->phy.type, rev);
+	goto error;
+
+error:
+	b43legacy_release_firmware(dev);
+	return err;
+}
+
+static int b43legacy_upload_microcode(struct b43legacy_wldev *dev)
+{
+	const size_t hdr_len = sizeof(struct b43legacy_fw_header);
+	const __be32 *data;
+	unsigned int i;
+	unsigned int len;
+	u16 fwrev;
+	u16 fwpatch;
+	u16 fwdate;
+	u16 fwtime;
+	u32 tmp;
+	int err = 0;
+
+	/* Upload Microcode. */
+	data = (__be32 *) (dev->fw.ucode->data + hdr_len);
+	len = (dev->fw.ucode->size - hdr_len) / sizeof(__be32);
+	b43legacy_shm_control_word(dev,
+				   B43legacy_SHM_UCODE |
+				   B43legacy_SHM_AUTOINC_W,
+				   0x0000);
+	for (i = 0; i < len; i++) {
+		b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA,
+				    be32_to_cpu(data[i]));
+		udelay(10);
+	}
+
+	if (dev->fw.pcm) {
+		/* Upload PCM data. */
+		data = (__be32 *) (dev->fw.pcm->data + hdr_len);
+		len = (dev->fw.pcm->size - hdr_len) / sizeof(__be32);
+		b43legacy_shm_control_word(dev, B43legacy_SHM_HW, 0x01EA);
+		b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA, 0x00004000);
+		/* No need for autoinc bit in SHM_HW */
+		b43legacy_shm_control_word(dev, B43legacy_SHM_HW, 0x01EB);
+		for (i = 0; i < len; i++) {
+			b43legacy_write32(dev, B43legacy_MMIO_SHM_DATA,
+					  be32_to_cpu(data[i]));
+			udelay(10);
+		}
+	}
+
+	b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
+			  B43legacy_IRQ_ALL);
+	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0x00020402);
+
+	/* Wait for the microcode to load and respond */
+	i = 0;
+	while (1) {
+		tmp = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+		if (tmp == B43legacy_IRQ_MAC_SUSPENDED)
+			break;
+		i++;
+		if (i >= B43legacy_IRQWAIT_MAX_RETRIES) {
+			b43legacyerr(dev->wl, "Microcode not responding\n");
+			b43legacy_print_fw_helptext(dev->wl);
+			err = -ENODEV;
+			goto out;
+		}
+		udelay(10);
+	}
+	/* dummy read follows */
+	b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+
+	/* Get and check the revisions. */
+	fwrev = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+				     B43legacy_SHM_SH_UCODEREV);
+	fwpatch = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+				       B43legacy_SHM_SH_UCODEPATCH);
+	fwdate = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+				      B43legacy_SHM_SH_UCODEDATE);
+	fwtime = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+				      B43legacy_SHM_SH_UCODETIME);
+
+	if (fwrev > 0x128) {
+		b43legacyerr(dev->wl, "YOU ARE TRYING TO LOAD V4 FIRMWARE."
+			     " Only firmware from binary drivers version 3.x"
+			     " is supported. You must change your firmware"
+			     " files.\n");
+		b43legacy_print_fw_helptext(dev->wl);
+		b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, 0);
+		err = -EOPNOTSUPP;
+		goto out;
+	}
+	b43legacydbg(dev->wl, "Loading firmware version 0x%X, patch level %u "
+	       "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch,
+	       (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF,
+	       (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F);
+
+	dev->fw.rev = fwrev;
+	dev->fw.patch = fwpatch;
+
+out:
+	return err;
+}
+
+static int b43legacy_write_initvals(struct b43legacy_wldev *dev,
+				    const struct b43legacy_iv *ivals,
+				    size_t count,
+				    size_t array_size)
+{
+	const struct b43legacy_iv *iv;
+	u16 offset;
+	size_t i;
+	bool bit32;
+
+	BUILD_BUG_ON(sizeof(struct b43legacy_iv) != 6);
+	iv = ivals;
+	for (i = 0; i < count; i++) {
+		if (array_size < sizeof(iv->offset_size))
+			goto err_format;
+		array_size -= sizeof(iv->offset_size);
+		offset = be16_to_cpu(iv->offset_size);
+		bit32 = !!(offset & B43legacy_IV_32BIT);
+		offset &= B43legacy_IV_OFFSET_MASK;
+		if (offset >= 0x1000)
+			goto err_format;
+		if (bit32) {
+			u32 value;
+
+			if (array_size < sizeof(iv->data.d32))
+				goto err_format;
+			array_size -= sizeof(iv->data.d32);
+
+			value = be32_to_cpu(get_unaligned(&iv->data.d32));
+			b43legacy_write32(dev, offset, value);
+
+			iv = (const struct b43legacy_iv *)((const uint8_t *)iv +
+							sizeof(__be16) +
+							sizeof(__be32));
+		} else {
+			u16 value;
+
+			if (array_size < sizeof(iv->data.d16))
+				goto err_format;
+			array_size -= sizeof(iv->data.d16);
+
+			value = be16_to_cpu(iv->data.d16);
+			b43legacy_write16(dev, offset, value);
+
+			iv = (const struct b43legacy_iv *)((const uint8_t *)iv +
+							sizeof(__be16) +
+							sizeof(__be16));
+		}
+	}
+	if (array_size)
+		goto err_format;
+
+	return 0;
+
+err_format:
+	b43legacyerr(dev->wl, "Initial Values Firmware file-format error.\n");
+	b43legacy_print_fw_helptext(dev->wl);
+
+	return -EPROTO;
+}
+
+static int b43legacy_upload_initvals(struct b43legacy_wldev *dev)
+{
+	const size_t hdr_len = sizeof(struct b43legacy_fw_header);
+	const struct b43legacy_fw_header *hdr;
+	struct b43legacy_firmware *fw = &dev->fw;
+	const struct b43legacy_iv *ivals;
+	size_t count;
+	int err;
+
+	hdr = (const struct b43legacy_fw_header *)(fw->initvals->data);
+	ivals = (const struct b43legacy_iv *)(fw->initvals->data + hdr_len);
+	count = be32_to_cpu(hdr->size);
+	err = b43legacy_write_initvals(dev, ivals, count,
+				 fw->initvals->size - hdr_len);
+	if (err)
+		goto out;
+	if (fw->initvals_band) {
+		hdr = (const struct b43legacy_fw_header *)
+		      (fw->initvals_band->data);
+		ivals = (const struct b43legacy_iv *)(fw->initvals_band->data
+			+ hdr_len);
+		count = be32_to_cpu(hdr->size);
+		err = b43legacy_write_initvals(dev, ivals, count,
+					 fw->initvals_band->size - hdr_len);
+		if (err)
+			goto out;
+	}
+out:
+
+	return err;
+}
+
+/* Initialize the GPIOs
+ * http://bcm-specs.sipsolutions.net/GPIO
+ */
+static int b43legacy_gpio_init(struct b43legacy_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+	struct ssb_device *gpiodev, *pcidev = NULL;
+	u32 mask;
+	u32 set;
+
+	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+			  b43legacy_read32(dev,
+			  B43legacy_MMIO_STATUS_BITFIELD)
+			  & 0xFFFF3FFF);
+
+	b43legacy_leds_switch_all(dev, 0);
+	b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK,
+			  b43legacy_read16(dev,
+			  B43legacy_MMIO_GPIO_MASK)
+			  | 0x000F);
+
+	mask = 0x0000001F;
+	set = 0x0000000F;
+	if (dev->dev->bus->chip_id == 0x4301) {
+		mask |= 0x0060;
+		set |= 0x0060;
+	}
+	if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL) {
+		b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK,
+				  b43legacy_read16(dev,
+				  B43legacy_MMIO_GPIO_MASK)
+				  | 0x0200);
+		mask |= 0x0200;
+		set |= 0x0200;
+	}
+	if (dev->dev->id.revision >= 2)
+		mask  |= 0x0010; /* FIXME: This is redundant. */
+
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+	pcidev = bus->pcicore.dev;
+#endif
+	gpiodev = bus->chipco.dev ? : pcidev;
+	if (!gpiodev)
+		return 0;
+	ssb_write32(gpiodev, B43legacy_GPIO_CONTROL,
+		    (ssb_read32(gpiodev, B43legacy_GPIO_CONTROL)
+		     & mask) | set);
+
+	return 0;
+}
+
+/* Turn off all GPIO stuff. Call this on module unload, for example. */
+static void b43legacy_gpio_cleanup(struct b43legacy_wldev *dev)
+{
+	struct ssb_bus *bus = dev->dev->bus;
+	struct ssb_device *gpiodev, *pcidev = NULL;
+
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+	pcidev = bus->pcicore.dev;
+#endif
+	gpiodev = bus->chipco.dev ? : pcidev;
+	if (!gpiodev)
+		return;
+	ssb_write32(gpiodev, B43legacy_GPIO_CONTROL, 0);
+}
+
+/* http://bcm-specs.sipsolutions.net/EnableMac */
+void b43legacy_mac_enable(struct b43legacy_wldev *dev)
+{
+	dev->mac_suspended--;
+	B43legacy_WARN_ON(dev->mac_suspended < 0);
+	if (dev->mac_suspended == 0) {
+		b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+				  b43legacy_read32(dev,
+				  B43legacy_MMIO_STATUS_BITFIELD)
+				  | B43legacy_SBF_MAC_ENABLED);
+		b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON,
+				  B43legacy_IRQ_MAC_SUSPENDED);
+		/* the next two are dummy reads */
+		b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+		b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+		b43legacy_power_saving_ctl_bits(dev, -1, -1);
+	}
+}
+
+/* http://bcm-specs.sipsolutions.net/SuspendMAC */
+void b43legacy_mac_suspend(struct b43legacy_wldev *dev)
+{
+	int i;
+	u32 tmp;
+
+	B43legacy_WARN_ON(dev->mac_suspended < 0);
+	if (dev->mac_suspended == 0) {
+		b43legacy_power_saving_ctl_bits(dev, -1, 1);
+		b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+				  b43legacy_read32(dev,
+				  B43legacy_MMIO_STATUS_BITFIELD)
+				  & ~B43legacy_SBF_MAC_ENABLED);
+		b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+		for (i = 10000; i; i--) {
+			tmp = b43legacy_read32(dev,
+					       B43legacy_MMIO_GEN_IRQ_REASON);
+			if (tmp & B43legacy_IRQ_MAC_SUSPENDED)
+				goto out;
+			udelay(1);
+		}
+		b43legacyerr(dev->wl, "MAC suspend failed\n");
+	}
+out:
+	dev->mac_suspended++;
+}
+
+static void b43legacy_adjust_opmode(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_wl *wl = dev->wl;
+	u32 ctl;
+	u16 cfp_pretbtt;
+
+	ctl = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+	/* Reset status to STA infrastructure mode. */
+	ctl &= ~B43legacy_MACCTL_AP;
+	ctl &= ~B43legacy_MACCTL_KEEP_CTL;
+	ctl &= ~B43legacy_MACCTL_KEEP_BADPLCP;
+	ctl &= ~B43legacy_MACCTL_KEEP_BAD;
+	ctl &= ~B43legacy_MACCTL_PROMISC;
+	ctl &= ~B43legacy_MACCTL_BEACPROMISC;
+	ctl |= B43legacy_MACCTL_INFRA;
+
+	if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP))
+		ctl |= B43legacy_MACCTL_AP;
+	else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
+		ctl &= ~B43legacy_MACCTL_INFRA;
+
+	if (wl->filter_flags & FIF_CONTROL)
+		ctl |= B43legacy_MACCTL_KEEP_CTL;
+	if (wl->filter_flags & FIF_FCSFAIL)
+		ctl |= B43legacy_MACCTL_KEEP_BAD;
+	if (wl->filter_flags & FIF_PLCPFAIL)
+		ctl |= B43legacy_MACCTL_KEEP_BADPLCP;
+	if (wl->filter_flags & FIF_PROMISC_IN_BSS)
+		ctl |= B43legacy_MACCTL_PROMISC;
+	if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
+		ctl |= B43legacy_MACCTL_BEACPROMISC;
+
+	/* Workaround: On old hardware the HW-MAC-address-filter
+	 * doesn't work properly, so always run promisc in filter
+	 * it in software. */
+	if (dev->dev->id.revision <= 4)
+		ctl |= B43legacy_MACCTL_PROMISC;
+
+	b43legacy_write32(dev, B43legacy_MMIO_MACCTL, ctl);
+
+	cfp_pretbtt = 2;
+	if ((ctl & B43legacy_MACCTL_INFRA) &&
+	    !(ctl & B43legacy_MACCTL_AP)) {
+		if (dev->dev->bus->chip_id == 0x4306 &&
+		    dev->dev->bus->chip_rev == 3)
+			cfp_pretbtt = 100;
+		else
+			cfp_pretbtt = 50;
+	}
+	b43legacy_write16(dev, 0x612, cfp_pretbtt);
+}
+
+static void b43legacy_rate_memory_write(struct b43legacy_wldev *dev,
+					u16 rate,
+					int is_ofdm)
+{
+	u16 offset;
+
+	if (is_ofdm) {
+		offset = 0x480;
+		offset += (b43legacy_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2;
+	} else {
+		offset = 0x4C0;
+		offset += (b43legacy_plcp_get_ratecode_cck(rate) & 0x000F) * 2;
+	}
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, offset + 0x20,
+			      b43legacy_shm_read16(dev,
+			      B43legacy_SHM_SHARED, offset));
+}
+
+static void b43legacy_rate_memory_init(struct b43legacy_wldev *dev)
+{
+	switch (dev->phy.type) {
+	case B43legacy_PHYTYPE_G:
+		b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_6MB, 1);
+		b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_12MB, 1);
+		b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_18MB, 1);
+		b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_24MB, 1);
+		b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_36MB, 1);
+		b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_48MB, 1);
+		b43legacy_rate_memory_write(dev, B43legacy_OFDM_RATE_54MB, 1);
+		/* fallthrough */
+	case B43legacy_PHYTYPE_B:
+		b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_1MB, 0);
+		b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_2MB, 0);
+		b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_5MB, 0);
+		b43legacy_rate_memory_write(dev, B43legacy_CCK_RATE_11MB, 0);
+		break;
+	default:
+		B43legacy_BUG_ON(1);
+	}
+}
+
+/* Set the TX-Antenna for management frames sent by firmware. */
+static void b43legacy_mgmtframe_txantenna(struct b43legacy_wldev *dev,
+					  int antenna)
+{
+	u16 ant = 0;
+	u16 tmp;
+
+	switch (antenna) {
+	case B43legacy_ANTENNA0:
+		ant |= B43legacy_TX4_PHY_ANT0;
+		break;
+	case B43legacy_ANTENNA1:
+		ant |= B43legacy_TX4_PHY_ANT1;
+		break;
+	case B43legacy_ANTENNA_AUTO:
+		ant |= B43legacy_TX4_PHY_ANTLAST;
+		break;
+	default:
+		B43legacy_BUG_ON(1);
+	}
+
+	/* FIXME We also need to set the other flags of the PHY control
+	 * field somewhere. */
+
+	/* For Beacons */
+	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+				   B43legacy_SHM_SH_BEACPHYCTL);
+	tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant;
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+			      B43legacy_SHM_SH_BEACPHYCTL, tmp);
+	/* For ACK/CTS */
+	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+				   B43legacy_SHM_SH_ACKCTSPHYCTL);
+	tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant;
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+			      B43legacy_SHM_SH_ACKCTSPHYCTL, tmp);
+	/* For Probe Resposes */
+	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+				   B43legacy_SHM_SH_PRPHYCTL);
+	tmp = (tmp & ~B43legacy_TX4_PHY_ANT) | ant;
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+			      B43legacy_SHM_SH_PRPHYCTL, tmp);
+}
+
+/* Returns TRUE, if the radio is enabled in hardware. */
+static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
+{
+	if (dev->phy.rev >= 3) {
+		if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI)
+		      & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK))
+			return 1;
+	} else {
+		if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO)
+		    & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK)
+			return 1;
+	}
+	return 0;
+}
+
+/* This is the opposite of b43legacy_chip_init() */
+static void b43legacy_chip_exit(struct b43legacy_wldev *dev)
+{
+	b43legacy_radio_turn_off(dev);
+	if (!modparam_noleds)
+		b43legacy_leds_exit(dev);
+	b43legacy_gpio_cleanup(dev);
+	/* firmware is released later */
+}
+
+/* Initialize the chip
+ * http://bcm-specs.sipsolutions.net/ChipInit
+ */
+static int b43legacy_chip_init(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	int err;
+	int tmp;
+	u32 value32;
+	u16 value16;
+
+	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD,
+			  B43legacy_SBF_CORE_READY
+			  | B43legacy_SBF_400);
+
+	err = b43legacy_request_firmware(dev);
+	if (err)
+		goto out;
+	err = b43legacy_upload_microcode(dev);
+	if (err)
+		goto out; /* firmware is released later */
+
+	err = b43legacy_gpio_init(dev);
+	if (err)
+		goto out; /* firmware is released later */
+	err = b43legacy_upload_initvals(dev);
+	if (err)
+		goto err_gpio_cleanup;
+	b43legacy_radio_turn_on(dev);
+
+	b43legacy_write16(dev, 0x03E6, 0x0000);
+	err = b43legacy_phy_init(dev);
+	if (err)
+		goto err_radio_off;
+
+	/* Select initial Interference Mitigation. */
+	tmp = phy->interfmode;
+	phy->interfmode = B43legacy_INTERFMODE_NONE;
+	b43legacy_radio_set_interference_mitigation(dev, tmp);
+
+	b43legacy_phy_set_antenna_diversity(dev);
+	b43legacy_mgmtframe_txantenna(dev, B43legacy_ANTENNA_DEFAULT);
+
+	if (phy->type == B43legacy_PHYTYPE_B) {
+		value16 = b43legacy_read16(dev, 0x005E);
+		value16 |= 0x0004;
+		b43legacy_write16(dev, 0x005E, value16);
+	}
+	b43legacy_write32(dev, 0x0100, 0x01000000);
+	if (dev->dev->id.revision < 5)
+		b43legacy_write32(dev, 0x010C, 0x01000000);
+
+	value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+	value32 &= ~B43legacy_SBF_MODE_NOTADHOC;
+	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
+	value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+	value32 |= B43legacy_SBF_MODE_NOTADHOC;
+	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
+
+	if (b43legacy_using_pio(dev)) {
+		b43legacy_write32(dev, 0x0210, 0x00000100);
+		b43legacy_write32(dev, 0x0230, 0x00000100);
+		b43legacy_write32(dev, 0x0250, 0x00000100);
+		b43legacy_write32(dev, 0x0270, 0x00000100);
+		b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0034,
+				      0x0000);
+	}
+
+	/* Probe Response Timeout value */
+	/* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0074, 0x0000);
+
+	/* Initially set the wireless operation mode. */
+	b43legacy_adjust_opmode(dev);
+
+	if (dev->dev->id.revision < 3) {
+		b43legacy_write16(dev, 0x060E, 0x0000);
+		b43legacy_write16(dev, 0x0610, 0x8000);
+		b43legacy_write16(dev, 0x0604, 0x0000);
+		b43legacy_write16(dev, 0x0606, 0x0200);
+	} else {
+		b43legacy_write32(dev, 0x0188, 0x80000000);
+		b43legacy_write32(dev, 0x018C, 0x02000000);
+	}
+	b43legacy_write32(dev, B43legacy_MMIO_GEN_IRQ_REASON, 0x00004000);
+	b43legacy_write32(dev, B43legacy_MMIO_DMA0_IRQ_MASK, 0x0001DC00);
+	b43legacy_write32(dev, B43legacy_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
+	b43legacy_write32(dev, B43legacy_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
+	b43legacy_write32(dev, B43legacy_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
+	b43legacy_write32(dev, B43legacy_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
+	b43legacy_write32(dev, B43legacy_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
+
+	value32 = ssb_read32(dev->dev, SSB_TMSLOW);
+	value32 |= 0x00100000;
+	ssb_write32(dev->dev, SSB_TMSLOW, value32);
+
+	b43legacy_write16(dev, B43legacy_MMIO_POWERUP_DELAY,
+			  dev->dev->bus->chipco.fast_pwrup_delay);
+
+	B43legacy_WARN_ON(err != 0);
+	b43legacydbg(dev->wl, "Chip initialized\n");
+out:
+	return err;
+
+err_radio_off:
+	b43legacy_radio_turn_off(dev);
+err_gpio_cleanup:
+	b43legacy_gpio_cleanup(dev);
+	goto out;
+}
+
+static void b43legacy_periodic_every120sec(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+
+	if (phy->type != B43legacy_PHYTYPE_G || phy->rev < 2)
+		return;
+
+	b43legacy_mac_suspend(dev);
+	b43legacy_phy_lo_g_measure(dev);
+	b43legacy_mac_enable(dev);
+}
+
+static void b43legacy_periodic_every60sec(struct b43legacy_wldev *dev)
+{
+	b43legacy_phy_lo_mark_all_unused(dev);
+	if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) {
+		b43legacy_mac_suspend(dev);
+		b43legacy_calc_nrssi_slope(dev);
+		b43legacy_mac_enable(dev);
+	}
+}
+
+static void b43legacy_periodic_every30sec(struct b43legacy_wldev *dev)
+{
+	/* Update device statistics. */
+	b43legacy_calculate_link_quality(dev);
+}
+
+static void b43legacy_periodic_every15sec(struct b43legacy_wldev *dev)
+{
+	b43legacy_phy_xmitpower(dev); /* FIXME: unless scanning? */
+}
+
+static void b43legacy_periodic_every1sec(struct b43legacy_wldev *dev)
+{
+	bool radio_hw_enable;
+
+	/* check if radio hardware enabled status changed */
+	radio_hw_enable = b43legacy_is_hw_radio_enabled(dev);
+	if (unlikely(dev->radio_hw_enable != radio_hw_enable)) {
+		dev->radio_hw_enable = radio_hw_enable;
+		b43legacyinfo(dev->wl, "Radio hardware status changed to %s\n",
+		       (radio_hw_enable) ? "enabled" : "disabled");
+		b43legacy_leds_update(dev, 0);
+	}
+}
+
+static void do_periodic_work(struct b43legacy_wldev *dev)
+{
+	unsigned int state;
+
+	state = dev->periodic_state;
+	if (state % 120 == 0)
+		b43legacy_periodic_every120sec(dev);
+	if (state % 60 == 0)
+		b43legacy_periodic_every60sec(dev);
+	if (state % 30 == 0)
+		b43legacy_periodic_every30sec(dev);
+	if (state % 15 == 0)
+		b43legacy_periodic_every15sec(dev);
+	b43legacy_periodic_every1sec(dev);
+}
+
+/* Estimate a "Badness" value based on the periodic work
+ * state-machine state. "Badness" is worse (bigger), if the
+ * periodic work will take longer.
+ */
+static int estimate_periodic_work_badness(unsigned int state)
+{
+	int badness = 0;
+
+	if (state % 120 == 0) /* every 120 sec */
+		badness += 10;
+	if (state % 60 == 0) /* every 60 sec */
+		badness += 5;
+	if (state % 30 == 0) /* every 30 sec */
+		badness += 1;
+	if (state % 15 == 0) /* every 15 sec */
+		badness += 1;
+
+#define BADNESS_LIMIT	4
+	return badness;
+}
+
+static void b43legacy_periodic_work_handler(struct work_struct *work)
+{
+	struct b43legacy_wldev *dev =
+			     container_of(work, struct b43legacy_wldev,
+			     periodic_work.work);
+	unsigned long flags;
+	unsigned long delay;
+	u32 savedirqs = 0;
+	int badness;
+
+	mutex_lock(&dev->wl->mutex);
+
+	if (unlikely(b43legacy_status(dev) != B43legacy_STAT_STARTED))
+		goto out;
+	if (b43legacy_debug(dev, B43legacy_DBG_PWORK_STOP))
+		goto out_requeue;
+
+	badness = estimate_periodic_work_badness(dev->periodic_state);
+	if (badness > BADNESS_LIMIT) {
+		spin_lock_irqsave(&dev->wl->irq_lock, flags);
+		/* Suspend TX as we don't want to transmit packets while
+		 * we recalibrate the hardware. */
+		b43legacy_tx_suspend(dev);
+		savedirqs = b43legacy_interrupt_disable(dev,
+							  B43legacy_IRQ_ALL);
+		/* Periodic work will take a long time, so we want it to
+		 * be preemtible and release the spinlock. */
+		spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+		b43legacy_synchronize_irq(dev);
+
+		do_periodic_work(dev);
+
+		spin_lock_irqsave(&dev->wl->irq_lock, flags);
+		b43legacy_interrupt_enable(dev, savedirqs);
+		b43legacy_tx_resume(dev);
+		mmiowb();
+		spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+	} else {
+		/* Take the global driver lock. This will lock any operation. */
+		spin_lock_irqsave(&dev->wl->irq_lock, flags);
+
+		do_periodic_work(dev);
+
+		mmiowb();
+		spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+	}
+	dev->periodic_state++;
+out_requeue:
+	if (b43legacy_debug(dev, B43legacy_DBG_PWORK_FAST))
+		delay = msecs_to_jiffies(50);
+	else
+		delay = round_jiffies(HZ);
+	queue_delayed_work(dev->wl->hw->workqueue,
+			   &dev->periodic_work, delay);
+out:
+	mutex_unlock(&dev->wl->mutex);
+}
+
+static void b43legacy_periodic_tasks_setup(struct b43legacy_wldev *dev)
+{
+	struct delayed_work *work = &dev->periodic_work;
+
+	dev->periodic_state = 0;
+	INIT_DELAYED_WORK(work, b43legacy_periodic_work_handler);
+	queue_delayed_work(dev->wl->hw->workqueue, work, 0);
+}
+
+/* Validate access to the chip (SHM) */
+static int b43legacy_validate_chipaccess(struct b43legacy_wldev *dev)
+{
+	u32 value;
+	u32 shm_backup;
+
+	shm_backup = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0);
+	b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, 0xAA5555AA);
+	if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0) !=
+				 0xAA5555AA)
+		goto error;
+	b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, 0x55AAAA55);
+	if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED, 0) !=
+				 0x55AAAA55)
+		goto error;
+	b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, 0, shm_backup);
+
+	value = b43legacy_read32(dev, B43legacy_MMIO_MACCTL);
+	if ((value | B43legacy_MACCTL_GMODE) !=
+	    (B43legacy_MACCTL_GMODE | B43legacy_MACCTL_IHR_ENABLED))
+		goto error;
+
+	value = b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_REASON);
+	if (value)
+		goto error;
+
+	return 0;
+error:
+	b43legacyerr(dev->wl, "Failed to validate the chipaccess\n");
+	return -ENODEV;
+}
+
+static void b43legacy_security_init(struct b43legacy_wldev *dev)
+{
+	dev->max_nr_keys = (dev->dev->id.revision >= 5) ? 58 : 20;
+	B43legacy_WARN_ON(dev->max_nr_keys > ARRAY_SIZE(dev->key));
+	dev->ktp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+					0x0056);
+	/* KTP is a word address, but we address SHM bytewise.
+	 * So multiply by two.
+	 */
+	dev->ktp *= 2;
+	if (dev->dev->id.revision >= 5)
+		/* Number of RCMTA address slots */
+		b43legacy_write16(dev, B43legacy_MMIO_RCMTA_COUNT,
+				  dev->max_nr_keys - 8);
+}
+
+static int b43legacy_rng_read(struct hwrng *rng, u32 *data)
+{
+	struct b43legacy_wl *wl = (struct b43legacy_wl *)rng->priv;
+	unsigned long flags;
+
+	/* Don't take wl->mutex here, as it could deadlock with
+	 * hwrng internal locking. It's not needed to take
+	 * wl->mutex here, anyway. */
+
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	*data = b43legacy_read16(wl->current_dev, B43legacy_MMIO_RNG);
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+	return (sizeof(u16));
+}
+
+static void b43legacy_rng_exit(struct b43legacy_wl *wl)
+{
+	if (wl->rng_initialized)
+		hwrng_unregister(&wl->rng);
+}
+
+static int b43legacy_rng_init(struct b43legacy_wl *wl)
+{
+	int err;
+
+	snprintf(wl->rng_name, ARRAY_SIZE(wl->rng_name),
+		 "%s_%s", KBUILD_MODNAME, wiphy_name(wl->hw->wiphy));
+	wl->rng.name = wl->rng_name;
+	wl->rng.data_read = b43legacy_rng_read;
+	wl->rng.priv = (unsigned long)wl;
+	wl->rng_initialized = 1;
+	err = hwrng_register(&wl->rng);
+	if (err) {
+		wl->rng_initialized = 0;
+		b43legacyerr(wl, "Failed to register the random "
+		       "number generator (%d)\n", err);
+	}
+
+	return err;
+}
+
+static int b43legacy_tx(struct ieee80211_hw *hw,
+			struct sk_buff *skb,
+			struct ieee80211_tx_control *ctl)
+{
+	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+	struct b43legacy_wldev *dev = wl->current_dev;
+	int err = -ENODEV;
+	unsigned long flags;
+
+	if (unlikely(!dev))
+		goto out;
+	if (unlikely(b43legacy_status(dev) < B43legacy_STAT_STARTED))
+		goto out;
+	/* DMA-TX is done without a global lock. */
+	if (b43legacy_using_pio(dev)) {
+		spin_lock_irqsave(&wl->irq_lock, flags);
+		err = b43legacy_pio_tx(dev, skb, ctl);
+		spin_unlock_irqrestore(&wl->irq_lock, flags);
+	} else
+		err = b43legacy_dma_tx(dev, skb, ctl);
+out:
+	if (unlikely(err))
+		return NETDEV_TX_BUSY;
+	return NETDEV_TX_OK;
+}
+
+static int b43legacy_conf_tx(struct ieee80211_hw *hw,
+			     int queue,
+			     const struct ieee80211_tx_queue_params *params)
+{
+	return 0;
+}
+
+static int b43legacy_get_tx_stats(struct ieee80211_hw *hw,
+				  struct ieee80211_tx_queue_stats *stats)
+{
+	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+	struct b43legacy_wldev *dev = wl->current_dev;
+	unsigned long flags;
+	int err = -ENODEV;
+
+	if (!dev)
+		goto out;
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	if (likely(b43legacy_status(dev) >= B43legacy_STAT_STARTED)) {
+		if (b43legacy_using_pio(dev))
+			b43legacy_pio_get_tx_stats(dev, stats);
+		else
+			b43legacy_dma_get_tx_stats(dev, stats);
+		err = 0;
+	}
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+out:
+	return err;
+}
+
+static int b43legacy_get_stats(struct ieee80211_hw *hw,
+			       struct ieee80211_low_level_stats *stats)
+{
+	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+	unsigned long flags;
+
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	memcpy(stats, &wl->ieee_stats, sizeof(*stats));
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+	return 0;
+}
+
+static const char *phymode_to_string(unsigned int phymode)
+{
+	switch (phymode) {
+	case B43legacy_PHYMODE_B:
+		return "B";
+	case B43legacy_PHYMODE_G:
+		return "G";
+	default:
+		B43legacy_BUG_ON(1);
+	}
+	return "";
+}
+
+static int find_wldev_for_phymode(struct b43legacy_wl *wl,
+				  unsigned int phymode,
+				  struct b43legacy_wldev **dev,
+				  bool *gmode)
+{
+	struct b43legacy_wldev *d;
+
+	list_for_each_entry(d, &wl->devlist, list) {
+		if (d->phy.possible_phymodes & phymode) {
+			/* Ok, this device supports the PHY-mode.
+			 * Set the gmode bit. */
+			*gmode = 1;
+			*dev = d;
+
+			return 0;
+		}
+	}
+
+	return -ESRCH;
+}
+
+static void b43legacy_put_phy_into_reset(struct b43legacy_wldev *dev)
+{
+	struct ssb_device *sdev = dev->dev;
+	u32 tmslow;
+
+	tmslow = ssb_read32(sdev, SSB_TMSLOW);
+	tmslow &= ~B43legacy_TMSLOW_GMODE;
+	tmslow |= B43legacy_TMSLOW_PHYRESET;
+	tmslow |= SSB_TMSLOW_FGC;
+	ssb_write32(sdev, SSB_TMSLOW, tmslow);
+	msleep(1);
+
+	tmslow = ssb_read32(sdev, SSB_TMSLOW);
+	tmslow &= ~SSB_TMSLOW_FGC;
+	tmslow |= B43legacy_TMSLOW_PHYRESET;
+	ssb_write32(sdev, SSB_TMSLOW, tmslow);
+	msleep(1);
+}
+
+/* Expects wl->mutex locked */
+static int b43legacy_switch_phymode(struct b43legacy_wl *wl,
+				      unsigned int new_mode)
+{
+	struct b43legacy_wldev *up_dev;
+	struct b43legacy_wldev *down_dev;
+	int err;
+	bool gmode = 0;
+	int prev_status;
+
+	err = find_wldev_for_phymode(wl, new_mode, &up_dev, &gmode);
+	if (err) {
+		b43legacyerr(wl, "Could not find a device for %s-PHY mode\n",
+		       phymode_to_string(new_mode));
+		return err;
+	}
+	if ((up_dev == wl->current_dev) &&
+	    (!!wl->current_dev->phy.gmode == !!gmode))
+		/* This device is already running. */
+		return 0;
+	b43legacydbg(wl, "Reconfiguring PHYmode to %s-PHY\n",
+	       phymode_to_string(new_mode));
+	down_dev = wl->current_dev;
+
+	prev_status = b43legacy_status(down_dev);
+	/* Shutdown the currently running core. */
+	if (prev_status >= B43legacy_STAT_STARTED)
+		b43legacy_wireless_core_stop(down_dev);
+	if (prev_status >= B43legacy_STAT_INITIALIZED)
+		b43legacy_wireless_core_exit(down_dev);
+
+	if (down_dev != up_dev)
+		/* We switch to a different core, so we put PHY into
+		 * RESET on the old core. */
+		b43legacy_put_phy_into_reset(down_dev);
+
+	/* Now start the new core. */
+	up_dev->phy.gmode = gmode;
+	if (prev_status >= B43legacy_STAT_INITIALIZED) {
+		err = b43legacy_wireless_core_init(up_dev);
+		if (err) {
+			b43legacyerr(wl, "Fatal: Could not initialize device"
+				     " for newly selected %s-PHY mode\n",
+				     phymode_to_string(new_mode));
+			goto init_failure;
+		}
+	}
+	if (prev_status >= B43legacy_STAT_STARTED) {
+		err = b43legacy_wireless_core_start(up_dev);
+		if (err) {
+			b43legacyerr(wl, "Fatal: Coult not start device for "
+			       "newly selected %s-PHY mode\n",
+			       phymode_to_string(new_mode));
+			b43legacy_wireless_core_exit(up_dev);
+			goto init_failure;
+		}
+	}
+	B43legacy_WARN_ON(b43legacy_status(up_dev) != prev_status);
+
+	b43legacy_shm_write32(up_dev, B43legacy_SHM_SHARED, 0x003E, 0);
+
+	wl->current_dev = up_dev;
+
+	return 0;
+init_failure:
+	/* Whoops, failed to init the new core. No core is operating now. */
+	wl->current_dev = NULL;
+	return err;
+}
+
+static int b43legacy_antenna_from_ieee80211(u8 antenna)
+{
+	switch (antenna) {
+	case 0: /* default/diversity */
+		return B43legacy_ANTENNA_DEFAULT;
+	case 1: /* Antenna 0 */
+		return B43legacy_ANTENNA0;
+	case 2: /* Antenna 1 */
+		return B43legacy_ANTENNA1;
+	default:
+		return B43legacy_ANTENNA_DEFAULT;
+	}
+}
+
+static int b43legacy_dev_config(struct ieee80211_hw *hw,
+				struct ieee80211_conf *conf)
+{
+	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+	struct b43legacy_wldev *dev;
+	struct b43legacy_phy *phy;
+	unsigned long flags;
+	unsigned int new_phymode = 0xFFFF;
+	int antenna_tx;
+	int antenna_rx;
+	int err = 0;
+	u32 savedirqs;
+
+	antenna_tx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_tx);
+	antenna_rx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_rx);
+
+	mutex_lock(&wl->mutex);
+
+	/* Switch the PHY mode (if necessary). */
+	switch (conf->phymode) {
+	case MODE_IEEE80211B:
+		new_phymode = B43legacy_PHYMODE_B;
+		break;
+	case MODE_IEEE80211G:
+		new_phymode = B43legacy_PHYMODE_G;
+		break;
+	default:
+		B43legacy_WARN_ON(1);
+	}
+	err = b43legacy_switch_phymode(wl, new_phymode);
+	if (err)
+		goto out_unlock_mutex;
+	dev = wl->current_dev;
+	phy = &dev->phy;
+
+	/* Disable IRQs while reconfiguring the device.
+	 * This makes it possible to drop the spinlock throughout
+	 * the reconfiguration process. */
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	if (b43legacy_status(dev) < B43legacy_STAT_STARTED) {
+		spin_unlock_irqrestore(&wl->irq_lock, flags);
+		goto out_unlock_mutex;
+	}
+	savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL);
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+	b43legacy_synchronize_irq(dev);
+
+	/* Switch to the requested channel.
+	 * The firmware takes care of races with the TX handler. */
+	if (conf->channel_val != phy->channel)
+		b43legacy_radio_selectchannel(dev, conf->channel_val, 0);
+
+	/* Enable/Disable ShortSlot timing. */
+	if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME))
+	     != dev->short_slot) {
+		B43legacy_WARN_ON(phy->type != B43legacy_PHYTYPE_G);
+		if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)
+			b43legacy_short_slot_timing_enable(dev);
+		else
+			b43legacy_short_slot_timing_disable(dev);
+	}
+
+	/* Adjust the desired TX power level. */
+	if (conf->power_level != 0) {
+		if (conf->power_level != phy->power_level) {
+			phy->power_level = conf->power_level;
+			b43legacy_phy_xmitpower(dev);
+		}
+	}
+
+	/* Antennas for RX and management frame TX. */
+	b43legacy_mgmtframe_txantenna(dev, antenna_tx);
+
+	/* Update templates for AP mode. */
+	if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP))
+		b43legacy_set_beacon_int(dev, conf->beacon_int);
+
+
+	if (!!conf->radio_enabled != phy->radio_on) {
+		if (conf->radio_enabled) {
+			b43legacy_radio_turn_on(dev);
+			b43legacyinfo(dev->wl, "Radio turned on by software\n");
+			if (!dev->radio_hw_enable)
+				b43legacyinfo(dev->wl, "The hardware RF-kill"
+					      " button still turns the radio"
+					      " physically off. Press the"
+					      " button to turn it on.\n");
+		} else {
+			b43legacy_radio_turn_off(dev);
+			b43legacyinfo(dev->wl, "Radio turned off by"
+				      " software\n");
+		}
+	}
+
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	b43legacy_interrupt_enable(dev, savedirqs);
+	mmiowb();
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+out_unlock_mutex:
+	mutex_unlock(&wl->mutex);
+
+	return err;
+}
+
+static int b43legacy_dev_set_key(struct ieee80211_hw *hw,
+				 enum set_key_cmd cmd,
+				 const u8 *local_addr, const u8 *addr,
+				 struct ieee80211_key_conf *key)
+{
+	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+	struct b43legacy_wldev *dev = wl->current_dev;
+	unsigned long flags;
+	int err = -EOPNOTSUPP;
+	DECLARE_MAC_BUF(mac);
+
+	if (!dev)
+		return -ENODEV;
+	mutex_lock(&wl->mutex);
+	spin_lock_irqsave(&wl->irq_lock, flags);
+
+	if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
+		err = -ENODEV;
+	}
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+	mutex_unlock(&wl->mutex);
+	b43legacydbg(wl, "Using software based encryption for "
+		     "mac: %s\n", print_mac(mac, addr));
+	return err;
+}
+
+static void b43legacy_configure_filter(struct ieee80211_hw *hw,
+				       unsigned int changed,
+				       unsigned int *fflags,
+				       int mc_count,
+				       struct dev_addr_list *mc_list)
+{
+	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+	struct b43legacy_wldev *dev = wl->current_dev;
+	unsigned long flags;
+
+	if (!dev) {
+		*fflags = 0;
+		return;
+	}
+
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	*fflags &= FIF_PROMISC_IN_BSS |
+		  FIF_ALLMULTI |
+		  FIF_FCSFAIL |
+		  FIF_PLCPFAIL |
+		  FIF_CONTROL |
+		  FIF_OTHER_BSS |
+		  FIF_BCN_PRBRESP_PROMISC;
+
+	changed &= FIF_PROMISC_IN_BSS |
+		   FIF_ALLMULTI |
+		   FIF_FCSFAIL |
+		   FIF_PLCPFAIL |
+		   FIF_CONTROL |
+		   FIF_OTHER_BSS |
+		   FIF_BCN_PRBRESP_PROMISC;
+
+	wl->filter_flags = *fflags;
+
+	if (changed && b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED)
+		b43legacy_adjust_opmode(dev);
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+}
+
+static int b43legacy_config_interface(struct ieee80211_hw *hw,
+				      int if_id,
+				      struct ieee80211_if_conf *conf)
+{
+	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+	struct b43legacy_wldev *dev = wl->current_dev;
+	unsigned long flags;
+
+	if (!dev)
+		return -ENODEV;
+	mutex_lock(&wl->mutex);
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	B43legacy_WARN_ON(wl->if_id != if_id);
+	if (conf->bssid)
+		memcpy(wl->bssid, conf->bssid, ETH_ALEN);
+	else
+		memset(wl->bssid, 0, ETH_ALEN);
+	if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
+		if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
+			B43legacy_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
+			b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len);
+			if (conf->beacon)
+				b43legacy_refresh_templates(dev, conf->beacon);
+		}
+		b43legacy_write_mac_bssid_templates(dev);
+	}
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+	mutex_unlock(&wl->mutex);
+
+	return 0;
+}
+
+/* Locking: wl->mutex */
+static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_wl *wl = dev->wl;
+	unsigned long flags;
+
+	if (b43legacy_status(dev) < B43legacy_STAT_STARTED)
+		return;
+	b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED);
+
+	mutex_unlock(&wl->mutex);
+	/* Must unlock as it would otherwise deadlock. No races here.
+	 * Cancel the possibly running self-rearming periodic work. */
+	cancel_delayed_work_sync(&dev->periodic_work);
+	mutex_lock(&wl->mutex);
+
+	ieee80211_stop_queues(wl->hw); /* FIXME this could cause a deadlock */
+
+	/* Disable and sync interrupts. */
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	dev->irq_savedstate = b43legacy_interrupt_disable(dev,
+							  B43legacy_IRQ_ALL);
+	b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); /* flush */
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+	b43legacy_synchronize_irq(dev);
+
+	b43legacy_mac_suspend(dev);
+	free_irq(dev->dev->irq, dev);
+	b43legacydbg(wl, "Wireless interface stopped\n");
+}
+
+/* Locking: wl->mutex */
+static int b43legacy_wireless_core_start(struct b43legacy_wldev *dev)
+{
+	int err;
+
+	B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_INITIALIZED);
+
+	drain_txstatus_queue(dev);
+	err = request_irq(dev->dev->irq, b43legacy_interrupt_handler,
+			  IRQF_SHARED, KBUILD_MODNAME, dev);
+	if (err) {
+		b43legacyerr(dev->wl, "Cannot request IRQ-%d\n",
+		       dev->dev->irq);
+		goto out;
+	}
+	/* We are ready to run. */
+	b43legacy_set_status(dev, B43legacy_STAT_STARTED);
+
+	/* Start data flow (TX/RX) */
+	b43legacy_mac_enable(dev);
+	b43legacy_interrupt_enable(dev, dev->irq_savedstate);
+	ieee80211_start_queues(dev->wl->hw);
+
+	/* Start maintenance work */
+	b43legacy_periodic_tasks_setup(dev);
+
+	b43legacydbg(dev->wl, "Wireless interface started\n");
+out:
+	return err;
+}
+
+/* Get PHY and RADIO versioning numbers */
+static int b43legacy_phy_versioning(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u32 tmp;
+	u8 analog_type;
+	u8 phy_type;
+	u8 phy_rev;
+	u16 radio_manuf;
+	u16 radio_ver;
+	u16 radio_rev;
+	int unsupported = 0;
+
+	/* Get PHY versioning */
+	tmp = b43legacy_read16(dev, B43legacy_MMIO_PHY_VER);
+	analog_type = (tmp & B43legacy_PHYVER_ANALOG)
+		      >> B43legacy_PHYVER_ANALOG_SHIFT;
+	phy_type = (tmp & B43legacy_PHYVER_TYPE) >> B43legacy_PHYVER_TYPE_SHIFT;
+	phy_rev = (tmp & B43legacy_PHYVER_VERSION);
+	switch (phy_type) {
+	case B43legacy_PHYTYPE_B:
+		if (phy_rev != 2 && phy_rev != 4
+		    && phy_rev != 6 && phy_rev != 7)
+			unsupported = 1;
+		break;
+	case B43legacy_PHYTYPE_G:
+		if (phy_rev > 8)
+			unsupported = 1;
+		break;
+	default:
+		unsupported = 1;
+	};
+	if (unsupported) {
+		b43legacyerr(dev->wl, "FOUND UNSUPPORTED PHY "
+		       "(Analog %u, Type %u, Revision %u)\n",
+		       analog_type, phy_type, phy_rev);
+		return -EOPNOTSUPP;
+	}
+	b43legacydbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n",
+	       analog_type, phy_type, phy_rev);
+
+
+	/* Get RADIO versioning */
+	if (dev->dev->bus->chip_id == 0x4317) {
+		if (dev->dev->bus->chip_rev == 0)
+			tmp = 0x3205017F;
+		else if (dev->dev->bus->chip_rev == 1)
+			tmp = 0x4205017F;
+		else
+			tmp = 0x5205017F;
+	} else {
+		b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL,
+				  B43legacy_RADIOCTL_ID);
+		tmp = b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_HIGH);
+		tmp <<= 16;
+		b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL,
+				  B43legacy_RADIOCTL_ID);
+		tmp |= b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW);
+	}
+	radio_manuf = (tmp & 0x00000FFF);
+	radio_ver = (tmp & 0x0FFFF000) >> 12;
+	radio_rev = (tmp & 0xF0000000) >> 28;
+	switch (phy_type) {
+	case B43legacy_PHYTYPE_B:
+		if ((radio_ver & 0xFFF0) != 0x2050)
+			unsupported = 1;
+		break;
+	case B43legacy_PHYTYPE_G:
+		if (radio_ver != 0x2050)
+			unsupported = 1;
+		break;
+	default:
+		B43legacy_BUG_ON(1);
+	}
+	if (unsupported) {
+		b43legacyerr(dev->wl, "FOUND UNSUPPORTED RADIO "
+		       "(Manuf 0x%X, Version 0x%X, Revision %u)\n",
+		       radio_manuf, radio_ver, radio_rev);
+		return -EOPNOTSUPP;
+	}
+	b43legacydbg(dev->wl, "Found Radio: Manuf 0x%X, Version 0x%X,"
+		     " Revision %u\n", radio_manuf, radio_ver, radio_rev);
+
+
+	phy->radio_manuf = radio_manuf;
+	phy->radio_ver = radio_ver;
+	phy->radio_rev = radio_rev;
+
+	phy->analog = analog_type;
+	phy->type = phy_type;
+	phy->rev = phy_rev;
+
+	return 0;
+}
+
+static void setup_struct_phy_for_init(struct b43legacy_wldev *dev,
+				      struct b43legacy_phy *phy)
+{
+	struct b43legacy_lopair *lo;
+	int i;
+
+	memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
+	memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
+
+	/* Flags */
+	phy->locked = 0;
+	/* Assume the radio is enabled. If it's not enabled, the state will
+	 * immediately get fixed on the first periodic work run. */
+	dev->radio_hw_enable = 1;
+
+	phy->savedpctlreg = 0xFFFF;
+	phy->aci_enable = 0;
+	phy->aci_wlan_automatic = 0;
+	phy->aci_hw_rssi = 0;
+
+	lo = phy->_lo_pairs;
+	if (lo)
+		memset(lo, 0, sizeof(struct b43legacy_lopair) *
+				     B43legacy_LO_COUNT);
+	phy->max_lb_gain = 0;
+	phy->trsw_rx_gain = 0;
+
+	/* Set default attenuation values. */
+	phy->bbatt = b43legacy_default_baseband_attenuation(dev);
+	phy->rfatt = b43legacy_default_radio_attenuation(dev);
+	phy->txctl1 = b43legacy_default_txctl1(dev);
+	phy->txpwr_offset = 0;
+
+	/* NRSSI */
+	phy->nrssislope = 0;
+	for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++)
+		phy->nrssi[i] = -1000;
+	for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++)
+		phy->nrssi_lt[i] = i;
+
+	phy->lofcal = 0xFFFF;
+	phy->initval = 0xFFFF;
+
+	spin_lock_init(&phy->lock);
+	phy->interfmode = B43legacy_INTERFMODE_NONE;
+	phy->channel = 0xFF;
+}
+
+static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev)
+{
+	/* Flags */
+	dev->reg124_set_0x4 = 0;
+
+	/* Stats */
+	memset(&dev->stats, 0, sizeof(dev->stats));
+
+	setup_struct_phy_for_init(dev, &dev->phy);
+
+	/* IRQ related flags */
+	dev->irq_reason = 0;
+	memset(dev->dma_reason, 0, sizeof(dev->dma_reason));
+	dev->irq_savedstate = B43legacy_IRQ_MASKTEMPLATE;
+
+	dev->mac_suspended = 1;
+
+	/* Noise calculation context */
+	memset(&dev->noisecalc, 0, sizeof(dev->noisecalc));
+}
+
+static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev)
+{
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+	struct ssb_bus *bus = dev->dev->bus;
+	u32 tmp;
+
+	if (bus->pcicore.dev &&
+	    bus->pcicore.dev->id.coreid == SSB_DEV_PCI &&
+	    bus->pcicore.dev->id.revision <= 5) {
+		/* IMCFGLO timeouts workaround. */
+		tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
+		tmp &= ~SSB_IMCFGLO_REQTO;
+		tmp &= ~SSB_IMCFGLO_SERTO;
+		switch (bus->bustype) {
+		case SSB_BUSTYPE_PCI:
+		case SSB_BUSTYPE_PCMCIA:
+			tmp |= 0x32;
+			break;
+		case SSB_BUSTYPE_SSB:
+			tmp |= 0x53;
+			break;
+		}
+		ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
+	}
+#endif /* CONFIG_SSB_DRIVER_PCICORE */
+}
+
+/* Shutdown a wireless core */
+/* Locking: wl->mutex */
+static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_wl *wl = dev->wl;
+	struct b43legacy_phy *phy = &dev->phy;
+
+	B43legacy_WARN_ON(b43legacy_status(dev) > B43legacy_STAT_INITIALIZED);
+	if (b43legacy_status(dev) != B43legacy_STAT_INITIALIZED)
+		return;
+	b43legacy_set_status(dev, B43legacy_STAT_UNINIT);
+
+	mutex_unlock(&wl->mutex);
+	/* Must unlock as it would otherwise deadlock. No races here.
+	 * Cancel possibly pending workqueues. */
+	cancel_work_sync(&dev->restart_work);
+	mutex_lock(&wl->mutex);
+
+	b43legacy_rng_exit(dev->wl);
+	b43legacy_pio_free(dev);
+	b43legacy_dma_free(dev);
+	b43legacy_chip_exit(dev);
+	b43legacy_radio_turn_off(dev);
+	b43legacy_switch_analog(dev, 0);
+	if (phy->dyn_tssi_tbl)
+		kfree(phy->tssi2dbm);
+	kfree(phy->lo_control);
+	phy->lo_control = NULL;
+	ssb_device_disable(dev->dev, 0);
+	ssb_bus_may_powerdown(dev->dev->bus);
+}
+
+static void prepare_phy_data_for_init(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	int i;
+
+	/* Set default attenuation values. */
+	phy->bbatt = b43legacy_default_baseband_attenuation(dev);
+	phy->rfatt = b43legacy_default_radio_attenuation(dev);
+	phy->txctl1 = b43legacy_default_txctl1(dev);
+	phy->txctl2 = 0xFFFF;
+	phy->txpwr_offset = 0;
+
+	/* NRSSI */
+	phy->nrssislope = 0;
+	for (i = 0; i < ARRAY_SIZE(phy->nrssi); i++)
+		phy->nrssi[i] = -1000;
+	for (i = 0; i < ARRAY_SIZE(phy->nrssi_lt); i++)
+		phy->nrssi_lt[i] = i;
+
+	phy->lofcal = 0xFFFF;
+	phy->initval = 0xFFFF;
+
+	phy->aci_enable = 0;
+	phy->aci_wlan_automatic = 0;
+	phy->aci_hw_rssi = 0;
+
+	phy->antenna_diversity = 0xFFFF;
+	memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
+	memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
+
+	/* Flags */
+	phy->calibrated = 0;
+	phy->locked = 0;
+
+	if (phy->_lo_pairs)
+		memset(phy->_lo_pairs, 0,
+		       sizeof(struct b43legacy_lopair) * B43legacy_LO_COUNT);
+	memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain));
+}
+
+/* Initialize a wireless core */
+static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_wl *wl = dev->wl;
+	struct ssb_bus *bus = dev->dev->bus;
+	struct b43legacy_phy *phy = &dev->phy;
+	struct ssb_sprom *sprom = &dev->dev->bus->sprom;
+	int err;
+	u32 hf;
+	u32 tmp;
+
+	B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_UNINIT);
+
+	err = ssb_bus_powerup(bus, 0);
+	if (err)
+		goto out;
+	if (!ssb_device_is_enabled(dev->dev)) {
+		tmp = phy->gmode ? B43legacy_TMSLOW_GMODE : 0;
+		b43legacy_wireless_core_reset(dev, tmp);
+	}
+
+	if ((phy->type == B43legacy_PHYTYPE_B) ||
+	    (phy->type == B43legacy_PHYTYPE_G)) {
+		phy->_lo_pairs = kzalloc(sizeof(struct b43legacy_lopair)
+					 * B43legacy_LO_COUNT,
+					 GFP_KERNEL);
+		if (!phy->_lo_pairs)
+			return -ENOMEM;
+	}
+	setup_struct_wldev_for_init(dev);
+
+	err = b43legacy_phy_init_tssi2dbm_table(dev);
+	if (err)
+		goto err_kfree_lo_control;
+
+	/* Enable IRQ routing to this device. */
+	ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
+
+	b43legacy_imcfglo_timeouts_workaround(dev);
+	prepare_phy_data_for_init(dev);
+	b43legacy_phy_calibrate(dev);
+	err = b43legacy_chip_init(dev);
+	if (err)
+		goto err_kfree_tssitbl;
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+			      B43legacy_SHM_SH_WLCOREREV,
+			      dev->dev->id.revision);
+	hf = b43legacy_hf_read(dev);
+	if (phy->type == B43legacy_PHYTYPE_G) {
+		hf |= B43legacy_HF_SYMW;
+		if (phy->rev == 1)
+			hf |= B43legacy_HF_GDCW;
+		if (sprom->r1.boardflags_lo & B43legacy_BFL_PACTRL)
+			hf |= B43legacy_HF_OFDMPABOOST;
+	} else if (phy->type == B43legacy_PHYTYPE_B) {
+		hf |= B43legacy_HF_SYMW;
+		if (phy->rev >= 2 && phy->radio_ver == 0x2050)
+			hf &= ~B43legacy_HF_GDCW;
+	}
+	b43legacy_hf_write(dev, hf);
+
+	/* Short/Long Retry Limit.
+	 * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing
+	 * the chip-internal counter.
+	 */
+	tmp = limit_value(modparam_short_retry, 0, 0xF);
+	b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
+			      0x0006, tmp);
+	tmp = limit_value(modparam_long_retry, 0, 0xF);
+	b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
+			      0x0007, tmp);
+
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+			      0x0044, 3);
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+			      0x0046, 2);
+
+	/* Disable sending probe responses from firmware.
+	 * Setting the MaxTime to one usec will always trigger
+	 * a timeout, so we never send any probe resp.
+	 * A timeout of zero is infinite. */
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED,
+			      B43legacy_SHM_SH_PRMAXTIME, 1);
+
+	b43legacy_rate_memory_init(dev);
+
+	/* Minimum Contention Window */
+	if (phy->type == B43legacy_PHYTYPE_B)
+		b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
+				      0x0003, 31);
+	else
+		b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
+				      0x0003, 15);
+	/* Maximum Contention Window */
+	b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS,
+			      0x0004, 1023);
+
+	do {
+		if (b43legacy_using_pio(dev))
+			err = b43legacy_pio_init(dev);
+		else {
+			err = b43legacy_dma_init(dev);
+			if (!err)
+				b43legacy_qos_init(dev);
+		}
+	} while (err == -EAGAIN);
+	if (err)
+		goto err_chip_exit;
+
+	b43legacy_write16(dev, 0x0612, 0x0050);
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0416, 0x0050);
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4);
+
+	ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
+	memset(wl->bssid, 0, ETH_ALEN);
+	memset(wl->mac_addr, 0, ETH_ALEN);
+	b43legacy_upload_card_macaddress(dev);
+	b43legacy_security_init(dev);
+	b43legacy_rng_init(wl);
+
+	b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED);
+
+out:
+	return err;
+
+err_chip_exit:
+	b43legacy_chip_exit(dev);
+err_kfree_tssitbl:
+	if (phy->dyn_tssi_tbl)
+		kfree(phy->tssi2dbm);
+err_kfree_lo_control:
+	kfree(phy->lo_control);
+	phy->lo_control = NULL;
+	ssb_bus_may_powerdown(bus);
+	B43legacy_WARN_ON(b43legacy_status(dev) != B43legacy_STAT_UNINIT);
+	return err;
+}
+
+static int b43legacy_add_interface(struct ieee80211_hw *hw,
+				   struct ieee80211_if_init_conf *conf)
+{
+	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+	struct b43legacy_wldev *dev;
+	unsigned long flags;
+	int err = -EOPNOTSUPP;
+
+	/* TODO: allow WDS/AP devices to coexist */
+
+	if (conf->type != IEEE80211_IF_TYPE_AP &&
+	    conf->type != IEEE80211_IF_TYPE_STA &&
+	    conf->type != IEEE80211_IF_TYPE_WDS &&
+	    conf->type != IEEE80211_IF_TYPE_IBSS)
+		return -EOPNOTSUPP;
+
+	mutex_lock(&wl->mutex);
+	if (wl->operating)
+		goto out_mutex_unlock;
+
+	b43legacydbg(wl, "Adding Interface type %d\n", conf->type);
+
+	dev = wl->current_dev;
+	wl->operating = 1;
+	wl->if_id = conf->if_id;
+	wl->if_type = conf->type;
+	memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	b43legacy_adjust_opmode(dev);
+	b43legacy_upload_card_macaddress(dev);
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+	err = 0;
+ out_mutex_unlock:
+	mutex_unlock(&wl->mutex);
+
+	return err;
+}
+
+static void b43legacy_remove_interface(struct ieee80211_hw *hw,
+				       struct ieee80211_if_init_conf *conf)
+{
+	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+	struct b43legacy_wldev *dev = wl->current_dev;
+	unsigned long flags;
+
+	b43legacydbg(wl, "Removing Interface type %d\n", conf->type);
+
+	mutex_lock(&wl->mutex);
+
+	B43legacy_WARN_ON(!wl->operating);
+	B43legacy_WARN_ON(wl->if_id != conf->if_id);
+
+	wl->operating = 0;
+
+	spin_lock_irqsave(&wl->irq_lock, flags);
+	b43legacy_adjust_opmode(dev);
+	memset(wl->mac_addr, 0, ETH_ALEN);
+	b43legacy_upload_card_macaddress(dev);
+	spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+	mutex_unlock(&wl->mutex);
+}
+
+static int b43legacy_start(struct ieee80211_hw *hw)
+{
+	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+	struct b43legacy_wldev *dev = wl->current_dev;
+	int did_init = 0;
+	int err;
+
+	mutex_lock(&wl->mutex);
+
+	if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
+		err = b43legacy_wireless_core_init(dev);
+		if (err)
+			goto out_mutex_unlock;
+		did_init = 1;
+	}
+
+	if (b43legacy_status(dev) < B43legacy_STAT_STARTED) {
+		err = b43legacy_wireless_core_start(dev);
+		if (err) {
+			if (did_init)
+				b43legacy_wireless_core_exit(dev);
+			goto out_mutex_unlock;
+		}
+	}
+
+out_mutex_unlock:
+	mutex_unlock(&wl->mutex);
+
+	return err;
+}
+
+void b43legacy_stop(struct ieee80211_hw *hw)
+{
+	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+	struct b43legacy_wldev *dev = wl->current_dev;
+
+	mutex_lock(&wl->mutex);
+	if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
+		b43legacy_wireless_core_stop(dev);
+	b43legacy_wireless_core_exit(dev);
+	mutex_unlock(&wl->mutex);
+}
+
+
+static const struct ieee80211_ops b43legacy_hw_ops = {
+	.tx = b43legacy_tx,
+	.conf_tx = b43legacy_conf_tx,
+	.add_interface = b43legacy_add_interface,
+	.remove_interface = b43legacy_remove_interface,
+	.config = b43legacy_dev_config,
+	.config_interface = b43legacy_config_interface,
+	.set_key = b43legacy_dev_set_key,
+	.configure_filter = b43legacy_configure_filter,
+	.get_stats = b43legacy_get_stats,
+	.get_tx_stats = b43legacy_get_tx_stats,
+	.start = b43legacy_start,
+	.stop = b43legacy_stop,
+};
+
+/* Hard-reset the chip. Do not call this directly.
+ * Use b43legacy_controller_restart()
+ */
+static void b43legacy_chip_reset(struct work_struct *work)
+{
+	struct b43legacy_wldev *dev =
+		container_of(work, struct b43legacy_wldev, restart_work);
+	struct b43legacy_wl *wl = dev->wl;
+	int err = 0;
+	int prev_status;
+
+	mutex_lock(&wl->mutex);
+
+	prev_status = b43legacy_status(dev);
+	/* Bring the device down... */
+	if (prev_status >= B43legacy_STAT_STARTED)
+		b43legacy_wireless_core_stop(dev);
+	if (prev_status >= B43legacy_STAT_INITIALIZED)
+		b43legacy_wireless_core_exit(dev);
+
+	/* ...and up again. */
+	if (prev_status >= B43legacy_STAT_INITIALIZED) {
+		err = b43legacy_wireless_core_init(dev);
+		if (err)
+			goto out;
+	}
+	if (prev_status >= B43legacy_STAT_STARTED) {
+		err = b43legacy_wireless_core_start(dev);
+		if (err) {
+			b43legacy_wireless_core_exit(dev);
+			goto out;
+		}
+	}
+out:
+	mutex_unlock(&wl->mutex);
+	if (err)
+		b43legacyerr(wl, "Controller restart FAILED\n");
+	else
+		b43legacyinfo(wl, "Controller restarted\n");
+}
+
+static int b43legacy_setup_modes(struct b43legacy_wldev *dev,
+				 int have_bphy,
+				 int have_gphy)
+{
+	struct ieee80211_hw *hw = dev->wl->hw;
+	struct ieee80211_hw_mode *mode;
+	struct b43legacy_phy *phy = &dev->phy;
+	int cnt = 0;
+	int err;
+
+	phy->possible_phymodes = 0;
+	for (; 1; cnt++) {
+		if (have_bphy) {
+			B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES);
+			mode = &phy->hwmodes[cnt];
+
+			mode->mode = MODE_IEEE80211B;
+			mode->num_channels = b43legacy_bg_chantable_size;
+			mode->channels = b43legacy_bg_chantable;
+			mode->num_rates = b43legacy_b_ratetable_size;
+			mode->rates = b43legacy_b_ratetable;
+			err = ieee80211_register_hwmode(hw, mode);
+			if (err)
+				return err;
+
+			phy->possible_phymodes |= B43legacy_PHYMODE_B;
+			have_bphy = 0;
+			continue;
+		}
+		if (have_gphy) {
+			B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES);
+			mode = &phy->hwmodes[cnt];
+
+			mode->mode = MODE_IEEE80211G;
+			mode->num_channels = b43legacy_bg_chantable_size;
+			mode->channels = b43legacy_bg_chantable;
+			mode->num_rates = b43legacy_g_ratetable_size;
+			mode->rates = b43legacy_g_ratetable;
+			err = ieee80211_register_hwmode(hw, mode);
+			if (err)
+				return err;
+
+			phy->possible_phymodes |= B43legacy_PHYMODE_G;
+			have_gphy = 0;
+			continue;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+static void b43legacy_wireless_core_detach(struct b43legacy_wldev *dev)
+{
+	/* We release firmware that late to not be required to re-request
+	 * is all the time when we reinit the core. */
+	b43legacy_release_firmware(dev);
+}
+
+static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_wl *wl = dev->wl;
+	struct ssb_bus *bus = dev->dev->bus;
+	struct pci_dev *pdev = bus->host_pci;
+	int err;
+	int have_bphy = 0;
+	int have_gphy = 0;
+	u32 tmp;
+
+	/* Do NOT do any device initialization here.
+	 * Do it in wireless_core_init() instead.
+	 * This function is for gathering basic information about the HW, only.
+	 * Also some structs may be set up here. But most likely you want to
+	 * have that in core_init(), too.
+	 */
+
+	err = ssb_bus_powerup(bus, 0);
+	if (err) {
+		b43legacyerr(wl, "Bus powerup failed\n");
+		goto out;
+	}
+	/* Get the PHY type. */
+	if (dev->dev->id.revision >= 5) {
+		u32 tmshigh;
+
+		tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
+		have_gphy = !!(tmshigh & B43legacy_TMSHIGH_GPHY);
+		if (!have_gphy)
+			have_bphy = 1;
+	} else if (dev->dev->id.revision == 4)
+		have_gphy = 1;
+	else
+		have_bphy = 1;
+
+	/* Initialize LEDs structs. */
+	err = b43legacy_leds_init(dev);
+	if (err)
+		goto err_powerdown;
+
+	dev->phy.gmode = (have_gphy || have_bphy);
+	tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0;
+	b43legacy_wireless_core_reset(dev, tmp);
+
+	err = b43legacy_phy_versioning(dev);
+	if (err)
+		goto err_leds_exit;
+	/* Check if this device supports multiband. */
+	if (!pdev ||
+	    (pdev->device != 0x4312 &&
+	     pdev->device != 0x4319 &&
+	     pdev->device != 0x4324)) {
+		/* No multiband support. */
+		have_bphy = 0;
+		have_gphy = 0;
+		switch (dev->phy.type) {
+		case B43legacy_PHYTYPE_B:
+			have_bphy = 1;
+			break;
+		case B43legacy_PHYTYPE_G:
+			have_gphy = 1;
+			break;
+		default:
+			B43legacy_BUG_ON(1);
+		}
+	}
+	dev->phy.gmode = (have_gphy || have_bphy);
+	tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0;
+	b43legacy_wireless_core_reset(dev, tmp);
+
+	err = b43legacy_validate_chipaccess(dev);
+	if (err)
+		goto err_leds_exit;
+	err = b43legacy_setup_modes(dev, have_bphy, have_gphy);
+	if (err)
+		goto err_leds_exit;
+
+	/* Now set some default "current_dev" */
+	if (!wl->current_dev)
+		wl->current_dev = dev;
+	INIT_WORK(&dev->restart_work, b43legacy_chip_reset);
+
+	b43legacy_radio_turn_off(dev);
+	b43legacy_switch_analog(dev, 0);
+	ssb_device_disable(dev->dev, 0);
+	ssb_bus_may_powerdown(bus);
+
+out:
+	return err;
+
+err_leds_exit:
+	b43legacy_leds_exit(dev);
+err_powerdown:
+	ssb_bus_may_powerdown(bus);
+	return err;
+}
+
+static void b43legacy_one_core_detach(struct ssb_device *dev)
+{
+	struct b43legacy_wldev *wldev;
+	struct b43legacy_wl *wl;
+
+	wldev = ssb_get_drvdata(dev);
+	wl = wldev->wl;
+	cancel_work_sync(&wldev->restart_work);
+	b43legacy_debugfs_remove_device(wldev);
+	b43legacy_wireless_core_detach(wldev);
+	list_del(&wldev->list);
+	wl->nr_devs--;
+	ssb_set_drvdata(dev, NULL);
+	kfree(wldev);
+}
+
+static int b43legacy_one_core_attach(struct ssb_device *dev,
+				     struct b43legacy_wl *wl)
+{
+	struct b43legacy_wldev *wldev;
+	struct pci_dev *pdev;
+	int err = -ENOMEM;
+
+	if (!list_empty(&wl->devlist)) {
+		/* We are not the first core on this chip. */
+		pdev = dev->bus->host_pci;
+		/* Only special chips support more than one wireless
+		 * core, although some of the other chips have more than
+		 * one wireless core as well. Check for this and
+		 * bail out early.
+		 */
+		if (!pdev ||
+		    ((pdev->device != 0x4321) &&
+		     (pdev->device != 0x4313) &&
+		     (pdev->device != 0x431A))) {
+			b43legacydbg(wl, "Ignoring unconnected 802.11 core\n");
+			return -ENODEV;
+		}
+	}
+
+	wldev = kzalloc(sizeof(*wldev), GFP_KERNEL);
+	if (!wldev)
+		goto out;
+
+	wldev->dev = dev;
+	wldev->wl = wl;
+	b43legacy_set_status(wldev, B43legacy_STAT_UNINIT);
+	wldev->bad_frames_preempt = modparam_bad_frames_preempt;
+	tasklet_init(&wldev->isr_tasklet,
+		     (void (*)(unsigned long))b43legacy_interrupt_tasklet,
+		     (unsigned long)wldev);
+	if (modparam_pio)
+		wldev->__using_pio = 1;
+	INIT_LIST_HEAD(&wldev->list);
+
+	err = b43legacy_wireless_core_attach(wldev);
+	if (err)
+		goto err_kfree_wldev;
+
+	list_add(&wldev->list, &wl->devlist);
+	wl->nr_devs++;
+	ssb_set_drvdata(dev, wldev);
+	b43legacy_debugfs_add_device(wldev);
+out:
+	return err;
+
+err_kfree_wldev:
+	kfree(wldev);
+	return err;
+}
+
+static void b43legacy_sprom_fixup(struct ssb_bus *bus)
+{
+	/* boardflags workarounds */
+	if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
+	    bus->boardinfo.type == 0x4E &&
+	    bus->boardinfo.rev > 0x40)
+		bus->sprom.r1.boardflags_lo |= B43legacy_BFL_PACTRL;
+
+	/* Convert Antennagain values to Q5.2 */
+	if (bus->sprom.r1.antenna_gain_bg == 0xFF)
+		bus->sprom.r1.antenna_gain_bg = 2; /* if unset, use 2 dBm */
+	bus->sprom.r1.antenna_gain_bg <<= 2;
+}
+
+static void b43legacy_wireless_exit(struct ssb_device *dev,
+				  struct b43legacy_wl *wl)
+{
+	struct ieee80211_hw *hw = wl->hw;
+
+	ssb_set_devtypedata(dev, NULL);
+	ieee80211_free_hw(hw);
+}
+
+static int b43legacy_wireless_init(struct ssb_device *dev)
+{
+	struct ssb_sprom *sprom = &dev->bus->sprom;
+	struct ieee80211_hw *hw;
+	struct b43legacy_wl *wl;
+	int err = -ENOMEM;
+
+	b43legacy_sprom_fixup(dev->bus);
+
+	hw = ieee80211_alloc_hw(sizeof(*wl), &b43legacy_hw_ops);
+	if (!hw) {
+		b43legacyerr(NULL, "Could not allocate ieee80211 device\n");
+		goto out;
+	}
+
+	/* fill hw info */
+	hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+		    IEEE80211_HW_RX_INCLUDES_FCS;
+	hw->max_signal = 100;
+	hw->max_rssi = -110;
+	hw->max_noise = -110;
+	hw->queues = 1; /* FIXME: hardware has more queues */
+	SET_IEEE80211_DEV(hw, dev->dev);
+	if (is_valid_ether_addr(sprom->r1.et1mac))
+		SET_IEEE80211_PERM_ADDR(hw, sprom->r1.et1mac);
+	else
+		SET_IEEE80211_PERM_ADDR(hw, sprom->r1.il0mac);
+
+	/* Get and initialize struct b43legacy_wl */
+	wl = hw_to_b43legacy_wl(hw);
+	memset(wl, 0, sizeof(*wl));
+	wl->hw = hw;
+	spin_lock_init(&wl->irq_lock);
+	spin_lock_init(&wl->leds_lock);
+	mutex_init(&wl->mutex);
+	INIT_LIST_HEAD(&wl->devlist);
+
+	ssb_set_devtypedata(dev, wl);
+	b43legacyinfo(wl, "Broadcom %04X WLAN found\n", dev->bus->chip_id);
+	err = 0;
+out:
+	return err;
+}
+
+static int b43legacy_probe(struct ssb_device *dev,
+			 const struct ssb_device_id *id)
+{
+	struct b43legacy_wl *wl;
+	int err;
+	int first = 0;
+
+	wl = ssb_get_devtypedata(dev);
+	if (!wl) {
+		/* Probing the first core - setup common struct b43legacy_wl */
+		first = 1;
+		err = b43legacy_wireless_init(dev);
+		if (err)
+			goto out;
+		wl = ssb_get_devtypedata(dev);
+		B43legacy_WARN_ON(!wl);
+	}
+	err = b43legacy_one_core_attach(dev, wl);
+	if (err)
+		goto err_wireless_exit;
+
+	if (first) {
+		err = ieee80211_register_hw(wl->hw);
+		if (err)
+			goto err_one_core_detach;
+	}
+
+out:
+	return err;
+
+err_one_core_detach:
+	b43legacy_one_core_detach(dev);
+err_wireless_exit:
+	if (first)
+		b43legacy_wireless_exit(dev, wl);
+	return err;
+}
+
+static void b43legacy_remove(struct ssb_device *dev)
+{
+	struct b43legacy_wl *wl = ssb_get_devtypedata(dev);
+	struct b43legacy_wldev *wldev = ssb_get_drvdata(dev);
+
+	B43legacy_WARN_ON(!wl);
+	if (wl->current_dev == wldev)
+		ieee80211_unregister_hw(wl->hw);
+
+	b43legacy_one_core_detach(dev);
+
+	if (list_empty(&wl->devlist))
+		/* Last core on the chip unregistered.
+		 * We can destroy common struct b43legacy_wl.
+		 */
+		b43legacy_wireless_exit(dev, wl);
+}
+
+/* Perform a hardware reset. This can be called from any context. */
+void b43legacy_controller_restart(struct b43legacy_wldev *dev,
+				  const char *reason)
+{
+	/* Must avoid requeueing, if we are in shutdown. */
+	if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)
+		return;
+	b43legacyinfo(dev->wl, "Controller RESET (%s) ...\n", reason);
+	queue_work(dev->wl->hw->workqueue, &dev->restart_work);
+}
+
+#ifdef CONFIG_PM
+
+static int b43legacy_suspend(struct ssb_device *dev, pm_message_t state)
+{
+	struct b43legacy_wldev *wldev = ssb_get_drvdata(dev);
+	struct b43legacy_wl *wl = wldev->wl;
+
+	b43legacydbg(wl, "Suspending...\n");
+
+	mutex_lock(&wl->mutex);
+	wldev->suspend_init_status = b43legacy_status(wldev);
+	if (wldev->suspend_init_status >= B43legacy_STAT_STARTED)
+		b43legacy_wireless_core_stop(wldev);
+	if (wldev->suspend_init_status >= B43legacy_STAT_INITIALIZED)
+		b43legacy_wireless_core_exit(wldev);
+	mutex_unlock(&wl->mutex);
+
+	b43legacydbg(wl, "Device suspended.\n");
+
+	return 0;
+}
+
+static int b43legacy_resume(struct ssb_device *dev)
+{
+	struct b43legacy_wldev *wldev = ssb_get_drvdata(dev);
+	struct b43legacy_wl *wl = wldev->wl;
+	int err = 0;
+
+	b43legacydbg(wl, "Resuming...\n");
+
+	mutex_lock(&wl->mutex);
+	if (wldev->suspend_init_status >= B43legacy_STAT_INITIALIZED) {
+		err = b43legacy_wireless_core_init(wldev);
+		if (err) {
+			b43legacyerr(wl, "Resume failed at core init\n");
+			goto out;
+		}
+	}
+	if (wldev->suspend_init_status >= B43legacy_STAT_STARTED) {
+		err = b43legacy_wireless_core_start(wldev);
+		if (err) {
+			b43legacy_wireless_core_exit(wldev);
+			b43legacyerr(wl, "Resume failed at core start\n");
+			goto out;
+		}
+	}
+	mutex_unlock(&wl->mutex);
+
+	b43legacydbg(wl, "Device resumed.\n");
+out:
+	return err;
+}
+
+#else	/* CONFIG_PM */
+# define b43legacy_suspend	NULL
+# define b43legacy_resume		NULL
+#endif	/* CONFIG_PM */
+
+static struct ssb_driver b43legacy_ssb_driver = {
+	.name		= KBUILD_MODNAME,
+	.id_table	= b43legacy_ssb_tbl,
+	.probe		= b43legacy_probe,
+	.remove		= b43legacy_remove,
+	.suspend	= b43legacy_suspend,
+	.resume		= b43legacy_resume,
+};
+
+static int __init b43legacy_init(void)
+{
+	int err;
+
+	b43legacy_debugfs_init();
+
+	err = ssb_driver_register(&b43legacy_ssb_driver);
+	if (err)
+		goto err_dfs_exit;
+
+	return err;
+
+err_dfs_exit:
+	b43legacy_debugfs_exit();
+	return err;
+}
+
+static void __exit b43legacy_exit(void)
+{
+	ssb_driver_unregister(&b43legacy_ssb_driver);
+	b43legacy_debugfs_exit();
+}
+
+module_init(b43legacy_init)
+module_exit(b43legacy_exit)
diff --git a/drivers/net/wireless/b43legacy/main.h b/drivers/net/wireless/b43legacy/main.h
new file mode 100644
index 0000000..68435c5
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/main.h
@@ -0,0 +1,127 @@
+/*
+
+  Broadcom B43legacy wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+  Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+  Copyright (c) 2005  Danny van Dyk <kugelfang@gentoo.org>
+  Copyright (c) 2005  Andreas Jaggi <andreas.jaggi@waterwave.ch>
+  Copyright (c) 2007  Larry Finger <Larry.Finger@lwfinger.net>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 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 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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef B43legacy_MAIN_H_
+#define B43legacy_MAIN_H_
+
+#include "b43legacy.h"
+
+
+#define P4D_BYT3S(magic, nr_bytes)	u8 __p4dding##magic[nr_bytes]
+#define P4D_BYTES(line, nr_bytes)	P4D_BYT3S(line, nr_bytes)
+/* Magic helper macro to pad structures. Ignore those above. It's magic. */
+#define PAD_BYTES(nr_bytes)		P4D_BYTES(__LINE__ , (nr_bytes))
+
+
+/* Lightweight function to convert a frequency (in Mhz) to a channel number. */
+static inline
+u8 b43legacy_freq_to_channel_bg(int freq)
+{
+	u8 channel;
+
+	if (freq == 2484)
+		channel = 14;
+	else
+		channel = (freq - 2407) / 5;
+
+	return channel;
+}
+static inline
+u8 b43legacy_freq_to_channel(struct b43legacy_wldev *dev,
+			     int freq)
+{
+	return b43legacy_freq_to_channel_bg(freq);
+}
+
+/* Lightweight function to convert a channel number to a frequency (in Mhz). */
+static inline
+int b43legacy_channel_to_freq_bg(u8 channel)
+{
+	int freq;
+
+	if (channel == 14)
+		freq = 2484;
+	else
+		freq = 2407 + (5 * channel);
+
+	return freq;
+}
+
+static inline
+int b43legacy_channel_to_freq(struct b43legacy_wldev *dev,
+			      u8 channel)
+{
+	return b43legacy_channel_to_freq_bg(channel);
+}
+
+static inline
+int b43legacy_is_cck_rate(int rate)
+{
+	return (rate == B43legacy_CCK_RATE_1MB ||
+		rate == B43legacy_CCK_RATE_2MB ||
+		rate == B43legacy_CCK_RATE_5MB ||
+		rate == B43legacy_CCK_RATE_11MB);
+}
+
+static inline
+int b43legacy_is_ofdm_rate(int rate)
+{
+	return !b43legacy_is_cck_rate(rate);
+}
+
+void b43legacy_tsf_read(struct b43legacy_wldev *dev, u64 *tsf);
+void b43legacy_tsf_write(struct b43legacy_wldev *dev, u64 tsf);
+
+u32 b43legacy_shm_read32(struct b43legacy_wldev *dev,
+			 u16 routing, u16 offset);
+u16 b43legacy_shm_read16(struct b43legacy_wldev *dev,
+			 u16 routing, u16 offset);
+void b43legacy_shm_write32(struct b43legacy_wldev *dev,
+			 u16 routing, u16 offset,
+			 u32 value);
+void b43legacy_shm_write16(struct b43legacy_wldev *dev,
+			 u16 routing, u16 offset,
+			 u16 value);
+
+u32 b43legacy_hf_read(struct b43legacy_wldev *dev);
+void b43legacy_hf_write(struct b43legacy_wldev *dev, u32 value);
+
+void b43legacy_dummy_transmission(struct b43legacy_wldev *dev);
+
+void b43legacy_wireless_core_reset(struct b43legacy_wldev *dev, u32 flags);
+
+void b43legacy_mac_suspend(struct b43legacy_wldev *dev);
+void b43legacy_mac_enable(struct b43legacy_wldev *dev);
+
+void b43legacy_controller_restart(struct b43legacy_wldev *dev,
+				  const char *reason);
+
+#endif /* B43legacy_MAIN_H_ */
diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c
new file mode 100644
index 0000000..22a4b3d
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/phy.c
@@ -0,0 +1,2255 @@
+/*
+
+  Broadcom B43legacy wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+		     Stefano Brivio <st3@riseup.net>
+		     Michael Buesch <mbuesch@freenet.de>
+		     Danny van Dyk <kugelfang@gentoo.org>
+     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+  Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 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 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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+
+#include "b43legacy.h"
+#include "phy.h"
+#include "main.h"
+#include "radio.h"
+#include "ilt.h"
+
+
+static const s8 b43legacy_tssi2dbm_b_table[] = {
+	0x4D, 0x4C, 0x4B, 0x4A,
+	0x4A, 0x49, 0x48, 0x47,
+	0x47, 0x46, 0x45, 0x45,
+	0x44, 0x43, 0x42, 0x42,
+	0x41, 0x40, 0x3F, 0x3E,
+	0x3D, 0x3C, 0x3B, 0x3A,
+	0x39, 0x38, 0x37, 0x36,
+	0x35, 0x34, 0x32, 0x31,
+	0x30, 0x2F, 0x2D, 0x2C,
+	0x2B, 0x29, 0x28, 0x26,
+	0x25, 0x23, 0x21, 0x1F,
+	0x1D, 0x1A, 0x17, 0x14,
+	0x10, 0x0C, 0x06, 0x00,
+	  -7,   -7,   -7,   -7,
+	  -7,   -7,   -7,   -7,
+	  -7,   -7,   -7,   -7,
+};
+
+static const s8 b43legacy_tssi2dbm_g_table[] = {
+	 77,  77,  77,  76,
+	 76,  76,  75,  75,
+	 74,  74,  73,  73,
+	 73,  72,  72,  71,
+	 71,  70,  70,  69,
+	 68,  68,  67,  67,
+	 66,  65,  65,  64,
+	 63,  63,  62,  61,
+	 60,  59,  58,  57,
+	 56,  55,  54,  53,
+	 52,  50,  49,  47,
+	 45,  43,  40,  37,
+	 33,  28,  22,  14,
+	  5,  -7, -20, -20,
+	-20, -20, -20, -20,
+	-20, -20, -20, -20,
+};
+
+static void b43legacy_phy_initg(struct b43legacy_wldev *dev);
+
+
+static inline
+void b43legacy_voluntary_preempt(void)
+{
+	B43legacy_BUG_ON(!(!in_atomic() && !in_irq() &&
+			  !in_interrupt() && !irqs_disabled()));
+#ifndef CONFIG_PREEMPT
+	cond_resched();
+#endif /* CONFIG_PREEMPT */
+}
+
+void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+
+	B43legacy_WARN_ON(!irqs_disabled());
+	if (b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD) == 0) {
+		phy->locked = 0;
+		return;
+	}
+	if (dev->dev->id.revision < 3) {
+		b43legacy_mac_suspend(dev);
+		spin_lock(&phy->lock);
+	} else {
+		if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+			b43legacy_power_saving_ctl_bits(dev, -1, 1);
+	}
+	phy->locked = 1;
+}
+
+void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+
+	B43legacy_WARN_ON(!irqs_disabled());
+	if (dev->dev->id.revision < 3) {
+		if (phy->locked) {
+			spin_unlock(&phy->lock);
+			b43legacy_mac_enable(dev);
+		}
+	} else {
+		if (!b43legacy_is_mode(dev->wl, IEEE80211_IF_TYPE_AP))
+			b43legacy_power_saving_ctl_bits(dev, -1, -1);
+	}
+	phy->locked = 0;
+}
+
+u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset)
+{
+	b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset);
+	return b43legacy_read16(dev, B43legacy_MMIO_PHY_DATA);
+}
+
+void b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val)
+{
+	b43legacy_write16(dev, B43legacy_MMIO_PHY_CONTROL, offset);
+	mmiowb();
+	b43legacy_write16(dev, B43legacy_MMIO_PHY_DATA, val);
+}
+
+void b43legacy_phy_calibrate(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+
+	b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD); /* Dummy read. */
+	if (phy->calibrated)
+		return;
+	if (phy->type == B43legacy_PHYTYPE_G && phy->rev == 1) {
+		b43legacy_wireless_core_reset(dev, 0);
+		b43legacy_phy_initg(dev);
+		b43legacy_wireless_core_reset(dev, B43legacy_TMSLOW_GMODE);
+	}
+	phy->calibrated = 1;
+}
+
+/* intialize B PHY power control
+ * as described in http://bcm-specs.sipsolutions.net/InitPowerControl
+ */
+static void b43legacy_phy_init_pctl(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 saved_batt = 0;
+	u16 saved_ratt = 0;
+	u16 saved_txctl1 = 0;
+	int must_reset_txpower = 0;
+
+	B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B ||
+			  phy->type == B43legacy_PHYTYPE_G));
+	if (is_bcm_board_vendor(dev) &&
+	    (dev->dev->bus->boardinfo.type == 0x0416))
+		return;
+
+	b43legacy_phy_write(dev, 0x0028, 0x8018);
+	b43legacy_write16(dev, 0x03E6, b43legacy_read16(dev, 0x03E6) & 0xFFDF);
+
+	if (phy->type == B43legacy_PHYTYPE_G) {
+		if (!phy->gmode)
+			return;
+		b43legacy_phy_write(dev, 0x047A, 0xC111);
+	}
+	if (phy->savedpctlreg != 0xFFFF)
+		return;
+#ifdef CONFIG_B43LEGACY_DEBUG
+	if (phy->manual_txpower_control)
+		return;
+#endif
+
+	if (phy->type == B43legacy_PHYTYPE_B &&
+	    phy->rev >= 2 &&
+	    phy->radio_ver == 0x2050)
+		b43legacy_radio_write16(dev, 0x0076,
+					b43legacy_radio_read16(dev, 0x0076)
+					| 0x0084);
+	else {
+		saved_batt = phy->bbatt;
+		saved_ratt = phy->rfatt;
+		saved_txctl1 = phy->txctl1;
+		if ((phy->radio_rev >= 6) && (phy->radio_rev <= 8)
+		    && /*FIXME: incomplete specs for 5 < revision < 9 */ 0)
+			b43legacy_radio_set_txpower_bg(dev, 0xB, 0x1F, 0);
+		else
+			b43legacy_radio_set_txpower_bg(dev, 0xB, 9, 0);
+		must_reset_txpower = 1;
+	}
+	b43legacy_dummy_transmission(dev);
+
+	phy->savedpctlreg = b43legacy_phy_read(dev, B43legacy_PHY_G_PCTL);
+
+	if (must_reset_txpower)
+		b43legacy_radio_set_txpower_bg(dev, saved_batt, saved_ratt,
+					       saved_txctl1);
+	else
+		b43legacy_radio_write16(dev, 0x0076, b43legacy_radio_read16(dev,
+					0x0076) & 0xFF7B);
+	b43legacy_radio_clear_tssi(dev);
+}
+
+static void b43legacy_phy_agcsetup(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 offset = 0x0000;
+
+	if (phy->rev == 1)
+		offset = 0x4C00;
+
+	b43legacy_ilt_write(dev, offset, 0x00FE);
+	b43legacy_ilt_write(dev, offset + 1, 0x000D);
+	b43legacy_ilt_write(dev, offset + 2, 0x0013);
+	b43legacy_ilt_write(dev, offset + 3, 0x0019);
+
+	if (phy->rev == 1) {
+		b43legacy_ilt_write(dev, 0x1800, 0x2710);
+		b43legacy_ilt_write(dev, 0x1801, 0x9B83);
+		b43legacy_ilt_write(dev, 0x1802, 0x9B83);
+		b43legacy_ilt_write(dev, 0x1803, 0x0F8D);
+		b43legacy_phy_write(dev, 0x0455, 0x0004);
+	}
+
+	b43legacy_phy_write(dev, 0x04A5, (b43legacy_phy_read(dev, 0x04A5)
+					  & 0x00FF) | 0x5700);
+	b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A)
+					  & 0xFF80) | 0x000F);
+	b43legacy_phy_write(dev, 0x041A, (b43legacy_phy_read(dev, 0x041A)
+					  & 0xC07F) | 0x2B80);
+	b43legacy_phy_write(dev, 0x048C, (b43legacy_phy_read(dev, 0x048C)
+					  & 0xF0FF) | 0x0300);
+
+	b43legacy_radio_write16(dev, 0x007A,
+				b43legacy_radio_read16(dev, 0x007A)
+				| 0x0008);
+
+	b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0)
+			    & 0xFFF0) | 0x0008);
+	b43legacy_phy_write(dev, 0x04A1, (b43legacy_phy_read(dev, 0x04A1)
+			    & 0xF0FF) | 0x0600);
+	b43legacy_phy_write(dev, 0x04A2, (b43legacy_phy_read(dev, 0x04A2)
+			    & 0xF0FF) | 0x0700);
+	b43legacy_phy_write(dev, 0x04A0, (b43legacy_phy_read(dev, 0x04A0)
+			    & 0xF0FF) | 0x0100);
+
+	if (phy->rev == 1)
+		b43legacy_phy_write(dev, 0x04A2,
+				    (b43legacy_phy_read(dev, 0x04A2)
+				    & 0xFFF0) | 0x0007);
+
+	b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488)
+			    & 0xFF00) | 0x001C);
+	b43legacy_phy_write(dev, 0x0488, (b43legacy_phy_read(dev, 0x0488)
+			    & 0xC0FF) | 0x0200);
+	b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496)
+			    & 0xFF00) | 0x001C);
+	b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489)
+			    & 0xFF00) | 0x0020);
+	b43legacy_phy_write(dev, 0x0489, (b43legacy_phy_read(dev, 0x0489)
+			    & 0xC0FF) | 0x0200);
+	b43legacy_phy_write(dev, 0x0482, (b43legacy_phy_read(dev, 0x0482)
+			    & 0xFF00) | 0x002E);
+	b43legacy_phy_write(dev, 0x0496, (b43legacy_phy_read(dev, 0x0496)
+			    & 0x00FF) | 0x1A00);
+	b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481)
+			    & 0xFF00) | 0x0028);
+	b43legacy_phy_write(dev, 0x0481, (b43legacy_phy_read(dev, 0x0481)
+			    & 0x00FF) | 0x2C00);
+
+	if (phy->rev == 1) {
+		b43legacy_phy_write(dev, 0x0430, 0x092B);
+		b43legacy_phy_write(dev, 0x041B,
+				    (b43legacy_phy_read(dev, 0x041B)
+				    & 0xFFE1) | 0x0002);
+	} else {
+		b43legacy_phy_write(dev, 0x041B,
+				    b43legacy_phy_read(dev, 0x041B) & 0xFFE1);
+		b43legacy_phy_write(dev, 0x041F, 0x287A);
+		b43legacy_phy_write(dev, 0x0420,
+				    (b43legacy_phy_read(dev, 0x0420)
+				    & 0xFFF0) | 0x0004);
+	}
+
+	if (phy->rev > 2) {
+		b43legacy_phy_write(dev, 0x0422, 0x287A);
+		b43legacy_phy_write(dev, 0x0420,
+				    (b43legacy_phy_read(dev, 0x0420)
+				    & 0x0FFF) | 0x3000);
+	}
+
+	b43legacy_phy_write(dev, 0x04A8, (b43legacy_phy_read(dev, 0x04A8)
+			    & 0x8080) | 0x7874);
+	b43legacy_phy_write(dev, 0x048E, 0x1C00);
+
+	if (phy->rev == 1) {
+		b43legacy_phy_write(dev, 0x04AB,
+				    (b43legacy_phy_read(dev, 0x04AB)
+				    & 0xF0FF) | 0x0600);
+		b43legacy_phy_write(dev, 0x048B, 0x005E);
+		b43legacy_phy_write(dev, 0x048C,
+				    (b43legacy_phy_read(dev, 0x048C) & 0xFF00)
+				    | 0x001E);
+		b43legacy_phy_write(dev, 0x048D, 0x0002);
+	}
+
+	b43legacy_ilt_write(dev, offset + 0x0800, 0);
+	b43legacy_ilt_write(dev, offset + 0x0801, 7);
+	b43legacy_ilt_write(dev, offset + 0x0802, 16);
+	b43legacy_ilt_write(dev, offset + 0x0803, 28);
+
+	if (phy->rev >= 6) {
+		b43legacy_phy_write(dev, 0x0426,
+				    (b43legacy_phy_read(dev, 0x0426) & 0xFFFC));
+		b43legacy_phy_write(dev, 0x0426,
+				    (b43legacy_phy_read(dev, 0x0426) & 0xEFFF));
+	}
+}
+
+static void b43legacy_phy_setupg(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 i;
+
+	B43legacy_BUG_ON(phy->type != B43legacy_PHYTYPE_G);
+	if (phy->rev == 1) {
+		b43legacy_phy_write(dev, 0x0406, 0x4F19);
+		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+				    (b43legacy_phy_read(dev,
+				    B43legacy_PHY_G_CRS) & 0xFC3F) | 0x0340);
+		b43legacy_phy_write(dev, 0x042C, 0x005A);
+		b43legacy_phy_write(dev, 0x0427, 0x001A);
+
+		for (i = 0; i < B43legacy_ILT_FINEFREQG_SIZE; i++)
+			b43legacy_ilt_write(dev, 0x5800 + i,
+					    b43legacy_ilt_finefreqg[i]);
+		for (i = 0; i < B43legacy_ILT_NOISEG1_SIZE; i++)
+			b43legacy_ilt_write(dev, 0x1800 + i,
+					    b43legacy_ilt_noiseg1[i]);
+		for (i = 0; i < B43legacy_ILT_ROTOR_SIZE; i++)
+			b43legacy_ilt_write32(dev, 0x2000 + i,
+					      b43legacy_ilt_rotor[i]);
+	} else {
+		/* nrssi values are signed 6-bit values. Why 0x7654 here? */
+		b43legacy_nrssi_hw_write(dev, 0xBA98, (s16)0x7654);
+
+		if (phy->rev == 2) {
+			b43legacy_phy_write(dev, 0x04C0, 0x1861);
+			b43legacy_phy_write(dev, 0x04C1, 0x0271);
+		} else if (phy->rev > 2) {
+			b43legacy_phy_write(dev, 0x04C0, 0x0098);
+			b43legacy_phy_write(dev, 0x04C1, 0x0070);
+			b43legacy_phy_write(dev, 0x04C9, 0x0080);
+		}
+		b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev,
+				    0x042B) | 0x800);
+
+		for (i = 0; i < 64; i++)
+			b43legacy_ilt_write(dev, 0x4000 + i, i);
+		for (i = 0; i < B43legacy_ILT_NOISEG2_SIZE; i++)
+			b43legacy_ilt_write(dev, 0x1800 + i,
+					    b43legacy_ilt_noiseg2[i]);
+	}
+
+	if (phy->rev <= 2)
+		for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
+			b43legacy_ilt_write(dev, 0x1400 + i,
+					    b43legacy_ilt_noisescaleg1[i]);
+	else if ((phy->rev >= 7) && (b43legacy_phy_read(dev, 0x0449) & 0x0200))
+		for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
+			b43legacy_ilt_write(dev, 0x1400 + i,
+					    b43legacy_ilt_noisescaleg3[i]);
+	else
+		for (i = 0; i < B43legacy_ILT_NOISESCALEG_SIZE; i++)
+			b43legacy_ilt_write(dev, 0x1400 + i,
+					    b43legacy_ilt_noisescaleg2[i]);
+
+	if (phy->rev == 2)
+		for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++)
+			b43legacy_ilt_write(dev, 0x5000 + i,
+					    b43legacy_ilt_sigmasqr1[i]);
+	else if ((phy->rev > 2) && (phy->rev <= 8))
+		for (i = 0; i < B43legacy_ILT_SIGMASQR_SIZE; i++)
+			b43legacy_ilt_write(dev, 0x5000 + i,
+					    b43legacy_ilt_sigmasqr2[i]);
+
+	if (phy->rev == 1) {
+		for (i = 0; i < B43legacy_ILT_RETARD_SIZE; i++)
+			b43legacy_ilt_write32(dev, 0x2400 + i,
+					      b43legacy_ilt_retard[i]);
+		for (i = 4; i < 20; i++)
+			b43legacy_ilt_write(dev, 0x5400 + i, 0x0020);
+		b43legacy_phy_agcsetup(dev);
+
+		if (is_bcm_board_vendor(dev) &&
+		    (dev->dev->bus->boardinfo.type == 0x0416) &&
+		    (dev->dev->bus->boardinfo.rev == 0x0017))
+			return;
+
+		b43legacy_ilt_write(dev, 0x5001, 0x0002);
+		b43legacy_ilt_write(dev, 0x5002, 0x0001);
+	} else {
+		for (i = 0; i <= 0x20; i++)
+			b43legacy_ilt_write(dev, 0x1000 + i, 0x0820);
+		b43legacy_phy_agcsetup(dev);
+		b43legacy_phy_read(dev, 0x0400); /* dummy read */
+		b43legacy_phy_write(dev, 0x0403, 0x1000);
+		b43legacy_ilt_write(dev, 0x3C02, 0x000F);
+		b43legacy_ilt_write(dev, 0x3C03, 0x0014);
+
+		if (is_bcm_board_vendor(dev) &&
+		    (dev->dev->bus->boardinfo.type == 0x0416) &&
+		    (dev->dev->bus->boardinfo.rev == 0x0017))
+			return;
+
+		b43legacy_ilt_write(dev, 0x0401, 0x0002);
+		b43legacy_ilt_write(dev, 0x0402, 0x0001);
+	}
+}
+
+/* Initialize the APHY portion of a GPHY. */
+static void b43legacy_phy_inita(struct b43legacy_wldev *dev)
+{
+
+	might_sleep();
+
+	b43legacy_phy_setupg(dev);
+	if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_PACTRL)
+		b43legacy_phy_write(dev, 0x046E, 0x03CF);
+}
+
+static void b43legacy_phy_initb2(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 offset;
+	int val;
+
+	b43legacy_write16(dev, 0x03EC, 0x3F22);
+	b43legacy_phy_write(dev, 0x0020, 0x301C);
+	b43legacy_phy_write(dev, 0x0026, 0x0000);
+	b43legacy_phy_write(dev, 0x0030, 0x00C6);
+	b43legacy_phy_write(dev, 0x0088, 0x3E00);
+	val = 0x3C3D;
+	for (offset = 0x0089; offset < 0x00A7; offset++) {
+		b43legacy_phy_write(dev, offset, val);
+		val -= 0x0202;
+	}
+	b43legacy_phy_write(dev, 0x03E4, 0x3000);
+	b43legacy_radio_selectchannel(dev, phy->channel, 0);
+	if (phy->radio_ver != 0x2050) {
+		b43legacy_radio_write16(dev, 0x0075, 0x0080);
+		b43legacy_radio_write16(dev, 0x0079, 0x0081);
+	}
+	b43legacy_radio_write16(dev, 0x0050, 0x0020);
+	b43legacy_radio_write16(dev, 0x0050, 0x0023);
+	if (phy->radio_ver == 0x2050) {
+		b43legacy_radio_write16(dev, 0x0050, 0x0020);
+		b43legacy_radio_write16(dev, 0x005A, 0x0070);
+		b43legacy_radio_write16(dev, 0x005B, 0x007B);
+		b43legacy_radio_write16(dev, 0x005C, 0x00B0);
+		b43legacy_radio_write16(dev, 0x007A, 0x000F);
+		b43legacy_phy_write(dev, 0x0038, 0x0677);
+		b43legacy_radio_init2050(dev);
+	}
+	b43legacy_phy_write(dev, 0x0014, 0x0080);
+	b43legacy_phy_write(dev, 0x0032, 0x00CA);
+	b43legacy_phy_write(dev, 0x0032, 0x00CC);
+	b43legacy_phy_write(dev, 0x0035, 0x07C2);
+	b43legacy_phy_lo_b_measure(dev);
+	b43legacy_phy_write(dev, 0x0026, 0xCC00);
+	if (phy->radio_ver != 0x2050)
+		b43legacy_phy_write(dev, 0x0026, 0xCE00);
+	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1000);
+	b43legacy_phy_write(dev, 0x002A, 0x88A3);
+	if (phy->radio_ver != 0x2050)
+		b43legacy_phy_write(dev, 0x002A, 0x88C2);
+	b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
+	b43legacy_phy_init_pctl(dev);
+}
+
+static void b43legacy_phy_initb4(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 offset;
+	u16 val;
+
+	b43legacy_write16(dev, 0x03EC, 0x3F22);
+	b43legacy_phy_write(dev, 0x0020, 0x301C);
+	b43legacy_phy_write(dev, 0x0026, 0x0000);
+	b43legacy_phy_write(dev, 0x0030, 0x00C6);
+	b43legacy_phy_write(dev, 0x0088, 0x3E00);
+	val = 0x3C3D;
+	for (offset = 0x0089; offset < 0x00A7; offset++) {
+		b43legacy_phy_write(dev, offset, val);
+		val -= 0x0202;
+	}
+	b43legacy_phy_write(dev, 0x03E4, 0x3000);
+	b43legacy_radio_selectchannel(dev, phy->channel, 0);
+	if (phy->radio_ver != 0x2050) {
+		b43legacy_radio_write16(dev, 0x0075, 0x0080);
+		b43legacy_radio_write16(dev, 0x0079, 0x0081);
+	}
+	b43legacy_radio_write16(dev, 0x0050, 0x0020);
+	b43legacy_radio_write16(dev, 0x0050, 0x0023);
+	if (phy->radio_ver == 0x2050) {
+		b43legacy_radio_write16(dev, 0x0050, 0x0020);
+		b43legacy_radio_write16(dev, 0x005A, 0x0070);
+		b43legacy_radio_write16(dev, 0x005B, 0x007B);
+		b43legacy_radio_write16(dev, 0x005C, 0x00B0);
+		b43legacy_radio_write16(dev, 0x007A, 0x000F);
+		b43legacy_phy_write(dev, 0x0038, 0x0677);
+		b43legacy_radio_init2050(dev);
+	}
+	b43legacy_phy_write(dev, 0x0014, 0x0080);
+	b43legacy_phy_write(dev, 0x0032, 0x00CA);
+	if (phy->radio_ver == 0x2050)
+		b43legacy_phy_write(dev, 0x0032, 0x00E0);
+	b43legacy_phy_write(dev, 0x0035, 0x07C2);
+
+	b43legacy_phy_lo_b_measure(dev);
+
+	b43legacy_phy_write(dev, 0x0026, 0xCC00);
+	if (phy->radio_ver == 0x2050)
+		b43legacy_phy_write(dev, 0x0026, 0xCE00);
+	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x1100);
+	b43legacy_phy_write(dev, 0x002A, 0x88A3);
+	if (phy->radio_ver == 0x2050)
+		b43legacy_phy_write(dev, 0x002A, 0x88C2);
+	b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
+	if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI) {
+		b43legacy_calc_nrssi_slope(dev);
+		b43legacy_calc_nrssi_threshold(dev);
+	}
+	b43legacy_phy_init_pctl(dev);
+}
+
+static void b43legacy_phy_initb5(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 offset;
+	u16 value;
+	u8 old_channel;
+
+	if (phy->analog == 1)
+		b43legacy_radio_write16(dev, 0x007A,
+					b43legacy_radio_read16(dev, 0x007A)
+					| 0x0050);
+	if (!is_bcm_board_vendor(dev) &&
+	    (dev->dev->bus->boardinfo.type != 0x0416)) {
+		value = 0x2120;
+		for (offset = 0x00A8 ; offset < 0x00C7; offset++) {
+			b43legacy_phy_write(dev, offset, value);
+			value += 0x0202;
+		}
+	}
+	b43legacy_phy_write(dev, 0x0035,
+			    (b43legacy_phy_read(dev, 0x0035) & 0xF0FF)
+			    | 0x0700);
+	if (phy->radio_ver == 0x2050)
+		b43legacy_phy_write(dev, 0x0038, 0x0667);
+
+	if (phy->gmode) {
+		if (phy->radio_ver == 0x2050) {
+			b43legacy_radio_write16(dev, 0x007A,
+					b43legacy_radio_read16(dev, 0x007A)
+					| 0x0020);
+			b43legacy_radio_write16(dev, 0x0051,
+					b43legacy_radio_read16(dev, 0x0051)
+					| 0x0004);
+		}
+		b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO, 0x0000);
+
+		b43legacy_phy_write(dev, 0x0802, b43legacy_phy_read(dev, 0x0802)
+				    | 0x0100);
+		b43legacy_phy_write(dev, 0x042B, b43legacy_phy_read(dev, 0x042B)
+				    | 0x2000);
+
+		b43legacy_phy_write(dev, 0x001C, 0x186A);
+
+		b43legacy_phy_write(dev, 0x0013, (b43legacy_phy_read(dev,
+				    0x0013) & 0x00FF) | 0x1900);
+		b43legacy_phy_write(dev, 0x0035, (b43legacy_phy_read(dev,
+				    0x0035) & 0xFFC0) | 0x0064);
+		b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev,
+				    0x005D) & 0xFF80) | 0x000A);
+	}
+
+	if (dev->bad_frames_preempt)
+		b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
+				    b43legacy_phy_read(dev,
+				    B43legacy_PHY_RADIO_BITFIELD) | (1 << 11));
+
+	if (phy->analog == 1) {
+		b43legacy_phy_write(dev, 0x0026, 0xCE00);
+		b43legacy_phy_write(dev, 0x0021, 0x3763);
+		b43legacy_phy_write(dev, 0x0022, 0x1BC3);
+		b43legacy_phy_write(dev, 0x0023, 0x06F9);
+		b43legacy_phy_write(dev, 0x0024, 0x037E);
+	} else
+		b43legacy_phy_write(dev, 0x0026, 0xCC00);
+	b43legacy_phy_write(dev, 0x0030, 0x00C6);
+	b43legacy_write16(dev, 0x03EC, 0x3F22);
+
+	if (phy->analog == 1)
+		b43legacy_phy_write(dev, 0x0020, 0x3E1C);
+	else
+		b43legacy_phy_write(dev, 0x0020, 0x301C);
+
+	if (phy->analog == 0)
+		b43legacy_write16(dev, 0x03E4, 0x3000);
+
+	old_channel = (phy->channel == 0xFF) ? 1 : phy->channel;
+	/* Force to channel 7, even if not supported. */
+	b43legacy_radio_selectchannel(dev, 7, 0);
+
+	if (phy->radio_ver != 0x2050) {
+		b43legacy_radio_write16(dev, 0x0075, 0x0080);
+		b43legacy_radio_write16(dev, 0x0079, 0x0081);
+	}
+
+	b43legacy_radio_write16(dev, 0x0050, 0x0020);
+	b43legacy_radio_write16(dev, 0x0050, 0x0023);
+
+	if (phy->radio_ver == 0x2050) {
+		b43legacy_radio_write16(dev, 0x0050, 0x0020);
+		b43legacy_radio_write16(dev, 0x005A, 0x0070);
+	}
+
+	b43legacy_radio_write16(dev, 0x005B, 0x007B);
+	b43legacy_radio_write16(dev, 0x005C, 0x00B0);
+
+	b43legacy_radio_write16(dev, 0x007A, b43legacy_radio_read16(dev,
+				0x007A) | 0x0007);
+
+	b43legacy_radio_selectchannel(dev, old_channel, 0);
+
+	b43legacy_phy_write(dev, 0x0014, 0x0080);
+	b43legacy_phy_write(dev, 0x0032, 0x00CA);
+	b43legacy_phy_write(dev, 0x002A, 0x88A3);
+
+	b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
+
+	if (phy->radio_ver == 0x2050)
+		b43legacy_radio_write16(dev, 0x005D, 0x000D);
+
+	b43legacy_write16(dev, 0x03E4, (b43legacy_read16(dev, 0x03E4) &
+			  0xFFC0) | 0x0004);
+}
+
+static void b43legacy_phy_initb6(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 offset;
+	u16 val;
+	u8 old_channel;
+
+	b43legacy_phy_write(dev, 0x003E, 0x817A);
+	b43legacy_radio_write16(dev, 0x007A,
+				(b43legacy_radio_read16(dev, 0x007A) | 0x0058));
+	if (phy->radio_rev == 4 ||
+	     phy->radio_rev == 5) {
+		b43legacy_radio_write16(dev, 0x0051, 0x0037);
+		b43legacy_radio_write16(dev, 0x0052, 0x0070);
+		b43legacy_radio_write16(dev, 0x0053, 0x00B3);
+		b43legacy_radio_write16(dev, 0x0054, 0x009B);
+		b43legacy_radio_write16(dev, 0x005A, 0x0088);
+		b43legacy_radio_write16(dev, 0x005B, 0x0088);
+		b43legacy_radio_write16(dev, 0x005D, 0x0088);
+		b43legacy_radio_write16(dev, 0x005E, 0x0088);
+		b43legacy_radio_write16(dev, 0x007D, 0x0088);
+		b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+				      B43legacy_UCODEFLAGS_OFFSET,
+				      (b43legacy_shm_read32(dev,
+				      B43legacy_SHM_SHARED,
+				      B43legacy_UCODEFLAGS_OFFSET)
+				      | 0x00000200));
+	}
+	if (phy->radio_rev == 8) {
+		b43legacy_radio_write16(dev, 0x0051, 0x0000);
+		b43legacy_radio_write16(dev, 0x0052, 0x0040);
+		b43legacy_radio_write16(dev, 0x0053, 0x00B7);
+		b43legacy_radio_write16(dev, 0x0054, 0x0098);
+		b43legacy_radio_write16(dev, 0x005A, 0x0088);
+		b43legacy_radio_write16(dev, 0x005B, 0x006B);
+		b43legacy_radio_write16(dev, 0x005C, 0x000F);
+		if (dev->dev->bus->sprom.r1.boardflags_lo & 0x8000) {
+			b43legacy_radio_write16(dev, 0x005D, 0x00FA);
+			b43legacy_radio_write16(dev, 0x005E, 0x00D8);
+		} else {
+			b43legacy_radio_write16(dev, 0x005D, 0x00F5);
+			b43legacy_radio_write16(dev, 0x005E, 0x00B8);
+		}
+		b43legacy_radio_write16(dev, 0x0073, 0x0003);
+		b43legacy_radio_write16(dev, 0x007D, 0x00A8);
+		b43legacy_radio_write16(dev, 0x007C, 0x0001);
+		b43legacy_radio_write16(dev, 0x007E, 0x0008);
+	}
+	val = 0x1E1F;
+	for (offset = 0x0088; offset < 0x0098; offset++) {
+		b43legacy_phy_write(dev, offset, val);
+		val -= 0x0202;
+	}
+	val = 0x3E3F;
+	for (offset = 0x0098; offset < 0x00A8; offset++) {
+		b43legacy_phy_write(dev, offset, val);
+		val -= 0x0202;
+	}
+	val = 0x2120;
+	for (offset = 0x00A8; offset < 0x00C8; offset++) {
+		b43legacy_phy_write(dev, offset, (val & 0x3F3F));
+		val += 0x0202;
+	}
+	if (phy->type == B43legacy_PHYTYPE_G) {
+		b43legacy_radio_write16(dev, 0x007A,
+					b43legacy_radio_read16(dev, 0x007A) |
+					0x0020);
+		b43legacy_radio_write16(dev, 0x0051,
+					b43legacy_radio_read16(dev, 0x0051) |
+					0x0004);
+		b43legacy_phy_write(dev, 0x0802,
+				    b43legacy_phy_read(dev, 0x0802) | 0x0100);
+		b43legacy_phy_write(dev, 0x042B,
+				    b43legacy_phy_read(dev, 0x042B) | 0x2000);
+		b43legacy_phy_write(dev, 0x5B, 0x0000);
+		b43legacy_phy_write(dev, 0x5C, 0x0000);
+	}
+
+	old_channel = phy->channel;
+	if (old_channel >= 8)
+		b43legacy_radio_selectchannel(dev, 1, 0);
+	else
+		b43legacy_radio_selectchannel(dev, 13, 0);
+
+	b43legacy_radio_write16(dev, 0x0050, 0x0020);
+	b43legacy_radio_write16(dev, 0x0050, 0x0023);
+	udelay(40);
+	if (phy->radio_rev < 6 || phy->radio_rev == 8) {
+		b43legacy_radio_write16(dev, 0x007C,
+					(b43legacy_radio_read16(dev, 0x007C)
+					| 0x0002));
+		b43legacy_radio_write16(dev, 0x0050, 0x0020);
+	}
+	if (phy->radio_rev <= 2) {
+		b43legacy_radio_write16(dev, 0x007C, 0x0020);
+		b43legacy_radio_write16(dev, 0x005A, 0x0070);
+		b43legacy_radio_write16(dev, 0x005B, 0x007B);
+		b43legacy_radio_write16(dev, 0x005C, 0x00B0);
+	}
+	b43legacy_radio_write16(dev, 0x007A,
+				(b43legacy_radio_read16(dev,
+				0x007A) & 0x00F8) | 0x0007);
+
+	b43legacy_radio_selectchannel(dev, old_channel, 0);
+
+	b43legacy_phy_write(dev, 0x0014, 0x0200);
+	if (phy->radio_rev >= 6)
+		b43legacy_phy_write(dev, 0x002A, 0x88C2);
+	else
+		b43legacy_phy_write(dev, 0x002A, 0x8AC0);
+	b43legacy_phy_write(dev, 0x0038, 0x0668);
+	b43legacy_radio_set_txpower_bg(dev, 0xFFFF, 0xFFFF, 0xFFFF);
+	if (phy->radio_rev <= 5)
+		b43legacy_phy_write(dev, 0x005D, (b43legacy_phy_read(dev,
+				    0x005D) & 0xFF80) | 0x0003);
+	if (phy->radio_rev <= 2)
+		b43legacy_radio_write16(dev, 0x005D, 0x000D);
+
+	if (phy->analog == 4) {
+		b43legacy_write16(dev, 0x03E4, 0x0009);
+		b43legacy_phy_write(dev, 0x61, b43legacy_phy_read(dev, 0x61)
+				    & 0xFFF);
+	} else
+		b43legacy_phy_write(dev, 0x0002, (b43legacy_phy_read(dev,
+				    0x0002) & 0xFFC0) | 0x0004);
+	if (phy->type == B43legacy_PHYTYPE_G)
+		b43legacy_write16(dev, 0x03E6, 0x0);
+	if (phy->type == B43legacy_PHYTYPE_B) {
+		b43legacy_write16(dev, 0x03E6, 0x8140);
+		b43legacy_phy_write(dev, 0x0016, 0x0410);
+		b43legacy_phy_write(dev, 0x0017, 0x0820);
+		b43legacy_phy_write(dev, 0x0062, 0x0007);
+		b43legacy_radio_init2050(dev);
+		b43legacy_phy_lo_g_measure(dev);
+		if (dev->dev->bus->sprom.r1.boardflags_lo &
+		    B43legacy_BFL_RSSI) {
+			b43legacy_calc_nrssi_slope(dev);
+			b43legacy_calc_nrssi_threshold(dev);
+		}
+		b43legacy_phy_init_pctl(dev);
+	}
+}
+
+static void b43legacy_calc_loopback_gain(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 backup_phy[15] = {0};
+	u16 backup_radio[3];
+	u16 backup_bband;
+	u16 i;
+	u16 loop1_cnt;
+	u16 loop1_done;
+	u16 loop1_omitted;
+	u16 loop2_done;
+
+	backup_phy[0] = b43legacy_phy_read(dev, 0x0429);
+	backup_phy[1] = b43legacy_phy_read(dev, 0x0001);
+	backup_phy[2] = b43legacy_phy_read(dev, 0x0811);
+	backup_phy[3] = b43legacy_phy_read(dev, 0x0812);
+	if (phy->rev != 1) {
+		backup_phy[4] = b43legacy_phy_read(dev, 0x0814);
+		backup_phy[5] = b43legacy_phy_read(dev, 0x0815);
+	}
+	backup_phy[6] = b43legacy_phy_read(dev, 0x005A);
+	backup_phy[7] = b43legacy_phy_read(dev, 0x0059);
+	backup_phy[8] = b43legacy_phy_read(dev, 0x0058);
+	backup_phy[9] = b43legacy_phy_read(dev, 0x000A);
+	backup_phy[10] = b43legacy_phy_read(dev, 0x0003);
+	backup_phy[11] = b43legacy_phy_read(dev, 0x080F);
+	backup_phy[12] = b43legacy_phy_read(dev, 0x0810);
+	backup_phy[13] = b43legacy_phy_read(dev, 0x002B);
+	backup_phy[14] = b43legacy_phy_read(dev, 0x0015);
+	b43legacy_phy_read(dev, 0x002D); /* dummy read */
+	backup_bband = phy->bbatt;
+	backup_radio[0] = b43legacy_radio_read16(dev, 0x0052);
+	backup_radio[1] = b43legacy_radio_read16(dev, 0x0043);
+	backup_radio[2] = b43legacy_radio_read16(dev, 0x007A);
+
+	b43legacy_phy_write(dev, 0x0429,
+			    b43legacy_phy_read(dev, 0x0429) & 0x3FFF);
+	b43legacy_phy_write(dev, 0x0001,
+			    b43legacy_phy_read(dev, 0x0001) & 0x8000);
+	b43legacy_phy_write(dev, 0x0811,
+			    b43legacy_phy_read(dev, 0x0811) | 0x0002);
+	b43legacy_phy_write(dev, 0x0812,
+			    b43legacy_phy_read(dev, 0x0812) & 0xFFFD);
+	b43legacy_phy_write(dev, 0x0811,
+			    b43legacy_phy_read(dev, 0x0811) | 0x0001);
+	b43legacy_phy_write(dev, 0x0812,
+			    b43legacy_phy_read(dev, 0x0812) & 0xFFFE);
+	if (phy->rev != 1) {
+		b43legacy_phy_write(dev, 0x0814,
+				    b43legacy_phy_read(dev, 0x0814) | 0x0001);
+		b43legacy_phy_write(dev, 0x0815,
+				    b43legacy_phy_read(dev, 0x0815) & 0xFFFE);
+		b43legacy_phy_write(dev, 0x0814,
+				    b43legacy_phy_read(dev, 0x0814) | 0x0002);
+		b43legacy_phy_write(dev, 0x0815,
+				    b43legacy_phy_read(dev, 0x0815) & 0xFFFD);
+	}
+	b43legacy_phy_write(dev, 0x0811, b43legacy_phy_read(dev, 0x0811) |
+			    0x000C);
+	b43legacy_phy_write(dev, 0x0812, b43legacy_phy_read(dev, 0x0812) |
+			    0x000C);
+
+	b43legacy_phy_write(dev, 0x0811, (b43legacy_phy_read(dev, 0x0811)
+			    & 0xFFCF) | 0x0030);
+	b43legacy_phy_write(dev, 0x0812, (b43legacy_phy_read(dev, 0x0812)
+			    & 0xFFCF) | 0x0010);
+
+	b43legacy_phy_write(dev, 0x005A, 0x0780);
+	b43legacy_phy_write(dev, 0x0059, 0xC810);
+	b43legacy_phy_write(dev, 0x0058, 0x000D);
+	if (phy->analog == 0)
+		b43legacy_phy_write(dev, 0x0003, 0x0122);
+	else
+		b43legacy_phy_write(dev, 0x000A,
+				    b43legacy_phy_read(dev, 0x000A)
+				    | 0x2000);
+	if (phy->rev != 1) {
+		b43legacy_phy_write(dev, 0x0814,
+				    b43legacy_phy_read(dev, 0x0814) | 0x0004);
+		b43legacy_phy_write(dev, 0x0815,
+				    b43legacy_phy_read(dev, 0x0815) & 0xFFFB);
+	}
+	b43legacy_phy_write(dev, 0x0003,
+			    (b43legacy_phy_read(dev, 0x0003)
+			     & 0xFF9F) | 0x0040);
+	if (phy->radio_ver == 0x2050 && phy->radio_rev == 2) {
+		b43legacy_radio_write16(dev, 0x0052, 0x0000);
+		b43legacy_radio_write16(dev, 0x0043,
+					(b43legacy_radio_read16(dev, 0x0043)
+					 & 0xFFF0) | 0x0009);
+		loop1_cnt = 9;
+	} else if (phy->radio_rev == 8) {
+		b43legacy_radio_write16(dev, 0x0043, 0x000F);
+		loop1_cnt = 15;
+	} else
+		loop1_cnt = 0;
+
+	b43legacy_phy_set_baseband_attenuation(dev, 11);
+
+	if (phy->rev >= 3)
+		b43legacy_phy_write(dev, 0x080F, 0xC020);
+	else
+		b43legacy_phy_write(dev, 0x080F, 0x8020);
+	b43legacy_phy_write(dev, 0x0810, 0x0000);
+
+	b43legacy_phy_write(dev, 0x002B,
+			    (b43legacy_phy_read(dev, 0x002B)
+			     & 0xFFC0) | 0x0001);
+	b43legacy_phy_write(dev, 0x002B,
+			    (b43legacy_phy_read(dev, 0x002B)
+			     & 0xC0FF) | 0x0800);
+	b43legacy_phy_write(dev, 0x0811,
+			    b43legacy_phy_read(dev, 0x0811) | 0x0100);
+	b43legacy_phy_write(dev, 0x0812,
+			    b43legacy_phy_read(dev, 0x0812) & 0xCFFF);
+	if (dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_EXTLNA) {
+		if (phy->rev >= 7) {
+			b43legacy_phy_write(dev, 0x0811,
+					    b43legacy_phy_read(dev, 0x0811)
+					    | 0x0800);
+			b43legacy_phy_write(dev, 0x0812,
+					    b43legacy_phy_read(dev, 0x0812)
+					    | 0x8000);
+		}
+	}
+	b43legacy_radio_write16(dev, 0x007A,
+				b43legacy_radio_read16(dev, 0x007A)
+				& 0x00F7);
+
+	for (i = 0; i < loop1_cnt; i++) {
+		b43legacy_radio_write16(dev, 0x0043, loop1_cnt);
+		b43legacy_phy_write(dev, 0x0812,
+				    (b43legacy_phy_read(dev, 0x0812)
+				     & 0xF0FF) | (i << 8));
+		b43legacy_phy_write(dev, 0x0015,
+				    (b43legacy_phy_read(dev, 0x0015)
+				     & 0x0FFF) | 0xA000);
+		b43legacy_phy_write(dev, 0x0015,
+				    (b43legacy_phy_read(dev, 0x0015)
+				     & 0x0FFF) | 0xF000);
+		udelay(20);
+		if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC)
+			break;
+	}
+	loop1_done = i;
+	loop1_omitted = loop1_cnt - loop1_done;
+
+	loop2_done = 0;
+	if (loop1_done >= 8) {
+		b43legacy_phy_write(dev, 0x0812,
+				    b43legacy_phy_read(dev, 0x0812)
+				    | 0x0030);
+		for (i = loop1_done - 8; i < 16; i++) {
+			b43legacy_phy_write(dev, 0x0812,
+					    (b43legacy_phy_read(dev, 0x0812)
+					     & 0xF0FF) | (i << 8));
+			b43legacy_phy_write(dev, 0x0015,
+					    (b43legacy_phy_read(dev, 0x0015)
+					     & 0x0FFF) | 0xA000);
+			b43legacy_phy_write(dev, 0x0015,
+					    (b43legacy_phy_read(dev, 0x0015)
+					     & 0x0FFF) | 0xF000);
+			udelay(20);
+			if (b43legacy_phy_read(dev, 0x002D) >= 0x0DFC)
+				break;
+		}
+	}
+
+	if (phy->rev != 1) {
+		b43legacy_phy_write(dev, 0x0814, backup_phy[4]);
+		b43legacy_phy_write(dev, 0x0815, backup_phy[5]);
+	}
+	b43legacy_phy_write(dev, 0x005A, backup_phy[6]);
+	b43legacy_phy_write(dev, 0x0059, backup_phy[7]);
+	b43legacy_phy_write(dev, 0x0058, backup_phy[8]);
+	b43legacy_phy_write(dev, 0x000A, backup_phy[9]);
+	b43legacy_phy_write(dev, 0x0003, backup_phy[10]);
+	b43legacy_phy_write(dev, 0x080F, backup_phy[11]);
+	b43legacy_phy_write(dev, 0x0810, backup_phy[12]);
+	b43legacy_phy_write(dev, 0x002B, backup_phy[13]);
+	b43legacy_phy_write(dev, 0x0015, backup_phy[14]);
+
+	b43legacy_phy_set_baseband_attenuation(dev, backup_bband);
+
+	b43legacy_radio_write16(dev, 0x0052, backup_radio[0]);
+	b43legacy_radio_write16(dev, 0x0043, backup_radio[1]);
+	b43legacy_radio_write16(dev, 0x007A, backup_radio[2]);
+
+	b43legacy_phy_write(dev, 0x0811, backup_phy[2] | 0x0003);
+	udelay(10);
+	b43legacy_phy_write(dev, 0x0811, backup_phy[2]);
+	b43legacy_phy_write(dev, 0x0812, backup_phy[3]);
+	b43legacy_phy_write(dev, 0x0429, backup_phy[0]);
+	b43legacy_phy_write(dev, 0x0001, backup_phy[1]);
+
+	phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11;
+	phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2;
+}
+
+static void b43legacy_phy_initg(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 tmp;
+
+	if (phy->rev == 1)
+		b43legacy_phy_initb5(dev);
+	else
+		b43legacy_phy_initb6(dev);
+	if (phy->rev >= 2 || phy->gmode)
+		b43legacy_phy_inita(dev);
+
+	if (phy->rev >= 2) {
+		b43legacy_phy_write(dev, 0x0814, 0x0000);
+		b43legacy_phy_write(dev, 0x0815, 0x0000);
+	}
+	if (phy->rev == 2) {
+		b43legacy_phy_write(dev, 0x0811, 0x0000);
+		b43legacy_phy_write(dev, 0x0015, 0x00C0);
+	}
+	if (phy->rev > 5) {
+		b43legacy_phy_write(dev, 0x0811, 0x0400);
+		b43legacy_phy_write(dev, 0x0015, 0x00C0);
+	}
+	if (phy->rev >= 2 || phy->gmode) {
+		tmp = b43legacy_phy_read(dev, 0x0400) & 0xFF;
+		if (tmp == 3 || tmp == 5) {
+			b43legacy_phy_write(dev, 0x04C2, 0x1816);
+			b43legacy_phy_write(dev, 0x04C3, 0x8006);
+			if (tmp == 5)
+				b43legacy_phy_write(dev, 0x04CC,
+						    (b43legacy_phy_read(dev,
+						     0x04CC) & 0x00FF) |
+						     0x1F00);
+		}
+		b43legacy_phy_write(dev, 0x047E, 0x0078);
+	}
+	if (phy->radio_rev == 8) {
+		b43legacy_phy_write(dev, 0x0801, b43legacy_phy_read(dev, 0x0801)
+				    | 0x0080);
+		b43legacy_phy_write(dev, 0x043E, b43legacy_phy_read(dev, 0x043E)
+				    | 0x0004);
+	}
+	if (phy->rev >= 2 && phy->gmode)
+		b43legacy_calc_loopback_gain(dev);
+	if (phy->radio_rev != 8) {
+		if (phy->initval == 0xFFFF)
+			phy->initval = b43legacy_radio_init2050(dev);
+		else
+			b43legacy_radio_write16(dev, 0x0078, phy->initval);
+	}
+	if (phy->txctl2 == 0xFFFF)
+		b43legacy_phy_lo_g_measure(dev);
+	else {
+		if (phy->radio_ver == 0x2050 && phy->radio_rev == 8)
+			b43legacy_radio_write16(dev, 0x0052,
+						(phy->txctl1 << 4) |
+						phy->txctl2);
+		else
+			b43legacy_radio_write16(dev, 0x0052,
+						(b43legacy_radio_read16(dev,
+						 0x0052) & 0xFFF0) |
+						 phy->txctl1);
+		if (phy->rev >= 6)
+			b43legacy_phy_write(dev, 0x0036,
+					    (b43legacy_phy_read(dev, 0x0036)
+					     & 0x0FFF) | (phy->txctl2 << 12));
+		if (dev->dev->bus->sprom.r1.boardflags_lo &
+		    B43legacy_BFL_PACTRL)
+			b43legacy_phy_write(dev, 0x002E, 0x8075);
+		else
+			b43legacy_phy_write(dev, 0x002E, 0x807F);
+		if (phy->rev < 2)
+			b43legacy_phy_write(dev, 0x002F, 0x0101);
+		else
+			b43legacy_phy_write(dev, 0x002F, 0x0202);
+	}
+	if (phy->gmode || phy->rev >= 2) {
+		b43legacy_phy_lo_adjust(dev, 0);
+		b43legacy_phy_write(dev, 0x080F, 0x8078);
+	}
+
+	if (!(dev->dev->bus->sprom.r1.boardflags_lo & B43legacy_BFL_RSSI)) {
+		/* The specs state to update the NRSSI LT with
+		 * the value 0x7FFFFFFF here. I think that is some weird
+		 * compiler optimization in the original driver.
+		 * Essentially, what we do here is resetting all NRSSI LT
+		 * entries to -32 (see the limit_value() in nrssi_hw_update())
+		 */
+		b43legacy_nrssi_hw_update(dev, 0xFFFF);
+		b43legacy_calc_nrssi_threshold(dev);
+	} else if (phy->gmode || phy->rev >= 2) {
+		if (phy->nrssi[0] == -1000) {
+			B43legacy_WARN_ON(phy->nrssi[1] != -1000);
+			b43legacy_calc_nrssi_slope(dev);
+		} else {
+			B43legacy_WARN_ON(phy->nrssi[1] == -1000);
+			b43legacy_calc_nrssi_threshold(dev);
+		}
+	}
+	if (phy->radio_rev == 8)
+		b43legacy_phy_write(dev, 0x0805, 0x3230);
+	b43legacy_phy_init_pctl(dev);
+	if (dev->dev->bus->chip_id == 0x4306
+	    && dev->dev->bus->chip_package == 2) {
+		b43legacy_phy_write(dev, 0x0429,
+				    b43legacy_phy_read(dev, 0x0429) & 0xBFFF);
+		b43legacy_phy_write(dev, 0x04C3,
+				    b43legacy_phy_read(dev, 0x04C3) & 0x7FFF);
+	}
+}
+
+static u16 b43legacy_phy_lo_b_r15_loop(struct b43legacy_wldev *dev)
+{
+	int i;
+	u16 ret = 0;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	for (i = 0; i < 10; i++) {
+		b43legacy_phy_write(dev, 0x0015, 0xAFA0);
+		udelay(1);
+		b43legacy_phy_write(dev, 0x0015, 0xEFA0);
+		udelay(10);
+		b43legacy_phy_write(dev, 0x0015, 0xFFA0);
+		udelay(40);
+		ret += b43legacy_phy_read(dev, 0x002C);
+	}
+	local_irq_restore(flags);
+	b43legacy_voluntary_preempt();
+
+	return ret;
+}
+
+void b43legacy_phy_lo_b_measure(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 regstack[12] = { 0 };
+	u16 mls;
+	u16 fval;
+	int i;
+	int j;
+
+	regstack[0] = b43legacy_phy_read(dev, 0x0015);
+	regstack[1] = b43legacy_radio_read16(dev, 0x0052) & 0xFFF0;
+
+	if (phy->radio_ver == 0x2053) {
+		regstack[2] = b43legacy_phy_read(dev, 0x000A);
+		regstack[3] = b43legacy_phy_read(dev, 0x002A);
+		regstack[4] = b43legacy_phy_read(dev, 0x0035);
+		regstack[5] = b43legacy_phy_read(dev, 0x0003);
+		regstack[6] = b43legacy_phy_read(dev, 0x0001);
+		regstack[7] = b43legacy_phy_read(dev, 0x0030);
+
+		regstack[8] = b43legacy_radio_read16(dev, 0x0043);
+		regstack[9] = b43legacy_radio_read16(dev, 0x007A);
+		regstack[10] = b43legacy_read16(dev, 0x03EC);
+		regstack[11] = b43legacy_radio_read16(dev, 0x0052) & 0x00F0;
+
+		b43legacy_phy_write(dev, 0x0030, 0x00FF);
+		b43legacy_write16(dev, 0x03EC, 0x3F3F);
+		b43legacy_phy_write(dev, 0x0035, regstack[4] & 0xFF7F);
+		b43legacy_radio_write16(dev, 0x007A, regstack[9] & 0xFFF0);
+	}
+	b43legacy_phy_write(dev, 0x0015, 0xB000);
+	b43legacy_phy_write(dev, 0x002B, 0x0004);
+
+	if (phy->radio_ver == 0x2053) {
+		b43legacy_phy_write(dev, 0x002B, 0x0203);
+		b43legacy_phy_write(dev, 0x002A, 0x08A3);
+	}
+
+	phy->minlowsig[0] = 0xFFFF;
+
+	for (i = 0; i < 4; i++) {
+		b43legacy_radio_write16(dev, 0x0052, regstack[1] | i);
+		b43legacy_phy_lo_b_r15_loop(dev);
+	}
+	for (i = 0; i < 10; i++) {
+		b43legacy_radio_write16(dev, 0x0052, regstack[1] | i);
+		mls = b43legacy_phy_lo_b_r15_loop(dev) / 10;
+		if (mls < phy->minlowsig[0]) {
+			phy->minlowsig[0] = mls;
+			phy->minlowsigpos[0] = i;
+		}
+	}
+	b43legacy_radio_write16(dev, 0x0052, regstack[1]
+				| phy->minlowsigpos[0]);
+
+	phy->minlowsig[1] = 0xFFFF;
+
+	for (i = -4; i < 5; i += 2) {
+		for (j = -4; j < 5; j += 2) {
+			if (j < 0)
+				fval = (0x0100 * i) + j + 0x0100;
+			else
+				fval = (0x0100 * i) + j;
+			b43legacy_phy_write(dev, 0x002F, fval);
+			mls = b43legacy_phy_lo_b_r15_loop(dev) / 10;
+			if (mls < phy->minlowsig[1]) {
+				phy->minlowsig[1] = mls;
+				phy->minlowsigpos[1] = fval;
+			}
+		}
+	}
+	phy->minlowsigpos[1] += 0x0101;
+
+	b43legacy_phy_write(dev, 0x002F, phy->minlowsigpos[1]);
+	if (phy->radio_ver == 0x2053) {
+		b43legacy_phy_write(dev, 0x000A, regstack[2]);
+		b43legacy_phy_write(dev, 0x002A, regstack[3]);
+		b43legacy_phy_write(dev, 0x0035, regstack[4]);
+		b43legacy_phy_write(dev, 0x0003, regstack[5]);
+		b43legacy_phy_write(dev, 0x0001, regstack[6]);
+		b43legacy_phy_write(dev, 0x0030, regstack[7]);
+
+		b43legacy_radio_write16(dev, 0x0043, regstack[8]);
+		b43legacy_radio_write16(dev, 0x007A, regstack[9]);
+
+		b43legacy_radio_write16(dev, 0x0052,
+					(b43legacy_radio_read16(dev, 0x0052)
+					& 0x000F) | regstack[11]);
+
+		b43legacy_write16(dev, 0x03EC, regstack[10]);
+	}
+	b43legacy_phy_write(dev, 0x0015, regstack[0]);
+}
+
+static inline
+u16 b43legacy_phy_lo_g_deviation_subval(struct b43legacy_wldev *dev,
+					u16 control)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 ret;
+	unsigned long flags;
+
+	local_irq_save(flags);
+	if (phy->gmode) {
+		b43legacy_phy_write(dev, 0x15, 0xE300);
+		control <<= 8;
+		b43legacy_phy_write(dev, 0x0812, control | 0x00B0);
+		udelay(5);
+		b43legacy_phy_write(dev, 0x0812, control | 0x00B2);
+		udelay(2);
+		b43legacy_phy_write(dev, 0x0812, control | 0x00B3);
+		udelay(4);
+		b43legacy_phy_write(dev, 0x0015, 0xF300);
+		udelay(8);
+	} else {
+		b43legacy_phy_write(dev, 0x0015, control | 0xEFA0);
+		udelay(2);
+		b43legacy_phy_write(dev, 0x0015, control | 0xEFE0);
+		udelay(4);
+		b43legacy_phy_write(dev, 0x0015, control | 0xFFE0);
+		udelay(8);
+	}
+	ret = b43legacy_phy_read(dev, 0x002D);
+	local_irq_restore(flags);
+	b43legacy_voluntary_preempt();
+
+	return ret;
+}
+
+static u32 b43legacy_phy_lo_g_singledeviation(struct b43legacy_wldev *dev,
+					      u16 control)
+{
+	int i;
+	u32 ret = 0;
+
+	for (i = 0; i < 8; i++)
+		ret += b43legacy_phy_lo_g_deviation_subval(dev, control);
+
+	return ret;
+}
+
+/* Write the LocalOscillator CONTROL */
+static inline
+void b43legacy_lo_write(struct b43legacy_wldev *dev,
+			struct b43legacy_lopair *pair)
+{
+	u16 value;
+
+	value = (u8)(pair->low);
+	value |= ((u8)(pair->high)) << 8;
+
+#ifdef CONFIG_B43LEGACY_DEBUG
+	/* Sanity check. */
+	if (pair->low < -8 || pair->low > 8 ||
+	    pair->high < -8 || pair->high > 8) {
+		struct b43legacy_phy *phy = &dev->phy;
+		b43legacydbg(dev->wl,
+		       "WARNING: Writing invalid LOpair "
+		       "(low: %d, high: %d, index: %lu)\n",
+		       pair->low, pair->high,
+		       (unsigned long)(pair - phy->_lo_pairs));
+		dump_stack();
+	}
+#endif
+
+	b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, value);
+}
+
+static inline
+struct b43legacy_lopair *b43legacy_find_lopair(struct b43legacy_wldev *dev,
+					       u16 bbatt,
+					       u16 rfatt,
+					       u16 tx)
+{
+	static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 };
+	struct b43legacy_phy *phy = &dev->phy;
+
+	if (bbatt > 6)
+		bbatt = 6;
+	B43legacy_WARN_ON(rfatt >= 10);
+
+	if (tx == 3)
+		return b43legacy_get_lopair(phy, rfatt, bbatt);
+	return b43legacy_get_lopair(phy, dict[rfatt], bbatt);
+}
+
+static inline
+struct b43legacy_lopair *b43legacy_current_lopair(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+
+	return b43legacy_find_lopair(dev, phy->bbatt,
+				     phy->rfatt, phy->txctl1);
+}
+
+/* Adjust B/G LO */
+void b43legacy_phy_lo_adjust(struct b43legacy_wldev *dev, int fixed)
+{
+	struct b43legacy_lopair *pair;
+
+	if (fixed) {
+		/* Use fixed values. Only for initialization. */
+		pair = b43legacy_find_lopair(dev, 2, 3, 0);
+	} else
+		pair = b43legacy_current_lopair(dev);
+	b43legacy_lo_write(dev, pair);
+}
+
+static void b43legacy_phy_lo_g_measure_txctl2(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 txctl2 = 0;
+	u16 i;
+	u32 smallest;
+	u32 tmp;
+
+	b43legacy_radio_write16(dev, 0x0052, 0x0000);
+	udelay(10);
+	smallest = b43legacy_phy_lo_g_singledeviation(dev, 0);
+	for (i = 0; i < 16; i++) {
+		b43legacy_radio_write16(dev, 0x0052, i);
+		udelay(10);
+		tmp = b43legacy_phy_lo_g_singledeviation(dev, 0);
+		if (tmp < smallest) {
+			smallest = tmp;
+			txctl2 = i;
+		}
+	}
+	phy->txctl2 = txctl2;
+}
+
+static
+void b43legacy_phy_lo_g_state(struct b43legacy_wldev *dev,
+			      const struct b43legacy_lopair *in_pair,
+			      struct b43legacy_lopair *out_pair,
+			      u16 r27)
+{
+	static const struct b43legacy_lopair transitions[8] = {
+		{ .high =  1,  .low =  1, },
+		{ .high =  1,  .low =  0, },
+		{ .high =  1,  .low = -1, },
+		{ .high =  0,  .low = -1, },
+		{ .high = -1,  .low = -1, },
+		{ .high = -1,  .low =  0, },
+		{ .high = -1,  .low =  1, },
+		{ .high =  0,  .low =  1, },
+	};
+	struct b43legacy_lopair lowest_transition = {
+		.high = in_pair->high,
+		.low = in_pair->low,
+	};
+	struct b43legacy_lopair tmp_pair;
+	struct b43legacy_lopair transition;
+	int i = 12;
+	int state = 0;
+	int found_lower;
+	int j;
+	int begin;
+	int end;
+	u32 lowest_deviation;
+	u32 tmp;
+
+	/* Note that in_pair and out_pair can point to the same pair.
+	 * Be careful. */
+
+	b43legacy_lo_write(dev, &lowest_transition);
+	lowest_deviation = b43legacy_phy_lo_g_singledeviation(dev, r27);
+	do {
+		found_lower = 0;
+		B43legacy_WARN_ON(!(state >= 0 && state <= 8));
+		if (state == 0) {
+			begin = 1;
+			end = 8;
+		} else if (state % 2 == 0) {
+			begin = state - 1;
+			end = state + 1;
+		} else {
+			begin = state - 2;
+			end = state + 2;
+		}
+		if (begin < 1)
+			begin += 8;
+		if (end > 8)
+			end -= 8;
+
+		j = begin;
+		tmp_pair.high = lowest_transition.high;
+		tmp_pair.low = lowest_transition.low;
+		while (1) {
+			B43legacy_WARN_ON(!(j >= 1 && j <= 8));
+			transition.high = tmp_pair.high +
+					  transitions[j - 1].high;
+			transition.low = tmp_pair.low + transitions[j - 1].low;
+			if ((abs(transition.low) < 9)
+			     && (abs(transition.high) < 9)) {
+				b43legacy_lo_write(dev, &transition);
+				tmp = b43legacy_phy_lo_g_singledeviation(dev,
+								       r27);
+				if (tmp < lowest_deviation) {
+					lowest_deviation = tmp;
+					state = j;
+					found_lower = 1;
+
+					lowest_transition.high =
+								transition.high;
+					lowest_transition.low = transition.low;
+				}
+			}
+			if (j == end)
+				break;
+			if (j == 8)
+				j = 1;
+			else
+				j++;
+		}
+	} while (i-- && found_lower);
+
+	out_pair->high = lowest_transition.high;
+	out_pair->low = lowest_transition.low;
+}
+
+/* Set the baseband attenuation value on chip. */
+void b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev,
+					    u16 bbatt)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 value;
+
+	if (phy->analog == 0) {
+		value = (b43legacy_read16(dev, 0x03E6) & 0xFFF0);
+		value |= (bbatt & 0x000F);
+		b43legacy_write16(dev, 0x03E6, value);
+		return;
+	}
+
+	if (phy->analog > 1) {
+		value = b43legacy_phy_read(dev, 0x0060) & 0xFFC3;
+		value |= (bbatt << 2) & 0x003C;
+	} else {
+		value = b43legacy_phy_read(dev, 0x0060) & 0xFF87;
+		value |= (bbatt << 3) & 0x0078;
+	}
+	b43legacy_phy_write(dev, 0x0060, value);
+}
+
+/* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */
+void b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev)
+{
+	static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 };
+	const int is_initializing = (b43legacy_status(dev)
+				     < B43legacy_STAT_STARTED);
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 h;
+	u16 i;
+	u16 oldi = 0;
+	u16 j;
+	struct b43legacy_lopair control;
+	struct b43legacy_lopair *tmp_control;
+	u16 tmp;
+	u16 regstack[16] = { 0 };
+	u8 oldchannel;
+
+	/* XXX: What are these? */
+	u8 r27 = 0;
+	u16 r31;
+
+	oldchannel = phy->channel;
+	/* Setup */
+	if (phy->gmode) {
+		regstack[0] = b43legacy_phy_read(dev, B43legacy_PHY_G_CRS);
+		regstack[1] = b43legacy_phy_read(dev, 0x0802);
+		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]
+				    & 0x7FFF);
+		b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC);
+	}
+	regstack[3] = b43legacy_read16(dev, 0x03E2);
+	b43legacy_write16(dev, 0x03E2, regstack[3] | 0x8000);
+	regstack[4] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
+	regstack[5] = b43legacy_phy_read(dev, 0x15);
+	regstack[6] = b43legacy_phy_read(dev, 0x2A);
+	regstack[7] = b43legacy_phy_read(dev, 0x35);
+	regstack[8] = b43legacy_phy_read(dev, 0x60);
+	regstack[9] = b43legacy_radio_read16(dev, 0x43);
+	regstack[10] = b43legacy_radio_read16(dev, 0x7A);
+	regstack[11] = b43legacy_radio_read16(dev, 0x52);
+	if (phy->gmode) {
+		regstack[12] = b43legacy_phy_read(dev, 0x0811);
+		regstack[13] = b43legacy_phy_read(dev, 0x0812);
+		regstack[14] = b43legacy_phy_read(dev, 0x0814);
+		regstack[15] = b43legacy_phy_read(dev, 0x0815);
+	}
+	b43legacy_radio_selectchannel(dev, 6, 0);
+	if (phy->gmode) {
+		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]
+				    & 0x7FFF);
+		b43legacy_phy_write(dev, 0x0802, regstack[1] & 0xFFFC);
+		b43legacy_dummy_transmission(dev);
+	}
+	b43legacy_radio_write16(dev, 0x0043, 0x0006);
+
+	b43legacy_phy_set_baseband_attenuation(dev, 2);
+
+	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, 0x0000);
+	b43legacy_phy_write(dev, 0x002E, 0x007F);
+	b43legacy_phy_write(dev, 0x080F, 0x0078);
+	b43legacy_phy_write(dev, 0x0035, regstack[7] & ~(1 << 7));
+	b43legacy_radio_write16(dev, 0x007A, regstack[10] & 0xFFF0);
+	b43legacy_phy_write(dev, 0x002B, 0x0203);
+	b43legacy_phy_write(dev, 0x002A, 0x08A3);
+	if (phy->gmode) {
+		b43legacy_phy_write(dev, 0x0814, regstack[14] | 0x0003);
+		b43legacy_phy_write(dev, 0x0815, regstack[15] & 0xFFFC);
+		b43legacy_phy_write(dev, 0x0811, 0x01B3);
+		b43legacy_phy_write(dev, 0x0812, 0x00B2);
+	}
+	if (is_initializing)
+		b43legacy_phy_lo_g_measure_txctl2(dev);
+	b43legacy_phy_write(dev, 0x080F, 0x8078);
+
+	/* Measure */
+	control.low = 0;
+	control.high = 0;
+	for (h = 0; h < 10; h++) {
+		/* Loop over each possible RadioAttenuation (0-9) */
+		i = pairorder[h];
+		if (is_initializing) {
+			if (i == 3) {
+				control.low = 0;
+				control.high = 0;
+			} else if (((i % 2 == 1) && (oldi % 2 == 1)) ||
+				  ((i % 2 == 0) && (oldi % 2 == 0))) {
+				tmp_control = b43legacy_get_lopair(phy, oldi,
+								   0);
+				memcpy(&control, tmp_control, sizeof(control));
+			} else {
+				tmp_control = b43legacy_get_lopair(phy, 3, 0);
+				memcpy(&control, tmp_control, sizeof(control));
+			}
+		}
+		/* Loop over each possible BasebandAttenuation/2 */
+		for (j = 0; j < 4; j++) {
+			if (is_initializing) {
+				tmp = i * 2 + j;
+				r27 = 0;
+				r31 = 0;
+				if (tmp > 14) {
+					r31 = 1;
+					if (tmp > 17)
+						r27 = 1;
+					if (tmp > 19)
+						r27 = 2;
+				}
+			} else {
+				tmp_control = b43legacy_get_lopair(phy, i,
+								   j * 2);
+				if (!tmp_control->used)
+					continue;
+				memcpy(&control, tmp_control, sizeof(control));
+				r27 = 3;
+				r31 = 0;
+			}
+			b43legacy_radio_write16(dev, 0x43, i);
+			b43legacy_radio_write16(dev, 0x52, phy->txctl2);
+			udelay(10);
+			b43legacy_voluntary_preempt();
+
+			b43legacy_phy_set_baseband_attenuation(dev, j * 2);
+
+			tmp = (regstack[10] & 0xFFF0);
+			if (r31)
+				tmp |= 0x0008;
+			b43legacy_radio_write16(dev, 0x007A, tmp);
+
+			tmp_control = b43legacy_get_lopair(phy, i, j * 2);
+			b43legacy_phy_lo_g_state(dev, &control, tmp_control,
+						 r27);
+		}
+		oldi = i;
+	}
+	/* Loop over each possible RadioAttenuation (10-13) */
+	for (i = 10; i < 14; i++) {
+		/* Loop over each possible BasebandAttenuation/2 */
+		for (j = 0; j < 4; j++) {
+			if (is_initializing) {
+				tmp_control = b43legacy_get_lopair(phy, i - 9,
+								 j * 2);
+				memcpy(&control, tmp_control, sizeof(control));
+				/* FIXME: The next line is wrong, as the
+				 * following if statement can never trigger. */
+				tmp = (i - 9) * 2 + j - 5;
+				r27 = 0;
+				r31 = 0;
+				if (tmp > 14) {
+					r31 = 1;
+					if (tmp > 17)
+						r27 = 1;
+					if (tmp > 19)
+						r27 = 2;
+				}
+			} else {
+				tmp_control = b43legacy_get_lopair(phy, i - 9,
+								   j * 2);
+				if (!tmp_control->used)
+					continue;
+				memcpy(&control, tmp_control, sizeof(control));
+				r27 = 3;
+				r31 = 0;
+			}
+			b43legacy_radio_write16(dev, 0x43, i - 9);
+			/* FIXME: shouldn't txctl1 be zero in the next line
+			 * and 3 in the loop above? */
+			b43legacy_radio_write16(dev, 0x52,
+					      phy->txctl2
+					      | (3/*txctl1*/ << 4));
+			udelay(10);
+			b43legacy_voluntary_preempt();
+
+			b43legacy_phy_set_baseband_attenuation(dev, j * 2);
+
+			tmp = (regstack[10] & 0xFFF0);
+			if (r31)
+				tmp |= 0x0008;
+			b43legacy_radio_write16(dev, 0x7A, tmp);
+
+			tmp_control = b43legacy_get_lopair(phy, i, j * 2);
+			b43legacy_phy_lo_g_state(dev, &control, tmp_control,
+						 r27);
+		}
+	}
+
+	/* Restoration */
+	if (phy->gmode) {
+		b43legacy_phy_write(dev, 0x0015, 0xE300);
+		b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA0);
+		udelay(5);
+		b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA2);
+		udelay(2);
+		b43legacy_phy_write(dev, 0x0812, (r27 << 8) | 0xA3);
+		b43legacy_voluntary_preempt();
+	} else
+		b43legacy_phy_write(dev, 0x0015, r27 | 0xEFA0);
+	b43legacy_phy_lo_adjust(dev, is_initializing);
+	b43legacy_phy_write(dev, 0x002E, 0x807F);
+	if (phy->gmode)
+		b43legacy_phy_write(dev, 0x002F, 0x0202);
+	else
+		b43legacy_phy_write(dev, 0x002F, 0x0101);
+	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, regstack[4]);
+	b43legacy_phy_write(dev, 0x0015, regstack[5]);
+	b43legacy_phy_write(dev, 0x002A, regstack[6]);
+	b43legacy_phy_write(dev, 0x0035, regstack[7]);
+	b43legacy_phy_write(dev, 0x0060, regstack[8]);
+	b43legacy_radio_write16(dev, 0x0043, regstack[9]);
+	b43legacy_radio_write16(dev, 0x007A, regstack[10]);
+	regstack[11] &= 0x00F0;
+	regstack[11] |= (b43legacy_radio_read16(dev, 0x52) & 0x000F);
+	b43legacy_radio_write16(dev, 0x52, regstack[11]);
+	b43legacy_write16(dev, 0x03E2, regstack[3]);
+	if (phy->gmode) {
+		b43legacy_phy_write(dev, 0x0811, regstack[12]);
+		b43legacy_phy_write(dev, 0x0812, regstack[13]);
+		b43legacy_phy_write(dev, 0x0814, regstack[14]);
+		b43legacy_phy_write(dev, 0x0815, regstack[15]);
+		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS, regstack[0]);
+		b43legacy_phy_write(dev, 0x0802, regstack[1]);
+	}
+	b43legacy_radio_selectchannel(dev, oldchannel, 1);
+
+#ifdef CONFIG_B43LEGACY_DEBUG
+	{
+		/* Sanity check for all lopairs. */
+		for (i = 0; i < B43legacy_LO_COUNT; i++) {
+			tmp_control = phy->_lo_pairs + i;
+			if (tmp_control->low < -8 || tmp_control->low > 8 ||
+			    tmp_control->high < -8 || tmp_control->high > 8)
+				b43legacywarn(dev->wl,
+				       "WARNING: Invalid LOpair (low: %d, high:"
+				       " %d, index: %d)\n",
+				       tmp_control->low, tmp_control->high, i);
+		}
+	}
+#endif /* CONFIG_B43LEGACY_DEBUG */
+}
+
+static
+void b43legacy_phy_lo_mark_current_used(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_lopair *pair;
+
+	pair = b43legacy_current_lopair(dev);
+	pair->used = 1;
+}
+
+void b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	struct b43legacy_lopair *pair;
+	int i;
+
+	for (i = 0; i < B43legacy_LO_COUNT; i++) {
+		pair = phy->_lo_pairs + i;
+		pair->used = 0;
+	}
+}
+
+/* http://bcm-specs.sipsolutions.net/EstimatePowerOut
+ * This function converts a TSSI value to dBm in Q5.2
+ */
+static s8 b43legacy_phy_estimate_power_out(struct b43legacy_wldev *dev, s8 tssi)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	s8 dbm = 0;
+	s32 tmp;
+
+	tmp = phy->idle_tssi;
+	tmp += tssi;
+	tmp -= phy->savedpctlreg;
+
+	switch (phy->type) {
+	case B43legacy_PHYTYPE_B:
+	case B43legacy_PHYTYPE_G:
+		tmp = limit_value(tmp, 0x00, 0x3F);
+		dbm = phy->tssi2dbm[tmp];
+		break;
+	default:
+		B43legacy_BUG_ON(1);
+	}
+
+	return dbm;
+}
+
+/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */
+void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 tmp;
+	u16 txpower;
+	s8 v0;
+	s8 v1;
+	s8 v2;
+	s8 v3;
+	s8 average;
+	int max_pwr;
+	s16 desired_pwr;
+	s16 estimated_pwr;
+	s16 pwr_adjust;
+	s16 radio_att_delta;
+	s16 baseband_att_delta;
+	s16 radio_attenuation;
+	s16 baseband_attenuation;
+	unsigned long phylock_flags;
+
+	if (phy->savedpctlreg == 0xFFFF)
+		return;
+	if ((dev->dev->bus->boardinfo.type == 0x0416) &&
+	    is_bcm_board_vendor(dev))
+		return;
+#ifdef CONFIG_B43LEGACY_DEBUG
+	if (phy->manual_txpower_control)
+		return;
+#endif
+
+	B43legacy_BUG_ON(!(phy->type == B43legacy_PHYTYPE_B ||
+			 phy->type == B43legacy_PHYTYPE_G));
+	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0058);
+	v0 = (s8)(tmp & 0x00FF);
+	v1 = (s8)((tmp & 0xFF00) >> 8);
+	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005A);
+	v2 = (s8)(tmp & 0x00FF);
+	v3 = (s8)((tmp & 0xFF00) >> 8);
+	tmp = 0;
+
+	if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) {
+		tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+					 0x0070);
+		v0 = (s8)(tmp & 0x00FF);
+		v1 = (s8)((tmp & 0xFF00) >> 8);
+		tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED,
+					 0x0072);
+		v2 = (s8)(tmp & 0x00FF);
+		v3 = (s8)((tmp & 0xFF00) >> 8);
+		if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F)
+			return;
+		v0 = (v0 + 0x20) & 0x3F;
+		v1 = (v1 + 0x20) & 0x3F;
+		v2 = (v2 + 0x20) & 0x3F;
+		v3 = (v3 + 0x20) & 0x3F;
+		tmp = 1;
+	}
+	b43legacy_radio_clear_tssi(dev);
+
+	average = (v0 + v1 + v2 + v3 + 2) / 4;
+
+	if (tmp && (b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x005E)
+	    & 0x8))
+		average -= 13;
+
+	estimated_pwr = b43legacy_phy_estimate_power_out(dev, average);
+
+	max_pwr = dev->dev->bus->sprom.r1.maxpwr_bg;
+
+	if ((dev->dev->bus->sprom.r1.boardflags_lo
+	     & B43legacy_BFL_PACTRL) &&
+	    (phy->type == B43legacy_PHYTYPE_G))
+		max_pwr -= 0x3;
+	if (unlikely(max_pwr <= 0)) {
+		b43legacywarn(dev->wl, "Invalid max-TX-power value in SPROM."
+			"\n");
+		max_pwr = 74; /* fake it */
+		dev->dev->bus->sprom.r1.maxpwr_bg = max_pwr;
+	}
+
+	/* Use regulatory information to get the maximum power.
+	 * In the absence of such data from mac80211, we will use 20 dBm, which
+	 * is the value for the EU, US, Canada, and most of the world.
+	 * The regulatory maximum is reduced by the antenna gain (from sprom)
+	 * and 1.5 dBm (a safety factor??). The result is in Q5.2 format
+	 * which accounts for the factor of 4 */
+#define REG_MAX_PWR 20
+	max_pwr = min(REG_MAX_PWR * 4 - dev->dev->bus->sprom.r1.antenna_gain_bg
+		      - 0x6, max_pwr);
+
+	/* find the desired power in Q5.2 - power_level is in dBm
+	 * and limit it - max_pwr is already in Q5.2 */
+	desired_pwr = limit_value(phy->power_level << 2, 0, max_pwr);
+	if (b43legacy_debug(dev, B43legacy_DBG_XMITPOWER))
+		b43legacydbg(dev->wl, "Current TX power output: " Q52_FMT
+		       " dBm, Desired TX power output: " Q52_FMT
+		       " dBm\n", Q52_ARG(estimated_pwr),
+		       Q52_ARG(desired_pwr));
+	/* Check if we need to adjust the current power. The factor of 2 is
+	 * for damping */
+	pwr_adjust = (desired_pwr - estimated_pwr) / 2;
+	/* RF attenuation delta
+	 * The minus sign is because lower attenuation => more power */
+	radio_att_delta = -(pwr_adjust + 7) >> 3;
+	/* Baseband attenuation delta */
+	baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta);
+	/* Do we need to adjust anything? */
+	if ((radio_att_delta == 0) && (baseband_att_delta == 0)) {
+		b43legacy_phy_lo_mark_current_used(dev);
+		return;
+	}
+
+	/* Calculate the new attenuation values. */
+	baseband_attenuation = phy->bbatt;
+	baseband_attenuation += baseband_att_delta;
+	radio_attenuation = phy->rfatt;
+	radio_attenuation += radio_att_delta;
+
+	/* Get baseband and radio attenuation values into permitted ranges.
+	 * baseband 0-11, radio 0-9.
+	 * Radio attenuation affects power level 4 times as much as baseband.
+	 */
+	if (radio_attenuation < 0) {
+		baseband_attenuation -= (4 * -radio_attenuation);
+		radio_attenuation = 0;
+	} else if (radio_attenuation > 9) {
+		baseband_attenuation += (4 * (radio_attenuation - 9));
+		radio_attenuation = 9;
+	} else {
+		while (baseband_attenuation < 0 && radio_attenuation > 0) {
+			baseband_attenuation += 4;
+			radio_attenuation--;
+		}
+		while (baseband_attenuation > 11 && radio_attenuation < 9) {
+			baseband_attenuation -= 4;
+			radio_attenuation++;
+		}
+	}
+	baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
+
+	txpower = phy->txctl1;
+	if ((phy->radio_ver == 0x2050) && (phy->radio_rev == 2)) {
+		if (radio_attenuation <= 1) {
+			if (txpower == 0) {
+				txpower = 3;
+				radio_attenuation += 2;
+				baseband_attenuation += 2;
+			} else if (dev->dev->bus->sprom.r1.boardflags_lo
+				   & B43legacy_BFL_PACTRL) {
+				baseband_attenuation += 4 *
+						     (radio_attenuation - 2);
+				radio_attenuation = 2;
+			}
+		} else if (radio_attenuation > 4 && txpower != 0) {
+			txpower = 0;
+			if (baseband_attenuation < 3) {
+				radio_attenuation -= 3;
+				baseband_attenuation += 2;
+			} else {
+				radio_attenuation -= 2;
+				baseband_attenuation -= 2;
+			}
+		}
+	}
+	/* Save the control values */
+	phy->txctl1 = txpower;
+	baseband_attenuation = limit_value(baseband_attenuation, 0, 11);
+	radio_attenuation = limit_value(radio_attenuation, 0, 9);
+	phy->rfatt = radio_attenuation;
+	phy->bbatt = baseband_attenuation;
+
+	/* Adjust the hardware */
+	b43legacy_phy_lock(dev, phylock_flags);
+	b43legacy_radio_lock(dev);
+	b43legacy_radio_set_txpower_bg(dev, baseband_attenuation,
+				       radio_attenuation, txpower);
+	b43legacy_phy_lo_mark_current_used(dev);
+	b43legacy_radio_unlock(dev);
+	b43legacy_phy_unlock(dev, phylock_flags);
+}
+
+static inline
+s32 b43legacy_tssi2dbm_ad(s32 num, s32 den)
+{
+	if (num < 0)
+		return num/den;
+	else
+		return (num+den/2)/den;
+}
+
+static inline
+s8 b43legacy_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2)
+{
+	s32 m1;
+	s32 m2;
+	s32 f = 256;
+	s32 q;
+	s32 delta;
+	s8 i = 0;
+
+	m1 = b43legacy_tssi2dbm_ad(16 * pab0 + index * pab1, 32);
+	m2 = max(b43legacy_tssi2dbm_ad(32768 + index * pab2, 256), 1);
+	do {
+		if (i > 15)
+			return -EINVAL;
+		q = b43legacy_tssi2dbm_ad(f * 4096 -
+					  b43legacy_tssi2dbm_ad(m2 * f, 16) *
+					  f, 2048);
+		delta = abs(q - f);
+		f = q;
+		i++;
+	} while (delta >= 2);
+	entry[index] = limit_value(b43legacy_tssi2dbm_ad(m1 * f, 8192),
+				   -127, 128);
+	return 0;
+}
+
+/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */
+int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	s16 pab0;
+	s16 pab1;
+	s16 pab2;
+	u8 idx;
+	s8 *dyn_tssi2dbm;
+
+	B43legacy_WARN_ON(!(phy->type == B43legacy_PHYTYPE_B ||
+			  phy->type == B43legacy_PHYTYPE_G));
+	pab0 = (s16)(dev->dev->bus->sprom.r1.pa0b0);
+	pab1 = (s16)(dev->dev->bus->sprom.r1.pa0b1);
+	pab2 = (s16)(dev->dev->bus->sprom.r1.pa0b2);
+
+	if ((dev->dev->bus->chip_id == 0x4301) && (phy->radio_ver != 0x2050)) {
+		phy->idle_tssi = 0x34;
+		phy->tssi2dbm = b43legacy_tssi2dbm_b_table;
+		return 0;
+	}
+
+	if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
+	    pab0 != -1 && pab1 != -1 && pab2 != -1) {
+		/* The pabX values are set in SPROM. Use them. */
+		if ((s8)dev->dev->bus->sprom.r1.itssi_bg != 0 &&
+		    (s8)dev->dev->bus->sprom.r1.itssi_bg != -1)
+			phy->idle_tssi = (s8)(dev->dev->bus->sprom.r1.itssi_bg);
+		else
+			phy->idle_tssi = 62;
+		dyn_tssi2dbm = kmalloc(64, GFP_KERNEL);
+		if (dyn_tssi2dbm == NULL) {
+			b43legacyerr(dev->wl, "Could not allocate memory"
+			       "for tssi2dbm table\n");
+			return -ENOMEM;
+		}
+		for (idx = 0; idx < 64; idx++)
+			if (b43legacy_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0,
+						     pab1, pab2)) {
+				phy->tssi2dbm = NULL;
+				b43legacyerr(dev->wl, "Could not generate "
+				       "tssi2dBm table\n");
+				kfree(dyn_tssi2dbm);
+				return -ENODEV;
+			}
+		phy->tssi2dbm = dyn_tssi2dbm;
+		phy->dyn_tssi_tbl = 1;
+	} else {
+		/* pabX values not set in SPROM. */
+		switch (phy->type) {
+		case B43legacy_PHYTYPE_B:
+			phy->idle_tssi = 0x34;
+			phy->tssi2dbm = b43legacy_tssi2dbm_b_table;
+			break;
+		case B43legacy_PHYTYPE_G:
+			phy->idle_tssi = 0x34;
+			phy->tssi2dbm = b43legacy_tssi2dbm_g_table;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+int b43legacy_phy_init(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	int err = -ENODEV;
+
+	switch (phy->type) {
+	case B43legacy_PHYTYPE_B:
+		switch (phy->rev) {
+		case 2:
+			b43legacy_phy_initb2(dev);
+			err = 0;
+			break;
+		case 4:
+			b43legacy_phy_initb4(dev);
+			err = 0;
+			break;
+		case 5:
+			b43legacy_phy_initb5(dev);
+			err = 0;
+			break;
+		case 6:
+			b43legacy_phy_initb6(dev);
+			err = 0;
+			break;
+		}
+		break;
+	case B43legacy_PHYTYPE_G:
+		b43legacy_phy_initg(dev);
+		err = 0;
+		break;
+	}
+	if (err)
+		b43legacyerr(dev->wl, "Unknown PHYTYPE found\n");
+
+	return err;
+}
+
+void b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 antennadiv;
+	u16 offset;
+	u16 value;
+	u32 ucodeflags;
+
+	antennadiv = phy->antenna_diversity;
+
+	if (antennadiv == 0xFFFF)
+		antennadiv = 3;
+	B43legacy_WARN_ON(antennadiv > 3);
+
+	ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
+					  B43legacy_UCODEFLAGS_OFFSET);
+	b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+			      B43legacy_UCODEFLAGS_OFFSET,
+			      ucodeflags & ~B43legacy_UCODEFLAG_AUTODIV);
+
+	switch (phy->type) {
+	case B43legacy_PHYTYPE_G:
+		offset = 0x0400;
+
+		if (antennadiv == 2)
+			value = (3/*automatic*/ << 7);
+		else
+			value = (antennadiv << 7);
+		b43legacy_phy_write(dev, offset + 1,
+				    (b43legacy_phy_read(dev, offset + 1)
+				    & 0x7E7F) | value);
+
+		if (antennadiv >= 2) {
+			if (antennadiv == 2)
+				value = (antennadiv << 7);
+			else
+				value = (0/*force0*/ << 7);
+			b43legacy_phy_write(dev, offset + 0x2B,
+					    (b43legacy_phy_read(dev,
+					    offset + 0x2B)
+					    & 0xFEFF) | value);
+		}
+
+		if (phy->type == B43legacy_PHYTYPE_G) {
+			if (antennadiv >= 2)
+				b43legacy_phy_write(dev, 0x048C,
+						    b43legacy_phy_read(dev,
+						    0x048C) | 0x2000);
+			else
+				b43legacy_phy_write(dev, 0x048C,
+						    b43legacy_phy_read(dev,
+						    0x048C) & ~0x2000);
+			if (phy->rev >= 2) {
+				b43legacy_phy_write(dev, 0x0461,
+						    b43legacy_phy_read(dev,
+						    0x0461) | 0x0010);
+				b43legacy_phy_write(dev, 0x04AD,
+						    (b43legacy_phy_read(dev,
+						    0x04AD)
+						    & 0x00FF) | 0x0015);
+				if (phy->rev == 2)
+					b43legacy_phy_write(dev, 0x0427,
+							    0x0008);
+				else
+					b43legacy_phy_write(dev, 0x0427,
+						(b43legacy_phy_read(dev, 0x0427)
+						 & 0x00FF) | 0x0008);
+			} else if (phy->rev >= 6)
+				b43legacy_phy_write(dev, 0x049B, 0x00DC);
+		} else {
+			if (phy->rev < 3)
+				b43legacy_phy_write(dev, 0x002B,
+						    (b43legacy_phy_read(dev,
+						    0x002B) & 0x00FF)
+						    | 0x0024);
+			else {
+				b43legacy_phy_write(dev, 0x0061,
+						    b43legacy_phy_read(dev,
+						    0x0061) | 0x0010);
+				if (phy->rev == 3) {
+					b43legacy_phy_write(dev, 0x0093,
+							    0x001D);
+					b43legacy_phy_write(dev, 0x0027,
+							    0x0008);
+				} else {
+					b43legacy_phy_write(dev, 0x0093,
+							    0x003A);
+					b43legacy_phy_write(dev, 0x0027,
+						(b43legacy_phy_read(dev, 0x0027)
+						 & 0x00FF) | 0x0008);
+				}
+			}
+		}
+		break;
+	case B43legacy_PHYTYPE_B:
+		if (dev->dev->id.revision == 2)
+			value = (3/*automatic*/ << 7);
+		else
+			value = (antennadiv << 7);
+		b43legacy_phy_write(dev, 0x03E2,
+				    (b43legacy_phy_read(dev, 0x03E2)
+				    & 0xFE7F) | value);
+		break;
+	default:
+		B43legacy_WARN_ON(1);
+	}
+
+	if (antennadiv >= 2) {
+		ucodeflags = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
+						  B43legacy_UCODEFLAGS_OFFSET);
+		b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+				      B43legacy_UCODEFLAGS_OFFSET,
+				      ucodeflags | B43legacy_UCODEFLAG_AUTODIV);
+	}
+
+	phy->antenna_diversity = antennadiv;
+}
+
+/* Set the PowerSavingControlBits.
+ * Bitvalues:
+ *   0  => unset the bit
+ *   1  => set the bit
+ *   -1 => calculate the bit
+ */
+void b43legacy_power_saving_ctl_bits(struct b43legacy_wldev *dev,
+				     int bit25, int bit26)
+{
+	int i;
+	u32 status;
+
+/* FIXME: Force 25 to off and 26 to on for now: */
+bit25 = 0;
+bit26 = 1;
+
+	if (bit25 == -1) {
+		/* TODO: If powersave is not off and FIXME is not set and we
+		 *	are not in adhoc and thus is not an AP and we arei
+		 *	associated, set bit 25 */
+	}
+	if (bit26 == -1) {
+		/* TODO: If the device is awake or this is an AP, or we are
+		 *	scanning, or FIXME, or we are associated, or FIXME,
+		 *	or the latest PS-Poll packet sent was successful,
+		 *	set bit26  */
+	}
+	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+	if (bit25)
+		status |= B43legacy_SBF_PS1;
+	else
+		status &= ~B43legacy_SBF_PS1;
+	if (bit26)
+		status |= B43legacy_SBF_PS2;
+	else
+		status &= ~B43legacy_SBF_PS2;
+	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+	if (bit26 && dev->dev->id.revision >= 5) {
+		for (i = 0; i < 100; i++) {
+			if (b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
+						 0x0040) != 4)
+				break;
+			udelay(10);
+		}
+	}
+}
diff --git a/drivers/net/wireless/b43legacy/phy.h b/drivers/net/wireless/b43legacy/phy.h
new file mode 100644
index 0000000..f11b427
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/phy.h
@@ -0,0 +1,219 @@
+/*
+
+  Broadcom B43legacy wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+		     Stefano Brivio <st3@riseup.net>
+		     Michael Buesch <mbuesch@freenet.de>
+		     Danny van Dyk <kugelfang@gentoo.org>
+		     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+  Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 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 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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef B43legacy_PHY_H_
+#define B43legacy_PHY_H_
+
+#include <linux/types.h>
+
+enum {
+	B43legacy_ANTENNA0,	  /* Antenna 0 */
+	B43legacy_ANTENNA1,	  /* Antenna 0 */
+	B43legacy_ANTENNA_AUTO1,  /* Automatic, starting with antenna 1 */
+	B43legacy_ANTENNA_AUTO0,  /* Automatic, starting with antenna 0 */
+
+	B43legacy_ANTENNA_AUTO	= B43legacy_ANTENNA_AUTO0,
+	B43legacy_ANTENNA_DEFAULT = B43legacy_ANTENNA_AUTO,
+};
+
+enum {
+	B43legacy_INTERFMODE_NONE,
+	B43legacy_INTERFMODE_NONWLAN,
+	B43legacy_INTERFMODE_MANUALWLAN,
+	B43legacy_INTERFMODE_AUTOWLAN,
+};
+
+/*** PHY Registers ***/
+
+/* Routing */
+#define B43legacy_PHYROUTE_OFDM_GPHY	0x400
+#define B43legacy_PHYROUTE_EXT_GPHY	0x800
+
+/* Base registers. */
+#define B43legacy_PHY_BASE(reg)	(reg)
+/* OFDM (A) registers of a G-PHY */
+#define B43legacy_PHY_OFDM(reg)	((reg) | B43legacy_PHYROUTE_OFDM_GPHY)
+/* Extended G-PHY registers */
+#define B43legacy_PHY_EXTG(reg)	((reg) | B43legacy_PHYROUTE_EXT_GPHY)
+
+
+/* Extended G-PHY Registers */
+#define B43legacy_PHY_CLASSCTL		B43legacy_PHY_EXTG(0x02)	/* Classify control */
+#define B43legacy_PHY_GTABCTL		B43legacy_PHY_EXTG(0x03)	/* G-PHY table control (see below) */
+#define  B43legacy_PHY_GTABOFF		0x03FF			/* G-PHY table offset (see below) */
+#define  B43legacy_PHY_GTABNR		0xFC00			/* G-PHY table number (see below) */
+#define  B43legacy_PHY_GTABNR_SHIFT	10
+#define B43legacy_PHY_GTABDATA		B43legacy_PHY_EXTG(0x04)	/* G-PHY table data */
+#define B43legacy_PHY_LO_MASK		B43legacy_PHY_EXTG(0x0F)	/* Local Oscillator control mask */
+#define B43legacy_PHY_LO_CTL		B43legacy_PHY_EXTG(0x10)	/* Local Oscillator control */
+#define B43legacy_PHY_RFOVER		B43legacy_PHY_EXTG(0x11)	/* RF override */
+#define B43legacy_PHY_RFOVERVAL		B43legacy_PHY_EXTG(0x12)	/* RF override value */
+/*** OFDM table numbers ***/
+#define B43legacy_OFDMTAB(number, offset)				\
+			  (((number) << B43legacy_PHY_OTABLENR_SHIFT)	\
+			  | (offset))
+#define B43legacy_OFDMTAB_AGC1		B43legacy_OFDMTAB(0x00, 0)
+#define B43legacy_OFDMTAB_GAIN0		B43legacy_OFDMTAB(0x00, 0)
+#define B43legacy_OFDMTAB_GAINX		B43legacy_OFDMTAB(0x01, 0)
+#define B43legacy_OFDMTAB_GAIN1		B43legacy_OFDMTAB(0x01, 4)
+#define B43legacy_OFDMTAB_AGC3		B43legacy_OFDMTAB(0x02, 0)
+#define B43legacy_OFDMTAB_GAIN2		B43legacy_OFDMTAB(0x02, 3)
+#define B43legacy_OFDMTAB_LNAHPFGAIN1	B43legacy_OFDMTAB(0x03, 0)
+#define B43legacy_OFDMTAB_WRSSI		B43legacy_OFDMTAB(0x04, 0)
+#define B43legacy_OFDMTAB_LNAHPFGAIN2	B43legacy_OFDMTAB(0x04, 0)
+#define B43legacy_OFDMTAB_NOISESCALE	B43legacy_OFDMTAB(0x05, 0)
+#define B43legacy_OFDMTAB_AGC2		B43legacy_OFDMTAB(0x06, 0)
+#define B43legacy_OFDMTAB_ROTOR		B43legacy_OFDMTAB(0x08, 0)
+#define B43legacy_OFDMTAB_ADVRETARD	B43legacy_OFDMTAB(0x09, 0)
+#define B43legacy_OFDMTAB_DAC		B43legacy_OFDMTAB(0x0C, 0)
+#define B43legacy_OFDMTAB_DC		B43legacy_OFDMTAB(0x0E, 7)
+#define B43legacy_OFDMTAB_PWRDYN2	B43legacy_OFDMTAB(0x0E, 12)
+#define B43legacy_OFDMTAB_LNAGAIN	B43legacy_OFDMTAB(0x0E, 13)
+
+#define B43legacy_OFDMTAB_LPFGAIN	B43legacy_OFDMTAB(0x0F, 12)
+#define B43legacy_OFDMTAB_RSSI		B43legacy_OFDMTAB(0x10, 0)
+
+#define B43legacy_OFDMTAB_AGC1_R1	B43legacy_OFDMTAB(0x13, 0)
+#define B43legacy_OFDMTAB_GAINX_R1	B43legacy_OFDMTAB(0x14, 0)
+#define B43legacy_OFDMTAB_MINSIGSQ	B43legacy_OFDMTAB(0x14, 1)
+#define B43legacy_OFDMTAB_AGC3_R1	B43legacy_OFDMTAB(0x15, 0)
+#define B43legacy_OFDMTAB_WRSSI_R1	B43legacy_OFDMTAB(0x15, 4)
+#define B43legacy_OFDMTAB_TSSI		B43legacy_OFDMTAB(0x15, 0)
+#define B43legacy_OFDMTAB_DACRFPABB	B43legacy_OFDMTAB(0x16, 0)
+#define B43legacy_OFDMTAB_DACOFF	B43legacy_OFDMTAB(0x17, 0)
+#define B43legacy_OFDMTAB_DCBIAS	B43legacy_OFDMTAB(0x18, 0)
+
+void b43legacy_put_attenuation_into_ranges(int *_bbatt, int *_rfatt);
+
+/* OFDM (A) PHY Registers */
+#define B43legacy_PHY_VERSION_OFDM	B43legacy_PHY_OFDM(0x00)	/* Versioning register for A-PHY */
+#define B43legacy_PHY_BBANDCFG		B43legacy_PHY_OFDM(0x01)	/* Baseband config */
+#define  B43legacy_PHY_BBANDCFG_RXANT	0x180			/* RX Antenna selection */
+#define  B43legacy_PHY_BBANDCFG_RXANT_SHIFT	7
+#define B43legacy_PHY_PWRDOWN		B43legacy_PHY_OFDM(0x03)	/* Powerdown */
+#define B43legacy_PHY_CRSTHRES1		B43legacy_PHY_OFDM(0x06)	/* CRS Threshold 1 */
+#define B43legacy_PHY_LNAHPFCTL		B43legacy_PHY_OFDM(0x1C)	/* LNA/HPF control */
+#define B43legacy_PHY_ADIVRELATED	B43legacy_PHY_OFDM(0x27)	/* FIXME rename */
+#define B43legacy_PHY_CRS0		B43legacy_PHY_OFDM(0x29)
+#define B43legacy_PHY_ANTDWELL		B43legacy_PHY_OFDM(0x2B)	/* Antenna dwell */
+#define  B43legacy_PHY_ANTDWELL_AUTODIV1	0x0100			/* Automatic RX diversity start antenna */
+#define B43legacy_PHY_ENCORE		B43legacy_PHY_OFDM(0x49)	/* "Encore" (RangeMax / BroadRange) */
+#define  B43legacy_PHY_ENCORE_EN	0x0200				/* Encore enable */
+#define B43legacy_PHY_LMS		B43legacy_PHY_OFDM(0x55)
+#define B43legacy_PHY_OFDM61		B43legacy_PHY_OFDM(0x61)	/* FIXME rename */
+#define  B43legacy_PHY_OFDM61_10	0x0010				/* FIXME rename */
+#define B43legacy_PHY_IQBAL		B43legacy_PHY_OFDM(0x69)	/* I/Q balance */
+#define B43legacy_PHY_OTABLECTL		B43legacy_PHY_OFDM(0x72)	/* OFDM table control (see below) */
+#define  B43legacy_PHY_OTABLEOFF	0x03FF				/* OFDM table offset (see below) */
+#define  B43legacy_PHY_OTABLENR		0xFC00				/* OFDM table number (see below) */
+#define  B43legacy_PHY_OTABLENR_SHIFT	10
+#define B43legacy_PHY_OTABLEI		B43legacy_PHY_OFDM(0x73)	/* OFDM table data I */
+#define B43legacy_PHY_OTABLEQ		B43legacy_PHY_OFDM(0x74)	/* OFDM table data Q */
+#define B43legacy_PHY_HPWR_TSSICTL	B43legacy_PHY_OFDM(0x78)	/* Hardware power TSSI control */
+#define B43legacy_PHY_NRSSITHRES	B43legacy_PHY_OFDM(0x8A)	/* NRSSI threshold */
+#define B43legacy_PHY_ANTWRSETT		B43legacy_PHY_OFDM(0x8C)	/* Antenna WR settle */
+#define  B43legacy_PHY_ANTWRSETT_ARXDIV	0x2000				/* Automatic RX diversity enabled */
+#define B43legacy_PHY_CLIPPWRDOWNT	B43legacy_PHY_OFDM(0x93)	/* Clip powerdown threshold */
+#define B43legacy_PHY_OFDM9B		B43legacy_PHY_OFDM(0x9B)	/* FIXME rename */
+#define B43legacy_PHY_N1P1GAIN		B43legacy_PHY_OFDM(0xA0)
+#define B43legacy_PHY_P1P2GAIN		B43legacy_PHY_OFDM(0xA1)
+#define B43legacy_PHY_N1N2GAIN		B43legacy_PHY_OFDM(0xA2)
+#define B43legacy_PHY_CLIPTHRES		B43legacy_PHY_OFDM(0xA3)
+#define B43legacy_PHY_CLIPN1P2THRES	B43legacy_PHY_OFDM(0xA4)
+#define B43legacy_PHY_DIVSRCHIDX	B43legacy_PHY_OFDM(0xA8)	/* Divider search gain/index */
+#define B43legacy_PHY_CLIPP2THRES	B43legacy_PHY_OFDM(0xA9)
+#define B43legacy_PHY_CLIPP3THRES	B43legacy_PHY_OFDM(0xAA)
+#define B43legacy_PHY_DIVP1P2GAIN	B43legacy_PHY_OFDM(0xAB)
+#define B43legacy_PHY_DIVSRCHGAINBACK	B43legacy_PHY_OFDM(0xAD)	/* Divider search gain back */
+#define B43legacy_PHY_DIVSRCHGAINCHNG	B43legacy_PHY_OFDM(0xAE)	/* Divider search gain change */
+#define B43legacy_PHY_CRSTHRES1_R1	B43legacy_PHY_OFDM(0xC0)	/* CRS Threshold 1 (rev 1 only) */
+#define B43legacy_PHY_CRSTHRES2_R1	B43legacy_PHY_OFDM(0xC1)	/* CRS Threshold 2 (rev 1 only) */
+#define B43legacy_PHY_TSSIP_LTBASE	B43legacy_PHY_OFDM(0x380)	/* TSSI power lookup table base */
+#define B43legacy_PHY_DC_LTBASE		B43legacy_PHY_OFDM(0x3A0)	/* DC lookup table base */
+#define B43legacy_PHY_GAIN_LTBASE	B43legacy_PHY_OFDM(0x3C0)	/* Gain lookup table base */
+
+void b43legacy_put_attenuation_into_ranges(int *_bbatt, int *_rfatt);
+
+/* Masks for the different PHY versioning registers. */
+#define B43legacy_PHYVER_ANALOG		0xF000
+#define B43legacy_PHYVER_ANALOG_SHIFT	12
+#define B43legacy_PHYVER_TYPE		0x0F00
+#define B43legacy_PHYVER_TYPE_SHIFT	8
+#define B43legacy_PHYVER_VERSION	0x00FF
+
+struct b43legacy_wldev;
+
+void b43legacy_raw_phy_lock(struct b43legacy_wldev *dev);
+#define b43legacy_phy_lock(bcm, flags) 		\
+	do {					\
+		local_irq_save(flags);		\
+		b43legacy_raw_phy_lock(bcm);	\
+	} while (0)
+void b43legacy_raw_phy_unlock(struct b43legacy_wldev *dev);
+#define b43legacy_phy_unlock(bcm, flags)	\
+	do {					\
+		b43legacy_raw_phy_unlock(bcm);	\
+		local_irq_restore(flags);	\
+	} while (0)
+
+/* Card uses the loopback gain stuff */
+#define has_loopback_gain(phy)			 \
+	(((phy)->rev > 1) || ((phy)->gmode))
+
+u16 b43legacy_phy_read(struct b43legacy_wldev *dev, u16 offset);
+void b43legacy_phy_write(struct b43legacy_wldev *dev, u16 offset, u16 val);
+
+int b43legacy_phy_init_tssi2dbm_table(struct b43legacy_wldev *dev);
+int b43legacy_phy_init(struct b43legacy_wldev *dev);
+
+void b43legacy_set_rx_antenna(struct b43legacy_wldev *dev, int antenna);
+
+void b43legacy_phy_set_antenna_diversity(struct b43legacy_wldev *dev);
+void b43legacy_phy_calibrate(struct b43legacy_wldev *dev);
+int b43legacy_phy_connect(struct b43legacy_wldev *dev, int connect);
+
+void b43legacy_phy_lo_b_measure(struct b43legacy_wldev *dev);
+void b43legacy_phy_lo_g_measure(struct b43legacy_wldev *dev);
+void b43legacy_phy_xmitpower(struct b43legacy_wldev *dev);
+
+/* Adjust the LocalOscillator to the saved values.
+ * "fixed" is only set to 1 once in initialization. Set to 0 otherwise.
+ */
+void b43legacy_phy_lo_adjust(struct b43legacy_wldev *dev, int fixed);
+void b43legacy_phy_lo_mark_all_unused(struct b43legacy_wldev *dev);
+
+void b43legacy_phy_set_baseband_attenuation(struct b43legacy_wldev *dev,
+					    u16 baseband_attenuation);
+
+void b43legacy_power_saving_ctl_bits(struct b43legacy_wldev *dev,
+				     int bit25, int bit26);
+
+#endif /* B43legacy_PHY_H_ */
diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c
new file mode 100644
index 0000000..de843ac
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/pio.c
@@ -0,0 +1,668 @@
+/*
+
+  Broadcom B43legacy wireless driver
+
+  PIO Transmission
+
+  Copyright (c) 2005 Michael Buesch <mb@bu3sch.de>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43legacy.h"
+#include "pio.h"
+#include "main.h"
+#include "xmit.h"
+
+#include <linux/delay.h>
+
+
+static void tx_start(struct b43legacy_pioqueue *queue)
+{
+	b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+			    B43legacy_PIO_TXCTL_INIT);
+}
+
+static void tx_octet(struct b43legacy_pioqueue *queue,
+		     u8 octet)
+{
+	if (queue->need_workarounds) {
+		b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet);
+		b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+				    B43legacy_PIO_TXCTL_WRITELO);
+	} else {
+		b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+				    B43legacy_PIO_TXCTL_WRITELO);
+		b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, octet);
+	}
+}
+
+static u16 tx_get_next_word(const u8 *txhdr,
+			    const u8 *packet,
+			    size_t txhdr_size,
+			    unsigned int *pos)
+{
+	const u8 *source;
+	unsigned int i = *pos;
+	u16 ret;
+
+	if (i < txhdr_size)
+		source = txhdr;
+	else {
+		source = packet;
+		i -= txhdr_size;
+	}
+	ret = le16_to_cpu(*((__le16 *)(source + i)));
+	*pos += 2;
+
+	return ret;
+}
+
+static void tx_data(struct b43legacy_pioqueue *queue,
+		    u8 *txhdr,
+		    const u8 *packet,
+		    unsigned int octets)
+{
+	u16 data;
+	unsigned int i = 0;
+
+	if (queue->need_workarounds) {
+		data = tx_get_next_word(txhdr, packet,
+					sizeof(struct b43legacy_txhdr_fw3), &i);
+		b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data);
+	}
+	b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+			    B43legacy_PIO_TXCTL_WRITELO |
+			    B43legacy_PIO_TXCTL_WRITEHI);
+	while (i < octets - 1) {
+		data = tx_get_next_word(txhdr, packet,
+					sizeof(struct b43legacy_txhdr_fw3), &i);
+		b43legacy_pio_write(queue, B43legacy_PIO_TXDATA, data);
+	}
+	if (octets % 2)
+		tx_octet(queue, packet[octets -
+			 sizeof(struct b43legacy_txhdr_fw3) - 1]);
+}
+
+static void tx_complete(struct b43legacy_pioqueue *queue,
+			struct sk_buff *skb)
+{
+	if (queue->need_workarounds) {
+		b43legacy_pio_write(queue, B43legacy_PIO_TXDATA,
+				    skb->data[skb->len - 1]);
+		b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+				    B43legacy_PIO_TXCTL_WRITELO |
+				    B43legacy_PIO_TXCTL_COMPLETE);
+	} else
+		b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+				    B43legacy_PIO_TXCTL_COMPLETE);
+}
+
+static u16 generate_cookie(struct b43legacy_pioqueue *queue,
+			   struct b43legacy_pio_txpacket *packet)
+{
+	u16 cookie = 0x0000;
+	int packetindex;
+
+	/* We use the upper 4 bits for the PIO
+	 * controller ID and the lower 12 bits
+	 * for the packet index (in the cache).
+	 */
+	switch (queue->mmio_base) {
+	case B43legacy_MMIO_PIO1_BASE:
+		break;
+	case B43legacy_MMIO_PIO2_BASE:
+		cookie = 0x1000;
+		break;
+	case B43legacy_MMIO_PIO3_BASE:
+		cookie = 0x2000;
+		break;
+	case B43legacy_MMIO_PIO4_BASE:
+		cookie = 0x3000;
+		break;
+	default:
+		B43legacy_WARN_ON(1);
+	}
+	packetindex = pio_txpacket_getindex(packet);
+	B43legacy_WARN_ON(!(((u16)packetindex & 0xF000) == 0x0000));
+	cookie |= (u16)packetindex;
+
+	return cookie;
+}
+
+static
+struct b43legacy_pioqueue *parse_cookie(struct b43legacy_wldev *dev,
+					u16 cookie,
+					struct b43legacy_pio_txpacket **packet)
+{
+	struct b43legacy_pio *pio = &dev->pio;
+	struct b43legacy_pioqueue *queue = NULL;
+	int packetindex;
+
+	switch (cookie & 0xF000) {
+	case 0x0000:
+		queue = pio->queue0;
+		break;
+	case 0x1000:
+		queue = pio->queue1;
+		break;
+	case 0x2000:
+		queue = pio->queue2;
+		break;
+	case 0x3000:
+		queue = pio->queue3;
+		break;
+	default:
+		B43legacy_WARN_ON(1);
+	}
+	packetindex = (cookie & 0x0FFF);
+	B43legacy_WARN_ON(!(packetindex >= 0 && packetindex
+			  < B43legacy_PIO_MAXTXPACKETS));
+	*packet = &(queue->tx_packets_cache[packetindex]);
+
+	return queue;
+}
+
+union txhdr_union {
+	struct b43legacy_txhdr_fw3 txhdr_fw3;
+};
+
+static void pio_tx_write_fragment(struct b43legacy_pioqueue *queue,
+				  struct sk_buff *skb,
+				  struct b43legacy_pio_txpacket *packet,
+				  size_t txhdr_size)
+{
+	union txhdr_union txhdr_data;
+	u8 *txhdr = NULL;
+	unsigned int octets;
+
+	txhdr = (u8 *)(&txhdr_data.txhdr_fw3);
+
+	B43legacy_WARN_ON(skb_shinfo(skb)->nr_frags != 0);
+	b43legacy_generate_txhdr(queue->dev,
+				 txhdr, skb->data, skb->len,
+				 &packet->txstat.control,
+				 generate_cookie(queue, packet));
+
+	tx_start(queue);
+	octets = skb->len + txhdr_size;
+	if (queue->need_workarounds)
+		octets--;
+	tx_data(queue, txhdr, (u8 *)skb->data, octets);
+	tx_complete(queue, skb);
+}
+
+static void free_txpacket(struct b43legacy_pio_txpacket *packet,
+			  int irq_context)
+{
+	struct b43legacy_pioqueue *queue = packet->queue;
+
+	if (packet->skb) {
+		if (irq_context)
+			dev_kfree_skb_irq(packet->skb);
+		else
+			dev_kfree_skb(packet->skb);
+	}
+	list_move(&packet->list, &queue->txfree);
+	queue->nr_txfree++;
+}
+
+static int pio_tx_packet(struct b43legacy_pio_txpacket *packet)
+{
+	struct b43legacy_pioqueue *queue = packet->queue;
+	struct sk_buff *skb = packet->skb;
+	u16 octets;
+
+	octets = (u16)skb->len + sizeof(struct b43legacy_txhdr_fw3);
+	if (queue->tx_devq_size < octets) {
+		b43legacywarn(queue->dev->wl, "PIO queue too small. "
+			"Dropping packet.\n");
+		/* Drop it silently (return success) */
+		free_txpacket(packet, 1);
+		return 0;
+	}
+	B43legacy_WARN_ON(queue->tx_devq_packets >
+			  B43legacy_PIO_MAXTXDEVQPACKETS);
+	B43legacy_WARN_ON(queue->tx_devq_used > queue->tx_devq_size);
+	/* Check if there is sufficient free space on the device
+	 * TX queue. If not, return and let the TX tasklet
+	 * retry later.
+	 */
+	if (queue->tx_devq_packets == B43legacy_PIO_MAXTXDEVQPACKETS)
+		return -EBUSY;
+	if (queue->tx_devq_used + octets > queue->tx_devq_size)
+		return -EBUSY;
+	/* Now poke the device. */
+	pio_tx_write_fragment(queue, skb, packet,
+			      sizeof(struct b43legacy_txhdr_fw3));
+
+	/* Account for the packet size.
+	 * (We must not overflow the device TX queue)
+	 */
+	queue->tx_devq_packets++;
+	queue->tx_devq_used += octets;
+
+	/* Transmission started, everything ok, move the
+	 * packet to the txrunning list.
+	 */
+	list_move_tail(&packet->list, &queue->txrunning);
+
+	return 0;
+}
+
+static void tx_tasklet(unsigned long d)
+{
+	struct b43legacy_pioqueue *queue = (struct b43legacy_pioqueue *)d;
+	struct b43legacy_wldev *dev = queue->dev;
+	unsigned long flags;
+	struct b43legacy_pio_txpacket *packet, *tmp_packet;
+	int err;
+	u16 txctl;
+
+	spin_lock_irqsave(&dev->wl->irq_lock, flags);
+	if (queue->tx_frozen)
+		goto out_unlock;
+	txctl = b43legacy_pio_read(queue, B43legacy_PIO_TXCTL);
+	if (txctl & B43legacy_PIO_TXCTL_SUSPEND)
+		goto out_unlock;
+
+	list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) {
+		/* Try to transmit the packet. This can fail, if
+		 * the device queue is full. In case of failure, the
+		 * packet is left in the txqueue.
+		 * If transmission succeed, the packet is moved to txrunning.
+		 * If it is impossible to transmit the packet, it
+		 * is dropped.
+		 */
+		err = pio_tx_packet(packet);
+		if (err)
+			break;
+	}
+out_unlock:
+	spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
+}
+
+static void setup_txqueues(struct b43legacy_pioqueue *queue)
+{
+	struct b43legacy_pio_txpacket *packet;
+	int i;
+
+	queue->nr_txfree = B43legacy_PIO_MAXTXPACKETS;
+	for (i = 0; i < B43legacy_PIO_MAXTXPACKETS; i++) {
+		packet = &(queue->tx_packets_cache[i]);
+
+		packet->queue = queue;
+		INIT_LIST_HEAD(&packet->list);
+
+		list_add(&packet->list, &queue->txfree);
+	}
+}
+
+static
+struct b43legacy_pioqueue *b43legacy_setup_pioqueue(struct b43legacy_wldev *dev,
+						    u16 pio_mmio_base)
+{
+	struct b43legacy_pioqueue *queue;
+	u32 value;
+	u16 qsize;
+
+	queue = kzalloc(sizeof(*queue), GFP_KERNEL);
+	if (!queue)
+		goto out;
+
+	queue->dev = dev;
+	queue->mmio_base = pio_mmio_base;
+	queue->need_workarounds = (dev->dev->id.revision < 3);
+
+	INIT_LIST_HEAD(&queue->txfree);
+	INIT_LIST_HEAD(&queue->txqueue);
+	INIT_LIST_HEAD(&queue->txrunning);
+	tasklet_init(&queue->txtask, tx_tasklet,
+		     (unsigned long)queue);
+
+	value = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+	value &= ~B43legacy_SBF_XFER_REG_BYTESWAP;
+	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value);
+
+	qsize = b43legacy_read16(dev, queue->mmio_base
+				 + B43legacy_PIO_TXQBUFSIZE);
+	if (qsize == 0) {
+		b43legacyerr(dev->wl, "This card does not support PIO "
+		       "operation mode. Please use DMA mode "
+		       "(module parameter pio=0).\n");
+		goto err_freequeue;
+	}
+	if (qsize <= B43legacy_PIO_TXQADJUST) {
+		b43legacyerr(dev->wl, "PIO tx device-queue too small (%u)\n",
+		       qsize);
+		goto err_freequeue;
+	}
+	qsize -= B43legacy_PIO_TXQADJUST;
+	queue->tx_devq_size = qsize;
+
+	setup_txqueues(queue);
+
+out:
+	return queue;
+
+err_freequeue:
+	kfree(queue);
+	queue = NULL;
+	goto out;
+}
+
+static void cancel_transfers(struct b43legacy_pioqueue *queue)
+{
+	struct b43legacy_pio_txpacket *packet, *tmp_packet;
+
+	tasklet_disable(&queue->txtask);
+
+	list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list)
+		free_txpacket(packet, 0);
+	list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list)
+		free_txpacket(packet, 0);
+}
+
+static void b43legacy_destroy_pioqueue(struct b43legacy_pioqueue *queue)
+{
+	if (!queue)
+		return;
+
+	cancel_transfers(queue);
+	kfree(queue);
+}
+
+void b43legacy_pio_free(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_pio *pio;
+
+	if (!b43legacy_using_pio(dev))
+		return;
+	pio = &dev->pio;
+
+	b43legacy_destroy_pioqueue(pio->queue3);
+	pio->queue3 = NULL;
+	b43legacy_destroy_pioqueue(pio->queue2);
+	pio->queue2 = NULL;
+	b43legacy_destroy_pioqueue(pio->queue1);
+	pio->queue1 = NULL;
+	b43legacy_destroy_pioqueue(pio->queue0);
+	pio->queue0 = NULL;
+}
+
+int b43legacy_pio_init(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_pio *pio = &dev->pio;
+	struct b43legacy_pioqueue *queue;
+	int err = -ENOMEM;
+
+	queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO1_BASE);
+	if (!queue)
+		goto out;
+	pio->queue0 = queue;
+
+	queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO2_BASE);
+	if (!queue)
+		goto err_destroy0;
+	pio->queue1 = queue;
+
+	queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO3_BASE);
+	if (!queue)
+		goto err_destroy1;
+	pio->queue2 = queue;
+
+	queue = b43legacy_setup_pioqueue(dev, B43legacy_MMIO_PIO4_BASE);
+	if (!queue)
+		goto err_destroy2;
+	pio->queue3 = queue;
+
+	if (dev->dev->id.revision < 3)
+		dev->irq_savedstate |= B43legacy_IRQ_PIO_WORKAROUND;
+
+	b43legacydbg(dev->wl, "PIO initialized\n");
+	err = 0;
+out:
+	return err;
+
+err_destroy2:
+	b43legacy_destroy_pioqueue(pio->queue2);
+	pio->queue2 = NULL;
+err_destroy1:
+	b43legacy_destroy_pioqueue(pio->queue1);
+	pio->queue1 = NULL;
+err_destroy0:
+	b43legacy_destroy_pioqueue(pio->queue0);
+	pio->queue0 = NULL;
+	goto out;
+}
+
+int b43legacy_pio_tx(struct b43legacy_wldev *dev,
+		     struct sk_buff *skb,
+		     struct ieee80211_tx_control *ctl)
+{
+	struct b43legacy_pioqueue *queue = dev->pio.queue1;
+	struct b43legacy_pio_txpacket *packet;
+
+	B43legacy_WARN_ON(queue->tx_suspended);
+	B43legacy_WARN_ON(list_empty(&queue->txfree));
+
+	packet = list_entry(queue->txfree.next, struct b43legacy_pio_txpacket,
+			    list);
+	packet->skb = skb;
+
+	memset(&packet->txstat, 0, sizeof(packet->txstat));
+	memcpy(&packet->txstat.control, ctl, sizeof(*ctl));
+
+	list_move_tail(&packet->list, &queue->txqueue);
+	queue->nr_txfree--;
+	queue->nr_tx_packets++;
+	B43legacy_WARN_ON(queue->nr_txfree >= B43legacy_PIO_MAXTXPACKETS);
+
+	tasklet_schedule(&queue->txtask);
+
+	return 0;
+}
+
+void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
+				   const struct b43legacy_txstatus *status)
+{
+	struct b43legacy_pioqueue *queue;
+	struct b43legacy_pio_txpacket *packet;
+
+	queue = parse_cookie(dev, status->cookie, &packet);
+	B43legacy_WARN_ON(!queue);
+
+	queue->tx_devq_packets--;
+	queue->tx_devq_used -= (packet->skb->len +
+				sizeof(struct b43legacy_txhdr_fw3));
+
+	if (status->acked)
+		packet->txstat.flags |= IEEE80211_TX_STATUS_ACK;
+	packet->txstat.retry_count = status->frame_count - 1;
+	ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb,
+				    &(packet->txstat));
+	packet->skb = NULL;
+
+	free_txpacket(packet, 1);
+	/* If there are packets on the txqueue, poke the tasklet
+	 * to transmit them.
+	 */
+	if (!list_empty(&queue->txqueue))
+		tasklet_schedule(&queue->txtask);
+}
+
+void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
+				struct ieee80211_tx_queue_stats *stats)
+{
+	struct b43legacy_pio *pio = &dev->pio;
+	struct b43legacy_pioqueue *queue;
+	struct ieee80211_tx_queue_stats_data *data;
+
+	queue = pio->queue1;
+	data = &(stats->data[0]);
+	data->len = B43legacy_PIO_MAXTXPACKETS - queue->nr_txfree;
+	data->limit = B43legacy_PIO_MAXTXPACKETS;
+	data->count = queue->nr_tx_packets;
+}
+
+static void pio_rx_error(struct b43legacy_pioqueue *queue,
+			 int clear_buffers,
+			 const char *error)
+{
+	int i;
+
+	b43legacyerr(queue->dev->wl, "PIO RX error: %s\n", error);
+	b43legacy_pio_write(queue, B43legacy_PIO_RXCTL,
+			    B43legacy_PIO_RXCTL_READY);
+	if (clear_buffers) {
+		B43legacy_WARN_ON(queue->mmio_base != B43legacy_MMIO_PIO1_BASE);
+		for (i = 0; i < 15; i++) {
+			/* Dummy read. */
+			b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
+		}
+	}
+}
+
+void b43legacy_pio_rx(struct b43legacy_pioqueue *queue)
+{
+	__le16 preamble[21] = { 0 };
+	struct b43legacy_rxhdr_fw3 *rxhdr;
+	u16 tmp;
+	u16 len;
+	u16 macstat;
+	int i;
+	int preamble_readwords;
+	struct sk_buff *skb;
+
+	tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL);
+	if (!(tmp & B43legacy_PIO_RXCTL_DATAAVAILABLE))
+		return;
+	b43legacy_pio_write(queue, B43legacy_PIO_RXCTL,
+			    B43legacy_PIO_RXCTL_DATAAVAILABLE);
+
+	for (i = 0; i < 10; i++) {
+		tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXCTL);
+		if (tmp & B43legacy_PIO_RXCTL_READY)
+			goto data_ready;
+		udelay(10);
+	}
+	b43legacydbg(queue->dev->wl, "PIO RX timed out\n");
+	return;
+data_ready:
+
+	len = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
+	if (unlikely(len > 0x700)) {
+		pio_rx_error(queue, 0, "len > 0x700");
+		return;
+	}
+	if (unlikely(len == 0 && queue->mmio_base !=
+		     B43legacy_MMIO_PIO4_BASE)) {
+		pio_rx_error(queue, 0, "len == 0");
+		return;
+	}
+	preamble[0] = cpu_to_le16(len);
+	if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE)
+		preamble_readwords = 14 / sizeof(u16);
+	else
+		preamble_readwords = 18 / sizeof(u16);
+	for (i = 0; i < preamble_readwords; i++) {
+		tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
+		preamble[i + 1] = cpu_to_le16(tmp);
+	}
+	rxhdr = (struct b43legacy_rxhdr_fw3 *)preamble;
+	macstat = le16_to_cpu(rxhdr->mac_status);
+	if (macstat & B43legacy_RX_MAC_FCSERR) {
+		pio_rx_error(queue,
+			     (queue->mmio_base == B43legacy_MMIO_PIO1_BASE),
+			     "Frame FCS error");
+		return;
+	}
+	if (queue->mmio_base == B43legacy_MMIO_PIO4_BASE) {
+		/* We received an xmit status. */
+		struct b43legacy_hwtxstatus *hw;
+
+		hw = (struct b43legacy_hwtxstatus *)(preamble + 1);
+		b43legacy_handle_hwtxstatus(queue->dev, hw);
+
+		return;
+	}
+
+	skb = dev_alloc_skb(len);
+	if (unlikely(!skb)) {
+		pio_rx_error(queue, 1, "OOM");
+		return;
+	}
+	skb_put(skb, len);
+	for (i = 0; i < len - 1; i += 2) {
+		tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
+		*((__le16 *)(skb->data + i)) = cpu_to_le16(tmp);
+	}
+	if (len % 2) {
+		tmp = b43legacy_pio_read(queue, B43legacy_PIO_RXDATA);
+		skb->data[len - 1] = (tmp & 0x00FF);
+	}
+	b43legacy_rx(queue->dev, skb, rxhdr);
+}
+
+void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue)
+{
+	b43legacy_power_saving_ctl_bits(queue->dev, -1, 1);
+	b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+			    b43legacy_pio_read(queue, B43legacy_PIO_TXCTL)
+			    | B43legacy_PIO_TXCTL_SUSPEND);
+}
+
+void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue)
+{
+	b43legacy_pio_write(queue, B43legacy_PIO_TXCTL,
+			    b43legacy_pio_read(queue, B43legacy_PIO_TXCTL)
+			    & ~B43legacy_PIO_TXCTL_SUSPEND);
+	b43legacy_power_saving_ctl_bits(queue->dev, -1, -1);
+	tasklet_schedule(&queue->txtask);
+}
+
+void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_pio *pio;
+
+	B43legacy_WARN_ON(!b43legacy_using_pio(dev));
+	pio = &dev->pio;
+	pio->queue0->tx_frozen = 1;
+	pio->queue1->tx_frozen = 1;
+	pio->queue2->tx_frozen = 1;
+	pio->queue3->tx_frozen = 1;
+}
+
+void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_pio *pio;
+
+	B43legacy_WARN_ON(!b43legacy_using_pio(dev));
+	pio = &dev->pio;
+	pio->queue0->tx_frozen = 0;
+	pio->queue1->tx_frozen = 0;
+	pio->queue2->tx_frozen = 0;
+	pio->queue3->tx_frozen = 0;
+	if (!list_empty(&pio->queue0->txqueue))
+		tasklet_schedule(&pio->queue0->txtask);
+	if (!list_empty(&pio->queue1->txqueue))
+		tasklet_schedule(&pio->queue1->txtask);
+	if (!list_empty(&pio->queue2->txqueue))
+		tasklet_schedule(&pio->queue2->txtask);
+	if (!list_empty(&pio->queue3->txqueue))
+		tasklet_schedule(&pio->queue3->txtask);
+}
diff --git a/drivers/net/wireless/b43legacy/pio.h b/drivers/net/wireless/b43legacy/pio.h
new file mode 100644
index 0000000..5bfed0c
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/pio.h
@@ -0,0 +1,172 @@
+#ifndef B43legacy_PIO_H_
+#define B43legacy_PIO_H_
+
+#include "b43legacy.h"
+
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+
+
+#define B43legacy_PIO_TXCTL		0x00
+#define B43legacy_PIO_TXDATA		0x02
+#define B43legacy_PIO_TXQBUFSIZE	0x04
+#define B43legacy_PIO_RXCTL		0x08
+#define B43legacy_PIO_RXDATA		0x0A
+
+#define B43legacy_PIO_TXCTL_WRITELO	(1 << 0)
+#define B43legacy_PIO_TXCTL_WRITEHI	(1 << 1)
+#define B43legacy_PIO_TXCTL_COMPLETE	(1 << 2)
+#define B43legacy_PIO_TXCTL_INIT	(1 << 3)
+#define B43legacy_PIO_TXCTL_SUSPEND	(1 << 7)
+
+#define B43legacy_PIO_RXCTL_DATAAVAILABLE	(1 << 0)
+#define B43legacy_PIO_RXCTL_READY		(1 << 1)
+
+/* PIO constants */
+#define B43legacy_PIO_MAXTXDEVQPACKETS	31
+#define B43legacy_PIO_TXQADJUST		80
+
+/* PIO tuning knobs */
+#define B43legacy_PIO_MAXTXPACKETS	256
+
+
+
+#ifdef CONFIG_B43LEGACY_PIO
+
+
+struct b43legacy_pioqueue;
+struct b43legacy_xmitstatus;
+
+struct b43legacy_pio_txpacket {
+	struct b43legacy_pioqueue *queue;
+	struct sk_buff *skb;
+	struct ieee80211_tx_status txstat;
+	struct list_head list;
+};
+
+#define pio_txpacket_getindex(packet) ((int)((packet) - \
+			      (packet)->queue->tx_packets_cache))
+
+struct b43legacy_pioqueue {
+	struct b43legacy_wldev *dev;
+	u16 mmio_base;
+
+	bool tx_suspended;
+	bool tx_frozen;
+	bool need_workarounds; /* Workarounds needed for core.rev < 3 */
+
+	/* Adjusted size of the device internal TX buffer. */
+	u16 tx_devq_size;
+	/* Used octets of the device internal TX buffer. */
+	u16 tx_devq_used;
+	/* Used packet slots in the device internal TX buffer. */
+	u8 tx_devq_packets;
+	/* Packets from the txfree list can
+	 * be taken on incoming TX requests.
+	 */
+	struct list_head txfree;
+	unsigned int nr_txfree;
+	/* Packets on the txqueue are queued,
+	 * but not completely written to the chip, yet.
+	 */
+	struct list_head txqueue;
+	/* Packets on the txrunning queue are completely
+	 * posted to the device. We are waiting for the txstatus.
+	 */
+	struct list_head txrunning;
+	/* Total number or packets sent.
+	 * (This counter can obviously wrap).
+	 */
+	unsigned int nr_tx_packets;
+	struct tasklet_struct txtask;
+	struct b43legacy_pio_txpacket
+			 tx_packets_cache[B43legacy_PIO_MAXTXPACKETS];
+};
+
+static inline
+u16 b43legacy_pio_read(struct b43legacy_pioqueue *queue,
+		     u16 offset)
+{
+	return b43legacy_read16(queue->dev, queue->mmio_base + offset);
+}
+
+static inline
+void b43legacy_pio_write(struct b43legacy_pioqueue *queue,
+		       u16 offset, u16 value)
+{
+	b43legacy_write16(queue->dev, queue->mmio_base + offset, value);
+	mmiowb();
+}
+
+
+int b43legacy_pio_init(struct b43legacy_wldev *dev);
+void b43legacy_pio_free(struct b43legacy_wldev *dev);
+
+int b43legacy_pio_tx(struct b43legacy_wldev *dev,
+		   struct sk_buff *skb,
+		   struct ieee80211_tx_control *ctl);
+void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
+				 const struct b43legacy_txstatus *status);
+void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
+			      struct ieee80211_tx_queue_stats *stats);
+void b43legacy_pio_rx(struct b43legacy_pioqueue *queue);
+
+/* Suspend TX queue in hardware. */
+void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue);
+void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue);
+/* Suspend (freeze) the TX tasklet (software level). */
+void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev);
+void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev);
+
+#else /* CONFIG_B43LEGACY_PIO */
+
+static inline
+int b43legacy_pio_init(struct b43legacy_wldev *dev)
+{
+	return 0;
+}
+static inline
+void b43legacy_pio_free(struct b43legacy_wldev *dev)
+{
+}
+static inline
+int b43legacy_pio_tx(struct b43legacy_wldev *dev,
+		   struct sk_buff *skb,
+		   struct ieee80211_tx_control *ctl)
+{
+	return 0;
+}
+static inline
+void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev,
+				 const struct b43legacy_txstatus *status)
+{
+}
+static inline
+void b43legacy_pio_get_tx_stats(struct b43legacy_wldev *dev,
+			      struct ieee80211_tx_queue_stats *stats)
+{
+}
+static inline
+void b43legacy_pio_rx(struct b43legacy_pioqueue *queue)
+{
+}
+static inline
+void b43legacy_pio_tx_suspend(struct b43legacy_pioqueue *queue)
+{
+}
+static inline
+void b43legacy_pio_tx_resume(struct b43legacy_pioqueue *queue)
+{
+}
+static inline
+void b43legacy_pio_freeze_txqueues(struct b43legacy_wldev *dev)
+{
+}
+static inline
+void b43legacy_pio_thaw_txqueues(struct b43legacy_wldev *dev)
+{
+}
+
+#endif /* CONFIG_B43LEGACY_PIO */
+#endif /* B43legacy_PIO_H_ */
diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c
new file mode 100644
index 0000000..a361dee
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/radio.c
@@ -0,0 +1,2158 @@
+/*
+
+  Broadcom B43legacy wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+		     Stefano Brivio <st3@riseup.net>
+		     Michael Buesch <mbuesch@freenet.de>
+		     Danny van Dyk <kugelfang@gentoo.org>
+		     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+  Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 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 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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/delay.h>
+
+#include "b43legacy.h"
+#include "main.h"
+#include "phy.h"
+#include "radio.h"
+#include "ilt.h"
+
+
+/* Table for b43legacy_radio_calibrationvalue() */
+static const u16 rcc_table[16] = {
+	0x0002, 0x0003, 0x0001, 0x000F,
+	0x0006, 0x0007, 0x0005, 0x000F,
+	0x000A, 0x000B, 0x0009, 0x000F,
+	0x000E, 0x000F, 0x000D, 0x000F,
+};
+
+/* Reverse the bits of a 4bit value.
+ * Example:  1101 is flipped 1011
+ */
+static u16 flip_4bit(u16 value)
+{
+	u16 flipped = 0x0000;
+
+	B43legacy_BUG_ON(!((value & ~0x000F) == 0x0000));
+
+	flipped |= (value & 0x0001) << 3;
+	flipped |= (value & 0x0002) << 1;
+	flipped |= (value & 0x0004) >> 1;
+	flipped |= (value & 0x0008) >> 3;
+
+	return flipped;
+}
+
+/* Get the freq, as it has to be written to the device. */
+static inline
+u16 channel2freq_bg(u8 channel)
+{
+	/* Frequencies are given as frequencies_bg[index] + 2.4GHz
+	 * Starting with channel 1
+	 */
+	static const u16 frequencies_bg[14] = {
+		12, 17, 22, 27,
+		32, 37, 42, 47,
+		52, 57, 62, 67,
+		72, 84,
+	};
+
+	if (unlikely(channel < 1 || channel > 14)) {
+		printk(KERN_INFO "b43legacy: Channel %d is out of range\n",
+				  channel);
+		dump_stack();
+		return 2412;
+	}
+
+	return frequencies_bg[channel - 1];
+}
+
+void b43legacy_radio_lock(struct b43legacy_wldev *dev)
+{
+	u32 status;
+
+	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+	status |= B43legacy_SBF_RADIOREG_LOCK;
+	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+	mmiowb();
+	udelay(10);
+}
+
+void b43legacy_radio_unlock(struct b43legacy_wldev *dev)
+{
+	u32 status;
+
+	b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */
+	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
+	status &= ~B43legacy_SBF_RADIOREG_LOCK;
+	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);
+	mmiowb();
+}
+
+u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+
+	switch (phy->type) {
+	case B43legacy_PHYTYPE_B:
+		if (phy->radio_ver == 0x2053) {
+			if (offset < 0x70)
+				offset += 0x80;
+			else if (offset < 0x80)
+				offset += 0x70;
+		} else if (phy->radio_ver == 0x2050)
+			offset |= 0x80;
+		else
+			B43legacy_WARN_ON(1);
+		break;
+	case B43legacy_PHYTYPE_G:
+		offset |= 0x80;
+		break;
+	default:
+		B43legacy_BUG_ON(1);
+	}
+
+	b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);
+	return b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW);
+}
+
+void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val)
+{
+	b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);
+	mmiowb();
+	b43legacy_write16(dev, B43legacy_MMIO_RADIO_DATA_LOW, val);
+}
+
+static void b43legacy_set_all_gains(struct b43legacy_wldev *dev,
+				  s16 first, s16 second, s16 third)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 i;
+	u16 start = 0x08;
+	u16 end = 0x18;
+	u16 offset = 0x0400;
+	u16 tmp;
+
+	if (phy->rev <= 1) {
+		offset = 0x5000;
+		start = 0x10;
+		end = 0x20;
+	}
+
+	for (i = 0; i < 4; i++)
+		b43legacy_ilt_write(dev, offset + i, first);
+
+	for (i = start; i < end; i++)
+		b43legacy_ilt_write(dev, offset + i, second);
+
+	if (third != -1) {
+		tmp = ((u16)third << 14) | ((u16)third << 6);
+		b43legacy_phy_write(dev, 0x04A0,
+				    (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)
+				    | tmp);
+		b43legacy_phy_write(dev, 0x04A1,
+				    (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)
+				    | tmp);
+		b43legacy_phy_write(dev, 0x04A2,
+				    (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)
+				    | tmp);
+	}
+	b43legacy_dummy_transmission(dev);
+}
+
+static void b43legacy_set_original_gains(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 i;
+	u16 tmp;
+	u16 offset = 0x0400;
+	u16 start = 0x0008;
+	u16 end = 0x0018;
+
+	if (phy->rev <= 1) {
+		offset = 0x5000;
+		start = 0x0010;
+		end = 0x0020;
+	}
+
+	for (i = 0; i < 4; i++) {
+		tmp = (i & 0xFFFC);
+		tmp |= (i & 0x0001) << 1;
+		tmp |= (i & 0x0002) >> 1;
+
+		b43legacy_ilt_write(dev, offset + i, tmp);
+	}
+
+	for (i = start; i < end; i++)
+		b43legacy_ilt_write(dev, offset + i, i - start);
+
+	b43legacy_phy_write(dev, 0x04A0,
+			    (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)
+			    | 0x4040);
+	b43legacy_phy_write(dev, 0x04A1,
+			    (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)
+			    | 0x4040);
+	b43legacy_phy_write(dev, 0x04A2,
+			    (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)
+			    | 0x4000);
+	b43legacy_dummy_transmission(dev);
+}
+
+/* Synthetic PU workaround */
+static void b43legacy_synth_pu_workaround(struct b43legacy_wldev *dev,
+					  u8 channel)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+
+	might_sleep();
+
+	if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6)
+		/* We do not need the workaround. */
+		return;
+
+	if (channel <= 10)
+		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
+				  channel2freq_bg(channel + 4));
+	else
+		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
+				  channel2freq_bg(channel));
+	msleep(1);
+	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
+			  channel2freq_bg(channel));
+}
+
+u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u8 ret = 0;
+	u16 saved;
+	u16 rssi;
+	u16 temp;
+	int i;
+	int j = 0;
+
+	saved = b43legacy_phy_read(dev, 0x0403);
+	b43legacy_radio_selectchannel(dev, channel, 0);
+	b43legacy_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);
+	if (phy->aci_hw_rssi)
+		rssi = b43legacy_phy_read(dev, 0x048A) & 0x3F;
+	else
+		rssi = saved & 0x3F;
+	/* clamp temp to signed 5bit */
+	if (rssi > 32)
+		rssi -= 64;
+	for (i = 0; i < 100; i++) {
+		temp = (b43legacy_phy_read(dev, 0x047F) >> 8) & 0x3F;
+		if (temp > 32)
+			temp -= 64;
+		if (temp < rssi)
+			j++;
+		if (j >= 20)
+			ret = 1;
+	}
+	b43legacy_phy_write(dev, 0x0403, saved);
+
+	return ret;
+}
+
+u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u8 ret[13];
+	unsigned int channel = phy->channel;
+	unsigned int i;
+	unsigned int j;
+	unsigned int start;
+	unsigned int end;
+	unsigned long phylock_flags;
+
+	if (!((phy->type == B43legacy_PHYTYPE_G) && (phy->rev > 0)))
+		return 0;
+
+	b43legacy_phy_lock(dev, phylock_flags);
+	b43legacy_radio_lock(dev);
+	b43legacy_phy_write(dev, 0x0802,
+			    b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
+	b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+			    b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
+			    & 0x7FFF);
+	b43legacy_set_all_gains(dev, 3, 8, 1);
+
+	start = (channel - 5 > 0) ? channel - 5 : 1;
+	end = (channel + 5 < 14) ? channel + 5 : 13;
+
+	for (i = start; i <= end; i++) {
+		if (abs(channel - i) > 2)
+			ret[i-1] = b43legacy_radio_aci_detect(dev, i);
+	}
+	b43legacy_radio_selectchannel(dev, channel, 0);
+	b43legacy_phy_write(dev, 0x0802,
+			    (b43legacy_phy_read(dev, 0x0802) & 0xFFFC)
+			    | 0x0003);
+	b43legacy_phy_write(dev, 0x0403,
+			    b43legacy_phy_read(dev, 0x0403) & 0xFFF8);
+	b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+			    b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
+			    | 0x8000);
+	b43legacy_set_original_gains(dev);
+	for (i = 0; i < 13; i++) {
+		if (!ret[i])
+			continue;
+		end = (i + 5 < 13) ? i + 5 : 13;
+		for (j = i; j < end; j++)
+			ret[j] = 1;
+	}
+	b43legacy_radio_unlock(dev);
+	b43legacy_phy_unlock(dev, phylock_flags);
+
+	return ret[channel - 1];
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val)
+{
+	b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);
+	mmiowb();
+	b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_DATA, (u16)val);
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset)
+{
+	u16 val;
+
+	b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);
+	val = b43legacy_phy_read(dev, B43legacy_PHY_NRSSILT_DATA);
+
+	return (s16)val;
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val)
+{
+	u16 i;
+	s16 tmp;
+
+	for (i = 0; i < 64; i++) {
+		tmp = b43legacy_nrssi_hw_read(dev, i);
+		tmp -= val;
+		tmp = limit_value(tmp, -32, 31);
+		b43legacy_nrssi_hw_write(dev, i, tmp);
+	}
+}
+
+/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */
+void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	s16 i;
+	s16 delta;
+	s32 tmp;
+
+	delta = 0x1F - phy->nrssi[0];
+	for (i = 0; i < 64; i++) {
+		tmp = (i - delta) * phy->nrssislope;
+		tmp /= 0x10000;
+		tmp += 0x3A;
+		tmp = limit_value(tmp, 0, 0x3F);
+		phy->nrssi_lt[i] = tmp;
+	}
+}
+
+static void b43legacy_calc_nrssi_offset(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 backup[20] = { 0 };
+	s16 v47F;
+	u16 i;
+	u16 saved = 0xFFFF;
+
+	backup[0] = b43legacy_phy_read(dev, 0x0001);
+	backup[1] = b43legacy_phy_read(dev, 0x0811);
+	backup[2] = b43legacy_phy_read(dev, 0x0812);
+	backup[3] = b43legacy_phy_read(dev, 0x0814);
+	backup[4] = b43legacy_phy_read(dev, 0x0815);
+	backup[5] = b43legacy_phy_read(dev, 0x005A);
+	backup[6] = b43legacy_phy_read(dev, 0x0059);
+	backup[7] = b43legacy_phy_read(dev, 0x0058);
+	backup[8] = b43legacy_phy_read(dev, 0x000A);
+	backup[9] = b43legacy_phy_read(dev, 0x0003);
+	backup[10] = b43legacy_radio_read16(dev, 0x007A);
+	backup[11] = b43legacy_radio_read16(dev, 0x0043);
+
+	b43legacy_phy_write(dev, 0x0429,
+			    b43legacy_phy_read(dev, 0x0429) & 0x7FFF);
+	b43legacy_phy_write(dev, 0x0001,
+			    (b43legacy_phy_read(dev, 0x0001) & 0x3FFF)
+			    | 0x4000);
+	b43legacy_phy_write(dev, 0x0811,
+			    b43legacy_phy_read(dev, 0x0811) | 0x000C);
+	b43legacy_phy_write(dev, 0x0812,
+			    (b43legacy_phy_read(dev, 0x0812) & 0xFFF3)
+			    | 0x0004);
+	b43legacy_phy_write(dev, 0x0802,
+			    b43legacy_phy_read(dev, 0x0802) & ~(0x1 | 0x2));
+	if (phy->rev >= 6) {
+		backup[12] = b43legacy_phy_read(dev, 0x002E);
+		backup[13] = b43legacy_phy_read(dev, 0x002F);
+		backup[14] = b43legacy_phy_read(dev, 0x080F);
+		backup[15] = b43legacy_phy_read(dev, 0x0810);
+		backup[16] = b43legacy_phy_read(dev, 0x0801);
+		backup[17] = b43legacy_phy_read(dev, 0x0060);
+		backup[18] = b43legacy_phy_read(dev, 0x0014);
+		backup[19] = b43legacy_phy_read(dev, 0x0478);
+
+		b43legacy_phy_write(dev, 0x002E, 0);
+		b43legacy_phy_write(dev, 0x002F, 0);
+		b43legacy_phy_write(dev, 0x080F, 0);
+		b43legacy_phy_write(dev, 0x0810, 0);
+		b43legacy_phy_write(dev, 0x0478,
+				    b43legacy_phy_read(dev, 0x0478) | 0x0100);
+		b43legacy_phy_write(dev, 0x0801,
+				    b43legacy_phy_read(dev, 0x0801) | 0x0040);
+		b43legacy_phy_write(dev, 0x0060,
+				    b43legacy_phy_read(dev, 0x0060) | 0x0040);
+		b43legacy_phy_write(dev, 0x0014,
+				    b43legacy_phy_read(dev, 0x0014) | 0x0200);
+	}
+	b43legacy_radio_write16(dev, 0x007A,
+				b43legacy_radio_read16(dev, 0x007A) | 0x0070);
+	b43legacy_radio_write16(dev, 0x007A,
+				b43legacy_radio_read16(dev, 0x007A) | 0x0080);
+	udelay(30);
+
+	v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
+	if (v47F >= 0x20)
+		v47F -= 0x40;
+	if (v47F == 31) {
+		for (i = 7; i >= 4; i--) {
+			b43legacy_radio_write16(dev, 0x007B, i);
+			udelay(20);
+			v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8)
+							 & 0x003F);
+			if (v47F >= 0x20)
+				v47F -= 0x40;
+			if (v47F < 31 && saved == 0xFFFF)
+				saved = i;
+		}
+		if (saved == 0xFFFF)
+			saved = 4;
+	} else {
+		b43legacy_radio_write16(dev, 0x007A,
+					b43legacy_radio_read16(dev, 0x007A)
+					& 0x007F);
+		b43legacy_phy_write(dev, 0x0814,
+				    b43legacy_phy_read(dev, 0x0814) | 0x0001);
+		b43legacy_phy_write(dev, 0x0815,
+				    b43legacy_phy_read(dev, 0x0815) & 0xFFFE);
+		b43legacy_phy_write(dev, 0x0811,
+				    b43legacy_phy_read(dev, 0x0811) | 0x000C);
+		b43legacy_phy_write(dev, 0x0812,
+				    b43legacy_phy_read(dev, 0x0812) | 0x000C);
+		b43legacy_phy_write(dev, 0x0811,
+				    b43legacy_phy_read(dev, 0x0811) | 0x0030);
+		b43legacy_phy_write(dev, 0x0812,
+				    b43legacy_phy_read(dev, 0x0812) | 0x0030);
+		b43legacy_phy_write(dev, 0x005A, 0x0480);
+		b43legacy_phy_write(dev, 0x0059, 0x0810);
+		b43legacy_phy_write(dev, 0x0058, 0x000D);
+		if (phy->analog == 0)
+			b43legacy_phy_write(dev, 0x0003, 0x0122);
+		else
+			b43legacy_phy_write(dev, 0x000A,
+					    b43legacy_phy_read(dev, 0x000A)
+					    | 0x2000);
+		b43legacy_phy_write(dev, 0x0814,
+				    b43legacy_phy_read(dev, 0x0814) | 0x0004);
+		b43legacy_phy_write(dev, 0x0815,
+				    b43legacy_phy_read(dev, 0x0815) & 0xFFFB);
+		b43legacy_phy_write(dev, 0x0003,
+				    (b43legacy_phy_read(dev, 0x0003) & 0xFF9F)
+				    | 0x0040);
+		b43legacy_radio_write16(dev, 0x007A,
+					b43legacy_radio_read16(dev, 0x007A)
+					| 0x000F);
+		b43legacy_set_all_gains(dev, 3, 0, 1);
+		b43legacy_radio_write16(dev, 0x0043,
+					(b43legacy_radio_read16(dev, 0x0043)
+					& 0x00F0) | 0x000F);
+		udelay(30);
+		v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
+		if (v47F >= 0x20)
+			v47F -= 0x40;
+		if (v47F == -32) {
+			for (i = 0; i < 4; i++) {
+				b43legacy_radio_write16(dev, 0x007B, i);
+				udelay(20);
+				v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >>
+								 8) & 0x003F);
+				if (v47F >= 0x20)
+					v47F -= 0x40;
+				if (v47F > -31 && saved == 0xFFFF)
+					saved = i;
+			}
+			if (saved == 0xFFFF)
+				saved = 3;
+		} else
+			saved = 0;
+	}
+	b43legacy_radio_write16(dev, 0x007B, saved);
+
+	if (phy->rev >= 6) {
+		b43legacy_phy_write(dev, 0x002E, backup[12]);
+		b43legacy_phy_write(dev, 0x002F, backup[13]);
+		b43legacy_phy_write(dev, 0x080F, backup[14]);
+		b43legacy_phy_write(dev, 0x0810, backup[15]);
+	}
+	b43legacy_phy_write(dev, 0x0814, backup[3]);
+	b43legacy_phy_write(dev, 0x0815, backup[4]);
+	b43legacy_phy_write(dev, 0x005A, backup[5]);
+	b43legacy_phy_write(dev, 0x0059, backup[6]);
+	b43legacy_phy_write(dev, 0x0058, backup[7]);
+	b43legacy_phy_write(dev, 0x000A, backup[8]);
+	b43legacy_phy_write(dev, 0x0003, backup[9]);
+	b43legacy_radio_write16(dev, 0x0043, backup[11]);
+	b43legacy_radio_write16(dev, 0x007A, backup[10]);
+	b43legacy_phy_write(dev, 0x0802,
+			    b43legacy_phy_read(dev, 0x0802) | 0x1 | 0x2);
+	b43legacy_phy_write(dev, 0x0429,
+			    b43legacy_phy_read(dev, 0x0429) | 0x8000);
+	b43legacy_set_original_gains(dev);
+	if (phy->rev >= 6) {
+		b43legacy_phy_write(dev, 0x0801, backup[16]);
+		b43legacy_phy_write(dev, 0x0060, backup[17]);
+		b43legacy_phy_write(dev, 0x0014, backup[18]);
+		b43legacy_phy_write(dev, 0x0478, backup[19]);
+	}
+	b43legacy_phy_write(dev, 0x0001, backup[0]);
+	b43legacy_phy_write(dev, 0x0812, backup[2]);
+	b43legacy_phy_write(dev, 0x0811, backup[1]);
+}
+
+void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 backup[18] = { 0 };
+	u16 tmp;
+	s16 nrssi0;
+	s16 nrssi1;
+
+	switch (phy->type) {
+	case B43legacy_PHYTYPE_B:
+		backup[0] = b43legacy_radio_read16(dev, 0x007A);
+		backup[1] = b43legacy_radio_read16(dev, 0x0052);
+		backup[2] = b43legacy_radio_read16(dev, 0x0043);
+		backup[3] = b43legacy_phy_read(dev, 0x0030);
+		backup[4] = b43legacy_phy_read(dev, 0x0026);
+		backup[5] = b43legacy_phy_read(dev, 0x0015);
+		backup[6] = b43legacy_phy_read(dev, 0x002A);
+		backup[7] = b43legacy_phy_read(dev, 0x0020);
+		backup[8] = b43legacy_phy_read(dev, 0x005A);
+		backup[9] = b43legacy_phy_read(dev, 0x0059);
+		backup[10] = b43legacy_phy_read(dev, 0x0058);
+		backup[11] = b43legacy_read16(dev, 0x03E2);
+		backup[12] = b43legacy_read16(dev, 0x03E6);
+		backup[13] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
+
+		tmp  = b43legacy_radio_read16(dev, 0x007A);
+		tmp &= (phy->rev >= 5) ? 0x007F : 0x000F;
+		b43legacy_radio_write16(dev, 0x007A, tmp);
+		b43legacy_phy_write(dev, 0x0030, 0x00FF);
+		b43legacy_write16(dev, 0x03EC, 0x7F7F);
+		b43legacy_phy_write(dev, 0x0026, 0x0000);
+		b43legacy_phy_write(dev, 0x0015,
+				    b43legacy_phy_read(dev, 0x0015) | 0x0020);
+		b43legacy_phy_write(dev, 0x002A, 0x08A3);
+		b43legacy_radio_write16(dev, 0x007A,
+					b43legacy_radio_read16(dev, 0x007A)
+					| 0x0080);
+
+		nrssi0 = (s16)b43legacy_phy_read(dev, 0x0027);
+		b43legacy_radio_write16(dev, 0x007A,
+					b43legacy_radio_read16(dev, 0x007A)
+					& 0x007F);
+		if (phy->analog >= 2)
+			b43legacy_write16(dev, 0x03E6, 0x0040);
+		else if (phy->analog == 0)
+			b43legacy_write16(dev, 0x03E6, 0x0122);
+		else
+			b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
+					  b43legacy_read16(dev,
+					  B43legacy_MMIO_CHANNEL_EXT) & 0x2000);
+		b43legacy_phy_write(dev, 0x0020, 0x3F3F);
+		b43legacy_phy_write(dev, 0x0015, 0xF330);
+		b43legacy_radio_write16(dev, 0x005A, 0x0060);
+		b43legacy_radio_write16(dev, 0x0043,
+					b43legacy_radio_read16(dev, 0x0043)
+					& 0x00F0);
+		b43legacy_phy_write(dev, 0x005A, 0x0480);
+		b43legacy_phy_write(dev, 0x0059, 0x0810);
+		b43legacy_phy_write(dev, 0x0058, 0x000D);
+		udelay(20);
+
+		nrssi1 = (s16)b43legacy_phy_read(dev, 0x0027);
+		b43legacy_phy_write(dev, 0x0030, backup[3]);
+		b43legacy_radio_write16(dev, 0x007A, backup[0]);
+		b43legacy_write16(dev, 0x03E2, backup[11]);
+		b43legacy_phy_write(dev, 0x0026, backup[4]);
+		b43legacy_phy_write(dev, 0x0015, backup[5]);
+		b43legacy_phy_write(dev, 0x002A, backup[6]);
+		b43legacy_synth_pu_workaround(dev, phy->channel);
+		if (phy->analog != 0)
+			b43legacy_write16(dev, 0x03F4, backup[13]);
+
+		b43legacy_phy_write(dev, 0x0020, backup[7]);
+		b43legacy_phy_write(dev, 0x005A, backup[8]);
+		b43legacy_phy_write(dev, 0x0059, backup[9]);
+		b43legacy_phy_write(dev, 0x0058, backup[10]);
+		b43legacy_radio_write16(dev, 0x0052, backup[1]);
+		b43legacy_radio_write16(dev, 0x0043, backup[2]);
+
+		if (nrssi0 == nrssi1)
+			phy->nrssislope = 0x00010000;
+		else
+			phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
+
+		if (nrssi0 <= -4) {
+			phy->nrssi[0] = nrssi0;
+			phy->nrssi[1] = nrssi1;
+		}
+		break;
+	case B43legacy_PHYTYPE_G:
+		if (phy->radio_rev >= 9)
+			return;
+		if (phy->radio_rev == 8)
+			b43legacy_calc_nrssi_offset(dev);
+
+		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+				    b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
+				    & 0x7FFF);
+		b43legacy_phy_write(dev, 0x0802,
+				    b43legacy_phy_read(dev, 0x0802) & 0xFFFC);
+		backup[7] = b43legacy_read16(dev, 0x03E2);
+		b43legacy_write16(dev, 0x03E2,
+				  b43legacy_read16(dev, 0x03E2) | 0x8000);
+		backup[0] = b43legacy_radio_read16(dev, 0x007A);
+		backup[1] = b43legacy_radio_read16(dev, 0x0052);
+		backup[2] = b43legacy_radio_read16(dev, 0x0043);
+		backup[3] = b43legacy_phy_read(dev, 0x0015);
+		backup[4] = b43legacy_phy_read(dev, 0x005A);
+		backup[5] = b43legacy_phy_read(dev, 0x0059);
+		backup[6] = b43legacy_phy_read(dev, 0x0058);
+		backup[8] = b43legacy_read16(dev, 0x03E6);
+		backup[9] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
+		if (phy->rev >= 3) {
+			backup[10] = b43legacy_phy_read(dev, 0x002E);
+			backup[11] = b43legacy_phy_read(dev, 0x002F);
+			backup[12] = b43legacy_phy_read(dev, 0x080F);
+			backup[13] = b43legacy_phy_read(dev,
+						B43legacy_PHY_G_LO_CONTROL);
+			backup[14] = b43legacy_phy_read(dev, 0x0801);
+			backup[15] = b43legacy_phy_read(dev, 0x0060);
+			backup[16] = b43legacy_phy_read(dev, 0x0014);
+			backup[17] = b43legacy_phy_read(dev, 0x0478);
+			b43legacy_phy_write(dev, 0x002E, 0);
+			b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL, 0);
+			switch (phy->rev) {
+			case 4: case 6: case 7:
+				b43legacy_phy_write(dev, 0x0478,
+						    b43legacy_phy_read(dev,
+						    0x0478) | 0x0100);
+				b43legacy_phy_write(dev, 0x0801,
+						    b43legacy_phy_read(dev,
+						    0x0801) | 0x0040);
+				break;
+			case 3: case 5:
+				b43legacy_phy_write(dev, 0x0801,
+						    b43legacy_phy_read(dev,
+						    0x0801) & 0xFFBF);
+				break;
+			}
+			b43legacy_phy_write(dev, 0x0060,
+					    b43legacy_phy_read(dev, 0x0060)
+					    | 0x0040);
+			b43legacy_phy_write(dev, 0x0014,
+					    b43legacy_phy_read(dev, 0x0014)
+					    | 0x0200);
+		}
+		b43legacy_radio_write16(dev, 0x007A,
+					b43legacy_radio_read16(dev, 0x007A)
+					| 0x0070);
+		b43legacy_set_all_gains(dev, 0, 8, 0);
+		b43legacy_radio_write16(dev, 0x007A,
+					b43legacy_radio_read16(dev, 0x007A)
+					& 0x00F7);
+		if (phy->rev >= 2) {
+			b43legacy_phy_write(dev, 0x0811,
+					    (b43legacy_phy_read(dev, 0x0811)
+					    & 0xFFCF) | 0x0030);
+			b43legacy_phy_write(dev, 0x0812,
+					    (b43legacy_phy_read(dev, 0x0812)
+					    & 0xFFCF) | 0x0010);
+		}
+		b43legacy_radio_write16(dev, 0x007A,
+					b43legacy_radio_read16(dev, 0x007A)
+					| 0x0080);
+		udelay(20);
+
+		nrssi0 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
+		if (nrssi0 >= 0x0020)
+			nrssi0 -= 0x0040;
+
+		b43legacy_radio_write16(dev, 0x007A,
+					b43legacy_radio_read16(dev, 0x007A)
+					& 0x007F);
+		if (phy->analog >= 2)
+			b43legacy_phy_write(dev, 0x0003,
+					    (b43legacy_phy_read(dev, 0x0003)
+					    & 0xFF9F) | 0x0040);
+
+		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
+				  b43legacy_read16(dev,
+				  B43legacy_MMIO_CHANNEL_EXT) | 0x2000);
+		b43legacy_radio_write16(dev, 0x007A,
+					b43legacy_radio_read16(dev, 0x007A)
+					| 0x000F);
+		b43legacy_phy_write(dev, 0x0015, 0xF330);
+		if (phy->rev >= 2) {
+			b43legacy_phy_write(dev, 0x0812,
+					    (b43legacy_phy_read(dev, 0x0812)
+					    & 0xFFCF) | 0x0020);
+			b43legacy_phy_write(dev, 0x0811,
+					    (b43legacy_phy_read(dev, 0x0811)
+					    & 0xFFCF) | 0x0020);
+		}
+
+		b43legacy_set_all_gains(dev, 3, 0, 1);
+		if (phy->radio_rev == 8)
+			b43legacy_radio_write16(dev, 0x0043, 0x001F);
+		else {
+			tmp = b43legacy_radio_read16(dev, 0x0052) & 0xFF0F;
+			b43legacy_radio_write16(dev, 0x0052, tmp | 0x0060);
+			tmp = b43legacy_radio_read16(dev, 0x0043) & 0xFFF0;
+			b43legacy_radio_write16(dev, 0x0043, tmp | 0x0009);
+		}
+		b43legacy_phy_write(dev, 0x005A, 0x0480);
+		b43legacy_phy_write(dev, 0x0059, 0x0810);
+		b43legacy_phy_write(dev, 0x0058, 0x000D);
+		udelay(20);
+		nrssi1 = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);
+		if (nrssi1 >= 0x0020)
+			nrssi1 -= 0x0040;
+		if (nrssi0 == nrssi1)
+			phy->nrssislope = 0x00010000;
+		else
+			phy->nrssislope = 0x00400000 / (nrssi0 - nrssi1);
+		if (nrssi0 >= -4) {
+			phy->nrssi[0] = nrssi1;
+			phy->nrssi[1] = nrssi0;
+		}
+		if (phy->rev >= 3) {
+			b43legacy_phy_write(dev, 0x002E, backup[10]);
+			b43legacy_phy_write(dev, 0x002F, backup[11]);
+			b43legacy_phy_write(dev, 0x080F, backup[12]);
+			b43legacy_phy_write(dev, B43legacy_PHY_G_LO_CONTROL,
+					    backup[13]);
+		}
+		if (phy->rev >= 2) {
+			b43legacy_phy_write(dev, 0x0812,
+					    b43legacy_phy_read(dev, 0x0812)
+					    & 0xFFCF);
+			b43legacy_phy_write(dev, 0x0811,
+					    b43legacy_phy_read(dev, 0x0811)
+					    & 0xFFCF);
+		}
+
+		b43legacy_radio_write16(dev, 0x007A, backup[0]);
+		b43legacy_radio_write16(dev, 0x0052, backup[1]);
+		b43legacy_radio_write16(dev, 0x0043, backup[2]);
+		b43legacy_write16(dev, 0x03E2, backup[7]);
+		b43legacy_write16(dev, 0x03E6, backup[8]);
+		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[9]);
+		b43legacy_phy_write(dev, 0x0015, backup[3]);
+		b43legacy_phy_write(dev, 0x005A, backup[4]);
+		b43legacy_phy_write(dev, 0x0059, backup[5]);
+		b43legacy_phy_write(dev, 0x0058, backup[6]);
+		b43legacy_synth_pu_workaround(dev, phy->channel);
+		b43legacy_phy_write(dev, 0x0802,
+				    b43legacy_phy_read(dev, 0x0802) | 0x0003);
+		b43legacy_set_original_gains(dev);
+		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+				    b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
+				    | 0x8000);
+		if (phy->rev >= 3) {
+			b43legacy_phy_write(dev, 0x0801, backup[14]);
+			b43legacy_phy_write(dev, 0x0060, backup[15]);
+			b43legacy_phy_write(dev, 0x0014, backup[16]);
+			b43legacy_phy_write(dev, 0x0478, backup[17]);
+		}
+		b43legacy_nrssi_mem_update(dev);
+		b43legacy_calc_nrssi_threshold(dev);
+		break;
+	default:
+		B43legacy_BUG_ON(1);
+	}
+}
+
+void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	s32 threshold;
+	s32 a;
+	s32 b;
+	s16 tmp16;
+	u16 tmp_u16;
+
+	switch (phy->type) {
+	case B43legacy_PHYTYPE_B: {
+		if (phy->radio_ver != 0x2050)
+			return;
+		if (!(dev->dev->bus->sprom.r1.boardflags_lo &
+		    B43legacy_BFL_RSSI))
+			return;
+
+		if (phy->radio_rev >= 6) {
+			threshold = (phy->nrssi[1] - phy->nrssi[0]) * 32;
+			threshold += 20 * (phy->nrssi[0] + 1);
+			threshold /= 40;
+		} else
+			threshold = phy->nrssi[1] - 5;
+
+		threshold = limit_value(threshold, 0, 0x3E);
+		b43legacy_phy_read(dev, 0x0020); /* dummy read */
+		b43legacy_phy_write(dev, 0x0020, (((u16)threshold) << 8)
+				    | 0x001C);
+
+		if (phy->radio_rev >= 6) {
+			b43legacy_phy_write(dev, 0x0087, 0x0E0D);
+			b43legacy_phy_write(dev, 0x0086, 0x0C0B);
+			b43legacy_phy_write(dev, 0x0085, 0x0A09);
+			b43legacy_phy_write(dev, 0x0084, 0x0808);
+			b43legacy_phy_write(dev, 0x0083, 0x0808);
+			b43legacy_phy_write(dev, 0x0082, 0x0604);
+			b43legacy_phy_write(dev, 0x0081, 0x0302);
+			b43legacy_phy_write(dev, 0x0080, 0x0100);
+		}
+		break;
+	}
+	case B43legacy_PHYTYPE_G:
+		if (!phy->gmode ||
+		    !(dev->dev->bus->sprom.r1.boardflags_lo &
+		    B43legacy_BFL_RSSI)) {
+			tmp16 = b43legacy_nrssi_hw_read(dev, 0x20);
+			if (tmp16 >= 0x20)
+				tmp16 -= 0x40;
+			if (tmp16 < 3)
+				b43legacy_phy_write(dev, 0x048A,
+						    (b43legacy_phy_read(dev,
+						    0x048A) & 0xF000) | 0x09EB);
+			else
+				b43legacy_phy_write(dev, 0x048A,
+						    (b43legacy_phy_read(dev,
+						    0x048A) & 0xF000) | 0x0AED);
+		} else {
+			if (phy->interfmode ==
+			    B43legacy_RADIO_INTERFMODE_NONWLAN) {
+				a = 0xE;
+				b = 0xA;
+			} else if (!phy->aci_wlan_automatic &&
+				    phy->aci_enable) {
+				a = 0x13;
+				b = 0x12;
+			} else {
+				a = 0xE;
+				b = 0x11;
+			}
+
+			a = a * (phy->nrssi[1] - phy->nrssi[0]);
+			a += (phy->nrssi[0] << 6);
+			if (a < 32)
+				a += 31;
+			else
+				a += 32;
+			a = a >> 6;
+			a = limit_value(a, -31, 31);
+
+			b = b * (phy->nrssi[1] - phy->nrssi[0]);
+			b += (phy->nrssi[0] << 6);
+			if (b < 32)
+				b += 31;
+			else
+				b += 32;
+			b = b >> 6;
+			b = limit_value(b, -31, 31);
+
+			tmp_u16 = b43legacy_phy_read(dev, 0x048A) & 0xF000;
+			tmp_u16 |= ((u32)b & 0x0000003F);
+			tmp_u16 |= (((u32)a & 0x0000003F) << 6);
+			b43legacy_phy_write(dev, 0x048A, tmp_u16);
+		}
+		break;
+	default:
+		B43legacy_BUG_ON(1);
+	}
+}
+
+/* Stack implementation to save/restore values from the
+ * interference mitigation code.
+ * It is save to restore values in random order.
+ */
+static void _stack_save(u32 *_stackptr, size_t *stackidx,
+			u8 id, u16 offset, u16 value)
+{
+	u32 *stackptr = &(_stackptr[*stackidx]);
+
+	B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));
+	B43legacy_WARN_ON(!((id & 0xF8) == 0x00));
+	*stackptr = offset;
+	*stackptr |= ((u32)id) << 13;
+	*stackptr |= ((u32)value) << 16;
+	(*stackidx)++;
+	B43legacy_WARN_ON(!(*stackidx < B43legacy_INTERFSTACK_SIZE));
+}
+
+static u16 _stack_restore(u32 *stackptr,
+			  u8 id, u16 offset)
+{
+	size_t i;
+
+	B43legacy_WARN_ON(!((offset & 0xE000) == 0x0000));
+	B43legacy_WARN_ON(!((id & 0xF8) == 0x00));
+	for (i = 0; i < B43legacy_INTERFSTACK_SIZE; i++, stackptr++) {
+		if ((*stackptr & 0x00001FFF) != offset)
+			continue;
+		if (((*stackptr & 0x00007000) >> 13) != id)
+			continue;
+		return ((*stackptr & 0xFFFF0000) >> 16);
+	}
+	B43legacy_BUG_ON(1);
+
+	return 0;
+}
+
+#define phy_stacksave(offset)					\
+	do {							\
+		_stack_save(stack, &stackidx, 0x1, (offset),	\
+			    b43legacy_phy_read(dev, (offset)));	\
+	} while (0)
+#define phy_stackrestore(offset)				\
+	do {							\
+		b43legacy_phy_write(dev, (offset),		\
+				    _stack_restore(stack, 0x1,	\
+				    (offset)));			\
+	} while (0)
+#define radio_stacksave(offset)						\
+	do {								\
+		_stack_save(stack, &stackidx, 0x2, (offset),		\
+			    b43legacy_radio_read16(dev, (offset)));	\
+	} while (0)
+#define radio_stackrestore(offset)					\
+	do {								\
+		b43legacy_radio_write16(dev, (offset),			\
+					_stack_restore(stack, 0x2,	\
+					(offset)));			\
+	} while (0)
+#define ilt_stacksave(offset)					\
+	do {							\
+		_stack_save(stack, &stackidx, 0x3, (offset),	\
+			    b43legacy_ilt_read(dev, (offset)));	\
+	} while (0)
+#define ilt_stackrestore(offset)				\
+	do {							\
+		b43legacy_ilt_write(dev, (offset),		\
+				  _stack_restore(stack, 0x3,	\
+						 (offset)));	\
+	} while (0)
+
+static void
+b43legacy_radio_interference_mitigation_enable(struct b43legacy_wldev *dev,
+					       int mode)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 tmp;
+	u16 flipped;
+	u32 tmp32;
+	size_t stackidx = 0;
+	u32 *stack = phy->interfstack;
+
+	switch (mode) {
+	case B43legacy_RADIO_INTERFMODE_NONWLAN:
+		if (phy->rev != 1) {
+			b43legacy_phy_write(dev, 0x042B,
+					    b43legacy_phy_read(dev, 0x042B)
+					    | 0x0800);
+			b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+					    b43legacy_phy_read(dev,
+					    B43legacy_PHY_G_CRS) & ~0x4000);
+			break;
+		}
+		radio_stacksave(0x0078);
+		tmp = (b43legacy_radio_read16(dev, 0x0078) & 0x001E);
+		flipped = flip_4bit(tmp);
+		if (flipped < 10 && flipped >= 8)
+			flipped = 7;
+		else if (flipped >= 10)
+			flipped -= 3;
+		flipped = flip_4bit(flipped);
+		flipped = (flipped << 1) | 0x0020;
+		b43legacy_radio_write16(dev, 0x0078, flipped);
+
+		b43legacy_calc_nrssi_threshold(dev);
+
+		phy_stacksave(0x0406);
+		b43legacy_phy_write(dev, 0x0406, 0x7E28);
+
+		b43legacy_phy_write(dev, 0x042B,
+				    b43legacy_phy_read(dev, 0x042B) | 0x0800);
+		b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
+				    b43legacy_phy_read(dev,
+				    B43legacy_PHY_RADIO_BITFIELD) | 0x1000);
+
+		phy_stacksave(0x04A0);
+		b43legacy_phy_write(dev, 0x04A0,
+				    (b43legacy_phy_read(dev, 0x04A0) & 0xC0C0)
+				    | 0x0008);
+		phy_stacksave(0x04A1);
+		b43legacy_phy_write(dev, 0x04A1,
+				    (b43legacy_phy_read(dev, 0x04A1) & 0xC0C0)
+				    | 0x0605);
+		phy_stacksave(0x04A2);
+		b43legacy_phy_write(dev, 0x04A2,
+				    (b43legacy_phy_read(dev, 0x04A2) & 0xC0C0)
+				    | 0x0204);
+		phy_stacksave(0x04A8);
+		b43legacy_phy_write(dev, 0x04A8,
+				    (b43legacy_phy_read(dev, 0x04A8) & 0xC0C0)
+				    | 0x0803);
+		phy_stacksave(0x04AB);
+		b43legacy_phy_write(dev, 0x04AB,
+				    (b43legacy_phy_read(dev, 0x04AB) & 0xC0C0)
+				    | 0x0605);
+
+		phy_stacksave(0x04A7);
+		b43legacy_phy_write(dev, 0x04A7, 0x0002);
+		phy_stacksave(0x04A3);
+		b43legacy_phy_write(dev, 0x04A3, 0x287A);
+		phy_stacksave(0x04A9);
+		b43legacy_phy_write(dev, 0x04A9, 0x2027);
+		phy_stacksave(0x0493);
+		b43legacy_phy_write(dev, 0x0493, 0x32F5);
+		phy_stacksave(0x04AA);
+		b43legacy_phy_write(dev, 0x04AA, 0x2027);
+		phy_stacksave(0x04AC);
+		b43legacy_phy_write(dev, 0x04AC, 0x32F5);
+		break;
+	case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
+		if (b43legacy_phy_read(dev, 0x0033) & 0x0800)
+			break;
+
+		phy->aci_enable = 1;
+
+		phy_stacksave(B43legacy_PHY_RADIO_BITFIELD);
+		phy_stacksave(B43legacy_PHY_G_CRS);
+		if (phy->rev < 2)
+			phy_stacksave(0x0406);
+		else {
+			phy_stacksave(0x04C0);
+			phy_stacksave(0x04C1);
+		}
+		phy_stacksave(0x0033);
+		phy_stacksave(0x04A7);
+		phy_stacksave(0x04A3);
+		phy_stacksave(0x04A9);
+		phy_stacksave(0x04AA);
+		phy_stacksave(0x04AC);
+		phy_stacksave(0x0493);
+		phy_stacksave(0x04A1);
+		phy_stacksave(0x04A0);
+		phy_stacksave(0x04A2);
+		phy_stacksave(0x048A);
+		phy_stacksave(0x04A8);
+		phy_stacksave(0x04AB);
+		if (phy->rev == 2) {
+			phy_stacksave(0x04AD);
+			phy_stacksave(0x04AE);
+		} else if (phy->rev >= 3) {
+			phy_stacksave(0x04AD);
+			phy_stacksave(0x0415);
+			phy_stacksave(0x0416);
+			phy_stacksave(0x0417);
+			ilt_stacksave(0x1A00 + 0x2);
+			ilt_stacksave(0x1A00 + 0x3);
+		}
+		phy_stacksave(0x042B);
+		phy_stacksave(0x048C);
+
+		b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
+				    b43legacy_phy_read(dev,
+				    B43legacy_PHY_RADIO_BITFIELD) & ~0x1000);
+		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+				    (b43legacy_phy_read(dev,
+				    B43legacy_PHY_G_CRS)
+				    & 0xFFFC) | 0x0002);
+
+		b43legacy_phy_write(dev, 0x0033, 0x0800);
+		b43legacy_phy_write(dev, 0x04A3, 0x2027);
+		b43legacy_phy_write(dev, 0x04A9, 0x1CA8);
+		b43legacy_phy_write(dev, 0x0493, 0x287A);
+		b43legacy_phy_write(dev, 0x04AA, 0x1CA8);
+		b43legacy_phy_write(dev, 0x04AC, 0x287A);
+
+		b43legacy_phy_write(dev, 0x04A0,
+				    (b43legacy_phy_read(dev, 0x04A0)
+				    & 0xFFC0) | 0x001A);
+		b43legacy_phy_write(dev, 0x04A7, 0x000D);
+
+		if (phy->rev < 2)
+			b43legacy_phy_write(dev, 0x0406, 0xFF0D);
+		else if (phy->rev == 2) {
+			b43legacy_phy_write(dev, 0x04C0, 0xFFFF);
+			b43legacy_phy_write(dev, 0x04C1, 0x00A9);
+		} else {
+			b43legacy_phy_write(dev, 0x04C0, 0x00C1);
+			b43legacy_phy_write(dev, 0x04C1, 0x0059);
+		}
+
+		b43legacy_phy_write(dev, 0x04A1,
+				    (b43legacy_phy_read(dev, 0x04A1)
+				    & 0xC0FF) | 0x1800);
+		b43legacy_phy_write(dev, 0x04A1,
+				    (b43legacy_phy_read(dev, 0x04A1)
+				    & 0xFFC0) | 0x0015);
+		b43legacy_phy_write(dev, 0x04A8,
+				    (b43legacy_phy_read(dev, 0x04A8)
+				    & 0xCFFF) | 0x1000);
+		b43legacy_phy_write(dev, 0x04A8,
+				    (b43legacy_phy_read(dev, 0x04A8)
+				    & 0xF0FF) | 0x0A00);
+		b43legacy_phy_write(dev, 0x04AB,
+				    (b43legacy_phy_read(dev, 0x04AB)
+				    & 0xCFFF) | 0x1000);
+		b43legacy_phy_write(dev, 0x04AB,
+				    (b43legacy_phy_read(dev, 0x04AB)
+				    & 0xF0FF) | 0x0800);
+		b43legacy_phy_write(dev, 0x04AB,
+				    (b43legacy_phy_read(dev, 0x04AB)
+				    & 0xFFCF) | 0x0010);
+		b43legacy_phy_write(dev, 0x04AB,
+				    (b43legacy_phy_read(dev, 0x04AB)
+				    & 0xFFF0) | 0x0005);
+		b43legacy_phy_write(dev, 0x04A8,
+				    (b43legacy_phy_read(dev, 0x04A8)
+				    & 0xFFCF) | 0x0010);
+		b43legacy_phy_write(dev, 0x04A8,
+				    (b43legacy_phy_read(dev, 0x04A8)
+				    & 0xFFF0) | 0x0006);
+		b43legacy_phy_write(dev, 0x04A2,
+				    (b43legacy_phy_read(dev, 0x04A2)
+				    & 0xF0FF) | 0x0800);
+		b43legacy_phy_write(dev, 0x04A0,
+				    (b43legacy_phy_read(dev, 0x04A0)
+				    & 0xF0FF) | 0x0500);
+		b43legacy_phy_write(dev, 0x04A2,
+				    (b43legacy_phy_read(dev, 0x04A2)
+				    & 0xFFF0) | 0x000B);
+
+		if (phy->rev >= 3) {
+			b43legacy_phy_write(dev, 0x048A,
+					    b43legacy_phy_read(dev, 0x048A)
+					    & ~0x8000);
+			b43legacy_phy_write(dev, 0x0415,
+					    (b43legacy_phy_read(dev, 0x0415)
+					    & 0x8000) | 0x36D8);
+			b43legacy_phy_write(dev, 0x0416,
+					    (b43legacy_phy_read(dev, 0x0416)
+					    & 0x8000) | 0x36D8);
+			b43legacy_phy_write(dev, 0x0417,
+					    (b43legacy_phy_read(dev, 0x0417)
+					    & 0xFE00) | 0x016D);
+		} else {
+			b43legacy_phy_write(dev, 0x048A,
+					    b43legacy_phy_read(dev, 0x048A)
+					    | 0x1000);
+			b43legacy_phy_write(dev, 0x048A,
+					    (b43legacy_phy_read(dev, 0x048A)
+					    & 0x9FFF) | 0x2000);
+			tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
+					    B43legacy_UCODEFLAGS_OFFSET);
+			if (!(tmp32 & 0x800)) {
+				tmp32 |= 0x800;
+				b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+					    B43legacy_UCODEFLAGS_OFFSET,
+					    tmp32);
+			}
+		}
+		if (phy->rev >= 2)
+			b43legacy_phy_write(dev, 0x042B,
+					    b43legacy_phy_read(dev, 0x042B)
+					    | 0x0800);
+		b43legacy_phy_write(dev, 0x048C,
+				    (b43legacy_phy_read(dev, 0x048C)
+				    & 0xF0FF) | 0x0200);
+		if (phy->rev == 2) {
+			b43legacy_phy_write(dev, 0x04AE,
+					    (b43legacy_phy_read(dev, 0x04AE)
+					    & 0xFF00) | 0x007F);
+			b43legacy_phy_write(dev, 0x04AD,
+					    (b43legacy_phy_read(dev, 0x04AD)
+					    & 0x00FF) | 0x1300);
+		} else if (phy->rev >= 6) {
+			b43legacy_ilt_write(dev, 0x1A00 + 0x3, 0x007F);
+			b43legacy_ilt_write(dev, 0x1A00 + 0x2, 0x007F);
+			b43legacy_phy_write(dev, 0x04AD,
+					    b43legacy_phy_read(dev, 0x04AD)
+					    & 0x00FF);
+		}
+		b43legacy_calc_nrssi_slope(dev);
+		break;
+	default:
+		B43legacy_BUG_ON(1);
+	}
+}
+
+static void
+b43legacy_radio_interference_mitigation_disable(struct b43legacy_wldev *dev,
+						int mode)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u32 tmp32;
+	u32 *stack = phy->interfstack;
+
+	switch (mode) {
+	case B43legacy_RADIO_INTERFMODE_NONWLAN:
+		if (phy->rev != 1) {
+			b43legacy_phy_write(dev, 0x042B,
+					    b43legacy_phy_read(dev, 0x042B)
+					    & ~0x0800);
+			b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+					    b43legacy_phy_read(dev,
+					    B43legacy_PHY_G_CRS) | 0x4000);
+			break;
+		}
+		phy_stackrestore(0x0078);
+		b43legacy_calc_nrssi_threshold(dev);
+		phy_stackrestore(0x0406);
+		b43legacy_phy_write(dev, 0x042B,
+				    b43legacy_phy_read(dev, 0x042B) & ~0x0800);
+		if (!dev->bad_frames_preempt)
+			b43legacy_phy_write(dev, B43legacy_PHY_RADIO_BITFIELD,
+					    b43legacy_phy_read(dev,
+					    B43legacy_PHY_RADIO_BITFIELD)
+					    & ~(1 << 11));
+		b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+				    b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)
+				    | 0x4000);
+		phy_stackrestore(0x04A0);
+		phy_stackrestore(0x04A1);
+		phy_stackrestore(0x04A2);
+		phy_stackrestore(0x04A8);
+		phy_stackrestore(0x04AB);
+		phy_stackrestore(0x04A7);
+		phy_stackrestore(0x04A3);
+		phy_stackrestore(0x04A9);
+		phy_stackrestore(0x0493);
+		phy_stackrestore(0x04AA);
+		phy_stackrestore(0x04AC);
+		break;
+	case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
+		if (!(b43legacy_phy_read(dev, 0x0033) & 0x0800))
+			break;
+
+		phy->aci_enable = 0;
+
+		phy_stackrestore(B43legacy_PHY_RADIO_BITFIELD);
+		phy_stackrestore(B43legacy_PHY_G_CRS);
+		phy_stackrestore(0x0033);
+		phy_stackrestore(0x04A3);
+		phy_stackrestore(0x04A9);
+		phy_stackrestore(0x0493);
+		phy_stackrestore(0x04AA);
+		phy_stackrestore(0x04AC);
+		phy_stackrestore(0x04A0);
+		phy_stackrestore(0x04A7);
+		if (phy->rev >= 2) {
+			phy_stackrestore(0x04C0);
+			phy_stackrestore(0x04C1);
+		} else
+			phy_stackrestore(0x0406);
+		phy_stackrestore(0x04A1);
+		phy_stackrestore(0x04AB);
+		phy_stackrestore(0x04A8);
+		if (phy->rev == 2) {
+			phy_stackrestore(0x04AD);
+			phy_stackrestore(0x04AE);
+		} else if (phy->rev >= 3) {
+			phy_stackrestore(0x04AD);
+			phy_stackrestore(0x0415);
+			phy_stackrestore(0x0416);
+			phy_stackrestore(0x0417);
+			ilt_stackrestore(0x1A00 + 0x2);
+			ilt_stackrestore(0x1A00 + 0x3);
+		}
+		phy_stackrestore(0x04A2);
+		phy_stackrestore(0x04A8);
+		phy_stackrestore(0x042B);
+		phy_stackrestore(0x048C);
+		tmp32 = b43legacy_shm_read32(dev, B43legacy_SHM_SHARED,
+					     B43legacy_UCODEFLAGS_OFFSET);
+		if (tmp32 & 0x800) {
+			tmp32 &= ~0x800;
+			b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+					      B43legacy_UCODEFLAGS_OFFSET,
+					      tmp32);
+		}
+		b43legacy_calc_nrssi_slope(dev);
+		break;
+	default:
+		B43legacy_BUG_ON(1);
+	}
+}
+
+#undef phy_stacksave
+#undef phy_stackrestore
+#undef radio_stacksave
+#undef radio_stackrestore
+#undef ilt_stacksave
+#undef ilt_stackrestore
+
+int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev,
+						int mode)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	int currentmode;
+
+	if ((phy->type != B43legacy_PHYTYPE_G) ||
+	    (phy->rev == 0) || (!phy->gmode))
+		return -ENODEV;
+
+	phy->aci_wlan_automatic = 0;
+	switch (mode) {
+	case B43legacy_RADIO_INTERFMODE_AUTOWLAN:
+		phy->aci_wlan_automatic = 1;
+		if (phy->aci_enable)
+			mode = B43legacy_RADIO_INTERFMODE_MANUALWLAN;
+		else
+			mode = B43legacy_RADIO_INTERFMODE_NONE;
+		break;
+	case B43legacy_RADIO_INTERFMODE_NONE:
+	case B43legacy_RADIO_INTERFMODE_NONWLAN:
+	case B43legacy_RADIO_INTERFMODE_MANUALWLAN:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	currentmode = phy->interfmode;
+	if (currentmode == mode)
+		return 0;
+	if (currentmode != B43legacy_RADIO_INTERFMODE_NONE)
+		b43legacy_radio_interference_mitigation_disable(dev,
+								currentmode);
+
+	if (mode == B43legacy_RADIO_INTERFMODE_NONE) {
+		phy->aci_enable = 0;
+		phy->aci_hw_rssi = 0;
+	} else
+		b43legacy_radio_interference_mitigation_enable(dev, mode);
+	phy->interfmode = mode;
+
+	return 0;
+}
+
+u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev)
+{
+	u16 reg;
+	u16 index;
+	u16 ret;
+
+	reg = b43legacy_radio_read16(dev, 0x0060);
+	index = (reg & 0x001E) >> 1;
+	ret = rcc_table[index] << 1;
+	ret |= (reg & 0x0001);
+	ret |= 0x0020;
+
+	return ret;
+}
+
+#define LPD(L, P, D)    (((L) << 2) | ((P) << 1) | ((D) << 0))
+static u16 b43legacy_get_812_value(struct b43legacy_wldev *dev, u8 lpd)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 loop_or = 0;
+	u16 adj_loopback_gain = phy->loopback_gain[0];
+	u8 loop;
+	u16 extern_lna_control;
+
+	if (!phy->gmode)
+		return 0;
+	if (!has_loopback_gain(phy)) {
+		if (phy->rev < 7 || !(dev->dev->bus->sprom.r1.boardflags_lo
+		    & B43legacy_BFL_EXTLNA)) {
+			switch (lpd) {
+			case LPD(0, 1, 1):
+				return 0x0FB2;
+			case LPD(0, 0, 1):
+				return 0x00B2;
+			case LPD(1, 0, 1):
+				return 0x30B2;
+			case LPD(1, 0, 0):
+				return 0x30B3;
+			default:
+				B43legacy_BUG_ON(1);
+			}
+		} else {
+			switch (lpd) {
+			case LPD(0, 1, 1):
+				return 0x8FB2;
+			case LPD(0, 0, 1):
+				return 0x80B2;
+			case LPD(1, 0, 1):
+				return 0x20B2;
+			case LPD(1, 0, 0):
+				return 0x20B3;
+			default:
+				B43legacy_BUG_ON(1);
+			}
+		}
+	} else {
+		if (phy->radio_rev == 8)
+			adj_loopback_gain += 0x003E;
+		else
+			adj_loopback_gain += 0x0026;
+		if (adj_loopback_gain >= 0x46) {
+			adj_loopback_gain -= 0x46;
+			extern_lna_control = 0x3000;
+		} else if (adj_loopback_gain >= 0x3A) {
+			adj_loopback_gain -= 0x3A;
+			extern_lna_control = 0x2000;
+		} else if (adj_loopback_gain >= 0x2E) {
+			adj_loopback_gain -= 0x2E;
+			extern_lna_control = 0x1000;
+		} else {
+			adj_loopback_gain -= 0x10;
+			extern_lna_control = 0x0000;
+		}
+		for (loop = 0; loop < 16; loop++) {
+			u16 tmp = adj_loopback_gain - 6 * loop;
+			if (tmp < 6)
+				break;
+		}
+
+		loop_or = (loop << 8) | extern_lna_control;
+		if (phy->rev >= 7 && dev->dev->bus->sprom.r1.boardflags_lo
+		    & B43legacy_BFL_EXTLNA) {
+			if (extern_lna_control)
+				loop_or |= 0x8000;
+			switch (lpd) {
+			case LPD(0, 1, 1):
+				return 0x8F92;
+			case LPD(0, 0, 1):
+				return (0x8092 | loop_or);
+			case LPD(1, 0, 1):
+				return (0x2092 | loop_or);
+			case LPD(1, 0, 0):
+				return (0x2093 | loop_or);
+			default:
+				B43legacy_BUG_ON(1);
+			}
+		} else {
+			switch (lpd) {
+			case LPD(0, 1, 1):
+				return 0x0F92;
+			case LPD(0, 0, 1):
+			case LPD(1, 0, 1):
+				return (0x0092 | loop_or);
+			case LPD(1, 0, 0):
+				return (0x0093 | loop_or);
+			default:
+				B43legacy_BUG_ON(1);
+			}
+		}
+	}
+	return 0;
+}
+
+u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 backup[21] = { 0 };
+	u16 ret;
+	u16 i;
+	u16 j;
+	u32 tmp1 = 0;
+	u32 tmp2 = 0;
+
+	backup[0] = b43legacy_radio_read16(dev, 0x0043);
+	backup[14] = b43legacy_radio_read16(dev, 0x0051);
+	backup[15] = b43legacy_radio_read16(dev, 0x0052);
+	backup[1] = b43legacy_phy_read(dev, 0x0015);
+	backup[16] = b43legacy_phy_read(dev, 0x005A);
+	backup[17] = b43legacy_phy_read(dev, 0x0059);
+	backup[18] = b43legacy_phy_read(dev, 0x0058);
+	if (phy->type == B43legacy_PHYTYPE_B) {
+		backup[2] = b43legacy_phy_read(dev, 0x0030);
+		backup[3] = b43legacy_read16(dev, 0x03EC);
+		b43legacy_phy_write(dev, 0x0030, 0x00FF);
+		b43legacy_write16(dev, 0x03EC, 0x3F3F);
+	} else {
+		if (phy->gmode) {
+			backup[4] = b43legacy_phy_read(dev, 0x0811);
+			backup[5] = b43legacy_phy_read(dev, 0x0812);
+			backup[6] = b43legacy_phy_read(dev, 0x0814);
+			backup[7] = b43legacy_phy_read(dev, 0x0815);
+			backup[8] = b43legacy_phy_read(dev,
+						       B43legacy_PHY_G_CRS);
+			backup[9] = b43legacy_phy_read(dev, 0x0802);
+			b43legacy_phy_write(dev, 0x0814,
+					    (b43legacy_phy_read(dev, 0x0814)
+					    | 0x0003));
+			b43legacy_phy_write(dev, 0x0815,
+					    (b43legacy_phy_read(dev, 0x0815)
+					    & 0xFFFC));
+			b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+					    (b43legacy_phy_read(dev,
+					    B43legacy_PHY_G_CRS) & 0x7FFF));
+			b43legacy_phy_write(dev, 0x0802,
+					    (b43legacy_phy_read(dev, 0x0802)
+					    & 0xFFFC));
+			if (phy->rev > 1) { /* loopback gain enabled */
+				backup[19] = b43legacy_phy_read(dev, 0x080F);
+				backup[20] = b43legacy_phy_read(dev, 0x0810);
+				if (phy->rev >= 3)
+					b43legacy_phy_write(dev, 0x080F,
+							    0xC020);
+				else
+					b43legacy_phy_write(dev, 0x080F,
+							    0x8020);
+				b43legacy_phy_write(dev, 0x0810, 0x0000);
+			}
+			b43legacy_phy_write(dev, 0x0812,
+					    b43legacy_get_812_value(dev,
+					    LPD(0, 1, 1)));
+			if (phy->rev < 7 ||
+			    !(dev->dev->bus->sprom.r1.boardflags_lo
+			    & B43legacy_BFL_EXTLNA))
+				b43legacy_phy_write(dev, 0x0811, 0x01B3);
+			else
+				b43legacy_phy_write(dev, 0x0811, 0x09B3);
+		}
+	}
+	b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
+			(b43legacy_read16(dev, B43legacy_MMIO_PHY_RADIO)
+					  | 0x8000));
+	backup[10] = b43legacy_phy_read(dev, 0x0035);
+	b43legacy_phy_write(dev, 0x0035,
+			    (b43legacy_phy_read(dev, 0x0035) & 0xFF7F));
+	backup[11] = b43legacy_read16(dev, 0x03E6);
+	backup[12] = b43legacy_read16(dev, B43legacy_MMIO_CHANNEL_EXT);
+
+	/* Initialization */
+	if (phy->analog == 0)
+		b43legacy_write16(dev, 0x03E6, 0x0122);
+	else {
+		if (phy->analog >= 2)
+			b43legacy_phy_write(dev, 0x0003,
+					    (b43legacy_phy_read(dev, 0x0003)
+					    & 0xFFBF) | 0x0040);
+		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
+				  (b43legacy_read16(dev,
+				  B43legacy_MMIO_CHANNEL_EXT) | 0x2000));
+	}
+
+	ret = b43legacy_radio_calibrationvalue(dev);
+
+	if (phy->type == B43legacy_PHYTYPE_B)
+		b43legacy_radio_write16(dev, 0x0078, 0x0026);
+
+	if (phy->gmode)
+		b43legacy_phy_write(dev, 0x0812,
+				    b43legacy_get_812_value(dev,
+				    LPD(0, 1, 1)));
+	b43legacy_phy_write(dev, 0x0015, 0xBFAF);
+	b43legacy_phy_write(dev, 0x002B, 0x1403);
+	if (phy->gmode)
+		b43legacy_phy_write(dev, 0x0812,
+				    b43legacy_get_812_value(dev,
+				    LPD(0, 0, 1)));
+	b43legacy_phy_write(dev, 0x0015, 0xBFA0);
+	b43legacy_radio_write16(dev, 0x0051,
+				(b43legacy_radio_read16(dev, 0x0051)
+				| 0x0004));
+	if (phy->radio_rev == 8)
+		b43legacy_radio_write16(dev, 0x0043, 0x001F);
+	else {
+		b43legacy_radio_write16(dev, 0x0052, 0x0000);
+		b43legacy_radio_write16(dev, 0x0043,
+					(b43legacy_radio_read16(dev, 0x0043)
+					& 0xFFF0) | 0x0009);
+	}
+	b43legacy_phy_write(dev, 0x0058, 0x0000);
+
+	for (i = 0; i < 16; i++) {
+		b43legacy_phy_write(dev, 0x005A, 0x0480);
+		b43legacy_phy_write(dev, 0x0059, 0xC810);
+		b43legacy_phy_write(dev, 0x0058, 0x000D);
+		if (phy->gmode)
+			b43legacy_phy_write(dev, 0x0812,
+					    b43legacy_get_812_value(dev,
+					    LPD(1, 0, 1)));
+		b43legacy_phy_write(dev, 0x0015, 0xAFB0);
+		udelay(10);
+		if (phy->gmode)
+			b43legacy_phy_write(dev, 0x0812,
+					    b43legacy_get_812_value(dev,
+					    LPD(1, 0, 1)));
+		b43legacy_phy_write(dev, 0x0015, 0xEFB0);
+		udelay(10);
+		if (phy->gmode)
+			b43legacy_phy_write(dev, 0x0812,
+					    b43legacy_get_812_value(dev,
+					    LPD(1, 0, 0)));
+		b43legacy_phy_write(dev, 0x0015, 0xFFF0);
+		udelay(20);
+		tmp1 += b43legacy_phy_read(dev, 0x002D);
+		b43legacy_phy_write(dev, 0x0058, 0x0000);
+		if (phy->gmode)
+			b43legacy_phy_write(dev, 0x0812,
+					    b43legacy_get_812_value(dev,
+					    LPD(1, 0, 1)));
+		b43legacy_phy_write(dev, 0x0015, 0xAFB0);
+	}
+
+	tmp1++;
+	tmp1 >>= 9;
+	udelay(10);
+	b43legacy_phy_write(dev, 0x0058, 0x0000);
+
+	for (i = 0; i < 16; i++) {
+		b43legacy_radio_write16(dev, 0x0078, (flip_4bit(i) << 1)
+					| 0x0020);
+		backup[13] = b43legacy_radio_read16(dev, 0x0078);
+		udelay(10);
+		for (j = 0; j < 16; j++) {
+			b43legacy_phy_write(dev, 0x005A, 0x0D80);
+			b43legacy_phy_write(dev, 0x0059, 0xC810);
+			b43legacy_phy_write(dev, 0x0058, 0x000D);
+			if (phy->gmode)
+				b43legacy_phy_write(dev, 0x0812,
+						    b43legacy_get_812_value(dev,
+						    LPD(1, 0, 1)));
+			b43legacy_phy_write(dev, 0x0015, 0xAFB0);
+			udelay(10);
+			if (phy->gmode)
+				b43legacy_phy_write(dev, 0x0812,
+						    b43legacy_get_812_value(dev,
+						    LPD(1, 0, 1)));
+			b43legacy_phy_write(dev, 0x0015, 0xEFB0);
+			udelay(10);
+			if (phy->gmode)
+				b43legacy_phy_write(dev, 0x0812,
+						    b43legacy_get_812_value(dev,
+						    LPD(1, 0, 0)));
+			b43legacy_phy_write(dev, 0x0015, 0xFFF0);
+			udelay(10);
+			tmp2 += b43legacy_phy_read(dev, 0x002D);
+			b43legacy_phy_write(dev, 0x0058, 0x0000);
+			if (phy->gmode)
+				b43legacy_phy_write(dev, 0x0812,
+						    b43legacy_get_812_value(dev,
+						    LPD(1, 0, 1)));
+			b43legacy_phy_write(dev, 0x0015, 0xAFB0);
+		}
+		tmp2++;
+		tmp2 >>= 8;
+		if (tmp1 < tmp2)
+			break;
+	}
+
+	/* Restore the registers */
+	b43legacy_phy_write(dev, 0x0015, backup[1]);
+	b43legacy_radio_write16(dev, 0x0051, backup[14]);
+	b43legacy_radio_write16(dev, 0x0052, backup[15]);
+	b43legacy_radio_write16(dev, 0x0043, backup[0]);
+	b43legacy_phy_write(dev, 0x005A, backup[16]);
+	b43legacy_phy_write(dev, 0x0059, backup[17]);
+	b43legacy_phy_write(dev, 0x0058, backup[18]);
+	b43legacy_write16(dev, 0x03E6, backup[11]);
+	if (phy->analog != 0)
+		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT, backup[12]);
+	b43legacy_phy_write(dev, 0x0035, backup[10]);
+	b43legacy_radio_selectchannel(dev, phy->channel, 1);
+	if (phy->type == B43legacy_PHYTYPE_B) {
+		b43legacy_phy_write(dev, 0x0030, backup[2]);
+		b43legacy_write16(dev, 0x03EC, backup[3]);
+	} else {
+		if (phy->gmode) {
+			b43legacy_write16(dev, B43legacy_MMIO_PHY_RADIO,
+					  (b43legacy_read16(dev,
+					  B43legacy_MMIO_PHY_RADIO) & 0x7FFF));
+			b43legacy_phy_write(dev, 0x0811, backup[4]);
+			b43legacy_phy_write(dev, 0x0812, backup[5]);
+			b43legacy_phy_write(dev, 0x0814, backup[6]);
+			b43legacy_phy_write(dev, 0x0815, backup[7]);
+			b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,
+					    backup[8]);
+			b43legacy_phy_write(dev, 0x0802, backup[9]);
+			if (phy->rev > 1) {
+				b43legacy_phy_write(dev, 0x080F, backup[19]);
+				b43legacy_phy_write(dev, 0x0810, backup[20]);
+			}
+		}
+	}
+	if (i >= 15)
+		ret = backup[13];
+
+	return ret;
+}
+
+static inline
+u16 freq_r3A_value(u16 frequency)
+{
+	u16 value;
+
+	if (frequency < 5091)
+		value = 0x0040;
+	else if (frequency < 5321)
+		value = 0x0000;
+	else if (frequency < 5806)
+		value = 0x0080;
+	else
+		value = 0x0040;
+
+	return value;
+}
+
+void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev)
+{
+	static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
+	static const u8 data_low[5]  = { 0x00, 0x01, 0x05, 0x06, 0x0A };
+	u16 tmp = b43legacy_radio_read16(dev, 0x001E);
+	int i;
+	int j;
+
+	for (i = 0; i < 5; i++) {
+		for (j = 0; j < 5; j++) {
+			if (tmp == (data_high[i] | data_low[j])) {
+				b43legacy_phy_write(dev, 0x0069, (i - j) << 8 |
+						    0x00C0);
+				return;
+			}
+		}
+	}
+}
+
+int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev,
+				  u8 channel,
+				  int synthetic_pu_workaround)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+
+	if (channel == 0xFF) {
+		switch (phy->type) {
+		case B43legacy_PHYTYPE_B:
+		case B43legacy_PHYTYPE_G:
+			channel = B43legacy_RADIO_DEFAULT_CHANNEL_BG;
+			break;
+		default:
+			B43legacy_WARN_ON(1);
+		}
+	}
+
+/* TODO: Check if channel is valid - return -EINVAL if not */
+	if (synthetic_pu_workaround)
+		b43legacy_synth_pu_workaround(dev, channel);
+
+	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,
+			  channel2freq_bg(channel));
+
+	if (channel == 14) {
+		if (dev->dev->bus->sprom.r1.country_code == 5)   /* JAPAN) */
+			b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+					      B43legacy_UCODEFLAGS_OFFSET,
+					      b43legacy_shm_read32(dev,
+					      B43legacy_SHM_SHARED,
+					      B43legacy_UCODEFLAGS_OFFSET)
+					      & ~(1 << 7));
+		else
+			b43legacy_shm_write32(dev, B43legacy_SHM_SHARED,
+					      B43legacy_UCODEFLAGS_OFFSET,
+					      b43legacy_shm_read32(dev,
+					      B43legacy_SHM_SHARED,
+					      B43legacy_UCODEFLAGS_OFFSET)
+					      | (1 << 7));
+		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
+				  b43legacy_read16(dev,
+				  B43legacy_MMIO_CHANNEL_EXT) | (1 << 11));
+	} else
+		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL_EXT,
+				  b43legacy_read16(dev,
+				  B43legacy_MMIO_CHANNEL_EXT) & 0xF7BF);
+
+	phy->channel = channel;
+	/*XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states
+	 *     that 2000 usecs might suffice. */
+	msleep(8);
+
+	return 0;
+}
+
+void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val)
+{
+	u16 tmp;
+
+	val <<= 8;
+	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0022) & 0xFCFF;
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0022, tmp | val);
+	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x03A8) & 0xFCFF;
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x03A8, tmp | val);
+	tmp = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, 0x0054) & 0xFCFF;
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0054, tmp | val);
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */
+static u16 b43legacy_get_txgain_base_band(u16 txpower)
+{
+	u16 ret;
+
+	B43legacy_WARN_ON(txpower > 63);
+
+	if (txpower >= 54)
+		ret = 2;
+	else if (txpower >= 49)
+		ret = 4;
+	else if (txpower >= 44)
+		ret = 5;
+	else
+		ret = 6;
+
+	return ret;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */
+static u16 b43legacy_get_txgain_freq_power_amp(u16 txpower)
+{
+	u16 ret;
+
+	B43legacy_WARN_ON(txpower > 63);
+
+	if (txpower >= 32)
+		ret = 0;
+	else if (txpower >= 25)
+		ret = 1;
+	else if (txpower >= 20)
+		ret = 2;
+	else if (txpower >= 12)
+		ret = 3;
+	else
+		ret = 4;
+
+	return ret;
+}
+
+/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */
+static u16 b43legacy_get_txgain_dac(u16 txpower)
+{
+	u16 ret;
+
+	B43legacy_WARN_ON(txpower > 63);
+
+	if (txpower >= 54)
+		ret = txpower - 53;
+	else if (txpower >= 49)
+		ret = txpower - 42;
+	else if (txpower >= 44)
+		ret = txpower - 37;
+	else if (txpower >= 32)
+		ret = txpower - 32;
+	else if (txpower >= 25)
+		ret = txpower - 20;
+	else if (txpower >= 20)
+		ret = txpower - 13;
+	else if (txpower >= 12)
+		ret = txpower - 8;
+	else
+		ret = txpower;
+
+	return ret;
+}
+
+void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 pamp;
+	u16 base;
+	u16 dac;
+	u16 ilt;
+
+	txpower = limit_value(txpower, 0, 63);
+
+	pamp = b43legacy_get_txgain_freq_power_amp(txpower);
+	pamp <<= 5;
+	pamp &= 0x00E0;
+	b43legacy_phy_write(dev, 0x0019, pamp);
+
+	base = b43legacy_get_txgain_base_band(txpower);
+	base &= 0x000F;
+	b43legacy_phy_write(dev, 0x0017, base | 0x0020);
+
+	ilt = b43legacy_ilt_read(dev, 0x3001);
+	ilt &= 0x0007;
+
+	dac = b43legacy_get_txgain_dac(txpower);
+	dac <<= 3;
+	dac |= ilt;
+
+	b43legacy_ilt_write(dev, 0x3001, dac);
+
+	phy->txpwr_offset = txpower;
+
+	/* TODO: FuncPlaceholder (Adjust BB loft cancel) */
+}
+
+void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev,
+				    u16 baseband_attenuation,
+				    u16 radio_attenuation,
+				    u16 txpower)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+
+	if (baseband_attenuation == 0xFFFF)
+		baseband_attenuation = phy->bbatt;
+	if (radio_attenuation == 0xFFFF)
+		radio_attenuation = phy->rfatt;
+	if (txpower == 0xFFFF)
+		txpower = phy->txctl1;
+	phy->bbatt = baseband_attenuation;
+	phy->rfatt = radio_attenuation;
+	phy->txctl1 = txpower;
+
+	B43legacy_WARN_ON(baseband_attenuation > 11);
+	if (phy->radio_rev < 6)
+		B43legacy_WARN_ON(radio_attenuation > 9);
+	else
+		B43legacy_WARN_ON(radio_attenuation > 31);
+	B43legacy_WARN_ON(txpower > 7);
+
+	b43legacy_phy_set_baseband_attenuation(dev, baseband_attenuation);
+	b43legacy_radio_write16(dev, 0x0043, radio_attenuation);
+	b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0064,
+			      radio_attenuation);
+	if (phy->radio_ver == 0x2050)
+		b43legacy_radio_write16(dev, 0x0052,
+					(b43legacy_radio_read16(dev, 0x0052)
+					& ~0x0070) | ((txpower << 4) & 0x0070));
+	/* FIXME: The spec is very weird and unclear here. */
+	if (phy->type == B43legacy_PHYTYPE_G)
+		b43legacy_phy_lo_adjust(dev, 0);
+}
+
+u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+
+	if (phy->radio_ver == 0x2050 && phy->radio_rev < 6)
+		return 0;
+	return 2;
+}
+
+u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	u16 att = 0xFFFF;
+
+	switch (phy->radio_ver) {
+	case 0x2053:
+		switch (phy->radio_rev) {
+		case 1:
+			att = 6;
+			break;
+		}
+		break;
+	case 0x2050:
+		switch (phy->radio_rev) {
+		case 0:
+			att = 5;
+			break;
+		case 1:
+			if (phy->type == B43legacy_PHYTYPE_G) {
+				if (is_bcm_board_vendor(dev) &&
+				    dev->dev->bus->boardinfo.type == 0x421 &&
+				    dev->dev->bus->boardinfo.rev >= 30)
+					att = 3;
+				else if (is_bcm_board_vendor(dev) &&
+					 dev->dev->bus->boardinfo.type == 0x416)
+					att = 3;
+				else
+					att = 1;
+			} else {
+				if (is_bcm_board_vendor(dev) &&
+				    dev->dev->bus->boardinfo.type == 0x421 &&
+				    dev->dev->bus->boardinfo.rev >= 30)
+					att = 7;
+				else
+					att = 6;
+			}
+			break;
+		case 2:
+			if (phy->type == B43legacy_PHYTYPE_G) {
+				if (is_bcm_board_vendor(dev) &&
+				    dev->dev->bus->boardinfo.type == 0x421 &&
+				    dev->dev->bus->boardinfo.rev >= 30)
+					att = 3;
+				else if (is_bcm_board_vendor(dev) &&
+					 dev->dev->bus->boardinfo.type ==
+					 0x416)
+					att = 5;
+				else if (dev->dev->bus->chip_id == 0x4320)
+					att = 4;
+				else
+					att = 3;
+			} else
+				att = 6;
+			break;
+		case 3:
+			att = 5;
+			break;
+		case 4:
+		case 5:
+			att = 1;
+			break;
+		case 6:
+		case 7:
+			att = 5;
+			break;
+		case 8:
+			att = 0x1A;
+			break;
+		case 9:
+		default:
+			att = 5;
+		}
+	}
+	if (is_bcm_board_vendor(dev) &&
+	    dev->dev->bus->boardinfo.type == 0x421) {
+		if (dev->dev->bus->boardinfo.rev < 0x43)
+			att = 2;
+		else if (dev->dev->bus->boardinfo.rev < 0x51)
+			att = 3;
+	}
+	if (att == 0xFFFF)
+		att = 5;
+
+	return att;
+}
+
+u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+
+	if (phy->radio_ver != 0x2050)
+		return 0;
+	if (phy->radio_rev == 1)
+		return 3;
+	if (phy->radio_rev < 6)
+		return 2;
+	if (phy->radio_rev == 8)
+		return 1;
+	return 0;
+}
+
+void b43legacy_radio_turn_on(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	int err;
+	u8 channel;
+
+	might_sleep();
+
+	if (phy->radio_on)
+		return;
+
+	switch (phy->type) {
+	case B43legacy_PHYTYPE_B:
+	case B43legacy_PHYTYPE_G:
+		b43legacy_phy_write(dev, 0x0015, 0x8000);
+		b43legacy_phy_write(dev, 0x0015, 0xCC00);
+		b43legacy_phy_write(dev, 0x0015,
+				    (phy->gmode ? 0x00C0 : 0x0000));
+		if (phy->radio_off_context.valid) {
+			/* Restore the RFover values. */
+			b43legacy_phy_write(dev, B43legacy_PHY_RFOVER,
+					    phy->radio_off_context.rfover);
+			b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
+					    phy->radio_off_context.rfoverval);
+			phy->radio_off_context.valid = 0;
+		}
+		channel = phy->channel;
+		err = b43legacy_radio_selectchannel(dev,
+					B43legacy_RADIO_DEFAULT_CHANNEL_BG, 1);
+		err |= b43legacy_radio_selectchannel(dev, channel, 0);
+		B43legacy_WARN_ON(err);
+		break;
+	default:
+		B43legacy_BUG_ON(1);
+	}
+	phy->radio_on = 1;
+	b43legacy_leds_update(dev, 0);
+}
+
+void b43legacy_radio_turn_off(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+
+	if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) {
+		u16 rfover, rfoverval;
+
+		rfover = b43legacy_phy_read(dev, B43legacy_PHY_RFOVER);
+		rfoverval = b43legacy_phy_read(dev, B43legacy_PHY_RFOVERVAL);
+		phy->radio_off_context.rfover = rfover;
+		phy->radio_off_context.rfoverval = rfoverval;
+		phy->radio_off_context.valid = 1;
+		b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C);
+		b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL,
+				    rfoverval & 0xFF73);
+	} else
+		b43legacy_phy_write(dev, 0x0015, 0xAA00);
+	phy->radio_on = 0;
+	b43legacydbg(dev->wl, "Radio initialized\n");
+	b43legacy_leds_update(dev, 0);
+}
+
+void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+
+	switch (phy->type) {
+	case B43legacy_PHYTYPE_B:
+	case B43legacy_PHYTYPE_G:
+		b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0058,
+				      0x7F7F);
+		b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x005a,
+				      0x7F7F);
+		b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0070,
+				      0x7F7F);
+		b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0072,
+				      0x7F7F);
+		break;
+	}
+}
diff --git a/drivers/net/wireless/b43legacy/radio.h b/drivers/net/wireless/b43legacy/radio.h
new file mode 100644
index 0000000..6c6a203
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/radio.h
@@ -0,0 +1,98 @@
+/*
+
+  Broadcom B43legacy wireless driver
+
+  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
+		     Stefano Brivio <st3@riseup.net>
+		     Michael Buesch <mbuesch@freenet.de>
+		     Danny van Dyk <kugelfang@gentoo.org>
+		     Andreas Jaggi <andreas.jaggi@waterwave.ch>
+
+  Some parts of the code in this file are derived from the ipw2200
+  driver  Copyright(c) 2003 - 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 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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#ifndef B43legacy_RADIO_H_
+#define B43legacy_RADIO_H_
+
+#include "b43legacy.h"
+
+
+#define B43legacy_RADIO_DEFAULT_CHANNEL_BG	6
+
+/* Force antenna 0. */
+#define B43legacy_RADIO_TXANTENNA_0		0
+/* Force antenna 1. */
+#define B43legacy_RADIO_TXANTENNA_1		1
+/* Use the RX antenna, that was selected for the most recently
+ * received good PLCP header.
+ */
+#define B43legacy_RADIO_TXANTENNA_LASTPLCP	3
+#define B43legacy_RADIO_TXANTENNA_DEFAULT	B43legacy_RADIO_TXANTENNA_LASTPLCP
+
+#define B43legacy_RADIO_INTERFMODE_NONE		0
+#define B43legacy_RADIO_INTERFMODE_NONWLAN	1
+#define B43legacy_RADIO_INTERFMODE_MANUALWLAN	2
+#define B43legacy_RADIO_INTERFMODE_AUTOWLAN	3
+
+
+void b43legacy_radio_lock(struct b43legacy_wldev *dev);
+void b43legacy_radio_unlock(struct b43legacy_wldev *dev);
+
+u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset);
+void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val);
+
+u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev);
+
+void b43legacy_radio_turn_on(struct b43legacy_wldev *dev);
+void b43legacy_radio_turn_off(struct b43legacy_wldev *dev);
+
+int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, u8 channel,
+				  int synthetic_pu_workaround);
+
+void b43legacy_radio_set_txpower_a(struct b43legacy_wldev *dev, u16 txpower);
+void b43legacy_radio_set_txpower_bg(struct b43legacy_wldev *dev,
+				    u16 baseband_attenuation, u16 attenuation,
+				    u16 txpower);
+
+u16 b43legacy_default_baseband_attenuation(struct b43legacy_wldev *dev);
+u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev);
+u16 b43legacy_default_txctl1(struct b43legacy_wldev *dev);
+
+void b43legacy_radio_set_txantenna(struct b43legacy_wldev *dev, u32 val);
+
+void b43legacy_radio_clear_tssi(struct b43legacy_wldev *dev);
+
+u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel);
+u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev);
+
+int b43legacy_radio_set_interference_mitigation(struct b43legacy_wldev *dev,
+						int mode);
+
+void b43legacy_calc_nrssi_slope(struct b43legacy_wldev *dev);
+void b43legacy_calc_nrssi_threshold(struct b43legacy_wldev *dev);
+s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset);
+void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val);
+void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val);
+void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev);
+
+void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev);
+u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev);
+
+#endif /* B43legacy_RADIO_H_ */
diff --git a/drivers/net/wireless/b43legacy/sysfs.c b/drivers/net/wireless/b43legacy/sysfs.c
new file mode 100644
index 0000000..56c384f
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/sysfs.c
@@ -0,0 +1,238 @@
+/*
+
+  Broadcom B43legacy wireless driver
+
+  SYSFS support routines
+
+  Copyright (c) 2006 Michael Buesch <mb@bu3sch.de>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "sysfs.h"
+#include "b43legacy.h"
+#include "main.h"
+#include "phy.h"
+#include "radio.h"
+
+#include <linux/capability.h>
+
+
+#define GENERIC_FILESIZE	64
+
+
+static int get_integer(const char *buf, size_t count)
+{
+	char tmp[10 + 1] = { 0 };
+	int ret = -EINVAL;
+
+	if (count == 0)
+		goto out;
+	count = min(count, (size_t)10);
+	memcpy(tmp, buf, count);
+	ret = simple_strtol(tmp, NULL, 10);
+out:
+	return ret;
+}
+
+static int get_boolean(const char *buf, size_t count)
+{
+	if (count != 0) {
+		if (buf[0] == '1')
+			return 1;
+		if (buf[0] == '0')
+			return 0;
+		if (count >= 4 && memcmp(buf, "true", 4) == 0)
+			return 1;
+		if (count >= 5 && memcmp(buf, "false", 5) == 0)
+			return 0;
+		if (count >= 3 && memcmp(buf, "yes", 3) == 0)
+			return 1;
+		if (count >= 2 && memcmp(buf, "no", 2) == 0)
+			return 0;
+		if (count >= 2 && memcmp(buf, "on", 2) == 0)
+			return 1;
+		if (count >= 3 && memcmp(buf, "off", 3) == 0)
+			return 0;
+	}
+	return -EINVAL;
+}
+
+static ssize_t b43legacy_attr_interfmode_show(struct device *dev,
+					      struct device_attribute *attr,
+					      char *buf)
+{
+	struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
+	ssize_t count = 0;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	mutex_lock(&wldev->wl->mutex);
+
+	switch (wldev->phy.interfmode) {
+	case B43legacy_INTERFMODE_NONE:
+		count = snprintf(buf, PAGE_SIZE, "0 (No Interference"
+				 " Mitigation)\n");
+		break;
+	case B43legacy_INTERFMODE_NONWLAN:
+		count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference"
+				 " Mitigation)\n");
+		break;
+	case B43legacy_INTERFMODE_MANUALWLAN:
+		count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference"
+				 " Mitigation)\n");
+		break;
+	default:
+		B43legacy_WARN_ON(1);
+	}
+
+	mutex_unlock(&wldev->wl->mutex);
+
+	return count;
+}
+
+static ssize_t b43legacy_attr_interfmode_store(struct device *dev,
+					       struct device_attribute *attr,
+					       const char *buf, size_t count)
+{
+	struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
+	unsigned long flags;
+	int err;
+	int mode;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	mode = get_integer(buf, count);
+	switch (mode) {
+	case 0:
+		mode = B43legacy_INTERFMODE_NONE;
+		break;
+	case 1:
+		mode = B43legacy_INTERFMODE_NONWLAN;
+		break;
+	case 2:
+		mode = B43legacy_INTERFMODE_MANUALWLAN;
+		break;
+	case 3:
+		mode = B43legacy_INTERFMODE_AUTOWLAN;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mutex_lock(&wldev->wl->mutex);
+	spin_lock_irqsave(&wldev->wl->irq_lock, flags);
+
+	err = b43legacy_radio_set_interference_mitigation(wldev, mode);
+	if (err)
+		b43legacyerr(wldev->wl, "Interference Mitigation not "
+		       "supported by device\n");
+	mmiowb();
+	spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
+	mutex_unlock(&wldev->wl->mutex);
+
+	return err ? err : count;
+}
+
+static DEVICE_ATTR(interference, 0644,
+		   b43legacy_attr_interfmode_show,
+		   b43legacy_attr_interfmode_store);
+
+static ssize_t b43legacy_attr_preamble_show(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
+{
+	struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
+	ssize_t count;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	mutex_lock(&wldev->wl->mutex);
+
+	if (wldev->short_preamble)
+		count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble"
+				 " enabled)\n");
+	else
+		count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble"
+				 " disabled)\n");
+
+	mutex_unlock(&wldev->wl->mutex);
+
+	return count;
+}
+
+static ssize_t b43legacy_attr_preamble_store(struct device *dev,
+					     struct device_attribute *attr,
+					     const char *buf, size_t count)
+{
+	struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
+	unsigned long flags;
+	int value;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	value = get_boolean(buf, count);
+	if (value < 0)
+		return value;
+	mutex_lock(&wldev->wl->mutex);
+	spin_lock_irqsave(&wldev->wl->irq_lock, flags);
+
+	wldev->short_preamble = !!value;
+
+	spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
+	mutex_unlock(&wldev->wl->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(shortpreamble, 0644,
+		   b43legacy_attr_preamble_show,
+		   b43legacy_attr_preamble_store);
+
+int b43legacy_sysfs_register(struct b43legacy_wldev *wldev)
+{
+	struct device *dev = wldev->dev->dev;
+	int err;
+
+	B43legacy_WARN_ON(b43legacy_status(wldev) !=
+			  B43legacy_STAT_INITIALIZED);
+
+	err = device_create_file(dev, &dev_attr_interference);
+	if (err)
+		goto out;
+	err = device_create_file(dev, &dev_attr_shortpreamble);
+	if (err)
+		goto err_remove_interfmode;
+
+out:
+	return err;
+err_remove_interfmode:
+	device_remove_file(dev, &dev_attr_interference);
+	goto out;
+}
+
+void b43legacy_sysfs_unregister(struct b43legacy_wldev *wldev)
+{
+	struct device *dev = wldev->dev->dev;
+
+	device_remove_file(dev, &dev_attr_shortpreamble);
+	device_remove_file(dev, &dev_attr_interference);
+}
diff --git a/drivers/net/wireless/b43legacy/sysfs.h b/drivers/net/wireless/b43legacy/sysfs.h
new file mode 100644
index 0000000..417d5098
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/sysfs.h
@@ -0,0 +1,9 @@
+#ifndef B43legacy_SYSFS_H_
+#define B43legacy_SYSFS_H_
+
+struct b43legacy_wldev;
+
+int b43legacy_sysfs_register(struct b43legacy_wldev *dev);
+void b43legacy_sysfs_unregister(struct b43legacy_wldev *dev);
+
+#endif /* B43legacy_SYSFS_H_ */
diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c
new file mode 100644
index 0000000..fa1e656
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/xmit.c
@@ -0,0 +1,642 @@
+/*
+
+  Broadcom B43legacy wireless driver
+
+  Transmission (TX/RX) related functions.
+
+  Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+  Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+  Copyright (C) 2005, 2006 Michael Buesch <mb@bu3sch.de>
+  Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
+  Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+  Copyright (C) 2007 Larry Finger <Larry.Finger@lwfinger.net>
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <net/dst.h>
+
+#include "xmit.h"
+#include "phy.h"
+#include "dma.h"
+#include "pio.h"
+
+
+/* Extract the bitrate out of a CCK PLCP header. */
+static u8 b43legacy_plcp_get_bitrate_cck(struct b43legacy_plcp_hdr6 *plcp)
+{
+	switch (plcp->raw[0]) {
+	case 0x0A:
+		return B43legacy_CCK_RATE_1MB;
+	case 0x14:
+		return B43legacy_CCK_RATE_2MB;
+	case 0x37:
+		return B43legacy_CCK_RATE_5MB;
+	case 0x6E:
+		return B43legacy_CCK_RATE_11MB;
+	}
+	B43legacy_BUG_ON(1);
+	return 0;
+}
+
+/* Extract the bitrate out of an OFDM PLCP header. */
+static u8 b43legacy_plcp_get_bitrate_ofdm(struct b43legacy_plcp_hdr6 *plcp)
+{
+	switch (plcp->raw[0] & 0xF) {
+	case 0xB:
+		return B43legacy_OFDM_RATE_6MB;
+	case 0xF:
+		return B43legacy_OFDM_RATE_9MB;
+	case 0xA:
+		return B43legacy_OFDM_RATE_12MB;
+	case 0xE:
+		return B43legacy_OFDM_RATE_18MB;
+	case 0x9:
+		return B43legacy_OFDM_RATE_24MB;
+	case 0xD:
+		return B43legacy_OFDM_RATE_36MB;
+	case 0x8:
+		return B43legacy_OFDM_RATE_48MB;
+	case 0xC:
+		return B43legacy_OFDM_RATE_54MB;
+	}
+	B43legacy_BUG_ON(1);
+	return 0;
+}
+
+u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate)
+{
+	switch (bitrate) {
+	case B43legacy_CCK_RATE_1MB:
+		return 0x0A;
+	case B43legacy_CCK_RATE_2MB:
+		return 0x14;
+	case B43legacy_CCK_RATE_5MB:
+		return 0x37;
+	case B43legacy_CCK_RATE_11MB:
+		return 0x6E;
+	}
+	B43legacy_BUG_ON(1);
+	return 0;
+}
+
+u8 b43legacy_plcp_get_ratecode_ofdm(const u8 bitrate)
+{
+	switch (bitrate) {
+	case B43legacy_OFDM_RATE_6MB:
+		return 0xB;
+	case B43legacy_OFDM_RATE_9MB:
+		return 0xF;
+	case B43legacy_OFDM_RATE_12MB:
+		return 0xA;
+	case B43legacy_OFDM_RATE_18MB:
+		return 0xE;
+	case B43legacy_OFDM_RATE_24MB:
+		return 0x9;
+	case B43legacy_OFDM_RATE_36MB:
+		return 0xD;
+	case B43legacy_OFDM_RATE_48MB:
+		return 0x8;
+	case B43legacy_OFDM_RATE_54MB:
+		return 0xC;
+	}
+	B43legacy_BUG_ON(1);
+	return 0;
+}
+
+void b43legacy_generate_plcp_hdr(struct b43legacy_plcp_hdr4 *plcp,
+				 const u16 octets, const u8 bitrate)
+{
+	__le32 *data = &(plcp->data);
+	__u8 *raw = plcp->raw;
+
+	if (b43legacy_is_ofdm_rate(bitrate)) {
+		u16 d;
+
+		d = b43legacy_plcp_get_ratecode_ofdm(bitrate);
+		B43legacy_WARN_ON(octets & 0xF000);
+		d |= (octets << 5);
+		*data = cpu_to_le32(d);
+	} else {
+		u32 plen;
+
+		plen = octets * 16 / bitrate;
+		if ((octets * 16 % bitrate) > 0) {
+			plen++;
+			if ((bitrate == B43legacy_CCK_RATE_11MB)
+			    && ((octets * 8 % 11) < 4))
+				raw[1] = 0x84;
+			else
+				raw[1] = 0x04;
+		} else
+			raw[1] = 0x04;
+		*data |= cpu_to_le32(plen << 16);
+		raw[0] = b43legacy_plcp_get_ratecode_cck(bitrate);
+	}
+}
+
+static u8 b43legacy_calc_fallback_rate(u8 bitrate)
+{
+	switch (bitrate) {
+	case B43legacy_CCK_RATE_1MB:
+		return B43legacy_CCK_RATE_1MB;
+	case B43legacy_CCK_RATE_2MB:
+		return B43legacy_CCK_RATE_1MB;
+	case B43legacy_CCK_RATE_5MB:
+		return B43legacy_CCK_RATE_2MB;
+	case B43legacy_CCK_RATE_11MB:
+		return B43legacy_CCK_RATE_5MB;
+	case B43legacy_OFDM_RATE_6MB:
+		return B43legacy_CCK_RATE_5MB;
+	case B43legacy_OFDM_RATE_9MB:
+		return B43legacy_OFDM_RATE_6MB;
+	case B43legacy_OFDM_RATE_12MB:
+		return B43legacy_OFDM_RATE_9MB;
+	case B43legacy_OFDM_RATE_18MB:
+		return B43legacy_OFDM_RATE_12MB;
+	case B43legacy_OFDM_RATE_24MB:
+		return B43legacy_OFDM_RATE_18MB;
+	case B43legacy_OFDM_RATE_36MB:
+		return B43legacy_OFDM_RATE_24MB;
+	case B43legacy_OFDM_RATE_48MB:
+		return B43legacy_OFDM_RATE_36MB;
+	case B43legacy_OFDM_RATE_54MB:
+		return B43legacy_OFDM_RATE_48MB;
+	}
+	B43legacy_BUG_ON(1);
+	return 0;
+}
+
+static void generate_txhdr_fw3(struct b43legacy_wldev *dev,
+			       struct b43legacy_txhdr_fw3 *txhdr,
+			       const unsigned char *fragment_data,
+			       unsigned int fragment_len,
+			       const struct ieee80211_tx_control *txctl,
+			       u16 cookie)
+{
+	const struct ieee80211_hdr *wlhdr;
+	int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT));
+	u16 fctl;
+	u8 rate;
+	u8 rate_fb;
+	int rate_ofdm;
+	int rate_fb_ofdm;
+	unsigned int plcp_fragment_len;
+	u32 mac_ctl = 0;
+	u16 phy_ctl = 0;
+
+	wlhdr = (const struct ieee80211_hdr *)fragment_data;
+	fctl = le16_to_cpu(wlhdr->frame_control);
+
+	memset(txhdr, 0, sizeof(*txhdr));
+
+	rate = txctl->tx_rate;
+	rate_ofdm = b43legacy_is_ofdm_rate(rate);
+	rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate;
+	rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb);
+
+	txhdr->mac_frame_ctl = wlhdr->frame_control;
+	memcpy(txhdr->tx_receiver, wlhdr->addr1, 6);
+
+	/* Calculate duration for fallback rate */
+	if ((rate_fb == rate) ||
+	    (wlhdr->duration_id & cpu_to_le16(0x8000)) ||
+	    (wlhdr->duration_id == cpu_to_le16(0))) {
+		/* If the fallback rate equals the normal rate or the
+		 * dur_id field contains an AID, CFP magic or 0,
+		 * use the original dur_id field. */
+		txhdr->dur_fb = wlhdr->duration_id;
+	} else {
+		int fbrate_base100kbps = B43legacy_RATE_TO_100KBPS(rate_fb);
+		txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw,
+							 dev->wl->if_id,
+							 fragment_len,
+							 fbrate_base100kbps);
+	}
+
+	plcp_fragment_len = fragment_len + FCS_LEN;
+	if (use_encryption) {
+		u8 key_idx = (u16)(txctl->key_idx);
+		struct b43legacy_key *key;
+		int wlhdr_len;
+		size_t iv_len;
+
+		B43legacy_WARN_ON(key_idx >= dev->max_nr_keys);
+		key = &(dev->key[key_idx]);
+
+		if (key->enabled) {
+			/* Hardware appends ICV. */
+			plcp_fragment_len += txctl->icv_len;
+
+			key_idx = b43legacy_kidx_to_fw(dev, key_idx);
+			mac_ctl |= (key_idx << B43legacy_TX4_MAC_KEYIDX_SHIFT) &
+				   B43legacy_TX4_MAC_KEYIDX;
+			mac_ctl |= (key->algorithm <<
+				   B43legacy_TX4_MAC_KEYALG_SHIFT) &
+				   B43legacy_TX4_MAC_KEYALG;
+			wlhdr_len = ieee80211_get_hdrlen(fctl);
+			iv_len = min((size_t)txctl->iv_len,
+				     ARRAY_SIZE(txhdr->iv));
+			memcpy(txhdr->iv, ((u8 *)wlhdr) + wlhdr_len, iv_len);
+		}
+	}
+	b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
+				    (&txhdr->plcp), plcp_fragment_len,
+				    rate);
+	b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
+				    (&txhdr->plcp_fb), plcp_fragment_len,
+				    rate_fb);
+
+	/* PHY TX Control word */
+	if (rate_ofdm)
+		phy_ctl |= B43legacy_TX4_PHY_OFDM;
+	if (dev->short_preamble)
+		phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL;
+	switch (txctl->antenna_sel_tx) {
+	case 0:
+		phy_ctl |= B43legacy_TX4_PHY_ANTLAST;
+		break;
+	case 1:
+		phy_ctl |= B43legacy_TX4_PHY_ANT0;
+		break;
+	case 2:
+		phy_ctl |= B43legacy_TX4_PHY_ANT1;
+		break;
+	default:
+		B43legacy_BUG_ON(1);
+	}
+
+	/* MAC control */
+	if (!(txctl->flags & IEEE80211_TXCTL_NO_ACK))
+		mac_ctl |= B43legacy_TX4_MAC_ACK;
+	if (!(((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+	      ((fctl & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)))
+		mac_ctl |= B43legacy_TX4_MAC_HWSEQ;
+	if (txctl->flags & IEEE80211_TXCTL_FIRST_FRAGMENT)
+		mac_ctl |= B43legacy_TX4_MAC_STMSDU;
+	if (rate_fb_ofdm)
+		mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM;
+
+	/* Generate the RTS or CTS-to-self frame */
+	if ((txctl->flags & IEEE80211_TXCTL_USE_RTS_CTS) ||
+	    (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) {
+		unsigned int len;
+		struct ieee80211_hdr *hdr;
+		int rts_rate;
+		int rts_rate_fb;
+		int rts_rate_ofdm;
+		int rts_rate_fb_ofdm;
+
+		rts_rate = txctl->rts_cts_rate;
+		rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate);
+		rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate);
+		rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb);
+		if (rts_rate_fb_ofdm)
+			mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM;
+
+		if (txctl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+			ieee80211_ctstoself_get(dev->wl->hw,
+						dev->wl->if_id,
+						fragment_data,
+						fragment_len, txctl,
+						(struct ieee80211_cts *)
+						(txhdr->rts_frame));
+			mac_ctl |= B43legacy_TX4_MAC_SENDCTS;
+			len = sizeof(struct ieee80211_cts);
+		} else {
+			ieee80211_rts_get(dev->wl->hw,
+					  dev->wl->if_id,
+					  fragment_data, fragment_len, txctl,
+					  (struct ieee80211_rts *)
+					  (txhdr->rts_frame));
+			mac_ctl |= B43legacy_TX4_MAC_SENDRTS;
+			len = sizeof(struct ieee80211_rts);
+		}
+		len += FCS_LEN;
+		b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
+					    (&txhdr->rts_plcp),
+					    len, rts_rate);
+		b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *)
+					    (&txhdr->rts_plcp_fb),
+					    len, rts_rate_fb);
+		hdr = (struct ieee80211_hdr *)(&txhdr->rts_frame);
+		txhdr->rts_dur_fb = hdr->duration_id;
+		mac_ctl |= B43legacy_TX4_MAC_LONGFRAME;
+	}
+
+	/* Magic cookie */
+	txhdr->cookie = cpu_to_le16(cookie);
+
+	/* Apply the bitfields */
+	txhdr->mac_ctl = cpu_to_le32(mac_ctl);
+	txhdr->phy_ctl = cpu_to_le16(phy_ctl);
+}
+
+void b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
+			      u8 *txhdr,
+			      const unsigned char *fragment_data,
+			      unsigned int fragment_len,
+			      const struct ieee80211_tx_control *txctl,
+			      u16 cookie)
+{
+	generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr,
+			   fragment_data, fragment_len,
+			   txctl, cookie);
+}
+
+static s8 b43legacy_rssi_postprocess(struct b43legacy_wldev *dev,
+				     u8 in_rssi, int ofdm,
+				     int adjust_2053, int adjust_2050)
+{
+	struct b43legacy_phy *phy = &dev->phy;
+	s32 tmp;
+
+	switch (phy->radio_ver) {
+	case 0x2050:
+		if (ofdm) {
+			tmp = in_rssi;
+			if (tmp > 127)
+				tmp -= 256;
+			tmp *= 73;
+			tmp /= 64;
+			if (adjust_2050)
+				tmp += 25;
+			else
+				tmp -= 3;
+		} else {
+			if (dev->dev->bus->sprom.r1.boardflags_lo
+			    & B43legacy_BFL_RSSI) {
+				if (in_rssi > 63)
+					in_rssi = 63;
+				tmp = phy->nrssi_lt[in_rssi];
+				tmp = 31 - tmp;
+				tmp *= -131;
+				tmp /= 128;
+				tmp -= 57;
+			} else {
+				tmp = in_rssi;
+				tmp = 31 - tmp;
+				tmp *= -149;
+				tmp /= 128;
+				tmp -= 68;
+			}
+			if (phy->type == B43legacy_PHYTYPE_G &&
+			    adjust_2050)
+				tmp += 25;
+		}
+		break;
+	case 0x2060:
+		if (in_rssi > 127)
+			tmp = in_rssi - 256;
+		else
+			tmp = in_rssi;
+		break;
+	default:
+		tmp = in_rssi;
+		tmp -= 11;
+		tmp *= 103;
+		tmp /= 64;
+		if (adjust_2053)
+			tmp -= 109;
+		else
+			tmp -= 83;
+	}
+
+	return (s8)tmp;
+}
+
+void b43legacy_rx(struct b43legacy_wldev *dev,
+		  struct sk_buff *skb,
+		  const void *_rxhdr)
+{
+	struct ieee80211_rx_status status;
+	struct b43legacy_plcp_hdr6 *plcp;
+	struct ieee80211_hdr *wlhdr;
+	const struct b43legacy_rxhdr_fw3 *rxhdr = _rxhdr;
+	u16 fctl;
+	u16 phystat0;
+	u16 phystat3;
+	u16 chanstat;
+	u16 mactime;
+	u32 macstat;
+	u16 chanid;
+	u8 jssi;
+	int padding;
+
+	memset(&status, 0, sizeof(status));
+
+	/* Get metadata about the frame from the header. */
+	phystat0 = le16_to_cpu(rxhdr->phy_status0);
+	phystat3 = le16_to_cpu(rxhdr->phy_status3);
+	jssi = rxhdr->jssi;
+	macstat = le16_to_cpu(rxhdr->mac_status);
+	mactime = le16_to_cpu(rxhdr->mac_time);
+	chanstat = le16_to_cpu(rxhdr->channel);
+
+	if (macstat & B43legacy_RX_MAC_FCSERR)
+		dev->wl->ieee_stats.dot11FCSErrorCount++;
+
+	/* Skip PLCP and padding */
+	padding = (macstat & B43legacy_RX_MAC_PADDING) ? 2 : 0;
+	if (unlikely(skb->len < (sizeof(struct b43legacy_plcp_hdr6) +
+	    padding))) {
+		b43legacydbg(dev->wl, "RX: Packet size underrun (1)\n");
+		goto drop;
+	}
+	plcp = (struct b43legacy_plcp_hdr6 *)(skb->data + padding);
+	skb_pull(skb, sizeof(struct b43legacy_plcp_hdr6) + padding);
+	/* The skb contains the Wireless Header + payload data now */
+	if (unlikely(skb->len < (2+2+6/*minimum hdr*/ + FCS_LEN))) {
+		b43legacydbg(dev->wl, "RX: Packet size underrun (2)\n");
+		goto drop;
+	}
+	wlhdr = (struct ieee80211_hdr *)(skb->data);
+	fctl = le16_to_cpu(wlhdr->frame_control);
+
+	if ((macstat & B43legacy_RX_MAC_DEC) &&
+	    !(macstat & B43legacy_RX_MAC_DECERR)) {
+		unsigned int keyidx;
+		int wlhdr_len;
+		int iv_len;
+		int icv_len;
+
+		keyidx = ((macstat & B43legacy_RX_MAC_KEYIDX)
+			  >> B43legacy_RX_MAC_KEYIDX_SHIFT);
+		/* We must adjust the key index here. We want the "physical"
+		 * key index, but the ucode passed it slightly different.
+		 */
+		keyidx = b43legacy_kidx_to_raw(dev, keyidx);
+		B43legacy_WARN_ON(keyidx >= dev->max_nr_keys);
+
+		if (dev->key[keyidx].algorithm != B43legacy_SEC_ALGO_NONE) {
+			/* Remove PROTECTED flag to mark it as decrypted. */
+			B43legacy_WARN_ON(!(fctl & IEEE80211_FCTL_PROTECTED));
+			fctl &= ~IEEE80211_FCTL_PROTECTED;
+			wlhdr->frame_control = cpu_to_le16(fctl);
+
+			wlhdr_len = ieee80211_get_hdrlen(fctl);
+			if (unlikely(skb->len < (wlhdr_len + 3))) {
+				b43legacydbg(dev->wl, "RX: Packet size"
+					     " underrun3\n");
+				goto drop;
+			}
+			if (skb->data[wlhdr_len + 3] & (1 << 5)) {
+				/* The Ext-IV Bit is set in the "KeyID"
+				 * octet of the IV.
+				 */
+				iv_len = 8;
+				icv_len = 8;
+			} else {
+				iv_len = 4;
+				icv_len = 4;
+			}
+			if (unlikely(skb->len < (wlhdr_len + iv_len +
+			    icv_len))) {
+				b43legacydbg(dev->wl, "RX: Packet size"
+					     " underrun4\n");
+				goto drop;
+			}
+			/* Remove the IV */
+			memmove(skb->data + iv_len, skb->data, wlhdr_len);
+			skb_pull(skb, iv_len);
+			/* Remove the ICV */
+			skb_trim(skb, skb->len - icv_len);
+
+			status.flag |= RX_FLAG_DECRYPTED;
+		}
+	}
+
+	status.ssi = b43legacy_rssi_postprocess(dev, jssi,
+				      (phystat0 & B43legacy_RX_PHYST0_OFDM),
+				      (phystat0 & B43legacy_RX_PHYST0_GAINCTL),
+				      (phystat3 & B43legacy_RX_PHYST3_TRSTATE));
+	status.noise = dev->stats.link_noise;
+	status.signal = (jssi * 100) / B43legacy_RX_MAX_SSI;
+	if (phystat0 & B43legacy_RX_PHYST0_OFDM)
+		status.rate = b43legacy_plcp_get_bitrate_ofdm(plcp);
+	else
+		status.rate = b43legacy_plcp_get_bitrate_cck(plcp);
+	status.antenna = !!(phystat0 & B43legacy_RX_PHYST0_ANT);
+	status.mactime = mactime;
+
+	chanid = (chanstat & B43legacy_RX_CHAN_ID) >>
+		  B43legacy_RX_CHAN_ID_SHIFT;
+	switch (chanstat & B43legacy_RX_CHAN_PHYTYPE) {
+	case B43legacy_PHYTYPE_B:
+		status.phymode = MODE_IEEE80211B;
+		status.freq = chanid + 2400;
+		status.channel = b43legacy_freq_to_channel_bg(chanid + 2400);
+		break;
+	case B43legacy_PHYTYPE_G:
+		status.phymode = MODE_IEEE80211G;
+		status.freq = chanid + 2400;
+		status.channel = b43legacy_freq_to_channel_bg(chanid + 2400);
+		break;
+	default:
+		b43legacywarn(dev->wl, "Unexpected value for chanstat (0x%X)\n",
+		       chanstat);
+	}
+
+	dev->stats.last_rx = jiffies;
+	ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
+
+	return;
+drop:
+	b43legacydbg(dev->wl, "RX: Packet dropped\n");
+	dev_kfree_skb_any(skb);
+}
+
+void b43legacy_handle_txstatus(struct b43legacy_wldev *dev,
+			     const struct b43legacy_txstatus *status)
+{
+	b43legacy_debugfs_log_txstat(dev, status);
+
+	if (status->intermediate)
+		return;
+	if (status->for_ampdu)
+		return;
+	if (!status->acked)
+		dev->wl->ieee_stats.dot11ACKFailureCount++;
+	if (status->rts_count) {
+		if (status->rts_count == 0xF) /* FIXME */
+			dev->wl->ieee_stats.dot11RTSFailureCount++;
+		else
+			dev->wl->ieee_stats.dot11RTSSuccessCount++;
+	}
+
+	if (b43legacy_using_pio(dev))
+		b43legacy_pio_handle_txstatus(dev, status);
+	else
+		b43legacy_dma_handle_txstatus(dev, status);
+}
+
+/* Handle TX status report as received through DMA/PIO queues */
+void b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev,
+				 const struct b43legacy_hwtxstatus *hw)
+{
+	struct b43legacy_txstatus status;
+	u8 tmp;
+
+	status.cookie = le16_to_cpu(hw->cookie);
+	status.seq = le16_to_cpu(hw->seq);
+	status.phy_stat = hw->phy_stat;
+	tmp = hw->count;
+	status.frame_count = (tmp >> 4);
+	status.rts_count = (tmp & 0x0F);
+	tmp = hw->flags;
+	status.supp_reason = ((tmp & 0x1C) >> 2);
+	status.pm_indicated = !!(tmp & 0x80);
+	status.intermediate = !!(tmp & 0x40);
+	status.for_ampdu = !!(tmp & 0x20);
+	status.acked = !!(tmp & 0x02);
+
+	b43legacy_handle_txstatus(dev, &status);
+}
+
+/* Stop any TX operation on the device (suspend the hardware queues) */
+void b43legacy_tx_suspend(struct b43legacy_wldev *dev)
+{
+	if (b43legacy_using_pio(dev))
+		b43legacy_pio_freeze_txqueues(dev);
+	else
+		b43legacy_dma_tx_suspend(dev);
+}
+
+/* Resume any TX operation on the device (resume the hardware queues) */
+void b43legacy_tx_resume(struct b43legacy_wldev *dev)
+{
+	if (b43legacy_using_pio(dev))
+		b43legacy_pio_thaw_txqueues(dev);
+	else
+		b43legacy_dma_tx_resume(dev);
+}
+
+/* Initialize the QoS parameters */
+void b43legacy_qos_init(struct b43legacy_wldev *dev)
+{
+	/* FIXME: This function must probably be called from the mac80211
+	 * config callback. */
+return;
+
+	b43legacy_hf_write(dev, b43legacy_hf_read(dev) | B43legacy_HF_EDCF);
+	/* FIXME kill magic */
+	b43legacy_write16(dev, 0x688,
+			  b43legacy_read16(dev, 0x688) | 0x4);
+
+
+	/*TODO: We might need some stack support here to get the values. */
+}
diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h
new file mode 100644
index 0000000..8a155d0
--- /dev/null
+++ b/drivers/net/wireless/b43legacy/xmit.h
@@ -0,0 +1,259 @@
+#ifndef B43legacy_XMIT_H_
+#define B43legacy_XMIT_H_
+
+#include "main.h"
+
+
+#define _b43legacy_declare_plcp_hdr(size)	\
+	struct b43legacy_plcp_hdr##size {	\
+		union {				\
+			__le32 data;		\
+			__u8 raw[size];		\
+		} __attribute__((__packed__));	\
+	} __attribute__((__packed__))
+
+/* struct b43legacy_plcp_hdr4 */
+_b43legacy_declare_plcp_hdr(4);
+/* struct b43legacy_plcp_hdr6 */
+_b43legacy_declare_plcp_hdr(6);
+
+#undef _b43legacy_declare_plcp_hdr
+
+
+/* TX header for v3 firmware */
+struct b43legacy_txhdr_fw3 {
+	__le32 mac_ctl;				/* MAC TX control */
+	__le16 mac_frame_ctl;			/* Copy of the FrameControl */
+	__le16 tx_fes_time_norm;		/* TX FES Time Normal */
+	__le16 phy_ctl;				/* PHY TX control */
+	__u8 iv[16];				/* Encryption IV */
+	__u8 tx_receiver[6];			/* TX Frame Receiver address */
+	__le16 tx_fes_time_fb;			/* TX FES Time Fallback */
+	struct b43legacy_plcp_hdr4 rts_plcp_fb;	/* RTS fallback PLCP */
+	__le16 rts_dur_fb;			/* RTS fallback duration */
+	struct b43legacy_plcp_hdr4 plcp_fb;	/* Fallback PLCP */
+	__le16 dur_fb;				/* Fallback duration */
+	PAD_BYTES(2);
+	__le16 cookie;
+	__le16 unknown_scb_stuff;
+	struct b43legacy_plcp_hdr6 rts_plcp;	/* RTS PLCP */
+	__u8 rts_frame[18];			/* The RTS frame (if used) */
+	struct b43legacy_plcp_hdr6 plcp;
+} __attribute__((__packed__));
+
+/* MAC TX control */
+#define B43legacy_TX4_MAC_KEYIDX	0x0FF00000 /* Security key index */
+#define B43legacy_TX4_MAC_KEYIDX_SHIFT	20
+#define B43legacy_TX4_MAC_KEYALG	0x00070000 /* Security key algorithm */
+#define B43legacy_TX4_MAC_KEYALG_SHIFT	16
+#define B43legacy_TX4_MAC_LIFETIME	0x00001000
+#define B43legacy_TX4_MAC_FRAMEBURST	0x00000800
+#define B43legacy_TX4_MAC_SENDCTS	0x00000400
+#define B43legacy_TX4_MAC_AMPDU		0x00000300
+#define B43legacy_TX4_MAC_AMPDU_SHIFT	8
+#define B43legacy_TX4_MAC_CTSFALLBACKOFDM	0x00000200
+#define B43legacy_TX4_MAC_FALLBACKOFDM	0x00000100
+#define B43legacy_TX4_MAC_5GHZ		0x00000080
+#define B43legacy_TX4_MAC_IGNPMQ	0x00000020
+#define B43legacy_TX4_MAC_HWSEQ		0x00000010 /* Use Hardware Seq No */
+#define B43legacy_TX4_MAC_STMSDU	0x00000008 /* Start MSDU */
+#define B43legacy_TX4_MAC_SENDRTS	0x00000004
+#define B43legacy_TX4_MAC_LONGFRAME	0x00000002
+#define B43legacy_TX4_MAC_ACK		0x00000001
+
+/* Extra Frame Types */
+#define B43legacy_TX4_EFT_FBOFDM	0x0001 /* Data frame fb rate type */
+#define B43legacy_TX4_EFT_RTSOFDM	0x0004 /* RTS/CTS rate type */
+#define B43legacy_TX4_EFT_RTSFBOFDM	0x0010 /* RTS/CTS fallback rate type */
+
+/* PHY TX control word */
+#define B43legacy_TX4_PHY_OFDM		0x0001 /* Data frame rate type */
+#define B43legacy_TX4_PHY_SHORTPRMBL	0x0010 /* Use short preamble */
+#define B43legacy_TX4_PHY_ANT		0x03C0 /* Antenna selection */
+#define  B43legacy_TX4_PHY_ANT0		0x0000 /* Use antenna 0 */
+#define  B43legacy_TX4_PHY_ANT1		0x0100 /* Use antenna 1 */
+#define  B43legacy_TX4_PHY_ANTLAST	0x0300 /* Use last used antenna */
+
+
+
+void b43legacy_generate_txhdr(struct b43legacy_wldev *dev,
+			      u8 *txhdr,
+			      const unsigned char *fragment_data,
+			      unsigned int fragment_len,
+			      const struct ieee80211_tx_control *txctl,
+			      u16 cookie);
+
+
+/* Transmit Status */
+struct b43legacy_txstatus {
+	u16 cookie;	/* The cookie from the txhdr */
+	u16 seq;	/* Sequence number */
+	u8 phy_stat;	/* PHY TX status */
+	u8 frame_count;	/* Frame transmit count */
+	u8 rts_count;	/* RTS transmit count */
+	u8 supp_reason;	/* Suppression reason */
+	/* flags */
+	u8 pm_indicated;/* PM mode indicated to AP */
+	u8 intermediate;/* Intermediate status notification */
+	u8 for_ampdu;	/* Status is for an AMPDU (afterburner) */
+	u8 acked;	/* Wireless ACK received */
+};
+
+/* txstatus supp_reason values */
+enum {
+	B43legacy_TXST_SUPP_NONE,	/* Not suppressed */
+	B43legacy_TXST_SUPP_PMQ,	/* Suppressed due to PMQ entry */
+	B43legacy_TXST_SUPP_FLUSH,	/* Suppressed due to flush request */
+	B43legacy_TXST_SUPP_PREV,	/* Previous fragment failed */
+	B43legacy_TXST_SUPP_CHAN,	/* Channel mismatch */
+	B43legacy_TXST_SUPP_LIFE,	/* Lifetime expired */
+	B43legacy_TXST_SUPP_UNDER,	/* Buffer underflow */
+	B43legacy_TXST_SUPP_ABNACK,	/* Afterburner NACK */
+};
+
+/* Transmit Status as received through DMA/PIO on old chips */
+struct b43legacy_hwtxstatus {
+	PAD_BYTES(4);
+	__le16 cookie;
+	u8 flags;
+	u8 count;
+	PAD_BYTES(2);
+	__le16 seq;
+	u8 phy_stat;
+	PAD_BYTES(1);
+} __attribute__((__packed__));
+
+
+/* Receive header for v3 firmware. */
+struct b43legacy_rxhdr_fw3 {
+	__le16 frame_len;	/* Frame length */
+	PAD_BYTES(2);
+	__le16 phy_status0;	/* PHY RX Status 0 */
+	__u8 jssi;		/* PHY RX Status 1: JSSI */
+	__u8 sig_qual;		/* PHY RX Status 1: Signal Quality */
+	PAD_BYTES(2);		/* PHY RX Status 2 */
+	__le16 phy_status3;	/* PHY RX Status 3 */
+	__le16 mac_status;	/* MAC RX status */
+	__le16 mac_time;
+	__le16 channel;
+} __attribute__((__packed__));
+
+
+/* PHY RX Status 0 */
+#define B43legacy_RX_PHYST0_GAINCTL	0x4000 /* Gain Control */
+#define B43legacy_RX_PHYST0_PLCPHCF	0x0200
+#define B43legacy_RX_PHYST0_PLCPFV	0x0100
+#define B43legacy_RX_PHYST0_SHORTPRMBL	0x0080 /* Recvd with Short Preamble */
+#define B43legacy_RX_PHYST0_LCRS	0x0040
+#define B43legacy_RX_PHYST0_ANT		0x0020 /* Antenna */
+#define B43legacy_RX_PHYST0_UNSRATE	0x0010
+#define B43legacy_RX_PHYST0_CLIP	0x000C
+#define B43legacy_RX_PHYST0_CLIP_SHIFT	2
+#define B43legacy_RX_PHYST0_FTYPE	0x0003 /* Frame type */
+#define  B43legacy_RX_PHYST0_CCK	0x0000 /* Frame type: CCK */
+#define  B43legacy_RX_PHYST0_OFDM	0x0001 /* Frame type: OFDM */
+#define  B43legacy_RX_PHYST0_PRE_N	0x0002 /* Pre-standard N-PHY frame */
+#define  B43legacy_RX_PHYST0_STD_N	0x0003 /* Standard N-PHY frame */
+
+/* PHY RX Status 2 */
+#define B43legacy_RX_PHYST2_LNAG	0xC000 /* LNA Gain */
+#define B43legacy_RX_PHYST2_LNAG_SHIFT	14
+#define B43legacy_RX_PHYST2_PNAG	0x3C00 /* PNA Gain */
+#define B43legacy_RX_PHYST2_PNAG_SHIFT	10
+#define B43legacy_RX_PHYST2_FOFF	0x03FF /* F offset */
+
+/* PHY RX Status 3 */
+#define B43legacy_RX_PHYST3_DIGG	0x1800 /* DIG Gain */
+#define B43legacy_RX_PHYST3_DIGG_SHIFT	11
+#define B43legacy_RX_PHYST3_TRSTATE	0x0400 /* TR state */
+
+/* MAC RX Status */
+#define B43legacy_RX_MAC_BEACONSENT	0x00008000 /* Beacon send flag */
+#define B43legacy_RX_MAC_KEYIDX		0x000007E0 /* Key index */
+#define B43legacy_RX_MAC_KEYIDX_SHIFT	5
+#define B43legacy_RX_MAC_DECERR		0x00000010 /* Decrypt error */
+#define B43legacy_RX_MAC_DEC		0x00000008 /* Decryption attempted */
+#define B43legacy_RX_MAC_PADDING	0x00000004 /* Pad bytes present */
+#define B43legacy_RX_MAC_RESP		0x00000002 /* Response frame xmitted */
+#define B43legacy_RX_MAC_FCSERR		0x00000001 /* FCS error */
+
+/* RX channel */
+#define B43legacy_RX_CHAN_GAIN		0xFC00 /* Gain */
+#define B43legacy_RX_CHAN_GAIN_SHIFT	10
+#define B43legacy_RX_CHAN_ID		0x03FC /* Channel ID */
+#define B43legacy_RX_CHAN_ID_SHIFT	2
+#define B43legacy_RX_CHAN_PHYTYPE	0x0003 /* PHY type */
+
+
+
+u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate);
+u8 b43legacy_plcp_get_ratecode_ofdm(const u8 bitrate);
+
+void b43legacy_generate_plcp_hdr(struct b43legacy_plcp_hdr4 *plcp,
+			       const u16 octets, const u8 bitrate);
+
+void b43legacy_rx(struct b43legacy_wldev *dev,
+		struct sk_buff *skb,
+		const void *_rxhdr);
+
+void b43legacy_handle_txstatus(struct b43legacy_wldev *dev,
+			       const struct b43legacy_txstatus *status);
+
+void b43legacy_handle_hwtxstatus(struct b43legacy_wldev *dev,
+				 const struct b43legacy_hwtxstatus *hw);
+
+void b43legacy_tx_suspend(struct b43legacy_wldev *dev);
+void b43legacy_tx_resume(struct b43legacy_wldev *dev);
+
+
+#define B43legacy_NR_QOSPARMS	22
+enum {
+	B43legacy_QOSPARM_TXOP = 0,
+	B43legacy_QOSPARM_CWMIN,
+	B43legacy_QOSPARM_CWMAX,
+	B43legacy_QOSPARM_CWCUR,
+	B43legacy_QOSPARM_AIFS,
+	B43legacy_QOSPARM_BSLOTS,
+	B43legacy_QOSPARM_REGGAP,
+	B43legacy_QOSPARM_STATUS,
+};
+
+void b43legacy_qos_init(struct b43legacy_wldev *dev);
+
+
+/* Helper functions for converting the key-table index from "firmware-format"
+ * to "raw-format" and back. The firmware API changed for this at some revision.
+ * We need to account for that here. */
+static inline
+int b43legacy_new_kidx_api(struct b43legacy_wldev *dev)
+{
+	/* FIXME: Not sure the change was at rev 351 */
+	return (dev->fw.rev >= 351);
+}
+static inline
+u8 b43legacy_kidx_to_fw(struct b43legacy_wldev *dev, u8 raw_kidx)
+{
+	u8 firmware_kidx;
+	if (b43legacy_new_kidx_api(dev))
+		firmware_kidx = raw_kidx;
+	else {
+		if (raw_kidx >= 4) /* Is per STA key? */
+			firmware_kidx = raw_kidx - 4;
+		else
+			firmware_kidx = raw_kidx; /* TX default key */
+	}
+	return firmware_kidx;
+}
+static inline
+u8 b43legacy_kidx_to_raw(struct b43legacy_wldev *dev, u8 firmware_kidx)
+{
+	u8 raw_kidx;
+	if (b43legacy_new_kidx_api(dev))
+		raw_kidx = firmware_kidx;
+	else
+		/* RX default keys or per STA keys */
+		raw_kidx = firmware_kidx + 4;
+	return raw_kidx;
+}
+
+#endif /* B43legacy_XMIT_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 10e07e8..5fdbf24 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -994,10 +994,4 @@
 	 	__value;				\
 	})
 
-/** Helpers to print MAC addresses. */
-#define BCM43xx_MACFMT		"%02x:%02x:%02x:%02x:%02x:%02x"
-#define BCM43xx_MACARG(x)	((u8*)(x))[0], ((u8*)(x))[1], \
-				((u8*)(x))[2], ((u8*)(x))[3], \
-				((u8*)(x))[4], ((u8*)(x))[5]
-
 #endif /* BCM43xx_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index c5d6753..4568343 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -2380,7 +2380,7 @@
 		goto err_gpio_cleanup;
 	bcm43xx_radio_turn_on(bcm);
 	bcm->radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
-	dprintk(KERN_INFO PFX "Radio %s by hardware\n",
+	printk(KERN_INFO PFX "Radio %s by hardware\n",
 		(bcm->radio_hw_enable == 0) ? "disabled" : "enabled");
 
 	bcm43xx_write16(bcm, 0x03E6, 0x0000);
@@ -3129,7 +3129,7 @@
 	radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
 	if (unlikely(bcm->radio_hw_enable != radio_hw_enable)) {
 		bcm->radio_hw_enable = radio_hw_enable;
-		dprintk(KERN_INFO PFX "Radio hardware status changed to %s\n",
+		printk(KERN_INFO PFX "Radio hardware status changed to %s\n",
 		       (radio_hw_enable == 0) ? "disabled" : "enabled");
 		bcm43xx_leds_update(bcm, 0);
 	}
@@ -3183,6 +3183,9 @@
 	unsigned long orig_trans_start = 0;
 
 	mutex_lock(&bcm->mutex);
+	/* keep from doing and rearming periodic work if shutting down */
+	if (bcm43xx_status(bcm) == BCM43xx_STAT_UNINIT)
+		goto unlock_mutex;
 	if (unlikely(bcm->periodic_state % 60 == 0)) {
 		/* Periodic work will take a long time, so we want it to
 		 * be preemtible.
@@ -3228,14 +3231,10 @@
 	mmiowb();
 	bcm->periodic_state++;
 	spin_unlock_irqrestore(&bcm->irq_lock, flags);
+unlock_mutex:
 	mutex_unlock(&bcm->mutex);
 }
 
-void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
-{
-	cancel_rearming_delayed_work(&bcm->periodic_work);
-}
-
 void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
 {
 	struct delayed_work *work = &bcm->periodic_work;
@@ -3285,6 +3284,14 @@
 	return err;
 }
 
+void bcm43xx_cancel_work(struct bcm43xx_private *bcm)
+{
+	/* The system must be unlocked when this routine is entered.
+	 * If not, the next 2 steps may deadlock */
+	cancel_work_sync(&bcm->restart_work);
+	cancel_delayed_work_sync(&bcm->periodic_work);
+}
+
 static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm)
 {
 	int ret = 0;
@@ -3321,7 +3328,12 @@
 {
 	bcm43xx_rng_exit(bcm);
 	bcm43xx_sysfs_unregister(bcm);
-	bcm43xx_periodic_tasks_delete(bcm);
+
+	mutex_lock(&(bcm)->mutex);
+	bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+	mutex_unlock(&(bcm)->mutex);
+
+	bcm43xx_cancel_work(bcm);
 
 	mutex_lock(&(bcm)->mutex);
 	bcm43xx_shutdown_all_wireless_cores(bcm);
@@ -4016,7 +4028,7 @@
 	err = bcm43xx_disable_interrupts_sync(bcm);
 	assert(!err);
 	bcm43xx_free_board(bcm);
-	flush_scheduled_work();
+	bcm43xx_cancel_work(bcm);
 
 	return 0;
 }
@@ -4080,7 +4092,6 @@
 		goto out;
 	}
 	/* initialize the net_device struct */
-	SET_MODULE_OWNER(net_dev);
 	SET_NETDEV_DEV(net_dev, &pdev->dev);
 
 	net_dev->open = bcm43xx_net_open;
@@ -4148,9 +4159,9 @@
 	struct bcm43xx_phyinfo *phy;
 	int err = -ENODEV;
 
+	bcm43xx_cancel_work(bcm);
 	mutex_lock(&(bcm)->mutex);
 	if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
-		bcm43xx_periodic_tasks_delete(bcm);
 		phy = bcm43xx_current_phy(bcm);
 		err = bcm43xx_select_wireless_core(bcm, phy->type);
 		if (!err)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index c8f3c53..14cfbeb 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -122,7 +122,7 @@
 void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
 void bcm43xx_mac_enable(struct bcm43xx_private *bcm);
 
-void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm);
+void bcm43xx_cancel_work(struct bcm43xx_private *bcm);
 void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm);
 
 void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index d779199..b37f1e3 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -1638,7 +1638,7 @@
 		return;
 	}
 
-	if (phy->analog == 1) {
+	if (phy->analog > 1) {
 		value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C;
 		value |= (baseband_attenuation << 2) & 0x003C;
 	} else {
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index 6a109f4..c605099 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -2146,7 +2146,7 @@
 	} else
 		bcm43xx_phy_write(bcm, 0x0015, 0xAA00);
 	radio->enabled = 0;
-	dprintk(KERN_INFO PFX "Radio turned off\n");
+	dprintk(KERN_INFO PFX "Radio initialized\n");
 	bcm43xx_leds_update(bcm, 0);
 }
 
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
index c71b998..8ab5f93 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -327,7 +327,7 @@
 		goto out;
 	}
 
-	bcm43xx_periodic_tasks_delete(bcm);
+	bcm43xx_cancel_work(bcm);
 	mutex_lock(&(bcm)->mutex);
 	err = bcm43xx_select_wireless_core(bcm, phytype);
 	if (!err)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index d6d9413..6acfdc4 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -444,7 +444,7 @@
 	u16 maxpower;
 
 	if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) {
-		printk(PFX KERN_ERR "TX power not in dBm.\n");
+		printk(KERN_ERR PFX "TX power not in dBm.\n");
 		return -EOPNOTSUPP;
 	}
 
diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h
index ef37a75..547ba84 100644
--- a/drivers/net/wireless/hostap/hostap.h
+++ b/drivers/net/wireless/hostap/hostap.h
@@ -30,12 +30,11 @@
 			   const struct hfa384x_rx_frame *rx);
 void hostap_dump_tx_header(const char *name,
 			   const struct hfa384x_tx_frame *tx);
-int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr);
-int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr);
+extern const struct header_ops hostap_80211_ops;
 int hostap_80211_get_hdrlen(u16 fc);
 struct net_device_stats *hostap_get_stats(struct net_device *dev);
 void hostap_setup_dev(struct net_device *dev, local_info_t *local,
-		      int main_dev);
+		      int type);
 void hostap_set_multicast_list_queue(struct work_struct *work);
 int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked);
 int hostap_set_hostapd_sta(local_info_t *local, int val, int rtnl_locked);
diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c
index cbedc9e..ef084df 100644
--- a/drivers/net/wireless/hostap/hostap_80211_rx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_rx.c
@@ -19,6 +19,7 @@
 {
 	struct ieee80211_hdr_4addr *hdr;
 	u16 fc;
+	DECLARE_MAC_BUF(mac);
 
 	hdr = (struct ieee80211_hdr_4addr *) skb->data;
 
@@ -44,10 +45,11 @@
 	printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
 	       le16_to_cpu(hdr->seq_ctl));
 
-	printk(KERN_DEBUG "   A1=" MACSTR " A2=" MACSTR " A3=" MACSTR,
-	       MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3));
+	printk(KERN_DEBUG "   A1=%s", print_mac(mac, hdr->addr1));
+	printk(" A2=%s", print_mac(mac, hdr->addr2));
+	printk(" A3=%s", print_mac(mac, hdr->addr3));
 	if (skb->len >= 30)
-		printk(" A4=" MACSTR, MAC2STR(hdr->addr4));
+		printk(" A4=%s", print_mac(mac, hdr->addr4));
 	printk("\n");
 }
 
@@ -534,6 +536,7 @@
 hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
 		    u16 fc, struct net_device **wds)
 {
+	DECLARE_MAC_BUF(mac);
 	/* FIX: is this really supposed to accept WDS frames only in Master
 	 * mode? What about Repeater or Managed with WDS frames? */
 	if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) !=
@@ -549,10 +552,10 @@
 	     hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) {
 		/* RA (or BSSID) is not ours - drop */
 		PDEBUG(DEBUG_EXTRA, "%s: received WDS frame with "
-		       "not own or broadcast %s=" MACSTR "\n",
+		       "not own or broadcast %s=%s\n",
 		       local->dev->name,
 		       fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID",
-		       MAC2STR(hdr->addr1));
+		       print_mac(mac, hdr->addr1));
 		return -1;
 	}
 
@@ -565,8 +568,8 @@
 		/* require that WDS link has been registered with TA or the
 		 * frame is from current AP when using 'AP client mode' */
 		PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame "
-		       "from unknown TA=" MACSTR "\n",
-		       local->dev->name, MAC2STR(hdr->addr2));
+		       "from unknown TA=%s\n",
+		       local->dev->name, print_mac(mac, hdr->addr2));
 		if (local->ap && local->ap->autom_ap_wds)
 			hostap_wds_link_oper(local, hdr->addr2, WDS_ADD);
 		return -1;
@@ -632,6 +635,7 @@
 {
 	struct ieee80211_hdr_4addr *hdr;
 	int res, hdrlen;
+	DECLARE_MAC_BUF(mac);
 
 	if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
 		return 0;
@@ -643,8 +647,8 @@
 	    strcmp(crypt->ops->name, "TKIP") == 0) {
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
-			       "received packet from " MACSTR "\n",
-			       local->dev->name, MAC2STR(hdr->addr2));
+			       "received packet from %s\n",
+			       local->dev->name, print_mac(mac, hdr->addr2));
 		}
 		return -1;
 	}
@@ -653,9 +657,9 @@
 	res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv);
 	atomic_dec(&crypt->refcnt);
 	if (res < 0) {
-		printk(KERN_DEBUG "%s: decryption failed (SA=" MACSTR
+		printk(KERN_DEBUG "%s: decryption failed (SA=%s"
 		       ") res=%d\n",
-		       local->dev->name, MAC2STR(hdr->addr2), res);
+		       local->dev->name, print_mac(mac, hdr->addr2), res);
 		local->comm_tallies.rx_discards_wep_undecryptable++;
 		return -1;
 	}
@@ -671,6 +675,7 @@
 {
 	struct ieee80211_hdr_4addr *hdr;
 	int res, hdrlen;
+	DECLARE_MAC_BUF(mac);
 
 	if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
 		return 0;
@@ -683,8 +688,8 @@
 	atomic_dec(&crypt->refcnt);
 	if (res < 0) {
 		printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
-		       " (SA=" MACSTR " keyidx=%d)\n",
-		       local->dev->name, MAC2STR(hdr->addr2), keyidx);
+		       " (SA=%s keyidx=%d)\n",
+		       local->dev->name, print_mac(mac, hdr->addr2), keyidx);
 		return -1;
 	}
 
@@ -716,6 +721,7 @@
 	struct ieee80211_crypt_data *crypt = NULL;
 	void *sta = NULL;
 	int keyidx = 0;
+	DECLARE_MAC_BUF(mac);
 
 	iface = netdev_priv(dev);
 	local = iface->local;
@@ -792,8 +798,8 @@
 			 * frames silently instead of filling system log with
 			 * these reports. */
 			printk(KERN_DEBUG "%s: WEP decryption failed (not set)"
-			       " (SA=" MACSTR ")\n",
-			       local->dev->name, MAC2STR(hdr->addr2));
+			       " (SA=%s)\n",
+			       local->dev->name, print_mac(mac, hdr->addr2));
 #endif
 			local->comm_tallies.rx_discards_wep_undecryptable++;
 			goto rx_dropped;
@@ -807,8 +813,8 @@
 		    (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0)
 		{
 			printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth "
-			       "from " MACSTR "\n", dev->name,
-			       MAC2STR(hdr->addr2));
+			       "from %s\n", dev->name,
+			       print_mac(mac, hdr->addr2));
 			/* TODO: could inform hostapd about this so that it
 			 * could send auth failure report */
 			goto rx_dropped;
@@ -976,8 +982,8 @@
 			       "unencrypted EAPOL frame\n", local->dev->name);
 		} else {
 			printk(KERN_DEBUG "%s: encryption configured, but RX "
-			       "frame not encrypted (SA=" MACSTR ")\n",
-			       local->dev->name, MAC2STR(hdr->addr2));
+			       "frame not encrypted (SA=%s)\n",
+			       local->dev->name, print_mac(mac, hdr->addr2));
 			goto rx_dropped;
 		}
 	}
@@ -986,8 +992,9 @@
 	    !hostap_is_eapol_frame(local, skb)) {
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "%s: dropped unencrypted RX data "
-			       "frame from " MACSTR " (drop_unencrypted=1)\n",
-			       dev->name, MAC2STR(hdr->addr2));
+			       "frame from %s"
+			       " (drop_unencrypted=1)\n",
+			       dev->name, print_mac(mac, hdr->addr2));
 		}
 		goto rx_dropped;
 	}
diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c
index 3df3c60..e7afc3e 100644
--- a/drivers/net/wireless/hostap/hostap_80211_tx.c
+++ b/drivers/net/wireless/hostap/hostap_80211_tx.c
@@ -17,6 +17,7 @@
 {
 	struct ieee80211_hdr_4addr *hdr;
 	u16 fc;
+	DECLARE_MAC_BUF(mac);
 
 	hdr = (struct ieee80211_hdr_4addr *) skb->data;
 
@@ -40,10 +41,11 @@
 	printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
 	       le16_to_cpu(hdr->seq_ctl));
 
-	printk(KERN_DEBUG "   A1=" MACSTR " A2=" MACSTR " A3=" MACSTR,
-	       MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), MAC2STR(hdr->addr3));
+	printk(KERN_DEBUG "   A1=%s", print_mac(mac, hdr->addr1));
+	printk(" A2=%s", print_mac(mac, hdr->addr2));
+	printk(" A3=%s", print_mac(mac, hdr->addr3));
 	if (skb->len >= 30)
-		printk(" A4=" MACSTR, MAC2STR(hdr->addr4));
+		printk(" A4=%s", print_mac(mac, hdr->addr4));
 	printk("\n");
 }
 
@@ -312,6 +314,7 @@
 	struct ieee80211_hdr_4addr *hdr;
 	u16 fc;
 	int prefix_len, postfix_len, hdr_len, res;
+	DECLARE_MAC_BUF(mac);
 
 	iface = netdev_priv(skb->dev);
 	local = iface->local;
@@ -326,8 +329,8 @@
 		hdr = (struct ieee80211_hdr_4addr *) skb->data;
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
-			       "TX packet to " MACSTR "\n",
-			       local->dev->name, MAC2STR(hdr->addr1));
+			       "TX packet to %s\n",
+			       local->dev->name, print_mac(mac, hdr->addr1));
 		}
 		kfree_skb(skb);
 		return NULL;
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 9090052..6bbdb76 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -94,6 +94,7 @@
 static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta)
 {
 	struct sta_info *s;
+	DECLARE_MAC_BUF(mac);
 
 	s = ap->sta_hash[STA_HASH(sta->addr)];
 	if (s == NULL) return;
@@ -108,18 +109,20 @@
 	if (s->hnext != NULL)
 		s->hnext = s->hnext->hnext;
 	else
-		printk("AP: could not remove STA " MACSTR " from hash table\n",
-		       MAC2STR(sta->addr));
+		printk("AP: could not remove STA %s"
+		       " from hash table\n",
+		       print_mac(mac, sta->addr));
 }
 
 static void ap_free_sta(struct ap_data *ap, struct sta_info *sta)
 {
+	DECLARE_MAC_BUF(mac);
 	if (sta->ap && sta->local)
 		hostap_event_expired_sta(sta->local->dev, sta);
 
 	if (ap->proc != NULL) {
 		char name[20];
-		sprintf(name, MACSTR, MAC2STR(sta->addr));
+		sprintf(name, "%s", print_mac(mac, sta->addr));
 		remove_proc_entry(name, ap->proc);
 	}
 
@@ -182,6 +185,7 @@
 	struct ap_data *ap;
 	unsigned long next_time = 0;
 	int was_assoc;
+	DECLARE_MAC_BUF(mac);
 
 	if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) {
 		PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n");
@@ -238,8 +242,8 @@
 	if (sta->ap) {
 		if (ap->autom_ap_wds) {
 			PDEBUG(DEBUG_AP, "%s: removing automatic WDS "
-			       "connection to AP " MACSTR "\n",
-			       local->dev->name, MAC2STR(sta->addr));
+			       "connection to AP %s\n",
+			       local->dev->name, print_mac(mac, sta->addr));
 			hostap_wds_link_oper(local, sta->addr, WDS_DEL);
 		}
 	} else if (sta->timeout_next == STA_NULLFUNC) {
@@ -255,11 +259,11 @@
 	} else {
 		int deauth = sta->timeout_next == STA_DEAUTH;
 		u16 resp;
-		PDEBUG(DEBUG_AP, "%s: sending %s info to STA " MACSTR
+		PDEBUG(DEBUG_AP, "%s: sending %s info to STA %s"
 		       "(last=%lu, jiffies=%lu)\n",
 		       local->dev->name,
 		       deauth ? "deauthentication" : "disassociation",
-		       MAC2STR(sta->addr), sta->last_rx, jiffies);
+		       print_mac(mac, sta->addr), sta->last_rx, jiffies);
 
 		resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID :
 				   WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
@@ -271,9 +275,10 @@
 
 	if (sta->timeout_next == STA_DEAUTH) {
 		if (sta->flags & WLAN_STA_PERM) {
-			PDEBUG(DEBUG_AP, "%s: STA " MACSTR " would have been "
-			       "removed, but it has 'perm' flag\n",
-			       local->dev->name, MAC2STR(sta->addr));
+			PDEBUG(DEBUG_AP, "%s: STA %s"
+			       " would have been removed, "
+			       "but it has 'perm' flag\n",
+			       local->dev->name, print_mac(mac, sta->addr));
 		} else
 			ap_free_sta(ap, sta);
 		return;
@@ -327,6 +332,7 @@
 	struct ap_data *ap = (struct ap_data *) data;
 	char *policy_txt;
 	struct mac_entry *entry;
+	DECLARE_MAC_BUF(mac);
 
 	if (off != 0) {
 		*eof = 1;
@@ -357,7 +363,7 @@
 			break;
 		}
 
-		p += sprintf(p, MACSTR "\n", MAC2STR(entry->addr));
+		p += sprintf(p, "%s\n", print_mac(mac, entry->addr));
 	}
 	spin_unlock_bh(&ap->mac_restrictions.lock);
 
@@ -514,6 +520,7 @@
 	struct ap_data *ap = (struct ap_data *) data;
 	struct sta_info *sta;
 	int i;
+	DECLARE_MAC_BUF(mac);
 
 	if (off > PROC_LIMIT) {
 		*eof = 1;
@@ -526,7 +533,8 @@
 		if (!sta->ap)
 			continue;
 
-		p += sprintf(p, MACSTR " %d %d %d %d '", MAC2STR(sta->addr),
+		p += sprintf(p, "%s %d %d %d %d '",
+			     print_mac(mac, sta->addr),
 			     sta->u.ap.channel, sta->last_rx_signal,
 			     sta->last_rx_silence, sta->last_rx_rate);
 		for (i = 0; i < sta->u.ap.ssid_len; i++)
@@ -623,6 +631,7 @@
 	u16 fc, *pos, auth_alg, auth_transaction, status;
 	struct sta_info *sta = NULL;
 	char *txt = NULL;
+	DECLARE_MAC_BUF(mac);
 
 	if (ap->local->hostapd) {
 		dev_kfree_skb(skb);
@@ -674,9 +683,9 @@
 	if (sta)
 		atomic_dec(&sta->users);
 	if (txt) {
-		PDEBUG(DEBUG_AP, "%s: " MACSTR " auth_cb - alg=%d trans#=%d "
-		       "status=%d - %s\n",
-		       dev->name, MAC2STR(hdr->addr1), auth_alg,
+		PDEBUG(DEBUG_AP, "%s: %s auth_cb - alg=%d "
+		       "trans#=%d status=%d - %s\n",
+		       dev->name, print_mac(mac, hdr->addr1), auth_alg,
 		       auth_transaction, status, txt);
 	}
 	dev_kfree_skb(skb);
@@ -692,6 +701,7 @@
 	u16 fc, *pos, status;
 	struct sta_info *sta = NULL;
 	char *txt = NULL;
+	DECLARE_MAC_BUF(mac);
 
 	if (ap->local->hostapd) {
 		dev_kfree_skb(skb);
@@ -742,8 +752,8 @@
 	if (sta)
 		atomic_dec(&sta->users);
 	if (txt) {
-		PDEBUG(DEBUG_AP, "%s: " MACSTR " assoc_cb - %s\n",
-		       dev->name, MAC2STR(hdr->addr1), txt);
+		PDEBUG(DEBUG_AP, "%s: %s assoc_cb - %s\n",
+		       dev->name, print_mac(mac, hdr->addr1), txt);
 	}
 	dev_kfree_skb(skb);
 }
@@ -755,6 +765,7 @@
 	struct ap_data *ap = data;
 	struct ieee80211_hdr_4addr *hdr;
 	struct sta_info *sta;
+	DECLARE_MAC_BUF(mac);
 
 	if (skb->len < 24)
 		goto fail;
@@ -766,9 +777,9 @@
 			sta->flags &= ~WLAN_STA_PENDING_POLL;
 		spin_unlock(&ap->sta_table_lock);
 	} else {
-		PDEBUG(DEBUG_AP, "%s: STA " MACSTR " did not ACK activity "
-		       "poll frame\n", ap->local->dev->name,
-		       MAC2STR(hdr->addr1));
+		PDEBUG(DEBUG_AP, "%s: STA %s"
+		       " did not ACK activity poll frame\n",
+		       ap->local->dev->name, print_mac(mac, hdr->addr1));
 	}
 
  fail:
@@ -985,6 +996,7 @@
 	char *p = page;
 	struct sta_info *sta = (struct sta_info *) data;
 	int i;
+	DECLARE_MAC_BUF(mac);
 
 	/* FIX: possible race condition.. the STA data could have just expired,
 	 * but proc entry was still here so that the read could have started;
@@ -995,11 +1007,11 @@
 		return 0;
 	}
 
-	p += sprintf(p, "%s=" MACSTR "\nusers=%d\naid=%d\n"
+	p += sprintf(p, "%s=%s\nusers=%d\naid=%d\n"
 		     "flags=0x%04x%s%s%s%s%s%s%s\n"
 		     "capability=0x%02x\nlisten_interval=%d\nsupported_rates=",
 		     sta->ap ? "AP" : "STA",
-		     MAC2STR(sta->addr), atomic_read(&sta->users), sta->aid,
+		     print_mac(mac, sta->addr), atomic_read(&sta->users), sta->aid,
 		     sta->flags,
 		     sta->flags & WLAN_STA_AUTH ? " AUTH" : "",
 		     sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "",
@@ -1060,6 +1072,7 @@
 	struct sta_info *sta;
 	char name[20];
 	struct add_sta_proc_data *entry, *prev;
+	DECLARE_MAC_BUF(mac);
 
 	entry = ap->add_sta_proc_entries;
 	ap->add_sta_proc_entries = NULL;
@@ -1072,7 +1085,7 @@
 		spin_unlock_bh(&ap->sta_table_lock);
 
 		if (sta) {
-			sprintf(name, MACSTR, MAC2STR(sta->addr));
+			sprintf(name, "%s", print_mac(mac, sta->addr));
 			sta->proc = create_proc_read_entry(
 				name, 0, ap->proc,
 				prism2_sta_proc_read, sta);
@@ -1290,6 +1303,7 @@
 	struct sta_info *sta = NULL;
 	struct ieee80211_crypt_data *crypt;
 	char *txt = "";
+	DECLARE_MAC_BUF(mac);
 
 	len = skb->len - IEEE80211_MGMT_HDR_LEN;
 
@@ -1298,8 +1312,8 @@
 
 	if (len < 6) {
 		PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload "
-		       "(len=%d) from " MACSTR "\n", dev->name, len,
-		       MAC2STR(hdr->addr2));
+		       "(len=%d) from %s\n", dev->name, len,
+		       print_mac(mac, hdr->addr2));
 		return;
 	}
 
@@ -1364,8 +1378,8 @@
 		if (time_after(jiffies, sta->u.ap.last_beacon +
 			       (10 * sta->listen_interval * HZ) / 1024)) {
 			PDEBUG(DEBUG_AP, "%s: no beacons received for a while,"
-			       " assuming AP " MACSTR " is now STA\n",
-			       dev->name, MAC2STR(sta->addr));
+			       " assuming AP %s is now STA\n",
+			       dev->name, print_mac(mac, sta->addr));
 			sta->ap = 0;
 			sta->flags = 0;
 			sta->u.sta.challenge = NULL;
@@ -1480,9 +1494,9 @@
 	}
 
 	if (resp) {
-		PDEBUG(DEBUG_AP, "%s: " MACSTR " auth (alg=%d trans#=%d "
-		       "stat=%d len=%d fc=%04x) ==> %d (%s)\n",
-		       dev->name, MAC2STR(hdr->addr2), auth_alg,
+		PDEBUG(DEBUG_AP, "%s: %s auth (alg=%d "
+		       "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n",
+		       dev->name, print_mac(mac, hdr->addr2), auth_alg,
 		       auth_transaction, status_code, len, fc, resp, txt);
 	}
 }
@@ -1502,13 +1516,14 @@
 	int send_deauth = 0;
 	char *txt = "";
 	u8 prev_ap[ETH_ALEN];
+	DECLARE_MAC_BUF(mac);
 
 	left = len = skb->len - IEEE80211_MGMT_HDR_LEN;
 
 	if (len < (reassoc ? 10 : 4)) {
 		PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload "
-		       "(len=%d, reassoc=%d) from " MACSTR "\n",
-		       dev->name, len, reassoc, MAC2STR(hdr->addr2));
+		       "(len=%d, reassoc=%d) from %s\n",
+		       dev->name, len, reassoc, print_mac(mac, hdr->addr2));
 		return;
 	}
 
@@ -1585,9 +1600,9 @@
 		}
 
 		if (left > 0) {
-			PDEBUG(DEBUG_AP, "%s: assoc from " MACSTR " with extra"
-			       " data (%d bytes) [",
-			       dev->name, MAC2STR(hdr->addr2), left);
+			PDEBUG(DEBUG_AP, "%s: assoc from %s"
+			       " with extra data (%d bytes) [",
+			       dev->name, print_mac(mac, hdr->addr2), left);
 			while (left > 0) {
 				PDEBUG2(DEBUG_AP, "<%02x>", *u);
 				u++; left--;
@@ -1687,10 +1702,10 @@
 	}
 
 #if 0
-	PDEBUG(DEBUG_AP, "%s: " MACSTR " %sassoc (len=%d prev_ap=" MACSTR
-	       ") => %d(%d) (%s)\n",
-	       dev->name, MAC2STR(hdr->addr2), reassoc ? "re" : "", len,
-	       MAC2STR(prev_ap), resp, send_deauth, txt);
+	PDEBUG(DEBUG_AP, "%s: %s %sassoc (len=%d "
+	       "prev_ap=%s) => %d(%d) (%s)\n",
+	       dev->name, print_mac(mac, hdr->addr2), reassoc ? "re" : "", len,
+	       print_mac(mac, prev_ap), resp, send_deauth, txt);
 #endif
 }
 
@@ -1705,6 +1720,7 @@
 	int len;
 	u16 reason_code, *pos;
 	struct sta_info *sta = NULL;
+	DECLARE_MAC_BUF(mac);
 
 	len = skb->len - IEEE80211_MGMT_HDR_LEN;
 
@@ -1716,8 +1732,8 @@
 	pos = (u16 *) body;
 	reason_code = __le16_to_cpu(*pos);
 
-	PDEBUG(DEBUG_AP, "%s: deauthentication: " MACSTR " len=%d, "
-	       "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len,
+	PDEBUG(DEBUG_AP, "%s: deauthentication: %s len=%d, "
+	       "reason_code=%d\n", dev->name, print_mac(mac, hdr->addr2), len,
 	       reason_code);
 
 	spin_lock_bh(&local->ap->sta_table_lock);
@@ -1729,9 +1745,9 @@
 	}
 	spin_unlock_bh(&local->ap->sta_table_lock);
 	if (sta == NULL) {
-		printk("%s: deauthentication from " MACSTR ", "
+		printk("%s: deauthentication from %s, "
 	       "reason_code=%d, but STA not authenticated\n", dev->name,
-		       MAC2STR(hdr->addr2), reason_code);
+		       print_mac(mac, hdr->addr2), reason_code);
 	}
 }
 
@@ -1746,6 +1762,7 @@
 	int len;
 	u16 reason_code, *pos;
 	struct sta_info *sta = NULL;
+	DECLARE_MAC_BUF(mac);
 
 	len = skb->len - IEEE80211_MGMT_HDR_LEN;
 
@@ -1757,8 +1774,8 @@
 	pos = (u16 *) body;
 	reason_code = __le16_to_cpu(*pos);
 
-	PDEBUG(DEBUG_AP, "%s: disassociation: " MACSTR " len=%d, "
-	       "reason_code=%d\n", dev->name, MAC2STR(hdr->addr2), len,
+	PDEBUG(DEBUG_AP, "%s: disassociation: %s len=%d, "
+	       "reason_code=%d\n", dev->name, print_mac(mac, hdr->addr2), len,
 	       reason_code);
 
 	spin_lock_bh(&local->ap->sta_table_lock);
@@ -1770,9 +1787,9 @@
 	}
 	spin_unlock_bh(&local->ap->sta_table_lock);
 	if (sta == NULL) {
-		printk("%s: disassociation from " MACSTR ", "
+		printk("%s: disassociation from %s, "
 		       "reason_code=%d, but STA not authenticated\n",
-		       dev->name, MAC2STR(hdr->addr2), reason_code);
+		       dev->name, print_mac(mac, hdr->addr2), reason_code);
 	}
 }
 
@@ -1862,15 +1879,16 @@
 	struct sta_info *sta;
 	u16 aid;
 	struct sk_buff *skb;
+	DECLARE_MAC_BUF(mac);
 
-	PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MACSTR ", TA=" MACSTR
-	       " PWRMGT=%d\n",
-	       MAC2STR(hdr->addr1), MAC2STR(hdr->addr2),
+	PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%s"
+	       ", TA=%s PWRMGT=%d\n",
+	       print_mac(mac, hdr->addr1), print_mac(mac, hdr->addr2),
 	       !!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM));
 
 	if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
-		PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MACSTR
-		       " not own MAC\n", MAC2STR(hdr->addr1));
+		PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=%s"
+		       " not own MAC\n", print_mac(mac, hdr->addr1));
 		return;
 	}
 
@@ -1948,6 +1966,7 @@
 					  wds_oper_queue);
 	local_info_t *local = ap->local;
 	struct wds_oper_data *entry, *prev;
+	DECLARE_MAC_BUF(mac);
 
 	spin_lock_bh(&local->lock);
 	entry = local->ap->wds_oper_entries;
@@ -1956,10 +1975,10 @@
 
 	while (entry) {
 		PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection "
-		       "to AP " MACSTR "\n",
+		       "to AP %s\n",
 		       local->dev->name,
 		       entry->type == WDS_ADD ? "adding" : "removing",
-		       MAC2STR(entry->addr));
+		       print_mac(mac, entry->addr));
 		if (entry->type == WDS_ADD)
 			prism2_wds_add(local, entry->addr, 0);
 		else if (entry->type == WDS_DEL)
@@ -2135,6 +2154,7 @@
 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
 	u16 fc, type, stype;
 	struct ieee80211_hdr_4addr *hdr;
+	DECLARE_MAC_BUF(mac);
 
 	/* FIX: should give skb->len to handler functions and check that the
 	 * buffer is long enough */
@@ -2163,8 +2183,8 @@
 
 		if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
 			PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)="
-			       MACSTR " not own MAC\n",
-			       MAC2STR(hdr->addr1));
+			       "%s not own MAC\n",
+			       print_mac(mac, hdr->addr1));
 			goto done;
 		}
 
@@ -2200,14 +2220,14 @@
 	}
 
 	if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
-		PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=" MACSTR
-		       " not own MAC\n", MAC2STR(hdr->addr1));
+		PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=%s"
+		       " not own MAC\n", print_mac(mac, hdr->addr1));
 		goto done;
 	}
 
 	if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) {
-		PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=" MACSTR
-		       " not own MAC\n", MAC2STR(hdr->addr3));
+		PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=%s"
+		       " not own MAC\n", print_mac(mac, hdr->addr3));
 		goto done;
 	}
 
@@ -2288,6 +2308,7 @@
 	struct sk_buff *skb;
 	struct ieee80211_hdr_4addr *hdr;
 	struct hostap_80211_rx_status rx_stats;
+	DECLARE_MAC_BUF(mac);
 
 	if (skb_queue_empty(&sta->tx_buf))
 		return;
@@ -2308,8 +2329,8 @@
 	memcpy(hdr->addr2, sta->addr, ETH_ALEN);
 	hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14));
 
-	PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for "
-	       "STA " MACSTR "\n", local->dev->name, MAC2STR(sta->addr));
+	PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for STA "
+	       "%s\n", local->dev->name, print_mac(mac, sta->addr));
 
 	skb->dev = local->dev;
 
@@ -2636,6 +2657,7 @@
 	int ret = sta->tx_rate;
 	struct hostap_interface *iface;
 	local_info_t *local;
+	DECLARE_MAC_BUF(mac);
 
 	iface = netdev_priv(dev);
 	local = iface->local;
@@ -2663,9 +2685,9 @@
 			case 3: sta->tx_rate = 110; break;
 			default: sta->tx_rate = 0; break;
 			}
-			PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate raised to"
-			       " %d\n", dev->name, MAC2STR(sta->addr),
-			       sta->tx_rate);
+			PDEBUG(DEBUG_AP, "%s: STA %s"
+			       " TX rate raised to %d\n",
+			       dev->name, print_mac(mac, sta->addr), sta->tx_rate);
 		}
 		sta->tx_since_last_failure = 0;
 	}
@@ -2683,6 +2705,7 @@
 	int set_tim, ret;
 	struct ieee80211_hdr_4addr *hdr;
 	struct hostap_skb_tx_data *meta;
+	DECLARE_MAC_BUF(mac);
 
 	meta = (struct hostap_skb_tx_data *) skb->cb;
 	ret = AP_TX_CONTINUE;
@@ -2718,7 +2741,8 @@
 		 * print out any errors here. */
 		if (net_ratelimit()) {
 			printk(KERN_DEBUG "AP: drop packet to non-associated "
-			       "STA " MACSTR "\n", MAC2STR(hdr->addr1));
+			       "STA %s\n",
+			       print_mac(mac, hdr->addr1));
 		}
 #endif
 		local->ap->tx_drop_nonassoc++;
@@ -2756,8 +2780,9 @@
 	}
 
 	if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) {
-		PDEBUG(DEBUG_PS, "%s: No more space in STA (" MACSTR ")'s PS "
-		       "mode buffer\n", local->dev->name, MAC2STR(sta->addr));
+		PDEBUG(DEBUG_PS, "%s: No more space in STA (%s"
+		       ")'s PS mode buffer\n",
+		       local->dev->name, print_mac(mac, sta->addr));
 		/* Make sure that TIM is set for the station (it might not be
 		 * after AP wlan hw reset). */
 		/* FIX: should fix hw reset to restore bits based on STA
@@ -2821,6 +2846,7 @@
 	struct sta_info *sta;
 	struct ieee80211_hdr_4addr *hdr;
 	struct hostap_skb_tx_data *meta;
+	DECLARE_MAC_BUF(mac);
 
 	hdr = (struct ieee80211_hdr_4addr *) skb->data;
 	meta = (struct hostap_skb_tx_data *) skb->cb;
@@ -2829,9 +2855,9 @@
 	sta = ap_get_sta(local->ap, hdr->addr1);
 	if (!sta) {
 		spin_unlock(&local->ap->sta_table_lock);
-		PDEBUG(DEBUG_AP, "%s: Could not find STA " MACSTR " for this "
-		       "TX error (@%lu)\n",
-		       local->dev->name, MAC2STR(hdr->addr1), jiffies);
+		PDEBUG(DEBUG_AP, "%s: Could not find STA %s"
+		       " for this TX error (@%lu)\n",
+		       local->dev->name, print_mac(mac, hdr->addr1), jiffies);
 		return;
 	}
 
@@ -2858,8 +2884,9 @@
 			case 3: sta->tx_rate = 110; break;
 			default: sta->tx_rate = 0; break;
 			}
-			PDEBUG(DEBUG_AP, "%s: STA " MACSTR " TX rate lowered "
-			       "to %d\n", local->dev->name, MAC2STR(sta->addr),
+			PDEBUG(DEBUG_AP, "%s: STA %s"
+			       " TX rate lowered to %d\n",
+			       local->dev->name, print_mac(mac, sta->addr),
 			       sta->tx_rate);
 		}
 		sta->tx_consecutive_exc = 0;
@@ -2871,16 +2898,17 @@
 static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta,
 				  int pwrmgt, int type, int stype)
 {
+	DECLARE_MAC_BUF(mac);
 	if (pwrmgt && !(sta->flags & WLAN_STA_PS)) {
 		sta->flags |= WLAN_STA_PS;
-		PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to use PS "
+		PDEBUG(DEBUG_PS2, "STA %s changed to use PS "
 		       "mode (type=0x%02X, stype=0x%02X)\n",
-		       MAC2STR(sta->addr), type >> 2, stype >> 4);
+		       print_mac(mac, sta->addr), type >> 2, stype >> 4);
 	} else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) {
 		sta->flags &= ~WLAN_STA_PS;
-		PDEBUG(DEBUG_PS2, "STA " MACSTR " changed to not use "
+		PDEBUG(DEBUG_PS2, "STA %s changed to not use "
 		       "PS mode (type=0x%02X, stype=0x%02X)\n",
-		       MAC2STR(sta->addr), type >> 2, stype >> 4);
+		       print_mac(mac, sta->addr), type >> 2, stype >> 4);
 		if (type != IEEE80211_FTYPE_CTL ||
 		    stype != IEEE80211_STYPE_PSPOLL)
 			schedule_packet_send(local, sta);
@@ -2924,6 +2952,7 @@
 	struct sta_info *sta;
 	u16 fc, type, stype;
 	struct ieee80211_hdr_4addr *hdr;
+	DECLARE_MAC_BUF(mac);
 
 	if (local->ap == NULL)
 		return AP_RX_CONTINUE;
@@ -2954,9 +2983,10 @@
 #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
 			} else {
 				printk(KERN_DEBUG "%s: dropped received packet"
-				       " from non-associated STA " MACSTR
+				       " from non-associated STA "
+				       "%s"
 				       " (type=0x%02x, subtype=0x%02x)\n",
-				       dev->name, MAC2STR(hdr->addr2),
+				       dev->name, print_mac(mac, hdr->addr2),
 				       type >> 2, stype >> 4);
 				hostap_rx(dev, skb, rx_stats);
 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
@@ -2991,8 +3021,8 @@
 			 * being associated. */
 			printk(KERN_DEBUG "%s: rejected received nullfunc "
 			       "frame without ToDS from not associated STA "
-			       MACSTR "\n",
-			       dev->name, MAC2STR(hdr->addr2));
+			       "%s\n",
+			       dev->name, print_mac(mac, hdr->addr2));
 			hostap_rx(dev, skb, rx_stats);
 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
 		}
@@ -3009,9 +3039,9 @@
 		 * If BSSID is own, report the dropping of this frame. */
 		if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) {
 			printk(KERN_DEBUG "%s: dropped received packet from "
-			       MACSTR " with no ToDS flag (type=0x%02x, "
-			       "subtype=0x%02x)\n", dev->name,
-			       MAC2STR(hdr->addr2), type >> 2, stype >> 4);
+			       "%s with no ToDS flag "
+			       "(type=0x%02x, subtype=0x%02x)\n", dev->name,
+			       print_mac(mac, hdr->addr2), type >> 2, stype >> 4);
 			hostap_dump_rx_80211(dev->name, skb, rx_stats);
 		}
 		ret = AP_RX_DROP;
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h
index b31e6a0..ceb7f1e 100644
--- a/drivers/net/wireless/hostap/hostap_common.h
+++ b/drivers/net/wireless/hostap/hostap_common.h
@@ -6,9 +6,6 @@
 
 #define BIT(x) (1 << (x))
 
-#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
-#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
-
 
 /* IEEE 802.11 defines */
 
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 30e723f..877d3bd 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -272,7 +272,7 @@
 {
 	int res, ret = 0;
 	conf_reg_t reg;
-	struct hostap_interface *iface = dev->priv;
+	struct hostap_interface *iface = netdev_priv(dev);
 	local_info_t *local = iface->local;
 	tuple_t tuple;
 	cisparse_t *parse = NULL;
@@ -822,6 +822,7 @@
 	PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777),
 	PCMCIA_DEVICE_MANF_CARD(0x0126, 0x8000),
 	PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
+	PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3301),
 	PCMCIA_DEVICE_MANF_CARD(0x0250, 0x0002),
 	PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030b),
 	PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1612),
@@ -889,6 +890,10 @@
 	PCMCIA_DEVICE_PROD_ID123(
 		"corega", "WL PCCL-11", "ISL37300P",
 		0xa21501a, 0x59868926, 0xc9049a39),
+	PCMCIA_DEVICE_PROD_ID1234(
+		"The Linksys Group, Inc.", "Wireless Network CF Card", "ISL37300P",
+		"RevA",
+		0xa5f472c2, 0x9c05598d, 0xc9049a39, 0x57a66194),
 	PCMCIA_DEVICE_NULL
 };
 MODULE_DEVICE_TABLE(pcmcia, hostap_cs_ids);
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index 959887b..c592641 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -825,7 +825,7 @@
 	    local->hw_downloading)
 		return -ENODEV;
 
-	res = down_interruptible(&local->rid_bap_sem);
+	res = mutex_lock_interruptible(&local->rid_bap_mtx);
 	if (res)
 		return res;
 
@@ -834,7 +834,7 @@
 		printk(KERN_DEBUG "%s: hfa384x_get_rid: CMDCODE_ACCESS failed "
 		       "(res=%d, rid=%04x, len=%d)\n",
 		       dev->name, res, rid, len);
-		up(&local->rid_bap_sem);
+		mutex_unlock(&local->rid_bap_mtx);
 		return res;
 	}
 
@@ -861,7 +861,7 @@
 		res = hfa384x_from_bap(dev, BAP0, buf, len);
 
 	spin_unlock_bh(&local->baplock);
-	up(&local->rid_bap_sem);
+	mutex_unlock(&local->rid_bap_mtx);
 
 	if (res) {
 		if (res != -ENODATA)
@@ -902,7 +902,7 @@
 	/* RID len in words and +1 for rec.rid */
 	rec.len = cpu_to_le16(len / 2 + len % 2 + 1);
 
-	res = down_interruptible(&local->rid_bap_sem);
+	res = mutex_lock_interruptible(&local->rid_bap_mtx);
 	if (res)
 		return res;
 
@@ -917,12 +917,12 @@
 	if (res) {
 		printk(KERN_DEBUG "%s: hfa384x_set_rid (rid=%04x, len=%d) - "
 		       "failed - res=%d\n", dev->name, rid, len, res);
-		up(&local->rid_bap_sem);
+		mutex_unlock(&local->rid_bap_mtx);
 		return res;
 	}
 
 	res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL);
-	up(&local->rid_bap_sem);
+	mutex_unlock(&local->rid_bap_mtx);
 
 	if (res) {
 		printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE "
@@ -2335,6 +2335,10 @@
 	int show_dump, res;
 	char *payload = NULL;
 	struct hfa384x_tx_frame txdesc;
+	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mac2);
+	DECLARE_MAC_BUF(mac3);
+	DECLARE_MAC_BUF(mac4);
 
 	show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR;
 	local->stats.tx_errors++;
@@ -2400,10 +2404,9 @@
 	       WLAN_FC_GET_STYPE(fc) >> 4,
 	       fc & IEEE80211_FCTL_TODS ? " ToDS" : "",
 	       fc & IEEE80211_FCTL_FROMDS ? " FromDS" : "");
-	PDEBUG(DEBUG_EXTRA, "   A1=" MACSTR " A2=" MACSTR " A3="
-	       MACSTR " A4=" MACSTR "\n",
-	       MAC2STR(txdesc.addr1), MAC2STR(txdesc.addr2),
-	       MAC2STR(txdesc.addr3), MAC2STR(txdesc.addr4));
+	PDEBUG(DEBUG_EXTRA, "   A1=%s A2=%s A3=%s A4=%s\n",
+	       print_mac(mac, txdesc.addr1), print_mac(mac2, txdesc.addr2),
+	       print_mac(mac3, txdesc.addr3), print_mac(mac4, txdesc.addr4));
 }
 
 
@@ -3171,7 +3174,7 @@
 	spin_lock_init(&local->cmdlock);
 	spin_lock_init(&local->baplock);
 	spin_lock_init(&local->lock);
-	init_MUTEX(&local->rid_bap_sem);
+	mutex_init(&local->rid_bap_mtx);
 
 	if (card_idx < 0 || card_idx >= MAX_PARM_DEVICES)
 		card_idx = 0;
@@ -3254,12 +3257,11 @@
 
 	INIT_LIST_HEAD(&local->bss_list);
 
-	hostap_setup_dev(dev, local, 1);
-	local->saved_eth_header_parse = dev->hard_header_parse;
+	hostap_setup_dev(dev, local, HOSTAP_INTERFACE_MASTER);
 
 	dev->hard_start_xmit = hostap_master_start_xmit;
 	dev->type = ARPHRD_IEEE80211;
-	dev->hard_header_parse = hostap_80211_header_parse;
+	dev->header_ops = &hostap_80211_ops;
 
 	rtnl_lock();
 	ret = dev_alloc_name(dev, "wifi%d");
@@ -3424,7 +3426,7 @@
 	struct local_info *local;
 	union iwreq_data wrqu;
 
-	iface = dev->priv;
+	iface = netdev_priv(dev);
 	local = iface->local;
 
 	/* Send disconnect event, e.g., to trigger reassociation after resume
diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c
index b6a02a0..636f4b2 100644
--- a/drivers/net/wireless/hostap/hostap_info.c
+++ b/drivers/net/wireless/hostap/hostap_info.c
@@ -166,6 +166,7 @@
 	struct hfa384x_hostscan_result *selected, *entry;
 	int i;
 	unsigned long flags;
+	DECLARE_MAC_BUF(mac);
 
 	if (local->last_join_time &&
 	    time_before(jiffies, local->last_join_time + 10 * HZ)) {
@@ -198,8 +199,9 @@
 	    local->preferred_ap[2] || local->preferred_ap[3] ||
 	    local->preferred_ap[4] || local->preferred_ap[5]) {
 		/* Try to find preferred AP */
-		PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID " MACSTR "\n",
-		       dev->name, MAC2STR(local->preferred_ap));
+		PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID "
+		       "%s\n",
+		       dev->name, print_mac(mac, local->preferred_ap));
 		for (i = 0; i < local->last_scan_results_count; i++) {
 			entry = &local->last_scan_results[i];
 			if (memcmp(local->preferred_ap, entry->bssid, 6) == 0)
@@ -216,8 +218,9 @@
 	req.channel = selected->chid;
 	spin_unlock_irqrestore(&local->lock, flags);
 
-	PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=" MACSTR " channel=%d\n",
-	       dev->name, MAC2STR(req.bssid), le16_to_cpu(req.channel));
+	PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%s"
+	       " channel=%d\n",
+	       dev->name, print_mac(mac, req.bssid), le16_to_cpu(req.channel));
 	if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
 				 sizeof(req))) {
 		printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name);
@@ -409,6 +412,7 @@
 	int val = local->prev_link_status;
 	int connected;
 	union iwreq_data wrqu;
+	DECLARE_MAC_BUF(mac);
 
 	connected =
 		val == HFA384X_LINKSTATUS_CONNECTED ||
@@ -420,9 +424,10 @@
 		printk(KERN_DEBUG "%s: could not read CURRENTBSSID after "
 		       "LinkStatus event\n", local->dev->name);
 	} else {
-		PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" MACSTR "\n",
+		PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID="
+		       "%s\n",
 		       local->dev->name,
-		       MAC2STR((unsigned char *) local->bssid));
+		       print_mac(mac, (unsigned char *) local->bssid));
 		if (local->wds_type & HOSTAP_WDS_AP_CLIENT)
 			hostap_add_sta(local->ap, local->bssid);
 	}
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index 8c71077..40f516d 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -664,6 +664,7 @@
 	unsigned long flags;
 	int i;
 	struct hfa384x_hostscan_result *entry;
+	DECLARE_MAC_BUF(mac);
 
 	iface = netdev_priv(dev);
 	local = iface->local;
@@ -685,14 +686,14 @@
 
 	if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req,
 				 sizeof(req))) {
-		printk(KERN_DEBUG "%s: JoinRequest " MACSTR
+		printk(KERN_DEBUG "%s: JoinRequest %s"
 		       " failed\n",
-		       dev->name, MAC2STR(local->preferred_ap));
+		       dev->name, print_mac(mac, local->preferred_ap));
 		return -1;
 	}
 
-	printk(KERN_DEBUG "%s: Trying to join BSSID " MACSTR "\n",
-	       dev->name, MAC2STR(local->preferred_ap));
+	printk(KERN_DEBUG "%s: Trying to join BSSID %s\n",
+	       dev->name, print_mac(mac, local->preferred_ap));
 
 	return 0;
 }
@@ -896,11 +897,8 @@
 	if (local->monitor_type == PRISM2_MONITOR_PRISM ||
 	    local->monitor_type == PRISM2_MONITOR_CAPHDR) {
 		dev->type = ARPHRD_IEEE80211_PRISM;
-		dev->hard_header_parse =
-			hostap_80211_prism_header_parse;
 	} else {
 		dev->type = ARPHRD_IEEE80211;
-		dev->hard_header_parse = hostap_80211_header_parse;
 	}
 }
 
@@ -1140,7 +1138,7 @@
 
 	printk(KERN_DEBUG "%s: Disabling monitor mode\n", dev->name);
 	dev->type = ARPHRD_ETHER;
-	dev->hard_header_parse = local->saved_eth_header_parse;
+
 	if (local->func->cmd(dev, HFA384X_CMDCODE_TEST |
 			     (HFA384X_TEST_STOP << 8),
 			     0, NULL, NULL))
@@ -3088,7 +3086,7 @@
 static int prism2_set_genericelement(struct net_device *dev, u8 *elem,
 				     size_t len)
 {
-	struct hostap_interface *iface = dev->priv;
+	struct hostap_interface *iface = netdev_priv(dev);
 	local_info_t *local = iface->local;
 	u8 *buf;
 
@@ -3116,7 +3114,7 @@
 				struct iw_request_info *info,
 				struct iw_param *data, char *extra)
 {
-	struct hostap_interface *iface = dev->priv;
+	struct hostap_interface *iface = netdev_priv(dev);
 	local_info_t *local = iface->local;
 
 	switch (data->flags & IW_AUTH_INDEX) {
@@ -3182,7 +3180,7 @@
 				struct iw_request_info *info,
 				struct iw_param *data, char *extra)
 {
-	struct hostap_interface *iface = dev->priv;
+	struct hostap_interface *iface = netdev_priv(dev);
 	local_info_t *local = iface->local;
 
 	switch (data->flags & IW_AUTH_INDEX) {
@@ -3221,7 +3219,7 @@
 				     struct iw_request_info *info,
 				     struct iw_point *erq, char *extra)
 {
-	struct hostap_interface *iface = dev->priv;
+	struct hostap_interface *iface = netdev_priv(dev);
 	local_info_t *local = iface->local;
 	struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
 	int i, ret = 0;
@@ -3395,7 +3393,7 @@
 				     struct iw_request_info *info,
 				     struct iw_point *erq, char *extra)
 {
-	struct hostap_interface *iface = dev->priv;
+	struct hostap_interface *iface = netdev_priv(dev);
 	local_info_t *local = iface->local;
 	struct ieee80211_crypt_data **crypt;
 	void *sta_ptr;
@@ -3697,8 +3695,10 @@
 					  struct prism2_hostapd_param *param,
 					  int param_len)
 {
-	printk(KERN_DEBUG "%ssta: associated as client with AP " MACSTR "\n",
-	       local->dev->name, MAC2STR(param->sta_addr));
+	DECLARE_MAC_BUF(mac);
+	printk(KERN_DEBUG "%ssta: associated as client with AP "
+	       "%s\n",
+	       local->dev->name, print_mac(mac, param->sta_addr));
 	memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN);
 	return 0;
 }
@@ -3716,7 +3716,7 @@
 				 struct iw_request_info *info,
 				 struct iw_point *data, char *extra)
 {
-	struct hostap_interface *iface = dev->priv;
+	struct hostap_interface *iface = netdev_priv(dev);
 	local_info_t *local = iface->local;
 	int len = local->generic_elem_len - 2;
 
@@ -3755,7 +3755,7 @@
 				struct iw_request_info *info,
 				struct iw_point *data, char *extra)
 {
-	struct hostap_interface *iface = dev->priv;
+	struct hostap_interface *iface = netdev_priv(dev);
 	local_info_t *local = iface->local;
 	struct iw_mlme *mlme = (struct iw_mlme *) extra;
 	u16 reason;
@@ -3976,9 +3976,9 @@
 
 const struct iw_handler_def hostap_iw_handler_def =
 {
-	.num_standard	= sizeof(prism2_handler) / sizeof(iw_handler),
-	.num_private	= sizeof(prism2_private_handler) / sizeof(iw_handler),
-	.num_private_args = sizeof(prism2_priv) / sizeof(struct iw_priv_args),
+	.num_standard	= ARRAY_SIZE(prism2_handler),
+	.num_private	= ARRAY_SIZE(prism2_private_handler),
+	.num_private_args = ARRAY_SIZE(prism2_priv),
 	.standard	= (iw_handler *) prism2_handler,
 	.private	= (iw_handler *) prism2_private_handler,
 	.private_args	= (struct iw_priv_args *) prism2_priv,
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 446de51..17c58e9 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -24,6 +24,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/wireless.h>
 #include <linux/etherdevice.h>
+#include <net/net_namespace.h>
 #include <net/iw_handler.h>
 #include <net/ieee80211.h>
 #include <net/ieee80211_crypt.h>
@@ -72,7 +73,7 @@
 	dev->mem_start = mdev->mem_start;
 	dev->mem_end = mdev->mem_end;
 
-	hostap_setup_dev(dev, local, 0);
+	hostap_setup_dev(dev, local, type);
 	dev->destructor = free_netdev;
 
 	sprintf(dev->name, "%s%s", prefix, name);
@@ -529,6 +530,10 @@
 void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx)
 {
 	u16 status, fc;
+	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mac2);
+	DECLARE_MAC_BUF(mac3);
+	DECLARE_MAC_BUF(mac4);
 
 	status = __le16_to_cpu(rx->status);
 
@@ -547,13 +552,12 @@
 	       fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
 	       fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
 
-	printk(KERN_DEBUG "   A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4="
-	       MACSTR "\n",
-	       MAC2STR(rx->addr1), MAC2STR(rx->addr2), MAC2STR(rx->addr3),
-	       MAC2STR(rx->addr4));
+	printk(KERN_DEBUG "   A1=%s A2=%s A3=%s A4=%s\n",
+	       print_mac(mac, rx->addr1), print_mac(mac2, rx->addr2),
+	       print_mac(mac3, rx->addr3), print_mac(mac4, rx->addr4));
 
-	printk(KERN_DEBUG "   dst=" MACSTR " src=" MACSTR " len=%d\n",
-	       MAC2STR(rx->dst_addr), MAC2STR(rx->src_addr),
+	printk(KERN_DEBUG "   dst=%s src=%s len=%d\n",
+	       print_mac(mac, rx->dst_addr), print_mac(mac2, rx->src_addr),
 	       __be16_to_cpu(rx->len));
 }
 
@@ -561,6 +565,10 @@
 void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx)
 {
 	u16 fc;
+	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mac2);
+	DECLARE_MAC_BUF(mac3);
+	DECLARE_MAC_BUF(mac4);
 
 	printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d "
 	       "tx_control=0x%04x; jiffies=%ld\n",
@@ -576,35 +584,37 @@
 	       fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
 	       fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
 
-	printk(KERN_DEBUG "   A1=" MACSTR " A2=" MACSTR " A3=" MACSTR " A4="
-	       MACSTR "\n",
-	       MAC2STR(tx->addr1), MAC2STR(tx->addr2), MAC2STR(tx->addr3),
-	       MAC2STR(tx->addr4));
+	printk(KERN_DEBUG "   A1=%s A2=%s A3=%s A4=%s\n",
+	       print_mac(mac, tx->addr1), print_mac(mac2, tx->addr2),
+	       print_mac(mac3, tx->addr3), print_mac(mac4, tx->addr4));
 
-	printk(KERN_DEBUG "   dst=" MACSTR " src=" MACSTR " len=%d\n",
-	       MAC2STR(tx->dst_addr), MAC2STR(tx->src_addr),
+	printk(KERN_DEBUG "   dst=%s src=%s len=%d\n",
+	       print_mac(mac, tx->dst_addr), print_mac(mac2, tx->src_addr),
 	       __be16_to_cpu(tx->len));
 }
 
 
-int hostap_80211_header_parse(struct sk_buff *skb, unsigned char *haddr)
+int hostap_80211_header_parse(const struct sk_buff *skb, unsigned char *haddr)
 {
-	memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
-	return ETH_ALEN;
-}
+	struct hostap_interface *iface = netdev_priv(skb->dev);
+	local_info_t *local = iface->local;
 
+	if (local->monitor_type == PRISM2_MONITOR_PRISM ||
+	    local->monitor_type == PRISM2_MONITOR_CAPHDR) {
+		const unsigned char *mac = skb_mac_header(skb);
 
-int hostap_80211_prism_header_parse(struct sk_buff *skb, unsigned char *haddr)
-{
-	const unsigned char *mac = skb_mac_header(skb);
+		if (*(u32 *)mac == LWNG_CAP_DID_BASE) {
+			memcpy(haddr,
+			       mac + sizeof(struct linux_wlan_ng_prism_hdr) + 10,
+			       ETH_ALEN); /* addr2 */
+		} else { /* (*(u32 *)mac == htonl(LWNG_CAPHDR_VERSION)) */
+			memcpy(haddr,
+			       mac + sizeof(struct linux_wlan_ng_cap_hdr) + 10,
+			       ETH_ALEN); /* addr2 */
+		}
+	} else
+		memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */
 
-	if (*(u32 *)mac == LWNG_CAP_DID_BASE) {
-		memcpy(haddr, mac + sizeof(struct linux_wlan_ng_prism_hdr) + 10,
-		       ETH_ALEN); /* addr2 */
-	} else { /* (*(u32 *)mac == htonl(LWNG_CAPHDR_VERSION)) */
-		memcpy(haddr, mac + sizeof(struct linux_wlan_ng_cap_hdr) + 10,
-		       ETH_ALEN); /* addr2 */
-	}
 	return ETH_ALEN;
 }
 
@@ -836,9 +846,18 @@
 	local->func->schedule_reset(local);
 }
 
+const struct header_ops hostap_80211_ops = {
+	.create		= eth_header,
+	.rebuild	= eth_rebuild_header,
+	.cache		= eth_header_cache,
+	.cache_update	= eth_header_cache_update,
+
+	.parse		= hostap_80211_header_parse,
+};
+EXPORT_SYMBOL(hostap_80211_ops);
 
 void hostap_setup_dev(struct net_device *dev, local_info_t *local,
-		      int main_dev)
+		      int type)
 {
 	struct hostap_interface *iface;
 
@@ -858,15 +877,22 @@
 	dev->do_ioctl = hostap_ioctl;
 	dev->open = prism2_open;
 	dev->stop = prism2_close;
-	dev->hard_start_xmit = hostap_data_start_xmit;
 	dev->set_mac_address = prism2_set_mac_address;
 	dev->set_multicast_list = hostap_set_multicast_list;
 	dev->change_mtu = prism2_change_mtu;
 	dev->tx_timeout = prism2_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
 
+	if (type == HOSTAP_INTERFACE_AP) {
+		dev->hard_start_xmit = hostap_mgmt_start_xmit;
+		dev->type = ARPHRD_IEEE80211;
+		dev->header_ops = &hostap_80211_ops;
+	} else {
+		dev->hard_start_xmit = hostap_data_start_xmit;
+	}
+
 	dev->mtu = local->mtu;
-	if (!main_dev) {
+	if (type != HOSTAP_INTERFACE_MASTER) {
 		/* use main radio device queue */
 		dev->tx_queue_len = 0;
 	}
@@ -876,7 +902,6 @@
 	netif_stop_queue(dev);
 }
 
-
 static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked)
 {
 	struct net_device *dev = local->dev;
@@ -892,10 +917,6 @@
 	if (local->apdev == NULL)
 		return -ENOMEM;
 
-	local->apdev->hard_start_xmit = hostap_mgmt_start_xmit;
-	local->apdev->type = ARPHRD_IEEE80211;
-	local->apdev->hard_header_parse = hostap_80211_header_parse;
-
 	return 0;
 }
 
@@ -1093,8 +1114,8 @@
 
 static int __init hostap_init(void)
 {
-	if (proc_net != NULL) {
-		hostap_proc = proc_mkdir("hostap", proc_net);
+	if (init_net.proc_net != NULL) {
+		hostap_proc = proc_mkdir("hostap", init_net.proc_net);
 		if (!hostap_proc)
 			printk(KERN_WARNING "Failed to mkdir "
 			       "/proc/net/hostap\n");
@@ -1109,7 +1130,7 @@
 {
 	if (hostap_proc != NULL) {
 		hostap_proc = NULL;
-		remove_proc_entry("hostap", proc_net);
+		remove_proc_entry("hostap", init_net.proc_net);
 	}
 }
 
diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c
index d1d8ce0..b035360 100644
--- a/drivers/net/wireless/hostap/hostap_proc.c
+++ b/drivers/net/wireless/hostap/hostap_proc.c
@@ -106,6 +106,7 @@
 	local_info_t *local = (local_info_t *) data;
 	struct list_head *ptr;
 	struct hostap_interface *iface;
+	DECLARE_MAC_BUF(mac);
 
 	if (off > PROC_LIMIT) {
 		*eof = 1;
@@ -117,9 +118,9 @@
 		iface = list_entry(ptr, struct hostap_interface, list);
 		if (iface->type != HOSTAP_INTERFACE_WDS)
 			continue;
-		p += sprintf(p, "%s\t" MACSTR "\n",
+		p += sprintf(p, "%s\t%s\n",
 			     iface->dev->name,
-			     MAC2STR(iface->u.wds.remote_addr));
+			     print_mac(mac, iface->u.wds.remote_addr));
 		if ((p - page) > PROC_LIMIT) {
 			printk(KERN_DEBUG "%s: wds proc did not fit\n",
 			       local->dev->name);
@@ -147,6 +148,7 @@
 	struct list_head *ptr;
 	struct hostap_bss_info *bss;
 	int i;
+	DECLARE_MAC_BUF(mac);
 
 	if (off > PROC_LIMIT) {
 		*eof = 1;
@@ -158,8 +160,8 @@
 	spin_lock_bh(&local->lock);
 	list_for_each(ptr, &local->bss_list) {
 		bss = list_entry(ptr, struct hostap_bss_info, list);
-		p += sprintf(p, MACSTR "\t%lu\t%u\t0x%x\t",
-			     MAC2STR(bss->bssid), bss->last_update,
+		p += sprintf(p, "%s\t%lu\t%u\t0x%x\t",
+			     print_mac(mac, bss->bssid), bss->last_update,
 			     bss->count, bss->capab_info);
 		for (i = 0; i < bss->ssid_len; i++) {
 			p += sprintf(p, "%c",
@@ -312,6 +314,7 @@
 	int entry, i, len, total = 0;
 	struct hfa384x_hostscan_result *scanres;
 	u8 *pos;
+	DECLARE_MAC_BUF(mac);
 
 	p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates "
 		     "SSID\n");
@@ -329,14 +332,14 @@
 		if ((p - page) > (PAGE_SIZE - 200))
 			break;
 
-		p += sprintf(p, "%d %d %d %d 0x%02x %d " MACSTR " %d ",
+		p += sprintf(p, "%d %d %d %d 0x%02x %d %s %d ",
 			     le16_to_cpu(scanres->chid),
 			     (s16) le16_to_cpu(scanres->anl),
 			     (s16) le16_to_cpu(scanres->sl),
 			     le16_to_cpu(scanres->beacon_interval),
 			     le16_to_cpu(scanres->capability),
 			     le16_to_cpu(scanres->rate),
-			     MAC2STR(scanres->bssid),
+			     print_mac(mac, scanres->bssid),
 			     le16_to_cpu(scanres->atim));
 
 		pos = scanres->sup_rates;
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h
index 87a54aa..c27b2c1 100644
--- a/drivers/net/wireless/hostap/hostap_wlan.h
+++ b/drivers/net/wireless/hostap/hostap_wlan.h
@@ -3,6 +3,7 @@
 
 #include <linux/wireless.h>
 #include <linux/netdevice.h>
+#include <linux/mutex.h>
 #include <net/iw_handler.h>
 
 #include "hostap_config.h"
@@ -641,7 +642,7 @@
 			      * when removing entries from the list.
 			      * TX and RX paths can use read lock. */
 	spinlock_t cmdlock, baplock, lock;
-	struct semaphore rid_bap_sem;
+	struct mutex rid_bap_mtx;
 	u16 infofid; /* MAC buffer id for info frame */
 	/* txfid, intransmitfid, next_txtid, and next_alloc are protected by
 	 * txfidlock */
@@ -735,8 +736,6 @@
 		PRISM2_MONITOR_80211 = 0, PRISM2_MONITOR_PRISM = 1,
 		PRISM2_MONITOR_CAPHDR = 2
 	} monitor_type;
-	int (*saved_eth_header_parse)(struct sk_buff *skb,
-				      unsigned char *haddr);
 	int monitor_allow_fcserr;
 
 	int hostapd; /* whether user space daemon, hostapd, is used for AP
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index 072ede7..2d46a16 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -1922,6 +1922,7 @@
 	u32 chan;
 	char *txratename;
 	u8 bssid[ETH_ALEN];
+	DECLARE_MAC_BUF(mac);
 
 	/*
 	 * TBD: BSSID is usually 00:00:00:00:00:00 here and not
@@ -1983,9 +1984,9 @@
 	}
 
 	IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID="
-		       MAC_FMT ")\n",
+		       "%s)\n",
 		       priv->net_dev->name, escape_essid(essid, essid_len),
-		       txratename, chan, MAC_ARG(bssid));
+		       txratename, chan, print_mac(mac, bssid));
 
 	/* now we copy read ssid into dev */
 	if (!(priv->config & CFG_STATIC_ESSID)) {
@@ -2053,10 +2054,12 @@
 
 static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status)
 {
+	DECLARE_MAC_BUF(mac);
+
 	IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC,
-		  "disassociated: '%s' " MAC_FMT " \n",
+		  "disassociated: '%s' %s \n",
 		  escape_essid(priv->essid, priv->essid_len),
-		  MAC_ARG(priv->bssid));
+		  print_mac(mac, priv->bssid));
 
 	priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
 
@@ -4049,6 +4052,7 @@
 	char *out = buf;
 	int length;
 	int ret;
+	DECLARE_MAC_BUF(mac);
 
 	if (priv->status & STATUS_RF_KILL_MASK)
 		return 0;
@@ -4076,9 +4080,7 @@
 			       __LINE__);
 
 	out += sprintf(out, "ESSID: %s\n", essid);
-	out += sprintf(out, "BSSID:   %02x:%02x:%02x:%02x:%02x:%02x\n",
-		       bssid[0], bssid[1], bssid[2],
-		       bssid[3], bssid[4], bssid[5]);
+	out += sprintf(out, "BSSID:   %s\n", print_mac(mac, bssid));
 	out += sprintf(out, "Channel: %d\n", chan);
 
 	return out - buf;
@@ -4652,19 +4654,20 @@
 static int ipw2100_read_mac_address(struct ipw2100_priv *priv)
 {
 	u32 length = ETH_ALEN;
-	u8 mac[ETH_ALEN];
+	u8 addr[ETH_ALEN];
+	DECLARE_MAC_BUF(mac);
 
 	int err;
 
-	err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, mac, &length);
+	err = ipw2100_get_ordinal(priv, IPW_ORD_STAT_ADAPTER_MAC, addr, &length);
 	if (err) {
 		IPW_DEBUG_INFO("MAC address read failed\n");
 		return -EIO;
 	}
-	IPW_DEBUG_INFO("card MAC is %02X:%02X:%02X:%02X:%02X:%02X\n",
-		       mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
 
-	memcpy(priv->net_dev->dev_addr, mac, ETH_ALEN);
+	memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN);
+	IPW_DEBUG_INFO("card MAC is %s\n",
+		       print_mac(mac, priv->net_dev->dev_addr));
 
 	return 0;
 }
@@ -5043,10 +5046,10 @@
 	int err;
 
 #ifdef CONFIG_IPW2100_DEBUG
+	DECLARE_MAC_BUF(mac);
 	if (bssid != NULL)
-		IPW_DEBUG_HC("MANDATORY_BSSID: %02X:%02X:%02X:%02X:%02X:%02X\n",
-			     bssid[0], bssid[1], bssid[2], bssid[3], bssid[4],
-			     bssid[5]);
+		IPW_DEBUG_HC("MANDATORY_BSSID: %s\n",
+			     print_mac(mac, bssid));
 	else
 		IPW_DEBUG_HC("MANDATORY_BSSID: <clear>\n");
 #endif
@@ -6239,8 +6242,6 @@
 
 	IPW_DEBUG_INFO("Attempting to register device...\n");
 
-	SET_MODULE_OWNER(dev);
-
 	printk(KERN_INFO DRV_NAME
 	       ": Detected Intel PRO/Wireless 2100 Network Connection\n");
 
@@ -6894,6 +6895,7 @@
 	static const unsigned char off[] = {
 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 	};
+	DECLARE_MAC_BUF(mac);
 
 	// sanity checks
 	if (wrqu->ap_addr.sa_family != ARPHRD_ETHER)
@@ -6919,13 +6921,8 @@
 
 	err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0);
 
-	IPW_DEBUG_WX("SET BSSID -> %02X:%02X:%02X:%02X:%02X:%02X\n",
-		     wrqu->ap_addr.sa_data[0] & 0xff,
-		     wrqu->ap_addr.sa_data[1] & 0xff,
-		     wrqu->ap_addr.sa_data[2] & 0xff,
-		     wrqu->ap_addr.sa_data[3] & 0xff,
-		     wrqu->ap_addr.sa_data[4] & 0xff,
-		     wrqu->ap_addr.sa_data[5] & 0xff);
+	IPW_DEBUG_WX("SET BSSID -> %s\n",
+		     print_mac(mac, wrqu->ap_addr.sa_data));
 
       done:
 	mutex_unlock(&priv->action_mutex);
@@ -6941,6 +6938,7 @@
 	 */
 
 	struct ipw2100_priv *priv = ieee80211_priv(dev);
+	DECLARE_MAC_BUF(mac);
 
 	/* If we are associated, trying to associate, or have a statically
 	 * configured BSSID then return that; otherwise return ANY */
@@ -6950,8 +6948,8 @@
 	} else
 		memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
 
-	IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n",
-		     MAC_ARG(wrqu->ap_addr.sa_data));
+	IPW_DEBUG_WX("Getting WAP BSSID: %s\n",
+		     print_mac(mac, wrqu->ap_addr.sa_data));
 	return 0;
 }
 
@@ -7868,10 +7866,10 @@
 		goto done;
 	}
 
-	if ((mode < 1) || (mode > POWER_MODES))
+	if ((mode < 0) || (mode > POWER_MODES))
 		mode = IPW_POWER_AUTO;
 
-	if (priv->power_mode != mode)
+	if (IPW_POWER_LEVEL(priv->power_mode) != mode)
 		err = ipw2100_set_power_mode(priv, mode);
       done:
 	mutex_unlock(&priv->action_mutex);
@@ -7902,7 +7900,7 @@
 			break;
 		case IPW_POWER_AUTO:
 			snprintf(extra, MAX_POWER_STRING,
-				 "Power save level: %d (Auto)", 0);
+				 "Power save level: %d (Auto)", level);
 			break;
 		default:
 			timeout = timeout_duration[level - 1] / 1000;
@@ -8279,10 +8277,9 @@
 
 static struct iw_handler_def ipw2100_wx_handler_def = {
 	.standard = ipw2100_wx_handlers,
-	.num_standard = sizeof(ipw2100_wx_handlers) / sizeof(iw_handler),
-	.num_private = sizeof(ipw2100_private_handler) / sizeof(iw_handler),
-	.num_private_args = sizeof(ipw2100_private_args) /
-	    sizeof(struct iw_priv_args),
+	.num_standard = ARRAY_SIZE(ipw2100_wx_handlers),
+	.num_private = ARRAY_SIZE(ipw2100_private_handler),
+	.num_private_args = ARRAY_SIZE(ipw2100_private_args),
 	.private = (iw_handler *) ipw2100_private_handler,
 	.private_args = (struct iw_priv_args *)ipw2100_private_args,
 	.get_wireless_stats = ipw2100_wx_wireless_stats,
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index aa32a97..feb8fcb 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -70,7 +70,7 @@
 #define VQ
 #endif
 
-#define IPW2200_VERSION "1.2.0" VK VD VM VP VR VQ
+#define IPW2200_VERSION "1.2.2" VK VD VM VP VR VQ
 #define DRV_DESCRIPTION	"Intel(R) PRO/Wireless 2200/2915 Network Driver"
 #define DRV_COPYRIGHT	"Copyright(c) 2003-2006 Intel Corporation"
 #define DRV_VERSION     IPW2200_VERSION
@@ -1740,8 +1740,10 @@
 	if (disable_radio) {
 		priv->status |= STATUS_RF_KILL_SW;
 
-		if (priv->workqueue)
+		if (priv->workqueue) {
 			cancel_delayed_work(&priv->request_scan);
+			cancel_delayed_work(&priv->scan_event);
+		}
 		queue_work(priv->workqueue, &priv->down);
 	} else {
 		priv->status &= ~STATUS_RF_KILL_SW;
@@ -1992,6 +1994,7 @@
 		wake_up_interruptible(&priv->wait_command_queue);
 		priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING);
 		cancel_delayed_work(&priv->request_scan);
+		cancel_delayed_work(&priv->scan_event);
 		schedule_work(&priv->link_down);
 		queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ);
 		handled |= IPW_INTA_BIT_RF_KILL_DONE;
@@ -2247,8 +2250,8 @@
 		return -1;
 	}
 
-	IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n",
-		       priv->net_dev->name, MAC_ARG(mac));
+	IPW_DEBUG_INFO("%s: Setting MAC to %s\n",
+		       priv->net_dev->name, print_mac(mac, mac));
 
 	return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac);
 }
@@ -2506,7 +2509,7 @@
 		break;
 	}
 
-	param = cpu_to_le32(mode);
+	param = cpu_to_le32(param);
 	return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param),
 				&param);
 }
@@ -3796,6 +3799,7 @@
 {
 	struct ipw_station_entry entry;
 	int i;
+	DECLARE_MAC_BUF(mac);
 
 	for (i = 0; i < priv->num_stations; i++) {
 		if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) {
@@ -3812,7 +3816,7 @@
 	if (i == MAX_STATIONS)
 		return IPW_INVALID_STATION;
 
-	IPW_DEBUG_SCAN("Adding AdHoc station: " MAC_FMT "\n", MAC_ARG(bssid));
+	IPW_DEBUG_SCAN("Adding AdHoc station: %s\n", print_mac(mac, bssid));
 
 	entry.reserved = 0;
 	entry.support_mode = 0;
@@ -3839,6 +3843,7 @@
 static void ipw_send_disassociate(struct ipw_priv *priv, int quiet)
 {
 	int err;
+	DECLARE_MAC_BUF(mac);
 
 	if (priv->status & STATUS_ASSOCIATING) {
 		IPW_DEBUG_ASSOC("Disassociating while associating.\n");
@@ -3851,9 +3856,9 @@
 		return;
 	}
 
-	IPW_DEBUG_ASSOC("Disassocation attempt from " MAC_FMT " "
+	IPW_DEBUG_ASSOC("Disassocation attempt from %s "
 			"on channel %d.\n",
-			MAC_ARG(priv->assoc_request.bssid),
+			print_mac(mac, priv->assoc_request.bssid),
 			priv->assoc_request.channel);
 
 	priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED);
@@ -4341,6 +4346,37 @@
 	IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count);
 }
 
+static void ipw_scan_event(struct work_struct *work)
+{
+	union iwreq_data wrqu;
+
+	struct ipw_priv *priv =
+		container_of(work, struct ipw_priv, scan_event.work);
+
+	wrqu.data.length = 0;
+	wrqu.data.flags = 0;
+	wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
+}
+
+static void handle_scan_event(struct ipw_priv *priv)
+{
+	/* Only userspace-requested scan completion events go out immediately */
+	if (!priv->user_requested_scan) {
+		if (!delayed_work_pending(&priv->scan_event))
+			queue_delayed_work(priv->workqueue, &priv->scan_event,
+					 round_jiffies(msecs_to_jiffies(4000)));
+	} else {
+		union iwreq_data wrqu;
+
+		priv->user_requested_scan = 0;
+		cancel_delayed_work(&priv->scan_event);
+
+		wrqu.data.length = 0;
+		wrqu.data.flags = 0;
+		wireless_send_event(priv->net_dev, SIOCGIWSCAN, &wrqu, NULL);
+	}
+}
+
 /**
  * Handle host notification packet.
  * Called from interrupt routine
@@ -4348,6 +4384,7 @@
 static void ipw_rx_notification(struct ipw_priv *priv,
 				       struct ipw_rx_notification *notif)
 {
+	DECLARE_MAC_BUF(mac);
 	notif->size = le16_to_cpu(notif->size);
 
 	IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, notif->size);
@@ -4360,11 +4397,11 @@
 			case CMAS_ASSOCIATED:{
 					IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
 						  IPW_DL_ASSOC,
-						  "associated: '%s' " MAC_FMT
+						  "associated: '%s' %s"
 						  " \n",
 						  escape_essid(priv->essid,
 							       priv->essid_len),
-						  MAC_ARG(priv->bssid));
+						  print_mac(mac, priv->bssid));
 
 					switch (priv->ieee->iw_mode) {
 					case IW_MODE_INFRA:
@@ -4444,13 +4481,13 @@
 							  IPW_DL_STATE |
 							  IPW_DL_ASSOC,
 							  "deauthenticated: '%s' "
-							  MAC_FMT
+							  "%s"
 							  ": (0x%04X) - %s \n",
 							  escape_essid(priv->
 								       essid,
 								       priv->
 								       essid_len),
-							  MAC_ARG(priv->bssid),
+							  print_mac(mac, priv->bssid),
 							  ntohs(auth->status),
 							  ipw_get_status_code
 							  (ntohs
@@ -4467,11 +4504,11 @@
 
 					IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
 						  IPW_DL_ASSOC,
-						  "authenticated: '%s' " MAC_FMT
+						  "authenticated: '%s' %s"
 						  "\n",
 						  escape_essid(priv->essid,
 							       priv->essid_len),
-						  MAC_ARG(priv->bssid));
+						  print_mac(mac, priv->bssid));
 					break;
 				}
 
@@ -4496,11 +4533,11 @@
 
 					IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
 						  IPW_DL_ASSOC,
-						  "disassociated: '%s' " MAC_FMT
+						  "disassociated: '%s' %s"
 						  " \n",
 						  escape_essid(priv->essid,
 							       priv->essid_len),
-						  MAC_ARG(priv->bssid));
+						  print_mac(mac, priv->bssid));
 
 					priv->status &=
 					    ~(STATUS_DISASSOCIATING |
@@ -4535,10 +4572,10 @@
 			switch (auth->state) {
 			case CMAS_AUTHENTICATED:
 				IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE,
-					  "authenticated: '%s' " MAC_FMT " \n",
+					  "authenticated: '%s' %s \n",
 					  escape_essid(priv->essid,
 						       priv->essid_len),
-					  MAC_ARG(priv->bssid));
+					  print_mac(mac, priv->bssid));
 				priv->status |= STATUS_AUTH;
 				break;
 
@@ -4554,10 +4591,10 @@
 				}
 				IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE |
 					  IPW_DL_ASSOC,
-					  "deauthenticated: '%s' " MAC_FMT "\n",
+					  "deauthenticated: '%s' %s\n",
 					  escape_essid(priv->essid,
 						       priv->essid_len),
-					  MAC_ARG(priv->bssid));
+					  print_mac(mac, priv->bssid));
 
 				priv->status &= ~(STATUS_ASSOCIATING |
 						  STATUS_AUTH |
@@ -4702,14 +4739,8 @@
 			 * on how the scan was initiated. User space can just
 			 * sync on periodic scan to get fresh data...
 			 * Jean II */
-			if (x->status == SCAN_COMPLETED_STATUS_COMPLETE) {
-				union iwreq_data wrqu;
-
-				wrqu.data.length = 0;
-				wrqu.data.flags = 0;
-				wireless_send_event(priv->net_dev, SIOCGIWSCAN,
-						    &wrqu, NULL);
-			}
+			if (x->status == SCAN_COMPLETED_STATUS_COMPLETE)
+				handle_scan_event(priv);
 			break;
 		}
 
@@ -5383,25 +5414,27 @@
 				  int roaming)
 {
 	struct ipw_supported_rates rates;
+	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mac2);
 
 	/* Verify that this network's capability is compatible with the
 	 * current mode (AdHoc or Infrastructure) */
 	if ((priv->ieee->iw_mode == IW_MODE_ADHOC &&
 	     !(network->capability & WLAN_CAPABILITY_IBSS))) {
-		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded due to "
+		IPW_DEBUG_MERGE("Network '%s (%s)' excluded due to "
 				"capability mismatch.\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid));
+				print_mac(mac, network->bssid));
 		return 0;
 	}
 
 	/* If we do not have an ESSID for this AP, we can not associate with
 	 * it */
 	if (network->flags & NETWORK_EMPTY_ESSID) {
-		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+		IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
 				"because of hidden ESSID.\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid));
+				print_mac(mac, network->bssid));
 		return 0;
 	}
 
@@ -5411,11 +5444,11 @@
 		if ((network->ssid_len != match->network->ssid_len) ||
 		    memcmp(network->ssid, match->network->ssid,
 			   network->ssid_len)) {
-			IPW_DEBUG_MERGE("Netowrk '%s (" MAC_FMT ")' excluded "
+			IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
 					"because of non-network ESSID.\n",
 					escape_essid(network->ssid,
 						     network->ssid_len),
-					MAC_ARG(network->bssid));
+					print_mac(mac, network->bssid));
 			return 0;
 		}
 	} else {
@@ -5430,9 +5463,9 @@
 			strncpy(escaped,
 				escape_essid(network->ssid, network->ssid_len),
 				sizeof(escaped));
-			IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+			IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
 					"because of ESSID mismatch: '%s'.\n",
-					escaped, MAC_ARG(network->bssid),
+					escaped, print_mac(mac, network->bssid),
 					escape_essid(priv->essid,
 						     priv->essid_len));
 			return 0;
@@ -5459,10 +5492,10 @@
 	/* Now go through and see if the requested network is valid... */
 	if (priv->ieee->scan_age != 0 &&
 	    time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
-		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+		IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
 				"because of age: %ums.\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid),
+				print_mac(mac, network->bssid),
 				jiffies_to_msecs(jiffies -
 						 network->last_scanned));
 		return 0;
@@ -5470,10 +5503,10 @@
 
 	if ((priv->config & CFG_STATIC_CHANNEL) &&
 	    (network->channel != priv->channel)) {
-		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+		IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
 				"because of channel mismatch: %d != %d.\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid),
+				print_mac(mac, network->bssid),
 				network->channel, priv->channel);
 		return 0;
 	}
@@ -5481,10 +5514,10 @@
 	/* Verify privacy compatability */
 	if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
 	    ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
-		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+		IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
 				"because of privacy mismatch: %s != %s.\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid),
+				print_mac(mac, network->bssid),
 				priv->
 				capability & CAP_PRIVACY_ON ? "on" : "off",
 				network->
@@ -5494,40 +5527,41 @@
 	}
 
 	if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
-		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
-				"because of the same BSSID match: " MAC_FMT
+		IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
+				"because of the same BSSID match: %s"
 				".\n", escape_essid(network->ssid,
 						    network->ssid_len),
-				MAC_ARG(network->bssid), MAC_ARG(priv->bssid));
+				print_mac(mac, network->bssid),
+				print_mac(mac2, priv->bssid));
 		return 0;
 	}
 
 	/* Filter out any incompatible freq / mode combinations */
 	if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) {
-		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+		IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
 				"because of invalid frequency/mode "
 				"combination.\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid));
+				print_mac(mac, network->bssid));
 		return 0;
 	}
 
 	/* Ensure that the rates supported by the driver are compatible with
 	 * this AP, including verification of basic rates (mandatory) */
 	if (!ipw_compatible_rates(priv, network, &rates)) {
-		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+		IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
 				"because configured rate mask excludes "
 				"AP mandatory rate.\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid));
+				print_mac(mac, network->bssid));
 		return 0;
 	}
 
 	if (rates.num_rates == 0) {
-		IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded "
+		IPW_DEBUG_MERGE("Network '%s (%s)' excluded "
 				"because of no compatible rates.\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid));
+				print_mac(mac, network->bssid));
 		return 0;
 	}
 
@@ -5538,9 +5572,9 @@
 	/* Set up 'new' AP to this network */
 	ipw_copy_rates(&match->rates, &rates);
 	match->network = network;
-	IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' is a viable match.\n",
+	IPW_DEBUG_MERGE("Network '%s (%s)' is a viable match.\n",
 			escape_essid(network->ssid, network->ssid_len),
-			MAC_ARG(network->bssid));
+			print_mac(mac, network->bssid));
 
 	return 1;
 }
@@ -5594,6 +5628,7 @@
 			    struct ieee80211_network *network, int roaming)
 {
 	struct ipw_supported_rates rates;
+	DECLARE_MAC_BUF(mac);
 
 	/* Verify that this network's capability is compatible with the
 	 * current mode (AdHoc or Infrastructure) */
@@ -5601,20 +5636,20 @@
 	     !(network->capability & WLAN_CAPABILITY_ESS)) ||
 	    (priv->ieee->iw_mode == IW_MODE_ADHOC &&
 	     !(network->capability & WLAN_CAPABILITY_IBSS))) {
-		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded due to "
+		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded due to "
 				"capability mismatch.\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid));
+				print_mac(mac, network->bssid));
 		return 0;
 	}
 
 	/* If we do not have an ESSID for this AP, we can not associate with
 	 * it */
 	if (network->flags & NETWORK_EMPTY_ESSID) {
-		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
 				"because of hidden ESSID.\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid));
+				print_mac(mac, network->bssid));
 		return 0;
 	}
 
@@ -5624,11 +5659,11 @@
 		if ((network->ssid_len != match->network->ssid_len) ||
 		    memcmp(network->ssid, match->network->ssid,
 			   network->ssid_len)) {
-			IPW_DEBUG_ASSOC("Netowrk '%s (" MAC_FMT ")' excluded "
+			IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
 					"because of non-network ESSID.\n",
 					escape_essid(network->ssid,
 						     network->ssid_len),
-					MAC_ARG(network->bssid));
+					print_mac(mac, network->bssid));
 			return 0;
 		}
 	} else {
@@ -5642,9 +5677,9 @@
 			strncpy(escaped,
 				escape_essid(network->ssid, network->ssid_len),
 				sizeof(escaped));
-			IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+			IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
 					"because of ESSID mismatch: '%s'.\n",
-					escaped, MAC_ARG(network->bssid),
+					escaped, print_mac(mac, network->bssid),
 					escape_essid(priv->essid,
 						     priv->essid_len));
 			return 0;
@@ -5658,12 +5693,12 @@
 		strncpy(escaped,
 			escape_essid(network->ssid, network->ssid_len),
 			sizeof(escaped));
-		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded because "
-				"'%s (" MAC_FMT ")' has a stronger signal.\n",
-				escaped, MAC_ARG(network->bssid),
+		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded because "
+				"'%s (%s)' has a stronger signal.\n",
+				escaped, print_mac(mac, network->bssid),
 				escape_essid(match->network->ssid,
 					     match->network->ssid_len),
-				MAC_ARG(match->network->bssid));
+				print_mac(mac, match->network->bssid));
 		return 0;
 	}
 
@@ -5671,11 +5706,11 @@
 	 * last 3 seconds, do not try and associate again... */
 	if (network->last_associate &&
 	    time_after(network->last_associate + (HZ * 3UL), jiffies)) {
-		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
 				"because of storming (%ums since last "
 				"assoc attempt).\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid),
+				print_mac(mac, network->bssid),
 				jiffies_to_msecs(jiffies -
 						 network->last_associate));
 		return 0;
@@ -5684,10 +5719,10 @@
 	/* Now go through and see if the requested network is valid... */
 	if (priv->ieee->scan_age != 0 &&
 	    time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) {
-		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
 				"because of age: %ums.\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid),
+				print_mac(mac, network->bssid),
 				jiffies_to_msecs(jiffies -
 						 network->last_scanned));
 		return 0;
@@ -5695,10 +5730,10 @@
 
 	if ((priv->config & CFG_STATIC_CHANNEL) &&
 	    (network->channel != priv->channel)) {
-		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
 				"because of channel mismatch: %d != %d.\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid),
+				print_mac(mac, network->bssid),
 				network->channel, priv->channel);
 		return 0;
 	}
@@ -5706,10 +5741,10 @@
 	/* Verify privacy compatability */
 	if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) !=
 	    ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) {
-		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
 				"because of privacy mismatch: %s != %s.\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid),
+				print_mac(mac, network->bssid),
 				priv->capability & CAP_PRIVACY_ON ? "on" :
 				"off",
 				network->capability &
@@ -5719,48 +5754,48 @@
 
 	if ((priv->config & CFG_STATIC_BSSID) &&
 	    memcmp(network->bssid, priv->bssid, ETH_ALEN)) {
-		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
-				"because of BSSID mismatch: " MAC_FMT ".\n",
+		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
+				"because of BSSID mismatch: %s.\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid), MAC_ARG(priv->bssid));
+				print_mac(mac, network->bssid), print_mac(mac, priv->bssid));
 		return 0;
 	}
 
 	/* Filter out any incompatible freq / mode combinations */
 	if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) {
-		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
 				"because of invalid frequency/mode "
 				"combination.\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid));
+				print_mac(mac, network->bssid));
 		return 0;
 	}
 
 	/* Filter out invalid channel in current GEO */
 	if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) {
-		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
 				"because of invalid channel in current GEO\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid));
+				print_mac(mac, network->bssid));
 		return 0;
 	}
 
 	/* Ensure that the rates supported by the driver are compatible with
 	 * this AP, including verification of basic rates (mandatory) */
 	if (!ipw_compatible_rates(priv, network, &rates)) {
-		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
 				"because configured rate mask excludes "
 				"AP mandatory rate.\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid));
+				print_mac(mac, network->bssid));
 		return 0;
 	}
 
 	if (rates.num_rates == 0) {
-		IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded "
+		IPW_DEBUG_ASSOC("Network '%s (%s)' excluded "
 				"because of no compatible rates.\n",
 				escape_essid(network->ssid, network->ssid_len),
-				MAC_ARG(network->bssid));
+				print_mac(mac, network->bssid));
 		return 0;
 	}
 
@@ -5772,9 +5807,9 @@
 	ipw_copy_rates(&match->rates, &rates);
 	match->network = network;
 
-	IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' is a viable match.\n",
+	IPW_DEBUG_ASSOC("Network '%s (%s)' is a viable match.\n",
 			escape_essid(network->ssid, network->ssid_len),
-			MAC_ARG(network->bssid));
+			print_mac(mac, network->bssid));
 
 	return 1;
 }
@@ -6016,6 +6051,7 @@
 
 static void ipw_debug_config(struct ipw_priv *priv)
 {
+	DECLARE_MAC_BUF(mac);
 	IPW_DEBUG_INFO("Scan completed, no valid APs matched "
 		       "[CFG 0x%08X]\n", priv->config);
 	if (priv->config & CFG_STATIC_CHANNEL)
@@ -6028,8 +6064,8 @@
 	else
 		IPW_DEBUG_INFO("ESSID unlocked.\n");
 	if (priv->config & CFG_STATIC_BSSID)
-		IPW_DEBUG_INFO("BSSID locked to " MAC_FMT "\n",
-			       MAC_ARG(priv->bssid));
+		IPW_DEBUG_INFO("BSSID locked to %s\n",
+			       print_mac(mac, priv->bssid));
 	else
 		IPW_DEBUG_INFO("BSSID unlocked.\n");
 	if (priv->capability & CAP_PRIVACY_ON)
@@ -7221,6 +7257,7 @@
 				 struct ipw_supported_rates *rates, int roaming)
 {
 	int err;
+	DECLARE_MAC_BUF(mac);
 
 	if (priv->config & CFG_FIXED_RATE)
 		ipw_set_fixed_rate(priv, network->mode);
@@ -7388,9 +7425,9 @@
 		return err;
 	}
 
-	IPW_DEBUG(IPW_DL_STATE, "associating: '%s' " MAC_FMT " \n",
+	IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %s \n",
 		  escape_essid(priv->essid, priv->essid_len),
-		  MAC_ARG(priv->bssid));
+		  print_mac(mac, priv->bssid));
 
 	return 0;
 }
@@ -8202,6 +8239,9 @@
 	struct ieee80211_hdr_4addr *header;
 	u32 r, w, i;
 	u8 network_packet;
+	DECLARE_MAC_BUF(mac);
+	DECLARE_MAC_BUF(mac2);
+	DECLARE_MAC_BUF(mac3);
 
 	r = ipw_read32(priv, IPW_RX_READ_INDEX);
 	w = ipw_read32(priv, IPW_RX_WRITE_INDEX);
@@ -8328,14 +8368,17 @@
 									 header)))
 					{
 						IPW_DEBUG_DROP("Dropping: "
-							       MAC_FMT ", "
-							       MAC_FMT ", "
-							       MAC_FMT "\n",
-							       MAC_ARG(header->
+							       "%s, "
+							       "%s, "
+							       "%s\n",
+							       print_mac(mac,
+									 header->
 								       addr1),
-							       MAC_ARG(header->
+							       print_mac(mac2,
+									 header->
 								       addr2),
-							       MAC_ARG(header->
+							       print_mac(mac3,
+									 header->
 								       addr3));
 						break;
 					}
@@ -8867,6 +8910,7 @@
 			  union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
+	DECLARE_MAC_BUF(mac);
 
 	static const unsigned char any[] = {
 		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
@@ -8897,8 +8941,8 @@
 		return 0;
 	}
 
-	IPW_DEBUG_WX("Setting mandatory BSSID to " MAC_FMT "\n",
-		     MAC_ARG(wrqu->ap_addr.sa_data));
+	IPW_DEBUG_WX("Setting mandatory BSSID to %s\n",
+		     print_mac(mac, wrqu->ap_addr.sa_data));
 
 	memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN);
 
@@ -8916,6 +8960,8 @@
 			  union iwreq_data *wrqu, char *extra)
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
+	DECLARE_MAC_BUF(mac);
+
 	/* If we are associated, trying to associate, or have a statically
 	 * configured BSSID then return that; otherwise return ANY */
 	mutex_lock(&priv->mutex);
@@ -8926,8 +8972,8 @@
 	} else
 		memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN);
 
-	IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n",
-		     MAC_ARG(wrqu->ap_addr.sa_data));
+	IPW_DEBUG_WX("Getting WAP BSSID: %s\n",
+		     print_mac(mac, wrqu->ap_addr.sa_data));
 	mutex_unlock(&priv->mutex);
 	return 0;
 }
@@ -9472,6 +9518,10 @@
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	struct iw_scan_req *req = (struct iw_scan_req *)extra;
 
+	mutex_lock(&priv->mutex);
+	priv->user_requested_scan = 1;
+	mutex_unlock(&priv->mutex);
+
 	if (wrqu->data.length == sizeof(struct iw_scan_req)) {
 		if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
 			ipw_request_direct_scan(priv, req->essid,
@@ -9568,6 +9618,7 @@
 		priv->power_mode = IPW_POWER_ENABLED | IPW_POWER_BATTERY;
 	else
 		priv->power_mode = IPW_POWER_ENABLED | priv->power_mode;
+
 	err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode));
 	if (err) {
 		IPW_DEBUG_WX("failed setting power mode.\n");
@@ -9604,22 +9655,19 @@
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	int mode = *(int *)extra;
 	int err;
+
 	mutex_lock(&priv->mutex);
-	if ((mode < 1) || (mode > IPW_POWER_LIMIT)) {
+	if ((mode < 1) || (mode > IPW_POWER_LIMIT))
 		mode = IPW_POWER_AC;
-		priv->power_mode = mode;
-	} else {
-		priv->power_mode = IPW_POWER_ENABLED | mode;
-	}
 
-	if (priv->power_mode != mode) {
+	if (IPW_POWER_LEVEL(priv->power_mode) != mode) {
 		err = ipw_send_power_mode(priv, mode);
-
 		if (err) {
 			IPW_DEBUG_WX("failed setting power mode.\n");
 			mutex_unlock(&priv->mutex);
 			return err;
 		}
+		priv->power_mode = IPW_POWER_ENABLED | mode;
 	}
 	mutex_unlock(&priv->mutex);
 	return 0;
@@ -10135,6 +10183,7 @@
 	u8 id, hdr_len, unicast;
 	u16 remaining_bytes;
 	int fc;
+	DECLARE_MAC_BUF(mac);
 
 	hdr_len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
 	switch (priv->ieee->iw_mode) {
@@ -10145,8 +10194,8 @@
 			id = ipw_add_station(priv, hdr->addr1);
 			if (id == IPW_INVALID_STATION) {
 				IPW_WARNING("Attempt to send data to "
-					    "invalid cell: " MAC_FMT "\n",
-					    MAC_ARG(hdr->addr1));
+					    "invalid cell: %s\n",
+					    print_mac(mac, hdr->addr1));
 				goto drop;
 			}
 		}
@@ -10462,13 +10511,15 @@
 {
 	struct ipw_priv *priv = ieee80211_priv(dev);
 	struct sockaddr *addr = p;
+	DECLARE_MAC_BUF(mac);
+
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
 	mutex_lock(&priv->mutex);
 	priv->config |= CFG_CUSTOM_MAC;
 	memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN);
-	printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n",
-	       priv->net_dev->name, MAC_ARG(priv->mac_addr));
+	printk(KERN_INFO "%s: Setting MAC to %s\n",
+	       priv->net_dev->name, print_mac(mac, priv->mac_addr));
 	queue_work(priv->workqueue, &priv->adapter_restart);
 	mutex_unlock(&priv->mutex);
 	return 0;
@@ -10555,7 +10606,7 @@
 	spin_lock(&priv->irq_lock);
 
 	if (!(priv->status & STATUS_INT_ENABLED)) {
-		/* Shared IRQ */
+		/* IRQ is disabled */
 		goto none;
 	}
 
@@ -10649,6 +10700,7 @@
 	}
 
 	cancel_delayed_work(&priv->request_scan);
+	cancel_delayed_work(&priv->scan_event);
 	ipw_reset_stats(priv);
 	/* Ensure the rate is updated immediately */
 	priv->last_rate = ipw_get_current_rate(priv);
@@ -10686,7 +10738,8 @@
 	if (!(priv->status & STATUS_EXIT_PENDING)) {
 		/* Queue up another scan... */
 		queue_delayed_work(priv->workqueue, &priv->request_scan, 0);
-	}
+	} else
+		cancel_delayed_work(&priv->scan_event);
 }
 
 static void ipw_bg_link_down(struct work_struct *work)
@@ -10716,6 +10769,7 @@
 	INIT_WORK(&priv->up, ipw_bg_up);
 	INIT_WORK(&priv->down, ipw_bg_down);
 	INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan);
+	INIT_DELAYED_WORK(&priv->scan_event, ipw_scan_event);
 	INIT_WORK(&priv->request_passive_scan, ipw_request_passive_scan);
 	INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats);
 	INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan);
@@ -11627,7 +11681,6 @@
 		goto out_destroy_workqueue;
 	}
 
-	SET_MODULE_OWNER(net_dev);
 	SET_NETDEV_DEV(net_dev, &pdev->dev);
 
 	mutex_lock(&priv->mutex);
@@ -11748,6 +11801,7 @@
 	cancel_delayed_work(&priv->adhoc_check);
 	cancel_delayed_work(&priv->gather_stats);
 	cancel_delayed_work(&priv->request_scan);
+	cancel_delayed_work(&priv->scan_event);
 	cancel_delayed_work(&priv->rf_kill);
 	cancel_delayed_work(&priv->scan_check);
 	destroy_workqueue(priv->workqueue);
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index 626a240..bec8e37 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -45,7 +45,6 @@
 
 #include <linux/firmware.h>
 #include <linux/wireless.h>
-#include <linux/dma-mapping.h>
 #include <linux/jiffies.h>
 #include <asm/io.h>
 
@@ -1288,6 +1287,8 @@
 
 	struct iw_public_data wireless_data;
 
+	int user_requested_scan;
+
 	struct workqueue_struct *workqueue;
 
 	struct delayed_work adhoc_check;
@@ -1296,6 +1297,7 @@
 	struct work_struct system_config;
 	struct work_struct rx_replenish;
 	struct delayed_work request_scan;
+	struct delayed_work scan_event;
   	struct work_struct request_passive_scan;
 	struct work_struct adapter_restart;
 	struct delayed_work rf_kill;
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
new file mode 100644
index 0000000..25cfc6c
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -0,0 +1,128 @@
+config IWLWIFI
+	bool "Intel Wireless WiFi Link Drivers"
+	depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
+	select FW_LOADER
+	default n
+	---help---
+	  Select to enable drivers based on the iwlwifi project.  This
+	  project provides a common foundation for Intel's wireless
+	  drivers designed to use the mac80211 subsystem.
+
+	  See <file:Documentation/networking/README.iwlwifi> for
+	  information on the capabilities currently enabled in this
+	  driver and for tips for debugging issues and problems.
+
+config IWLWIFI_DEBUG
+	bool "Enable full debugging output in iwlwifi drivers"
+	depends on IWLWIFI
+	default y
+	---help---
+	  This option will enable debug tracing output for the iwlwifi
+	  drivers.
+
+	  This will result in the kernel module being ~100k larger.  You can
+	  control which debug output is sent to the kernel log by setting the
+	  value in
+
+	          /sys/bus/pci/drivers/${DRIVER}/debug_level
+
+	  This entry will only exist if this option is enabled.
+
+	  To set a value, simply echo an 8-byte hex value to the same file:
+
+		  % echo 0x43fff > /sys/bus/pci/drivers/${DRIVER}/debug_level
+
+	  You can find the list of debug mask values in:
+		  drivers/net/wireless/mac80211/iwlwifi/iwl-debug.h
+
+	  If this is your first time using this driver, you should say Y here
+	  as the debug information can assist others in helping you resolve
+	  any problems you may encounter.
+
+config IWLWIFI_SENSITIVITY
+	bool "Enable Sensitivity Calibration in iwlwifi drivers"
+	depends on IWLWIFI
+	default y
+	---help---
+	  This option will enable sensitivity calibration for the iwlwifi
+	  drivers.
+
+config IWLWIFI_SPECTRUM_MEASUREMENT
+	bool "Enable Spectrum Measurement in iwlwifi drivers"
+	depends on IWLWIFI
+	default y
+	---help---
+	  This option will enable spectrum measurement for the iwlwifi drivers.
+
+config IWLWIFI_QOS
+	bool "Enable Wireless QoS in iwlwifi drivers"
+	depends on IWLWIFI
+	default y
+	---help---
+	  This option will enable wireless quality of service (QoS) for the
+	  iwlwifi drivers.
+
+config IWLWIFI_HT
+	bool "Enable 802.11n HT features in iwlwifi drivers"
+	depends on EXPERIMENTAL
+	depends on IWLWIFI && MAC80211_HT
+	default n
+	---help---
+	  This option enables IEEE 802.11n High Throughput features
+	  for the iwlwifi drivers.
+
+config IWL4965
+	tristate "Intel Wireless WiFi 4965AGN"
+	depends on m && IWLWIFI && EXPERIMENTAL
+	default m
+	---help---
+	  Select to build the driver supporting the:
+
+	  Intel Wireless WiFi Link 4965AGN
+
+	  This driver uses the kernel's mac80211 subsystem.
+
+	  See <file:Documentation/networking/README.iwlwifi> for
+	  information on the capabilities currently enabled in this
+	  driver and for tips for debugging any issues or problems.
+
+	  In order to use this driver, you will need a microcode (uCode)
+	  image for it. You can obtain the microcode from:
+
+	          <http://intellinuxwireless.org/>.
+
+	  See the above referenced README.iwlwifi for information on where
+	  to install the microcode images.
+
+	  If you want to compile the driver as a module ( = code which can be
+	  inserted in and remvoed from the running kernel whenever you want),
+	  say M here and read <file:Documentation/modules.txt>.  The module
+	  will be called iwl4965.ko.
+
+config IWL3945
+	tristate "Intel PRO/Wireless 3945ABG/BG Network Connection"
+	depends on m && IWLWIFI && EXPERIMENTAL
+	default m
+	---help---
+	  Select to build the driver supporting the:
+
+	  Intel PRO/Wireless 3945ABG/BG Network Connection
+
+	  This driver uses the kernel's mac80211 subsystem.
+
+	  See <file:Documentation/networking/README.iwlwifi> for
+	  information on the capabilities currently enabled in this
+	  driver and for tips for debugging any issues or problems.
+
+	  In order to use this driver, you will need a microcode (uCode)
+	  image for it. You can obtain the microcode from:
+
+	          <http://intellinuxwireless.org/>.
+
+	  See the above referenced README.iwlwifi for information on where
+	  to install the microcode images.
+
+	  If you want to compile the driver as a module ( = code which can be
+	  inserted in and remvoed from the running kernel whenever you want),
+	  say M here and read <file:Documentation/modules.txt>.  The module
+	  will be called iwl3945.ko.
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
new file mode 100644
index 0000000..3bbd383
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_IWL3945)	+= iwl3945.o
+iwl3945-objs		= iwl3945-base.o iwl-3945.o iwl-3945-rs.o
+
+obj-$(CONFIG_IWL4965)	+= iwl4965.o
+iwl4965-objs		= iwl4965-base.o iwl-4965.o iwl-4965-rs.o
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
new file mode 100644
index 0000000..fb5f064
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -0,0 +1,118 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_3945_hw__
+#define __iwl_3945_hw__
+
+#define IWL_RX_BUF_SIZE 3000
+/* card static random access memory (SRAM) for processor data and instructs */
+#define ALM_RTC_INST_UPPER_BOUND		(0x014000)
+#define ALM_RTC_DATA_UPPER_BOUND		(0x808000)
+
+#define ALM_RTC_INST_SIZE (ALM_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND)
+#define ALM_RTC_DATA_SIZE (ALM_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND)
+
+#define IWL_MAX_BSM_SIZE ALM_RTC_INST_SIZE
+#define IWL_MAX_INST_SIZE ALM_RTC_INST_SIZE
+#define IWL_MAX_DATA_SIZE ALM_RTC_DATA_SIZE
+#define IWL_MAX_NUM_QUEUES	8
+
+static inline int iwl_hw_valid_rtc_data_addr(u32 addr)
+{
+	return (addr >= RTC_DATA_LOWER_BOUND) &&
+	       (addr < ALM_RTC_DATA_UPPER_BOUND);
+}
+
+/* Base physical address of iwl_shared is provided to FH_TSSR_CBB_BASE
+ * and &iwl_shared.rx_read_ptr[0] is provided to FH_RCSR_RPTR_ADDR(0) */
+struct iwl_shared {
+	__le32 tx_base_ptr[8];
+	__le32 rx_read_ptr[3];
+} __attribute__ ((packed));
+
+struct iwl_tfd_frame_data {
+	__le32 addr;
+	__le32 len;
+} __attribute__ ((packed));
+
+struct iwl_tfd_frame {
+	__le32 control_flags;
+	struct iwl_tfd_frame_data pa[4];
+	u8 reserved[28];
+} __attribute__ ((packed));
+
+static inline u8 iwl_hw_get_rate(__le16 rate_n_flags)
+{
+	return le16_to_cpu(rate_n_flags) & 0xFF;
+}
+
+static inline u16 iwl_hw_get_rate_n_flags(__le16 rate_n_flags)
+{
+	return le16_to_cpu(rate_n_flags);
+}
+
+static inline __le16 iwl_hw_set_rate_n_flags(u8 rate, u16 flags)
+{
+	return cpu_to_le16((u16)rate|flags);
+}
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
new file mode 100644
index 0000000..f4aabcf
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -0,0 +1,982 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/wireless.h>
+#include <net/mac80211.h>
+#include <net/ieee80211.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+
+#include <linux/workqueue.h>
+
+#include <net/mac80211.h>
+#include <linux/wireless.h>
+
+#define IWL 3945
+
+#include "../net/mac80211/ieee80211_rate.h"
+
+#include "iwlwifi.h"
+
+#define RS_NAME "iwl-3945-rs"
+
+struct iwl_rate_scale_data {
+	u64 data;
+	s32 success_counter;
+	s32 success_ratio;
+	s32 counter;
+	s32 average_tpt;
+	unsigned long stamp;
+};
+
+struct iwl_rate_scale_priv {
+	spinlock_t lock;
+	s32 *expected_tpt;
+	unsigned long last_partial_flush;
+	unsigned long last_flush;
+	u32 flush_time;
+	u32 last_tx_packets;
+	u32 tx_packets;
+	u8 tgg;
+	u8 flush_pending;
+	u8 start_rate;
+	u8 ibss_sta_added;
+	struct timer_list rate_scale_flush;
+	struct iwl_rate_scale_data win[IWL_RATE_COUNT];
+};
+
+static s32 iwl_expected_tpt_g[IWL_RATE_COUNT] = {
+	0, 0, 76, 104, 130, 168, 191, 202, 7, 13, 35, 58
+};
+
+static s32 iwl_expected_tpt_g_prot[IWL_RATE_COUNT] = {
+	0, 0, 0, 80, 93, 113, 123, 125, 7, 13, 35, 58
+};
+
+static s32 iwl_expected_tpt_a[IWL_RATE_COUNT] = {
+	40, 57, 72, 98, 121, 154, 177, 186, 0, 0, 0, 0
+};
+
+static s32 iwl_expected_tpt_b[IWL_RATE_COUNT] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 7, 13, 35, 58
+};
+
+struct iwl_tpt_entry {
+	s8 min_rssi;
+	u8 index;
+};
+
+static struct iwl_tpt_entry iwl_tpt_table_a[] = {
+	{-60, IWL_RATE_54M_INDEX},
+	{-64, IWL_RATE_48M_INDEX},
+	{-72, IWL_RATE_36M_INDEX},
+	{-80, IWL_RATE_24M_INDEX},
+	{-84, IWL_RATE_18M_INDEX},
+	{-85, IWL_RATE_12M_INDEX},
+	{-87, IWL_RATE_9M_INDEX},
+	{-89, IWL_RATE_6M_INDEX}
+};
+
+static struct iwl_tpt_entry iwl_tpt_table_b[] = {
+	{-86, IWL_RATE_11M_INDEX},
+	{-88, IWL_RATE_5M_INDEX},
+	{-90, IWL_RATE_2M_INDEX},
+	{-92, IWL_RATE_1M_INDEX}
+
+};
+
+static struct iwl_tpt_entry iwl_tpt_table_g[] = {
+	{-60, IWL_RATE_54M_INDEX},
+	{-64, IWL_RATE_48M_INDEX},
+	{-68, IWL_RATE_36M_INDEX},
+	{-80, IWL_RATE_24M_INDEX},
+	{-84, IWL_RATE_18M_INDEX},
+	{-85, IWL_RATE_12M_INDEX},
+	{-86, IWL_RATE_11M_INDEX},
+	{-88, IWL_RATE_5M_INDEX},
+	{-90, IWL_RATE_2M_INDEX},
+	{-92, IWL_RATE_1M_INDEX}
+};
+
+#define IWL_RATE_MAX_WINDOW          62
+#define IWL_RATE_FLUSH        (3*HZ/10)
+#define IWL_RATE_WIN_FLUSH       (HZ/2)
+#define IWL_RATE_HIGH_TH          11520
+#define IWL_RATE_MIN_FAILURE_TH       8
+#define IWL_RATE_MIN_SUCCESS_TH       8
+#define IWL_RATE_DECREASE_TH       1920
+
+static u8 iwl_get_rate_index_by_rssi(s32 rssi, u8 mode)
+{
+	u32 index = 0;
+	u32 table_size = 0;
+	struct iwl_tpt_entry *tpt_table = NULL;
+
+	if ((rssi < IWL_MIN_RSSI_VAL) || (rssi > IWL_MAX_RSSI_VAL))
+		rssi = IWL_MIN_RSSI_VAL;
+
+	switch (mode) {
+	case MODE_IEEE80211G:
+		tpt_table = iwl_tpt_table_g;
+		table_size = ARRAY_SIZE(iwl_tpt_table_g);
+		break;
+
+	case MODE_IEEE80211A:
+		tpt_table = iwl_tpt_table_a;
+		table_size = ARRAY_SIZE(iwl_tpt_table_a);
+		break;
+
+	default:
+	case MODE_IEEE80211B:
+		tpt_table = iwl_tpt_table_b;
+		table_size = ARRAY_SIZE(iwl_tpt_table_b);
+		break;
+	}
+
+	while ((index < table_size) && (rssi < tpt_table[index].min_rssi))
+		index++;
+
+	index = min(index, (table_size - 1));
+
+	return tpt_table[index].index;
+}
+
+static void iwl_clear_window(struct iwl_rate_scale_data *window)
+{
+	window->data = 0;
+	window->success_counter = 0;
+	window->success_ratio = IWL_INVALID_VALUE;
+	window->counter = 0;
+	window->average_tpt = IWL_INVALID_VALUE;
+	window->stamp = 0;
+}
+
+/**
+ * iwl_rate_scale_flush_windows - flush out the rate scale windows
+ *
+ * Returns the number of windows that have gathered data but were
+ * not flushed.  If there were any that were not flushed, then
+ * reschedule the rate flushing routine.
+ */
+static int iwl_rate_scale_flush_windows(struct iwl_rate_scale_priv *rs_priv)
+{
+	int unflushed = 0;
+	int i;
+	unsigned long flags;
+
+	/*
+	 * For each rate, if we have collected data on that rate
+	 * and it has been more than IWL_RATE_WIN_FLUSH
+	 * since we flushed, clear out the gathered statistics
+	 */
+	for (i = 0; i < IWL_RATE_COUNT; i++) {
+		if (!rs_priv->win[i].counter)
+			continue;
+
+		spin_lock_irqsave(&rs_priv->lock, flags);
+		if (time_after(jiffies, rs_priv->win[i].stamp +
+			       IWL_RATE_WIN_FLUSH)) {
+			IWL_DEBUG_RATE("flushing %d samples of rate "
+				       "index %d\n",
+				       rs_priv->win[i].counter, i);
+			iwl_clear_window(&rs_priv->win[i]);
+		} else
+			unflushed++;
+		spin_unlock_irqrestore(&rs_priv->lock, flags);
+	}
+
+	return unflushed;
+}
+
+#define IWL_RATE_FLUSH_MAX              5000	/* msec */
+#define IWL_RATE_FLUSH_MIN              50	/* msec */
+
+static void iwl_bg_rate_scale_flush(unsigned long data)
+{
+	struct iwl_rate_scale_priv *rs_priv = (void *)data;
+	int unflushed = 0;
+	unsigned long flags;
+	u32 packet_count, duration, pps;
+
+	IWL_DEBUG_RATE("enter\n");
+
+	unflushed = iwl_rate_scale_flush_windows(rs_priv);
+
+	spin_lock_irqsave(&rs_priv->lock, flags);
+
+	rs_priv->flush_pending = 0;
+
+	/* Number of packets Rx'd since last time this timer ran */
+	packet_count = (rs_priv->tx_packets - rs_priv->last_tx_packets) + 1;
+
+	rs_priv->last_tx_packets = rs_priv->tx_packets + 1;
+
+	if (unflushed) {
+		duration =
+		    jiffies_to_msecs(jiffies - rs_priv->last_partial_flush);
+/*              duration = jiffies_to_msecs(rs_priv->flush_time); */
+
+		IWL_DEBUG_RATE("Tx'd %d packets in %dms\n",
+			       packet_count, duration);
+
+		/* Determine packets per second */
+		if (duration)
+			pps = (packet_count * 1000) / duration;
+		else
+			pps = 0;
+
+		if (pps) {
+			duration = IWL_RATE_FLUSH_MAX / pps;
+			if (duration < IWL_RATE_FLUSH_MIN)
+				duration = IWL_RATE_FLUSH_MIN;
+		} else
+			duration = IWL_RATE_FLUSH_MAX;
+
+		rs_priv->flush_time = msecs_to_jiffies(duration);
+
+		IWL_DEBUG_RATE("new flush period: %d msec ave %d\n",
+			       duration, packet_count);
+
+		mod_timer(&rs_priv->rate_scale_flush, jiffies +
+			  rs_priv->flush_time);
+
+		rs_priv->last_partial_flush = jiffies;
+	}
+
+	/* If there weren't any unflushed entries, we don't schedule the timer
+	 * to run again */
+
+	rs_priv->last_flush = jiffies;
+
+	spin_unlock_irqrestore(&rs_priv->lock, flags);
+
+	IWL_DEBUG_RATE("leave\n");
+}
+
+/**
+ * iwl_collect_tx_data - Update the success/failure sliding window
+ *
+ * We keep a sliding window of the last 64 packets transmitted
+ * at this rate.  window->data contains the bitmask of successful
+ * packets.
+ */
+static void iwl_collect_tx_data(struct iwl_rate_scale_priv *rs_priv,
+				struct iwl_rate_scale_data *window,
+				int success, int retries)
+{
+	unsigned long flags;
+
+	if (!retries) {
+		IWL_DEBUG_RATE("leave: retries == 0 -- should be at least 1\n");
+		return;
+	}
+
+	while (retries--) {
+		spin_lock_irqsave(&rs_priv->lock, flags);
+
+		/* If we have filled up the window then subtract one from the
+		 * success counter if the high-bit is counting toward
+		 * success */
+		if (window->counter == IWL_RATE_MAX_WINDOW) {
+			if (window->data & (1ULL << (IWL_RATE_MAX_WINDOW - 1)))
+				window->success_counter--;
+		} else
+			window->counter++;
+
+		/* Slide the window to the left one bit */
+		window->data = (window->data << 1);
+
+		/* If this packet was a success then set the low bit high */
+		if (success) {
+			window->success_counter++;
+			window->data |= 1;
+		}
+
+		/* window->counter can't be 0 -- it is either >0 or
+		 * IWL_RATE_MAX_WINDOW */
+		window->success_ratio = 12800 * window->success_counter /
+		    window->counter;
+
+		/* Tag this window as having been updated */
+		window->stamp = jiffies;
+
+		spin_unlock_irqrestore(&rs_priv->lock, flags);
+	}
+}
+
+static void rs_rate_init(void *priv_rate, void *priv_sta,
+			 struct ieee80211_local *local, struct sta_info *sta)
+{
+	int i;
+
+	IWL_DEBUG_RATE("enter\n");
+
+	/* TODO: what is a good starting rate for STA? About middle? Maybe not
+	 * the lowest or the highest rate.. Could consider using RSSI from
+	 * previous packets? Need to have IEEE 802.1X auth succeed immediately
+	 * after assoc.. */
+
+	for (i = IWL_RATE_COUNT - 1; i >= 0; i--) {
+		if (sta->supp_rates & (1 << i)) {
+			sta->txrate = i;
+			break;
+		}
+	}
+
+	sta->last_txrate = sta->txrate;
+
+	IWL_DEBUG_RATE("leave\n");
+}
+
+static void *rs_alloc(struct ieee80211_local *local)
+{
+	return local->hw.priv;
+}
+
+/* rate scale requires free function to be implmented */
+static void rs_free(void *priv)
+{
+	return;
+}
+static void rs_clear(void *priv)
+{
+	return;
+}
+
+
+static void *rs_alloc_sta(void *priv, gfp_t gfp)
+{
+	struct iwl_rate_scale_priv *rs_priv;
+	int i;
+
+	IWL_DEBUG_RATE("enter\n");
+
+	rs_priv = kzalloc(sizeof(struct iwl_rate_scale_priv), gfp);
+	if (!rs_priv) {
+		IWL_DEBUG_RATE("leave: ENOMEM\n");
+		return NULL;
+	}
+
+	spin_lock_init(&rs_priv->lock);
+
+	rs_priv->start_rate = IWL_RATE_INVALID;
+
+	/* default to just 802.11b */
+	rs_priv->expected_tpt = iwl_expected_tpt_b;
+
+	rs_priv->last_partial_flush = jiffies;
+	rs_priv->last_flush = jiffies;
+	rs_priv->flush_time = IWL_RATE_FLUSH;
+	rs_priv->last_tx_packets = 0;
+	rs_priv->ibss_sta_added = 0;
+
+	init_timer(&rs_priv->rate_scale_flush);
+	rs_priv->rate_scale_flush.data = (unsigned long)rs_priv;
+	rs_priv->rate_scale_flush.function = &iwl_bg_rate_scale_flush;
+
+	for (i = 0; i < IWL_RATE_COUNT; i++)
+		iwl_clear_window(&rs_priv->win[i]);
+
+	IWL_DEBUG_RATE("leave\n");
+
+	return rs_priv;
+}
+
+static void rs_free_sta(void *priv, void *priv_sta)
+{
+	struct iwl_rate_scale_priv *rs_priv = priv_sta;
+
+	IWL_DEBUG_RATE("enter\n");
+	del_timer_sync(&rs_priv->rate_scale_flush);
+	kfree(rs_priv);
+	IWL_DEBUG_RATE("leave\n");
+}
+
+/**
+ * rs_tx_status - Update rate control values based on Tx results
+ *
+ * NOTE: Uses iwl_priv->retry_rate for the # of retries attempted by
+ * the hardware for each rate.
+ */
+static void rs_tx_status(void *priv_rate,
+			 struct net_device *dev,
+			 struct sk_buff *skb,
+			 struct ieee80211_tx_status *tx_resp)
+{
+	u8 retries, current_count;
+	int scale_rate_index, first_index, last_index;
+	unsigned long flags;
+	struct sta_info *sta;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct iwl_rate_scale_priv *rs_priv;
+
+	IWL_DEBUG_RATE("enter\n");
+
+	retries = tx_resp->retry_count;
+
+	first_index = tx_resp->control.tx_rate;
+	if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) {
+		IWL_DEBUG_RATE("leave: Rate out of bounds: %0x for %d\n",
+			       tx_resp->control.tx_rate, first_index);
+		return;
+	}
+
+	sta = sta_info_get(local, hdr->addr1);
+	if (!sta || !sta->rate_ctrl_priv) {
+		if (sta)
+			sta_info_put(sta);
+		IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
+		return;
+	}
+
+	rs_priv = (void *)sta->rate_ctrl_priv;
+
+	rs_priv->tx_packets++;
+
+	scale_rate_index = first_index;
+	last_index = first_index;
+
+	/*
+	 * Update the window for each rate.  We determine which rates
+	 * were Tx'd based on the total number of retries vs. the number
+	 * of retries configured for each rate -- currently set to the
+	 * priv value 'retry_rate' vs. rate specific
+	 *
+	 * On exit from this while loop last_index indicates the rate
+	 * at which the frame was finally transmitted (or failed if no
+	 * ACK)
+	 */
+	while (retries > 0) {
+		if (retries < priv->retry_rate) {
+			current_count = retries;
+			last_index = scale_rate_index;
+		} else {
+			current_count = priv->retry_rate;
+			last_index = iwl_get_prev_ieee_rate(scale_rate_index);
+		}
+
+		/* Update this rate accounting for as many retries
+		 * as was used for it (per current_count) */
+		iwl_collect_tx_data(rs_priv,
+				    &rs_priv->win[scale_rate_index],
+				    0, current_count);
+		IWL_DEBUG_RATE("Update rate %d for %d retries.\n",
+			       scale_rate_index, current_count);
+
+		retries -= current_count;
+
+		if (retries)
+			scale_rate_index =
+			    iwl_get_prev_ieee_rate(scale_rate_index);
+	}
+
+	/* Update the last index window with success/failure based on ACK */
+	IWL_DEBUG_RATE("Update rate %d with %s.\n",
+		       last_index,
+		       (tx_resp->flags & IEEE80211_TX_STATUS_ACK) ?
+		       "success" : "failure");
+	iwl_collect_tx_data(rs_priv,
+			    &rs_priv->win[last_index],
+			    tx_resp->flags & IEEE80211_TX_STATUS_ACK, 1);
+
+	/* We updated the rate scale window -- if its been more than
+	 * flush_time since the last run, schedule the flush
+	 * again */
+	spin_lock_irqsave(&rs_priv->lock, flags);
+
+	if (!rs_priv->flush_pending &&
+	    time_after(jiffies, rs_priv->last_partial_flush +
+		       rs_priv->flush_time)) {
+
+		rs_priv->flush_pending = 1;
+		mod_timer(&rs_priv->rate_scale_flush,
+			  jiffies + rs_priv->flush_time);
+	}
+
+	spin_unlock_irqrestore(&rs_priv->lock, flags);
+
+	sta_info_put(sta);
+
+	IWL_DEBUG_RATE("leave\n");
+
+	return;
+}
+
+static struct ieee80211_rate *iwl_get_lowest_rate(struct ieee80211_local
+						  *local)
+{
+	struct ieee80211_hw_mode *mode = local->oper_hw_mode;
+	int i;
+
+	for (i = 0; i < mode->num_rates; i++) {
+		struct ieee80211_rate *rate = &mode->rates[i];
+
+		if (rate->flags & IEEE80211_RATE_SUPPORTED)
+			return rate;
+	}
+
+	return &mode->rates[0];
+}
+
+static u16 iwl_get_adjacent_rate(struct iwl_rate_scale_priv *rs_priv,
+				 u8 index, u16 rate_mask, int phymode)
+{
+	u8 high = IWL_RATE_INVALID;
+	u8 low = IWL_RATE_INVALID;
+
+	/* 802.11A walks to the next literal adjascent rate in
+	 * the rate table */
+	if (unlikely(phymode == MODE_IEEE80211A)) {
+		int i;
+		u32 mask;
+
+		/* Find the previous rate that is in the rate mask */
+		i = index - 1;
+		for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
+			if (rate_mask & mask) {
+				low = i;
+				break;
+			}
+		}
+
+		/* Find the next rate that is in the rate mask */
+		i = index + 1;
+		for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) {
+			if (rate_mask & mask) {
+				high = i;
+				break;
+			}
+		}
+
+		return (high << 8) | low;
+	}
+
+	low = index;
+	while (low != IWL_RATE_INVALID) {
+		if (rs_priv->tgg)
+			low = iwl_rates[low].prev_rs_tgg;
+		else
+			low = iwl_rates[low].prev_rs;
+		if (low == IWL_RATE_INVALID)
+			break;
+		if (rate_mask & (1 << low))
+			break;
+		IWL_DEBUG_RATE("Skipping masked lower rate: %d\n", low);
+	}
+
+	high = index;
+	while (high != IWL_RATE_INVALID) {
+		if (rs_priv->tgg)
+			high = iwl_rates[high].next_rs_tgg;
+		else
+			high = iwl_rates[high].next_rs;
+		if (high == IWL_RATE_INVALID)
+			break;
+		if (rate_mask & (1 << high))
+			break;
+		IWL_DEBUG_RATE("Skipping masked higher rate: %d\n", high);
+	}
+
+	return (high << 8) | low;
+}
+
+/**
+ * rs_get_rate - find the rate for the requested packet
+ *
+ * Returns the ieee80211_rate structure allocated by the driver.
+ *
+ * The rate control algorithm has no internal mapping between hw_mode's
+ * rate ordering and the rate ordering used by the rate control algorithm.
+ *
+ * The rate control algorithm uses a single table of rates that goes across
+ * the entire A/B/G spectrum vs. being limited to just one particular
+ * hw_mode.
+ *
+ * As such, we can't convert the index obtained below into the hw_mode's
+ * rate table and must reference the driver allocated rate table
+ *
+ */
+static struct ieee80211_rate *rs_get_rate(void *priv_rate,
+					  struct net_device *dev,
+					  struct sk_buff *skb,
+					  struct rate_control_extra *extra)
+{
+	u8 low = IWL_RATE_INVALID;
+	u8 high = IWL_RATE_INVALID;
+	u16 high_low;
+	int index;
+	struct iwl_rate_scale_priv *rs_priv;
+	struct iwl_rate_scale_data *window = NULL;
+	int current_tpt = IWL_INVALID_VALUE;
+	int low_tpt = IWL_INVALID_VALUE;
+	int high_tpt = IWL_INVALID_VALUE;
+	u32 fail_count;
+	s8 scale_action = 0;
+	unsigned long flags;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct sta_info *sta;
+	u16 fc, rate_mask;
+	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+	DECLARE_MAC_BUF(mac);
+
+	IWL_DEBUG_RATE("enter\n");
+
+	memset(extra, 0, sizeof(*extra));
+
+	fc = le16_to_cpu(hdr->frame_control);
+	if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
+	    (is_multicast_ether_addr(hdr->addr1))) {
+		/* Send management frames and broadcast/multicast data using
+		 * lowest rate. */
+		/* TODO: this could probably be improved.. */
+		IWL_DEBUG_RATE("leave: lowest rate (not data or is "
+			       "multicast)\n");
+
+		return iwl_get_lowest_rate(local);
+	}
+
+	sta = sta_info_get(local, hdr->addr1);
+	if (!sta || !sta->rate_ctrl_priv) {
+		IWL_DEBUG_RATE("leave: No STA priv data to update!\n");
+		if (sta)
+			sta_info_put(sta);
+		return NULL;
+	}
+
+	rate_mask = sta->supp_rates;
+	index = min(sta->txrate & 0xffff, IWL_RATE_COUNT - 1);
+
+	rs_priv = (void *)sta->rate_ctrl_priv;
+
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+	    !rs_priv->ibss_sta_added) {
+		u8 sta_id = iwl_hw_find_station(priv, hdr->addr1);
+
+		if (sta_id == IWL_INVALID_STATION) {
+			IWL_DEBUG_RATE("LQ: ADD station %s\n",
+				       print_mac(mac, hdr->addr1));
+			sta_id = iwl_add_station(priv,
+				    hdr->addr1, 0, CMD_ASYNC);
+		}
+		if (sta_id != IWL_INVALID_STATION)
+			rs_priv->ibss_sta_added = 1;
+	}
+
+	spin_lock_irqsave(&rs_priv->lock, flags);
+
+	if (rs_priv->start_rate != IWL_RATE_INVALID) {
+		index = rs_priv->start_rate;
+		rs_priv->start_rate = IWL_RATE_INVALID;
+	}
+
+	window = &(rs_priv->win[index]);
+
+	fail_count = window->counter - window->success_counter;
+
+	if (((fail_count <= IWL_RATE_MIN_FAILURE_TH) &&
+	     (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) {
+		window->average_tpt = IWL_INVALID_VALUE;
+		spin_unlock_irqrestore(&rs_priv->lock, flags);
+
+		IWL_DEBUG_RATE("Invalid average_tpt on rate %d: "
+			       "counter: %d, success_counter: %d, "
+			       "expected_tpt is %sNULL\n",
+			       index,
+			       window->counter,
+			       window->success_counter,
+			       rs_priv->expected_tpt ? "not " : "");
+		goto out;
+
+	}
+
+	window->average_tpt = ((window->success_ratio *
+				rs_priv->expected_tpt[index] + 64) / 128);
+	current_tpt = window->average_tpt;
+
+	high_low = iwl_get_adjacent_rate(rs_priv, index, rate_mask,
+					 local->hw.conf.phymode);
+	low = high_low & 0xff;
+	high = (high_low >> 8) & 0xff;
+
+	if (low != IWL_RATE_INVALID)
+		low_tpt = rs_priv->win[low].average_tpt;
+
+	if (high != IWL_RATE_INVALID)
+		high_tpt = rs_priv->win[high].average_tpt;
+
+	spin_unlock_irqrestore(&rs_priv->lock, flags);
+
+	scale_action = 1;
+
+	if ((window->success_ratio < IWL_RATE_DECREASE_TH) || !current_tpt) {
+		IWL_DEBUG_RATE("decrease rate because of low success_ratio\n");
+		scale_action = -1;
+	} else if ((low_tpt == IWL_INVALID_VALUE) &&
+		   (high_tpt == IWL_INVALID_VALUE))
+		scale_action = 1;
+	else if ((low_tpt != IWL_INVALID_VALUE) &&
+		   (high_tpt != IWL_INVALID_VALUE)
+		   && (low_tpt < current_tpt)
+		   && (high_tpt < current_tpt)) {
+		IWL_DEBUG_RATE("No action -- low [%d] & high [%d] < "
+			       "current_tpt [%d]\n",
+			       low_tpt, high_tpt, current_tpt);
+		scale_action = 0;
+	} else {
+		if (high_tpt != IWL_INVALID_VALUE) {
+			if (high_tpt > current_tpt)
+				scale_action = 1;
+			else {
+				IWL_DEBUG_RATE
+				    ("decrease rate because of high tpt\n");
+				scale_action = -1;
+			}
+		} else if (low_tpt != IWL_INVALID_VALUE) {
+			if (low_tpt > current_tpt) {
+				IWL_DEBUG_RATE
+				    ("decrease rate because of low tpt\n");
+				scale_action = -1;
+			} else
+				scale_action = 1;
+		}
+	}
+
+	if ((window->success_ratio > IWL_RATE_HIGH_TH) ||
+	    (current_tpt > window->average_tpt)) {
+		IWL_DEBUG_RATE("No action -- success_ratio [%d] > HIGH_TH or "
+			       "current_tpt [%d] > average_tpt [%d]\n",
+			       window->success_ratio,
+			       current_tpt, window->average_tpt);
+		scale_action = 0;
+	}
+
+	switch (scale_action) {
+	case -1:
+		if (low != IWL_RATE_INVALID)
+			index = low;
+		break;
+
+	case 1:
+		if (high != IWL_RATE_INVALID)
+			index = high;
+
+		break;
+
+	case 0:
+	default:
+		break;
+	}
+
+	IWL_DEBUG_RATE("Selected %d (action %d) - low %d high %d\n",
+		       index, scale_action, low, high);
+
+ out:
+
+	sta->last_txrate = index;
+	sta->txrate = sta->last_txrate;
+	sta_info_put(sta);
+
+	IWL_DEBUG_RATE("leave: %d\n", index);
+
+	return &priv->ieee_rates[index];
+}
+
+static struct rate_control_ops rs_ops = {
+	.module = NULL,
+	.name = RS_NAME,
+	.tx_status = rs_tx_status,
+	.get_rate = rs_get_rate,
+	.rate_init = rs_rate_init,
+	.clear = rs_clear,
+	.alloc = rs_alloc,
+	.free = rs_free,
+	.alloc_sta = rs_alloc_sta,
+	.free_sta = rs_free_sta,
+};
+
+int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct iwl_priv *priv = hw->priv;
+	struct iwl_rate_scale_priv *rs_priv;
+	struct sta_info *sta;
+	unsigned long flags;
+	int count = 0, i;
+	u32 samples = 0, success = 0, good = 0;
+	unsigned long now = jiffies;
+	u32 max_time = 0;
+
+	sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
+	if (!sta || !sta->rate_ctrl_priv) {
+		if (sta) {
+			sta_info_put(sta);
+			IWL_DEBUG_RATE("leave - no private rate data!\n");
+		} else
+			IWL_DEBUG_RATE("leave - no station!\n");
+		return sprintf(buf, "station %d not found\n", sta_id);
+	}
+
+	rs_priv = (void *)sta->rate_ctrl_priv;
+	spin_lock_irqsave(&rs_priv->lock, flags);
+	i = IWL_RATE_54M_INDEX;
+	while (1) {
+		u64 mask;
+		int j;
+
+		count +=
+		    sprintf(&buf[count], " %2dMbs: ", iwl_rates[i].ieee / 2);
+
+		mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
+		for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
+			buf[count++] =
+			    (rs_priv->win[i].data & mask) ? '1' : '0';
+
+		samples += rs_priv->win[i].counter;
+		good += rs_priv->win[i].success_counter;
+		success += rs_priv->win[i].success_counter * iwl_rates[i].ieee;
+
+		if (rs_priv->win[i].stamp) {
+			int delta =
+			    jiffies_to_msecs(now - rs_priv->win[i].stamp);
+
+			if (delta > max_time)
+				max_time = delta;
+
+			count += sprintf(&buf[count], "%5dms\n", delta);
+		} else
+			buf[count++] = '\n';
+
+		j = iwl_get_prev_ieee_rate(i);
+		if (j == i)
+			break;
+		i = j;
+	}
+	spin_unlock_irqrestore(&rs_priv->lock, flags);
+	sta_info_put(sta);
+
+	/* Display the average rate of all samples taken.
+	 *
+	 * NOTE:  We multiple # of samples by 2 since the IEEE measurement
+	 * added from iwl_rates is actually 2X the rate */
+	if (samples)
+		count += sprintf(
+			&buf[count],
+			"\nAverage rate is %3d.%02dMbs over last %4dms\n"
+			"%3d%% success (%d good packets over %d tries)\n",
+			success / (2 * samples), (success * 5 / samples) % 10,
+			max_time, good * 100 / samples, good, samples);
+	else
+		count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n");
+
+	return count;
+}
+
+void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
+{
+	struct iwl_priv *priv = hw->priv;
+	s32 rssi = 0;
+	unsigned long flags;
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct iwl_rate_scale_priv *rs_priv;
+	struct sta_info *sta;
+
+	IWL_DEBUG_RATE("enter\n");
+
+	if (!local->rate_ctrl->ops->name ||
+	    strcmp(local->rate_ctrl->ops->name, RS_NAME)) {
+		IWL_WARNING("iwl-3945-rs not selected as rate control algo!\n");
+		IWL_DEBUG_RATE("leave - mac80211 picked the wrong RC algo.\n");
+		return;
+	}
+
+	sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
+	if (!sta || !sta->rate_ctrl_priv) {
+		if (sta)
+			sta_info_put(sta);
+		IWL_DEBUG_RATE("leave - no private rate data!\n");
+		return;
+	}
+
+	rs_priv = (void *)sta->rate_ctrl_priv;
+
+	spin_lock_irqsave(&rs_priv->lock, flags);
+
+	rs_priv->tgg = 0;
+	switch (priv->phymode) {
+	case MODE_IEEE80211G:
+		if (priv->active_rxon.flags & RXON_FLG_TGG_PROTECT_MSK) {
+			rs_priv->tgg = 1;
+			rs_priv->expected_tpt = iwl_expected_tpt_g_prot;
+		} else
+			rs_priv->expected_tpt = iwl_expected_tpt_g;
+		break;
+
+	case MODE_IEEE80211A:
+		rs_priv->expected_tpt = iwl_expected_tpt_a;
+		break;
+
+	default:
+		IWL_WARNING("Invalid phymode.  Defaulting to 802.11b\n");
+	case MODE_IEEE80211B:
+		rs_priv->expected_tpt = iwl_expected_tpt_b;
+		break;
+	}
+
+	sta_info_put(sta);
+	spin_unlock_irqrestore(&rs_priv->lock, flags);
+
+	rssi = priv->last_rx_rssi;
+	if (rssi == 0)
+		rssi = IWL_MIN_RSSI_VAL;
+
+	IWL_DEBUG(IWL_DL_INFO | IWL_DL_RATE, "Network RSSI: %d\n", rssi);
+
+	rs_priv->start_rate = iwl_get_rate_index_by_rssi(rssi, priv->phymode);
+
+	IWL_DEBUG_RATE("leave: rssi %d assign rate index: "
+		       "%d (plcp 0x%x)\n", rssi, rs_priv->start_rate,
+		       iwl_rates[rs_priv->start_rate].plcp);
+}
+
+void iwl_rate_control_register(struct ieee80211_hw *hw)
+{
+	ieee80211_rate_control_register(&rs_ops);
+}
+
+void iwl_rate_control_unregister(struct ieee80211_hw *hw)
+{
+	ieee80211_rate_control_unregister(&rs_ops);
+}
+
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
new file mode 100644
index 0000000..b926738
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h
@@ -0,0 +1,191 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_3945_rs_h__
+#define __iwl_3945_rs_h__
+
+struct iwl_rate_info {
+	u8 plcp;
+	u8 ieee;
+	u8 prev_ieee;		/* previous rate in IEEE speeds */
+	u8 next_ieee;		/* next rate in IEEE speeds */
+	u8 prev_rs;		/* previous rate used in rs algo */
+	u8 next_rs;		/* next rate used in rs algo */
+	u8 prev_rs_tgg;		/* previous rate used in TGG rs algo */
+	u8 next_rs_tgg;		/* next rate used in TGG rs algo */
+};
+
+enum {
+	IWL_RATE_6M_INDEX = 0,
+	IWL_RATE_9M_INDEX,
+	IWL_RATE_12M_INDEX,
+	IWL_RATE_18M_INDEX,
+	IWL_RATE_24M_INDEX,
+	IWL_RATE_36M_INDEX,
+	IWL_RATE_48M_INDEX,
+	IWL_RATE_54M_INDEX,
+	IWL_RATE_1M_INDEX,
+	IWL_RATE_2M_INDEX,
+	IWL_RATE_5M_INDEX,
+	IWL_RATE_11M_INDEX,
+	IWL_RATE_COUNT,
+	IWL_RATE_INVM_INDEX,
+	IWL_RATE_INVALID = IWL_RATE_INVM_INDEX
+};
+
+enum {
+	IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
+	IWL_LAST_OFDM_RATE = IWL_RATE_54M_INDEX,
+	IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX,
+	IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX,
+};
+
+/* #define vs. enum to keep from defaulting to 'large integer' */
+#define	IWL_RATE_6M_MASK   (1<<IWL_RATE_6M_INDEX)
+#define	IWL_RATE_9M_MASK   (1<<IWL_RATE_9M_INDEX)
+#define	IWL_RATE_12M_MASK  (1<<IWL_RATE_12M_INDEX)
+#define	IWL_RATE_18M_MASK  (1<<IWL_RATE_18M_INDEX)
+#define	IWL_RATE_24M_MASK  (1<<IWL_RATE_24M_INDEX)
+#define	IWL_RATE_36M_MASK  (1<<IWL_RATE_36M_INDEX)
+#define	IWL_RATE_48M_MASK  (1<<IWL_RATE_48M_INDEX)
+#define	IWL_RATE_54M_MASK  (1<<IWL_RATE_54M_INDEX)
+#define	IWL_RATE_1M_MASK   (1<<IWL_RATE_1M_INDEX)
+#define	IWL_RATE_2M_MASK   (1<<IWL_RATE_2M_INDEX)
+#define	IWL_RATE_5M_MASK   (1<<IWL_RATE_5M_INDEX)
+#define	IWL_RATE_11M_MASK  (1<<IWL_RATE_11M_INDEX)
+
+enum {
+	IWL_RATE_6M_PLCP = 13,
+	IWL_RATE_9M_PLCP = 15,
+	IWL_RATE_12M_PLCP = 5,
+	IWL_RATE_18M_PLCP = 7,
+	IWL_RATE_24M_PLCP = 9,
+	IWL_RATE_36M_PLCP = 11,
+	IWL_RATE_48M_PLCP = 1,
+	IWL_RATE_54M_PLCP = 3,
+	IWL_RATE_1M_PLCP = 10,
+	IWL_RATE_2M_PLCP = 20,
+	IWL_RATE_5M_PLCP = 55,
+	IWL_RATE_11M_PLCP = 110,
+};
+
+enum {
+	IWL_RATE_6M_IEEE = 12,
+	IWL_RATE_9M_IEEE = 18,
+	IWL_RATE_12M_IEEE = 24,
+	IWL_RATE_18M_IEEE = 36,
+	IWL_RATE_24M_IEEE = 48,
+	IWL_RATE_36M_IEEE = 72,
+	IWL_RATE_48M_IEEE = 96,
+	IWL_RATE_54M_IEEE = 108,
+	IWL_RATE_1M_IEEE = 2,
+	IWL_RATE_2M_IEEE = 4,
+	IWL_RATE_5M_IEEE = 11,
+	IWL_RATE_11M_IEEE = 22,
+};
+
+#define IWL_CCK_BASIC_RATES_MASK    \
+       (IWL_RATE_1M_MASK          | \
+	IWL_RATE_2M_MASK)
+
+#define IWL_CCK_RATES_MASK          \
+       (IWL_BASIC_RATES_MASK      | \
+	IWL_RATE_5M_MASK          | \
+	IWL_RATE_11M_MASK)
+
+#define IWL_OFDM_BASIC_RATES_MASK   \
+	(IWL_RATE_6M_MASK         | \
+	IWL_RATE_12M_MASK         | \
+	IWL_RATE_24M_MASK)
+
+#define IWL_OFDM_RATES_MASK         \
+       (IWL_OFDM_BASIC_RATES_MASK | \
+	IWL_RATE_9M_MASK          | \
+	IWL_RATE_18M_MASK         | \
+	IWL_RATE_36M_MASK         | \
+	IWL_RATE_48M_MASK         | \
+	IWL_RATE_54M_MASK)
+
+#define IWL_BASIC_RATES_MASK         \
+	(IWL_OFDM_BASIC_RATES_MASK | \
+	 IWL_CCK_BASIC_RATES_MASK)
+
+#define IWL_RATES_MASK ((1<<IWL_RATE_COUNT)-1)
+
+#define IWL_INVALID_VALUE    -1
+
+#define IWL_MIN_RSSI_VAL                 -100
+#define IWL_MAX_RSSI_VAL                    0
+
+extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
+
+static inline u8 iwl_get_prev_ieee_rate(u8 rate_index)
+{
+	u8 rate = iwl_rates[rate_index].prev_ieee;
+
+	if (rate == IWL_RATE_INVALID)
+		rate = rate_index;
+	return rate;
+}
+
+/**
+ * iwl_fill_rs_info - Fill an output text buffer with the rate representation
+ *
+ * NOTE:  This is provided as a quick mechanism for a user to visualize
+ * the performance of the rate control alogirthm and is not meant to be
+ * parsed software.
+ */
+extern int iwl_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
+
+/**
+ * iwl_rate_scale_init - Initialize the rate scale table based on assoc info
+ *
+ * The specific througput table used is based on the type of network
+ * the associated with, including A, B, G, and G w/ TGG protection
+ */
+extern void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
+
+/**
+ * iwl_rate_control_register - Register the rate control algorithm callbacks
+ *
+ * Since the rate control algorithm is hardware specific, there is no need
+ * or reason to place it as a stand alone module.  The driver can call
+ * iwl_rate_control_register in order to register the rate control callbacks
+ * with the mac80211 subsystem.  This should be performed prior to calling
+ * ieee80211_register_hw
+ *
+ */
+extern void iwl_rate_control_register(struct ieee80211_hw *hw);
+
+/**
+ * iwl_rate_control_unregister - Unregister the rate control callbacks
+ *
+ * This should be called after calling ieee80211_unregister_hw, but before
+ * the driver is unloaded.
+ */
+extern void iwl_rate_control_unregister(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
new file mode 100644
index 0000000..acb3875
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -0,0 +1,2300 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/firmware.h>
+#include <net/mac80211.h>
+
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+
+#define IWL 3945
+
+#include "iwlwifi.h"
+#include "iwl-helpers.h"
+#include "iwl-3945.h"
+#include "iwl-3945-rs.h"
+
+#define IWL_DECLARE_RATE_INFO(r, ip, in, rp, rn, pp, np)    \
+	[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,   \
+				    IWL_RATE_##r##M_IEEE,   \
+				    IWL_RATE_##ip##M_INDEX, \
+				    IWL_RATE_##in##M_INDEX, \
+				    IWL_RATE_##rp##M_INDEX, \
+				    IWL_RATE_##rn##M_INDEX, \
+				    IWL_RATE_##pp##M_INDEX, \
+				    IWL_RATE_##np##M_INDEX }
+
+/*
+ * Parameter order:
+ *   rate, prev rate, next rate, prev tgg rate, next tgg rate
+ *
+ * If there isn't a valid next or previous rate then INV is used which
+ * maps to IWL_RATE_INVALID
+ *
+ */
+const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
+	IWL_DECLARE_RATE_INFO(6, 5, 9, 5, 11, 5, 11),        /*  6mbps */
+	IWL_DECLARE_RATE_INFO(9, 6, 11, 5, 11, 5, 11),       /*  9mbps */
+	IWL_DECLARE_RATE_INFO(12, 11, 18, 11, 18, 11, 18),   /* 12mbps */
+	IWL_DECLARE_RATE_INFO(18, 12, 24, 12, 24, 11, 24),   /* 18mbps */
+	IWL_DECLARE_RATE_INFO(24, 18, 36, 18, 36, 18, 36),   /* 24mbps */
+	IWL_DECLARE_RATE_INFO(36, 24, 48, 24, 48, 24, 48),   /* 36mbps */
+	IWL_DECLARE_RATE_INFO(48, 36, 54, 36, 54, 36, 54),   /* 48mbps */
+	IWL_DECLARE_RATE_INFO(54, 48, INV, 48, INV, 48, INV),/* 54mbps */
+	IWL_DECLARE_RATE_INFO(1, INV, 2, INV, 2, INV, 2),    /*  1mbps */
+	IWL_DECLARE_RATE_INFO(2, 1, 5, 1, 5, 1, 5),          /*  2mbps */
+	IWL_DECLARE_RATE_INFO(5, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
+	IWL_DECLARE_RATE_INFO(11, 9, 12, 5, 12, 5, 18),      /* 11mbps */
+};
+
+/* 1 = enable the iwl_disable_events() function */
+#define IWL_EVT_DISABLE (0)
+#define IWL_EVT_DISABLE_SIZE (1532/32)
+
+/**
+ * iwl_disable_events - Disable selected events in uCode event log
+ *
+ * Disable an event by writing "1"s into "disable"
+ *   bitmap in SRAM.  Bit position corresponds to Event # (id/type).
+ *   Default values of 0 enable uCode events to be logged.
+ * Use for only special debugging.  This function is just a placeholder as-is,
+ *   you'll need to provide the special bits! ...
+ *   ... and set IWL_EVT_DISABLE to 1. */
+void iwl_disable_events(struct iwl_priv *priv)
+{
+	int rc;
+	int i;
+	u32 base;		/* SRAM address of event log header */
+	u32 disable_ptr;	/* SRAM address of event-disable bitmap array */
+	u32 array_size;		/* # of u32 entries in array */
+	u32 evt_disable[IWL_EVT_DISABLE_SIZE] = {
+		0x00000000,	/*   31 -    0  Event id numbers */
+		0x00000000,	/*   63 -   32 */
+		0x00000000,	/*   95 -   64 */
+		0x00000000,	/*  127 -   96 */
+		0x00000000,	/*  159 -  128 */
+		0x00000000,	/*  191 -  160 */
+		0x00000000,	/*  223 -  192 */
+		0x00000000,	/*  255 -  224 */
+		0x00000000,	/*  287 -  256 */
+		0x00000000,	/*  319 -  288 */
+		0x00000000,	/*  351 -  320 */
+		0x00000000,	/*  383 -  352 */
+		0x00000000,	/*  415 -  384 */
+		0x00000000,	/*  447 -  416 */
+		0x00000000,	/*  479 -  448 */
+		0x00000000,	/*  511 -  480 */
+		0x00000000,	/*  543 -  512 */
+		0x00000000,	/*  575 -  544 */
+		0x00000000,	/*  607 -  576 */
+		0x00000000,	/*  639 -  608 */
+		0x00000000,	/*  671 -  640 */
+		0x00000000,	/*  703 -  672 */
+		0x00000000,	/*  735 -  704 */
+		0x00000000,	/*  767 -  736 */
+		0x00000000,	/*  799 -  768 */
+		0x00000000,	/*  831 -  800 */
+		0x00000000,	/*  863 -  832 */
+		0x00000000,	/*  895 -  864 */
+		0x00000000,	/*  927 -  896 */
+		0x00000000,	/*  959 -  928 */
+		0x00000000,	/*  991 -  960 */
+		0x00000000,	/* 1023 -  992 */
+		0x00000000,	/* 1055 - 1024 */
+		0x00000000,	/* 1087 - 1056 */
+		0x00000000,	/* 1119 - 1088 */
+		0x00000000,	/* 1151 - 1120 */
+		0x00000000,	/* 1183 - 1152 */
+		0x00000000,	/* 1215 - 1184 */
+		0x00000000,	/* 1247 - 1216 */
+		0x00000000,	/* 1279 - 1248 */
+		0x00000000,	/* 1311 - 1280 */
+		0x00000000,	/* 1343 - 1312 */
+		0x00000000,	/* 1375 - 1344 */
+		0x00000000,	/* 1407 - 1376 */
+		0x00000000,	/* 1439 - 1408 */
+		0x00000000,	/* 1471 - 1440 */
+		0x00000000,	/* 1503 - 1472 */
+	};
+
+	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+	if (!iwl_hw_valid_rtc_data_addr(base)) {
+		IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
+		return;
+	}
+
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		IWL_WARNING("Can not read from adapter at this time.\n");
+		return;
+	}
+
+	disable_ptr = iwl_read_restricted_mem(priv, base + (4 * sizeof(u32)));
+	array_size = iwl_read_restricted_mem(priv, base + (5 * sizeof(u32)));
+	iwl_release_restricted_access(priv);
+
+	if (IWL_EVT_DISABLE && (array_size == IWL_EVT_DISABLE_SIZE)) {
+		IWL_DEBUG_INFO("Disabling selected uCode log events at 0x%x\n",
+			       disable_ptr);
+		rc = iwl_grab_restricted_access(priv);
+		for (i = 0; i < IWL_EVT_DISABLE_SIZE; i++)
+			iwl_write_restricted_mem(priv,
+						 disable_ptr +
+						 (i * sizeof(u32)),
+						 evt_disable[i]);
+
+		iwl_release_restricted_access(priv);
+	} else {
+		IWL_DEBUG_INFO("Selected uCode log events may be disabled\n");
+		IWL_DEBUG_INFO("  by writing \"1\"s into disable bitmap\n");
+		IWL_DEBUG_INFO("  in SRAM at 0x%x, size %d u32s\n",
+			       disable_ptr, array_size);
+	}
+
+}
+
+/**
+ * iwl3945_get_antenna_flags - Get antenna flags for RXON command
+ * @priv: eeprom and antenna fields are used to determine antenna flags
+ *
+ * priv->eeprom  is used to determine if antenna AUX/MAIN are reversed
+ * priv->antenna specifies the antenna diversity mode:
+ *
+ * IWL_ANTENNA_DIVERISTY - NIC selects best antenna by itself
+ * IWL_ANTENNA_MAIN      - Force MAIN antenna
+ * IWL_ANTENNA_AUX       - Force AUX antenna
+ */
+__le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv)
+{
+	switch (priv->antenna) {
+	case IWL_ANTENNA_DIVERSITY:
+		return 0;
+
+	case IWL_ANTENNA_MAIN:
+		if (priv->eeprom.antenna_switch_type)
+			return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK;
+		return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK;
+
+	case IWL_ANTENNA_AUX:
+		if (priv->eeprom.antenna_switch_type)
+			return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_A_MSK;
+		return RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_B_MSK;
+	}
+
+	/* bad antenna selector value */
+	IWL_ERROR("Bad antenna selector value (0x%x)\n", priv->antenna);
+	return 0;		/* "diversity" is default if error */
+}
+
+/*****************************************************************************
+ *
+ * Intel PRO/Wireless 3945ABG/BG Network Connection
+ *
+ *  RX handler implementations
+ *
+ *  Used by iwl-base.c
+ *
+ *****************************************************************************/
+
+void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n",
+		     (int)sizeof(struct iwl_notif_statistics),
+		     le32_to_cpu(pkt->len));
+
+	memcpy(&priv->statistics, pkt->u.raw, sizeof(priv->statistics));
+
+	priv->last_statistics_time = jiffies;
+}
+
+static void iwl3945_handle_data_packet(struct iwl_priv *priv, int is_data,
+				   struct iwl_rx_mem_buffer *rxb,
+				   struct ieee80211_rx_status *stats,
+				   u16 phy_flags)
+{
+	struct ieee80211_hdr *hdr;
+	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+	struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+	struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+	short len = le16_to_cpu(rx_hdr->len);
+
+	/* We received data from the HW, so stop the watchdog */
+	if (unlikely((len + IWL_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) {
+		IWL_DEBUG_DROP("Corruption detected!\n");
+		return;
+	}
+
+	/* We only process data packets if the interface is open */
+	if (unlikely(!priv->is_open)) {
+		IWL_DEBUG_DROP_LIMIT
+		    ("Dropping packet while interface is not open.\n");
+		return;
+	}
+	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+		if (iwl_param_hwcrypto)
+			iwl_set_decrypted_flag(priv, rxb->skb,
+					       le32_to_cpu(rx_end->status),
+					       stats);
+		iwl_handle_data_packet_monitor(priv, rxb, IWL_RX_DATA(pkt),
+					       len, stats, phy_flags);
+		return;
+	}
+
+	skb_reserve(rxb->skb, (void *)rx_hdr->payload - (void *)pkt);
+	/* Set the size of the skb to the size of the frame */
+	skb_put(rxb->skb, le16_to_cpu(rx_hdr->len));
+
+	hdr = (void *)rxb->skb->data;
+
+	if (iwl_param_hwcrypto)
+		iwl_set_decrypted_flag(priv, rxb->skb,
+				       le32_to_cpu(rx_end->status), stats);
+
+	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+	rxb->skb = NULL;
+}
+
+static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
+				struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
+	struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+	struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+	struct ieee80211_hdr *header;
+	u16 phy_flags = le16_to_cpu(rx_hdr->phy_flags);
+	u16 rx_stats_sig_avg = le16_to_cpu(rx_stats->sig_avg);
+	u16 rx_stats_noise_diff = le16_to_cpu(rx_stats->noise_diff);
+	struct ieee80211_rx_status stats = {
+		.mactime = le64_to_cpu(rx_end->timestamp),
+		.freq = ieee80211chan2mhz(le16_to_cpu(rx_hdr->channel)),
+		.channel = le16_to_cpu(rx_hdr->channel),
+		.phymode = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
+		MODE_IEEE80211G : MODE_IEEE80211A,
+		.antenna = 0,
+		.rate = rx_hdr->rate,
+		.flag = 0,
+	};
+	u8 network_packet;
+	int snr;
+
+	if ((unlikely(rx_stats->phy_count > 20))) {
+		IWL_DEBUG_DROP
+		    ("dsp size out of range [0,20]: "
+		     "%d/n", rx_stats->phy_count);
+		return;
+	}
+
+	if (!(rx_end->status & RX_RES_STATUS_NO_CRC32_ERROR)
+	    || !(rx_end->status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
+		IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n", rx_end->status);
+		return;
+	}
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+		iwl3945_handle_data_packet(priv, 1, rxb, &stats, phy_flags);
+		return;
+	}
+
+	/* Convert 3945's rssi indicator to dBm */
+	stats.ssi = rx_stats->rssi - IWL_RSSI_OFFSET;
+
+	/* Set default noise value to -127 */
+	if (priv->last_rx_noise == 0)
+		priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+
+	/* 3945 provides noise info for OFDM frames only.
+	 * sig_avg and noise_diff are measured by the 3945's digital signal
+	 *   processor (DSP), and indicate linear levels of signal level and
+	 *   distortion/noise within the packet preamble after
+	 *   automatic gain control (AGC).  sig_avg should stay fairly
+	 *   constant if the radio's AGC is working well.
+	 * Since these values are linear (not dB or dBm), linear
+	 *   signal-to-noise ratio (SNR) is (sig_avg / noise_diff).
+	 * Convert linear SNR to dB SNR, then subtract that from rssi dBm
+	 *   to obtain noise level in dBm.
+	 * Calculate stats.signal (quality indicator in %) based on SNR. */
+	if (rx_stats_noise_diff) {
+		snr = rx_stats_sig_avg / rx_stats_noise_diff;
+		stats.noise = stats.ssi - iwl_calc_db_from_ratio(snr);
+		stats.signal = iwl_calc_sig_qual(stats.ssi, stats.noise);
+
+	/* If noise info not available, calculate signal quality indicator (%)
+	 *   using just the dBm signal level. */
+	} else {
+		stats.noise = priv->last_rx_noise;
+		stats.signal = iwl_calc_sig_qual(stats.ssi, 0);
+	}
+
+
+	IWL_DEBUG_STATS("Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n",
+			stats.ssi, stats.noise, stats.signal,
+			rx_stats_sig_avg, rx_stats_noise_diff);
+
+	stats.freq = ieee80211chan2mhz(stats.channel);
+
+	/* can be covered by iwl_report_frame() in most cases */
+/*      IWL_DEBUG_RX("RX status: 0x%08X\n", rx_end->status); */
+
+	header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
+
+	network_packet = iwl_is_network_packet(priv, header);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (iwl_debug_level & IWL_DL_STATS && net_ratelimit())
+		IWL_DEBUG_STATS
+		    ("[%c] %d RSSI: %d Signal: %u, Noise: %u, Rate: %u\n",
+		     network_packet ? '*' : ' ',
+		     stats.channel, stats.ssi, stats.ssi,
+		     stats.ssi, stats.rate);
+
+	if (iwl_debug_level & (IWL_DL_RX))
+		/* Set "1" to report good data frames in groups of 100 */
+		iwl_report_frame(priv, pkt, header, 1);
+#endif
+
+	if (network_packet) {
+		priv->last_beacon_time = le32_to_cpu(rx_end->beacon_timestamp);
+		priv->last_tsf = le64_to_cpu(rx_end->timestamp);
+		priv->last_rx_rssi = stats.ssi;
+		priv->last_rx_noise = stats.noise;
+	}
+
+	switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) {
+	case IEEE80211_FTYPE_MGMT:
+		switch (le16_to_cpu(header->frame_control) &
+			IEEE80211_FCTL_STYPE) {
+		case IEEE80211_STYPE_PROBE_RESP:
+		case IEEE80211_STYPE_BEACON:{
+				/* If this is a beacon or probe response for
+				 * our network then cache the beacon
+				 * timestamp */
+				if ((((priv->iw_mode == IEEE80211_IF_TYPE_STA)
+				      && !compare_ether_addr(header->addr2,
+							     priv->bssid)) ||
+				     ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+				      && !compare_ether_addr(header->addr3,
+							     priv->bssid)))) {
+					struct ieee80211_mgmt *mgmt =
+					    (struct ieee80211_mgmt *)header;
+					__le32 *pos;
+					pos =
+					    (__le32 *) & mgmt->u.beacon.
+					    timestamp;
+					priv->timestamp0 = le32_to_cpu(pos[0]);
+					priv->timestamp1 = le32_to_cpu(pos[1]);
+					priv->beacon_int = le16_to_cpu(
+					    mgmt->u.beacon.beacon_int);
+					if (priv->call_post_assoc_from_beacon &&
+					    (priv->iw_mode ==
+						IEEE80211_IF_TYPE_STA))
+						queue_work(priv->workqueue,
+						    &priv->post_associate.work);
+
+					priv->call_post_assoc_from_beacon = 0;
+				}
+
+				break;
+			}
+
+		case IEEE80211_STYPE_ACTION:
+			/* TODO: Parse 802.11h frames for CSA... */
+			break;
+
+			/*
+			 * TODO: There is no callback function from upper
+			 * stack to inform us when associated status. this
+			 * work around to sniff assoc_resp management frame
+			 * and finish the association process.
+			 */
+		case IEEE80211_STYPE_ASSOC_RESP:
+		case IEEE80211_STYPE_REASSOC_RESP:{
+				struct ieee80211_mgmt *mgnt =
+				    (struct ieee80211_mgmt *)header;
+				priv->assoc_id = (~((1 << 15) | (1 << 14)) &
+						  le16_to_cpu(mgnt->u.
+							      assoc_resp.aid));
+				priv->assoc_capability =
+				    le16_to_cpu(mgnt->u.assoc_resp.capab_info);
+				if (priv->beacon_int)
+					queue_work(priv->workqueue,
+					    &priv->post_associate.work);
+				else
+					priv->call_post_assoc_from_beacon = 1;
+				break;
+			}
+
+		case IEEE80211_STYPE_PROBE_REQ:{
+				DECLARE_MAC_BUF(mac1);
+				DECLARE_MAC_BUF(mac2);
+				DECLARE_MAC_BUF(mac3);
+				if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+					IWL_DEBUG_DROP
+					    ("Dropping (non network): %s"
+					     ", %s, %s\n",
+					     print_mac(mac1, header->addr1),
+					     print_mac(mac2, header->addr2),
+					     print_mac(mac3, header->addr3));
+				return;
+			}
+		}
+
+		iwl3945_handle_data_packet(priv, 0, rxb, &stats, phy_flags);
+		break;
+
+	case IEEE80211_FTYPE_CTL:
+		break;
+
+	case IEEE80211_FTYPE_DATA: {
+		DECLARE_MAC_BUF(mac1);
+		DECLARE_MAC_BUF(mac2);
+		DECLARE_MAC_BUF(mac3);
+
+		if (unlikely(is_duplicate_packet(priv, header)))
+			IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n",
+				       print_mac(mac1, header->addr1),
+				       print_mac(mac2, header->addr2),
+				       print_mac(mac3, header->addr3));
+		else
+			iwl3945_handle_data_packet(priv, 1, rxb, &stats,
+						   phy_flags);
+		break;
+	}
+	}
+}
+
+int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
+				 dma_addr_t addr, u16 len)
+{
+	int count;
+	u32 pad;
+	struct iwl_tfd_frame *tfd = (struct iwl_tfd_frame *)ptr;
+
+	count = TFD_CTL_COUNT_GET(le32_to_cpu(tfd->control_flags));
+	pad = TFD_CTL_PAD_GET(le32_to_cpu(tfd->control_flags));
+
+	if ((count >= NUM_TFD_CHUNKS) || (count < 0)) {
+		IWL_ERROR("Error can not send more than %d chunks\n",
+			  NUM_TFD_CHUNKS);
+		return -EINVAL;
+	}
+
+	tfd->pa[count].addr = cpu_to_le32(addr);
+	tfd->pa[count].len = cpu_to_le32(len);
+
+	count++;
+
+	tfd->control_flags = cpu_to_le32(TFD_CTL_COUNT_SET(count) |
+					 TFD_CTL_PAD_SET(pad));
+
+	return 0;
+}
+
+/**
+ * iwl_hw_txq_free_tfd - Free one TFD, those at index [txq->q.last_used]
+ *
+ * Does NOT advance any indexes
+ */
+int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+	struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0];
+	struct iwl_tfd_frame *bd = &bd_tmp[txq->q.last_used];
+	struct pci_dev *dev = priv->pci_dev;
+	int i;
+	int counter;
+
+	/* classify bd */
+	if (txq->q.id == IWL_CMD_QUEUE_NUM)
+		/* nothing to cleanup after for host commands */
+		return 0;
+
+	/* sanity check */
+	counter = TFD_CTL_COUNT_GET(le32_to_cpu(bd->control_flags));
+	if (counter > NUM_TFD_CHUNKS) {
+		IWL_ERROR("Too many chunks: %i\n", counter);
+		/* @todo issue fatal error, it is quite serious situation */
+		return 0;
+	}
+
+	/* unmap chunks if any */
+
+	for (i = 1; i < counter; i++) {
+		pci_unmap_single(dev, le32_to_cpu(bd->pa[i].addr),
+				 le32_to_cpu(bd->pa[i].len), PCI_DMA_TODEVICE);
+		if (txq->txb[txq->q.last_used].skb[0]) {
+			struct sk_buff *skb = txq->txb[txq->q.last_used].skb[0];
+			if (txq->txb[txq->q.last_used].skb[0]) {
+				/* Can be called from interrupt context */
+				dev_kfree_skb_any(skb);
+				txq->txb[txq->q.last_used].skb[0] = NULL;
+			}
+		}
+	}
+	return 0;
+}
+
+u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr)
+{
+	int i;
+	int ret = IWL_INVALID_STATION;
+	unsigned long flags;
+	DECLARE_MAC_BUF(mac);
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
+		if ((priv->stations[i].used) &&
+		    (!compare_ether_addr
+		     (priv->stations[i].sta.sta.addr, addr))) {
+			ret = i;
+			goto out;
+		}
+
+	IWL_DEBUG_INFO("can not find STA %s (total %d)\n",
+		       print_mac(mac, addr), priv->num_stations);
+ out:
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+	return ret;
+}
+
+/**
+ * iwl_hw_build_tx_cmd_rate - Add rate portion to TX_CMD:
+ *
+*/
+void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
+			      struct iwl_cmd *cmd,
+			      struct ieee80211_tx_control *ctrl,
+			      struct ieee80211_hdr *hdr, int sta_id, int tx_id)
+{
+	unsigned long flags;
+	u16 rate_index = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1);
+	u16 rate_mask;
+	int rate;
+	u8 rts_retry_limit;
+	u8 data_retry_limit;
+	__le32 tx_flags;
+	u16 fc = le16_to_cpu(hdr->frame_control);
+
+	rate = iwl_rates[rate_index].plcp;
+	tx_flags = cmd->cmd.tx.tx_flags;
+
+	/* We need to figure out how to get the sta->supp_rates while
+	 * in this running context; perhaps encoding into ctrl->tx_rate? */
+	rate_mask = IWL_RATES_MASK;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+
+	priv->stations[sta_id].current_rate.rate_n_flags = rate;
+
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+	    (sta_id != IWL3945_BROADCAST_ID) &&
+		(sta_id != IWL_MULTICAST_ID))
+		priv->stations[IWL_STA_ID].current_rate.rate_n_flags = rate;
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	if (tx_id >= IWL_CMD_QUEUE_NUM)
+		rts_retry_limit = 3;
+	else
+		rts_retry_limit = 7;
+
+	if (ieee80211_is_probe_response(fc)) {
+		data_retry_limit = 3;
+		if (data_retry_limit < rts_retry_limit)
+			rts_retry_limit = data_retry_limit;
+	} else
+		data_retry_limit = IWL_DEFAULT_TX_RETRY;
+
+	if (priv->data_retry_limit != -1)
+		data_retry_limit = priv->data_retry_limit;
+
+	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+		switch (fc & IEEE80211_FCTL_STYPE) {
+		case IEEE80211_STYPE_AUTH:
+		case IEEE80211_STYPE_DEAUTH:
+		case IEEE80211_STYPE_ASSOC_REQ:
+		case IEEE80211_STYPE_REASSOC_REQ:
+			if (tx_flags & TX_CMD_FLG_RTS_MSK) {
+				tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+				tx_flags |= TX_CMD_FLG_CTS_MSK;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	cmd->cmd.tx.rts_retry_limit = rts_retry_limit;
+	cmd->cmd.tx.data_retry_limit = data_retry_limit;
+	cmd->cmd.tx.rate = rate;
+	cmd->cmd.tx.tx_flags = tx_flags;
+
+	/* OFDM */
+	cmd->cmd.tx.supp_rates[0] = rate_mask & IWL_OFDM_RATES_MASK;
+
+	/* CCK */
+	cmd->cmd.tx.supp_rates[1] = (rate_mask >> 8) & 0xF;
+
+	IWL_DEBUG_RATE("Tx sta id: %d, rate: %d (plcp), flags: 0x%4X "
+		       "cck/ofdm mask: 0x%x/0x%x\n", sta_id,
+		       cmd->cmd.tx.rate, le32_to_cpu(cmd->cmd.tx.tx_flags),
+		       cmd->cmd.tx.supp_rates[1], cmd->cmd.tx.supp_rates[0]);
+}
+
+u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate, u8 flags)
+{
+	unsigned long flags_spin;
+	struct iwl_station_entry *station;
+
+	if (sta_id == IWL_INVALID_STATION)
+		return IWL_INVALID_STATION;
+
+	spin_lock_irqsave(&priv->sta_lock, flags_spin);
+	station = &priv->stations[sta_id];
+
+	station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK;
+	station->sta.rate_n_flags = cpu_to_le16(tx_rate);
+	station->current_rate.rate_n_flags = tx_rate;
+	station->sta.mode = STA_CONTROL_MODIFY_MSK;
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+
+	iwl_send_add_station(priv, &station->sta, flags);
+	IWL_DEBUG_RATE("SCALE sync station %d to rate %d\n",
+			sta_id, tx_rate);
+	return sta_id;
+}
+
+void iwl_hw_card_show_info(struct iwl_priv *priv)
+{
+	IWL_DEBUG_INFO("3945ABG HW Version %u.%u.%u\n",
+		       ((priv->eeprom.board_revision >> 8) & 0x0F),
+		       ((priv->eeprom.board_revision >> 8) >> 4),
+		       (priv->eeprom.board_revision & 0x00FF));
+
+	IWL_DEBUG_INFO("3945ABG PBA Number %.*s\n",
+		       (int)sizeof(priv->eeprom.board_pba_number),
+		       priv->eeprom.board_pba_number);
+
+	IWL_DEBUG_INFO("EEPROM_ANTENNA_SWITCH_TYPE is 0x%02X\n",
+		       priv->eeprom.antenna_switch_type);
+}
+
+static int iwl3945_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
+{
+	int rc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+
+	if (!pwr_max) {
+		u32 val;
+
+		rc = pci_read_config_dword(priv->pci_dev,
+				PCI_POWER_SOURCE, &val);
+		if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT) {
+			iwl_set_bits_mask_restricted_reg(priv, APMG_PS_CTRL_REG,
+					APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
+					~APMG_PS_CTRL_MSK_PWR_SRC);
+			iwl_release_restricted_access(priv);
+
+			iwl_poll_bit(priv, CSR_GPIO_IN,
+				     CSR_GPIO_IN_VAL_VAUX_PWR_SRC,
+				     CSR_GPIO_IN_BIT_AUX_POWER, 5000);
+		} else
+			iwl_release_restricted_access(priv);
+	} else {
+		iwl_set_bits_mask_restricted_reg(priv, APMG_PS_CTRL_REG,
+				APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+				~APMG_PS_CTRL_MSK_PWR_SRC);
+
+		iwl_release_restricted_access(priv);
+		iwl_poll_bit(priv, CSR_GPIO_IN, CSR_GPIO_IN_VAL_VMAIN_PWR_SRC,
+			     CSR_GPIO_IN_BIT_AUX_POWER, 5000);	/* uS */
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return rc;
+}
+
+static int iwl3945_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+	int rc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+
+	iwl_write_restricted(priv, FH_RCSR_RBD_BASE(0), rxq->dma_addr);
+	iwl_write_restricted(priv, FH_RCSR_RPTR_ADDR(0),
+			     priv->hw_setting.shared_phys +
+			     offsetof(struct iwl_shared, rx_read_ptr[0]));
+	iwl_write_restricted(priv, FH_RCSR_WPTR(0), 0);
+	iwl_write_restricted(priv, FH_RCSR_CONFIG(0),
+		ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE |
+		ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE |
+		ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN |
+		ALM_FH_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128 |
+		(RX_QUEUE_SIZE_LOG << ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE) |
+		ALM_FH_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST |
+		(1 << ALM_FH_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH) |
+		ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH);
+
+	/* fake read to flush all prev I/O */
+	iwl_read_restricted(priv, FH_RSSR_CTRL);
+
+	iwl_release_restricted_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+static int iwl3945_tx_reset(struct iwl_priv *priv)
+{
+	int rc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+
+	/* bypass mode */
+	iwl_write_restricted_reg(priv, SCD_MODE_REG, 0x2);
+
+	/* RA 0 is active */
+	iwl_write_restricted_reg(priv, SCD_ARASTAT_REG, 0x01);
+
+	/* all 6 fifo are active */
+	iwl_write_restricted_reg(priv, SCD_TXFACT_REG, 0x3f);
+
+	iwl_write_restricted_reg(priv, SCD_SBYP_MODE_1_REG, 0x010000);
+	iwl_write_restricted_reg(priv, SCD_SBYP_MODE_2_REG, 0x030002);
+	iwl_write_restricted_reg(priv, SCD_TXF4MF_REG, 0x000004);
+	iwl_write_restricted_reg(priv, SCD_TXF5MF_REG, 0x000005);
+
+	iwl_write_restricted(priv, FH_TSSR_CBB_BASE,
+			     priv->hw_setting.shared_phys);
+
+	iwl_write_restricted(priv, FH_TSSR_MSG_CONFIG,
+		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON |
+		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON |
+		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B |
+		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON |
+		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON |
+		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH |
+		ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH);
+
+	iwl_release_restricted_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+/**
+ * iwl3945_txq_ctx_reset - Reset TX queue context
+ *
+ * Destroys all DMA structures and initialize them again
+ */
+static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
+{
+	int rc;
+	int txq_id, slots_num;
+
+	iwl_hw_txq_ctx_free(priv);
+
+	/* Tx CMD queue */
+	rc = iwl3945_tx_reset(priv);
+	if (rc)
+		goto error;
+
+	/* Tx queue(s) */
+	for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++) {
+		slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
+				TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+		rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
+				txq_id);
+		if (rc) {
+			IWL_ERROR("Tx %d queue init failed\n", txq_id);
+			goto error;
+		}
+	}
+
+	return rc;
+
+ error:
+	iwl_hw_txq_ctx_free(priv);
+	return rc;
+}
+
+int iwl_hw_nic_init(struct iwl_priv *priv)
+{
+	u8 rev_id;
+	int rc;
+	unsigned long flags;
+	struct iwl_rx_queue *rxq = &priv->rxq;
+
+	iwl_power_init_handle(priv);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl_set_bit(priv, CSR_ANA_PLL_CFG, (1 << 24));
+	iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+		    CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
+
+	iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+	rc = iwl_poll_bit(priv, CSR_GP_CNTRL,
+			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+	if (rc < 0) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		IWL_DEBUG_INFO("Failed to init the card\n");
+		return rc;
+	}
+
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+	iwl_write_restricted_reg(priv, APMG_CLK_EN_REG,
+				 APMG_CLK_VAL_DMA_CLK_RQT |
+				 APMG_CLK_VAL_BSM_CLK_RQT);
+	udelay(20);
+	iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG,
+				    APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+	iwl_release_restricted_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	/* Determine HW type */
+	rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id);
+	if (rc)
+		return rc;
+	IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id);
+
+	iwl3945_nic_set_pwr_src(priv, 1);
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (rev_id & PCI_CFG_REV_ID_BIT_RTP)
+		IWL_DEBUG_INFO("RTP type \n");
+	else if (rev_id & PCI_CFG_REV_ID_BIT_BASIC_SKU) {
+		IWL_DEBUG_INFO("ALM-MB type\n");
+		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+			    CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB);
+	} else {
+		IWL_DEBUG_INFO("ALM-MM type\n");
+		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+			    CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM);
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	/* Initialize the EEPROM */
+	rc = iwl_eeprom_init(priv);
+	if (rc)
+		return rc;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (EEPROM_SKU_CAP_OP_MODE_MRC == priv->eeprom.sku_cap) {
+		IWL_DEBUG_INFO("SKU OP mode is mrc\n");
+		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+			    CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC);
+	} else
+		IWL_DEBUG_INFO("SKU OP mode is basic\n");
+
+	if ((priv->eeprom.board_revision & 0xF0) == 0xD0) {
+		IWL_DEBUG_INFO("3945ABG revision is 0x%X\n",
+			       priv->eeprom.board_revision);
+		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+			    CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
+	} else {
+		IWL_DEBUG_INFO("3945ABG revision is 0x%X\n",
+			       priv->eeprom.board_revision);
+		iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+			      CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE);
+	}
+
+	if (priv->eeprom.almgor_m_version <= 1) {
+		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+			    CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A);
+		IWL_DEBUG_INFO("Card M type A version is 0x%X\n",
+			       priv->eeprom.almgor_m_version);
+	} else {
+		IWL_DEBUG_INFO("Card M type B version is 0x%X\n",
+			       priv->eeprom.almgor_m_version);
+		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+			    CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B);
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE)
+		IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n");
+
+	if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE)
+		IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n");
+
+	/* Allocate the RX queue, or reset if it is already allocated */
+	if (!rxq->bd) {
+		rc = iwl_rx_queue_alloc(priv);
+		if (rc) {
+			IWL_ERROR("Unable to initialize Rx queue\n");
+			return -ENOMEM;
+		}
+	} else
+		iwl_rx_queue_reset(priv, rxq);
+
+	iwl_rx_replenish(priv);
+
+	iwl3945_rx_init(priv, rxq);
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	/* Look at using this instead:
+	rxq->need_update = 1;
+	iwl_rx_queue_update_write_ptr(priv, rxq);
+	*/
+
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+	iwl_write_restricted(priv, FH_RCSR_WPTR(0), rxq->write & ~7);
+	iwl_release_restricted_access(priv);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	rc = iwl3945_txq_ctx_reset(priv);
+	if (rc)
+		return rc;
+
+	set_bit(STATUS_INIT, &priv->status);
+
+	return 0;
+}
+
+/**
+ * iwl_hw_txq_ctx_free - Free TXQ Context
+ *
+ * Destroy all TX DMA queues and structures
+ */
+void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
+{
+	int txq_id;
+
+	/* Tx queues */
+	for (txq_id = 0; txq_id < TFD_QUEUE_MAX; txq_id++)
+		iwl_tx_queue_free(priv, &priv->txq[txq_id]);
+}
+
+void iwl_hw_txq_ctx_stop(struct iwl_priv *priv)
+{
+	int queue;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (iwl_grab_restricted_access(priv)) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		iwl_hw_txq_ctx_free(priv);
+		return;
+	}
+
+	/* stop SCD */
+	iwl_write_restricted_reg(priv, SCD_MODE_REG, 0);
+
+	/* reset TFD queues */
+	for (queue = TFD_QUEUE_MIN; queue < TFD_QUEUE_MAX; queue++) {
+		iwl_write_restricted(priv, FH_TCSR_CONFIG(queue), 0x0);
+		iwl_poll_restricted_bit(priv, FH_TSSR_TX_STATUS,
+				ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(queue),
+				1000);
+	}
+
+	iwl_release_restricted_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	iwl_hw_txq_ctx_free(priv);
+}
+
+int iwl_hw_nic_stop_master(struct iwl_priv *priv)
+{
+	int rc = 0;
+	u32 reg_val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	/* set stop master bit */
+	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+
+	reg_val = iwl_read32(priv, CSR_GP_CNTRL);
+
+	if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE ==
+	    (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE))
+		IWL_DEBUG_INFO("Card in power save, master is already "
+			       "stopped\n");
+	else {
+		rc = iwl_poll_bit(priv, CSR_RESET,
+				  CSR_RESET_REG_FLAG_MASTER_DISABLED,
+				  CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
+		if (rc < 0) {
+			spin_unlock_irqrestore(&priv->lock, flags);
+			return rc;
+		}
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+	IWL_DEBUG_INFO("stop master\n");
+
+	return rc;
+}
+
+int iwl_hw_nic_reset(struct iwl_priv *priv)
+{
+	int rc;
+	unsigned long flags;
+
+	iwl_hw_nic_stop_master(priv);
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+	rc = iwl_poll_bit(priv, CSR_GP_CNTRL,
+			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+
+	rc = iwl_grab_restricted_access(priv);
+	if (!rc) {
+		iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG,
+					 APMG_CLK_VAL_BSM_CLK_RQT);
+
+		udelay(10);
+
+		iwl_set_bit(priv, CSR_GP_CNTRL,
+			    CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+
+		iwl_write_restricted_reg(priv, APMG_RTC_INT_MSK_REG, 0x0);
+		iwl_write_restricted_reg(priv, APMG_RTC_INT_STT_REG,
+					0xFFFFFFFF);
+
+		/* enable DMA */
+		iwl_write_restricted_reg(priv, APMG_CLK_EN_REG,
+					 APMG_CLK_VAL_DMA_CLK_RQT |
+					 APMG_CLK_VAL_BSM_CLK_RQT);
+		udelay(10);
+
+		iwl_set_bits_restricted_reg(priv, APMG_PS_CTRL_REG,
+				APMG_PS_CTRL_VAL_RESET_REQ);
+		udelay(5);
+		iwl_clear_bits_restricted_reg(priv, APMG_PS_CTRL_REG,
+				APMG_PS_CTRL_VAL_RESET_REQ);
+		iwl_release_restricted_access(priv);
+	}
+
+	/* Clear the 'host command active' bit... */
+	clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+	wake_up_interruptible(&priv->wait_command_queue);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return rc;
+}
+
+/**
+ * iwl_hw_reg_adjust_power_by_temp - return index delta into power gain settings table
+ */
+static int iwl_hw_reg_adjust_power_by_temp(int new_reading, int old_reading)
+{
+	return (new_reading - old_reading) * (-11) / 100;
+}
+
+/**
+ * iwl_hw_reg_temp_out_of_range - Keep temperature in sane range
+ */
+static inline int iwl_hw_reg_temp_out_of_range(int temperature)
+{
+	return (((temperature < -260) || (temperature > 25)) ? 1 : 0);
+}
+
+int iwl_hw_get_temperature(struct iwl_priv *priv)
+{
+	return iwl_read32(priv, CSR_UCODE_DRV_GP2);
+}
+
+/**
+ * iwl_hw_reg_txpower_get_temperature - get current temperature by reading from NIC
+ */
+static int iwl_hw_reg_txpower_get_temperature(struct iwl_priv *priv)
+{
+	int temperature;
+
+	temperature = iwl_hw_get_temperature(priv);
+
+	/* driver's okay range is -260 to +25.
+	 *   human readable okay range is 0 to +285 */
+	IWL_DEBUG_INFO("Temperature: %d\n", temperature + IWL_TEMP_CONVERT);
+
+	/* handle insane temp reading */
+	if (iwl_hw_reg_temp_out_of_range(temperature)) {
+		IWL_ERROR("Error bad temperature value  %d\n", temperature);
+
+		/* if really really hot(?),
+		 *   substitute the 3rd band/group's temp measured at factory */
+		if (priv->last_temperature > 100)
+			temperature = priv->eeprom.groups[2].temperature;
+		else /* else use most recent "sane" value from driver */
+			temperature = priv->last_temperature;
+	}
+
+	return temperature;	/* raw, not "human readable" */
+}
+
+/* Adjust Txpower only if temperature variance is greater than threshold.
+ *
+ * Both are lower than older versions' 9 degrees */
+#define IWL_TEMPERATURE_LIMIT_TIMER   6
+
+/**
+ * is_temp_calib_needed - determines if new calibration is needed
+ *
+ * records new temperature in tx_mgr->temperature.
+ * replaces tx_mgr->last_temperature *only* if calib needed
+ *    (assumes caller will actually do the calibration!). */
+static int is_temp_calib_needed(struct iwl_priv *priv)
+{
+	int temp_diff;
+
+	priv->temperature = iwl_hw_reg_txpower_get_temperature(priv);
+	temp_diff = priv->temperature - priv->last_temperature;
+
+	/* get absolute value */
+	if (temp_diff < 0) {
+		IWL_DEBUG_POWER("Getting cooler, delta %d,\n", temp_diff);
+		temp_diff = -temp_diff;
+	} else if (temp_diff == 0)
+		IWL_DEBUG_POWER("Same temp,\n");
+	else
+		IWL_DEBUG_POWER("Getting warmer, delta %d,\n", temp_diff);
+
+	/* if we don't need calibration, *don't* update last_temperature */
+	if (temp_diff < IWL_TEMPERATURE_LIMIT_TIMER) {
+		IWL_DEBUG_POWER("Timed thermal calib not needed\n");
+		return 0;
+	}
+
+	IWL_DEBUG_POWER("Timed thermal calib needed\n");
+
+	/* assume that caller will actually do calib ...
+	 *   update the "last temperature" value */
+	priv->last_temperature = priv->temperature;
+	return 1;
+}
+
+#define IWL_MAX_GAIN_ENTRIES 78
+#define IWL_CCK_FROM_OFDM_POWER_DIFF  -5
+#define IWL_CCK_FROM_OFDM_INDEX_DIFF (10)
+
+/* radio and DSP power table, each step is 1/2 dB.
+ * 1st number is for RF analog gain, 2nd number is for DSP pre-DAC gain. */
+static struct iwl_tx_power power_gain_table[2][IWL_MAX_GAIN_ENTRIES] = {
+	{
+	 {251, 127},		/* 2.4 GHz, highest power */
+	 {251, 127},
+	 {251, 127},
+	 {251, 127},
+	 {251, 125},
+	 {251, 110},
+	 {251, 105},
+	 {251, 98},
+	 {187, 125},
+	 {187, 115},
+	 {187, 108},
+	 {187, 99},
+	 {243, 119},
+	 {243, 111},
+	 {243, 105},
+	 {243, 97},
+	 {243, 92},
+	 {211, 106},
+	 {211, 100},
+	 {179, 120},
+	 {179, 113},
+	 {179, 107},
+	 {147, 125},
+	 {147, 119},
+	 {147, 112},
+	 {147, 106},
+	 {147, 101},
+	 {147, 97},
+	 {147, 91},
+	 {115, 107},
+	 {235, 121},
+	 {235, 115},
+	 {235, 109},
+	 {203, 127},
+	 {203, 121},
+	 {203, 115},
+	 {203, 108},
+	 {203, 102},
+	 {203, 96},
+	 {203, 92},
+	 {171, 110},
+	 {171, 104},
+	 {171, 98},
+	 {139, 116},
+	 {227, 125},
+	 {227, 119},
+	 {227, 113},
+	 {227, 107},
+	 {227, 101},
+	 {227, 96},
+	 {195, 113},
+	 {195, 106},
+	 {195, 102},
+	 {195, 95},
+	 {163, 113},
+	 {163, 106},
+	 {163, 102},
+	 {163, 95},
+	 {131, 113},
+	 {131, 106},
+	 {131, 102},
+	 {131, 95},
+	 {99, 113},
+	 {99, 106},
+	 {99, 102},
+	 {99, 95},
+	 {67, 113},
+	 {67, 106},
+	 {67, 102},
+	 {67, 95},
+	 {35, 113},
+	 {35, 106},
+	 {35, 102},
+	 {35, 95},
+	 {3, 113},
+	 {3, 106},
+	 {3, 102},
+	 {3, 95} },		/* 2.4 GHz, lowest power */
+	{
+	 {251, 127},		/* 5.x GHz, highest power */
+	 {251, 120},
+	 {251, 114},
+	 {219, 119},
+	 {219, 101},
+	 {187, 113},
+	 {187, 102},
+	 {155, 114},
+	 {155, 103},
+	 {123, 117},
+	 {123, 107},
+	 {123, 99},
+	 {123, 92},
+	 {91, 108},
+	 {59, 125},
+	 {59, 118},
+	 {59, 109},
+	 {59, 102},
+	 {59, 96},
+	 {59, 90},
+	 {27, 104},
+	 {27, 98},
+	 {27, 92},
+	 {115, 118},
+	 {115, 111},
+	 {115, 104},
+	 {83, 126},
+	 {83, 121},
+	 {83, 113},
+	 {83, 105},
+	 {83, 99},
+	 {51, 118},
+	 {51, 111},
+	 {51, 104},
+	 {51, 98},
+	 {19, 116},
+	 {19, 109},
+	 {19, 102},
+	 {19, 98},
+	 {19, 93},
+	 {171, 113},
+	 {171, 107},
+	 {171, 99},
+	 {139, 120},
+	 {139, 113},
+	 {139, 107},
+	 {139, 99},
+	 {107, 120},
+	 {107, 113},
+	 {107, 107},
+	 {107, 99},
+	 {75, 120},
+	 {75, 113},
+	 {75, 107},
+	 {75, 99},
+	 {43, 120},
+	 {43, 113},
+	 {43, 107},
+	 {43, 99},
+	 {11, 120},
+	 {11, 113},
+	 {11, 107},
+	 {11, 99},
+	 {131, 107},
+	 {131, 99},
+	 {99, 120},
+	 {99, 113},
+	 {99, 107},
+	 {99, 99},
+	 {67, 120},
+	 {67, 113},
+	 {67, 107},
+	 {67, 99},
+	 {35, 120},
+	 {35, 113},
+	 {35, 107},
+	 {35, 99},
+	 {3, 120} }		/* 5.x GHz, lowest power */
+};
+
+static inline u8 iwl_hw_reg_fix_power_index(int index)
+{
+	if (index < 0)
+		return 0;
+	if (index >= IWL_MAX_GAIN_ENTRIES)
+		return IWL_MAX_GAIN_ENTRIES - 1;
+	return (u8) index;
+}
+
+/* Kick off thermal recalibration check every 60 seconds */
+#define REG_RECALIB_PERIOD (60)
+
+/**
+ * iwl_hw_reg_set_scan_power - Set Tx power for scan probe requests
+ *
+ * Set (in our channel info database) the direct scan Tx power for 1 Mbit (CCK)
+ * or 6 Mbit (OFDM) rates.
+ */
+static void iwl_hw_reg_set_scan_power(struct iwl_priv *priv, u32 scan_tbl_index,
+			       s32 rate_index, const s8 *clip_pwrs,
+			       struct iwl_channel_info *ch_info,
+			       int band_index)
+{
+	struct iwl_scan_power_info *scan_power_info;
+	s8 power;
+	u8 power_index;
+
+	scan_power_info = &ch_info->scan_pwr_info[scan_tbl_index];
+
+	/* use this channel group's 6Mbit clipping/saturation pwr,
+	 *   but cap at regulatory scan power restriction (set during init
+	 *   based on eeprom channel data) for this channel.  */
+	power = min(ch_info->scan_power, clip_pwrs[IWL_RATE_6M_INDEX]);
+
+	/* further limit to user's max power preference.
+	 * FIXME:  Other spectrum management power limitations do not
+	 *   seem to apply?? */
+	power = min(power, priv->user_txpower_limit);
+	scan_power_info->requested_power = power;
+
+	/* find difference between new scan *power* and current "normal"
+	 *   Tx *power* for 6Mb.  Use this difference (x2) to adjust the
+	 *   current "normal" temperature-compensated Tx power *index* for
+	 *   this rate (1Mb or 6Mb) to yield new temp-compensated scan power
+	 *   *index*. */
+	power_index = ch_info->power_info[rate_index].power_table_index
+	    - (power - ch_info->power_info
+	       [IWL_RATE_6M_INDEX].requested_power) * 2;
+
+	/* store reference index that we use when adjusting *all* scan
+	 *   powers.  So we can accommodate user (all channel) or spectrum
+	 *   management (single channel) power changes "between" temperature
+	 *   feedback compensation procedures.
+	 * don't force fit this reference index into gain table; it may be a
+	 *   negative number.  This will help avoid errors when we're at
+	 *   the lower bounds (highest gains, for warmest temperatures)
+	 *   of the table. */
+
+	/* don't exceed table bounds for "real" setting */
+	power_index = iwl_hw_reg_fix_power_index(power_index);
+
+	scan_power_info->power_table_index = power_index;
+	scan_power_info->tpc.tx_gain =
+	    power_gain_table[band_index][power_index].tx_gain;
+	scan_power_info->tpc.dsp_atten =
+	    power_gain_table[band_index][power_index].dsp_atten;
+}
+
+/**
+ * iwl_hw_reg_send_txpower - fill in Tx Power command with gain settings
+ *
+ * Configures power settings for all rates for the current channel,
+ * using values from channel info struct, and send to NIC
+ */
+int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
+{
+	int rate_idx;
+	const struct iwl_channel_info *ch_info = NULL;
+	struct iwl_txpowertable_cmd txpower = {
+		.channel = priv->active_rxon.channel,
+	};
+
+	txpower.band = (priv->phymode == MODE_IEEE80211A) ? 0 : 1;
+	ch_info = iwl_get_channel_info(priv,
+				       priv->phymode,
+				       le16_to_cpu(priv->active_rxon.channel));
+	if (!ch_info) {
+		IWL_ERROR
+		    ("Failed to get channel info for channel %d [%d]\n",
+		     le16_to_cpu(priv->active_rxon.channel), priv->phymode);
+		return -EINVAL;
+	}
+
+	if (!is_channel_valid(ch_info)) {
+		IWL_DEBUG_POWER("Not calling TX_PWR_TABLE_CMD on "
+				"non-Tx channel.\n");
+		return 0;
+	}
+
+	/* fill cmd with power settings for all rates for current channel */
+	for (rate_idx = 0; rate_idx < IWL_RATE_COUNT; rate_idx++) {
+		txpower.power[rate_idx].tpc = ch_info->power_info[rate_idx].tpc;
+		txpower.power[rate_idx].rate = iwl_rates[rate_idx].plcp;
+
+		IWL_DEBUG_POWER("ch %d:%d rf %d dsp %3d rate code 0x%02x\n",
+				le16_to_cpu(txpower.channel),
+				txpower.band,
+				txpower.power[rate_idx].tpc.tx_gain,
+				txpower.power[rate_idx].tpc.dsp_atten,
+				txpower.power[rate_idx].rate);
+	}
+
+	return iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD,
+				sizeof(struct iwl_txpowertable_cmd), &txpower);
+
+}
+
+/**
+ * iwl_hw_reg_set_new_power - Configures power tables at new levels
+ * @ch_info: Channel to update.  Uses power_info.requested_power.
+ *
+ * Replace requested_power and base_power_index ch_info fields for
+ * one channel.
+ *
+ * Called if user or spectrum management changes power preferences.
+ * Takes into account h/w and modulation limitations (clip power).
+ *
+ * This does *not* send anything to NIC, just sets up ch_info for one channel.
+ *
+ * NOTE: reg_compensate_for_temperature_dif() *must* be run after this to
+ *	 properly fill out the scan powers, and actual h/w gain settings,
+ *	 and send changes to NIC
+ */
+static int iwl_hw_reg_set_new_power(struct iwl_priv *priv,
+			     struct iwl_channel_info *ch_info)
+{
+	struct iwl_channel_power_info *power_info;
+	int power_changed = 0;
+	int i;
+	const s8 *clip_pwrs;
+	int power;
+
+	/* Get this chnlgrp's rate-to-max/clip-powers table */
+	clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers;
+
+	/* Get this channel's rate-to-current-power settings table */
+	power_info = ch_info->power_info;
+
+	/* update OFDM Txpower settings */
+	for (i = IWL_FIRST_OFDM_RATE; i <= IWL_LAST_OFDM_RATE;
+	     i++, ++power_info) {
+		int delta_idx;
+
+		/* limit new power to be no more than h/w capability */
+		power = min(ch_info->curr_txpow, clip_pwrs[i]);
+		if (power == power_info->requested_power)
+			continue;
+
+		/* find difference between old and new requested powers,
+		 *    update base (non-temp-compensated) power index */
+		delta_idx = (power - power_info->requested_power) * 2;
+		power_info->base_power_index -= delta_idx;
+
+		/* save new requested power value */
+		power_info->requested_power = power;
+
+		power_changed = 1;
+	}
+
+	/* update CCK Txpower settings, based on OFDM 12M setting ...
+	 *    ... all CCK power settings for a given channel are the *same*. */
+	if (power_changed) {
+		power =
+		    ch_info->power_info[IWL_RATE_12M_INDEX].
+		    requested_power + IWL_CCK_FROM_OFDM_POWER_DIFF;
+
+		/* do all CCK rates' iwl_channel_power_info structures */
+		for (i = IWL_FIRST_CCK_RATE; i <= IWL_LAST_CCK_RATE; i++) {
+			power_info->requested_power = power;
+			power_info->base_power_index =
+			    ch_info->power_info[IWL_RATE_12M_INDEX].
+			    base_power_index + IWL_CCK_FROM_OFDM_INDEX_DIFF;
+			++power_info;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * iwl_hw_reg_get_ch_txpower_limit - returns new power limit for channel
+ *
+ * NOTE: Returned power limit may be less (but not more) than requested,
+ *	 based strictly on regulatory (eeprom and spectrum mgt) limitations
+ *	 (no consideration for h/w clipping limitations).
+ */
+static int iwl_hw_reg_get_ch_txpower_limit(struct iwl_channel_info *ch_info)
+{
+	s8 max_power;
+
+#if 0
+	/* if we're using TGd limits, use lower of TGd or EEPROM */
+	if (ch_info->tgd_data.max_power != 0)
+		max_power = min(ch_info->tgd_data.max_power,
+				ch_info->eeprom.max_power_avg);
+
+	/* else just use EEPROM limits */
+	else
+#endif
+		max_power = ch_info->eeprom.max_power_avg;
+
+	return min(max_power, ch_info->max_power_avg);
+}
+
+/**
+ * iwl_hw_reg_comp_txpower_temp - Compensate for temperature
+ *
+ * Compensate txpower settings of *all* channels for temperature.
+ * This only accounts for the difference between current temperature
+ *   and the factory calibration temperatures, and bases the new settings
+ *   on the channel's base_power_index.
+ *
+ * If RxOn is "associated", this sends the new Txpower to NIC!
+ */
+static int iwl_hw_reg_comp_txpower_temp(struct iwl_priv *priv)
+{
+	struct iwl_channel_info *ch_info = NULL;
+	int delta_index;
+	const s8 *clip_pwrs; /* array of h/w max power levels for each rate */
+	u8 a_band;
+	u8 rate_index;
+	u8 scan_tbl_index;
+	u8 i;
+	int ref_temp;
+	int temperature = priv->temperature;
+
+	/* set up new Tx power info for each and every channel, 2.4 and 5.x */
+	for (i = 0; i < priv->channel_count; i++) {
+		ch_info = &priv->channel_info[i];
+		a_band = is_channel_a_band(ch_info);
+
+		/* Get this chnlgrp's factory calibration temperature */
+		ref_temp = (s16)priv->eeprom.groups[ch_info->group_index].
+		    temperature;
+
+		/* get power index adjustment based on curr and factory
+		 * temps */
+		delta_index = iwl_hw_reg_adjust_power_by_temp(temperature,
+							      ref_temp);
+
+		/* set tx power value for all rates, OFDM and CCK */
+		for (rate_index = 0; rate_index < IWL_RATE_COUNT;
+		     rate_index++) {
+			int power_idx =
+			    ch_info->power_info[rate_index].base_power_index;
+
+			/* temperature compensate */
+			power_idx += delta_index;
+
+			/* stay within table range */
+			power_idx = iwl_hw_reg_fix_power_index(power_idx);
+			ch_info->power_info[rate_index].
+			    power_table_index = (u8) power_idx;
+			ch_info->power_info[rate_index].tpc =
+			    power_gain_table[a_band][power_idx];
+		}
+
+		/* Get this chnlgrp's rate-to-max/clip-powers table */
+		clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers;
+
+		/* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */
+		for (scan_tbl_index = 0;
+		     scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) {
+			s32 actual_index = (scan_tbl_index == 0) ?
+			    IWL_RATE_1M_INDEX : IWL_RATE_6M_INDEX;
+			iwl_hw_reg_set_scan_power(priv, scan_tbl_index,
+					   actual_index, clip_pwrs,
+					   ch_info, a_band);
+		}
+	}
+
+	/* send Txpower command for current channel to ucode */
+	return iwl_hw_reg_send_txpower(priv);
+}
+
+int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
+{
+	struct iwl_channel_info *ch_info;
+	s8 max_power;
+	u8 a_band;
+	u8 i;
+
+	if (priv->user_txpower_limit == power) {
+		IWL_DEBUG_POWER("Requested Tx power same as current "
+				"limit: %ddBm.\n", power);
+		return 0;
+	}
+
+	IWL_DEBUG_POWER("Setting upper limit clamp to %ddBm.\n", power);
+	priv->user_txpower_limit = power;
+
+	/* set up new Tx powers for each and every channel, 2.4 and 5.x */
+
+	for (i = 0; i < priv->channel_count; i++) {
+		ch_info = &priv->channel_info[i];
+		a_band = is_channel_a_band(ch_info);
+
+		/* find minimum power of all user and regulatory constraints
+		 *    (does not consider h/w clipping limitations) */
+		max_power = iwl_hw_reg_get_ch_txpower_limit(ch_info);
+		max_power = min(power, max_power);
+		if (max_power != ch_info->curr_txpow) {
+			ch_info->curr_txpow = max_power;
+
+			/* this considers the h/w clipping limitations */
+			iwl_hw_reg_set_new_power(priv, ch_info);
+		}
+	}
+
+	/* update txpower settings for all channels,
+	 *   send to NIC if associated. */
+	is_temp_calib_needed(priv);
+	iwl_hw_reg_comp_txpower_temp(priv);
+
+	return 0;
+}
+
+/* will add 3945 channel switch cmd handling later */
+int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+{
+	return 0;
+}
+
+/**
+ * iwl3945_reg_txpower_periodic -  called when time to check our temperature.
+ *
+ * -- reset periodic timer
+ * -- see if temp has changed enough to warrant re-calibration ... if so:
+ *     -- correct coeffs for temp (can reset temp timer)
+ *     -- save this temp as "last",
+ *     -- send new set of gain settings to NIC
+ * NOTE:  This should continue working, even when we're not associated,
+ *   so we can keep our internal table of scan powers current. */
+void iwl3945_reg_txpower_periodic(struct iwl_priv *priv)
+{
+	/* This will kick in the "brute force"
+	 * iwl_hw_reg_comp_txpower_temp() below */
+	if (!is_temp_calib_needed(priv))
+		goto reschedule;
+
+	/* Set up a new set of temp-adjusted TxPowers, send to NIC.
+	 * This is based *only* on current temperature,
+	 * ignoring any previous power measurements */
+	iwl_hw_reg_comp_txpower_temp(priv);
+
+ reschedule:
+	queue_delayed_work(priv->workqueue,
+			   &priv->thermal_periodic, REG_RECALIB_PERIOD * HZ);
+}
+
+void iwl3945_bg_reg_txpower_periodic(struct work_struct *work)
+{
+	struct iwl_priv *priv = container_of(work, struct iwl_priv,
+					     thermal_periodic.work);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	iwl3945_reg_txpower_periodic(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+/**
+ * iwl_hw_reg_get_ch_grp_index - find the channel-group index (0-4)
+ * 				   for the channel.
+ *
+ * This function is used when initializing channel-info structs.
+ *
+ * NOTE: These channel groups do *NOT* match the bands above!
+ *	 These channel groups are based on factory-tested channels;
+ *	 on A-band, EEPROM's "group frequency" entries represent the top
+ *	 channel in each group 1-4.  Group 5 All B/G channels are in group 0.
+ */
+static u16 iwl_hw_reg_get_ch_grp_index(struct iwl_priv *priv,
+				       const struct iwl_channel_info *ch_info)
+{
+	struct iwl_eeprom_txpower_group *ch_grp = &priv->eeprom.groups[0];
+	u8 group;
+	u16 group_index = 0;	/* based on factory calib frequencies */
+	u8 grp_channel;
+
+	/* Find the group index for the channel ... don't use index 1(?) */
+	if (is_channel_a_band(ch_info)) {
+		for (group = 1; group < 5; group++) {
+			grp_channel = ch_grp[group].group_channel;
+			if (ch_info->channel <= grp_channel) {
+				group_index = group;
+				break;
+			}
+		}
+		/* group 4 has a few channels *above* its factory cal freq */
+		if (group == 5)
+			group_index = 4;
+	} else
+		group_index = 0;	/* 2.4 GHz, group 0 */
+
+	IWL_DEBUG_POWER("Chnl %d mapped to grp %d\n", ch_info->channel,
+			group_index);
+	return group_index;
+}
+
+/**
+ * iwl_hw_reg_get_matched_power_index - Interpolate to get nominal index
+ *
+ * Interpolate to get nominal (i.e. at factory calibration temperature) index
+ *   into radio/DSP gain settings table for requested power.
+ */
+static int iwl_hw_reg_get_matched_power_index(struct iwl_priv *priv,
+				       s8 requested_power,
+				       s32 setting_index, s32 *new_index)
+{
+	const struct iwl_eeprom_txpower_group *chnl_grp = NULL;
+	s32 index0, index1;
+	s32 power = 2 * requested_power;
+	s32 i;
+	const struct iwl_eeprom_txpower_sample *samples;
+	s32 gains0, gains1;
+	s32 res;
+	s32 denominator;
+
+	chnl_grp = &priv->eeprom.groups[setting_index];
+	samples = chnl_grp->samples;
+	for (i = 0; i < 5; i++) {
+		if (power == samples[i].power) {
+			*new_index = samples[i].gain_index;
+			return 0;
+		}
+	}
+
+	if (power > samples[1].power) {
+		index0 = 0;
+		index1 = 1;
+	} else if (power > samples[2].power) {
+		index0 = 1;
+		index1 = 2;
+	} else if (power > samples[3].power) {
+		index0 = 2;
+		index1 = 3;
+	} else {
+		index0 = 3;
+		index1 = 4;
+	}
+
+	denominator = (s32) samples[index1].power - (s32) samples[index0].power;
+	if (denominator == 0)
+		return -EINVAL;
+	gains0 = (s32) samples[index0].gain_index * (1 << 19);
+	gains1 = (s32) samples[index1].gain_index * (1 << 19);
+	res = gains0 + (gains1 - gains0) *
+	    ((s32) power - (s32) samples[index0].power) / denominator +
+	    (1 << 18);
+	*new_index = res >> 19;
+	return 0;
+}
+
+static void iwl_hw_reg_init_channel_groups(struct iwl_priv *priv)
+{
+	u32 i;
+	s32 rate_index;
+	const struct iwl_eeprom_txpower_group *group;
+
+	IWL_DEBUG_POWER("Initializing factory calib info from EEPROM\n");
+
+	for (i = 0; i < IWL_NUM_TX_CALIB_GROUPS; i++) {
+		s8 *clip_pwrs;	/* table of power levels for each rate */
+		s8 satur_pwr;	/* saturation power for each chnl group */
+		group = &priv->eeprom.groups[i];
+
+		/* sanity check on factory saturation power value */
+		if (group->saturation_power < 40) {
+			IWL_WARNING("Error: saturation power is %d, "
+				    "less than minimum expected 40\n",
+				    group->saturation_power);
+			return;
+		}
+
+		/*
+		 * Derive requested power levels for each rate, based on
+		 *   hardware capabilities (saturation power for band).
+		 * Basic value is 3dB down from saturation, with further
+		 *   power reductions for highest 3 data rates.  These
+		 *   backoffs provide headroom for high rate modulation
+		 *   power peaks, without too much distortion (clipping).
+		 */
+		/* we'll fill in this array with h/w max power levels */
+		clip_pwrs = (s8 *) priv->clip_groups[i].clip_powers;
+
+		/* divide factory saturation power by 2 to find -3dB level */
+		satur_pwr = (s8) (group->saturation_power >> 1);
+
+		/* fill in channel group's nominal powers for each rate */
+		for (rate_index = 0;
+		     rate_index < IWL_RATE_COUNT; rate_index++, clip_pwrs++) {
+			switch (rate_index) {
+			case IWL_RATE_36M_INDEX:
+				if (i == 0)	/* B/G */
+					*clip_pwrs = satur_pwr;
+				else	/* A */
+					*clip_pwrs = satur_pwr - 5;
+				break;
+			case IWL_RATE_48M_INDEX:
+				if (i == 0)
+					*clip_pwrs = satur_pwr - 7;
+				else
+					*clip_pwrs = satur_pwr - 10;
+				break;
+			case IWL_RATE_54M_INDEX:
+				if (i == 0)
+					*clip_pwrs = satur_pwr - 9;
+				else
+					*clip_pwrs = satur_pwr - 12;
+				break;
+			default:
+				*clip_pwrs = satur_pwr;
+				break;
+			}
+		}
+	}
+}
+
+/**
+ * iwl3945_txpower_set_from_eeprom - Set channel power info based on EEPROM
+ *
+ * Second pass (during init) to set up priv->channel_info
+ *
+ * Set up Tx-power settings in our channel info database for each VALID
+ * (for this geo/SKU) channel, at all Tx data rates, based on eeprom values
+ * and current temperature.
+ *
+ * Since this is based on current temperature (at init time), these values may
+ * not be valid for very long, but it gives us a starting/default point,
+ * and allows us to active (i.e. using Tx) scan.
+ *
+ * This does *not* write values to NIC, just sets up our internal table.
+ */
+int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv)
+{
+	struct iwl_channel_info *ch_info = NULL;
+	struct iwl_channel_power_info *pwr_info;
+	int delta_index;
+	u8 rate_index;
+	u8 scan_tbl_index;
+	const s8 *clip_pwrs;	/* array of power levels for each rate */
+	u8 gain, dsp_atten;
+	s8 power;
+	u8 pwr_index, base_pwr_index, a_band;
+	u8 i;
+	int temperature;
+
+	/* save temperature reference,
+	 *   so we can determine next time to calibrate */
+	temperature = iwl_hw_reg_txpower_get_temperature(priv);
+	priv->last_temperature = temperature;
+
+	iwl_hw_reg_init_channel_groups(priv);
+
+	/* initialize Tx power info for each and every channel, 2.4 and 5.x */
+	for (i = 0, ch_info = priv->channel_info; i < priv->channel_count;
+	     i++, ch_info++) {
+		a_band = is_channel_a_band(ch_info);
+		if (!is_channel_valid(ch_info))
+			continue;
+
+		/* find this channel's channel group (*not* "band") index */
+		ch_info->group_index =
+			iwl_hw_reg_get_ch_grp_index(priv, ch_info);
+
+		/* Get this chnlgrp's rate->max/clip-powers table */
+		clip_pwrs = priv->clip_groups[ch_info->group_index].clip_powers;
+
+		/* calculate power index *adjustment* value according to
+		 *  diff between current temperature and factory temperature */
+		delta_index = iwl_hw_reg_adjust_power_by_temp(temperature,
+				priv->eeprom.groups[ch_info->group_index].
+				temperature);
+
+		IWL_DEBUG_POWER("Delta index for channel %d: %d [%d]\n",
+				ch_info->channel, delta_index, temperature +
+				IWL_TEMP_CONVERT);
+
+		/* set tx power value for all OFDM rates */
+		for (rate_index = 0; rate_index < IWL_OFDM_RATES;
+		     rate_index++) {
+			s32 power_idx;
+			int rc;
+
+			/* use channel group's clip-power table,
+			 *   but don't exceed channel's max power */
+			s8 pwr = min(ch_info->max_power_avg,
+				     clip_pwrs[rate_index]);
+
+			pwr_info = &ch_info->power_info[rate_index];
+
+			/* get base (i.e. at factory-measured temperature)
+			 *    power table index for this rate's power */
+			rc = iwl_hw_reg_get_matched_power_index(priv, pwr,
+							 ch_info->group_index,
+							 &power_idx);
+			if (rc) {
+				IWL_ERROR("Invalid power index\n");
+				return rc;
+			}
+			pwr_info->base_power_index = (u8) power_idx;
+
+			/* temperature compensate */
+			power_idx += delta_index;
+
+			/* stay within range of gain table */
+			power_idx = iwl_hw_reg_fix_power_index(power_idx);
+
+			/* fill 1 OFDM rate's iwl_channel_power_info struct */
+			pwr_info->requested_power = pwr;
+			pwr_info->power_table_index = (u8) power_idx;
+			pwr_info->tpc.tx_gain =
+			    power_gain_table[a_band][power_idx].tx_gain;
+			pwr_info->tpc.dsp_atten =
+			    power_gain_table[a_band][power_idx].dsp_atten;
+		}
+
+		/* set tx power for CCK rates, based on OFDM 12 Mbit settings*/
+		pwr_info = &ch_info->power_info[IWL_RATE_12M_INDEX];
+		power = pwr_info->requested_power +
+			IWL_CCK_FROM_OFDM_POWER_DIFF;
+		pwr_index = pwr_info->power_table_index +
+			IWL_CCK_FROM_OFDM_INDEX_DIFF;
+		base_pwr_index = pwr_info->base_power_index +
+			IWL_CCK_FROM_OFDM_INDEX_DIFF;
+
+		/* stay within table range */
+		pwr_index = iwl_hw_reg_fix_power_index(pwr_index);
+		gain = power_gain_table[a_band][pwr_index].tx_gain;
+		dsp_atten = power_gain_table[a_band][pwr_index].dsp_atten;
+
+		/* fill each CCK rate's iwl_channel_power_info structure
+		 * NOTE:  All CCK-rate Txpwrs are the same for a given chnl!
+		 * NOTE:  CCK rates start at end of OFDM rates! */
+		for (rate_index = IWL_OFDM_RATES;
+		     rate_index < IWL_RATE_COUNT; rate_index++) {
+			pwr_info = &ch_info->power_info[rate_index];
+			pwr_info->requested_power = power;
+			pwr_info->power_table_index = pwr_index;
+			pwr_info->base_power_index = base_pwr_index;
+			pwr_info->tpc.tx_gain = gain;
+			pwr_info->tpc.dsp_atten = dsp_atten;
+		}
+
+		/* set scan tx power, 1Mbit for CCK, 6Mbit for OFDM */
+		for (scan_tbl_index = 0;
+		     scan_tbl_index < IWL_NUM_SCAN_RATES; scan_tbl_index++) {
+			s32 actual_index = (scan_tbl_index == 0) ?
+				IWL_RATE_1M_INDEX : IWL_RATE_6M_INDEX;
+			iwl_hw_reg_set_scan_power(priv, scan_tbl_index,
+				actual_index, clip_pwrs, ch_info, a_band);
+		}
+	}
+
+	return 0;
+}
+
+int iwl_hw_rxq_stop(struct iwl_priv *priv)
+{
+	int rc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+
+	iwl_write_restricted(priv, FH_RCSR_CONFIG(0), 0);
+	rc = iwl_poll_restricted_bit(priv, FH_RSSR_STATUS, (1 << 24), 1000);
+	if (rc < 0)
+		IWL_ERROR("Can't stop Rx DMA.\n");
+
+	iwl_release_restricted_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+	int rc;
+	unsigned long flags;
+	int txq_id = txq->q.id;
+
+	struct iwl_shared *shared_data = priv->hw_setting.shared_virt;
+
+	shared_data->tx_base_ptr[txq_id] = cpu_to_le32((u32)txq->q.dma_addr);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+	iwl_write_restricted(priv, FH_CBCC_CTRL(txq_id), 0);
+	iwl_write_restricted(priv, FH_CBCC_BASE(txq_id), 0);
+
+	iwl_write_restricted(priv, FH_TCSR_CONFIG(txq_id),
+		ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT |
+		ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF |
+		ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD |
+		ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL |
+		ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE);
+	iwl_release_restricted_access(priv);
+
+	/* fake read to flush all prev. writes */
+	iwl_read32(priv, FH_TSSR_CBB_BASE);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+int iwl_hw_get_rx_read(struct iwl_priv *priv)
+{
+	struct iwl_shared *shared_data = priv->hw_setting.shared_virt;
+
+	return le32_to_cpu(shared_data->rx_read_ptr[0]);
+}
+
+/**
+ * iwl3945_init_hw_rate_table - Initialize the hardware rate fallback table
+ */
+int iwl3945_init_hw_rate_table(struct iwl_priv *priv)
+{
+	int rc, i;
+	struct iwl_rate_scaling_cmd rate_cmd = {
+		.reserved = {0, 0, 0},
+	};
+	struct iwl_rate_scaling_info *table = rate_cmd.table;
+
+	for (i = 0; i < ARRAY_SIZE(iwl_rates); i++) {
+		table[i].rate_n_flags =
+			iwl_hw_set_rate_n_flags(iwl_rates[i].plcp, 0);
+		table[i].try_cnt = priv->retry_rate;
+		table[i].next_rate_index = iwl_get_prev_ieee_rate(i);
+	}
+
+	switch (priv->phymode) {
+	case MODE_IEEE80211A:
+		IWL_DEBUG_RATE("Select A mode rate scale\n");
+		/* If one of the following CCK rates is used,
+		 * have it fall back to the 6M OFDM rate */
+		for (i = IWL_FIRST_CCK_RATE; i <= IWL_LAST_CCK_RATE; i++)
+			table[i].next_rate_index = IWL_FIRST_OFDM_RATE;
+
+		/* Don't fall back to CCK rates */
+		table[IWL_RATE_12M_INDEX].next_rate_index = IWL_RATE_9M_INDEX;
+
+		/* Don't drop out of OFDM rates */
+		table[IWL_FIRST_OFDM_RATE].next_rate_index =
+		    IWL_FIRST_OFDM_RATE;
+		break;
+
+	case MODE_IEEE80211B:
+		IWL_DEBUG_RATE("Select B mode rate scale\n");
+		/* If an OFDM rate is used, have it fall back to the
+		 * 1M CCK rates */
+		for (i = IWL_FIRST_OFDM_RATE; i <= IWL_LAST_OFDM_RATE; i++)
+			table[i].next_rate_index = IWL_FIRST_CCK_RATE;
+
+		/* CCK shouldn't fall back to OFDM... */
+		table[IWL_RATE_11M_INDEX].next_rate_index = IWL_RATE_5M_INDEX;
+		break;
+
+	default:
+		IWL_DEBUG_RATE("Select G mode rate scale\n");
+		break;
+	}
+
+	/* Update the rate scaling for control frame Tx */
+	rate_cmd.table_id = 0;
+	rc = iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
+			      &rate_cmd);
+	if (rc)
+		return rc;
+
+	/* Update the rate scaling for data frame Tx */
+	rate_cmd.table_id = 1;
+	return iwl_send_cmd_pdu(priv, REPLY_RATE_SCALE, sizeof(rate_cmd),
+				&rate_cmd);
+}
+
+int iwl_hw_set_hw_setting(struct iwl_priv *priv)
+{
+	memset((void *)&priv->hw_setting, 0,
+	       sizeof(struct iwl_driver_hw_info));
+
+	priv->hw_setting.shared_virt =
+	    pci_alloc_consistent(priv->pci_dev,
+				 sizeof(struct iwl_shared),
+				 &priv->hw_setting.shared_phys);
+
+	if (!priv->hw_setting.shared_virt) {
+		IWL_ERROR("failed to allocate pci memory\n");
+		mutex_unlock(&priv->mutex);
+		return -ENOMEM;
+	}
+
+	priv->hw_setting.ac_queue_count = AC_NUM;
+	priv->hw_setting.rx_buffer_size = IWL_RX_BUF_SIZE;
+	priv->hw_setting.tx_cmd_len = sizeof(struct iwl_tx_cmd);
+	priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE;
+	priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG;
+	priv->hw_setting.cck_flag = 0;
+	priv->hw_setting.max_stations = IWL3945_STATION_COUNT;
+	priv->hw_setting.bcast_sta_id = IWL3945_BROADCAST_ID;
+	return 0;
+}
+
+unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
+			  struct iwl_frame *frame, u8 rate)
+{
+	struct iwl_tx_beacon_cmd *tx_beacon_cmd;
+	unsigned int frame_size;
+
+	tx_beacon_cmd = (struct iwl_tx_beacon_cmd *)&frame->u;
+	memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
+
+	tx_beacon_cmd->tx.sta_id = IWL3945_BROADCAST_ID;
+	tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+	frame_size = iwl_fill_beacon_frame(priv,
+				tx_beacon_cmd->frame,
+				BROADCAST_ADDR,
+				sizeof(frame->u) - sizeof(*tx_beacon_cmd));
+
+	BUG_ON(frame_size > MAX_MPDU_SIZE);
+	tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
+
+	tx_beacon_cmd->tx.rate = rate;
+	tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK |
+				      TX_CMD_FLG_TSF_MSK);
+
+	/* supp_rates[0] == OFDM  */
+	tx_beacon_cmd->tx.supp_rates[0] = IWL_OFDM_BASIC_RATES_MASK;
+
+	/* supp_rates[1] == CCK
+	 *
+	 * NOTE:  IWL_*_RATES_MASK are not in the order that supp_rates
+	 * expects so we have to shift them around.
+	 *
+	 * supp_rates expects:
+	 * CCK rates are bit0..3
+	 *
+	 * However IWL_*_RATES_MASK has:
+	 * CCK rates are bit8..11
+	 */
+	tx_beacon_cmd->tx.supp_rates[1] =
+		(IWL_CCK_BASIC_RATES_MASK >> 8) & 0xF;
+
+	return (sizeof(struct iwl_tx_beacon_cmd) + frame_size);
+}
+
+void iwl_hw_rx_handler_setup(struct iwl_priv *priv)
+{
+	priv->rx_handlers[REPLY_3945_RX] = iwl3945_rx_reply_rx;
+}
+
+void iwl_hw_setup_deferred_work(struct iwl_priv *priv)
+{
+	INIT_DELAYED_WORK(&priv->thermal_periodic,
+			  iwl3945_bg_reg_txpower_periodic);
+}
+
+void iwl_hw_cancel_deferred_work(struct iwl_priv *priv)
+{
+	cancel_delayed_work(&priv->thermal_periodic);
+}
+
+struct pci_device_id iwl_hw_card_ids[] = {
+	{0x8086, 0x4222, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x4227, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0}
+};
+
+inline int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv)
+{
+	_iwl_clear_bit(priv, CSR_EEPROM_GP, CSR_EEPROM_GP_IF_OWNER_MSK);
+	return 0;
+}
+
+MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
new file mode 100644
index 0000000..813902e
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_3945_h__
+#define __iwl_3945_h__
+
+/*
+ * Forward declare iwl-3945.c functions for iwl-base.c
+ */
+extern int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv);
+extern __le32 iwl3945_get_antenna_flags(const struct iwl_priv *priv);
+extern int iwl3945_init_hw_rate_table(struct iwl_priv *priv);
+extern void iwl3945_reg_txpower_periodic(struct iwl_priv *priv);
+extern void iwl3945_bg_reg_txpower_periodic(struct work_struct *work);
+extern int iwl3945_txpower_set_from_eeprom(struct iwl_priv *priv);
+extern u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id,
+		 u16 tx_rate, u8 flags);
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
new file mode 100644
index 0000000..99a19ef
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -0,0 +1,581 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_4965_hw_h__
+#define __iwl_4965_hw_h__
+
+#define IWL_RX_BUF_SIZE (4 * 1024)
+#define IWL_MAX_BSM_SIZE BSM_SRAM_SIZE
+#define KDR_RTC_INST_UPPER_BOUND		(0x018000)
+#define KDR_RTC_DATA_UPPER_BOUND		(0x80A000)
+#define KDR_RTC_INST_SIZE    (KDR_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND)
+#define KDR_RTC_DATA_SIZE    (KDR_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND)
+
+#define IWL_MAX_INST_SIZE KDR_RTC_INST_SIZE
+#define IWL_MAX_DATA_SIZE KDR_RTC_DATA_SIZE
+
+static inline int iwl_hw_valid_rtc_data_addr(u32 addr)
+{
+	return (addr >= RTC_DATA_LOWER_BOUND) &&
+	       (addr < KDR_RTC_DATA_UPPER_BOUND);
+}
+
+/********************* START TXPOWER *****************************************/
+enum {
+	HT_IE_EXT_CHANNEL_NONE = 0,
+	HT_IE_EXT_CHANNEL_ABOVE,
+	HT_IE_EXT_CHANNEL_INVALID,
+	HT_IE_EXT_CHANNEL_BELOW,
+	HT_IE_EXT_CHANNEL_MAX
+};
+
+enum {
+	CALIB_CH_GROUP_1 = 0,
+	CALIB_CH_GROUP_2 = 1,
+	CALIB_CH_GROUP_3 = 2,
+	CALIB_CH_GROUP_4 = 3,
+	CALIB_CH_GROUP_5 = 4,
+	CALIB_CH_GROUP_MAX
+};
+
+/* Temperature calibration offset is 3% 0C in Kelvin */
+#define TEMPERATURE_CALIB_KELVIN_OFFSET 8
+#define TEMPERATURE_CALIB_A_VAL 259
+
+#define IWL_TX_POWER_TEMPERATURE_MIN  (263)
+#define IWL_TX_POWER_TEMPERATURE_MAX  (410)
+
+#define IWL_TX_POWER_TEMPERATURE_OUT_OF_RANGE(t) \
+	(((t) < IWL_TX_POWER_TEMPERATURE_MIN) || \
+	 ((t) > IWL_TX_POWER_TEMPERATURE_MAX))
+
+#define IWL_TX_POWER_ILLEGAL_TEMPERATURE (300)
+
+#define IWL_TX_POWER_TEMPERATURE_DIFFERENCE (2)
+
+#define IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION (6)
+
+#define IWL_TX_POWER_TARGET_POWER_MIN       (0)	/* 0 dBm = 1 milliwatt */
+#define IWL_TX_POWER_TARGET_POWER_MAX      (16)	/* 16 dBm */
+
+/* timeout equivalent to 3 minutes */
+#define IWL_TX_POWER_TIMELIMIT_NOCALIB 1800000000
+
+#define IWL_TX_POWER_CCK_COMPENSATION (9)
+
+#define MIN_TX_GAIN_INDEX		(0)
+#define MIN_TX_GAIN_INDEX_52GHZ_EXT	(-9)
+#define MAX_TX_GAIN_INDEX_52GHZ		(98)
+#define MIN_TX_GAIN_52GHZ		(98)
+#define MAX_TX_GAIN_INDEX_24GHZ		(98)
+#define MIN_TX_GAIN_24GHZ		(98)
+#define MAX_TX_GAIN			(0)
+#define MAX_TX_GAIN_52GHZ_EXT		(-9)
+
+#define IWL_TX_POWER_DEFAULT_REGULATORY_24   (34)
+#define IWL_TX_POWER_DEFAULT_REGULATORY_52   (34)
+#define IWL_TX_POWER_REGULATORY_MIN          (0)
+#define IWL_TX_POWER_REGULATORY_MAX          (34)
+#define IWL_TX_POWER_DEFAULT_SATURATION_24   (38)
+#define IWL_TX_POWER_DEFAULT_SATURATION_52   (38)
+#define IWL_TX_POWER_SATURATION_MIN          (20)
+#define IWL_TX_POWER_SATURATION_MAX          (50)
+
+/* dv *0.4 = dt; so that 5 degrees temperature diff equals
+ * 12.5 in voltage diff */
+#define IWL_TX_TEMPERATURE_UPDATE_LIMIT 9
+
+#define IWL_INVALID_CHANNEL                 (0xffffffff)
+#define IWL_TX_POWER_REGITRY_BIT            (2)
+
+#define MIN_IWL_TX_POWER_CALIB_DUR          (100)
+#define IWL_CCK_FROM_OFDM_POWER_DIFF        (-5)
+#define IWL_CCK_FROM_OFDM_INDEX_DIFF (9)
+
+/* Number of entries in the gain table */
+#define POWER_GAIN_NUM_ENTRIES 78
+#define TX_POW_MAX_SESSION_NUM 5
+/*  timeout equivalent to 3 minutes */
+#define TX_IWL_TIMELIMIT_NOCALIB 1800000000
+
+/* Kedron TX_CALIB_STATES */
+#define IWL_TX_CALIB_STATE_SEND_TX        0x00000001
+#define IWL_TX_CALIB_WAIT_TX_RESPONSE     0x00000002
+#define IWL_TX_CALIB_ENABLED              0x00000004
+#define IWL_TX_CALIB_XVT_ON               0x00000008
+#define IWL_TX_CALIB_TEMPERATURE_CORRECT  0x00000010
+#define IWL_TX_CALIB_WORKING_WITH_XVT     0x00000020
+#define IWL_TX_CALIB_XVT_PERIODICAL       0x00000040
+
+#define NUM_IWL_TX_CALIB_SETTINS 5	/* Number of tx correction groups */
+
+#define IWL_MIN_POWER_IN_VP_TABLE 1	/* 0.5dBm multiplied by 2 */
+#define IWL_MAX_POWER_IN_VP_TABLE 40	/* 20dBm - multiplied by 2 (because
+					 * entries are for each 0.5dBm) */
+#define IWL_STEP_IN_VP_TABLE 1	/* 0.5dB - multiplied by 2 */
+#define IWL_NUM_POINTS_IN_VPTABLE \
+	(1 + IWL_MAX_POWER_IN_VP_TABLE - IWL_MIN_POWER_IN_VP_TABLE)
+
+#define MIN_TX_GAIN_INDEX         (0)
+#define MAX_TX_GAIN_INDEX_52GHZ   (98)
+#define MIN_TX_GAIN_52GHZ         (98)
+#define MAX_TX_GAIN_INDEX_24GHZ   (98)
+#define MIN_TX_GAIN_24GHZ         (98)
+#define MAX_TX_GAIN               (0)
+
+/* First and last channels of all groups */
+#define CALIB_IWL_TX_ATTEN_GR1_FCH 34
+#define CALIB_IWL_TX_ATTEN_GR1_LCH 43
+#define CALIB_IWL_TX_ATTEN_GR2_FCH 44
+#define CALIB_IWL_TX_ATTEN_GR2_LCH 70
+#define CALIB_IWL_TX_ATTEN_GR3_FCH 71
+#define CALIB_IWL_TX_ATTEN_GR3_LCH 124
+#define CALIB_IWL_TX_ATTEN_GR4_FCH 125
+#define CALIB_IWL_TX_ATTEN_GR4_LCH 200
+#define CALIB_IWL_TX_ATTEN_GR5_FCH 1
+#define CALIB_IWL_TX_ATTEN_GR5_LCH 20
+
+
+union iwl_tx_power_dual_stream {
+	struct {
+		u8 radio_tx_gain[2];
+		u8 dsp_predis_atten[2];
+	} s;
+	u32 dw;
+};
+
+/********************* END TXPOWER *****************************************/
+
+/* HT flags */
+#define RXON_FLG_CTRL_CHANNEL_LOC_POS		(22)
+#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK	__constant_cpu_to_le32(0x1<<22)
+
+#define RXON_FLG_HT_OPERATING_MODE_POS		(23)
+
+#define RXON_FLG_HT_PROT_MSK			__constant_cpu_to_le32(0x1<<23)
+#define RXON_FLG_FAT_PROT_MSK			__constant_cpu_to_le32(0x2<<23)
+
+#define RXON_FLG_CHANNEL_MODE_POS		(25)
+#define RXON_FLG_CHANNEL_MODE_MSK		__constant_cpu_to_le32(0x3<<25)
+#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK	__constant_cpu_to_le32(0x1<<25)
+#define RXON_FLG_CHANNEL_MODE_MIXED_MSK		__constant_cpu_to_le32(0x2<<25)
+
+#define RXON_RX_CHAIN_DRIVER_FORCE_MSK		__constant_cpu_to_le16(0x1<<0)
+#define RXON_RX_CHAIN_VALID_MSK			__constant_cpu_to_le16(0x7<<1)
+#define RXON_RX_CHAIN_VALID_POS			(1)
+#define RXON_RX_CHAIN_FORCE_SEL_MSK		__constant_cpu_to_le16(0x7<<4)
+#define RXON_RX_CHAIN_FORCE_SEL_POS		(4)
+#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK	__constant_cpu_to_le16(0x7<<7)
+#define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS	(7)
+#define RXON_RX_CHAIN_CNT_MSK			__constant_cpu_to_le16(0x3<<10)
+#define RXON_RX_CHAIN_CNT_POS			(10)
+#define RXON_RX_CHAIN_MIMO_CNT_MSK		__constant_cpu_to_le16(0x3<<12)
+#define RXON_RX_CHAIN_MIMO_CNT_POS		(12)
+#define RXON_RX_CHAIN_MIMO_FORCE_MSK		__constant_cpu_to_le16(0x1<<14)
+#define RXON_RX_CHAIN_MIMO_FORCE_POS		(14)
+
+
+#define MCS_DUP_6M_PLCP 0x20
+
+/* OFDM HT rate masks */
+/* ***************************************** */
+#define R_MCS_6M_MSK 0x1
+#define R_MCS_12M_MSK 0x2
+#define R_MCS_18M_MSK 0x4
+#define R_MCS_24M_MSK 0x8
+#define R_MCS_36M_MSK 0x10
+#define R_MCS_48M_MSK 0x20
+#define R_MCS_54M_MSK 0x40
+#define R_MCS_60M_MSK 0x80
+#define R_MCS_12M_DUAL_MSK 0x100
+#define R_MCS_24M_DUAL_MSK 0x200
+#define R_MCS_36M_DUAL_MSK 0x400
+#define R_MCS_48M_DUAL_MSK 0x800
+
+#define is_legacy(tbl) (((tbl) == LQ_G) || ((tbl) == LQ_A))
+#define is_siso(tbl) (((tbl) == LQ_SISO))
+#define is_mimo(tbl) (((tbl) == LQ_MIMO))
+#define is_Ht(tbl) (is_siso(tbl) || is_mimo(tbl))
+#define is_a_band(tbl) (((tbl) == LQ_A))
+#define is_g_and(tbl) (((tbl) == LQ_G))
+
+/* Flow Handler Definitions */
+
+/**********************/
+/*     Addresses      */
+/**********************/
+
+#define FH_MEM_LOWER_BOUND                   (0x1000)
+#define FH_MEM_UPPER_BOUND                   (0x1EF0)
+
+#define IWL_FH_REGS_LOWER_BOUND		     (0x1000)
+#define IWL_FH_REGS_UPPER_BOUND		     (0x2000)
+
+#define IWL_FH_KW_MEM_ADDR_REG		     (FH_MEM_LOWER_BOUND + 0x97C)
+
+/* CBBC Area - Circular buffers base address cache pointers table */
+#define FH_MEM_CBBC_LOWER_BOUND              (FH_MEM_LOWER_BOUND + 0x9D0)
+#define FH_MEM_CBBC_UPPER_BOUND              (FH_MEM_LOWER_BOUND + 0xA10)
+/* queues 0 - 15 */
+#define FH_MEM_CBBC_QUEUE(x)  (FH_MEM_CBBC_LOWER_BOUND + (x) * 0x4)
+
+/* RSCSR Area */
+#define FH_MEM_RSCSR_LOWER_BOUND	(FH_MEM_LOWER_BOUND + 0xBC0)
+#define FH_MEM_RSCSR_UPPER_BOUND	(FH_MEM_LOWER_BOUND + 0xC00)
+#define FH_MEM_RSCSR_CHNL0		(FH_MEM_RSCSR_LOWER_BOUND)
+
+#define FH_RSCSR_CHNL0_STTS_WPTR_REG		(FH_MEM_RSCSR_CHNL0)
+#define FH_RSCSR_CHNL0_RBDCB_BASE_REG		(FH_MEM_RSCSR_CHNL0 + 0x004)
+#define FH_RSCSR_CHNL0_RBDCB_WPTR_REG		(FH_MEM_RSCSR_CHNL0 + 0x008)
+
+/* RCSR Area - Registers address map */
+#define FH_MEM_RCSR_LOWER_BOUND      (FH_MEM_LOWER_BOUND + 0xC00)
+#define FH_MEM_RCSR_UPPER_BOUND      (FH_MEM_LOWER_BOUND + 0xCC0)
+#define FH_MEM_RCSR_CHNL0            (FH_MEM_RCSR_LOWER_BOUND)
+
+#define FH_MEM_RCSR_CHNL0_CONFIG_REG	(FH_MEM_RCSR_CHNL0)
+
+/* RSSR Area - Rx shared ctrl & status registers */
+#define FH_MEM_RSSR_LOWER_BOUND                	(FH_MEM_LOWER_BOUND + 0xC40)
+#define FH_MEM_RSSR_UPPER_BOUND               	(FH_MEM_LOWER_BOUND + 0xD00)
+#define FH_MEM_RSSR_SHARED_CTRL_REG           	(FH_MEM_RSSR_LOWER_BOUND)
+#define FH_MEM_RSSR_RX_STATUS_REG	(FH_MEM_RSSR_LOWER_BOUND + 0x004)
+#define FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV  (FH_MEM_RSSR_LOWER_BOUND + 0x008)
+
+/* TCSR */
+#define IWL_FH_TCSR_LOWER_BOUND  (IWL_FH_REGS_LOWER_BOUND + 0xD00)
+#define IWL_FH_TCSR_UPPER_BOUND  (IWL_FH_REGS_LOWER_BOUND + 0xE60)
+
+#define IWL_FH_TCSR_CHNL_NUM                            (7)
+#define IWL_FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \
+	(IWL_FH_TCSR_LOWER_BOUND + 0x20 * _chnl)
+
+/* TSSR Area - Tx shared status registers */
+/* TSSR */
+#define IWL_FH_TSSR_LOWER_BOUND		(IWL_FH_REGS_LOWER_BOUND + 0xEA0)
+#define IWL_FH_TSSR_UPPER_BOUND		(IWL_FH_REGS_LOWER_BOUND + 0xEC0)
+
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG	(IWL_FH_TSSR_LOWER_BOUND + 0x008)
+#define IWL_FH_TSSR_TX_STATUS_REG	(IWL_FH_TSSR_LOWER_BOUND + 0x010)
+
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON	(0xFF000000)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON	(0x00FF0000)
+
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_64B	(0x00000000)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B	(0x00000400)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_256B	(0x00000800)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_512B	(0x00000C00)
+
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON	(0x00000100)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON	(0x00000080)
+
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH	(0x00000020)
+#define IWL_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH		(0x00000005)
+
+#define IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl)	\
+	((1 << (_chnl)) << 24)
+#define IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) \
+	((1 << (_chnl)) << 16)
+
+#define IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_chnl) \
+	(IWL_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \
+	IWL_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl))
+
+/* TCSR: tx_config register values */
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF              (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER           (0x00000001)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_ARC              (0x00000002)
+
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL    (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL     (0x00000008)
+
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT           (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD          (0x00100000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD           (0x00200000)
+
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT            (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD           (0x00400000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD            (0x00800000)
+
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE            (0x00000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF        (0x40000000)
+#define IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE           (0x80000000)
+
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY          (0x00000000)
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT           (0x00002000)
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID          (0x00000003)
+
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR           (0x00000001)
+
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM              (20)
+#define IWL_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX              (12)
+
+/* RCSR:  channel 0 rx_config register defines */
+#define FH_RCSR_CHNL0_RX_CONFIG_DMA_CHNL_EN_MASK  (0xC0000000) /* bits 30-31 */
+#define FH_RCSR_CHNL0_RX_CONFIG_RBDBC_SIZE_MASK   (0x00F00000) /* bits 20-23 */
+#define FH_RCSR_CHNL0_RX_CONFIG_RB_SIZE_MASK	  (0x00030000) /* bits 16-17 */
+#define FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MASK (0x00008000) /* bit 15 */
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_MASK     (0x00001000) /* bit 12 */
+#define FH_RCSR_CHNL0_RX_CONFIG_RB_TIMEOUT_MASK   (0x00000FF0) /* bit 4-11 */
+
+#define FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT       (20)
+#define FH_RCSR_RX_CONFIG_RB_SIZE_BITSHIFT			(16)
+
+/* RCSR: rx_config register values */
+#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL         (0x00000000)
+#define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL     (0x40000000)
+#define FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL        (0x80000000)
+
+#define IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K    (0x00000000)
+
+/* RCSR channel 0 config register values */
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL       (0x00000000)
+#define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL     (0x00001000)
+
+/* RSCSR: defs used in normal mode */
+#define FH_RSCSR_CHNL0_RBDCB_WPTR_MASK		(0x00000FFF)	/* bits 0-11 */
+
+#define SCD_WIN_SIZE				64
+#define SCD_FRAME_LIMIT				64
+
+/* memory mapped registers */
+#define SCD_START_OFFSET		0xa02c00
+
+#define SCD_SRAM_BASE_ADDR           (SCD_START_OFFSET + 0x0)
+#define SCD_EMPTY_BITS               (SCD_START_OFFSET + 0x4)
+#define SCD_DRAM_BASE_ADDR           (SCD_START_OFFSET + 0x10)
+#define SCD_AIT                      (SCD_START_OFFSET + 0x18)
+#define SCD_TXFACT                   (SCD_START_OFFSET + 0x1c)
+#define SCD_QUEUE_WRPTR(x)           (SCD_START_OFFSET + 0x24 + (x) * 4)
+#define SCD_QUEUE_RDPTR(x)           (SCD_START_OFFSET + 0x64 + (x) * 4)
+#define SCD_SETQUEUENUM              (SCD_START_OFFSET + 0xa4)
+#define SCD_SET_TXSTAT_TXED          (SCD_START_OFFSET + 0xa8)
+#define SCD_SET_TXSTAT_DONE          (SCD_START_OFFSET + 0xac)
+#define SCD_SET_TXSTAT_NOT_SCHD      (SCD_START_OFFSET + 0xb0)
+#define SCD_DECREASE_CREDIT          (SCD_START_OFFSET + 0xb4)
+#define SCD_DECREASE_SCREDIT         (SCD_START_OFFSET + 0xb8)
+#define SCD_LOAD_CREDIT              (SCD_START_OFFSET + 0xbc)
+#define SCD_LOAD_SCREDIT             (SCD_START_OFFSET + 0xc0)
+#define SCD_BAR                      (SCD_START_OFFSET + 0xc4)
+#define SCD_BAR_DW0                  (SCD_START_OFFSET + 0xc8)
+#define SCD_BAR_DW1                  (SCD_START_OFFSET + 0xcc)
+#define SCD_QUEUECHAIN_SEL           (SCD_START_OFFSET + 0xd0)
+#define SCD_QUERY_REQ                (SCD_START_OFFSET + 0xd8)
+#define SCD_QUERY_RES                (SCD_START_OFFSET + 0xdc)
+#define SCD_PENDING_FRAMES           (SCD_START_OFFSET + 0xe0)
+#define SCD_INTERRUPT_MASK           (SCD_START_OFFSET + 0xe4)
+#define SCD_INTERRUPT_THRESHOLD      (SCD_START_OFFSET + 0xe8)
+#define SCD_QUERY_MIN_FRAME_SIZE     (SCD_START_OFFSET + 0x100)
+#define SCD_QUEUE_STATUS_BITS(x)     (SCD_START_OFFSET + 0x104 + (x) * 4)
+
+/* SRAM structures */
+#define SCD_CONTEXT_DATA_OFFSET			0x380
+#define SCD_TX_STTS_BITMAP_OFFSET		0x400
+#define SCD_TRANSLATE_TBL_OFFSET		0x500
+#define SCD_CONTEXT_QUEUE_OFFSET(x)	(SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
+#define SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
+	((SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc)
+
+#define SCD_TXFACT_REG_TXFIFO_MASK(lo, hi) \
+       ((1<<(hi))|((1<<(hi))-(1<<(lo))))
+
+
+#define SCD_MODE_REG_BIT_SEARCH_MODE		(1<<0)
+#define SCD_MODE_REG_BIT_SBYP_MODE		(1<<1)
+
+#define SCD_TXFIFO_POS_TID			(0)
+#define SCD_TXFIFO_POS_RA			(4)
+#define SCD_QUEUE_STTS_REG_POS_ACTIVE		(0)
+#define SCD_QUEUE_STTS_REG_POS_TXF		(1)
+#define SCD_QUEUE_STTS_REG_POS_WSL		(5)
+#define SCD_QUEUE_STTS_REG_POS_SCD_ACK		(8)
+#define SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN	(10)
+#define SCD_QUEUE_STTS_REG_MSK			(0x0007FC00)
+
+#define SCD_QUEUE_RA_TID_MAP_RATID_MSK		(0x01FF)
+
+#define SCD_QUEUE_CTX_REG1_WIN_SIZE_POS		(0)
+#define SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK		(0x0000007F)
+#define SCD_QUEUE_CTX_REG1_CREDIT_POS		(8)
+#define SCD_QUEUE_CTX_REG1_CREDIT_MSK		(0x00FFFF00)
+#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_POS	(24)
+#define SCD_QUEUE_CTX_REG1_SUPER_CREDIT_MSK	(0xFF000000)
+#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS	(16)
+#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK	(0x007F0000)
+
+#define CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R	(0x00000010)
+#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER	(0x00000C00)
+#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI		(0x00000100)
+#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI	(0x00000200)
+
+static inline u8 iwl_hw_get_rate(__le32 rate_n_flags)
+{
+	return le32_to_cpu(rate_n_flags) & 0xFF;
+}
+static inline u16 iwl_hw_get_rate_n_flags(__le32 rate_n_flags)
+{
+	return le32_to_cpu(rate_n_flags) & 0xFFFF;
+}
+static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u16 flags)
+{
+	return cpu_to_le32(flags|(u16)rate);
+}
+
+struct iwl_tfd_frame_data {
+	__le32 tb1_addr;
+
+	__le32 val1;
+	/* __le32 ptb1_32_35:4; */
+#define IWL_tb1_addr_hi_POS 0
+#define IWL_tb1_addr_hi_LEN 4
+#define IWL_tb1_addr_hi_SYM val1
+	/* __le32 tb_len1:12; */
+#define IWL_tb1_len_POS 4
+#define IWL_tb1_len_LEN 12
+#define IWL_tb1_len_SYM val1
+	/* __le32 ptb2_0_15:16; */
+#define IWL_tb2_addr_lo16_POS 16
+#define IWL_tb2_addr_lo16_LEN 16
+#define IWL_tb2_addr_lo16_SYM val1
+
+	__le32 val2;
+	/* __le32 ptb2_16_35:20; */
+#define IWL_tb2_addr_hi20_POS 0
+#define IWL_tb2_addr_hi20_LEN 20
+#define IWL_tb2_addr_hi20_SYM val2
+	/* __le32 tb_len2:12; */
+#define IWL_tb2_len_POS 20
+#define IWL_tb2_len_LEN 12
+#define IWL_tb2_len_SYM val2
+} __attribute__ ((packed));
+
+struct iwl_tfd_frame {
+	__le32 val0;
+	/* __le32 rsvd1:24; */
+	/* __le32 num_tbs:5; */
+#define IWL_num_tbs_POS 24
+#define IWL_num_tbs_LEN 5
+#define IWL_num_tbs_SYM val0
+	/* __le32 rsvd2:1; */
+	/* __le32 padding:2; */
+	struct iwl_tfd_frame_data pa[10];
+	__le32 reserved;
+} __attribute__ ((packed));
+
+#define IWL4965_MAX_WIN_SIZE              64
+#define IWL4965_QUEUE_SIZE               256
+#define IWL4965_NUM_FIFOS                  7
+#define IWL_MAX_NUM_QUEUES                16
+
+struct iwl4965_queue_byte_cnt_entry {
+	__le16 val;
+	/* __le16 byte_cnt:12; */
+#define IWL_byte_cnt_POS 0
+#define IWL_byte_cnt_LEN 12
+#define IWL_byte_cnt_SYM val
+	/* __le16 rsvd:4; */
+} __attribute__ ((packed));
+
+struct iwl4965_sched_queue_byte_cnt_tbl {
+	struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL4965_QUEUE_SIZE +
+						       IWL4965_MAX_WIN_SIZE];
+	u8 dont_care[1024 -
+		     (IWL4965_QUEUE_SIZE + IWL4965_MAX_WIN_SIZE) *
+		     sizeof(__le16)];
+} __attribute__ ((packed));
+
+/* Base physical address of iwl_shared is provided to SCD_DRAM_BASE_ADDR
+ * and &iwl_shared.val0 is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG */
+struct iwl_shared {
+	struct iwl4965_sched_queue_byte_cnt_tbl
+	 queues_byte_cnt_tbls[IWL_MAX_NUM_QUEUES];
+	__le32 val0;
+
+	/* __le32 rb_closed_stts_rb_num:12; */
+#define IWL_rb_closed_stts_rb_num_POS 0
+#define IWL_rb_closed_stts_rb_num_LEN 12
+#define IWL_rb_closed_stts_rb_num_SYM val0
+	/* __le32 rsrv1:4; */
+	/* __le32 rb_closed_stts_rx_frame_num:12; */
+#define IWL_rb_closed_stts_rx_frame_num_POS 16
+#define IWL_rb_closed_stts_rx_frame_num_LEN 12
+#define IWL_rb_closed_stts_rx_frame_num_SYM val0
+	/* __le32 rsrv2:4; */
+
+	__le32 val1;
+	/* __le32 frame_finished_stts_rb_num:12; */
+#define IWL_frame_finished_stts_rb_num_POS 0
+#define IWL_frame_finished_stts_rb_num_LEN 12
+#define IWL_frame_finished_stts_rb_num_SYM val1
+	/* __le32 rsrv3:4; */
+	/* __le32 frame_finished_stts_rx_frame_num:12; */
+#define IWL_frame_finished_stts_rx_frame_num_POS 16
+#define IWL_frame_finished_stts_rx_frame_num_LEN 12
+#define IWL_frame_finished_stts_rx_frame_num_SYM val1
+	/* __le32 rsrv4:4; */
+
+	__le32 padding1;  /* so that allocation will be aligned to 16B */
+	__le32 padding2;
+} __attribute__ ((packed));
+
+#endif /* __iwl_4965_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
new file mode 100644
index 0000000..287c757
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c
@@ -0,0 +1,2295 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/wireless.h>
+#include <net/mac80211.h>
+#include <net/ieee80211.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+
+#include <linux/workqueue.h>
+
+#include <net/mac80211.h>
+#include <linux/wireless.h>
+
+#define IWL 4965
+
+#include "../net/mac80211/ieee80211_rate.h"
+
+#include "iwlwifi.h"
+#include "iwl-helpers.h"
+
+#define RS_NAME "iwl-4965-rs"
+
+#define NUM_TRY_BEFORE_ANTENNA_TOGGLE 1
+#define IWL_NUMBER_TRY      1
+#define IWL_HT_NUMBER_TRY   3
+
+#define IWL_RATE_MAX_WINDOW		62
+#define IWL_RATE_HIGH_TH		10880
+#define IWL_RATE_MIN_FAILURE_TH		6
+#define IWL_RATE_MIN_SUCCESS_TH		8
+#define IWL_RATE_DECREASE_TH		1920
+#define IWL_RATE_INCREASE_TH            8960
+#define IWL_RATE_SCALE_FLUSH_INTVL   (2*HZ)        /*2 seconds */
+
+static u8 rs_ht_to_legacy[] = {
+	IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
+	IWL_RATE_6M_INDEX, IWL_RATE_6M_INDEX,
+	IWL_RATE_6M_INDEX,
+	IWL_RATE_6M_INDEX, IWL_RATE_9M_INDEX,
+	IWL_RATE_12M_INDEX, IWL_RATE_18M_INDEX,
+	IWL_RATE_24M_INDEX, IWL_RATE_36M_INDEX,
+	IWL_RATE_48M_INDEX, IWL_RATE_54M_INDEX
+};
+
+struct iwl_rate {
+	u32 rate_n_flags;
+} __attribute__ ((packed));
+
+struct iwl_rate_scale_data {
+	u64 data;
+	s32 success_counter;
+	s32 success_ratio;
+	s32 counter;
+	s32 average_tpt;
+	unsigned long stamp;
+};
+
+struct iwl_scale_tbl_info {
+	enum iwl_table_type lq_type;
+	enum iwl_antenna_type antenna_type;
+	u8 is_SGI;
+	u8 is_fat;
+	u8 is_dup;
+	u8 action;
+	s32 *expected_tpt;
+	struct iwl_rate current_rate;
+	struct iwl_rate_scale_data win[IWL_RATE_COUNT];
+};
+
+struct iwl_rate_scale_priv {
+	u8 active_tbl;
+	u8 enable_counter;
+	u8 stay_in_tbl;
+	u8 search_better_tbl;
+	s32 last_tpt;
+	u32 table_count_limit;
+	u32 max_failure_limit;
+	u32 max_success_limit;
+	u32 table_count;
+	u32 total_failed;
+	u32 total_success;
+	u32 flush_timer;
+	u8 action_counter;
+	u8 antenna;
+	u8 valid_antenna;
+	u8 is_green;
+	u8 is_dup;
+	u8 phymode;
+	u8 ibss_sta_added;
+	u32 supp_rates;
+	u16 active_rate;
+	u16 active_siso_rate;
+	u16 active_mimo_rate;
+	u16 active_rate_basic;
+	struct iwl_link_quality_cmd lq;
+	struct iwl_scale_tbl_info lq_info[LQ_SIZE];
+#ifdef CONFIG_MAC80211_DEBUGFS
+	struct dentry *rs_sta_dbgfs_scale_table_file;
+	struct dentry *rs_sta_dbgfs_stats_table_file;
+	struct iwl_rate dbg_fixed;
+	struct iwl_priv *drv;
+#endif
+};
+
+static void rs_rate_scale_perform(struct iwl_priv *priv,
+				   struct net_device *dev,
+				   struct ieee80211_hdr *hdr,
+				   struct sta_info *sta);
+static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
+			     struct iwl_rate *tx_mcs,
+			     struct iwl_link_quality_cmd *tbl);
+
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,
+				struct iwl_rate *mcs, int index);
+#else
+static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,
+				struct iwl_rate *mcs, int index)
+{}
+#endif
+static s32 expected_tpt_A[IWL_RATE_COUNT] = {
+	0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186
+};
+
+static s32 expected_tpt_G[IWL_RATE_COUNT] = {
+	7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 186
+};
+
+static s32 expected_tpt_siso20MHz[IWL_RATE_COUNT] = {
+	0, 0, 0, 0, 42, 42, 76, 102, 124, 159, 183, 193, 202
+};
+
+static s32 expected_tpt_siso20MHzSGI[IWL_RATE_COUNT] = {
+	0, 0, 0, 0, 46, 46, 82, 110, 132, 168, 192, 202, 211
+};
+
+static s32 expected_tpt_mimo20MHz[IWL_RATE_COUNT] = {
+	0, 0, 0, 0, 74, 74, 123, 155, 179, 214, 236, 244, 251
+};
+
+static s32 expected_tpt_mimo20MHzSGI[IWL_RATE_COUNT] = {
+	0, 0, 0, 0, 81, 81, 131, 164, 188, 222, 243, 251, 257
+};
+
+static s32 expected_tpt_siso40MHz[IWL_RATE_COUNT] = {
+	0, 0, 0, 0, 77, 77, 127, 160, 184, 220, 242, 250, 257
+};
+
+static s32 expected_tpt_siso40MHzSGI[IWL_RATE_COUNT] = {
+	0, 0, 0, 0, 83, 83, 135, 169, 193, 229, 250, 257, 264
+};
+
+static s32 expected_tpt_mimo40MHz[IWL_RATE_COUNT] = {
+	0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289
+};
+
+static s32 expected_tpt_mimo40MHzSGI[IWL_RATE_COUNT] = {
+	0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293
+};
+
+static int iwl_lq_sync_callback(struct iwl_priv *priv,
+				struct iwl_cmd *cmd, struct sk_buff *skb)
+{
+	/*We didn't cache the SKB; let the caller free it */
+	return 1;
+}
+
+static inline u8 iwl_rate_get_rate(u32 rate_n_flags)
+{
+	return (u8)(rate_n_flags & 0xFF);
+}
+
+static int rs_send_lq_cmd(struct iwl_priv *priv,
+			  struct iwl_link_quality_cmd *lq, u8 flags)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+	int i;
+#endif
+	int rc = -1;
+
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_TX_LINK_QUALITY_CMD,
+		.len = sizeof(struct iwl_link_quality_cmd),
+		.meta.flags = flags,
+		.data = lq,
+	};
+
+	if ((lq->sta_id == 0xFF) &&
+	    (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
+		return rc;
+
+	if (lq->sta_id == 0xFF)
+		lq->sta_id = IWL_AP_ID;
+
+	IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id);
+	IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n",
+		       lq->general_params.single_stream_ant_msk,
+		       lq->general_params.dual_stream_ant_msk);
+#ifdef CONFIG_IWLWIFI_DEBUG
+	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
+		IWL_DEBUG_RATE("lq index %d 0x%X\n",
+				i, lq->rs_table[i].rate_n_flags);
+#endif
+
+	if (flags & CMD_ASYNC)
+		cmd.meta.u.callback = iwl_lq_sync_callback;
+
+	if (iwl_is_associated(priv) && priv->assoc_station_added &&
+	    priv->lq_mngr.lq_ready)
+		rc = iwl_send_cmd(priv, &cmd);
+
+	return rc;
+}
+
+static int rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
+{
+	window->data = 0;
+	window->success_counter = 0;
+	window->success_ratio = IWL_INVALID_VALUE;
+	window->counter = 0;
+	window->average_tpt = IWL_INVALID_VALUE;
+	window->stamp = 0;
+
+	return 0;
+}
+
+static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
+			      int scale_index, s32 tpt, u32 status)
+{
+	int rc = 0;
+	struct iwl_rate_scale_data *window = NULL;
+	u64 mask;
+	u8 win_size = IWL_RATE_MAX_WINDOW;
+	s32 fail_count;
+
+	if (scale_index < 0)
+		return -1;
+
+	if (scale_index >= IWL_RATE_COUNT)
+		return -1;
+
+	window = &(windows[scale_index]);
+
+	if (window->counter >= win_size) {
+
+		window->counter = win_size - 1;
+		mask = 1;
+		mask = (mask << (win_size - 1));
+		if ((window->data & mask)) {
+			window->data &= ~mask;
+			window->success_counter = window->success_counter - 1;
+		}
+	}
+
+	window->counter = window->counter + 1;
+	mask = window->data;
+	window->data = (mask << 1);
+	if (status != 0) {
+		window->success_counter = window->success_counter + 1;
+		window->data |= 0x1;
+	}
+
+	if (window->counter > 0)
+		window->success_ratio = 128 * (100 * window->success_counter)
+					/ window->counter;
+	else
+		window->success_ratio = IWL_INVALID_VALUE;
+
+	fail_count = window->counter - window->success_counter;
+
+	if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||
+	    (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))
+		window->average_tpt = (window->success_ratio * tpt + 64) / 128;
+	else
+		window->average_tpt = IWL_INVALID_VALUE;
+
+	window->stamp = jiffies;
+
+	return rc;
+}
+
+int static rs_mcs_from_tbl(struct iwl_rate *mcs_rate,
+			   struct iwl_scale_tbl_info *tbl,
+			   int index, u8 use_green)
+{
+	int rc = 0;
+
+	if (is_legacy(tbl->lq_type)) {
+		mcs_rate->rate_n_flags = iwl_rates[index].plcp;
+		if (index >= IWL_FIRST_CCK_RATE && index <= IWL_LAST_CCK_RATE)
+			mcs_rate->rate_n_flags |= RATE_MCS_CCK_MSK;
+
+	} else if (is_siso(tbl->lq_type)) {
+		if (index > IWL_LAST_OFDM_RATE)
+			index = IWL_LAST_OFDM_RATE;
+		 mcs_rate->rate_n_flags = iwl_rates[index].plcp_siso |
+					  RATE_MCS_HT_MSK;
+	} else {
+		if (index > IWL_LAST_OFDM_RATE)
+			index = IWL_LAST_OFDM_RATE;
+		mcs_rate->rate_n_flags = iwl_rates[index].plcp_mimo |
+					 RATE_MCS_HT_MSK;
+	}
+
+	switch (tbl->antenna_type) {
+	case ANT_BOTH:
+		mcs_rate->rate_n_flags |= RATE_MCS_ANT_AB_MSK;
+		break;
+	case ANT_MAIN:
+		mcs_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK;
+		break;
+	case ANT_AUX:
+		mcs_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK;
+		break;
+	case ANT_NONE:
+		break;
+	}
+
+	if (is_legacy(tbl->lq_type))
+		return rc;
+
+	if (tbl->is_fat) {
+		if (tbl->is_dup)
+			mcs_rate->rate_n_flags |= RATE_MCS_DUP_MSK;
+		else
+			mcs_rate->rate_n_flags |= RATE_MCS_FAT_MSK;
+	}
+	if (tbl->is_SGI)
+		mcs_rate->rate_n_flags |= RATE_MCS_SGI_MSK;
+
+	if (use_green) {
+		mcs_rate->rate_n_flags |= RATE_MCS_GF_MSK;
+		if (is_siso(tbl->lq_type))
+			mcs_rate->rate_n_flags &= ~RATE_MCS_SGI_MSK;
+	}
+	return rc;
+}
+
+static int rs_get_tbl_info_from_mcs(const struct iwl_rate *mcs_rate,
+				    int phymode, struct iwl_scale_tbl_info *tbl,
+				    int *rate_idx)
+{
+	int index;
+	u32 ant_msk;
+
+	index = iwl_rate_index_from_plcp(mcs_rate->rate_n_flags);
+
+	if (index  == IWL_RATE_INVALID) {
+		*rate_idx = -1;
+		return -1;
+	}
+	tbl->is_SGI = 0;
+	tbl->is_fat = 0;
+	tbl->is_dup = 0;
+	tbl->antenna_type = ANT_BOTH;
+
+	if (!(mcs_rate->rate_n_flags & RATE_MCS_HT_MSK)) {
+		ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK);
+
+		if (ant_msk == RATE_MCS_ANT_AB_MSK)
+			tbl->lq_type = LQ_NONE;
+		else {
+
+			if (phymode == MODE_IEEE80211A)
+				tbl->lq_type = LQ_A;
+			else
+				tbl->lq_type = LQ_G;
+
+			if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK)
+				tbl->antenna_type = ANT_MAIN;
+			else
+				tbl->antenna_type = ANT_AUX;
+		}
+		*rate_idx = index;
+
+	} else if (iwl_rate_get_rate(mcs_rate->rate_n_flags)
+					<= IWL_RATE_SISO_60M_PLCP) {
+		tbl->lq_type = LQ_SISO;
+
+		ant_msk = (mcs_rate->rate_n_flags & RATE_MCS_ANT_AB_MSK);
+		if (ant_msk == RATE_MCS_ANT_AB_MSK)
+			tbl->lq_type = LQ_NONE;
+		else {
+			if (mcs_rate->rate_n_flags & RATE_MCS_ANT_A_MSK)
+				tbl->antenna_type = ANT_MAIN;
+			else
+				tbl->antenna_type = ANT_AUX;
+		}
+		if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK)
+			tbl->is_SGI = 1;
+
+		if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) ||
+		    (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK))
+			tbl->is_fat = 1;
+
+		if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)
+			tbl->is_dup = 1;
+
+		*rate_idx = index;
+	} else {
+		tbl->lq_type = LQ_MIMO;
+		if (mcs_rate->rate_n_flags & RATE_MCS_SGI_MSK)
+			tbl->is_SGI = 1;
+
+		if ((mcs_rate->rate_n_flags & RATE_MCS_FAT_MSK) ||
+		    (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK))
+			tbl->is_fat = 1;
+
+		if (mcs_rate->rate_n_flags & RATE_MCS_DUP_MSK)
+			tbl->is_dup = 1;
+		*rate_idx = index;
+	}
+	return 0;
+}
+
+static inline void rs_toggle_antenna(struct iwl_rate *new_rate,
+				     struct iwl_scale_tbl_info *tbl)
+{
+	if (tbl->antenna_type == ANT_AUX) {
+		tbl->antenna_type = ANT_MAIN;
+		new_rate->rate_n_flags &= ~RATE_MCS_ANT_B_MSK;
+		new_rate->rate_n_flags |= RATE_MCS_ANT_A_MSK;
+	} else {
+		tbl->antenna_type = ANT_AUX;
+		new_rate->rate_n_flags &= ~RATE_MCS_ANT_A_MSK;
+		new_rate->rate_n_flags |= RATE_MCS_ANT_B_MSK;
+	}
+}
+
+static inline s8 rs_use_green(struct iwl_priv *priv)
+{
+	s8 rc = 0;
+#ifdef CONFIG_IWLWIFI_HT
+	if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
+		return 0;
+
+	if ((priv->current_assoc_ht.is_green_field) &&
+	    !(priv->current_assoc_ht.operating_mode & 0x4))
+		rc = 1;
+#endif	/*CONFIG_IWLWIFI_HT */
+	return rc;
+}
+
+/**
+ * rs_get_supported_rates - get the available rates
+ *
+ * if management frame or broadcast frame only return
+ * basic available rates.
+ *
+ */
+static void rs_get_supported_rates(struct iwl_rate_scale_priv *lq_data,
+				   struct ieee80211_hdr *hdr,
+				   enum iwl_table_type rate_type,
+				   u16 *data_rate)
+{
+	if (is_legacy(rate_type))
+		*data_rate = lq_data->active_rate;
+	else {
+		if (is_siso(rate_type))
+			*data_rate = lq_data->active_siso_rate;
+		else
+			*data_rate = lq_data->active_mimo_rate;
+	}
+
+	if (hdr && is_multicast_ether_addr(hdr->addr1) &&
+	    lq_data->active_rate_basic)
+		*data_rate = lq_data->active_rate_basic;
+}
+
+static u16 rs_get_adjacent_rate(u8 index, u16 rate_mask, int rate_type)
+{
+	u8 high = IWL_RATE_INVALID;
+	u8 low = IWL_RATE_INVALID;
+
+	/* 802.11A or ht walks to the next literal adjascent rate in
+	 * the rate table */
+	if (is_a_band(rate_type) || !is_legacy(rate_type)) {
+		int i;
+		u32 mask;
+
+		/* Find the previous rate that is in the rate mask */
+		i = index - 1;
+		for (mask = (1 << i); i >= 0; i--, mask >>= 1) {
+			if (rate_mask & mask) {
+				low = i;
+				break;
+			}
+		}
+
+		/* Find the next rate that is in the rate mask */
+		i = index + 1;
+		for (mask = (1 << i); i < IWL_RATE_COUNT; i++, mask <<= 1) {
+			if (rate_mask & mask) {
+				high = i;
+				break;
+			}
+		}
+
+		return (high << 8) | low;
+	}
+
+	low = index;
+	while (low != IWL_RATE_INVALID) {
+		low = iwl_rates[low].prev_rs;
+		if (low == IWL_RATE_INVALID)
+			break;
+		if (rate_mask & (1 << low))
+			break;
+		IWL_DEBUG_RATE("Skipping masked lower rate: %d\n", low);
+	}
+
+	high = index;
+	while (high != IWL_RATE_INVALID) {
+		high = iwl_rates[high].next_rs;
+		if (high == IWL_RATE_INVALID)
+			break;
+		if (rate_mask & (1 << high))
+			break;
+		IWL_DEBUG_RATE("Skipping masked higher rate: %d\n", high);
+	}
+
+	return (high << 8) | low;
+}
+
+static int rs_get_lower_rate(struct iwl_rate_scale_priv *lq_data,
+			     struct iwl_scale_tbl_info *tbl, u8 scale_index,
+			     u8 ht_possible, struct iwl_rate *mcs_rate)
+{
+	s32 low;
+	u16 rate_mask;
+	u16 high_low;
+	u8 switch_to_legacy = 0;
+	u8 is_green = lq_data->is_green;
+
+	/* check if we need to switch from HT to legacy rates.
+	 * assumption is that mandatory rates (1Mbps or 6Mbps)
+	 * are always supported (spec demand) */
+	if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) {
+		switch_to_legacy = 1;
+		scale_index = rs_ht_to_legacy[scale_index];
+		if (lq_data->phymode == MODE_IEEE80211A)
+			tbl->lq_type = LQ_A;
+		else
+			tbl->lq_type = LQ_G;
+
+		if ((tbl->antenna_type == ANT_BOTH) ||
+		    (tbl->antenna_type == ANT_NONE))
+			tbl->antenna_type = ANT_MAIN;
+
+		tbl->is_fat = 0;
+		tbl->is_SGI = 0;
+	}
+
+	rs_get_supported_rates(lq_data, NULL, tbl->lq_type, &rate_mask);
+
+	/* mask with station rate restriction */
+	if (is_legacy(tbl->lq_type)) {
+		if (lq_data->phymode == (u8) MODE_IEEE80211A)
+			rate_mask  = (u16)(rate_mask &
+			   (lq_data->supp_rates << IWL_FIRST_OFDM_RATE));
+		else
+			rate_mask = (u16)(rate_mask & lq_data->supp_rates);
+	}
+
+	/* if we did switched from HT to legacy check current rate */
+	if ((switch_to_legacy) &&
+	    (rate_mask & (1 << scale_index))) {
+		rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green);
+		return 0;
+	}
+
+	high_low = rs_get_adjacent_rate(scale_index, rate_mask, tbl->lq_type);
+	low = high_low & 0xff;
+
+	if (low != IWL_RATE_INVALID)
+		rs_mcs_from_tbl(mcs_rate, tbl, low, is_green);
+	else
+		rs_mcs_from_tbl(mcs_rate, tbl, scale_index, is_green);
+
+	return 0;
+}
+
+static void rs_tx_status(void *priv_rate,
+			 struct net_device *dev,
+			 struct sk_buff *skb,
+			 struct ieee80211_tx_status *tx_resp)
+{
+	int status;
+	u8 retries;
+	int rs_index, index = 0;
+	struct iwl_rate_scale_priv *lq;
+	struct iwl_link_quality_cmd *table;
+	struct sta_info *sta;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct iwl_rate_scale_data *window = NULL;
+	struct iwl_rate_scale_data *search_win = NULL;
+	struct iwl_rate tx_mcs;
+	struct iwl_scale_tbl_info tbl_type;
+	struct iwl_scale_tbl_info *curr_tbl, *search_tbl;
+	u8 active_index = 0;
+	u16 fc = le16_to_cpu(hdr->frame_control);
+	s32 tpt = 0;
+
+	IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n");
+
+	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1))
+		return;
+
+	retries = tx_resp->retry_count;
+
+	if (retries > 15)
+		retries = 15;
+
+
+	sta = sta_info_get(local, hdr->addr1);
+
+	if (!sta || !sta->rate_ctrl_priv) {
+		if (sta)
+			sta_info_put(sta);
+		return;
+	}
+
+	lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+
+	if (!priv->lq_mngr.lq_ready)
+		return;
+
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added)
+		return;
+
+	table = &lq->lq;
+	active_index = lq->active_tbl;
+
+	lq->antenna = (lq->valid_antenna & local->hw.conf.antenna_sel_tx);
+	if (!lq->antenna)
+		lq->antenna = lq->valid_antenna;
+
+	lq->antenna = lq->valid_antenna;
+	curr_tbl = &(lq->lq_info[active_index]);
+	search_tbl = &(lq->lq_info[(1 - active_index)]);
+	window = (struct iwl_rate_scale_data *)
+	    &(curr_tbl->win[0]);
+	search_win = (struct iwl_rate_scale_data *)
+	    &(search_tbl->win[0]);
+
+	tx_mcs.rate_n_flags = tx_resp->control.tx_rate;
+
+	rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
+				  &tbl_type, &rs_index);
+	if ((rs_index < 0) || (rs_index >= IWL_RATE_COUNT)) {
+		IWL_DEBUG_RATE("bad rate index at: %d rate 0x%X\n",
+			     rs_index, tx_mcs.rate_n_flags);
+		sta_info_put(sta);
+		return;
+	}
+
+	if (retries &&
+	    (tx_mcs.rate_n_flags !=
+				le32_to_cpu(table->rs_table[0].rate_n_flags))) {
+		IWL_DEBUG_RATE("initial rate does not match 0x%x 0x%x\n",
+				tx_mcs.rate_n_flags,
+				le32_to_cpu(table->rs_table[0].rate_n_flags));
+		sta_info_put(sta);
+		return;
+	}
+
+	while (retries) {
+		tx_mcs.rate_n_flags =
+		    le32_to_cpu(table->rs_table[index].rate_n_flags);
+		rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
+					  &tbl_type, &rs_index);
+
+		if ((tbl_type.lq_type == search_tbl->lq_type) &&
+		    (tbl_type.antenna_type == search_tbl->antenna_type) &&
+		    (tbl_type.is_SGI == search_tbl->is_SGI)) {
+			if (search_tbl->expected_tpt)
+				tpt = search_tbl->expected_tpt[rs_index];
+			else
+				tpt = 0;
+			rs_collect_tx_data(search_win,
+					    rs_index, tpt, 0);
+		} else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
+			   (tbl_type.antenna_type == curr_tbl->antenna_type) &&
+			   (tbl_type.is_SGI == curr_tbl->is_SGI)) {
+			if (curr_tbl->expected_tpt)
+				tpt = curr_tbl->expected_tpt[rs_index];
+			else
+				tpt = 0;
+			rs_collect_tx_data(window, rs_index, tpt, 0);
+		}
+		if (lq->stay_in_tbl)
+			lq->total_failed++;
+		--retries;
+		index++;
+
+	}
+
+	if (!tx_resp->retry_count)
+		tx_mcs.rate_n_flags = tx_resp->control.tx_rate;
+	else
+		tx_mcs.rate_n_flags =
+			le32_to_cpu(table->rs_table[index].rate_n_flags);
+
+	rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode,
+				  &tbl_type, &rs_index);
+
+	if (tx_resp->flags & IEEE80211_TX_STATUS_ACK)
+		status = 1;
+	else
+		status = 0;
+
+	if ((tbl_type.lq_type == search_tbl->lq_type) &&
+	    (tbl_type.antenna_type == search_tbl->antenna_type) &&
+	    (tbl_type.is_SGI == search_tbl->is_SGI)) {
+		if (search_tbl->expected_tpt)
+			tpt = search_tbl->expected_tpt[rs_index];
+		else
+			tpt = 0;
+		rs_collect_tx_data(search_win,
+				    rs_index, tpt, status);
+	} else if ((tbl_type.lq_type == curr_tbl->lq_type) &&
+		   (tbl_type.antenna_type == curr_tbl->antenna_type) &&
+		   (tbl_type.is_SGI == curr_tbl->is_SGI)) {
+		if (curr_tbl->expected_tpt)
+			tpt = curr_tbl->expected_tpt[rs_index];
+		else
+			tpt = 0;
+		rs_collect_tx_data(window, rs_index, tpt, status);
+	}
+
+	if (lq->stay_in_tbl) {
+		if (status)
+			lq->total_success++;
+		else
+			lq->total_failed++;
+	}
+
+	rs_rate_scale_perform(priv, dev, hdr, sta);
+	sta_info_put(sta);
+	return;
+}
+
+static u8 rs_is_ant_connected(u8 valid_antenna,
+			      enum iwl_antenna_type antenna_type)
+{
+	if (antenna_type == ANT_AUX)
+		return ((valid_antenna & 0x2) ? 1:0);
+	else if (antenna_type == ANT_MAIN)
+		return ((valid_antenna & 0x1) ? 1:0);
+	else if (antenna_type == ANT_BOTH) {
+		if ((valid_antenna & 0x3) == 0x3)
+			return 1;
+		else
+			return 0;
+	}
+
+	return 1;
+}
+
+static u8 rs_is_other_ant_connected(u8 valid_antenna,
+				    enum iwl_antenna_type antenna_type)
+{
+	if (antenna_type == ANT_AUX)
+		return (rs_is_ant_connected(valid_antenna, ANT_MAIN));
+	else
+		return (rs_is_ant_connected(valid_antenna, ANT_AUX));
+
+	return 0;
+}
+
+static void rs_set_stay_in_table(u8 is_legacy,
+				 struct iwl_rate_scale_priv *lq_data)
+{
+	IWL_DEBUG_HT("we are staying in the same table\n");
+	lq_data->stay_in_tbl = 1;
+	if (is_legacy) {
+		lq_data->table_count_limit = IWL_LEGACY_TABLE_COUNT;
+		lq_data->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
+		lq_data->max_success_limit = IWL_LEGACY_TABLE_COUNT;
+	} else {
+		lq_data->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT;
+		lq_data->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT;
+		lq_data->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT;
+	}
+	lq_data->table_count = 0;
+	lq_data->total_failed = 0;
+	lq_data->total_success = 0;
+}
+
+static void rs_get_expected_tpt_table(struct iwl_rate_scale_priv *lq_data,
+				      struct iwl_scale_tbl_info *tbl)
+{
+	if (is_legacy(tbl->lq_type)) {
+		if (!is_a_band(tbl->lq_type))
+			tbl->expected_tpt = expected_tpt_G;
+		else
+			tbl->expected_tpt = expected_tpt_A;
+	} else if (is_siso(tbl->lq_type)) {
+		if (tbl->is_fat && !lq_data->is_dup)
+			if (tbl->is_SGI)
+				tbl->expected_tpt = expected_tpt_siso40MHzSGI;
+			else
+				tbl->expected_tpt = expected_tpt_siso40MHz;
+		else if (tbl->is_SGI)
+			tbl->expected_tpt = expected_tpt_siso20MHzSGI;
+		else
+			tbl->expected_tpt = expected_tpt_siso20MHz;
+
+	} else if (is_mimo(tbl->lq_type)) {
+		if (tbl->is_fat && !lq_data->is_dup)
+			if (tbl->is_SGI)
+				tbl->expected_tpt = expected_tpt_mimo40MHzSGI;
+			else
+				tbl->expected_tpt = expected_tpt_mimo40MHz;
+		else if (tbl->is_SGI)
+			tbl->expected_tpt = expected_tpt_mimo20MHzSGI;
+		else
+			tbl->expected_tpt = expected_tpt_mimo20MHz;
+	} else
+		tbl->expected_tpt = expected_tpt_G;
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+static s32 rs_get_best_rate(struct iwl_priv *priv,
+			    struct iwl_rate_scale_priv *lq_data,
+			    struct iwl_scale_tbl_info *tbl,
+			    u16 rate_mask, s8 index, s8 rate)
+{
+	struct iwl_scale_tbl_info *active_tbl =
+	    &(lq_data->lq_info[lq_data->active_tbl]);
+	s32 new_rate, high, low, start_hi;
+	s32 active_sr = active_tbl->win[index].success_ratio;
+	s32 *tpt_tbl = tbl->expected_tpt;
+	s32 active_tpt = active_tbl->expected_tpt[index];
+	u16 high_low;
+
+	new_rate = high = low = start_hi = IWL_RATE_INVALID;
+
+	for (; ;) {
+		high_low = rs_get_adjacent_rate(rate, rate_mask, tbl->lq_type);
+
+		low = high_low & 0xff;
+		high = (high_low >> 8) & 0xff;
+
+		if ((((100 * tpt_tbl[rate]) > lq_data->last_tpt) &&
+		     ((active_sr > IWL_RATE_DECREASE_TH) &&
+		      (active_sr <= IWL_RATE_HIGH_TH) &&
+		      (tpt_tbl[rate] <= active_tpt))) ||
+		    ((active_sr >= IWL_RATE_SCALE_SWITCH) &&
+		     (tpt_tbl[rate] > active_tpt))) {
+
+			if (start_hi != IWL_RATE_INVALID) {
+				new_rate = start_hi;
+				break;
+			}
+			new_rate = rate;
+			if (low != IWL_RATE_INVALID)
+				rate = low;
+			else
+				break;
+		} else {
+			if (new_rate != IWL_RATE_INVALID)
+				break;
+			else if (high != IWL_RATE_INVALID) {
+				start_hi = high;
+				rate = high;
+			} else {
+				new_rate = rate;
+				break;
+			}
+		}
+	}
+
+	return new_rate;
+}
+#endif				/* CONFIG_IWLWIFI_HT */
+
+static inline u8 rs_is_both_ant_supp(u8 valid_antenna)
+{
+	return (rs_is_ant_connected(valid_antenna, ANT_BOTH));
+}
+
+static int rs_switch_to_mimo(struct iwl_priv *priv,
+			     struct iwl_rate_scale_priv *lq_data,
+			     struct iwl_scale_tbl_info *tbl, int index)
+{
+	int rc = -1;
+#ifdef CONFIG_IWLWIFI_HT
+	u16 rate_mask;
+	s32 rate;
+	s8 is_green = lq_data->is_green;
+
+	if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
+		return -1;
+
+	IWL_DEBUG_HT("LQ: try to switch to MIMO\n");
+	tbl->lq_type = LQ_MIMO;
+	rs_get_supported_rates(lq_data, NULL, tbl->lq_type,
+				&rate_mask);
+
+	if (priv->current_assoc_ht.tx_mimo_ps_mode == IWL_MIMO_PS_STATIC)
+		return -1;
+
+	if (!rs_is_both_ant_supp(lq_data->antenna))
+		return -1;
+
+	rc = 0;
+	tbl->is_dup = lq_data->is_dup;
+	tbl->action = 0;
+	if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ)
+		tbl->is_fat = 1;
+	else
+		tbl->is_fat = 0;
+
+	if (tbl->is_fat) {
+		if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY)
+			tbl->is_SGI = 1;
+		else
+			tbl->is_SGI = 0;
+	} else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY)
+		tbl->is_SGI = 1;
+	else
+		tbl->is_SGI = 0;
+
+	rs_get_expected_tpt_table(lq_data, tbl);
+
+	rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index);
+
+	IWL_DEBUG_HT("LQ: MIMO best rate %d mask %X\n", rate, rate_mask);
+	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask))
+		return -1;
+	rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green);
+
+	IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n",
+		     tbl->current_rate.rate_n_flags, is_green);
+
+#endif				/*CONFIG_IWLWIFI_HT */
+	return rc;
+}
+
+static int rs_switch_to_siso(struct iwl_priv *priv,
+			     struct iwl_rate_scale_priv *lq_data,
+			     struct iwl_scale_tbl_info *tbl, int index)
+{
+	int rc = -1;
+#ifdef CONFIG_IWLWIFI_HT
+	u16 rate_mask;
+	u8 is_green = lq_data->is_green;
+	s32 rate;
+
+	IWL_DEBUG_HT("LQ: try to switch to SISO\n");
+	if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht)
+		return -1;
+
+	rc = 0;
+	tbl->is_dup = lq_data->is_dup;
+	tbl->lq_type = LQ_SISO;
+	tbl->action = 0;
+	rs_get_supported_rates(lq_data, NULL, tbl->lq_type,
+				&rate_mask);
+
+	if (priv->current_channel_width == IWL_CHANNEL_WIDTH_40MHZ)
+		tbl->is_fat = 1;
+	else
+		tbl->is_fat = 0;
+
+	if (tbl->is_fat) {
+		if (priv->current_assoc_ht.sgf & HT_SHORT_GI_40MHZ_ONLY)
+			tbl->is_SGI = 1;
+		else
+			tbl->is_SGI = 0;
+	} else if (priv->current_assoc_ht.sgf & HT_SHORT_GI_20MHZ_ONLY)
+		tbl->is_SGI = 1;
+	else
+		tbl->is_SGI = 0;
+
+	if (is_green)
+		tbl->is_SGI = 0;
+
+	rs_get_expected_tpt_table(lq_data, tbl);
+	rate = rs_get_best_rate(priv, lq_data, tbl, rate_mask, index, index);
+
+	IWL_DEBUG_HT("LQ: get best rate %d mask %X\n", rate, rate_mask);
+	if ((rate == IWL_RATE_INVALID) || !((1 << rate) & rate_mask)) {
+		IWL_DEBUG_HT("can not switch with index %d rate mask %x\n",
+			     rate, rate_mask);
+		return -1;
+	}
+	rs_mcs_from_tbl(&tbl->current_rate, tbl, rate, is_green);
+	IWL_DEBUG_HT("LQ: Switch to new mcs %X index is green %X\n",
+		     tbl->current_rate.rate_n_flags, is_green);
+
+#endif				/*CONFIG_IWLWIFI_HT */
+	return rc;
+}
+
+static int rs_move_legacy_other(struct iwl_priv *priv,
+				struct iwl_rate_scale_priv *lq_data,
+				int index)
+{
+	int rc = 0;
+	struct iwl_scale_tbl_info *tbl =
+	    &(lq_data->lq_info[lq_data->active_tbl]);
+	struct iwl_scale_tbl_info *search_tbl =
+	    &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
+	struct iwl_rate_scale_data *window = &(tbl->win[index]);
+	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+	u8 start_action = tbl->action;
+
+	for (; ;) {
+		switch (tbl->action) {
+		case IWL_LEGACY_SWITCH_ANTENNA:
+			IWL_DEBUG_HT("LQ Legacy switch Antenna\n");
+
+			search_tbl->lq_type = LQ_NONE;
+			lq_data->action_counter++;
+			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+				break;
+			if (!rs_is_other_ant_connected(lq_data->antenna,
+							tbl->antenna_type))
+				break;
+
+			memcpy(search_tbl, tbl, sz);
+
+			rs_toggle_antenna(&(search_tbl->current_rate),
+					   search_tbl);
+			rs_get_expected_tpt_table(lq_data, search_tbl);
+			lq_data->search_better_tbl = 1;
+			goto out;
+
+		case IWL_LEGACY_SWITCH_SISO:
+			IWL_DEBUG_HT("LQ: Legacy switch to SISO\n");
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->lq_type = LQ_SISO;
+			search_tbl->is_SGI = 0;
+			search_tbl->is_fat = 0;
+			rc = rs_switch_to_siso(priv, lq_data, search_tbl,
+					       index);
+			if (!rc) {
+				lq_data->search_better_tbl = 1;
+				lq_data->action_counter = 0;
+			}
+			if (!rc)
+				goto out;
+
+			break;
+		case IWL_LEGACY_SWITCH_MIMO:
+			IWL_DEBUG_HT("LQ: Legacy switch MIMO\n");
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->lq_type = LQ_MIMO;
+			search_tbl->is_SGI = 0;
+			search_tbl->is_fat = 0;
+			search_tbl->antenna_type = ANT_BOTH;
+			rc = rs_switch_to_mimo(priv, lq_data, search_tbl,
+					       index);
+			if (!rc) {
+				lq_data->search_better_tbl = 1;
+				lq_data->action_counter = 0;
+			}
+			if (!rc)
+				goto out;
+			break;
+		}
+		tbl->action++;
+		if (tbl->action > IWL_LEGACY_SWITCH_MIMO)
+			tbl->action = IWL_LEGACY_SWITCH_ANTENNA;
+
+		if (tbl->action == start_action)
+			break;
+
+	}
+	return 0;
+
+ out:
+	tbl->action++;
+	if (tbl->action > IWL_LEGACY_SWITCH_MIMO)
+		tbl->action = IWL_LEGACY_SWITCH_ANTENNA;
+	return 0;
+
+}
+
+static int rs_move_siso_to_other(struct iwl_priv *priv,
+				 struct iwl_rate_scale_priv *lq_data,
+				 int index)
+{
+	int rc = -1;
+	u8 is_green = lq_data->is_green;
+	struct iwl_scale_tbl_info *tbl =
+	    &(lq_data->lq_info[lq_data->active_tbl]);
+	struct iwl_scale_tbl_info *search_tbl =
+	    &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
+	struct iwl_rate_scale_data *window = &(tbl->win[index]);
+	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+	u8 start_action = tbl->action;
+
+	for (;;) {
+		lq_data->action_counter++;
+		switch (tbl->action) {
+		case IWL_SISO_SWITCH_ANTENNA:
+			IWL_DEBUG_HT("LQ: SISO SWITCH ANTENNA SISO\n");
+			search_tbl->lq_type = LQ_NONE;
+			if (window->success_ratio >= IWL_RS_GOOD_RATIO)
+				break;
+			if (!rs_is_other_ant_connected(lq_data->antenna,
+						       tbl->antenna_type))
+				break;
+
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->action = IWL_SISO_SWITCH_MIMO;
+			rs_toggle_antenna(&(search_tbl->current_rate),
+					   search_tbl);
+			lq_data->search_better_tbl = 1;
+
+			goto out;
+
+		case IWL_SISO_SWITCH_MIMO:
+			IWL_DEBUG_HT("LQ: SISO SWITCH TO MIMO FROM SISO\n");
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->lq_type = LQ_MIMO;
+			search_tbl->is_SGI = 0;
+			search_tbl->is_fat = 0;
+			search_tbl->antenna_type = ANT_BOTH;
+			rc = rs_switch_to_mimo(priv, lq_data, search_tbl,
+					       index);
+			if (!rc)
+				lq_data->search_better_tbl = 1;
+
+			if (!rc)
+				goto out;
+			break;
+		case IWL_SISO_SWITCH_GI:
+			IWL_DEBUG_HT("LQ: SISO SWITCH TO GI\n");
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->action = 0;
+			if (search_tbl->is_SGI)
+				search_tbl->is_SGI = 0;
+			else if (!is_green)
+				search_tbl->is_SGI = 1;
+			else
+				break;
+			lq_data->search_better_tbl = 1;
+			if ((tbl->lq_type == LQ_SISO) &&
+			    (tbl->is_SGI)) {
+				s32 tpt = lq_data->last_tpt / 100;
+				if (((!tbl->is_fat) &&
+				     (tpt >= expected_tpt_siso20MHz[index])) ||
+				    ((tbl->is_fat) &&
+				     (tpt >= expected_tpt_siso40MHz[index])))
+					lq_data->search_better_tbl = 0;
+			}
+			rs_get_expected_tpt_table(lq_data, search_tbl);
+			rs_mcs_from_tbl(&search_tbl->current_rate,
+					     search_tbl, index, is_green);
+			goto out;
+		}
+		tbl->action++;
+		if (tbl->action > IWL_SISO_SWITCH_GI)
+			tbl->action = IWL_SISO_SWITCH_ANTENNA;
+
+		if (tbl->action == start_action)
+			break;
+	}
+	return 0;
+
+ out:
+	tbl->action++;
+	if (tbl->action > IWL_SISO_SWITCH_GI)
+		tbl->action = IWL_SISO_SWITCH_ANTENNA;
+	return 0;
+}
+
+static int rs_move_mimo_to_other(struct iwl_priv *priv,
+				 struct iwl_rate_scale_priv *lq_data,
+				 int index)
+{
+	int rc = -1;
+	s8 is_green = lq_data->is_green;
+	struct iwl_scale_tbl_info *tbl =
+	    &(lq_data->lq_info[lq_data->active_tbl]);
+	struct iwl_scale_tbl_info *search_tbl =
+	    &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
+	u32 sz = (sizeof(struct iwl_scale_tbl_info) -
+		  (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT));
+	u8 start_action = tbl->action;
+
+	for (;;) {
+		lq_data->action_counter++;
+		switch (tbl->action) {
+		case IWL_MIMO_SWITCH_ANTENNA_A:
+		case IWL_MIMO_SWITCH_ANTENNA_B:
+			IWL_DEBUG_HT("LQ: MIMO SWITCH TO SISO\n");
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->lq_type = LQ_SISO;
+			search_tbl->is_SGI = 0;
+			search_tbl->is_fat = 0;
+			if (tbl->action == IWL_MIMO_SWITCH_ANTENNA_A)
+				search_tbl->antenna_type = ANT_MAIN;
+			else
+				search_tbl->antenna_type = ANT_AUX;
+
+			rc = rs_switch_to_siso(priv, lq_data, search_tbl,
+					       index);
+			if (!rc) {
+				lq_data->search_better_tbl = 1;
+				goto out;
+			}
+			break;
+
+		case IWL_MIMO_SWITCH_GI:
+			IWL_DEBUG_HT("LQ: MIMO SWITCH TO GI\n");
+			memcpy(search_tbl, tbl, sz);
+			search_tbl->lq_type = LQ_MIMO;
+			search_tbl->antenna_type = ANT_BOTH;
+			search_tbl->action = 0;
+			if (search_tbl->is_SGI)
+				search_tbl->is_SGI = 0;
+			else
+				search_tbl->is_SGI = 1;
+			lq_data->search_better_tbl = 1;
+			if ((tbl->lq_type == LQ_MIMO) &&
+			    (tbl->is_SGI)) {
+				s32 tpt = lq_data->last_tpt / 100;
+				if (((!tbl->is_fat) &&
+				     (tpt >= expected_tpt_mimo20MHz[index])) ||
+				    ((tbl->is_fat) &&
+				     (tpt >= expected_tpt_mimo40MHz[index])))
+					lq_data->search_better_tbl = 0;
+			}
+			rs_get_expected_tpt_table(lq_data, search_tbl);
+			rs_mcs_from_tbl(&search_tbl->current_rate,
+					     search_tbl, index, is_green);
+			goto out;
+
+		}
+		tbl->action++;
+		if (tbl->action > IWL_MIMO_SWITCH_GI)
+			tbl->action = IWL_MIMO_SWITCH_ANTENNA_A;
+
+		if (tbl->action == start_action)
+			break;
+	}
+
+	return 0;
+ out:
+	tbl->action++;
+	if (tbl->action > IWL_MIMO_SWITCH_GI)
+		tbl->action = IWL_MIMO_SWITCH_ANTENNA_A;
+	return 0;
+
+}
+
+static void rs_stay_in_table(struct iwl_rate_scale_priv *lq_data)
+{
+	struct iwl_scale_tbl_info *tbl;
+	int i;
+	int active_tbl;
+	int flush_interval_passed = 0;
+
+	active_tbl = lq_data->active_tbl;
+
+	tbl = &(lq_data->lq_info[active_tbl]);
+
+	if (lq_data->stay_in_tbl) {
+
+		if (lq_data->flush_timer)
+			flush_interval_passed =
+			    time_after(jiffies,
+				       (unsigned long)(lq_data->flush_timer +
+					IWL_RATE_SCALE_FLUSH_INTVL));
+
+		flush_interval_passed = 0;
+		if ((lq_data->total_failed > lq_data->max_failure_limit) ||
+		    (lq_data->total_success > lq_data->max_success_limit) ||
+		    ((!lq_data->search_better_tbl) && (lq_data->flush_timer)
+		     && (flush_interval_passed))) {
+			IWL_DEBUG_HT("LQ: stay is expired %d %d %d\n:",
+				     lq_data->total_failed,
+				     lq_data->total_success,
+				     flush_interval_passed);
+			lq_data->stay_in_tbl = 0;
+			lq_data->total_failed = 0;
+			lq_data->total_success = 0;
+			lq_data->flush_timer = 0;
+		} else if (lq_data->table_count > 0) {
+			lq_data->table_count++;
+			if (lq_data->table_count >=
+			    lq_data->table_count_limit) {
+				lq_data->table_count = 0;
+
+				IWL_DEBUG_HT("LQ: stay in table clear win\n");
+				for (i = 0; i < IWL_RATE_COUNT; i++)
+					rs_rate_scale_clear_window(
+						&(tbl->win[i]));
+			}
+		}
+
+		if (!lq_data->stay_in_tbl) {
+			for (i = 0; i < IWL_RATE_COUNT; i++)
+				rs_rate_scale_clear_window(&(tbl->win[i]));
+		}
+	}
+}
+
+static void rs_rate_scale_perform(struct iwl_priv *priv,
+				  struct net_device *dev,
+				  struct ieee80211_hdr *hdr,
+				  struct sta_info *sta)
+{
+	int low = IWL_RATE_INVALID;
+	int high = IWL_RATE_INVALID;
+	int index;
+	int i;
+	struct iwl_rate_scale_data *window = NULL;
+	int current_tpt = IWL_INVALID_VALUE;
+	int low_tpt = IWL_INVALID_VALUE;
+	int high_tpt = IWL_INVALID_VALUE;
+	u32 fail_count;
+	s8 scale_action = 0;
+	u16 fc, rate_mask;
+	u8 update_lq = 0;
+	struct iwl_rate_scale_priv *lq_data;
+	struct iwl_scale_tbl_info *tbl, *tbl1;
+	u16 rate_scale_index_msk = 0;
+	struct iwl_rate mcs_rate;
+	u8 is_green = 0;
+	u8 active_tbl = 0;
+	u8 done_search = 0;
+	u16 high_low;
+
+	IWL_DEBUG_RATE("rate scale calculate new rate for skb\n");
+
+	fc = le16_to_cpu(hdr->frame_control);
+	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) {
+		/* Send management frames and broadcast/multicast data using
+		 * lowest rate. */
+		/* TODO: this could probably be improved.. */
+		return;
+	}
+
+	if (!sta || !sta->rate_ctrl_priv)
+		return;
+
+	if (!priv->lq_mngr.lq_ready) {
+		IWL_DEBUG_RATE("still rate scaling not ready\n");
+		return;
+	}
+	lq_data = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+
+	if (!lq_data->search_better_tbl)
+		active_tbl = lq_data->active_tbl;
+	else
+		active_tbl = 1 - lq_data->active_tbl;
+
+	tbl = &(lq_data->lq_info[active_tbl]);
+	is_green = lq_data->is_green;
+
+	index = sta->last_txrate;
+
+	IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index,
+		       tbl->lq_type);
+
+	rs_get_supported_rates(lq_data, hdr, tbl->lq_type,
+				&rate_mask);
+
+	IWL_DEBUG_RATE("mask 0x%04X \n", rate_mask);
+
+	/* mask with station rate restriction */
+	if (is_legacy(tbl->lq_type)) {
+		if (lq_data->phymode == (u8) MODE_IEEE80211A)
+			rate_scale_index_msk = (u16) (rate_mask &
+				(lq_data->supp_rates << IWL_FIRST_OFDM_RATE));
+		else
+			rate_scale_index_msk = (u16) (rate_mask &
+						      lq_data->supp_rates);
+
+	} else
+		rate_scale_index_msk = rate_mask;
+
+	if (!rate_scale_index_msk)
+		rate_scale_index_msk = rate_mask;
+
+	if (index < 0 || !((1 << index) & rate_scale_index_msk)) {
+		index = IWL_INVALID_VALUE;
+		update_lq = 1;
+
+		/* get the lowest availabe rate */
+		for (i = 0; i <= IWL_RATE_COUNT; i++) {
+			if ((1 << i) & rate_scale_index_msk)
+				index = i;
+		}
+
+		if (index == IWL_INVALID_VALUE) {
+			IWL_WARNING("Can not find a suitable rate\n");
+			return;
+		}
+	}
+
+	if (!tbl->expected_tpt)
+		rs_get_expected_tpt_table(lq_data, tbl);
+
+	window = &(tbl->win[index]);
+
+	fail_count = window->counter - window->success_counter;
+	if (((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
+	     (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))
+	    || (tbl->expected_tpt == NULL)) {
+		IWL_DEBUG_RATE("LQ: still below TH succ %d total %d "
+			       "for index %d\n",
+			       window->success_counter, window->counter, index);
+		window->average_tpt = IWL_INVALID_VALUE;
+		rs_stay_in_table(lq_data);
+		if (update_lq) {
+			rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
+			rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq);
+			rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
+		}
+		goto out;
+
+	} else
+		window->average_tpt = ((window->success_ratio *
+					tbl->expected_tpt[index] + 64) / 128);
+
+	if (lq_data->search_better_tbl) {
+		int success_limit = IWL_RATE_SCALE_SWITCH;
+
+		if ((window->success_ratio > success_limit) ||
+		    (window->average_tpt > lq_data->last_tpt)) {
+			if (!is_legacy(tbl->lq_type)) {
+				IWL_DEBUG_HT("LQ: we are switching to HT"
+					     " rate suc %d current tpt %d"
+					     " old tpt %d\n",
+					     window->success_ratio,
+					     window->average_tpt,
+					     lq_data->last_tpt);
+				lq_data->enable_counter = 1;
+			}
+			lq_data->active_tbl = active_tbl;
+			current_tpt = window->average_tpt;
+		} else {
+			tbl->lq_type = LQ_NONE;
+			active_tbl = lq_data->active_tbl;
+			tbl = &(lq_data->lq_info[active_tbl]);
+
+			index = iwl_rate_index_from_plcp(
+				tbl->current_rate.rate_n_flags);
+
+			update_lq = 1;
+			current_tpt = lq_data->last_tpt;
+			IWL_DEBUG_HT("XXY GO BACK TO OLD TABLE\n");
+		}
+		lq_data->search_better_tbl = 0;
+		done_search = 1;
+		goto lq_update;
+	}
+
+	high_low = rs_get_adjacent_rate(index, rate_scale_index_msk,
+					tbl->lq_type);
+	low = high_low & 0xff;
+	high = (high_low >> 8) & 0xff;
+
+	current_tpt = window->average_tpt;
+
+	if (low != IWL_RATE_INVALID)
+		low_tpt = tbl->win[low].average_tpt;
+
+	if (high != IWL_RATE_INVALID)
+		high_tpt = tbl->win[high].average_tpt;
+
+
+	scale_action = 1;
+
+	if ((window->success_ratio <= IWL_RATE_DECREASE_TH) ||
+	    (current_tpt == 0)) {
+		IWL_DEBUG_RATE("decrease rate because of low success_ratio\n");
+		scale_action = -1;
+	} else if ((low_tpt == IWL_INVALID_VALUE) &&
+		   (high_tpt == IWL_INVALID_VALUE))
+		scale_action = 1;
+	else if ((low_tpt != IWL_INVALID_VALUE) &&
+		 (high_tpt != IWL_INVALID_VALUE) &&
+		 (low_tpt < current_tpt) &&
+		 (high_tpt < current_tpt))
+		scale_action = 0;
+	else {
+		if (high_tpt != IWL_INVALID_VALUE) {
+			if (high_tpt > current_tpt)
+				scale_action = 1;
+			else {
+				IWL_DEBUG_RATE
+				    ("decrease rate because of high tpt\n");
+				scale_action = -1;
+			}
+		} else if (low_tpt != IWL_INVALID_VALUE) {
+			if (low_tpt > current_tpt) {
+				IWL_DEBUG_RATE
+				    ("decrease rate because of low tpt\n");
+				scale_action = -1;
+			} else
+				scale_action = 1;
+		}
+	}
+
+	if (scale_action == -1) {
+		if ((low != IWL_RATE_INVALID) &&
+		    ((window->success_ratio > IWL_RATE_HIGH_TH) ||
+		     (current_tpt > (100 * tbl->expected_tpt[low]))))
+			scale_action = 0;
+	} else if ((scale_action == 1) &&
+		   (window->success_ratio < IWL_RATE_INCREASE_TH))
+		scale_action = 0;
+
+	switch (scale_action) {
+	case -1:
+		if (low != IWL_RATE_INVALID) {
+			update_lq = 1;
+			index = low;
+		}
+		break;
+	case 1:
+		if (high != IWL_RATE_INVALID) {
+			update_lq = 1;
+			index = high;
+		}
+
+		break;
+	case 0:
+	default:
+		break;
+	}
+
+	IWL_DEBUG_HT("choose rate scale index %d action %d low %d "
+		    "high %d type %d\n",
+		     index, scale_action, low, high, tbl->lq_type);
+
+ lq_update:
+	if (update_lq) {
+		rs_mcs_from_tbl(&mcs_rate, tbl, index, is_green);
+		rs_fill_link_cmd(lq_data, &mcs_rate, &lq_data->lq);
+		rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
+	}
+	rs_stay_in_table(lq_data);
+
+	if (!update_lq && !done_search && !lq_data->stay_in_tbl) {
+		lq_data->last_tpt = current_tpt;
+
+		if (is_legacy(tbl->lq_type))
+			rs_move_legacy_other(priv, lq_data, index);
+		else if (is_siso(tbl->lq_type))
+			rs_move_siso_to_other(priv, lq_data, index);
+		else
+			rs_move_mimo_to_other(priv, lq_data, index);
+
+		if (lq_data->search_better_tbl) {
+			tbl = &(lq_data->lq_info[(1 - lq_data->active_tbl)]);
+			for (i = 0; i < IWL_RATE_COUNT; i++)
+				rs_rate_scale_clear_window(&(tbl->win[i]));
+
+			index = iwl_rate_index_from_plcp(
+					tbl->current_rate.rate_n_flags);
+
+			IWL_DEBUG_HT("Switch current  mcs: %X index: %d\n",
+				     tbl->current_rate.rate_n_flags, index);
+			rs_fill_link_cmd(lq_data, &tbl->current_rate,
+					 &lq_data->lq);
+			rs_send_lq_cmd(priv, &lq_data->lq, CMD_ASYNC);
+		}
+		tbl1 = &(lq_data->lq_info[lq_data->active_tbl]);
+
+		if (is_legacy(tbl1->lq_type) &&
+#ifdef CONFIG_IWLWIFI_HT
+		    !priv->current_assoc_ht.is_ht &&
+#endif
+		    (lq_data->action_counter >= 1)) {
+			lq_data->action_counter = 0;
+			IWL_DEBUG_HT("LQ: STAY in legacy table\n");
+			rs_set_stay_in_table(1, lq_data);
+		}
+
+		if (lq_data->enable_counter &&
+		    (lq_data->action_counter >= IWL_ACTION_LIMIT)) {
+#ifdef CONFIG_IWLWIFI_HT_AGG
+			if ((lq_data->last_tpt > TID_AGG_TPT_THREHOLD) &&
+			    (priv->lq_mngr.agg_ctrl.auto_agg)) {
+				priv->lq_mngr.agg_ctrl.tid_retry =
+				    TID_ALL_SPECIFIED;
+				schedule_work(&priv->agg_work);
+			}
+#endif /*CONFIG_IWLWIFI_HT_AGG */
+			lq_data->action_counter = 0;
+			rs_set_stay_in_table(0, lq_data);
+		}
+	} else {
+		if ((!update_lq) && (!done_search) && (!lq_data->flush_timer))
+			lq_data->flush_timer = jiffies;
+	}
+
+out:
+	rs_mcs_from_tbl(&tbl->current_rate, tbl, index, is_green);
+	i = index;
+	sta->last_txrate = i;
+
+	/* sta->txrate is an index to A mode rates which start
+	 * at IWL_FIRST_OFDM_RATE
+	 */
+	if (lq_data->phymode == (u8) MODE_IEEE80211A)
+		sta->txrate = i - IWL_FIRST_OFDM_RATE;
+	else
+		sta->txrate = i;
+
+	return;
+}
+
+
+static void rs_initialize_lq(struct iwl_priv *priv,
+			     struct sta_info *sta)
+{
+	int i;
+	struct iwl_rate_scale_priv *lq;
+	struct iwl_scale_tbl_info *tbl;
+	u8 active_tbl = 0;
+	int rate_idx;
+	u8 use_green = rs_use_green(priv);
+	struct iwl_rate mcs_rate;
+
+	if (!sta || !sta->rate_ctrl_priv)
+		goto out;
+
+	lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+	i = sta->last_txrate;
+
+	if ((lq->lq.sta_id == 0xff) &&
+	    (priv->iw_mode == IEEE80211_IF_TYPE_IBSS))
+		goto out;
+
+	if (!lq->search_better_tbl)
+		active_tbl = lq->active_tbl;
+	else
+		active_tbl = 1 - lq->active_tbl;
+
+	tbl = &(lq->lq_info[active_tbl]);
+
+	if ((i < 0) || (i >= IWL_RATE_COUNT))
+		i = 0;
+
+	mcs_rate.rate_n_flags = iwl_rates[i].plcp ;
+	mcs_rate.rate_n_flags |= RATE_MCS_ANT_B_MSK;
+	mcs_rate.rate_n_flags &= ~RATE_MCS_ANT_A_MSK;
+
+	if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE)
+		mcs_rate.rate_n_flags |= RATE_MCS_CCK_MSK;
+
+	tbl->antenna_type = ANT_AUX;
+	rs_get_tbl_info_from_mcs(&mcs_rate, priv->phymode, tbl, &rate_idx);
+	if (!rs_is_ant_connected(priv->valid_antenna, tbl->antenna_type))
+	    rs_toggle_antenna(&mcs_rate, tbl);
+
+	rs_mcs_from_tbl(&mcs_rate, tbl, rate_idx, use_green);
+	tbl->current_rate.rate_n_flags = mcs_rate.rate_n_flags;
+	rs_get_expected_tpt_table(lq, tbl);
+	rs_fill_link_cmd(lq, &mcs_rate, &lq->lq);
+	rs_send_lq_cmd(priv, &lq->lq, CMD_ASYNC);
+ out:
+	return;
+}
+
+static struct ieee80211_rate *rs_get_lowest_rate(struct ieee80211_local
+						 *local)
+{
+	struct ieee80211_hw_mode *mode = local->oper_hw_mode;
+	int i;
+
+	for (i = 0; i < mode->num_rates; i++) {
+		struct ieee80211_rate *rate = &mode->rates[i];
+
+		if (rate->flags & IEEE80211_RATE_SUPPORTED)
+			return rate;
+	}
+
+	return &mode->rates[0];
+}
+
+static struct ieee80211_rate *rs_get_rate(void *priv_rate,
+					       struct net_device *dev,
+					       struct sk_buff *skb,
+					       struct rate_control_extra
+					       *extra)
+{
+
+	int i;
+	struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct sta_info *sta;
+	u16 fc;
+	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+	struct iwl_rate_scale_priv *lq;
+
+	IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n");
+
+	memset(extra, 0, sizeof(*extra));
+
+	fc = le16_to_cpu(hdr->frame_control);
+	if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) {
+		/* Send management frames and broadcast/multicast data using
+		 * lowest rate. */
+		/* TODO: this could probably be improved.. */
+		return rs_get_lowest_rate(local);
+	}
+
+	sta = sta_info_get(local, hdr->addr1);
+
+	if (!sta || !sta->rate_ctrl_priv) {
+		if (sta)
+			sta_info_put(sta);
+		return rs_get_lowest_rate(local);
+	}
+
+	lq = (struct iwl_rate_scale_priv *)sta->rate_ctrl_priv;
+	i = sta->last_txrate;
+
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq->ibss_sta_added) {
+		u8 sta_id = iwl_hw_find_station(priv, hdr->addr1);
+		DECLARE_MAC_BUF(mac);
+
+		if (sta_id == IWL_INVALID_STATION) {
+			IWL_DEBUG_RATE("LQ: ADD station %s\n",
+				       print_mac(mac, hdr->addr1));
+			sta_id = iwl_add_station(priv,
+						 hdr->addr1, 0, CMD_ASYNC);
+		}
+		if ((sta_id != IWL_INVALID_STATION)) {
+			lq->lq.sta_id = sta_id;
+			lq->lq.rs_table[0].rate_n_flags = 0;
+			lq->ibss_sta_added = 1;
+			rs_initialize_lq(priv, sta);
+		}
+		if (!lq->ibss_sta_added)
+			goto done;
+	}
+
+ done:
+	sta_info_put(sta);
+	if ((i < 0) || (i > IWL_RATE_COUNT))
+		return rs_get_lowest_rate(local);
+
+	return &priv->ieee_rates[i];
+}
+
+static void *rs_alloc_sta(void *priv, gfp_t gfp)
+{
+	struct iwl_rate_scale_priv *crl;
+	int i, j;
+
+	IWL_DEBUG_RATE("create station rate scale window\n");
+
+	crl = kzalloc(sizeof(struct iwl_rate_scale_priv), gfp);
+
+	if (crl == NULL)
+		return NULL;
+	crl->lq.sta_id = 0xff;
+
+
+	for (j = 0; j < LQ_SIZE; j++)
+		for (i = 0; i < IWL_RATE_COUNT; i++)
+			rs_rate_scale_clear_window(&(crl->lq_info[j].win[i]));
+
+	return crl;
+}
+
+static void rs_rate_init(void *priv_rate, void *priv_sta,
+			 struct ieee80211_local *local,
+			 struct sta_info *sta)
+{
+	int i, j;
+	struct ieee80211_hw_mode *mode = local->oper_hw_mode;
+	struct iwl_priv *priv = (struct iwl_priv *)priv_rate;
+	struct iwl_rate_scale_priv *crl = priv_sta;
+
+	crl->flush_timer = 0;
+	crl->supp_rates = sta->supp_rates;
+	sta->txrate = 3;
+	for (j = 0; j < LQ_SIZE; j++)
+		for (i = 0; i < IWL_RATE_COUNT; i++)
+			rs_rate_scale_clear_window(&(crl->lq_info[j].win[i]));
+
+	IWL_DEBUG_RATE("rate scale global init\n");
+	/* TODO: what is a good starting rate for STA? About middle? Maybe not
+	 * the lowest or the highest rate.. Could consider using RSSI from
+	 * previous packets? Need to have IEEE 802.1X auth succeed immediately
+	 * after assoc.. */
+
+	crl->ibss_sta_added = 0;
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		u8 sta_id = iwl_hw_find_station(priv, sta->addr);
+		DECLARE_MAC_BUF(mac);
+
+		/* for IBSS the call are from tasklet */
+		IWL_DEBUG_HT("LQ: ADD station %s\n",
+			     print_mac(mac, sta->addr));
+
+		if (sta_id == IWL_INVALID_STATION) {
+			IWL_DEBUG_RATE("LQ: ADD station %s\n",
+				       print_mac(mac, sta->addr));
+			sta_id = iwl_add_station(priv,
+						 sta->addr, 0, CMD_ASYNC);
+		}
+		if ((sta_id != IWL_INVALID_STATION)) {
+			crl->lq.sta_id = sta_id;
+			crl->lq.rs_table[0].rate_n_flags = 0;
+		}
+		/* FIXME: this is w/a remove it later */
+		priv->assoc_station_added = 1;
+	}
+
+	for (i = 0; i < mode->num_rates; i++) {
+		if ((sta->supp_rates & BIT(i)) &&
+		    (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED))
+			sta->txrate = i;
+	}
+	sta->last_txrate = sta->txrate;
+	/* For MODE_IEEE80211A mode cck rate are at end
+	 * rate table
+	 */
+	if (local->hw.conf.phymode == MODE_IEEE80211A)
+		sta->last_txrate += IWL_FIRST_OFDM_RATE;
+
+	crl->is_dup = priv->is_dup;
+	crl->valid_antenna = priv->valid_antenna;
+	crl->antenna = priv->antenna;
+	crl->is_green = rs_use_green(priv);
+	crl->active_rate = priv->active_rate;
+	crl->active_rate &= ~(0x1000);
+	crl->active_rate_basic = priv->active_rate_basic;
+	crl->phymode = priv->phymode;
+#ifdef CONFIG_IWLWIFI_HT
+	crl->active_siso_rate = (priv->current_assoc_ht.supp_rates[0] << 1);
+	crl->active_siso_rate |= (priv->current_assoc_ht.supp_rates[0] & 0x1);
+	crl->active_siso_rate &= ~((u16)0x2);
+	crl->active_siso_rate = crl->active_siso_rate << IWL_FIRST_OFDM_RATE;
+
+	crl->active_mimo_rate = (priv->current_assoc_ht.supp_rates[1] << 1);
+	crl->active_mimo_rate |= (priv->current_assoc_ht.supp_rates[1] & 0x1);
+	crl->active_mimo_rate &= ~((u16)0x2);
+	crl->active_mimo_rate = crl->active_mimo_rate << IWL_FIRST_OFDM_RATE;
+	IWL_DEBUG_HT("MIMO RATE 0x%X SISO MASK 0x%X\n", crl->active_siso_rate,
+		     crl->active_mimo_rate);
+#endif /*CONFIG_IWLWIFI_HT*/
+#ifdef CONFIG_MAC80211_DEBUGFS
+	crl->drv = priv;
+#endif
+
+	if (priv->assoc_station_added)
+		priv->lq_mngr.lq_ready = 1;
+
+	rs_initialize_lq(priv, sta);
+}
+
+static void rs_fill_link_cmd(struct iwl_rate_scale_priv *lq_data,
+			    struct iwl_rate *tx_mcs,
+			    struct iwl_link_quality_cmd *lq_cmd)
+{
+	int index = 0;
+	int rate_idx;
+	int repeat_rate = 0;
+	u8 ant_toggle_count = 0;
+	u8 use_ht_possible = 1;
+	struct iwl_rate new_rate;
+	struct iwl_scale_tbl_info tbl_type = { 0 };
+
+	rs_dbgfs_set_mcs(lq_data, tx_mcs, index);
+
+	rs_get_tbl_info_from_mcs(tx_mcs, lq_data->phymode,
+				  &tbl_type, &rate_idx);
+
+	if (is_legacy(tbl_type.lq_type)) {
+		ant_toggle_count = 1;
+		repeat_rate = IWL_NUMBER_TRY;
+	} else
+		repeat_rate = IWL_HT_NUMBER_TRY;
+
+	lq_cmd->general_params.mimo_delimiter =
+			is_mimo(tbl_type.lq_type) ? 1 : 0;
+	lq_cmd->rs_table[index].rate_n_flags =
+			cpu_to_le32(tx_mcs->rate_n_flags);
+	new_rate.rate_n_flags = tx_mcs->rate_n_flags;
+
+	if (is_mimo(tbl_type.lq_type) || (tbl_type.antenna_type == ANT_MAIN))
+		lq_cmd->general_params.single_stream_ant_msk = 1;
+	else
+		lq_cmd->general_params.single_stream_ant_msk = 2;
+
+	index++;
+	repeat_rate--;
+
+	while (index < LINK_QUAL_MAX_RETRY_NUM) {
+		while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
+			if (is_legacy(tbl_type.lq_type)) {
+				if (ant_toggle_count <
+				    NUM_TRY_BEFORE_ANTENNA_TOGGLE)
+					ant_toggle_count++;
+				else {
+					rs_toggle_antenna(&new_rate, &tbl_type);
+					ant_toggle_count = 1;
+				}
+			}
+
+			rs_dbgfs_set_mcs(lq_data, &new_rate, index);
+			lq_cmd->rs_table[index].rate_n_flags =
+					cpu_to_le32(new_rate.rate_n_flags);
+			repeat_rate--;
+			index++;
+		}
+
+		rs_get_tbl_info_from_mcs(&new_rate, lq_data->phymode, &tbl_type,
+						&rate_idx);
+
+		if (is_mimo(tbl_type.lq_type))
+			lq_cmd->general_params.mimo_delimiter = index;
+
+		rs_get_lower_rate(lq_data, &tbl_type, rate_idx,
+				  use_ht_possible, &new_rate);
+
+		if (is_legacy(tbl_type.lq_type)) {
+			if (ant_toggle_count < NUM_TRY_BEFORE_ANTENNA_TOGGLE)
+				ant_toggle_count++;
+			else {
+				rs_toggle_antenna(&new_rate, &tbl_type);
+				ant_toggle_count = 1;
+			}
+			repeat_rate = IWL_NUMBER_TRY;
+		} else
+			repeat_rate = IWL_HT_NUMBER_TRY;
+
+		use_ht_possible = 0;
+
+		rs_dbgfs_set_mcs(lq_data, &new_rate, index);
+		lq_cmd->rs_table[index].rate_n_flags =
+				cpu_to_le32(new_rate.rate_n_flags);
+
+		index++;
+		repeat_rate--;
+	}
+
+	lq_cmd->general_params.dual_stream_ant_msk = 3;
+	lq_cmd->agg_params.agg_dis_start_th = 3;
+	lq_cmd->agg_params.agg_time_limit = cpu_to_le16(4000);
+}
+
+static void *rs_alloc(struct ieee80211_local *local)
+{
+	return local->hw.priv;
+}
+/* rate scale requires free function to be implemented */
+static void rs_free(void *priv_rate)
+{
+	return;
+}
+
+static void rs_clear(void *priv_rate)
+{
+	struct iwl_priv *priv = (struct iwl_priv *) priv_rate;
+
+	IWL_DEBUG_RATE("enter\n");
+
+	priv->lq_mngr.lq_ready = 0;
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+	if (priv->lq_mngr.agg_ctrl.granted_ba)
+		iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);
+#endif /*CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+	IWL_DEBUG_RATE("leave\n");
+}
+
+static void rs_free_sta(void *priv, void *priv_sta)
+{
+	struct iwl_rate_scale_priv *rs_priv = priv_sta;
+
+	IWL_DEBUG_RATE("enter\n");
+	kfree(rs_priv);
+	IWL_DEBUG_RATE("leave\n");
+}
+
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+static int open_file_generic(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+static void rs_dbgfs_set_mcs(struct iwl_rate_scale_priv *rs_priv,
+				struct iwl_rate *mcs, int index)
+{
+	const u32 cck_rate = 0x820A;
+	if (rs_priv->dbg_fixed.rate_n_flags) {
+		if (index < 12)
+			mcs->rate_n_flags = rs_priv->dbg_fixed.rate_n_flags;
+		else
+			mcs->rate_n_flags = cck_rate;
+		IWL_DEBUG_RATE("Fixed rate ON\n");
+		return;
+	}
+
+	IWL_DEBUG_RATE("Fixed rate OFF\n");
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
+			const char __user *user_buf, size_t count, loff_t *ppos)
+{
+	struct iwl_rate_scale_priv *rs_priv = file->private_data;
+	char buf[64];
+	int buf_size;
+	u32 parsed_rate;
+
+	memset(buf, 0, sizeof(buf));
+	buf_size = min(count, sizeof(buf) -  1);
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+
+	if (sscanf(buf, "%x", &parsed_rate) == 1)
+		rs_priv->dbg_fixed.rate_n_flags = parsed_rate;
+	else
+		rs_priv->dbg_fixed.rate_n_flags = 0;
+
+	rs_priv->active_rate = 0x0FFF;
+	rs_priv->active_siso_rate = 0x1FD0;
+	rs_priv->active_mimo_rate = 0x1FD0;
+
+	IWL_DEBUG_RATE("sta_id %d rate 0x%X\n",
+		rs_priv->lq.sta_id, rs_priv->dbg_fixed.rate_n_flags);
+
+	if (rs_priv->dbg_fixed.rate_n_flags) {
+		rs_fill_link_cmd(rs_priv, &rs_priv->dbg_fixed, &rs_priv->lq);
+		rs_send_lq_cmd(rs_priv->drv, &rs_priv->lq, CMD_ASYNC);
+	}
+
+	return count;
+}
+
+static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
+			char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buff[1024];
+	int desc = 0;
+	int i = 0;
+
+	struct iwl_rate_scale_priv *rs_priv = file->private_data;
+
+	desc += sprintf(buff+desc, "sta_id %d\n", rs_priv->lq.sta_id);
+	desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
+			rs_priv->total_failed, rs_priv->total_success,
+			rs_priv->active_rate);
+	desc += sprintf(buff+desc, "fixed rate 0x%X\n",
+			rs_priv->dbg_fixed.rate_n_flags);
+	desc += sprintf(buff+desc, "general:"
+		"flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
+		rs_priv->lq.general_params.flags,
+		rs_priv->lq.general_params.mimo_delimiter,
+		rs_priv->lq.general_params.single_stream_ant_msk,
+		rs_priv->lq.general_params.dual_stream_ant_msk);
+
+	desc += sprintf(buff+desc, "agg:"
+			"time_limit=%d dist_start_th=%d frame_cnt_limit=%d\n",
+			le16_to_cpu(rs_priv->lq.agg_params.agg_time_limit),
+			rs_priv->lq.agg_params.agg_dis_start_th,
+			rs_priv->lq.agg_params.agg_frame_cnt_limit);
+
+	desc += sprintf(buff+desc,
+			"Start idx [0]=0x%x [1]=0x%x [2]=0x%x [3]=0x%x\n",
+			rs_priv->lq.general_params.start_rate_index[0],
+			rs_priv->lq.general_params.start_rate_index[1],
+			rs_priv->lq.general_params.start_rate_index[2],
+			rs_priv->lq.general_params.start_rate_index[3]);
+
+
+	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++)
+		desc += sprintf(buff+desc, " rate[%d] 0x%X\n",
+			i, le32_to_cpu(rs_priv->lq.rs_table[i].rate_n_flags));
+
+	return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+}
+
+static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
+	.write = rs_sta_dbgfs_scale_table_write,
+	.read = rs_sta_dbgfs_scale_table_read,
+	.open = open_file_generic,
+};
+static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
+			char __user *user_buf, size_t count, loff_t *ppos)
+{
+	char buff[1024];
+	int desc = 0;
+	int i, j;
+
+	struct iwl_rate_scale_priv *rs_priv = file->private_data;
+	for (i = 0; i < LQ_SIZE; i++) {
+		desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n"
+				"rate=0x%X\n",
+				rs_priv->active_tbl == i?"*":"x",
+				rs_priv->lq_info[i].lq_type,
+				rs_priv->lq_info[i].is_SGI,
+				rs_priv->lq_info[i].is_fat,
+				rs_priv->lq_info[i].is_dup,
+				rs_priv->lq_info[i].current_rate.rate_n_flags);
+		for (j = 0; j < IWL_RATE_COUNT; j++) {
+			desc += sprintf(buff+desc,
+					"counter=%d success=%d %%=%d\n",
+					rs_priv->lq_info[i].win[j].counter,
+					rs_priv->lq_info[i].win[j].success_counter,
+					rs_priv->lq_info[i].win[j].success_ratio);
+		}
+	}
+	return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+}
+
+static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
+	.read = rs_sta_dbgfs_stats_table_read,
+	.open = open_file_generic,
+};
+
+static void rs_add_debugfs(void *priv, void *priv_sta,
+					struct dentry *dir)
+{
+	struct iwl_rate_scale_priv *rs_priv = priv_sta;
+	rs_priv->rs_sta_dbgfs_scale_table_file =
+		debugfs_create_file("rate_scale_table", 0600, dir,
+				rs_priv, &rs_sta_dbgfs_scale_table_ops);
+	rs_priv->rs_sta_dbgfs_stats_table_file =
+		debugfs_create_file("rate_stats_table", 0600, dir,
+			rs_priv, &rs_sta_dbgfs_stats_table_ops);
+}
+
+static void rs_remove_debugfs(void *priv, void *priv_sta)
+{
+	struct iwl_rate_scale_priv *rs_priv = priv_sta;
+	debugfs_remove(rs_priv->rs_sta_dbgfs_scale_table_file);
+	debugfs_remove(rs_priv->rs_sta_dbgfs_stats_table_file);
+}
+#endif
+
+static struct rate_control_ops rs_ops = {
+	.module = NULL,
+	.name = RS_NAME,
+	.tx_status = rs_tx_status,
+	.get_rate = rs_get_rate,
+	.rate_init = rs_rate_init,
+	.clear = rs_clear,
+	.alloc = rs_alloc,
+	.free = rs_free,
+	.alloc_sta = rs_alloc_sta,
+	.free_sta = rs_free_sta,
+#ifdef CONFIG_MAC80211_DEBUGFS
+	.add_sta_debugfs = rs_add_debugfs,
+	.remove_sta_debugfs = rs_remove_debugfs,
+#endif
+};
+
+int iwl_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id)
+{
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct iwl_priv *priv = hw->priv;
+	struct iwl_rate_scale_priv *rs_priv;
+	struct sta_info *sta;
+	int count = 0, i;
+	u32 samples = 0, success = 0, good = 0;
+	unsigned long now = jiffies;
+	u32 max_time = 0;
+	u8 lq_type, antenna;
+
+	sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr);
+	if (!sta || !sta->rate_ctrl_priv) {
+		if (sta) {
+			sta_info_put(sta);
+			IWL_DEBUG_RATE("leave - no private rate data!\n");
+		} else
+			IWL_DEBUG_RATE("leave - no station!\n");
+		return sprintf(buf, "station %d not found\n", sta_id);
+	}
+
+	rs_priv = (void *)sta->rate_ctrl_priv;
+
+	lq_type = rs_priv->lq_info[rs_priv->active_tbl].lq_type;
+	antenna = rs_priv->lq_info[rs_priv->active_tbl].antenna_type;
+
+	if (is_legacy(lq_type))
+		i = IWL_RATE_54M_INDEX;
+	else
+		i = IWL_RATE_60M_INDEX;
+	while (1) {
+		u64 mask;
+		int j;
+		int active = rs_priv->active_tbl;
+
+		count +=
+		    sprintf(&buf[count], " %2dMbs: ", iwl_rates[i].ieee / 2);
+
+		mask = (1ULL << (IWL_RATE_MAX_WINDOW - 1));
+		for (j = 0; j < IWL_RATE_MAX_WINDOW; j++, mask >>= 1)
+			buf[count++] =
+				(rs_priv->lq_info[active].win[i].data & mask)
+				? '1' : '0';
+
+		samples += rs_priv->lq_info[active].win[i].counter;
+		good += rs_priv->lq_info[active].win[i].success_counter;
+		success += rs_priv->lq_info[active].win[i].success_counter *
+			   iwl_rates[i].ieee;
+
+		if (rs_priv->lq_info[active].win[i].stamp) {
+			int delta =
+				   jiffies_to_msecs(now -
+				   rs_priv->lq_info[active].win[i].stamp);
+
+			if (delta > max_time)
+				max_time = delta;
+
+			count += sprintf(&buf[count], "%5dms\n", delta);
+		} else
+			buf[count++] = '\n';
+
+		j = iwl_get_prev_ieee_rate(i);
+		if (j == i)
+			break;
+		i = j;
+	}
+
+	/* Display the average rate of all samples taken.
+	 *
+	 * NOTE:  We multiple # of samples by 2 since the IEEE measurement
+	 * added from iwl_rates is actually 2X the rate */
+	if (samples)
+		count += sprintf(&buf[count],
+			 "\nAverage rate is %3d.%02dMbs over last %4dms\n"
+			 "%3d%% success (%d good packets over %d tries)\n",
+			 success / (2 * samples), (success * 5 / samples) % 10,
+			 max_time, good * 100 / samples, good, samples);
+	else
+		count += sprintf(&buf[count], "\nAverage rate: 0Mbs\n");
+	count += sprintf(&buf[count], "\nrate scale type %d anntena %d "
+			 "active_search %d rate index %d\n", lq_type, antenna,
+			 rs_priv->search_better_tbl, sta->last_txrate);
+
+	sta_info_put(sta);
+	return count;
+}
+
+void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id)
+{
+	struct iwl_priv *priv = hw->priv;
+
+	priv->lq_mngr.lq_ready = 1;
+}
+
+void iwl_rate_control_register(struct ieee80211_hw *hw)
+{
+	ieee80211_rate_control_register(&rs_ops);
+}
+
+void iwl_rate_control_unregister(struct ieee80211_hw *hw)
+{
+	ieee80211_rate_control_unregister(&rs_ops);
+}
+
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.h b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
new file mode 100644
index 0000000..c6325f7
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.h
@@ -0,0 +1,266 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_4965_rs_h__
+#define __iwl_4965_rs_h__
+
+#include "iwl-4965.h"
+
+struct iwl_rate_info {
+	u8 plcp;
+	u8 plcp_siso;
+	u8 plcp_mimo;
+	u8 ieee;
+	u8 prev_ieee;    /* previous rate in IEEE speeds */
+	u8 next_ieee;    /* next rate in IEEE speeds */
+	u8 prev_rs;      /* previous rate used in rs algo */
+	u8 next_rs;      /* next rate used in rs algo */
+	u8 prev_rs_tgg;  /* previous rate used in TGG rs algo */
+	u8 next_rs_tgg;  /* next rate used in TGG rs algo */
+};
+
+enum {
+	IWL_RATE_1M_INDEX = 0,
+	IWL_RATE_2M_INDEX,
+	IWL_RATE_5M_INDEX,
+	IWL_RATE_11M_INDEX,
+	IWL_RATE_6M_INDEX,
+	IWL_RATE_9M_INDEX,
+	IWL_RATE_12M_INDEX,
+	IWL_RATE_18M_INDEX,
+	IWL_RATE_24M_INDEX,
+	IWL_RATE_36M_INDEX,
+	IWL_RATE_48M_INDEX,
+	IWL_RATE_54M_INDEX,
+	IWL_RATE_60M_INDEX,
+	IWL_RATE_COUNT,
+	IWL_RATE_INVM_INDEX = IWL_RATE_COUNT,
+	IWL_RATE_INVALID = IWL_RATE_INVM_INDEX
+};
+
+enum {
+	IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
+	IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX,
+	IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX,
+	IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX,
+};
+
+/* #define vs. enum to keep from defaulting to 'large integer' */
+#define	IWL_RATE_6M_MASK   (1<<IWL_RATE_6M_INDEX)
+#define	IWL_RATE_9M_MASK   (1<<IWL_RATE_9M_INDEX)
+#define	IWL_RATE_12M_MASK  (1<<IWL_RATE_12M_INDEX)
+#define	IWL_RATE_18M_MASK  (1<<IWL_RATE_18M_INDEX)
+#define	IWL_RATE_24M_MASK  (1<<IWL_RATE_24M_INDEX)
+#define	IWL_RATE_36M_MASK  (1<<IWL_RATE_36M_INDEX)
+#define	IWL_RATE_48M_MASK  (1<<IWL_RATE_48M_INDEX)
+#define	IWL_RATE_54M_MASK  (1<<IWL_RATE_54M_INDEX)
+#define IWL_RATE_60M_MASK  (1<<IWL_RATE_60M_INDEX)
+#define	IWL_RATE_1M_MASK   (1<<IWL_RATE_1M_INDEX)
+#define	IWL_RATE_2M_MASK   (1<<IWL_RATE_2M_INDEX)
+#define	IWL_RATE_5M_MASK   (1<<IWL_RATE_5M_INDEX)
+#define	IWL_RATE_11M_MASK  (1<<IWL_RATE_11M_INDEX)
+
+enum {
+	IWL_RATE_6M_PLCP  = 13,
+	IWL_RATE_9M_PLCP  = 15,
+	IWL_RATE_12M_PLCP = 5,
+	IWL_RATE_18M_PLCP = 7,
+	IWL_RATE_24M_PLCP = 9,
+	IWL_RATE_36M_PLCP = 11,
+	IWL_RATE_48M_PLCP = 1,
+	IWL_RATE_54M_PLCP = 3,
+	IWL_RATE_60M_PLCP = 3,
+	IWL_RATE_1M_PLCP  = 10,
+	IWL_RATE_2M_PLCP  = 20,
+	IWL_RATE_5M_PLCP  = 55,
+	IWL_RATE_11M_PLCP = 110,
+};
+
+/* OFDM HT rate plcp */
+enum {
+	IWL_RATE_SISO_6M_PLCP = 0,
+	IWL_RATE_SISO_12M_PLCP = 1,
+	IWL_RATE_SISO_18M_PLCP = 2,
+	IWL_RATE_SISO_24M_PLCP = 3,
+	IWL_RATE_SISO_36M_PLCP = 4,
+	IWL_RATE_SISO_48M_PLCP = 5,
+	IWL_RATE_SISO_54M_PLCP = 6,
+	IWL_RATE_SISO_60M_PLCP = 7,
+	IWL_RATE_MIMO_6M_PLCP  = 0x8,
+	IWL_RATE_MIMO_12M_PLCP = 0x9,
+	IWL_RATE_MIMO_18M_PLCP = 0xa,
+	IWL_RATE_MIMO_24M_PLCP = 0xb,
+	IWL_RATE_MIMO_36M_PLCP = 0xc,
+	IWL_RATE_MIMO_48M_PLCP = 0xd,
+	IWL_RATE_MIMO_54M_PLCP = 0xe,
+	IWL_RATE_MIMO_60M_PLCP = 0xf,
+	IWL_RATE_SISO_INVM_PLCP,
+	IWL_RATE_MIMO_INVM_PLCP = IWL_RATE_SISO_INVM_PLCP,
+};
+
+enum {
+	IWL_RATE_6M_IEEE  = 12,
+	IWL_RATE_9M_IEEE  = 18,
+	IWL_RATE_12M_IEEE = 24,
+	IWL_RATE_18M_IEEE = 36,
+	IWL_RATE_24M_IEEE = 48,
+	IWL_RATE_36M_IEEE = 72,
+	IWL_RATE_48M_IEEE = 96,
+	IWL_RATE_54M_IEEE = 108,
+	IWL_RATE_60M_IEEE = 120,
+	IWL_RATE_1M_IEEE  = 2,
+	IWL_RATE_2M_IEEE  = 4,
+	IWL_RATE_5M_IEEE  = 11,
+	IWL_RATE_11M_IEEE = 22,
+};
+
+#define IWL_CCK_BASIC_RATES_MASK    \
+       (IWL_RATE_1M_MASK          | \
+	IWL_RATE_2M_MASK)
+
+#define IWL_CCK_RATES_MASK          \
+       (IWL_BASIC_RATES_MASK      | \
+	IWL_RATE_5M_MASK          | \
+	IWL_RATE_11M_MASK)
+
+#define IWL_OFDM_BASIC_RATES_MASK   \
+	(IWL_RATE_6M_MASK         | \
+	IWL_RATE_12M_MASK         | \
+	IWL_RATE_24M_MASK)
+
+#define IWL_OFDM_RATES_MASK         \
+       (IWL_OFDM_BASIC_RATES_MASK | \
+	IWL_RATE_9M_MASK          | \
+	IWL_RATE_18M_MASK         | \
+	IWL_RATE_36M_MASK         | \
+	IWL_RATE_48M_MASK         | \
+	IWL_RATE_54M_MASK)
+
+#define IWL_BASIC_RATES_MASK         \
+	(IWL_OFDM_BASIC_RATES_MASK | \
+	 IWL_CCK_BASIC_RATES_MASK)
+
+#define IWL_RATES_MASK ((1<<IWL_RATE_COUNT)-1)
+
+#define IWL_INVALID_VALUE    -1
+
+#define IWL_MIN_RSSI_VAL                 -100
+#define IWL_MAX_RSSI_VAL                    0
+
+#define IWL_LEGACY_SWITCH_ANTENNA	0
+#define IWL_LEGACY_SWITCH_SISO		1
+#define IWL_LEGACY_SWITCH_MIMO	        2
+
+#define IWL_RS_GOOD_RATIO		12800
+
+#define IWL_ACTION_LIMIT		3
+#define IWL_LEGACY_FAILURE_LIMIT	160
+#define IWL_LEGACY_SUCCESS_LIMIT	480
+#define IWL_LEGACY_TABLE_COUNT		160
+
+#define IWL_NONE_LEGACY_FAILURE_LIMIT	400
+#define IWL_NONE_LEGACY_SUCCESS_LIMIT	4500
+#define IWL_NONE_LEGACY_TABLE_COUNT	1500
+
+#define IWL_RATE_SCALE_SWITCH		(10880)
+
+#define IWL_SISO_SWITCH_ANTENNA		0
+#define IWL_SISO_SWITCH_MIMO		1
+#define IWL_SISO_SWITCH_GI		2
+
+#define IWL_MIMO_SWITCH_ANTENNA_A	0
+#define IWL_MIMO_SWITCH_ANTENNA_B	1
+#define IWL_MIMO_SWITCH_GI		2
+
+#define LQ_SIZE		2
+
+extern const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
+
+enum iwl_table_type {
+	LQ_NONE,
+	LQ_G,
+	LQ_A,
+	LQ_SISO,
+	LQ_MIMO,
+	LQ_MAX,
+};
+
+enum iwl_antenna_type {
+	ANT_NONE,
+	ANT_MAIN,
+	ANT_AUX,
+	ANT_BOTH,
+};
+
+static inline u8 iwl_get_prev_ieee_rate(u8 rate_index)
+{
+	u8 rate = iwl_rates[rate_index].prev_ieee;
+
+	if (rate == IWL_RATE_INVALID)
+		rate = rate_index;
+	return rate;
+}
+
+extern int iwl_rate_index_from_plcp(int plcp);
+
+/**
+ * iwl_fill_rs_info - Fill an output text buffer with the rate representation
+ *
+ * NOTE:  This is provided as a quick mechanism for a user to visualize
+ * the performance of the rate control alogirthm and is not meant to be
+ * parsed software.
+ */
+extern int iwl_fill_rs_info(struct ieee80211_hw *, char *buf, u8 sta_id);
+
+/**
+ * iwl_rate_scale_init - Initialize the rate scale table based on assoc info
+ *
+ * The specific througput table used is based on the type of network
+ * the associated with, including A, B, G, and G w/ TGG protection
+ */
+extern void iwl_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
+
+/**
+ * iwl_rate_control_register - Register the rate control algorithm callbacks
+ *
+ * Since the rate control algorithm is hardware specific, there is no need
+ * or reason to place it as a stand alone module.  The driver can call
+ * iwl_rate_control_register in order to register the rate control callbacks
+ * with the mac80211 subsystem.  This should be performed prior to calling
+ * ieee80211_register_hw
+ *
+ */
+extern void iwl_rate_control_register(struct ieee80211_hw *hw);
+
+/**
+ * iwl_rate_control_unregister - Unregister the rate control callbacks
+ *
+ * This should be called after calling ieee80211_unregister_hw, but before
+ * the driver is unloaded.
+ */
+extern void iwl_rate_control_unregister(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
new file mode 100644
index 0000000..b50d202
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -0,0 +1,4736 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <net/mac80211.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+
+#define IWL 4965
+
+#include "iwlwifi.h"
+#include "iwl-4965.h"
+#include "iwl-helpers.h"
+
+#define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np)    \
+	[IWL_RATE_##r##M_INDEX] = { IWL_RATE_##r##M_PLCP,      \
+				    IWL_RATE_SISO_##s##M_PLCP, \
+				    IWL_RATE_MIMO_##s##M_PLCP, \
+				    IWL_RATE_##r##M_IEEE,      \
+				    IWL_RATE_##ip##M_INDEX,    \
+				    IWL_RATE_##in##M_INDEX,    \
+				    IWL_RATE_##rp##M_INDEX,    \
+				    IWL_RATE_##rn##M_INDEX,    \
+				    IWL_RATE_##pp##M_INDEX,    \
+				    IWL_RATE_##np##M_INDEX }
+
+/*
+ * Parameter order:
+ *   rate, ht rate, prev rate, next rate, prev tgg rate, next tgg rate
+ *
+ * If there isn't a valid next or previous rate then INV is used which
+ * maps to IWL_RATE_INVALID
+ *
+ */
+const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
+	IWL_DECLARE_RATE_INFO(1, INV, INV, 2, INV, 2, INV, 2),    /*  1mbps */
+	IWL_DECLARE_RATE_INFO(2, INV, 1, 5, 1, 5, 1, 5),          /*  2mbps */
+	IWL_DECLARE_RATE_INFO(5, INV, 2, 6, 2, 11, 2, 11),        /*5.5mbps */
+	IWL_DECLARE_RATE_INFO(11, INV, 9, 12, 9, 12, 5, 18),      /* 11mbps */
+	IWL_DECLARE_RATE_INFO(6, 6, 5, 9, 5, 11, 5, 11),        /*  6mbps */
+	IWL_DECLARE_RATE_INFO(9, 6, 6, 11, 6, 11, 5, 11),       /*  9mbps */
+	IWL_DECLARE_RATE_INFO(12, 12, 11, 18, 11, 18, 11, 18),   /* 12mbps */
+	IWL_DECLARE_RATE_INFO(18, 18, 12, 24, 12, 24, 11, 24),   /* 18mbps */
+	IWL_DECLARE_RATE_INFO(24, 24, 18, 36, 18, 36, 18, 36),   /* 24mbps */
+	IWL_DECLARE_RATE_INFO(36, 36, 24, 48, 24, 48, 24, 48),   /* 36mbps */
+	IWL_DECLARE_RATE_INFO(48, 48, 36, 54, 36, 54, 36, 54),   /* 48mbps */
+	IWL_DECLARE_RATE_INFO(54, 54, 48, INV, 48, INV, 48, INV),/* 54mbps */
+	IWL_DECLARE_RATE_INFO(60, 60, 48, INV, 48, INV, 48, INV),/* 60mbps */
+};
+
+static int is_fat_channel(__le32 rxon_flags)
+{
+	return (rxon_flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) ||
+		(rxon_flags & RXON_FLG_CHANNEL_MODE_MIXED_MSK);
+}
+
+static u8 is_single_stream(struct iwl_priv *priv)
+{
+#ifdef CONFIG_IWLWIFI_HT
+	if (!priv->is_ht_enabled || !priv->current_assoc_ht.is_ht ||
+	    (priv->active_rate_ht[1] == 0) ||
+	    (priv->ps_mode == IWL_MIMO_PS_STATIC))
+		return 1;
+#else
+	return 1;
+#endif	/*CONFIG_IWLWIFI_HT */
+	return 0;
+}
+
+/*
+ * Determine how many receiver/antenna chains to use.
+ * More provides better reception via diversity.  Fewer saves power.
+ * MIMO (dual stream) requires at least 2, but works better with 3.
+ * This does not determine *which* chains to use, just how many.
+ */
+static int iwl4965_get_rx_chain_counter(struct iwl_priv *priv,
+					u8 *idle_state, u8 *rx_state)
+{
+	u8 is_single = is_single_stream(priv);
+	u8 is_cam = test_bit(STATUS_POWER_PMI, &priv->status) ? 0 : 1;
+
+	/* # of Rx chains to use when expecting MIMO. */
+	if (is_single || (!is_cam && (priv->ps_mode == IWL_MIMO_PS_STATIC)))
+		*rx_state = 2;
+	else
+		*rx_state = 3;
+
+	/* # Rx chains when idling and maybe trying to save power */
+	switch (priv->ps_mode) {
+	case IWL_MIMO_PS_STATIC:
+	case IWL_MIMO_PS_DYNAMIC:
+		*idle_state = (is_cam) ? 2 : 1;
+		break;
+	case IWL_MIMO_PS_NONE:
+		*idle_state = (is_cam) ? *rx_state : 1;
+		break;
+	default:
+		*idle_state = 1;
+		break;
+	}
+
+	return 0;
+}
+
+int iwl_hw_rxq_stop(struct iwl_priv *priv)
+{
+	int rc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+
+	/* stop HW */
+	iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+	rc = iwl_poll_restricted_bit(priv, FH_MEM_RSSR_RX_STATUS_REG,
+				     (1 << 24), 1000);
+	if (rc < 0)
+		IWL_ERROR("Can't stop Rx DMA.\n");
+
+	iwl_release_restricted_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *addr)
+{
+	int i;
+	int start = 0;
+	int ret = IWL_INVALID_STATION;
+	unsigned long flags;
+	DECLARE_MAC_BUF(mac);
+
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) ||
+	    (priv->iw_mode == IEEE80211_IF_TYPE_AP))
+		start = IWL_STA_ID;
+
+	if (is_broadcast_ether_addr(addr))
+		return IWL4965_BROADCAST_ID;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	for (i = start; i < priv->hw_setting.max_stations; i++)
+		if ((priv->stations[i].used) &&
+		    (!compare_ether_addr
+		     (priv->stations[i].sta.sta.addr, addr))) {
+			ret = i;
+			goto out;
+		}
+
+	IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n",
+			print_mac(mac, addr), priv->num_stations);
+
+ out:
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+	return ret;
+}
+
+static int iwl4965_nic_set_pwr_src(struct iwl_priv *priv, int pwr_max)
+{
+	int rc = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+
+	if (!pwr_max) {
+		u32 val;
+
+		rc = pci_read_config_dword(priv->pci_dev, PCI_POWER_SOURCE,
+					   &val);
+
+		if (val & PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT)
+			iwl_set_bits_mask_restricted_reg(
+				priv, APMG_PS_CTRL_REG,
+				APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
+				~APMG_PS_CTRL_MSK_PWR_SRC);
+	} else
+		iwl_set_bits_mask_restricted_reg(
+			priv, APMG_PS_CTRL_REG,
+			APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+			~APMG_PS_CTRL_MSK_PWR_SRC);
+
+	iwl_release_restricted_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return rc;
+}
+
+static int iwl4965_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+	int rc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+
+	/* stop HW */
+	iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+
+	iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
+	iwl_write_restricted(priv, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+			     rxq->dma_addr >> 8);
+
+	iwl_write_restricted(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG,
+			     (priv->hw_setting.shared_phys +
+			      offsetof(struct iwl_shared, val0)) >> 4);
+
+	iwl_write_restricted(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG,
+			     FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
+			     FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
+			     IWL_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K |
+			     /*0x10 << 4 | */
+			     (RX_QUEUE_SIZE_LOG <<
+			      FH_RCSR_RX_CONFIG_RBDCB_SIZE_BITSHIFT));
+
+	/*
+	 * iwl_write32(priv,CSR_INT_COAL_REG,0);
+	 */
+
+	iwl_release_restricted_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+static int iwl4965_kw_init(struct iwl_priv *priv)
+{
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl_grab_restricted_access(priv);
+	if (rc)
+		goto out;
+
+	iwl_write_restricted(priv, IWL_FH_KW_MEM_ADDR_REG,
+			     priv->kw.dma_addr >> 4);
+	iwl_release_restricted_access(priv);
+out:
+	spin_unlock_irqrestore(&priv->lock, flags);
+	return rc;
+}
+
+static int iwl4965_kw_alloc(struct iwl_priv *priv)
+{
+	struct pci_dev *dev = priv->pci_dev;
+	struct iwl_kw *kw = &priv->kw;
+
+	kw->size = IWL4965_KW_SIZE;	/* TBW need set somewhere else */
+	kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr);
+	if (!kw->v_addr)
+		return -ENOMEM;
+
+	return 0;
+}
+
+#define CHECK_AND_PRINT(x) ((eeprom_ch->flags & EEPROM_CHANNEL_##x) \
+			    ? # x " " : "")
+
+int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode, u16 channel,
+			      const struct iwl_eeprom_channel *eeprom_ch,
+			      u8 fat_extension_channel)
+{
+	struct iwl_channel_info *ch_info;
+
+	ch_info = (struct iwl_channel_info *)
+			iwl_get_channel_info(priv, phymode, channel);
+
+	if (!is_channel_valid(ch_info))
+		return -1;
+
+	IWL_DEBUG_INFO("FAT Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
+			" %ddBm): Ad-Hoc %ssupported\n",
+			ch_info->channel,
+			is_channel_a_band(ch_info) ?
+			"5.2" : "2.4",
+			CHECK_AND_PRINT(IBSS),
+			CHECK_AND_PRINT(ACTIVE),
+			CHECK_AND_PRINT(RADAR),
+			CHECK_AND_PRINT(WIDE),
+			CHECK_AND_PRINT(NARROW),
+			CHECK_AND_PRINT(DFS),
+			eeprom_ch->flags,
+			eeprom_ch->max_power_avg,
+			((eeprom_ch->flags & EEPROM_CHANNEL_IBSS)
+			 && !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ?
+			"" : "not ");
+
+	ch_info->fat_eeprom = *eeprom_ch;
+	ch_info->fat_max_power_avg = eeprom_ch->max_power_avg;
+	ch_info->fat_curr_txpow = eeprom_ch->max_power_avg;
+	ch_info->fat_min_power = 0;
+	ch_info->fat_scan_power = eeprom_ch->max_power_avg;
+	ch_info->fat_flags = eeprom_ch->flags;
+	ch_info->fat_extension_channel = fat_extension_channel;
+
+	return 0;
+}
+
+static void iwl4965_kw_free(struct iwl_priv *priv)
+{
+	struct pci_dev *dev = priv->pci_dev;
+	struct iwl_kw *kw = &priv->kw;
+
+	if (kw->v_addr) {
+		pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr);
+		memset(kw, 0, sizeof(*kw));
+	}
+}
+
+/**
+ * iwl4965_txq_ctx_reset - Reset TX queue context
+ * Destroys all DMA structures and initialise them again
+ *
+ * @param priv
+ * @return error code
+ */
+static int iwl4965_txq_ctx_reset(struct iwl_priv *priv)
+{
+	int rc = 0;
+	int txq_id, slots_num;
+	unsigned long flags;
+
+	iwl4965_kw_free(priv);
+
+	iwl_hw_txq_ctx_free(priv);
+
+	/* Tx CMD queue */
+	rc = iwl4965_kw_alloc(priv);
+	if (rc) {
+		IWL_ERROR("Keep Warm allocation failed");
+		goto error_kw;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	rc = iwl_grab_restricted_access(priv);
+	if (unlikely(rc)) {
+		IWL_ERROR("TX reset failed");
+		spin_unlock_irqrestore(&priv->lock, flags);
+		goto error_reset;
+	}
+
+	iwl_write_restricted_reg(priv, SCD_TXFACT, 0);
+	iwl_release_restricted_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	rc = iwl4965_kw_init(priv);
+	if (rc) {
+		IWL_ERROR("kw_init failed\n");
+		goto error_reset;
+	}
+
+	/* Tx queue(s) */
+	for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) {
+		slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
+					TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+		rc = iwl_tx_queue_init(priv, &priv->txq[txq_id], slots_num,
+				       txq_id);
+		if (rc) {
+			IWL_ERROR("Tx %d queue init failed\n", txq_id);
+			goto error;
+		}
+	}
+
+	return rc;
+
+ error:
+	iwl_hw_txq_ctx_free(priv);
+ error_reset:
+	iwl4965_kw_free(priv);
+ error_kw:
+	return rc;
+}
+
+int iwl_hw_nic_init(struct iwl_priv *priv)
+{
+	int rc;
+	unsigned long flags;
+	struct iwl_rx_queue *rxq = &priv->rxq;
+	u8 rev_id;
+	u32 val;
+	u8 val_link;
+
+	iwl_power_init_handle(priv);
+
+	/* nic_init */
+	spin_lock_irqsave(&priv->lock, flags);
+
+	iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+		    CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
+
+	iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+	rc = iwl_poll_bit(priv, CSR_GP_CNTRL,
+			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+	if (rc < 0) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		IWL_DEBUG_INFO("Failed to init the card\n");
+		return rc;
+	}
+
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+
+	iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG);
+
+	iwl_write_restricted_reg(priv, APMG_CLK_CTRL_REG,
+				 APMG_CLK_VAL_DMA_CLK_RQT |
+				 APMG_CLK_VAL_BSM_CLK_RQT);
+	iwl_read_restricted_reg(priv, APMG_CLK_CTRL_REG);
+
+	udelay(20);
+
+	iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG,
+				    APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
+	iwl_release_restricted_access(priv);
+	iwl_write32(priv, CSR_INT_COALESCING, 512 / 32);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	/* Determine HW type */
+	rc = pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id);
+	if (rc)
+		return rc;
+
+	IWL_DEBUG_INFO("HW Revision ID = 0x%X\n", rev_id);
+
+	iwl4965_nic_set_pwr_src(priv, 1);
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if ((rev_id & 0x80) == 0x80 && (rev_id & 0x7f) < 8) {
+		pci_read_config_dword(priv->pci_dev, PCI_REG_WUM8, &val);
+		/* Enable No Snoop field */
+		pci_write_config_dword(priv->pci_dev, PCI_REG_WUM8,
+				       val & ~(1 << 11));
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	/* Read the EEPROM */
+	rc = iwl_eeprom_init(priv);
+	if (rc)
+		return rc;
+
+	if (priv->eeprom.calib_version < EEPROM_TX_POWER_VERSION_NEW) {
+		IWL_ERROR("Older EEPROM detected!  Aborting.\n");
+		return -EINVAL;
+	}
+
+	pci_read_config_byte(priv->pci_dev, PCI_LINK_CTRL, &val_link);
+
+	/* disable L1 entry -- workaround for pre-B1 */
+	pci_write_config_byte(priv->pci_dev, PCI_LINK_CTRL, val_link & ~0x02);
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	/* set CSR_HW_CONFIG_REG for uCode use */
+
+	iwl_set_bit(priv, CSR_SW_VER, CSR_HW_IF_CONFIG_REG_BIT_KEDRON_R |
+		    CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI |
+		    CSR_HW_IF_CONFIG_REG_BIT_MAC_SI);
+
+	rc = iwl_grab_restricted_access(priv);
+	if (rc < 0) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		IWL_DEBUG_INFO("Failed to init the card\n");
+		return rc;
+	}
+
+	iwl_read_restricted_reg(priv, APMG_PS_CTRL_REG);
+	iwl_set_bits_restricted_reg(priv, APMG_PS_CTRL_REG,
+				    APMG_PS_CTRL_VAL_RESET_REQ);
+	udelay(5);
+	iwl_clear_bits_restricted_reg(priv, APMG_PS_CTRL_REG,
+				      APMG_PS_CTRL_VAL_RESET_REQ);
+
+	iwl_release_restricted_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	iwl_hw_card_show_info(priv);
+
+	/* end nic_init */
+
+	/* Allocate the RX queue, or reset if it is already allocated */
+	if (!rxq->bd) {
+		rc = iwl_rx_queue_alloc(priv);
+		if (rc) {
+			IWL_ERROR("Unable to initialize Rx queue\n");
+			return -ENOMEM;
+		}
+	} else
+		iwl_rx_queue_reset(priv, rxq);
+
+	iwl_rx_replenish(priv);
+
+	iwl4965_rx_init(priv, rxq);
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	rxq->need_update = 1;
+	iwl_rx_queue_update_write_ptr(priv, rxq);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+	rc = iwl4965_txq_ctx_reset(priv);
+	if (rc)
+		return rc;
+
+	if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_SW_RF_KILL_ENABLE)
+		IWL_DEBUG_RF_KILL("SW RF KILL supported in EEPROM.\n");
+
+	if (priv->eeprom.sku_cap & EEPROM_SKU_CAP_HW_RF_KILL_ENABLE)
+		IWL_DEBUG_RF_KILL("HW RF KILL supported in EEPROM.\n");
+
+	set_bit(STATUS_INIT, &priv->status);
+
+	return 0;
+}
+
+int iwl_hw_nic_stop_master(struct iwl_priv *priv)
+{
+	int rc = 0;
+	u32 reg_val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	/* set stop master bit */
+	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER);
+
+	reg_val = iwl_read32(priv, CSR_GP_CNTRL);
+
+	if (CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE ==
+	    (reg_val & CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE))
+		IWL_DEBUG_INFO("Card in power save, master is already "
+			       "stopped\n");
+	else {
+		rc = iwl_poll_bit(priv, CSR_RESET,
+				  CSR_RESET_REG_FLAG_MASTER_DISABLED,
+				  CSR_RESET_REG_FLAG_MASTER_DISABLED, 100);
+		if (rc < 0) {
+			spin_unlock_irqrestore(&priv->lock, flags);
+			return rc;
+		}
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+	IWL_DEBUG_INFO("stop master\n");
+
+	return rc;
+}
+
+void iwl_hw_txq_ctx_stop(struct iwl_priv *priv)
+{
+
+	int txq_id;
+	unsigned long flags;
+
+	/* reset TFD queues */
+	for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++) {
+		spin_lock_irqsave(&priv->lock, flags);
+		if (iwl_grab_restricted_access(priv)) {
+			spin_unlock_irqrestore(&priv->lock, flags);
+			continue;
+		}
+
+		iwl_write_restricted(priv,
+				     IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
+				     0x0);
+		iwl_poll_restricted_bit(priv, IWL_FH_TSSR_TX_STATUS_REG,
+					IWL_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE
+					(txq_id), 200);
+		iwl_release_restricted_access(priv);
+		spin_unlock_irqrestore(&priv->lock, flags);
+	}
+
+	iwl_hw_txq_ctx_free(priv);
+}
+
+int iwl_hw_nic_reset(struct iwl_priv *priv)
+{
+	int rc = 0;
+	unsigned long flags;
+
+	iwl_hw_nic_stop_master(priv);
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+
+	udelay(10);
+
+	iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+	rc = iwl_poll_bit(priv, CSR_RESET,
+			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+			  CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25);
+
+	udelay(10);
+
+	rc = iwl_grab_restricted_access(priv);
+	if (!rc) {
+		iwl_write_restricted_reg(priv, APMG_CLK_EN_REG,
+					 APMG_CLK_VAL_DMA_CLK_RQT |
+					 APMG_CLK_VAL_BSM_CLK_RQT);
+
+		udelay(10);
+
+		iwl_set_bits_restricted_reg(priv, APMG_PCIDEV_STT_REG,
+				APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+
+		iwl_release_restricted_access(priv);
+	}
+
+	clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+	wake_up_interruptible(&priv->wait_command_queue);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return rc;
+
+}
+
+#define REG_RECALIB_PERIOD (60)
+
+/**
+ * iwl4965_bg_statistics_periodic - Timer callback to queue statistics
+ *
+ * This callback is provided in order to queue the statistics_work
+ * in work_queue context (v. softirq)
+ *
+ * This timer function is continually reset to execute within
+ * REG_RECALIB_PERIOD seconds since the last STATISTICS_NOTIFICATION
+ * was received.  We need to ensure we receive the statistics in order
+ * to update the temperature used for calibrating the TXPOWER.  However,
+ * we can't send the statistics command from softirq context (which
+ * is the context which timers run at) so we have to queue off the
+ * statistics_work to actually send the command to the hardware.
+ */
+static void iwl4965_bg_statistics_periodic(unsigned long data)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)data;
+
+	queue_work(priv->workqueue, &priv->statistics_work);
+}
+
+/**
+ * iwl4965_bg_statistics_work - Send the statistics request to the hardware.
+ *
+ * This is queued by iwl_bg_statistics_periodic.
+ */
+static void iwl4965_bg_statistics_work(struct work_struct *work)
+{
+	struct iwl_priv *priv = container_of(work, struct iwl_priv,
+					     statistics_work);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	iwl_send_statistics_request(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+#define CT_LIMIT_CONST		259
+#define TM_CT_KILL_THRESHOLD	110
+
+void iwl4965_rf_kill_ct_config(struct iwl_priv *priv)
+{
+	struct iwl_ct_kill_config cmd;
+	u32 R1, R2, R3;
+	u32 temp_th;
+	u32 crit_temperature;
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+		    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK) {
+		R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]);
+		R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]);
+		R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]);
+	} else {
+		R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]);
+		R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]);
+		R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]);
+	}
+
+	temp_th = CELSIUS_TO_KELVIN(TM_CT_KILL_THRESHOLD);
+
+	crit_temperature = ((temp_th * (R3-R1))/CT_LIMIT_CONST) + R2;
+	cmd.critical_temperature_R =  cpu_to_le32(crit_temperature);
+	rc = iwl_send_cmd_pdu(priv,
+			      REPLY_CT_KILL_CONFIG_CMD, sizeof(cmd), &cmd);
+	if (rc)
+		IWL_ERROR("REPLY_CT_KILL_CONFIG_CMD failed\n");
+	else
+		IWL_DEBUG_INFO("REPLY_CT_KILL_CONFIG_CMD succeeded\n");
+}
+
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+
+/* "false alarms" are signals that our DSP tries to lock onto,
+ *   but then determines that they are either noise, or transmissions
+ *   from a distant wireless network (also "noise", really) that get
+ *   "stepped on" by stronger transmissions within our own network.
+ * This algorithm attempts to set a sensitivity level that is high
+ *   enough to receive all of our own network traffic, but not so
+ *   high that our DSP gets too busy trying to lock onto non-network
+ *   activity/noise. */
+static int iwl4965_sens_energy_cck(struct iwl_priv *priv,
+				   u32 norm_fa,
+				   u32 rx_enable_time,
+				   struct statistics_general_data *rx_info)
+{
+	u32 max_nrg_cck = 0;
+	int i = 0;
+	u8 max_silence_rssi = 0;
+	u32 silence_ref = 0;
+	u8 silence_rssi_a = 0;
+	u8 silence_rssi_b = 0;
+	u8 silence_rssi_c = 0;
+	u32 val;
+
+	/* "false_alarms" values below are cross-multiplications to assess the
+	 *   numbers of false alarms within the measured period of actual Rx
+	 *   (Rx is off when we're txing), vs the min/max expected false alarms
+	 *   (some should be expected if rx is sensitive enough) in a
+	 *   hypothetical listening period of 200 time units (TU), 204.8 msec:
+	 *
+	 * MIN_FA/fixed-time < false_alarms/actual-rx-time < MAX_FA/beacon-time
+	 *
+	 * */
+	u32 false_alarms = norm_fa * 200 * 1024;
+	u32 max_false_alarms = MAX_FA_CCK * rx_enable_time;
+	u32 min_false_alarms = MIN_FA_CCK * rx_enable_time;
+	struct iwl_sensitivity_data *data = NULL;
+
+	data = &(priv->sensitivity_data);
+
+	data->nrg_auto_corr_silence_diff = 0;
+
+	/* Find max silence rssi among all 3 receivers.
+	 * This is background noise, which may include transmissions from other
+	 *    networks, measured during silence before our network's beacon */
+	silence_rssi_a = (u8)((rx_info->beacon_silence_rssi_a &
+			    ALL_BAND_FILTER)>>8);
+	silence_rssi_b = (u8)((rx_info->beacon_silence_rssi_b &
+			    ALL_BAND_FILTER)>>8);
+	silence_rssi_c = (u8)((rx_info->beacon_silence_rssi_c &
+			    ALL_BAND_FILTER)>>8);
+
+	val = max(silence_rssi_b, silence_rssi_c);
+	max_silence_rssi = max(silence_rssi_a, (u8) val);
+
+	/* Store silence rssi in 20-beacon history table */
+	data->nrg_silence_rssi[data->nrg_silence_idx] = max_silence_rssi;
+	data->nrg_silence_idx++;
+	if (data->nrg_silence_idx >= NRG_NUM_PREV_STAT_L)
+		data->nrg_silence_idx = 0;
+
+	/* Find max silence rssi across 20 beacon history */
+	for (i = 0; i < NRG_NUM_PREV_STAT_L; i++) {
+		val = data->nrg_silence_rssi[i];
+		silence_ref = max(silence_ref, val);
+	}
+	IWL_DEBUG_CALIB("silence a %u, b %u, c %u, 20-bcn max %u\n",
+			silence_rssi_a, silence_rssi_b, silence_rssi_c,
+			silence_ref);
+
+	/* Find max rx energy (min value!) among all 3 receivers,
+	 *   measured during beacon frame.
+	 * Save it in 10-beacon history table. */
+	i = data->nrg_energy_idx;
+	val = min(rx_info->beacon_energy_b, rx_info->beacon_energy_c);
+	data->nrg_value[i] = min(rx_info->beacon_energy_a, val);
+
+	data->nrg_energy_idx++;
+	if (data->nrg_energy_idx >= 10)
+		data->nrg_energy_idx = 0;
+
+	/* Find min rx energy (max value) across 10 beacon history.
+	 * This is the minimum signal level that we want to receive well.
+	 * Add backoff (margin so we don't miss slightly lower energy frames).
+	 * This establishes an upper bound (min value) for energy threshold. */
+	max_nrg_cck = data->nrg_value[0];
+	for (i = 1; i < 10; i++)
+		max_nrg_cck = (u32) max(max_nrg_cck, (data->nrg_value[i]));
+	max_nrg_cck += 6;
+
+	IWL_DEBUG_CALIB("rx energy a %u, b %u, c %u, 10-bcn max/min %u\n",
+			rx_info->beacon_energy_a, rx_info->beacon_energy_b,
+			rx_info->beacon_energy_c, max_nrg_cck - 6);
+
+	/* Count number of consecutive beacons with fewer-than-desired
+	 *   false alarms. */
+	if (false_alarms < min_false_alarms)
+		data->num_in_cck_no_fa++;
+	else
+		data->num_in_cck_no_fa = 0;
+	IWL_DEBUG_CALIB("consecutive bcns with few false alarms = %u\n",
+			data->num_in_cck_no_fa);
+
+	/* If we got too many false alarms this time, reduce sensitivity */
+	if (false_alarms > max_false_alarms) {
+		IWL_DEBUG_CALIB("norm FA %u > max FA %u\n",
+			     false_alarms, max_false_alarms);
+		IWL_DEBUG_CALIB("... reducing sensitivity\n");
+		data->nrg_curr_state = IWL_FA_TOO_MANY;
+
+		if (data->auto_corr_cck > AUTO_CORR_MAX_TH_CCK) {
+			/* Store for "fewer than desired" on later beacon */
+			data->nrg_silence_ref = silence_ref;
+
+			/* increase energy threshold (reduce nrg value)
+			 *   to decrease sensitivity */
+			if (data->nrg_th_cck > (NRG_MAX_CCK + NRG_STEP_CCK))
+				data->nrg_th_cck = data->nrg_th_cck
+							 - NRG_STEP_CCK;
+		}
+
+		/* increase auto_corr values to decrease sensitivity */
+		if (data->auto_corr_cck < AUTO_CORR_MAX_TH_CCK)
+			data->auto_corr_cck = AUTO_CORR_MAX_TH_CCK + 1;
+		else {
+			val = data->auto_corr_cck + AUTO_CORR_STEP_CCK;
+			data->auto_corr_cck = min((u32)AUTO_CORR_MAX_CCK, val);
+		}
+		val = data->auto_corr_cck_mrc + AUTO_CORR_STEP_CCK;
+		data->auto_corr_cck_mrc = min((u32)AUTO_CORR_MAX_CCK_MRC, val);
+
+	/* Else if we got fewer than desired, increase sensitivity */
+	} else if (false_alarms < min_false_alarms) {
+		data->nrg_curr_state = IWL_FA_TOO_FEW;
+
+		/* Compare silence level with silence level for most recent
+		 *   healthy number or too many false alarms */
+		data->nrg_auto_corr_silence_diff = (s32)data->nrg_silence_ref -
+						   (s32)silence_ref;
+
+		IWL_DEBUG_CALIB("norm FA %u < min FA %u, silence diff %d\n",
+			 false_alarms, min_false_alarms,
+			 data->nrg_auto_corr_silence_diff);
+
+		/* Increase value to increase sensitivity, but only if:
+		 * 1a) previous beacon did *not* have *too many* false alarms
+		 * 1b) AND there's a significant difference in Rx levels
+		 *      from a previous beacon with too many, or healthy # FAs
+		 * OR 2) We've seen a lot of beacons (100) with too few
+		 *       false alarms */
+		if ((data->nrg_prev_state != IWL_FA_TOO_MANY) &&
+			((data->nrg_auto_corr_silence_diff > NRG_DIFF) ||
+			(data->num_in_cck_no_fa > MAX_NUMBER_CCK_NO_FA))) {
+
+			IWL_DEBUG_CALIB("... increasing sensitivity\n");
+			/* Increase nrg value to increase sensitivity */
+			val = data->nrg_th_cck + NRG_STEP_CCK;
+			data->nrg_th_cck = min((u32)NRG_MIN_CCK, val);
+
+			/* Decrease auto_corr values to increase sensitivity */
+			val = data->auto_corr_cck - AUTO_CORR_STEP_CCK;
+			data->auto_corr_cck = max((u32)AUTO_CORR_MIN_CCK, val);
+
+			val = data->auto_corr_cck_mrc - AUTO_CORR_STEP_CCK;
+			data->auto_corr_cck_mrc =
+					 max((u32)AUTO_CORR_MIN_CCK_MRC, val);
+
+		} else
+			IWL_DEBUG_CALIB("... but not changing sensitivity\n");
+
+	/* Else we got a healthy number of false alarms, keep status quo */
+	} else {
+		IWL_DEBUG_CALIB(" FA in safe zone\n");
+		data->nrg_curr_state = IWL_FA_GOOD_RANGE;
+
+		/* Store for use in "fewer than desired" with later beacon */
+		data->nrg_silence_ref = silence_ref;
+
+		/* If previous beacon had too many false alarms,
+		 *   give it some extra margin by reducing sensitivity again
+		 *   (but don't go below measured energy of desired Rx) */
+		if (IWL_FA_TOO_MANY == data->nrg_prev_state) {
+			IWL_DEBUG_CALIB("... increasing margin\n");
+			data->nrg_th_cck -= NRG_MARGIN;
+		}
+	}
+
+	/* Make sure the energy threshold does not go above the measured
+	 * energy of the desired Rx signals (reduced by backoff margin),
+	 * or else we might start missing Rx frames.
+	 * Lower value is higher energy, so we use max()!
+	 */
+	data->nrg_th_cck = max(max_nrg_cck, data->nrg_th_cck);
+	IWL_DEBUG_CALIB("new nrg_th_cck %u\n", data->nrg_th_cck);
+
+	data->nrg_prev_state = data->nrg_curr_state;
+
+	return 0;
+}
+
+
+static int iwl4965_sens_auto_corr_ofdm(struct iwl_priv *priv,
+				       u32 norm_fa,
+				       u32 rx_enable_time)
+{
+	u32 val;
+	u32 false_alarms = norm_fa * 200 * 1024;
+	u32 max_false_alarms = MAX_FA_OFDM * rx_enable_time;
+	u32 min_false_alarms = MIN_FA_OFDM * rx_enable_time;
+	struct iwl_sensitivity_data *data = NULL;
+
+	data = &(priv->sensitivity_data);
+
+	/* If we got too many false alarms this time, reduce sensitivity */
+	if (false_alarms > max_false_alarms) {
+
+		IWL_DEBUG_CALIB("norm FA %u > max FA %u)\n",
+			     false_alarms, max_false_alarms);
+
+		val = data->auto_corr_ofdm + AUTO_CORR_STEP_OFDM;
+		data->auto_corr_ofdm =
+				min((u32)AUTO_CORR_MAX_OFDM, val);
+
+		val = data->auto_corr_ofdm_mrc + AUTO_CORR_STEP_OFDM;
+		data->auto_corr_ofdm_mrc =
+				min((u32)AUTO_CORR_MAX_OFDM_MRC, val);
+
+		val = data->auto_corr_ofdm_x1 + AUTO_CORR_STEP_OFDM;
+		data->auto_corr_ofdm_x1 =
+				min((u32)AUTO_CORR_MAX_OFDM_X1, val);
+
+		val = data->auto_corr_ofdm_mrc_x1 + AUTO_CORR_STEP_OFDM;
+		data->auto_corr_ofdm_mrc_x1 =
+				min((u32)AUTO_CORR_MAX_OFDM_MRC_X1, val);
+	}
+
+	/* Else if we got fewer than desired, increase sensitivity */
+	else if (false_alarms < min_false_alarms) {
+
+		IWL_DEBUG_CALIB("norm FA %u < min FA %u\n",
+			     false_alarms, min_false_alarms);
+
+		val = data->auto_corr_ofdm - AUTO_CORR_STEP_OFDM;
+		data->auto_corr_ofdm =
+				max((u32)AUTO_CORR_MIN_OFDM, val);
+
+		val = data->auto_corr_ofdm_mrc - AUTO_CORR_STEP_OFDM;
+		data->auto_corr_ofdm_mrc =
+				max((u32)AUTO_CORR_MIN_OFDM_MRC, val);
+
+		val = data->auto_corr_ofdm_x1 - AUTO_CORR_STEP_OFDM;
+		data->auto_corr_ofdm_x1 =
+				max((u32)AUTO_CORR_MIN_OFDM_X1, val);
+
+		val = data->auto_corr_ofdm_mrc_x1 - AUTO_CORR_STEP_OFDM;
+		data->auto_corr_ofdm_mrc_x1 =
+				max((u32)AUTO_CORR_MIN_OFDM_MRC_X1, val);
+	}
+
+	else
+		IWL_DEBUG_CALIB("min FA %u < norm FA %u < max FA %u OK\n",
+			 min_false_alarms, false_alarms, max_false_alarms);
+
+	return 0;
+}
+
+static int iwl_sensitivity_callback(struct iwl_priv *priv,
+				    struct iwl_cmd *cmd, struct sk_buff *skb)
+{
+	/* We didn't cache the SKB; let the caller free it */
+	return 1;
+}
+
+/* Prepare a SENSITIVITY_CMD, send to uCode if values have changed */
+static int iwl4965_sensitivity_write(struct iwl_priv *priv, u8 flags)
+{
+	int rc = 0;
+	struct iwl_sensitivity_cmd cmd ;
+	struct iwl_sensitivity_data *data = NULL;
+	struct iwl_host_cmd cmd_out = {
+		.id = SENSITIVITY_CMD,
+		.len = sizeof(struct iwl_sensitivity_cmd),
+		.meta.flags = flags,
+		.data = &cmd,
+	};
+
+	data = &(priv->sensitivity_data);
+
+	memset(&cmd, 0, sizeof(cmd));
+
+	cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX] =
+				cpu_to_le16((u16)data->auto_corr_ofdm);
+	cmd.table[HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX] =
+				cpu_to_le16((u16)data->auto_corr_ofdm_mrc);
+	cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX] =
+				cpu_to_le16((u16)data->auto_corr_ofdm_x1);
+	cmd.table[HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX] =
+				cpu_to_le16((u16)data->auto_corr_ofdm_mrc_x1);
+
+	cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX] =
+				cpu_to_le16((u16)data->auto_corr_cck);
+	cmd.table[HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX] =
+				cpu_to_le16((u16)data->auto_corr_cck_mrc);
+
+	cmd.table[HD_MIN_ENERGY_CCK_DET_INDEX] =
+				cpu_to_le16((u16)data->nrg_th_cck);
+	cmd.table[HD_MIN_ENERGY_OFDM_DET_INDEX] =
+				cpu_to_le16((u16)data->nrg_th_ofdm);
+
+	cmd.table[HD_BARKER_CORR_TH_ADD_MIN_INDEX] =
+				__constant_cpu_to_le16(190);
+	cmd.table[HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX] =
+				__constant_cpu_to_le16(390);
+	cmd.table[HD_OFDM_ENERGY_TH_IN_INDEX] =
+				__constant_cpu_to_le16(62);
+
+	IWL_DEBUG_CALIB("ofdm: ac %u mrc %u x1 %u mrc_x1 %u thresh %u\n",
+			data->auto_corr_ofdm, data->auto_corr_ofdm_mrc,
+			data->auto_corr_ofdm_x1, data->auto_corr_ofdm_mrc_x1,
+			data->nrg_th_ofdm);
+
+	IWL_DEBUG_CALIB("cck: ac %u mrc %u thresh %u\n",
+			data->auto_corr_cck, data->auto_corr_cck_mrc,
+			data->nrg_th_cck);
+
+	cmd.control = SENSITIVITY_CMD_CONTROL_WORK_TABLE;
+
+	if (flags & CMD_ASYNC)
+		cmd_out.meta.u.callback = iwl_sensitivity_callback;
+
+	/* Don't send command to uCode if nothing has changed */
+	if (!memcmp(&cmd.table[0], &(priv->sensitivity_tbl[0]),
+		    sizeof(u16)*HD_TABLE_SIZE)) {
+		IWL_DEBUG_CALIB("No change in SENSITIVITY_CMD\n");
+		return 0;
+	}
+
+	/* Copy table for comparison next time */
+	memcpy(&(priv->sensitivity_tbl[0]), &(cmd.table[0]),
+	       sizeof(u16)*HD_TABLE_SIZE);
+
+	rc = iwl_send_cmd(priv, &cmd_out);
+	if (!rc) {
+		IWL_DEBUG_CALIB("SENSITIVITY_CMD succeeded\n");
+		return rc;
+	}
+
+	return 0;
+}
+
+void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags, u8 force)
+{
+	int rc = 0;
+	int i;
+	struct iwl_sensitivity_data *data = NULL;
+
+	IWL_DEBUG_CALIB("Start iwl4965_init_sensitivity\n");
+
+	if (force)
+		memset(&(priv->sensitivity_tbl[0]), 0,
+			sizeof(u16)*HD_TABLE_SIZE);
+
+	/* Clear driver's sensitivity algo data */
+	data = &(priv->sensitivity_data);
+	memset(data, 0, sizeof(struct iwl_sensitivity_data));
+
+	data->num_in_cck_no_fa = 0;
+	data->nrg_curr_state = IWL_FA_TOO_MANY;
+	data->nrg_prev_state = IWL_FA_TOO_MANY;
+	data->nrg_silence_ref = 0;
+	data->nrg_silence_idx = 0;
+	data->nrg_energy_idx = 0;
+
+	for (i = 0; i < 10; i++)
+		data->nrg_value[i] = 0;
+
+	for (i = 0; i < NRG_NUM_PREV_STAT_L; i++)
+		data->nrg_silence_rssi[i] = 0;
+
+	data->auto_corr_ofdm = 90;
+	data->auto_corr_ofdm_mrc = 170;
+	data->auto_corr_ofdm_x1  = 105;
+	data->auto_corr_ofdm_mrc_x1 = 220;
+	data->auto_corr_cck = AUTO_CORR_CCK_MIN_VAL_DEF;
+	data->auto_corr_cck_mrc = 200;
+	data->nrg_th_cck = 100;
+	data->nrg_th_ofdm = 100;
+
+	data->last_bad_plcp_cnt_ofdm = 0;
+	data->last_fa_cnt_ofdm = 0;
+	data->last_bad_plcp_cnt_cck = 0;
+	data->last_fa_cnt_cck = 0;
+
+	/* Clear prior Sensitivity command data to force send to uCode */
+	if (force)
+		memset(&(priv->sensitivity_tbl[0]), 0,
+		    sizeof(u16)*HD_TABLE_SIZE);
+
+	rc |= iwl4965_sensitivity_write(priv, flags);
+	IWL_DEBUG_CALIB("<<return 0x%X\n", rc);
+
+	return;
+}
+
+
+/* Reset differential Rx gains in NIC to prepare for chain noise calibration.
+ * Called after every association, but this runs only once!
+ *  ... once chain noise is calibrated the first time, it's good forever.  */
+void iwl4965_chain_noise_reset(struct iwl_priv *priv)
+{
+	struct iwl_chain_noise_data *data = NULL;
+	int rc = 0;
+
+	data = &(priv->chain_noise_data);
+	if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
+		struct iwl_calibration_cmd cmd;
+
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
+		cmd.diff_gain_a = 0;
+		cmd.diff_gain_b = 0;
+		cmd.diff_gain_c = 0;
+		rc = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+				 sizeof(cmd), &cmd);
+		msleep(4);
+		data->state = IWL_CHAIN_NOISE_ACCUMULATE;
+		IWL_DEBUG_CALIB("Run chain_noise_calibrate\n");
+	}
+	return;
+}
+
+/*
+ * Accumulate 20 beacons of signal and noise statistics for each of
+ *   3 receivers/antennas/rx-chains, then figure out:
+ * 1)  Which antennas are connected.
+ * 2)  Differential rx gain settings to balance the 3 receivers.
+ */
+static void iwl4965_noise_calibration(struct iwl_priv *priv,
+				      struct iwl_notif_statistics *stat_resp)
+{
+	struct iwl_chain_noise_data *data = NULL;
+	int rc = 0;
+
+	u32 chain_noise_a;
+	u32 chain_noise_b;
+	u32 chain_noise_c;
+	u32 chain_sig_a;
+	u32 chain_sig_b;
+	u32 chain_sig_c;
+	u32 average_sig[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
+	u32 average_noise[NUM_RX_CHAINS] = {INITIALIZATION_VALUE};
+	u32 max_average_sig;
+	u16 max_average_sig_antenna_i;
+	u32 min_average_noise = MIN_AVERAGE_NOISE_MAX_VALUE;
+	u16 min_average_noise_antenna_i = INITIALIZATION_VALUE;
+	u16 i = 0;
+	u16 chan_num = INITIALIZATION_VALUE;
+	u32 band = INITIALIZATION_VALUE;
+	u32 active_chains = 0;
+	unsigned long flags;
+	struct statistics_rx_non_phy *rx_info = &(stat_resp->rx.general);
+
+	data = &(priv->chain_noise_data);
+
+	/* Accumulate just the first 20 beacons after the first association,
+	 *   then we're done forever. */
+	if (data->state != IWL_CHAIN_NOISE_ACCUMULATE) {
+		if (data->state == IWL_CHAIN_NOISE_ALIVE)
+			IWL_DEBUG_CALIB("Wait for noise calib reset\n");
+		return;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
+		IWL_DEBUG_CALIB(" << Interference data unavailable\n");
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return;
+	}
+
+	band = (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) ? 0 : 1;
+	chan_num = le16_to_cpu(priv->staging_rxon.channel);
+
+	/* Make sure we accumulate data for just the associated channel
+	 *   (even if scanning). */
+	if ((chan_num != (le32_to_cpu(stat_resp->flag) >> 16)) ||
+	    ((STATISTICS_REPLY_FLG_BAND_24G_MSK ==
+	     (stat_resp->flag & STATISTICS_REPLY_FLG_BAND_24G_MSK)) && band)) {
+		IWL_DEBUG_CALIB("Stats not from chan=%d, band=%d\n",
+				chan_num, band);
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return;
+	}
+
+	/* Accumulate beacon statistics values across 20 beacons */
+	chain_noise_a = le32_to_cpu(rx_info->beacon_silence_rssi_a) &
+				IN_BAND_FILTER;
+	chain_noise_b = le32_to_cpu(rx_info->beacon_silence_rssi_b) &
+				IN_BAND_FILTER;
+	chain_noise_c = le32_to_cpu(rx_info->beacon_silence_rssi_c) &
+				IN_BAND_FILTER;
+
+	chain_sig_a = le32_to_cpu(rx_info->beacon_rssi_a) & IN_BAND_FILTER;
+	chain_sig_b = le32_to_cpu(rx_info->beacon_rssi_b) & IN_BAND_FILTER;
+	chain_sig_c = le32_to_cpu(rx_info->beacon_rssi_c) & IN_BAND_FILTER;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	data->beacon_count++;
+
+	data->chain_noise_a = (chain_noise_a + data->chain_noise_a);
+	data->chain_noise_b = (chain_noise_b + data->chain_noise_b);
+	data->chain_noise_c = (chain_noise_c + data->chain_noise_c);
+
+	data->chain_signal_a = (chain_sig_a + data->chain_signal_a);
+	data->chain_signal_b = (chain_sig_b + data->chain_signal_b);
+	data->chain_signal_c = (chain_sig_c + data->chain_signal_c);
+
+	IWL_DEBUG_CALIB("chan=%d, band=%d, beacon=%d\n", chan_num, band,
+			data->beacon_count);
+	IWL_DEBUG_CALIB("chain_sig: a %d b %d c %d\n",
+			chain_sig_a, chain_sig_b, chain_sig_c);
+	IWL_DEBUG_CALIB("chain_noise: a %d b %d c %d\n",
+			chain_noise_a, chain_noise_b, chain_noise_c);
+
+	/* If this is the 20th beacon, determine:
+	 * 1)  Disconnected antennas (using signal strengths)
+	 * 2)  Differential gain (using silence noise) to balance receivers */
+	if (data->beacon_count == CAL_NUM_OF_BEACONS) {
+
+		/* Analyze signal for disconnected antenna */
+		average_sig[0] = (data->chain_signal_a) / CAL_NUM_OF_BEACONS;
+		average_sig[1] = (data->chain_signal_b) / CAL_NUM_OF_BEACONS;
+		average_sig[2] = (data->chain_signal_c) / CAL_NUM_OF_BEACONS;
+
+		if (average_sig[0] >= average_sig[1]) {
+			max_average_sig = average_sig[0];
+			max_average_sig_antenna_i = 0;
+			active_chains = (1 << max_average_sig_antenna_i);
+		} else {
+			max_average_sig = average_sig[1];
+			max_average_sig_antenna_i = 1;
+			active_chains = (1 << max_average_sig_antenna_i);
+		}
+
+		if (average_sig[2] >= max_average_sig) {
+			max_average_sig = average_sig[2];
+			max_average_sig_antenna_i = 2;
+			active_chains = (1 << max_average_sig_antenna_i);
+		}
+
+		IWL_DEBUG_CALIB("average_sig: a %d b %d c %d\n",
+			     average_sig[0], average_sig[1], average_sig[2]);
+		IWL_DEBUG_CALIB("max_average_sig = %d, antenna %d\n",
+			     max_average_sig, max_average_sig_antenna_i);
+
+		/* Compare signal strengths for all 3 receivers. */
+		for (i = 0; i < NUM_RX_CHAINS; i++) {
+			if (i != max_average_sig_antenna_i) {
+				s32 rssi_delta = (max_average_sig -
+						  average_sig[i]);
+
+				/* If signal is very weak, compared with
+				 * strongest, mark it as disconnected. */
+				if (rssi_delta > MAXIMUM_ALLOWED_PATHLOSS)
+					data->disconn_array[i] = 1;
+				else
+					active_chains |= (1 << i);
+			IWL_DEBUG_CALIB("i = %d  rssiDelta = %d  "
+				     "disconn_array[i] = %d\n",
+				     i, rssi_delta, data->disconn_array[i]);
+			}
+		}
+
+		/*If both chains A & B are disconnected -
+		 * connect B and leave A as is */
+		if (data->disconn_array[CHAIN_A] &&
+		    data->disconn_array[CHAIN_B]) {
+			data->disconn_array[CHAIN_B] = 0;
+			active_chains |= (1 << CHAIN_B);
+			IWL_DEBUG_CALIB("both A & B chains are disconnected! "
+				     "W/A - declare B as connected\n");
+		}
+
+		IWL_DEBUG_CALIB("active_chains (bitwise) = 0x%x\n",
+				active_chains);
+
+		/* Save for use within RXON, TX, SCAN commands, etc. */
+		priv->valid_antenna = active_chains;
+
+		/* Analyze noise for rx balance */
+		average_noise[0] = ((data->chain_noise_a)/CAL_NUM_OF_BEACONS);
+		average_noise[1] = ((data->chain_noise_b)/CAL_NUM_OF_BEACONS);
+		average_noise[2] = ((data->chain_noise_c)/CAL_NUM_OF_BEACONS);
+
+		for (i = 0; i < NUM_RX_CHAINS; i++) {
+			if (!(data->disconn_array[i]) &&
+			   (average_noise[i] <= min_average_noise)) {
+				/* This means that chain i is active and has
+				 * lower noise values so far: */
+				min_average_noise = average_noise[i];
+				min_average_noise_antenna_i = i;
+			}
+		}
+
+		data->delta_gain_code[min_average_noise_antenna_i] = 0;
+
+		IWL_DEBUG_CALIB("average_noise: a %d b %d c %d\n",
+				average_noise[0], average_noise[1],
+				average_noise[2]);
+
+		IWL_DEBUG_CALIB("min_average_noise = %d, antenna %d\n",
+				min_average_noise, min_average_noise_antenna_i);
+
+		for (i = 0; i < NUM_RX_CHAINS; i++) {
+			s32 delta_g = 0;
+
+			if (!(data->disconn_array[i]) &&
+			    (data->delta_gain_code[i] ==
+			     CHAIN_NOISE_DELTA_GAIN_INIT_VAL)) {
+				delta_g = average_noise[i] - min_average_noise;
+				data->delta_gain_code[i] = (u8)((delta_g *
+								    10) / 15);
+				if (CHAIN_NOISE_MAX_DELTA_GAIN_CODE <
+				   data->delta_gain_code[i])
+					data->delta_gain_code[i] =
+					  CHAIN_NOISE_MAX_DELTA_GAIN_CODE;
+
+				data->delta_gain_code[i] =
+					(data->delta_gain_code[i] | (1 << 2));
+			} else
+				data->delta_gain_code[i] = 0;
+		}
+		IWL_DEBUG_CALIB("delta_gain_codes: a %d b %d c %d\n",
+			     data->delta_gain_code[0],
+			     data->delta_gain_code[1],
+			     data->delta_gain_code[2]);
+
+		/* Differential gain gets sent to uCode only once */
+		if (!data->radio_write) {
+			struct iwl_calibration_cmd cmd;
+			data->radio_write = 1;
+
+			memset(&cmd, 0, sizeof(cmd));
+			cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD;
+			cmd.diff_gain_a = data->delta_gain_code[0];
+			cmd.diff_gain_b = data->delta_gain_code[1];
+			cmd.diff_gain_c = data->delta_gain_code[2];
+			rc = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD,
+					      sizeof(cmd), &cmd);
+			if (rc)
+				IWL_DEBUG_CALIB("fail sending cmd "
+					     "REPLY_PHY_CALIBRATION_CMD \n");
+
+			/* TODO we might want recalculate
+			 * rx_chain in rxon cmd */
+
+			/* Mark so we run this algo only once! */
+			data->state = IWL_CHAIN_NOISE_CALIBRATED;
+		}
+		data->chain_noise_a = 0;
+		data->chain_noise_b = 0;
+		data->chain_noise_c = 0;
+		data->chain_signal_a = 0;
+		data->chain_signal_b = 0;
+		data->chain_signal_c = 0;
+		data->beacon_count = 0;
+	}
+	return;
+}
+
+static void iwl4965_sensitivity_calibration(struct iwl_priv *priv,
+					    struct iwl_notif_statistics *resp)
+{
+	int rc = 0;
+	u32 rx_enable_time;
+	u32 fa_cck;
+	u32 fa_ofdm;
+	u32 bad_plcp_cck;
+	u32 bad_plcp_ofdm;
+	u32 norm_fa_ofdm;
+	u32 norm_fa_cck;
+	struct iwl_sensitivity_data *data = NULL;
+	struct statistics_rx_non_phy *rx_info = &(resp->rx.general);
+	struct statistics_rx *statistics = &(resp->rx);
+	unsigned long flags;
+	struct statistics_general_data statis;
+
+	data = &(priv->sensitivity_data);
+
+	if (!iwl_is_associated(priv)) {
+		IWL_DEBUG_CALIB("<< - not associated\n");
+		return;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
+		IWL_DEBUG_CALIB("<< invalid data.\n");
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return;
+	}
+
+	/* Extract Statistics: */
+	rx_enable_time = le32_to_cpu(rx_info->channel_load);
+	fa_cck = le32_to_cpu(statistics->cck.false_alarm_cnt);
+	fa_ofdm = le32_to_cpu(statistics->ofdm.false_alarm_cnt);
+	bad_plcp_cck = le32_to_cpu(statistics->cck.plcp_err);
+	bad_plcp_ofdm = le32_to_cpu(statistics->ofdm.plcp_err);
+
+	statis.beacon_silence_rssi_a =
+			le32_to_cpu(statistics->general.beacon_silence_rssi_a);
+	statis.beacon_silence_rssi_b =
+			le32_to_cpu(statistics->general.beacon_silence_rssi_b);
+	statis.beacon_silence_rssi_c =
+			le32_to_cpu(statistics->general.beacon_silence_rssi_c);
+	statis.beacon_energy_a =
+			le32_to_cpu(statistics->general.beacon_energy_a);
+	statis.beacon_energy_b =
+			le32_to_cpu(statistics->general.beacon_energy_b);
+	statis.beacon_energy_c =
+			le32_to_cpu(statistics->general.beacon_energy_c);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	IWL_DEBUG_CALIB("rx_enable_time = %u usecs\n", rx_enable_time);
+
+	if (!rx_enable_time) {
+		IWL_DEBUG_CALIB("<< RX Enable Time == 0! \n");
+		return;
+	}
+
+	/* These statistics increase monotonically, and do not reset
+	 *   at each beacon.  Calculate difference from last value, or just
+	 *   use the new statistics value if it has reset or wrapped around. */
+	if (data->last_bad_plcp_cnt_cck > bad_plcp_cck)
+		data->last_bad_plcp_cnt_cck = bad_plcp_cck;
+	else {
+		bad_plcp_cck -= data->last_bad_plcp_cnt_cck;
+		data->last_bad_plcp_cnt_cck += bad_plcp_cck;
+	}
+
+	if (data->last_bad_plcp_cnt_ofdm > bad_plcp_ofdm)
+		data->last_bad_plcp_cnt_ofdm = bad_plcp_ofdm;
+	else {
+		bad_plcp_ofdm -= data->last_bad_plcp_cnt_ofdm;
+		data->last_bad_plcp_cnt_ofdm += bad_plcp_ofdm;
+	}
+
+	if (data->last_fa_cnt_ofdm > fa_ofdm)
+		data->last_fa_cnt_ofdm = fa_ofdm;
+	else {
+		fa_ofdm -= data->last_fa_cnt_ofdm;
+		data->last_fa_cnt_ofdm += fa_ofdm;
+	}
+
+	if (data->last_fa_cnt_cck > fa_cck)
+		data->last_fa_cnt_cck = fa_cck;
+	else {
+		fa_cck -= data->last_fa_cnt_cck;
+		data->last_fa_cnt_cck += fa_cck;
+	}
+
+	/* Total aborted signal locks */
+	norm_fa_ofdm = fa_ofdm + bad_plcp_ofdm;
+	norm_fa_cck = fa_cck + bad_plcp_cck;
+
+	IWL_DEBUG_CALIB("cck: fa %u badp %u  ofdm: fa %u badp %u\n", fa_cck,
+			bad_plcp_cck, fa_ofdm, bad_plcp_ofdm);
+
+	iwl4965_sens_auto_corr_ofdm(priv, norm_fa_ofdm, rx_enable_time);
+	iwl4965_sens_energy_cck(priv, norm_fa_cck, rx_enable_time, &statis);
+	rc |= iwl4965_sensitivity_write(priv, CMD_ASYNC);
+
+	return;
+}
+
+static void iwl4965_bg_sensitivity_work(struct work_struct *work)
+{
+	struct iwl_priv *priv = container_of(work, struct iwl_priv,
+			sensitivity_work);
+
+	mutex_lock(&priv->mutex);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
+	    test_bit(STATUS_SCANNING, &priv->status)) {
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+
+	if (priv->start_calib) {
+		iwl4965_noise_calibration(priv, &priv->statistics);
+
+		if (priv->sensitivity_data.state ==
+					IWL_SENS_CALIB_NEED_REINIT) {
+			iwl4965_init_sensitivity(priv, CMD_ASYNC, 0);
+			priv->sensitivity_data.state = IWL_SENS_CALIB_ALLOWED;
+		} else
+			iwl4965_sensitivity_calibration(priv,
+					&priv->statistics);
+	}
+
+	mutex_unlock(&priv->mutex);
+	return;
+}
+#endif /*CONFIG_IWLWIFI_SENSITIVITY*/
+
+static void iwl4965_bg_txpower_work(struct work_struct *work)
+{
+	struct iwl_priv *priv = container_of(work, struct iwl_priv,
+			txpower_work);
+
+	/* If a scan happened to start before we got here
+	 * then just return; the statistics notification will
+	 * kick off another scheduled work to compensate for
+	 * any temperature delta we missed here. */
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
+	    test_bit(STATUS_SCANNING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+
+	/* Regardless of if we are assocaited, we must reconfigure the
+	 * TX power since frames can be sent on non-radar channels while
+	 * not associated */
+	iwl_hw_reg_send_txpower(priv);
+
+	/* Update last_temperature to keep is_calib_needed from running
+	 * when it isn't needed... */
+	priv->last_temperature = priv->temperature;
+
+	mutex_unlock(&priv->mutex);
+}
+
+/*
+ * Acquire priv->lock before calling this function !
+ */
+static void iwl4965_set_wr_ptrs(struct iwl_priv *priv, int txq_id, u32 index)
+{
+	iwl_write_restricted(priv, HBUS_TARG_WRPTR,
+			     (index & 0xff) | (txq_id << 8));
+	iwl_write_restricted_reg(priv, SCD_QUEUE_RDPTR(txq_id), index);
+}
+
+/*
+ * Acquire priv->lock before calling this function !
+ */
+static void iwl4965_tx_queue_set_status(struct iwl_priv *priv,
+					struct iwl_tx_queue *txq,
+					int tx_fifo_id, int scd_retry)
+{
+	int txq_id = txq->q.id;
+	int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0;
+
+	iwl_write_restricted_reg(priv, SCD_QUEUE_STATUS_BITS(txq_id),
+				 (active << SCD_QUEUE_STTS_REG_POS_ACTIVE) |
+				 (tx_fifo_id << SCD_QUEUE_STTS_REG_POS_TXF) |
+				 (scd_retry << SCD_QUEUE_STTS_REG_POS_WSL) |
+				 (scd_retry << SCD_QUEUE_STTS_REG_POS_SCD_ACK) |
+				 SCD_QUEUE_STTS_REG_MSK);
+
+	txq->sched_retry = scd_retry;
+
+	IWL_DEBUG_INFO("%s %s Queue %d on AC %d\n",
+		       active ? "Activete" : "Deactivate",
+		       scd_retry ? "BA" : "AC", txq_id, tx_fifo_id);
+}
+
+static const u16 default_queue_to_tx_fifo[] = {
+	IWL_TX_FIFO_AC3,
+	IWL_TX_FIFO_AC2,
+	IWL_TX_FIFO_AC1,
+	IWL_TX_FIFO_AC0,
+	IWL_CMD_FIFO_NUM,
+	IWL_TX_FIFO_HCCA_1,
+	IWL_TX_FIFO_HCCA_2
+};
+
+static inline void iwl4965_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
+{
+	set_bit(txq_id, &priv->txq_ctx_active_msk);
+}
+
+static inline void iwl4965_txq_ctx_deactivate(struct iwl_priv *priv, int txq_id)
+{
+	clear_bit(txq_id, &priv->txq_ctx_active_msk);
+}
+
+int iwl4965_alive_notify(struct iwl_priv *priv)
+{
+	u32 a;
+	int i = 0;
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+	memset(&(priv->sensitivity_data), 0,
+	       sizeof(struct iwl_sensitivity_data));
+	memset(&(priv->chain_noise_data), 0,
+	       sizeof(struct iwl_chain_noise_data));
+	for (i = 0; i < NUM_RX_CHAINS; i++)
+		priv->chain_noise_data.delta_gain_code[i] =
+				CHAIN_NOISE_DELTA_GAIN_INIT_VAL;
+#endif /* CONFIG_IWLWIFI_SENSITIVITY*/
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+
+	priv->scd_base_addr = iwl_read_restricted_reg(priv, SCD_SRAM_BASE_ADDR);
+	a = priv->scd_base_addr + SCD_CONTEXT_DATA_OFFSET;
+	for (; a < priv->scd_base_addr + SCD_TX_STTS_BITMAP_OFFSET; a += 4)
+		iwl_write_restricted_mem(priv, a, 0);
+	for (; a < priv->scd_base_addr + SCD_TRANSLATE_TBL_OFFSET; a += 4)
+		iwl_write_restricted_mem(priv, a, 0);
+	for (; a < sizeof(u16) * priv->hw_setting.max_txq_num; a += 4)
+		iwl_write_restricted_mem(priv, a, 0);
+
+	iwl_write_restricted_reg(priv, SCD_DRAM_BASE_ADDR,
+		(priv->hw_setting.shared_phys +
+		 offsetof(struct iwl_shared, queues_byte_cnt_tbls)) >> 10);
+	iwl_write_restricted_reg(priv, SCD_QUEUECHAIN_SEL, 0);
+
+	/* initiate the queues */
+	for (i = 0; i < priv->hw_setting.max_txq_num; i++) {
+		iwl_write_restricted_reg(priv, SCD_QUEUE_RDPTR(i), 0);
+		iwl_write_restricted(priv, HBUS_TARG_WRPTR, 0 | (i << 8));
+		iwl_write_restricted_mem(priv, priv->scd_base_addr +
+					SCD_CONTEXT_QUEUE_OFFSET(i),
+					(SCD_WIN_SIZE <<
+					SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
+					SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
+		iwl_write_restricted_mem(priv, priv->scd_base_addr +
+					SCD_CONTEXT_QUEUE_OFFSET(i) +
+					sizeof(u32),
+					(SCD_FRAME_LIMIT <<
+					SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+					SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
+
+	}
+	iwl_write_restricted_reg(priv, SCD_INTERRUPT_MASK,
+				 (1 << priv->hw_setting.max_txq_num) - 1);
+
+	iwl_write_restricted_reg(priv, SCD_TXFACT,
+				 SCD_TXFACT_REG_TXFIFO_MASK(0, 7));
+
+	iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0);
+	/* map qos queues to fifos one-to-one */
+	for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) {
+		int ac = default_queue_to_tx_fifo[i];
+		iwl4965_txq_ctx_activate(priv, i);
+		iwl4965_tx_queue_set_status(priv, &priv->txq[i], ac, 0);
+	}
+
+	iwl_release_restricted_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+int iwl_hw_set_hw_setting(struct iwl_priv *priv)
+{
+	priv->hw_setting.shared_virt =
+	    pci_alloc_consistent(priv->pci_dev,
+				 sizeof(struct iwl_shared),
+				 &priv->hw_setting.shared_phys);
+
+	if (!priv->hw_setting.shared_virt)
+		return -1;
+
+	memset(priv->hw_setting.shared_virt, 0, sizeof(struct iwl_shared));
+
+	priv->hw_setting.max_txq_num = iwl_param_queues_num;
+	priv->hw_setting.ac_queue_count = AC_NUM;
+
+	priv->hw_setting.cck_flag = RATE_MCS_CCK_MSK;
+	priv->hw_setting.tx_cmd_len = sizeof(struct iwl_tx_cmd);
+	priv->hw_setting.max_rxq_size = RX_QUEUE_SIZE;
+	priv->hw_setting.max_rxq_log = RX_QUEUE_SIZE_LOG;
+
+	priv->hw_setting.max_stations = IWL4965_STATION_COUNT;
+	priv->hw_setting.bcast_sta_id = IWL4965_BROADCAST_ID;
+	return 0;
+}
+
+/**
+ * iwl_hw_txq_ctx_free - Free TXQ Context
+ *
+ * Destroy all TX DMA queues and structures
+ */
+void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
+{
+	int txq_id;
+
+	/* Tx queues */
+	for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++)
+		iwl_tx_queue_free(priv, &priv->txq[txq_id]);
+
+	iwl4965_kw_free(priv);
+}
+
+/**
+ * iwl_hw_txq_free_tfd -  Free one TFD, those at index [txq->q.last_used]
+ *
+ * Does NOT advance any indexes
+ */
+int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+	struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0];
+	struct iwl_tfd_frame *bd = &bd_tmp[txq->q.last_used];
+	struct pci_dev *dev = priv->pci_dev;
+	int i;
+	int counter = 0;
+	int index, is_odd;
+
+	/* classify bd */
+	if (txq->q.id == IWL_CMD_QUEUE_NUM)
+		/* nothing to cleanup after for host commands */
+		return 0;
+
+	/* sanity check */
+	counter = IWL_GET_BITS(*bd, num_tbs);
+	if (counter > MAX_NUM_OF_TBS) {
+		IWL_ERROR("Too many chunks: %i\n", counter);
+		/* @todo issue fatal error, it is quite serious situation */
+		return 0;
+	}
+
+	/* unmap chunks if any */
+
+	for (i = 0; i < counter; i++) {
+		index = i / 2;
+		is_odd = i & 0x1;
+
+		if (is_odd)
+			pci_unmap_single(
+				dev,
+				IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) |
+				(IWL_GET_BITS(bd->pa[index],
+					      tb2_addr_hi20) << 16),
+				IWL_GET_BITS(bd->pa[index], tb2_len),
+				PCI_DMA_TODEVICE);
+
+		else if (i > 0)
+			pci_unmap_single(dev,
+					 le32_to_cpu(bd->pa[index].tb1_addr),
+					 IWL_GET_BITS(bd->pa[index], tb1_len),
+					 PCI_DMA_TODEVICE);
+
+		if (txq->txb[txq->q.last_used].skb[i]) {
+			struct sk_buff *skb = txq->txb[txq->q.last_used].skb[i];
+
+			dev_kfree_skb(skb);
+			txq->txb[txq->q.last_used].skb[i] = NULL;
+		}
+	}
+	return 0;
+}
+
+int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power)
+{
+	IWL_ERROR("TODO: Implement iwl_hw_reg_set_txpower!\n");
+	return -EINVAL;
+}
+
+static s32 iwl4965_math_div_round(s32 num, s32 denom, s32 *res)
+{
+	s32 sign = 1;
+
+	if (num < 0) {
+		sign = -sign;
+		num = -num;
+	}
+	if (denom < 0) {
+		sign = -sign;
+		denom = -denom;
+	}
+	*res = 1;
+	*res = ((num * 2 + denom) / (denom * 2)) * sign;
+
+	return 1;
+}
+
+static s32 iwl4965_get_voltage_compensation(s32 eeprom_voltage,
+					    s32 current_voltage)
+{
+	s32 comp = 0;
+
+	if ((TX_POWER_IWL_ILLEGAL_VOLTAGE == eeprom_voltage) ||
+	    (TX_POWER_IWL_ILLEGAL_VOLTAGE == current_voltage))
+		return 0;
+
+	iwl4965_math_div_round(current_voltage - eeprom_voltage,
+			       TX_POWER_IWL_VOLTAGE_CODES_PER_03V, &comp);
+
+	if (current_voltage > eeprom_voltage)
+		comp *= 2;
+	if ((comp < -2) || (comp > 2))
+		comp = 0;
+
+	return comp;
+}
+
+static const struct iwl_channel_info *
+iwl4965_get_channel_txpower_info(struct iwl_priv *priv, u8 phymode, u16 channel)
+{
+	const struct iwl_channel_info *ch_info;
+
+	ch_info = iwl_get_channel_info(priv, phymode, channel);
+
+	if (!is_channel_valid(ch_info))
+		return NULL;
+
+	return ch_info;
+}
+
+static s32 iwl4965_get_tx_atten_grp(u16 channel)
+{
+	if (channel >= CALIB_IWL_TX_ATTEN_GR5_FCH &&
+	    channel <= CALIB_IWL_TX_ATTEN_GR5_LCH)
+		return CALIB_CH_GROUP_5;
+
+	if (channel >= CALIB_IWL_TX_ATTEN_GR1_FCH &&
+	    channel <= CALIB_IWL_TX_ATTEN_GR1_LCH)
+		return CALIB_CH_GROUP_1;
+
+	if (channel >= CALIB_IWL_TX_ATTEN_GR2_FCH &&
+	    channel <= CALIB_IWL_TX_ATTEN_GR2_LCH)
+		return CALIB_CH_GROUP_2;
+
+	if (channel >= CALIB_IWL_TX_ATTEN_GR3_FCH &&
+	    channel <= CALIB_IWL_TX_ATTEN_GR3_LCH)
+		return CALIB_CH_GROUP_3;
+
+	if (channel >= CALIB_IWL_TX_ATTEN_GR4_FCH &&
+	    channel <= CALIB_IWL_TX_ATTEN_GR4_LCH)
+		return CALIB_CH_GROUP_4;
+
+	IWL_ERROR("Can't find txatten group for channel %d.\n", channel);
+	return -1;
+}
+
+static u32 iwl4965_get_sub_band(const struct iwl_priv *priv, u32 channel)
+{
+	s32 b = -1;
+
+	for (b = 0; b < EEPROM_TX_POWER_BANDS; b++) {
+		if (priv->eeprom.calib_info.band_info[b].ch_from == 0)
+			continue;
+
+		if ((channel >= priv->eeprom.calib_info.band_info[b].ch_from)
+		    && (channel <= priv->eeprom.calib_info.band_info[b].ch_to))
+			break;
+	}
+
+	return b;
+}
+
+static s32 iwl4965_interpolate_value(s32 x, s32 x1, s32 y1, s32 x2, s32 y2)
+{
+	s32 val;
+
+	if (x2 == x1)
+		return y1;
+	else {
+		iwl4965_math_div_round((x2 - x) * (y1 - y2), (x2 - x1), &val);
+		return val + y2;
+	}
+}
+
+static int iwl4965_interpolate_chan(struct iwl_priv *priv, u32 channel,
+				    struct iwl_eeprom_calib_ch_info *chan_info)
+{
+	s32 s = -1;
+	u32 c;
+	u32 m;
+	const struct iwl_eeprom_calib_measure *m1;
+	const struct iwl_eeprom_calib_measure *m2;
+	struct iwl_eeprom_calib_measure *omeas;
+	u32 ch_i1;
+	u32 ch_i2;
+
+	s = iwl4965_get_sub_band(priv, channel);
+	if (s >= EEPROM_TX_POWER_BANDS) {
+		IWL_ERROR("Tx Power can not find channel %d ", channel);
+		return -1;
+	}
+
+	ch_i1 = priv->eeprom.calib_info.band_info[s].ch1.ch_num;
+	ch_i2 = priv->eeprom.calib_info.band_info[s].ch2.ch_num;
+	chan_info->ch_num = (u8) channel;
+
+	IWL_DEBUG_TXPOWER("channel %d subband %d factory cal ch %d & %d\n",
+			  channel, s, ch_i1, ch_i2);
+
+	for (c = 0; c < EEPROM_TX_POWER_TX_CHAINS; c++) {
+		for (m = 0; m < EEPROM_TX_POWER_MEASUREMENTS; m++) {
+			m1 = &(priv->eeprom.calib_info.band_info[s].ch1.
+			       measurements[c][m]);
+			m2 = &(priv->eeprom.calib_info.band_info[s].ch2.
+			       measurements[c][m]);
+			omeas = &(chan_info->measurements[c][m]);
+
+			omeas->actual_pow =
+			    (u8) iwl4965_interpolate_value(channel, ch_i1,
+							   m1->actual_pow,
+							   ch_i2,
+							   m2->actual_pow);
+			omeas->gain_idx =
+			    (u8) iwl4965_interpolate_value(channel, ch_i1,
+							   m1->gain_idx, ch_i2,
+							   m2->gain_idx);
+			omeas->temperature =
+			    (u8) iwl4965_interpolate_value(channel, ch_i1,
+							   m1->temperature,
+							   ch_i2,
+							   m2->temperature);
+			omeas->pa_det =
+			    (s8) iwl4965_interpolate_value(channel, ch_i1,
+							   m1->pa_det, ch_i2,
+							   m2->pa_det);
+
+			IWL_DEBUG_TXPOWER
+			    ("chain %d meas %d AP1=%d AP2=%d AP=%d\n", c, m,
+			     m1->actual_pow, m2->actual_pow, omeas->actual_pow);
+			IWL_DEBUG_TXPOWER
+			    ("chain %d meas %d NI1=%d NI2=%d NI=%d\n", c, m,
+			     m1->gain_idx, m2->gain_idx, omeas->gain_idx);
+			IWL_DEBUG_TXPOWER
+			    ("chain %d meas %d PA1=%d PA2=%d PA=%d\n", c, m,
+			     m1->pa_det, m2->pa_det, omeas->pa_det);
+			IWL_DEBUG_TXPOWER
+			    ("chain %d meas %d  T1=%d  T2=%d  T=%d\n", c, m,
+			     m1->temperature, m2->temperature,
+			     omeas->temperature);
+		}
+	}
+
+	return 0;
+}
+
+/* bit-rate-dependent table to prevent Tx distortion, in half-dB units,
+ * for OFDM 6, 12, 18, 24, 36, 48, 54, 60 MBit, and CCK all rates. */
+static s32 back_off_table[] = {
+	10, 10, 10, 10, 10, 15, 17, 20,	/* OFDM SISO 20 MHz */
+	10, 10, 10, 10, 10, 15, 17, 20,	/* OFDM MIMO 20 MHz */
+	10, 10, 10, 10, 10, 15, 17, 20,	/* OFDM SISO 40 MHz */
+	10, 10, 10, 10, 10, 15, 17, 20,	/* OFDM MIMO 40 MHz */
+	10			/* CCK */
+};
+
+/* Thermal compensation values for txpower for various frequency ranges ...
+ *   ratios from 3:1 to 4.5:1 of degrees (Celsius) per half-dB gain adjust */
+static struct iwl_txpower_comp_entry {
+	s32 degrees_per_05db_a;
+	s32 degrees_per_05db_a_denom;
+} tx_power_cmp_tble[CALIB_CH_GROUP_MAX] = {
+	{9, 2},			/* group 0 5.2, ch  34-43 */
+	{4, 1},			/* group 1 5.2, ch  44-70 */
+	{4, 1},			/* group 2 5.2, ch  71-124 */
+	{4, 1},			/* group 3 5.2, ch 125-200 */
+	{3, 1}			/* group 4 2.4, ch   all */
+};
+
+static s32 get_min_power_index(s32 rate_power_index, u32 band)
+{
+	if (!band) {
+		if ((rate_power_index & 7) <= 4)
+			return MIN_TX_GAIN_INDEX_52GHZ_EXT;
+	}
+	return MIN_TX_GAIN_INDEX;
+}
+
+struct gain_entry {
+	u8 dsp;
+	u8 radio;
+};
+
+static const struct gain_entry gain_table[2][108] = {
+	/* 5.2GHz power gain index table */
+	{
+	 {123, 0x3F},		/* highest txpower */
+	 {117, 0x3F},
+	 {110, 0x3F},
+	 {104, 0x3F},
+	 {98, 0x3F},
+	 {110, 0x3E},
+	 {104, 0x3E},
+	 {98, 0x3E},
+	 {110, 0x3D},
+	 {104, 0x3D},
+	 {98, 0x3D},
+	 {110, 0x3C},
+	 {104, 0x3C},
+	 {98, 0x3C},
+	 {110, 0x3B},
+	 {104, 0x3B},
+	 {98, 0x3B},
+	 {110, 0x3A},
+	 {104, 0x3A},
+	 {98, 0x3A},
+	 {110, 0x39},
+	 {104, 0x39},
+	 {98, 0x39},
+	 {110, 0x38},
+	 {104, 0x38},
+	 {98, 0x38},
+	 {110, 0x37},
+	 {104, 0x37},
+	 {98, 0x37},
+	 {110, 0x36},
+	 {104, 0x36},
+	 {98, 0x36},
+	 {110, 0x35},
+	 {104, 0x35},
+	 {98, 0x35},
+	 {110, 0x34},
+	 {104, 0x34},
+	 {98, 0x34},
+	 {110, 0x33},
+	 {104, 0x33},
+	 {98, 0x33},
+	 {110, 0x32},
+	 {104, 0x32},
+	 {98, 0x32},
+	 {110, 0x31},
+	 {104, 0x31},
+	 {98, 0x31},
+	 {110, 0x30},
+	 {104, 0x30},
+	 {98, 0x30},
+	 {110, 0x25},
+	 {104, 0x25},
+	 {98, 0x25},
+	 {110, 0x24},
+	 {104, 0x24},
+	 {98, 0x24},
+	 {110, 0x23},
+	 {104, 0x23},
+	 {98, 0x23},
+	 {110, 0x22},
+	 {104, 0x18},
+	 {98, 0x18},
+	 {110, 0x17},
+	 {104, 0x17},
+	 {98, 0x17},
+	 {110, 0x16},
+	 {104, 0x16},
+	 {98, 0x16},
+	 {110, 0x15},
+	 {104, 0x15},
+	 {98, 0x15},
+	 {110, 0x14},
+	 {104, 0x14},
+	 {98, 0x14},
+	 {110, 0x13},
+	 {104, 0x13},
+	 {98, 0x13},
+	 {110, 0x12},
+	 {104, 0x08},
+	 {98, 0x08},
+	 {110, 0x07},
+	 {104, 0x07},
+	 {98, 0x07},
+	 {110, 0x06},
+	 {104, 0x06},
+	 {98, 0x06},
+	 {110, 0x05},
+	 {104, 0x05},
+	 {98, 0x05},
+	 {110, 0x04},
+	 {104, 0x04},
+	 {98, 0x04},
+	 {110, 0x03},
+	 {104, 0x03},
+	 {98, 0x03},
+	 {110, 0x02},
+	 {104, 0x02},
+	 {98, 0x02},
+	 {110, 0x01},
+	 {104, 0x01},
+	 {98, 0x01},
+	 {110, 0x00},
+	 {104, 0x00},
+	 {98, 0x00},
+	 {93, 0x00},
+	 {88, 0x00},
+	 {83, 0x00},
+	 {78, 0x00},
+	 },
+	/* 2.4GHz power gain index table */
+	{
+	 {110, 0x3f},		/* highest txpower */
+	 {104, 0x3f},
+	 {98, 0x3f},
+	 {110, 0x3e},
+	 {104, 0x3e},
+	 {98, 0x3e},
+	 {110, 0x3d},
+	 {104, 0x3d},
+	 {98, 0x3d},
+	 {110, 0x3c},
+	 {104, 0x3c},
+	 {98, 0x3c},
+	 {110, 0x3b},
+	 {104, 0x3b},
+	 {98, 0x3b},
+	 {110, 0x3a},
+	 {104, 0x3a},
+	 {98, 0x3a},
+	 {110, 0x39},
+	 {104, 0x39},
+	 {98, 0x39},
+	 {110, 0x38},
+	 {104, 0x38},
+	 {98, 0x38},
+	 {110, 0x37},
+	 {104, 0x37},
+	 {98, 0x37},
+	 {110, 0x36},
+	 {104, 0x36},
+	 {98, 0x36},
+	 {110, 0x35},
+	 {104, 0x35},
+	 {98, 0x35},
+	 {110, 0x34},
+	 {104, 0x34},
+	 {98, 0x34},
+	 {110, 0x33},
+	 {104, 0x33},
+	 {98, 0x33},
+	 {110, 0x32},
+	 {104, 0x32},
+	 {98, 0x32},
+	 {110, 0x31},
+	 {104, 0x31},
+	 {98, 0x31},
+	 {110, 0x30},
+	 {104, 0x30},
+	 {98, 0x30},
+	 {110, 0x6},
+	 {104, 0x6},
+	 {98, 0x6},
+	 {110, 0x5},
+	 {104, 0x5},
+	 {98, 0x5},
+	 {110, 0x4},
+	 {104, 0x4},
+	 {98, 0x4},
+	 {110, 0x3},
+	 {104, 0x3},
+	 {98, 0x3},
+	 {110, 0x2},
+	 {104, 0x2},
+	 {98, 0x2},
+	 {110, 0x1},
+	 {104, 0x1},
+	 {98, 0x1},
+	 {110, 0x0},
+	 {104, 0x0},
+	 {98, 0x0},
+	 {97, 0},
+	 {96, 0},
+	 {95, 0},
+	 {94, 0},
+	 {93, 0},
+	 {92, 0},
+	 {91, 0},
+	 {90, 0},
+	 {89, 0},
+	 {88, 0},
+	 {87, 0},
+	 {86, 0},
+	 {85, 0},
+	 {84, 0},
+	 {83, 0},
+	 {82, 0},
+	 {81, 0},
+	 {80, 0},
+	 {79, 0},
+	 {78, 0},
+	 {77, 0},
+	 {76, 0},
+	 {75, 0},
+	 {74, 0},
+	 {73, 0},
+	 {72, 0},
+	 {71, 0},
+	 {70, 0},
+	 {69, 0},
+	 {68, 0},
+	 {67, 0},
+	 {66, 0},
+	 {65, 0},
+	 {64, 0},
+	 {63, 0},
+	 {62, 0},
+	 {61, 0},
+	 {60, 0},
+	 {59, 0},
+	 }
+};
+
+static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
+				    u8 is_fat, u8 ctrl_chan_high,
+				    struct iwl_tx_power_db *tx_power_tbl)
+{
+	u8 saturation_power;
+	s32 target_power;
+	s32 user_target_power;
+	s32 power_limit;
+	s32 current_temp;
+	s32 reg_limit;
+	s32 current_regulatory;
+	s32 txatten_grp = CALIB_CH_GROUP_MAX;
+	int i;
+	int c;
+	const struct iwl_channel_info *ch_info = NULL;
+	struct iwl_eeprom_calib_ch_info ch_eeprom_info;
+	const struct iwl_eeprom_calib_measure *measurement;
+	s16 voltage;
+	s32 init_voltage;
+	s32 voltage_compensation;
+	s32 degrees_per_05db_num;
+	s32 degrees_per_05db_denom;
+	s32 factory_temp;
+	s32 temperature_comp[2];
+	s32 factory_gain_index[2];
+	s32 factory_actual_pwr[2];
+	s32 power_index;
+
+	/* Sanity check requested level (dBm) */
+	if (priv->user_txpower_limit < IWL_TX_POWER_TARGET_POWER_MIN) {
+		IWL_WARNING("Requested user TXPOWER %d below limit.\n",
+			    priv->user_txpower_limit);
+		return -EINVAL;
+	}
+	if (priv->user_txpower_limit > IWL_TX_POWER_TARGET_POWER_MAX) {
+		IWL_WARNING("Requested user TXPOWER %d above limit.\n",
+			    priv->user_txpower_limit);
+		return -EINVAL;
+	}
+
+	/* user_txpower_limit is in dBm, convert to half-dBm (half-dB units
+	 *   are used for indexing into txpower table) */
+	user_target_power = 2 * priv->user_txpower_limit;
+
+	/* Get current (RXON) channel, band, width */
+	ch_info =
+		iwl4965_get_channel_txpower_info(priv, priv->phymode, channel);
+
+	IWL_DEBUG_TXPOWER("chan %d band %d is_fat %d\n", channel, band,
+			  is_fat);
+
+	if (!ch_info)
+		return -EINVAL;
+
+	/* get txatten group, used to select 1) thermal txpower adjustment
+	 *   and 2) mimo txpower balance between Tx chains. */
+	txatten_grp = iwl4965_get_tx_atten_grp(channel);
+	if (txatten_grp < 0)
+		return -EINVAL;
+
+	IWL_DEBUG_TXPOWER("channel %d belongs to txatten group %d\n",
+			  channel, txatten_grp);
+
+	if (is_fat) {
+		if (ctrl_chan_high)
+			channel -= 2;
+		else
+			channel += 2;
+	}
+
+	/* hardware txpower limits ...
+	 * saturation (clipping distortion) txpowers are in half-dBm */
+	if (band)
+		saturation_power = priv->eeprom.calib_info.saturation_power24;
+	else
+		saturation_power = priv->eeprom.calib_info.saturation_power52;
+
+	if (saturation_power < IWL_TX_POWER_SATURATION_MIN ||
+	    saturation_power > IWL_TX_POWER_SATURATION_MAX) {
+		if (band)
+			saturation_power = IWL_TX_POWER_DEFAULT_SATURATION_24;
+		else
+			saturation_power = IWL_TX_POWER_DEFAULT_SATURATION_52;
+	}
+
+	/* regulatory txpower limits ... reg_limit values are in half-dBm,
+	 *   max_power_avg values are in dBm, convert * 2 */
+	if (is_fat)
+		reg_limit = ch_info->fat_max_power_avg * 2;
+	else
+		reg_limit = ch_info->max_power_avg * 2;
+
+	if ((reg_limit < IWL_TX_POWER_REGULATORY_MIN) ||
+	    (reg_limit > IWL_TX_POWER_REGULATORY_MAX)) {
+		if (band)
+			reg_limit = IWL_TX_POWER_DEFAULT_REGULATORY_24;
+		else
+			reg_limit = IWL_TX_POWER_DEFAULT_REGULATORY_52;
+	}
+
+	/* Interpolate txpower calibration values for this channel,
+	 *   based on factory calibration tests on spaced channels. */
+	iwl4965_interpolate_chan(priv, channel, &ch_eeprom_info);
+
+	/* calculate tx gain adjustment based on power supply voltage */
+	voltage = priv->eeprom.calib_info.voltage;
+	init_voltage = (s32)le32_to_cpu(priv->card_alive_init.voltage);
+	voltage_compensation =
+	    iwl4965_get_voltage_compensation(voltage, init_voltage);
+
+	IWL_DEBUG_TXPOWER("curr volt %d eeprom volt %d volt comp %d\n",
+			  init_voltage,
+			  voltage, voltage_compensation);
+
+	/* get current temperature (Celsius) */
+	current_temp = max(priv->temperature, IWL_TX_POWER_TEMPERATURE_MIN);
+	current_temp = min(priv->temperature, IWL_TX_POWER_TEMPERATURE_MAX);
+	current_temp = KELVIN_TO_CELSIUS(current_temp);
+
+	/* select thermal txpower adjustment params, based on channel group
+	 *   (same frequency group used for mimo txatten adjustment) */
+	degrees_per_05db_num =
+	    tx_power_cmp_tble[txatten_grp].degrees_per_05db_a;
+	degrees_per_05db_denom =
+	    tx_power_cmp_tble[txatten_grp].degrees_per_05db_a_denom;
+
+	/* get per-chain txpower values from factory measurements */
+	for (c = 0; c < 2; c++) {
+		measurement = &ch_eeprom_info.measurements[c][1];
+
+		/* txgain adjustment (in half-dB steps) based on difference
+		 *   between factory and current temperature */
+		factory_temp = measurement->temperature;
+		iwl4965_math_div_round((current_temp - factory_temp) *
+				       degrees_per_05db_denom,
+				       degrees_per_05db_num,
+				       &temperature_comp[c]);
+
+		factory_gain_index[c] = measurement->gain_idx;
+		factory_actual_pwr[c] = measurement->actual_pow;
+
+		IWL_DEBUG_TXPOWER("chain = %d\n", c);
+		IWL_DEBUG_TXPOWER("fctry tmp %d, "
+				  "curr tmp %d, comp %d steps\n",
+				  factory_temp, current_temp,
+				  temperature_comp[c]);
+
+		IWL_DEBUG_TXPOWER("fctry idx %d, fctry pwr %d\n",
+				  factory_gain_index[c],
+				  factory_actual_pwr[c]);
+	}
+
+	/* for each of 33 bit-rates (including 1 for CCK) */
+	for (i = 0; i < POWER_TABLE_NUM_ENTRIES; i++) {
+		u8 is_mimo_rate;
+		union iwl_tx_power_dual_stream tx_power;
+
+		/* for mimo, reduce each chain's txpower by half
+		 * (3dB, 6 steps), so total output power is regulatory
+		 * compliant. */
+		if (i & 0x8) {
+			current_regulatory = reg_limit -
+			    IWL_TX_POWER_MIMO_REGULATORY_COMPENSATION;
+			is_mimo_rate = 1;
+		} else {
+			current_regulatory = reg_limit;
+			is_mimo_rate = 0;
+		}
+
+		/* find txpower limit, either hardware or regulatory */
+		power_limit = saturation_power - back_off_table[i];
+		if (power_limit > current_regulatory)
+			power_limit = current_regulatory;
+
+		/* reduce user's txpower request if necessary
+		 * for this rate on this channel */
+		target_power = user_target_power;
+		if (target_power > power_limit)
+			target_power = power_limit;
+
+		IWL_DEBUG_TXPOWER("rate %d sat %d reg %d usr %d tgt %d\n",
+				  i, saturation_power - back_off_table[i],
+				  current_regulatory, user_target_power,
+				  target_power);
+
+		/* for each of 2 Tx chains (radio transmitters) */
+		for (c = 0; c < 2; c++) {
+			s32 atten_value;
+
+			if (is_mimo_rate)
+				atten_value =
+				    (s32)le32_to_cpu(priv->card_alive_init.
+				    tx_atten[txatten_grp][c]);
+			else
+				atten_value = 0;
+
+			/* calculate index; higher index means lower txpower */
+			power_index = (u8) (factory_gain_index[c] -
+					    (target_power -
+					     factory_actual_pwr[c]) -
+					    temperature_comp[c] -
+					    voltage_compensation +
+					    atten_value);
+
+/*			IWL_DEBUG_TXPOWER("calculated txpower index %d\n",
+						power_index); */
+
+			if (power_index < get_min_power_index(i, band))
+				power_index = get_min_power_index(i, band);
+
+			/* adjust 5 GHz index to support negative indexes */
+			if (!band)
+				power_index += 9;
+
+			/* CCK, rate 32, reduce txpower for CCK */
+			if (i == POWER_TABLE_CCK_ENTRY)
+				power_index +=
+				    IWL_TX_POWER_CCK_COMPENSATION_C_STEP;
+
+			/* stay within the table! */
+			if (power_index > 107) {
+				IWL_WARNING("txpower index %d > 107\n",
+					    power_index);
+				power_index = 107;
+			}
+			if (power_index < 0) {
+				IWL_WARNING("txpower index %d < 0\n",
+					    power_index);
+				power_index = 0;
+			}
+
+			/* fill txpower command for this rate/chain */
+			tx_power.s.radio_tx_gain[c] =
+				gain_table[band][power_index].radio;
+			tx_power.s.dsp_predis_atten[c] =
+				gain_table[band][power_index].dsp;
+
+			IWL_DEBUG_TXPOWER("chain %d mimo %d index %d "
+					  "gain 0x%02x dsp %d\n",
+					  c, atten_value, power_index,
+					tx_power.s.radio_tx_gain[c],
+					tx_power.s.dsp_predis_atten[c]);
+		}/* for each chain */
+
+		tx_power_tbl->power_tbl[i].dw = cpu_to_le32(tx_power.dw);
+
+	}/* for each rate */
+
+	return 0;
+}
+
+/**
+ * iwl_hw_reg_send_txpower - Configure the TXPOWER level user limit
+ *
+ * Uses the active RXON for channel, band, and characteristics (fat, high)
+ * The power limit is taken from priv->user_txpower_limit.
+ */
+int iwl_hw_reg_send_txpower(struct iwl_priv *priv)
+{
+	struct iwl_txpowertable_cmd cmd = { 0 };
+	int rc = 0;
+	u8 band = 0;
+	u8 is_fat = 0;
+	u8 ctrl_chan_high = 0;
+
+	if (test_bit(STATUS_SCANNING, &priv->status)) {
+		/* If this gets hit a lot, switch it to a BUG() and catch
+		 * the stack trace to find out who is calling this during
+		 * a scan. */
+		IWL_WARNING("TX Power requested while scanning!\n");
+		return -EAGAIN;
+	}
+
+	band = ((priv->phymode == MODE_IEEE80211B) ||
+		(priv->phymode == MODE_IEEE80211G));
+
+	is_fat =  is_fat_channel(priv->active_rxon.flags);
+
+	if (is_fat &&
+	    (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
+		ctrl_chan_high = 1;
+
+	cmd.band = band;
+	cmd.channel = priv->active_rxon.channel;
+
+	rc = iwl4965_fill_txpower_tbl(priv, band,
+				le16_to_cpu(priv->active_rxon.channel),
+				is_fat, ctrl_chan_high, &cmd.tx_power);
+	if (rc)
+		return rc;
+
+	rc = iwl_send_cmd_pdu(priv, REPLY_TX_PWR_TABLE_CMD, sizeof(cmd), &cmd);
+	return rc;
+}
+
+int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+{
+	int rc;
+	u8 band = 0;
+	u8 is_fat = 0;
+	u8 ctrl_chan_high = 0;
+	struct iwl_channel_switch_cmd cmd = { 0 };
+	const struct iwl_channel_info *ch_info;
+
+	band = ((priv->phymode == MODE_IEEE80211B) ||
+		(priv->phymode == MODE_IEEE80211G));
+
+	ch_info = iwl_get_channel_info(priv, priv->phymode, channel);
+
+	is_fat = is_fat_channel(priv->staging_rxon.flags);
+
+	if (is_fat &&
+	    (priv->active_rxon.flags & RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK))
+		ctrl_chan_high = 1;
+
+	cmd.band = band;
+	cmd.expect_beacon = 0;
+	cmd.channel = cpu_to_le16(channel);
+	cmd.rxon_flags = priv->active_rxon.flags;
+	cmd.rxon_filter_flags = priv->active_rxon.filter_flags;
+	cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+	if (ch_info)
+		cmd.expect_beacon = is_channel_radar(ch_info);
+	else
+		cmd.expect_beacon = 1;
+
+	rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_fat,
+				      ctrl_chan_high, &cmd.tx_power);
+	if (rc) {
+		IWL_DEBUG_11H("error:%d  fill txpower_tbl\n", rc);
+		return rc;
+	}
+
+	rc = iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
+	return rc;
+}
+
+#define RTS_HCCA_RETRY_LIMIT		3
+#define RTS_DFAULT_RETRY_LIMIT		60
+
+void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
+			      struct iwl_cmd *cmd,
+			      struct ieee80211_tx_control *ctrl,
+			      struct ieee80211_hdr *hdr, int sta_id,
+			      int is_hcca)
+{
+	u8 rate;
+	u8 rts_retry_limit = 0;
+	u8 data_retry_limit = 0;
+	__le32 tx_flags;
+	u16 fc = le16_to_cpu(hdr->frame_control);
+
+	tx_flags = cmd->cmd.tx.tx_flags;
+
+	rate = iwl_rates[ctrl->tx_rate].plcp;
+
+	rts_retry_limit = (is_hcca) ?
+	    RTS_HCCA_RETRY_LIMIT : RTS_DFAULT_RETRY_LIMIT;
+
+	if (ieee80211_is_probe_response(fc)) {
+		data_retry_limit = 3;
+		if (data_retry_limit < rts_retry_limit)
+			rts_retry_limit = data_retry_limit;
+	} else
+		data_retry_limit = IWL_DEFAULT_TX_RETRY;
+
+	if (priv->data_retry_limit != -1)
+		data_retry_limit = priv->data_retry_limit;
+
+	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+		switch (fc & IEEE80211_FCTL_STYPE) {
+		case IEEE80211_STYPE_AUTH:
+		case IEEE80211_STYPE_DEAUTH:
+		case IEEE80211_STYPE_ASSOC_REQ:
+		case IEEE80211_STYPE_REASSOC_REQ:
+			if (tx_flags & TX_CMD_FLG_RTS_MSK) {
+				tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+				tx_flags |= TX_CMD_FLG_CTS_MSK;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	cmd->cmd.tx.rts_retry_limit = rts_retry_limit;
+	cmd->cmd.tx.data_retry_limit = data_retry_limit;
+	cmd->cmd.tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate, 0);
+	cmd->cmd.tx.tx_flags = tx_flags;
+}
+
+int iwl_hw_get_rx_read(struct iwl_priv *priv)
+{
+	struct iwl_shared *shared_data = priv->hw_setting.shared_virt;
+
+	return IWL_GET_BITS(*shared_data, rb_closed_stts_rb_num);
+}
+
+int iwl_hw_get_temperature(struct iwl_priv *priv)
+{
+	return priv->temperature;
+}
+
+unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
+			  struct iwl_frame *frame, u8 rate)
+{
+	struct iwl_tx_beacon_cmd *tx_beacon_cmd;
+	unsigned int frame_size;
+
+	tx_beacon_cmd = &frame->u.beacon;
+	memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
+
+	tx_beacon_cmd->tx.sta_id = IWL4965_BROADCAST_ID;
+	tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+	frame_size = iwl_fill_beacon_frame(priv,
+				tx_beacon_cmd->frame,
+				BROADCAST_ADDR,
+				sizeof(frame->u) - sizeof(*tx_beacon_cmd));
+
+	BUG_ON(frame_size > MAX_MPDU_SIZE);
+	tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
+
+	if ((rate == IWL_RATE_1M_PLCP) || (rate >= IWL_RATE_2M_PLCP))
+		tx_beacon_cmd->tx.rate_n_flags =
+			iwl_hw_set_rate_n_flags(rate, RATE_MCS_CCK_MSK);
+	else
+		tx_beacon_cmd->tx.rate_n_flags =
+			iwl_hw_set_rate_n_flags(rate, 0);
+
+	tx_beacon_cmd->tx.tx_flags = (TX_CMD_FLG_SEQ_CTL_MSK |
+				TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK);
+	return (sizeof(*tx_beacon_cmd) + frame_size);
+}
+
+int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+	int rc;
+	unsigned long flags;
+	int txq_id = txq->q.id;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+
+	iwl_write_restricted(priv, FH_MEM_CBBC_QUEUE(txq_id),
+			     txq->q.dma_addr >> 8);
+	iwl_write_restricted(
+		priv, IWL_FH_TCSR_CHNL_TX_CONFIG_REG(txq_id),
+		IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+		IWL_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL);
+	iwl_release_restricted_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+static inline u8 iwl4965_get_dma_hi_address(dma_addr_t addr)
+{
+	return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0;
+}
+
+int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr,
+				 dma_addr_t addr, u16 len)
+{
+	int index, is_odd;
+	struct iwl_tfd_frame *tfd = ptr;
+	u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs);
+
+	if ((num_tbs >= MAX_NUM_OF_TBS) || (num_tbs < 0)) {
+		IWL_ERROR("Error can not send more than %d chunks\n",
+			  MAX_NUM_OF_TBS);
+		return -EINVAL;
+	}
+
+	index = num_tbs / 2;
+	is_odd = num_tbs & 0x1;
+
+	if (!is_odd) {
+		tfd->pa[index].tb1_addr = cpu_to_le32(addr);
+		IWL_SET_BITS(tfd->pa[index], tb1_addr_hi,
+			     iwl4965_get_dma_hi_address(addr));
+		IWL_SET_BITS(tfd->pa[index], tb1_len, len);
+	} else {
+		IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16,
+			     (u32) (addr & 0xffff));
+		IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16);
+		IWL_SET_BITS(tfd->pa[index], tb2_len, len);
+	}
+
+	IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1);
+
+	return 0;
+}
+
+void iwl_hw_card_show_info(struct iwl_priv *priv)
+{
+	u16 hw_version = priv->eeprom.board_revision_4965;
+
+	IWL_DEBUG_INFO("4965ABGN HW Version %u.%u.%u\n",
+		       ((hw_version >> 8) & 0x0F),
+		       ((hw_version >> 8) >> 4), (hw_version & 0x00FF));
+
+	IWL_DEBUG_INFO("4965ABGN PBA Number %.16s\n",
+		       priv->eeprom.board_pba_number_4965);
+}
+
+#define IWL_TX_CRC_SIZE		4
+#define IWL_TX_DELIMITER_SIZE	4
+
+int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
+				   struct iwl_tx_queue *txq, u16 byte_cnt)
+{
+	int len;
+	int txq_id = txq->q.id;
+	struct iwl_shared *shared_data = priv->hw_setting.shared_virt;
+
+	if (txq->need_update == 0)
+		return 0;
+
+	len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
+
+	IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
+		       tfd_offset[txq->q.first_empty], byte_cnt, len);
+
+	if (txq->q.first_empty < IWL4965_MAX_WIN_SIZE)
+		IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id].
+			tfd_offset[IWL4965_QUEUE_SIZE + txq->q.first_empty],
+			byte_cnt, len);
+
+	return 0;
+}
+
+/* Set up Rx receiver/antenna/chain usage in "staging" RXON image.
+ * This should not be used for scan command ... it puts data in wrong place.  */
+void iwl4965_set_rxon_chain(struct iwl_priv *priv)
+{
+	u8 is_single = is_single_stream(priv);
+	u8 idle_state, rx_state;
+
+	priv->staging_rxon.rx_chain = 0;
+	rx_state = idle_state = 3;
+
+	/* Tell uCode which antennas are actually connected.
+	 * Before first association, we assume all antennas are connected.
+	 * Just after first association, iwl4965_noise_calibration()
+	 *    checks which antennas actually *are* connected. */
+	priv->staging_rxon.rx_chain |=
+	    cpu_to_le16(priv->valid_antenna << RXON_RX_CHAIN_VALID_POS);
+
+	/* How many receivers should we use? */
+	iwl4965_get_rx_chain_counter(priv, &idle_state, &rx_state);
+	priv->staging_rxon.rx_chain |=
+		cpu_to_le16(rx_state << RXON_RX_CHAIN_MIMO_CNT_POS);
+	priv->staging_rxon.rx_chain |=
+		cpu_to_le16(idle_state << RXON_RX_CHAIN_CNT_POS);
+
+	if (!is_single && (rx_state >= 2) &&
+	    !test_bit(STATUS_POWER_PMI, &priv->status))
+		priv->staging_rxon.rx_chain |= RXON_RX_CHAIN_MIMO_FORCE_MSK;
+	else
+		priv->staging_rxon.rx_chain &= ~RXON_RX_CHAIN_MIMO_FORCE_MSK;
+
+	IWL_DEBUG_ASSOC("rx chain %X\n", priv->staging_rxon.rx_chain);
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+/*
+	get the traffic load value for tid
+*/
+static u32 iwl4965_tl_get_load(struct iwl_priv *priv, u8 tid)
+{
+	u32 load = 0;
+	u32 current_time = jiffies_to_msecs(jiffies);
+	u32 time_diff;
+	s32 index;
+	unsigned long flags;
+	struct iwl_traffic_load *tid_ptr = NULL;
+
+	if (tid >= TID_MAX_LOAD_COUNT)
+		return 0;
+
+	tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]);
+
+	current_time -= current_time % TID_ROUND_VALUE;
+
+	spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+	if (!(tid_ptr->queue_count))
+		goto out;
+
+	time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time);
+	index = time_diff / TID_QUEUE_CELL_SPACING;
+
+	if (index >= TID_QUEUE_MAX_SIZE) {
+		u32 oldest_time = current_time - TID_MAX_TIME_DIFF;
+
+		while (tid_ptr->queue_count &&
+		       (tid_ptr->time_stamp < oldest_time)) {
+			tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head];
+			tid_ptr->packet_count[tid_ptr->head] = 0;
+			tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING;
+			tid_ptr->queue_count--;
+			tid_ptr->head++;
+			if (tid_ptr->head >= TID_QUEUE_MAX_SIZE)
+				tid_ptr->head = 0;
+		}
+	}
+	load = tid_ptr->total;
+
+ out:
+	spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+	return load;
+}
+
+/*
+	increment traffic load value for tid and also remove
+	any old values if passed the certian time period
+*/
+static void iwl4965_tl_add_packet(struct iwl_priv *priv, u8 tid)
+{
+	u32 current_time = jiffies_to_msecs(jiffies);
+	u32 time_diff;
+	s32 index;
+	unsigned long flags;
+	struct iwl_traffic_load *tid_ptr = NULL;
+
+	if (tid >= TID_MAX_LOAD_COUNT)
+		return;
+
+	tid_ptr = &(priv->lq_mngr.agg_ctrl.traffic_load[tid]);
+
+	current_time -= current_time % TID_ROUND_VALUE;
+
+	spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+	if (!(tid_ptr->queue_count)) {
+		tid_ptr->total = 1;
+		tid_ptr->time_stamp = current_time;
+		tid_ptr->queue_count = 1;
+		tid_ptr->head = 0;
+		tid_ptr->packet_count[0] = 1;
+		goto out;
+	}
+
+	time_diff = TIME_WRAP_AROUND(tid_ptr->time_stamp, current_time);
+	index = time_diff / TID_QUEUE_CELL_SPACING;
+
+	if (index >= TID_QUEUE_MAX_SIZE) {
+		u32 oldest_time = current_time - TID_MAX_TIME_DIFF;
+
+		while (tid_ptr->queue_count &&
+		       (tid_ptr->time_stamp < oldest_time)) {
+			tid_ptr->total -= tid_ptr->packet_count[tid_ptr->head];
+			tid_ptr->packet_count[tid_ptr->head] = 0;
+			tid_ptr->time_stamp += TID_QUEUE_CELL_SPACING;
+			tid_ptr->queue_count--;
+			tid_ptr->head++;
+			if (tid_ptr->head >= TID_QUEUE_MAX_SIZE)
+				tid_ptr->head = 0;
+		}
+	}
+
+	index = (tid_ptr->head + index) % TID_QUEUE_MAX_SIZE;
+	tid_ptr->packet_count[index] = tid_ptr->packet_count[index] + 1;
+	tid_ptr->total = tid_ptr->total + 1;
+
+	if ((index + 1) > tid_ptr->queue_count)
+		tid_ptr->queue_count = index + 1;
+ out:
+	spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+
+}
+
+#define MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS   7
+enum HT_STATUS {
+	BA_STATUS_FAILURE = 0,
+	BA_STATUS_INITIATOR_DELBA,
+	BA_STATUS_RECIPIENT_DELBA,
+	BA_STATUS_RENEW_ADDBA_REQUEST,
+	BA_STATUS_ACTIVE,
+};
+
+static u8 iwl4964_tl_ba_avail(struct iwl_priv *priv)
+{
+	int i;
+	struct iwl_lq_mngr *lq;
+	u8 count = 0;
+	u16 msk;
+
+	lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+	for (i = 0; i < TID_MAX_LOAD_COUNT ; i++) {
+		msk = 1 << i;
+		if ((lq->agg_ctrl.granted_ba & msk) ||
+		    (lq->agg_ctrl.wait_for_agg_status & msk))
+			count++;
+	}
+
+	if (count < MMAC_SCHED_MAX_NUMBER_OF_HT_BACK_FLOWS)
+		return 1;
+
+	return 0;
+}
+
+static void iwl4965_ba_status(struct iwl_priv *priv,
+			      u8 tid, enum HT_STATUS status);
+
+static int iwl4965_perform_addba(struct iwl_priv *priv, u8 tid, u32 length,
+				 u32 ba_timeout)
+{
+	int rc;
+
+	rc = ieee80211_start_BA_session(priv->hw, priv->bssid, tid);
+	if (rc)
+		iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE);
+
+	return rc;
+}
+
+static int iwl4965_perform_delba(struct iwl_priv *priv, u8 tid)
+{
+	int rc;
+
+	rc = ieee80211_stop_BA_session(priv->hw, priv->bssid, tid);
+	if (rc)
+		iwl4965_ba_status(priv, tid, BA_STATUS_FAILURE);
+
+	return rc;
+}
+
+static void iwl4965_turn_on_agg_for_tid(struct iwl_priv *priv,
+					struct iwl_lq_mngr *lq,
+					u8 auto_agg, u8 tid)
+{
+	u32 tid_msk = (1 << tid);
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+/*
+	if ((auto_agg) && (!lq->enable_counter)){
+		lq->agg_ctrl.next_retry = 0;
+		lq->agg_ctrl.tid_retry = 0;
+		spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+		return;
+	}
+*/
+	if (!(lq->agg_ctrl.granted_ba & tid_msk) &&
+	    (lq->agg_ctrl.requested_ba & tid_msk)) {
+		u8 available_queues;
+		u32 load;
+
+		spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+		available_queues = iwl4964_tl_ba_avail(priv);
+		load = iwl4965_tl_get_load(priv, tid);
+
+		spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+		if (!available_queues) {
+			if (auto_agg)
+				lq->agg_ctrl.tid_retry |= tid_msk;
+			else {
+				lq->agg_ctrl.requested_ba &= ~tid_msk;
+				lq->agg_ctrl.wait_for_agg_status &= ~tid_msk;
+			}
+		} else if ((auto_agg) &&
+			   ((load <= lq->agg_ctrl.tid_traffic_load_threshold) ||
+			    ((lq->agg_ctrl.wait_for_agg_status & tid_msk))))
+			lq->agg_ctrl.tid_retry |= tid_msk;
+		else {
+			lq->agg_ctrl.wait_for_agg_status |= tid_msk;
+			spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+			iwl4965_perform_addba(priv, tid, 0x40,
+					      lq->agg_ctrl.ba_timeout);
+			spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+		}
+	}
+	spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+}
+
+static void iwl4965_turn_on_agg(struct iwl_priv *priv, u8 tid)
+{
+	struct iwl_lq_mngr *lq;
+	unsigned long flags;
+
+	lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+
+	if ((tid < TID_MAX_LOAD_COUNT))
+		iwl4965_turn_on_agg_for_tid(priv, lq, lq->agg_ctrl.auto_agg,
+					    tid);
+	else if (tid == TID_ALL_SPECIFIED) {
+		if (lq->agg_ctrl.requested_ba) {
+			for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++)
+				iwl4965_turn_on_agg_for_tid(priv, lq,
+					lq->agg_ctrl.auto_agg, tid);
+		} else {
+			spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+			lq->agg_ctrl.tid_retry = 0;
+			lq->agg_ctrl.next_retry = 0;
+			spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+		}
+	}
+
+}
+
+void iwl4965_turn_off_agg(struct iwl_priv *priv, u8 tid)
+{
+	u32 tid_msk;
+	struct iwl_lq_mngr *lq;
+	unsigned long flags;
+
+	lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+
+	if ((tid < TID_MAX_LOAD_COUNT)) {
+		tid_msk = 1 << tid;
+		spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+		lq->agg_ctrl.wait_for_agg_status |= tid_msk;
+		lq->agg_ctrl.requested_ba &= ~tid_msk;
+		spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+		iwl4965_perform_delba(priv, tid);
+	} else if (tid == TID_ALL_SPECIFIED) {
+		spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+		for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) {
+			tid_msk = 1 << tid;
+			lq->agg_ctrl.wait_for_agg_status |= tid_msk;
+			spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+			iwl4965_perform_delba(priv, tid);
+			spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+		}
+		lq->agg_ctrl.requested_ba = 0;
+		spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+	}
+}
+
+static void iwl4965_ba_status(struct iwl_priv *priv,
+				u8 tid, enum HT_STATUS status)
+{
+	struct iwl_lq_mngr *lq;
+	u32 tid_msk = (1 << tid);
+	unsigned long flags;
+
+	lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+
+	if ((tid >= TID_MAX_LOAD_COUNT))
+		goto out;
+
+	spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+	switch (status) {
+	case BA_STATUS_ACTIVE:
+		if (!(lq->agg_ctrl.granted_ba & tid_msk))
+			lq->agg_ctrl.granted_ba |= tid_msk;
+		break;
+	default:
+		if ((lq->agg_ctrl.granted_ba & tid_msk))
+			lq->agg_ctrl.granted_ba &= ~tid_msk;
+		break;
+	}
+
+	lq->agg_ctrl.wait_for_agg_status &= ~tid_msk;
+	if (status != BA_STATUS_ACTIVE) {
+		if (lq->agg_ctrl.auto_agg) {
+			lq->agg_ctrl.tid_retry |= tid_msk;
+			lq->agg_ctrl.next_retry =
+			    jiffies + msecs_to_jiffies(500);
+		} else
+			lq->agg_ctrl.requested_ba &= ~tid_msk;
+	}
+	spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+ out:
+	return;
+}
+
+static void iwl4965_bg_agg_work(struct work_struct *work)
+{
+	struct iwl_priv *priv = container_of(work, struct iwl_priv,
+					agg_work);
+
+	u32 tid;
+	u32 retry_tid;
+	u32 tid_msk;
+	unsigned long flags;
+	struct iwl_lq_mngr *lq = (struct iwl_lq_mngr *)&(priv->lq_mngr);
+
+	spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+	retry_tid = lq->agg_ctrl.tid_retry;
+	lq->agg_ctrl.tid_retry = 0;
+	spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+
+	if (retry_tid == TID_ALL_SPECIFIED)
+		iwl4965_turn_on_agg(priv, TID_ALL_SPECIFIED);
+	else {
+		for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++) {
+			tid_msk = (1 << tid);
+			if (retry_tid & tid_msk)
+				iwl4965_turn_on_agg(priv, tid);
+		}
+	}
+
+	spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+	if (lq->agg_ctrl.tid_retry)
+		lq->agg_ctrl.next_retry = jiffies + msecs_to_jiffies(500);
+	spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+	return;
+}
+#endif /*CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd,
+		   u8 sta_id, dma_addr_t txcmd_phys,
+		   struct ieee80211_hdr *hdr, u8 hdr_len,
+		   struct ieee80211_tx_control *ctrl, void *sta_in)
+{
+	struct iwl_tx_cmd cmd;
+	struct iwl_tx_cmd *tx = (struct iwl_tx_cmd *)&out_cmd->cmd.payload[0];
+	dma_addr_t scratch_phys;
+	u8 unicast = 0;
+	u8 is_data = 1;
+	u16 fc;
+	u16 rate_flags;
+	int rate_index = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1);
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+	__le16 *qc;
+#endif /*CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+	unicast = !is_multicast_ether_addr(hdr->addr1);
+
+	fc = le16_to_cpu(hdr->frame_control);
+	if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)
+		is_data = 0;
+
+	memcpy(&cmd, &(out_cmd->cmd.tx), sizeof(struct iwl_tx_cmd));
+	memset(tx, 0, sizeof(struct iwl_tx_cmd));
+	memcpy(tx->hdr, hdr, hdr_len);
+
+	tx->len = cmd.len;
+	tx->driver_txop = cmd.driver_txop;
+	tx->stop_time.life_time = cmd.stop_time.life_time;
+	tx->tx_flags = cmd.tx_flags;
+	tx->sta_id = cmd.sta_id;
+	tx->tid_tspec = cmd.tid_tspec;
+	tx->timeout.pm_frame_timeout = cmd.timeout.pm_frame_timeout;
+	tx->next_frame_len = cmd.next_frame_len;
+
+	tx->sec_ctl = cmd.sec_ctl;
+	memcpy(&(tx->key[0]), &(cmd.key[0]), 16);
+	tx->tx_flags = cmd.tx_flags;
+
+	tx->rts_retry_limit = cmd.rts_retry_limit;
+	tx->data_retry_limit = cmd.data_retry_limit;
+
+	scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
+	    offsetof(struct iwl_tx_cmd, scratch);
+	tx->dram_lsb_ptr = cpu_to_le32(scratch_phys);
+	tx->dram_msb_ptr = iwl4965_get_dma_hi_address(scratch_phys);
+
+	/* Hard coded to start at the highest retry fallback position
+	 * until the 4965 specific rate control algorithm is tied in */
+	tx->initial_rate_index = LINK_QUAL_MAX_RETRY_NUM - 1;
+
+	/* Alternate between antenna A and B for successive frames */
+	if (priv->use_ant_b_for_management_frame) {
+		priv->use_ant_b_for_management_frame = 0;
+		rate_flags = RATE_MCS_ANT_B_MSK;
+	} else {
+		priv->use_ant_b_for_management_frame = 1;
+		rate_flags = RATE_MCS_ANT_A_MSK;
+	}
+
+	if (!unicast || !is_data) {
+		if ((rate_index >= IWL_FIRST_CCK_RATE) &&
+		    (rate_index <= IWL_LAST_CCK_RATE))
+			rate_flags |= RATE_MCS_CCK_MSK;
+	} else {
+		tx->initial_rate_index = 0;
+		tx->tx_flags |= TX_CMD_FLG_STA_RATE_MSK;
+	}
+
+	tx->rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[rate_index].plcp,
+						rate_flags);
+
+	if (ieee80211_is_probe_request(fc))
+		tx->tx_flags |= TX_CMD_FLG_TSF_MSK;
+	else if (ieee80211_is_back_request(fc))
+		tx->tx_flags |= TX_CMD_FLG_ACK_MSK |
+			TX_CMD_FLG_IMM_BA_RSP_MASK;
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+	qc = ieee80211_get_qos_ctrl(hdr);
+	if (qc &&
+	    (priv->iw_mode != IEEE80211_IF_TYPE_IBSS)) {
+		u8 tid = 0;
+		tid = (u8) (le16_to_cpu(*qc) & 0xF);
+		if (tid < TID_MAX_LOAD_COUNT)
+			iwl4965_tl_add_packet(priv, tid);
+	}
+
+	if (priv->lq_mngr.agg_ctrl.next_retry &&
+	    (time_after(priv->lq_mngr.agg_ctrl.next_retry, jiffies))) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&priv->lq_mngr.lock, flags);
+		priv->lq_mngr.agg_ctrl.next_retry = 0;
+		spin_unlock_irqrestore(&priv->lq_mngr.lock, flags);
+		schedule_work(&priv->agg_work);
+	}
+#endif
+#endif
+	return 0;
+}
+
+/**
+ * sign_extend - Sign extend a value using specified bit as sign-bit
+ *
+ * Example: sign_extend(9, 3) would return -7 as bit3 of 1001b is 1
+ * and bit0..2 is 001b which when sign extended to 1111111111111001b is -7.
+ *
+ * @param oper value to sign extend
+ * @param index 0 based bit index (0<=index<32) to sign bit
+ */
+static s32 sign_extend(u32 oper, int index)
+{
+	u8 shift = 31 - index;
+
+	return (s32)(oper << shift) >> shift;
+}
+
+/**
+ * iwl4965_get_temperature - return the calibrated temperature (in Kelvin)
+ * @statistics: Provides the temperature reading from the uCode
+ *
+ * A return of <0 indicates bogus data in the statistics
+ */
+int iwl4965_get_temperature(const struct iwl_priv *priv)
+{
+	s32 temperature;
+	s32 vt;
+	s32 R1, R2, R3;
+	u32 R4;
+
+	if (test_bit(STATUS_TEMPERATURE, &priv->status) &&
+		(priv->statistics.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK)) {
+		IWL_DEBUG_TEMP("Running FAT temperature calibration\n");
+		R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[1]);
+		R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[1]);
+		R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[1]);
+		R4 = le32_to_cpu(priv->card_alive_init.therm_r4[1]);
+	} else {
+		IWL_DEBUG_TEMP("Running temperature calibration\n");
+		R1 = (s32)le32_to_cpu(priv->card_alive_init.therm_r1[0]);
+		R2 = (s32)le32_to_cpu(priv->card_alive_init.therm_r2[0]);
+		R3 = (s32)le32_to_cpu(priv->card_alive_init.therm_r3[0]);
+		R4 = le32_to_cpu(priv->card_alive_init.therm_r4[0]);
+	}
+
+	/*
+	 * Temperature is only 23 bits so sign extend out to 32
+	 *
+	 * NOTE If we haven't received a statistics notification yet
+	 * with an updated temperature, use R4 provided to us in the
+	 * ALIVE response. */
+	if (!test_bit(STATUS_TEMPERATURE, &priv->status))
+		vt = sign_extend(R4, 23);
+	else
+		vt = sign_extend(
+			le32_to_cpu(priv->statistics.general.temperature), 23);
+
+	IWL_DEBUG_TEMP("Calib values R[1-3]: %d %d %d R4: %d\n",
+		       R1, R2, R3, vt);
+
+	if (R3 == R1) {
+		IWL_ERROR("Calibration conflict R1 == R3\n");
+		return -1;
+	}
+
+	/* Calculate temperature in degrees Kelvin, adjust by 97%.
+	 * Add offset to center the adjustment around 0 degrees Centigrade. */
+	temperature = TEMPERATURE_CALIB_A_VAL * (vt - R2);
+	temperature /= (R3 - R1);
+	temperature = (temperature * 97) / 100 +
+	    TEMPERATURE_CALIB_KELVIN_OFFSET;
+
+	IWL_DEBUG_TEMP("Calibrated temperature: %dK, %dC\n", temperature,
+	    KELVIN_TO_CELSIUS(temperature));
+
+	return temperature;
+}
+
+/* Adjust Txpower only if temperature variance is greater than threshold. */
+#define IWL_TEMPERATURE_THRESHOLD   3
+
+/**
+ * iwl4965_is_temp_calib_needed - determines if new calibration is needed
+ *
+ * If the temperature changed has changed sufficiently, then a recalibration
+ * is needed.
+ *
+ * Assumes caller will replace priv->last_temperature once calibration
+ * executed.
+ */
+static int iwl4965_is_temp_calib_needed(struct iwl_priv *priv)
+{
+	int temp_diff;
+
+	if (!test_bit(STATUS_STATISTICS, &priv->status)) {
+		IWL_DEBUG_TEMP("Temperature not updated -- no statistics.\n");
+		return 0;
+	}
+
+	temp_diff = priv->temperature - priv->last_temperature;
+
+	/* get absolute value */
+	if (temp_diff < 0) {
+		IWL_DEBUG_POWER("Getting cooler, delta %d, \n", temp_diff);
+		temp_diff = -temp_diff;
+	} else if (temp_diff == 0)
+		IWL_DEBUG_POWER("Same temp, \n");
+	else
+		IWL_DEBUG_POWER("Getting warmer, delta %d, \n", temp_diff);
+
+	if (temp_diff < IWL_TEMPERATURE_THRESHOLD) {
+		IWL_DEBUG_POWER("Thermal txpower calib not needed\n");
+		return 0;
+	}
+
+	IWL_DEBUG_POWER("Thermal txpower calib needed\n");
+
+	return 1;
+}
+
+/* Calculate noise level, based on measurements during network silence just
+ *   before arriving beacon.  This measurement can be done only if we know
+ *   exactly when to expect beacons, therefore only when we're associated. */
+static void iwl4965_rx_calc_noise(struct iwl_priv *priv)
+{
+	struct statistics_rx_non_phy *rx_info
+				= &(priv->statistics.rx.general);
+	int num_active_rx = 0;
+	int total_silence = 0;
+	int bcn_silence_a =
+		le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
+	int bcn_silence_b =
+		le32_to_cpu(rx_info->beacon_silence_rssi_b) & IN_BAND_FILTER;
+	int bcn_silence_c =
+		le32_to_cpu(rx_info->beacon_silence_rssi_c) & IN_BAND_FILTER;
+
+	if (bcn_silence_a) {
+		total_silence += bcn_silence_a;
+		num_active_rx++;
+	}
+	if (bcn_silence_b) {
+		total_silence += bcn_silence_b;
+		num_active_rx++;
+	}
+	if (bcn_silence_c) {
+		total_silence += bcn_silence_c;
+		num_active_rx++;
+	}
+
+	/* Average among active antennas */
+	if (num_active_rx)
+		priv->last_rx_noise = (total_silence / num_active_rx) - 107;
+	else
+		priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+
+	IWL_DEBUG_CALIB("inband silence a %u, b %u, c %u, dBm %d\n",
+			bcn_silence_a, bcn_silence_b, bcn_silence_c,
+			priv->last_rx_noise);
+}
+
+void iwl_hw_rx_statistics(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	int change;
+	s32 temp;
+
+	IWL_DEBUG_RX("Statistics notification received (%d vs %d).\n",
+		     (int)sizeof(priv->statistics), pkt->len);
+
+	change = ((priv->statistics.general.temperature !=
+		   pkt->u.stats.general.temperature) ||
+		  ((priv->statistics.flag &
+		    STATISTICS_REPLY_FLG_FAT_MODE_MSK) !=
+		   (pkt->u.stats.flag & STATISTICS_REPLY_FLG_FAT_MODE_MSK)));
+
+	memcpy(&priv->statistics, &pkt->u.stats, sizeof(priv->statistics));
+
+	set_bit(STATUS_STATISTICS, &priv->status);
+
+	/* Reschedule the statistics timer to occur in
+	 * REG_RECALIB_PERIOD seconds to ensure we get a
+	 * thermal update even if the uCode doesn't give
+	 * us one */
+	mod_timer(&priv->statistics_periodic, jiffies +
+		  msecs_to_jiffies(REG_RECALIB_PERIOD * 1000));
+
+	if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
+	    (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
+		iwl4965_rx_calc_noise(priv);
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+		queue_work(priv->workqueue, &priv->sensitivity_work);
+#endif
+	}
+
+	/* If the hardware hasn't reported a change in
+	 * temperature then don't bother computing a
+	 * calibrated temperature value */
+	if (!change)
+		return;
+
+	temp = iwl4965_get_temperature(priv);
+	if (temp < 0)
+		return;
+
+	if (priv->temperature != temp) {
+		if (priv->temperature)
+			IWL_DEBUG_TEMP("Temperature changed "
+				       "from %dC to %dC\n",
+				       KELVIN_TO_CELSIUS(priv->temperature),
+				       KELVIN_TO_CELSIUS(temp));
+		else
+			IWL_DEBUG_TEMP("Temperature "
+				       "initialized to %dC\n",
+				       KELVIN_TO_CELSIUS(temp));
+	}
+
+	priv->temperature = temp;
+	set_bit(STATUS_TEMPERATURE, &priv->status);
+
+	if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
+		     iwl4965_is_temp_calib_needed(priv))
+		queue_work(priv->workqueue, &priv->txpower_work);
+}
+
+static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
+				       int include_phy,
+				       struct iwl_rx_mem_buffer *rxb,
+				       struct ieee80211_rx_status *stats)
+{
+	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+	struct iwl4965_rx_phy_res *rx_start = (include_phy) ?
+	    (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL;
+	struct ieee80211_hdr *hdr;
+	u16 len;
+	__le32 *rx_end;
+	unsigned int skblen;
+	u32 ampdu_status;
+
+	if (!include_phy && priv->last_phy_res[0])
+		rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1];
+
+	if (!rx_start) {
+		IWL_ERROR("MPDU frame without a PHY data\n");
+		return;
+	}
+	if (include_phy) {
+		hdr = (struct ieee80211_hdr *)((u8 *) & rx_start[1] +
+					       rx_start->cfg_phy_cnt);
+
+		len = le16_to_cpu(rx_start->byte_count);
+
+		rx_end = (__le32 *) ((u8 *) & pkt->u.raw[0] +
+				  sizeof(struct iwl4965_rx_phy_res) +
+				  rx_start->cfg_phy_cnt + len);
+
+	} else {
+		struct iwl4965_rx_mpdu_res_start *amsdu =
+		    (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
+
+		hdr = (struct ieee80211_hdr *)(pkt->u.raw +
+			       sizeof(struct iwl4965_rx_mpdu_res_start));
+		len =  le16_to_cpu(amsdu->byte_count);
+		rx_start->byte_count = amsdu->byte_count;
+		rx_end = (__le32 *) (((u8 *) hdr) + len);
+	}
+	if (len > 2342 || len < 16) {
+		IWL_DEBUG_DROP("byte count out of range [16,2342]"
+			       " : %d\n", len);
+		return;
+	}
+
+	ampdu_status = le32_to_cpu(*rx_end);
+	skblen = ((u8 *) rx_end - (u8 *) & pkt->u.raw[0]) + sizeof(u32);
+
+	/* start from MAC */
+	skb_reserve(rxb->skb, (void *)hdr - (void *)pkt);
+	skb_put(rxb->skb, len);	/* end where data ends */
+
+	/* We only process data packets if the interface is open */
+	if (unlikely(!priv->is_open)) {
+		IWL_DEBUG_DROP_LIMIT
+		    ("Dropping packet while interface is not open.\n");
+		return;
+	}
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+		if (iwl_param_hwcrypto)
+			iwl_set_decrypted_flag(priv, rxb->skb,
+					       ampdu_status, stats);
+		iwl_handle_data_packet_monitor(priv, rxb, hdr, len, stats, 0);
+		return;
+	}
+
+	stats->flag = 0;
+	hdr = (struct ieee80211_hdr *)rxb->skb->data;
+
+	if (iwl_param_hwcrypto)
+		iwl_set_decrypted_flag(priv, rxb->skb, ampdu_status, stats);
+
+	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+	priv->alloc_rxb_skb--;
+	rxb->skb = NULL;
+#ifdef LED
+	priv->led_packets += len;
+	iwl_setup_activity_timer(priv);
+#endif
+}
+
+/* Calc max signal level (dBm) among 3 possible receivers */
+static int iwl4965_calc_rssi(struct iwl4965_rx_phy_res *rx_resp)
+{
+	/* data from PHY/DSP regarding signal strength, etc.,
+	 *   contents are always there, not configurable by host.  */
+	struct iwl4965_rx_non_cfg_phy *ncphy =
+	    (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy;
+	u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL_AGC_DB_MASK)
+			>> IWL_AGC_DB_POS;
+
+	u32 valid_antennae =
+	    (le16_to_cpu(rx_resp->phy_flags) & RX_PHY_FLAGS_ANTENNAE_MASK)
+			>> RX_PHY_FLAGS_ANTENNAE_OFFSET;
+	u8 max_rssi = 0;
+	u32 i;
+
+	/* Find max rssi among 3 possible receivers.
+	 * These values are measured by the digital signal processor (DSP).
+	 * They should stay fairly constant even as the signal strength varies,
+	 *   if the radio's automatic gain control (AGC) is working right.
+	 * AGC value (see below) will provide the "interesting" info. */
+	for (i = 0; i < 3; i++)
+		if (valid_antennae & (1 << i))
+			max_rssi = max(ncphy->rssi_info[i << 1], max_rssi);
+
+	IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n",
+		ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4],
+		max_rssi, agc);
+
+	/* dBm = max_rssi dB - agc dB - constant.
+	 * Higher AGC (higher radio gain) means lower signal. */
+	return (max_rssi - agc - IWL_RSSI_OFFSET);
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+
+/* Parsed Information Elements */
+struct ieee802_11_elems {
+	u8 *ds_params;
+	u8 ds_params_len;
+	u8 *tim;
+	u8 tim_len;
+	u8 *ibss_params;
+	u8 ibss_params_len;
+	u8 *erp_info;
+	u8 erp_info_len;
+	u8 *ht_cap_param;
+	u8 ht_cap_param_len;
+	u8 *ht_extra_param;
+	u8 ht_extra_param_len;
+};
+
+static int parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems)
+{
+	size_t left = len;
+	u8 *pos = start;
+	int unknown = 0;
+
+	memset(elems, 0, sizeof(*elems));
+
+	while (left >= 2) {
+		u8 id, elen;
+
+		id = *pos++;
+		elen = *pos++;
+		left -= 2;
+
+		if (elen > left)
+			return -1;
+
+		switch (id) {
+		case WLAN_EID_DS_PARAMS:
+			elems->ds_params = pos;
+			elems->ds_params_len = elen;
+			break;
+		case WLAN_EID_TIM:
+			elems->tim = pos;
+			elems->tim_len = elen;
+			break;
+		case WLAN_EID_IBSS_PARAMS:
+			elems->ibss_params = pos;
+			elems->ibss_params_len = elen;
+			break;
+		case WLAN_EID_ERP_INFO:
+			elems->erp_info = pos;
+			elems->erp_info_len = elen;
+			break;
+		case WLAN_EID_HT_CAPABILITY:
+			elems->ht_cap_param = pos;
+			elems->ht_cap_param_len = elen;
+			break;
+		case WLAN_EID_HT_EXTRA_INFO:
+			elems->ht_extra_param = pos;
+			elems->ht_extra_param_len = elen;
+			break;
+		default:
+			unknown++;
+			break;
+		}
+
+		left -= elen;
+		pos += elen;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IWLWIFI_HT */
+
+static void iwl4965_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
+	priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
+	priv->stations[sta_id].sta.sta.modify_mask = 0;
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+static void iwl4965_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr)
+{
+	/* FIXME: need locking over ps_status ??? */
+	u8 sta_id = iwl_hw_find_station(priv, addr);
+
+	if (sta_id != IWL_INVALID_STATION) {
+		u8 sta_awake = priv->stations[sta_id].
+				ps_status == STA_PS_STATUS_WAKE;
+
+		if (sta_awake && ps_bit)
+			priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP;
+		else if (!sta_awake && !ps_bit) {
+			iwl4965_sta_modify_ps_wake(priv, sta_id);
+			priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE;
+		}
+	}
+}
+
+/* Called for REPLY_4965_RX (legacy ABG frames), or
+ * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
+static void iwl4965_rx_reply_rx(struct iwl_priv *priv,
+				struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	/* Use phy data (Rx signal strength, etc.) contained within
+	 *   this rx packet for legacy frames,
+	 *   or phy data cached from REPLY_RX_PHY_CMD for HT frames. */
+	int include_phy = (pkt->hdr.cmd == REPLY_4965_RX);
+	struct iwl4965_rx_phy_res *rx_start = (include_phy) ?
+		(struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) :
+		(struct iwl4965_rx_phy_res *)&priv->last_phy_res[1];
+	__le32 *rx_end;
+	unsigned int len = 0;
+	struct ieee80211_hdr *header;
+	u16 fc;
+	struct ieee80211_rx_status stats = {
+		.mactime = le64_to_cpu(rx_start->timestamp),
+		.channel = le16_to_cpu(rx_start->channel),
+		.phymode =
+			(rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
+			MODE_IEEE80211G : MODE_IEEE80211A,
+		.antenna = 0,
+		.rate = iwl_hw_get_rate(rx_start->rate_n_flags),
+		.flag = 0,
+#ifdef CONFIG_IWLWIFI_HT_AGG
+		.ordered = 0
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+	};
+	u8 network_packet;
+
+	if ((unlikely(rx_start->cfg_phy_cnt > 20))) {
+		IWL_DEBUG_DROP
+			("dsp size out of range [0,20]: "
+			 "%d/n", rx_start->cfg_phy_cnt);
+		return;
+	}
+	if (!include_phy) {
+		if (priv->last_phy_res[0])
+			rx_start = (struct iwl4965_rx_phy_res *)
+				&priv->last_phy_res[1];
+		else
+			rx_start = NULL;
+	}
+
+	if (!rx_start) {
+		IWL_ERROR("MPDU frame without a PHY data\n");
+		return;
+	}
+
+	if (include_phy) {
+		header = (struct ieee80211_hdr *)((u8 *) & rx_start[1]
+						  + rx_start->cfg_phy_cnt);
+
+		len = le16_to_cpu(rx_start->byte_count);
+		rx_end = (__le32 *) (pkt->u.raw + rx_start->cfg_phy_cnt +
+				  sizeof(struct iwl4965_rx_phy_res) + len);
+	} else {
+		struct iwl4965_rx_mpdu_res_start *amsdu =
+			(struct iwl4965_rx_mpdu_res_start *)pkt->u.raw;
+
+		header = (void *)(pkt->u.raw +
+			sizeof(struct iwl4965_rx_mpdu_res_start));
+		len = le16_to_cpu(amsdu->byte_count);
+		rx_end = (__le32 *) (pkt->u.raw +
+			sizeof(struct iwl4965_rx_mpdu_res_start) + len);
+	}
+
+	if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) ||
+	    !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
+		IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n",
+				le32_to_cpu(*rx_end));
+		return;
+	}
+
+	priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp);
+
+	stats.freq = ieee80211chan2mhz(stats.channel);
+
+	/* Find max signal strength (dBm) among 3 antenna/receiver chains */
+	stats.ssi = iwl4965_calc_rssi(rx_start);
+
+	/* Meaningful noise values are available only from beacon statistics,
+	 *   which are gathered only when associated, and indicate noise
+	 *   only for the associated network channel ...
+	 * Ignore these noise values while scanning (other channels) */
+	if (iwl_is_associated(priv) &&
+	    !test_bit(STATUS_SCANNING, &priv->status)) {
+		stats.noise = priv->last_rx_noise;
+		stats.signal = iwl_calc_sig_qual(stats.ssi, stats.noise);
+	} else {
+		stats.noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+		stats.signal = iwl_calc_sig_qual(stats.ssi, 0);
+	}
+
+	/* Reset beacon noise level if not associated. */
+	if (!iwl_is_associated(priv))
+		priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	/* TODO:  Parts of iwl_report_frame are broken for 4965 */
+	if (iwl_debug_level & (IWL_DL_RX))
+		/* Set "1" to report good data frames in groups of 100 */
+		iwl_report_frame(priv, pkt, header, 1);
+
+	if (iwl_debug_level & (IWL_DL_RX | IWL_DL_STATS))
+	IWL_DEBUG_RX("Rssi %d, noise %d, qual %d, TSF %lu\n",
+		stats.ssi, stats.noise, stats.signal,
+		 (long unsigned int)le64_to_cpu(rx_start->timestamp));
+#endif
+
+	network_packet = iwl_is_network_packet(priv, header);
+	if (network_packet) {
+		priv->last_rx_rssi = stats.ssi;
+		priv->last_beacon_time =  priv->ucode_beacon_time;
+		priv->last_tsf = le64_to_cpu(rx_start->timestamp);
+	}
+
+	fc = le16_to_cpu(header->frame_control);
+	switch (fc & IEEE80211_FCTL_FTYPE) {
+	case IEEE80211_FTYPE_MGMT:
+
+		if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+			iwl4965_update_ps_mode(priv, fc  & IEEE80211_FCTL_PM,
+						header->addr2);
+		switch (fc & IEEE80211_FCTL_STYPE) {
+		case IEEE80211_STYPE_PROBE_RESP:
+		case IEEE80211_STYPE_BEACON:
+			if ((priv->iw_mode == IEEE80211_IF_TYPE_STA &&
+			     !compare_ether_addr(header->addr2, priv->bssid)) ||
+			    (priv->iw_mode == IEEE80211_IF_TYPE_IBSS &&
+			     !compare_ether_addr(header->addr3, priv->bssid))) {
+				struct ieee80211_mgmt *mgmt =
+					(struct ieee80211_mgmt *)header;
+				u64 timestamp =
+					le64_to_cpu(mgmt->u.beacon.timestamp);
+
+				priv->timestamp0 = timestamp & 0xFFFFFFFF;
+				priv->timestamp1 =
+					(timestamp >> 32) & 0xFFFFFFFF;
+				priv->beacon_int = le16_to_cpu(
+				    mgmt->u.beacon.beacon_int);
+				if (priv->call_post_assoc_from_beacon &&
+				    (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
+					priv->call_post_assoc_from_beacon = 0;
+					queue_work(priv->workqueue,
+					    &priv->post_associate.work);
+				}
+			}
+			break;
+
+		case IEEE80211_STYPE_ACTION:
+			break;
+
+			/*
+			 * TODO: There is no callback function from upper
+			 * stack to inform us when associated status. this
+			 * work around to sniff assoc_resp management frame
+			 * and finish the association process.
+			 */
+		case IEEE80211_STYPE_ASSOC_RESP:
+		case IEEE80211_STYPE_REASSOC_RESP:
+			if (network_packet && iwl_is_associated(priv)) {
+#ifdef CONFIG_IWLWIFI_HT
+				u8 *pos = NULL;
+				struct ieee802_11_elems elems;
+#endif				/*CONFIG_IWLWIFI_HT */
+				struct ieee80211_mgmt *mgnt =
+					(struct ieee80211_mgmt *)header;
+
+				priv->assoc_id = (~((1 << 15) | (1 << 14))
+					& le16_to_cpu(mgnt->u.assoc_resp.aid));
+				priv->assoc_capability =
+					le16_to_cpu(
+						mgnt->u.assoc_resp.capab_info);
+#ifdef CONFIG_IWLWIFI_HT
+				pos = mgnt->u.assoc_resp.variable;
+				if (!parse_elems(pos,
+						 len - (pos - (u8 *) mgnt),
+						 &elems)) {
+					if (elems.ht_extra_param &&
+					    elems.ht_cap_param)
+						break;
+				}
+#endif				/*CONFIG_IWLWIFI_HT */
+				/* assoc_id is 0 no association */
+				if (!priv->assoc_id)
+					break;
+				if (priv->beacon_int)
+					queue_work(priv->workqueue,
+					    &priv->post_associate.work);
+				else
+					priv->call_post_assoc_from_beacon = 1;
+			}
+
+			break;
+
+		case IEEE80211_STYPE_PROBE_REQ:
+			if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+			    !iwl_is_associated(priv)) {
+				DECLARE_MAC_BUF(mac1);
+				DECLARE_MAC_BUF(mac2);
+				DECLARE_MAC_BUF(mac3);
+
+				IWL_DEBUG_DROP("Dropping (non network): "
+					       "%s, %s, %s\n",
+					       print_mac(mac1, header->addr1),
+					       print_mac(mac2, header->addr2),
+					       print_mac(mac3, header->addr3));
+				return;
+			}
+		}
+		iwl4965_handle_data_packet(priv, 0, include_phy, rxb, &stats);
+		break;
+
+	case IEEE80211_FTYPE_CTL:
+#ifdef CONFIG_IWLWIFI_HT_AGG
+		switch (fc & IEEE80211_FCTL_STYPE) {
+		case IEEE80211_STYPE_BACK_REQ:
+			IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n");
+			iwl4965_handle_data_packet(priv, 0, include_phy,
+						rxb, &stats);
+			break;
+		default:
+			break;
+		}
+#endif
+
+		break;
+
+	case IEEE80211_FTYPE_DATA: {
+		DECLARE_MAC_BUF(mac1);
+		DECLARE_MAC_BUF(mac2);
+		DECLARE_MAC_BUF(mac3);
+
+		if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+			iwl4965_update_ps_mode(priv, fc  & IEEE80211_FCTL_PM,
+						header->addr2);
+
+		if (unlikely(!network_packet))
+			IWL_DEBUG_DROP("Dropping (non network): "
+				       "%s, %s, %s\n",
+				       print_mac(mac1, header->addr1),
+				       print_mac(mac2, header->addr2),
+				       print_mac(mac3, header->addr3));
+		else if (unlikely(is_duplicate_packet(priv, header)))
+			IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n",
+				       print_mac(mac1, header->addr1),
+				       print_mac(mac2, header->addr2),
+				       print_mac(mac3, header->addr3));
+		else
+			iwl4965_handle_data_packet(priv, 1, include_phy, rxb,
+						   &stats);
+		break;
+	}
+	default:
+		break;
+
+	}
+}
+
+/* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
+ * This will be used later in iwl4965_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
+static void iwl4965_rx_reply_rx_phy(struct iwl_priv *priv,
+				    struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	priv->last_phy_res[0] = 1;
+	memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]),
+	       sizeof(struct iwl4965_rx_phy_res));
+}
+
+static void iwl4965_rx_missed_beacon_notif(struct iwl_priv *priv,
+					   struct iwl_rx_mem_buffer *rxb)
+
+{
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_missed_beacon_notif *missed_beacon;
+
+	missed_beacon = &pkt->u.missed_beacon;
+	if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) {
+		IWL_DEBUG_CALIB("missed bcn cnsq %d totl %d rcd %d expctd %d\n",
+		    le32_to_cpu(missed_beacon->consequtive_missed_beacons),
+		    le32_to_cpu(missed_beacon->total_missed_becons),
+		    le32_to_cpu(missed_beacon->num_recvd_beacons),
+		    le32_to_cpu(missed_beacon->num_expected_beacons));
+		priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
+		if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)))
+			queue_work(priv->workqueue, &priv->sensitivity_work);
+	}
+#endif /*CONFIG_IWLWIFI_SENSITIVITY*/
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+
+static void iwl4965_set_tx_status(struct iwl_priv *priv, int txq_id, int idx,
+				  u32 status, u32 retry_count, u32 rate)
+{
+	struct ieee80211_tx_status *tx_status =
+		&(priv->txq[txq_id].txb[idx].status);
+
+	tx_status->flags = status ? IEEE80211_TX_STATUS_ACK : 0;
+	tx_status->retry_count += retry_count;
+	tx_status->control.tx_rate = rate;
+}
+
+
+static void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv,
+					 int sta_id, int tid)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
+	priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+
+static int iwl4965_tx_status_reply_compressed_ba(struct iwl_priv *priv,
+						 struct iwl_ht_agg *agg,
+						 struct iwl_compressed_ba_resp*
+						 ba_resp)
+
+{
+	int i, sh, ack;
+	u16 ba_seq_ctl = le16_to_cpu(ba_resp->ba_seq_ctl);
+	u32 bitmap0, bitmap1;
+	u32 resp_bitmap0 = le32_to_cpu(ba_resp->ba_bitmap0);
+	u32 resp_bitmap1 = le32_to_cpu(ba_resp->ba_bitmap1);
+
+	if (unlikely(!agg->wait_for_ba))  {
+		IWL_ERROR("Received BA when not expected\n");
+		return -EINVAL;
+	}
+	agg->wait_for_ba = 0;
+	IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->ba_seq_ctl);
+	sh = agg->start_idx - SEQ_TO_INDEX(ba_seq_ctl>>4);
+	if (sh < 0) /* tbw something is wrong with indeces */
+		sh += 0x100;
+
+	/* don't use 64 bits for now */
+	bitmap0 = resp_bitmap0 >> sh;
+	bitmap1 = resp_bitmap1 >> sh;
+	bitmap0 |= (resp_bitmap1 & ((1<<sh)|((1<<sh)-1))) << (32 - sh);
+
+	if (agg->frame_count > (64 - sh)) {
+		IWL_DEBUG_TX_REPLY("more frames than bitmap size");
+		return -1;
+	}
+
+	/* check for success or failure according to the
+	 * transmitted bitmap and back bitmap */
+	bitmap0 &= agg->bitmap0;
+	bitmap1 &= agg->bitmap1;
+
+	for (i = 0; i < agg->frame_count ; i++) {
+		int idx = (agg->start_idx + i) & 0xff;
+		ack = bitmap0 & (1 << i);
+		IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n",
+			ack? "ACK":"NACK", i, idx, agg->start_idx + i);
+		iwl4965_set_tx_status(priv, agg->txq_id, idx, ack, 0,
+			agg->rate_n_flags);
+
+	}
+
+	IWL_DEBUG_TX_REPLY("Bitmap %x%x\n", bitmap0, bitmap1);
+
+	return 0;
+}
+
+static inline int iwl_queue_dec_wrap(int index, int n_bd)
+{
+	return (index == 0) ? n_bd - 1 : index - 1;
+}
+
+static void iwl4965_rx_reply_compressed_ba(struct iwl_priv *priv,
+					   struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
+	int index;
+	struct iwl_tx_queue *txq = NULL;
+	struct iwl_ht_agg *agg;
+	u16 ba_resp_scd_flow = le16_to_cpu(ba_resp->scd_flow);
+	u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
+
+	if (ba_resp_scd_flow >= ARRAY_SIZE(priv->txq)) {
+		IWL_ERROR("BUG_ON scd_flow is bigger than number of queues");
+		return;
+	}
+
+	txq = &priv->txq[ba_resp_scd_flow];
+	agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg;
+	index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
+
+	/* TODO: Need to get this copy more sefely - now good for debug */
+/*
+	{
+	DECLARE_MAC_BUF(mac);
+	IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, "
+			   "sta_id = %d\n",
+			   agg->wait_for_ba,
+			   print_mac(mac, (u8*) &ba_resp->sta_addr_lo32),
+			   ba_resp->sta_id);
+	IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%X%X, scd_flow = "
+			   "%d, scd_ssn = %d\n",
+			   ba_resp->tid,
+			   ba_resp->ba_seq_ctl,
+			   ba_resp->ba_bitmap1,
+			   ba_resp->ba_bitmap0,
+			   ba_resp->scd_flow,
+			   ba_resp->scd_ssn);
+	IWL_DEBUG_TX_REPLY("DAT start_idx = %d, bitmap = 0x%X%X \n",
+			   agg->start_idx,
+			   agg->bitmap1,
+			   agg->bitmap0);
+	}
+*/
+	iwl4965_tx_status_reply_compressed_ba(priv, agg, ba_resp);
+	/* releases all the TFDs until the SSN */
+	if (txq->q.last_used != (ba_resp_scd_ssn & 0xff))
+		iwl_tx_queue_reclaim(priv, ba_resp_scd_flow, index);
+
+}
+
+
+static void iwl4965_tx_queue_stop_scheduler(struct iwl_priv *priv, u16 txq_id)
+{
+	iwl_write_restricted_reg(priv,
+		SCD_QUEUE_STATUS_BITS(txq_id),
+		(0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
+		(1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+}
+
+static int iwl4965_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid,
+					u16 txq_id)
+{
+	u32 tbl_dw_addr;
+	u32 tbl_dw;
+	u16 scd_q2ratid;
+
+	scd_q2ratid = ra_tid & SCD_QUEUE_RA_TID_MAP_RATID_MSK;
+
+	tbl_dw_addr = priv->scd_base_addr +
+			SCD_TRANSLATE_TBL_OFFSET_QUEUE(txq_id);
+
+	tbl_dw = iwl_read_restricted_mem(priv, tbl_dw_addr);
+
+	if (txq_id & 0x1)
+		tbl_dw = (scd_q2ratid << 16) | (tbl_dw & 0x0000FFFF);
+	else
+		tbl_dw = scd_q2ratid | (tbl_dw & 0xFFFF0000);
+
+	iwl_write_restricted_mem(priv, tbl_dw_addr, tbl_dw);
+
+	return 0;
+}
+
+/**
+ * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID
+ */
+static int iwl4965_tx_queue_agg_enable(struct iwl_priv *priv, int txq_id,
+				       int tx_fifo, int sta_id, int tid,
+				       u16 ssn_idx)
+{
+	unsigned long flags;
+	int rc;
+	u16 ra_tid;
+
+	if (IWL_BACK_QUEUE_FIRST_ID > txq_id)
+		IWL_WARNING("queue number too small: %d, must be > %d\n",
+			txq_id, IWL_BACK_QUEUE_FIRST_ID);
+
+	ra_tid = BUILD_RAxTID(sta_id, tid);
+
+	iwl_sta_modify_enable_tid_tx(priv, sta_id, tid);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+
+	iwl4965_tx_queue_stop_scheduler(priv, txq_id);
+
+	iwl4965_tx_queue_set_q2ratid(priv, ra_tid, txq_id);
+
+
+	iwl_set_bits_restricted_reg(priv, SCD_QUEUECHAIN_SEL, (1<<txq_id));
+
+	priv->txq[txq_id].q.last_used = (ssn_idx & 0xff);
+	priv->txq[txq_id].q.first_empty = (ssn_idx & 0xff);
+
+	/* supposes that ssn_idx is valid (!= 0xFFF) */
+	iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx);
+
+	iwl_write_restricted_mem(priv,
+			priv->scd_base_addr + SCD_CONTEXT_QUEUE_OFFSET(txq_id),
+			(SCD_WIN_SIZE << SCD_QUEUE_CTX_REG1_WIN_SIZE_POS) &
+			SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK);
+
+	iwl_write_restricted_mem(priv, priv->scd_base_addr +
+			SCD_CONTEXT_QUEUE_OFFSET(txq_id) + sizeof(u32),
+			(SCD_FRAME_LIMIT << SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS)
+			& SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK);
+
+	iwl_set_bits_restricted_reg(priv, SCD_INTERRUPT_MASK, (1 << txq_id));
+
+	iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
+
+	iwl_release_restricted_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+/**
+ * txq_id must be greater than IWL_BACK_QUEUE_FIRST_ID
+ */
+static int iwl4965_tx_queue_agg_disable(struct iwl_priv *priv, u16 txq_id,
+					u16 ssn_idx, u8 tx_fifo)
+{
+	unsigned long flags;
+	int rc;
+
+	if (IWL_BACK_QUEUE_FIRST_ID > txq_id) {
+		IWL_WARNING("queue number too small: %d, must be > %d\n",
+				txq_id, IWL_BACK_QUEUE_FIRST_ID);
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+
+	iwl4965_tx_queue_stop_scheduler(priv, txq_id);
+
+	iwl_clear_bits_restricted_reg(priv, SCD_QUEUECHAIN_SEL, (1 << txq_id));
+
+	priv->txq[txq_id].q.last_used = (ssn_idx & 0xff);
+	priv->txq[txq_id].q.first_empty = (ssn_idx & 0xff);
+	/* supposes that ssn_idx is valid (!= 0xFFF) */
+	iwl4965_set_wr_ptrs(priv, txq_id, ssn_idx);
+
+	iwl_clear_bits_restricted_reg(priv, SCD_INTERRUPT_MASK, (1 << txq_id));
+	iwl4965_txq_ctx_deactivate(priv, txq_id);
+	iwl4965_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 0);
+
+	iwl_release_restricted_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return 0;
+}
+
+#endif/* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+/*
+ * RATE SCALE CODE
+ */
+int iwl4965_init_hw_rates(struct iwl_priv *priv, struct ieee80211_rate *rates)
+{
+	return 0;
+}
+
+
+/**
+ * iwl4965_add_station - Initialize a station's hardware rate table
+ *
+ * The uCode contains a table of fallback rates and retries per rate
+ * for automatic fallback during transmission.
+ *
+ * NOTE: This initializes the table for a single retry per data rate
+ * which is not optimal.  Setting up an intelligent retry per rate
+ * requires feedback from transmission, which isn't exposed through
+ * rc80211_simple which is what this driver is currently using.
+ *
+ */
+void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
+{
+	int i, r;
+	struct iwl_link_quality_cmd link_cmd = {
+		.reserved1 = 0,
+	};
+	u16 rate_flags;
+
+	/* Set up the rate scaling to start at 54M and fallback
+	 * all the way to 1M in IEEE order and then spin on IEEE */
+	if (is_ap)
+		r = IWL_RATE_54M_INDEX;
+	else if (priv->phymode == MODE_IEEE80211A)
+		r = IWL_RATE_6M_INDEX;
+	else
+		r = IWL_RATE_1M_INDEX;
+
+	for (i = 0; i < LINK_QUAL_MAX_RETRY_NUM; i++) {
+		rate_flags = 0;
+		if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE)
+			rate_flags |= RATE_MCS_CCK_MSK;
+
+		rate_flags |= RATE_MCS_ANT_B_MSK;
+		rate_flags &= ~RATE_MCS_ANT_A_MSK;
+		link_cmd.rs_table[i].rate_n_flags =
+			iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags);
+		r = iwl_get_prev_ieee_rate(r);
+	}
+
+	link_cmd.general_params.single_stream_ant_msk = 2;
+	link_cmd.general_params.dual_stream_ant_msk = 3;
+	link_cmd.agg_params.agg_dis_start_th = 3;
+	link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000);
+
+	/* Update the rate scaling for control frame Tx to AP */
+	link_cmd.sta_id = is_ap ? IWL_AP_ID : IWL4965_BROADCAST_ID;
+
+	iwl_send_cmd_pdu(priv, REPLY_TX_LINK_QUALITY_CMD, sizeof(link_cmd),
+			 &link_cmd);
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+
+static u8 iwl_is_channel_extension(struct iwl_priv *priv, int phymode,
+				   u16 channel, u8 extension_chan_offset)
+{
+	const struct iwl_channel_info *ch_info;
+
+	ch_info = iwl_get_channel_info(priv, phymode, channel);
+	if (!is_channel_valid(ch_info))
+		return 0;
+
+	if (extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO)
+		return 0;
+
+	if ((ch_info->fat_extension_channel == extension_chan_offset) ||
+	    (ch_info->fat_extension_channel == HT_IE_EXT_CHANNEL_MAX))
+		return 1;
+
+	return 0;
+}
+
+static u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv,
+				const struct sta_ht_info *ht_info)
+{
+
+	if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
+		return 0;
+
+	if (ht_info->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ)
+		return 0;
+
+	if (ht_info->extension_chan_offset == IWL_EXT_CHANNEL_OFFSET_AUTO)
+		return 0;
+
+	/* no fat tx allowed on 2.4GHZ */
+	if (priv->phymode != MODE_IEEE80211A)
+		return 0;
+	return (iwl_is_channel_extension(priv, priv->phymode,
+					 ht_info->control_channel,
+					 ht_info->extension_chan_offset));
+}
+
+void iwl4965_set_rxon_ht(struct iwl_priv *priv, struct sta_ht_info *ht_info)
+{
+	struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+	u32 val;
+
+	if (!ht_info->is_ht)
+		return;
+
+	if (iwl_is_fat_tx_allowed(priv, ht_info))
+		rxon->flags |= RXON_FLG_CHANNEL_MODE_MIXED_MSK;
+	else
+		rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
+				 RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
+
+	if (le16_to_cpu(rxon->channel) != ht_info->control_channel) {
+		IWL_DEBUG_ASSOC("control diff than current %d %d\n",
+				le16_to_cpu(rxon->channel),
+				ht_info->control_channel);
+		rxon->channel = cpu_to_le16(ht_info->control_channel);
+		return;
+	}
+
+	/* Note: control channel is oposit to extension channel */
+	switch (ht_info->extension_chan_offset) {
+	case IWL_EXT_CHANNEL_OFFSET_ABOVE:
+		rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK);
+		break;
+	case IWL_EXT_CHANNEL_OFFSET_BELOW:
+		rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK;
+		break;
+	case IWL_EXT_CHANNEL_OFFSET_AUTO:
+		rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
+		break;
+	default:
+		rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK;
+		break;
+	}
+
+	val = ht_info->operating_mode;
+
+	rxon->flags |= cpu_to_le32(val << RXON_FLG_HT_OPERATING_MODE_POS);
+
+	priv->active_rate_ht[0] = ht_info->supp_rates[0];
+	priv->active_rate_ht[1] = ht_info->supp_rates[1];
+	iwl4965_set_rxon_chain(priv);
+
+	IWL_DEBUG_ASSOC("supported HT rate 0x%X %X "
+			"rxon flags 0x%X operation mode :0x%X "
+			"extension channel offset 0x%x "
+			"control chan %d\n",
+			priv->active_rate_ht[0], priv->active_rate_ht[1],
+			le32_to_cpu(rxon->flags), ht_info->operating_mode,
+			ht_info->extension_chan_offset,
+			ht_info->control_channel);
+	return;
+}
+
+void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index)
+{
+	__le32 sta_flags;
+	struct sta_ht_info *ht_info = &priv->current_assoc_ht;
+
+	priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ;
+	if (!ht_info->is_ht)
+		goto done;
+
+	sta_flags = priv->stations[index].sta.station_flags;
+
+	if (ht_info->tx_mimo_ps_mode == IWL_MIMO_PS_DYNAMIC)
+		sta_flags |= STA_FLG_RTS_MIMO_PROT_MSK;
+	else
+		sta_flags &= ~STA_FLG_RTS_MIMO_PROT_MSK;
+
+	sta_flags |= cpu_to_le32(
+		(u32)ht_info->ampdu_factor << STA_FLG_MAX_AGG_SIZE_POS);
+
+	sta_flags |= cpu_to_le32(
+		(u32)ht_info->mpdu_density << STA_FLG_AGG_MPDU_DENSITY_POS);
+
+	sta_flags &= (~STA_FLG_FAT_EN_MSK);
+	ht_info->tx_chan_width = IWL_CHANNEL_WIDTH_20MHZ;
+	ht_info->chan_width_cap = IWL_CHANNEL_WIDTH_20MHZ;
+
+	if (iwl_is_fat_tx_allowed(priv, ht_info)) {
+		sta_flags |= STA_FLG_FAT_EN_MSK;
+		ht_info->chan_width_cap = IWL_CHANNEL_WIDTH_40MHZ;
+		if (ht_info->supported_chan_width == IWL_CHANNEL_WIDTH_40MHZ)
+			ht_info->tx_chan_width = IWL_CHANNEL_WIDTH_40MHZ;
+	}
+	priv->current_channel_width = ht_info->tx_chan_width;
+	priv->stations[index].sta.station_flags = sta_flags;
+ done:
+	return;
+}
+
+#ifdef CONFIG_IWLWIFI_HT_AGG
+
+static void iwl4965_sta_modify_add_ba_tid(struct iwl_priv *priv,
+					  int sta_id, int tid, u16 ssn)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	priv->stations[sta_id].sta.station_flags_msk = 0;
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK;
+	priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid;
+	priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn);
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+static void iwl4965_sta_modify_del_ba_tid(struct iwl_priv *priv,
+					  int sta_id, int tid)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	priv->stations[sta_id].sta.station_flags_msk = 0;
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
+	priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	iwl_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+static const u16 default_tid_to_tx_fifo[] = {
+	IWL_TX_FIFO_AC1,
+	IWL_TX_FIFO_AC0,
+	IWL_TX_FIFO_AC0,
+	IWL_TX_FIFO_AC1,
+	IWL_TX_FIFO_AC2,
+	IWL_TX_FIFO_AC2,
+	IWL_TX_FIFO_AC3,
+	IWL_TX_FIFO_AC3,
+	IWL_TX_FIFO_NONE,
+	IWL_TX_FIFO_NONE,
+	IWL_TX_FIFO_NONE,
+	IWL_TX_FIFO_NONE,
+	IWL_TX_FIFO_NONE,
+	IWL_TX_FIFO_NONE,
+	IWL_TX_FIFO_NONE,
+	IWL_TX_FIFO_NONE,
+	IWL_TX_FIFO_AC3
+};
+
+static int iwl_txq_ctx_activate_free(struct iwl_priv *priv)
+{
+	int txq_id;
+
+	for (txq_id = 0; txq_id < priv->hw_setting.max_txq_num; txq_id++)
+		if (!test_and_set_bit(txq_id, &priv->txq_ctx_active_msk))
+			return txq_id;
+	return -1;
+}
+
+int iwl_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid,
+			    u16 *start_seq_num)
+{
+
+	struct iwl_priv *priv = hw->priv;
+	int sta_id;
+	int tx_fifo;
+	int txq_id;
+	int ssn = -1;
+	unsigned long flags;
+	struct iwl_tid_data *tid_data;
+	DECLARE_MAC_BUF(mac);
+
+	if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
+		tx_fifo = default_tid_to_tx_fifo[tid];
+	else
+		return -EINVAL;
+
+	IWL_WARNING("iwl-AGG iwl_mac_ht_tx_agg_start on da=%s"
+		    " tid=%d\n", print_mac(mac, da), tid);
+
+	sta_id = iwl_hw_find_station(priv, da);
+	if (sta_id == IWL_INVALID_STATION)
+		return -ENXIO;
+
+	txq_id = iwl_txq_ctx_activate_free(priv);
+	if (txq_id == -1)
+		return -ENXIO;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	tid_data = &priv->stations[sta_id].tid[tid];
+	ssn = SEQ_TO_SN(tid_data->seq_number);
+	tid_data->agg.txq_id = txq_id;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	*start_seq_num = ssn;
+	iwl4965_ba_status(priv, tid, BA_STATUS_ACTIVE);
+	return iwl4965_tx_queue_agg_enable(priv, txq_id, tx_fifo,
+					   sta_id, tid, ssn);
+}
+
+
+int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da, u16 tid,
+			   int generator)
+{
+
+	struct iwl_priv *priv = hw->priv;
+	int tx_fifo_id, txq_id, sta_id, ssn = -1;
+	struct iwl_tid_data *tid_data;
+	int rc;
+	DECLARE_MAC_BUF(mac);
+
+	if (!da) {
+		IWL_ERROR("%s: da = NULL\n", __func__);
+		return -EINVAL;
+	}
+
+	if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo)))
+		tx_fifo_id = default_tid_to_tx_fifo[tid];
+	else
+		return -EINVAL;
+
+	sta_id = iwl_hw_find_station(priv, da);
+
+	if (sta_id == IWL_INVALID_STATION)
+		return -ENXIO;
+
+	tid_data = &priv->stations[sta_id].tid[tid];
+	ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
+	txq_id = tid_data->agg.txq_id;
+
+	rc = iwl4965_tx_queue_agg_disable(priv, txq_id, ssn, tx_fifo_id);
+	/* FIXME: need more safe way to handle error condition */
+	if (rc)
+		return rc;
+
+	iwl4965_ba_status(priv, tid, BA_STATUS_INITIATOR_DELBA);
+	IWL_DEBUG_INFO("iwl_mac_ht_tx_agg_stop on da=%s tid=%d\n",
+		       print_mac(mac, da), tid);
+
+	return 0;
+}
+
+int iwl_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da,
+			    u16 tid, u16 start_seq_num)
+{
+	struct iwl_priv *priv = hw->priv;
+	int sta_id;
+	DECLARE_MAC_BUF(mac);
+
+	IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_start on da=%s"
+		    " tid=%d\n", print_mac(mac, da), tid);
+	sta_id = iwl_hw_find_station(priv, da);
+	iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, start_seq_num);
+	return 0;
+}
+
+int iwl_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da,
+			   u16 tid, int generator)
+{
+	struct iwl_priv *priv = hw->priv;
+	int sta_id;
+	DECLARE_MAC_BUF(mac);
+
+	IWL_WARNING("iwl-AGG iwl_mac_ht_rx_agg_stop on da=%s tid=%d\n",
+		    print_mac(mac, da), tid);
+	sta_id = iwl_hw_find_station(priv, da);
+	iwl4965_sta_modify_del_ba_tid(priv, sta_id, tid);
+	return 0;
+}
+
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+/* Set up 4965-specific Rx frame reply handlers */
+void iwl_hw_rx_handler_setup(struct iwl_priv *priv)
+{
+	/* Legacy Rx frames */
+	priv->rx_handlers[REPLY_4965_RX] = iwl4965_rx_reply_rx;
+
+	/* High-throughput (HT) Rx frames */
+	priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl4965_rx_reply_rx_phy;
+	priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl4965_rx_reply_rx;
+
+	priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] =
+	    iwl4965_rx_missed_beacon_notif;
+
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+	priv->rx_handlers[REPLY_COMPRESSED_BA] = iwl4965_rx_reply_compressed_ba;
+#endif /* CONFIG_IWLWIFI_AGG */
+#endif /* CONFIG_IWLWIFI */
+}
+
+void iwl_hw_setup_deferred_work(struct iwl_priv *priv)
+{
+	INIT_WORK(&priv->txpower_work, iwl4965_bg_txpower_work);
+	INIT_WORK(&priv->statistics_work, iwl4965_bg_statistics_work);
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+	INIT_WORK(&priv->sensitivity_work, iwl4965_bg_sensitivity_work);
+#endif
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+	INIT_WORK(&priv->agg_work, iwl4965_bg_agg_work);
+#endif /* CONFIG_IWLWIFI_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+	init_timer(&priv->statistics_periodic);
+	priv->statistics_periodic.data = (unsigned long)priv;
+	priv->statistics_periodic.function = iwl4965_bg_statistics_periodic;
+}
+
+void iwl_hw_cancel_deferred_work(struct iwl_priv *priv)
+{
+	del_timer_sync(&priv->statistics_periodic);
+
+	cancel_delayed_work(&priv->init_alive_start);
+}
+
+struct pci_device_id iwl_hw_card_ids[] = {
+	{0x8086, 0x4229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0x8086, 0x4230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0}
+};
+
+int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv)
+{
+	u16 count;
+	int rc;
+
+	for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
+		iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+			CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+		rc = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
+					CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+					CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+					EEPROM_SEM_TIMEOUT);
+		if (rc >= 0) {
+			IWL_DEBUG_IO("Aqcuired semaphore after %d tries.\n",
+				count+1);
+			return rc;
+		}
+	}
+
+	return rc;
+}
+
+inline void iwl_eeprom_release_semaphore(struct iwl_priv *priv)
+{
+	iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+		CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+}
+
+
+MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h
new file mode 100644
index 0000000..4c70081
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.h
@@ -0,0 +1,341 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#ifndef __iwl_4965_h__
+#define __iwl_4965_h__
+
+struct iwl_priv;
+struct sta_ht_info;
+
+/*
+ * Forward declare iwl-4965.c functions for iwl-base.c
+ */
+extern int iwl_eeprom_aqcuire_semaphore(struct iwl_priv *priv);
+extern void iwl_eeprom_release_semaphore(struct iwl_priv *priv);
+
+extern int iwl4965_tx_queue_update_wr_ptr(struct iwl_priv *priv,
+					  struct iwl_tx_queue *txq,
+					  u16 byte_cnt);
+extern void iwl4965_add_station(struct iwl_priv *priv, const u8 *addr,
+				int is_ap);
+extern void iwl4965_set_rxon_ht(struct iwl_priv *priv,
+				struct sta_ht_info *ht_info);
+
+extern void iwl4965_set_rxon_chain(struct iwl_priv *priv);
+extern int iwl4965_tx_cmd(struct iwl_priv *priv, struct iwl_cmd *out_cmd,
+			  u8 sta_id, dma_addr_t txcmd_phys,
+			  struct ieee80211_hdr *hdr, u8 hdr_len,
+			  struct ieee80211_tx_control *ctrl, void *sta_in);
+extern int iwl4965_init_hw_rates(struct iwl_priv *priv,
+				 struct ieee80211_rate *rates);
+extern int iwl4965_alive_notify(struct iwl_priv *priv);
+extern void iwl4965_update_rate_scaling(struct iwl_priv *priv, u8 mode);
+extern void iwl4965_set_ht_add_station(struct iwl_priv *priv, u8 index);
+
+extern void iwl4965_chain_noise_reset(struct iwl_priv *priv);
+extern void iwl4965_init_sensitivity(struct iwl_priv *priv, u8 flags,
+				     u8 force);
+extern int iwl4965_set_fat_chan_info(struct iwl_priv *priv, int phymode,
+				u16 channel,
+				const struct iwl_eeprom_channel *eeprom_ch,
+				u8 fat_extension_channel);
+extern void iwl4965_rf_kill_ct_config(struct iwl_priv *priv);
+
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+extern int iwl_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da,
+				   u16 tid, u16 *start_seq_num);
+extern int iwl_mac_ht_rx_agg_start(struct ieee80211_hw *hw, u8 *da,
+				   u16 tid, u16 start_seq_num);
+extern int iwl_mac_ht_rx_agg_stop(struct ieee80211_hw *hw, u8 *da,
+				  u16 tid, int generator);
+extern int iwl_mac_ht_tx_agg_stop(struct ieee80211_hw *hw, u8 *da,
+				  u16 tid, int generator);
+extern void iwl4965_turn_off_agg(struct iwl_priv *priv, u8 tid);
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /*CONFIG_IWLWIFI_HT */
+/* Structures, enum, and defines specific to the 4965 */
+
+#define IWL4965_KW_SIZE 0x1000	/*4k */
+
+struct iwl_kw {
+	dma_addr_t dma_addr;
+	void *v_addr;
+	size_t size;
+};
+
+#define TID_QUEUE_CELL_SPACING 50	/*mS */
+#define TID_QUEUE_MAX_SIZE     20
+#define TID_ROUND_VALUE        5	/* mS */
+#define TID_MAX_LOAD_COUNT     8
+
+#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
+#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
+
+#define TID_ALL_ENABLED		0x7f
+#define TID_ALL_SPECIFIED       0xff
+#define TID_AGG_TPT_THREHOLD    0x0
+
+#define IWL_CHANNEL_WIDTH_20MHZ   0
+#define IWL_CHANNEL_WIDTH_40MHZ   1
+
+#define IWL_MIMO_PS_STATIC        0
+#define IWL_MIMO_PS_NONE          3
+#define IWL_MIMO_PS_DYNAMIC       1
+#define IWL_MIMO_PS_INVALID       2
+
+#define IWL_OPERATION_MODE_AUTO     0
+#define IWL_OPERATION_MODE_HT_ONLY  1
+#define IWL_OPERATION_MODE_MIXED    2
+#define IWL_OPERATION_MODE_20MHZ    3
+
+#define IWL_EXT_CHANNEL_OFFSET_AUTO   0
+#define IWL_EXT_CHANNEL_OFFSET_ABOVE  1
+#define IWL_EXT_CHANNEL_OFFSET_       2
+#define IWL_EXT_CHANNEL_OFFSET_BELOW  3
+#define IWL_EXT_CHANNEL_OFFSET_MAX    4
+
+#define NRG_NUM_PREV_STAT_L     20
+#define NUM_RX_CHAINS           (3)
+
+#define TX_POWER_IWL_ILLEGAL_VDET    -100000
+#define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000
+#define TX_POWER_IWL_CLOSED_LOOP_MIN_POWER 18
+#define TX_POWER_IWL_CLOSED_LOOP_MAX_POWER 34
+#define TX_POWER_IWL_VDET_SLOPE_BELOW_NOMINAL 17
+#define TX_POWER_IWL_VDET_SLOPE_ABOVE_NOMINAL 20
+#define TX_POWER_IWL_NOMINAL_POWER            26
+#define TX_POWER_IWL_CLOSED_LOOP_ITERATION_LIMIT 1
+#define TX_POWER_IWL_VOLTAGE_CODES_PER_03V       7
+#define TX_POWER_IWL_DEGREES_PER_VDET_CODE       11
+#define IWL_TX_POWER_MAX_NUM_PA_MEASUREMENTS 1
+#define IWL_TX_POWER_CCK_COMPENSATION_B_STEP (9)
+#define IWL_TX_POWER_CCK_COMPENSATION_C_STEP (5)
+
+struct iwl_traffic_load {
+	unsigned long time_stamp;
+	u32 packet_count[TID_QUEUE_MAX_SIZE];
+	u8 queue_count;
+	u8 head;
+	u32 total;
+};
+
+#ifdef CONFIG_IWLWIFI_HT_AGG
+struct iwl_agg_control {
+	unsigned long next_retry;
+	u32 wait_for_agg_status;
+	u32 tid_retry;
+	u32 requested_ba;
+	u32 granted_ba;
+	u8 auto_agg;
+	u32 tid_traffic_load_threshold;
+	u32 ba_timeout;
+	struct iwl_traffic_load traffic_load[TID_MAX_LOAD_COUNT];
+};
+#endif				/*CONFIG_IWLWIFI_HT_AGG */
+
+struct iwl_lq_mngr {
+#ifdef CONFIG_IWLWIFI_HT_AGG
+	struct iwl_agg_control agg_ctrl;
+#endif
+	spinlock_t lock;
+	s32 max_window_size;
+	s32 *expected_tpt;
+	u8 *next_higher_rate;
+	u8 *next_lower_rate;
+	unsigned long stamp;
+	unsigned long stamp_last;
+	u32 flush_time;
+	u32 tx_packets;
+	u8 lq_ready;
+};
+
+
+/* Sensitivity and chain noise calibration */
+#define INTERFERENCE_DATA_AVAILABLE	__constant_cpu_to_le32(1)
+#define INITIALIZATION_VALUE		0xFFFF
+#define CAL_NUM_OF_BEACONS		20
+#define MAXIMUM_ALLOWED_PATHLOSS	15
+
+/* Param table within SENSITIVITY_CMD */
+#define HD_MIN_ENERGY_CCK_DET_INDEX                 (0)
+#define HD_MIN_ENERGY_OFDM_DET_INDEX                (1)
+#define HD_AUTO_CORR32_X1_TH_ADD_MIN_INDEX          (2)
+#define HD_AUTO_CORR32_X1_TH_ADD_MIN_MRC_INDEX      (3)
+#define HD_AUTO_CORR40_X4_TH_ADD_MIN_MRC_INDEX      (4)
+#define HD_AUTO_CORR32_X4_TH_ADD_MIN_INDEX          (5)
+#define HD_AUTO_CORR32_X4_TH_ADD_MIN_MRC_INDEX      (6)
+#define HD_BARKER_CORR_TH_ADD_MIN_INDEX             (7)
+#define HD_BARKER_CORR_TH_ADD_MIN_MRC_INDEX         (8)
+#define HD_AUTO_CORR40_X4_TH_ADD_MIN_INDEX          (9)
+#define HD_OFDM_ENERGY_TH_IN_INDEX                  (10)
+
+#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE	__constant_cpu_to_le16(0)
+#define SENSITIVITY_CMD_CONTROL_WORK_TABLE	__constant_cpu_to_le16(1)
+
+#define CHAIN_NOISE_MAX_DELTA_GAIN_CODE 3
+
+#define MAX_FA_OFDM  50
+#define MIN_FA_OFDM  5
+#define MAX_FA_CCK   50
+#define MIN_FA_CCK   5
+
+#define NRG_MIN_CCK  97
+#define NRG_MAX_CCK  0
+
+#define AUTO_CORR_MIN_OFDM        85
+#define AUTO_CORR_MIN_OFDM_MRC    170
+#define AUTO_CORR_MIN_OFDM_X1     105
+#define AUTO_CORR_MIN_OFDM_MRC_X1 220
+#define AUTO_CORR_MAX_OFDM        120
+#define AUTO_CORR_MAX_OFDM_MRC    210
+#define AUTO_CORR_MAX_OFDM_X1     140
+#define AUTO_CORR_MAX_OFDM_MRC_X1 270
+#define AUTO_CORR_STEP_OFDM       1
+
+#define AUTO_CORR_MIN_CCK      (125)
+#define AUTO_CORR_MAX_CCK      (200)
+#define AUTO_CORR_MIN_CCK_MRC  200
+#define AUTO_CORR_MAX_CCK_MRC  400
+#define AUTO_CORR_STEP_CCK     3
+#define AUTO_CORR_MAX_TH_CCK   160
+
+#define NRG_ALG                0
+#define AUTO_CORR_ALG          1
+#define NRG_DIFF               2
+#define NRG_STEP_CCK           2
+#define NRG_MARGIN             8
+#define MAX_NUMBER_CCK_NO_FA 100
+
+#define AUTO_CORR_CCK_MIN_VAL_DEF    (125)
+
+#define CHAIN_A             0
+#define CHAIN_B             1
+#define CHAIN_C             2
+#define CHAIN_NOISE_DELTA_GAIN_INIT_VAL 4
+#define ALL_BAND_FILTER			0xFF00
+#define IN_BAND_FILTER			0xFF
+#define MIN_AVERAGE_NOISE_MAX_VALUE	0xFFFFFFFF
+
+enum iwl_false_alarm_state {
+	IWL_FA_TOO_MANY = 0,
+	IWL_FA_TOO_FEW = 1,
+	IWL_FA_GOOD_RANGE = 2,
+};
+
+enum iwl_chain_noise_state {
+	IWL_CHAIN_NOISE_ALIVE = 0,  /* must be 0 */
+	IWL_CHAIN_NOISE_ACCUMULATE = 1,
+	IWL_CHAIN_NOISE_CALIBRATED = 2,
+};
+
+enum iwl_sensitivity_state {
+	IWL_SENS_CALIB_ALLOWED = 0,
+	IWL_SENS_CALIB_NEED_REINIT = 1,
+};
+
+enum iwl_calib_enabled_state {
+	IWL_CALIB_DISABLED = 0,  /* must be 0 */
+	IWL_CALIB_ENABLED = 1,
+};
+
+struct statistics_general_data {
+	u32 beacon_silence_rssi_a;
+	u32 beacon_silence_rssi_b;
+	u32 beacon_silence_rssi_c;
+	u32 beacon_energy_a;
+	u32 beacon_energy_b;
+	u32 beacon_energy_c;
+};
+
+/* Sensitivity calib data */
+struct iwl_sensitivity_data {
+	u32 auto_corr_ofdm;
+	u32 auto_corr_ofdm_mrc;
+	u32 auto_corr_ofdm_x1;
+	u32 auto_corr_ofdm_mrc_x1;
+	u32 auto_corr_cck;
+	u32 auto_corr_cck_mrc;
+
+	u32 last_bad_plcp_cnt_ofdm;
+	u32 last_fa_cnt_ofdm;
+	u32 last_bad_plcp_cnt_cck;
+	u32 last_fa_cnt_cck;
+
+	u32 nrg_curr_state;
+	u32 nrg_prev_state;
+	u32 nrg_value[10];
+	u8  nrg_silence_rssi[NRG_NUM_PREV_STAT_L];
+	u32 nrg_silence_ref;
+	u32 nrg_energy_idx;
+	u32 nrg_silence_idx;
+	u32 nrg_th_cck;
+	s32 nrg_auto_corr_silence_diff;
+	u32 num_in_cck_no_fa;
+	u32 nrg_th_ofdm;
+
+	u8 state;
+};
+
+/* Chain noise (differential Rx gain) calib data */
+struct iwl_chain_noise_data {
+	u8 state;
+	u16 beacon_count;
+	u32 chain_noise_a;
+	u32 chain_noise_b;
+	u32 chain_noise_c;
+	u32 chain_signal_a;
+	u32 chain_signal_b;
+	u32 chain_signal_c;
+	u8 disconn_array[NUM_RX_CHAINS];
+	u8 delta_gain_code[NUM_RX_CHAINS];
+	u8 radio_write;
+};
+
+/* IWL4965 */
+#define RATE_MCS_CODE_MSK 0x7
+#define RATE_MCS_MIMO_POS 3
+#define RATE_MCS_MIMO_MSK 0x8
+#define RATE_MCS_HT_DUP_POS 5
+#define RATE_MCS_HT_DUP_MSK 0x20
+#define RATE_MCS_FLAGS_POS 8
+#define RATE_MCS_HT_POS 8
+#define RATE_MCS_HT_MSK 0x100
+#define RATE_MCS_CCK_POS 9
+#define RATE_MCS_CCK_MSK 0x200
+#define RATE_MCS_GF_POS 10
+#define RATE_MCS_GF_MSK 0x400
+
+#define RATE_MCS_FAT_POS 11
+#define RATE_MCS_FAT_MSK 0x800
+#define RATE_MCS_DUP_POS 12
+#define RATE_MCS_DUP_MSK 0x1000
+#define RATE_MCS_SGI_POS 13
+#define RATE_MCS_SGI_MSK 0x2000
+
+#define	EEPROM_SEM_TIMEOUT 10
+#define EEPROM_SEM_RETRY_LIMIT 1000
+
+#endif				/* __iwl_4965_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-channel.h b/drivers/net/wireless/iwlwifi/iwl-channel.h
new file mode 100644
index 0000000..023c3f2
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-channel.h
@@ -0,0 +1,161 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#ifndef __iwl_channel_h__
+#define __iwl_channel_h__
+
+#define IWL_NUM_SCAN_RATES         (2)
+
+struct iwl_channel_tgd_info {
+	u8 type;
+	s8 max_power;
+};
+
+struct iwl_channel_tgh_info {
+	s64 last_radar_time;
+};
+
+/* current Tx power values to use, one for each rate for each channel.
+ * requested power is limited by:
+ * -- regulatory EEPROM limits for this channel
+ * -- hardware capabilities (clip-powers)
+ * -- spectrum management
+ * -- user preference (e.g. iwconfig)
+ * when requested power is set, base power index must also be set. */
+struct iwl_channel_power_info {
+	struct iwl_tx_power tpc;	/* actual radio and DSP gain settings */
+	s8 power_table_index;	/* actual (compenst'd) index into gain table */
+	s8 base_power_index;	/* gain index for power at factory temp. */
+	s8 requested_power;	/* power (dBm) requested for this chnl/rate */
+};
+
+/* current scan Tx power values to use, one for each scan rate for each
+ * channel. */
+struct iwl_scan_power_info {
+	struct iwl_tx_power tpc;	/* actual radio and DSP gain settings */
+	s8 power_table_index;	/* actual (compenst'd) index into gain table */
+	s8 requested_power;	/* scan pwr (dBm) requested for chnl/rate */
+};
+
+/* Channel unlock period is 15 seconds. If no beacon or probe response
+ * has been received within 15 seconds on a locked channel then the channel
+ * remains locked. */
+#define TX_UNLOCK_PERIOD 15
+
+/* CSA lock period is 15 seconds.  If a CSA has been received on a channel in
+ * the last 15 seconds, the channel is locked */
+#define CSA_LOCK_PERIOD 15
+/*
+ * One for each channel, holds all channel setup data
+ * Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant
+ *     with one another!
+ */
+#define IWL4965_MAX_RATE (33)
+
+struct iwl_channel_info {
+	struct iwl_channel_tgd_info tgd;
+	struct iwl_channel_tgh_info tgh;
+	struct iwl_eeprom_channel eeprom;	/* EEPROM regulatory limit */
+	struct iwl_eeprom_channel fat_eeprom;	/* EEPROM regulatory limit for
+						 * FAT channel */
+
+	u8 channel;	  /* channel number */
+	u8 flags;	  /* flags copied from EEPROM */
+	s8 max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
+	s8 curr_txpow;	  /* (dBm) regulatory/spectrum/user (not h/w) */
+	s8 min_power;	  /* always 0 */
+	s8 scan_power;	  /* (dBm) regul. eeprom, direct scans, any rate */
+
+	u8 group_index;	  /* 0-4, maps channel to group1/2/3/4/5 */
+	u8 band_index;	  /* 0-4, maps channel to band1/2/3/4/5 */
+	u8 phymode;	  /* MODE_IEEE80211{A,B,G} */
+
+	/* Radio/DSP gain settings for each "normal" data Tx rate.
+	 * These include, in addition to RF and DSP gain, a few fields for
+	 *   remembering/modifying gain settings (indexes). */
+	struct iwl_channel_power_info power_info[IWL4965_MAX_RATE];
+
+#if IWL == 4965
+	/* FAT channel info */
+	s8 fat_max_power_avg;	/* (dBm) regul. eeprom, normal Tx, any rate */
+	s8 fat_curr_txpow;	/* (dBm) regulatory/spectrum/user (not h/w) */
+	s8 fat_min_power;	/* always 0 */
+	s8 fat_scan_power;	/* (dBm) eeprom, direct scans, any rate */
+	u8 fat_flags;		/* flags copied from EEPROM */
+	u8 fat_extension_channel;
+#endif
+
+	/* Radio/DSP gain settings for each scan rate, for directed scans. */
+	struct iwl_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES];
+};
+
+struct iwl_clip_group {
+	/* maximum power level to prevent clipping for each rate, derived by
+	 *   us from this band's saturation power in EEPROM */
+	const s8 clip_powers[IWL_MAX_RATES];
+};
+
+static inline int is_channel_valid(const struct iwl_channel_info *ch_info)
+{
+	if (ch_info == NULL)
+		return 0;
+	return (ch_info->flags & EEPROM_CHANNEL_VALID) ? 1 : 0;
+}
+
+static inline int is_channel_narrow(const struct iwl_channel_info *ch_info)
+{
+	return (ch_info->flags & EEPROM_CHANNEL_NARROW) ? 1 : 0;
+}
+
+static inline int is_channel_radar(const struct iwl_channel_info *ch_info)
+{
+	return (ch_info->flags & EEPROM_CHANNEL_RADAR) ? 1 : 0;
+}
+
+static inline u8 is_channel_a_band(const struct iwl_channel_info *ch_info)
+{
+	return ch_info->phymode == MODE_IEEE80211A;
+}
+
+static inline u8 is_channel_bg_band(const struct iwl_channel_info *ch_info)
+{
+	return ((ch_info->phymode == MODE_IEEE80211B) ||
+		(ch_info->phymode == MODE_IEEE80211G));
+}
+
+static inline int is_channel_passive(const struct iwl_channel_info *ch)
+{
+	return (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) ? 1 : 0;
+}
+
+static inline int is_channel_ibss(const struct iwl_channel_info *ch)
+{
+	return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0;
+}
+
+extern const struct iwl_channel_info *iwl_get_channel_info(
+	const struct iwl_priv *priv, int phymode, u16 channel);
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
new file mode 100644
index 0000000..9de8d7f
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -0,0 +1,1734 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_commands_h__
+#define __iwl_commands_h__
+
+enum {
+	REPLY_ALIVE = 0x1,
+	REPLY_ERROR = 0x2,
+
+	/* RXON and QOS commands */
+	REPLY_RXON = 0x10,
+	REPLY_RXON_ASSOC = 0x11,
+	REPLY_QOS_PARAM = 0x13,
+	REPLY_RXON_TIMING = 0x14,
+
+	/* Multi-Station support */
+	REPLY_ADD_STA = 0x18,
+	REPLY_REMOVE_STA = 0x19,	/* not used */
+	REPLY_REMOVE_ALL_STA = 0x1a,	/* not used */
+
+	/* RX, TX, LEDs */
+#if IWL == 3945
+	REPLY_3945_RX = 0x1b,		/* 3945 only */
+#endif
+	REPLY_TX = 0x1c,
+	REPLY_RATE_SCALE = 0x47,	/* 3945 only */
+	REPLY_LEDS_CMD = 0x48,
+	REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* 4965 only */
+
+	/* 802.11h related */
+	RADAR_NOTIFICATION = 0x70,	/* not used */
+	REPLY_QUIET_CMD = 0x71,		/* not used */
+	REPLY_CHANNEL_SWITCH = 0x72,
+	CHANNEL_SWITCH_NOTIFICATION = 0x73,
+	REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74,
+	SPECTRUM_MEASURE_NOTIFICATION = 0x75,
+
+	/* Power Management */
+	POWER_TABLE_CMD = 0x77,
+	PM_SLEEP_NOTIFICATION = 0x7A,
+	PM_DEBUG_STATISTIC_NOTIFIC = 0x7B,
+
+	/* Scan commands and notifications */
+	REPLY_SCAN_CMD = 0x80,
+	REPLY_SCAN_ABORT_CMD = 0x81,
+	SCAN_START_NOTIFICATION = 0x82,
+	SCAN_RESULTS_NOTIFICATION = 0x83,
+	SCAN_COMPLETE_NOTIFICATION = 0x84,
+
+	/* IBSS/AP commands */
+	BEACON_NOTIFICATION = 0x90,
+	REPLY_TX_BEACON = 0x91,
+	WHO_IS_AWAKE_NOTIFICATION = 0x94,	/* not used */
+
+	/* Miscellaneous commands */
+	QUIET_NOTIFICATION = 0x96,		/* not used */
+	REPLY_TX_PWR_TABLE_CMD = 0x97,
+	MEASURE_ABORT_NOTIFICATION = 0x99,	/* not used */
+
+	/* BT config command */
+	REPLY_BT_CONFIG = 0x9b,
+
+	/* 4965 Statistics */
+	REPLY_STATISTICS_CMD = 0x9c,
+	STATISTICS_NOTIFICATION = 0x9d,
+
+	/* RF-KILL commands and notifications */
+	REPLY_CARD_STATE_CMD = 0xa0,
+	CARD_STATE_NOTIFICATION = 0xa1,
+
+	/* Missed beacons notification */
+	MISSED_BEACONS_NOTIFICATION = 0xa2,
+
+#if IWL == 4965
+	REPLY_CT_KILL_CONFIG_CMD = 0xa4,
+	SENSITIVITY_CMD = 0xa8,
+	REPLY_PHY_CALIBRATION_CMD = 0xb0,
+	REPLY_RX_PHY_CMD = 0xc0,
+	REPLY_RX_MPDU_CMD = 0xc1,
+	REPLY_4965_RX = 0xc3,
+	REPLY_COMPRESSED_BA = 0xc5,
+#endif
+	REPLY_MAX = 0xff
+};
+
+/******************************************************************************
+ * (0)
+ * Header
+ *
+ *****************************************************************************/
+
+#define IWL_CMD_FAILED_MSK 0x40
+
+struct iwl_cmd_header {
+	u8 cmd;
+	u8 flags;
+	/* We have 15 LSB to use as we please (MSB indicates
+	 * a frame Rx'd from the HW).  We encode the following
+	 * information into the sequence field:
+	 *
+	 *  0:7    index in fifo
+	 *  8:13   fifo selection
+	 * 14:14   bit indicating if this packet references the 'extra'
+	 *         storage at the end of the memory queue
+	 * 15:15   (Rx indication)
+	 *
+	 */
+	__le16 sequence;
+
+	/* command data follows immediately */
+	u8 data[0];
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (0a)
+ * Alive and Error Commands & Responses:
+ *
+ *****************************************************************************/
+
+#define UCODE_VALID_OK	__constant_cpu_to_le32(0x1)
+#define INITIALIZE_SUBTYPE    (9)
+
+/*
+ * REPLY_ALIVE = 0x1 (response only, not a command)
+ */
+struct iwl_alive_resp {
+	u8 ucode_minor;
+	u8 ucode_major;
+	__le16 reserved1;
+	u8 sw_rev[8];
+	u8 ver_type;
+	u8 ver_subtype;
+	__le16 reserved2;
+	__le32 log_event_table_ptr;
+	__le32 error_event_table_ptr;
+	__le32 timestamp;
+	__le32 is_valid;
+} __attribute__ ((packed));
+
+struct iwl_init_alive_resp {
+	u8 ucode_minor;
+	u8 ucode_major;
+	__le16 reserved1;
+	u8 sw_rev[8];
+	u8 ver_type;
+	u8 ver_subtype;
+	__le16 reserved2;
+	__le32 log_event_table_ptr;
+	__le32 error_event_table_ptr;
+	__le32 timestamp;
+	__le32 is_valid;
+
+#if IWL == 4965
+	/* calibration values from "initialize" uCode */
+	__le32 voltage;		/* signed */
+	__le32 therm_r1[2];	/* signed 1st for normal, 2nd for FAT channel */
+	__le32 therm_r2[2];	/* signed */
+	__le32 therm_r3[2];	/* signed */
+	__le32 therm_r4[2];	/* signed */
+	__le32 tx_atten[5][2];	/* signed MIMO gain comp, 5 freq groups,
+				 * 2 Tx chains */
+#endif
+} __attribute__ ((packed));
+
+union tsf {
+	u8 byte[8];
+	__le16 word[4];
+	__le32 dw[2];
+};
+
+/*
+ * REPLY_ERROR = 0x2 (response only, not a command)
+ */
+struct iwl_error_resp {
+	__le32 error_type;
+	u8 cmd_id;
+	u8 reserved1;
+	__le16 bad_cmd_seq_num;
+#if IWL == 3945
+	__le16 reserved2;
+#endif
+	__le32 error_info;
+	union tsf timestamp;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (1)
+ * RXON Commands & Responses:
+ *
+ *****************************************************************************/
+
+/*
+ * Rx config defines & structure
+ */
+/* rx_config device types  */
+enum {
+	RXON_DEV_TYPE_AP = 1,
+	RXON_DEV_TYPE_ESS = 3,
+	RXON_DEV_TYPE_IBSS = 4,
+	RXON_DEV_TYPE_SNIFFER = 6,
+};
+
+/* rx_config flags */
+/* band & modulation selection */
+#define RXON_FLG_BAND_24G_MSK           __constant_cpu_to_le32(1 << 0)
+#define RXON_FLG_CCK_MSK                __constant_cpu_to_le32(1 << 1)
+/* auto detection enable */
+#define RXON_FLG_AUTO_DETECT_MSK        __constant_cpu_to_le32(1 << 2)
+/* TGg protection when tx */
+#define RXON_FLG_TGG_PROTECT_MSK        __constant_cpu_to_le32(1 << 3)
+/* cck short slot & preamble */
+#define RXON_FLG_SHORT_SLOT_MSK          __constant_cpu_to_le32(1 << 4)
+#define RXON_FLG_SHORT_PREAMBLE_MSK     __constant_cpu_to_le32(1 << 5)
+/* antenna selection */
+#define RXON_FLG_DIS_DIV_MSK            __constant_cpu_to_le32(1 << 7)
+#define RXON_FLG_ANT_SEL_MSK            __constant_cpu_to_le32(0x0f00)
+#define RXON_FLG_ANT_A_MSK              __constant_cpu_to_le32(1 << 8)
+#define RXON_FLG_ANT_B_MSK              __constant_cpu_to_le32(1 << 9)
+/* radar detection enable */
+#define RXON_FLG_RADAR_DETECT_MSK       __constant_cpu_to_le32(1 << 12)
+#define RXON_FLG_TGJ_NARROW_BAND_MSK    __constant_cpu_to_le32(1 << 13)
+/* rx response to host with 8-byte TSF
+* (according to ON_AIR deassertion) */
+#define RXON_FLG_TSF2HOST_MSK           __constant_cpu_to_le32(1 << 15)
+
+/* rx_config filter flags */
+/* accept all data frames */
+#define RXON_FILTER_PROMISC_MSK         __constant_cpu_to_le32(1 << 0)
+/* pass control & management to host */
+#define RXON_FILTER_CTL2HOST_MSK        __constant_cpu_to_le32(1 << 1)
+/* accept multi-cast */
+#define RXON_FILTER_ACCEPT_GRP_MSK      __constant_cpu_to_le32(1 << 2)
+/* don't decrypt uni-cast frames */
+#define RXON_FILTER_DIS_DECRYPT_MSK     __constant_cpu_to_le32(1 << 3)
+/* don't decrypt multi-cast frames */
+#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4)
+/* STA is associated */
+#define RXON_FILTER_ASSOC_MSK           __constant_cpu_to_le32(1 << 5)
+/* transfer to host non bssid beacons in associated state */
+#define RXON_FILTER_BCON_AWARE_MSK      __constant_cpu_to_le32(1 << 6)
+
+/*
+ * REPLY_RXON = 0x10 (command, has simple generic response)
+ */
+struct iwl_rxon_cmd {
+	u8 node_addr[6];
+	__le16 reserved1;
+	u8 bssid_addr[6];
+	__le16 reserved2;
+	u8 wlap_bssid_addr[6];
+	__le16 reserved3;
+	u8 dev_type;
+	u8 air_propagation;
+#if IWL == 3945
+	__le16 reserved4;
+#elif IWL == 4965
+	__le16 rx_chain;
+#endif
+	u8 ofdm_basic_rates;
+	u8 cck_basic_rates;
+	__le16 assoc_id;
+	__le32 flags;
+	__le32 filter_flags;
+	__le16 channel;
+#if IWL == 3945
+	__le16 reserved5;
+#elif IWL == 4965
+	u8 ofdm_ht_single_stream_basic_rates;
+	u8 ofdm_ht_dual_stream_basic_rates;
+#endif
+} __attribute__ ((packed));
+
+/*
+ * REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
+ */
+struct iwl_rxon_assoc_cmd {
+	__le32 flags;
+	__le32 filter_flags;
+	u8 ofdm_basic_rates;
+	u8 cck_basic_rates;
+#if IWL == 4965
+	u8 ofdm_ht_single_stream_basic_rates;
+	u8 ofdm_ht_dual_stream_basic_rates;
+	__le16 rx_chain_select_flags;
+#endif
+	__le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_RXON_TIMING = 0x14 (command, has simple generic response)
+ */
+struct iwl_rxon_time_cmd {
+	union tsf timestamp;
+	__le16 beacon_interval;
+	__le16 atim_window;
+	__le32 beacon_init_val;
+	__le16 listen_interval;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+struct iwl_tx_power {
+	u8 tx_gain;		/* gain for analog radio */
+	u8 dsp_atten;		/* gain for DSP */
+} __attribute__ ((packed));
+
+#if IWL == 3945
+struct iwl_power_per_rate {
+	u8 rate;		/* plcp */
+	struct iwl_tx_power tpc;
+	u8 reserved;
+} __attribute__ ((packed));
+
+#elif IWL == 4965
+#define POWER_TABLE_NUM_ENTRIES			33
+#define POWER_TABLE_NUM_HT_OFDM_ENTRIES		32
+#define POWER_TABLE_CCK_ENTRY			32
+struct tx_power_dual_stream {
+	__le32 dw;
+} __attribute__ ((packed));
+
+struct iwl_tx_power_db {
+	struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES];
+} __attribute__ ((packed));
+#endif
+
+/*
+ * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
+ */
+struct iwl_channel_switch_cmd {
+	u8 band;
+	u8 expect_beacon;
+	__le16 channel;
+	__le32 rxon_flags;
+	__le32 rxon_filter_flags;
+	__le32 switch_time;
+#if IWL == 3945
+	struct iwl_power_per_rate power[IWL_MAX_RATES];
+#elif IWL == 4965
+	struct iwl_tx_power_db tx_power;
+#endif
+} __attribute__ ((packed));
+
+/*
+ * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
+ */
+struct iwl_csa_notification {
+	__le16 band;
+	__le16 channel;
+	__le32 status;		/* 0 - OK, 1 - fail */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (2)
+ * Quality-of-Service (QOS) Commands & Responses:
+ *
+ *****************************************************************************/
+struct iwl_ac_qos {
+	__le16 cw_min;
+	__le16 cw_max;
+	u8 aifsn;
+	u8 reserved1;
+	__le16 edca_txop;
+} __attribute__ ((packed));
+
+/* QoS flags defines */
+#define QOS_PARAM_FLG_UPDATE_EDCA_MSK	__constant_cpu_to_le32(0x01)
+#define QOS_PARAM_FLG_TGN_MSK		__constant_cpu_to_le32(0x02)
+#define QOS_PARAM_FLG_TXOP_TYPE_MSK	__constant_cpu_to_le32(0x10)
+
+/*
+ *  TXFIFO Queue number defines
+ */
+/* number of Access categories (AC) (EDCA), queues 0..3 */
+#define AC_NUM                4
+
+/*
+ * REPLY_QOS_PARAM = 0x13 (command, has simple generic response)
+ */
+struct iwl_qosparam_cmd {
+	__le32 qos_flags;
+	struct iwl_ac_qos ac[AC_NUM];
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (3)
+ * Add/Modify Stations Commands & Responses:
+ *
+ *****************************************************************************/
+/*
+ * Multi station support
+ */
+#define	IWL_AP_ID		0
+#define IWL_MULTICAST_ID	1
+#define	IWL_STA_ID		2
+
+#define	IWL3945_BROADCAST_ID	24
+#define IWL3945_STATION_COUNT	25
+
+#define IWL4965_BROADCAST_ID	31
+#define	IWL4965_STATION_COUNT	32
+
+#define	IWL_STATION_COUNT	32 	/* MAX(3945,4965)*/
+#define	IWL_INVALID_STATION 	255
+
+#if IWL == 3945
+#define STA_FLG_TX_RATE_MSK		__constant_cpu_to_le32(1<<2);
+#endif
+#define STA_FLG_PWR_SAVE_MSK		__constant_cpu_to_le32(1<<8);
+
+#define STA_CONTROL_MODIFY_MSK		0x01
+
+/* key flags __le16*/
+#define STA_KEY_FLG_ENCRYPT_MSK	__constant_cpu_to_le16(0x7)
+#define STA_KEY_FLG_NO_ENC	__constant_cpu_to_le16(0x0)
+#define STA_KEY_FLG_WEP		__constant_cpu_to_le16(0x1)
+#define STA_KEY_FLG_CCMP	__constant_cpu_to_le16(0x2)
+#define STA_KEY_FLG_TKIP	__constant_cpu_to_le16(0x3)
+
+#define STA_KEY_FLG_KEYID_POS	8
+#define STA_KEY_FLG_INVALID 	__constant_cpu_to_le16(0x0800)
+
+/* modify flags  */
+#define	STA_MODIFY_KEY_MASK		0x01
+#define	STA_MODIFY_TID_DISABLE_TX	0x02
+#define	STA_MODIFY_TX_RATE_MSK		0x04
+#define STA_MODIFY_ADDBA_TID_MSK	0x08
+#define STA_MODIFY_DELBA_TID_MSK	0x10
+#define BUILD_RAxTID(sta_id, tid)	(((sta_id) << 4) + (tid))
+
+/*
+ * Antenna masks:
+ * bit14:15 01 B inactive, A active
+ *          10 B active, A inactive
+ *          11 Both active
+ */
+#define RATE_MCS_ANT_A_POS	14
+#define RATE_MCS_ANT_B_POS	15
+#define RATE_MCS_ANT_A_MSK	0x4000
+#define RATE_MCS_ANT_B_MSK	0x8000
+#define RATE_MCS_ANT_AB_MSK	0xc000
+
+struct iwl_keyinfo {
+	__le16 key_flags;
+	u8 tkip_rx_tsc_byte2;	/* TSC[2] for key mix ph1 detection */
+	u8 reserved1;
+	__le16 tkip_rx_ttak[5];	/* 10-byte unicast TKIP TTAK */
+	__le16 reserved2;
+	u8 key[16];		/* 16-byte unicast decryption key */
+} __attribute__ ((packed));
+
+struct sta_id_modify {
+	u8 addr[ETH_ALEN];
+	__le16 reserved1;
+	u8 sta_id;
+	u8 modify_mask;
+	__le16 reserved2;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_ADD_STA = 0x18 (command)
+ */
+struct iwl_addsta_cmd {
+	u8 mode;
+	u8 reserved[3];
+	struct sta_id_modify sta;
+	struct iwl_keyinfo key;
+	__le32 station_flags;
+	__le32 station_flags_msk;
+	__le16 tid_disable_tx;
+#if IWL == 3945
+	__le16 rate_n_flags;
+#else
+	__le16	reserved1;
+#endif
+	u8 add_immediate_ba_tid;
+	u8 remove_immediate_ba_tid;
+	__le16 add_immediate_ba_ssn;
+#if IWL == 4965
+	__le32 reserved2;
+#endif
+} __attribute__ ((packed));
+
+/*
+ * REPLY_ADD_STA = 0x18 (response)
+ */
+struct iwl_add_sta_resp {
+	u8 status;
+} __attribute__ ((packed));
+
+#define ADD_STA_SUCCESS_MSK              0x1
+
+/******************************************************************************
+ * (4)
+ * Rx Responses:
+ *
+ *****************************************************************************/
+
+struct iwl_rx_frame_stats {
+	u8 phy_count;
+	u8 id;
+	u8 rssi;
+	u8 agc;
+	__le16 sig_avg;
+	__le16 noise_diff;
+	u8 payload[0];
+} __attribute__ ((packed));
+
+struct iwl_rx_frame_hdr {
+	__le16 channel;
+	__le16 phy_flags;
+	u8 reserved1;
+	u8 rate;
+	__le16 len;
+	u8 payload[0];
+} __attribute__ ((packed));
+
+#define	RX_RES_STATUS_NO_CRC32_ERROR	__constant_cpu_to_le32(1 << 0)
+#define	RX_RES_STATUS_NO_RXE_OVERFLOW	__constant_cpu_to_le32(1 << 1)
+
+#define	RX_RES_PHY_FLAGS_BAND_24_MSK	__constant_cpu_to_le16(1 << 0)
+#define	RX_RES_PHY_FLAGS_MOD_CCK_MSK		__constant_cpu_to_le16(1 << 1)
+#define	RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK	__constant_cpu_to_le16(1 << 2)
+#define	RX_RES_PHY_FLAGS_NARROW_BAND_MSK	__constant_cpu_to_le16(1 << 3)
+#define	RX_RES_PHY_FLAGS_ANTENNA_MSK		__constant_cpu_to_le16(0xf0)
+
+#define	RX_RES_STATUS_SEC_TYPE_MSK	(0x7 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_NONE	(0x0 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_WEP	(0x1 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_CCMP	(0x2 << 8)
+#define	RX_RES_STATUS_SEC_TYPE_TKIP	(0x3 << 8)
+
+#define	RX_RES_STATUS_DECRYPT_TYPE_MSK	(0x3 << 11)
+#define	RX_RES_STATUS_NOT_DECRYPT	(0x0 << 11)
+#define	RX_RES_STATUS_DECRYPT_OK	(0x3 << 11)
+#define	RX_RES_STATUS_BAD_ICV_MIC	(0x1 << 11)
+#define	RX_RES_STATUS_BAD_KEY_TTAK	(0x2 << 11)
+
+struct iwl_rx_frame_end {
+	__le32 status;
+	__le64 timestamp;
+	__le32 beacon_timestamp;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_3945_RX = 0x1b (response only, not a command)
+ *
+ * NOTE:  DO NOT dereference from casts to this structure
+ * It is provided only for calculating minimum data set size.
+ * The actual offsets of the hdr and end are dynamic based on
+ * stats.phy_count
+ */
+struct iwl_rx_frame {
+	struct iwl_rx_frame_stats stats;
+	struct iwl_rx_frame_hdr hdr;
+	struct iwl_rx_frame_end end;
+} __attribute__ ((packed));
+
+/* Fixed (non-configurable) rx data from phy */
+#define RX_PHY_FLAGS_ANTENNAE_OFFSET		(4)
+#define RX_PHY_FLAGS_ANTENNAE_MASK		(0x70)
+#define IWL_AGC_DB_MASK 	(0x3f80)	/* MASK(7,13) */
+#define IWL_AGC_DB_POS		(7)
+struct iwl4965_rx_non_cfg_phy {
+	__le16 ant_selection;	/* ant A bit 4, ant B bit 5, ant C bit 6 */
+	__le16 agc_info;	/* agc code 0:6, agc dB 7:13, reserved 14:15 */
+	u8 rssi_info[6];	/* we use even entries, 0/2/4 for A/B/C rssi */
+	u8 pad[0];
+} __attribute__ ((packed));
+
+/*
+ * REPLY_4965_RX = 0xc3 (response only, not a command)
+ * Used only for legacy (non 11n) frames.
+ */
+#define RX_RES_PHY_CNT 14
+struct iwl4965_rx_phy_res {
+	u8 non_cfg_phy_cnt;     /* non configurable DSP phy data byte count */
+	u8 cfg_phy_cnt;		/* configurable DSP phy data byte count */
+	u8 stat_id;		/* configurable DSP phy data set ID */
+	u8 reserved1;
+	__le64 timestamp;	/* TSF at on air rise */
+	__le32 beacon_time_stamp; /* beacon at on-air rise */
+	__le16 phy_flags;	/* general phy flags: band, modulation, ... */
+	__le16 channel;		/* channel number */
+	__le16 non_cfg_phy[RX_RES_PHY_CNT];	/* upto 14 phy entries */
+	__le32 reserved2;
+	__le32 rate_n_flags;
+	__le16 byte_count;		/* frame's byte-count */
+	__le16 reserved3;
+} __attribute__ ((packed));
+
+struct iwl4965_rx_mpdu_res_start {
+	__le16 byte_count;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (5)
+ * Tx Commands & Responses:
+ *
+ *****************************************************************************/
+
+/* Tx flags */
+#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1)
+#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2)
+#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3)
+#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4)
+#define TX_CMD_FLG_IMM_BA_RSP_MASK  __constant_cpu_to_le32(1 << 6)
+#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7)
+#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00)
+#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8)
+#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9)
+
+/* ucode ignores BT priority for this frame */
+#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12)
+
+/* ucode overrides sequence control */
+#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13)
+
+/* signal that this frame is non-last MPDU */
+#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14)
+
+/* calculate TSF in outgoing frame */
+#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16)
+
+/* activate TX calibration. */
+#define TX_CMD_FLG_CALIB_MSK __constant_cpu_to_le32(1 << 17)
+
+/* signals that 2 bytes pad was inserted
+   after the MAC header */
+#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20)
+
+/* HCCA-AP - disable duration overwriting. */
+#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25)
+
+/*
+ * TX command security control
+ */
+#define TX_CMD_SEC_WEP  	0x01
+#define TX_CMD_SEC_CCM  	0x02
+#define TX_CMD_SEC_TKIP		0x03
+#define TX_CMD_SEC_MSK		0x03
+#define TX_CMD_SEC_SHIFT	6
+#define TX_CMD_SEC_KEY128	0x08
+
+/*
+ * TX command Frame life time
+ */
+
+struct iwl_dram_scratch {
+	u8 try_cnt;
+	u8 bt_kill_cnt;
+	__le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX = 0x1c (command)
+ */
+struct iwl_tx_cmd {
+	__le16 len;
+	__le16 next_frame_len;
+	__le32 tx_flags;
+#if IWL == 3945
+	u8 rate;
+	u8 sta_id;
+	u8 tid_tspec;
+#elif IWL == 4965
+	struct iwl_dram_scratch scratch;
+	__le32 rate_n_flags;
+	u8 sta_id;
+#endif
+	u8 sec_ctl;
+#if IWL == 4965
+	u8 initial_rate_index;
+	u8 reserved;
+#endif
+	u8 key[16];
+#if IWL == 3945
+	union {
+		u8 byte[8];
+		__le16 word[4];
+		__le32 dw[2];
+	} tkip_mic;
+	__le32 next_frame_info;
+#elif IWL == 4965
+	__le16 next_frame_flags;
+	__le16 reserved2;
+#endif
+	union {
+		__le32 life_time;
+		__le32 attempt;
+	} stop_time;
+#if IWL == 3945
+	u8 supp_rates[2];
+#elif IWL == 4965
+	__le32 dram_lsb_ptr;
+	u8 dram_msb_ptr;
+#endif
+	u8 rts_retry_limit;	/*byte 50 */
+	u8 data_retry_limit;	/*byte 51 */
+#if IWL == 4965
+	u8 tid_tspec;
+#endif
+	union {
+		__le16 pm_frame_timeout;
+		__le16 attempt_duration;
+	} timeout;
+	__le16 driver_txop;
+	u8 payload[0];
+	struct ieee80211_hdr hdr[0];
+} __attribute__ ((packed));
+
+/* TX command response is sent after *all* transmission attempts.
+ *
+ * NOTES:
+ *
+ * TX_STATUS_FAIL_NEXT_FRAG
+ *
+ * If the fragment flag in the MAC header for the frame being transmitted
+ * is set and there is insufficient time to transmit the next frame, the
+ * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'.
+ *
+ * TX_STATUS_FIFO_UNDERRUN
+ *
+ * Indicates the host did not provide bytes to the FIFO fast enough while
+ * a TX was in progress.
+ *
+ * TX_STATUS_FAIL_MGMNT_ABORT
+ *
+ * This status is only possible if the ABORT ON MGMT RX parameter was
+ * set to true with the TX command.
+ *
+ * If the MSB of the status parameter is set then an abort sequence is
+ * required.  This sequence consists of the host activating the TX Abort
+ * control line, and then waiting for the TX Abort command response.  This
+ * indicates that a the device is no longer in a transmit state, and that the
+ * command FIFO has been cleared.  The host must then deactivate the TX Abort
+ * control line.  Receiving is still allowed in this case.
+ */
+enum {
+	TX_STATUS_SUCCESS = 0x01,
+	TX_STATUS_DIRECT_DONE = 0x02,
+	TX_STATUS_FAIL_SHORT_LIMIT = 0x82,
+	TX_STATUS_FAIL_LONG_LIMIT = 0x83,
+	TX_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
+	TX_STATUS_FAIL_MGMNT_ABORT = 0x85,
+	TX_STATUS_FAIL_NEXT_FRAG = 0x86,
+	TX_STATUS_FAIL_LIFE_EXPIRE = 0x87,
+	TX_STATUS_FAIL_DEST_PS = 0x88,
+	TX_STATUS_FAIL_ABORTED = 0x89,
+	TX_STATUS_FAIL_BT_RETRY = 0x8a,
+	TX_STATUS_FAIL_STA_INVALID = 0x8b,
+	TX_STATUS_FAIL_FRAG_DROPPED = 0x8c,
+	TX_STATUS_FAIL_TID_DISABLE = 0x8d,
+	TX_STATUS_FAIL_FRAME_FLUSHED = 0x8e,
+	TX_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
+	TX_STATUS_FAIL_TX_LOCKED = 0x90,
+	TX_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
+};
+
+#define	TX_PACKET_MODE_REGULAR		0x0000
+#define	TX_PACKET_MODE_BURST_SEQ	0x0100
+#define	TX_PACKET_MODE_BURST_FIRST	0x0200
+
+enum {
+	TX_POWER_PA_NOT_ACTIVE = 0x0,
+};
+
+enum {
+	TX_STATUS_MSK = 0x000000ff,	/* bits 0:7 */
+	TX_STATUS_DELAY_MSK = 0x00000040,
+	TX_STATUS_ABORT_MSK = 0x00000080,
+	TX_PACKET_MODE_MSK = 0x0000ff00,	/* bits 8:15 */
+	TX_FIFO_NUMBER_MSK = 0x00070000,	/* bits 16:18 */
+	TX_RESERVED = 0x00780000,	/* bits 19:22 */
+	TX_POWER_PA_DETECT_MSK = 0x7f800000,	/* bits 23:30 */
+	TX_ABORT_REQUIRED_MSK = 0x80000000,	/* bits 31:31 */
+};
+
+/* *******************************
+ * TX aggregation state
+ ******************************* */
+
+enum {
+	AGG_TX_STATE_TRANSMITTED = 0x00,
+	AGG_TX_STATE_UNDERRUN_MSK = 0x01,
+	AGG_TX_STATE_BT_PRIO_MSK = 0x02,
+	AGG_TX_STATE_FEW_BYTES_MSK = 0x04,
+	AGG_TX_STATE_ABORT_MSK = 0x08,
+	AGG_TX_STATE_LAST_SENT_TTL_MSK = 0x10,
+	AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK = 0x20,
+	AGG_TX_STATE_LAST_SENT_BT_KILL_MSK = 0x40,
+	AGG_TX_STATE_SCD_QUERY_MSK = 0x80,
+	AGG_TX_STATE_TEST_BAD_CRC32_MSK = 0x100,
+	AGG_TX_STATE_RESPONSE_MSK = 0x1ff,
+	AGG_TX_STATE_DUMP_TX_MSK = 0x200,
+	AGG_TX_STATE_DELAY_TX_MSK = 0x400
+};
+
+#define AGG_TX_STATE_LAST_SENT_MSK \
+(AGG_TX_STATE_LAST_SENT_TTL_MSK | \
+ AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \
+ AGG_TX_STATE_LAST_SENT_BT_KILL_MSK)
+
+#define AGG_TX_STATE_TRY_CNT_POS 12
+#define AGG_TX_STATE_TRY_CNT_MSK 0xf000
+
+#define AGG_TX_STATE_SEQ_NUM_POS 16
+#define AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000
+
+/*
+ * REPLY_TX = 0x1c (response)
+ */
+#if IWL == 4965
+struct iwl_tx_resp {
+	u8 frame_count;		/* 1 no aggregation, >1 aggregation */
+	u8 bt_kill_count;
+	u8 failure_rts;
+	u8 failure_frame;
+	__le32 rate_n_flags;
+	__le16 wireless_media_time;
+	__le16 reserved;
+	__le32 pa_power1;
+	__le32 pa_power2;
+	__le32 status;	/* TX status (for aggregation status of 1st frame) */
+} __attribute__ ((packed));
+
+#elif IWL == 3945
+struct iwl_tx_resp {
+	u8 failure_rts;
+	u8 failure_frame;
+	u8 bt_kill_count;
+	u8 rate;
+	__le32 wireless_media_time;
+	__le32 status;	/* TX status (for aggregation status of 1st frame) */
+} __attribute__ ((packed));
+#endif
+
+/*
+ * REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
+ */
+struct iwl_compressed_ba_resp {
+	__le32 sta_addr_lo32;
+	__le16 sta_addr_hi16;
+	__le16 reserved;
+	u8 sta_id;
+	u8 tid;
+	__le16 ba_seq_ctl;
+	__le32 ba_bitmap0;
+	__le32 ba_bitmap1;
+	__le16 scd_flow;
+	__le16 scd_ssn;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
+ */
+struct iwl_txpowertable_cmd {
+	u8 band;		/* 0: 5 GHz, 1: 2.4 GHz */
+	u8 reserved;
+	__le16 channel;
+#if IWL == 3945
+	struct iwl_power_per_rate power[IWL_MAX_RATES];
+#elif IWL == 4965
+	struct iwl_tx_power_db tx_power;
+#endif
+} __attribute__ ((packed));
+
+#if IWL == 3945
+struct iwl_rate_scaling_info {
+	__le16 rate_n_flags;
+	u8 try_cnt;
+	u8 next_rate_index;
+} __attribute__ ((packed));
+
+/**
+ * struct iwl_rate_scaling_cmd - Rate Scaling Command & Response
+ *
+ * REPLY_RATE_SCALE = 0x47 (command, has simple generic response)
+ *
+ * NOTE: The table of rates passed to the uCode via the
+ * RATE_SCALE command sets up the corresponding order of
+ * rates used for all related commands, including rate
+ * masks, etc.
+ *
+ * For example, if you set 9MB (PLCP 0x0f) as the first
+ * rate in the rate table, the bit mask for that rate
+ * when passed through ofdm_basic_rates on the REPLY_RXON
+ * command would be bit 0 (1<<0)
+ */
+struct iwl_rate_scaling_cmd {
+	u8 table_id;
+	u8 reserved[3];
+	struct iwl_rate_scaling_info table[IWL_MAX_RATES];
+} __attribute__ ((packed));
+
+#elif IWL == 4965
+
+/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
+#define  LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK	(1<<0)
+
+#define  LINK_QUAL_AC_NUM AC_NUM
+#define  LINK_QUAL_MAX_RETRY_NUM 16
+
+#define  LINK_QUAL_ANT_A_MSK (1<<0)
+#define  LINK_QUAL_ANT_B_MSK (1<<1)
+#define  LINK_QUAL_ANT_MSK   (LINK_QUAL_ANT_A_MSK|LINK_QUAL_ANT_B_MSK)
+
+struct iwl_link_qual_general_params {
+	u8 flags;
+	u8 mimo_delimiter;
+	u8 single_stream_ant_msk;
+	u8 dual_stream_ant_msk;
+	u8 start_rate_index[LINK_QUAL_AC_NUM];
+} __attribute__ ((packed));
+
+struct iwl_link_qual_agg_params {
+	__le16 agg_time_limit;
+	u8 agg_dis_start_th;
+	u8 agg_frame_cnt_limit;
+	__le32 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
+ */
+struct iwl_link_quality_cmd {
+	u8 sta_id;
+	u8 reserved1;
+	__le16 control;
+	struct iwl_link_qual_general_params general_params;
+	struct iwl_link_qual_agg_params agg_params;
+	struct {
+		__le32 rate_n_flags;
+	} rs_table[LINK_QUAL_MAX_RETRY_NUM];
+	__le32 reserved2;
+} __attribute__ ((packed));
+#endif
+
+/*
+ * REPLY_BT_CONFIG = 0x9b (command, has simple generic response)
+ */
+struct iwl_bt_cmd {
+	u8 flags;
+	u8 lead_time;
+	u8 max_kill;
+	u8 reserved;
+	__le32 kill_ack_mask;
+	__le32 kill_cts_mask;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (6)
+ * Spectrum Management (802.11h) Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/*
+ * Spectrum Management
+ */
+#define MEASUREMENT_FILTER_FLAG (RXON_FILTER_PROMISC_MSK         | \
+				 RXON_FILTER_CTL2HOST_MSK        | \
+				 RXON_FILTER_ACCEPT_GRP_MSK      | \
+				 RXON_FILTER_DIS_DECRYPT_MSK     | \
+				 RXON_FILTER_DIS_GRP_DECRYPT_MSK | \
+				 RXON_FILTER_ASSOC_MSK           | \
+				 RXON_FILTER_BCON_AWARE_MSK)
+
+struct iwl_measure_channel {
+	__le32 duration;	/* measurement duration in extended beacon
+				 * format */
+	u8 channel;		/* channel to measure */
+	u8 type;		/* see enum iwl_measure_type */
+	__le16 reserved;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
+ */
+struct iwl_spectrum_cmd {
+	__le16 len;		/* number of bytes starting from token */
+	u8 token;		/* token id */
+	u8 id;			/* measurement id -- 0 or 1 */
+	u8 origin;		/* 0 = TGh, 1 = other, 2 = TGk */
+	u8 periodic;		/* 1 = periodic */
+	__le16 path_loss_timeout;
+	__le32 start_time;	/* start time in extended beacon format */
+	__le32 reserved2;
+	__le32 flags;		/* rxon flags */
+	__le32 filter_flags;	/* rxon filter flags */
+	__le16 channel_count;	/* minimum 1, maximum 10 */
+	__le16 reserved3;
+	struct iwl_measure_channel channels[10];
+} __attribute__ ((packed));
+
+/*
+ * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
+ */
+struct iwl_spectrum_resp {
+	u8 token;
+	u8 id;			/* id of the prior command replaced, or 0xff */
+	__le16 status;		/* 0 - command will be handled
+				 * 1 - cannot handle (conflicts with another
+				 *     measurement) */
+} __attribute__ ((packed));
+
+enum iwl_measurement_state {
+	IWL_MEASUREMENT_START = 0,
+	IWL_MEASUREMENT_STOP = 1,
+};
+
+enum iwl_measurement_status {
+	IWL_MEASUREMENT_OK = 0,
+	IWL_MEASUREMENT_CONCURRENT = 1,
+	IWL_MEASUREMENT_CSA_CONFLICT = 2,
+	IWL_MEASUREMENT_TGH_CONFLICT = 3,
+	/* 4-5 reserved */
+	IWL_MEASUREMENT_STOPPED = 6,
+	IWL_MEASUREMENT_TIMEOUT = 7,
+	IWL_MEASUREMENT_PERIODIC_FAILED = 8,
+};
+
+#define NUM_ELEMENTS_IN_HISTOGRAM 8
+
+struct iwl_measurement_histogram {
+	__le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 0.8usec counts */
+	__le32 cck[NUM_ELEMENTS_IN_HISTOGRAM];	/* in 1usec counts */
+} __attribute__ ((packed));
+
+/* clear channel availability counters */
+struct iwl_measurement_cca_counters {
+	__le32 ofdm;
+	__le32 cck;
+} __attribute__ ((packed));
+
+enum iwl_measure_type {
+	IWL_MEASURE_BASIC = (1 << 0),
+	IWL_MEASURE_CHANNEL_LOAD = (1 << 1),
+	IWL_MEASURE_HISTOGRAM_RPI = (1 << 2),
+	IWL_MEASURE_HISTOGRAM_NOISE = (1 << 3),
+	IWL_MEASURE_FRAME = (1 << 4),
+	/* bits 5:6 are reserved */
+	IWL_MEASURE_IDLE = (1 << 7),
+};
+
+/*
+ * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command)
+ */
+struct iwl_spectrum_notification {
+	u8 id;			/* measurement id -- 0 or 1 */
+	u8 token;
+	u8 channel_index;	/* index in measurement channel list */
+	u8 state;		/* 0 - start, 1 - stop */
+	__le32 start_time;	/* lower 32-bits of TSF */
+	u8 band;		/* 0 - 5.2GHz, 1 - 2.4GHz */
+	u8 channel;
+	u8 type;		/* see enum iwl_measurement_type */
+	u8 reserved1;
+	/* NOTE:  cca_ofdm, cca_cck, basic_type, and histogram are only only
+	 * valid if applicable for measurement type requested. */
+	__le32 cca_ofdm;	/* cca fraction time in 40Mhz clock periods */
+	__le32 cca_cck;		/* cca fraction time in 44Mhz clock periods */
+	__le32 cca_time;	/* channel load time in usecs */
+	u8 basic_type;		/* 0 - bss, 1 - ofdm preamble, 2 -
+				 * unidentified */
+	u8 reserved2[3];
+	struct iwl_measurement_histogram histogram;
+	__le32 stop_time;	/* lower 32-bits of TSF */
+	__le32 status;		/* see iwl_measurement_status */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (7)
+ * Power Management Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+/**
+ * struct iwl_powertable_cmd - Power Table Command
+ * @flags: See below:
+ *
+ * POWER_TABLE_CMD = 0x77 (command, has simple generic response)
+ *
+ * PM allow:
+ *   bit 0 - '0' Driver not allow power management
+ *           '1' Driver allow PM (use rest of parameters)
+ * uCode send sleep notifications:
+ *   bit 1 - '0' Don't send sleep notification
+ *           '1' send sleep notification (SEND_PM_NOTIFICATION)
+ * Sleep over DTIM
+ *   bit 2 - '0' PM have to walk up every DTIM
+ *           '1' PM could sleep over DTIM till listen Interval.
+ * PCI power managed
+ *   bit 3 - '0' (PCI_LINK_CTRL & 0x1)
+ *           '1' !(PCI_LINK_CTRL & 0x1)
+ * Force sleep Modes
+ *   bit 31/30- '00' use both mac/xtal sleeps
+ *              '01' force Mac sleep
+ *              '10' force xtal sleep
+ *              '11' Illegal set
+ *
+ * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then
+ * ucode assume sleep over DTIM is allowed and we don't need to wakeup
+ * for every DTIM.
+ */
+#define IWL_POWER_VEC_SIZE 5
+
+
+#if IWL == 3945
+
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK	__constant_cpu_to_le32(1<<0)
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK		__constant_cpu_to_le32(1<<2)
+#define IWL_POWER_PCI_PM_MSK			__constant_cpu_to_le32(1<<3)
+struct iwl_powertable_cmd {
+	__le32 flags;
+	__le32 rx_data_timeout;
+	__le32 tx_data_timeout;
+	__le32 sleep_interval[IWL_POWER_VEC_SIZE];
+} __attribute__((packed));
+
+#elif IWL == 4965
+
+#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK	__constant_cpu_to_le16(1<<0)
+#define IWL_POWER_SLEEP_OVER_DTIM_MSK		__constant_cpu_to_le16(1<<2)
+#define IWL_POWER_PCI_PM_MSK			__constant_cpu_to_le16(1<<3)
+
+struct iwl_powertable_cmd {
+	__le16 flags;
+	u8 keep_alive_seconds;
+	u8 debug_flags;
+	__le32 rx_data_timeout;
+	__le32 tx_data_timeout;
+	__le32 sleep_interval[IWL_POWER_VEC_SIZE];
+	__le32 keep_alive_beacons;
+} __attribute__ ((packed));
+#endif
+
+/*
+ * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
+ * 3945 and 4965 identical.
+ */
+struct iwl_sleep_notification {
+	u8 pm_sleep_mode;
+	u8 pm_wakeup_src;
+	__le16 reserved;
+	__le32 sleep_time;
+	__le32 tsf_low;
+	__le32 bcon_timer;
+} __attribute__ ((packed));
+
+/* Sleep states.  3945 and 4965 identical. */
+enum {
+	IWL_PM_NO_SLEEP = 0,
+	IWL_PM_SLP_MAC = 1,
+	IWL_PM_SLP_FULL_MAC_UNASSOCIATE = 2,
+	IWL_PM_SLP_FULL_MAC_CARD_STATE = 3,
+	IWL_PM_SLP_PHY = 4,
+	IWL_PM_SLP_REPENT = 5,
+	IWL_PM_WAKEUP_BY_TIMER = 6,
+	IWL_PM_WAKEUP_BY_DRIVER = 7,
+	IWL_PM_WAKEUP_BY_RFKILL = 8,
+	/* 3 reserved */
+	IWL_PM_NUM_OF_MODES = 12,
+};
+
+/*
+ * REPLY_CARD_STATE_CMD = 0xa0 (command, has simple generic response)
+ */
+#define CARD_STATE_CMD_DISABLE 0x00	/* Put card to sleep */
+#define CARD_STATE_CMD_ENABLE  0x01	/* Wake up card */
+#define CARD_STATE_CMD_HALT    0x02	/* Power down permanently */
+struct iwl_card_state_cmd {
+	__le32 status;		/* CARD_STATE_CMD_* request new power state */
+} __attribute__ ((packed));
+
+/*
+ * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
+ */
+struct iwl_card_state_notif {
+	__le32 flags;
+} __attribute__ ((packed));
+
+#define HW_CARD_DISABLED   0x01
+#define SW_CARD_DISABLED   0x02
+#define RF_CARD_DISABLED   0x04
+#define RXON_CARD_DISABLED 0x10
+
+struct iwl_ct_kill_config {
+	__le32   reserved;
+	__le32   critical_temperature_M;
+	__le32   critical_temperature_R;
+}  __attribute__ ((packed));
+
+/******************************************************************************
+ * (8)
+ * Scan Commands, Responses, Notifications:
+ *
+ *****************************************************************************/
+
+struct iwl_scan_channel {
+	/* type is defined as:
+	 * 0:0 active (0 - passive)
+	 * 1:4 SSID direct
+	 *     If 1 is set then corresponding SSID IE is transmitted in probe
+	 * 5:7 reserved
+	 */
+	u8 type;
+	u8 channel;
+	struct iwl_tx_power tpc;
+	__le16 active_dwell;
+	__le16 passive_dwell;
+} __attribute__ ((packed));
+
+struct iwl_ssid_ie {
+	u8 id;
+	u8 len;
+	u8 ssid[32];
+} __attribute__ ((packed));
+
+#define PROBE_OPTION_MAX        0x4
+#define TX_CMD_LIFE_TIME_INFINITE	__constant_cpu_to_le32(0xFFFFFFFF)
+#define IWL_GOOD_CRC_TH		__constant_cpu_to_le16(1)
+#define IWL_MAX_SCAN_SIZE 1024
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (command)
+ */
+struct iwl_scan_cmd {
+	__le16 len;
+	u8 reserved0;
+	u8 channel_count;
+	__le16 quiet_time;     /* dwell only this long on quiet chnl
+				* (active scan) */
+	__le16 quiet_plcp_th;  /* quiet chnl is < this # pkts (typ. 1) */
+	__le16 good_CRC_th;    /* passive -> active promotion threshold */
+#if IWL == 3945
+	__le16 reserved1;
+#elif IWL == 4965
+	__le16 rx_chain;
+#endif
+	__le32 max_out_time;   /* max usec to be out of associated (service)
+				* chnl */
+	__le32 suspend_time;   /* pause scan this long when returning to svc
+				* chnl.
+				* 3945 -- 31:24 # beacons, 19:0 additional usec,
+				* 4965 -- 31:22 # beacons, 21:0 additional usec.
+				*/
+	__le32 flags;
+	__le32 filter_flags;
+
+	struct iwl_tx_cmd tx_cmd;
+	struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
+
+	u8 data[0];
+	/*
+	 * The channels start after the probe request payload and are of type:
+	 *
+	 * struct iwl_scan_channel channels[0];
+	 *
+	 * NOTE:  Only one band of channels can be scanned per pass.  You
+	 * can not mix 2.4GHz channels and 5.2GHz channels and must
+	 * request a scan multiple times (not concurrently)
+	 *
+	 */
+} __attribute__ ((packed));
+
+/* Can abort will notify by complete notification with abort status. */
+#define CAN_ABORT_STATUS	__constant_cpu_to_le32(0x1)
+/* complete notification statuses */
+#define ABORT_STATUS            0x2
+
+/*
+ * REPLY_SCAN_CMD = 0x80 (response)
+ */
+struct iwl_scanreq_notification {
+	__le32 status;		/* 1: okay, 2: cannot fulfill request */
+} __attribute__ ((packed));
+
+/*
+ * SCAN_START_NOTIFICATION = 0x82 (notification only, not a command)
+ */
+struct iwl_scanstart_notification {
+	__le32 tsf_low;
+	__le32 tsf_high;
+	__le32 beacon_timer;
+	u8 channel;
+	u8 band;
+	u8 reserved[2];
+	__le32 status;
+} __attribute__ ((packed));
+
+#define  SCAN_OWNER_STATUS 0x1;
+#define  MEASURE_OWNER_STATUS 0x2;
+
+#define NUMBER_OF_STATISTICS 1	/* first __le32 is good CRC */
+/*
+ * SCAN_RESULTS_NOTIFICATION = 0x83 (notification only, not a command)
+ */
+struct iwl_scanresults_notification {
+	u8 channel;
+	u8 band;
+	u8 reserved[2];
+	__le32 tsf_low;
+	__le32 tsf_high;
+	__le32 statistics[NUMBER_OF_STATISTICS];
+} __attribute__ ((packed));
+
+/*
+ * SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command)
+ */
+struct iwl_scancomplete_notification {
+	u8 scanned_channels;
+	u8 status;
+	u8 reserved;
+	u8 last_channel;
+	__le32 tsf_low;
+	__le32 tsf_high;
+} __attribute__ ((packed));
+
+
+/******************************************************************************
+ * (9)
+ * IBSS/AP Commands and Notifications:
+ *
+ *****************************************************************************/
+
+/*
+ * BEACON_NOTIFICATION = 0x90 (notification only, not a command)
+ */
+struct iwl_beacon_notif {
+	struct iwl_tx_resp beacon_notify_hdr;
+	__le32 low_tsf;
+	__le32 high_tsf;
+	__le32 ibss_mgr_status;
+} __attribute__ ((packed));
+
+/*
+ * REPLY_TX_BEACON = 0x91 (command, has simple generic response)
+ */
+struct iwl_tx_beacon_cmd {
+	struct iwl_tx_cmd tx;
+	__le16 tim_idx;
+	u8 tim_size;
+	u8 reserved1;
+	struct ieee80211_hdr frame[0];	/* beacon frame */
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (10)
+ * Statistics Commands and Notifications:
+ *
+ *****************************************************************************/
+
+#define IWL_TEMP_CONVERT 260
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
+
+/* Used for passing to driver number of successes and failures per rate */
+struct rate_histogram {
+	union {
+		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+	} success;
+	union {
+		__le32 a[SUP_RATE_11A_MAX_NUM_CHANNELS];
+		__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
+		__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
+	} failed;
+} __attribute__ ((packed));
+
+/* statistics command response */
+
+struct statistics_rx_phy {
+	__le32 ina_cnt;
+	__le32 fina_cnt;
+	__le32 plcp_err;
+	__le32 crc32_err;
+	__le32 overrun_err;
+	__le32 early_overrun_err;
+	__le32 crc32_good;
+	__le32 false_alarm_cnt;
+	__le32 fina_sync_err_cnt;
+	__le32 sfd_timeout;
+	__le32 fina_timeout;
+	__le32 unresponded_rts;
+	__le32 rxe_frame_limit_overrun;
+	__le32 sent_ack_cnt;
+	__le32 sent_cts_cnt;
+#if IWL == 4965
+	__le32 sent_ba_rsp_cnt;
+	__le32 dsp_self_kill;
+	__le32 mh_format_err;
+	__le32 re_acq_main_rssi_sum;
+	__le32 reserved3;
+#endif
+} __attribute__ ((packed));
+
+#if IWL == 4965
+struct statistics_rx_ht_phy {
+	__le32 plcp_err;
+	__le32 overrun_err;
+	__le32 early_overrun_err;
+	__le32 crc32_good;
+	__le32 crc32_err;
+	__le32 mh_format_err;
+	__le32 agg_crc32_good;
+	__le32 agg_mpdu_cnt;
+	__le32 agg_cnt;
+	__le32 reserved2;
+} __attribute__ ((packed));
+#endif
+
+struct statistics_rx_non_phy {
+	__le32 bogus_cts;	/* CTS received when not expecting CTS */
+	__le32 bogus_ack;	/* ACK received when not expecting ACK */
+	__le32 non_bssid_frames;	/* number of frames with BSSID that
+					 * doesn't belong to the STA BSSID */
+	__le32 filtered_frames;	/* count frames that were dumped in the
+				 * filtering process */
+	__le32 non_channel_beacons;	/* beacons with our bss id but not on
+					 * our serving channel */
+#if IWL == 4965
+	__le32 channel_beacons;	/* beacons with our bss id and in our
+				 * serving channel */
+	__le32 num_missed_bcon;	/* number of missed beacons */
+	__le32 adc_rx_saturation_time;	/* count in 0.8us units the time the
+					 * ADC was in saturation */
+	__le32 ina_detection_search_time;/* total time (in 0.8us) searched
+					  * for INA */
+	__le32 beacon_silence_rssi_a;	/* RSSI silence after beacon frame */
+	__le32 beacon_silence_rssi_b;	/* RSSI silence after beacon frame */
+	__le32 beacon_silence_rssi_c;	/* RSSI silence after beacon frame */
+	__le32 interference_data_flag;	/* flag for interference data
+					 * availability. 1 when data is
+					 * available. */
+	__le32 channel_load;	/* counts RX Enable time */
+	__le32 dsp_false_alarms;	/* DSP false alarm (both OFDM
+					 * and CCK) counter */
+	__le32 beacon_rssi_a;
+	__le32 beacon_rssi_b;
+	__le32 beacon_rssi_c;
+	__le32 beacon_energy_a;
+	__le32 beacon_energy_b;
+	__le32 beacon_energy_c;
+#endif
+} __attribute__ ((packed));
+
+struct statistics_rx {
+	struct statistics_rx_phy ofdm;
+	struct statistics_rx_phy cck;
+	struct statistics_rx_non_phy general;
+#if IWL == 4965
+	struct statistics_rx_ht_phy ofdm_ht;
+#endif
+} __attribute__ ((packed));
+
+#if IWL == 4965
+struct statistics_tx_non_phy_agg {
+	__le32 ba_timeout;
+	__le32 ba_reschedule_frames;
+	__le32 scd_query_agg_frame_cnt;
+	__le32 scd_query_no_agg;
+	__le32 scd_query_agg;
+	__le32 scd_query_mismatch;
+	__le32 frame_not_ready;
+	__le32 underrun;
+	__le32 bt_prio_kill;
+	__le32 rx_ba_rsp_cnt;
+	__le32 reserved2;
+	__le32 reserved3;
+} __attribute__ ((packed));
+#endif
+
+struct statistics_tx {
+	__le32 preamble_cnt;
+	__le32 rx_detected_cnt;
+	__le32 bt_prio_defer_cnt;
+	__le32 bt_prio_kill_cnt;
+	__le32 few_bytes_cnt;
+	__le32 cts_timeout;
+	__le32 ack_timeout;
+	__le32 expected_ack_cnt;
+	__le32 actual_ack_cnt;
+#if IWL == 4965
+	__le32 dump_msdu_cnt;
+	__le32 burst_abort_next_frame_mismatch_cnt;
+	__le32 burst_abort_missing_next_frame_cnt;
+	__le32 cts_timeout_collision;
+	__le32 ack_or_ba_timeout_collision;
+	struct statistics_tx_non_phy_agg agg;
+#endif
+} __attribute__ ((packed));
+
+struct statistics_dbg {
+	__le32 burst_check;
+	__le32 burst_count;
+	__le32 reserved[4];
+} __attribute__ ((packed));
+
+struct statistics_div {
+	__le32 tx_on_a;
+	__le32 tx_on_b;
+	__le32 exec_time;
+	__le32 probe_time;
+#if IWL == 4965
+	__le32 reserved1;
+	__le32 reserved2;
+#endif
+} __attribute__ ((packed));
+
+struct statistics_general {
+	__le32 temperature;
+#if IWL == 4965
+	__le32 temperature_m;
+#endif
+	struct statistics_dbg dbg;
+	__le32 sleep_time;
+	__le32 slots_out;
+	__le32 slots_idle;
+	__le32 ttl_timestamp;
+	struct statistics_div div;
+#if IWL == 4965
+	__le32 rx_enable_counter;
+	__le32 reserved1;
+	__le32 reserved2;
+	__le32 reserved3;
+#endif
+} __attribute__ ((packed));
+
+/*
+ * REPLY_STATISTICS_CMD = 0x9c,
+ * 3945 and 4965 identical.
+ *
+ * This command triggers an immediate response containing uCode statistics.
+ * The response is in the same format as STATISTICS_NOTIFICATION 0x9d, below.
+ *
+ * If the CLEAR_STATS configuration flag is set, uCode will clear its
+ * internal copy of the statistics (counters) after issuing the response.
+ * This flag does not affect STATISTICS_NOTIFICATIONs after beacons (see below).
+ *
+ * If the DISABLE_NOTIF configuration flag is set, uCode will not issue
+ * STATISTICS_NOTIFICATIONs after received beacons (see below).  This flag
+ * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself.
+ */
+#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1)	/* see above */
+#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */
+struct iwl_statistics_cmd {
+	__le32 configuration_flags;	/* IWL_STATS_CONF_* */
+} __attribute__ ((packed));
+
+/*
+ * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
+ *
+ * By default, uCode issues this notification after receiving a beacon
+ * while associated.  To disable this behavior, set DISABLE_NOTIF flag in the
+ * REPLY_STATISTICS_CMD 0x9c, above.
+ *
+ * Statistics counters continue to increment beacon after beacon, but are
+ * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
+ * 0x9c with CLEAR_STATS bit set (see above).
+ *
+ * uCode also issues this notification during scans.  uCode clears statistics
+ * appropriately so that each notification contains statistics for only the
+ * one channel that has just been scanned.
+ */
+#define STATISTICS_REPLY_FLG_BAND_24G_MSK         __constant_cpu_to_le32(0x2)
+#define STATISTICS_REPLY_FLG_FAT_MODE_MSK         __constant_cpu_to_le32(0x8)
+struct iwl_notif_statistics {
+	__le32 flag;
+	struct statistics_rx rx;
+	struct statistics_tx tx;
+	struct statistics_general general;
+} __attribute__ ((packed));
+
+
+/*
+ * MISSED_BEACONS_NOTIFICATION = 0xa2 (notification only, not a command)
+ */
+/* if ucode missed CONSECUTIVE_MISSED_BCONS_TH beacons in a row,
+ * then this notification will be sent. */
+#define CONSECUTIVE_MISSED_BCONS_TH 20
+
+struct iwl_missed_beacon_notif {
+	__le32 consequtive_missed_beacons;
+	__le32 total_missed_becons;
+	__le32 num_expected_beacons;
+	__le32 num_recvd_beacons;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (11)
+ * Rx Calibration Commands:
+ *
+ *****************************************************************************/
+
+#define PHY_CALIBRATE_DIFF_GAIN_CMD (7)
+#define HD_TABLE_SIZE  (11)
+
+struct iwl_sensitivity_cmd {
+	__le16 control;
+	__le16 table[HD_TABLE_SIZE];
+} __attribute__ ((packed));
+
+struct iwl_calibration_cmd {
+	u8 opCode;
+	u8 flags;
+	__le16 reserved;
+	s8 diff_gain_a;
+	s8 diff_gain_b;
+	s8 diff_gain_c;
+	u8 reserved1;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (12)
+ * Miscellaneous Commands:
+ *
+ *****************************************************************************/
+
+/*
+ * LEDs Command & Response
+ * REPLY_LEDS_CMD = 0x48 (command, has simple generic response)
+ *
+ * For each of 3 possible LEDs (Activity/Link/Tech, selected by "id" field),
+ * this command turns it on or off, or sets up a periodic blinking cycle.
+ */
+struct iwl_led_cmd {
+	__le32 interval;	/* "interval" in uSec */
+	u8 id;			/* 1: Activity, 2: Link, 3: Tech */
+	u8 off;			/* # intervals off while blinking;
+				 * "0", with >0 "on" value, turns LED on */
+	u8 on;			/* # intervals on while blinking;
+				 * "0", regardless of "off", turns LED off */
+	u8 reserved;
+} __attribute__ ((packed));
+
+/******************************************************************************
+ * (13)
+ * Union of all expected notifications/responses:
+ *
+ *****************************************************************************/
+
+struct iwl_rx_packet {
+	__le32 len;
+	struct iwl_cmd_header hdr;
+	union {
+		struct iwl_alive_resp alive_frame;
+		struct iwl_rx_frame rx_frame;
+		struct iwl_tx_resp tx_resp;
+		struct iwl_spectrum_notification spectrum_notif;
+		struct iwl_csa_notification csa_notif;
+		struct iwl_error_resp err_resp;
+		struct iwl_card_state_notif card_state_notif;
+		struct iwl_beacon_notif beacon_status;
+		struct iwl_add_sta_resp add_sta;
+		struct iwl_sleep_notification sleep_notif;
+		struct iwl_spectrum_resp spectrum;
+		struct iwl_notif_statistics stats;
+#if IWL == 4965
+		struct iwl_compressed_ba_resp compressed_ba;
+		struct iwl_missed_beacon_notif missed_beacon;
+#endif
+		__le32 status;
+		u8 raw[0];
+	} u;
+} __attribute__ ((packed));
+
+#define IWL_RX_FRAME_SIZE        (4 + sizeof(struct iwl_rx_frame))
+
+#endif				/* __iwl_commands_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
new file mode 100644
index 0000000..72318d7
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -0,0 +1,152 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_debug_h__
+#define __iwl_debug_h__
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+extern u32 iwl_debug_level;
+#define IWL_DEBUG(level, fmt, args...) \
+do { if (iwl_debug_level & (level)) \
+  printk(KERN_ERR DRV_NAME": %c %s " fmt, \
+	 in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+
+#define IWL_DEBUG_LIMIT(level, fmt, args...) \
+do { if ((iwl_debug_level & (level)) && net_ratelimit()) \
+  printk(KERN_ERR DRV_NAME": %c %s " fmt, \
+	 in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+#else
+static inline void IWL_DEBUG(int level, const char *fmt, ...)
+{
+}
+static inline void IWL_DEBUG_LIMIT(int level, const char *fmt, ...)
+{
+}
+#endif				/* CONFIG_IWLWIFI_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 IWL_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 IWL_xxxx_DEBUG() macro definition for your
+ * classification, or use IWL_DEBUG(IWL_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/iwl/debug_level
+ *
+ * you simply need to add your entry to the iwl_debug_levels array.
+ *
+ * If you do not see debug_level in /proc/net/iwl then you do not have
+ * CONFIG_IWLWIFI_DEBUG defined in your kernel configuration
+ *
+ */
+
+#define IWL_DL_INFO          (1<<0)
+#define IWL_DL_MAC80211      (1<<1)
+#define IWL_DL_HOST_COMMAND  (1<<2)
+#define IWL_DL_STATE         (1<<3)
+
+#define IWL_DL_RADIO         (1<<7)
+#define IWL_DL_POWER         (1<<8)
+#define IWL_DL_TEMP          (1<<9)
+
+#define IWL_DL_NOTIF         (1<<10)
+#define IWL_DL_SCAN          (1<<11)
+#define IWL_DL_ASSOC         (1<<12)
+#define IWL_DL_DROP          (1<<13)
+
+#define IWL_DL_TXPOWER       (1<<14)
+
+#define IWL_DL_AP            (1<<15)
+
+#define IWL_DL_FW            (1<<16)
+#define IWL_DL_RF_KILL       (1<<17)
+#define IWL_DL_FW_ERRORS     (1<<18)
+
+#define IWL_DL_LED           (1<<19)
+
+#define IWL_DL_RATE          (1<<20)
+
+#define IWL_DL_CALIB         (1<<21)
+#define IWL_DL_WEP           (1<<22)
+#define IWL_DL_TX            (1<<23)
+#define IWL_DL_RX            (1<<24)
+#define IWL_DL_ISR           (1<<25)
+#define IWL_DL_HT            (1<<26)
+#define IWL_DL_IO            (1<<27)
+#define IWL_DL_11H           (1<<28)
+
+#define IWL_DL_STATS         (1<<29)
+#define IWL_DL_TX_REPLY      (1<<30)
+#define IWL_DL_QOS           (1<<31)
+
+#define IWL_ERROR(f, a...) printk(KERN_ERR DRV_NAME ": " f, ## a)
+#define IWL_WARNING(f, a...) printk(KERN_WARNING DRV_NAME ": " f, ## a)
+#define IWL_DEBUG_INFO(f, a...)    IWL_DEBUG(IWL_DL_INFO, f, ## a)
+
+#define IWL_DEBUG_MAC80211(f, a...)     IWL_DEBUG(IWL_DL_MAC80211, f, ## a)
+#define IWL_DEBUG_TEMP(f, a...)   IWL_DEBUG(IWL_DL_TEMP, f, ## a)
+#define IWL_DEBUG_SCAN(f, a...)   IWL_DEBUG(IWL_DL_SCAN, f, ## a)
+#define IWL_DEBUG_RX(f, a...)     IWL_DEBUG(IWL_DL_RX, f, ## a)
+#define IWL_DEBUG_TX(f, a...)     IWL_DEBUG(IWL_DL_TX, f, ## a)
+#define IWL_DEBUG_ISR(f, a...)    IWL_DEBUG(IWL_DL_ISR, f, ## a)
+#define IWL_DEBUG_LED(f, a...) IWL_DEBUG(IWL_DL_LED, f, ## a)
+#define IWL_DEBUG_WEP(f, a...)    IWL_DEBUG(IWL_DL_WEP, f, ## a)
+#define IWL_DEBUG_HC(f, a...) IWL_DEBUG(IWL_DL_HOST_COMMAND, f, ## a)
+#define IWL_DEBUG_CALIB(f, a...) IWL_DEBUG(IWL_DL_CALIB, f, ## a)
+#define IWL_DEBUG_FW(f, a...) IWL_DEBUG(IWL_DL_FW, f, ## a)
+#define IWL_DEBUG_RF_KILL(f, a...) IWL_DEBUG(IWL_DL_RF_KILL, f, ## a)
+#define IWL_DEBUG_DROP(f, a...) IWL_DEBUG(IWL_DL_DROP, f, ## a)
+#define IWL_DEBUG_DROP_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_DROP, f, ## a)
+#define IWL_DEBUG_AP(f, a...) IWL_DEBUG(IWL_DL_AP, f, ## a)
+#define IWL_DEBUG_TXPOWER(f, a...) IWL_DEBUG(IWL_DL_TXPOWER, f, ## a)
+#define IWL_DEBUG_IO(f, a...) IWL_DEBUG(IWL_DL_IO, f, ## a)
+#define IWL_DEBUG_RATE(f, a...) IWL_DEBUG(IWL_DL_RATE, f, ## a)
+#define IWL_DEBUG_RATE_LIMIT(f, a...) IWL_DEBUG_LIMIT(IWL_DL_RATE, f, ## a)
+#define IWL_DEBUG_NOTIF(f, a...) IWL_DEBUG(IWL_DL_NOTIF, f, ## a)
+#define IWL_DEBUG_ASSOC(f, a...) IWL_DEBUG(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a)
+#define IWL_DEBUG_ASSOC_LIMIT(f, a...) \
+	IWL_DEBUG_LIMIT(IWL_DL_ASSOC | IWL_DL_INFO, f, ## a)
+#define IWL_DEBUG_HT(f, a...) IWL_DEBUG(IWL_DL_HT, f, ## a)
+#define IWL_DEBUG_STATS(f, a...) IWL_DEBUG(IWL_DL_STATS, f, ## a)
+#define IWL_DEBUG_TX_REPLY(f, a...) IWL_DEBUG(IWL_DL_TX_REPLY, f, ## a)
+#define IWL_DEBUG_QOS(f, a...)   IWL_DEBUG(IWL_DL_QOS, f, ## a)
+#define IWL_DEBUG_RADIO(f, a...)  IWL_DEBUG(IWL_DL_RADIO, f, ## a)
+#define IWL_DEBUG_POWER(f, a...)  IWL_DEBUG(IWL_DL_POWER, f, ## a)
+#define IWL_DEBUG_11H(f, a...)  IWL_DEBUG(IWL_DL_11H, f, ## a)
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
new file mode 100644
index 0000000..e473c97
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -0,0 +1,336 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_eeprom_h__
+#define __iwl_eeprom_h__
+
+/*
+ * This file defines EEPROM related constants, enums, and inline functions.
+ *
+ */
+
+#define IWL_EEPROM_ACCESS_TIMEOUT	5000 /* uSec */
+#define IWL_EEPROM_ACCESS_DELAY		10   /* uSec */
+/* EEPROM field values */
+#define ANTENNA_SWITCH_NORMAL     0
+#define ANTENNA_SWITCH_INVERSE    1
+
+enum {
+	EEPROM_CHANNEL_VALID = (1 << 0),	/* usable for this SKU/geo */
+	EEPROM_CHANNEL_IBSS = (1 << 1),	/* usable as an IBSS channel */
+	/* Bit 2 Reserved */
+	EEPROM_CHANNEL_ACTIVE = (1 << 3),	/* active scanning allowed */
+	EEPROM_CHANNEL_RADAR = (1 << 4),	/* radar detection required */
+	EEPROM_CHANNEL_WIDE = (1 << 5),
+	EEPROM_CHANNEL_NARROW = (1 << 6),
+	EEPROM_CHANNEL_DFS = (1 << 7),	/* dynamic freq selection candidate */
+};
+
+/* EEPROM field lengths */
+#define EEPROM_BOARD_PBA_NUMBER_LENGTH                  11
+
+/* EEPROM field lengths */
+#define EEPROM_BOARD_PBA_NUMBER_LENGTH                  11
+#define EEPROM_REGULATORY_SKU_ID_LENGTH                 4
+#define EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH         14
+#define EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH         13
+#define EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH         12
+#define EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH         11
+#define EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH         6
+
+#if IWL == 3945
+#define EEPROM_REGULATORY_CHANNELS_LENGTH ( \
+	EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH + \
+	EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH + \
+	EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH + \
+	EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH + \
+	EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH)
+#elif IWL == 4965
+#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS_LENGTH 7
+#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS_LENGTH 11
+#define EEPROM_REGULATORY_CHANNELS_LENGTH ( \
+	EEPROM_REGULATORY_BAND1_CHANNELS_LENGTH + \
+	EEPROM_REGULATORY_BAND2_CHANNELS_LENGTH + \
+	EEPROM_REGULATORY_BAND3_CHANNELS_LENGTH + \
+	EEPROM_REGULATORY_BAND4_CHANNELS_LENGTH + \
+	EEPROM_REGULATORY_BAND5_CHANNELS_LENGTH + \
+	EEPROM_REGULATORY_BAND_24_FAT_CHANNELS_LENGTH + \
+	EEPROM_REGULATORY_BAND_52_FAT_CHANNELS_LENGTH)
+#endif
+
+#define EEPROM_REGULATORY_NUMBER_OF_BANDS               5
+
+/* SKU Capabilities */
+#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE                (1 << 0)
+#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE                (1 << 1)
+#define EEPROM_SKU_CAP_OP_MODE_MRC                      (1 << 7)
+
+/* *regulatory* channel data from eeprom, one for each channel */
+struct iwl_eeprom_channel {
+	u8 flags;		/* flags copied from EEPROM */
+	s8 max_power_avg;	/* max power (dBm) on this chnl, limit 31 */
+} __attribute__ ((packed));
+
+/*
+ * Mapping of a Tx power level, at factory calibration temperature,
+ *   to a radio/DSP gain table index.
+ * One for each of 5 "sample" power levels in each band.
+ * v_det is measured at the factory, using the 3945's built-in power amplifier
+ *   (PA) output voltage detector.  This same detector is used during Tx of
+ *   long packets in normal operation to provide feedback as to proper output
+ *   level.
+ * Data copied from EEPROM.
+ */
+struct iwl_eeprom_txpower_sample {
+	u8 gain_index;		/* index into power (gain) setup table ... */
+	s8 power;		/* ... for this pwr level for this chnl group */
+	u16 v_det;		/* PA output voltage */
+} __attribute__ ((packed));
+
+/*
+ * Mappings of Tx power levels -> nominal radio/DSP gain table indexes.
+ * One for each channel group (a.k.a. "band") (1 for BG, 4 for A).
+ * Tx power setup code interpolates between the 5 "sample" power levels
+ *    to determine the nominal setup for a requested power level.
+ * Data copied from EEPROM.
+ * DO NOT ALTER THIS STRUCTURE!!!
+ */
+struct iwl_eeprom_txpower_group {
+	struct iwl_eeprom_txpower_sample samples[5];	/* 5 power levels */
+	s32 a, b, c, d, e;	/* coefficients for voltage->power
+				 * formula (signed) */
+	s32 Fa, Fb, Fc, Fd, Fe;	/* these modify coeffs based on
+					 * frequency (signed) */
+	s8 saturation_power;	/* highest power possible by h/w in this
+				 * band */
+	u8 group_channel;	/* "representative" channel # in this band */
+	s16 temperature;	/* h/w temperature at factory calib this band
+				 * (signed) */
+} __attribute__ ((packed));
+
+/*
+ * Temperature-based Tx-power compensation data, not band-specific.
+ * These coefficients are use to modify a/b/c/d/e coeffs based on
+ *   difference between current temperature and factory calib temperature.
+ * Data copied from EEPROM.
+ */
+struct iwl_eeprom_temperature_corr {
+	u32 Ta;
+	u32 Tb;
+	u32 Tc;
+	u32 Td;
+	u32 Te;
+} __attribute__ ((packed));
+
+#if IWL == 4965
+#define EEPROM_TX_POWER_TX_CHAINS      (2)
+#define EEPROM_TX_POWER_BANDS          (8)
+#define EEPROM_TX_POWER_MEASUREMENTS   (3)
+#define EEPROM_TX_POWER_VERSION        (2)
+#define EEPROM_TX_POWER_VERSION_NEW    (5)
+
+struct iwl_eeprom_calib_measure {
+	u8 temperature;
+	u8 gain_idx;
+	u8 actual_pow;
+	s8 pa_det;
+} __attribute__ ((packed));
+
+struct iwl_eeprom_calib_ch_info {
+	u8 ch_num;
+	struct iwl_eeprom_calib_measure measurements[EEPROM_TX_POWER_TX_CHAINS]
+		[EEPROM_TX_POWER_MEASUREMENTS];
+} __attribute__ ((packed));
+
+struct iwl_eeprom_calib_subband_info {
+	u8 ch_from;
+	u8 ch_to;
+	struct iwl_eeprom_calib_ch_info ch1;
+	struct iwl_eeprom_calib_ch_info ch2;
+} __attribute__ ((packed));
+
+struct iwl_eeprom_calib_info {
+	u8 saturation_power24;
+	u8 saturation_power52;
+	s16 voltage;		/* signed */
+	struct iwl_eeprom_calib_subband_info band_info[EEPROM_TX_POWER_BANDS];
+} __attribute__ ((packed));
+
+#endif
+
+struct iwl_eeprom {
+	u8 reserved0[16];
+#define EEPROM_DEVICE_ID                    (2*0x08)	/* 2 bytes */
+	u16 device_id;	/* abs.ofs: 16 */
+	u8 reserved1[2];
+#define EEPROM_PMC                          (2*0x0A)	/* 2 bytes */
+	u16 pmc;		/* abs.ofs: 20 */
+	u8 reserved2[20];
+#define EEPROM_MAC_ADDRESS                  (2*0x15)	/* 6  bytes */
+	u8 mac_address[6];	/* abs.ofs: 42 */
+	u8 reserved3[58];
+#define EEPROM_BOARD_REVISION               (2*0x35)	/* 2  bytes */
+	u16 board_revision;	/* abs.ofs: 106 */
+	u8 reserved4[11];
+#define EEPROM_BOARD_PBA_NUMBER             (2*0x3B+1)	/* 9  bytes */
+	u8 board_pba_number[9];	/* abs.ofs: 119 */
+	u8 reserved5[8];
+#define EEPROM_VERSION                      (2*0x44)	/* 2  bytes */
+	u16 version;		/* abs.ofs: 136 */
+#define EEPROM_SKU_CAP                      (2*0x45)	/* 1  bytes */
+	u8 sku_cap;		/* abs.ofs: 138 */
+#define EEPROM_LEDS_MODE                    (2*0x45+1)	/* 1  bytes */
+	u8 leds_mode;		/* abs.ofs: 139 */
+#define EEPROM_OEM_MODE                     (2*0x46)	/* 2  bytes */
+	u16 oem_mode;
+#define EEPROM_WOWLAN_MODE                  (2*0x47)	/* 2  bytes */
+	u16 wowlan_mode;	/* abs.ofs: 142 */
+#define EEPROM_LEDS_TIME_INTERVAL           (2*0x48)	/* 2  bytes */
+	u16 leds_time_interval;	/* abs.ofs: 144 */
+#define EEPROM_LEDS_OFF_TIME                (2*0x49)	/* 1  bytes */
+	u8 leds_off_time;	/* abs.ofs: 146 */
+#define EEPROM_LEDS_ON_TIME                 (2*0x49+1)	/* 1  bytes */
+	u8 leds_on_time;	/* abs.ofs: 147 */
+#define EEPROM_ALMGOR_M_VERSION             (2*0x4A)	/* 1  bytes */
+	u8 almgor_m_version;	/* abs.ofs: 148 */
+#define EEPROM_ANTENNA_SWITCH_TYPE          (2*0x4A+1)	/* 1  bytes */
+	u8 antenna_switch_type;	/* abs.ofs: 149 */
+#if IWL == 3945
+	u8 reserved6[42];
+#else
+	u8 reserved6[8];
+#define EEPROM_4965_BOARD_REVISION          (2*0x4F)	/* 2 bytes */
+	u16 board_revision_4965;	/* abs.ofs: 158 */
+	u8 reserved7[13];
+#define EEPROM_4965_BOARD_PBA               (2*0x56+1)	/* 9 bytes */
+	u8 board_pba_number_4965[9];	/* abs.ofs: 173 */
+	u8 reserved8[10];
+#endif
+#define EEPROM_REGULATORY_SKU_ID            (2*0x60)	/* 4  bytes */
+	u8 sku_id[4];		/* abs.ofs: 192 */
+#define EEPROM_REGULATORY_BAND_1            (2*0x62)	/* 2  bytes */
+	u16 band_1_count;	/* abs.ofs: 196 */
+#define EEPROM_REGULATORY_BAND_1_CHANNELS   (2*0x63)	/* 28 bytes */
+	struct iwl_eeprom_channel band_1_channels[14];	/* abs.ofs: 196 */
+#define EEPROM_REGULATORY_BAND_2            (2*0x71)	/* 2  bytes */
+	u16 band_2_count;	/* abs.ofs: 226 */
+#define EEPROM_REGULATORY_BAND_2_CHANNELS   (2*0x72)	/* 26 bytes */
+	struct iwl_eeprom_channel band_2_channels[13];	/* abs.ofs: 228 */
+#define EEPROM_REGULATORY_BAND_3            (2*0x7F)	/* 2  bytes */
+	u16 band_3_count;	/* abs.ofs: 254 */
+#define EEPROM_REGULATORY_BAND_3_CHANNELS   (2*0x80)	/* 24 bytes */
+	struct iwl_eeprom_channel band_3_channels[12];	/* abs.ofs: 256 */
+#define EEPROM_REGULATORY_BAND_4            (2*0x8C)	/* 2  bytes */
+	u16 band_4_count;	/* abs.ofs: 280 */
+#define EEPROM_REGULATORY_BAND_4_CHANNELS   (2*0x8D)	/* 22 bytes */
+	struct iwl_eeprom_channel band_4_channels[11];	/* abs.ofs: 282 */
+#define EEPROM_REGULATORY_BAND_5            (2*0x98)	/* 2  bytes */
+	u16 band_5_count;	/* abs.ofs: 304 */
+#define EEPROM_REGULATORY_BAND_5_CHANNELS   (2*0x99)	/* 12 bytes */
+	struct iwl_eeprom_channel band_5_channels[6];	/* abs.ofs: 306 */
+
+/* From here on out the EEPROM diverges between the 4965 and the 3945 */
+#if IWL == 3945
+
+	u8 reserved9[194];
+
+#define EEPROM_TXPOWER_CALIB_GROUP0 0x200
+#define EEPROM_TXPOWER_CALIB_GROUP1 0x240
+#define EEPROM_TXPOWER_CALIB_GROUP2 0x280
+#define EEPROM_TXPOWER_CALIB_GROUP3 0x2c0
+#define EEPROM_TXPOWER_CALIB_GROUP4 0x300
+#define IWL_NUM_TX_CALIB_GROUPS 5
+	struct iwl_eeprom_txpower_group groups[IWL_NUM_TX_CALIB_GROUPS];
+/* abs.ofs: 512 */
+#define EEPROM_CALIB_TEMPERATURE_CORRECT 0x340
+	struct iwl_eeprom_temperature_corr corrections;	/* abs.ofs: 832 */
+	u8 reserved16[172];	/* fill out to full 1024 byte block */
+
+/* 4965AGN adds fat channel support */
+#elif IWL == 4965
+
+	u8 reserved10[2];
+#define EEPROM_REGULATORY_BAND_24_FAT_CHANNELS (2*0xA0)	/* 14 bytes */
+	struct iwl_eeprom_channel band_24_channels[7];	/* abs.ofs: 320 */
+	u8 reserved11[2];
+#define EEPROM_REGULATORY_BAND_52_FAT_CHANNELS (2*0xA8)	/* 22 bytes */
+	struct iwl_eeprom_channel band_52_channels[11];	/* abs.ofs: 336 */
+	u8 reserved12[6];
+#define EEPROM_CALIB_VERSION_OFFSET            (2*0xB6)	/* 2 bytes */
+	u16 calib_version;	/* abs.ofs: 364 */
+	u8 reserved13[2];
+#define EEPROM_SATURATION_POWER_OFFSET         (2*0xB8)	/* 2 bytes */
+	u16 satruation_power;	/* abs.ofs: 368 */
+	u8 reserved14[94];
+#define EEPROM_IWL_CALIB_TXPOWER_OFFSET        (2*0xE8)	/* 48  bytes */
+	struct iwl_eeprom_calib_info calib_info;	/* abs.ofs: 464 */
+
+	u8 reserved16[140];	/* fill out to full 1024 byte block */
+
+#endif
+
+} __attribute__ ((packed));
+
+#define IWL_EEPROM_IMAGE_SIZE 1024
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
new file mode 100644
index 0000000..e2a8d95
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -0,0 +1,255 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_helpers_h__
+#define __iwl_helpers_h__
+
+#include <linux/ctype.h>
+
+/*
+ * The structures defined by the hardware/uCode interface
+ * have bit-wise operations.  For each bit-field there is
+ * a data symbol in the structure, the start bit position
+ * and the length of the bit-field.
+ *
+ * iwl_get_bits and iwl_set_bits will return or set the
+ * appropriate bits on a 32-bit value.
+ *
+ * IWL_GET_BITS and IWL_SET_BITS use symbol expansion to
+ * expand out to the appropriate call to iwl_get_bits
+ * and iwl_set_bits without having to reference all of the
+ * numerical constants and defines provided in the hardware
+ * definition
+ */
+
+/**
+ * iwl_get_bits - Extract a hardware bit-field value
+ * @src: source hardware value (__le32)
+ * @pos: bit-position (0-based) of first bit of value
+ * @len: length of bit-field
+ *
+ * iwl_get_bits will return the bit-field in cpu endian ordering.
+ *
+ * NOTE:  If used from IWL_GET_BITS then pos and len are compile-constants and
+ *        will collapse to minimal code by the compiler.
+ */
+static inline u32 iwl_get_bits(__le32 src, u8 pos, u8 len)
+{
+	u32 tmp = le32_to_cpu(src);
+
+	tmp >>= pos;
+	tmp &= (1UL << len) - 1;
+	return tmp;
+}
+
+/**
+ * iwl_set_bits - Set a hardware bit-field value
+ * @dst: Address of __le32 hardware value
+ * @pos: bit-position (0-based) of first bit of value
+ * @len: length of bit-field
+ * @val: cpu endian value to encode into the bit-field
+ *
+ * iwl_set_bits will encode val into dst, masked to be len bits long at bit
+ * position pos.
+ *
+ * NOTE:  If used IWL_SET_BITS pos and len will be compile-constants and
+ *        will collapse to minimal code by the compiler.
+ */
+static inline void iwl_set_bits(__le32 *dst, u8 pos, u8 len, int val)
+{
+	u32 tmp = le32_to_cpu(*dst);
+
+	tmp &= ~(((1UL << len) - 1) << pos);
+	tmp |= (val & ((1UL << len) - 1)) << pos;
+	*dst = cpu_to_le32(tmp);
+}
+
+static inline void iwl_set_bits16(__le16 *dst, u8 pos, u8 len, int val)
+{
+	u16 tmp = le16_to_cpu(*dst);
+
+	tmp &= ~((1UL << (pos + len)) - (1UL << pos));
+	tmp |= (val & ((1UL << len) - 1)) << pos;
+	*dst = cpu_to_le16(tmp);
+}
+
+/*
+ * The bit-field definitions in iwl-xxxx-hw.h are in the form of:
+ *
+ * struct example {
+ *         __le32 val1;
+ * #define IWL_name_POS 8
+ * #define IWL_name_LEN 4
+ * #define IWL_name_SYM val1
+ * };
+ *
+ * The IWL_SET_BITS and IWL_GET_BITS macros are provided to allow the driver
+ * to call:
+ *
+ * struct example bar;
+ * u32 val = IWL_GET_BITS(bar, name);
+ * val = val * 2;
+ * IWL_SET_BITS(bar, name, val);
+ *
+ * All cpu / host ordering, masking, and shifts are performed by the macros
+ * and iwl_{get,set}_bits.
+ *
+ */
+#define IWL_SET_BITS(s, sym, v) \
+	iwl_set_bits(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
+		     IWL_ ## sym ## _LEN, (v))
+
+#define IWL_SET_BITS16(s, sym, v) \
+	iwl_set_bits16(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
+		       IWL_ ## sym ## _LEN, (v))
+
+#define IWL_GET_BITS(s, sym) \
+	iwl_get_bits((s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \
+		      IWL_ ## sym ## _LEN)
+
+
+#define KELVIN_TO_CELSIUS(x) ((x)-273)
+#define CELSIUS_TO_KELVIN(x) ((x)+273)
+
+#define IEEE80211_CHAN_W_RADAR_DETECT 0x00000010
+
+static inline struct ieee80211_conf *ieee80211_get_hw_conf(
+	struct ieee80211_hw *hw)
+{
+	return &hw->conf;
+}
+
+#define QOS_CONTROL_LEN 2
+
+#define IEEE80211_STYPE_BACK_REQ	0x0080
+#define IEEE80211_STYPE_BACK		0x0090
+
+
+static inline int ieee80211_is_management(u16 fc)
+{
+	return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT;
+}
+
+static inline int ieee80211_is_control(u16 fc)
+{
+	return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL;
+}
+
+static inline int ieee80211_is_data(u16 fc)
+{
+	return (fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA;
+}
+
+static inline int ieee80211_is_back_request(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ);
+}
+
+static inline int ieee80211_is_probe_response(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP);
+}
+
+static inline int ieee80211_is_probe_request(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_REQ);
+}
+
+static inline int ieee80211_is_beacon(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON);
+}
+
+static inline int ieee80211_is_atim(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ATIM);
+}
+
+static inline int ieee80211_is_assoc_request(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ);
+}
+
+static inline int ieee80211_is_assoc_response(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_RESP);
+}
+
+static inline int ieee80211_is_auth(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ);
+}
+
+static inline int ieee80211_is_deauth(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ);
+}
+
+static inline int ieee80211_is_disassoc(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ);
+}
+
+static inline int ieee80211_is_reassoc_request(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ);
+}
+
+static inline int ieee80211_is_reassoc_response(u16 fc)
+{
+	return ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+	       ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_RESP);
+}
+
+static inline int iwl_check_bits(unsigned long field, unsigned long mask)
+{
+	return ((field & mask) == mask) ? 1 : 0;
+}
+
+static inline unsigned long elapsed_jiffies(unsigned long start,
+					    unsigned long end)
+{
+	if (end > start)
+		return end - start;
+
+	return end + (MAX_JIFFY_OFFSET - start);
+}
+
+#endif				/* __iwl_helpers_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-hw.h b/drivers/net/wireless/iwlwifi/iwl-hw.h
new file mode 100644
index 0000000..1aa6fcd
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-hw.h
@@ -0,0 +1,537 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef	__iwlwifi_hw_h__
+#define __iwlwifi_hw_h__
+
+/*
+ * This file defines hardware constants common to 3945 and 4965.
+ *
+ * Device-specific constants are defined in iwl-3945-hw.h and iwl-4965-hw.h,
+ * although this file contains a few definitions for which the .c
+ * implementation is the same for 3945 and 4965, except for the value of
+ * a constant.
+ *
+ * uCode API constants are defined in iwl-commands.h.
+ *
+ * NOTE:  DO NOT PUT OS IMPLEMENTATION-SPECIFIC DECLARATIONS HERE
+ *
+ * The iwl-*hw.h (and files they include) files should remain OS/driver
+ * implementation independent, declaring only the hardware interface.
+ */
+
+/* uCode queue management definitions */
+#define IWL_CMD_QUEUE_NUM       4
+#define IWL_CMD_FIFO_NUM        4
+#define IWL_BACK_QUEUE_FIRST_ID 7
+
+/* Tx rates */
+#define IWL_CCK_RATES 4
+#define IWL_OFDM_RATES 8
+
+#if IWL == 3945
+#define IWL_HT_RATES 0
+#elif IWL == 4965
+#define IWL_HT_RATES 16
+#endif
+
+#define IWL_MAX_RATES  (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES)
+
+/* Time constants */
+#define SHORT_SLOT_TIME 9
+#define LONG_SLOT_TIME 20
+
+/* RSSI to dBm */
+#if IWL == 3945
+#define IWL_RSSI_OFFSET	95
+#elif IWL == 4965
+#define IWL_RSSI_OFFSET	44
+#endif
+
+#include "iwl-eeprom.h"
+#include "iwl-commands.h"
+
+#define PCI_LINK_CTRL      0x0F0
+#define PCI_POWER_SOURCE   0x0C8
+#define PCI_REG_WUM8       0x0E8
+#define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT         (0x80000000)
+
+/*=== CSR (control and status registers) ===*/
+#define CSR_BASE    (0x000)
+
+#define CSR_SW_VER              (CSR_BASE+0x000)
+#define CSR_HW_IF_CONFIG_REG    (CSR_BASE+0x000) /* hardware interface config */
+#define CSR_INT_COALESCING      (CSR_BASE+0x004) /* accum ints, 32-usec units */
+#define CSR_INT                 (CSR_BASE+0x008) /* host interrupt status/ack */
+#define CSR_INT_MASK            (CSR_BASE+0x00c) /* host interrupt enable */
+#define CSR_FH_INT_STATUS       (CSR_BASE+0x010) /* busmaster int status/ack*/
+#define CSR_GPIO_IN             (CSR_BASE+0x018) /* read external chip pins */
+#define CSR_RESET               (CSR_BASE+0x020) /* busmaster enable, NMI, etc*/
+#define CSR_GP_CNTRL            (CSR_BASE+0x024)
+#define CSR_HW_REV              (CSR_BASE+0x028)
+#define CSR_EEPROM_REG          (CSR_BASE+0x02c)
+#define CSR_EEPROM_GP           (CSR_BASE+0x030)
+#define CSR_GP_UCODE		(CSR_BASE+0x044)
+#define CSR_UCODE_DRV_GP1       (CSR_BASE+0x054)
+#define CSR_UCODE_DRV_GP1_SET   (CSR_BASE+0x058)
+#define CSR_UCODE_DRV_GP1_CLR   (CSR_BASE+0x05c)
+#define CSR_UCODE_DRV_GP2       (CSR_BASE+0x060)
+#define CSR_LED_REG		(CSR_BASE+0x094)
+#define CSR_DRAM_INT_TBL_CTL	(CSR_BASE+0x0A0)
+#define CSR_GIO_CHICKEN_BITS    (CSR_BASE+0x100)
+#define CSR_ANA_PLL_CFG         (CSR_BASE+0x20c)
+#define CSR_HW_REV_WA_REG	(CSR_BASE+0x22C)
+
+/* HW I/F configuration */
+#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MB         (0x00000100)
+#define CSR_HW_IF_CONFIG_REG_BIT_ALMAGOR_MM         (0x00000200)
+#define CSR_HW_IF_CONFIG_REG_BIT_SKU_MRC            (0x00000400)
+#define CSR_HW_IF_CONFIG_REG_BIT_BOARD_TYPE         (0x00000800)
+#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A    (0x00000000)
+#define CSR_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B    (0x00001000)
+#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM     (0x00200000)
+
+/* interrupt flags in INTA, set by uCode or hardware (e.g. dma),
+ * acknowledged (reset) by host writing "1" to flagged bits. */
+#define CSR_INT_BIT_FH_RX        (1<<31) /* Rx DMA, cmd responses, FH_INT[17:16] */
+#define CSR_INT_BIT_HW_ERR       (1<<29) /* DMA hardware error FH_INT[31] */
+#define CSR_INT_BIT_DNLD         (1<<28) /* uCode Download */
+#define CSR_INT_BIT_FH_TX        (1<<27) /* Tx DMA FH_INT[1:0] */
+#define CSR_INT_BIT_MAC_CLK_ACTV (1<<26) /* NIC controller's clock toggled on/off */
+#define CSR_INT_BIT_SW_ERR       (1<<25) /* uCode error */
+#define CSR_INT_BIT_RF_KILL      (1<<7)  /* HW RFKILL switch GP_CNTRL[27] toggled */
+#define CSR_INT_BIT_CT_KILL      (1<<6)  /* Critical temp (chip too hot) rfkill */
+#define CSR_INT_BIT_SW_RX        (1<<3)  /* Rx, command responses, 3945 */
+#define CSR_INT_BIT_WAKEUP       (1<<1)  /* NIC controller waking up (pwr mgmt) */
+#define CSR_INT_BIT_ALIVE        (1<<0)  /* uCode interrupts once it initializes */
+
+#define CSR_INI_SET_MASK	(CSR_INT_BIT_FH_RX   | \
+				 CSR_INT_BIT_HW_ERR  | \
+				 CSR_INT_BIT_FH_TX   | \
+				 CSR_INT_BIT_SW_ERR  | \
+				 CSR_INT_BIT_RF_KILL | \
+				 CSR_INT_BIT_SW_RX   | \
+				 CSR_INT_BIT_WAKEUP  | \
+				 CSR_INT_BIT_ALIVE)
+
+/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
+#define CSR_FH_INT_BIT_ERR       (1<<31) /* Error */
+#define CSR_FH_INT_BIT_HI_PRIOR  (1<<30) /* High priority Rx, bypass coalescing */
+#define CSR_FH_INT_BIT_RX_CHNL2  (1<<18) /* Rx channel 2 (3945 only) */
+#define CSR_FH_INT_BIT_RX_CHNL1  (1<<17) /* Rx channel 1 */
+#define CSR_FH_INT_BIT_RX_CHNL0  (1<<16) /* Rx channel 0 */
+#define CSR_FH_INT_BIT_TX_CHNL6  (1<<6)  /* Tx channel 6 (3945 only) */
+#define CSR_FH_INT_BIT_TX_CHNL1  (1<<1)  /* Tx channel 1 */
+#define CSR_FH_INT_BIT_TX_CHNL0  (1<<0)  /* Tx channel 0 */
+
+#define CSR_FH_INT_RX_MASK	(CSR_FH_INT_BIT_HI_PRIOR | \
+				 CSR_FH_INT_BIT_RX_CHNL2 | \
+				 CSR_FH_INT_BIT_RX_CHNL1 | \
+				 CSR_FH_INT_BIT_RX_CHNL0)
+
+#define CSR_FH_INT_TX_MASK	(CSR_FH_INT_BIT_TX_CHNL6 | \
+				 CSR_FH_INT_BIT_TX_CHNL1 | \
+				 CSR_FH_INT_BIT_TX_CHNL0 )
+
+
+/* RESET */
+#define CSR_RESET_REG_FLAG_NEVO_RESET                (0x00000001)
+#define CSR_RESET_REG_FLAG_FORCE_NMI                 (0x00000002)
+#define CSR_RESET_REG_FLAG_SW_RESET                  (0x00000080)
+#define CSR_RESET_REG_FLAG_MASTER_DISABLED           (0x00000100)
+#define CSR_RESET_REG_FLAG_STOP_MASTER               (0x00000200)
+
+/* GP (general purpose) CONTROL */
+#define CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY        (0x00000001)
+#define CSR_GP_CNTRL_REG_FLAG_INIT_DONE              (0x00000004)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ         (0x00000008)
+#define CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP         (0x00000010)
+
+#define CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN           (0x00000001)
+
+#define CSR_GP_CNTRL_REG_MSK_POWER_SAVE_TYPE         (0x07000000)
+#define CSR_GP_CNTRL_REG_FLAG_MAC_POWER_SAVE         (0x04000000)
+#define CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW          (0x08000000)
+
+
+/* EEPROM REG */
+#define CSR_EEPROM_REG_READ_VALID_MSK	(0x00000001)
+#define CSR_EEPROM_REG_BIT_CMD		(0x00000002)
+
+/* EEPROM GP */
+#define CSR_EEPROM_GP_VALID_MSK		(0x00000006)
+#define CSR_EEPROM_GP_BAD_SIGNATURE	(0x00000000)
+#define CSR_EEPROM_GP_IF_OWNER_MSK	(0x00000180)
+
+/* UCODE DRV GP */
+#define CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP             (0x00000001)
+#define CSR_UCODE_SW_BIT_RFKILL                     (0x00000002)
+#define CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED           (0x00000004)
+#define CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT      (0x00000008)
+
+/* GPIO */
+#define CSR_GPIO_IN_BIT_AUX_POWER                   (0x00000200)
+#define CSR_GPIO_IN_VAL_VAUX_PWR_SRC                (0x00000000)
+#define CSR_GPIO_IN_VAL_VMAIN_PWR_SRC		CSR_GPIO_IN_BIT_AUX_POWER
+
+/* GI Chicken Bits */
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX  (0x00800000)
+#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER  (0x20000000)
+
+/* CSR_ANA_PLL_CFG */
+#define CSR_ANA_PLL_CFG_SH		(0x00880300)
+
+#define CSR_LED_REG_TRUN_ON		(0x00000078)
+#define CSR_LED_REG_TRUN_OFF		(0x00000038)
+#define CSR_LED_BSM_CTRL_MSK		(0xFFFFFFDF)
+
+/* DRAM_INT_TBL_CTRL */
+#define CSR_DRAM_INT_TBL_CTRL_EN	(1<<31)
+#define CSR_DRAM_INT_TBL_CTRL_WRAP_CHK	(1<<27)
+
+/*=== HBUS (Host-side Bus) ===*/
+#define HBUS_BASE	(0x400)
+
+#define HBUS_TARG_MEM_RADDR     (HBUS_BASE+0x00c)
+#define HBUS_TARG_MEM_WADDR     (HBUS_BASE+0x010)
+#define HBUS_TARG_MEM_WDAT      (HBUS_BASE+0x018)
+#define HBUS_TARG_MEM_RDAT      (HBUS_BASE+0x01c)
+#define HBUS_TARG_PRPH_WADDR    (HBUS_BASE+0x044)
+#define HBUS_TARG_PRPH_RADDR    (HBUS_BASE+0x048)
+#define HBUS_TARG_PRPH_WDAT     (HBUS_BASE+0x04c)
+#define HBUS_TARG_PRPH_RDAT     (HBUS_BASE+0x050)
+#define HBUS_TARG_WRPTR         (HBUS_BASE+0x060)
+
+#define HBUS_TARG_MBX_C         (HBUS_BASE+0x030)
+
+
+/* SCD (Scheduler) */
+#define SCD_BASE                        (CSR_BASE + 0x2E00)
+
+#define SCD_MODE_REG                    (SCD_BASE + 0x000)
+#define SCD_ARASTAT_REG                 (SCD_BASE + 0x004)
+#define SCD_TXFACT_REG                  (SCD_BASE + 0x010)
+#define SCD_TXF4MF_REG                  (SCD_BASE + 0x014)
+#define SCD_TXF5MF_REG                  (SCD_BASE + 0x020)
+#define SCD_SBYP_MODE_1_REG             (SCD_BASE + 0x02C)
+#define SCD_SBYP_MODE_2_REG             (SCD_BASE + 0x030)
+
+/*=== FH (data Flow Handler) ===*/
+#define FH_BASE     (0x800)
+
+#define FH_CBCC_TABLE           (FH_BASE+0x140)
+#define FH_TFDB_TABLE           (FH_BASE+0x180)
+#define FH_RCSR_TABLE           (FH_BASE+0x400)
+#define FH_RSSR_TABLE           (FH_BASE+0x4c0)
+#define FH_TCSR_TABLE           (FH_BASE+0x500)
+#define FH_TSSR_TABLE           (FH_BASE+0x680)
+
+/* TFDB (Transmit Frame Buffer Descriptor) */
+#define FH_TFDB(_channel, buf) \
+	(FH_TFDB_TABLE+((_channel)*2+(buf))*0x28)
+#define ALM_FH_TFDB_CHNL_BUF_CTRL_REG(_channel) \
+	(FH_TFDB_TABLE + 0x50 * _channel)
+/* CBCC _channel is [0,2] */
+#define FH_CBCC(_channel)           (FH_CBCC_TABLE+(_channel)*0x8)
+#define FH_CBCC_CTRL(_channel)      (FH_CBCC(_channel)+0x00)
+#define FH_CBCC_BASE(_channel)      (FH_CBCC(_channel)+0x04)
+
+/* RCSR _channel is [0,2] */
+#define FH_RCSR(_channel)           (FH_RCSR_TABLE+(_channel)*0x40)
+#define FH_RCSR_CONFIG(_channel)    (FH_RCSR(_channel)+0x00)
+#define FH_RCSR_RBD_BASE(_channel)  (FH_RCSR(_channel)+0x04)
+#define FH_RCSR_WPTR(_channel)      (FH_RCSR(_channel)+0x20)
+#define FH_RCSR_RPTR_ADDR(_channel) (FH_RCSR(_channel)+0x24)
+
+#if IWL == 3945
+#define FH_RSCSR_CHNL0_WPTR        (FH_RCSR_WPTR(0))
+#elif IWL == 4965
+#define FH_RSCSR_CHNL0_WPTR        (FH_RSCSR_CHNL0_RBDCB_WPTR_REG)
+#endif
+
+/* RSSR */
+#define FH_RSSR_CTRL            (FH_RSSR_TABLE+0x000)
+#define FH_RSSR_STATUS          (FH_RSSR_TABLE+0x004)
+/* TCSR */
+#define FH_TCSR(_channel)           (FH_TCSR_TABLE+(_channel)*0x20)
+#define FH_TCSR_CONFIG(_channel)    (FH_TCSR(_channel)+0x00)
+#define FH_TCSR_CREDIT(_channel)    (FH_TCSR(_channel)+0x04)
+#define FH_TCSR_BUFF_STTS(_channel) (FH_TCSR(_channel)+0x08)
+/* TSSR */
+#define FH_TSSR_CBB_BASE        (FH_TSSR_TABLE+0x000)
+#define FH_TSSR_MSG_CONFIG      (FH_TSSR_TABLE+0x008)
+#define FH_TSSR_TX_STATUS       (FH_TSSR_TABLE+0x010)
+/* 18 - reserved */
+
+/* card static random access memory (SRAM) for processor data and instructs */
+#define RTC_INST_LOWER_BOUND			(0x000000)
+#define RTC_DATA_LOWER_BOUND			(0x800000)
+
+
+/* DBM */
+
+#define ALM_FH_SRVC_CHNL                            (6)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_POS_RBDC_SIZE     (20)
+#define ALM_FH_RCSR_RX_CONFIG_REG_POS_IRQ_RBTH      (4)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_BIT_WR_STTS_EN    (0x08000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_DMA_CHNL_EN_ENABLE        (0x80000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_RDRBD_EN_ENABLE           (0x20000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MAX_FRAG_SIZE_128         (0x01000000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_IRQ_DEST_INT_HOST         (0x00001000)
+
+#define ALM_FH_RCSR_RX_CONFIG_REG_VAL_MSG_MODE_FH               (0x00000000)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF              (0x00000000)
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRIVER           (0x00000001)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL    (0x00000000)
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL     (0x00000008)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD           (0x00200000)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT            (0x00000000)
+
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE            (0x00000000)
+#define ALM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE           (0x80000000)
+
+#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID          (0x00004000)
+
+#define ALM_FH_TCSR_CHNL_TX_BUF_STS_REG_BIT_TFDB_WPTR           (0x00000001)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TXPD_ON      (0xFF000000)
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_TXPD_ON      (0x00FF0000)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_MAX_FRAG_SIZE_128B    (0x00000400)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_SNOOP_RD_TFD_ON       (0x00000100)
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RD_CBB_ON       (0x00000080)
+
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_ORDER_RSP_WAIT_TH     (0x00000020)
+#define ALM_FH_TSSR_TX_MSG_CONFIG_REG_VAL_RSP_WAIT_TH           (0x00000005)
+
+#define ALM_TB_MAX_BYTES_COUNT      (0xFFF0)
+
+#define ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) \
+	((1LU << _channel) << 24)
+#define ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel) \
+	((1LU << _channel) << 16)
+
+#define ALM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(_channel) \
+	(ALM_FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_channel) | \
+	 ALM_FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_channel))
+#define PCI_CFG_REV_ID_BIT_BASIC_SKU                (0x40)	/* bit 6    */
+#define PCI_CFG_REV_ID_BIT_RTP                      (0x80)	/* bit 7    */
+
+#define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED         (0x00000004)
+
+#define TFD_QUEUE_MIN           0
+#define TFD_QUEUE_MAX           6
+#define TFD_QUEUE_SIZE_MAX      (256)
+
+/* spectrum and channel data structures */
+#define IWL_NUM_SCAN_RATES         (2)
+
+#define IWL_SCAN_FLAG_24GHZ  (1<<0)
+#define IWL_SCAN_FLAG_52GHZ  (1<<1)
+#define IWL_SCAN_FLAG_ACTIVE (1<<2)
+#define IWL_SCAN_FLAG_DIRECT (1<<3)
+
+#define IWL_MAX_CMD_SIZE 1024
+
+#define IWL_DEFAULT_TX_RETRY  15
+#define IWL_MAX_TX_RETRY      16
+
+/*********************************************/
+
+#define RFD_SIZE                              4
+#define NUM_TFD_CHUNKS                        4
+
+#define RX_QUEUE_SIZE                         256
+#define RX_QUEUE_MASK                         255
+#define RX_QUEUE_SIZE_LOG                     8
+
+/* QoS  definitions */
+
+#define CW_MIN_OFDM          15
+#define CW_MAX_OFDM          1023
+#define CW_MIN_CCK           31
+#define CW_MAX_CCK           1023
+
+#define QOS_TX0_CW_MIN_OFDM      CW_MIN_OFDM
+#define QOS_TX1_CW_MIN_OFDM      CW_MIN_OFDM
+#define QOS_TX2_CW_MIN_OFDM      ((CW_MIN_OFDM + 1) / 2 - 1)
+#define QOS_TX3_CW_MIN_OFDM      ((CW_MIN_OFDM + 1) / 4 - 1)
+
+#define QOS_TX0_CW_MIN_CCK       CW_MIN_CCK
+#define QOS_TX1_CW_MIN_CCK       CW_MIN_CCK
+#define QOS_TX2_CW_MIN_CCK       ((CW_MIN_CCK + 1) / 2 - 1)
+#define QOS_TX3_CW_MIN_CCK       ((CW_MIN_CCK + 1) / 4 - 1)
+
+#define QOS_TX0_CW_MAX_OFDM      CW_MAX_OFDM
+#define QOS_TX1_CW_MAX_OFDM      CW_MAX_OFDM
+#define QOS_TX2_CW_MAX_OFDM      CW_MIN_OFDM
+#define QOS_TX3_CW_MAX_OFDM      ((CW_MIN_OFDM + 1) / 2 - 1)
+
+#define QOS_TX0_CW_MAX_CCK       CW_MAX_CCK
+#define QOS_TX1_CW_MAX_CCK       CW_MAX_CCK
+#define QOS_TX2_CW_MAX_CCK       CW_MIN_CCK
+#define QOS_TX3_CW_MAX_CCK       ((CW_MIN_CCK + 1) / 2 - 1)
+
+#define QOS_TX0_AIFS            3
+#define QOS_TX1_AIFS            7
+#define QOS_TX2_AIFS            2
+#define QOS_TX3_AIFS            2
+
+#define QOS_TX0_ACM             0
+#define QOS_TX1_ACM             0
+#define QOS_TX2_ACM             0
+#define QOS_TX3_ACM             0
+
+#define QOS_TX0_TXOP_LIMIT_CCK          0
+#define QOS_TX1_TXOP_LIMIT_CCK          0
+#define QOS_TX2_TXOP_LIMIT_CCK          6016
+#define QOS_TX3_TXOP_LIMIT_CCK          3264
+
+#define QOS_TX0_TXOP_LIMIT_OFDM      0
+#define QOS_TX1_TXOP_LIMIT_OFDM      0
+#define QOS_TX2_TXOP_LIMIT_OFDM      3008
+#define QOS_TX3_TXOP_LIMIT_OFDM      1504
+
+#define DEF_TX0_CW_MIN_OFDM      CW_MIN_OFDM
+#define DEF_TX1_CW_MIN_OFDM      CW_MIN_OFDM
+#define DEF_TX2_CW_MIN_OFDM      CW_MIN_OFDM
+#define DEF_TX3_CW_MIN_OFDM      CW_MIN_OFDM
+
+#define DEF_TX0_CW_MIN_CCK       CW_MIN_CCK
+#define DEF_TX1_CW_MIN_CCK       CW_MIN_CCK
+#define DEF_TX2_CW_MIN_CCK       CW_MIN_CCK
+#define DEF_TX3_CW_MIN_CCK       CW_MIN_CCK
+
+#define DEF_TX0_CW_MAX_OFDM      CW_MAX_OFDM
+#define DEF_TX1_CW_MAX_OFDM      CW_MAX_OFDM
+#define DEF_TX2_CW_MAX_OFDM      CW_MAX_OFDM
+#define DEF_TX3_CW_MAX_OFDM      CW_MAX_OFDM
+
+#define DEF_TX0_CW_MAX_CCK       CW_MAX_CCK
+#define DEF_TX1_CW_MAX_CCK       CW_MAX_CCK
+#define DEF_TX2_CW_MAX_CCK       CW_MAX_CCK
+#define DEF_TX3_CW_MAX_CCK       CW_MAX_CCK
+
+#define DEF_TX0_AIFS            (2)
+#define DEF_TX1_AIFS            (2)
+#define DEF_TX2_AIFS            (2)
+#define DEF_TX3_AIFS            (2)
+
+#define DEF_TX0_ACM             0
+#define DEF_TX1_ACM             0
+#define DEF_TX2_ACM             0
+#define DEF_TX3_ACM             0
+
+#define DEF_TX0_TXOP_LIMIT_CCK        0
+#define DEF_TX1_TXOP_LIMIT_CCK        0
+#define DEF_TX2_TXOP_LIMIT_CCK        0
+#define DEF_TX3_TXOP_LIMIT_CCK        0
+
+#define DEF_TX0_TXOP_LIMIT_OFDM       0
+#define DEF_TX1_TXOP_LIMIT_OFDM       0
+#define DEF_TX2_TXOP_LIMIT_OFDM       0
+#define DEF_TX3_TXOP_LIMIT_OFDM       0
+
+#define QOS_QOS_SETS                  3
+#define QOS_PARAM_SET_ACTIVE          0
+#define QOS_PARAM_SET_DEF_CCK         1
+#define QOS_PARAM_SET_DEF_OFDM        2
+
+#define CTRL_QOS_NO_ACK               (0x0020)
+#define DCT_FLAG_EXT_QOS_ENABLED      (0x10)
+
+#define U32_PAD(n)		((4-(n))&0x3)
+
+/*
+ * Generic queue structure
+ *
+ * Contains common data for Rx and Tx queues
+ */
+#define TFD_CTL_COUNT_SET(n)       (n<<24)
+#define TFD_CTL_COUNT_GET(ctl)     ((ctl>>24) & 7)
+#define TFD_CTL_PAD_SET(n)         (n<<28)
+#define TFD_CTL_PAD_GET(ctl)       (ctl>>28)
+
+#define TFD_TX_CMD_SLOTS 256
+#define TFD_CMD_SLOTS 32
+
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \
+			      sizeof(struct iwl_cmd_meta))
+
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
+
+#endif				/* __iwlwifi_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
new file mode 100644
index 0000000..8a8b96fc
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -0,0 +1,470 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_io_h__
+#define __iwl_io_h__
+
+#include <linux/io.h>
+
+#include "iwl-debug.h"
+
+/*
+ * IO, register, and NIC memory access functions
+ *
+ * NOTE on naming convention and macro usage for these
+ *
+ * A single _ prefix before a an access function means that no state
+ * check or debug information is printed when that function is called.
+ *
+ * A double __ prefix before an access function means that state is checked
+ * (in the case of *restricted calls) and the current line number is printed
+ * in addition to any other debug output.
+ *
+ * The non-prefixed name is the #define that maps the caller into a
+ * #define that provides the caller's __LINE__ to the double prefix version.
+ *
+ * If you wish to call the function without any debug or state checking,
+ * you should use the single _ prefix version (as is used by dependent IO
+ * routines, for example _iwl_read_restricted calls the non-check version of
+ * _iwl_read32.)
+ *
+ * These declarations are *extremely* useful in quickly isolating code deltas
+ * which result in misconfiguring of the hardware I/O.  In combination with
+ * git-bisect and the IO debug level you can quickly determine the specific
+ * commit which breaks the IO sequence to the hardware.
+ *
+ */
+
+#define _iwl_write32(iwl, ofs, val) writel((val), (iwl)->hw_base + (ofs))
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *iwl,
+				 u32 ofs, u32 val)
+{
+	IWL_DEBUG_IO("write_direct32(0x%08X, 0x%08X) - %s %d\n",
+		     (u32) (ofs), (u32) (val), f, l);
+	_iwl_write32(iwl, ofs, val);
+}
+#define iwl_write32(iwl, ofs, val) \
+	__iwl_write32(__FILE__, __LINE__, iwl, ofs, val)
+#else
+#define iwl_write32(iwl, ofs, val) _iwl_write32(iwl, ofs, val)
+#endif
+
+#define _iwl_read32(iwl, ofs) readl((iwl)->hw_base + (ofs))
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *iwl, u32 ofs)
+{
+	IWL_DEBUG_IO("read_direct32(0x%08X) - %s %d\n", ofs, f, l);
+	return _iwl_read32(iwl, ofs);
+}
+#define iwl_read32(iwl, ofs) __iwl_read32(__FILE__, __LINE__, iwl, ofs)
+#else
+#define iwl_read32(p, o) _iwl_read32(p, o)
+#endif
+
+static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr,
+				u32 bits, u32 mask, int timeout)
+{
+	int i = 0;
+
+	do {
+		if ((_iwl_read32(priv, addr) & mask) == (bits & mask))
+			return i;
+		mdelay(10);
+		i += 10;
+	} while (i < timeout);
+
+	return -ETIMEDOUT;
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline int __iwl_poll_bit(const char *f, u32 l,
+				 struct iwl_priv *priv, u32 addr,
+				 u32 bits, u32 mask, int timeout)
+{
+	int rc = _iwl_poll_bit(priv, addr, bits, mask, timeout);
+	if (unlikely(rc == -ETIMEDOUT))
+		IWL_DEBUG_IO
+		    ("poll_bit(0x%08X, 0x%08X, 0x%08X) - timedout - %s %d\n",
+		     addr, bits, mask, f, l);
+	else
+		IWL_DEBUG_IO
+		    ("poll_bit(0x%08X, 0x%08X, 0x%08X) = 0x%08X - %s %d\n",
+		     addr, bits, mask, rc, f, l);
+	return rc;
+}
+#define iwl_poll_bit(iwl, addr, bits, mask, timeout) \
+	__iwl_poll_bit(__FILE__, __LINE__, iwl, addr, bits, mask, timeout)
+#else
+#define iwl_poll_bit(p, a, b, m, t) _iwl_poll_bit(p, a, b, m, t)
+#endif
+
+static inline void _iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+	_iwl_write32(priv, reg, _iwl_read32(priv, reg) | mask);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_set_bit(const char *f, u32 l,
+				 struct iwl_priv *priv, u32 reg, u32 mask)
+{
+	u32 val = _iwl_read32(priv, reg) | mask;
+	IWL_DEBUG_IO("set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
+	_iwl_write32(priv, reg, val);
+}
+#define iwl_set_bit(p, r, m) __iwl_set_bit(__FILE__, __LINE__, p, r, m)
+#else
+#define iwl_set_bit(p, r, m) _iwl_set_bit(p, r, m)
+#endif
+
+static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+	_iwl_write32(priv, reg, _iwl_read32(priv, reg) & ~mask);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_clear_bit(const char *f, u32 l,
+				   struct iwl_priv *priv, u32 reg, u32 mask)
+{
+	u32 val = _iwl_read32(priv, reg) & ~mask;
+	IWL_DEBUG_IO("clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
+	_iwl_write32(priv, reg, val);
+}
+#define iwl_clear_bit(p, r, m) __iwl_clear_bit(__FILE__, __LINE__, p, r, m)
+#else
+#define iwl_clear_bit(p, r, m) _iwl_clear_bit(p, r, m)
+#endif
+
+static inline int _iwl_grab_restricted_access(struct iwl_priv *priv)
+{
+	int rc;
+	u32 gp_ctl;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (atomic_read(&priv->restrict_refcnt))
+		return 0;
+#endif
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status) ||
+	    test_bit(STATUS_RF_KILL_SW, &priv->status)) {
+		IWL_WARNING("WARNING: Requesting MAC access during RFKILL "
+			"wakes up NIC\n");
+
+		/* 10 msec allows time for NIC to complete its data save */
+		gp_ctl = _iwl_read32(priv, CSR_GP_CNTRL);
+		if (gp_ctl & CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY) {
+			IWL_DEBUG_RF_KILL("Wait for complete power-down, "
+				"gpctl = 0x%08x\n", gp_ctl);
+			mdelay(10);
+		} else
+			IWL_DEBUG_RF_KILL("power-down complete, "
+					  "gpctl = 0x%08x\n", gp_ctl);
+	}
+
+	/* this bit wakes up the NIC */
+	_iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+	rc = _iwl_poll_bit(priv, CSR_GP_CNTRL,
+			   CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
+			   (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
+			    CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 50);
+	if (rc < 0) {
+		IWL_ERROR("MAC is in deep sleep!\n");
+		return -EIO;
+	}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	atomic_inc(&priv->restrict_refcnt);
+#endif
+	return 0;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline int __iwl_grab_restricted_access(const char *f, u32 l,
+					       struct iwl_priv *priv)
+{
+	if (atomic_read(&priv->restrict_refcnt))
+		IWL_DEBUG_INFO("Grabbing access while already held at "
+			       "line %d.\n", l);
+
+	IWL_DEBUG_IO("grabbing restricted access - %s %d\n", f, l);
+
+	return _iwl_grab_restricted_access(priv);
+}
+#define iwl_grab_restricted_access(priv) \
+	__iwl_grab_restricted_access(__FILE__, __LINE__, priv)
+#else
+#define iwl_grab_restricted_access(priv) \
+	_iwl_grab_restricted_access(priv)
+#endif
+
+static inline void _iwl_release_restricted_access(struct iwl_priv *priv)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (atomic_dec_and_test(&priv->restrict_refcnt))
+#endif
+		_iwl_clear_bit(priv, CSR_GP_CNTRL,
+			       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_release_restricted_access(const char *f, u32 l,
+						   struct iwl_priv *priv)
+{
+	if (atomic_read(&priv->restrict_refcnt) <= 0)
+		IWL_ERROR("Release unheld restricted access at line %d.\n", l);
+
+	IWL_DEBUG_IO("releasing restricted access - %s %d\n", f, l);
+	_iwl_release_restricted_access(priv);
+}
+#define iwl_release_restricted_access(priv) \
+	__iwl_release_restricted_access(__FILE__, __LINE__, priv)
+#else
+#define iwl_release_restricted_access(priv) \
+	_iwl_release_restricted_access(priv)
+#endif
+
+static inline u32 _iwl_read_restricted(struct iwl_priv *priv, u32 reg)
+{
+	return _iwl_read32(priv, reg);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline u32 __iwl_read_restricted(const char *f, u32 l,
+					struct iwl_priv *priv, u32 reg)
+{
+	u32 value = _iwl_read_restricted(priv, reg);
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Unrestricted access from %s %d\n", f, l);
+	IWL_DEBUG_IO("read_restricted(0x%4X) = 0x%08x - %s %d \n", reg, value,
+		     f, l);
+	return value;
+}
+#define iwl_read_restricted(priv, reg) \
+	__iwl_read_restricted(__FILE__, __LINE__, priv, reg)
+#else
+#define iwl_read_restricted _iwl_read_restricted
+#endif
+
+static inline void _iwl_write_restricted(struct iwl_priv *priv,
+					 u32 reg, u32 value)
+{
+	_iwl_write32(priv, reg, value);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static void __iwl_write_restricted(u32 line,
+				   struct iwl_priv *priv, u32 reg, u32 value)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Unrestricted access from line %d\n", line);
+	_iwl_write_restricted(priv, reg, value);
+}
+#define iwl_write_restricted(priv, reg, value) \
+	__iwl_write_restricted(__LINE__, priv, reg, value)
+#else
+#define iwl_write_restricted _iwl_write_restricted
+#endif
+
+static inline void iwl_write_buffer_restricted(struct iwl_priv *priv,
+					       u32 reg, u32 len, u32 *values)
+{
+	u32 count = sizeof(u32);
+
+	if ((priv != NULL) && (values != NULL)) {
+		for (; 0 < len; len -= count, reg += count, values++)
+			_iwl_write_restricted(priv, reg, *values);
+	}
+}
+
+static inline int _iwl_poll_restricted_bit(struct iwl_priv *priv,
+					   u32 addr, u32 mask, int timeout)
+{
+	int i = 0;
+
+	do {
+		if ((_iwl_read_restricted(priv, addr) & mask) == mask)
+			return i;
+		mdelay(10);
+		i += 10;
+	} while (i < timeout);
+
+	return -ETIMEDOUT;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline int __iwl_poll_restricted_bit(const char *f, u32 l,
+					    struct iwl_priv *priv,
+					    u32 addr, u32 mask, int timeout)
+{
+	int rc = _iwl_poll_restricted_bit(priv, addr, mask, timeout);
+
+	if (unlikely(rc == -ETIMEDOUT))
+		IWL_DEBUG_IO("poll_restricted_bit(0x%08X, 0x%08X) - "
+			     "timedout - %s %d\n", addr, mask, f, l);
+	else
+		IWL_DEBUG_IO("poll_restricted_bit(0x%08X, 0x%08X) = 0x%08X "
+			     "- %s %d\n", addr, mask, rc, f, l);
+	return rc;
+}
+#define iwl_poll_restricted_bit(iwl, addr, mask, timeout) \
+	__iwl_poll_restricted_bit(__FILE__, __LINE__, iwl, addr, mask, timeout)
+#else
+#define iwl_poll_restricted_bit _iwl_poll_restricted_bit
+#endif
+
+static inline u32 _iwl_read_restricted_reg(struct iwl_priv *priv, u32 reg)
+{
+	_iwl_write_restricted(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
+	return _iwl_read_restricted(priv, HBUS_TARG_PRPH_RDAT);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline u32 __iwl_read_restricted_reg(u32 line,
+					    struct iwl_priv *priv, u32 reg)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Unrestricted access from line %d\n", line);
+	return _iwl_read_restricted_reg(priv, reg);
+}
+
+#define iwl_read_restricted_reg(priv, reg) \
+	__iwl_read_restricted_reg(__LINE__, priv, reg)
+#else
+#define iwl_read_restricted_reg _iwl_read_restricted_reg
+#endif
+
+static inline void _iwl_write_restricted_reg(struct iwl_priv *priv,
+					     u32 addr, u32 val)
+{
+	_iwl_write_restricted(priv, HBUS_TARG_PRPH_WADDR,
+			      ((addr & 0x0000FFFF) | (3 << 24)));
+	_iwl_write_restricted(priv, HBUS_TARG_PRPH_WDAT, val);
+}
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_write_restricted_reg(u32 line,
+					      struct iwl_priv *priv,
+					      u32 addr, u32 val)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Unrestricted access from line %d\n", line);
+	_iwl_write_restricted_reg(priv, addr, val);
+}
+
+#define iwl_write_restricted_reg(priv, addr, val) \
+	__iwl_write_restricted_reg(__LINE__, priv, addr, val);
+#else
+#define iwl_write_restricted_reg _iwl_write_restricted_reg
+#endif
+
+#define _iwl_set_bits_restricted_reg(priv, reg, mask) \
+	_iwl_write_restricted_reg(priv, reg, \
+				  (_iwl_read_restricted_reg(priv, reg) | mask))
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_set_bits_restricted_reg(u32 line, struct iwl_priv
+						 *priv, u32 reg, u32 mask)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Unrestricted access from line %d\n", line);
+	_iwl_set_bits_restricted_reg(priv, reg, mask);
+}
+#define iwl_set_bits_restricted_reg(priv, reg, mask) \
+	__iwl_set_bits_restricted_reg(__LINE__, priv, reg, mask)
+#else
+#define iwl_set_bits_restricted_reg _iwl_set_bits_restricted_reg
+#endif
+
+#define _iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask) \
+	_iwl_write_restricted_reg( \
+	    priv, reg, ((_iwl_read_restricted_reg(priv, reg) & mask) | bits))
+#ifdef CONFIG_IWLWIFI_DEBUG
+static inline void __iwl_set_bits_mask_restricted_reg(u32 line,
+		struct iwl_priv *priv, u32 reg, u32 bits, u32 mask)
+{
+	if (!atomic_read(&priv->restrict_refcnt))
+		IWL_ERROR("Unrestricted access from line %d\n", line);
+	_iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask);
+}
+
+#define iwl_set_bits_mask_restricted_reg(priv, reg, bits, mask) \
+	__iwl_set_bits_mask_restricted_reg(__LINE__, priv, reg, bits, mask)
+#else
+#define iwl_set_bits_mask_restricted_reg _iwl_set_bits_mask_restricted_reg
+#endif
+
+static inline void iwl_clear_bits_restricted_reg(struct iwl_priv
+						 *priv, u32 reg, u32 mask)
+{
+	u32 val = _iwl_read_restricted_reg(priv, reg);
+	_iwl_write_restricted_reg(priv, reg, (val & ~mask));
+}
+
+static inline u32 iwl_read_restricted_mem(struct iwl_priv *priv, u32 addr)
+{
+	iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, addr);
+	return iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+}
+
+static inline void iwl_write_restricted_mem(struct iwl_priv *priv, u32 addr,
+					    u32 val)
+{
+	iwl_write_restricted(priv, HBUS_TARG_MEM_WADDR, addr);
+	iwl_write_restricted(priv, HBUS_TARG_MEM_WDAT, val);
+}
+
+static inline void iwl_write_restricted_mems(struct iwl_priv *priv, u32 addr,
+					     u32 len, u32 *values)
+{
+	iwl_write_restricted(priv, HBUS_TARG_MEM_WADDR, addr);
+	for (; 0 < len; len -= sizeof(u32), values++)
+		iwl_write_restricted(priv, HBUS_TARG_MEM_WDAT, *values);
+}
+
+static inline void iwl_write_restricted_regs(struct iwl_priv *priv, u32 reg,
+					     u32 len, u8 *values)
+{
+	u32 reg_offset = reg;
+	u32 aligment = reg & 0x3;
+
+	/* write any non-dword-aligned stuff at the beginning */
+	if (len < sizeof(u32)) {
+		if ((aligment + len) <= sizeof(u32)) {
+			u8 size;
+			u32 value = 0;
+			size = len - 1;
+			memcpy(&value, values, len);
+			reg_offset = (reg_offset & 0x0000FFFF);
+
+			_iwl_write_restricted(priv,
+					      HBUS_TARG_PRPH_WADDR,
+					      (reg_offset | (size << 24)));
+			_iwl_write_restricted(priv, HBUS_TARG_PRPH_WDAT,
+					      value);
+		}
+
+		return;
+	}
+
+	/* now write all the dword-aligned stuff */
+	for (; reg_offset < (reg + len);
+	     reg_offset += sizeof(u32), values += sizeof(u32))
+		_iwl_write_restricted_reg(priv, reg_offset, *((u32 *) values));
+}
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-priv.h b/drivers/net/wireless/iwlwifi/iwl-priv.h
new file mode 100644
index 0000000..6b490d0
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-priv.h
@@ -0,0 +1,308 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_priv_h__
+#define __iwl_priv_h__
+
+#include <linux/workqueue.h>
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+
+enum {
+	MEASUREMENT_READY = (1 << 0),
+	MEASUREMENT_ACTIVE = (1 << 1),
+};
+
+#endif
+
+struct iwl_priv {
+
+	/* ieee device used by generic ieee processing code */
+	struct ieee80211_hw *hw;
+	struct ieee80211_channel *ieee_channels;
+	struct ieee80211_rate *ieee_rates;
+
+	/* temporary frame storage list */
+	struct list_head free_frames;
+	int frames_count;
+
+	u8 phymode;
+	int alloc_rxb_skb;
+
+	void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
+				       struct iwl_rx_mem_buffer *rxb);
+
+	const struct ieee80211_hw_mode *modes;
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+	/* spectrum measurement report caching */
+	struct iwl_spectrum_notification measure_report;
+	u8 measurement_status;
+#endif
+	/* ucode beacon time */
+	u32 ucode_beacon_time;
+
+	/* we allocate array of iwl_channel_info for NIC's valid channels.
+	 *    Access via channel # using indirect index array */
+	struct iwl_channel_info *channel_info;	/* channel info array */
+	u8 channel_count;	/* # of channels */
+
+	/* each calibration channel group in the EEPROM has a derived
+	 * clip setting for each rate. */
+	const struct iwl_clip_group clip_groups[5];
+
+	/* thermal calibration */
+	s32 temperature;	/* degrees Kelvin */
+	s32 last_temperature;
+
+	/* Scan related variables */
+	unsigned long last_scan_jiffies;
+	unsigned long scan_start;
+	unsigned long scan_pass_start;
+	unsigned long scan_start_tsf;
+	int scan_bands;
+	int one_direct_scan;
+	u8 direct_ssid_len;
+	u8 direct_ssid[IW_ESSID_MAX_SIZE];
+	struct iwl_scan_cmd *scan;
+	u8 only_active_channel;
+
+	/* spinlock */
+	spinlock_t lock;	/* protect general shared data */
+	spinlock_t hcmd_lock;	/* protect hcmd */
+	struct mutex mutex;
+
+	/* basic pci-network driver stuff */
+	struct pci_dev *pci_dev;
+
+	/* pci hardware address support */
+	void __iomem *hw_base;
+
+	/* uCode images, save to reload in case of failure */
+	struct fw_image_desc ucode_code;	/* runtime inst */
+	struct fw_image_desc ucode_data;	/* runtime data original */
+	struct fw_image_desc ucode_data_backup;	/* runtime data save/restore */
+	struct fw_image_desc ucode_init;	/* initialization inst */
+	struct fw_image_desc ucode_init_data;	/* initialization data */
+	struct fw_image_desc ucode_boot;	/* bootstrap inst */
+
+
+	struct iwl_rxon_time_cmd rxon_timing;
+
+	/* We declare this const so it can only be
+	 * changed via explicit cast within the
+	 * routines that actually update the physical
+	 * hardware */
+	const struct iwl_rxon_cmd active_rxon;
+	struct iwl_rxon_cmd staging_rxon;
+
+	int error_recovering;
+	struct iwl_rxon_cmd recovery_rxon;
+
+	/* 1st responses from initialize and runtime uCode images.
+	 * 4965's initialize alive response contains some calibration data. */
+	struct iwl_init_alive_resp card_alive_init;
+	struct iwl_alive_resp card_alive;
+
+#ifdef LED
+	/* LED related variables */
+	struct iwl_activity_blink activity;
+	unsigned long led_packets;
+	int led_state;
+#endif
+
+	u16 active_rate;
+	u16 active_rate_basic;
+
+	u8 call_post_assoc_from_beacon;
+	u8 assoc_station_added;
+#if IWL == 4965
+	u8 use_ant_b_for_management_frame;	/* Tx antenna selection */
+	/* HT variables */
+	u8 is_dup;
+	u8 is_ht_enabled;
+	u8 channel_width;	/* 0=20MHZ, 1=40MHZ */
+	u8 current_channel_width;
+	u8 valid_antenna;	/* Bit mask of antennas actually connected */
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+	struct iwl_sensitivity_data sensitivity_data;
+	struct iwl_chain_noise_data chain_noise_data;
+	u8 start_calib;
+	__le16 sensitivity_tbl[HD_TABLE_SIZE];
+#endif /*CONFIG_IWLWIFI_SENSITIVITY*/
+
+#ifdef CONFIG_IWLWIFI_HT
+	struct sta_ht_info current_assoc_ht;
+#endif
+	u8 active_rate_ht[2];
+	u8 last_phy_res[100];
+
+	/* Rate scaling data */
+	struct iwl_lq_mngr lq_mngr;
+#endif
+
+	/* Rate scaling data */
+	s8 data_retry_limit;
+	u8 retry_rate;
+
+	wait_queue_head_t wait_command_queue;
+
+	int activity_timer_active;
+
+	/* Rx and Tx DMA processing queues */
+	struct iwl_rx_queue rxq;
+	struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES];
+#if IWL == 4965
+	unsigned long txq_ctx_active_msk;
+	struct iwl_kw kw;	/* keep warm address */
+	u32 scd_base_addr;	/* scheduler sram base address */
+#endif
+
+	unsigned long status;
+	u32 config;
+
+	int last_rx_rssi;	/* From Rx packet statisitics */
+	int last_rx_noise;	/* From beacon statistics */
+
+	struct iwl_power_mgr power_data;
+
+	struct iwl_notif_statistics statistics;
+	unsigned long last_statistics_time;
+
+	/* context information */
+	u8 essid[IW_ESSID_MAX_SIZE];
+	u8 essid_len;
+	u16 rates_mask;
+
+	u32 power_mode;
+	u32 antenna;
+	u8 bssid[ETH_ALEN];
+	u16 rts_threshold;
+	u8 mac_addr[ETH_ALEN];
+
+	/*station table variables */
+	spinlock_t sta_lock;
+	int num_stations;
+	struct iwl_station_entry stations[IWL_STATION_COUNT];
+
+	/* Indication if ieee80211_ops->open has been called */
+	int is_open;
+
+	u8 mac80211_registered;
+	int is_abg;
+
+	u32 notif_missed_beacons;
+
+	/* Rx'd packet timing information */
+	u32 last_beacon_time;
+	u64 last_tsf;
+
+	/* Duplicate packet detection */
+	u16 last_seq_num;
+	u16 last_frag_num;
+	unsigned long last_packet_time;
+	struct list_head ibss_mac_hash[IWL_IBSS_MAC_HASH_SIZE];
+
+	/* eeprom */
+	struct iwl_eeprom eeprom;
+
+	int iw_mode;
+
+	struct sk_buff *ibss_beacon;
+
+	/* Last Rx'd beacon timestamp */
+	u32 timestamp0;
+	u32 timestamp1;
+	u16 beacon_int;
+	struct iwl_driver_hw_info hw_setting;
+	int interface_id;
+
+	/* Current association information needed to configure the
+	 * hardware */
+	u16 assoc_id;
+	u16 assoc_capability;
+	u8 ps_mode;
+
+#ifdef CONFIG_IWLWIFI_QOS
+	struct iwl_qos_info qos_data;
+#endif /*CONFIG_IWLWIFI_QOS */
+
+	struct workqueue_struct *workqueue;
+
+	struct work_struct up;
+	struct work_struct restart;
+	struct work_struct calibrated_work;
+	struct work_struct scan_completed;
+	struct work_struct rx_replenish;
+	struct work_struct rf_kill;
+	struct work_struct abort_scan;
+	struct work_struct update_link_led;
+	struct work_struct auth_work;
+	struct work_struct report_work;
+	struct work_struct request_scan;
+	struct work_struct beacon_update;
+
+	struct tasklet_struct irq_tasklet;
+
+	struct delayed_work init_alive_start;
+	struct delayed_work alive_start;
+	struct delayed_work activity_timer;
+	struct delayed_work thermal_periodic;
+	struct delayed_work gather_stats;
+	struct delayed_work scan_check;
+	struct delayed_work post_associate;
+
+#define IWL_DEFAULT_TX_POWER 0x0F
+	s8 user_txpower_limit;
+	s8 max_channel_txpower_limit;
+	u32 cck_power_index_compensation;
+
+#ifdef CONFIG_PM
+	u32 pm_state[16];
+#endif
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	/* debugging info */
+	u32 framecnt_to_us;
+	atomic_t restrict_refcnt;
+#endif
+
+#if IWL == 4965
+	struct work_struct txpower_work;
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+	struct work_struct sensitivity_work;
+#endif
+	struct work_struct statistics_work;
+	struct timer_list statistics_periodic;
+
+#ifdef CONFIG_IWLWIFI_HT_AGG
+	struct work_struct agg_work;
+#endif
+
+#endif /* 4965 */
+};				/*iwl_priv */
+
+#endif /* __iwl_priv_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
new file mode 100644
index 0000000..0df4114
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -0,0 +1,229 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU Geeral Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2007 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name Intel Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+#ifndef	__iwl_prph_h__
+#define __iwl_prph_h__
+
+
+#define PRPH_BASE	(0x00000)
+#define PRPH_END	(0xFFFFF)
+
+/* APMG (power management) constants */
+#define APMG_BASE			(PRPH_BASE + 0x3000)
+#define APMG_CLK_CTRL_REG		(APMG_BASE + 0x0000)
+#define APMG_CLK_EN_REG			(APMG_BASE + 0x0004)
+#define APMG_CLK_DIS_REG		(APMG_BASE + 0x0008)
+#define APMG_PS_CTRL_REG		(APMG_BASE + 0x000c)
+#define APMG_PCIDEV_STT_REG		(APMG_BASE + 0x0010)
+#define APMG_RFKILL_REG			(APMG_BASE + 0x0014)
+#define APMG_RTC_INT_STT_REG		(APMG_BASE + 0x001c)
+#define APMG_RTC_INT_MSK_REG		(APMG_BASE + 0x0020)
+
+#define APMG_CLK_VAL_DMA_CLK_RQT	(0x00000200)
+#define APMG_CLK_VAL_BSM_CLK_RQT	(0x00000800)
+
+#define APMG_PS_CTRL_VAL_RESET_REQ	(0x04000000)
+
+#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS	(0x00000800)
+
+#define APMG_PS_CTRL_MSK_PWR_SRC              (0x03000000)
+#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN        (0x00000000)
+#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX         (0x01000000)
+
+
+/**
+ * BSM (Bootstrap State Machine)
+ *
+ * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
+ * in special SRAM that does not power down when the embedded control
+ * processor is sleeping (e.g. for periodic power-saving shutdowns of radio).
+ *
+ * When powering back up after sleeps (or during initial uCode load), the BSM
+ * internally loads the short bootstrap program from the special SRAM into the
+ * embedded processor's instruction SRAM, and starts the processor so it runs
+ * the bootstrap program.
+ *
+ * This bootstrap program loads (via PCI busmaster DMA) instructions and data
+ * images for a uCode program from host DRAM locations.  The host driver
+ * indicates DRAM locations and sizes for instruction and data images via the
+ * four BSM_DRAM_* registers.  Once the bootstrap program loads the new program,
+ * the new program starts automatically.
+ *
+ * The uCode used for open-source drivers includes two programs:
+ *
+ * 1)  Initialization -- performs hardware calibration and sets up some
+ *     internal data, then notifies host via "initialize alive" notification
+ *     (struct iwl_init_alive_resp) that it has completed all of its work.
+ *     After signal from host, it then loads and starts the runtime program.
+ *     The initialization program must be used when initially setting up the
+ *     NIC after loading the driver.
+ *
+ * 2)  Runtime/Protocol -- performs all normal runtime operations.  This
+ *     notifies host via "alive" notification (struct iwl_alive_resp) that it
+ *     is ready to be used.
+ *
+ * When initializing the NIC, the host driver does the following procedure:
+ *
+ * 1)  Load bootstrap program (instructions only, no data image for bootstrap)
+ *     into bootstrap memory.  Use dword writes starting at BSM_SRAM_LOWER_BOUND
+ *
+ * 2)  Point (via BSM_DRAM_*) to the "initialize" uCode data and instruction
+ *     images in host DRAM.
+ *
+ * 3)  Set up BSM to copy from BSM SRAM into uCode instruction SRAM when asked:
+ *     BSM_WR_MEM_SRC_REG = 0
+ *     BSM_WR_MEM_DST_REG = RTC_INST_LOWER_BOUND
+ *     BSM_WR_MEM_DWCOUNT_REG = # dwords in bootstrap instruction image
+ *
+ * 4)  Load bootstrap into instruction SRAM:
+ *     BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START
+ *
+ * 5)  Wait for load completion:
+ *     Poll BSM_WR_CTRL_REG for BSM_WR_CTRL_REG_BIT_START = 0
+ *
+ * 6)  Enable future boot loads whenever NIC's power management triggers it:
+ *     BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START_EN
+ *
+ * 7)  Start the NIC by removing all reset bits:
+ *     CSR_RESET = 0
+ *
+ *     The bootstrap uCode (already in instruction SRAM) loads initialization
+ *     uCode.  Initialization uCode performs data initialization, sends
+ *     "initialize alive" notification to host, and waits for a signal from
+ *     host to load runtime code.
+ *
+ * 4)  Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction
+ *     images in host DRAM.  The last register loaded must be the instruction
+ *     bytecount register ("1" in MSbit tells initialization uCode to load
+ *     the runtime uCode):
+ *     BSM_DRAM_INST_BYTECOUNT_REG = bytecount | BSM_DRAM_INST_LOAD
+ *
+ * 5)  Wait for "alive" notification, then issue normal runtime commands.
+ *
+ * Data caching during power-downs:
+ *
+ * Just before the embedded controller powers down (e.g for automatic
+ * power-saving modes, or for RFKILL), uCode stores (via PCI busmaster DMA)
+ * a current snapshot of the embedded processor's data SRAM into host DRAM.
+ * This caches the data while the embedded processor's memory is powered down.
+ * Location and size are controlled by BSM_DRAM_DATA_* registers.
+ *
+ * NOTE:  Instruction SRAM does not need to be saved, since that doesn't
+ *        change during operation; the original image (from uCode distribution
+ *        file) can be used for reload.
+ *
+ * When powering back up, the BSM loads the bootstrap program.  Bootstrap looks
+ * at the BSM_DRAM_* registers, which now point to the runtime instruction
+ * image and the cached (modified) runtime data (*not* the initialization
+ * uCode).  Bootstrap reloads these runtime images into SRAM, and restarts the
+ * uCode from where it left off before the power-down.
+ *
+ * NOTE:  Initialization uCode does *not* run as part of the save/restore
+ *        procedure.
+ *
+ * This save/restore method is mostly for autonomous power management during
+ * normal operation (result of POWER_TABLE_CMD).  Platform suspend/resume and
+ * RFKILL should use complete restarts (with total re-initialization) of uCode,
+ * allowing total shutdown (including BSM memory).
+ *
+ * Note that, during normal operation, the host DRAM that held the initial
+ * startup data for the runtime code is now being used as a backup data cache
+ * for modified data!  If you need to completely re-initialize the NIC, make
+ * sure that you use the runtime data image from the uCode distribution file,
+ * not the modified/saved runtime data.  You may want to store a separate
+ * "clean" runtime data image in DRAM to avoid disk reads of distribution file.
+ */
+
+/* BSM bit fields */
+#define BSM_WR_CTRL_REG_BIT_START     (0x80000000) /* start boot load now */
+#define BSM_WR_CTRL_REG_BIT_START_EN  (0x40000000) /* enable boot after pwrup*/
+#define BSM_DRAM_INST_LOAD            (0x80000000) /* start program load now */
+
+/* BSM addresses */
+#define BSM_BASE                     (PRPH_BASE + 0x3400)
+#define BSM_END                      (PRPH_BASE + 0x3800)
+
+#define BSM_WR_CTRL_REG              (BSM_BASE + 0x000) /* ctl and status */
+#define BSM_WR_MEM_SRC_REG           (BSM_BASE + 0x004) /* source in BSM mem */
+#define BSM_WR_MEM_DST_REG           (BSM_BASE + 0x008) /* dest in SRAM mem */
+#define BSM_WR_DWCOUNT_REG           (BSM_BASE + 0x00C) /* bytes */
+#define BSM_WR_STATUS_REG            (BSM_BASE + 0x010) /* bit 0:  1 == done */
+
+/*
+ * Pointers and size regs for bootstrap load and data SRAM save/restore.
+ * NOTE:  3945 pointers use bits 31:0 of DRAM address.
+ *        4965 pointers use bits 35:4 of DRAM address.
+ */
+#define BSM_DRAM_INST_PTR_REG        (BSM_BASE + 0x090)
+#define BSM_DRAM_INST_BYTECOUNT_REG  (BSM_BASE + 0x094)
+#define BSM_DRAM_DATA_PTR_REG        (BSM_BASE + 0x098)
+#define BSM_DRAM_DATA_BYTECOUNT_REG  (BSM_BASE + 0x09C)
+
+/*
+ * BSM special memory, stays powered on during power-save sleeps.
+ * Read/write, address range from LOWER_BOUND to (LOWER_BOUND + SIZE -1)
+ */
+#define BSM_SRAM_LOWER_BOUND         (PRPH_BASE + 0x3800)
+#define BSM_SRAM_SIZE			(1024) /* bytes */
+
+
+#endif				/* __iwl_prph_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
new file mode 100644
index 0000000..b576ff2
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
@@ -0,0 +1,91 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwl_spectrum_h__
+#define __iwl_spectrum_h__
+enum {				/* ieee80211_basic_report.map */
+	IEEE80211_BASIC_MAP_BSS = (1 << 0),
+	IEEE80211_BASIC_MAP_OFDM = (1 << 1),
+	IEEE80211_BASIC_MAP_UNIDENTIFIED = (1 << 2),
+	IEEE80211_BASIC_MAP_RADAR = (1 << 3),
+	IEEE80211_BASIC_MAP_UNMEASURED = (1 << 4),
+	/* Bits 5-7 are reserved */
+
+};
+struct ieee80211_basic_report {
+	u8 channel;
+	__le64 start_time;
+	__le16 duration;
+	u8 map;
+} __attribute__ ((packed));
+
+enum {				/* ieee80211_measurement_request.mode */
+	/* Bit 0 is reserved */
+	IEEE80211_MEASUREMENT_ENABLE = (1 << 1),
+	IEEE80211_MEASUREMENT_REQUEST = (1 << 2),
+	IEEE80211_MEASUREMENT_REPORT = (1 << 3),
+	/* Bits 4-7 are reserved */
+};
+
+enum {
+	IEEE80211_REPORT_BASIC = 0,	/* required */
+	IEEE80211_REPORT_CCA = 1,	/* optional */
+	IEEE80211_REPORT_RPI = 2,	/* optional */
+	/* 3-255 reserved */
+};
+
+struct ieee80211_measurement_params {
+	u8 channel;
+	__le64 start_time;
+	__le16 duration;
+} __attribute__ ((packed));
+
+struct ieee80211_info_element {
+	u8 id;
+	u8 len;
+	u8 data[0];
+} __attribute__ ((packed));
+
+struct ieee80211_measurement_request {
+	struct ieee80211_info_element ie;
+	u8 token;
+	u8 mode;
+	u8 type;
+	struct ieee80211_measurement_params params[0];
+} __attribute__ ((packed));
+
+struct ieee80211_measurement_report {
+	struct ieee80211_info_element ie;
+	u8 token;
+	u8 mode;
+	u8 type;
+	union {
+		struct ieee80211_basic_report basic[0];
+	} u;
+} __attribute__ ((packed));
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
new file mode 100644
index 0000000..75e3b5c
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -0,0 +1,8746 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+/*
+ * NOTE:  This file (iwl-base.c) is used to build to multiple hardware targets
+ * by defining IWL to either 3945 or 4965.  The Makefile used when building
+ * the base targets will create base-3945.o and base-4965.o
+ *
+ * The eventual goal is to move as many of the #if IWL / #endif blocks out of
+ * this file and into the hardware specific implementation files (iwl-XXXX.c)
+ * and leave only the common (non #ifdef sprinkled) code in this file
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/firmware.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/ieee80211_radiotap.h>
+#include <net/mac80211.h>
+
+#include <asm/div64.h>
+
+#define IWL 3945
+
+#include "iwlwifi.h"
+#include "iwl-3945.h"
+#include "iwl-helpers.h"
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+u32 iwl_debug_level;
+#endif
+
+/******************************************************************************
+ *
+ * module boiler plate
+ *
+ ******************************************************************************/
+
+/* module parameters */
+int iwl_param_disable_hw_scan;
+int iwl_param_debug;
+int iwl_param_disable;      /* def: enable radio */
+int iwl_param_antenna;      /* def: 0 = both antennas (use diversity) */
+int iwl_param_hwcrypto;     /* def: using software encryption */
+int iwl_param_qos_enable = 1;
+int iwl_param_queues_num = IWL_MAX_NUM_QUEUES;
+
+/*
+ * module name, copyright, version, etc.
+ * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk
+ */
+
+#define DRV_DESCRIPTION	\
+"Intel(R) PRO/Wireless 3945ABG/BG Network Connection driver for Linux"
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define VD "d"
+#else
+#define VD
+#endif
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+#define VS "s"
+#else
+#define VS
+#endif
+
+#define IWLWIFI_VERSION "1.1.17k" VD VS
+#define DRV_COPYRIGHT	"Copyright(c) 2003-2007 Intel Corporation"
+#define DRV_VERSION     IWLWIFI_VERSION
+
+/* Change firmware file name, using "-" and incrementing number,
+ *   *only* when uCode interface or architecture changes so that it
+ *   is not compatible with earlier drivers.
+ * This number will also appear in << 8 position of 1st dword of uCode file */
+#define IWL3945_UCODE_API "-1"
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_LICENSE("GPL");
+
+__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
+{
+	u16 fc = le16_to_cpu(hdr->frame_control);
+	int hdr_len = ieee80211_get_hdrlen(fc);
+
+	if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA))
+		return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
+	return NULL;
+}
+
+static const struct ieee80211_hw_mode *iwl_get_hw_mode(
+		struct iwl_priv *priv, int mode)
+{
+	int i;
+
+	for (i = 0; i < 3; i++)
+		if (priv->modes[i].mode == mode)
+			return &priv->modes[i];
+
+	return NULL;
+}
+
+static int iwl_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;
+}
+
+static const char *iwl_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 (iwl_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;
+}
+
+static void iwl_print_hex_dump(int level, void *p, u32 len)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (!(iwl_debug_level & level))
+		return;
+
+	print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
+			p, len, 1);
+#endif
+}
+
+/*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
+ * DMA services
+ *
+ * Theory of operation
+ *
+ * A queue is a circular buffers with 'Read' and 'Write' pointers.
+ * 2 empty entries always kept in the buffer to protect from overflow.
+ *
+ * For Tx queue, there are low mark and high mark limits. If, after queuing
+ * the packet for Tx, free space become < low mark, Tx queue stopped. When
+ * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
+ * Tx queue resumed.
+ *
+ * The IWL operates with six queues, one receive queue in the device's
+ * sram, one transmit queue for sending commands to the device firmware,
+ * and four transmit queues for data.
+ ***************************************************/
+
+static int iwl_queue_space(const struct iwl_queue *q)
+{
+	int s = q->last_used - q->first_empty;
+
+	if (q->last_used > q->first_empty)
+		s -= q->n_bd;
+
+	if (s <= 0)
+		s += q->n_window;
+	/* keep some reserve to not confuse empty and full situations */
+	s -= 2;
+	if (s < 0)
+		s = 0;
+	return s;
+}
+
+/* XXX: n_bd must be power-of-two size */
+static inline int iwl_queue_inc_wrap(int index, int n_bd)
+{
+	return ++index & (n_bd - 1);
+}
+
+/* XXX: n_bd must be power-of-two size */
+static inline int iwl_queue_dec_wrap(int index, int n_bd)
+{
+	return --index & (n_bd - 1);
+}
+
+static inline int x2_queue_used(const struct iwl_queue *q, int i)
+{
+	return q->first_empty > q->last_used ?
+		(i >= q->last_used && i < q->first_empty) :
+		!(i < q->last_used && i >= q->first_empty);
+}
+
+static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
+{
+	if (is_huge)
+		return q->n_window;
+
+	return index & (q->n_window - 1);
+}
+
+static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
+			  int count, int slots_num, u32 id)
+{
+	q->n_bd = count;
+	q->n_window = slots_num;
+	q->id = id;
+
+	/* count must be power-of-two size, otherwise iwl_queue_inc_wrap
+	 * and iwl_queue_dec_wrap are broken. */
+	BUG_ON(!is_power_of_2(count));
+
+	/* slots_num must be power-of-two size, otherwise
+	 * get_cmd_index is broken. */
+	BUG_ON(!is_power_of_2(slots_num));
+
+	q->low_mark = q->n_window / 4;
+	if (q->low_mark < 4)
+		q->low_mark = 4;
+
+	q->high_mark = q->n_window / 8;
+	if (q->high_mark < 2)
+		q->high_mark = 2;
+
+	q->first_empty = q->last_used = 0;
+
+	return 0;
+}
+
+static int iwl_tx_queue_alloc(struct iwl_priv *priv,
+			      struct iwl_tx_queue *txq, u32 id)
+{
+	struct pci_dev *dev = priv->pci_dev;
+
+	if (id != IWL_CMD_QUEUE_NUM) {
+		txq->txb = kmalloc(sizeof(txq->txb[0]) *
+				   TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
+		if (!txq->txb) {
+			IWL_ERROR("kmalloc for auxilary BD "
+				  "structures failed\n");
+			goto error;
+		}
+	} else
+		txq->txb = NULL;
+
+	txq->bd = pci_alloc_consistent(dev,
+			sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
+			&txq->q.dma_addr);
+
+	if (!txq->bd) {
+		IWL_ERROR("pci_alloc_consistent(%zd) failed\n",
+			  sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX);
+		goto error;
+	}
+	txq->q.id = id;
+
+	return 0;
+
+ error:
+	if (txq->txb) {
+		kfree(txq->txb);
+		txq->txb = NULL;
+	}
+
+	return -ENOMEM;
+}
+
+int iwl_tx_queue_init(struct iwl_priv *priv,
+		      struct iwl_tx_queue *txq, int slots_num, u32 txq_id)
+{
+	struct pci_dev *dev = priv->pci_dev;
+	int len;
+	int rc = 0;
+
+	/* alocate command space + one big command for scan since scan
+	 * command is very huge the system will not have two scan at the
+	 * same time */
+	len = sizeof(struct iwl_cmd) * slots_num;
+	if (txq_id == IWL_CMD_QUEUE_NUM)
+		len +=  IWL_MAX_SCAN_SIZE;
+	txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
+	if (!txq->cmd)
+		return -ENOMEM;
+
+	rc = iwl_tx_queue_alloc(priv, txq, txq_id);
+	if (rc) {
+		pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+		return -ENOMEM;
+	}
+	txq->need_update = 0;
+
+	/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+	 * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
+	BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+	iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+
+	iwl_hw_tx_queue_init(priv, txq);
+
+	return 0;
+}
+
+/**
+ * iwl_tx_queue_free - Deallocate DMA queue.
+ * @txq: Transmit queue to deallocate.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers.  txq itself is not freed.
+ *
+ */
+void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+	struct iwl_queue *q = &txq->q;
+	struct pci_dev *dev = priv->pci_dev;
+	int len;
+
+	if (q->n_bd == 0)
+		return;
+
+	/* first, empty all BD's */
+	for (; q->first_empty != q->last_used;
+	     q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd))
+		iwl_hw_txq_free_tfd(priv, txq);
+
+	len = sizeof(struct iwl_cmd) * q->n_window;
+	if (q->id == IWL_CMD_QUEUE_NUM)
+		len += IWL_MAX_SCAN_SIZE;
+
+	pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+	/* free buffers belonging to queue itself */
+	if (txq->q.n_bd)
+		pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) *
+				    txq->q.n_bd, txq->bd, txq->q.dma_addr);
+
+	if (txq->txb) {
+		kfree(txq->txb);
+		txq->txb = NULL;
+	}
+
+	/* 0 fill whole structure */
+	memset(txq, 0, sizeof(*txq));
+}
+
+const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+/*************** STATION TABLE MANAGEMENT ****
+ *
+ * NOTE:  This needs to be overhauled to better synchronize between
+ * how the iwl-4965.c is using iwl_hw_find_station vs. iwl-3945.c
+ *
+ * mac80211 should also be examined to determine if sta_info is duplicating
+ * the functionality provided here
+ */
+
+/**************************************************************/
+#if 0 /* temparary disable till we add real remove station */
+static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
+{
+	int index = IWL_INVALID_STATION;
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+
+	if (is_ap)
+		index = IWL_AP_ID;
+	else if (is_broadcast_ether_addr(addr))
+		index = priv->hw_setting.bcast_sta_id;
+	else
+		for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
+			if (priv->stations[i].used &&
+			    !compare_ether_addr(priv->stations[i].sta.sta.addr,
+						addr)) {
+				index = i;
+				break;
+			}
+
+	if (unlikely(index == IWL_INVALID_STATION))
+		goto out;
+
+	if (priv->stations[index].used) {
+		priv->stations[index].used = 0;
+		priv->num_stations--;
+	}
+
+	BUG_ON(priv->num_stations < 0);
+
+out:
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+	return 0;
+}
+#endif
+static void iwl_clear_stations_table(struct iwl_priv *priv)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+
+	priv->num_stations = 0;
+	memset(priv->stations, 0, sizeof(priv->stations));
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+}
+
+
+u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags)
+{
+	int i;
+	int index = IWL_INVALID_STATION;
+	struct iwl_station_entry *station;
+	unsigned long flags_spin;
+	DECLARE_MAC_BUF(mac);
+	u8 rate;
+
+	spin_lock_irqsave(&priv->sta_lock, flags_spin);
+	if (is_ap)
+		index = IWL_AP_ID;
+	else if (is_broadcast_ether_addr(addr))
+		index = priv->hw_setting.bcast_sta_id;
+	else
+		for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) {
+			if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
+						addr)) {
+				index = i;
+				break;
+			}
+
+			if (!priv->stations[i].used &&
+			    index == IWL_INVALID_STATION)
+				index = i;
+		}
+
+	/* These twh conditions has the same outcome but keep them separate
+	  since they have different meaning */
+	if (unlikely(index == IWL_INVALID_STATION)) {
+		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+		return index;
+	}
+
+	if (priv->stations[index].used &&
+	   !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) {
+		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+		return index;
+	}
+
+	IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));
+	station = &priv->stations[index];
+	station->used = 1;
+	priv->num_stations++;
+
+	memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
+	memcpy(station->sta.sta.addr, addr, ETH_ALEN);
+	station->sta.mode = 0;
+	station->sta.sta.sta_id = index;
+	station->sta.station_flags = 0;
+
+	rate = (priv->phymode == MODE_IEEE80211A) ? IWL_RATE_6M_PLCP :
+				IWL_RATE_1M_PLCP | priv->hw_setting.cck_flag;
+
+	/* Turn on both antennas for the station... */
+	station->sta.rate_n_flags =
+			iwl_hw_set_rate_n_flags(rate, RATE_MCS_ANT_AB_MSK);
+	station->current_rate.rate_n_flags =
+			le16_to_cpu(station->sta.rate_n_flags);
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+	iwl_send_add_station(priv, &station->sta, flags);
+	return index;
+
+}
+
+/*************** DRIVER STATUS FUNCTIONS   *****/
+
+static inline int iwl_is_ready(struct iwl_priv *priv)
+{
+	/* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
+	 * set but EXIT_PENDING is not */
+	return test_bit(STATUS_READY, &priv->status) &&
+	       test_bit(STATUS_GEO_CONFIGURED, &priv->status) &&
+	       !test_bit(STATUS_EXIT_PENDING, &priv->status);
+}
+
+static inline int iwl_is_alive(struct iwl_priv *priv)
+{
+	return test_bit(STATUS_ALIVE, &priv->status);
+}
+
+static inline int iwl_is_init(struct iwl_priv *priv)
+{
+	return test_bit(STATUS_INIT, &priv->status);
+}
+
+static inline int iwl_is_rfkill(struct iwl_priv *priv)
+{
+	return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
+	       test_bit(STATUS_RF_KILL_SW, &priv->status);
+}
+
+static inline int iwl_is_ready_rf(struct iwl_priv *priv)
+{
+
+	if (iwl_is_rfkill(priv))
+		return 0;
+
+	return iwl_is_ready(priv);
+}
+
+/*************** HOST COMMAND QUEUE FUNCTIONS   *****/
+
+#define IWL_CMD(x) case x : return #x
+
+static const char *get_cmd_string(u8 cmd)
+{
+	switch (cmd) {
+		IWL_CMD(REPLY_ALIVE);
+		IWL_CMD(REPLY_ERROR);
+		IWL_CMD(REPLY_RXON);
+		IWL_CMD(REPLY_RXON_ASSOC);
+		IWL_CMD(REPLY_QOS_PARAM);
+		IWL_CMD(REPLY_RXON_TIMING);
+		IWL_CMD(REPLY_ADD_STA);
+		IWL_CMD(REPLY_REMOVE_STA);
+		IWL_CMD(REPLY_REMOVE_ALL_STA);
+		IWL_CMD(REPLY_3945_RX);
+		IWL_CMD(REPLY_TX);
+		IWL_CMD(REPLY_RATE_SCALE);
+		IWL_CMD(REPLY_LEDS_CMD);
+		IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
+		IWL_CMD(RADAR_NOTIFICATION);
+		IWL_CMD(REPLY_QUIET_CMD);
+		IWL_CMD(REPLY_CHANNEL_SWITCH);
+		IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
+		IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD);
+		IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION);
+		IWL_CMD(POWER_TABLE_CMD);
+		IWL_CMD(PM_SLEEP_NOTIFICATION);
+		IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC);
+		IWL_CMD(REPLY_SCAN_CMD);
+		IWL_CMD(REPLY_SCAN_ABORT_CMD);
+		IWL_CMD(SCAN_START_NOTIFICATION);
+		IWL_CMD(SCAN_RESULTS_NOTIFICATION);
+		IWL_CMD(SCAN_COMPLETE_NOTIFICATION);
+		IWL_CMD(BEACON_NOTIFICATION);
+		IWL_CMD(REPLY_TX_BEACON);
+		IWL_CMD(WHO_IS_AWAKE_NOTIFICATION);
+		IWL_CMD(QUIET_NOTIFICATION);
+		IWL_CMD(REPLY_TX_PWR_TABLE_CMD);
+		IWL_CMD(MEASURE_ABORT_NOTIFICATION);
+		IWL_CMD(REPLY_BT_CONFIG);
+		IWL_CMD(REPLY_STATISTICS_CMD);
+		IWL_CMD(STATISTICS_NOTIFICATION);
+		IWL_CMD(REPLY_CARD_STATE_CMD);
+		IWL_CMD(CARD_STATE_NOTIFICATION);
+		IWL_CMD(MISSED_BEACONS_NOTIFICATION);
+	default:
+		return "UNKNOWN";
+
+	}
+}
+
+#define HOST_COMPLETE_TIMEOUT (HZ / 2)
+
+/**
+ * iwl_enqueue_hcmd - enqueue a uCode command
+ * @priv: device private data point
+ * @cmd: a point to the ucode command structure
+ *
+ * The function returns < 0 values to indicate the operation is
+ * failed. On success, it turns the index (> 0) of command in the
+ * command queue.
+ */
+static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+	struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+	struct iwl_queue *q = &txq->q;
+	struct iwl_tfd_frame *tfd;
+	u32 *control_flags;
+	struct iwl_cmd *out_cmd;
+	u32 idx;
+	u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
+	dma_addr_t phys_addr;
+	int pad;
+	u16 count;
+	int ret;
+	unsigned long flags;
+
+	/* If any of the command structures end up being larger than
+	 * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
+	 * we will need to increase the size of the TFD entries */
+	BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
+	       !(cmd->meta.flags & CMD_SIZE_HUGE));
+
+	if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
+		IWL_ERROR("No space for Tx\n");
+		return -ENOSPC;
+	}
+
+	spin_lock_irqsave(&priv->hcmd_lock, flags);
+
+	tfd = &txq->bd[q->first_empty];
+	memset(tfd, 0, sizeof(*tfd));
+
+	control_flags = (u32 *) tfd;
+
+	idx = get_cmd_index(q, q->first_empty, cmd->meta.flags & CMD_SIZE_HUGE);
+	out_cmd = &txq->cmd[idx];
+
+	out_cmd->hdr.cmd = cmd->id;
+	memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
+	memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
+
+	/* At this point, the out_cmd now has all of the incoming cmd
+	 * information */
+
+	out_cmd->hdr.flags = 0;
+	out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
+			INDEX_TO_SEQ(q->first_empty));
+	if (out_cmd->meta.flags & CMD_SIZE_HUGE)
+		out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);
+
+	phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +
+			offsetof(struct iwl_cmd, hdr);
+	iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
+
+	pad = U32_PAD(cmd->len);
+	count = TFD_CTL_COUNT_GET(*control_flags);
+	*control_flags = TFD_CTL_COUNT_SET(count) | TFD_CTL_PAD_SET(pad);
+
+	IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
+		     "%d bytes at %d[%d]:%d\n",
+		     get_cmd_string(out_cmd->hdr.cmd),
+		     out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
+		     fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM);
+
+	txq->need_update = 1;
+	q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
+	ret = iwl_tx_queue_update_write_ptr(priv, txq);
+
+	spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+	return ret ? ret : idx;
+}
+
+int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+	int ret;
+
+	BUG_ON(!(cmd->meta.flags & CMD_ASYNC));
+
+	/* An asynchronous command can not expect an SKB to be set. */
+	BUG_ON(cmd->meta.flags & CMD_WANT_SKB);
+
+	/* An asynchronous command MUST have a callback. */
+	BUG_ON(!cmd->meta.u.callback);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return -EBUSY;
+
+	ret = iwl_enqueue_hcmd(priv, cmd);
+	if (ret < 0) {
+		IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",
+			  get_cmd_string(cmd->id), ret);
+		return ret;
+	}
+	return 0;
+}
+
+int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+	int cmd_idx;
+	int ret;
+	static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */
+
+	BUG_ON(cmd->meta.flags & CMD_ASYNC);
+
+	 /* A synchronous command can not have a callback set. */
+	BUG_ON(cmd->meta.u.callback != NULL);
+
+	if (atomic_xchg(&entry, 1)) {
+		IWL_ERROR("Error sending %s: Already sending a host command\n",
+			  get_cmd_string(cmd->id));
+		return -EBUSY;
+	}
+
+	set_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+	if (cmd->meta.flags & CMD_WANT_SKB)
+		cmd->meta.source = &cmd->meta;
+
+	cmd_idx = iwl_enqueue_hcmd(priv, cmd);
+	if (cmd_idx < 0) {
+		ret = cmd_idx;
+		IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",
+			  get_cmd_string(cmd->id), ret);
+		goto out;
+	}
+
+	ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+			!test_bit(STATUS_HCMD_ACTIVE, &priv->status),
+			HOST_COMPLETE_TIMEOUT);
+	if (!ret) {
+		if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) {
+			IWL_ERROR("Error sending %s: time out after %dms.\n",
+				  get_cmd_string(cmd->id),
+				  jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
+
+			clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+			ret = -ETIMEDOUT;
+			goto cancel;
+		}
+	}
+
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
+		IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n",
+			       get_cmd_string(cmd->id));
+		ret = -ECANCELED;
+		goto fail;
+	}
+	if (test_bit(STATUS_FW_ERROR, &priv->status)) {
+		IWL_DEBUG_INFO("Command %s failed: FW Error\n",
+			       get_cmd_string(cmd->id));
+		ret = -EIO;
+		goto fail;
+	}
+	if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) {
+		IWL_ERROR("Error: Response NULL in '%s'\n",
+			  get_cmd_string(cmd->id));
+		ret = -EIO;
+		goto out;
+	}
+
+	ret = 0;
+	goto out;
+
+cancel:
+	if (cmd->meta.flags & CMD_WANT_SKB) {
+		struct iwl_cmd *qcmd;
+
+		/* Cancel the CMD_WANT_SKB flag for the cmd in the
+		 * TX cmd queue. Otherwise in case the cmd comes
+		 * in later, it will possibly set an invalid
+		 * address (cmd->meta.source). */
+		qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx];
+		qcmd->meta.flags &= ~CMD_WANT_SKB;
+	}
+fail:
+	if (cmd->meta.u.skb) {
+		dev_kfree_skb_any(cmd->meta.u.skb);
+		cmd->meta.u.skb = NULL;
+	}
+out:
+	atomic_set(&entry, 0);
+	return ret;
+}
+
+int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+	/* A command can not be asynchronous AND expect an SKB to be set. */
+	BUG_ON((cmd->meta.flags & CMD_ASYNC) &&
+	       (cmd->meta.flags & CMD_WANT_SKB));
+
+	if (cmd->meta.flags & CMD_ASYNC)
+		return iwl_send_cmd_async(priv, cmd);
+
+	return iwl_send_cmd_sync(priv, cmd);
+}
+
+int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data)
+{
+	struct iwl_host_cmd cmd = {
+		.id = id,
+		.len = len,
+		.data = data,
+	};
+
+	return iwl_send_cmd_sync(priv, &cmd);
+}
+
+static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val)
+{
+	struct iwl_host_cmd cmd = {
+		.id = id,
+		.len = sizeof(val),
+		.data = &val,
+	};
+
+	return iwl_send_cmd_sync(priv, &cmd);
+}
+
+int iwl_send_statistics_request(struct iwl_priv *priv)
+{
+	return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0);
+}
+
+/**
+ * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON
+ * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
+ * @channel: Any channel valid for the requested phymode
+
+ * In addition to setting the staging RXON, priv->phymode is also set.
+ *
+ * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
+ * in the staging RXON flag structure based on the phymode
+ */
+static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel)
+{
+	if (!iwl_get_channel_info(priv, phymode, channel)) {
+		IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
+			       channel, phymode);
+		return -EINVAL;
+	}
+
+	if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
+	    (priv->phymode == phymode))
+		return 0;
+
+	priv->staging_rxon.channel = cpu_to_le16(channel);
+	if (phymode == MODE_IEEE80211A)
+		priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;
+	else
+		priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+
+	priv->phymode = phymode;
+
+	IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode);
+
+	return 0;
+}
+
+/**
+ * iwl_check_rxon_cmd - validate RXON structure is valid
+ *
+ * NOTE:  This is really only useful during development and can eventually
+ * be #ifdef'd out once the driver is stable and folks aren't actively
+ * making changes
+ */
+static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
+{
+	int error = 0;
+	int counter = 1;
+
+	if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
+		error |= le32_to_cpu(rxon->flags &
+				(RXON_FLG_TGJ_NARROW_BAND_MSK |
+				 RXON_FLG_RADAR_DETECT_MSK));
+		if (error)
+			IWL_WARNING("check 24G fields %d | %d\n",
+				    counter++, error);
+	} else {
+		error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ?
+				0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK);
+		if (error)
+			IWL_WARNING("check 52 fields %d | %d\n",
+				    counter++, error);
+		error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK);
+		if (error)
+			IWL_WARNING("check 52 CCK %d | %d\n",
+				    counter++, error);
+	}
+	error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1;
+	if (error)
+		IWL_WARNING("check mac addr %d | %d\n", counter++, error);
+
+	/* make sure basic rates 6Mbps and 1Mbps are supported */
+	error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) &&
+		  ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0));
+	if (error)
+		IWL_WARNING("check basic rate %d | %d\n", counter++, error);
+
+	error |= (le16_to_cpu(rxon->assoc_id) > 2007);
+	if (error)
+		IWL_WARNING("check assoc id %d | %d\n", counter++, error);
+
+	error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
+			== (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK));
+	if (error)
+		IWL_WARNING("check CCK and short slot %d | %d\n",
+			    counter++, error);
+
+	error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
+			== (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK));
+	if (error)
+		IWL_WARNING("check CCK & auto detect %d | %d\n",
+			    counter++, error);
+
+	error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
+			RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK);
+	if (error)
+		IWL_WARNING("check TGG and auto detect %d | %d\n",
+			    counter++, error);
+
+	if ((rxon->flags & RXON_FLG_DIS_DIV_MSK))
+		error |= ((rxon->flags & (RXON_FLG_ANT_B_MSK |
+				RXON_FLG_ANT_A_MSK)) == 0);
+	if (error)
+		IWL_WARNING("check antenna %d %d\n", counter++, error);
+
+	if (error)
+		IWL_WARNING("Tuning to channel %d\n",
+			    le16_to_cpu(rxon->channel));
+
+	if (error) {
+		IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n");
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * iwl_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit
+ * @priv: staging_rxon is comapred to active_rxon
+ *
+ * If the RXON structure is changing sufficient to require a new
+ * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1
+ * to indicate a new tune is required.
+ */
+static int iwl_full_rxon_required(struct iwl_priv *priv)
+{
+
+	/* These items are only settable from the full RXON command */
+	if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ||
+	    compare_ether_addr(priv->staging_rxon.bssid_addr,
+			       priv->active_rxon.bssid_addr) ||
+	    compare_ether_addr(priv->staging_rxon.node_addr,
+			       priv->active_rxon.node_addr) ||
+	    compare_ether_addr(priv->staging_rxon.wlap_bssid_addr,
+			       priv->active_rxon.wlap_bssid_addr) ||
+	    (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) ||
+	    (priv->staging_rxon.channel != priv->active_rxon.channel) ||
+	    (priv->staging_rxon.air_propagation !=
+	     priv->active_rxon.air_propagation) ||
+	    (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
+		return 1;
+
+	/* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
+	 * be updated with the RXON_ASSOC command -- however only some
+	 * flag transitions are allowed using RXON_ASSOC */
+
+	/* Check if we are not switching bands */
+	if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) !=
+	    (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK))
+		return 1;
+
+	/* Check if we are switching association toggle */
+	if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) !=
+		(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK))
+		return 1;
+
+	return 0;
+}
+
+static int iwl_send_rxon_assoc(struct iwl_priv *priv)
+{
+	int rc = 0;
+	struct iwl_rx_packet *res = NULL;
+	struct iwl_rxon_assoc_cmd rxon_assoc;
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_RXON_ASSOC,
+		.len = sizeof(rxon_assoc),
+		.meta.flags = CMD_WANT_SKB,
+		.data = &rxon_assoc,
+	};
+	const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
+	const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+
+	if ((rxon1->flags == rxon2->flags) &&
+	    (rxon1->filter_flags == rxon2->filter_flags) &&
+	    (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
+	    (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
+		IWL_DEBUG_INFO("Using current RXON_ASSOC.  Not resending.\n");
+		return 0;
+	}
+
+	rxon_assoc.flags = priv->staging_rxon.flags;
+	rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
+	rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
+	rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+	rxon_assoc.reserved = 0;
+
+	rc = iwl_send_cmd_sync(priv, &cmd);
+	if (rc)
+		return rc;
+
+	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+		IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n");
+		rc = -EIO;
+	}
+
+	priv->alloc_rxb_skb--;
+	dev_kfree_skb_any(cmd.meta.u.skb);
+
+	return rc;
+}
+
+/**
+ * iwl_commit_rxon - commit staging_rxon to hardware
+ *
+ * The RXON command in staging_rxon is commited to the hardware and
+ * the active_rxon structure is updated with the new data.  This
+ * function correctly transitions out of the RXON_ASSOC_MSK state if
+ * a HW tune is required based on the RXON structure changes.
+ */
+static int iwl_commit_rxon(struct iwl_priv *priv)
+{
+	/* cast away the const for active_rxon in this function */
+	struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
+	int rc = 0;
+	DECLARE_MAC_BUF(mac);
+
+	if (!iwl_is_alive(priv))
+		return -1;
+
+	/* always get timestamp with Rx frame */
+	priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
+
+	/* select antenna */
+	priv->staging_rxon.flags &=
+	    ~(RXON_FLG_DIS_DIV_MSK | RXON_FLG_ANT_SEL_MSK);
+	priv->staging_rxon.flags |= iwl3945_get_antenna_flags(priv);
+
+	rc = iwl_check_rxon_cmd(&priv->staging_rxon);
+	if (rc) {
+		IWL_ERROR("Invalid RXON configuration.  Not committing.\n");
+		return -EINVAL;
+	}
+
+	/* If we don't need to send a full RXON, we can use
+	 * iwl_rxon_assoc_cmd which is used to reconfigure filter
+	 * and other flags for the current radio configuration. */
+	if (!iwl_full_rxon_required(priv)) {
+		rc = iwl_send_rxon_assoc(priv);
+		if (rc) {
+			IWL_ERROR("Error setting RXON_ASSOC "
+				  "configuration (%d).\n", rc);
+			return rc;
+		}
+
+		memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+
+		return 0;
+	}
+
+	/* If we are currently associated and the new config requires
+	 * an RXON_ASSOC and the new config wants the associated mask enabled,
+	 * we must clear the associated from the active configuration
+	 * before we apply the new config */
+	if (iwl_is_associated(priv) &&
+	    (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) {
+		IWL_DEBUG_INFO("Toggling associated bit on current RXON\n");
+		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+
+		rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
+				      sizeof(struct iwl_rxon_cmd),
+				      &priv->active_rxon);
+
+		/* If the mask clearing failed then we set
+		 * active_rxon back to what it was previously */
+		if (rc) {
+			active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
+			IWL_ERROR("Error clearing ASSOC_MSK on current "
+				  "configuration (%d).\n", rc);
+			return rc;
+		}
+	}
+
+	IWL_DEBUG_INFO("Sending RXON\n"
+		       "* with%s RXON_FILTER_ASSOC_MSK\n"
+		       "* channel = %d\n"
+		       "* bssid = %s\n",
+		       ((priv->staging_rxon.filter_flags &
+			 RXON_FILTER_ASSOC_MSK) ? "" : "out"),
+		       le16_to_cpu(priv->staging_rxon.channel),
+		       print_mac(mac, priv->staging_rxon.bssid_addr));
+
+	/* Apply the new configuration */
+	rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
+			      sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
+	if (rc) {
+		IWL_ERROR("Error setting new configuration (%d).\n", rc);
+		return rc;
+	}
+
+	memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+
+	iwl_clear_stations_table(priv);
+
+	/* If we issue a new RXON command which required a tune then we must
+	 * send a new TXPOWER command or we won't be able to Tx any frames */
+	rc = iwl_hw_reg_send_txpower(priv);
+	if (rc) {
+		IWL_ERROR("Error setting Tx power (%d).\n", rc);
+		return rc;
+	}
+
+	/* Add the broadcast address so we can send broadcast frames */
+	if (iwl_add_station(priv, BROADCAST_ADDR, 0, 0) ==
+	    IWL_INVALID_STATION) {
+		IWL_ERROR("Error adding BROADCAST address for transmit.\n");
+		return -EIO;
+	}
+
+	/* If we have set the ASSOC_MSK and we are in BSS mode then
+	 * add the IWL_AP_ID to the station rate table */
+	if (iwl_is_associated(priv) &&
+	    (priv->iw_mode == IEEE80211_IF_TYPE_STA))
+		if (iwl_add_station(priv, priv->active_rxon.bssid_addr, 1, 0)
+		    == IWL_INVALID_STATION) {
+			IWL_ERROR("Error adding AP address for transmit.\n");
+			return -EIO;
+		}
+
+	/* Init the hardware's rate fallback order based on the
+	 * phymode */
+	rc = iwl3945_init_hw_rate_table(priv);
+	if (rc) {
+		IWL_ERROR("Error setting HW rate table: %02X\n", rc);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int iwl_send_bt_config(struct iwl_priv *priv)
+{
+	struct iwl_bt_cmd bt_cmd = {
+		.flags = 3,
+		.lead_time = 0xAA,
+		.max_kill = 1,
+		.kill_ack_mask = 0,
+		.kill_cts_mask = 0,
+	};
+
+	return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+				sizeof(struct iwl_bt_cmd), &bt_cmd);
+}
+
+static int iwl_send_scan_abort(struct iwl_priv *priv)
+{
+	int rc = 0;
+	struct iwl_rx_packet *res;
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_SCAN_ABORT_CMD,
+		.meta.flags = CMD_WANT_SKB,
+	};
+
+	/* If there isn't a scan actively going on in the hardware
+	 * then we are in between scan bands and not actually
+	 * actively scanning, so don't send the abort command */
+	if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
+		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+		return 0;
+	}
+
+	rc = iwl_send_cmd_sync(priv, &cmd);
+	if (rc) {
+		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+		return rc;
+	}
+
+	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	if (res->u.status != CAN_ABORT_STATUS) {
+		/* The scan abort will return 1 for success or
+		 * 2 for "failure".  A failure condition can be
+		 * due to simply not being in an active scan which
+		 * can occur if we send the scan abort before we
+		 * the microcode has notified us that a scan is
+		 * completed. */
+		IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status);
+		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+		clear_bit(STATUS_SCAN_HW, &priv->status);
+	}
+
+	dev_kfree_skb_any(cmd.meta.u.skb);
+
+	return rc;
+}
+
+static int iwl_card_state_sync_callback(struct iwl_priv *priv,
+					struct iwl_cmd *cmd,
+					struct sk_buff *skb)
+{
+	return 1;
+}
+
+/*
+ * CARD_STATE_CMD
+ *
+ * Use: Sets the internal card state to enable, disable, or halt
+ *
+ * When in the 'enable' state the card operates as normal.
+ * When in the 'disable' state, the card enters into a low power mode.
+ * When in the 'halt' state, the card is shut down and must be fully
+ * restarted to come back on.
+ */
+static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
+{
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_CARD_STATE_CMD,
+		.len = sizeof(u32),
+		.data = &flags,
+		.meta.flags = meta_flag,
+	};
+
+	if (meta_flag & CMD_ASYNC)
+		cmd.meta.u.callback = iwl_card_state_sync_callback;
+
+	return iwl_send_cmd(priv, &cmd);
+}
+
+static int iwl_add_sta_sync_callback(struct iwl_priv *priv,
+				     struct iwl_cmd *cmd, struct sk_buff *skb)
+{
+	struct iwl_rx_packet *res = NULL;
+
+	if (!skb) {
+		IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
+		return 1;
+	}
+
+	res = (struct iwl_rx_packet *)skb->data;
+	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+		IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+			  res->hdr.flags);
+		return 1;
+	}
+
+	switch (res->u.add_sta.status) {
+	case ADD_STA_SUCCESS_MSK:
+		break;
+	default:
+		break;
+	}
+
+	/* We didn't cache the SKB; let the caller free it */
+	return 1;
+}
+
+int iwl_send_add_station(struct iwl_priv *priv,
+			 struct iwl_addsta_cmd *sta, u8 flags)
+{
+	struct iwl_rx_packet *res = NULL;
+	int rc = 0;
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_ADD_STA,
+		.len = sizeof(struct iwl_addsta_cmd),
+		.meta.flags = flags,
+		.data = sta,
+	};
+
+	if (flags & CMD_ASYNC)
+		cmd.meta.u.callback = iwl_add_sta_sync_callback;
+	else
+		cmd.meta.flags |= CMD_WANT_SKB;
+
+	rc = iwl_send_cmd(priv, &cmd);
+
+	if (rc || (flags & CMD_ASYNC))
+		return rc;
+
+	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+		IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+			  res->hdr.flags);
+		rc = -EIO;
+	}
+
+	if (rc == 0) {
+		switch (res->u.add_sta.status) {
+		case ADD_STA_SUCCESS_MSK:
+			IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
+			break;
+		default:
+			rc = -EIO;
+			IWL_WARNING("REPLY_ADD_STA failed\n");
+			break;
+		}
+	}
+
+	priv->alloc_rxb_skb--;
+	dev_kfree_skb_any(cmd.meta.u.skb);
+
+	return rc;
+}
+
+static int iwl_update_sta_key_info(struct iwl_priv *priv,
+				   struct ieee80211_key_conf *keyconf,
+				   u8 sta_id)
+{
+	unsigned long flags;
+	__le16 key_flags = 0;
+
+	switch (keyconf->alg) {
+	case ALG_CCMP:
+		key_flags |= STA_KEY_FLG_CCMP;
+		key_flags |= cpu_to_le16(
+				keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+		key_flags &= ~STA_KEY_FLG_INVALID;
+		break;
+	case ALG_TKIP:
+	case ALG_WEP:
+		return -EINVAL;
+	default:
+		return -EINVAL;
+	}
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	priv->stations[sta_id].keyinfo.alg = keyconf->alg;
+	priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
+	memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
+	       keyconf->keylen);
+
+	memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
+	       keyconf->keylen);
+	priv->stations[sta_id].sta.key.key_flags = key_flags;
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
+	iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+	return 0;
+}
+
+static int iwl_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
+	memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl_keyinfo));
+	priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
+	iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+	return 0;
+}
+
+static void iwl_clear_free_frames(struct iwl_priv *priv)
+{
+	struct list_head *element;
+
+	IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n",
+		       priv->frames_count);
+
+	while (!list_empty(&priv->free_frames)) {
+		element = priv->free_frames.next;
+		list_del(element);
+		kfree(list_entry(element, struct iwl_frame, list));
+		priv->frames_count--;
+	}
+
+	if (priv->frames_count) {
+		IWL_WARNING("%d frames still in use.  Did we lose one?\n",
+			    priv->frames_count);
+		priv->frames_count = 0;
+	}
+}
+
+static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv)
+{
+	struct iwl_frame *frame;
+	struct list_head *element;
+	if (list_empty(&priv->free_frames)) {
+		frame = kzalloc(sizeof(*frame), GFP_KERNEL);
+		if (!frame) {
+			IWL_ERROR("Could not allocate frame!\n");
+			return NULL;
+		}
+
+		priv->frames_count++;
+		return frame;
+	}
+
+	element = priv->free_frames.next;
+	list_del(element);
+	return list_entry(element, struct iwl_frame, list);
+}
+
+static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
+{
+	memset(frame, 0, sizeof(*frame));
+	list_add(&frame->list, &priv->free_frames);
+}
+
+unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
+				struct ieee80211_hdr *hdr,
+				const u8 *dest, int left)
+{
+
+	if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
+	    ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) &&
+	     (priv->iw_mode != IEEE80211_IF_TYPE_AP)))
+		return 0;
+
+	if (priv->ibss_beacon->len > left)
+		return 0;
+
+	memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len);
+
+	return priv->ibss_beacon->len;
+}
+
+static int iwl_rate_index_from_plcp(int plcp)
+{
+	int i = 0;
+
+	for (i = 0; i < IWL_RATE_COUNT; i++)
+		if (iwl_rates[i].plcp == plcp)
+			return i;
+	return -1;
+}
+
+static u8 iwl_rate_get_lowest_plcp(int rate_mask)
+{
+	u8 i;
+
+	for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
+	     i = iwl_rates[i].next_ieee) {
+		if (rate_mask & (1 << i))
+			return iwl_rates[i].plcp;
+	}
+
+	return IWL_RATE_INVALID;
+}
+
+static int iwl_send_beacon_cmd(struct iwl_priv *priv)
+{
+	struct iwl_frame *frame;
+	unsigned int frame_size;
+	int rc;
+	u8 rate;
+
+	frame = iwl_get_free_frame(priv);
+
+	if (!frame) {
+		IWL_ERROR("Could not obtain free frame buffer for beacon "
+			  "command.\n");
+		return -ENOMEM;
+	}
+
+	if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) {
+		rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic &
+						0xFF0);
+		if (rate == IWL_INVALID_RATE)
+			rate = IWL_RATE_6M_PLCP;
+	} else {
+		rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & 0xF);
+		if (rate == IWL_INVALID_RATE)
+			rate = IWL_RATE_1M_PLCP;
+	}
+
+	frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate);
+
+	rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
+			      &frame->u.cmd[0]);
+
+	iwl_free_frame(priv, frame);
+
+	return rc;
+}
+
+/******************************************************************************
+ *
+ * EEPROM related functions
+ *
+ ******************************************************************************/
+
+static void get_eeprom_mac(struct iwl_priv *priv, u8 *mac)
+{
+	memcpy(mac, priv->eeprom.mac_address, 6);
+}
+
+/**
+ * iwl_eeprom_init - read EEPROM contents
+ *
+ * Load the EEPROM from adapter into priv->eeprom
+ *
+ * NOTE:  This routine uses the non-debug IO access functions.
+ */
+int iwl_eeprom_init(struct iwl_priv *priv)
+{
+	u16 *e = (u16 *)&priv->eeprom;
+	u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
+	u32 r;
+	int sz = sizeof(priv->eeprom);
+	int rc;
+	int i;
+	u16 addr;
+
+	/* The EEPROM structure has several padding buffers within it
+	 * and when adding new EEPROM maps is subject to programmer errors
+	 * which may be very difficult to identify without explicitly
+	 * checking the resulting size of the eeprom map. */
+	BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE);
+
+	if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
+		IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp);
+		return -ENOENT;
+	}
+
+	rc = iwl_eeprom_aqcuire_semaphore(priv);
+	if (rc < 0) {
+		IWL_ERROR("Failed to aqcuire EEPROM semaphore.\n");
+		return -ENOENT;
+	}
+
+	/* eeprom is an array of 16bit values */
+	for (addr = 0; addr < sz; addr += sizeof(u16)) {
+		_iwl_write32(priv, CSR_EEPROM_REG, addr << 1);
+		_iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
+
+		for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT;
+					i += IWL_EEPROM_ACCESS_DELAY) {
+			r = _iwl_read_restricted(priv, CSR_EEPROM_REG);
+			if (r & CSR_EEPROM_REG_READ_VALID_MSK)
+				break;
+			udelay(IWL_EEPROM_ACCESS_DELAY);
+		}
+
+		if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) {
+			IWL_ERROR("Time out reading EEPROM[%d]", addr);
+			return -ETIMEDOUT;
+		}
+		e[addr / 2] = le16_to_cpu(r >> 16);
+	}
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ * Misc. internal state and helper functions
+ *
+ ******************************************************************************/
+#ifdef CONFIG_IWLWIFI_DEBUG
+
+/**
+ * iwl_report_frame - dump frame to syslog during debug sessions
+ *
+ * hack this function to show different aspects of received frames,
+ * including selective frame dumps.
+ * group100 parameter selects whether to show 1 out of 100 good frames.
+ *
+ * TODO:  ieee80211_hdr stuff is common to 3945 and 4965, so frame type
+ *        info output is okay, but some of this stuff (e.g. iwl_rx_frame_stats)
+ *        is 3945-specific and gives bad output for 4965.  Need to split the
+ *        functionality, keep common stuff here.
+ */
+void iwl_report_frame(struct iwl_priv *priv,
+		      struct iwl_rx_packet *pkt,
+		      struct ieee80211_hdr *header, int group100)
+{
+	u32 to_us;
+	u32 print_summary = 0;
+	u32 print_dump = 0;	/* set to 1 to dump all frames' contents */
+	u32 hundred = 0;
+	u32 dataframe = 0;
+	u16 fc;
+	u16 seq_ctl;
+	u16 channel;
+	u16 phy_flags;
+	int rate_sym;
+	u16 length;
+	u16 status;
+	u16 bcn_tmr;
+	u32 tsf_low;
+	u64 tsf;
+	u8 rssi;
+	u8 agc;
+	u16 sig_avg;
+	u16 noise_diff;
+	struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
+	struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+	struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+	u8 *data = IWL_RX_DATA(pkt);
+
+	/* MAC header */
+	fc = le16_to_cpu(header->frame_control);
+	seq_ctl = le16_to_cpu(header->seq_ctrl);
+
+	/* metadata */
+	channel = le16_to_cpu(rx_hdr->channel);
+	phy_flags = le16_to_cpu(rx_hdr->phy_flags);
+	rate_sym = rx_hdr->rate;
+	length = le16_to_cpu(rx_hdr->len);
+
+	/* end-of-frame status and timestamp */
+	status = le32_to_cpu(rx_end->status);
+	bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
+	tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
+	tsf = le64_to_cpu(rx_end->timestamp);
+
+	/* signal statistics */
+	rssi = rx_stats->rssi;
+	agc = rx_stats->agc;
+	sig_avg = le16_to_cpu(rx_stats->sig_avg);
+	noise_diff = le16_to_cpu(rx_stats->noise_diff);
+
+	to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
+
+	/* if data frame is to us and all is good,
+	 *   (optionally) print summary for only 1 out of every 100 */
+	if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) ==
+	    (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
+		dataframe = 1;
+		if (!group100)
+			print_summary = 1;	/* print each frame */
+		else if (priv->framecnt_to_us < 100) {
+			priv->framecnt_to_us++;
+			print_summary = 0;
+		} else {
+			priv->framecnt_to_us = 0;
+			print_summary = 1;
+			hundred = 1;
+		}
+	} else {
+		/* print summary for all other frames */
+		print_summary = 1;
+	}
+
+	if (print_summary) {
+		char *title;
+		u32 rate;
+
+		if (hundred)
+			title = "100Frames";
+		else if (fc & IEEE80211_FCTL_RETRY)
+			title = "Retry";
+		else if (ieee80211_is_assoc_response(fc))
+			title = "AscRsp";
+		else if (ieee80211_is_reassoc_response(fc))
+			title = "RasRsp";
+		else if (ieee80211_is_probe_response(fc)) {
+			title = "PrbRsp";
+			print_dump = 1;	/* dump frame contents */
+		} else if (ieee80211_is_beacon(fc)) {
+			title = "Beacon";
+			print_dump = 1;	/* dump frame contents */
+		} else if (ieee80211_is_atim(fc))
+			title = "ATIM";
+		else if (ieee80211_is_auth(fc))
+			title = "Auth";
+		else if (ieee80211_is_deauth(fc))
+			title = "DeAuth";
+		else if (ieee80211_is_disassoc(fc))
+			title = "DisAssoc";
+		else
+			title = "Frame";
+
+		rate = iwl_rate_index_from_plcp(rate_sym);
+		if (rate == -1)
+			rate = 0;
+		else
+			rate = iwl_rates[rate].ieee / 2;
+
+		/* print frame summary.
+		 * MAC addresses show just the last byte (for brevity),
+		 *    but you can hack it to show more, if you'd like to. */
+		if (dataframe)
+			IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, "
+				     "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
+				     title, fc, header->addr1[5],
+				     length, rssi, channel, rate);
+		else {
+			/* src/dst addresses assume managed mode */
+			IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, "
+				     "src=0x%02x, rssi=%u, tim=%lu usec, "
+				     "phy=0x%02x, chnl=%d\n",
+				     title, fc, header->addr1[5],
+				     header->addr3[5], rssi,
+				     tsf_low - priv->scan_start_tsf,
+				     phy_flags, channel);
+		}
+	}
+	if (print_dump)
+		iwl_print_hex_dump(IWL_DL_RX, data, length);
+}
+#endif
+
+static void iwl_unset_hw_setting(struct iwl_priv *priv)
+{
+	if (priv->hw_setting.shared_virt)
+		pci_free_consistent(priv->pci_dev,
+				    sizeof(struct iwl_shared),
+				    priv->hw_setting.shared_virt,
+				    priv->hw_setting.shared_phys);
+}
+
+/**
+ * iwl_supported_rate_to_ie - fill in the supported rate in IE field
+ *
+ * return : set the bit for each supported rate insert in ie
+ */
+static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
+				    u16 basic_rate, int max_count)
+{
+	u16 ret_rates = 0, bit;
+	int i;
+	u8 *rates;
+
+	rates = &(ie[1]);
+
+	for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
+		if (bit & supported_rate) {
+			ret_rates |= bit;
+			rates[*ie] = iwl_rates[i].ieee |
+			    ((bit & basic_rate) ? 0x80 : 0x00);
+			*ie = *ie + 1;
+			if (*ie >= max_count)
+				break;
+		}
+	}
+
+	return ret_rates;
+}
+
+/**
+ * iwl_fill_probe_req - fill in all required fields and IE for probe request
+ */
+static u16 iwl_fill_probe_req(struct iwl_priv *priv,
+			      struct ieee80211_mgmt *frame,
+			      int left, int is_direct)
+{
+	int len = 0;
+	u8 *pos = NULL;
+	u16 ret_rates;
+
+	/* Make sure there is enough space for the probe request,
+	 * two mandatory IEs and the data */
+	left -= 24;
+	if (left < 0)
+		return 0;
+	len += 24;
+
+	frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
+	memcpy(frame->da, BROADCAST_ADDR, ETH_ALEN);
+	memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
+	memcpy(frame->bssid, BROADCAST_ADDR, ETH_ALEN);
+	frame->seq_ctrl = 0;
+
+	/* fill in our indirect SSID IE */
+	/* ...next IE... */
+
+	left -= 2;
+	if (left < 0)
+		return 0;
+	len += 2;
+	pos = &(frame->u.probe_req.variable[0]);
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = 0;
+
+	/* fill in our direct SSID IE... */
+	if (is_direct) {
+		/* ...next IE... */
+		left -= 2 + priv->essid_len;
+		if (left < 0)
+			return 0;
+		/* ... fill it in... */
+		*pos++ = WLAN_EID_SSID;
+		*pos++ = priv->essid_len;
+		memcpy(pos, priv->essid, priv->essid_len);
+		pos += priv->essid_len;
+		len += 2 + priv->essid_len;
+	}
+
+	/* fill in supported rate */
+	/* ...next IE... */
+	left -= 2;
+	if (left < 0)
+		return 0;
+	/* ... fill it in... */
+	*pos++ = WLAN_EID_SUPP_RATES;
+	*pos = 0;
+	ret_rates = priv->active_rate = priv->rates_mask;
+	priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+
+	iwl_supported_rate_to_ie(pos, priv->active_rate,
+				 priv->active_rate_basic, left);
+	len += 2 + *pos;
+	pos += (*pos) + 1;
+	ret_rates = ~ret_rates & priv->active_rate;
+
+	if (ret_rates == 0)
+		goto fill_end;
+
+	/* fill in supported extended rate */
+	/* ...next IE... */
+	left -= 2;
+	if (left < 0)
+		return 0;
+	/* ... fill it in... */
+	*pos++ = WLAN_EID_EXT_SUPP_RATES;
+	*pos = 0;
+	iwl_supported_rate_to_ie(pos, ret_rates, priv->active_rate_basic, left);
+	if (*pos > 0)
+		len += 2 + *pos;
+
+ fill_end:
+	return (u16)len;
+}
+
+/*
+ * QoS  support
+*/
+#ifdef CONFIG_IWLWIFI_QOS
+static int iwl_send_qos_params_command(struct iwl_priv *priv,
+				       struct iwl_qosparam_cmd *qos)
+{
+
+	return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM,
+				sizeof(struct iwl_qosparam_cmd), qos);
+}
+
+static void iwl_reset_qos(struct iwl_priv *priv)
+{
+	u16 cw_min = 15;
+	u16 cw_max = 1023;
+	u8 aifs = 2;
+	u8 is_legacy = 0;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->qos_data.qos_active = 0;
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) {
+		if (priv->qos_data.qos_enable)
+			priv->qos_data.qos_active = 1;
+		if (!(priv->active_rate & 0xfff0)) {
+			cw_min = 31;
+			is_legacy = 1;
+		}
+	} else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		if (priv->qos_data.qos_enable)
+			priv->qos_data.qos_active = 1;
+	} else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) {
+		cw_min = 31;
+		is_legacy = 1;
+	}
+
+	if (priv->qos_data.qos_active)
+		aifs = 3;
+
+	priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min);
+	priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max);
+	priv->qos_data.def_qos_parm.ac[0].aifsn = aifs;
+	priv->qos_data.def_qos_parm.ac[0].edca_txop = 0;
+	priv->qos_data.def_qos_parm.ac[0].reserved1 = 0;
+
+	if (priv->qos_data.qos_active) {
+		i = 1;
+		priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min);
+		priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max);
+		priv->qos_data.def_qos_parm.ac[i].aifsn = 7;
+		priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+		priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+		i = 2;
+		priv->qos_data.def_qos_parm.ac[i].cw_min =
+			cpu_to_le16((cw_min + 1) / 2 - 1);
+		priv->qos_data.def_qos_parm.ac[i].cw_max =
+			cpu_to_le16(cw_max);
+		priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+		if (is_legacy)
+			priv->qos_data.def_qos_parm.ac[i].edca_txop =
+				cpu_to_le16(6016);
+		else
+			priv->qos_data.def_qos_parm.ac[i].edca_txop =
+				cpu_to_le16(3008);
+		priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+		i = 3;
+		priv->qos_data.def_qos_parm.ac[i].cw_min =
+			cpu_to_le16((cw_min + 1) / 4 - 1);
+		priv->qos_data.def_qos_parm.ac[i].cw_max =
+			cpu_to_le16((cw_max + 1) / 2 - 1);
+		priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+		priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+		if (is_legacy)
+			priv->qos_data.def_qos_parm.ac[i].edca_txop =
+				cpu_to_le16(3264);
+		else
+			priv->qos_data.def_qos_parm.ac[i].edca_txop =
+				cpu_to_le16(1504);
+	} else {
+		for (i = 1; i < 4; i++) {
+			priv->qos_data.def_qos_parm.ac[i].cw_min =
+				cpu_to_le16(cw_min);
+			priv->qos_data.def_qos_parm.ac[i].cw_max =
+				cpu_to_le16(cw_max);
+			priv->qos_data.def_qos_parm.ac[i].aifsn = aifs;
+			priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+			priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+		}
+	}
+	IWL_DEBUG_QOS("set QoS to default \n");
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
+{
+	unsigned long flags;
+
+	if (priv == NULL)
+		return;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	if (!priv->qos_data.qos_enable)
+		return;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->qos_data.def_qos_parm.qos_flags = 0;
+
+	if (priv->qos_data.qos_cap.q_AP.queue_request &&
+	    !priv->qos_data.qos_cap.q_AP.txop_request)
+		priv->qos_data.def_qos_parm.qos_flags |=
+			QOS_PARAM_FLG_TXOP_TYPE_MSK;
+
+	if (priv->qos_data.qos_active)
+		priv->qos_data.def_qos_parm.qos_flags |=
+			QOS_PARAM_FLG_UPDATE_EDCA_MSK;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (force || iwl_is_associated(priv)) {
+		IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n",
+			      priv->qos_data.qos_active);
+
+		iwl_send_qos_params_command(priv,
+				&(priv->qos_data.def_qos_parm));
+	}
+}
+
+#endif /* CONFIG_IWLWIFI_QOS */
+/*
+ * Power management (not Tx power!) functions
+ */
+#define MSEC_TO_USEC 1024
+
+#define NOSLP __constant_cpu_to_le32(0)
+#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK
+#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC)
+#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \
+				     __constant_cpu_to_le32(X1), \
+				     __constant_cpu_to_le32(X2), \
+				     __constant_cpu_to_le32(X3), \
+				     __constant_cpu_to_le32(X4)}
+
+
+/* default power management (not Tx power) table values */
+/* for tim  0-10 */
+static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
+	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
+	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0},
+	{{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0},
+	{{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1},
+	{{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1}
+};
+
+/* for tim > 10 */
+static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
+	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
+		 SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
+	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300),
+		 SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
+	{{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100),
+		 SLP_VEC(2, 6, 9, 9, 0xFF)}, 0},
+	{{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
+	{{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25),
+		 SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
+};
+
+int iwl_power_init_handle(struct iwl_priv *priv)
+{
+	int rc = 0, i;
+	struct iwl_power_mgr *pow_data;
+	int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC;
+	u16 pci_pm;
+
+	IWL_DEBUG_POWER("Initialize power \n");
+
+	pow_data = &(priv->power_data);
+
+	memset(pow_data, 0, sizeof(*pow_data));
+
+	pow_data->active_index = IWL_POWER_RANGE_0;
+	pow_data->dtim_val = 0xffff;
+
+	memcpy(&pow_data->pwr_range_0[0], &range_0[0], size);
+	memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
+
+	rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm);
+	if (rc != 0)
+		return 0;
+	else {
+		struct iwl_powertable_cmd *cmd;
+
+		IWL_DEBUG_POWER("adjust power command flags\n");
+
+		for (i = 0; i < IWL_POWER_AC; i++) {
+			cmd = &pow_data->pwr_range_0[i].cmd;
+
+			if (pci_pm & 0x1)
+				cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
+			else
+				cmd->flags |= IWL_POWER_PCI_PM_MSK;
+		}
+	}
+	return rc;
+}
+
+static int iwl_update_power_cmd(struct iwl_priv *priv,
+				struct iwl_powertable_cmd *cmd, u32 mode)
+{
+	int rc = 0, i;
+	u8 skip;
+	u32 max_sleep = 0;
+	struct iwl_power_vec_entry *range;
+	u8 period = 0;
+	struct iwl_power_mgr *pow_data;
+
+	if (mode > IWL_POWER_INDEX_5) {
+		IWL_DEBUG_POWER("Error invalid power mode \n");
+		return -1;
+	}
+	pow_data = &(priv->power_data);
+
+	if (pow_data->active_index == IWL_POWER_RANGE_0)
+		range = &pow_data->pwr_range_0[0];
+	else
+		range = &pow_data->pwr_range_1[1];
+
+	memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd));
+
+#ifdef IWL_MAC80211_DISABLE
+	if (priv->assoc_network != NULL) {
+		unsigned long flags;
+
+		period = priv->assoc_network->tim.tim_period;
+	}
+#endif	/*IWL_MAC80211_DISABLE */
+	skip = range[mode].no_dtim;
+
+	if (period == 0) {
+		period = 1;
+		skip = 0;
+	}
+
+	if (skip == 0) {
+		max_sleep = period;
+		cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
+	} else {
+		__le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
+		max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
+		cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
+	}
+
+	for (i = 0; i < IWL_POWER_VEC_SIZE; i++) {
+		if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
+			cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
+	}
+
+	IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags);
+	IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
+	IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
+	IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n",
+			le32_to_cpu(cmd->sleep_interval[0]),
+			le32_to_cpu(cmd->sleep_interval[1]),
+			le32_to_cpu(cmd->sleep_interval[2]),
+			le32_to_cpu(cmd->sleep_interval[3]),
+			le32_to_cpu(cmd->sleep_interval[4]));
+
+	return rc;
+}
+
+static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
+{
+	u32 final_mode = mode;
+	int rc;
+	struct iwl_powertable_cmd cmd;
+
+	/* If on battery, set to 3,
+	 * if plugged into AC power, set to CAM ("continuosly aware mode"),
+	 * else user level */
+	switch (mode) {
+	case IWL_POWER_BATTERY:
+		final_mode = IWL_POWER_INDEX_3;
+		break;
+	case IWL_POWER_AC:
+		final_mode = IWL_POWER_MODE_CAM;
+		break;
+	default:
+		final_mode = mode;
+		break;
+	}
+
+	iwl_update_power_cmd(priv, &cmd, final_mode);
+
+	rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd);
+
+	if (final_mode == IWL_POWER_MODE_CAM)
+		clear_bit(STATUS_POWER_PMI, &priv->status);
+	else
+		set_bit(STATUS_POWER_PMI, &priv->status);
+
+	return rc;
+}
+
+int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+{
+	/* Filter incoming packets to determine if they are targeted toward
+	 * this network, discarding packets coming from ourselves */
+	switch (priv->iw_mode) {
+	case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source    | BSSID */
+		/* packets from our adapter are dropped (echo) */
+		if (!compare_ether_addr(header->addr2, priv->mac_addr))
+			return 0;
+		/* {broad,multi}cast packets to our IBSS go through */
+		if (is_multicast_ether_addr(header->addr1))
+			return !compare_ether_addr(header->addr3, priv->bssid);
+		/* packets to our adapter go through */
+		return !compare_ether_addr(header->addr1, priv->mac_addr);
+	case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
+		/* packets from our adapter are dropped (echo) */
+		if (!compare_ether_addr(header->addr3, priv->mac_addr))
+			return 0;
+		/* {broad,multi}cast packets to our BSS go through */
+		if (is_multicast_ether_addr(header->addr1))
+			return !compare_ether_addr(header->addr2, priv->bssid);
+		/* packets to our adapter go through */
+		return !compare_ether_addr(header->addr1, priv->mac_addr);
+	}
+
+	return 1;
+}
+
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+const char *iwl_get_tx_fail_reason(u32 status)
+{
+	switch (status & TX_STATUS_MSK) {
+	case TX_STATUS_SUCCESS:
+		return "SUCCESS";
+		TX_STATUS_ENTRY(SHORT_LIMIT);
+		TX_STATUS_ENTRY(LONG_LIMIT);
+		TX_STATUS_ENTRY(FIFO_UNDERRUN);
+		TX_STATUS_ENTRY(MGMNT_ABORT);
+		TX_STATUS_ENTRY(NEXT_FRAG);
+		TX_STATUS_ENTRY(LIFE_EXPIRE);
+		TX_STATUS_ENTRY(DEST_PS);
+		TX_STATUS_ENTRY(ABORTED);
+		TX_STATUS_ENTRY(BT_RETRY);
+		TX_STATUS_ENTRY(STA_INVALID);
+		TX_STATUS_ENTRY(FRAG_DROPPED);
+		TX_STATUS_ENTRY(TID_DISABLE);
+		TX_STATUS_ENTRY(FRAME_FLUSHED);
+		TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
+		TX_STATUS_ENTRY(TX_LOCKED);
+		TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
+	}
+
+	return "UNKNOWN";
+}
+
+/**
+ * iwl_scan_cancel - Cancel any currently executing HW scan
+ *
+ * NOTE: priv->mutex is not required before calling this function
+ */
+static int iwl_scan_cancel(struct iwl_priv *priv)
+{
+	if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
+		clear_bit(STATUS_SCANNING, &priv->status);
+		return 0;
+	}
+
+	if (test_bit(STATUS_SCANNING, &priv->status)) {
+		if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+			IWL_DEBUG_SCAN("Queuing scan abort.\n");
+			set_bit(STATUS_SCAN_ABORTING, &priv->status);
+			queue_work(priv->workqueue, &priv->abort_scan);
+
+		} else
+			IWL_DEBUG_SCAN("Scan abort already in progress.\n");
+
+		return test_bit(STATUS_SCANNING, &priv->status);
+	}
+
+	return 0;
+}
+
+/**
+ * iwl_scan_cancel_timeout - Cancel any currently executing HW scan
+ * @ms: amount of time to wait (in milliseconds) for scan to abort
+ *
+ * NOTE: priv->mutex must be held before calling this function
+ */
+static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
+{
+	unsigned long now = jiffies;
+	int ret;
+
+	ret = iwl_scan_cancel(priv);
+	if (ret && ms) {
+		mutex_unlock(&priv->mutex);
+		while (!time_after(jiffies, now + msecs_to_jiffies(ms)) &&
+				test_bit(STATUS_SCANNING, &priv->status))
+			msleep(1);
+		mutex_lock(&priv->mutex);
+
+		return test_bit(STATUS_SCANNING, &priv->status);
+	}
+
+	return ret;
+}
+
+static void iwl_sequence_reset(struct iwl_priv *priv)
+{
+	/* Reset ieee stats */
+
+	/* We don't reset the net_device_stats (ieee->stats) on
+	 * re-association */
+
+	priv->last_seq_num = -1;
+	priv->last_frag_num = -1;
+	priv->last_packet_time = 0;
+
+	iwl_scan_cancel(priv);
+}
+
+#define MAX_UCODE_BEACON_INTERVAL	1024
+#define INTEL_CONN_LISTEN_INTERVAL	__constant_cpu_to_le16(0xA)
+
+static __le16 iwl_adjust_beacon_interval(u16 beacon_val)
+{
+	u16 new_val = 0;
+	u16 beacon_factor = 0;
+
+	beacon_factor =
+	    (beacon_val + MAX_UCODE_BEACON_INTERVAL)
+		/ MAX_UCODE_BEACON_INTERVAL;
+	new_val = beacon_val / beacon_factor;
+
+	return cpu_to_le16(new_val);
+}
+
+static void iwl_setup_rxon_timing(struct iwl_priv *priv)
+{
+	u64 interval_tm_unit;
+	u64 tsf, result;
+	unsigned long flags;
+	struct ieee80211_conf *conf = NULL;
+	u16 beacon_int = 0;
+
+	conf = ieee80211_get_hw_conf(priv->hw);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp1);
+	priv->rxon_timing.timestamp.dw[0] = cpu_to_le32(priv->timestamp0);
+
+	priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL;
+
+	tsf = priv->timestamp1;
+	tsf = ((tsf << 32) | priv->timestamp0);
+
+	beacon_int = priv->beacon_int;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+		if (beacon_int == 0) {
+			priv->rxon_timing.beacon_interval = cpu_to_le16(100);
+			priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
+		} else {
+			priv->rxon_timing.beacon_interval =
+				cpu_to_le16(beacon_int);
+			priv->rxon_timing.beacon_interval =
+			    iwl_adjust_beacon_interval(
+				le16_to_cpu(priv->rxon_timing.beacon_interval));
+		}
+
+		priv->rxon_timing.atim_window = 0;
+	} else {
+		priv->rxon_timing.beacon_interval =
+			iwl_adjust_beacon_interval(conf->beacon_int);
+		/* TODO: we need to get atim_window from upper stack
+		 * for now we set to 0 */
+		priv->rxon_timing.atim_window = 0;
+	}
+
+	interval_tm_unit =
+		(le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024);
+	result = do_div(tsf, interval_tm_unit);
+	priv->rxon_timing.beacon_init_val =
+	    cpu_to_le32((u32) ((u64) interval_tm_unit - result));
+
+	IWL_DEBUG_ASSOC
+	    ("beacon interval %d beacon timer %d beacon tim %d\n",
+		le16_to_cpu(priv->rxon_timing.beacon_interval),
+		le32_to_cpu(priv->rxon_timing.beacon_init_val),
+		le16_to_cpu(priv->rxon_timing.atim_window));
+}
+
+static int iwl_scan_initiate(struct iwl_priv *priv)
+{
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		IWL_ERROR("APs don't scan.\n");
+		return 0;
+	}
+
+	if (!iwl_is_ready_rf(priv)) {
+		IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
+		return -EIO;
+	}
+
+	if (test_bit(STATUS_SCANNING, &priv->status)) {
+		IWL_DEBUG_SCAN("Scan already in progress.\n");
+		return -EAGAIN;
+	}
+
+	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG_SCAN("Scan request while abort pending.  "
+			       "Queuing.\n");
+		return -EAGAIN;
+	}
+
+	IWL_DEBUG_INFO("Starting scan...\n");
+	priv->scan_bands = 2;
+	set_bit(STATUS_SCANNING, &priv->status);
+	priv->scan_start = jiffies;
+	priv->scan_pass_start = priv->scan_start;
+
+	queue_work(priv->workqueue, &priv->request_scan);
+
+	return 0;
+}
+
+static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+{
+	struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+
+	if (hw_decrypt)
+		rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
+	else
+		rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
+
+	return 0;
+}
+
+static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
+{
+	if (phymode == MODE_IEEE80211A) {
+		priv->staging_rxon.flags &=
+		    ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
+		      | RXON_FLG_CCK_MSK);
+		priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+	} else {
+		/* Copied from iwl_bg_post_associate() */
+		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+		else
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+		if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+		priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+		priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK;
+		priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
+	}
+}
+
+/*
+ * initilize rxon structure with default values fromm eeprom
+ */
+static void iwl_connection_init_rx_config(struct iwl_priv *priv)
+{
+	const struct iwl_channel_info *ch_info;
+
+	memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
+
+	switch (priv->iw_mode) {
+	case IEEE80211_IF_TYPE_AP:
+		priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
+		break;
+
+	case IEEE80211_IF_TYPE_STA:
+		priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS;
+		priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
+		break;
+
+	case IEEE80211_IF_TYPE_IBSS:
+		priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS;
+		priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
+		priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
+						  RXON_FILTER_ACCEPT_GRP_MSK;
+		break;
+
+	case IEEE80211_IF_TYPE_MNTR:
+		priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER;
+		priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK |
+		    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
+		break;
+	}
+
+#if 0
+	/* TODO:  Figure out when short_preamble would be set and cache from
+	 * that */
+	if (!hw_to_local(priv->hw)->short_preamble)
+		priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+	else
+		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+#endif
+
+	ch_info = iwl_get_channel_info(priv, priv->phymode,
+				       le16_to_cpu(priv->staging_rxon.channel));
+
+	if (!ch_info)
+		ch_info = &priv->channel_info[0];
+
+	/*
+	 * in some case A channels are all non IBSS
+	 * in this case force B/G channel
+	 */
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+	    !(is_channel_ibss(ch_info)))
+		ch_info = &priv->channel_info[0];
+
+	priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
+	if (is_channel_a_band(ch_info))
+		priv->phymode = MODE_IEEE80211A;
+	else
+		priv->phymode = MODE_IEEE80211G;
+
+	iwl_set_flags_for_phymode(priv, priv->phymode);
+
+	priv->staging_rxon.ofdm_basic_rates =
+	    (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+	priv->staging_rxon.cck_basic_rates =
+	    (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+}
+
+static int iwl_set_mode(struct iwl_priv *priv, int mode)
+{
+	if (!iwl_is_ready_rf(priv))
+		return -EAGAIN;
+
+	if (mode == IEEE80211_IF_TYPE_IBSS) {
+		const struct iwl_channel_info *ch_info;
+
+		ch_info = iwl_get_channel_info(priv,
+			priv->phymode,
+			le16_to_cpu(priv->staging_rxon.channel));
+
+		if (!ch_info || !is_channel_ibss(ch_info)) {
+			IWL_ERROR("channel %d not IBSS channel\n",
+				  le16_to_cpu(priv->staging_rxon.channel));
+			return -EINVAL;
+		}
+	}
+
+	cancel_delayed_work(&priv->scan_check);
+	if (iwl_scan_cancel_timeout(priv, 100)) {
+		IWL_WARNING("Aborted scan still in progress after 100ms\n");
+		IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
+		return -EAGAIN;
+	}
+
+	priv->iw_mode = mode;
+
+	iwl_connection_init_rx_config(priv);
+	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+
+	iwl_clear_stations_table(priv);
+
+	iwl_commit_rxon(priv);
+
+	return 0;
+}
+
+static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
+				      struct ieee80211_tx_control *ctl,
+				      struct iwl_cmd *cmd,
+				      struct sk_buff *skb_frag,
+				      int last_frag)
+{
+	struct iwl_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo;
+
+	switch (keyinfo->alg) {
+	case ALG_CCMP:
+		cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM;
+		memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen);
+		IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n");
+		break;
+
+	case ALG_TKIP:
+#if 0
+		cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP;
+
+		if (last_frag)
+			memcpy(cmd->cmd.tx.tkip_mic.byte, skb_frag->tail - 8,
+			       8);
+		else
+			memset(cmd->cmd.tx.tkip_mic.byte, 0, 8);
+#endif
+		break;
+
+	case ALG_WEP:
+		cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP |
+		    (ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
+
+		if (keyinfo->keylen == 13)
+			cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
+
+		memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen);
+
+		IWL_DEBUG_TX("Configuring packet for WEP encryption "
+			     "with key %d\n", ctl->key_idx);
+		break;
+
+	default:
+		printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg);
+		break;
+	}
+}
+
+/*
+ * handle build REPLY_TX command notification.
+ */
+static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
+				  struct iwl_cmd *cmd,
+				  struct ieee80211_tx_control *ctrl,
+				  struct ieee80211_hdr *hdr,
+				  int is_unicast, u8 std_id)
+{
+	__le16 *qc;
+	u16 fc = le16_to_cpu(hdr->frame_control);
+	__le32 tx_flags = cmd->cmd.tx.tx_flags;
+
+	cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+	if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) {
+		tx_flags |= TX_CMD_FLG_ACK_MSK;
+		if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
+			tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+		if (ieee80211_is_probe_response(fc) &&
+		    !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
+			tx_flags |= TX_CMD_FLG_TSF_MSK;
+	} else {
+		tx_flags &= (~TX_CMD_FLG_ACK_MSK);
+		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+	}
+
+	cmd->cmd.tx.sta_id = std_id;
+	if (ieee80211_get_morefrag(hdr))
+		tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
+
+	qc = ieee80211_get_qos_ctrl(hdr);
+	if (qc) {
+		cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf);
+		tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
+	} else
+		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+
+	if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+		tx_flags |= TX_CMD_FLG_RTS_MSK;
+		tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+	} else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+		tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+		tx_flags |= TX_CMD_FLG_CTS_MSK;
+	}
+
+	if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
+		tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+
+	tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
+	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+		if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ ||
+		    (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
+			cmd->cmd.tx.timeout.pm_frame_timeout =
+				cpu_to_le16(3);
+		else
+			cmd->cmd.tx.timeout.pm_frame_timeout =
+				cpu_to_le16(2);
+	} else
+		cmd->cmd.tx.timeout.pm_frame_timeout = 0;
+
+	cmd->cmd.tx.driver_txop = 0;
+	cmd->cmd.tx.tx_flags = tx_flags;
+	cmd->cmd.tx.next_frame_len = 0;
+}
+
+static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
+{
+	int sta_id;
+	u16 fc = le16_to_cpu(hdr->frame_control);
+
+	/* If this frame is broadcast or not data then use the broadcast
+	 * station id */
+	if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
+	    is_multicast_ether_addr(hdr->addr1))
+		return priv->hw_setting.bcast_sta_id;
+
+	switch (priv->iw_mode) {
+
+	/* If this frame is part of a BSS network (we're a station), then
+	 * we use the AP's station id */
+	case IEEE80211_IF_TYPE_STA:
+		return IWL_AP_ID;
+
+	/* If we are an AP, then find the station, or use BCAST */
+	case IEEE80211_IF_TYPE_AP:
+		sta_id = iwl_hw_find_station(priv, hdr->addr1);
+		if (sta_id != IWL_INVALID_STATION)
+			return sta_id;
+		return priv->hw_setting.bcast_sta_id;
+
+	/* If this frame is part of a IBSS network, then we use the
+	 * target specific station id */
+	case IEEE80211_IF_TYPE_IBSS: {
+		DECLARE_MAC_BUF(mac);
+
+		sta_id = iwl_hw_find_station(priv, hdr->addr1);
+		if (sta_id != IWL_INVALID_STATION)
+			return sta_id;
+
+		sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC);
+
+		if (sta_id != IWL_INVALID_STATION)
+			return sta_id;
+
+		IWL_DEBUG_DROP("Station %s not in station map. "
+			       "Defaulting to broadcast...\n",
+			       print_mac(mac, hdr->addr1));
+		iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
+		return priv->hw_setting.bcast_sta_id;
+	}
+	default:
+		IWL_WARNING("Unkown mode of operation: %d", priv->iw_mode);
+		return priv->hw_setting.bcast_sta_id;
+	}
+}
+
+/*
+ * start REPLY_TX command process
+ */
+static int iwl_tx_skb(struct iwl_priv *priv,
+		      struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct iwl_tfd_frame *tfd;
+	u32 *control_flags;
+	int txq_id = ctl->queue;
+	struct iwl_tx_queue *txq = NULL;
+	struct iwl_queue *q = NULL;
+	dma_addr_t phys_addr;
+	dma_addr_t txcmd_phys;
+	struct iwl_cmd *out_cmd = NULL;
+	u16 len, idx, len_org;
+	u8 id, hdr_len, unicast;
+	u8 sta_id;
+	u16 seq_number = 0;
+	u16 fc;
+	__le16 *qc;
+	u8 wait_write_ptr = 0;
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (iwl_is_rfkill(priv)) {
+		IWL_DEBUG_DROP("Dropping - RF KILL\n");
+		goto drop_unlock;
+	}
+
+	if (!priv->interface_id) {
+		IWL_DEBUG_DROP("Dropping - !priv->interface_id\n");
+		goto drop_unlock;
+	}
+
+	if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) {
+		IWL_ERROR("ERROR: No TX rate available.\n");
+		goto drop_unlock;
+	}
+
+	unicast = !is_multicast_ether_addr(hdr->addr1);
+	id = 0;
+
+	fc = le16_to_cpu(hdr->frame_control);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (ieee80211_is_auth(fc))
+		IWL_DEBUG_TX("Sending AUTH frame\n");
+	else if (ieee80211_is_assoc_request(fc))
+		IWL_DEBUG_TX("Sending ASSOC frame\n");
+	else if (ieee80211_is_reassoc_request(fc))
+		IWL_DEBUG_TX("Sending REASSOC frame\n");
+#endif
+
+	if (!iwl_is_associated(priv) &&
+	    ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
+		IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
+		goto drop_unlock;
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	hdr_len = ieee80211_get_hdrlen(fc);
+	sta_id = iwl_get_sta_id(priv, hdr);
+	if (sta_id == IWL_INVALID_STATION) {
+		DECLARE_MAC_BUF(mac);
+
+		IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n",
+			       print_mac(mac, hdr->addr1));
+		goto drop;
+	}
+
+	IWL_DEBUG_RATE("station Id %d\n", sta_id);
+
+	qc = ieee80211_get_qos_ctrl(hdr);
+	if (qc) {
+		u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+		seq_number = priv->stations[sta_id].tid[tid].seq_number &
+				IEEE80211_SCTL_SEQ;
+		hdr->seq_ctrl = cpu_to_le16(seq_number) |
+			(hdr->seq_ctrl &
+				__constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
+		seq_number += 0x10;
+	}
+	txq = &priv->txq[txq_id];
+	q = &txq->q;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	tfd = &txq->bd[q->first_empty];
+	memset(tfd, 0, sizeof(*tfd));
+	control_flags = (u32 *) tfd;
+	idx = get_cmd_index(q, q->first_empty, 0);
+
+	memset(&(txq->txb[q->first_empty]), 0, sizeof(struct iwl_tx_info));
+	txq->txb[q->first_empty].skb[0] = skb;
+	memcpy(&(txq->txb[q->first_empty].status.control),
+	       ctl, sizeof(struct ieee80211_tx_control));
+	out_cmd = &txq->cmd[idx];
+	memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
+	memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx));
+	out_cmd->hdr.cmd = REPLY_TX;
+	out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+				INDEX_TO_SEQ(q->first_empty)));
+	/* copy frags header */
+	memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len);
+
+	/* hdr = (struct ieee80211_hdr *)out_cmd->cmd.tx.hdr; */
+	len = priv->hw_setting.tx_cmd_len +
+		sizeof(struct iwl_cmd_header) + hdr_len;
+
+	len_org = len;
+	len = (len + 3) & ~3;
+
+	if (len_org != len)
+		len_org = 1;
+	else
+		len_org = 0;
+
+	txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx +
+		     offsetof(struct iwl_cmd, hdr);
+
+	iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
+
+	if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
+		iwl_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
+
+	/* 802.11 null functions have no payload... */
+	len = skb->len - hdr_len;
+	if (len) {
+		phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
+					   len, PCI_DMA_TODEVICE);
+		iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
+	}
+
+	/* If there is no payload, then only one TFD is used */
+	if (!len)
+		*control_flags = TFD_CTL_COUNT_SET(1);
+	else
+		*control_flags = TFD_CTL_COUNT_SET(2) |
+			TFD_CTL_PAD_SET(U32_PAD(len));
+
+	len = (u16)skb->len;
+	out_cmd->cmd.tx.len = cpu_to_le16(len);
+
+	/* TODO need this for burst mode later on */
+	iwl_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
+
+	/* set is_hcca to 0; it probably will never be implemented */
+	iwl_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
+
+	out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_A_MSK;
+	out_cmd->cmd.tx.tx_flags &= ~TX_CMD_FLG_ANT_B_MSK;
+
+	if (!ieee80211_get_morefrag(hdr)) {
+		txq->need_update = 1;
+		if (qc) {
+			u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+			priv->stations[sta_id].tid[tid].seq_number = seq_number;
+		}
+	} else {
+		wait_write_ptr = 1;
+		txq->need_update = 0;
+	}
+
+	iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload,
+			   sizeof(out_cmd->cmd.tx));
+
+	iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
+			   ieee80211_get_hdrlen(fc));
+
+	q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
+	rc = iwl_tx_queue_update_write_ptr(priv, txq);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (rc)
+		return rc;
+
+	if ((iwl_queue_space(q) < q->high_mark)
+	    && priv->mac80211_registered) {
+		if (wait_write_ptr) {
+			spin_lock_irqsave(&priv->lock, flags);
+			txq->need_update = 1;
+			iwl_tx_queue_update_write_ptr(priv, txq);
+			spin_unlock_irqrestore(&priv->lock, flags);
+		}
+
+		ieee80211_stop_queue(priv->hw, ctl->queue);
+	}
+
+	return 0;
+
+drop_unlock:
+	spin_unlock_irqrestore(&priv->lock, flags);
+drop:
+	return -1;
+}
+
+static void iwl_set_rate(struct iwl_priv *priv)
+{
+	const struct ieee80211_hw_mode *hw = NULL;
+	struct ieee80211_rate *rate;
+	int i;
+
+	hw = iwl_get_hw_mode(priv, priv->phymode);
+
+	priv->active_rate = 0;
+	priv->active_rate_basic = 0;
+
+	IWL_DEBUG_RATE("Setting rates for 802.11%c\n",
+		       hw->mode == MODE_IEEE80211A ?
+		       'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g'));
+
+	for (i = 0; i < hw->num_rates; i++) {
+		rate = &(hw->rates[i]);
+		if ((rate->val < IWL_RATE_COUNT) &&
+		    (rate->flags & IEEE80211_RATE_SUPPORTED)) {
+			IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n",
+				       rate->val, iwl_rates[rate->val].plcp,
+				       (rate->flags & IEEE80211_RATE_BASIC) ?
+				       "*" : "");
+			priv->active_rate |= (1 << rate->val);
+			if (rate->flags & IEEE80211_RATE_BASIC)
+				priv->active_rate_basic |= (1 << rate->val);
+		} else
+			IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n",
+				       rate->val, iwl_rates[rate->val].plcp);
+	}
+
+	IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
+		       priv->active_rate, priv->active_rate_basic);
+
+	/*
+	 * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK)
+	 * otherwise set it to the default of all CCK rates and 6, 12, 24 for
+	 * OFDM
+	 */
+	if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK)
+		priv->staging_rxon.cck_basic_rates =
+		    ((priv->active_rate_basic &
+		      IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF;
+	else
+		priv->staging_rxon.cck_basic_rates =
+		    (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+
+	if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK)
+		priv->staging_rxon.ofdm_basic_rates =
+		    ((priv->active_rate_basic &
+		      (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >>
+		      IWL_FIRST_OFDM_RATE) & 0xFF;
+	else
+		priv->staging_rxon.ofdm_basic_rates =
+		   (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+}
+
+static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
+{
+	unsigned long flags;
+
+	if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status))
+		return;
+
+	IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n",
+			  disable_radio ? "OFF" : "ON");
+
+	if (disable_radio) {
+		iwl_scan_cancel(priv);
+		/* FIXME: This is a workaround for AP */
+		if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+			spin_lock_irqsave(&priv->lock, flags);
+			iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+				    CSR_UCODE_SW_BIT_RFKILL);
+			spin_unlock_irqrestore(&priv->lock, flags);
+			iwl_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0);
+			set_bit(STATUS_RF_KILL_SW, &priv->status);
+		}
+		return;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+	clear_bit(STATUS_RF_KILL_SW, &priv->status);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	/* wake up ucode */
+	msleep(10);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl_read32(priv, CSR_UCODE_DRV_GP1);
+	if (!iwl_grab_restricted_access(priv))
+		iwl_release_restricted_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
+		IWL_DEBUG_RF_KILL("Can not turn radio back on - "
+				  "disabled by HW switch\n");
+		return;
+	}
+
+	queue_work(priv->workqueue, &priv->restart);
+	return;
+}
+
+void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
+			    u32 decrypt_res, struct ieee80211_rx_status *stats)
+{
+	u16 fc =
+	    le16_to_cpu(((struct ieee80211_hdr *)skb->data)->frame_control);
+
+	if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK)
+		return;
+
+	if (!(fc & IEEE80211_FCTL_PROTECTED))
+		return;
+
+	IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res);
+	switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
+	case RX_RES_STATUS_SEC_TYPE_TKIP:
+		if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+		    RX_RES_STATUS_BAD_ICV_MIC)
+			stats->flag |= RX_FLAG_MMIC_ERROR;
+	case RX_RES_STATUS_SEC_TYPE_WEP:
+	case RX_RES_STATUS_SEC_TYPE_CCMP:
+		if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+		    RX_RES_STATUS_DECRYPT_OK) {
+			IWL_DEBUG_RX("hw decrypt successfully!!!\n");
+			stats->flag |= RX_FLAG_DECRYPTED;
+		}
+		break;
+
+	default:
+		break;
+	}
+}
+
+void iwl_handle_data_packet_monitor(struct iwl_priv *priv,
+				    struct iwl_rx_mem_buffer *rxb,
+				    void *data, short len,
+				    struct ieee80211_rx_status *stats,
+				    u16 phy_flags)
+{
+	struct iwl_rt_rx_hdr *iwl_rt;
+
+	/* First cache any information we need before we overwrite
+	 * the information provided in the skb from the hardware */
+	s8 signal = stats->ssi;
+	s8 noise = 0;
+	int rate = stats->rate;
+	u64 tsf = stats->mactime;
+	__le16 phy_flags_hw = cpu_to_le16(phy_flags);
+
+	/* We received data from the HW, so stop the watchdog */
+	if (len > IWL_RX_BUF_SIZE - sizeof(*iwl_rt)) {
+		IWL_DEBUG_DROP("Dropping too large packet in monitor\n");
+		return;
+	}
+
+	/* copy the frame data to write after where the radiotap header goes */
+	iwl_rt = (void *)rxb->skb->data;
+	memmove(iwl_rt->payload, data, len);
+
+	iwl_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+	iwl_rt->rt_hdr.it_pad = 0; /* always good to zero */
+
+	/* total header + data */
+	iwl_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl_rt));
+
+	/* Set the size of the skb to the size of the frame */
+	skb_put(rxb->skb, sizeof(*iwl_rt) + len);
+
+	/* Big bitfield of all the fields we provide in radiotap */
+	iwl_rt->rt_hdr.it_present =
+	    cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
+			(1 << IEEE80211_RADIOTAP_FLAGS) |
+			(1 << IEEE80211_RADIOTAP_RATE) |
+			(1 << IEEE80211_RADIOTAP_CHANNEL) |
+			(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+			(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
+			(1 << IEEE80211_RADIOTAP_ANTENNA));
+
+	/* Zero the flags, we'll add to them as we go */
+	iwl_rt->rt_flags = 0;
+
+	iwl_rt->rt_tsf = cpu_to_le64(tsf);
+
+	/* Convert to dBm */
+	iwl_rt->rt_dbmsignal = signal;
+	iwl_rt->rt_dbmnoise = noise;
+
+	/* Convert the channel frequency and set the flags */
+	iwl_rt->rt_channelMHz = cpu_to_le16(stats->freq);
+	if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
+		iwl_rt->rt_chbitmask =
+		    cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
+	else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
+		iwl_rt->rt_chbitmask =
+		    cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
+	else	/* 802.11g */
+		iwl_rt->rt_chbitmask =
+		    cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ));
+
+	rate = iwl_rate_index_from_plcp(rate);
+	if (rate == -1)
+		iwl_rt->rt_rate = 0;
+	else
+		iwl_rt->rt_rate = iwl_rates[rate].ieee;
+
+	/* antenna number */
+	iwl_rt->rt_antenna =
+		le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
+
+	/* set the preamble flag if we have it */
+	if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+		iwl_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+	IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
+
+	stats->flag |= RX_FLAG_RADIOTAP;
+	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+	rxb->skb = NULL;
+}
+
+
+#define IWL_PACKET_RETRY_TIME HZ
+
+int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+{
+	u16 sc = le16_to_cpu(header->seq_ctrl);
+	u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
+	u16 frag = sc & IEEE80211_SCTL_FRAG;
+	u16 *last_seq, *last_frag;
+	unsigned long *last_time;
+
+	switch (priv->iw_mode) {
+	case IEEE80211_IF_TYPE_IBSS:{
+		struct list_head *p;
+		struct iwl_ibss_seq *entry = NULL;
+		u8 *mac = header->addr2;
+		int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1);
+
+		__list_for_each(p, &priv->ibss_mac_hash[index]) {
+			entry =
+				list_entry(p, struct iwl_ibss_seq, list);
+			if (!compare_ether_addr(entry->mac, mac))
+				break;
+		}
+		if (p == &priv->ibss_mac_hash[index]) {
+			entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+			if (!entry) {
+				IWL_ERROR
+					("Cannot malloc new mac entry\n");
+				return 0;
+			}
+			memcpy(entry->mac, mac, ETH_ALEN);
+			entry->seq_num = seq;
+			entry->frag_num = frag;
+			entry->packet_time = jiffies;
+			list_add(&entry->list,
+				 &priv->ibss_mac_hash[index]);
+			return 0;
+		}
+		last_seq = &entry->seq_num;
+		last_frag = &entry->frag_num;
+		last_time = &entry->packet_time;
+		break;
+	}
+	case IEEE80211_IF_TYPE_STA:
+		last_seq = &priv->last_seq_num;
+		last_frag = &priv->last_frag_num;
+		last_time = &priv->last_packet_time;
+		break;
+	default:
+		return 0;
+	}
+	if ((*last_seq == seq) &&
+	    time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) {
+		if (*last_frag == frag)
+			goto drop;
+		if (*last_frag + 1 != frag)
+			/* out-of-order fragment */
+			goto drop;
+	} else
+		*last_seq = seq;
+
+	*last_frag = frag;
+	*last_time = jiffies;
+	return 0;
+
+ drop:
+	return 1;
+}
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+
+#include "iwl-spectrum.h"
+
+#define BEACON_TIME_MASK_LOW	0x00FFFFFF
+#define BEACON_TIME_MASK_HIGH	0xFF000000
+#define TIME_UNIT		1024
+
+/*
+ * extended beacon time format
+ * time in usec will be changed into a 32-bit value in 8:24 format
+ * the high 1 byte is the beacon counts
+ * the lower 3 bytes is the time in usec within one beacon interval
+ */
+
+static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
+{
+	u32 quot;
+	u32 rem;
+	u32 interval = beacon_interval * 1024;
+
+	if (!interval || !usec)
+		return 0;
+
+	quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
+	rem = (usec % interval) & BEACON_TIME_MASK_LOW;
+
+	return (quot << 24) + rem;
+}
+
+/* base is usually what we get from ucode with each received frame,
+ * the same as HW timer counter counting down
+ */
+
+static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
+{
+	u32 base_low = base & BEACON_TIME_MASK_LOW;
+	u32 addon_low = addon & BEACON_TIME_MASK_LOW;
+	u32 interval = beacon_interval * TIME_UNIT;
+	u32 res = (base & BEACON_TIME_MASK_HIGH) +
+	    (addon & BEACON_TIME_MASK_HIGH);
+
+	if (base_low > addon_low)
+		res += base_low - addon_low;
+	else if (base_low < addon_low) {
+		res += interval + base_low - addon_low;
+		res += (1 << 24);
+	} else
+		res += (1 << 24);
+
+	return cpu_to_le32(res);
+}
+
+static int iwl_get_measurement(struct iwl_priv *priv,
+			       struct ieee80211_measurement_params *params,
+			       u8 type)
+{
+	struct iwl_spectrum_cmd spectrum;
+	struct iwl_rx_packet *res;
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
+		.data = (void *)&spectrum,
+		.meta.flags = CMD_WANT_SKB,
+	};
+	u32 add_time = le64_to_cpu(params->start_time);
+	int rc;
+	int spectrum_resp_status;
+	int duration = le16_to_cpu(params->duration);
+
+	if (iwl_is_associated(priv))
+		add_time =
+		    iwl_usecs_to_beacons(
+			le64_to_cpu(params->start_time) - priv->last_tsf,
+			le16_to_cpu(priv->rxon_timing.beacon_interval));
+
+	memset(&spectrum, 0, sizeof(spectrum));
+
+	spectrum.channel_count = cpu_to_le16(1);
+	spectrum.flags =
+	    RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK;
+	spectrum.filter_flags = MEASUREMENT_FILTER_FLAG;
+	cmd.len = sizeof(spectrum);
+	spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
+
+	if (iwl_is_associated(priv))
+		spectrum.start_time =
+		    iwl_add_beacon_time(priv->last_beacon_time,
+				add_time,
+				le16_to_cpu(priv->rxon_timing.beacon_interval));
+	else
+		spectrum.start_time = 0;
+
+	spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
+	spectrum.channels[0].channel = params->channel;
+	spectrum.channels[0].type = type;
+	if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
+		spectrum.flags |= RXON_FLG_BAND_24G_MSK |
+		    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
+
+	rc = iwl_send_cmd_sync(priv, &cmd);
+	if (rc)
+		return rc;
+
+	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+		IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
+		rc = -EIO;
+	}
+
+	spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
+	switch (spectrum_resp_status) {
+	case 0:		/* Command will be handled */
+		if (res->u.spectrum.id != 0xff) {
+			IWL_DEBUG_INFO
+			    ("Replaced existing measurement: %d\n",
+			     res->u.spectrum.id);
+			priv->measurement_status &= ~MEASUREMENT_READY;
+		}
+		priv->measurement_status |= MEASUREMENT_ACTIVE;
+		rc = 0;
+		break;
+
+	case 1:		/* Command will not be handled */
+		rc = -EAGAIN;
+		break;
+	}
+
+	dev_kfree_skb_any(cmd.meta.u.skb);
+
+	return rc;
+}
+#endif
+
+static void iwl_txstatus_to_ieee(struct iwl_priv *priv,
+				 struct iwl_tx_info *tx_sta)
+{
+
+	tx_sta->status.ack_signal = 0;
+	tx_sta->status.excessive_retries = 0;
+	tx_sta->status.queue_length = 0;
+	tx_sta->status.queue_number = 0;
+
+	if (in_interrupt())
+		ieee80211_tx_status_irqsafe(priv->hw,
+					    tx_sta->skb[0], &(tx_sta->status));
+	else
+		ieee80211_tx_status(priv->hw,
+				    tx_sta->skb[0], &(tx_sta->status));
+
+	tx_sta->skb[0] = NULL;
+}
+
+/**
+ * iwl_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC.
+ *
+ * When FW advances 'R' index, all entries between old and
+ * new 'R' index need to be reclaimed. As result, some free space
+ * forms. If there is enough free space (> low mark), wake Tx queue.
+ */
+int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+{
+	struct iwl_tx_queue *txq = &priv->txq[txq_id];
+	struct iwl_queue *q = &txq->q;
+	int nfreed = 0;
+
+	if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) {
+		IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
+			  "is out of range [0-%d] %d %d.\n", txq_id,
+			  index, q->n_bd, q->first_empty, q->last_used);
+		return 0;
+	}
+
+	for (index = iwl_queue_inc_wrap(index, q->n_bd);
+		q->last_used != index;
+		q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) {
+		if (txq_id != IWL_CMD_QUEUE_NUM) {
+			iwl_txstatus_to_ieee(priv,
+					&(txq->txb[txq->q.last_used]));
+			iwl_hw_txq_free_tfd(priv, txq);
+		} else if (nfreed > 1) {
+			IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
+					q->first_empty, q->last_used);
+			queue_work(priv->workqueue, &priv->restart);
+		}
+		nfreed++;
+	}
+
+	if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) &&
+			(txq_id != IWL_CMD_QUEUE_NUM) &&
+			priv->mac80211_registered)
+		ieee80211_wake_queue(priv->hw, txq_id);
+
+
+	return nfreed;
+}
+
+static int iwl_is_tx_success(u32 status)
+{
+	return (status & 0xFF) == 0x1;
+}
+
+/******************************************************************************
+ *
+ * Generic RX handler implementations
+ *
+ ******************************************************************************/
+static void iwl_rx_reply_tx(struct iwl_priv *priv,
+			    struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+	int txq_id = SEQ_TO_QUEUE(sequence);
+	int index = SEQ_TO_INDEX(sequence);
+	struct iwl_tx_queue *txq = &priv->txq[txq_id];
+	struct ieee80211_tx_status *tx_status;
+	struct iwl_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+	u32  status = le32_to_cpu(tx_resp->status);
+
+	if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) {
+		IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
+			  "is out of range [0-%d] %d %d\n", txq_id,
+			  index, txq->q.n_bd, txq->q.first_empty,
+			  txq->q.last_used);
+		return;
+	}
+
+	tx_status = &(txq->txb[txq->q.last_used].status);
+
+	tx_status->retry_count = tx_resp->failure_frame;
+	tx_status->queue_number = status;
+	tx_status->queue_length = tx_resp->bt_kill_count;
+	tx_status->queue_length |= tx_resp->failure_rts;
+
+	tx_status->flags =
+	    iwl_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0;
+
+	tx_status->control.tx_rate = iwl_rate_index_from_plcp(tx_resp->rate);
+
+	IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n",
+			txq_id, iwl_get_tx_fail_reason(status), status,
+			tx_resp->rate, tx_resp->failure_frame);
+
+	IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
+	if (index != -1)
+		iwl_tx_queue_reclaim(priv, txq_id, index);
+
+	if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
+		IWL_ERROR("TODO:  Implement Tx ABORT REQUIRED!!!\n");
+}
+
+
+static void iwl_rx_reply_alive(struct iwl_priv *priv,
+			       struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_alive_resp *palive;
+	struct delayed_work *pwork;
+
+	palive = &pkt->u.alive_frame;
+
+	IWL_DEBUG_INFO("Alive ucode status 0x%08X revision "
+		       "0x%01X 0x%01X\n",
+		       palive->is_valid, palive->ver_type,
+		       palive->ver_subtype);
+
+	if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
+		IWL_DEBUG_INFO("Initialization Alive received.\n");
+		memcpy(&priv->card_alive_init,
+		       &pkt->u.alive_frame,
+		       sizeof(struct iwl_init_alive_resp));
+		pwork = &priv->init_alive_start;
+	} else {
+		IWL_DEBUG_INFO("Runtime Alive received.\n");
+		memcpy(&priv->card_alive, &pkt->u.alive_frame,
+		       sizeof(struct iwl_alive_resp));
+		pwork = &priv->alive_start;
+		iwl_disable_events(priv);
+	}
+
+	/* We delay the ALIVE response by 5ms to
+	 * give the HW RF Kill time to activate... */
+	if (palive->is_valid == UCODE_VALID_OK)
+		queue_delayed_work(priv->workqueue, pwork,
+				   msecs_to_jiffies(5));
+	else
+		IWL_WARNING("uCode did not respond OK.\n");
+}
+
+static void iwl_rx_reply_add_sta(struct iwl_priv *priv,
+				 struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+
+	IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
+	return;
+}
+
+static void iwl_rx_reply_error(struct iwl_priv *priv,
+			       struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+
+	IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) "
+		"seq 0x%04X ser 0x%08X\n",
+		le32_to_cpu(pkt->u.err_resp.error_type),
+		get_cmd_string(pkt->u.err_resp.cmd_id),
+		pkt->u.err_resp.cmd_id,
+		le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
+		le32_to_cpu(pkt->u.err_resp.error_info));
+}
+
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
+	struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
+	IWL_DEBUG_11H("CSA notif: channel %d, status %d\n",
+		      le16_to_cpu(csa->channel), le32_to_cpu(csa->status));
+	rxon->channel = csa->channel;
+	priv->staging_rxon.channel = csa->channel;
+}
+
+static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
+					  struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
+
+	if (!report->state) {
+		IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO,
+			  "Spectrum Measure Notification: Start\n");
+		return;
+	}
+
+	memcpy(&priv->measure_report, report, sizeof(*report));
+	priv->measurement_status |= MEASUREMENT_READY;
+#endif
+}
+
+static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
+				  struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
+	IWL_DEBUG_RX("sleep mode: %d, src: %d\n",
+		     sleep->pm_sleep_mode, sleep->pm_wakeup_src);
+#endif
+}
+
+static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
+					     struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	IWL_DEBUG_RADIO("Dumping %d bytes of unhandled "
+			"notification for %s:\n",
+			le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
+	iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+}
+
+static void iwl_bg_beacon_update(struct work_struct *work)
+{
+	struct iwl_priv *priv =
+		container_of(work, struct iwl_priv, beacon_update);
+	struct sk_buff *beacon;
+
+	/* Pull updated AP beacon from mac80211. will fail if not in AP mode */
+	beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL);
+
+	if (!beacon) {
+		IWL_ERROR("update beacon failed\n");
+		return;
+	}
+
+	mutex_lock(&priv->mutex);
+	/* new beacon skb is allocated every time; dispose previous.*/
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+
+	priv->ibss_beacon = beacon;
+	mutex_unlock(&priv->mutex);
+
+	iwl_send_beacon_cmd(priv);
+}
+
+static void iwl_rx_beacon_notif(struct iwl_priv *priv,
+				struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_beacon_notif *beacon = &(pkt->u.beacon_status);
+	u8 rate = beacon->beacon_notify_hdr.rate;
+
+	IWL_DEBUG_RX("beacon status %x retries %d iss %d "
+		"tsf %d %d rate %d\n",
+		le32_to_cpu(beacon->beacon_notify_hdr.status) & TX_STATUS_MSK,
+		beacon->beacon_notify_hdr.failure_frame,
+		le32_to_cpu(beacon->ibss_mgr_status),
+		le32_to_cpu(beacon->high_tsf),
+		le32_to_cpu(beacon->low_tsf), rate);
+#endif
+
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+	    (!test_bit(STATUS_EXIT_PENDING, &priv->status)))
+		queue_work(priv->workqueue, &priv->beacon_update);
+}
+
+/* Service response to REPLY_SCAN_CMD (0x80) */
+static void iwl_rx_reply_scan(struct iwl_priv *priv,
+			      struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_scanreq_notification *notif =
+	    (struct iwl_scanreq_notification *)pkt->u.raw;
+
+	IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status);
+#endif
+}
+
+/* Service SCAN_START_NOTIFICATION (0x82) */
+static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
+				    struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_scanstart_notification *notif =
+	    (struct iwl_scanstart_notification *)pkt->u.raw;
+	priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
+	IWL_DEBUG_SCAN("Scan start: "
+		       "%d [802.11%s] "
+		       "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
+		       notif->channel,
+		       notif->band ? "bg" : "a",
+		       notif->tsf_high,
+		       notif->tsf_low, notif->status, notif->beacon_timer);
+}
+
+/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
+static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
+				      struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_scanresults_notification *notif =
+	    (struct iwl_scanresults_notification *)pkt->u.raw;
+
+	IWL_DEBUG_SCAN("Scan ch.res: "
+		       "%d [802.11%s] "
+		       "(TSF: 0x%08X:%08X) - %d "
+		       "elapsed=%lu usec (%dms since last)\n",
+		       notif->channel,
+		       notif->band ? "bg" : "a",
+		       le32_to_cpu(notif->tsf_high),
+		       le32_to_cpu(notif->tsf_low),
+		       le32_to_cpu(notif->statistics[0]),
+		       le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf,
+		       jiffies_to_msecs(elapsed_jiffies
+					(priv->last_scan_jiffies, jiffies)));
+
+	priv->last_scan_jiffies = jiffies;
+}
+
+/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
+static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
+				       struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
+
+	IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
+		       scan_notif->scanned_channels,
+		       scan_notif->tsf_low,
+		       scan_notif->tsf_high, scan_notif->status);
+
+	/* The HW is no longer scanning */
+	clear_bit(STATUS_SCAN_HW, &priv->status);
+
+	/* The scan completion notification came in, so kill that timer... */
+	cancel_delayed_work(&priv->scan_check);
+
+	IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
+		       (priv->scan_bands == 2) ? "2.4" : "5.2",
+		       jiffies_to_msecs(elapsed_jiffies
+					(priv->scan_pass_start, jiffies)));
+
+	/* Remove this scanned band from the list
+	 * of pending bands to scan */
+	priv->scan_bands--;
+
+	/* If a request to abort was given, or the scan did not succeed
+	 * then we reset the scan state machine and terminate,
+	 * re-queuing another scan if one has been requested */
+	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG_INFO("Aborted scan completed.\n");
+		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+	} else {
+		/* If there are more bands on this scan pass reschedule */
+		if (priv->scan_bands > 0)
+			goto reschedule;
+	}
+
+	priv->last_scan_jiffies = jiffies;
+	IWL_DEBUG_INFO("Setting scan to off\n");
+
+	clear_bit(STATUS_SCANNING, &priv->status);
+
+	IWL_DEBUG_INFO("Scan took %dms\n",
+		jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies)));
+
+	queue_work(priv->workqueue, &priv->scan_completed);
+
+	return;
+
+reschedule:
+	priv->scan_pass_start = jiffies;
+	queue_work(priv->workqueue, &priv->request_scan);
+}
+
+/* Handle notification from uCode that card's power state is changing
+ * due to software, hardware, or critical temperature RFKILL */
+static void iwl_rx_card_state_notif(struct iwl_priv *priv,
+				    struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
+	unsigned long status = priv->status;
+
+	IWL_DEBUG_RF_KILL("Card state received: HW:%s SW:%s\n",
+			  (flags & HW_CARD_DISABLED) ? "Kill" : "On",
+			  (flags & SW_CARD_DISABLED) ? "Kill" : "On");
+
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+	if (flags & HW_CARD_DISABLED)
+		set_bit(STATUS_RF_KILL_HW, &priv->status);
+	else
+		clear_bit(STATUS_RF_KILL_HW, &priv->status);
+
+
+	if (flags & SW_CARD_DISABLED)
+		set_bit(STATUS_RF_KILL_SW, &priv->status);
+	else
+		clear_bit(STATUS_RF_KILL_SW, &priv->status);
+
+	iwl_scan_cancel(priv);
+
+	if ((test_bit(STATUS_RF_KILL_HW, &status) !=
+	     test_bit(STATUS_RF_KILL_HW, &priv->status)) ||
+	    (test_bit(STATUS_RF_KILL_SW, &status) !=
+	     test_bit(STATUS_RF_KILL_SW, &priv->status)))
+		queue_work(priv->workqueue, &priv->rf_kill);
+	else
+		wake_up_interruptible(&priv->wait_command_queue);
+}
+
+/**
+ * iwl_setup_rx_handlers - Initialize Rx handler callbacks
+ *
+ * Setup the RX handlers for each of the reply types sent from the uCode
+ * to the host.
+ *
+ * This function chains into the hardware specific files for them to setup
+ * any hardware specific handlers as well.
+ */
+static void iwl_setup_rx_handlers(struct iwl_priv *priv)
+{
+	priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
+	priv->rx_handlers[REPLY_ADD_STA] = iwl_rx_reply_add_sta;
+	priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
+	priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
+	priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
+	    iwl_rx_spectrum_measure_notif;
+	priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
+	priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
+	    iwl_rx_pm_debug_statistics_notif;
+	priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif;
+
+	/* NOTE:  iwl_rx_statistics is different based on whether
+	 * the build is for the 3945 or the 4965.  See the
+	 * corresponding implementation in iwl-XXXX.c
+	 *
+	 * The same handler is used for both the REPLY to a
+	 * discrete statistics request from the host as well as
+	 * for the periodic statistics notification from the uCode
+	 */
+	priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_hw_rx_statistics;
+	priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_hw_rx_statistics;
+
+	priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan;
+	priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif;
+	priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
+	    iwl_rx_scan_results_notif;
+	priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
+	    iwl_rx_scan_complete_notif;
+	priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif;
+	priv->rx_handlers[REPLY_TX] = iwl_rx_reply_tx;
+
+	/* Setup hardware specific Rx handlers */
+	iwl_hw_rx_handler_setup(priv);
+}
+
+/**
+ * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
+ * @rxb: Rx buffer to reclaim
+ *
+ * If an Rx buffer has an async callback associated with it the callback
+ * will be executed.  The attached skb (if present) will only be freed
+ * if the callback returns 1
+ */
+static void iwl_tx_cmd_complete(struct iwl_priv *priv,
+				struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+	int txq_id = SEQ_TO_QUEUE(sequence);
+	int index = SEQ_TO_INDEX(sequence);
+	int huge = sequence & SEQ_HUGE_FRAME;
+	int cmd_index;
+	struct iwl_cmd *cmd;
+
+	/* If a Tx command is being handled and it isn't in the actual
+	 * command queue then there a command routing bug has been introduced
+	 * in the queue management code. */
+	if (txq_id != IWL_CMD_QUEUE_NUM)
+		IWL_ERROR("Error wrong command queue %d command id 0x%X\n",
+			  txq_id, pkt->hdr.cmd);
+	BUG_ON(txq_id != IWL_CMD_QUEUE_NUM);
+
+	cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
+	cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
+
+	/* Input error checking is done when commands are added to queue. */
+	if (cmd->meta.flags & CMD_WANT_SKB) {
+		cmd->meta.source->u.skb = rxb->skb;
+		rxb->skb = NULL;
+	} else if (cmd->meta.u.callback &&
+		   !cmd->meta.u.callback(priv, cmd, rxb->skb))
+		rxb->skb = NULL;
+
+	iwl_tx_queue_reclaim(priv, txq_id, index);
+
+	if (!(cmd->meta.flags & CMD_ASYNC)) {
+		clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+		wake_up_interruptible(&priv->wait_command_queue);
+	}
+}
+
+/************************** RX-FUNCTIONS ****************************/
+/*
+ * Rx theory of operation
+ *
+ * The host allocates 32 DMA target addresses and passes the host address
+ * to the firmware at register IWL_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
+ * 0 to 31
+ *
+ * Rx Queue Indexes
+ * The host/firmware share two index registers for managing the Rx buffers.
+ *
+ * The READ index maps to the first position that the firmware may be writing
+ * to -- the driver can read up to (but not including) this position and get
+ * good data.
+ * The READ index is managed by the firmware once the card is enabled.
+ *
+ * The WRITE index maps to the last position the driver has read from -- the
+ * position preceding WRITE is the last slot the firmware can place a packet.
+ *
+ * The queue is empty (no good data) if WRITE = READ - 1, and is full if
+ * WRITE = READ.
+ *
+ * During initialization the host sets up the READ queue position to the first
+ * INDEX position, and WRITE to the last (READ - 1 wrapped)
+ *
+ * When the firmware places a packet in a buffer it will advance the READ index
+ * and fire the RX interrupt.  The driver can then query the READ index and
+ * process as many packets as possible, moving the WRITE index forward as it
+ * resets the Rx queue buffers with new memory.
+ *
+ * The management in the driver is as follows:
+ * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free.  When
+ *   iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
+ *   to replensish the iwl->rxq->rx_free.
+ * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
+ *   iwl->rxq is replenished and the READ INDEX is updated (updating the
+ *   'processed' and 'read' driver indexes as well)
+ * + A received packet is processed and handed to the kernel network stack,
+ *   detached from the iwl->rxq.  The driver 'processed' index is updated.
+ * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
+ *   list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
+ *   INDEX is not incremented and iwl->status(RX_STALLED) is set.  If there
+ *   were enough free buffers and RX_STALLED is set it is cleared.
+ *
+ *
+ * Driver sequence:
+ *
+ * iwl_rx_queue_alloc()       Allocates rx_free
+ * iwl_rx_replenish()         Replenishes rx_free list from rx_used, and calls
+ *                            iwl_rx_queue_restock
+ * iwl_rx_queue_restock()     Moves available buffers from rx_free into Rx
+ *                            queue, updates firmware pointers, and updates
+ *                            the WRITE index.  If insufficient rx_free buffers
+ *                            are available, schedules iwl_rx_replenish
+ *
+ * -- enable interrupts --
+ * ISR - iwl_rx()             Detach iwl_rx_mem_buffers from pool up to the
+ *                            READ INDEX, detaching the SKB from the pool.
+ *                            Moves the packet buffer from queue to rx_used.
+ *                            Calls iwl_rx_queue_restock to refill any empty
+ *                            slots.
+ * ...
+ *
+ */
+
+/**
+ * iwl_rx_queue_space - Return number of free slots available in queue.
+ */
+static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
+{
+	int s = q->read - q->write;
+	if (s <= 0)
+		s += RX_QUEUE_SIZE;
+	/* keep some buffer to not confuse full and empty queue */
+	s -= 2;
+	if (s < 0)
+		s = 0;
+	return s;
+}
+
+/**
+ * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
+ *
+ * NOTE: This function has 3945 and 4965 specific code sections
+ * but is declared in base due to the majority of the
+ * implementation being the same (only a numeric constant is
+ * different)
+ *
+ */
+int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
+{
+	u32 reg = 0;
+	int rc = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&q->lock, flags);
+
+	if (q->need_update == 0)
+		goto exit_unlock;
+
+	if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+		reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+
+		if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+			iwl_set_bit(priv, CSR_GP_CNTRL,
+				    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+			goto exit_unlock;
+		}
+
+		rc = iwl_grab_restricted_access(priv);
+		if (rc)
+			goto exit_unlock;
+
+		iwl_write_restricted(priv, FH_RSCSR_CHNL0_WPTR,
+				     q->write & ~0x7);
+		iwl_release_restricted_access(priv);
+	} else
+		iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
+
+
+	q->need_update = 0;
+
+ exit_unlock:
+	spin_unlock_irqrestore(&q->lock, flags);
+	return rc;
+}
+
+/**
+ * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer pointer.
+ *
+ * NOTE: This function has 3945 and 4965 specific code paths in it.
+ */
+static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
+					  dma_addr_t dma_addr)
+{
+	return cpu_to_le32((u32)dma_addr);
+}
+
+/**
+ * iwl_rx_queue_restock - refill RX queue from pre-allocated pool
+ *
+ * If there are slots in the RX queue that  need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+int iwl_rx_queue_restock(struct iwl_priv *priv)
+{
+	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct list_head *element;
+	struct iwl_rx_mem_buffer *rxb;
+	unsigned long flags;
+	int write, rc;
+
+	spin_lock_irqsave(&rxq->lock, flags);
+	write = rxq->write & ~0x7;
+	while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+		element = rxq->rx_free.next;
+		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+		list_del(element);
+		rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr);
+		rxq->queue[rxq->write] = rxb;
+		rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
+		rxq->free_count--;
+	}
+	spin_unlock_irqrestore(&rxq->lock, flags);
+	/* If the pre-allocated buffer pool is dropping low, schedule to
+	 * refill it */
+	if (rxq->free_count <= RX_LOW_WATERMARK)
+		queue_work(priv->workqueue, &priv->rx_replenish);
+
+
+	/* If we've added more space for the firmware to place data, tell it */
+	if ((write != (rxq->write & ~0x7))
+	    || (abs(rxq->write - rxq->read) > 7)) {
+		spin_lock_irqsave(&rxq->lock, flags);
+		rxq->need_update = 1;
+		spin_unlock_irqrestore(&rxq->lock, flags);
+		rc = iwl_rx_queue_update_write_ptr(priv, rxq);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * iwl_rx_replensih - Move all used packet from rx_used to rx_free
+ *
+ * When moving to rx_free an SKB is allocated for the slot.
+ *
+ * Also restock the Rx queue via iwl_rx_queue_restock.
+ * This is called as a scheduled work item (except for during intialization)
+ */
+void iwl_rx_replenish(void *data)
+{
+	struct iwl_priv *priv = data;
+	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct list_head *element;
+	struct iwl_rx_mem_buffer *rxb;
+	unsigned long flags;
+	spin_lock_irqsave(&rxq->lock, flags);
+	while (!list_empty(&rxq->rx_used)) {
+		element = rxq->rx_used.next;
+		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+		rxb->skb =
+		    alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC);
+		if (!rxb->skb) {
+			if (net_ratelimit())
+				printk(KERN_CRIT DRV_NAME
+				       ": Can not allocate SKB buffers\n");
+			/* We don't reschedule replenish work here -- we will
+			 * call the restock method and if it still needs
+			 * more buffers it will schedule replenish */
+			break;
+		}
+		priv->alloc_rxb_skb++;
+		list_del(element);
+		rxb->dma_addr =
+		    pci_map_single(priv->pci_dev, rxb->skb->data,
+				   IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+		list_add_tail(&rxb->list, &rxq->rx_free);
+		rxq->free_count++;
+	}
+	spin_unlock_irqrestore(&rxq->lock, flags);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl_rx_queue_restock(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
+ * If an SKB has been detached, the POOL needs to have it's SKB set to NULL
+ * This free routine walks the list of POOL entries and if SKB is set to
+ * non NULL it is unmapped and freed
+ */
+void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+	int i;
+	for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
+		if (rxq->pool[i].skb != NULL) {
+			pci_unmap_single(priv->pci_dev,
+					 rxq->pool[i].dma_addr,
+					 IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(rxq->pool[i].skb);
+		}
+	}
+
+	pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+			    rxq->dma_addr);
+	rxq->bd = NULL;
+}
+
+int iwl_rx_queue_alloc(struct iwl_priv *priv)
+{
+	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct pci_dev *dev = priv->pci_dev;
+	int i;
+
+	spin_lock_init(&rxq->lock);
+	INIT_LIST_HEAD(&rxq->rx_free);
+	INIT_LIST_HEAD(&rxq->rx_used);
+	rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
+	if (!rxq->bd)
+		return -ENOMEM;
+	/* Fill the rx_used queue with _all_ of the Rx buffers */
+	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
+		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+	/* Set us so that we have processed and used all buffers, but have
+	 * not restocked the Rx queue with fresh buffers */
+	rxq->read = rxq->write = 0;
+	rxq->free_count = 0;
+	rxq->need_update = 0;
+	return 0;
+}
+
+void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+	unsigned long flags;
+	int i;
+	spin_lock_irqsave(&rxq->lock, flags);
+	INIT_LIST_HEAD(&rxq->rx_free);
+	INIT_LIST_HEAD(&rxq->rx_used);
+	/* Fill the rx_used queue with _all_ of the Rx buffers */
+	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+		/* In the reset function, these buffers may have been allocated
+		 * to an SKB, so we need to unmap and free potential storage */
+		if (rxq->pool[i].skb != NULL) {
+			pci_unmap_single(priv->pci_dev,
+					 rxq->pool[i].dma_addr,
+					 IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+			priv->alloc_rxb_skb--;
+			dev_kfree_skb(rxq->pool[i].skb);
+			rxq->pool[i].skb = NULL;
+		}
+		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+	}
+
+	/* Set us so that we have processed and used all buffers, but have
+	 * not restocked the Rx queue with fresh buffers */
+	rxq->read = rxq->write = 0;
+	rxq->free_count = 0;
+	spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+/* Convert linear signal-to-noise ratio into dB */
+static u8 ratio2dB[100] = {
+/*	 0   1   2   3   4   5   6   7   8   9 */
+	 0,  0,  6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */
+	20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */
+	26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */
+	29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */
+	32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */
+	34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */
+	36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */
+	37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */
+	38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */
+	39, 39, 39, 39, 39, 40, 40, 40, 40, 40  /* 90 - 99 */
+};
+
+/* Calculates a relative dB value from a ratio of linear
+ *   (i.e. not dB) signal levels.
+ * Conversion assumes that levels are voltages (20*log), not powers (10*log). */
+int iwl_calc_db_from_ratio(int sig_ratio)
+{
+	/* Anything above 1000:1 just report as 60 dB */
+	if (sig_ratio > 1000)
+		return 60;
+
+	/* Above 100:1, divide by 10 and use table,
+	 *   add 20 dB to make up for divide by 10 */
+	if (sig_ratio > 100)
+		return (20 + (int)ratio2dB[sig_ratio/10]);
+
+	/* We shouldn't see this */
+	if (sig_ratio < 1)
+		return 0;
+
+	/* Use table for ratios 1:1 - 99:1 */
+	return (int)ratio2dB[sig_ratio];
+}
+
+#define PERFECT_RSSI (-20) /* dBm */
+#define WORST_RSSI (-95)   /* dBm */
+#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
+
+/* Calculate an indication of rx signal quality (a percentage, not dBm!).
+ * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
+ *   about formulas used below. */
+int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
+{
+	int sig_qual;
+	int degradation = PERFECT_RSSI - rssi_dbm;
+
+	/* If we get a noise measurement, use signal-to-noise ratio (SNR)
+	 * as indicator; formula is (signal dbm - noise dbm).
+	 * SNR at or above 40 is a great signal (100%).
+	 * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator.
+	 * Weakest usable signal is usually 10 - 15 dB SNR. */
+	if (noise_dbm) {
+		if (rssi_dbm - noise_dbm >= 40)
+			return 100;
+		else if (rssi_dbm < noise_dbm)
+			return 0;
+		sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2;
+
+	/* Else use just the signal level.
+	 * This formula is a least squares fit of data points collected and
+	 *   compared with a reference system that had a percentage (%) display
+	 *   for signal quality. */
+	} else
+		sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation *
+			    (15 * RSSI_RANGE + 62 * degradation)) /
+			   (RSSI_RANGE * RSSI_RANGE);
+
+	if (sig_qual > 100)
+		sig_qual = 100;
+	else if (sig_qual < 1)
+		sig_qual = 0;
+
+	return sig_qual;
+}
+
+/**
+ * iwl_rx_handle - Main entry function for receiving responses from the uCode
+ *
+ * Uses the priv->rx_handlers callback function array to invoke
+ * the appropriate handlers, including command responses,
+ * frame-received notifications, and other notifications.
+ */
+static void iwl_rx_handle(struct iwl_priv *priv)
+{
+	struct iwl_rx_mem_buffer *rxb;
+	struct iwl_rx_packet *pkt;
+	struct iwl_rx_queue *rxq = &priv->rxq;
+	u32 r, i;
+	int reclaim;
+	unsigned long flags;
+
+	r = iwl_hw_get_rx_read(priv);
+	i = rxq->read;
+
+	/* Rx interrupt, but nothing sent from uCode */
+	if (i == r)
+		IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i);
+
+	while (i != r) {
+		rxb = rxq->queue[i];
+
+		/* If an RXB doesn't have a queue slot associated with it
+		 * then a bug has been introduced in the queue refilling
+		 * routines -- catch it here */
+		BUG_ON(rxb == NULL);
+
+		rxq->queue[i] = NULL;
+
+		pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
+					    IWL_RX_BUF_SIZE,
+					    PCI_DMA_FROMDEVICE);
+		pkt = (struct iwl_rx_packet *)rxb->skb->data;
+
+		/* Reclaim a command buffer only if this packet is a response
+		 *   to a (driver-originated) command.
+		 * If the packet (e.g. Rx frame) originated from uCode,
+		 *   there is no command buffer to reclaim.
+		 * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
+		 *   but apparently a few don't get set; catch them here. */
+		reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
+			(pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
+			(pkt->hdr.cmd != REPLY_TX);
+
+		/* Based on type of command response or notification,
+		 *   handle those that need handling via function in
+		 *   rx_handlers table.  See iwl_setup_rx_handlers() */
+		if (priv->rx_handlers[pkt->hdr.cmd]) {
+			IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
+				"r = %d, i = %d, %s, 0x%02x\n", r, i,
+				get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
+			priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
+		} else {
+			/* No handling needed */
+			IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
+				"r %d i %d No handler needed for %s, 0x%02x\n",
+				r, i, get_cmd_string(pkt->hdr.cmd),
+				pkt->hdr.cmd);
+		}
+
+		if (reclaim) {
+			/* Invoke any callbacks, transfer the skb to caller,
+			 * and fire off the (possibly) blocking iwl_send_cmd()
+			 * as we reclaim the driver command queue */
+			if (rxb && rxb->skb)
+				iwl_tx_cmd_complete(priv, rxb);
+			else
+				IWL_WARNING("Claim null rxb?\n");
+		}
+
+		/* For now we just don't re-use anything.  We can tweak this
+		 * later to try and re-use notification packets and SKBs that
+		 * fail to Rx correctly */
+		if (rxb->skb != NULL) {
+			priv->alloc_rxb_skb--;
+			dev_kfree_skb_any(rxb->skb);
+			rxb->skb = NULL;
+		}
+
+		pci_unmap_single(priv->pci_dev, rxb->dma_addr,
+				 IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+		spin_lock_irqsave(&rxq->lock, flags);
+		list_add_tail(&rxb->list, &priv->rxq.rx_used);
+		spin_unlock_irqrestore(&rxq->lock, flags);
+		i = (i + 1) & RX_QUEUE_MASK;
+	}
+
+	/* Backtrack one entry */
+	priv->rxq.read = i;
+	iwl_rx_queue_restock(priv);
+}
+
+int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
+				  struct iwl_tx_queue *txq)
+{
+	u32 reg = 0;
+	int rc = 0;
+	int txq_id = txq->q.id;
+
+	if (txq->need_update == 0)
+		return rc;
+
+	/* if we're trying to save power */
+	if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+		/* wake up nic if it's powered down ...
+		 * uCode will wake up, and interrupt us again, so next
+		 * time we'll skip this part. */
+		reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+
+		if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+			IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg);
+			iwl_set_bit(priv, CSR_GP_CNTRL,
+				    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+			return rc;
+		}
+
+		/* restore this queue's parameters in nic hardware. */
+		rc = iwl_grab_restricted_access(priv);
+		if (rc)
+			return rc;
+		iwl_write_restricted(priv, HBUS_TARG_WRPTR,
+				     txq->q.first_empty | (txq_id << 8));
+		iwl_release_restricted_access(priv);
+
+	/* else not in power-save mode, uCode will never sleep when we're
+	 * trying to tx (during RFKILL, we're not trying to tx). */
+	} else
+		iwl_write32(priv, HBUS_TARG_WRPTR,
+			    txq->q.first_empty | (txq_id << 8));
+
+	txq->need_update = 0;
+
+	return rc;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon)
+{
+	DECLARE_MAC_BUF(mac);
+
+	IWL_DEBUG_RADIO("RX CONFIG:\n");
+	iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+	IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
+	IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
+	IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n",
+			le32_to_cpu(rxon->filter_flags));
+	IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type);
+	IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n",
+			rxon->ofdm_basic_rates);
+	IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
+	IWL_DEBUG_RADIO("u8[6] node_addr: %s\n",
+			print_mac(mac, rxon->node_addr));
+	IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n",
+			print_mac(mac, rxon->bssid_addr));
+	IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
+}
+#endif
+
+static void iwl_enable_interrupts(struct iwl_priv *priv)
+{
+	IWL_DEBUG_ISR("Enabling interrupts\n");
+	set_bit(STATUS_INT_ENABLED, &priv->status);
+	iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
+}
+
+static inline void iwl_disable_interrupts(struct iwl_priv *priv)
+{
+	clear_bit(STATUS_INT_ENABLED, &priv->status);
+
+	/* disable interrupts from uCode/NIC to host */
+	iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+	/* acknowledge/clear/reset any interrupts still pending
+	 * from uCode or flow handler (Rx/Tx DMA) */
+	iwl_write32(priv, CSR_INT, 0xffffffff);
+	iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+	IWL_DEBUG_ISR("Disabled interrupts\n");
+}
+
+static const char *desc_lookup(int i)
+{
+	switch (i) {
+	case 1:
+		return "FAIL";
+	case 2:
+		return "BAD_PARAM";
+	case 3:
+		return "BAD_CHECKSUM";
+	case 4:
+		return "NMI_INTERRUPT";
+	case 5:
+		return "SYSASSERT";
+	case 6:
+		return "FATAL_ERROR";
+	}
+
+	return "UNKNOWN";
+}
+
+#define ERROR_START_OFFSET  (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
+
+static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+{
+	u32 i;
+	u32 desc, time, count, base, data1;
+	u32 blink1, blink2, ilink1, ilink2;
+	int rc;
+
+	base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+
+	if (!iwl_hw_valid_rtc_data_addr(base)) {
+		IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
+		return;
+	}
+
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		IWL_WARNING("Can not read from adapter at this time.\n");
+		return;
+	}
+
+	count = iwl_read_restricted_mem(priv, base);
+
+	if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+		IWL_ERROR("Start IWL Error Log Dump:\n");
+		IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n",
+			  priv->status, priv->config, count);
+	}
+
+	IWL_ERROR("Desc       Time       asrtPC  blink2 "
+		  "ilink1  nmiPC   Line\n");
+	for (i = ERROR_START_OFFSET;
+	     i < (count * ERROR_ELEM_SIZE) + ERROR_START_OFFSET;
+	     i += ERROR_ELEM_SIZE) {
+		desc = iwl_read_restricted_mem(priv, base + i);
+		time =
+		    iwl_read_restricted_mem(priv, base + i + 1 * sizeof(u32));
+		blink1 =
+		    iwl_read_restricted_mem(priv, base + i + 2 * sizeof(u32));
+		blink2 =
+		    iwl_read_restricted_mem(priv, base + i + 3 * sizeof(u32));
+		ilink1 =
+		    iwl_read_restricted_mem(priv, base + i + 4 * sizeof(u32));
+		ilink2 =
+		    iwl_read_restricted_mem(priv, base + i + 5 * sizeof(u32));
+		data1 =
+		    iwl_read_restricted_mem(priv, base + i + 6 * sizeof(u32));
+
+		IWL_ERROR
+		    ("%-13s (#%d) %010u 0x%05X 0x%05X 0x%05X 0x%05X %u\n\n",
+		     desc_lookup(desc), desc, time, blink1, blink2,
+		     ilink1, ilink2, data1);
+	}
+
+	iwl_release_restricted_access(priv);
+
+}
+
+#define EVENT_START_OFFSET  (4 * sizeof(u32))
+
+/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ * NOTE: Must be called with iwl_grab_restricted_access() already obtained!
+ */
+static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+				u32 num_events, u32 mode)
+{
+	u32 i;
+	u32 base;       /* SRAM byte address of event log header */
+	u32 event_size;	/* 2 u32s, or 3 u32s if timestamp recorded */
+	u32 ptr;        /* SRAM byte address of log data */
+	u32 ev, time, data; /* event log data */
+
+	if (num_events == 0)
+		return;
+
+	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+
+	if (mode == 0)
+		event_size = 2 * sizeof(u32);
+	else
+		event_size = 3 * sizeof(u32);
+
+	ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+	/* "time" is actually "data" for mode 0 (no timestamp).
+	 * place event id # at far right for easier visual parsing. */
+	for (i = 0; i < num_events; i++) {
+		ev = iwl_read_restricted_mem(priv, ptr);
+		ptr += sizeof(u32);
+		time = iwl_read_restricted_mem(priv, ptr);
+		ptr += sizeof(u32);
+		if (mode == 0)
+			IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */
+		else {
+			data = iwl_read_restricted_mem(priv, ptr);
+			ptr += sizeof(u32);
+			IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev);
+		}
+	}
+}
+
+static void iwl_dump_nic_event_log(struct iwl_priv *priv)
+{
+	int rc;
+	u32 base;       /* SRAM byte address of event log header */
+	u32 capacity;   /* event log capacity in # entries */
+	u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
+	u32 num_wraps;  /* # times uCode wrapped to top of log */
+	u32 next_entry; /* index of next entry to be written by uCode */
+	u32 size;       /* # entries that we'll print */
+
+	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+	if (!iwl_hw_valid_rtc_data_addr(base)) {
+		IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
+		return;
+	}
+
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		IWL_WARNING("Can not read from adapter at this time.\n");
+		return;
+	}
+
+	/* event log header */
+	capacity = iwl_read_restricted_mem(priv, base);
+	mode = iwl_read_restricted_mem(priv, base + (1 * sizeof(u32)));
+	num_wraps = iwl_read_restricted_mem(priv, base + (2 * sizeof(u32)));
+	next_entry = iwl_read_restricted_mem(priv, base + (3 * sizeof(u32)));
+
+	size = num_wraps ? capacity : next_entry;
+
+	/* bail out if nothing in log */
+	if (size == 0) {
+		IWL_ERROR("Start IWL Event Log Dump: nothing in log\n");
+		iwl_release_restricted_access(priv);
+		return;
+	}
+
+	IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n",
+		  size, num_wraps);
+
+	/* if uCode has wrapped back to top of log, start at the oldest entry,
+	 * i.e the next one that uCode would fill. */
+	if (num_wraps)
+		iwl_print_event_log(priv, next_entry,
+				    capacity - next_entry, mode);
+
+	/* (then/else) start at top of log */
+	iwl_print_event_log(priv, 0, next_entry, mode);
+
+	iwl_release_restricted_access(priv);
+}
+
+/**
+ * iwl_irq_handle_error - called for HW or SW error interrupt from card
+ */
+static void iwl_irq_handle_error(struct iwl_priv *priv)
+{
+	/* Set the FW error flag -- cleared on iwl_down */
+	set_bit(STATUS_FW_ERROR, &priv->status);
+
+	/* Cancel currently queued command. */
+	clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (iwl_debug_level & IWL_DL_FW_ERRORS) {
+		iwl_dump_nic_error_log(priv);
+		iwl_dump_nic_event_log(priv);
+		iwl_print_rx_config_cmd(&priv->staging_rxon);
+	}
+#endif
+
+	wake_up_interruptible(&priv->wait_command_queue);
+
+	/* Keep the restart process from trying to send host
+	 * commands by clearing the INIT status bit */
+	clear_bit(STATUS_READY, &priv->status);
+
+	if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+		IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS,
+			  "Restarting adapter due to uCode error.\n");
+
+		if (iwl_is_associated(priv)) {
+			memcpy(&priv->recovery_rxon, &priv->active_rxon,
+			       sizeof(priv->recovery_rxon));
+			priv->error_recovering = 1;
+		}
+		queue_work(priv->workqueue, &priv->restart);
+	}
+}
+
+static void iwl_error_recovery(struct iwl_priv *priv)
+{
+	unsigned long flags;
+
+	memcpy(&priv->staging_rxon, &priv->recovery_rxon,
+	       sizeof(priv->staging_rxon));
+	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	iwl_commit_rxon(priv);
+
+	iwl_add_station(priv, priv->bssid, 1, 0);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id);
+	priv->error_recovering = 0;
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void iwl_irq_tasklet(struct iwl_priv *priv)
+{
+	u32 inta, handled = 0;
+	u32 inta_fh;
+	unsigned long flags;
+#ifdef CONFIG_IWLWIFI_DEBUG
+	u32 inta_mask;
+#endif
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	/* Ack/clear/reset pending uCode interrupts.
+	 * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
+	 *  and will clear only when CSR_FH_INT_STATUS gets cleared. */
+	inta = iwl_read32(priv, CSR_INT);
+	iwl_write32(priv, CSR_INT, inta);
+
+	/* Ack/clear/reset pending flow-handler (DMA) interrupts.
+	 * Any new interrupts that happen after this, either while we're
+	 * in this tasklet, or later, will show up in next ISR/tasklet. */
+	inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+	iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (iwl_debug_level & IWL_DL_ISR) {
+		inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
+		IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+			      inta, inta_mask, inta_fh);
+	}
+#endif
+
+	/* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
+	 * atomic, make sure that inta covers all the interrupts that
+	 * we've discovered, even if FH interrupt came in just after
+	 * reading CSR_INT. */
+	if (inta_fh & CSR_FH_INT_RX_MASK)
+		inta |= CSR_INT_BIT_FH_RX;
+	if (inta_fh & CSR_FH_INT_TX_MASK)
+		inta |= CSR_INT_BIT_FH_TX;
+
+	/* Now service all interrupt bits discovered above. */
+	if (inta & CSR_INT_BIT_HW_ERR) {
+		IWL_ERROR("Microcode HW error detected.  Restarting.\n");
+
+		/* Tell the device to stop sending interrupts */
+		iwl_disable_interrupts(priv);
+
+		iwl_irq_handle_error(priv);
+
+		handled |= CSR_INT_BIT_HW_ERR;
+
+		spin_unlock_irqrestore(&priv->lock, flags);
+
+		return;
+	}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (iwl_debug_level & (IWL_DL_ISR)) {
+		/* NIC fires this, but we don't use it, redundant with WAKEUP */
+		if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
+			IWL_DEBUG_ISR("Microcode started or stopped.\n");
+
+		/* Alive notification via Rx interrupt will do the real work */
+		if (inta & CSR_INT_BIT_ALIVE)
+			IWL_DEBUG_ISR("Alive interrupt\n");
+	}
+#endif
+	/* Safely ignore these bits for debug checks below */
+	inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
+
+	/* HW RF KILL switch toggled (4965 only) */
+	if (inta & CSR_INT_BIT_RF_KILL) {
+		int hw_rf_kill = 0;
+		if (!(iwl_read32(priv, CSR_GP_CNTRL) &
+				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+			hw_rf_kill = 1;
+
+		IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR,
+				"RF_KILL bit toggled to %s.\n",
+				hw_rf_kill ? "disable radio":"enable radio");
+
+		/* Queue restart only if RF_KILL switch was set to "kill"
+		 *   when we loaded driver, and is now set to "enable".
+		 * After we're Alive, RF_KILL gets handled by
+		 *   iwl_rx_card_state_notif() */
+		if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status))
+			queue_work(priv->workqueue, &priv->restart);
+
+		handled |= CSR_INT_BIT_RF_KILL;
+	}
+
+	/* Chip got too hot and stopped itself (4965 only) */
+	if (inta & CSR_INT_BIT_CT_KILL) {
+		IWL_ERROR("Microcode CT kill error detected.\n");
+		handled |= CSR_INT_BIT_CT_KILL;
+	}
+
+	/* Error detected by uCode */
+	if (inta & CSR_INT_BIT_SW_ERR) {
+		IWL_ERROR("Microcode SW error detected.  Restarting 0x%X.\n",
+			  inta);
+		iwl_irq_handle_error(priv);
+		handled |= CSR_INT_BIT_SW_ERR;
+	}
+
+	/* uCode wakes up after power-down sleep */
+	if (inta & CSR_INT_BIT_WAKEUP) {
+		IWL_DEBUG_ISR("Wakeup interrupt\n");
+		iwl_rx_queue_update_write_ptr(priv, &priv->rxq);
+		iwl_tx_queue_update_write_ptr(priv, &priv->txq[0]);
+		iwl_tx_queue_update_write_ptr(priv, &priv->txq[1]);
+		iwl_tx_queue_update_write_ptr(priv, &priv->txq[2]);
+		iwl_tx_queue_update_write_ptr(priv, &priv->txq[3]);
+		iwl_tx_queue_update_write_ptr(priv, &priv->txq[4]);
+		iwl_tx_queue_update_write_ptr(priv, &priv->txq[5]);
+
+		handled |= CSR_INT_BIT_WAKEUP;
+	}
+
+	/* All uCode command responses, including Tx command responses,
+	 * Rx "responses" (frame-received notification), and other
+	 * notifications from uCode come through here*/
+	if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
+		iwl_rx_handle(priv);
+		handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
+	}
+
+	if (inta & CSR_INT_BIT_FH_TX) {
+		IWL_DEBUG_ISR("Tx interrupt\n");
+
+		iwl_write32(priv, CSR_FH_INT_STATUS, (1 << 6));
+		if (!iwl_grab_restricted_access(priv)) {
+			iwl_write_restricted(priv,
+					     FH_TCSR_CREDIT
+					     (ALM_FH_SRVC_CHNL), 0x0);
+			iwl_release_restricted_access(priv);
+		}
+		handled |= CSR_INT_BIT_FH_TX;
+	}
+
+	if (inta & ~handled)
+		IWL_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
+
+	if (inta & ~CSR_INI_SET_MASK) {
+		IWL_WARNING("Disabled INTA bits 0x%08x were pending\n",
+			 inta & ~CSR_INI_SET_MASK);
+		IWL_WARNING("   with FH_INT = 0x%08x\n", inta_fh);
+	}
+
+	/* Re-enable all interrupts */
+	iwl_enable_interrupts(priv);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (iwl_debug_level & (IWL_DL_ISR)) {
+		inta = iwl_read32(priv, CSR_INT);
+		inta_mask = iwl_read32(priv, CSR_INT_MASK);
+		inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+		IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, "
+			"flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
+	}
+#endif
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static irqreturn_t iwl_isr(int irq, void *data)
+{
+	struct iwl_priv *priv = data;
+	u32 inta, inta_mask;
+	u32 inta_fh;
+	if (!priv)
+		return IRQ_NONE;
+
+	spin_lock(&priv->lock);
+
+	/* Disable (but don't clear!) interrupts here to avoid
+	 *    back-to-back ISRs and sporadic interrupts from our NIC.
+	 * If we have something to service, the tasklet will re-enable ints.
+	 * If we *don't* have something, we'll re-enable before leaving here. */
+	inta_mask = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
+	iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+	/* Discover which interrupts are active/pending */
+	inta = iwl_read32(priv, CSR_INT);
+	inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+
+	/* Ignore interrupt if there's nothing in NIC to service.
+	 * This may be due to IRQ shared with another device,
+	 * or due to sporadic interrupts thrown from our NIC. */
+	if (!inta && !inta_fh) {
+		IWL_DEBUG_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n");
+		goto none;
+	}
+
+	if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+		/* Hardware disappeared */
+		IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta);
+		goto none;
+	}
+
+	IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+		      inta, inta_mask, inta_fh);
+
+	/* iwl_irq_tasklet() will service interrupts and re-enable them */
+	tasklet_schedule(&priv->irq_tasklet);
+	spin_unlock(&priv->lock);
+
+	return IRQ_HANDLED;
+
+ none:
+	/* re-enable interrupts here since we don't have anything to service. */
+	iwl_enable_interrupts(priv);
+	spin_unlock(&priv->lock);
+	return IRQ_NONE;
+}
+
+/************************** EEPROM BANDS ****************************
+ *
+ * The iwl_eeprom_band definitions below provide the mapping from the
+ * EEPROM contents to the specific channel number supported for each
+ * band.
+ *
+ * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3
+ * definition below maps to physical channel 42 in the 5.2GHz spectrum.
+ * The specific geography and calibration information for that channel
+ * is contained in the eeprom map itself.
+ *
+ * During init, we copy the eeprom information and channel map
+ * information into priv->channel_info_24/52 and priv->channel_map_24/52
+ *
+ * channel_map_24/52 provides the index in the channel_info array for a
+ * given channel.  We have to have two separate maps as there is channel
+ * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and
+ * band_2
+ *
+ * A value of 0xff stored in the channel_map indicates that the channel
+ * is not supported by the hardware at all.
+ *
+ * A value of 0xfe in the channel_map indicates that the channel is not
+ * valid for Tx with the current hardware.  This means that
+ * while the system can tune and receive on a given channel, it may not
+ * be able to associate or transmit any frames on that
+ * channel.  There is no corresponding channel information for that
+ * entry.
+ *
+ *********************************************************************/
+
+/* 2.4 GHz */
+static const u8 iwl_eeprom_band_1[14] = {
+	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+};
+
+/* 5.2 GHz bands */
+static const u8 iwl_eeprom_band_2[] = {
+	183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
+};
+
+static const u8 iwl_eeprom_band_3[] = {	/* 5205-5320MHz */
+	34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
+};
+
+static const u8 iwl_eeprom_band_4[] = {	/* 5500-5700MHz */
+	100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
+};
+
+static const u8 iwl_eeprom_band_5[] = {	/* 5725-5825MHz */
+	145, 149, 153, 157, 161, 165
+};
+
+static void iwl_init_band_reference(const struct iwl_priv *priv, int band,
+				    int *eeprom_ch_count,
+				    const struct iwl_eeprom_channel
+				    **eeprom_ch_info,
+				    const u8 **eeprom_ch_index)
+{
+	switch (band) {
+	case 1:		/* 2.4GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1);
+		*eeprom_ch_info = priv->eeprom.band_1_channels;
+		*eeprom_ch_index = iwl_eeprom_band_1;
+		break;
+	case 2:		/* 5.2GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2);
+		*eeprom_ch_info = priv->eeprom.band_2_channels;
+		*eeprom_ch_index = iwl_eeprom_band_2;
+		break;
+	case 3:		/* 5.2GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3);
+		*eeprom_ch_info = priv->eeprom.band_3_channels;
+		*eeprom_ch_index = iwl_eeprom_band_3;
+		break;
+	case 4:		/* 5.2GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4);
+		*eeprom_ch_info = priv->eeprom.band_4_channels;
+		*eeprom_ch_index = iwl_eeprom_band_4;
+		break;
+	case 5:		/* 5.2GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5);
+		*eeprom_ch_info = priv->eeprom.band_5_channels;
+		*eeprom_ch_index = iwl_eeprom_band_5;
+		break;
+	default:
+		BUG();
+		return;
+	}
+}
+
+const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
+						    int phymode, u16 channel)
+{
+	int i;
+
+	switch (phymode) {
+	case MODE_IEEE80211A:
+		for (i = 14; i < priv->channel_count; i++) {
+			if (priv->channel_info[i].channel == channel)
+				return &priv->channel_info[i];
+		}
+		break;
+
+	case MODE_IEEE80211B:
+	case MODE_IEEE80211G:
+		if (channel >= 1 && channel <= 14)
+			return &priv->channel_info[channel - 1];
+		break;
+
+	}
+
+	return NULL;
+}
+
+#define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
+			    ? # x " " : "")
+
+static int iwl_init_channel_map(struct iwl_priv *priv)
+{
+	int eeprom_ch_count = 0;
+	const u8 *eeprom_ch_index = NULL;
+	const struct iwl_eeprom_channel *eeprom_ch_info = NULL;
+	int band, ch;
+	struct iwl_channel_info *ch_info;
+
+	if (priv->channel_count) {
+		IWL_DEBUG_INFO("Channel map already initialized.\n");
+		return 0;
+	}
+
+	if (priv->eeprom.version < 0x2f) {
+		IWL_WARNING("Unsupported EEPROM version: 0x%04X\n",
+			    priv->eeprom.version);
+		return -EINVAL;
+	}
+
+	IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n");
+
+	priv->channel_count =
+	    ARRAY_SIZE(iwl_eeprom_band_1) +
+	    ARRAY_SIZE(iwl_eeprom_band_2) +
+	    ARRAY_SIZE(iwl_eeprom_band_3) +
+	    ARRAY_SIZE(iwl_eeprom_band_4) +
+	    ARRAY_SIZE(iwl_eeprom_band_5);
+
+	IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count);
+
+	priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) *
+				     priv->channel_count, GFP_KERNEL);
+	if (!priv->channel_info) {
+		IWL_ERROR("Could not allocate channel_info\n");
+		priv->channel_count = 0;
+		return -ENOMEM;
+	}
+
+	ch_info = priv->channel_info;
+
+	/* Loop through the 5 EEPROM bands adding them in order to the
+	 * channel map we maintain (that contains additional information than
+	 * what just in the EEPROM) */
+	for (band = 1; band <= 5; band++) {
+
+		iwl_init_band_reference(priv, band, &eeprom_ch_count,
+					&eeprom_ch_info, &eeprom_ch_index);
+
+		/* Loop through each band adding each of the channels */
+		for (ch = 0; ch < eeprom_ch_count; ch++) {
+			ch_info->channel = eeprom_ch_index[ch];
+			ch_info->phymode = (band == 1) ? MODE_IEEE80211B :
+			    MODE_IEEE80211A;
+
+			/* permanently store EEPROM's channel regulatory flags
+			 *   and max power in channel info database. */
+			ch_info->eeprom = eeprom_ch_info[ch];
+
+			/* Copy the run-time flags so they are there even on
+			 * invalid channels */
+			ch_info->flags = eeprom_ch_info[ch].flags;
+
+			if (!(is_channel_valid(ch_info))) {
+				IWL_DEBUG_INFO("Ch. %d Flags %x [%sGHz] - "
+					       "No traffic\n",
+					       ch_info->channel,
+					       ch_info->flags,
+					       is_channel_a_band(ch_info) ?
+					       "5.2" : "2.4");
+				ch_info++;
+				continue;
+			}
+
+			/* Initialize regulatory-based run-time data */
+			ch_info->max_power_avg = ch_info->curr_txpow =
+			    eeprom_ch_info[ch].max_power_avg;
+			ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
+			ch_info->min_power = 0;
+
+			IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
+				       " %ddBm): Ad-Hoc %ssupported\n",
+				       ch_info->channel,
+				       is_channel_a_band(ch_info) ?
+				       "5.2" : "2.4",
+				       CHECK_AND_PRINT(IBSS),
+				       CHECK_AND_PRINT(ACTIVE),
+				       CHECK_AND_PRINT(RADAR),
+				       CHECK_AND_PRINT(WIDE),
+				       CHECK_AND_PRINT(NARROW),
+				       CHECK_AND_PRINT(DFS),
+				       eeprom_ch_info[ch].flags,
+				       eeprom_ch_info[ch].max_power_avg,
+				       ((eeprom_ch_info[ch].
+					 flags & EEPROM_CHANNEL_IBSS)
+					&& !(eeprom_ch_info[ch].
+					     flags & EEPROM_CHANNEL_RADAR))
+				       ? "" : "not ");
+
+			/* Set the user_txpower_limit to the highest power
+			 * supported by any channel */
+			if (eeprom_ch_info[ch].max_power_avg >
+			    priv->user_txpower_limit)
+				priv->user_txpower_limit =
+				    eeprom_ch_info[ch].max_power_avg;
+
+			ch_info++;
+		}
+	}
+
+	if (iwl3945_txpower_set_from_eeprom(priv))
+		return -EIO;
+
+	return 0;
+}
+
+/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
+ * sending probe req.  This should be set long enough to hear probe responses
+ * from more than one AP.  */
+#define IWL_ACTIVE_DWELL_TIME_24    (20)	/* all times in msec */
+#define IWL_ACTIVE_DWELL_TIME_52    (10)
+
+/* For faster active scanning, scan will move to the next channel if fewer than
+ * PLCP_QUIET_THRESH packets are heard on this channel within
+ * ACTIVE_QUIET_TIME after sending probe request.  This shortens the dwell
+ * time if it's a quiet channel (nothing responded to our probe, and there's
+ * no other traffic).
+ * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
+#define IWL_PLCP_QUIET_THRESH       __constant_cpu_to_le16(1)	/* packets */
+#define IWL_ACTIVE_QUIET_TIME       __constant_cpu_to_le16(5)	/* msec */
+
+/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
+ * Must be set longer than active dwell time.
+ * For the most reliable scan, set > AP beacon interval (typically 100msec). */
+#define IWL_PASSIVE_DWELL_TIME_24   (20)	/* all times in msec */
+#define IWL_PASSIVE_DWELL_TIME_52   (10)
+#define IWL_PASSIVE_DWELL_BASE      (100)
+#define IWL_CHANNEL_TUNE_TIME       5
+
+static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode)
+{
+	if (phymode == MODE_IEEE80211A)
+		return IWL_ACTIVE_DWELL_TIME_52;
+	else
+		return IWL_ACTIVE_DWELL_TIME_24;
+}
+
+static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode)
+{
+	u16 active = iwl_get_active_dwell_time(priv, phymode);
+	u16 passive = (phymode != MODE_IEEE80211A) ?
+	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
+	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
+
+	if (iwl_is_associated(priv)) {
+		/* If we're associated, we clamp the maximum passive
+		 * dwell time to be 98% of the beacon interval (minus
+		 * 2 * channel tune time) */
+		passive = priv->beacon_int;
+		if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive)
+			passive = IWL_PASSIVE_DWELL_BASE;
+		passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
+	}
+
+	if (passive <= active)
+		passive = active + 1;
+
+	return passive;
+}
+
+static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
+				     u8 is_active, u8 direct_mask,
+				     struct iwl_scan_channel *scan_ch)
+{
+	const struct ieee80211_channel *channels = NULL;
+	const struct ieee80211_hw_mode *hw_mode;
+	const struct iwl_channel_info *ch_info;
+	u16 passive_dwell = 0;
+	u16 active_dwell = 0;
+	int added, i;
+
+	hw_mode = iwl_get_hw_mode(priv, phymode);
+	if (!hw_mode)
+		return 0;
+
+	channels = hw_mode->channels;
+
+	active_dwell = iwl_get_active_dwell_time(priv, phymode);
+	passive_dwell = iwl_get_passive_dwell_time(priv, phymode);
+
+	for (i = 0, added = 0; i < hw_mode->num_channels; i++) {
+		if (channels[i].chan ==
+		    le16_to_cpu(priv->active_rxon.channel)) {
+			if (iwl_is_associated(priv)) {
+				IWL_DEBUG_SCAN
+				    ("Skipping current channel %d\n",
+				     le16_to_cpu(priv->active_rxon.channel));
+				continue;
+			}
+		} else if (priv->only_active_channel)
+			continue;
+
+		scan_ch->channel = channels[i].chan;
+
+		ch_info = iwl_get_channel_info(priv, phymode, scan_ch->channel);
+		if (!is_channel_valid(ch_info)) {
+			IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
+				       scan_ch->channel);
+			continue;
+		}
+
+		if (!is_active || is_channel_passive(ch_info) ||
+		    !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN))
+			scan_ch->type = 0;	/* passive */
+		else
+			scan_ch->type = 1;	/* active */
+
+		if (scan_ch->type & 1)
+			scan_ch->type |= (direct_mask << 1);
+
+		if (is_channel_narrow(ch_info))
+			scan_ch->type |= (1 << 7);
+
+		scan_ch->active_dwell = cpu_to_le16(active_dwell);
+		scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+
+		/* Set power levels to defaults */
+		scan_ch->tpc.dsp_atten = 110;
+		/* scan_pwr_info->tpc.dsp_atten; */
+
+		/*scan_pwr_info->tpc.tx_gain; */
+		if (phymode == MODE_IEEE80211A)
+			scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3;
+		else {
+			scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
+			/* NOTE: if we were doing 6Mb OFDM for scans we'd use
+			 * power level
+			 scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3;
+			 */
+		}
+
+		IWL_DEBUG_SCAN("Scanning %d [%s %d]\n",
+			       scan_ch->channel,
+			       (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE",
+			       (scan_ch->type & 1) ?
+			       active_dwell : passive_dwell);
+
+		scan_ch++;
+		added++;
+	}
+
+	IWL_DEBUG_SCAN("total channels to scan %d \n", added);
+	return added;
+}
+
+static void iwl_reset_channel_flag(struct iwl_priv *priv)
+{
+	int i, j;
+	for (i = 0; i < 3; i++) {
+		struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i];
+		for (j = 0; j < hw_mode->num_channels; j++)
+			hw_mode->channels[j].flag = hw_mode->channels[j].val;
+	}
+}
+
+static void iwl_init_hw_rates(struct iwl_priv *priv,
+			      struct ieee80211_rate *rates)
+{
+	int i;
+
+	for (i = 0; i < IWL_RATE_COUNT; i++) {
+		rates[i].rate = iwl_rates[i].ieee * 5;
+		rates[i].val = i; /* Rate scaling will work on indexes */
+		rates[i].val2 = i;
+		rates[i].flags = IEEE80211_RATE_SUPPORTED;
+		/* Only OFDM have the bits-per-symbol set */
+		if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE))
+			rates[i].flags |= IEEE80211_RATE_OFDM;
+		else {
+			/*
+			 * If CCK 1M then set rate flag to CCK else CCK_2
+			 * which is CCK | PREAMBLE2
+			 */
+			rates[i].flags |= (iwl_rates[i].plcp == 10) ?
+				IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2;
+		}
+
+		/* Set up which ones are basic rates... */
+		if (IWL_BASIC_RATES_MASK & (1 << i))
+			rates[i].flags |= IEEE80211_RATE_BASIC;
+	}
+}
+
+/**
+ * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom
+ */
+static int iwl_init_geos(struct iwl_priv *priv)
+{
+	struct iwl_channel_info *ch;
+	struct ieee80211_hw_mode *modes;
+	struct ieee80211_channel *channels;
+	struct ieee80211_channel *geo_ch;
+	struct ieee80211_rate *rates;
+	int i = 0;
+	enum {
+		A = 0,
+		B = 1,
+		G = 2,
+	};
+	int mode_count = 3;
+
+	if (priv->modes) {
+		IWL_DEBUG_INFO("Geography modes already initialized.\n");
+		set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+		return 0;
+	}
+
+	modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count,
+			GFP_KERNEL);
+	if (!modes)
+		return -ENOMEM;
+
+	channels = kzalloc(sizeof(struct ieee80211_channel) *
+			   priv->channel_count, GFP_KERNEL);
+	if (!channels) {
+		kfree(modes);
+		return -ENOMEM;
+	}
+
+	rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)),
+			GFP_KERNEL);
+	if (!rates) {
+		kfree(modes);
+		kfree(channels);
+		return -ENOMEM;
+	}
+
+	/* 0 = 802.11a
+	 * 1 = 802.11b
+	 * 2 = 802.11g
+	 */
+
+	/* 5.2GHz channels start after the 2.4GHz channels */
+	modes[A].mode = MODE_IEEE80211A;
+	modes[A].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
+	modes[A].rates = rates;
+	modes[A].num_rates = 8;	/* just OFDM */
+	modes[A].num_channels = 0;
+
+	modes[B].mode = MODE_IEEE80211B;
+	modes[B].channels = channels;
+	modes[B].rates = &rates[8];
+	modes[B].num_rates = 4;	/* just CCK */
+	modes[B].num_channels = 0;
+
+	modes[G].mode = MODE_IEEE80211G;
+	modes[G].channels = channels;
+	modes[G].rates = rates;
+	modes[G].num_rates = 12;	/* OFDM & CCK */
+	modes[G].num_channels = 0;
+
+	priv->ieee_channels = channels;
+	priv->ieee_rates = rates;
+
+	iwl_init_hw_rates(priv, rates);
+
+	for (i = 0, geo_ch = channels; i < priv->channel_count; i++) {
+		ch = &priv->channel_info[i];
+
+		if (!is_channel_valid(ch)) {
+			IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- "
+				    "skipping.\n",
+				    ch->channel, is_channel_a_band(ch) ?
+				    "5.2" : "2.4");
+			continue;
+		}
+
+		if (is_channel_a_band(ch))
+			geo_ch = &modes[A].channels[modes[A].num_channels++];
+		else {
+			geo_ch = &modes[B].channels[modes[B].num_channels++];
+			modes[G].num_channels++;
+		}
+
+		geo_ch->freq = ieee80211chan2mhz(ch->channel);
+		geo_ch->chan = ch->channel;
+		geo_ch->power_level = ch->max_power_avg;
+		geo_ch->antenna_max = 0xff;
+
+		if (is_channel_valid(ch)) {
+			geo_ch->flag = IEEE80211_CHAN_W_SCAN;
+			if (ch->flags & EEPROM_CHANNEL_IBSS)
+				geo_ch->flag |= IEEE80211_CHAN_W_IBSS;
+
+			if (ch->flags & EEPROM_CHANNEL_ACTIVE)
+				geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN;
+
+			if (ch->flags & EEPROM_CHANNEL_RADAR)
+				geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT;
+
+			if (ch->max_power_avg > priv->max_channel_txpower_limit)
+				priv->max_channel_txpower_limit =
+				    ch->max_power_avg;
+		}
+
+		geo_ch->val = geo_ch->flag;
+	}
+
+	if ((modes[A].num_channels == 0) && priv->is_abg) {
+		printk(KERN_INFO DRV_NAME
+		       ": Incorrectly detected BG card as ABG.  Please send "
+		       "your PCI ID 0x%04X:0x%04X to maintainer.\n",
+		       priv->pci_dev->device, priv->pci_dev->subsystem_device);
+		priv->is_abg = 0;
+	}
+
+	printk(KERN_INFO DRV_NAME
+	       ": Tunable channels: %d 802.11bg, %d 802.11a channels\n",
+	       modes[G].num_channels, modes[A].num_channels);
+
+	/*
+	 * NOTE:  We register these in preference of order -- the
+	 * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick
+	 * a phymode based on rates or AP capabilities but seems to
+	 * configure it purely on if the channel being configured
+	 * is supported by a mode -- and the first match is taken
+	 */
+
+	if (modes[G].num_channels)
+		ieee80211_register_hwmode(priv->hw, &modes[G]);
+	if (modes[B].num_channels)
+		ieee80211_register_hwmode(priv->hw, &modes[B]);
+	if (modes[A].num_channels)
+		ieee80211_register_hwmode(priv->hw, &modes[A]);
+
+	priv->modes = modes;
+	set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ * uCode download functions
+ *
+ ******************************************************************************/
+
+static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
+{
+	if (priv->ucode_code.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_code.len,
+				    priv->ucode_code.v_addr,
+				    priv->ucode_code.p_addr);
+		priv->ucode_code.v_addr = NULL;
+	}
+	if (priv->ucode_data.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_data.len,
+				    priv->ucode_data.v_addr,
+				    priv->ucode_data.p_addr);
+		priv->ucode_data.v_addr = NULL;
+	}
+	if (priv->ucode_data_backup.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_data_backup.len,
+				    priv->ucode_data_backup.v_addr,
+				    priv->ucode_data_backup.p_addr);
+		priv->ucode_data_backup.v_addr = NULL;
+	}
+	if (priv->ucode_init.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_init.len,
+				    priv->ucode_init.v_addr,
+				    priv->ucode_init.p_addr);
+		priv->ucode_init.v_addr = NULL;
+	}
+	if (priv->ucode_init_data.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_init_data.len,
+				    priv->ucode_init_data.v_addr,
+				    priv->ucode_init_data.p_addr);
+		priv->ucode_init_data.v_addr = NULL;
+	}
+	if (priv->ucode_boot.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_boot.len,
+				    priv->ucode_boot.v_addr,
+				    priv->ucode_boot.p_addr);
+		priv->ucode_boot.v_addr = NULL;
+	}
+}
+
+/**
+ * iwl_verify_inst_full - verify runtime uCode image in card vs. host,
+ *     looking at all data.
+ */
+static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
+{
+	u32 val;
+	u32 save_len = len;
+	int rc = 0;
+	u32 errcnt;
+
+	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+	rc = iwl_grab_restricted_access(priv);
+	if (rc)
+		return rc;
+
+	iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND);
+
+	errcnt = 0;
+	for (; len > 0; len -= sizeof(u32), image++) {
+		/* read data comes through single port, auto-incr addr */
+		/* NOTE: Use the debugless read so we don't flood kernel log
+		 * if IWL_DL_IO is set */
+		val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+		if (val != le32_to_cpu(*image)) {
+			IWL_ERROR("uCode INST section is invalid at "
+				  "offset 0x%x, is 0x%x, s/b 0x%x\n",
+				  save_len - len, val, le32_to_cpu(*image));
+			rc = -EIO;
+			errcnt++;
+			if (errcnt >= 20)
+				break;
+		}
+	}
+
+	iwl_release_restricted_access(priv);
+
+	if (!errcnt)
+		IWL_DEBUG_INFO
+		    ("ucode image in INSTRUCTION memory is good\n");
+
+	return rc;
+}
+
+
+/**
+ * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
+ *   using sample data 100 bytes apart.  If these sample points are good,
+ *   it's a pretty good bet that everything between them is good, too.
+ */
+static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+{
+	u32 val;
+	int rc = 0;
+	u32 errcnt = 0;
+	u32 i;
+
+	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+	rc = iwl_grab_restricted_access(priv);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
+		/* read data comes through single port, auto-incr addr */
+		/* NOTE: Use the debugless read so we don't flood kernel log
+		 * if IWL_DL_IO is set */
+		iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR,
+			i + RTC_INST_LOWER_BOUND);
+		val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+		if (val != le32_to_cpu(*image)) {
+#if 0 /* Enable this if you want to see details */
+			IWL_ERROR("uCode INST section is invalid at "
+				  "offset 0x%x, is 0x%x, s/b 0x%x\n",
+				  i, val, *image);
+#endif
+			rc = -EIO;
+			errcnt++;
+			if (errcnt >= 3)
+				break;
+		}
+	}
+
+	iwl_release_restricted_access(priv);
+
+	return rc;
+}
+
+
+/**
+ * iwl_verify_ucode - determine which instruction image is in SRAM,
+ *    and verify its contents
+ */
+static int iwl_verify_ucode(struct iwl_priv *priv)
+{
+	__le32 *image;
+	u32 len;
+	int rc = 0;
+
+	/* Try bootstrap */
+	image = (__le32 *)priv->ucode_boot.v_addr;
+	len = priv->ucode_boot.len;
+	rc = iwl_verify_inst_sparse(priv, image, len);
+	if (rc == 0) {
+		IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
+		return 0;
+	}
+
+	/* Try initialize */
+	image = (__le32 *)priv->ucode_init.v_addr;
+	len = priv->ucode_init.len;
+	rc = iwl_verify_inst_sparse(priv, image, len);
+	if (rc == 0) {
+		IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
+		return 0;
+	}
+
+	/* Try runtime/protocol */
+	image = (__le32 *)priv->ucode_code.v_addr;
+	len = priv->ucode_code.len;
+	rc = iwl_verify_inst_sparse(priv, image, len);
+	if (rc == 0) {
+		IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
+		return 0;
+	}
+
+	IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
+
+	/* Show first several data entries in instruction SRAM.
+	 * Selection of bootstrap image is arbitrary. */
+	image = (__le32 *)priv->ucode_boot.v_addr;
+	len = priv->ucode_boot.len;
+	rc = iwl_verify_inst_full(priv, image, len);
+
+	return rc;
+}
+
+
+/* check contents of special bootstrap uCode SRAM */
+static int iwl_verify_bsm(struct iwl_priv *priv)
+{
+	__le32 *image = priv->ucode_boot.v_addr;
+	u32 len = priv->ucode_boot.len;
+	u32 reg;
+	u32 val;
+
+	IWL_DEBUG_INFO("Begin verify bsm\n");
+
+	/* verify BSM SRAM contents */
+	val = iwl_read_restricted_reg(priv, BSM_WR_DWCOUNT_REG);
+	for (reg = BSM_SRAM_LOWER_BOUND;
+	     reg < BSM_SRAM_LOWER_BOUND + len;
+	     reg += sizeof(u32), image ++) {
+		val = iwl_read_restricted_reg(priv, reg);
+		if (val != le32_to_cpu(*image)) {
+			IWL_ERROR("BSM uCode verification failed at "
+				  "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
+				  BSM_SRAM_LOWER_BOUND,
+				  reg - BSM_SRAM_LOWER_BOUND, len,
+				  val, le32_to_cpu(*image));
+			return -EIO;
+		}
+	}
+
+	IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n");
+
+	return 0;
+}
+
+/**
+ * iwl_load_bsm - Load bootstrap instructions
+ *
+ * BSM operation:
+ *
+ * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
+ * in special SRAM that does not power down during RFKILL.  When powering back
+ * up after power-saving sleeps (or during initial uCode load), the BSM loads
+ * the bootstrap program into the on-board processor, and starts it.
+ *
+ * The bootstrap program loads (via DMA) instructions and data for a new
+ * program from host DRAM locations indicated by the host driver in the
+ * BSM_DRAM_* registers.  Once the new program is loaded, it starts
+ * automatically.
+ *
+ * When initializing the NIC, the host driver points the BSM to the
+ * "initialize" uCode image.  This uCode sets up some internal data, then
+ * notifies host via "initialize alive" that it is complete.
+ *
+ * The host then replaces the BSM_DRAM_* pointer values to point to the
+ * normal runtime uCode instructions and a backup uCode data cache buffer
+ * (filled initially with starting data values for the on-board processor),
+ * then triggers the "initialize" uCode to load and launch the runtime uCode,
+ * which begins normal operation.
+ *
+ * When doing a power-save shutdown, runtime uCode saves data SRAM into
+ * the backup data cache in DRAM before SRAM is powered down.
+ *
+ * When powering back up, the BSM loads the bootstrap program.  This reloads
+ * the runtime uCode instructions and the backup data cache into SRAM,
+ * and re-launches the runtime uCode from where it left off.
+ */
+static int iwl_load_bsm(struct iwl_priv *priv)
+{
+	__le32 *image = priv->ucode_boot.v_addr;
+	u32 len = priv->ucode_boot.len;
+	dma_addr_t pinst;
+	dma_addr_t pdata;
+	u32 inst_len;
+	u32 data_len;
+	int rc;
+	int i;
+	u32 done;
+	u32 reg_offset;
+
+	IWL_DEBUG_INFO("Begin load bsm\n");
+
+	/* make sure bootstrap program is no larger than BSM's SRAM size */
+	if (len > IWL_MAX_BSM_SIZE)
+		return -EINVAL;
+
+	/* Tell bootstrap uCode where to find the "Initialize" uCode
+	 *   in host DRAM ... bits 31:0 for 3945, bits 35:4 for 4965.
+	 * NOTE:  iwl_initialize_alive_start() will replace these values,
+	 *        after the "initialize" uCode has run, to point to
+	 *        runtime/protocol instructions and backup data cache. */
+	pinst = priv->ucode_init.p_addr;
+	pdata = priv->ucode_init_data.p_addr;
+	inst_len = priv->ucode_init.len;
+	data_len = priv->ucode_init_data.len;
+
+	rc = iwl_grab_restricted_access(priv);
+	if (rc)
+		return rc;
+
+	iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
+	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+	iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
+	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
+
+	/* Fill BSM memory with bootstrap instructions */
+	for (reg_offset = BSM_SRAM_LOWER_BOUND;
+	     reg_offset < BSM_SRAM_LOWER_BOUND + len;
+	     reg_offset += sizeof(u32), image++)
+		_iwl_write_restricted_reg(priv, reg_offset,
+					  le32_to_cpu(*image));
+
+	rc = iwl_verify_bsm(priv);
+	if (rc) {
+		iwl_release_restricted_access(priv);
+		return rc;
+	}
+
+	/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
+	iwl_write_restricted_reg(priv, BSM_WR_MEM_SRC_REG, 0x0);
+	iwl_write_restricted_reg(priv, BSM_WR_MEM_DST_REG,
+				 RTC_INST_LOWER_BOUND);
+	iwl_write_restricted_reg(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
+
+	/* Load bootstrap code into instruction SRAM now,
+	 *   to prepare to load "initialize" uCode */
+	iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG,
+		BSM_WR_CTRL_REG_BIT_START);
+
+	/* Wait for load of bootstrap uCode to finish */
+	for (i = 0; i < 100; i++) {
+		done = iwl_read_restricted_reg(priv, BSM_WR_CTRL_REG);
+		if (!(done & BSM_WR_CTRL_REG_BIT_START))
+			break;
+		udelay(10);
+	}
+	if (i < 100)
+		IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i);
+	else {
+		IWL_ERROR("BSM write did not complete!\n");
+		return -EIO;
+	}
+
+	/* Enable future boot loads whenever power management unit triggers it
+	 *   (e.g. when powering back up after power-save shutdown) */
+	iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG,
+		BSM_WR_CTRL_REG_BIT_START_EN);
+
+	iwl_release_restricted_access(priv);
+
+	return 0;
+}
+
+static void iwl_nic_start(struct iwl_priv *priv)
+{
+	/* Remove all resets to allow NIC to operate */
+	iwl_write32(priv, CSR_RESET, 0);
+}
+
+/**
+ * iwl_read_ucode - Read uCode images from disk file.
+ *
+ * Copy into buffers for card to fetch via bus-mastering
+ */
+static int iwl_read_ucode(struct iwl_priv *priv)
+{
+	struct iwl_ucode *ucode;
+	int rc = 0;
+	const struct firmware *ucode_raw;
+	/* firmware file name contains uCode/driver compatibility version */
+	const char *name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode";
+	u8 *src;
+	size_t len;
+	u32 ver, inst_size, data_size, init_size, init_data_size, boot_size;
+
+	/* Ask kernel firmware_class module to get the boot firmware off disk.
+	 * request_firmware() is synchronous, file is in memory on return. */
+	rc = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
+	if (rc < 0) {
+		IWL_ERROR("%s firmware file req failed: Reason %d\n", name, rc);
+		goto error;
+	}
+
+	IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n",
+		       name, ucode_raw->size);
+
+	/* Make sure that we got at least our header! */
+	if (ucode_raw->size < sizeof(*ucode)) {
+		IWL_ERROR("File size way too small!\n");
+		rc = -EINVAL;
+		goto err_release;
+	}
+
+	/* Data from ucode file:  header followed by uCode images */
+	ucode = (void *)ucode_raw->data;
+
+	ver = le32_to_cpu(ucode->ver);
+	inst_size = le32_to_cpu(ucode->inst_size);
+	data_size = le32_to_cpu(ucode->data_size);
+	init_size = le32_to_cpu(ucode->init_size);
+	init_data_size = le32_to_cpu(ucode->init_data_size);
+	boot_size = le32_to_cpu(ucode->boot_size);
+
+	IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver);
+	IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n",
+		       inst_size);
+	IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n",
+		       data_size);
+	IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n",
+		       init_size);
+	IWL_DEBUG_INFO("f/w package hdr init data size = %u\n",
+		       init_data_size);
+	IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n",
+		       boot_size);
+
+	/* Verify size of file vs. image size info in file's header */
+	if (ucode_raw->size < sizeof(*ucode) +
+		inst_size + data_size + init_size +
+		init_data_size + boot_size) {
+
+		IWL_DEBUG_INFO("uCode file size %d too small\n",
+			       (int)ucode_raw->size);
+		rc = -EINVAL;
+		goto err_release;
+	}
+
+	/* Verify that uCode images will fit in card's SRAM */
+	if (inst_size > IWL_MAX_INST_SIZE) {
+		IWL_DEBUG_INFO("uCode instr len %d too large to fit in card\n",
+			       (int)inst_size);
+		rc = -EINVAL;
+		goto err_release;
+	}
+
+	if (data_size > IWL_MAX_DATA_SIZE) {
+		IWL_DEBUG_INFO("uCode data len %d too large to fit in card\n",
+			       (int)data_size);
+		rc = -EINVAL;
+		goto err_release;
+	}
+	if (init_size > IWL_MAX_INST_SIZE) {
+		IWL_DEBUG_INFO
+		    ("uCode init instr len %d too large to fit in card\n",
+		     (int)init_size);
+		rc = -EINVAL;
+		goto err_release;
+	}
+	if (init_data_size > IWL_MAX_DATA_SIZE) {
+		IWL_DEBUG_INFO
+		    ("uCode init data len %d too large to fit in card\n",
+		     (int)init_data_size);
+		rc = -EINVAL;
+		goto err_release;
+	}
+	if (boot_size > IWL_MAX_BSM_SIZE) {
+		IWL_DEBUG_INFO
+		    ("uCode boot instr len %d too large to fit in bsm\n",
+		     (int)boot_size);
+		rc = -EINVAL;
+		goto err_release;
+	}
+
+	/* Allocate ucode buffers for card's bus-master loading ... */
+
+	/* Runtime instructions and 2 copies of data:
+	 * 1) unmodified from disk
+	 * 2) backup cache for save/restore during power-downs */
+	priv->ucode_code.len = inst_size;
+	priv->ucode_code.v_addr =
+	    pci_alloc_consistent(priv->pci_dev,
+				 priv->ucode_code.len,
+				 &(priv->ucode_code.p_addr));
+
+	priv->ucode_data.len = data_size;
+	priv->ucode_data.v_addr =
+	    pci_alloc_consistent(priv->pci_dev,
+				 priv->ucode_data.len,
+				 &(priv->ucode_data.p_addr));
+
+	priv->ucode_data_backup.len = data_size;
+	priv->ucode_data_backup.v_addr =
+	    pci_alloc_consistent(priv->pci_dev,
+				 priv->ucode_data_backup.len,
+				 &(priv->ucode_data_backup.p_addr));
+
+
+	/* Initialization instructions and data */
+	priv->ucode_init.len = init_size;
+	priv->ucode_init.v_addr =
+	    pci_alloc_consistent(priv->pci_dev,
+				 priv->ucode_init.len,
+				 &(priv->ucode_init.p_addr));
+
+	priv->ucode_init_data.len = init_data_size;
+	priv->ucode_init_data.v_addr =
+	    pci_alloc_consistent(priv->pci_dev,
+				 priv->ucode_init_data.len,
+				 &(priv->ucode_init_data.p_addr));
+
+	/* Bootstrap (instructions only, no data) */
+	priv->ucode_boot.len = boot_size;
+	priv->ucode_boot.v_addr =
+	    pci_alloc_consistent(priv->pci_dev,
+				 priv->ucode_boot.len,
+				 &(priv->ucode_boot.p_addr));
+
+	if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
+	    !priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr ||
+	    !priv->ucode_boot.v_addr || !priv->ucode_data_backup.v_addr)
+		goto err_pci_alloc;
+
+	/* Copy images into buffers for card's bus-master reads ... */
+
+	/* Runtime instructions (first block of data in file) */
+	src = &ucode->data[0];
+	len = priv->ucode_code.len;
+	IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %d\n",
+		       (int)len);
+	memcpy(priv->ucode_code.v_addr, src, len);
+	IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
+		priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
+
+	/* Runtime data (2nd block)
+	 * NOTE:  Copy into backup buffer will be done in iwl_up()  */
+	src = &ucode->data[inst_size];
+	len = priv->ucode_data.len;
+	IWL_DEBUG_INFO("Copying (but not loading) uCode data len %d\n",
+		       (int)len);
+	memcpy(priv->ucode_data.v_addr, src, len);
+	memcpy(priv->ucode_data_backup.v_addr, src, len);
+
+	/* Initialization instructions (3rd block) */
+	if (init_size) {
+		src = &ucode->data[inst_size + data_size];
+		len = priv->ucode_init.len;
+		IWL_DEBUG_INFO("Copying (but not loading) init instr len %d\n",
+			       (int)len);
+		memcpy(priv->ucode_init.v_addr, src, len);
+	}
+
+	/* Initialization data (4th block) */
+	if (init_data_size) {
+		src = &ucode->data[inst_size + data_size + init_size];
+		len = priv->ucode_init_data.len;
+		IWL_DEBUG_INFO("Copying (but not loading) init data len %d\n",
+			       (int)len);
+		memcpy(priv->ucode_init_data.v_addr, src, len);
+	}
+
+	/* Bootstrap instructions (5th block) */
+	src = &ucode->data[inst_size + data_size + init_size + init_data_size];
+	len = priv->ucode_boot.len;
+	IWL_DEBUG_INFO("Copying (but not loading) boot instr len %d\n",
+		       (int)len);
+	memcpy(priv->ucode_boot.v_addr, src, len);
+
+	/* We have our copies now, allow OS release its copies */
+	release_firmware(ucode_raw);
+	return 0;
+
+ err_pci_alloc:
+	IWL_ERROR("failed to allocate pci memory\n");
+	rc = -ENOMEM;
+	iwl_dealloc_ucode_pci(priv);
+
+ err_release:
+	release_firmware(ucode_raw);
+
+ error:
+	return rc;
+}
+
+
+/**
+ * iwl_set_ucode_ptrs - Set uCode address location
+ *
+ * Tell initialization uCode where to find runtime uCode.
+ *
+ * BSM registers initially contain pointers to initialization uCode.
+ * We need to replace them to load runtime uCode inst and data,
+ * and to save runtime data when powering down.
+ */
+static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
+{
+	dma_addr_t pinst;
+	dma_addr_t pdata;
+	int rc = 0;
+	unsigned long flags;
+
+	/* bits 31:0 for 3945 */
+	pinst = priv->ucode_code.p_addr;
+	pdata = priv->ucode_data_backup.p_addr;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+
+	/* Tell bootstrap uCode where to find image to load */
+	iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
+	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
+				 priv->ucode_data.len);
+
+	/* Inst bytecount must be last to set up, bit 31 signals uCode
+	 *   that all new ptr/size info is in place */
+	iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG,
+				 priv->ucode_code.len | BSM_DRAM_INST_LOAD);
+
+	iwl_release_restricted_access(priv);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	IWL_DEBUG_INFO("Runtime uCode pointers are set.\n");
+
+	return rc;
+}
+
+/**
+ * iwl_init_alive_start - Called after REPLY_ALIVE notification receieved
+ *
+ * Called after REPLY_ALIVE notification received from "initialize" uCode.
+ *
+ * The 4965 "initialize" ALIVE reply contains calibration data for:
+ *   Voltage, temperature, and MIMO tx gain correction, now stored in priv
+ *   (3945 does not contain this data).
+ *
+ * Tell "initialize" uCode to go ahead and load the runtime uCode.
+*/
+static void iwl_init_alive_start(struct iwl_priv *priv)
+{
+	/* Check alive response for "valid" sign from uCode */
+	if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
+		/* We had an error bringing up the hardware, so take it
+		 * all the way back down so we can try again */
+		IWL_DEBUG_INFO("Initialize Alive failed.\n");
+		goto restart;
+	}
+
+	/* Bootstrap uCode has loaded initialize uCode ... verify inst image.
+	 * This is a paranoid check, because we would not have gotten the
+	 * "initialize" alive if code weren't properly loaded.  */
+	if (iwl_verify_ucode(priv)) {
+		/* Runtime instruction load was bad;
+		 * take it all the way back down so we can try again */
+		IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
+		goto restart;
+	}
+
+	/* Send pointers to protocol/runtime uCode image ... init code will
+	 * load and launch runtime uCode, which will send us another "Alive"
+	 * notification. */
+	IWL_DEBUG_INFO("Initialization Alive received.\n");
+	if (iwl_set_ucode_ptrs(priv)) {
+		/* Runtime instruction load won't happen;
+		 * take it all the way back down so we can try again */
+		IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n");
+		goto restart;
+	}
+	return;
+
+ restart:
+	queue_work(priv->workqueue, &priv->restart);
+}
+
+
+/**
+ * iwl_alive_start - called after REPLY_ALIVE notification received
+ *                   from protocol/runtime uCode (initialization uCode's
+ *                   Alive gets handled by iwl_init_alive_start()).
+ */
+static void iwl_alive_start(struct iwl_priv *priv)
+{
+	int rc = 0;
+	int thermal_spin = 0;
+	u32 rfkill;
+
+	IWL_DEBUG_INFO("Runtime Alive received.\n");
+
+	if (priv->card_alive.is_valid != UCODE_VALID_OK) {
+		/* We had an error bringing up the hardware, so take it
+		 * all the way back down so we can try again */
+		IWL_DEBUG_INFO("Alive failed.\n");
+		goto restart;
+	}
+
+	/* Initialize uCode has loaded Runtime uCode ... verify inst image.
+	 * This is a paranoid check, because we would not have gotten the
+	 * "runtime" alive if code weren't properly loaded.  */
+	if (iwl_verify_ucode(priv)) {
+		/* Runtime instruction load was bad;
+		 * take it all the way back down so we can try again */
+		IWL_DEBUG_INFO("Bad runtime uCode load.\n");
+		goto restart;
+	}
+
+	iwl_clear_stations_table(priv);
+
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		IWL_WARNING("Can not read rfkill status from adapter\n");
+		return;
+	}
+
+	rfkill = iwl_read_restricted_reg(priv, APMG_RFKILL_REG);
+	IWL_DEBUG_INFO("RFKILL status: 0x%x\n", rfkill);
+	iwl_release_restricted_access(priv);
+
+	if (rfkill & 0x1) {
+		clear_bit(STATUS_RF_KILL_HW, &priv->status);
+		/* if rfkill is not on, then wait for thermal
+		 * sensor in adapter to kick in */
+		while (iwl_hw_get_temperature(priv) == 0) {
+			thermal_spin++;
+			udelay(10);
+		}
+
+		if (thermal_spin)
+			IWL_DEBUG_INFO("Thermal calibration took %dus\n",
+				       thermal_spin * 10);
+	} else
+		set_bit(STATUS_RF_KILL_HW, &priv->status);
+
+	/* After the ALIVE response, we can process host commands */
+	set_bit(STATUS_ALIVE, &priv->status);
+
+	/* Clear out the uCode error bit if it is set */
+	clear_bit(STATUS_FW_ERROR, &priv->status);
+
+	rc = iwl_init_channel_map(priv);
+	if (rc) {
+		IWL_ERROR("initializing regulatory failed: %d\n", rc);
+		return;
+	}
+
+	iwl_init_geos(priv);
+
+	if (iwl_is_rfkill(priv))
+		return;
+
+	if (!priv->mac80211_registered) {
+		/* Unlock so any user space entry points can call back into
+		 * the driver without a deadlock... */
+		mutex_unlock(&priv->mutex);
+		iwl_rate_control_register(priv->hw);
+		rc = ieee80211_register_hw(priv->hw);
+		priv->hw->conf.beacon_int = 100;
+		mutex_lock(&priv->mutex);
+
+		if (rc) {
+			IWL_ERROR("Failed to register network "
+				  "device (error %d)\n", rc);
+			return;
+		}
+
+		priv->mac80211_registered = 1;
+
+		iwl_reset_channel_flag(priv);
+	} else
+		ieee80211_start_queues(priv->hw);
+
+	priv->active_rate = priv->rates_mask;
+	priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+
+	iwl_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode));
+
+	if (iwl_is_associated(priv)) {
+		struct iwl_rxon_cmd *active_rxon =
+				(struct iwl_rxon_cmd *)(&priv->active_rxon);
+
+		memcpy(&priv->staging_rxon, &priv->active_rxon,
+		       sizeof(priv->staging_rxon));
+		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	} else {
+		/* Initialize our rx_config data */
+		iwl_connection_init_rx_config(priv);
+		memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+	}
+
+	/* Configure BT coexistence */
+	iwl_send_bt_config(priv);
+
+	/* Configure the adapter for unassociated operation */
+	iwl_commit_rxon(priv);
+
+	/* At this point, the NIC is initialized and operational */
+	priv->notif_missed_beacons = 0;
+	set_bit(STATUS_READY, &priv->status);
+
+	iwl3945_reg_txpower_periodic(priv);
+
+	IWL_DEBUG_INFO("ALIVE processing complete.\n");
+
+	if (priv->error_recovering)
+		iwl_error_recovery(priv);
+
+	return;
+
+ restart:
+	queue_work(priv->workqueue, &priv->restart);
+}
+
+static void iwl_cancel_deferred_work(struct iwl_priv *priv);
+
+static void __iwl_down(struct iwl_priv *priv)
+{
+	unsigned long flags;
+	int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
+	struct ieee80211_conf *conf = NULL;
+
+	IWL_DEBUG_INFO(DRV_NAME " is going down\n");
+
+	conf = ieee80211_get_hw_conf(priv->hw);
+
+	if (!exit_pending)
+		set_bit(STATUS_EXIT_PENDING, &priv->status);
+
+	iwl_clear_stations_table(priv);
+
+	/* Unblock any waiting calls */
+	wake_up_interruptible_all(&priv->wait_command_queue);
+
+	iwl_cancel_deferred_work(priv);
+
+	/* Wipe out the EXIT_PENDING status bit if we are not actually
+	 * exiting the module */
+	if (!exit_pending)
+		clear_bit(STATUS_EXIT_PENDING, &priv->status);
+
+	/* stop and reset the on-board processor */
+	iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+
+	/* tell the device to stop sending interrupts */
+	iwl_disable_interrupts(priv);
+
+	if (priv->mac80211_registered)
+		ieee80211_stop_queues(priv->hw);
+
+	/* If we have not previously called iwl_init() then
+	 * clear all bits but the RF Kill and SUSPEND bits and return */
+	if (!iwl_is_init(priv)) {
+		priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+					STATUS_RF_KILL_HW |
+			       test_bit(STATUS_RF_KILL_SW, &priv->status) <<
+					STATUS_RF_KILL_SW |
+			       test_bit(STATUS_IN_SUSPEND, &priv->status) <<
+					STATUS_IN_SUSPEND;
+		goto exit;
+	}
+
+	/* ...otherwise clear out all the status bits but the RF Kill and
+	 * SUSPEND bits and continue taking the NIC down. */
+	priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+				STATUS_RF_KILL_HW |
+			test_bit(STATUS_RF_KILL_SW, &priv->status) <<
+				STATUS_RF_KILL_SW |
+			test_bit(STATUS_IN_SUSPEND, &priv->status) <<
+				STATUS_IN_SUSPEND |
+			test_bit(STATUS_FW_ERROR, &priv->status) <<
+				STATUS_FW_ERROR;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	iwl_hw_txq_ctx_stop(priv);
+	iwl_hw_rxq_stop(priv);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (!iwl_grab_restricted_access(priv)) {
+		iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG,
+					 APMG_CLK_VAL_DMA_CLK_RQT);
+		iwl_release_restricted_access(priv);
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	udelay(5);
+
+	iwl_hw_nic_stop_master(priv);
+	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+	iwl_hw_nic_reset(priv);
+
+ exit:
+	memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
+
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+	priv->ibss_beacon = NULL;
+
+	/* clear out any free frames */
+	iwl_clear_free_frames(priv);
+}
+
+static void iwl_down(struct iwl_priv *priv)
+{
+	mutex_lock(&priv->mutex);
+	__iwl_down(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+#define MAX_HW_RESTARTS 5
+
+static int __iwl_up(struct iwl_priv *priv)
+{
+	DECLARE_MAC_BUF(mac);
+	int rc, i;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+		IWL_WARNING("Exit pending; will not bring the NIC up\n");
+		return -EIO;
+	}
+
+	if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
+		IWL_WARNING("Radio disabled by SW RF kill (module "
+			    "parameter)\n");
+		return 0;
+	}
+
+	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+	rc = iwl_hw_nic_init(priv);
+	if (rc) {
+		IWL_ERROR("Unable to int nic\n");
+		return rc;
+	}
+
+	/* make sure rfkill handshake bits are cleared */
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+	/* clear (again), then enable host interrupts */
+	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+	iwl_enable_interrupts(priv);
+
+	/* really make sure rfkill handshake bits are cleared */
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+	/* Copy original ucode data image from disk into backup cache.
+	 * This will be used to initialize the on-board processor's
+	 * data SRAM for a clean start when the runtime program first loads. */
+	memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
+			priv->ucode_data.len);
+
+	for (i = 0; i < MAX_HW_RESTARTS; i++) {
+
+		iwl_clear_stations_table(priv);
+
+		/* load bootstrap state machine,
+		 * load bootstrap program into processor's memory,
+		 * prepare to load the "initialize" uCode */
+		rc = iwl_load_bsm(priv);
+
+		if (rc) {
+			IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc);
+			continue;
+		}
+
+		/* start card; "initialize" will load runtime ucode */
+		iwl_nic_start(priv);
+
+		/* MAC Address location in EEPROM same for 3945/4965 */
+		get_eeprom_mac(priv, priv->mac_addr);
+		IWL_DEBUG_INFO("MAC address: %s\n",
+			       print_mac(mac, priv->mac_addr));
+
+		SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+
+		IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
+
+		return 0;
+	}
+
+	set_bit(STATUS_EXIT_PENDING, &priv->status);
+	__iwl_down(priv);
+
+	/* tried to restart and config the device for as long as our
+	 * patience could withstand */
+	IWL_ERROR("Unable to initialize device after %d attempts.\n", i);
+	return -EIO;
+}
+
+
+/*****************************************************************************
+ *
+ * Workqueue callbacks
+ *
+ *****************************************************************************/
+
+static void iwl_bg_init_alive_start(struct work_struct *data)
+{
+	struct iwl_priv *priv =
+	    container_of(data, struct iwl_priv, init_alive_start.work);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	iwl_init_alive_start(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_alive_start(struct work_struct *data)
+{
+	struct iwl_priv *priv =
+	    container_of(data, struct iwl_priv, alive_start.work);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	iwl_alive_start(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_rf_kill(struct work_struct *work)
+{
+	struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill);
+
+	wake_up_interruptible(&priv->wait_command_queue);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+
+	if (!iwl_is_rfkill(priv)) {
+		IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL,
+			  "HW and/or SW RF Kill no longer active, restarting "
+			  "device\n");
+		if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+			queue_work(priv->workqueue, &priv->restart);
+	} else {
+
+		if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
+			IWL_DEBUG_RF_KILL("Can not turn radio back on - "
+					  "disabled by SW switch\n");
+		else
+			IWL_WARNING("Radio Frequency Kill Switch is On:\n"
+				    "Kill switch must be turned off for "
+				    "wireless networking to work.\n");
+	}
+	mutex_unlock(&priv->mutex);
+}
+
+#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
+
+static void iwl_bg_scan_check(struct work_struct *data)
+{
+	struct iwl_priv *priv =
+	    container_of(data, struct iwl_priv, scan_check.work);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	if (test_bit(STATUS_SCANNING, &priv->status) ||
+	    test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN,
+			  "Scan completion watchdog resetting adapter (%dms)\n",
+			  jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
+		if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+			queue_work(priv->workqueue, &priv->restart);
+	}
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_request_scan(struct work_struct *data)
+{
+	struct iwl_priv *priv =
+	    container_of(data, struct iwl_priv, request_scan);
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_SCAN_CMD,
+		.len = sizeof(struct iwl_scan_cmd),
+		.meta.flags = CMD_SIZE_HUGE,
+	};
+	int rc = 0;
+	struct iwl_scan_cmd *scan;
+	struct ieee80211_conf *conf = NULL;
+	u8 direct_mask;
+	int phymode;
+
+	conf = ieee80211_get_hw_conf(priv->hw);
+
+	mutex_lock(&priv->mutex);
+
+	if (!iwl_is_ready(priv)) {
+		IWL_WARNING("request scan called when driver not ready.\n");
+		goto done;
+	}
+
+	/* Make sure the scan wasn't cancelled before this queued work
+	 * was given the chance to run... */
+	if (!test_bit(STATUS_SCANNING, &priv->status))
+		goto done;
+
+	/* This should never be called or scheduled if there is currently
+	 * a scan active in the hardware. */
+	if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+		IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. "
+			       "Ignoring second request.\n");
+		rc = -EIO;
+		goto done;
+	}
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+		IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n");
+		goto done;
+	}
+
+	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG_HC("Scan request while abort pending.  Queuing.\n");
+		goto done;
+	}
+
+	if (iwl_is_rfkill(priv)) {
+		IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n");
+		goto done;
+	}
+
+	if (!test_bit(STATUS_READY, &priv->status)) {
+		IWL_DEBUG_HC("Scan request while uninitialized.  Queuing.\n");
+		goto done;
+	}
+
+	if (!priv->scan_bands) {
+		IWL_DEBUG_HC("Aborting scan due to no requested bands\n");
+		goto done;
+	}
+
+	if (!priv->scan) {
+		priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) +
+				     IWL_MAX_SCAN_SIZE, GFP_KERNEL);
+		if (!priv->scan) {
+			rc = -ENOMEM;
+			goto done;
+		}
+	}
+	scan = priv->scan;
+	memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
+
+	scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
+	scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
+
+	if (iwl_is_associated(priv)) {
+		u16 interval = 0;
+		u32 extra;
+		u32 suspend_time = 100;
+		u32 scan_suspend_time = 100;
+		unsigned long flags;
+
+		IWL_DEBUG_INFO("Scanning while associated...\n");
+
+		spin_lock_irqsave(&priv->lock, flags);
+		interval = priv->beacon_int;
+		spin_unlock_irqrestore(&priv->lock, flags);
+
+		scan->suspend_time = 0;
+		scan->max_out_time = cpu_to_le32(600 * 1024);
+		if (!interval)
+			interval = suspend_time;
+		/*
+		 * suspend time format:
+		 *  0-19: beacon interval in usec (time before exec.)
+		 * 20-23: 0
+		 * 24-31: number of beacons (suspend between channels)
+		 */
+
+		extra = (suspend_time / interval) << 24;
+		scan_suspend_time = 0xFF0FFFFF &
+		    (extra | ((suspend_time % interval) * 1024));
+
+		scan->suspend_time = cpu_to_le32(scan_suspend_time);
+		IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n",
+			       scan_suspend_time, interval);
+	}
+
+	/* We should add the ability for user to lock to PASSIVE ONLY */
+	if (priv->one_direct_scan) {
+		IWL_DEBUG_SCAN
+		    ("Kicking off one direct scan for '%s'\n",
+		     iwl_escape_essid(priv->direct_ssid,
+				      priv->direct_ssid_len));
+		scan->direct_scan[0].id = WLAN_EID_SSID;
+		scan->direct_scan[0].len = priv->direct_ssid_len;
+		memcpy(scan->direct_scan[0].ssid,
+		       priv->direct_ssid, priv->direct_ssid_len);
+		direct_mask = 1;
+	} else if (!iwl_is_associated(priv)) {
+		scan->direct_scan[0].id = WLAN_EID_SSID;
+		scan->direct_scan[0].len = priv->essid_len;
+		memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
+		direct_mask = 1;
+	} else
+		direct_mask = 0;
+
+	/* We don't build a direct scan probe request; the uCode will do
+	 * that based on the direct_mask added to each channel entry */
+	scan->tx_cmd.len = cpu_to_le16(
+		iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
+			IWL_MAX_SCAN_SIZE - sizeof(scan), 0));
+	scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
+	scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
+	scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+	/* flags + rate selection */
+
+	switch (priv->scan_bands) {
+	case 2:
+		scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
+		scan->tx_cmd.rate = IWL_RATE_1M_PLCP;
+		scan->good_CRC_th = 0;
+		phymode = MODE_IEEE80211G;
+		break;
+
+	case 1:
+		scan->tx_cmd.rate = IWL_RATE_6M_PLCP;
+		scan->good_CRC_th = IWL_GOOD_CRC_TH;
+		phymode = MODE_IEEE80211A;
+		break;
+
+	default:
+		IWL_WARNING("Invalid scan band count\n");
+		goto done;
+	}
+
+	/* select Rx antennas */
+	scan->flags |= iwl3945_get_antenna_flags(priv);
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR)
+		scan->filter_flags = RXON_FILTER_PROMISC_MSK;
+
+	if (direct_mask)
+		IWL_DEBUG_SCAN
+		    ("Initiating direct scan for %s.\n",
+		     iwl_escape_essid(priv->essid, priv->essid_len));
+	else
+		IWL_DEBUG_SCAN("Initiating indirect scan.\n");
+
+	scan->channel_count =
+		iwl_get_channels_for_scan(
+			priv, phymode, 1, /* active */
+			direct_mask,
+			(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+
+	cmd.len += le16_to_cpu(scan->tx_cmd.len) +
+	    scan->channel_count * sizeof(struct iwl_scan_channel);
+	cmd.data = scan;
+	scan->len = cpu_to_le16(cmd.len);
+
+	set_bit(STATUS_SCAN_HW, &priv->status);
+	rc = iwl_send_cmd_sync(priv, &cmd);
+	if (rc)
+		goto done;
+
+	queue_delayed_work(priv->workqueue, &priv->scan_check,
+			   IWL_SCAN_CHECK_WATCHDOG);
+
+	mutex_unlock(&priv->mutex);
+	return;
+
+ done:
+	/* inform mac80211 sacn aborted */
+	queue_work(priv->workqueue, &priv->scan_completed);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_up(struct work_struct *data)
+{
+	struct iwl_priv *priv = container_of(data, struct iwl_priv, up);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	__iwl_up(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_restart(struct work_struct *data)
+{
+	struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	iwl_down(priv);
+	queue_work(priv->workqueue, &priv->up);
+}
+
+static void iwl_bg_rx_replenish(struct work_struct *data)
+{
+	struct iwl_priv *priv =
+	    container_of(data, struct iwl_priv, rx_replenish);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	iwl_rx_replenish(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_post_associate(struct work_struct *data)
+{
+	struct iwl_priv *priv = container_of(data, struct iwl_priv,
+					     post_associate.work);
+
+	int rc = 0;
+	struct ieee80211_conf *conf = NULL;
+	DECLARE_MAC_BUF(mac);
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__);
+		return;
+	}
+
+
+	IWL_DEBUG_ASSOC("Associated as %d to: %s\n",
+			priv->assoc_id,
+			print_mac(mac, priv->active_rxon.bssid_addr));
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+
+	conf = ieee80211_get_hw_conf(priv->hw);
+
+	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	iwl_commit_rxon(priv);
+
+	memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
+	iwl_setup_rxon_timing(priv);
+	rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+			      sizeof(priv->rxon_timing), &priv->rxon_timing);
+	if (rc)
+		IWL_WARNING("REPLY_RXON_TIMING failed - "
+			    "Attempting to continue.\n");
+
+	priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+
+	priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+
+	IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n",
+			priv->assoc_id, priv->beacon_int);
+
+	if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+	else
+		priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+	if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+		else
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+		if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+	}
+
+	iwl_commit_rxon(priv);
+
+	switch (priv->iw_mode) {
+	case IEEE80211_IF_TYPE_STA:
+		iwl_rate_scale_init(priv->hw, IWL_AP_ID);
+		break;
+
+	case IEEE80211_IF_TYPE_IBSS:
+
+		/* clear out the station table */
+		iwl_clear_stations_table(priv);
+
+		iwl_add_station(priv, BROADCAST_ADDR, 0, 0);
+		iwl_add_station(priv, priv->bssid, 0, 0);
+		iwl3945_sync_sta(priv, IWL_STA_ID,
+				 (priv->phymode == MODE_IEEE80211A)?
+				 IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
+				 CMD_ASYNC);
+		iwl_rate_scale_init(priv->hw, IWL_STA_ID);
+		iwl_send_beacon_cmd(priv);
+
+		break;
+
+	default:
+		 IWL_ERROR("%s Should not be called in %d mode\n",
+				__FUNCTION__, priv->iw_mode);
+		break;
+	}
+
+	iwl_sequence_reset(priv);
+
+#ifdef CONFIG_IWLWIFI_QOS
+	iwl_activate_qos(priv, 0);
+#endif /* CONFIG_IWLWIFI_QOS */
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_abort_scan(struct work_struct *work)
+{
+	struct iwl_priv *priv = container_of(work, struct iwl_priv,
+					     abort_scan);
+
+	if (!iwl_is_ready(priv))
+		return;
+
+	mutex_lock(&priv->mutex);
+
+	set_bit(STATUS_SCAN_ABORTING, &priv->status);
+	iwl_send_scan_abort(priv);
+
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_scan_completed(struct work_struct *work)
+{
+	struct iwl_priv *priv =
+	    container_of(work, struct iwl_priv, scan_completed);
+
+	IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n");
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	ieee80211_scan_completed(priv->hw);
+
+	/* Since setting the TXPOWER may have been deferred while
+	 * performing the scan, fire one off */
+	mutex_lock(&priv->mutex);
+	iwl_hw_reg_send_txpower(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+/*****************************************************************************
+ *
+ * mac80211 entry point functions
+ *
+ *****************************************************************************/
+
+static int iwl_mac_start(struct ieee80211_hw *hw)
+{
+	struct iwl_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	/* we should be verifying the device is ready to be opened */
+	mutex_lock(&priv->mutex);
+
+	priv->is_open = 1;
+
+	if (!iwl_is_rfkill(priv))
+		ieee80211_start_queues(priv->hw);
+
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211("leave\n");
+	return 0;
+}
+
+static void iwl_mac_stop(struct ieee80211_hw *hw)
+{
+	struct iwl_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+	priv->is_open = 0;
+	/*netif_stop_queue(dev); */
+	flush_workqueue(priv->workqueue);
+	IWL_DEBUG_MAC80211("leave\n");
+}
+
+static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+		      struct ieee80211_tx_control *ctl)
+{
+	struct iwl_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+		IWL_DEBUG_MAC80211("leave - monitor\n");
+		return -1;
+	}
+
+	IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
+		     ctl->tx_rate);
+
+	if (iwl_tx_skb(priv, skb, ctl))
+		dev_kfree_skb_any(skb);
+
+	IWL_DEBUG_MAC80211("leave\n");
+	return 0;
+}
+
+static int iwl_mac_add_interface(struct ieee80211_hw *hw,
+				 struct ieee80211_if_init_conf *conf)
+{
+	struct iwl_priv *priv = hw->priv;
+	unsigned long flags;
+	DECLARE_MAC_BUF(mac);
+
+	IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type);
+	if (conf->mac_addr)
+		IWL_DEBUG_MAC80211("enter: MAC %s\n",
+				   print_mac(mac, conf->mac_addr));
+
+	if (priv->interface_id) {
+		IWL_DEBUG_MAC80211("leave - interface_id != 0\n");
+		return 0;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->interface_id = conf->if_id;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	mutex_lock(&priv->mutex);
+	iwl_set_mode(priv, conf->type);
+
+	IWL_DEBUG_MAC80211("leave\n");
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+/**
+ * iwl_mac_config - mac80211 config callback
+ *
+ * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
+ * be set inappropriately and the driver currently sets the hardware up to
+ * use it whenever needed.
+ */
+static int iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+{
+	struct iwl_priv *priv = hw->priv;
+	const struct iwl_channel_info *ch_info;
+	unsigned long flags;
+
+	mutex_lock(&priv->mutex);
+	IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel);
+
+	if (!iwl_is_ready(priv)) {
+		IWL_DEBUG_MAC80211("leave - not ready\n");
+		mutex_unlock(&priv->mutex);
+		return -EIO;
+	}
+
+	/* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only
+	 * what is exposed through include/ declrations */
+	if (unlikely(!iwl_param_disable_hw_scan &&
+		     test_bit(STATUS_SCANNING, &priv->status))) {
+		IWL_DEBUG_MAC80211("leave - scanning\n");
+		mutex_unlock(&priv->mutex);
+		return 0;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	ch_info = iwl_get_channel_info(priv, conf->phymode, conf->channel);
+	if (!is_channel_valid(ch_info)) {
+		IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n",
+			       conf->channel, conf->phymode);
+		IWL_DEBUG_MAC80211("leave - invalid channel\n");
+		spin_unlock_irqrestore(&priv->lock, flags);
+		mutex_unlock(&priv->mutex);
+		return -EINVAL;
+	}
+
+	iwl_set_rxon_channel(priv, conf->phymode, conf->channel);
+
+	iwl_set_flags_for_phymode(priv, conf->phymode);
+
+	/* The list of supported rates and rate mask can be different
+	 * for each phymode; since the phymode may have changed, reset
+	 * the rate mask to what mac80211 lists */
+	iwl_set_rate(priv);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+#ifdef IEEE80211_CONF_CHANNEL_SWITCH
+	if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) {
+		iwl_hw_channel_switch(priv, conf->channel);
+		mutex_unlock(&priv->mutex);
+		return 0;
+	}
+#endif
+
+	iwl_radio_kill_sw(priv, !conf->radio_enabled);
+
+	if (!conf->radio_enabled) {
+		IWL_DEBUG_MAC80211("leave - radio disabled\n");
+		mutex_unlock(&priv->mutex);
+		return 0;
+	}
+
+	if (iwl_is_rfkill(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF kill\n");
+		mutex_unlock(&priv->mutex);
+		return -EIO;
+	}
+
+	iwl_set_rate(priv);
+
+	if (memcmp(&priv->active_rxon,
+		   &priv->staging_rxon, sizeof(priv->staging_rxon)))
+		iwl_commit_rxon(priv);
+	else
+		IWL_DEBUG_INFO("No re-sending same RXON configuration.\n");
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+static void iwl_config_ap(struct iwl_priv *priv)
+{
+	int rc = 0;
+
+	if (priv->status & STATUS_EXIT_PENDING)
+		return;
+
+	/* The following should be done only at AP bring up */
+	if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) {
+
+		/* RXON - unassoc (to set timing command) */
+		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+		iwl_commit_rxon(priv);
+
+		/* RXON Timing */
+		memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
+		iwl_setup_rxon_timing(priv);
+		rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+				sizeof(priv->rxon_timing), &priv->rxon_timing);
+		if (rc)
+			IWL_WARNING("REPLY_RXON_TIMING failed - "
+					"Attempting to continue.\n");
+
+		/* FIXME: what should be the assoc_id for AP? */
+		priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+			priv->staging_rxon.flags |=
+				RXON_FLG_SHORT_PREAMBLE_MSK;
+		else
+			priv->staging_rxon.flags &=
+				~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+		if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+			if (priv->assoc_capability &
+				WLAN_CAPABILITY_SHORT_SLOT_TIME)
+				priv->staging_rxon.flags |=
+					RXON_FLG_SHORT_SLOT_MSK;
+			else
+				priv->staging_rxon.flags &=
+					~RXON_FLG_SHORT_SLOT_MSK;
+
+			if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+				priv->staging_rxon.flags &=
+					~RXON_FLG_SHORT_SLOT_MSK;
+		}
+		/* restore RXON assoc */
+		priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+		iwl_commit_rxon(priv);
+		iwl_add_station(priv, BROADCAST_ADDR, 0, 0);
+	}
+	iwl_send_beacon_cmd(priv);
+
+	/* FIXME - we need to add code here to detect a totally new
+	 * configuration, reset the AP, unassoc, rxon timing, assoc,
+	 * clear sta table, add BCAST sta... */
+}
+
+static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+				    struct ieee80211_if_conf *conf)
+{
+	struct iwl_priv *priv = hw->priv;
+	DECLARE_MAC_BUF(mac);
+	unsigned long flags;
+	int rc;
+
+	if (conf == NULL)
+		return -EIO;
+
+	/* XXX: this MUST use conf->mac_addr */
+
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+	    (!conf->beacon || !conf->ssid_len)) {
+		IWL_DEBUG_MAC80211
+		    ("Leaving in AP mode because HostAPD is not ready.\n");
+		return 0;
+	}
+
+	mutex_lock(&priv->mutex);
+
+	IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id);
+	if (conf->bssid)
+		IWL_DEBUG_MAC80211("bssid: %s\n",
+				   print_mac(mac, conf->bssid));
+
+/*
+ * very dubious code was here; the probe filtering flag is never set:
+ *
+	if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) &&
+	    !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
+ */
+	if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
+		IWL_DEBUG_MAC80211("leave - scanning\n");
+		mutex_unlock(&priv->mutex);
+		return 0;
+	}
+
+	if (priv->interface_id != if_id) {
+		IWL_DEBUG_MAC80211("leave - interface_id != if_id\n");
+		mutex_unlock(&priv->mutex);
+		return 0;
+	}
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		if (!conf->bssid) {
+			conf->bssid = priv->mac_addr;
+			memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
+			IWL_DEBUG_MAC80211("bssid was set to: %s\n",
+					   print_mac(mac, conf->bssid));
+		}
+		if (priv->ibss_beacon)
+			dev_kfree_skb(priv->ibss_beacon);
+
+		priv->ibss_beacon = conf->beacon;
+	}
+
+	if (conf->bssid && !is_zero_ether_addr(conf->bssid) &&
+	    !is_multicast_ether_addr(conf->bssid)) {
+		/* If there is currently a HW scan going on in the background
+		 * then we need to cancel it else the RXON below will fail. */
+		if (iwl_scan_cancel_timeout(priv, 100)) {
+			IWL_WARNING("Aborted scan still in progress "
+				    "after 100ms\n");
+			IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
+			mutex_unlock(&priv->mutex);
+			return -EAGAIN;
+		}
+		memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN);
+
+		/* TODO: Audit driver for usage of these members and see
+		 * if mac80211 deprecates them (priv->bssid looks like it
+		 * shouldn't be there, but I haven't scanned the IBSS code
+		 * to verify) - jpk */
+		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+
+		if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+			iwl_config_ap(priv);
+		else {
+			priv->staging_rxon.filter_flags |=
+						RXON_FILTER_ASSOC_MSK;
+			rc = iwl_commit_rxon(priv);
+			if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc)
+				iwl_add_station(priv,
+					priv->active_rxon.bssid_addr, 1, 0);
+		}
+
+	} else {
+		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+		iwl_commit_rxon(priv);
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (!conf->ssid_len)
+		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
+	else
+		memcpy(priv->essid, conf->ssid, conf->ssid_len);
+
+	priv->essid_len = conf->ssid_len;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	IWL_DEBUG_MAC80211("leave\n");
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+static void iwl_configure_filter(struct ieee80211_hw *hw,
+				 unsigned int changed_flags,
+				 unsigned int *total_flags,
+				 int mc_count, struct dev_addr_list *mc_list)
+{
+	/*
+	 * XXX: dummy
+	 * see also iwl_connection_init_rx_config
+	 */
+	*total_flags = 0;
+}
+
+static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
+				     struct ieee80211_if_init_conf *conf)
+{
+	struct iwl_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	mutex_lock(&priv->mutex);
+	if (priv->interface_id == conf->if_id) {
+		priv->interface_id = 0;
+		memset(priv->bssid, 0, ETH_ALEN);
+		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
+		priv->essid_len = 0;
+	}
+	mutex_unlock(&priv->mutex);
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+}
+
+#define IWL_DELAY_NEXT_SCAN (HZ*2)
+static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
+{
+	int rc = 0;
+	unsigned long flags;
+	struct iwl_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (!iwl_is_ready_rf(priv)) {
+		rc = -EIO;
+		IWL_DEBUG_MAC80211("leave - not ready or exit pending\n");
+		goto out_unlock;
+	}
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {	/* APs don't scan */
+		rc = -EIO;
+		IWL_ERROR("ERROR: APs don't scan\n");
+		goto out_unlock;
+	}
+
+	/* if we just finished scan ask for delay */
+	if (priv->last_scan_jiffies &&
+	    time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN,
+		       jiffies)) {
+		rc = -EAGAIN;
+		goto out_unlock;
+	}
+	if (len) {
+		IWL_DEBUG_SCAN("direct scan for  "
+			       "%s [%d]\n ",
+			       iwl_escape_essid(ssid, len), (int)len);
+
+		priv->one_direct_scan = 1;
+		priv->direct_ssid_len = (u8)
+		    min((u8) len, (u8) IW_ESSID_MAX_SIZE);
+		memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
+	}
+
+	rc = iwl_scan_initiate(priv);
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+out_unlock:
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return rc;
+}
+
+static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+			   const u8 *local_addr, const u8 *addr,
+			   struct ieee80211_key_conf *key)
+{
+	struct iwl_priv *priv = hw->priv;
+	int rc = 0;
+	u8 sta_id;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (!iwl_param_hwcrypto) {
+		IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (is_zero_ether_addr(addr))
+		/* only support pairwise keys */
+		return -EOPNOTSUPP;
+
+	sta_id = iwl_hw_find_station(priv, addr);
+	if (sta_id == IWL_INVALID_STATION) {
+		DECLARE_MAC_BUF(mac);
+
+		IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
+				   print_mac(mac, addr));
+		return -EINVAL;
+	}
+
+	mutex_lock(&priv->mutex);
+
+	switch (cmd) {
+	case  SET_KEY:
+		rc = iwl_update_sta_key_info(priv, key, sta_id);
+		if (!rc) {
+			iwl_set_rxon_hwcrypto(priv, 1);
+			iwl_commit_rxon(priv);
+			key->hw_key_idx = sta_id;
+			IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n");
+			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+		}
+		break;
+	case DISABLE_KEY:
+		rc = iwl_clear_sta_key_info(priv, sta_id);
+		if (!rc) {
+			iwl_set_rxon_hwcrypto(priv, 0);
+			iwl_commit_rxon(priv);
+			IWL_DEBUG_MAC80211("disable hwcrypto key\n");
+		}
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	IWL_DEBUG_MAC80211("leave\n");
+	mutex_unlock(&priv->mutex);
+
+	return rc;
+}
+
+static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+			   const struct ieee80211_tx_queue_params *params)
+{
+	struct iwl_priv *priv = hw->priv;
+#ifdef CONFIG_IWLWIFI_QOS
+	unsigned long flags;
+	int q;
+#endif /* CONFIG_IWL_QOS */
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (!iwl_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF not ready\n");
+		return -EIO;
+	}
+
+	if (queue >= AC_NUM) {
+		IWL_DEBUG_MAC80211("leave - queue >= AC_NUM %d\n", queue);
+		return 0;
+	}
+
+#ifdef CONFIG_IWLWIFI_QOS
+	if (!priv->qos_data.qos_enable) {
+		priv->qos_data.qos_active = 0;
+		IWL_DEBUG_MAC80211("leave - qos not enabled\n");
+		return 0;
+	}
+	q = AC_NUM - 1 - queue;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min);
+	priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max);
+	priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+	priv->qos_data.def_qos_parm.ac[q].edca_txop =
+			cpu_to_le16((params->burst_time * 100));
+
+	priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+	priv->qos_data.qos_active = 1;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	mutex_lock(&priv->mutex);
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+		iwl_activate_qos(priv, 1);
+	else if (priv->assoc_id && iwl_is_associated(priv))
+		iwl_activate_qos(priv, 0);
+
+	mutex_unlock(&priv->mutex);
+
+#endif /*CONFIG_IWLWIFI_QOS */
+
+	IWL_DEBUG_MAC80211("leave\n");
+	return 0;
+}
+
+static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
+				struct ieee80211_tx_queue_stats *stats)
+{
+	struct iwl_priv *priv = hw->priv;
+	int i, avail;
+	struct iwl_tx_queue *txq;
+	struct iwl_queue *q;
+	unsigned long flags;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (!iwl_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF not ready\n");
+		return -EIO;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	for (i = 0; i < AC_NUM; i++) {
+		txq = &priv->txq[i];
+		q = &txq->q;
+		avail = iwl_queue_space(q);
+
+		stats->data[i].len = q->n_window - avail;
+		stats->data[i].limit = q->n_window - q->high_mark;
+		stats->data[i].count = q->n_window;
+
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+	return 0;
+}
+
+static int iwl_mac_get_stats(struct ieee80211_hw *hw,
+			     struct ieee80211_low_level_stats *stats)
+{
+	IWL_DEBUG_MAC80211("enter\n");
+	IWL_DEBUG_MAC80211("leave\n");
+
+	return 0;
+}
+
+static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw)
+{
+	IWL_DEBUG_MAC80211("enter\n");
+	IWL_DEBUG_MAC80211("leave\n");
+
+	return 0;
+}
+
+static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
+{
+	struct iwl_priv *priv = hw->priv;
+	unsigned long flags;
+
+	mutex_lock(&priv->mutex);
+	IWL_DEBUG_MAC80211("enter\n");
+
+#ifdef CONFIG_IWLWIFI_QOS
+	iwl_reset_qos(priv);
+#endif
+	cancel_delayed_work(&priv->post_associate);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->assoc_id = 0;
+	priv->assoc_capability = 0;
+	priv->call_post_assoc_from_beacon = 0;
+
+	/* new association get rid of ibss beacon skb */
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+
+	priv->ibss_beacon = NULL;
+
+	priv->beacon_int = priv->hw->conf.beacon_int;
+	priv->timestamp1 = 0;
+	priv->timestamp0 = 0;
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_STA))
+		priv->beacon_int = 0;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	/* Per mac80211.h: This is only used in IBSS mode... */
+	if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+		IWL_DEBUG_MAC80211("leave - not in IBSS\n");
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+
+	if (!iwl_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - not ready\n");
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+
+	priv->only_active_channel = 0;
+
+	iwl_set_rate(priv);
+
+	mutex_unlock(&priv->mutex);
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+}
+
+static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+				 struct ieee80211_tx_control *control)
+{
+	struct iwl_priv *priv = hw->priv;
+	unsigned long flags;
+
+	mutex_lock(&priv->mutex);
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (!iwl_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF not ready\n");
+		mutex_unlock(&priv->mutex);
+		return -EIO;
+	}
+
+	if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+		IWL_DEBUG_MAC80211("leave - not IBSS\n");
+		mutex_unlock(&priv->mutex);
+		return -EIO;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+
+	priv->ibss_beacon = skb;
+
+	priv->assoc_id = 0;
+
+	IWL_DEBUG_MAC80211("leave\n");
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+#ifdef CONFIG_IWLWIFI_QOS
+	iwl_reset_qos(priv);
+#endif
+
+	queue_work(priv->workqueue, &priv->post_associate.work);
+
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+/*****************************************************************************
+ *
+ * sysfs attributes
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+
+/*
+ * The following adds a new attribute to the sysfs representation
+ * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/)
+ * used for controlling the debug level.
+ *
+ * See the level definitions in iwl for details.
+ */
+
+static ssize_t show_debug_level(struct device_driver *d, char *buf)
+{
+	return sprintf(buf, "0x%08X\n", iwl_debug_level);
+}
+static ssize_t store_debug_level(struct device_driver *d,
+				 const char *buf, size_t count)
+{
+	char *p = (char *)buf;
+	u32 val;
+
+	val = simple_strtoul(p, &p, 0);
+	if (p == buf)
+		printk(KERN_INFO DRV_NAME
+		       ": %s is not in hex or decimal form.\n", buf);
+	else
+		iwl_debug_level = val;
+
+	return strnlen(buf, count);
+}
+
+static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
+		   show_debug_level, store_debug_level);
+
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+static ssize_t show_rf_kill(struct device *d,
+			    struct device_attribute *attr, char *buf)
+{
+	/*
+	 * 0 - RF kill not enabled
+	 * 1 - SW based RF kill active (sysfs)
+	 * 2 - HW based RF kill active
+	 * 3 - Both HW and SW based RF kill active
+	 */
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) |
+		  (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0);
+
+	return sprintf(buf, "%i\n", val);
+}
+
+static ssize_t store_rf_kill(struct device *d,
+			     struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+	mutex_lock(&priv->mutex);
+	iwl_radio_kill_sw(priv, buf[0] == '1');
+	mutex_unlock(&priv->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
+
+static ssize_t show_temperature(struct device *d,
+				struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	return sprintf(buf, "%d\n", iwl_hw_get_temperature(priv));
+}
+
+static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
+
+static ssize_t show_rs_window(struct device *d,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	struct iwl_priv *priv = d->driver_data;
+	return iwl_fill_rs_info(priv->hw, buf, IWL_AP_ID);
+}
+static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL);
+
+static ssize_t show_tx_power(struct device *d,
+			     struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	return sprintf(buf, "%d\n", priv->user_txpower_limit);
+}
+
+static ssize_t store_tx_power(struct device *d,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	char *p = (char *)buf;
+	u32 val;
+
+	val = simple_strtoul(p, &p, 10);
+	if (p == buf)
+		printk(KERN_INFO DRV_NAME
+		       ": %s is not in decimal form.\n", buf);
+	else
+		iwl_hw_reg_set_txpower(priv, val);
+
+	return count;
+}
+
+static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
+
+static ssize_t show_flags(struct device *d,
+			  struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+	return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
+}
+
+static ssize_t store_flags(struct device *d,
+			   struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	u32 flags = simple_strtoul(buf, NULL, 0);
+
+	mutex_lock(&priv->mutex);
+	if (le32_to_cpu(priv->staging_rxon.flags) != flags) {
+		/* Cancel any currently running scans... */
+		if (iwl_scan_cancel_timeout(priv, 100))
+			IWL_WARNING("Could not cancel scan.\n");
+		else {
+			IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n",
+				       flags);
+			priv->staging_rxon.flags = cpu_to_le32(flags);
+			iwl_commit_rxon(priv);
+		}
+	}
+	mutex_unlock(&priv->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags);
+
+static ssize_t show_filter_flags(struct device *d,
+				 struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+	return sprintf(buf, "0x%04X\n",
+		le32_to_cpu(priv->active_rxon.filter_flags));
+}
+
+static ssize_t store_filter_flags(struct device *d,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	u32 filter_flags = simple_strtoul(buf, NULL, 0);
+
+	mutex_lock(&priv->mutex);
+	if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) {
+		/* Cancel any currently running scans... */
+		if (iwl_scan_cancel_timeout(priv, 100))
+			IWL_WARNING("Could not cancel scan.\n");
+		else {
+			IWL_DEBUG_INFO("Committing rxon.filter_flags = "
+				       "0x%04X\n", filter_flags);
+			priv->staging_rxon.filter_flags =
+				cpu_to_le32(filter_flags);
+			iwl_commit_rxon(priv);
+		}
+	}
+	mutex_unlock(&priv->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
+		   store_filter_flags);
+
+static ssize_t show_tune(struct device *d,
+			 struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+	return sprintf(buf, "0x%04X\n",
+		       (priv->phymode << 8) |
+			le16_to_cpu(priv->active_rxon.channel));
+}
+
+static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode);
+
+static ssize_t store_tune(struct device *d,
+			  struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	char *p = (char *)buf;
+	u16 tune = simple_strtoul(p, &p, 0);
+	u8 phymode = (tune >> 8) & 0xff;
+	u16 channel = tune & 0xff;
+
+	IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel);
+
+	mutex_lock(&priv->mutex);
+	if ((le16_to_cpu(priv->staging_rxon.channel) != channel) ||
+	    (priv->phymode != phymode)) {
+		const struct iwl_channel_info *ch_info;
+
+		ch_info = iwl_get_channel_info(priv, phymode, channel);
+		if (!ch_info) {
+			IWL_WARNING("Requested invalid phymode/channel "
+				    "combination: %d %d\n", phymode, channel);
+			mutex_unlock(&priv->mutex);
+			return -EINVAL;
+		}
+
+		/* Cancel any currently running scans... */
+		if (iwl_scan_cancel_timeout(priv, 100))
+			IWL_WARNING("Could not cancel scan.\n");
+		else {
+			IWL_DEBUG_INFO("Committing phymode and "
+				       "rxon.channel = %d %d\n",
+				       phymode, channel);
+
+			iwl_set_rxon_channel(priv, phymode, channel);
+			iwl_set_flags_for_phymode(priv, phymode);
+
+			iwl_set_rate(priv);
+			iwl_commit_rxon(priv);
+		}
+	}
+	mutex_unlock(&priv->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune);
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+
+static ssize_t show_measurement(struct device *d,
+				struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl_spectrum_notification measure_report;
+	u32 size = sizeof(measure_report), len = 0, ofs = 0;
+	u8 *data = (u8 *) & measure_report;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (!(priv->measurement_status & MEASUREMENT_READY)) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return 0;
+	}
+	memcpy(&measure_report, &priv->measure_report, size);
+	priv->measurement_status = 0;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	while (size && (PAGE_SIZE - len)) {
+		hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
+				   PAGE_SIZE - len, 1);
+		len = strlen(buf);
+		if (PAGE_SIZE - len)
+			buf[len++] = '\n';
+
+		ofs += 16;
+		size -= min(size, 16U);
+	}
+
+	return len;
+}
+
+static ssize_t store_measurement(struct device *d,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct ieee80211_measurement_params params = {
+		.channel = le16_to_cpu(priv->active_rxon.channel),
+		.start_time = cpu_to_le64(priv->last_tsf),
+		.duration = cpu_to_le16(1),
+	};
+	u8 type = IWL_MEASURE_BASIC;
+	u8 buffer[32];
+	u8 channel;
+
+	if (count) {
+		char *p = buffer;
+		strncpy(buffer, buf, min(sizeof(buffer), count));
+		channel = simple_strtoul(p, NULL, 0);
+		if (channel)
+			params.channel = channel;
+
+		p = buffer;
+		while (*p && *p != ' ')
+			p++;
+		if (*p)
+			type = simple_strtoul(p + 1, NULL, 0);
+	}
+
+	IWL_DEBUG_INFO("Invoking measurement of type %d on "
+		       "channel %d (for '%s')\n", type, params.channel, buf);
+	iwl_get_measurement(priv, &params, type);
+
+	return count;
+}
+
+static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR,
+		   show_measurement, store_measurement);
+#endif /* CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT */
+
+static ssize_t show_rate(struct device *d,
+			 struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	if (priv->iw_mode == IEEE80211_IF_TYPE_STA)
+		i = priv->stations[IWL_AP_ID].current_rate.s.rate;
+	else
+		i = priv->stations[IWL_STA_ID].current_rate.s.rate;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	i = iwl_rate_index_from_plcp(i);
+	if (i == -1)
+		return sprintf(buf, "0\n");
+
+	return sprintf(buf, "%d%s\n",
+		       (iwl_rates[i].ieee >> 1),
+		       (iwl_rates[i].ieee & 0x1) ? ".5" : "");
+}
+
+static DEVICE_ATTR(rate, S_IRUSR, show_rate, NULL);
+
+static ssize_t store_retry_rate(struct device *d,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+
+	priv->retry_rate = simple_strtoul(buf, NULL, 0);
+	if (priv->retry_rate <= 0)
+		priv->retry_rate = 1;
+
+	return count;
+}
+
+static ssize_t show_retry_rate(struct device *d,
+			       struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+	return sprintf(buf, "%d", priv->retry_rate);
+}
+
+static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate,
+		   store_retry_rate);
+
+static ssize_t store_power_level(struct device *d,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+	int rc;
+	int mode;
+
+	mode = simple_strtoul(buf, NULL, 0);
+	mutex_lock(&priv->mutex);
+
+	if (!iwl_is_ready(priv)) {
+		rc = -EAGAIN;
+		goto out;
+	}
+
+	if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC))
+		mode = IWL_POWER_AC;
+	else
+		mode |= IWL_POWER_ENABLED;
+
+	if (mode != priv->power_mode) {
+		rc = iwl_send_power_mode(priv, IWL_POWER_LEVEL(mode));
+		if (rc) {
+			IWL_DEBUG_MAC80211("failed setting power mode.\n");
+			goto out;
+		}
+		priv->power_mode = mode;
+	}
+
+	rc = count;
+
+ out:
+	mutex_unlock(&priv->mutex);
+	return rc;
+}
+
+#define MAX_WX_STRING 80
+
+/* Values are in microsecond */
+static const s32 timeout_duration[] = {
+	350000,
+	250000,
+	75000,
+	37000,
+	25000,
+};
+static const s32 period_duration[] = {
+	400000,
+	700000,
+	1000000,
+	1000000,
+	1000000
+};
+
+static ssize_t show_power_level(struct device *d,
+				struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+	int level = IWL_POWER_LEVEL(priv->power_mode);
+	char *p = buf;
+
+	p += sprintf(p, "%d ", level);
+	switch (level) {
+	case IWL_POWER_MODE_CAM:
+	case IWL_POWER_AC:
+		p += sprintf(p, "(AC)");
+		break;
+	case IWL_POWER_BATTERY:
+		p += sprintf(p, "(BATTERY)");
+		break;
+	default:
+		p += sprintf(p,
+			     "(Timeout %dms, Period %dms)",
+			     timeout_duration[level - 1] / 1000,
+			     period_duration[level - 1] / 1000);
+	}
+
+	if (!(priv->power_mode & IWL_POWER_ENABLED))
+		p += sprintf(p, " OFF\n");
+	else
+		p += sprintf(p, " \n");
+
+	return (p - buf + 1);
+
+}
+
+static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
+		   store_power_level);
+
+static ssize_t show_channels(struct device *d,
+			     struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+	int len = 0, i;
+	struct ieee80211_channel *channels = NULL;
+	const struct ieee80211_hw_mode *hw_mode = NULL;
+	int count = 0;
+
+	if (!iwl_is_ready(priv))
+		return -EAGAIN;
+
+	hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211G);
+	if (!hw_mode)
+		hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211B);
+	if (hw_mode) {
+		channels = hw_mode->channels;
+		count = hw_mode->num_channels;
+	}
+
+	len +=
+	    sprintf(&buf[len],
+		    "Displaying %d channels in 2.4GHz band "
+		    "(802.11bg):\n", count);
+
+	for (i = 0; i < count; i++)
+		len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
+			       channels[i].chan,
+			       channels[i].power_level,
+			       channels[i].
+			       flag & IEEE80211_CHAN_W_RADAR_DETECT ?
+			       " (IEEE 802.11h required)" : "",
+			       (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
+				|| (channels[i].
+				    flag &
+				    IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
+			       ", IBSS",
+			       channels[i].
+			       flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
+			       "active/passive" : "passive only");
+
+	hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211A);
+	if (hw_mode) {
+		channels = hw_mode->channels;
+		count = hw_mode->num_channels;
+	} else {
+		channels = NULL;
+		count = 0;
+	}
+
+	len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band "
+		       "(802.11a):\n", count);
+
+	for (i = 0; i < count; i++)
+		len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
+			       channels[i].chan,
+			       channels[i].power_level,
+			       channels[i].
+			       flag & IEEE80211_CHAN_W_RADAR_DETECT ?
+			       " (IEEE 802.11h required)" : "",
+			       (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
+				|| (channels[i].
+				    flag &
+				    IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
+			       ", IBSS",
+			       channels[i].
+			       flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
+			       "active/passive" : "passive only");
+
+	return len;
+}
+
+static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
+
+static ssize_t show_statistics(struct device *d,
+			       struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+	u32 size = sizeof(struct iwl_notif_statistics);
+	u32 len = 0, ofs = 0;
+	u8 *data = (u8 *) & priv->statistics;
+	int rc = 0;
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	mutex_lock(&priv->mutex);
+	rc = iwl_send_statistics_request(priv);
+	mutex_unlock(&priv->mutex);
+
+	if (rc) {
+		len = sprintf(buf,
+			      "Error sending statistics request: 0x%08X\n", rc);
+		return len;
+	}
+
+	while (size && (PAGE_SIZE - len)) {
+		hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
+				   PAGE_SIZE - len, 1);
+		len = strlen(buf);
+		if (PAGE_SIZE - len)
+			buf[len++] = '\n';
+
+		ofs += 16;
+		size -= min(size, 16U);
+	}
+
+	return len;
+}
+
+static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
+
+static ssize_t show_antenna(struct device *d,
+			    struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	return sprintf(buf, "%d\n", priv->antenna);
+}
+
+static ssize_t store_antenna(struct device *d,
+			     struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	int ant;
+	struct iwl_priv *priv = dev_get_drvdata(d);
+
+	if (count == 0)
+		return 0;
+
+	if (sscanf(buf, "%1i", &ant) != 1) {
+		IWL_DEBUG_INFO("not in hex or decimal form.\n");
+		return count;
+	}
+
+	if ((ant >= 0) && (ant <= 2)) {
+		IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant);
+		priv->antenna = (enum iwl_antenna)ant;
+	} else
+		IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant);
+
+
+	return count;
+}
+
+static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna);
+
+static ssize_t show_status(struct device *d,
+			   struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+	return sprintf(buf, "0x%08x\n", (int)priv->status);
+}
+
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
+static ssize_t dump_error_log(struct device *d,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	char *p = (char *)buf;
+
+	if (p[0] == '1')
+		iwl_dump_nic_error_log((struct iwl_priv *)d->driver_data);
+
+	return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log);
+
+static ssize_t dump_event_log(struct device *d,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	char *p = (char *)buf;
+
+	if (p[0] == '1')
+		iwl_dump_nic_event_log((struct iwl_priv *)d->driver_data);
+
+	return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
+
+/*****************************************************************************
+ *
+ * driver setup and teardown
+ *
+ *****************************************************************************/
+
+static void iwl_setup_deferred_work(struct iwl_priv *priv)
+{
+	priv->workqueue = create_workqueue(DRV_NAME);
+
+	init_waitqueue_head(&priv->wait_command_queue);
+
+	INIT_WORK(&priv->up, iwl_bg_up);
+	INIT_WORK(&priv->restart, iwl_bg_restart);
+	INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
+	INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
+	INIT_WORK(&priv->request_scan, iwl_bg_request_scan);
+	INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
+	INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill);
+	INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
+	INIT_DELAYED_WORK(&priv->post_associate, iwl_bg_post_associate);
+	INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
+	INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
+	INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
+
+	iwl_hw_setup_deferred_work(priv);
+
+	tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+		     iwl_irq_tasklet, (unsigned long)priv);
+}
+
+static void iwl_cancel_deferred_work(struct iwl_priv *priv)
+{
+	iwl_hw_cancel_deferred_work(priv);
+
+	cancel_delayed_work(&priv->scan_check);
+	cancel_delayed_work(&priv->alive_start);
+	cancel_delayed_work(&priv->post_associate);
+	cancel_work_sync(&priv->beacon_update);
+}
+
+static struct attribute *iwl_sysfs_entries[] = {
+	&dev_attr_antenna.attr,
+	&dev_attr_channels.attr,
+	&dev_attr_dump_errors.attr,
+	&dev_attr_dump_events.attr,
+	&dev_attr_flags.attr,
+	&dev_attr_filter_flags.attr,
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+	&dev_attr_measurement.attr,
+#endif
+	&dev_attr_power_level.attr,
+	&dev_attr_rate.attr,
+	&dev_attr_retry_rate.attr,
+	&dev_attr_rf_kill.attr,
+	&dev_attr_rs_window.attr,
+	&dev_attr_statistics.attr,
+	&dev_attr_status.attr,
+	&dev_attr_temperature.attr,
+	&dev_attr_tune.attr,
+	&dev_attr_tx_power.attr,
+
+	NULL
+};
+
+static struct attribute_group iwl_attribute_group = {
+	.name = NULL,		/* put in device directory */
+	.attrs = iwl_sysfs_entries,
+};
+
+static struct ieee80211_ops iwl_hw_ops = {
+	.tx = iwl_mac_tx,
+	.start = iwl_mac_start,
+	.stop = iwl_mac_stop,
+	.add_interface = iwl_mac_add_interface,
+	.remove_interface = iwl_mac_remove_interface,
+	.config = iwl_mac_config,
+	.config_interface = iwl_mac_config_interface,
+	.configure_filter = iwl_configure_filter,
+	.set_key = iwl_mac_set_key,
+	.get_stats = iwl_mac_get_stats,
+	.get_tx_stats = iwl_mac_get_tx_stats,
+	.conf_tx = iwl_mac_conf_tx,
+	.get_tsf = iwl_mac_get_tsf,
+	.reset_tsf = iwl_mac_reset_tsf,
+	.beacon_update = iwl_mac_beacon_update,
+	.hw_scan = iwl_mac_hw_scan
+};
+
+static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int err = 0;
+	u32 pci_id;
+	struct iwl_priv *priv;
+	struct ieee80211_hw *hw;
+	int i;
+
+	if (iwl_param_disable_hw_scan) {
+		IWL_DEBUG_INFO("Disabling hw_scan\n");
+		iwl_hw_ops.hw_scan = NULL;
+	}
+
+	if ((iwl_param_queues_num > IWL_MAX_NUM_QUEUES) ||
+	    (iwl_param_queues_num < IWL_MIN_NUM_QUEUES)) {
+		IWL_ERROR("invalid queues_num, should be between %d and %d\n",
+			  IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES);
+		err = -EINVAL;
+		goto out;
+	}
+
+	/* mac80211 allocates memory for this device instance, including
+	 *   space for this driver's private structure */
+	hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwl_hw_ops);
+	if (hw == NULL) {
+		IWL_ERROR("Can not allocate network device\n");
+		err = -ENOMEM;
+		goto out;
+	}
+	SET_IEEE80211_DEV(hw, &pdev->dev);
+
+	IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
+	priv = hw->priv;
+	priv->hw = hw;
+
+	priv->pci_dev = pdev;
+	priv->antenna = (enum iwl_antenna)iwl_param_antenna;
+#ifdef CONFIG_IWLWIFI_DEBUG
+	iwl_debug_level = iwl_param_debug;
+	atomic_set(&priv->restrict_refcnt, 0);
+#endif
+	priv->retry_rate = 1;
+
+	priv->ibss_beacon = NULL;
+
+	/* Tell mac80211 and its clients (e.g. Wireless Extensions)
+	 *   the range of signal quality values that we'll provide.
+	 * Negative values for level/noise indicate that we'll provide dBm.
+	 * For WE, at least, non-0 values here *enable* display of values
+	 *   in app (iwconfig). */
+	hw->max_rssi = -20;	/* signal level, negative indicates dBm */
+	hw->max_noise = -20;	/* noise level, negative indicates dBm */
+	hw->max_signal = 100;	/* link quality indication (%) */
+
+	/* Tell mac80211 our Tx characteristics */
+	hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+
+	hw->queues = 4;
+
+	spin_lock_init(&priv->lock);
+	spin_lock_init(&priv->power_data.lock);
+	spin_lock_init(&priv->sta_lock);
+	spin_lock_init(&priv->hcmd_lock);
+
+	for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
+		INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
+
+	INIT_LIST_HEAD(&priv->free_frames);
+
+	mutex_init(&priv->mutex);
+	if (pci_enable_device(pdev)) {
+		err = -ENODEV;
+		goto out_ieee80211_free_hw;
+	}
+
+	pci_set_master(pdev);
+
+	iwl_clear_stations_table(priv);
+
+	priv->data_retry_limit = -1;
+	priv->ieee_channels = NULL;
+	priv->ieee_rates = NULL;
+	priv->phymode = -1;
+
+	err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+	if (!err)
+		err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+	if (err) {
+		printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n");
+		goto out_pci_disable_device;
+	}
+
+	pci_set_drvdata(pdev, priv);
+	err = pci_request_regions(pdev, DRV_NAME);
+	if (err)
+		goto out_pci_disable_device;
+	/* We disable the RETRY_TIMEOUT register (0x41) to keep
+	 * PCI Tx retries from interfering with C3 CPU state */
+	pci_write_config_byte(pdev, 0x41, 0x00);
+	priv->hw_base = pci_iomap(pdev, 0, 0);
+	if (!priv->hw_base) {
+		err = -ENODEV;
+		goto out_pci_release_regions;
+	}
+
+	IWL_DEBUG_INFO("pci_resource_len = 0x%08llx\n",
+			(unsigned long long) pci_resource_len(pdev, 0));
+	IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base);
+
+	/* Initialize module parameter values here */
+
+	if (iwl_param_disable) {
+		set_bit(STATUS_RF_KILL_SW, &priv->status);
+		IWL_DEBUG_INFO("Radio disabled.\n");
+	}
+
+	priv->iw_mode = IEEE80211_IF_TYPE_STA;
+
+	pci_id =
+	    (priv->pci_dev->device << 16) | priv->pci_dev->subsystem_device;
+
+	switch (pci_id) {
+	case 0x42221005:	/* 0x4222 0x8086 0x1005 is BG SKU */
+	case 0x42221034:	/* 0x4222 0x8086 0x1034 is BG SKU */
+	case 0x42271014:	/* 0x4227 0x8086 0x1014 is BG SKU */
+	case 0x42221044:	/* 0x4222 0x8086 0x1044 is BG SKU */
+		priv->is_abg = 0;
+		break;
+
+	/*
+	 * Rest are assumed ABG SKU -- if this is not the
+	 * case then the card will get the wrong 'Detected'
+	 * line in the kernel log however the code that
+	 * initializes the GEO table will detect no A-band
+	 * channels and remove the is_abg mask.
+	 */
+	default:
+		priv->is_abg = 1;
+		break;
+	}
+
+	printk(KERN_INFO DRV_NAME
+	       ": Detected Intel PRO/Wireless 3945%sBG Network Connection\n",
+	       priv->is_abg ? "A" : "");
+
+	/* Device-specific setup */
+	if (iwl_hw_set_hw_setting(priv)) {
+		IWL_ERROR("failed to set hw settings\n");
+		mutex_unlock(&priv->mutex);
+		goto out_iounmap;
+	}
+
+#ifdef CONFIG_IWLWIFI_QOS
+	if (iwl_param_qos_enable)
+		priv->qos_data.qos_enable = 1;
+
+	iwl_reset_qos(priv);
+
+	priv->qos_data.qos_active = 0;
+	priv->qos_data.qos_cap.val = 0;
+#endif /* CONFIG_IWLWIFI_QOS */
+
+	iwl_set_rxon_channel(priv, MODE_IEEE80211G, 6);
+	iwl_setup_deferred_work(priv);
+	iwl_setup_rx_handlers(priv);
+
+	priv->rates_mask = IWL_RATES_MASK;
+	/* If power management is turned on, default to AC mode */
+	priv->power_mode = IWL_POWER_AC;
+	priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
+
+	pci_enable_msi(pdev);
+
+	err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv);
+	if (err) {
+		IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
+		goto out_disable_msi;
+	}
+
+	mutex_lock(&priv->mutex);
+
+	err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
+	if (err) {
+		IWL_ERROR("failed to create sysfs device attributes\n");
+		mutex_unlock(&priv->mutex);
+		goto out_release_irq;
+	}
+
+	/* fetch ucode file from disk, alloc and copy to bus-master buffers ...
+	 * ucode filename and max sizes are card-specific. */
+	err = iwl_read_ucode(priv);
+	if (err) {
+		IWL_ERROR("Could not read microcode: %d\n", err);
+		mutex_unlock(&priv->mutex);
+		goto out_pci_alloc;
+	}
+
+	mutex_unlock(&priv->mutex);
+
+	IWL_DEBUG_INFO("Queing UP work.\n");
+
+	queue_work(priv->workqueue, &priv->up);
+
+	return 0;
+
+ out_pci_alloc:
+	iwl_dealloc_ucode_pci(priv);
+
+	sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
+
+ out_release_irq:
+	free_irq(pdev->irq, priv);
+
+ out_disable_msi:
+	pci_disable_msi(pdev);
+	destroy_workqueue(priv->workqueue);
+	priv->workqueue = NULL;
+	iwl_unset_hw_setting(priv);
+
+ out_iounmap:
+	pci_iounmap(pdev, priv->hw_base);
+ out_pci_release_regions:
+	pci_release_regions(pdev);
+ out_pci_disable_device:
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+ out_ieee80211_free_hw:
+	ieee80211_free_hw(priv->hw);
+ out:
+	return err;
+}
+
+static void iwl_pci_remove(struct pci_dev *pdev)
+{
+	struct iwl_priv *priv = pci_get_drvdata(pdev);
+	struct list_head *p, *q;
+	int i;
+
+	if (!priv)
+		return;
+
+	IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n");
+
+	mutex_lock(&priv->mutex);
+	set_bit(STATUS_EXIT_PENDING, &priv->status);
+	__iwl_down(priv);
+	mutex_unlock(&priv->mutex);
+
+	/* Free MAC hash list for ADHOC */
+	for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
+		list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
+			list_del(p);
+			kfree(list_entry(p, struct iwl_ibss_seq, list));
+		}
+	}
+
+	sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
+
+	iwl_dealloc_ucode_pci(priv);
+
+	if (priv->rxq.bd)
+		iwl_rx_queue_free(priv, &priv->rxq);
+	iwl_hw_txq_ctx_free(priv);
+
+	iwl_unset_hw_setting(priv);
+	iwl_clear_stations_table(priv);
+
+	if (priv->mac80211_registered) {
+		ieee80211_unregister_hw(priv->hw);
+		iwl_rate_control_unregister(priv->hw);
+	}
+
+	/* ieee80211_unregister_hw calls iwl_mac_stop, which flushes
+	 * priv->workqueue... so we can't take down the workqueue
+	 * until now... */
+	destroy_workqueue(priv->workqueue);
+	priv->workqueue = NULL;
+
+	free_irq(pdev->irq, priv);
+	pci_disable_msi(pdev);
+	pci_iounmap(pdev, priv->hw_base);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+
+	kfree(priv->channel_info);
+
+	kfree(priv->ieee_channels);
+	kfree(priv->ieee_rates);
+
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+
+	ieee80211_free_hw(priv->hw);
+}
+
+#ifdef CONFIG_PM
+
+static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct iwl_priv *priv = pci_get_drvdata(pdev);
+
+	mutex_lock(&priv->mutex);
+
+	set_bit(STATUS_IN_SUSPEND, &priv->status);
+
+	/* Take down the device; powers it off, etc. */
+	__iwl_down(priv);
+
+	if (priv->mac80211_registered)
+		ieee80211_stop_queues(priv->hw);
+
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, PCI_D3hot);
+
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+static void iwl_resume(struct iwl_priv *priv)
+{
+	unsigned long flags;
+
+	/* The following it a temporary work around due to the
+	 * suspend / resume not fully initializing the NIC correctly.
+	 * Without all of the following, resume will not attempt to take
+	 * down the NIC (it shouldn't really need to) and will just try
+	 * and bring the NIC back up.  However that fails during the
+	 * ucode verification process.  This then causes iwl_down to be
+	 * called *after* iwl_hw_nic_init() has succeeded -- which
+	 * then lets the next init sequence succeed.  So, we've
+	 * replicated all of that NIC init code here... */
+
+	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+	iwl_hw_nic_init(priv);
+
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+	/* tell the device to stop sending interrupts */
+	iwl_disable_interrupts(priv);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+	if (!iwl_grab_restricted_access(priv)) {
+		iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG,
+					 APMG_CLK_VAL_DMA_CLK_RQT);
+		iwl_release_restricted_access(priv);
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	udelay(5);
+
+	iwl_hw_nic_reset(priv);
+
+	/* Bring the device back up */
+	clear_bit(STATUS_IN_SUSPEND, &priv->status);
+	queue_work(priv->workqueue, &priv->up);
+}
+
+static int iwl_pci_resume(struct pci_dev *pdev)
+{
+	struct iwl_priv *priv = pci_get_drvdata(pdev);
+	int err;
+
+	printk(KERN_INFO "Coming out of suspend...\n");
+
+	mutex_lock(&priv->mutex);
+
+	pci_set_power_state(pdev, PCI_D0);
+	err = pci_enable_device(pdev);
+	pci_restore_state(pdev);
+
+	/*
+	 * Suspend/Resume resets the PCI configuration space, so we have to
+	 * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
+	 * from interfering with C3 CPU state. pci_restore_state won't help
+	 * here since it only restores the first 64 bytes pci config header.
+	 */
+	pci_write_config_byte(pdev, 0x41, 0x00);
+
+	iwl_resume(priv);
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+
+/*****************************************************************************
+ *
+ * driver and module entry point
+ *
+ *****************************************************************************/
+
+static struct pci_driver iwl_driver = {
+	.name = DRV_NAME,
+	.id_table = iwl_hw_card_ids,
+	.probe = iwl_pci_probe,
+	.remove = __devexit_p(iwl_pci_remove),
+#ifdef CONFIG_PM
+	.suspend = iwl_pci_suspend,
+	.resume = iwl_pci_resume,
+#endif
+};
+
+static int __init iwl_init(void)
+{
+
+	int ret;
+	printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
+	printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+	ret = pci_register_driver(&iwl_driver);
+	if (ret) {
+		IWL_ERROR("Unable to initialize PCI module\n");
+		return ret;
+	}
+#ifdef CONFIG_IWLWIFI_DEBUG
+	ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level);
+	if (ret) {
+		IWL_ERROR("Unable to create driver sysfs file\n");
+		pci_unregister_driver(&iwl_driver);
+		return ret;
+	}
+#endif
+
+	return ret;
+}
+
+static void __exit iwl_exit(void)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+	driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level);
+#endif
+	pci_unregister_driver(&iwl_driver);
+}
+
+module_param_named(antenna, iwl_param_antenna, int, 0444);
+MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
+module_param_named(disable, iwl_param_disable, int, 0444);
+MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
+module_param_named(hwcrypto, iwl_param_hwcrypto, int, 0444);
+MODULE_PARM_DESC(hwcrypto,
+		 "using hardware crypto engine (default 0 [software])\n");
+module_param_named(debug, iwl_param_debug, int, 0444);
+MODULE_PARM_DESC(debug, "debug output mask");
+module_param_named(disable_hw_scan, iwl_param_disable_hw_scan, int, 0444);
+MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
+
+module_param_named(queues_num, iwl_param_queues_num, int, 0444);
+MODULE_PARM_DESC(queues_num, "number of hw queues.");
+
+/* QoS */
+module_param_named(qos_enable, iwl_param_qos_enable, int, 0444);
+MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
+
+module_exit(iwl_exit);
+module_init(iwl_init);
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
new file mode 100644
index 0000000..b1a6e39
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -0,0 +1,9340 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+/*
+ * NOTE:  This file (iwl-base.c) is used to build to multiple hardware targets
+ * by defining IWL to either 3945 or 4965.  The Makefile used when building
+ * the base targets will create base-3945.o and base-4965.o
+ *
+ * The eventual goal is to move as many of the #if IWL / #endif blocks out of
+ * this file and into the hardware specific implementation files (iwl-XXXX.c)
+ * and leave only the common (non #ifdef sprinkled) code in this file
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/firmware.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/ieee80211_radiotap.h>
+#include <net/mac80211.h>
+
+#include <asm/div64.h>
+
+#define IWL 4965
+
+#include "iwlwifi.h"
+#include "iwl-4965.h"
+#include "iwl-helpers.h"
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+u32 iwl_debug_level;
+#endif
+
+/******************************************************************************
+ *
+ * module boiler plate
+ *
+ ******************************************************************************/
+
+/* module parameters */
+int iwl_param_disable_hw_scan;
+int iwl_param_debug;
+int iwl_param_disable;      /* def: enable radio */
+int iwl_param_antenna;      /* def: 0 = both antennas (use diversity) */
+int iwl_param_hwcrypto;     /* def: using software encryption */
+int iwl_param_qos_enable = 1;
+int iwl_param_queues_num = IWL_MAX_NUM_QUEUES;
+
+/*
+ * module name, copyright, version, etc.
+ * NOTE: DRV_NAME is defined in iwlwifi.h for use by iwl-debug.h and printk
+ */
+
+#define DRV_DESCRIPTION	"Intel(R) Wireless WiFi Link 4965AGN driver for Linux"
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+#define VD "d"
+#else
+#define VD
+#endif
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+#define VS "s"
+#else
+#define VS
+#endif
+
+#define IWLWIFI_VERSION "1.1.17k" VD VS
+#define DRV_COPYRIGHT	"Copyright(c) 2003-2007 Intel Corporation"
+#define DRV_VERSION     IWLWIFI_VERSION
+
+/* Change firmware file name, using "-" and incrementing number,
+ *   *only* when uCode interface or architecture changes so that it
+ *   is not compatible with earlier drivers.
+ * This number will also appear in << 8 position of 1st dword of uCode file */
+#define IWL4965_UCODE_API "-1"
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_LICENSE("GPL");
+
+__le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr)
+{
+	u16 fc = le16_to_cpu(hdr->frame_control);
+	int hdr_len = ieee80211_get_hdrlen(fc);
+
+	if ((fc & 0x00cc) == (IEEE80211_STYPE_QOS_DATA | IEEE80211_FTYPE_DATA))
+		return (__le16 *) ((u8 *) hdr + hdr_len - QOS_CONTROL_LEN);
+	return NULL;
+}
+
+static const struct ieee80211_hw_mode *iwl_get_hw_mode(
+		struct iwl_priv *priv, int mode)
+{
+	int i;
+
+	for (i = 0; i < 3; i++)
+		if (priv->modes[i].mode == mode)
+			return &priv->modes[i];
+
+	return NULL;
+}
+
+static int iwl_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;
+}
+
+static const char *iwl_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 (iwl_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;
+}
+
+static void iwl_print_hex_dump(int level, void *p, u32 len)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (!(iwl_debug_level & level))
+		return;
+
+	print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1,
+			p, len, 1);
+#endif
+}
+
+/*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
+ * DMA services
+ *
+ * Theory of operation
+ *
+ * A queue is a circular buffers with 'Read' and 'Write' pointers.
+ * 2 empty entries always kept in the buffer to protect from overflow.
+ *
+ * For Tx queue, there are low mark and high mark limits. If, after queuing
+ * the packet for Tx, free space become < low mark, Tx queue stopped. When
+ * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
+ * Tx queue resumed.
+ *
+ * The IWL operates with six queues, one receive queue in the device's
+ * sram, one transmit queue for sending commands to the device firmware,
+ * and four transmit queues for data.
+ ***************************************************/
+
+static int iwl_queue_space(const struct iwl_queue *q)
+{
+	int s = q->last_used - q->first_empty;
+
+	if (q->last_used > q->first_empty)
+		s -= q->n_bd;
+
+	if (s <= 0)
+		s += q->n_window;
+	/* keep some reserve to not confuse empty and full situations */
+	s -= 2;
+	if (s < 0)
+		s = 0;
+	return s;
+}
+
+/* XXX: n_bd must be power-of-two size */
+static inline int iwl_queue_inc_wrap(int index, int n_bd)
+{
+	return ++index & (n_bd - 1);
+}
+
+/* XXX: n_bd must be power-of-two size */
+static inline int iwl_queue_dec_wrap(int index, int n_bd)
+{
+	return --index & (n_bd - 1);
+}
+
+static inline int x2_queue_used(const struct iwl_queue *q, int i)
+{
+	return q->first_empty > q->last_used ?
+		(i >= q->last_used && i < q->first_empty) :
+		!(i < q->last_used && i >= q->first_empty);
+}
+
+static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
+{
+	if (is_huge)
+		return q->n_window;
+
+	return index & (q->n_window - 1);
+}
+
+static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
+			  int count, int slots_num, u32 id)
+{
+	q->n_bd = count;
+	q->n_window = slots_num;
+	q->id = id;
+
+	/* count must be power-of-two size, otherwise iwl_queue_inc_wrap
+	 * and iwl_queue_dec_wrap are broken. */
+	BUG_ON(!is_power_of_2(count));
+
+	/* slots_num must be power-of-two size, otherwise
+	 * get_cmd_index is broken. */
+	BUG_ON(!is_power_of_2(slots_num));
+
+	q->low_mark = q->n_window / 4;
+	if (q->low_mark < 4)
+		q->low_mark = 4;
+
+	q->high_mark = q->n_window / 8;
+	if (q->high_mark < 2)
+		q->high_mark = 2;
+
+	q->first_empty = q->last_used = 0;
+
+	return 0;
+}
+
+static int iwl_tx_queue_alloc(struct iwl_priv *priv,
+			      struct iwl_tx_queue *txq, u32 id)
+{
+	struct pci_dev *dev = priv->pci_dev;
+
+	if (id != IWL_CMD_QUEUE_NUM) {
+		txq->txb = kmalloc(sizeof(txq->txb[0]) *
+				   TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
+		if (!txq->txb) {
+			IWL_ERROR("kmalloc for auxilary BD "
+				  "structures failed\n");
+			goto error;
+		}
+	} else
+		txq->txb = NULL;
+
+	txq->bd = pci_alloc_consistent(dev,
+			sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX,
+			&txq->q.dma_addr);
+
+	if (!txq->bd) {
+		IWL_ERROR("pci_alloc_consistent(%zd) failed\n",
+			  sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX);
+		goto error;
+	}
+	txq->q.id = id;
+
+	return 0;
+
+ error:
+	if (txq->txb) {
+		kfree(txq->txb);
+		txq->txb = NULL;
+	}
+
+	return -ENOMEM;
+}
+
+int iwl_tx_queue_init(struct iwl_priv *priv,
+		      struct iwl_tx_queue *txq, int slots_num, u32 txq_id)
+{
+	struct pci_dev *dev = priv->pci_dev;
+	int len;
+	int rc = 0;
+
+	/* alocate command space + one big command for scan since scan
+	 * command is very huge the system will not have two scan at the
+	 * same time */
+	len = sizeof(struct iwl_cmd) * slots_num;
+	if (txq_id == IWL_CMD_QUEUE_NUM)
+		len +=  IWL_MAX_SCAN_SIZE;
+	txq->cmd = pci_alloc_consistent(dev, len, &txq->dma_addr_cmd);
+	if (!txq->cmd)
+		return -ENOMEM;
+
+	rc = iwl_tx_queue_alloc(priv, txq, txq_id);
+	if (rc) {
+		pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+		return -ENOMEM;
+	}
+	txq->need_update = 0;
+
+	/* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+	 * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
+	BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+	iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+
+	iwl_hw_tx_queue_init(priv, txq);
+
+	return 0;
+}
+
+/**
+ * iwl_tx_queue_free - Deallocate DMA queue.
+ * @txq: Transmit queue to deallocate.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers.  txq itself is not freed.
+ *
+ */
+void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+	struct iwl_queue *q = &txq->q;
+	struct pci_dev *dev = priv->pci_dev;
+	int len;
+
+	if (q->n_bd == 0)
+		return;
+
+	/* first, empty all BD's */
+	for (; q->first_empty != q->last_used;
+	     q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd))
+		iwl_hw_txq_free_tfd(priv, txq);
+
+	len = sizeof(struct iwl_cmd) * q->n_window;
+	if (q->id == IWL_CMD_QUEUE_NUM)
+		len += IWL_MAX_SCAN_SIZE;
+
+	pci_free_consistent(dev, len, txq->cmd, txq->dma_addr_cmd);
+
+	/* free buffers belonging to queue itself */
+	if (txq->q.n_bd)
+		pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) *
+				    txq->q.n_bd, txq->bd, txq->q.dma_addr);
+
+	if (txq->txb) {
+		kfree(txq->txb);
+		txq->txb = NULL;
+	}
+
+	/* 0 fill whole structure */
+	memset(txq, 0, sizeof(*txq));
+}
+
+const u8 BROADCAST_ADDR[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+/*************** STATION TABLE MANAGEMENT ****
+ *
+ * NOTE:  This needs to be overhauled to better synchronize between
+ * how the iwl-4965.c is using iwl_hw_find_station vs. iwl-3945.c
+ *
+ * mac80211 should also be examined to determine if sta_info is duplicating
+ * the functionality provided here
+ */
+
+/**************************************************************/
+
+#if 0 /* temparary disable till we add real remove station */
+static u8 iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap)
+{
+	int index = IWL_INVALID_STATION;
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+
+	if (is_ap)
+		index = IWL_AP_ID;
+	else if (is_broadcast_ether_addr(addr))
+		index = priv->hw_setting.bcast_sta_id;
+	else
+		for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
+			if (priv->stations[i].used &&
+			    !compare_ether_addr(priv->stations[i].sta.sta.addr,
+						addr)) {
+				index = i;
+				break;
+			}
+
+	if (unlikely(index == IWL_INVALID_STATION))
+		goto out;
+
+	if (priv->stations[index].used) {
+		priv->stations[index].used = 0;
+		priv->num_stations--;
+	}
+
+	BUG_ON(priv->num_stations < 0);
+
+out:
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+	return 0;
+}
+#endif
+
+static void iwl_clear_stations_table(struct iwl_priv *priv)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+
+	priv->num_stations = 0;
+	memset(priv->stations, 0, sizeof(priv->stations));
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+}
+
+u8 iwl_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap, u8 flags)
+{
+	int i;
+	int index = IWL_INVALID_STATION;
+	struct iwl_station_entry *station;
+	unsigned long flags_spin;
+	DECLARE_MAC_BUF(mac);
+
+	spin_lock_irqsave(&priv->sta_lock, flags_spin);
+	if (is_ap)
+		index = IWL_AP_ID;
+	else if (is_broadcast_ether_addr(addr))
+		index = priv->hw_setting.bcast_sta_id;
+	else
+		for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) {
+			if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
+						addr)) {
+				index = i;
+				break;
+			}
+
+			if (!priv->stations[i].used &&
+			    index == IWL_INVALID_STATION)
+				index = i;
+		}
+
+
+	/* These twh conditions has the same outcome but keep them separate
+	  since they have different meaning */
+	if (unlikely(index == IWL_INVALID_STATION)) {
+		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+		return index;
+	}
+
+	if (priv->stations[index].used &&
+	    !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) {
+		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+		return index;
+	}
+
+
+	IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));
+	station = &priv->stations[index];
+	station->used = 1;
+	priv->num_stations++;
+
+	memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));
+	memcpy(station->sta.sta.addr, addr, ETH_ALEN);
+	station->sta.mode = 0;
+	station->sta.sta.sta_id = index;
+	station->sta.station_flags = 0;
+
+#ifdef CONFIG_IWLWIFI_HT
+	/* BCAST station and IBSS stations do not work in HT mode */
+	if (index != priv->hw_setting.bcast_sta_id &&
+	    priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
+		iwl4965_set_ht_add_station(priv, index);
+#endif /*CONFIG_IWLWIFI_HT*/
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
+	iwl_send_add_station(priv, &station->sta, flags);
+	return index;
+
+}
+
+/*************** DRIVER STATUS FUNCTIONS   *****/
+
+static inline int iwl_is_ready(struct iwl_priv *priv)
+{
+	/* The adapter is 'ready' if READY and GEO_CONFIGURED bits are
+	 * set but EXIT_PENDING is not */
+	return test_bit(STATUS_READY, &priv->status) &&
+	       test_bit(STATUS_GEO_CONFIGURED, &priv->status) &&
+	       !test_bit(STATUS_EXIT_PENDING, &priv->status);
+}
+
+static inline int iwl_is_alive(struct iwl_priv *priv)
+{
+	return test_bit(STATUS_ALIVE, &priv->status);
+}
+
+static inline int iwl_is_init(struct iwl_priv *priv)
+{
+	return test_bit(STATUS_INIT, &priv->status);
+}
+
+static inline int iwl_is_rfkill(struct iwl_priv *priv)
+{
+	return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
+	       test_bit(STATUS_RF_KILL_SW, &priv->status);
+}
+
+static inline int iwl_is_ready_rf(struct iwl_priv *priv)
+{
+
+	if (iwl_is_rfkill(priv))
+		return 0;
+
+	return iwl_is_ready(priv);
+}
+
+/*************** HOST COMMAND QUEUE FUNCTIONS   *****/
+
+#define IWL_CMD(x) case x : return #x
+
+static const char *get_cmd_string(u8 cmd)
+{
+	switch (cmd) {
+		IWL_CMD(REPLY_ALIVE);
+		IWL_CMD(REPLY_ERROR);
+		IWL_CMD(REPLY_RXON);
+		IWL_CMD(REPLY_RXON_ASSOC);
+		IWL_CMD(REPLY_QOS_PARAM);
+		IWL_CMD(REPLY_RXON_TIMING);
+		IWL_CMD(REPLY_ADD_STA);
+		IWL_CMD(REPLY_REMOVE_STA);
+		IWL_CMD(REPLY_REMOVE_ALL_STA);
+		IWL_CMD(REPLY_TX);
+		IWL_CMD(REPLY_RATE_SCALE);
+		IWL_CMD(REPLY_LEDS_CMD);
+		IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
+		IWL_CMD(RADAR_NOTIFICATION);
+		IWL_CMD(REPLY_QUIET_CMD);
+		IWL_CMD(REPLY_CHANNEL_SWITCH);
+		IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);
+		IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD);
+		IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION);
+		IWL_CMD(POWER_TABLE_CMD);
+		IWL_CMD(PM_SLEEP_NOTIFICATION);
+		IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC);
+		IWL_CMD(REPLY_SCAN_CMD);
+		IWL_CMD(REPLY_SCAN_ABORT_CMD);
+		IWL_CMD(SCAN_START_NOTIFICATION);
+		IWL_CMD(SCAN_RESULTS_NOTIFICATION);
+		IWL_CMD(SCAN_COMPLETE_NOTIFICATION);
+		IWL_CMD(BEACON_NOTIFICATION);
+		IWL_CMD(REPLY_TX_BEACON);
+		IWL_CMD(WHO_IS_AWAKE_NOTIFICATION);
+		IWL_CMD(QUIET_NOTIFICATION);
+		IWL_CMD(REPLY_TX_PWR_TABLE_CMD);
+		IWL_CMD(MEASURE_ABORT_NOTIFICATION);
+		IWL_CMD(REPLY_BT_CONFIG);
+		IWL_CMD(REPLY_STATISTICS_CMD);
+		IWL_CMD(STATISTICS_NOTIFICATION);
+		IWL_CMD(REPLY_CARD_STATE_CMD);
+		IWL_CMD(CARD_STATE_NOTIFICATION);
+		IWL_CMD(MISSED_BEACONS_NOTIFICATION);
+		IWL_CMD(REPLY_CT_KILL_CONFIG_CMD);
+		IWL_CMD(SENSITIVITY_CMD);
+		IWL_CMD(REPLY_PHY_CALIBRATION_CMD);
+		IWL_CMD(REPLY_RX_PHY_CMD);
+		IWL_CMD(REPLY_RX_MPDU_CMD);
+		IWL_CMD(REPLY_4965_RX);
+		IWL_CMD(REPLY_COMPRESSED_BA);
+	default:
+		return "UNKNOWN";
+
+	}
+}
+
+#define HOST_COMPLETE_TIMEOUT (HZ / 2)
+
+/**
+ * iwl_enqueue_hcmd - enqueue a uCode command
+ * @priv: device private data point
+ * @cmd: a point to the ucode command structure
+ *
+ * The function returns < 0 values to indicate the operation is
+ * failed. On success, it turns the index (> 0) of command in the
+ * command queue.
+ */
+static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+	struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
+	struct iwl_queue *q = &txq->q;
+	struct iwl_tfd_frame *tfd;
+	u32 *control_flags;
+	struct iwl_cmd *out_cmd;
+	u32 idx;
+	u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
+	dma_addr_t phys_addr;
+	int ret;
+	unsigned long flags;
+
+	/* If any of the command structures end up being larger than
+	 * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
+	 * we will need to increase the size of the TFD entries */
+	BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
+	       !(cmd->meta.flags & CMD_SIZE_HUGE));
+
+	if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {
+		IWL_ERROR("No space for Tx\n");
+		return -ENOSPC;
+	}
+
+	spin_lock_irqsave(&priv->hcmd_lock, flags);
+
+	tfd = &txq->bd[q->first_empty];
+	memset(tfd, 0, sizeof(*tfd));
+
+	control_flags = (u32 *) tfd;
+
+	idx = get_cmd_index(q, q->first_empty, cmd->meta.flags & CMD_SIZE_HUGE);
+	out_cmd = &txq->cmd[idx];
+
+	out_cmd->hdr.cmd = cmd->id;
+	memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));
+	memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
+
+	/* At this point, the out_cmd now has all of the incoming cmd
+	 * information */
+
+	out_cmd->hdr.flags = 0;
+	out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |
+			INDEX_TO_SEQ(q->first_empty));
+	if (out_cmd->meta.flags & CMD_SIZE_HUGE)
+		out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);
+
+	phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +
+			offsetof(struct iwl_cmd, hdr);
+	iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);
+
+	IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "
+		     "%d bytes at %d[%d]:%d\n",
+		     get_cmd_string(out_cmd->hdr.cmd),
+		     out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
+		     fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM);
+
+	txq->need_update = 1;
+	ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0);
+	q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
+	iwl_tx_queue_update_write_ptr(priv, txq);
+
+	spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+	return ret ? ret : idx;
+}
+
+int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+	int ret;
+
+	BUG_ON(!(cmd->meta.flags & CMD_ASYNC));
+
+	/* An asynchronous command can not expect an SKB to be set. */
+	BUG_ON(cmd->meta.flags & CMD_WANT_SKB);
+
+	/* An asynchronous command MUST have a callback. */
+	BUG_ON(!cmd->meta.u.callback);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return -EBUSY;
+
+	ret = iwl_enqueue_hcmd(priv, cmd);
+	if (ret < 0) {
+		IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",
+			  get_cmd_string(cmd->id), ret);
+		return ret;
+	}
+	return 0;
+}
+
+int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+	int cmd_idx;
+	int ret;
+	static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */
+
+	BUG_ON(cmd->meta.flags & CMD_ASYNC);
+
+	 /* A synchronous command can not have a callback set. */
+	BUG_ON(cmd->meta.u.callback != NULL);
+
+	if (atomic_xchg(&entry, 1)) {
+		IWL_ERROR("Error sending %s: Already sending a host command\n",
+			  get_cmd_string(cmd->id));
+		return -EBUSY;
+	}
+
+	set_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+	if (cmd->meta.flags & CMD_WANT_SKB)
+		cmd->meta.source = &cmd->meta;
+
+	cmd_idx = iwl_enqueue_hcmd(priv, cmd);
+	if (cmd_idx < 0) {
+		ret = cmd_idx;
+		IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",
+			  get_cmd_string(cmd->id), ret);
+		goto out;
+	}
+
+	ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+			!test_bit(STATUS_HCMD_ACTIVE, &priv->status),
+			HOST_COMPLETE_TIMEOUT);
+	if (!ret) {
+		if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) {
+			IWL_ERROR("Error sending %s: time out after %dms.\n",
+				  get_cmd_string(cmd->id),
+				  jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
+
+			clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+			ret = -ETIMEDOUT;
+			goto cancel;
+		}
+	}
+
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
+		IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n",
+			       get_cmd_string(cmd->id));
+		ret = -ECANCELED;
+		goto fail;
+	}
+	if (test_bit(STATUS_FW_ERROR, &priv->status)) {
+		IWL_DEBUG_INFO("Command %s failed: FW Error\n",
+			       get_cmd_string(cmd->id));
+		ret = -EIO;
+		goto fail;
+	}
+	if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) {
+		IWL_ERROR("Error: Response NULL in '%s'\n",
+			  get_cmd_string(cmd->id));
+		ret = -EIO;
+		goto out;
+	}
+
+	ret = 0;
+	goto out;
+
+cancel:
+	if (cmd->meta.flags & CMD_WANT_SKB) {
+		struct iwl_cmd *qcmd;
+
+		/* Cancel the CMD_WANT_SKB flag for the cmd in the
+		 * TX cmd queue. Otherwise in case the cmd comes
+		 * in later, it will possibly set an invalid
+		 * address (cmd->meta.source). */
+		qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx];
+		qcmd->meta.flags &= ~CMD_WANT_SKB;
+	}
+fail:
+	if (cmd->meta.u.skb) {
+		dev_kfree_skb_any(cmd->meta.u.skb);
+		cmd->meta.u.skb = NULL;
+	}
+out:
+	atomic_set(&entry, 0);
+	return ret;
+}
+
+int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
+{
+	/* A command can not be asynchronous AND expect an SKB to be set. */
+	BUG_ON((cmd->meta.flags & CMD_ASYNC) &&
+	       (cmd->meta.flags & CMD_WANT_SKB));
+
+	if (cmd->meta.flags & CMD_ASYNC)
+		return iwl_send_cmd_async(priv, cmd);
+
+	return iwl_send_cmd_sync(priv, cmd);
+}
+
+int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data)
+{
+	struct iwl_host_cmd cmd = {
+		.id = id,
+		.len = len,
+		.data = data,
+	};
+
+	return iwl_send_cmd_sync(priv, &cmd);
+}
+
+static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val)
+{
+	struct iwl_host_cmd cmd = {
+		.id = id,
+		.len = sizeof(val),
+		.data = &val,
+	};
+
+	return iwl_send_cmd_sync(priv, &cmd);
+}
+
+int iwl_send_statistics_request(struct iwl_priv *priv)
+{
+	return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0);
+}
+
+/**
+ * iwl_rxon_add_station - add station into station table.
+ *
+ * there is only one AP station with id= IWL_AP_ID
+ * NOTE: mutex must be held before calling the this fnction
+*/
+static int iwl_rxon_add_station(struct iwl_priv *priv,
+				const u8 *addr, int is_ap)
+{
+	u8 sta_id;
+
+	sta_id = iwl_add_station(priv, addr, is_ap, 0);
+	iwl4965_add_station(priv, addr, is_ap);
+
+	return sta_id;
+}
+
+/**
+ * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON
+ * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
+ * @channel: Any channel valid for the requested phymode
+
+ * In addition to setting the staging RXON, priv->phymode is also set.
+ *
+ * NOTE:  Does not commit to the hardware; it sets appropriate bit fields
+ * in the staging RXON flag structure based on the phymode
+ */
+static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel)
+{
+	if (!iwl_get_channel_info(priv, phymode, channel)) {
+		IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",
+			       channel, phymode);
+		return -EINVAL;
+	}
+
+	if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&
+	    (priv->phymode == phymode))
+		return 0;
+
+	priv->staging_rxon.channel = cpu_to_le16(channel);
+	if (phymode == MODE_IEEE80211A)
+		priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;
+	else
+		priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+
+	priv->phymode = phymode;
+
+	IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode);
+
+	return 0;
+}
+
+/**
+ * iwl_check_rxon_cmd - validate RXON structure is valid
+ *
+ * NOTE:  This is really only useful during development and can eventually
+ * be #ifdef'd out once the driver is stable and folks aren't actively
+ * making changes
+ */
+static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon)
+{
+	int error = 0;
+	int counter = 1;
+
+	if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
+		error |= le32_to_cpu(rxon->flags &
+				(RXON_FLG_TGJ_NARROW_BAND_MSK |
+				 RXON_FLG_RADAR_DETECT_MSK));
+		if (error)
+			IWL_WARNING("check 24G fields %d | %d\n",
+				    counter++, error);
+	} else {
+		error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ?
+				0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK);
+		if (error)
+			IWL_WARNING("check 52 fields %d | %d\n",
+				    counter++, error);
+		error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK);
+		if (error)
+			IWL_WARNING("check 52 CCK %d | %d\n",
+				    counter++, error);
+	}
+	error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1;
+	if (error)
+		IWL_WARNING("check mac addr %d | %d\n", counter++, error);
+
+	/* make sure basic rates 6Mbps and 1Mbps are supported */
+	error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) &&
+		  ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0));
+	if (error)
+		IWL_WARNING("check basic rate %d | %d\n", counter++, error);
+
+	error |= (le16_to_cpu(rxon->assoc_id) > 2007);
+	if (error)
+		IWL_WARNING("check assoc id %d | %d\n", counter++, error);
+
+	error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
+			== (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK));
+	if (error)
+		IWL_WARNING("check CCK and short slot %d | %d\n",
+			    counter++, error);
+
+	error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
+			== (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK));
+	if (error)
+		IWL_WARNING("check CCK & auto detect %d | %d\n",
+			    counter++, error);
+
+	error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
+			RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK);
+	if (error)
+		IWL_WARNING("check TGG and auto detect %d | %d\n",
+			    counter++, error);
+
+	if (error)
+		IWL_WARNING("Tuning to channel %d\n",
+			    le16_to_cpu(rxon->channel));
+
+	if (error) {
+		IWL_ERROR("Not a valid iwl_rxon_assoc_cmd field values\n");
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * iwl_full_rxon_required - determine if RXON_ASSOC can be used in RXON commit
+ * @priv: staging_rxon is comapred to active_rxon
+ *
+ * If the RXON structure is changing sufficient to require a new
+ * tune or to clear and reset the RXON_FILTER_ASSOC_MSK then return 1
+ * to indicate a new tune is required.
+ */
+static int iwl_full_rxon_required(struct iwl_priv *priv)
+{
+
+	/* These items are only settable from the full RXON command */
+	if (!(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ||
+	    compare_ether_addr(priv->staging_rxon.bssid_addr,
+			       priv->active_rxon.bssid_addr) ||
+	    compare_ether_addr(priv->staging_rxon.node_addr,
+			       priv->active_rxon.node_addr) ||
+	    compare_ether_addr(priv->staging_rxon.wlap_bssid_addr,
+			       priv->active_rxon.wlap_bssid_addr) ||
+	    (priv->staging_rxon.dev_type != priv->active_rxon.dev_type) ||
+	    (priv->staging_rxon.channel != priv->active_rxon.channel) ||
+	    (priv->staging_rxon.air_propagation !=
+	     priv->active_rxon.air_propagation) ||
+	    (priv->staging_rxon.ofdm_ht_single_stream_basic_rates !=
+	     priv->active_rxon.ofdm_ht_single_stream_basic_rates) ||
+	    (priv->staging_rxon.ofdm_ht_dual_stream_basic_rates !=
+	     priv->active_rxon.ofdm_ht_dual_stream_basic_rates) ||
+	    (priv->staging_rxon.rx_chain != priv->active_rxon.rx_chain) ||
+	    (priv->staging_rxon.assoc_id != priv->active_rxon.assoc_id))
+		return 1;
+
+	/* flags, filter_flags, ofdm_basic_rates, and cck_basic_rates can
+	 * be updated with the RXON_ASSOC command -- however only some
+	 * flag transitions are allowed using RXON_ASSOC */
+
+	/* Check if we are not switching bands */
+	if ((priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) !=
+	    (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK))
+		return 1;
+
+	/* Check if we are switching association toggle */
+	if ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) !=
+		(priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK))
+		return 1;
+
+	return 0;
+}
+
+static int iwl_send_rxon_assoc(struct iwl_priv *priv)
+{
+	int rc = 0;
+	struct iwl_rx_packet *res = NULL;
+	struct iwl_rxon_assoc_cmd rxon_assoc;
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_RXON_ASSOC,
+		.len = sizeof(rxon_assoc),
+		.meta.flags = CMD_WANT_SKB,
+		.data = &rxon_assoc,
+	};
+	const struct iwl_rxon_cmd *rxon1 = &priv->staging_rxon;
+	const struct iwl_rxon_cmd *rxon2 = &priv->active_rxon;
+
+	if ((rxon1->flags == rxon2->flags) &&
+	    (rxon1->filter_flags == rxon2->filter_flags) &&
+	    (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
+	    (rxon1->ofdm_ht_single_stream_basic_rates ==
+	     rxon2->ofdm_ht_single_stream_basic_rates) &&
+	    (rxon1->ofdm_ht_dual_stream_basic_rates ==
+	     rxon2->ofdm_ht_dual_stream_basic_rates) &&
+	    (rxon1->rx_chain == rxon2->rx_chain) &&
+	    (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
+		IWL_DEBUG_INFO("Using current RXON_ASSOC.  Not resending.\n");
+		return 0;
+	}
+
+	rxon_assoc.flags = priv->staging_rxon.flags;
+	rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
+	rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
+	rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
+	rxon_assoc.reserved = 0;
+	rxon_assoc.ofdm_ht_single_stream_basic_rates =
+	    priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
+	rxon_assoc.ofdm_ht_dual_stream_basic_rates =
+	    priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
+	rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
+
+	rc = iwl_send_cmd_sync(priv, &cmd);
+	if (rc)
+		return rc;
+
+	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+		IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n");
+		rc = -EIO;
+	}
+
+	priv->alloc_rxb_skb--;
+	dev_kfree_skb_any(cmd.meta.u.skb);
+
+	return rc;
+}
+
+/**
+ * iwl_commit_rxon - commit staging_rxon to hardware
+ *
+ * The RXON command in staging_rxon is commited to the hardware and
+ * the active_rxon structure is updated with the new data.  This
+ * function correctly transitions out of the RXON_ASSOC_MSK state if
+ * a HW tune is required based on the RXON structure changes.
+ */
+static int iwl_commit_rxon(struct iwl_priv *priv)
+{
+	/* cast away the const for active_rxon in this function */
+	struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
+	DECLARE_MAC_BUF(mac);
+	int rc = 0;
+
+	if (!iwl_is_alive(priv))
+		return -1;
+
+	/* always get timestamp with Rx frame */
+	priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
+
+	rc = iwl_check_rxon_cmd(&priv->staging_rxon);
+	if (rc) {
+		IWL_ERROR("Invalid RXON configuration.  Not committing.\n");
+		return -EINVAL;
+	}
+
+	/* If we don't need to send a full RXON, we can use
+	 * iwl_rxon_assoc_cmd which is used to reconfigure filter
+	 * and other flags for the current radio configuration. */
+	if (!iwl_full_rxon_required(priv)) {
+		rc = iwl_send_rxon_assoc(priv);
+		if (rc) {
+			IWL_ERROR("Error setting RXON_ASSOC "
+				  "configuration (%d).\n", rc);
+			return rc;
+		}
+
+		memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+
+		return 0;
+	}
+
+	/* station table will be cleared */
+	priv->assoc_station_added = 0;
+
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+	priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
+	if (!priv->error_recovering)
+		priv->start_calib = 0;
+
+	iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);
+#endif /* CONFIG_IWLWIFI_SENSITIVITY */
+
+	/* If we are currently associated and the new config requires
+	 * an RXON_ASSOC and the new config wants the associated mask enabled,
+	 * we must clear the associated from the active configuration
+	 * before we apply the new config */
+	if (iwl_is_associated(priv) &&
+	    (priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK)) {
+		IWL_DEBUG_INFO("Toggling associated bit on current RXON\n");
+		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+
+		rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
+				      sizeof(struct iwl_rxon_cmd),
+				      &priv->active_rxon);
+
+		/* If the mask clearing failed then we set
+		 * active_rxon back to what it was previously */
+		if (rc) {
+			active_rxon->filter_flags |= RXON_FILTER_ASSOC_MSK;
+			IWL_ERROR("Error clearing ASSOC_MSK on current "
+				  "configuration (%d).\n", rc);
+			return rc;
+		}
+	}
+
+	IWL_DEBUG_INFO("Sending RXON\n"
+		       "* with%s RXON_FILTER_ASSOC_MSK\n"
+		       "* channel = %d\n"
+		       "* bssid = %s\n",
+		       ((priv->staging_rxon.filter_flags &
+			 RXON_FILTER_ASSOC_MSK) ? "" : "out"),
+		       le16_to_cpu(priv->staging_rxon.channel),
+		       print_mac(mac, priv->staging_rxon.bssid_addr));
+
+	/* Apply the new configuration */
+	rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
+			      sizeof(struct iwl_rxon_cmd), &priv->staging_rxon);
+	if (rc) {
+		IWL_ERROR("Error setting new configuration (%d).\n", rc);
+		return rc;
+	}
+
+	iwl_clear_stations_table(priv);
+
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+	if (!priv->error_recovering)
+		priv->start_calib = 0;
+
+	priv->sensitivity_data.state = IWL_SENS_CALIB_NEED_REINIT;
+	iwl4965_init_sensitivity(priv, CMD_ASYNC, 1);
+#endif /* CONFIG_IWLWIFI_SENSITIVITY */
+
+	memcpy(active_rxon, &priv->staging_rxon, sizeof(*active_rxon));
+
+	/* If we issue a new RXON command which required a tune then we must
+	 * send a new TXPOWER command or we won't be able to Tx any frames */
+	rc = iwl_hw_reg_send_txpower(priv);
+	if (rc) {
+		IWL_ERROR("Error setting Tx power (%d).\n", rc);
+		return rc;
+	}
+
+	/* Add the broadcast address so we can send broadcast frames */
+	if (iwl_rxon_add_station(priv, BROADCAST_ADDR, 0) ==
+	    IWL_INVALID_STATION) {
+		IWL_ERROR("Error adding BROADCAST address for transmit.\n");
+		return -EIO;
+	}
+
+	/* If we have set the ASSOC_MSK and we are in BSS mode then
+	 * add the IWL_AP_ID to the station rate table */
+	if (iwl_is_associated(priv) &&
+	    (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
+		if (iwl_rxon_add_station(priv, priv->active_rxon.bssid_addr, 1)
+		    == IWL_INVALID_STATION) {
+			IWL_ERROR("Error adding AP address for transmit.\n");
+			return -EIO;
+		}
+		priv->assoc_station_added = 1;
+	}
+
+	return 0;
+}
+
+static int iwl_send_bt_config(struct iwl_priv *priv)
+{
+	struct iwl_bt_cmd bt_cmd = {
+		.flags = 3,
+		.lead_time = 0xAA,
+		.max_kill = 1,
+		.kill_ack_mask = 0,
+		.kill_cts_mask = 0,
+	};
+
+	return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG,
+				sizeof(struct iwl_bt_cmd), &bt_cmd);
+}
+
+static int iwl_send_scan_abort(struct iwl_priv *priv)
+{
+	int rc = 0;
+	struct iwl_rx_packet *res;
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_SCAN_ABORT_CMD,
+		.meta.flags = CMD_WANT_SKB,
+	};
+
+	/* If there isn't a scan actively going on in the hardware
+	 * then we are in between scan bands and not actually
+	 * actively scanning, so don't send the abort command */
+	if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
+		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+		return 0;
+	}
+
+	rc = iwl_send_cmd_sync(priv, &cmd);
+	if (rc) {
+		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+		return rc;
+	}
+
+	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	if (res->u.status != CAN_ABORT_STATUS) {
+		/* The scan abort will return 1 for success or
+		 * 2 for "failure".  A failure condition can be
+		 * due to simply not being in an active scan which
+		 * can occur if we send the scan abort before we
+		 * the microcode has notified us that a scan is
+		 * completed. */
+		IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status);
+		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+		clear_bit(STATUS_SCAN_HW, &priv->status);
+	}
+
+	dev_kfree_skb_any(cmd.meta.u.skb);
+
+	return rc;
+}
+
+static int iwl_card_state_sync_callback(struct iwl_priv *priv,
+					struct iwl_cmd *cmd,
+					struct sk_buff *skb)
+{
+	return 1;
+}
+
+/*
+ * CARD_STATE_CMD
+ *
+ * Use: Sets the internal card state to enable, disable, or halt
+ *
+ * When in the 'enable' state the card operates as normal.
+ * When in the 'disable' state, the card enters into a low power mode.
+ * When in the 'halt' state, the card is shut down and must be fully
+ * restarted to come back on.
+ */
+static int iwl_send_card_state(struct iwl_priv *priv, u32 flags, u8 meta_flag)
+{
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_CARD_STATE_CMD,
+		.len = sizeof(u32),
+		.data = &flags,
+		.meta.flags = meta_flag,
+	};
+
+	if (meta_flag & CMD_ASYNC)
+		cmd.meta.u.callback = iwl_card_state_sync_callback;
+
+	return iwl_send_cmd(priv, &cmd);
+}
+
+static int iwl_add_sta_sync_callback(struct iwl_priv *priv,
+				     struct iwl_cmd *cmd, struct sk_buff *skb)
+{
+	struct iwl_rx_packet *res = NULL;
+
+	if (!skb) {
+		IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n");
+		return 1;
+	}
+
+	res = (struct iwl_rx_packet *)skb->data;
+	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+		IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+			  res->hdr.flags);
+		return 1;
+	}
+
+	switch (res->u.add_sta.status) {
+	case ADD_STA_SUCCESS_MSK:
+		break;
+	default:
+		break;
+	}
+
+	/* We didn't cache the SKB; let the caller free it */
+	return 1;
+}
+
+int iwl_send_add_station(struct iwl_priv *priv,
+			 struct iwl_addsta_cmd *sta, u8 flags)
+{
+	struct iwl_rx_packet *res = NULL;
+	int rc = 0;
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_ADD_STA,
+		.len = sizeof(struct iwl_addsta_cmd),
+		.meta.flags = flags,
+		.data = sta,
+	};
+
+	if (flags & CMD_ASYNC)
+		cmd.meta.u.callback = iwl_add_sta_sync_callback;
+	else
+		cmd.meta.flags |= CMD_WANT_SKB;
+
+	rc = iwl_send_cmd(priv, &cmd);
+
+	if (rc || (flags & CMD_ASYNC))
+		return rc;
+
+	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+		IWL_ERROR("Bad return from REPLY_ADD_STA (0x%08X)\n",
+			  res->hdr.flags);
+		rc = -EIO;
+	}
+
+	if (rc == 0) {
+		switch (res->u.add_sta.status) {
+		case ADD_STA_SUCCESS_MSK:
+			IWL_DEBUG_INFO("REPLY_ADD_STA PASSED\n");
+			break;
+		default:
+			rc = -EIO;
+			IWL_WARNING("REPLY_ADD_STA failed\n");
+			break;
+		}
+	}
+
+	priv->alloc_rxb_skb--;
+	dev_kfree_skb_any(cmd.meta.u.skb);
+
+	return rc;
+}
+
+static int iwl_update_sta_key_info(struct iwl_priv *priv,
+				   struct ieee80211_key_conf *keyconf,
+				   u8 sta_id)
+{
+	unsigned long flags;
+	__le16 key_flags = 0;
+
+	switch (keyconf->alg) {
+	case ALG_CCMP:
+		key_flags |= STA_KEY_FLG_CCMP;
+		key_flags |= cpu_to_le16(
+				keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+		key_flags &= ~STA_KEY_FLG_INVALID;
+		break;
+	case ALG_TKIP:
+	case ALG_WEP:
+		return -EINVAL;
+	default:
+		return -EINVAL;
+	}
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	priv->stations[sta_id].keyinfo.alg = keyconf->alg;
+	priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
+	memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
+	       keyconf->keylen);
+
+	memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
+	       keyconf->keylen);
+	priv->stations[sta_id].sta.key.key_flags = key_flags;
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
+	iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+	return 0;
+}
+
+static int iwl_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->sta_lock, flags);
+	memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
+	memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl_keyinfo));
+	priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
+	priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+	priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+	spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+	IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
+	iwl_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+	return 0;
+}
+
+static void iwl_clear_free_frames(struct iwl_priv *priv)
+{
+	struct list_head *element;
+
+	IWL_DEBUG_INFO("%d frames on pre-allocated heap on clear.\n",
+		       priv->frames_count);
+
+	while (!list_empty(&priv->free_frames)) {
+		element = priv->free_frames.next;
+		list_del(element);
+		kfree(list_entry(element, struct iwl_frame, list));
+		priv->frames_count--;
+	}
+
+	if (priv->frames_count) {
+		IWL_WARNING("%d frames still in use.  Did we lose one?\n",
+			    priv->frames_count);
+		priv->frames_count = 0;
+	}
+}
+
+static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv)
+{
+	struct iwl_frame *frame;
+	struct list_head *element;
+	if (list_empty(&priv->free_frames)) {
+		frame = kzalloc(sizeof(*frame), GFP_KERNEL);
+		if (!frame) {
+			IWL_ERROR("Could not allocate frame!\n");
+			return NULL;
+		}
+
+		priv->frames_count++;
+		return frame;
+	}
+
+	element = priv->free_frames.next;
+	list_del(element);
+	return list_entry(element, struct iwl_frame, list);
+}
+
+static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
+{
+	memset(frame, 0, sizeof(*frame));
+	list_add(&frame->list, &priv->free_frames);
+}
+
+unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
+				struct ieee80211_hdr *hdr,
+				const u8 *dest, int left)
+{
+
+	if (!iwl_is_associated(priv) || !priv->ibss_beacon ||
+	    ((priv->iw_mode != IEEE80211_IF_TYPE_IBSS) &&
+	     (priv->iw_mode != IEEE80211_IF_TYPE_AP)))
+		return 0;
+
+	if (priv->ibss_beacon->len > left)
+		return 0;
+
+	memcpy(hdr, priv->ibss_beacon->data, priv->ibss_beacon->len);
+
+	return priv->ibss_beacon->len;
+}
+
+int iwl_rate_index_from_plcp(int plcp)
+{
+	int i = 0;
+
+	if (plcp & RATE_MCS_HT_MSK) {
+		i = (plcp & 0xff);
+
+		if (i >= IWL_RATE_MIMO_6M_PLCP)
+			i = i - IWL_RATE_MIMO_6M_PLCP;
+
+		i += IWL_FIRST_OFDM_RATE;
+		/* skip 9M not supported in ht*/
+		if (i >= IWL_RATE_9M_INDEX)
+			i += 1;
+		if ((i >= IWL_FIRST_OFDM_RATE) &&
+		    (i <= IWL_LAST_OFDM_RATE))
+			return i;
+	} else {
+		for (i = 0; i < ARRAY_SIZE(iwl_rates); i++)
+			if (iwl_rates[i].plcp == (plcp &0xFF))
+				return i;
+	}
+	return -1;
+}
+
+static u8 iwl_rate_get_lowest_plcp(int rate_mask)
+{
+	u8 i;
+
+	for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID;
+	     i = iwl_rates[i].next_ieee) {
+		if (rate_mask & (1 << i))
+			return iwl_rates[i].plcp;
+	}
+
+	return IWL_RATE_INVALID;
+}
+
+static int iwl_send_beacon_cmd(struct iwl_priv *priv)
+{
+	struct iwl_frame *frame;
+	unsigned int frame_size;
+	int rc;
+	u8 rate;
+
+	frame = iwl_get_free_frame(priv);
+
+	if (!frame) {
+		IWL_ERROR("Could not obtain free frame buffer for beacon "
+			  "command.\n");
+		return -ENOMEM;
+	}
+
+	if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) {
+		rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic &
+						0xFF0);
+		if (rate == IWL_INVALID_RATE)
+			rate = IWL_RATE_6M_PLCP;
+	} else {
+		rate = iwl_rate_get_lowest_plcp(priv->active_rate_basic & 0xF);
+		if (rate == IWL_INVALID_RATE)
+			rate = IWL_RATE_1M_PLCP;
+	}
+
+	frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate);
+
+	rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
+			      &frame->u.cmd[0]);
+
+	iwl_free_frame(priv, frame);
+
+	return rc;
+}
+
+/******************************************************************************
+ *
+ * EEPROM related functions
+ *
+ ******************************************************************************/
+
+static void get_eeprom_mac(struct iwl_priv *priv, u8 *mac)
+{
+	memcpy(mac, priv->eeprom.mac_address, 6);
+}
+
+/**
+ * iwl_eeprom_init - read EEPROM contents
+ *
+ * Load the EEPROM from adapter into priv->eeprom
+ *
+ * NOTE:  This routine uses the non-debug IO access functions.
+ */
+int iwl_eeprom_init(struct iwl_priv *priv)
+{
+	u16 *e = (u16 *)&priv->eeprom;
+	u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
+	u32 r;
+	int sz = sizeof(priv->eeprom);
+	int rc;
+	int i;
+	u16 addr;
+
+	/* The EEPROM structure has several padding buffers within it
+	 * and when adding new EEPROM maps is subject to programmer errors
+	 * which may be very difficult to identify without explicitly
+	 * checking the resulting size of the eeprom map. */
+	BUILD_BUG_ON(sizeof(priv->eeprom) != IWL_EEPROM_IMAGE_SIZE);
+
+	if ((gp & CSR_EEPROM_GP_VALID_MSK) == CSR_EEPROM_GP_BAD_SIGNATURE) {
+		IWL_ERROR("EEPROM not found, EEPROM_GP=0x%08x", gp);
+		return -ENOENT;
+	}
+
+	rc = iwl_eeprom_aqcuire_semaphore(priv);
+	if (rc < 0) {
+		IWL_ERROR("Failed to aqcuire EEPROM semaphore.\n");
+		return -ENOENT;
+	}
+
+	/* eeprom is an array of 16bit values */
+	for (addr = 0; addr < sz; addr += sizeof(u16)) {
+		_iwl_write32(priv, CSR_EEPROM_REG, addr << 1);
+		_iwl_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD);
+
+		for (i = 0; i < IWL_EEPROM_ACCESS_TIMEOUT;
+					i += IWL_EEPROM_ACCESS_DELAY) {
+			r = _iwl_read_restricted(priv, CSR_EEPROM_REG);
+			if (r & CSR_EEPROM_REG_READ_VALID_MSK)
+				break;
+			udelay(IWL_EEPROM_ACCESS_DELAY);
+		}
+
+		if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) {
+			IWL_ERROR("Time out reading EEPROM[%d]", addr);
+			rc = -ETIMEDOUT;
+			goto done;
+		}
+		e[addr / 2] = le16_to_cpu(r >> 16);
+	}
+	rc = 0;
+
+done:
+	iwl_eeprom_release_semaphore(priv);
+	return rc;
+}
+
+/******************************************************************************
+ *
+ * Misc. internal state and helper functions
+ *
+ ******************************************************************************/
+#ifdef CONFIG_IWLWIFI_DEBUG
+
+/**
+ * iwl_report_frame - dump frame to syslog during debug sessions
+ *
+ * hack this function to show different aspects of received frames,
+ * including selective frame dumps.
+ * group100 parameter selects whether to show 1 out of 100 good frames.
+ *
+ * TODO:  ieee80211_hdr stuff is common to 3945 and 4965, so frame type
+ *        info output is okay, but some of this stuff (e.g. iwl_rx_frame_stats)
+ *        is 3945-specific and gives bad output for 4965.  Need to split the
+ *        functionality, keep common stuff here.
+ */
+void iwl_report_frame(struct iwl_priv *priv,
+		      struct iwl_rx_packet *pkt,
+		      struct ieee80211_hdr *header, int group100)
+{
+	u32 to_us;
+	u32 print_summary = 0;
+	u32 print_dump = 0;	/* set to 1 to dump all frames' contents */
+	u32 hundred = 0;
+	u32 dataframe = 0;
+	u16 fc;
+	u16 seq_ctl;
+	u16 channel;
+	u16 phy_flags;
+	int rate_sym;
+	u16 length;
+	u16 status;
+	u16 bcn_tmr;
+	u32 tsf_low;
+	u64 tsf;
+	u8 rssi;
+	u8 agc;
+	u16 sig_avg;
+	u16 noise_diff;
+	struct iwl_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
+	struct iwl_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
+	struct iwl_rx_frame_end *rx_end = IWL_RX_END(pkt);
+	u8 *data = IWL_RX_DATA(pkt);
+
+	/* MAC header */
+	fc = le16_to_cpu(header->frame_control);
+	seq_ctl = le16_to_cpu(header->seq_ctrl);
+
+	/* metadata */
+	channel = le16_to_cpu(rx_hdr->channel);
+	phy_flags = le16_to_cpu(rx_hdr->phy_flags);
+	rate_sym = rx_hdr->rate;
+	length = le16_to_cpu(rx_hdr->len);
+
+	/* end-of-frame status and timestamp */
+	status = le32_to_cpu(rx_end->status);
+	bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
+	tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
+	tsf = le64_to_cpu(rx_end->timestamp);
+
+	/* signal statistics */
+	rssi = rx_stats->rssi;
+	agc = rx_stats->agc;
+	sig_avg = le16_to_cpu(rx_stats->sig_avg);
+	noise_diff = le16_to_cpu(rx_stats->noise_diff);
+
+	to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
+
+	/* if data frame is to us and all is good,
+	 *   (optionally) print summary for only 1 out of every 100 */
+	if (to_us && (fc & ~IEEE80211_FCTL_PROTECTED) ==
+	    (IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
+		dataframe = 1;
+		if (!group100)
+			print_summary = 1;	/* print each frame */
+		else if (priv->framecnt_to_us < 100) {
+			priv->framecnt_to_us++;
+			print_summary = 0;
+		} else {
+			priv->framecnt_to_us = 0;
+			print_summary = 1;
+			hundred = 1;
+		}
+	} else {
+		/* print summary for all other frames */
+		print_summary = 1;
+	}
+
+	if (print_summary) {
+		char *title;
+		u32 rate;
+
+		if (hundred)
+			title = "100Frames";
+		else if (fc & IEEE80211_FCTL_RETRY)
+			title = "Retry";
+		else if (ieee80211_is_assoc_response(fc))
+			title = "AscRsp";
+		else if (ieee80211_is_reassoc_response(fc))
+			title = "RasRsp";
+		else if (ieee80211_is_probe_response(fc)) {
+			title = "PrbRsp";
+			print_dump = 1;	/* dump frame contents */
+		} else if (ieee80211_is_beacon(fc)) {
+			title = "Beacon";
+			print_dump = 1;	/* dump frame contents */
+		} else if (ieee80211_is_atim(fc))
+			title = "ATIM";
+		else if (ieee80211_is_auth(fc))
+			title = "Auth";
+		else if (ieee80211_is_deauth(fc))
+			title = "DeAuth";
+		else if (ieee80211_is_disassoc(fc))
+			title = "DisAssoc";
+		else
+			title = "Frame";
+
+		rate = iwl_rate_index_from_plcp(rate_sym);
+		if (rate == -1)
+			rate = 0;
+		else
+			rate = iwl_rates[rate].ieee / 2;
+
+		/* print frame summary.
+		 * MAC addresses show just the last byte (for brevity),
+		 *    but you can hack it to show more, if you'd like to. */
+		if (dataframe)
+			IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, "
+				     "len=%u, rssi=%d, chnl=%d, rate=%u, \n",
+				     title, fc, header->addr1[5],
+				     length, rssi, channel, rate);
+		else {
+			/* src/dst addresses assume managed mode */
+			IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, "
+				     "src=0x%02x, rssi=%u, tim=%lu usec, "
+				     "phy=0x%02x, chnl=%d\n",
+				     title, fc, header->addr1[5],
+				     header->addr3[5], rssi,
+				     tsf_low - priv->scan_start_tsf,
+				     phy_flags, channel);
+		}
+	}
+	if (print_dump)
+		iwl_print_hex_dump(IWL_DL_RX, data, length);
+}
+#endif
+
+static void iwl_unset_hw_setting(struct iwl_priv *priv)
+{
+	if (priv->hw_setting.shared_virt)
+		pci_free_consistent(priv->pci_dev,
+				    sizeof(struct iwl_shared),
+				    priv->hw_setting.shared_virt,
+				    priv->hw_setting.shared_phys);
+}
+
+/**
+ * iwl_supported_rate_to_ie - fill in the supported rate in IE field
+ *
+ * return : set the bit for each supported rate insert in ie
+ */
+static u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate,
+				    u16 basic_rate, int max_count)
+{
+	u16 ret_rates = 0, bit;
+	int i;
+	u8 *rates;
+
+	rates = &(ie[1]);
+
+	for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) {
+		if (bit & supported_rate) {
+			ret_rates |= bit;
+			rates[*ie] = iwl_rates[i].ieee |
+			    ((bit & basic_rate) ? 0x80 : 0x00);
+			*ie = *ie + 1;
+			if (*ie >= max_count)
+				break;
+		}
+	}
+
+	return ret_rates;
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+void static iwl_set_ht_capab(struct ieee80211_hw *hw,
+			     struct ieee80211_ht_capability *ht_cap,
+			     u8 use_wide_chan);
+#endif
+
+/**
+ * iwl_fill_probe_req - fill in all required fields and IE for probe request
+ */
+static u16 iwl_fill_probe_req(struct iwl_priv *priv,
+			      struct ieee80211_mgmt *frame,
+			      int left, int is_direct)
+{
+	int len = 0;
+	u8 *pos = NULL;
+	u16 ret_rates;
+
+	/* Make sure there is enough space for the probe request,
+	 * two mandatory IEs and the data */
+	left -= 24;
+	if (left < 0)
+		return 0;
+	len += 24;
+
+	frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
+	memcpy(frame->da, BROADCAST_ADDR, ETH_ALEN);
+	memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
+	memcpy(frame->bssid, BROADCAST_ADDR, ETH_ALEN);
+	frame->seq_ctrl = 0;
+
+	/* fill in our indirect SSID IE */
+	/* ...next IE... */
+
+	left -= 2;
+	if (left < 0)
+		return 0;
+	len += 2;
+	pos = &(frame->u.probe_req.variable[0]);
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = 0;
+
+	/* fill in our direct SSID IE... */
+	if (is_direct) {
+		/* ...next IE... */
+		left -= 2 + priv->essid_len;
+		if (left < 0)
+			return 0;
+		/* ... fill it in... */
+		*pos++ = WLAN_EID_SSID;
+		*pos++ = priv->essid_len;
+		memcpy(pos, priv->essid, priv->essid_len);
+		pos += priv->essid_len;
+		len += 2 + priv->essid_len;
+	}
+
+	/* fill in supported rate */
+	/* ...next IE... */
+	left -= 2;
+	if (left < 0)
+		return 0;
+	/* ... fill it in... */
+	*pos++ = WLAN_EID_SUPP_RATES;
+	*pos = 0;
+	ret_rates = priv->active_rate = priv->rates_mask;
+	priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+
+	iwl_supported_rate_to_ie(pos, priv->active_rate,
+				 priv->active_rate_basic, left);
+	len += 2 + *pos;
+	pos += (*pos) + 1;
+	ret_rates = ~ret_rates & priv->active_rate;
+
+	if (ret_rates == 0)
+		goto fill_end;
+
+	/* fill in supported extended rate */
+	/* ...next IE... */
+	left -= 2;
+	if (left < 0)
+		return 0;
+	/* ... fill it in... */
+	*pos++ = WLAN_EID_EXT_SUPP_RATES;
+	*pos = 0;
+	iwl_supported_rate_to_ie(pos, ret_rates, priv->active_rate_basic, left);
+	if (*pos > 0)
+		len += 2 + *pos;
+
+#ifdef CONFIG_IWLWIFI_HT
+	if (is_direct && priv->is_ht_enabled) {
+		u8 use_wide_chan = 1;
+
+		if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
+			use_wide_chan = 0;
+		pos += (*pos) + 1;
+		*pos++ = WLAN_EID_HT_CAPABILITY;
+		*pos++ = sizeof(struct ieee80211_ht_capability);
+		iwl_set_ht_capab(NULL, (struct ieee80211_ht_capability *)pos,
+				 use_wide_chan);
+		len += 2 + sizeof(struct ieee80211_ht_capability);
+	}
+#endif  /*CONFIG_IWLWIFI_HT */
+
+ fill_end:
+	return (u16)len;
+}
+
+/*
+ * QoS  support
+*/
+#ifdef CONFIG_IWLWIFI_QOS
+static int iwl_send_qos_params_command(struct iwl_priv *priv,
+				       struct iwl_qosparam_cmd *qos)
+{
+
+	return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM,
+				sizeof(struct iwl_qosparam_cmd), qos);
+}
+
+static void iwl_reset_qos(struct iwl_priv *priv)
+{
+	u16 cw_min = 15;
+	u16 cw_max = 1023;
+	u8 aifs = 2;
+	u8 is_legacy = 0;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->qos_data.qos_active = 0;
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS) {
+		if (priv->qos_data.qos_enable)
+			priv->qos_data.qos_active = 1;
+		if (!(priv->active_rate & 0xfff0)) {
+			cw_min = 31;
+			is_legacy = 1;
+		}
+	} else if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		if (priv->qos_data.qos_enable)
+			priv->qos_data.qos_active = 1;
+	} else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) {
+		cw_min = 31;
+		is_legacy = 1;
+	}
+
+	if (priv->qos_data.qos_active)
+		aifs = 3;
+
+	priv->qos_data.def_qos_parm.ac[0].cw_min = cpu_to_le16(cw_min);
+	priv->qos_data.def_qos_parm.ac[0].cw_max = cpu_to_le16(cw_max);
+	priv->qos_data.def_qos_parm.ac[0].aifsn = aifs;
+	priv->qos_data.def_qos_parm.ac[0].edca_txop = 0;
+	priv->qos_data.def_qos_parm.ac[0].reserved1 = 0;
+
+	if (priv->qos_data.qos_active) {
+		i = 1;
+		priv->qos_data.def_qos_parm.ac[i].cw_min = cpu_to_le16(cw_min);
+		priv->qos_data.def_qos_parm.ac[i].cw_max = cpu_to_le16(cw_max);
+		priv->qos_data.def_qos_parm.ac[i].aifsn = 7;
+		priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+		priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+		i = 2;
+		priv->qos_data.def_qos_parm.ac[i].cw_min =
+			cpu_to_le16((cw_min + 1) / 2 - 1);
+		priv->qos_data.def_qos_parm.ac[i].cw_max =
+			cpu_to_le16(cw_max);
+		priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+		if (is_legacy)
+			priv->qos_data.def_qos_parm.ac[i].edca_txop =
+				cpu_to_le16(6016);
+		else
+			priv->qos_data.def_qos_parm.ac[i].edca_txop =
+				cpu_to_le16(3008);
+		priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+
+		i = 3;
+		priv->qos_data.def_qos_parm.ac[i].cw_min =
+			cpu_to_le16((cw_min + 1) / 4 - 1);
+		priv->qos_data.def_qos_parm.ac[i].cw_max =
+			cpu_to_le16((cw_max + 1) / 2 - 1);
+		priv->qos_data.def_qos_parm.ac[i].aifsn = 2;
+		priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+		if (is_legacy)
+			priv->qos_data.def_qos_parm.ac[i].edca_txop =
+				cpu_to_le16(3264);
+		else
+			priv->qos_data.def_qos_parm.ac[i].edca_txop =
+				cpu_to_le16(1504);
+	} else {
+		for (i = 1; i < 4; i++) {
+			priv->qos_data.def_qos_parm.ac[i].cw_min =
+				cpu_to_le16(cw_min);
+			priv->qos_data.def_qos_parm.ac[i].cw_max =
+				cpu_to_le16(cw_max);
+			priv->qos_data.def_qos_parm.ac[i].aifsn = aifs;
+			priv->qos_data.def_qos_parm.ac[i].edca_txop = 0;
+			priv->qos_data.def_qos_parm.ac[i].reserved1 = 0;
+		}
+	}
+	IWL_DEBUG_QOS("set QoS to default \n");
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
+{
+	unsigned long flags;
+
+	if (priv == NULL)
+		return;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	if (!priv->qos_data.qos_enable)
+		return;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->qos_data.def_qos_parm.qos_flags = 0;
+
+	if (priv->qos_data.qos_cap.q_AP.queue_request &&
+	    !priv->qos_data.qos_cap.q_AP.txop_request)
+		priv->qos_data.def_qos_parm.qos_flags |=
+			QOS_PARAM_FLG_TXOP_TYPE_MSK;
+
+	if (priv->qos_data.qos_active)
+		priv->qos_data.def_qos_parm.qos_flags |=
+			QOS_PARAM_FLG_UPDATE_EDCA_MSK;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (force || iwl_is_associated(priv)) {
+		IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n",
+			      priv->qos_data.qos_active);
+
+		iwl_send_qos_params_command(priv,
+				&(priv->qos_data.def_qos_parm));
+	}
+}
+
+#endif /* CONFIG_IWLWIFI_QOS */
+/*
+ * Power management (not Tx power!) functions
+ */
+#define MSEC_TO_USEC 1024
+
+#define NOSLP __constant_cpu_to_le16(0), 0, 0
+#define SLP IWL_POWER_DRIVER_ALLOW_SLEEP_MSK, 0, 0
+#define SLP_TIMEOUT(T) __constant_cpu_to_le32((T) * MSEC_TO_USEC)
+#define SLP_VEC(X0, X1, X2, X3, X4) {__constant_cpu_to_le32(X0), \
+				     __constant_cpu_to_le32(X1), \
+				     __constant_cpu_to_le32(X2), \
+				     __constant_cpu_to_le32(X3), \
+				     __constant_cpu_to_le32(X4)}
+
+
+/* default power management (not Tx power) table values */
+/* for tim  0-10 */
+static struct iwl_power_vec_entry range_0[IWL_POWER_AC] = {
+	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0},
+	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300), SLP_VEC(2, 4, 6, 7, 7)}, 0},
+	{{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100), SLP_VEC(2, 6, 9, 9, 10)}, 0},
+	{{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 10)}, 1},
+	{{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1}
+};
+
+/* for tim > 10 */
+static struct iwl_power_vec_entry range_1[IWL_POWER_AC] = {
+	{{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0},
+	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500),
+		 SLP_VEC(1, 2, 3, 4, 0xFF)}, 0},
+	{{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(300),
+		 SLP_VEC(2, 4, 6, 7, 0xFF)}, 0},
+	{{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(100),
+		 SLP_VEC(2, 6, 9, 9, 0xFF)}, 0},
+	{{SLP, SLP_TIMEOUT(50), SLP_TIMEOUT(25), SLP_VEC(2, 7, 9, 9, 0xFF)}, 0},
+	{{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25),
+		 SLP_VEC(4, 7, 10, 10, 0xFF)}, 0}
+};
+
+int iwl_power_init_handle(struct iwl_priv *priv)
+{
+	int rc = 0, i;
+	struct iwl_power_mgr *pow_data;
+	int size = sizeof(struct iwl_power_vec_entry) * IWL_POWER_AC;
+	u16 pci_pm;
+
+	IWL_DEBUG_POWER("Initialize power \n");
+
+	pow_data = &(priv->power_data);
+
+	memset(pow_data, 0, sizeof(*pow_data));
+
+	pow_data->active_index = IWL_POWER_RANGE_0;
+	pow_data->dtim_val = 0xffff;
+
+	memcpy(&pow_data->pwr_range_0[0], &range_0[0], size);
+	memcpy(&pow_data->pwr_range_1[0], &range_1[0], size);
+
+	rc = pci_read_config_word(priv->pci_dev, PCI_LINK_CTRL, &pci_pm);
+	if (rc != 0)
+		return 0;
+	else {
+		struct iwl_powertable_cmd *cmd;
+
+		IWL_DEBUG_POWER("adjust power command flags\n");
+
+		for (i = 0; i < IWL_POWER_AC; i++) {
+			cmd = &pow_data->pwr_range_0[i].cmd;
+
+			if (pci_pm & 0x1)
+				cmd->flags &= ~IWL_POWER_PCI_PM_MSK;
+			else
+				cmd->flags |= IWL_POWER_PCI_PM_MSK;
+		}
+	}
+	return rc;
+}
+
+static int iwl_update_power_cmd(struct iwl_priv *priv,
+				struct iwl_powertable_cmd *cmd, u32 mode)
+{
+	int rc = 0, i;
+	u8 skip;
+	u32 max_sleep = 0;
+	struct iwl_power_vec_entry *range;
+	u8 period = 0;
+	struct iwl_power_mgr *pow_data;
+
+	if (mode > IWL_POWER_INDEX_5) {
+		IWL_DEBUG_POWER("Error invalid power mode \n");
+		return -1;
+	}
+	pow_data = &(priv->power_data);
+
+	if (pow_data->active_index == IWL_POWER_RANGE_0)
+		range = &pow_data->pwr_range_0[0];
+	else
+		range = &pow_data->pwr_range_1[1];
+
+	memcpy(cmd, &range[mode].cmd, sizeof(struct iwl_powertable_cmd));
+
+#ifdef IWL_MAC80211_DISABLE
+	if (priv->assoc_network != NULL) {
+		unsigned long flags;
+
+		period = priv->assoc_network->tim.tim_period;
+	}
+#endif	/*IWL_MAC80211_DISABLE */
+	skip = range[mode].no_dtim;
+
+	if (period == 0) {
+		period = 1;
+		skip = 0;
+	}
+
+	if (skip == 0) {
+		max_sleep = period;
+		cmd->flags &= ~IWL_POWER_SLEEP_OVER_DTIM_MSK;
+	} else {
+		__le32 slp_itrvl = cmd->sleep_interval[IWL_POWER_VEC_SIZE - 1];
+		max_sleep = (le32_to_cpu(slp_itrvl) / period) * period;
+		cmd->flags |= IWL_POWER_SLEEP_OVER_DTIM_MSK;
+	}
+
+	for (i = 0; i < IWL_POWER_VEC_SIZE; i++) {
+		if (le32_to_cpu(cmd->sleep_interval[i]) > max_sleep)
+			cmd->sleep_interval[i] = cpu_to_le32(max_sleep);
+	}
+
+	IWL_DEBUG_POWER("Flags value = 0x%08X\n", cmd->flags);
+	IWL_DEBUG_POWER("Tx timeout = %u\n", le32_to_cpu(cmd->tx_data_timeout));
+	IWL_DEBUG_POWER("Rx timeout = %u\n", le32_to_cpu(cmd->rx_data_timeout));
+	IWL_DEBUG_POWER("Sleep interval vector = { %d , %d , %d , %d , %d }\n",
+			le32_to_cpu(cmd->sleep_interval[0]),
+			le32_to_cpu(cmd->sleep_interval[1]),
+			le32_to_cpu(cmd->sleep_interval[2]),
+			le32_to_cpu(cmd->sleep_interval[3]),
+			le32_to_cpu(cmd->sleep_interval[4]));
+
+	return rc;
+}
+
+static int iwl_send_power_mode(struct iwl_priv *priv, u32 mode)
+{
+	u32 final_mode = mode;
+	int rc;
+	struct iwl_powertable_cmd cmd;
+
+	/* If on battery, set to 3,
+	 * if plugged into AC power, set to CAM ("continuosly aware mode"),
+	 * else user level */
+	switch (mode) {
+	case IWL_POWER_BATTERY:
+		final_mode = IWL_POWER_INDEX_3;
+		break;
+	case IWL_POWER_AC:
+		final_mode = IWL_POWER_MODE_CAM;
+		break;
+	default:
+		final_mode = mode;
+		break;
+	}
+
+	cmd.keep_alive_beacons = 0;
+
+	iwl_update_power_cmd(priv, &cmd, final_mode);
+
+	rc = iwl_send_cmd_pdu(priv, POWER_TABLE_CMD, sizeof(cmd), &cmd);
+
+	if (final_mode == IWL_POWER_MODE_CAM)
+		clear_bit(STATUS_POWER_PMI, &priv->status);
+	else
+		set_bit(STATUS_POWER_PMI, &priv->status);
+
+	return rc;
+}
+
+int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+{
+	/* Filter incoming packets to determine if they are targeted toward
+	 * this network, discarding packets coming from ourselves */
+	switch (priv->iw_mode) {
+	case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source    | BSSID */
+		/* packets from our adapter are dropped (echo) */
+		if (!compare_ether_addr(header->addr2, priv->mac_addr))
+			return 0;
+		/* {broad,multi}cast packets to our IBSS go through */
+		if (is_multicast_ether_addr(header->addr1))
+			return !compare_ether_addr(header->addr3, priv->bssid);
+		/* packets to our adapter go through */
+		return !compare_ether_addr(header->addr1, priv->mac_addr);
+	case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */
+		/* packets from our adapter are dropped (echo) */
+		if (!compare_ether_addr(header->addr3, priv->mac_addr))
+			return 0;
+		/* {broad,multi}cast packets to our BSS go through */
+		if (is_multicast_ether_addr(header->addr1))
+			return !compare_ether_addr(header->addr2, priv->bssid);
+		/* packets to our adapter go through */
+		return !compare_ether_addr(header->addr1, priv->mac_addr);
+	}
+
+	return 1;
+}
+
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+const char *iwl_get_tx_fail_reason(u32 status)
+{
+	switch (status & TX_STATUS_MSK) {
+	case TX_STATUS_SUCCESS:
+		return "SUCCESS";
+		TX_STATUS_ENTRY(SHORT_LIMIT);
+		TX_STATUS_ENTRY(LONG_LIMIT);
+		TX_STATUS_ENTRY(FIFO_UNDERRUN);
+		TX_STATUS_ENTRY(MGMNT_ABORT);
+		TX_STATUS_ENTRY(NEXT_FRAG);
+		TX_STATUS_ENTRY(LIFE_EXPIRE);
+		TX_STATUS_ENTRY(DEST_PS);
+		TX_STATUS_ENTRY(ABORTED);
+		TX_STATUS_ENTRY(BT_RETRY);
+		TX_STATUS_ENTRY(STA_INVALID);
+		TX_STATUS_ENTRY(FRAG_DROPPED);
+		TX_STATUS_ENTRY(TID_DISABLE);
+		TX_STATUS_ENTRY(FRAME_FLUSHED);
+		TX_STATUS_ENTRY(INSUFFICIENT_CF_POLL);
+		TX_STATUS_ENTRY(TX_LOCKED);
+		TX_STATUS_ENTRY(NO_BEACON_ON_RADAR);
+	}
+
+	return "UNKNOWN";
+}
+
+/**
+ * iwl_scan_cancel - Cancel any currently executing HW scan
+ *
+ * NOTE: priv->mutex is not required before calling this function
+ */
+static int iwl_scan_cancel(struct iwl_priv *priv)
+{
+	if (!test_bit(STATUS_SCAN_HW, &priv->status)) {
+		clear_bit(STATUS_SCANNING, &priv->status);
+		return 0;
+	}
+
+	if (test_bit(STATUS_SCANNING, &priv->status)) {
+		if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+			IWL_DEBUG_SCAN("Queuing scan abort.\n");
+			set_bit(STATUS_SCAN_ABORTING, &priv->status);
+			queue_work(priv->workqueue, &priv->abort_scan);
+
+		} else
+			IWL_DEBUG_SCAN("Scan abort already in progress.\n");
+
+		return test_bit(STATUS_SCANNING, &priv->status);
+	}
+
+	return 0;
+}
+
+/**
+ * iwl_scan_cancel_timeout - Cancel any currently executing HW scan
+ * @ms: amount of time to wait (in milliseconds) for scan to abort
+ *
+ * NOTE: priv->mutex must be held before calling this function
+ */
+static int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
+{
+	unsigned long now = jiffies;
+	int ret;
+
+	ret = iwl_scan_cancel(priv);
+	if (ret && ms) {
+		mutex_unlock(&priv->mutex);
+		while (!time_after(jiffies, now + msecs_to_jiffies(ms)) &&
+				test_bit(STATUS_SCANNING, &priv->status))
+			msleep(1);
+		mutex_lock(&priv->mutex);
+
+		return test_bit(STATUS_SCANNING, &priv->status);
+	}
+
+	return ret;
+}
+
+static void iwl_sequence_reset(struct iwl_priv *priv)
+{
+	/* Reset ieee stats */
+
+	/* We don't reset the net_device_stats (ieee->stats) on
+	 * re-association */
+
+	priv->last_seq_num = -1;
+	priv->last_frag_num = -1;
+	priv->last_packet_time = 0;
+
+	iwl_scan_cancel(priv);
+}
+
+#define MAX_UCODE_BEACON_INTERVAL	4096
+#define INTEL_CONN_LISTEN_INTERVAL	__constant_cpu_to_le16(0xA)
+
+static __le16 iwl_adjust_beacon_interval(u16 beacon_val)
+{
+	u16 new_val = 0;
+	u16 beacon_factor = 0;
+
+	beacon_factor =
+	    (beacon_val + MAX_UCODE_BEACON_INTERVAL)
+		/ MAX_UCODE_BEACON_INTERVAL;
+	new_val = beacon_val / beacon_factor;
+
+	return cpu_to_le16(new_val);
+}
+
+static void iwl_setup_rxon_timing(struct iwl_priv *priv)
+{
+	u64 interval_tm_unit;
+	u64 tsf, result;
+	unsigned long flags;
+	struct ieee80211_conf *conf = NULL;
+	u16 beacon_int = 0;
+
+	conf = ieee80211_get_hw_conf(priv->hw);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp1);
+	priv->rxon_timing.timestamp.dw[0] = cpu_to_le32(priv->timestamp0);
+
+	priv->rxon_timing.listen_interval = INTEL_CONN_LISTEN_INTERVAL;
+
+	tsf = priv->timestamp1;
+	tsf = ((tsf << 32) | priv->timestamp0);
+
+	beacon_int = priv->beacon_int;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_STA) {
+		if (beacon_int == 0) {
+			priv->rxon_timing.beacon_interval = cpu_to_le16(100);
+			priv->rxon_timing.beacon_init_val = cpu_to_le32(102400);
+		} else {
+			priv->rxon_timing.beacon_interval =
+				cpu_to_le16(beacon_int);
+			priv->rxon_timing.beacon_interval =
+			    iwl_adjust_beacon_interval(
+				le16_to_cpu(priv->rxon_timing.beacon_interval));
+		}
+
+		priv->rxon_timing.atim_window = 0;
+	} else {
+		priv->rxon_timing.beacon_interval =
+			iwl_adjust_beacon_interval(conf->beacon_int);
+		/* TODO: we need to get atim_window from upper stack
+		 * for now we set to 0 */
+		priv->rxon_timing.atim_window = 0;
+	}
+
+	interval_tm_unit =
+		(le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024);
+	result = do_div(tsf, interval_tm_unit);
+	priv->rxon_timing.beacon_init_val =
+	    cpu_to_le32((u32) ((u64) interval_tm_unit - result));
+
+	IWL_DEBUG_ASSOC
+	    ("beacon interval %d beacon timer %d beacon tim %d\n",
+		le16_to_cpu(priv->rxon_timing.beacon_interval),
+		le32_to_cpu(priv->rxon_timing.beacon_init_val),
+		le16_to_cpu(priv->rxon_timing.atim_window));
+}
+
+static int iwl_scan_initiate(struct iwl_priv *priv)
+{
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		IWL_ERROR("APs don't scan.\n");
+		return 0;
+	}
+
+	if (!iwl_is_ready_rf(priv)) {
+		IWL_DEBUG_SCAN("Aborting scan due to not ready.\n");
+		return -EIO;
+	}
+
+	if (test_bit(STATUS_SCANNING, &priv->status)) {
+		IWL_DEBUG_SCAN("Scan already in progress.\n");
+		return -EAGAIN;
+	}
+
+	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG_SCAN("Scan request while abort pending.  "
+			       "Queuing.\n");
+		return -EAGAIN;
+	}
+
+	IWL_DEBUG_INFO("Starting scan...\n");
+	priv->scan_bands = 2;
+	set_bit(STATUS_SCANNING, &priv->status);
+	priv->scan_start = jiffies;
+	priv->scan_pass_start = priv->scan_start;
+
+	queue_work(priv->workqueue, &priv->request_scan);
+
+	return 0;
+}
+
+static int iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+{
+	struct iwl_rxon_cmd *rxon = &priv->staging_rxon;
+
+	if (hw_decrypt)
+		rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
+	else
+		rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
+
+	return 0;
+}
+
+static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode)
+{
+	if (phymode == MODE_IEEE80211A) {
+		priv->staging_rxon.flags &=
+		    ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK
+		      | RXON_FLG_CCK_MSK);
+		priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+	} else {
+		/* Copied from iwl_bg_post_associate() */
+		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+		else
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+		if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+		priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
+		priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK;
+		priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
+	}
+}
+
+/*
+ * initilize rxon structure with default values fromm eeprom
+ */
+static void iwl_connection_init_rx_config(struct iwl_priv *priv)
+{
+	const struct iwl_channel_info *ch_info;
+
+	memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon));
+
+	switch (priv->iw_mode) {
+	case IEEE80211_IF_TYPE_AP:
+		priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP;
+		break;
+
+	case IEEE80211_IF_TYPE_STA:
+		priv->staging_rxon.dev_type = RXON_DEV_TYPE_ESS;
+		priv->staging_rxon.filter_flags = RXON_FILTER_ACCEPT_GRP_MSK;
+		break;
+
+	case IEEE80211_IF_TYPE_IBSS:
+		priv->staging_rxon.dev_type = RXON_DEV_TYPE_IBSS;
+		priv->staging_rxon.flags = RXON_FLG_SHORT_PREAMBLE_MSK;
+		priv->staging_rxon.filter_flags = RXON_FILTER_BCON_AWARE_MSK |
+						  RXON_FILTER_ACCEPT_GRP_MSK;
+		break;
+
+	case IEEE80211_IF_TYPE_MNTR:
+		priv->staging_rxon.dev_type = RXON_DEV_TYPE_SNIFFER;
+		priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK |
+		    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
+		break;
+	}
+
+#if 0
+	/* TODO:  Figure out when short_preamble would be set and cache from
+	 * that */
+	if (!hw_to_local(priv->hw)->short_preamble)
+		priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+	else
+		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+#endif
+
+	ch_info = iwl_get_channel_info(priv, priv->phymode,
+				       le16_to_cpu(priv->staging_rxon.channel));
+
+	if (!ch_info)
+		ch_info = &priv->channel_info[0];
+
+	/*
+	 * in some case A channels are all non IBSS
+	 * in this case force B/G channel
+	 */
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) &&
+	    !(is_channel_ibss(ch_info)))
+		ch_info = &priv->channel_info[0];
+
+	priv->staging_rxon.channel = cpu_to_le16(ch_info->channel);
+	if (is_channel_a_band(ch_info))
+		priv->phymode = MODE_IEEE80211A;
+	else
+		priv->phymode = MODE_IEEE80211G;
+
+	iwl_set_flags_for_phymode(priv, priv->phymode);
+
+	priv->staging_rxon.ofdm_basic_rates =
+	    (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+	priv->staging_rxon.cck_basic_rates =
+	    (IWL_CCK_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+
+	priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK |
+					RXON_FLG_CHANNEL_MODE_PURE_40_MSK);
+	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+	memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN);
+	priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
+	priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff;
+	iwl4965_set_rxon_chain(priv);
+}
+
+static int iwl_set_mode(struct iwl_priv *priv, int mode)
+{
+	if (!iwl_is_ready_rf(priv))
+		return -EAGAIN;
+
+	if (mode == IEEE80211_IF_TYPE_IBSS) {
+		const struct iwl_channel_info *ch_info;
+
+		ch_info = iwl_get_channel_info(priv,
+			priv->phymode,
+			le16_to_cpu(priv->staging_rxon.channel));
+
+		if (!ch_info || !is_channel_ibss(ch_info)) {
+			IWL_ERROR("channel %d not IBSS channel\n",
+				  le16_to_cpu(priv->staging_rxon.channel));
+			return -EINVAL;
+		}
+	}
+
+	cancel_delayed_work(&priv->scan_check);
+	if (iwl_scan_cancel_timeout(priv, 100)) {
+		IWL_WARNING("Aborted scan still in progress after 100ms\n");
+		IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
+		return -EAGAIN;
+	}
+
+	priv->iw_mode = mode;
+
+	iwl_connection_init_rx_config(priv);
+	memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+
+	iwl_clear_stations_table(priv);
+
+	iwl_commit_rxon(priv);
+
+	return 0;
+}
+
+static void iwl_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
+				      struct ieee80211_tx_control *ctl,
+				      struct iwl_cmd *cmd,
+				      struct sk_buff *skb_frag,
+				      int last_frag)
+{
+	struct iwl_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo;
+
+	switch (keyinfo->alg) {
+	case ALG_CCMP:
+		cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM;
+		memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen);
+		IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n");
+		break;
+
+	case ALG_TKIP:
+#if 0
+		cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP;
+
+		if (last_frag)
+			memcpy(cmd->cmd.tx.tkip_mic.byte, skb_frag->tail - 8,
+			       8);
+		else
+			memset(cmd->cmd.tx.tkip_mic.byte, 0, 8);
+#endif
+		break;
+
+	case ALG_WEP:
+		cmd->cmd.tx.sec_ctl = TX_CMD_SEC_WEP |
+			(ctl->key_idx & TX_CMD_SEC_MSK) << TX_CMD_SEC_SHIFT;
+
+		if (keyinfo->keylen == 13)
+			cmd->cmd.tx.sec_ctl |= TX_CMD_SEC_KEY128;
+
+		memcpy(&cmd->cmd.tx.key[3], keyinfo->key, keyinfo->keylen);
+
+		IWL_DEBUG_TX("Configuring packet for WEP encryption "
+			     "with key %d\n", ctl->key_idx);
+		break;
+
+	default:
+		printk(KERN_ERR "Unknown encode alg %d\n", keyinfo->alg);
+		break;
+	}
+}
+
+/*
+ * handle build REPLY_TX command notification.
+ */
+static void iwl_build_tx_cmd_basic(struct iwl_priv *priv,
+				  struct iwl_cmd *cmd,
+				  struct ieee80211_tx_control *ctrl,
+				  struct ieee80211_hdr *hdr,
+				  int is_unicast, u8 std_id)
+{
+	__le16 *qc;
+	u16 fc = le16_to_cpu(hdr->frame_control);
+	__le32 tx_flags = cmd->cmd.tx.tx_flags;
+
+	cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+	if (!(ctrl->flags & IEEE80211_TXCTL_NO_ACK)) {
+		tx_flags |= TX_CMD_FLG_ACK_MSK;
+		if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)
+			tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+		if (ieee80211_is_probe_response(fc) &&
+		    !(le16_to_cpu(hdr->seq_ctrl) & 0xf))
+			tx_flags |= TX_CMD_FLG_TSF_MSK;
+	} else {
+		tx_flags &= (~TX_CMD_FLG_ACK_MSK);
+		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+	}
+
+	cmd->cmd.tx.sta_id = std_id;
+	if (ieee80211_get_morefrag(hdr))
+		tx_flags |= TX_CMD_FLG_MORE_FRAG_MSK;
+
+	qc = ieee80211_get_qos_ctrl(hdr);
+	if (qc) {
+		cmd->cmd.tx.tid_tspec = (u8) (le16_to_cpu(*qc) & 0xf);
+		tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK;
+	} else
+		tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK;
+
+	if (ctrl->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+		tx_flags |= TX_CMD_FLG_RTS_MSK;
+		tx_flags &= ~TX_CMD_FLG_CTS_MSK;
+	} else if (ctrl->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) {
+		tx_flags &= ~TX_CMD_FLG_RTS_MSK;
+		tx_flags |= TX_CMD_FLG_CTS_MSK;
+	}
+
+	if ((tx_flags & TX_CMD_FLG_RTS_MSK) || (tx_flags & TX_CMD_FLG_CTS_MSK))
+		tx_flags |= TX_CMD_FLG_FULL_TXOP_PROT_MSK;
+
+	tx_flags &= ~(TX_CMD_FLG_ANT_SEL_MSK);
+	if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) {
+		if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_ASSOC_REQ ||
+		    (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_REASSOC_REQ)
+			cmd->cmd.tx.timeout.pm_frame_timeout =
+				cpu_to_le16(3);
+		else
+			cmd->cmd.tx.timeout.pm_frame_timeout =
+				cpu_to_le16(2);
+	} else
+		cmd->cmd.tx.timeout.pm_frame_timeout = 0;
+
+	cmd->cmd.tx.driver_txop = 0;
+	cmd->cmd.tx.tx_flags = tx_flags;
+	cmd->cmd.tx.next_frame_len = 0;
+}
+
+static int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr)
+{
+	int sta_id;
+	u16 fc = le16_to_cpu(hdr->frame_control);
+	DECLARE_MAC_BUF(mac);
+
+	/* If this frame is broadcast or not data then use the broadcast
+	 * station id */
+	if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
+	    is_multicast_ether_addr(hdr->addr1))
+		return priv->hw_setting.bcast_sta_id;
+
+	switch (priv->iw_mode) {
+
+	/* If this frame is part of a BSS network (we're a station), then
+	 * we use the AP's station id */
+	case IEEE80211_IF_TYPE_STA:
+		return IWL_AP_ID;
+
+	/* If we are an AP, then find the station, or use BCAST */
+	case IEEE80211_IF_TYPE_AP:
+		sta_id = iwl_hw_find_station(priv, hdr->addr1);
+		if (sta_id != IWL_INVALID_STATION)
+			return sta_id;
+		return priv->hw_setting.bcast_sta_id;
+
+	/* If this frame is part of a IBSS network, then we use the
+	 * target specific station id */
+	case IEEE80211_IF_TYPE_IBSS:
+		sta_id = iwl_hw_find_station(priv, hdr->addr1);
+		if (sta_id != IWL_INVALID_STATION)
+			return sta_id;
+
+		sta_id = iwl_add_station(priv, hdr->addr1, 0, CMD_ASYNC);
+
+		if (sta_id != IWL_INVALID_STATION)
+			return sta_id;
+
+		IWL_DEBUG_DROP("Station %s not in station map. "
+			       "Defaulting to broadcast...\n",
+			       print_mac(mac, hdr->addr1));
+		iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
+		return priv->hw_setting.bcast_sta_id;
+
+	default:
+		IWL_WARNING("Unkown mode of operation: %d", priv->iw_mode);
+		return priv->hw_setting.bcast_sta_id;
+	}
+}
+
+/*
+ * start REPLY_TX command process
+ */
+static int iwl_tx_skb(struct iwl_priv *priv,
+		      struct sk_buff *skb, struct ieee80211_tx_control *ctl)
+{
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+	struct iwl_tfd_frame *tfd;
+	u32 *control_flags;
+	int txq_id = ctl->queue;
+	struct iwl_tx_queue *txq = NULL;
+	struct iwl_queue *q = NULL;
+	dma_addr_t phys_addr;
+	dma_addr_t txcmd_phys;
+	struct iwl_cmd *out_cmd = NULL;
+	u16 len, idx, len_org;
+	u8 id, hdr_len, unicast;
+	u8 sta_id;
+	u16 seq_number = 0;
+	u16 fc;
+	__le16 *qc;
+	u8 wait_write_ptr = 0;
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (iwl_is_rfkill(priv)) {
+		IWL_DEBUG_DROP("Dropping - RF KILL\n");
+		goto drop_unlock;
+	}
+
+	if (!priv->interface_id) {
+		IWL_DEBUG_DROP("Dropping - !priv->interface_id\n");
+		goto drop_unlock;
+	}
+
+	if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) {
+		IWL_ERROR("ERROR: No TX rate available.\n");
+		goto drop_unlock;
+	}
+
+	unicast = !is_multicast_ether_addr(hdr->addr1);
+	id = 0;
+
+	fc = le16_to_cpu(hdr->frame_control);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (ieee80211_is_auth(fc))
+		IWL_DEBUG_TX("Sending AUTH frame\n");
+	else if (ieee80211_is_assoc_request(fc))
+		IWL_DEBUG_TX("Sending ASSOC frame\n");
+	else if (ieee80211_is_reassoc_request(fc))
+		IWL_DEBUG_TX("Sending REASSOC frame\n");
+#endif
+
+	if (!iwl_is_associated(priv) &&
+	    ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) {
+		IWL_DEBUG_DROP("Dropping - !iwl_is_associated\n");
+		goto drop_unlock;
+	}
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	hdr_len = ieee80211_get_hdrlen(fc);
+	sta_id = iwl_get_sta_id(priv, hdr);
+	if (sta_id == IWL_INVALID_STATION) {
+		DECLARE_MAC_BUF(mac);
+
+		IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n",
+			       print_mac(mac, hdr->addr1));
+		goto drop;
+	}
+
+	IWL_DEBUG_RATE("station Id %d\n", sta_id);
+
+	qc = ieee80211_get_qos_ctrl(hdr);
+	if (qc) {
+		u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+		seq_number = priv->stations[sta_id].tid[tid].seq_number &
+				IEEE80211_SCTL_SEQ;
+		hdr->seq_ctrl = cpu_to_le16(seq_number) |
+			(hdr->seq_ctrl &
+				__constant_cpu_to_le16(IEEE80211_SCTL_FRAG));
+		seq_number += 0x10;
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+		/* aggregation is on for this <sta,tid> */
+		if (ctl->flags & IEEE80211_TXCTL_HT_MPDU_AGG)
+			txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+	}
+	txq = &priv->txq[txq_id];
+	q = &txq->q;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	tfd = &txq->bd[q->first_empty];
+	memset(tfd, 0, sizeof(*tfd));
+	control_flags = (u32 *) tfd;
+	idx = get_cmd_index(q, q->first_empty, 0);
+
+	memset(&(txq->txb[q->first_empty]), 0, sizeof(struct iwl_tx_info));
+	txq->txb[q->first_empty].skb[0] = skb;
+	memcpy(&(txq->txb[q->first_empty].status.control),
+	       ctl, sizeof(struct ieee80211_tx_control));
+	out_cmd = &txq->cmd[idx];
+	memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr));
+	memset(&out_cmd->cmd.tx, 0, sizeof(out_cmd->cmd.tx));
+	out_cmd->hdr.cmd = REPLY_TX;
+	out_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+				INDEX_TO_SEQ(q->first_empty)));
+	/* copy frags header */
+	memcpy(out_cmd->cmd.tx.hdr, hdr, hdr_len);
+
+	/* hdr = (struct ieee80211_hdr *)out_cmd->cmd.tx.hdr; */
+	len = priv->hw_setting.tx_cmd_len +
+		sizeof(struct iwl_cmd_header) + hdr_len;
+
+	len_org = len;
+	len = (len + 3) & ~3;
+
+	if (len_org != len)
+		len_org = 1;
+	else
+		len_org = 0;
+
+	txcmd_phys = txq->dma_addr_cmd + sizeof(struct iwl_cmd) * idx +
+		     offsetof(struct iwl_cmd, hdr);
+
+	iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);
+
+	if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
+		iwl_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
+
+	/* 802.11 null functions have no payload... */
+	len = skb->len - hdr_len;
+	if (len) {
+		phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
+					   len, PCI_DMA_TODEVICE);
+		iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, len);
+	}
+
+	if (len_org)
+		out_cmd->cmd.tx.tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
+
+	len = (u16)skb->len;
+	out_cmd->cmd.tx.len = cpu_to_le16(len);
+
+	/* TODO need this for burst mode later on */
+	iwl_build_tx_cmd_basic(priv, out_cmd, ctl, hdr, unicast, sta_id);
+
+	/* set is_hcca to 0; it probably will never be implemented */
+	iwl_hw_build_tx_cmd_rate(priv, out_cmd, ctl, hdr, sta_id, 0);
+
+	iwl4965_tx_cmd(priv, out_cmd, sta_id, txcmd_phys,
+		       hdr, hdr_len, ctl, NULL);
+
+	if (!ieee80211_get_morefrag(hdr)) {
+		txq->need_update = 1;
+		if (qc) {
+			u8 tid = (u8)(le16_to_cpu(*qc) & 0xf);
+			priv->stations[sta_id].tid[tid].seq_number = seq_number;
+		}
+	} else {
+		wait_write_ptr = 1;
+		txq->need_update = 0;
+	}
+
+	iwl_print_hex_dump(IWL_DL_TX, out_cmd->cmd.payload,
+			   sizeof(out_cmd->cmd.tx));
+
+	iwl_print_hex_dump(IWL_DL_TX, (u8 *)out_cmd->cmd.tx.hdr,
+			   ieee80211_get_hdrlen(fc));
+
+	iwl4965_tx_queue_update_wr_ptr(priv, txq, len);
+
+	q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);
+	rc = iwl_tx_queue_update_write_ptr(priv, txq);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (rc)
+		return rc;
+
+	if ((iwl_queue_space(q) < q->high_mark)
+	    && priv->mac80211_registered) {
+		if (wait_write_ptr) {
+			spin_lock_irqsave(&priv->lock, flags);
+			txq->need_update = 1;
+			iwl_tx_queue_update_write_ptr(priv, txq);
+			spin_unlock_irqrestore(&priv->lock, flags);
+		}
+
+		ieee80211_stop_queue(priv->hw, ctl->queue);
+	}
+
+	return 0;
+
+drop_unlock:
+	spin_unlock_irqrestore(&priv->lock, flags);
+drop:
+	return -1;
+}
+
+static void iwl_set_rate(struct iwl_priv *priv)
+{
+	const struct ieee80211_hw_mode *hw = NULL;
+	struct ieee80211_rate *rate;
+	int i;
+
+	hw = iwl_get_hw_mode(priv, priv->phymode);
+
+	priv->active_rate = 0;
+	priv->active_rate_basic = 0;
+
+	IWL_DEBUG_RATE("Setting rates for 802.11%c\n",
+		       hw->mode == MODE_IEEE80211A ?
+		       'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g'));
+
+	for (i = 0; i < hw->num_rates; i++) {
+		rate = &(hw->rates[i]);
+		if ((rate->val < IWL_RATE_COUNT) &&
+		    (rate->flags & IEEE80211_RATE_SUPPORTED)) {
+			IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n",
+				       rate->val, iwl_rates[rate->val].plcp,
+				       (rate->flags & IEEE80211_RATE_BASIC) ?
+				       "*" : "");
+			priv->active_rate |= (1 << rate->val);
+			if (rate->flags & IEEE80211_RATE_BASIC)
+				priv->active_rate_basic |= (1 << rate->val);
+		} else
+			IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n",
+				       rate->val, iwl_rates[rate->val].plcp);
+	}
+
+	IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n",
+		       priv->active_rate, priv->active_rate_basic);
+
+	/*
+	 * If a basic rate is configured, then use it (adding IWL_RATE_1M_MASK)
+	 * otherwise set it to the default of all CCK rates and 6, 12, 24 for
+	 * OFDM
+	 */
+	if (priv->active_rate_basic & IWL_CCK_BASIC_RATES_MASK)
+		priv->staging_rxon.cck_basic_rates =
+		    ((priv->active_rate_basic &
+		      IWL_CCK_RATES_MASK) >> IWL_FIRST_CCK_RATE) & 0xF;
+	else
+		priv->staging_rxon.cck_basic_rates =
+		    (IWL_CCK_BASIC_RATES_MASK >> IWL_FIRST_CCK_RATE) & 0xF;
+
+	if (priv->active_rate_basic & IWL_OFDM_BASIC_RATES_MASK)
+		priv->staging_rxon.ofdm_basic_rates =
+		    ((priv->active_rate_basic &
+		      (IWL_OFDM_BASIC_RATES_MASK | IWL_RATE_6M_MASK)) >>
+		      IWL_FIRST_OFDM_RATE) & 0xFF;
+	else
+		priv->staging_rxon.ofdm_basic_rates =
+		   (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
+}
+
+static void iwl_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
+{
+	unsigned long flags;
+
+	if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status))
+		return;
+
+	IWL_DEBUG_RF_KILL("Manual SW RF KILL set to: RADIO %s\n",
+			  disable_radio ? "OFF" : "ON");
+
+	if (disable_radio) {
+		iwl_scan_cancel(priv);
+		/* FIXME: This is a workaround for AP */
+		if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
+			spin_lock_irqsave(&priv->lock, flags);
+			iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+				    CSR_UCODE_SW_BIT_RFKILL);
+			spin_unlock_irqrestore(&priv->lock, flags);
+			iwl_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0);
+			set_bit(STATUS_RF_KILL_SW, &priv->status);
+		}
+		return;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+	clear_bit(STATUS_RF_KILL_SW, &priv->status);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	/* wake up ucode */
+	msleep(10);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl_read32(priv, CSR_UCODE_DRV_GP1);
+	if (!iwl_grab_restricted_access(priv))
+		iwl_release_restricted_access(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
+		IWL_DEBUG_RF_KILL("Can not turn radio back on - "
+				  "disabled by HW switch\n");
+		return;
+	}
+
+	queue_work(priv->workqueue, &priv->restart);
+	return;
+}
+
+void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
+			    u32 decrypt_res, struct ieee80211_rx_status *stats)
+{
+	u16 fc =
+	    le16_to_cpu(((struct ieee80211_hdr *)skb->data)->frame_control);
+
+	if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK)
+		return;
+
+	if (!(fc & IEEE80211_FCTL_PROTECTED))
+		return;
+
+	IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res);
+	switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
+	case RX_RES_STATUS_SEC_TYPE_TKIP:
+		if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+		    RX_RES_STATUS_BAD_ICV_MIC)
+			stats->flag |= RX_FLAG_MMIC_ERROR;
+	case RX_RES_STATUS_SEC_TYPE_WEP:
+	case RX_RES_STATUS_SEC_TYPE_CCMP:
+		if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+		    RX_RES_STATUS_DECRYPT_OK) {
+			IWL_DEBUG_RX("hw decrypt successfully!!!\n");
+			stats->flag |= RX_FLAG_DECRYPTED;
+		}
+		break;
+
+	default:
+		break;
+	}
+}
+
+void iwl_handle_data_packet_monitor(struct iwl_priv *priv,
+				    struct iwl_rx_mem_buffer *rxb,
+				    void *data, short len,
+				    struct ieee80211_rx_status *stats,
+				    u16 phy_flags)
+{
+	struct iwl_rt_rx_hdr *iwl_rt;
+
+	/* First cache any information we need before we overwrite
+	 * the information provided in the skb from the hardware */
+	s8 signal = stats->ssi;
+	s8 noise = 0;
+	int rate = stats->rate;
+	u64 tsf = stats->mactime;
+	__le16 phy_flags_hw = cpu_to_le16(phy_flags);
+
+	/* We received data from the HW, so stop the watchdog */
+	if (len > IWL_RX_BUF_SIZE - sizeof(*iwl_rt)) {
+		IWL_DEBUG_DROP("Dropping too large packet in monitor\n");
+		return;
+	}
+
+	/* copy the frame data to write after where the radiotap header goes */
+	iwl_rt = (void *)rxb->skb->data;
+	memmove(iwl_rt->payload, data, len);
+
+	iwl_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+	iwl_rt->rt_hdr.it_pad = 0; /* always good to zero */
+
+	/* total header + data */
+	iwl_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*iwl_rt));
+
+	/* Set the size of the skb to the size of the frame */
+	skb_put(rxb->skb, sizeof(*iwl_rt) + len);
+
+	/* Big bitfield of all the fields we provide in radiotap */
+	iwl_rt->rt_hdr.it_present =
+	    cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
+			(1 << IEEE80211_RADIOTAP_FLAGS) |
+			(1 << IEEE80211_RADIOTAP_RATE) |
+			(1 << IEEE80211_RADIOTAP_CHANNEL) |
+			(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+			(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
+			(1 << IEEE80211_RADIOTAP_ANTENNA));
+
+	/* Zero the flags, we'll add to them as we go */
+	iwl_rt->rt_flags = 0;
+
+	iwl_rt->rt_tsf = cpu_to_le64(tsf);
+
+	/* Convert to dBm */
+	iwl_rt->rt_dbmsignal = signal;
+	iwl_rt->rt_dbmnoise = noise;
+
+	/* Convert the channel frequency and set the flags */
+	iwl_rt->rt_channelMHz = cpu_to_le16(stats->freq);
+	if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
+		iwl_rt->rt_chbitmask =
+		    cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ));
+	else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
+		iwl_rt->rt_chbitmask =
+		    cpu_to_le16((IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ));
+	else	/* 802.11g */
+		iwl_rt->rt_chbitmask =
+		    cpu_to_le16((IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ));
+
+	rate = iwl_rate_index_from_plcp(rate);
+	if (rate == -1)
+		iwl_rt->rt_rate = 0;
+	else
+		iwl_rt->rt_rate = iwl_rates[rate].ieee;
+
+	/* antenna number */
+	iwl_rt->rt_antenna =
+		le16_to_cpu(phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
+
+	/* set the preamble flag if we have it */
+	if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK)
+		iwl_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+	IWL_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
+
+	stats->flag |= RX_FLAG_RADIOTAP;
+	ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
+	rxb->skb = NULL;
+}
+
+
+#define IWL_PACKET_RETRY_TIME HZ
+
+int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr *header)
+{
+	u16 sc = le16_to_cpu(header->seq_ctrl);
+	u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
+	u16 frag = sc & IEEE80211_SCTL_FRAG;
+	u16 *last_seq, *last_frag;
+	unsigned long *last_time;
+
+	switch (priv->iw_mode) {
+	case IEEE80211_IF_TYPE_IBSS:{
+		struct list_head *p;
+		struct iwl_ibss_seq *entry = NULL;
+		u8 *mac = header->addr2;
+		int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1);
+
+		__list_for_each(p, &priv->ibss_mac_hash[index]) {
+			entry =
+				list_entry(p, struct iwl_ibss_seq, list);
+			if (!compare_ether_addr(entry->mac, mac))
+				break;
+		}
+		if (p == &priv->ibss_mac_hash[index]) {
+			entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+			if (!entry) {
+				IWL_ERROR
+					("Cannot malloc new mac entry\n");
+				return 0;
+			}
+			memcpy(entry->mac, mac, ETH_ALEN);
+			entry->seq_num = seq;
+			entry->frag_num = frag;
+			entry->packet_time = jiffies;
+			list_add(&entry->list,
+				 &priv->ibss_mac_hash[index]);
+			return 0;
+		}
+		last_seq = &entry->seq_num;
+		last_frag = &entry->frag_num;
+		last_time = &entry->packet_time;
+		break;
+	}
+	case IEEE80211_IF_TYPE_STA:
+		last_seq = &priv->last_seq_num;
+		last_frag = &priv->last_frag_num;
+		last_time = &priv->last_packet_time;
+		break;
+	default:
+		return 0;
+	}
+	if ((*last_seq == seq) &&
+	    time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) {
+		if (*last_frag == frag)
+			goto drop;
+		if (*last_frag + 1 != frag)
+			/* out-of-order fragment */
+			goto drop;
+	} else
+		*last_seq = seq;
+
+	*last_frag = frag;
+	*last_time = jiffies;
+	return 0;
+
+ drop:
+	return 1;
+}
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+
+#include "iwl-spectrum.h"
+
+#define BEACON_TIME_MASK_LOW	0x00FFFFFF
+#define BEACON_TIME_MASK_HIGH	0xFF000000
+#define TIME_UNIT		1024
+
+/*
+ * extended beacon time format
+ * time in usec will be changed into a 32-bit value in 8:24 format
+ * the high 1 byte is the beacon counts
+ * the lower 3 bytes is the time in usec within one beacon interval
+ */
+
+static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval)
+{
+	u32 quot;
+	u32 rem;
+	u32 interval = beacon_interval * 1024;
+
+	if (!interval || !usec)
+		return 0;
+
+	quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
+	rem = (usec % interval) & BEACON_TIME_MASK_LOW;
+
+	return (quot << 24) + rem;
+}
+
+/* base is usually what we get from ucode with each received frame,
+ * the same as HW timer counter counting down
+ */
+
+static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
+{
+	u32 base_low = base & BEACON_TIME_MASK_LOW;
+	u32 addon_low = addon & BEACON_TIME_MASK_LOW;
+	u32 interval = beacon_interval * TIME_UNIT;
+	u32 res = (base & BEACON_TIME_MASK_HIGH) +
+	    (addon & BEACON_TIME_MASK_HIGH);
+
+	if (base_low > addon_low)
+		res += base_low - addon_low;
+	else if (base_low < addon_low) {
+		res += interval + base_low - addon_low;
+		res += (1 << 24);
+	} else
+		res += (1 << 24);
+
+	return cpu_to_le32(res);
+}
+
+static int iwl_get_measurement(struct iwl_priv *priv,
+			       struct ieee80211_measurement_params *params,
+			       u8 type)
+{
+	struct iwl_spectrum_cmd spectrum;
+	struct iwl_rx_packet *res;
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_SPECTRUM_MEASUREMENT_CMD,
+		.data = (void *)&spectrum,
+		.meta.flags = CMD_WANT_SKB,
+	};
+	u32 add_time = le64_to_cpu(params->start_time);
+	int rc;
+	int spectrum_resp_status;
+	int duration = le16_to_cpu(params->duration);
+
+	if (iwl_is_associated(priv))
+		add_time =
+		    iwl_usecs_to_beacons(
+			le64_to_cpu(params->start_time) - priv->last_tsf,
+			le16_to_cpu(priv->rxon_timing.beacon_interval));
+
+	memset(&spectrum, 0, sizeof(spectrum));
+
+	spectrum.channel_count = cpu_to_le16(1);
+	spectrum.flags =
+	    RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK;
+	spectrum.filter_flags = MEASUREMENT_FILTER_FLAG;
+	cmd.len = sizeof(spectrum);
+	spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len));
+
+	if (iwl_is_associated(priv))
+		spectrum.start_time =
+		    iwl_add_beacon_time(priv->last_beacon_time,
+				add_time,
+				le16_to_cpu(priv->rxon_timing.beacon_interval));
+	else
+		spectrum.start_time = 0;
+
+	spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT);
+	spectrum.channels[0].channel = params->channel;
+	spectrum.channels[0].type = type;
+	if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK)
+		spectrum.flags |= RXON_FLG_BAND_24G_MSK |
+		    RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK;
+
+	rc = iwl_send_cmd_sync(priv, &cmd);
+	if (rc)
+		return rc;
+
+	res = (struct iwl_rx_packet *)cmd.meta.u.skb->data;
+	if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
+		IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n");
+		rc = -EIO;
+	}
+
+	spectrum_resp_status = le16_to_cpu(res->u.spectrum.status);
+	switch (spectrum_resp_status) {
+	case 0:		/* Command will be handled */
+		if (res->u.spectrum.id != 0xff) {
+			IWL_DEBUG_INFO
+			    ("Replaced existing measurement: %d\n",
+			     res->u.spectrum.id);
+			priv->measurement_status &= ~MEASUREMENT_READY;
+		}
+		priv->measurement_status |= MEASUREMENT_ACTIVE;
+		rc = 0;
+		break;
+
+	case 1:		/* Command will not be handled */
+		rc = -EAGAIN;
+		break;
+	}
+
+	dev_kfree_skb_any(cmd.meta.u.skb);
+
+	return rc;
+}
+#endif
+
+static void iwl_txstatus_to_ieee(struct iwl_priv *priv,
+				 struct iwl_tx_info *tx_sta)
+{
+
+	tx_sta->status.ack_signal = 0;
+	tx_sta->status.excessive_retries = 0;
+	tx_sta->status.queue_length = 0;
+	tx_sta->status.queue_number = 0;
+
+	if (in_interrupt())
+		ieee80211_tx_status_irqsafe(priv->hw,
+					    tx_sta->skb[0], &(tx_sta->status));
+	else
+		ieee80211_tx_status(priv->hw,
+				    tx_sta->skb[0], &(tx_sta->status));
+
+	tx_sta->skb[0] = NULL;
+}
+
+/**
+ * iwl_tx_queue_reclaim - Reclaim Tx queue entries no more used by NIC.
+ *
+ * When FW advances 'R' index, all entries between old and
+ * new 'R' index need to be reclaimed. As result, some free space
+ * forms. If there is enough free space (> low mark), wake Tx queue.
+ */
+int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
+{
+	struct iwl_tx_queue *txq = &priv->txq[txq_id];
+	struct iwl_queue *q = &txq->q;
+	int nfreed = 0;
+
+	if ((index >= q->n_bd) || (x2_queue_used(q, index) == 0)) {
+		IWL_ERROR("Read index for DMA queue txq id (%d), index %d, "
+			  "is out of range [0-%d] %d %d.\n", txq_id,
+			  index, q->n_bd, q->first_empty, q->last_used);
+		return 0;
+	}
+
+	for (index = iwl_queue_inc_wrap(index, q->n_bd);
+		q->last_used != index;
+		q->last_used = iwl_queue_inc_wrap(q->last_used, q->n_bd)) {
+		if (txq_id != IWL_CMD_QUEUE_NUM) {
+			iwl_txstatus_to_ieee(priv,
+					&(txq->txb[txq->q.last_used]));
+			iwl_hw_txq_free_tfd(priv, txq);
+		} else if (nfreed > 1) {
+			IWL_ERROR("HCMD skipped: index (%d) %d %d\n", index,
+					q->first_empty, q->last_used);
+			queue_work(priv->workqueue, &priv->restart);
+		}
+		nfreed++;
+	}
+
+	if (iwl_queue_space(q) > q->low_mark && (txq_id >= 0) &&
+			(txq_id != IWL_CMD_QUEUE_NUM) &&
+			priv->mac80211_registered)
+		ieee80211_wake_queue(priv->hw, txq_id);
+
+
+	return nfreed;
+}
+
+static int iwl_is_tx_success(u32 status)
+{
+	status &= TX_STATUS_MSK;
+	return (status == TX_STATUS_SUCCESS)
+	    || (status == TX_STATUS_DIRECT_DONE);
+}
+
+/******************************************************************************
+ *
+ * Generic RX handler implementations
+ *
+ ******************************************************************************/
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+
+static inline int iwl_get_ra_sta_id(struct iwl_priv *priv,
+				    struct ieee80211_hdr *hdr)
+{
+	if (priv->iw_mode == IEEE80211_IF_TYPE_STA)
+		return IWL_AP_ID;
+	else {
+		u8 *da = ieee80211_get_DA(hdr);
+		return iwl_hw_find_station(priv, da);
+	}
+}
+
+static struct ieee80211_hdr *iwl_tx_queue_get_hdr(
+	struct iwl_priv *priv, int txq_id, int idx)
+{
+	if (priv->txq[txq_id].txb[idx].skb[0])
+		return (struct ieee80211_hdr *)priv->txq[txq_id].
+				txb[idx].skb[0]->data;
+	return NULL;
+}
+
+static inline u32 iwl_get_scd_ssn(struct iwl_tx_resp *tx_resp)
+{
+	__le32 *scd_ssn = (__le32 *)((u32 *)&tx_resp->status +
+				tx_resp->frame_count);
+	return le32_to_cpu(*scd_ssn) & MAX_SN;
+
+}
+static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
+				      struct iwl_ht_agg *agg,
+				      struct iwl_tx_resp *tx_resp,
+				      u16 start_idx)
+{
+	u32 status;
+	__le32 *frame_status = &tx_resp->status;
+	struct ieee80211_tx_status *tx_status = NULL;
+	struct ieee80211_hdr *hdr = NULL;
+	int i, sh;
+	int txq_id, idx;
+	u16 seq;
+
+	if (agg->wait_for_ba)
+		IWL_DEBUG_TX_REPLY("got tx repsons w/o back\n");
+
+	agg->frame_count = tx_resp->frame_count;
+	agg->start_idx = start_idx;
+	agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+	agg->bitmap0 = agg->bitmap1 = 0;
+
+	if (agg->frame_count == 1) {
+		struct iwl_tx_queue *txq ;
+		status = le32_to_cpu(frame_status[0]);
+
+		txq_id = agg->txq_id;
+		txq = &priv->txq[txq_id];
+		/* FIXME: code repetition */
+		IWL_DEBUG_TX_REPLY("FrameCnt = %d, StartIdx=%d \n",
+				   agg->frame_count, agg->start_idx);
+
+		tx_status = &(priv->txq[txq_id].txb[txq->q.last_used].status);
+		tx_status->retry_count = tx_resp->failure_frame;
+		tx_status->queue_number = status & 0xff;
+		tx_status->queue_length = tx_resp->bt_kill_count;
+		tx_status->queue_length |= tx_resp->failure_rts;
+
+		tx_status->flags = iwl_is_tx_success(status)?
+			IEEE80211_TX_STATUS_ACK : 0;
+		tx_status->control.tx_rate =
+				iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags);
+		/* FIXME: code repetition end */
+
+		IWL_DEBUG_TX_REPLY("1 Frame 0x%x failure :%d\n",
+				    status & 0xff, tx_resp->failure_frame);
+		IWL_DEBUG_TX_REPLY("Rate Info rate_n_flags=%x\n",
+				iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags));
+
+		agg->wait_for_ba = 0;
+	} else {
+		u64 bitmap = 0;
+		int start = agg->start_idx;
+
+		for (i = 0; i < agg->frame_count; i++) {
+			u16 sc;
+			status = le32_to_cpu(frame_status[i]);
+			seq  = status >> 16;
+			idx = SEQ_TO_INDEX(seq);
+			txq_id = SEQ_TO_QUEUE(seq);
+
+			if (status & (AGG_TX_STATE_FEW_BYTES_MSK |
+				      AGG_TX_STATE_ABORT_MSK))
+				continue;
+
+			IWL_DEBUG_TX_REPLY("FrameCnt = %d, txq_id=%d idx=%d\n",
+					   agg->frame_count, txq_id, idx);
+
+			hdr = iwl_tx_queue_get_hdr(priv, txq_id, idx);
+
+			sc = le16_to_cpu(hdr->seq_ctrl);
+			if (idx != (SEQ_TO_SN(sc) & 0xff)) {
+				IWL_ERROR("BUG_ON idx doesn't match seq control"
+					  " idx=%d, seq_idx=%d, seq=%d\n",
+					  idx, SEQ_TO_SN(sc),
+					  hdr->seq_ctrl);
+				return -1;
+			}
+
+			IWL_DEBUG_TX_REPLY("AGG Frame i=%d idx %d seq=%d\n",
+					   i, idx, SEQ_TO_SN(sc));
+
+			sh = idx - start;
+			if (sh > 64) {
+				sh = (start - idx) + 0xff;
+				bitmap = bitmap << sh;
+				sh = 0;
+				start = idx;
+			} else if (sh < -64)
+				sh  = 0xff - (start - idx);
+			else if (sh < 0) {
+				sh = start - idx;
+				start = idx;
+				bitmap = bitmap << sh;
+				sh = 0;
+			}
+			bitmap |= (1 << sh);
+			IWL_DEBUG_TX_REPLY("start=%d bitmap=0x%x\n",
+					   start, (u32)(bitmap & 0xFFFFFFFF));
+		}
+
+		agg->bitmap0 = bitmap & 0xFFFFFFFF;
+		agg->bitmap1 = bitmap >> 32;
+		agg->start_idx = start;
+		agg->rate_n_flags = le32_to_cpu(tx_resp->rate_n_flags);
+		IWL_DEBUG_TX_REPLY("Frames %d start_idx=%d bitmap=0x%x\n",
+				   agg->frame_count, agg->start_idx,
+				   agg->bitmap0);
+
+		if (bitmap)
+			agg->wait_for_ba = 1;
+	}
+	return 0;
+}
+#endif
+#endif
+
+static void iwl_rx_reply_tx(struct iwl_priv *priv,
+			    struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+	int txq_id = SEQ_TO_QUEUE(sequence);
+	int index = SEQ_TO_INDEX(sequence);
+	struct iwl_tx_queue *txq = &priv->txq[txq_id];
+	struct ieee80211_tx_status *tx_status;
+	struct iwl_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
+	u32  status = le32_to_cpu(tx_resp->status);
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+	int tid, sta_id;
+#endif
+#endif
+
+	if ((index >= txq->q.n_bd) || (x2_queue_used(&txq->q, index) == 0)) {
+		IWL_ERROR("Read index for DMA queue txq_id (%d) index %d "
+			  "is out of range [0-%d] %d %d\n", txq_id,
+			  index, txq->q.n_bd, txq->q.first_empty,
+			  txq->q.last_used);
+		return;
+	}
+
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+	if (txq->sched_retry) {
+		const u32 scd_ssn = iwl_get_scd_ssn(tx_resp);
+		struct ieee80211_hdr *hdr =
+			iwl_tx_queue_get_hdr(priv, txq_id, index);
+		struct iwl_ht_agg *agg = NULL;
+		__le16 *qc = ieee80211_get_qos_ctrl(hdr);
+
+		if (qc == NULL) {
+			IWL_ERROR("BUG_ON qc is null!!!!\n");
+			return;
+		}
+
+		tid = le16_to_cpu(*qc) & 0xf;
+
+		sta_id = iwl_get_ra_sta_id(priv, hdr);
+		if (unlikely(sta_id == IWL_INVALID_STATION)) {
+			IWL_ERROR("Station not known for\n");
+			return;
+		}
+
+		agg = &priv->stations[sta_id].tid[tid].agg;
+
+		iwl4965_tx_status_reply_tx(priv, agg, tx_resp, index);
+
+		if ((tx_resp->frame_count == 1) &&
+		    !iwl_is_tx_success(status)) {
+			/* TODO: send BAR */
+		}
+
+		if ((txq->q.last_used != (scd_ssn & 0xff))) {
+			index = iwl_queue_dec_wrap(scd_ssn & 0xff, txq->q.n_bd);
+			IWL_DEBUG_TX_REPLY("Retry scheduler reclaim scd_ssn "
+					   "%d index %d\n", scd_ssn , index);
+			iwl_tx_queue_reclaim(priv, txq_id, index);
+		}
+	} else {
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+	tx_status = &(txq->txb[txq->q.last_used].status);
+
+	tx_status->retry_count = tx_resp->failure_frame;
+	tx_status->queue_number = status;
+	tx_status->queue_length = tx_resp->bt_kill_count;
+	tx_status->queue_length |= tx_resp->failure_rts;
+
+	tx_status->flags =
+	    iwl_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0;
+
+	tx_status->control.tx_rate =
+		iwl_hw_get_rate_n_flags(tx_resp->rate_n_flags);
+
+	IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x "
+		     "retries %d\n", txq_id, iwl_get_tx_fail_reason(status),
+		     status, le32_to_cpu(tx_resp->rate_n_flags),
+		     tx_resp->failure_frame);
+
+	IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
+	if (index != -1)
+		iwl_tx_queue_reclaim(priv, txq_id, index);
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+	}
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+	if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
+		IWL_ERROR("TODO:  Implement Tx ABORT REQUIRED!!!\n");
+}
+
+
+static void iwl_rx_reply_alive(struct iwl_priv *priv,
+			       struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_alive_resp *palive;
+	struct delayed_work *pwork;
+
+	palive = &pkt->u.alive_frame;
+
+	IWL_DEBUG_INFO("Alive ucode status 0x%08X revision "
+		       "0x%01X 0x%01X\n",
+		       palive->is_valid, palive->ver_type,
+		       palive->ver_subtype);
+
+	if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
+		IWL_DEBUG_INFO("Initialization Alive received.\n");
+		memcpy(&priv->card_alive_init,
+		       &pkt->u.alive_frame,
+		       sizeof(struct iwl_init_alive_resp));
+		pwork = &priv->init_alive_start;
+	} else {
+		IWL_DEBUG_INFO("Runtime Alive received.\n");
+		memcpy(&priv->card_alive, &pkt->u.alive_frame,
+		       sizeof(struct iwl_alive_resp));
+		pwork = &priv->alive_start;
+	}
+
+	/* We delay the ALIVE response by 5ms to
+	 * give the HW RF Kill time to activate... */
+	if (palive->is_valid == UCODE_VALID_OK)
+		queue_delayed_work(priv->workqueue, pwork,
+				   msecs_to_jiffies(5));
+	else
+		IWL_WARNING("uCode did not respond OK.\n");
+}
+
+static void iwl_rx_reply_add_sta(struct iwl_priv *priv,
+				 struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+
+	IWL_DEBUG_RX("Received REPLY_ADD_STA: 0x%02X\n", pkt->u.status);
+	return;
+}
+
+static void iwl_rx_reply_error(struct iwl_priv *priv,
+			       struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+
+	IWL_ERROR("Error Reply type 0x%08X cmd %s (0x%02X) "
+		"seq 0x%04X ser 0x%08X\n",
+		le32_to_cpu(pkt->u.err_resp.error_type),
+		get_cmd_string(pkt->u.err_resp.cmd_id),
+		pkt->u.err_resp.cmd_id,
+		le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
+		le32_to_cpu(pkt->u.err_resp.error_info));
+}
+
+#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
+
+static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon;
+	struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
+	IWL_DEBUG_11H("CSA notif: channel %d, status %d\n",
+		      le16_to_cpu(csa->channel), le32_to_cpu(csa->status));
+	rxon->channel = csa->channel;
+	priv->staging_rxon.channel = csa->channel;
+}
+
+static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
+					  struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
+
+	if (!report->state) {
+		IWL_DEBUG(IWL_DL_11H | IWL_DL_INFO,
+			  "Spectrum Measure Notification: Start\n");
+		return;
+	}
+
+	memcpy(&priv->measure_report, report, sizeof(*report));
+	priv->measurement_status |= MEASUREMENT_READY;
+#endif
+}
+
+static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
+				  struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
+	IWL_DEBUG_RX("sleep mode: %d, src: %d\n",
+		     sleep->pm_sleep_mode, sleep->pm_wakeup_src);
+#endif
+}
+
+static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
+					     struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	IWL_DEBUG_RADIO("Dumping %d bytes of unhandled "
+			"notification for %s:\n",
+			le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
+	iwl_print_hex_dump(IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+}
+
+static void iwl_bg_beacon_update(struct work_struct *work)
+{
+	struct iwl_priv *priv =
+		container_of(work, struct iwl_priv, beacon_update);
+	struct sk_buff *beacon;
+
+	/* Pull updated AP beacon from mac80211. will fail if not in AP mode */
+	beacon = ieee80211_beacon_get(priv->hw, priv->interface_id, NULL);
+
+	if (!beacon) {
+		IWL_ERROR("update beacon failed\n");
+		return;
+	}
+
+	mutex_lock(&priv->mutex);
+	/* new beacon skb is allocated every time; dispose previous.*/
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+
+	priv->ibss_beacon = beacon;
+	mutex_unlock(&priv->mutex);
+
+	iwl_send_beacon_cmd(priv);
+}
+
+static void iwl_rx_beacon_notif(struct iwl_priv *priv,
+				struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_beacon_notif *beacon = &(pkt->u.beacon_status);
+	u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags);
+
+	IWL_DEBUG_RX("beacon status %x retries %d iss %d "
+		"tsf %d %d rate %d\n",
+		le32_to_cpu(beacon->beacon_notify_hdr.status) & TX_STATUS_MSK,
+		beacon->beacon_notify_hdr.failure_frame,
+		le32_to_cpu(beacon->ibss_mgr_status),
+		le32_to_cpu(beacon->high_tsf),
+		le32_to_cpu(beacon->low_tsf), rate);
+#endif
+
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+	    (!test_bit(STATUS_EXIT_PENDING, &priv->status)))
+		queue_work(priv->workqueue, &priv->beacon_update);
+}
+
+/* Service response to REPLY_SCAN_CMD (0x80) */
+static void iwl_rx_reply_scan(struct iwl_priv *priv,
+			      struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_scanreq_notification *notif =
+	    (struct iwl_scanreq_notification *)pkt->u.raw;
+
+	IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status);
+#endif
+}
+
+/* Service SCAN_START_NOTIFICATION (0x82) */
+static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
+				    struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_scanstart_notification *notif =
+	    (struct iwl_scanstart_notification *)pkt->u.raw;
+	priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
+	IWL_DEBUG_SCAN("Scan start: "
+		       "%d [802.11%s] "
+		       "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
+		       notif->channel,
+		       notif->band ? "bg" : "a",
+		       notif->tsf_high,
+		       notif->tsf_low, notif->status, notif->beacon_timer);
+}
+
+/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
+static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
+				      struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_scanresults_notification *notif =
+	    (struct iwl_scanresults_notification *)pkt->u.raw;
+
+	IWL_DEBUG_SCAN("Scan ch.res: "
+		       "%d [802.11%s] "
+		       "(TSF: 0x%08X:%08X) - %d "
+		       "elapsed=%lu usec (%dms since last)\n",
+		       notif->channel,
+		       notif->band ? "bg" : "a",
+		       le32_to_cpu(notif->tsf_high),
+		       le32_to_cpu(notif->tsf_low),
+		       le32_to_cpu(notif->statistics[0]),
+		       le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf,
+		       jiffies_to_msecs(elapsed_jiffies
+					(priv->last_scan_jiffies, jiffies)));
+
+	priv->last_scan_jiffies = jiffies;
+}
+
+/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
+static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
+				       struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
+
+	IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
+		       scan_notif->scanned_channels,
+		       scan_notif->tsf_low,
+		       scan_notif->tsf_high, scan_notif->status);
+
+	/* The HW is no longer scanning */
+	clear_bit(STATUS_SCAN_HW, &priv->status);
+
+	/* The scan completion notification came in, so kill that timer... */
+	cancel_delayed_work(&priv->scan_check);
+
+	IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
+		       (priv->scan_bands == 2) ? "2.4" : "5.2",
+		       jiffies_to_msecs(elapsed_jiffies
+					(priv->scan_pass_start, jiffies)));
+
+	/* Remove this scanned band from the list
+	 * of pending bands to scan */
+	priv->scan_bands--;
+
+	/* If a request to abort was given, or the scan did not succeed
+	 * then we reset the scan state machine and terminate,
+	 * re-queuing another scan if one has been requested */
+	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG_INFO("Aborted scan completed.\n");
+		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
+	} else {
+		/* If there are more bands on this scan pass reschedule */
+		if (priv->scan_bands > 0)
+			goto reschedule;
+	}
+
+	priv->last_scan_jiffies = jiffies;
+	IWL_DEBUG_INFO("Setting scan to off\n");
+
+	clear_bit(STATUS_SCANNING, &priv->status);
+
+	IWL_DEBUG_INFO("Scan took %dms\n",
+		jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies)));
+
+	queue_work(priv->workqueue, &priv->scan_completed);
+
+	return;
+
+reschedule:
+	priv->scan_pass_start = jiffies;
+	queue_work(priv->workqueue, &priv->request_scan);
+}
+
+/* Handle notification from uCode that card's power state is changing
+ * due to software, hardware, or critical temperature RFKILL */
+static void iwl_rx_card_state_notif(struct iwl_priv *priv,
+				    struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
+	u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
+	unsigned long status = priv->status;
+
+	IWL_DEBUG_RF_KILL("Card state received: HW:%s SW:%s\n",
+			  (flags & HW_CARD_DISABLED) ? "Kill" : "On",
+			  (flags & SW_CARD_DISABLED) ? "Kill" : "On");
+
+	if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
+		     RF_CARD_DISABLED)) {
+
+		iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+			    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+		if (!iwl_grab_restricted_access(priv)) {
+			iwl_write_restricted(
+				priv, HBUS_TARG_MBX_C,
+				HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
+
+			iwl_release_restricted_access(priv);
+		}
+
+		if (!(flags & RXON_CARD_DISABLED)) {
+			iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+				    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+			if (!iwl_grab_restricted_access(priv)) {
+				iwl_write_restricted(
+					priv, HBUS_TARG_MBX_C,
+					HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
+
+				iwl_release_restricted_access(priv);
+			}
+		}
+
+		if (flags & RF_CARD_DISABLED) {
+			iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
+				    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
+			iwl_read32(priv, CSR_UCODE_DRV_GP1);
+			if (!iwl_grab_restricted_access(priv))
+				iwl_release_restricted_access(priv);
+		}
+	}
+
+	if (flags & HW_CARD_DISABLED)
+		set_bit(STATUS_RF_KILL_HW, &priv->status);
+	else
+		clear_bit(STATUS_RF_KILL_HW, &priv->status);
+
+
+	if (flags & SW_CARD_DISABLED)
+		set_bit(STATUS_RF_KILL_SW, &priv->status);
+	else
+		clear_bit(STATUS_RF_KILL_SW, &priv->status);
+
+	if (!(flags & RXON_CARD_DISABLED))
+		iwl_scan_cancel(priv);
+
+	if ((test_bit(STATUS_RF_KILL_HW, &status) !=
+	     test_bit(STATUS_RF_KILL_HW, &priv->status)) ||
+	    (test_bit(STATUS_RF_KILL_SW, &status) !=
+	     test_bit(STATUS_RF_KILL_SW, &priv->status)))
+		queue_work(priv->workqueue, &priv->rf_kill);
+	else
+		wake_up_interruptible(&priv->wait_command_queue);
+}
+
+/**
+ * iwl_setup_rx_handlers - Initialize Rx handler callbacks
+ *
+ * Setup the RX handlers for each of the reply types sent from the uCode
+ * to the host.
+ *
+ * This function chains into the hardware specific files for them to setup
+ * any hardware specific handlers as well.
+ */
+static void iwl_setup_rx_handlers(struct iwl_priv *priv)
+{
+	priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
+	priv->rx_handlers[REPLY_ADD_STA] = iwl_rx_reply_add_sta;
+	priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
+	priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
+	priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
+	    iwl_rx_spectrum_measure_notif;
+	priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
+	priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
+	    iwl_rx_pm_debug_statistics_notif;
+	priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif;
+
+	/* NOTE:  iwl_rx_statistics is different based on whether
+	 * the build is for the 3945 or the 4965.  See the
+	 * corresponding implementation in iwl-XXXX.c
+	 *
+	 * The same handler is used for both the REPLY to a
+	 * discrete statistics request from the host as well as
+	 * for the periodic statistics notification from the uCode
+	 */
+	priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_hw_rx_statistics;
+	priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_hw_rx_statistics;
+
+	priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan;
+	priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif;
+	priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
+	    iwl_rx_scan_results_notif;
+	priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
+	    iwl_rx_scan_complete_notif;
+	priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif;
+	priv->rx_handlers[REPLY_TX] = iwl_rx_reply_tx;
+
+	/* Setup hardware specific Rx handlers */
+	iwl_hw_rx_handler_setup(priv);
+}
+
+/**
+ * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
+ * @rxb: Rx buffer to reclaim
+ *
+ * If an Rx buffer has an async callback associated with it the callback
+ * will be executed.  The attached skb (if present) will only be freed
+ * if the callback returns 1
+ */
+static void iwl_tx_cmd_complete(struct iwl_priv *priv,
+				struct iwl_rx_mem_buffer *rxb)
+{
+	struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+	u16 sequence = le16_to_cpu(pkt->hdr.sequence);
+	int txq_id = SEQ_TO_QUEUE(sequence);
+	int index = SEQ_TO_INDEX(sequence);
+	int huge = sequence & SEQ_HUGE_FRAME;
+	int cmd_index;
+	struct iwl_cmd *cmd;
+
+	/* If a Tx command is being handled and it isn't in the actual
+	 * command queue then there a command routing bug has been introduced
+	 * in the queue management code. */
+	if (txq_id != IWL_CMD_QUEUE_NUM)
+		IWL_ERROR("Error wrong command queue %d command id 0x%X\n",
+			  txq_id, pkt->hdr.cmd);
+	BUG_ON(txq_id != IWL_CMD_QUEUE_NUM);
+
+	cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
+	cmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
+
+	/* Input error checking is done when commands are added to queue. */
+	if (cmd->meta.flags & CMD_WANT_SKB) {
+		cmd->meta.source->u.skb = rxb->skb;
+		rxb->skb = NULL;
+	} else if (cmd->meta.u.callback &&
+		   !cmd->meta.u.callback(priv, cmd, rxb->skb))
+		rxb->skb = NULL;
+
+	iwl_tx_queue_reclaim(priv, txq_id, index);
+
+	if (!(cmd->meta.flags & CMD_ASYNC)) {
+		clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+		wake_up_interruptible(&priv->wait_command_queue);
+	}
+}
+
+/************************** RX-FUNCTIONS ****************************/
+/*
+ * Rx theory of operation
+ *
+ * The host allocates 32 DMA target addresses and passes the host address
+ * to the firmware at register IWL_RFDS_TABLE_LOWER + N * RFD_SIZE where N is
+ * 0 to 31
+ *
+ * Rx Queue Indexes
+ * The host/firmware share two index registers for managing the Rx buffers.
+ *
+ * The READ index maps to the first position that the firmware may be writing
+ * to -- the driver can read up to (but not including) this position and get
+ * good data.
+ * The READ index is managed by the firmware once the card is enabled.
+ *
+ * The WRITE index maps to the last position the driver has read from -- the
+ * position preceding WRITE is the last slot the firmware can place a packet.
+ *
+ * The queue is empty (no good data) if WRITE = READ - 1, and is full if
+ * WRITE = READ.
+ *
+ * During initialization the host sets up the READ queue position to the first
+ * INDEX position, and WRITE to the last (READ - 1 wrapped)
+ *
+ * When the firmware places a packet in a buffer it will advance the READ index
+ * and fire the RX interrupt.  The driver can then query the READ index and
+ * process as many packets as possible, moving the WRITE index forward as it
+ * resets the Rx queue buffers with new memory.
+ *
+ * The management in the driver is as follows:
+ * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free.  When
+ *   iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
+ *   to replensish the iwl->rxq->rx_free.
+ * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
+ *   iwl->rxq is replenished and the READ INDEX is updated (updating the
+ *   'processed' and 'read' driver indexes as well)
+ * + A received packet is processed and handed to the kernel network stack,
+ *   detached from the iwl->rxq.  The driver 'processed' index is updated.
+ * + The Host/Firmware iwl->rxq is replenished at tasklet time from the rx_free
+ *   list. If there are no allocated buffers in iwl->rxq->rx_free, the READ
+ *   INDEX is not incremented and iwl->status(RX_STALLED) is set.  If there
+ *   were enough free buffers and RX_STALLED is set it is cleared.
+ *
+ *
+ * Driver sequence:
+ *
+ * iwl_rx_queue_alloc()       Allocates rx_free
+ * iwl_rx_replenish()         Replenishes rx_free list from rx_used, and calls
+ *                            iwl_rx_queue_restock
+ * iwl_rx_queue_restock()     Moves available buffers from rx_free into Rx
+ *                            queue, updates firmware pointers, and updates
+ *                            the WRITE index.  If insufficient rx_free buffers
+ *                            are available, schedules iwl_rx_replenish
+ *
+ * -- enable interrupts --
+ * ISR - iwl_rx()             Detach iwl_rx_mem_buffers from pool up to the
+ *                            READ INDEX, detaching the SKB from the pool.
+ *                            Moves the packet buffer from queue to rx_used.
+ *                            Calls iwl_rx_queue_restock to refill any empty
+ *                            slots.
+ * ...
+ *
+ */
+
+/**
+ * iwl_rx_queue_space - Return number of free slots available in queue.
+ */
+static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
+{
+	int s = q->read - q->write;
+	if (s <= 0)
+		s += RX_QUEUE_SIZE;
+	/* keep some buffer to not confuse full and empty queue */
+	s -= 2;
+	if (s < 0)
+		s = 0;
+	return s;
+}
+
+/**
+ * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
+ *
+ * NOTE: This function has 3945 and 4965 specific code sections
+ * but is declared in base due to the majority of the
+ * implementation being the same (only a numeric constant is
+ * different)
+ *
+ */
+int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
+{
+	u32 reg = 0;
+	int rc = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&q->lock, flags);
+
+	if (q->need_update == 0)
+		goto exit_unlock;
+
+	if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+		reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+
+		if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+			iwl_set_bit(priv, CSR_GP_CNTRL,
+				    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+			goto exit_unlock;
+		}
+
+		rc = iwl_grab_restricted_access(priv);
+		if (rc)
+			goto exit_unlock;
+
+		iwl_write_restricted(priv, FH_RSCSR_CHNL0_WPTR,
+				     q->write & ~0x7);
+		iwl_release_restricted_access(priv);
+	} else
+		iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
+
+
+	q->need_update = 0;
+
+ exit_unlock:
+	spin_unlock_irqrestore(&q->lock, flags);
+	return rc;
+}
+
+/**
+ * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer pointer.
+ *
+ * NOTE: This function has 3945 and 4965 specific code paths in it.
+ */
+static inline __le32 iwl_dma_addr2rbd_ptr(struct iwl_priv *priv,
+					  dma_addr_t dma_addr)
+{
+	return cpu_to_le32((u32)(dma_addr >> 8));
+}
+
+
+/**
+ * iwl_rx_queue_restock - refill RX queue from pre-allocated pool
+ *
+ * If there are slots in the RX queue that  need to be restocked,
+ * and we have free pre-allocated buffers, fill the ranks as much
+ * as we can pulling from rx_free.
+ *
+ * This moves the 'write' index forward to catch up with 'processed', and
+ * also updates the memory address in the firmware to reference the new
+ * target buffer.
+ */
+int iwl_rx_queue_restock(struct iwl_priv *priv)
+{
+	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct list_head *element;
+	struct iwl_rx_mem_buffer *rxb;
+	unsigned long flags;
+	int write, rc;
+
+	spin_lock_irqsave(&rxq->lock, flags);
+	write = rxq->write & ~0x7;
+	while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+		element = rxq->rx_free.next;
+		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+		list_del(element);
+		rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(priv, rxb->dma_addr);
+		rxq->queue[rxq->write] = rxb;
+		rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
+		rxq->free_count--;
+	}
+	spin_unlock_irqrestore(&rxq->lock, flags);
+	/* If the pre-allocated buffer pool is dropping low, schedule to
+	 * refill it */
+	if (rxq->free_count <= RX_LOW_WATERMARK)
+		queue_work(priv->workqueue, &priv->rx_replenish);
+
+
+	/* If we've added more space for the firmware to place data, tell it */
+	if ((write != (rxq->write & ~0x7))
+	    || (abs(rxq->write - rxq->read) > 7)) {
+		spin_lock_irqsave(&rxq->lock, flags);
+		rxq->need_update = 1;
+		spin_unlock_irqrestore(&rxq->lock, flags);
+		rc = iwl_rx_queue_update_write_ptr(priv, rxq);
+		if (rc)
+			return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * iwl_rx_replensih - Move all used packet from rx_used to rx_free
+ *
+ * When moving to rx_free an SKB is allocated for the slot.
+ *
+ * Also restock the Rx queue via iwl_rx_queue_restock.
+ * This is called as a scheduled work item (except for during intialization)
+ */
+void iwl_rx_replenish(void *data)
+{
+	struct iwl_priv *priv = data;
+	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct list_head *element;
+	struct iwl_rx_mem_buffer *rxb;
+	unsigned long flags;
+	spin_lock_irqsave(&rxq->lock, flags);
+	while (!list_empty(&rxq->rx_used)) {
+		element = rxq->rx_used.next;
+		rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+		rxb->skb =
+		    alloc_skb(IWL_RX_BUF_SIZE, __GFP_NOWARN | GFP_ATOMIC);
+		if (!rxb->skb) {
+			if (net_ratelimit())
+				printk(KERN_CRIT DRV_NAME
+				       ": Can not allocate SKB buffers\n");
+			/* We don't reschedule replenish work here -- we will
+			 * call the restock method and if it still needs
+			 * more buffers it will schedule replenish */
+			break;
+		}
+		priv->alloc_rxb_skb++;
+		list_del(element);
+		rxb->dma_addr =
+		    pci_map_single(priv->pci_dev, rxb->skb->data,
+				   IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+		list_add_tail(&rxb->list, &rxq->rx_free);
+		rxq->free_count++;
+	}
+	spin_unlock_irqrestore(&rxq->lock, flags);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl_rx_queue_restock(priv);
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
+ * If an SKB has been detached, the POOL needs to have it's SKB set to NULL
+ * This free routine walks the list of POOL entries and if SKB is set to
+ * non NULL it is unmapped and freed
+ */
+void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+	int i;
+	for (i = 0; i < RX_QUEUE_SIZE + RX_FREE_BUFFERS; i++) {
+		if (rxq->pool[i].skb != NULL) {
+			pci_unmap_single(priv->pci_dev,
+					 rxq->pool[i].dma_addr,
+					 IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+			dev_kfree_skb(rxq->pool[i].skb);
+		}
+	}
+
+	pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd,
+			    rxq->dma_addr);
+	rxq->bd = NULL;
+}
+
+int iwl_rx_queue_alloc(struct iwl_priv *priv)
+{
+	struct iwl_rx_queue *rxq = &priv->rxq;
+	struct pci_dev *dev = priv->pci_dev;
+	int i;
+
+	spin_lock_init(&rxq->lock);
+	INIT_LIST_HEAD(&rxq->rx_free);
+	INIT_LIST_HEAD(&rxq->rx_used);
+	rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr);
+	if (!rxq->bd)
+		return -ENOMEM;
+	/* Fill the rx_used queue with _all_ of the Rx buffers */
+	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++)
+		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+	/* Set us so that we have processed and used all buffers, but have
+	 * not restocked the Rx queue with fresh buffers */
+	rxq->read = rxq->write = 0;
+	rxq->free_count = 0;
+	rxq->need_update = 0;
+	return 0;
+}
+
+void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
+{
+	unsigned long flags;
+	int i;
+	spin_lock_irqsave(&rxq->lock, flags);
+	INIT_LIST_HEAD(&rxq->rx_free);
+	INIT_LIST_HEAD(&rxq->rx_used);
+	/* Fill the rx_used queue with _all_ of the Rx buffers */
+	for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+		/* In the reset function, these buffers may have been allocated
+		 * to an SKB, so we need to unmap and free potential storage */
+		if (rxq->pool[i].skb != NULL) {
+			pci_unmap_single(priv->pci_dev,
+					 rxq->pool[i].dma_addr,
+					 IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+			priv->alloc_rxb_skb--;
+			dev_kfree_skb(rxq->pool[i].skb);
+			rxq->pool[i].skb = NULL;
+		}
+		list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+	}
+
+	/* Set us so that we have processed and used all buffers, but have
+	 * not restocked the Rx queue with fresh buffers */
+	rxq->read = rxq->write = 0;
+	rxq->free_count = 0;
+	spin_unlock_irqrestore(&rxq->lock, flags);
+}
+
+/* Convert linear signal-to-noise ratio into dB */
+static u8 ratio2dB[100] = {
+/*	 0   1   2   3   4   5   6   7   8   9 */
+	 0,  0,  6, 10, 12, 14, 16, 17, 18, 19, /* 00 - 09 */
+	20, 21, 22, 22, 23, 23, 24, 25, 26, 26, /* 10 - 19 */
+	26, 26, 26, 27, 27, 28, 28, 28, 29, 29, /* 20 - 29 */
+	29, 30, 30, 30, 31, 31, 31, 31, 32, 32, /* 30 - 39 */
+	32, 32, 32, 33, 33, 33, 33, 33, 34, 34, /* 40 - 49 */
+	34, 34, 34, 34, 35, 35, 35, 35, 35, 35, /* 50 - 59 */
+	36, 36, 36, 36, 36, 36, 36, 37, 37, 37, /* 60 - 69 */
+	37, 37, 37, 37, 37, 38, 38, 38, 38, 38, /* 70 - 79 */
+	38, 38, 38, 38, 38, 39, 39, 39, 39, 39, /* 80 - 89 */
+	39, 39, 39, 39, 39, 40, 40, 40, 40, 40  /* 90 - 99 */
+};
+
+/* Calculates a relative dB value from a ratio of linear
+ *   (i.e. not dB) signal levels.
+ * Conversion assumes that levels are voltages (20*log), not powers (10*log). */
+int iwl_calc_db_from_ratio(int sig_ratio)
+{
+	/* Anything above 1000:1 just report as 60 dB */
+	if (sig_ratio > 1000)
+		return 60;
+
+	/* Above 100:1, divide by 10 and use table,
+	 *   add 20 dB to make up for divide by 10 */
+	if (sig_ratio > 100)
+		return (20 + (int)ratio2dB[sig_ratio/10]);
+
+	/* We shouldn't see this */
+	if (sig_ratio < 1)
+		return 0;
+
+	/* Use table for ratios 1:1 - 99:1 */
+	return (int)ratio2dB[sig_ratio];
+}
+
+#define PERFECT_RSSI (-20) /* dBm */
+#define WORST_RSSI (-95)   /* dBm */
+#define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI)
+
+/* Calculate an indication of rx signal quality (a percentage, not dBm!).
+ * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
+ *   about formulas used below. */
+int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm)
+{
+	int sig_qual;
+	int degradation = PERFECT_RSSI - rssi_dbm;
+
+	/* If we get a noise measurement, use signal-to-noise ratio (SNR)
+	 * as indicator; formula is (signal dbm - noise dbm).
+	 * SNR at or above 40 is a great signal (100%).
+	 * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator.
+	 * Weakest usable signal is usually 10 - 15 dB SNR. */
+	if (noise_dbm) {
+		if (rssi_dbm - noise_dbm >= 40)
+			return 100;
+		else if (rssi_dbm < noise_dbm)
+			return 0;
+		sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2;
+
+	/* Else use just the signal level.
+	 * This formula is a least squares fit of data points collected and
+	 *   compared with a reference system that had a percentage (%) display
+	 *   for signal quality. */
+	} else
+		sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation *
+			    (15 * RSSI_RANGE + 62 * degradation)) /
+			   (RSSI_RANGE * RSSI_RANGE);
+
+	if (sig_qual > 100)
+		sig_qual = 100;
+	else if (sig_qual < 1)
+		sig_qual = 0;
+
+	return sig_qual;
+}
+
+/**
+ * iwl_rx_handle - Main entry function for receiving responses from the uCode
+ *
+ * Uses the priv->rx_handlers callback function array to invoke
+ * the appropriate handlers, including command responses,
+ * frame-received notifications, and other notifications.
+ */
+static void iwl_rx_handle(struct iwl_priv *priv)
+{
+	struct iwl_rx_mem_buffer *rxb;
+	struct iwl_rx_packet *pkt;
+	struct iwl_rx_queue *rxq = &priv->rxq;
+	u32 r, i;
+	int reclaim;
+	unsigned long flags;
+
+	r = iwl_hw_get_rx_read(priv);
+	i = rxq->read;
+
+	/* Rx interrupt, but nothing sent from uCode */
+	if (i == r)
+		IWL_DEBUG(IWL_DL_RX | IWL_DL_ISR, "r = %d, i = %d\n", r, i);
+
+	while (i != r) {
+		rxb = rxq->queue[i];
+
+		/* If an RXB doesn't have a queue slot associated with it
+		 * then a bug has been introduced in the queue refilling
+		 * routines -- catch it here */
+		BUG_ON(rxb == NULL);
+
+		rxq->queue[i] = NULL;
+
+		pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
+					    IWL_RX_BUF_SIZE,
+					    PCI_DMA_FROMDEVICE);
+		pkt = (struct iwl_rx_packet *)rxb->skb->data;
+
+		/* Reclaim a command buffer only if this packet is a response
+		 *   to a (driver-originated) command.
+		 * If the packet (e.g. Rx frame) originated from uCode,
+		 *   there is no command buffer to reclaim.
+		 * Ucode should set SEQ_RX_FRAME bit if ucode-originated,
+		 *   but apparently a few don't get set; catch them here. */
+		reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) &&
+			(pkt->hdr.cmd != REPLY_RX_PHY_CMD) &&
+			(pkt->hdr.cmd != REPLY_4965_RX) &&
+			(pkt->hdr.cmd != REPLY_COMPRESSED_BA) &&
+			(pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
+			(pkt->hdr.cmd != REPLY_TX);
+
+		/* Based on type of command response or notification,
+		 *   handle those that need handling via function in
+		 *   rx_handlers table.  See iwl_setup_rx_handlers() */
+		if (priv->rx_handlers[pkt->hdr.cmd]) {
+			IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
+				"r = %d, i = %d, %s, 0x%02x\n", r, i,
+				get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
+			priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
+		} else {
+			/* No handling needed */
+			IWL_DEBUG(IWL_DL_HOST_COMMAND | IWL_DL_RX | IWL_DL_ISR,
+				"r %d i %d No handler needed for %s, 0x%02x\n",
+				r, i, get_cmd_string(pkt->hdr.cmd),
+				pkt->hdr.cmd);
+		}
+
+		if (reclaim) {
+			/* Invoke any callbacks, transfer the skb to caller,
+			 * and fire off the (possibly) blocking iwl_send_cmd()
+			 * as we reclaim the driver command queue */
+			if (rxb && rxb->skb)
+				iwl_tx_cmd_complete(priv, rxb);
+			else
+				IWL_WARNING("Claim null rxb?\n");
+		}
+
+		/* For now we just don't re-use anything.  We can tweak this
+		 * later to try and re-use notification packets and SKBs that
+		 * fail to Rx correctly */
+		if (rxb->skb != NULL) {
+			priv->alloc_rxb_skb--;
+			dev_kfree_skb_any(rxb->skb);
+			rxb->skb = NULL;
+		}
+
+		pci_unmap_single(priv->pci_dev, rxb->dma_addr,
+				 IWL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+		spin_lock_irqsave(&rxq->lock, flags);
+		list_add_tail(&rxb->list, &priv->rxq.rx_used);
+		spin_unlock_irqrestore(&rxq->lock, flags);
+		i = (i + 1) & RX_QUEUE_MASK;
+	}
+
+	/* Backtrack one entry */
+	priv->rxq.read = i;
+	iwl_rx_queue_restock(priv);
+}
+
+int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
+				  struct iwl_tx_queue *txq)
+{
+	u32 reg = 0;
+	int rc = 0;
+	int txq_id = txq->q.id;
+
+	if (txq->need_update == 0)
+		return rc;
+
+	/* if we're trying to save power */
+	if (test_bit(STATUS_POWER_PMI, &priv->status)) {
+		/* wake up nic if it's powered down ...
+		 * uCode will wake up, and interrupt us again, so next
+		 * time we'll skip this part. */
+		reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
+
+		if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
+			IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg);
+			iwl_set_bit(priv, CSR_GP_CNTRL,
+				    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+			return rc;
+		}
+
+		/* restore this queue's parameters in nic hardware. */
+		rc = iwl_grab_restricted_access(priv);
+		if (rc)
+			return rc;
+		iwl_write_restricted(priv, HBUS_TARG_WRPTR,
+				     txq->q.first_empty | (txq_id << 8));
+		iwl_release_restricted_access(priv);
+
+	/* else not in power-save mode, uCode will never sleep when we're
+	 * trying to tx (during RFKILL, we're not trying to tx). */
+	} else
+		iwl_write32(priv, HBUS_TARG_WRPTR,
+			    txq->q.first_empty | (txq_id << 8));
+
+	txq->need_update = 0;
+
+	return rc;
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+static void iwl_print_rx_config_cmd(struct iwl_rxon_cmd *rxon)
+{
+	DECLARE_MAC_BUF(mac);
+
+	IWL_DEBUG_RADIO("RX CONFIG:\n");
+	iwl_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon));
+	IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel));
+	IWL_DEBUG_RADIO("u32 flags: 0x%08X\n", le32_to_cpu(rxon->flags));
+	IWL_DEBUG_RADIO("u32 filter_flags: 0x%08x\n",
+			le32_to_cpu(rxon->filter_flags));
+	IWL_DEBUG_RADIO("u8 dev_type: 0x%x\n", rxon->dev_type);
+	IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n",
+			rxon->ofdm_basic_rates);
+	IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates);
+	IWL_DEBUG_RADIO("u8[6] node_addr: %s\n",
+			print_mac(mac, rxon->node_addr));
+	IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n",
+			print_mac(mac, rxon->bssid_addr));
+	IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
+}
+#endif
+
+static void iwl_enable_interrupts(struct iwl_priv *priv)
+{
+	IWL_DEBUG_ISR("Enabling interrupts\n");
+	set_bit(STATUS_INT_ENABLED, &priv->status);
+	iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
+}
+
+static inline void iwl_disable_interrupts(struct iwl_priv *priv)
+{
+	clear_bit(STATUS_INT_ENABLED, &priv->status);
+
+	/* disable interrupts from uCode/NIC to host */
+	iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+	/* acknowledge/clear/reset any interrupts still pending
+	 * from uCode or flow handler (Rx/Tx DMA) */
+	iwl_write32(priv, CSR_INT, 0xffffffff);
+	iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+	IWL_DEBUG_ISR("Disabled interrupts\n");
+}
+
+static const char *desc_lookup(int i)
+{
+	switch (i) {
+	case 1:
+		return "FAIL";
+	case 2:
+		return "BAD_PARAM";
+	case 3:
+		return "BAD_CHECKSUM";
+	case 4:
+		return "NMI_INTERRUPT";
+	case 5:
+		return "SYSASSERT";
+	case 6:
+		return "FATAL_ERROR";
+	}
+
+	return "UNKNOWN";
+}
+
+#define ERROR_START_OFFSET  (1 * sizeof(u32))
+#define ERROR_ELEM_SIZE     (7 * sizeof(u32))
+
+static void iwl_dump_nic_error_log(struct iwl_priv *priv)
+{
+	u32 data2, line;
+	u32 desc, time, count, base, data1;
+	u32 blink1, blink2, ilink1, ilink2;
+	int rc;
+
+	base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+
+	if (!iwl_hw_valid_rtc_data_addr(base)) {
+		IWL_ERROR("Not valid error log pointer 0x%08X\n", base);
+		return;
+	}
+
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		IWL_WARNING("Can not read from adapter at this time.\n");
+		return;
+	}
+
+	count = iwl_read_restricted_mem(priv, base);
+
+	if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+		IWL_ERROR("Start IWL Error Log Dump:\n");
+		IWL_ERROR("Status: 0x%08lX, Config: %08X count: %d\n",
+			  priv->status, priv->config, count);
+	}
+
+	desc = iwl_read_restricted_mem(priv, base + 1 * sizeof(u32));
+	blink1 = iwl_read_restricted_mem(priv, base + 3 * sizeof(u32));
+	blink2 = iwl_read_restricted_mem(priv, base + 4 * sizeof(u32));
+	ilink1 = iwl_read_restricted_mem(priv, base + 5 * sizeof(u32));
+	ilink2 = iwl_read_restricted_mem(priv, base + 6 * sizeof(u32));
+	data1 = iwl_read_restricted_mem(priv, base + 7 * sizeof(u32));
+	data2 = iwl_read_restricted_mem(priv, base + 8 * sizeof(u32));
+	line = iwl_read_restricted_mem(priv, base + 9 * sizeof(u32));
+	time = iwl_read_restricted_mem(priv, base + 11 * sizeof(u32));
+
+	IWL_ERROR("Desc               Time       "
+		  "data1      data2      line\n");
+	IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n",
+		  desc_lookup(desc), desc, time, data1, data2, line);
+	IWL_ERROR("blink1  blink2  ilink1  ilink2\n");
+	IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
+		  ilink1, ilink2);
+
+	iwl_release_restricted_access(priv);
+}
+
+#define EVENT_START_OFFSET  (4 * sizeof(u32))
+
+/**
+ * iwl_print_event_log - Dump error event log to syslog
+ *
+ * NOTE: Must be called with iwl_grab_restricted_access() already obtained!
+ */
+static void iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
+				u32 num_events, u32 mode)
+{
+	u32 i;
+	u32 base;       /* SRAM byte address of event log header */
+	u32 event_size;	/* 2 u32s, or 3 u32s if timestamp recorded */
+	u32 ptr;        /* SRAM byte address of log data */
+	u32 ev, time, data; /* event log data */
+
+	if (num_events == 0)
+		return;
+
+	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+
+	if (mode == 0)
+		event_size = 2 * sizeof(u32);
+	else
+		event_size = 3 * sizeof(u32);
+
+	ptr = base + EVENT_START_OFFSET + (start_idx * event_size);
+
+	/* "time" is actually "data" for mode 0 (no timestamp).
+	 * place event id # at far right for easier visual parsing. */
+	for (i = 0; i < num_events; i++) {
+		ev = iwl_read_restricted_mem(priv, ptr);
+		ptr += sizeof(u32);
+		time = iwl_read_restricted_mem(priv, ptr);
+		ptr += sizeof(u32);
+		if (mode == 0)
+			IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */
+		else {
+			data = iwl_read_restricted_mem(priv, ptr);
+			ptr += sizeof(u32);
+			IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev);
+		}
+	}
+}
+
+static void iwl_dump_nic_event_log(struct iwl_priv *priv)
+{
+	int rc;
+	u32 base;       /* SRAM byte address of event log header */
+	u32 capacity;   /* event log capacity in # entries */
+	u32 mode;       /* 0 - no timestamp, 1 - timestamp recorded */
+	u32 num_wraps;  /* # times uCode wrapped to top of log */
+	u32 next_entry; /* index of next entry to be written by uCode */
+	u32 size;       /* # entries that we'll print */
+
+	base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+	if (!iwl_hw_valid_rtc_data_addr(base)) {
+		IWL_ERROR("Invalid event log pointer 0x%08X\n", base);
+		return;
+	}
+
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		IWL_WARNING("Can not read from adapter at this time.\n");
+		return;
+	}
+
+	/* event log header */
+	capacity = iwl_read_restricted_mem(priv, base);
+	mode = iwl_read_restricted_mem(priv, base + (1 * sizeof(u32)));
+	num_wraps = iwl_read_restricted_mem(priv, base + (2 * sizeof(u32)));
+	next_entry = iwl_read_restricted_mem(priv, base + (3 * sizeof(u32)));
+
+	size = num_wraps ? capacity : next_entry;
+
+	/* bail out if nothing in log */
+	if (size == 0) {
+		IWL_ERROR("Start IWL Event Log Dump: nothing in log\n");
+		iwl_release_restricted_access(priv);
+		return;
+	}
+
+	IWL_ERROR("Start IWL Event Log Dump: display count %d, wraps %d\n",
+		  size, num_wraps);
+
+	/* if uCode has wrapped back to top of log, start at the oldest entry,
+	 * i.e the next one that uCode would fill. */
+	if (num_wraps)
+		iwl_print_event_log(priv, next_entry,
+				    capacity - next_entry, mode);
+
+	/* (then/else) start at top of log */
+	iwl_print_event_log(priv, 0, next_entry, mode);
+
+	iwl_release_restricted_access(priv);
+}
+
+/**
+ * iwl_irq_handle_error - called for HW or SW error interrupt from card
+ */
+static void iwl_irq_handle_error(struct iwl_priv *priv)
+{
+	/* Set the FW error flag -- cleared on iwl_down */
+	set_bit(STATUS_FW_ERROR, &priv->status);
+
+	/* Cancel currently queued command. */
+	clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (iwl_debug_level & IWL_DL_FW_ERRORS) {
+		iwl_dump_nic_error_log(priv);
+		iwl_dump_nic_event_log(priv);
+		iwl_print_rx_config_cmd(&priv->staging_rxon);
+	}
+#endif
+
+	wake_up_interruptible(&priv->wait_command_queue);
+
+	/* Keep the restart process from trying to send host
+	 * commands by clearing the INIT status bit */
+	clear_bit(STATUS_READY, &priv->status);
+
+	if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+		IWL_DEBUG(IWL_DL_INFO | IWL_DL_FW_ERRORS,
+			  "Restarting adapter due to uCode error.\n");
+
+		if (iwl_is_associated(priv)) {
+			memcpy(&priv->recovery_rxon, &priv->active_rxon,
+			       sizeof(priv->recovery_rxon));
+			priv->error_recovering = 1;
+		}
+		queue_work(priv->workqueue, &priv->restart);
+	}
+}
+
+static void iwl_error_recovery(struct iwl_priv *priv)
+{
+	unsigned long flags;
+
+	memcpy(&priv->staging_rxon, &priv->recovery_rxon,
+	       sizeof(priv->staging_rxon));
+	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	iwl_commit_rxon(priv);
+
+	iwl_rxon_add_station(priv, priv->bssid, 1);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->assoc_id = le16_to_cpu(priv->staging_rxon.assoc_id);
+	priv->error_recovering = 0;
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void iwl_irq_tasklet(struct iwl_priv *priv)
+{
+	u32 inta, handled = 0;
+	u32 inta_fh;
+	unsigned long flags;
+#ifdef CONFIG_IWLWIFI_DEBUG
+	u32 inta_mask;
+#endif
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	/* Ack/clear/reset pending uCode interrupts.
+	 * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
+	 *  and will clear only when CSR_FH_INT_STATUS gets cleared. */
+	inta = iwl_read32(priv, CSR_INT);
+	iwl_write32(priv, CSR_INT, inta);
+
+	/* Ack/clear/reset pending flow-handler (DMA) interrupts.
+	 * Any new interrupts that happen after this, either while we're
+	 * in this tasklet, or later, will show up in next ISR/tasklet. */
+	inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+	iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (iwl_debug_level & IWL_DL_ISR) {
+		inta_mask = iwl_read32(priv, CSR_INT_MASK); /* just for debug */
+		IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+			      inta, inta_mask, inta_fh);
+	}
+#endif
+
+	/* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
+	 * atomic, make sure that inta covers all the interrupts that
+	 * we've discovered, even if FH interrupt came in just after
+	 * reading CSR_INT. */
+	if (inta_fh & CSR_FH_INT_RX_MASK)
+		inta |= CSR_INT_BIT_FH_RX;
+	if (inta_fh & CSR_FH_INT_TX_MASK)
+		inta |= CSR_INT_BIT_FH_TX;
+
+	/* Now service all interrupt bits discovered above. */
+	if (inta & CSR_INT_BIT_HW_ERR) {
+		IWL_ERROR("Microcode HW error detected.  Restarting.\n");
+
+		/* Tell the device to stop sending interrupts */
+		iwl_disable_interrupts(priv);
+
+		iwl_irq_handle_error(priv);
+
+		handled |= CSR_INT_BIT_HW_ERR;
+
+		spin_unlock_irqrestore(&priv->lock, flags);
+
+		return;
+	}
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (iwl_debug_level & (IWL_DL_ISR)) {
+		/* NIC fires this, but we don't use it, redundant with WAKEUP */
+		if (inta & CSR_INT_BIT_MAC_CLK_ACTV)
+			IWL_DEBUG_ISR("Microcode started or stopped.\n");
+
+		/* Alive notification via Rx interrupt will do the real work */
+		if (inta & CSR_INT_BIT_ALIVE)
+			IWL_DEBUG_ISR("Alive interrupt\n");
+	}
+#endif
+	/* Safely ignore these bits for debug checks below */
+	inta &= ~(CSR_INT_BIT_MAC_CLK_ACTV | CSR_INT_BIT_ALIVE);
+
+	/* HW RF KILL switch toggled (4965 only) */
+	if (inta & CSR_INT_BIT_RF_KILL) {
+		int hw_rf_kill = 0;
+		if (!(iwl_read32(priv, CSR_GP_CNTRL) &
+				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+			hw_rf_kill = 1;
+
+		IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR,
+				"RF_KILL bit toggled to %s.\n",
+				hw_rf_kill ? "disable radio":"enable radio");
+
+		/* Queue restart only if RF_KILL switch was set to "kill"
+		 *   when we loaded driver, and is now set to "enable".
+		 * After we're Alive, RF_KILL gets handled by
+		 *   iwl_rx_card_state_notif() */
+		if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status))
+			queue_work(priv->workqueue, &priv->restart);
+
+		handled |= CSR_INT_BIT_RF_KILL;
+	}
+
+	/* Chip got too hot and stopped itself (4965 only) */
+	if (inta & CSR_INT_BIT_CT_KILL) {
+		IWL_ERROR("Microcode CT kill error detected.\n");
+		handled |= CSR_INT_BIT_CT_KILL;
+	}
+
+	/* Error detected by uCode */
+	if (inta & CSR_INT_BIT_SW_ERR) {
+		IWL_ERROR("Microcode SW error detected.  Restarting 0x%X.\n",
+			  inta);
+		iwl_irq_handle_error(priv);
+		handled |= CSR_INT_BIT_SW_ERR;
+	}
+
+	/* uCode wakes up after power-down sleep */
+	if (inta & CSR_INT_BIT_WAKEUP) {
+		IWL_DEBUG_ISR("Wakeup interrupt\n");
+		iwl_rx_queue_update_write_ptr(priv, &priv->rxq);
+		iwl_tx_queue_update_write_ptr(priv, &priv->txq[0]);
+		iwl_tx_queue_update_write_ptr(priv, &priv->txq[1]);
+		iwl_tx_queue_update_write_ptr(priv, &priv->txq[2]);
+		iwl_tx_queue_update_write_ptr(priv, &priv->txq[3]);
+		iwl_tx_queue_update_write_ptr(priv, &priv->txq[4]);
+		iwl_tx_queue_update_write_ptr(priv, &priv->txq[5]);
+
+		handled |= CSR_INT_BIT_WAKEUP;
+	}
+
+	/* All uCode command responses, including Tx command responses,
+	 * Rx "responses" (frame-received notification), and other
+	 * notifications from uCode come through here*/
+	if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
+		iwl_rx_handle(priv);
+		handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
+	}
+
+	if (inta & CSR_INT_BIT_FH_TX) {
+		IWL_DEBUG_ISR("Tx interrupt\n");
+		handled |= CSR_INT_BIT_FH_TX;
+	}
+
+	if (inta & ~handled)
+		IWL_ERROR("Unhandled INTA bits 0x%08x\n", inta & ~handled);
+
+	if (inta & ~CSR_INI_SET_MASK) {
+		IWL_WARNING("Disabled INTA bits 0x%08x were pending\n",
+			 inta & ~CSR_INI_SET_MASK);
+		IWL_WARNING("   with FH_INT = 0x%08x\n", inta_fh);
+	}
+
+	/* Re-enable all interrupts */
+	iwl_enable_interrupts(priv);
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+	if (iwl_debug_level & (IWL_DL_ISR)) {
+		inta = iwl_read32(priv, CSR_INT);
+		inta_mask = iwl_read32(priv, CSR_INT_MASK);
+		inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+		IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, "
+			"flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
+	}
+#endif
+	spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static irqreturn_t iwl_isr(int irq, void *data)
+{
+	struct iwl_priv *priv = data;
+	u32 inta, inta_mask;
+	u32 inta_fh;
+	if (!priv)
+		return IRQ_NONE;
+
+	spin_lock(&priv->lock);
+
+	/* Disable (but don't clear!) interrupts here to avoid
+	 *    back-to-back ISRs and sporadic interrupts from our NIC.
+	 * If we have something to service, the tasklet will re-enable ints.
+	 * If we *don't* have something, we'll re-enable before leaving here. */
+	inta_mask = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
+	iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+	/* Discover which interrupts are active/pending */
+	inta = iwl_read32(priv, CSR_INT);
+	inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+
+	/* Ignore interrupt if there's nothing in NIC to service.
+	 * This may be due to IRQ shared with another device,
+	 * or due to sporadic interrupts thrown from our NIC. */
+	if (!inta && !inta_fh) {
+		IWL_DEBUG_ISR("Ignore interrupt, inta == 0, inta_fh == 0\n");
+		goto none;
+	}
+
+	if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+		/* Hardware disappeared */
+		IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta);
+		goto none;
+	}
+
+	IWL_DEBUG_ISR("ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+		      inta, inta_mask, inta_fh);
+
+	/* iwl_irq_tasklet() will service interrupts and re-enable them */
+	tasklet_schedule(&priv->irq_tasklet);
+	spin_unlock(&priv->lock);
+
+	return IRQ_HANDLED;
+
+ none:
+	/* re-enable interrupts here since we don't have anything to service. */
+	iwl_enable_interrupts(priv);
+	spin_unlock(&priv->lock);
+	return IRQ_NONE;
+}
+
+/************************** EEPROM BANDS ****************************
+ *
+ * The iwl_eeprom_band definitions below provide the mapping from the
+ * EEPROM contents to the specific channel number supported for each
+ * band.
+ *
+ * For example, iwl_priv->eeprom.band_3_channels[4] from the band_3
+ * definition below maps to physical channel 42 in the 5.2GHz spectrum.
+ * The specific geography and calibration information for that channel
+ * is contained in the eeprom map itself.
+ *
+ * During init, we copy the eeprom information and channel map
+ * information into priv->channel_info_24/52 and priv->channel_map_24/52
+ *
+ * channel_map_24/52 provides the index in the channel_info array for a
+ * given channel.  We have to have two separate maps as there is channel
+ * overlap with the 2.4GHz and 5.2GHz spectrum as seen in band_1 and
+ * band_2
+ *
+ * A value of 0xff stored in the channel_map indicates that the channel
+ * is not supported by the hardware at all.
+ *
+ * A value of 0xfe in the channel_map indicates that the channel is not
+ * valid for Tx with the current hardware.  This means that
+ * while the system can tune and receive on a given channel, it may not
+ * be able to associate or transmit any frames on that
+ * channel.  There is no corresponding channel information for that
+ * entry.
+ *
+ *********************************************************************/
+
+/* 2.4 GHz */
+static const u8 iwl_eeprom_band_1[14] = {
+	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+};
+
+/* 5.2 GHz bands */
+static const u8 iwl_eeprom_band_2[] = {
+	183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16
+};
+
+static const u8 iwl_eeprom_band_3[] = {	/* 5205-5320MHz */
+	34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
+};
+
+static const u8 iwl_eeprom_band_4[] = {	/* 5500-5700MHz */
+	100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
+};
+
+static const u8 iwl_eeprom_band_5[] = {	/* 5725-5825MHz */
+	145, 149, 153, 157, 161, 165
+};
+
+static u8 iwl_eeprom_band_6[] = {       /* 2.4 FAT channel */
+	1, 2, 3, 4, 5, 6, 7
+};
+
+static u8 iwl_eeprom_band_7[] = {       /* 5.2 FAT channel */
+	36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157
+};
+
+static void iwl_init_band_reference(const struct iwl_priv *priv, int band,
+				    int *eeprom_ch_count,
+				    const struct iwl_eeprom_channel
+				    **eeprom_ch_info,
+				    const u8 **eeprom_ch_index)
+{
+	switch (band) {
+	case 1:		/* 2.4GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1);
+		*eeprom_ch_info = priv->eeprom.band_1_channels;
+		*eeprom_ch_index = iwl_eeprom_band_1;
+		break;
+	case 2:		/* 5.2GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2);
+		*eeprom_ch_info = priv->eeprom.band_2_channels;
+		*eeprom_ch_index = iwl_eeprom_band_2;
+		break;
+	case 3:		/* 5.2GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3);
+		*eeprom_ch_info = priv->eeprom.band_3_channels;
+		*eeprom_ch_index = iwl_eeprom_band_3;
+		break;
+	case 4:		/* 5.2GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4);
+		*eeprom_ch_info = priv->eeprom.band_4_channels;
+		*eeprom_ch_index = iwl_eeprom_band_4;
+		break;
+	case 5:		/* 5.2GHz band */
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5);
+		*eeprom_ch_info = priv->eeprom.band_5_channels;
+		*eeprom_ch_index = iwl_eeprom_band_5;
+		break;
+	case 6:
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6);
+		*eeprom_ch_info = priv->eeprom.band_24_channels;
+		*eeprom_ch_index = iwl_eeprom_band_6;
+		break;
+	case 7:
+		*eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7);
+		*eeprom_ch_info = priv->eeprom.band_52_channels;
+		*eeprom_ch_index = iwl_eeprom_band_7;
+		break;
+	default:
+		BUG();
+		return;
+	}
+}
+
+const struct iwl_channel_info *iwl_get_channel_info(const struct iwl_priv *priv,
+						    int phymode, u16 channel)
+{
+	int i;
+
+	switch (phymode) {
+	case MODE_IEEE80211A:
+		for (i = 14; i < priv->channel_count; i++) {
+			if (priv->channel_info[i].channel == channel)
+				return &priv->channel_info[i];
+		}
+		break;
+
+	case MODE_IEEE80211B:
+	case MODE_IEEE80211G:
+		if (channel >= 1 && channel <= 14)
+			return &priv->channel_info[channel - 1];
+		break;
+
+	}
+
+	return NULL;
+}
+
+#define CHECK_AND_PRINT(x) ((eeprom_ch_info[ch].flags & EEPROM_CHANNEL_##x) \
+			    ? # x " " : "")
+
+static int iwl_init_channel_map(struct iwl_priv *priv)
+{
+	int eeprom_ch_count = 0;
+	const u8 *eeprom_ch_index = NULL;
+	const struct iwl_eeprom_channel *eeprom_ch_info = NULL;
+	int band, ch;
+	struct iwl_channel_info *ch_info;
+
+	if (priv->channel_count) {
+		IWL_DEBUG_INFO("Channel map already initialized.\n");
+		return 0;
+	}
+
+	if (priv->eeprom.version < 0x2f) {
+		IWL_WARNING("Unsupported EEPROM version: 0x%04X\n",
+			    priv->eeprom.version);
+		return -EINVAL;
+	}
+
+	IWL_DEBUG_INFO("Initializing regulatory info from EEPROM\n");
+
+	priv->channel_count =
+	    ARRAY_SIZE(iwl_eeprom_band_1) +
+	    ARRAY_SIZE(iwl_eeprom_band_2) +
+	    ARRAY_SIZE(iwl_eeprom_band_3) +
+	    ARRAY_SIZE(iwl_eeprom_band_4) +
+	    ARRAY_SIZE(iwl_eeprom_band_5);
+
+	IWL_DEBUG_INFO("Parsing data for %d channels.\n", priv->channel_count);
+
+	priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) *
+				     priv->channel_count, GFP_KERNEL);
+	if (!priv->channel_info) {
+		IWL_ERROR("Could not allocate channel_info\n");
+		priv->channel_count = 0;
+		return -ENOMEM;
+	}
+
+	ch_info = priv->channel_info;
+
+	/* Loop through the 5 EEPROM bands adding them in order to the
+	 * channel map we maintain (that contains additional information than
+	 * what just in the EEPROM) */
+	for (band = 1; band <= 5; band++) {
+
+		iwl_init_band_reference(priv, band, &eeprom_ch_count,
+					&eeprom_ch_info, &eeprom_ch_index);
+
+		/* Loop through each band adding each of the channels */
+		for (ch = 0; ch < eeprom_ch_count; ch++) {
+			ch_info->channel = eeprom_ch_index[ch];
+			ch_info->phymode = (band == 1) ? MODE_IEEE80211B :
+			    MODE_IEEE80211A;
+
+			/* permanently store EEPROM's channel regulatory flags
+			 *   and max power in channel info database. */
+			ch_info->eeprom = eeprom_ch_info[ch];
+
+			/* Copy the run-time flags so they are there even on
+			 * invalid channels */
+			ch_info->flags = eeprom_ch_info[ch].flags;
+
+			if (!(is_channel_valid(ch_info))) {
+				IWL_DEBUG_INFO("Ch. %d Flags %x [%sGHz] - "
+					       "No traffic\n",
+					       ch_info->channel,
+					       ch_info->flags,
+					       is_channel_a_band(ch_info) ?
+					       "5.2" : "2.4");
+				ch_info++;
+				continue;
+			}
+
+			/* Initialize regulatory-based run-time data */
+			ch_info->max_power_avg = ch_info->curr_txpow =
+			    eeprom_ch_info[ch].max_power_avg;
+			ch_info->scan_power = eeprom_ch_info[ch].max_power_avg;
+			ch_info->min_power = 0;
+
+			IWL_DEBUG_INFO("Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x"
+				       " %ddBm): Ad-Hoc %ssupported\n",
+				       ch_info->channel,
+				       is_channel_a_band(ch_info) ?
+				       "5.2" : "2.4",
+				       CHECK_AND_PRINT(IBSS),
+				       CHECK_AND_PRINT(ACTIVE),
+				       CHECK_AND_PRINT(RADAR),
+				       CHECK_AND_PRINT(WIDE),
+				       CHECK_AND_PRINT(NARROW),
+				       CHECK_AND_PRINT(DFS),
+				       eeprom_ch_info[ch].flags,
+				       eeprom_ch_info[ch].max_power_avg,
+				       ((eeprom_ch_info[ch].
+					 flags & EEPROM_CHANNEL_IBSS)
+					&& !(eeprom_ch_info[ch].
+					     flags & EEPROM_CHANNEL_RADAR))
+				       ? "" : "not ");
+
+			/* Set the user_txpower_limit to the highest power
+			 * supported by any channel */
+			if (eeprom_ch_info[ch].max_power_avg >
+			    priv->user_txpower_limit)
+				priv->user_txpower_limit =
+				    eeprom_ch_info[ch].max_power_avg;
+
+			ch_info++;
+		}
+	}
+
+	for (band = 6; band <= 7; band++) {
+		int phymode;
+		u8 fat_extension_chan;
+
+		iwl_init_band_reference(priv, band, &eeprom_ch_count,
+					&eeprom_ch_info, &eeprom_ch_index);
+
+		phymode = (band == 6) ? MODE_IEEE80211B : MODE_IEEE80211A;
+		/* Loop through each band adding each of the channels */
+		for (ch = 0; ch < eeprom_ch_count; ch++) {
+
+			if ((band == 6) &&
+			    ((eeprom_ch_index[ch] == 5) ||
+			    (eeprom_ch_index[ch] == 6) ||
+			    (eeprom_ch_index[ch] == 7)))
+			       fat_extension_chan = HT_IE_EXT_CHANNEL_MAX;
+			else
+				fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE;
+
+			iwl4965_set_fat_chan_info(priv, phymode,
+						  eeprom_ch_index[ch],
+						  &(eeprom_ch_info[ch]),
+						  fat_extension_chan);
+
+			iwl4965_set_fat_chan_info(priv, phymode,
+						  (eeprom_ch_index[ch] + 4),
+						  &(eeprom_ch_info[ch]),
+						  HT_IE_EXT_CHANNEL_BELOW);
+		}
+	}
+
+	return 0;
+}
+
+/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
+ * sending probe req.  This should be set long enough to hear probe responses
+ * from more than one AP.  */
+#define IWL_ACTIVE_DWELL_TIME_24    (20)	/* all times in msec */
+#define IWL_ACTIVE_DWELL_TIME_52    (10)
+
+/* For faster active scanning, scan will move to the next channel if fewer than
+ * PLCP_QUIET_THRESH packets are heard on this channel within
+ * ACTIVE_QUIET_TIME after sending probe request.  This shortens the dwell
+ * time if it's a quiet channel (nothing responded to our probe, and there's
+ * no other traffic).
+ * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */
+#define IWL_PLCP_QUIET_THRESH       __constant_cpu_to_le16(1)	/* packets */
+#define IWL_ACTIVE_QUIET_TIME       __constant_cpu_to_le16(5)	/* msec */
+
+/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
+ * Must be set longer than active dwell time.
+ * For the most reliable scan, set > AP beacon interval (typically 100msec). */
+#define IWL_PASSIVE_DWELL_TIME_24   (20)	/* all times in msec */
+#define IWL_PASSIVE_DWELL_TIME_52   (10)
+#define IWL_PASSIVE_DWELL_BASE      (100)
+#define IWL_CHANNEL_TUNE_TIME       5
+
+static inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, int phymode)
+{
+	if (phymode == MODE_IEEE80211A)
+		return IWL_ACTIVE_DWELL_TIME_52;
+	else
+		return IWL_ACTIVE_DWELL_TIME_24;
+}
+
+static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, int phymode)
+{
+	u16 active = iwl_get_active_dwell_time(priv, phymode);
+	u16 passive = (phymode != MODE_IEEE80211A) ?
+	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
+	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
+
+	if (iwl_is_associated(priv)) {
+		/* If we're associated, we clamp the maximum passive
+		 * dwell time to be 98% of the beacon interval (minus
+		 * 2 * channel tune time) */
+		passive = priv->beacon_int;
+		if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive)
+			passive = IWL_PASSIVE_DWELL_BASE;
+		passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
+	}
+
+	if (passive <= active)
+		passive = active + 1;
+
+	return passive;
+}
+
+static int iwl_get_channels_for_scan(struct iwl_priv *priv, int phymode,
+				     u8 is_active, u8 direct_mask,
+				     struct iwl_scan_channel *scan_ch)
+{
+	const struct ieee80211_channel *channels = NULL;
+	const struct ieee80211_hw_mode *hw_mode;
+	const struct iwl_channel_info *ch_info;
+	u16 passive_dwell = 0;
+	u16 active_dwell = 0;
+	int added, i;
+
+	hw_mode = iwl_get_hw_mode(priv, phymode);
+	if (!hw_mode)
+		return 0;
+
+	channels = hw_mode->channels;
+
+	active_dwell = iwl_get_active_dwell_time(priv, phymode);
+	passive_dwell = iwl_get_passive_dwell_time(priv, phymode);
+
+	for (i = 0, added = 0; i < hw_mode->num_channels; i++) {
+		if (channels[i].chan ==
+		    le16_to_cpu(priv->active_rxon.channel)) {
+			if (iwl_is_associated(priv)) {
+				IWL_DEBUG_SCAN
+				    ("Skipping current channel %d\n",
+				     le16_to_cpu(priv->active_rxon.channel));
+				continue;
+			}
+		} else if (priv->only_active_channel)
+			continue;
+
+		scan_ch->channel = channels[i].chan;
+
+		ch_info = iwl_get_channel_info(priv, phymode, scan_ch->channel);
+		if (!is_channel_valid(ch_info)) {
+			IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
+				       scan_ch->channel);
+			continue;
+		}
+
+		if (!is_active || is_channel_passive(ch_info) ||
+		    !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN))
+			scan_ch->type = 0;	/* passive */
+		else
+			scan_ch->type = 1;	/* active */
+
+		if (scan_ch->type & 1)
+			scan_ch->type |= (direct_mask << 1);
+
+		if (is_channel_narrow(ch_info))
+			scan_ch->type |= (1 << 7);
+
+		scan_ch->active_dwell = cpu_to_le16(active_dwell);
+		scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+
+		/* Set power levels to defaults */
+		scan_ch->tpc.dsp_atten = 110;
+		/* scan_pwr_info->tpc.dsp_atten; */
+
+		/*scan_pwr_info->tpc.tx_gain; */
+		if (phymode == MODE_IEEE80211A)
+			scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3;
+		else {
+			scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
+			/* NOTE: if we were doing 6Mb OFDM for scans we'd use
+			 * power level
+			 scan_ch->tpc.tx_gain = ((1<<5) | (2 << 3)) | 3;
+			 */
+		}
+
+		IWL_DEBUG_SCAN("Scanning %d [%s %d]\n",
+			       scan_ch->channel,
+			       (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE",
+			       (scan_ch->type & 1) ?
+			       active_dwell : passive_dwell);
+
+		scan_ch++;
+		added++;
+	}
+
+	IWL_DEBUG_SCAN("total channels to scan %d \n", added);
+	return added;
+}
+
+static void iwl_reset_channel_flag(struct iwl_priv *priv)
+{
+	int i, j;
+	for (i = 0; i < 3; i++) {
+		struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i];
+		for (j = 0; j < hw_mode->num_channels; j++)
+			hw_mode->channels[j].flag = hw_mode->channels[j].val;
+	}
+}
+
+static void iwl_init_hw_rates(struct iwl_priv *priv,
+			      struct ieee80211_rate *rates)
+{
+	int i;
+
+	for (i = 0; i < IWL_RATE_COUNT; i++) {
+		rates[i].rate = iwl_rates[i].ieee * 5;
+		rates[i].val = i; /* Rate scaling will work on indexes */
+		rates[i].val2 = i;
+		rates[i].flags = IEEE80211_RATE_SUPPORTED;
+		/* Only OFDM have the bits-per-symbol set */
+		if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE))
+			rates[i].flags |= IEEE80211_RATE_OFDM;
+		else {
+			/*
+			 * If CCK 1M then set rate flag to CCK else CCK_2
+			 * which is CCK | PREAMBLE2
+			 */
+			rates[i].flags |= (iwl_rates[i].plcp == 10) ?
+				IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2;
+		}
+
+		/* Set up which ones are basic rates... */
+		if (IWL_BASIC_RATES_MASK & (1 << i))
+			rates[i].flags |= IEEE80211_RATE_BASIC;
+	}
+
+	iwl4965_init_hw_rates(priv, rates);
+}
+
+/**
+ * iwl_init_geos - Initialize mac80211's geo/channel info based from eeprom
+ */
+static int iwl_init_geos(struct iwl_priv *priv)
+{
+	struct iwl_channel_info *ch;
+	struct ieee80211_hw_mode *modes;
+	struct ieee80211_channel *channels;
+	struct ieee80211_channel *geo_ch;
+	struct ieee80211_rate *rates;
+	int i = 0;
+	enum {
+		A = 0,
+		B = 1,
+		G = 2,
+		A_11N = 3,
+		G_11N = 4,
+	};
+	int mode_count = 5;
+
+	if (priv->modes) {
+		IWL_DEBUG_INFO("Geography modes already initialized.\n");
+		set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+		return 0;
+	}
+
+	modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count,
+			GFP_KERNEL);
+	if (!modes)
+		return -ENOMEM;
+
+	channels = kzalloc(sizeof(struct ieee80211_channel) *
+			   priv->channel_count, GFP_KERNEL);
+	if (!channels) {
+		kfree(modes);
+		return -ENOMEM;
+	}
+
+	rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)),
+			GFP_KERNEL);
+	if (!rates) {
+		kfree(modes);
+		kfree(channels);
+		return -ENOMEM;
+	}
+
+	/* 0 = 802.11a
+	 * 1 = 802.11b
+	 * 2 = 802.11g
+	 */
+
+	/* 5.2GHz channels start after the 2.4GHz channels */
+	modes[A].mode = MODE_IEEE80211A;
+	modes[A].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
+	modes[A].rates = rates;
+	modes[A].num_rates = 8;	/* just OFDM */
+	modes[A].rates = &rates[4];
+	modes[A].num_channels = 0;
+
+	modes[B].mode = MODE_IEEE80211B;
+	modes[B].channels = channels;
+	modes[B].rates = rates;
+	modes[B].num_rates = 4;	/* just CCK */
+	modes[B].num_channels = 0;
+
+	modes[G].mode = MODE_IEEE80211G;
+	modes[G].channels = channels;
+	modes[G].rates = rates;
+	modes[G].num_rates = 12;	/* OFDM & CCK */
+	modes[G].num_channels = 0;
+
+	modes[G_11N].mode = MODE_IEEE80211G;
+	modes[G_11N].channels = channels;
+	modes[G_11N].num_rates = 13;        /* OFDM & CCK */
+	modes[G_11N].rates = rates;
+	modes[G_11N].num_channels = 0;
+
+	modes[A_11N].mode = MODE_IEEE80211A;
+	modes[A_11N].channels = &channels[ARRAY_SIZE(iwl_eeprom_band_1)];
+	modes[A_11N].rates = &rates[4];
+	modes[A_11N].num_rates = 9; /* just OFDM */
+	modes[A_11N].num_channels = 0;
+
+	priv->ieee_channels = channels;
+	priv->ieee_rates = rates;
+
+	iwl_init_hw_rates(priv, rates);
+
+	for (i = 0, geo_ch = channels; i < priv->channel_count; i++) {
+		ch = &priv->channel_info[i];
+
+		if (!is_channel_valid(ch)) {
+			IWL_DEBUG_INFO("Channel %d [%sGHz] is restricted -- "
+				    "skipping.\n",
+				    ch->channel, is_channel_a_band(ch) ?
+				    "5.2" : "2.4");
+			continue;
+		}
+
+		if (is_channel_a_band(ch)) {
+			geo_ch = &modes[A].channels[modes[A].num_channels++];
+			modes[A_11N].num_channels++;
+		} else {
+			geo_ch = &modes[B].channels[modes[B].num_channels++];
+			modes[G].num_channels++;
+			modes[G_11N].num_channels++;
+		}
+
+		geo_ch->freq = ieee80211chan2mhz(ch->channel);
+		geo_ch->chan = ch->channel;
+		geo_ch->power_level = ch->max_power_avg;
+		geo_ch->antenna_max = 0xff;
+
+		if (is_channel_valid(ch)) {
+			geo_ch->flag = IEEE80211_CHAN_W_SCAN;
+			if (ch->flags & EEPROM_CHANNEL_IBSS)
+				geo_ch->flag |= IEEE80211_CHAN_W_IBSS;
+
+			if (ch->flags & EEPROM_CHANNEL_ACTIVE)
+				geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN;
+
+			if (ch->flags & EEPROM_CHANNEL_RADAR)
+				geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT;
+
+			if (ch->max_power_avg > priv->max_channel_txpower_limit)
+				priv->max_channel_txpower_limit =
+				    ch->max_power_avg;
+		}
+
+		geo_ch->val = geo_ch->flag;
+	}
+
+	if ((modes[A].num_channels == 0) && priv->is_abg) {
+		printk(KERN_INFO DRV_NAME
+		       ": Incorrectly detected BG card as ABG.  Please send "
+		       "your PCI ID 0x%04X:0x%04X to maintainer.\n",
+		       priv->pci_dev->device, priv->pci_dev->subsystem_device);
+		priv->is_abg = 0;
+	}
+
+	printk(KERN_INFO DRV_NAME
+	       ": Tunable channels: %d 802.11bg, %d 802.11a channels\n",
+	       modes[G].num_channels, modes[A].num_channels);
+
+	/*
+	 * NOTE:  We register these in preference of order -- the
+	 * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick
+	 * a phymode based on rates or AP capabilities but seems to
+	 * configure it purely on if the channel being configured
+	 * is supported by a mode -- and the first match is taken
+	 */
+
+	if (modes[G].num_channels)
+		ieee80211_register_hwmode(priv->hw, &modes[G]);
+	if (modes[B].num_channels)
+		ieee80211_register_hwmode(priv->hw, &modes[B]);
+	if (modes[A].num_channels)
+		ieee80211_register_hwmode(priv->hw, &modes[A]);
+
+	priv->modes = modes;
+	set_bit(STATUS_GEO_CONFIGURED, &priv->status);
+
+	return 0;
+}
+
+/******************************************************************************
+ *
+ * uCode download functions
+ *
+ ******************************************************************************/
+
+static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
+{
+	if (priv->ucode_code.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_code.len,
+				    priv->ucode_code.v_addr,
+				    priv->ucode_code.p_addr);
+		priv->ucode_code.v_addr = NULL;
+	}
+	if (priv->ucode_data.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_data.len,
+				    priv->ucode_data.v_addr,
+				    priv->ucode_data.p_addr);
+		priv->ucode_data.v_addr = NULL;
+	}
+	if (priv->ucode_data_backup.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_data_backup.len,
+				    priv->ucode_data_backup.v_addr,
+				    priv->ucode_data_backup.p_addr);
+		priv->ucode_data_backup.v_addr = NULL;
+	}
+	if (priv->ucode_init.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_init.len,
+				    priv->ucode_init.v_addr,
+				    priv->ucode_init.p_addr);
+		priv->ucode_init.v_addr = NULL;
+	}
+	if (priv->ucode_init_data.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_init_data.len,
+				    priv->ucode_init_data.v_addr,
+				    priv->ucode_init_data.p_addr);
+		priv->ucode_init_data.v_addr = NULL;
+	}
+	if (priv->ucode_boot.v_addr != NULL) {
+		pci_free_consistent(priv->pci_dev,
+				    priv->ucode_boot.len,
+				    priv->ucode_boot.v_addr,
+				    priv->ucode_boot.p_addr);
+		priv->ucode_boot.v_addr = NULL;
+	}
+}
+
+/**
+ * iwl_verify_inst_full - verify runtime uCode image in card vs. host,
+ *     looking at all data.
+ */
+static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 * image, u32 len)
+{
+	u32 val;
+	u32 save_len = len;
+	int rc = 0;
+	u32 errcnt;
+
+	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+	rc = iwl_grab_restricted_access(priv);
+	if (rc)
+		return rc;
+
+	iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND);
+
+	errcnt = 0;
+	for (; len > 0; len -= sizeof(u32), image++) {
+		/* read data comes through single port, auto-incr addr */
+		/* NOTE: Use the debugless read so we don't flood kernel log
+		 * if IWL_DL_IO is set */
+		val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+		if (val != le32_to_cpu(*image)) {
+			IWL_ERROR("uCode INST section is invalid at "
+				  "offset 0x%x, is 0x%x, s/b 0x%x\n",
+				  save_len - len, val, le32_to_cpu(*image));
+			rc = -EIO;
+			errcnt++;
+			if (errcnt >= 20)
+				break;
+		}
+	}
+
+	iwl_release_restricted_access(priv);
+
+	if (!errcnt)
+		IWL_DEBUG_INFO
+		    ("ucode image in INSTRUCTION memory is good\n");
+
+	return rc;
+}
+
+
+/**
+ * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
+ *   using sample data 100 bytes apart.  If these sample points are good,
+ *   it's a pretty good bet that everything between them is good, too.
+ */
+static int iwl_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+{
+	u32 val;
+	int rc = 0;
+	u32 errcnt = 0;
+	u32 i;
+
+	IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
+
+	rc = iwl_grab_restricted_access(priv);
+	if (rc)
+		return rc;
+
+	for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
+		/* read data comes through single port, auto-incr addr */
+		/* NOTE: Use the debugless read so we don't flood kernel log
+		 * if IWL_DL_IO is set */
+		iwl_write_restricted(priv, HBUS_TARG_MEM_RADDR,
+			i + RTC_INST_LOWER_BOUND);
+		val = _iwl_read_restricted(priv, HBUS_TARG_MEM_RDAT);
+		if (val != le32_to_cpu(*image)) {
+#if 0 /* Enable this if you want to see details */
+			IWL_ERROR("uCode INST section is invalid at "
+				  "offset 0x%x, is 0x%x, s/b 0x%x\n",
+				  i, val, *image);
+#endif
+			rc = -EIO;
+			errcnt++;
+			if (errcnt >= 3)
+				break;
+		}
+	}
+
+	iwl_release_restricted_access(priv);
+
+	return rc;
+}
+
+
+/**
+ * iwl_verify_ucode - determine which instruction image is in SRAM,
+ *    and verify its contents
+ */
+static int iwl_verify_ucode(struct iwl_priv *priv)
+{
+	__le32 *image;
+	u32 len;
+	int rc = 0;
+
+	/* Try bootstrap */
+	image = (__le32 *)priv->ucode_boot.v_addr;
+	len = priv->ucode_boot.len;
+	rc = iwl_verify_inst_sparse(priv, image, len);
+	if (rc == 0) {
+		IWL_DEBUG_INFO("Bootstrap uCode is good in inst SRAM\n");
+		return 0;
+	}
+
+	/* Try initialize */
+	image = (__le32 *)priv->ucode_init.v_addr;
+	len = priv->ucode_init.len;
+	rc = iwl_verify_inst_sparse(priv, image, len);
+	if (rc == 0) {
+		IWL_DEBUG_INFO("Initialize uCode is good in inst SRAM\n");
+		return 0;
+	}
+
+	/* Try runtime/protocol */
+	image = (__le32 *)priv->ucode_code.v_addr;
+	len = priv->ucode_code.len;
+	rc = iwl_verify_inst_sparse(priv, image, len);
+	if (rc == 0) {
+		IWL_DEBUG_INFO("Runtime uCode is good in inst SRAM\n");
+		return 0;
+	}
+
+	IWL_ERROR("NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
+
+	/* Show first several data entries in instruction SRAM.
+	 * Selection of bootstrap image is arbitrary. */
+	image = (__le32 *)priv->ucode_boot.v_addr;
+	len = priv->ucode_boot.len;
+	rc = iwl_verify_inst_full(priv, image, len);
+
+	return rc;
+}
+
+
+/* check contents of special bootstrap uCode SRAM */
+static int iwl_verify_bsm(struct iwl_priv *priv)
+{
+	__le32 *image = priv->ucode_boot.v_addr;
+	u32 len = priv->ucode_boot.len;
+	u32 reg;
+	u32 val;
+
+	IWL_DEBUG_INFO("Begin verify bsm\n");
+
+	/* verify BSM SRAM contents */
+	val = iwl_read_restricted_reg(priv, BSM_WR_DWCOUNT_REG);
+	for (reg = BSM_SRAM_LOWER_BOUND;
+	     reg < BSM_SRAM_LOWER_BOUND + len;
+	     reg += sizeof(u32), image ++) {
+		val = iwl_read_restricted_reg(priv, reg);
+		if (val != le32_to_cpu(*image)) {
+			IWL_ERROR("BSM uCode verification failed at "
+				  "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
+				  BSM_SRAM_LOWER_BOUND,
+				  reg - BSM_SRAM_LOWER_BOUND, len,
+				  val, le32_to_cpu(*image));
+			return -EIO;
+		}
+	}
+
+	IWL_DEBUG_INFO("BSM bootstrap uCode image OK\n");
+
+	return 0;
+}
+
+/**
+ * iwl_load_bsm - Load bootstrap instructions
+ *
+ * BSM operation:
+ *
+ * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
+ * in special SRAM that does not power down during RFKILL.  When powering back
+ * up after power-saving sleeps (or during initial uCode load), the BSM loads
+ * the bootstrap program into the on-board processor, and starts it.
+ *
+ * The bootstrap program loads (via DMA) instructions and data for a new
+ * program from host DRAM locations indicated by the host driver in the
+ * BSM_DRAM_* registers.  Once the new program is loaded, it starts
+ * automatically.
+ *
+ * When initializing the NIC, the host driver points the BSM to the
+ * "initialize" uCode image.  This uCode sets up some internal data, then
+ * notifies host via "initialize alive" that it is complete.
+ *
+ * The host then replaces the BSM_DRAM_* pointer values to point to the
+ * normal runtime uCode instructions and a backup uCode data cache buffer
+ * (filled initially with starting data values for the on-board processor),
+ * then triggers the "initialize" uCode to load and launch the runtime uCode,
+ * which begins normal operation.
+ *
+ * When doing a power-save shutdown, runtime uCode saves data SRAM into
+ * the backup data cache in DRAM before SRAM is powered down.
+ *
+ * When powering back up, the BSM loads the bootstrap program.  This reloads
+ * the runtime uCode instructions and the backup data cache into SRAM,
+ * and re-launches the runtime uCode from where it left off.
+ */
+static int iwl_load_bsm(struct iwl_priv *priv)
+{
+	__le32 *image = priv->ucode_boot.v_addr;
+	u32 len = priv->ucode_boot.len;
+	dma_addr_t pinst;
+	dma_addr_t pdata;
+	u32 inst_len;
+	u32 data_len;
+	int rc;
+	int i;
+	u32 done;
+	u32 reg_offset;
+
+	IWL_DEBUG_INFO("Begin load bsm\n");
+
+	/* make sure bootstrap program is no larger than BSM's SRAM size */
+	if (len > IWL_MAX_BSM_SIZE)
+		return -EINVAL;
+
+	/* Tell bootstrap uCode where to find the "Initialize" uCode
+	 *   in host DRAM ... bits 31:0 for 3945, bits 35:4 for 4965.
+	 * NOTE:  iwl_initialize_alive_start() will replace these values,
+	 *        after the "initialize" uCode has run, to point to
+	 *        runtime/protocol instructions and backup data cache. */
+	pinst = priv->ucode_init.p_addr >> 4;
+	pdata = priv->ucode_init_data.p_addr >> 4;
+	inst_len = priv->ucode_init.len;
+	data_len = priv->ucode_init_data.len;
+
+	rc = iwl_grab_restricted_access(priv);
+	if (rc)
+		return rc;
+
+	iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
+	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+	iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
+	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
+
+	/* Fill BSM memory with bootstrap instructions */
+	for (reg_offset = BSM_SRAM_LOWER_BOUND;
+	     reg_offset < BSM_SRAM_LOWER_BOUND + len;
+	     reg_offset += sizeof(u32), image++)
+		_iwl_write_restricted_reg(priv, reg_offset,
+					  le32_to_cpu(*image));
+
+	rc = iwl_verify_bsm(priv);
+	if (rc) {
+		iwl_release_restricted_access(priv);
+		return rc;
+	}
+
+	/* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
+	iwl_write_restricted_reg(priv, BSM_WR_MEM_SRC_REG, 0x0);
+	iwl_write_restricted_reg(priv, BSM_WR_MEM_DST_REG,
+				 RTC_INST_LOWER_BOUND);
+	iwl_write_restricted_reg(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
+
+	/* Load bootstrap code into instruction SRAM now,
+	 *   to prepare to load "initialize" uCode */
+	iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG,
+		BSM_WR_CTRL_REG_BIT_START);
+
+	/* Wait for load of bootstrap uCode to finish */
+	for (i = 0; i < 100; i++) {
+		done = iwl_read_restricted_reg(priv, BSM_WR_CTRL_REG);
+		if (!(done & BSM_WR_CTRL_REG_BIT_START))
+			break;
+		udelay(10);
+	}
+	if (i < 100)
+		IWL_DEBUG_INFO("BSM write complete, poll %d iterations\n", i);
+	else {
+		IWL_ERROR("BSM write did not complete!\n");
+		return -EIO;
+	}
+
+	/* Enable future boot loads whenever power management unit triggers it
+	 *   (e.g. when powering back up after power-save shutdown) */
+	iwl_write_restricted_reg(priv, BSM_WR_CTRL_REG,
+		BSM_WR_CTRL_REG_BIT_START_EN);
+
+	iwl_release_restricted_access(priv);
+
+	return 0;
+}
+
+static void iwl_nic_start(struct iwl_priv *priv)
+{
+	/* Remove all resets to allow NIC to operate */
+	iwl_write32(priv, CSR_RESET, 0);
+}
+
+/**
+ * iwl_read_ucode - Read uCode images from disk file.
+ *
+ * Copy into buffers for card to fetch via bus-mastering
+ */
+static int iwl_read_ucode(struct iwl_priv *priv)
+{
+	struct iwl_ucode *ucode;
+	int rc = 0;
+	const struct firmware *ucode_raw;
+	const char *name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode";
+	u8 *src;
+	size_t len;
+	u32 ver, inst_size, data_size, init_size, init_data_size, boot_size;
+
+	/* Ask kernel firmware_class module to get the boot firmware off disk.
+	 * request_firmware() is synchronous, file is in memory on return. */
+	rc = request_firmware(&ucode_raw, name, &priv->pci_dev->dev);
+	if (rc < 0) {
+		IWL_ERROR("%s firmware file req failed: Reason %d\n", name, rc);
+		goto error;
+	}
+
+	IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n",
+		       name, ucode_raw->size);
+
+	/* Make sure that we got at least our header! */
+	if (ucode_raw->size < sizeof(*ucode)) {
+		IWL_ERROR("File size way too small!\n");
+		rc = -EINVAL;
+		goto err_release;
+	}
+
+	/* Data from ucode file:  header followed by uCode images */
+	ucode = (void *)ucode_raw->data;
+
+	ver = le32_to_cpu(ucode->ver);
+	inst_size = le32_to_cpu(ucode->inst_size);
+	data_size = le32_to_cpu(ucode->data_size);
+	init_size = le32_to_cpu(ucode->init_size);
+	init_data_size = le32_to_cpu(ucode->init_data_size);
+	boot_size = le32_to_cpu(ucode->boot_size);
+
+	IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver);
+	IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n",
+		       inst_size);
+	IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n",
+		       data_size);
+	IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n",
+		       init_size);
+	IWL_DEBUG_INFO("f/w package hdr init data size = %u\n",
+		       init_data_size);
+	IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n",
+		       boot_size);
+
+	/* Verify size of file vs. image size info in file's header */
+	if (ucode_raw->size < sizeof(*ucode) +
+		inst_size + data_size + init_size +
+		init_data_size + boot_size) {
+
+		IWL_DEBUG_INFO("uCode file size %d too small\n",
+			       (int)ucode_raw->size);
+		rc = -EINVAL;
+		goto err_release;
+	}
+
+	/* Verify that uCode images will fit in card's SRAM */
+	if (inst_size > IWL_MAX_INST_SIZE) {
+		IWL_DEBUG_INFO("uCode instr len %d too large to fit in card\n",
+			       (int)inst_size);
+		rc = -EINVAL;
+		goto err_release;
+	}
+
+	if (data_size > IWL_MAX_DATA_SIZE) {
+		IWL_DEBUG_INFO("uCode data len %d too large to fit in card\n",
+			       (int)data_size);
+		rc = -EINVAL;
+		goto err_release;
+	}
+	if (init_size > IWL_MAX_INST_SIZE) {
+		IWL_DEBUG_INFO
+		    ("uCode init instr len %d too large to fit in card\n",
+		     (int)init_size);
+		rc = -EINVAL;
+		goto err_release;
+	}
+	if (init_data_size > IWL_MAX_DATA_SIZE) {
+		IWL_DEBUG_INFO
+		    ("uCode init data len %d too large to fit in card\n",
+		     (int)init_data_size);
+		rc = -EINVAL;
+		goto err_release;
+	}
+	if (boot_size > IWL_MAX_BSM_SIZE) {
+		IWL_DEBUG_INFO
+		    ("uCode boot instr len %d too large to fit in bsm\n",
+		     (int)boot_size);
+		rc = -EINVAL;
+		goto err_release;
+	}
+
+	/* Allocate ucode buffers for card's bus-master loading ... */
+
+	/* Runtime instructions and 2 copies of data:
+	 * 1) unmodified from disk
+	 * 2) backup cache for save/restore during power-downs */
+	priv->ucode_code.len = inst_size;
+	priv->ucode_code.v_addr =
+	    pci_alloc_consistent(priv->pci_dev,
+				 priv->ucode_code.len,
+				 &(priv->ucode_code.p_addr));
+
+	priv->ucode_data.len = data_size;
+	priv->ucode_data.v_addr =
+	    pci_alloc_consistent(priv->pci_dev,
+				 priv->ucode_data.len,
+				 &(priv->ucode_data.p_addr));
+
+	priv->ucode_data_backup.len = data_size;
+	priv->ucode_data_backup.v_addr =
+	    pci_alloc_consistent(priv->pci_dev,
+				 priv->ucode_data_backup.len,
+				 &(priv->ucode_data_backup.p_addr));
+
+
+	/* Initialization instructions and data */
+	priv->ucode_init.len = init_size;
+	priv->ucode_init.v_addr =
+	    pci_alloc_consistent(priv->pci_dev,
+				 priv->ucode_init.len,
+				 &(priv->ucode_init.p_addr));
+
+	priv->ucode_init_data.len = init_data_size;
+	priv->ucode_init_data.v_addr =
+	    pci_alloc_consistent(priv->pci_dev,
+				 priv->ucode_init_data.len,
+				 &(priv->ucode_init_data.p_addr));
+
+	/* Bootstrap (instructions only, no data) */
+	priv->ucode_boot.len = boot_size;
+	priv->ucode_boot.v_addr =
+	    pci_alloc_consistent(priv->pci_dev,
+				 priv->ucode_boot.len,
+				 &(priv->ucode_boot.p_addr));
+
+	if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
+	    !priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr ||
+	    !priv->ucode_boot.v_addr || !priv->ucode_data_backup.v_addr)
+		goto err_pci_alloc;
+
+	/* Copy images into buffers for card's bus-master reads ... */
+
+	/* Runtime instructions (first block of data in file) */
+	src = &ucode->data[0];
+	len = priv->ucode_code.len;
+	IWL_DEBUG_INFO("Copying (but not loading) uCode instr len %d\n",
+		       (int)len);
+	memcpy(priv->ucode_code.v_addr, src, len);
+	IWL_DEBUG_INFO("uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
+		priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
+
+	/* Runtime data (2nd block)
+	 * NOTE:  Copy into backup buffer will be done in iwl_up()  */
+	src = &ucode->data[inst_size];
+	len = priv->ucode_data.len;
+	IWL_DEBUG_INFO("Copying (but not loading) uCode data len %d\n",
+		       (int)len);
+	memcpy(priv->ucode_data.v_addr, src, len);
+	memcpy(priv->ucode_data_backup.v_addr, src, len);
+
+	/* Initialization instructions (3rd block) */
+	if (init_size) {
+		src = &ucode->data[inst_size + data_size];
+		len = priv->ucode_init.len;
+		IWL_DEBUG_INFO("Copying (but not loading) init instr len %d\n",
+			       (int)len);
+		memcpy(priv->ucode_init.v_addr, src, len);
+	}
+
+	/* Initialization data (4th block) */
+	if (init_data_size) {
+		src = &ucode->data[inst_size + data_size + init_size];
+		len = priv->ucode_init_data.len;
+		IWL_DEBUG_INFO("Copying (but not loading) init data len %d\n",
+			       (int)len);
+		memcpy(priv->ucode_init_data.v_addr, src, len);
+	}
+
+	/* Bootstrap instructions (5th block) */
+	src = &ucode->data[inst_size + data_size + init_size + init_data_size];
+	len = priv->ucode_boot.len;
+	IWL_DEBUG_INFO("Copying (but not loading) boot instr len %d\n",
+		       (int)len);
+	memcpy(priv->ucode_boot.v_addr, src, len);
+
+	/* We have our copies now, allow OS release its copies */
+	release_firmware(ucode_raw);
+	return 0;
+
+ err_pci_alloc:
+	IWL_ERROR("failed to allocate pci memory\n");
+	rc = -ENOMEM;
+	iwl_dealloc_ucode_pci(priv);
+
+ err_release:
+	release_firmware(ucode_raw);
+
+ error:
+	return rc;
+}
+
+
+/**
+ * iwl_set_ucode_ptrs - Set uCode address location
+ *
+ * Tell initialization uCode where to find runtime uCode.
+ *
+ * BSM registers initially contain pointers to initialization uCode.
+ * We need to replace them to load runtime uCode inst and data,
+ * and to save runtime data when powering down.
+ */
+static int iwl_set_ucode_ptrs(struct iwl_priv *priv)
+{
+	dma_addr_t pinst;
+	dma_addr_t pdata;
+	int rc = 0;
+	unsigned long flags;
+
+	/* bits 35:4 for 4965 */
+	pinst = priv->ucode_code.p_addr >> 4;
+	pdata = priv->ucode_data_backup.p_addr >> 4;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	rc = iwl_grab_restricted_access(priv);
+	if (rc) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return rc;
+	}
+
+	/* Tell bootstrap uCode where to find image to load */
+	iwl_write_restricted_reg(priv, BSM_DRAM_INST_PTR_REG, pinst);
+	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+	iwl_write_restricted_reg(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
+				 priv->ucode_data.len);
+
+	/* Inst bytecount must be last to set up, bit 31 signals uCode
+	 *   that all new ptr/size info is in place */
+	iwl_write_restricted_reg(priv, BSM_DRAM_INST_BYTECOUNT_REG,
+				 priv->ucode_code.len | BSM_DRAM_INST_LOAD);
+
+	iwl_release_restricted_access(priv);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	IWL_DEBUG_INFO("Runtime uCode pointers are set.\n");
+
+	return rc;
+}
+
+/**
+ * iwl_init_alive_start - Called after REPLY_ALIVE notification receieved
+ *
+ * Called after REPLY_ALIVE notification received from "initialize" uCode.
+ *
+ * The 4965 "initialize" ALIVE reply contains calibration data for:
+ *   Voltage, temperature, and MIMO tx gain correction, now stored in priv
+ *   (3945 does not contain this data).
+ *
+ * Tell "initialize" uCode to go ahead and load the runtime uCode.
+*/
+static void iwl_init_alive_start(struct iwl_priv *priv)
+{
+	/* Check alive response for "valid" sign from uCode */
+	if (priv->card_alive_init.is_valid != UCODE_VALID_OK) {
+		/* We had an error bringing up the hardware, so take it
+		 * all the way back down so we can try again */
+		IWL_DEBUG_INFO("Initialize Alive failed.\n");
+		goto restart;
+	}
+
+	/* Bootstrap uCode has loaded initialize uCode ... verify inst image.
+	 * This is a paranoid check, because we would not have gotten the
+	 * "initialize" alive if code weren't properly loaded.  */
+	if (iwl_verify_ucode(priv)) {
+		/* Runtime instruction load was bad;
+		 * take it all the way back down so we can try again */
+		IWL_DEBUG_INFO("Bad \"initialize\" uCode load.\n");
+		goto restart;
+	}
+
+	/* Calculate temperature */
+	priv->temperature = iwl4965_get_temperature(priv);
+
+	/* Send pointers to protocol/runtime uCode image ... init code will
+	 * load and launch runtime uCode, which will send us another "Alive"
+	 * notification. */
+	IWL_DEBUG_INFO("Initialization Alive received.\n");
+	if (iwl_set_ucode_ptrs(priv)) {
+		/* Runtime instruction load won't happen;
+		 * take it all the way back down so we can try again */
+		IWL_DEBUG_INFO("Couldn't set up uCode pointers.\n");
+		goto restart;
+	}
+	return;
+
+ restart:
+	queue_work(priv->workqueue, &priv->restart);
+}
+
+
+/**
+ * iwl_alive_start - called after REPLY_ALIVE notification received
+ *                   from protocol/runtime uCode (initialization uCode's
+ *                   Alive gets handled by iwl_init_alive_start()).
+ */
+static void iwl_alive_start(struct iwl_priv *priv)
+{
+	int rc = 0;
+
+	IWL_DEBUG_INFO("Runtime Alive received.\n");
+
+	if (priv->card_alive.is_valid != UCODE_VALID_OK) {
+		/* We had an error bringing up the hardware, so take it
+		 * all the way back down so we can try again */
+		IWL_DEBUG_INFO("Alive failed.\n");
+		goto restart;
+	}
+
+	/* Initialize uCode has loaded Runtime uCode ... verify inst image.
+	 * This is a paranoid check, because we would not have gotten the
+	 * "runtime" alive if code weren't properly loaded.  */
+	if (iwl_verify_ucode(priv)) {
+		/* Runtime instruction load was bad;
+		 * take it all the way back down so we can try again */
+		IWL_DEBUG_INFO("Bad runtime uCode load.\n");
+		goto restart;
+	}
+
+	iwl_clear_stations_table(priv);
+
+	rc = iwl4965_alive_notify(priv);
+	if (rc) {
+		IWL_WARNING("Could not complete ALIVE transition [ntf]: %d\n",
+			    rc);
+		goto restart;
+	}
+
+	/* After the ALIVE response, we can process host commands */
+	set_bit(STATUS_ALIVE, &priv->status);
+
+	/* Clear out the uCode error bit if it is set */
+	clear_bit(STATUS_FW_ERROR, &priv->status);
+
+	rc = iwl_init_channel_map(priv);
+	if (rc) {
+		IWL_ERROR("initializing regulatory failed: %d\n", rc);
+		return;
+	}
+
+	iwl_init_geos(priv);
+
+	if (iwl_is_rfkill(priv))
+		return;
+
+	if (!priv->mac80211_registered) {
+		/* Unlock so any user space entry points can call back into
+		 * the driver without a deadlock... */
+		mutex_unlock(&priv->mutex);
+		iwl_rate_control_register(priv->hw);
+		rc = ieee80211_register_hw(priv->hw);
+		priv->hw->conf.beacon_int = 100;
+		mutex_lock(&priv->mutex);
+
+		if (rc) {
+			IWL_ERROR("Failed to register network "
+				  "device (error %d)\n", rc);
+			return;
+		}
+
+		priv->mac80211_registered = 1;
+
+		iwl_reset_channel_flag(priv);
+	} else
+		ieee80211_start_queues(priv->hw);
+
+	priv->active_rate = priv->rates_mask;
+	priv->active_rate_basic = priv->rates_mask & IWL_BASIC_RATES_MASK;
+
+	iwl_send_power_mode(priv, IWL_POWER_LEVEL(priv->power_mode));
+
+	if (iwl_is_associated(priv)) {
+		struct iwl_rxon_cmd *active_rxon =
+				(struct iwl_rxon_cmd *)(&priv->active_rxon);
+
+		memcpy(&priv->staging_rxon, &priv->active_rxon,
+		       sizeof(priv->staging_rxon));
+		active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	} else {
+		/* Initialize our rx_config data */
+		iwl_connection_init_rx_config(priv);
+		memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
+	}
+
+	/* Configure BT coexistence */
+	iwl_send_bt_config(priv);
+
+	/* Configure the adapter for unassociated operation */
+	iwl_commit_rxon(priv);
+
+	/* At this point, the NIC is initialized and operational */
+	priv->notif_missed_beacons = 0;
+	set_bit(STATUS_READY, &priv->status);
+
+	iwl4965_rf_kill_ct_config(priv);
+	IWL_DEBUG_INFO("ALIVE processing complete.\n");
+
+	if (priv->error_recovering)
+		iwl_error_recovery(priv);
+
+	return;
+
+ restart:
+	queue_work(priv->workqueue, &priv->restart);
+}
+
+static void iwl_cancel_deferred_work(struct iwl_priv *priv);
+
+static void __iwl_down(struct iwl_priv *priv)
+{
+	unsigned long flags;
+	int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
+	struct ieee80211_conf *conf = NULL;
+
+	IWL_DEBUG_INFO(DRV_NAME " is going down\n");
+
+	conf = ieee80211_get_hw_conf(priv->hw);
+
+	if (!exit_pending)
+		set_bit(STATUS_EXIT_PENDING, &priv->status);
+
+	iwl_clear_stations_table(priv);
+
+	/* Unblock any waiting calls */
+	wake_up_interruptible_all(&priv->wait_command_queue);
+
+	iwl_cancel_deferred_work(priv);
+
+	/* Wipe out the EXIT_PENDING status bit if we are not actually
+	 * exiting the module */
+	if (!exit_pending)
+		clear_bit(STATUS_EXIT_PENDING, &priv->status);
+
+	/* stop and reset the on-board processor */
+	iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+
+	/* tell the device to stop sending interrupts */
+	iwl_disable_interrupts(priv);
+
+	if (priv->mac80211_registered)
+		ieee80211_stop_queues(priv->hw);
+
+	/* If we have not previously called iwl_init() then
+	 * clear all bits but the RF Kill and SUSPEND bits and return */
+	if (!iwl_is_init(priv)) {
+		priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+					STATUS_RF_KILL_HW |
+			       test_bit(STATUS_RF_KILL_SW, &priv->status) <<
+					STATUS_RF_KILL_SW |
+			       test_bit(STATUS_IN_SUSPEND, &priv->status) <<
+					STATUS_IN_SUSPEND;
+		goto exit;
+	}
+
+	/* ...otherwise clear out all the status bits but the RF Kill and
+	 * SUSPEND bits and continue taking the NIC down. */
+	priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
+				STATUS_RF_KILL_HW |
+			test_bit(STATUS_RF_KILL_SW, &priv->status) <<
+				STATUS_RF_KILL_SW |
+			test_bit(STATUS_IN_SUSPEND, &priv->status) <<
+				STATUS_IN_SUSPEND |
+			test_bit(STATUS_FW_ERROR, &priv->status) <<
+				STATUS_FW_ERROR;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	iwl_hw_txq_ctx_stop(priv);
+	iwl_hw_rxq_stop(priv);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (!iwl_grab_restricted_access(priv)) {
+		iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG,
+					 APMG_CLK_VAL_DMA_CLK_RQT);
+		iwl_release_restricted_access(priv);
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	udelay(5);
+
+	iwl_hw_nic_stop_master(priv);
+	iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+	iwl_hw_nic_reset(priv);
+
+ exit:
+	memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
+
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+	priv->ibss_beacon = NULL;
+
+	/* clear out any free frames */
+	iwl_clear_free_frames(priv);
+}
+
+static void iwl_down(struct iwl_priv *priv)
+{
+	mutex_lock(&priv->mutex);
+	__iwl_down(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+#define MAX_HW_RESTARTS 5
+
+static int __iwl_up(struct iwl_priv *priv)
+{
+	DECLARE_MAC_BUF(mac);
+	int rc, i;
+	u32 hw_rf_kill = 0;
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+		IWL_WARNING("Exit pending; will not bring the NIC up\n");
+		return -EIO;
+	}
+
+	if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
+		IWL_WARNING("Radio disabled by SW RF kill (module "
+			    "parameter)\n");
+		return 0;
+	}
+
+	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+	rc = iwl_hw_nic_init(priv);
+	if (rc) {
+		IWL_ERROR("Unable to int nic\n");
+		return rc;
+	}
+
+	/* make sure rfkill handshake bits are cleared */
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+	/* clear (again), then enable host interrupts */
+	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+	iwl_enable_interrupts(priv);
+
+	/* really make sure rfkill handshake bits are cleared */
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+	/* Copy original ucode data image from disk into backup cache.
+	 * This will be used to initialize the on-board processor's
+	 * data SRAM for a clean start when the runtime program first loads. */
+	memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
+			priv->ucode_data.len);
+
+	/* If platform's RF_KILL switch is set to KILL,
+	 * wait for BIT_INT_RF_KILL interrupt before loading uCode
+	 * and getting things started */
+	if (!(iwl_read32(priv, CSR_GP_CNTRL) &
+				CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+		hw_rf_kill = 1;
+
+	if (test_bit(STATUS_RF_KILL_HW, &priv->status) || hw_rf_kill) {
+		IWL_WARNING("Radio disabled by HW RF Kill switch\n");
+		return 0;
+	}
+
+	for (i = 0; i < MAX_HW_RESTARTS; i++) {
+
+		iwl_clear_stations_table(priv);
+
+		/* load bootstrap state machine,
+		 * load bootstrap program into processor's memory,
+		 * prepare to load the "initialize" uCode */
+		rc = iwl_load_bsm(priv);
+
+		if (rc) {
+			IWL_ERROR("Unable to set up bootstrap uCode: %d\n", rc);
+			continue;
+		}
+
+		/* start card; "initialize" will load runtime ucode */
+		iwl_nic_start(priv);
+
+		/* MAC Address location in EEPROM same for 3945/4965 */
+		get_eeprom_mac(priv, priv->mac_addr);
+		IWL_DEBUG_INFO("MAC address: %s\n",
+			       print_mac(mac, priv->mac_addr));
+
+		SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+
+		IWL_DEBUG_INFO(DRV_NAME " is coming up\n");
+
+		return 0;
+	}
+
+	set_bit(STATUS_EXIT_PENDING, &priv->status);
+	__iwl_down(priv);
+
+	/* tried to restart and config the device for as long as our
+	 * patience could withstand */
+	IWL_ERROR("Unable to initialize device after %d attempts.\n", i);
+	return -EIO;
+}
+
+
+/*****************************************************************************
+ *
+ * Workqueue callbacks
+ *
+ *****************************************************************************/
+
+static void iwl_bg_init_alive_start(struct work_struct *data)
+{
+	struct iwl_priv *priv =
+	    container_of(data, struct iwl_priv, init_alive_start.work);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	iwl_init_alive_start(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_alive_start(struct work_struct *data)
+{
+	struct iwl_priv *priv =
+	    container_of(data, struct iwl_priv, alive_start.work);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	iwl_alive_start(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_rf_kill(struct work_struct *work)
+{
+	struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill);
+
+	wake_up_interruptible(&priv->wait_command_queue);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+
+	if (!iwl_is_rfkill(priv)) {
+		IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL,
+			  "HW and/or SW RF Kill no longer active, restarting "
+			  "device\n");
+		if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+			queue_work(priv->workqueue, &priv->restart);
+	} else {
+
+		if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
+			IWL_DEBUG_RF_KILL("Can not turn radio back on - "
+					  "disabled by SW switch\n");
+		else
+			IWL_WARNING("Radio Frequency Kill Switch is On:\n"
+				    "Kill switch must be turned off for "
+				    "wireless networking to work.\n");
+	}
+	mutex_unlock(&priv->mutex);
+}
+
+#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
+
+static void iwl_bg_scan_check(struct work_struct *data)
+{
+	struct iwl_priv *priv =
+	    container_of(data, struct iwl_priv, scan_check.work);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	if (test_bit(STATUS_SCANNING, &priv->status) ||
+	    test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN,
+			  "Scan completion watchdog resetting adapter (%dms)\n",
+			  jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
+		if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
+			queue_work(priv->workqueue, &priv->restart);
+	}
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_request_scan(struct work_struct *data)
+{
+	struct iwl_priv *priv =
+	    container_of(data, struct iwl_priv, request_scan);
+	struct iwl_host_cmd cmd = {
+		.id = REPLY_SCAN_CMD,
+		.len = sizeof(struct iwl_scan_cmd),
+		.meta.flags = CMD_SIZE_HUGE,
+	};
+	int rc = 0;
+	struct iwl_scan_cmd *scan;
+	struct ieee80211_conf *conf = NULL;
+	u8 direct_mask;
+	int phymode;
+
+	conf = ieee80211_get_hw_conf(priv->hw);
+
+	mutex_lock(&priv->mutex);
+
+	if (!iwl_is_ready(priv)) {
+		IWL_WARNING("request scan called when driver not ready.\n");
+		goto done;
+	}
+
+	/* Make sure the scan wasn't cancelled before this queued work
+	 * was given the chance to run... */
+	if (!test_bit(STATUS_SCANNING, &priv->status))
+		goto done;
+
+	/* This should never be called or scheduled if there is currently
+	 * a scan active in the hardware. */
+	if (test_bit(STATUS_SCAN_HW, &priv->status)) {
+		IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. "
+			       "Ignoring second request.\n");
+		rc = -EIO;
+		goto done;
+	}
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+		IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n");
+		goto done;
+	}
+
+	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
+		IWL_DEBUG_HC("Scan request while abort pending.  Queuing.\n");
+		goto done;
+	}
+
+	if (iwl_is_rfkill(priv)) {
+		IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n");
+		goto done;
+	}
+
+	if (!test_bit(STATUS_READY, &priv->status)) {
+		IWL_DEBUG_HC("Scan request while uninitialized.  Queuing.\n");
+		goto done;
+	}
+
+	if (!priv->scan_bands) {
+		IWL_DEBUG_HC("Aborting scan due to no requested bands\n");
+		goto done;
+	}
+
+	if (!priv->scan) {
+		priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) +
+				     IWL_MAX_SCAN_SIZE, GFP_KERNEL);
+		if (!priv->scan) {
+			rc = -ENOMEM;
+			goto done;
+		}
+	}
+	scan = priv->scan;
+	memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
+
+	scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
+	scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
+
+	if (iwl_is_associated(priv)) {
+		u16 interval = 0;
+		u32 extra;
+		u32 suspend_time = 100;
+		u32 scan_suspend_time = 100;
+		unsigned long flags;
+
+		IWL_DEBUG_INFO("Scanning while associated...\n");
+
+		spin_lock_irqsave(&priv->lock, flags);
+		interval = priv->beacon_int;
+		spin_unlock_irqrestore(&priv->lock, flags);
+
+		scan->suspend_time = 0;
+		scan->max_out_time = cpu_to_le32(600 * 1024);
+		if (!interval)
+			interval = suspend_time;
+
+		extra = (suspend_time / interval) << 22;
+		scan_suspend_time = (extra |
+		    ((suspend_time % interval) * 1024));
+		scan->suspend_time = cpu_to_le32(scan_suspend_time);
+		IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n",
+			       scan_suspend_time, interval);
+	}
+
+	/* We should add the ability for user to lock to PASSIVE ONLY */
+	if (priv->one_direct_scan) {
+		IWL_DEBUG_SCAN
+		    ("Kicking off one direct scan for '%s'\n",
+		     iwl_escape_essid(priv->direct_ssid,
+				      priv->direct_ssid_len));
+		scan->direct_scan[0].id = WLAN_EID_SSID;
+		scan->direct_scan[0].len = priv->direct_ssid_len;
+		memcpy(scan->direct_scan[0].ssid,
+		       priv->direct_ssid, priv->direct_ssid_len);
+		direct_mask = 1;
+	} else if (!iwl_is_associated(priv)) {
+		scan->direct_scan[0].id = WLAN_EID_SSID;
+		scan->direct_scan[0].len = priv->essid_len;
+		memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
+		direct_mask = 1;
+	} else
+		direct_mask = 0;
+
+	/* We don't build a direct scan probe request; the uCode will do
+	 * that based on the direct_mask added to each channel entry */
+	scan->tx_cmd.len = cpu_to_le16(
+		iwl_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data,
+			IWL_MAX_SCAN_SIZE - sizeof(scan), 0));
+	scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
+	scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
+	scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+	/* flags + rate selection */
+
+	scan->tx_cmd.tx_flags |= cpu_to_le32(0x200);
+
+	switch (priv->scan_bands) {
+	case 2:
+		scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
+		scan->tx_cmd.rate_n_flags =
+				iwl_hw_set_rate_n_flags(IWL_RATE_1M_PLCP,
+				RATE_MCS_ANT_B_MSK|RATE_MCS_CCK_MSK);
+
+		scan->good_CRC_th = 0;
+		phymode = MODE_IEEE80211G;
+		break;
+
+	case 1:
+		scan->tx_cmd.rate_n_flags =
+				iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP,
+				RATE_MCS_ANT_B_MSK);
+		scan->good_CRC_th = IWL_GOOD_CRC_TH;
+		phymode = MODE_IEEE80211A;
+		break;
+
+	default:
+		IWL_WARNING("Invalid scan band count\n");
+		goto done;
+	}
+
+	/* select Rx chains */
+
+	/* Force use of chains B and C (0x6) for scan Rx.
+	 * Avoid A (0x1) because of its off-channel reception on A-band.
+	 * MIMO is not used here, but value is required to make uCode happy. */
+	scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK |
+			cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) |
+			(0x6 << RXON_RX_CHAIN_FORCE_SEL_POS) |
+			(0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS));
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR)
+		scan->filter_flags = RXON_FILTER_PROMISC_MSK;
+
+	if (direct_mask)
+		IWL_DEBUG_SCAN
+		    ("Initiating direct scan for %s.\n",
+		     iwl_escape_essid(priv->essid, priv->essid_len));
+	else
+		IWL_DEBUG_SCAN("Initiating indirect scan.\n");
+
+	scan->channel_count =
+		iwl_get_channels_for_scan(
+			priv, phymode, 1, /* active */
+			direct_mask,
+			(void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
+
+	cmd.len += le16_to_cpu(scan->tx_cmd.len) +
+	    scan->channel_count * sizeof(struct iwl_scan_channel);
+	cmd.data = scan;
+	scan->len = cpu_to_le16(cmd.len);
+
+	set_bit(STATUS_SCAN_HW, &priv->status);
+	rc = iwl_send_cmd_sync(priv, &cmd);
+	if (rc)
+		goto done;
+
+	queue_delayed_work(priv->workqueue, &priv->scan_check,
+			   IWL_SCAN_CHECK_WATCHDOG);
+
+	mutex_unlock(&priv->mutex);
+	return;
+
+ done:
+	/* inform mac80211 sacn aborted */
+	queue_work(priv->workqueue, &priv->scan_completed);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_up(struct work_struct *data)
+{
+	struct iwl_priv *priv = container_of(data, struct iwl_priv, up);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	__iwl_up(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_restart(struct work_struct *data)
+{
+	struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	iwl_down(priv);
+	queue_work(priv->workqueue, &priv->up);
+}
+
+static void iwl_bg_rx_replenish(struct work_struct *data)
+{
+	struct iwl_priv *priv =
+	    container_of(data, struct iwl_priv, rx_replenish);
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+	iwl_rx_replenish(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_post_associate(struct work_struct *data)
+{
+	struct iwl_priv *priv = container_of(data, struct iwl_priv,
+					     post_associate.work);
+
+	int rc = 0;
+	struct ieee80211_conf *conf = NULL;
+	DECLARE_MAC_BUF(mac);
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		IWL_ERROR("%s Should not be called in AP mode\n", __FUNCTION__);
+		return;
+	}
+
+	IWL_DEBUG_ASSOC("Associated as %d to: %s\n",
+			priv->assoc_id,
+			print_mac(mac, priv->active_rxon.bssid_addr));
+
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	mutex_lock(&priv->mutex);
+
+	conf = ieee80211_get_hw_conf(priv->hw);
+
+	priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+	iwl_commit_rxon(priv);
+
+	memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
+	iwl_setup_rxon_timing(priv);
+	rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+			      sizeof(priv->rxon_timing), &priv->rxon_timing);
+	if (rc)
+		IWL_WARNING("REPLY_RXON_TIMING failed - "
+			    "Attempting to continue.\n");
+
+	priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+
+#ifdef CONFIG_IWLWIFI_HT
+	if (priv->is_ht_enabled && priv->current_assoc_ht.is_ht)
+		iwl4965_set_rxon_ht(priv, &priv->current_assoc_ht);
+	else {
+		priv->active_rate_ht[0] = 0;
+		priv->active_rate_ht[1] = 0;
+		priv->current_channel_width = IWL_CHANNEL_WIDTH_20MHZ;
+	}
+#endif /* CONFIG_IWLWIFI_HT*/
+	iwl4965_set_rxon_chain(priv);
+	priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+
+	IWL_DEBUG_ASSOC("assoc id %d beacon interval %d\n",
+			priv->assoc_id, priv->beacon_int);
+
+	if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+		priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
+	else
+		priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+	if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+			priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
+		else
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+		if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+			priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+
+	}
+
+	iwl_commit_rxon(priv);
+
+	switch (priv->iw_mode) {
+	case IEEE80211_IF_TYPE_STA:
+		iwl_rate_scale_init(priv->hw, IWL_AP_ID);
+		break;
+
+	case IEEE80211_IF_TYPE_IBSS:
+
+		/* clear out the station table */
+		iwl_clear_stations_table(priv);
+
+		iwl_rxon_add_station(priv, BROADCAST_ADDR, 0);
+		iwl_rxon_add_station(priv, priv->bssid, 0);
+		iwl_rate_scale_init(priv->hw, IWL_STA_ID);
+		iwl_send_beacon_cmd(priv);
+
+		break;
+
+	default:
+		IWL_ERROR("%s Should not be called in %d mode\n",
+				__FUNCTION__, priv->iw_mode);
+		break;
+	}
+
+	iwl_sequence_reset(priv);
+
+#ifdef CONFIG_IWLWIFI_SENSITIVITY
+	/* Enable Rx differential gain and sensitivity calibrations */
+	iwl4965_chain_noise_reset(priv);
+	priv->start_calib = 1;
+#endif /* CONFIG_IWLWIFI_SENSITIVITY */
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+		priv->assoc_station_added = 1;
+
+#ifdef CONFIG_IWLWIFI_QOS
+	iwl_activate_qos(priv, 0);
+#endif /* CONFIG_IWLWIFI_QOS */
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_abort_scan(struct work_struct *work)
+{
+	struct iwl_priv *priv = container_of(work, struct iwl_priv,
+					     abort_scan);
+
+	if (!iwl_is_ready(priv))
+		return;
+
+	mutex_lock(&priv->mutex);
+
+	set_bit(STATUS_SCAN_ABORTING, &priv->status);
+	iwl_send_scan_abort(priv);
+
+	mutex_unlock(&priv->mutex);
+}
+
+static void iwl_bg_scan_completed(struct work_struct *work)
+{
+	struct iwl_priv *priv =
+	    container_of(work, struct iwl_priv, scan_completed);
+
+	IWL_DEBUG(IWL_DL_INFO | IWL_DL_SCAN, "SCAN complete scan\n");
+
+	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+		return;
+
+	ieee80211_scan_completed(priv->hw);
+
+	/* Since setting the TXPOWER may have been deferred while
+	 * performing the scan, fire one off */
+	mutex_lock(&priv->mutex);
+	iwl_hw_reg_send_txpower(priv);
+	mutex_unlock(&priv->mutex);
+}
+
+/*****************************************************************************
+ *
+ * mac80211 entry point functions
+ *
+ *****************************************************************************/
+
+static int iwl_mac_start(struct ieee80211_hw *hw)
+{
+	struct iwl_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	/* we should be verifying the device is ready to be opened */
+	mutex_lock(&priv->mutex);
+
+	priv->is_open = 1;
+
+	if (!iwl_is_rfkill(priv))
+		ieee80211_start_queues(priv->hw);
+
+	mutex_unlock(&priv->mutex);
+	IWL_DEBUG_MAC80211("leave\n");
+	return 0;
+}
+
+static void iwl_mac_stop(struct ieee80211_hw *hw)
+{
+	struct iwl_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+	priv->is_open = 0;
+	/*netif_stop_queue(dev); */
+	flush_workqueue(priv->workqueue);
+	IWL_DEBUG_MAC80211("leave\n");
+}
+
+static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+		      struct ieee80211_tx_control *ctl)
+{
+	struct iwl_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+		IWL_DEBUG_MAC80211("leave - monitor\n");
+		return -1;
+	}
+
+	IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
+		     ctl->tx_rate);
+
+	if (iwl_tx_skb(priv, skb, ctl))
+		dev_kfree_skb_any(skb);
+
+	IWL_DEBUG_MAC80211("leave\n");
+	return 0;
+}
+
+static int iwl_mac_add_interface(struct ieee80211_hw *hw,
+				 struct ieee80211_if_init_conf *conf)
+{
+	struct iwl_priv *priv = hw->priv;
+	unsigned long flags;
+	DECLARE_MAC_BUF(mac);
+
+	IWL_DEBUG_MAC80211("enter: id %d, type %d\n", conf->if_id, conf->type);
+	if (conf->mac_addr)
+		IWL_DEBUG_MAC80211("enter: MAC %s\n",
+				   print_mac(mac, conf->mac_addr));
+
+	if (priv->interface_id) {
+		IWL_DEBUG_MAC80211("leave - interface_id != 0\n");
+		return 0;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->interface_id = conf->if_id;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	mutex_lock(&priv->mutex);
+	iwl_set_mode(priv, conf->type);
+
+	IWL_DEBUG_MAC80211("leave\n");
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+/**
+ * iwl_mac_config - mac80211 config callback
+ *
+ * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to
+ * be set inappropriately and the driver currently sets the hardware up to
+ * use it whenever needed.
+ */
+static int iwl_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+{
+	struct iwl_priv *priv = hw->priv;
+	const struct iwl_channel_info *ch_info;
+	unsigned long flags;
+
+	mutex_lock(&priv->mutex);
+	IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel);
+
+	if (!iwl_is_ready(priv)) {
+		IWL_DEBUG_MAC80211("leave - not ready\n");
+		mutex_unlock(&priv->mutex);
+		return -EIO;
+	}
+
+	/* TODO: Figure out how to get ieee80211_local->sta_scanning w/ only
+	 * what is exposed through include/ declrations */
+	if (unlikely(!iwl_param_disable_hw_scan &&
+		     test_bit(STATUS_SCANNING, &priv->status))) {
+		IWL_DEBUG_MAC80211("leave - scanning\n");
+		mutex_unlock(&priv->mutex);
+		return 0;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	ch_info = iwl_get_channel_info(priv, conf->phymode, conf->channel);
+	if (!is_channel_valid(ch_info)) {
+		IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n",
+			       conf->channel, conf->phymode);
+		IWL_DEBUG_MAC80211("leave - invalid channel\n");
+		spin_unlock_irqrestore(&priv->lock, flags);
+		mutex_unlock(&priv->mutex);
+		return -EINVAL;
+	}
+
+#ifdef CONFIG_IWLWIFI_HT
+	/* if we are switching fron ht to 2.4 clear flags
+	 * from any ht related info since 2.4 does not
+	 * support ht */
+	if ((le16_to_cpu(priv->staging_rxon.channel) != conf->channel)
+#ifdef IEEE80211_CONF_CHANNEL_SWITCH
+	    && !(conf->flags & IEEE80211_CONF_CHANNEL_SWITCH)
+#endif
+	)
+		priv->staging_rxon.flags = 0;
+#endif /* CONFIG_IWLWIFI_HT */
+
+	iwl_set_rxon_channel(priv, conf->phymode, conf->channel);
+
+	iwl_set_flags_for_phymode(priv, conf->phymode);
+
+	/* The list of supported rates and rate mask can be different
+	 * for each phymode; since the phymode may have changed, reset
+	 * the rate mask to what mac80211 lists */
+	iwl_set_rate(priv);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+#ifdef IEEE80211_CONF_CHANNEL_SWITCH
+	if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) {
+		iwl_hw_channel_switch(priv, conf->channel);
+		mutex_unlock(&priv->mutex);
+		return 0;
+	}
+#endif
+
+	iwl_radio_kill_sw(priv, !conf->radio_enabled);
+
+	if (!conf->radio_enabled) {
+		IWL_DEBUG_MAC80211("leave - radio disabled\n");
+		mutex_unlock(&priv->mutex);
+		return 0;
+	}
+
+	if (iwl_is_rfkill(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF kill\n");
+		mutex_unlock(&priv->mutex);
+		return -EIO;
+	}
+
+	iwl_set_rate(priv);
+
+	if (memcmp(&priv->active_rxon,
+		   &priv->staging_rxon, sizeof(priv->staging_rxon)))
+		iwl_commit_rxon(priv);
+	else
+		IWL_DEBUG_INFO("No re-sending same RXON configuration.\n");
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+static void iwl_config_ap(struct iwl_priv *priv)
+{
+	int rc = 0;
+
+	if (priv->status & STATUS_EXIT_PENDING)
+		return;
+
+	/* The following should be done only at AP bring up */
+	if ((priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) == 0) {
+
+		/* RXON - unassoc (to set timing command) */
+		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+		iwl_commit_rxon(priv);
+
+		/* RXON Timing */
+		memset(&priv->rxon_timing, 0, sizeof(struct iwl_rxon_time_cmd));
+		iwl_setup_rxon_timing(priv);
+		rc = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING,
+				sizeof(priv->rxon_timing), &priv->rxon_timing);
+		if (rc)
+			IWL_WARNING("REPLY_RXON_TIMING failed - "
+					"Attempting to continue.\n");
+
+		iwl4965_set_rxon_chain(priv);
+
+		/* FIXME: what should be the assoc_id for AP? */
+		priv->staging_rxon.assoc_id = cpu_to_le16(priv->assoc_id);
+		if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+			priv->staging_rxon.flags |=
+				RXON_FLG_SHORT_PREAMBLE_MSK;
+		else
+			priv->staging_rxon.flags &=
+				~RXON_FLG_SHORT_PREAMBLE_MSK;
+
+		if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
+			if (priv->assoc_capability &
+				WLAN_CAPABILITY_SHORT_SLOT_TIME)
+				priv->staging_rxon.flags |=
+					RXON_FLG_SHORT_SLOT_MSK;
+			else
+				priv->staging_rxon.flags &=
+					~RXON_FLG_SHORT_SLOT_MSK;
+
+			if (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)
+				priv->staging_rxon.flags &=
+					~RXON_FLG_SHORT_SLOT_MSK;
+		}
+		/* restore RXON assoc */
+		priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
+		iwl_commit_rxon(priv);
+#ifdef CONFIG_IWLWIFI_QOS
+		iwl_activate_qos(priv, 1);
+#endif
+		iwl_rxon_add_station(priv, BROADCAST_ADDR, 0);
+	}
+	iwl_send_beacon_cmd(priv);
+
+	/* FIXME - we need to add code here to detect a totally new
+	 * configuration, reset the AP, unassoc, rxon timing, assoc,
+	 * clear sta table, add BCAST sta... */
+}
+
+static int iwl_mac_config_interface(struct ieee80211_hw *hw, int if_id,
+				    struct ieee80211_if_conf *conf)
+{
+	struct iwl_priv *priv = hw->priv;
+	DECLARE_MAC_BUF(mac);
+	unsigned long flags;
+	int rc;
+
+	if (conf == NULL)
+		return -EIO;
+
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_AP) &&
+	    (!conf->beacon || !conf->ssid_len)) {
+		IWL_DEBUG_MAC80211
+		    ("Leaving in AP mode because HostAPD is not ready.\n");
+		return 0;
+	}
+
+	mutex_lock(&priv->mutex);
+
+	IWL_DEBUG_MAC80211("enter: interface id %d\n", if_id);
+	if (conf->bssid)
+		IWL_DEBUG_MAC80211("bssid: %s\n",
+				   print_mac(mac, conf->bssid));
+
+/*
+ * very dubious code was here; the probe filtering flag is never set:
+ *
+	if (unlikely(test_bit(STATUS_SCANNING, &priv->status)) &&
+	    !(priv->hw->flags & IEEE80211_HW_NO_PROBE_FILTERING)) {
+ */
+	if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
+		IWL_DEBUG_MAC80211("leave - scanning\n");
+		mutex_unlock(&priv->mutex);
+		return 0;
+	}
+
+	if (priv->interface_id != if_id) {
+		IWL_DEBUG_MAC80211("leave - interface_id != if_id\n");
+		mutex_unlock(&priv->mutex);
+		return 0;
+	}
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {
+		if (!conf->bssid) {
+			conf->bssid = priv->mac_addr;
+			memcpy(priv->bssid, priv->mac_addr, ETH_ALEN);
+			IWL_DEBUG_MAC80211("bssid was set to: %s\n",
+					   print_mac(mac, conf->bssid));
+		}
+		if (priv->ibss_beacon)
+			dev_kfree_skb(priv->ibss_beacon);
+
+		priv->ibss_beacon = conf->beacon;
+	}
+
+	if (conf->bssid && !is_zero_ether_addr(conf->bssid) &&
+	    !is_multicast_ether_addr(conf->bssid)) {
+		/* If there is currently a HW scan going on in the background
+		 * then we need to cancel it else the RXON below will fail. */
+		if (iwl_scan_cancel_timeout(priv, 100)) {
+			IWL_WARNING("Aborted scan still in progress "
+				    "after 100ms\n");
+			IWL_DEBUG_MAC80211("leaving - scan abort failed.\n");
+			mutex_unlock(&priv->mutex);
+			return -EAGAIN;
+		}
+		memcpy(priv->staging_rxon.bssid_addr, conf->bssid, ETH_ALEN);
+
+		/* TODO: Audit driver for usage of these members and see
+		 * if mac80211 deprecates them (priv->bssid looks like it
+		 * shouldn't be there, but I haven't scanned the IBSS code
+		 * to verify) - jpk */
+		memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+
+		if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+			iwl_config_ap(priv);
+		else {
+			priv->staging_rxon.filter_flags |=
+						RXON_FILTER_ASSOC_MSK;
+			rc = iwl_commit_rxon(priv);
+			if ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && rc)
+				iwl_rxon_add_station(
+					priv, priv->active_rxon.bssid_addr, 1);
+		}
+
+	} else {
+		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+		iwl_commit_rxon(priv);
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (!conf->ssid_len)
+		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
+	else
+		memcpy(priv->essid, conf->ssid, conf->ssid_len);
+
+	priv->essid_len = conf->ssid_len;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	IWL_DEBUG_MAC80211("leave\n");
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+static void iwl_configure_filter(struct ieee80211_hw *hw,
+				 unsigned int changed_flags,
+				 unsigned int *total_flags,
+				 int mc_count, struct dev_addr_list *mc_list)
+{
+	/*
+	 * XXX: dummy
+	 * see also iwl_connection_init_rx_config
+	 */
+	*total_flags = 0;
+}
+
+static void iwl_mac_remove_interface(struct ieee80211_hw *hw,
+				     struct ieee80211_if_init_conf *conf)
+{
+	struct iwl_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	mutex_lock(&priv->mutex);
+	if (priv->interface_id == conf->if_id) {
+		priv->interface_id = 0;
+		memset(priv->bssid, 0, ETH_ALEN);
+		memset(priv->essid, 0, IW_ESSID_MAX_SIZE);
+		priv->essid_len = 0;
+	}
+	mutex_unlock(&priv->mutex);
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+}
+
+#define IWL_DELAY_NEXT_SCAN (HZ*2)
+static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len)
+{
+	int rc = 0;
+	unsigned long flags;
+	struct iwl_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (!iwl_is_ready_rf(priv)) {
+		rc = -EIO;
+		IWL_DEBUG_MAC80211("leave - not ready or exit pending\n");
+		goto out_unlock;
+	}
+
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP) {	/* APs don't scan */
+		rc = -EIO;
+		IWL_ERROR("ERROR: APs don't scan\n");
+		goto out_unlock;
+	}
+
+	/* if we just finished scan ask for delay */
+	if (priv->last_scan_jiffies &&
+	    time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN,
+		       jiffies)) {
+		rc = -EAGAIN;
+		goto out_unlock;
+	}
+	if (len) {
+		IWL_DEBUG_SCAN("direct scan for  "
+			       "%s [%d]\n ",
+			       iwl_escape_essid(ssid, len), (int)len);
+
+		priv->one_direct_scan = 1;
+		priv->direct_ssid_len = (u8)
+		    min((u8) len, (u8) IW_ESSID_MAX_SIZE);
+		memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
+	}
+
+	rc = iwl_scan_initiate(priv);
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+out_unlock:
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return rc;
+}
+
+static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+			   const u8 *local_addr, const u8 *addr,
+			   struct ieee80211_key_conf *key)
+{
+	struct iwl_priv *priv = hw->priv;
+	DECLARE_MAC_BUF(mac);
+	int rc = 0;
+	u8 sta_id;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (!iwl_param_hwcrypto) {
+		IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
+		return -EOPNOTSUPP;
+	}
+
+	if (is_zero_ether_addr(addr))
+		/* only support pairwise keys */
+		return -EOPNOTSUPP;
+
+	sta_id = iwl_hw_find_station(priv, addr);
+	if (sta_id == IWL_INVALID_STATION) {
+		IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
+				   print_mac(mac, addr));
+		return -EINVAL;
+	}
+
+	mutex_lock(&priv->mutex);
+
+	switch (cmd) {
+	case  SET_KEY:
+		rc = iwl_update_sta_key_info(priv, key, sta_id);
+		if (!rc) {
+			iwl_set_rxon_hwcrypto(priv, 1);
+			iwl_commit_rxon(priv);
+			key->hw_key_idx = sta_id;
+			IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n");
+			key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+		}
+		break;
+	case DISABLE_KEY:
+		rc = iwl_clear_sta_key_info(priv, sta_id);
+		if (!rc) {
+			iwl_set_rxon_hwcrypto(priv, 0);
+			iwl_commit_rxon(priv);
+			IWL_DEBUG_MAC80211("disable hwcrypto key\n");
+		}
+		break;
+	default:
+		rc = -EINVAL;
+	}
+
+	IWL_DEBUG_MAC80211("leave\n");
+	mutex_unlock(&priv->mutex);
+
+	return rc;
+}
+
+static int iwl_mac_conf_tx(struct ieee80211_hw *hw, int queue,
+			   const struct ieee80211_tx_queue_params *params)
+{
+	struct iwl_priv *priv = hw->priv;
+#ifdef CONFIG_IWLWIFI_QOS
+	unsigned long flags;
+	int q;
+#endif /* CONFIG_IWL_QOS */
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (!iwl_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF not ready\n");
+		return -EIO;
+	}
+
+	if (queue >= AC_NUM) {
+		IWL_DEBUG_MAC80211("leave - queue >= AC_NUM %d\n", queue);
+		return 0;
+	}
+
+#ifdef CONFIG_IWLWIFI_QOS
+	if (!priv->qos_data.qos_enable) {
+		priv->qos_data.qos_active = 0;
+		IWL_DEBUG_MAC80211("leave - qos not enabled\n");
+		return 0;
+	}
+	q = AC_NUM - 1 - queue;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	priv->qos_data.def_qos_parm.ac[q].cw_min = cpu_to_le16(params->cw_min);
+	priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max);
+	priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+	priv->qos_data.def_qos_parm.ac[q].edca_txop =
+			cpu_to_le16((params->burst_time * 100));
+
+	priv->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+	priv->qos_data.qos_active = 1;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	mutex_lock(&priv->mutex);
+	if (priv->iw_mode == IEEE80211_IF_TYPE_AP)
+		iwl_activate_qos(priv, 1);
+	else if (priv->assoc_id && iwl_is_associated(priv))
+		iwl_activate_qos(priv, 0);
+
+	mutex_unlock(&priv->mutex);
+
+#endif /*CONFIG_IWLWIFI_QOS */
+
+	IWL_DEBUG_MAC80211("leave\n");
+	return 0;
+}
+
+static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw,
+				struct ieee80211_tx_queue_stats *stats)
+{
+	struct iwl_priv *priv = hw->priv;
+	int i, avail;
+	struct iwl_tx_queue *txq;
+	struct iwl_queue *q;
+	unsigned long flags;
+
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (!iwl_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF not ready\n");
+		return -EIO;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	for (i = 0; i < AC_NUM; i++) {
+		txq = &priv->txq[i];
+		q = &txq->q;
+		avail = iwl_queue_space(q);
+
+		stats->data[i].len = q->n_window - avail;
+		stats->data[i].limit = q->n_window - q->high_mark;
+		stats->data[i].count = q->n_window;
+
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+	return 0;
+}
+
+static int iwl_mac_get_stats(struct ieee80211_hw *hw,
+			     struct ieee80211_low_level_stats *stats)
+{
+	IWL_DEBUG_MAC80211("enter\n");
+	IWL_DEBUG_MAC80211("leave\n");
+
+	return 0;
+}
+
+static u64 iwl_mac_get_tsf(struct ieee80211_hw *hw)
+{
+	IWL_DEBUG_MAC80211("enter\n");
+	IWL_DEBUG_MAC80211("leave\n");
+
+	return 0;
+}
+
+static void iwl_mac_reset_tsf(struct ieee80211_hw *hw)
+{
+	struct iwl_priv *priv = hw->priv;
+	unsigned long flags;
+
+	mutex_lock(&priv->mutex);
+	IWL_DEBUG_MAC80211("enter\n");
+
+	priv->lq_mngr.lq_ready = 0;
+#ifdef CONFIG_IWLWIFI_HT
+	spin_lock_irqsave(&priv->lock, flags);
+	memset(&priv->current_assoc_ht, 0, sizeof(struct sta_ht_info));
+	spin_unlock_irqrestore(&priv->lock, flags);
+#ifdef CONFIG_IWLWIFI_HT_AGG
+/*	if (priv->lq_mngr.agg_ctrl.granted_ba)
+		iwl4965_turn_off_agg(priv, TID_ALL_SPECIFIED);*/
+
+	memset(&(priv->lq_mngr.agg_ctrl), 0, sizeof(struct iwl_agg_control));
+	priv->lq_mngr.agg_ctrl.tid_traffic_load_threshold = 10;
+	priv->lq_mngr.agg_ctrl.ba_timeout = 5000;
+	priv->lq_mngr.agg_ctrl.auto_agg = 1;
+
+	if (priv->lq_mngr.agg_ctrl.auto_agg)
+		priv->lq_mngr.agg_ctrl.requested_ba = TID_ALL_ENABLED;
+#endif /*CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+#ifdef CONFIG_IWLWIFI_QOS
+	iwl_reset_qos(priv);
+#endif
+
+	cancel_delayed_work(&priv->post_associate);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	priv->assoc_id = 0;
+	priv->assoc_capability = 0;
+	priv->call_post_assoc_from_beacon = 0;
+	priv->assoc_station_added = 0;
+
+	/* new association get rid of ibss beacon skb */
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+
+	priv->ibss_beacon = NULL;
+
+	priv->beacon_int = priv->hw->conf.beacon_int;
+	priv->timestamp1 = 0;
+	priv->timestamp0 = 0;
+	if ((priv->iw_mode == IEEE80211_IF_TYPE_STA))
+		priv->beacon_int = 0;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	/* Per mac80211.h: This is only used in IBSS mode... */
+	if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+		IWL_DEBUG_MAC80211("leave - not in IBSS\n");
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+
+	if (!iwl_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - not ready\n");
+		mutex_unlock(&priv->mutex);
+		return;
+	}
+
+	priv->only_active_channel = 0;
+
+	iwl_set_rate(priv);
+
+	mutex_unlock(&priv->mutex);
+
+	IWL_DEBUG_MAC80211("leave\n");
+
+}
+
+static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+				 struct ieee80211_tx_control *control)
+{
+	struct iwl_priv *priv = hw->priv;
+	unsigned long flags;
+
+	mutex_lock(&priv->mutex);
+	IWL_DEBUG_MAC80211("enter\n");
+
+	if (!iwl_is_ready_rf(priv)) {
+		IWL_DEBUG_MAC80211("leave - RF not ready\n");
+		mutex_unlock(&priv->mutex);
+		return -EIO;
+	}
+
+	if (priv->iw_mode != IEEE80211_IF_TYPE_IBSS) {
+		IWL_DEBUG_MAC80211("leave - not IBSS\n");
+		mutex_unlock(&priv->mutex);
+		return -EIO;
+	}
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+
+	priv->ibss_beacon = skb;
+
+	priv->assoc_id = 0;
+
+	IWL_DEBUG_MAC80211("leave\n");
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+#ifdef CONFIG_IWLWIFI_QOS
+	iwl_reset_qos(priv);
+#endif
+
+	queue_work(priv->workqueue, &priv->post_associate.work);
+
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+#ifdef CONFIG_IWLWIFI_HT
+union ht_cap_info {
+	struct {
+		u16 advanced_coding_cap		:1;
+		u16 supported_chan_width_set	:1;
+		u16 mimo_power_save_mode	:2;
+		u16 green_field			:1;
+		u16 short_GI20			:1;
+		u16 short_GI40			:1;
+		u16 tx_stbc			:1;
+		u16 rx_stbc			:1;
+		u16 beam_forming		:1;
+		u16 delayed_ba			:1;
+		u16 maximal_amsdu_size		:1;
+		u16 cck_mode_at_40MHz		:1;
+		u16 psmp_support		:1;
+		u16 stbc_ctrl_frame_support	:1;
+		u16 sig_txop_protection_support	:1;
+	};
+	u16 val;
+} __attribute__ ((packed));
+
+union ht_param_info{
+	struct {
+		u8 max_rx_ampdu_factor	:2;
+		u8 mpdu_density		:3;
+		u8 reserved		:3;
+	};
+	u8 val;
+} __attribute__ ((packed));
+
+union ht_exra_param_info {
+	struct {
+		u8 ext_chan_offset		:2;
+		u8 tx_chan_width		:1;
+		u8 rifs_mode			:1;
+		u8 controlled_access_only	:1;
+		u8 service_interval_granularity	:3;
+	};
+	u8 val;
+} __attribute__ ((packed));
+
+union ht_operation_mode{
+	struct {
+		u16 op_mode	:2;
+		u16 non_GF	:1;
+		u16 reserved	:13;
+	};
+	u16 val;
+} __attribute__ ((packed));
+
+
+static int sta_ht_info_init(struct ieee80211_ht_capability *ht_cap,
+			    struct ieee80211_ht_additional_info *ht_extra,
+			    struct sta_ht_info *ht_info_ap,
+			    struct sta_ht_info *ht_info)
+{
+	union ht_cap_info cap;
+	union ht_operation_mode op_mode;
+	union ht_param_info param_info;
+	union ht_exra_param_info extra_param_info;
+
+	IWL_DEBUG_MAC80211("enter: \n");
+
+	if (!ht_info) {
+		IWL_DEBUG_MAC80211("leave: ht_info is NULL\n");
+		return -1;
+	}
+
+	if (ht_cap) {
+		cap.val = (u16) le16_to_cpu(ht_cap->capabilities_info);
+		param_info.val = ht_cap->mac_ht_params_info;
+		ht_info->is_ht = 1;
+		if (cap.short_GI20)
+			ht_info->sgf |= 0x1;
+		if (cap.short_GI40)
+			ht_info->sgf |= 0x2;
+		ht_info->is_green_field = cap.green_field;
+		ht_info->max_amsdu_size = cap.maximal_amsdu_size;
+		ht_info->supported_chan_width = cap.supported_chan_width_set;
+		ht_info->tx_mimo_ps_mode = cap.mimo_power_save_mode;
+		memcpy(ht_info->supp_rates, ht_cap->supported_mcs_set, 16);
+
+		ht_info->ampdu_factor = param_info.max_rx_ampdu_factor;
+		ht_info->mpdu_density = param_info.mpdu_density;
+
+		IWL_DEBUG_MAC80211("SISO mask 0x%X MIMO mask 0x%X \n",
+				    ht_cap->supported_mcs_set[0],
+				    ht_cap->supported_mcs_set[1]);
+
+		if (ht_info_ap) {
+			ht_info->control_channel = ht_info_ap->control_channel;
+			ht_info->extension_chan_offset =
+				ht_info_ap->extension_chan_offset;
+			ht_info->tx_chan_width = ht_info_ap->tx_chan_width;
+			ht_info->operating_mode = ht_info_ap->operating_mode;
+		}
+
+		if (ht_extra) {
+			extra_param_info.val = ht_extra->ht_param;
+			ht_info->control_channel = ht_extra->control_chan;
+			ht_info->extension_chan_offset =
+			    extra_param_info.ext_chan_offset;
+			ht_info->tx_chan_width = extra_param_info.tx_chan_width;
+			op_mode.val = (u16)
+			    le16_to_cpu(ht_extra->operation_mode);
+			ht_info->operating_mode = op_mode.op_mode;
+			IWL_DEBUG_MAC80211("control channel %d\n",
+					    ht_extra->control_chan);
+		}
+	} else
+		ht_info->is_ht = 0;
+
+	IWL_DEBUG_MAC80211("leave\n");
+	return 0;
+}
+
+static int iwl_mac_conf_ht(struct ieee80211_hw *hw,
+			   struct ieee80211_ht_capability *ht_cap,
+			   struct ieee80211_ht_additional_info *ht_extra)
+{
+	struct iwl_priv *priv = hw->priv;
+	int rs;
+
+	IWL_DEBUG_MAC80211("enter: \n");
+
+	rs = sta_ht_info_init(ht_cap, ht_extra, NULL, &priv->current_assoc_ht);
+	iwl4965_set_rxon_chain(priv);
+
+	if (priv && priv->assoc_id &&
+	    (priv->iw_mode == IEEE80211_IF_TYPE_STA)) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&priv->lock, flags);
+		if (priv->beacon_int)
+			queue_work(priv->workqueue, &priv->post_associate.work);
+		else
+			priv->call_post_assoc_from_beacon = 1;
+		spin_unlock_irqrestore(&priv->lock, flags);
+	}
+
+	IWL_DEBUG_MAC80211("leave: control channel %d\n",
+			ht_extra->control_chan);
+	return rs;
+
+}
+
+static void iwl_set_ht_capab(struct ieee80211_hw *hw,
+			     struct ieee80211_ht_capability *ht_cap,
+			     u8 use_wide_chan)
+{
+	union ht_cap_info cap;
+	union ht_param_info param_info;
+
+	memset(&cap, 0, sizeof(union ht_cap_info));
+	memset(&param_info, 0, sizeof(union ht_param_info));
+
+	cap.maximal_amsdu_size = HT_IE_MAX_AMSDU_SIZE_4K;
+	cap.green_field = 1;
+	cap.short_GI20 = 1;
+	cap.short_GI40 = 1;
+	cap.supported_chan_width_set = use_wide_chan;
+	cap.mimo_power_save_mode = 0x3;
+
+	param_info.max_rx_ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
+	param_info.mpdu_density = CFG_HT_MPDU_DENSITY_DEF;
+	ht_cap->capabilities_info = (__le16) cpu_to_le16(cap.val);
+	ht_cap->mac_ht_params_info = (u8) param_info.val;
+
+	ht_cap->supported_mcs_set[0] = 0xff;
+	ht_cap->supported_mcs_set[1] = 0xff;
+	ht_cap->supported_mcs_set[4] =
+	    (cap.supported_chan_width_set) ? 0x1: 0x0;
+}
+
+static void iwl_mac_get_ht_capab(struct ieee80211_hw *hw,
+				 struct ieee80211_ht_capability *ht_cap)
+{
+	u8 use_wide_channel = 1;
+	struct iwl_priv *priv = hw->priv;
+
+	IWL_DEBUG_MAC80211("enter: \n");
+	if (priv->channel_width != IWL_CHANNEL_WIDTH_40MHZ)
+		use_wide_channel = 0;
+
+	/* no fat tx allowed on 2.4GHZ */
+	if (priv->phymode != MODE_IEEE80211A)
+		use_wide_channel = 0;
+
+	iwl_set_ht_capab(hw, ht_cap, use_wide_channel);
+	IWL_DEBUG_MAC80211("leave: \n");
+}
+#endif /*CONFIG_IWLWIFI_HT*/
+
+/*****************************************************************************
+ *
+ * sysfs attributes
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+
+/*
+ * The following adds a new attribute to the sysfs representation
+ * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/)
+ * used for controlling the debug level.
+ *
+ * See the level definitions in iwl for details.
+ */
+
+static ssize_t show_debug_level(struct device_driver *d, char *buf)
+{
+	return sprintf(buf, "0x%08X\n", iwl_debug_level);
+}
+static ssize_t store_debug_level(struct device_driver *d,
+				 const char *buf, size_t count)
+{
+	char *p = (char *)buf;
+	u32 val;
+
+	val = simple_strtoul(p, &p, 0);
+	if (p == buf)
+		printk(KERN_INFO DRV_NAME
+		       ": %s is not in hex or decimal form.\n", buf);
+	else
+		iwl_debug_level = val;
+
+	return strnlen(buf, count);
+}
+
+static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
+		   show_debug_level, store_debug_level);
+
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+static ssize_t show_rf_kill(struct device *d,
+			    struct device_attribute *attr, char *buf)
+{
+	/*
+	 * 0 - RF kill not enabled
+	 * 1 - SW based RF kill active (sysfs)
+	 * 2 - HW based RF kill active
+	 * 3 - Both HW and SW based RF kill active
+	 */
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) |
+		  (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0);
+
+	return sprintf(buf, "%i\n", val);
+}
+
+static ssize_t store_rf_kill(struct device *d,
+			     struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+	mutex_lock(&priv->mutex);
+	iwl_radio_kill_sw(priv, buf[0] == '1');
+	mutex_unlock(&priv->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
+
+static ssize_t show_temperature(struct device *d,
+				struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	return sprintf(buf, "%d\n", iwl_hw_get_temperature(priv));
+}
+
+static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
+
+static ssize_t show_rs_window(struct device *d,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	struct iwl_priv *priv = d->driver_data;
+	return iwl_fill_rs_info(priv->hw, buf, IWL_AP_ID);
+}
+static DEVICE_ATTR(rs_window, S_IRUGO, show_rs_window, NULL);
+
+static ssize_t show_tx_power(struct device *d,
+			     struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	return sprintf(buf, "%d\n", priv->user_txpower_limit);
+}
+
+static ssize_t store_tx_power(struct device *d,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	char *p = (char *)buf;
+	u32 val;
+
+	val = simple_strtoul(p, &p, 10);
+	if (p == buf)
+		printk(KERN_INFO DRV_NAME
+		       ": %s is not in decimal form.\n", buf);
+	else
+		iwl_hw_reg_set_txpower(priv, val);
+
+	return count;
+}
+
+static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
+
+static ssize_t show_flags(struct device *d,
+			  struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+	return sprintf(buf, "0x%04X\n", priv->active_rxon.flags);
+}
+
+static ssize_t store_flags(struct device *d,
+			   struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	u32 flags = simple_strtoul(buf, NULL, 0);
+
+	mutex_lock(&priv->mutex);
+	if (le32_to_cpu(priv->staging_rxon.flags) != flags) {
+		/* Cancel any currently running scans... */
+		if (iwl_scan_cancel_timeout(priv, 100))
+			IWL_WARNING("Could not cancel scan.\n");
+		else {
+			IWL_DEBUG_INFO("Committing rxon.flags = 0x%04X\n",
+				       flags);
+			priv->staging_rxon.flags = cpu_to_le32(flags);
+			iwl_commit_rxon(priv);
+		}
+	}
+	mutex_unlock(&priv->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, show_flags, store_flags);
+
+static ssize_t show_filter_flags(struct device *d,
+				 struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+	return sprintf(buf, "0x%04X\n",
+		le32_to_cpu(priv->active_rxon.filter_flags));
+}
+
+static ssize_t store_filter_flags(struct device *d,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	u32 filter_flags = simple_strtoul(buf, NULL, 0);
+
+	mutex_lock(&priv->mutex);
+	if (le32_to_cpu(priv->staging_rxon.filter_flags) != filter_flags) {
+		/* Cancel any currently running scans... */
+		if (iwl_scan_cancel_timeout(priv, 100))
+			IWL_WARNING("Could not cancel scan.\n");
+		else {
+			IWL_DEBUG_INFO("Committing rxon.filter_flags = "
+				       "0x%04X\n", filter_flags);
+			priv->staging_rxon.filter_flags =
+				cpu_to_le32(filter_flags);
+			iwl_commit_rxon(priv);
+		}
+	}
+	mutex_unlock(&priv->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags,
+		   store_filter_flags);
+
+static ssize_t show_tune(struct device *d,
+			 struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+
+	return sprintf(buf, "0x%04X\n",
+		       (priv->phymode << 8) |
+			le16_to_cpu(priv->active_rxon.channel));
+}
+
+static void iwl_set_flags_for_phymode(struct iwl_priv *priv, u8 phymode);
+
+static ssize_t store_tune(struct device *d,
+			  struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	char *p = (char *)buf;
+	u16 tune = simple_strtoul(p, &p, 0);
+	u8 phymode = (tune >> 8) & 0xff;
+	u16 channel = tune & 0xff;
+
+	IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel);
+
+	mutex_lock(&priv->mutex);
+	if ((le16_to_cpu(priv->staging_rxon.channel) != channel) ||
+	    (priv->phymode != phymode)) {
+		const struct iwl_channel_info *ch_info;
+
+		ch_info = iwl_get_channel_info(priv, phymode, channel);
+		if (!ch_info) {
+			IWL_WARNING("Requested invalid phymode/channel "
+				    "combination: %d %d\n", phymode, channel);
+			mutex_unlock(&priv->mutex);
+			return -EINVAL;
+		}
+
+		/* Cancel any currently running scans... */
+		if (iwl_scan_cancel_timeout(priv, 100))
+			IWL_WARNING("Could not cancel scan.\n");
+		else {
+			IWL_DEBUG_INFO("Committing phymode and "
+				       "rxon.channel = %d %d\n",
+				       phymode, channel);
+
+			iwl_set_rxon_channel(priv, phymode, channel);
+			iwl_set_flags_for_phymode(priv, phymode);
+
+			iwl_set_rate(priv);
+			iwl_commit_rxon(priv);
+		}
+	}
+	mutex_unlock(&priv->mutex);
+
+	return count;
+}
+
+static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune);
+
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+
+static ssize_t show_measurement(struct device *d,
+				struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct iwl_spectrum_notification measure_report;
+	u32 size = sizeof(measure_report), len = 0, ofs = 0;
+	u8 *data = (u8 *) & measure_report;
+	unsigned long flags;
+
+	spin_lock_irqsave(&priv->lock, flags);
+	if (!(priv->measurement_status & MEASUREMENT_READY)) {
+		spin_unlock_irqrestore(&priv->lock, flags);
+		return 0;
+	}
+	memcpy(&measure_report, &priv->measure_report, size);
+	priv->measurement_status = 0;
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	while (size && (PAGE_SIZE - len)) {
+		hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
+				   PAGE_SIZE - len, 1);
+		len = strlen(buf);
+		if (PAGE_SIZE - len)
+			buf[len++] = '\n';
+
+		ofs += 16;
+		size -= min(size, 16U);
+	}
+
+	return len;
+}
+
+static ssize_t store_measurement(struct device *d,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+	struct ieee80211_measurement_params params = {
+		.channel = le16_to_cpu(priv->active_rxon.channel),
+		.start_time = cpu_to_le64(priv->last_tsf),
+		.duration = cpu_to_le16(1),
+	};
+	u8 type = IWL_MEASURE_BASIC;
+	u8 buffer[32];
+	u8 channel;
+
+	if (count) {
+		char *p = buffer;
+		strncpy(buffer, buf, min(sizeof(buffer), count));
+		channel = simple_strtoul(p, NULL, 0);
+		if (channel)
+			params.channel = channel;
+
+		p = buffer;
+		while (*p && *p != ' ')
+			p++;
+		if (*p)
+			type = simple_strtoul(p + 1, NULL, 0);
+	}
+
+	IWL_DEBUG_INFO("Invoking measurement of type %d on "
+		       "channel %d (for '%s')\n", type, params.channel, buf);
+	iwl_get_measurement(priv, &params, type);
+
+	return count;
+}
+
+static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR,
+		   show_measurement, store_measurement);
+#endif /* CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT */
+
+static ssize_t store_retry_rate(struct device *d,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+
+	priv->retry_rate = simple_strtoul(buf, NULL, 0);
+	if (priv->retry_rate <= 0)
+		priv->retry_rate = 1;
+
+	return count;
+}
+
+static ssize_t show_retry_rate(struct device *d,
+			       struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+	return sprintf(buf, "%d", priv->retry_rate);
+}
+
+static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, show_retry_rate,
+		   store_retry_rate);
+
+static ssize_t store_power_level(struct device *d,
+				 struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+	int rc;
+	int mode;
+
+	mode = simple_strtoul(buf, NULL, 0);
+	mutex_lock(&priv->mutex);
+
+	if (!iwl_is_ready(priv)) {
+		rc = -EAGAIN;
+		goto out;
+	}
+
+	if ((mode < 1) || (mode > IWL_POWER_LIMIT) || (mode == IWL_POWER_AC))
+		mode = IWL_POWER_AC;
+	else
+		mode |= IWL_POWER_ENABLED;
+
+	if (mode != priv->power_mode) {
+		rc = iwl_send_power_mode(priv, IWL_POWER_LEVEL(mode));
+		if (rc) {
+			IWL_DEBUG_MAC80211("failed setting power mode.\n");
+			goto out;
+		}
+		priv->power_mode = mode;
+	}
+
+	rc = count;
+
+ out:
+	mutex_unlock(&priv->mutex);
+	return rc;
+}
+
+#define MAX_WX_STRING 80
+
+/* Values are in microsecond */
+static const s32 timeout_duration[] = {
+	350000,
+	250000,
+	75000,
+	37000,
+	25000,
+};
+static const s32 period_duration[] = {
+	400000,
+	700000,
+	1000000,
+	1000000,
+	1000000
+};
+
+static ssize_t show_power_level(struct device *d,
+				struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+	int level = IWL_POWER_LEVEL(priv->power_mode);
+	char *p = buf;
+
+	p += sprintf(p, "%d ", level);
+	switch (level) {
+	case IWL_POWER_MODE_CAM:
+	case IWL_POWER_AC:
+		p += sprintf(p, "(AC)");
+		break;
+	case IWL_POWER_BATTERY:
+		p += sprintf(p, "(BATTERY)");
+		break;
+	default:
+		p += sprintf(p,
+			     "(Timeout %dms, Period %dms)",
+			     timeout_duration[level - 1] / 1000,
+			     period_duration[level - 1] / 1000);
+	}
+
+	if (!(priv->power_mode & IWL_POWER_ENABLED))
+		p += sprintf(p, " OFF\n");
+	else
+		p += sprintf(p, " \n");
+
+	return (p - buf + 1);
+
+}
+
+static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level,
+		   store_power_level);
+
+static ssize_t show_channels(struct device *d,
+			     struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+	int len = 0, i;
+	struct ieee80211_channel *channels = NULL;
+	const struct ieee80211_hw_mode *hw_mode = NULL;
+	int count = 0;
+
+	if (!iwl_is_ready(priv))
+		return -EAGAIN;
+
+	hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211G);
+	if (!hw_mode)
+		hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211B);
+	if (hw_mode) {
+		channels = hw_mode->channels;
+		count = hw_mode->num_channels;
+	}
+
+	len +=
+	    sprintf(&buf[len],
+		    "Displaying %d channels in 2.4GHz band "
+		    "(802.11bg):\n", count);
+
+	for (i = 0; i < count; i++)
+		len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
+			       channels[i].chan,
+			       channels[i].power_level,
+			       channels[i].
+			       flag & IEEE80211_CHAN_W_RADAR_DETECT ?
+			       " (IEEE 802.11h required)" : "",
+			       (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
+				|| (channels[i].
+				    flag &
+				    IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
+			       ", IBSS",
+			       channels[i].
+			       flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
+			       "active/passive" : "passive only");
+
+	hw_mode = iwl_get_hw_mode(priv, MODE_IEEE80211A);
+	if (hw_mode) {
+		channels = hw_mode->channels;
+		count = hw_mode->num_channels;
+	} else {
+		channels = NULL;
+		count = 0;
+	}
+
+	len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band "
+		       "(802.11a):\n", count);
+
+	for (i = 0; i < count; i++)
+		len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n",
+			       channels[i].chan,
+			       channels[i].power_level,
+			       channels[i].
+			       flag & IEEE80211_CHAN_W_RADAR_DETECT ?
+			       " (IEEE 802.11h required)" : "",
+			       (!(channels[i].flag & IEEE80211_CHAN_W_IBSS)
+				|| (channels[i].
+				    flag &
+				    IEEE80211_CHAN_W_RADAR_DETECT)) ? "" :
+			       ", IBSS",
+			       channels[i].
+			       flag & IEEE80211_CHAN_W_ACTIVE_SCAN ?
+			       "active/passive" : "passive only");
+
+	return len;
+}
+
+static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL);
+
+static ssize_t show_statistics(struct device *d,
+			       struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+	u32 size = sizeof(struct iwl_notif_statistics);
+	u32 len = 0, ofs = 0;
+	u8 *data = (u8 *) & priv->statistics;
+	int rc = 0;
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	mutex_lock(&priv->mutex);
+	rc = iwl_send_statistics_request(priv);
+	mutex_unlock(&priv->mutex);
+
+	if (rc) {
+		len = sprintf(buf,
+			      "Error sending statistics request: 0x%08X\n", rc);
+		return len;
+	}
+
+	while (size && (PAGE_SIZE - len)) {
+		hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len,
+				   PAGE_SIZE - len, 1);
+		len = strlen(buf);
+		if (PAGE_SIZE - len)
+			buf[len++] = '\n';
+
+		ofs += 16;
+		size -= min(size, 16U);
+	}
+
+	return len;
+}
+
+static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
+
+static ssize_t show_antenna(struct device *d,
+			    struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = dev_get_drvdata(d);
+
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+
+	return sprintf(buf, "%d\n", priv->antenna);
+}
+
+static ssize_t store_antenna(struct device *d,
+			     struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	int ant;
+	struct iwl_priv *priv = dev_get_drvdata(d);
+
+	if (count == 0)
+		return 0;
+
+	if (sscanf(buf, "%1i", &ant) != 1) {
+		IWL_DEBUG_INFO("not in hex or decimal form.\n");
+		return count;
+	}
+
+	if ((ant >= 0) && (ant <= 2)) {
+		IWL_DEBUG_INFO("Setting antenna select to %d.\n", ant);
+		priv->antenna = (enum iwl_antenna)ant;
+	} else
+		IWL_DEBUG_INFO("Bad antenna select value %d.\n", ant);
+
+
+	return count;
+}
+
+static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, show_antenna, store_antenna);
+
+static ssize_t show_status(struct device *d,
+			   struct device_attribute *attr, char *buf)
+{
+	struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
+	if (!iwl_is_alive(priv))
+		return -EAGAIN;
+	return sprintf(buf, "0x%08x\n", (int)priv->status);
+}
+
+static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
+
+static ssize_t dump_error_log(struct device *d,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	char *p = (char *)buf;
+
+	if (p[0] == '1')
+		iwl_dump_nic_error_log((struct iwl_priv *)d->driver_data);
+
+	return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, dump_error_log);
+
+static ssize_t dump_event_log(struct device *d,
+			      struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	char *p = (char *)buf;
+
+	if (p[0] == '1')
+		iwl_dump_nic_event_log((struct iwl_priv *)d->driver_data);
+
+	return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
+
+/*****************************************************************************
+ *
+ * driver setup and teardown
+ *
+ *****************************************************************************/
+
+static void iwl_setup_deferred_work(struct iwl_priv *priv)
+{
+	priv->workqueue = create_workqueue(DRV_NAME);
+
+	init_waitqueue_head(&priv->wait_command_queue);
+
+	INIT_WORK(&priv->up, iwl_bg_up);
+	INIT_WORK(&priv->restart, iwl_bg_restart);
+	INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish);
+	INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
+	INIT_WORK(&priv->request_scan, iwl_bg_request_scan);
+	INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
+	INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill);
+	INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
+	INIT_DELAYED_WORK(&priv->post_associate, iwl_bg_post_associate);
+	INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
+	INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
+	INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
+
+	iwl_hw_setup_deferred_work(priv);
+
+	tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+		     iwl_irq_tasklet, (unsigned long)priv);
+}
+
+static void iwl_cancel_deferred_work(struct iwl_priv *priv)
+{
+	iwl_hw_cancel_deferred_work(priv);
+
+	cancel_delayed_work(&priv->scan_check);
+	cancel_delayed_work(&priv->alive_start);
+	cancel_delayed_work(&priv->post_associate);
+	cancel_work_sync(&priv->beacon_update);
+}
+
+static struct attribute *iwl_sysfs_entries[] = {
+	&dev_attr_antenna.attr,
+	&dev_attr_channels.attr,
+	&dev_attr_dump_errors.attr,
+	&dev_attr_dump_events.attr,
+	&dev_attr_flags.attr,
+	&dev_attr_filter_flags.attr,
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
+	&dev_attr_measurement.attr,
+#endif
+	&dev_attr_power_level.attr,
+	&dev_attr_retry_rate.attr,
+	&dev_attr_rf_kill.attr,
+	&dev_attr_rs_window.attr,
+	&dev_attr_statistics.attr,
+	&dev_attr_status.attr,
+	&dev_attr_temperature.attr,
+	&dev_attr_tune.attr,
+	&dev_attr_tx_power.attr,
+
+	NULL
+};
+
+static struct attribute_group iwl_attribute_group = {
+	.name = NULL,		/* put in device directory */
+	.attrs = iwl_sysfs_entries,
+};
+
+static struct ieee80211_ops iwl_hw_ops = {
+	.tx = iwl_mac_tx,
+	.start = iwl_mac_start,
+	.stop = iwl_mac_stop,
+	.add_interface = iwl_mac_add_interface,
+	.remove_interface = iwl_mac_remove_interface,
+	.config = iwl_mac_config,
+	.config_interface = iwl_mac_config_interface,
+	.configure_filter = iwl_configure_filter,
+	.set_key = iwl_mac_set_key,
+	.get_stats = iwl_mac_get_stats,
+	.get_tx_stats = iwl_mac_get_tx_stats,
+	.conf_tx = iwl_mac_conf_tx,
+	.get_tsf = iwl_mac_get_tsf,
+	.reset_tsf = iwl_mac_reset_tsf,
+	.beacon_update = iwl_mac_beacon_update,
+#ifdef CONFIG_IWLWIFI_HT
+	.conf_ht = iwl_mac_conf_ht,
+	.get_ht_capab = iwl_mac_get_ht_capab,
+#ifdef CONFIG_IWLWIFI_HT_AGG
+	.ht_tx_agg_start = iwl_mac_ht_tx_agg_start,
+	.ht_tx_agg_stop = iwl_mac_ht_tx_agg_stop,
+	.ht_rx_agg_start = iwl_mac_ht_rx_agg_start,
+	.ht_rx_agg_stop = iwl_mac_ht_rx_agg_stop,
+#endif  /* CONFIG_IWLWIFI_HT_AGG */
+#endif  /* CONFIG_IWLWIFI_HT */
+	.hw_scan = iwl_mac_hw_scan
+};
+
+static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int err = 0;
+	struct iwl_priv *priv;
+	struct ieee80211_hw *hw;
+	int i;
+
+	if (iwl_param_disable_hw_scan) {
+		IWL_DEBUG_INFO("Disabling hw_scan\n");
+		iwl_hw_ops.hw_scan = NULL;
+	}
+
+	if ((iwl_param_queues_num > IWL_MAX_NUM_QUEUES) ||
+	    (iwl_param_queues_num < IWL_MIN_NUM_QUEUES)) {
+		IWL_ERROR("invalid queues_num, should be between %d and %d\n",
+			  IWL_MIN_NUM_QUEUES, IWL_MAX_NUM_QUEUES);
+		err = -EINVAL;
+		goto out;
+	}
+
+	/* mac80211 allocates memory for this device instance, including
+	 *   space for this driver's private structure */
+	hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwl_hw_ops);
+	if (hw == NULL) {
+		IWL_ERROR("Can not allocate network device\n");
+		err = -ENOMEM;
+		goto out;
+	}
+	SET_IEEE80211_DEV(hw, &pdev->dev);
+
+	IWL_DEBUG_INFO("*** LOAD DRIVER ***\n");
+	priv = hw->priv;
+	priv->hw = hw;
+
+	priv->pci_dev = pdev;
+	priv->antenna = (enum iwl_antenna)iwl_param_antenna;
+#ifdef CONFIG_IWLWIFI_DEBUG
+	iwl_debug_level = iwl_param_debug;
+	atomic_set(&priv->restrict_refcnt, 0);
+#endif
+	priv->retry_rate = 1;
+
+	priv->ibss_beacon = NULL;
+
+	/* Tell mac80211 and its clients (e.g. Wireless Extensions)
+	 *   the range of signal quality values that we'll provide.
+	 * Negative values for level/noise indicate that we'll provide dBm.
+	 * For WE, at least, non-0 values here *enable* display of values
+	 *   in app (iwconfig). */
+	hw->max_rssi = -20;	/* signal level, negative indicates dBm */
+	hw->max_noise = -20;	/* noise level, negative indicates dBm */
+	hw->max_signal = 100;	/* link quality indication (%) */
+
+	/* Tell mac80211 our Tx characteristics */
+	hw->flags = IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE;
+
+	hw->queues = 4;
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+	hw->queues = 16;
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+
+	spin_lock_init(&priv->lock);
+	spin_lock_init(&priv->power_data.lock);
+	spin_lock_init(&priv->sta_lock);
+	spin_lock_init(&priv->hcmd_lock);
+	spin_lock_init(&priv->lq_mngr.lock);
+
+	for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++)
+		INIT_LIST_HEAD(&priv->ibss_mac_hash[i]);
+
+	INIT_LIST_HEAD(&priv->free_frames);
+
+	mutex_init(&priv->mutex);
+	if (pci_enable_device(pdev)) {
+		err = -ENODEV;
+		goto out_ieee80211_free_hw;
+	}
+
+	pci_set_master(pdev);
+
+	iwl_clear_stations_table(priv);
+
+	priv->data_retry_limit = -1;
+	priv->ieee_channels = NULL;
+	priv->ieee_rates = NULL;
+	priv->phymode = -1;
+
+	err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+	if (!err)
+		err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+	if (err) {
+		printk(KERN_WARNING DRV_NAME ": No suitable DMA available.\n");
+		goto out_pci_disable_device;
+	}
+
+	pci_set_drvdata(pdev, priv);
+	err = pci_request_regions(pdev, DRV_NAME);
+	if (err)
+		goto out_pci_disable_device;
+	/* We disable the RETRY_TIMEOUT register (0x41) to keep
+	 * PCI Tx retries from interfering with C3 CPU state */
+	pci_write_config_byte(pdev, 0x41, 0x00);
+	priv->hw_base = pci_iomap(pdev, 0, 0);
+	if (!priv->hw_base) {
+		err = -ENODEV;
+		goto out_pci_release_regions;
+	}
+
+	IWL_DEBUG_INFO("pci_resource_len = 0x%08llx\n",
+			(unsigned long long) pci_resource_len(pdev, 0));
+	IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base);
+
+	/* Initialize module parameter values here */
+
+	if (iwl_param_disable) {
+		set_bit(STATUS_RF_KILL_SW, &priv->status);
+		IWL_DEBUG_INFO("Radio disabled.\n");
+	}
+
+	priv->iw_mode = IEEE80211_IF_TYPE_STA;
+
+	priv->ps_mode = 0;
+	priv->use_ant_b_for_management_frame = 1; /* start with ant B */
+	priv->is_ht_enabled = 1;
+	priv->channel_width = IWL_CHANNEL_WIDTH_40MHZ;
+	priv->valid_antenna = 0x7;	/* assume all 3 connected */
+	priv->ps_mode = IWL_MIMO_PS_NONE;
+	priv->cck_power_index_compensation = iwl_read32(
+		priv, CSR_HW_REV_WA_REG);
+
+	iwl4965_set_rxon_chain(priv);
+
+	printk(KERN_INFO DRV_NAME
+	       ": Detected Intel Wireless WiFi Link 4965AGN\n");
+
+	/* Device-specific setup */
+	if (iwl_hw_set_hw_setting(priv)) {
+		IWL_ERROR("failed to set hw settings\n");
+		mutex_unlock(&priv->mutex);
+		goto out_iounmap;
+	}
+
+#ifdef CONFIG_IWLWIFI_QOS
+	if (iwl_param_qos_enable)
+		priv->qos_data.qos_enable = 1;
+
+	iwl_reset_qos(priv);
+
+	priv->qos_data.qos_active = 0;
+	priv->qos_data.qos_cap.val = 0;
+#endif /* CONFIG_IWLWIFI_QOS */
+
+	iwl_set_rxon_channel(priv, MODE_IEEE80211G, 6);
+	iwl_setup_deferred_work(priv);
+	iwl_setup_rx_handlers(priv);
+
+	priv->rates_mask = IWL_RATES_MASK;
+	/* If power management is turned on, default to AC mode */
+	priv->power_mode = IWL_POWER_AC;
+	priv->user_txpower_limit = IWL_DEFAULT_TX_POWER;
+
+	pci_enable_msi(pdev);
+
+	err = request_irq(pdev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv);
+	if (err) {
+		IWL_ERROR("Error allocating IRQ %d\n", pdev->irq);
+		goto out_disable_msi;
+	}
+
+	mutex_lock(&priv->mutex);
+
+	err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
+	if (err) {
+		IWL_ERROR("failed to create sysfs device attributes\n");
+		mutex_unlock(&priv->mutex);
+		goto out_release_irq;
+	}
+
+	/* fetch ucode file from disk, alloc and copy to bus-master buffers ...
+	 * ucode filename and max sizes are card-specific. */
+	err = iwl_read_ucode(priv);
+	if (err) {
+		IWL_ERROR("Could not read microcode: %d\n", err);
+		mutex_unlock(&priv->mutex);
+		goto out_pci_alloc;
+	}
+
+	mutex_unlock(&priv->mutex);
+
+	IWL_DEBUG_INFO("Queing UP work.\n");
+
+	queue_work(priv->workqueue, &priv->up);
+
+	return 0;
+
+ out_pci_alloc:
+	iwl_dealloc_ucode_pci(priv);
+
+	sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
+
+ out_release_irq:
+	free_irq(pdev->irq, priv);
+
+ out_disable_msi:
+	pci_disable_msi(pdev);
+	destroy_workqueue(priv->workqueue);
+	priv->workqueue = NULL;
+	iwl_unset_hw_setting(priv);
+
+ out_iounmap:
+	pci_iounmap(pdev, priv->hw_base);
+ out_pci_release_regions:
+	pci_release_regions(pdev);
+ out_pci_disable_device:
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+ out_ieee80211_free_hw:
+	ieee80211_free_hw(priv->hw);
+ out:
+	return err;
+}
+
+static void iwl_pci_remove(struct pci_dev *pdev)
+{
+	struct iwl_priv *priv = pci_get_drvdata(pdev);
+	struct list_head *p, *q;
+	int i;
+
+	if (!priv)
+		return;
+
+	IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n");
+
+	mutex_lock(&priv->mutex);
+	set_bit(STATUS_EXIT_PENDING, &priv->status);
+	__iwl_down(priv);
+	mutex_unlock(&priv->mutex);
+
+	/* Free MAC hash list for ADHOC */
+	for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
+		list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
+			list_del(p);
+			kfree(list_entry(p, struct iwl_ibss_seq, list));
+		}
+	}
+
+	sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
+
+	iwl_dealloc_ucode_pci(priv);
+
+	if (priv->rxq.bd)
+		iwl_rx_queue_free(priv, &priv->rxq);
+	iwl_hw_txq_ctx_free(priv);
+
+	iwl_unset_hw_setting(priv);
+	iwl_clear_stations_table(priv);
+
+	if (priv->mac80211_registered) {
+		ieee80211_unregister_hw(priv->hw);
+		iwl_rate_control_unregister(priv->hw);
+	}
+
+	/* ieee80211_unregister_hw calls iwl_mac_stop, which flushes
+	 * priv->workqueue... so we can't take down the workqueue
+	 * until now... */
+	destroy_workqueue(priv->workqueue);
+	priv->workqueue = NULL;
+
+	free_irq(pdev->irq, priv);
+	pci_disable_msi(pdev);
+	pci_iounmap(pdev, priv->hw_base);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+
+	kfree(priv->channel_info);
+
+	kfree(priv->ieee_channels);
+	kfree(priv->ieee_rates);
+
+	if (priv->ibss_beacon)
+		dev_kfree_skb(priv->ibss_beacon);
+
+	ieee80211_free_hw(priv->hw);
+}
+
+#ifdef CONFIG_PM
+
+static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct iwl_priv *priv = pci_get_drvdata(pdev);
+
+	mutex_lock(&priv->mutex);
+
+	set_bit(STATUS_IN_SUSPEND, &priv->status);
+
+	/* Take down the device; powers it off, etc. */
+	__iwl_down(priv);
+
+	if (priv->mac80211_registered)
+		ieee80211_stop_queues(priv->hw);
+
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, PCI_D3hot);
+
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+static void iwl_resume(struct iwl_priv *priv)
+{
+	unsigned long flags;
+
+	/* The following it a temporary work around due to the
+	 * suspend / resume not fully initializing the NIC correctly.
+	 * Without all of the following, resume will not attempt to take
+	 * down the NIC (it shouldn't really need to) and will just try
+	 * and bring the NIC back up.  However that fails during the
+	 * ucode verification process.  This then causes iwl_down to be
+	 * called *after* iwl_hw_nic_init() has succeeded -- which
+	 * then lets the next init sequence succeed.  So, we've
+	 * replicated all of that NIC init code here... */
+
+	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+	iwl_hw_nic_init(priv);
+
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+		    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+	iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+	iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+	/* tell the device to stop sending interrupts */
+	iwl_disable_interrupts(priv);
+
+	spin_lock_irqsave(&priv->lock, flags);
+	iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+	if (!iwl_grab_restricted_access(priv)) {
+		iwl_write_restricted_reg(priv, APMG_CLK_DIS_REG,
+					 APMG_CLK_VAL_DMA_CLK_RQT);
+		iwl_release_restricted_access(priv);
+	}
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	udelay(5);
+
+	iwl_hw_nic_reset(priv);
+
+	/* Bring the device back up */
+	clear_bit(STATUS_IN_SUSPEND, &priv->status);
+	queue_work(priv->workqueue, &priv->up);
+}
+
+static int iwl_pci_resume(struct pci_dev *pdev)
+{
+	struct iwl_priv *priv = pci_get_drvdata(pdev);
+	int err;
+
+	printk(KERN_INFO "Coming out of suspend...\n");
+
+	mutex_lock(&priv->mutex);
+
+	pci_set_power_state(pdev, PCI_D0);
+	err = pci_enable_device(pdev);
+	pci_restore_state(pdev);
+
+	/*
+	 * Suspend/Resume resets the PCI configuration space, so we have to
+	 * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries
+	 * from interfering with C3 CPU state. pci_restore_state won't help
+	 * here since it only restores the first 64 bytes pci config header.
+	 */
+	pci_write_config_byte(pdev, 0x41, 0x00);
+
+	iwl_resume(priv);
+	mutex_unlock(&priv->mutex);
+
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+
+/*****************************************************************************
+ *
+ * driver and module entry point
+ *
+ *****************************************************************************/
+
+static struct pci_driver iwl_driver = {
+	.name = DRV_NAME,
+	.id_table = iwl_hw_card_ids,
+	.probe = iwl_pci_probe,
+	.remove = __devexit_p(iwl_pci_remove),
+#ifdef CONFIG_PM
+	.suspend = iwl_pci_suspend,
+	.resume = iwl_pci_resume,
+#endif
+};
+
+static int __init iwl_init(void)
+{
+
+	int ret;
+	printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
+	printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+	ret = pci_register_driver(&iwl_driver);
+	if (ret) {
+		IWL_ERROR("Unable to initialize PCI module\n");
+		return ret;
+	}
+#ifdef CONFIG_IWLWIFI_DEBUG
+	ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level);
+	if (ret) {
+		IWL_ERROR("Unable to create driver sysfs file\n");
+		pci_unregister_driver(&iwl_driver);
+		return ret;
+	}
+#endif
+
+	return ret;
+}
+
+static void __exit iwl_exit(void)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+	driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level);
+#endif
+	pci_unregister_driver(&iwl_driver);
+}
+
+module_param_named(antenna, iwl_param_antenna, int, 0444);
+MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])");
+module_param_named(disable, iwl_param_disable, int, 0444);
+MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])");
+module_param_named(hwcrypto, iwl_param_hwcrypto, int, 0444);
+MODULE_PARM_DESC(hwcrypto,
+		 "using hardware crypto engine (default 0 [software])\n");
+module_param_named(debug, iwl_param_debug, int, 0444);
+MODULE_PARM_DESC(debug, "debug output mask");
+module_param_named(disable_hw_scan, iwl_param_disable_hw_scan, int, 0444);
+MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)");
+
+module_param_named(queues_num, iwl_param_queues_num, int, 0444);
+MODULE_PARM_DESC(queues_num, "number of hw queues.");
+
+/* QoS */
+module_param_named(qos_enable, iwl_param_qos_enable, int, 0444);
+MODULE_PARM_DESC(qos_enable, "enable all QoS functionality");
+
+module_exit(iwl_exit);
+module_init(iwl_init);
diff --git a/drivers/net/wireless/iwlwifi/iwlwifi.h b/drivers/net/wireless/iwlwifi/iwlwifi.h
new file mode 100644
index 0000000..e0b97c3
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwlwifi.h
@@ -0,0 +1,713 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2007 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * James P. Ketrenos <ipw2100-admin@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#ifndef __iwlwifi_h__
+#define __iwlwifi_h__
+
+#include <linux/pci.h> /* for struct pci_device_id */
+#include <linux/kernel.h>
+#include <net/ieee80211_radiotap.h>
+
+struct iwl_priv;
+
+/* Hardware specific file defines the PCI IDs table for that hardware module */
+extern struct pci_device_id iwl_hw_card_ids[];
+
+#if IWL == 3945
+
+#define DRV_NAME	"iwl3945"
+#include "iwl-hw.h"
+#include "iwl-3945-hw.h"
+
+#elif IWL == 4965
+
+#define DRV_NAME        "iwl4965"
+#include "iwl-hw.h"
+#include "iwl-4965-hw.h"
+
+#endif
+
+#include "iwl-prph.h"
+
+/*
+ * Driver implementation data structures, constants, inline
+ * functions
+ *
+ * NOTE:  DO NOT PUT HARDWARE/UCODE SPECIFIC DECLRATIONS HERE
+ *
+ * Hardware specific declrations go into iwl-*hw.h
+ *
+ */
+
+#include "iwl-debug.h"
+
+/* Default noise level to report when noise measurement is not available.
+ *   This may be because we're:
+ *   1)  Not associated (4965, no beacon statistics being sent to driver)
+ *   2)  Scanning (noise measurement does not apply to associated channel)
+ *   3)  Receiving CCK (3945 delivers noise info only for OFDM frames)
+ * Use default noise value of -127 ... this is below the range of measurable
+ *   Rx dBm for either 3945 or 4965, so it can indicate "unmeasurable" to user.
+ *   Also, -127 works better than 0 when averaging frames with/without
+ *   noise info (e.g. averaging might be done in app); measured dBm values are
+ *   always negative ... using a negative value as the default keeps all
+ *   averages within an s8's (used in some apps) range of negative values. */
+#define IWL_NOISE_MEAS_NOT_AVAILABLE (-127)
+
+/* Module parameters accessible from iwl-*.c */
+extern int iwl_param_disable_hw_scan;
+extern int iwl_param_debug;
+extern int iwl_param_mode;
+extern int iwl_param_disable;
+extern int iwl_param_antenna;
+extern int iwl_param_hwcrypto;
+extern int iwl_param_qos_enable;
+extern int iwl_param_queues_num;
+
+enum iwl_antenna {
+	IWL_ANTENNA_DIVERSITY,
+	IWL_ANTENNA_MAIN,
+	IWL_ANTENNA_AUX
+};
+
+/*
+ * RTS threshold here is total size [2347] minus 4 FCS bytes
+ * Per spec:
+ *   a value of 0 means RTS on all data/management packets
+ *   a value > max MSDU size means no RTS
+ * else RTS for data/management frames where MPDU is larger
+ *   than RTS value.
+ */
+#define DEFAULT_RTS_THRESHOLD     2347U
+#define MIN_RTS_THRESHOLD         0U
+#define MAX_RTS_THRESHOLD         2347U
+#define MAX_MSDU_SIZE		  2304U
+#define MAX_MPDU_SIZE		  2346U
+#define DEFAULT_BEACON_INTERVAL   100U
+#define	DEFAULT_SHORT_RETRY_LIMIT 7U
+#define	DEFAULT_LONG_RETRY_LIMIT  4U
+
+struct iwl_rx_mem_buffer {
+	dma_addr_t dma_addr;
+	struct sk_buff *skb;
+	struct list_head list;
+};
+
+struct iwl_rt_rx_hdr {
+	struct ieee80211_radiotap_header rt_hdr;
+	__le64 rt_tsf;		/* TSF */
+	u8 rt_flags;		/* radiotap packet flags */
+	u8 rt_rate;		/* rate in 500kb/s */
+	__le16 rt_channelMHz;	/* channel in MHz */
+	__le16 rt_chbitmask;	/* channel bitfield */
+	s8 rt_dbmsignal;	/* signal in dBm, kluged to signed */
+	s8 rt_dbmnoise;
+	u8 rt_antenna;		/* antenna number */
+	u8 payload[0];		/* payload... */
+} __attribute__ ((packed));
+
+struct iwl_rt_tx_hdr {
+	struct ieee80211_radiotap_header rt_hdr;
+	u8 rt_rate;		/* rate in 500kb/s */
+	__le16 rt_channel;	/* channel in mHz */
+	__le16 rt_chbitmask;	/* channel bitfield */
+	s8 rt_dbmsignal;	/* signal in dBm, kluged to signed */
+	u8 rt_antenna;		/* antenna number */
+	u8 payload[0];		/* payload... */
+} __attribute__ ((packed));
+
+/*
+ * Generic queue structure
+ *
+ * Contains common data for Rx and Tx queues
+ */
+struct iwl_queue {
+	int n_bd;              /* number of BDs in this queue */
+	int first_empty;       /* 1-st empty entry (index) host_w*/
+	int last_used;         /* last used entry (index) host_r*/
+	dma_addr_t dma_addr;   /* physical addr for BD's */
+	int n_window;	       /* safe queue window */
+	u32 id;
+	int low_mark;	       /* low watermark, resume queue if free
+				* space more than this */
+	int high_mark;         /* high watermark, stop queue if free
+				* space less than this */
+} __attribute__ ((packed));
+
+#define MAX_NUM_OF_TBS          (20)
+
+struct iwl_tx_info {
+	struct ieee80211_tx_status status;
+	struct sk_buff *skb[MAX_NUM_OF_TBS];
+};
+
+/**
+ * struct iwl_tx_queue - Tx Queue for DMA
+ * @need_update: need to update read/write index
+ * @shed_retry: queue is HT AGG enabled
+ *
+ * Queue consists of circular buffer of BD's and required locking structures.
+ */
+struct iwl_tx_queue {
+	struct iwl_queue q;
+	struct iwl_tfd_frame *bd;
+	struct iwl_cmd *cmd;
+	dma_addr_t dma_addr_cmd;
+	struct iwl_tx_info *txb;
+	int need_update;
+	int sched_retry;
+	int active;
+};
+
+#include "iwl-channel.h"
+
+#if IWL == 3945
+#include "iwl-3945-rs.h"
+#else
+#include "iwl-4965-rs.h"
+#endif
+
+#define IWL_TX_FIFO_AC0	0
+#define IWL_TX_FIFO_AC1	1
+#define IWL_TX_FIFO_AC2	2
+#define IWL_TX_FIFO_AC3	3
+#define IWL_TX_FIFO_HCCA_1	5
+#define IWL_TX_FIFO_HCCA_2	6
+#define IWL_TX_FIFO_NONE	7
+
+/* Minimum number of queues. MAX_NUM is defined in hw specific files */
+#define IWL_MIN_NUM_QUEUES	4
+
+/* Power management (not Tx power) structures */
+
+struct iwl_power_vec_entry {
+	struct iwl_powertable_cmd cmd;
+	u8 no_dtim;
+};
+#define IWL_POWER_RANGE_0  (0)
+#define IWL_POWER_RANGE_1  (1)
+
+#define IWL_POWER_MODE_CAM	0x00	/* Continuously Aware Mode, always on */
+#define IWL_POWER_INDEX_3	0x03
+#define IWL_POWER_INDEX_5	0x05
+#define IWL_POWER_AC		0x06
+#define IWL_POWER_BATTERY	0x07
+#define IWL_POWER_LIMIT		0x07
+#define IWL_POWER_MASK		0x0F
+#define IWL_POWER_ENABLED	0x10
+#define IWL_POWER_LEVEL(x)	((x) & IWL_POWER_MASK)
+
+struct iwl_power_mgr {
+	spinlock_t lock;
+	struct iwl_power_vec_entry pwr_range_0[IWL_POWER_AC];
+	struct iwl_power_vec_entry pwr_range_1[IWL_POWER_AC];
+	u8 active_index;
+	u32 dtim_val;
+};
+
+#define IEEE80211_DATA_LEN              2304
+#define IEEE80211_4ADDR_LEN             30
+#define IEEE80211_HLEN                  (IEEE80211_4ADDR_LEN)
+#define IEEE80211_FRAME_LEN             (IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+struct iwl_frame {
+	union {
+		struct ieee80211_hdr frame;
+		struct iwl_tx_beacon_cmd beacon;
+		u8 raw[IEEE80211_FRAME_LEN];
+		u8 cmd[360];
+	} u;
+	struct list_head list;
+};
+
+#define SEQ_TO_QUEUE(x)  ((x >> 8) & 0xbf)
+#define QUEUE_TO_SEQ(x)  ((x & 0xbf) << 8)
+#define SEQ_TO_INDEX(x) (x & 0xff)
+#define INDEX_TO_SEQ(x) (x & 0xff)
+#define SEQ_HUGE_FRAME  (0x4000)
+#define SEQ_RX_FRAME    __constant_cpu_to_le16(0x8000)
+#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
+#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
+#define MAX_SN ((IEEE80211_SCTL_SEQ) >> 4)
+
+enum {
+	/* CMD_SIZE_NORMAL = 0, */
+	CMD_SIZE_HUGE = (1 << 0),
+	/* CMD_SYNC = 0, */
+	CMD_ASYNC = (1 << 1),
+	/* CMD_NO_SKB = 0, */
+	CMD_WANT_SKB = (1 << 2),
+};
+
+struct iwl_cmd;
+struct iwl_priv;
+
+struct iwl_cmd_meta {
+	struct iwl_cmd_meta *source;
+	union {
+		struct sk_buff *skb;
+		int (*callback)(struct iwl_priv *priv,
+				struct iwl_cmd *cmd, struct sk_buff *skb);
+	} __attribute__ ((packed)) u;
+
+	/* The CMD_SIZE_HUGE flag bit indicates that the command
+	 * structure is stored at the end of the shared queue memory. */
+	u32 flags;
+
+} __attribute__ ((packed));
+
+struct iwl_cmd {
+	struct iwl_cmd_meta meta;
+	struct iwl_cmd_header hdr;
+	union {
+		struct iwl_addsta_cmd addsta;
+		struct iwl_led_cmd led;
+		u32 flags;
+		u8 val8;
+		u16 val16;
+		u32 val32;
+		struct iwl_bt_cmd bt;
+		struct iwl_rxon_time_cmd rxon_time;
+		struct iwl_powertable_cmd powertable;
+		struct iwl_qosparam_cmd qosparam;
+		struct iwl_tx_cmd tx;
+		struct iwl_tx_beacon_cmd tx_beacon;
+		struct iwl_rxon_assoc_cmd rxon_assoc;
+		u8 *indirect;
+		u8 payload[360];
+	} __attribute__ ((packed)) cmd;
+} __attribute__ ((packed));
+
+struct iwl_host_cmd {
+	u8 id;
+	u16 len;
+	struct iwl_cmd_meta meta;
+	const void *data;
+};
+
+#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_cmd) - \
+			      sizeof(struct iwl_cmd_meta))
+
+/*
+ * RX related structures and functions
+ */
+#define RX_FREE_BUFFERS 64
+#define RX_LOW_WATERMARK 8
+
+#define SUP_RATE_11A_MAX_NUM_CHANNELS  8
+#define SUP_RATE_11B_MAX_NUM_CHANNELS  4
+#define SUP_RATE_11G_MAX_NUM_CHANNELS  12
+
+/**
+ * struct iwl_rx_queue - Rx queue
+ * @processed: Internal index to last handled Rx packet
+ * @read: Shared index to newest available Rx buffer
+ * @write: Shared index to oldest written Rx packet
+ * @free_count: Number of pre-allocated buffers in rx_free
+ * @rx_free: list of free SKBs for use
+ * @rx_used: List of Rx buffers with no SKB
+ * @need_update: flag to indicate we need to update read/write index
+ *
+ * NOTE:  rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
+ */
+struct iwl_rx_queue {
+	__le32 *bd;
+	dma_addr_t dma_addr;
+	struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
+	struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
+	u32 processed;
+	u32 read;
+	u32 write;
+	u32 free_count;
+	struct list_head rx_free;
+	struct list_head rx_used;
+	int need_update;
+	spinlock_t lock;
+};
+
+#define IWL_SUPPORTED_RATES_IE_LEN         8
+
+#define SCAN_INTERVAL 100
+
+#define MAX_A_CHANNELS  252
+#define MIN_A_CHANNELS  7
+
+#define MAX_B_CHANNELS  14
+#define MIN_B_CHANNELS  1
+
+#define STATUS_HCMD_ACTIVE	0	/* host command in progress */
+#define STATUS_INT_ENABLED	1
+#define STATUS_RF_KILL_HW	2
+#define STATUS_RF_KILL_SW	3
+#define STATUS_INIT		4
+#define STATUS_ALIVE		5
+#define STATUS_READY		6
+#define STATUS_TEMPERATURE	7
+#define STATUS_GEO_CONFIGURED	8
+#define STATUS_EXIT_PENDING	9
+#define STATUS_IN_SUSPEND	10
+#define STATUS_STATISTICS	11
+#define STATUS_SCANNING		12
+#define STATUS_SCAN_ABORTING	13
+#define STATUS_SCAN_HW		14
+#define STATUS_POWER_PMI	15
+#define STATUS_FW_ERROR		16
+
+#define MAX_TID_COUNT        9
+
+#define IWL_INVALID_RATE     0xFF
+#define IWL_INVALID_VALUE    -1
+
+#if IWL == 4965
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+struct iwl_ht_agg {
+	u16 txq_id;
+	u16 frame_count;
+	u16 wait_for_ba;
+	u16 start_idx;
+	u32 bitmap0;
+	u32 bitmap1;
+	u32 rate_n_flags;
+};
+#endif /* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+#endif
+
+struct iwl_tid_data {
+	u16 seq_number;
+#if IWL == 4965
+#ifdef CONFIG_IWLWIFI_HT
+#ifdef CONFIG_IWLWIFI_HT_AGG
+	struct iwl_ht_agg agg;
+#endif	/* CONFIG_IWLWIFI_HT_AGG */
+#endif /* CONFIG_IWLWIFI_HT */
+#endif
+};
+
+struct iwl_hw_key {
+	enum ieee80211_key_alg alg;
+	int keylen;
+	u8 key[32];
+};
+
+union iwl_ht_rate_supp {
+	u16 rates;
+	struct {
+		u8 siso_rate;
+		u8 mimo_rate;
+	};
+};
+
+#ifdef CONFIG_IWLWIFI_HT
+#define CFG_HT_RX_AMPDU_FACTOR_DEF  (0x3)
+#define HT_IE_MAX_AMSDU_SIZE_4K     (0)
+#define CFG_HT_MPDU_DENSITY_2USEC   (0x5)
+#define CFG_HT_MPDU_DENSITY_DEF CFG_HT_MPDU_DENSITY_2USEC
+
+struct sta_ht_info {
+	u8 is_ht;
+	u16 rx_mimo_ps_mode;
+	u16 tx_mimo_ps_mode;
+	u16 control_channel;
+	u8 max_amsdu_size;
+	u8 ampdu_factor;
+	u8 mpdu_density;
+	u8 operating_mode;
+	u8 supported_chan_width;
+	u8 extension_chan_offset;
+	u8 is_green_field;
+	u8 sgf;
+	u8 supp_rates[16];
+	u8 tx_chan_width;
+	u8 chan_width_cap;
+};
+#endif				/*CONFIG_IWLWIFI_HT */
+
+#ifdef CONFIG_IWLWIFI_QOS
+
+union iwl_qos_capabity {
+	struct {
+		u8 edca_count:4;	/* bit 0-3 */
+		u8 q_ack:1;		/* bit 4 */
+		u8 queue_request:1;	/* bit 5 */
+		u8 txop_request:1;	/* bit 6 */
+		u8 reserved:1;		/* bit 7 */
+	} q_AP;
+	struct {
+		u8 acvo_APSD:1;		/* bit 0 */
+		u8 acvi_APSD:1;		/* bit 1 */
+		u8 ac_bk_APSD:1;	/* bit 2 */
+		u8 ac_be_APSD:1;	/* bit 3 */
+		u8 q_ack:1;		/* bit 4 */
+		u8 max_len:2;		/* bit 5-6 */
+		u8 more_data_ack:1;	/* bit 7 */
+	} q_STA;
+	u8 val;
+};
+
+/* QoS sturctures */
+struct iwl_qos_info {
+	int qos_enable;
+	int qos_active;
+	union iwl_qos_capabity qos_cap;
+	struct iwl_qosparam_cmd def_qos_parm;
+};
+#endif /*CONFIG_IWLWIFI_QOS */
+
+#define STA_PS_STATUS_WAKE             0
+#define STA_PS_STATUS_SLEEP            1
+
+struct iwl_station_entry {
+	struct iwl_addsta_cmd sta;
+	struct iwl_tid_data tid[MAX_TID_COUNT];
+#if IWL == 3945
+	union {
+		struct {
+			u8 rate;
+			u8 flags;
+		} s;
+		u16 rate_n_flags;
+	} current_rate;
+#endif
+	u8 used;
+	u8 ps_status;
+	struct iwl_hw_key keyinfo;
+};
+
+/* one for each uCode image (inst/data, boot/init/runtime) */
+struct fw_image_desc {
+	void *v_addr;		/* access by driver */
+	dma_addr_t p_addr;	/* access by card's busmaster DMA */
+	u32 len;		/* bytes */
+};
+
+/* uCode file layout */
+struct iwl_ucode {
+	__le32 ver;		/* major/minor/subminor */
+	__le32 inst_size;	/* bytes of runtime instructions */
+	__le32 data_size;	/* bytes of runtime data */
+	__le32 init_size;	/* bytes of initialization instructions */
+	__le32 init_data_size;	/* bytes of initialization data */
+	__le32 boot_size;	/* bytes of bootstrap instructions */
+	u8 data[0];		/* data in same order as "size" elements */
+};
+
+#define IWL_IBSS_MAC_HASH_SIZE 32
+
+struct iwl_ibss_seq {
+	u8 mac[ETH_ALEN];
+	u16 seq_num;
+	u16 frag_num;
+	unsigned long packet_time;
+	struct list_head list;
+};
+
+struct iwl_driver_hw_info {
+	u16 max_txq_num;
+	u16 ac_queue_count;
+	u32 rx_buffer_size;
+	u16 tx_cmd_len;
+	u16 max_rxq_size;
+	u16 max_rxq_log;
+	u32 cck_flag;
+	u8  max_stations;
+	u8  bcast_sta_id;
+	void *shared_virt;
+	dma_addr_t shared_phys;
+};
+
+
+#define STA_FLG_RTS_MIMO_PROT_MSK	__constant_cpu_to_le32(1 << 17)
+#define STA_FLG_AGG_MPDU_8US_MSK	__constant_cpu_to_le32(1 << 18)
+#define STA_FLG_MAX_AGG_SIZE_POS	(19)
+#define STA_FLG_MAX_AGG_SIZE_MSK	__constant_cpu_to_le32(3 << 19)
+#define STA_FLG_FAT_EN_MSK		__constant_cpu_to_le32(1 << 21)
+#define STA_FLG_MIMO_DIS_MSK		__constant_cpu_to_le32(1 << 22)
+#define STA_FLG_AGG_MPDU_DENSITY_POS	(23)
+#define STA_FLG_AGG_MPDU_DENSITY_MSK	__constant_cpu_to_le32(7 << 23)
+#define HT_SHORT_GI_20MHZ_ONLY          (1 << 0)
+#define HT_SHORT_GI_40MHZ_ONLY          (1 << 1)
+
+
+#include "iwl-priv.h"
+
+/* Requires full declaration of iwl_priv before including */
+#include "iwl-io.h"
+
+#define IWL_RX_HDR(x) ((struct iwl_rx_frame_hdr *)(\
+		       x->u.rx_frame.stats.payload + \
+		       x->u.rx_frame.stats.phy_count))
+#define IWL_RX_END(x) ((struct iwl_rx_frame_end *)(\
+		       IWL_RX_HDR(x)->payload + \
+		       le16_to_cpu(IWL_RX_HDR(x)->len)))
+#define IWL_RX_STATS(x) (&x->u.rx_frame.stats)
+#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload)
+
+
+/******************************************************************************
+ *
+ * Functions implemented in iwl-base.c which are forward declared here
+ * for use by iwl-*.c
+ *
+ *****************************************************************************/
+struct iwl_addsta_cmd;
+extern int iwl_send_add_station(struct iwl_priv *priv,
+				struct iwl_addsta_cmd *sta, u8 flags);
+extern const char *iwl_get_tx_fail_reason(u32 status);
+extern u8 iwl_add_station(struct iwl_priv *priv, const u8 *bssid,
+			  int is_ap, u8 flags);
+extern int iwl_is_network_packet(struct iwl_priv *priv,
+				 struct ieee80211_hdr *header);
+extern int iwl_power_init_handle(struct iwl_priv *priv);
+extern int iwl_eeprom_init(struct iwl_priv *priv);
+#ifdef CONFIG_IWLWIFI_DEBUG
+extern void iwl_report_frame(struct iwl_priv *priv,
+			     struct iwl_rx_packet *pkt,
+			     struct ieee80211_hdr *header, int group100);
+#else
+static inline void iwl_report_frame(struct iwl_priv *priv,
+				    struct iwl_rx_packet *pkt,
+				    struct ieee80211_hdr *header,
+				    int group100) {}
+#endif
+extern int iwl_tx_queue_update_write_ptr(struct iwl_priv *priv,
+					 struct iwl_tx_queue *txq);
+extern void iwl_handle_data_packet_monitor(struct iwl_priv *priv,
+					   struct iwl_rx_mem_buffer *rxb,
+					   void *data, short len,
+					   struct ieee80211_rx_status *stats,
+					   u16 phy_flags);
+extern int is_duplicate_packet(struct iwl_priv *priv, struct ieee80211_hdr
+			       *header);
+extern void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
+extern int iwl_rx_queue_alloc(struct iwl_priv *priv);
+extern void iwl_rx_queue_reset(struct iwl_priv *priv,
+			       struct iwl_rx_queue *rxq);
+extern int iwl_calc_db_from_ratio(int sig_ratio);
+extern int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm);
+extern int iwl_tx_queue_init(struct iwl_priv *priv,
+			     struct iwl_tx_queue *txq, int count, u32 id);
+extern int iwl_rx_queue_restock(struct iwl_priv *priv);
+extern void iwl_rx_replenish(void *data);
+extern void iwl_tx_queue_free(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+extern int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len,
+			    const void *data);
+extern int __must_check iwl_send_cmd_async(struct iwl_priv *priv,
+		struct iwl_host_cmd *cmd);
+extern int __must_check iwl_send_cmd_sync(struct iwl_priv *priv,
+		struct iwl_host_cmd *cmd);
+extern int __must_check iwl_send_cmd(struct iwl_priv *priv,
+		struct iwl_host_cmd *cmd);
+extern unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv,
+					struct ieee80211_hdr *hdr,
+					const u8 *dest, int left);
+extern int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
+					 struct iwl_rx_queue *q);
+extern int iwl_send_statistics_request(struct iwl_priv *priv);
+extern void iwl_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
+				   u32 decrypt_res,
+				   struct ieee80211_rx_status *stats);
+extern __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr);
+
+extern const u8 BROADCAST_ADDR[ETH_ALEN];
+
+/*
+ * Currently used by iwl-3945-rs... look at restructuring so that it doesn't
+ * call this... todo... fix that.
+*/
+extern u8 iwl_sync_station(struct iwl_priv *priv, int sta_id,
+			   u16 tx_rate, u8 flags);
+
+static inline int iwl_is_associated(struct iwl_priv *priv)
+{
+	return (priv->active_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+}
+
+/******************************************************************************
+ *
+ * Functions implemented in iwl-[34]*.c which are forward declared here
+ * for use by iwl-base.c
+ *
+ * NOTE:  The implementation of these functions are hardware specific
+ * which is why they are in the hardware specific files (vs. iwl-base.c)
+ *
+ * Naming convention --
+ * iwl_         <-- Its part of iwlwifi (should be changed to iwl_)
+ * iwl_hw_      <-- Hardware specific (implemented in iwl-XXXX.c by all HW)
+ * iwlXXXX_     <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
+ * iwl_bg_      <-- Called from work queue context
+ * iwl_mac_     <-- mac80211 callback
+ *
+ ****************************************************************************/
+extern void iwl_hw_rx_handler_setup(struct iwl_priv *priv);
+extern void iwl_hw_setup_deferred_work(struct iwl_priv *priv);
+extern void iwl_hw_cancel_deferred_work(struct iwl_priv *priv);
+extern int iwl_hw_rxq_stop(struct iwl_priv *priv);
+extern int iwl_hw_set_hw_setting(struct iwl_priv *priv);
+extern int iwl_hw_nic_init(struct iwl_priv *priv);
+extern void iwl_hw_card_show_info(struct iwl_priv *priv);
+extern int iwl_hw_nic_stop_master(struct iwl_priv *priv);
+extern void iwl_hw_txq_ctx_free(struct iwl_priv *priv);
+extern void iwl_hw_txq_ctx_stop(struct iwl_priv *priv);
+extern int iwl_hw_nic_reset(struct iwl_priv *priv);
+extern int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *tfd,
+					dma_addr_t addr, u16 len);
+extern int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+extern int iwl_hw_get_temperature(struct iwl_priv *priv);
+extern int iwl_hw_tx_queue_init(struct iwl_priv *priv,
+				struct iwl_tx_queue *txq);
+extern unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
+				 struct iwl_frame *frame, u8 rate);
+extern int iwl_hw_get_rx_read(struct iwl_priv *priv);
+extern void iwl_hw_build_tx_cmd_rate(struct iwl_priv *priv,
+				     struct iwl_cmd *cmd,
+				     struct ieee80211_tx_control *ctrl,
+				     struct ieee80211_hdr *hdr,
+				     int sta_id, int tx_id);
+extern int iwl_hw_reg_send_txpower(struct iwl_priv *priv);
+extern int iwl_hw_reg_set_txpower(struct iwl_priv *priv, s8 power);
+extern void iwl_hw_rx_statistics(struct iwl_priv *priv,
+				 struct iwl_rx_mem_buffer *rxb);
+extern void iwl_disable_events(struct iwl_priv *priv);
+extern int iwl4965_get_temperature(const struct iwl_priv *priv);
+
+/**
+ * iwl_hw_find_station - Find station id for a given BSSID
+ * @bssid: MAC address of station ID to find
+ *
+ * NOTE:  This should not be hardware specific but the code has
+ * not yet been merged into a single common layer for managing the
+ * station tables.
+ */
+extern u8 iwl_hw_find_station(struct iwl_priv *priv, const u8 *bssid);
+
+extern int iwl_hw_channel_switch(struct iwl_priv *priv, u16 channel);
+extern int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
+#endif
diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c
index 4cf0ff7b..9cf0211 100644
--- a/drivers/net/wireless/libertas/11d.c
+++ b/drivers/net/wireless/libertas/11d.c
@@ -124,17 +124,17 @@
 	u8 nr_chan = parsed_region_chan->nr_chan;
 	u8 i = 0;
 
-	lbs_dbg_hex("11D:parsed_region_chan:", (char *)chanpwr,
+	lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)chanpwr,
 		sizeof(struct chan_power_11d) * nr_chan);
 
 	for (i = 0; i < nr_chan; i++) {
 		if (chan == chanpwr[i].chan) {
-			lbs_deb_11d("11D: Found Chan:%d\n", chan);
+			lbs_deb_11d("found chan %d\n", chan);
 			return 1;
 		}
 	}
 
-	lbs_deb_11d("11D: Not Find Chan:%d\n", chan);
+	lbs_deb_11d("chan %d not found\n", chan);
 	return 0;
 }
 
@@ -174,8 +174,8 @@
 	memcpy(domaininfo->countrycode, parsed_region_chan->countrycode,
 	       COUNTRY_CODE_LEN);
 
-	lbs_deb_11d("11D:nrchan=%d\n", nr_chan);
-	lbs_dbg_hex("11D:parsed_region_chan:", (char *)parsed_region_chan,
+	lbs_deb_11d("nrchan %d\n", nr_chan);
+	lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (char *)parsed_region_chan,
 		sizeof(struct parsed_region_chan_11d));
 
 	for (i = 0; i < nr_chan; i++) {
@@ -213,7 +213,7 @@
 	domaininfo->nr_subband = nr_subband;
 
 	lbs_deb_11d("nr_subband=%x\n", domaininfo->nr_subband);
-	lbs_dbg_hex("11D:domaininfo:", (char *)domaininfo,
+	lbs_deb_hex(LBS_DEB_11D, "domaininfo", (char *)domaininfo,
 		COUNTRY_CODE_LEN + 1 +
 		sizeof(struct ieeetypes_subbandset) * nr_subband);
 	return 0;
@@ -233,13 +233,13 @@
 	struct chan_freq_power *cfp;
 
 	if (region_chan == NULL) {
-		lbs_deb_11d("11D: region_chan is NULL\n");
+		lbs_deb_11d("region_chan is NULL\n");
 		return;
 	}
 
 	cfp = region_chan->CFP;
 	if (cfp == NULL) {
-		lbs_deb_11d("11D: cfp equal NULL \n");
+		lbs_deb_11d("cfp is NULL \n");
 		return;
 	}
 
@@ -248,19 +248,19 @@
 	memcpy(parsed_region_chan->countrycode,
 	       wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN);
 
-	lbs_deb_11d("11D: region[0x%x] band[%d]\n", parsed_region_chan->region,
+	lbs_deb_11d("region 0x%x, band %d\n", parsed_region_chan->region,
 	       parsed_region_chan->band);
 
 	for (i = 0; i < region_chan->nrcfp; i++, cfp++) {
 		parsed_region_chan->chanpwr[i].chan = cfp->channel;
 		parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower;
-		lbs_deb_11d("11D: Chan[%d] Pwr[%d]\n",
+		lbs_deb_11d("chan %d, pwr %d\n",
 		       parsed_region_chan->chanpwr[i].chan,
 		       parsed_region_chan->chanpwr[i].pwr);
 	}
 	parsed_region_chan->nr_chan = region_chan->nrcfp;
 
-	lbs_deb_11d("11D: nrchan[%d]\n", parsed_region_chan->nr_chan);
+	lbs_deb_11d("nrchan %d\n", parsed_region_chan->nr_chan);
 
 	return;
 }
@@ -336,7 +336,7 @@
 	   6. Others
 	 */
 
-	lbs_dbg_hex("CountryInfo:", (u8 *) countryinfo, 30);
+	lbs_deb_hex(LBS_DEB_11D, "countryinfo", (u8 *) countryinfo, 30);
 
 	if ((*(countryinfo->countrycode)) == 0
 	    || (countryinfo->len <= COUNTRY_CODE_LEN)) {
@@ -349,7 +349,7 @@
 	    wlan_region_2_code(countryinfo->countrycode);
 
 	lbs_deb_11d("regioncode=%x\n", (u8) parsed_region_chan->region);
-	lbs_dbg_hex("CountryCode:", (char *)countryinfo->countrycode,
+	lbs_deb_hex(LBS_DEB_11D, "countrycode", (char *)countryinfo->countrycode,
 		COUNTRY_CODE_LEN);
 
 	parsed_region_chan->band = band;
@@ -364,7 +364,7 @@
 
 		if (countryinfo->subband[j].firstchan <= lastchan) {
 			/*Step2&3. Check First Chan Num increment and no overlap */
-			lbs_deb_11d("11D: Chan[%d>%d] Overlap\n",
+			lbs_deb_11d("chan %d>%d, overlap\n",
 			       countryinfo->subband[j].firstchan, lastchan);
 			continue;
 		}
@@ -393,7 +393,7 @@
 			} else {
 				/*not supported and ignore the chan */
 				lbs_deb_11d(
-				       "11D:i[%d] chan[%d] unsupported in region[%x] band[%d]\n",
+				       "i %d, chan %d unsupported in region %x, band %d\n",
 				       i, curchan, region, band);
 			}
 		}
@@ -405,7 +405,7 @@
 	parsed_region_chan->nr_chan = idx;
 
 	lbs_deb_11d("nrchan=%x\n", parsed_region_chan->nr_chan);
-	lbs_dbg_hex("11D:parsed_region_chan:", (u8 *) parsed_region_chan,
+	lbs_deb_hex(LBS_DEB_11D, "parsed_region_chan", (u8 *) parsed_region_chan,
 		2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx);
 
 done:
@@ -422,15 +422,15 @@
 u8 libertas_get_scan_type_11d(u8 chan,
 			  struct parsed_region_chan_11d * parsed_region_chan)
 {
-	u8 scan_type = cmd_scan_type_passive;
+	u8 scan_type = CMD_SCAN_TYPE_PASSIVE;
 
 	lbs_deb_enter(LBS_DEB_11D);
 
 	if (wlan_channel_known_11d(chan, parsed_region_chan)) {
-		lbs_deb_11d("11D: Found and do Active Scan\n");
-		scan_type = cmd_scan_type_active;
+		lbs_deb_11d("found, do active scan\n");
+		scan_type = CMD_SCAN_TYPE_ACTIVE;
 	} else {
-		lbs_deb_11d("11D: Not Find and do Passive Scan\n");
+		lbs_deb_11d("not found, do passive scan\n");
 	}
 
 	lbs_deb_leave_args(LBS_DEB_11D, "ret scan_type %d", scan_type);
@@ -446,25 +446,6 @@
 	return;
 }
 
-static int wlan_enable_11d(wlan_private * priv, u8 flag)
-{
-	int ret;
-
-	priv->adapter->enable11d = flag;
-
-	/* send cmd to FW to enable/disable 11D function in FW */
-	ret = libertas_prepare_and_send_command(priv,
-				    cmd_802_11_snmp_mib,
-				    cmd_act_set,
-				    cmd_option_waitforrsp,
-				    OID_802_11D_ENABLE,
-				    &priv->adapter->enable11d);
-	if (ret)
-		lbs_deb_11d("11D: Fail to enable 11D \n");
-
-	return 0;
-}
-
 /**
  *  @brief This function sets DOMAIN INFO to FW
  *  @param priv       pointer to wlan_private
@@ -475,15 +456,15 @@
 	int ret;
 
 	if (!priv->adapter->enable11d) {
-		lbs_deb_11d("11D: dnld domain Info with 11d disabled\n");
+		lbs_deb_11d("dnld domain Info with 11d disabled\n");
 		return 0;
 	}
 
-	ret = libertas_prepare_and_send_command(priv, cmd_802_11d_domain_info,
-				    cmd_act_set,
-				    cmd_option_waitforrsp, 0, NULL);
+	ret = libertas_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
+				    CMD_ACT_SET,
+				    CMD_OPTION_WAITFORRSP, 0, NULL);
 	if (ret)
-		lbs_deb_11d("11D: Fail to dnld domain Info\n");
+		lbs_deb_11d("fail to dnld domain info\n");
 
 	return ret;
 }
@@ -505,7 +486,7 @@
 
 	adapter->universal_channel[i].nrcfp =
 	    sizeof(channel_freq_power_UN_BG) / size;
-	lbs_deb_11d("11D: BG-band nrcfp=%d\n",
+	lbs_deb_11d("BG-band nrcfp %d\n",
 	       adapter->universal_channel[i].nrcfp);
 
 	adapter->universal_channel[i].CFP = channel_freq_power_UN_BG;
@@ -541,10 +522,10 @@
 
 	cmd->command = cpu_to_le16(cmdno);
 	pdomaininfo->action = cpu_to_le16(cmdoption);
-	if (cmdoption == cmd_act_get) {
+	if (cmdoption == CMD_ACT_GET) {
 		cmd->size =
 		    cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
-		lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd,
+		lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
 			(int)(cmd->size));
 		goto done;
 	}
@@ -562,7 +543,7 @@
 		       nr_subband * sizeof(struct ieeetypes_subbandset));
 
 		cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
-					     domain->header.len +
+					     le16_to_cpu(domain->header.len) +
 					     sizeof(struct mrvlietypesheader) +
 					     S_DS_GEN);
 	} else {
@@ -570,7 +551,7 @@
 		    cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN);
 	}
 
-	lbs_dbg_hex("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, le16_to_cpu(cmd->size));
+	lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd, le16_to_cpu(cmd->size));
 
 done:
 	lbs_deb_enter(LBS_DEB_11D);
@@ -578,31 +559,6 @@
 }
 
 /**
- *  @brief This function implements private cmd: enable/disable 11D
- *  @param priv    pointer to wlan_private
- *  @param wrq     pointer to user data
- *  @return 	   0 or -1
- */
-int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq)
-{
-	int data = 0;
-	int *val;
-
-	lbs_deb_enter(LBS_DEB_11D);
-	data = SUBCMD_DATA(wrq);
-
-	lbs_deb_11d("enable 11D: %s\n",
-	       (data == 1) ? "enable" : "Disable");
-
-	wlan_enable_11d(priv, data);
-	val = (int *)wrq->u.name;
-	*val = priv->adapter->enable11d;
-
-	lbs_deb_enter(LBS_DEB_11D);
-	return 0;
-}
-
-/**
  *  @brief This function parses countryinfo from AP and download country info to FW
  *  @param priv    pointer to wlan_private
  *  @param resp    pointer to command response buffer
@@ -619,13 +575,13 @@
 
 	lbs_deb_enter(LBS_DEB_11D);
 
-	lbs_dbg_hex("11D DOMAIN Info Rsp Data:", (u8 *) resp,
+	lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
 		(int)le16_to_cpu(resp->size));
 
 	nr_subband = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
 		      sizeof(struct ieeetypes_subbandset);
 
-	lbs_deb_11d("11D Domain Info Resp: nr_subband=%d\n", nr_subband);
+	lbs_deb_11d("domain info resp: nr_subband %d\n", nr_subband);
 
 	if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) {
 		lbs_deb_11d("Invalid Numrer of Subband returned!!\n");
@@ -633,10 +589,10 @@
 	}
 
 	switch (action) {
-	case cmd_act_set:	/*Proc Set action */
+	case CMD_ACT_SET:	/*Proc Set action */
 		break;
 
-	case cmd_act_get:
+	case CMD_ACT_GET:
 		break;
 	default:
 		lbs_deb_11d("Invalid action:%d\n", domaininfo->action);
@@ -667,7 +623,7 @@
 					       &adapter->parsed_region_chan);
 
 		if (ret == -1) {
-			lbs_deb_11d("11D: Err Parse domain_info from AP..\n");
+			lbs_deb_11d("error parsing domain_info from AP\n");
 			goto done;
 		}
 
@@ -679,7 +635,7 @@
 		ret = set_domain_info_11d(priv);
 
 		if (ret) {
-			lbs_deb_11d("11D: Err set domainInfo to FW\n");
+			lbs_deb_11d("error setting domain info\n");
 			goto done;
 		}
 	}
@@ -703,7 +659,7 @@
 	u8 j;
 
 	lbs_deb_enter(LBS_DEB_11D);
-	lbs_deb_11d("11D:curbssparams.band[%d]\n", adapter->curbssparams.band);
+	lbs_deb_11d("curbssparams.band %d\n", adapter->curbssparams.band);
 
 	if (priv->adapter->enable11d) {
 		/* update parsed_region_chan_11; dnld domaininf to FW */
@@ -712,7 +668,7 @@
 		     sizeof(adapter->region_channel[0]); j++) {
 			region_chan = &adapter->region_channel[j];
 
-			lbs_deb_11d("11D:[%d] region_chan->band[%d]\n", j,
+			lbs_deb_11d("%d region_chan->band %d\n", j,
 			       region_chan->band);
 
 			if (!region_chan || !region_chan->valid
@@ -725,7 +681,7 @@
 
 		if (j >= sizeof(adapter->region_channel) /
 		    sizeof(adapter->region_channel[0])) {
-			lbs_deb_11d("11D:region_chan not found. band[%d]\n",
+			lbs_deb_11d("region_chan not found, band %d\n",
 			       adapter->curbssparams.band);
 			ret = -1;
 			goto done;
@@ -745,7 +701,7 @@
 		ret = set_domain_info_11d(priv);
 
 		if (ret) {
-			lbs_deb_11d("11D: Err set domainInfo to FW\n");
+			lbs_deb_11d("error setting domain info\n");
 			goto done;
 		}
 
diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h
index 73e42e7..3a6d1f8 100644
--- a/drivers/net/wireless/libertas/11d.h
+++ b/drivers/net/wireless/libertas/11d.h
@@ -83,8 +83,6 @@
 
 u32 libertas_chan_2_freq(u8 chan, u8 band);
 
-enum state_11d libertas_get_state_11d(wlan_private * priv);
-
 void libertas_init_11d(wlan_private * priv);
 
 int libertas_set_universaltable(wlan_private * priv, u8 band);
@@ -93,8 +91,6 @@
 				 struct cmd_ds_command *cmd, u16 cmdno,
 				 u16 cmdOption);
 
-int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq);
-
 int libertas_ret_802_11d_domain_info(wlan_private * priv,
 				 struct cmd_ds_command *resp);
 
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
index 32ed413..c469d56 100644
--- a/drivers/net/wireless/libertas/Makefile
+++ b/drivers/net/wireless/libertas/Makefile
@@ -1,12 +1,13 @@
-libertas-objs := main.o fw.o wext.o \
+libertas-objs := main.o wext.o \
 		rx.o tx.o cmd.o 	  \
 		cmdresp.o scan.o	  \
 		join.o 11d.o 		  \
 		debugfs.o	  \
 		ethtool.o assoc.o
 
-usb8xxx-objs += if_bootcmd.o
 usb8xxx-objs += if_usb.o
+libertas_cs-objs += if_cs.o
 
 obj-$(CONFIG_LIBERTAS)     += libertas.o
 obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o
+obj-$(CONFIG_LIBERTAS_CS)  += libertas_cs.o
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index afd5617..b61b176 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -16,6 +16,7 @@
 
 static void print_assoc_req(const char * extra, struct assoc_request * assoc_req)
 {
+	DECLARE_MAC_BUF(mac);
 	lbs_deb_assoc(
 	       "#### Association Request: %s\n"
 	       "       flags:      0x%08lX\n"
@@ -23,13 +24,13 @@
 	       "       channel:    %d\n"
 	       "       band:       %d\n"
 	       "       mode:       %d\n"
-	       "       BSSID:      " MAC_FMT "\n"
+	       "       BSSID:      %s\n"
 	       "       Encryption:%s%s%s\n"
 	       "       auth:       %d\n",
 	       extra, assoc_req->flags,
 	       escape_essid(assoc_req->ssid, assoc_req->ssid_len),
 	       assoc_req->channel, assoc_req->band, assoc_req->mode,
-	       MAC_ARG(assoc_req->bssid),
+	       print_mac(mac, assoc_req->bssid),
 	       assoc_req->secinfo.WPAenabled ? " WPA" : "",
 	       assoc_req->secinfo.WPA2enabled ? " WPA2" : "",
 	       assoc_req->secinfo.wep_enabled ? " WEP" : "",
@@ -57,10 +58,8 @@
 	lbs_deb_assoc("New SSID requested: '%s'\n",
 	              escape_essid(assoc_req->ssid, assoc_req->ssid_len));
 	if (assoc_req->mode == IW_MODE_INFRA) {
-		if (adapter->prescan) {
-			libertas_send_specific_ssid_scan(priv, assoc_req->ssid,
-				assoc_req->ssid_len, 0);
-		}
+		libertas_send_specific_ssid_scan(priv, assoc_req->ssid,
+			assoc_req->ssid_len, 0);
 
 		bss = libertas_find_ssid_in_list(adapter, assoc_req->ssid,
 				assoc_req->ssid_len, NULL, IW_MODE_INFRA, channel);
@@ -106,16 +105,17 @@
 	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
 	struct bss_descriptor * bss;
+	DECLARE_MAC_BUF(mac);
 
-	lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID " MAC_FMT,
-		MAC_ARG(assoc_req->bssid));
+	lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %s",
+		print_mac(mac, assoc_req->bssid));
 
 	/* Search for index position in list for requested MAC */
 	bss = libertas_find_bssid_in_list(adapter, assoc_req->bssid,
 			    assoc_req->mode);
 	if (bss == NULL) {
-		lbs_deb_assoc("ASSOC: WAP: BSSID " MAC_FMT " not found, "
-			"cannot associate.\n", MAC_ARG(assoc_req->bssid));
+		lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, "
+			"cannot associate.\n", print_mac(mac, assoc_req->bssid));
 		goto out;
 	}
 
@@ -175,14 +175,14 @@
 
 	if (assoc_req->mode == IW_MODE_INFRA) {
 		if (adapter->psstate != PS_STATE_FULL_POWER)
-			libertas_ps_wakeup(priv, cmd_option_waitforrsp);
-		adapter->psmode = wlan802_11powermodecam;
+			libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
+		adapter->psmode = WLAN802_11POWERMODECAM;
 	}
 
 	adapter->mode = assoc_req->mode;
 	ret = libertas_prepare_and_send_command(priv,
-				    cmd_802_11_snmp_mib,
-				    0, cmd_option_waitforrsp,
+				    CMD_802_11_SNMP_MIB,
+				    0, CMD_OPTION_WAITFORRSP,
 				    OID_802_11_INFRASTRUCTURE_MODE,
 		/* Shoot me now */  (void *) (size_t) assoc_req->mode);
 
@@ -195,9 +195,9 @@
 static int update_channel(wlan_private * priv)
 {
 	/* the channel in f/w could be out of sync, get the current channel */
-	return libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
-				    cmd_opt_802_11_rf_channel_get,
-				    cmd_option_waitforrsp, 0, NULL);
+	return libertas_prepare_and_send_command(priv, CMD_802_11_RF_CHANNEL,
+				    CMD_OPT_802_11_RF_CHANNEL_GET,
+				    CMD_OPTION_WAITFORRSP, 0, NULL);
 }
 
 void libertas_sync_channel(struct work_struct *work)
@@ -227,9 +227,9 @@
 	lbs_deb_assoc("ASSOC: channel: %d -> %d\n",
 	       adapter->curbssparams.channel, assoc_req->channel);
 
-	ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel,
-				cmd_opt_802_11_rf_channel_set,
-				cmd_option_waitforrsp, 0, &assoc_req->channel);
+	ret = libertas_prepare_and_send_command(priv, CMD_802_11_RF_CHANNEL,
+				CMD_OPT_802_11_RF_CHANNEL_SET,
+				CMD_OPTION_WAITFORRSP, 0, &assoc_req->channel);
 	if (ret < 0) {
 		lbs_deb_assoc("ASSOC: channel: error setting channel.");
 	}
@@ -278,15 +278,15 @@
 	    || assoc_req->wep_keys[2].len
 	    || assoc_req->wep_keys[3].len) {
 		ret = libertas_prepare_and_send_command(priv,
-					    cmd_802_11_set_wep,
-					    cmd_act_add,
-					    cmd_option_waitforrsp,
+					    CMD_802_11_SET_WEP,
+					    CMD_ACT_ADD,
+					    CMD_OPTION_WAITFORRSP,
 					    0, assoc_req);
 	} else {
 		ret = libertas_prepare_and_send_command(priv,
-					    cmd_802_11_set_wep,
-					    cmd_act_remove,
-					    cmd_option_waitforrsp,
+					    CMD_802_11_SET_WEP,
+					    CMD_ACT_REMOVE,
+					    CMD_OPTION_WAITFORRSP,
 					    0, NULL);
 	}
 
@@ -295,9 +295,9 @@
 
 	/* enable/disable the MAC's WEP packet filter */
 	if (assoc_req->secinfo.wep_enabled)
-		adapter->currentpacketfilter |= cmd_act_mac_wep_enable;
+		adapter->currentpacketfilter |= CMD_ACT_MAC_WEP_ENABLE;
 	else
-		adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable;
+		adapter->currentpacketfilter &= ~CMD_ACT_MAC_WEP_ENABLE;
 	ret = libertas_set_mac_packet_filter(priv);
 	if (ret)
 		goto out;
@@ -307,7 +307,7 @@
 	/* Copy WEP keys into adapter wep key fields */
 	for (i = 0; i < 4; i++) {
 		memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i],
-			sizeof(struct WLAN_802_11_KEY));
+			sizeof(struct enc_key));
 	}
 	adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx;
 
@@ -342,9 +342,9 @@
 
 	/* Get RSN enabled/disabled */
 	ret = libertas_prepare_and_send_command(priv,
-				    cmd_802_11_enable_rsn,
-				    cmd_act_set,
-				    cmd_option_waitforrsp,
+				    CMD_802_11_ENABLE_RSN,
+				    CMD_ACT_GET,
+				    CMD_OPTION_WAITFORRSP,
 				    0, &rsn);
 	if (ret) {
 		lbs_deb_assoc("Failed to get RSN status: %d", ret);
@@ -359,9 +359,9 @@
 	/* Set RSN enabled/disabled */
 	rsn = do_wpa;
 	ret = libertas_prepare_and_send_command(priv,
-				    cmd_802_11_enable_rsn,
-				    cmd_act_set,
-				    cmd_option_waitforrsp,
+				    CMD_802_11_ENABLE_RSN,
+				    CMD_ACT_SET,
+				    CMD_OPTION_WAITFORRSP,
 				    0, &rsn);
 
 out:
@@ -374,15 +374,40 @@
                                  struct assoc_request * assoc_req)
 {
 	int ret = 0;
+	unsigned int flags = assoc_req->flags;
 
 	lbs_deb_enter(LBS_DEB_ASSOC);
 
-	ret = libertas_prepare_and_send_command(priv,
-				    cmd_802_11_key_material,
-				    cmd_act_set,
-				    cmd_option_waitforrsp,
-				    0, assoc_req);
+	/* Work around older firmware bug where WPA unicast and multicast
+	 * keys must be set independently.  Seen in SDIO parts with firmware
+	 * version 5.0.11p0.
+	 */
 
+	if (test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
+		clear_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
+		ret = libertas_prepare_and_send_command(priv,
+					CMD_802_11_KEY_MATERIAL,
+					CMD_ACT_SET,
+					CMD_OPTION_WAITFORRSP,
+					0, assoc_req);
+		assoc_req->flags = flags;
+	}
+
+	if (ret)
+		goto out;
+
+	if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
+		clear_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
+
+		ret = libertas_prepare_and_send_command(priv,
+					CMD_802_11_KEY_MATERIAL,
+					CMD_ACT_SET,
+					CMD_OPTION_WAITFORRSP,
+					0, assoc_req);
+		assoc_req->flags = flags;
+	}
+
+out:
 	lbs_deb_leave_args(LBS_DEB_ASSOC, "ret %d", ret);
 	return ret;
 }
@@ -412,7 +437,7 @@
 static int should_deauth_infrastructure(wlan_adapter *adapter,
                                         struct assoc_request * assoc_req)
 {
-	if (adapter->connect_status != libertas_connected)
+	if (adapter->connect_status != LIBERTAS_CONNECTED)
 		return 0;
 
 	if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) {
@@ -453,7 +478,7 @@
 static int should_stop_adhoc(wlan_adapter *adapter,
                              struct assoc_request * assoc_req)
 {
-	if (adapter->connect_status != libertas_connected)
+	if (adapter->connect_status != LIBERTAS_CONNECTED)
 		return 0;
 
 	if (libertas_ssid_cmp(adapter->curbssparams.ssid,
@@ -483,6 +508,7 @@
 	struct assoc_request * assoc_req = NULL;
 	int ret = 0;
 	int find_any_ssid = 0;
+	DECLARE_MAC_BUF(mac);
 
 	lbs_deb_enter(LBS_DEB_ASSOC);
 
@@ -556,7 +582,8 @@
 	if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) {
 		ret = assoc_helper_mode(priv, assoc_req);
 		if (ret) {
-lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n", __LINE__, ret);
+			lbs_deb_assoc("ASSOC(:%d) mode: ret = %d\n",
+			              __LINE__, ret);
 			goto out;
 		}
 	}
@@ -574,7 +601,8 @@
 	    || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) {
 		ret = assoc_helper_wep_keys(priv, assoc_req);
 		if (ret) {
-lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret);
+			lbs_deb_assoc("ASSOC(:%d) wep_keys: ret = %d\n",
+			              __LINE__, ret);
 			goto out;
 		}
 	}
@@ -582,7 +610,8 @@
 	if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
 		ret = assoc_helper_secinfo(priv, assoc_req);
 		if (ret) {
-lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret);
+			lbs_deb_assoc("ASSOC(:%d) secinfo: ret = %d\n",
+			              __LINE__, ret);
 			goto out;
 		}
 	}
@@ -590,7 +619,8 @@
 	if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) {
 		ret = assoc_helper_wpa_ie(priv, assoc_req);
 		if (ret) {
-lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret);
+			lbs_deb_assoc("ASSOC(:%d) wpa_ie: ret = %d\n",
+			              __LINE__, ret);
 			goto out;
 		}
 	}
@@ -599,7 +629,8 @@
 	    || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
 		ret = assoc_helper_wpa_keys(priv, assoc_req);
 		if (ret) {
-lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret);
+			lbs_deb_assoc("ASSOC(:%d) wpa_keys: ret = %d\n",
+			              __LINE__, ret);
 			goto out;
 		}
 	}
@@ -618,25 +649,25 @@
 			success = 0;
 		}
 
-		if (adapter->connect_status != libertas_connected) {
-			lbs_deb_assoc("ASSOC: assoication attempt unsuccessful, "
+		if (adapter->connect_status != LIBERTAS_CONNECTED) {
+			lbs_deb_assoc("ASSOC: association attempt unsuccessful, "
 				"not connected.\n");
 			success = 0;
 		}
 
 		if (success) {
 			lbs_deb_assoc("ASSOC: association attempt successful. "
-				"Associated to '%s' (" MAC_FMT ")\n",
+				"Associated to '%s' (%s)\n",
 				escape_essid(adapter->curbssparams.ssid,
 				             adapter->curbssparams.ssid_len),
-				MAC_ARG(adapter->curbssparams.bssid));
+				print_mac(mac, adapter->curbssparams.bssid));
 			libertas_prepare_and_send_command(priv,
-				cmd_802_11_rssi,
-				0, cmd_option_waitforrsp, 0, NULL);
+				CMD_802_11_RSSI,
+				0, CMD_OPTION_WAITFORRSP, 0, NULL);
 
 			libertas_prepare_and_send_command(priv,
-				cmd_802_11_get_log,
-				0, cmd_option_waitforrsp, 0, NULL);
+				CMD_802_11_GET_LOG,
+				0, CMD_OPTION_WAITFORRSP, 0, NULL);
 		} else {
 			ret = -1;
 		}
@@ -703,7 +734,7 @@
 		int i;
 		for (i = 0; i < 4; i++) {
 			memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i],
-				sizeof(struct WLAN_802_11_KEY));
+				sizeof(struct enc_key));
 		}
 	}
 
@@ -712,12 +743,12 @@
 
 	if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) {
 		memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key,
-			sizeof(struct WLAN_802_11_KEY));
+			sizeof(struct enc_key));
 	}
 
 	if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) {
 		memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key,
-			sizeof(struct WLAN_802_11_KEY));
+			sizeof(struct enc_key));
 	}
 
 	if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) {
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h
index 5e9c31f..e09b749 100644
--- a/drivers/net/wireless/libertas/assoc.h
+++ b/drivers/net/wireless/libertas/assoc.h
@@ -17,7 +17,7 @@
 	if (priv->adapter->surpriseremoved)
 		return;
 	cancel_delayed_work(&priv->assoc_work);
-	queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY);
+	queue_delayed_work(priv->work_thread, &priv->assoc_work, ASSOC_DELAY);
 }
 
 static inline void wlan_cancel_association_work(wlan_private *priv)
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 4a8f5dc..1cbbd96 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -15,7 +15,7 @@
 static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode);
 
 static u16 commands_allowed_in_ps[] = {
-	cmd_802_11_rssi,
+	CMD_802_11_RSSI,
 };
 
 /**
@@ -43,7 +43,7 @@
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	cmd->command = cpu_to_le16(cmd_get_hw_spec);
+	cmd->command = cpu_to_le16(CMD_GET_HW_SPEC);
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN);
 	memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN);
 
@@ -56,34 +56,29 @@
 				   u16 cmd_action)
 {
 	struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode;
-	wlan_adapter *adapter = priv->adapter;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	cmd->command = cpu_to_le16(cmd_802_11_ps_mode);
+	cmd->command = cpu_to_le16(CMD_802_11_PS_MODE);
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) +
 				S_DS_GEN);
 	psm->action = cpu_to_le16(cmd_action);
 	psm->multipledtim = 0;
 	switch (cmd_action) {
-	case cmd_subcmd_enter_ps:
+	case CMD_SUBCMD_ENTER_PS:
 		lbs_deb_cmd("PS command:" "SubCode- Enter PS\n");
-		lbs_deb_cmd("locallisteninterval = %d\n",
-		       adapter->locallisteninterval);
 
-		psm->locallisteninterval =
-		    cpu_to_le16(adapter->locallisteninterval);
-		psm->nullpktinterval =
-		    cpu_to_le16(adapter->nullpktinterval);
+		psm->locallisteninterval = 0;
+		psm->nullpktinterval = 0;
 		psm->multipledtim =
-		    cpu_to_le16(priv->adapter->multipledtim);
+		    cpu_to_le16(MRVDRV_DEFAULT_MULTIPLE_DTIM);
 		break;
 
-	case cmd_subcmd_exit_ps:
+	case CMD_SUBCMD_EXIT_PS:
 		lbs_deb_cmd("PS command:" "SubCode- Exit PS\n");
 		break;
 
-	case cmd_subcmd_sleep_confirmed:
+	case CMD_SUBCMD_SLEEP_CONFIRMED:
 		lbs_deb_cmd("PS command: SubCode- sleep confirm\n");
 		break;
 
@@ -101,7 +96,9 @@
 {
 	u16 *timeout = pdata_buf;
 
-	cmd->command = cpu_to_le16(cmd_802_11_inactivity_timeout);
+	lbs_deb_enter(LBS_DEB_CMD);
+
+	cmd->command = cpu_to_le16(CMD_802_11_INACTIVITY_TIMEOUT);
 	cmd->size =
 	    cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout)
 			     + S_DS_GEN);
@@ -113,6 +110,7 @@
 	else
 		cmd->params.inactivity_timeout.timeout = 0;
 
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
@@ -127,13 +125,13 @@
 
 	cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) +
 				S_DS_GEN);
-	cmd->command = cpu_to_le16(cmd_802_11_sleep_params);
+	cmd->command = cpu_to_le16(CMD_802_11_SLEEP_PARAMS);
 
-	if (cmd_action == cmd_act_get) {
+	if (cmd_action == CMD_ACT_GET) {
 		memset(&adapter->sp, 0, sizeof(struct sleep_params));
 		memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params));
 		sp->action = cpu_to_le16(cmd_action);
-	} else if (cmd_action == cmd_act_set) {
+	} else if (cmd_action == CMD_ACT_SET) {
 		sp->action = cpu_to_le16(cmd_action);
 		sp->error = cpu_to_le16(adapter->sp.sp_error);
 		sp->offset = cpu_to_le16(adapter->sp.sp_offset);
@@ -159,10 +157,10 @@
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	cmd->command = cpu_to_le16(cmd_802_11_set_wep);
+	cmd->command = cpu_to_le16(CMD_802_11_SET_WEP);
 	cmd->size = cpu_to_le16(sizeof(*wep) + S_DS_GEN);
 
-	if (cmd_act == cmd_act_add) {
+	if (cmd_act == CMD_ACT_ADD) {
 		int i;
 
 		if (!assoc_req) {
@@ -171,48 +169,47 @@
 			goto done;
 		}
 
-		wep->action = cpu_to_le16(cmd_act_add);
+		wep->action = cpu_to_le16(CMD_ACT_ADD);
 
 		/* default tx key index */
 		wep->keyindex = cpu_to_le16((u16)(assoc_req->wep_tx_keyidx &
-						  (u32)cmd_WEP_KEY_INDEX_MASK));
-
-		lbs_deb_cmd("Tx key Index: %u\n", le16_to_cpu(wep->keyindex));
+						  (u32)CMD_WEP_KEY_INDEX_MASK));
 
 		/* Copy key types and material to host command structure */
 		for (i = 0; i < 4; i++) {
-			struct WLAN_802_11_KEY * pkey = &assoc_req->wep_keys[i];
+			struct enc_key * pkey = &assoc_req->wep_keys[i];
 
 			switch (pkey->len) {
 			case KEY_LEN_WEP_40:
-				wep->keytype[i] =
-					cpu_to_le16(cmd_type_wep_40_bit);
+				wep->keytype[i] = CMD_TYPE_WEP_40_BIT;
 				memmove(&wep->keymaterial[i], pkey->key,
 				        pkey->len);
+				lbs_deb_cmd("SET_WEP: add key %d (40 bit)\n", i);
 				break;
 			case KEY_LEN_WEP_104:
-				wep->keytype[i] =
-					cpu_to_le16(cmd_type_wep_104_bit);
+				wep->keytype[i] = CMD_TYPE_WEP_104_BIT;
 				memmove(&wep->keymaterial[i], pkey->key,
 				        pkey->len);
+				lbs_deb_cmd("SET_WEP: add key %d (104 bit)\n", i);
 				break;
 			case 0:
 				break;
 			default:
-				lbs_deb_cmd("Invalid WEP key %d length of %d\n",
+				lbs_deb_cmd("SET_WEP: invalid key %d, length %d\n",
 				       i, pkey->len);
 				ret = -1;
 				goto done;
 				break;
 			}
 		}
-	} else if (cmd_act == cmd_act_remove) {
+	} else if (cmd_act == CMD_ACT_REMOVE) {
 		/* ACT_REMOVE clears _all_ WEP keys */
-		wep->action = cpu_to_le16(cmd_act_remove);
+		wep->action = cpu_to_le16(CMD_ACT_REMOVE);
 
 		/* default tx key index */
 		wep->keyindex = cpu_to_le16((u16)(adapter->wep_tx_keyidx &
-						  (u32)cmd_WEP_KEY_INDEX_MASK));
+						  (u32)CMD_WEP_KEY_INDEX_MASK));
+		lbs_deb_cmd("SET_WEP: remove key %d\n", adapter->wep_tx_keyidx);
 	}
 
 	ret = 0;
@@ -232,15 +229,16 @@
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	cmd->command = cpu_to_le16(cmd_802_11_enable_rsn);
+	cmd->command = cpu_to_le16(CMD_802_11_ENABLE_RSN);
 	cmd->size = cpu_to_le16(sizeof(*penableRSN) + S_DS_GEN);
 	penableRSN->action = cpu_to_le16(cmd_action);
 
-	if (cmd_action == cmd_act_set) {
+	if (cmd_action == CMD_ACT_SET) {
 		if (*enable)
-			penableRSN->enable = cpu_to_le16(cmd_enable_rsn);
+			penableRSN->enable = cpu_to_le16(CMD_ENABLE_RSN);
 		else
-			penableRSN->enable = cpu_to_le16(cmd_disable_rsn);
+			penableRSN->enable = cpu_to_le16(CMD_DISABLE_RSN);
+		lbs_deb_cmd("ENABLE_RSN: %d\n", *enable);
 	}
 
 	lbs_deb_leave(LBS_DEB_CMD);
@@ -249,9 +247,9 @@
 
 
 static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset,
-                            struct WLAN_802_11_KEY * pkey)
+                            struct enc_key * pkey)
 {
-	pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
+	lbs_deb_enter(LBS_DEB_CMD);
 
 	if (pkey->flags & KEY_INFO_WPA_ENABLED) {
 		pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_ENABLED);
@@ -264,12 +262,14 @@
 	}
 
 	pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+	pkeyparamset->keytypeid = cpu_to_le16(pkey->type);
 	pkeyparamset->keylen = cpu_to_le16(pkey->len);
 	memcpy(pkeyparamset->key, pkey->key, pkey->len);
 	pkeyparamset->length = cpu_to_le16(  sizeof(pkeyparamset->keytypeid)
 	                                        + sizeof(pkeyparamset->keyinfo)
 	                                        + sizeof(pkeyparamset->keylen)
 	                                        + sizeof(pkeyparamset->key));
+	lbs_deb_leave(LBS_DEB_CMD);
 }
 
 static int wlan_cmd_802_11_key_material(wlan_private * priv,
@@ -285,10 +285,10 @@
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	cmd->command = cpu_to_le16(cmd_802_11_key_material);
+	cmd->command = cpu_to_le16(CMD_802_11_KEY_MATERIAL);
 	pkeymaterial->action = cpu_to_le16(cmd_action);
 
-	if (cmd_action == cmd_act_get) {
+	if (cmd_action == CMD_ACT_GET) {
 		cmd->size = cpu_to_le16(S_DS_GEN + sizeof (pkeymaterial->action));
 		ret = 0;
 		goto done;
@@ -324,30 +324,37 @@
 {
 	struct cmd_ds_802_11_reset *reset = &cmd->params.reset;
 
-	cmd->command = cpu_to_le16(cmd_802_11_reset);
+	lbs_deb_enter(LBS_DEB_CMD);
+
+	cmd->command = cpu_to_le16(CMD_802_11_RESET);
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN);
 	reset->action = cpu_to_le16(cmd_action);
 
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
 static int wlan_cmd_802_11_get_log(wlan_private * priv,
 				   struct cmd_ds_command *cmd)
 {
-	cmd->command = cpu_to_le16(cmd_802_11_get_log);
+	lbs_deb_enter(LBS_DEB_CMD);
+	cmd->command = cpu_to_le16(CMD_802_11_GET_LOG);
 	cmd->size =
 		cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN);
 
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
 static int wlan_cmd_802_11_get_stat(wlan_private * priv,
 				    struct cmd_ds_command *cmd)
 {
-	cmd->command = cpu_to_le16(cmd_802_11_get_stat);
+	lbs_deb_enter(LBS_DEB_CMD);
+	cmd->command = cpu_to_le16(CMD_802_11_GET_STAT);
 	cmd->size =
 	    cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + S_DS_GEN);
 
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
@@ -364,15 +371,15 @@
 
 	lbs_deb_cmd("SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
 
-	cmd->command = cpu_to_le16(cmd_802_11_snmp_mib);
+	cmd->command = cpu_to_le16(CMD_802_11_SNMP_MIB);
 	cmd->size = cpu_to_le16(sizeof(*pSNMPMIB) + S_DS_GEN);
 
 	switch (cmd_oid) {
 	case OID_802_11_INFRASTRUCTURE_MODE:
 	{
 		u8 mode = (u8) (size_t) pdata_buf;
-		pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
-		pSNMPMIB->oid = cpu_to_le16((u16) desired_bsstype_i);
+		pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
+		pSNMPMIB->oid = cpu_to_le16((u16) DESIRED_BSSTYPE_I);
 		pSNMPMIB->bufsize = sizeof(u8);
 		if (mode == IW_MODE_ADHOC) {
 			ucTemp = SNMP_MIB_VALUE_ADHOC;
@@ -390,10 +397,10 @@
 		{
 			u32 ulTemp;
 
-			pSNMPMIB->oid = cpu_to_le16((u16) dot11d_i);
+			pSNMPMIB->oid = cpu_to_le16((u16) DOT11D_I);
 
-			if (cmd_action == cmd_act_set) {
-				pSNMPMIB->querytype = cmd_act_set;
+			if (cmd_action == CMD_ACT_SET) {
+				pSNMPMIB->querytype = CMD_ACT_SET;
 				pSNMPMIB->bufsize = sizeof(u16);
 				ulTemp = *(u32 *)pdata_buf;
 				*((__le16 *)(pSNMPMIB->value)) =
@@ -406,12 +413,12 @@
 		{
 			u32 ulTemp;
 
-			pSNMPMIB->oid = cpu_to_le16((u16) fragthresh_i);
+			pSNMPMIB->oid = cpu_to_le16((u16) FRAGTHRESH_I);
 
-			if (cmd_action == cmd_act_get) {
-				pSNMPMIB->querytype = cpu_to_le16(cmd_act_get);
-			} else if (cmd_action == cmd_act_set) {
-				pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
+			if (cmd_action == CMD_ACT_GET) {
+				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
+			} else if (cmd_action == CMD_ACT_SET) {
+				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
 				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
 				ulTemp = *((u32 *) pdata_buf);
 				*((__le16 *)(pSNMPMIB->value)) =
@@ -426,12 +433,12 @@
 		{
 
 			u32 ulTemp;
-			pSNMPMIB->oid = le16_to_cpu((u16) rtsthresh_i);
+			pSNMPMIB->oid = le16_to_cpu((u16) RTSTHRESH_I);
 
-			if (cmd_action == cmd_act_get) {
-				pSNMPMIB->querytype = cpu_to_le16(cmd_act_get);
-			} else if (cmd_action == cmd_act_set) {
-				pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
+			if (cmd_action == CMD_ACT_GET) {
+				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
+			} else if (cmd_action == CMD_ACT_SET) {
+				pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
 				pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
 				ulTemp = *((u32 *)pdata_buf);
 				*(__le16 *)(pSNMPMIB->value) =
@@ -441,12 +448,12 @@
 			break;
 		}
 	case OID_802_11_TX_RETRYCOUNT:
-		pSNMPMIB->oid = cpu_to_le16((u16) short_retrylim_i);
+		pSNMPMIB->oid = cpu_to_le16((u16) SHORT_RETRYLIM_I);
 
-		if (cmd_action == cmd_act_get) {
-			pSNMPMIB->querytype = cpu_to_le16(cmd_act_get);
-		} else if (cmd_action == cmd_act_set) {
-			pSNMPMIB->querytype = cpu_to_le16(cmd_act_set);
+		if (cmd_action == CMD_ACT_GET) {
+			pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_GET);
+		} else if (cmd_action == CMD_ACT_SET) {
+			pSNMPMIB->querytype = cpu_to_le16(CMD_ACT_SET);
 			pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16));
 			*((__le16 *)(pSNMPMIB->value)) =
 			    cpu_to_le16((u16) adapter->txretrycount);
@@ -463,7 +470,7 @@
 	       le16_to_cpu(cmd->seqnum), le16_to_cpu(cmd->result));
 
 	lbs_deb_cmd(
-	       "SNMP_CMD: action=0x%x, oid=0x%x, oidsize=0x%x, value=0x%x\n",
+	       "SNMP_CMD: action 0x%x, oid 0x%x, oidsize 0x%x, value 0x%x\n",
 	       le16_to_cpu(pSNMPMIB->querytype), le16_to_cpu(pSNMPMIB->oid),
 	       le16_to_cpu(pSNMPMIB->bufsize),
 	       le16_to_cpu(*(__le16 *) pSNMPMIB->value));
@@ -484,20 +491,20 @@
 	cmd->size =
 	    cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) +
 			     S_DS_GEN);
-	cmd->command = cpu_to_le16(cmd_802_11_radio_control);
+	cmd->command = cpu_to_le16(CMD_802_11_RADIO_CONTROL);
 
 	pradiocontrol->action = cpu_to_le16(cmd_action);
 
 	switch (adapter->preamble) {
-	case cmd_type_short_preamble:
+	case CMD_TYPE_SHORT_PREAMBLE:
 		pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE);
 		break;
 
-	case cmd_type_long_preamble:
+	case CMD_TYPE_LONG_PREAMBLE:
 		pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE);
 		break;
 
-	case cmd_type_auto_preamble:
+	case CMD_TYPE_AUTO_PREAMBLE:
 	default:
 		pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE);
 		break;
@@ -523,7 +530,7 @@
 
 	cmd->size =
 	    cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + S_DS_GEN);
-	cmd->command = cpu_to_le16(cmd_802_11_rf_tx_power);
+	cmd->command = cpu_to_le16(CMD_802_11_RF_TX_POWER);
 	prtp->action = cpu_to_le16(cmd_action);
 
 	lbs_deb_cmd("RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n",
@@ -531,23 +538,23 @@
 		    le16_to_cpu(prtp->action));
 
 	switch (cmd_action) {
-	case cmd_act_tx_power_opt_get:
-		prtp->action = cpu_to_le16(cmd_act_get);
+	case CMD_ACT_TX_POWER_OPT_GET:
+		prtp->action = cpu_to_le16(CMD_ACT_GET);
 		prtp->currentlevel = 0;
 		break;
 
-	case cmd_act_tx_power_opt_set_high:
-		prtp->action = cpu_to_le16(cmd_act_set);
-		prtp->currentlevel = cpu_to_le16(cmd_act_tx_power_index_high);
+	case CMD_ACT_TX_POWER_OPT_SET_HIGH:
+		prtp->action = cpu_to_le16(CMD_ACT_SET);
+		prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_HIGH);
 		break;
 
-	case cmd_act_tx_power_opt_set_mid:
-		prtp->action = cpu_to_le16(cmd_act_set);
-		prtp->currentlevel = cpu_to_le16(cmd_act_tx_power_index_mid);
+	case CMD_ACT_TX_POWER_OPT_SET_MID:
+		prtp->action = cpu_to_le16(CMD_ACT_SET);
+		prtp->currentlevel = cpu_to_le16(CMD_ACT_TX_POWER_INDEX_MID);
 		break;
 
-	case cmd_act_tx_power_opt_set_low:
-		prtp->action = cpu_to_le16(cmd_act_set);
+	case CMD_ACT_TX_POWER_OPT_SET_LOW:
+		prtp->action = cpu_to_le16(CMD_ACT_SET);
 		prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf));
 		break;
 	}
@@ -556,19 +563,21 @@
 	return 0;
 }
 
-static int wlan_cmd_802_11_rf_antenna(wlan_private * priv,
+static int wlan_cmd_802_11_monitor_mode(wlan_private * priv,
 				      struct cmd_ds_command *cmd,
 				      u16 cmd_action, void *pdata_buf)
 {
-	struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant;
+	struct cmd_ds_802_11_monitor_mode *monitor = &cmd->params.monitor;
 
-	cmd->command = cpu_to_le16(cmd_802_11_rf_antenna);
-	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) +
-				S_DS_GEN);
+	cmd->command = cpu_to_le16(CMD_802_11_MONITOR_MODE);
+	cmd->size =
+	    cpu_to_le16(sizeof(struct cmd_ds_802_11_monitor_mode) +
+			     S_DS_GEN);
 
-	rant->action = cpu_to_le16(cmd_action);
-	if ((cmd_action == cmd_act_set_rx) || (cmd_action == cmd_act_set_tx)) {
-		rant->antennamode = cpu_to_le16((u16) (*(u32 *) pdata_buf));
+	monitor->action = cpu_to_le16(cmd_action);
+	if (cmd_action == CMD_ACT_SET) {
+		monitor->mode =
+		    cpu_to_le16((u16) (*(u32 *) pdata_buf));
 	}
 
 	return 0;
@@ -582,12 +591,11 @@
 	*rateadapt = &cmd->params.rateset;
 	wlan_adapter *adapter = priv->adapter;
 
+	lbs_deb_enter(LBS_DEB_CMD);
 	cmd->size =
 	    cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset)
 			     + S_DS_GEN);
-	cmd->command = cpu_to_le16(cmd_802_11_rate_adapt_rateset);
-
-	lbs_deb_enter(LBS_DEB_CMD);
+	cmd->command = cpu_to_le16(CMD_802_11_RATE_ADAPT_RATESET);
 
 	rateadapt->action = cpu_to_le16(cmd_action);
 	rateadapt->enablehwauto = cpu_to_le16(adapter->enablehwauto);
@@ -608,19 +616,16 @@
 
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) +
 			     S_DS_GEN);
-
-	cmd->command = cpu_to_le16(cmd_802_11_data_rate);
-
+	cmd->command = cpu_to_le16(CMD_802_11_DATA_RATE);
 	memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate));
-
 	pdatarate->action = cpu_to_le16(cmd_action);
 
-	if (cmd_action == cmd_act_set_tx_fix_rate) {
-		pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate);
-		lbs_deb_cmd("Setting FW for fixed rate 0x%02X\n",
-		       adapter->datarate);
-	} else if (cmd_action == cmd_act_set_tx_auto) {
-		lbs_deb_cmd("Setting FW for AUTO rate\n");
+	if (cmd_action == CMD_ACT_SET_TX_FIX_RATE) {
+		pdatarate->rates[0] = libertas_data_rate_to_fw_index(adapter->cur_rate);
+		lbs_deb_cmd("DATA_RATE: set fixed 0x%02X\n",
+		       adapter->cur_rate);
+	} else if (cmd_action == CMD_ACT_SET_TX_AUTO) {
+		lbs_deb_cmd("DATA_RATE: setting auto\n");
 	}
 
 	lbs_deb_leave(LBS_DEB_CMD);
@@ -634,16 +639,19 @@
 	struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr;
 	wlan_adapter *adapter = priv->adapter;
 
+	lbs_deb_enter(LBS_DEB_CMD);
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) +
 			     S_DS_GEN);
-	cmd->command = cpu_to_le16(cmd_mac_multicast_adr);
+	cmd->command = cpu_to_le16(CMD_MAC_MULTICAST_ADR);
 
+	lbs_deb_cmd("MULTICAST_ADR: setting %d addresses\n", pMCastAdr->nr_of_adrs);
 	pMCastAdr->action = cpu_to_le16(cmd_action);
 	pMCastAdr->nr_of_adrs =
 	    cpu_to_le16((u16) adapter->nr_of_multicastmacaddr);
 	memcpy(pMCastAdr->maclist, adapter->multicastlist,
 	       adapter->nr_of_multicastmacaddr * ETH_ALEN);
 
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
@@ -653,16 +661,18 @@
 {
 	struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel;
 
-	cmd->command = cpu_to_le16(cmd_802_11_rf_channel);
+	lbs_deb_enter(LBS_DEB_CMD);
+	cmd->command = cpu_to_le16(CMD_802_11_RF_CHANNEL);
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) +
 				S_DS_GEN);
 
-	if (option == cmd_opt_802_11_rf_channel_set) {
+	if (option == CMD_OPT_802_11_RF_CHANNEL_SET) {
 		rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf));
 	}
 
 	rfchan->action = cpu_to_le16(option);
 
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
@@ -671,9 +681,10 @@
 {
 	wlan_adapter *adapter = priv->adapter;
 
-	cmd->command = cpu_to_le16(cmd_802_11_rssi);
+	lbs_deb_enter(LBS_DEB_CMD);
+	cmd->command = cpu_to_le16(CMD_802_11_RSSI);
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN);
-	cmd->params.rssi.N = cpu_to_le16(priv->adapter->bcn_avg_factor);
+	cmd->params.rssi.N = cpu_to_le16(DEFAULT_BCN_AVG_FACTOR);
 
 	/* reset Beacon SNR/NF/RSSI values */
 	adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0;
@@ -683,6 +694,7 @@
 	adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0;
 	adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0;
 
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
@@ -697,7 +709,7 @@
 	offval = (struct wlan_offset_value *)pdata_buf;
 
 	switch (cmdptr->command) {
-	case cmd_mac_reg_access:
+	case CMD_MAC_REG_ACCESS:
 		{
 			struct cmd_ds_mac_reg_access *macreg;
 
@@ -715,7 +727,7 @@
 			break;
 		}
 
-	case cmd_bbp_reg_access:
+	case CMD_BBP_REG_ACCESS:
 		{
 			struct cmd_ds_bbp_reg_access *bbpreg;
 
@@ -734,7 +746,7 @@
 			break;
 		}
 
-	case cmd_rf_reg_access:
+	case CMD_RF_REG_ACCESS:
 		{
 			struct cmd_ds_rf_reg_access *rfreg;
 
@@ -767,19 +779,21 @@
 {
 	wlan_adapter *adapter = priv->adapter;
 
-	cmd->command = cpu_to_le16(cmd_802_11_mac_address);
+	lbs_deb_enter(LBS_DEB_CMD);
+	cmd->command = cpu_to_le16(CMD_802_11_MAC_ADDRESS);
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) +
 			     S_DS_GEN);
 	cmd->result = 0;
 
 	cmd->params.macadd.action = cpu_to_le16(cmd_action);
 
-	if (cmd_action == cmd_act_set) {
+	if (cmd_action == CMD_ACT_SET) {
 		memcpy(cmd->params.macadd.macadd,
 		       adapter->current_addr, ETH_ALEN);
-		lbs_dbg_hex("SET_CMD: MAC ADDRESS-", adapter->current_addr, 6);
+		lbs_deb_hex(LBS_DEB_CMD, "SET_CMD: MAC addr", adapter->current_addr, 6);
 	}
 
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
@@ -791,7 +805,7 @@
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	cmd->command = cpu_to_le16(cmd_802_11_eeprom_access);
+	cmd->command = cpu_to_le16(CMD_802_11_EEPROM_ACCESS);
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) +
 				S_DS_GEN);
 	cmd->result = 0;
@@ -801,6 +815,7 @@
 	cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB);
 	cmd->params.rdeeprom.value = 0;
 
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
@@ -809,35 +824,36 @@
 			       u16 cmd_action, void *pdata_buf)
 {
 	struct cmd_ds_bt_access *bt_access = &cmd->params.bt;
-	lbs_deb_cmd("BT CMD(%d)\n", cmd_action);
+	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
 
-	cmd->command = cpu_to_le16(cmd_bt_access);
+	cmd->command = cpu_to_le16(CMD_BT_ACCESS);
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) + S_DS_GEN);
 	cmd->result = 0;
 	bt_access->action = cpu_to_le16(cmd_action);
 
 	switch (cmd_action) {
-	case cmd_act_bt_access_add:
+	case CMD_ACT_BT_ACCESS_ADD:
 		memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN);
-		lbs_dbg_hex("BT_ADD: blinded mac address-", bt_access->addr1, 6);
+		lbs_deb_hex(LBS_DEB_MESH, "BT_ADD: blinded MAC addr", bt_access->addr1, 6);
 		break;
-	case cmd_act_bt_access_del:
+	case CMD_ACT_BT_ACCESS_DEL:
 		memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN);
-		lbs_dbg_hex("BT_DEL: blinded mac address-", bt_access->addr1, 6);
+		lbs_deb_hex(LBS_DEB_MESH, "BT_DEL: blinded MAC addr", bt_access->addr1, 6);
 		break;
-	case cmd_act_bt_access_list:
+	case CMD_ACT_BT_ACCESS_LIST:
 		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
 		break;
-	case cmd_act_bt_access_reset:
+	case CMD_ACT_BT_ACCESS_RESET:
 		break;
-	case cmd_act_bt_access_set_invert:
+	case CMD_ACT_BT_ACCESS_SET_INVERT:
 		bt_access->id = cpu_to_le32(*(u32 *) pdata_buf);
 		break;
-	case cmd_act_bt_access_get_invert:
+	case CMD_ACT_BT_ACCESS_GET_INVERT:
 		break;
 	default:
 		break;
 	}
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
@@ -846,9 +862,9 @@
 			       u16 cmd_action, void *pdata_buf)
 {
 	struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt;
-	lbs_deb_cmd("FWT CMD(%d)\n", cmd_action);
+	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
 
-	cmd->command = cpu_to_le16(cmd_fwt_access);
+	cmd->command = cpu_to_le16(CMD_FWT_ACCESS);
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) + S_DS_GEN);
 	cmd->result = 0;
 
@@ -859,6 +875,7 @@
 
 	fwt_access->action = cpu_to_le16(cmd_action);
 
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
@@ -867,9 +884,9 @@
 				u16 cmd_action, void *pdata_buf)
 {
 	struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh;
-	lbs_deb_cmd("FWT CMD(%d)\n", cmd_action);
+	lbs_deb_enter_args(LBS_DEB_CMD, "action %d", cmd_action);
 
-	cmd->command = cpu_to_le16(cmd_mesh_access);
+	cmd->command = cpu_to_le16(CMD_MESH_ACCESS);
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) + S_DS_GEN);
 	cmd->result = 0;
 
@@ -880,6 +897,18 @@
 
 	mesh_access->action = cpu_to_le16(cmd_action);
 
+	lbs_deb_leave(LBS_DEB_CMD);
+	return 0;
+}
+
+static int wlan_cmd_set_boot2_ver(wlan_private * priv,
+				struct cmd_ds_command *cmd,
+				u16 cmd_action, void *pdata_buf)
+{
+	struct cmd_ds_set_boot2_ver *boot2_ver = &cmd->params.boot2_ver;
+	cmd->command = cpu_to_le16(CMD_SET_BOOT2_VER);
+	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_set_boot2_ver) + S_DS_GEN);
+	boot2_ver->version = priv->boot2_version;
 	return 0;
 }
 
@@ -888,23 +917,23 @@
 	unsigned long flags;
 	struct cmd_ds_command *cmdptr;
 
-	lbs_deb_enter(LBS_DEB_CMD);
+	lbs_deb_enter(LBS_DEB_HOST);
 
 	if (!cmdnode) {
-		lbs_deb_cmd("QUEUE_CMD: cmdnode is NULL\n");
+		lbs_deb_host("QUEUE_CMD: cmdnode is NULL\n");
 		goto done;
 	}
 
 	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
 	if (!cmdptr) {
-		lbs_deb_cmd("QUEUE_CMD: cmdptr is NULL\n");
+		lbs_deb_host("QUEUE_CMD: cmdptr is NULL\n");
 		goto done;
 	}
 
 	/* Exit_PS command needs to be queued in the header always. */
-	if (cmdptr->command == cmd_802_11_ps_mode) {
+	if (cmdptr->command == CMD_802_11_PS_MODE) {
 		struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode;
-		if (psm->action == cpu_to_le16(cmd_subcmd_exit_ps)) {
+		if (psm->action == cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
 			if (adapter->psstate != PS_STATE_FULL_POWER)
 				addtail = 0;
 		}
@@ -920,17 +949,16 @@
 
 	spin_unlock_irqrestore(&adapter->driver_lock, flags);
 
-	lbs_deb_cmd("QUEUE_CMD: Inserted node=%p, cmd=0x%x in cmdpendingq\n",
-	       cmdnode,
+	lbs_deb_host("QUEUE_CMD: inserted command 0x%04x into cmdpendingq\n",
 	       le16_to_cpu(((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command));
 
 done:
-	lbs_deb_leave(LBS_DEB_CMD);
+	lbs_deb_leave(LBS_DEB_HOST);
 }
 
 /*
  * TODO: Fix the issue when DownloadcommandToStation is being called the
- * second time when the command timesout. All the cmdptr->xxx are in little
+ * second time when the command times out. All the cmdptr->xxx are in little
  * endian and therefore all the comparissions will fail.
  * For now - we are not performing the endian conversion the second time - but
  * for PS and DEEP_SLEEP we need to worry
@@ -941,68 +969,59 @@
 	unsigned long flags;
 	struct cmd_ds_command *cmdptr;
 	wlan_adapter *adapter = priv->adapter;
-	int ret = 0;
+	int ret = -1;
 	u16 cmdsize;
 	u16 command;
 
-	lbs_deb_enter(LBS_DEB_CMD);
+	lbs_deb_enter(LBS_DEB_HOST);
 
 	if (!adapter || !cmdnode) {
-		lbs_deb_cmd("DNLD_CMD: adapter = %p, cmdnode = %p\n",
-		       adapter, cmdnode);
-		if (cmdnode) {
-			spin_lock_irqsave(&adapter->driver_lock, flags);
-			__libertas_cleanup_and_insert_cmd(priv, cmdnode);
-			spin_unlock_irqrestore(&adapter->driver_lock, flags);
-		}
-		ret = -1;
+		lbs_deb_host("DNLD_CMD: adapter or cmdmode is NULL\n");
 		goto done;
 	}
 
 	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
 
-
 	spin_lock_irqsave(&adapter->driver_lock, flags);
 	if (!cmdptr || !cmdptr->size) {
-		lbs_deb_cmd("DNLD_CMD: cmdptr is Null or cmd size is Zero, "
-		       "Not sending\n");
+		lbs_deb_host("DNLD_CMD: cmdptr is NULL or zero\n");
 		__libertas_cleanup_and_insert_cmd(priv, cmdnode);
 		spin_unlock_irqrestore(&adapter->driver_lock, flags);
-		ret = -1;
 		goto done;
 	}
 
 	adapter->cur_cmd = cmdnode;
 	adapter->cur_cmd_retcode = 0;
 	spin_unlock_irqrestore(&adapter->driver_lock, flags);
-	lbs_deb_cmd("DNLD_CMD:: Before download, size of cmd = %d\n",
-		    le16_to_cpu(cmdptr->size));
 
 	cmdsize = cmdptr->size;
-
 	command = cpu_to_le16(cmdptr->command);
 
+	lbs_deb_host("DNLD_CMD: command 0x%04x, size %d, jiffies %lu\n",
+		    command, le16_to_cpu(cmdptr->size), jiffies);
+	lbs_deb_hex(LBS_DEB_HOST, "DNLD_CMD", cmdnode->bufvirtualaddr, cmdsize);
+
 	cmdnode->cmdwaitqwoken = 0;
 	cmdsize = cpu_to_le16(cmdsize);
 
 	ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize);
 
 	if (ret != 0) {
-		lbs_deb_cmd("DNLD_CMD: Host to Card failed\n");
+		lbs_deb_host("DNLD_CMD: hw_host_to_card failed\n");
 		spin_lock_irqsave(&adapter->driver_lock, flags);
+		adapter->cur_cmd_retcode = ret;
 		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
+		adapter->nr_cmd_pending--;
 		adapter->cur_cmd = NULL;
 		spin_unlock_irqrestore(&adapter->driver_lock, flags);
-		ret = -1;
 		goto done;
 	}
 
-	lbs_deb_cmd("DNLD_CMD: Sent command 0x%x @ %lu\n", command, jiffies);
-	lbs_dbg_hex("DNLD_CMD: command", cmdnode->bufvirtualaddr, cmdsize);
+	lbs_deb_cmd("DNLD_CMD: sent command 0x%04x, jiffies %lu\n", command, jiffies);
 
 	/* Setup the timer after transmit command */
-	if (command == cmd_802_11_scan || command == cmd_802_11_authenticate
-	    || command == cmd_802_11_associate)
+	if (command == CMD_802_11_SCAN || command == CMD_802_11_AUTHENTICATE
+	    || command == CMD_802_11_ASSOCIATE)
 		mod_timer(&adapter->command_timer, jiffies + (10*HZ));
 	else
 		mod_timer(&adapter->command_timer, jiffies + (5*HZ));
@@ -1010,7 +1029,7 @@
 	ret = 0;
 
 done:
-	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
 	return ret;
 }
 
@@ -1021,11 +1040,11 @@
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	cmd->command = cpu_to_le16(cmd_mac_control);
+	cmd->command = cpu_to_le16(CMD_MAC_CONTROL);
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN);
 	mac->action = cpu_to_le16(priv->adapter->currentpacketfilter);
 
-	lbs_deb_cmd("wlan_cmd_mac_control(): action=0x%X size=%d\n",
+	lbs_deb_cmd("MAC_CONTROL: action 0x%x, size %d\n",
 		    le16_to_cpu(mac->action), le16_to_cpu(cmd->size));
 
 	lbs_deb_leave(LBS_DEB_CMD);
@@ -1041,15 +1060,13 @@
 	wlan_adapter *adapter = priv->adapter;
 
 	if (!ptempcmd)
-		goto done;
+		return;
 
 	cleanup_cmdnode(ptempcmd);
 	list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq);
-done:
-	return;
 }
 
-void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
+static void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd)
 {
 	unsigned long flags;
 
@@ -1065,11 +1082,11 @@
 	lbs_deb_enter(LBS_DEB_CMD);
 
 	ret = libertas_prepare_and_send_command(priv,
-				    cmd_802_11_radio_control,
-				    cmd_act_set,
-				    cmd_option_waitforrsp, 0, NULL);
+				    CMD_802_11_RADIO_CONTROL,
+				    CMD_ACT_SET,
+				    CMD_OPTION_WAITFORRSP, 0, NULL);
 
-	lbs_deb_cmd("RADIO_SET: on or off: 0x%X, preamble = 0x%X\n",
+	lbs_deb_cmd("RADIO_SET: radio %d, preamble %d\n",
 	       priv->adapter->radioon, priv->adapter->preamble);
 
 	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
@@ -1082,12 +1099,9 @@
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	lbs_deb_cmd("libertas_set_mac_packet_filter value = %x\n",
-	       priv->adapter->currentpacketfilter);
-
 	/* Send MAC control command to station */
 	ret = libertas_prepare_and_send_command(priv,
-				    cmd_mac_control, 0, 0, 0, NULL);
+				    CMD_MAC_CONTROL, 0, 0, 0, NULL);
 
 	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
 	return ret;
@@ -1115,16 +1129,16 @@
 	struct cmd_ds_command *cmdptr;
 	unsigned long flags;
 
-	lbs_deb_enter(LBS_DEB_CMD);
+	lbs_deb_enter(LBS_DEB_HOST);
 
 	if (!adapter) {
-		lbs_deb_cmd("PREP_CMD: adapter is Null\n");
+		lbs_deb_host("PREP_CMD: adapter is NULL\n");
 		ret = -1;
 		goto done;
 	}
 
 	if (adapter->surpriseremoved) {
-		lbs_deb_cmd("PREP_CMD: Card is Removed\n");
+		lbs_deb_host("PREP_CMD: card removed\n");
 		ret = -1;
 		goto done;
 	}
@@ -1132,10 +1146,10 @@
 	cmdnode = libertas_get_free_cmd_ctrl_node(priv);
 
 	if (cmdnode == NULL) {
-		lbs_deb_cmd("PREP_CMD: No free cmdnode\n");
+		lbs_deb_host("PREP_CMD: cmdnode is NULL\n");
 
 		/* Wake up main thread to execute next command */
-		wake_up_interruptible(&priv->mainthread.waitq);
+		wake_up_interruptible(&priv->waitq);
 		ret = -1;
 		goto done;
 	}
@@ -1144,11 +1158,10 @@
 
 	cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
 
-	lbs_deb_cmd("PREP_CMD: Val of cmd ptr=%p, command=0x%X\n",
-	       cmdptr, cmd_no);
+	lbs_deb_host("PREP_CMD: command 0x%04x\n", cmd_no);
 
 	if (!cmdptr) {
-		lbs_deb_cmd("PREP_CMD: bufvirtualaddr of cmdnode is NULL\n");
+		lbs_deb_host("PREP_CMD: cmdptr is NULL\n");
 		libertas_cleanup_and_insert_cmd(priv, cmdnode);
 		ret = -1;
 		goto done;
@@ -1162,136 +1175,136 @@
 	cmdptr->result = 0;
 
 	switch (cmd_no) {
-	case cmd_get_hw_spec:
+	case CMD_GET_HW_SPEC:
 		ret = wlan_cmd_hw_spec(priv, cmdptr);
 		break;
-	case cmd_802_11_ps_mode:
+	case CMD_802_11_PS_MODE:
 		ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action);
 		break;
 
-	case cmd_802_11_scan:
+	case CMD_802_11_SCAN:
 		ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf);
 		break;
 
-	case cmd_mac_control:
+	case CMD_MAC_CONTROL:
 		ret = wlan_cmd_mac_control(priv, cmdptr);
 		break;
 
-	case cmd_802_11_associate:
-	case cmd_802_11_reassociate:
+	case CMD_802_11_ASSOCIATE:
+	case CMD_802_11_REASSOCIATE:
 		ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf);
 		break;
 
-	case cmd_802_11_deauthenticate:
+	case CMD_802_11_DEAUTHENTICATE:
 		ret = libertas_cmd_80211_deauthenticate(priv, cmdptr);
 		break;
 
-	case cmd_802_11_set_wep:
+	case CMD_802_11_SET_WEP:
 		ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf);
 		break;
 
-	case cmd_802_11_ad_hoc_start:
+	case CMD_802_11_AD_HOC_START:
 		ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf);
 		break;
-	case cmd_code_dnld:
+	case CMD_CODE_DNLD:
 		break;
 
-	case cmd_802_11_reset:
+	case CMD_802_11_RESET:
 		ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action);
 		break;
 
-	case cmd_802_11_get_log:
+	case CMD_802_11_GET_LOG:
 		ret = wlan_cmd_802_11_get_log(priv, cmdptr);
 		break;
 
-	case cmd_802_11_authenticate:
+	case CMD_802_11_AUTHENTICATE:
 		ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf);
 		break;
 
-	case cmd_802_11_get_stat:
+	case CMD_802_11_GET_STAT:
 		ret = wlan_cmd_802_11_get_stat(priv, cmdptr);
 		break;
 
-	case cmd_802_11_snmp_mib:
+	case CMD_802_11_SNMP_MIB:
 		ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr,
 					       cmd_action, cmd_oid, pdata_buf);
 		break;
 
-	case cmd_mac_reg_access:
-	case cmd_bbp_reg_access:
-	case cmd_rf_reg_access:
+	case CMD_MAC_REG_ACCESS:
+	case CMD_BBP_REG_ACCESS:
+	case CMD_RF_REG_ACCESS:
 		ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf);
 		break;
 
-	case cmd_802_11_rf_channel:
+	case CMD_802_11_RF_CHANNEL:
 		ret = wlan_cmd_802_11_rf_channel(priv, cmdptr,
 						 cmd_action, pdata_buf);
 		break;
 
-	case cmd_802_11_rf_tx_power:
+	case CMD_802_11_RF_TX_POWER:
 		ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr,
 						  cmd_action, pdata_buf);
 		break;
 
-	case cmd_802_11_radio_control:
+	case CMD_802_11_RADIO_CONTROL:
 		ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action);
 		break;
 
-	case cmd_802_11_rf_antenna:
-		ret = wlan_cmd_802_11_rf_antenna(priv, cmdptr,
-						 cmd_action, pdata_buf);
-		break;
-
-	case cmd_802_11_data_rate:
+	case CMD_802_11_DATA_RATE:
 		ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action);
 		break;
-	case cmd_802_11_rate_adapt_rateset:
+	case CMD_802_11_RATE_ADAPT_RATESET:
 		ret = wlan_cmd_802_11_rate_adapt_rateset(priv,
 							 cmdptr, cmd_action);
 		break;
 
-	case cmd_mac_multicast_adr:
+	case CMD_MAC_MULTICAST_ADR:
 		ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action);
 		break;
 
-	case cmd_802_11_ad_hoc_join:
+	case CMD_802_11_MONITOR_MODE:
+		ret = wlan_cmd_802_11_monitor_mode(priv, cmdptr,
+				          cmd_action, pdata_buf);
+		break;
+
+	case CMD_802_11_AD_HOC_JOIN:
 		ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf);
 		break;
 
-	case cmd_802_11_rssi:
+	case CMD_802_11_RSSI:
 		ret = wlan_cmd_802_11_rssi(priv, cmdptr);
 		break;
 
-	case cmd_802_11_ad_hoc_stop:
+	case CMD_802_11_AD_HOC_STOP:
 		ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr);
 		break;
 
-	case cmd_802_11_enable_rsn:
+	case CMD_802_11_ENABLE_RSN:
 		ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action,
 				pdata_buf);
 		break;
 
-	case cmd_802_11_key_material:
+	case CMD_802_11_KEY_MATERIAL:
 		ret = wlan_cmd_802_11_key_material(priv, cmdptr, cmd_action,
 				cmd_oid, pdata_buf);
 		break;
 
-	case cmd_802_11_pairwise_tsc:
+	case CMD_802_11_PAIRWISE_TSC:
 		break;
-	case cmd_802_11_group_tsc:
+	case CMD_802_11_GROUP_TSC:
 		break;
 
-	case cmd_802_11_mac_address:
+	case CMD_802_11_MAC_ADDRESS:
 		ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action);
 		break;
 
-	case cmd_802_11_eeprom_access:
+	case CMD_802_11_EEPROM_ACCESS:
 		ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr,
 						    cmd_action, pdata_buf);
 		break;
 
-	case cmd_802_11_set_afc:
-	case cmd_802_11_get_afc:
+	case CMD_802_11_SET_AFC:
+	case CMD_802_11_GET_AFC:
 
 		cmdptr->command = cpu_to_le16(cmd_no);
 		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) +
@@ -1303,22 +1316,22 @@
 		ret = 0;
 		goto done;
 
-	case cmd_802_11d_domain_info:
+	case CMD_802_11D_DOMAIN_INFO:
 		ret = libertas_cmd_802_11d_domain_info(priv, cmdptr,
 						   cmd_no, cmd_action);
 		break;
 
-	case cmd_802_11_sleep_params:
+	case CMD_802_11_SLEEP_PARAMS:
 		ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action);
 		break;
-	case cmd_802_11_inactivity_timeout:
+	case CMD_802_11_INACTIVITY_TIMEOUT:
 		ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr,
 							 cmd_action, pdata_buf);
 		libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf);
 		break;
 
-	case cmd_802_11_tpc_cfg:
-		cmdptr->command = cpu_to_le16(cmd_802_11_tpc_cfg);
+	case CMD_802_11_TPC_CFG:
+		cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
 		cmdptr->size =
 		    cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) +
 				     S_DS_GEN);
@@ -1328,7 +1341,7 @@
 
 		ret = 0;
 		break;
-	case cmd_802_11_led_gpio_ctrl:
+	case CMD_802_11_LED_GPIO_CTRL:
 		{
 			struct mrvlietypes_ledgpio *gpio =
 			    (struct mrvlietypes_ledgpio*)
@@ -1339,7 +1352,7 @@
 				sizeof(struct cmd_ds_802_11_led_ctrl));
 
 			cmdptr->command =
-			    cpu_to_le16(cmd_802_11_led_gpio_ctrl);
+			    cpu_to_le16(CMD_802_11_LED_GPIO_CTRL);
 
 #define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8
 			cmdptr->size =
@@ -1350,8 +1363,8 @@
 			ret = 0;
 			break;
 		}
-	case cmd_802_11_pwr_cfg:
-		cmdptr->command = cpu_to_le16(cmd_802_11_pwr_cfg);
+	case CMD_802_11_PWR_CFG:
+		cmdptr->command = cpu_to_le16(CMD_802_11_PWR_CFG);
 		cmdptr->size =
 		    cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) +
 				     S_DS_GEN);
@@ -1360,40 +1373,37 @@
 
 		ret = 0;
 		break;
-	case cmd_bt_access:
+	case CMD_BT_ACCESS:
 		ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf);
 		break;
 
-	case cmd_fwt_access:
+	case CMD_FWT_ACCESS:
 		ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf);
 		break;
 
-	case cmd_mesh_access:
+	case CMD_MESH_ACCESS:
 		ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf);
 		break;
 
-	case cmd_get_tsf:
-		cmdptr->command = cpu_to_le16(cmd_get_tsf);
+	case CMD_SET_BOOT2_VER:
+		ret = wlan_cmd_set_boot2_ver(priv, cmdptr, cmd_action, pdata_buf);
+		break;
+
+	case CMD_GET_TSF:
+		cmdptr->command = cpu_to_le16(CMD_GET_TSF);
 		cmdptr->size = cpu_to_le16(sizeof(struct cmd_ds_get_tsf) +
 					   S_DS_GEN);
 		ret = 0;
 		break;
-	case cmd_802_11_tx_rate_query:
-		cmdptr->command = cpu_to_le16(cmd_802_11_tx_rate_query);
-		cmdptr->size = cpu_to_le16(sizeof(struct cmd_tx_rate_query) +
-					   S_DS_GEN);
-		adapter->txrate = 0;
-		ret = 0;
-		break;
 	default:
-		lbs_deb_cmd("PREP_CMD: unknown command- %#x\n", cmd_no);
+		lbs_deb_host("PREP_CMD: unknown command 0x%04x\n", cmd_no);
 		ret = -1;
 		break;
 	}
 
 	/* return error, since the command preparation failed */
 	if (ret != 0) {
-		lbs_deb_cmd("PREP_CMD: command preparation failed\n");
+		lbs_deb_host("PREP_CMD: command preparation failed\n");
 		libertas_cleanup_and_insert_cmd(priv, cmdnode);
 		ret = -1;
 		goto done;
@@ -1403,10 +1413,10 @@
 
 	libertas_queue_cmd(adapter, cmdnode, 1);
 	adapter->nr_cmd_pending++;
-	wake_up_interruptible(&priv->mainthread.waitq);
+	wake_up_interruptible(&priv->waitq);
 
-	if (wait_option & cmd_option_waitforrsp) {
-		lbs_deb_cmd("PREP_CMD: Wait for CMD response\n");
+	if (wait_option & CMD_OPTION_WAITFORRSP) {
+		lbs_deb_host("PREP_CMD: wait for response\n");
 		might_sleep();
 		wait_event_interruptible(cmdnode->cmdwait_q,
 					 cmdnode->cmdwaitqwoken);
@@ -1414,7 +1424,7 @@
 
 	spin_lock_irqsave(&adapter->driver_lock, flags);
 	if (adapter->cur_cmd_retcode) {
-		lbs_deb_cmd("PREP_CMD: command failed with return code=%d\n",
+		lbs_deb_host("PREP_CMD: command failed with return code %d\n",
 		       adapter->cur_cmd_retcode);
 		adapter->cur_cmd_retcode = 0;
 		ret = -1;
@@ -1422,7 +1432,7 @@
 	spin_unlock_irqrestore(&adapter->driver_lock, flags);
 
 done:
-	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(libertas_prepare_and_send_command);
@@ -1443,14 +1453,13 @@
 	u8 *ptempvirtualaddr;
 	wlan_adapter *adapter = priv->adapter;
 
-	lbs_deb_enter(LBS_DEB_CMD);
+	lbs_deb_enter(LBS_DEB_HOST);
 
 	/* Allocate and initialize cmdCtrlNode */
 	ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER;
 
 	if (!(tempcmd_array = kzalloc(ulbufsize, GFP_KERNEL))) {
-		lbs_deb_cmd(
-		       "ALLOC_CMD_BUF: failed to allocate tempcmd_array\n");
+		lbs_deb_host("ALLOC_CMD_BUF: tempcmd_array is NULL\n");
 		ret = -1;
 		goto done;
 	}
@@ -1460,8 +1469,7 @@
 	ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
 	for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
 		if (!(ptempvirtualaddr = kzalloc(ulbufsize, GFP_KERNEL))) {
-			lbs_deb_cmd(
-			       "ALLOC_CMD_BUF: ptempvirtualaddr: out of memory\n");
+			lbs_deb_host("ALLOC_CMD_BUF: ptempvirtualaddr is NULL\n");
 			ret = -1;
 			goto done;
 		}
@@ -1478,7 +1486,7 @@
 	ret = 0;
 
 done:
-	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
 	return ret;
 }
 
@@ -1495,11 +1503,11 @@
 	struct cmd_ctrl_node *tempcmd_array;
 	wlan_adapter *adapter = priv->adapter;
 
-	lbs_deb_enter(LBS_DEB_CMD);
+	lbs_deb_enter(LBS_DEB_HOST);
 
 	/* need to check if cmd array is allocated or not */
 	if (adapter->cmd_array == NULL) {
-		lbs_deb_cmd("FREE_CMD_BUF: cmd_array is Null\n");
+		lbs_deb_host("FREE_CMD_BUF: cmd_array is NULL\n");
 		goto done;
 	}
 
@@ -1509,7 +1517,6 @@
 	ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER;
 	for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) {
 		if (tempcmd_array[i].bufvirtualaddr) {
-			lbs_deb_cmd("Free all the array\n");
 			kfree(tempcmd_array[i].bufvirtualaddr);
 			tempcmd_array[i].bufvirtualaddr = NULL;
 		}
@@ -1517,13 +1524,12 @@
 
 	/* Release cmd_ctrl_node */
 	if (adapter->cmd_array) {
-		lbs_deb_cmd("Free cmd_array\n");
 		kfree(adapter->cmd_array);
 		adapter->cmd_array = NULL;
 	}
 
 done:
-	lbs_deb_leave(LBS_DEB_CMD);
+	lbs_deb_leave(LBS_DEB_HOST);
 	return 0;
 }
 
@@ -1540,6 +1546,8 @@
 	wlan_adapter *adapter = priv->adapter;
 	unsigned long flags;
 
+	lbs_deb_enter(LBS_DEB_HOST);
+
 	if (!adapter)
 		return NULL;
 
@@ -1549,21 +1557,16 @@
 		tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next;
 		list_del((struct list_head *)tempnode);
 	} else {
-		lbs_deb_cmd("GET_CMD_NODE: cmd_ctrl_node is not available\n");
+		lbs_deb_host("GET_CMD_NODE: cmd_ctrl_node is not available\n");
 		tempnode = NULL;
 	}
 
 	spin_unlock_irqrestore(&adapter->driver_lock, flags);
 
-	if (tempnode) {
-		/*
-		lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode available\n");
-		lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode Address = %p\n",
-		       tempnode);
-		*/
+	if (tempnode)
 		cleanup_cmdnode(tempnode);
-	}
 
+	lbs_deb_leave(LBS_DEB_HOST);
 	return tempnode;
 }
 
@@ -1575,6 +1578,8 @@
  */
 static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode)
 {
+	lbs_deb_enter(LBS_DEB_HOST);
+
 	if (!ptempnode)
 		return;
 	ptempnode->cmdwaitqwoken = 1;
@@ -1586,7 +1591,8 @@
 
 	if (ptempnode->bufvirtualaddr != NULL)
 		memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER);
-	return;
+
+	lbs_deb_leave(LBS_DEB_HOST);
 }
 
 /**
@@ -1603,7 +1609,7 @@
 		    struct cmd_ctrl_node *ptempnode,
 		    u32 cmd_oid, u16 wait_option, void *pdata_buf)
 {
-	lbs_deb_enter(LBS_DEB_CMD);
+	lbs_deb_enter(LBS_DEB_HOST);
 
 	if (!ptempnode)
 		return;
@@ -1612,7 +1618,7 @@
 	ptempnode->wait_option = wait_option;
 	ptempnode->pdata_buf = pdata_buf;
 
-	lbs_deb_leave(LBS_DEB_CMD);
+	lbs_deb_leave(LBS_DEB_HOST);
 }
 
 /**
@@ -1631,12 +1637,15 @@
 	unsigned long flags;
 	int ret = 0;
 
-	lbs_deb_enter(LBS_DEB_CMD);
+	// Debug group is LBS_DEB_THREAD and not LBS_DEB_HOST, because the
+	// only caller to us is libertas_thread() and we get even when a
+	// data packet is received
+	lbs_deb_enter(LBS_DEB_THREAD);
 
 	spin_lock_irqsave(&adapter->driver_lock, flags);
 
 	if (adapter->cur_cmd) {
-		lbs_pr_alert( "EXEC_NEXT_CMD: there is command in processing!\n");
+		lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
 		spin_unlock_irqrestore(&adapter->driver_lock, flags);
 		ret = -1;
 		goto done;
@@ -1650,22 +1659,20 @@
 	spin_unlock_irqrestore(&adapter->driver_lock, flags);
 
 	if (cmdnode) {
-		lbs_deb_cmd(
-		       "EXEC_NEXT_CMD: Got next command from cmdpendingq\n");
 		cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr;
 
 		if (is_command_allowed_in_ps(cmdptr->command)) {
 			if ((adapter->psstate == PS_STATE_SLEEP) ||
 			    (adapter->psstate == PS_STATE_PRE_SLEEP)) {
-				lbs_deb_cmd(
-				       "EXEC_NEXT_CMD: Cannot send cmd 0x%x in psstate %d\n",
+				lbs_deb_host(
+				       "EXEC_NEXT_CMD: cannot send cmd 0x%04x in psstate %d\n",
 				       le16_to_cpu(cmdptr->command),
 				       adapter->psstate);
 				ret = -1;
 				goto done;
 			}
-			lbs_deb_cmd("EXEC_NEXT_CMD: OK to send command "
-			       "0x%x in psstate %d\n",
+			lbs_deb_host("EXEC_NEXT_CMD: OK to send command "
+			       "0x%04x in psstate %d\n",
 				    le16_to_cpu(cmdptr->command),
 				    adapter->psstate);
 		} else if (adapter->psstate != PS_STATE_FULL_POWER) {
@@ -1681,7 +1688,7 @@
 			 * immediately.
 			 */
 			if (cmdptr->command !=
-			    cpu_to_le16(cmd_802_11_ps_mode)) {
+			    cpu_to_le16(CMD_802_11_PS_MODE)) {
 				/*  Prepare to send Exit PS,
 				 *  this non PS command will be sent later */
 				if ((adapter->psstate == PS_STATE_SLEEP)
@@ -1703,13 +1710,13 @@
 				struct cmd_ds_802_11_ps_mode *psm =
 				    &cmdptr->params.psmode;
 
-				lbs_deb_cmd(
-				       "EXEC_NEXT_CMD: PS cmd- action=0x%x\n",
+				lbs_deb_host(
+				       "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
 				       psm->action);
 				if (psm->action !=
-				    cpu_to_le16(cmd_subcmd_exit_ps)) {
-					lbs_deb_cmd(
-					       "EXEC_NEXT_CMD: Ignore Enter PS cmd\n");
+				    cpu_to_le16(CMD_SUBCMD_EXIT_PS)) {
+					lbs_deb_host(
+					       "EXEC_NEXT_CMD: ignore ENTER_PS cmd\n");
 					list_del((struct list_head *)cmdnode);
 					libertas_cleanup_and_insert_cmd(priv, cmdnode);
 
@@ -1719,8 +1726,8 @@
 
 				if ((adapter->psstate == PS_STATE_SLEEP) ||
 				    (adapter->psstate == PS_STATE_PRE_SLEEP)) {
-					lbs_deb_cmd(
-					       "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n");
+					lbs_deb_host(
+					       "EXEC_NEXT_CMD: ignore EXIT_PS cmd in sleep\n");
 					list_del((struct list_head *)cmdnode);
 					libertas_cleanup_and_insert_cmd(priv, cmdnode);
 					adapter->needtowakeup = 1;
@@ -1729,12 +1736,12 @@
 					goto done;
 				}
 
-				lbs_deb_cmd(
-				       "EXEC_NEXT_CMD: Sending Exit_PS down...\n");
+				lbs_deb_host(
+				       "EXEC_NEXT_CMD: sending EXIT_PS\n");
 			}
 		}
 		list_del((struct list_head *)cmdnode);
-		lbs_deb_cmd("EXEC_NEXT_CMD: Sending 0x%04X command\n",
+		lbs_deb_host("EXEC_NEXT_CMD: sending command 0x%04x\n",
 			    le16_to_cpu(cmdptr->command));
 		DownloadcommandToStation(priv, cmdnode);
 	} else {
@@ -1742,23 +1749,23 @@
 		 * check if in power save mode, if yes, put the device back
 		 * to PS mode
 		 */
-		if ((adapter->psmode != wlan802_11powermodecam) &&
+		if ((adapter->psmode != WLAN802_11POWERMODECAM) &&
 		    (adapter->psstate == PS_STATE_FULL_POWER) &&
-		    (adapter->connect_status == libertas_connected)) {
+		    (adapter->connect_status == LIBERTAS_CONNECTED)) {
 			if (adapter->secinfo.WPAenabled ||
 			    adapter->secinfo.WPA2enabled) {
 				/* check for valid WPA group keys */
 				if (adapter->wpa_mcast_key.len ||
 				    adapter->wpa_unicast_key.len) {
-					lbs_deb_cmd(
+					lbs_deb_host(
 					       "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
 					       " go back to PS_SLEEP");
 					libertas_ps_sleep(priv, 0);
 				}
 			} else {
-				lbs_deb_cmd(
-				       "EXEC_NEXT_CMD: command PendQ is empty,"
-				       " go back to PS_SLEEP");
+				lbs_deb_host(
+				       "EXEC_NEXT_CMD: cmdpendingq empty, "
+				       "go back to PS_SLEEP");
 				libertas_ps_sleep(priv, 0);
 			}
 		}
@@ -1766,7 +1773,7 @@
 
 	ret = 0;
 done:
-	lbs_deb_leave(LBS_DEB_CMD);
+	lbs_deb_leave(LBS_DEB_THREAD);
 	return ret;
 }
 
@@ -1775,7 +1782,7 @@
 	union iwreq_data iwrq;
 	u8 buf[50];
 
-	lbs_deb_enter(LBS_DEB_CMD);
+	lbs_deb_enter(LBS_DEB_WEXT);
 
 	memset(&iwrq, 0, sizeof(union iwreq_data));
 	memset(buf, 0, sizeof(buf));
@@ -1785,13 +1792,13 @@
 	iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN;
 
 	/* Send Event to upper layer */
-	lbs_deb_cmd("Event Indication string = %s\n", (char *)buf);
-	lbs_deb_cmd("Event Indication String length = %d\n", iwrq.data.length);
+	lbs_deb_wext("event indication string %s\n", (char *)buf);
+	lbs_deb_wext("event indication length %d\n", iwrq.data.length);
+	lbs_deb_wext("sending wireless event IWEVCUSTOM for %s\n", str);
 
-	lbs_deb_cmd("Sending wireless event IWEVCUSTOM for %s\n", str);
 	wireless_send_event(priv->dev, IWEVCUSTOM, &iwrq, buf);
 
-	lbs_deb_leave(LBS_DEB_CMD);
+	lbs_deb_leave(LBS_DEB_WEXT);
 }
 
 static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size)
@@ -1800,19 +1807,19 @@
 	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
 
-	lbs_deb_enter(LBS_DEB_CMD);
+	lbs_deb_enter(LBS_DEB_HOST);
 
-	lbs_deb_cmd("SEND_SLEEPC_CMD: Before download, size of cmd = %d\n",
+	lbs_deb_host("SEND_SLEEPC_CMD: before download, cmd size %d\n",
 	       size);
 
-	lbs_dbg_hex("SEND_SLEEPC_CMD: Sleep confirm command", cmdptr, size);
+	lbs_deb_hex(LBS_DEB_HOST, "sleep confirm command", cmdptr, size);
 
 	ret = priv->hw_host_to_card(priv, MVMS_CMD, cmdptr, size);
 	priv->dnld_sent = DNLD_RES_RECEIVED;
 
 	spin_lock_irqsave(&adapter->driver_lock, flags);
 	if (adapter->intcounter || adapter->currenttxskb)
-		lbs_deb_cmd("SEND_SLEEPC_CMD: intcounter=%d currenttxskb=%p\n",
+		lbs_deb_host("SEND_SLEEPC_CMD: intcounter %d, currenttxskb %p\n",
 		       adapter->intcounter, adapter->currenttxskb);
 	spin_unlock_irqrestore(&adapter->driver_lock, flags);
 
@@ -1824,36 +1831,35 @@
 		if (!adapter->intcounter) {
 			adapter->psstate = PS_STATE_SLEEP;
 		} else {
-			lbs_deb_cmd("SEND_SLEEPC_CMD: After sent,IntC=%d\n",
+			lbs_deb_host("SEND_SLEEPC_CMD: after sent, intcounter %d\n",
 			       adapter->intcounter);
 		}
 		spin_unlock_irqrestore(&adapter->driver_lock, flags);
 
-		lbs_deb_cmd("SEND_SLEEPC_CMD: Sent Confirm Sleep command\n");
-		lbs_deb_cmd("+");
+		lbs_deb_host("SEND_SLEEPC_CMD: sent confirm sleep\n");
 	}
 
-	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
 	return ret;
 }
 
 void libertas_ps_sleep(wlan_private * priv, int wait_option)
 {
-	lbs_deb_enter(LBS_DEB_CMD);
+	lbs_deb_enter(LBS_DEB_HOST);
 
 	/*
 	 * PS is currently supported only in Infrastructure mode
 	 * Remove this check if it is to be supported in IBSS mode also
 	 */
 
-	libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
-			      cmd_subcmd_enter_ps, wait_option, 0, NULL);
+	libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
+			      CMD_SUBCMD_ENTER_PS, wait_option, 0, NULL);
 
-	lbs_deb_leave(LBS_DEB_CMD);
+	lbs_deb_leave(LBS_DEB_HOST);
 }
 
 /**
- *  @brief This function sends Eixt_PS command to firmware.
+ *  @brief This function sends Exit_PS command to firmware.
  *
  *  @param priv    	A pointer to wlan_private structure
  *  @param wait_option	wait response or not
@@ -1863,17 +1869,15 @@
 {
 	__le32 Localpsmode;
 
-	lbs_deb_enter(LBS_DEB_CMD);
+	lbs_deb_enter(LBS_DEB_HOST);
 
-	Localpsmode = cpu_to_le32(wlan802_11powermodecam);
+	Localpsmode = cpu_to_le32(WLAN802_11POWERMODECAM);
 
-	lbs_deb_cmd("Exit_PS: Localpsmode = %d\n", wlan802_11powermodecam);
-
-	libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode,
-			      cmd_subcmd_exit_ps,
+	libertas_prepare_and_send_command(priv, CMD_802_11_PS_MODE,
+			      CMD_SUBCMD_EXIT_PS,
 			      wait_option, 0, &Localpsmode);
 
-	lbs_deb_leave(LBS_DEB_CMD);
+	lbs_deb_leave(LBS_DEB_HOST);
 }
 
 /**
@@ -1890,31 +1894,31 @@
 	wlan_adapter *adapter = priv->adapter;
 	u8 allowed = 1;
 
-	lbs_deb_enter(LBS_DEB_CMD);
+	lbs_deb_enter(LBS_DEB_HOST);
 
 	if (priv->dnld_sent) {
 		allowed = 0;
-		lbs_deb_cmd("D");
+		lbs_deb_host("dnld_sent was set");
 	}
 
 	spin_lock_irqsave(&adapter->driver_lock, flags);
 	if (adapter->cur_cmd) {
 		allowed = 0;
-		lbs_deb_cmd("C");
+		lbs_deb_host("cur_cmd was set");
 	}
 	if (adapter->intcounter > 0) {
 		allowed = 0;
-		lbs_deb_cmd("I%d", adapter->intcounter);
+		lbs_deb_host("intcounter %d", adapter->intcounter);
 	}
 	spin_unlock_irqrestore(&adapter->driver_lock, flags);
 
 	if (allowed) {
-		lbs_deb_cmd("Sending libertas_ps_confirm_sleep\n");
+		lbs_deb_host("sending libertas_ps_confirm_sleep\n");
 		sendconfirmsleep(priv, (u8 *) & adapter->libertas_ps_confirm_sleep,
 				 sizeof(struct PS_CMD_ConfirmSleep));
 	} else {
-		lbs_deb_cmd("Sleep Confirm has been delayed\n");
+		lbs_deb_host("sleep confirm has been delayed\n");
 	}
 
-	lbs_deb_leave(LBS_DEB_CMD);
+	lbs_deb_leave(LBS_DEB_HOST);
 }
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 6ac0d47..8f90892 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -28,10 +28,10 @@
 	wlan_adapter *adapter = priv->adapter;
 	union iwreq_data wrqu;
 
-	if (adapter->connect_status != libertas_connected)
+	if (adapter->connect_status != LIBERTAS_CONNECTED)
 		return;
 
-	lbs_deb_cmd("Handles disconnect event.\n");
+	lbs_deb_enter(LBS_DEB_CMD);
 
 	memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN);
 	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
@@ -60,22 +60,12 @@
 	memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF));
 	adapter->nextSNRNF = 0;
 	adapter->numSNRNF = 0;
-	adapter->rxpd_rate = 0;
-	lbs_deb_cmd("Current SSID='%s', ssid length=%u\n",
+	lbs_deb_cmd("current SSID '%s', length %u\n",
 	            escape_essid(adapter->curbssparams.ssid,
 	                         adapter->curbssparams.ssid_len),
 	            adapter->curbssparams.ssid_len);
-	lbs_deb_cmd("Previous SSID='%s', ssid length=%u\n",
-	            escape_essid(adapter->prev_ssid, adapter->prev_ssid_len),
-	            adapter->prev_ssid_len);
 
-	adapter->connect_status = libertas_disconnected;
-
-	/* Save previous SSID and BSSID for possible reassociation */
-	memcpy(&adapter->prev_ssid, &adapter->curbssparams.ssid,
-	       IW_ESSID_MAX_SIZE);
-	adapter->prev_ssid_len = adapter->curbssparams.ssid_len;
-	memcpy(adapter->prev_bssid, adapter->curbssparams.bssid, ETH_ALEN);
+	adapter->connect_status = LIBERTAS_DISCONNECTED;
 
 	/* Clear out associated SSID and BSSID since connection is
 	 * no longer valid.
@@ -86,9 +76,10 @@
 
 	if (adapter->psstate != PS_STATE_FULL_POWER) {
 		/* make firmware to exit PS mode */
-		lbs_deb_cmd("Disconnected, so exit PS mode.\n");
+		lbs_deb_cmd("disconnected, so exit PS mode\n");
 		libertas_ps_wakeup(priv, 0);
 	}
+	lbs_deb_leave(LBS_DEB_CMD);
 }
 
 /**
@@ -102,6 +93,7 @@
 {
 	char buf[50];
 
+	lbs_deb_enter(LBS_DEB_CMD);
 	memset(buf, 0, sizeof(buf));
 
 	sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication ");
@@ -113,6 +105,7 @@
 	}
 
 	libertas_send_iwevcustom_event(priv, buf);
+	lbs_deb_leave(LBS_DEB_CMD);
 }
 
 static int wlan_ret_reg_access(wlan_private * priv,
@@ -124,7 +117,7 @@
 	lbs_deb_enter(LBS_DEB_CMD);
 
 	switch (type) {
-	case cmd_ret_mac_reg_access:
+	case CMD_RET(CMD_MAC_REG_ACCESS):
 		{
 			struct cmd_ds_mac_reg_access *reg = &resp->params.macreg;
 
@@ -133,7 +126,7 @@
 			break;
 		}
 
-	case cmd_ret_bbp_reg_access:
+	case CMD_RET(CMD_BBP_REG_ACCESS):
 		{
 			struct cmd_ds_bbp_reg_access *reg = &resp->params.bbpreg;
 
@@ -142,7 +135,7 @@
 			break;
 		}
 
-	case cmd_ret_rf_reg_access:
+	case CMD_RET(CMD_RF_REG_ACCESS):
 		{
 			struct cmd_ds_rf_reg_access *reg = &resp->params.rfreg;
 
@@ -155,7 +148,7 @@
 		ret = -1;
 	}
 
-	lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret);
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
 	return ret;
 }
 
@@ -166,6 +159,7 @@
 	struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec;
 	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
+	DECLARE_MAC_BUF(mac);
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
@@ -173,22 +167,23 @@
 
 	memcpy(adapter->fwreleasenumber, hwspec->fwreleasenumber, 4);
 
-	lbs_deb_cmd("GET_HW_SPEC: FWReleaseVersion- %u.%u.%u.p%u\n",
+	lbs_deb_cmd("GET_HW_SPEC: firmware release %u.%u.%up%u\n",
 		    adapter->fwreleasenumber[2], adapter->fwreleasenumber[1],
 		    adapter->fwreleasenumber[0], adapter->fwreleasenumber[3]);
-	lbs_deb_cmd("GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n",
-	       hwspec->permanentaddr[0], hwspec->permanentaddr[1],
-	       hwspec->permanentaddr[2], hwspec->permanentaddr[3],
-	       hwspec->permanentaddr[4], hwspec->permanentaddr[5]);
-	lbs_deb_cmd("GET_HW_SPEC: hwifversion=0x%X  version=0x%X\n",
+	lbs_deb_cmd("GET_HW_SPEC: MAC addr %s\n",
+		    print_mac(mac, hwspec->permanentaddr));
+	lbs_deb_cmd("GET_HW_SPEC: hardware interface 0x%x, hardware spec 0x%04x\n",
 	       hwspec->hwifversion, hwspec->version);
 
-	adapter->regioncode = le16_to_cpu(hwspec->regioncode);
+	/* Clamp region code to 8-bit since FW spec indicates that it should
+	 * only ever be 8-bit, even though the field size is 16-bit.  Some firmware
+	 * returns non-zero high 8 bits here.
+	 */
+	adapter->regioncode = le16_to_cpu(hwspec->regioncode) & 0xFF;
 
 	for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
 		/* use the region code to search for the index */
 		if (adapter->regioncode == libertas_region_code_to_index[i]) {
-			adapter->regiontableindex = (u16) i;
 			break;
 		}
 	}
@@ -196,7 +191,6 @@
 	/* if it's unidentified region code, use the default (USA) */
 	if (i >= MRVDRV_MAX_REGION_CODE) {
 		adapter->regioncode = 0x10;
-		adapter->regiontableindex = 0;
 		lbs_pr_info("unidentified region code; using the default (USA)\n");
 	}
 
@@ -230,8 +224,8 @@
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	lbs_deb_cmd("error=%x offset=%x stabletime=%x calcontrol=%x\n"
-		    " extsleepclk=%x\n", le16_to_cpu(sp->error),
+	lbs_deb_cmd("error 0x%x, offset 0x%x, stabletime 0x%x, calcontrol 0x%x "
+		    "extsleepclk 0x%x\n", le16_to_cpu(sp->error),
 		    le16_to_cpu(sp->offset), le16_to_cpu(sp->stabletime),
 		    sp->calcontrol, sp->externalsleepclk);
 
@@ -249,6 +243,7 @@
 static int wlan_ret_802_11_stat(wlan_private * priv,
 				struct cmd_ds_command *resp)
 {
+	lbs_deb_enter(LBS_DEB_CMD);
 /*	currently adapter->wlan802_11Stat is unused
 
 	struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat;
@@ -258,6 +253,7 @@
 	memcpy(&adapter->wlan802_11Stat,
 	       p11Stat, sizeof(struct cmd_ds_802_11_get_stat));
 */
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
@@ -270,28 +266,28 @@
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	lbs_deb_cmd("SNMP_RESP: value of the oid = %x, querytype=%x\n", oid,
+	lbs_deb_cmd("SNMP_RESP: oid 0x%x, querytype 0x%x\n", oid,
 	       querytype);
-	lbs_deb_cmd("SNMP_RESP: Buf size  = %x\n", le16_to_cpu(smib->bufsize));
+	lbs_deb_cmd("SNMP_RESP: Buf size %d\n", le16_to_cpu(smib->bufsize));
 
-	if (querytype == cmd_act_get) {
+	if (querytype == CMD_ACT_GET) {
 		switch (oid) {
-		case fragthresh_i:
+		case FRAGTHRESH_I:
 			priv->adapter->fragthsd =
 				le16_to_cpu(*((__le16 *)(smib->value)));
-			lbs_deb_cmd("SNMP_RESP: fragthsd =%u\n",
+			lbs_deb_cmd("SNMP_RESP: frag threshold %u\n",
 				    priv->adapter->fragthsd);
 			break;
-		case rtsthresh_i:
+		case RTSTHRESH_I:
 			priv->adapter->rtsthsd =
 				le16_to_cpu(*((__le16 *)(smib->value)));
-			lbs_deb_cmd("SNMP_RESP: rtsthsd =%u\n",
+			lbs_deb_cmd("SNMP_RESP: rts threshold %u\n",
 				    priv->adapter->rtsthsd);
 			break;
-		case short_retrylim_i:
+		case SHORT_RETRYLIM_I:
 			priv->adapter->txretrycount =
 				le16_to_cpu(*((__le16 *)(smib->value)));
-			lbs_deb_cmd("SNMP_RESP: txretrycount =%u\n",
+			lbs_deb_cmd("SNMP_RESP: tx retry count %u\n",
 				    priv->adapter->rtsthsd);
 			break;
 		default:
@@ -314,18 +310,19 @@
 	lbs_deb_enter(LBS_DEB_CMD);
 
 	/* Copy the returned key to driver private data */
-	if (action == cmd_act_get) {
+	if (action == CMD_ACT_GET) {
 		u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet;
 		u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size));
 
 		while (buf_ptr < resp_end) {
 			struct MrvlIEtype_keyParamSet * pkeyparamset =
 			    (struct MrvlIEtype_keyParamSet *) buf_ptr;
-			struct WLAN_802_11_KEY * pkey;
-			u16 key_info = le16_to_cpu(pkeyparamset->keyinfo);
+			struct enc_key * pkey;
 			u16 param_set_len = le16_to_cpu(pkeyparamset->length);
-			u8 * end;
 			u16 key_len = le16_to_cpu(pkeyparamset->keylen);
+			u16 key_flags = le16_to_cpu(pkeyparamset->keyinfo);
+			u16 key_type = le16_to_cpu(pkeyparamset->keytypeid);
+			u8 * end;
 
 			end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type)
 			                          + sizeof (pkeyparamset->length)
@@ -334,20 +331,20 @@
 			if (end > resp_end)
 				break;
 
-			if (key_info & KEY_INFO_WPA_UNICAST)
+			if (key_flags & KEY_INFO_WPA_UNICAST)
 				pkey = &adapter->wpa_unicast_key;
-			else if (key_info & KEY_INFO_WPA_MCAST)
+			else if (key_flags & KEY_INFO_WPA_MCAST)
 				pkey = &adapter->wpa_mcast_key;
 			else
 				break;
 
 			/* Copy returned key into driver */
-			memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
+			memset(pkey, 0, sizeof(struct enc_key));
 			if (key_len > sizeof(pkey->key))
 				break;
-			pkey->type = le16_to_cpu(pkeyparamset->keytypeid);
-			pkey->flags = le16_to_cpu(pkeyparamset->keyinfo);
-			pkey->len = le16_to_cpu(pkeyparamset->keylen);
+			pkey->type = key_type;
+			pkey->flags = key_flags;
+			pkey->len = key_len;
 			memcpy(pkey->key, pkeyparamset->key, pkey->len);
 
 			buf_ptr = end + 1;
@@ -382,28 +379,9 @@
 
 	adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel);
 
-	lbs_deb_cmd("Current TxPower Level = %d\n", adapter->txpowerlevel);
+	lbs_deb_cmd("TX power currently %d\n", adapter->txpowerlevel);
 
-	lbs_deb_enter(LBS_DEB_CMD);
-	return 0;
-}
-
-static int wlan_ret_802_11_rf_antenna(wlan_private * priv,
-				      struct cmd_ds_command *resp)
-{
-	struct cmd_ds_802_11_rf_antenna *pAntenna = &resp->params.rant;
-	wlan_adapter *adapter = priv->adapter;
-	u16 action = le16_to_cpu(pAntenna->action);
-
-	if (action == cmd_act_get_rx)
-		adapter->rxantennamode = le16_to_cpu(pAntenna->antennamode);
-
-	if (action == cmd_act_get_tx)
-		adapter->txantennamode = le16_to_cpu(pAntenna->antennamode);
-
-	lbs_deb_cmd("RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n",
-	       action, le16_to_cpu(pAntenna->antennamode));
-
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
@@ -415,12 +393,12 @@
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	if (rates->action == cmd_act_get) {
+	if (rates->action == CMD_ACT_GET) {
 		adapter->enablehwauto = le16_to_cpu(rates->enablehwauto);
 		adapter->ratebitmap = le16_to_cpu(rates->bitmap);
 	}
 
-	lbs_deb_enter(LBS_DEB_CMD);
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
@@ -429,21 +407,19 @@
 {
 	struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate;
 	wlan_adapter *adapter = priv->adapter;
-	u8 dot11datarate;
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	lbs_dbg_hex("DATA_RATE_RESP: data_rate- ",
-		(u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate));
+	lbs_deb_hex(LBS_DEB_CMD, "DATA_RATE_RESP", (u8 *) pdatarate,
+		sizeof(struct cmd_ds_802_11_data_rate));
 
-	dot11datarate = pdatarate->datarate[0];
-	if (pdatarate->action == cpu_to_le16(cmd_act_get_tx_rate)) {
-		memcpy(adapter->libertas_supported_rates, pdatarate->datarate,
-		       sizeof(adapter->libertas_supported_rates));
-	}
-	adapter->datarate = libertas_index_to_data_rate(dot11datarate);
+	/* FIXME: get actual rates FW can do if this command actually returns
+	 * all data rates supported.
+	 */
+	adapter->cur_rate = libertas_fw_index_to_data_rate(pdatarate->rates[0]);
+	lbs_deb_cmd("DATA_RATE: current rate 0x%02x\n", adapter->cur_rate);
 
-	lbs_deb_enter(LBS_DEB_CMD);
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
@@ -457,9 +433,9 @@
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	if (action == cmd_opt_802_11_rf_channel_get
+	if (action == CMD_OPT_802_11_RF_CHANNEL_GET
 	    && adapter->curbssparams.channel != newchannel) {
-		lbs_deb_cmd("channel Switch: %d to %d\n",
+		lbs_deb_cmd("channel switch from %d to %d\n",
 		       adapter->curbssparams.channel, newchannel);
 
 		/* Update the channel again */
@@ -476,6 +452,8 @@
 	struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp;
 	wlan_adapter *adapter = priv->adapter;
 
+	lbs_deb_enter(LBS_DEB_CMD);
+
 	/* store the non average value */
 	adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR);
 	adapter->NF[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->noisefloor);
@@ -491,9 +469,11 @@
 	    CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE,
 		     adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE);
 
-	lbs_deb_cmd("Beacon RSSI value = 0x%x\n",
+	lbs_deb_cmd("RSSI: beacon %d, avg %d\n",
+	       adapter->RSSI[TYPE_BEACON][TYPE_NOAVG],
 	       adapter->RSSI[TYPE_BEACON][TYPE_AVG]);
 
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
@@ -504,11 +484,11 @@
 	struct wlan_ioctl_regrdwr *pbuf;
 	pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom;
 
-	lbs_deb_cmd("eeprom read len=%x\n",
+	lbs_deb_enter_args(LBS_DEB_CMD, "len %d",
 	       le16_to_cpu(resp->params.rdeeprom.bytecount));
 	if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) {
 		pbuf->NOB = 0;
-		lbs_deb_cmd("eeprom read return length is too big\n");
+		lbs_deb_cmd("EEPROM read length too big\n");
 		return -1;
 	}
 	pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount);
@@ -516,9 +496,10 @@
 
 		memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value,
 		       le16_to_cpu(resp->params.rdeeprom.bytecount));
-		lbs_dbg_hex("adapter", (char *)&pbuf->value,
+		lbs_deb_hex(LBS_DEB_CMD, "EEPROM", (char *)&pbuf->value,
 			le16_to_cpu(resp->params.rdeeprom.bytecount));
 	}
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
@@ -533,7 +514,7 @@
 	/* Stored little-endian */
 	memcpy(&adapter->logmsg, logmessage, sizeof(struct cmd_ds_802_11_get_log));
 
-	lbs_deb_enter(LBS_DEB_CMD);
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
@@ -546,12 +527,12 @@
 
 	lbs_deb_enter(LBS_DEB_CMD);
 
-	if (enable_rsn->action == cpu_to_le16(cmd_act_get)) {
+	if (enable_rsn->action == cpu_to_le16(CMD_ACT_GET)) {
 		if (pdata_buf)
 			*pdata_buf = (u32) le16_to_cpu(enable_rsn->enable);
 	}
 
-	lbs_deb_enter(LBS_DEB_CMD);
+	lbs_deb_leave(LBS_DEB_CMD);
 	return 0;
 }
 
@@ -563,135 +544,134 @@
 	unsigned long flags;
 	wlan_adapter *adapter = priv->adapter;
 
+	lbs_deb_enter(LBS_DEB_HOST);
+
 	switch (respcmd) {
-	case cmd_ret_mac_reg_access:
-	case cmd_ret_bbp_reg_access:
-	case cmd_ret_rf_reg_access:
+	case CMD_RET(CMD_MAC_REG_ACCESS):
+	case CMD_RET(CMD_BBP_REG_ACCESS):
+	case CMD_RET(CMD_RF_REG_ACCESS):
 		ret = wlan_ret_reg_access(priv, respcmd, resp);
 		break;
 
-	case cmd_ret_hw_spec_info:
+	case CMD_RET(CMD_GET_HW_SPEC):
 		ret = wlan_ret_get_hw_spec(priv, resp);
 		break;
 
-	case cmd_ret_802_11_scan:
+	case CMD_RET(CMD_802_11_SCAN):
 		ret = libertas_ret_80211_scan(priv, resp);
 		break;
 
-	case cmd_ret_802_11_get_log:
+	case CMD_RET(CMD_802_11_GET_LOG):
 		ret = wlan_ret_get_log(priv, resp);
 		break;
 
-	case cmd_ret_802_11_associate:
-	case cmd_ret_802_11_reassociate:
+	case CMD_RET_802_11_ASSOCIATE:
+	case CMD_RET(CMD_802_11_ASSOCIATE):
+	case CMD_RET(CMD_802_11_REASSOCIATE):
 		ret = libertas_ret_80211_associate(priv, resp);
 		break;
 
-	case cmd_ret_802_11_disassociate:
-	case cmd_ret_802_11_deauthenticate:
+	case CMD_RET(CMD_802_11_DISASSOCIATE):
+	case CMD_RET(CMD_802_11_DEAUTHENTICATE):
 		ret = libertas_ret_80211_disassociate(priv, resp);
 		break;
 
-	case cmd_ret_802_11_ad_hoc_start:
-	case cmd_ret_802_11_ad_hoc_join:
+	case CMD_RET(CMD_802_11_AD_HOC_START):
+	case CMD_RET(CMD_802_11_AD_HOC_JOIN):
 		ret = libertas_ret_80211_ad_hoc_start(priv, resp);
 		break;
 
-	case cmd_ret_802_11_stat:
+	case CMD_RET(CMD_802_11_GET_STAT):
 		ret = wlan_ret_802_11_stat(priv, resp);
 		break;
 
-	case cmd_ret_802_11_snmp_mib:
+	case CMD_RET(CMD_802_11_SNMP_MIB):
 		ret = wlan_ret_802_11_snmp_mib(priv, resp);
 		break;
 
-	case cmd_ret_802_11_rf_tx_power:
+	case CMD_RET(CMD_802_11_RF_TX_POWER):
 		ret = wlan_ret_802_11_rf_tx_power(priv, resp);
 		break;
 
-	case cmd_ret_802_11_set_afc:
-	case cmd_ret_802_11_get_afc:
+	case CMD_RET(CMD_802_11_SET_AFC):
+	case CMD_RET(CMD_802_11_GET_AFC):
 		spin_lock_irqsave(&adapter->driver_lock, flags);
 		memmove(adapter->cur_cmd->pdata_buf, &resp->params.afc,
 			sizeof(struct cmd_ds_802_11_afc));
 		spin_unlock_irqrestore(&adapter->driver_lock, flags);
 
 		break;
-	case cmd_ret_802_11_rf_antenna:
-		ret = wlan_ret_802_11_rf_antenna(priv, resp);
+
+	case CMD_RET(CMD_MAC_MULTICAST_ADR):
+	case CMD_RET(CMD_MAC_CONTROL):
+	case CMD_RET(CMD_802_11_SET_WEP):
+	case CMD_RET(CMD_802_11_RESET):
+	case CMD_RET(CMD_802_11_AUTHENTICATE):
+	case CMD_RET(CMD_802_11_RADIO_CONTROL):
+	case CMD_RET(CMD_802_11_BEACON_STOP):
 		break;
 
-	case cmd_ret_mac_multicast_adr:
-	case cmd_ret_mac_control:
-	case cmd_ret_802_11_set_wep:
-	case cmd_ret_802_11_reset:
-	case cmd_ret_802_11_authenticate:
-	case cmd_ret_802_11_radio_control:
-	case cmd_ret_802_11_beacon_stop:
-		break;
-
-	case cmd_ret_802_11_enable_rsn:
+	case CMD_RET(CMD_802_11_ENABLE_RSN):
 		ret = libertas_ret_802_11_enable_rsn(priv, resp);
 		break;
 
-	case cmd_ret_802_11_data_rate:
+	case CMD_RET(CMD_802_11_DATA_RATE):
 		ret = wlan_ret_802_11_data_rate(priv, resp);
 		break;
-	case cmd_ret_802_11_rate_adapt_rateset:
+	case CMD_RET(CMD_802_11_RATE_ADAPT_RATESET):
 		ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp);
 		break;
-	case cmd_ret_802_11_rf_channel:
+	case CMD_RET(CMD_802_11_RF_CHANNEL):
 		ret = wlan_ret_802_11_rf_channel(priv, resp);
 		break;
 
-	case cmd_ret_802_11_rssi:
+	case CMD_RET(CMD_802_11_RSSI):
 		ret = wlan_ret_802_11_rssi(priv, resp);
 		break;
 
-	case cmd_ret_802_11_mac_address:
+	case CMD_RET(CMD_802_11_MAC_ADDRESS):
 		ret = wlan_ret_802_11_mac_address(priv, resp);
 		break;
 
-	case cmd_ret_802_11_ad_hoc_stop:
+	case CMD_RET(CMD_802_11_AD_HOC_STOP):
 		ret = libertas_ret_80211_ad_hoc_stop(priv, resp);
 		break;
 
-	case cmd_ret_802_11_key_material:
-		lbs_deb_cmd("CMD_RESP: KEY_MATERIAL command response\n");
+	case CMD_RET(CMD_802_11_KEY_MATERIAL):
 		ret = wlan_ret_802_11_key_material(priv, resp);
 		break;
 
-	case cmd_ret_802_11_eeprom_access:
+	case CMD_RET(CMD_802_11_EEPROM_ACCESS):
 		ret = wlan_ret_802_11_eeprom_access(priv, resp);
 		break;
 
-	case cmd_ret_802_11d_domain_info:
+	case CMD_RET(CMD_802_11D_DOMAIN_INFO):
 		ret = libertas_ret_802_11d_domain_info(priv, resp);
 		break;
 
-	case cmd_ret_802_11_sleep_params:
+	case CMD_RET(CMD_802_11_SLEEP_PARAMS):
 		ret = wlan_ret_802_11_sleep_params(priv, resp);
 		break;
-	case cmd_ret_802_11_inactivity_timeout:
+	case CMD_RET(CMD_802_11_INACTIVITY_TIMEOUT):
 		spin_lock_irqsave(&adapter->driver_lock, flags);
 		*((u16 *) adapter->cur_cmd->pdata_buf) =
 		    le16_to_cpu(resp->params.inactivity_timeout.timeout);
 		spin_unlock_irqrestore(&adapter->driver_lock, flags);
 		break;
 
-	case cmd_ret_802_11_tpc_cfg:
+	case CMD_RET(CMD_802_11_TPC_CFG):
 		spin_lock_irqsave(&adapter->driver_lock, flags);
 		memmove(adapter->cur_cmd->pdata_buf, &resp->params.tpccfg,
 			sizeof(struct cmd_ds_802_11_tpc_cfg));
 		spin_unlock_irqrestore(&adapter->driver_lock, flags);
 		break;
-	case cmd_ret_802_11_led_gpio_ctrl:
+	case CMD_RET(CMD_802_11_LED_GPIO_CTRL):
 		spin_lock_irqsave(&adapter->driver_lock, flags);
 		memmove(adapter->cur_cmd->pdata_buf, &resp->params.ledgpio,
 			sizeof(struct cmd_ds_802_11_led_ctrl));
 		spin_unlock_irqrestore(&adapter->driver_lock, flags);
 		break;
-	case cmd_ret_802_11_pwr_cfg:
+	case CMD_RET(CMD_802_11_PWR_CFG):
 		spin_lock_irqsave(&adapter->driver_lock, flags);
 		memmove(adapter->cur_cmd->pdata_buf, &resp->params.pwrcfg,
 			sizeof(struct cmd_ds_802_11_pwr_cfg));
@@ -699,39 +679,37 @@
 
 		break;
 
-	case cmd_ret_get_tsf:
+	case CMD_RET(CMD_GET_TSF):
 		spin_lock_irqsave(&adapter->driver_lock, flags);
 		memcpy(priv->adapter->cur_cmd->pdata_buf,
 		       &resp->params.gettsf.tsfvalue, sizeof(u64));
 		spin_unlock_irqrestore(&adapter->driver_lock, flags);
 		break;
-	case cmd_ret_bt_access:
+	case CMD_RET(CMD_BT_ACCESS):
 		spin_lock_irqsave(&adapter->driver_lock, flags);
 		if (adapter->cur_cmd->pdata_buf)
 			memcpy(adapter->cur_cmd->pdata_buf,
 			       &resp->params.bt.addr1, 2 * ETH_ALEN);
 		spin_unlock_irqrestore(&adapter->driver_lock, flags);
 		break;
-	case cmd_ret_fwt_access:
+	case CMD_RET(CMD_FWT_ACCESS):
 		spin_lock_irqsave(&adapter->driver_lock, flags);
 		if (adapter->cur_cmd->pdata_buf)
 			memcpy(adapter->cur_cmd->pdata_buf, &resp->params.fwt,
 			       sizeof(resp->params.fwt));
 		spin_unlock_irqrestore(&adapter->driver_lock, flags);
 		break;
-	case cmd_ret_mesh_access:
+	case CMD_RET(CMD_MESH_ACCESS):
 		if (adapter->cur_cmd->pdata_buf)
 			memcpy(adapter->cur_cmd->pdata_buf, &resp->params.mesh,
 			       sizeof(resp->params.mesh));
 		break;
-	case cmd_rte_802_11_tx_rate_query:
-		priv->adapter->txrate = resp->params.txrate.txrate;
-		break;
 	default:
-		lbs_deb_cmd("CMD_RESP: Unknown command response %#x\n",
+		lbs_deb_host("CMD_RESP: unknown cmd response 0x%04x\n",
 			    resp->command);
 		break;
 	}
+	lbs_deb_leave(LBS_DEB_HOST);
 	return ret;
 }
 
@@ -744,9 +722,7 @@
 	ulong flags;
 	u16 result;
 
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	lbs_deb_cmd("CMD_RESP: @ %lu\n", jiffies);
+	lbs_deb_enter(LBS_DEB_HOST);
 
 	/* Now we got response from FW, cancel the command timer */
 	del_timer(&adapter->command_timer);
@@ -755,25 +731,23 @@
 	spin_lock_irqsave(&adapter->driver_lock, flags);
 
 	if (!adapter->cur_cmd) {
-		lbs_deb_cmd("CMD_RESP: NULL cur_cmd=%p\n", adapter->cur_cmd);
+		lbs_deb_host("CMD_RESP: cur_cmd is NULL\n");
 		ret = -1;
 		spin_unlock_irqrestore(&adapter->driver_lock, flags);
 		goto done;
 	}
 	resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr);
 
-	lbs_dbg_hex("CMD_RESP:", adapter->cur_cmd->bufvirtualaddr,
-		    priv->upld_len);
-
 	respcmd = le16_to_cpu(resp->command);
-
 	result = le16_to_cpu(resp->result);
 
-	lbs_deb_cmd("CMD_RESP: %x result: %d length: %d\n", respcmd,
-		    result, priv->upld_len);
+	lbs_deb_host("CMD_RESP: response 0x%04x, size %d, jiffies %lu\n",
+		respcmd, priv->upld_len, jiffies);
+	lbs_deb_hex(LBS_DEB_HOST, "CMD_RESP", adapter->cur_cmd->bufvirtualaddr,
+		    priv->upld_len);
 
 	if (!(respcmd & 0x8000)) {
-		lbs_deb_cmd("Invalid response to command!");
+		lbs_deb_host("invalid response!\n");
 		adapter->cur_cmd_retcode = -1;
 		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
 		adapter->nr_cmd_pending--;
@@ -786,16 +760,16 @@
 	/* Store the response code to cur_cmd_retcode. */
 	adapter->cur_cmd_retcode = result;;
 
-	if (respcmd == cmd_ret_802_11_ps_mode) {
+	if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
 		struct cmd_ds_802_11_ps_mode *psmode = &resp->params.psmode;
 		u16 action = le16_to_cpu(psmode->action);
 
-		lbs_deb_cmd(
-		       "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n",
+		lbs_deb_host(
+		       "CMD_RESP: PS_MODE cmd reply result 0x%x, action 0x%x\n",
 		       result, action);
 
 		if (result) {
-			lbs_deb_cmd("CMD_RESP: PS command failed- %#x \n",
+			lbs_deb_host("CMD_RESP: PS command failed with 0x%x\n",
 				    result);
 			/*
 			 * We should not re-try enter-ps command in
@@ -803,20 +777,20 @@
 			 * libertas_execute_next_command().
 			 */
 			if (adapter->mode == IW_MODE_ADHOC &&
-			    action == cmd_subcmd_enter_ps)
-				adapter->psmode = wlan802_11powermodecam;
-		} else if (action == cmd_subcmd_enter_ps) {
+			    action == CMD_SUBCMD_ENTER_PS)
+				adapter->psmode = WLAN802_11POWERMODECAM;
+		} else if (action == CMD_SUBCMD_ENTER_PS) {
 			adapter->needtowakeup = 0;
 			adapter->psstate = PS_STATE_AWAKE;
 
-			lbs_deb_cmd("CMD_RESP: Enter_PS command response\n");
-			if (adapter->connect_status != libertas_connected) {
+			lbs_deb_host("CMD_RESP: ENTER_PS command response\n");
+			if (adapter->connect_status != LIBERTAS_CONNECTED) {
 				/*
 				 * When Deauth Event received before Enter_PS command
 				 * response, We need to wake up the firmware.
 				 */
-				lbs_deb_cmd(
-				       "Disconnected, Going to invoke libertas_ps_wakeup\n");
+				lbs_deb_host(
+				       "disconnected, invoking libertas_ps_wakeup\n");
 
 				spin_unlock_irqrestore(&adapter->driver_lock, flags);
 				mutex_unlock(&adapter->lock);
@@ -824,12 +798,12 @@
 				mutex_lock(&adapter->lock);
 				spin_lock_irqsave(&adapter->driver_lock, flags);
 			}
-		} else if (action == cmd_subcmd_exit_ps) {
+		} else if (action == CMD_SUBCMD_EXIT_PS) {
 			adapter->needtowakeup = 0;
 			adapter->psstate = PS_STATE_FULL_POWER;
-			lbs_deb_cmd("CMD_RESP: Exit_PS command response\n");
+			lbs_deb_host("CMD_RESP: EXIT_PS command response\n");
 		} else {
-			lbs_deb_cmd("CMD_RESP: PS- action=0x%X\n", action);
+			lbs_deb_host("CMD_RESP: PS action 0x%X\n", action);
 		}
 
 		__libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd);
@@ -843,22 +817,22 @@
 
 	if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) {
 		/* Copy the response back to response buffer */
-		memcpy(adapter->cur_cmd->pdata_buf, resp, resp->size);
-
+		memcpy(adapter->cur_cmd->pdata_buf, resp,
+		       le16_to_cpu(resp->size));
 		adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD;
 	}
 
 	/* If the command is not successful, cleanup and return failure */
 	if ((result != 0 || !(respcmd & 0x8000))) {
-		lbs_deb_cmd("CMD_RESP: command reply %#x result=%#x\n",
-		       respcmd, result);
+		lbs_deb_host("CMD_RESP: error 0x%04x in command reply 0x%04x\n",
+		       result, respcmd);
 		/*
 		 * Handling errors here
 		 */
 		switch (respcmd) {
-		case cmd_ret_hw_spec_info:
-		case cmd_ret_802_11_reset:
-			lbs_deb_cmd("CMD_RESP: Reset command failed\n");
+		case CMD_RET(CMD_GET_HW_SPEC):
+		case CMD_RET(CMD_802_11_RESET):
+			lbs_deb_host("CMD_RESP: reset failed\n");
 			break;
 
 		}
@@ -888,7 +862,7 @@
 
 done:
 	mutex_unlock(&adapter->lock);
-	lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret);
+	lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
 	return ret;
 }
 
@@ -898,13 +872,13 @@
 	wlan_adapter *adapter = priv->adapter;
 	u32 eventcause;
 
+	lbs_deb_enter(LBS_DEB_CMD);
+
 	spin_lock_irq(&adapter->driver_lock);
 	eventcause = adapter->eventcause;
 	spin_unlock_irq(&adapter->driver_lock);
 
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	lbs_deb_cmd("EVENT Cause %x\n", eventcause);
+	lbs_deb_cmd("event cause 0x%x\n", eventcause);
 
 	switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) {
 	case MACREG_INT_CODE_LINK_SENSED:
@@ -912,28 +886,27 @@
 		break;
 
 	case MACREG_INT_CODE_DEAUTHENTICATED:
-		lbs_deb_cmd("EVENT: Deauthenticated\n");
+		lbs_deb_cmd("EVENT: deauthenticated\n");
 		libertas_mac_event_disconnected(priv);
 		break;
 
 	case MACREG_INT_CODE_DISASSOCIATED:
-		lbs_deb_cmd("EVENT: Disassociated\n");
+		lbs_deb_cmd("EVENT: disassociated\n");
 		libertas_mac_event_disconnected(priv);
 		break;
 
 	case MACREG_INT_CODE_LINK_LOSE_NO_SCAN:
-		lbs_deb_cmd("EVENT: Link lost\n");
+		lbs_deb_cmd("EVENT: link lost\n");
 		libertas_mac_event_disconnected(priv);
 		break;
 
 	case MACREG_INT_CODE_PS_SLEEP:
-		lbs_deb_cmd("EVENT: SLEEP\n");
-		lbs_deb_cmd("_");
+		lbs_deb_cmd("EVENT: sleep\n");
 
 		/* handle unexpected PS SLEEP event */
 		if (adapter->psstate == PS_STATE_FULL_POWER) {
 			lbs_deb_cmd(
-			       "EVENT: In FULL POWER mode - ignore PS SLEEP\n");
+			       "EVENT: in FULL POWER mode, ignoreing PS_SLEEP\n");
 			break;
 		}
 		adapter->psstate = PS_STATE_PRE_SLEEP;
@@ -943,8 +916,7 @@
 		break;
 
 	case MACREG_INT_CODE_PS_AWAKE:
-		lbs_deb_cmd("EVENT: AWAKE \n");
-		lbs_deb_cmd("|");
+		lbs_deb_cmd("EVENT: awake\n");
 
 		/* handle unexpected PS AWAKE event */
 		if (adapter->psstate == PS_STATE_FULL_POWER) {
@@ -962,7 +934,7 @@
 			 * adapter->needtowakeup will be set to FALSE
 			 * in libertas_ps_wakeup()
 			 */
-			lbs_deb_cmd("Waking up...\n");
+			lbs_deb_cmd("waking up ...\n");
 			libertas_ps_wakeup(priv, 0);
 		}
 		break;
@@ -981,38 +953,43 @@
 		break;
 
 	case MACREG_INT_CODE_ADHOC_BCN_LOST:
-		lbs_deb_cmd("EVENT: HWAC - ADHOC BCN LOST\n");
+		lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
 		break;
 
 	case MACREG_INT_CODE_RSSI_LOW:
-		lbs_pr_alert( "EVENT: RSSI_LOW\n");
+		lbs_pr_alert("EVENT: rssi low\n");
 		break;
 	case MACREG_INT_CODE_SNR_LOW:
-		lbs_pr_alert( "EVENT: SNR_LOW\n");
+		lbs_pr_alert("EVENT: snr low\n");
 		break;
 	case MACREG_INT_CODE_MAX_FAIL:
-		lbs_pr_alert( "EVENT: MAX_FAIL\n");
+		lbs_pr_alert("EVENT: max fail\n");
 		break;
 	case MACREG_INT_CODE_RSSI_HIGH:
-		lbs_pr_alert( "EVENT: RSSI_HIGH\n");
+		lbs_pr_alert("EVENT: rssi high\n");
 		break;
 	case MACREG_INT_CODE_SNR_HIGH:
-		lbs_pr_alert( "EVENT: SNR_HIGH\n");
+		lbs_pr_alert("EVENT: snr high\n");
 		break;
 
 	case MACREG_INT_CODE_MESH_AUTO_STARTED:
-		lbs_pr_alert( "EVENT: MESH_AUTO_STARTED\n");
-		adapter->connect_status = libertas_connected ;
-		if (priv->mesh_open == 1) {
-			netif_wake_queue(priv->mesh_dev) ;
-			netif_carrier_on(priv->mesh_dev) ;
+		/* Ignore spurious autostart events if autostart is disabled */
+		if (!priv->mesh_autostart_enabled) {
+			lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
+			break;
 		}
-		adapter->mode = IW_MODE_ADHOC ;
+		lbs_pr_info("EVENT: MESH_AUTO_STARTED\n");
+		adapter->connect_status = LIBERTAS_CONNECTED;
+		if (priv->mesh_open == 1) {
+			netif_wake_queue(priv->mesh_dev);
+			netif_carrier_on(priv->mesh_dev);
+		}
+		adapter->mode = IW_MODE_ADHOC;
 		schedule_work(&priv->sync_channel);
 		break;
 
 	default:
-		lbs_pr_alert( "EVENT: unknown event id: %#x\n",
+		lbs_pr_alert("EVENT: unknown event id 0x%04x\n",
 		       eventcause >> SBI_EVENT_CAUSE_SHIFT);
 		break;
 	}
@@ -1021,6 +998,6 @@
 	adapter->eventcause = 0;
 	spin_unlock_irq(&adapter->driver_lock);
 
-	lbs_deb_enter_args(LBS_DEB_CMD, "ret %d", ret);
+	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
 	return ret;
 }
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 715cbda..0bda0b5 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -3,6 +3,7 @@
 #include <linux/debugfs.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
+#include <linux/string.h>
 #include <net/iw_handler.h>
 
 #include "dev.h"
@@ -63,27 +64,27 @@
 	int numscansdone = 0, res;
 	unsigned long addr = get_zeroed_page(GFP_KERNEL);
 	char *buf = (char *)addr;
+	DECLARE_MAC_BUF(mac);
 	struct bss_descriptor * iter_bss;
 
 	pos += snprintf(buf+pos, len-pos,
-		"# | ch  | ss  |       bssid       |   cap    |    TSF   | Qual | SSID \n");
+		"# | ch  | rssi |       bssid       |   cap    | Qual | SSID \n");
 
 	mutex_lock(&priv->adapter->lock);
 	list_for_each_entry (iter_bss, &priv->adapter->network_list, list) {
-		u16 cap;
+		u16 ibss = (iter_bss->capability & WLAN_CAPABILITY_IBSS);
+		u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY);
+		u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT);
 
-		memcpy(&cap, &iter_bss->cap, sizeof(cap));
 		pos += snprintf(buf+pos, len-pos,
-			"%02u| %03d | %03ld | " MAC_FMT " |",
+			"%02u| %03d | %04ld | %s |",
 			numscansdone, iter_bss->channel, iter_bss->rssi,
-			MAC_ARG(iter_bss->bssid));
-		pos += snprintf(buf+pos, len-pos, " %04x-", cap);
+			print_mac(mac, iter_bss->bssid));
+		pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability);
 		pos += snprintf(buf+pos, len-pos, "%c%c%c |",
-				iter_bss->cap.ibss ? 'A' : 'I',
-				iter_bss->cap.privacy ? 'P' : ' ',
-				iter_bss->cap.spectrummgmt ? 'S' : ' ');
-		pos += snprintf(buf+pos, len-pos, " %08llx |", iter_bss->networktsf);
-		pos += snprintf(buf+pos, len-pos, " %d |", SCAN_RSSI(iter_bss->rssi));
+				ibss ? 'A' : 'I', privacy ? 'P' : ' ',
+				spectrum_mgmt ? 'S' : ' ');
+		pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi));
 		pos += snprintf(buf+pos, len-pos, " %s\n",
 		                escape_essid(iter_bss->ssid, iter_bss->ssid_len));
 
@@ -125,9 +126,9 @@
 	priv->adapter->sp.sp_reserved = p6;
 
         res = libertas_prepare_and_send_command(priv,
-				cmd_802_11_sleep_params,
-				cmd_act_set,
-				cmd_option_waitforrsp, 0, NULL);
+				CMD_802_11_SLEEP_PARAMS,
+				CMD_ACT_SET,
+				CMD_OPTION_WAITFORRSP, 0, NULL);
 
 	if (!res)
 		res = count;
@@ -150,9 +151,9 @@
 	char *buf = (char *)addr;
 
         res = libertas_prepare_and_send_command(priv,
-				cmd_802_11_sleep_params,
-				cmd_act_get,
-				cmd_option_waitforrsp, 0, NULL);
+				CMD_802_11_SLEEP_PARAMS,
+				CMD_ACT_GET,
+				CMD_OPTION_WAITFORRSP, 0, NULL);
 	if (res) {
 		res = -EFAULT;
 		goto out_unlock;
@@ -205,7 +206,7 @@
 	if (!start)
 		return -EINVAL;
 	start += 5;
-	end = strstr(start, " ");
+	end = strchr(start, ' ');
 	if (!end)
 		end = buf + count;
 	hold = kzalloc((end - start)+1, GFP_KERNEL);
@@ -256,7 +257,7 @@
 	if (!hold)
 		return;
 	hold += 5;
-	end = strstr(hold, " ");
+	end = strchr(hold, ' ');
 	if (!end)
 		end = buf + count - 1;
 
@@ -386,7 +387,7 @@
 			struct cmd_ctrl_node **cmdnode,
 			struct cmd_ds_command **cmd)
 {
-	u16 wait_option = cmd_option_waitforrsp;
+	u16 wait_option = CMD_OPTION_WAITFORRSP;
 
 	if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) {
 		lbs_deb_debugfs("failed libertas_get_free_cmd_ctrl_node\n");
@@ -402,7 +403,7 @@
 	(*cmdnode)->cmdflags |= CMD_F_HOSTCMD;
 	(*cmdnode)->cmdwaitqwoken = 0;
 	*cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr;
-	(*cmd)->command = cpu_to_le16(cmd_802_11_subscribe_event);
+	(*cmd)->command = cpu_to_le16(CMD_802_11_SUBSCRIBE_EVENT);
 	(*cmd)->seqnum = cpu_to_le16(++priv->adapter->seqnum);
 	(*cmd)->result = 0;
 	return 0;
@@ -429,10 +430,10 @@
 	}
 
 	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(cmd_act_get);
+	event->action = cpu_to_le16(CMD_ACT_GET);
 	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
 	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->mainthread.waitq);
+	wake_up_interruptible(&priv->waitq);
 
 	/* Sleep until response is generated by FW */
 	wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -447,7 +448,7 @@
 		return 0;
 	}
 
-	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
 		lbs_pr_err("command response incorrect!\n");
 		kfree(response_buf);
 		free_page(addr);
@@ -493,10 +494,10 @@
 		return res;
 
 	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(cmd_act_get);
+	event->action = cpu_to_le16(CMD_ACT_GET);
 	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
 	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->mainthread.waitq);
+	wake_up_interruptible(&priv->waitq);
 
 	/* Sleep until response is generated by FW */
 	wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -511,7 +512,7 @@
 		return 0;
 	}
 
-	if (pcmdptr->command != cmd_ret_802_11_subscribe_event) {
+	if (le16_to_cpu(pcmdptr->command) != CMD_RET(CMD_802_11_SUBSCRIBE_EVENT)) {
 		lbs_pr_err("command response incorrect!\n");
 		kfree(response_buf);
 		return 0;
@@ -559,7 +560,7 @@
 		goto out_unlock;
 
 	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(cmd_act_set);
+	event->action = cpu_to_le16(CMD_ACT_SET);
 	pcmdptr->size = cpu_to_le16(S_DS_GEN +
 		sizeof(struct cmd_ds_802_11_subscribe_event) +
 		sizeof(struct mrvlietypes_rssithreshold));
@@ -575,7 +576,7 @@
 	event->events = cpu_to_le16(event_bitmap);
 
 	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->mainthread.waitq);
+	wake_up_interruptible(&priv->waitq);
 
 	/* Sleep until response is generated by FW */
 	wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -591,7 +592,7 @@
 		return 0;
 	}
 
-	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
 		lbs_pr_err("command response incorrect!\n");
 		kfree(response_buf);
 		free_page(addr);
@@ -625,10 +626,10 @@
 	}
 
 	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(cmd_act_get);
+	event->action = cpu_to_le16(CMD_ACT_GET);
 	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
 	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->mainthread.waitq);
+	wake_up_interruptible(&priv->waitq);
 
 	/* Sleep until response is generated by FW */
 	wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -644,7 +645,7 @@
 		return 0;
 	}
 
-	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
 		lbs_pr_err("command response incorrect!\n");
 		kfree(response_buf);
 		free_page(addr);
@@ -712,7 +713,7 @@
 		goto out_unlock;
 
 	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(cmd_act_set);
+	event->action = cpu_to_le16(CMD_ACT_SET);
 	pcmdptr->size = cpu_to_le16(S_DS_GEN +
 		sizeof(struct cmd_ds_802_11_subscribe_event) +
 		sizeof(struct mrvlietypes_snrthreshold));
@@ -727,7 +728,7 @@
 	event->events = cpu_to_le16(event_bitmap);
 
 	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->mainthread.waitq);
+	wake_up_interruptible(&priv->waitq);
 
 	/* Sleep until response is generated by FW */
 	wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -743,7 +744,7 @@
 		return 0;
 	}
 
-	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
 		lbs_pr_err("command response incorrect!\n");
 		kfree(response_buf);
 		free_page(addr);
@@ -778,10 +779,10 @@
 	}
 
 	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(cmd_act_get);
+	event->action = cpu_to_le16(CMD_ACT_GET);
 	pcmdptr->size =	cpu_to_le16(sizeof(*event) + S_DS_GEN);
 	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->mainthread.waitq);
+	wake_up_interruptible(&priv->waitq);
 
 	/* Sleep until response is generated by FW */
 	wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -797,7 +798,7 @@
 		return 0;
 	}
 
-	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
 		lbs_pr_err("command response incorrect!\n");
 		kfree(response_buf);
 		free_page(addr);
@@ -864,7 +865,7 @@
 		goto out_unlock;
 
 	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(cmd_act_set);
+	event->action = cpu_to_le16(CMD_ACT_SET);
 	pcmdptr->size = cpu_to_le16(S_DS_GEN +
 		sizeof(struct cmd_ds_802_11_subscribe_event) +
 		sizeof(struct mrvlietypes_failurecount));
@@ -879,7 +880,7 @@
 	event->events = cpu_to_le16(event_bitmap);
 
 	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->mainthread.waitq);
+	wake_up_interruptible(&priv->waitq);
 
 	/* Sleep until response is generated by FW */
 	wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -895,7 +896,7 @@
 		return 0;
 	}
 
-	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
 		lbs_pr_err("command response incorrect!\n");
 		kfree(response_buf);
 		free_page(addr);
@@ -929,10 +930,10 @@
 	}
 
 	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(cmd_act_get);
+	event->action = cpu_to_le16(CMD_ACT_GET);
 	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
 	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->mainthread.waitq);
+	wake_up_interruptible(&priv->waitq);
 
 	/* Sleep until response is generated by FW */
 	wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -948,7 +949,7 @@
 		return 0;
 	}
 
-	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
 		lbs_pr_err("command response incorrect!\n");
 		free_page(addr);
 		kfree(response_buf);
@@ -1015,7 +1016,7 @@
 		goto out_unlock;
 
 	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(cmd_act_set);
+	event->action = cpu_to_le16(CMD_ACT_SET);
 	pcmdptr->size = cpu_to_le16(S_DS_GEN +
 		sizeof(struct cmd_ds_802_11_subscribe_event) +
 		sizeof(struct mrvlietypes_beaconsmissed));
@@ -1029,7 +1030,7 @@
 	event->events = cpu_to_le16(event_bitmap);
 
 	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->mainthread.waitq);
+	wake_up_interruptible(&priv->waitq);
 
 	/* Sleep until response is generated by FW */
 	wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -1045,7 +1046,7 @@
 		return 0;
 	}
 
-	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
 		lbs_pr_err("command response incorrect!\n");
 		free_page(addr);
 		kfree(response_buf);
@@ -1079,10 +1080,10 @@
 	}
 
 	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(cmd_act_get);
+	event->action = cpu_to_le16(CMD_ACT_GET);
 	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
 	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->mainthread.waitq);
+	wake_up_interruptible(&priv->waitq);
 
 	/* Sleep until response is generated by FW */
 	wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -1098,7 +1099,7 @@
 		return 0;
 	}
 
-	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
 		lbs_pr_err("command response incorrect!\n");
 		kfree(response_buf);
 		free_page(addr);
@@ -1166,7 +1167,7 @@
 		goto out_unlock;
 
 	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(cmd_act_set);
+	event->action = cpu_to_le16(CMD_ACT_SET);
 	pcmdptr->size = cpu_to_le16(S_DS_GEN +
 		sizeof(struct cmd_ds_802_11_subscribe_event) +
 		sizeof(struct mrvlietypes_rssithreshold));
@@ -1181,7 +1182,7 @@
 	event->events = cpu_to_le16(event_bitmap);
 
 	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->mainthread.waitq);
+	wake_up_interruptible(&priv->waitq);
 
 	/* Sleep until response is generated by FW */
 	wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -1196,7 +1197,7 @@
 		return 0;
 	}
 
-	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
 		lbs_pr_err("command response incorrect!\n");
 		kfree(response_buf);
 		return 0;
@@ -1229,10 +1230,10 @@
 	}
 
 	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(cmd_act_get);
+	event->action = cpu_to_le16(CMD_ACT_GET);
 	pcmdptr->size = cpu_to_le16(sizeof(*event) + S_DS_GEN);
 	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->mainthread.waitq);
+	wake_up_interruptible(&priv->waitq);
 
 	/* Sleep until response is generated by FW */
 	wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -1248,7 +1249,7 @@
 		return 0;
 	}
 
-	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
 		lbs_pr_err("command response incorrect!\n");
 		kfree(response_buf);
 		free_page(addr);
@@ -1316,7 +1317,7 @@
 		goto out_unlock;
 
 	event = &pcmdptr->params.subscribe_event;
-	event->action = cpu_to_le16(cmd_act_set);
+	event->action = cpu_to_le16(CMD_ACT_SET);
 	pcmdptr->size = cpu_to_le16(S_DS_GEN +
 		sizeof(struct cmd_ds_802_11_subscribe_event) +
 		sizeof(struct mrvlietypes_snrthreshold));
@@ -1331,7 +1332,7 @@
 	event->events = cpu_to_le16(event_bitmap);
 
 	libertas_queue_cmd(adapter, pcmdnode, 1);
-	wake_up_interruptible(&priv->mainthread.waitq);
+	wake_up_interruptible(&priv->waitq);
 
 	/* Sleep until response is generated by FW */
 	wait_event_interruptible(pcmdnode->cmdwait_q,
@@ -1347,7 +1348,7 @@
 		return 0;
 	}
 
-	if (pcmdptr->command != cpu_to_le16(cmd_ret_802_11_subscribe_event)) {
+	if (pcmdptr->command != cpu_to_le16(CMD_RET(CMD_802_11_SUBSCRIBE_EVENT))) {
 		lbs_pr_err("command response incorrect!\n");
 		kfree(response_buf);
 		free_page(addr);
@@ -1375,8 +1376,8 @@
 	offval.value = 0;
 
 	ret = libertas_prepare_and_send_command(priv,
-				cmd_mac_reg_access, 0,
-				cmd_option_waitforrsp, 0, &offval);
+				CMD_MAC_REG_ACCESS, 0,
+				CMD_OPTION_WAITFORRSP, 0, &offval);
 	mdelay(10);
 	pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n",
 				priv->mac_offset, adapter->offsetvalue.value);
@@ -1433,8 +1434,8 @@
 	offval.offset = offset;
 	offval.value = value;
 	res = libertas_prepare_and_send_command(priv,
-				cmd_mac_reg_access, 1,
-				cmd_option_waitforrsp, 0, &offval);
+				CMD_MAC_REG_ACCESS, 1,
+				CMD_OPTION_WAITFORRSP, 0, &offval);
 	mdelay(10);
 
 	res = count;
@@ -1458,8 +1459,8 @@
 	offval.value = 0;
 
 	ret = libertas_prepare_and_send_command(priv,
-				cmd_bbp_reg_access, 0,
-				cmd_option_waitforrsp, 0, &offval);
+				CMD_BBP_REG_ACCESS, 0,
+				CMD_OPTION_WAITFORRSP, 0, &offval);
 	mdelay(10);
 	pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n",
 				priv->bbp_offset, adapter->offsetvalue.value);
@@ -1517,8 +1518,8 @@
 	offval.offset = offset;
 	offval.value = value;
 	res = libertas_prepare_and_send_command(priv,
-				cmd_bbp_reg_access, 1,
-				cmd_option_waitforrsp, 0, &offval);
+				CMD_BBP_REG_ACCESS, 1,
+				CMD_OPTION_WAITFORRSP, 0, &offval);
 	mdelay(10);
 
 	res = count;
@@ -1542,8 +1543,8 @@
 	offval.value = 0;
 
 	ret = libertas_prepare_and_send_command(priv,
-				cmd_rf_reg_access, 0,
-				cmd_option_waitforrsp, 0, &offval);
+				CMD_RF_REG_ACCESS, 0,
+				CMD_OPTION_WAITFORRSP, 0, &offval);
 	mdelay(10);
 	pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n",
 				priv->rf_offset, adapter->offsetvalue.value);
@@ -1601,8 +1602,8 @@
 	offval.offset = offset;
 	offval.value = value;
 	res = libertas_prepare_and_send_command(priv,
-				cmd_rf_reg_access, 1,
-				cmd_option_waitforrsp, 0, &offval);
+				CMD_RF_REG_ACCESS, 1,
+				CMD_OPTION_WAITFORRSP, 0, &offval);
 	mdelay(10);
 
 	res = count;
@@ -1839,7 +1840,7 @@
 	char *p2;
 	struct debug_data *d = (struct debug_data *)f->private_data;
 
-	pdata = (char *)kmalloc(cnt, GFP_KERNEL);
+	pdata = kmalloc(cnt, GFP_KERNEL);
 	if (pdata == NULL)
 		return 0;
 
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 40f56bb..87fea9d 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -15,14 +15,9 @@
 struct sk_buff;
 struct net_device;
 
-extern char *libertas_fw_name;
-
-void libertas_free_adapter(wlan_private * priv);
 int libertas_set_mac_packet_filter(wlan_private * priv);
 
-int libertas_send_null_packet(wlan_private * priv, u8 pwr_mgmt);
 void libertas_send_tx_feedback(wlan_private * priv);
-u8 libertas_check_last_packet_indication(wlan_private * priv);
 
 int libertas_free_cmd_buffer(wlan_private * priv);
 struct cmd_ctrl_node;
@@ -44,8 +39,8 @@
 int libertas_process_event(wlan_private * priv);
 void libertas_interrupt(struct net_device *);
 int libertas_set_radio_control(wlan_private * priv);
-u32 libertas_index_to_data_rate(u8 index);
-u8 libertas_data_rate_to_index(u32 rate);
+u32 libertas_fw_index_to_data_rate(u8 index);
+u8 libertas_data_rate_to_fw_index(u32 rate);
 void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen);
 
 void libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb);
@@ -53,8 +48,6 @@
 /** The proc fs interface */
 int libertas_process_rx_command(wlan_private * priv);
 int libertas_process_tx(wlan_private * priv, struct sk_buff *skb);
-void libertas_cleanup_and_insert_cmd(wlan_private * priv,
-					struct cmd_ctrl_node *ptempcmd);
 void __libertas_cleanup_and_insert_cmd(wlan_private * priv,
 					struct cmd_ctrl_node *ptempcmd);
 
@@ -75,17 +68,15 @@
 
 void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str);
 
-/* fw.c */
-int libertas_init_fw(wlan_private * priv, char *fw_name);
-
 /* main.c */
 struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band,
 						             int *cfp_no);
 wlan_private *libertas_add_card(void *card, struct device *dmdev);
-int libertas_activate_card(wlan_private *priv, char *fw_name);
 int libertas_remove_card(wlan_private *priv);
+int libertas_start_card(wlan_private *priv);
+int libertas_stop_card(wlan_private *priv);
 int libertas_add_mesh(wlan_private *priv, struct device *dev);
 void libertas_remove_mesh(wlan_private *priv);
-
+int libertas_reset_device(wlan_private *priv);
 
 #endif				/* _WLAN_DECL_H_ */
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 4dd43e5..7c5b7f7b 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -43,43 +43,43 @@
 extern unsigned int libertas_debug;
 
 #ifdef DEBUG
-#define LBS_DEB_LL(grp, fmt, args...) \
+#define LBS_DEB_LL(grp, grpnam, fmt, args...) \
 do { if ((libertas_debug & (grp)) == (grp)) \
-  printk(KERN_DEBUG DRV_NAME "%s: " fmt, \
+  printk(KERN_DEBUG DRV_NAME grpnam "%s: " fmt, \
          in_interrupt() ? " (INT)" : "", ## args); } while (0)
 #else
-#define LBS_DEB_LL(grp, fmt, args...) do {} while (0)
+#define LBS_DEB_LL(grp, grpnam, fmt, args...) do {} while (0)
 #endif
 
 #define lbs_deb_enter(grp) \
-  LBS_DEB_LL(grp | LBS_DEB_ENTER, "%s():%d enter\n", __FUNCTION__, __LINE__);
+  LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s():%d\n", __FUNCTION__, __LINE__);
 #define lbs_deb_enter_args(grp, fmt, args...) \
-  LBS_DEB_LL(grp | LBS_DEB_ENTER, "%s(" fmt "):%d\n", __FUNCTION__, ## args, __LINE__);
+  LBS_DEB_LL(grp | LBS_DEB_ENTER, " enter", "%s(" fmt "):%d\n", __FUNCTION__, ## args, __LINE__);
 #define lbs_deb_leave(grp) \
-  LBS_DEB_LL(grp | LBS_DEB_LEAVE, "%s():%d leave\n", __FUNCTION__, __LINE__);
+  LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d\n", __FUNCTION__, __LINE__);
 #define lbs_deb_leave_args(grp, fmt, args...) \
-  LBS_DEB_LL(grp | LBS_DEB_LEAVE, "%s():%d leave, " fmt "\n", \
+  LBS_DEB_LL(grp | LBS_DEB_LEAVE, " leave", "%s():%d, " fmt "\n", \
   __FUNCTION__, __LINE__, ##args);
-#define lbs_deb_main(fmt, args...)      LBS_DEB_LL(LBS_DEB_MAIN, fmt, ##args)
-#define lbs_deb_net(fmt, args...)       LBS_DEB_LL(LBS_DEB_NET, fmt, ##args)
-#define lbs_deb_mesh(fmt, args...)      LBS_DEB_LL(LBS_DEB_MESH, fmt, ##args)
-#define lbs_deb_wext(fmt, args...)      LBS_DEB_LL(LBS_DEB_WEXT, fmt, ##args)
-#define lbs_deb_ioctl(fmt, args...)     LBS_DEB_LL(LBS_DEB_IOCTL, fmt, ##args)
-#define lbs_deb_scan(fmt, args...)      LBS_DEB_LL(LBS_DEB_SCAN, fmt, ##args)
-#define lbs_deb_assoc(fmt, args...)     LBS_DEB_LL(LBS_DEB_ASSOC, fmt, ##args)
-#define lbs_deb_join(fmt, args...)      LBS_DEB_LL(LBS_DEB_JOIN, fmt, ##args)
-#define lbs_deb_11d(fmt, args...)       LBS_DEB_LL(LBS_DEB_11D, fmt, ##args)
-#define lbs_deb_debugfs(fmt, args...)   LBS_DEB_LL(LBS_DEB_DEBUGFS, fmt, ##args)
-#define lbs_deb_ethtool(fmt, args...)   LBS_DEB_LL(LBS_DEB_ETHTOOL, fmt, ##args)
-#define lbs_deb_host(fmt, args...)      LBS_DEB_LL(LBS_DEB_HOST, fmt, ##args)
-#define lbs_deb_cmd(fmt, args...)       LBS_DEB_LL(LBS_DEB_CMD, fmt, ##args)
-#define lbs_deb_rx(fmt, args...)        LBS_DEB_LL(LBS_DEB_RX, fmt, ##args)
-#define lbs_deb_tx(fmt, args...)        LBS_DEB_LL(LBS_DEB_TX, fmt, ##args)
-#define lbs_deb_fw(fmt, args...)        LBS_DEB_LL(LBS_DEB_FW, fmt, ##args)
-#define lbs_deb_usb(fmt, args...)       LBS_DEB_LL(LBS_DEB_USB, fmt, ##args)
-#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, "%s:" fmt, (dev)->bus_id, ##args)
-#define lbs_deb_cs(fmt, args...)        LBS_DEB_LL(LBS_DEB_CS, fmt, ##args)
-#define lbs_deb_thread(fmt, args...)    LBS_DEB_LL(LBS_DEB_THREAD, fmt, ##args)
+#define lbs_deb_main(fmt, args...)      LBS_DEB_LL(LBS_DEB_MAIN, " main", fmt, ##args)
+#define lbs_deb_net(fmt, args...)       LBS_DEB_LL(LBS_DEB_NET, " net", fmt, ##args)
+#define lbs_deb_mesh(fmt, args...)      LBS_DEB_LL(LBS_DEB_MESH, " mesh", fmt, ##args)
+#define lbs_deb_wext(fmt, args...)      LBS_DEB_LL(LBS_DEB_WEXT, " wext", fmt, ##args)
+#define lbs_deb_ioctl(fmt, args...)     LBS_DEB_LL(LBS_DEB_IOCTL, " ioctl", fmt, ##args)
+#define lbs_deb_scan(fmt, args...)      LBS_DEB_LL(LBS_DEB_SCAN, " scan", fmt, ##args)
+#define lbs_deb_assoc(fmt, args...)     LBS_DEB_LL(LBS_DEB_ASSOC, " assoc", fmt, ##args)
+#define lbs_deb_join(fmt, args...)      LBS_DEB_LL(LBS_DEB_JOIN, " join", fmt, ##args)
+#define lbs_deb_11d(fmt, args...)       LBS_DEB_LL(LBS_DEB_11D, " 11d", fmt, ##args)
+#define lbs_deb_debugfs(fmt, args...)   LBS_DEB_LL(LBS_DEB_DEBUGFS, " debugfs", fmt, ##args)
+#define lbs_deb_ethtool(fmt, args...)   LBS_DEB_LL(LBS_DEB_ETHTOOL, " ethtool", fmt, ##args)
+#define lbs_deb_host(fmt, args...)      LBS_DEB_LL(LBS_DEB_HOST, " host", fmt, ##args)
+#define lbs_deb_cmd(fmt, args...)       LBS_DEB_LL(LBS_DEB_CMD, " cmd", fmt, ##args)
+#define lbs_deb_rx(fmt, args...)        LBS_DEB_LL(LBS_DEB_RX, " rx", fmt, ##args)
+#define lbs_deb_tx(fmt, args...)        LBS_DEB_LL(LBS_DEB_TX, " tx", fmt, ##args)
+#define lbs_deb_fw(fmt, args...)        LBS_DEB_LL(LBS_DEB_FW, " fw", fmt, ##args)
+#define lbs_deb_usb(fmt, args...)       LBS_DEB_LL(LBS_DEB_USB, " usb", fmt, ##args)
+#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args)
+#define lbs_deb_cs(fmt, args...)        LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args)
+#define lbs_deb_thread(fmt, args...)    LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args)
 
 #define lbs_pr_info(format, args...) \
 	printk(KERN_INFO DRV_NAME": " format, ## args)
@@ -89,22 +89,28 @@
 	printk(KERN_ALERT DRV_NAME": " format, ## args)
 
 #ifdef DEBUG
-static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len)
+static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len)
 {
 	int i = 0;
 
-	if (!(libertas_debug & LBS_DEB_HEX))
-		return;
-
-	printk(KERN_DEBUG "%s: ", prompt);
-	for (i = 1; i <= len; i++) {
-		printk("%02x ", (u8) * buf);
-		buf++;
+	if (len &&
+	    (libertas_debug & LBS_DEB_HEX) &&
+	    (libertas_debug & grp))
+	{
+		for (i = 1; i <= len; i++) {
+			if ((i & 0xf) == 1) {
+				if (i != 1)
+					printk("\n");
+				printk(DRV_NAME " %s: ", prompt);
+			}
+			printk("%02x ", (u8) * buf);
+			buf++;
+		}
+		printk("\n");
 	}
-	printk("\n");
 }
 #else
-#define lbs_dbg_hex(x,y,z)				do {} while (0)
+#define lbs_deb_hex(grp,prompt,buf,len)	do {} while (0)
 #endif
 
 
@@ -149,17 +155,18 @@
 #define	MRVDRV_CHANNELS_PER_SCAN		4
 #define	MRVDRV_MAX_CHANNELS_PER_SCAN		14
 
-#define MRVDRV_DEBUG_RX_PATH		0x00000001
-#define MRVDRV_DEBUG_TX_PATH		0x00000002
-
 #define MRVDRV_MIN_BEACON_INTERVAL		20
 #define MRVDRV_MAX_BEACON_INTERVAL		1000
 #define MRVDRV_BEACON_INTERVAL			100
 
+#define MARVELL_MESH_IE_LENGTH		9
+
 /** INT status Bit Definition*/
-#define his_cmddnldrdy			0x01
-#define his_cardevent			0x02
-#define his_cmdupldrdy			0x04
+#define MRVDRV_TX_DNLD_RDY		0x0001
+#define MRVDRV_RX_UPLD_RDY		0x0002
+#define MRVDRV_CMD_DNLD_RDY		0x0004
+#define MRVDRV_CMD_UPLD_RDY		0x0008
+#define MRVDRV_CARDEVENT		0x0010
 
 #define SBI_EVENT_CAUSE_SHIFT		3
 
@@ -218,9 +225,6 @@
 #define	CMD_F_HOSTCMD		(1 << 0)
 #define FW_CAPINFO_WPA  	(1 << 0)
 
-/** WPA key LENGTH*/
-#define MRVL_MAX_KEY_WPA_KEY_LENGTH     32
-
 #define KEY_LEN_WPA_AES			16
 #define KEY_LEN_WPA_TKIP		32
 #define KEY_LEN_WEP_104			13
@@ -247,10 +251,7 @@
                         ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \
                         AVG_SCALE))  / N))
 
-#define B_SUPPORTED_RATES		8
-#define G_SUPPORTED_RATES		14
-
-#define	WLAN_SUPPORTED_RATES		14
+#define MAX_RATES			14
 
 #define	MAX_LEDS			8
 
@@ -264,11 +265,7 @@
 extern const char libertas_driver_version[];
 extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE];
 
-extern u8 libertas_supported_rates[G_SUPPORTED_RATES];
-
-extern u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES];
-
-extern u8 libertas_adhoc_rates_b[4];
+extern u8 libertas_bg_rates[MAX_RATES];
 
 /** ENUM definition*/
 /** SNRNF_TYPE */
@@ -287,11 +284,11 @@
 
 /** WLAN_802_11_POWER_MODE */
 enum WLAN_802_11_POWER_MODE {
-	wlan802_11powermodecam,
-	wlan802_11powermodemax_psp,
-	wlan802_11Powermodefast_psp,
+	WLAN802_11POWERMODECAM,
+	WLAN802_11POWERMODEMAX_PSP,
+	WLAN802_11POWERMODEFAST_PSP,
 	/*not a real mode, defined as an upper bound */
-	wlan802_11powemodemax
+	WLAN802_11POWEMODEMAX
 };
 
 /** PS_STATE */
@@ -311,14 +308,14 @@
 
 /** WLAN_MEDIA_STATE */
 enum WLAN_MEDIA_STATE {
-	libertas_connected,
-	libertas_disconnected
+	LIBERTAS_CONNECTED,
+	LIBERTAS_DISCONNECTED
 };
 
 /** WLAN_802_11_PRIVACY_FILTER */
 enum WLAN_802_11_PRIVACY_FILTER {
-	wlan802_11privfilteracceptall,
-	wlan802_11privfilter8021xWEP
+	WLAN802_11PRIVFILTERACCEPTALL,
+	WLAN802_11PRIVFILTER8021XWEP
 };
 
 /** mv_ms_type */
@@ -331,23 +328,23 @@
 
 /** SNMP_MIB_INDEX_e */
 enum SNMP_MIB_INDEX_e {
-	desired_bsstype_i = 0,
-	op_rateset_i,
-	bcnperiod_i,
-	dtimperiod_i,
-	assocrsp_timeout_i,
-	rtsthresh_i,
-	short_retrylim_i,
-	long_retrylim_i,
-	fragthresh_i,
-	dot11d_i,
-	dot11h_i,
-	manufid_i,
-	prodID_i,
-	manuf_oui_i,
-	manuf_name_i,
-	manuf_prodname_i,
-	manuf_prodver_i,
+	DESIRED_BSSTYPE_I = 0,
+	OP_RATESET_I,
+	BCNPERIOD_I,
+	DTIMPERIOD_I,
+	ASSOCRSP_TIMEOUT_I,
+	RTSTHRESH_I,
+	SHORT_RETRYLIM_I,
+	LONG_RETRYLIM_I,
+	FRAGTHRESH_I,
+	DOT11D_I,
+	DOT11H_I,
+	MANUFID_I,
+	PRODID_I,
+	MANUF_OUI_I,
+	MANUF_NAME_I,
+	MANUF_PRODNAME_I,
+	MANUF_PRODVER_I,
 };
 
 /** KEY_TYPE_ID */
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index 785192b..1fb807a 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -14,7 +14,6 @@
 
 #include "defs.h"
 #include "scan.h"
-#include "thread.h"
 
 extern struct ethtool_ops libertas_ethtool_ops;
 
@@ -73,10 +72,8 @@
 	u8 band;
 	/** channel */
 	u8 channel;
-	/** number of rates supported */
-	int numofrates;
-	/** supported rates*/
-	u8 datarates[WLAN_SUPPORTED_RATES];
+	/** zero-terminated array of supported data rates */
+	u8 rates[MAX_RATES + 1];
 };
 
 /** sleep_params */
@@ -106,6 +103,8 @@
 	int open;
 	int mesh_open;
 	int infra_open;
+	int mesh_autostart_enabled;
+	__le16 boot2_version;
 
 	char name[DEV_NAME_LEN];
 
@@ -114,7 +113,9 @@
 	struct net_device *dev;
 
 	struct net_device_stats stats;
-	struct net_device *mesh_dev ; /* Virtual device */
+	struct net_device *mesh_dev; /* Virtual device */
+	struct net_device *rtap_net_dev;
+	struct ieee80211_device *ieee;
 
 	struct iw_statistics wstats;
 	struct wlan_mesh_stats mstats;
@@ -142,20 +143,18 @@
 	   all other bits reserved 0 */
 	u8 dnld_sent;
 
-	const struct firmware *firmware;
 	struct device *hotplug_device;
 
 	/** thread to service interrupts */
-	struct wlan_thread mainthread;
+	struct task_struct *main_thread;
+	wait_queue_head_t waitq;
+	struct workqueue_struct *work_thread;
 
+	struct delayed_work scan_work;
 	struct delayed_work assoc_work;
-	struct workqueue_struct *assoc_thread;
 	struct work_struct sync_channel;
 
 	/** Hardware access */
-	int (*hw_register_dev) (wlan_private * priv);
-	int (*hw_unregister_dev) (wlan_private *);
-	int (*hw_prog_firmware) (wlan_private *);
 	int (*hw_host_to_card) (wlan_private * priv, u8 type, u8 * payload, u16 nb);
 	int (*hw_get_int_status) (wlan_private * priv, u8 *);
 	int (*hw_read_event_cause) (wlan_private *);
@@ -188,12 +187,12 @@
 	u8 bssid[ETH_ALEN];
 
 	/** WEP keys */
-	struct WLAN_802_11_KEY wep_keys[4];
+	struct enc_key wep_keys[4];
 	u16 wep_tx_keyidx;
 
 	/** WPA keys */
-	struct WLAN_802_11_KEY wpa_mcast_key;
-	struct WLAN_802_11_KEY wpa_unicast_key;
+	struct enc_key wpa_mcast_key;
+	struct enc_key wpa_unicast_key;
 
 	struct wlan_802_11_security secinfo;
 
@@ -259,23 +258,15 @@
 	/* IW_MODE_* */
 	u8 mode;
 
-	u8 prev_ssid[IW_ESSID_MAX_SIZE + 1];
-	u8 prev_ssid_len;
-	u8 prev_bssid[ETH_ALEN];
-
 	/* Scan results list */
 	struct list_head network_list;
 	struct list_head network_free_list;
 	struct bss_descriptor *networks;
 
-	u8 scantype;
-	u32 scanmode;
-
-	u16 beaconperiod;
 	u8 adhoccreate;
 
 	/** capability Info used in Association, start, join */
-	struct ieeetypes_capinfo capinfo;
+	u16 capability;
 
 	/** MAC address information */
 	u8 current_addr[ETH_ALEN];
@@ -287,20 +278,10 @@
 
 	u16 enablehwauto;
 	u16 ratebitmap;
-	/** control G rates */
-	u8 adhoc_grate_enabled;
-
-	u32 txantenna;
-	u32 rxantenna;
 
 	u32 fragthsd;
 	u32 rtsthsd;
 
-	u32 datarate;
-	u8 is_datarate_auto;
-
-	u16 listeninterval;
-	u16 prescan;
 	u8 txretrycount;
 
 	/** Tx-related variables (for single packet tx) */
@@ -311,22 +292,17 @@
 	u16 currentpacketfilter;
 	u32 connect_status;
 	u16 regioncode;
-	u16 regiontableindex;
 	u16 txpowerlevel;
 
 	/** POWER MANAGEMENT AND PnP SUPPORT */
 	u8 surpriseremoved;
-	u16 atimwindow;
 
 	u16 psmode;		/* Wlan802_11PowermodeCAM=disable
 				   Wlan802_11PowermodeMAX_PSP=enable */
-	u16 multipledtim;
 	u32 psstate;
 	u8 needtowakeup;
 
 	struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep;
-	u16 locallisteninterval;
-	u16 nullpktinterval;
 
 	struct assoc_request * pending_assoc_req;
 	struct assoc_request * in_progress_assoc_req;
@@ -335,23 +311,18 @@
 	struct wlan_802_11_security secinfo;
 
 	/** WEP keys */
-	struct WLAN_802_11_KEY wep_keys[4];
+	struct enc_key wep_keys[4];
 	u16 wep_tx_keyidx;
 
 	/** WPA keys */
-	struct WLAN_802_11_KEY wpa_mcast_key;
-	struct WLAN_802_11_KEY wpa_unicast_key;
+	struct enc_key wpa_mcast_key;
+	struct enc_key wpa_unicast_key;
 
 	/** WPA Information Elements*/
 	u8 wpa_ie[MAX_WPA_IE_LEN];
 	u8 wpa_ie_len;
 
-	u16 rxantennamode;
-	u16 txantennamode;
-
 	/** Requested Signal Strength*/
-	u16 bcn_avg_factor;
-	u16 data_avg_factor;
 	u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG];
 	u16 NF[MAX_TYPE_B][MAX_TYPE_AVG];
 	u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG];
@@ -359,15 +330,13 @@
 	u8 rawNF[DEFAULT_DATA_AVG_FACTOR];
 	u16 nextSNRNF;
 	u16 numSNRNF;
-	u16 rxpd_rate;
 
 	u8 radioon;
 	u32 preamble;
 
-	/** Multi bands Parameter*/
-	u8 libertas_supported_rates[G_SUPPORTED_RATES];
-
-	/** Blue Tooth Co-existence Arbitration */
+	/** data rate stuff */
+	u8 cur_rate;
+	u8 auto_rate;
 
 	/** sleep_params */
 	struct sleep_params sp;
@@ -392,14 +361,8 @@
 	struct wlan_offset_value offsetvalue;
 
 	struct cmd_ds_802_11_get_log logmsg;
-	u16 scanprobes;
 
-	u32 pkttxctrl;
-
-	u16 txrate;
-	u32 linkmode;
-	u32 radiomode;
-	u32 debugmode;
+	u32 monitormode;
 	u8 fw_ready;
 
 	u8 last_scanned_channel;
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 96f1974..3dae152 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -60,8 +60,7 @@
 
 //      mutex_lock(&priv->mutex);
 
-	adapter->prdeeprom =
-		    (char *)kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
+	adapter->prdeeprom = kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL);
 	if (!adapter->prdeeprom)
 		return -ENOMEM;
 	memcpy(adapter->prdeeprom, &regctrl, sizeof(regctrl));
@@ -72,9 +71,9 @@
 	       regctrl.action, regctrl.offset, regctrl.NOB);
 
 	ret = libertas_prepare_and_send_command(priv,
-				    cmd_802_11_eeprom_access,
+				    CMD_802_11_EEPROM_ACCESS,
 				    regctrl.action,
-				    cmd_option_waitforrsp, 0,
+				    CMD_OPTION_WAITFORRSP, 0,
 				    &regctrl);
 
 	if (ret) {
@@ -110,56 +109,48 @@
 				struct ethtool_stats * stats, u64 * data)
 {
 	wlan_private *priv = dev->priv;
-
-	lbs_deb_enter(LBS_DEB_ETHTOOL);
-
-	stats->cmd = ETHTOOL_GSTATS;
-	BUG_ON(stats->n_stats != MESH_STATS_NUM);
-
-        data[0] = priv->mstats.fwd_drop_rbt;
-        data[1] = priv->mstats.fwd_drop_ttl;
-        data[2] = priv->mstats.fwd_drop_noroute;
-        data[3] = priv->mstats.fwd_drop_nobuf;
-        data[4] = priv->mstats.fwd_unicast_cnt;
-        data[5] = priv->mstats.fwd_bcast_cnt;
-        data[6] = priv->mstats.drop_blind;
-        data[7] = priv->mstats.tx_failed_cnt;
-
-	lbs_deb_enter(LBS_DEB_ETHTOOL);
-}
-
-static int libertas_ethtool_get_stats_count(struct net_device * dev)
-{
-	int ret;
-	wlan_private *priv = dev->priv;
 	struct cmd_ds_mesh_access mesh_access;
+	int ret;
 
 	lbs_deb_enter(LBS_DEB_ETHTOOL);
 
 	/* Get Mesh Statistics */
 	ret = libertas_prepare_and_send_command(priv,
-			cmd_mesh_access, cmd_act_mesh_get_stats,
-			cmd_option_waitforrsp, 0, &mesh_access);
+			CMD_MESH_ACCESS, CMD_ACT_MESH_GET_STATS,
+			CMD_OPTION_WAITFORRSP, 0, &mesh_access);
 
-	if (ret) {
-		ret = 0;
-		goto done;
+	if (ret)
+		return;
+
+	priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
+	priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
+	priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
+	priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
+	priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
+	priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
+	priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
+	priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
+
+	data[0] = priv->mstats.fwd_drop_rbt;
+	data[1] = priv->mstats.fwd_drop_ttl;
+	data[2] = priv->mstats.fwd_drop_noroute;
+	data[3] = priv->mstats.fwd_drop_nobuf;
+	data[4] = priv->mstats.fwd_unicast_cnt;
+	data[5] = priv->mstats.fwd_bcast_cnt;
+	data[6] = priv->mstats.drop_blind;
+	data[7] = priv->mstats.tx_failed_cnt;
+
+	lbs_deb_enter(LBS_DEB_ETHTOOL);
+}
+
+static int libertas_ethtool_get_sset_count(struct net_device * dev, int sset)
+{
+	switch (sset) {
+	case ETH_SS_STATS:
+		return MESH_STATS_NUM;
+	default:
+		return -EOPNOTSUPP;
 	}
-
-        priv->mstats.fwd_drop_rbt = le32_to_cpu(mesh_access.data[0]);
-        priv->mstats.fwd_drop_ttl = le32_to_cpu(mesh_access.data[1]);
-        priv->mstats.fwd_drop_noroute = le32_to_cpu(mesh_access.data[2]);
-        priv->mstats.fwd_drop_nobuf = le32_to_cpu(mesh_access.data[3]);
-        priv->mstats.fwd_unicast_cnt = le32_to_cpu(mesh_access.data[4]);
-        priv->mstats.fwd_bcast_cnt = le32_to_cpu(mesh_access.data[5]);
-        priv->mstats.drop_blind = le32_to_cpu(mesh_access.data[6]);
-        priv->mstats.tx_failed_cnt = le32_to_cpu(mesh_access.data[7]);
-
-	ret = MESH_STATS_NUM;
-
-done:
-	lbs_deb_enter_args(LBS_DEB_ETHTOOL, "ret %d", ret);
-	return ret;
 }
 
 static void libertas_ethtool_get_strings (struct net_device * dev,
@@ -186,7 +177,7 @@
 	.get_drvinfo = libertas_ethtool_get_drvinfo,
 	.get_eeprom =  libertas_ethtool_get_eeprom,
 	.get_eeprom_len = libertas_ethtool_get_eeprom_len,
-	.get_stats_count = libertas_ethtool_get_stats_count,
+	.get_sset_count = libertas_ethtool_get_sset_count,
 	.get_ethtool_stats = libertas_ethtool_get_stats,
 	.get_strings = libertas_ethtool_get_strings,
 };
diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c
deleted file mode 100644
index 2dc84ff..0000000
--- a/drivers/net/wireless/libertas/fw.c
+++ /dev/null
@@ -1,349 +0,0 @@
-/**
-  * This file contains the initialization for FW and HW
-  */
-#include <linux/firmware.h>
-
-#include "host.h"
-#include "defs.h"
-#include "decl.h"
-#include "dev.h"
-#include "wext.h"
-#include "if_usb.h"
-
-/**
- *  @brief This function checks the validity of Boot2/FW image.
- *
- *  @param data              pointer to image
- *         len               image length
- *  @return     0 or -1
- */
-static int check_fwfile_format(u8 *data, u32 totlen)
-{
-	u32 bincmd, exit;
-	u32 blksize, offset, len;
-	int ret;
-
-	ret = 1;
-	exit = len = 0;
-
-	do {
-		struct fwheader *fwh = (void *)data;
-
-		bincmd = le32_to_cpu(fwh->dnldcmd);
-		blksize = le32_to_cpu(fwh->datalength);
-		switch (bincmd) {
-		case FW_HAS_DATA_TO_RECV:
-			offset = sizeof(struct fwheader) + blksize;
-			data += offset;
-			len += offset;
-			if (len >= totlen)
-				exit = 1;
-			break;
-		case FW_HAS_LAST_BLOCK:
-			exit = 1;
-			ret = 0;
-			break;
-		default:
-			exit = 1;
-			break;
-		}
-	} while (!exit);
-
-	if (ret)
-		lbs_pr_err("firmware file format check FAIL\n");
-	else
-		lbs_deb_fw("firmware file format check PASS\n");
-
-	return ret;
-}
-
-/**
- *  @brief This function downloads firmware image, gets
- *  HW spec from firmware and set basic parameters to
- *  firmware.
- *
- *  @param priv    A pointer to wlan_private structure
- *  @return 	   0 or -1
- */
-static int wlan_setup_station_hw(wlan_private * priv, char *fw_name)
-{
-	int ret = -1;
-	wlan_adapter *adapter = priv->adapter;
-
-	lbs_deb_enter(LBS_DEB_FW);
-
-	if ((ret = request_firmware(&priv->firmware, fw_name,
-				    priv->hotplug_device)) < 0) {
-		lbs_pr_err("request_firmware() failed with %#x\n", ret);
-		lbs_pr_err("firmware %s not found\n", fw_name);
-		goto done;
-	}
-
-	if (check_fwfile_format(priv->firmware->data, priv->firmware->size)) {
-		release_firmware(priv->firmware);
-		goto done;
-	}
-
-	ret = priv->hw_prog_firmware(priv);
-
-	release_firmware(priv->firmware);
-
-	if (ret) {
-		lbs_deb_fw("bootloader in invalid state\n");
-		ret = -1;
-		goto done;
-	}
-
-	/*
-	 * Read MAC address from HW
-	 */
-	memset(adapter->current_addr, 0xff, ETH_ALEN);
-
-	ret = libertas_prepare_and_send_command(priv, cmd_get_hw_spec,
-				    0, cmd_option_waitforrsp, 0, NULL);
-
-	if (ret) {
-		ret = -1;
-		goto done;
-	}
-
-	libertas_set_mac_packet_filter(priv);
-
-	/* Get the supported Data rates */
-	ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
-				    cmd_act_get_tx_rate,
-				    cmd_option_waitforrsp, 0, NULL);
-
-	if (ret) {
-		ret = -1;
-		goto done;
-	}
-
-	ret = 0;
-done:
-	lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
-	return ret;
-}
-
-static int wlan_allocate_adapter(wlan_private * priv)
-{
-	size_t bufsize;
-	wlan_adapter *adapter = priv->adapter;
-
-	/* Allocate buffer to store the BSSID list */
-	bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
-	adapter->networks = kzalloc(bufsize, GFP_KERNEL);
-	if (!adapter->networks) {
-		lbs_pr_err("Out of memory allocating beacons\n");
-		libertas_free_adapter(priv);
-		return -ENOMEM;
-	}
-
-	/* Allocate the command buffers */
-	libertas_allocate_cmd_buffer(priv);
-
-	memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep));
-	adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum);
-	adapter->libertas_ps_confirm_sleep.command =
-	    cpu_to_le16(cmd_802_11_ps_mode);
-	adapter->libertas_ps_confirm_sleep.size =
-	    cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
-	adapter->libertas_ps_confirm_sleep.result = 0;
-	adapter->libertas_ps_confirm_sleep.action =
-	    cpu_to_le16(cmd_subcmd_sleep_confirmed);
-
-	return 0;
-}
-
-static void wlan_init_adapter(wlan_private * priv)
-{
-	wlan_adapter *adapter = priv->adapter;
-	int i;
-
-	adapter->scanprobes = 0;
-
-	adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
-	adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
-
-	/* ATIM params */
-	adapter->atimwindow = 0;
-
-	adapter->connect_status = libertas_disconnected;
-	memset(adapter->current_addr, 0xff, ETH_ALEN);
-
-	/* scan type */
-	adapter->scantype = cmd_scan_type_active;
-
-	/* scan mode */
-	adapter->scanmode = cmd_bss_type_any;
-
-	/* 802.11 specific */
-	adapter->secinfo.wep_enabled = 0;
-	for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]);
-	     i++)
-		memset(&adapter->wep_keys[i], 0, sizeof(struct WLAN_802_11_KEY));
-	adapter->wep_tx_keyidx = 0;
-	adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
-	adapter->mode = IW_MODE_INFRA;
-
-	adapter->pending_assoc_req = NULL;
-	adapter->in_progress_assoc_req = NULL;
-
-	/* Initialize scan result lists */
-	INIT_LIST_HEAD(&adapter->network_free_list);
-	INIT_LIST_HEAD(&adapter->network_list);
-	for (i = 0; i < MAX_NETWORK_COUNT; i++) {
-		list_add_tail(&adapter->networks[i].list,
-			      &adapter->network_free_list);
-	}
-
-	mutex_init(&adapter->lock);
-
-	adapter->prescan = 1;
-
-	memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams));
-	adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
-
-	/* PnP and power profile */
-	adapter->surpriseremoved = 0;
-
-	adapter->currentpacketfilter =
-	    cmd_act_mac_rx_on | cmd_act_mac_tx_on;
-
-	adapter->radioon = RADIO_ON;
-	adapter->txantenna = RF_ANTENNA_2;
-	adapter->rxantenna = RF_ANTENNA_AUTO;
-
-	adapter->is_datarate_auto = 1;
-	adapter->beaconperiod = MRVDRV_BEACON_INTERVAL;
-
-	// set default value of capinfo.
-#define SHORT_PREAMBLE_ALLOWED		1
-	memset(&adapter->capinfo, 0, sizeof(adapter->capinfo));
-	adapter->capinfo.shortpreamble = SHORT_PREAMBLE_ALLOWED;
-
-	adapter->psmode = wlan802_11powermodecam;
-	adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM;
-
-	adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL;
-
-	adapter->psstate = PS_STATE_FULL_POWER;
-	adapter->needtowakeup = 0;
-	adapter->locallisteninterval = 0;	/* default value in firmware will be used */
-
-	adapter->datarate = 0;	// Initially indicate the rate as auto
-
-	adapter->adhoc_grate_enabled = 0;
-
-	adapter->intcounter = 0;
-
-	adapter->currenttxskb = NULL;
-	adapter->pkttxctrl = 0;
-
-	memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*));
-	adapter->tx_queue_idx = 0;
-	spin_lock_init(&adapter->txqueue_lock);
-
-	return;
-}
-
-static void command_timer_fn(unsigned long data);
-
-int libertas_init_fw(wlan_private * priv, char *fw_name)
-{
-	int ret = -1;
-	wlan_adapter *adapter = priv->adapter;
-
-	lbs_deb_enter(LBS_DEB_FW);
-
-	/* Allocate adapter structure */
-	if ((ret = wlan_allocate_adapter(priv)) != 0)
-		goto done;
-
-	/* init adapter structure */
-	wlan_init_adapter(priv);
-
-	/* init timer etc. */
-	setup_timer(&adapter->command_timer, command_timer_fn,
-			(unsigned long)priv);
-
-	/* download fimrware etc. */
-	if ((ret = wlan_setup_station_hw(priv, fw_name)) != 0) {
-		del_timer_sync(&adapter->command_timer);
-		goto done;
-	}
-
-	/* init 802.11d */
-	libertas_init_11d(priv);
-
-	ret = 0;
-done:
-	lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
-	return ret;
-}
-
-void libertas_free_adapter(wlan_private * priv)
-{
-	wlan_adapter *adapter = priv->adapter;
-
-	if (!adapter) {
-		lbs_deb_fw("why double free adapter?\n");
-		return;
-	}
-
-	lbs_deb_fw("free command buffer\n");
-	libertas_free_cmd_buffer(priv);
-
-	lbs_deb_fw("free command_timer\n");
-	del_timer(&adapter->command_timer);
-
-	lbs_deb_fw("free scan results table\n");
-	kfree(adapter->networks);
-	adapter->networks = NULL;
-
-	/* Free the adapter object itself */
-	lbs_deb_fw("free adapter\n");
-	kfree(adapter);
-	priv->adapter = NULL;
-}
-
-/**
- *  This function handles the timeout of command sending.
- *  It will re-send the same command again.
- */
-static void command_timer_fn(unsigned long data)
-{
-	wlan_private *priv = (wlan_private *)data;
-	wlan_adapter *adapter = priv->adapter;
-	struct cmd_ctrl_node *ptempnode;
-	struct cmd_ds_command *cmd;
-	unsigned long flags;
-
-	ptempnode = adapter->cur_cmd;
-	if (ptempnode == NULL) {
-		lbs_deb_fw("ptempnode empty\n");
-		return;
-	}
-
-	cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr;
-	if (!cmd) {
-		lbs_deb_fw("cmd is NULL\n");
-		return;
-	}
-
-	lbs_deb_fw("command_timer_fn fired, cmd %x\n", cmd->command);
-
-	if (!adapter->fw_ready)
-		return;
-
-	spin_lock_irqsave(&adapter->driver_lock, flags);
-	adapter->cur_cmd = NULL;
-	spin_unlock_irqrestore(&adapter->driver_lock, flags);
-
-	lbs_deb_fw("re-sending same command because of timeout\n");
-	libertas_queue_cmd(adapter, ptempnode, 0);
-
-	wake_up_interruptible(&priv->mainthread.waitq);
-
-	return;
-}
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 7509cc1..b37ddbc 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -20,224 +20,163 @@
 #define OID_802_11_TX_RETRYCOUNT              0x0000801D
 #define OID_802_11D_ENABLE                    0x00008020
 
-#define cmd_option_waitforrsp             0x0002
+#define CMD_OPTION_WAITFORRSP             0x0002
 
-/** Host command ID */
-#define cmd_code_dnld                 0x0002
-#define cmd_get_hw_spec               0x0003
-#define cmd_eeprom_update             0x0004
-#define cmd_802_11_reset              0x0005
-#define cmd_802_11_scan               0x0006
-#define cmd_802_11_get_log            0x000b
-#define cmd_mac_multicast_adr         0x0010
-#define cmd_802_11_authenticate       0x0011
-#define cmd_802_11_eeprom_access      0x0059
-#define cmd_802_11_associate          0x0050
-#define cmd_802_11_set_wep            0x0013
-#define cmd_802_11_get_stat           0x0014
-#define cmd_802_3_get_stat            0x0015
-#define cmd_802_11_snmp_mib           0x0016
-#define cmd_mac_reg_map               0x0017
-#define cmd_bbp_reg_map               0x0018
-#define cmd_mac_reg_access            0x0019
-#define cmd_bbp_reg_access            0x001a
-#define cmd_rf_reg_access             0x001b
-#define cmd_802_11_radio_control      0x001c
-#define cmd_802_11_rf_channel         0x001d
-#define cmd_802_11_rf_tx_power        0x001e
-#define cmd_802_11_rssi               0x001f
-#define cmd_802_11_rf_antenna         0x0020
+/** Host command IDs */
 
-#define cmd_802_11_ps_mode	      0x0021
+/* Return command are almost always the same as the host command, but with
+ * bit 15 set high.  There are a few exceptions, though...
+ */
+#define CMD_RET(cmd)			(0x8000 | cmd)
 
-#define cmd_802_11_data_rate          0x0022
-#define cmd_rf_reg_map                0x0023
-#define cmd_802_11_deauthenticate     0x0024
-#define cmd_802_11_reassociate        0x0025
-#define cmd_802_11_disassociate       0x0026
-#define cmd_mac_control               0x0028
-#define cmd_802_11_ad_hoc_start       0x002b
-#define cmd_802_11_ad_hoc_join        0x002c
+/* Return command convention exceptions: */
+#define CMD_RET_802_11_ASSOCIATE      0x8012
 
-#define cmd_802_11_query_tkip_reply_cntrs  0x002e
-#define cmd_802_11_enable_rsn              0x002f
-#define cmd_802_11_pairwise_tsc       0x0036
-#define cmd_802_11_group_tsc          0x0037
-#define cmd_802_11_key_material       0x005e
+/* Command codes */
+#define CMD_CODE_DNLD                 0x0002
+#define CMD_GET_HW_SPEC               0x0003
+#define CMD_EEPROM_UPDATE             0x0004
+#define CMD_802_11_RESET              0x0005
+#define CMD_802_11_SCAN               0x0006
+#define CMD_802_11_GET_LOG            0x000b
+#define CMD_MAC_MULTICAST_ADR         0x0010
+#define CMD_802_11_AUTHENTICATE       0x0011
+#define CMD_802_11_EEPROM_ACCESS      0x0059
+#define CMD_802_11_ASSOCIATE          0x0050
+#define CMD_802_11_SET_WEP            0x0013
+#define CMD_802_11_GET_STAT           0x0014
+#define CMD_802_3_GET_STAT            0x0015
+#define CMD_802_11_SNMP_MIB           0x0016
+#define CMD_MAC_REG_MAP               0x0017
+#define CMD_BBP_REG_MAP               0x0018
+#define CMD_MAC_REG_ACCESS            0x0019
+#define CMD_BBP_REG_ACCESS            0x001a
+#define CMD_RF_REG_ACCESS             0x001b
+#define CMD_802_11_RADIO_CONTROL      0x001c
+#define CMD_802_11_RF_CHANNEL         0x001d
+#define CMD_802_11_RF_TX_POWER        0x001e
+#define CMD_802_11_RSSI               0x001f
+#define CMD_802_11_RF_ANTENNA         0x0020
 
-#define cmd_802_11_set_afc            0x003c
-#define cmd_802_11_get_afc            0x003d
+#define CMD_802_11_PS_MODE	      0x0021
 
-#define cmd_802_11_ad_hoc_stop        0x0040
+#define CMD_802_11_DATA_RATE          0x0022
+#define CMD_RF_REG_MAP                0x0023
+#define CMD_802_11_DEAUTHENTICATE     0x0024
+#define CMD_802_11_REASSOCIATE        0x0025
+#define CMD_802_11_DISASSOCIATE       0x0026
+#define CMD_MAC_CONTROL               0x0028
+#define CMD_802_11_AD_HOC_START       0x002b
+#define CMD_802_11_AD_HOC_JOIN        0x002c
 
-#define cmd_802_11_beacon_stop        0x0049
+#define CMD_802_11_QUERY_TKIP_REPLY_CNTRS  0x002e
+#define CMD_802_11_ENABLE_RSN              0x002f
+#define CMD_802_11_PAIRWISE_TSC       0x0036
+#define CMD_802_11_GROUP_TSC          0x0037
+#define CMD_802_11_KEY_MATERIAL       0x005e
 
-#define cmd_802_11_mac_address        0x004D
-#define cmd_802_11_eeprom_access      0x0059
+#define CMD_802_11_SET_AFC            0x003c
+#define CMD_802_11_GET_AFC            0x003d
 
-#define cmd_802_11_band_config        0x0058
+#define CMD_802_11_AD_HOC_STOP        0x0040
 
-#define cmd_802_11d_domain_info       0x005b
+#define CMD_802_11_BEACON_STOP        0x0049
 
-#define cmd_802_11_sleep_params          0x0066
+#define CMD_802_11_MAC_ADDRESS        0x004D
+#define CMD_802_11_EEPROM_ACCESS      0x0059
 
-#define cmd_802_11_inactivity_timeout    0x0067
+#define CMD_802_11_BAND_CONFIG        0x0058
 
-#define cmd_802_11_tpc_cfg               0x0072
-#define cmd_802_11_pwr_cfg               0x0073
+#define CMD_802_11D_DOMAIN_INFO       0x005b
 
-#define cmd_802_11_led_gpio_ctrl         0x004e
+#define CMD_802_11_SLEEP_PARAMS          0x0066
 
-#define cmd_802_11_subscribe_event       0x0075
+#define CMD_802_11_INACTIVITY_TIMEOUT    0x0067
 
-#define cmd_802_11_rate_adapt_rateset    0x0076
+#define CMD_802_11_TPC_CFG               0x0072
+#define CMD_802_11_PWR_CFG               0x0073
 
-#define cmd_802_11_tx_rate_query	0x007f
+#define CMD_802_11_LED_GPIO_CTRL         0x004e
 
-#define cmd_get_tsf                      0x0080
+#define CMD_802_11_SUBSCRIBE_EVENT       0x0075
 
-#define cmd_bt_access                 0x0087
-#define cmd_ret_bt_access                 0x8087
+#define CMD_802_11_RATE_ADAPT_RATESET    0x0076
 
-#define cmd_fwt_access                0x0095
-#define cmd_ret_fwt_access                0x8095
+#define CMD_802_11_TX_RATE_QUERY	0x007f
 
-#define cmd_mesh_access               0x009b
-#define cmd_ret_mesh_access               0x809b
+#define CMD_GET_TSF                      0x0080
+
+#define CMD_BT_ACCESS                 0x0087
+
+#define CMD_FWT_ACCESS                0x0095
+
+#define CMD_802_11_MONITOR_MODE       0x0098
+
+#define CMD_MESH_ACCESS               0x009b
+
+#define CMD_SET_BOOT2_VER                 0x00a5
 
 /* For the IEEE Power Save */
-#define cmd_subcmd_enter_ps               0x0030
-#define cmd_subcmd_exit_ps                0x0031
-#define cmd_subcmd_sleep_confirmed        0x0034
-#define cmd_subcmd_full_powerdown         0x0035
-#define cmd_subcmd_full_powerup           0x0036
+#define CMD_SUBCMD_ENTER_PS               0x0030
+#define CMD_SUBCMD_EXIT_PS                0x0031
+#define CMD_SUBCMD_SLEEP_CONFIRMED        0x0034
+#define CMD_SUBCMD_FULL_POWERDOWN         0x0035
+#define CMD_SUBCMD_FULL_POWERUP           0x0036
 
-/* command RET code, MSB is set to 1 */
-#define cmd_ret_hw_spec_info              0x8003
-#define cmd_ret_eeprom_update             0x8004
-#define cmd_ret_802_11_reset              0x8005
-#define cmd_ret_802_11_scan               0x8006
-#define cmd_ret_802_11_get_log            0x800b
-#define cmd_ret_mac_control               0x8028
-#define cmd_ret_mac_multicast_adr         0x8010
-#define cmd_ret_802_11_authenticate       0x8011
-#define cmd_ret_802_11_deauthenticate     0x8024
-#define cmd_ret_802_11_associate          0x8012
-#define cmd_ret_802_11_reassociate        0x8025
-#define cmd_ret_802_11_disassociate       0x8026
-#define cmd_ret_802_11_set_wep            0x8013
-#define cmd_ret_802_11_stat               0x8014
-#define cmd_ret_802_3_stat                0x8015
-#define cmd_ret_802_11_snmp_mib           0x8016
-#define cmd_ret_mac_reg_map               0x8017
-#define cmd_ret_bbp_reg_map               0x8018
-#define cmd_ret_rf_reg_map                0x8023
-#define cmd_ret_mac_reg_access            0x8019
-#define cmd_ret_bbp_reg_access            0x801a
-#define cmd_ret_rf_reg_access             0x801b
-#define cmd_ret_802_11_radio_control      0x801c
-#define cmd_ret_802_11_rf_channel         0x801d
-#define cmd_ret_802_11_rssi               0x801f
-#define cmd_ret_802_11_rf_tx_power        0x801e
-#define cmd_ret_802_11_rf_antenna         0x8020
-#define cmd_ret_802_11_ps_mode            0x8021
-#define cmd_ret_802_11_data_rate          0x8022
+#define CMD_ENABLE_RSN                    0x0001
+#define CMD_DISABLE_RSN                   0x0000
 
-#define cmd_ret_802_11_ad_hoc_start       0x802B
-#define cmd_ret_802_11_ad_hoc_join        0x802C
+#define CMD_ACT_SET                       0x0001
+#define CMD_ACT_GET                       0x0000
 
-#define cmd_ret_802_11_query_tkip_reply_cntrs  0x802e
-#define cmd_ret_802_11_enable_rsn              0x802f
-#define cmd_ret_802_11_pairwise_tsc       0x8036
-#define cmd_ret_802_11_group_tsc          0x8037
-#define cmd_ret_802_11_key_material       0x805e
+#define CMD_ACT_GET_AES                   (CMD_ACT_GET + 2)
+#define CMD_ACT_SET_AES                   (CMD_ACT_SET + 2)
+#define CMD_ACT_REMOVE_AES                (CMD_ACT_SET + 3)
 
-#define cmd_enable_rsn                    0x0001
-#define cmd_disable_rsn                   0x0000
+/* Define action or option for CMD_802_11_SET_WEP */
+#define CMD_ACT_ADD                         0x0002
+#define CMD_ACT_REMOVE                      0x0004
+#define CMD_ACT_USE_DEFAULT                 0x0008
 
-#define cmd_act_set                       0x0001
-#define cmd_act_get                       0x0000
+#define CMD_TYPE_WEP_40_BIT                 0x01
+#define CMD_TYPE_WEP_104_BIT                0x02
 
-#define cmd_act_get_AES                   (cmd_act_get + 2)
-#define cmd_act_set_AES                   (cmd_act_set + 2)
-#define cmd_act_remove_aes                (cmd_act_set + 3)
+#define CMD_NUM_OF_WEP_KEYS                 4
 
-#define cmd_ret_802_11_set_afc            0x803c
-#define cmd_ret_802_11_get_afc            0x803d
+#define CMD_WEP_KEY_INDEX_MASK              0x3fff
 
-#define cmd_ret_802_11_ad_hoc_stop        0x8040
+/* Define action or option for CMD_802_11_RESET */
+#define CMD_ACT_HALT                        0x0003
 
-#define cmd_ret_802_11_beacon_stop        0x8049
+/* Define action or option for CMD_802_11_SCAN */
+#define CMD_BSS_TYPE_BSS                    0x0001
+#define CMD_BSS_TYPE_IBSS                   0x0002
+#define CMD_BSS_TYPE_ANY                    0x0003
 
-#define cmd_ret_802_11_mac_address        0x804D
-#define cmd_ret_802_11_eeprom_access      0x8059
+/* Define action or option for CMD_802_11_SCAN */
+#define CMD_SCAN_TYPE_ACTIVE                0x0000
+#define CMD_SCAN_TYPE_PASSIVE               0x0001
 
-#define cmd_ret_802_11_band_config        0x8058
+#define CMD_SCAN_RADIO_TYPE_BG		0
 
-#define cmd_ret_802_11_sleep_params          0x8066
+#define CMD_SCAN_PROBE_DELAY_TIME           0
 
-#define cmd_ret_802_11_inactivity_timeout    0x8067
+/* Define action or option for CMD_MAC_CONTROL */
+#define CMD_ACT_MAC_RX_ON                   0x0001
+#define CMD_ACT_MAC_TX_ON                   0x0002
+#define CMD_ACT_MAC_LOOPBACK_ON             0x0004
+#define CMD_ACT_MAC_WEP_ENABLE              0x0008
+#define CMD_ACT_MAC_INT_ENABLE              0x0010
+#define CMD_ACT_MAC_MULTICAST_ENABLE        0x0020
+#define CMD_ACT_MAC_BROADCAST_ENABLE        0x0040
+#define CMD_ACT_MAC_PROMISCUOUS_ENABLE      0x0080
+#define CMD_ACT_MAC_ALL_MULTICAST_ENABLE    0x0100
+#define CMD_ACT_MAC_STRICT_PROTECTION_ENABLE  0x0400
 
-#define cmd_ret_802_11d_domain_info      (0x8000 |                  \
-                                              cmd_802_11d_domain_info)
-
-#define cmd_ret_802_11_tpc_cfg        (cmd_802_11_tpc_cfg | 0x8000)
-#define cmd_ret_802_11_pwr_cfg        (cmd_802_11_pwr_cfg | 0x8000)
-
-#define cmd_ret_802_11_led_gpio_ctrl     0x804e
-
-#define cmd_ret_802_11_subscribe_event	(cmd_802_11_subscribe_event | 0x8000)
-
-#define cmd_ret_802_11_rate_adapt_rateset	(cmd_802_11_rate_adapt_rateset | 0x8000)
-
-#define cmd_rte_802_11_tx_rate_query 	(cmd_802_11_tx_rate_query | 0x8000)
-
-#define cmd_ret_get_tsf             0x8080
-
-/* Define action or option for cmd_802_11_set_wep */
-#define cmd_act_add                         0x0002
-#define cmd_act_remove                      0x0004
-#define cmd_act_use_default                 0x0008
-
-#define cmd_type_wep_40_bit                 0x0001
-#define cmd_type_wep_104_bit                0x0002
-
-#define cmd_NUM_OF_WEP_KEYS                 4
-
-#define cmd_WEP_KEY_INDEX_MASK              0x3fff
-
-/* Define action or option for cmd_802_11_reset */
-#define cmd_act_halt                        0x0003
-
-/* Define action or option for cmd_802_11_scan */
-#define cmd_bss_type_bss                    0x0001
-#define cmd_bss_type_ibss                   0x0002
-#define cmd_bss_type_any                    0x0003
-
-/* Define action or option for cmd_802_11_scan */
-#define cmd_scan_type_active                0x0000
-#define cmd_scan_type_passive               0x0001
-
-#define cmd_scan_radio_type_bg		0
-
-#define cmd_scan_probe_delay_time           0
-
-/* Define action or option for cmd_mac_control */
-#define cmd_act_mac_rx_on                   0x0001
-#define cmd_act_mac_tx_on                   0x0002
-#define cmd_act_mac_loopback_on             0x0004
-#define cmd_act_mac_wep_enable              0x0008
-#define cmd_act_mac_int_enable              0x0010
-#define cmd_act_mac_multicast_enable        0x0020
-#define cmd_act_mac_broadcast_enable        0x0040
-#define cmd_act_mac_promiscuous_enable      0x0080
-#define cmd_act_mac_all_multicast_enable    0x0100
-#define cmd_act_mac_strict_protection_enable  0x0400
-
-/* Define action or option for cmd_802_11_radio_control */
-#define cmd_type_auto_preamble              0x0001
-#define cmd_type_short_preamble             0x0002
-#define cmd_type_long_preamble              0x0003
+/* Define action or option for CMD_802_11_RADIO_CONTROL */
+#define CMD_TYPE_AUTO_PREAMBLE              0x0001
+#define CMD_TYPE_SHORT_PREAMBLE             0x0002
+#define CMD_TYPE_LONG_PREAMBLE              0x0003
 
 #define TURN_ON_RF                              0x01
 #define RADIO_ON                                0x01
@@ -248,70 +187,80 @@
 #define SET_LONG_PREAMBLE                       0x01
 
 /* Define action or option for CMD_802_11_RF_CHANNEL */
-#define cmd_opt_802_11_rf_channel_get       0x00
-#define cmd_opt_802_11_rf_channel_set       0x01
+#define CMD_OPT_802_11_RF_CHANNEL_GET       0x00
+#define CMD_OPT_802_11_RF_CHANNEL_SET       0x01
 
-/* Define action or option for cmd_802_11_rf_tx_power */
-#define cmd_act_tx_power_opt_get            0x0000
-#define cmd_act_tx_power_opt_set_high       0x8007
-#define cmd_act_tx_power_opt_set_mid        0x8004
-#define cmd_act_tx_power_opt_set_low        0x8000
+/* Define action or option for CMD_802_11_RF_TX_POWER */
+#define CMD_ACT_TX_POWER_OPT_GET            0x0000
+#define CMD_ACT_TX_POWER_OPT_SET_HIGH       0x8007
+#define CMD_ACT_TX_POWER_OPT_SET_MID        0x8004
+#define CMD_ACT_TX_POWER_OPT_SET_LOW        0x8000
 
-#define cmd_act_tx_power_index_high         0x0007
-#define cmd_act_tx_power_index_mid          0x0004
-#define cmd_act_tx_power_index_low          0x0000
+#define CMD_ACT_TX_POWER_INDEX_HIGH         0x0007
+#define CMD_ACT_TX_POWER_INDEX_MID          0x0004
+#define CMD_ACT_TX_POWER_INDEX_LOW          0x0000
 
-/* Define action or option for cmd_802_11_data_rate */
-#define cmd_act_set_tx_auto                 0x0000
-#define cmd_act_set_tx_fix_rate             0x0001
-#define cmd_act_get_tx_rate                 0x0002
+/* Define action or option for CMD_802_11_DATA_RATE */
+#define CMD_ACT_SET_TX_AUTO                 0x0000
+#define CMD_ACT_SET_TX_FIX_RATE             0x0001
+#define CMD_ACT_GET_TX_RATE                 0x0002
 
-#define cmd_act_set_rx                      0x0001
-#define cmd_act_set_tx                      0x0002
-#define cmd_act_set_both                    0x0003
-#define cmd_act_get_rx                      0x0004
-#define cmd_act_get_tx                      0x0008
-#define cmd_act_get_both                    0x000c
+#define CMD_ACT_SET_RX                      0x0001
+#define CMD_ACT_SET_TX                      0x0002
+#define CMD_ACT_SET_BOTH                    0x0003
+#define CMD_ACT_GET_RX                      0x0004
+#define CMD_ACT_GET_TX                      0x0008
+#define CMD_ACT_GET_BOTH                    0x000c
 
-/* Define action or option for cmd_802_11_ps_mode */
-#define cmd_type_cam                        0x0000
-#define cmd_type_max_psp                    0x0001
-#define cmd_type_fast_psp                   0x0002
+/* Define action or option for CMD_802_11_PS_MODE */
+#define CMD_TYPE_CAM                        0x0000
+#define CMD_TYPE_MAX_PSP                    0x0001
+#define CMD_TYPE_FAST_PSP                   0x0002
 
-/* Define action or option for cmd_bt_access */
+/* Define action or option for CMD_BT_ACCESS */
 enum cmd_bt_access_opts {
 	/* The bt commands start at 5 instead of 1 because the old dft commands
 	 * are mapped to 1-4.  These old commands are no longer maintained and
 	 * should not be called.
 	 */
-	cmd_act_bt_access_add = 5,
-	cmd_act_bt_access_del,
-	cmd_act_bt_access_list,
-	cmd_act_bt_access_reset,
-	cmd_act_bt_access_set_invert,
-	cmd_act_bt_access_get_invert
+	CMD_ACT_BT_ACCESS_ADD = 5,
+	CMD_ACT_BT_ACCESS_DEL,
+	CMD_ACT_BT_ACCESS_LIST,
+	CMD_ACT_BT_ACCESS_RESET,
+	CMD_ACT_BT_ACCESS_SET_INVERT,
+	CMD_ACT_BT_ACCESS_GET_INVERT
 };
 
-/* Define action or option for cmd_fwt_access */
+/* Define action or option for CMD_FWT_ACCESS */
 enum cmd_fwt_access_opts {
-	cmd_act_fwt_access_add = 1,
-	cmd_act_fwt_access_del,
-	cmd_act_fwt_access_lookup,
-	cmd_act_fwt_access_list,
-	cmd_act_fwt_access_list_route,
-	cmd_act_fwt_access_list_neighbor,
-	cmd_act_fwt_access_reset,
-	cmd_act_fwt_access_cleanup,
-	cmd_act_fwt_access_time,
+	CMD_ACT_FWT_ACCESS_ADD = 1,
+	CMD_ACT_FWT_ACCESS_DEL,
+	CMD_ACT_FWT_ACCESS_LOOKUP,
+	CMD_ACT_FWT_ACCESS_LIST,
+	CMD_ACT_FWT_ACCESS_LIST_route,
+	CMD_ACT_FWT_ACCESS_LIST_neighbor,
+	CMD_ACT_FWT_ACCESS_RESET,
+	CMD_ACT_FWT_ACCESS_CLEANUP,
+	CMD_ACT_FWT_ACCESS_TIME,
 };
 
-/* Define action or option for cmd_mesh_access */
+/* Define action or option for CMD_MESH_ACCESS */
 enum cmd_mesh_access_opts {
-	cmd_act_mesh_get_ttl = 1,
-	cmd_act_mesh_set_ttl,
-	cmd_act_mesh_get_stats,
-	cmd_act_mesh_get_anycast,
-	cmd_act_mesh_set_anycast,
+	CMD_ACT_MESH_GET_TTL = 1,
+	CMD_ACT_MESH_SET_TTL,
+	CMD_ACT_MESH_GET_STATS,
+	CMD_ACT_MESH_GET_ANYCAST,
+	CMD_ACT_MESH_SET_ANYCAST,
+	CMD_ACT_MESH_SET_LINK_COSTS,
+	CMD_ACT_MESH_GET_LINK_COSTS,
+	CMD_ACT_MESH_SET_BCAST_RATE,
+	CMD_ACT_MESH_GET_BCAST_RATE,
+	CMD_ACT_MESH_SET_RREQ_DELAY,
+	CMD_ACT_MESH_GET_RREQ_DELAY,
+	CMD_ACT_MESH_SET_ROUTE_EXP,
+	CMD_ACT_MESH_GET_ROUTE_EXP,
+	CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+	CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
 };
 
 /** Card Event definition */
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h
index 09b898f..e1045dc 100644
--- a/drivers/net/wireless/libertas/hostcmd.h
+++ b/drivers/net/wireless/libertas/hostcmd.h
@@ -83,23 +83,12 @@
 	wait_queue_head_t cmdwait_q;
 };
 
-/* WLAN_802_11_KEY
- *
- * Generic structure to hold all key types.  key type (WEP40, WEP104, TKIP, AES)
- * is determined from the keylength field.
- */
-struct WLAN_802_11_KEY {
-	__le32 len;
-	__le32 flags;  /* KEY_INFO_* from wlan_defs.h */
-	u8 key[MRVL_MAX_KEY_WPA_KEY_LENGTH];
-	__le16 type; /* KEY_TYPE_* from wlan_defs.h */
-};
-
-struct IE_WPA {
-	u8 elementid;
-	u8 len;
-	u8 oui[4];
-	__le16 version;
+/* Generic structure to hold all key types. */
+struct enc_key {
+	u16 len;
+	u16 flags;  /* KEY_INFO_* from wlan_defs.h */
+	u16 type; /* KEY_TYPE_* from wlan_defs.h */
+	u8 key[32];
 };
 
 /* wlan_offset_value */
@@ -108,18 +97,6 @@
 	u32 value;
 };
 
-struct WLAN_802_11_FIXED_IEs {
-	__le64 timestamp;
-	__le16 beaconinterval;
-	u16 capabilities; /* Actually struct ieeetypes_capinfo */
-};
-
-struct WLAN_802_11_VARIABLE_IEs {
-	u8 elementid;
-	u8 length;
-	u8 data[1];
-};
-
 /* Define general data structure */
 /* cmd_DS_GEN */
 struct cmd_ds_gen {
@@ -131,7 +108,7 @@
 
 #define S_DS_GEN sizeof(struct cmd_ds_gen)
 /*
- * Define data structure for cmd_get_hw_spec
+ * Define data structure for CMD_GET_HW_SPEC
  * This structure defines the response for the GET_HW_SPEC command
  */
 struct cmd_ds_get_hw_spec {
@@ -178,11 +155,11 @@
 
 /*
  * This scan handle Country Information IE(802.11d compliant)
- * Define data structure for cmd_802_11_scan
+ * Define data structure for CMD_802_11_SCAN
  */
 struct cmd_ds_802_11_scan {
 	u8 bsstype;
-	u8 BSSID[ETH_ALEN];
+	u8 bssid[ETH_ALEN];
 	u8 tlvbuffer[1];
 #if 0
 	mrvlietypes_ssidparamset_t ssidParamSet;
@@ -237,7 +214,7 @@
 
 struct cmd_ds_802_11_associate {
 	u8 peerstaaddr[6];
-	struct ieeetypes_capinfo capinfo;
+	__le16 capability;
 	__le16 listeninterval;
 	__le16 bcnperiod;
 	u8 dtimperiod;
@@ -260,8 +237,8 @@
 };
 
 struct cmd_ds_802_11_ad_hoc_result {
-	u8 PAD[3];
-	u8 BSSID[ETH_ALEN];
+	u8 pad[3];
+	u8 bssid[ETH_ALEN];
 };
 
 struct cmd_ds_802_11_set_wep {
@@ -428,6 +405,16 @@
 
 };
 
+struct cmd_ds_802_11_monitor_mode {
+	u16 action;
+	u16 mode;
+};
+
+struct cmd_ds_set_boot2_ver {
+	u16 action;
+	u16 version;
+};
+
 struct cmd_ds_802_11_ps_mode {
 	__le16 action;
 	__le16 nullpktinterval;
@@ -451,8 +438,8 @@
 
 struct cmd_ds_802_11_data_rate {
 	__le16 action;
-	__le16 reserverd;
-	u8 datarate[G_SUPPORTED_RATES];
+	__le16 reserved;
+	u8 rates[MAX_RATES];
 };
 
 struct cmd_ds_802_11_rate_adapt_rateset {
@@ -462,30 +449,30 @@
 };
 
 struct cmd_ds_802_11_ad_hoc_start {
-	u8 SSID[IW_ESSID_MAX_SIZE];
+	u8 ssid[IW_ESSID_MAX_SIZE];
 	u8 bsstype;
 	__le16 beaconperiod;
 	u8 dtimperiod;
 	union IEEEtypes_ssparamset ssparamset;
 	union ieeetypes_phyparamset phyparamset;
 	__le16 probedelay;
-	struct ieeetypes_capinfo cap;
-	u8 datarate[G_SUPPORTED_RATES];
+	__le16 capability;
+	u8 rates[MAX_RATES];
 	u8 tlv_memory_size_pad[100];
 } __attribute__ ((packed));
 
 struct adhoc_bssdesc {
-	u8 BSSID[6];
-	u8 SSID[32];
-	u8 bsstype;
+	u8 bssid[6];
+	u8 ssid[32];
+	u8 type;
 	__le16 beaconperiod;
 	u8 dtimperiod;
 	__le64 timestamp;
 	__le64 localtime;
 	union ieeetypes_phyparamset phyparamset;
 	union IEEEtypes_ssparamset ssparamset;
-	struct ieeetypes_capinfo cap;
-	u8 datarates[G_SUPPORTED_RATES];
+	__le16 capability;
+	u8 rates[MAX_RATES];
 
 	/* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
 	 * Adhoc join command and will cause a binary layout mismatch with
@@ -494,7 +481,7 @@
 } __attribute__ ((packed));
 
 struct cmd_ds_802_11_ad_hoc_join {
-	struct adhoc_bssdesc bssdescriptor;
+	struct adhoc_bssdesc bss;
 	__le16 failtimeout;
 	__le16 probedelay;
 
@@ -646,6 +633,7 @@
 		struct cmd_ds_802_11_snmp_mib smib;
 		struct cmd_ds_802_11_rf_tx_power txp;
 		struct cmd_ds_802_11_rf_antenna rant;
+		struct cmd_ds_802_11_monitor_mode monitor;
 		struct cmd_ds_802_11_data_rate drate;
 		struct cmd_ds_802_11_rate_adapt_rateset rateset;
 		struct cmd_ds_mac_multicast_adr madr;
@@ -677,6 +665,7 @@
 		struct cmd_ds_bt_access bt;
 		struct cmd_ds_fwt_access fwt;
 		struct cmd_ds_mesh_access mesh;
+		struct cmd_ds_set_boot2_ver boot2_ver;
 		struct cmd_ds_get_tsf gettsf;
 		struct cmd_ds_802_11_subscribe_event subscribe_event;
 	} params;
diff --git a/drivers/net/wireless/libertas/if_bootcmd.c b/drivers/net/wireless/libertas/if_bootcmd.c
deleted file mode 100644
index 8bca306..0000000
--- a/drivers/net/wireless/libertas/if_bootcmd.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
-  * This file contains functions used in USB Boot command
-  * and Boot2/FW update
-  */
-
-#include <linux/delay.h>
-#include <linux/firmware.h>
-#include <linux/netdevice.h>
-#include <linux/usb.h>
-
-#define DRV_NAME "usb8xxx"
-
-#include "defs.h"
-#include "dev.h"
-#include "if_usb.h"
-
-/**
- *  @brief This function issues Boot command to the Boot2 code
- *  @param ivalue   1:Boot from FW by USB-Download
- *                  2:Boot from FW in EEPROM
- *  @return 	   	0
- */
-int if_usb_issue_boot_command(wlan_private *priv, int ivalue)
-{
-	struct usb_card_rec	*cardp = priv->card;
-	struct bootcmdstr	sbootcmd;
-	int i;
-
-	/* Prepare command */
-	sbootcmd.u32magicnumber = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
-	sbootcmd.u8cmd_tag = ivalue;
-	for (i=0; i<11; i++)
-		sbootcmd.au8dumy[i]=0x00;
-	memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));
-
-	/* Issue command */
-	usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr));
-
-	return 0;
-}
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
new file mode 100644
index 0000000..0360cad
--- /dev/null
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -0,0 +1,969 @@
+/*
+
+  Driver for the Marvell 8385 based compact flash WLAN cards.
+
+  (C) 2007 by Holger Schurig <hs4233@mail.mn-solutions.de>
+
+  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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/netdevice.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include <linux/io.h>
+
+#define DRV_NAME "libertas_cs"
+
+#include "decl.h"
+#include "defs.h"
+#include "dev.h"
+
+
+/********************************************************************/
+/* Module stuff                                                     */
+/********************************************************************/
+
+MODULE_AUTHOR("Holger Schurig <hs4233@mail.mn-solutions.de>");
+MODULE_DESCRIPTION("Driver for Marvell 83xx compact flash WLAN cards");
+MODULE_LICENSE("GPL");
+
+
+
+/********************************************************************/
+/* Data structures                                                  */
+/********************************************************************/
+
+struct if_cs_card {
+	struct pcmcia_device *p_dev;
+	wlan_private *priv;
+	void __iomem *iobase;
+};
+
+
+
+/********************************************************************/
+/* Hardware access                                                  */
+/********************************************************************/
+
+/* This define enables wrapper functions which allow you
+   to dump all register accesses. You normally won't this,
+   except for development */
+/* #define DEBUG_IO */
+
+#ifdef DEBUG_IO
+static int debug_output = 0;
+#else
+/* This way the compiler optimizes the printk's away */
+#define debug_output 0
+#endif
+
+static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg)
+{
+	unsigned int val = ioread8(card->iobase + reg);
+	if (debug_output)
+		printk(KERN_INFO "##inb %08x<%02x\n", reg, val);
+	return val;
+}
+static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg)
+{
+	unsigned int val = ioread16(card->iobase + reg);
+	if (debug_output)
+		printk(KERN_INFO "##inw %08x<%04x\n", reg, val);
+	return val;
+}
+static inline void if_cs_read16_rep(
+	struct if_cs_card *card,
+	uint reg,
+	void *buf,
+	unsigned long count)
+{
+	if (debug_output)
+		printk(KERN_INFO "##insw %08x<(0x%lx words)\n",
+			reg, count);
+	ioread16_rep(card->iobase + reg, buf, count);
+}
+
+static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val)
+{
+	if (debug_output)
+		printk(KERN_INFO "##outb %08x>%02x\n", reg, val);
+	iowrite8(val, card->iobase + reg);
+}
+
+static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val)
+{
+	if (debug_output)
+		printk(KERN_INFO "##outw %08x>%04x\n", reg, val);
+	iowrite16(val, card->iobase + reg);
+}
+
+static inline void if_cs_write16_rep(
+	struct if_cs_card *card,
+	uint reg,
+	void *buf,
+	unsigned long count)
+{
+	if (debug_output)
+		printk(KERN_INFO "##outsw %08x>(0x%lx words)\n",
+			reg, count);
+	iowrite16_rep(card->iobase + reg, buf, count);
+}
+
+
+/*
+ * I know that polling/delaying is frowned upon. However, this procedure
+ * with polling is needed while downloading the firmware. At this stage,
+ * the hardware does unfortunately not create any interrupts.
+ *
+ * Fortunately, this function is never used once the firmware is in
+ * the card. :-)
+ *
+ * As a reference, see the "Firmware Specification v5.1", page 18
+ * and 19. I did not follow their suggested timing to the word,
+ * but this works nice & fast anyway.
+ */
+static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 reg)
+{
+	int i;
+
+	for (i = 0; i < 500; i++) {
+		u8 val = if_cs_read8(card, addr);
+		if (val == reg)
+			return i;
+		udelay(100);
+	}
+	return -ETIME;
+}
+
+
+
+/* Host control registers and their bit definitions */
+
+#define IF_CS_H_STATUS			0x00000000
+#define IF_CS_H_STATUS_TX_OVER		0x0001
+#define IF_CS_H_STATUS_RX_OVER		0x0002
+#define IF_CS_H_STATUS_DNLD_OVER	0x0004
+
+#define IF_CS_H_INT_CAUSE		0x00000002
+#define IF_CS_H_IC_TX_OVER		0x0001
+#define IF_CS_H_IC_RX_OVER		0x0002
+#define IF_CS_H_IC_DNLD_OVER		0x0004
+#define IF_CS_H_IC_HOST_EVENT		0x0008
+#define IF_CS_H_IC_MASK			0x001f
+
+#define IF_CS_H_INT_MASK		0x00000004
+#define	IF_CS_H_IM_MASK			0x001f
+
+#define IF_CS_H_WRITE_LEN		0x00000014
+
+#define IF_CS_H_WRITE			0x00000016
+
+#define IF_CS_H_CMD_LEN			0x00000018
+
+#define IF_CS_H_CMD			0x0000001A
+
+#define IF_CS_C_READ_LEN		0x00000024
+
+#define IF_CS_H_READ			0x00000010
+
+/* Card control registers and their bit definitions */
+
+#define IF_CS_C_STATUS			0x00000020
+#define IF_CS_C_S_TX_DNLD_RDY		0x0001
+#define IF_CS_C_S_RX_UPLD_RDY		0x0002
+#define IF_CS_C_S_CMD_DNLD_RDY		0x0004
+#define IF_CS_C_S_CMD_UPLD_RDY		0x0008
+#define IF_CS_C_S_CARDEVENT		0x0010
+#define IF_CS_C_S_MASK			0x001f
+#define IF_CS_C_S_STATUS_MASK		0x7f00
+/* The following definitions should be the same as the MRVDRV_ ones */
+
+#if MRVDRV_CMD_DNLD_RDY != IF_CS_C_S_CMD_DNLD_RDY
+#error MRVDRV_CMD_DNLD_RDY and IF_CS_C_S_CMD_DNLD_RDY not in sync
+#endif
+#if MRVDRV_CMD_UPLD_RDY != IF_CS_C_S_CMD_UPLD_RDY
+#error MRVDRV_CMD_UPLD_RDY and IF_CS_C_S_CMD_UPLD_RDY not in sync
+#endif
+#if MRVDRV_CARDEVENT != IF_CS_C_S_CARDEVENT
+#error MRVDRV_CARDEVENT and IF_CS_C_S_CARDEVENT not in sync
+#endif
+
+#define IF_CS_C_INT_CAUSE		0x00000022
+#define	IF_CS_C_IC_MASK			0x001f
+
+#define IF_CS_C_SQ_READ_LOW		0x00000028
+#define IF_CS_C_SQ_HELPER_OK		0x10
+
+#define IF_CS_C_CMD_LEN			0x00000030
+
+#define IF_CS_C_CMD			0x00000012
+
+#define IF_CS_SCRATCH			0x0000003F
+
+
+
+/********************************************************************/
+/* Interrupts                                                       */
+/********************************************************************/
+
+static inline void if_cs_enable_ints(struct if_cs_card *card)
+{
+	lbs_deb_enter(LBS_DEB_CS);
+	if_cs_write16(card, IF_CS_H_INT_MASK, 0);
+}
+
+static inline void if_cs_disable_ints(struct if_cs_card *card)
+{
+	lbs_deb_enter(LBS_DEB_CS);
+	if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
+}
+
+static irqreturn_t if_cs_interrupt(int irq, void *data)
+{
+	struct if_cs_card *card = (struct if_cs_card *)data;
+	u16 int_cause;
+
+	lbs_deb_enter(LBS_DEB_CS);
+
+	int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
+	if(int_cause == 0x0) {
+		/* Not for us */
+		return IRQ_NONE;
+
+	} else if(int_cause == 0xffff) {
+		/* Read in junk, the card has probably been removed */
+		card->priv->adapter->surpriseremoved = 1;
+
+	} else {
+		if(int_cause & IF_CS_H_IC_TX_OVER) {
+			card->priv->dnld_sent = DNLD_RES_RECEIVED;
+			if (!card->priv->adapter->cur_cmd)
+				wake_up_interruptible(&card->priv->waitq);
+
+			if (card->priv->adapter->connect_status == LIBERTAS_CONNECTED)
+				netif_wake_queue(card->priv->dev);
+		}
+
+		/* clear interrupt */
+		if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause & IF_CS_C_IC_MASK);
+	}
+
+	libertas_interrupt(card->priv->dev);
+
+	return IRQ_HANDLED;
+}
+
+
+
+
+/********************************************************************/
+/* I/O                                                              */
+/********************************************************************/
+
+/*
+ * Called from if_cs_host_to_card to send a command to the hardware
+ */
+static int if_cs_send_cmd(wlan_private *priv, u8 *buf, u16 nb)
+{
+	struct if_cs_card *card = (struct if_cs_card *)priv->card;
+	int ret = -1;
+	int loops = 0;
+
+	lbs_deb_enter(LBS_DEB_CS);
+
+	/* Is hardware ready? */
+	while (1) {
+		u16 val = if_cs_read16(card, IF_CS_C_STATUS);
+		if (val & IF_CS_C_S_CMD_DNLD_RDY)
+			break;
+		if (++loops > 100) {
+			lbs_pr_err("card not ready for commands\n");
+			goto done;
+		}
+		mdelay(1);
+	}
+
+	if_cs_write16(card, IF_CS_H_CMD_LEN, nb);
+
+	if_cs_write16_rep(card, IF_CS_H_CMD, buf, nb / 2);
+	/* Are we supposed to transfer an odd amount of bytes? */
+	if (nb & 1)
+		if_cs_write8(card, IF_CS_H_CMD, buf[nb-1]);
+
+	/* "Assert the download over interrupt command in the Host
+	 * status register" */
+	if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
+
+	/* "Assert the download over interrupt command in the Card
+	 * interrupt case register" */
+	if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
+	ret = 0;
+
+done:
+	lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+	return ret;
+}
+
+
+/*
+ * Called from if_cs_host_to_card to send a data to the hardware
+ */
+static void if_cs_send_data(wlan_private *priv, u8 *buf, u16 nb)
+{
+	struct if_cs_card *card = (struct if_cs_card *)priv->card;
+
+	lbs_deb_enter(LBS_DEB_CS);
+
+	if_cs_write16(card, IF_CS_H_WRITE_LEN, nb);
+
+	/* write even number of bytes, then odd byte if necessary */
+	if_cs_write16_rep(card, IF_CS_H_WRITE, buf, nb / 2);
+	if (nb & 1)
+		if_cs_write8(card, IF_CS_H_WRITE, buf[nb-1]);
+
+	if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_TX_OVER);
+	if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_STATUS_TX_OVER);
+
+	lbs_deb_leave(LBS_DEB_CS);
+}
+
+
+/*
+ * Get the command result out of the card.
+ */
+static int if_cs_receive_cmdres(wlan_private *priv, u8* data, u32 *len)
+{
+	int ret = -1;
+	u16 val;
+
+	lbs_deb_enter(LBS_DEB_CS);
+
+	/* is hardware ready? */
+	val = if_cs_read16(priv->card, IF_CS_C_STATUS);
+	if ((val & IF_CS_C_S_CMD_UPLD_RDY) == 0) {
+		lbs_pr_err("card not ready for CMD\n");
+		goto out;
+	}
+
+	*len = if_cs_read16(priv->card, IF_CS_C_CMD_LEN);
+	if ((*len == 0) || (*len > MRVDRV_SIZE_OF_CMD_BUFFER)) {
+		lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len);
+		goto out;
+	}
+
+	/* read even number of bytes, then odd byte if necessary */
+	if_cs_read16_rep(priv->card, IF_CS_C_CMD, data, *len/sizeof(u16));
+	if (*len & 1)
+		data[*len-1] = if_cs_read8(priv->card, IF_CS_C_CMD);
+
+	ret = 0;
+out:
+	lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len);
+	return ret;
+}
+
+
+static struct sk_buff *if_cs_receive_data(wlan_private *priv)
+{
+	struct sk_buff *skb = NULL;
+	u16 len;
+	u8 *data;
+
+	lbs_deb_enter(LBS_DEB_CS);
+
+	len = if_cs_read16(priv->card, IF_CS_C_READ_LEN);
+	if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
+		lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
+		priv->stats.rx_dropped++;
+		printk(KERN_INFO "##HS %s:%d TODO\n", __FUNCTION__, __LINE__);
+		goto dat_err;
+	}
+
+	//TODO: skb = dev_alloc_skb(len+ETH_FRAME_LEN+MRVDRV_SNAP_HEADER_LEN+EXTRA_LEN);
+	skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2);
+	if (!skb)
+		goto out;
+	skb_put(skb, len);
+	skb_reserve(skb, 2);/* 16 byte align */
+	data = skb->data;
+
+	/* read even number of bytes, then odd byte if necessary */
+	if_cs_read16_rep(priv->card, IF_CS_H_READ, data, len/sizeof(u16));
+	if (len & 1)
+		data[len-1] = if_cs_read8(priv->card, IF_CS_H_READ);
+
+dat_err:
+	if_cs_write16(priv->card, IF_CS_H_STATUS, IF_CS_H_STATUS_RX_OVER);
+	if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_RX_OVER);
+
+out:
+	lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb);
+	return skb;
+}
+
+
+
+/********************************************************************/
+/* Firmware                                                         */
+/********************************************************************/
+
+/*
+ * Tries to program the helper firmware.
+ *
+ * Return 0 on success
+ */
+static int if_cs_prog_helper(struct if_cs_card *card)
+{
+	int ret = 0;
+	int sent = 0;
+	u8  scratch;
+	const struct firmware *fw;
+
+	lbs_deb_enter(LBS_DEB_CS);
+
+	scratch = if_cs_read8(card, IF_CS_SCRATCH);
+
+	/* "If the value is 0x5a, the firmware is already
+	 * downloaded successfully"
+	 */
+	if (scratch == 0x5a)
+		goto done;
+
+	/* "If the value is != 00, it is invalid value of register */
+	if (scratch != 0x00) {
+		ret = -ENODEV;
+		goto done;
+	}
+
+	/* TODO: make firmware file configurable */
+	ret = request_firmware(&fw, "libertas_cs_helper.fw",
+		&handle_to_dev(card->p_dev));
+	if (ret) {
+		lbs_pr_err("can't load helper firmware\n");
+		ret = -ENODEV;
+		goto done;
+	}
+	lbs_deb_cs("helper size %td\n", fw->size);
+
+	/* "Set the 5 bytes of the helper image to 0" */
+	/* Not needed, this contains an ARM branch instruction */
+
+	for (;;) {
+		/* "the number of bytes to send is 256" */
+		int count = 256;
+		int remain = fw->size - sent;
+
+		if (remain < count)
+			count = remain;
+		/* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
+			__LINE__, sent, fw->size); */
+
+		/* "write the number of bytes to be sent to the I/O Command
+		 * write length register" */
+		if_cs_write16(card, IF_CS_H_CMD_LEN, count);
+
+		/* "write this to I/O Command port register as 16 bit writes */
+		if (count)
+			if_cs_write16_rep(card, IF_CS_H_CMD,
+				&fw->data[sent],
+				count >> 1);
+
+		/* "Assert the download over interrupt command in the Host
+		 * status register" */
+		if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
+
+		/* "Assert the download over interrupt command in the Card
+		 * interrupt case register" */
+		if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
+
+		/* "The host polls the Card Status register ... for 50 ms before
+		   declaring a failure */
+		ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,
+			IF_CS_C_S_CMD_DNLD_RDY);
+		if (ret < 0) {
+			lbs_pr_err("can't download helper at 0x%x, ret %d\n",
+				sent, ret);
+			goto done;
+		}
+
+		if (count == 0)
+			break;
+
+		sent += count;
+	}
+
+	release_firmware(fw);
+	ret = 0;
+
+done:
+	lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+	return ret;
+}
+
+
+static int if_cs_prog_real(struct if_cs_card *card)
+{
+	const struct firmware *fw;
+	int ret = 0;
+	int retry = 0;
+	int len = 0;
+	int sent;
+
+	lbs_deb_enter(LBS_DEB_CS);
+
+	/* TODO: make firmware file configurable */
+	ret = request_firmware(&fw, "libertas_cs.fw",
+		&handle_to_dev(card->p_dev));
+	if (ret) {
+		lbs_pr_err("can't load firmware\n");
+		ret = -ENODEV;
+		goto done;
+	}
+	lbs_deb_cs("fw size %td\n", fw->size);
+
+	ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK);
+	if (ret < 0) {
+		int i;
+		lbs_pr_err("helper firmware doesn't answer\n");
+		for (i = 0; i < 0x50; i += 2)
+			printk(KERN_INFO "## HS %02x: %04x\n",
+				i, if_cs_read16(card, i));
+		goto err_release;
+	}
+
+	for (sent = 0; sent < fw->size; sent += len) {
+		len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW);
+		/* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
+			__LINE__, sent, fw->size); */
+		if (len & 1) {
+			retry++;
+			lbs_pr_info("odd, need to retry this firmware block\n");
+		} else {
+			retry = 0;
+		}
+
+		if (retry > 20) {
+			lbs_pr_err("could not download firmware\n");
+			ret = -ENODEV;
+			goto err_release;
+		}
+		if (retry) {
+			sent -= len;
+		}
+
+
+		if_cs_write16(card, IF_CS_H_CMD_LEN, len);
+
+		if_cs_write16_rep(card, IF_CS_H_CMD,
+			&fw->data[sent],
+			(len+1) >> 1);
+		if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER);
+		if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER);
+
+		ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS,
+			IF_CS_C_S_CMD_DNLD_RDY);
+		if (ret < 0) {
+			lbs_pr_err("can't download firmware at 0x%x\n", sent);
+			goto err_release;
+		}
+	}
+
+	ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a);
+	if (ret < 0) {
+		lbs_pr_err("firmware download failed\n");
+		goto err_release;
+	}
+
+	ret = 0;
+	goto done;
+
+
+err_release:
+	release_firmware(fw);
+
+done:
+	lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+	return ret;
+}
+
+
+
+/********************************************************************/
+/* Callback functions for libertas.ko                               */
+/********************************************************************/
+
+/* Send commands or data packets to the card */
+static int if_cs_host_to_card(wlan_private *priv, u8 type, u8 *buf, u16 nb)
+{
+	int ret = -1;
+
+	lbs_deb_enter_args(LBS_DEB_CS, "type %d, bytes %d", type, nb);
+
+	switch (type) {
+	case MVMS_DAT:
+		priv->dnld_sent = DNLD_DATA_SENT;
+		if_cs_send_data(priv, buf, nb);
+		ret = 0;
+		break;
+	case MVMS_CMD:
+		priv->dnld_sent = DNLD_CMD_SENT;
+		ret = if_cs_send_cmd(priv, buf, nb);
+		break;
+	default:
+		lbs_pr_err("%s: unsupported type %d\n", __FUNCTION__, type);
+	}
+
+	lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+	return ret;
+}
+
+
+static int if_cs_get_int_status(wlan_private *priv, u8 *ireg)
+{
+	struct if_cs_card *card = (struct if_cs_card *)priv->card;
+	//wlan_adapter *adapter = priv->adapter;
+	int ret = 0;
+	u16 int_cause;
+	u8 *cmdbuf;
+	*ireg = 0;
+
+	lbs_deb_enter(LBS_DEB_CS);
+
+	if (priv->adapter->surpriseremoved)
+		goto out;
+
+	int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE) & IF_CS_C_IC_MASK;
+	if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause);
+
+	*ireg = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;
+
+	if (!*ireg)
+		goto sbi_get_int_status_exit;
+
+sbi_get_int_status_exit:
+
+	/* is there a data packet for us? */
+	if (*ireg & IF_CS_C_S_RX_UPLD_RDY) {
+		struct sk_buff *skb = if_cs_receive_data(priv);
+		libertas_process_rxed_packet(priv, skb);
+		*ireg &= ~IF_CS_C_S_RX_UPLD_RDY;
+	}
+
+	if (*ireg & IF_CS_C_S_TX_DNLD_RDY) {
+		priv->dnld_sent = DNLD_RES_RECEIVED;
+	}
+
+	/* Card has a command result for us */
+	if (*ireg & IF_CS_C_S_CMD_UPLD_RDY) {
+		spin_lock(&priv->adapter->driver_lock);
+		if (!priv->adapter->cur_cmd) {
+			cmdbuf = priv->upld_buf;
+			priv->adapter->hisregcpy &= ~IF_CS_C_S_RX_UPLD_RDY;
+		} else {
+			cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr;
+		}
+
+		ret = if_cs_receive_cmdres(priv, cmdbuf, &priv->upld_len);
+		spin_unlock(&priv->adapter->driver_lock);
+		if (ret < 0)
+			lbs_pr_err("could not receive cmd from card\n");
+	}
+
+out:
+	lbs_deb_leave_args(LBS_DEB_CS, "ret %d, ireg 0x%x, hisregcpy 0x%x", ret, *ireg, priv->adapter->hisregcpy);
+	return ret;
+}
+
+
+static int if_cs_read_event_cause(wlan_private *priv)
+{
+	lbs_deb_enter(LBS_DEB_CS);
+
+	priv->adapter->eventcause = (if_cs_read16(priv->card, IF_CS_C_STATUS) & IF_CS_C_S_STATUS_MASK) >> 5;
+	if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_HOST_EVENT);
+
+	return 0;
+}
+
+
+
+/********************************************************************/
+/* Card Services                                                    */
+/********************************************************************/
+
+/*
+ * After a card is removed, if_cs_release() will unregister the
+ * device, and release the PCMCIA configuration.  If the device is
+ * still open, this will be postponed until it is closed.
+ */
+static void if_cs_release(struct pcmcia_device *p_dev)
+{
+	struct if_cs_card *card = p_dev->priv;
+
+	lbs_deb_enter(LBS_DEB_CS);
+
+	pcmcia_disable_device(p_dev);
+	free_irq(p_dev->irq.AssignedIRQ, card);
+	if (card->iobase)
+		ioport_unmap(card->iobase);
+
+	lbs_deb_leave(LBS_DEB_CS);
+}
+
+
+/*
+ * This creates an "instance" of the driver, allocating local data
+ * structures for one device.  The device is registered with Card
+ * Services.
+ *
+ * The dev_link structure is initialized, but we don't actually
+ * configure the card at this point -- we wait until we receive a card
+ * insertion event.
+ */
+static int if_cs_probe(struct pcmcia_device *p_dev)
+{
+	int ret = -ENOMEM;
+	wlan_private *priv;
+	struct if_cs_card *card;
+	/* CIS parsing */
+	tuple_t tuple;
+	cisparse_t parse;
+	cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
+	cistpl_io_t *io = &cfg->io;
+	u_char buf[64];
+
+	lbs_deb_enter(LBS_DEB_CS);
+
+	card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL);
+	if (!card) {
+		lbs_pr_err("error in kzalloc\n");
+		goto out;
+	}
+	card->p_dev = p_dev;
+	p_dev->priv = card;
+
+	p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
+	p_dev->irq.Handler = NULL;
+	p_dev->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+
+	p_dev->conf.Attributes = 0;
+	p_dev->conf.IntType = INT_MEMORY_AND_IO;
+
+	tuple.Attributes = 0;
+	tuple.TupleData = buf;
+	tuple.TupleDataMax = sizeof(buf);
+	tuple.TupleOffset = 0;
+
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	if ((ret = pcmcia_get_first_tuple(p_dev, &tuple)) != 0 ||
+	    (ret = pcmcia_get_tuple_data(p_dev, &tuple)) != 0 ||
+	    (ret = pcmcia_parse_tuple(p_dev, &tuple, &parse)) != 0)
+	{
+		lbs_pr_err("error in pcmcia_get_first_tuple etc\n");
+		goto out1;
+	}
+
+	p_dev->conf.ConfigIndex = cfg->index;
+
+	/* Do we need to allocate an interrupt? */
+	if (cfg->irq.IRQInfo1) {
+		p_dev->conf.Attributes |= CONF_ENABLE_IRQ;
+	}
+
+	/* IO window settings */
+	if (cfg->io.nwin != 1) {
+		lbs_pr_err("wrong CIS (check number of IO windows)\n");
+		ret = -ENODEV;
+		goto out1;
+	}
+	p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+	p_dev->io.BasePort1 = io->win[0].base;
+	p_dev->io.NumPorts1 = io->win[0].len;
+
+	/* This reserves IO space but doesn't actually enable it */
+	ret = pcmcia_request_io(p_dev, &p_dev->io);
+	if (ret) {
+		lbs_pr_err("error in pcmcia_request_io\n");
+		goto out1;
+	}
+
+	/*
+	 * Allocate an interrupt line.  Note that this does not assign
+	 * a handler to the interrupt, unless the 'Handler' member of
+	 * the irq structure is initialized.
+	 */
+	if (p_dev->conf.Attributes & CONF_ENABLE_IRQ) {
+		ret = pcmcia_request_irq(p_dev, &p_dev->irq);
+		if (ret) {
+			lbs_pr_err("error in pcmcia_request_irq\n");
+			goto out1;
+		}
+	}
+
+	/* Initialize io access */
+	card->iobase = ioport_map(p_dev->io.BasePort1, p_dev->io.NumPorts1);
+	if (!card->iobase) {
+		lbs_pr_err("error in ioport_map\n");
+		ret = -EIO;
+		goto out1;
+	}
+
+	/*
+	 * This actually configures the PCMCIA socket -- setting up
+	 * the I/O windows and the interrupt mapping, and putting the
+	 * card and host interface into "Memory and IO" mode.
+	 */
+	ret = pcmcia_request_configuration(p_dev, &p_dev->conf);
+	if (ret) {
+		lbs_pr_err("error in pcmcia_request_configuration\n");
+		goto out2;
+	}
+
+	/* Finally, report what we've done */
+	lbs_deb_cs("irq %d, io 0x%04x-0x%04x\n",
+	       p_dev->irq.AssignedIRQ, p_dev->io.BasePort1,
+	       p_dev->io.BasePort1 + p_dev->io.NumPorts1 - 1);
+
+
+	/* Load the firmware early, before calling into libertas.ko */
+	ret = if_cs_prog_helper(card);
+	if (ret == 0)
+		ret = if_cs_prog_real(card);
+	if (ret)
+		goto out2;
+
+	/* Make this card known to the libertas driver */
+	priv = libertas_add_card(card, &p_dev->dev);
+	if (!priv) {
+		ret = -ENOMEM;
+		goto out2;
+	}
+
+	/* Store pointers to our call-back functions */
+	card->priv = priv;
+	priv->card = card;
+	priv->hw_host_to_card     = if_cs_host_to_card;
+	priv->hw_get_int_status   = if_cs_get_int_status;
+	priv->hw_read_event_cause = if_cs_read_event_cause;
+
+	priv->adapter->fw_ready = 1;
+
+	/* Now actually get the IRQ */
+	ret = request_irq(p_dev->irq.AssignedIRQ, if_cs_interrupt,
+		IRQF_SHARED, DRV_NAME, card);
+	if (ret) {
+		lbs_pr_err("error in request_irq\n");
+		goto out3;
+	}
+
+	if_cs_enable_ints(card);
+
+	/* And finally bring the card up */
+	if (libertas_start_card(priv) != 0) {
+		lbs_pr_err("could not activate card\n");
+		goto out3;
+	}
+
+	ret = 0;
+	goto out;
+
+out3:
+	libertas_remove_card(priv);
+out2:
+	ioport_unmap(card->iobase);
+out1:
+	pcmcia_disable_device(p_dev);
+out:
+	lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
+	return ret;
+}
+
+
+/*
+ * This deletes a driver "instance".  The device is de-registered with
+ * Card Services.  If it has been released, all local data structures
+ * are freed.  Otherwise, the structures will be freed when the device
+ * is released.
+ */
+static void if_cs_detach(struct pcmcia_device *p_dev)
+{
+	struct if_cs_card *card = p_dev->priv;
+
+	lbs_deb_enter(LBS_DEB_CS);
+
+	libertas_stop_card(card->priv);
+	libertas_remove_card(card->priv);
+	if_cs_disable_ints(card);
+	if_cs_release(p_dev);
+	kfree(card);
+
+	lbs_deb_leave(LBS_DEB_CS);
+}
+
+
+
+/********************************************************************/
+/* Module initialization                                            */
+/********************************************************************/
+
+static struct pcmcia_device_id if_cs_ids[] = {
+	PCMCIA_DEVICE_MANF_CARD(0x02df, 0x8103),
+	PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, if_cs_ids);
+
+
+static struct pcmcia_driver libertas_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= DRV_NAME,
+	},
+	.probe		= if_cs_probe,
+	.remove		= if_cs_detach,
+	.id_table       = if_cs_ids,
+};
+
+
+static int __init if_cs_init(void)
+{
+	int ret;
+
+	lbs_deb_enter(LBS_DEB_CS);
+	ret = pcmcia_register_driver(&libertas_driver);
+	lbs_deb_leave(LBS_DEB_CS);
+	return ret;
+}
+
+
+static void __exit if_cs_exit(void)
+{
+	lbs_deb_enter(LBS_DEB_CS);
+	pcmcia_unregister_driver(&libertas_driver);
+	lbs_deb_leave(LBS_DEB_CS);
+}
+
+
+module_init(if_cs_init);
+module_exit(if_cs_exit);
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 9983175..cb59f46 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -21,7 +21,7 @@
 static const char usbdriver_name[] = "usb8xxx";
 static u8 *default_fw_name = "usb8388.bin";
 
-char *libertas_fw_name = NULL;
+static char *libertas_fw_name = NULL;
 module_param_named(fw_name, libertas_fw_name, charp, 0644);
 
 /*
@@ -44,13 +44,14 @@
 
 static void if_usb_receive(struct urb *urb);
 static void if_usb_receive_fwload(struct urb *urb);
-static int if_usb_reset_device(wlan_private *priv);
-static int if_usb_register_dev(wlan_private * priv);
-static int if_usb_unregister_dev(wlan_private *);
-static int if_usb_prog_firmware(wlan_private *);
+static int if_usb_prog_firmware(struct usb_card_rec *cardp);
 static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb);
 static int if_usb_get_int_status(wlan_private * priv, u8 *);
 static int if_usb_read_event_cause(wlan_private *);
+static int usb_tx_block(struct usb_card_rec *cardp, u8 *payload, u16 nb);
+static void if_usb_free(struct usb_card_rec *cardp);
+static int if_usb_submit_rx_urb(struct usb_card_rec *cardp);
+static int if_usb_reset_device(struct usb_card_rec *cardp);
 
 /**
  *  @brief  call back function to handle the status of the URB
@@ -59,29 +60,40 @@
  */
 static void if_usb_write_bulk_callback(struct urb *urb)
 {
-	wlan_private *priv = (wlan_private *) (urb->context);
-	wlan_adapter *adapter = priv->adapter;
-	struct net_device *dev = priv->dev;
+	struct usb_card_rec *cardp = (struct usb_card_rec *) urb->context;
 
 	/* handle the transmission complete validations */
 
-	if (urb->status != 0) {
-		/* print the failure status number for debug */
-		lbs_pr_info("URB in failure status: %d\n", urb->status);
-	} else {
+	if (urb->status == 0) {
+		wlan_private *priv = cardp->priv;
+
 		/*
 		lbs_deb_usbd(&urb->dev->dev, "URB status is successfull\n");
 		lbs_deb_usbd(&urb->dev->dev, "Actual length transmitted %d\n",
 		       urb->actual_length);
 		*/
-		priv->dnld_sent = DNLD_RES_RECEIVED;
-		/* Wake main thread if commands are pending */
-		if (!adapter->cur_cmd)
-			wake_up_interruptible(&priv->mainthread.waitq);
-		if ((adapter->connect_status == libertas_connected)) {
-			netif_wake_queue(dev);
-			netif_wake_queue(priv->mesh_dev);
+
+		/* Used for both firmware TX and regular TX.  priv isn't
+		 * valid at firmware load time.
+		 */
+		if (priv) {
+			wlan_adapter *adapter = priv->adapter;
+			struct net_device *dev = priv->dev;
+
+			priv->dnld_sent = DNLD_RES_RECEIVED;
+
+			/* Wake main thread if commands are pending */
+			if (!adapter->cur_cmd)
+				wake_up_interruptible(&priv->waitq);
+
+			if ((adapter->connect_status == LIBERTAS_CONNECTED)) {
+				netif_wake_queue(dev);
+				netif_wake_queue(priv->mesh_dev);
+			}
 		}
+	} else {
+		/* print the failure status number for debug */
+		lbs_pr_info("URB in failure status: %d\n", urb->status);
 	}
 
 	return;
@@ -92,7 +104,7 @@
  *  @param cardp	pointer usb_card_rec
  *  @return 	   	N/A
  */
-void if_usb_free(struct usb_card_rec *cardp)
+static void if_usb_free(struct usb_card_rec *cardp)
 {
 	lbs_deb_enter(LBS_DEB_USB);
 
@@ -203,21 +215,35 @@
 		}
 	}
 
+	/* Upload firmware */
+	cardp->rinfo.cardp = cardp;
+	if (if_usb_prog_firmware(cardp)) {
+		lbs_deb_usbd(&udev->dev, "FW upload failed");
+		goto err_prog_firmware;
+	}
+
 	if (!(priv = libertas_add_card(cardp, &udev->dev)))
-		goto dealloc;
+		goto err_prog_firmware;
+
+	cardp->priv = priv;
 
 	if (libertas_add_mesh(priv, &udev->dev))
 		goto err_add_mesh;
 
-	priv->hw_register_dev = if_usb_register_dev;
-	priv->hw_unregister_dev = if_usb_unregister_dev;
-	priv->hw_prog_firmware = if_usb_prog_firmware;
+	cardp->eth_dev = priv->dev;
+
 	priv->hw_host_to_card = if_usb_host_to_card;
 	priv->hw_get_int_status = if_usb_get_int_status;
 	priv->hw_read_event_cause = if_usb_read_event_cause;
+	priv->boot2_version = udev->descriptor.bcdDevice;
 
-	if (libertas_activate_card(priv, libertas_fw_name))
-		goto err_activate_card;
+	/* Delay 200 ms to waiting for the FW ready */
+	if_usb_submit_rx_urb(cardp);
+	msleep_interruptible(200);
+	priv->adapter->fw_ready = 1;
+
+	if (libertas_start_card(priv))
+		goto err_start_card;
 
 	list_add_tail(&cardp->list, &usb_devices);
 
@@ -226,11 +252,12 @@
 
 	return 0;
 
-err_activate_card:
+err_start_card:
 	libertas_remove_mesh(priv);
 err_add_mesh:
-	free_netdev(priv->dev);
-	kfree(priv->adapter);
+	libertas_remove_card(priv);
+err_prog_firmware:
+	if_usb_reset_device(cardp);
 dealloc:
 	if_usb_free(cardp);
 
@@ -247,21 +274,22 @@
 {
 	struct usb_card_rec *cardp = usb_get_intfdata(intf);
 	wlan_private *priv = (wlan_private *) cardp->priv;
-	wlan_adapter *adapter = NULL;
 
-	adapter = priv->adapter;
+	lbs_deb_enter(LBS_DEB_MAIN);
 
-	/*
-	 * Update Surprise removed to TRUE
-	 */
-	adapter->surpriseremoved = 1;
+	/* Update Surprise removed to TRUE */
+	cardp->surprise_removed = 1;
 
 	list_del(&cardp->list);
 
-	/* card is removed and we can call wlan_remove_card */
-	lbs_deb_usbd(&cardp->udev->dev, "call remove card\n");
-	libertas_remove_mesh(priv);
-	libertas_remove_card(priv);
+	if (priv) {
+		wlan_adapter *adapter = priv->adapter;
+
+		adapter->surpriseremoved = 1;
+		libertas_stop_card(priv);
+		libertas_remove_mesh(priv);
+		libertas_remove_card(priv);
+	}
 
 	/* Unlink and free urb */
 	if_usb_free(cardp);
@@ -269,7 +297,7 @@
 	usb_set_intfdata(intf, NULL);
 	usb_put_dev(interface_to_usbdev(intf));
 
-	return;
+	lbs_deb_leave(LBS_DEB_MAIN);
 }
 
 /**
@@ -277,12 +305,11 @@
  *  @param priv		pointer to wlan_private
  *  @return 	   	0
  */
-static int if_prog_firmware(wlan_private * priv)
+static int if_prog_firmware(struct usb_card_rec *cardp)
 {
-	struct usb_card_rec *cardp = priv->card;
 	struct FWData *fwdata;
 	struct fwheader *fwheader;
-	u8 *firmware = priv->firmware->data;
+	u8 *firmware = cardp->fw->data;
 
 	fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC);
 
@@ -330,7 +357,7 @@
 			    cardp->totalbytes);
 		*/
 		memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
-		usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
+		usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
 
 	} else if (fwdata->fwheader.dnldcmd == cpu_to_le32(FW_HAS_LAST_BLOCK)) {
 		/*
@@ -340,7 +367,7 @@
 			    "Donwloading FW JUMP BLOCK\n");
 		*/
 		memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE);
-		usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
+		usb_tx_block(cardp, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE);
 		cardp->fwfinalblk = 1;
 	}
 
@@ -355,17 +382,20 @@
 	return 0;
 }
 
-static int libertas_do_reset(wlan_private *priv)
+static int if_usb_reset_device(struct usb_card_rec *cardp)
 {
 	int ret;
-	struct usb_card_rec *cardp = priv->card;
+	wlan_private * priv = cardp->priv;
 
 	lbs_deb_enter(LBS_DEB_USB);
 
+	/* Try a USB port reset first, if that fails send the reset
+	 * command to the firmware.
+	 */
 	ret = usb_reset_device(cardp->udev);
-	if (!ret) {
+	if (!ret && priv) {
 		msleep(10);
-		if_usb_reset_device(priv);
+		ret = libertas_reset_device(priv);
 		msleep(10);
 	}
 
@@ -381,14 +411,12 @@
  *  @param nb		data length
  *  @return 	   	0 or -1
  */
-int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb)
+static int usb_tx_block(struct usb_card_rec *cardp, u8 * payload, u16 nb)
 {
-	/* pointer to card structure */
-	struct usb_card_rec *cardp = priv->card;
 	int ret = -1;
 
 	/* check if device is removed */
-	if (priv->adapter->surpriseremoved) {
+	if (cardp->surprise_removed) {
 		lbs_deb_usbd(&cardp->udev->dev, "Device removed\n");
 		goto tx_ret;
 	}
@@ -396,7 +424,7 @@
 	usb_fill_bulk_urb(cardp->tx_urb, cardp->udev,
 			  usb_sndbulkpipe(cardp->udev,
 					  cardp->bulk_out_endpointAddr),
-			  payload, nb, if_usb_write_bulk_callback, priv);
+			  payload, nb, if_usb_write_bulk_callback, cardp);
 
 	cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET;
 
@@ -413,11 +441,9 @@
 	return ret;
 }
 
-static int __if_usb_submit_rx_urb(wlan_private * priv,
-				  void (*callbackfn)
-				  (struct urb *urb))
+static int __if_usb_submit_rx_urb(struct usb_card_rec *cardp,
+				  void (*callbackfn)(struct urb *urb))
 {
-	struct usb_card_rec *cardp = priv->card;
 	struct sk_buff *skb;
 	struct read_cb_info *rinfo = &cardp->rinfo;
 	int ret = -1;
@@ -453,22 +479,21 @@
 	return ret;
 }
 
-static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv)
+static int if_usb_submit_rx_urb_fwload(struct usb_card_rec *cardp)
 {
-	return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload);
+	return __if_usb_submit_rx_urb(cardp, &if_usb_receive_fwload);
 }
 
-static inline int if_usb_submit_rx_urb(wlan_private * priv)
+static int if_usb_submit_rx_urb(struct usb_card_rec *cardp)
 {
-	return __if_usb_submit_rx_urb(priv, &if_usb_receive);
+	return __if_usb_submit_rx_urb(cardp, &if_usb_receive);
 }
 
 static void if_usb_receive_fwload(struct urb *urb)
 {
 	struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
-	wlan_private *priv = rinfo->priv;
 	struct sk_buff *skb = rinfo->skb;
-	struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
+	struct usb_card_rec *cardp = (struct usb_card_rec *)rinfo->cardp;
 	struct fwsyncheader *syncfwheader;
 	struct bootcmdrespStr bootcmdresp;
 
@@ -484,7 +509,7 @@
 			sizeof(bootcmdresp));
 		if (le16_to_cpu(cardp->udev->descriptor.bcdDevice) < 0x3106) {
 			kfree_skb(skb);
-			if_usb_submit_rx_urb_fwload(priv);
+			if_usb_submit_rx_urb_fwload(cardp);
 			cardp->bootcmdresp = 1;
 			lbs_deb_usbd(&cardp->udev->dev,
 				    "Received valid boot command response\n");
@@ -508,7 +533,7 @@
 				    "Received valid boot command response\n");
 		}
 		kfree_skb(skb);
-		if_usb_submit_rx_urb_fwload(priv);
+		if_usb_submit_rx_urb_fwload(cardp);
 		return;
 	}
 
@@ -544,9 +569,9 @@
 		goto exit;
 	}
 
-	if_prog_firmware(priv);
+	if_prog_firmware(cardp);
 
-	if_usb_submit_rx_urb_fwload(priv);
+	if_usb_submit_rx_urb_fwload(cardp);
 exit:
 	kfree(syncfwheader);
 
@@ -596,11 +621,11 @@
 	 * data to clear the interrupt */
 	if (!priv->adapter->cur_cmd) {
 		cmdbuf = priv->upld_buf;
-		priv->adapter->hisregcpy &= ~his_cmdupldrdy;
+		priv->adapter->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
 	} else
 		cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr;
 
-	cardp->usb_int_cause |= his_cmdupldrdy;
+	cardp->usb_int_cause |= MRVDRV_CMD_UPLD_RDY;
 	priv->upld_len = (recvlength - MESSAGE_HEADER_LEN);
 	memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN,
 	       priv->upld_len);
@@ -625,17 +650,19 @@
 static void if_usb_receive(struct urb *urb)
 {
 	struct read_cb_info *rinfo = (struct read_cb_info *)urb->context;
-	wlan_private *priv = rinfo->priv;
 	struct sk_buff *skb = rinfo->skb;
-	struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
+	struct usb_card_rec *cardp = (struct usb_card_rec *) rinfo->cardp;
+	wlan_private * priv = cardp->priv;
 
 	int recvlength = urb->actual_length;
 	u8 *recvbuff = NULL;
-	u32 recvtype;
+	u32 recvtype = 0;
 
 	lbs_deb_enter(LBS_DEB_USB);
 
 	if (recvlength) {
+		__le32 tmp;
+
 		if (urb->status) {
 			lbs_deb_usbd(&cardp->udev->dev,
 				    "URB status is failed\n");
@@ -644,18 +671,14 @@
 		}
 
 		recvbuff = skb->data + IPFIELD_ALIGN_OFFSET;
-		memcpy(&recvtype, recvbuff, sizeof(u32));
+		memcpy(&tmp, recvbuff, sizeof(u32));
+		recvtype = le32_to_cpu(tmp);
 		lbs_deb_usbd(&cardp->udev->dev,
-			    "Recv length = 0x%x\n", recvlength);
-		lbs_deb_usbd(&cardp->udev->dev,
-			    "Receive type = 0x%X\n", recvtype);
-		recvtype = le32_to_cpu(recvtype);
-		lbs_deb_usbd(&cardp->udev->dev,
-			    "Receive type after = 0x%X\n", recvtype);
+			    "Recv length = 0x%x, Recv type = 0x%X\n",
+			    recvlength, recvtype);
 	} else if (urb->status)
 		goto rx_exit;
 
-
 	switch (recvtype) {
 	case CMD_TYPE_DATA:
 		process_cmdtypedata(recvlength, skb, cardp, priv);
@@ -677,18 +700,20 @@
 			break;
 		}
 		cardp->usb_event_cause <<= 3;
-		cardp->usb_int_cause |= his_cardevent;
+		cardp->usb_int_cause |= MRVDRV_CARDEVENT;
 		kfree_skb(skb);
 		libertas_interrupt(priv->dev);
 		spin_unlock(&priv->adapter->driver_lock);
 		goto rx_exit;
 	default:
+		lbs_deb_usbd(&cardp->udev->dev, "Unknown command type 0x%X\n",
+		             recvtype);
 		kfree_skb(skb);
 		break;
 	}
 
 setup_for_next:
-	if_usb_submit_rx_urb(priv);
+	if_usb_submit_rx_urb(cardp);
 rx_exit:
 	lbs_deb_leave(LBS_DEB_USB);
 }
@@ -703,21 +728,19 @@
  */
 static int if_usb_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb)
 {
-	int ret = -1;
-	u32 tmp;
 	struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
 
 	lbs_deb_usbd(&cardp->udev->dev,"*** type = %u\n", type);
 	lbs_deb_usbd(&cardp->udev->dev,"size after = %d\n", nb);
 
 	if (type == MVMS_CMD) {
-		tmp = cpu_to_le32(CMD_TYPE_REQUEST);
+		__le32 tmp = cpu_to_le32(CMD_TYPE_REQUEST);
 		priv->dnld_sent = DNLD_CMD_SENT;
 		memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
 		       MESSAGE_HEADER_LEN);
 
 	} else {
-		tmp = cpu_to_le32(CMD_TYPE_DATA);
+		__le32 tmp = cpu_to_le32(CMD_TYPE_DATA);
 		priv->dnld_sent = DNLD_DATA_SENT;
 		memcpy(cardp->bulk_out_buffer, (u8 *) & tmp,
 		       MESSAGE_HEADER_LEN);
@@ -725,10 +748,8 @@
 
 	memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb);
 
-	ret =
-	    usb_tx_block(priv, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN);
-
-	return ret;
+	return usb_tx_block(cardp, cardp->bulk_out_buffer,
+	                    nb + MESSAGE_HEADER_LEN);
 }
 
 /* called with adapter->driver_lock held */
@@ -747,80 +768,109 @@
 static int if_usb_read_event_cause(wlan_private * priv)
 {
 	struct usb_card_rec *cardp = priv->card;
+
 	priv->adapter->eventcause = cardp->usb_event_cause;
 	/* Re-submit rx urb here to avoid event lost issue */
-	if_usb_submit_rx_urb(priv);
+	if_usb_submit_rx_urb(cardp);
 	return 0;
 }
 
-static int if_usb_reset_device(wlan_private *priv)
+/**
+ *  @brief This function issues Boot command to the Boot2 code
+ *  @param ivalue   1:Boot from FW by USB-Download
+ *                  2:Boot from FW in EEPROM
+ *  @return 	   	0
+ */
+static int if_usb_issue_boot_command(struct usb_card_rec *cardp, int ivalue)
 {
-	int ret;
+	struct bootcmdstr sbootcmd;
+	int i;
 
-	lbs_deb_enter(LBS_DEB_USB);
-	ret = libertas_prepare_and_send_command(priv, cmd_802_11_reset,
-				    cmd_act_halt, 0, 0, NULL);
-	msleep_interruptible(10);
+	/* Prepare command */
+	sbootcmd.u32magicnumber = cpu_to_le32(BOOT_CMD_MAGIC_NUMBER);
+	sbootcmd.u8cmd_tag = ivalue;
+	for (i=0; i<11; i++)
+		sbootcmd.au8dumy[i]=0x00;
+	memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr));
 
-	lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
-	return ret;
-}
+	/* Issue command */
+	usb_tx_block(cardp, cardp->bulk_out_buffer, sizeof(struct bootcmdstr));
 
-static int if_usb_unregister_dev(wlan_private * priv)
-{
-	int ret = 0;
-
-	/* Need to send a Reset command to device before USB resources freed
-	 * and wlan_remove_card() called, then device can handle FW download
-	 * again.
-	 */
-	if (priv)
-		if_usb_reset_device(priv);
-
-	return ret;
+	return 0;
 }
 
 
 /**
- *  @brief  This function register usb device and initialize parameter
- *  @param		priv pointer to wlan_private
- *  @return		0 or -1
+ *  @brief This function checks the validity of Boot2/FW image.
+ *
+ *  @param data              pointer to image
+ *         len               image length
+ *  @return     0 or -1
  */
-static int if_usb_register_dev(wlan_private * priv)
+static int check_fwfile_format(u8 *data, u32 totlen)
 {
-	struct usb_card_rec *cardp = (struct usb_card_rec *)priv->card;
+	u32 bincmd, exit;
+	u32 blksize, offset, len;
+	int ret;
 
-	lbs_deb_enter(LBS_DEB_USB);
+	ret = 1;
+	exit = len = 0;
 
-	cardp->priv = priv;
-	cardp->eth_dev = priv->dev;
-	priv->hotplug_device = &(cardp->udev->dev);
+	do {
+		struct fwheader *fwh = (void *)data;
 
-	lbs_deb_usbd(&cardp->udev->dev, "udev pointer is at %p\n",
-		    cardp->udev);
+		bincmd = le32_to_cpu(fwh->dnldcmd);
+		blksize = le32_to_cpu(fwh->datalength);
+		switch (bincmd) {
+		case FW_HAS_DATA_TO_RECV:
+			offset = sizeof(struct fwheader) + blksize;
+			data += offset;
+			len += offset;
+			if (len >= totlen)
+				exit = 1;
+			break;
+		case FW_HAS_LAST_BLOCK:
+			exit = 1;
+			ret = 0;
+			break;
+		default:
+			exit = 1;
+			break;
+		}
+	} while (!exit);
 
-	lbs_deb_leave(LBS_DEB_USB);
-	return 0;
+	if (ret)
+		lbs_pr_err("firmware file format check FAIL\n");
+	else
+		lbs_deb_fw("firmware file format check PASS\n");
+
+	return ret;
 }
 
 
-
-static int if_usb_prog_firmware(wlan_private * priv)
+static int if_usb_prog_firmware(struct usb_card_rec *cardp)
 {
-	struct usb_card_rec *cardp = priv->card;
 	int i = 0;
 	static int reset_count = 10;
 	int ret = 0;
 
 	lbs_deb_enter(LBS_DEB_USB);
 
-	cardp->rinfo.priv = priv;
+	if ((ret = request_firmware(&cardp->fw, libertas_fw_name,
+				    &cardp->udev->dev)) < 0) {
+		lbs_pr_err("request_firmware() failed with %#x\n", ret);
+		lbs_pr_err("firmware %s not found\n", libertas_fw_name);
+		goto done;
+	}
+
+	if (check_fwfile_format(cardp->fw->data, cardp->fw->size))
+		goto release_fw;
 
 restart:
-	if (if_usb_submit_rx_urb_fwload(priv) < 0) {
+	if (if_usb_submit_rx_urb_fwload(cardp) < 0) {
 		lbs_deb_usbd(&cardp->udev->dev, "URB submission is failed\n");
 		ret = -1;
-		goto done;
+		goto release_fw;
 	}
 
 	cardp->bootcmdresp = 0;
@@ -828,7 +878,7 @@
 		int j = 0;
 		i++;
 		/* Issue Boot command = 1, Boot from Download-FW */
-		if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB);
+		if_usb_issue_boot_command(cardp, BOOT_CMD_FW_BY_USB);
 		/* wait for command response */
 		do {
 			j++;
@@ -838,14 +888,13 @@
 
 	if (cardp->bootcmdresp == 0) {
 		if (--reset_count >= 0) {
-			libertas_do_reset(priv);
+			if_usb_reset_device(cardp);
 			goto restart;
 		}
 		return -1;
 	}
 
 	i = 0;
-	priv->adapter->fw_ready = 0;
 
 	cardp->totalbytes = 0;
 	cardp->fwlastblksent = 0;
@@ -855,40 +904,38 @@
 	cardp->totalbytes = 0;
 	cardp->fwfinalblk = 0;
 
-	if_prog_firmware(priv);
+	if_prog_firmware(cardp);
 
 	do {
 		lbs_deb_usbd(&cardp->udev->dev,"Wlan sched timeout\n");
 		i++;
 		msleep_interruptible(100);
-		if (priv->adapter->surpriseremoved || i >= 20)
+		if (cardp->surprise_removed || i >= 20)
 			break;
 	} while (!cardp->fwdnldover);
 
 	if (!cardp->fwdnldover) {
 		lbs_pr_info("failed to load fw, resetting device!\n");
 		if (--reset_count >= 0) {
-			libertas_do_reset(priv);
+			if_usb_reset_device(cardp);
 			goto restart;
 		}
 
 		lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
 		ret = -1;
-		goto done;
+		goto release_fw;
 	}
 
-	if_usb_submit_rx_urb(priv);
-
-	/* Delay 200 ms to waiting for the FW ready */
-	msleep_interruptible(200);
-
-	priv->adapter->fw_ready = 1;
+release_fw:
+	release_firmware(cardp->fw);
+	cardp->fw = NULL;
 
 done:
 	lbs_deb_leave_args(LBS_DEB_USB, "ret %d", ret);
 	return ret;
 }
 
+
 #ifdef CONFIG_PM
 static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
 {
@@ -900,6 +947,19 @@
 	if (priv->adapter->psstate != PS_STATE_FULL_POWER)
 		return -1;
 
+	if (priv->mesh_dev && !priv->mesh_autostart_enabled) {
+		/* Mesh autostart must be activated while sleeping
+		 * On resume it will go back to the current state
+		 */
+		struct cmd_ds_mesh_access mesh_access;
+		memset(&mesh_access, 0, sizeof(mesh_access));
+		mesh_access.data[0] = cpu_to_le32(1);
+		libertas_prepare_and_send_command(priv,
+				CMD_MESH_ACCESS,
+				CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+				CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+	}
+
 	netif_device_detach(cardp->eth_dev);
 	netif_device_detach(priv->mesh_dev);
 
@@ -927,6 +987,19 @@
 	netif_device_attach(cardp->eth_dev);
 	netif_device_attach(priv->mesh_dev);
 
+	if (priv->mesh_dev && !priv->mesh_autostart_enabled) {
+		/* Mesh autostart was activated while sleeping
+		 * Disable it if appropriate
+		 */
+		struct cmd_ds_mesh_access mesh_access;
+		memset(&mesh_access, 0, sizeof(mesh_access));
+		mesh_access.data[0] = cpu_to_le32(0);
+		libertas_prepare_and_send_command(priv,
+				CMD_MESH_ACCESS,
+				CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+				CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+	}
+
 	lbs_deb_leave(LBS_DEB_USB);
 	return 0;
 }
@@ -970,8 +1043,10 @@
 
 	lbs_deb_enter(LBS_DEB_MAIN);
 
-	list_for_each_entry_safe(cardp, cardp_temp, &usb_devices, list)
-		if_usb_reset_device((wlan_private *) cardp->priv);
+	list_for_each_entry_safe(cardp, cardp_temp, &usb_devices, list) {
+		libertas_prepare_and_send_command(cardp->priv, CMD_802_11_RESET,
+		                                  CMD_ACT_HALT, 0, 0, NULL);
+	}
 
 	/* API unregisters the driver from USB subsystem */
 	usb_deregister(&if_usb_driver);
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h
index 156bb48..e07a10ed 100644
--- a/drivers/net/wireless/libertas/if_usb.h
+++ b/drivers/net/wireless/libertas/if_usb.h
@@ -38,7 +38,7 @@
 
 /* read callback private data */
 struct read_cb_info {
-        wlan_private *priv;
+        struct usb_card_rec *cardp;
         struct sk_buff *skb;
 };
 
@@ -58,6 +58,7 @@
 	int bulk_out_size;
 	u8 bulk_out_endpointAddr;
 
+	const struct firmware *fw;
 	u8 CRC_OK;
 	u32 fwseqnum;
 	u32 lastseqnum;
@@ -65,6 +66,7 @@
 	u32 fwlastblksent;
 	u8 fwdnldover;
 	u8 fwfinalblk;
+	u8 surprise_removed;
 
 	u32 usb_event_cause;
 	u8 usb_int_cause;
@@ -102,8 +104,4 @@
 #define FW_DATA_XMIT_SIZE \
 	sizeof(struct fwheader) + le32_to_cpu(fwdata->fwheader.datalength) + sizeof(u32)
 
-int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb);
-void if_usb_free(struct usb_card_rec *cardp);
-int if_usb_issue_boot_command(wlan_private *priv, int ivalue);
-
 #endif
diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c
index 78ac306..dc24a05 100644
--- a/drivers/net/wireless/libertas/join.c
+++ b/drivers/net/wireless/libertas/join.c
@@ -17,10 +17,13 @@
 #include "dev.h"
 #include "assoc.h"
 
-#define AD_HOC_CAP_PRIVACY_ON 1
+/* The firmware needs certain bits masked out of the beacon-derviced capability
+ * field when associating/joining to BSSs.
+ */
+#define CAPINFO_MASK	(~(0xda00))
 
 /**
- *  @brief This function finds out the common rates between rate1 and rate2.
+ *  @brief This function finds common rates between rate1 and card rates.
  *
  * It will fill common rates in rate1 as output if found.
  *
@@ -29,76 +32,88 @@
  *
  *  @param adapter     A pointer to wlan_adapter structure
  *  @param rate1       the buffer which keeps input and output
- *  @param rate1_size  the size of rate1 buffer
- *  @param rate2       the buffer which keeps rate2
- *  @param rate2_size  the size of rate2 buffer.
+ *  @param rate1_size  the size of rate1 buffer; new size of buffer on return
  *
  *  @return            0 or -1
  */
-static int get_common_rates(wlan_adapter * adapter, u8 * rate1,
-			    int rate1_size, u8 * rate2, int rate2_size)
+static int get_common_rates(wlan_adapter * adapter, u8 * rates, u16 *rates_size)
 {
-	u8 *ptr = rate1;
-	int ret = 0;
+	u8 *card_rates = libertas_bg_rates;
+	size_t num_card_rates = sizeof(libertas_bg_rates);
+	int ret = 0, i, j;
 	u8 tmp[30];
-	int i;
+	size_t tmp_size = 0;
 
-	memset(&tmp, 0, sizeof(tmp));
-	memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp)));
-	memset(rate1, 0, rate1_size);
-
-	/* Mask the top bit of the original values */
-	for (i = 0; tmp[i] && i < sizeof(tmp); i++)
-		tmp[i] &= 0x7F;
-
-	for (i = 0; rate2[i] && i < rate2_size; i++) {
-		/* Check for Card Rate in tmp, excluding the top bit */
-		if (strchr(tmp, rate2[i] & 0x7F)) {
-			/* values match, so copy the Card Rate to rate1 */
-			*rate1++ = rate2[i];
+	/* For each rate in card_rates that exists in rate1, copy to tmp */
+	for (i = 0; card_rates[i] && (i < num_card_rates); i++) {
+		for (j = 0; rates[j] && (j < *rates_size); j++) {
+			if (rates[j] == card_rates[i])
+				tmp[tmp_size++] = card_rates[i];
 		}
 	}
 
-	lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp));
-	lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size);
-	lbs_dbg_hex("Common rates:", ptr, rate1_size);
-	lbs_deb_join("Tx datarate is set to 0x%X\n", adapter->datarate);
+	lbs_deb_hex(LBS_DEB_JOIN, "AP rates    ", rates, *rates_size);
+	lbs_deb_hex(LBS_DEB_JOIN, "card rates  ", card_rates, num_card_rates);
+	lbs_deb_hex(LBS_DEB_JOIN, "common rates", tmp, tmp_size);
+	lbs_deb_join("Tx datarate is currently 0x%X\n", adapter->cur_rate);
 
-	if (!adapter->is_datarate_auto) {
-		while (*ptr) {
-			if ((*ptr & 0x7f) == adapter->datarate) {
-				ret = 0;
+	if (!adapter->auto_rate) {
+		for (i = 0; i < tmp_size; i++) {
+			if (tmp[i] == adapter->cur_rate)
 				goto done;
-			}
-			ptr++;
 		}
-		lbs_pr_alert( "Previously set fixed data rate %#x isn't "
-		       "compatible with the network.\n", adapter->datarate);
-
+		lbs_pr_alert("Previously set fixed data rate %#x isn't "
+		       "compatible with the network.\n", adapter->cur_rate);
 		ret = -1;
 		goto done;
 	}
-
 	ret = 0;
+
 done:
+	memset(rates, 0, *rates_size);
+	*rates_size = min_t(int, tmp_size, *rates_size);
+	memcpy(rates, tmp, *rates_size);
 	return ret;
 }
 
-int libertas_send_deauth(wlan_private * priv)
+
+/**
+ *  @brief Sets the MSB on basic rates as the firmware requires
+ *
+ * Scan through an array and set the MSB for basic data rates.
+ *
+ *  @param rates     buffer of data rates
+ *  @param len       size of buffer
+ */
+static void libertas_set_basic_rate_flags(u8 * rates, size_t len)
 {
-	wlan_adapter *adapter = priv->adapter;
-	int ret = 0;
+	int i;
 
-	if (adapter->mode == IW_MODE_INFRA &&
-	    adapter->connect_status == libertas_connected)
-		ret = libertas_send_deauthentication(priv);
-	else
-		ret = -ENOTSUPP;
-
-	return ret;
+	for (i = 0; i < len; i++) {
+		if (rates[i] == 0x02 || rates[i] == 0x04 ||
+		    rates[i] == 0x0b || rates[i] == 0x16)
+			rates[i] |= 0x80;
+	}
 }
 
 /**
+ *  @brief Unsets the MSB on basic rates
+ *
+ * Scan through an array and unset the MSB for basic data rates.
+ *
+ *  @param rates     buffer of data rates
+ *  @param len       size of buffer
+ */
+void libertas_unset_basic_rate_flags(u8 * rates, size_t len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		rates[i] &= 0x7f;
+}
+
+
+/**
  *  @brief Associate to a specific BSS discovered in a scan
  *
  *  @param priv      A pointer to wlan_private structure
@@ -113,23 +128,24 @@
 
 	lbs_deb_enter(LBS_DEB_JOIN);
 
-	ret = libertas_prepare_and_send_command(priv, cmd_802_11_authenticate,
-				    0, cmd_option_waitforrsp,
+	ret = libertas_prepare_and_send_command(priv, CMD_802_11_AUTHENTICATE,
+				    0, CMD_OPTION_WAITFORRSP,
 				    0, assoc_req->bss.bssid);
 
 	if (ret)
 		goto done;
 
 	/* set preamble to firmware */
-	if (adapter->capinfo.shortpreamble && assoc_req->bss.cap.shortpreamble)
-		adapter->preamble = cmd_type_short_preamble;
+	if (   (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+	    && (assoc_req->bss.capability & WLAN_CAPABILITY_SHORT_PREAMBLE))
+		adapter->preamble = CMD_TYPE_SHORT_PREAMBLE;
 	else
-		adapter->preamble = cmd_type_long_preamble;
+		adapter->preamble = CMD_TYPE_LONG_PREAMBLE;
 
 	libertas_set_radio_control(priv);
 
-	ret = libertas_prepare_and_send_command(priv, cmd_802_11_associate,
-				    0, cmd_option_waitforrsp, 0, assoc_req);
+	ret = libertas_prepare_and_send_command(priv, CMD_802_11_ASSOCIATE,
+				    0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
 
 done:
 	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
@@ -150,12 +166,12 @@
 
 	adapter->adhoccreate = 1;
 
-	if (!adapter->capinfo.shortpreamble) {
-		lbs_deb_join("AdhocStart: Long preamble\n");
-		adapter->preamble = cmd_type_long_preamble;
-	} else {
+	if (adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) {
 		lbs_deb_join("AdhocStart: Short preamble\n");
-		adapter->preamble = cmd_type_short_preamble;
+		adapter->preamble = CMD_TYPE_SHORT_PREAMBLE;
+	} else {
+		lbs_deb_join("AdhocStart: Long preamble\n");
+		adapter->preamble = CMD_TYPE_LONG_PREAMBLE;
 	}
 
 	libertas_set_radio_control(priv);
@@ -163,8 +179,8 @@
 	lbs_deb_join("AdhocStart: channel = %d\n", assoc_req->channel);
 	lbs_deb_join("AdhocStart: band = %d\n", assoc_req->band);
 
-	ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_start,
-				    0, cmd_option_waitforrsp, 0, assoc_req);
+	ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_START,
+				    0, CMD_OPTION_WAITFORRSP, 0, assoc_req);
 
 	return ret;
 }
@@ -194,25 +210,37 @@
 	             bss->ssid_len);
 
 	/* check if the requested SSID is already joined */
-	if (adapter->curbssparams.ssid_len
+	if (   adapter->curbssparams.ssid_len
 	    && !libertas_ssid_cmp(adapter->curbssparams.ssid,
 	                          adapter->curbssparams.ssid_len,
 	                          bss->ssid, bss->ssid_len)
-	    && (adapter->mode == IW_MODE_ADHOC)) {
-		lbs_deb_join(
-		       "ADHOC_J_CMD: New ad-hoc SSID is the same as current, "
-		       "not attempting to re-join");
-		return -1;
+	    && (adapter->mode == IW_MODE_ADHOC)
+	    && (adapter->connect_status == LIBERTAS_CONNECTED)) {
+		union iwreq_data wrqu;
+
+		lbs_deb_join("ADHOC_J_CMD: New ad-hoc SSID is the same as "
+		             "current, not attempting to re-join");
+
+		/* Send the re-association event though, because the association
+		 * request really was successful, even if just a null-op.
+		 */
+		memset(&wrqu, 0, sizeof(wrqu));
+		memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid,
+		       ETH_ALEN);
+		wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+		wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+		goto out;
 	}
 
-	/*Use shortpreamble only when both creator and card supports
+	/* Use shortpreamble only when both creator and card supports
 	   short preamble */
-	if (!bss->cap.shortpreamble || !adapter->capinfo.shortpreamble) {
+	if (   !(bss->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+	    || !(adapter->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)) {
 		lbs_deb_join("AdhocJoin: Long preamble\n");
-		adapter->preamble = cmd_type_long_preamble;
+		adapter->preamble = CMD_TYPE_LONG_PREAMBLE;
 	} else {
 		lbs_deb_join("AdhocJoin: Short preamble\n");
-		adapter->preamble = cmd_type_short_preamble;
+		adapter->preamble = CMD_TYPE_SHORT_PREAMBLE;
 	}
 
 	libertas_set_radio_control(priv);
@@ -222,17 +250,18 @@
 
 	adapter->adhoccreate = 0;
 
-	ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_join,
-				    0, cmd_option_waitforrsp,
+	ret = libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_JOIN,
+				    0, CMD_OPTION_WAITFORRSP,
 				    OID_802_11_SSID, assoc_req);
 
+out:
 	return ret;
 }
 
 int libertas_stop_adhoc_network(wlan_private * priv)
 {
-	return libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_stop,
-				     0, cmd_option_waitforrsp, 0, NULL);
+	return libertas_prepare_and_send_command(priv, CMD_802_11_AD_HOC_STOP,
+				     0, CMD_OPTION_WAITFORRSP, 0, NULL);
 }
 
 /**
@@ -243,8 +272,8 @@
  */
 int libertas_send_deauthentication(wlan_private * priv)
 {
-	return libertas_prepare_and_send_command(priv, cmd_802_11_deauthenticate,
-				     0, cmd_option_waitforrsp, 0, NULL);
+	return libertas_prepare_and_send_command(priv, CMD_802_11_DEAUTHENTICATE,
+				     0, CMD_OPTION_WAITFORRSP, 0, NULL);
 }
 
 /**
@@ -264,10 +293,11 @@
 	struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth;
 	int ret = -1;
 	u8 *bssid = pdata_buf;
+	DECLARE_MAC_BUF(mac);
 
 	lbs_deb_enter(LBS_DEB_JOIN);
 
-	cmd->command = cpu_to_le16(cmd_802_11_authenticate);
+	cmd->command = cpu_to_le16(CMD_802_11_AUTHENTICATE);
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate)
 	                        + S_DS_GEN);
 
@@ -290,8 +320,8 @@
 
 	memcpy(pauthenticate->macaddr, bssid, ETH_ALEN);
 
-	lbs_deb_join("AUTH_CMD: BSSID is : " MAC_FMT " auth=0x%X\n",
-	             MAC_ARG(bssid), pauthenticate->authtype);
+	lbs_deb_join("AUTH_CMD: BSSID is : %s auth=0x%X\n",
+	             print_mac(mac, bssid), pauthenticate->authtype);
 	ret = 0;
 
 out:
@@ -307,7 +337,7 @@
 
 	lbs_deb_enter(LBS_DEB_JOIN);
 
-	cmd->command = cpu_to_le16(cmd_802_11_deauthenticate);
+	cmd->command = cpu_to_le16(CMD_802_11_DEAUTHENTICATE);
 	cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) +
 			     S_DS_GEN);
 
@@ -330,9 +360,7 @@
 	int ret = 0;
 	struct assoc_request * assoc_req = pdata_buf;
 	struct bss_descriptor * bss = &assoc_req->bss;
-	u8 *card_rates;
 	u8 *pos;
-	int card_rates_size;
 	u16 tmpcap, tmplen;
 	struct mrvlietypes_ssidparamset *ssid;
 	struct mrvlietypes_phyparamset *phy;
@@ -349,15 +377,15 @@
 		goto done;
 	}
 
-	cmd->command = cpu_to_le16(cmd_802_11_associate);
+	cmd->command = cpu_to_le16(CMD_802_11_ASSOCIATE);
 
 	memcpy(passo->peerstaaddr, bss->bssid, sizeof(passo->peerstaaddr));
 	pos += sizeof(passo->peerstaaddr);
 
 	/* set the listen interval */
-	passo->listeninterval = cpu_to_le16(adapter->listeninterval);
+	passo->listeninterval = cpu_to_le16(MRVDRV_DEFAULT_LISTEN_INTERVAL);
 
-	pos += sizeof(passo->capinfo);
+	pos += sizeof(passo->capability);
 	pos += sizeof(passo->listeninterval);
 	pos += sizeof(passo->bcnperiod);
 	pos += sizeof(passo->dtimperiod);
@@ -386,23 +414,24 @@
 
 	rates = (struct mrvlietypes_ratesparamset *) pos;
 	rates->header.type = cpu_to_le16(TLV_TYPE_RATES);
-
-	memcpy(&rates->rates, &bss->libertas_supported_rates, WLAN_SUPPORTED_RATES);
-
-	card_rates = libertas_supported_rates;
-	card_rates_size = sizeof(libertas_supported_rates);
-
-	if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES,
-			     card_rates, card_rates_size)) {
+	memcpy(&rates->rates, &bss->rates, MAX_RATES);
+	tmplen = MAX_RATES;
+	if (get_common_rates(adapter, rates->rates, &tmplen)) {
 		ret = -1;
 		goto done;
 	}
-
-	tmplen = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES);
-	adapter->curbssparams.numofrates = tmplen;
-
 	pos += sizeof(rates->header) + tmplen;
 	rates->header.len = cpu_to_le16(tmplen);
+	lbs_deb_join("ASSOC_CMD: num rates = %u\n", tmplen);
+
+	/* Copy the infra. association rates into Current BSS state structure */
+	memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates));
+	memcpy(&adapter->curbssparams.rates, &rates->rates, tmplen);
+
+	/* Set MSB on basic rates as the firmware requires, but _after_
+	 * copying to current bss rates.
+	 */
+	libertas_set_basic_rate_flags(rates->rates, tmplen);
 
 	if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) {
 		rsn = (struct mrvlietypes_rsnparamset *) pos;
@@ -411,7 +440,7 @@
 		tmplen = (u16) assoc_req->wpa_ie[1];
 		rsn->header.len = cpu_to_le16(tmplen);
 		memcpy(rsn->rsnie, &assoc_req->wpa_ie[2], tmplen);
-		lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn,
+		lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_CMD: RSN IE", (u8 *) rsn,
 			sizeof(rsn->header) + tmplen);
 		pos += sizeof(rsn->header) + tmplen;
 	}
@@ -419,20 +448,6 @@
 	/* update curbssparams */
 	adapter->curbssparams.channel = bss->phyparamset.dsparamset.currentchan;
 
-	/* Copy the infra. association rates into Current BSS state structure */
-	memcpy(&adapter->curbssparams.datarates, &rates->rates,
-	       min_t(size_t, sizeof(adapter->curbssparams.datarates),
-		     cpu_to_le16(rates->header.len)));
-
-	lbs_deb_join("ASSOC_CMD: rates->header.len = %d\n",
-		     cpu_to_le16(rates->header.len));
-
-	/* set IBSS field */
-	if (bss->mode == IW_MODE_INFRA) {
-#define CAPINFO_ESS_MODE 1
-		passo->capinfo.ess = CAPINFO_ESS_MODE;
-	}
-
 	if (libertas_parse_dnld_countryinfo_11d(priv, bss)) {
 		ret = -1;
 		goto done;
@@ -440,12 +455,13 @@
 
 	cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN);
 
-	/* set the capability info at last */
-	memcpy(&tmpcap, &bss->cap, sizeof(passo->capinfo));
-	tmpcap &= CAPINFO_MASK;
-	lbs_deb_join("ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
+	/* set the capability info */
+	tmpcap = (bss->capability & CAPINFO_MASK);
+	if (bss->mode == IW_MODE_INFRA)
+		tmpcap |= WLAN_CAPABILITY_ESS;
+	passo->capability = cpu_to_le16(tmpcap);
+	lbs_deb_join("ASSOC_CMD: capability=%4X CAPINFO_MASK=%4X\n",
 		     tmpcap, CAPINFO_MASK);
-	memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo));
 
 done:
 	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
@@ -459,8 +475,9 @@
 	struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads;
 	int ret = 0;
 	int cmdappendsize = 0;
-	int i;
 	struct assoc_request * assoc_req = pdata_buf;
+	u16 tmpcap = 0;
+	size_t ratesize = 0;
 
 	lbs_deb_enter(LBS_DEB_JOIN);
 
@@ -469,7 +486,7 @@
 		goto done;
 	}
 
-	cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start);
+	cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_START);
 
 	/*
 	 * Fill in the parameters for 2 data structures:
@@ -483,17 +500,17 @@
 	 *   and operational rates.
 	 */
 
-	memset(adhs->SSID, 0, IW_ESSID_MAX_SIZE);
-	memcpy(adhs->SSID, assoc_req->ssid, assoc_req->ssid_len);
+	memset(adhs->ssid, 0, IW_ESSID_MAX_SIZE);
+	memcpy(adhs->ssid, assoc_req->ssid, assoc_req->ssid_len);
 
 	lbs_deb_join("ADHOC_S_CMD: SSID '%s', ssid length %u\n",
 	             escape_essid(assoc_req->ssid, assoc_req->ssid_len),
 	             assoc_req->ssid_len);
 
 	/* set the BSS type */
-	adhs->bsstype = cmd_bss_type_ibss;
+	adhs->bsstype = CMD_BSS_TYPE_IBSS;
 	adapter->mode = IW_MODE_ADHOC;
-	adhs->beaconperiod = cpu_to_le16(adapter->beaconperiod);
+	adhs->beaconperiod = cpu_to_le16(MRVDRV_BEACON_INTERVAL);
 
 	/* set Physical param set */
 #define DS_PARA_IE_ID   3
@@ -515,45 +532,36 @@
 
 	adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID;
 	adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN;
-	adhs->ssparamset.ibssparamset.atimwindow = cpu_to_le16(adapter->atimwindow);
+	adhs->ssparamset.ibssparamset.atimwindow = 0;
 
 	/* set capability info */
-	adhs->cap.ess = 0;
-	adhs->cap.ibss = 1;
-
-	/* probedelay */
-	adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time);
-
-	/* set up privacy in adapter->scantable[i] */
+	tmpcap = WLAN_CAPABILITY_IBSS;
 	if (assoc_req->secinfo.wep_enabled) {
 		lbs_deb_join("ADHOC_S_CMD: WEP enabled, setting privacy on\n");
-		adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+		tmpcap |= WLAN_CAPABILITY_PRIVACY;
 	} else {
 		lbs_deb_join("ADHOC_S_CMD: WEP disabled, setting privacy off\n");
 	}
+	adhs->capability = cpu_to_le16(tmpcap);
 
-	memset(adhs->datarate, 0, sizeof(adhs->datarate));
+	/* probedelay */
+	adhs->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
 
-	if (adapter->adhoc_grate_enabled) {
-		memcpy(adhs->datarate, libertas_adhoc_rates_g,
-		       min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g)));
-	} else {
-		memcpy(adhs->datarate, libertas_adhoc_rates_b,
-		       min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b)));
-	}
-
-	/* Find the last non zero */
-	for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ;
-
-	adapter->curbssparams.numofrates = i;
+	memset(adhs->rates, 0, sizeof(adhs->rates));
+	ratesize = min(sizeof(adhs->rates), sizeof(libertas_bg_rates));
+	memcpy(adhs->rates, libertas_bg_rates, ratesize);
 
 	/* Copy the ad-hoc creating rates into Current BSS state structure */
-	memcpy(&adapter->curbssparams.datarates,
-	       &adhs->datarate, adapter->curbssparams.numofrates);
+	memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates));
+	memcpy(&adapter->curbssparams.rates, &adhs->rates, ratesize);
+
+	/* Set MSB on basic rates as the firmware requires, but _after_
+	 * copying to current bss rates.
+	 */
+	libertas_set_basic_rate_flags(adhs->rates, ratesize);
 
 	lbs_deb_join("ADHOC_S_CMD: rates=%02x %02x %02x %02x \n",
-	       adhs->datarate[0], adhs->datarate[1],
-	       adhs->datarate[2], adhs->datarate[3]);
+	       adhs->rates[0], adhs->rates[1], adhs->rates[2], adhs->rates[3]);
 
 	lbs_deb_join("ADHOC_S_CMD: AD HOC Start command is ready\n");
 
@@ -575,7 +583,7 @@
 int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
 				struct cmd_ds_command *cmd)
 {
-	cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop);
+	cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_STOP);
 	cmd->size = cpu_to_le16(S_DS_GEN);
 
 	return 0;
@@ -585,101 +593,84 @@
 				struct cmd_ds_command *cmd, void *pdata_buf)
 {
 	wlan_adapter *adapter = priv->adapter;
-	struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj;
+	struct cmd_ds_802_11_ad_hoc_join *join_cmd = &cmd->params.adj;
 	struct assoc_request * assoc_req = pdata_buf;
 	struct bss_descriptor *bss = &assoc_req->bss;
 	int cmdappendsize = 0;
 	int ret = 0;
-	u8 *card_rates;
-	int card_rates_size;
-	u16 tmpcap;
-	int i;
+	u16 ratesize = 0;
+	DECLARE_MAC_BUF(mac);
 
 	lbs_deb_enter(LBS_DEB_JOIN);
 
-	cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join);
+	cmd->command = cpu_to_le16(CMD_802_11_AD_HOC_JOIN);
 
-	padhocjoin->bssdescriptor.bsstype = cmd_bss_type_ibss;
+	join_cmd->bss.type = CMD_BSS_TYPE_IBSS;
+	join_cmd->bss.beaconperiod = cpu_to_le16(bss->beaconperiod);
 
-	padhocjoin->bssdescriptor.beaconperiod = cpu_to_le16(bss->beaconperiod);
+	memcpy(&join_cmd->bss.bssid, &bss->bssid, ETH_ALEN);
+	memcpy(&join_cmd->bss.ssid, &bss->ssid, bss->ssid_len);
 
-	memcpy(&padhocjoin->bssdescriptor.BSSID, &bss->bssid, ETH_ALEN);
-	memcpy(&padhocjoin->bssdescriptor.SSID, &bss->ssid, bss->ssid_len);
+	memcpy(&join_cmd->bss.phyparamset, &bss->phyparamset,
+	       sizeof(union ieeetypes_phyparamset));
 
-	memcpy(&padhocjoin->bssdescriptor.phyparamset,
-	       &bss->phyparamset, sizeof(union ieeetypes_phyparamset));
+	memcpy(&join_cmd->bss.ssparamset, &bss->ssparamset,
+	       sizeof(union IEEEtypes_ssparamset));
 
-	memcpy(&padhocjoin->bssdescriptor.ssparamset,
-	       &bss->ssparamset, sizeof(union IEEEtypes_ssparamset));
-
-	memcpy(&tmpcap, &bss->cap, sizeof(struct ieeetypes_capinfo));
-	tmpcap &= CAPINFO_MASK;
-
+	join_cmd->bss.capability = cpu_to_le16(bss->capability & CAPINFO_MASK);
 	lbs_deb_join("ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n",
-	       tmpcap, CAPINFO_MASK);
-	memcpy(&padhocjoin->bssdescriptor.cap, &tmpcap,
-	       sizeof(struct ieeetypes_capinfo));
+	       bss->capability, CAPINFO_MASK);
 
 	/* information on BSSID descriptor passed to FW */
 	lbs_deb_join(
-	       "ADHOC_J_CMD: BSSID = " MAC_FMT ", SSID = '%s'\n",
-	       MAC_ARG(padhocjoin->bssdescriptor.BSSID),
-	       padhocjoin->bssdescriptor.SSID);
+	       "ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n",
+	       print_mac(mac, join_cmd->bss.bssid),
+	       join_cmd->bss.ssid);
 
 	/* failtimeout */
-	padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
+	join_cmd->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT);
 
 	/* probedelay */
-	padhocjoin->probedelay = cpu_to_le16(cmd_scan_probe_delay_time);
-
-	/* Copy Data rates from the rates recorded in scan response */
-	memset(padhocjoin->bssdescriptor.datarates, 0,
-	       sizeof(padhocjoin->bssdescriptor.datarates));
-	memcpy(padhocjoin->bssdescriptor.datarates, bss->datarates,
-	       min(sizeof(padhocjoin->bssdescriptor.datarates),
-		   sizeof(bss->datarates)));
-
-	card_rates = libertas_supported_rates;
-	card_rates_size = sizeof(libertas_supported_rates);
+	join_cmd->probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
 
 	adapter->curbssparams.channel = bss->channel;
 
-	if (get_common_rates(adapter, padhocjoin->bssdescriptor.datarates,
-			     sizeof(padhocjoin->bssdescriptor.datarates),
-			     card_rates, card_rates_size)) {
+	/* Copy Data rates from the rates recorded in scan response */
+	memset(join_cmd->bss.rates, 0, sizeof(join_cmd->bss.rates));
+	ratesize = min_t(u16, sizeof(join_cmd->bss.rates), MAX_RATES);
+	memcpy(join_cmd->bss.rates, bss->rates, ratesize);
+	if (get_common_rates(adapter, join_cmd->bss.rates, &ratesize)) {
 		lbs_deb_join("ADHOC_J_CMD: get_common_rates returns error.\n");
 		ret = -1;
 		goto done;
 	}
 
-	/* Find the last non zero */
-	for (i = 0; i < sizeof(padhocjoin->bssdescriptor.datarates)
-	     && padhocjoin->bssdescriptor.datarates[i]; i++) ;
+	/* Copy the ad-hoc creating rates into Current BSS state structure */
+	memset(&adapter->curbssparams.rates, 0, sizeof(adapter->curbssparams.rates));
+	memcpy(&adapter->curbssparams.rates, join_cmd->bss.rates, ratesize);
 
-	adapter->curbssparams.numofrates = i;
-
-	/*
-	 * Copy the adhoc joining rates to Current BSS State structure
+	/* Set MSB on basic rates as the firmware requires, but _after_
+	 * copying to current bss rates.
 	 */
-	memcpy(adapter->curbssparams.datarates,
-	       padhocjoin->bssdescriptor.datarates,
-	       adapter->curbssparams.numofrates);
+	libertas_set_basic_rate_flags(join_cmd->bss.rates, ratesize);
 
-	padhocjoin->bssdescriptor.ssparamset.ibssparamset.atimwindow =
+	join_cmd->bss.ssparamset.ibssparamset.atimwindow =
 	    cpu_to_le16(bss->atimwindow);
 
 	if (assoc_req->secinfo.wep_enabled) {
-		padhocjoin->bssdescriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON;
+		u16 tmp = le16_to_cpu(join_cmd->bss.capability);
+		tmp |= WLAN_CAPABILITY_PRIVACY;
+		join_cmd->bss.capability = cpu_to_le16(tmp);
 	}
 
-	if (adapter->psmode == wlan802_11powermodemax_psp) {
+	if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) {
 		/* wake up first */
 		__le32 Localpsmode;
 
-		Localpsmode = cpu_to_le32(wlan802_11powermodecam);
+		Localpsmode = cpu_to_le32(WLAN802_11POWERMODECAM);
 		ret = libertas_prepare_and_send_command(priv,
-					    cmd_802_11_ps_mode,
-					    cmd_act_set,
+					    CMD_802_11_PS_MODE,
+					    CMD_ACT_SET,
 					    0, 0, &Localpsmode);
 
 		if (ret) {
@@ -709,6 +700,7 @@
 	union iwreq_data wrqu;
 	struct ieeetypes_assocrsp *passocrsp;
 	struct bss_descriptor * bss;
+	u16 status_code;
 
 	lbs_deb_enter(LBS_DEB_JOIN);
 
@@ -721,21 +713,65 @@
 
 	passocrsp = (struct ieeetypes_assocrsp *) & resp->params;
 
-	if (le16_to_cpu(passocrsp->statuscode)) {
+	/*
+	 * Older FW versions map the IEEE 802.11 Status Code in the association
+	 * response to the following values returned in passocrsp->statuscode:
+	 *
+	 *    IEEE Status Code                Marvell Status Code
+	 *    0                       ->      0x0000 ASSOC_RESULT_SUCCESS
+	 *    13                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+	 *    14                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+	 *    15                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+	 *    16                      ->      0x0004 ASSOC_RESULT_AUTH_REFUSED
+	 *    others                  ->      0x0003 ASSOC_RESULT_REFUSED
+	 *
+	 * Other response codes:
+	 *    0x0001 -> ASSOC_RESULT_INVALID_PARAMETERS (unused)
+	 *    0x0002 -> ASSOC_RESULT_TIMEOUT (internal timer expired waiting for
+	 *                                    association response from the AP)
+	 */
+
+	status_code = le16_to_cpu(passocrsp->statuscode);
+	switch (status_code) {
+	case 0x00:
+		lbs_deb_join("ASSOC_RESP: Association succeeded\n");
+		break;
+	case 0x01:
+		lbs_deb_join("ASSOC_RESP: Association failed; invalid "
+		             "parameters (status code %d)\n", status_code);
+		break;
+	case 0x02:
+		lbs_deb_join("ASSOC_RESP: Association failed; internal timer "
+		             "expired while waiting for the AP (status code %d)"
+		             "\n", status_code);
+		break;
+	case 0x03:
+		lbs_deb_join("ASSOC_RESP: Association failed; association "
+		             "was refused by the AP (status code %d)\n",
+		             status_code);
+		break;
+	case 0x04:
+		lbs_deb_join("ASSOC_RESP: Association failed; authentication "
+		             "was refused by the AP (status code %d)\n",
+		             status_code);
+		break;
+	default:
+		lbs_deb_join("ASSOC_RESP: Association failed; reason unknown "
+		             "(status code %d)\n", status_code);
+		break;
+	}
+
+	if (status_code) {
 		libertas_mac_event_disconnected(priv);
-
-		lbs_deb_join("ASSOC_RESP: Association failed, status code = %d\n",
-			     le16_to_cpu(passocrsp->statuscode));
-
 		ret = -1;
 		goto done;
 	}
 
-	lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params,
+	lbs_deb_hex(LBS_DEB_JOIN, "ASSOC_RESP", (void *)&resp->params,
 		le16_to_cpu(resp->size) - S_DS_GEN);
 
 	/* Send a Media Connected event, according to the Spec */
-	adapter->connect_status = libertas_connected;
+	adapter->connect_status = LIBERTAS_CONNECTED;
 
 	lbs_deb_join("ASSOC_RESP: assocated to '%s'\n",
 	             escape_essid(bss->ssid, bss->ssid_len));
@@ -759,10 +795,10 @@
 	netif_carrier_on(priv->dev);
 	netif_wake_queue(priv->dev);
 
-	netif_carrier_on(priv->mesh_dev);
-	netif_wake_queue(priv->mesh_dev);
-
-	lbs_deb_join("ASSOC_RESP: Associated \n");
+	if (priv->mesh_dev) {
+		netif_carrier_on(priv->mesh_dev);
+		netif_wake_queue(priv->mesh_dev);
+	}
 
 	memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
 	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
@@ -794,6 +830,7 @@
 	struct cmd_ds_802_11_ad_hoc_result *padhocresult;
 	union iwreq_data wrqu;
 	struct bss_descriptor *bss;
+	DECLARE_MAC_BUF(mac);
 
 	lbs_deb_enter(LBS_DEB_JOIN);
 
@@ -815,7 +852,7 @@
 	 */
 	if (result) {
 		lbs_deb_join("ADHOC_RESP: failed\n");
-		if (adapter->connect_status == libertas_connected) {
+		if (adapter->connect_status == LIBERTAS_CONNECTED) {
 			libertas_mac_event_disconnected(priv);
 		}
 		ret = -1;
@@ -830,11 +867,11 @@
 	             escape_essid(bss->ssid, bss->ssid_len));
 
 	/* Send a Media Connected event, according to the Spec */
-	adapter->connect_status = libertas_connected;
+	adapter->connect_status = LIBERTAS_CONNECTED;
 
-	if (command == cmd_ret_802_11_ad_hoc_start) {
+	if (command == CMD_RET(CMD_802_11_AD_HOC_START)) {
 		/* Update the created network descriptor with the new BSSID */
-		memcpy(bss->bssid, padhocresult->BSSID, ETH_ALEN);
+		memcpy(bss->bssid, padhocresult->bssid, ETH_ALEN);
 	}
 
 	/* Set the BSSID from the joined/started descriptor */
@@ -847,8 +884,10 @@
 	netif_carrier_on(priv->dev);
 	netif_wake_queue(priv->dev);
 
-	netif_carrier_on(priv->mesh_dev);
-	netif_wake_queue(priv->mesh_dev);
+	if (priv->mesh_dev) {
+		netif_carrier_on(priv->mesh_dev);
+		netif_wake_queue(priv->mesh_dev);
+	}
 
 	memset(&wrqu, 0, sizeof(wrqu));
 	memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN);
@@ -857,8 +896,8 @@
 
 	lbs_deb_join("ADHOC_RESP: - Joined/Started Ad Hoc\n");
 	lbs_deb_join("ADHOC_RESP: channel = %d\n", adapter->curbssparams.channel);
-	lbs_deb_join("ADHOC_RESP: BSSID = " MAC_FMT "\n",
-	       MAC_ARG(padhocresult->BSSID));
+	lbs_deb_join("ADHOC_RESP: BSSID = %s\n",
+		     print_mac(mac, padhocresult->bssid));
 
 done:
 	lbs_deb_leave_args(LBS_DEB_JOIN, "ret %d", ret);
diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h
index d522630..894a072 100644
--- a/drivers/net/wireless/libertas/join.h
+++ b/drivers/net/wireless/libertas/join.h
@@ -12,45 +12,42 @@
 #include "dev.h"
 
 struct cmd_ds_command;
-extern int libertas_cmd_80211_authenticate(wlan_private * priv,
+int libertas_cmd_80211_authenticate(wlan_private * priv,
 					struct cmd_ds_command *cmd,
 					void *pdata_buf);
-extern int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
+int libertas_cmd_80211_ad_hoc_join(wlan_private * priv,
 				       struct cmd_ds_command *cmd,
 				       void *pdata_buf);
-extern int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
+int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv,
 				       struct cmd_ds_command *cmd);
-extern int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
+int libertas_cmd_80211_ad_hoc_start(wlan_private * priv,
 					struct cmd_ds_command *cmd,
 					void *pdata_buf);
-extern int libertas_cmd_80211_deauthenticate(wlan_private * priv,
+int libertas_cmd_80211_deauthenticate(wlan_private * priv,
 					  struct cmd_ds_command *cmd);
-extern int libertas_cmd_80211_associate(wlan_private * priv,
+int libertas_cmd_80211_associate(wlan_private * priv,
 				     struct cmd_ds_command *cmd,
 				     void *pdata_buf);
 
-extern int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
+int libertas_ret_80211_ad_hoc_start(wlan_private * priv,
 					struct cmd_ds_command *resp);
-extern int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
+int libertas_ret_80211_ad_hoc_stop(wlan_private * priv,
 				       struct cmd_ds_command *resp);
-extern int libertas_ret_80211_disassociate(wlan_private * priv,
+int libertas_ret_80211_disassociate(wlan_private * priv,
 					struct cmd_ds_command *resp);
-extern int libertas_ret_80211_associate(wlan_private * priv,
+int libertas_ret_80211_associate(wlan_private * priv,
 				     struct cmd_ds_command *resp);
 
-extern int libertas_reassociation_thread(void *data);
-
-extern int libertas_start_adhoc_network(wlan_private * priv,
+int libertas_start_adhoc_network(wlan_private * priv,
 			     struct assoc_request * assoc_req);
-extern int libertas_join_adhoc_network(wlan_private * priv,
+int libertas_join_adhoc_network(wlan_private * priv,
 				struct assoc_request * assoc_req);
-extern int libertas_stop_adhoc_network(wlan_private * priv);
+int libertas_stop_adhoc_network(wlan_private * priv);
 
-extern int libertas_send_deauthentication(wlan_private * priv);
-extern int libertas_send_deauth(wlan_private * priv);
-
-extern int libertas_do_adhocstop_ioctl(wlan_private * priv);
+int libertas_send_deauthentication(wlan_private * priv);
 
 int wlan_associate(wlan_private * priv, struct assoc_request * assoc_req);
 
+void libertas_unset_basic_rate_flags(u8 * rates, size_t len);
+
 #endif
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 9f36624..5ead083 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -10,6 +10,7 @@
 #include <linux/etherdevice.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
+#include <linux/kthread.h>
 
 #include <net/iw_handler.h>
 #include <net/ieee80211.h>
@@ -20,8 +21,9 @@
 #include "wext.h"
 #include "debugfs.h"
 #include "assoc.h"
+#include "join.h"
 
-#define DRIVER_RELEASE_VERSION "322.p0"
+#define DRIVER_RELEASE_VERSION "323.p0"
 const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION
 #ifdef  DEBUG
     "-dbg"
@@ -121,59 +123,90 @@
 static struct region_cfp_table region_cfp_table[] = {
 	{0x10,			/*US FCC */
 	 channel_freq_power_US_BG,
-	 sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
+	 ARRAY_SIZE(channel_freq_power_US_BG),
 	 }
 	,
 	{0x20,			/*CANADA IC */
 	 channel_freq_power_US_BG,
-	 sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power),
+	 ARRAY_SIZE(channel_freq_power_US_BG),
 	 }
 	,
 	{0x30, /*EU*/ channel_freq_power_EU_BG,
-	 sizeof(channel_freq_power_EU_BG) / sizeof(struct chan_freq_power),
+	 ARRAY_SIZE(channel_freq_power_EU_BG),
 	 }
 	,
 	{0x31, /*SPAIN*/ channel_freq_power_SPN_BG,
-	 sizeof(channel_freq_power_SPN_BG) / sizeof(struct chan_freq_power),
+	 ARRAY_SIZE(channel_freq_power_SPN_BG),
 	 }
 	,
 	{0x32, /*FRANCE*/ channel_freq_power_FR_BG,
-	 sizeof(channel_freq_power_FR_BG) / sizeof(struct chan_freq_power),
+	 ARRAY_SIZE(channel_freq_power_FR_BG),
 	 }
 	,
 	{0x40, /*JAPAN*/ channel_freq_power_JPN_BG,
-	 sizeof(channel_freq_power_JPN_BG) / sizeof(struct chan_freq_power),
+	 ARRAY_SIZE(channel_freq_power_JPN_BG),
 	 }
 	,
 /*Add new region here */
 };
 
 /**
- * the rates supported
- */
-u8 libertas_supported_rates[G_SUPPORTED_RATES] =
-    { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
-0 };
-
-/**
- * the rates supported for ad-hoc G mode
- */
-u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES] =
-    { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
-0 };
-
-/**
- * the rates supported for ad-hoc B mode
- */
-u8 libertas_adhoc_rates_b[4] = { 0x82, 0x84, 0x8b, 0x96 };
-
-/**
  * the table to keep region code
  */
 u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
     { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
 
 /**
+ * 802.11b/g supported bitrates (in 500Kb/s units)
+ */
+u8 libertas_bg_rates[MAX_RATES] =
+    { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c,
+0x00, 0x00 };
+
+/**
+ * FW rate table.  FW refers to rates by their index in this table, not by the
+ * rate value itself.  Values of 0x00 are
+ * reserved positions.
+ */
+static u8 fw_data_rates[MAX_RATES] =
+    { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
+      0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
+};
+
+/**
+ *  @brief use index to get the data rate
+ *
+ *  @param idx                The index of data rate
+ *  @return 	   		data rate or 0
+ */
+u32 libertas_fw_index_to_data_rate(u8 idx)
+{
+	if (idx >= sizeof(fw_data_rates))
+		idx = 0;
+	return fw_data_rates[idx];
+}
+
+/**
+ *  @brief use rate to get the index
+ *
+ *  @param rate                 data rate
+ *  @return 	   		index or 0
+ */
+u8 libertas_data_rate_to_fw_index(u32 rate)
+{
+	u8 i;
+
+	if (!rate)
+		return 0;
+
+	for (i = 0; i < sizeof(fw_data_rates); i++) {
+		if (rate == fw_data_rates[i])
+			return i;
+	}
+	return 0;
+}
+
+/**
  * Attributes exported through sysfs
  */
 
@@ -187,9 +220,9 @@
 
 	memset(&mesh_access, 0, sizeof(mesh_access));
 	libertas_prepare_and_send_command(to_net_dev(dev)->priv,
-			cmd_mesh_access,
-			cmd_act_mesh_get_anycast,
-			cmd_option_waitforrsp, 0, (void *)&mesh_access);
+			CMD_MESH_ACCESS,
+			CMD_ACT_MESH_GET_ANYCAST,
+			CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
 
 	return snprintf(buf, 12, "0x%X\n", le32_to_cpu(mesh_access.data[0]));
 }
@@ -208,18 +241,127 @@
 	mesh_access.data[0] = cpu_to_le32(datum);
 
 	libertas_prepare_and_send_command((to_net_dev(dev))->priv,
-			cmd_mesh_access,
-			cmd_act_mesh_set_anycast,
-			cmd_option_waitforrsp, 0, (void *)&mesh_access);
+			CMD_MESH_ACCESS,
+			CMD_ACT_MESH_SET_ANYCAST,
+			CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
 	return strlen(buf);
 }
 
+int libertas_add_rtap(wlan_private *priv);
+void libertas_remove_rtap(wlan_private *priv);
+
+/**
+ * Get function for sysfs attribute rtap
+ */
+static ssize_t libertas_rtap_get(struct device * dev,
+		struct device_attribute *attr, char * buf)
+{
+	wlan_private *priv = (wlan_private *) (to_net_dev(dev))->priv;
+	wlan_adapter *adapter = priv->adapter;
+	return snprintf(buf, 5, "0x%X\n", adapter->monitormode);
+}
+
+/**
+ *  Set function for sysfs attribute rtap
+ */
+static ssize_t libertas_rtap_set(struct device * dev,
+		struct device_attribute *attr, const char * buf, size_t count)
+{
+	int monitor_mode;
+	wlan_private *priv = (wlan_private *) (to_net_dev(dev))->priv;
+	wlan_adapter *adapter = priv->adapter;
+
+	sscanf(buf, "%x", &monitor_mode);
+	if (monitor_mode != WLAN_MONITOR_OFF) {
+		if(adapter->monitormode == monitor_mode)
+			return strlen(buf);
+		if (adapter->monitormode == WLAN_MONITOR_OFF) {
+			if (adapter->mode == IW_MODE_INFRA)
+				libertas_send_deauthentication(priv);
+			else if (adapter->mode == IW_MODE_ADHOC)
+				libertas_stop_adhoc_network(priv);
+			libertas_add_rtap(priv);
+		}
+		adapter->monitormode = monitor_mode;
+	}
+
+	else {
+		if(adapter->monitormode == WLAN_MONITOR_OFF)
+			return strlen(buf);
+		adapter->monitormode = WLAN_MONITOR_OFF;
+		libertas_remove_rtap(priv);
+		netif_wake_queue(priv->dev);
+		netif_wake_queue(priv->mesh_dev);
+	}
+
+	libertas_prepare_and_send_command(priv,
+			CMD_802_11_MONITOR_MODE, CMD_ACT_SET,
+			CMD_OPTION_WAITFORRSP, 0, &adapter->monitormode);
+	return strlen(buf);
+}
+
+/**
+ * libertas_rtap attribute to be exported per mshX interface
+ * through sysfs (/sys/class/net/mshX/libertas-rtap)
+ */
+static DEVICE_ATTR(libertas_rtap, 0644, libertas_rtap_get,
+		libertas_rtap_set );
+
 /**
  * anycast_mask attribute to be exported per mshX interface
  * through sysfs (/sys/class/net/mshX/anycast_mask)
  */
 static DEVICE_ATTR(anycast_mask, 0644, libertas_anycast_get, libertas_anycast_set);
 
+static ssize_t libertas_autostart_enabled_get(struct device * dev,
+		struct device_attribute *attr, char * buf)
+{
+	struct cmd_ds_mesh_access mesh_access;
+
+	memset(&mesh_access, 0, sizeof(mesh_access));
+	libertas_prepare_and_send_command(to_net_dev(dev)->priv,
+			CMD_MESH_ACCESS,
+			CMD_ACT_MESH_GET_AUTOSTART_ENABLED,
+			CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+
+	return sprintf(buf, "%d\n", le32_to_cpu(mesh_access.data[0]));
+}
+
+static ssize_t libertas_autostart_enabled_set(struct device * dev,
+		struct device_attribute *attr, const char * buf, size_t count)
+{
+	struct cmd_ds_mesh_access mesh_access;
+	uint32_t datum;
+	wlan_private * priv = (to_net_dev(dev))->priv;
+	int ret;
+
+	memset(&mesh_access, 0, sizeof(mesh_access));
+	sscanf(buf, "%d", &datum);
+	mesh_access.data[0] = cpu_to_le32(datum);
+
+	ret = libertas_prepare_and_send_command(priv,
+			CMD_MESH_ACCESS,
+			CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+			CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+	if (ret == 0)
+		priv->mesh_autostart_enabled = datum ? 1 : 0;
+
+	return strlen(buf);
+}
+
+static DEVICE_ATTR(autostart_enabled, 0644,
+		libertas_autostart_enabled_get, libertas_autostart_enabled_set);
+
+static struct attribute *libertas_mesh_sysfs_entries[] = {
+	&dev_attr_anycast_mask.attr,
+	&dev_attr_autostart_enabled.attr,
+	NULL,
+};
+
+static struct attribute_group libertas_mesh_attr_group = {
+	.attrs = libertas_mesh_sysfs_entries,
+};
+
 /**
  *  @brief Check if the device can be open and wait if necessary.
  *
@@ -255,7 +397,7 @@
  *  @param dev     A pointer to net_device structure
  *  @return 	   0
  */
-static int wlan_dev_open(struct net_device *dev)
+static int libertas_dev_open(struct net_device *dev)
 {
 	wlan_private *priv = (wlan_private *) dev->priv;
 	wlan_adapter *adapter = priv->adapter;
@@ -264,12 +406,14 @@
 
 	priv->open = 1;
 
-	if (adapter->connect_status == libertas_connected) {
+	if (adapter->connect_status == LIBERTAS_CONNECTED) {
 		netif_carrier_on(priv->dev);
-		netif_carrier_on(priv->mesh_dev);
+		if (priv->mesh_dev)
+			netif_carrier_on(priv->mesh_dev);
 	} else {
 		netif_carrier_off(priv->dev);
-		netif_carrier_off(priv->mesh_dev);
+		if (priv->mesh_dev)
+			netif_carrier_off(priv->mesh_dev);
 	}
 
 	lbs_deb_leave(LBS_DEB_NET);
@@ -281,7 +425,7 @@
  *  @param dev     A pointer to net_device structure
  *  @return 	   0
  */
-static int mesh_open(struct net_device *dev)
+static int libertas_mesh_open(struct net_device *dev)
 {
 	wlan_private *priv = (wlan_private *) dev->priv ;
 
@@ -290,7 +434,7 @@
 	priv->mesh_open = 1 ;
 	netif_wake_queue(priv->mesh_dev);
 	if (priv->infra_open == 0)
-		return wlan_dev_open(priv->dev) ;
+		return libertas_dev_open(priv->dev) ;
 	return 0;
 }
 
@@ -300,7 +444,7 @@
  *  @param dev     A pointer to net_device structure
  *  @return 	   0
  */
-static int wlan_open(struct net_device *dev)
+static int libertas_open(struct net_device *dev)
 {
 	wlan_private *priv = (wlan_private *) dev->priv ;
 
@@ -309,11 +453,11 @@
 	priv->infra_open = 1 ;
 	netif_wake_queue(priv->dev);
 	if (priv->open == 0)
-		return wlan_dev_open(priv->dev) ;
+		return libertas_dev_open(priv->dev) ;
 	return 0;
 }
 
-static int wlan_dev_close(struct net_device *dev)
+static int libertas_dev_close(struct net_device *dev)
 {
 	wlan_private *priv = dev->priv;
 
@@ -332,14 +476,14 @@
  *  @param dev     A pointer to net_device structure
  *  @return 	   0
  */
-static int mesh_close(struct net_device *dev)
+static int libertas_mesh_close(struct net_device *dev)
 {
 	wlan_private *priv = (wlan_private *) (dev->priv);
 
 	priv->mesh_open = 0;
 	netif_stop_queue(priv->mesh_dev);
 	if (priv->infra_open == 0)
-		return wlan_dev_close(dev);
+		return libertas_dev_close(dev);
 	else
 		return 0;
 }
@@ -350,20 +494,20 @@
  *  @param dev     A pointer to net_device structure
  *  @return 	   0
  */
-static int wlan_close(struct net_device *dev)
+static int libertas_close(struct net_device *dev)
 {
 	wlan_private *priv = (wlan_private *) dev->priv;
 
 	netif_stop_queue(dev);
 	priv->infra_open = 0;
 	if (priv->mesh_open == 0)
-		return wlan_dev_close(dev);
+		return libertas_dev_close(dev);
 	else
 		return 0;
 }
 
 
-static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int libertas_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	int ret = 0;
 	wlan_private *priv = dev->priv;
@@ -376,7 +520,8 @@
 	}
 
 	netif_stop_queue(priv->dev);
-	netif_stop_queue(priv->mesh_dev);
+	if (priv->mesh_dev)
+		netif_stop_queue(priv->mesh_dev);
 
 	if (libertas_process_tx(priv, skb) == 0)
 		dev->trans_start = jiffies;
@@ -386,41 +531,52 @@
 }
 
 /**
- * @brief Mark mesh packets and handover them to wlan_hard_start_xmit
+ * @brief Mark mesh packets and handover them to libertas_hard_start_xmit
  *
  */
-static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int libertas_mesh_pre_start_xmit(struct sk_buff *skb,
+		struct net_device *dev)
 {
 	wlan_private *priv = dev->priv;
 	int ret;
 
 	lbs_deb_enter(LBS_DEB_MESH);
+	if(priv->adapter->monitormode != WLAN_MONITOR_OFF) {
+		netif_stop_queue(dev);
+		return -EOPNOTSUPP;
+	}
 
 	SET_MESH_FRAME(skb);
 
-	ret = wlan_hard_start_xmit(skb, priv->dev);
+	ret = libertas_hard_start_xmit(skb, priv->dev);
 	lbs_deb_leave_args(LBS_DEB_MESH, "ret %d", ret);
 	return ret;
 }
 
 /**
- * @brief Mark non-mesh packets and handover them to wlan_hard_start_xmit
+ * @brief Mark non-mesh packets and handover them to libertas_hard_start_xmit
  *
  */
-static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int libertas_pre_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
+	wlan_private *priv = dev->priv;
 	int ret;
 
 	lbs_deb_enter(LBS_DEB_NET);
 
+	if(priv->adapter->monitormode != WLAN_MONITOR_OFF) {
+		netif_stop_queue(dev);
+		return -EOPNOTSUPP;
+	}
+
 	UNSET_MESH_FRAME(skb);
 
-	ret = wlan_hard_start_xmit(skb, dev);
+	ret = libertas_hard_start_xmit(skb, dev);
 	lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
 	return ret;
 }
 
-static void wlan_tx_timeout(struct net_device *dev)
+static void libertas_tx_timeout(struct net_device *dev)
 {
 	wlan_private *priv = (wlan_private *) dev->priv;
 
@@ -432,16 +588,17 @@
 	dev->trans_start = jiffies;
 
 	if (priv->adapter->currenttxskb) {
-		if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+		if (priv->adapter->monitormode != WLAN_MONITOR_OFF) {
 			/* If we are here, we have not received feedback from
 			   the previous packet.  Assume TX_FAIL and move on. */
 			priv->adapter->eventcause = 0x01000000;
 			libertas_send_tx_feedback(priv);
 		} else
-			wake_up_interruptible(&priv->mainthread.waitq);
-	} else if (priv->adapter->connect_status == libertas_connected) {
+			wake_up_interruptible(&priv->waitq);
+	} else if (priv->adapter->connect_status == LIBERTAS_CONNECTED) {
 		netif_wake_queue(priv->dev);
-		netif_wake_queue(priv->mesh_dev);
+		if (priv->mesh_dev)
+			netif_wake_queue(priv->mesh_dev);
 	}
 
 	lbs_deb_leave(LBS_DEB_TX);
@@ -453,14 +610,14 @@
  *  @param dev     A pointer to wlan_private structure
  *  @return 	   A pointer to net_device_stats structure
  */
-static struct net_device_stats *wlan_get_stats(struct net_device *dev)
+static struct net_device_stats *libertas_get_stats(struct net_device *dev)
 {
 	wlan_private *priv = (wlan_private *) dev->priv;
 
 	return &priv->stats;
 }
 
-static int wlan_set_mac_address(struct net_device *dev, void *addr)
+static int libertas_set_mac_address(struct net_device *dev, void *addr)
 {
 	int ret = 0;
 	wlan_private *priv = (wlan_private *) dev->priv;
@@ -475,14 +632,14 @@
 	memset(adapter->current_addr, 0, ETH_ALEN);
 
 	/* dev->dev_addr is 8 bytes */
-	lbs_dbg_hex("dev->dev_addr:", dev->dev_addr, ETH_ALEN);
+	lbs_deb_hex(LBS_DEB_NET, "dev->dev_addr", dev->dev_addr, ETH_ALEN);
 
-	lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN);
+	lbs_deb_hex(LBS_DEB_NET, "addr", phwaddr->sa_data, ETH_ALEN);
 	memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN);
 
-	ret = libertas_prepare_and_send_command(priv, cmd_802_11_mac_address,
-				    cmd_act_set,
-				    cmd_option_waitforrsp, 0, NULL);
+	ret = libertas_prepare_and_send_command(priv, CMD_802_11_MAC_ADDRESS,
+				    CMD_ACT_SET,
+				    CMD_OPTION_WAITFORRSP, 0, NULL);
 
 	if (ret) {
 		lbs_deb_net("set MAC address failed\n");
@@ -490,7 +647,7 @@
 		goto done;
 	}
 
-	lbs_dbg_hex("adapter->macaddr:", adapter->current_addr, ETH_ALEN);
+	lbs_deb_hex(LBS_DEB_NET, "adapter->macaddr", adapter->current_addr, ETH_ALEN);
 	memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN);
 	if (priv->mesh_dev)
 		memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN);
@@ -500,7 +657,7 @@
 	return ret;
 }
 
-static int wlan_copy_multicast_address(wlan_adapter * adapter,
+static int libertas_copy_multicast_address(wlan_adapter * adapter,
 				     struct net_device *dev)
 {
 	int i = 0;
@@ -515,11 +672,12 @@
 
 }
 
-static void wlan_set_multicast_list(struct net_device *dev)
+static void libertas_set_multicast_list(struct net_device *dev)
 {
 	wlan_private *priv = dev->priv;
 	wlan_adapter *adapter = priv->adapter;
 	int oldpacketfilter;
+	DECLARE_MAC_BUF(mac);
 
 	lbs_deb_enter(LBS_DEB_NET);
 
@@ -528,57 +686,52 @@
 	if (dev->flags & IFF_PROMISC) {
 		lbs_deb_net("enable promiscuous mode\n");
 		adapter->currentpacketfilter |=
-		    cmd_act_mac_promiscuous_enable;
+		    CMD_ACT_MAC_PROMISCUOUS_ENABLE;
 		adapter->currentpacketfilter &=
-		    ~(cmd_act_mac_all_multicast_enable |
-		      cmd_act_mac_multicast_enable);
+		    ~(CMD_ACT_MAC_ALL_MULTICAST_ENABLE |
+		      CMD_ACT_MAC_MULTICAST_ENABLE);
 	} else {
 		/* Multicast */
 		adapter->currentpacketfilter &=
-		    ~cmd_act_mac_promiscuous_enable;
+		    ~CMD_ACT_MAC_PROMISCUOUS_ENABLE;
 
 		if (dev->flags & IFF_ALLMULTI || dev->mc_count >
 		    MRVDRV_MAX_MULTICAST_LIST_SIZE) {
 			lbs_deb_net( "enabling all multicast\n");
 			adapter->currentpacketfilter |=
-			    cmd_act_mac_all_multicast_enable;
+			    CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
 			adapter->currentpacketfilter &=
-			    ~cmd_act_mac_multicast_enable;
+			    ~CMD_ACT_MAC_MULTICAST_ENABLE;
 		} else {
 			adapter->currentpacketfilter &=
-			    ~cmd_act_mac_all_multicast_enable;
+			    ~CMD_ACT_MAC_ALL_MULTICAST_ENABLE;
 
 			if (!dev->mc_count) {
 				lbs_deb_net("no multicast addresses, "
 				       "disabling multicast\n");
 				adapter->currentpacketfilter &=
-				    ~cmd_act_mac_multicast_enable;
+				    ~CMD_ACT_MAC_MULTICAST_ENABLE;
 			} else {
 				int i;
 
 				adapter->currentpacketfilter |=
-				    cmd_act_mac_multicast_enable;
+				    CMD_ACT_MAC_MULTICAST_ENABLE;
 
 				adapter->nr_of_multicastmacaddr =
-				    wlan_copy_multicast_address(adapter, dev);
+				    libertas_copy_multicast_address(adapter, dev);
 
 				lbs_deb_net("multicast addresses: %d\n",
 				       dev->mc_count);
 
 				for (i = 0; i < dev->mc_count; i++) {
-					lbs_deb_net("Multicast address %d:"
-					       MAC_FMT "\n", i,
-					       adapter->multicastlist[i][0],
-					       adapter->multicastlist[i][1],
-					       adapter->multicastlist[i][2],
-					       adapter->multicastlist[i][3],
-					       adapter->multicastlist[i][4],
-					       adapter->multicastlist[i][5]);
+					lbs_deb_net("Multicast address %d:%s\n",
+					       i, print_mac(mac,
+					       adapter->multicastlist[i]));
 				}
 				/* send multicast addresses to firmware */
 				libertas_prepare_and_send_command(priv,
-						      cmd_mac_multicast_adr,
-						      cmd_act_set, 0, 0,
+						      CMD_MAC_MULTICAST_ADR,
+						      CMD_ACT_SET, 0, 0,
 						      NULL);
 			}
 		}
@@ -599,18 +752,16 @@
  *  @param data    A pointer to wlan_thread structure
  *  @return 	   0
  */
-static int wlan_service_main_thread(void *data)
+static int libertas_thread(void *data)
 {
-	struct wlan_thread *thread = data;
-	wlan_private *priv = thread->priv;
+	struct net_device *dev = data;
+	wlan_private *priv = dev->priv;
 	wlan_adapter *adapter = priv->adapter;
 	wait_queue_t wait;
 	u8 ireg = 0;
 
 	lbs_deb_enter(LBS_DEB_THREAD);
 
-	wlan_activate_thread(thread);
-
 	init_waitqueue_entry(&wait, current);
 
 	set_freezable();
@@ -620,7 +771,7 @@
 		       adapter->intcounter,
 		       adapter->currenttxskb, priv->dnld_sent);
 
-		add_wait_queue(&thread->waitq, &wait);
+		add_wait_queue(&priv->waitq, &wait);
 		set_current_state(TASK_INTERRUPTIBLE);
 		spin_lock_irq(&adapter->driver_lock);
 		if ((adapter->psstate == PS_STATE_SLEEP) ||
@@ -636,14 +787,13 @@
 		} else
 			spin_unlock_irq(&adapter->driver_lock);
 
-
 		lbs_deb_thread(
 		       "main-thread 222 (waking up): intcounter=%d currenttxskb=%p "
 		       "dnld_sent=%d\n", adapter->intcounter,
 		       adapter->currenttxskb, priv->dnld_sent);
 
 		set_current_state(TASK_RUNNING);
-		remove_wait_queue(&thread->waitq, &wait);
+		remove_wait_queue(&priv->waitq, &wait);
 		try_to_freeze();
 
 		lbs_deb_thread("main-thread 333: intcounter=%d currenttxskb=%p "
@@ -681,20 +831,20 @@
 		       adapter->currenttxskb, priv->dnld_sent);
 
 		/* command response? */
-		if (adapter->hisregcpy & his_cmdupldrdy) {
+		if (adapter->hisregcpy & MRVDRV_CMD_UPLD_RDY) {
 			lbs_deb_thread("main-thread: cmd response ready\n");
 
-			adapter->hisregcpy &= ~his_cmdupldrdy;
+			adapter->hisregcpy &= ~MRVDRV_CMD_UPLD_RDY;
 			spin_unlock_irq(&adapter->driver_lock);
 			libertas_process_rx_command(priv);
 			spin_lock_irq(&adapter->driver_lock);
 		}
 
 		/* Any Card Event */
-		if (adapter->hisregcpy & his_cardevent) {
+		if (adapter->hisregcpy & MRVDRV_CARDEVENT) {
 			lbs_deb_thread("main-thread: Card Event Activity\n");
 
-			adapter->hisregcpy &= ~his_cardevent;
+			adapter->hisregcpy &= ~MRVDRV_CARDEVENT;
 
 			if (priv->hw_read_event_cause(priv)) {
 				lbs_pr_alert(
@@ -711,7 +861,7 @@
 		if (adapter->psstate == PS_STATE_PRE_SLEEP) {
 			if (!priv->dnld_sent && !adapter->cur_cmd) {
 				if (adapter->connect_status ==
-				    libertas_connected) {
+				    LIBERTAS_CONNECTED) {
 					lbs_deb_thread(
 					       "main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p "
 					       "dnld_sent=%d cur_cmd=%p, confirm now\n",
@@ -758,13 +908,214 @@
 	del_timer(&adapter->command_timer);
 	adapter->nr_cmd_pending = 0;
 	wake_up_all(&adapter->cmd_pending);
-	wlan_deactivate_thread(thread);
 
 	lbs_deb_leave(LBS_DEB_THREAD);
 	return 0;
 }
 
 /**
+ *  @brief This function downloads firmware image, gets
+ *  HW spec from firmware and set basic parameters to
+ *  firmware.
+ *
+ *  @param priv    A pointer to wlan_private structure
+ *  @return 	   0 or -1
+ */
+static int wlan_setup_firmware(wlan_private * priv)
+{
+	int ret = -1;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ds_mesh_access mesh_access;
+
+	lbs_deb_enter(LBS_DEB_FW);
+
+	/*
+	 * Read MAC address from HW
+	 */
+	memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+	ret = libertas_prepare_and_send_command(priv, CMD_GET_HW_SPEC,
+				    0, CMD_OPTION_WAITFORRSP, 0, NULL);
+
+	if (ret) {
+		ret = -1;
+		goto done;
+	}
+
+	libertas_set_mac_packet_filter(priv);
+
+	/* Get the supported Data rates */
+	ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE,
+				    CMD_ACT_GET_TX_RATE,
+				    CMD_OPTION_WAITFORRSP, 0, NULL);
+
+	if (ret) {
+		ret = -1;
+		goto done;
+	}
+
+	/* Disable mesh autostart */
+	if (priv->mesh_dev) {
+		memset(&mesh_access, 0, sizeof(mesh_access));
+		mesh_access.data[0] = cpu_to_le32(0);
+		ret = libertas_prepare_and_send_command(priv,
+				CMD_MESH_ACCESS,
+				CMD_ACT_MESH_SET_AUTOSTART_ENABLED,
+				CMD_OPTION_WAITFORRSP, 0, (void *)&mesh_access);
+		if (ret) {
+			ret = -1;
+			goto done;
+		}
+		priv->mesh_autostart_enabled = 0;
+	}
+
+       /* Set the boot2 version in firmware */
+       ret = libertas_prepare_and_send_command(priv, CMD_SET_BOOT2_VER,
+                                   0, CMD_OPTION_WAITFORRSP, 0, NULL);
+
+	ret = 0;
+done:
+	lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
+	return ret;
+}
+
+/**
+ *  This function handles the timeout of command sending.
+ *  It will re-send the same command again.
+ */
+static void command_timer_fn(unsigned long data)
+{
+	wlan_private *priv = (wlan_private *)data;
+	wlan_adapter *adapter = priv->adapter;
+	struct cmd_ctrl_node *ptempnode;
+	struct cmd_ds_command *cmd;
+	unsigned long flags;
+
+	ptempnode = adapter->cur_cmd;
+	if (ptempnode == NULL) {
+		lbs_deb_fw("ptempnode empty\n");
+		return;
+	}
+
+	cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr;
+	if (!cmd) {
+		lbs_deb_fw("cmd is NULL\n");
+		return;
+	}
+
+	lbs_deb_fw("command_timer_fn fired, cmd %x\n", cmd->command);
+
+	if (!adapter->fw_ready)
+		return;
+
+	spin_lock_irqsave(&adapter->driver_lock, flags);
+	adapter->cur_cmd = NULL;
+	spin_unlock_irqrestore(&adapter->driver_lock, flags);
+
+	lbs_deb_fw("re-sending same command because of timeout\n");
+	libertas_queue_cmd(adapter, ptempnode, 0);
+
+	wake_up_interruptible(&priv->waitq);
+
+	return;
+}
+
+static int libertas_init_adapter(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	size_t bufsize;
+	int i, ret = 0;
+
+	/* Allocate buffer to store the BSSID list */
+	bufsize = MAX_NETWORK_COUNT * sizeof(struct bss_descriptor);
+	adapter->networks = kzalloc(bufsize, GFP_KERNEL);
+	if (!adapter->networks) {
+		lbs_pr_err("Out of memory allocating beacons\n");
+		ret = -1;
+		goto out;
+	}
+
+	/* Initialize scan result lists */
+	INIT_LIST_HEAD(&adapter->network_free_list);
+	INIT_LIST_HEAD(&adapter->network_list);
+	for (i = 0; i < MAX_NETWORK_COUNT; i++) {
+		list_add_tail(&adapter->networks[i].list,
+			      &adapter->network_free_list);
+	}
+
+	adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum);
+	adapter->libertas_ps_confirm_sleep.command =
+	    cpu_to_le16(CMD_802_11_PS_MODE);
+	adapter->libertas_ps_confirm_sleep.size =
+	    cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep));
+	adapter->libertas_ps_confirm_sleep.action =
+	    cpu_to_le16(CMD_SUBCMD_SLEEP_CONFIRMED);
+
+	memset(adapter->current_addr, 0xff, ETH_ALEN);
+
+	adapter->connect_status = LIBERTAS_DISCONNECTED;
+	adapter->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM;
+	adapter->mode = IW_MODE_INFRA;
+	adapter->curbssparams.channel = DEFAULT_AD_HOC_CHANNEL;
+	adapter->currentpacketfilter = CMD_ACT_MAC_RX_ON | CMD_ACT_MAC_TX_ON;
+	adapter->radioon = RADIO_ON;
+	adapter->auto_rate = 1;
+	adapter->capability = WLAN_CAPABILITY_SHORT_PREAMBLE;
+	adapter->psmode = WLAN802_11POWERMODECAM;
+	adapter->psstate = PS_STATE_FULL_POWER;
+
+	mutex_init(&adapter->lock);
+
+	memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*));
+	adapter->tx_queue_idx = 0;
+	spin_lock_init(&adapter->txqueue_lock);
+
+	setup_timer(&adapter->command_timer, command_timer_fn,
+	            (unsigned long)priv);
+
+	INIT_LIST_HEAD(&adapter->cmdfreeq);
+	INIT_LIST_HEAD(&adapter->cmdpendingq);
+
+	spin_lock_init(&adapter->driver_lock);
+	init_waitqueue_head(&adapter->cmd_pending);
+	adapter->nr_cmd_pending = 0;
+
+	/* Allocate the command buffers */
+	if (libertas_allocate_cmd_buffer(priv)) {
+		lbs_pr_err("Out of memory allocating command buffers\n");
+		ret = -1;
+	}
+
+out:
+	return ret;
+}
+
+static void libertas_free_adapter(wlan_private * priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+
+	if (!adapter) {
+		lbs_deb_fw("why double free adapter?\n");
+		return;
+	}
+
+	lbs_deb_fw("free command buffer\n");
+	libertas_free_cmd_buffer(priv);
+
+	lbs_deb_fw("free command_timer\n");
+	del_timer(&adapter->command_timer);
+
+	lbs_deb_fw("free scan results table\n");
+	kfree(adapter->networks);
+	adapter->networks = NULL;
+
+	/* Free the adapter object itself */
+	lbs_deb_fw("free adapter\n");
+	kfree(adapter);
+	priv->adapter = NULL;
+}
+
+/**
  * @brief This function adds the card. it will probe the
  * card, allocate the wlan_priv and initialize the device.
  *
@@ -781,7 +1132,7 @@
 	/* Allocate an Ethernet device and register it */
 	if (!(dev = alloc_etherdev(sizeof(wlan_private)))) {
 		lbs_pr_err("init ethX device failed\n");
-		return NULL;
+		goto done;
 	}
 	priv = dev->priv;
 
@@ -791,20 +1142,24 @@
 		goto err_kzalloc;
 	}
 
+	if (libertas_init_adapter(priv)) {
+		lbs_pr_err("failed to initialize adapter structure.\n");
+		goto err_init_adapter;
+	}
+
 	priv->dev = dev;
 	priv->card = card;
 	priv->mesh_open = 0;
 	priv->infra_open = 0;
-
-	SET_MODULE_OWNER(dev);
+	priv->hotplug_device = dmdev;
 
 	/* Setup the OS Interface to our functions */
-	dev->open = wlan_open;
-	dev->hard_start_xmit = wlan_pre_start_xmit;
-	dev->stop = wlan_close;
-	dev->set_mac_address = wlan_set_mac_address;
-	dev->tx_timeout = wlan_tx_timeout;
-	dev->get_stats = wlan_get_stats;
+	dev->open = libertas_open;
+	dev->hard_start_xmit = libertas_pre_start_xmit;
+	dev->stop = libertas_close;
+	dev->set_mac_address = libertas_set_mac_address;
+	dev->tx_timeout = libertas_tx_timeout;
+	dev->get_stats = libertas_get_stats;
 	dev->watchdog_timeo = 5 * HZ;
 	dev->ethtool_ops = &libertas_ethtool_ops;
 #ifdef	WIRELESS_EXT
@@ -813,84 +1168,148 @@
 #define NETIF_F_DYNALLOC 16
 	dev->features |= NETIF_F_DYNALLOC;
 	dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
-	dev->set_multicast_list = wlan_set_multicast_list;
+	dev->set_multicast_list = libertas_set_multicast_list;
 
 	SET_NETDEV_DEV(dev, dmdev);
 
-	INIT_LIST_HEAD(&priv->adapter->cmdfreeq);
-	INIT_LIST_HEAD(&priv->adapter->cmdpendingq);
+	priv->rtap_net_dev = NULL;
+	if (device_create_file(dmdev, &dev_attr_libertas_rtap))
+		goto err_init_adapter;
 
-	spin_lock_init(&priv->adapter->driver_lock);
-	init_waitqueue_head(&priv->adapter->cmd_pending);
-	priv->adapter->nr_cmd_pending = 0;
+	lbs_deb_thread("Starting main thread...\n");
+	init_waitqueue_head(&priv->waitq);
+	priv->main_thread = kthread_run(libertas_thread, dev, "libertas_main");
+	if (IS_ERR(priv->main_thread)) {
+		lbs_deb_thread("Error creating main thread.\n");
+		goto err_kthread_run;
+	}
+
+	priv->work_thread = create_singlethread_workqueue("libertas_worker");
+	INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker);
+	INIT_DELAYED_WORK(&priv->scan_work, libertas_scan_worker);
+	INIT_WORK(&priv->sync_channel, libertas_sync_channel);
+
 	goto done;
 
+err_kthread_run:
+	device_remove_file(dmdev, &dev_attr_libertas_rtap);
+
+err_init_adapter:
+	libertas_free_adapter(priv);
+
 err_kzalloc:
 	free_netdev(dev);
 	priv = NULL;
+
 done:
 	lbs_deb_leave_args(LBS_DEB_NET, "priv %p", priv);
 	return priv;
 }
 EXPORT_SYMBOL_GPL(libertas_add_card);
 
-int libertas_activate_card(wlan_private *priv, char *fw_name)
+
+int libertas_remove_card(wlan_private *priv)
+{
+	wlan_adapter *adapter = priv->adapter;
+	struct net_device *dev = priv->dev;
+	union iwreq_data wrqu;
+
+	lbs_deb_enter(LBS_DEB_MAIN);
+
+	libertas_remove_rtap(priv);
+
+	dev = priv->dev;
+	device_remove_file(priv->hotplug_device, &dev_attr_libertas_rtap);
+
+	cancel_delayed_work(&priv->scan_work);
+	cancel_delayed_work(&priv->assoc_work);
+	destroy_workqueue(priv->work_thread);
+
+	if (adapter->psmode == WLAN802_11POWERMODEMAX_PSP) {
+		adapter->psmode = WLAN802_11POWERMODECAM;
+		libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
+	}
+
+	memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
+	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+	wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+
+	/* Stop the thread servicing the interrupts */
+	adapter->surpriseremoved = 1;
+	kthread_stop(priv->main_thread);
+
+	libertas_free_adapter(priv);
+
+	priv->dev = NULL;
+	free_netdev(dev);
+
+	lbs_deb_leave(LBS_DEB_MAIN);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(libertas_remove_card);
+
+
+int libertas_start_card(wlan_private *priv)
 {
 	struct net_device *dev = priv->dev;
 	int ret = -1;
 
 	lbs_deb_enter(LBS_DEB_MAIN);
 
-	lbs_deb_thread("Starting kthread...\n");
-	priv->mainthread.priv = priv;
-	wlan_create_thread(wlan_service_main_thread,
-			   &priv->mainthread, "wlan_main_service");
+	/* poke the firmware */
+	ret = wlan_setup_firmware(priv);
+	if (ret)
+		goto done;
 
-	priv->assoc_thread =
-		create_singlethread_workqueue("libertas_assoc");
-	INIT_DELAYED_WORK(&priv->assoc_work, libertas_association_worker);
-	INIT_WORK(&priv->sync_channel, libertas_sync_channel);
-
-	/*
-	 * Register the device. Fillup the private data structure with
-	 * relevant information from the card and request for the required
-	 * IRQ.
-	 */
-	if (priv->hw_register_dev(priv) < 0) {
-		lbs_pr_err("failed to register WLAN device\n");
-		goto err_registerdev;
-	}
-
-	/* init FW and HW */
-	if (fw_name && libertas_init_fw(priv, fw_name)) {
-		lbs_pr_err("firmware init failed\n");
-		goto err_registerdev;
-	}
+	/* init 802.11d */
+	libertas_init_11d(priv);
 
 	if (register_netdev(dev)) {
 		lbs_pr_err("cannot register ethX device\n");
-		goto err_init_fw;
+		goto done;
 	}
 
-	lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
-
 	libertas_debugfs_init_one(priv, dev);
 
-	ret = 0;
-	goto done;
+	lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
 
-err_init_fw:
-	priv->hw_unregister_dev(priv);
-err_registerdev:
-	destroy_workqueue(priv->assoc_thread);
-	/* Stop the thread servicing the interrupts */
-	wake_up_interruptible(&priv->mainthread.waitq);
-	wlan_terminate_thread(&priv->mainthread);
+	ret = 0;
+
 done:
-	lbs_deb_leave_args(LBS_DEB_NET, "ret %d", ret);
+	lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(libertas_activate_card);
+EXPORT_SYMBOL_GPL(libertas_start_card);
+
+
+int libertas_stop_card(wlan_private *priv)
+{
+	struct net_device *dev = priv->dev;
+	int ret = -1;
+	struct cmd_ctrl_node *cmdnode;
+	unsigned long flags;
+
+	lbs_deb_enter(LBS_DEB_MAIN);
+
+	netif_stop_queue(priv->dev);
+	netif_carrier_off(priv->dev);
+
+	libertas_debugfs_remove_one(priv);
+
+	/* Flush pending command nodes */
+	spin_lock_irqsave(&priv->adapter->driver_lock, flags);
+	list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
+		cmdnode->cmdwaitqwoken = 1;
+		wake_up_interruptible(&cmdnode->cmdwait_q);
+	}
+	spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
+
+	unregister_netdev(dev);
+
+	lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(libertas_stop_card);
 
 
 /**
@@ -915,13 +1334,11 @@
 	mesh_dev->priv = priv;
 	priv->mesh_dev = mesh_dev;
 
-	SET_MODULE_OWNER(mesh_dev);
-
-	mesh_dev->open = mesh_open;
-	mesh_dev->hard_start_xmit = mesh_pre_start_xmit;
-	mesh_dev->stop = mesh_close;
-	mesh_dev->get_stats = wlan_get_stats;
-	mesh_dev->set_mac_address = wlan_set_mac_address;
+	mesh_dev->open = libertas_mesh_open;
+	mesh_dev->hard_start_xmit = libertas_mesh_pre_start_xmit;
+	mesh_dev->stop = libertas_mesh_close;
+	mesh_dev->get_stats = libertas_get_stats;
+	mesh_dev->set_mac_address = libertas_set_mac_address;
 	mesh_dev->ethtool_ops = &libertas_ethtool_ops;
 	memcpy(mesh_dev->dev_addr, priv->dev->dev_addr,
 			sizeof(priv->dev->dev_addr));
@@ -940,7 +1357,7 @@
 		goto err_free;
 	}
 
-	ret = device_create_file(&(mesh_dev->dev), &dev_attr_anycast_mask);
+	ret = sysfs_create_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group);
 	if (ret)
 		goto err_unregister;
 
@@ -948,7 +1365,6 @@
 	ret = 0;
 	goto done;
 
-
 err_unregister:
 	unregister_netdev(mesh_dev);
 
@@ -961,86 +1377,12 @@
 }
 EXPORT_SYMBOL_GPL(libertas_add_mesh);
 
-static void wake_pending_cmdnodes(wlan_private *priv)
-{
-	struct cmd_ctrl_node *cmdnode;
-	unsigned long flags;
-
-	lbs_deb_enter(LBS_DEB_CMD);
-
-	spin_lock_irqsave(&priv->adapter->driver_lock, flags);
-	list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) {
-		cmdnode->cmdwaitqwoken = 1;
-		wake_up_interruptible(&cmdnode->cmdwait_q);
-	}
-	spin_unlock_irqrestore(&priv->adapter->driver_lock, flags);
-}
-
-
-int libertas_remove_card(wlan_private *priv)
-{
-	wlan_adapter *adapter;
-	struct net_device *dev;
-	union iwreq_data wrqu;
-
-	lbs_deb_enter(LBS_DEB_NET);
-
-	if (!priv)
-		goto out;
-
-	adapter = priv->adapter;
-
-	if (!adapter)
-		goto out;
-
-	dev = priv->dev;
-
-	netif_stop_queue(priv->dev);
-	netif_carrier_off(priv->dev);
-
-	wake_pending_cmdnodes(priv);
-
-	unregister_netdev(dev);
-
-	cancel_delayed_work(&priv->assoc_work);
-	destroy_workqueue(priv->assoc_thread);
-
-	if (adapter->psmode == wlan802_11powermodemax_psp) {
-		adapter->psmode = wlan802_11powermodecam;
-		libertas_ps_wakeup(priv, cmd_option_waitforrsp);
-	}
-
-	memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN);
-	wrqu.ap_addr.sa_family = ARPHRD_ETHER;
-	wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
-
-	adapter->surpriseremoved = 1;
-
-	/* Stop the thread servicing the interrupts */
-	wlan_terminate_thread(&priv->mainthread);
-
-	libertas_debugfs_remove_one(priv);
-
-	lbs_deb_net("free adapter\n");
-	libertas_free_adapter(priv);
-
-	lbs_deb_net("unregister finish\n");
-
-	priv->dev = NULL;
-	free_netdev(dev);
-
-out:
-	lbs_deb_leave(LBS_DEB_NET);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(libertas_remove_card);
-
 
 void libertas_remove_mesh(wlan_private *priv)
 {
 	struct net_device *mesh_dev;
 
-	lbs_deb_enter(LBS_DEB_NET);
+	lbs_deb_enter(LBS_DEB_MAIN);
 
 	if (!priv)
 		goto out;
@@ -1050,14 +1392,14 @@
 	netif_stop_queue(mesh_dev);
 	netif_carrier_off(priv->mesh_dev);
 
-	device_remove_file(&(mesh_dev->dev), &dev_attr_anycast_mask);
+	sysfs_remove_group(&(mesh_dev->dev.kobj), &libertas_mesh_attr_group);
 	unregister_netdev(mesh_dev);
 
 	priv->mesh_dev = NULL ;
 	free_netdev(mesh_dev);
 
 out:
-	lbs_deb_leave(LBS_DEB_NET);
+	lbs_deb_leave(LBS_DEB_MAIN);
 }
 EXPORT_SYMBOL_GPL(libertas_remove_mesh);
 
@@ -1076,7 +1418,7 @@
 
 	lbs_deb_enter(LBS_DEB_MAIN);
 
-	end = sizeof(region_cfp_table)/sizeof(struct region_cfp_table);
+	end = ARRAY_SIZE(region_cfp_table);
 
 	for (i = 0; i < end ; i++) {
 		lbs_deb_main("region_cfp_table[i].region=%d\n",
@@ -1148,15 +1490,30 @@
 	if (priv->adapter->psstate == PS_STATE_SLEEP) {
 		priv->adapter->psstate = PS_STATE_AWAKE;
 		netif_wake_queue(dev);
-		netif_wake_queue(priv->mesh_dev);
+		if (priv->mesh_dev)
+			netif_wake_queue(priv->mesh_dev);
 	}
 
-	wake_up_interruptible(&priv->mainthread.waitq);
+	wake_up_interruptible(&priv->waitq);
 
 	lbs_deb_leave(LBS_DEB_THREAD);
 }
 EXPORT_SYMBOL_GPL(libertas_interrupt);
 
+int libertas_reset_device(wlan_private *priv)
+{
+	int ret;
+
+	lbs_deb_enter(LBS_DEB_MAIN);
+	ret = libertas_prepare_and_send_command(priv, CMD_802_11_RESET,
+				    CMD_ACT_HALT, 0, 0, NULL);
+	msleep_interruptible(10);
+
+	lbs_deb_leave_args(LBS_DEB_MAIN, "ret %d", ret);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(libertas_reset_device);
+
 static int libertas_init_module(void)
 {
 	lbs_deb_enter(LBS_DEB_MAIN);
@@ -1174,6 +1531,81 @@
 	lbs_deb_leave(LBS_DEB_MAIN);
 }
 
+/*
+ * rtap interface support fuctions
+ */
+
+static int libertas_rtap_open(struct net_device *dev)
+{
+        netif_carrier_off(dev);
+        netif_stop_queue(dev);
+        return 0;
+}
+
+static int libertas_rtap_stop(struct net_device *dev)
+{
+        return 0;
+}
+
+static int libertas_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+        netif_stop_queue(dev);
+        return -EOPNOTSUPP;
+}
+
+static struct net_device_stats *libertas_rtap_get_stats(struct net_device *dev)
+{
+	wlan_private *priv = dev->priv;
+	return &priv->ieee->stats;
+}
+
+
+void libertas_remove_rtap(wlan_private *priv)
+{
+	if (priv->rtap_net_dev == NULL)
+		return;
+	unregister_netdev(priv->rtap_net_dev);
+	free_ieee80211(priv->rtap_net_dev);
+	priv->rtap_net_dev = NULL;
+}
+
+int libertas_add_rtap(wlan_private *priv)
+{
+	int rc = 0;
+
+	if (priv->rtap_net_dev)
+		return -EPERM;
+
+	priv->rtap_net_dev = alloc_ieee80211(0);
+	if (priv->rtap_net_dev == NULL)
+		return -ENOMEM;
+
+
+	priv->ieee = netdev_priv(priv->rtap_net_dev);
+
+	strcpy(priv->rtap_net_dev->name, "rtap%d");
+
+	priv->rtap_net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
+	priv->rtap_net_dev->open = libertas_rtap_open;
+	priv->rtap_net_dev->stop = libertas_rtap_stop;
+	priv->rtap_net_dev->get_stats = libertas_rtap_get_stats;
+	priv->rtap_net_dev->hard_start_xmit = libertas_rtap_hard_start_xmit;
+	priv->rtap_net_dev->set_multicast_list = libertas_set_multicast_list;
+	priv->rtap_net_dev->priv = priv;
+
+	priv->ieee->iw_mode = IW_MODE_MONITOR;
+
+	rc = register_netdev(priv->rtap_net_dev);
+	if (rc) {
+		free_ieee80211(priv->rtap_net_dev);
+		priv->rtap_net_dev = NULL;
+		return rc;
+	}
+
+	return 0;
+}
+
+
 module_init(libertas_init_module);
 module_exit(libertas_exit_module);
 
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index 769c86f..0420e5b 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -85,12 +85,12 @@
 static void wlan_save_rawSNRNF(wlan_private * priv, struct rxpd *p_rx_pd)
 {
 	wlan_adapter *adapter = priv->adapter;
-	if (adapter->numSNRNF < adapter->data_avg_factor)
+	if (adapter->numSNRNF < DEFAULT_DATA_AVG_FACTOR)
 		adapter->numSNRNF++;
 	adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr;
 	adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->nf;
 	adapter->nextSNRNF++;
-	if (adapter->nextSNRNF >= adapter->data_avg_factor)
+	if (adapter->nextSNRNF >= DEFAULT_DATA_AVG_FACTOR)
 		adapter->nextSNRNF = 0;
 	return;
 }
@@ -117,8 +117,6 @@
 	adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf;
 	wlan_save_rawSNRNF(priv, p_rx_pd);
 
-	adapter->rxpd_rate = p_rx_pd->rx_rate;
-
 	adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE;
 	adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE;
 	lbs_deb_rx("after computing SNR: SNR-avg = %d, NF-avg = %d\n",
@@ -140,12 +138,15 @@
 {
 	lbs_deb_rx("skb->data %p\n", skb->data);
 
-	if (priv->mesh_dev && IS_MESH_FRAME(skb))
-		skb->protocol = eth_type_trans(skb, priv->mesh_dev);
-	else
-		skb->protocol = eth_type_trans(skb, priv->dev);
+	if (priv->adapter->monitormode != WLAN_MONITOR_OFF) {
+		skb->protocol = eth_type_trans(skb, priv->rtap_net_dev);
+	} else {
+		if (priv->mesh_dev && IS_MESH_FRAME(skb))
+			skb->protocol = eth_type_trans(skb, priv->mesh_dev);
+		else
+			skb->protocol = eth_type_trans(skb, priv->dev);
+	}
 	skb->ip_summed = CHECKSUM_UNNECESSARY;
-
 	netif_rx(skb);
 }
 
@@ -172,11 +173,7 @@
 
 	lbs_deb_enter(LBS_DEB_RX);
 
-	if (priv->adapter->debugmode & MRVDRV_DEBUG_RX_PATH)
-		lbs_dbg_hex("RX packet: ", skb->data,
-			 min_t(unsigned int, skb->len, 100));
-
-	if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+	if (priv->adapter->monitormode != WLAN_MONITOR_OFF)
 		return process_rxed_802_11_packet(priv, skb);
 
 	p_rx_pkt = (struct rxpackethdr *) skb->data;
@@ -186,7 +183,7 @@
 	else
 		UNSET_MESH_FRAME(skb);
 
-	lbs_dbg_hex("RX Data: Before chop rxpd", skb->data,
+	lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data,
 		 min_t(unsigned int, skb->len, 100));
 
 	if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
@@ -210,9 +207,9 @@
 	lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
 	       skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
 
-	lbs_dbg_hex("RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
+	lbs_deb_hex(LBS_DEB_RX, "RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr,
 		sizeof(p_rx_pkt->eth803_hdr.dest_addr));
-	lbs_dbg_hex("RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
+	lbs_deb_hex(LBS_DEB_RX, "RX Data: Src", p_rx_pkt->eth803_hdr.src_addr,
 		sizeof(p_rx_pkt->eth803_hdr.src_addr));
 
 	if (memcmp(&p_rx_pkt->rfc1042_hdr,
@@ -244,7 +241,7 @@
 		 */
 		hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt;
 	} else {
-		lbs_dbg_hex("RX Data: LLC/SNAP",
+		lbs_deb_hex(LBS_DEB_RX, "RX Data: LLC/SNAP",
 			(u8 *) & p_rx_pkt->rfc1042_hdr,
 			sizeof(p_rx_pkt->rfc1042_hdr));
 
@@ -260,8 +257,8 @@
 	/* Take the data rate from the rxpd structure
 	 * only if the rate is auto
 	 */
-	if (adapter->is_datarate_auto)
-		adapter->datarate = libertas_index_to_data_rate(p_rx_pd->rx_rate);
+	if (adapter->auto_rate)
+		adapter->cur_rate = libertas_fw_index_to_data_rate(p_rx_pd->rx_rate);
 
 	wlan_compute_rssi(priv, p_rx_pd);
 
@@ -296,21 +293,22 @@
 		return 11;
 	case 3:		/*  11 Mbps */
 		return 22;
-	case 4:		/*   6 Mbps */
+	/* case 4: reserved */
+	case 5:		/*   6 Mbps */
 		return 12;
-	case 5:		/*   9 Mbps */
+	case 6:		/*   9 Mbps */
 		return 18;
-	case 6:		/*  12 Mbps */
+	case 7:		/*  12 Mbps */
 		return 24;
-	case 7:		/*  18 Mbps */
+	case 8:		/*  18 Mbps */
 		return 36;
-	case 8:		/*  24 Mbps */
+	case 9:		/*  24 Mbps */
 		return 48;
-	case 9:		/*  36 Mbps */
+	case 10:		/*  36 Mbps */
 		return 72;
-	case 10:		/*  48 Mbps */
+	case 11:		/*  48 Mbps */
 		return 96;
-	case 11:		/*  54 Mbps */
+	case 12:		/*  54 Mbps */
 		return 108;
 	}
 	lbs_pr_alert("Invalid Marvell WLAN rate %i\n", rate);
@@ -340,7 +338,7 @@
 	p_rx_pkt = (struct rx80211packethdr *) skb->data;
 	prxpd = &p_rx_pkt->rx_pd;
 
-	// lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
+	// lbs_deb_hex(LBS_DEB_RX, "RX Data: Before chop rxpd", skb->data, min(skb->len, 100));
 
 	if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
 		lbs_deb_rx("rx err: frame received wit bad length\n");
@@ -361,20 +359,19 @@
 	       skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd));
 
 	/* create the exported radio header */
-	switch (priv->adapter->radiomode) {
-	case WLAN_RADIOMODE_NONE:
+	if(priv->adapter->monitormode == WLAN_MONITOR_OFF) {
 		/* no radio header */
 		/* chop the rxpd */
 		skb_pull(skb, sizeof(struct rxpd));
-		break;
+	}
 
-	case WLAN_RADIOMODE_RADIOTAP:
+	else {
 		/* radiotap header */
 		radiotap_hdr.hdr.it_version = 0;
 		/* XXX must check this value for pad */
 		radiotap_hdr.hdr.it_pad = 0;
-		radiotap_hdr.hdr.it_len = sizeof(struct rx_radiotap_hdr);
-		radiotap_hdr.hdr.it_present = RX_RADIOTAP_PRESENT;
+		radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr));
+		radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT);
 		/* unknown values */
 		radiotap_hdr.flags = 0;
 		radiotap_hdr.chan_freq = 0;
@@ -389,8 +386,6 @@
 			radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS;
 		//memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18);
 
-		// lbs_dbg_hex1("RX radiomode packet BEF: ", skb->data, min(skb->len, 100));
-
 		/* chop the rxpd */
 		skb_pull(skb, sizeof(struct rxpd));
 
@@ -408,25 +403,13 @@
 							    rx_radiotap_hdr));
 		memcpy(pradiotap_hdr, &radiotap_hdr,
 		       sizeof(struct rx_radiotap_hdr));
-		//lbs_dbg_hex1("RX radiomode packet AFT: ", skb->data, min(skb->len, 100));
-		break;
-
-	default:
-		/* unknown header */
-		lbs_pr_alert("Unknown radiomode %i\n",
-		       priv->adapter->radiomode);
-		/* don't export any header */
-		/* chop the rxpd */
-		skb_pull(skb, sizeof(struct rxpd));
-		break;
 	}
 
 	/* Take the data rate from the rxpd structure
 	 * only if the rate is auto
 	 */
-	if (adapter->is_datarate_auto) {
-		adapter->datarate = libertas_index_to_data_rate(prxpd->rx_rate);
-	}
+	if (adapter->auto_rate)
+		adapter->cur_rate = libertas_fw_index_to_data_rate(prxpd->rx_rate);
 
 	wlan_compute_rssi(priv, prxpd);
 
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index c3043dc..ad1e67d 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -13,10 +13,13 @@
 #include <net/ieee80211.h>
 #include <net/iw_handler.h>
 
+#include <asm/unaligned.h>
+
 #include "host.h"
 #include "decl.h"
 #include "dev.h"
 #include "scan.h"
+#include "join.h"
 
 //! Approximate amount of data needed to pass a scan result back to iwlist
 #define MAX_SCAN_CELL_SIZE  (IW_EV_ADDR_LEN             \
@@ -62,6 +65,15 @@
 static const u8 zeromac[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 static const u8 bcastmac[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
 
+
+
+
+/*********************************************************************/
+/*                                                                   */
+/*  Misc helper functions                                            */
+/*                                                                   */
+/*********************************************************************/
+
 static inline void clear_bss_descriptor (struct bss_descriptor * bss)
 {
 	/* Don't blow away ->list, just BSS data */
@@ -74,9 +86,9 @@
 	if (   !secinfo->wep_enabled
 	    && !secinfo->WPAenabled
 	    && !secinfo->WPA2enabled
-	    && match_bss->wpa_ie[0] != WPA_IE
-	    && match_bss->rsn_ie[0] != WPA2_IE
-	    && !match_bss->privacy) {
+	    && match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC
+	    && match_bss->rsn_ie[0] != MFIE_TYPE_RSN
+	    && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
 		return 1;
 	}
 	return 0;
@@ -88,7 +100,7 @@
 	if ( secinfo->wep_enabled
 	   && !secinfo->WPAenabled
 	   && !secinfo->WPA2enabled
-	   && match_bss->privacy) {
+	   && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
 		return 1;
 	}
 	return 0;
@@ -99,9 +111,10 @@
 {
 	if (  !secinfo->wep_enabled
 	   && secinfo->WPAenabled
-	   && (match_bss->wpa_ie[0] == WPA_IE)
+	   && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC)
 	   /* privacy bit may NOT be set in some APs like LinkSys WRT54G
-	      && bss->privacy */
+	      && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
+	    */
 	   ) {
 		return 1;
 	}
@@ -113,9 +126,10 @@
 {
 	if (  !secinfo->wep_enabled
 	   && secinfo->WPA2enabled
-	   && (match_bss->rsn_ie[0] == WPA2_IE)
+	   && (match_bss->rsn_ie[0] == MFIE_TYPE_RSN)
 	   /* privacy bit may NOT be set in some APs like LinkSys WRT54G
-	      && bss->privacy */
+	      && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
+	    */
 	   ) {
 		return 1;
 	}
@@ -128,9 +142,9 @@
 	if (  !secinfo->wep_enabled
 	   && !secinfo->WPAenabled
 	   && !secinfo->WPA2enabled
-	   && (match_bss->wpa_ie[0] != WPA_IE)
-	   && (match_bss->rsn_ie[0] != WPA2_IE)
-	   && match_bss->privacy) {
+	   && (match_bss->wpa_ie[0] != MFIE_TYPE_GENERIC)
+	   && (match_bss->rsn_ie[0] != MFIE_TYPE_RSN)
+	   && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) {
 		return 1;
 	}
 	return 0;
@@ -160,7 +174,7 @@
 {
 	int matched = 0;
 
-	lbs_deb_enter(LBS_DEB_ASSOC);
+	lbs_deb_enter(LBS_DEB_SCAN);
 
 	if (bss->mode != mode)
 		goto done;
@@ -177,7 +191,7 @@
 		       adapter->secinfo.wep_enabled ? "e" : "d",
 		       adapter->secinfo.WPAenabled ? "e" : "d",
 		       adapter->secinfo.WPA2enabled ? "e" : "d",
-		       bss->privacy);
+		       (bss->capability & WLAN_CAPABILITY_PRIVACY));
 		goto done;
 	} else if ((matched = match_bss_wpa2(&adapter->secinfo, bss))) {
 		lbs_deb_scan(
@@ -187,15 +201,14 @@
 		       adapter->secinfo.wep_enabled ? "e" : "d",
 		       adapter->secinfo.WPAenabled ? "e" : "d",
 		       adapter->secinfo.WPA2enabled ? "e" : "d",
-		       bss->privacy);
+		       (bss->capability & WLAN_CAPABILITY_PRIVACY));
 		goto done;
 	} else if ((matched = match_bss_dynamic_wep(&adapter->secinfo, bss))) {
 		lbs_deb_scan(
 		       "is_network_compatible() dynamic WEP: "
 		       "wpa_ie=%#x wpa2_ie=%#x privacy=%#x\n",
-		       bss->wpa_ie[0],
-		       bss->rsn_ie[0],
-		       bss->privacy);
+		       bss->wpa_ie[0], bss->rsn_ie[0],
+		       (bss->capability & WLAN_CAPABILITY_PRIVACY));
 		goto done;
 	}
 
@@ -207,16 +220,44 @@
 	       adapter->secinfo.wep_enabled ? "e" : "d",
 	       adapter->secinfo.WPAenabled ? "e" : "d",
 	       adapter->secinfo.WPA2enabled ? "e" : "d",
-	       bss->privacy);
+	       (bss->capability & WLAN_CAPABILITY_PRIVACY));
 
 done:
-	lbs_deb_leave(LBS_DEB_SCAN);
+	lbs_deb_leave_args(LBS_DEB_SCAN, "matched: %d", matched);
 	return matched;
 }
 
 /**
+ *  @brief Compare two SSIDs
+ *
+ *  @param ssid1    A pointer to ssid to compare
+ *  @param ssid2    A pointer to ssid to compare
+ *
+ *  @return         0--ssid is same, otherwise is different
+ */
+int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
+{
+	if (ssid1_len != ssid2_len)
+		return -1;
+
+	return memcmp(ssid1, ssid2, ssid1_len);
+}
+
+
+
+
+/*********************************************************************/
+/*                                                                   */
+/*  Main scanning support                                            */
+/*                                                                   */
+/*********************************************************************/
+
+
+/**
  *  @brief Create a channel list for the driver to scan based on region info
  *
+ *  Only used from wlan_scan_setup_scan_config()
+ *
  *  Use the driver region/band information to construct a comprehensive list
  *    of channels to scan.  This routine is used for any scan that is not
  *    provided a specific channel list to scan.
@@ -244,17 +285,19 @@
 	int nextchan;
 	u8 scantype;
 
+	lbs_deb_enter_args(LBS_DEB_SCAN, "filteredscan %d", filteredscan);
+
 	chanidx = 0;
 
 	/* Set the default scan type to the user specified type, will later
 	 *   be changed to passive on a per channel basis if restricted by
 	 *   regulatory requirements (11d or 11h)
 	 */
-	scantype = adapter->scantype;
+	scantype = CMD_SCAN_TYPE_ACTIVE;
 
 	for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) {
 		if (priv->adapter->enable11d &&
-		    adapter->connect_status != libertas_connected) {
+		    adapter->connect_status != LIBERTAS_CONNECTED) {
 			/* Scan all the supported chan for the first scan */
 			if (!adapter->universal_channel[rgnidx].valid)
 				continue;
@@ -286,11 +329,11 @@
 			case BAND_G:
 			default:
 				scanchanlist[chanidx].radiotype =
-				    cmd_scan_radio_type_bg;
+				    CMD_SCAN_RADIO_TYPE_BG;
 				break;
 			}
 
-			if (scantype == cmd_scan_type_passive) {
+			if (scantype == CMD_SCAN_TYPE_PASSIVE) {
 				scanchanlist[chanidx].maxscantime =
 				    cpu_to_le16(MRVDRV_PASSIVE_SCAN_CHAN_TIME);
 				scanchanlist[chanidx].chanscanmode.passivescan =
@@ -312,6 +355,16 @@
 	}
 }
 
+
+/* Delayed partial scan worker */
+void libertas_scan_worker(struct work_struct *work)
+{
+	wlan_private *priv = container_of(work, wlan_private, scan_work.work);
+
+	wlan_scan_networks(priv, NULL, 0);
+}
+
+
 /**
  *  @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds
  *
@@ -359,7 +412,6 @@
 			    u8 * pfilteredscan,
 			    u8 * pscancurrentonly)
 {
-	wlan_adapter *adapter = priv->adapter;
 	struct mrvlietypes_numprobes *pnumprobestlv;
 	struct mrvlietypes_ssidparamset *pssidtlv;
 	struct wlan_scan_cmd_config * pscancfgout = NULL;
@@ -371,6 +423,8 @@
 	int channel;
 	int radiotype;
 
+	lbs_deb_enter(LBS_DEB_SCAN);
+
 	pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL);
 	if (pscancfgout == NULL)
 		goto out;
@@ -407,15 +461,12 @@
 	*pscancurrentonly = 0;
 
 	if (puserscanin) {
-
 		/* Set the bss type scan filter, use adapter setting if unset */
 		pscancfgout->bsstype =
-		    (puserscanin->bsstype ? puserscanin->bsstype : adapter->
-		     scanmode);
+		    puserscanin->bsstype ? puserscanin->bsstype : CMD_BSS_TYPE_ANY;
 
 		/* Set the number of probes to send, use adapter setting if unset */
-		numprobes = (puserscanin->numprobes ? puserscanin->numprobes :
-			     adapter->scanprobes);
+		numprobes = puserscanin->numprobes ? puserscanin->numprobes : 0;
 
 		/*
 		 * Set the BSSID filter to the incoming configuration,
@@ -447,8 +498,8 @@
 			*pfilteredscan = 1;
 		}
 	} else {
-		pscancfgout->bsstype = adapter->scanmode;
-		numprobes = adapter->scanprobes;
+		pscancfgout->bsstype = CMD_BSS_TYPE_ANY;
+		numprobes = 0;
 	}
 
 	/* If the input config or adapter has the number of Probes set, add tlv */
@@ -469,59 +520,56 @@
 	 */
 	*ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos;
 
-	if (puserscanin && puserscanin->chanlist[0].channumber) {
-
-		lbs_deb_scan("Scan: Using supplied channel list\n");
-
-		for (chanidx = 0;
-		     chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
-		     && puserscanin->chanlist[chanidx].channumber; chanidx++) {
-
-			channel = puserscanin->chanlist[chanidx].channumber;
-			(pscanchanlist + chanidx)->channumber = channel;
-
-			radiotype = puserscanin->chanlist[chanidx].radiotype;
-			(pscanchanlist + chanidx)->radiotype = radiotype;
-
-			scantype = puserscanin->chanlist[chanidx].scantype;
-
-			if (scantype == cmd_scan_type_passive) {
-				(pscanchanlist +
-				 chanidx)->chanscanmode.passivescan = 1;
-			} else {
-				(pscanchanlist +
-				 chanidx)->chanscanmode.passivescan = 0;
-			}
-
-			if (puserscanin->chanlist[chanidx].scantime) {
-				scandur =
-				    puserscanin->chanlist[chanidx].scantime;
-			} else {
-				if (scantype == cmd_scan_type_passive) {
-					scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
-				} else {
-					scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
-				}
-			}
-
-			(pscanchanlist + chanidx)->minscantime =
-			    cpu_to_le16(scandur);
-			(pscanchanlist + chanidx)->maxscantime =
-			    cpu_to_le16(scandur);
-		}
-
-		/* Check if we are only scanning the current channel */
-		if ((chanidx == 1) && (puserscanin->chanlist[0].channumber
-				       ==
-				       priv->adapter->curbssparams.channel)) {
-			*pscancurrentonly = 1;
-			lbs_deb_scan("Scan: Scanning current channel only");
-		}
-
-	} else {
-		lbs_deb_scan("Scan: Creating full region channel list\n");
+	if (!puserscanin || !puserscanin->chanlist[0].channumber) {
+		/* Create a default channel scan list */
+		lbs_deb_scan("creating full region channel list\n");
 		wlan_scan_create_channel_list(priv, pscanchanlist,
 					      *pfilteredscan);
+		goto out;
+	}
+
+	for (chanidx = 0;
+	     chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX
+	     && puserscanin->chanlist[chanidx].channumber; chanidx++) {
+
+		channel = puserscanin->chanlist[chanidx].channumber;
+		(pscanchanlist + chanidx)->channumber = channel;
+
+		radiotype = puserscanin->chanlist[chanidx].radiotype;
+		(pscanchanlist + chanidx)->radiotype = radiotype;
+
+		scantype = puserscanin->chanlist[chanidx].scantype;
+
+		if (scantype == CMD_SCAN_TYPE_PASSIVE) {
+			(pscanchanlist +
+			 chanidx)->chanscanmode.passivescan = 1;
+		} else {
+			(pscanchanlist +
+			 chanidx)->chanscanmode.passivescan = 0;
+		}
+
+		if (puserscanin->chanlist[chanidx].scantime) {
+			scandur = puserscanin->chanlist[chanidx].scantime;
+		} else {
+			if (scantype == CMD_SCAN_TYPE_PASSIVE) {
+				scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME;
+			} else {
+				scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME;
+			}
+		}
+
+		(pscanchanlist + chanidx)->minscantime =
+		    cpu_to_le16(scandur);
+		(pscanchanlist + chanidx)->maxscantime =
+		    cpu_to_le16(scandur);
+	}
+
+	/* Check if we are only scanning the current channel */
+	if ((chanidx == 1) &&
+	    (puserscanin->chanlist[0].channumber ==
+			       priv->adapter->curbssparams.channel)) {
+		*pscancurrentonly = 1;
+		lbs_deb_scan("scanning current channel only");
 	}
 
 out:
@@ -531,6 +579,8 @@
 /**
  *  @brief Construct and send multiple scan config commands to the firmware
  *
+ *  Only used from wlan_scan_networks()
+ *
  *  Previous routines have created a wlan_scan_cmd_config with any requested
  *   TLVs.  This function splits the channel TLV into maxchanperscan lists
  *   and sends the portion of the channel TLV along with the other TLVs
@@ -568,12 +618,14 @@
 	int scanned = 0;
 	union iwreq_data wrqu;
 
-	lbs_deb_enter(LBS_DEB_ASSOC);
+	lbs_deb_enter_args(LBS_DEB_SCAN, "maxchanperscan %d, filteredscan %d, "
+		"full_scan %d", maxchanperscan, filteredscan, full_scan);
 
-	if (pscancfgout == 0 || pchantlvout == 0 || pscanchanlist == 0) {
-		lbs_deb_scan("Scan: Null detect: %p, %p, %p\n",
-		       pscancfgout, pchantlvout, pscanchanlist);
-		return -1;
+	if (!pscancfgout || !pchantlvout || !pscanchanlist) {
+		lbs_deb_scan("pscancfgout, pchantlvout or "
+			"pscanchanlist is NULL\n");
+		ret = -1;
+		goto out;
 	}
 
 	pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
@@ -605,12 +657,13 @@
 		while (tlvidx < maxchanperscan && ptmpchan->channumber
 		       && !doneearly && scanned < 2) {
 
-            lbs_deb_scan(
-                    "Scan: Chan(%3d), Radio(%d), mode(%d,%d), Dur(%d)\n",
-                ptmpchan->channumber, ptmpchan->radiotype,
-                ptmpchan->chanscanmode.passivescan,
-                ptmpchan->chanscanmode.disablechanfilt,
-                ptmpchan->maxscantime);
+			lbs_deb_scan("channel %d, radio %d, passive %d, "
+				"dischanflt %d, maxscantime %d\n",
+				ptmpchan->channumber,
+				ptmpchan->radiotype,
+			             ptmpchan->chanscanmode.passivescan,
+			             ptmpchan->chanscanmode.disablechanfilt,
+			             ptmpchan->maxscantime);
 
 			/* Copy the current channel TLV to the command being prepared */
 			memcpy(pchantlvout->chanscanparam + tlvidx,
@@ -667,7 +720,7 @@
 		}
 
 		/* Send the scan command to the firmware with the specified cfg */
-		ret = libertas_prepare_and_send_command(priv, cmd_802_11_scan, 0,
+		ret = libertas_prepare_and_send_command(priv, CMD_802_11_SCAN, 0,
 					    0, 0, pscancfgout);
 		if (scanned >= 2 && !full_scan) {
 			ret = 0;
@@ -679,24 +732,38 @@
 done:
 	priv->adapter->last_scanned_channel = ptmpchan->channumber;
 
-	/* Tell userspace the scan table has been updated */
-	memset(&wrqu, 0, sizeof(union iwreq_data));
-	wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
+	if (priv->adapter->last_scanned_channel) {
+		/* Schedule the next part of the partial scan */
+		if (!full_scan && !priv->adapter->surpriseremoved) {
+			cancel_delayed_work(&priv->scan_work);
+			queue_delayed_work(priv->work_thread, &priv->scan_work,
+			                   msecs_to_jiffies(300));
+		}
+	} else {
+		/* All done, tell userspace the scan table has been updated */
+		memset(&wrqu, 0, sizeof(union iwreq_data));
+		wireless_send_event(priv->dev, SIOCGIWSCAN, &wrqu, NULL);
+	}
 
+out:
 	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
 	return ret;
 }
 
-static void
-clear_selected_scan_list_entries(wlan_adapter * adapter,
-                                 const struct wlan_ioctl_user_scan_cfg * scan_cfg)
+/*
+ * Only used from wlan_scan_networks()
+*/
+static void clear_selected_scan_list_entries(wlan_adapter *adapter,
+	const struct wlan_ioctl_user_scan_cfg *scan_cfg)
 {
-	struct bss_descriptor * bss;
-	struct bss_descriptor * safe;
+	struct bss_descriptor *bss;
+	struct bss_descriptor *safe;
 	u32 clear_ssid_flag = 0, clear_bssid_flag = 0;
 
+	lbs_deb_enter(LBS_DEB_SCAN);
+
 	if (!scan_cfg)
-		return;
+		goto out;
 
 	if (scan_cfg->clear_ssid && scan_cfg->ssid_len)
 		clear_ssid_flag = 1;
@@ -708,7 +775,7 @@
 	}
 
 	if (!clear_ssid_flag && !clear_bssid_flag)
-		return;
+		goto out;
 
 	mutex_lock(&adapter->lock);
 	list_for_each_entry_safe (bss, safe, &adapter->network_list, list) {
@@ -731,12 +798,16 @@
 		}
 	}
 	mutex_unlock(&adapter->lock);
+out:
+	lbs_deb_leave(LBS_DEB_SCAN);
 }
 
 
 /**
  *  @brief Internal function used to start a scan based on an input config
  *
+ *  Also used from debugfs
+ *
  *  Use the input user scan configuration information when provided in
  *    order to send the appropriate scan commands to firmware to populate or
  *    update the internal driver scan table
@@ -744,12 +815,13 @@
  *  @param priv          A pointer to wlan_private structure
  *  @param puserscanin   Pointer to the input configuration for the requested
  *                       scan.
+ *  @param full_scan     ???
  *
  *  @return              0 or < 0 if error
  */
 int wlan_scan_networks(wlan_private * priv,
-			      const struct wlan_ioctl_user_scan_cfg * puserscanin,
-			      int full_scan)
+                       const struct wlan_ioctl_user_scan_cfg * puserscanin,
+                       int full_scan)
 {
 	wlan_adapter * adapter = priv->adapter;
 	struct mrvlietypes_chanlistparamset *pchantlvout;
@@ -762,9 +834,16 @@
 #ifdef CONFIG_LIBERTAS_DEBUG
 	struct bss_descriptor * iter_bss;
 	int i = 0;
+	DECLARE_MAC_BUF(mac);
 #endif
 
-	lbs_deb_enter(LBS_DEB_ASSOC);
+	lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan);
+
+	/* Cancel any partial outstanding partial scans if this scan
+	 * is a full scan.
+	 */
+	if (full_scan && delayed_work_pending(&priv->scan_work))
+		cancel_delayed_work(&priv->scan_work);
 
 	scan_chan_list = kzalloc(sizeof(struct chanscanparamset) *
 				WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL);
@@ -791,8 +870,10 @@
 	if (!scancurrentchanonly) {
 		netif_stop_queue(priv->dev);
 		netif_carrier_off(priv->dev);
-		netif_stop_queue(priv->mesh_dev);
-		netif_carrier_off(priv->mesh_dev);
+		if (priv->mesh_dev) {
+			netif_stop_queue(priv->mesh_dev);
+			netif_carrier_off(priv->mesh_dev);
+		}
 	}
 
 	ret = wlan_scan_channel_list(priv,
@@ -807,19 +888,22 @@
 #ifdef CONFIG_LIBERTAS_DEBUG
 	/* Dump the scan table */
 	mutex_lock(&adapter->lock);
+	lbs_deb_scan("The scan table contains:\n");
 	list_for_each_entry (iter_bss, &adapter->network_list, list) {
-		lbs_deb_scan("Scan:(%02d) " MAC_FMT ", RSSI[%03d], SSID[%s]\n",
-		       i++, MAC_ARG(iter_bss->bssid), (s32) iter_bss->rssi,
+		lbs_deb_scan("scan %02d, %s, RSSI, %d, SSID '%s'\n",
+		       i++, print_mac(mac, iter_bss->bssid), (s32) iter_bss->rssi,
 		       escape_essid(iter_bss->ssid, iter_bss->ssid_len));
 	}
 	mutex_unlock(&adapter->lock);
 #endif
 
-	if (priv->adapter->connect_status == libertas_connected) {
+	if (priv->adapter->connect_status == LIBERTAS_CONNECTED) {
 		netif_carrier_on(priv->dev);
 		netif_wake_queue(priv->dev);
-		netif_carrier_on(priv->mesh_dev);
-		netif_wake_queue(priv->mesh_dev);
+		if (priv->mesh_dev) {
+			netif_carrier_on(priv->mesh_dev);
+			netif_wake_queue(priv->mesh_dev);
+		}
 	}
 
 out:
@@ -834,58 +918,6 @@
 }
 
 /**
- *  @brief Inspect the scan response buffer for pointers to expected TLVs
- *
- *  TLVs can be included at the end of the scan response BSS information.
- *    Parse the data in the buffer for pointers to TLVs that can potentially
- *    be passed back in the response
- *
- *  @param ptlv        Pointer to the start of the TLV buffer to parse
- *  @param tlvbufsize  size of the TLV buffer
- *  @param ptsftlv     Output parameter: Pointer to the TSF TLV if found
- *
- *  @return            void
- */
-static
-void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv,
-				       int tlvbufsize,
-				       struct mrvlietypes_tsftimestamp ** ptsftlv)
-{
-	struct mrvlietypes_data *pcurrenttlv;
-	int tlvbufleft;
-	u16 tlvtype;
-	u16 tlvlen;
-
-	pcurrenttlv = ptlv;
-	tlvbufleft = tlvbufsize;
-	*ptsftlv = NULL;
-
-	lbs_deb_scan("SCAN_RESP: tlvbufsize = %d\n", tlvbufsize);
-	lbs_dbg_hex("SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize);
-
-	while (tlvbufleft >= sizeof(struct mrvlietypesheader)) {
-		tlvtype = le16_to_cpu(pcurrenttlv->header.type);
-		tlvlen = le16_to_cpu(pcurrenttlv->header.len);
-
-		switch (tlvtype) {
-		case TLV_TYPE_TSFTIMESTAMP:
-			*ptsftlv = (struct mrvlietypes_tsftimestamp *) pcurrenttlv;
-			break;
-
-		default:
-			lbs_deb_scan("SCAN_RESP: Unhandled TLV = %d\n",
-			       tlvtype);
-			/* Give up, this seems corrupted */
-			return;
-		}		/* switch */
-
-		tlvbufleft -= (sizeof(ptlv->header) + tlvlen);
-		pcurrenttlv =
-		    (struct mrvlietypes_data *) (pcurrenttlv->Data + tlvlen);
-	}			/* while */
-}
-
-/**
  *  @brief Interpret a BSS scan response returned from the firmware
  *
  *  Parse the various fixed fields and IEs passed back for a a BSS probe
@@ -899,67 +931,49 @@
 static int libertas_process_bss(struct bss_descriptor * bss,
 				u8 ** pbeaconinfo, int *bytesleft)
 {
-	enum ieeetypes_elementid elemID;
 	struct ieeetypes_fhparamset *pFH;
 	struct ieeetypes_dsparamset *pDS;
 	struct ieeetypes_cfparamset *pCF;
 	struct ieeetypes_ibssparamset *pibss;
-	struct ieeetypes_capinfo *pcap;
-	struct WLAN_802_11_FIXED_IEs fixedie;
-	u8 *pcurrentptr;
-	u8 *pRate;
-	u8 elemlen;
-	u8 bytestocopy;
-	u8 ratesize;
-	u16 beaconsize;
-	u8 founddatarateie;
-	int bytesleftforcurrentbeacon;
+	DECLARE_MAC_BUF(mac);
+	struct ieeetypes_countryinfoset *pcountryinfo;
+	u8 *pos, *end, *p;
+	u8 n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0;
+	u16 beaconsize = 0;
 	int ret;
 
-	struct IE_WPA *pIe;
-	const u8 oui01[4] = { 0x00, 0x50, 0xf2, 0x01 };
-
-	struct ieeetypes_countryinfoset *pcountryinfo;
-
-	lbs_deb_enter(LBS_DEB_ASSOC);
-
-	founddatarateie = 0;
-	ratesize = 0;
-	beaconsize = 0;
+	lbs_deb_enter(LBS_DEB_SCAN);
 
 	if (*bytesleft >= sizeof(beaconsize)) {
 		/* Extract & convert beacon size from the command buffer */
-		beaconsize = le16_to_cpup((void *)*pbeaconinfo);
+		beaconsize = le16_to_cpu(get_unaligned((u16 *)*pbeaconinfo));
 		*bytesleft -= sizeof(beaconsize);
 		*pbeaconinfo += sizeof(beaconsize);
 	}
 
 	if (beaconsize == 0 || beaconsize > *bytesleft) {
-
 		*pbeaconinfo += *bytesleft;
 		*bytesleft = 0;
-
-		return -1;
+		ret = -1;
+		goto done;
 	}
 
 	/* Initialize the current working beacon pointer for this BSS iteration */
-	pcurrentptr = *pbeaconinfo;
+	pos = *pbeaconinfo;
+	end = pos + beaconsize;
 
 	/* Advance the return beacon pointer past the current beacon */
 	*pbeaconinfo += beaconsize;
 	*bytesleft -= beaconsize;
 
-	bytesleftforcurrentbeacon = beaconsize;
+	memcpy(bss->bssid, pos, ETH_ALEN);
+	lbs_deb_scan("process_bss: AP BSSID %s\n", print_mac(mac, bss->bssid));
+	pos += ETH_ALEN;
 
-	memcpy(bss->bssid, pcurrentptr, ETH_ALEN);
-	lbs_deb_scan("process_bss: AP BSSID " MAC_FMT "\n", MAC_ARG(bss->bssid));
-
-	pcurrentptr += ETH_ALEN;
-	bytesleftforcurrentbeacon -= ETH_ALEN;
-
-	if (bytesleftforcurrentbeacon < 12) {
+	if ((end - pos) < 12) {
 		lbs_deb_scan("process_bss: Not enough bytes left\n");
-		return -1;
+		ret = -1;
+		goto done;
 	}
 
 	/*
@@ -968,85 +982,61 @@
 	 */
 
 	/* RSSI is 1 byte long */
-	bss->rssi = *pcurrentptr;
-	lbs_deb_scan("process_bss: RSSI=%02X\n", *pcurrentptr);
-	pcurrentptr += 1;
-	bytesleftforcurrentbeacon -= 1;
+	bss->rssi = *pos;
+	lbs_deb_scan("process_bss: RSSI=%02X\n", *pos);
+	pos++;
 
 	/* time stamp is 8 bytes long */
-	fixedie.timestamp = bss->timestamp = le64_to_cpup((void *)pcurrentptr);
-	pcurrentptr += 8;
-	bytesleftforcurrentbeacon -= 8;
+	pos += 8;
 
 	/* beacon interval is 2 bytes long */
-	fixedie.beaconinterval = bss->beaconperiod = le16_to_cpup((void *)pcurrentptr);
-	pcurrentptr += 2;
-	bytesleftforcurrentbeacon -= 2;
+	bss->beaconperiod = le16_to_cpup((void *) pos);
+	pos += 2;
 
 	/* capability information is 2 bytes long */
-        memcpy(&fixedie.capabilities, pcurrentptr, 2);
-	lbs_deb_scan("process_bss: fixedie.capabilities=0x%X\n",
-	       fixedie.capabilities);
-	pcap = (struct ieeetypes_capinfo *) & fixedie.capabilities;
-	memcpy(&bss->cap, pcap, sizeof(struct ieeetypes_capinfo));
-	pcurrentptr += 2;
-	bytesleftforcurrentbeacon -= 2;
+	bss->capability = le16_to_cpup((void *) pos);
+	lbs_deb_scan("process_bss: capabilities = 0x%4X\n", bss->capability);
+	pos += 2;
+
+	if (bss->capability & WLAN_CAPABILITY_PRIVACY)
+		lbs_deb_scan("process_bss: AP WEP enabled\n");
+	if (bss->capability & WLAN_CAPABILITY_IBSS)
+		bss->mode = IW_MODE_ADHOC;
+	else
+		bss->mode = IW_MODE_INFRA;
 
 	/* rest of the current buffer are IE's */
-	lbs_deb_scan("process_bss: IE length for this AP = %d\n",
-	       bytesleftforcurrentbeacon);
-
-	lbs_dbg_hex("process_bss: IE info", (u8 *) pcurrentptr,
-		bytesleftforcurrentbeacon);
-
-	if (pcap->privacy) {
-		lbs_deb_scan("process_bss: AP WEP enabled\n");
-		bss->privacy = wlan802_11privfilter8021xWEP;
-	} else {
-		bss->privacy = wlan802_11privfilteracceptall;
-	}
-
-	if (pcap->ibss == 1) {
-		bss->mode = IW_MODE_ADHOC;
-	} else {
-		bss->mode = IW_MODE_INFRA;
-	}
+	lbs_deb_scan("process_bss: IE length for this AP = %zd\n", end - pos);
+	lbs_deb_hex(LBS_DEB_SCAN, "process_bss: IE info", pos, end - pos);
 
 	/* process variable IE */
-	while (bytesleftforcurrentbeacon >= 2) {
-		elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr));
-		elemlen = *((u8 *) pcurrentptr + 1);
+	while (pos <= end - 2) {
+		struct ieee80211_info_element * elem =
+			(struct ieee80211_info_element *) pos;
 
-		if (bytesleftforcurrentbeacon < elemlen) {
+		if (pos + elem->len > end) {
 			lbs_deb_scan("process_bss: error in processing IE, "
 			       "bytes left < IE length\n");
-			bytesleftforcurrentbeacon = 0;
-			continue;
+			break;
 		}
 
-		switch (elemID) {
-		case SSID:
-			bss->ssid_len = elemlen;
-			memcpy(bss->ssid, (pcurrentptr + 2), elemlen);
+		switch (elem->id) {
+		case MFIE_TYPE_SSID:
+			bss->ssid_len = elem->len;
+			memcpy(bss->ssid, elem->data, elem->len);
 			lbs_deb_scan("ssid '%s', ssid length %u\n",
 			             escape_essid(bss->ssid, bss->ssid_len),
 			             bss->ssid_len);
 			break;
 
-		case SUPPORTED_RATES:
-			memcpy(bss->datarates, (pcurrentptr + 2), elemlen);
-			memmove(bss->libertas_supported_rates, (pcurrentptr + 2),
-				elemlen);
-			ratesize = elemlen;
-			founddatarateie = 1;
+		case MFIE_TYPE_RATES:
+			n_basic_rates = min_t(u8, MAX_RATES, elem->len);
+			memcpy(bss->rates, elem->data, n_basic_rates);
+			got_basic_rates = 1;
 			break;
 
-		case EXTRA_IE:
-			lbs_deb_scan("process_bss: EXTRA_IE Found!\n");
-			break;
-
-		case FH_PARAM_SET:
-			pFH = (struct ieeetypes_fhparamset *) pcurrentptr;
+		case MFIE_TYPE_FH_SET:
+			pFH = (struct ieeetypes_fhparamset *) pos;
 			memmove(&bss->phyparamset.fhparamset, pFH,
 				sizeof(struct ieeetypes_fhparamset));
 #if 0 /* I think we can store these LE */
@@ -1055,21 +1045,21 @@
 #endif
 			break;
 
-		case DS_PARAM_SET:
-			pDS = (struct ieeetypes_dsparamset *) pcurrentptr;
+		case MFIE_TYPE_DS_SET:
+			pDS = (struct ieeetypes_dsparamset *) pos;
 			bss->channel = pDS->currentchan;
 			memcpy(&bss->phyparamset.dsparamset, pDS,
 			       sizeof(struct ieeetypes_dsparamset));
 			break;
 
-		case CF_PARAM_SET:
-			pCF = (struct ieeetypes_cfparamset *) pcurrentptr;
+		case MFIE_TYPE_CF_SET:
+			pCF = (struct ieeetypes_cfparamset *) pos;
 			memcpy(&bss->ssparamset.cfparamset, pCF,
 			       sizeof(struct ieeetypes_cfparamset));
 			break;
 
-		case IBSS_PARAM_SET:
-			pibss = (struct ieeetypes_ibssparamset *) pcurrentptr;
+		case MFIE_TYPE_IBSS_SET:
+			pibss = (struct ieeetypes_ibssparamset *) pos;
 			bss->atimwindow = le32_to_cpu(pibss->atimwindow);
 			memmove(&bss->ssparamset.ibssparamset, pibss,
 				sizeof(struct ieeetypes_ibssparamset));
@@ -1079,9 +1069,8 @@
 #endif
 			break;
 
-			/* Handle Country Info IE */
-		case COUNTRY_INFO:
-			pcountryinfo = (struct ieeetypes_countryinfoset *) pcurrentptr;
+		case MFIE_TYPE_COUNTRY:
+			pcountryinfo = (struct ieeetypes_countryinfoset *) pos;
 			if (pcountryinfo->len < sizeof(pcountryinfo->countrycode)
 			    || pcountryinfo->len > 254) {
 				lbs_deb_scan("process_bss: 11D- Err "
@@ -1094,70 +1083,63 @@
 
 			memcpy(&bss->countryinfo,
 			       pcountryinfo, pcountryinfo->len + 2);
-			lbs_dbg_hex("process_bss: 11D- CountryInfo:",
+			lbs_deb_hex(LBS_DEB_SCAN, "process_bss: 11d countryinfo",
 				(u8 *) pcountryinfo,
 				(u32) (pcountryinfo->len + 2));
 			break;
 
-		case EXTENDED_SUPPORTED_RATES:
-			/*
-			 * only process extended supported rate
-			 * if data rate is already found.
-			 * data rate IE should come before
+		case MFIE_TYPE_RATES_EX:
+			/* only process extended supported rate if data rate is
+			 * already found. Data rate IE should come before
 			 * extended supported rate IE
 			 */
-			if (founddatarateie) {
-				if ((elemlen + ratesize) > WLAN_SUPPORTED_RATES) {
-					bytestocopy =
-					    (WLAN_SUPPORTED_RATES - ratesize);
-				} else {
-					bytestocopy = elemlen;
-				}
+			if (!got_basic_rates)
+				break;
 
-				pRate = (u8 *) bss->datarates;
-				pRate += ratesize;
-				memmove(pRate, (pcurrentptr + 2), bytestocopy);
-				pRate = (u8 *) bss->libertas_supported_rates;
-				pRate += ratesize;
-				memmove(pRate, (pcurrentptr + 2), bytestocopy);
+			n_ex_rates = elem->len;
+			if (n_basic_rates + n_ex_rates > MAX_RATES)
+				n_ex_rates = MAX_RATES - n_basic_rates;
+
+			p = bss->rates + n_basic_rates;
+			memcpy(p, elem->data, n_ex_rates);
+			break;
+
+		case MFIE_TYPE_GENERIC:
+			if (elem->len >= 4 &&
+			    elem->data[0] == 0x00 &&
+			    elem->data[1] == 0x50 &&
+			    elem->data[2] == 0xf2 &&
+			    elem->data[3] == 0x01) {
+				bss->wpa_ie_len = min(elem->len + 2,
+				                      MAX_WPA_IE_LEN);
+				memcpy(bss->wpa_ie, elem, bss->wpa_ie_len);
+				lbs_deb_hex(LBS_DEB_SCAN, "process_bss: WPA IE", bss->wpa_ie,
+				            elem->len);
+			} else if (elem->len >= MARVELL_MESH_IE_LENGTH &&
+			    elem->data[0] == 0x00 &&
+			    elem->data[1] == 0x50 &&
+			    elem->data[2] == 0x43 &&
+			    elem->data[3] == 0x04) {
+				bss->mesh = 1;
 			}
 			break;
 
-		case VENDOR_SPECIFIC_221:
-#define IE_ID_LEN_FIELDS_BYTES 2
-			pIe = (struct IE_WPA *)pcurrentptr;
-
-			if (memcmp(pIe->oui, oui01, sizeof(oui01)))
-				break;
-
-			bss->wpa_ie_len = min(elemlen + IE_ID_LEN_FIELDS_BYTES,
-				MAX_WPA_IE_LEN);
-			memcpy(bss->wpa_ie, pcurrentptr, bss->wpa_ie_len);
-			lbs_dbg_hex("process_bss: WPA IE", bss->wpa_ie, elemlen);
-			break;
-		case WPA2_IE:
-			pIe = (struct IE_WPA *)pcurrentptr;
-			bss->rsn_ie_len = min(elemlen + IE_ID_LEN_FIELDS_BYTES,
-				MAX_WPA_IE_LEN);
-			memcpy(bss->rsn_ie, pcurrentptr, bss->rsn_ie_len);
-			lbs_dbg_hex("process_bss: RSN_IE", bss->rsn_ie, elemlen);
-			break;
-		case TIM:
+		case MFIE_TYPE_RSN:
+			bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN);
+			memcpy(bss->rsn_ie, elem, bss->rsn_ie_len);
+			lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", bss->rsn_ie, elem->len);
 			break;
 
-		case CHALLENGE_TEXT:
+		default:
 			break;
 		}
 
-		pcurrentptr += elemlen + 2;
-
-		/* need to account for IE ID and IE len */
-		bytesleftforcurrentbeacon -= (elemlen + 2);
-
-	}			/* while (bytesleftforcurrentbeacon > 2) */
+		pos += elem->len + 2;
+	}
 
 	/* Timestamp */
 	bss->last_scanned = jiffies;
+	libertas_unset_basic_rate_flags(bss->rates, sizeof(bss->rates));
 
 	ret = 0;
 
@@ -1167,40 +1149,28 @@
 }
 
 /**
- *  @brief Compare two SSIDs
- *
- *  @param ssid1    A pointer to ssid to compare
- *  @param ssid2    A pointer to ssid to compare
- *
- *  @return         0--ssid is same, otherwise is different
- */
-int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len)
-{
-	if (ssid1_len != ssid2_len)
-		return -1;
-
-	return memcmp(ssid1, ssid2, ssid1_len);
-}
-
-/**
  *  @brief This function finds a specific compatible BSSID in the scan list
  *
+ *  Used in association code
+ *
  *  @param adapter  A pointer to wlan_adapter
  *  @param bssid    BSSID to find in the scan list
  *  @param mode     Network mode: Infrastructure or IBSS
  *
  *  @return         index in BSSID list, or error return code (< 0)
  */
-struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter,
+struct bss_descriptor *libertas_find_bssid_in_list(wlan_adapter * adapter,
 		u8 * bssid, u8 mode)
 {
 	struct bss_descriptor * iter_bss;
 	struct bss_descriptor * found_bss = NULL;
 
-	if (!bssid)
-		return NULL;
+	lbs_deb_enter(LBS_DEB_SCAN);
 
-	lbs_dbg_hex("libertas_find_BSSID_in_list: looking for ",
+	if (!bssid)
+		goto out;
+
+	lbs_deb_hex(LBS_DEB_SCAN, "looking for",
 		bssid, ETH_ALEN);
 
 	/* Look through the scan table for a compatible match.  The loop will
@@ -1225,12 +1195,16 @@
 	}
 	mutex_unlock(&adapter->lock);
 
+out:
+	lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
 	return found_bss;
 }
 
 /**
  *  @brief This function finds ssid in ssid list.
  *
+ *  Used in association code
+ *
  *  @param adapter  A pointer to wlan_adapter
  *  @param ssid     SSID to find in the list
  *  @param bssid    BSSID to qualify the SSID selection (if provided)
@@ -1247,6 +1221,8 @@
 	struct bss_descriptor * found_bss = NULL;
 	struct bss_descriptor * tmp_oldest = NULL;
 
+	lbs_deb_enter(LBS_DEB_SCAN);
+
 	mutex_lock(&adapter->lock);
 
 	list_for_each_entry (iter_bss, &adapter->network_list, list) {
@@ -1291,6 +1267,7 @@
 
 out:
 	mutex_unlock(&adapter->lock);
+	lbs_deb_leave_args(LBS_DEB_SCAN, "found_bss %p", found_bss);
 	return found_bss;
 }
 
@@ -1304,13 +1281,15 @@
  *
  *  @return         index in BSSID list
  */
-struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter,
+static struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter,
 		u8 mode)
 {
 	u8 bestrssi = 0;
 	struct bss_descriptor * iter_bss;
 	struct bss_descriptor * best_bss = NULL;
 
+	lbs_deb_enter(LBS_DEB_SCAN);
+
 	mutex_lock(&adapter->lock);
 
 	list_for_each_entry (iter_bss, &adapter->network_list, list) {
@@ -1335,12 +1314,15 @@
 	}
 
 	mutex_unlock(&adapter->lock);
+	lbs_deb_leave_args(LBS_DEB_SCAN, "best_bss %p", best_bss);
 	return best_bss;
 }
 
 /**
  *  @brief Find the AP with specific ssid in the scan list
  *
+ *  Used from association worker.
+ *
  *  @param priv         A pointer to wlan_private structure
  *  @param pSSID        A pointer to AP's ssid
  *
@@ -1353,11 +1335,11 @@
 	int ret = -1;
 	struct bss_descriptor * found;
 
-	lbs_deb_enter(LBS_DEB_ASSOC);
+	lbs_deb_enter(LBS_DEB_SCAN);
 
 	wlan_scan_networks(priv, NULL, 1);
 	if (adapter->surpriseremoved)
-		return -1;
+		goto out;
 
 	wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
 
@@ -1369,6 +1351,7 @@
 		ret = 0;
 	}
 
+out:
 	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
 	return ret;
 }
@@ -1391,7 +1374,10 @@
 
 	lbs_deb_enter(LBS_DEB_SCAN);
 
-	wlan_scan_networks(priv, NULL, 0);
+	if (!delayed_work_pending(&priv->scan_work)) {
+		queue_delayed_work(priv->work_thread, &priv->scan_work,
+		                   msecs_to_jiffies(50));
+	}
 
 	if (adapter->surpriseremoved)
 		return -1;
@@ -1400,10 +1386,17 @@
 	return 0;
 }
 
+
 /**
  *  @brief Send a scan command for all available channels filtered on a spec
  *
+ *  Used in association code and from debugfs
+ *
  *  @param priv             A pointer to wlan_private structure
+ *  @param ssid             A pointer to the SSID to scan for
+ *  @param ssid_len         Length of the SSID
+ *  @param clear_ssid       Should existing scan results with this SSID
+ *                          be cleared?
  *  @param prequestedssid   A pointer to AP's ssid
  *  @param keeppreviousscan Flag used to save/clear scan table before scan
  *
@@ -1416,7 +1409,8 @@
 	struct wlan_ioctl_user_scan_cfg scancfg;
 	int ret = 0;
 
-	lbs_deb_enter(LBS_DEB_ASSOC);
+	lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s', clear %d",
+		escape_essid(ssid, ssid_len), clear_ssid);
 
 	if (!ssid_len)
 		goto out;
@@ -1427,47 +1421,27 @@
 	scancfg.clear_ssid = clear_ssid;
 
 	wlan_scan_networks(priv, &scancfg, 1);
-	if (adapter->surpriseremoved)
-		return -1;
+	if (adapter->surpriseremoved) {
+		ret = -1;
+		goto out;
+	}
 	wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending);
 
 out:
-	lbs_deb_leave(LBS_DEB_ASSOC);
+	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret);
 	return ret;
 }
 
-/**
- *  @brief scan an AP with specific BSSID
- *
- *  @param priv             A pointer to wlan_private structure
- *  @param bssid            A pointer to AP's bssid
- *  @param keeppreviousscan Flag used to save/clear scan table before scan
- *
- *  @return          0-success, otherwise fail
- */
-int libertas_send_specific_bssid_scan(wlan_private * priv, u8 * bssid, u8 clear_bssid)
-{
-	struct wlan_ioctl_user_scan_cfg scancfg;
 
-	lbs_deb_enter(LBS_DEB_ASSOC);
 
-	if (bssid == NULL)
-		goto out;
 
-	memset(&scancfg, 0x00, sizeof(scancfg));
-	memcpy(scancfg.bssid, bssid, ETH_ALEN);
-	scancfg.clear_bssid = clear_bssid;
+/*********************************************************************/
+/*                                                                   */
+/*  Support for Wireless Extensions                                  */
+/*                                                                   */
+/*********************************************************************/
 
-	wlan_scan_networks(priv, &scancfg, 1);
-	if (priv->adapter->surpriseremoved)
-		return -1;
-	wait_event_interruptible(priv->adapter->cmd_pending,
-		!priv->adapter->nr_cmd_pending);
-
-out:
-	lbs_deb_leave(LBS_DEB_ASSOC);
-	return 0;
-}
+#define MAX_CUSTOM_LEN 64
 
 static inline char *libertas_translate_scan(wlan_private *priv,
 					char *start, char *stop,
@@ -1483,10 +1457,13 @@
 #define RSSI_DIFF    ((u8)(PERFECT_RSSI - WORST_RSSI))
 	u8 rssi;
 
+	lbs_deb_enter(LBS_DEB_SCAN);
+
 	cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, bss->channel);
 	if (!cfp) {
 		lbs_deb_scan("Invalid channel number %d\n", bss->channel);
-		return NULL;
+		start = NULL;
+		goto out;
 	}
 
 	/* First entry *MUST* be the AP BSSID */
@@ -1550,7 +1527,7 @@
 
 	/* Add encryption capability */
 	iwe.cmd = SIOCGIWENCODE;
-	if (bss->privacy) {
+	if (bss->capability & WLAN_CAPABILITY_PRIVACY) {
 		iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
 	} else {
 		iwe.u.data.flags = IW_ENCODE_DISABLED;
@@ -1565,12 +1542,9 @@
 	iwe.u.bitrate.disabled = 0;
 	iwe.u.bitrate.value = 0;
 
-	for (j = 0; j < sizeof(bss->libertas_supported_rates); j++) {
-		u8 rate = bss->libertas_supported_rates[j];
-		if (rate == 0)
-			break; /* no more rates */
-		/* Bit rate given in 500 kb/s units (+ 0x80) */
-		iwe.u.bitrate.value = (rate & 0x7f) * 500000;
+	for (j = 0; bss->rates[j] && (j < sizeof(bss->rates)); j++) {
+		/* Bit rate given in 500 kb/s units */
+		iwe.u.bitrate.value = bss->rates[j] * 500000;
 		current_val = iwe_stream_add_value(start, current_val,
 					 stop, &iwe, IW_EV_PARAM_LEN);
 	}
@@ -1605,11 +1579,25 @@
 		start = iwe_stream_add_point(start, stop, &iwe, buf);
 	}
 
+	if (bss->mesh) {
+		char custom[MAX_CUSTOM_LEN];
+		char *p = custom;
+
+		iwe.cmd = IWEVCUSTOM;
+		p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
+		              "mesh-type: olpc");
+		iwe.u.data.length = p - custom;
+		if (iwe.u.data.length)
+			start = iwe_stream_add_point(start, stop, &iwe, custom);
+	}
+
+out:
+	lbs_deb_leave_args(LBS_DEB_SCAN, "start %p", start);
 	return start;
 }
 
 /**
- *  @brief  Retrieve the scan table entries via wireless tools IOCTL call
+ *  @brief  Handle Retrieve scan table ioctl
  *
  *  @param dev          A pointer to net_device structure
  *  @param info         A pointer to iw_request_info structure
@@ -1630,16 +1618,12 @@
 	struct bss_descriptor * iter_bss;
 	struct bss_descriptor * safe;
 
-	lbs_deb_enter(LBS_DEB_ASSOC);
-
-	/* If we've got an uncompleted scan, schedule the next part */
-	if (!adapter->nr_cmd_pending && adapter->last_scanned_channel)
-		wlan_scan_networks(priv, NULL, 0);
+	lbs_deb_enter(LBS_DEB_SCAN);
 
 	/* Update RSSI if current BSS is a locally created ad-hoc BSS */
 	if ((adapter->mode == IW_MODE_ADHOC) && adapter->adhoccreate) {
-		libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
-					cmd_option_waitforrsp, 0, NULL);
+		libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
+					CMD_OPTION_WAITFORRSP, 0, NULL);
 	}
 
 	mutex_lock(&adapter->lock);
@@ -1652,6 +1636,10 @@
 			break;
 		}
 
+		/* For mesh device, list only mesh networks */
+		if (dev == priv->mesh_dev && !iter_bss->mesh)
+			continue;
+
 		/* Prune old an old scan result */
 		stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE;
 		if (time_after(jiffies, stale_time)) {
@@ -1672,19 +1660,27 @@
 	dwrq->length = (ev - extra);
 	dwrq->flags = 0;
 
-	lbs_deb_leave(LBS_DEB_ASSOC);
+	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", err);
 	return err;
 }
 
+
+
+
+/*********************************************************************/
+/*                                                                   */
+/*  Command execution                                                */
+/*                                                                   */
+/*********************************************************************/
+
+
 /**
  *  @brief Prepare a scan command to be sent to the firmware
  *
- *  Use the wlan_scan_cmd_config sent to the command processing module in
- *   the libertas_prepare_and_send_command to configure a cmd_ds_802_11_scan command
- *   struct to send to firmware.
+ *  Called from libertas_prepare_and_send_command() in cmd.c
  *
- *  The fixed fields specifying the BSS type and BSSID filters as well as a
- *   variable number/length of TLVs are sent in the command to firmware.
+ *  Sends a fixed lenght data part (specifying the BSS type and BSSID filters)
+ *  as well as a variable number/length of TLVs to the firmware.
  *
  *  @param priv       A pointer to wlan_private structure
  *  @param cmd        A pointer to cmd_ds_command structure to be sent to
@@ -1693,36 +1689,31 @@
  *                    to set the fields/TLVs for the command sent to firmware
  *
  *  @return           0 or -1
- *
- *  @sa wlan_scan_create_channel_list
  */
 int libertas_cmd_80211_scan(wlan_private * priv,
 			 struct cmd_ds_command *cmd, void *pdata_buf)
 {
 	struct cmd_ds_802_11_scan *pscan = &cmd->params.scan;
-	struct wlan_scan_cmd_config *pscancfg;
+	struct wlan_scan_cmd_config *pscancfg = pdata_buf;
 
-	lbs_deb_enter(LBS_DEB_ASSOC);
-
-	pscancfg = pdata_buf;
+	lbs_deb_enter(LBS_DEB_SCAN);
 
 	/* Set fixed field variables in scan command */
 	pscan->bsstype = pscancfg->bsstype;
-	memcpy(pscan->BSSID, pscancfg->bssid, sizeof(pscan->BSSID));
+	memcpy(pscan->bssid, pscancfg->bssid, ETH_ALEN);
 	memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen);
 
-	cmd->command = cpu_to_le16(cmd_802_11_scan);
+	cmd->command = cpu_to_le16(CMD_802_11_SCAN);
 
 	/* size is equal to the sizeof(fixed portions) + the TLV len + header */
-	cmd->size = cpu_to_le16(sizeof(pscan->bsstype)
-				     + sizeof(pscan->BSSID)
-				     + pscancfg->tlvbufferlen + S_DS_GEN);
+	cmd->size = cpu_to_le16(sizeof(pscan->bsstype) + ETH_ALEN
+				+ pscancfg->tlvbufferlen + S_DS_GEN);
 
-	lbs_deb_scan("SCAN_CMD: command=%x, size=%x, seqnum=%x\n",
+	lbs_deb_scan("SCAN_CMD: command 0x%04x, size %d, seqnum %d\n",
 		     le16_to_cpu(cmd->command), le16_to_cpu(cmd->size),
 		     le16_to_cpu(cmd->seqnum));
 
-	lbs_deb_leave(LBS_DEB_ASSOC);
+	lbs_deb_leave(LBS_DEB_SCAN);
 	return 0;
 }
 
@@ -1741,6 +1732,8 @@
 /**
  *  @brief This function handles the command response of scan
  *
+ *  Called from handle_cmd_response() in cmdrespc.
+ *
  *   The response buffer for the scan command has the following
  *      memory layout:
  *
@@ -1766,8 +1759,6 @@
 {
 	wlan_adapter *adapter = priv->adapter;
 	struct cmd_ds_802_11_scan_rsp *pscan;
-	struct mrvlietypes_data *ptlv;
-	struct mrvlietypes_tsftimestamp *ptsftlv;
 	struct bss_descriptor * iter_bss;
 	struct bss_descriptor * safe;
 	u8 *pbssinfo;
@@ -1777,7 +1768,7 @@
 	int tlvbufsize;
 	int ret;
 
-	lbs_deb_enter(LBS_DEB_ASSOC);
+	lbs_deb_enter(LBS_DEB_SCAN);
 
 	/* Prune old entries from scan table */
 	list_for_each_entry_safe (iter_bss, safe, &adapter->network_list, list) {
@@ -1798,10 +1789,10 @@
 		goto done;
 	}
 
-	bytesleft = le16_to_cpu(pscan->bssdescriptsize);
+	bytesleft = le16_to_cpu(get_unaligned((u16*)&pscan->bssdescriptsize));
 	lbs_deb_scan("SCAN_RESP: bssdescriptsize %d\n", bytesleft);
 
-	scanrespsize = le16_to_cpu(resp->size);
+	scanrespsize = le16_to_cpu(get_unaligned((u16*)&resp->size));
 	lbs_deb_scan("SCAN_RESP: returned %d AP before parsing\n",
 	       pscan->nr_sets);
 
@@ -1816,11 +1807,6 @@
 				     + sizeof(pscan->nr_sets)
 				     + S_DS_GEN);
 
-	ptlv = (struct mrvlietypes_data *) (pscan->bssdesc_and_tlvbuffer + bytesleft);
-
-	/* Search the TLV buffer space in the scan response for any valid TLVs */
-	wlan_ret_802_11_scan_get_tlv_ptrs(ptlv, tlvbufsize, &ptsftlv);
-
 	/*
 	 *  Process each scan response returned (pscan->nr_sets).  Save
 	 *    the information in the newbssentry and then insert into the
@@ -1831,6 +1817,7 @@
 		struct bss_descriptor new;
 		struct bss_descriptor * found = NULL;
 		struct bss_descriptor * oldest = NULL;
+		DECLARE_MAC_BUF(mac);
 
 		/* Process the data fields and IEs returned for this BSS */
 		memset(&new, 0, sizeof (struct bss_descriptor));
@@ -1869,19 +1856,8 @@
 			continue;
 		}
 
-		lbs_deb_scan("SCAN_RESP: BSSID = " MAC_FMT "\n",
-		       new.bssid[0], new.bssid[1], new.bssid[2],
-		       new.bssid[3], new.bssid[4], new.bssid[5]);
-
-		/*
-		 * If the TSF TLV was appended to the scan results, save the
-		 *   this entries TSF value in the networktsf field.  The
-		 *   networktsf is the firmware's TSF value at the time the
-		 *   beacon or probe response was received.
-		 */
-		if (ptsftlv) {
-			new.networktsf = le64_to_cpup(&ptsftlv->tsftable[idx]);
-		}
+		lbs_deb_scan("SCAN_RESP: BSSID = %s\n",
+			     print_mac(mac, new.bssid));
 
 		/* Copy the locally created newbssentry to the scan table */
 		memcpy(found, &new, offsetof(struct bss_descriptor, list));
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h
index bd019e5..c29c031 100644
--- a/drivers/net/wireless/libertas/scan.h
+++ b/drivers/net/wireless/libertas/scan.h
@@ -140,8 +140,7 @@
 	u8 ssid[IW_ESSID_MAX_SIZE + 1];
 	u8 ssid_len;
 
-	/* WEP encryption requirement */
-	u32 privacy;
+	u16 capability;
 
 	/* receive signal strength in dBm */
 	long rssi;
@@ -152,18 +151,16 @@
 
 	u32 atimwindow;
 
+	/* IW_MODE_AUTO, IW_MODE_ADHOC, IW_MODE_INFRA */
 	u8 mode;
-	u8 libertas_supported_rates[WLAN_SUPPORTED_RATES];
 
-	__le64 timestamp;	//!< TSF value included in the beacon/probe response
+	/* zero-terminated array of supported data rates */
+	u8 rates[MAX_RATES + 1];
+
 	unsigned long last_scanned;
 
 	union ieeetypes_phyparamset phyparamset;
 	union IEEEtypes_ssparamset ssparamset;
-	struct ieeetypes_capinfo cap;
-	u8 datarates[WLAN_SUPPORTED_RATES];
-
-	u64 networktsf;		//!< TSF timestamp from the current firmware TSF
 
 	struct ieeetypes_countryinfofullset countryinfo;
 
@@ -172,34 +169,31 @@
 	u8 rsn_ie[MAX_WPA_IE_LEN];
 	size_t rsn_ie_len;
 
+	u8 mesh;
+
 	struct list_head list;
 };
 
-extern int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
+int libertas_ssid_cmp(u8 *ssid1, u8 ssid1_len, u8 *ssid2, u8 ssid2_len);
 
 struct bss_descriptor * libertas_find_ssid_in_list(wlan_adapter * adapter,
 			u8 *ssid, u8 ssid_len, u8 * bssid, u8 mode,
 			int channel);
 
-struct bss_descriptor * libertas_find_best_ssid_in_list(wlan_adapter * adapter,
-			u8 mode);
-
-extern struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter,
+struct bss_descriptor * libertas_find_bssid_in_list(wlan_adapter * adapter,
 			u8 * bssid, u8 mode);
 
 int libertas_find_best_network_ssid(wlan_private * priv, u8 *out_ssid,
 			u8 *out_ssid_len, u8 preferred_mode, u8 *out_mode);
 
-extern int libertas_send_specific_ssid_scan(wlan_private * priv, u8 *ssid,
+int libertas_send_specific_ssid_scan(wlan_private * priv, u8 *ssid,
 				u8 ssid_len, u8 clear_ssid);
-extern int libertas_send_specific_bssid_scan(wlan_private * priv,
-				 u8 * bssid, u8 clear_bssid);
 
-extern int libertas_cmd_80211_scan(wlan_private * priv,
+int libertas_cmd_80211_scan(wlan_private * priv,
 				struct cmd_ds_command *cmd,
 				void *pdata_buf);
 
-extern int libertas_ret_80211_scan(wlan_private * priv,
+int libertas_ret_80211_scan(wlan_private * priv,
 				struct cmd_ds_command *resp);
 
 int wlan_scan_networks(wlan_private * priv,
@@ -211,9 +205,11 @@
 struct iw_point;
 struct iw_param;
 struct iw_request_info;
-extern int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
+int libertas_get_scan(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_point *dwrq, char *extra);
-extern int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
+int libertas_set_scan(struct net_device *dev, struct iw_request_info *info,
 			 struct iw_param *vwrq, char *extra);
 
+void libertas_scan_worker(struct work_struct *work);
+
 #endif				/* _WLAN_SCAN_H */
diff --git a/drivers/net/wireless/libertas/thread.h b/drivers/net/wireless/libertas/thread.h
deleted file mode 100644
index b1f34d9..0000000
--- a/drivers/net/wireless/libertas/thread.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef	__WLAN_THREAD_H_
-#define	__WLAN_THREAD_H_
-
-#include	<linux/kthread.h>
-
-struct wlan_thread {
-	struct task_struct *task;
-	wait_queue_head_t waitq;
-	pid_t pid;
-	void *priv;
-};
-
-static inline void wlan_activate_thread(struct wlan_thread * thr)
-{
-	/** Record the thread pid */
-	thr->pid = current->pid;
-
-	/** Initialize the wait queue */
-	init_waitqueue_head(&thr->waitq);
-}
-
-static inline void wlan_deactivate_thread(struct wlan_thread * thr)
-{
-	lbs_deb_enter(LBS_DEB_THREAD);
-
-	thr->pid = 0;
-
-	lbs_deb_leave(LBS_DEB_THREAD);
-}
-
-static inline void wlan_create_thread(int (*wlanfunc) (void *),
-				      struct wlan_thread * thr, char *name)
-{
-	thr->task = kthread_run(wlanfunc, thr, "%s", name);
-}
-
-static inline int wlan_terminate_thread(struct wlan_thread * thr)
-{
-	lbs_deb_enter(LBS_DEB_THREAD);
-
-	/* Check if the thread is active or not */
-	if (!thr->pid) {
-		printk(KERN_ERR "Thread does not exist\n");
-		return -1;
-	}
-	kthread_stop(thr->task);
-
-	lbs_deb_leave(LBS_DEB_THREAD);
-	return 0;
-}
-
-#endif
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index 17c4376..fbec06c 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -58,7 +58,6 @@
  */
 static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb)
 {
-	wlan_adapter *adapter = priv->adapter;
 	int ret = 0;
 	struct txpd localtxpd;
 	struct txpd *plocaltxpd = &localtxpd;
@@ -72,10 +71,6 @@
 	if (priv->adapter->surpriseremoved)
 		return -1;
 
-	if ((priv->adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
-		lbs_dbg_hex("TX packet: ", skb->data,
-			 min_t(unsigned int, skb->len, 100));
-
 	if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) {
 		lbs_deb_tx("tx err: skb length %d 0 or > %zd\n",
 		       skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
@@ -90,11 +85,8 @@
 	/* offset of actual data */
 	plocaltxpd->tx_packet_location = cpu_to_le32(sizeof(struct txpd));
 
-	/* TxCtrl set by user or default */
-	plocaltxpd->tx_control = cpu_to_le32(adapter->pkttxctrl);
-
 	p802x_hdr = skb->data;
-	if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+	if (priv->adapter->monitormode != WLAN_MONITOR_OFF) {
 
 		/* locate radiotap header */
 		pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data;
@@ -103,7 +95,6 @@
 		new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate);
 		if (new_rate != 0) {
 			/* use new tx_control[4:0] */
-			new_rate |= (adapter->pkttxctrl & ~0x1f);
 			plocaltxpd->tx_control = cpu_to_le32(new_rate);
 		}
 
@@ -115,12 +106,12 @@
 
 	}
 	/* copy destination address from 802.3 or 802.11 header */
-	if (priv->adapter->linkmode == WLAN_LINKMODE_802_11)
+	if (priv->adapter->monitormode != WLAN_MONITOR_OFF)
 		memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN);
 	else
 		memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN);
 
-	lbs_dbg_hex("txpd", (u8 *) plocaltxpd, sizeof(struct txpd));
+	lbs_deb_hex(LBS_DEB_TX, "txpd", (u8 *) plocaltxpd, sizeof(struct txpd));
 
 	if (IS_MESH_FRAME(skb)) {
 		plocaltxpd->tx_control |= cpu_to_le32(TxPD_MESH_FRAME);
@@ -130,7 +121,7 @@
 
 	ptr += sizeof(struct txpd);
 
-	lbs_dbg_hex("Tx Data", (u8 *) p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length));
+	lbs_deb_hex(LBS_DEB_TX, "Tx Data", (u8 *) p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length));
 	memcpy(ptr, p802x_hdr, le16_to_cpu(plocaltxpd->tx_packet_length));
 	ret = priv->hw_host_to_card(priv, MVMS_DAT,
 				    priv->adapter->tmptxbuf,
@@ -153,13 +144,14 @@
 		priv->stats.tx_errors++;
 	}
 
-	if (!ret && priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) {
+	if (!ret && priv->adapter->monitormode != WLAN_MONITOR_OFF) {
 		/* Keep the skb to echo it back once Tx feedback is
 		   received from FW */
 		skb_orphan(skb);
 		/* stop processing outgoing pkts */
 		netif_stop_queue(priv->dev);
-		netif_stop_queue(priv->mesh_dev);
+		if (priv->mesh_dev)
+			netif_stop_queue(priv->mesh_dev);
 		/* freeze any packets already in our queues */
 		priv->adapter->TxLockFlag = 1;
 	} else {
@@ -198,10 +190,12 @@
 	adapter->tx_queue_ps[adapter->tx_queue_idx++] = skb;
 	if (adapter->tx_queue_idx == NR_TX_QUEUE) {
 		netif_stop_queue(priv->dev);
-		netif_stop_queue(priv->mesh_dev);
+		if (priv->mesh_dev)
+			netif_stop_queue(priv->mesh_dev);
 	} else {
 		netif_start_queue(priv->dev);
-		netif_start_queue(priv->mesh_dev);
+		if (priv->mesh_dev)
+			netif_start_queue(priv->mesh_dev);
 	}
 
 	spin_unlock(&adapter->txqueue_lock);
@@ -219,7 +213,7 @@
 	int ret = -1;
 
 	lbs_deb_enter(LBS_DEB_TX);
-	lbs_dbg_hex("TX Data", skb->data, min_t(unsigned int, skb->len, 100));
+	lbs_deb_hex(LBS_DEB_TX, "TX Data", skb->data, min_t(unsigned int, skb->len, 100));
 
 	if (priv->dnld_sent) {
 		lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n",
@@ -258,16 +252,12 @@
 	int txfail;
 	int try_count;
 
-	if (adapter->radiomode != WLAN_RADIOMODE_RADIOTAP ||
+	if (adapter->monitormode == WLAN_MONITOR_OFF ||
 	    adapter->currenttxskb == NULL)
 		return;
 
 	radiotap_hdr = (struct tx_radiotap_hdr *)adapter->currenttxskb->data;
 
-	if ((adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0)
-		lbs_dbg_hex("TX feedback: ", (u8 *) radiotap_hdr,
-			min_t(unsigned int, adapter->currenttxskb->len, 100));
-
 	txfail = (status >> 24);
 
 #if 0
@@ -283,9 +273,10 @@
 	libertas_upload_rx_packet(priv, adapter->currenttxskb);
 	adapter->currenttxskb = NULL;
 	priv->adapter->TxLockFlag = 0;
-	if (priv->adapter->connect_status == libertas_connected) {
+	if (priv->adapter->connect_status == LIBERTAS_CONNECTED) {
 		netif_wake_queue(priv->dev);
-		netif_wake_queue(priv->mesh_dev);
+		if (priv->mesh_dev)
+			netif_wake_queue(priv->mesh_dev);
 	}
 }
 EXPORT_SYMBOL_GPL(libertas_send_tx_feedback);
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index 028e2f3..a43a5f6 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -7,71 +7,6 @@
 #include <linux/if_ether.h>
 #include <asm/byteorder.h>
 
-/** IEEE type definitions  */
-enum ieeetypes_elementid {
-	SSID = 0,
-	SUPPORTED_RATES,
-	FH_PARAM_SET,
-	DS_PARAM_SET,
-	CF_PARAM_SET,
-	TIM,
-	IBSS_PARAM_SET,
-	COUNTRY_INFO = 7,
-
-	CHALLENGE_TEXT = 16,
-
-	EXTENDED_SUPPORTED_RATES = 50,
-
-	VENDOR_SPECIFIC_221 = 221,
-
-	WPA_IE = 221,
-	WPA2_IE = 48,
-
-	EXTRA_IE = 133,
-} __attribute__ ((packed));
-
-#ifdef __BIG_ENDIAN
-#define CAPINFO_MASK	(~(0xda00))
-#else
-#define CAPINFO_MASK	(~(0x00da))
-#endif
-
-struct ieeetypes_capinfo {
-#ifdef __BIG_ENDIAN_BITFIELD
-	u8 chanagility:1;
-	u8 pbcc:1;
-	u8 shortpreamble:1;
-	u8 privacy:1;
-	u8 cfpollrqst:1;
-	u8 cfpollable:1;
-	u8 ibss:1;
-	u8 ess:1;
-	u8 rsrvd1:2;
-	u8 dsssofdm:1;
-	u8 rsvrd2:1;
-	u8 apsd:1;
-	u8 shortslottime:1;
-	u8 rsrvd3:1;
-	u8 spectrummgmt:1;
-#else
-	u8 ess:1;
-	u8 ibss:1;
-	u8 cfpollable:1;
-	u8 cfpollrqst:1;
-	u8 privacy:1;
-	u8 shortpreamble:1;
-	u8 pbcc:1;
-	u8 chanagility:1;
-	u8 spectrummgmt:1;
-	u8 rsrvd3:1;
-	u8 shortslottime:1;
-	u8 apsd:1;
-	u8 rsvrd2:1;
-	u8 dsssofdm:1;
-	u8 rsrvd1:2;
-#endif
-} __attribute__ ((packed));
-
 struct ieeetypes_cfparamset {
 	u8 elementid;
 	u8 len;
@@ -114,7 +49,7 @@
 } __attribute__ ((packed));
 
 struct ieeetypes_assocrsp {
-	struct ieeetypes_capinfo capability;
+	__le16 capability;
 	__le16 statuscode;
 	__le16 aid;
 	u8 iebuffer[1];
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 2fcc3bf..c6f5aa3 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -22,60 +22,6 @@
 
 
 /**
- * the rates supported by the card
- */
-static u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] =
-    { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12,
-      0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00
-};
-
-/**
- *  @brief Convert mw value to dbm value
- *
- *  @param mw	   the value of mw
- *  @return 	   the value of dbm
- */
-static int mw_to_dbm(int mw)
-{
-	if (mw < 2)
-		return 0;
-	else if (mw < 3)
-		return 3;
-	else if (mw < 4)
-		return 5;
-	else if (mw < 6)
-		return 7;
-	else if (mw < 7)
-		return 8;
-	else if (mw < 8)
-		return 9;
-	else if (mw < 10)
-		return 10;
-	else if (mw < 13)
-		return 11;
-	else if (mw < 16)
-		return 12;
-	else if (mw < 20)
-		return 13;
-	else if (mw < 25)
-		return 14;
-	else if (mw < 32)
-		return 15;
-	else if (mw < 40)
-		return 16;
-	else if (mw < 50)
-		return 17;
-	else if (mw < 63)
-		return 18;
-	else if (mw < 79)
-		return 19;
-	else if (mw < 100)
-		return 20;
-	else
-		return 21;
-}
-
-/**
  *  @brief Find the channel frequency power info with specific channel
  *
  *  @param adapter 	A pointer to wlan_adapter structure
@@ -165,7 +111,7 @@
  *  @option 			Radio Option
  *  @return 	   		0 --success, otherwise fail
  */
-int wlan_radio_ioctl(wlan_private * priv, u8 option)
+static int wlan_radio_ioctl(wlan_private * priv, u8 option)
 {
 	int ret = 0;
 	wlan_adapter *adapter = priv->adapter;
@@ -177,9 +123,9 @@
 		adapter->radioon = option;
 
 		ret = libertas_prepare_and_send_command(priv,
-					    cmd_802_11_radio_control,
-					    cmd_act_set,
-					    cmd_option_waitforrsp, 0, NULL);
+					    CMD_802_11_RADIO_CONTROL,
+					    CMD_ACT_SET,
+					    CMD_OPTION_WAITFORRSP, 0, NULL);
 	}
 
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
@@ -187,84 +133,31 @@
 }
 
 /**
- *  @brief Copy rates
- *
- *  @param dest                 A pointer to Dest Buf
- *  @param src		        A pointer to Src Buf
- *  @param len                  The len of Src Buf
- *  @return 	   	        Number of rates copyed
- */
-static inline int copyrates(u8 * dest, int pos, u8 * src, int len)
-{
-	int i;
-
-	for (i = 0; i < len && src[i]; i++, pos++) {
-		if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES)
-			break;
-		dest[pos] = src[i];
-	}
-
-	return pos;
-}
-
-/**
- *  @brief Get active data rates
+ *  @brief Copy active data rates based on adapter mode and status
  *
  *  @param adapter              A pointer to wlan_adapter structure
  *  @param rate		        The buf to return the active rates
- *  @return 	   	        The number of rates
  */
-static int get_active_data_rates(wlan_adapter * adapter,
-				 u8* rates)
+static void copy_active_data_rates(wlan_adapter * adapter, u8 * rates)
 {
-	int k = 0;
-
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	if (adapter->connect_status != libertas_connected) {
-		if (adapter->mode == IW_MODE_INFRA) {
-			lbs_deb_wext("infra\n");
-			k = copyrates(rates, k, libertas_supported_rates,
-				      sizeof(libertas_supported_rates));
-		} else {
-			lbs_deb_wext("Adhoc G\n");
-			k = copyrates(rates, k, libertas_adhoc_rates_g,
-				      sizeof(libertas_adhoc_rates_g));
-		}
-	} else {
-		k = copyrates(rates, 0, adapter->curbssparams.datarates,
-			      adapter->curbssparams.numofrates);
-	}
+	if (adapter->connect_status != LIBERTAS_CONNECTED)
+		memcpy(rates, libertas_bg_rates, MAX_RATES);
+	else
+		memcpy(rates, adapter->curbssparams.rates, MAX_RATES);
 
-	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", k);
-	return k;
+	lbs_deb_leave(LBS_DEB_WEXT);
 }
 
 static int wlan_get_name(struct net_device *dev, struct iw_request_info *info,
 			 char *cwrq, char *extra)
 {
-	const char *cp;
-	char comm[6] = { "COMM-" };
-	char mrvl[6] = { "MRVL-" };
-	int cnt;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	strcpy(cwrq, mrvl);
-
-	cp = strstr(libertas_driver_version, comm);
-	if (cp == libertas_driver_version)	//skip leading "COMM-"
-		cp = libertas_driver_version + strlen(comm);
-	else
-		cp = libertas_driver_version;
-
-	cnt = strlen(mrvl);
-	cwrq += cnt;
-	while (cnt < 16 && (*cp != '-')) {
-		*cwrq++ = toupper(*cp++);
-		cnt++;
-	}
-	*cwrq = '\0';
+	/* We could add support for 802.11n here as needed. Jean II */
+	snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g");
 
 	lbs_deb_leave(LBS_DEB_WEXT);
 	return 0;
@@ -305,7 +198,7 @@
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	if (adapter->connect_status == libertas_connected) {
+	if (adapter->connect_status == LIBERTAS_CONNECTED) {
 		memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN);
 	} else {
 		memset(awrq->sa_data, 0, ETH_ALEN);
@@ -349,24 +242,11 @@
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	/*
-	 * Get the Nick Name saved
-	 */
+	dwrq->length = strlen(adapter->nodename);
+	memcpy(extra, adapter->nodename, dwrq->length);
+	extra[dwrq->length] = '\0';
 
-	mutex_lock(&adapter->lock);
-	strncpy(extra, adapter->nodename, 16);
-	mutex_unlock(&adapter->lock);
-
-	extra[16] = '\0';
-
-	/*
-	 * If none, we may want to get the one that was set
-	 */
-
-	/*
-	 * Push it out !
-	 */
-	dwrq->length = strlen(extra) + 1;
+	dwrq->flags = 1;	/* active */
 
 	lbs_deb_leave(LBS_DEB_WEXT);
 	return 0;
@@ -382,20 +262,21 @@
 
 	/* Use nickname to indicate that mesh is on */
 
-	if (adapter->connect_status == libertas_connected) {
+	if (adapter->connect_status == LIBERTAS_CONNECTED) {
 		strncpy(extra, "Mesh", 12);
 		extra[12] = '\0';
-		dwrq->length = strlen(extra) + 1;
+		dwrq->length = strlen(extra);
 	}
 
 	else {
 		extra[0] = '\0';
-		dwrq->length = 1 ;
+		dwrq->length = 0;
 	}
 
 	lbs_deb_leave(LBS_DEB_WEXT);
 	return 0;
 }
+
 static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info,
 			struct iw_param *vwrq, char *extra)
 {
@@ -414,8 +295,8 @@
 		adapter->rtsthsd = rthr;
 	}
 
-	ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
-				    cmd_act_set, cmd_option_waitforrsp,
+	ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
+				    CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
 				    OID_802_11_RTS_THRESHOLD, &rthr);
 
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
@@ -432,8 +313,8 @@
 	lbs_deb_enter(LBS_DEB_WEXT);
 
 	adapter->rtsthsd = 0;
-	ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
-				    cmd_act_get, cmd_option_waitforrsp,
+	ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
+				    CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
 				    OID_802_11_RTS_THRESHOLD, NULL);
 	if (ret)
 		goto out;
@@ -467,8 +348,8 @@
 		adapter->fragthsd = fthr;
 	}
 
-	ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
-				    cmd_act_set, cmd_option_waitforrsp,
+	ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
+				    CMD_ACT_SET, CMD_OPTION_WAITFORRSP,
 				    OID_802_11_FRAGMENTATION_THRESHOLD, &fthr);
 
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
@@ -486,8 +367,8 @@
 
 	adapter->fragthsd = 0;
 	ret = libertas_prepare_and_send_command(priv,
-				    cmd_802_11_snmp_mib,
-				    cmd_act_get, cmd_option_waitforrsp,
+				    CMD_802_11_SNMP_MIB,
+				    CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
 				    OID_802_11_FRAGMENTATION_THRESHOLD, NULL);
 	if (ret)
 		goto out;
@@ -539,9 +420,9 @@
 	lbs_deb_enter(LBS_DEB_WEXT);
 
 	ret = libertas_prepare_and_send_command(priv,
-				    cmd_802_11_rf_tx_power,
-				    cmd_act_tx_power_opt_get,
-				    cmd_option_waitforrsp, 0, NULL);
+				    CMD_802_11_RF_TX_POWER,
+				    CMD_ACT_TX_POWER_OPT_GET,
+				    CMD_OPTION_WAITFORRSP, 0, NULL);
 
 	if (ret)
 		goto out;
@@ -581,9 +462,9 @@
 		/* Adding 1 to convert retry count to try count */
 		adapter->txretrycount = vwrq->value + 1;
 
-		ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib,
-					    cmd_act_set,
-					    cmd_option_waitforrsp,
+		ret = libertas_prepare_and_send_command(priv, CMD_802_11_SNMP_MIB,
+					    CMD_ACT_SET,
+					    CMD_OPTION_WAITFORRSP,
 					    OID_802_11_TX_RETRYCOUNT, NULL);
 
 		if (ret)
@@ -608,8 +489,8 @@
 
 	adapter->txretrycount = 0;
 	ret = libertas_prepare_and_send_command(priv,
-				    cmd_802_11_snmp_mib,
-				    cmd_act_get, cmd_option_waitforrsp,
+				    CMD_802_11_SNMP_MIB,
+				    CMD_ACT_GET, CMD_OPTION_WAITFORRSP,
 				    OID_802_11_TX_RETRYCOUNT, NULL);
 	if (ret)
 		goto out;
@@ -673,7 +554,7 @@
 	wlan_adapter *adapter = priv->adapter;
 	struct iw_range *range = (struct iw_range *)extra;
 	struct chan_freq_power *cfp;
-	u8 rates[WLAN_SUPPORTED_RATES];
+	u8 rates[MAX_RATES + 1];
 
 	u8 flag = 0;
 
@@ -686,19 +567,17 @@
 	range->max_nwid = 0;
 
 	memset(rates, 0, sizeof(rates));
-	range->num_bitrates = get_active_data_rates(adapter, rates);
-
-	for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i];
-	     i++) {
-		range->bitrate[i] = (rates[i] & 0x7f) * 500000;
-	}
+	copy_active_data_rates(adapter, rates);
+	range->num_bitrates = strnlen(rates, IW_MAX_BITRATES);
+	for (i = 0; i < range->num_bitrates; i++)
+		range->bitrate[i] = rates[i] * 500000;
 	range->num_bitrates = i;
 	lbs_deb_wext("IW_MAX_BITRATES %d, num_bitrates %d\n", IW_MAX_BITRATES,
 	       range->num_bitrates);
 
 	range->num_frequency = 0;
 	if (priv->adapter->enable11d &&
-	    adapter->connect_status == libertas_connected) {
+	    adapter->connect_status == LIBERTAS_CONNECTED) {
 		u8 chan_no;
 		u8 band;
 
@@ -858,9 +737,9 @@
 	 */
 
 	if (vwrq->disabled) {
-		adapter->psmode = wlan802_11powermodecam;
+		adapter->psmode = WLAN802_11POWERMODECAM;
 		if (adapter->psstate != PS_STATE_FULL_POWER) {
-			libertas_ps_wakeup(priv, cmd_option_waitforrsp);
+			libertas_ps_wakeup(priv, CMD_OPTION_WAITFORRSP);
 		}
 
 		return 0;
@@ -875,14 +754,14 @@
 		return -EINVAL;
 	}
 
-	if (adapter->psmode != wlan802_11powermodecam) {
+	if (adapter->psmode != WLAN802_11POWERMODECAM) {
 		return 0;
 	}
 
-	adapter->psmode = wlan802_11powermodemax_psp;
+	adapter->psmode = WLAN802_11POWERMODEMAX_PSP;
 
-	if (adapter->connect_status == libertas_connected) {
-		libertas_ps_sleep(priv, cmd_option_waitforrsp);
+	if (adapter->connect_status == LIBERTAS_CONNECTED) {
+		libertas_ps_sleep(priv, CMD_OPTION_WAITFORRSP);
 	}
 
 	lbs_deb_leave(LBS_DEB_WEXT);
@@ -900,8 +779,8 @@
 
 	mode = adapter->psmode;
 
-	if ((vwrq->disabled = (mode == wlan802_11powermodecam))
-	    || adapter->connect_status == libertas_disconnected)
+	if ((vwrq->disabled = (mode == WLAN802_11POWERMODECAM))
+	    || adapter->connect_status == LIBERTAS_DISCONNECTED)
 	{
 		goto out;
 	}
@@ -937,7 +816,7 @@
 	priv->wstats.status = adapter->mode;
 
 	/* If we're not associated, all quality values are meaningless */
-	if (adapter->connect_status != libertas_connected)
+	if (adapter->connect_status != LIBERTAS_CONNECTED)
 		goto out;
 
 	/* Quality by RSSI */
@@ -973,7 +852,7 @@
 	/* Quality by TX errors */
 	priv->wstats.discard.retries = priv->stats.tx_errors;
 
-	tx_retries = le16_to_cpu(adapter->logmsg.retry);
+	tx_retries = le32_to_cpu(adapter->logmsg.retry);
 
 	if (tx_retries > 75)
 		tx_qual = (90 - tx_retries) * POOR / 15;
@@ -989,20 +868,20 @@
 		    (PERFECT - VERY_GOOD) / 50 + VERY_GOOD;
 	quality = min(quality, tx_qual);
 
-	priv->wstats.discard.code = le16_to_cpu(adapter->logmsg.wepundecryptable);
-	priv->wstats.discard.fragment = le16_to_cpu(adapter->logmsg.rxfrag);
+	priv->wstats.discard.code = le32_to_cpu(adapter->logmsg.wepundecryptable);
+	priv->wstats.discard.fragment = le32_to_cpu(adapter->logmsg.rxfrag);
 	priv->wstats.discard.retries = tx_retries;
-	priv->wstats.discard.misc = le16_to_cpu(adapter->logmsg.ackfailure);
+	priv->wstats.discard.misc = le32_to_cpu(adapter->logmsg.ackfailure);
 
 	/* Calculate quality */
-	priv->wstats.qual.qual = max(quality, (u32)100);
+	priv->wstats.qual.qual = min_t(u8, quality, 100);
 	priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
 	stats_valid = 1;
 
 	/* update stats asynchronously for future calls */
-	libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0,
+	libertas_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
 					0, 0, NULL);
-	libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0,
+	libertas_prepare_and_send_command(priv, CMD_802_11_GET_LOG, 0,
 					0, 0, NULL);
 out:
 	if (!stats_valid) {
@@ -1080,88 +959,46 @@
 	return ret;
 }
 
-/**
- *  @brief use index to get the data rate
- *
- *  @param index                The index of data rate
- *  @return 	   		data rate or 0
- */
-u32 libertas_index_to_data_rate(u8 index)
-{
-	if (index >= sizeof(libertas_wlan_data_rates))
-		index = 0;
-
-	return libertas_wlan_data_rates[index];
-}
-
-/**
- *  @brief use rate to get the index
- *
- *  @param rate                 data rate
- *  @return 	   		index or 0
- */
-u8 libertas_data_rate_to_index(u32 rate)
-{
-	u8 *ptr;
-
-	if (rate)
-		if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate,
-				  sizeof(libertas_wlan_data_rates))))
-			return (ptr - libertas_wlan_data_rates);
-
-	return 0;
-}
-
 static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info,
 		  struct iw_param *vwrq, char *extra)
 {
 	wlan_private *priv = dev->priv;
 	wlan_adapter *adapter = priv->adapter;
-	u32 data_rate;
+	u32 new_rate;
 	u16 action;
-	int ret = 0;
-	u8 rates[WLAN_SUPPORTED_RATES];
-	u8 *rate;
+	int ret = -EINVAL;
+	u8 rates[MAX_RATES + 1];
 
 	lbs_deb_enter(LBS_DEB_WEXT);
-
 	lbs_deb_wext("vwrq->value %d\n", vwrq->value);
 
+	/* Auto rate? */
 	if (vwrq->value == -1) {
-		action = cmd_act_set_tx_auto;	// Auto
-		adapter->is_datarate_auto = 1;
-		adapter->datarate = 0;
+		action = CMD_ACT_SET_TX_AUTO;
+		adapter->auto_rate = 1;
+		adapter->cur_rate = 0;
 	} else {
-		if (vwrq->value % 100000) {
-			return -EINVAL;
-		}
-
-		data_rate = vwrq->value / 500000;
+		if (vwrq->value % 100000)
+			goto out;
 
 		memset(rates, 0, sizeof(rates));
-		get_active_data_rates(adapter, rates);
-		rate = rates;
-		while (*rate) {
-			lbs_deb_wext("rate=0x%X, wanted data_rate 0x%X\n", *rate,
-			       data_rate);
-			if ((*rate & 0x7f) == (data_rate & 0x7f))
-				break;
-			rate++;
-		}
-		if (!*rate) {
-			lbs_pr_alert("fixed data rate 0x%X out "
-			       "of range\n", data_rate);
-			return -EINVAL;
+		copy_active_data_rates(adapter, rates);
+		new_rate = vwrq->value / 500000;
+		if (!memchr(rates, new_rate, sizeof(rates))) {
+			lbs_pr_alert("fixed data rate 0x%X out of range\n",
+				new_rate);
+			goto out;
 		}
 
-		adapter->datarate = data_rate;
-		action = cmd_act_set_tx_fix_rate;
-		adapter->is_datarate_auto = 0;
+		adapter->cur_rate = new_rate;
+		action = CMD_ACT_SET_TX_FIX_RATE;
+		adapter->auto_rate = 0;
 	}
 
-	ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate,
-				    action, cmd_option_waitforrsp, 0, NULL);
+	ret = libertas_prepare_and_send_command(priv, CMD_802_11_DATA_RATE,
+				    action, CMD_OPTION_WAITFORRSP, 0, NULL);
 
+out:
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
 	return ret;
 }
@@ -1174,13 +1011,18 @@
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	if (adapter->is_datarate_auto) {
-		vwrq->fixed = 0;
-	} else {
-		vwrq->fixed = 1;
-	}
+	if (adapter->connect_status == LIBERTAS_CONNECTED) {
+		vwrq->value = adapter->cur_rate * 500000;
 
-	vwrq->value = adapter->datarate * 500000;
+		if (adapter->auto_rate)
+			vwrq->fixed = 0;
+		else
+			vwrq->fixed = 1;
+
+	} else {
+		vwrq->fixed = 0;
+		vwrq->value = 0;
+	}
 
 	lbs_deb_leave(LBS_DEB_WEXT);
 	return 0;
@@ -1298,7 +1140,7 @@
 
 	dwrq->flags |= IW_ENCODE_NOKEY;
 
-	lbs_deb_wext("key: " MAC_FMT ", keylen %d\n",
+	lbs_deb_wext("key: %02x:%02x:%02x:%02x:%02x:%02x, keylen %d\n",
 	       extra[0], extra[1], extra[2],
 	       extra[3], extra[4], extra[5], dwrq->length);
 
@@ -1325,7 +1167,7 @@
 			    int set_tx_key)
 {
 	int ret = 0;
-	struct WLAN_802_11_KEY *pkey;
+	struct enc_key *pkey;
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -1344,7 +1186,7 @@
 	pkey = &assoc_req->wep_keys[index];
 
 	if (key_length > 0) {
-		memset(pkey, 0, sizeof(struct WLAN_802_11_KEY));
+		memset(pkey, 0, sizeof(struct enc_key));
 		pkey->type = KEY_TYPE_ID_WEP;
 
 		/* Standardize the key length */
@@ -1412,11 +1254,11 @@
 {
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct WLAN_802_11_KEY));
+	memset(&assoc_req->wpa_mcast_key, 0, sizeof (struct enc_key));
 	assoc_req->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST;
 	set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags);
 
-	memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct WLAN_802_11_KEY));
+	memset(&assoc_req->wpa_unicast_key, 0, sizeof (struct enc_key));
 	assoc_req->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST;
 	set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
 
@@ -1567,7 +1409,7 @@
 		           && (adapter->secinfo.WPAenabled ||
 		               adapter->secinfo.WPA2enabled)) {
 			/* WPA */
-			struct WLAN_802_11_KEY * pkey = NULL;
+			struct enc_key * pkey = NULL;
 
 			if (   adapter->wpa_mcast_key.len
 			    && (adapter->wpa_mcast_key.flags & KEY_INFO_WPA_ENABLED))
@@ -1679,7 +1521,7 @@
 		if (set_tx_key)
 			set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags);
 	} else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) {
-		struct WLAN_802_11_KEY * pkey;
+		struct enc_key * pkey;
 
 		/* validate key length */
 		if (((alg == IW_ENCODE_ALG_TKIP)
@@ -1702,7 +1544,7 @@
 			set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags);
 		}
 
-		memset(pkey, 0, sizeof (struct WLAN_802_11_KEY));
+		memset(pkey, 0, sizeof (struct enc_key));
 		memcpy(pkey->key, ext->key, ext->key_len);
 		pkey->len = ext->key_len;
 		if (pkey->len)
@@ -1976,12 +1818,14 @@
 		return 0;
 	}
 
-	adapter->preamble = cmd_type_auto_preamble;
+	adapter->preamble = CMD_TYPE_AUTO_PREAMBLE;
 
 	wlan_radio_ioctl(priv, RADIO_ON);
 
+	/* Userspace check in iwrange if it should use dBm or mW,
+	 * therefore this should never happen... Jean II */
 	if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) {
-		dbm = (u16) mw_to_dbm(vwrq->value);
+		return -EOPNOTSUPP;
 	} else
 		dbm = (u16) vwrq->value;
 
@@ -1993,9 +1837,9 @@
 	lbs_deb_wext("txpower set %d dbm\n", dbm);
 
 	ret = libertas_prepare_and_send_command(priv,
-				    cmd_802_11_rf_tx_power,
-				    cmd_act_tx_power_opt_set_low,
-				    cmd_option_waitforrsp, 0, (void *)&dbm);
+				    CMD_802_11_RF_TX_POWER,
+				    CMD_ACT_TX_POWER_OPT_SET_LOW,
+				    CMD_OPTION_WAITFORRSP, 0, (void *)&dbm);
 
 	lbs_deb_leave_args(LBS_DEB_WEXT, "ret %d", ret);
 	return ret;
@@ -2017,7 +1861,7 @@
 	/*
 	 * Get the current SSID
 	 */
-	if (adapter->connect_status == libertas_connected) {
+	if (adapter->connect_status == LIBERTAS_CONNECTED) {
 		memcpy(extra, adapter->curbssparams.ssid,
 		       adapter->curbssparams.ssid_len);
 		extra[adapter->curbssparams.ssid_len] = '\0';
@@ -2029,12 +1873,7 @@
 	 * If none, we may want to get the one that was set
 	 */
 
-	/* To make the driver backward compatible with WPA supplicant v0.2.4 */
-	if (dwrq->length == 32)	/* check with WPA supplicant buffer size */
-		dwrq->length = min_t(size_t, adapter->curbssparams.ssid_len,
-				   IW_ESSID_MAX_SIZE);
-	else
-		dwrq->length = adapter->curbssparams.ssid_len + 1;
+	dwrq->length = adapter->curbssparams.ssid_len;
 
 	dwrq->flags = 1;	/* active */
 
@@ -2055,14 +1894,6 @@
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
-	/*
-	 * WE-20 and earlier NULL pad the end of the SSID and increment
-	 * SSID length so it can be used like a string.  WE-21 and later don't,
-	 * but some userspace tools aren't able to cope with the change.
-	 */
-	if ((in_ssid_len > 0) && (extra[in_ssid_len - 1] == '\0'))
-		in_ssid_len--;
-
 	/* Check the size of the string */
 	if (in_ssid_len > IW_ESSID_MAX_SIZE) {
 		ret = -E2BIG;
@@ -2129,13 +1960,14 @@
 	wlan_adapter *adapter = priv->adapter;
 	struct assoc_request * assoc_req;
 	int ret = 0;
+	DECLARE_MAC_BUF(mac);
 
 	lbs_deb_enter(LBS_DEB_WEXT);
 
 	if (awrq->sa_family != ARPHRD_ETHER)
 		return -EINVAL;
 
-	lbs_deb_wext("ASSOC: WAP: sa_data " MAC_FMT "\n", MAC_ARG(awrq->sa_data));
+	lbs_deb_wext("ASSOC: WAP: sa_data %s\n", print_mac(mac, awrq->sa_data));
 
 	mutex_lock(&adapter->lock);
 
@@ -2298,13 +2130,13 @@
 	(iw_handler) NULL,		/* SIOCSIWPMKSA */
 };
 struct iw_handler_def libertas_handler_def = {
-	.num_standard	= sizeof(wlan_handler) / sizeof(iw_handler),
+	.num_standard	= ARRAY_SIZE(wlan_handler),
 	.standard	= (iw_handler *) wlan_handler,
 	.get_wireless_stats = wlan_get_wireless_stats,
 };
 
 struct iw_handler_def mesh_handler_def = {
-	.num_standard	= sizeof(mesh_wlan_handler) / sizeof(iw_handler),
+	.num_standard	= ARRAY_SIZE(mesh_wlan_handler),
 	.standard	= (iw_handler *) mesh_wlan_handler,
 	.get_wireless_stats = wlan_get_wireless_stats,
 };
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h
index 3d5196c..6aa444c 100644
--- a/drivers/net/wireless/libertas/wext.h
+++ b/drivers/net/wireless/libertas/wext.h
@@ -4,9 +4,6 @@
 #ifndef	_WLAN_WEXT_H_
 #define	_WLAN_WEXT_H_
 
-#define SUBCMD_OFFSET			4
-#define SUBCMD_DATA(x)			*((int *)(x->u.name + SUBCMD_OFFSET))
-
 /** wlan_ioctl_regrdwr */
 struct wlan_ioctl_regrdwr {
 	/** Which register to access */
@@ -18,13 +15,9 @@
 	u32 value;
 };
 
-#define WLAN_LINKMODE_802_3			0
-#define WLAN_LINKMODE_802_11			2
-#define WLAN_RADIOMODE_NONE			0
-#define WLAN_RADIOMODE_RADIOTAP			2
+#define WLAN_MONITOR_OFF			0
 
 extern struct iw_handler_def libertas_handler_def;
 extern struct iw_handler_def mesh_handler_def;
-int wlan_radio_ioctl(wlan_private * priv, u8 option);
 
 #endif				/* _WLAN_WEXT_H_ */
diff --git a/drivers/net/wireless/net2280.h b/drivers/net/wireless/net2280.h
new file mode 100644
index 0000000..120eb83
--- /dev/null
+++ b/drivers/net/wireless/net2280.h
@@ -0,0 +1,452 @@
+#ifndef NET2280_H
+#define NET2280_H
+/*
+ * NetChip 2280 high/full speed USB device controller.
+ * Unlike many such controllers, this one talks PCI.
+ */
+
+/*
+ * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com)
+ * Copyright (C) 2003 David Brownell
+ *
+ * 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
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* NET2280 MEMORY MAPPED REGISTERS
+ *
+ * The register layout came from the chip documentation, and the bit
+ * number definitions were extracted from chip specification.
+ *
+ * Use the shift operator ('<<') to build bit masks, with readl/writel
+ * to access the registers through PCI.
+ */
+
+/* main registers, BAR0 + 0x0000 */
+struct net2280_regs {
+	// offset 0x0000
+	__le32                  devinit;
+#define     LOCAL_CLOCK_FREQUENCY                               8
+#define     FORCE_PCI_RESET                                     7
+#define     PCI_ID                                              6
+#define     PCI_ENABLE                                          5
+#define     FIFO_SOFT_RESET                                     4
+#define     CFG_SOFT_RESET                                      3
+#define     PCI_SOFT_RESET                                      2
+#define     USB_SOFT_RESET                                      1
+#define     M8051_RESET                                         0
+	__le32                  eectl;
+#define     EEPROM_ADDRESS_WIDTH                                23
+#define     EEPROM_CHIP_SELECT_ACTIVE                           22
+#define     EEPROM_PRESENT                                      21
+#define     EEPROM_VALID                                        20
+#define     EEPROM_BUSY                                         19
+#define     EEPROM_CHIP_SELECT_ENABLE                           18
+#define     EEPROM_BYTE_READ_START                              17
+#define     EEPROM_BYTE_WRITE_START                             16
+#define     EEPROM_READ_DATA                                    8
+#define     EEPROM_WRITE_DATA                                   0
+	__le32                  eeclkfreq;
+	u32                     _unused0;
+	// offset 0x0010
+
+	__le32                  pciirqenb0;	/* interrupt PCI master ... */
+#define     SETUP_PACKET_INTERRUPT_ENABLE                       7
+#define     ENDPOINT_F_INTERRUPT_ENABLE                         6
+#define     ENDPOINT_E_INTERRUPT_ENABLE                         5
+#define     ENDPOINT_D_INTERRUPT_ENABLE                         4
+#define     ENDPOINT_C_INTERRUPT_ENABLE                         3
+#define     ENDPOINT_B_INTERRUPT_ENABLE                         2
+#define     ENDPOINT_A_INTERRUPT_ENABLE                         1
+#define     ENDPOINT_0_INTERRUPT_ENABLE                         0
+	__le32                  pciirqenb1;
+#define     PCI_INTERRUPT_ENABLE                                31
+#define     POWER_STATE_CHANGE_INTERRUPT_ENABLE                 27
+#define     PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE                26
+#define     PCI_PARITY_ERROR_INTERRUPT_ENABLE                   25
+#define     PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE          20
+#define     PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE          19
+#define     PCI_TARGET_ABORT_ASSERTED_INTERRUPT_ENABLE          18
+#define     PCI_RETRY_ABORT_INTERRUPT_ENABLE                    17
+#define     PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE              16
+#define     GPIO_INTERRUPT_ENABLE                               13
+#define     DMA_D_INTERRUPT_ENABLE                              12
+#define     DMA_C_INTERRUPT_ENABLE                              11
+#define     DMA_B_INTERRUPT_ENABLE                              10
+#define     DMA_A_INTERRUPT_ENABLE                              9
+#define     EEPROM_DONE_INTERRUPT_ENABLE                        8
+#define     VBUS_INTERRUPT_ENABLE                               7
+#define     CONTROL_STATUS_INTERRUPT_ENABLE                     6
+#define     ROOT_PORT_RESET_INTERRUPT_ENABLE                    4
+#define     SUSPEND_REQUEST_INTERRUPT_ENABLE                    3
+#define     SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE             2
+#define     RESUME_INTERRUPT_ENABLE                             1
+#define     SOF_INTERRUPT_ENABLE                                0
+	__le32                  cpu_irqenb0;	/* ... or onboard 8051 */
+#define     SETUP_PACKET_INTERRUPT_ENABLE                       7
+#define     ENDPOINT_F_INTERRUPT_ENABLE                         6
+#define     ENDPOINT_E_INTERRUPT_ENABLE                         5
+#define     ENDPOINT_D_INTERRUPT_ENABLE                         4
+#define     ENDPOINT_C_INTERRUPT_ENABLE                         3
+#define     ENDPOINT_B_INTERRUPT_ENABLE                         2
+#define     ENDPOINT_A_INTERRUPT_ENABLE                         1
+#define     ENDPOINT_0_INTERRUPT_ENABLE                         0
+	__le32                  cpu_irqenb1;
+#define     CPU_INTERRUPT_ENABLE                                31
+#define     POWER_STATE_CHANGE_INTERRUPT_ENABLE                 27
+#define     PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE                26
+#define     PCI_PARITY_ERROR_INTERRUPT_ENABLE                   25
+#define     PCI_INTA_INTERRUPT_ENABLE                           24
+#define     PCI_PME_INTERRUPT_ENABLE                            23
+#define     PCI_SERR_INTERRUPT_ENABLE                           22
+#define     PCI_PERR_INTERRUPT_ENABLE                           21
+#define     PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE          20
+#define     PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE          19
+#define     PCI_RETRY_ABORT_INTERRUPT_ENABLE                    17
+#define     PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE              16
+#define     GPIO_INTERRUPT_ENABLE                               13
+#define     DMA_D_INTERRUPT_ENABLE                              12
+#define     DMA_C_INTERRUPT_ENABLE                              11
+#define     DMA_B_INTERRUPT_ENABLE                              10
+#define     DMA_A_INTERRUPT_ENABLE                              9
+#define     EEPROM_DONE_INTERRUPT_ENABLE                        8
+#define     VBUS_INTERRUPT_ENABLE                               7
+#define     CONTROL_STATUS_INTERRUPT_ENABLE                     6
+#define     ROOT_PORT_RESET_INTERRUPT_ENABLE                    4
+#define     SUSPEND_REQUEST_INTERRUPT_ENABLE                    3
+#define     SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE             2
+#define     RESUME_INTERRUPT_ENABLE                             1
+#define     SOF_INTERRUPT_ENABLE                                0
+
+	// offset 0x0020
+	u32                     _unused1;
+	__le32                  usbirqenb1;
+#define     USB_INTERRUPT_ENABLE                                31
+#define     POWER_STATE_CHANGE_INTERRUPT_ENABLE                 27
+#define     PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE                26
+#define     PCI_PARITY_ERROR_INTERRUPT_ENABLE                   25
+#define     PCI_INTA_INTERRUPT_ENABLE                           24
+#define     PCI_PME_INTERRUPT_ENABLE                            23
+#define     PCI_SERR_INTERRUPT_ENABLE                           22
+#define     PCI_PERR_INTERRUPT_ENABLE                           21
+#define     PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE          20
+#define     PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE          19
+#define     PCI_RETRY_ABORT_INTERRUPT_ENABLE                    17
+#define     PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE              16
+#define     GPIO_INTERRUPT_ENABLE                               13
+#define     DMA_D_INTERRUPT_ENABLE                              12
+#define     DMA_C_INTERRUPT_ENABLE                              11
+#define     DMA_B_INTERRUPT_ENABLE                              10
+#define     DMA_A_INTERRUPT_ENABLE                              9
+#define     EEPROM_DONE_INTERRUPT_ENABLE                        8
+#define     VBUS_INTERRUPT_ENABLE                               7
+#define     CONTROL_STATUS_INTERRUPT_ENABLE                     6
+#define     ROOT_PORT_RESET_INTERRUPT_ENABLE                    4
+#define     SUSPEND_REQUEST_INTERRUPT_ENABLE                    3
+#define     SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE             2
+#define     RESUME_INTERRUPT_ENABLE                             1
+#define     SOF_INTERRUPT_ENABLE                                0
+	__le32                  irqstat0;
+#define     INTA_ASSERTED                                       12
+#define     SETUP_PACKET_INTERRUPT                              7
+#define     ENDPOINT_F_INTERRUPT                                6
+#define     ENDPOINT_E_INTERRUPT                                5
+#define     ENDPOINT_D_INTERRUPT                                4
+#define     ENDPOINT_C_INTERRUPT                                3
+#define     ENDPOINT_B_INTERRUPT                                2
+#define     ENDPOINT_A_INTERRUPT                                1
+#define     ENDPOINT_0_INTERRUPT                                0
+	__le32                  irqstat1;
+#define     POWER_STATE_CHANGE_INTERRUPT                        27
+#define     PCI_ARBITER_TIMEOUT_INTERRUPT                       26
+#define     PCI_PARITY_ERROR_INTERRUPT                          25
+#define     PCI_INTA_INTERRUPT                                  24
+#define     PCI_PME_INTERRUPT                                   23
+#define     PCI_SERR_INTERRUPT                                  22
+#define     PCI_PERR_INTERRUPT                                  21
+#define     PCI_MASTER_ABORT_RECEIVED_INTERRUPT                 20
+#define     PCI_TARGET_ABORT_RECEIVED_INTERRUPT                 19
+#define     PCI_RETRY_ABORT_INTERRUPT                           17
+#define     PCI_MASTER_CYCLE_DONE_INTERRUPT                     16
+#define     GPIO_INTERRUPT                                      13
+#define     DMA_D_INTERRUPT                                     12
+#define     DMA_C_INTERRUPT                                     11
+#define     DMA_B_INTERRUPT                                     10
+#define     DMA_A_INTERRUPT                                     9
+#define     EEPROM_DONE_INTERRUPT                               8
+#define     VBUS_INTERRUPT                                      7
+#define     CONTROL_STATUS_INTERRUPT                            6
+#define     ROOT_PORT_RESET_INTERRUPT                           4
+#define     SUSPEND_REQUEST_INTERRUPT                           3
+#define     SUSPEND_REQUEST_CHANGE_INTERRUPT                    2
+#define     RESUME_INTERRUPT                                    1
+#define     SOF_INTERRUPT                                       0
+	// offset 0x0030
+	__le32                  idxaddr;
+	__le32                  idxdata;
+	__le32                  fifoctl;
+#define     PCI_BASE2_RANGE                                     16
+#define     IGNORE_FIFO_AVAILABILITY                            3
+#define     PCI_BASE2_SELECT                                    2
+#define     FIFO_CONFIGURATION_SELECT                           0
+	u32                     _unused2;
+	// offset 0x0040
+	__le32                  memaddr;
+#define     START                                               28
+#define     DIRECTION                                           27
+#define     FIFO_DIAGNOSTIC_SELECT                              24
+#define     MEMORY_ADDRESS                                      0
+	__le32                  memdata0;
+	__le32                  memdata1;
+	u32                     _unused3;
+	// offset 0x0050
+	__le32                  gpioctl;
+#define     GPIO3_LED_SELECT                                    12
+#define     GPIO3_INTERRUPT_ENABLE                              11
+#define     GPIO2_INTERRUPT_ENABLE                              10
+#define     GPIO1_INTERRUPT_ENABLE                              9
+#define     GPIO0_INTERRUPT_ENABLE                              8
+#define     GPIO3_OUTPUT_ENABLE                                 7
+#define     GPIO2_OUTPUT_ENABLE                                 6
+#define     GPIO1_OUTPUT_ENABLE                                 5
+#define     GPIO0_OUTPUT_ENABLE                                 4
+#define     GPIO3_DATA                                          3
+#define     GPIO2_DATA                                          2
+#define     GPIO1_DATA                                          1
+#define     GPIO0_DATA                                          0
+	__le32                  gpiostat;
+#define     GPIO3_INTERRUPT                                     3
+#define     GPIO2_INTERRUPT                                     2
+#define     GPIO1_INTERRUPT                                     1
+#define     GPIO0_INTERRUPT                                     0
+} __attribute__ ((packed));
+
+/* usb control, BAR0 + 0x0080 */
+struct net2280_usb_regs {
+	// offset 0x0080
+	__le32                  stdrsp;
+#define     STALL_UNSUPPORTED_REQUESTS                          31
+#define     SET_TEST_MODE                                       16
+#define     GET_OTHER_SPEED_CONFIGURATION                       15
+#define     GET_DEVICE_QUALIFIER                                14
+#define     SET_ADDRESS                                         13
+#define     ENDPOINT_SET_CLEAR_HALT                             12
+#define     DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP               11
+#define     GET_STRING_DESCRIPTOR_2                             10
+#define     GET_STRING_DESCRIPTOR_1                             9
+#define     GET_STRING_DESCRIPTOR_0                             8
+#define     GET_SET_INTERFACE                                   6
+#define     GET_SET_CONFIGURATION                               5
+#define     GET_CONFIGURATION_DESCRIPTOR                        4
+#define     GET_DEVICE_DESCRIPTOR                               3
+#define     GET_ENDPOINT_STATUS                                 2
+#define     GET_INTERFACE_STATUS                                1
+#define     GET_DEVICE_STATUS                                   0
+	__le32                  prodvendid;
+#define     PRODUCT_ID                                          16
+#define     VENDOR_ID                                           0
+	__le32                  relnum;
+	__le32                  usbctl;
+#define     SERIAL_NUMBER_INDEX                                 16
+#define     PRODUCT_ID_STRING_ENABLE                            13
+#define     VENDOR_ID_STRING_ENABLE                             12
+#define     USB_ROOT_PORT_WAKEUP_ENABLE                         11
+#define     VBUS_PIN                                            10
+#define     TIMED_DISCONNECT                                    9
+#define     SUSPEND_IMMEDIATELY                                 7
+#define     SELF_POWERED_USB_DEVICE                             6
+#define     REMOTE_WAKEUP_SUPPORT                               5
+#define     PME_POLARITY                                        4
+#define     USB_DETECT_ENABLE                                   3
+#define     PME_WAKEUP_ENABLE                                   2
+#define     DEVICE_REMOTE_WAKEUP_ENABLE                         1
+#define     SELF_POWERED_STATUS                                 0
+	// offset 0x0090
+	__le32                  usbstat;
+#define     HIGH_SPEED                                          7
+#define     FULL_SPEED                                          6
+#define     GENERATE_RESUME                                     5
+#define     GENERATE_DEVICE_REMOTE_WAKEUP                       4
+	__le32                  xcvrdiag;
+#define     FORCE_HIGH_SPEED_MODE                               31
+#define     FORCE_FULL_SPEED_MODE                               30
+#define     USB_TEST_MODE                                       24
+#define     LINE_STATE                                          16
+#define     TRANSCEIVER_OPERATION_MODE                          2
+#define     TRANSCEIVER_SELECT                                  1
+#define     TERMINATION_SELECT                                  0
+	__le32                  setup0123;
+	__le32                  setup4567;
+	// offset 0x0090
+	u32                     _unused0;
+	__le32                  ouraddr;
+#define     FORCE_IMMEDIATE                                     7
+#define     OUR_USB_ADDRESS                                     0
+	__le32                  ourconfig;
+} __attribute__ ((packed));
+
+/* pci control, BAR0 + 0x0100 */
+struct net2280_pci_regs {
+	// offset 0x0100
+	__le32                  pcimstctl;
+#define     PCI_ARBITER_PARK_SELECT                             13
+#define     PCI_MULTI LEVEL_ARBITER                             12
+#define     PCI_RETRY_ABORT_ENABLE                              11
+#define     DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE              10
+#define     DMA_READ_MULTIPLE_ENABLE                            9
+#define     DMA_READ_LINE_ENABLE                                8
+#define     PCI_MASTER_COMMAND_SELECT                           6
+#define         MEM_READ_OR_WRITE                                   0
+#define         IO_READ_OR_WRITE                                    1
+#define         CFG_READ_OR_WRITE                                   2
+#define     PCI_MASTER_START                                    5
+#define     PCI_MASTER_READ_WRITE                               4
+#define         PCI_MASTER_WRITE                                    0
+#define         PCI_MASTER_READ                                     1
+#define     PCI_MASTER_BYTE_WRITE_ENABLES                       0
+	__le32                  pcimstaddr;
+	__le32                  pcimstdata;
+	__le32                  pcimststat;
+#define     PCI_ARBITER_CLEAR                                   2
+#define     PCI_EXTERNAL_ARBITER                                1
+#define     PCI_HOST_MODE                                       0
+} __attribute__ ((packed));
+
+/* dma control, BAR0 + 0x0180 ... array of four structs like this,
+ * for channels 0..3.  see also struct net2280_dma:  descriptor
+ * that can be loaded into some of these registers.
+ */
+struct net2280_dma_regs {	/* [11.7] */
+	// offset 0x0180, 0x01a0, 0x01c0, 0x01e0,
+	__le32                  dmactl;
+#define     DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE            25
+#define     DMA_CLEAR_COUNT_ENABLE                              21
+#define     DESCRIPTOR_POLLING_RATE                             19
+#define         POLL_CONTINUOUS                                     0
+#define         POLL_1_USEC                                         1
+#define         POLL_100_USEC                                       2
+#define         POLL_1_MSEC                                         3
+#define     DMA_VALID_BIT_POLLING_ENABLE                        18
+#define     DMA_VALID_BIT_ENABLE                                17
+#define     DMA_SCATTER_GATHER_ENABLE                           16
+#define     DMA_OUT_AUTO_START_ENABLE                           4
+#define     DMA_PREEMPT_ENABLE                                  3
+#define     DMA_FIFO_VALIDATE                                   2
+#define     DMA_ENABLE                                          1
+#define     DMA_ADDRESS_HOLD                                    0
+	__le32                  dmastat;
+#define     DMA_SCATTER_GATHER_DONE_INTERRUPT                   25
+#define     DMA_TRANSACTION_DONE_INTERRUPT                      24
+#define     DMA_ABORT                                           1
+#define     DMA_START                                           0
+	u32                     _unused0[2];
+	// offset 0x0190, 0x01b0, 0x01d0, 0x01f0,
+	__le32                  dmacount;
+#define     VALID_BIT                                           31
+#define     DMA_DIRECTION                                       30
+#define     DMA_DONE_INTERRUPT_ENABLE                           29
+#define     END_OF_CHAIN                                        28
+#define         DMA_BYTE_COUNT_MASK                                 ((1<<24)-1)
+#define     DMA_BYTE_COUNT                                      0
+	__le32                  dmaaddr;
+	__le32                  dmadesc;
+	u32                     _unused1;
+} __attribute__ ((packed));
+
+/* dedicated endpoint registers, BAR0 + 0x0200 */
+
+struct net2280_dep_regs {	/* [11.8] */
+	// offset 0x0200, 0x0210, 0x220, 0x230, 0x240
+	__le32                  dep_cfg;
+	// offset 0x0204, 0x0214, 0x224, 0x234, 0x244
+	__le32                  dep_rsp;
+	u32                     _unused[2];
+} __attribute__ ((packed));
+
+/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs
+ * like this, for ep0 then the configurable endpoints A..F
+ * ep0 reserved for control; E and F have only 64 bytes of fifo
+ */
+struct net2280_ep_regs {	/* [11.9] */
+	// offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0
+	__le32                  ep_cfg;
+#define     ENDPOINT_BYTE_COUNT                                 16
+#define     ENDPOINT_ENABLE                                     10
+#define     ENDPOINT_TYPE                                       8
+#define     ENDPOINT_DIRECTION                                  7
+#define     ENDPOINT_NUMBER                                     0
+	__le32                  ep_rsp;
+#define     SET_NAK_OUT_PACKETS                                 15
+#define     SET_EP_HIDE_STATUS_PHASE                            14
+#define     SET_EP_FORCE_CRC_ERROR                              13
+#define     SET_INTERRUPT_MODE                                  12
+#define     SET_CONTROL_STATUS_PHASE_HANDSHAKE                  11
+#define     SET_NAK_OUT_PACKETS_MODE                            10
+#define     SET_ENDPOINT_TOGGLE                                 9
+#define     SET_ENDPOINT_HALT                                   8
+#define     CLEAR_NAK_OUT_PACKETS                               7
+#define     CLEAR_EP_HIDE_STATUS_PHASE                          6
+#define     CLEAR_EP_FORCE_CRC_ERROR                            5
+#define     CLEAR_INTERRUPT_MODE                                4
+#define     CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE                3
+#define     CLEAR_NAK_OUT_PACKETS_MODE                          2
+#define     CLEAR_ENDPOINT_TOGGLE                               1
+#define     CLEAR_ENDPOINT_HALT                                 0
+	__le32                  ep_irqenb;
+#define     SHORT_PACKET_OUT_DONE_INTERRUPT_ENABLE              6
+#define     SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE           5
+#define     DATA_PACKET_RECEIVED_INTERRUPT_ENABLE               3
+#define     DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE            2
+#define     DATA_OUT_PING_TOKEN_INTERRUPT_ENABLE                1
+#define     DATA_IN_TOKEN_INTERRUPT_ENABLE                      0
+	__le32                  ep_stat;
+#define     FIFO_VALID_COUNT                                    24
+#define     HIGH_BANDWIDTH_OUT_TRANSACTION_PID                  22
+#define     TIMEOUT                                             21
+#define     USB_STALL_SENT                                      20
+#define     USB_IN_NAK_SENT                                     19
+#define     USB_IN_ACK_RCVD                                     18
+#define     USB_OUT_PING_NAK_SENT                               17
+#define     USB_OUT_ACK_SENT                                    16
+#define     FIFO_OVERFLOW                                       13
+#define     FIFO_UNDERFLOW                                      12
+#define     FIFO_FULL                                           11
+#define     FIFO_EMPTY                                          10
+#define     FIFO_FLUSH                                          9
+#define     SHORT_PACKET_OUT_DONE_INTERRUPT                     6
+#define     SHORT_PACKET_TRANSFERRED_INTERRUPT                  5
+#define     NAK_OUT_PACKETS                                     4
+#define     DATA_PACKET_RECEIVED_INTERRUPT                      3
+#define     DATA_PACKET_TRANSMITTED_INTERRUPT                   2
+#define     DATA_OUT_PING_TOKEN_INTERRUPT                       1
+#define     DATA_IN_TOKEN_INTERRUPT                             0
+	// offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0
+	__le32                  ep_avail;
+	__le32                  ep_data;
+	u32                     _unused0[2];
+} __attribute__ ((packed));
+
+struct net2280_reg_write {
+	__le16 port;
+	__le32 addr;
+	__le32 val;
+} __attribute__ ((packed));
+
+struct net2280_reg_read {
+	__le16 port;
+	__le32 addr;
+} __attribute__ ((packed));
+#endif /* NET2280_H */
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index 45b00e1..c2d71af 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -412,7 +412,6 @@
     spin_lock_init(&priv->spinlock);
 
     /* Netwave specific entries in the device structure */
-    SET_MODULE_OWNER(dev);
     dev->hard_start_xmit = &netwave_start_xmit;
     dev->get_stats  = &netwave_get_stats;
     dev->set_multicast_list = &set_multicast_list;
@@ -710,9 +709,9 @@
 
 static const struct iw_handler_def	netwave_handler_def =
 {
-	.num_standard	= sizeof(netwave_handler)/sizeof(iw_handler),
-	.num_private	= sizeof(netwave_private_handler)/sizeof(iw_handler),
-	.num_private_args = sizeof(netwave_private_args)/sizeof(struct iw_priv_args),
+	.num_standard	= ARRAY_SIZE(netwave_handler),
+	.num_private	= ARRAY_SIZE(netwave_private_handler),
+	.num_private_args = ARRAY_SIZE(netwave_private_args),
 	.standard	= (iw_handler *) netwave_handler,
 	.private	= (iw_handler *) netwave_private_handler,
 	.private_args	= (struct iw_priv_args *) netwave_private_args,
@@ -738,6 +737,7 @@
     win_req_t req;
     memreq_t mem;
     u_char __iomem *ramBase = NULL;
+    DECLARE_MAC_BUF(mac);
 
     DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link);
 
@@ -806,12 +806,13 @@
     for (i = 0; i < 6; i++) 
 	dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i);
 
-    printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx id "
-	   "%c%c, hw_addr ", dev->name, dev->base_addr, dev->irq,
-	   (u_long) ramBase, (int) readb(ramBase+NETWAVE_EREG_NI),
-	   (int) readb(ramBase+NETWAVE_EREG_NI+1));
-    for (i = 0; i < 6; i++)
-	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+    printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx"
+	   "id %c%c, hw_addr %s\n",
+	   dev->name, dev->base_addr, dev->irq,
+	   (u_long) ramBase,
+	   (int) readb(ramBase+NETWAVE_EREG_NI),
+	   (int) readb(ramBase+NETWAVE_EREG_NI+1),
+	   print_mac(mac, dev->dev_addr));
 
     /* get revision words */
     printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n", 
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 062286d..ca6c2da 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -2232,6 +2232,7 @@
 	struct hermes_idstring nickbuf;
 	u16 reclen;
 	int len;
+	DECLARE_MAC_BUF(mac);
 
 	/* No need to lock, the hw_unavailable flag is already set in
 	 * alloc_orinocodev() */
@@ -2274,10 +2275,8 @@
 		goto out;
 	}
 
-	printk(KERN_DEBUG "%s: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n",
-	       dev->name, dev->dev_addr[0], dev->dev_addr[1],
-	       dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4],
-	       dev->dev_addr[5]);
+	printk(KERN_DEBUG "%s: MAC address %s\n",
+	       dev->name, print_mac(mac, dev->dev_addr));
 
 	/* Get the station name */
 	err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index d1e5022..8b7f576 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -313,7 +313,6 @@
 	/* Ok, we have the configuration, prepare to register the netdev */
 	dev->base_addr = link->io.BasePort1;
 	dev->irq = link->irq.AssignedIRQ;
-	SET_MODULE_OWNER(dev);
 	card->node.major = card->node.minor = 0;
 
 	SET_NETDEV_DEV(dev, &handle_to_dev(link));
diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c
index eaf3d13..35ec5fc 100644
--- a/drivers/net/wireless/orinoco_nortel.c
+++ b/drivers/net/wireless/orinoco_nortel.c
@@ -193,7 +193,6 @@
 	card = priv->card;
 	card->bridge_io = bridge_io;
 	card->attr_io = attr_io;
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c
index 97a8b4f..2547d5d 100644
--- a/drivers/net/wireless/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco_pci.c
@@ -148,7 +148,6 @@
 
 	priv = netdev_priv(dev);
 	card = priv->card;
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c
index 31162ac..98fe165 100644
--- a/drivers/net/wireless/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco_plx.c
@@ -232,7 +232,6 @@
 	card = priv->card;
 	card->bridge_io = bridge_io;
 	card->attr_io = attr_io;
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c
index 7c7b960..df493185 100644
--- a/drivers/net/wireless/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco_tmd.c
@@ -134,7 +134,6 @@
 	priv = netdev_priv(dev);
 	card = priv->card;
 	card->bridge_io = bridge_io;
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
@@ -190,7 +189,7 @@
 static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev)
 {
 	struct net_device *dev = pci_get_drvdata(pdev);
-	struct orinoco_private *priv = dev->priv;
+	struct orinoco_private *priv = netdev_priv(dev);
 	struct orinoco_pci_card *card = priv->card;
 
 	unregister_netdev(dev);
diff --git a/drivers/net/wireless/p54.h b/drivers/net/wireless/p54.h
new file mode 100644
index 0000000..744c866
--- /dev/null
+++ b/drivers/net/wireless/p54.h
@@ -0,0 +1,81 @@
+#ifndef PRISM54_H
+#define PRISM54_H
+
+/*
+ * Shared defines for all mac80211 Prism54 code
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * 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.
+ */
+
+enum control_frame_types {
+	P54_CONTROL_TYPE_FILTER_SET = 0,
+	P54_CONTROL_TYPE_CHANNEL_CHANGE,
+	P54_CONTROL_TYPE_FREQDONE,
+	P54_CONTROL_TYPE_DCFINIT,
+	P54_CONTROL_TYPE_FREEQUEUE = 7,
+	P54_CONTROL_TYPE_TXDONE,
+	P54_CONTROL_TYPE_PING,
+	P54_CONTROL_TYPE_STAT_READBACK,
+	P54_CONTROL_TYPE_BBP,
+	P54_CONTROL_TYPE_EEPROM_READBACK,
+	P54_CONTROL_TYPE_LED
+};
+
+struct p54_control_hdr {
+	__le16 magic1;
+	__le16 len;
+	__le32 req_id;
+	__le16 type;	/* enum control_frame_types */
+	u8 retry1;
+	u8 retry2;
+	u8 data[0];
+} __attribute__ ((packed));
+
+#define EEPROM_READBACK_LEN (sizeof(struct p54_control_hdr) + 4 /* p54_eeprom_lm86 */)
+#define MAX_RX_SIZE (IEEE80211_MAX_RTS_THRESHOLD + sizeof(struct p54_control_hdr) + 20 /* length of struct p54_rx_hdr */ + 16 )
+
+#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
+
+struct p54_common {
+	u32 rx_start;
+	u32 rx_end;
+	struct sk_buff_head tx_queue;
+	void (*tx)(struct ieee80211_hw *dev, struct p54_control_hdr *data,
+		   size_t len, int free_on_tx);
+	int (*open)(struct ieee80211_hw *dev);
+	void (*stop)(struct ieee80211_hw *dev);
+	int mode;
+	u8 mac_addr[ETH_ALEN];
+	u8 bssid[ETH_ALEN];
+	struct pda_iq_autocal_entry *iq_autocal;
+	unsigned int iq_autocal_len;
+	struct pda_channel_output_limit *output_limit;
+	unsigned int output_limit_len;
+	struct pda_pa_curve_data *curve_data;
+	__le16 rxhw;
+	u8 version;
+	unsigned int tx_hdr_len;
+	void *cached_vdcf;
+	unsigned int fw_var;
+	/* FIXME: this channels/modes/rates stuff sucks */
+	struct ieee80211_channel channels[14];
+	struct ieee80211_rate rates[12];
+	struct ieee80211_hw_mode modes[2];
+	struct ieee80211_tx_queue_stats tx_stats;
+};
+
+int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
+void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
+int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len);
+void p54_fill_eeprom_readback(struct p54_control_hdr *hdr);
+struct ieee80211_hw *p54_init_common(size_t priv_data_len);
+void p54_free_common(struct ieee80211_hw *dev);
+
+#endif /* PRISM54_H */
diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54common.c
new file mode 100644
index 0000000..2c63cf0
--- /dev/null
+++ b/drivers/net/wireless/p54common.c
@@ -0,0 +1,1019 @@
+
+/*
+ * Common code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * 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/init.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "p54common.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_DESCRIPTION("Softmac Prism54 common code");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("prism54common");
+
+void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
+{
+	struct p54_common *priv = dev->priv;
+	struct bootrec_exp_if *exp_if;
+	struct bootrec *bootrec;
+	u32 *data = (u32 *)fw->data;
+	u32 *end_data = (u32 *)fw->data + (fw->size >> 2);
+	u8 *fw_version = NULL;
+	size_t len;
+	int i;
+
+	if (priv->rx_start)
+		return;
+
+	while (data < end_data && *data)
+		data++;
+
+	while (data < end_data && !*data)
+		data++;
+
+	bootrec = (struct bootrec *) data;
+
+	while (bootrec->data <= end_data &&
+	       (bootrec->data + (len = le32_to_cpu(bootrec->len))) <= end_data) {
+		u32 code = le32_to_cpu(bootrec->code);
+		switch (code) {
+		case BR_CODE_COMPONENT_ID:
+			switch (be32_to_cpu(*bootrec->data)) {
+			case FW_FMAC:
+				printk(KERN_INFO "p54: FreeMAC firmware\n");
+				break;
+			case FW_LM20:
+				printk(KERN_INFO "p54: LM20 firmware\n");
+				break;
+			case FW_LM86:
+				printk(KERN_INFO "p54: LM86 firmware\n");
+				break;
+			case FW_LM87:
+				printk(KERN_INFO "p54: LM87 firmware - not supported yet!\n");
+				break;
+			default:
+				printk(KERN_INFO "p54: unknown firmware\n");
+				break;
+			}
+			break;
+		case BR_CODE_COMPONENT_VERSION:
+			/* 24 bytes should be enough for all firmwares */
+			if (strnlen((unsigned char*)bootrec->data, 24) < 24)
+				fw_version = (unsigned char*)bootrec->data;
+			break;
+		case BR_CODE_DESCR:
+			priv->rx_start = le32_to_cpu(bootrec->data[1]);
+			/* FIXME add sanity checking */
+			priv->rx_end = le32_to_cpu(bootrec->data[2]) - 0x3500;
+			break;
+		case BR_CODE_EXPOSED_IF:
+			exp_if = (struct bootrec_exp_if *) bootrec->data;
+			for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
+				if (exp_if[i].if_id == 0x1a)
+					priv->fw_var = le16_to_cpu(exp_if[i].variant);
+			break;
+		case BR_CODE_DEPENDENT_IF:
+			break;
+		case BR_CODE_END_OF_BRA:
+		case LEGACY_BR_CODE_END_OF_BRA:
+			end_data = NULL;
+			break;
+		default:
+			break;
+		}
+		bootrec = (struct bootrec *)&bootrec->data[len];
+	}
+
+	if (fw_version)
+		printk(KERN_INFO "p54: FW rev %s - Softmac protocol %x.%x\n",
+			fw_version, priv->fw_var >> 8, priv->fw_var & 0xff);
+
+	if (priv->fw_var >= 0x300) {
+		/* Firmware supports QoS, use it! */
+		priv->tx_stats.data[0].limit = 3;
+		priv->tx_stats.data[1].limit = 4;
+		priv->tx_stats.data[2].limit = 3;
+		priv->tx_stats.data[3].limit = 1;
+		dev->queues = 4;
+	}
+}
+EXPORT_SYMBOL_GPL(p54_parse_firmware);
+
+static int p54_convert_rev0_to_rev1(struct ieee80211_hw *dev,
+				    struct pda_pa_curve_data *curve_data)
+{
+	struct p54_common *priv = dev->priv;
+	struct pda_pa_curve_data_sample_rev1 *rev1;
+	struct pda_pa_curve_data_sample_rev0 *rev0;
+	size_t cd_len = sizeof(*curve_data) +
+		(curve_data->points_per_channel*sizeof(*rev1) + 2) *
+		 curve_data->channels;
+	unsigned int i, j;
+	void *source, *target;
+
+	priv->curve_data = kmalloc(cd_len, GFP_KERNEL);
+	if (!priv->curve_data)
+		return -ENOMEM;
+
+	memcpy(priv->curve_data, curve_data, sizeof(*curve_data));
+	source = curve_data->data;
+	target = priv->curve_data->data;
+	for (i = 0; i < curve_data->channels; i++) {
+		__le16 *freq = source;
+		source += sizeof(__le16);
+		*((__le16 *)target) = *freq;
+		target += sizeof(__le16);
+		for (j = 0; j < curve_data->points_per_channel; j++) {
+			rev1 = target;
+			rev0 = source;
+
+			rev1->rf_power = rev0->rf_power;
+			rev1->pa_detector = rev0->pa_detector;
+			rev1->data_64qam = rev0->pcv;
+			/* "invent" the points for the other modulations */
+#define SUB(x,y) (u8)((x) - (y)) > (x) ? 0 : (x) - (y)
+			rev1->data_16qam = SUB(rev0->pcv, 12);
+			rev1->data_qpsk  = SUB(rev1->data_16qam, 12);
+			rev1->data_bpsk  = SUB(rev1->data_qpsk, 12);
+			rev1->data_barker= SUB(rev1->data_bpsk, 14);
+#undef SUB
+			target += sizeof(*rev1);
+			source += sizeof(*rev0);
+		}
+	}
+
+	return 0;
+}
+
+int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
+{
+	struct p54_common *priv = dev->priv;
+	struct eeprom_pda_wrap *wrap = NULL;
+	struct pda_entry *entry;
+	int i = 0;
+	unsigned int data_len, entry_len;
+	void *tmp;
+	int err;
+
+	wrap = (struct eeprom_pda_wrap *) eeprom;
+	entry = (void *)wrap->data + wrap->len;
+	i += 2;
+	i += le16_to_cpu(entry->len)*2;
+	while (i < len) {
+		entry_len = le16_to_cpu(entry->len);
+		data_len = ((entry_len - 1) << 1);
+		switch (le16_to_cpu(entry->code)) {
+		case PDR_MAC_ADDRESS:
+			SET_IEEE80211_PERM_ADDR(dev, entry->data);
+			break;
+		case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
+			if (data_len < 2) {
+				err = -EINVAL;
+				goto err;
+			}
+
+			if (2 + entry->data[1]*sizeof(*priv->output_limit) > data_len) {
+				err = -EINVAL;
+				goto err;
+			}
+
+			priv->output_limit = kmalloc(entry->data[1] *
+				sizeof(*priv->output_limit), GFP_KERNEL);
+
+			if (!priv->output_limit) {
+				err = -ENOMEM;
+				goto err;
+			}
+
+			memcpy(priv->output_limit, &entry->data[2],
+			       entry->data[1]*sizeof(*priv->output_limit));
+			priv->output_limit_len = entry->data[1];
+			break;
+		case PDR_PRISM_PA_CAL_CURVE_DATA:
+			if (data_len < sizeof(struct pda_pa_curve_data)) {
+				err = -EINVAL;
+				goto err;
+			}
+
+			if (((struct pda_pa_curve_data *)entry->data)->cal_method_rev) {
+				priv->curve_data = kmalloc(data_len, GFP_KERNEL);
+				if (!priv->curve_data) {
+					err = -ENOMEM;
+					goto err;
+				}
+
+				memcpy(priv->curve_data, entry->data, data_len);
+			} else {
+				err = p54_convert_rev0_to_rev1(dev, (struct pda_pa_curve_data *)entry->data);
+				if (err)
+					goto err;
+			}
+
+			break;
+		case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
+			priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
+			if (!priv->iq_autocal) {
+				err = -ENOMEM;
+				goto err;
+			}
+
+			memcpy(priv->iq_autocal, entry->data, data_len);
+			priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
+			break;
+		case PDR_INTERFACE_LIST:
+			tmp = entry->data;
+			while ((u8 *)tmp < entry->data + data_len) {
+				struct bootrec_exp_if *exp_if = tmp;
+				if (le16_to_cpu(exp_if->if_id) == 0xF)
+					priv->rxhw = exp_if->variant & cpu_to_le16(0x07);
+				tmp += sizeof(struct bootrec_exp_if);
+			}
+			break;
+		case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
+			priv->version = *(u8 *)(entry->data + 1);
+			break;
+		case PDR_END:
+			i = len;
+			break;
+		}
+
+		entry = (void *)entry + (entry_len + 1)*2;
+		i += 2;
+		i += entry_len*2;
+	}
+
+	if (!priv->iq_autocal || !priv->output_limit || !priv->curve_data) {
+		printk(KERN_ERR "p54: not all required entries found in eeprom!\n");
+		err = -EINVAL;
+		goto err;
+	}
+
+	return 0;
+
+  err:
+	if (priv->iq_autocal) {
+		kfree(priv->iq_autocal);
+		priv->iq_autocal = NULL;
+	}
+
+	if (priv->output_limit) {
+		kfree(priv->output_limit);
+		priv->output_limit = NULL;
+	}
+
+	if (priv->curve_data) {
+		kfree(priv->curve_data);
+		priv->curve_data = NULL;
+	}
+
+	printk(KERN_ERR "p54: eeprom parse failed!\n");
+	return err;
+}
+EXPORT_SYMBOL_GPL(p54_parse_eeprom);
+
+void p54_fill_eeprom_readback(struct p54_control_hdr *hdr)
+{
+	struct p54_eeprom_lm86 *eeprom_hdr;
+
+	hdr->magic1 = cpu_to_le16(0x8000);
+	hdr->len = cpu_to_le16(sizeof(*eeprom_hdr) + 0x2000);
+	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK);
+	hdr->retry1 = hdr->retry2 = 0;
+	eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data;
+	eeprom_hdr->offset = 0x0;
+	eeprom_hdr->len = cpu_to_le16(0x2000);
+}
+EXPORT_SYMBOL_GPL(p54_fill_eeprom_readback);
+
+static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+	struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data;
+	struct ieee80211_rx_status rx_status = {0};
+	u16 freq = le16_to_cpu(hdr->freq);
+
+	rx_status.ssi = hdr->rssi;
+	rx_status.rate = hdr->rate & 0x1f; /* report short preambles & CCK too */
+	rx_status.channel = freq == 2484 ? 14 : (freq - 2407)/5;
+	rx_status.freq = freq;
+	rx_status.phymode = MODE_IEEE80211G;
+	rx_status.antenna = hdr->antenna;
+	rx_status.mactime = le64_to_cpu(hdr->timestamp);
+
+	skb_pull(skb, sizeof(*hdr));
+	skb_trim(skb, le16_to_cpu(hdr->len));
+
+	ieee80211_rx_irqsafe(dev, skb, &rx_status);
+}
+
+static void inline p54_wake_free_queues(struct ieee80211_hw *dev)
+{
+	struct p54_common *priv = dev->priv;
+	int i;
+
+	/* ieee80211_start_queues is great if all queues are really empty.
+	 * But, what if some are full? */
+
+	for (i = 0; i < dev->queues; i++)
+		if (priv->tx_stats.data[i].len < priv->tx_stats.data[i].limit)
+			ieee80211_wake_queue(dev, i);
+}
+
+static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+	struct p54_common *priv = dev->priv;
+	struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
+	struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data;
+	struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next;
+	u32 addr = le32_to_cpu(hdr->req_id) - 0x70;
+	struct memrecord *range = NULL;
+	u32 freed = 0;
+	u32 last_addr = priv->rx_start;
+
+	while (entry != (struct sk_buff *)&priv->tx_queue) {
+		range = (struct memrecord *)&entry->cb;
+		if (range->start_addr == addr) {
+			struct ieee80211_tx_status status = {{0}};
+			struct p54_control_hdr *entry_hdr;
+			struct p54_tx_control_allocdata *entry_data;
+			int pad = 0;
+
+			if (entry->next != (struct sk_buff *)&priv->tx_queue)
+				freed = ((struct memrecord *)&entry->next->cb)->start_addr - last_addr;
+			else
+				freed = priv->rx_end - last_addr;
+
+			last_addr = range->end_addr;
+			__skb_unlink(entry, &priv->tx_queue);
+			if (!range->control) {
+				kfree_skb(entry);
+				break;
+			}
+			memcpy(&status.control, range->control,
+			       sizeof(status.control));
+			kfree(range->control);
+			priv->tx_stats.data[status.control.queue].len--;
+
+			entry_hdr = (struct p54_control_hdr *) entry->data;
+			entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data;
+			if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0)
+				pad = entry_data->align[0];
+
+			if (!status.control.flags & IEEE80211_TXCTL_NO_ACK) {
+				if (!(payload->status & 0x01))
+					status.flags |= IEEE80211_TX_STATUS_ACK;
+				else
+					status.excessive_retries = 1;
+			}
+			status.retry_count = payload->retries - 1;
+			status.ack_signal = le16_to_cpu(payload->ack_rssi);
+			skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
+			ieee80211_tx_status_irqsafe(dev, entry, &status);
+			break;
+		} else
+			last_addr = range->end_addr;
+		entry = entry->next;
+	}
+
+	if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
+	    sizeof(struct p54_control_hdr))
+		p54_wake_free_queues(dev);
+}
+
+static void p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+	struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
+
+	switch (le16_to_cpu(hdr->type)) {
+	case P54_CONTROL_TYPE_TXDONE:
+		p54_rx_frame_sent(dev, skb);
+		break;
+	case P54_CONTROL_TYPE_BBP:
+		break;
+	default:
+		printk(KERN_DEBUG "%s: not handling 0x%02x type control frame\n",
+		       wiphy_name(dev->wiphy), le16_to_cpu(hdr->type));
+		break;
+	}
+}
+
+/* returns zero if skb can be reused */
+int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+	u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8;
+	switch (type) {
+	case 0x00:
+	case 0x01:
+		p54_rx_data(dev, skb);
+		return -1;
+	case 0x4d:
+		/* TODO: do something better... but then again, I've never seen this happen */
+		printk(KERN_ERR "%s: Received fault. Probably need to restart hardware now..\n",
+		       wiphy_name(dev->wiphy));
+		break;
+	case 0x80:
+		p54_rx_control(dev, skb);
+		break;
+	default:
+		printk(KERN_ERR "%s: unknown frame RXed (0x%02x)\n",
+		       wiphy_name(dev->wiphy), type);
+		break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(p54_rx);
+
+/*
+ * So, the firmware is somewhat stupid and doesn't know what places in its
+ * memory incoming data should go to. By poking around in the firmware, we
+ * can find some unused memory to upload our packets to. However, data that we
+ * want the card to TX needs to stay intact until the card has told us that
+ * it is done with it. This function finds empty places we can upload to and
+ * marks allocated areas as reserved if necessary. p54_rx_frame_sent frees
+ * allocated areas.
+ */
+static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
+			       struct p54_control_hdr *data, u32 len,
+			       struct ieee80211_tx_control *control)
+{
+	struct p54_common *priv = dev->priv;
+	struct sk_buff *entry = priv->tx_queue.next;
+	struct sk_buff *target_skb = NULL;
+	struct memrecord *range;
+	u32 last_addr = priv->rx_start;
+	u32 largest_hole = 0;
+	u32 target_addr = priv->rx_start;
+	unsigned long flags;
+	unsigned int left;
+	len = (len + 0x170 + 3) & ~0x3; /* 0x70 headroom, 0x100 tailroom */
+
+	spin_lock_irqsave(&priv->tx_queue.lock, flags);
+	left = skb_queue_len(&priv->tx_queue);
+	while (left--) {
+		u32 hole_size;
+		range = (struct memrecord *)&entry->cb;
+		hole_size = range->start_addr - last_addr;
+		if (!target_skb && hole_size >= len) {
+			target_skb = entry->prev;
+			hole_size -= len;
+			target_addr = last_addr;
+		}
+		largest_hole = max(largest_hole, hole_size);
+		last_addr = range->end_addr;
+		entry = entry->next;
+	}
+	if (!target_skb && priv->rx_end - last_addr >= len) {
+		target_skb = priv->tx_queue.prev;
+		largest_hole = max(largest_hole, priv->rx_end - last_addr - len);
+		if (!skb_queue_empty(&priv->tx_queue)) {
+			range = (struct memrecord *)&target_skb->cb;
+			target_addr = range->end_addr;
+		}
+	} else
+		largest_hole = max(largest_hole, priv->rx_end - last_addr);
+
+	if (skb) {
+		range = (struct memrecord *)&skb->cb;
+		range->start_addr = target_addr;
+		range->end_addr = target_addr + len;
+		range->control = control;
+		__skb_queue_after(&priv->tx_queue, target_skb, skb);
+		if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
+				   sizeof(struct p54_control_hdr))
+			ieee80211_stop_queues(dev);
+	}
+	spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+
+	data->req_id = cpu_to_le32(target_addr + 0x70);
+}
+
+static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb,
+		  struct ieee80211_tx_control *control)
+{
+	struct ieee80211_tx_queue_stats_data *current_queue;
+	struct p54_common *priv = dev->priv;
+	struct p54_control_hdr *hdr;
+	struct p54_tx_control_allocdata *txhdr;
+	struct ieee80211_tx_control *control_copy;
+	size_t padding, len;
+	u8 rate;
+
+	current_queue = &priv->tx_stats.data[control->queue];
+	if (unlikely(current_queue->len > current_queue->limit))
+		return NETDEV_TX_BUSY;
+	current_queue->len++;
+	current_queue->count++;
+	if (current_queue->len == current_queue->limit)
+		ieee80211_stop_queue(dev, control->queue);
+
+	padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
+	len = skb->len;
+
+	control_copy = kmalloc(sizeof(*control), GFP_ATOMIC);
+	if (control_copy)
+		memcpy(control_copy, control, sizeof(*control));
+
+	txhdr = (struct p54_tx_control_allocdata *)
+			skb_push(skb, sizeof(*txhdr) + padding);
+	hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr));
+
+	if (padding)
+		hdr->magic1 = cpu_to_le16(0x4010);
+	else
+		hdr->magic1 = cpu_to_le16(0x0010);
+	hdr->len = cpu_to_le16(len);
+	hdr->type = (control->flags & IEEE80211_TXCTL_NO_ACK) ? 0 : cpu_to_le16(1);
+	hdr->retry1 = hdr->retry2 = control->retry_limit;
+	p54_assign_address(dev, skb, hdr, skb->len, control_copy);
+
+	memset(txhdr->wep_key, 0x0, 16);
+	txhdr->padding = 0;
+	txhdr->padding2 = 0;
+
+	/* TODO: add support for alternate retry TX rates */
+	rate = control->tx_rate;
+	if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS)
+		rate |= 0x40;
+	else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+		rate |= 0x20;
+	memset(txhdr->rateset, rate, 8);
+	txhdr->wep_key_present = 0;
+	txhdr->wep_key_len = 0;
+	txhdr->frame_type = cpu_to_le32(control->queue + 4);
+	txhdr->magic4 = 0;
+	txhdr->antenna = (control->antenna_sel_tx == 0) ?
+		2 : control->antenna_sel_tx - 1;
+	txhdr->output_power = 0x7f; // HW Maximum
+	txhdr->magic5 = (control->flags & IEEE80211_TXCTL_NO_ACK) ?
+		0 : ((rate > 0x3) ? cpu_to_le32(0x33) : cpu_to_le32(0x23));
+	if (padding)
+		txhdr->align[0] = padding;
+
+	priv->tx(dev, hdr, skb->len, 0);
+	return 0;
+}
+
+static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type,
+			  const u8 *dst, const u8 *src, u8 antenna,
+			  u32 magic3, u32 magic8, u32 magic9)
+{
+	struct p54_common *priv = dev->priv;
+	struct p54_control_hdr *hdr;
+	struct p54_tx_control_filter *filter;
+
+	hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) +
+		      priv->tx_hdr_len, GFP_KERNEL);
+	if (!hdr)
+		return -ENOMEM;
+
+	hdr = (void *)hdr + priv->tx_hdr_len;
+
+	filter = (struct p54_tx_control_filter *) hdr->data;
+	hdr->magic1 = cpu_to_le16(0x8001);
+	hdr->len = cpu_to_le16(sizeof(*filter));
+	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*filter), NULL);
+	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET);
+
+	filter->filter_type = cpu_to_le16(filter_type);
+	memcpy(filter->dst, dst, ETH_ALEN);
+	if (!src)
+		memset(filter->src, ~0, ETH_ALEN);
+	else
+		memcpy(filter->src, src, ETH_ALEN);
+	filter->antenna = antenna;
+	filter->magic3 = cpu_to_le32(magic3);
+	filter->rx_addr = cpu_to_le32(priv->rx_end);
+	filter->max_rx = cpu_to_le16(0x0620);	/* FIXME: for usb ver 1.. maybe */
+	filter->rxhw = priv->rxhw;
+	filter->magic8 = cpu_to_le16(magic8);
+	filter->magic9 = cpu_to_le16(magic9);
+
+	priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*filter), 1);
+	return 0;
+}
+
+static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq)
+{
+	struct p54_common *priv = dev->priv;
+	struct p54_control_hdr *hdr;
+	struct p54_tx_control_channel *chan;
+	unsigned int i;
+	size_t payload_len = sizeof(*chan) + sizeof(u32)*2 +
+			     sizeof(*chan->curve_data) *
+			     priv->curve_data->points_per_channel;
+	void *entry;
+
+	hdr = kzalloc(sizeof(*hdr) + payload_len +
+		      priv->tx_hdr_len, GFP_KERNEL);
+	if (!hdr)
+		return -ENOMEM;
+
+	hdr = (void *)hdr + priv->tx_hdr_len;
+
+	chan = (struct p54_tx_control_channel *) hdr->data;
+
+	hdr->magic1 = cpu_to_le16(0x8001);
+	hdr->len = cpu_to_le16(sizeof(*chan));
+	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE);
+	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + payload_len, NULL);
+
+	chan->magic1 = cpu_to_le16(0x1);
+	chan->magic2 = cpu_to_le16(0x0);
+
+	for (i = 0; i < priv->iq_autocal_len; i++) {
+		if (priv->iq_autocal[i].freq != freq)
+			continue;
+
+		memcpy(&chan->iq_autocal, &priv->iq_autocal[i],
+		       sizeof(*priv->iq_autocal));
+		break;
+	}
+	if (i == priv->iq_autocal_len)
+		goto err;
+
+	for (i = 0; i < priv->output_limit_len; i++) {
+		if (priv->output_limit[i].freq != freq)
+			continue;
+
+		chan->val_barker = 0x38;
+		chan->val_bpsk = priv->output_limit[i].val_bpsk;
+		chan->val_qpsk = priv->output_limit[i].val_qpsk;
+		chan->val_16qam = priv->output_limit[i].val_16qam;
+		chan->val_64qam = priv->output_limit[i].val_64qam;
+		break;
+	}
+	if (i == priv->output_limit_len)
+		goto err;
+
+	chan->pa_points_per_curve = priv->curve_data->points_per_channel;
+
+	entry = priv->curve_data->data;
+	for (i = 0; i < priv->curve_data->channels; i++) {
+		if (*((__le16 *)entry) != freq) {
+			entry += sizeof(__le16);
+			entry += sizeof(struct pda_pa_curve_data_sample_rev1) *
+				 chan->pa_points_per_curve;
+			continue;
+		}
+
+		entry += sizeof(__le16);
+		memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) *
+		       chan->pa_points_per_curve);
+		break;
+	}
+
+	memcpy(hdr->data + payload_len - 4, &chan->val_bpsk, 4);
+
+	priv->tx(dev, hdr, sizeof(*hdr) + payload_len, 1);
+	return 0;
+
+ err:
+	printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy));
+	kfree(hdr);
+	return -EINVAL;
+}
+
+static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act)
+{
+	struct p54_common *priv = dev->priv;
+	struct p54_control_hdr *hdr;
+	struct p54_tx_control_led *led;
+
+	hdr = kzalloc(sizeof(*hdr) + sizeof(*led) +
+		      priv->tx_hdr_len, GFP_KERNEL);
+	if (!hdr)
+		return -ENOMEM;
+
+	hdr = (void *)hdr + priv->tx_hdr_len;
+	hdr->magic1 = cpu_to_le16(0x8001);
+	hdr->len = cpu_to_le16(sizeof(*led));
+	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED);
+	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led), NULL);
+
+	led = (struct p54_tx_control_led *) hdr->data;
+	led->mode = cpu_to_le16(mode);
+	led->led_permanent = cpu_to_le16(link);
+	led->led_temporary = cpu_to_le16(act);
+	led->duration = cpu_to_le16(1000);
+
+	priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*led), 1);
+
+	return 0;
+}
+
+#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, burst)	\
+do {	 							\
+	queue.aifs = cpu_to_le16(ai_fs);			\
+	queue.cwmin = cpu_to_le16(cw_min);			\
+	queue.cwmax = cpu_to_le16(cw_max);			\
+	queue.txop = (burst == 0) ? 				\
+		0 : cpu_to_le16((burst * 100) / 32 + 1);	\
+} while(0)
+
+static void p54_init_vdcf(struct ieee80211_hw *dev)
+{
+	struct p54_common *priv = dev->priv;
+	struct p54_control_hdr *hdr;
+	struct p54_tx_control_vdcf *vdcf;
+
+	/* all USB V1 adapters need a extra headroom */
+	hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len;
+	hdr->magic1 = cpu_to_le16(0x8001);
+	hdr->len = cpu_to_le16(sizeof(*vdcf));
+	hdr->type = cpu_to_le16(P54_CONTROL_TYPE_DCFINIT);
+	hdr->req_id = cpu_to_le32(priv->rx_start);
+
+	vdcf = (struct p54_tx_control_vdcf *) hdr->data;
+
+	P54_SET_QUEUE(vdcf->queue[0], 0x0002, 0x0003, 0x0007, 0x000f);
+	P54_SET_QUEUE(vdcf->queue[1], 0x0002, 0x0007, 0x000f, 0x001e);
+	P54_SET_QUEUE(vdcf->queue[2], 0x0002, 0x000f, 0x03ff, 0x0014);
+	P54_SET_QUEUE(vdcf->queue[3], 0x0007, 0x000f, 0x03ff, 0x0000);
+}
+
+static void p54_set_vdcf(struct ieee80211_hw *dev)
+{
+	struct p54_common *priv = dev->priv;
+	struct p54_control_hdr *hdr;
+	struct p54_tx_control_vdcf *vdcf;
+
+	hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len;
+
+	p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf), NULL);
+
+	vdcf = (struct p54_tx_control_vdcf *) hdr->data;
+
+	if (dev->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) {
+		vdcf->slottime = 9;
+		vdcf->magic1 = 0x00;
+		vdcf->magic2 = 0x10;
+	} else {
+		vdcf->slottime = 20;
+		vdcf->magic1 = 0x0a;
+		vdcf->magic2 = 0x06;
+	}
+
+	/* (see prism54/isl_oid.h for further details) */
+	vdcf->frameburst = cpu_to_le16(0);
+
+	priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*vdcf), 0);
+}
+
+static int p54_start(struct ieee80211_hw *dev)
+{
+	struct p54_common *priv = dev->priv;
+	int err;
+
+	err = priv->open(dev);
+	if (!err)
+		priv->mode = IEEE80211_IF_TYPE_MNTR;
+
+	return err;
+}
+
+static void p54_stop(struct ieee80211_hw *dev)
+{
+	struct p54_common *priv = dev->priv;
+	struct sk_buff *skb;
+	while ((skb = skb_dequeue(&priv->tx_queue))) {
+		struct memrecord *range = (struct memrecord *)&skb->cb;
+		if (range->control)
+			kfree(range->control);
+		kfree_skb(skb);
+	}
+	priv->stop(dev);
+	priv->mode = IEEE80211_IF_TYPE_INVALID;
+}
+
+static int p54_add_interface(struct ieee80211_hw *dev,
+			     struct ieee80211_if_init_conf *conf)
+{
+	struct p54_common *priv = dev->priv;
+
+	if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+		return -EOPNOTSUPP;
+
+	switch (conf->type) {
+	case IEEE80211_IF_TYPE_STA:
+		priv->mode = conf->type;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
+
+	p54_set_filter(dev, 0, priv->mac_addr, NULL, 0, 1, 0, 0xF642);
+	p54_set_filter(dev, 0, priv->mac_addr, NULL, 1, 0, 0, 0xF642);
+
+	switch (conf->type) {
+	case IEEE80211_IF_TYPE_STA:
+		p54_set_filter(dev, 1, priv->mac_addr, NULL, 0, 0x15F, 0x1F4, 0);
+		break;
+	default:
+		BUG();	/* impossible */
+		break;
+	}
+
+	p54_set_leds(dev, 1, 0, 0);
+
+	return 0;
+}
+
+static void p54_remove_interface(struct ieee80211_hw *dev,
+				 struct ieee80211_if_init_conf *conf)
+{
+	struct p54_common *priv = dev->priv;
+	priv->mode = IEEE80211_IF_TYPE_MNTR;
+	memset(priv->mac_addr, 0, ETH_ALEN);
+	p54_set_filter(dev, 0, priv->mac_addr, NULL, 2, 0, 0, 0);
+}
+
+static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
+{
+	int ret;
+
+	ret = p54_set_freq(dev, cpu_to_le16(conf->freq));
+	p54_set_vdcf(dev);
+	return ret;
+}
+
+static int p54_config_interface(struct ieee80211_hw *dev, int if_id,
+				struct ieee80211_if_conf *conf)
+{
+	struct p54_common *priv = dev->priv;
+
+	p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 0, 1, 0, 0xF642);
+	p54_set_filter(dev, 0, priv->mac_addr, conf->bssid, 2, 0, 0, 0);
+	p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0);
+	memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+	return 0;
+}
+
+static void p54_configure_filter(struct ieee80211_hw *dev,
+				 unsigned int changed_flags,
+				 unsigned int *total_flags,
+				 int mc_count, struct dev_mc_list *mclist)
+{
+	struct p54_common *priv = dev->priv;
+
+	*total_flags &= FIF_BCN_PRBRESP_PROMISC;
+
+	if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+		if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+			p54_set_filter(dev, 0, priv->mac_addr,
+				       NULL, 2, 0, 0, 0);
+		else
+			p54_set_filter(dev, 0, priv->mac_addr,
+				       priv->bssid, 2, 0, 0, 0);
+	}
+}
+
+static int p54_conf_tx(struct ieee80211_hw *dev, int queue,
+		       const struct ieee80211_tx_queue_params *params)
+{
+	struct p54_common *priv = dev->priv;
+	struct p54_tx_control_vdcf *vdcf;
+
+	vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *)
+		((void *)priv->cached_vdcf + priv->tx_hdr_len))->data);
+
+	if ((params) && !((queue < 0) || (queue > 4))) {
+		P54_SET_QUEUE(vdcf->queue[queue], params->aifs,
+			params->cw_min, params->cw_max, params->burst_time);
+	} else
+		return -EINVAL;
+
+	p54_set_vdcf(dev);
+
+	return 0;
+}
+
+static int p54_get_stats(struct ieee80211_hw *dev,
+			 struct ieee80211_low_level_stats *stats)
+{
+	/* TODO */
+	return 0;
+}
+
+static int p54_get_tx_stats(struct ieee80211_hw *dev,
+			    struct ieee80211_tx_queue_stats *stats)
+{
+	struct p54_common *priv = dev->priv;
+	unsigned int i;
+
+	for (i = 0; i < dev->queues; i++)
+		memcpy(&stats->data[i], &priv->tx_stats.data[i],
+			sizeof(stats->data[i]));
+
+	return 0;
+}
+
+static const struct ieee80211_ops p54_ops = {
+	.tx			= p54_tx,
+	.start			= p54_start,
+	.stop			= p54_stop,
+	.add_interface		= p54_add_interface,
+	.remove_interface	= p54_remove_interface,
+	.config			= p54_config,
+	.config_interface	= p54_config_interface,
+	.configure_filter	= p54_configure_filter,
+	.conf_tx		= p54_conf_tx,
+	.get_stats		= p54_get_stats,
+	.get_tx_stats		= p54_get_tx_stats
+};
+
+struct ieee80211_hw *p54_init_common(size_t priv_data_len)
+{
+	struct ieee80211_hw *dev;
+	struct p54_common *priv;
+	int i;
+
+	dev = ieee80211_alloc_hw(priv_data_len, &p54_ops);
+	if (!dev)
+		return NULL;
+
+	priv = dev->priv;
+	priv->mode = IEEE80211_IF_TYPE_INVALID;
+	skb_queue_head_init(&priv->tx_queue);
+	memcpy(priv->channels, p54_channels, sizeof(p54_channels));
+	memcpy(priv->rates, p54_rates, sizeof(p54_rates));
+	priv->modes[1].mode = MODE_IEEE80211B;
+	priv->modes[1].num_rates = 4;
+	priv->modes[1].rates = priv->rates;
+	priv->modes[1].num_channels = ARRAY_SIZE(p54_channels);
+	priv->modes[1].channels = priv->channels;
+	priv->modes[0].mode = MODE_IEEE80211G;
+	priv->modes[0].num_rates = ARRAY_SIZE(p54_rates);
+	priv->modes[0].rates = priv->rates;
+	priv->modes[0].num_channels = ARRAY_SIZE(p54_channels);
+	priv->modes[0].channels = priv->channels;
+	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */
+		    IEEE80211_HW_RX_INCLUDES_FCS;
+	dev->channel_change_time = 1000;	/* TODO: find actual value */
+	dev->max_rssi = 127;
+
+	priv->tx_stats.data[0].limit = 5;
+	dev->queues = 1;
+
+	dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 +
+				 sizeof(struct p54_tx_control_allocdata);
+
+        priv->cached_vdcf = kzalloc(sizeof(struct p54_tx_control_vdcf) +
+              priv->tx_hdr_len + sizeof(struct p54_control_hdr), GFP_KERNEL);
+
+	if (!priv->cached_vdcf) {
+		ieee80211_free_hw(dev);
+		return NULL;
+	}
+
+	p54_init_vdcf(dev);
+
+	for (i = 0; i < 2; i++) {
+		if (ieee80211_register_hwmode(dev, &priv->modes[i])) {
+			kfree(priv->cached_vdcf);
+			ieee80211_free_hw(dev);
+			return NULL;
+		}
+	}
+
+	return dev;
+}
+EXPORT_SYMBOL_GPL(p54_init_common);
+
+void p54_free_common(struct ieee80211_hw *dev)
+{
+	struct p54_common *priv = dev->priv;
+	kfree(priv->iq_autocal);
+	kfree(priv->output_limit);
+	kfree(priv->curve_data);
+	kfree(priv->cached_vdcf);
+}
+EXPORT_SYMBOL_GPL(p54_free_common);
+
+static int __init p54_init(void)
+{
+	return 0;
+}
+
+static void __exit p54_exit(void)
+{
+}
+
+module_init(p54_init);
+module_exit(p54_exit);
diff --git a/drivers/net/wireless/p54common.h b/drivers/net/wireless/p54common.h
new file mode 100644
index 0000000..a721334
--- /dev/null
+++ b/drivers/net/wireless/p54common.h
@@ -0,0 +1,329 @@
+#ifndef PRISM54COMMON_H
+#define PRISM54COMMON_H
+
+/*
+ * Common code specific definitions for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * 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.
+ */
+
+struct bootrec {
+	__le32 code;
+	__le32 len;
+	u32 data[0];
+} __attribute__((packed));
+
+struct bootrec_exp_if {
+	__le16 role;
+	__le16 if_id;
+	__le16 variant;
+	__le16 btm_compat;
+	__le16 top_compat;
+} __attribute__((packed));
+
+#define BR_CODE_MIN			0x80000000
+#define BR_CODE_COMPONENT_ID		0x80000001
+#define BR_CODE_COMPONENT_VERSION	0x80000002
+#define BR_CODE_DEPENDENT_IF		0x80000003
+#define BR_CODE_EXPOSED_IF		0x80000004
+#define BR_CODE_DESCR			0x80000101
+#define BR_CODE_MAX			0x8FFFFFFF
+#define BR_CODE_END_OF_BRA		0xFF0000FF
+#define LEGACY_BR_CODE_END_OF_BRA	0xFFFFFFFF
+
+#define FW_FMAC 0x464d4143
+#define FW_LM86 0x4c4d3836
+#define FW_LM87 0x4c4d3837
+#define FW_LM20 0x4c4d3230
+
+/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
+
+struct pda_entry {
+	__le16 len;	/* includes both code and data */
+	__le16 code;
+	u8 data[0];
+} __attribute__ ((packed));
+
+struct eeprom_pda_wrap {
+	u32 magic;
+	u16 pad;
+	u16 len;
+	u32 arm_opcode;
+	u8 data[0];
+} __attribute__ ((packed));
+
+struct pda_iq_autocal_entry {
+        __le16 freq;
+        __le16 iq_param[4];
+} __attribute__ ((packed));
+
+struct pda_channel_output_limit {
+	__le16 freq;
+	u8 val_bpsk;
+	u8 val_qpsk;
+	u8 val_16qam;
+	u8 val_64qam;
+	u8 rate_set_mask;
+	u8 rate_set_size;
+} __attribute__ ((packed));
+
+struct pda_pa_curve_data_sample_rev0 {
+	u8 rf_power;
+	u8 pa_detector;
+	u8 pcv;
+} __attribute__ ((packed));
+
+struct pda_pa_curve_data_sample_rev1 {
+	u8 rf_power;
+	u8 pa_detector;
+	u8 data_barker;
+	u8 data_bpsk;
+	u8 data_qpsk;
+	u8 data_16qam;
+	u8 data_64qam;
+	u8 padding;
+} __attribute__ ((packed));
+
+struct pda_pa_curve_data {
+	u8 cal_method_rev;
+	u8 channels;
+	u8 points_per_channel;
+	u8 padding;
+	u8 data[0];
+} __attribute__ ((packed));
+
+/*
+ * this defines the PDR codes used to build PDAs as defined in document
+ * number 553155. The current implementation mirrors version 1.1 of the
+ * document and lists only PDRs supported by the ARM platform.
+ */
+
+/* common and choice range (0x0000 - 0x0fff) */
+#define PDR_END					0x0000
+#define PDR_MANUFACTURING_PART_NUMBER		0x0001
+#define PDR_PDA_VERSION				0x0002
+#define PDR_NIC_SERIAL_NUMBER			0x0003
+
+#define PDR_MAC_ADDRESS				0x0101
+#define PDR_REGULATORY_DOMAIN_LIST		0x0103
+#define PDR_TEMPERATURE_TYPE			0x0107
+
+#define PDR_PRISM_PCI_IDENTIFIER		0x0402
+
+/* ARM range (0x1000 - 0x1fff) */
+#define PDR_COUNTRY_INFORMATION			0x1000
+#define PDR_INTERFACE_LIST			0x1001
+#define PDR_HARDWARE_PLATFORM_COMPONENT_ID	0x1002
+#define PDR_OEM_NAME				0x1003
+#define PDR_PRODUCT_NAME			0x1004
+#define PDR_UTF8_OEM_NAME			0x1005
+#define PDR_UTF8_PRODUCT_NAME			0x1006
+#define PDR_COUNTRY_LIST			0x1007
+#define PDR_DEFAULT_COUNTRY			0x1008
+
+#define PDR_ANTENNA_GAIN			0x1100
+
+#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA	0x1901
+#define PDR_RSSI_LINEAR_APPROXIMATION		0x1902
+#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS	0x1903
+#define PDR_PRISM_PA_CAL_CURVE_DATA		0x1904
+#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND	0x1905
+#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION		0x1906
+#define PDR_REGULATORY_POWER_LIMITS		0x1907
+#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED	0x1908
+#define PDR_RADIATED_TRANSMISSION_CORRECTION	0x1909
+#define PDR_PRISM_TX_IQ_CALIBRATION		0x190a
+
+/* reserved range (0x2000 - 0x7fff) */
+
+/* customer range (0x8000 - 0xffff) */
+#define PDR_BASEBAND_REGISTERS			0x8000
+#define PDR_PER_CHANNEL_BASEBAND_REGISTERS	0x8001
+
+/* stored in skb->cb */
+struct memrecord {
+	u32 start_addr;
+	u32 end_addr;
+	struct ieee80211_tx_control *control;
+};
+
+struct p54_eeprom_lm86 {
+	__le16 offset;
+	__le16 len;
+	u8 data[0];
+} __attribute__ ((packed));
+
+struct p54_rx_hdr {
+	__le16 magic;
+	__le16 len;
+	__le16 freq;
+	u8 antenna;
+	u8 rate;
+	u8 rssi;
+	u8 quality;
+	u16 unknown2;
+	__le64 timestamp;
+	u8 data[0];
+} __attribute__ ((packed));
+
+struct p54_frame_sent_hdr {
+	u8 status;
+	u8 retries;
+	__le16 ack_rssi;
+	__le16 seq;
+	u16 rate;
+} __attribute__ ((packed));
+
+struct p54_tx_control_allocdata {
+	u8 rateset[8];
+	u16 padding;
+	u8 wep_key_present;
+	u8 wep_key_len;
+	u8 wep_key[16];
+	__le32 frame_type;
+	u32 padding2;
+	__le16 magic4;
+	u8 antenna;
+	u8 output_power;
+	__le32 magic5;
+	u8 align[0];
+} __attribute__ ((packed));
+
+struct p54_tx_control_filter {
+	__le16 filter_type;
+	u8 dst[ETH_ALEN];
+	u8 src[ETH_ALEN];
+	u8 antenna;
+	u8 debug;
+	__le32 magic3;
+	u8 rates[8];	// FIXME: what's this for?
+	__le32 rx_addr;
+	__le16 max_rx;
+	__le16 rxhw;
+	__le16 magic8;
+	__le16 magic9;
+} __attribute__ ((packed));
+
+struct p54_tx_control_channel {
+	__le16 magic1;
+	__le16 magic2;
+	u8 padding1[20];
+	struct pda_iq_autocal_entry iq_autocal;
+	u8 pa_points_per_curve;
+	u8 val_barker;
+	u8 val_bpsk;
+	u8 val_qpsk;
+	u8 val_16qam;
+	u8 val_64qam;
+	struct pda_pa_curve_data_sample_rev1 curve_data[0];
+	/* additional padding/data after curve_data */
+} __attribute__ ((packed));
+
+struct p54_tx_control_led {
+	__le16 mode;
+	__le16 led_temporary;
+	__le16 led_permanent;
+	__le16 duration;
+} __attribute__ ((packed));
+
+struct p54_tx_vdcf_queues {
+	__le16 aifs;
+	__le16 cwmin;
+	__le16 cwmax;
+	__le16 txop;
+} __attribute__ ((packed));
+
+struct p54_tx_control_vdcf {
+	u8 padding;
+	u8 slottime;
+	u8 magic1;
+	u8 magic2;
+	struct p54_tx_vdcf_queues queue[8];
+	u8 pad2[4];
+	__le16 frameburst;
+} __attribute__ ((packed));
+
+static const struct ieee80211_rate p54_rates[] = {
+	{ .rate = 10,
+	  .val = 0,
+	  .val2 = 0x10,
+	  .flags = IEEE80211_RATE_CCK_2 },
+	{ .rate = 20,
+	  .val = 1,
+	  .val2 = 0x11,
+	  .flags = IEEE80211_RATE_CCK_2 },
+	{ .rate = 55,
+	  .val = 2,
+	  .val2 = 0x12,
+	  .flags = IEEE80211_RATE_CCK_2 },
+	{ .rate = 110,
+	  .val = 3,
+	  .val2 = 0x13,
+	  .flags = IEEE80211_RATE_CCK_2 },
+	{ .rate = 60,
+	  .val = 4,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 90,
+	  .val = 5,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 120,
+	  .val = 6,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 180,
+	  .val = 7,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 240,
+	  .val = 8,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 360,
+	  .val = 9,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 480,
+	  .val = 10,
+	  .flags = IEEE80211_RATE_OFDM },
+	{ .rate = 540,
+	  .val = 11,
+	  .flags = IEEE80211_RATE_OFDM },
+};
+
+// TODO: just generate this..
+static const struct ieee80211_channel p54_channels[] = {
+	{ .chan = 1,
+	  .freq = 2412},
+	{ .chan = 2,
+	  .freq = 2417},
+	{ .chan = 3,
+	  .freq = 2422},
+	{ .chan = 4,
+	  .freq = 2427},
+	{ .chan = 5,
+	  .freq = 2432},
+	{ .chan = 6,
+	  .freq = 2437},
+	{ .chan = 7,
+	  .freq = 2442},
+	{ .chan = 8,
+	  .freq = 2447},
+	{ .chan = 9,
+	  .freq = 2452},
+	{ .chan = 10,
+	  .freq = 2457},
+	{ .chan = 11,
+	  .freq = 2462},
+	{ .chan = 12,
+	  .freq = 2467},
+	{ .chan = 13,
+	  .freq = 2472},
+	{ .chan = 14,
+	  .freq = 2484}
+};
+
+#endif /* PRISM54COMMON_H */
diff --git a/drivers/net/wireless/p54pci.c b/drivers/net/wireless/p54pci.c
new file mode 100644
index 0000000..410b543
--- /dev/null
+++ b/drivers/net/wireless/p54pci.c
@@ -0,0 +1,692 @@
+
+/*
+ * Linux device driver for PCI based Prism54
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jean-baptiste.note@m4x.org>, et al.
+ *
+ * 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/init.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "p54pci.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_DESCRIPTION("Prism54 PCI wireless driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("prism54pci");
+
+static struct pci_device_id p54p_table[] __devinitdata = {
+	/* Intersil PRISM Duette/Prism GT Wireless LAN adapter */
+	{ PCI_DEVICE(0x1260, 0x3890) },
+	/* 3COM 3CRWE154G72 Wireless LAN adapter */
+	{ PCI_DEVICE(0x10b7, 0x6001) },
+	/* Intersil PRISM Indigo Wireless LAN adapter */
+	{ PCI_DEVICE(0x1260, 0x3877) },
+	/* Intersil PRISM Javelin/Xbow Wireless LAN adapter */
+	{ PCI_DEVICE(0x1260, 0x3886) },
+	{ },
+};
+
+MODULE_DEVICE_TABLE(pci, p54p_table);
+
+static int p54p_upload_firmware(struct ieee80211_hw *dev)
+{
+	struct p54p_priv *priv = dev->priv;
+	const struct firmware *fw_entry = NULL;
+	__le32 reg;
+	int err;
+	u32 *data;
+	u32 remains, left, device_addr;
+
+	P54P_WRITE(int_enable, 0);
+	P54P_READ(int_enable);
+	udelay(10);
+
+	reg = P54P_READ(ctrl_stat);
+	reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+	reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
+	P54P_WRITE(ctrl_stat, reg);
+	P54P_READ(ctrl_stat);
+	udelay(10);
+
+	reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
+	P54P_WRITE(ctrl_stat, reg);
+	wmb();
+	udelay(10);
+
+	reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+	P54P_WRITE(ctrl_stat, reg);
+	wmb();
+
+	mdelay(50);
+
+	err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev);
+	if (err) {
+		printk(KERN_ERR "%s (prism54pci): cannot find firmware "
+		       "(isl3886)\n", pci_name(priv->pdev));
+		return err;
+	}
+
+	p54_parse_firmware(dev, fw_entry);
+
+	data = (u32 *) fw_entry->data;
+	remains = fw_entry->size;
+	device_addr = ISL38XX_DEV_FIRMWARE_ADDR;
+	while (remains) {
+		u32 i = 0;
+		left = min((u32)0x1000, remains);
+		P54P_WRITE(direct_mem_base, cpu_to_le32(device_addr));
+		P54P_READ(int_enable);
+
+		device_addr += 0x1000;
+		while (i < left) {
+			P54P_WRITE(direct_mem_win[i], *data++);
+			i += sizeof(u32);
+		}
+
+		remains -= left;
+		P54P_READ(int_enable);
+	}
+
+	release_firmware(fw_entry);
+
+	reg = P54P_READ(ctrl_stat);
+	reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
+	reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+	reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
+	P54P_WRITE(ctrl_stat, reg);
+	P54P_READ(ctrl_stat);
+	udelay(10);
+
+	reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
+	P54P_WRITE(ctrl_stat, reg);
+	wmb();
+	udelay(10);
+
+	reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+	P54P_WRITE(ctrl_stat, reg);
+	wmb();
+	udelay(10);
+
+	return 0;
+}
+
+static irqreturn_t p54p_simple_interrupt(int irq, void *dev_id)
+{
+	struct p54p_priv *priv = (struct p54p_priv *) dev_id;
+	__le32 reg;
+
+	reg = P54P_READ(int_ident);
+	P54P_WRITE(int_ack, reg);
+
+	if (reg & P54P_READ(int_enable))
+		complete(&priv->boot_comp);
+
+	return IRQ_HANDLED;
+}
+
+static int p54p_read_eeprom(struct ieee80211_hw *dev)
+{
+	struct p54p_priv *priv = dev->priv;
+	int err;
+	struct p54_control_hdr *hdr;
+	void *eeprom;
+	dma_addr_t rx_mapping, tx_mapping;
+	u16 alen;
+
+	init_completion(&priv->boot_comp);
+	err = request_irq(priv->pdev->irq, &p54p_simple_interrupt,
+			  IRQF_SHARED, "prism54pci", priv);
+	if (err) {
+		printk(KERN_ERR "%s (prism54pci): failed to register IRQ handler\n",
+		       pci_name(priv->pdev));
+		return err;
+	}
+
+	eeprom = kmalloc(0x2010 + EEPROM_READBACK_LEN, GFP_KERNEL);
+	if (!eeprom) {
+		printk(KERN_ERR "%s (prism54pci): no memory for eeprom!\n",
+		       pci_name(priv->pdev));
+		err = -ENOMEM;
+		goto out;
+	}
+
+	memset(priv->ring_control, 0, sizeof(*priv->ring_control));
+	P54P_WRITE(ring_control_base, priv->ring_control_dma);
+	P54P_READ(ring_control_base);
+	udelay(10);
+
+	P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT));
+	P54P_READ(int_enable);
+	udelay(10);
+
+	P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
+
+	if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) {
+		printk(KERN_ERR "%s (prism54pci): Cannot boot firmware!\n",
+		       pci_name(priv->pdev));
+		err = -EINVAL;
+		goto out;
+	}
+
+	P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE));
+	P54P_READ(int_enable);
+
+	hdr = eeprom + 0x2010;
+	p54_fill_eeprom_readback(hdr);
+	hdr->req_id = cpu_to_le32(priv->common.rx_start);
+
+	rx_mapping = pci_map_single(priv->pdev, eeprom,
+				    0x2010, PCI_DMA_FROMDEVICE);
+	tx_mapping = pci_map_single(priv->pdev, (void *)hdr,
+				    EEPROM_READBACK_LEN, PCI_DMA_TODEVICE);
+
+	priv->ring_control->rx_mgmt[0].host_addr = cpu_to_le32(rx_mapping);
+	priv->ring_control->rx_mgmt[0].len = cpu_to_le16(0x2010);
+	priv->ring_control->tx_data[0].host_addr = cpu_to_le32(tx_mapping);
+	priv->ring_control->tx_data[0].device_addr = hdr->req_id;
+	priv->ring_control->tx_data[0].len = cpu_to_le16(EEPROM_READBACK_LEN);
+
+	priv->ring_control->host_idx[2] = cpu_to_le32(1);
+	priv->ring_control->host_idx[1] = cpu_to_le32(1);
+
+	wmb();
+	mdelay(100);
+	P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
+
+	wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ);
+	wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ);
+
+	pci_unmap_single(priv->pdev, tx_mapping,
+			 EEPROM_READBACK_LEN, PCI_DMA_TODEVICE);
+	pci_unmap_single(priv->pdev, rx_mapping,
+			 0x2010, PCI_DMA_FROMDEVICE);
+
+	alen = le16_to_cpu(priv->ring_control->rx_mgmt[0].len);
+	if (le32_to_cpu(priv->ring_control->device_idx[2]) != 1 ||
+	    alen < 0x10) {
+		printk(KERN_ERR "%s (prism54pci): Cannot read eeprom!\n",
+		       pci_name(priv->pdev));
+		err = -EINVAL;
+		goto out;
+	}
+
+	p54_parse_eeprom(dev, (u8 *)eeprom + 0x10, alen - 0x10);
+
+ out:
+	kfree(eeprom);
+	P54P_WRITE(int_enable, 0);
+	P54P_READ(int_enable);
+	udelay(10);
+	free_irq(priv->pdev->irq, priv);
+	P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
+	return err;
+}
+
+static void p54p_refill_rx_ring(struct ieee80211_hw *dev)
+{
+	struct p54p_priv *priv = dev->priv;
+	u32 limit, host_idx, idx;
+
+	host_idx = le32_to_cpu(priv->ring_control->host_idx[0]);
+	limit = host_idx;
+	limit -= le32_to_cpu(priv->ring_control->device_idx[0]);
+	limit = ARRAY_SIZE(priv->ring_control->rx_data) - limit;
+
+	idx = host_idx % ARRAY_SIZE(priv->ring_control->rx_data);
+	while (limit-- > 1) {
+		struct p54p_desc *desc = &priv->ring_control->rx_data[idx];
+
+		if (!desc->host_addr) {
+			struct sk_buff *skb;
+			dma_addr_t mapping;
+			skb = dev_alloc_skb(MAX_RX_SIZE);
+			if (!skb)
+				break;
+
+			mapping = pci_map_single(priv->pdev,
+						 skb_tail_pointer(skb),
+						 MAX_RX_SIZE,
+						 PCI_DMA_FROMDEVICE);
+			desc->host_addr = cpu_to_le32(mapping);
+			desc->device_addr = 0;	// FIXME: necessary?
+			desc->len = cpu_to_le16(MAX_RX_SIZE);
+			desc->flags = 0;
+			priv->rx_buf[idx] = skb;
+		}
+
+		idx++;
+		host_idx++;
+		idx %= ARRAY_SIZE(priv->ring_control->rx_data);
+	}
+
+	wmb();
+	priv->ring_control->host_idx[0] = cpu_to_le32(host_idx);
+}
+
+static irqreturn_t p54p_interrupt(int irq, void *dev_id)
+{
+	struct ieee80211_hw *dev = dev_id;
+	struct p54p_priv *priv = dev->priv;
+	__le32 reg;
+
+	spin_lock(&priv->lock);
+	reg = P54P_READ(int_ident);
+	if (unlikely(reg == 0xFFFFFFFF)) {
+		spin_unlock(&priv->lock);
+		return IRQ_HANDLED;
+	}
+
+	P54P_WRITE(int_ack, reg);
+
+	reg &= P54P_READ(int_enable);
+
+	if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) {
+		struct p54p_desc *desc;
+		u32 idx, i;
+		i = priv->tx_idx;
+		i %= ARRAY_SIZE(priv->ring_control->tx_data);
+		priv->tx_idx = idx = le32_to_cpu(priv->ring_control->device_idx[1]);
+		idx %= ARRAY_SIZE(priv->ring_control->tx_data);
+
+		while (i != idx) {
+			desc = &priv->ring_control->tx_data[i];
+			if (priv->tx_buf[i]) {
+				kfree(priv->tx_buf[i]);
+				priv->tx_buf[i] = NULL;
+			}
+
+			pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
+					 le16_to_cpu(desc->len), PCI_DMA_TODEVICE);
+
+			desc->host_addr = 0;
+			desc->device_addr = 0;
+			desc->len = 0;
+			desc->flags = 0;
+
+			i++;
+			i %= ARRAY_SIZE(priv->ring_control->tx_data);
+		}
+
+		i = priv->rx_idx;
+		i %= ARRAY_SIZE(priv->ring_control->rx_data);
+		priv->rx_idx = idx = le32_to_cpu(priv->ring_control->device_idx[0]);
+		idx %= ARRAY_SIZE(priv->ring_control->rx_data);
+		while (i != idx) {
+			u16 len;
+			struct sk_buff *skb;
+			desc = &priv->ring_control->rx_data[i];
+			len = le16_to_cpu(desc->len);
+			skb = priv->rx_buf[i];
+
+			skb_put(skb, len);
+
+			if (p54_rx(dev, skb)) {
+				pci_unmap_single(priv->pdev,
+						 le32_to_cpu(desc->host_addr),
+						 MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
+
+				priv->rx_buf[i] = NULL;
+				desc->host_addr = 0;
+			} else {
+				skb_trim(skb, 0);
+				desc->len = cpu_to_le16(MAX_RX_SIZE);
+			}
+
+			i++;
+			i %= ARRAY_SIZE(priv->ring_control->rx_data);
+		}
+
+		p54p_refill_rx_ring(dev);
+
+		wmb();
+		P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
+	} else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT))
+		complete(&priv->boot_comp);
+
+	spin_unlock(&priv->lock);
+
+	return reg ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data,
+		    size_t len, int free_on_tx)
+{
+	struct p54p_priv *priv = dev->priv;
+	unsigned long flags;
+	struct p54p_desc *desc;
+	dma_addr_t mapping;
+	u32 device_idx, idx, i;
+
+	spin_lock_irqsave(&priv->lock, flags);
+
+	device_idx = le32_to_cpu(priv->ring_control->device_idx[1]);
+	idx = le32_to_cpu(priv->ring_control->host_idx[1]);
+	i = idx % ARRAY_SIZE(priv->ring_control->tx_data);
+
+	mapping = pci_map_single(priv->pdev, data, len, PCI_DMA_TODEVICE);
+	desc = &priv->ring_control->tx_data[i];
+	desc->host_addr = cpu_to_le32(mapping);
+	desc->device_addr = data->req_id;
+	desc->len = cpu_to_le16(len);
+	desc->flags = 0;
+
+	wmb();
+	priv->ring_control->host_idx[1] = cpu_to_le32(idx + 1);
+
+	if (free_on_tx)
+		priv->tx_buf[i] = data;
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
+	P54P_READ(dev_int);
+
+	/* FIXME: unlikely to happen because the device usually runs out of
+	   memory before we fill the ring up, but we can make it impossible */
+	if (idx - device_idx > ARRAY_SIZE(priv->ring_control->tx_data) - 2)
+		printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy));
+}
+
+static int p54p_open(struct ieee80211_hw *dev)
+{
+	struct p54p_priv *priv = dev->priv;
+	int err;
+
+	init_completion(&priv->boot_comp);
+	err = request_irq(priv->pdev->irq, &p54p_interrupt,
+			  IRQF_SHARED, "prism54pci", dev);
+	if (err) {
+		printk(KERN_ERR "%s: failed to register IRQ handler\n",
+		       wiphy_name(dev->wiphy));
+		return err;
+	}
+
+	memset(priv->ring_control, 0, sizeof(*priv->ring_control));
+	priv->rx_idx = priv->tx_idx = 0;
+	p54p_refill_rx_ring(dev);
+
+	p54p_upload_firmware(dev);
+
+	P54P_WRITE(ring_control_base, priv->ring_control_dma);
+	P54P_READ(ring_control_base);
+	wmb();
+	udelay(10);
+
+	P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT));
+	P54P_READ(int_enable);
+	wmb();
+	udelay(10);
+
+	P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
+	P54P_READ(dev_int);
+
+	if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) {
+		printk(KERN_ERR "%s: Cannot boot firmware!\n",
+		       wiphy_name(dev->wiphy));
+		free_irq(priv->pdev->irq, dev);
+		return -ETIMEDOUT;
+	}
+
+	P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE));
+	P54P_READ(int_enable);
+	wmb();
+	udelay(10);
+
+	P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
+	P54P_READ(dev_int);
+	wmb();
+	udelay(10);
+
+	return 0;
+}
+
+static void p54p_stop(struct ieee80211_hw *dev)
+{
+	struct p54p_priv *priv = dev->priv;
+	unsigned int i;
+	struct p54p_desc *desc;
+
+	P54P_WRITE(int_enable, 0);
+	P54P_READ(int_enable);
+	udelay(10);
+
+	free_irq(priv->pdev->irq, dev);
+
+	P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
+
+	for (i = 0; i < ARRAY_SIZE(priv->rx_buf); i++) {
+		desc = &priv->ring_control->rx_data[i];
+		if (desc->host_addr)
+			pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
+					 MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
+		kfree_skb(priv->rx_buf[i]);
+		priv->rx_buf[i] = NULL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(priv->tx_buf); i++) {
+		desc = &priv->ring_control->tx_data[i];
+		if (desc->host_addr)
+			pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
+					 le16_to_cpu(desc->len), PCI_DMA_TODEVICE);
+
+		kfree(priv->tx_buf[i]);
+		priv->tx_buf[i] = NULL;
+	}
+
+	memset(priv->ring_control, 0, sizeof(*priv->ring_control));
+}
+
+static int __devinit p54p_probe(struct pci_dev *pdev,
+				const struct pci_device_id *id)
+{
+	struct p54p_priv *priv;
+	struct ieee80211_hw *dev;
+	unsigned long mem_addr, mem_len;
+	int err;
+	DECLARE_MAC_BUF(mac);
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR "%s (prism54pci): Cannot enable new PCI device\n",
+		       pci_name(pdev));
+		return err;
+	}
+
+	mem_addr = pci_resource_start(pdev, 0);
+	mem_len = pci_resource_len(pdev, 0);
+	if (mem_len < sizeof(struct p54p_csr)) {
+		printk(KERN_ERR "%s (prism54pci): Too short PCI resources\n",
+		       pci_name(pdev));
+		pci_disable_device(pdev);
+		return err;
+	}
+
+	err = pci_request_regions(pdev, "prism54pci");
+	if (err) {
+		printk(KERN_ERR "%s (prism54pci): Cannot obtain PCI resources\n",
+		       pci_name(pdev));
+		return err;
+	}
+
+	if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
+	    pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+		printk(KERN_ERR "%s (prism54pci): No suitable DMA available\n",
+		       pci_name(pdev));
+		goto err_free_reg;
+	}
+
+	pci_set_master(pdev);
+	pci_try_set_mwi(pdev);
+
+	pci_write_config_byte(pdev, 0x40, 0);
+	pci_write_config_byte(pdev, 0x41, 0);
+
+	dev = p54_init_common(sizeof(*priv));
+	if (!dev) {
+		printk(KERN_ERR "%s (prism54pci): ieee80211 alloc failed\n",
+		       pci_name(pdev));
+		err = -ENOMEM;
+		goto err_free_reg;
+	}
+
+	priv = dev->priv;
+	priv->pdev = pdev;
+
+	SET_IEEE80211_DEV(dev, &pdev->dev);
+	pci_set_drvdata(pdev, dev);
+
+	priv->map = ioremap(mem_addr, mem_len);
+	if (!priv->map) {
+		printk(KERN_ERR "%s (prism54pci): Cannot map device memory\n",
+		       pci_name(pdev));
+		err = -EINVAL;	// TODO: use a better error code?
+		goto err_free_dev;
+	}
+
+	priv->ring_control = pci_alloc_consistent(pdev, sizeof(*priv->ring_control),
+						  &priv->ring_control_dma);
+	if (!priv->ring_control) {
+		printk(KERN_ERR "%s (prism54pci): Cannot allocate rings\n",
+		       pci_name(pdev));
+		err = -ENOMEM;
+		goto err_iounmap;
+	}
+	memset(priv->ring_control, 0, sizeof(*priv->ring_control));
+
+	err = p54p_upload_firmware(dev);
+	if (err)
+		goto err_free_desc;
+
+	err = p54p_read_eeprom(dev);
+	if (err)
+		goto err_free_desc;
+
+	priv->common.open = p54p_open;
+	priv->common.stop = p54p_stop;
+	priv->common.tx = p54p_tx;
+
+	spin_lock_init(&priv->lock);
+
+	err = ieee80211_register_hw(dev);
+	if (err) {
+		printk(KERN_ERR "%s (prism54pci): Cannot register netdevice\n",
+		       pci_name(pdev));
+		goto err_free_common;
+	}
+
+	printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n",
+	       wiphy_name(dev->wiphy),
+	       print_mac(mac, dev->wiphy->perm_addr),
+	       priv->common.version);
+
+	return 0;
+
+ err_free_common:
+	p54_free_common(dev);
+
+ err_free_desc:
+	pci_free_consistent(pdev, sizeof(*priv->ring_control),
+			    priv->ring_control, priv->ring_control_dma);
+
+ err_iounmap:
+	iounmap(priv->map);
+
+ err_free_dev:
+	pci_set_drvdata(pdev, NULL);
+	ieee80211_free_hw(dev);
+
+ err_free_reg:
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	return err;
+}
+
+static void __devexit p54p_remove(struct pci_dev *pdev)
+{
+	struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+	struct p54p_priv *priv;
+
+	if (!dev)
+		return;
+
+	ieee80211_unregister_hw(dev);
+	priv = dev->priv;
+	pci_free_consistent(pdev, sizeof(*priv->ring_control),
+			    priv->ring_control, priv->ring_control_dma);
+	p54_free_common(dev);
+	iounmap(priv->map);
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	ieee80211_free_hw(dev);
+}
+
+#ifdef CONFIG_PM
+static int p54p_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+	struct p54p_priv *priv = dev->priv;
+
+	if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) {
+		ieee80211_stop_queues(dev);
+		p54p_stop(dev);
+	}
+
+	pci_save_state(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+	return 0;
+}
+
+static int p54p_resume(struct pci_dev *pdev)
+{
+	struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+	struct p54p_priv *priv = dev->priv;
+
+	pci_set_power_state(pdev, PCI_D0);
+	pci_restore_state(pdev);
+
+	if (priv->common.mode != IEEE80211_IF_TYPE_INVALID) {
+		p54p_open(dev);
+		ieee80211_start_queues(dev);
+	}
+
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static struct pci_driver p54p_driver = {
+	.name		= "prism54pci",
+	.id_table	= p54p_table,
+	.probe		= p54p_probe,
+	.remove		= __devexit_p(p54p_remove),
+#ifdef CONFIG_PM
+	.suspend	= p54p_suspend,
+	.resume		= p54p_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init p54p_init(void)
+{
+	return pci_register_driver(&p54p_driver);
+}
+
+static void __exit p54p_exit(void)
+{
+	pci_unregister_driver(&p54p_driver);
+}
+
+module_init(p54p_init);
+module_exit(p54p_exit);
diff --git a/drivers/net/wireless/p54pci.h b/drivers/net/wireless/p54pci.h
new file mode 100644
index 0000000..52feb59
--- /dev/null
+++ b/drivers/net/wireless/p54pci.h
@@ -0,0 +1,106 @@
+#ifndef PRISM54PCI_H
+#define PRISM54PCI_H
+
+/*
+ * Defines for PCI based mac80211 Prism54 driver
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * 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.
+ */
+
+/* Device Interrupt register bits */
+#define ISL38XX_DEV_INT_RESET                   0x0001
+#define ISL38XX_DEV_INT_UPDATE                  0x0002
+#define ISL38XX_DEV_INT_WAKEUP                  0x0008
+#define ISL38XX_DEV_INT_SLEEP                   0x0010
+#define ISL38XX_DEV_INT_ABORT                   0x0020
+/* these two only used in USB */
+#define ISL38XX_DEV_INT_DATA                    0x0040
+#define ISL38XX_DEV_INT_MGMT                    0x0080
+
+#define ISL38XX_DEV_INT_PCIUART_CTS             0x4000
+#define ISL38XX_DEV_INT_PCIUART_DR              0x8000
+
+/* Interrupt Identification/Acknowledge/Enable register bits */
+#define ISL38XX_INT_IDENT_UPDATE		0x0002
+#define ISL38XX_INT_IDENT_INIT			0x0004
+#define ISL38XX_INT_IDENT_WAKEUP		0x0008
+#define ISL38XX_INT_IDENT_SLEEP			0x0010
+#define ISL38XX_INT_IDENT_PCIUART_CTS		0x4000
+#define ISL38XX_INT_IDENT_PCIUART_DR		0x8000
+
+/* Control/Status register bits */
+#define ISL38XX_CTRL_STAT_SLEEPMODE		0x00000200
+#define ISL38XX_CTRL_STAT_CLKRUN		0x00800000
+#define ISL38XX_CTRL_STAT_RESET			0x10000000
+#define ISL38XX_CTRL_STAT_RAMBOOT		0x20000000
+#define ISL38XX_CTRL_STAT_STARTHALTED		0x40000000
+#define ISL38XX_CTRL_STAT_HOST_OVERRIDE		0x80000000
+
+struct p54p_csr {
+	__le32 dev_int;
+	u8 unused_1[12];
+	__le32 int_ident;
+	__le32 int_ack;
+	__le32 int_enable;
+	u8 unused_2[4];
+	union {
+		__le32 ring_control_base;
+		__le32 gen_purp_com[2];
+	};
+	u8 unused_3[8];
+	__le32 direct_mem_base;
+	u8 unused_4[44];
+	__le32 dma_addr;
+	__le32 dma_len;
+	__le32 dma_ctrl;
+	u8 unused_5[12];
+	__le32 ctrl_stat;
+	u8 unused_6[1924];
+	u8 cardbus_cis[0x800];
+	u8 direct_mem_win[0x1000];
+} __attribute__ ((packed));
+
+/* usb backend only needs the register defines above */
+#ifndef PRISM54USB_H
+struct p54p_desc {
+	__le32 host_addr;
+	__le32 device_addr;
+	__le16 len;
+	__le16 flags;
+} __attribute__ ((packed));
+
+struct p54p_ring_control {
+	__le32 host_idx[4];
+	__le32 device_idx[4];
+	struct p54p_desc rx_data[8];
+	struct p54p_desc tx_data[32];
+	struct p54p_desc rx_mgmt[4];
+	struct p54p_desc tx_mgmt[4];
+} __attribute__ ((packed));
+
+#define P54P_READ(r) __raw_readl(&priv->map->r)
+#define P54P_WRITE(r, val) __raw_writel((__force u32)(val), &priv->map->r)
+
+struct p54p_priv {
+	struct p54_common common;
+	struct pci_dev *pdev;
+	struct p54p_csr __iomem *map;
+
+	spinlock_t lock;
+	struct p54p_ring_control *ring_control;
+	dma_addr_t ring_control_dma;
+	u32 rx_idx, tx_idx;
+	struct sk_buff *rx_buf[8];
+	void *tx_buf[32];
+	struct completion boot_comp;
+};
+
+#endif /* PRISM54USB_H */
+#endif /* PRISM54PCI_H */
diff --git a/drivers/net/wireless/p54usb.c b/drivers/net/wireless/p54usb.c
new file mode 100644
index 0000000..755482a
--- /dev/null
+++ b/drivers/net/wireless/p54usb.c
@@ -0,0 +1,907 @@
+
+/*
+ * Linux device driver for USB based Prism54
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * 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/init.h>
+#include <linux/usb.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/crc32.h>
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "p54usb.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_DESCRIPTION("Prism54 USB wireless driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("prism54usb");
+
+static struct usb_device_id p54u_table[] __devinitdata = {
+	/* Version 1 devices (pci chip + net2280) */
+	{USB_DEVICE(0x0506, 0x0a11)},	/* 3COM 3CRWE254G72 */
+	{USB_DEVICE(0x0707, 0xee06)},	/* SMC 2862W-G */
+	{USB_DEVICE(0x083a, 0x4501)},	/* Accton 802.11g WN4501 USB */
+	{USB_DEVICE(0x083a, 0x4502)},	/* Siemens Gigaset USB Adapter */
+	{USB_DEVICE(0x0846, 0x4200)},	/* Netgear WG121 */
+	{USB_DEVICE(0x0846, 0x4210)},	/* Netgear WG121 the second ? */
+	{USB_DEVICE(0x0846, 0x4220)},	/* Netgear WG111 */
+	{USB_DEVICE(0x0cde, 0x0006)},	/* Medion 40900, Roper Europe */
+	{USB_DEVICE(0x124a, 0x4023)},	/* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
+	{USB_DEVICE(0x1915, 0x2234)},	/* Linksys WUSB54G OEM */
+	{USB_DEVICE(0x1915, 0x2235)},	/* Linksys WUSB54G Portable OEM */
+	{USB_DEVICE(0x2001, 0x3701)},	/* DLink DWL-G120 Spinnaker */
+	{USB_DEVICE(0x2001, 0x3703)},	/* DLink DWL-G122 */
+	{USB_DEVICE(0x5041, 0x2234)},	/* Linksys WUSB54G */
+	{USB_DEVICE(0x5041, 0x2235)},	/* Linksys WUSB54G Portable */
+
+	/* Version 2 devices (3887) */
+	{USB_DEVICE(0x050d, 0x7050)},	/* Belkin F5D7050 ver 1000 */
+	{USB_DEVICE(0x0572, 0x2000)},	/* Cohiba Proto board */
+	{USB_DEVICE(0x0572, 0x2002)},	/* Cohiba Proto board */
+	{USB_DEVICE(0x0707, 0xee13)},   /* SMC 2862W-G version 2 */
+	{USB_DEVICE(0x083a, 0x4521)},   /* Siemens Gigaset USB Adapter 54 version 2 */
+	{USB_DEVICE(0x0846, 0x4240)},	/* Netgear WG111 (v2) */
+	{USB_DEVICE(0x0915, 0x2000)},	/* Cohiba Proto board */
+	{USB_DEVICE(0x0915, 0x2002)},	/* Cohiba Proto board */
+	{USB_DEVICE(0x0baf, 0x0118)},   /* U.S. Robotics U5 802.11g Adapter*/
+	{USB_DEVICE(0x0bf8, 0x1009)},   /* FUJITSU E-5400 USB D1700*/
+	{USB_DEVICE(0x0cde, 0x0006)},   /* Medion MD40900 */
+	{USB_DEVICE(0x0cde, 0x0008)},	/* Sagem XG703A */
+	{USB_DEVICE(0x0d8e, 0x3762)},	/* DLink DWL-G120 Cohiba */
+	{USB_DEVICE(0x09aa, 0x1000)},	/* Spinnaker Proto board */
+	{USB_DEVICE(0x13B1, 0x000C)},	/* Linksys WUSB54AG */
+	{USB_DEVICE(0x1435, 0x0427)},	/* Inventel UR054G */
+	{USB_DEVICE(0x2001, 0x3704)},	/* DLink DWL-G122 rev A2 */
+	{USB_DEVICE(0x413c, 0x8102)},	/* Spinnaker DUT */
+	{USB_DEVICE(0x413c, 0x8104)},	/* Cohiba Proto board */
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, p54u_table);
+
+static void p54u_rx_cb(struct urb *urb)
+{
+	struct sk_buff *skb = (struct sk_buff *) urb->context;
+	struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
+	struct ieee80211_hw *dev = info->dev;
+	struct p54u_priv *priv = dev->priv;
+
+	if (unlikely(urb->status)) {
+		info->urb = NULL;
+		usb_free_urb(urb);
+		return;
+	}
+
+	skb_unlink(skb, &priv->rx_queue);
+	skb_put(skb, urb->actual_length);
+	if (!priv->hw_type)
+		skb_pull(skb, sizeof(struct net2280_tx_hdr));
+
+	if (p54_rx(dev, skb)) {
+		skb = dev_alloc_skb(MAX_RX_SIZE);
+		if (unlikely(!skb)) {
+			usb_free_urb(urb);
+			/* TODO check rx queue length and refill *somewhere* */
+			return;
+		}
+
+		info = (struct p54u_rx_info *) skb->cb;
+		info->urb = urb;
+		info->dev = dev;
+		urb->transfer_buffer = skb_tail_pointer(skb);
+		urb->context = skb;
+		skb_queue_tail(&priv->rx_queue, skb);
+	} else {
+		skb_trim(skb, 0);
+		skb_queue_tail(&priv->rx_queue, skb);
+	}
+
+	usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static void p54u_tx_cb(struct urb *urb)
+{
+	usb_free_urb(urb);
+}
+
+static void p54u_tx_free_cb(struct urb *urb)
+{
+	kfree(urb->transfer_buffer);
+	usb_free_urb(urb);
+}
+
+static int p54u_init_urbs(struct ieee80211_hw *dev)
+{
+	struct p54u_priv *priv = dev->priv;
+	struct urb *entry;
+	struct sk_buff *skb;
+	struct p54u_rx_info *info;
+
+	while (skb_queue_len(&priv->rx_queue) < 32) {
+		skb = __dev_alloc_skb(MAX_RX_SIZE, GFP_KERNEL);
+		if (!skb)
+			break;
+		entry = usb_alloc_urb(0, GFP_KERNEL);
+		if (!entry) {
+			kfree_skb(skb);
+			break;
+		}
+		usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), skb_tail_pointer(skb), MAX_RX_SIZE, p54u_rx_cb, skb);
+		info = (struct p54u_rx_info *) skb->cb;
+		info->urb = entry;
+		info->dev = dev;
+		skb_queue_tail(&priv->rx_queue, skb);
+		usb_submit_urb(entry, GFP_KERNEL);
+	}
+
+	return 0;
+}
+
+static void p54u_free_urbs(struct ieee80211_hw *dev)
+{
+	struct p54u_priv *priv = dev->priv;
+	struct p54u_rx_info *info;
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(&priv->rx_queue))) {
+		info = (struct p54u_rx_info *) skb->cb;
+		if (!info->urb)
+			continue;
+
+		usb_kill_urb(info->urb);
+		kfree_skb(skb);
+	}
+}
+
+static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data,
+			 size_t len, int free_on_tx)
+{
+	struct p54u_priv *priv = dev->priv;
+	struct urb *addr_urb, *data_urb;
+
+	addr_urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!addr_urb)
+		return;
+
+	data_urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!data_urb) {
+		usb_free_urb(addr_urb);
+		return;
+	}
+
+	usb_fill_bulk_urb(addr_urb, priv->udev,
+		usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), &data->req_id,
+		sizeof(data->req_id), p54u_tx_cb, dev);
+	usb_fill_bulk_urb(data_urb, priv->udev,
+		usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), data, len,
+		free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev);
+
+	usb_submit_urb(addr_urb, GFP_ATOMIC);
+	usb_submit_urb(data_urb, GFP_ATOMIC);
+}
+
+static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data,
+			    size_t len, int free_on_tx)
+{
+	struct p54u_priv *priv = dev->priv;
+	struct urb *int_urb, *data_urb;
+	struct net2280_tx_hdr *hdr;
+	struct net2280_reg_write *reg;
+
+	reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
+	if (!reg)
+		return;
+
+	int_urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!int_urb) {
+		kfree(reg);
+		return;
+	}
+
+	data_urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!data_urb) {
+		kfree(reg);
+		usb_free_urb(int_urb);
+		return;
+	}
+
+	reg->port = cpu_to_le16(NET2280_DEV_U32);
+	reg->addr = cpu_to_le32(P54U_DEV_BASE);
+	reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
+
+	len += sizeof(*data);
+	hdr = (void *)data - sizeof(*hdr);
+	memset(hdr, 0, sizeof(*hdr));
+	hdr->device_addr = data->req_id;
+	hdr->len = cpu_to_le16(len);
+
+	usb_fill_bulk_urb(int_urb, priv->udev,
+		usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
+		p54u_tx_free_cb, dev);
+	usb_submit_urb(int_urb, GFP_ATOMIC);
+
+	usb_fill_bulk_urb(data_urb, priv->udev,
+		usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, len + sizeof(*hdr),
+		free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev);
+	usb_submit_urb(data_urb, GFP_ATOMIC);
+}
+
+static int p54u_write(struct p54u_priv *priv,
+		      struct net2280_reg_write *buf,
+		      enum net2280_op_type type,
+		      __le32 addr, __le32 val)
+{
+	unsigned int ep;
+	int alen;
+
+	if (type & 0x0800)
+		ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
+	else
+		ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
+
+	buf->port = cpu_to_le16(type);
+	buf->addr = addr;
+	buf->val = val;
+
+	return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
+}
+
+static int p54u_read(struct p54u_priv *priv, void *buf,
+		     enum net2280_op_type type,
+		     __le32 addr, __le32 *val)
+{
+	struct net2280_reg_read *read = buf;
+	__le32 *reg = buf;
+	unsigned int ep;
+	int alen, err;
+
+	if (type & 0x0800)
+		ep = P54U_PIPE_DEV;
+	else
+		ep = P54U_PIPE_BRG;
+
+	read->port = cpu_to_le16(type);
+	read->addr = addr;
+
+	err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
+			   read, sizeof(*read), &alen, 1000);
+	if (err)
+		return err;
+
+	err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
+			   reg, sizeof(*reg), &alen, 1000);
+	if (err)
+		return err;
+
+	*val = *reg;
+	return 0;
+}
+
+static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
+			 void *data, size_t len)
+{
+	int alen;
+	return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
+			    data, len, &alen, 2000);
+}
+
+static int p54u_read_eeprom(struct ieee80211_hw *dev)
+{
+	struct p54u_priv *priv = dev->priv;
+	void *buf;
+	struct p54_control_hdr *hdr;
+	int err, alen;
+	size_t offset = priv->hw_type ? 0x10 : 0x20;
+
+	buf = kmalloc(0x2020, GFP_KERNEL);
+	if (!buf) {
+		printk(KERN_ERR "prism54usb: cannot allocate memory for"
+		       "eeprom readback!\n");
+		return -ENOMEM;
+	}
+
+	if (priv->hw_type) {
+		*((u32 *) buf) = priv->common.rx_start;
+		err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
+		if (err) {
+			printk(KERN_ERR "prism54usb: addr send failed\n");
+			goto fail;
+		}
+	} else {
+		struct net2280_reg_write *reg = buf;
+		reg->port = cpu_to_le16(NET2280_DEV_U32);
+		reg->addr = cpu_to_le32(P54U_DEV_BASE);
+		reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
+		err = p54u_bulk_msg(priv, P54U_PIPE_DEV, buf, sizeof(*reg));
+		if (err) {
+			printk(KERN_ERR "prism54usb: dev_int send failed\n");
+			goto fail;
+		}
+	}
+
+	hdr = buf + priv->common.tx_hdr_len;
+	p54_fill_eeprom_readback(hdr);
+	hdr->req_id = cpu_to_le32(priv->common.rx_start);
+	if (priv->common.tx_hdr_len) {
+		struct net2280_tx_hdr *tx_hdr = buf;
+		tx_hdr->device_addr = hdr->req_id;
+		tx_hdr->len = cpu_to_le16(EEPROM_READBACK_LEN);
+	}
+
+	/* we can just pretend to send 0x2000 bytes of nothing in the headers */
+	err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf,
+			    EEPROM_READBACK_LEN + priv->common.tx_hdr_len);
+	if (err) {
+		printk(KERN_ERR "prism54usb: eeprom req send failed\n");
+		goto fail;
+	}
+
+	err = usb_bulk_msg(priv->udev,
+			   usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
+			   buf, 0x2020, &alen, 1000);
+	if (!err && alen > offset) {
+		p54_parse_eeprom(dev, (u8 *)buf + offset, alen - offset);
+	} else {
+		printk(KERN_ERR "prism54usb: eeprom read failed!\n");
+		err = -EINVAL;
+		goto fail;
+	}
+
+ fail:
+	kfree(buf);
+	return err;
+}
+
+static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
+{
+	static char start_string[] = "~~~~<\r";
+	struct p54u_priv *priv = dev->priv;
+	const struct firmware *fw_entry = NULL;
+	int err, alen;
+	u8 carry = 0;
+	u8 *buf, *tmp, *data;
+	unsigned int left, remains, block_size;
+	struct x2_header *hdr;
+	unsigned long timeout;
+
+	tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
+	if (!buf) {
+		printk(KERN_ERR "p54usb: cannot allocate firmware upload buffer!\n");
+		err = -ENOMEM;
+		goto err_bufalloc;
+	}
+
+	memcpy(buf, start_string, 4);
+	err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4);
+	if (err) {
+		printk(KERN_ERR "p54usb: reset failed! (%d)\n", err);
+		goto err_reset;
+	}
+
+	err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev);
+	if (err) {
+		printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb_bare)!\n");
+		goto err_req_fw_failed;
+	}
+
+	p54_parse_firmware(dev, fw_entry);
+
+	left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
+	strcpy(buf, start_string);
+	left -= strlen(start_string);
+	tmp += strlen(start_string);
+
+	data = fw_entry->data;
+	remains = fw_entry->size;
+
+	hdr = (struct x2_header *)(buf + strlen(start_string));
+	memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
+	hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
+	hdr->fw_length = cpu_to_le32(fw_entry->size);
+	hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
+					 sizeof(u32)*2));
+	left -= sizeof(*hdr);
+	tmp += sizeof(*hdr);
+
+	while (remains) {
+		while (left--) {
+			if (carry) {
+				*tmp++ = carry;
+				carry = 0;
+				remains--;
+				continue;
+			}
+			switch (*data) {
+			case '~':
+				*tmp++ = '}';
+				carry = '^';
+				break;
+			case '}':
+				*tmp++ = '}';
+				carry = ']';
+				break;
+			default:
+				*tmp++ = *data;
+				remains--;
+				break;
+			}
+			data++;
+		}
+
+		err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
+		if (err) {
+			printk(KERN_ERR "prism54usb: firmware upload failed!\n");
+			goto err_upload_failed;
+		}
+
+		tmp = buf;
+		left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
+	}
+
+	*((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size));
+	err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
+	if (err) {
+		printk(KERN_ERR "prism54usb: firmware upload failed!\n");
+		goto err_upload_failed;
+	}
+
+	timeout = jiffies + msecs_to_jiffies(1000);
+	while (!(err = usb_bulk_msg(priv->udev,
+		usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
+		if (alen > 2 && !memcmp(buf, "OK", 2))
+			break;
+
+		if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
+			printk(KERN_INFO "prism54usb: firmware upload failed!\n");
+			err = -EINVAL;
+			break;
+		}
+
+		if (time_after(jiffies, timeout)) {
+			printk(KERN_ERR "prism54usb: firmware boot timed out!\n");
+			err = -ETIMEDOUT;
+			break;
+		}
+	}
+	if (err)
+		goto err_upload_failed;
+
+	buf[0] = 'g';
+	buf[1] = '\r';
+	err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
+	if (err) {
+		printk(KERN_ERR "prism54usb: firmware boot failed!\n");
+		goto err_upload_failed;
+	}
+
+	timeout = jiffies + msecs_to_jiffies(1000);
+	while (!(err = usb_bulk_msg(priv->udev,
+		usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
+		if (alen > 0 && buf[0] == 'g')
+			break;
+
+		if (time_after(jiffies, timeout)) {
+			err = -ETIMEDOUT;
+			break;
+		}
+	}
+	if (err)
+		goto err_upload_failed;
+
+  err_upload_failed:
+	release_firmware(fw_entry);
+  err_req_fw_failed:
+  err_reset:
+	kfree(buf);
+  err_bufalloc:
+	return err;
+}
+
+static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
+{
+	struct p54u_priv *priv = dev->priv;
+	const struct firmware *fw_entry = NULL;
+	const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
+	int err, alen;
+	void *buf;
+	__le32 reg;
+	unsigned int remains, offset;
+	u8 *data;
+
+	buf = kmalloc(512, GFP_KERNEL);
+	if (!buf) {
+		printk(KERN_ERR "p54usb: firmware buffer alloc failed!\n");
+		return -ENOMEM;
+	}
+
+	err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev);
+	if (err) {
+		printk(KERN_ERR "p54usb: cannot find firmware (isl3890usb)!\n");
+		kfree(buf);
+		return err;
+	}
+
+	p54_parse_firmware(dev, fw_entry);
+
+#define P54U_WRITE(type, addr, data) \
+	do {\
+		err = p54u_write(priv, buf, type,\
+				 cpu_to_le32((u32)(unsigned long)addr), data);\
+		if (err) \
+			goto fail;\
+	} while (0)
+
+#define P54U_READ(type, addr) \
+	do {\
+		err = p54u_read(priv, buf, type,\
+				cpu_to_le32((u32)(unsigned long)addr), &reg);\
+		if (err)\
+			goto fail;\
+	} while (0)
+
+	/* power down net2280 bridge */
+	P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
+	reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
+	reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
+	P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
+
+	mdelay(100);
+
+	/* power up bridge */
+	reg |= cpu_to_le32(P54U_BRG_POWER_UP);
+	reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
+	P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
+
+	mdelay(100);
+
+	P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
+		   cpu_to_le32(NET2280_CLK_30Mhz |
+			       NET2280_PCI_ENABLE |
+			       NET2280_PCI_SOFT_RESET));
+
+	mdelay(20);
+
+	P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
+		   cpu_to_le32(PCI_COMMAND_MEMORY |
+			       PCI_COMMAND_MASTER));
+
+	P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
+		   cpu_to_le32(NET2280_BASE));
+
+	P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
+	reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
+	P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
+
+	// TODO: we really need this?
+	P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
+
+	P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
+		   cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
+	P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
+		   cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
+
+	P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
+		   cpu_to_le32(NET2280_BASE2));
+
+	/* finally done setting up the bridge */
+
+	P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
+		   cpu_to_le32(PCI_COMMAND_MEMORY |
+			       PCI_COMMAND_MASTER));
+
+	P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
+	P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
+		   cpu_to_le32(P54U_DEV_BASE));
+
+	P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
+	P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
+		   cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
+
+	/* do romboot */
+	P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
+
+	P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
+	reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+	reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
+	reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
+	P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+	mdelay(20);
+
+	reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
+	P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+	mdelay(20);
+
+	reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+	P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+	mdelay(100);
+
+	P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
+	P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
+
+	/* finally, we can upload firmware now! */
+	remains = fw_entry->size;
+	data = fw_entry->data;
+	offset = ISL38XX_DEV_FIRMWARE_ADDR;
+
+	while (remains) {
+		unsigned int block_len = min(remains, (unsigned int)512);
+		memcpy(buf, data, block_len);
+
+		err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
+		if (err) {
+			printk(KERN_ERR "prism54usb: firmware block upload "
+			       "failed\n");
+			goto fail;
+		}
+
+		P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
+			   cpu_to_le32(0xc0000f00));
+
+		P54U_WRITE(NET2280_DEV_U32,
+			   0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
+		P54U_WRITE(NET2280_DEV_U32,
+			   0x0020 | (unsigned long)&devreg->direct_mem_win,
+			   cpu_to_le32(1));
+
+		P54U_WRITE(NET2280_DEV_U32,
+			   0x0024 | (unsigned long)&devreg->direct_mem_win,
+			   cpu_to_le32(block_len));
+		P54U_WRITE(NET2280_DEV_U32,
+			   0x0028 | (unsigned long)&devreg->direct_mem_win,
+			   cpu_to_le32(offset));
+
+		P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
+			   cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
+		P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
+			   cpu_to_le32(block_len >> 2));
+		P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
+			   cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
+
+		mdelay(10);
+
+		P54U_READ(NET2280_DEV_U32,
+			  0x002C | (unsigned long)&devreg->direct_mem_win);
+		if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
+		    !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
+			printk(KERN_ERR "prism54usb: firmware DMA transfer "
+			       "failed\n");
+			goto fail;
+		}
+
+		P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
+			   cpu_to_le32(NET2280_FIFO_FLUSH));
+
+		remains -= block_len;
+		data += block_len;
+		offset += block_len;
+	}
+
+	/* do ramboot */
+	P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
+	reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+	reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
+	reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
+	P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+	mdelay(20);
+
+	reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
+	P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+	reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+	P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+	mdelay(100);
+
+	P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
+	P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
+
+	/* start up the firmware */
+	P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
+		   cpu_to_le32(ISL38XX_INT_IDENT_INIT));
+
+	P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
+		   cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
+
+	P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
+		   cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
+			       NET2280_USB_INTERRUPT_ENABLE));
+
+	P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
+		   cpu_to_le32(ISL38XX_DEV_INT_RESET));
+
+	err = usb_interrupt_msg(priv->udev,
+				usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
+				buf, sizeof(__le32), &alen, 1000);
+	if (err || alen != sizeof(__le32))
+		goto fail;
+
+	P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
+	P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
+
+	if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
+		err = -EINVAL;
+
+	P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
+	P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
+		   cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
+
+#undef P54U_WRITE
+#undef P54U_READ
+
+ fail:
+	release_firmware(fw_entry);
+	kfree(buf);
+	return err;
+}
+
+static int p54u_open(struct ieee80211_hw *dev)
+{
+	struct p54u_priv *priv = dev->priv;
+	int err;
+
+	err = p54u_init_urbs(dev);
+	if (err) {
+		return err;
+	}
+
+	priv->common.open = p54u_init_urbs;
+
+	return 0;
+}
+
+static void p54u_stop(struct ieee80211_hw *dev)
+{
+	/* TODO: figure out how to reliably stop the 3887 and net2280 so
+	   the hardware is still usable next time we want to start it.
+	   until then, we just stop listening to the hardware.. */
+	p54u_free_urbs(dev);
+	return;
+}
+
+static int __devinit p54u_probe(struct usb_interface *intf,
+				const struct usb_device_id *id)
+{
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct ieee80211_hw *dev;
+	struct p54u_priv *priv;
+	int err;
+	unsigned int i, recognized_pipes;
+	DECLARE_MAC_BUF(mac);
+
+	dev = p54_init_common(sizeof(*priv));
+	if (!dev) {
+		printk(KERN_ERR "prism54usb: ieee80211 alloc failed\n");
+		return -ENOMEM;
+	}
+
+	priv = dev->priv;
+
+	SET_IEEE80211_DEV(dev, &intf->dev);
+	usb_set_intfdata(intf, dev);
+	priv->udev = udev;
+
+	usb_get_dev(udev);
+
+	/* really lazy and simple way of figuring out if we're a 3887 */
+	/* TODO: should just stick the identification in the device table */
+	i = intf->altsetting->desc.bNumEndpoints;
+	recognized_pipes = 0;
+	while (i--) {
+		switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
+		case P54U_PIPE_DATA:
+		case P54U_PIPE_MGMT:
+		case P54U_PIPE_BRG:
+		case P54U_PIPE_DEV:
+		case P54U_PIPE_DATA | USB_DIR_IN:
+		case P54U_PIPE_MGMT | USB_DIR_IN:
+		case P54U_PIPE_BRG | USB_DIR_IN:
+		case P54U_PIPE_DEV | USB_DIR_IN:
+		case P54U_PIPE_INT | USB_DIR_IN:
+			recognized_pipes++;
+		}
+	}
+	priv->common.open = p54u_open;
+
+	if (recognized_pipes < P54U_PIPE_NUMBER) {
+		priv->hw_type = P54U_3887;
+		priv->common.tx = p54u_tx_3887;
+	} else {
+		dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
+		priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
+		priv->common.tx = p54u_tx_net2280;
+	}
+	priv->common.stop = p54u_stop;
+
+	if (priv->hw_type)
+		err = p54u_upload_firmware_3887(dev);
+	else
+		err = p54u_upload_firmware_net2280(dev);
+	if (err)
+		goto err_free_dev;
+
+	err = p54u_read_eeprom(dev);
+	if (err)
+		goto err_free_dev;
+
+	if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+		u8 perm_addr[ETH_ALEN];
+
+		printk(KERN_WARNING "prism54usb: Invalid hwaddr! Using randomly generated MAC addr\n");
+		random_ether_addr(perm_addr);
+		SET_IEEE80211_PERM_ADDR(dev, perm_addr);
+	}
+
+	skb_queue_head_init(&priv->rx_queue);
+
+	err = ieee80211_register_hw(dev);
+	if (err) {
+		printk(KERN_ERR "prism54usb: Cannot register netdevice\n");
+		goto err_free_dev;
+	}
+
+	printk(KERN_INFO "%s: hwaddr %s, isl38%02x\n",
+	       wiphy_name(dev->wiphy),
+	       print_mac(mac, dev->wiphy->perm_addr),
+	       priv->common.version);
+
+	return 0;
+
+ err_free_dev:
+	ieee80211_free_hw(dev);
+	usb_set_intfdata(intf, NULL);
+	usb_put_dev(udev);
+	return err;
+}
+
+static void __devexit p54u_disconnect(struct usb_interface *intf)
+{
+	struct ieee80211_hw *dev = usb_get_intfdata(intf);
+	struct p54u_priv *priv;
+
+	if (!dev)
+		return;
+
+	ieee80211_unregister_hw(dev);
+
+	priv = dev->priv;
+	usb_put_dev(interface_to_usbdev(intf));
+	p54_free_common(dev);
+	ieee80211_free_hw(dev);
+}
+
+static struct usb_driver p54u_driver = {
+	.name	= "prism54usb",
+	.id_table = p54u_table,
+	.probe = p54u_probe,
+	.disconnect = p54u_disconnect,
+};
+
+static int __init p54u_init(void)
+{
+	return usb_register(&p54u_driver);
+}
+
+static void __exit p54u_exit(void)
+{
+	usb_deregister(&p54u_driver);
+}
+
+module_init(p54u_init);
+module_exit(p54u_exit);
diff --git a/drivers/net/wireless/p54usb.h b/drivers/net/wireless/p54usb.h
new file mode 100644
index 0000000..d1896b3
--- /dev/null
+++ b/drivers/net/wireless/p54usb.h
@@ -0,0 +1,133 @@
+#ifndef PRISM54USB_H
+#define PRISM54USB_H
+
+/*
+ * Defines for USB based mac80211 Prism54 driver
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * 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.
+ */
+
+/* for isl3886 register definitions used on ver 1 devices */
+#include "p54pci.h"
+#include "net2280.h"
+
+/* pci */
+#define NET2280_BASE		0x10000000
+#define NET2280_BASE2		0x20000000
+
+/* gpio */
+#define P54U_BRG_POWER_UP	(1 << GPIO0_DATA)
+#define P54U_BRG_POWER_DOWN	(1 << GPIO1_DATA)
+
+/* devinit */
+#define NET2280_CLK_4Mhz	(15 << LOCAL_CLOCK_FREQUENCY)
+#define NET2280_CLK_30Mhz	(2 << LOCAL_CLOCK_FREQUENCY)
+#define NET2280_CLK_60Mhz	(1 << LOCAL_CLOCK_FREQUENCY)
+#define NET2280_CLK_STOP	(0 << LOCAL_CLOCK_FREQUENCY)
+#define NET2280_PCI_ENABLE	(1 << PCI_ENABLE)
+#define NET2280_PCI_SOFT_RESET	(1 << PCI_SOFT_RESET)
+
+/* endpoints */
+#define NET2280_CLEAR_NAK_OUT_PACKETS_MODE	(1 << CLEAR_NAK_OUT_PACKETS_MODE)
+#define NET2280_FIFO_FLUSH			(1 << FIFO_FLUSH)
+
+/* irq */
+#define NET2280_USB_INTERRUPT_ENABLE		(1 << USB_INTERRUPT_ENABLE)
+#define NET2280_PCI_INTA_INTERRUPT		(1 << PCI_INTA_INTERRUPT)
+#define NET2280_PCI_INTA_INTERRUPT_ENABLE	(1 << PCI_INTA_INTERRUPT_ENABLE)
+
+/* registers */
+#define NET2280_DEVINIT		0x00
+#define NET2280_USBIRQENB1	0x24
+#define NET2280_IRQSTAT1	0x2c
+#define NET2280_FIFOCTL         0x38
+#define NET2280_GPIOCTL		0x50
+#define NET2280_RELNUM		0x88
+#define NET2280_EPA_RSP		0x324
+#define NET2280_EPA_STAT	0x32c
+#define NET2280_EPB_STAT	0x34c
+#define NET2280_EPC_RSP		0x364
+#define NET2280_EPC_STAT	0x36c
+#define NET2280_EPD_STAT	0x38c
+
+#define NET2280_EPA_CFG     0x320
+#define NET2280_EPB_CFG     0x340
+#define NET2280_EPC_CFG     0x360
+#define NET2280_EPD_CFG     0x380
+#define NET2280_EPE_CFG     0x3A0
+#define NET2280_EPF_CFG     0x3C0
+#define P54U_DEV_BASE 0x40000000
+
+struct net2280_tx_hdr {
+	__le32 device_addr;
+	__le16 len;
+	__le16 follower;	/* ? */
+	u8 padding[8];
+} __attribute__((packed));
+
+/* Some flags for the isl hardware registers controlling DMA inside the
+ * chip */
+#define ISL38XX_DMA_STATUS_DONE			0x00000001
+#define ISL38XX_DMA_STATUS_READY		0x00000002
+#define NET2280_EPA_FIFO_PCI_ADDR		0x20000000
+#define ISL38XX_DMA_MASTER_CONTROL_TRIGGER	0x00000004
+
+enum net2280_op_type {
+	NET2280_BRG_U32		= 0x001F,
+	NET2280_BRG_CFG_U32	= 0x000F,
+	NET2280_BRG_CFG_U16	= 0x0003,
+	NET2280_DEV_U32		= 0x080F,
+	NET2280_DEV_CFG_U32	= 0x088F,
+	NET2280_DEV_CFG_U16	= 0x0883
+};
+
+#define P54U_FW_BLOCK 2048
+
+#define X2_SIGNATURE "x2  "
+#define X2_SIGNATURE_SIZE 4
+
+struct x2_header {
+	u8 signature[X2_SIGNATURE_SIZE];
+	__le32 fw_load_addr;
+	__le32 fw_length;
+	__le32 crc;
+} __attribute__((packed));
+
+/* pipes 3 and 4 are not used by the driver */
+#define P54U_PIPE_NUMBER 9
+
+enum p54u_pipe_addr {
+        P54U_PIPE_DATA = 0x01,
+        P54U_PIPE_MGMT = 0x02,
+        P54U_PIPE_3 = 0x03,
+        P54U_PIPE_4 = 0x04,
+        P54U_PIPE_BRG = 0x0d,
+        P54U_PIPE_DEV = 0x0e,
+        P54U_PIPE_INT = 0x0f
+};
+
+struct p54u_rx_info {
+	struct urb *urb;
+	struct ieee80211_hw *dev;
+};
+
+struct p54u_priv {
+	struct p54_common common;
+	struct usb_device *udev;
+	enum {
+		P54U_NET2280 = 0,
+		P54U_3887
+	} hw_type;
+
+	spinlock_t lock;
+	struct sk_buff_head rx_queue;
+};
+
+#endif /* PRISM54USB_H */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 585f599..6d80ca4 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -1753,7 +1753,7 @@
 	int rvalue;
 	enum oid_num_t n = dwrq->flags;
 
-	rvalue = mgt_get_request((islpci_private *) ndev->priv, n, 0, NULL, &r);
+	rvalue = mgt_get_request(netdev_priv(ndev), n, 0, NULL, &r);
 	dwrq->length = mgt_response_to_str(n, &r, extra);
 	if ((isl_oid[n].flags & OID_FLAG_TYPE) != OID_TYPE_U32)
 		kfree(r.ptr);
@@ -1766,7 +1766,7 @@
 {
 	u32 oid = uwrq[0], u = uwrq[1];
 
-	return mgt_set_request((islpci_private *) ndev->priv, oid, 0, &u);
+	return mgt_set_request(netdev_priv(ndev), oid, 0, &u);
 }
 
 static int
@@ -1775,7 +1775,7 @@
 {
 	u32 oid = dwrq->flags;
 
-	return mgt_set_request((islpci_private *) ndev->priv, oid, 0, extra);
+	return mgt_set_request(netdev_priv(ndev), oid, 0, extra);
 }
 
 void
@@ -2029,12 +2029,12 @@
 format_event(islpci_private *priv, char *dest, const char *str,
 	     const struct obj_mlme *mlme, u16 *length, int error)
 {
-	const u8 *a = mlme->address;
+	DECLARE_MAC_BUF(mac);
 	int n = snprintf(dest, IW_CUSTOM_MAX,
-			 "%s %s %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X %s (%2.2X)",
+			 "%s %s %s %s (%2.2X)",
 			 str,
 			 ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"),
-			 a[0], a[1], a[2], a[3], a[4], a[5],
+			 print_mac(mac, mlme->address),
 			 (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ")
 			  : ""), mlme->code);
 	BUG_ON(n > IW_CUSTOM_MAX);
@@ -2105,15 +2105,13 @@
 #define WLAN_EID_GENERIC 0xdd
 static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };
 
-#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
-#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
-
 static void
 prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
 		       u8 *wpa_ie, size_t wpa_ie_len)
 {
 	struct list_head *ptr;
 	struct islpci_bss_wpa_ie *bss = NULL;
+	DECLARE_MAC_BUF(mac);
 
 	if (wpa_ie_len > MAX_WPA_IE_LEN)
 		wpa_ie_len = MAX_WPA_IE_LEN;
@@ -2154,8 +2152,8 @@
 		bss->wpa_ie_len = wpa_ie_len;
 		bss->last_update = jiffies;
 	} else {
-		printk(KERN_DEBUG "Failed to add BSS WPA entry for " MACSTR
-		       "\n", MAC2STR(bssid));
+		printk(KERN_DEBUG "Failed to add BSS WPA entry for "
+		       "%s\n", print_mac(mac, bssid));
 	}
 
 	/* expire old entries from WPA list */
@@ -2221,6 +2219,7 @@
 {
 	struct ieee80211_beacon_phdr *hdr;
 	u8 *pos, *end;
+	DECLARE_MAC_BUF(mac);
 
 	if (!priv->wpa)
 		return;
@@ -2231,7 +2230,7 @@
 	while (pos < end) {
 		if (pos + 2 + pos[1] > end) {
 			printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed "
-			       "for " MACSTR "\n", MAC2STR(addr));
+			       "for %s\n", print_mac(mac, addr));
 			return;
 		}
 		if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
@@ -2270,6 +2269,7 @@
 	size_t len = 0; /* u16, better? */
 	u8 *payload = NULL, *pos = NULL;
 	int ret;
+	DECLARE_MAC_BUF(mac);
 
 	/* I think all trapable objects are listed here.
 	 * Some oids have a EX version. The difference is that they are emitted
@@ -2358,14 +2358,8 @@
 			break;
 
 		memcpy(&confirm->address, mlmeex->address, ETH_ALEN);
-		printk(KERN_DEBUG "Authenticate from: address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
-				mlmeex->address[0],
-				mlmeex->address[1],
-				mlmeex->address[2],
-				mlmeex->address[3],
-				mlmeex->address[4],
-				mlmeex->address[5]
-				);
+		printk(KERN_DEBUG "Authenticate from: address:\t%s\n",
+		       print_mac(mac, mlmeex->address));
 		confirm->id = -1; /* or mlmeex->id ? */
 		confirm->state = 0; /* not used */
 		confirm->code = 0;
@@ -2410,15 +2404,8 @@
 		wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
 
 		if (!wpa_ie_len) {
-			printk(KERN_DEBUG "No WPA IE found from "
-					"address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
-				mlmeex->address[0],
-				mlmeex->address[1],
-				mlmeex->address[2],
-				mlmeex->address[3],
-				mlmeex->address[4],
-				mlmeex->address[5]
-				);
+			printk(KERN_DEBUG "No WPA IE found from address:\t%s\n",
+			       print_mac(mac, mlmeex->address));
 			kfree(confirm);
 			break;
 		}
@@ -2454,15 +2441,8 @@
 		wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
 
 		if (!wpa_ie_len) {
-			printk(KERN_DEBUG "No WPA IE found from "
-					"address:\t%02x:%02x:%02x:%02x:%02x:%02x\n",
-				mlmeex->address[0],
-				mlmeex->address[1],
-				mlmeex->address[2],
-				mlmeex->address[3],
-				mlmeex->address[4],
-				mlmeex->address[5]
-				);
+			printk(KERN_DEBUG "No WPA IE found from address:\t%s\n",
+			       print_mac(mac, mlmeex->address));
 			kfree(confirm);
 			break;
 		}
@@ -3239,10 +3219,9 @@
 };
 
 const struct iw_handler_def prism54_handler_def = {
-	.num_standard = sizeof (prism54_handler) / sizeof (iw_handler),
-	.num_private = sizeof (prism54_private_handler) / sizeof (iw_handler),
-	.num_private_args =
-	    sizeof (prism54_private_args) / sizeof (struct iw_priv_args),
+	.num_standard = ARRAY_SIZE(prism54_handler),
+	.num_private = ARRAY_SIZE(prism54_private_handler),
+	.num_private_args = ARRAY_SIZE(prism54_private_args),
 	.standard = (iw_handler *) prism54_handler,
 	.private = (iw_handler *) prism54_private_handler,
 	.private_args = (struct iw_priv_args *) prism54_private_args,
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index 0847953..219dd65 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -808,7 +808,6 @@
 	if (!ndev)
 		return ndev;
 
-	SET_MODULE_OWNER(ndev);
 	pci_set_drvdata(pdev, ndev);
 #if defined(SET_NETDEV_DEV)
 	SET_NETDEV_DEV(ndev, &pdev->dev);
diff --git a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c
index 4278032..57a4ac3 100644
--- a/drivers/net/wireless/prism54/oid_mgt.c
+++ b/drivers/net/wireless/prism54/oid_mgt.c
@@ -244,13 +244,11 @@
 	/* Alloc the cache */
 	for (i = 0; i < OID_NUM_LAST; i++) {
 		if (isl_oid[i].flags & OID_FLAG_CACHED) {
-			priv->mib[i] = kmalloc(isl_oid[i].size *
+			priv->mib[i] = kzalloc(isl_oid[i].size *
 					       (isl_oid[i].range + 1),
 					       GFP_KERNEL);
 			if (!priv->mib[i])
 				return -ENOMEM;
-			memset(priv->mib[i], 0,
-			       isl_oid[i].size * (isl_oid[i].range + 1));
 		} else
 			priv->mib[i] = NULL;
 	}
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 3be6242..f87fe10 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -314,7 +314,7 @@
     if (!dev)
 	    goto fail_alloc_dev;
 
-    local = dev->priv;
+    local = netdev_priv(dev);
     local->finder = p_dev;
 
     /* The io structure describes IO port mapping. None used here */
@@ -356,7 +356,6 @@
     dev->set_multicast_list = &set_multicast_list;
 
     DEBUG(2,"ray_cs ray_attach calling ether_setup.)\n");
-    SET_MODULE_OWNER(dev);
     dev->init = &ray_dev_init;
     dev->open = &ray_open;
     dev->stop = &ray_dev_close;
@@ -388,7 +387,7 @@
 
     ray_release(link);
 
-    local = (ray_dev_t *)dev->priv;
+    local = netdev_priv(dev);
     del_timer(&local->timer);
 
     if (link->priv) {
@@ -412,7 +411,8 @@
     win_req_t req;
     memreq_t mem;
     struct net_device *dev = (struct net_device *)link->priv;
-    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    ray_dev_t *local = netdev_priv(dev);
+    DECLARE_MAC_BUF(mac);
 
     DEBUG(1, "ray_config(0x%p)\n", link);
 
@@ -483,10 +483,8 @@
     strcpy(local->node.dev_name, dev->name);
     link->dev_node = &local->node;
 
-    printk(KERN_INFO "%s: RayLink, irq %d, hw_addr ",
-       dev->name, dev->irq);
-    for (i = 0; i < 6; i++)
-    printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+    printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %s\n",
+       dev->name, dev->irq, print_mac(mac, dev->dev_addr));
 
     return 0;
 
@@ -520,7 +518,7 @@
     int i;
     UCHAR *p;
     struct ccs __iomem *pccs;
-    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    ray_dev_t *local = netdev_priv(dev);
     struct pcmcia_device *link = local->finder;
     DEBUG(1, "ray_init(0x%p)\n", dev);
     if (!(pcmcia_dev_present(link))) {
@@ -581,7 +579,7 @@
 static int dl_startup_params(struct net_device *dev)
 {
     int ccsindex;
-    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    ray_dev_t *local = netdev_priv(dev);
     struct ccs __iomem *pccs;
     struct pcmcia_device *link = local->finder;
 
@@ -786,7 +784,7 @@
 static void ray_release(struct pcmcia_device *link)
 {
     struct net_device *dev = link->priv; 
-    ray_dev_t *local = dev->priv;
+    ray_dev_t *local = netdev_priv(dev);
     int i;
     
     DEBUG(1, "ray_release(0x%p)\n", link);
@@ -834,7 +832,7 @@
 #ifdef RAY_IMMEDIATE_INIT
     int i;
 #endif	/* RAY_IMMEDIATE_INIT */
-    ray_dev_t *local = dev->priv;
+    ray_dev_t *local = netdev_priv(dev);
     struct pcmcia_device *link = local->finder;
 
     DEBUG(1,"ray_dev_init(dev=%p)\n",dev);
@@ -868,7 +866,7 @@
 /*===========================================================================*/
 static int ray_dev_config(struct net_device *dev, struct ifmap *map)
 {
-    ray_dev_t *local = dev->priv;
+    ray_dev_t *local = netdev_priv(dev);
     struct pcmcia_device *link = local->finder;
     /* Dummy routine to satisfy device structure */
     DEBUG(1,"ray_dev_config(dev=%p,ifmap=%p)\n",dev,map);
@@ -882,7 +880,7 @@
 /*===========================================================================*/
 static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-    ray_dev_t *local = dev->priv;
+    ray_dev_t *local = netdev_priv(dev);
     struct pcmcia_device *link = local->finder;
     short length = skb->len;
 
@@ -925,7 +923,7 @@
 static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, 
                 UCHAR msg_type)
 {
-    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    ray_dev_t *local = netdev_priv(dev);
     struct ccs __iomem *pccs;
     int ccsindex;
     int offset;
@@ -1099,7 +1097,7 @@
 			struct iw_freq *fwrq,
 			char *extra)
 {
-	ray_dev_t *local = (ray_dev_t *)dev->priv;
+	ray_dev_t *local = netdev_priv(dev);
 	int err = -EINPROGRESS;		/* Call commit handler */
 
 	/* Reject if card is already initialised */
@@ -1124,7 +1122,7 @@
 			struct iw_freq *fwrq,
 			char *extra)
 {
-	ray_dev_t *local = (ray_dev_t *)dev->priv;
+	ray_dev_t *local = netdev_priv(dev);
 
 	fwrq->m = local->sparm.b5.a_hop_pattern;
 	fwrq->e = 0;
@@ -1140,7 +1138,7 @@
 			 struct iw_point *dwrq,
 			 char *extra)
 {
-	ray_dev_t *local = (ray_dev_t *)dev->priv;
+	ray_dev_t *local = netdev_priv(dev);
 
 	/* Reject if card is already initialised */
 	if(local->card_status != CARD_AWAITING_PARAM)
@@ -1173,7 +1171,7 @@
 			 struct iw_point *dwrq,
 			 char *extra)
 {
-	ray_dev_t *local = (ray_dev_t *)dev->priv;
+	ray_dev_t *local = netdev_priv(dev);
 
 	/* Get the essid that was set */
 	memcpy(extra, local->sparm.b5.a_current_ess_id, IW_ESSID_MAX_SIZE);
@@ -1194,7 +1192,7 @@
 			struct sockaddr *awrq,
 			char *extra)
 {
-	ray_dev_t *local = (ray_dev_t *)dev->priv;
+	ray_dev_t *local = netdev_priv(dev);
 
 	memcpy(awrq->sa_data, local->bss_id, ETH_ALEN);
 	awrq->sa_family = ARPHRD_ETHER;
@@ -1211,7 +1209,7 @@
 			struct iw_param *vwrq,
 			char *extra)
 {
-	ray_dev_t *local = (ray_dev_t *)dev->priv;
+	ray_dev_t *local = netdev_priv(dev);
 
 	/* Reject if card is already initialised */
 	if(local->card_status != CARD_AWAITING_PARAM)
@@ -1240,7 +1238,7 @@
 			struct iw_param *vwrq,
 			char *extra)
 {
-	ray_dev_t *local = (ray_dev_t *)dev->priv;
+	ray_dev_t *local = netdev_priv(dev);
 
 	if(local->net_default_tx_rate == 3)
 		vwrq->value = 2000000;		/* Hum... */
@@ -1260,7 +1258,7 @@
 		       struct iw_param *vwrq,
 		       char *extra)
 {
-	ray_dev_t *local = (ray_dev_t *)dev->priv;
+	ray_dev_t *local = netdev_priv(dev);
 	int rthr = vwrq->value;
 
 	/* Reject if card is already initialised */
@@ -1290,7 +1288,7 @@
 		       struct iw_param *vwrq,
 		       char *extra)
 {
-	ray_dev_t *local = (ray_dev_t *)dev->priv;
+	ray_dev_t *local = netdev_priv(dev);
 
 	vwrq->value = (local->sparm.b5.a_rts_threshold[0] << 8)
 		+ local->sparm.b5.a_rts_threshold[1];
@@ -1309,7 +1307,7 @@
 			struct iw_param *vwrq,
 			char *extra)
 {
-	ray_dev_t *local = (ray_dev_t *)dev->priv;
+	ray_dev_t *local = netdev_priv(dev);
 	int fthr = vwrq->value;
 
 	/* Reject if card is already initialised */
@@ -1338,7 +1336,7 @@
 			struct iw_param *vwrq,
 			char *extra)
 {
-	ray_dev_t *local = (ray_dev_t *)dev->priv;
+	ray_dev_t *local = netdev_priv(dev);
 
 	vwrq->value = (local->sparm.b5.a_frag_threshold[0] << 8)
 		+ local->sparm.b5.a_frag_threshold[1];
@@ -1357,7 +1355,7 @@
 			__u32 *uwrq,
 			char *extra)
 {
-	ray_dev_t *local = (ray_dev_t *)dev->priv;
+	ray_dev_t *local = netdev_priv(dev);
 	int err = -EINPROGRESS;		/* Call commit handler */
 	char card_mode = 1;
 
@@ -1389,7 +1387,7 @@
 			__u32 *uwrq,
 			char *extra)
 {
-	ray_dev_t *local = (ray_dev_t *)dev->priv;
+	ray_dev_t *local = netdev_priv(dev);
 
 	if(local->sparm.b5.a_network_type)
 		*uwrq = IW_MODE_INFRA;
@@ -1492,7 +1490,7 @@
  */
 static iw_stats * ray_get_wireless_stats(struct net_device *	dev)
 {
-  ray_dev_t *	local = (ray_dev_t *) dev->priv;
+  ray_dev_t *	local = netdev_priv(dev);
   struct pcmcia_device *link = local->finder;
   struct status __iomem *p = local->sram + STATUS_BASE;
 
@@ -1568,9 +1566,9 @@
 
 static const struct iw_handler_def	ray_handler_def =
 {
-	.num_standard	= sizeof(ray_handler)/sizeof(iw_handler),
-	.num_private	= sizeof(ray_private_handler)/sizeof(iw_handler),
-	.num_private_args = sizeof(ray_private_args)/sizeof(struct iw_priv_args),
+	.num_standard	= ARRAY_SIZE(ray_handler),
+	.num_private	= ARRAY_SIZE(ray_private_handler),
+	.num_private_args = ARRAY_SIZE(ray_private_args),
 	.standard	= ray_handler,
 	.private	= ray_private_handler,
 	.private_args	= ray_private_args,
@@ -1580,7 +1578,7 @@
 /*===========================================================================*/
 static int ray_open(struct net_device *dev)
 {
-    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    ray_dev_t *local = netdev_priv(dev);
     struct pcmcia_device *link;
     link = local->finder;
     
@@ -1614,7 +1612,7 @@
 /*===========================================================================*/
 static int ray_dev_close(struct net_device *dev)
 {
-    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    ray_dev_t *local = netdev_priv(dev);
     struct pcmcia_device *link;
     link = local->finder;
 
@@ -1773,7 +1771,7 @@
 /*===========================================================================*/
 static struct net_device_stats *ray_get_stats(struct net_device *dev)
 {
-    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    ray_dev_t *local = netdev_priv(dev);
     struct pcmcia_device *link = local->finder;
     struct status __iomem *p = local->sram + STATUS_BASE;
     if (!(pcmcia_dev_present(link))) {
@@ -1803,7 +1801,7 @@
 /*===========================================================================*/
 static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len)
 {
-    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    ray_dev_t *local = netdev_priv(dev);
     struct pcmcia_device *link = local->finder;
     int ccsindex;
     int i;
@@ -1840,7 +1838,7 @@
     int ccsindex;
     struct ccs __iomem *pccs;
     int i = 0;
-    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    ray_dev_t *local = netdev_priv(dev);
     struct pcmcia_device *link = local->finder;
     void __iomem *p = local->sram + HOST_TO_ECF_BASE;
 
@@ -1884,7 +1882,7 @@
 /*===========================================================================*/
 static void set_multicast_list(struct net_device *dev)
 {
-    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    ray_dev_t *local = netdev_priv(dev);
     UCHAR promisc;
 
     DEBUG(2,"ray_cs set_multicast_list(%p)\n",dev);
@@ -1935,7 +1933,7 @@
 
     DEBUG(4,"ray_cs: interrupt for *dev=%p\n",dev);
 
-    local = (ray_dev_t *)dev->priv;
+    local = netdev_priv(dev);
     link = (struct pcmcia_device *)local->finder;
     if (!pcmcia_dev_present(link)) {
         DEBUG(2,"ray_cs interrupt from device not present or suspended.\n");
@@ -2165,7 +2163,7 @@
 {
     struct sk_buff *skb = NULL;
     struct rcs __iomem *prcslink = prcs;
-    ray_dev_t *local = dev->priv;
+    ray_dev_t *local = netdev_priv(dev);
     UCHAR *rx_ptr;
     int total_len;
     int tmp;
@@ -2611,6 +2609,7 @@
     UCHAR *p;
     struct freq_hop_element *pfh;
     UCHAR c[33];
+    DECLARE_MAC_BUF(mac);
 
     link = this_device;
     if (!link)
@@ -2618,7 +2617,7 @@
     dev = (struct net_device *)link->priv;
     if (!dev)
     	return 0;
-    local = (ray_dev_t *)dev->priv;
+    local = netdev_priv(dev);
     if (!local)
     	return 0;
 
@@ -2640,9 +2639,8 @@
                    nettype[local->sparm.b5.a_network_type], c);
 
     p = local->bss_id;
-    len += sprintf(buf + len, 
-                   "BSSID                = %02x:%02x:%02x:%02x:%02x:%02x\n",
-                   p[0],p[1],p[2],p[3],p[4],p[5]);
+    len += sprintf(buf + len, "BSSID                = %s\n",
+                   print_mac(mac, p));
 
     len += sprintf(buf + len, "Country code         = %d\n", 
                    local->sparm.b5.a_curr_country_code);
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
new file mode 100644
index 0000000..da05b1f
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -0,0 +1,130 @@
+config RT2X00
+	tristate "Ralink driver support"
+	depends on MAC80211 && WLAN_80211 && EXPERIMENTAL
+	---help---
+	  This will enable the experimental support for the Ralink drivers,
+	  developed in the rt2x00 project <http://rt2x00.serialmonkey.com>.
+
+	  These drivers will make use of the Devicescape ieee80211 stack.
+
+	  When building one of the individual drivers, the rt2x00 library
+	  will also be created. That library (when the driver is built as
+	  a module) will be called "rt2x00lib.ko".
+
+config RT2X00_LIB
+	tristate
+	depends on RT2X00
+
+config RT2X00_LIB_PCI
+	tristate
+	depends on RT2X00
+	select RT2X00_LIB
+
+config RT2X00_LIB_USB
+	tristate
+	depends on RT2X00
+	select RT2X00_LIB
+
+config RT2X00_LIB_FIRMWARE
+	boolean
+	depends on RT2X00_LIB
+	select CRC_ITU_T
+	select FW_LOADER
+
+config RT2X00_LIB_RFKILL
+	boolean
+	depends on RT2X00_LIB
+	select RFKILL
+	select INPUT_POLLDEV
+
+config RT2400PCI
+	tristate "Ralink rt2400 pci/pcmcia support"
+	depends on RT2X00 && PCI
+	select RT2X00_LIB_PCI
+	select EEPROM_93CX6
+	---help---
+	  This is an experimental driver for the Ralink rt2400 wireless chip.
+
+	  When compiled as a module, this driver will be called "rt2400pci.ko".
+
+config RT2400PCI_RFKILL
+	bool "RT2400 rfkill support"
+	depends on RT2400PCI
+	select RT2X00_LIB_RFKILL
+	---help---
+	  This adds support for integrated rt2400 devices that feature a
+	  hardware button to control the radio state.
+	  This feature depends on the RF switch subsystem rfkill.
+
+config RT2500PCI
+	tristate "Ralink rt2500 pci/pcmcia support"
+	depends on RT2X00 && PCI
+	select RT2X00_LIB_PCI
+	select EEPROM_93CX6
+	---help---
+	  This is an experimental driver for the Ralink rt2500 wireless chip.
+
+	  When compiled as a module, this driver will be called "rt2500pci.ko".
+
+config RT2500PCI_RFKILL
+	bool "RT2500 rfkill support"
+	depends on RT2500PCI
+	select RT2X00_LIB_RFKILL
+	---help---
+	  This adds support for integrated rt2500 devices that feature a
+	  hardware button to control the radio state.
+	  This feature depends on the RF switch subsystem rfkill.
+
+config RT61PCI
+	tristate "Ralink rt61 pci/pcmcia support"
+	depends on RT2X00 && PCI
+	select RT2X00_LIB_PCI
+	select RT2X00_LIB_FIRMWARE
+	select EEPROM_93CX6
+	---help---
+	  This is an experimental driver for the Ralink rt61 wireless chip.
+
+	  When compiled as a module, this driver will be called "rt61pci.ko".
+
+config RT61PCI_RFKILL
+	bool "RT61 rfkill support"
+	depends on RT61PCI
+	select RT2X00_LIB_RFKILL
+	---help---
+	  This adds support for integrated rt61 devices that feature a
+	  hardware button to control the radio state.
+	  This feature depends on the RF switch subsystem rfkill.
+
+config RT2500USB
+	tristate "Ralink rt2500 usb support"
+	depends on RT2X00 && USB
+	select RT2X00_LIB_USB
+	---help---
+	  This is an experimental driver for the Ralink rt2500 wireless chip.
+
+	  When compiled as a module, this driver will be called "rt2500usb.ko".
+
+config RT73USB
+	tristate "Ralink rt73 usb support"
+	depends on RT2X00 && USB
+	select RT2X00_LIB_USB
+	select RT2X00_LIB_FIRMWARE
+	---help---
+	  This is an experimental driver for the Ralink rt73 wireless chip.
+
+	  When compiled as a module, this driver will be called "rt73usb.ko".
+
+config RT2X00_LIB_DEBUGFS
+	bool "Ralink debugfs support"
+	depends on RT2X00_LIB && MAC80211_DEBUGFS
+	---help---
+	  Enable creation of debugfs files for the rt2x00 drivers.
+	  These debugfs files support both reading and writing of the
+	  most important register types of the rt2x00 devices.
+
+config RT2X00_DEBUG
+	bool "Ralink debug output"
+	depends on RT2X00_LIB
+	---help---
+	  Enable debugging output for all rt2x00 modules
+
diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile
new file mode 100644
index 0000000..30d654a
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/Makefile
@@ -0,0 +1,22 @@
+rt2x00lib-objs := rt2x00dev.o rt2x00mac.o rt2x00config.o
+
+ifeq ($(CONFIG_RT2X00_LIB_DEBUGFS),y)
+	rt2x00lib-objs += rt2x00debug.o
+endif
+
+ifeq ($(CONFIG_RT2X00_LIB_RFKILL),y)
+	rt2x00lib-objs += rt2x00rfkill.o
+endif
+
+ifeq ($(CONFIG_RT2X00_LIB_FIRMWARE),y)
+	rt2x00lib-objs += rt2x00firmware.o
+endif
+
+obj-$(CONFIG_RT2X00_LIB)	+= rt2x00lib.o
+obj-$(CONFIG_RT2X00_LIB_PCI)	+= rt2x00pci.o
+obj-$(CONFIG_RT2X00_LIB_USB)	+= rt2x00usb.o
+obj-$(CONFIG_RT2400PCI)		+= rt2400pci.o
+obj-$(CONFIG_RT2500PCI)		+= rt2500pci.o
+obj-$(CONFIG_RT61PCI)		+= rt61pci.o
+obj-$(CONFIG_RT2500USB)		+= rt2500usb.o
+obj-$(CONFIG_RT73USB)		+= rt73usb.o
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
new file mode 100644
index 0000000..31c1dd27
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -0,0 +1,1664 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2400pci
+	Abstract: rt2400pci device specific routines.
+	Supported chipsets: RT2460.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2400pci"
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/eeprom_93cx6.h>
+
+#include "rt2x00.h"
+#include "rt2x00pci.h"
+#include "rt2400pci.h"
+
+/*
+ * Register access.
+ * All access to the CSR registers will go through the methods
+ * rt2x00pci_register_read and rt2x00pci_register_write.
+ * BBP and RF register require indirect register access,
+ * and use the CSR registers BBPCSR and RFCSR to achieve this.
+ * These indirect registers work with busy bits,
+ * and we will try maximal REGISTER_BUSY_COUNT times to access
+ * the register while taking a REGISTER_BUSY_DELAY us delay
+ * between each attampt. When the busy bit is still set at that time,
+ * the access attempt is considered to have failed,
+ * and we will print an error.
+ */
+static u32 rt2400pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+	unsigned int i;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2x00pci_register_read(rt2x00dev, BBPCSR, &reg);
+		if (!rt2x00_get_field32(reg, BBPCSR_BUSY))
+			break;
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	return reg;
+}
+
+static void rt2400pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
+				const unsigned int word, const u8 value)
+{
+	u32 reg;
+
+	/*
+	 * Wait until the BBP becomes ready.
+	 */
+	reg = rt2400pci_bbp_check(rt2x00dev);
+	if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+		ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
+		return;
+	}
+
+	/*
+	 * Write the data into the BBP.
+	 */
+	reg = 0;
+	rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
+	rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+	rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+	rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
+
+	rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+}
+
+static void rt2400pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
+			       const unsigned int word, u8 *value)
+{
+	u32 reg;
+
+	/*
+	 * Wait until the BBP becomes ready.
+	 */
+	reg = rt2400pci_bbp_check(rt2x00dev);
+	if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+		ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
+		return;
+	}
+
+	/*
+	 * Write the request into the BBP.
+	 */
+	reg = 0;
+	rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+	rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+	rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
+
+	rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+
+	/*
+	 * Wait until the BBP becomes ready.
+	 */
+	reg = rt2400pci_bbp_check(rt2x00dev);
+	if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+		ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
+		*value = 0xff;
+		return;
+	}
+
+	*value = rt2x00_get_field32(reg, BBPCSR_VALUE);
+}
+
+static void rt2400pci_rf_write(const struct rt2x00_dev *rt2x00dev,
+			       const unsigned int word, const u32 value)
+{
+	u32 reg;
+	unsigned int i;
+
+	if (!word)
+		return;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2x00pci_register_read(rt2x00dev, RFCSR, &reg);
+		if (!rt2x00_get_field32(reg, RFCSR_BUSY))
+			goto rf_write;
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n");
+	return;
+
+rf_write:
+	reg = 0;
+	rt2x00_set_field32(&reg, RFCSR_VALUE, value);
+	rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
+	rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
+	rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
+
+	rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
+	rt2x00_rf_write(rt2x00dev, word, value);
+}
+
+static void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
+{
+	struct rt2x00_dev *rt2x00dev = eeprom->data;
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, CSR21, &reg);
+
+	eeprom->reg_data_in = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_IN);
+	eeprom->reg_data_out = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_OUT);
+	eeprom->reg_data_clock =
+	    !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_CLOCK);
+	eeprom->reg_chip_select =
+	    !!rt2x00_get_field32(reg, CSR21_EEPROM_CHIP_SELECT);
+}
+
+static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
+{
+	struct rt2x00_dev *rt2x00dev = eeprom->data;
+	u32 reg = 0;
+
+	rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_IN, !!eeprom->reg_data_in);
+	rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_OUT, !!eeprom->reg_data_out);
+	rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_CLOCK,
+			   !!eeprom->reg_data_clock);
+	rt2x00_set_field32(&reg, CSR21_EEPROM_CHIP_SELECT,
+			   !!eeprom->reg_chip_select);
+
+	rt2x00pci_register_write(rt2x00dev, CSR21, reg);
+}
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+#define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
+
+static void rt2400pci_read_csr(const struct rt2x00_dev *rt2x00dev,
+			       const unsigned int word, u32 *data)
+{
+	rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static void rt2400pci_write_csr(const struct rt2x00_dev *rt2x00dev,
+				const unsigned int word, u32 data)
+{
+	rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static const struct rt2x00debug rt2400pci_rt2x00debug = {
+	.owner	= THIS_MODULE,
+	.csr	= {
+		.read		= rt2400pci_read_csr,
+		.write		= rt2400pci_write_csr,
+		.word_size	= sizeof(u32),
+		.word_count	= CSR_REG_SIZE / sizeof(u32),
+	},
+	.eeprom	= {
+		.read		= rt2x00_eeprom_read,
+		.write		= rt2x00_eeprom_write,
+		.word_size	= sizeof(u16),
+		.word_count	= EEPROM_SIZE / sizeof(u16),
+	},
+	.bbp	= {
+		.read		= rt2400pci_bbp_read,
+		.write		= rt2400pci_bbp_write,
+		.word_size	= sizeof(u8),
+		.word_count	= BBP_SIZE / sizeof(u8),
+	},
+	.rf	= {
+		.read		= rt2x00_rf_read,
+		.write		= rt2400pci_rf_write,
+		.word_size	= sizeof(u32),
+		.word_count	= RF_SIZE / sizeof(u32),
+	},
+};
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+#ifdef CONFIG_RT2400PCI_RFKILL
+static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
+	return rt2x00_get_field32(reg, GPIOCSR_BIT0);
+}
+#else
+#define rt2400pci_rfkill_poll	NULL
+#endif /* CONFIG_RT2400PCI_RFKILL */
+
+/*
+ * Configuration handlers.
+ */
+static void rt2400pci_config_mac_addr(struct rt2x00_dev *rt2x00dev,
+				      __le32 *mac)
+{
+	rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac,
+				      (2 * sizeof(__le32)));
+}
+
+static void rt2400pci_config_bssid(struct rt2x00_dev *rt2x00dev,
+				   __le32 *bssid)
+{
+	rt2x00pci_register_multiwrite(rt2x00dev, CSR5, bssid,
+				      (2 * sizeof(__le32)));
+}
+
+static void rt2400pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
+				  const int tsf_sync)
+{
+	u32 reg;
+
+	rt2x00pci_register_write(rt2x00dev, CSR14, 0);
+
+	/*
+	 * Enable beacon config
+	 */
+	rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg);
+	rt2x00_set_field32(&reg, BCNCSR1_PRELOAD,
+			   PREAMBLE + get_duration(IEEE80211_HEADER, 20));
+	rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg);
+
+	/*
+	 * Enable synchronisation.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+	rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
+	rt2x00_set_field32(&reg, CSR14_TBCN, 1);
+	rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+	rt2x00_set_field32(&reg, CSR14_TSF_SYNC, tsf_sync);
+	rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+}
+
+static void rt2400pci_config_preamble(struct rt2x00_dev *rt2x00dev,
+				      const int short_preamble,
+				      const int ack_timeout,
+				      const int ack_consume_time)
+{
+	int preamble_mask;
+	u32 reg;
+
+	/*
+	 * When short preamble is enabled, we should set bit 0x08
+	 */
+	preamble_mask = short_preamble << 3;
+
+	rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
+	rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, ack_timeout);
+	rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME, ack_consume_time);
+	rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
+
+	rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
+	rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00 | preamble_mask);
+	rt2x00_set_field32(&reg, ARCSR2_SERVICE, 0x04);
+	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10));
+	rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
+
+	rt2x00pci_register_read(rt2x00dev, ARCSR3, &reg);
+	rt2x00_set_field32(&reg, ARCSR3_SIGNAL, 0x01 | preamble_mask);
+	rt2x00_set_field32(&reg, ARCSR3_SERVICE, 0x04);
+	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20));
+	rt2x00pci_register_write(rt2x00dev, ARCSR3, reg);
+
+	rt2x00pci_register_read(rt2x00dev, ARCSR4, &reg);
+	rt2x00_set_field32(&reg, ARCSR4_SIGNAL, 0x02 | preamble_mask);
+	rt2x00_set_field32(&reg, ARCSR4_SERVICE, 0x04);
+	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55));
+	rt2x00pci_register_write(rt2x00dev, ARCSR4, reg);
+
+	rt2x00pci_register_read(rt2x00dev, ARCSR5, &reg);
+	rt2x00_set_field32(&reg, ARCSR5_SIGNAL, 0x03 | preamble_mask);
+	rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
+	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
+	rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+}
+
+static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev,
+				     const int basic_rate_mask)
+{
+	rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask);
+}
+
+static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev,
+				     struct rf_channel *rf)
+{
+	/*
+	 * Switch on tuning bits.
+	 */
+	rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1);
+	rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1);
+
+	rt2400pci_rf_write(rt2x00dev, 1, rf->rf1);
+	rt2400pci_rf_write(rt2x00dev, 2, rf->rf2);
+	rt2400pci_rf_write(rt2x00dev, 3, rf->rf3);
+
+	/*
+	 * RF2420 chipset don't need any additional actions.
+	 */
+	if (rt2x00_rf(&rt2x00dev->chip, RF2420))
+		return;
+
+	/*
+	 * For the RT2421 chipsets we need to write an invalid
+	 * reference clock rate to activate auto_tune.
+	 * After that we set the value back to the correct channel.
+	 */
+	rt2400pci_rf_write(rt2x00dev, 1, rf->rf1);
+	rt2400pci_rf_write(rt2x00dev, 2, 0x000c2a32);
+	rt2400pci_rf_write(rt2x00dev, 3, rf->rf3);
+
+	msleep(1);
+
+	rt2400pci_rf_write(rt2x00dev, 1, rf->rf1);
+	rt2400pci_rf_write(rt2x00dev, 2, rf->rf2);
+	rt2400pci_rf_write(rt2x00dev, 3, rf->rf3);
+
+	msleep(1);
+
+	/*
+	 * Switch off tuning bits.
+	 */
+	rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0);
+	rt2x00_set_field32(&rf->rf3, RF3_TUNER, 0);
+
+	rt2400pci_rf_write(rt2x00dev, 1, rf->rf1);
+	rt2400pci_rf_write(rt2x00dev, 3, rf->rf3);
+
+	/*
+	 * Clear false CRC during channel switch.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CNT0, &rf->rf1);
+}
+
+static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower)
+{
+	rt2400pci_bbp_write(rt2x00dev, 3, TXPOWER_TO_DEV(txpower));
+}
+
+static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev,
+				     int antenna_tx, int antenna_rx)
+{
+	u8 r1;
+	u8 r4;
+
+	rt2400pci_bbp_read(rt2x00dev, 4, &r4);
+	rt2400pci_bbp_read(rt2x00dev, 1, &r1);
+
+	/*
+	 * Configure the TX antenna.
+	 */
+	switch (antenna_tx) {
+	case ANTENNA_SW_DIVERSITY:
+	case ANTENNA_HW_DIVERSITY:
+		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1);
+		break;
+	case ANTENNA_A:
+		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0);
+		break;
+	case ANTENNA_B:
+		rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2);
+		break;
+	}
+
+	/*
+	 * Configure the RX antenna.
+	 */
+	switch (antenna_rx) {
+	case ANTENNA_SW_DIVERSITY:
+	case ANTENNA_HW_DIVERSITY:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+		break;
+	case ANTENNA_A:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0);
+		break;
+	case ANTENNA_B:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+		break;
+	}
+
+	rt2400pci_bbp_write(rt2x00dev, 4, r4);
+	rt2400pci_bbp_write(rt2x00dev, 1, r1);
+}
+
+static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev,
+				      struct rt2x00lib_conf *libconf)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+	rt2x00_set_field32(&reg, CSR11_SLOT_TIME, libconf->slot_time);
+	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+	rt2x00_set_field32(&reg, CSR18_SIFS, libconf->sifs);
+	rt2x00_set_field32(&reg, CSR18_PIFS, libconf->pifs);
+	rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+	rt2x00_set_field32(&reg, CSR19_DIFS, libconf->difs);
+	rt2x00_set_field32(&reg, CSR19_EIFS, libconf->eifs);
+	rt2x00pci_register_write(rt2x00dev, CSR19, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
+	rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
+	rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
+	rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR12, &reg);
+	rt2x00_set_field32(&reg, CSR12_BEACON_INTERVAL,
+			   libconf->conf->beacon_int * 16);
+	rt2x00_set_field32(&reg, CSR12_CFP_MAX_DURATION,
+			   libconf->conf->beacon_int * 16);
+	rt2x00pci_register_write(rt2x00dev, CSR12, reg);
+}
+
+static void rt2400pci_config(struct rt2x00_dev *rt2x00dev,
+			     const unsigned int flags,
+			     struct rt2x00lib_conf *libconf)
+{
+	if (flags & CONFIG_UPDATE_PHYMODE)
+		rt2400pci_config_phymode(rt2x00dev, libconf->basic_rates);
+	if (flags & CONFIG_UPDATE_CHANNEL)
+		rt2400pci_config_channel(rt2x00dev, &libconf->rf);
+	if (flags & CONFIG_UPDATE_TXPOWER)
+		rt2400pci_config_txpower(rt2x00dev,
+					 libconf->conf->power_level);
+	if (flags & CONFIG_UPDATE_ANTENNA)
+		rt2400pci_config_antenna(rt2x00dev,
+					 libconf->conf->antenna_sel_tx,
+					 libconf->conf->antenna_sel_rx);
+	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+		rt2400pci_config_duration(rt2x00dev, libconf);
+}
+
+static void rt2400pci_config_cw(struct rt2x00_dev *rt2x00dev,
+				struct ieee80211_tx_queue_params *params)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+	rt2x00_set_field32(&reg, CSR11_CWMIN, params->cw_min);
+	rt2x00_set_field32(&reg, CSR11_CWMAX, params->cw_max);
+	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+}
+
+/*
+ * LED functions.
+ */
+static void rt2400pci_enable_led(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
+
+	rt2x00_set_field32(&reg, LEDCSR_ON_PERIOD, 70);
+	rt2x00_set_field32(&reg, LEDCSR_OFF_PERIOD, 30);
+
+	if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) {
+		rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
+		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
+	} else if (rt2x00dev->led_mode == LED_MODE_ASUS) {
+		rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
+		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
+	} else {
+		rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
+		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
+	}
+
+	rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
+}
+
+static void rt2400pci_disable_led(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
+	rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
+	rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
+	rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
+}
+
+/*
+ * Link tuning
+ */
+static void rt2400pci_link_stats(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+	u8 bbp;
+
+	/*
+	 * Update FCS error count from register.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
+	rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR);
+
+	/*
+	 * Update False CCA count from register.
+	 */
+	rt2400pci_bbp_read(rt2x00dev, 39, &bbp);
+	rt2x00dev->link.false_cca = bbp;
+}
+
+static void rt2400pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
+{
+	rt2400pci_bbp_write(rt2x00dev, 13, 0x08);
+	rt2x00dev->link.vgc_level = 0x08;
+}
+
+static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+	u8 reg;
+
+	/*
+	 * The link tuner should not run longer then 60 seconds,
+	 * and should run once every 2 seconds.
+	 */
+	if (rt2x00dev->link.count > 60 || !(rt2x00dev->link.count & 1))
+		return;
+
+	/*
+	 * Base r13 link tuning on the false cca count.
+	 */
+	rt2400pci_bbp_read(rt2x00dev, 13, &reg);
+
+	if (rt2x00dev->link.false_cca > 512 && reg < 0x20) {
+		rt2400pci_bbp_write(rt2x00dev, 13, ++reg);
+		rt2x00dev->link.vgc_level = reg;
+	} else if (rt2x00dev->link.false_cca < 100 && reg > 0x08) {
+		rt2400pci_bbp_write(rt2x00dev, 13, --reg);
+		rt2x00dev->link.vgc_level = reg;
+	}
+}
+
+/*
+ * Initialization functions.
+ */
+static void rt2400pci_init_rxring(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_ring *ring = rt2x00dev->rx;
+	struct data_desc *rxd;
+	unsigned int i;
+	u32 word;
+
+	memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+	for (i = 0; i < ring->stats.limit; i++) {
+		rxd = ring->entry[i].priv;
+
+		rt2x00_desc_read(rxd, 2, &word);
+		rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH,
+				   ring->data_size);
+		rt2x00_desc_write(rxd, 2, word);
+
+		rt2x00_desc_read(rxd, 1, &word);
+		rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS,
+				   ring->entry[i].data_dma);
+		rt2x00_desc_write(rxd, 1, word);
+
+		rt2x00_desc_read(rxd, 0, &word);
+		rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+		rt2x00_desc_write(rxd, 0, word);
+	}
+
+	rt2x00_ring_index_clear(rt2x00dev->rx);
+}
+
+static void rt2400pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue)
+{
+	struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
+	struct data_desc *txd;
+	unsigned int i;
+	u32 word;
+
+	memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+	for (i = 0; i < ring->stats.limit; i++) {
+		txd = ring->entry[i].priv;
+
+		rt2x00_desc_read(txd, 1, &word);
+		rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS,
+				   ring->entry[i].data_dma);
+		rt2x00_desc_write(txd, 1, word);
+
+		rt2x00_desc_read(txd, 2, &word);
+		rt2x00_set_field32(&word, TXD_W2_BUFFER_LENGTH,
+				   ring->data_size);
+		rt2x00_desc_write(txd, 2, word);
+
+		rt2x00_desc_read(txd, 0, &word);
+		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+		rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+		rt2x00_desc_write(txd, 0, word);
+	}
+
+	rt2x00_ring_index_clear(ring);
+}
+
+static int rt2400pci_init_rings(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	/*
+	 * Initialize rings.
+	 */
+	rt2400pci_init_rxring(rt2x00dev);
+	rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+	rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+	rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
+	rt2400pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+
+	/*
+	 * Initialize registers.
+	 */
+	rt2x00pci_register_read(rt2x00dev, TXCSR2, &reg);
+	rt2x00_set_field32(&reg, TXCSR2_TXD_SIZE,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size);
+	rt2x00_set_field32(&reg, TXCSR2_NUM_TXD,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit);
+	rt2x00_set_field32(&reg, TXCSR2_NUM_ATIM,
+			   rt2x00dev->bcn[1].stats.limit);
+	rt2x00_set_field32(&reg, TXCSR2_NUM_PRIO,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit);
+	rt2x00pci_register_write(rt2x00dev, TXCSR2, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TXCSR3, &reg);
+	rt2x00_set_field32(&reg, TXCSR3_TX_RING_REGISTER,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma);
+	rt2x00pci_register_write(rt2x00dev, TXCSR3, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TXCSR5, &reg);
+	rt2x00_set_field32(&reg, TXCSR5_PRIO_RING_REGISTER,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma);
+	rt2x00pci_register_write(rt2x00dev, TXCSR5, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TXCSR4, &reg);
+	rt2x00_set_field32(&reg, TXCSR4_ATIM_RING_REGISTER,
+			   rt2x00dev->bcn[1].data_dma);
+	rt2x00pci_register_write(rt2x00dev, TXCSR4, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TXCSR6, &reg);
+	rt2x00_set_field32(&reg, TXCSR6_BEACON_RING_REGISTER,
+			   rt2x00dev->bcn[0].data_dma);
+	rt2x00pci_register_write(rt2x00dev, TXCSR6, reg);
+
+	rt2x00pci_register_read(rt2x00dev, RXCSR1, &reg);
+	rt2x00_set_field32(&reg, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size);
+	rt2x00_set_field32(&reg, RXCSR1_NUM_RXD, rt2x00dev->rx->stats.limit);
+	rt2x00pci_register_write(rt2x00dev, RXCSR1, reg);
+
+	rt2x00pci_register_read(rt2x00dev, RXCSR2, &reg);
+	rt2x00_set_field32(&reg, RXCSR2_RX_RING_REGISTER,
+			   rt2x00dev->rx->data_dma);
+	rt2x00pci_register_write(rt2x00dev, RXCSR2, reg);
+
+	return 0;
+}
+
+static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	rt2x00pci_register_write(rt2x00dev, PSCSR0, 0x00020002);
+	rt2x00pci_register_write(rt2x00dev, PSCSR1, 0x00000002);
+	rt2x00pci_register_write(rt2x00dev, PSCSR2, 0x00023f20);
+	rt2x00pci_register_write(rt2x00dev, PSCSR3, 0x00000002);
+
+	rt2x00pci_register_read(rt2x00dev, TIMECSR, &reg);
+	rt2x00_set_field32(&reg, TIMECSR_US_COUNT, 33);
+	rt2x00_set_field32(&reg, TIMECSR_US_64_COUNT, 63);
+	rt2x00_set_field32(&reg, TIMECSR_BEACON_EXPECT, 0);
+	rt2x00pci_register_write(rt2x00dev, TIMECSR, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR9, &reg);
+	rt2x00_set_field32(&reg, CSR9_MAX_FRAME_UNIT,
+			   (rt2x00dev->rx->data_size / 128));
+	rt2x00pci_register_write(rt2x00dev, CSR9, reg);
+
+	rt2x00pci_register_write(rt2x00dev, CNT3, 0x3f080000);
+
+	rt2x00pci_register_read(rt2x00dev, ARCSR0, &reg);
+	rt2x00_set_field32(&reg, ARCSR0_AR_BBP_DATA0, 133);
+	rt2x00_set_field32(&reg, ARCSR0_AR_BBP_ID0, 134);
+	rt2x00_set_field32(&reg, ARCSR0_AR_BBP_DATA1, 136);
+	rt2x00_set_field32(&reg, ARCSR0_AR_BBP_ID1, 135);
+	rt2x00pci_register_write(rt2x00dev, ARCSR0, reg);
+
+	rt2x00pci_register_read(rt2x00dev, RXCSR3, &reg);
+	rt2x00_set_field32(&reg, RXCSR3_BBP_ID0, 3); /* Tx power.*/
+	rt2x00_set_field32(&reg, RXCSR3_BBP_ID0_VALID, 1);
+	rt2x00_set_field32(&reg, RXCSR3_BBP_ID1, 32); /* Signal */
+	rt2x00_set_field32(&reg, RXCSR3_BBP_ID1_VALID, 1);
+	rt2x00_set_field32(&reg, RXCSR3_BBP_ID2, 36); /* Rssi */
+	rt2x00_set_field32(&reg, RXCSR3_BBP_ID2_VALID, 1);
+	rt2x00pci_register_write(rt2x00dev, RXCSR3, reg);
+
+	rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100);
+
+	if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+		return -EBUSY;
+
+	rt2x00pci_register_write(rt2x00dev, MACCSR0, 0x00217223);
+	rt2x00pci_register_write(rt2x00dev, MACCSR1, 0x00235518);
+
+	rt2x00pci_register_read(rt2x00dev, MACCSR2, &reg);
+	rt2x00_set_field32(&reg, MACCSR2_DELAY, 64);
+	rt2x00pci_register_write(rt2x00dev, MACCSR2, reg);
+
+	rt2x00pci_register_read(rt2x00dev, RALINKCSR, &reg);
+	rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_DATA0, 17);
+	rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_ID0, 154);
+	rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_DATA1, 0);
+	rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_ID1, 154);
+	rt2x00pci_register_write(rt2x00dev, RALINKCSR, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR1, &reg);
+	rt2x00_set_field32(&reg, CSR1_SOFT_RESET, 1);
+	rt2x00_set_field32(&reg, CSR1_BBP_RESET, 0);
+	rt2x00_set_field32(&reg, CSR1_HOST_READY, 0);
+	rt2x00pci_register_write(rt2x00dev, CSR1, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR1, &reg);
+	rt2x00_set_field32(&reg, CSR1_SOFT_RESET, 0);
+	rt2x00_set_field32(&reg, CSR1_HOST_READY, 1);
+	rt2x00pci_register_write(rt2x00dev, CSR1, reg);
+
+	/*
+	 * We must clear the FCS and FIFO error count.
+	 * These registers are cleared on read,
+	 * so we may pass a useless variable to store the value.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
+	rt2x00pci_register_read(rt2x00dev, CNT4, &reg);
+
+	return 0;
+}
+
+static int rt2400pci_init_bbp(struct rt2x00_dev *rt2x00dev)
+{
+	unsigned int i;
+	u16 eeprom;
+	u8 reg_id;
+	u8 value;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2400pci_bbp_read(rt2x00dev, 0, &value);
+		if ((value != 0xff) && (value != 0x00))
+			goto continue_csr_init;
+		NOTICE(rt2x00dev, "Waiting for BBP register.\n");
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+	return -EACCES;
+
+continue_csr_init:
+	rt2400pci_bbp_write(rt2x00dev, 1, 0x00);
+	rt2400pci_bbp_write(rt2x00dev, 3, 0x27);
+	rt2400pci_bbp_write(rt2x00dev, 4, 0x08);
+	rt2400pci_bbp_write(rt2x00dev, 10, 0x0f);
+	rt2400pci_bbp_write(rt2x00dev, 15, 0x72);
+	rt2400pci_bbp_write(rt2x00dev, 16, 0x74);
+	rt2400pci_bbp_write(rt2x00dev, 17, 0x20);
+	rt2400pci_bbp_write(rt2x00dev, 18, 0x72);
+	rt2400pci_bbp_write(rt2x00dev, 19, 0x0b);
+	rt2400pci_bbp_write(rt2x00dev, 20, 0x00);
+	rt2400pci_bbp_write(rt2x00dev, 28, 0x11);
+	rt2400pci_bbp_write(rt2x00dev, 29, 0x04);
+	rt2400pci_bbp_write(rt2x00dev, 30, 0x21);
+	rt2400pci_bbp_write(rt2x00dev, 31, 0x00);
+
+	DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
+	for (i = 0; i < EEPROM_BBP_SIZE; i++) {
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+
+		if (eeprom != 0xffff && eeprom != 0x0000) {
+			reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
+			value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
+			DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
+			      reg_id, value);
+			rt2400pci_bbp_write(rt2x00dev, reg_id, value);
+		}
+	}
+	DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
+
+	return 0;
+}
+
+/*
+ * Device state switch handlers.
+ */
+static void rt2400pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
+				enum dev_state state)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+	rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX,
+			   state == STATE_RADIO_RX_OFF);
+	rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+}
+
+static void rt2400pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
+				 enum dev_state state)
+{
+	int mask = (state == STATE_RADIO_IRQ_OFF);
+	u32 reg;
+
+	/*
+	 * When interrupts are being enabled, the interrupt registers
+	 * should clear the register to assure a clean state.
+	 */
+	if (state == STATE_RADIO_IRQ_ON) {
+		rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+		rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+	}
+
+	/*
+	 * Only toggle the interrupts bits we are going to use.
+	 * Non-checked interrupt bits are disabled by default.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+	rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, mask);
+	rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, mask);
+	rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, mask);
+	rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, mask);
+	rt2x00_set_field32(&reg, CSR8_RXDONE, mask);
+	rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+}
+
+static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+	/*
+	 * Initialize all registers.
+	 */
+	if (rt2400pci_init_rings(rt2x00dev) ||
+	    rt2400pci_init_registers(rt2x00dev) ||
+	    rt2400pci_init_bbp(rt2x00dev)) {
+		ERROR(rt2x00dev, "Register initialization failed.\n");
+		return -EIO;
+	}
+
+	/*
+	 * Enable interrupts.
+	 */
+	rt2400pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON);
+
+	/*
+	 * Enable LED
+	 */
+	rt2400pci_enable_led(rt2x00dev);
+
+	return 0;
+}
+
+static void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	/*
+	 * Disable LED
+	 */
+	rt2400pci_disable_led(rt2x00dev);
+
+	rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0);
+
+	/*
+	 * Disable synchronisation.
+	 */
+	rt2x00pci_register_write(rt2x00dev, CSR14, 0);
+
+	/*
+	 * Cancel RX and TX.
+	 */
+	rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+	rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
+	rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+
+	/*
+	 * Disable interrupts.
+	 */
+	rt2400pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF);
+}
+
+static int rt2400pci_set_state(struct rt2x00_dev *rt2x00dev,
+			       enum dev_state state)
+{
+	u32 reg;
+	unsigned int i;
+	char put_to_sleep;
+	char bbp_state;
+	char rf_state;
+
+	put_to_sleep = (state != STATE_AWAKE);
+
+	rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg);
+	rt2x00_set_field32(&reg, PWRCSR1_SET_STATE, 1);
+	rt2x00_set_field32(&reg, PWRCSR1_BBP_DESIRE_STATE, state);
+	rt2x00_set_field32(&reg, PWRCSR1_RF_DESIRE_STATE, state);
+	rt2x00_set_field32(&reg, PWRCSR1_PUT_TO_SLEEP, put_to_sleep);
+	rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg);
+
+	/*
+	 * Device is not guaranteed to be in the requested state yet.
+	 * We must wait until the register indicates that the
+	 * device has entered the correct state.
+	 */
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg);
+		bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE);
+		rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE);
+		if (bbp_state == state && rf_state == state)
+			return 0;
+		msleep(10);
+	}
+
+	NOTICE(rt2x00dev, "Device failed to enter state %d, "
+	       "current device state: bbp %d and rf %d.\n",
+	       state, bbp_state, rf_state);
+
+	return -EBUSY;
+}
+
+static int rt2400pci_set_device_state(struct rt2x00_dev *rt2x00dev,
+				      enum dev_state state)
+{
+	int retval = 0;
+
+	switch (state) {
+	case STATE_RADIO_ON:
+		retval = rt2400pci_enable_radio(rt2x00dev);
+		break;
+	case STATE_RADIO_OFF:
+		rt2400pci_disable_radio(rt2x00dev);
+		break;
+	case STATE_RADIO_RX_ON:
+	case STATE_RADIO_RX_OFF:
+		rt2400pci_toggle_rx(rt2x00dev, state);
+		break;
+	case STATE_DEEP_SLEEP:
+	case STATE_SLEEP:
+	case STATE_STANDBY:
+	case STATE_AWAKE:
+		retval = rt2400pci_set_state(rt2x00dev, state);
+		break;
+	default:
+		retval = -ENOTSUPP;
+		break;
+	}
+
+	return retval;
+}
+
+/*
+ * TX descriptor initialization
+ */
+static void rt2400pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+				    struct data_desc *txd,
+				    struct txdata_entry_desc *desc,
+				    struct ieee80211_hdr *ieee80211hdr,
+				    unsigned int length,
+				    struct ieee80211_tx_control *control)
+{
+	u32 word;
+	u32 signal = 0;
+	u32 service = 0;
+	u32 length_high = 0;
+	u32 length_low = 0;
+
+	/*
+	 * The PLCP values should be treated as if they
+	 * were BBP values.
+	 */
+	rt2x00_set_field32(&signal, BBPCSR_VALUE, desc->signal);
+	rt2x00_set_field32(&signal, BBPCSR_REGNUM, 5);
+	rt2x00_set_field32(&signal, BBPCSR_BUSY, 1);
+
+	rt2x00_set_field32(&service, BBPCSR_VALUE, desc->service);
+	rt2x00_set_field32(&service, BBPCSR_REGNUM, 6);
+	rt2x00_set_field32(&service, BBPCSR_BUSY, 1);
+
+	rt2x00_set_field32(&length_high, BBPCSR_VALUE, desc->length_high);
+	rt2x00_set_field32(&length_high, BBPCSR_REGNUM, 7);
+	rt2x00_set_field32(&length_high, BBPCSR_BUSY, 1);
+
+	rt2x00_set_field32(&length_low, BBPCSR_VALUE, desc->length_low);
+	rt2x00_set_field32(&length_low, BBPCSR_REGNUM, 8);
+	rt2x00_set_field32(&length_low, BBPCSR_BUSY, 1);
+
+	/*
+	 * Start writing the descriptor words.
+	 */
+	rt2x00_desc_read(txd, 2, &word);
+	rt2x00_set_field32(&word, TXD_W2_DATABYTE_COUNT, length);
+	rt2x00_desc_write(txd, 2, word);
+
+	rt2x00_desc_read(txd, 3, &word);
+	rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, signal);
+	rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, service);
+	rt2x00_desc_write(txd, 3, word);
+
+	rt2x00_desc_read(txd, 4, &word);
+	rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_LOW, length_low);
+	rt2x00_set_field32(&word, TXD_W4_PLCP_LENGTH_HIGH, length_high);
+	rt2x00_desc_write(txd, 4, word);
+
+	rt2x00_desc_read(txd, 0, &word);
+	rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
+	rt2x00_set_field32(&word, TXD_W0_VALID, 1);
+	rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+			   test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_ACK,
+			   !(control->flags & IEEE80211_TXCTL_NO_ACK));
+	rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+			   test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_RTS,
+			   test_bit(ENTRY_TXD_RTS_FRAME, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+	rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
+			   !!(control->flags &
+			      IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+	rt2x00_desc_write(txd, 0, word);
+}
+
+/*
+ * TX data initialization
+ */
+static void rt2400pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+				    unsigned int queue)
+{
+	u32 reg;
+
+	if (queue == IEEE80211_TX_QUEUE_BEACON) {
+		rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+		if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
+			rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
+			rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+		}
+		return;
+	}
+
+	rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+	if (queue == IEEE80211_TX_QUEUE_DATA0)
+		rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
+	else if (queue == IEEE80211_TX_QUEUE_DATA1)
+		rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
+	else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
+		rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
+	rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+}
+
+/*
+ * RX control handlers
+ */
+static void rt2400pci_fill_rxdone(struct data_entry *entry,
+				  struct rxdata_entry_desc *desc)
+{
+	struct data_desc *rxd = entry->priv;
+	u32 word0;
+	u32 word2;
+
+	rt2x00_desc_read(rxd, 0, &word0);
+	rt2x00_desc_read(rxd, 2, &word2);
+
+	desc->flags = 0;
+	if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+		desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+	if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
+		desc->flags |= RX_FLAG_FAILED_PLCP_CRC;
+
+	/*
+	 * Obtain the status about this packet.
+	 */
+	desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
+	desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
+	    entry->ring->rt2x00dev->rssi_offset;
+	desc->ofdm = 0;
+	desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+}
+
+/*
+ * Interrupt functions.
+ */
+static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
+{
+	struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
+	struct data_entry *entry;
+	struct data_desc *txd;
+	u32 word;
+	int tx_status;
+	int retry;
+
+	while (!rt2x00_ring_empty(ring)) {
+		entry = rt2x00_get_data_entry_done(ring);
+		txd = entry->priv;
+		rt2x00_desc_read(txd, 0, &word);
+
+		if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
+		    !rt2x00_get_field32(word, TXD_W0_VALID))
+			break;
+
+		/*
+		 * Obtain the status about this packet.
+		 */
+		tx_status = rt2x00_get_field32(word, TXD_W0_RESULT);
+		retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
+
+		rt2x00lib_txdone(entry, tx_status, retry);
+
+		/*
+		 * Make this entry available for reuse.
+		 */
+		entry->flags = 0;
+		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+		rt2x00_desc_write(txd, 0, word);
+		rt2x00_ring_index_done_inc(ring);
+	}
+
+	/*
+	 * If the data ring was full before the txdone handler
+	 * we must make sure the packet queue in the mac80211 stack
+	 * is reenabled when the txdone handler has finished.
+	 */
+	entry = ring->entry;
+	if (!rt2x00_ring_full(ring))
+		ieee80211_wake_queue(rt2x00dev->hw,
+				     entry->tx_status.control.queue);
+}
+
+static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
+{
+	struct rt2x00_dev *rt2x00dev = dev_instance;
+	u32 reg;
+
+	/*
+	 * Get the interrupt sources & saved to local variable.
+	 * Write register value back to clear pending interrupts.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+	rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+
+	if (!reg)
+		return IRQ_NONE;
+
+	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+		return IRQ_HANDLED;
+
+	/*
+	 * Handle interrupts, walk through all bits
+	 * and run the tasks, the bits are checked in order of
+	 * priority.
+	 */
+
+	/*
+	 * 1 - Beacon timer expired interrupt.
+	 */
+	if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE))
+		rt2x00lib_beacondone(rt2x00dev);
+
+	/*
+	 * 2 - Rx ring done interrupt.
+	 */
+	if (rt2x00_get_field32(reg, CSR7_RXDONE))
+		rt2x00pci_rxdone(rt2x00dev);
+
+	/*
+	 * 3 - Atim ring transmit done interrupt.
+	 */
+	if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING))
+		rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
+
+	/*
+	 * 4 - Priority ring transmit done interrupt.
+	 */
+	if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
+		rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+
+	/*
+	 * 5 - Tx ring transmit done interrupt.
+	 */
+	if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
+		rt2400pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Device probe functions.
+ */
+static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+	struct eeprom_93cx6 eeprom;
+	u32 reg;
+	u16 word;
+	u8 *mac;
+
+	rt2x00pci_register_read(rt2x00dev, CSR21, &reg);
+
+	eeprom.data = rt2x00dev;
+	eeprom.register_read = rt2400pci_eepromregister_read;
+	eeprom.register_write = rt2400pci_eepromregister_write;
+	eeprom.width = rt2x00_get_field32(reg, CSR21_TYPE_93C46) ?
+	    PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66;
+	eeprom.reg_data_in = 0;
+	eeprom.reg_data_out = 0;
+	eeprom.reg_data_clock = 0;
+	eeprom.reg_chip_select = 0;
+
+	eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
+			       EEPROM_SIZE / sizeof(u16));
+
+	/*
+	 * Start validation of the data that has been read.
+	 */
+	mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+	if (!is_valid_ether_addr(mac)) {
+		DECLARE_MAC_BUF(macbuf);
+
+		random_ether_addr(mac);
+		EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+	if (word == 0xffff) {
+		ERROR(rt2x00dev, "Invalid EEPROM data detected.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+	u16 value;
+	u16 eeprom;
+
+	/*
+	 * Read EEPROM word for configuration.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+	/*
+	 * Identify RF chipset.
+	 */
+	value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+	rt2x00pci_register_read(rt2x00dev, CSR0, &reg);
+	rt2x00_set_chip(rt2x00dev, RT2460, value, reg);
+
+	if (!rt2x00_rf(&rt2x00dev->chip, RF2420) &&
+	    !rt2x00_rf(&rt2x00dev->chip, RF2421)) {
+		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Identify default antenna configuration.
+	 */
+	rt2x00dev->hw->conf.antenna_sel_tx =
+	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
+	rt2x00dev->hw->conf.antenna_sel_rx =
+	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
+
+	/*
+	 * Store led mode, for correct led behaviour.
+	 */
+	rt2x00dev->led_mode =
+	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
+
+	/*
+	 * Detect if this device has an hardware controlled radio.
+	 */
+#ifdef CONFIG_RT2400PCI_RFKILL
+	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
+		__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+#endif /* CONFIG_RT2400PCI_RFKILL */
+
+	/*
+	 * Check if the BBP tuning should be enabled.
+	 */
+	if (!rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_AGCVGC_TUNING))
+		__set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
+
+	return 0;
+}
+
+/*
+ * RF value list for RF2420 & RF2421
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg[] = {
+	{ 1,  0x00022058, 0x000c1fda, 0x00000101, 0 },
+	{ 2,  0x00022058, 0x000c1fee, 0x00000101, 0 },
+	{ 3,  0x00022058, 0x000c2002, 0x00000101, 0 },
+	{ 4,  0x00022058, 0x000c2016, 0x00000101, 0 },
+	{ 5,  0x00022058, 0x000c202a, 0x00000101, 0 },
+	{ 6,  0x00022058, 0x000c203e, 0x00000101, 0 },
+	{ 7,  0x00022058, 0x000c2052, 0x00000101, 0 },
+	{ 8,  0x00022058, 0x000c2066, 0x00000101, 0 },
+	{ 9,  0x00022058, 0x000c207a, 0x00000101, 0 },
+	{ 10, 0x00022058, 0x000c208e, 0x00000101, 0 },
+	{ 11, 0x00022058, 0x000c20a2, 0x00000101, 0 },
+	{ 12, 0x00022058, 0x000c20b6, 0x00000101, 0 },
+	{ 13, 0x00022058, 0x000c20ca, 0x00000101, 0 },
+	{ 14, 0x00022058, 0x000c20fa, 0x00000101, 0 },
+};
+
+static void rt2400pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+{
+	struct hw_mode_spec *spec = &rt2x00dev->spec;
+	u8 *txpower;
+	unsigned int i;
+
+	/*
+	 * Initialize all hw fields.
+	 */
+	rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+	rt2x00dev->hw->extra_tx_headroom = 0;
+	rt2x00dev->hw->max_signal = MAX_SIGNAL;
+	rt2x00dev->hw->max_rssi = MAX_RX_SSI;
+	rt2x00dev->hw->queues = 2;
+
+	SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+				rt2x00_eeprom_addr(rt2x00dev,
+						   EEPROM_MAC_ADDR_0));
+
+	/*
+	 * Convert tx_power array in eeprom.
+	 */
+	txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
+	for (i = 0; i < 14; i++)
+		txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+	/*
+	 * Initialize hw_mode information.
+	 */
+	spec->num_modes = 1;
+	spec->num_rates = 4;
+	spec->tx_power_a = NULL;
+	spec->tx_power_bg = txpower;
+	spec->tx_power_default = DEFAULT_TXPOWER;
+
+	spec->num_channels = ARRAY_SIZE(rf_vals_bg);
+	spec->channels = rf_vals_bg;
+}
+
+static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+	int retval;
+
+	/*
+	 * Allocate eeprom data.
+	 */
+	retval = rt2400pci_validate_eeprom(rt2x00dev);
+	if (retval)
+		return retval;
+
+	retval = rt2400pci_init_eeprom(rt2x00dev);
+	if (retval)
+		return retval;
+
+	/*
+	 * Initialize hw specifications.
+	 */
+	rt2400pci_probe_hw_mode(rt2x00dev);
+
+	/*
+	 * This device requires the beacon ring
+	 */
+	__set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
+
+	/*
+	 * Set the rssi offset.
+	 */
+	rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
+	return 0;
+}
+
+/*
+ * IEEE80211 stack callback functions.
+ */
+static void rt2400pci_configure_filter(struct ieee80211_hw *hw,
+				       unsigned int changed_flags,
+				       unsigned int *total_flags,
+				       int mc_count,
+				       struct dev_addr_list *mc_list)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct interface *intf = &rt2x00dev->interface;
+	u32 reg;
+
+	/*
+	 * Mask off any flags we are going to ignore from
+	 * the total_flags field.
+	 */
+	*total_flags &=
+	    FIF_ALLMULTI |
+	    FIF_FCSFAIL |
+	    FIF_PLCPFAIL |
+	    FIF_CONTROL |
+	    FIF_OTHER_BSS |
+	    FIF_PROMISC_IN_BSS;
+
+	/*
+	 * Apply some rules to the filters:
+	 * - Some filters imply different filters to be set.
+	 * - Some things we can't filter out at all.
+	 * - Some filters are set based on interface type.
+	 */
+	*total_flags |= FIF_ALLMULTI;
+	if (*total_flags & FIF_OTHER_BSS ||
+	    *total_flags & FIF_PROMISC_IN_BSS)
+		*total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+	if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+		*total_flags |= FIF_PROMISC_IN_BSS;
+
+	/*
+	 * Check if there is any work left for us.
+	 */
+	if (intf->filter == *total_flags)
+		return;
+	intf->filter = *total_flags;
+
+	/*
+	 * Start configuration steps.
+	 * Note that the version error will always be dropped
+	 * since there is no filter for it at this time.
+	 */
+	rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+	rt2x00_set_field32(&reg, RXCSR0_DROP_CRC,
+			   !(*total_flags & FIF_FCSFAIL));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_PHYSICAL,
+			   !(*total_flags & FIF_PLCPFAIL));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL,
+			   !(*total_flags & FIF_CONTROL));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_TODS,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
+	rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+}
+
+static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw,
+				     u32 short_retry, u32 long_retry)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+	rt2x00_set_field32(&reg, CSR11_LONG_RETRY, long_retry);
+	rt2x00_set_field32(&reg, CSR11_SHORT_RETRY, short_retry);
+	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+	return 0;
+}
+
+static int rt2400pci_conf_tx(struct ieee80211_hw *hw,
+			     int queue,
+			     const struct ieee80211_tx_queue_params *params)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+
+	/*
+	 * We don't support variating cw_min and cw_max variables
+	 * per queue. So by default we only configure the TX queue,
+	 * and ignore all other configurations.
+	 */
+	if (queue != IEEE80211_TX_QUEUE_DATA0)
+		return -EINVAL;
+
+	if (rt2x00mac_conf_tx(hw, queue, params))
+		return -EINVAL;
+
+	/*
+	 * Write configuration to register.
+	 */
+	rt2400pci_config_cw(rt2x00dev, &rt2x00dev->tx->tx_params);
+
+	return 0;
+}
+
+static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	u64 tsf;
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, CSR17, &reg);
+	tsf = (u64) rt2x00_get_field32(reg, CSR17_HIGH_TSFTIMER) << 32;
+	rt2x00pci_register_read(rt2x00dev, CSR16, &reg);
+	tsf |= rt2x00_get_field32(reg, CSR16_LOW_TSFTIMER);
+
+	return tsf;
+}
+
+static void rt2400pci_reset_tsf(struct ieee80211_hw *hw)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+
+	rt2x00pci_register_write(rt2x00dev, CSR16, 0);
+	rt2x00pci_register_write(rt2x00dev, CSR17, 0);
+}
+
+static int rt2400pci_tx_last_beacon(struct ieee80211_hw *hw)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, CSR15, &reg);
+	return rt2x00_get_field32(reg, CSR15_BEACON_SENT);
+}
+
+static const struct ieee80211_ops rt2400pci_mac80211_ops = {
+	.tx			= rt2x00mac_tx,
+	.start			= rt2x00mac_start,
+	.stop			= rt2x00mac_stop,
+	.add_interface		= rt2x00mac_add_interface,
+	.remove_interface	= rt2x00mac_remove_interface,
+	.config			= rt2x00mac_config,
+	.config_interface	= rt2x00mac_config_interface,
+	.configure_filter	= rt2400pci_configure_filter,
+	.get_stats		= rt2x00mac_get_stats,
+	.set_retry_limit	= rt2400pci_set_retry_limit,
+	.erp_ie_changed		= rt2x00mac_erp_ie_changed,
+	.conf_tx		= rt2400pci_conf_tx,
+	.get_tx_stats		= rt2x00mac_get_tx_stats,
+	.get_tsf		= rt2400pci_get_tsf,
+	.reset_tsf		= rt2400pci_reset_tsf,
+	.beacon_update		= rt2x00pci_beacon_update,
+	.tx_last_beacon		= rt2400pci_tx_last_beacon,
+};
+
+static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
+	.irq_handler		= rt2400pci_interrupt,
+	.probe_hw		= rt2400pci_probe_hw,
+	.initialize		= rt2x00pci_initialize,
+	.uninitialize		= rt2x00pci_uninitialize,
+	.set_device_state	= rt2400pci_set_device_state,
+	.rfkill_poll		= rt2400pci_rfkill_poll,
+	.link_stats		= rt2400pci_link_stats,
+	.reset_tuner		= rt2400pci_reset_tuner,
+	.link_tuner		= rt2400pci_link_tuner,
+	.write_tx_desc		= rt2400pci_write_tx_desc,
+	.write_tx_data		= rt2x00pci_write_tx_data,
+	.kick_tx_queue		= rt2400pci_kick_tx_queue,
+	.fill_rxdone		= rt2400pci_fill_rxdone,
+	.config_mac_addr	= rt2400pci_config_mac_addr,
+	.config_bssid		= rt2400pci_config_bssid,
+	.config_type		= rt2400pci_config_type,
+	.config_preamble	= rt2400pci_config_preamble,
+	.config			= rt2400pci_config,
+};
+
+static const struct rt2x00_ops rt2400pci_ops = {
+	.name		= DRV_NAME,
+	.rxd_size	= RXD_DESC_SIZE,
+	.txd_size	= TXD_DESC_SIZE,
+	.eeprom_size	= EEPROM_SIZE,
+	.rf_size	= RF_SIZE,
+	.lib		= &rt2400pci_rt2x00_ops,
+	.hw		= &rt2400pci_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+	.debugfs	= &rt2400pci_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * RT2400pci module information.
+ */
+static struct pci_device_id rt2400pci_device_table[] = {
+	{ PCI_DEVICE(0x1814, 0x0101), PCI_DEVICE_DATA(&rt2400pci_ops) },
+	{ 0, }
+};
+
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT2400 PCI & PCMCIA Wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Ralink RT2460 PCI & PCMCIA chipset based cards");
+MODULE_DEVICE_TABLE(pci, rt2400pci_device_table);
+MODULE_LICENSE("GPL");
+
+static struct pci_driver rt2400pci_driver = {
+	.name		= DRV_NAME,
+	.id_table	= rt2400pci_device_table,
+	.probe		= rt2x00pci_probe,
+	.remove		= __devexit_p(rt2x00pci_remove),
+	.suspend	= rt2x00pci_suspend,
+	.resume		= rt2x00pci_resume,
+};
+
+static int __init rt2400pci_init(void)
+{
+	return pci_register_driver(&rt2400pci_driver);
+}
+
+static void __exit rt2400pci_exit(void)
+{
+	pci_unregister_driver(&rt2400pci_driver);
+}
+
+module_init(rt2400pci_init);
+module_exit(rt2400pci_exit);
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h
new file mode 100644
index 0000000..ae22501
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2400pci.h
@@ -0,0 +1,943 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2400pci
+	Abstract: Data structures and registers for the rt2400pci module.
+	Supported chipsets: RT2460.
+ */
+
+#ifndef RT2400PCI_H
+#define RT2400PCI_H
+
+/*
+ * RF chip defines.
+ */
+#define RF2420				0x0000
+#define RF2421				0x0001
+
+/*
+ * Signal information.
+ * Defaul offset is required for RSSI <-> dBm conversion.
+ */
+#define MAX_SIGNAL			100
+#define MAX_RX_SSI			-1
+#define DEFAULT_RSSI_OFFSET		100
+
+/*
+ * Register layout information.
+ */
+#define CSR_REG_BASE			0x0000
+#define CSR_REG_SIZE			0x014c
+#define EEPROM_BASE			0x0000
+#define EEPROM_SIZE			0x0100
+#define BBP_SIZE			0x0020
+#define RF_SIZE				0x0010
+
+/*
+ * Control/Status Registers(CSR).
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * CSR0: ASIC revision number.
+ */
+#define CSR0				0x0000
+
+/*
+ * CSR1: System control register.
+ * SOFT_RESET: Software reset, 1: reset, 0: normal.
+ * BBP_RESET: Hardware reset, 1: reset, 0, release.
+ * HOST_READY: Host ready after initialization.
+ */
+#define CSR1				0x0004
+#define CSR1_SOFT_RESET			FIELD32(0x00000001)
+#define CSR1_BBP_RESET			FIELD32(0x00000002)
+#define CSR1_HOST_READY			FIELD32(0x00000004)
+
+/*
+ * CSR2: System admin status register (invalid).
+ */
+#define CSR2				0x0008
+
+/*
+ * CSR3: STA MAC address register 0.
+ */
+#define CSR3				0x000c
+#define CSR3_BYTE0			FIELD32(0x000000ff)
+#define CSR3_BYTE1			FIELD32(0x0000ff00)
+#define CSR3_BYTE2			FIELD32(0x00ff0000)
+#define CSR3_BYTE3			FIELD32(0xff000000)
+
+/*
+ * CSR4: STA MAC address register 1.
+ */
+#define CSR4				0x0010
+#define CSR4_BYTE4			FIELD32(0x000000ff)
+#define CSR4_BYTE5			FIELD32(0x0000ff00)
+
+/*
+ * CSR5: BSSID register 0.
+ */
+#define CSR5				0x0014
+#define CSR5_BYTE0			FIELD32(0x000000ff)
+#define CSR5_BYTE1			FIELD32(0x0000ff00)
+#define CSR5_BYTE2			FIELD32(0x00ff0000)
+#define CSR5_BYTE3			FIELD32(0xff000000)
+
+/*
+ * CSR6: BSSID register 1.
+ */
+#define CSR6				0x0018
+#define CSR6_BYTE4			FIELD32(0x000000ff)
+#define CSR6_BYTE5			FIELD32(0x0000ff00)
+
+/*
+ * CSR7: Interrupt source register.
+ * Write 1 to clear interrupt.
+ * TBCN_EXPIRE: Beacon timer expired interrupt.
+ * TWAKE_EXPIRE: Wakeup timer expired interrupt.
+ * TATIMW_EXPIRE: Timer of atim window expired interrupt.
+ * TXDONE_TXRING: Tx ring transmit done interrupt.
+ * TXDONE_ATIMRING: Atim ring transmit done interrupt.
+ * TXDONE_PRIORING: Priority ring transmit done interrupt.
+ * RXDONE: Receive done interrupt.
+ */
+#define CSR7				0x001c
+#define CSR7_TBCN_EXPIRE		FIELD32(0x00000001)
+#define CSR7_TWAKE_EXPIRE		FIELD32(0x00000002)
+#define CSR7_TATIMW_EXPIRE		FIELD32(0x00000004)
+#define CSR7_TXDONE_TXRING		FIELD32(0x00000008)
+#define CSR7_TXDONE_ATIMRING		FIELD32(0x00000010)
+#define CSR7_TXDONE_PRIORING		FIELD32(0x00000020)
+#define CSR7_RXDONE			FIELD32(0x00000040)
+
+/*
+ * CSR8: Interrupt mask register.
+ * Write 1 to mask interrupt.
+ * TBCN_EXPIRE: Beacon timer expired interrupt.
+ * TWAKE_EXPIRE: Wakeup timer expired interrupt.
+ * TATIMW_EXPIRE: Timer of atim window expired interrupt.
+ * TXDONE_TXRING: Tx ring transmit done interrupt.
+ * TXDONE_ATIMRING: Atim ring transmit done interrupt.
+ * TXDONE_PRIORING: Priority ring transmit done interrupt.
+ * RXDONE: Receive done interrupt.
+ */
+#define CSR8				0x0020
+#define CSR8_TBCN_EXPIRE		FIELD32(0x00000001)
+#define CSR8_TWAKE_EXPIRE		FIELD32(0x00000002)
+#define CSR8_TATIMW_EXPIRE		FIELD32(0x00000004)
+#define CSR8_TXDONE_TXRING		FIELD32(0x00000008)
+#define CSR8_TXDONE_ATIMRING		FIELD32(0x00000010)
+#define CSR8_TXDONE_PRIORING		FIELD32(0x00000020)
+#define CSR8_RXDONE			FIELD32(0x00000040)
+
+/*
+ * CSR9: Maximum frame length register.
+ * MAX_FRAME_UNIT: Maximum frame length in 128b unit, default: 12.
+ */
+#define CSR9				0x0024
+#define CSR9_MAX_FRAME_UNIT		FIELD32(0x00000f80)
+
+/*
+ * CSR11: Back-off control register.
+ * CWMIN: CWmin. Default cwmin is 31 (2^5 - 1).
+ * CWMAX: CWmax. Default cwmax is 1023 (2^10 - 1).
+ * SLOT_TIME: Slot time, default is 20us for 802.11b.
+ * LONG_RETRY: Long retry count.
+ * SHORT_RETRY: Short retry count.
+ */
+#define CSR11				0x002c
+#define CSR11_CWMIN			FIELD32(0x0000000f)
+#define CSR11_CWMAX			FIELD32(0x000000f0)
+#define CSR11_SLOT_TIME			FIELD32(0x00001f00)
+#define CSR11_LONG_RETRY		FIELD32(0x00ff0000)
+#define CSR11_SHORT_RETRY		FIELD32(0xff000000)
+
+/*
+ * CSR12: Synchronization configuration register 0.
+ * All units in 1/16 TU.
+ * BEACON_INTERVAL: Beacon interval, default is 100 TU.
+ * CFPMAX_DURATION: Cfp maximum duration, default is 100 TU.
+ */
+#define CSR12				0x0030
+#define CSR12_BEACON_INTERVAL		FIELD32(0x0000ffff)
+#define CSR12_CFP_MAX_DURATION		FIELD32(0xffff0000)
+
+/*
+ * CSR13: Synchronization configuration register 1.
+ * All units in 1/16 TU.
+ * ATIMW_DURATION: Atim window duration.
+ * CFP_PERIOD: Cfp period, default is 0 TU.
+ */
+#define CSR13				0x0034
+#define CSR13_ATIMW_DURATION		FIELD32(0x0000ffff)
+#define CSR13_CFP_PERIOD		FIELD32(0x00ff0000)
+
+/*
+ * CSR14: Synchronization control register.
+ * TSF_COUNT: Enable tsf auto counting.
+ * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
+ * TBCN: Enable tbcn with reload value.
+ * TCFP: Enable tcfp & cfp / cp switching.
+ * TATIMW: Enable tatimw & atim window switching.
+ * BEACON_GEN: Enable beacon generator.
+ * CFP_COUNT_PRELOAD: Cfp count preload value.
+ * TBCM_PRELOAD: Tbcn preload value in units of 64us.
+ */
+#define CSR14				0x0038
+#define CSR14_TSF_COUNT			FIELD32(0x00000001)
+#define CSR14_TSF_SYNC			FIELD32(0x00000006)
+#define CSR14_TBCN			FIELD32(0x00000008)
+#define CSR14_TCFP			FIELD32(0x00000010)
+#define CSR14_TATIMW			FIELD32(0x00000020)
+#define CSR14_BEACON_GEN		FIELD32(0x00000040)
+#define CSR14_CFP_COUNT_PRELOAD		FIELD32(0x0000ff00)
+#define CSR14_TBCM_PRELOAD		FIELD32(0xffff0000)
+
+/*
+ * CSR15: Synchronization status register.
+ * CFP: ASIC is in contention-free period.
+ * ATIMW: ASIC is in ATIM window.
+ * BEACON_SENT: Beacon is send.
+ */
+#define CSR15				0x003c
+#define CSR15_CFP			FIELD32(0x00000001)
+#define CSR15_ATIMW			FIELD32(0x00000002)
+#define CSR15_BEACON_SENT		FIELD32(0x00000004)
+
+/*
+ * CSR16: TSF timer register 0.
+ */
+#define CSR16				0x0040
+#define CSR16_LOW_TSFTIMER		FIELD32(0xffffffff)
+
+/*
+ * CSR17: TSF timer register 1.
+ */
+#define CSR17				0x0044
+#define CSR17_HIGH_TSFTIMER		FIELD32(0xffffffff)
+
+/*
+ * CSR18: IFS timer register 0.
+ * SIFS: Sifs, default is 10 us.
+ * PIFS: Pifs, default is 30 us.
+ */
+#define CSR18				0x0048
+#define CSR18_SIFS			FIELD32(0x0000ffff)
+#define CSR18_PIFS			FIELD32(0xffff0000)
+
+/*
+ * CSR19: IFS timer register 1.
+ * DIFS: Difs, default is 50 us.
+ * EIFS: Eifs, default is 364 us.
+ */
+#define CSR19				0x004c
+#define CSR19_DIFS			FIELD32(0x0000ffff)
+#define CSR19_EIFS			FIELD32(0xffff0000)
+
+/*
+ * CSR20: Wakeup timer register.
+ * DELAY_AFTER_TBCN: Delay after tbcn expired in units of 1/16 TU.
+ * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup.
+ * AUTOWAKE: Enable auto wakeup / sleep mechanism.
+ */
+#define CSR20				0x0050
+#define CSR20_DELAY_AFTER_TBCN		FIELD32(0x0000ffff)
+#define CSR20_TBCN_BEFORE_WAKEUP	FIELD32(0x00ff0000)
+#define CSR20_AUTOWAKE			FIELD32(0x01000000)
+
+/*
+ * CSR21: EEPROM control register.
+ * RELOAD: Write 1 to reload eeprom content.
+ * TYPE_93C46: 1: 93c46, 0:93c66.
+ */
+#define CSR21				0x0054
+#define CSR21_RELOAD			FIELD32(0x00000001)
+#define CSR21_EEPROM_DATA_CLOCK		FIELD32(0x00000002)
+#define CSR21_EEPROM_CHIP_SELECT	FIELD32(0x00000004)
+#define CSR21_EEPROM_DATA_IN		FIELD32(0x00000008)
+#define CSR21_EEPROM_DATA_OUT		FIELD32(0x00000010)
+#define CSR21_TYPE_93C46		FIELD32(0x00000020)
+
+/*
+ * CSR22: CFP control register.
+ * CFP_DURATION_REMAIN: Cfp duration remain, in units of TU.
+ * RELOAD_CFP_DURATION: Write 1 to reload cfp duration remain.
+ */
+#define CSR22				0x0058
+#define CSR22_CFP_DURATION_REMAIN	FIELD32(0x0000ffff)
+#define CSR22_RELOAD_CFP_DURATION	FIELD32(0x00010000)
+
+/*
+ * Transmit related CSRs.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * TXCSR0: TX Control Register.
+ * KICK_TX: Kick tx ring.
+ * KICK_ATIM: Kick atim ring.
+ * KICK_PRIO: Kick priority ring.
+ * ABORT: Abort all transmit related ring operation.
+ */
+#define TXCSR0				0x0060
+#define TXCSR0_KICK_TX			FIELD32(0x00000001)
+#define TXCSR0_KICK_ATIM		FIELD32(0x00000002)
+#define TXCSR0_KICK_PRIO		FIELD32(0x00000004)
+#define TXCSR0_ABORT			FIELD32(0x00000008)
+
+/*
+ * TXCSR1: TX Configuration Register.
+ * ACK_TIMEOUT: Ack timeout, default = sifs + 2*slottime + acktime @ 1mbps.
+ * ACK_CONSUME_TIME: Ack consume time, default = sifs + acktime @ 1mbps.
+ * TSF_OFFSET: Insert tsf offset.
+ * AUTORESPONDER: Enable auto responder which include ack & cts.
+ */
+#define TXCSR1				0x0064
+#define TXCSR1_ACK_TIMEOUT		FIELD32(0x000001ff)
+#define TXCSR1_ACK_CONSUME_TIME		FIELD32(0x0003fe00)
+#define TXCSR1_TSF_OFFSET		FIELD32(0x00fc0000)
+#define TXCSR1_AUTORESPONDER		FIELD32(0x01000000)
+
+/*
+ * TXCSR2: Tx descriptor configuration register.
+ * TXD_SIZE: Tx descriptor size, default is 48.
+ * NUM_TXD: Number of tx entries in ring.
+ * NUM_ATIM: Number of atim entries in ring.
+ * NUM_PRIO: Number of priority entries in ring.
+ */
+#define TXCSR2				0x0068
+#define TXCSR2_TXD_SIZE			FIELD32(0x000000ff)
+#define TXCSR2_NUM_TXD			FIELD32(0x0000ff00)
+#define TXCSR2_NUM_ATIM			FIELD32(0x00ff0000)
+#define TXCSR2_NUM_PRIO			FIELD32(0xff000000)
+
+/*
+ * TXCSR3: TX Ring Base address register.
+ */
+#define TXCSR3				0x006c
+#define TXCSR3_TX_RING_REGISTER		FIELD32(0xffffffff)
+
+/*
+ * TXCSR4: TX Atim Ring Base address register.
+ */
+#define TXCSR4				0x0070
+#define TXCSR4_ATIM_RING_REGISTER	FIELD32(0xffffffff)
+
+/*
+ * TXCSR5: TX Prio Ring Base address register.
+ */
+#define TXCSR5				0x0074
+#define TXCSR5_PRIO_RING_REGISTER	FIELD32(0xffffffff)
+
+/*
+ * TXCSR6: Beacon Base address register.
+ */
+#define TXCSR6				0x0078
+#define TXCSR6_BEACON_RING_REGISTER	FIELD32(0xffffffff)
+
+/*
+ * TXCSR7: Auto responder control register.
+ * AR_POWERMANAGEMENT: Auto responder power management bit.
+ */
+#define TXCSR7				0x007c
+#define TXCSR7_AR_POWERMANAGEMENT	FIELD32(0x00000001)
+
+/*
+ * Receive related CSRs.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * RXCSR0: RX Control Register.
+ * DISABLE_RX: Disable rx engine.
+ * DROP_CRC: Drop crc error.
+ * DROP_PHYSICAL: Drop physical error.
+ * DROP_CONTROL: Drop control frame.
+ * DROP_NOT_TO_ME: Drop not to me unicast frame.
+ * DROP_TODS: Drop frame tods bit is true.
+ * DROP_VERSION_ERROR: Drop version error frame.
+ * PASS_CRC: Pass all packets with crc attached.
+ */
+#define RXCSR0				0x0080
+#define RXCSR0_DISABLE_RX		FIELD32(0x00000001)
+#define RXCSR0_DROP_CRC			FIELD32(0x00000002)
+#define RXCSR0_DROP_PHYSICAL		FIELD32(0x00000004)
+#define RXCSR0_DROP_CONTROL		FIELD32(0x00000008)
+#define RXCSR0_DROP_NOT_TO_ME		FIELD32(0x00000010)
+#define RXCSR0_DROP_TODS		FIELD32(0x00000020)
+#define RXCSR0_DROP_VERSION_ERROR	FIELD32(0x00000040)
+#define RXCSR0_PASS_CRC			FIELD32(0x00000080)
+
+/*
+ * RXCSR1: RX descriptor configuration register.
+ * RXD_SIZE: Rx descriptor size, default is 32b.
+ * NUM_RXD: Number of rx entries in ring.
+ */
+#define RXCSR1				0x0084
+#define RXCSR1_RXD_SIZE			FIELD32(0x000000ff)
+#define RXCSR1_NUM_RXD			FIELD32(0x0000ff00)
+
+/*
+ * RXCSR2: RX Ring base address register.
+ */
+#define RXCSR2				0x0088
+#define RXCSR2_RX_RING_REGISTER		FIELD32(0xffffffff)
+
+/*
+ * RXCSR3: BBP ID register for Rx operation.
+ * BBP_ID#: BBP register # id.
+ * BBP_ID#_VALID: BBP register # id is valid or not.
+ */
+#define RXCSR3				0x0090
+#define RXCSR3_BBP_ID0			FIELD32(0x0000007f)
+#define RXCSR3_BBP_ID0_VALID		FIELD32(0x00000080)
+#define RXCSR3_BBP_ID1			FIELD32(0x00007f00)
+#define RXCSR3_BBP_ID1_VALID		FIELD32(0x00008000)
+#define RXCSR3_BBP_ID2			FIELD32(0x007f0000)
+#define RXCSR3_BBP_ID2_VALID		FIELD32(0x00800000)
+#define RXCSR3_BBP_ID3			FIELD32(0x7f000000)
+#define RXCSR3_BBP_ID3_VALID		FIELD32(0x80000000)
+
+/*
+ * RXCSR4: BBP ID register for Rx operation.
+ * BBP_ID#: BBP register # id.
+ * BBP_ID#_VALID: BBP register # id is valid or not.
+ */
+#define RXCSR4				0x0094
+#define RXCSR4_BBP_ID4			FIELD32(0x0000007f)
+#define RXCSR4_BBP_ID4_VALID		FIELD32(0x00000080)
+#define RXCSR4_BBP_ID5			FIELD32(0x00007f00)
+#define RXCSR4_BBP_ID5_VALID		FIELD32(0x00008000)
+
+/*
+ * ARCSR0: Auto Responder PLCP config register 0.
+ * ARCSR0_AR_BBP_DATA#: Auto responder BBP register # data.
+ * ARCSR0_AR_BBP_ID#: Auto responder BBP register # Id.
+ */
+#define ARCSR0				0x0098
+#define ARCSR0_AR_BBP_DATA0		FIELD32(0x000000ff)
+#define ARCSR0_AR_BBP_ID0		FIELD32(0x0000ff00)
+#define ARCSR0_AR_BBP_DATA1		FIELD32(0x00ff0000)
+#define ARCSR0_AR_BBP_ID1		FIELD32(0xff000000)
+
+/*
+ * ARCSR1: Auto Responder PLCP config register 1.
+ * ARCSR0_AR_BBP_DATA#: Auto responder BBP register # data.
+ * ARCSR0_AR_BBP_ID#: Auto responder BBP register # Id.
+ */
+#define ARCSR1				0x009c
+#define ARCSR1_AR_BBP_DATA2		FIELD32(0x000000ff)
+#define ARCSR1_AR_BBP_ID2		FIELD32(0x0000ff00)
+#define ARCSR1_AR_BBP_DATA3		FIELD32(0x00ff0000)
+#define ARCSR1_AR_BBP_ID3		FIELD32(0xff000000)
+
+/*
+ * Miscellaneous Registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * PCICSR: PCI control register.
+ * BIG_ENDIAN: 1: big endian, 0: little endian.
+ * RX_TRESHOLD: Rx threshold in dw to start pci access
+ * 0: 16dw (default), 1: 8dw, 2: 4dw, 3: 32dw.
+ * TX_TRESHOLD: Tx threshold in dw to start pci access
+ * 0: 0dw (default), 1: 1dw, 2: 4dw, 3: forward.
+ * BURST_LENTH: Pci burst length 0: 4dw (default, 1: 8dw, 2: 16dw, 3:32dw.
+ * ENABLE_CLK: Enable clk_run, pci clock can't going down to non-operational.
+ */
+#define PCICSR				0x008c
+#define PCICSR_BIG_ENDIAN		FIELD32(0x00000001)
+#define PCICSR_RX_TRESHOLD		FIELD32(0x00000006)
+#define PCICSR_TX_TRESHOLD		FIELD32(0x00000018)
+#define PCICSR_BURST_LENTH		FIELD32(0x00000060)
+#define PCICSR_ENABLE_CLK		FIELD32(0x00000080)
+
+/*
+ * CNT0: FCS error count.
+ * FCS_ERROR: FCS error count, cleared when read.
+ */
+#define CNT0				0x00a0
+#define CNT0_FCS_ERROR			FIELD32(0x0000ffff)
+
+/*
+ * Statistic Register.
+ * CNT1: PLCP error count.
+ * CNT2: Long error count.
+ * CNT3: CCA false alarm count.
+ * CNT4: Rx FIFO overflow count.
+ * CNT5: Tx FIFO underrun count.
+ */
+#define TIMECSR2			0x00a8
+#define CNT1				0x00ac
+#define CNT2				0x00b0
+#define TIMECSR3			0x00b4
+#define CNT3				0x00b8
+#define CNT4				0x00bc
+#define CNT5				0x00c0
+
+/*
+ * Baseband Control Register.
+ */
+
+/*
+ * PWRCSR0: Power mode configuration register.
+ */
+#define PWRCSR0				0x00c4
+
+/*
+ * Power state transition time registers.
+ */
+#define PSCSR0				0x00c8
+#define PSCSR1				0x00cc
+#define PSCSR2				0x00d0
+#define PSCSR3				0x00d4
+
+/*
+ * PWRCSR1: Manual power control / status register.
+ * Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake.
+ * SET_STATE: Set state. Write 1 to trigger, self cleared.
+ * BBP_DESIRE_STATE: BBP desired state.
+ * RF_DESIRE_STATE: RF desired state.
+ * BBP_CURR_STATE: BBP current state.
+ * RF_CURR_STATE: RF current state.
+ * PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared.
+ */
+#define PWRCSR1				0x00d8
+#define PWRCSR1_SET_STATE		FIELD32(0x00000001)
+#define PWRCSR1_BBP_DESIRE_STATE	FIELD32(0x00000006)
+#define PWRCSR1_RF_DESIRE_STATE		FIELD32(0x00000018)
+#define PWRCSR1_BBP_CURR_STATE		FIELD32(0x00000060)
+#define PWRCSR1_RF_CURR_STATE		FIELD32(0x00000180)
+#define PWRCSR1_PUT_TO_SLEEP		FIELD32(0x00000200)
+
+/*
+ * TIMECSR: Timer control register.
+ * US_COUNT: 1 us timer count in units of clock cycles.
+ * US_64_COUNT: 64 us timer count in units of 1 us timer.
+ * BEACON_EXPECT: Beacon expect window.
+ */
+#define TIMECSR				0x00dc
+#define TIMECSR_US_COUNT		FIELD32(0x000000ff)
+#define TIMECSR_US_64_COUNT		FIELD32(0x0000ff00)
+#define TIMECSR_BEACON_EXPECT		FIELD32(0x00070000)
+
+/*
+ * MACCSR0: MAC configuration register 0.
+ */
+#define MACCSR0				0x00e0
+
+/*
+ * MACCSR1: MAC configuration register 1.
+ * KICK_RX: Kick one-shot rx in one-shot rx mode.
+ * ONESHOT_RXMODE: Enable one-shot rx mode for debugging.
+ * BBPRX_RESET_MODE: Ralink bbp rx reset mode.
+ * AUTO_TXBBP: Auto tx logic access bbp control register.
+ * AUTO_RXBBP: Auto rx logic access bbp control register.
+ * LOOPBACK: Loopback mode. 0: normal, 1: internal, 2: external, 3:rsvd.
+ * INTERSIL_IF: Intersil if calibration pin.
+ */
+#define MACCSR1				0x00e4
+#define MACCSR1_KICK_RX			FIELD32(0x00000001)
+#define MACCSR1_ONESHOT_RXMODE		FIELD32(0x00000002)
+#define MACCSR1_BBPRX_RESET_MODE	FIELD32(0x00000004)
+#define MACCSR1_AUTO_TXBBP		FIELD32(0x00000008)
+#define MACCSR1_AUTO_RXBBP		FIELD32(0x00000010)
+#define MACCSR1_LOOPBACK		FIELD32(0x00000060)
+#define MACCSR1_INTERSIL_IF		FIELD32(0x00000080)
+
+/*
+ * RALINKCSR: Ralink Rx auto-reset BBCR.
+ * AR_BBP_DATA#: Auto reset BBP register # data.
+ * AR_BBP_ID#: Auto reset BBP register # id.
+ */
+#define RALINKCSR			0x00e8
+#define RALINKCSR_AR_BBP_DATA0		FIELD32(0x000000ff)
+#define RALINKCSR_AR_BBP_ID0		FIELD32(0x0000ff00)
+#define RALINKCSR_AR_BBP_DATA1		FIELD32(0x00ff0000)
+#define RALINKCSR_AR_BBP_ID1		FIELD32(0xff000000)
+
+/*
+ * BCNCSR: Beacon interval control register.
+ * CHANGE: Write one to change beacon interval.
+ * DELTATIME: The delta time value.
+ * NUM_BEACON: Number of beacon according to mode.
+ * MODE: Please refer to asic specs.
+ * PLUS: Plus or minus delta time value.
+ */
+#define BCNCSR				0x00ec
+#define BCNCSR_CHANGE			FIELD32(0x00000001)
+#define BCNCSR_DELTATIME		FIELD32(0x0000001e)
+#define BCNCSR_NUM_BEACON		FIELD32(0x00001fe0)
+#define BCNCSR_MODE			FIELD32(0x00006000)
+#define BCNCSR_PLUS			FIELD32(0x00008000)
+
+/*
+ * BBP / RF / IF Control Register.
+ */
+
+/*
+ * BBPCSR: BBP serial control register.
+ * VALUE: Register value to program into BBP.
+ * REGNUM: Selected BBP register.
+ * BUSY: 1: asic is busy execute BBP programming.
+ * WRITE_CONTROL: 1: write BBP, 0: read BBP.
+ */
+#define BBPCSR				0x00f0
+#define BBPCSR_VALUE			FIELD32(0x000000ff)
+#define BBPCSR_REGNUM			FIELD32(0x00007f00)
+#define BBPCSR_BUSY			FIELD32(0x00008000)
+#define BBPCSR_WRITE_CONTROL		FIELD32(0x00010000)
+
+/*
+ * RFCSR: RF serial control register.
+ * VALUE: Register value + id to program into rf/if.
+ * NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22).
+ * IF_SELECT: Chip to program: 0: rf, 1: if.
+ * PLL_LD: Rf pll_ld status.
+ * BUSY: 1: asic is busy execute rf programming.
+ */
+#define RFCSR				0x00f4
+#define RFCSR_VALUE			FIELD32(0x00ffffff)
+#define RFCSR_NUMBER_OF_BITS		FIELD32(0x1f000000)
+#define RFCSR_IF_SELECT			FIELD32(0x20000000)
+#define RFCSR_PLL_LD			FIELD32(0x40000000)
+#define RFCSR_BUSY			FIELD32(0x80000000)
+
+/*
+ * LEDCSR: LED control register.
+ * ON_PERIOD: On period, default 70ms.
+ * OFF_PERIOD: Off period, default 30ms.
+ * LINK: 0: linkoff, 1: linkup.
+ * ACTIVITY: 0: idle, 1: active.
+ */
+#define LEDCSR				0x00f8
+#define LEDCSR_ON_PERIOD		FIELD32(0x000000ff)
+#define LEDCSR_OFF_PERIOD		FIELD32(0x0000ff00)
+#define LEDCSR_LINK			FIELD32(0x00010000)
+#define LEDCSR_ACTIVITY			FIELD32(0x00020000)
+
+/*
+ * ASIC pointer information.
+ * RXPTR: Current RX ring address.
+ * TXPTR: Current Tx ring address.
+ * PRIPTR: Current Priority ring address.
+ * ATIMPTR: Current ATIM ring address.
+ */
+#define RXPTR				0x0100
+#define TXPTR				0x0104
+#define PRIPTR				0x0108
+#define ATIMPTR				0x010c
+
+/*
+ * GPIO and others.
+ */
+
+/*
+ * GPIOCSR: GPIO control register.
+ */
+#define GPIOCSR				0x0120
+#define GPIOCSR_BIT0			FIELD32(0x00000001)
+#define GPIOCSR_BIT1			FIELD32(0x00000002)
+#define GPIOCSR_BIT2			FIELD32(0x00000004)
+#define GPIOCSR_BIT3			FIELD32(0x00000008)
+#define GPIOCSR_BIT4			FIELD32(0x00000010)
+#define GPIOCSR_BIT5			FIELD32(0x00000020)
+#define GPIOCSR_BIT6			FIELD32(0x00000040)
+#define GPIOCSR_BIT7			FIELD32(0x00000080)
+
+/*
+ * BBPPCSR: BBP Pin control register.
+ */
+#define BBPPCSR				0x0124
+
+/*
+ * BCNCSR1: Tx BEACON offset time control register.
+ * PRELOAD: Beacon timer offset in units of usec.
+ */
+#define BCNCSR1				0x0130
+#define BCNCSR1_PRELOAD			FIELD32(0x0000ffff)
+
+/*
+ * MACCSR2: TX_PE to RX_PE turn-around time control register
+ * DELAY: RX_PE low width, in units of pci clock cycle.
+ */
+#define MACCSR2				0x0134
+#define MACCSR2_DELAY			FIELD32(0x000000ff)
+
+/*
+ * ARCSR2: 1 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR2				0x013c
+#define ARCSR2_SIGNAL			FIELD32(0x000000ff)
+#define ARCSR2_SERVICE			FIELD32(0x0000ff00)
+#define ARCSR2_LENGTH_LOW		FIELD32(0x00ff0000)
+#define ARCSR2_LENGTH			FIELD32(0xffff0000)
+
+/*
+ * ARCSR3: 2 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR3				0x0140
+#define ARCSR3_SIGNAL			FIELD32(0x000000ff)
+#define ARCSR3_SERVICE			FIELD32(0x0000ff00)
+#define ARCSR3_LENGTH			FIELD32(0xffff0000)
+
+/*
+ * ARCSR4: 5.5 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR4				0x0144
+#define ARCSR4_SIGNAL			FIELD32(0x000000ff)
+#define ARCSR4_SERVICE			FIELD32(0x0000ff00)
+#define ARCSR4_LENGTH			FIELD32(0xffff0000)
+
+/*
+ * ARCSR5: 11 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR5				0x0148
+#define ARCSR5_SIGNAL			FIELD32(0x000000ff)
+#define ARCSR5_SERVICE			FIELD32(0x0000ff00)
+#define ARCSR5_LENGTH			FIELD32(0xffff0000)
+
+/*
+ * BBP registers.
+ * The wordsize of the BBP is 8 bits.
+ */
+
+/*
+ * R1: TX antenna control
+ */
+#define BBP_R1_TX_ANTENNA		FIELD8(0x03)
+
+/*
+ * R4: RX antenna control
+ */
+#define BBP_R4_RX_ANTENNA		FIELD8(0x06)
+
+/*
+ * RF registers
+ */
+
+/*
+ * RF 1
+ */
+#define RF1_TUNER			FIELD32(0x00020000)
+
+/*
+ * RF 3
+ */
+#define RF3_TUNER			FIELD32(0x00000100)
+#define RF3_TXPOWER			FIELD32(0x00003e00)
+
+/*
+ * EEPROM content.
+ * The wordsize of the EEPROM is 16 bits.
+ */
+
+/*
+ * HW MAC address.
+ */
+#define EEPROM_MAC_ADDR_0		0x0002
+#define EEPROM_MAC_ADDR_BYTE0		FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE1		FIELD16(0xff00)
+#define EEPROM_MAC_ADDR1		0x0003
+#define EEPROM_MAC_ADDR_BYTE2		FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE3		FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_2		0x0004
+#define EEPROM_MAC_ADDR_BYTE4		FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE5		FIELD16(0xff00)
+
+/*
+ * EEPROM antenna.
+ * ANTENNA_NUM: Number of antenna's.
+ * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RF_TYPE: Rf_type of this adapter.
+ * LED_MODE: 0: default, 1: TX/RX activity,2: Single (ignore link), 3: rsvd.
+ * RX_AGCVGC: 0: disable, 1:enable BBP R13 tuning.
+ * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
+ */
+#define EEPROM_ANTENNA			0x0b
+#define EEPROM_ANTENNA_NUM		FIELD16(0x0003)
+#define EEPROM_ANTENNA_TX_DEFAULT	FIELD16(0x000c)
+#define EEPROM_ANTENNA_RX_DEFAULT	FIELD16(0x0030)
+#define EEPROM_ANTENNA_RF_TYPE		FIELD16(0x0040)
+#define EEPROM_ANTENNA_LED_MODE		FIELD16(0x0180)
+#define EEPROM_ANTENNA_RX_AGCVGC_TUNING	FIELD16(0x0200)
+#define EEPROM_ANTENNA_HARDWARE_RADIO	FIELD16(0x0400)
+
+/*
+ * EEPROM BBP.
+ */
+#define EEPROM_BBP_START		0x0c
+#define EEPROM_BBP_SIZE			7
+#define EEPROM_BBP_VALUE		FIELD16(0x00ff)
+#define EEPROM_BBP_REG_ID		FIELD16(0xff00)
+
+/*
+ * EEPROM TXPOWER
+ */
+#define EEPROM_TXPOWER_START		0x13
+#define EEPROM_TXPOWER_SIZE		7
+#define EEPROM_TXPOWER_1		FIELD16(0x00ff)
+#define EEPROM_TXPOWER_2		FIELD16(0xff00)
+
+/*
+ * DMA descriptor defines.
+ */
+#define TXD_DESC_SIZE			( 8 * sizeof(struct data_desc) )
+#define RXD_DESC_SIZE			( 8 * sizeof(struct data_desc) )
+
+/*
+ * TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
+ */
+
+/*
+ * Word0
+ */
+#define TXD_W0_OWNER_NIC		FIELD32(0x00000001)
+#define TXD_W0_VALID			FIELD32(0x00000002)
+#define TXD_W0_RESULT			FIELD32(0x0000001c)
+#define TXD_W0_RETRY_COUNT		FIELD32(0x000000e0)
+#define TXD_W0_MORE_FRAG		FIELD32(0x00000100)
+#define TXD_W0_ACK			FIELD32(0x00000200)
+#define TXD_W0_TIMESTAMP		FIELD32(0x00000400)
+#define TXD_W0_RTS			FIELD32(0x00000800)
+#define TXD_W0_IFS			FIELD32(0x00006000)
+#define TXD_W0_RETRY_MODE		FIELD32(0x00008000)
+#define TXD_W0_AGC			FIELD32(0x00ff0000)
+#define TXD_W0_R2			FIELD32(0xff000000)
+
+/*
+ * Word1
+ */
+#define TXD_W1_BUFFER_ADDRESS		FIELD32(0xffffffff)
+
+/*
+ * Word2
+ */
+#define TXD_W2_BUFFER_LENGTH		FIELD32(0x0000ffff)
+#define TXD_W2_DATABYTE_COUNT		FIELD32(0xffff0000)
+
+/*
+ * Word3 & 4: PLCP information
+ */
+#define TXD_W3_PLCP_SIGNAL		FIELD32(0x0000ffff)
+#define TXD_W3_PLCP_SERVICE		FIELD32(0xffff0000)
+#define TXD_W4_PLCP_LENGTH_LOW		FIELD32(0x0000ffff)
+#define TXD_W4_PLCP_LENGTH_HIGH		FIELD32(0xffff0000)
+
+/*
+ * Word5
+ */
+#define TXD_W5_BBCR4			FIELD32(0x0000ffff)
+#define TXD_W5_AGC_REG			FIELD32(0x007f0000)
+#define TXD_W5_AGC_REG_VALID		FIELD32(0x00800000)
+#define TXD_W5_XXX_REG			FIELD32(0x7f000000)
+#define TXD_W5_XXX_REG_VALID		FIELD32(0x80000000)
+
+/*
+ * Word6
+ */
+#define TXD_W6_SK_BUFF			FIELD32(0xffffffff)
+
+/*
+ * Word7
+ */
+#define TXD_W7_RESERVED			FIELD32(0xffffffff)
+
+/*
+ * RX descriptor format for RX Ring.
+ */
+
+/*
+ * Word0
+ */
+#define RXD_W0_OWNER_NIC		FIELD32(0x00000001)
+#define RXD_W0_UNICAST_TO_ME		FIELD32(0x00000002)
+#define RXD_W0_MULTICAST		FIELD32(0x00000004)
+#define RXD_W0_BROADCAST		FIELD32(0x00000008)
+#define RXD_W0_MY_BSS			FIELD32(0x00000010)
+#define RXD_W0_CRC_ERROR		FIELD32(0x00000020)
+#define RXD_W0_PHYSICAL_ERROR		FIELD32(0x00000080)
+#define RXD_W0_DATABYTE_COUNT		FIELD32(0xffff0000)
+
+/*
+ * Word1
+ */
+#define RXD_W1_BUFFER_ADDRESS		FIELD32(0xffffffff)
+
+/*
+ * Word2
+ */
+#define RXD_W2_BUFFER_LENGTH		FIELD32(0x0000ffff)
+#define RXD_W2_SIGNAL			FIELD32(0x00ff0000)
+#define RXD_W2_RSSI			FIELD32(0xff000000)
+
+/*
+ * Word3
+ */
+#define RXD_W3_BBR2			FIELD32(0x000000ff)
+#define RXD_W3_BBR3			FIELD32(0x0000ff00)
+#define RXD_W3_BBR4			FIELD32(0x00ff0000)
+#define RXD_W3_BBR5			FIELD32(0xff000000)
+
+/*
+ * Word4
+ */
+#define RXD_W4_RX_END_TIME		FIELD32(0xffffffff)
+
+/*
+ * Word5 & 6 & 7: Reserved
+ */
+#define RXD_W5_RESERVED			FIELD32(0xffffffff)
+#define RXD_W6_RESERVED			FIELD32(0xffffffff)
+#define RXD_W7_RESERVED			FIELD32(0xffffffff)
+
+/*
+ * Macro's for converting txpower from EEPROM to dscape value
+ * and from dscape value to register value.
+ * NOTE: Logics in rt2400pci for txpower are reversed
+ * compared to the other rt2x00 drivers. A higher txpower
+ * value means that the txpower must be lowered. This is
+ * important when converting the value coming from the
+ * dscape stack to the rt2400 acceptable value.
+ */
+#define MIN_TXPOWER	31
+#define MAX_TXPOWER	62
+#define DEFAULT_TXPOWER	39
+
+#define TXPOWER_FROM_DEV(__txpower)					\
+({									\
+	((__txpower) > MAX_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER :	\
+	((__txpower) < MIN_TXPOWER) ? DEFAULT_TXPOWER - MIN_TXPOWER :	\
+	(((__txpower) - MAX_TXPOWER) + MIN_TXPOWER);			\
+})
+
+#define TXPOWER_TO_DEV(__txpower)			\
+({							\
+	(__txpower) += MIN_TXPOWER;			\
+	((__txpower) <= MIN_TXPOWER) ? MAX_TXPOWER :	\
+	(((__txpower) >= MAX_TXPOWER) ? MIN_TXPOWER :	\
+	(MAX_TXPOWER - ((__txpower) - MIN_TXPOWER)));	\
+})
+
+#endif /* RT2400PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
new file mode 100644
index 0000000..ff2d632
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -0,0 +1,1971 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2500pci
+	Abstract: rt2500pci device specific routines.
+	Supported chipsets: RT2560.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2500pci"
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/eeprom_93cx6.h>
+
+#include "rt2x00.h"
+#include "rt2x00pci.h"
+#include "rt2500pci.h"
+
+/*
+ * Register access.
+ * All access to the CSR registers will go through the methods
+ * rt2x00pci_register_read and rt2x00pci_register_write.
+ * BBP and RF register require indirect register access,
+ * and use the CSR registers BBPCSR and RFCSR to achieve this.
+ * These indirect registers work with busy bits,
+ * and we will try maximal REGISTER_BUSY_COUNT times to access
+ * the register while taking a REGISTER_BUSY_DELAY us delay
+ * between each attampt. When the busy bit is still set at that time,
+ * the access attempt is considered to have failed,
+ * and we will print an error.
+ */
+static u32 rt2500pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+	unsigned int i;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2x00pci_register_read(rt2x00dev, BBPCSR, &reg);
+		if (!rt2x00_get_field32(reg, BBPCSR_BUSY))
+			break;
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	return reg;
+}
+
+static void rt2500pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
+				const unsigned int word, const u8 value)
+{
+	u32 reg;
+
+	/*
+	 * Wait until the BBP becomes ready.
+	 */
+	reg = rt2500pci_bbp_check(rt2x00dev);
+	if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+		ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n");
+		return;
+	}
+
+	/*
+	 * Write the data into the BBP.
+	 */
+	reg = 0;
+	rt2x00_set_field32(&reg, BBPCSR_VALUE, value);
+	rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+	rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+	rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 1);
+
+	rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+}
+
+static void rt2500pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
+			       const unsigned int word, u8 *value)
+{
+	u32 reg;
+
+	/*
+	 * Wait until the BBP becomes ready.
+	 */
+	reg = rt2500pci_bbp_check(rt2x00dev);
+	if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+		ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
+		return;
+	}
+
+	/*
+	 * Write the request into the BBP.
+	 */
+	reg = 0;
+	rt2x00_set_field32(&reg, BBPCSR_REGNUM, word);
+	rt2x00_set_field32(&reg, BBPCSR_BUSY, 1);
+	rt2x00_set_field32(&reg, BBPCSR_WRITE_CONTROL, 0);
+
+	rt2x00pci_register_write(rt2x00dev, BBPCSR, reg);
+
+	/*
+	 * Wait until the BBP becomes ready.
+	 */
+	reg = rt2500pci_bbp_check(rt2x00dev);
+	if (rt2x00_get_field32(reg, BBPCSR_BUSY)) {
+		ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n");
+		*value = 0xff;
+		return;
+	}
+
+	*value = rt2x00_get_field32(reg, BBPCSR_VALUE);
+}
+
+static void rt2500pci_rf_write(const struct rt2x00_dev *rt2x00dev,
+			       const unsigned int word, const u32 value)
+{
+	u32 reg;
+	unsigned int i;
+
+	if (!word)
+		return;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2x00pci_register_read(rt2x00dev, RFCSR, &reg);
+		if (!rt2x00_get_field32(reg, RFCSR_BUSY))
+			goto rf_write;
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n");
+	return;
+
+rf_write:
+	reg = 0;
+	rt2x00_set_field32(&reg, RFCSR_VALUE, value);
+	rt2x00_set_field32(&reg, RFCSR_NUMBER_OF_BITS, 20);
+	rt2x00_set_field32(&reg, RFCSR_IF_SELECT, 0);
+	rt2x00_set_field32(&reg, RFCSR_BUSY, 1);
+
+	rt2x00pci_register_write(rt2x00dev, RFCSR, reg);
+	rt2x00_rf_write(rt2x00dev, word, value);
+}
+
+static void rt2500pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
+{
+	struct rt2x00_dev *rt2x00dev = eeprom->data;
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, CSR21, &reg);
+
+	eeprom->reg_data_in = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_IN);
+	eeprom->reg_data_out = !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_OUT);
+	eeprom->reg_data_clock =
+	    !!rt2x00_get_field32(reg, CSR21_EEPROM_DATA_CLOCK);
+	eeprom->reg_chip_select =
+	    !!rt2x00_get_field32(reg, CSR21_EEPROM_CHIP_SELECT);
+}
+
+static void rt2500pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
+{
+	struct rt2x00_dev *rt2x00dev = eeprom->data;
+	u32 reg = 0;
+
+	rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_IN, !!eeprom->reg_data_in);
+	rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_OUT, !!eeprom->reg_data_out);
+	rt2x00_set_field32(&reg, CSR21_EEPROM_DATA_CLOCK,
+			   !!eeprom->reg_data_clock);
+	rt2x00_set_field32(&reg, CSR21_EEPROM_CHIP_SELECT,
+			   !!eeprom->reg_chip_select);
+
+	rt2x00pci_register_write(rt2x00dev, CSR21, reg);
+}
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+#define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
+
+static void rt2500pci_read_csr(const struct rt2x00_dev *rt2x00dev,
+			       const unsigned int word, u32 *data)
+{
+	rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static void rt2500pci_write_csr(const struct rt2x00_dev *rt2x00dev,
+				const unsigned int word, u32 data)
+{
+	rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static const struct rt2x00debug rt2500pci_rt2x00debug = {
+	.owner	= THIS_MODULE,
+	.csr	= {
+		.read		= rt2500pci_read_csr,
+		.write		= rt2500pci_write_csr,
+		.word_size	= sizeof(u32),
+		.word_count	= CSR_REG_SIZE / sizeof(u32),
+	},
+	.eeprom	= {
+		.read		= rt2x00_eeprom_read,
+		.write		= rt2x00_eeprom_write,
+		.word_size	= sizeof(u16),
+		.word_count	= EEPROM_SIZE / sizeof(u16),
+	},
+	.bbp	= {
+		.read		= rt2500pci_bbp_read,
+		.write		= rt2500pci_bbp_write,
+		.word_size	= sizeof(u8),
+		.word_count	= BBP_SIZE / sizeof(u8),
+	},
+	.rf	= {
+		.read		= rt2x00_rf_read,
+		.write		= rt2500pci_rf_write,
+		.word_size	= sizeof(u32),
+		.word_count	= RF_SIZE / sizeof(u32),
+	},
+};
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+#ifdef CONFIG_RT2500PCI_RFKILL
+static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, GPIOCSR, &reg);
+	return rt2x00_get_field32(reg, GPIOCSR_BIT0);
+}
+#else
+#define rt2500pci_rfkill_poll	NULL
+#endif /* CONFIG_RT2500PCI_RFKILL */
+
+/*
+ * Configuration handlers.
+ */
+static void rt2500pci_config_mac_addr(struct rt2x00_dev *rt2x00dev,
+				      __le32 *mac)
+{
+	rt2x00pci_register_multiwrite(rt2x00dev, CSR3, mac,
+				      (2 * sizeof(__le32)));
+}
+
+static void rt2500pci_config_bssid(struct rt2x00_dev *rt2x00dev,
+				   __le32 *bssid)
+{
+	rt2x00pci_register_multiwrite(rt2x00dev, CSR5, bssid,
+				      (2 * sizeof(__le32)));
+}
+
+static void rt2500pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
+				  const int tsf_sync)
+{
+	u32 reg;
+
+	rt2x00pci_register_write(rt2x00dev, CSR14, 0);
+
+	/*
+	 * Enable beacon config
+	 */
+	rt2x00pci_register_read(rt2x00dev, BCNCSR1, &reg);
+	rt2x00_set_field32(&reg, BCNCSR1_PRELOAD,
+			   PREAMBLE + get_duration(IEEE80211_HEADER, 20));
+	rt2x00_set_field32(&reg, BCNCSR1_BEACON_CWMIN,
+			   rt2x00lib_get_ring(rt2x00dev,
+					      IEEE80211_TX_QUEUE_BEACON)
+			   ->tx_params.cw_min);
+	rt2x00pci_register_write(rt2x00dev, BCNCSR1, reg);
+
+	/*
+	 * Enable synchronisation.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+	rt2x00_set_field32(&reg, CSR14_TSF_COUNT, 1);
+	rt2x00_set_field32(&reg, CSR14_TBCN, 1);
+	rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
+	rt2x00_set_field32(&reg, CSR14_TSF_SYNC, tsf_sync);
+	rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+}
+
+static void rt2500pci_config_preamble(struct rt2x00_dev *rt2x00dev,
+				      const int short_preamble,
+				      const int ack_timeout,
+				      const int ack_consume_time)
+{
+	int preamble_mask;
+	u32 reg;
+
+	/*
+	 * When short preamble is enabled, we should set bit 0x08
+	 */
+	preamble_mask = short_preamble << 3;
+
+	rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
+	rt2x00_set_field32(&reg, TXCSR1_ACK_TIMEOUT, ack_timeout);
+	rt2x00_set_field32(&reg, TXCSR1_ACK_CONSUME_TIME, ack_consume_time);
+	rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
+
+	rt2x00pci_register_read(rt2x00dev, ARCSR2, &reg);
+	rt2x00_set_field32(&reg, ARCSR2_SIGNAL, 0x00 | preamble_mask);
+	rt2x00_set_field32(&reg, ARCSR2_SERVICE, 0x04);
+	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10));
+	rt2x00pci_register_write(rt2x00dev, ARCSR2, reg);
+
+	rt2x00pci_register_read(rt2x00dev, ARCSR3, &reg);
+	rt2x00_set_field32(&reg, ARCSR3_SIGNAL, 0x01 | preamble_mask);
+	rt2x00_set_field32(&reg, ARCSR3_SERVICE, 0x04);
+	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20));
+	rt2x00pci_register_write(rt2x00dev, ARCSR3, reg);
+
+	rt2x00pci_register_read(rt2x00dev, ARCSR4, &reg);
+	rt2x00_set_field32(&reg, ARCSR4_SIGNAL, 0x02 | preamble_mask);
+	rt2x00_set_field32(&reg, ARCSR4_SERVICE, 0x04);
+	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55));
+	rt2x00pci_register_write(rt2x00dev, ARCSR4, reg);
+
+	rt2x00pci_register_read(rt2x00dev, ARCSR5, &reg);
+	rt2x00_set_field32(&reg, ARCSR5_SIGNAL, 0x03 | preamble_mask);
+	rt2x00_set_field32(&reg, ARCSR5_SERVICE, 0x84);
+	rt2x00_set_field32(&reg, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110));
+	rt2x00pci_register_write(rt2x00dev, ARCSR5, reg);
+}
+
+static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev,
+				     const int basic_rate_mask)
+{
+	rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask);
+}
+
+static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev,
+				     struct rf_channel *rf, const int txpower)
+{
+	u8 r70;
+
+	/*
+	 * Set TXpower.
+	 */
+	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+
+	/*
+	 * Switch on tuning bits.
+	 * For RT2523 devices we do not need to update the R1 register.
+	 */
+	if (!rt2x00_rf(&rt2x00dev->chip, RF2523))
+		rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1);
+	rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1);
+
+	/*
+	 * For RT2525 we should first set the channel to half band higher.
+	 */
+	if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+		static const u32 vals[] = {
+			0x00080cbe, 0x00080d02, 0x00080d06, 0x00080d0a,
+			0x00080d0e, 0x00080d12, 0x00080d16, 0x00080d1a,
+			0x00080d1e, 0x00080d22, 0x00080d26, 0x00080d2a,
+			0x00080d2e, 0x00080d3a
+		};
+
+		rt2500pci_rf_write(rt2x00dev, 1, rf->rf1);
+		rt2500pci_rf_write(rt2x00dev, 2, vals[rf->channel - 1]);
+		rt2500pci_rf_write(rt2x00dev, 3, rf->rf3);
+		if (rf->rf4)
+			rt2500pci_rf_write(rt2x00dev, 4, rf->rf4);
+	}
+
+	rt2500pci_rf_write(rt2x00dev, 1, rf->rf1);
+	rt2500pci_rf_write(rt2x00dev, 2, rf->rf2);
+	rt2500pci_rf_write(rt2x00dev, 3, rf->rf3);
+	if (rf->rf4)
+		rt2500pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+	/*
+	 * Channel 14 requires the Japan filter bit to be set.
+	 */
+	r70 = 0x46;
+	rt2x00_set_field8(&r70, BBP_R70_JAPAN_FILTER, rf->channel == 14);
+	rt2500pci_bbp_write(rt2x00dev, 70, r70);
+
+	msleep(1);
+
+	/*
+	 * Switch off tuning bits.
+	 * For RT2523 devices we do not need to update the R1 register.
+	 */
+	if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+		rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0);
+		rt2500pci_rf_write(rt2x00dev, 1, rf->rf1);
+	}
+
+	rt2x00_set_field32(&rf->rf3, RF3_TUNER, 0);
+	rt2500pci_rf_write(rt2x00dev, 3, rf->rf3);
+
+	/*
+	 * Clear false CRC during channel switch.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CNT0, &rf->rf1);
+}
+
+static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev,
+				     const int txpower)
+{
+	u32 rf3;
+
+	rt2x00_rf_read(rt2x00dev, 3, &rf3);
+	rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+	rt2500pci_rf_write(rt2x00dev, 3, rf3);
+}
+
+static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev,
+				     const int antenna_tx, const int antenna_rx)
+{
+	u32 reg;
+	u8 r14;
+	u8 r2;
+
+	rt2x00pci_register_read(rt2x00dev, BBPCSR1, &reg);
+	rt2500pci_bbp_read(rt2x00dev, 14, &r14);
+	rt2500pci_bbp_read(rt2x00dev, 2, &r2);
+
+	/*
+	 * Configure the TX antenna.
+	 */
+	switch (antenna_tx) {
+	case ANTENNA_SW_DIVERSITY:
+	case ANTENNA_HW_DIVERSITY:
+		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
+		rt2x00_set_field32(&reg, BBPCSR1_CCK, 2);
+		rt2x00_set_field32(&reg, BBPCSR1_OFDM, 2);
+		break;
+	case ANTENNA_A:
+		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0);
+		rt2x00_set_field32(&reg, BBPCSR1_CCK, 0);
+		rt2x00_set_field32(&reg, BBPCSR1_OFDM, 0);
+		break;
+	case ANTENNA_B:
+		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
+		rt2x00_set_field32(&reg, BBPCSR1_CCK, 2);
+		rt2x00_set_field32(&reg, BBPCSR1_OFDM, 2);
+		break;
+	}
+
+	/*
+	 * Configure the RX antenna.
+	 */
+	switch (antenna_rx) {
+	case ANTENNA_SW_DIVERSITY:
+	case ANTENNA_HW_DIVERSITY:
+		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
+		break;
+	case ANTENNA_A:
+		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
+		break;
+	case ANTENNA_B:
+		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
+		break;
+	}
+
+	/*
+	 * RT2525E and RT5222 need to flip TX I/Q
+	 */
+	if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
+	    rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+		rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
+		rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 1);
+		rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 1);
+
+		/*
+		 * RT2525E does not need RX I/Q Flip.
+		 */
+		if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
+			rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
+	} else {
+		rt2x00_set_field32(&reg, BBPCSR1_CCK_FLIP, 0);
+		rt2x00_set_field32(&reg, BBPCSR1_OFDM_FLIP, 0);
+	}
+
+	rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg);
+	rt2500pci_bbp_write(rt2x00dev, 14, r14);
+	rt2500pci_bbp_write(rt2x00dev, 2, r2);
+}
+
+static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev,
+				      struct rt2x00lib_conf *libconf)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+	rt2x00_set_field32(&reg, CSR11_SLOT_TIME, libconf->slot_time);
+	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR18, &reg);
+	rt2x00_set_field32(&reg, CSR18_SIFS, libconf->sifs);
+	rt2x00_set_field32(&reg, CSR18_PIFS, libconf->pifs);
+	rt2x00pci_register_write(rt2x00dev, CSR18, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR19, &reg);
+	rt2x00_set_field32(&reg, CSR19_DIFS, libconf->difs);
+	rt2x00_set_field32(&reg, CSR19_EIFS, libconf->eifs);
+	rt2x00pci_register_write(rt2x00dev, CSR19, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TXCSR1, &reg);
+	rt2x00_set_field32(&reg, TXCSR1_TSF_OFFSET, IEEE80211_HEADER);
+	rt2x00_set_field32(&reg, TXCSR1_AUTORESPONDER, 1);
+	rt2x00pci_register_write(rt2x00dev, TXCSR1, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR12, &reg);
+	rt2x00_set_field32(&reg, CSR12_BEACON_INTERVAL,
+			   libconf->conf->beacon_int * 16);
+	rt2x00_set_field32(&reg, CSR12_CFP_MAX_DURATION,
+			   libconf->conf->beacon_int * 16);
+	rt2x00pci_register_write(rt2x00dev, CSR12, reg);
+}
+
+static void rt2500pci_config(struct rt2x00_dev *rt2x00dev,
+			     const unsigned int flags,
+			     struct rt2x00lib_conf *libconf)
+{
+	if (flags & CONFIG_UPDATE_PHYMODE)
+		rt2500pci_config_phymode(rt2x00dev, libconf->basic_rates);
+	if (flags & CONFIG_UPDATE_CHANNEL)
+		rt2500pci_config_channel(rt2x00dev, &libconf->rf,
+					 libconf->conf->power_level);
+	if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+		rt2500pci_config_txpower(rt2x00dev,
+					 libconf->conf->power_level);
+	if (flags & CONFIG_UPDATE_ANTENNA)
+		rt2500pci_config_antenna(rt2x00dev,
+					 libconf->conf->antenna_sel_tx,
+					 libconf->conf->antenna_sel_rx);
+	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+		rt2500pci_config_duration(rt2x00dev, libconf);
+}
+
+/*
+ * LED functions.
+ */
+static void rt2500pci_enable_led(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
+
+	rt2x00_set_field32(&reg, LEDCSR_ON_PERIOD, 70);
+	rt2x00_set_field32(&reg, LEDCSR_OFF_PERIOD, 30);
+
+	if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) {
+		rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
+		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
+	} else if (rt2x00dev->led_mode == LED_MODE_ASUS) {
+		rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
+		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
+	} else {
+		rt2x00_set_field32(&reg, LEDCSR_LINK, 1);
+		rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 1);
+	}
+
+	rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
+}
+
+static void rt2500pci_disable_led(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
+	rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
+	rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
+	rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
+}
+
+/*
+ * Link tuning
+ */
+static void rt2500pci_link_stats(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	/*
+	 * Update FCS error count from register.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
+	rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, CNT0_FCS_ERROR);
+
+	/*
+	 * Update False CCA count from register.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CNT3, &reg);
+	rt2x00dev->link.false_cca = rt2x00_get_field32(reg, CNT3_FALSE_CCA);
+}
+
+static void rt2500pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
+{
+	rt2500pci_bbp_write(rt2x00dev, 17, 0x48);
+	rt2x00dev->link.vgc_level = 0x48;
+}
+
+static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+	int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
+	u8 r17;
+
+	/*
+	 * To prevent collisions with MAC ASIC on chipsets
+	 * up to version C the link tuning should halt after 20
+	 * seconds.
+	 */
+	if (rt2x00_get_rev(&rt2x00dev->chip) < RT2560_VERSION_D &&
+	    rt2x00dev->link.count > 20)
+		return;
+
+	rt2500pci_bbp_read(rt2x00dev, 17, &r17);
+
+	/*
+	 * Chipset versions C and lower should directly continue
+	 * to the dynamic CCA tuning.
+	 */
+	if (rt2x00_get_rev(&rt2x00dev->chip) < RT2560_VERSION_D)
+		goto dynamic_cca_tune;
+
+	/*
+	 * A too low RSSI will cause too much false CCA which will
+	 * then corrupt the R17 tuning. To remidy this the tuning should
+	 * be stopped (While making sure the R17 value will not exceed limits)
+	 */
+	if (rssi < -80 && rt2x00dev->link.count > 20) {
+		if (r17 >= 0x41) {
+			r17 = rt2x00dev->link.vgc_level;
+			rt2500pci_bbp_write(rt2x00dev, 17, r17);
+		}
+		return;
+	}
+
+	/*
+	 * Special big-R17 for short distance
+	 */
+	if (rssi >= -58) {
+		if (r17 != 0x50)
+			rt2500pci_bbp_write(rt2x00dev, 17, 0x50);
+		return;
+	}
+
+	/*
+	 * Special mid-R17 for middle distance
+	 */
+	if (rssi >= -74) {
+		if (r17 != 0x41)
+			rt2500pci_bbp_write(rt2x00dev, 17, 0x41);
+		return;
+	}
+
+	/*
+	 * Leave short or middle distance condition, restore r17
+	 * to the dynamic tuning range.
+	 */
+	if (r17 >= 0x41) {
+		rt2500pci_bbp_write(rt2x00dev, 17, rt2x00dev->link.vgc_level);
+		return;
+	}
+
+dynamic_cca_tune:
+
+	/*
+	 * R17 is inside the dynamic tuning range,
+	 * start tuning the link based on the false cca counter.
+	 */
+	if (rt2x00dev->link.false_cca > 512 && r17 < 0x40) {
+		rt2500pci_bbp_write(rt2x00dev, 17, ++r17);
+		rt2x00dev->link.vgc_level = r17;
+	} else if (rt2x00dev->link.false_cca < 100 && r17 > 0x32) {
+		rt2500pci_bbp_write(rt2x00dev, 17, --r17);
+		rt2x00dev->link.vgc_level = r17;
+	}
+}
+
+/*
+ * Initialization functions.
+ */
+static void rt2500pci_init_rxring(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_ring *ring = rt2x00dev->rx;
+	struct data_desc *rxd;
+	unsigned int i;
+	u32 word;
+
+	memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+	for (i = 0; i < ring->stats.limit; i++) {
+		rxd = ring->entry[i].priv;
+
+		rt2x00_desc_read(rxd, 1, &word);
+		rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS,
+				   ring->entry[i].data_dma);
+		rt2x00_desc_write(rxd, 1, word);
+
+		rt2x00_desc_read(rxd, 0, &word);
+		rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+		rt2x00_desc_write(rxd, 0, word);
+	}
+
+	rt2x00_ring_index_clear(rt2x00dev->rx);
+}
+
+static void rt2500pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue)
+{
+	struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
+	struct data_desc *txd;
+	unsigned int i;
+	u32 word;
+
+	memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+	for (i = 0; i < ring->stats.limit; i++) {
+		txd = ring->entry[i].priv;
+
+		rt2x00_desc_read(txd, 1, &word);
+		rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS,
+				   ring->entry[i].data_dma);
+		rt2x00_desc_write(txd, 1, word);
+
+		rt2x00_desc_read(txd, 0, &word);
+		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+		rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+		rt2x00_desc_write(txd, 0, word);
+	}
+
+	rt2x00_ring_index_clear(ring);
+}
+
+static int rt2500pci_init_rings(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	/*
+	 * Initialize rings.
+	 */
+	rt2500pci_init_rxring(rt2x00dev);
+	rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+	rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+	rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
+	rt2500pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+
+	/*
+	 * Initialize registers.
+	 */
+	rt2x00pci_register_read(rt2x00dev, TXCSR2, &reg);
+	rt2x00_set_field32(&reg, TXCSR2_TXD_SIZE,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size);
+	rt2x00_set_field32(&reg, TXCSR2_NUM_TXD,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit);
+	rt2x00_set_field32(&reg, TXCSR2_NUM_ATIM,
+			   rt2x00dev->bcn[1].stats.limit);
+	rt2x00_set_field32(&reg, TXCSR2_NUM_PRIO,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit);
+	rt2x00pci_register_write(rt2x00dev, TXCSR2, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TXCSR3, &reg);
+	rt2x00_set_field32(&reg, TXCSR3_TX_RING_REGISTER,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma);
+	rt2x00pci_register_write(rt2x00dev, TXCSR3, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TXCSR5, &reg);
+	rt2x00_set_field32(&reg, TXCSR5_PRIO_RING_REGISTER,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma);
+	rt2x00pci_register_write(rt2x00dev, TXCSR5, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TXCSR4, &reg);
+	rt2x00_set_field32(&reg, TXCSR4_ATIM_RING_REGISTER,
+			   rt2x00dev->bcn[1].data_dma);
+	rt2x00pci_register_write(rt2x00dev, TXCSR4, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TXCSR6, &reg);
+	rt2x00_set_field32(&reg, TXCSR6_BEACON_RING_REGISTER,
+			   rt2x00dev->bcn[0].data_dma);
+	rt2x00pci_register_write(rt2x00dev, TXCSR6, reg);
+
+	rt2x00pci_register_read(rt2x00dev, RXCSR1, &reg);
+	rt2x00_set_field32(&reg, RXCSR1_RXD_SIZE, rt2x00dev->rx->desc_size);
+	rt2x00_set_field32(&reg, RXCSR1_NUM_RXD, rt2x00dev->rx->stats.limit);
+	rt2x00pci_register_write(rt2x00dev, RXCSR1, reg);
+
+	rt2x00pci_register_read(rt2x00dev, RXCSR2, &reg);
+	rt2x00_set_field32(&reg, RXCSR2_RX_RING_REGISTER,
+			   rt2x00dev->rx->data_dma);
+	rt2x00pci_register_write(rt2x00dev, RXCSR2, reg);
+
+	return 0;
+}
+
+static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	rt2x00pci_register_write(rt2x00dev, PSCSR0, 0x00020002);
+	rt2x00pci_register_write(rt2x00dev, PSCSR1, 0x00000002);
+	rt2x00pci_register_write(rt2x00dev, PSCSR2, 0x00020002);
+	rt2x00pci_register_write(rt2x00dev, PSCSR3, 0x00000002);
+
+	rt2x00pci_register_read(rt2x00dev, TIMECSR, &reg);
+	rt2x00_set_field32(&reg, TIMECSR_US_COUNT, 33);
+	rt2x00_set_field32(&reg, TIMECSR_US_64_COUNT, 63);
+	rt2x00_set_field32(&reg, TIMECSR_BEACON_EXPECT, 0);
+	rt2x00pci_register_write(rt2x00dev, TIMECSR, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR9, &reg);
+	rt2x00_set_field32(&reg, CSR9_MAX_FRAME_UNIT,
+			   rt2x00dev->rx->data_size / 128);
+	rt2x00pci_register_write(rt2x00dev, CSR9, reg);
+
+	/*
+	 * Always use CWmin and CWmax set in descriptor.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+	rt2x00_set_field32(&reg, CSR11_CW_SELECT, 0);
+	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+	rt2x00pci_register_write(rt2x00dev, CNT3, 0);
+
+	rt2x00pci_register_read(rt2x00dev, TXCSR8, &reg);
+	rt2x00_set_field32(&reg, TXCSR8_BBP_ID0, 10);
+	rt2x00_set_field32(&reg, TXCSR8_BBP_ID0_VALID, 1);
+	rt2x00_set_field32(&reg, TXCSR8_BBP_ID1, 11);
+	rt2x00_set_field32(&reg, TXCSR8_BBP_ID1_VALID, 1);
+	rt2x00_set_field32(&reg, TXCSR8_BBP_ID2, 13);
+	rt2x00_set_field32(&reg, TXCSR8_BBP_ID2_VALID, 1);
+	rt2x00_set_field32(&reg, TXCSR8_BBP_ID3, 12);
+	rt2x00_set_field32(&reg, TXCSR8_BBP_ID3_VALID, 1);
+	rt2x00pci_register_write(rt2x00dev, TXCSR8, reg);
+
+	rt2x00pci_register_read(rt2x00dev, ARTCSR0, &reg);
+	rt2x00_set_field32(&reg, ARTCSR0_ACK_CTS_1MBS, 112);
+	rt2x00_set_field32(&reg, ARTCSR0_ACK_CTS_2MBS, 56);
+	rt2x00_set_field32(&reg, ARTCSR0_ACK_CTS_5_5MBS, 20);
+	rt2x00_set_field32(&reg, ARTCSR0_ACK_CTS_11MBS, 10);
+	rt2x00pci_register_write(rt2x00dev, ARTCSR0, reg);
+
+	rt2x00pci_register_read(rt2x00dev, ARTCSR1, &reg);
+	rt2x00_set_field32(&reg, ARTCSR1_ACK_CTS_6MBS, 45);
+	rt2x00_set_field32(&reg, ARTCSR1_ACK_CTS_9MBS, 37);
+	rt2x00_set_field32(&reg, ARTCSR1_ACK_CTS_12MBS, 33);
+	rt2x00_set_field32(&reg, ARTCSR1_ACK_CTS_18MBS, 29);
+	rt2x00pci_register_write(rt2x00dev, ARTCSR1, reg);
+
+	rt2x00pci_register_read(rt2x00dev, ARTCSR2, &reg);
+	rt2x00_set_field32(&reg, ARTCSR2_ACK_CTS_24MBS, 29);
+	rt2x00_set_field32(&reg, ARTCSR2_ACK_CTS_36MBS, 25);
+	rt2x00_set_field32(&reg, ARTCSR2_ACK_CTS_48MBS, 25);
+	rt2x00_set_field32(&reg, ARTCSR2_ACK_CTS_54MBS, 25);
+	rt2x00pci_register_write(rt2x00dev, ARTCSR2, reg);
+
+	rt2x00pci_register_read(rt2x00dev, RXCSR3, &reg);
+	rt2x00_set_field32(&reg, RXCSR3_BBP_ID0, 47); /* CCK Signal */
+	rt2x00_set_field32(&reg, RXCSR3_BBP_ID0_VALID, 1);
+	rt2x00_set_field32(&reg, RXCSR3_BBP_ID1, 51); /* Rssi */
+	rt2x00_set_field32(&reg, RXCSR3_BBP_ID1_VALID, 1);
+	rt2x00_set_field32(&reg, RXCSR3_BBP_ID2, 42); /* OFDM Rate */
+	rt2x00_set_field32(&reg, RXCSR3_BBP_ID2_VALID, 1);
+	rt2x00_set_field32(&reg, RXCSR3_BBP_ID3, 51); /* RSSI */
+	rt2x00_set_field32(&reg, RXCSR3_BBP_ID3_VALID, 1);
+	rt2x00pci_register_write(rt2x00dev, RXCSR3, reg);
+
+	rt2x00pci_register_read(rt2x00dev, PCICSR, &reg);
+	rt2x00_set_field32(&reg, PCICSR_BIG_ENDIAN, 0);
+	rt2x00_set_field32(&reg, PCICSR_RX_TRESHOLD, 0);
+	rt2x00_set_field32(&reg, PCICSR_TX_TRESHOLD, 3);
+	rt2x00_set_field32(&reg, PCICSR_BURST_LENTH, 1);
+	rt2x00_set_field32(&reg, PCICSR_ENABLE_CLK, 1);
+	rt2x00_set_field32(&reg, PCICSR_READ_MULTIPLE, 1);
+	rt2x00_set_field32(&reg, PCICSR_WRITE_INVALID, 1);
+	rt2x00pci_register_write(rt2x00dev, PCICSR, reg);
+
+	rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0x3f3b3100);
+
+	rt2x00pci_register_write(rt2x00dev, GPIOCSR, 0x0000ff00);
+	rt2x00pci_register_write(rt2x00dev, TESTCSR, 0x000000f0);
+
+	if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+		return -EBUSY;
+
+	rt2x00pci_register_write(rt2x00dev, MACCSR0, 0x00213223);
+	rt2x00pci_register_write(rt2x00dev, MACCSR1, 0x00235518);
+
+	rt2x00pci_register_read(rt2x00dev, MACCSR2, &reg);
+	rt2x00_set_field32(&reg, MACCSR2_DELAY, 64);
+	rt2x00pci_register_write(rt2x00dev, MACCSR2, reg);
+
+	rt2x00pci_register_read(rt2x00dev, RALINKCSR, &reg);
+	rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_DATA0, 17);
+	rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_ID0, 26);
+	rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_VALID0, 1);
+	rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_DATA1, 0);
+	rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_ID1, 26);
+	rt2x00_set_field32(&reg, RALINKCSR_AR_BBP_VALID1, 1);
+	rt2x00pci_register_write(rt2x00dev, RALINKCSR, reg);
+
+	rt2x00pci_register_write(rt2x00dev, BBPCSR1, 0x82188200);
+
+	rt2x00pci_register_write(rt2x00dev, TXACKCSR0, 0x00000020);
+
+	rt2x00pci_register_read(rt2x00dev, CSR1, &reg);
+	rt2x00_set_field32(&reg, CSR1_SOFT_RESET, 1);
+	rt2x00_set_field32(&reg, CSR1_BBP_RESET, 0);
+	rt2x00_set_field32(&reg, CSR1_HOST_READY, 0);
+	rt2x00pci_register_write(rt2x00dev, CSR1, reg);
+
+	rt2x00pci_register_read(rt2x00dev, CSR1, &reg);
+	rt2x00_set_field32(&reg, CSR1_SOFT_RESET, 0);
+	rt2x00_set_field32(&reg, CSR1_HOST_READY, 1);
+	rt2x00pci_register_write(rt2x00dev, CSR1, reg);
+
+	/*
+	 * We must clear the FCS and FIFO error count.
+	 * These registers are cleared on read,
+	 * so we may pass a useless variable to store the value.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CNT0, &reg);
+	rt2x00pci_register_read(rt2x00dev, CNT4, &reg);
+
+	return 0;
+}
+
+static int rt2500pci_init_bbp(struct rt2x00_dev *rt2x00dev)
+{
+	unsigned int i;
+	u16 eeprom;
+	u8 reg_id;
+	u8 value;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2500pci_bbp_read(rt2x00dev, 0, &value);
+		if ((value != 0xff) && (value != 0x00))
+			goto continue_csr_init;
+		NOTICE(rt2x00dev, "Waiting for BBP register.\n");
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+	return -EACCES;
+
+continue_csr_init:
+	rt2500pci_bbp_write(rt2x00dev, 3, 0x02);
+	rt2500pci_bbp_write(rt2x00dev, 4, 0x19);
+	rt2500pci_bbp_write(rt2x00dev, 14, 0x1c);
+	rt2500pci_bbp_write(rt2x00dev, 15, 0x30);
+	rt2500pci_bbp_write(rt2x00dev, 16, 0xac);
+	rt2500pci_bbp_write(rt2x00dev, 18, 0x18);
+	rt2500pci_bbp_write(rt2x00dev, 19, 0xff);
+	rt2500pci_bbp_write(rt2x00dev, 20, 0x1e);
+	rt2500pci_bbp_write(rt2x00dev, 21, 0x08);
+	rt2500pci_bbp_write(rt2x00dev, 22, 0x08);
+	rt2500pci_bbp_write(rt2x00dev, 23, 0x08);
+	rt2500pci_bbp_write(rt2x00dev, 24, 0x70);
+	rt2500pci_bbp_write(rt2x00dev, 25, 0x40);
+	rt2500pci_bbp_write(rt2x00dev, 26, 0x08);
+	rt2500pci_bbp_write(rt2x00dev, 27, 0x23);
+	rt2500pci_bbp_write(rt2x00dev, 30, 0x10);
+	rt2500pci_bbp_write(rt2x00dev, 31, 0x2b);
+	rt2500pci_bbp_write(rt2x00dev, 32, 0xb9);
+	rt2500pci_bbp_write(rt2x00dev, 34, 0x12);
+	rt2500pci_bbp_write(rt2x00dev, 35, 0x50);
+	rt2500pci_bbp_write(rt2x00dev, 39, 0xc4);
+	rt2500pci_bbp_write(rt2x00dev, 40, 0x02);
+	rt2500pci_bbp_write(rt2x00dev, 41, 0x60);
+	rt2500pci_bbp_write(rt2x00dev, 53, 0x10);
+	rt2500pci_bbp_write(rt2x00dev, 54, 0x18);
+	rt2500pci_bbp_write(rt2x00dev, 56, 0x08);
+	rt2500pci_bbp_write(rt2x00dev, 57, 0x10);
+	rt2500pci_bbp_write(rt2x00dev, 58, 0x08);
+	rt2500pci_bbp_write(rt2x00dev, 61, 0x6d);
+	rt2500pci_bbp_write(rt2x00dev, 62, 0x10);
+
+	DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
+	for (i = 0; i < EEPROM_BBP_SIZE; i++) {
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+
+		if (eeprom != 0xffff && eeprom != 0x0000) {
+			reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
+			value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
+			DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
+			      reg_id, value);
+			rt2500pci_bbp_write(rt2x00dev, reg_id, value);
+		}
+	}
+	DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
+
+	return 0;
+}
+
+/*
+ * Device state switch handlers.
+ */
+static void rt2500pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
+				enum dev_state state)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+	rt2x00_set_field32(&reg, RXCSR0_DISABLE_RX,
+			   state == STATE_RADIO_RX_OFF);
+	rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+}
+
+static void rt2500pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
+				 enum dev_state state)
+{
+	int mask = (state == STATE_RADIO_IRQ_OFF);
+	u32 reg;
+
+	/*
+	 * When interrupts are being enabled, the interrupt registers
+	 * should clear the register to assure a clean state.
+	 */
+	if (state == STATE_RADIO_IRQ_ON) {
+		rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+		rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+	}
+
+	/*
+	 * Only toggle the interrupts bits we are going to use.
+	 * Non-checked interrupt bits are disabled by default.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CSR8, &reg);
+	rt2x00_set_field32(&reg, CSR8_TBCN_EXPIRE, mask);
+	rt2x00_set_field32(&reg, CSR8_TXDONE_TXRING, mask);
+	rt2x00_set_field32(&reg, CSR8_TXDONE_ATIMRING, mask);
+	rt2x00_set_field32(&reg, CSR8_TXDONE_PRIORING, mask);
+	rt2x00_set_field32(&reg, CSR8_RXDONE, mask);
+	rt2x00pci_register_write(rt2x00dev, CSR8, reg);
+}
+
+static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+	/*
+	 * Initialize all registers.
+	 */
+	if (rt2500pci_init_rings(rt2x00dev) ||
+	    rt2500pci_init_registers(rt2x00dev) ||
+	    rt2500pci_init_bbp(rt2x00dev)) {
+		ERROR(rt2x00dev, "Register initialization failed.\n");
+		return -EIO;
+	}
+
+	/*
+	 * Enable interrupts.
+	 */
+	rt2500pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON);
+
+	/*
+	 * Enable LED
+	 */
+	rt2500pci_enable_led(rt2x00dev);
+
+	return 0;
+}
+
+static void rt2500pci_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	/*
+	 * Disable LED
+	 */
+	rt2500pci_disable_led(rt2x00dev);
+
+	rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0);
+
+	/*
+	 * Disable synchronisation.
+	 */
+	rt2x00pci_register_write(rt2x00dev, CSR14, 0);
+
+	/*
+	 * Cancel RX and TX.
+	 */
+	rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+	rt2x00_set_field32(&reg, TXCSR0_ABORT, 1);
+	rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+
+	/*
+	 * Disable interrupts.
+	 */
+	rt2500pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF);
+}
+
+static int rt2500pci_set_state(struct rt2x00_dev *rt2x00dev,
+			       enum dev_state state)
+{
+	u32 reg;
+	unsigned int i;
+	char put_to_sleep;
+	char bbp_state;
+	char rf_state;
+
+	put_to_sleep = (state != STATE_AWAKE);
+
+	rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg);
+	rt2x00_set_field32(&reg, PWRCSR1_SET_STATE, 1);
+	rt2x00_set_field32(&reg, PWRCSR1_BBP_DESIRE_STATE, state);
+	rt2x00_set_field32(&reg, PWRCSR1_RF_DESIRE_STATE, state);
+	rt2x00_set_field32(&reg, PWRCSR1_PUT_TO_SLEEP, put_to_sleep);
+	rt2x00pci_register_write(rt2x00dev, PWRCSR1, reg);
+
+	/*
+	 * Device is not guaranteed to be in the requested state yet.
+	 * We must wait until the register indicates that the
+	 * device has entered the correct state.
+	 */
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2x00pci_register_read(rt2x00dev, PWRCSR1, &reg);
+		bbp_state = rt2x00_get_field32(reg, PWRCSR1_BBP_CURR_STATE);
+		rf_state = rt2x00_get_field32(reg, PWRCSR1_RF_CURR_STATE);
+		if (bbp_state == state && rf_state == state)
+			return 0;
+		msleep(10);
+	}
+
+	NOTICE(rt2x00dev, "Device failed to enter state %d, "
+	       "current device state: bbp %d and rf %d.\n",
+	       state, bbp_state, rf_state);
+
+	return -EBUSY;
+}
+
+static int rt2500pci_set_device_state(struct rt2x00_dev *rt2x00dev,
+				      enum dev_state state)
+{
+	int retval = 0;
+
+	switch (state) {
+	case STATE_RADIO_ON:
+		retval = rt2500pci_enable_radio(rt2x00dev);
+		break;
+	case STATE_RADIO_OFF:
+		rt2500pci_disable_radio(rt2x00dev);
+		break;
+	case STATE_RADIO_RX_ON:
+	case STATE_RADIO_RX_OFF:
+		rt2500pci_toggle_rx(rt2x00dev, state);
+		break;
+	case STATE_DEEP_SLEEP:
+	case STATE_SLEEP:
+	case STATE_STANDBY:
+	case STATE_AWAKE:
+		retval = rt2500pci_set_state(rt2x00dev, state);
+		break;
+	default:
+		retval = -ENOTSUPP;
+		break;
+	}
+
+	return retval;
+}
+
+/*
+ * TX descriptor initialization
+ */
+static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+				    struct data_desc *txd,
+				    struct txdata_entry_desc *desc,
+				    struct ieee80211_hdr *ieee80211hdr,
+				    unsigned int length,
+				    struct ieee80211_tx_control *control)
+{
+	u32 word;
+
+	/*
+	 * Start writing the descriptor words.
+	 */
+	rt2x00_desc_read(txd, 2, &word);
+	rt2x00_set_field32(&word, TXD_W2_IV_OFFSET, IEEE80211_HEADER);
+	rt2x00_set_field32(&word, TXD_W2_AIFS, desc->aifs);
+	rt2x00_set_field32(&word, TXD_W2_CWMIN, desc->cw_min);
+	rt2x00_set_field32(&word, TXD_W2_CWMAX, desc->cw_max);
+	rt2x00_desc_write(txd, 2, word);
+
+	rt2x00_desc_read(txd, 3, &word);
+	rt2x00_set_field32(&word, TXD_W3_PLCP_SIGNAL, desc->signal);
+	rt2x00_set_field32(&word, TXD_W3_PLCP_SERVICE, desc->service);
+	rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_LOW, desc->length_low);
+	rt2x00_set_field32(&word, TXD_W3_PLCP_LENGTH_HIGH, desc->length_high);
+	rt2x00_desc_write(txd, 3, word);
+
+	rt2x00_desc_read(txd, 10, &word);
+	rt2x00_set_field32(&word, TXD_W10_RTS,
+			   test_bit(ENTRY_TXD_RTS_FRAME, &desc->flags));
+	rt2x00_desc_write(txd, 10, word);
+
+	rt2x00_desc_read(txd, 0, &word);
+	rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
+	rt2x00_set_field32(&word, TXD_W0_VALID, 1);
+	rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+			   test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_ACK,
+			   !(control->flags & IEEE80211_TXCTL_NO_ACK));
+	rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+			   test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_OFDM,
+			   test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_CIPHER_OWNER, 1);
+	rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+	rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
+			   !!(control->flags &
+			      IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
+	rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
+	rt2x00_desc_write(txd, 0, word);
+}
+
+/*
+ * TX data initialization
+ */
+static void rt2500pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+				    unsigned int queue)
+{
+	u32 reg;
+
+	if (queue == IEEE80211_TX_QUEUE_BEACON) {
+		rt2x00pci_register_read(rt2x00dev, CSR14, &reg);
+		if (!rt2x00_get_field32(reg, CSR14_BEACON_GEN)) {
+			rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
+			rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+		}
+		return;
+	}
+
+	rt2x00pci_register_read(rt2x00dev, TXCSR0, &reg);
+	if (queue == IEEE80211_TX_QUEUE_DATA0)
+		rt2x00_set_field32(&reg, TXCSR0_KICK_PRIO, 1);
+	else if (queue == IEEE80211_TX_QUEUE_DATA1)
+		rt2x00_set_field32(&reg, TXCSR0_KICK_TX, 1);
+	else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
+		rt2x00_set_field32(&reg, TXCSR0_KICK_ATIM, 1);
+	rt2x00pci_register_write(rt2x00dev, TXCSR0, reg);
+}
+
+/*
+ * RX control handlers
+ */
+static void rt2500pci_fill_rxdone(struct data_entry *entry,
+				  struct rxdata_entry_desc *desc)
+{
+	struct data_desc *rxd = entry->priv;
+	u32 word0;
+	u32 word2;
+
+	rt2x00_desc_read(rxd, 0, &word0);
+	rt2x00_desc_read(rxd, 2, &word2);
+
+	desc->flags = 0;
+	if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+		desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+	if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
+		desc->flags |= RX_FLAG_FAILED_PLCP_CRC;
+
+	desc->signal = rt2x00_get_field32(word2, RXD_W2_SIGNAL);
+	desc->rssi = rt2x00_get_field32(word2, RXD_W2_RSSI) -
+	    entry->ring->rt2x00dev->rssi_offset;
+	desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+	desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+}
+
+/*
+ * Interrupt functions.
+ */
+static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev, const int queue)
+{
+	struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
+	struct data_entry *entry;
+	struct data_desc *txd;
+	u32 word;
+	int tx_status;
+	int retry;
+
+	while (!rt2x00_ring_empty(ring)) {
+		entry = rt2x00_get_data_entry_done(ring);
+		txd = entry->priv;
+		rt2x00_desc_read(txd, 0, &word);
+
+		if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
+		    !rt2x00_get_field32(word, TXD_W0_VALID))
+			break;
+
+		/*
+		 * Obtain the status about this packet.
+		 */
+		tx_status = rt2x00_get_field32(word, TXD_W0_RESULT);
+		retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
+
+		rt2x00lib_txdone(entry, tx_status, retry);
+
+		/*
+		 * Make this entry available for reuse.
+		 */
+		entry->flags = 0;
+		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+		rt2x00_desc_write(txd, 0, word);
+		rt2x00_ring_index_done_inc(ring);
+	}
+
+	/*
+	 * If the data ring was full before the txdone handler
+	 * we must make sure the packet queue in the mac80211 stack
+	 * is reenabled when the txdone handler has finished.
+	 */
+	entry = ring->entry;
+	if (!rt2x00_ring_full(ring))
+		ieee80211_wake_queue(rt2x00dev->hw,
+				     entry->tx_status.control.queue);
+}
+
+static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
+{
+	struct rt2x00_dev *rt2x00dev = dev_instance;
+	u32 reg;
+
+	/*
+	 * Get the interrupt sources & saved to local variable.
+	 * Write register value back to clear pending interrupts.
+	 */
+	rt2x00pci_register_read(rt2x00dev, CSR7, &reg);
+	rt2x00pci_register_write(rt2x00dev, CSR7, reg);
+
+	if (!reg)
+		return IRQ_NONE;
+
+	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+		return IRQ_HANDLED;
+
+	/*
+	 * Handle interrupts, walk through all bits
+	 * and run the tasks, the bits are checked in order of
+	 * priority.
+	 */
+
+	/*
+	 * 1 - Beacon timer expired interrupt.
+	 */
+	if (rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE))
+		rt2x00lib_beacondone(rt2x00dev);
+
+	/*
+	 * 2 - Rx ring done interrupt.
+	 */
+	if (rt2x00_get_field32(reg, CSR7_RXDONE))
+		rt2x00pci_rxdone(rt2x00dev);
+
+	/*
+	 * 3 - Atim ring transmit done interrupt.
+	 */
+	if (rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING))
+		rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_AFTER_BEACON);
+
+	/*
+	 * 4 - Priority ring transmit done interrupt.
+	 */
+	if (rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING))
+		rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+
+	/*
+	 * 5 - Tx ring transmit done interrupt.
+	 */
+	if (rt2x00_get_field32(reg, CSR7_TXDONE_TXRING))
+		rt2500pci_txdone(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Device probe functions.
+ */
+static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+	struct eeprom_93cx6 eeprom;
+	u32 reg;
+	u16 word;
+	u8 *mac;
+
+	rt2x00pci_register_read(rt2x00dev, CSR21, &reg);
+
+	eeprom.data = rt2x00dev;
+	eeprom.register_read = rt2500pci_eepromregister_read;
+	eeprom.register_write = rt2500pci_eepromregister_write;
+	eeprom.width = rt2x00_get_field32(reg, CSR21_TYPE_93C46) ?
+	    PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66;
+	eeprom.reg_data_in = 0;
+	eeprom.reg_data_out = 0;
+	eeprom.reg_data_clock = 0;
+	eeprom.reg_chip_select = 0;
+
+	eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
+			       EEPROM_SIZE / sizeof(u16));
+
+	/*
+	 * Start validation of the data that has been read.
+	 */
+	mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+	if (!is_valid_ether_addr(mac)) {
+		DECLARE_MAC_BUF(macbuf);
+
+		random_ether_addr(mac);
+		EEPROM(rt2x00dev, "MAC: %s\n",
+		       print_mac(macbuf, mac));
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+		EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
+		rt2x00_set_field16(&word, EEPROM_NIC_DYN_BBP_TUNE, 0);
+		rt2x00_set_field16(&word, EEPROM_NIC_CCK_TX_POWER, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
+		EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI,
+				   DEFAULT_RSSI_OFFSET);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word);
+		EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word);
+	}
+
+	return 0;
+}
+
+static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+	u16 value;
+	u16 eeprom;
+
+	/*
+	 * Read EEPROM word for configuration.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+	/*
+	 * Identify RF chipset.
+	 */
+	value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+	rt2x00pci_register_read(rt2x00dev, CSR0, &reg);
+	rt2x00_set_chip(rt2x00dev, RT2560, value, reg);
+
+	if (!rt2x00_rf(&rt2x00dev->chip, RF2522) &&
+	    !rt2x00_rf(&rt2x00dev->chip, RF2523) &&
+	    !rt2x00_rf(&rt2x00dev->chip, RF2524) &&
+	    !rt2x00_rf(&rt2x00dev->chip, RF2525) &&
+	    !rt2x00_rf(&rt2x00dev->chip, RF2525E) &&
+	    !rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Identify default antenna configuration.
+	 */
+	rt2x00dev->hw->conf.antenna_sel_tx =
+	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
+	rt2x00dev->hw->conf.antenna_sel_rx =
+	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
+
+	/*
+	 * Store led mode, for correct led behaviour.
+	 */
+	rt2x00dev->led_mode =
+	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
+
+	/*
+	 * Detect if this device has an hardware controlled radio.
+	 */
+#ifdef CONFIG_RT2500PCI_RFKILL
+	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
+		__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+#endif /* CONFIG_RT2500PCI_RFKILL */
+
+	/*
+	 * Check if the BBP tuning should be enabled.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+
+	if (rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE))
+		__set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
+
+	/*
+	 * Read the RSSI <-> dBm offset information.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom);
+	rt2x00dev->rssi_offset =
+	    rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI);
+
+	return 0;
+}
+
+/*
+ * RF value list for RF2522
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2522[] = {
+	{ 1,  0x00002050, 0x000c1fda, 0x00000101, 0 },
+	{ 2,  0x00002050, 0x000c1fee, 0x00000101, 0 },
+	{ 3,  0x00002050, 0x000c2002, 0x00000101, 0 },
+	{ 4,  0x00002050, 0x000c2016, 0x00000101, 0 },
+	{ 5,  0x00002050, 0x000c202a, 0x00000101, 0 },
+	{ 6,  0x00002050, 0x000c203e, 0x00000101, 0 },
+	{ 7,  0x00002050, 0x000c2052, 0x00000101, 0 },
+	{ 8,  0x00002050, 0x000c2066, 0x00000101, 0 },
+	{ 9,  0x00002050, 0x000c207a, 0x00000101, 0 },
+	{ 10, 0x00002050, 0x000c208e, 0x00000101, 0 },
+	{ 11, 0x00002050, 0x000c20a2, 0x00000101, 0 },
+	{ 12, 0x00002050, 0x000c20b6, 0x00000101, 0 },
+	{ 13, 0x00002050, 0x000c20ca, 0x00000101, 0 },
+	{ 14, 0x00002050, 0x000c20fa, 0x00000101, 0 },
+};
+
+/*
+ * RF value list for RF2523
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2523[] = {
+	{ 1,  0x00022010, 0x00000c9e, 0x000e0111, 0x00000a1b },
+	{ 2,  0x00022010, 0x00000ca2, 0x000e0111, 0x00000a1b },
+	{ 3,  0x00022010, 0x00000ca6, 0x000e0111, 0x00000a1b },
+	{ 4,  0x00022010, 0x00000caa, 0x000e0111, 0x00000a1b },
+	{ 5,  0x00022010, 0x00000cae, 0x000e0111, 0x00000a1b },
+	{ 6,  0x00022010, 0x00000cb2, 0x000e0111, 0x00000a1b },
+	{ 7,  0x00022010, 0x00000cb6, 0x000e0111, 0x00000a1b },
+	{ 8,  0x00022010, 0x00000cba, 0x000e0111, 0x00000a1b },
+	{ 9,  0x00022010, 0x00000cbe, 0x000e0111, 0x00000a1b },
+	{ 10, 0x00022010, 0x00000d02, 0x000e0111, 0x00000a1b },
+	{ 11, 0x00022010, 0x00000d06, 0x000e0111, 0x00000a1b },
+	{ 12, 0x00022010, 0x00000d0a, 0x000e0111, 0x00000a1b },
+	{ 13, 0x00022010, 0x00000d0e, 0x000e0111, 0x00000a1b },
+	{ 14, 0x00022010, 0x00000d1a, 0x000e0111, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2524
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2524[] = {
+	{ 1,  0x00032020, 0x00000c9e, 0x00000101, 0x00000a1b },
+	{ 2,  0x00032020, 0x00000ca2, 0x00000101, 0x00000a1b },
+	{ 3,  0x00032020, 0x00000ca6, 0x00000101, 0x00000a1b },
+	{ 4,  0x00032020, 0x00000caa, 0x00000101, 0x00000a1b },
+	{ 5,  0x00032020, 0x00000cae, 0x00000101, 0x00000a1b },
+	{ 6,  0x00032020, 0x00000cb2, 0x00000101, 0x00000a1b },
+	{ 7,  0x00032020, 0x00000cb6, 0x00000101, 0x00000a1b },
+	{ 8,  0x00032020, 0x00000cba, 0x00000101, 0x00000a1b },
+	{ 9,  0x00032020, 0x00000cbe, 0x00000101, 0x00000a1b },
+	{ 10, 0x00032020, 0x00000d02, 0x00000101, 0x00000a1b },
+	{ 11, 0x00032020, 0x00000d06, 0x00000101, 0x00000a1b },
+	{ 12, 0x00032020, 0x00000d0a, 0x00000101, 0x00000a1b },
+	{ 13, 0x00032020, 0x00000d0e, 0x00000101, 0x00000a1b },
+	{ 14, 0x00032020, 0x00000d1a, 0x00000101, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2525
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2525[] = {
+	{ 1,  0x00022020, 0x00080c9e, 0x00060111, 0x00000a1b },
+	{ 2,  0x00022020, 0x00080ca2, 0x00060111, 0x00000a1b },
+	{ 3,  0x00022020, 0x00080ca6, 0x00060111, 0x00000a1b },
+	{ 4,  0x00022020, 0x00080caa, 0x00060111, 0x00000a1b },
+	{ 5,  0x00022020, 0x00080cae, 0x00060111, 0x00000a1b },
+	{ 6,  0x00022020, 0x00080cb2, 0x00060111, 0x00000a1b },
+	{ 7,  0x00022020, 0x00080cb6, 0x00060111, 0x00000a1b },
+	{ 8,  0x00022020, 0x00080cba, 0x00060111, 0x00000a1b },
+	{ 9,  0x00022020, 0x00080cbe, 0x00060111, 0x00000a1b },
+	{ 10, 0x00022020, 0x00080d02, 0x00060111, 0x00000a1b },
+	{ 11, 0x00022020, 0x00080d06, 0x00060111, 0x00000a1b },
+	{ 12, 0x00022020, 0x00080d0a, 0x00060111, 0x00000a1b },
+	{ 13, 0x00022020, 0x00080d0e, 0x00060111, 0x00000a1b },
+	{ 14, 0x00022020, 0x00080d1a, 0x00060111, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2525e
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2525e[] = {
+	{ 1,  0x00022020, 0x00081136, 0x00060111, 0x00000a0b },
+	{ 2,  0x00022020, 0x0008113a, 0x00060111, 0x00000a0b },
+	{ 3,  0x00022020, 0x0008113e, 0x00060111, 0x00000a0b },
+	{ 4,  0x00022020, 0x00081182, 0x00060111, 0x00000a0b },
+	{ 5,  0x00022020, 0x00081186, 0x00060111, 0x00000a0b },
+	{ 6,  0x00022020, 0x0008118a, 0x00060111, 0x00000a0b },
+	{ 7,  0x00022020, 0x0008118e, 0x00060111, 0x00000a0b },
+	{ 8,  0x00022020, 0x00081192, 0x00060111, 0x00000a0b },
+	{ 9,  0x00022020, 0x00081196, 0x00060111, 0x00000a0b },
+	{ 10, 0x00022020, 0x0008119a, 0x00060111, 0x00000a0b },
+	{ 11, 0x00022020, 0x0008119e, 0x00060111, 0x00000a0b },
+	{ 12, 0x00022020, 0x000811a2, 0x00060111, 0x00000a0b },
+	{ 13, 0x00022020, 0x000811a6, 0x00060111, 0x00000a0b },
+	{ 14, 0x00022020, 0x000811ae, 0x00060111, 0x00000a1b },
+};
+
+/*
+ * RF value list for RF5222
+ * Supports: 2.4 GHz & 5.2 GHz
+ */
+static const struct rf_channel rf_vals_5222[] = {
+	{ 1,  0x00022020, 0x00001136, 0x00000101, 0x00000a0b },
+	{ 2,  0x00022020, 0x0000113a, 0x00000101, 0x00000a0b },
+	{ 3,  0x00022020, 0x0000113e, 0x00000101, 0x00000a0b },
+	{ 4,  0x00022020, 0x00001182, 0x00000101, 0x00000a0b },
+	{ 5,  0x00022020, 0x00001186, 0x00000101, 0x00000a0b },
+	{ 6,  0x00022020, 0x0000118a, 0x00000101, 0x00000a0b },
+	{ 7,  0x00022020, 0x0000118e, 0x00000101, 0x00000a0b },
+	{ 8,  0x00022020, 0x00001192, 0x00000101, 0x00000a0b },
+	{ 9,  0x00022020, 0x00001196, 0x00000101, 0x00000a0b },
+	{ 10, 0x00022020, 0x0000119a, 0x00000101, 0x00000a0b },
+	{ 11, 0x00022020, 0x0000119e, 0x00000101, 0x00000a0b },
+	{ 12, 0x00022020, 0x000011a2, 0x00000101, 0x00000a0b },
+	{ 13, 0x00022020, 0x000011a6, 0x00000101, 0x00000a0b },
+	{ 14, 0x00022020, 0x000011ae, 0x00000101, 0x00000a1b },
+
+	/* 802.11 UNI / HyperLan 2 */
+	{ 36, 0x00022010, 0x00018896, 0x00000101, 0x00000a1f },
+	{ 40, 0x00022010, 0x0001889a, 0x00000101, 0x00000a1f },
+	{ 44, 0x00022010, 0x0001889e, 0x00000101, 0x00000a1f },
+	{ 48, 0x00022010, 0x000188a2, 0x00000101, 0x00000a1f },
+	{ 52, 0x00022010, 0x000188a6, 0x00000101, 0x00000a1f },
+	{ 66, 0x00022010, 0x000188aa, 0x00000101, 0x00000a1f },
+	{ 60, 0x00022010, 0x000188ae, 0x00000101, 0x00000a1f },
+	{ 64, 0x00022010, 0x000188b2, 0x00000101, 0x00000a1f },
+
+	/* 802.11 HyperLan 2 */
+	{ 100, 0x00022010, 0x00008802, 0x00000101, 0x00000a0f },
+	{ 104, 0x00022010, 0x00008806, 0x00000101, 0x00000a0f },
+	{ 108, 0x00022010, 0x0000880a, 0x00000101, 0x00000a0f },
+	{ 112, 0x00022010, 0x0000880e, 0x00000101, 0x00000a0f },
+	{ 116, 0x00022010, 0x00008812, 0x00000101, 0x00000a0f },
+	{ 120, 0x00022010, 0x00008816, 0x00000101, 0x00000a0f },
+	{ 124, 0x00022010, 0x0000881a, 0x00000101, 0x00000a0f },
+	{ 128, 0x00022010, 0x0000881e, 0x00000101, 0x00000a0f },
+	{ 132, 0x00022010, 0x00008822, 0x00000101, 0x00000a0f },
+	{ 136, 0x00022010, 0x00008826, 0x00000101, 0x00000a0f },
+
+	/* 802.11 UNII */
+	{ 140, 0x00022010, 0x0000882a, 0x00000101, 0x00000a0f },
+	{ 149, 0x00022020, 0x000090a6, 0x00000101, 0x00000a07 },
+	{ 153, 0x00022020, 0x000090ae, 0x00000101, 0x00000a07 },
+	{ 157, 0x00022020, 0x000090b6, 0x00000101, 0x00000a07 },
+	{ 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 },
+};
+
+static void rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+{
+	struct hw_mode_spec *spec = &rt2x00dev->spec;
+	u8 *txpower;
+	unsigned int i;
+
+	/*
+	 * Initialize all hw fields.
+	 */
+	rt2x00dev->hw->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+	rt2x00dev->hw->extra_tx_headroom = 0;
+	rt2x00dev->hw->max_signal = MAX_SIGNAL;
+	rt2x00dev->hw->max_rssi = MAX_RX_SSI;
+	rt2x00dev->hw->queues = 2;
+
+	SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+				rt2x00_eeprom_addr(rt2x00dev,
+						   EEPROM_MAC_ADDR_0));
+
+	/*
+	 * Convert tx_power array in eeprom.
+	 */
+	txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
+	for (i = 0; i < 14; i++)
+		txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+	/*
+	 * Initialize hw_mode information.
+	 */
+	spec->num_modes = 2;
+	spec->num_rates = 12;
+	spec->tx_power_a = NULL;
+	spec->tx_power_bg = txpower;
+	spec->tx_power_default = DEFAULT_TXPOWER;
+
+	if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
+		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
+		spec->channels = rf_vals_bg_2522;
+	} else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523);
+		spec->channels = rf_vals_bg_2523;
+	} else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) {
+		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524);
+		spec->channels = rf_vals_bg_2524;
+	} else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525);
+		spec->channels = rf_vals_bg_2525;
+	} else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
+		spec->channels = rf_vals_bg_2525e;
+	} else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+		spec->num_channels = ARRAY_SIZE(rf_vals_5222);
+		spec->channels = rf_vals_5222;
+		spec->num_modes = 3;
+	}
+}
+
+static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+	int retval;
+
+	/*
+	 * Allocate eeprom data.
+	 */
+	retval = rt2500pci_validate_eeprom(rt2x00dev);
+	if (retval)
+		return retval;
+
+	retval = rt2500pci_init_eeprom(rt2x00dev);
+	if (retval)
+		return retval;
+
+	/*
+	 * Initialize hw specifications.
+	 */
+	rt2500pci_probe_hw_mode(rt2x00dev);
+
+	/*
+	 * This device requires the beacon ring
+	 */
+	__set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
+
+	/*
+	 * Set the rssi offset.
+	 */
+	rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
+	return 0;
+}
+
+/*
+ * IEEE80211 stack callback functions.
+ */
+static void rt2500pci_configure_filter(struct ieee80211_hw *hw,
+				       unsigned int changed_flags,
+				       unsigned int *total_flags,
+				       int mc_count,
+				       struct dev_addr_list *mc_list)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct interface *intf = &rt2x00dev->interface;
+	u32 reg;
+
+	/*
+	 * Mask off any flags we are going to ignore from
+	 * the total_flags field.
+	 */
+	*total_flags &=
+	    FIF_ALLMULTI |
+	    FIF_FCSFAIL |
+	    FIF_PLCPFAIL |
+	    FIF_CONTROL |
+	    FIF_OTHER_BSS |
+	    FIF_PROMISC_IN_BSS;
+
+	/*
+	 * Apply some rules to the filters:
+	 * - Some filters imply different filters to be set.
+	 * - Some things we can't filter out at all.
+	 * - Some filters are set based on interface type.
+	 */
+	if (mc_count)
+		*total_flags |= FIF_ALLMULTI;
+	if (*total_flags & FIF_OTHER_BSS ||
+	    *total_flags & FIF_PROMISC_IN_BSS)
+		*total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+	if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+		*total_flags |= FIF_PROMISC_IN_BSS;
+
+	/*
+	 * Check if there is any work left for us.
+	 */
+	if (intf->filter == *total_flags)
+		return;
+	intf->filter = *total_flags;
+
+	/*
+	 * Start configuration steps.
+	 * Note that the version error will always be dropped
+	 * and broadcast frames will always be accepted since
+	 * there is no filter for it at this time.
+	 */
+	rt2x00pci_register_read(rt2x00dev, RXCSR0, &reg);
+	rt2x00_set_field32(&reg, RXCSR0_DROP_CRC,
+			   !(*total_flags & FIF_FCSFAIL));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_PHYSICAL,
+			   !(*total_flags & FIF_PLCPFAIL));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_CONTROL,
+			   !(*total_flags & FIF_CONTROL));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_NOT_TO_ME,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_TODS,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_VERSION_ERROR, 1);
+	rt2x00_set_field32(&reg, RXCSR0_DROP_MCAST,
+			   !(*total_flags & FIF_ALLMULTI));
+	rt2x00_set_field32(&reg, RXCSR0_DROP_BCAST, 0);
+	rt2x00pci_register_write(rt2x00dev, RXCSR0, reg);
+}
+
+static int rt2500pci_set_retry_limit(struct ieee80211_hw *hw,
+				     u32 short_retry, u32 long_retry)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, CSR11, &reg);
+	rt2x00_set_field32(&reg, CSR11_LONG_RETRY, long_retry);
+	rt2x00_set_field32(&reg, CSR11_SHORT_RETRY, short_retry);
+	rt2x00pci_register_write(rt2x00dev, CSR11, reg);
+
+	return 0;
+}
+
+static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	u64 tsf;
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, CSR17, &reg);
+	tsf = (u64) rt2x00_get_field32(reg, CSR17_HIGH_TSFTIMER) << 32;
+	rt2x00pci_register_read(rt2x00dev, CSR16, &reg);
+	tsf |= rt2x00_get_field32(reg, CSR16_LOW_TSFTIMER);
+
+	return tsf;
+}
+
+static void rt2500pci_reset_tsf(struct ieee80211_hw *hw)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+
+	rt2x00pci_register_write(rt2x00dev, CSR16, 0);
+	rt2x00pci_register_write(rt2x00dev, CSR17, 0);
+}
+
+static int rt2500pci_tx_last_beacon(struct ieee80211_hw *hw)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, CSR15, &reg);
+	return rt2x00_get_field32(reg, CSR15_BEACON_SENT);
+}
+
+static const struct ieee80211_ops rt2500pci_mac80211_ops = {
+	.tx			= rt2x00mac_tx,
+	.start			= rt2x00mac_start,
+	.stop			= rt2x00mac_stop,
+	.add_interface		= rt2x00mac_add_interface,
+	.remove_interface	= rt2x00mac_remove_interface,
+	.config			= rt2x00mac_config,
+	.config_interface	= rt2x00mac_config_interface,
+	.configure_filter	= rt2500pci_configure_filter,
+	.get_stats		= rt2x00mac_get_stats,
+	.set_retry_limit	= rt2500pci_set_retry_limit,
+	.erp_ie_changed		= rt2x00mac_erp_ie_changed,
+	.conf_tx		= rt2x00mac_conf_tx,
+	.get_tx_stats		= rt2x00mac_get_tx_stats,
+	.get_tsf		= rt2500pci_get_tsf,
+	.reset_tsf		= rt2500pci_reset_tsf,
+	.beacon_update		= rt2x00pci_beacon_update,
+	.tx_last_beacon		= rt2500pci_tx_last_beacon,
+};
+
+static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
+	.irq_handler		= rt2500pci_interrupt,
+	.probe_hw		= rt2500pci_probe_hw,
+	.initialize		= rt2x00pci_initialize,
+	.uninitialize		= rt2x00pci_uninitialize,
+	.set_device_state	= rt2500pci_set_device_state,
+	.rfkill_poll		= rt2500pci_rfkill_poll,
+	.link_stats		= rt2500pci_link_stats,
+	.reset_tuner		= rt2500pci_reset_tuner,
+	.link_tuner		= rt2500pci_link_tuner,
+	.write_tx_desc		= rt2500pci_write_tx_desc,
+	.write_tx_data		= rt2x00pci_write_tx_data,
+	.kick_tx_queue		= rt2500pci_kick_tx_queue,
+	.fill_rxdone		= rt2500pci_fill_rxdone,
+	.config_mac_addr	= rt2500pci_config_mac_addr,
+	.config_bssid		= rt2500pci_config_bssid,
+	.config_type		= rt2500pci_config_type,
+	.config_preamble	= rt2500pci_config_preamble,
+	.config			= rt2500pci_config,
+};
+
+static const struct rt2x00_ops rt2500pci_ops = {
+	.name		= DRV_NAME,
+	.rxd_size	= RXD_DESC_SIZE,
+	.txd_size	= TXD_DESC_SIZE,
+	.eeprom_size	= EEPROM_SIZE,
+	.rf_size	= RF_SIZE,
+	.lib		= &rt2500pci_rt2x00_ops,
+	.hw		= &rt2500pci_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+	.debugfs	= &rt2500pci_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * RT2500pci module information.
+ */
+static struct pci_device_id rt2500pci_device_table[] = {
+	{ PCI_DEVICE(0x1814, 0x0201), PCI_DEVICE_DATA(&rt2500pci_ops) },
+	{ 0, }
+};
+
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT2500 PCI & PCMCIA Wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Ralink RT2560 PCI & PCMCIA chipset based cards");
+MODULE_DEVICE_TABLE(pci, rt2500pci_device_table);
+MODULE_LICENSE("GPL");
+
+static struct pci_driver rt2500pci_driver = {
+	.name		= DRV_NAME,
+	.id_table	= rt2500pci_device_table,
+	.probe		= rt2x00pci_probe,
+	.remove		= __devexit_p(rt2x00pci_remove),
+	.suspend	= rt2x00pci_suspend,
+	.resume		= rt2x00pci_resume,
+};
+
+static int __init rt2500pci_init(void)
+{
+	return pci_register_driver(&rt2500pci_driver);
+}
+
+static void __exit rt2500pci_exit(void)
+{
+	pci_unregister_driver(&rt2500pci_driver);
+}
+
+module_init(rt2500pci_init);
+module_exit(rt2500pci_exit);
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h
new file mode 100644
index 0000000..d92aa56
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2500pci.h
@@ -0,0 +1,1236 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2500pci
+	Abstract: Data structures and registers for the rt2500pci module.
+	Supported chipsets: RT2560.
+ */
+
+#ifndef RT2500PCI_H
+#define RT2500PCI_H
+
+/*
+ * RF chip defines.
+ */
+#define RF2522				0x0000
+#define RF2523				0x0001
+#define RF2524				0x0002
+#define RF2525				0x0003
+#define RF2525E				0x0004
+#define RF5222				0x0010
+
+/*
+ * RT2560 version
+ */
+#define RT2560_VERSION_B		2
+#define RT2560_VERSION_C		3
+#define RT2560_VERSION_D		4
+
+/*
+ * Signal information.
+ * Defaul offset is required for RSSI <-> dBm conversion.
+ */
+#define MAX_SIGNAL			100
+#define MAX_RX_SSI			-1
+#define DEFAULT_RSSI_OFFSET		121
+
+/*
+ * Register layout information.
+ */
+#define CSR_REG_BASE			0x0000
+#define CSR_REG_SIZE			0x0174
+#define EEPROM_BASE			0x0000
+#define EEPROM_SIZE			0x0200
+#define BBP_SIZE			0x0040
+#define RF_SIZE				0x0014
+
+/*
+ * Control/Status Registers(CSR).
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * CSR0: ASIC revision number.
+ */
+#define CSR0				0x0000
+
+/*
+ * CSR1: System control register.
+ * SOFT_RESET: Software reset, 1: reset, 0: normal.
+ * BBP_RESET: Hardware reset, 1: reset, 0, release.
+ * HOST_READY: Host ready after initialization.
+ */
+#define CSR1				0x0004
+#define CSR1_SOFT_RESET			FIELD32(0x00000001)
+#define CSR1_BBP_RESET			FIELD32(0x00000002)
+#define CSR1_HOST_READY			FIELD32(0x00000004)
+
+/*
+ * CSR2: System admin status register (invalid).
+ */
+#define CSR2				0x0008
+
+/*
+ * CSR3: STA MAC address register 0.
+ */
+#define CSR3				0x000c
+#define CSR3_BYTE0			FIELD32(0x000000ff)
+#define CSR3_BYTE1			FIELD32(0x0000ff00)
+#define CSR3_BYTE2			FIELD32(0x00ff0000)
+#define CSR3_BYTE3			FIELD32(0xff000000)
+
+/*
+ * CSR4: STA MAC address register 1.
+ */
+#define CSR4				0x0010
+#define CSR4_BYTE4			FIELD32(0x000000ff)
+#define CSR4_BYTE5			FIELD32(0x0000ff00)
+
+/*
+ * CSR5: BSSID register 0.
+ */
+#define CSR5				0x0014
+#define CSR5_BYTE0			FIELD32(0x000000ff)
+#define CSR5_BYTE1			FIELD32(0x0000ff00)
+#define CSR5_BYTE2			FIELD32(0x00ff0000)
+#define CSR5_BYTE3			FIELD32(0xff000000)
+
+/*
+ * CSR6: BSSID register 1.
+ */
+#define CSR6				0x0018
+#define CSR6_BYTE4			FIELD32(0x000000ff)
+#define CSR6_BYTE5			FIELD32(0x0000ff00)
+
+/*
+ * CSR7: Interrupt source register.
+ * Write 1 to clear.
+ * TBCN_EXPIRE: Beacon timer expired interrupt.
+ * TWAKE_EXPIRE: Wakeup timer expired interrupt.
+ * TATIMW_EXPIRE: Timer of atim window expired interrupt.
+ * TXDONE_TXRING: Tx ring transmit done interrupt.
+ * TXDONE_ATIMRING: Atim ring transmit done interrupt.
+ * TXDONE_PRIORING: Priority ring transmit done interrupt.
+ * RXDONE: Receive done interrupt.
+ * DECRYPTION_DONE: Decryption done interrupt.
+ * ENCRYPTION_DONE: Encryption done interrupt.
+ * UART1_TX_TRESHOLD: UART1 TX reaches threshold.
+ * UART1_RX_TRESHOLD: UART1 RX reaches threshold.
+ * UART1_IDLE_TRESHOLD: UART1 IDLE over threshold.
+ * UART1_TX_BUFF_ERROR: UART1 TX buffer error.
+ * UART1_RX_BUFF_ERROR: UART1 RX buffer error.
+ * UART2_TX_TRESHOLD: UART2 TX reaches threshold.
+ * UART2_RX_TRESHOLD: UART2 RX reaches threshold.
+ * UART2_IDLE_TRESHOLD: UART2 IDLE over threshold.
+ * UART2_TX_BUFF_ERROR: UART2 TX buffer error.
+ * UART2_RX_BUFF_ERROR: UART2 RX buffer error.
+ * TIMER_CSR3_EXPIRE: TIMECSR3 timer expired (802.1H quiet period).
+
+ */
+#define CSR7				0x001c
+#define CSR7_TBCN_EXPIRE		FIELD32(0x00000001)
+#define CSR7_TWAKE_EXPIRE		FIELD32(0x00000002)
+#define CSR7_TATIMW_EXPIRE		FIELD32(0x00000004)
+#define CSR7_TXDONE_TXRING		FIELD32(0x00000008)
+#define CSR7_TXDONE_ATIMRING		FIELD32(0x00000010)
+#define CSR7_TXDONE_PRIORING		FIELD32(0x00000020)
+#define CSR7_RXDONE			FIELD32(0x00000040)
+#define CSR7_DECRYPTION_DONE		FIELD32(0x00000080)
+#define CSR7_ENCRYPTION_DONE		FIELD32(0x00000100)
+#define CSR7_UART1_TX_TRESHOLD		FIELD32(0x00000200)
+#define CSR7_UART1_RX_TRESHOLD		FIELD32(0x00000400)
+#define CSR7_UART1_IDLE_TRESHOLD	FIELD32(0x00000800)
+#define CSR7_UART1_TX_BUFF_ERROR	FIELD32(0x00001000)
+#define CSR7_UART1_RX_BUFF_ERROR	FIELD32(0x00002000)
+#define CSR7_UART2_TX_TRESHOLD		FIELD32(0x00004000)
+#define CSR7_UART2_RX_TRESHOLD		FIELD32(0x00008000)
+#define CSR7_UART2_IDLE_TRESHOLD	FIELD32(0x00010000)
+#define CSR7_UART2_TX_BUFF_ERROR	FIELD32(0x00020000)
+#define CSR7_UART2_RX_BUFF_ERROR	FIELD32(0x00040000)
+#define CSR7_TIMER_CSR3_EXPIRE		FIELD32(0x00080000)
+
+/*
+ * CSR8: Interrupt mask register.
+ * Write 1 to mask interrupt.
+ * TBCN_EXPIRE: Beacon timer expired interrupt.
+ * TWAKE_EXPIRE: Wakeup timer expired interrupt.
+ * TATIMW_EXPIRE: Timer of atim window expired interrupt.
+ * TXDONE_TXRING: Tx ring transmit done interrupt.
+ * TXDONE_ATIMRING: Atim ring transmit done interrupt.
+ * TXDONE_PRIORING: Priority ring transmit done interrupt.
+ * RXDONE: Receive done interrupt.
+ * DECRYPTION_DONE: Decryption done interrupt.
+ * ENCRYPTION_DONE: Encryption done interrupt.
+ * UART1_TX_TRESHOLD: UART1 TX reaches threshold.
+ * UART1_RX_TRESHOLD: UART1 RX reaches threshold.
+ * UART1_IDLE_TRESHOLD: UART1 IDLE over threshold.
+ * UART1_TX_BUFF_ERROR: UART1 TX buffer error.
+ * UART1_RX_BUFF_ERROR: UART1 RX buffer error.
+ * UART2_TX_TRESHOLD: UART2 TX reaches threshold.
+ * UART2_RX_TRESHOLD: UART2 RX reaches threshold.
+ * UART2_IDLE_TRESHOLD: UART2 IDLE over threshold.
+ * UART2_TX_BUFF_ERROR: UART2 TX buffer error.
+ * UART2_RX_BUFF_ERROR: UART2 RX buffer error.
+ * TIMER_CSR3_EXPIRE: TIMECSR3 timer expired (802.1H quiet period).
+ */
+#define CSR8				0x0020
+#define CSR8_TBCN_EXPIRE		FIELD32(0x00000001)
+#define CSR8_TWAKE_EXPIRE		FIELD32(0x00000002)
+#define CSR8_TATIMW_EXPIRE		FIELD32(0x00000004)
+#define CSR8_TXDONE_TXRING		FIELD32(0x00000008)
+#define CSR8_TXDONE_ATIMRING		FIELD32(0x00000010)
+#define CSR8_TXDONE_PRIORING		FIELD32(0x00000020)
+#define CSR8_RXDONE			FIELD32(0x00000040)
+#define CSR8_DECRYPTION_DONE		FIELD32(0x00000080)
+#define CSR8_ENCRYPTION_DONE		FIELD32(0x00000100)
+#define CSR8_UART1_TX_TRESHOLD		FIELD32(0x00000200)
+#define CSR8_UART1_RX_TRESHOLD		FIELD32(0x00000400)
+#define CSR8_UART1_IDLE_TRESHOLD	FIELD32(0x00000800)
+#define CSR8_UART1_TX_BUFF_ERROR	FIELD32(0x00001000)
+#define CSR8_UART1_RX_BUFF_ERROR	FIELD32(0x00002000)
+#define CSR8_UART2_TX_TRESHOLD		FIELD32(0x00004000)
+#define CSR8_UART2_RX_TRESHOLD		FIELD32(0x00008000)
+#define CSR8_UART2_IDLE_TRESHOLD	FIELD32(0x00010000)
+#define CSR8_UART2_TX_BUFF_ERROR	FIELD32(0x00020000)
+#define CSR8_UART2_RX_BUFF_ERROR	FIELD32(0x00040000)
+#define CSR8_TIMER_CSR3_EXPIRE		FIELD32(0x00080000)
+
+/*
+ * CSR9: Maximum frame length register.
+ * MAX_FRAME_UNIT: Maximum frame length in 128b unit, default: 12.
+ */
+#define CSR9				0x0024
+#define CSR9_MAX_FRAME_UNIT		FIELD32(0x00000f80)
+
+/*
+ * SECCSR0: WEP control register.
+ * KICK_DECRYPT: Kick decryption engine, self-clear.
+ * ONE_SHOT: 0: ring mode, 1: One shot only mode.
+ * DESC_ADDRESS: Descriptor physical address of frame.
+ */
+#define SECCSR0				0x0028
+#define SECCSR0_KICK_DECRYPT		FIELD32(0x00000001)
+#define SECCSR0_ONE_SHOT		FIELD32(0x00000002)
+#define SECCSR0_DESC_ADDRESS		FIELD32(0xfffffffc)
+
+/*
+ * CSR11: Back-off control register.
+ * CWMIN: CWmin. Default cwmin is 31 (2^5 - 1).
+ * CWMAX: CWmax. Default cwmax is 1023 (2^10 - 1).
+ * SLOT_TIME: Slot time, default is 20us for 802.11b
+ * CW_SELECT: CWmin/CWmax selection, 1: Register, 0: TXD.
+ * LONG_RETRY: Long retry count.
+ * SHORT_RETRY: Short retry count.
+ */
+#define CSR11				0x002c
+#define CSR11_CWMIN			FIELD32(0x0000000f)
+#define CSR11_CWMAX			FIELD32(0x000000f0)
+#define CSR11_SLOT_TIME			FIELD32(0x00001f00)
+#define CSR11_CW_SELECT			FIELD32(0x00002000)
+#define CSR11_LONG_RETRY		FIELD32(0x00ff0000)
+#define CSR11_SHORT_RETRY		FIELD32(0xff000000)
+
+/*
+ * CSR12: Synchronization configuration register 0.
+ * All units in 1/16 TU.
+ * BEACON_INTERVAL: Beacon interval, default is 100 TU.
+ * CFP_MAX_DURATION: Cfp maximum duration, default is 100 TU.
+ */
+#define CSR12				0x0030
+#define CSR12_BEACON_INTERVAL		FIELD32(0x0000ffff)
+#define CSR12_CFP_MAX_DURATION		FIELD32(0xffff0000)
+
+/*
+ * CSR13: Synchronization configuration register 1.
+ * All units in 1/16 TU.
+ * ATIMW_DURATION: Atim window duration.
+ * CFP_PERIOD: Cfp period, default is 0 TU.
+ */
+#define CSR13				0x0034
+#define CSR13_ATIMW_DURATION		FIELD32(0x0000ffff)
+#define CSR13_CFP_PERIOD		FIELD32(0x00ff0000)
+
+/*
+ * CSR14: Synchronization control register.
+ * TSF_COUNT: Enable tsf auto counting.
+ * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
+ * TBCN: Enable tbcn with reload value.
+ * TCFP: Enable tcfp & cfp / cp switching.
+ * TATIMW: Enable tatimw & atim window switching.
+ * BEACON_GEN: Enable beacon generator.
+ * CFP_COUNT_PRELOAD: Cfp count preload value.
+ * TBCM_PRELOAD: Tbcn preload value in units of 64us.
+ */
+#define CSR14				0x0038
+#define CSR14_TSF_COUNT			FIELD32(0x00000001)
+#define CSR14_TSF_SYNC			FIELD32(0x00000006)
+#define CSR14_TBCN			FIELD32(0x00000008)
+#define CSR14_TCFP			FIELD32(0x00000010)
+#define CSR14_TATIMW			FIELD32(0x00000020)
+#define CSR14_BEACON_GEN		FIELD32(0x00000040)
+#define CSR14_CFP_COUNT_PRELOAD		FIELD32(0x0000ff00)
+#define CSR14_TBCM_PRELOAD		FIELD32(0xffff0000)
+
+/*
+ * CSR15: Synchronization status register.
+ * CFP: ASIC is in contention-free period.
+ * ATIMW: ASIC is in ATIM window.
+ * BEACON_SENT: Beacon is send.
+ */
+#define CSR15				0x003c
+#define CSR15_CFP			FIELD32(0x00000001)
+#define CSR15_ATIMW			FIELD32(0x00000002)
+#define CSR15_BEACON_SENT		FIELD32(0x00000004)
+
+/*
+ * CSR16: TSF timer register 0.
+ */
+#define CSR16				0x0040
+#define CSR16_LOW_TSFTIMER		FIELD32(0xffffffff)
+
+/*
+ * CSR17: TSF timer register 1.
+ */
+#define CSR17				0x0044
+#define CSR17_HIGH_TSFTIMER		FIELD32(0xffffffff)
+
+/*
+ * CSR18: IFS timer register 0.
+ * SIFS: Sifs, default is 10 us.
+ * PIFS: Pifs, default is 30 us.
+ */
+#define CSR18				0x0048
+#define CSR18_SIFS			FIELD32(0x000001ff)
+#define CSR18_PIFS			FIELD32(0x001f0000)
+
+/*
+ * CSR19: IFS timer register 1.
+ * DIFS: Difs, default is 50 us.
+ * EIFS: Eifs, default is 364 us.
+ */
+#define CSR19				0x004c
+#define CSR19_DIFS			FIELD32(0x0000ffff)
+#define CSR19_EIFS			FIELD32(0xffff0000)
+
+/*
+ * CSR20: Wakeup timer register.
+ * DELAY_AFTER_TBCN: Delay after tbcn expired in units of 1/16 TU.
+ * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup.
+ * AUTOWAKE: Enable auto wakeup / sleep mechanism.
+ */
+#define CSR20				0x0050
+#define CSR20_DELAY_AFTER_TBCN		FIELD32(0x0000ffff)
+#define CSR20_TBCN_BEFORE_WAKEUP	FIELD32(0x00ff0000)
+#define CSR20_AUTOWAKE			FIELD32(0x01000000)
+
+/*
+ * CSR21: EEPROM control register.
+ * RELOAD: Write 1 to reload eeprom content.
+ * TYPE_93C46: 1: 93c46, 0:93c66.
+ */
+#define CSR21				0x0054
+#define CSR21_RELOAD			FIELD32(0x00000001)
+#define CSR21_EEPROM_DATA_CLOCK		FIELD32(0x00000002)
+#define CSR21_EEPROM_CHIP_SELECT	FIELD32(0x00000004)
+#define CSR21_EEPROM_DATA_IN		FIELD32(0x00000008)
+#define CSR21_EEPROM_DATA_OUT		FIELD32(0x00000010)
+#define CSR21_TYPE_93C46		FIELD32(0x00000020)
+
+/*
+ * CSR22: CFP control register.
+ * CFP_DURATION_REMAIN: Cfp duration remain, in units of TU.
+ * RELOAD_CFP_DURATION: Write 1 to reload cfp duration remain.
+ */
+#define CSR22				0x0058
+#define CSR22_CFP_DURATION_REMAIN	FIELD32(0x0000ffff)
+#define CSR22_RELOAD_CFP_DURATION	FIELD32(0x00010000)
+
+/*
+ * Transmit related CSRs.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * TXCSR0: TX Control Register.
+ * KICK_TX: Kick tx ring.
+ * KICK_ATIM: Kick atim ring.
+ * KICK_PRIO: Kick priority ring.
+ * ABORT: Abort all transmit related ring operation.
+ */
+#define TXCSR0				0x0060
+#define TXCSR0_KICK_TX			FIELD32(0x00000001)
+#define TXCSR0_KICK_ATIM		FIELD32(0x00000002)
+#define TXCSR0_KICK_PRIO		FIELD32(0x00000004)
+#define TXCSR0_ABORT			FIELD32(0x00000008)
+
+/*
+ * TXCSR1: TX Configuration Register.
+ * ACK_TIMEOUT: Ack timeout, default = sifs + 2*slottime + acktime @ 1mbps.
+ * ACK_CONSUME_TIME: Ack consume time, default = sifs + acktime @ 1mbps.
+ * TSF_OFFSET: Insert tsf offset.
+ * AUTORESPONDER: Enable auto responder which include ack & cts.
+ */
+#define TXCSR1				0x0064
+#define TXCSR1_ACK_TIMEOUT		FIELD32(0x000001ff)
+#define TXCSR1_ACK_CONSUME_TIME		FIELD32(0x0003fe00)
+#define TXCSR1_TSF_OFFSET		FIELD32(0x00fc0000)
+#define TXCSR1_AUTORESPONDER		FIELD32(0x01000000)
+
+/*
+ * TXCSR2: Tx descriptor configuration register.
+ * TXD_SIZE: Tx descriptor size, default is 48.
+ * NUM_TXD: Number of tx entries in ring.
+ * NUM_ATIM: Number of atim entries in ring.
+ * NUM_PRIO: Number of priority entries in ring.
+ */
+#define TXCSR2				0x0068
+#define TXCSR2_TXD_SIZE			FIELD32(0x000000ff)
+#define TXCSR2_NUM_TXD			FIELD32(0x0000ff00)
+#define TXCSR2_NUM_ATIM			FIELD32(0x00ff0000)
+#define TXCSR2_NUM_PRIO			FIELD32(0xff000000)
+
+/*
+ * TXCSR3: TX Ring Base address register.
+ */
+#define TXCSR3				0x006c
+#define TXCSR3_TX_RING_REGISTER		FIELD32(0xffffffff)
+
+/*
+ * TXCSR4: TX Atim Ring Base address register.
+ */
+#define TXCSR4				0x0070
+#define TXCSR4_ATIM_RING_REGISTER	FIELD32(0xffffffff)
+
+/*
+ * TXCSR5: TX Prio Ring Base address register.
+ */
+#define TXCSR5				0x0074
+#define TXCSR5_PRIO_RING_REGISTER	FIELD32(0xffffffff)
+
+/*
+ * TXCSR6: Beacon Base address register.
+ */
+#define TXCSR6				0x0078
+#define TXCSR6_BEACON_RING_REGISTER	FIELD32(0xffffffff)
+
+/*
+ * TXCSR7: Auto responder control register.
+ * AR_POWERMANAGEMENT: Auto responder power management bit.
+ */
+#define TXCSR7				0x007c
+#define TXCSR7_AR_POWERMANAGEMENT	FIELD32(0x00000001)
+
+/*
+ * TXCSR8: CCK Tx BBP register.
+ */
+#define TXCSR8				0x0098
+#define TXCSR8_BBP_ID0			FIELD32(0x0000007f)
+#define TXCSR8_BBP_ID0_VALID		FIELD32(0x00000080)
+#define TXCSR8_BBP_ID1			FIELD32(0x00007f00)
+#define TXCSR8_BBP_ID1_VALID		FIELD32(0x00008000)
+#define TXCSR8_BBP_ID2			FIELD32(0x007f0000)
+#define TXCSR8_BBP_ID2_VALID		FIELD32(0x00800000)
+#define TXCSR8_BBP_ID3			FIELD32(0x7f000000)
+#define TXCSR8_BBP_ID3_VALID		FIELD32(0x80000000)
+
+/*
+ * TXCSR9: OFDM TX BBP registers
+ * OFDM_SIGNAL: BBP rate field address for OFDM.
+ * OFDM_SERVICE: BBP service field address for OFDM.
+ * OFDM_LENGTH_LOW: BBP length low byte address for OFDM.
+ * OFDM_LENGTH_HIGH: BBP length high byte address for OFDM.
+ */
+#define TXCSR9				0x0094
+#define TXCSR9_OFDM_RATE		FIELD32(0x000000ff)
+#define TXCSR9_OFDM_SERVICE		FIELD32(0x0000ff00)
+#define TXCSR9_OFDM_LENGTH_LOW		FIELD32(0x00ff0000)
+#define TXCSR9_OFDM_LENGTH_HIGH		FIELD32(0xff000000)
+
+/*
+ * Receive related CSRs.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * RXCSR0: RX Control Register.
+ * DISABLE_RX: Disable rx engine.
+ * DROP_CRC: Drop crc error.
+ * DROP_PHYSICAL: Drop physical error.
+ * DROP_CONTROL: Drop control frame.
+ * DROP_NOT_TO_ME: Drop not to me unicast frame.
+ * DROP_TODS: Drop frame tods bit is true.
+ * DROP_VERSION_ERROR: Drop version error frame.
+ * PASS_CRC: Pass all packets with crc attached.
+ * PASS_CRC: Pass all packets with crc attached.
+ * PASS_PLCP: Pass all packets with 4 bytes PLCP attached.
+ * DROP_MCAST: Drop multicast frames.
+ * DROP_BCAST: Drop broadcast frames.
+ * ENABLE_QOS: Accept QOS data frame and parse QOS field.
+ */
+#define RXCSR0				0x0080
+#define RXCSR0_DISABLE_RX		FIELD32(0x00000001)
+#define RXCSR0_DROP_CRC			FIELD32(0x00000002)
+#define RXCSR0_DROP_PHYSICAL		FIELD32(0x00000004)
+#define RXCSR0_DROP_CONTROL		FIELD32(0x00000008)
+#define RXCSR0_DROP_NOT_TO_ME		FIELD32(0x00000010)
+#define RXCSR0_DROP_TODS		FIELD32(0x00000020)
+#define RXCSR0_DROP_VERSION_ERROR	FIELD32(0x00000040)
+#define RXCSR0_PASS_CRC			FIELD32(0x00000080)
+#define RXCSR0_PASS_PLCP		FIELD32(0x00000100)
+#define RXCSR0_DROP_MCAST		FIELD32(0x00000200)
+#define RXCSR0_DROP_BCAST		FIELD32(0x00000400)
+#define RXCSR0_ENABLE_QOS		FIELD32(0x00000800)
+
+/*
+ * RXCSR1: RX descriptor configuration register.
+ * RXD_SIZE: Rx descriptor size, default is 32b.
+ * NUM_RXD: Number of rx entries in ring.
+ */
+#define RXCSR1				0x0084
+#define RXCSR1_RXD_SIZE			FIELD32(0x000000ff)
+#define RXCSR1_NUM_RXD			FIELD32(0x0000ff00)
+
+/*
+ * RXCSR2: RX Ring base address register.
+ */
+#define RXCSR2				0x0088
+#define RXCSR2_RX_RING_REGISTER		FIELD32(0xffffffff)
+
+/*
+ * RXCSR3: BBP ID register for Rx operation.
+ * BBP_ID#: BBP register # id.
+ * BBP_ID#_VALID: BBP register # id is valid or not.
+ */
+#define RXCSR3				0x0090
+#define RXCSR3_BBP_ID0			FIELD32(0x0000007f)
+#define RXCSR3_BBP_ID0_VALID		FIELD32(0x00000080)
+#define RXCSR3_BBP_ID1			FIELD32(0x00007f00)
+#define RXCSR3_BBP_ID1_VALID		FIELD32(0x00008000)
+#define RXCSR3_BBP_ID2			FIELD32(0x007f0000)
+#define RXCSR3_BBP_ID2_VALID		FIELD32(0x00800000)
+#define RXCSR3_BBP_ID3			FIELD32(0x7f000000)
+#define RXCSR3_BBP_ID3_VALID		FIELD32(0x80000000)
+
+/*
+ * ARCSR1: Auto Responder PLCP config register 1.
+ * AR_BBP_DATA#: Auto responder BBP register # data.
+ * AR_BBP_ID#: Auto responder BBP register # Id.
+ */
+#define ARCSR1				0x009c
+#define ARCSR1_AR_BBP_DATA2		FIELD32(0x000000ff)
+#define ARCSR1_AR_BBP_ID2		FIELD32(0x0000ff00)
+#define ARCSR1_AR_BBP_DATA3		FIELD32(0x00ff0000)
+#define ARCSR1_AR_BBP_ID3		FIELD32(0xff000000)
+
+/*
+ * Miscellaneous Registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+
+ */
+
+/*
+ * PCICSR: PCI control register.
+ * BIG_ENDIAN: 1: big endian, 0: little endian.
+ * RX_TRESHOLD: Rx threshold in dw to start pci access
+ * 0: 16dw (default), 1: 8dw, 2: 4dw, 3: 32dw.
+ * TX_TRESHOLD: Tx threshold in dw to start pci access
+ * 0: 0dw (default), 1: 1dw, 2: 4dw, 3: forward.
+ * BURST_LENTH: Pci burst length 0: 4dw (default, 1: 8dw, 2: 16dw, 3:32dw.
+ * ENABLE_CLK: Enable clk_run, pci clock can't going down to non-operational.
+ * READ_MULTIPLE: Enable memory read multiple.
+ * WRITE_INVALID: Enable memory write & invalid.
+ */
+#define PCICSR				0x008c
+#define PCICSR_BIG_ENDIAN		FIELD32(0x00000001)
+#define PCICSR_RX_TRESHOLD		FIELD32(0x00000006)
+#define PCICSR_TX_TRESHOLD		FIELD32(0x00000018)
+#define PCICSR_BURST_LENTH		FIELD32(0x00000060)
+#define PCICSR_ENABLE_CLK		FIELD32(0x00000080)
+#define PCICSR_READ_MULTIPLE		FIELD32(0x00000100)
+#define PCICSR_WRITE_INVALID		FIELD32(0x00000200)
+
+/*
+ * CNT0: FCS error count.
+ * FCS_ERROR: FCS error count, cleared when read.
+ */
+#define CNT0				0x00a0
+#define CNT0_FCS_ERROR			FIELD32(0x0000ffff)
+
+/*
+ * Statistic Register.
+ * CNT1: PLCP error count.
+ * CNT2: Long error count.
+ */
+#define TIMECSR2			0x00a8
+#define CNT1				0x00ac
+#define CNT2				0x00b0
+#define TIMECSR3			0x00b4
+
+/*
+ * CNT3: CCA false alarm count.
+ */
+#define CNT3				0x00b8
+#define CNT3_FALSE_CCA			FIELD32(0x0000ffff)
+
+/*
+ * Statistic Register.
+ * CNT4: Rx FIFO overflow count.
+ * CNT5: Tx FIFO underrun count.
+ */
+#define CNT4				0x00bc
+#define CNT5				0x00c0
+
+/*
+ * Baseband Control Register.
+ */
+
+/*
+ * PWRCSR0: Power mode configuration register.
+ */
+#define PWRCSR0				0x00c4
+
+/*
+ * Power state transition time registers.
+ */
+#define PSCSR0				0x00c8
+#define PSCSR1				0x00cc
+#define PSCSR2				0x00d0
+#define PSCSR3				0x00d4
+
+/*
+ * PWRCSR1: Manual power control / status register.
+ * Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake.
+ * SET_STATE: Set state. Write 1 to trigger, self cleared.
+ * BBP_DESIRE_STATE: BBP desired state.
+ * RF_DESIRE_STATE: RF desired state.
+ * BBP_CURR_STATE: BBP current state.
+ * RF_CURR_STATE: RF current state.
+ * PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared.
+ */
+#define PWRCSR1				0x00d8
+#define PWRCSR1_SET_STATE		FIELD32(0x00000001)
+#define PWRCSR1_BBP_DESIRE_STATE	FIELD32(0x00000006)
+#define PWRCSR1_RF_DESIRE_STATE		FIELD32(0x00000018)
+#define PWRCSR1_BBP_CURR_STATE		FIELD32(0x00000060)
+#define PWRCSR1_RF_CURR_STATE		FIELD32(0x00000180)
+#define PWRCSR1_PUT_TO_SLEEP		FIELD32(0x00000200)
+
+/*
+ * TIMECSR: Timer control register.
+ * US_COUNT: 1 us timer count in units of clock cycles.
+ * US_64_COUNT: 64 us timer count in units of 1 us timer.
+ * BEACON_EXPECT: Beacon expect window.
+ */
+#define TIMECSR				0x00dc
+#define TIMECSR_US_COUNT		FIELD32(0x000000ff)
+#define TIMECSR_US_64_COUNT		FIELD32(0x0000ff00)
+#define TIMECSR_BEACON_EXPECT		FIELD32(0x00070000)
+
+/*
+ * MACCSR0: MAC configuration register 0.
+ */
+#define MACCSR0				0x00e0
+
+/*
+ * MACCSR1: MAC configuration register 1.
+ * KICK_RX: Kick one-shot rx in one-shot rx mode.
+ * ONESHOT_RXMODE: Enable one-shot rx mode for debugging.
+ * BBPRX_RESET_MODE: Ralink bbp rx reset mode.
+ * AUTO_TXBBP: Auto tx logic access bbp control register.
+ * AUTO_RXBBP: Auto rx logic access bbp control register.
+ * LOOPBACK: Loopback mode. 0: normal, 1: internal, 2: external, 3:rsvd.
+ * INTERSIL_IF: Intersil if calibration pin.
+ */
+#define MACCSR1				0x00e4
+#define MACCSR1_KICK_RX			FIELD32(0x00000001)
+#define MACCSR1_ONESHOT_RXMODE		FIELD32(0x00000002)
+#define MACCSR1_BBPRX_RESET_MODE	FIELD32(0x00000004)
+#define MACCSR1_AUTO_TXBBP		FIELD32(0x00000008)
+#define MACCSR1_AUTO_RXBBP		FIELD32(0x00000010)
+#define MACCSR1_LOOPBACK		FIELD32(0x00000060)
+#define MACCSR1_INTERSIL_IF		FIELD32(0x00000080)
+
+/*
+ * RALINKCSR: Ralink Rx auto-reset BBCR.
+ * AR_BBP_DATA#: Auto reset BBP register # data.
+ * AR_BBP_ID#: Auto reset BBP register # id.
+ */
+#define RALINKCSR			0x00e8
+#define RALINKCSR_AR_BBP_DATA0		FIELD32(0x000000ff)
+#define RALINKCSR_AR_BBP_ID0		FIELD32(0x00007f00)
+#define RALINKCSR_AR_BBP_VALID0		FIELD32(0x00008000)
+#define RALINKCSR_AR_BBP_DATA1		FIELD32(0x00ff0000)
+#define RALINKCSR_AR_BBP_ID1		FIELD32(0x7f000000)
+#define RALINKCSR_AR_BBP_VALID1		FIELD32(0x80000000)
+
+/*
+ * BCNCSR: Beacon interval control register.
+ * CHANGE: Write one to change beacon interval.
+ * DELTATIME: The delta time value.
+ * NUM_BEACON: Number of beacon according to mode.
+ * MODE: Please refer to asic specs.
+ * PLUS: Plus or minus delta time value.
+ */
+#define BCNCSR				0x00ec
+#define BCNCSR_CHANGE			FIELD32(0x00000001)
+#define BCNCSR_DELTATIME		FIELD32(0x0000001e)
+#define BCNCSR_NUM_BEACON		FIELD32(0x00001fe0)
+#define BCNCSR_MODE			FIELD32(0x00006000)
+#define BCNCSR_PLUS			FIELD32(0x00008000)
+
+/*
+ * BBP / RF / IF Control Register.
+ */
+
+/*
+ * BBPCSR: BBP serial control register.
+ * VALUE: Register value to program into BBP.
+ * REGNUM: Selected BBP register.
+ * BUSY: 1: asic is busy execute BBP programming.
+ * WRITE_CONTROL: 1: write BBP, 0: read BBP.
+ */
+#define BBPCSR				0x00f0
+#define BBPCSR_VALUE			FIELD32(0x000000ff)
+#define BBPCSR_REGNUM			FIELD32(0x00007f00)
+#define BBPCSR_BUSY			FIELD32(0x00008000)
+#define BBPCSR_WRITE_CONTROL		FIELD32(0x00010000)
+
+/*
+ * RFCSR: RF serial control register.
+ * VALUE: Register value + id to program into rf/if.
+ * NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22).
+ * IF_SELECT: Chip to program: 0: rf, 1: if.
+ * PLL_LD: Rf pll_ld status.
+ * BUSY: 1: asic is busy execute rf programming.
+ */
+#define RFCSR				0x00f4
+#define RFCSR_VALUE			FIELD32(0x00ffffff)
+#define RFCSR_NUMBER_OF_BITS		FIELD32(0x1f000000)
+#define RFCSR_IF_SELECT			FIELD32(0x20000000)
+#define RFCSR_PLL_LD			FIELD32(0x40000000)
+#define RFCSR_BUSY			FIELD32(0x80000000)
+
+/*
+ * LEDCSR: LED control register.
+ * ON_PERIOD: On period, default 70ms.
+ * OFF_PERIOD: Off period, default 30ms.
+ * LINK: 0: linkoff, 1: linkup.
+ * ACTIVITY: 0: idle, 1: active.
+ * LINK_POLARITY: 0: active low, 1: active high.
+ * ACTIVITY_POLARITY: 0: active low, 1: active high.
+ * LED_DEFAULT: LED state for "enable" 0: ON, 1: OFF.
+ */
+#define LEDCSR				0x00f8
+#define LEDCSR_ON_PERIOD		FIELD32(0x000000ff)
+#define LEDCSR_OFF_PERIOD		FIELD32(0x0000ff00)
+#define LEDCSR_LINK			FIELD32(0x00010000)
+#define LEDCSR_ACTIVITY			FIELD32(0x00020000)
+#define LEDCSR_LINK_POLARITY		FIELD32(0x00040000)
+#define LEDCSR_ACTIVITY_POLARITY	FIELD32(0x00080000)
+#define LEDCSR_LED_DEFAULT		FIELD32(0x00100000)
+
+/*
+ * AES control register.
+ */
+#define SECCSR3				0x00fc
+
+/*
+ * ASIC pointer information.
+ * RXPTR: Current RX ring address.
+ * TXPTR: Current Tx ring address.
+ * PRIPTR: Current Priority ring address.
+ * ATIMPTR: Current ATIM ring address.
+ */
+#define RXPTR				0x0100
+#define TXPTR				0x0104
+#define PRIPTR				0x0108
+#define ATIMPTR				0x010c
+
+/*
+ * TXACKCSR0: TX ACK timeout.
+ */
+#define TXACKCSR0			0x0110
+
+/*
+ * ACK timeout count registers.
+ * ACKCNT0: TX ACK timeout count.
+ * ACKCNT1: RX ACK timeout count.
+ */
+#define ACKCNT0				0x0114
+#define ACKCNT1				0x0118
+
+/*
+ * GPIO and others.
+ */
+
+/*
+ * GPIOCSR: GPIO control register.
+ */
+#define GPIOCSR				0x0120
+#define GPIOCSR_BIT0			FIELD32(0x00000001)
+#define GPIOCSR_BIT1			FIELD32(0x00000002)
+#define GPIOCSR_BIT2			FIELD32(0x00000004)
+#define GPIOCSR_BIT3			FIELD32(0x00000008)
+#define GPIOCSR_BIT4			FIELD32(0x00000010)
+#define GPIOCSR_BIT5			FIELD32(0x00000020)
+#define GPIOCSR_BIT6			FIELD32(0x00000040)
+#define GPIOCSR_BIT7			FIELD32(0x00000080)
+#define GPIOCSR_DIR0			FIELD32(0x00000100)
+#define GPIOCSR_DIR1			FIELD32(0x00000200)
+#define GPIOCSR_DIR2			FIELD32(0x00000400)
+#define GPIOCSR_DIR3			FIELD32(0x00000800)
+#define GPIOCSR_DIR4			FIELD32(0x00001000)
+#define GPIOCSR_DIR5			FIELD32(0x00002000)
+#define GPIOCSR_DIR6			FIELD32(0x00004000)
+#define GPIOCSR_DIR7			FIELD32(0x00008000)
+
+/*
+ * FIFO pointer registers.
+ * FIFOCSR0: TX FIFO pointer.
+ * FIFOCSR1: RX FIFO pointer.
+ */
+#define FIFOCSR0			0x0128
+#define FIFOCSR1			0x012c
+
+/*
+ * BCNCSR1: Tx BEACON offset time control register.
+ * PRELOAD: Beacon timer offset in units of usec.
+ * BEACON_CWMIN: 2^CwMin.
+ */
+#define BCNCSR1				0x0130
+#define BCNCSR1_PRELOAD			FIELD32(0x0000ffff)
+#define BCNCSR1_BEACON_CWMIN		FIELD32(0x000f0000)
+
+/*
+ * MACCSR2: TX_PE to RX_PE turn-around time control register
+ * DELAY: RX_PE low width, in units of pci clock cycle.
+ */
+#define MACCSR2				0x0134
+#define MACCSR2_DELAY			FIELD32(0x000000ff)
+
+/*
+ * TESTCSR: TEST mode selection register.
+ */
+#define TESTCSR				0x0138
+
+/*
+ * ARCSR2: 1 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR2				0x013c
+#define ARCSR2_SIGNAL			FIELD32(0x000000ff)
+#define ARCSR2_SERVICE			FIELD32(0x0000ff00)
+#define ARCSR2_LENGTH			FIELD32(0xffff0000)
+
+/*
+ * ARCSR3: 2 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR3				0x0140
+#define ARCSR3_SIGNAL			FIELD32(0x000000ff)
+#define ARCSR3_SERVICE			FIELD32(0x0000ff00)
+#define ARCSR3_LENGTH			FIELD32(0xffff0000)
+
+/*
+ * ARCSR4: 5.5 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR4				0x0144
+#define ARCSR4_SIGNAL			FIELD32(0x000000ff)
+#define ARCSR4_SERVICE			FIELD32(0x0000ff00)
+#define ARCSR4_LENGTH			FIELD32(0xffff0000)
+
+/*
+ * ARCSR5: 11 Mbps ACK/CTS PLCP.
+ */
+#define ARCSR5				0x0148
+#define ARCSR5_SIGNAL			FIELD32(0x000000ff)
+#define ARCSR5_SERVICE			FIELD32(0x0000ff00)
+#define ARCSR5_LENGTH			FIELD32(0xffff0000)
+
+/*
+ * ARTCSR0: CCK ACK/CTS payload consumed time for 1/2/5.5/11 mbps.
+ */
+#define ARTCSR0				0x014c
+#define ARTCSR0_ACK_CTS_11MBS		FIELD32(0x000000ff)
+#define ARTCSR0_ACK_CTS_5_5MBS		FIELD32(0x0000ff00)
+#define ARTCSR0_ACK_CTS_2MBS		FIELD32(0x00ff0000)
+#define ARTCSR0_ACK_CTS_1MBS		FIELD32(0xff000000)
+
+
+/*
+ * ARTCSR1: OFDM ACK/CTS payload consumed time for 6/9/12/18 mbps.
+ */
+#define ARTCSR1				0x0150
+#define ARTCSR1_ACK_CTS_6MBS		FIELD32(0x000000ff)
+#define ARTCSR1_ACK_CTS_9MBS		FIELD32(0x0000ff00)
+#define ARTCSR1_ACK_CTS_12MBS		FIELD32(0x00ff0000)
+#define ARTCSR1_ACK_CTS_18MBS		FIELD32(0xff000000)
+
+/*
+ * ARTCSR2: OFDM ACK/CTS payload consumed time for 24/36/48/54 mbps.
+ */
+#define ARTCSR2				0x0154
+#define ARTCSR2_ACK_CTS_24MBS		FIELD32(0x000000ff)
+#define ARTCSR2_ACK_CTS_36MBS		FIELD32(0x0000ff00)
+#define ARTCSR2_ACK_CTS_48MBS		FIELD32(0x00ff0000)
+#define ARTCSR2_ACK_CTS_54MBS		FIELD32(0xff000000)
+
+/*
+ * SECCSR1_RT2509: WEP control register.
+ * KICK_ENCRYPT: Kick encryption engine, self-clear.
+ * ONE_SHOT: 0: ring mode, 1: One shot only mode.
+ * DESC_ADDRESS: Descriptor physical address of frame.
+ */
+#define SECCSR1				0x0158
+#define SECCSR1_KICK_ENCRYPT		FIELD32(0x00000001)
+#define SECCSR1_ONE_SHOT		FIELD32(0x00000002)
+#define SECCSR1_DESC_ADDRESS		FIELD32(0xfffffffc)
+
+/*
+ * BBPCSR1: BBP TX configuration.
+ */
+#define BBPCSR1				0x015c
+#define BBPCSR1_CCK			FIELD32(0x00000003)
+#define BBPCSR1_CCK_FLIP		FIELD32(0x00000004)
+#define BBPCSR1_OFDM			FIELD32(0x00030000)
+#define BBPCSR1_OFDM_FLIP		FIELD32(0x00040000)
+
+/*
+ * Dual band configuration registers.
+ * DBANDCSR0: Dual band configuration register 0.
+ * DBANDCSR1: Dual band configuration register 1.
+ */
+#define DBANDCSR0			0x0160
+#define DBANDCSR1			0x0164
+
+/*
+ * BBPPCSR: BBP Pin control register.
+ */
+#define BBPPCSR				0x0168
+
+/*
+ * MAC special debug mode selection registers.
+ * DBGSEL0: MAC special debug mode selection register 0.
+ * DBGSEL1: MAC special debug mode selection register 1.
+ */
+#define DBGSEL0				0x016c
+#define DBGSEL1				0x0170
+
+/*
+ * BISTCSR: BBP BIST register.
+ */
+#define BISTCSR				0x0174
+
+/*
+ * Multicast filter registers.
+ * MCAST0: Multicast filter register 0.
+ * MCAST1: Multicast filter register 1.
+ */
+#define MCAST0				0x0178
+#define MCAST1				0x017c
+
+/*
+ * UART registers.
+ * UARTCSR0: UART1 TX register.
+ * UARTCSR1: UART1 RX register.
+ * UARTCSR3: UART1 frame control register.
+ * UARTCSR4: UART1 buffer control register.
+ * UART2CSR0: UART2 TX register.
+ * UART2CSR1: UART2 RX register.
+ * UART2CSR3: UART2 frame control register.
+ * UART2CSR4: UART2 buffer control register.
+ */
+#define UARTCSR0			0x0180
+#define UARTCSR1			0x0184
+#define UARTCSR3			0x0188
+#define UARTCSR4			0x018c
+#define UART2CSR0			0x0190
+#define UART2CSR1			0x0194
+#define UART2CSR3			0x0198
+#define UART2CSR4			0x019c
+
+/*
+ * BBP registers.
+ * The wordsize of the BBP is 8 bits.
+ */
+
+/*
+ * R2: TX antenna control
+ */
+#define BBP_R2_TX_ANTENNA		FIELD8(0x03)
+#define BBP_R2_TX_IQ_FLIP		FIELD8(0x04)
+
+/*
+ * R14: RX antenna control
+ */
+#define BBP_R14_RX_ANTENNA		FIELD8(0x03)
+#define BBP_R14_RX_IQ_FLIP		FIELD8(0x04)
+
+/*
+ * BBP_R70
+ */
+#define BBP_R70_JAPAN_FILTER		FIELD8(0x08)
+
+/*
+ * RF registers
+ */
+
+/*
+ * RF 1
+ */
+#define RF1_TUNER			FIELD32(0x00020000)
+
+/*
+ * RF 3
+ */
+#define RF3_TUNER			FIELD32(0x00000100)
+#define RF3_TXPOWER			FIELD32(0x00003e00)
+
+/*
+ * EEPROM content.
+ * The wordsize of the EEPROM is 16 bits.
+ */
+
+/*
+ * HW MAC address.
+ */
+#define EEPROM_MAC_ADDR_0		0x0002
+#define EEPROM_MAC_ADDR_BYTE0		FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE1		FIELD16(0xff00)
+#define EEPROM_MAC_ADDR1		0x0003
+#define EEPROM_MAC_ADDR_BYTE2		FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE3		FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_2		0x0004
+#define EEPROM_MAC_ADDR_BYTE4		FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE5		FIELD16(0xff00)
+
+/*
+ * EEPROM antenna.
+ * ANTENNA_NUM: Number of antenna's.
+ * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * LED_MODE: 0: default, 1: TX/RX activity,2: Single (ignore link), 3: rsvd.
+ * DYN_TXAGC: Dynamic TX AGC control.
+ * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
+ * RF_TYPE: Rf_type of this adapter.
+ */
+#define EEPROM_ANTENNA			0x10
+#define EEPROM_ANTENNA_NUM		FIELD16(0x0003)
+#define EEPROM_ANTENNA_TX_DEFAULT	FIELD16(0x000c)
+#define EEPROM_ANTENNA_RX_DEFAULT	FIELD16(0x0030)
+#define EEPROM_ANTENNA_LED_MODE		FIELD16(0x01c0)
+#define EEPROM_ANTENNA_DYN_TXAGC	FIELD16(0x0200)
+#define EEPROM_ANTENNA_HARDWARE_RADIO	FIELD16(0x0400)
+#define EEPROM_ANTENNA_RF_TYPE		FIELD16(0xf800)
+
+/*
+ * EEPROM NIC config.
+ * CARDBUS_ACCEL: 0: enable, 1: disable.
+ * DYN_BBP_TUNE: 0: enable, 1: disable.
+ * CCK_TX_POWER: CCK TX power compensation.
+ */
+#define EEPROM_NIC			0x11
+#define EEPROM_NIC_CARDBUS_ACCEL	FIELD16(0x0001)
+#define EEPROM_NIC_DYN_BBP_TUNE		FIELD16(0x0002)
+#define EEPROM_NIC_CCK_TX_POWER		FIELD16(0x000c)
+
+/*
+ * EEPROM geography.
+ * GEO: Default geography setting for device.
+ */
+#define EEPROM_GEOGRAPHY		0x12
+#define EEPROM_GEOGRAPHY_GEO		FIELD16(0x0f00)
+
+/*
+ * EEPROM BBP.
+ */
+#define EEPROM_BBP_START		0x13
+#define EEPROM_BBP_SIZE			16
+#define EEPROM_BBP_VALUE		FIELD16(0x00ff)
+#define EEPROM_BBP_REG_ID		FIELD16(0xff00)
+
+/*
+ * EEPROM TXPOWER
+ */
+#define EEPROM_TXPOWER_START		0x23
+#define EEPROM_TXPOWER_SIZE		7
+#define EEPROM_TXPOWER_1		FIELD16(0x00ff)
+#define EEPROM_TXPOWER_2		FIELD16(0xff00)
+
+/*
+ * RSSI <-> dBm offset calibration
+ */
+#define EEPROM_CALIBRATE_OFFSET		0x3e
+#define EEPROM_CALIBRATE_OFFSET_RSSI	FIELD16(0x00ff)
+
+/*
+ * DMA descriptor defines.
+ */
+#define TXD_DESC_SIZE			( 11 * sizeof(struct data_desc) )
+#define RXD_DESC_SIZE			( 11 * sizeof(struct data_desc) )
+
+/*
+ * TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
+ */
+
+/*
+ * Word0
+ */
+#define TXD_W0_OWNER_NIC		FIELD32(0x00000001)
+#define TXD_W0_VALID			FIELD32(0x00000002)
+#define TXD_W0_RESULT			FIELD32(0x0000001c)
+#define TXD_W0_RETRY_COUNT		FIELD32(0x000000e0)
+#define TXD_W0_MORE_FRAG		FIELD32(0x00000100)
+#define TXD_W0_ACK			FIELD32(0x00000200)
+#define TXD_W0_TIMESTAMP		FIELD32(0x00000400)
+#define TXD_W0_OFDM			FIELD32(0x00000800)
+#define TXD_W0_CIPHER_OWNER		FIELD32(0x00001000)
+#define TXD_W0_IFS			FIELD32(0x00006000)
+#define TXD_W0_RETRY_MODE		FIELD32(0x00008000)
+#define TXD_W0_DATABYTE_COUNT		FIELD32(0x0fff0000)
+#define TXD_W0_CIPHER_ALG		FIELD32(0xe0000000)
+
+/*
+ * Word1
+ */
+#define TXD_W1_BUFFER_ADDRESS		FIELD32(0xffffffff)
+
+/*
+ * Word2
+ */
+#define TXD_W2_IV_OFFSET		FIELD32(0x0000003f)
+#define TXD_W2_AIFS			FIELD32(0x000000c0)
+#define TXD_W2_CWMIN			FIELD32(0x00000f00)
+#define TXD_W2_CWMAX			FIELD32(0x0000f000)
+
+/*
+ * Word3: PLCP information
+ */
+#define TXD_W3_PLCP_SIGNAL		FIELD32(0x000000ff)
+#define TXD_W3_PLCP_SERVICE		FIELD32(0x0000ff00)
+#define TXD_W3_PLCP_LENGTH_LOW		FIELD32(0x00ff0000)
+#define TXD_W3_PLCP_LENGTH_HIGH		FIELD32(0xff000000)
+
+/*
+ * Word4
+ */
+#define TXD_W4_IV			FIELD32(0xffffffff)
+
+/*
+ * Word5
+ */
+#define TXD_W5_EIV			FIELD32(0xffffffff)
+
+/*
+ * Word6-9: Key
+ */
+#define TXD_W6_KEY			FIELD32(0xffffffff)
+#define TXD_W7_KEY			FIELD32(0xffffffff)
+#define TXD_W8_KEY			FIELD32(0xffffffff)
+#define TXD_W9_KEY			FIELD32(0xffffffff)
+
+/*
+ * Word10
+ */
+#define TXD_W10_RTS			FIELD32(0x00000001)
+#define TXD_W10_TX_RATE			FIELD32(0x000000fe)
+
+/*
+ * RX descriptor format for RX Ring.
+ */
+
+/*
+ * Word0
+ */
+#define RXD_W0_OWNER_NIC		FIELD32(0x00000001)
+#define RXD_W0_UNICAST_TO_ME		FIELD32(0x00000002)
+#define RXD_W0_MULTICAST		FIELD32(0x00000004)
+#define RXD_W0_BROADCAST		FIELD32(0x00000008)
+#define RXD_W0_MY_BSS			FIELD32(0x00000010)
+#define RXD_W0_CRC_ERROR		FIELD32(0x00000020)
+#define RXD_W0_OFDM			FIELD32(0x00000040)
+#define RXD_W0_PHYSICAL_ERROR		FIELD32(0x00000080)
+#define RXD_W0_CIPHER_OWNER		FIELD32(0x00000100)
+#define RXD_W0_ICV_ERROR		FIELD32(0x00000200)
+#define RXD_W0_IV_OFFSET		FIELD32(0x0000fc00)
+#define RXD_W0_DATABYTE_COUNT		FIELD32(0x0fff0000)
+#define RXD_W0_CIPHER_ALG		FIELD32(0xe0000000)
+
+/*
+ * Word1
+ */
+#define RXD_W1_BUFFER_ADDRESS		FIELD32(0xffffffff)
+
+/*
+ * Word2
+ */
+#define RXD_W2_SIGNAL			FIELD32(0x000000ff)
+#define RXD_W2_RSSI			FIELD32(0x0000ff00)
+#define RXD_W2_TA			FIELD32(0xffff0000)
+
+/*
+ * Word3
+ */
+#define RXD_W3_TA			FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define RXD_W4_IV			FIELD32(0xffffffff)
+
+/*
+ * Word5
+ */
+#define RXD_W5_EIV			FIELD32(0xffffffff)
+
+/*
+ * Word6-9: Key
+ */
+#define RXD_W6_KEY			FIELD32(0xffffffff)
+#define RXD_W7_KEY			FIELD32(0xffffffff)
+#define RXD_W8_KEY			FIELD32(0xffffffff)
+#define RXD_W9_KEY			FIELD32(0xffffffff)
+
+/*
+ * Word10
+ */
+#define RXD_W10_DROP			FIELD32(0x00000001)
+
+/*
+ * Macro's for converting txpower from EEPROM to dscape value
+ * and from dscape value to register value.
+ */
+#define MIN_TXPOWER	0
+#define MAX_TXPOWER	31
+#define DEFAULT_TXPOWER	24
+
+#define TXPOWER_FROM_DEV(__txpower)		\
+({						\
+	((__txpower) > MAX_TXPOWER) ?		\
+		DEFAULT_TXPOWER : (__txpower);	\
+})
+
+#define TXPOWER_TO_DEV(__txpower)			\
+({							\
+	((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER :	\
+	(((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER :	\
+	(__txpower));					\
+})
+
+#endif /* RT2500PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
new file mode 100644
index 0000000..7cdc80a
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -0,0 +1,1832 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2500usb
+	Abstract: rt2500usb device specific routines.
+	Supported chipsets: RT2570.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2500usb"
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "rt2x00.h"
+#include "rt2x00usb.h"
+#include "rt2500usb.h"
+
+/*
+ * Register access.
+ * All access to the CSR registers will go through the methods
+ * rt2500usb_register_read and rt2500usb_register_write.
+ * BBP and RF register require indirect register access,
+ * and use the CSR registers BBPCSR and RFCSR to achieve this.
+ * These indirect registers work with busy bits,
+ * and we will try maximal REGISTER_BUSY_COUNT times to access
+ * the register while taking a REGISTER_BUSY_DELAY us delay
+ * between each attampt. When the busy bit is still set at that time,
+ * the access attempt is considered to have failed,
+ * and we will print an error.
+ */
+static inline void rt2500usb_register_read(const struct rt2x00_dev *rt2x00dev,
+					   const unsigned int offset,
+					   u16 *value)
+{
+	__le16 reg;
+	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+				      USB_VENDOR_REQUEST_IN, offset,
+				      &reg, sizeof(u16), REGISTER_TIMEOUT);
+	*value = le16_to_cpu(reg);
+}
+
+static inline void rt2500usb_register_multiread(const struct rt2x00_dev
+						*rt2x00dev,
+						const unsigned int offset,
+						void *value, const u16 length)
+{
+	int timeout = REGISTER_TIMEOUT * (length / sizeof(u16));
+	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+				      USB_VENDOR_REQUEST_IN, offset,
+				      value, length, timeout);
+}
+
+static inline void rt2500usb_register_write(const struct rt2x00_dev *rt2x00dev,
+					    const unsigned int offset,
+					    u16 value)
+{
+	__le16 reg = cpu_to_le16(value);
+	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+				      USB_VENDOR_REQUEST_OUT, offset,
+				      &reg, sizeof(u16), REGISTER_TIMEOUT);
+}
+
+static inline void rt2500usb_register_multiwrite(const struct rt2x00_dev
+						 *rt2x00dev,
+						 const unsigned int offset,
+						 void *value, const u16 length)
+{
+	int timeout = REGISTER_TIMEOUT * (length / sizeof(u16));
+	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+				      USB_VENDOR_REQUEST_OUT, offset,
+				      value, length, timeout);
+}
+
+static u16 rt2500usb_bbp_check(const struct rt2x00_dev *rt2x00dev)
+{
+	u16 reg;
+	unsigned int i;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2500usb_register_read(rt2x00dev, PHY_CSR8, &reg);
+		if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY))
+			break;
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	return reg;
+}
+
+static void rt2500usb_bbp_write(const struct rt2x00_dev *rt2x00dev,
+				const unsigned int word, const u8 value)
+{
+	u16 reg;
+
+	/*
+	 * Wait until the BBP becomes ready.
+	 */
+	reg = rt2500usb_bbp_check(rt2x00dev);
+	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
+		ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n");
+		return;
+	}
+
+	/*
+	 * Write the data into the BBP.
+	 */
+	reg = 0;
+	rt2x00_set_field16(&reg, PHY_CSR7_DATA, value);
+	rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
+	rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 0);
+
+	rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg);
+}
+
+static void rt2500usb_bbp_read(const struct rt2x00_dev *rt2x00dev,
+			       const unsigned int word, u8 *value)
+{
+	u16 reg;
+
+	/*
+	 * Wait until the BBP becomes ready.
+	 */
+	reg = rt2500usb_bbp_check(rt2x00dev);
+	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
+		ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
+		return;
+	}
+
+	/*
+	 * Write the request into the BBP.
+	 */
+	reg = 0;
+	rt2x00_set_field16(&reg, PHY_CSR7_REG_ID, word);
+	rt2x00_set_field16(&reg, PHY_CSR7_READ_CONTROL, 1);
+
+	rt2500usb_register_write(rt2x00dev, PHY_CSR7, reg);
+
+	/*
+	 * Wait until the BBP becomes ready.
+	 */
+	reg = rt2500usb_bbp_check(rt2x00dev);
+	if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) {
+		ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n");
+		*value = 0xff;
+		return;
+	}
+
+	rt2500usb_register_read(rt2x00dev, PHY_CSR7, &reg);
+	*value = rt2x00_get_field16(reg, PHY_CSR7_DATA);
+}
+
+static void rt2500usb_rf_write(const struct rt2x00_dev *rt2x00dev,
+			       const unsigned int word, const u32 value)
+{
+	u16 reg;
+	unsigned int i;
+
+	if (!word)
+		return;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2500usb_register_read(rt2x00dev, PHY_CSR10, &reg);
+		if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY))
+			goto rf_write;
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n");
+	return;
+
+rf_write:
+	reg = 0;
+	rt2x00_set_field16(&reg, PHY_CSR9_RF_VALUE, value);
+	rt2500usb_register_write(rt2x00dev, PHY_CSR9, reg);
+
+	reg = 0;
+	rt2x00_set_field16(&reg, PHY_CSR10_RF_VALUE, value >> 16);
+	rt2x00_set_field16(&reg, PHY_CSR10_RF_NUMBER_OF_BITS, 20);
+	rt2x00_set_field16(&reg, PHY_CSR10_RF_IF_SELECT, 0);
+	rt2x00_set_field16(&reg, PHY_CSR10_RF_BUSY, 1);
+
+	rt2500usb_register_write(rt2x00dev, PHY_CSR10, reg);
+	rt2x00_rf_write(rt2x00dev, word, value);
+}
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+#define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u16)) )
+
+static void rt2500usb_read_csr(const struct rt2x00_dev *rt2x00dev,
+			       const unsigned int word, u32 *data)
+{
+	rt2500usb_register_read(rt2x00dev, CSR_OFFSET(word), (u16 *) data);
+}
+
+static void rt2500usb_write_csr(const struct rt2x00_dev *rt2x00dev,
+				const unsigned int word, u32 data)
+{
+	rt2500usb_register_write(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static const struct rt2x00debug rt2500usb_rt2x00debug = {
+	.owner	= THIS_MODULE,
+	.csr	= {
+		.read		= rt2500usb_read_csr,
+		.write		= rt2500usb_write_csr,
+		.word_size	= sizeof(u16),
+		.word_count	= CSR_REG_SIZE / sizeof(u16),
+	},
+	.eeprom	= {
+		.read		= rt2x00_eeprom_read,
+		.write		= rt2x00_eeprom_write,
+		.word_size	= sizeof(u16),
+		.word_count	= EEPROM_SIZE / sizeof(u16),
+	},
+	.bbp	= {
+		.read		= rt2500usb_bbp_read,
+		.write		= rt2500usb_bbp_write,
+		.word_size	= sizeof(u8),
+		.word_count	= BBP_SIZE / sizeof(u8),
+	},
+	.rf	= {
+		.read		= rt2x00_rf_read,
+		.write		= rt2500usb_rf_write,
+		.word_size	= sizeof(u32),
+		.word_count	= RF_SIZE / sizeof(u32),
+	},
+};
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+/*
+ * Configuration handlers.
+ */
+static void rt2500usb_config_mac_addr(struct rt2x00_dev *rt2x00dev,
+				      __le32 *mac)
+{
+	rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR2, &mac,
+				      (3 * sizeof(__le16)));
+}
+
+static void rt2500usb_config_bssid(struct rt2x00_dev *rt2x00dev,
+				   __le32 *bssid)
+{
+	rt2500usb_register_multiwrite(rt2x00dev, MAC_CSR5, bssid,
+				      (3 * sizeof(__le16)));
+}
+
+static void rt2500usb_config_type(struct rt2x00_dev *rt2x00dev, const int type,
+				  const int tsf_sync)
+{
+	u16 reg;
+
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
+
+	/*
+	 * Enable beacon config
+	 */
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR20, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR20_OFFSET,
+			   (PREAMBLE + get_duration(IEEE80211_HEADER, 20)) >> 6);
+	if (type == IEEE80211_IF_TYPE_STA)
+		rt2x00_set_field16(&reg, TXRX_CSR20_BCN_EXPECT_WINDOW, 0);
+	else
+		rt2x00_set_field16(&reg, TXRX_CSR20_BCN_EXPECT_WINDOW, 2);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR20, reg);
+
+	/*
+	 * Enable synchronisation.
+	 */
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR18, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR18_OFFSET, 0);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
+
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR19_TSF_COUNT, 1);
+	rt2x00_set_field16(&reg, TXRX_CSR19_TBCN, 1);
+	rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 0);
+	rt2x00_set_field16(&reg, TXRX_CSR19_TSF_SYNC, tsf_sync);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+}
+
+static void rt2500usb_config_preamble(struct rt2x00_dev *rt2x00dev,
+				      const int short_preamble,
+				      const int ack_timeout,
+				      const int ack_consume_time)
+{
+	u16 reg;
+
+	/*
+	 * When in atomic context, reschedule and let rt2x00lib
+	 * call this function again.
+	 */
+	if (in_atomic()) {
+		queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work);
+		return;
+	}
+
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR1_ACK_TIMEOUT, ack_timeout);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg);
+
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR10, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR10_AUTORESPOND_PREAMBLE,
+			   !!short_preamble);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg);
+}
+
+static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev,
+				     const int phymode,
+				     const int basic_rate_mask)
+{
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR11, basic_rate_mask);
+
+	if (phymode == HWMODE_B) {
+		rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x000b);
+		rt2500usb_register_write(rt2x00dev, MAC_CSR12, 0x0040);
+	} else {
+		rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x0005);
+		rt2500usb_register_write(rt2x00dev, MAC_CSR12, 0x016c);
+	}
+}
+
+static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev,
+				     struct rf_channel *rf, const int txpower)
+{
+	/*
+	 * Set TXpower.
+	 */
+	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+
+	/*
+	 * For RT2525E we should first set the channel to half band higher.
+	 */
+	if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+		static const u32 vals[] = {
+			0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2,
+			0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba,
+			0x000008ba, 0x000008be, 0x000008b7, 0x00000902,
+			0x00000902, 0x00000906
+		};
+
+		rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]);
+		if (rf->rf4)
+			rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
+	}
+
+	rt2500usb_rf_write(rt2x00dev, 1, rf->rf1);
+	rt2500usb_rf_write(rt2x00dev, 2, rf->rf2);
+	rt2500usb_rf_write(rt2x00dev, 3, rf->rf3);
+	if (rf->rf4)
+		rt2500usb_rf_write(rt2x00dev, 4, rf->rf4);
+}
+
+static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev,
+				     const int txpower)
+{
+	u32 rf3;
+
+	rt2x00_rf_read(rt2x00dev, 3, &rf3);
+	rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+	rt2500usb_rf_write(rt2x00dev, 3, rf3);
+}
+
+static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev,
+				     const int antenna_tx, const int antenna_rx)
+{
+	u8 r2;
+	u8 r14;
+	u16 csr5;
+	u16 csr6;
+
+	rt2500usb_bbp_read(rt2x00dev, 2, &r2);
+	rt2500usb_bbp_read(rt2x00dev, 14, &r14);
+	rt2500usb_register_read(rt2x00dev, PHY_CSR5, &csr5);
+	rt2500usb_register_read(rt2x00dev, PHY_CSR6, &csr6);
+
+	/*
+	 * Configure the TX antenna.
+	 */
+	switch (antenna_tx) {
+	case ANTENNA_SW_DIVERSITY:
+	case ANTENNA_HW_DIVERSITY:
+		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 1);
+		rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 1);
+		rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 1);
+		break;
+	case ANTENNA_A:
+		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0);
+		rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 0);
+		rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 0);
+		break;
+	case ANTENNA_B:
+		rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 2);
+		rt2x00_set_field16(&csr5, PHY_CSR5_CCK, 2);
+		rt2x00_set_field16(&csr6, PHY_CSR6_OFDM, 2);
+		break;
+	}
+
+	/*
+	 * Configure the RX antenna.
+	 */
+	switch (antenna_rx) {
+	case ANTENNA_SW_DIVERSITY:
+	case ANTENNA_HW_DIVERSITY:
+		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 1);
+		break;
+	case ANTENNA_A:
+		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0);
+		break;
+	case ANTENNA_B:
+		rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2);
+		break;
+	}
+
+	/*
+	 * RT2525E and RT5222 need to flip TX I/Q
+	 */
+	if (rt2x00_rf(&rt2x00dev->chip, RF2525E) ||
+	    rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+		rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1);
+		rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 1);
+		rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 1);
+
+		/*
+		 * RT2525E does not need RX I/Q Flip.
+		 */
+		if (rt2x00_rf(&rt2x00dev->chip, RF2525E))
+			rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0);
+	} else {
+		rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 0);
+		rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 0);
+	}
+
+	rt2500usb_bbp_write(rt2x00dev, 2, r2);
+	rt2500usb_bbp_write(rt2x00dev, 14, r14);
+	rt2500usb_register_write(rt2x00dev, PHY_CSR5, csr5);
+	rt2500usb_register_write(rt2x00dev, PHY_CSR6, csr6);
+}
+
+static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev,
+				      struct rt2x00lib_conf *libconf)
+{
+	u16 reg;
+
+	rt2500usb_register_write(rt2x00dev, MAC_CSR10, libconf->slot_time);
+
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR18, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR18_INTERVAL,
+			   libconf->conf->beacon_int * 4);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR18, reg);
+}
+
+static void rt2500usb_config(struct rt2x00_dev *rt2x00dev,
+			     const unsigned int flags,
+			     struct rt2x00lib_conf *libconf)
+{
+	if (flags & CONFIG_UPDATE_PHYMODE)
+		rt2500usb_config_phymode(rt2x00dev, libconf->phymode,
+					 libconf->basic_rates);
+	if (flags & CONFIG_UPDATE_CHANNEL)
+		rt2500usb_config_channel(rt2x00dev, &libconf->rf,
+					 libconf->conf->power_level);
+	if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+		rt2500usb_config_txpower(rt2x00dev,
+					 libconf->conf->power_level);
+	if (flags & CONFIG_UPDATE_ANTENNA)
+		rt2500usb_config_antenna(rt2x00dev,
+					 libconf->conf->antenna_sel_tx,
+					 libconf->conf->antenna_sel_rx);
+	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+		rt2500usb_config_duration(rt2x00dev, libconf);
+}
+
+/*
+ * LED functions.
+ */
+static void rt2500usb_enable_led(struct rt2x00_dev *rt2x00dev)
+{
+	u16 reg;
+
+	rt2500usb_register_read(rt2x00dev, MAC_CSR21, &reg);
+	rt2x00_set_field16(&reg, MAC_CSR21_ON_PERIOD, 70);
+	rt2x00_set_field16(&reg, MAC_CSR21_OFF_PERIOD, 30);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR21, reg);
+
+	rt2500usb_register_read(rt2x00dev, MAC_CSR20, &reg);
+
+	if (rt2x00dev->led_mode == LED_MODE_TXRX_ACTIVITY) {
+		rt2x00_set_field16(&reg, MAC_CSR20_LINK, 1);
+		rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY, 0);
+	} else if (rt2x00dev->led_mode == LED_MODE_ASUS) {
+		rt2x00_set_field16(&reg, MAC_CSR20_LINK, 0);
+		rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY, 1);
+	} else {
+		rt2x00_set_field16(&reg, MAC_CSR20_LINK, 1);
+		rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY, 1);
+	}
+
+	rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg);
+}
+
+static void rt2500usb_disable_led(struct rt2x00_dev *rt2x00dev)
+{
+	u16 reg;
+
+	rt2500usb_register_read(rt2x00dev, MAC_CSR20, &reg);
+	rt2x00_set_field16(&reg, MAC_CSR20_LINK, 0);
+	rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY, 0);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg);
+}
+
+/*
+ * Link tuning
+ */
+static void rt2500usb_link_stats(struct rt2x00_dev *rt2x00dev)
+{
+	u16 reg;
+
+	/*
+	 * Update FCS error count from register.
+	 */
+	rt2500usb_register_read(rt2x00dev, STA_CSR0, &reg);
+	rt2x00dev->link.rx_failed = rt2x00_get_field16(reg, STA_CSR0_FCS_ERROR);
+
+	/*
+	 * Update False CCA count from register.
+	 */
+	rt2500usb_register_read(rt2x00dev, STA_CSR3, &reg);
+	rt2x00dev->link.false_cca =
+	    rt2x00_get_field16(reg, STA_CSR3_FALSE_CCA_ERROR);
+}
+
+static void rt2500usb_reset_tuner(struct rt2x00_dev *rt2x00dev)
+{
+	u16 eeprom;
+	u16 value;
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &eeprom);
+	value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R24_LOW);
+	rt2500usb_bbp_write(rt2x00dev, 24, value);
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &eeprom);
+	value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R25_LOW);
+	rt2500usb_bbp_write(rt2x00dev, 25, value);
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &eeprom);
+	value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_R61_LOW);
+	rt2500usb_bbp_write(rt2x00dev, 61, value);
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &eeprom);
+	value = rt2x00_get_field16(eeprom, EEPROM_BBPTUNE_VGCUPPER);
+	rt2500usb_bbp_write(rt2x00dev, 17, value);
+
+	rt2x00dev->link.vgc_level = value;
+}
+
+static void rt2500usb_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+	int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
+	u16 bbp_thresh;
+	u16 vgc_bound;
+	u16 sens;
+	u16 r24;
+	u16 r25;
+	u16 r61;
+	u16 r17_sens;
+	u8 r17;
+	u8 up_bound;
+	u8 low_bound;
+
+	/*
+	 * Determine the BBP tuning threshold and correctly
+	 * set BBP 24, 25 and 61.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE, &bbp_thresh);
+	bbp_thresh = rt2x00_get_field16(bbp_thresh, EEPROM_BBPTUNE_THRESHOLD);
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &r24);
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &r25);
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &r61);
+
+	if ((rssi + bbp_thresh) > 0) {
+		r24 = rt2x00_get_field16(r24, EEPROM_BBPTUNE_R24_HIGH);
+		r25 = rt2x00_get_field16(r25, EEPROM_BBPTUNE_R25_HIGH);
+		r61 = rt2x00_get_field16(r61, EEPROM_BBPTUNE_R61_HIGH);
+	} else {
+		r24 = rt2x00_get_field16(r24, EEPROM_BBPTUNE_R24_LOW);
+		r25 = rt2x00_get_field16(r25, EEPROM_BBPTUNE_R25_LOW);
+		r61 = rt2x00_get_field16(r61, EEPROM_BBPTUNE_R61_LOW);
+	}
+
+	rt2500usb_bbp_write(rt2x00dev, 24, r24);
+	rt2500usb_bbp_write(rt2x00dev, 25, r25);
+	rt2500usb_bbp_write(rt2x00dev, 61, r61);
+
+	/*
+	 * Read current r17 value, as well as the sensitivity values
+	 * for the r17 register.
+	 */
+	rt2500usb_bbp_read(rt2x00dev, 17, &r17);
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &r17_sens);
+
+	/*
+	 * A too low RSSI will cause too much false CCA which will
+	 * then corrupt the R17 tuning. To remidy this the tuning should
+	 * be stopped (While making sure the R17 value will not exceed limits)
+	 */
+	if (rssi >= -40) {
+		if (r17 != 0x60)
+			rt2500usb_bbp_write(rt2x00dev, 17, 0x60);
+		return;
+	}
+
+	/*
+	 * Special big-R17 for short distance
+	 */
+	if (rssi >= -58) {
+		sens = rt2x00_get_field16(r17_sens, EEPROM_BBPTUNE_R17_LOW);
+		if (r17 != sens)
+			rt2500usb_bbp_write(rt2x00dev, 17, sens);
+		return;
+	}
+
+	/*
+	 * Special mid-R17 for middle distance
+	 */
+	if (rssi >= -74) {
+		sens = rt2x00_get_field16(r17_sens, EEPROM_BBPTUNE_R17_HIGH);
+		if (r17 != sens)
+			rt2500usb_bbp_write(rt2x00dev, 17, sens);
+		return;
+	}
+
+	/*
+	 * Leave short or middle distance condition, restore r17
+	 * to the dynamic tuning range.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &vgc_bound);
+	vgc_bound = rt2x00_get_field16(vgc_bound, EEPROM_BBPTUNE_VGCUPPER);
+
+	low_bound = 0x32;
+	if (rssi >= -77)
+		up_bound = vgc_bound;
+	else
+		up_bound = vgc_bound - (-77 - rssi);
+
+	if (up_bound < low_bound)
+		up_bound = low_bound;
+
+	if (r17 > up_bound) {
+		rt2500usb_bbp_write(rt2x00dev, 17, up_bound);
+		rt2x00dev->link.vgc_level = up_bound;
+	} else if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) {
+		rt2500usb_bbp_write(rt2x00dev, 17, ++r17);
+		rt2x00dev->link.vgc_level = r17;
+	} else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) {
+		rt2500usb_bbp_write(rt2x00dev, 17, --r17);
+		rt2x00dev->link.vgc_level = r17;
+	}
+}
+
+/*
+ * Initialization functions.
+ */
+static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+	u16 reg;
+
+	rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0x0001,
+				    USB_MODE_TEST, REGISTER_TIMEOUT);
+	rt2x00usb_vendor_request_sw(rt2x00dev, USB_SINGLE_WRITE, 0x0308,
+				    0x00f0, REGISTER_TIMEOUT);
+
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR2_DISABLE_RX, 1);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+
+	rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x1111);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x1e11);
+
+	rt2500usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+	rt2x00_set_field16(&reg, MAC_CSR1_SOFT_RESET, 1);
+	rt2x00_set_field16(&reg, MAC_CSR1_BBP_RESET, 1);
+	rt2x00_set_field16(&reg, MAC_CSR1_HOST_READY, 0);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+	rt2500usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+	rt2x00_set_field16(&reg, MAC_CSR1_SOFT_RESET, 0);
+	rt2x00_set_field16(&reg, MAC_CSR1_BBP_RESET, 0);
+	rt2x00_set_field16(&reg, MAC_CSR1_HOST_READY, 0);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR5, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR5_BBP_ID0, 13);
+	rt2x00_set_field16(&reg, TXRX_CSR5_BBP_ID0_VALID, 1);
+	rt2x00_set_field16(&reg, TXRX_CSR5_BBP_ID1, 12);
+	rt2x00_set_field16(&reg, TXRX_CSR5_BBP_ID1_VALID, 1);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR5, reg);
+
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR6, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR6_BBP_ID0, 10);
+	rt2x00_set_field16(&reg, TXRX_CSR6_BBP_ID0_VALID, 1);
+	rt2x00_set_field16(&reg, TXRX_CSR6_BBP_ID1, 11);
+	rt2x00_set_field16(&reg, TXRX_CSR6_BBP_ID1_VALID, 1);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR6, reg);
+
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR7, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR7_BBP_ID0, 7);
+	rt2x00_set_field16(&reg, TXRX_CSR7_BBP_ID0_VALID, 1);
+	rt2x00_set_field16(&reg, TXRX_CSR7_BBP_ID1, 6);
+	rt2x00_set_field16(&reg, TXRX_CSR7_BBP_ID1_VALID, 1);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR7, reg);
+
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR8, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR8_BBP_ID0, 5);
+	rt2x00_set_field16(&reg, TXRX_CSR8_BBP_ID0_VALID, 1);
+	rt2x00_set_field16(&reg, TXRX_CSR8_BBP_ID1, 0);
+	rt2x00_set_field16(&reg, TXRX_CSR8_BBP_ID1_VALID, 0);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR8, reg);
+
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR21, 0xe78f);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR9, 0xff1d);
+
+	if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+		return -EBUSY;
+
+	rt2500usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+	rt2x00_set_field16(&reg, MAC_CSR1_SOFT_RESET, 0);
+	rt2x00_set_field16(&reg, MAC_CSR1_BBP_RESET, 0);
+	rt2x00_set_field16(&reg, MAC_CSR1_HOST_READY, 1);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+	if (rt2x00_get_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) {
+		rt2500usb_register_read(rt2x00dev, PHY_CSR2, &reg);
+		reg &= ~0x0002;
+	} else {
+		reg = 0x3002;
+	}
+	rt2500usb_register_write(rt2x00dev, PHY_CSR2, reg);
+
+	rt2500usb_register_write(rt2x00dev, MAC_CSR11, 0x0002);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR22, 0x0053);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR15, 0x01ee);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR16, 0x0000);
+
+	rt2500usb_register_read(rt2x00dev, MAC_CSR8, &reg);
+	rt2x00_set_field16(&reg, MAC_CSR8_MAX_FRAME_UNIT,
+			   rt2x00dev->rx->data_size);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR8, reg);
+
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER);
+	rt2x00_set_field16(&reg, TXRX_CSR0_KEY_ID, 0xff);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+	rt2500usb_register_read(rt2x00dev, MAC_CSR18, &reg);
+	rt2x00_set_field16(&reg, MAC_CSR18_DELAY_AFTER_BEACON, 90);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR18, reg);
+
+	rt2500usb_register_read(rt2x00dev, PHY_CSR4, &reg);
+	rt2x00_set_field16(&reg, PHY_CSR4_LOW_RF_LE, 1);
+	rt2500usb_register_write(rt2x00dev, PHY_CSR4, reg);
+
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR1_AUTO_SEQUENCE, 1);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR1, reg);
+
+	return 0;
+}
+
+static int rt2500usb_init_bbp(struct rt2x00_dev *rt2x00dev)
+{
+	unsigned int i;
+	u16 eeprom;
+	u8 value;
+	u8 reg_id;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2500usb_bbp_read(rt2x00dev, 0, &value);
+		if ((value != 0xff) && (value != 0x00))
+			goto continue_csr_init;
+		NOTICE(rt2x00dev, "Waiting for BBP register.\n");
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+	return -EACCES;
+
+continue_csr_init:
+	rt2500usb_bbp_write(rt2x00dev, 3, 0x02);
+	rt2500usb_bbp_write(rt2x00dev, 4, 0x19);
+	rt2500usb_bbp_write(rt2x00dev, 14, 0x1c);
+	rt2500usb_bbp_write(rt2x00dev, 15, 0x30);
+	rt2500usb_bbp_write(rt2x00dev, 16, 0xac);
+	rt2500usb_bbp_write(rt2x00dev, 18, 0x18);
+	rt2500usb_bbp_write(rt2x00dev, 19, 0xff);
+	rt2500usb_bbp_write(rt2x00dev, 20, 0x1e);
+	rt2500usb_bbp_write(rt2x00dev, 21, 0x08);
+	rt2500usb_bbp_write(rt2x00dev, 22, 0x08);
+	rt2500usb_bbp_write(rt2x00dev, 23, 0x08);
+	rt2500usb_bbp_write(rt2x00dev, 24, 0x80);
+	rt2500usb_bbp_write(rt2x00dev, 25, 0x50);
+	rt2500usb_bbp_write(rt2x00dev, 26, 0x08);
+	rt2500usb_bbp_write(rt2x00dev, 27, 0x23);
+	rt2500usb_bbp_write(rt2x00dev, 30, 0x10);
+	rt2500usb_bbp_write(rt2x00dev, 31, 0x2b);
+	rt2500usb_bbp_write(rt2x00dev, 32, 0xb9);
+	rt2500usb_bbp_write(rt2x00dev, 34, 0x12);
+	rt2500usb_bbp_write(rt2x00dev, 35, 0x50);
+	rt2500usb_bbp_write(rt2x00dev, 39, 0xc4);
+	rt2500usb_bbp_write(rt2x00dev, 40, 0x02);
+	rt2500usb_bbp_write(rt2x00dev, 41, 0x60);
+	rt2500usb_bbp_write(rt2x00dev, 53, 0x10);
+	rt2500usb_bbp_write(rt2x00dev, 54, 0x18);
+	rt2500usb_bbp_write(rt2x00dev, 56, 0x08);
+	rt2500usb_bbp_write(rt2x00dev, 57, 0x10);
+	rt2500usb_bbp_write(rt2x00dev, 58, 0x08);
+	rt2500usb_bbp_write(rt2x00dev, 61, 0x60);
+	rt2500usb_bbp_write(rt2x00dev, 62, 0x10);
+	rt2500usb_bbp_write(rt2x00dev, 75, 0xff);
+
+	DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
+	for (i = 0; i < EEPROM_BBP_SIZE; i++) {
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+
+		if (eeprom != 0xffff && eeprom != 0x0000) {
+			reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
+			value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
+			DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
+			      reg_id, value);
+			rt2500usb_bbp_write(rt2x00dev, reg_id, value);
+		}
+	}
+	DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
+
+	return 0;
+}
+
+/*
+ * Device state switch handlers.
+ */
+static void rt2500usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
+				enum dev_state state)
+{
+	u16 reg;
+
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR2_DISABLE_RX,
+			   state == STATE_RADIO_RX_OFF);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+}
+
+static int rt2500usb_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+	/*
+	 * Initialize all registers.
+	 */
+	if (rt2500usb_init_registers(rt2x00dev) ||
+	    rt2500usb_init_bbp(rt2x00dev)) {
+		ERROR(rt2x00dev, "Register initialization failed.\n");
+		return -EIO;
+	}
+
+	rt2x00usb_enable_radio(rt2x00dev);
+
+	/*
+	 * Enable LED
+	 */
+	rt2500usb_enable_led(rt2x00dev);
+
+	return 0;
+}
+
+static void rt2500usb_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+	/*
+	 * Disable LED
+	 */
+	rt2500usb_disable_led(rt2x00dev);
+
+	rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x2121);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x2121);
+
+	/*
+	 * Disable synchronisation.
+	 */
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
+
+	rt2x00usb_disable_radio(rt2x00dev);
+}
+
+static int rt2500usb_set_state(struct rt2x00_dev *rt2x00dev,
+			       enum dev_state state)
+{
+	u16 reg;
+	u16 reg2;
+	unsigned int i;
+	char put_to_sleep;
+	char bbp_state;
+	char rf_state;
+
+	put_to_sleep = (state != STATE_AWAKE);
+
+	reg = 0;
+	rt2x00_set_field16(&reg, MAC_CSR17_BBP_DESIRE_STATE, state);
+	rt2x00_set_field16(&reg, MAC_CSR17_RF_DESIRE_STATE, state);
+	rt2x00_set_field16(&reg, MAC_CSR17_PUT_TO_SLEEP, put_to_sleep);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR17, reg);
+	rt2x00_set_field16(&reg, MAC_CSR17_SET_STATE, 1);
+	rt2500usb_register_write(rt2x00dev, MAC_CSR17, reg);
+
+	/*
+	 * Device is not guaranteed to be in the requested state yet.
+	 * We must wait until the register indicates that the
+	 * device has entered the correct state.
+	 */
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2500usb_register_read(rt2x00dev, MAC_CSR17, &reg2);
+		bbp_state = rt2x00_get_field16(reg2, MAC_CSR17_BBP_CURR_STATE);
+		rf_state = rt2x00_get_field16(reg2, MAC_CSR17_RF_CURR_STATE);
+		if (bbp_state == state && rf_state == state)
+			return 0;
+		rt2500usb_register_write(rt2x00dev, MAC_CSR17, reg);
+		msleep(30);
+	}
+
+	NOTICE(rt2x00dev, "Device failed to enter state %d, "
+	       "current device state: bbp %d and rf %d.\n",
+	       state, bbp_state, rf_state);
+
+	return -EBUSY;
+}
+
+static int rt2500usb_set_device_state(struct rt2x00_dev *rt2x00dev,
+				      enum dev_state state)
+{
+	int retval = 0;
+
+	switch (state) {
+	case STATE_RADIO_ON:
+		retval = rt2500usb_enable_radio(rt2x00dev);
+		break;
+	case STATE_RADIO_OFF:
+		rt2500usb_disable_radio(rt2x00dev);
+		break;
+	case STATE_RADIO_RX_ON:
+	case STATE_RADIO_RX_OFF:
+		rt2500usb_toggle_rx(rt2x00dev, state);
+		break;
+	case STATE_DEEP_SLEEP:
+	case STATE_SLEEP:
+	case STATE_STANDBY:
+	case STATE_AWAKE:
+		retval = rt2500usb_set_state(rt2x00dev, state);
+		break;
+	default:
+		retval = -ENOTSUPP;
+		break;
+	}
+
+	return retval;
+}
+
+/*
+ * TX descriptor initialization
+ */
+static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+				    struct data_desc *txd,
+				    struct txdata_entry_desc *desc,
+				    struct ieee80211_hdr *ieee80211hdr,
+				    unsigned int length,
+				    struct ieee80211_tx_control *control)
+{
+	u32 word;
+
+	/*
+	 * Start writing the descriptor words.
+	 */
+	rt2x00_desc_read(txd, 1, &word);
+	rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
+	rt2x00_set_field32(&word, TXD_W1_AIFS, desc->aifs);
+	rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min);
+	rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max);
+	rt2x00_desc_write(txd, 1, word);
+
+	rt2x00_desc_read(txd, 2, &word);
+	rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal);
+	rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service);
+	rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low);
+	rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high);
+	rt2x00_desc_write(txd, 2, word);
+
+	rt2x00_desc_read(txd, 0, &word);
+	rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, control->retry_limit);
+	rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+			   test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_ACK,
+			   !(control->flags & IEEE80211_TXCTL_NO_ACK));
+	rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+			   test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_OFDM,
+			   test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_NEW_SEQ,
+			   !!(control->flags & IEEE80211_TXCTL_FIRST_FRAGMENT));
+	rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
+	rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE);
+	rt2x00_desc_write(txd, 0, word);
+}
+
+static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
+				     int maxpacket, struct sk_buff *skb)
+{
+	int length;
+
+	/*
+	 * The length _must_ be a multiple of 2,
+	 * but it must _not_ be a multiple of the USB packet size.
+	 */
+	length = roundup(skb->len, 2);
+	length += (2 * !(length % maxpacket));
+
+	return length;
+}
+
+/*
+ * TX data initialization
+ */
+static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+				    unsigned int queue)
+{
+	u16 reg;
+
+	if (queue != IEEE80211_TX_QUEUE_BEACON)
+		return;
+
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR19, &reg);
+	if (!rt2x00_get_field16(reg, TXRX_CSR19_BEACON_GEN)) {
+		rt2x00_set_field16(&reg, TXRX_CSR19_BEACON_GEN, 1);
+		/*
+		 * Beacon generation will fail initially.
+		 * To prevent this we need to register the TXRX_CSR19
+		 * register several times.
+		 */
+		rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+		rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
+		rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+		rt2500usb_register_write(rt2x00dev, TXRX_CSR19, 0);
+		rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+	}
+}
+
+/*
+ * RX control handlers
+ */
+static void rt2500usb_fill_rxdone(struct data_entry *entry,
+				  struct rxdata_entry_desc *desc)
+{
+	struct urb *urb = entry->priv;
+	struct data_desc *rxd = (struct data_desc *)(entry->skb->data +
+						     (urb->actual_length -
+						      entry->ring->desc_size));
+	u32 word0;
+	u32 word1;
+
+	rt2x00_desc_read(rxd, 0, &word0);
+	rt2x00_desc_read(rxd, 1, &word1);
+
+	desc->flags = 0;
+	if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+		desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+	if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR))
+		desc->flags |= RX_FLAG_FAILED_PLCP_CRC;
+
+	/*
+	 * Obtain the status about this packet.
+	 */
+	desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+	desc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) -
+	    entry->ring->rt2x00dev->rssi_offset;
+	desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+	desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+
+	return;
+}
+
+/*
+ * Interrupt functions.
+ */
+static void rt2500usb_beacondone(struct urb *urb)
+{
+	struct data_entry *entry = (struct data_entry *)urb->context;
+	struct data_ring *ring = entry->ring;
+
+	if (!test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags))
+		return;
+
+	/*
+	 * Check if this was the guardian beacon,
+	 * if that was the case we need to send the real beacon now.
+	 * Otherwise we should free the sk_buffer, the device
+	 * should be doing the rest of the work now.
+	 */
+	if (ring->index == 1) {
+		rt2x00_ring_index_done_inc(ring);
+		entry = rt2x00_get_data_entry(ring);
+		usb_submit_urb(entry->priv, GFP_ATOMIC);
+		rt2x00_ring_index_inc(ring);
+	} else if (ring->index_done == 1) {
+		entry = rt2x00_get_data_entry_done(ring);
+		if (entry->skb) {
+			dev_kfree_skb(entry->skb);
+			entry->skb = NULL;
+		}
+		rt2x00_ring_index_done_inc(ring);
+	}
+}
+
+/*
+ * Device probe functions.
+ */
+static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+	u16 word;
+	u8 *mac;
+
+	rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE);
+
+	/*
+	 * Start validation of the data that has been read.
+	 */
+	mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+	if (!is_valid_ether_addr(mac)) {
+		DECLARE_MAC_BUF(macbuf);
+
+		random_ether_addr(mac);
+		EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_LED_MODE, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2522);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+		EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
+		rt2x00_set_field16(&word, EEPROM_NIC_DYN_BBP_TUNE, 0);
+		rt2x00_set_field16(&word, EEPROM_NIC_CCK_TX_POWER, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
+		EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_CALIBRATE_OFFSET_RSSI,
+				   DEFAULT_RSSI_OFFSET);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_CALIBRATE_OFFSET, word);
+		EEPROM(rt2x00dev, "Calibrate offset: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_BBPTUNE_THRESHOLD, 45);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE, word);
+		EEPROM(rt2x00dev, "BBPtune: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_VGC, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCUPPER, 0x40);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word);
+		EEPROM(rt2x00dev, "BBPtune vgc: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_LOW, 0x48);
+		rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_HIGH, 0x41);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R17, word);
+		EEPROM(rt2x00dev, "BBPtune r17: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_BBPTUNE_R24_LOW, 0x40);
+		rt2x00_set_field16(&word, EEPROM_BBPTUNE_R24_HIGH, 0x80);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R24, word);
+		EEPROM(rt2x00dev, "BBPtune r24: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R25, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_BBPTUNE_R25_LOW, 0x40);
+		rt2x00_set_field16(&word, EEPROM_BBPTUNE_R25_HIGH, 0x50);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R25, word);
+		EEPROM(rt2x00dev, "BBPtune r25: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R61, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_BBPTUNE_R61_LOW, 0x60);
+		rt2x00_set_field16(&word, EEPROM_BBPTUNE_R61_HIGH, 0x6d);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R61, word);
+		EEPROM(rt2x00dev, "BBPtune r61: 0x%04x\n", word);
+	}
+
+	return 0;
+}
+
+static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+	u16 reg;
+	u16 value;
+	u16 eeprom;
+
+	/*
+	 * Read EEPROM word for configuration.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+	/*
+	 * Identify RF chipset.
+	 */
+	value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+	rt2500usb_register_read(rt2x00dev, MAC_CSR0, &reg);
+	rt2x00_set_chip(rt2x00dev, RT2570, value, reg);
+
+	if (rt2x00_rev(&rt2x00dev->chip, 0xffff0)) {
+		ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
+		return -ENODEV;
+	}
+
+	if (!rt2x00_rf(&rt2x00dev->chip, RF2522) &&
+	    !rt2x00_rf(&rt2x00dev->chip, RF2523) &&
+	    !rt2x00_rf(&rt2x00dev->chip, RF2524) &&
+	    !rt2x00_rf(&rt2x00dev->chip, RF2525) &&
+	    !rt2x00_rf(&rt2x00dev->chip, RF2525E) &&
+	    !rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Identify default antenna configuration.
+	 */
+	rt2x00dev->hw->conf.antenna_sel_tx =
+	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
+	rt2x00dev->hw->conf.antenna_sel_rx =
+	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
+
+	/*
+	 * Store led mode, for correct led behaviour.
+	 */
+	rt2x00dev->led_mode =
+	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
+
+	/*
+	 * Check if the BBP tuning should be disabled.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+	if (rt2x00_get_field16(eeprom, EEPROM_NIC_DYN_BBP_TUNE))
+		__set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags);
+
+	/*
+	 * Read the RSSI <-> dBm offset information.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_CALIBRATE_OFFSET, &eeprom);
+	rt2x00dev->rssi_offset =
+	    rt2x00_get_field16(eeprom, EEPROM_CALIBRATE_OFFSET_RSSI);
+
+	return 0;
+}
+
+/*
+ * RF value list for RF2522
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2522[] = {
+	{ 1,  0x00002050, 0x000c1fda, 0x00000101, 0 },
+	{ 2,  0x00002050, 0x000c1fee, 0x00000101, 0 },
+	{ 3,  0x00002050, 0x000c2002, 0x00000101, 0 },
+	{ 4,  0x00002050, 0x000c2016, 0x00000101, 0 },
+	{ 5,  0x00002050, 0x000c202a, 0x00000101, 0 },
+	{ 6,  0x00002050, 0x000c203e, 0x00000101, 0 },
+	{ 7,  0x00002050, 0x000c2052, 0x00000101, 0 },
+	{ 8,  0x00002050, 0x000c2066, 0x00000101, 0 },
+	{ 9,  0x00002050, 0x000c207a, 0x00000101, 0 },
+	{ 10, 0x00002050, 0x000c208e, 0x00000101, 0 },
+	{ 11, 0x00002050, 0x000c20a2, 0x00000101, 0 },
+	{ 12, 0x00002050, 0x000c20b6, 0x00000101, 0 },
+	{ 13, 0x00002050, 0x000c20ca, 0x00000101, 0 },
+	{ 14, 0x00002050, 0x000c20fa, 0x00000101, 0 },
+};
+
+/*
+ * RF value list for RF2523
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2523[] = {
+	{ 1,  0x00022010, 0x00000c9e, 0x000e0111, 0x00000a1b },
+	{ 2,  0x00022010, 0x00000ca2, 0x000e0111, 0x00000a1b },
+	{ 3,  0x00022010, 0x00000ca6, 0x000e0111, 0x00000a1b },
+	{ 4,  0x00022010, 0x00000caa, 0x000e0111, 0x00000a1b },
+	{ 5,  0x00022010, 0x00000cae, 0x000e0111, 0x00000a1b },
+	{ 6,  0x00022010, 0x00000cb2, 0x000e0111, 0x00000a1b },
+	{ 7,  0x00022010, 0x00000cb6, 0x000e0111, 0x00000a1b },
+	{ 8,  0x00022010, 0x00000cba, 0x000e0111, 0x00000a1b },
+	{ 9,  0x00022010, 0x00000cbe, 0x000e0111, 0x00000a1b },
+	{ 10, 0x00022010, 0x00000d02, 0x000e0111, 0x00000a1b },
+	{ 11, 0x00022010, 0x00000d06, 0x000e0111, 0x00000a1b },
+	{ 12, 0x00022010, 0x00000d0a, 0x000e0111, 0x00000a1b },
+	{ 13, 0x00022010, 0x00000d0e, 0x000e0111, 0x00000a1b },
+	{ 14, 0x00022010, 0x00000d1a, 0x000e0111, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2524
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2524[] = {
+	{ 1,  0x00032020, 0x00000c9e, 0x00000101, 0x00000a1b },
+	{ 2,  0x00032020, 0x00000ca2, 0x00000101, 0x00000a1b },
+	{ 3,  0x00032020, 0x00000ca6, 0x00000101, 0x00000a1b },
+	{ 4,  0x00032020, 0x00000caa, 0x00000101, 0x00000a1b },
+	{ 5,  0x00032020, 0x00000cae, 0x00000101, 0x00000a1b },
+	{ 6,  0x00032020, 0x00000cb2, 0x00000101, 0x00000a1b },
+	{ 7,  0x00032020, 0x00000cb6, 0x00000101, 0x00000a1b },
+	{ 8,  0x00032020, 0x00000cba, 0x00000101, 0x00000a1b },
+	{ 9,  0x00032020, 0x00000cbe, 0x00000101, 0x00000a1b },
+	{ 10, 0x00032020, 0x00000d02, 0x00000101, 0x00000a1b },
+	{ 11, 0x00032020, 0x00000d06, 0x00000101, 0x00000a1b },
+	{ 12, 0x00032020, 0x00000d0a, 0x00000101, 0x00000a1b },
+	{ 13, 0x00032020, 0x00000d0e, 0x00000101, 0x00000a1b },
+	{ 14, 0x00032020, 0x00000d1a, 0x00000101, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2525
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2525[] = {
+	{ 1,  0x00022020, 0x00080c9e, 0x00060111, 0x00000a1b },
+	{ 2,  0x00022020, 0x00080ca2, 0x00060111, 0x00000a1b },
+	{ 3,  0x00022020, 0x00080ca6, 0x00060111, 0x00000a1b },
+	{ 4,  0x00022020, 0x00080caa, 0x00060111, 0x00000a1b },
+	{ 5,  0x00022020, 0x00080cae, 0x00060111, 0x00000a1b },
+	{ 6,  0x00022020, 0x00080cb2, 0x00060111, 0x00000a1b },
+	{ 7,  0x00022020, 0x00080cb6, 0x00060111, 0x00000a1b },
+	{ 8,  0x00022020, 0x00080cba, 0x00060111, 0x00000a1b },
+	{ 9,  0x00022020, 0x00080cbe, 0x00060111, 0x00000a1b },
+	{ 10, 0x00022020, 0x00080d02, 0x00060111, 0x00000a1b },
+	{ 11, 0x00022020, 0x00080d06, 0x00060111, 0x00000a1b },
+	{ 12, 0x00022020, 0x00080d0a, 0x00060111, 0x00000a1b },
+	{ 13, 0x00022020, 0x00080d0e, 0x00060111, 0x00000a1b },
+	{ 14, 0x00022020, 0x00080d1a, 0x00060111, 0x00000a03 },
+};
+
+/*
+ * RF value list for RF2525e
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2525e[] = {
+	{ 1,  0x00022010, 0x0000089a, 0x00060111, 0x00000e1b },
+	{ 2,  0x00022010, 0x0000089e, 0x00060111, 0x00000e07 },
+	{ 3,  0x00022010, 0x0000089e, 0x00060111, 0x00000e1b },
+	{ 4,  0x00022010, 0x000008a2, 0x00060111, 0x00000e07 },
+	{ 5,  0x00022010, 0x000008a2, 0x00060111, 0x00000e1b },
+	{ 6,  0x00022010, 0x000008a6, 0x00060111, 0x00000e07 },
+	{ 7,  0x00022010, 0x000008a6, 0x00060111, 0x00000e1b },
+	{ 8,  0x00022010, 0x000008aa, 0x00060111, 0x00000e07 },
+	{ 9,  0x00022010, 0x000008aa, 0x00060111, 0x00000e1b },
+	{ 10, 0x00022010, 0x000008ae, 0x00060111, 0x00000e07 },
+	{ 11, 0x00022010, 0x000008ae, 0x00060111, 0x00000e1b },
+	{ 12, 0x00022010, 0x000008b2, 0x00060111, 0x00000e07 },
+	{ 13, 0x00022010, 0x000008b2, 0x00060111, 0x00000e1b },
+	{ 14, 0x00022010, 0x000008b6, 0x00060111, 0x00000e23 },
+};
+
+/*
+ * RF value list for RF5222
+ * Supports: 2.4 GHz & 5.2 GHz
+ */
+static const struct rf_channel rf_vals_5222[] = {
+	{ 1,  0x00022020, 0x00001136, 0x00000101, 0x00000a0b },
+	{ 2,  0x00022020, 0x0000113a, 0x00000101, 0x00000a0b },
+	{ 3,  0x00022020, 0x0000113e, 0x00000101, 0x00000a0b },
+	{ 4,  0x00022020, 0x00001182, 0x00000101, 0x00000a0b },
+	{ 5,  0x00022020, 0x00001186, 0x00000101, 0x00000a0b },
+	{ 6,  0x00022020, 0x0000118a, 0x00000101, 0x00000a0b },
+	{ 7,  0x00022020, 0x0000118e, 0x00000101, 0x00000a0b },
+	{ 8,  0x00022020, 0x00001192, 0x00000101, 0x00000a0b },
+	{ 9,  0x00022020, 0x00001196, 0x00000101, 0x00000a0b },
+	{ 10, 0x00022020, 0x0000119a, 0x00000101, 0x00000a0b },
+	{ 11, 0x00022020, 0x0000119e, 0x00000101, 0x00000a0b },
+	{ 12, 0x00022020, 0x000011a2, 0x00000101, 0x00000a0b },
+	{ 13, 0x00022020, 0x000011a6, 0x00000101, 0x00000a0b },
+	{ 14, 0x00022020, 0x000011ae, 0x00000101, 0x00000a1b },
+
+	/* 802.11 UNI / HyperLan 2 */
+	{ 36, 0x00022010, 0x00018896, 0x00000101, 0x00000a1f },
+	{ 40, 0x00022010, 0x0001889a, 0x00000101, 0x00000a1f },
+	{ 44, 0x00022010, 0x0001889e, 0x00000101, 0x00000a1f },
+	{ 48, 0x00022010, 0x000188a2, 0x00000101, 0x00000a1f },
+	{ 52, 0x00022010, 0x000188a6, 0x00000101, 0x00000a1f },
+	{ 66, 0x00022010, 0x000188aa, 0x00000101, 0x00000a1f },
+	{ 60, 0x00022010, 0x000188ae, 0x00000101, 0x00000a1f },
+	{ 64, 0x00022010, 0x000188b2, 0x00000101, 0x00000a1f },
+
+	/* 802.11 HyperLan 2 */
+	{ 100, 0x00022010, 0x00008802, 0x00000101, 0x00000a0f },
+	{ 104, 0x00022010, 0x00008806, 0x00000101, 0x00000a0f },
+	{ 108, 0x00022010, 0x0000880a, 0x00000101, 0x00000a0f },
+	{ 112, 0x00022010, 0x0000880e, 0x00000101, 0x00000a0f },
+	{ 116, 0x00022010, 0x00008812, 0x00000101, 0x00000a0f },
+	{ 120, 0x00022010, 0x00008816, 0x00000101, 0x00000a0f },
+	{ 124, 0x00022010, 0x0000881a, 0x00000101, 0x00000a0f },
+	{ 128, 0x00022010, 0x0000881e, 0x00000101, 0x00000a0f },
+	{ 132, 0x00022010, 0x00008822, 0x00000101, 0x00000a0f },
+	{ 136, 0x00022010, 0x00008826, 0x00000101, 0x00000a0f },
+
+	/* 802.11 UNII */
+	{ 140, 0x00022010, 0x0000882a, 0x00000101, 0x00000a0f },
+	{ 149, 0x00022020, 0x000090a6, 0x00000101, 0x00000a07 },
+	{ 153, 0x00022020, 0x000090ae, 0x00000101, 0x00000a07 },
+	{ 157, 0x00022020, 0x000090b6, 0x00000101, 0x00000a07 },
+	{ 161, 0x00022020, 0x000090be, 0x00000101, 0x00000a07 },
+};
+
+static void rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+{
+	struct hw_mode_spec *spec = &rt2x00dev->spec;
+	u8 *txpower;
+	unsigned int i;
+
+	/*
+	 * Initialize all hw fields.
+	 */
+	rt2x00dev->hw->flags =
+	    IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+	    IEEE80211_HW_RX_INCLUDES_FCS |
+	    IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+	rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
+	rt2x00dev->hw->max_signal = MAX_SIGNAL;
+	rt2x00dev->hw->max_rssi = MAX_RX_SSI;
+	rt2x00dev->hw->queues = 2;
+
+	SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
+	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+				rt2x00_eeprom_addr(rt2x00dev,
+						   EEPROM_MAC_ADDR_0));
+
+	/*
+	 * Convert tx_power array in eeprom.
+	 */
+	txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_START);
+	for (i = 0; i < 14; i++)
+		txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+	/*
+	 * Initialize hw_mode information.
+	 */
+	spec->num_modes = 2;
+	spec->num_rates = 12;
+	spec->tx_power_a = NULL;
+	spec->tx_power_bg = txpower;
+	spec->tx_power_default = DEFAULT_TXPOWER;
+
+	if (rt2x00_rf(&rt2x00dev->chip, RF2522)) {
+		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522);
+		spec->channels = rf_vals_bg_2522;
+	} else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) {
+		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523);
+		spec->channels = rf_vals_bg_2523;
+	} else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) {
+		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524);
+		spec->channels = rf_vals_bg_2524;
+	} else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) {
+		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525);
+		spec->channels = rf_vals_bg_2525;
+	} else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) {
+		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e);
+		spec->channels = rf_vals_bg_2525e;
+	} else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) {
+		spec->num_channels = ARRAY_SIZE(rf_vals_5222);
+		spec->channels = rf_vals_5222;
+		spec->num_modes = 3;
+	}
+}
+
+static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+	int retval;
+
+	/*
+	 * Allocate eeprom data.
+	 */
+	retval = rt2500usb_validate_eeprom(rt2x00dev);
+	if (retval)
+		return retval;
+
+	retval = rt2500usb_init_eeprom(rt2x00dev);
+	if (retval)
+		return retval;
+
+	/*
+	 * Initialize hw specifications.
+	 */
+	rt2500usb_probe_hw_mode(rt2x00dev);
+
+	/*
+	 * This device requires the beacon ring
+	 */
+	__set_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
+
+	/*
+	 * Set the rssi offset.
+	 */
+	rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
+	return 0;
+}
+
+/*
+ * IEEE80211 stack callback functions.
+ */
+static void rt2500usb_configure_filter(struct ieee80211_hw *hw,
+				       unsigned int changed_flags,
+				       unsigned int *total_flags,
+				       int mc_count,
+				       struct dev_addr_list *mc_list)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct interface *intf = &rt2x00dev->interface;
+	u16 reg;
+
+	/*
+	 * Mask off any flags we are going to ignore from
+	 * the total_flags field.
+	 */
+	*total_flags &=
+	    FIF_ALLMULTI |
+	    FIF_FCSFAIL |
+	    FIF_PLCPFAIL |
+	    FIF_CONTROL |
+	    FIF_OTHER_BSS |
+	    FIF_PROMISC_IN_BSS;
+
+	/*
+	 * Apply some rules to the filters:
+	 * - Some filters imply different filters to be set.
+	 * - Some things we can't filter out at all.
+	 * - Some filters are set based on interface type.
+	 */
+	if (mc_count)
+		*total_flags |= FIF_ALLMULTI;
+	if (*total_flags & FIF_OTHER_BSS ||
+	    *total_flags & FIF_PROMISC_IN_BSS)
+		*total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+	if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+		*total_flags |= FIF_PROMISC_IN_BSS;
+
+	/*
+	 * Check if there is any work left for us.
+	 */
+	if (intf->filter == *total_flags)
+		return;
+	intf->filter = *total_flags;
+
+	/*
+	 * When in atomic context, reschedule and let rt2x00lib
+	 * call this function again.
+	 */
+	if (in_atomic()) {
+		queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
+		return;
+	}
+
+	/*
+	 * Start configuration steps.
+	 * Note that the version error will always be dropped
+	 * and broadcast frames will always be accepted since
+	 * there is no filter for it at this time.
+	 */
+	rt2500usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+	rt2x00_set_field16(&reg, TXRX_CSR2_DROP_CRC,
+			   !(*total_flags & FIF_FCSFAIL));
+	rt2x00_set_field16(&reg, TXRX_CSR2_DROP_PHYSICAL,
+			   !(*total_flags & FIF_PLCPFAIL));
+	rt2x00_set_field16(&reg, TXRX_CSR2_DROP_CONTROL,
+			   !(*total_flags & FIF_CONTROL));
+	rt2x00_set_field16(&reg, TXRX_CSR2_DROP_NOT_TO_ME,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field16(&reg, TXRX_CSR2_DROP_TODS,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field16(&reg, TXRX_CSR2_DROP_VERSION_ERROR, 1);
+	rt2x00_set_field16(&reg, TXRX_CSR2_DROP_MULTICAST,
+			   !(*total_flags & FIF_ALLMULTI));
+	rt2x00_set_field16(&reg, TXRX_CSR2_DROP_BROADCAST, 0);
+	rt2500usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+}
+
+static int rt2500usb_beacon_update(struct ieee80211_hw *hw,
+				   struct sk_buff *skb,
+				   struct ieee80211_tx_control *control)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct usb_device *usb_dev =
+	    interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
+	struct data_ring *ring =
+	    rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+	struct data_entry *beacon;
+	struct data_entry *guardian;
+	int pipe = usb_sndbulkpipe(usb_dev, 1);
+	int max_packet = usb_maxpacket(usb_dev, pipe, 1);
+	int length;
+
+	/*
+	 * Just in case the ieee80211 doesn't set this,
+	 * but we need this queue set for the descriptor
+	 * initialization.
+	 */
+	control->queue = IEEE80211_TX_QUEUE_BEACON;
+
+	/*
+	 * Obtain 2 entries, one for the guardian byte,
+	 * the second for the actual beacon.
+	 */
+	guardian = rt2x00_get_data_entry(ring);
+	rt2x00_ring_index_inc(ring);
+	beacon = rt2x00_get_data_entry(ring);
+
+	/*
+	 * First we create the beacon.
+	 */
+	skb_push(skb, ring->desc_size);
+	memset(skb->data, 0, ring->desc_size);
+
+	rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data,
+				(struct ieee80211_hdr *)(skb->data +
+							 ring->desc_size),
+				skb->len - ring->desc_size, control);
+
+	length = rt2500usb_get_tx_data_len(rt2x00dev, max_packet, skb);
+
+	usb_fill_bulk_urb(beacon->priv, usb_dev, pipe,
+			  skb->data, length, rt2500usb_beacondone, beacon);
+
+	beacon->skb = skb;
+
+	/*
+	 * Second we need to create the guardian byte.
+	 * We only need a single byte, so lets recycle
+	 * the 'flags' field we are not using for beacons.
+	 */
+	guardian->flags = 0;
+	usb_fill_bulk_urb(guardian->priv, usb_dev, pipe,
+			  &guardian->flags, 1, rt2500usb_beacondone, guardian);
+
+	/*
+	 * Send out the guardian byte.
+	 */
+	usb_submit_urb(guardian->priv, GFP_ATOMIC);
+
+	/*
+	 * Enable beacon generation.
+	 */
+	rt2500usb_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+
+	return 0;
+}
+
+static const struct ieee80211_ops rt2500usb_mac80211_ops = {
+	.tx			= rt2x00mac_tx,
+	.start			= rt2x00mac_start,
+	.stop			= rt2x00mac_stop,
+	.add_interface		= rt2x00mac_add_interface,
+	.remove_interface	= rt2x00mac_remove_interface,
+	.config			= rt2x00mac_config,
+	.config_interface	= rt2x00mac_config_interface,
+	.configure_filter	= rt2500usb_configure_filter,
+	.get_stats		= rt2x00mac_get_stats,
+	.erp_ie_changed		= rt2x00mac_erp_ie_changed,
+	.conf_tx		= rt2x00mac_conf_tx,
+	.get_tx_stats		= rt2x00mac_get_tx_stats,
+	.beacon_update		= rt2500usb_beacon_update,
+};
+
+static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
+	.probe_hw		= rt2500usb_probe_hw,
+	.initialize		= rt2x00usb_initialize,
+	.uninitialize		= rt2x00usb_uninitialize,
+	.set_device_state	= rt2500usb_set_device_state,
+	.link_stats		= rt2500usb_link_stats,
+	.reset_tuner		= rt2500usb_reset_tuner,
+	.link_tuner		= rt2500usb_link_tuner,
+	.write_tx_desc		= rt2500usb_write_tx_desc,
+	.write_tx_data		= rt2x00usb_write_tx_data,
+	.get_tx_data_len	= rt2500usb_get_tx_data_len,
+	.kick_tx_queue		= rt2500usb_kick_tx_queue,
+	.fill_rxdone		= rt2500usb_fill_rxdone,
+	.config_mac_addr	= rt2500usb_config_mac_addr,
+	.config_bssid		= rt2500usb_config_bssid,
+	.config_type		= rt2500usb_config_type,
+	.config_preamble	= rt2500usb_config_preamble,
+	.config			= rt2500usb_config,
+};
+
+static const struct rt2x00_ops rt2500usb_ops = {
+	.name		= DRV_NAME,
+	.rxd_size	= RXD_DESC_SIZE,
+	.txd_size	= TXD_DESC_SIZE,
+	.eeprom_size	= EEPROM_SIZE,
+	.rf_size	= RF_SIZE,
+	.lib		= &rt2500usb_rt2x00_ops,
+	.hw		= &rt2500usb_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+	.debugfs	= &rt2500usb_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * rt2500usb module information.
+ */
+static struct usb_device_id rt2500usb_device_table[] = {
+	/* ASUS */
+	{ USB_DEVICE(0x0b05, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x0b05, 0x1707), USB_DEVICE_DATA(&rt2500usb_ops) },
+	/* Belkin */
+	{ USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x050d, 0x7051), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt2500usb_ops) },
+	/* Cisco Systems */
+	{ USB_DEVICE(0x13b1, 0x000d), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x13b1, 0x0011), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x13b1, 0x001a), USB_DEVICE_DATA(&rt2500usb_ops) },
+	/* Conceptronic */
+	{ USB_DEVICE(0x14b2, 0x3c02), USB_DEVICE_DATA(&rt2500usb_ops) },
+	/* D-LINK */
+	{ USB_DEVICE(0x2001, 0x3c00), USB_DEVICE_DATA(&rt2500usb_ops) },
+	/* Gigabyte */
+	{ USB_DEVICE(0x1044, 0x8001), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x1044, 0x8007), USB_DEVICE_DATA(&rt2500usb_ops) },
+	/* Hercules */
+	{ USB_DEVICE(0x06f8, 0xe000), USB_DEVICE_DATA(&rt2500usb_ops) },
+	/* Melco */
+	{ USB_DEVICE(0x0411, 0x0066), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x0411, 0x0067), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x0411, 0x008b), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x0411, 0x0097), USB_DEVICE_DATA(&rt2500usb_ops) },
+
+	/* MSI */
+	{ USB_DEVICE(0x0db0, 0x6861), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x0db0, 0x6865), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x0db0, 0x6869), USB_DEVICE_DATA(&rt2500usb_ops) },
+	/* Ralink */
+	{ USB_DEVICE(0x148f, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x148f, 0x2570), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ USB_DEVICE(0x148f, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) },
+	/* Siemens */
+	{ USB_DEVICE(0x0681, 0x3c06), USB_DEVICE_DATA(&rt2500usb_ops) },
+	/* SMC */
+	{ USB_DEVICE(0x0707, 0xee13), USB_DEVICE_DATA(&rt2500usb_ops) },
+	/* Spairon */
+	{ USB_DEVICE(0x114b, 0x0110), USB_DEVICE_DATA(&rt2500usb_ops) },
+	/* Trust */
+	{ USB_DEVICE(0x0eb0, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) },
+	/* Zinwell */
+	{ USB_DEVICE(0x5a57, 0x0260), USB_DEVICE_DATA(&rt2500usb_ops) },
+	{ 0, }
+};
+
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT2500 USB Wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Ralink RT2570 USB chipset based cards");
+MODULE_DEVICE_TABLE(usb, rt2500usb_device_table);
+MODULE_LICENSE("GPL");
+
+static struct usb_driver rt2500usb_driver = {
+	.name		= DRV_NAME,
+	.id_table	= rt2500usb_device_table,
+	.probe		= rt2x00usb_probe,
+	.disconnect	= rt2x00usb_disconnect,
+	.suspend	= rt2x00usb_suspend,
+	.resume		= rt2x00usb_resume,
+};
+
+static int __init rt2500usb_init(void)
+{
+	return usb_register(&rt2500usb_driver);
+}
+
+static void __exit rt2500usb_exit(void)
+{
+	usb_deregister(&rt2500usb_driver);
+}
+
+module_init(rt2500usb_init);
+module_exit(rt2500usb_exit);
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h
new file mode 100644
index 0000000..b18d56e
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2500usb.h
@@ -0,0 +1,798 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2500usb
+	Abstract: Data structures and registers for the rt2500usb module.
+	Supported chipsets: RT2570.
+ */
+
+#ifndef RT2500USB_H
+#define RT2500USB_H
+
+/*
+ * RF chip defines.
+ */
+#define RF2522				0x0000
+#define RF2523				0x0001
+#define RF2524				0x0002
+#define RF2525				0x0003
+#define RF2525E				0x0005
+#define RF5222				0x0010
+
+/*
+ * RT2570 version
+ */
+#define RT2570_VERSION_B		2
+#define RT2570_VERSION_C		3
+#define RT2570_VERSION_D		4
+
+/*
+ * Signal information.
+ * Defaul offset is required for RSSI <-> dBm conversion.
+ */
+#define MAX_SIGNAL			100
+#define MAX_RX_SSI			-1
+#define DEFAULT_RSSI_OFFSET		120
+
+/*
+ * Register layout information.
+ */
+#define CSR_REG_BASE			0x0400
+#define CSR_REG_SIZE			0x0100
+#define EEPROM_BASE			0x0000
+#define EEPROM_SIZE			0x006a
+#define BBP_SIZE			0x0060
+#define RF_SIZE				0x0014
+
+/*
+ * Control/Status Registers(CSR).
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * MAC_CSR0: ASIC revision number.
+ */
+#define MAC_CSR0			0x0400
+
+/*
+ * MAC_CSR1: System control.
+ * SOFT_RESET: Software reset, 1: reset, 0: normal.
+ * BBP_RESET: Hardware reset, 1: reset, 0, release.
+ * HOST_READY: Host ready after initialization.
+ */
+#define MAC_CSR1			0x0402
+#define MAC_CSR1_SOFT_RESET		FIELD16(0x00000001)
+#define MAC_CSR1_BBP_RESET		FIELD16(0x00000002)
+#define MAC_CSR1_HOST_READY		FIELD16(0x00000004)
+
+/*
+ * MAC_CSR2: STA MAC register 0.
+ */
+#define MAC_CSR2			0x0404
+#define MAC_CSR2_BYTE0			FIELD16(0x00ff)
+#define MAC_CSR2_BYTE1			FIELD16(0xff00)
+
+/*
+ * MAC_CSR3: STA MAC register 1.
+ */
+#define MAC_CSR3			0x0406
+#define MAC_CSR3_BYTE2			FIELD16(0x00ff)
+#define MAC_CSR3_BYTE3			FIELD16(0xff00)
+
+/*
+ * MAC_CSR4: STA MAC register 2.
+ */
+#define MAC_CSR4			0X0408
+#define MAC_CSR4_BYTE4			FIELD16(0x00ff)
+#define MAC_CSR4_BYTE5			FIELD16(0xff00)
+
+/*
+ * MAC_CSR5: BSSID register 0.
+ */
+#define MAC_CSR5			0x040a
+#define MAC_CSR5_BYTE0			FIELD16(0x00ff)
+#define MAC_CSR5_BYTE1			FIELD16(0xff00)
+
+/*
+ * MAC_CSR6: BSSID register 1.
+ */
+#define MAC_CSR6			0x040c
+#define MAC_CSR6_BYTE2			FIELD16(0x00ff)
+#define MAC_CSR6_BYTE3			FIELD16(0xff00)
+
+/*
+ * MAC_CSR7: BSSID register 2.
+ */
+#define MAC_CSR7			0x040e
+#define MAC_CSR7_BYTE4			FIELD16(0x00ff)
+#define MAC_CSR7_BYTE5			FIELD16(0xff00)
+
+/*
+ * MAC_CSR8: Max frame length.
+ */
+#define MAC_CSR8			0x0410
+#define MAC_CSR8_MAX_FRAME_UNIT		FIELD16(0x0fff)
+
+/*
+ * Misc MAC_CSR registers.
+ * MAC_CSR9: Timer control.
+ * MAC_CSR10: Slot time.
+ * MAC_CSR11: IFS.
+ * MAC_CSR12: EIFS.
+ * MAC_CSR13: Power mode0.
+ * MAC_CSR14: Power mode1.
+ * MAC_CSR15: Power saving transition0
+ * MAC_CSR16: Power saving transition1
+ */
+#define MAC_CSR9			0x0412
+#define MAC_CSR10			0x0414
+#define MAC_CSR11			0x0416
+#define MAC_CSR12			0x0418
+#define MAC_CSR13			0x041a
+#define MAC_CSR14			0x041c
+#define MAC_CSR15			0x041e
+#define MAC_CSR16			0x0420
+
+/*
+ * MAC_CSR17: Manual power control / status register.
+ * Allowed state: 0 deep_sleep, 1: sleep, 2: standby, 3: awake.
+ * SET_STATE: Set state. Write 1 to trigger, self cleared.
+ * BBP_DESIRE_STATE: BBP desired state.
+ * RF_DESIRE_STATE: RF desired state.
+ * BBP_CURRENT_STATE: BBP current state.
+ * RF_CURRENT_STATE: RF current state.
+ * PUT_TO_SLEEP: Put to sleep. Write 1 to trigger, self cleared.
+ */
+#define MAC_CSR17			0x0422
+#define MAC_CSR17_SET_STATE		FIELD16(0x0001)
+#define MAC_CSR17_BBP_DESIRE_STATE	FIELD16(0x0006)
+#define MAC_CSR17_RF_DESIRE_STATE	FIELD16(0x0018)
+#define MAC_CSR17_BBP_CURR_STATE	FIELD16(0x0060)
+#define MAC_CSR17_RF_CURR_STATE		FIELD16(0x0180)
+#define MAC_CSR17_PUT_TO_SLEEP		FIELD16(0x0200)
+
+/*
+ * MAC_CSR18: Wakeup timer register.
+ * DELAY_AFTER_BEACON: Delay after Tbcn expired in units of 1/16 TU.
+ * BEACONS_BEFORE_WAKEUP: Number of beacon before wakeup.
+ * AUTO_WAKE: Enable auto wakeup / sleep mechanism.
+ */
+#define MAC_CSR18			0x0424
+#define MAC_CSR18_DELAY_AFTER_BEACON	FIELD16(0x00ff)
+#define MAC_CSR18_BEACONS_BEFORE_WAKEUP	FIELD16(0x7f00)
+#define MAC_CSR18_AUTO_WAKE		FIELD16(0x8000)
+
+/*
+ * MAC_CSR19: GPIO control register.
+ */
+#define MAC_CSR19			0x0426
+
+/*
+ * MAC_CSR20: LED control register.
+ * ACTIVITY: 0: idle, 1: active.
+ * LINK: 0: linkoff, 1: linkup.
+ * ACTIVITY_POLARITY: 0: active low, 1: active high.
+ */
+#define MAC_CSR20			0x0428
+#define MAC_CSR20_ACTIVITY		FIELD16(0x0001)
+#define MAC_CSR20_LINK			FIELD16(0x0002)
+#define MAC_CSR20_ACTIVITY_POLARITY	FIELD16(0x0004)
+
+/*
+ * MAC_CSR21: LED control register.
+ * ON_PERIOD: On period, default 70ms.
+ * OFF_PERIOD: Off period, default 30ms.
+ */
+#define MAC_CSR21			0x042a
+#define MAC_CSR21_ON_PERIOD		FIELD16(0x00ff)
+#define MAC_CSR21_OFF_PERIOD		FIELD16(0xff00)
+
+/*
+ * Collision window control register.
+ */
+#define MAC_CSR22			0x042c
+
+/*
+ * Transmit related CSRs.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * TXRX_CSR0: Security control register.
+ */
+#define TXRX_CSR0			0x0440
+#define TXRX_CSR0_ALGORITHM		FIELD16(0x0007)
+#define TXRX_CSR0_IV_OFFSET		FIELD16(0x01f8)
+#define TXRX_CSR0_KEY_ID		FIELD16(0x1e00)
+
+/*
+ * TXRX_CSR1: TX configuration.
+ * ACK_TIMEOUT: ACK Timeout in unit of 1-us.
+ * TSF_OFFSET: TSF offset in MAC header.
+ * AUTO_SEQUENCE: Let ASIC control frame sequence number.
+ */
+#define TXRX_CSR1			0x0442
+#define TXRX_CSR1_ACK_TIMEOUT		FIELD16(0x00ff)
+#define TXRX_CSR1_TSF_OFFSET		FIELD16(0x7f00)
+#define TXRX_CSR1_AUTO_SEQUENCE		FIELD16(0x8000)
+
+/*
+ * TXRX_CSR2: RX control.
+ * DISABLE_RX: Disable rx engine.
+ * DROP_CRC: Drop crc error.
+ * DROP_PHYSICAL: Drop physical error.
+ * DROP_CONTROL: Drop control frame.
+ * DROP_NOT_TO_ME: Drop not to me unicast frame.
+ * DROP_TODS: Drop frame tods bit is true.
+ * DROP_VERSION_ERROR: Drop version error frame.
+ * DROP_MCAST: Drop multicast frames.
+ * DROP_BCAST: Drop broadcast frames.
+ */
+#define TXRX_CSR2			0x0444
+#define	TXRX_CSR2_DISABLE_RX		FIELD16(0x0001)
+#define TXRX_CSR2_DROP_CRC		FIELD16(0x0002)
+#define TXRX_CSR2_DROP_PHYSICAL		FIELD16(0x0004)
+#define TXRX_CSR2_DROP_CONTROL		FIELD16(0x0008)
+#define TXRX_CSR2_DROP_NOT_TO_ME	FIELD16(0x0010)
+#define TXRX_CSR2_DROP_TODS		FIELD16(0x0020)
+#define TXRX_CSR2_DROP_VERSION_ERROR	FIELD16(0x0040)
+#define TXRX_CSR2_DROP_MULTICAST	FIELD16(0x0200)
+#define TXRX_CSR2_DROP_BROADCAST	FIELD16(0x0400)
+
+/*
+ * RX BBP ID registers
+ * TXRX_CSR3: CCK RX BBP ID.
+ * TXRX_CSR4: OFDM RX BBP ID.
+ */
+#define TXRX_CSR3			0x0446
+#define TXRX_CSR4			0x0448
+
+/*
+ * TXRX_CSR5: CCK TX BBP ID0.
+ */
+#define TXRX_CSR5			0x044a
+#define TXRX_CSR5_BBP_ID0		FIELD16(0x007f)
+#define TXRX_CSR5_BBP_ID0_VALID		FIELD16(0x0080)
+#define TXRX_CSR5_BBP_ID1		FIELD16(0x7f00)
+#define TXRX_CSR5_BBP_ID1_VALID		FIELD16(0x8000)
+
+/*
+ * TXRX_CSR6: CCK TX BBP ID1.
+ */
+#define TXRX_CSR6			0x044c
+#define TXRX_CSR6_BBP_ID0		FIELD16(0x007f)
+#define TXRX_CSR6_BBP_ID0_VALID		FIELD16(0x0080)
+#define TXRX_CSR6_BBP_ID1		FIELD16(0x7f00)
+#define TXRX_CSR6_BBP_ID1_VALID		FIELD16(0x8000)
+
+/*
+ * TXRX_CSR7: OFDM TX BBP ID0.
+ */
+#define TXRX_CSR7			0x044e
+#define TXRX_CSR7_BBP_ID0		FIELD16(0x007f)
+#define TXRX_CSR7_BBP_ID0_VALID		FIELD16(0x0080)
+#define TXRX_CSR7_BBP_ID1		FIELD16(0x7f00)
+#define TXRX_CSR7_BBP_ID1_VALID		FIELD16(0x8000)
+
+/*
+ * TXRX_CSR5: OFDM TX BBP ID1.
+ */
+#define TXRX_CSR8			0x0450
+#define TXRX_CSR8_BBP_ID0		FIELD16(0x007f)
+#define TXRX_CSR8_BBP_ID0_VALID		FIELD16(0x0080)
+#define TXRX_CSR8_BBP_ID1		FIELD16(0x7f00)
+#define TXRX_CSR8_BBP_ID1_VALID		FIELD16(0x8000)
+
+/*
+ * TXRX_CSR9: TX ACK time-out.
+ */
+#define TXRX_CSR9			0x0452
+
+/*
+ * TXRX_CSR10: Auto responder control.
+ */
+#define TXRX_CSR10			0x0454
+#define TXRX_CSR10_AUTORESPOND_PREAMBLE FIELD16(0x0004)
+
+/*
+ * TXRX_CSR11: Auto responder basic rate.
+ */
+#define TXRX_CSR11			0x0456
+
+/*
+ * ACK/CTS time registers.
+ */
+#define TXRX_CSR12			0x0458
+#define TXRX_CSR13			0x045a
+#define TXRX_CSR14			0x045c
+#define TXRX_CSR15			0x045e
+#define TXRX_CSR16			0x0460
+#define TXRX_CSR17			0x0462
+
+/*
+ * TXRX_CSR18: Synchronization control register.
+ */
+#define TXRX_CSR18			0x0464
+#define TXRX_CSR18_OFFSET		FIELD16(0x000f)
+#define TXRX_CSR18_INTERVAL		FIELD16(0xfff0)
+
+/*
+ * TXRX_CSR19: Synchronization control register.
+ * TSF_COUNT: Enable TSF auto counting.
+ * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
+ * TBCN: Enable Tbcn with reload value.
+ * BEACON_GEN: Enable beacon generator.
+ */
+#define TXRX_CSR19			0x0466
+#define TXRX_CSR19_TSF_COUNT		FIELD16(0x0001)
+#define TXRX_CSR19_TSF_SYNC		FIELD16(0x0006)
+#define TXRX_CSR19_TBCN			FIELD16(0x0008)
+#define TXRX_CSR19_BEACON_GEN		FIELD16(0x0010)
+
+/*
+ * TXRX_CSR20: Tx BEACON offset time control register.
+ * OFFSET: In units of usec.
+ * BCN_EXPECT_WINDOW: Default: 2^CWmin
+ */
+#define TXRX_CSR20			0x0468
+#define TXRX_CSR20_OFFSET		FIELD16(0x1fff)
+#define TXRX_CSR20_BCN_EXPECT_WINDOW	FIELD16(0xe000)
+
+/*
+ * TXRX_CSR21
+ */
+#define TXRX_CSR21			0x046a
+
+/*
+ * Encryption related CSRs.
+ *
+ */
+
+/*
+ * SEC_CSR0-SEC_CSR7: Shared key 0, word 0-7
+ */
+#define SEC_CSR0			0x0480
+#define SEC_CSR1			0x0482
+#define SEC_CSR2			0x0484
+#define SEC_CSR3			0x0486
+#define SEC_CSR4			0x0488
+#define SEC_CSR5			0x048a
+#define SEC_CSR6			0x048c
+#define SEC_CSR7			0x048e
+
+/*
+ * SEC_CSR8-SEC_CSR15: Shared key 1, word 0-7
+ */
+#define SEC_CSR8			0x0490
+#define SEC_CSR9			0x0492
+#define SEC_CSR10			0x0494
+#define SEC_CSR11			0x0496
+#define SEC_CSR12			0x0498
+#define SEC_CSR13			0x049a
+#define SEC_CSR14			0x049c
+#define SEC_CSR15			0x049e
+
+/*
+ * SEC_CSR16-SEC_CSR23: Shared key 2, word 0-7
+ */
+#define SEC_CSR16			0x04a0
+#define SEC_CSR17			0x04a2
+#define SEC_CSR18			0X04A4
+#define SEC_CSR19			0x04a6
+#define SEC_CSR20			0x04a8
+#define SEC_CSR21			0x04aa
+#define SEC_CSR22			0x04ac
+#define SEC_CSR23			0x04ae
+
+/*
+ * SEC_CSR24-SEC_CSR31: Shared key 3, word 0-7
+ */
+#define SEC_CSR24			0x04b0
+#define SEC_CSR25			0x04b2
+#define SEC_CSR26			0x04b4
+#define SEC_CSR27			0x04b6
+#define SEC_CSR28			0x04b8
+#define SEC_CSR29			0x04ba
+#define SEC_CSR30			0x04bc
+#define SEC_CSR31			0x04be
+
+/*
+ * PHY control registers.
+ */
+
+/*
+ * PHY_CSR0: RF switching timing control.
+ */
+#define PHY_CSR0			0x04c0
+
+/*
+ * PHY_CSR1: TX PA configuration.
+ */
+#define PHY_CSR1			0x04c2
+
+/*
+ * MAC configuration registers.
+ * PHY_CSR2: TX MAC configuration.
+ * PHY_CSR3: RX MAC configuration.
+ */
+#define PHY_CSR2			0x04c4
+#define PHY_CSR3			0x04c6
+
+/*
+ * PHY_CSR4: Interface configuration.
+ */
+#define PHY_CSR4			0x04c8
+#define PHY_CSR4_LOW_RF_LE		FIELD16(0x0001)
+
+/*
+ * BBP pre-TX registers.
+ * PHY_CSR5: BBP pre-TX CCK.
+ */
+#define PHY_CSR5			0x04ca
+#define PHY_CSR5_CCK			FIELD16(0x0003)
+#define PHY_CSR5_CCK_FLIP		FIELD16(0x0004)
+
+/*
+ * BBP pre-TX registers.
+ * PHY_CSR6: BBP pre-TX OFDM.
+ */
+#define PHY_CSR6			0x04cc
+#define PHY_CSR6_OFDM			FIELD16(0x0003)
+#define PHY_CSR6_OFDM_FLIP		FIELD16(0x0004)
+
+/*
+ * PHY_CSR7: BBP access register 0.
+ * BBP_DATA: BBP data.
+ * BBP_REG_ID: BBP register ID.
+ * BBP_READ_CONTROL: 0: write, 1: read.
+ */
+#define PHY_CSR7			0x04ce
+#define PHY_CSR7_DATA			FIELD16(0x00ff)
+#define PHY_CSR7_REG_ID			FIELD16(0x7f00)
+#define PHY_CSR7_READ_CONTROL		FIELD16(0x8000)
+
+/*
+ * PHY_CSR8: BBP access register 1.
+ * BBP_BUSY: ASIC is busy execute BBP programming.
+ */
+#define PHY_CSR8			0x04d0
+#define PHY_CSR8_BUSY			FIELD16(0x0001)
+
+/*
+ * PHY_CSR9: RF access register.
+ * RF_VALUE: Register value + id to program into rf/if.
+ */
+#define PHY_CSR9			0x04d2
+#define PHY_CSR9_RF_VALUE		FIELD16(0xffff)
+
+/*
+ * PHY_CSR10: RF access register.
+ * RF_VALUE: Register value + id to program into rf/if.
+ * RF_NUMBER_OF_BITS: Number of bits used in value (i:20, rfmd:22).
+ * RF_IF_SELECT: Chip to program: 0: rf, 1: if.
+ * RF_PLL_LD: Rf pll_ld status.
+ * RF_BUSY: 1: asic is busy execute rf programming.
+ */
+#define PHY_CSR10			0x04d4
+#define PHY_CSR10_RF_VALUE		FIELD16(0x00ff)
+#define PHY_CSR10_RF_NUMBER_OF_BITS	FIELD16(0x1f00)
+#define PHY_CSR10_RF_IF_SELECT		FIELD16(0x2000)
+#define PHY_CSR10_RF_PLL_LD		FIELD16(0x4000)
+#define PHY_CSR10_RF_BUSY		FIELD16(0x8000)
+
+/*
+ * STA_CSR0: FCS error count.
+ * FCS_ERROR: FCS error count, cleared when read.
+ */
+#define STA_CSR0			0x04e0
+#define STA_CSR0_FCS_ERROR		FIELD16(0xffff)
+
+/*
+ * STA_CSR1: PLCP error count.
+ */
+#define STA_CSR1			0x04e2
+
+/*
+ * STA_CSR2: LONG error count.
+ */
+#define STA_CSR2			0x04e4
+
+/*
+ * STA_CSR3: CCA false alarm.
+ * FALSE_CCA_ERROR: False CCA error count, cleared when read.
+ */
+#define STA_CSR3			0x04e6
+#define STA_CSR3_FALSE_CCA_ERROR	FIELD16(0xffff)
+
+/*
+ * STA_CSR4: RX FIFO overflow.
+ */
+#define STA_CSR4			0x04e8
+
+/*
+ * STA_CSR5: Beacon sent counter.
+ */
+#define STA_CSR5			0x04ea
+
+/*
+ *  Statistics registers
+ */
+#define STA_CSR6			0x04ec
+#define STA_CSR7			0x04ee
+#define STA_CSR8			0x04f0
+#define STA_CSR9			0x04f2
+#define STA_CSR10			0x04f4
+
+/*
+ * BBP registers.
+ * The wordsize of the BBP is 8 bits.
+ */
+
+/*
+ * R2: TX antenna control
+ */
+#define BBP_R2_TX_ANTENNA		FIELD8(0x03)
+#define BBP_R2_TX_IQ_FLIP		FIELD8(0x04)
+
+/*
+ * R14: RX antenna control
+ */
+#define BBP_R14_RX_ANTENNA		FIELD8(0x03)
+#define BBP_R14_RX_IQ_FLIP		FIELD8(0x04)
+
+/*
+ * RF registers.
+ */
+
+/*
+ * RF 1
+ */
+#define RF1_TUNER			FIELD32(0x00020000)
+
+/*
+ * RF 3
+ */
+#define RF3_TUNER			FIELD32(0x00000100)
+#define RF3_TXPOWER			FIELD32(0x00003e00)
+
+/*
+ * EEPROM contents.
+ */
+
+/*
+ * HW MAC address.
+ */
+#define EEPROM_MAC_ADDR_0		0x0002
+#define EEPROM_MAC_ADDR_BYTE0		FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE1		FIELD16(0xff00)
+#define EEPROM_MAC_ADDR1		0x0003
+#define EEPROM_MAC_ADDR_BYTE2		FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE3		FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_2		0x0004
+#define EEPROM_MAC_ADDR_BYTE4		FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE5		FIELD16(0xff00)
+
+/*
+ * EEPROM antenna.
+ * ANTENNA_NUM: Number of antenna's.
+ * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * LED_MODE: 0: default, 1: TX/RX activity, 2: Single (ignore link), 3: rsvd.
+ * DYN_TXAGC: Dynamic TX AGC control.
+ * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
+ * RF_TYPE: Rf_type of this adapter.
+ */
+#define EEPROM_ANTENNA			0x000b
+#define EEPROM_ANTENNA_NUM		FIELD16(0x0003)
+#define EEPROM_ANTENNA_TX_DEFAULT	FIELD16(0x000c)
+#define EEPROM_ANTENNA_RX_DEFAULT	FIELD16(0x0030)
+#define EEPROM_ANTENNA_LED_MODE		FIELD16(0x01c0)
+#define EEPROM_ANTENNA_DYN_TXAGC	FIELD16(0x0200)
+#define EEPROM_ANTENNA_HARDWARE_RADIO	FIELD16(0x0400)
+#define EEPROM_ANTENNA_RF_TYPE		FIELD16(0xf800)
+
+/*
+ * EEPROM NIC config.
+ * CARDBUS_ACCEL: 0: enable, 1: disable.
+ * DYN_BBP_TUNE: 0: enable, 1: disable.
+ * CCK_TX_POWER: CCK TX power compensation.
+ */
+#define EEPROM_NIC			0x000c
+#define EEPROM_NIC_CARDBUS_ACCEL	FIELD16(0x0001)
+#define EEPROM_NIC_DYN_BBP_TUNE		FIELD16(0x0002)
+#define EEPROM_NIC_CCK_TX_POWER		FIELD16(0x000c)
+
+/*
+ * EEPROM geography.
+ * GEO: Default geography setting for device.
+ */
+#define EEPROM_GEOGRAPHY		0x000d
+#define EEPROM_GEOGRAPHY_GEO		FIELD16(0x0f00)
+
+/*
+ * EEPROM BBP.
+ */
+#define EEPROM_BBP_START		0x000e
+#define EEPROM_BBP_SIZE			16
+#define EEPROM_BBP_VALUE		FIELD16(0x00ff)
+#define EEPROM_BBP_REG_ID		FIELD16(0xff00)
+
+/*
+ * EEPROM TXPOWER
+ */
+#define EEPROM_TXPOWER_START		0x001e
+#define EEPROM_TXPOWER_SIZE		7
+#define EEPROM_TXPOWER_1		FIELD16(0x00ff)
+#define EEPROM_TXPOWER_2		FIELD16(0xff00)
+
+/*
+ * EEPROM Tuning threshold
+ */
+#define EEPROM_BBPTUNE			0x0030
+#define EEPROM_BBPTUNE_THRESHOLD	FIELD16(0x00ff)
+
+/*
+ * EEPROM BBP R24 Tuning.
+ */
+#define EEPROM_BBPTUNE_R24		0x0031
+#define EEPROM_BBPTUNE_R24_LOW		FIELD16(0x00ff)
+#define EEPROM_BBPTUNE_R24_HIGH		FIELD16(0xff00)
+
+/*
+ * EEPROM BBP R25 Tuning.
+ */
+#define EEPROM_BBPTUNE_R25		0x0032
+#define EEPROM_BBPTUNE_R25_LOW		FIELD16(0x00ff)
+#define EEPROM_BBPTUNE_R25_HIGH		FIELD16(0xff00)
+
+/*
+ * EEPROM BBP R24 Tuning.
+ */
+#define EEPROM_BBPTUNE_R61		0x0033
+#define EEPROM_BBPTUNE_R61_LOW		FIELD16(0x00ff)
+#define EEPROM_BBPTUNE_R61_HIGH		FIELD16(0xff00)
+
+/*
+ * EEPROM BBP VGC Tuning.
+ */
+#define EEPROM_BBPTUNE_VGC		0x0034
+#define EEPROM_BBPTUNE_VGCUPPER		FIELD16(0x00ff)
+
+/*
+ * EEPROM BBP R17 Tuning.
+ */
+#define EEPROM_BBPTUNE_R17		0x0035
+#define EEPROM_BBPTUNE_R17_LOW		FIELD16(0x00ff)
+#define EEPROM_BBPTUNE_R17_HIGH		FIELD16(0xff00)
+
+/*
+ * RSSI <-> dBm offset calibration
+ */
+#define EEPROM_CALIBRATE_OFFSET		0x0036
+#define EEPROM_CALIBRATE_OFFSET_RSSI	FIELD16(0x00ff)
+
+/*
+ * DMA descriptor defines.
+ */
+#define TXD_DESC_SIZE			( 5 * sizeof(struct data_desc) )
+#define RXD_DESC_SIZE			( 4 * sizeof(struct data_desc) )
+
+/*
+ * TX descriptor format for TX, PRIO, ATIM and Beacon Ring.
+ */
+
+/*
+ * Word0
+ */
+#define TXD_W0_PACKET_ID		FIELD32(0x0000000f)
+#define TXD_W0_RETRY_LIMIT		FIELD32(0x000000f0)
+#define TXD_W0_MORE_FRAG		FIELD32(0x00000100)
+#define TXD_W0_ACK			FIELD32(0x00000200)
+#define TXD_W0_TIMESTAMP		FIELD32(0x00000400)
+#define TXD_W0_OFDM			FIELD32(0x00000800)
+#define TXD_W0_NEW_SEQ			FIELD32(0x00001000)
+#define TXD_W0_IFS			FIELD32(0x00006000)
+#define TXD_W0_DATABYTE_COUNT		FIELD32(0x0fff0000)
+#define TXD_W0_CIPHER			FIELD32(0x20000000)
+#define TXD_W0_KEY_ID			FIELD32(0xc0000000)
+
+/*
+ * Word1
+ */
+#define TXD_W1_IV_OFFSET		FIELD32(0x0000003f)
+#define TXD_W1_AIFS			FIELD32(0x000000c0)
+#define TXD_W1_CWMIN			FIELD32(0x00000f00)
+#define TXD_W1_CWMAX			FIELD32(0x0000f000)
+
+/*
+ * Word2: PLCP information
+ */
+#define TXD_W2_PLCP_SIGNAL		FIELD32(0x000000ff)
+#define TXD_W2_PLCP_SERVICE		FIELD32(0x0000ff00)
+#define TXD_W2_PLCP_LENGTH_LOW		FIELD32(0x00ff0000)
+#define TXD_W2_PLCP_LENGTH_HIGH		FIELD32(0xff000000)
+
+/*
+ * Word3
+ */
+#define TXD_W3_IV			FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define TXD_W4_EIV			FIELD32(0xffffffff)
+
+/*
+ * RX descriptor format for RX Ring.
+ */
+
+/*
+ * Word0
+ */
+#define RXD_W0_UNICAST_TO_ME		FIELD32(0x00000002)
+#define RXD_W0_MULTICAST		FIELD32(0x00000004)
+#define RXD_W0_BROADCAST		FIELD32(0x00000008)
+#define RXD_W0_MY_BSS			FIELD32(0x00000010)
+#define RXD_W0_CRC_ERROR		FIELD32(0x00000020)
+#define RXD_W0_OFDM			FIELD32(0x00000040)
+#define RXD_W0_PHYSICAL_ERROR		FIELD32(0x00000080)
+#define RXD_W0_CIPHER			FIELD32(0x00000100)
+#define RXD_W0_CIPHER_ERROR		FIELD32(0x00000200)
+#define RXD_W0_DATABYTE_COUNT		FIELD32(0x0fff0000)
+
+/*
+ * Word1
+ */
+#define RXD_W1_RSSI			FIELD32(0x000000ff)
+#define RXD_W1_SIGNAL			FIELD32(0x0000ff00)
+
+/*
+ * Word2
+ */
+#define RXD_W2_IV			FIELD32(0xffffffff)
+
+/*
+ * Word3
+ */
+#define RXD_W3_EIV			FIELD32(0xffffffff)
+
+/*
+ * Macro's for converting txpower from EEPROM to dscape value
+ * and from dscape value to register value.
+ */
+#define MIN_TXPOWER	0
+#define MAX_TXPOWER	31
+#define DEFAULT_TXPOWER	24
+
+#define TXPOWER_FROM_DEV(__txpower)		\
+({						\
+	((__txpower) > MAX_TXPOWER) ?		\
+		DEFAULT_TXPOWER : (__txpower);	\
+})
+
+#define TXPOWER_TO_DEV(__txpower)			\
+({							\
+	((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER :	\
+	(((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER :	\
+	(__txpower));					\
+})
+
+#endif /* RT2500USB_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
new file mode 100644
index 0000000..9845e58
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -0,0 +1,838 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2x00
+	Abstract: rt2x00 global information.
+ */
+
+#ifndef RT2X00_H
+#define RT2X00_H
+
+#include <linux/bitops.h>
+#include <linux/prefetch.h>
+#include <linux/skbuff.h>
+#include <linux/workqueue.h>
+#include <linux/firmware.h>
+
+#include <net/mac80211.h>
+
+#include "rt2x00debug.h"
+#include "rt2x00reg.h"
+#include "rt2x00ring.h"
+
+/*
+ * Module information.
+ * DRV_NAME should be set within the individual module source files.
+ */
+#define DRV_VERSION	"2.0.10"
+#define DRV_PROJECT	"http://rt2x00.serialmonkey.com"
+
+/*
+ * Debug definitions.
+ * Debug output has to be enabled during compile time.
+ */
+#define DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, __args...)	\
+	printk(__kernlvl "%s -> %s: %s - " __msg,			\
+	       wiphy_name((__dev)->hw->wiphy), __FUNCTION__, __lvl, ##__args)
+
+#define DEBUG_PRINTK_PROBE(__kernlvl, __lvl, __msg, __args...)	\
+	printk(__kernlvl "%s -> %s: %s - " __msg,		\
+	       DRV_NAME, __FUNCTION__, __lvl, ##__args)
+
+#ifdef CONFIG_RT2X00_DEBUG
+#define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...)	\
+	DEBUG_PRINTK_MSG(__dev, __kernlvl, __lvl, __msg, ##__args);
+#else
+#define DEBUG_PRINTK(__dev, __kernlvl, __lvl, __msg, __args...)	\
+	do { } while (0)
+#endif /* CONFIG_RT2X00_DEBUG */
+
+/*
+ * Various debug levels.
+ * The debug levels PANIC and ERROR both indicate serious problems,
+ * for this reason they should never be ignored.
+ * The special ERROR_PROBE message is for messages that are generated
+ * when the rt2x00_dev is not yet initialized.
+ */
+#define PANIC(__dev, __msg, __args...) \
+	DEBUG_PRINTK_MSG(__dev, KERN_CRIT, "Panic", __msg, ##__args)
+#define ERROR(__dev, __msg, __args...)	\
+	DEBUG_PRINTK_MSG(__dev, KERN_ERR, "Error", __msg, ##__args)
+#define ERROR_PROBE(__msg, __args...) \
+	DEBUG_PRINTK_PROBE(KERN_ERR, "Error", __msg, ##__args)
+#define WARNING(__dev, __msg, __args...) \
+	DEBUG_PRINTK(__dev, KERN_WARNING, "Warning", __msg, ##__args)
+#define NOTICE(__dev, __msg, __args...) \
+	DEBUG_PRINTK(__dev, KERN_NOTICE, "Notice", __msg, ##__args)
+#define INFO(__dev, __msg, __args...) \
+	DEBUG_PRINTK(__dev, KERN_INFO, "Info", __msg, ##__args)
+#define DEBUG(__dev, __msg, __args...) \
+	DEBUG_PRINTK(__dev, KERN_DEBUG, "Debug", __msg, ##__args)
+#define EEPROM(__dev, __msg, __args...) \
+	DEBUG_PRINTK(__dev, KERN_DEBUG, "EEPROM recovery", __msg, ##__args)
+
+/*
+ * Ring sizes.
+ * Ralink PCI devices demand the Frame size to be a multiple of 128 bytes.
+ * DATA_FRAME_SIZE is used for TX, RX, ATIM and PRIO rings.
+ * MGMT_FRAME_SIZE is used for the BEACON ring.
+ */
+#define DATA_FRAME_SIZE	2432
+#define MGMT_FRAME_SIZE	256
+
+/*
+ * Number of entries in a packet ring.
+ * PCI devices only need 1 Beacon entry,
+ * but USB devices require a second because they
+ * have to send a Guardian byte first.
+ */
+#define RX_ENTRIES	12
+#define TX_ENTRIES	12
+#define ATIM_ENTRIES	1
+#define BEACON_ENTRIES	2
+
+/*
+ * Standard timing and size defines.
+ * These values should follow the ieee80211 specifications.
+ */
+#define ACK_SIZE		14
+#define IEEE80211_HEADER	24
+#define PLCP			48
+#define BEACON			100
+#define PREAMBLE		144
+#define SHORT_PREAMBLE		72
+#define SLOT_TIME		20
+#define SHORT_SLOT_TIME		9
+#define SIFS			10
+#define PIFS			( SIFS + SLOT_TIME )
+#define SHORT_PIFS		( SIFS + SHORT_SLOT_TIME )
+#define DIFS			( PIFS + SLOT_TIME )
+#define SHORT_DIFS		( SHORT_PIFS + SHORT_SLOT_TIME )
+#define EIFS			( SIFS + (8 * (IEEE80211_HEADER + ACK_SIZE)) )
+
+/*
+ * IEEE802.11 header defines
+ */
+static inline int is_rts_frame(u16 fc)
+{
+	return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+		  ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_RTS));
+}
+
+static inline int is_cts_frame(u16 fc)
+{
+	return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) &&
+		  ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_CTS));
+}
+
+static inline int is_probe_resp(u16 fc)
+{
+	return !!(((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) &&
+		  ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP));
+}
+
+/*
+ * Chipset identification
+ * The chipset on the device is composed of a RT and RF chip.
+ * The chipset combination is important for determining device capabilities.
+ */
+struct rt2x00_chip {
+	u16 rt;
+#define RT2460		0x0101
+#define RT2560		0x0201
+#define RT2570		0x1201
+#define RT2561s		0x0301	/* Turbo */
+#define RT2561		0x0302
+#define RT2661		0x0401
+#define RT2571		0x1300
+
+	u16 rf;
+	u32 rev;
+};
+
+/*
+ * RF register values that belong to a particular channel.
+ */
+struct rf_channel {
+	int channel;
+	u32 rf1;
+	u32 rf2;
+	u32 rf3;
+	u32 rf4;
+};
+
+/*
+ * To optimize the quality of the link we need to store
+ * the quality of received frames and periodically
+ * optimize the link.
+ */
+struct link {
+	/*
+	 * Link tuner counter
+	 * The number of times the link has been tuned
+	 * since the radio has been switched on.
+	 */
+	u32 count;
+
+	/*
+	 * Statistics required for Link tuning.
+	 * For the average RSSI value we use the "Walking average" approach.
+	 * When adding RSSI to the average value the following calculation
+	 * is needed:
+	 *
+	 *        avg_rssi = ((avg_rssi * 7) + rssi) / 8;
+	 *
+	 * The advantage of this approach is that we only need 1 variable
+	 * to store the average in (No need for a count and a total).
+	 * But more importantly, normal average values will over time
+	 * move less and less towards newly added values this results
+	 * that with link tuning, the device can have a very good RSSI
+	 * for a few minutes but when the device is moved away from the AP
+	 * the average will not decrease fast enough to compensate.
+	 * The walking average compensates this and will move towards
+	 * the new values correctly allowing a effective link tuning.
+	 */
+	int avg_rssi;
+	int vgc_level;
+	int false_cca;
+
+	/*
+	 * Statistics required for Signal quality calculation.
+	 * For calculating the Signal quality we have to determine
+	 * the total number of success and failed RX and TX frames.
+	 * After that we also use the average RSSI value to help
+	 * determining the signal quality.
+	 * For the calculation we will use the following algorithm:
+	 *
+	 *         rssi_percentage = (avg_rssi * 100) / rssi_offset
+	 *         rx_percentage = (rx_success * 100) / rx_total
+	 *         tx_percentage = (tx_success * 100) / tx_total
+	 *         avg_signal = ((WEIGHT_RSSI * avg_rssi) +
+	 *                       (WEIGHT_TX * tx_percentage) +
+	 *                       (WEIGHT_RX * rx_percentage)) / 100
+	 *
+	 * This value should then be checked to not be greated then 100.
+	 */
+	int rx_percentage;
+	int rx_success;
+	int rx_failed;
+	int tx_percentage;
+	int tx_success;
+	int tx_failed;
+#define WEIGHT_RSSI	20
+#define WEIGHT_RX	40
+#define WEIGHT_TX	40
+
+	/*
+	 * Work structure for scheduling periodic link tuning.
+	 */
+	struct delayed_work work;
+};
+
+/*
+ * Clear all counters inside the link structure.
+ * This can be easiest achieved by memsetting everything
+ * except for the work structure at the end.
+ */
+static inline void rt2x00_clear_link(struct link *link)
+{
+	memset(link, 0x00, sizeof(*link) - sizeof(link->work));
+	link->rx_percentage = 50;
+	link->tx_percentage = 50;
+}
+
+/*
+ * Update the rssi using the walking average approach.
+ */
+static inline void rt2x00_update_link_rssi(struct link *link, int rssi)
+{
+	if (!link->avg_rssi)
+		link->avg_rssi = rssi;
+	else
+		link->avg_rssi = ((link->avg_rssi * 7) + rssi) / 8;
+}
+
+/*
+ * When the avg_rssi is unset or no frames  have been received),
+ * we need to return the default value which needs to be less
+ * than -80 so the device will select the maximum sensitivity.
+ */
+static inline int rt2x00_get_link_rssi(struct link *link)
+{
+	return (link->avg_rssi && link->rx_success) ? link->avg_rssi : -128;
+}
+
+/*
+ * Interface structure
+ * Configuration details about the current interface.
+ */
+struct interface {
+	/*
+	 * Interface identification. The value is assigned
+	 * to us by the 80211 stack, and is used to request
+	 * new beacons.
+	 */
+	int id;
+
+	/*
+	 * Current working type (IEEE80211_IF_TYPE_*).
+	 * When set to INVALID_INTERFACE, no interface is configured.
+	 */
+	int type;
+#define INVALID_INTERFACE	IEEE80211_IF_TYPE_INVALID
+
+	/*
+	 * MAC of the device.
+	 */
+	u8 mac[ETH_ALEN];
+
+	/*
+	 * BBSID of the AP to associate with.
+	 */
+	u8 bssid[ETH_ALEN];
+
+	/*
+	 * Store the packet filter mode for the current interface.
+	 */
+	unsigned int filter;
+};
+
+static inline int is_interface_present(struct interface *intf)
+{
+	return !!intf->id;
+}
+
+static inline int is_interface_type(struct interface *intf, int type)
+{
+	return intf->type == type;
+}
+
+/*
+ * Details about the supported modes, rates and channels
+ * of a particular chipset. This is used by rt2x00lib
+ * to build the ieee80211_hw_mode array for mac80211.
+ */
+struct hw_mode_spec {
+	/*
+	 * Number of modes, rates and channels.
+	 */
+	int num_modes;
+	int num_rates;
+	int num_channels;
+
+	/*
+	 * txpower values.
+	 */
+	const u8 *tx_power_a;
+	const u8 *tx_power_bg;
+	u8 tx_power_default;
+
+	/*
+	 * Device/chipset specific value.
+	 */
+	const struct rf_channel *channels;
+};
+
+/*
+ * Configuration structure wrapper around the
+ * mac80211 configuration structure.
+ * When mac80211 configures the driver, rt2x00lib
+ * can precalculate values which are equal for all
+ * rt2x00 drivers. Those values can be stored in here.
+ */
+struct rt2x00lib_conf {
+	struct ieee80211_conf *conf;
+	struct rf_channel rf;
+
+	int phymode;
+
+	int basic_rates;
+	int slot_time;
+
+	short sifs;
+	short pifs;
+	short difs;
+	short eifs;
+};
+
+/*
+ * rt2x00lib callback functions.
+ */
+struct rt2x00lib_ops {
+	/*
+	 * Interrupt handlers.
+	 */
+	irq_handler_t irq_handler;
+
+	/*
+	 * Device init handlers.
+	 */
+	int (*probe_hw) (struct rt2x00_dev *rt2x00dev);
+	char *(*get_firmware_name) (struct rt2x00_dev *rt2x00dev);
+	int (*load_firmware) (struct rt2x00_dev *rt2x00dev, void *data,
+			      const size_t len);
+
+	/*
+	 * Device initialization/deinitialization handlers.
+	 */
+	int (*initialize) (struct rt2x00_dev *rt2x00dev);
+	void (*uninitialize) (struct rt2x00_dev *rt2x00dev);
+
+	/*
+	 * Radio control handlers.
+	 */
+	int (*set_device_state) (struct rt2x00_dev *rt2x00dev,
+				 enum dev_state state);
+	int (*rfkill_poll) (struct rt2x00_dev *rt2x00dev);
+	void (*link_stats) (struct rt2x00_dev *rt2x00dev);
+	void (*reset_tuner) (struct rt2x00_dev *rt2x00dev);
+	void (*link_tuner) (struct rt2x00_dev *rt2x00dev);
+
+	/*
+	 * TX control handlers
+	 */
+	void (*write_tx_desc) (struct rt2x00_dev *rt2x00dev,
+			       struct data_desc *txd,
+			       struct txdata_entry_desc *desc,
+			       struct ieee80211_hdr *ieee80211hdr,
+			       unsigned int length,
+			       struct ieee80211_tx_control *control);
+	int (*write_tx_data) (struct rt2x00_dev *rt2x00dev,
+			      struct data_ring *ring, struct sk_buff *skb,
+			      struct ieee80211_tx_control *control);
+	int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev, int maxpacket,
+				struct sk_buff *skb);
+	void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev,
+			       unsigned int queue);
+
+	/*
+	 * RX control handlers
+	 */
+	void (*fill_rxdone) (struct data_entry *entry,
+			     struct rxdata_entry_desc *desc);
+
+	/*
+	 * Configuration handlers.
+	 */
+	void (*config_mac_addr) (struct rt2x00_dev *rt2x00dev, __le32 *mac);
+	void (*config_bssid) (struct rt2x00_dev *rt2x00dev, __le32 *bssid);
+	void (*config_type) (struct rt2x00_dev *rt2x00dev, const int type,
+							   const int tsf_sync);
+	void (*config_preamble) (struct rt2x00_dev *rt2x00dev,
+				 const int short_preamble,
+				 const int ack_timeout,
+				 const int ack_consume_time);
+	void (*config) (struct rt2x00_dev *rt2x00dev, const unsigned int flags,
+			struct rt2x00lib_conf *libconf);
+#define CONFIG_UPDATE_PHYMODE		( 1 << 1 )
+#define CONFIG_UPDATE_CHANNEL		( 1 << 2 )
+#define CONFIG_UPDATE_TXPOWER		( 1 << 3 )
+#define CONFIG_UPDATE_ANTENNA		( 1 << 4 )
+#define CONFIG_UPDATE_SLOT_TIME 	( 1 << 5 )
+#define CONFIG_UPDATE_BEACON_INT	( 1 << 6 )
+#define CONFIG_UPDATE_ALL		0xffff
+};
+
+/*
+ * rt2x00 driver callback operation structure.
+ */
+struct rt2x00_ops {
+	const char *name;
+	const unsigned int rxd_size;
+	const unsigned int txd_size;
+	const unsigned int eeprom_size;
+	const unsigned int rf_size;
+	const struct rt2x00lib_ops *lib;
+	const struct ieee80211_ops *hw;
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+	const struct rt2x00debug *debugfs;
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * rt2x00 device flags
+ */
+enum rt2x00_flags {
+	/*
+	 * Device state flags
+	 */
+	DEVICE_PRESENT,
+	DEVICE_REGISTERED_HW,
+	DEVICE_INITIALIZED,
+	DEVICE_STARTED,
+	DEVICE_STARTED_SUSPEND,
+	DEVICE_ENABLED_RADIO,
+	DEVICE_DISABLED_RADIO_HW,
+
+	/*
+	 * Driver features
+	 */
+	DRIVER_REQUIRE_FIRMWARE,
+	DRIVER_REQUIRE_BEACON_RING,
+
+	/*
+	 * Driver configuration
+	 */
+	CONFIG_SUPPORT_HW_BUTTON,
+	CONFIG_FRAME_TYPE,
+	CONFIG_RF_SEQUENCE,
+	CONFIG_EXTERNAL_LNA_A,
+	CONFIG_EXTERNAL_LNA_BG,
+	CONFIG_DOUBLE_ANTENNA,
+	CONFIG_DISABLE_LINK_TUNING,
+	CONFIG_SHORT_PREAMBLE,
+};
+
+/*
+ * rt2x00 device structure.
+ */
+struct rt2x00_dev {
+	/*
+	 * Device structure.
+	 * The structure stored in here depends on the
+	 * system bus (PCI or USB).
+	 * When accessing this variable, the rt2x00dev_{pci,usb}
+	 * macro's should be used for correct typecasting.
+	 */
+	void *dev;
+#define rt2x00dev_pci(__dev)	( (struct pci_dev*)(__dev)->dev )
+#define rt2x00dev_usb(__dev)	( (struct usb_interface*)(__dev)->dev )
+
+	/*
+	 * Callback functions.
+	 */
+	const struct rt2x00_ops *ops;
+
+	/*
+	 * IEEE80211 control structure.
+	 */
+	struct ieee80211_hw *hw;
+	struct ieee80211_hw_mode *hwmodes;
+	unsigned int curr_hwmode;
+#define HWMODE_B	0
+#define HWMODE_G	1
+#define HWMODE_A	2
+
+	/*
+	 * rfkill structure for RF state switching support.
+	 * This will only be compiled in when required.
+	 */
+#ifdef CONFIG_RT2X00_LIB_RFKILL
+	struct rfkill *rfkill;
+	struct input_polled_dev *poll_dev;
+#endif /* CONFIG_RT2X00_LIB_RFKILL */
+
+	/*
+	 * If enabled, the debugfs interface structures
+	 * required for deregistration of debugfs.
+	 */
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+	const struct rt2x00debug_intf *debugfs_intf;
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+	/*
+	 * Device flags.
+	 * In these flags the current status and some
+	 * of the device capabilities are stored.
+	 */
+	unsigned long flags;
+
+	/*
+	 * Chipset identification.
+	 */
+	struct rt2x00_chip chip;
+
+	/*
+	 * hw capability specifications.
+	 */
+	struct hw_mode_spec spec;
+
+	/*
+	 * Register pointers
+	 * csr_addr: Base register address. (PCI)
+	 * csr_cache: CSR cache for usb_control_msg. (USB)
+	 */
+	void __iomem *csr_addr;
+	void *csr_cache;
+
+	/*
+	 * Interface configuration.
+	 */
+	struct interface interface;
+
+	/*
+	 * Link quality
+	 */
+	struct link link;
+
+	/*
+	 * EEPROM data.
+	 */
+	__le16 *eeprom;
+
+	/*
+	 * Active RF register values.
+	 * These are stored here so we don't need
+	 * to read the rf registers and can directly
+	 * use this value instead.
+	 * This field should be accessed by using
+	 * rt2x00_rf_read() and rt2x00_rf_write().
+	 */
+	u32 *rf;
+
+	/*
+	 * Current TX power value.
+	 */
+	u16 tx_power;
+
+	/*
+	 * LED register (for rt61pci & rt73usb).
+	 */
+	u16 led_reg;
+
+	/*
+	 * Led mode (LED_MODE_*)
+	 */
+	u8 led_mode;
+
+	/*
+	 * Rssi <-> Dbm offset
+	 */
+	u8 rssi_offset;
+
+	/*
+	 * Frequency offset (for rt61pci & rt73usb).
+	 */
+	u8 freq_offset;
+
+	/*
+	 * Low level statistics which will have
+	 * to be kept up to date while device is running.
+	 */
+	struct ieee80211_low_level_stats low_level_stats;
+
+	/*
+	 * RX configuration information.
+	 */
+	struct ieee80211_rx_status rx_status;
+
+	/*
+	 * Scheduled work.
+	 */
+	struct work_struct beacon_work;
+	struct work_struct filter_work;
+	struct work_struct config_work;
+
+	/*
+	 * Data ring arrays for RX, TX and Beacon.
+	 * The Beacon array also contains the Atim ring
+	 * if that is supported by the device.
+	 */
+	int data_rings;
+	struct data_ring *rx;
+	struct data_ring *tx;
+	struct data_ring *bcn;
+
+	/*
+	 * Firmware image.
+	 */
+	const struct firmware *fw;
+};
+
+/*
+ * For-each loop for the ring array.
+ * All rings have been allocated as a single array,
+ * this means we can create a very simply loop macro
+ * that is capable of looping through all rings.
+ * ring_end(), txring_end() and ring_loop() are helper macro's which
+ * should not be used directly. Instead the following should be used:
+ * ring_for_each() - Loops through all rings (RX, TX, Beacon & Atim)
+ * txring_for_each() - Loops through TX data rings (TX only)
+ * txringall_for_each() - Loops through all TX rings (TX, Beacon & Atim)
+ */
+#define ring_end(__dev) \
+	&(__dev)->rx[(__dev)->data_rings]
+
+#define txring_end(__dev) \
+	&(__dev)->tx[(__dev)->hw->queues]
+
+#define ring_loop(__entry, __start, __end)			\
+	for ((__entry) = (__start);				\
+	     prefetch(&(__entry)[1]), (__entry) != (__end);	\
+	     (__entry) = &(__entry)[1])
+
+#define ring_for_each(__dev, __entry) \
+	ring_loop(__entry, (__dev)->rx, ring_end(__dev))
+
+#define txring_for_each(__dev, __entry) \
+	ring_loop(__entry, (__dev)->tx, txring_end(__dev))
+
+#define txringall_for_each(__dev, __entry) \
+	ring_loop(__entry, (__dev)->tx, ring_end(__dev))
+
+/*
+ * Generic RF access.
+ * The RF is being accessed by word index.
+ */
+static inline void rt2x00_rf_read(const struct rt2x00_dev *rt2x00dev,
+				  const unsigned int word, u32 *data)
+{
+	*data = rt2x00dev->rf[word];
+}
+
+static inline void rt2x00_rf_write(const struct rt2x00_dev *rt2x00dev,
+				   const unsigned int word, u32 data)
+{
+	rt2x00dev->rf[word] = data;
+}
+
+/*
+ *  Generic EEPROM access.
+ * The EEPROM is being accessed by word index.
+ */
+static inline void *rt2x00_eeprom_addr(const struct rt2x00_dev *rt2x00dev,
+				       const unsigned int word)
+{
+	return (void *)&rt2x00dev->eeprom[word];
+}
+
+static inline void rt2x00_eeprom_read(const struct rt2x00_dev *rt2x00dev,
+				      const unsigned int word, u16 *data)
+{
+	*data = le16_to_cpu(rt2x00dev->eeprom[word]);
+}
+
+static inline void rt2x00_eeprom_write(const struct rt2x00_dev *rt2x00dev,
+				       const unsigned int word, u16 data)
+{
+	rt2x00dev->eeprom[word] = cpu_to_le16(data);
+}
+
+/*
+ * Chipset handlers
+ */
+static inline void rt2x00_set_chip(struct rt2x00_dev *rt2x00dev,
+				   const u16 rt, const u16 rf, const u32 rev)
+{
+	INFO(rt2x00dev,
+	     "Chipset detected - rt: %04x, rf: %04x, rev: %08x.\n",
+	     rt, rf, rev);
+
+	rt2x00dev->chip.rt = rt;
+	rt2x00dev->chip.rf = rf;
+	rt2x00dev->chip.rev = rev;
+}
+
+static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip)
+{
+	return (chipset->rt == chip);
+}
+
+static inline char rt2x00_rf(const struct rt2x00_chip *chipset, const u16 chip)
+{
+	return (chipset->rf == chip);
+}
+
+static inline u16 rt2x00_get_rev(const struct rt2x00_chip *chipset)
+{
+	return chipset->rev;
+}
+
+static inline u16 rt2x00_rev(const struct rt2x00_chip *chipset, const u32 mask)
+{
+	return chipset->rev & mask;
+}
+
+/*
+ * Duration calculations
+ * The rate variable passed is: 100kbs.
+ * To convert from bytes to bits we multiply size with 8,
+ * then the size is multiplied with 10 to make the
+ * real rate -> rate argument correction.
+ */
+static inline u16 get_duration(const unsigned int size, const u8 rate)
+{
+	return ((size * 8 * 10) / rate);
+}
+
+static inline u16 get_duration_res(const unsigned int size, const u8 rate)
+{
+	return ((size * 8 * 10) % rate);
+}
+
+/*
+ * Library functions.
+ */
+struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev,
+				     const unsigned int queue);
+
+/*
+ * Interrupt context handlers.
+ */
+void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_txdone(struct data_entry *entry,
+		      const int status, const int retry);
+void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb,
+		      struct rxdata_entry_desc *desc);
+
+/*
+ * TX descriptor initializer
+ */
+void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+			     struct data_desc *txd,
+			     struct ieee80211_hdr *ieee80211hdr,
+			     unsigned int length,
+			     struct ieee80211_tx_control *control);
+
+/*
+ * mac80211 handlers.
+ */
+int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+		 struct ieee80211_tx_control *control);
+int rt2x00mac_start(struct ieee80211_hw *hw);
+void rt2x00mac_stop(struct ieee80211_hw *hw);
+int rt2x00mac_add_interface(struct ieee80211_hw *hw,
+			    struct ieee80211_if_init_conf *conf);
+void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
+				struct ieee80211_if_init_conf *conf);
+int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf);
+int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id,
+			       struct ieee80211_if_conf *conf);
+int rt2x00mac_get_stats(struct ieee80211_hw *hw,
+			struct ieee80211_low_level_stats *stats);
+int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
+			   struct ieee80211_tx_queue_stats *stats);
+void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes,
+			      int cts_protection, int preamble);
+int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue,
+		      const struct ieee80211_tx_queue_params *params);
+
+/*
+ * Driver allocation handlers.
+ */
+int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev);
+#ifdef CONFIG_PM
+int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state);
+int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev);
+#endif /* CONFIG_PM */
+
+#endif /* RT2X00_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
new file mode 100644
index 0000000..12914cf
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -0,0 +1,205 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2x00lib
+	Abstract: rt2x00 generic configuration routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+
+/*
+ * The MAC and BSSID addressess are simple array of bytes,
+ * these arrays are little endian, so when sending the addressess
+ * to the drivers, copy the it into a endian-signed variable.
+ *
+ * Note that all devices (except rt2500usb) have 32 bits
+ * register word sizes. This means that whatever variable we
+ * pass _must_ be a multiple of 32 bits. Otherwise the device
+ * might not accept what we are sending to it.
+ * This will also make it easier for the driver to write
+ * the data to the device.
+ *
+ * Also note that when NULL is passed as address the
+ * we will send 00:00:00:00:00 to the device to clear the address.
+ * This will prevent the device being confused when it wants
+ * to ACK frames or consideres itself associated.
+ */
+void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac)
+{
+	__le32 reg[2];
+
+	memset(&reg, 0, sizeof(reg));
+	if (mac)
+		memcpy(&reg, mac, ETH_ALEN);
+
+	rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, &reg[0]);
+}
+
+void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid)
+{
+	__le32 reg[2];
+
+	memset(&reg, 0, sizeof(reg));
+	if (bssid)
+		memcpy(&reg, bssid, ETH_ALEN);
+
+	rt2x00dev->ops->lib->config_bssid(rt2x00dev, &reg[0]);
+}
+
+void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type)
+{
+	int tsf_sync;
+
+	switch (type) {
+	case IEEE80211_IF_TYPE_IBSS:
+	case IEEE80211_IF_TYPE_AP:
+		tsf_sync = TSF_SYNC_BEACON;
+		break;
+	case IEEE80211_IF_TYPE_STA:
+		tsf_sync = TSF_SYNC_INFRA;
+		break;
+	default:
+		tsf_sync = TSF_SYNC_NONE;
+		break;
+	}
+
+	rt2x00dev->ops->lib->config_type(rt2x00dev, type, tsf_sync);
+}
+
+void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
+		      struct ieee80211_conf *conf, const int force_config)
+{
+	struct rt2x00lib_conf libconf;
+	struct ieee80211_hw_mode *mode;
+	struct ieee80211_rate *rate;
+	int flags = 0;
+	int short_slot_time;
+
+	/*
+	 * In some situations we want to force all configurations
+	 * to be reloaded (When resuming for instance).
+	 */
+	if (force_config) {
+		flags = CONFIG_UPDATE_ALL;
+		goto config;
+	}
+
+	/*
+	 * Check which configuration options have been
+	 * updated and should be send to the device.
+	 */
+	if (rt2x00dev->rx_status.phymode != conf->phymode)
+		flags |= CONFIG_UPDATE_PHYMODE;
+	if (rt2x00dev->rx_status.channel != conf->channel)
+		flags |= CONFIG_UPDATE_CHANNEL;
+	if (rt2x00dev->tx_power != conf->power_level)
+		flags |= CONFIG_UPDATE_TXPOWER;
+	if (rt2x00dev->rx_status.antenna == conf->antenna_sel_rx)
+		flags |= CONFIG_UPDATE_ANTENNA;
+
+	/*
+	 * The following configuration options are never
+	 * stored anywhere and will always be updated.
+	 */
+	flags |= CONFIG_UPDATE_SLOT_TIME;
+	flags |= CONFIG_UPDATE_BEACON_INT;
+
+	/*
+	 * We have determined what options should be updated,
+	 * now precalculate device configuration values depending
+	 * on what configuration options need to be updated.
+	 */
+config:
+	memset(&libconf, 0, sizeof(libconf));
+
+	if (flags & CONFIG_UPDATE_PHYMODE) {
+		switch (conf->phymode) {
+		case MODE_IEEE80211A:
+			libconf.phymode = HWMODE_A;
+			break;
+		case MODE_IEEE80211B:
+			libconf.phymode = HWMODE_B;
+			break;
+		case MODE_IEEE80211G:
+			libconf.phymode = HWMODE_G;
+			break;
+		default:
+			ERROR(rt2x00dev,
+			      "Attempt to configure unsupported mode (%d)"
+			      "Defaulting to 802.11b", conf->phymode);
+			libconf.phymode = HWMODE_B;
+		}
+
+		mode = &rt2x00dev->hwmodes[libconf.phymode];
+		rate = &mode->rates[mode->num_rates - 1];
+
+		libconf.basic_rates =
+		    DEVICE_GET_RATE_FIELD(rate->val, RATEMASK) & DEV_BASIC_RATEMASK;
+	}
+
+	if (flags & CONFIG_UPDATE_CHANNEL) {
+		memcpy(&libconf.rf,
+		       &rt2x00dev->spec.channels[conf->channel_val],
+		       sizeof(libconf.rf));
+	}
+
+	if (flags & CONFIG_UPDATE_SLOT_TIME) {
+		short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME;
+
+		libconf.slot_time =
+		    short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME;
+		libconf.sifs = SIFS;
+		libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS;
+		libconf.difs = short_slot_time ? SHORT_DIFS : DIFS;
+		libconf.eifs = EIFS;
+	}
+
+	libconf.conf = conf;
+
+	/*
+	 * Start configuration.
+	 */
+	rt2x00dev->ops->lib->config(rt2x00dev, flags, &libconf);
+
+	/*
+	 * Some configuration changes affect the link quality
+	 * which means we need to reset the link tuner.
+	 */
+	if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA))
+		rt2x00lib_reset_link_tuner(rt2x00dev);
+
+	rt2x00dev->curr_hwmode = libconf.phymode;
+	rt2x00dev->rx_status.phymode = conf->phymode;
+	rt2x00dev->rx_status.freq = conf->freq;
+	rt2x00dev->rx_status.channel = conf->channel;
+	rt2x00dev->tx_power = conf->power_level;
+	rt2x00dev->rx_status.antenna = conf->antenna_sel_rx;
+}
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
new file mode 100644
index 0000000..9275d6f
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -0,0 +1,368 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2x00lib
+	Abstract: rt2x00 debugfs specific routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+#define PRINT_LINE_LEN_MAX 32
+
+struct rt2x00debug_intf {
+	/*
+	 * Pointer to driver structure where
+	 * this debugfs entry belongs to.
+	 */
+	struct rt2x00_dev *rt2x00dev;
+
+	/*
+	 * Reference to the rt2x00debug structure
+	 * which can be used to communicate with
+	 * the registers.
+	 */
+	const struct rt2x00debug *debug;
+
+	/*
+	 * Debugfs entries for:
+	 * - driver folder
+	 * - driver file
+	 * - chipset file
+	 * - device flags file
+	 * - register offset/value files
+	 * - eeprom offset/value files
+	 * - bbp offset/value files
+	 * - rf offset/value files
+	 */
+	struct dentry *driver_folder;
+	struct dentry *driver_entry;
+	struct dentry *chipset_entry;
+	struct dentry *dev_flags;
+	struct dentry *csr_off_entry;
+	struct dentry *csr_val_entry;
+	struct dentry *eeprom_off_entry;
+	struct dentry *eeprom_val_entry;
+	struct dentry *bbp_off_entry;
+	struct dentry *bbp_val_entry;
+	struct dentry *rf_off_entry;
+	struct dentry *rf_val_entry;
+
+	/*
+	 * Driver and chipset files will use a data buffer
+	 * that has been created in advance. This will simplify
+	 * the code since we can use the debugfs functions.
+	 */
+	struct debugfs_blob_wrapper driver_blob;
+	struct debugfs_blob_wrapper chipset_blob;
+
+	/*
+	 * Requested offset for each register type.
+	 */
+	unsigned int offset_csr;
+	unsigned int offset_eeprom;
+	unsigned int offset_bbp;
+	unsigned int offset_rf;
+};
+
+static int rt2x00debug_file_open(struct inode *inode, struct file *file)
+{
+	struct rt2x00debug_intf *intf = inode->i_private;
+
+	file->private_data = inode->i_private;
+
+	if (!try_module_get(intf->debug->owner))
+		return -EBUSY;
+
+	return 0;
+}
+
+static int rt2x00debug_file_release(struct inode *inode, struct file *file)
+{
+	struct rt2x00debug_intf *intf = file->private_data;
+
+	module_put(intf->debug->owner);
+
+	return 0;
+}
+
+#define RT2X00DEBUGFS_OPS_READ(__name, __format, __type)	\
+static ssize_t rt2x00debug_read_##__name(struct file *file,	\
+					 char __user *buf,	\
+					 size_t length,		\
+					 loff_t *offset)	\
+{								\
+	struct rt2x00debug_intf *intf =	file->private_data;	\
+	const struct rt2x00debug *debug = intf->debug;		\
+	char line[16];						\
+	size_t size;						\
+	__type value;						\
+								\
+	if (*offset)						\
+		return 0;					\
+								\
+	if (intf->offset_##__name >= debug->__name.word_count)	\
+		return -EINVAL;					\
+								\
+	debug->__name.read(intf->rt2x00dev,			\
+			   intf->offset_##__name, &value);	\
+								\
+	size = sprintf(line, __format, value);			\
+								\
+	if (copy_to_user(buf, line, size))			\
+		return -EFAULT;					\
+								\
+	*offset += size;					\
+	return size;						\
+}
+
+#define RT2X00DEBUGFS_OPS_WRITE(__name, __type)			\
+static ssize_t rt2x00debug_write_##__name(struct file *file,	\
+					  const char __user *buf,\
+					  size_t length,	\
+					  loff_t *offset)	\
+{								\
+	struct rt2x00debug_intf *intf =	file->private_data;	\
+	const struct rt2x00debug *debug = intf->debug;		\
+	char line[16];						\
+	size_t size;						\
+	__type value;						\
+								\
+	if (*offset)						\
+		return 0;					\
+								\
+	if (!capable(CAP_NET_ADMIN))				\
+		return -EPERM;					\
+								\
+	if (intf->offset_##__name >= debug->__name.word_count)	\
+		return -EINVAL;					\
+								\
+	if (copy_from_user(line, buf, length))			\
+		return -EFAULT;					\
+								\
+	size = strlen(line);					\
+	value = simple_strtoul(line, NULL, 0);			\
+								\
+	debug->__name.write(intf->rt2x00dev,			\
+			    intf->offset_##__name, value);	\
+								\
+	*offset += size;					\
+	return size;						\
+}
+
+#define RT2X00DEBUGFS_OPS(__name, __format, __type)		\
+RT2X00DEBUGFS_OPS_READ(__name, __format, __type);		\
+RT2X00DEBUGFS_OPS_WRITE(__name, __type);			\
+								\
+static const struct file_operations rt2x00debug_fop_##__name = {\
+	.owner		= THIS_MODULE,				\
+	.read		= rt2x00debug_read_##__name,		\
+	.write		= rt2x00debug_write_##__name,		\
+	.open		= rt2x00debug_file_open,		\
+	.release	= rt2x00debug_file_release,		\
+};
+
+RT2X00DEBUGFS_OPS(csr, "0x%.8x\n", u32);
+RT2X00DEBUGFS_OPS(eeprom, "0x%.4x\n", u16);
+RT2X00DEBUGFS_OPS(bbp, "0x%.2x\n", u8);
+RT2X00DEBUGFS_OPS(rf, "0x%.8x\n", u32);
+
+static ssize_t rt2x00debug_read_dev_flags(struct file *file,
+					  char __user *buf,
+					  size_t length,
+					  loff_t *offset)
+{
+	struct rt2x00debug_intf *intf =	file->private_data;
+	char line[16];
+	size_t size;
+
+	if (*offset)
+		return 0;
+
+	size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->flags);
+
+	if (copy_to_user(buf, line, size))
+		return -EFAULT;
+
+	*offset += size;
+	return size;
+}
+
+static const struct file_operations rt2x00debug_fop_dev_flags = {
+	.owner		= THIS_MODULE,
+	.read		= rt2x00debug_read_dev_flags,
+	.open		= rt2x00debug_file_open,
+	.release	= rt2x00debug_file_release,
+};
+
+static struct dentry *rt2x00debug_create_file_driver(const char *name,
+						     struct rt2x00debug_intf
+						     *intf,
+						     struct debugfs_blob_wrapper
+						     *blob)
+{
+	char *data;
+
+	data = kzalloc(3 * PRINT_LINE_LEN_MAX, GFP_KERNEL);
+	if (!data)
+		return NULL;
+
+	blob->data = data;
+	data += sprintf(data, "driver: %s\n", intf->rt2x00dev->ops->name);
+	data += sprintf(data, "version: %s\n", DRV_VERSION);
+	data += sprintf(data, "compiled: %s %s\n", __DATE__, __TIME__);
+	blob->size = strlen(blob->data);
+
+	return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob);
+}
+
+static struct dentry *rt2x00debug_create_file_chipset(const char *name,
+						      struct rt2x00debug_intf
+						      *intf,
+						      struct
+						      debugfs_blob_wrapper
+						      *blob)
+{
+	const struct rt2x00debug *debug = intf->debug;
+	char *data;
+
+	data = kzalloc(4 * PRINT_LINE_LEN_MAX, GFP_KERNEL);
+	if (!data)
+		return NULL;
+
+	blob->data = data;
+	data += sprintf(data, "csr length: %d\n", debug->csr.word_count);
+	data += sprintf(data, "eeprom length: %d\n", debug->eeprom.word_count);
+	data += sprintf(data, "bbp length: %d\n", debug->bbp.word_count);
+	data += sprintf(data, "rf length: %d\n", debug->rf.word_count);
+	blob->size = strlen(blob->data);
+
+	return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob);
+}
+
+void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
+{
+	const struct rt2x00debug *debug = rt2x00dev->ops->debugfs;
+	struct rt2x00debug_intf *intf;
+
+	intf = kzalloc(sizeof(struct rt2x00debug_intf), GFP_KERNEL);
+	if (!intf) {
+		ERROR(rt2x00dev, "Failed to allocate debug handler.\n");
+		return;
+	}
+
+	intf->debug = debug;
+	intf->rt2x00dev = rt2x00dev;
+	rt2x00dev->debugfs_intf = intf;
+
+	intf->driver_folder =
+	    debugfs_create_dir(intf->rt2x00dev->ops->name,
+			       rt2x00dev->hw->wiphy->debugfsdir);
+	if (IS_ERR(intf->driver_folder))
+		goto exit;
+
+	intf->driver_entry =
+	    rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob);
+	if (IS_ERR(intf->driver_entry))
+		goto exit;
+
+	intf->chipset_entry =
+	    rt2x00debug_create_file_chipset("chipset",
+					    intf, &intf->chipset_blob);
+	if (IS_ERR(intf->chipset_entry))
+		goto exit;
+
+	intf->dev_flags = debugfs_create_file("dev_flags", S_IRUGO,
+					      intf->driver_folder, intf,
+					      &rt2x00debug_fop_dev_flags);
+	if (IS_ERR(intf->dev_flags))
+		goto exit;
+
+#define RT2X00DEBUGFS_CREATE_ENTRY(__intf, __name)		\
+({								\
+	(__intf)->__name##_off_entry =				\
+	    debugfs_create_u32(__stringify(__name) "_offset",	\
+			       S_IRUGO | S_IWUSR,		\
+			       (__intf)->driver_folder,		\
+			       &(__intf)->offset_##__name);	\
+	if (IS_ERR((__intf)->__name##_off_entry))		\
+		goto exit;					\
+								\
+	(__intf)->__name##_val_entry =				\
+	    debugfs_create_file(__stringify(__name) "_value",	\
+				S_IRUGO | S_IWUSR,		\
+				(__intf)->driver_folder,	\
+				(__intf), &rt2x00debug_fop_##__name);\
+	if (IS_ERR((__intf)->__name##_val_entry))		\
+		goto exit;					\
+})
+
+	RT2X00DEBUGFS_CREATE_ENTRY(intf, csr);
+	RT2X00DEBUGFS_CREATE_ENTRY(intf, eeprom);
+	RT2X00DEBUGFS_CREATE_ENTRY(intf, bbp);
+	RT2X00DEBUGFS_CREATE_ENTRY(intf, rf);
+
+#undef RT2X00DEBUGFS_CREATE_ENTRY
+
+	return;
+
+exit:
+	rt2x00debug_deregister(rt2x00dev);
+	ERROR(rt2x00dev, "Failed to register debug handler.\n");
+
+	return;
+}
+
+void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
+{
+	const struct rt2x00debug_intf *intf = rt2x00dev->debugfs_intf;
+
+	if (unlikely(!intf))
+		return;
+
+	debugfs_remove(intf->rf_val_entry);
+	debugfs_remove(intf->rf_off_entry);
+	debugfs_remove(intf->bbp_val_entry);
+	debugfs_remove(intf->bbp_off_entry);
+	debugfs_remove(intf->eeprom_val_entry);
+	debugfs_remove(intf->eeprom_off_entry);
+	debugfs_remove(intf->csr_val_entry);
+	debugfs_remove(intf->csr_off_entry);
+	debugfs_remove(intf->dev_flags);
+	debugfs_remove(intf->chipset_entry);
+	debugfs_remove(intf->driver_entry);
+	debugfs_remove(intf->driver_folder);
+	kfree(intf->chipset_blob.data);
+	kfree(intf->driver_blob.data);
+	kfree(intf);
+
+	rt2x00dev->debugfs_intf = NULL;
+}
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.h b/drivers/net/wireless/rt2x00/rt2x00debug.h
new file mode 100644
index 0000000..860e8fa
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.h
@@ -0,0 +1,57 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2x00debug
+	Abstract: Data structures for the rt2x00debug.
+ */
+
+#ifndef RT2X00DEBUG_H
+#define RT2X00DEBUG_H
+
+struct rt2x00_dev;
+
+#define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type)		\
+struct reg##__name {						\
+	void (*read)(const struct rt2x00_dev *rt2x00dev,	\
+		     const unsigned int word, __type *data);	\
+	void (*write)(const struct rt2x00_dev *rt2x00dev,	\
+		      const unsigned int word, __type data);	\
+								\
+	unsigned int word_size;					\
+	unsigned int word_count;				\
+} __name
+
+struct rt2x00debug {
+	/*
+	 * Reference to the modules structure.
+	 */
+	struct module *owner;
+
+	/*
+	 * Register access entries.
+	 */
+	RT2X00DEBUGFS_REGISTER_ENTRY(csr, u32);
+	RT2X00DEBUGFS_REGISTER_ENTRY(eeprom, u16);
+	RT2X00DEBUGFS_REGISTER_ENTRY(bbp, u8);
+	RT2X00DEBUGFS_REGISTER_ENTRY(rf, u32);
+};
+
+#endif /* RT2X00DEBUG_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
new file mode 100644
index 0000000..bb6f46c
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -0,0 +1,1202 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2x00lib
+	Abstract: rt2x00 generic device routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+/*
+ * Ring handler.
+ */
+struct data_ring *rt2x00lib_get_ring(struct rt2x00_dev *rt2x00dev,
+				     const unsigned int queue)
+{
+	int beacon = test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags);
+
+	/*
+	 * Check if we are requesting a reqular TX ring,
+	 * or if we are requesting a Beacon or Atim ring.
+	 * For Atim rings, we should check if it is supported.
+	 */
+	if (queue < rt2x00dev->hw->queues && rt2x00dev->tx)
+		return &rt2x00dev->tx[queue];
+
+	if (!rt2x00dev->bcn || !beacon)
+		return NULL;
+
+	if (queue == IEEE80211_TX_QUEUE_BEACON)
+		return &rt2x00dev->bcn[0];
+	else if (queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
+		return &rt2x00dev->bcn[1];
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_get_ring);
+
+/*
+ * Link tuning handlers
+ */
+static void rt2x00lib_start_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+	rt2x00_clear_link(&rt2x00dev->link);
+
+	/*
+	 * Reset the link tuner.
+	 */
+	rt2x00dev->ops->lib->reset_tuner(rt2x00dev);
+
+	queue_delayed_work(rt2x00dev->hw->workqueue,
+			   &rt2x00dev->link.work, LINK_TUNE_INTERVAL);
+}
+
+static void rt2x00lib_stop_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+	cancel_delayed_work_sync(&rt2x00dev->link.work);
+}
+
+void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+		return;
+
+	rt2x00lib_stop_link_tuner(rt2x00dev);
+	rt2x00lib_start_link_tuner(rt2x00dev);
+}
+
+/*
+ * Radio control handlers.
+ */
+int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+	int status;
+
+	/*
+	 * Don't enable the radio twice.
+	 * And check if the hardware button has been disabled.
+	 */
+	if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
+	    test_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags))
+		return 0;
+
+	/*
+	 * Enable radio.
+	 */
+	status = rt2x00dev->ops->lib->set_device_state(rt2x00dev,
+						       STATE_RADIO_ON);
+	if (status)
+		return status;
+
+	__set_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags);
+
+	/*
+	 * Enable RX.
+	 */
+	rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+
+	/*
+	 * Start the TX queues.
+	 */
+	ieee80211_start_queues(rt2x00dev->hw);
+
+	return 0;
+}
+
+void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+	if (!__test_and_clear_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+		return;
+
+	/*
+	 * Stop all scheduled work.
+	 */
+	if (work_pending(&rt2x00dev->beacon_work))
+		cancel_work_sync(&rt2x00dev->beacon_work);
+	if (work_pending(&rt2x00dev->filter_work))
+		cancel_work_sync(&rt2x00dev->filter_work);
+	if (work_pending(&rt2x00dev->config_work))
+		cancel_work_sync(&rt2x00dev->config_work);
+
+	/*
+	 * Stop the TX queues.
+	 */
+	ieee80211_stop_queues(rt2x00dev->hw);
+
+	/*
+	 * Disable RX.
+	 */
+	rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
+
+	/*
+	 * Disable radio.
+	 */
+	rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_RADIO_OFF);
+}
+
+void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state)
+{
+	/*
+	 * When we are disabling the RX, we should also stop the link tuner.
+	 */
+	if (state == STATE_RADIO_RX_OFF)
+		rt2x00lib_stop_link_tuner(rt2x00dev);
+
+	rt2x00dev->ops->lib->set_device_state(rt2x00dev, state);
+
+	/*
+	 * When we are enabling the RX, we should also start the link tuner.
+	 */
+	if (state == STATE_RADIO_RX_ON &&
+	    is_interface_present(&rt2x00dev->interface))
+		rt2x00lib_start_link_tuner(rt2x00dev);
+}
+
+static void rt2x00lib_precalculate_link_signal(struct link *link)
+{
+	if (link->rx_failed || link->rx_success)
+		link->rx_percentage =
+		    (link->rx_success * 100) /
+		    (link->rx_failed + link->rx_success);
+	else
+		link->rx_percentage = 50;
+
+	if (link->tx_failed || link->tx_success)
+		link->tx_percentage =
+		    (link->tx_success * 100) /
+		    (link->tx_failed + link->tx_success);
+	else
+		link->tx_percentage = 50;
+
+	link->rx_success = 0;
+	link->rx_failed = 0;
+	link->tx_success = 0;
+	link->tx_failed = 0;
+}
+
+static int rt2x00lib_calculate_link_signal(struct rt2x00_dev *rt2x00dev,
+					   int rssi)
+{
+	int rssi_percentage = 0;
+	int signal;
+
+	/*
+	 * We need a positive value for the RSSI.
+	 */
+	if (rssi < 0)
+		rssi += rt2x00dev->rssi_offset;
+
+	/*
+	 * Calculate the different percentages,
+	 * which will be used for the signal.
+	 */
+	if (rt2x00dev->rssi_offset)
+		rssi_percentage = (rssi * 100) / rt2x00dev->rssi_offset;
+
+	/*
+	 * Add the individual percentages and use the WEIGHT
+	 * defines to calculate the current link signal.
+	 */
+	signal = ((WEIGHT_RSSI * rssi_percentage) +
+		  (WEIGHT_TX * rt2x00dev->link.tx_percentage) +
+		  (WEIGHT_RX * rt2x00dev->link.rx_percentage)) / 100;
+
+	return (signal > 100) ? 100 : signal;
+}
+
+static void rt2x00lib_link_tuner(struct work_struct *work)
+{
+	struct rt2x00_dev *rt2x00dev =
+	    container_of(work, struct rt2x00_dev, link.work.work);
+
+	/*
+	 * When the radio is shutting down we should
+	 * immediately cease all link tuning.
+	 */
+	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+		return;
+
+	/*
+	 * Update statistics.
+	 */
+	rt2x00dev->ops->lib->link_stats(rt2x00dev);
+
+	rt2x00dev->low_level_stats.dot11FCSErrorCount +=
+	    rt2x00dev->link.rx_failed;
+
+	/*
+	 * Only perform the link tuning when Link tuning
+	 * has been enabled (This could have been disabled from the EEPROM).
+	 */
+	if (!test_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags))
+		rt2x00dev->ops->lib->link_tuner(rt2x00dev);
+
+	/*
+	 * Precalculate a portion of the link signal which is
+	 * in based on the tx/rx success/failure counters.
+	 */
+	rt2x00lib_precalculate_link_signal(&rt2x00dev->link);
+
+	/*
+	 * Increase tuner counter, and reschedule the next link tuner run.
+	 */
+	rt2x00dev->link.count++;
+	queue_delayed_work(rt2x00dev->hw->workqueue, &rt2x00dev->link.work,
+			   LINK_TUNE_INTERVAL);
+}
+
+static void rt2x00lib_packetfilter_scheduled(struct work_struct *work)
+{
+	struct rt2x00_dev *rt2x00dev =
+	    container_of(work, struct rt2x00_dev, filter_work);
+	unsigned int filter = rt2x00dev->interface.filter;
+
+	/*
+	 * Since we had stored the filter inside interface.filter,
+	 * we should now clear that field. Otherwise the driver will
+	 * assume nothing has changed (*total_flags will be compared
+	 * to interface.filter to determine if any action is required).
+	 */
+	rt2x00dev->interface.filter = 0;
+
+	rt2x00dev->ops->hw->configure_filter(rt2x00dev->hw,
+					     filter, &filter, 0, NULL);
+}
+
+static void rt2x00lib_configuration_scheduled(struct work_struct *work)
+{
+	struct rt2x00_dev *rt2x00dev =
+	    container_of(work, struct rt2x00_dev, config_work);
+	int preamble = !test_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
+
+	rt2x00mac_erp_ie_changed(rt2x00dev->hw,
+				 IEEE80211_ERP_CHANGE_PREAMBLE, 0, preamble);
+}
+
+/*
+ * Interrupt context handlers.
+ */
+static void rt2x00lib_beacondone_scheduled(struct work_struct *work)
+{
+	struct rt2x00_dev *rt2x00dev =
+	    container_of(work, struct rt2x00_dev, beacon_work);
+	struct data_ring *ring =
+	    rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+	struct data_entry *entry = rt2x00_get_data_entry(ring);
+	struct sk_buff *skb;
+
+	skb = ieee80211_beacon_get(rt2x00dev->hw,
+				   rt2x00dev->interface.id,
+				   &entry->tx_status.control);
+	if (!skb)
+		return;
+
+	rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw, skb,
+					  &entry->tx_status.control);
+
+	dev_kfree_skb(skb);
+}
+
+void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
+{
+	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+		return;
+
+	queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->beacon_work);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
+
+void rt2x00lib_txdone(struct data_entry *entry,
+		      const int status, const int retry)
+{
+	struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev;
+	struct ieee80211_tx_status *tx_status = &entry->tx_status;
+	struct ieee80211_low_level_stats *stats = &rt2x00dev->low_level_stats;
+	int success = !!(status == TX_SUCCESS || status == TX_SUCCESS_RETRY);
+	int fail = !!(status == TX_FAIL_RETRY || status == TX_FAIL_INVALID ||
+		      status == TX_FAIL_OTHER);
+
+	/*
+	 * Update TX statistics.
+	 */
+	tx_status->flags = 0;
+	tx_status->ack_signal = 0;
+	tx_status->excessive_retries = (status == TX_FAIL_RETRY);
+	tx_status->retry_count = retry;
+	rt2x00dev->link.tx_success += success;
+	rt2x00dev->link.tx_failed += retry + fail;
+
+	if (!(tx_status->control.flags & IEEE80211_TXCTL_NO_ACK)) {
+		if (success)
+			tx_status->flags |= IEEE80211_TX_STATUS_ACK;
+		else
+			stats->dot11ACKFailureCount++;
+	}
+
+	tx_status->queue_length = entry->ring->stats.limit;
+	tx_status->queue_number = tx_status->control.queue;
+
+	if (tx_status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) {
+		if (success)
+			stats->dot11RTSSuccessCount++;
+		else
+			stats->dot11RTSFailureCount++;
+	}
+
+	/*
+	 * Send the tx_status to mac80211,
+	 * that method also cleans up the skb structure.
+	 */
+	ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb, tx_status);
+	entry->skb = NULL;
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_txdone);
+
+void rt2x00lib_rxdone(struct data_entry *entry, struct sk_buff *skb,
+		      struct rxdata_entry_desc *desc)
+{
+	struct rt2x00_dev *rt2x00dev = entry->ring->rt2x00dev;
+	struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status;
+	struct ieee80211_hw_mode *mode;
+	struct ieee80211_rate *rate;
+	unsigned int i;
+	int val = 0;
+
+	/*
+	 * Update RX statistics.
+	 */
+	mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode];
+	for (i = 0; i < mode->num_rates; i++) {
+		rate = &mode->rates[i];
+
+		/*
+		 * When frame was received with an OFDM bitrate,
+		 * the signal is the PLCP value. If it was received with
+		 * a CCK bitrate the signal is the rate in 0.5kbit/s.
+		 */
+		if (!desc->ofdm)
+			val = DEVICE_GET_RATE_FIELD(rate->val, RATE);
+		else
+			val = DEVICE_GET_RATE_FIELD(rate->val, PLCP);
+
+		if (val == desc->signal) {
+			val = rate->val;
+			break;
+		}
+	}
+
+	rt2x00_update_link_rssi(&rt2x00dev->link, desc->rssi);
+	rt2x00dev->link.rx_success++;
+	rx_status->rate = val;
+	rx_status->signal =
+	    rt2x00lib_calculate_link_signal(rt2x00dev, desc->rssi);
+	rx_status->ssi = desc->rssi;
+	rx_status->flag = desc->flags;
+
+	/*
+	 * Send frame to mac80211
+	 */
+	ieee80211_rx_irqsafe(rt2x00dev->hw, skb, rx_status);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_rxdone);
+
+/*
+ * TX descriptor initializer
+ */
+void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+			     struct data_desc *txd,
+			     struct ieee80211_hdr *ieee80211hdr,
+			     unsigned int length,
+			     struct ieee80211_tx_control *control)
+{
+	struct txdata_entry_desc desc;
+	struct data_ring *ring;
+	int tx_rate;
+	int bitrate;
+	int duration;
+	int residual;
+	u16 frame_control;
+	u16 seq_ctrl;
+
+	/*
+	 * Make sure the descriptor is properly cleared.
+	 */
+	memset(&desc, 0x00, sizeof(desc));
+
+	/*
+	 * Get ring pointer, if we fail to obtain the
+	 * correct ring, then use the first TX ring.
+	 */
+	ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
+	if (!ring)
+		ring = rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+
+	desc.cw_min = ring->tx_params.cw_min;
+	desc.cw_max = ring->tx_params.cw_max;
+	desc.aifs = ring->tx_params.aifs;
+
+	/*
+	 * Identify queue
+	 */
+	if (control->queue < rt2x00dev->hw->queues)
+		desc.queue = control->queue;
+	else if (control->queue == IEEE80211_TX_QUEUE_BEACON ||
+		 control->queue == IEEE80211_TX_QUEUE_AFTER_BEACON)
+		desc.queue = QUEUE_MGMT;
+	else
+		desc.queue = QUEUE_OTHER;
+
+	/*
+	 * Read required fields from ieee80211 header.
+	 */
+	frame_control = le16_to_cpu(ieee80211hdr->frame_control);
+	seq_ctrl = le16_to_cpu(ieee80211hdr->seq_ctrl);
+
+	tx_rate = control->tx_rate;
+
+	/*
+	 * Check if this is a RTS/CTS frame
+	 */
+	if (is_rts_frame(frame_control) || is_cts_frame(frame_control)) {
+		__set_bit(ENTRY_TXD_BURST, &desc.flags);
+		if (is_rts_frame(frame_control))
+			__set_bit(ENTRY_TXD_RTS_FRAME, &desc.flags);
+		if (control->rts_cts_rate)
+			tx_rate = control->rts_cts_rate;
+	}
+
+	/*
+	 * Check for OFDM
+	 */
+	if (DEVICE_GET_RATE_FIELD(tx_rate, RATEMASK) & DEV_OFDM_RATEMASK)
+		__set_bit(ENTRY_TXD_OFDM_RATE, &desc.flags);
+
+	/*
+	 * Check if more fragments are pending
+	 */
+	if (ieee80211_get_morefrag(ieee80211hdr)) {
+		__set_bit(ENTRY_TXD_BURST, &desc.flags);
+		__set_bit(ENTRY_TXD_MORE_FRAG, &desc.flags);
+	}
+
+	/*
+	 * Beacons and probe responses require the tsf timestamp
+	 * to be inserted into the frame.
+	 */
+	if (control->queue == IEEE80211_TX_QUEUE_BEACON ||
+	    is_probe_resp(frame_control))
+		__set_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc.flags);
+
+	/*
+	 * Determine with what IFS priority this frame should be send.
+	 * Set ifs to IFS_SIFS when the this is not the first fragment,
+	 * or this fragment came after RTS/CTS.
+	 */
+	if ((seq_ctrl & IEEE80211_SCTL_FRAG) > 0 ||
+	    test_bit(ENTRY_TXD_RTS_FRAME, &desc.flags))
+		desc.ifs = IFS_SIFS;
+	else
+		desc.ifs = IFS_BACKOFF;
+
+	/*
+	 * PLCP setup
+	 * Length calculation depends on OFDM/CCK rate.
+	 */
+	desc.signal = DEVICE_GET_RATE_FIELD(tx_rate, PLCP);
+	desc.service = 0x04;
+
+	if (test_bit(ENTRY_TXD_OFDM_RATE, &desc.flags)) {
+		desc.length_high = ((length + FCS_LEN) >> 6) & 0x3f;
+		desc.length_low = ((length + FCS_LEN) & 0x3f);
+	} else {
+		bitrate = DEVICE_GET_RATE_FIELD(tx_rate, RATE);
+
+		/*
+		 * Convert length to microseconds.
+		 */
+		residual = get_duration_res(length + FCS_LEN, bitrate);
+		duration = get_duration(length + FCS_LEN, bitrate);
+
+		if (residual != 0) {
+			duration++;
+
+			/*
+			 * Check if we need to set the Length Extension
+			 */
+			if (bitrate == 110 && residual <= 3)
+				desc.service |= 0x80;
+		}
+
+		desc.length_high = (duration >> 8) & 0xff;
+		desc.length_low = duration & 0xff;
+
+		/*
+		 * When preamble is enabled we should set the
+		 * preamble bit for the signal.
+		 */
+		if (DEVICE_GET_RATE_FIELD(tx_rate, PREAMBLE))
+			desc.signal |= 0x08;
+	}
+
+	rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, txd, &desc,
+					   ieee80211hdr, length, control);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_write_tx_desc);
+
+/*
+ * Driver initialization handlers.
+ */
+static void rt2x00lib_channel(struct ieee80211_channel *entry,
+			      const int channel, const int tx_power,
+			      const int value)
+{
+	entry->chan = channel;
+	if (channel <= 14)
+		entry->freq = 2407 + (5 * channel);
+	else
+		entry->freq = 5000 + (5 * channel);
+	entry->val = value;
+	entry->flag =
+	    IEEE80211_CHAN_W_IBSS |
+	    IEEE80211_CHAN_W_ACTIVE_SCAN |
+	    IEEE80211_CHAN_W_SCAN;
+	entry->power_level = tx_power;
+	entry->antenna_max = 0xff;
+}
+
+static void rt2x00lib_rate(struct ieee80211_rate *entry,
+			   const int rate, const int mask,
+			   const int plcp, const int flags)
+{
+	entry->rate = rate;
+	entry->val =
+	    DEVICE_SET_RATE_FIELD(rate, RATE) |
+	    DEVICE_SET_RATE_FIELD(mask, RATEMASK) |
+	    DEVICE_SET_RATE_FIELD(plcp, PLCP);
+	entry->flags = flags;
+	entry->val2 = entry->val;
+	if (entry->flags & IEEE80211_RATE_PREAMBLE2)
+		entry->val2 |= DEVICE_SET_RATE_FIELD(1, PREAMBLE);
+	entry->min_rssi_ack = 0;
+	entry->min_rssi_ack_delta = 0;
+}
+
+static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev,
+				    struct hw_mode_spec *spec)
+{
+	struct ieee80211_hw *hw = rt2x00dev->hw;
+	struct ieee80211_hw_mode *hwmodes;
+	struct ieee80211_channel *channels;
+	struct ieee80211_rate *rates;
+	unsigned int i;
+	unsigned char tx_power;
+
+	hwmodes = kzalloc(sizeof(*hwmodes) * spec->num_modes, GFP_KERNEL);
+	if (!hwmodes)
+		goto exit;
+
+	channels = kzalloc(sizeof(*channels) * spec->num_channels, GFP_KERNEL);
+	if (!channels)
+		goto exit_free_modes;
+
+	rates = kzalloc(sizeof(*rates) * spec->num_rates, GFP_KERNEL);
+	if (!rates)
+		goto exit_free_channels;
+
+	/*
+	 * Initialize Rate list.
+	 */
+	rt2x00lib_rate(&rates[0], 10, DEV_RATEMASK_1MB,
+		       0x00, IEEE80211_RATE_CCK);
+	rt2x00lib_rate(&rates[1], 20, DEV_RATEMASK_2MB,
+		       0x01, IEEE80211_RATE_CCK_2);
+	rt2x00lib_rate(&rates[2], 55, DEV_RATEMASK_5_5MB,
+		       0x02, IEEE80211_RATE_CCK_2);
+	rt2x00lib_rate(&rates[3], 110, DEV_RATEMASK_11MB,
+		       0x03, IEEE80211_RATE_CCK_2);
+
+	if (spec->num_rates > 4) {
+		rt2x00lib_rate(&rates[4], 60, DEV_RATEMASK_6MB,
+			       0x0b, IEEE80211_RATE_OFDM);
+		rt2x00lib_rate(&rates[5], 90, DEV_RATEMASK_9MB,
+			       0x0f, IEEE80211_RATE_OFDM);
+		rt2x00lib_rate(&rates[6], 120, DEV_RATEMASK_12MB,
+			       0x0a, IEEE80211_RATE_OFDM);
+		rt2x00lib_rate(&rates[7], 180, DEV_RATEMASK_18MB,
+			       0x0e, IEEE80211_RATE_OFDM);
+		rt2x00lib_rate(&rates[8], 240, DEV_RATEMASK_24MB,
+			       0x09, IEEE80211_RATE_OFDM);
+		rt2x00lib_rate(&rates[9], 360, DEV_RATEMASK_36MB,
+			       0x0d, IEEE80211_RATE_OFDM);
+		rt2x00lib_rate(&rates[10], 480, DEV_RATEMASK_48MB,
+			       0x08, IEEE80211_RATE_OFDM);
+		rt2x00lib_rate(&rates[11], 540, DEV_RATEMASK_54MB,
+			       0x0c, IEEE80211_RATE_OFDM);
+	}
+
+	/*
+	 * Initialize Channel list.
+	 */
+	for (i = 0; i < spec->num_channels; i++) {
+		if (spec->channels[i].channel <= 14)
+			tx_power = spec->tx_power_bg[i];
+		else if (spec->tx_power_a)
+			tx_power = spec->tx_power_a[i];
+		else
+			tx_power = spec->tx_power_default;
+
+		rt2x00lib_channel(&channels[i],
+				  spec->channels[i].channel, tx_power, i);
+	}
+
+	/*
+	 * Intitialize 802.11b
+	 * Rates: CCK.
+	 * Channels: OFDM.
+	 */
+	if (spec->num_modes > HWMODE_B) {
+		hwmodes[HWMODE_B].mode = MODE_IEEE80211B;
+		hwmodes[HWMODE_B].num_channels = 14;
+		hwmodes[HWMODE_B].num_rates = 4;
+		hwmodes[HWMODE_B].channels = channels;
+		hwmodes[HWMODE_B].rates = rates;
+	}
+
+	/*
+	 * Intitialize 802.11g
+	 * Rates: CCK, OFDM.
+	 * Channels: OFDM.
+	 */
+	if (spec->num_modes > HWMODE_G) {
+		hwmodes[HWMODE_G].mode = MODE_IEEE80211G;
+		hwmodes[HWMODE_G].num_channels = 14;
+		hwmodes[HWMODE_G].num_rates = spec->num_rates;
+		hwmodes[HWMODE_G].channels = channels;
+		hwmodes[HWMODE_G].rates = rates;
+	}
+
+	/*
+	 * Intitialize 802.11a
+	 * Rates: OFDM.
+	 * Channels: OFDM, UNII, HiperLAN2.
+	 */
+	if (spec->num_modes > HWMODE_A) {
+		hwmodes[HWMODE_A].mode = MODE_IEEE80211A;
+		hwmodes[HWMODE_A].num_channels = spec->num_channels - 14;
+		hwmodes[HWMODE_A].num_rates = spec->num_rates - 4;
+		hwmodes[HWMODE_A].channels = &channels[14];
+		hwmodes[HWMODE_A].rates = &rates[4];
+	}
+
+	if (spec->num_modes > HWMODE_G &&
+	    ieee80211_register_hwmode(hw, &hwmodes[HWMODE_G]))
+		goto exit_free_rates;
+
+	if (spec->num_modes > HWMODE_B &&
+	    ieee80211_register_hwmode(hw, &hwmodes[HWMODE_B]))
+		goto exit_free_rates;
+
+	if (spec->num_modes > HWMODE_A &&
+	    ieee80211_register_hwmode(hw, &hwmodes[HWMODE_A]))
+		goto exit_free_rates;
+
+	rt2x00dev->hwmodes = hwmodes;
+
+	return 0;
+
+exit_free_rates:
+	kfree(rates);
+
+exit_free_channels:
+	kfree(channels);
+
+exit_free_modes:
+	kfree(hwmodes);
+
+exit:
+	ERROR(rt2x00dev, "Allocation ieee80211 modes failed.\n");
+	return -ENOMEM;
+}
+
+static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev)
+{
+	if (test_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags))
+		ieee80211_unregister_hw(rt2x00dev->hw);
+
+	if (likely(rt2x00dev->hwmodes)) {
+		kfree(rt2x00dev->hwmodes->channels);
+		kfree(rt2x00dev->hwmodes->rates);
+		kfree(rt2x00dev->hwmodes);
+		rt2x00dev->hwmodes = NULL;
+	}
+}
+
+static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+	struct hw_mode_spec *spec = &rt2x00dev->spec;
+	int status;
+
+	/*
+	 * Initialize HW modes.
+	 */
+	status = rt2x00lib_probe_hw_modes(rt2x00dev, spec);
+	if (status)
+		return status;
+
+	/*
+	 * Register HW.
+	 */
+	status = ieee80211_register_hw(rt2x00dev->hw);
+	if (status) {
+		rt2x00lib_remove_hw(rt2x00dev);
+		return status;
+	}
+
+	__set_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags);
+
+	return 0;
+}
+
+/*
+ * Initialization/uninitialization handlers.
+ */
+static int rt2x00lib_alloc_entries(struct data_ring *ring,
+				   const u16 max_entries, const u16 data_size,
+				   const u16 desc_size)
+{
+	struct data_entry *entry;
+	unsigned int i;
+
+	ring->stats.limit = max_entries;
+	ring->data_size = data_size;
+	ring->desc_size = desc_size;
+
+	/*
+	 * Allocate all ring entries.
+	 */
+	entry = kzalloc(ring->stats.limit * sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
+	for (i = 0; i < ring->stats.limit; i++) {
+		entry[i].flags = 0;
+		entry[i].ring = ring;
+		entry[i].skb = NULL;
+	}
+
+	ring->entry = entry;
+
+	return 0;
+}
+
+static int rt2x00lib_alloc_ring_entries(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_ring *ring;
+
+	/*
+	 * Allocate the RX ring.
+	 */
+	if (rt2x00lib_alloc_entries(rt2x00dev->rx, RX_ENTRIES, DATA_FRAME_SIZE,
+				    rt2x00dev->ops->rxd_size))
+		return -ENOMEM;
+
+	/*
+	 * First allocate the TX rings.
+	 */
+	txring_for_each(rt2x00dev, ring) {
+		if (rt2x00lib_alloc_entries(ring, TX_ENTRIES, DATA_FRAME_SIZE,
+					    rt2x00dev->ops->txd_size))
+			return -ENOMEM;
+	}
+
+	if (!test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags))
+		return 0;
+
+	/*
+	 * Allocate the BEACON ring.
+	 */
+	if (rt2x00lib_alloc_entries(&rt2x00dev->bcn[0], BEACON_ENTRIES,
+				    MGMT_FRAME_SIZE, rt2x00dev->ops->txd_size))
+		return -ENOMEM;
+
+	/*
+	 * Allocate the Atim ring.
+	 */
+	if (rt2x00lib_alloc_entries(&rt2x00dev->bcn[1], ATIM_ENTRIES,
+				    DATA_FRAME_SIZE, rt2x00dev->ops->txd_size))
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void rt2x00lib_free_ring_entries(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_ring *ring;
+
+	ring_for_each(rt2x00dev, ring) {
+		kfree(ring->entry);
+		ring->entry = NULL;
+	}
+}
+
+void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev)
+{
+	if (!__test_and_clear_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
+		return;
+
+	/*
+	 * Unregister rfkill.
+	 */
+	rt2x00rfkill_unregister(rt2x00dev);
+
+	/*
+	 * Allow the HW to uninitialize.
+	 */
+	rt2x00dev->ops->lib->uninitialize(rt2x00dev);
+
+	/*
+	 * Free allocated ring entries.
+	 */
+	rt2x00lib_free_ring_entries(rt2x00dev);
+}
+
+int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev)
+{
+	int status;
+
+	if (test_bit(DEVICE_INITIALIZED, &rt2x00dev->flags))
+		return 0;
+
+	/*
+	 * Allocate all ring entries.
+	 */
+	status = rt2x00lib_alloc_ring_entries(rt2x00dev);
+	if (status) {
+		ERROR(rt2x00dev, "Ring entries allocation failed.\n");
+		return status;
+	}
+
+	/*
+	 * Initialize the device.
+	 */
+	status = rt2x00dev->ops->lib->initialize(rt2x00dev);
+	if (status)
+		goto exit;
+
+	__set_bit(DEVICE_INITIALIZED, &rt2x00dev->flags);
+
+	/*
+	 * Register the rfkill handler.
+	 */
+	status = rt2x00rfkill_register(rt2x00dev);
+	if (status)
+		goto exit_unitialize;
+
+	return 0;
+
+exit_unitialize:
+	rt2x00lib_uninitialize(rt2x00dev);
+
+exit:
+	rt2x00lib_free_ring_entries(rt2x00dev);
+
+	return status;
+}
+
+/*
+ * driver allocation handlers.
+ */
+static int rt2x00lib_alloc_rings(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_ring *ring;
+
+	/*
+	 * We need the following rings:
+	 * RX: 1
+	 * TX: hw->queues
+	 * Beacon: 1 (if required)
+	 * Atim: 1 (if required)
+	 */
+	rt2x00dev->data_rings = 1 + rt2x00dev->hw->queues +
+	    (2 * test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags));
+
+	ring = kzalloc(rt2x00dev->data_rings * sizeof(*ring), GFP_KERNEL);
+	if (!ring) {
+		ERROR(rt2x00dev, "Ring allocation failed.\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * Initialize pointers
+	 */
+	rt2x00dev->rx = ring;
+	rt2x00dev->tx = &rt2x00dev->rx[1];
+	if (test_bit(DRIVER_REQUIRE_BEACON_RING, &rt2x00dev->flags))
+		rt2x00dev->bcn = &rt2x00dev->tx[rt2x00dev->hw->queues];
+
+	/*
+	 * Initialize ring parameters.
+	 * cw_min: 2^5 = 32.
+	 * cw_max: 2^10 = 1024.
+	 */
+	ring_for_each(rt2x00dev, ring) {
+		ring->rt2x00dev = rt2x00dev;
+		ring->tx_params.aifs = 2;
+		ring->tx_params.cw_min = 5;
+		ring->tx_params.cw_max = 10;
+	}
+
+	return 0;
+}
+
+static void rt2x00lib_free_rings(struct rt2x00_dev *rt2x00dev)
+{
+	kfree(rt2x00dev->rx);
+	rt2x00dev->rx = NULL;
+	rt2x00dev->tx = NULL;
+	rt2x00dev->bcn = NULL;
+}
+
+int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
+{
+	int retval = -ENOMEM;
+
+	/*
+	 * Let the driver probe the device to detect the capabilities.
+	 */
+	retval = rt2x00dev->ops->lib->probe_hw(rt2x00dev);
+	if (retval) {
+		ERROR(rt2x00dev, "Failed to allocate device.\n");
+		goto exit;
+	}
+
+	/*
+	 * Initialize configuration work.
+	 */
+	INIT_WORK(&rt2x00dev->beacon_work, rt2x00lib_beacondone_scheduled);
+	INIT_WORK(&rt2x00dev->filter_work, rt2x00lib_packetfilter_scheduled);
+	INIT_WORK(&rt2x00dev->config_work, rt2x00lib_configuration_scheduled);
+	INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00lib_link_tuner);
+
+	/*
+	 * Reset current working type.
+	 */
+	rt2x00dev->interface.type = INVALID_INTERFACE;
+
+	/*
+	 * Allocate ring array.
+	 */
+	retval = rt2x00lib_alloc_rings(rt2x00dev);
+	if (retval)
+		goto exit;
+
+	/*
+	 * Initialize ieee80211 structure.
+	 */
+	retval = rt2x00lib_probe_hw(rt2x00dev);
+	if (retval) {
+		ERROR(rt2x00dev, "Failed to initialize hw.\n");
+		goto exit;
+	}
+
+	/*
+	 * Allocatie rfkill.
+	 */
+	retval = rt2x00rfkill_allocate(rt2x00dev);
+	if (retval)
+		goto exit;
+
+	/*
+	 * Open the debugfs entry.
+	 */
+	rt2x00debug_register(rt2x00dev);
+
+	__set_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+
+	return 0;
+
+exit:
+	rt2x00lib_remove_dev(rt2x00dev);
+
+	return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_probe_dev);
+
+void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
+{
+	__clear_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+
+	/*
+	 * Disable radio.
+	 */
+	rt2x00lib_disable_radio(rt2x00dev);
+
+	/*
+	 * Uninitialize device.
+	 */
+	rt2x00lib_uninitialize(rt2x00dev);
+
+	/*
+	 * Close debugfs entry.
+	 */
+	rt2x00debug_deregister(rt2x00dev);
+
+	/*
+	 * Free rfkill
+	 */
+	rt2x00rfkill_free(rt2x00dev);
+
+	/*
+	 * Free ieee80211_hw memory.
+	 */
+	rt2x00lib_remove_hw(rt2x00dev);
+
+	/*
+	 * Free firmware image.
+	 */
+	rt2x00lib_free_firmware(rt2x00dev);
+
+	/*
+	 * Free ring structures.
+	 */
+	rt2x00lib_free_rings(rt2x00dev);
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_remove_dev);
+
+/*
+ * Device state handlers
+ */
+#ifdef CONFIG_PM
+int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state)
+{
+	int retval;
+
+	NOTICE(rt2x00dev, "Going to sleep.\n");
+	__clear_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+
+	/*
+	 * Only continue if mac80211 has open interfaces.
+	 */
+	if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+		goto exit;
+	__set_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags);
+
+	/*
+	 * Disable radio and unitialize all items
+	 * that must be recreated on resume.
+	 */
+	rt2x00mac_stop(rt2x00dev->hw);
+	rt2x00lib_uninitialize(rt2x00dev);
+	rt2x00debug_deregister(rt2x00dev);
+
+exit:
+	/*
+	 * Set device mode to sleep for power management.
+	 */
+	retval = rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_SLEEP);
+	if (retval)
+		return retval;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_suspend);
+
+int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
+{
+	struct interface *intf = &rt2x00dev->interface;
+	int retval;
+
+	NOTICE(rt2x00dev, "Waking up.\n");
+	__set_bit(DEVICE_PRESENT, &rt2x00dev->flags);
+
+	/*
+	 * Open the debugfs entry.
+	 */
+	rt2x00debug_register(rt2x00dev);
+
+	/*
+	 * Only continue if mac80211 had open interfaces.
+	 */
+	if (!__test_and_clear_bit(DEVICE_STARTED_SUSPEND, &rt2x00dev->flags))
+		return 0;
+
+	/*
+	 * Reinitialize device and all active interfaces.
+	 */
+	retval = rt2x00mac_start(rt2x00dev->hw);
+	if (retval)
+		goto exit;
+
+	/*
+	 * Reconfigure device.
+	 */
+	rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, 1);
+	if (!rt2x00dev->hw->conf.radio_enabled)
+		rt2x00lib_disable_radio(rt2x00dev);
+
+	rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
+	rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
+	rt2x00lib_config_type(rt2x00dev, intf->type);
+
+	/*
+	 * It is possible that during that mac80211 has attempted
+	 * to send frames while we were suspending or resuming.
+	 * In that case we have disabled the TX queue and should
+	 * now enable it again
+	 */
+	ieee80211_start_queues(rt2x00dev->hw);
+
+	/*
+	 * When in Master or Ad-hoc mode,
+	 * restart Beacon transmitting by faking a beacondone event.
+	 */
+	if (intf->type == IEEE80211_IF_TYPE_AP ||
+	    intf->type == IEEE80211_IF_TYPE_IBSS)
+		rt2x00lib_beacondone(rt2x00dev);
+
+	return 0;
+
+exit:
+	rt2x00lib_disable_radio(rt2x00dev);
+	rt2x00lib_uninitialize(rt2x00dev);
+	rt2x00debug_deregister(rt2x00dev);
+
+	return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00lib_resume);
+#endif /* CONFIG_PM */
+
+/*
+ * rt2x00lib module information.
+ */
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("rt2x00 library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c
new file mode 100644
index 0000000..236025f
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c
@@ -0,0 +1,124 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2x00lib
+	Abstract: rt2x00 firmware loading routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/crc-itu-t.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev)
+{
+	struct device *device = wiphy_dev(rt2x00dev->hw->wiphy);
+	const struct firmware *fw;
+	char *fw_name;
+	int retval;
+	u16 crc;
+	u16 tmp;
+
+	/*
+	 * Read correct firmware from harddisk.
+	 */
+	fw_name = rt2x00dev->ops->lib->get_firmware_name(rt2x00dev);
+	if (!fw_name) {
+		ERROR(rt2x00dev,
+		      "Invalid firmware filename.\n"
+		      "Please file bug report to %s.\n", DRV_PROJECT);
+		return -EINVAL;
+	}
+
+	INFO(rt2x00dev, "Loading firmware file '%s'.\n", fw_name);
+
+	retval = request_firmware(&fw, fw_name, device);
+	if (retval) {
+		ERROR(rt2x00dev, "Failed to request Firmware.\n");
+		return retval;
+	}
+
+	if (!fw || !fw->size || !fw->data) {
+		ERROR(rt2x00dev, "Failed to read Firmware.\n");
+		return -ENOENT;
+	}
+
+	/*
+	 * Validate the firmware using 16 bit CRC.
+	 * The last 2 bytes of the firmware are the CRC
+	 * so substract those 2 bytes from the CRC checksum,
+	 * and set those 2 bytes to 0 when calculating CRC.
+	 */
+	tmp = 0;
+	crc = crc_itu_t(0, fw->data, fw->size - 2);
+	crc = crc_itu_t(crc, (u8 *)&tmp, 2);
+
+	if (crc != (fw->data[fw->size - 2] << 8 | fw->data[fw->size - 1])) {
+		ERROR(rt2x00dev, "Firmware CRC error.\n");
+		retval = -ENOENT;
+		goto exit;
+	}
+
+	INFO(rt2x00dev, "Firmware detected - version: %d.%d.\n",
+	     fw->data[fw->size - 4], fw->data[fw->size - 3]);
+
+	rt2x00dev->fw = fw;
+
+	return 0;
+
+exit:
+	release_firmware(fw);
+
+	return retval;
+}
+
+int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
+{
+	int retval;
+
+	if (!rt2x00dev->fw) {
+		retval = rt2x00lib_request_firmware(rt2x00dev);
+		if (retval)
+			return retval;
+	}
+
+	/*
+	 * Send firmware to the device.
+	 */
+	retval = rt2x00dev->ops->lib->load_firmware(rt2x00dev,
+						    rt2x00dev->fw->data,
+						    rt2x00dev->fw->size);
+	return retval;
+}
+
+void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
+{
+	release_firmware(rt2x00dev->fw);
+	rt2x00dev->fw = NULL;
+}
+
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
new file mode 100644
index 0000000..298faa9d
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -0,0 +1,119 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2x00lib
+	Abstract: Data structures and definitions for the rt2x00lib module.
+ */
+
+#ifndef RT2X00LIB_H
+#define RT2X00LIB_H
+
+/*
+ * Interval defines
+ * Both the link tuner as the rfkill will be called once per second.
+ */
+#define LINK_TUNE_INTERVAL	( round_jiffies(HZ) )
+#define RFKILL_POLL_INTERVAL	( 1000 )
+
+/*
+ * Radio control handlers.
+ */
+int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state);
+void rt2x00lib_reset_link_tuner(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * Initialization handlers.
+ */
+int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * Configuration handlers.
+ */
+void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac);
+void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid);
+void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type);
+void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
+		      struct ieee80211_conf *conf, const int force_config);
+
+/*
+ * Firmware handlers.
+ */
+#ifdef CONFIG_RT2X00_LIB_FIRMWARE
+int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev);
+void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev);
+#else
+static inline int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
+{
+	return 0;
+}
+static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
+{
+}
+#endif /* CONFIG_RT2X00_LIB_FIRMWARE */
+
+/*
+ * Debugfs handlers.
+ */
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+void rt2x00debug_register(struct rt2x00_dev *rt2x00dev);
+void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
+#else
+static inline void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
+{
+}
+
+static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
+{
+}
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+/*
+ * RFkill handlers.
+ */
+#ifdef CONFIG_RT2X00_LIB_RFKILL
+int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev);
+void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev);
+int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev);
+void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev);
+#else
+static inline int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
+{
+	return 0;
+}
+
+static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
+{
+}
+
+static inline int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
+{
+	return 0;
+}
+
+static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
+{
+}
+#endif /* CONFIG_RT2X00_LIB_RFKILL */
+
+#endif /* RT2X00LIB_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
new file mode 100644
index 0000000..4a6a0bd
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -0,0 +1,438 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2x00mac
+	Abstract: rt2x00 generic mac80211 routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev,
+				struct data_ring *ring,
+				struct sk_buff *frag_skb,
+				struct ieee80211_tx_control *control)
+{
+	struct sk_buff *skb;
+	int size;
+
+	if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+		size = sizeof(struct ieee80211_cts);
+	else
+		size = sizeof(struct ieee80211_rts);
+
+	skb = dev_alloc_skb(size + rt2x00dev->hw->extra_tx_headroom);
+	if (!skb) {
+		WARNING(rt2x00dev, "Failed to create RTS/CTS frame.\n");
+		return NETDEV_TX_BUSY;
+	}
+
+	skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom);
+	skb_put(skb, size);
+
+	if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
+		ieee80211_ctstoself_get(rt2x00dev->hw, rt2x00dev->interface.id,
+					frag_skb->data, frag_skb->len, control,
+					(struct ieee80211_cts *)(skb->data));
+	else
+		ieee80211_rts_get(rt2x00dev->hw, rt2x00dev->interface.id,
+				  frag_skb->data, frag_skb->len, control,
+				  (struct ieee80211_rts *)(skb->data));
+
+	if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control)) {
+		WARNING(rt2x00dev, "Failed to send RTS/CTS frame.\n");
+		return NETDEV_TX_BUSY;
+	}
+
+	return NETDEV_TX_OK;
+}
+
+int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+		 struct ieee80211_tx_control *control)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
+	struct data_ring *ring;
+	u16 frame_control;
+
+	/*
+	 * Mac80211 might be calling this function while we are trying
+	 * to remove the device or perhaps suspending it.
+	 * Note that we can only stop the TX queues inside the TX path
+	 * due to possible race conditions in mac80211.
+	 */
+	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags)) {
+		ieee80211_stop_queues(hw);
+		return 0;
+	}
+
+	/*
+	 * Determine which ring to put packet on.
+	 */
+	ring = rt2x00lib_get_ring(rt2x00dev, control->queue);
+	if (unlikely(!ring)) {
+		ERROR(rt2x00dev,
+		      "Attempt to send packet over invalid queue %d.\n"
+		      "Please file bug report to %s.\n",
+		      control->queue, DRV_PROJECT);
+		dev_kfree_skb_any(skb);
+		return NETDEV_TX_OK;
+	}
+
+	/*
+	 * If CTS/RTS is required. and this frame is not CTS or RTS,
+	 * create and queue that frame first. But make sure we have
+	 * at least enough entries available to send this CTS/RTS
+	 * frame as well as the data frame.
+	 */
+	frame_control = le16_to_cpu(ieee80211hdr->frame_control);
+	if (!is_rts_frame(frame_control) && !is_cts_frame(frame_control) &&
+	    (control->flags & (IEEE80211_TXCTL_USE_RTS_CTS |
+			       IEEE80211_TXCTL_USE_CTS_PROTECT))) {
+		if (rt2x00_ring_free(ring) <= 1)
+			return NETDEV_TX_BUSY;
+
+		if (rt2x00mac_tx_rts_cts(rt2x00dev, ring, skb, control))
+			return NETDEV_TX_BUSY;
+	}
+
+	if (rt2x00dev->ops->lib->write_tx_data(rt2x00dev, ring, skb, control))
+		return NETDEV_TX_BUSY;
+
+	if (rt2x00dev->ops->lib->kick_tx_queue)
+		rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
+
+	return NETDEV_TX_OK;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_tx);
+
+int rt2x00mac_start(struct ieee80211_hw *hw)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	int status;
+
+	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
+	    test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+		return 0;
+
+	/*
+	 * If this is the first interface which is added,
+	 * we should load the firmware now.
+	 */
+	if (test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) {
+		status = rt2x00lib_load_firmware(rt2x00dev);
+		if (status)
+			return status;
+	}
+
+	/*
+	 * Initialize the device.
+	 */
+	status = rt2x00lib_initialize(rt2x00dev);
+	if (status)
+		return status;
+
+	/*
+	 * Enable radio.
+	 */
+	status = rt2x00lib_enable_radio(rt2x00dev);
+	if (status) {
+		rt2x00lib_uninitialize(rt2x00dev);
+		return status;
+	}
+
+	__set_bit(DEVICE_STARTED, &rt2x00dev->flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_start);
+
+void rt2x00mac_stop(struct ieee80211_hw *hw)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+
+	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+		return;
+
+	/*
+	 * Perhaps we can add something smarter here,
+	 * but for now just disabling the radio should do.
+	 */
+	rt2x00lib_disable_radio(rt2x00dev);
+
+	__clear_bit(DEVICE_STARTED, &rt2x00dev->flags);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_stop);
+
+int rt2x00mac_add_interface(struct ieee80211_hw *hw,
+			    struct ieee80211_if_init_conf *conf)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct interface *intf = &rt2x00dev->interface;
+
+	/*
+	 * Don't allow interfaces to be added while
+	 * either the device has disappeared or when
+	 * another interface is already present.
+	 */
+	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
+	    is_interface_present(intf))
+		return -ENOBUFS;
+
+	intf->id = conf->if_id;
+	intf->type = conf->type;
+	if (conf->type == IEEE80211_IF_TYPE_AP)
+		memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN);
+	memcpy(&intf->mac, conf->mac_addr, ETH_ALEN);
+
+	/*
+	 * The MAC adddress must be configured after the device
+	 * has been initialized. Otherwise the device can reset
+	 * the MAC registers.
+	 */
+	rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
+	rt2x00lib_config_type(rt2x00dev, conf->type);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_add_interface);
+
+void rt2x00mac_remove_interface(struct ieee80211_hw *hw,
+				struct ieee80211_if_init_conf *conf)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct interface *intf = &rt2x00dev->interface;
+
+	/*
+	 * Don't allow interfaces to be remove while
+	 * either the device has disappeared or when
+	 * no interface is present.
+	 */
+	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags) ||
+	    !is_interface_present(intf))
+		return;
+
+	intf->id = 0;
+	intf->type = INVALID_INTERFACE;
+	memset(&intf->bssid, 0x00, ETH_ALEN);
+	memset(&intf->mac, 0x00, ETH_ALEN);
+
+	/*
+	 * Make sure the bssid and mac address registers
+	 * are cleared to prevent false ACKing of frames.
+	 */
+	rt2x00lib_config_mac_addr(rt2x00dev, intf->mac);
+	rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
+	rt2x00lib_config_type(rt2x00dev, intf->type);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface);
+
+int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+
+	/*
+	 * Mac80211 might be calling this function while we are trying
+	 * to remove the device or perhaps suspending it.
+	 */
+	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+		return 0;
+
+	/*
+	 * Check if we need to disable the radio,
+	 * if this is not the case, at least the RX must be disabled.
+	 */
+	if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) {
+		if (!conf->radio_enabled)
+			rt2x00lib_disable_radio(rt2x00dev);
+		else
+			rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF);
+	}
+
+	rt2x00lib_config(rt2x00dev, conf, 0);
+
+	/*
+	 * Reenable RX only if the radio should be on.
+	 */
+	if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+		rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON);
+	else if (conf->radio_enabled)
+		return rt2x00lib_enable_radio(rt2x00dev);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_config);
+
+int rt2x00mac_config_interface(struct ieee80211_hw *hw, int if_id,
+			       struct ieee80211_if_conf *conf)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct interface *intf = &rt2x00dev->interface;
+	int status;
+
+	/*
+	 * Mac80211 might be calling this function while we are trying
+	 * to remove the device or perhaps suspending it.
+	 */
+	if (!test_bit(DEVICE_PRESENT, &rt2x00dev->flags))
+		return 0;
+
+	/*
+	 * If the given type does not match the configured type,
+	 * there has been a problem.
+	 */
+	if (conf->type != intf->type)
+		return -EINVAL;
+
+	/*
+	 * If the interface does not work in master mode,
+	 * then the bssid value in the interface structure
+	 * should now be set.
+	 */
+	if (conf->type != IEEE80211_IF_TYPE_AP)
+		memcpy(&intf->bssid, conf->bssid, ETH_ALEN);
+	rt2x00lib_config_bssid(rt2x00dev, intf->bssid);
+
+	/*
+	 * We only need to initialize the beacon when master mode is enabled.
+	 */
+	if (conf->type != IEEE80211_IF_TYPE_AP || !conf->beacon)
+		return 0;
+
+	status = rt2x00dev->ops->hw->beacon_update(rt2x00dev->hw,
+						   conf->beacon,
+						   conf->beacon_control);
+	if (status)
+		dev_kfree_skb(conf->beacon);
+
+	return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_config_interface);
+
+int rt2x00mac_get_stats(struct ieee80211_hw *hw,
+			struct ieee80211_low_level_stats *stats)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+
+	/*
+	 * The dot11ACKFailureCount, dot11RTSFailureCount and
+	 * dot11RTSSuccessCount are updated in interrupt time.
+	 * dot11FCSErrorCount is updated in the link tuner.
+	 */
+	memcpy(stats, &rt2x00dev->low_level_stats, sizeof(*stats));
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_get_stats);
+
+int rt2x00mac_get_tx_stats(struct ieee80211_hw *hw,
+			   struct ieee80211_tx_queue_stats *stats)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	unsigned int i;
+
+	for (i = 0; i < hw->queues; i++)
+		memcpy(&stats->data[i], &rt2x00dev->tx[i].stats,
+		       sizeof(rt2x00dev->tx[i].stats));
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_get_tx_stats);
+
+void rt2x00mac_erp_ie_changed(struct ieee80211_hw *hw, u8 changes,
+			      int cts_protection, int preamble)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	int short_preamble;
+	int ack_timeout;
+	int ack_consume_time;
+	int difs;
+
+	/*
+	 * We only support changing preamble mode.
+	 */
+	if (!(changes & IEEE80211_ERP_CHANGE_PREAMBLE))
+		return;
+
+	short_preamble = !preamble;
+	preamble = !!(preamble) ? PREAMBLE : SHORT_PREAMBLE;
+
+	difs = (hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) ?
+		SHORT_DIFS : DIFS;
+	ack_timeout = difs + PLCP + preamble + get_duration(ACK_SIZE, 10);
+
+	ack_consume_time = SIFS + PLCP + preamble + get_duration(ACK_SIZE, 10);
+
+	if (short_preamble)
+		__set_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
+	else
+		__clear_bit(CONFIG_SHORT_PREAMBLE, &rt2x00dev->flags);
+
+	rt2x00dev->ops->lib->config_preamble(rt2x00dev, short_preamble,
+					     ack_timeout, ack_consume_time);
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_erp_ie_changed);
+
+int rt2x00mac_conf_tx(struct ieee80211_hw *hw, int queue,
+		      const struct ieee80211_tx_queue_params *params)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct data_ring *ring;
+
+	ring = rt2x00lib_get_ring(rt2x00dev, queue);
+	if (unlikely(!ring))
+		return -EINVAL;
+
+	/*
+	 * The passed variables are stored as real value ((2^n)-1).
+	 * Ralink registers require to know the bit number 'n'.
+	 */
+	if (params->cw_min)
+		ring->tx_params.cw_min = fls(params->cw_min);
+	else
+		ring->tx_params.cw_min = 5; /* cw_min: 2^5 = 32. */
+
+	if (params->cw_max)
+		ring->tx_params.cw_max = fls(params->cw_max);
+	else
+		ring->tx_params.cw_max = 10; /* cw_min: 2^10 = 1024. */
+
+	if (params->aifs)
+		ring->tx_params.aifs = params->aifs;
+	else
+		ring->tx_params.aifs = 2;
+
+	INFO(rt2x00dev,
+	     "Configured TX ring %d - CWmin: %d, CWmax: %d, Aifs: %d.\n",
+	     queue, ring->tx_params.cw_min, ring->tx_params.cw_max,
+	     ring->tx_params.aifs);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_conf_tx);
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
new file mode 100644
index 0000000..2780df0
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -0,0 +1,474 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2x00pci
+	Abstract: rt2x00 generic pci device routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00pci"
+
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "rt2x00.h"
+#include "rt2x00pci.h"
+
+/*
+ * Beacon handlers.
+ */
+int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+			    struct ieee80211_tx_control *control)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct data_ring *ring =
+	    rt2x00lib_get_ring(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+	struct data_entry *entry = rt2x00_get_data_entry(ring);
+
+	/*
+	 * Just in case mac80211 doesn't set this correctly,
+	 * but we need this queue set for the descriptor
+	 * initialization.
+	 */
+	control->queue = IEEE80211_TX_QUEUE_BEACON;
+
+	/*
+	 * Update the beacon entry.
+	 */
+	memcpy(entry->data_addr, skb->data, skb->len);
+	rt2x00lib_write_tx_desc(rt2x00dev, entry->priv,
+				(struct ieee80211_hdr *)skb->data,
+				skb->len, control);
+
+	/*
+	 * Enable beacon generation.
+	 */
+	rt2x00dev->ops->lib->kick_tx_queue(rt2x00dev, control->queue);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_beacon_update);
+
+/*
+ * TX data handlers.
+ */
+int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
+			    struct data_ring *ring, struct sk_buff *skb,
+			    struct ieee80211_tx_control *control)
+{
+	struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data;
+	struct data_entry *entry = rt2x00_get_data_entry(ring);
+	struct data_desc *txd = entry->priv;
+	u32 word;
+
+	if (rt2x00_ring_full(ring)) {
+		ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+		return -EINVAL;
+	}
+
+	rt2x00_desc_read(txd, 0, &word);
+
+	if (rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) ||
+	    rt2x00_get_field32(word, TXD_ENTRY_VALID)) {
+		ERROR(rt2x00dev,
+		      "Arrived at non-free entry in the non-full queue %d.\n"
+		      "Please file bug report to %s.\n",
+		      control->queue, DRV_PROJECT);
+		ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+		return -EINVAL;
+	}
+
+	entry->skb = skb;
+	memcpy(&entry->tx_status.control, control, sizeof(*control));
+	memcpy(entry->data_addr, skb->data, skb->len);
+	rt2x00lib_write_tx_desc(rt2x00dev, txd, ieee80211hdr,
+				skb->len, control);
+
+	rt2x00_ring_index_inc(ring);
+
+	if (rt2x00_ring_full(ring))
+		ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
+
+/*
+ * RX data handlers.
+ */
+void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_ring *ring = rt2x00dev->rx;
+	struct data_entry *entry;
+	struct data_desc *rxd;
+	struct sk_buff *skb;
+	struct rxdata_entry_desc desc;
+	u32 word;
+
+	while (1) {
+		entry = rt2x00_get_data_entry(ring);
+		rxd = entry->priv;
+		rt2x00_desc_read(rxd, 0, &word);
+
+		if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC))
+			break;
+
+		memset(&desc, 0x00, sizeof(desc));
+		rt2x00dev->ops->lib->fill_rxdone(entry, &desc);
+
+		/*
+		 * Allocate the sk_buffer, initialize it and copy
+		 * all data into it.
+		 */
+		skb = dev_alloc_skb(desc.size + NET_IP_ALIGN);
+		if (!skb)
+			return;
+
+		skb_reserve(skb, NET_IP_ALIGN);
+		skb_put(skb, desc.size);
+		memcpy(skb->data, entry->data_addr, desc.size);
+
+		/*
+		 * Send the frame to rt2x00lib for further processing.
+		 */
+		rt2x00lib_rxdone(entry, skb, &desc);
+
+		if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
+			rt2x00_set_field32(&word, RXD_ENTRY_OWNER_NIC, 1);
+			rt2x00_desc_write(rxd, 0, word);
+		}
+
+		rt2x00_ring_index_inc(ring);
+	}
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
+
+/*
+ * Device initialization handlers.
+ */
+#define priv_offset(__ring, __i)				\
+({								\
+	ring->data_addr + (i * ring->desc_size);		\
+})
+
+#define data_addr_offset(__ring, __i)				\
+({								\
+	(__ring)->data_addr +					\
+	    ((__ring)->stats.limit * (__ring)->desc_size) +	\
+	    ((__i) * (__ring)->data_size);			\
+})
+
+#define data_dma_offset(__ring, __i)				\
+({								\
+	(__ring)->data_dma +					\
+	    ((__ring)->stats.limit * (__ring)->desc_size) +	\
+	    ((__i) * (__ring)->data_size);			\
+})
+
+static int rt2x00pci_alloc_dma(struct rt2x00_dev *rt2x00dev,
+			       struct data_ring *ring)
+{
+	unsigned int i;
+
+	/*
+	 * Allocate DMA memory for descriptor and buffer.
+	 */
+	ring->data_addr = pci_alloc_consistent(rt2x00dev_pci(rt2x00dev),
+					       rt2x00_get_ring_size(ring),
+					       &ring->data_dma);
+	if (!ring->data_addr)
+		return -ENOMEM;
+
+	/*
+	 * Initialize all ring entries to contain valid
+	 * addresses.
+	 */
+	for (i = 0; i < ring->stats.limit; i++) {
+		ring->entry[i].priv = priv_offset(ring, i);
+		ring->entry[i].data_addr = data_addr_offset(ring, i);
+		ring->entry[i].data_dma = data_dma_offset(ring, i);
+	}
+
+	return 0;
+}
+
+static void rt2x00pci_free_dma(struct rt2x00_dev *rt2x00dev,
+			       struct data_ring *ring)
+{
+	if (ring->data_addr)
+		pci_free_consistent(rt2x00dev_pci(rt2x00dev),
+				    rt2x00_get_ring_size(ring),
+				    ring->data_addr, ring->data_dma);
+	ring->data_addr = NULL;
+}
+
+int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev)
+{
+	struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
+	struct data_ring *ring;
+	int status;
+
+	/*
+	 * Allocate DMA
+	 */
+	ring_for_each(rt2x00dev, ring) {
+		status = rt2x00pci_alloc_dma(rt2x00dev, ring);
+		if (status)
+			goto exit;
+	}
+
+	/*
+	 * Register interrupt handler.
+	 */
+	status = request_irq(pci_dev->irq, rt2x00dev->ops->lib->irq_handler,
+			     IRQF_SHARED, pci_name(pci_dev), rt2x00dev);
+	if (status) {
+		ERROR(rt2x00dev, "IRQ %d allocation failed (error %d).\n",
+		      pci_dev->irq, status);
+		return status;
+	}
+
+	return 0;
+
+exit:
+	rt2x00pci_uninitialize(rt2x00dev);
+
+	return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_initialize);
+
+void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_ring *ring;
+
+	/*
+	 * Free irq line.
+	 */
+	free_irq(rt2x00dev_pci(rt2x00dev)->irq, rt2x00dev);
+
+	/*
+	 * Free DMA
+	 */
+	ring_for_each(rt2x00dev, ring)
+		rt2x00pci_free_dma(rt2x00dev, ring);
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_uninitialize);
+
+/*
+ * PCI driver handlers.
+ */
+static void rt2x00pci_free_reg(struct rt2x00_dev *rt2x00dev)
+{
+	kfree(rt2x00dev->rf);
+	rt2x00dev->rf = NULL;
+
+	kfree(rt2x00dev->eeprom);
+	rt2x00dev->eeprom = NULL;
+
+	if (rt2x00dev->csr_addr) {
+		iounmap(rt2x00dev->csr_addr);
+		rt2x00dev->csr_addr = NULL;
+	}
+}
+
+static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev)
+{
+	struct pci_dev *pci_dev = rt2x00dev_pci(rt2x00dev);
+
+	rt2x00dev->csr_addr = ioremap(pci_resource_start(pci_dev, 0),
+				      pci_resource_len(pci_dev, 0));
+	if (!rt2x00dev->csr_addr)
+		goto exit;
+
+	rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
+	if (!rt2x00dev->eeprom)
+		goto exit;
+
+	rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
+	if (!rt2x00dev->rf)
+		goto exit;
+
+	return 0;
+
+exit:
+	ERROR_PROBE("Failed to allocate registers.\n");
+
+	rt2x00pci_free_reg(rt2x00dev);
+
+	return -ENOMEM;
+}
+
+int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
+{
+	struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_data;
+	struct ieee80211_hw *hw;
+	struct rt2x00_dev *rt2x00dev;
+	int retval;
+
+	retval = pci_request_regions(pci_dev, pci_name(pci_dev));
+	if (retval) {
+		ERROR_PROBE("PCI request regions failed.\n");
+		return retval;
+	}
+
+	retval = pci_enable_device(pci_dev);
+	if (retval) {
+		ERROR_PROBE("Enable device failed.\n");
+		goto exit_release_regions;
+	}
+
+	pci_set_master(pci_dev);
+
+	if (pci_set_mwi(pci_dev))
+		ERROR_PROBE("MWI not available.\n");
+
+	if (pci_set_dma_mask(pci_dev, DMA_64BIT_MASK) &&
+	    pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) {
+		ERROR_PROBE("PCI DMA not supported.\n");
+		retval = -EIO;
+		goto exit_disable_device;
+	}
+
+	hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
+	if (!hw) {
+		ERROR_PROBE("Failed to allocate hardware.\n");
+		retval = -ENOMEM;
+		goto exit_disable_device;
+	}
+
+	pci_set_drvdata(pci_dev, hw);
+
+	rt2x00dev = hw->priv;
+	rt2x00dev->dev = pci_dev;
+	rt2x00dev->ops = ops;
+	rt2x00dev->hw = hw;
+
+	retval = rt2x00pci_alloc_reg(rt2x00dev);
+	if (retval)
+		goto exit_free_device;
+
+	retval = rt2x00lib_probe_dev(rt2x00dev);
+	if (retval)
+		goto exit_free_reg;
+
+	return 0;
+
+exit_free_reg:
+	rt2x00pci_free_reg(rt2x00dev);
+
+exit_free_device:
+	ieee80211_free_hw(hw);
+
+exit_disable_device:
+	if (retval != -EBUSY)
+		pci_disable_device(pci_dev);
+
+exit_release_regions:
+	pci_release_regions(pci_dev);
+
+	pci_set_drvdata(pci_dev, NULL);
+
+	return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_probe);
+
+void rt2x00pci_remove(struct pci_dev *pci_dev)
+{
+	struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+
+	/*
+	 * Free all allocated data.
+	 */
+	rt2x00lib_remove_dev(rt2x00dev);
+	rt2x00pci_free_reg(rt2x00dev);
+	ieee80211_free_hw(hw);
+
+	/*
+	 * Free the PCI device data.
+	 */
+	pci_set_drvdata(pci_dev, NULL);
+	pci_disable_device(pci_dev);
+	pci_release_regions(pci_dev);
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_remove);
+
+#ifdef CONFIG_PM
+int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state)
+{
+	struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	int retval;
+
+	retval = rt2x00lib_suspend(rt2x00dev, state);
+	if (retval)
+		return retval;
+
+	rt2x00pci_free_reg(rt2x00dev);
+
+	pci_save_state(pci_dev);
+	pci_disable_device(pci_dev);
+	return pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_suspend);
+
+int rt2x00pci_resume(struct pci_dev *pci_dev)
+{
+	struct ieee80211_hw *hw = pci_get_drvdata(pci_dev);
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	int retval;
+
+	if (pci_set_power_state(pci_dev, PCI_D0) ||
+	    pci_enable_device(pci_dev) ||
+	    pci_restore_state(pci_dev)) {
+		ERROR(rt2x00dev, "Failed to resume device.\n");
+		return -EIO;
+	}
+
+	retval = rt2x00pci_alloc_reg(rt2x00dev);
+	if (retval)
+		return retval;
+
+	retval = rt2x00lib_resume(rt2x00dev);
+	if (retval)
+		goto exit_free_reg;
+
+	return 0;
+
+exit_free_reg:
+	rt2x00pci_free_reg(rt2x00dev);
+
+	return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_resume);
+#endif /* CONFIG_PM */
+
+/*
+ * rt2x00pci module information.
+ */
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("rt2x00 library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
new file mode 100644
index 0000000..82adeac
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -0,0 +1,127 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2x00pci
+	Abstract: Data structures for the rt2x00pci module.
+ */
+
+#ifndef RT2X00PCI_H
+#define RT2X00PCI_H
+
+#include <linux/io.h>
+
+/*
+ * This variable should be used with the
+ * pci_driver structure initialization.
+ */
+#define PCI_DEVICE_DATA(__ops)	.driver_data = (kernel_ulong_t)(__ops)
+
+/*
+ * Register defines.
+ * Some registers require multiple attempts before success,
+ * in those cases REGISTER_BUSY_COUNT attempts should be
+ * taken with a REGISTER_BUSY_DELAY interval.
+ */
+#define REGISTER_BUSY_COUNT	5
+#define REGISTER_BUSY_DELAY	100
+
+/*
+ * Descriptor availability flags.
+ * All PCI device descriptors have these 2 flags
+ * with the exact same definition.
+ * By storing them here we can use them inside rt2x00pci
+ * for some simple entry availability checking.
+ */
+#define TXD_ENTRY_OWNER_NIC	FIELD32(0x00000001)
+#define TXD_ENTRY_VALID		FIELD32(0x00000002)
+#define RXD_ENTRY_OWNER_NIC	FIELD32(0x00000001)
+
+/*
+ * Register access.
+ */
+static inline void rt2x00pci_register_read(const struct rt2x00_dev *rt2x00dev,
+					   const unsigned long offset,
+					   u32 *value)
+{
+	*value = readl(rt2x00dev->csr_addr + offset);
+}
+
+static inline void
+rt2x00pci_register_multiread(const struct rt2x00_dev *rt2x00dev,
+			     const unsigned long offset,
+			     void *value, const u16 length)
+{
+	memcpy_fromio(value, rt2x00dev->csr_addr + offset, length);
+}
+
+static inline void rt2x00pci_register_write(const struct rt2x00_dev *rt2x00dev,
+					    const unsigned long offset,
+					    u32 value)
+{
+	writel(value, rt2x00dev->csr_addr + offset);
+}
+
+static inline void
+rt2x00pci_register_multiwrite(const struct rt2x00_dev *rt2x00dev,
+			      const unsigned long offset,
+			      void *value, const u16 length)
+{
+	memcpy_toio(rt2x00dev->csr_addr + offset, value, length);
+}
+
+/*
+ * Beacon handlers.
+ */
+int rt2x00pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+			    struct ieee80211_tx_control *control);
+
+/*
+ * TX data handlers.
+ */
+int rt2x00pci_write_tx_data(struct rt2x00_dev *rt2x00dev,
+			    struct data_ring *ring, struct sk_buff *skb,
+			    struct ieee80211_tx_control *control);
+
+/*
+ * RX data handlers.
+ */
+void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * Device initialization handlers.
+ */
+int rt2x00pci_initialize(struct rt2x00_dev *rt2x00dev);
+void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * PCI driver handlers.
+ */
+int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id);
+void rt2x00pci_remove(struct pci_dev *pci_dev);
+#ifdef CONFIG_PM
+int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state);
+int rt2x00pci_resume(struct pci_dev *pci_dev);
+#else
+#define rt2x00pci_suspend	NULL
+#define rt2x00pci_resume	NULL
+#endif /* CONFIG_PM */
+
+#endif /* RT2X00PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00reg.h b/drivers/net/wireless/rt2x00/rt2x00reg.h
new file mode 100644
index 0000000..8384212
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00reg.h
@@ -0,0 +1,292 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2x00
+	Abstract: rt2x00 generic register information.
+ */
+
+#ifndef RT2X00REG_H
+#define RT2X00REG_H
+
+/*
+ * TX result flags.
+ */
+enum TX_STATUS {
+	TX_SUCCESS = 0,
+	TX_SUCCESS_RETRY = 1,
+	TX_FAIL_RETRY = 2,
+	TX_FAIL_INVALID = 3,
+	TX_FAIL_OTHER = 4,
+};
+
+/*
+ * Antenna values
+ */
+enum antenna {
+	ANTENNA_SW_DIVERSITY = 0,
+	ANTENNA_A = 1,
+	ANTENNA_B = 2,
+	ANTENNA_HW_DIVERSITY = 3,
+};
+
+/*
+ * Led mode values.
+ */
+enum led_mode {
+	LED_MODE_DEFAULT = 0,
+	LED_MODE_TXRX_ACTIVITY = 1,
+	LED_MODE_SIGNAL_STRENGTH = 2,
+	LED_MODE_ASUS = 3,
+	LED_MODE_ALPHA = 4,
+};
+
+/*
+ * TSF sync values
+ */
+enum tsf_sync {
+	TSF_SYNC_NONE = 0,
+	TSF_SYNC_INFRA = 1,
+	TSF_SYNC_BEACON = 2,
+};
+
+/*
+ * Device states
+ */
+enum dev_state {
+	STATE_DEEP_SLEEP = 0,
+	STATE_SLEEP = 1,
+	STATE_STANDBY = 2,
+	STATE_AWAKE = 3,
+
+/*
+ * Additional device states, these values are
+ * not strict since they are not directly passed
+ * into the device.
+ */
+	STATE_RADIO_ON,
+	STATE_RADIO_OFF,
+	STATE_RADIO_RX_ON,
+	STATE_RADIO_RX_OFF,
+	STATE_RADIO_IRQ_ON,
+	STATE_RADIO_IRQ_OFF,
+};
+
+/*
+ * IFS backoff values
+ */
+enum ifs {
+	IFS_BACKOFF = 0,
+	IFS_SIFS = 1,
+	IFS_NEW_BACKOFF = 2,
+	IFS_NONE = 3,
+};
+
+/*
+ * Cipher types for hardware encryption
+ */
+enum cipher {
+	CIPHER_NONE = 0,
+	CIPHER_WEP64 = 1,
+	CIPHER_WEP128 = 2,
+	CIPHER_TKIP = 3,
+	CIPHER_AES = 4,
+/*
+ * The following fields were added by rt61pci and rt73usb.
+ */
+	CIPHER_CKIP64 = 5,
+	CIPHER_CKIP128 = 6,
+	CIPHER_TKIP_NO_MIC = 7,
+};
+
+/*
+ * Register handlers.
+ * We store the position of a register field inside a field structure,
+ * This will simplify the process of setting and reading a certain field
+ * inside the register while making sure the process remains byte order safe.
+ */
+struct rt2x00_field8 {
+	u8 bit_offset;
+	u8 bit_mask;
+};
+
+struct rt2x00_field16 {
+	u16 bit_offset;
+	u16 bit_mask;
+};
+
+struct rt2x00_field32 {
+	u32 bit_offset;
+	u32 bit_mask;
+};
+
+/*
+ * Power of two check, this will check
+ * if the mask that has been given contains
+ * and contiguous set of bits.
+ */
+#define is_power_of_two(x)	( !((x) & ((x)-1)) )
+#define low_bit_mask(x)		( ((x)-1) & ~(x) )
+#define is_valid_mask(x)	is_power_of_two(1 + (x) + low_bit_mask(x))
+
+#define FIELD8(__mask)				\
+({						\
+	BUILD_BUG_ON(!(__mask) ||		\
+		     !is_valid_mask(__mask) ||	\
+		     (__mask) != (u8)(__mask));	\
+	(struct rt2x00_field8) {		\
+		__ffs(__mask), (__mask)		\
+	};					\
+})
+
+#define FIELD16(__mask)				\
+({						\
+	BUILD_BUG_ON(!(__mask) ||		\
+		     !is_valid_mask(__mask) ||	\
+		     (__mask) != (u16)(__mask));\
+	(struct rt2x00_field16) {		\
+		__ffs(__mask), (__mask)		\
+	};					\
+})
+
+#define FIELD32(__mask)				\
+({						\
+	BUILD_BUG_ON(!(__mask) ||		\
+		     !is_valid_mask(__mask) ||	\
+		     (__mask) != (u32)(__mask));\
+	(struct rt2x00_field32) {		\
+		__ffs(__mask), (__mask)		\
+	};					\
+})
+
+static inline void rt2x00_set_field32(u32 *reg,
+				      const struct rt2x00_field32 field,
+				      const u32 value)
+{
+	*reg &= ~(field.bit_mask);
+	*reg |= (value << field.bit_offset) & field.bit_mask;
+}
+
+static inline u32 rt2x00_get_field32(const u32 reg,
+				     const struct rt2x00_field32 field)
+{
+	return (reg & field.bit_mask) >> field.bit_offset;
+}
+
+static inline void rt2x00_set_field16(u16 *reg,
+				      const struct rt2x00_field16 field,
+				      const u16 value)
+{
+	*reg &= ~(field.bit_mask);
+	*reg |= (value << field.bit_offset) & field.bit_mask;
+}
+
+static inline u16 rt2x00_get_field16(const u16 reg,
+				     const struct rt2x00_field16 field)
+{
+	return (reg & field.bit_mask) >> field.bit_offset;
+}
+
+static inline void rt2x00_set_field8(u8 *reg,
+				     const struct rt2x00_field8 field,
+				     const u8 value)
+{
+	*reg &= ~(field.bit_mask);
+	*reg |= (value << field.bit_offset) & field.bit_mask;
+}
+
+static inline u8 rt2x00_get_field8(const u8 reg,
+				   const struct rt2x00_field8 field)
+{
+	return (reg & field.bit_mask) >> field.bit_offset;
+}
+
+/*
+ * Device specific rate value.
+ * We will have to create the device specific rate value
+ * passed to the ieee80211 kernel. We need to make it a consist of
+ * multiple fields because we want to store more then 1 device specific
+ * values inside the value.
+ *	1 - rate, stored as 100 kbit/s.
+ *	2 - preamble, short_preamble enabled flag.
+ *	3 - MASK_RATE, which rates are enabled in this mode, this mask
+ *	corresponds with the TX register format for the current device.
+ *	4 - plcp, 802.11b rates are device specific,
+ *	802.11g rates are set according to the ieee802.11a-1999 p.14.
+ * The bit to enable preamble is set in a seperate define.
+ */
+#define DEV_RATE	FIELD32(0x000007ff)
+#define DEV_PREAMBLE	FIELD32(0x00000800)
+#define DEV_RATEMASK	FIELD32(0x00fff000)
+#define DEV_PLCP	FIELD32(0xff000000)
+
+/*
+ * Bitfields
+ */
+#define DEV_RATEBIT_1MB		( 1 << 0 )
+#define DEV_RATEBIT_2MB		( 1 << 1 )
+#define DEV_RATEBIT_5_5MB	( 1 << 2 )
+#define DEV_RATEBIT_11MB	( 1 << 3 )
+#define DEV_RATEBIT_6MB		( 1 << 4 )
+#define DEV_RATEBIT_9MB		( 1 << 5 )
+#define DEV_RATEBIT_12MB	( 1 << 6 )
+#define DEV_RATEBIT_18MB	( 1 << 7 )
+#define DEV_RATEBIT_24MB	( 1 << 8 )
+#define DEV_RATEBIT_36MB	( 1 << 9 )
+#define DEV_RATEBIT_48MB	( 1 << 10 )
+#define DEV_RATEBIT_54MB	( 1 << 11 )
+
+/*
+ * Bitmasks for DEV_RATEMASK
+ */
+#define DEV_RATEMASK_1MB	( (DEV_RATEBIT_1MB << 1) -1 )
+#define DEV_RATEMASK_2MB	( (DEV_RATEBIT_2MB << 1) -1 )
+#define DEV_RATEMASK_5_5MB	( (DEV_RATEBIT_5_5MB << 1) -1 )
+#define DEV_RATEMASK_11MB	( (DEV_RATEBIT_11MB << 1) -1 )
+#define DEV_RATEMASK_6MB	( (DEV_RATEBIT_6MB << 1) -1 )
+#define DEV_RATEMASK_9MB	( (DEV_RATEBIT_9MB << 1) -1 )
+#define DEV_RATEMASK_12MB	( (DEV_RATEBIT_12MB << 1) -1 )
+#define DEV_RATEMASK_18MB	( (DEV_RATEBIT_18MB << 1) -1 )
+#define DEV_RATEMASK_24MB	( (DEV_RATEBIT_24MB << 1) -1 )
+#define DEV_RATEMASK_36MB	( (DEV_RATEBIT_36MB << 1) -1 )
+#define DEV_RATEMASK_48MB	( (DEV_RATEBIT_48MB << 1) -1 )
+#define DEV_RATEMASK_54MB	( (DEV_RATEBIT_54MB << 1) -1 )
+
+/*
+ * Bitmask groups of bitrates
+ */
+#define DEV_BASIC_RATEMASK \
+	( DEV_RATEMASK_11MB | \
+	  DEV_RATEBIT_6MB | DEV_RATEBIT_12MB | DEV_RATEBIT_24MB )
+
+#define DEV_CCK_RATEMASK	( DEV_RATEMASK_11MB )
+#define DEV_OFDM_RATEMASK	( DEV_RATEMASK_54MB & ~DEV_CCK_RATEMASK )
+
+/*
+ * Macro's to set and get specific fields from the device specific val and val2
+ * fields inside the ieee80211_rate entry.
+ */
+#define DEVICE_SET_RATE_FIELD(__value, __mask) \
+	(int)( ((__value) << DEV_##__mask.bit_offset) & DEV_##__mask.bit_mask )
+
+#define DEVICE_GET_RATE_FIELD(__value, __mask) \
+	(int)( ((__value) & DEV_##__mask.bit_mask) >> DEV_##__mask.bit_offset )
+
+#endif /* RT2X00REG_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00rfkill.c b/drivers/net/wireless/rt2x00/rt2x00rfkill.c
new file mode 100644
index 0000000..a0f8b8e
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00rfkill.c
@@ -0,0 +1,146 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2x00rfkill
+	Abstract: rt2x00 rfkill routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00lib"
+
+#include <linux/input-polldev.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rfkill.h>
+
+#include "rt2x00.h"
+#include "rt2x00lib.h"
+
+static int rt2x00rfkill_toggle_radio(void *data, enum rfkill_state state)
+{
+	struct rt2x00_dev *rt2x00dev = data;
+	int retval = 0;
+
+	if (unlikely(!rt2x00dev))
+		return 0;
+
+	/*
+	 * Only continue if there are enabled interfaces.
+	 */
+	if (!test_bit(DEVICE_STARTED, &rt2x00dev->flags))
+		return 0;
+
+	if (state == RFKILL_STATE_ON) {
+		INFO(rt2x00dev, "Hardware button pressed, enabling radio.\n");
+		__clear_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
+		retval = rt2x00lib_enable_radio(rt2x00dev);
+	} else if (state == RFKILL_STATE_OFF) {
+		INFO(rt2x00dev, "Hardware button pressed, disabling radio.\n");
+		__set_bit(DEVICE_DISABLED_RADIO_HW, &rt2x00dev->flags);
+		rt2x00lib_disable_radio(rt2x00dev);
+	}
+
+	return retval;
+}
+
+static void rt2x00rfkill_poll(struct input_polled_dev *poll_dev)
+{
+	struct rt2x00_dev *rt2x00dev = poll_dev->private;
+	int state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
+
+	if (rt2x00dev->rfkill->state != state)
+		input_report_key(poll_dev->input, KEY_WLAN, 1);
+}
+
+int rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
+{
+	int retval;
+
+	if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+		return 0;
+
+	retval = rfkill_register(rt2x00dev->rfkill);
+	if (retval) {
+		ERROR(rt2x00dev, "Failed to register rfkill handler.\n");
+		return retval;
+	}
+
+	retval = input_register_polled_device(rt2x00dev->poll_dev);
+	if (retval) {
+		ERROR(rt2x00dev, "Failed to register polled device.\n");
+		rfkill_unregister(rt2x00dev->rfkill);
+		return retval;
+	}
+
+	return 0;
+}
+
+void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
+{
+	if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+		return;
+
+	input_unregister_polled_device(rt2x00dev->poll_dev);
+	rfkill_unregister(rt2x00dev->rfkill);
+}
+
+int rt2x00rfkill_allocate(struct rt2x00_dev *rt2x00dev)
+{
+	struct device *device = wiphy_dev(rt2x00dev->hw->wiphy);
+
+	if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+		return 0;
+
+	rt2x00dev->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN);
+	if (!rt2x00dev->rfkill) {
+		ERROR(rt2x00dev, "Failed to allocate rfkill handler.\n");
+		return -ENOMEM;
+	}
+
+	rt2x00dev->rfkill->name = rt2x00dev->ops->name;
+	rt2x00dev->rfkill->data = rt2x00dev;
+	rt2x00dev->rfkill->state = rt2x00dev->ops->lib->rfkill_poll(rt2x00dev);
+	rt2x00dev->rfkill->toggle_radio = rt2x00rfkill_toggle_radio;
+
+	rt2x00dev->poll_dev = input_allocate_polled_device();
+	if (!rt2x00dev->poll_dev) {
+		ERROR(rt2x00dev, "Failed to allocate polled device.\n");
+		rfkill_free(rt2x00dev->rfkill);
+		return -ENOMEM;
+	}
+
+	rt2x00dev->poll_dev->private = rt2x00dev;
+	rt2x00dev->poll_dev->poll = rt2x00rfkill_poll;
+	rt2x00dev->poll_dev->poll_interval = RFKILL_POLL_INTERVAL;
+
+	return 0;
+}
+
+void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
+{
+	if (!test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+		return;
+
+	input_free_polled_device(rt2x00dev->poll_dev);
+	rfkill_free(rt2x00dev->rfkill);
+}
diff --git a/drivers/net/wireless/rt2x00/rt2x00ring.h b/drivers/net/wireless/rt2x00/rt2x00ring.h
new file mode 100644
index 0000000..1a864d3
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00ring.h
@@ -0,0 +1,268 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2x00
+	Abstract: rt2x00 ring datastructures and routines
+ */
+
+#ifndef RT2X00RING_H
+#define RT2X00RING_H
+
+/*
+ * data_desc
+ * Each data entry also contains a descriptor which is used by the
+ * device to determine what should be done with the packet and
+ * what the current status is.
+ * This structure is greatly simplified, but the descriptors
+ * are basically a list of little endian 32 bit values.
+ * Make the array by default 1 word big, this will allow us
+ * to use sizeof() correctly.
+ */
+struct data_desc {
+	__le32 word[1];
+};
+
+/*
+ * rxdata_entry_desc
+ * Summary of information that has been read from the
+ * RX frame descriptor.
+ */
+struct rxdata_entry_desc {
+	int signal;
+	int rssi;
+	int ofdm;
+	int size;
+	int flags;
+};
+
+/*
+ * txdata_entry_desc
+ * Summary of information that should be written into the
+ * descriptor for sending a TX frame.
+ */
+struct txdata_entry_desc {
+	unsigned long flags;
+#define ENTRY_TXDONE		1
+#define ENTRY_TXD_RTS_FRAME	2
+#define ENTRY_TXD_OFDM_RATE	3
+#define ENTRY_TXD_MORE_FRAG	4
+#define ENTRY_TXD_REQ_TIMESTAMP	5
+#define ENTRY_TXD_BURST		6
+
+/*
+ * Queue ID. ID's 0-4 are data TX rings
+ */
+	int queue;
+#define QUEUE_MGMT		13
+#define QUEUE_RX		14
+#define QUEUE_OTHER		15
+
+	/*
+	 * PLCP values.
+	 */
+	u16 length_high;
+	u16 length_low;
+	u16 signal;
+	u16 service;
+
+	/*
+	 * Timing information
+	 */
+	int aifs;
+	int ifs;
+	int cw_min;
+	int cw_max;
+};
+
+/*
+ * data_entry
+ * The data ring is a list of data entries.
+ * Each entry holds a reference to the descriptor
+ * and the data buffer. For TX rings the reference to the
+ * sk_buff of the packet being transmitted is also stored here.
+ */
+struct data_entry {
+	/*
+	 * Status flags
+	 */
+	unsigned long flags;
+#define ENTRY_OWNER_NIC		1
+
+	/*
+	 * Ring we belong to.
+	 */
+	struct data_ring *ring;
+
+	/*
+	 * sk_buff for the packet which is being transmitted
+	 * in this entry (Only used with TX related rings).
+	 */
+	struct sk_buff *skb;
+
+	/*
+	 * Store a ieee80211_tx_status structure in each
+	 * ring entry, this will optimize the txdone
+	 * handler.
+	 */
+	struct ieee80211_tx_status tx_status;
+
+	/*
+	 * private pointer specific to driver.
+	 */
+	void *priv;
+
+	/*
+	 * Data address for this entry.
+	 */
+	void *data_addr;
+	dma_addr_t data_dma;
+};
+
+/*
+ * data_ring
+ * Data rings are used by the device to send and receive packets.
+ * The data_addr is the base address of the data memory.
+ * To determine at which point in the ring we are,
+ * have to use the rt2x00_ring_index_*() functions.
+ */
+struct data_ring {
+	/*
+	 * Pointer to main rt2x00dev structure where this
+	 * ring belongs to.
+	 */
+	struct rt2x00_dev *rt2x00dev;
+
+	/*
+	 * Base address for the device specific data entries.
+	 */
+	struct data_entry *entry;
+
+	/*
+	 * TX queue statistic info.
+	 */
+	struct ieee80211_tx_queue_stats_data stats;
+
+	/*
+	 * TX Queue parameters.
+	 */
+	struct ieee80211_tx_queue_params tx_params;
+
+	/*
+	 * Base address for data ring.
+	 */
+	dma_addr_t data_dma;
+	void *data_addr;
+
+	/*
+	 * Index variables.
+	 */
+	u16 index;
+	u16 index_done;
+
+	/*
+	 * Size of packet and descriptor in bytes.
+	 */
+	u16 data_size;
+	u16 desc_size;
+};
+
+/*
+ * Handlers to determine the address of the current device specific
+ * data entry, where either index or index_done points to.
+ */
+static inline struct data_entry *rt2x00_get_data_entry(struct data_ring *ring)
+{
+	return &ring->entry[ring->index];
+}
+
+static inline struct data_entry *rt2x00_get_data_entry_done(struct data_ring
+							    *ring)
+{
+	return &ring->entry[ring->index_done];
+}
+
+/*
+ * Total ring memory
+ */
+static inline int rt2x00_get_ring_size(struct data_ring *ring)
+{
+	return ring->stats.limit * (ring->desc_size + ring->data_size);
+}
+
+/*
+ * Ring index manipulation functions.
+ */
+static inline void rt2x00_ring_index_inc(struct data_ring *ring)
+{
+	ring->index++;
+	if (ring->index >= ring->stats.limit)
+		ring->index = 0;
+	ring->stats.len++;
+}
+
+static inline void rt2x00_ring_index_done_inc(struct data_ring *ring)
+{
+	ring->index_done++;
+	if (ring->index_done >= ring->stats.limit)
+		ring->index_done = 0;
+	ring->stats.len--;
+	ring->stats.count++;
+}
+
+static inline void rt2x00_ring_index_clear(struct data_ring *ring)
+{
+	ring->index = 0;
+	ring->index_done = 0;
+	ring->stats.len = 0;
+	ring->stats.count = 0;
+}
+
+static inline int rt2x00_ring_empty(struct data_ring *ring)
+{
+	return ring->stats.len == 0;
+}
+
+static inline int rt2x00_ring_full(struct data_ring *ring)
+{
+	return ring->stats.len == ring->stats.limit;
+}
+
+static inline int rt2x00_ring_free(struct data_ring *ring)
+{
+	return ring->stats.limit - ring->stats.len;
+}
+
+/*
+ * TX/RX Descriptor access functions.
+ */
+static inline void rt2x00_desc_read(struct data_desc *desc,
+				    const u8 word, u32 *value)
+{
+	*value = le32_to_cpu(desc->word[word]);
+}
+
+static inline void rt2x00_desc_write(struct data_desc *desc,
+				     const u8 word, const u32 value)
+{
+	desc->word[word] = cpu_to_le32(value);
+}
+
+#endif /* RT2X00RING_H */
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
new file mode 100644
index 0000000..73cc726
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -0,0 +1,592 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2x00usb
+	Abstract: rt2x00 generic usb device routines.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt2x00usb"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "rt2x00.h"
+#include "rt2x00usb.h"
+
+/*
+ * Interfacing with the HW.
+ */
+int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev,
+			     const u8 request, const u8 requesttype,
+			     const u16 offset, const u16 value,
+			     void *buffer, const u16 buffer_length,
+			     const int timeout)
+{
+	struct usb_device *usb_dev =
+	    interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
+	int status;
+	unsigned int i;
+	unsigned int pipe =
+	    (requesttype == USB_VENDOR_REQUEST_IN) ?
+	    usb_rcvctrlpipe(usb_dev, 0) : usb_sndctrlpipe(usb_dev, 0);
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		status = usb_control_msg(usb_dev, pipe, request, requesttype,
+					 value, offset, buffer, buffer_length,
+					 timeout);
+		if (status >= 0)
+			return 0;
+
+		/*
+		 * Check for errors
+		 * -ENODEV: Device has disappeared, no point continuing.
+		 * All other errors: Try again.
+		 */
+		else if (status == -ENODEV)
+			break;
+	}
+
+	ERROR(rt2x00dev,
+	      "Vendor Request 0x%02x failed for offset 0x%04x with error %d.\n",
+	      request, offset, status);
+
+	return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request);
+
+int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev,
+				  const u8 request, const u8 requesttype,
+				  const u16 offset, void *buffer,
+				  const u16 buffer_length, const int timeout)
+{
+	int status;
+
+	/*
+	 * Check for Cache availability.
+	 */
+	if (unlikely(!rt2x00dev->csr_cache || buffer_length > CSR_CACHE_SIZE)) {
+		ERROR(rt2x00dev, "CSR cache not available.\n");
+		return -ENOMEM;
+	}
+
+	if (requesttype == USB_VENDOR_REQUEST_OUT)
+		memcpy(rt2x00dev->csr_cache, buffer, buffer_length);
+
+	status = rt2x00usb_vendor_request(rt2x00dev, request, requesttype,
+					  offset, 0, rt2x00dev->csr_cache,
+					  buffer_length, timeout);
+
+	if (!status && requesttype == USB_VENDOR_REQUEST_IN)
+		memcpy(buffer, rt2x00dev->csr_cache, buffer_length);
+
+	return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff);
+
+/*
+ * TX data handlers.
+ */
+static void rt2x00usb_interrupt_txdone(struct urb *urb)
+{
+	struct data_entry *entry = (struct data_entry *)urb->context;
+	struct data_ring *ring = entry->ring;
+	struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
+	struct data_desc *txd = (struct data_desc *)entry->skb->data;
+	u32 word;
+	int tx_status;
+
+	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
+	    !__test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags))
+		return;
+
+	rt2x00_desc_read(txd, 0, &word);
+
+	/*
+	 * Remove the descriptor data from the buffer.
+	 */
+	skb_pull(entry->skb, ring->desc_size);
+
+	/*
+	 * Obtain the status about this packet.
+	 */
+	tx_status = !urb->status ? TX_SUCCESS : TX_FAIL_RETRY;
+
+	rt2x00lib_txdone(entry, tx_status, 0);
+
+	/*
+	 * Make this entry available for reuse.
+	 */
+	entry->flags = 0;
+	rt2x00_ring_index_done_inc(entry->ring);
+
+	/*
+	 * If the data ring was full before the txdone handler
+	 * we must make sure the packet queue in the mac80211 stack
+	 * is reenabled when the txdone handler has finished.
+	 */
+	if (!rt2x00_ring_full(ring))
+		ieee80211_wake_queue(rt2x00dev->hw,
+				     entry->tx_status.control.queue);
+}
+
+int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
+			    struct data_ring *ring, struct sk_buff *skb,
+			    struct ieee80211_tx_control *control)
+{
+	struct usb_device *usb_dev =
+	    interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
+	struct data_entry *entry = rt2x00_get_data_entry(ring);
+	int pipe = usb_sndbulkpipe(usb_dev, 1);
+	int max_packet = usb_maxpacket(usb_dev, pipe, 1);
+	u32 length;
+
+	if (rt2x00_ring_full(ring)) {
+		ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+		return -EINVAL;
+	}
+
+	if (test_bit(ENTRY_OWNER_NIC, &entry->flags)) {
+		ERROR(rt2x00dev,
+		      "Arrived at non-free entry in the non-full queue %d.\n"
+		      "Please file bug report to %s.\n",
+		      control->queue, DRV_PROJECT);
+		ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+		return -EINVAL;
+	}
+
+	/*
+	 * Add the descriptor in front of the skb.
+	 */
+	skb_push(skb, ring->desc_size);
+	memset(skb->data, 0, ring->desc_size);
+
+	rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data,
+				(struct ieee80211_hdr *)(skb->data +
+							 ring->desc_size),
+				skb->len - ring->desc_size, control);
+	memcpy(&entry->tx_status.control, control, sizeof(*control));
+	entry->skb = skb;
+
+	/*
+	 * USB devices cannot blindly pass the skb->len as the
+	 * length of the data to usb_fill_bulk_urb. Pass the skb
+	 * to the driver to determine what the length should be.
+	 */
+	length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev,
+						      max_packet, skb);
+
+	/*
+	 * Initialize URB and send the frame to the device.
+	 */
+	__set_bit(ENTRY_OWNER_NIC, &entry->flags);
+	usb_fill_bulk_urb(entry->priv, usb_dev, pipe,
+			  skb->data, length, rt2x00usb_interrupt_txdone, entry);
+	usb_submit_urb(entry->priv, GFP_ATOMIC);
+
+	rt2x00_ring_index_inc(ring);
+
+	if (rt2x00_ring_full(ring))
+		ieee80211_stop_queue(rt2x00dev->hw, control->queue);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_write_tx_data);
+
+/*
+ * RX data handlers.
+ */
+static void rt2x00usb_interrupt_rxdone(struct urb *urb)
+{
+	struct data_entry *entry = (struct data_entry *)urb->context;
+	struct data_ring *ring = entry->ring;
+	struct rt2x00_dev *rt2x00dev = ring->rt2x00dev;
+	struct sk_buff *skb;
+	struct rxdata_entry_desc desc;
+	int frame_size;
+
+	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags) ||
+	    !test_and_clear_bit(ENTRY_OWNER_NIC, &entry->flags))
+		return;
+
+	/*
+	 * Check if the received data is simply too small
+	 * to be actually valid, or if the urb is signaling
+	 * a problem.
+	 */
+	if (urb->actual_length < entry->ring->desc_size || urb->status)
+		goto skip_entry;
+
+	memset(&desc, 0x00, sizeof(desc));
+	rt2x00dev->ops->lib->fill_rxdone(entry, &desc);
+
+	/*
+	 * Allocate a new sk buffer to replace the current one.
+	 * If allocation fails, we should drop the current frame
+	 * so we can recycle the existing sk buffer for the new frame.
+	 */
+	frame_size = entry->ring->data_size + entry->ring->desc_size;
+	skb = dev_alloc_skb(frame_size + NET_IP_ALIGN);
+	if (!skb)
+		goto skip_entry;
+
+	skb_reserve(skb, NET_IP_ALIGN);
+	skb_put(skb, frame_size);
+
+	/*
+	 * Trim the skb_buffer to only contain the valid
+	 * frame data (so ignore the device's descriptor).
+	 */
+	skb_trim(entry->skb, desc.size);
+
+	/*
+	 * Send the frame to rt2x00lib for further processing.
+	 */
+	rt2x00lib_rxdone(entry, entry->skb, &desc);
+
+	/*
+	 * Replace current entry's skb with the newly allocated one,
+	 * and reinitialize the urb.
+	 */
+	entry->skb = skb;
+	urb->transfer_buffer = entry->skb->data;
+	urb->transfer_buffer_length = entry->skb->len;
+
+skip_entry:
+	if (test_bit(DEVICE_ENABLED_RADIO, &ring->rt2x00dev->flags)) {
+		__set_bit(ENTRY_OWNER_NIC, &entry->flags);
+		usb_submit_urb(urb, GFP_ATOMIC);
+	}
+
+	rt2x00_ring_index_inc(ring);
+}
+
+/*
+ * Radio handlers
+ */
+void rt2x00usb_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+	struct usb_device *usb_dev =
+	    interface_to_usbdev(rt2x00dev_usb(rt2x00dev));
+	struct data_ring *ring;
+	struct data_entry *entry;
+	unsigned int i;
+
+	/*
+	 * Initialize the TX rings
+	 */
+	txringall_for_each(rt2x00dev, ring) {
+		for (i = 0; i < ring->stats.limit; i++)
+			ring->entry[i].flags = 0;
+
+		rt2x00_ring_index_clear(ring);
+	}
+
+	/*
+	 * Initialize and start the RX ring.
+	 */
+	rt2x00_ring_index_clear(rt2x00dev->rx);
+
+	for (i = 0; i < rt2x00dev->rx->stats.limit; i++) {
+		entry = &rt2x00dev->rx->entry[i];
+
+		usb_fill_bulk_urb(entry->priv, usb_dev,
+				  usb_rcvbulkpipe(usb_dev, 1),
+				  entry->skb->data, entry->skb->len,
+				  rt2x00usb_interrupt_rxdone, entry);
+
+		__set_bit(ENTRY_OWNER_NIC, &entry->flags);
+		usb_submit_urb(entry->priv, GFP_ATOMIC);
+	}
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_enable_radio);
+
+void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_ring *ring;
+	unsigned int i;
+
+	rt2x00usb_vendor_request_sw(rt2x00dev, USB_RX_CONTROL, 0x0000, 0x0000,
+				    REGISTER_TIMEOUT);
+
+	/*
+	 * Cancel all rings.
+	 */
+	ring_for_each(rt2x00dev, ring) {
+		for (i = 0; i < ring->stats.limit; i++)
+			usb_kill_urb(ring->entry[i].priv);
+	}
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio);
+
+/*
+ * Device initialization handlers.
+ */
+static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev,
+			       struct data_ring *ring)
+{
+	unsigned int i;
+
+	/*
+	 * Allocate the URB's
+	 */
+	for (i = 0; i < ring->stats.limit; i++) {
+		ring->entry[i].priv = usb_alloc_urb(0, GFP_KERNEL);
+		if (!ring->entry[i].priv)
+			return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void rt2x00usb_free_urb(struct rt2x00_dev *rt2x00dev,
+			       struct data_ring *ring)
+{
+	unsigned int i;
+
+	if (!ring->entry)
+		return;
+
+	for (i = 0; i < ring->stats.limit; i++) {
+		usb_kill_urb(ring->entry[i].priv);
+		usb_free_urb(ring->entry[i].priv);
+		if (ring->entry[i].skb)
+			kfree_skb(ring->entry[i].skb);
+	}
+}
+
+int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_ring *ring;
+	struct sk_buff *skb;
+	unsigned int entry_size;
+	unsigned int i;
+	int status;
+
+	/*
+	 * Allocate DMA
+	 */
+	ring_for_each(rt2x00dev, ring) {
+		status = rt2x00usb_alloc_urb(rt2x00dev, ring);
+		if (status)
+			goto exit;
+	}
+
+	/*
+	 * For the RX ring, skb's should be allocated.
+	 */
+	entry_size = rt2x00dev->rx->data_size + rt2x00dev->rx->desc_size;
+	for (i = 0; i < rt2x00dev->rx->stats.limit; i++) {
+		skb = dev_alloc_skb(NET_IP_ALIGN + entry_size);
+		if (!skb)
+			goto exit;
+
+		skb_reserve(skb, NET_IP_ALIGN);
+		skb_put(skb, entry_size);
+
+		rt2x00dev->rx->entry[i].skb = skb;
+	}
+
+	return 0;
+
+exit:
+	rt2x00usb_uninitialize(rt2x00dev);
+
+	return status;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_initialize);
+
+void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_ring *ring;
+
+	ring_for_each(rt2x00dev, ring)
+		rt2x00usb_free_urb(rt2x00dev, ring);
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_uninitialize);
+
+/*
+ * USB driver handlers.
+ */
+static void rt2x00usb_free_reg(struct rt2x00_dev *rt2x00dev)
+{
+	kfree(rt2x00dev->rf);
+	rt2x00dev->rf = NULL;
+
+	kfree(rt2x00dev->eeprom);
+	rt2x00dev->eeprom = NULL;
+
+	kfree(rt2x00dev->csr_cache);
+	rt2x00dev->csr_cache = NULL;
+}
+
+static int rt2x00usb_alloc_reg(struct rt2x00_dev *rt2x00dev)
+{
+	rt2x00dev->csr_cache = kzalloc(CSR_CACHE_SIZE, GFP_KERNEL);
+	if (!rt2x00dev->csr_cache)
+		goto exit;
+
+	rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL);
+	if (!rt2x00dev->eeprom)
+		goto exit;
+
+	rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL);
+	if (!rt2x00dev->rf)
+		goto exit;
+
+	return 0;
+
+exit:
+	ERROR_PROBE("Failed to allocate registers.\n");
+
+	rt2x00usb_free_reg(rt2x00dev);
+
+	return -ENOMEM;
+}
+
+int rt2x00usb_probe(struct usb_interface *usb_intf,
+		    const struct usb_device_id *id)
+{
+	struct usb_device *usb_dev = interface_to_usbdev(usb_intf);
+	struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_info;
+	struct ieee80211_hw *hw;
+	struct rt2x00_dev *rt2x00dev;
+	int retval;
+
+	usb_dev = usb_get_dev(usb_dev);
+
+	hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw);
+	if (!hw) {
+		ERROR_PROBE("Failed to allocate hardware.\n");
+		retval = -ENOMEM;
+		goto exit_put_device;
+	}
+
+	usb_set_intfdata(usb_intf, hw);
+
+	rt2x00dev = hw->priv;
+	rt2x00dev->dev = usb_intf;
+	rt2x00dev->ops = ops;
+	rt2x00dev->hw = hw;
+
+	retval = rt2x00usb_alloc_reg(rt2x00dev);
+	if (retval)
+		goto exit_free_device;
+
+	retval = rt2x00lib_probe_dev(rt2x00dev);
+	if (retval)
+		goto exit_free_reg;
+
+	return 0;
+
+exit_free_reg:
+	rt2x00usb_free_reg(rt2x00dev);
+
+exit_free_device:
+	ieee80211_free_hw(hw);
+
+exit_put_device:
+	usb_put_dev(usb_dev);
+
+	usb_set_intfdata(usb_intf, NULL);
+
+	return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_probe);
+
+void rt2x00usb_disconnect(struct usb_interface *usb_intf)
+{
+	struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+
+	/*
+	 * Free all allocated data.
+	 */
+	rt2x00lib_remove_dev(rt2x00dev);
+	rt2x00usb_free_reg(rt2x00dev);
+	ieee80211_free_hw(hw);
+
+	/*
+	 * Free the USB device data.
+	 */
+	usb_set_intfdata(usb_intf, NULL);
+	usb_put_dev(interface_to_usbdev(usb_intf));
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_disconnect);
+
+#ifdef CONFIG_PM
+int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state)
+{
+	struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	int retval;
+
+	retval = rt2x00lib_suspend(rt2x00dev, state);
+	if (retval)
+		return retval;
+
+	rt2x00usb_free_reg(rt2x00dev);
+
+	/*
+	 * Decrease usbdev refcount.
+	 */
+	usb_put_dev(interface_to_usbdev(usb_intf));
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_suspend);
+
+int rt2x00usb_resume(struct usb_interface *usb_intf)
+{
+	struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	int retval;
+
+	usb_get_dev(interface_to_usbdev(usb_intf));
+
+	retval = rt2x00usb_alloc_reg(rt2x00dev);
+	if (retval)
+		return retval;
+
+	retval = rt2x00lib_resume(rt2x00dev);
+	if (retval)
+		goto exit_free_reg;
+
+	return 0;
+
+exit_free_reg:
+	rt2x00usb_free_reg(rt2x00dev);
+
+	return retval;
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_resume);
+#endif /* CONFIG_PM */
+
+/*
+ * rt2x00pci module information.
+ */
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("rt2x00 library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
new file mode 100644
index 0000000..2681abe
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -0,0 +1,180 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt2x00usb
+	Abstract: Data structures for the rt2x00usb module.
+ */
+
+#ifndef RT2X00USB_H
+#define RT2X00USB_H
+
+/*
+ * This variable should be used with the
+ * usb_driver structure initialization.
+ */
+#define USB_DEVICE_DATA(__ops)	.driver_info = (kernel_ulong_t)(__ops)
+
+/*
+ * Register defines.
+ * Some registers require multiple attempts before success,
+ * in those cases REGISTER_BUSY_COUNT attempts should be
+ * taken with a REGISTER_BUSY_DELAY interval.
+ * For USB vendor requests we need to pass a timeout
+ * time in ms, for this we use the REGISTER_TIMEOUT,
+ * however when loading firmware a higher value is
+ * required. In that case we use the REGISTER_TIMEOUT_FIRMWARE.
+ */
+#define REGISTER_BUSY_COUNT		5
+#define REGISTER_BUSY_DELAY		100
+#define REGISTER_TIMEOUT		500
+#define REGISTER_TIMEOUT_FIRMWARE	1000
+
+/*
+ * Cache size
+ */
+#define CSR_CACHE_SIZE			8
+#define CSR_CACHE_SIZE_FIRMWARE		64
+
+/*
+ * USB request types.
+ */
+#define USB_VENDOR_REQUEST	( USB_TYPE_VENDOR | USB_RECIP_DEVICE )
+#define USB_VENDOR_REQUEST_IN	( USB_DIR_IN | USB_VENDOR_REQUEST )
+#define USB_VENDOR_REQUEST_OUT	( USB_DIR_OUT | USB_VENDOR_REQUEST )
+
+/*
+ * USB vendor commands.
+ */
+#define USB_DEVICE_MODE		0x01
+#define USB_SINGLE_WRITE	0x02
+#define USB_SINGLE_READ		0x03
+#define USB_MULTI_WRITE		0x06
+#define USB_MULTI_READ		0x07
+#define USB_EEPROM_WRITE	0x08
+#define USB_EEPROM_READ		0x09
+#define USB_LED_CONTROL		0x0a	/* RT73USB */
+#define USB_RX_CONTROL		0x0c
+
+/*
+ * Device modes offset
+ */
+#define USB_MODE_RESET		0x01
+#define USB_MODE_UNPLUG		0x02
+#define USB_MODE_FUNCTION	0x03
+#define USB_MODE_TEST		0x04
+#define USB_MODE_SLEEP		0x07	/* RT73USB */
+#define USB_MODE_FIRMWARE	0x08	/* RT73USB */
+#define USB_MODE_WAKEUP		0x09	/* RT73USB */
+
+/*
+ * Used to read/write from/to the device.
+ * This is the main function to communicate with the device,
+ * the buffer argument _must_ either be NULL or point to
+ * a buffer allocated by kmalloc. Failure to do so can lead
+ * to unexpected behavior depending on the architecture.
+ */
+int rt2x00usb_vendor_request(const struct rt2x00_dev *rt2x00dev,
+			     const u8 request, const u8 requesttype,
+			     const u16 offset, const u16 value,
+			     void *buffer, const u16 buffer_length,
+			     const int timeout);
+
+/*
+ * Used to read/write from/to the device.
+ * This function will use a previously with kmalloc allocated cache
+ * to communicate with the device. The contents of the buffer pointer
+ * will be copied to this cache when writing, or read from the cache
+ * when reading.
+ * Buffers send to rt2x00usb_vendor_request _must_ be allocated with
+ * kmalloc. Hence the reason for using a previously allocated cache
+ * which has been allocated properly.
+ */
+int rt2x00usb_vendor_request_buff(const struct rt2x00_dev *rt2x00dev,
+				  const u8 request, const u8 requesttype,
+				  const u16 offset, void *buffer,
+				  const u16 buffer_length, const int timeout);
+
+/*
+ * Simple wrapper around rt2x00usb_vendor_request to write a single
+ * command to the device. Since we don't use the buffer argument we
+ * don't have to worry about kmalloc here.
+ */
+static inline int rt2x00usb_vendor_request_sw(const struct rt2x00_dev
+					      *rt2x00dev,
+					      const u8 request,
+					      const u16 offset,
+					      const u16 value,
+					      const int timeout)
+{
+	return rt2x00usb_vendor_request(rt2x00dev, request,
+					USB_VENDOR_REQUEST_OUT, offset,
+					value, NULL, 0, timeout);
+}
+
+/*
+ * Simple wrapper around rt2x00usb_vendor_request to read the eeprom
+ * from the device. Note that the eeprom argument _must_ be allocated using
+ * kmalloc for correct handling inside the kernel USB layer.
+ */
+static inline int rt2x00usb_eeprom_read(const struct rt2x00_dev *rt2x00dev,
+					 __le16 *eeprom, const u16 lenght)
+{
+	int timeout = REGISTER_TIMEOUT * (lenght / sizeof(u16));
+
+	return rt2x00usb_vendor_request(rt2x00dev, USB_EEPROM_READ,
+					USB_VENDOR_REQUEST_IN, 0x0000,
+					0x0000, eeprom, lenght, timeout);
+}
+
+/*
+ * Radio handlers
+ */
+void rt2x00usb_enable_radio(struct rt2x00_dev *rt2x00dev);
+void rt2x00usb_disable_radio(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * TX data handlers.
+ */
+int rt2x00usb_write_tx_data(struct rt2x00_dev *rt2x00dev,
+			    struct data_ring *ring, struct sk_buff *skb,
+			    struct ieee80211_tx_control *control);
+
+/*
+ * Device initialization handlers.
+ */
+int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev);
+void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev);
+
+/*
+ * USB driver handlers.
+ */
+int rt2x00usb_probe(struct usb_interface *usb_intf,
+		    const struct usb_device_id *id);
+void rt2x00usb_disconnect(struct usb_interface *usb_intf);
+#ifdef CONFIG_PM
+int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state);
+int rt2x00usb_resume(struct usb_interface *usb_intf);
+#else
+#define rt2x00usb_suspend	NULL
+#define rt2x00usb_resume	NULL
+#endif /* CONFIG_PM */
+
+#endif /* RT2X00USB_H */
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
new file mode 100644
index 0000000..01dbef1
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -0,0 +1,2557 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt61pci
+	Abstract: rt61pci device specific routines.
+	Supported chipsets: RT2561, RT2561s, RT2661.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt61pci"
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/eeprom_93cx6.h>
+
+#include "rt2x00.h"
+#include "rt2x00pci.h"
+#include "rt61pci.h"
+
+/*
+ * Register access.
+ * BBP and RF register require indirect register access,
+ * and use the CSR registers PHY_CSR3 and PHY_CSR4 to achieve this.
+ * These indirect registers work with busy bits,
+ * and we will try maximal REGISTER_BUSY_COUNT times to access
+ * the register while taking a REGISTER_BUSY_DELAY us delay
+ * between each attampt. When the busy bit is still set at that time,
+ * the access attempt is considered to have failed,
+ * and we will print an error.
+ */
+static u32 rt61pci_bbp_check(const struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+	unsigned int i;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2x00pci_register_read(rt2x00dev, PHY_CSR3, &reg);
+		if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+			break;
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	return reg;
+}
+
+static void rt61pci_bbp_write(const struct rt2x00_dev *rt2x00dev,
+			      const unsigned int word, const u8 value)
+{
+	u32 reg;
+
+	/*
+	 * Wait until the BBP becomes ready.
+	 */
+	reg = rt61pci_bbp_check(rt2x00dev);
+	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+		ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
+		return;
+	}
+
+	/*
+	 * Write the data into the BBP.
+	 */
+	reg = 0;
+	rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
+	rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+	rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+	rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
+
+	rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
+}
+
+static void rt61pci_bbp_read(const struct rt2x00_dev *rt2x00dev,
+			     const unsigned int word, u8 *value)
+{
+	u32 reg;
+
+	/*
+	 * Wait until the BBP becomes ready.
+	 */
+	reg = rt61pci_bbp_check(rt2x00dev);
+	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+		ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+		return;
+	}
+
+	/*
+	 * Write the request into the BBP.
+	 */
+	reg = 0;
+	rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+	rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+	rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
+
+	rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg);
+
+	/*
+	 * Wait until the BBP becomes ready.
+	 */
+	reg = rt61pci_bbp_check(rt2x00dev);
+	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+		ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+		*value = 0xff;
+		return;
+	}
+
+	*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
+}
+
+static void rt61pci_rf_write(const struct rt2x00_dev *rt2x00dev,
+			     const unsigned int word, const u32 value)
+{
+	u32 reg;
+	unsigned int i;
+
+	if (!word)
+		return;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2x00pci_register_read(rt2x00dev, PHY_CSR4, &reg);
+		if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY))
+			goto rf_write;
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n");
+	return;
+
+rf_write:
+	reg = 0;
+	rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
+	rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS, 21);
+	rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
+	rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
+
+	rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg);
+	rt2x00_rf_write(rt2x00dev, word, value);
+}
+
+static void rt61pci_mcu_request(const struct rt2x00_dev *rt2x00dev,
+				const u8 command, const u8 token,
+				const u8 arg0, const u8 arg1)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, &reg);
+
+	if (rt2x00_get_field32(reg, H2M_MAILBOX_CSR_OWNER)) {
+		ERROR(rt2x00dev, "mcu request error. "
+		      "Request 0x%02x failed for token 0x%02x.\n",
+		      command, token);
+		return;
+	}
+
+	rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_OWNER, 1);
+	rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_CMD_TOKEN, token);
+	rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG0, arg0);
+	rt2x00_set_field32(&reg, H2M_MAILBOX_CSR_ARG1, arg1);
+	rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg);
+
+	rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, &reg);
+	rt2x00_set_field32(&reg, HOST_CMD_CSR_HOST_COMMAND, command);
+	rt2x00_set_field32(&reg, HOST_CMD_CSR_INTERRUPT_MCU, 1);
+	rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg);
+}
+
+static void rt61pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
+{
+	struct rt2x00_dev *rt2x00dev = eeprom->data;
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
+
+	eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN);
+	eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT);
+	eeprom->reg_data_clock =
+	    !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_CLOCK);
+	eeprom->reg_chip_select =
+	    !!rt2x00_get_field32(reg, E2PROM_CSR_CHIP_SELECT);
+}
+
+static void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
+{
+	struct rt2x00_dev *rt2x00dev = eeprom->data;
+	u32 reg = 0;
+
+	rt2x00_set_field32(&reg, E2PROM_CSR_DATA_IN, !!eeprom->reg_data_in);
+	rt2x00_set_field32(&reg, E2PROM_CSR_DATA_OUT, !!eeprom->reg_data_out);
+	rt2x00_set_field32(&reg, E2PROM_CSR_DATA_CLOCK,
+			   !!eeprom->reg_data_clock);
+	rt2x00_set_field32(&reg, E2PROM_CSR_CHIP_SELECT,
+			   !!eeprom->reg_chip_select);
+
+	rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg);
+}
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+#define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
+
+static void rt61pci_read_csr(const struct rt2x00_dev *rt2x00dev,
+			     const unsigned int word, u32 *data)
+{
+	rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static void rt61pci_write_csr(const struct rt2x00_dev *rt2x00dev,
+			      const unsigned int word, u32 data)
+{
+	rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static const struct rt2x00debug rt61pci_rt2x00debug = {
+	.owner	= THIS_MODULE,
+	.csr	= {
+		.read		= rt61pci_read_csr,
+		.write		= rt61pci_write_csr,
+		.word_size	= sizeof(u32),
+		.word_count	= CSR_REG_SIZE / sizeof(u32),
+	},
+	.eeprom	= {
+		.read		= rt2x00_eeprom_read,
+		.write		= rt2x00_eeprom_write,
+		.word_size	= sizeof(u16),
+		.word_count	= EEPROM_SIZE / sizeof(u16),
+	},
+	.bbp	= {
+		.read		= rt61pci_bbp_read,
+		.write		= rt61pci_bbp_write,
+		.word_size	= sizeof(u8),
+		.word_count	= BBP_SIZE / sizeof(u8),
+	},
+	.rf	= {
+		.read		= rt2x00_rf_read,
+		.write		= rt61pci_rf_write,
+		.word_size	= sizeof(u32),
+		.word_count	= RF_SIZE / sizeof(u32),
+	},
+};
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+#ifdef CONFIG_RT61PCI_RFKILL
+static int rt61pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, MAC_CSR13, &reg);
+	return rt2x00_get_field32(reg, MAC_CSR13_BIT5);;
+}
+#else
+#define rt61pci_rfkill_poll	NULL
+#endif /* CONFIG_RT61PCI_RFKILL */
+
+/*
+ * Configuration handlers.
+ */
+static void rt61pci_config_mac_addr(struct rt2x00_dev *rt2x00dev, __le32 *mac)
+{
+	u32 tmp;
+
+	tmp = le32_to_cpu(mac[1]);
+	rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
+	mac[1] = cpu_to_le32(tmp);
+
+	rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR2, mac,
+				      (2 * sizeof(__le32)));
+}
+
+static void rt61pci_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid)
+{
+	u32 tmp;
+
+	tmp = le32_to_cpu(bssid[1]);
+	rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3);
+	bssid[1] = cpu_to_le32(tmp);
+
+	rt2x00pci_register_multiwrite(rt2x00dev, MAC_CSR4, bssid,
+				      (2 * sizeof(__le32)));
+}
+
+static void rt61pci_config_type(struct rt2x00_dev *rt2x00dev, const int type,
+				const int tsf_sync)
+{
+	u32 reg;
+
+	/*
+	 * Clear current synchronisation setup.
+	 * For the Beacon base registers we only need to clear
+	 * the first byte since that byte contains the VALID and OWNER
+	 * bits which (when set to 0) will invalidate the entire beacon.
+	 */
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0);
+	rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
+	rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
+	rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
+	rt2x00pci_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
+
+	/*
+	 * Enable synchronisation.
+	 */
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, tsf_sync);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+}
+
+static void rt61pci_config_preamble(struct rt2x00_dev *rt2x00dev,
+				    const int short_preamble,
+				    const int ack_timeout,
+				    const int ack_consume_time)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
+			   !!short_preamble);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+}
+
+static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev,
+				   const int basic_rate_mask)
+{
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask);
+}
+
+static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev,
+				   struct rf_channel *rf, const int txpower)
+{
+	u8 r3;
+	u8 r94;
+	u8 smart;
+
+	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
+
+	smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+		  rt2x00_rf(&rt2x00dev->chip, RF2527));
+
+	rt61pci_bbp_read(rt2x00dev, 3, &r3);
+	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
+	rt61pci_bbp_write(rt2x00dev, 3, r3);
+
+	r94 = 6;
+	if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
+		r94 += txpower - MAX_TXPOWER;
+	else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
+		r94 += txpower;
+	rt61pci_bbp_write(rt2x00dev, 94, r94);
+
+	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+	udelay(200);
+
+	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
+	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+	udelay(200);
+
+	rt61pci_rf_write(rt2x00dev, 1, rf->rf1);
+	rt61pci_rf_write(rt2x00dev, 2, rf->rf2);
+	rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+	rt61pci_rf_write(rt2x00dev, 4, rf->rf4);
+
+	msleep(1);
+}
+
+static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev,
+				   const int txpower)
+{
+	struct rf_channel rf;
+
+	rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
+	rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
+	rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
+	rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+
+	rt61pci_config_channel(rt2x00dev, &rf, txpower);
+}
+
+static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
+				      const int antenna_tx,
+				      const int antenna_rx)
+{
+	u8 r3;
+	u8 r4;
+	u8 r77;
+
+	rt61pci_bbp_read(rt2x00dev, 3, &r3);
+	rt61pci_bbp_read(rt2x00dev, 4, &r4);
+	rt61pci_bbp_read(rt2x00dev, 77, &r77);
+
+	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE,
+			  !rt2x00_rf(&rt2x00dev->chip, RF5225));
+
+	switch (antenna_rx) {
+	case ANTENNA_SW_DIVERSITY:
+	case ANTENNA_HW_DIVERSITY:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
+				  !!(rt2x00dev->curr_hwmode != HWMODE_A));
+		break;
+	case ANTENNA_A:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+		if (rt2x00dev->curr_hwmode == HWMODE_A)
+			rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+		else
+			rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+		break;
+	case ANTENNA_B:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+		if (rt2x00dev->curr_hwmode == HWMODE_A)
+			rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+		else
+			rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+		break;
+	}
+
+	rt61pci_bbp_write(rt2x00dev, 77, r77);
+	rt61pci_bbp_write(rt2x00dev, 3, r3);
+	rt61pci_bbp_write(rt2x00dev, 4, r4);
+}
+
+static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
+				      const int antenna_tx,
+				      const int antenna_rx)
+{
+	u8 r3;
+	u8 r4;
+	u8 r77;
+
+	rt61pci_bbp_read(rt2x00dev, 3, &r3);
+	rt61pci_bbp_read(rt2x00dev, 4, &r4);
+	rt61pci_bbp_read(rt2x00dev, 77, &r77);
+
+	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE,
+			  !rt2x00_rf(&rt2x00dev->chip, RF2527));
+	rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
+			  !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags));
+
+	switch (antenna_rx) {
+	case ANTENNA_SW_DIVERSITY:
+	case ANTENNA_HW_DIVERSITY:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+		break;
+	case ANTENNA_A:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+		rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+		break;
+	case ANTENNA_B:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+		rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+		break;
+	}
+
+	rt61pci_bbp_write(rt2x00dev, 77, r77);
+	rt61pci_bbp_write(rt2x00dev, 3, r3);
+	rt61pci_bbp_write(rt2x00dev, 4, r4);
+}
+
+static void rt61pci_config_antenna_2529_rx(struct rt2x00_dev *rt2x00dev,
+					   const int p1, const int p2)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, MAC_CSR13, &reg);
+
+	if (p1 != 0xff) {
+		rt2x00_set_field32(&reg, MAC_CSR13_BIT4, !!p1);
+		rt2x00_set_field32(&reg, MAC_CSR13_BIT12, 0);
+		rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg);
+	}
+	if (p2 != 0xff) {
+		rt2x00_set_field32(&reg, MAC_CSR13_BIT3, !p2);
+		rt2x00_set_field32(&reg, MAC_CSR13_BIT11, 0);
+		rt2x00pci_register_write(rt2x00dev, MAC_CSR13, reg);
+	}
+}
+
+static void rt61pci_config_antenna_2529(struct rt2x00_dev *rt2x00dev,
+					const int antenna_tx,
+					const int antenna_rx)
+{
+	u16 eeprom;
+	u8 r3;
+	u8 r4;
+	u8 r77;
+
+	rt61pci_bbp_read(rt2x00dev, 3, &r3);
+	rt61pci_bbp_read(rt2x00dev, 4, &r4);
+	rt61pci_bbp_read(rt2x00dev, 77, &r77);
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+
+	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0);
+
+	if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) &&
+	    rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) {
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 1);
+		rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1);
+	} else if (rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY)) {
+		if (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED) >= 2) {
+			rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+			rt61pci_bbp_write(rt2x00dev, 77, r77);
+		}
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+		rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1);
+	} else if (!rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) &&
+		   rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) {
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+		switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) {
+		case 0:
+			rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1);
+			break;
+		case 1:
+			rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 0);
+			break;
+		case 2:
+			rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0);
+			break;
+		case 3:
+			rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1);
+			break;
+		}
+	} else if (!rt2x00_get_field16(eeprom, EEPROM_NIC_ENABLE_DIVERSITY) &&
+		   !rt2x00_get_field16(eeprom, EEPROM_NIC_TX_DIVERSITY)) {
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+		switch (rt2x00_get_field16(eeprom, EEPROM_NIC_TX_RX_FIXED)) {
+		case 0:
+			rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+			rt61pci_bbp_write(rt2x00dev, 77, r77);
+			rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 1);
+			break;
+		case 1:
+			rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+			rt61pci_bbp_write(rt2x00dev, 77, r77);
+			rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 0);
+			break;
+		case 2:
+			rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+			rt61pci_bbp_write(rt2x00dev, 77, r77);
+			rt61pci_config_antenna_2529_rx(rt2x00dev, 0, 0);
+			break;
+		case 3:
+			rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+			rt61pci_bbp_write(rt2x00dev, 77, r77);
+			rt61pci_config_antenna_2529_rx(rt2x00dev, 1, 1);
+			break;
+		}
+	}
+
+	rt61pci_bbp_write(rt2x00dev, 3, r3);
+	rt61pci_bbp_write(rt2x00dev, 4, r4);
+}
+
+struct antenna_sel {
+	u8 word;
+	/*
+	 * value[0] -> non-LNA
+	 * value[1] -> LNA
+	 */
+	u8 value[2];
+};
+
+static const struct antenna_sel antenna_sel_a[] = {
+	{ 96,  { 0x58, 0x78 } },
+	{ 104, { 0x38, 0x48 } },
+	{ 75,  { 0xfe, 0x80 } },
+	{ 86,  { 0xfe, 0x80 } },
+	{ 88,  { 0xfe, 0x80 } },
+	{ 35,  { 0x60, 0x60 } },
+	{ 97,  { 0x58, 0x58 } },
+	{ 98,  { 0x58, 0x58 } },
+};
+
+static const struct antenna_sel antenna_sel_bg[] = {
+	{ 96,  { 0x48, 0x68 } },
+	{ 104, { 0x2c, 0x3c } },
+	{ 75,  { 0xfe, 0x80 } },
+	{ 86,  { 0xfe, 0x80 } },
+	{ 88,  { 0xfe, 0x80 } },
+	{ 35,  { 0x50, 0x50 } },
+	{ 97,  { 0x48, 0x48 } },
+	{ 98,  { 0x48, 0x48 } },
+};
+
+static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev,
+				   const int antenna_tx, const int antenna_rx)
+{
+	const struct antenna_sel *sel;
+	unsigned int lna;
+	unsigned int i;
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, PHY_CSR0, &reg);
+
+	if (rt2x00dev->curr_hwmode == HWMODE_A) {
+		sel = antenna_sel_a;
+		lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+
+		rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG, 0);
+		rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A, 1);
+	} else {
+		sel = antenna_sel_bg;
+		lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+
+		rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG, 1);
+		rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A, 0);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
+		rt61pci_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]);
+
+	rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg);
+
+	if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+	    rt2x00_rf(&rt2x00dev->chip, RF5325))
+		rt61pci_config_antenna_5x(rt2x00dev, antenna_tx, antenna_rx);
+	else if (rt2x00_rf(&rt2x00dev->chip, RF2527))
+		rt61pci_config_antenna_2x(rt2x00dev, antenna_tx, antenna_rx);
+	else if (rt2x00_rf(&rt2x00dev->chip, RF2529)) {
+		if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags))
+			rt61pci_config_antenna_2x(rt2x00dev, antenna_tx,
+						  antenna_rx);
+		else
+			rt61pci_config_antenna_2529(rt2x00dev, antenna_tx,
+						    antenna_rx);
+	}
+}
+
+static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev,
+				    struct rt2x00lib_conf *libconf)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, libconf->slot_time);
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
+
+	rt2x00pci_register_read(rt2x00dev, MAC_CSR8, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR8_SIFS, libconf->sifs);
+	rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
+	rt2x00_set_field32(&reg, MAC_CSR8_EIFS, libconf->eifs);
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
+			   libconf->conf->beacon_int * 16);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+}
+
+static void rt61pci_config(struct rt2x00_dev *rt2x00dev,
+			   const unsigned int flags,
+			   struct rt2x00lib_conf *libconf)
+{
+	if (flags & CONFIG_UPDATE_PHYMODE)
+		rt61pci_config_phymode(rt2x00dev, libconf->basic_rates);
+	if (flags & CONFIG_UPDATE_CHANNEL)
+		rt61pci_config_channel(rt2x00dev, &libconf->rf,
+				       libconf->conf->power_level);
+	if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+		rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level);
+	if (flags & CONFIG_UPDATE_ANTENNA)
+		rt61pci_config_antenna(rt2x00dev, libconf->conf->antenna_sel_tx,
+				       libconf->conf->antenna_sel_rx);
+	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+		rt61pci_config_duration(rt2x00dev, libconf);
+}
+
+/*
+ * LED functions.
+ */
+static void rt61pci_enable_led(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+	u16 led_reg;
+	u8 arg0;
+	u8 arg1;
+
+	rt2x00pci_register_read(rt2x00dev, MAC_CSR14, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR14_ON_PERIOD, 70);
+	rt2x00_set_field32(&reg, MAC_CSR14_OFF_PERIOD, 30);
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR14, reg);
+
+	led_reg = rt2x00dev->led_reg;
+	rt2x00_set_field16(&led_reg, MCU_LEDCS_RADIO_STATUS, 1);
+	if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A)
+		rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_A_STATUS, 1);
+	else
+		rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_BG_STATUS, 1);
+
+	arg0 = led_reg & 0xff;
+	arg1 = (led_reg >> 8) & 0xff;
+
+	rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1);
+}
+
+static void rt61pci_disable_led(struct rt2x00_dev *rt2x00dev)
+{
+	u16 led_reg;
+	u8 arg0;
+	u8 arg1;
+
+	led_reg = rt2x00dev->led_reg;
+	rt2x00_set_field16(&led_reg, MCU_LEDCS_RADIO_STATUS, 0);
+	rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_BG_STATUS, 0);
+	rt2x00_set_field16(&led_reg, MCU_LEDCS_LINK_A_STATUS, 0);
+
+	arg0 = led_reg & 0xff;
+	arg1 = (led_reg >> 8) & 0xff;
+
+	rt61pci_mcu_request(rt2x00dev, MCU_LED, 0xff, arg0, arg1);
+}
+
+static void rt61pci_activity_led(struct rt2x00_dev *rt2x00dev, int rssi)
+{
+	u8 led;
+
+	if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH)
+		return;
+
+	/*
+	 * Led handling requires a positive value for the rssi,
+	 * to do that correctly we need to add the correction.
+	 */
+	rssi += rt2x00dev->rssi_offset;
+
+	if (rssi <= 30)
+		led = 0;
+	else if (rssi <= 39)
+		led = 1;
+	else if (rssi <= 49)
+		led = 2;
+	else if (rssi <= 53)
+		led = 3;
+	else if (rssi <= 63)
+		led = 4;
+	else
+		led = 5;
+
+	rt61pci_mcu_request(rt2x00dev, MCU_LED_STRENGTH, 0xff, led, 0);
+}
+
+/*
+ * Link tuning
+ */
+static void rt61pci_link_stats(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	/*
+	 * Update FCS error count from register.
+	 */
+	rt2x00pci_register_read(rt2x00dev, STA_CSR0, &reg);
+	rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR);
+
+	/*
+	 * Update False CCA count from register.
+	 */
+	rt2x00pci_register_read(rt2x00dev, STA_CSR1, &reg);
+	rt2x00dev->link.false_cca =
+	    rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
+}
+
+static void rt61pci_reset_tuner(struct rt2x00_dev *rt2x00dev)
+{
+	rt61pci_bbp_write(rt2x00dev, 17, 0x20);
+	rt2x00dev->link.vgc_level = 0x20;
+}
+
+static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+	int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
+	u8 r17;
+	u8 up_bound;
+	u8 low_bound;
+
+	/*
+	 * Update Led strength
+	 */
+	rt61pci_activity_led(rt2x00dev, rssi);
+
+	rt61pci_bbp_read(rt2x00dev, 17, &r17);
+
+	/*
+	 * Determine r17 bounds.
+	 */
+	if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+		low_bound = 0x28;
+		up_bound = 0x48;
+		if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
+			low_bound += 0x10;
+			up_bound += 0x10;
+		}
+	} else {
+		low_bound = 0x20;
+		up_bound = 0x40;
+		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) {
+			low_bound += 0x10;
+			up_bound += 0x10;
+		}
+	}
+
+	/*
+	 * Special big-R17 for very short distance
+	 */
+	if (rssi >= -35) {
+		if (r17 != 0x60)
+			rt61pci_bbp_write(rt2x00dev, 17, 0x60);
+		return;
+	}
+
+	/*
+	 * Special big-R17 for short distance
+	 */
+	if (rssi >= -58) {
+		if (r17 != up_bound)
+			rt61pci_bbp_write(rt2x00dev, 17, up_bound);
+		return;
+	}
+
+	/*
+	 * Special big-R17 for middle-short distance
+	 */
+	if (rssi >= -66) {
+		low_bound += 0x10;
+		if (r17 != low_bound)
+			rt61pci_bbp_write(rt2x00dev, 17, low_bound);
+		return;
+	}
+
+	/*
+	 * Special mid-R17 for middle distance
+	 */
+	if (rssi >= -74) {
+		low_bound += 0x08;
+		if (r17 != low_bound)
+			rt61pci_bbp_write(rt2x00dev, 17, low_bound);
+		return;
+	}
+
+	/*
+	 * Special case: Change up_bound based on the rssi.
+	 * Lower up_bound when rssi is weaker then -74 dBm.
+	 */
+	up_bound -= 2 * (-74 - rssi);
+	if (low_bound > up_bound)
+		up_bound = low_bound;
+
+	if (r17 > up_bound) {
+		rt61pci_bbp_write(rt2x00dev, 17, up_bound);
+		return;
+	}
+
+	/*
+	 * r17 does not yet exceed upper limit, continue and base
+	 * the r17 tuning on the false CCA count.
+	 */
+	if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) {
+		if (++r17 > up_bound)
+			r17 = up_bound;
+		rt61pci_bbp_write(rt2x00dev, 17, r17);
+	} else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) {
+		if (--r17 < low_bound)
+			r17 = low_bound;
+		rt61pci_bbp_write(rt2x00dev, 17, r17);
+	}
+}
+
+/*
+ * Firmware name function.
+ */
+static char *rt61pci_get_firmware_name(struct rt2x00_dev *rt2x00dev)
+{
+	char *fw_name;
+
+	switch (rt2x00dev->chip.rt) {
+	case RT2561:
+		fw_name = FIRMWARE_RT2561;
+		break;
+	case RT2561s:
+		fw_name = FIRMWARE_RT2561s;
+		break;
+	case RT2661:
+		fw_name = FIRMWARE_RT2661;
+		break;
+	default:
+		fw_name = NULL;
+		break;
+	}
+
+	return fw_name;
+}
+
+/*
+ * Initialization functions.
+ */
+static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, void *data,
+				 const size_t len)
+{
+	int i;
+	u32 reg;
+
+	/*
+	 * Wait for stable hardware.
+	 */
+	for (i = 0; i < 100; i++) {
+		rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
+		if (reg)
+			break;
+		msleep(1);
+	}
+
+	if (!reg) {
+		ERROR(rt2x00dev, "Unstable hardware.\n");
+		return -EBUSY;
+	}
+
+	/*
+	 * Prepare MCU and mailbox for firmware loading.
+	 */
+	reg = 0;
+	rt2x00_set_field32(&reg, MCU_CNTL_CSR_RESET, 1);
+	rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
+	rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff);
+	rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+	rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, 0);
+
+	/*
+	 * Write firmware to device.
+	 */
+	reg = 0;
+	rt2x00_set_field32(&reg, MCU_CNTL_CSR_RESET, 1);
+	rt2x00_set_field32(&reg, MCU_CNTL_CSR_SELECT_BANK, 1);
+	rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
+
+	rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
+				      data, len);
+
+	rt2x00_set_field32(&reg, MCU_CNTL_CSR_SELECT_BANK, 0);
+	rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
+
+	rt2x00_set_field32(&reg, MCU_CNTL_CSR_RESET, 0);
+	rt2x00pci_register_write(rt2x00dev, MCU_CNTL_CSR, reg);
+
+	for (i = 0; i < 100; i++) {
+		rt2x00pci_register_read(rt2x00dev, MCU_CNTL_CSR, &reg);
+		if (rt2x00_get_field32(reg, MCU_CNTL_CSR_READY))
+			break;
+		msleep(1);
+	}
+
+	if (i == 100) {
+		ERROR(rt2x00dev, "MCU Control register not ready.\n");
+		return -EBUSY;
+	}
+
+	/*
+	 * Reset MAC and BBP registers.
+	 */
+	reg = 0;
+	rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 1);
+	rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 1);
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+	rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 0);
+	rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 0);
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+	rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR1_HOST_READY, 1);
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+	return 0;
+}
+
+static void rt61pci_init_rxring(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_ring *ring = rt2x00dev->rx;
+	struct data_desc *rxd;
+	unsigned int i;
+	u32 word;
+
+	memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+	for (i = 0; i < ring->stats.limit; i++) {
+		rxd = ring->entry[i].priv;
+
+		rt2x00_desc_read(rxd, 5, &word);
+		rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS,
+				   ring->entry[i].data_dma);
+		rt2x00_desc_write(rxd, 5, word);
+
+		rt2x00_desc_read(rxd, 0, &word);
+		rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1);
+		rt2x00_desc_write(rxd, 0, word);
+	}
+
+	rt2x00_ring_index_clear(rt2x00dev->rx);
+}
+
+static void rt61pci_init_txring(struct rt2x00_dev *rt2x00dev, const int queue)
+{
+	struct data_ring *ring = rt2x00lib_get_ring(rt2x00dev, queue);
+	struct data_desc *txd;
+	unsigned int i;
+	u32 word;
+
+	memset(ring->data_addr, 0x00, rt2x00_get_ring_size(ring));
+
+	for (i = 0; i < ring->stats.limit; i++) {
+		txd = ring->entry[i].priv;
+
+		rt2x00_desc_read(txd, 1, &word);
+		rt2x00_set_field32(&word, TXD_W1_BUFFER_COUNT, 1);
+		rt2x00_desc_write(txd, 1, word);
+
+		rt2x00_desc_read(txd, 5, &word);
+		rt2x00_set_field32(&word, TXD_W5_PID_TYPE, queue);
+		rt2x00_set_field32(&word, TXD_W5_PID_SUBTYPE, i);
+		rt2x00_desc_write(txd, 5, word);
+
+		rt2x00_desc_read(txd, 6, &word);
+		rt2x00_set_field32(&word, TXD_W6_BUFFER_PHYSICAL_ADDRESS,
+				   ring->entry[i].data_dma);
+		rt2x00_desc_write(txd, 6, word);
+
+		rt2x00_desc_read(txd, 0, &word);
+		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+		rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0);
+		rt2x00_desc_write(txd, 0, word);
+	}
+
+	rt2x00_ring_index_clear(ring);
+}
+
+static int rt61pci_init_rings(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	/*
+	 * Initialize rings.
+	 */
+	rt61pci_init_rxring(rt2x00dev);
+	rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA0);
+	rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA1);
+	rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA2);
+	rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA3);
+	rt61pci_init_txring(rt2x00dev, IEEE80211_TX_QUEUE_DATA4);
+
+	/*
+	 * Initialize registers.
+	 */
+	rt2x00pci_register_read(rt2x00dev, TX_RING_CSR0, &reg);
+	rt2x00_set_field32(&reg, TX_RING_CSR0_AC0_RING_SIZE,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].stats.limit);
+	rt2x00_set_field32(&reg, TX_RING_CSR0_AC1_RING_SIZE,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].stats.limit);
+	rt2x00_set_field32(&reg, TX_RING_CSR0_AC2_RING_SIZE,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA2].stats.limit);
+	rt2x00_set_field32(&reg, TX_RING_CSR0_AC3_RING_SIZE,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA3].stats.limit);
+	rt2x00pci_register_write(rt2x00dev, TX_RING_CSR0, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TX_RING_CSR1, &reg);
+	rt2x00_set_field32(&reg, TX_RING_CSR1_MGMT_RING_SIZE,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA4].stats.limit);
+	rt2x00_set_field32(&reg, TX_RING_CSR1_TXD_SIZE,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].desc_size /
+			   4);
+	rt2x00pci_register_write(rt2x00dev, TX_RING_CSR1, reg);
+
+	rt2x00pci_register_read(rt2x00dev, AC0_BASE_CSR, &reg);
+	rt2x00_set_field32(&reg, AC0_BASE_CSR_RING_REGISTER,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA0].data_dma);
+	rt2x00pci_register_write(rt2x00dev, AC0_BASE_CSR, reg);
+
+	rt2x00pci_register_read(rt2x00dev, AC1_BASE_CSR, &reg);
+	rt2x00_set_field32(&reg, AC1_BASE_CSR_RING_REGISTER,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA1].data_dma);
+	rt2x00pci_register_write(rt2x00dev, AC1_BASE_CSR, reg);
+
+	rt2x00pci_register_read(rt2x00dev, AC2_BASE_CSR, &reg);
+	rt2x00_set_field32(&reg, AC2_BASE_CSR_RING_REGISTER,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA2].data_dma);
+	rt2x00pci_register_write(rt2x00dev, AC2_BASE_CSR, reg);
+
+	rt2x00pci_register_read(rt2x00dev, AC3_BASE_CSR, &reg);
+	rt2x00_set_field32(&reg, AC3_BASE_CSR_RING_REGISTER,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA3].data_dma);
+	rt2x00pci_register_write(rt2x00dev, AC3_BASE_CSR, reg);
+
+	rt2x00pci_register_read(rt2x00dev, MGMT_BASE_CSR, &reg);
+	rt2x00_set_field32(&reg, MGMT_BASE_CSR_RING_REGISTER,
+			   rt2x00dev->tx[IEEE80211_TX_QUEUE_DATA4].data_dma);
+	rt2x00pci_register_write(rt2x00dev, MGMT_BASE_CSR, reg);
+
+	rt2x00pci_register_read(rt2x00dev, RX_RING_CSR, &reg);
+	rt2x00_set_field32(&reg, RX_RING_CSR_RING_SIZE,
+			   rt2x00dev->rx->stats.limit);
+	rt2x00_set_field32(&reg, RX_RING_CSR_RXD_SIZE,
+			   rt2x00dev->rx->desc_size / 4);
+	rt2x00_set_field32(&reg, RX_RING_CSR_RXD_WRITEBACK_SIZE, 4);
+	rt2x00pci_register_write(rt2x00dev, RX_RING_CSR, reg);
+
+	rt2x00pci_register_read(rt2x00dev, RX_BASE_CSR, &reg);
+	rt2x00_set_field32(&reg, RX_BASE_CSR_RING_REGISTER,
+			   rt2x00dev->rx->data_dma);
+	rt2x00pci_register_write(rt2x00dev, RX_BASE_CSR, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TX_DMA_DST_CSR, &reg);
+	rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC0, 2);
+	rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC1, 2);
+	rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC2, 2);
+	rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_AC3, 2);
+	rt2x00_set_field32(&reg, TX_DMA_DST_CSR_DEST_MGMT, 0);
+	rt2x00pci_register_write(rt2x00dev, TX_DMA_DST_CSR, reg);
+
+	rt2x00pci_register_read(rt2x00dev, LOAD_TX_RING_CSR, &reg);
+	rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC0, 1);
+	rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC1, 1);
+	rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC2, 1);
+	rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_AC3, 1);
+	rt2x00_set_field32(&reg, LOAD_TX_RING_CSR_LOAD_TXD_MGMT, 1);
+	rt2x00pci_register_write(rt2x00dev, LOAD_TX_RING_CSR, reg);
+
+	rt2x00pci_register_read(rt2x00dev, RX_CNTL_CSR, &reg);
+	rt2x00_set_field32(&reg, RX_CNTL_CSR_LOAD_RXD, 1);
+	rt2x00pci_register_write(rt2x00dev, RX_CNTL_CSR, reg);
+
+	return 0;
+}
+
+static int rt61pci_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 0);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR1, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */
+	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0_VALID, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1, 30); /* Rssi */
+	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1_VALID, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2, 42); /* OFDM Rate */
+	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2_VALID, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3, 30); /* Rssi */
+	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3_VALID, 1);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR1, reg);
+
+	/*
+	 * CCK TXD BBP registers
+	 */
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR2, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0, 13);
+	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0_VALID, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1, 12);
+	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1_VALID, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2, 11);
+	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2_VALID, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3, 10);
+	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3_VALID, 1);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR2, reg);
+
+	/*
+	 * OFDM TXD BBP registers
+	 */
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR3, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0, 7);
+	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0_VALID, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1, 6);
+	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1_VALID, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2, 5);
+	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2_VALID, 1);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR3, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR7, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_6MBS, 59);
+	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_9MBS, 53);
+	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_12MBS, 49);
+	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_18MBS, 46);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR7, reg);
+
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR8, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_24MBS, 44);
+	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_36MBS, 42);
+	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_48MBS, 42);
+	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR8, reg);
+
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
+
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR6, 0x00000fff);
+
+	rt2x00pci_register_read(rt2x00dev, MAC_CSR9, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg);
+
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x0000071c);
+
+	if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+		return -EBUSY;
+
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR13, 0x0000e000);
+
+	/*
+	 * Invalidate all Shared Keys (SEC_CSR0),
+	 * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5)
+	 */
+	rt2x00pci_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
+	rt2x00pci_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
+	rt2x00pci_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
+
+	rt2x00pci_register_write(rt2x00dev, PHY_CSR1, 0x000023b0);
+	rt2x00pci_register_write(rt2x00dev, PHY_CSR5, 0x060a100c);
+	rt2x00pci_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
+	rt2x00pci_register_write(rt2x00dev, PHY_CSR7, 0x00000a08);
+
+	rt2x00pci_register_write(rt2x00dev, PCI_CFG_CSR, 0x28ca4404);
+
+	rt2x00pci_register_write(rt2x00dev, TEST_MODE_CSR, 0x00000200);
+
+	rt2x00pci_register_write(rt2x00dev, M2H_CMD_DONE_CSR, 0xffffffff);
+
+	rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
+	rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC0_TX_OP, 0);
+	rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC1_TX_OP, 0);
+	rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
+
+	rt2x00pci_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
+	rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC2_TX_OP, 192);
+	rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC3_TX_OP, 48);
+	rt2x00pci_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
+
+	/*
+	 * We must clear the error counters.
+	 * These registers are cleared on read,
+	 * so we may pass a useless variable to store the value.
+	 */
+	rt2x00pci_register_read(rt2x00dev, STA_CSR0, &reg);
+	rt2x00pci_register_read(rt2x00dev, STA_CSR1, &reg);
+	rt2x00pci_register_read(rt2x00dev, STA_CSR2, &reg);
+
+	/*
+	 * Reset MAC and BBP registers.
+	 */
+	rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 1);
+	rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 1);
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+	rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 0);
+	rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 0);
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+	rt2x00pci_register_read(rt2x00dev, MAC_CSR1, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR1_HOST_READY, 1);
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR1, reg);
+
+	return 0;
+}
+
+static int rt61pci_init_bbp(struct rt2x00_dev *rt2x00dev)
+{
+	unsigned int i;
+	u16 eeprom;
+	u8 reg_id;
+	u8 value;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt61pci_bbp_read(rt2x00dev, 0, &value);
+		if ((value != 0xff) && (value != 0x00))
+			goto continue_csr_init;
+		NOTICE(rt2x00dev, "Waiting for BBP register.\n");
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+	return -EACCES;
+
+continue_csr_init:
+	rt61pci_bbp_write(rt2x00dev, 3, 0x00);
+	rt61pci_bbp_write(rt2x00dev, 15, 0x30);
+	rt61pci_bbp_write(rt2x00dev, 21, 0xc8);
+	rt61pci_bbp_write(rt2x00dev, 22, 0x38);
+	rt61pci_bbp_write(rt2x00dev, 23, 0x06);
+	rt61pci_bbp_write(rt2x00dev, 24, 0xfe);
+	rt61pci_bbp_write(rt2x00dev, 25, 0x0a);
+	rt61pci_bbp_write(rt2x00dev, 26, 0x0d);
+	rt61pci_bbp_write(rt2x00dev, 34, 0x12);
+	rt61pci_bbp_write(rt2x00dev, 37, 0x07);
+	rt61pci_bbp_write(rt2x00dev, 39, 0xf8);
+	rt61pci_bbp_write(rt2x00dev, 41, 0x60);
+	rt61pci_bbp_write(rt2x00dev, 53, 0x10);
+	rt61pci_bbp_write(rt2x00dev, 54, 0x18);
+	rt61pci_bbp_write(rt2x00dev, 60, 0x10);
+	rt61pci_bbp_write(rt2x00dev, 61, 0x04);
+	rt61pci_bbp_write(rt2x00dev, 62, 0x04);
+	rt61pci_bbp_write(rt2x00dev, 75, 0xfe);
+	rt61pci_bbp_write(rt2x00dev, 86, 0xfe);
+	rt61pci_bbp_write(rt2x00dev, 88, 0xfe);
+	rt61pci_bbp_write(rt2x00dev, 90, 0x0f);
+	rt61pci_bbp_write(rt2x00dev, 99, 0x00);
+	rt61pci_bbp_write(rt2x00dev, 102, 0x16);
+	rt61pci_bbp_write(rt2x00dev, 107, 0x04);
+
+	DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
+	for (i = 0; i < EEPROM_BBP_SIZE; i++) {
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+
+		if (eeprom != 0xffff && eeprom != 0x0000) {
+			reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
+			value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
+			DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
+			      reg_id, value);
+			rt61pci_bbp_write(rt2x00dev, reg_id, value);
+		}
+	}
+	DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
+
+	return 0;
+}
+
+/*
+ * Device state switch handlers.
+ */
+static void rt61pci_toggle_rx(struct rt2x00_dev *rt2x00dev,
+			      enum dev_state state)
+{
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX,
+			   state == STATE_RADIO_RX_OFF);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+}
+
+static void rt61pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
+			       enum dev_state state)
+{
+	int mask = (state == STATE_RADIO_IRQ_OFF);
+	u32 reg;
+
+	/*
+	 * When interrupts are being enabled, the interrupt registers
+	 * should clear the register to assure a clean state.
+	 */
+	if (state == STATE_RADIO_IRQ_ON) {
+		rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+		rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+
+		rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg);
+		rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg);
+	}
+
+	/*
+	 * Only toggle the interrupts bits we are going to use.
+	 * Non-checked interrupt bits are disabled by default.
+	 */
+	rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+	rt2x00_set_field32(&reg, INT_MASK_CSR_TXDONE, mask);
+	rt2x00_set_field32(&reg, INT_MASK_CSR_RXDONE, mask);
+	rt2x00_set_field32(&reg, INT_MASK_CSR_ENABLE_MITIGATION, mask);
+	rt2x00_set_field32(&reg, INT_MASK_CSR_MITIGATION_PERIOD, 0xff);
+	rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
+
+	rt2x00pci_register_read(rt2x00dev, MCU_INT_MASK_CSR, &reg);
+	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_0, mask);
+	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_1, mask);
+	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_2, mask);
+	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_3, mask);
+	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_4, mask);
+	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_5, mask);
+	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_6, mask);
+	rt2x00_set_field32(&reg, MCU_INT_MASK_CSR_7, mask);
+	rt2x00pci_register_write(rt2x00dev, MCU_INT_MASK_CSR, reg);
+}
+
+static int rt61pci_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	/*
+	 * Initialize all registers.
+	 */
+	if (rt61pci_init_rings(rt2x00dev) ||
+	    rt61pci_init_registers(rt2x00dev) ||
+	    rt61pci_init_bbp(rt2x00dev)) {
+		ERROR(rt2x00dev, "Register initialization failed.\n");
+		return -EIO;
+	}
+
+	/*
+	 * Enable interrupts.
+	 */
+	rt61pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON);
+
+	/*
+	 * Enable RX.
+	 */
+	rt2x00pci_register_read(rt2x00dev, RX_CNTL_CSR, &reg);
+	rt2x00_set_field32(&reg, RX_CNTL_CSR_ENABLE_RX_DMA, 1);
+	rt2x00pci_register_write(rt2x00dev, RX_CNTL_CSR, reg);
+
+	/*
+	 * Enable LED
+	 */
+	rt61pci_enable_led(rt2x00dev);
+
+	return 0;
+}
+
+static void rt61pci_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	/*
+	 * Disable LED
+	 */
+	rt61pci_disable_led(rt2x00dev);
+
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
+
+	/*
+	 * Disable synchronisation.
+	 */
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, 0);
+
+	/*
+	 * Cancel RX and TX.
+	 */
+	rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+	rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC0, 1);
+	rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC1, 1);
+	rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC2, 1);
+	rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_AC3, 1);
+	rt2x00_set_field32(&reg, TX_CNTL_CSR_ABORT_TX_MGMT, 1);
+	rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+
+	/*
+	 * Disable interrupts.
+	 */
+	rt61pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_OFF);
+}
+
+static int rt61pci_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
+{
+	u32 reg;
+	unsigned int i;
+	char put_to_sleep;
+	char current_state;
+
+	put_to_sleep = (state != STATE_AWAKE);
+
+	rt2x00pci_register_read(rt2x00dev, MAC_CSR12, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep);
+	rt2x00_set_field32(&reg, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep);
+	rt2x00pci_register_write(rt2x00dev, MAC_CSR12, reg);
+
+	/*
+	 * Device is not guaranteed to be in the requested state yet.
+	 * We must wait until the register indicates that the
+	 * device has entered the correct state.
+	 */
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt2x00pci_register_read(rt2x00dev, MAC_CSR12, &reg);
+		current_state =
+		    rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE);
+		if (current_state == !put_to_sleep)
+			return 0;
+		msleep(10);
+	}
+
+	NOTICE(rt2x00dev, "Device failed to enter state %d, "
+	       "current device state %d.\n", !put_to_sleep, current_state);
+
+	return -EBUSY;
+}
+
+static int rt61pci_set_device_state(struct rt2x00_dev *rt2x00dev,
+				    enum dev_state state)
+{
+	int retval = 0;
+
+	switch (state) {
+	case STATE_RADIO_ON:
+		retval = rt61pci_enable_radio(rt2x00dev);
+		break;
+	case STATE_RADIO_OFF:
+		rt61pci_disable_radio(rt2x00dev);
+		break;
+	case STATE_RADIO_RX_ON:
+	case STATE_RADIO_RX_OFF:
+		rt61pci_toggle_rx(rt2x00dev, state);
+		break;
+	case STATE_DEEP_SLEEP:
+	case STATE_SLEEP:
+	case STATE_STANDBY:
+	case STATE_AWAKE:
+		retval = rt61pci_set_state(rt2x00dev, state);
+		break;
+	default:
+		retval = -ENOTSUPP;
+		break;
+	}
+
+	return retval;
+}
+
+/*
+ * TX descriptor initialization
+ */
+static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+				  struct data_desc *txd,
+				  struct txdata_entry_desc *desc,
+				  struct ieee80211_hdr *ieee80211hdr,
+				  unsigned int length,
+				  struct ieee80211_tx_control *control)
+{
+	u32 word;
+
+	/*
+	 * Start writing the descriptor words.
+	 */
+	rt2x00_desc_read(txd, 1, &word);
+	rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, desc->queue);
+	rt2x00_set_field32(&word, TXD_W1_AIFSN, desc->aifs);
+	rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min);
+	rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max);
+	rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
+	rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
+	rt2x00_desc_write(txd, 1, word);
+
+	rt2x00_desc_read(txd, 2, &word);
+	rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal);
+	rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service);
+	rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low);
+	rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high);
+	rt2x00_desc_write(txd, 2, word);
+
+	rt2x00_desc_read(txd, 5, &word);
+	rt2x00_set_field32(&word, TXD_W5_TX_POWER,
+			   TXPOWER_TO_DEV(control->power_level));
+	rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
+	rt2x00_desc_write(txd, 5, word);
+
+	rt2x00_desc_read(txd, 11, &word);
+	rt2x00_set_field32(&word, TXD_W11_BUFFER_LENGTH0, length);
+	rt2x00_desc_write(txd, 11, word);
+
+	rt2x00_desc_read(txd, 0, &word);
+	rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 1);
+	rt2x00_set_field32(&word, TXD_W0_VALID, 1);
+	rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+			   test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_ACK,
+			   !(control->flags & IEEE80211_TXCTL_NO_ACK));
+	rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+			   test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_OFDM,
+			   test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+	rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
+			   !!(control->flags &
+			      IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+	rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
+	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
+	rt2x00_set_field32(&word, TXD_W0_BURST,
+			   test_bit(ENTRY_TXD_BURST, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
+	rt2x00_desc_write(txd, 0, word);
+}
+
+/*
+ * TX data initialization
+ */
+static void rt61pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+				  unsigned int queue)
+{
+	u32 reg;
+
+	if (queue == IEEE80211_TX_QUEUE_BEACON) {
+		/*
+		 * For Wi-Fi faily generated beacons between participating
+		 * stations. Set TBTT phase adaptive adjustment step to 8us.
+		 */
+		rt2x00pci_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
+
+		rt2x00pci_register_read(rt2x00dev, TXRX_CSR9, &reg);
+		if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
+			rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
+			rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
+		}
+		return;
+	}
+
+	rt2x00pci_register_read(rt2x00dev, TX_CNTL_CSR, &reg);
+	if (queue == IEEE80211_TX_QUEUE_DATA0)
+		rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC0, 1);
+	else if (queue == IEEE80211_TX_QUEUE_DATA1)
+		rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC1, 1);
+	else if (queue == IEEE80211_TX_QUEUE_DATA2)
+		rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC2, 1);
+	else if (queue == IEEE80211_TX_QUEUE_DATA3)
+		rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_AC3, 1);
+	else if (queue == IEEE80211_TX_QUEUE_DATA4)
+		rt2x00_set_field32(&reg, TX_CNTL_CSR_KICK_TX_MGMT, 1);
+	rt2x00pci_register_write(rt2x00dev, TX_CNTL_CSR, reg);
+}
+
+/*
+ * RX control handlers
+ */
+static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
+{
+	u16 eeprom;
+	u8 offset;
+	u8 lna;
+
+	lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA);
+	switch (lna) {
+	case 3:
+		offset = 90;
+		break;
+	case 2:
+		offset = 74;
+		break;
+	case 1:
+		offset = 64;
+		break;
+	default:
+		return 0;
+	}
+
+	if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+		if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
+			offset += 14;
+
+		if (lna == 3 || lna == 2)
+			offset += 10;
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+		offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+	} else {
+		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+			offset += 14;
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+		offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+	}
+
+	return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
+}
+
+static void rt61pci_fill_rxdone(struct data_entry *entry,
+			        struct rxdata_entry_desc *desc)
+{
+	struct data_desc *rxd = entry->priv;
+	u32 word0;
+	u32 word1;
+
+	rt2x00_desc_read(rxd, 0, &word0);
+	rt2x00_desc_read(rxd, 1, &word1);
+
+	desc->flags = 0;
+	if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+		desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+
+	/*
+	 * Obtain the status about this packet.
+	 */
+	desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+	desc->rssi = rt61pci_agc_to_rssi(entry->ring->rt2x00dev, word1);
+	desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+	desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+
+	return;
+}
+
+/*
+ * Interrupt functions.
+ */
+static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
+{
+	struct data_ring *ring;
+	struct data_entry *entry;
+	struct data_desc *txd;
+	u32 word;
+	u32 reg;
+	u32 old_reg;
+	int type;
+	int index;
+	int tx_status;
+	int retry;
+
+	/*
+	 * During each loop we will compare the freshly read
+	 * STA_CSR4 register value with the value read from
+	 * the previous loop. If the 2 values are equal then
+	 * we should stop processing because the chance it
+	 * quite big that the device has been unplugged and
+	 * we risk going into an endless loop.
+	 */
+	old_reg = 0;
+
+	while (1) {
+		rt2x00pci_register_read(rt2x00dev, STA_CSR4, &reg);
+		if (!rt2x00_get_field32(reg, STA_CSR4_VALID))
+			break;
+
+		if (old_reg == reg)
+			break;
+		old_reg = reg;
+
+		/*
+		 * Skip this entry when it contains an invalid
+		 * ring identication number.
+		 */
+		type = rt2x00_get_field32(reg, STA_CSR4_PID_TYPE);
+		ring = rt2x00lib_get_ring(rt2x00dev, type);
+		if (unlikely(!ring))
+			continue;
+
+		/*
+		 * Skip this entry when it contains an invalid
+		 * index number.
+		 */
+		index = rt2x00_get_field32(reg, STA_CSR4_PID_SUBTYPE);
+		if (unlikely(index >= ring->stats.limit))
+			continue;
+
+		entry = &ring->entry[index];
+		txd = entry->priv;
+		rt2x00_desc_read(txd, 0, &word);
+
+		if (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) ||
+		    !rt2x00_get_field32(word, TXD_W0_VALID))
+			return;
+
+		/*
+		 * Obtain the status about this packet.
+		 */
+		tx_status = rt2x00_get_field32(reg, STA_CSR4_TX_RESULT);
+		retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
+
+		rt2x00lib_txdone(entry, tx_status, retry);
+
+		/*
+		 * Make this entry available for reuse.
+		 */
+		entry->flags = 0;
+		rt2x00_set_field32(&word, TXD_W0_VALID, 0);
+		rt2x00_desc_write(txd, 0, word);
+		rt2x00_ring_index_done_inc(entry->ring);
+
+		/*
+		 * If the data ring was full before the txdone handler
+		 * we must make sure the packet queue in the mac80211 stack
+		 * is reenabled when the txdone handler has finished.
+		 */
+		if (!rt2x00_ring_full(ring))
+			ieee80211_wake_queue(rt2x00dev->hw,
+					     entry->tx_status.control.queue);
+	}
+}
+
+static irqreturn_t rt61pci_interrupt(int irq, void *dev_instance)
+{
+	struct rt2x00_dev *rt2x00dev = dev_instance;
+	u32 reg_mcu;
+	u32 reg;
+
+	/*
+	 * Get the interrupt sources & saved to local variable.
+	 * Write register value back to clear pending interrupts.
+	 */
+	rt2x00pci_register_read(rt2x00dev, MCU_INT_SOURCE_CSR, &reg_mcu);
+	rt2x00pci_register_write(rt2x00dev, MCU_INT_SOURCE_CSR, reg_mcu);
+
+	rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+	rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+
+	if (!reg && !reg_mcu)
+		return IRQ_NONE;
+
+	if (!test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags))
+		return IRQ_HANDLED;
+
+	/*
+	 * Handle interrupts, walk through all bits
+	 * and run the tasks, the bits are checked in order of
+	 * priority.
+	 */
+
+	/*
+	 * 1 - Rx ring done interrupt.
+	 */
+	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_RXDONE))
+		rt2x00pci_rxdone(rt2x00dev);
+
+	/*
+	 * 2 - Tx ring done interrupt.
+	 */
+	if (rt2x00_get_field32(reg, INT_SOURCE_CSR_TXDONE))
+		rt61pci_txdone(rt2x00dev);
+
+	/*
+	 * 3 - Handle MCU command done.
+	 */
+	if (reg_mcu)
+		rt2x00pci_register_write(rt2x00dev,
+					 M2H_CMD_DONE_CSR, 0xffffffff);
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * Device probe functions.
+ */
+static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+	struct eeprom_93cx6 eeprom;
+	u32 reg;
+	u16 word;
+	u8 *mac;
+	s8 value;
+
+	rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
+
+	eeprom.data = rt2x00dev;
+	eeprom.register_read = rt61pci_eepromregister_read;
+	eeprom.register_write = rt61pci_eepromregister_write;
+	eeprom.width = rt2x00_get_field32(reg, E2PROM_CSR_TYPE_93C46) ?
+	    PCI_EEPROM_WIDTH_93C46 : PCI_EEPROM_WIDTH_93C66;
+	eeprom.reg_data_in = 0;
+	eeprom.reg_data_out = 0;
+	eeprom.reg_data_clock = 0;
+	eeprom.reg_chip_select = 0;
+
+	eeprom_93cx6_multiread(&eeprom, EEPROM_BASE, rt2x00dev->eeprom,
+			       EEPROM_SIZE / sizeof(u16));
+
+	/*
+	 * Start validation of the data that has been read.
+	 */
+	mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+	if (!is_valid_ether_addr(mac)) {
+		DECLARE_MAC_BUF(macbuf);
+
+		random_ether_addr(mac);
+		EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 2);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 2);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF5225);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+		EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_NIC_ENABLE_DIVERSITY, 0);
+		rt2x00_set_field16(&word, EEPROM_NIC_TX_DIVERSITY, 0);
+		rt2x00_set_field16(&word, EEPROM_NIC_TX_RX_FIXED, 0);
+		rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_BG, 0);
+		rt2x00_set_field16(&word, EEPROM_NIC_CARDBUS_ACCEL, 0);
+		rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA_A, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
+		EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_LED_LED_MODE,
+				   LED_MODE_DEFAULT);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_LED, word);
+		EEPROM(rt2x00dev, "Led: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
+		rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
+		EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+		EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+	} else {
+		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1);
+		if (value < -10 || value > 10)
+			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2);
+		if (value < -10 || value > 10)
+			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+		EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+	} else {
+		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1);
+		if (value < -10 || value > 10)
+			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2);
+		if (value < -10 || value > 10)
+			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+	}
+
+	return 0;
+}
+
+static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+	u16 value;
+	u16 eeprom;
+	u16 device;
+
+	/*
+	 * Read EEPROM word for configuration.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+	/*
+	 * Identify RF chipset.
+	 * To determine the RT chip we have to read the
+	 * PCI header of the device.
+	 */
+	pci_read_config_word(rt2x00dev_pci(rt2x00dev),
+			     PCI_CONFIG_HEADER_DEVICE, &device);
+	value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+	rt2x00pci_register_read(rt2x00dev, MAC_CSR0, &reg);
+	rt2x00_set_chip(rt2x00dev, device, value, reg);
+
+	if (!rt2x00_rf(&rt2x00dev->chip, RF5225) &&
+	    !rt2x00_rf(&rt2x00dev->chip, RF5325) &&
+	    !rt2x00_rf(&rt2x00dev->chip, RF2527) &&
+	    !rt2x00_rf(&rt2x00dev->chip, RF2529)) {
+		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Identify default antenna configuration.
+	 */
+	rt2x00dev->hw->conf.antenna_sel_tx =
+	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
+	rt2x00dev->hw->conf.antenna_sel_rx =
+	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
+
+	/*
+	 * Read the Frame type.
+	 */
+	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE))
+		__set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags);
+
+	/*
+	 * Determine number of antenna's.
+	 */
+	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2)
+		__set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags);
+
+	/*
+	 * Detect if this device has an hardware controlled radio.
+	 */
+#ifdef CONFIG_RT61PCI_RFKILL
+	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
+		__set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+#endif /* CONFIG_RT61PCI_RFKILL */
+
+	/*
+	 * Read frequency offset and RF programming sequence.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
+	if (rt2x00_get_field16(eeprom, EEPROM_FREQ_SEQ))
+		__set_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags);
+
+	rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
+
+	/*
+	 * Read external LNA informations.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+
+	if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A))
+		__set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+	if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
+		__set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+
+	/*
+	 * Store led settings, for correct led behaviour.
+	 * If the eeprom value is invalid,
+	 * switch to default led mode.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom);
+
+	rt2x00dev->led_mode = rt2x00_get_field16(eeprom, EEPROM_LED_LED_MODE);
+
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LED_MODE,
+			   rt2x00dev->led_mode);
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_0,
+			   rt2x00_get_field16(eeprom,
+					      EEPROM_LED_POLARITY_GPIO_0));
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_1,
+			   rt2x00_get_field16(eeprom,
+					      EEPROM_LED_POLARITY_GPIO_1));
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_2,
+			   rt2x00_get_field16(eeprom,
+					      EEPROM_LED_POLARITY_GPIO_2));
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_3,
+			   rt2x00_get_field16(eeprom,
+					      EEPROM_LED_POLARITY_GPIO_3));
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_4,
+			   rt2x00_get_field16(eeprom,
+					      EEPROM_LED_POLARITY_GPIO_4));
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_ACT,
+			   rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_ACT));
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_BG,
+			   rt2x00_get_field16(eeprom,
+					      EEPROM_LED_POLARITY_RDY_G));
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_A,
+			   rt2x00_get_field16(eeprom,
+					      EEPROM_LED_POLARITY_RDY_A));
+
+	return 0;
+}
+
+/*
+ * RF value list for RF5225 & RF5325
+ * Supports: 2.4 GHz & 5.2 GHz, rf_sequence disabled
+ */
+static const struct rf_channel rf_vals_noseq[] = {
+	{ 1,  0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b },
+	{ 2,  0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f },
+	{ 3,  0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b },
+	{ 4,  0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f },
+	{ 5,  0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b },
+	{ 6,  0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f },
+	{ 7,  0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b },
+	{ 8,  0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f },
+	{ 9,  0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b },
+	{ 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f },
+	{ 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b },
+	{ 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f },
+	{ 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b },
+	{ 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 },
+
+	/* 802.11 UNI / HyperLan 2 */
+	{ 36, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa23 },
+	{ 40, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa03 },
+	{ 44, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa0b },
+	{ 48, 0x00002ccc, 0x000049aa, 0x0009be55, 0x000ffa13 },
+	{ 52, 0x00002ccc, 0x000049ae, 0x0009ae55, 0x000ffa1b },
+	{ 56, 0x00002ccc, 0x000049b2, 0x0009ae55, 0x000ffa23 },
+	{ 60, 0x00002ccc, 0x000049ba, 0x0009ae55, 0x000ffa03 },
+	{ 64, 0x00002ccc, 0x000049be, 0x0009ae55, 0x000ffa0b },
+
+	/* 802.11 HyperLan 2 */
+	{ 100, 0x00002ccc, 0x00004a2a, 0x000bae55, 0x000ffa03 },
+	{ 104, 0x00002ccc, 0x00004a2e, 0x000bae55, 0x000ffa0b },
+	{ 108, 0x00002ccc, 0x00004a32, 0x000bae55, 0x000ffa13 },
+	{ 112, 0x00002ccc, 0x00004a36, 0x000bae55, 0x000ffa1b },
+	{ 116, 0x00002ccc, 0x00004a3a, 0x000bbe55, 0x000ffa23 },
+	{ 120, 0x00002ccc, 0x00004a82, 0x000bbe55, 0x000ffa03 },
+	{ 124, 0x00002ccc, 0x00004a86, 0x000bbe55, 0x000ffa0b },
+	{ 128, 0x00002ccc, 0x00004a8a, 0x000bbe55, 0x000ffa13 },
+	{ 132, 0x00002ccc, 0x00004a8e, 0x000bbe55, 0x000ffa1b },
+	{ 136, 0x00002ccc, 0x00004a92, 0x000bbe55, 0x000ffa23 },
+
+	/* 802.11 UNII */
+	{ 140, 0x00002ccc, 0x00004a9a, 0x000bbe55, 0x000ffa03 },
+	{ 149, 0x00002ccc, 0x00004aa2, 0x000bbe55, 0x000ffa1f },
+	{ 153, 0x00002ccc, 0x00004aa6, 0x000bbe55, 0x000ffa27 },
+	{ 157, 0x00002ccc, 0x00004aae, 0x000bbe55, 0x000ffa07 },
+	{ 161, 0x00002ccc, 0x00004ab2, 0x000bbe55, 0x000ffa0f },
+	{ 165, 0x00002ccc, 0x00004ab6, 0x000bbe55, 0x000ffa17 },
+
+	/* MMAC(Japan)J52 ch 34,38,42,46 */
+	{ 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa0b },
+	{ 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000ffa13 },
+	{ 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa1b },
+	{ 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa23 },
+};
+
+/*
+ * RF value list for RF5225 & RF5325
+ * Supports: 2.4 GHz & 5.2 GHz, rf_sequence enabled
+ */
+static const struct rf_channel rf_vals_seq[] = {
+	{ 1,  0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b },
+	{ 2,  0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f },
+	{ 3,  0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b },
+	{ 4,  0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f },
+	{ 5,  0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b },
+	{ 6,  0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f },
+	{ 7,  0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b },
+	{ 8,  0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f },
+	{ 9,  0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b },
+	{ 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f },
+	{ 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b },
+	{ 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f },
+	{ 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b },
+	{ 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 },
+
+	/* 802.11 UNI / HyperLan 2 */
+	{ 36, 0x00002cd4, 0x0004481a, 0x00098455, 0x000c0a03 },
+	{ 40, 0x00002cd0, 0x00044682, 0x00098455, 0x000c0a03 },
+	{ 44, 0x00002cd0, 0x00044686, 0x00098455, 0x000c0a1b },
+	{ 48, 0x00002cd0, 0x0004468e, 0x00098655, 0x000c0a0b },
+	{ 52, 0x00002cd0, 0x00044692, 0x00098855, 0x000c0a23 },
+	{ 56, 0x00002cd0, 0x0004469a, 0x00098c55, 0x000c0a13 },
+	{ 60, 0x00002cd0, 0x000446a2, 0x00098e55, 0x000c0a03 },
+	{ 64, 0x00002cd0, 0x000446a6, 0x00099255, 0x000c0a1b },
+
+	/* 802.11 HyperLan 2 */
+	{ 100, 0x00002cd4, 0x0004489a, 0x000b9855, 0x000c0a03 },
+	{ 104, 0x00002cd4, 0x000448a2, 0x000b9855, 0x000c0a03 },
+	{ 108, 0x00002cd4, 0x000448aa, 0x000b9855, 0x000c0a03 },
+	{ 112, 0x00002cd4, 0x000448b2, 0x000b9a55, 0x000c0a03 },
+	{ 116, 0x00002cd4, 0x000448ba, 0x000b9a55, 0x000c0a03 },
+	{ 120, 0x00002cd0, 0x00044702, 0x000b9a55, 0x000c0a03 },
+	{ 124, 0x00002cd0, 0x00044706, 0x000b9a55, 0x000c0a1b },
+	{ 128, 0x00002cd0, 0x0004470e, 0x000b9c55, 0x000c0a0b },
+	{ 132, 0x00002cd0, 0x00044712, 0x000b9c55, 0x000c0a23 },
+	{ 136, 0x00002cd0, 0x0004471a, 0x000b9e55, 0x000c0a13 },
+
+	/* 802.11 UNII */
+	{ 140, 0x00002cd0, 0x00044722, 0x000b9e55, 0x000c0a03 },
+	{ 149, 0x00002cd0, 0x0004472e, 0x000ba255, 0x000c0a1b },
+	{ 153, 0x00002cd0, 0x00044736, 0x000ba255, 0x000c0a0b },
+	{ 157, 0x00002cd4, 0x0004490a, 0x000ba255, 0x000c0a17 },
+	{ 161, 0x00002cd4, 0x00044912, 0x000ba255, 0x000c0a17 },
+	{ 165, 0x00002cd4, 0x0004491a, 0x000ba255, 0x000c0a17 },
+
+	/* MMAC(Japan)J52 ch 34,38,42,46 */
+	{ 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000c0a0b },
+	{ 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000c0a13 },
+	{ 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000c0a1b },
+	{ 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000c0a23 },
+};
+
+static void rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+{
+	struct hw_mode_spec *spec = &rt2x00dev->spec;
+	u8 *txpower;
+	unsigned int i;
+
+	/*
+	 * Initialize all hw fields.
+	 */
+	rt2x00dev->hw->flags =
+	    IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+	    IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+	rt2x00dev->hw->extra_tx_headroom = 0;
+	rt2x00dev->hw->max_signal = MAX_SIGNAL;
+	rt2x00dev->hw->max_rssi = MAX_RX_SSI;
+	rt2x00dev->hw->queues = 5;
+
+	SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_pci(rt2x00dev)->dev);
+	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+				rt2x00_eeprom_addr(rt2x00dev,
+						   EEPROM_MAC_ADDR_0));
+
+	/*
+	 * Convert tx_power array in eeprom.
+	 */
+	txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
+	for (i = 0; i < 14; i++)
+		txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+	/*
+	 * Initialize hw_mode information.
+	 */
+	spec->num_modes = 2;
+	spec->num_rates = 12;
+	spec->tx_power_a = NULL;
+	spec->tx_power_bg = txpower;
+	spec->tx_power_default = DEFAULT_TXPOWER;
+
+	if (!test_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags)) {
+		spec->num_channels = 14;
+		spec->channels = rf_vals_noseq;
+	} else {
+		spec->num_channels = 14;
+		spec->channels = rf_vals_seq;
+	}
+
+	if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+	    rt2x00_rf(&rt2x00dev->chip, RF5325)) {
+		spec->num_modes = 3;
+		spec->num_channels = ARRAY_SIZE(rf_vals_seq);
+
+		txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
+		for (i = 0; i < 14; i++)
+			txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+		spec->tx_power_a = txpower;
+	}
+}
+
+static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+	int retval;
+
+	/*
+	 * Allocate eeprom data.
+	 */
+	retval = rt61pci_validate_eeprom(rt2x00dev);
+	if (retval)
+		return retval;
+
+	retval = rt61pci_init_eeprom(rt2x00dev);
+	if (retval)
+		return retval;
+
+	/*
+	 * Initialize hw specifications.
+	 */
+	rt61pci_probe_hw_mode(rt2x00dev);
+
+	/*
+	 * This device requires firmware
+	 */
+	__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
+
+	/*
+	 * Set the rssi offset.
+	 */
+	rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
+	return 0;
+}
+
+/*
+ * IEEE80211 stack callback functions.
+ */
+static void rt61pci_configure_filter(struct ieee80211_hw *hw,
+				     unsigned int changed_flags,
+				     unsigned int *total_flags,
+				     int mc_count,
+				     struct dev_addr_list *mc_list)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct interface *intf = &rt2x00dev->interface;
+	u32 reg;
+
+	/*
+	 * Mask off any flags we are going to ignore from
+	 * the total_flags field.
+	 */
+	*total_flags &=
+	    FIF_ALLMULTI |
+	    FIF_FCSFAIL |
+	    FIF_PLCPFAIL |
+	    FIF_CONTROL |
+	    FIF_OTHER_BSS |
+	    FIF_PROMISC_IN_BSS;
+
+	/*
+	 * Apply some rules to the filters:
+	 * - Some filters imply different filters to be set.
+	 * - Some things we can't filter out at all.
+	 * - Some filters are set based on interface type.
+	 */
+	if (mc_count)
+		*total_flags |= FIF_ALLMULTI;
+	if (*total_flags & FIF_OTHER_BSS ||
+	    *total_flags & FIF_PROMISC_IN_BSS)
+		*total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+	if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+		*total_flags |= FIF_PROMISC_IN_BSS;
+
+	/*
+	 * Check if there is any work left for us.
+	 */
+	if (intf->filter == *total_flags)
+		return;
+	intf->filter = *total_flags;
+
+	/*
+	 * Start configuration steps.
+	 * Note that the version error will always be dropped
+	 * and broadcast frames will always be accepted since
+	 * there is no filter for it at this time.
+	 */
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CRC,
+			   !(*total_flags & FIF_FCSFAIL));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL,
+			   !(*total_flags & FIF_PLCPFAIL));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
+			   !(*total_flags & FIF_CONTROL));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST,
+			   !(*total_flags & FIF_ALLMULTI));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_BORADCAST, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS, 1);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR0, reg);
+}
+
+static int rt61pci_set_retry_limit(struct ieee80211_hw *hw,
+				   u32 short_retry, u32 long_retry)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry);
+	rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg);
+
+	return 0;
+}
+
+static u64 rt61pci_get_tsf(struct ieee80211_hw *hw)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	u64 tsf;
+	u32 reg;
+
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR13, &reg);
+	tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32;
+	rt2x00pci_register_read(rt2x00dev, TXRX_CSR12, &reg);
+	tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER);
+
+	return tsf;
+}
+
+static void rt61pci_reset_tsf(struct ieee80211_hw *hw)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR12, 0);
+	rt2x00pci_register_write(rt2x00dev, TXRX_CSR13, 0);
+}
+
+static int rt61pci_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+			  struct ieee80211_tx_control *control)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+
+	/*
+	 * Just in case the ieee80211 doesn't set this,
+	 * but we need this queue set for the descriptor
+	 * initialization.
+	 */
+	control->queue = IEEE80211_TX_QUEUE_BEACON;
+
+	/*
+	 * We need to append the descriptor in front of the
+	 * beacon frame.
+	 */
+	if (skb_headroom(skb) < TXD_DESC_SIZE) {
+		if (pskb_expand_head(skb, TXD_DESC_SIZE, 0, GFP_ATOMIC)) {
+			dev_kfree_skb(skb);
+			return -ENOMEM;
+		}
+	}
+
+	/*
+	 * First we create the beacon.
+	 */
+	skb_push(skb, TXD_DESC_SIZE);
+	memset(skb->data, 0, TXD_DESC_SIZE);
+
+	rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data,
+				(struct ieee80211_hdr *)(skb->data +
+							 TXD_DESC_SIZE),
+				skb->len - TXD_DESC_SIZE, control);
+
+	/*
+	 * Write entire beacon with descriptor to register,
+	 * and kick the beacon generator.
+	 */
+	rt2x00pci_register_multiwrite(rt2x00dev, HW_BEACON_BASE0,
+				      skb->data, skb->len);
+	rt61pci_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+
+	return 0;
+}
+
+static const struct ieee80211_ops rt61pci_mac80211_ops = {
+	.tx			= rt2x00mac_tx,
+	.start			= rt2x00mac_start,
+	.stop			= rt2x00mac_stop,
+	.add_interface		= rt2x00mac_add_interface,
+	.remove_interface	= rt2x00mac_remove_interface,
+	.config			= rt2x00mac_config,
+	.config_interface	= rt2x00mac_config_interface,
+	.configure_filter	= rt61pci_configure_filter,
+	.get_stats		= rt2x00mac_get_stats,
+	.set_retry_limit	= rt61pci_set_retry_limit,
+	.erp_ie_changed		= rt2x00mac_erp_ie_changed,
+	.conf_tx		= rt2x00mac_conf_tx,
+	.get_tx_stats		= rt2x00mac_get_tx_stats,
+	.get_tsf		= rt61pci_get_tsf,
+	.reset_tsf		= rt61pci_reset_tsf,
+	.beacon_update		= rt61pci_beacon_update,
+};
+
+static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
+	.irq_handler		= rt61pci_interrupt,
+	.probe_hw		= rt61pci_probe_hw,
+	.get_firmware_name	= rt61pci_get_firmware_name,
+	.load_firmware		= rt61pci_load_firmware,
+	.initialize		= rt2x00pci_initialize,
+	.uninitialize		= rt2x00pci_uninitialize,
+	.set_device_state	= rt61pci_set_device_state,
+	.rfkill_poll		= rt61pci_rfkill_poll,
+	.link_stats		= rt61pci_link_stats,
+	.reset_tuner		= rt61pci_reset_tuner,
+	.link_tuner		= rt61pci_link_tuner,
+	.write_tx_desc		= rt61pci_write_tx_desc,
+	.write_tx_data		= rt2x00pci_write_tx_data,
+	.kick_tx_queue		= rt61pci_kick_tx_queue,
+	.fill_rxdone		= rt61pci_fill_rxdone,
+	.config_mac_addr	= rt61pci_config_mac_addr,
+	.config_bssid		= rt61pci_config_bssid,
+	.config_type		= rt61pci_config_type,
+	.config_preamble	= rt61pci_config_preamble,
+	.config			= rt61pci_config,
+};
+
+static const struct rt2x00_ops rt61pci_ops = {
+	.name		= DRV_NAME,
+	.rxd_size	= RXD_DESC_SIZE,
+	.txd_size	= TXD_DESC_SIZE,
+	.eeprom_size	= EEPROM_SIZE,
+	.rf_size	= RF_SIZE,
+	.lib		= &rt61pci_rt2x00_ops,
+	.hw		= &rt61pci_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+	.debugfs	= &rt61pci_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * RT61pci module information.
+ */
+static struct pci_device_id rt61pci_device_table[] = {
+	/* RT2561s */
+	{ PCI_DEVICE(0x1814, 0x0301), PCI_DEVICE_DATA(&rt61pci_ops) },
+	/* RT2561 v2 */
+	{ PCI_DEVICE(0x1814, 0x0302), PCI_DEVICE_DATA(&rt61pci_ops) },
+	/* RT2661 */
+	{ PCI_DEVICE(0x1814, 0x0401), PCI_DEVICE_DATA(&rt61pci_ops) },
+	{ 0, }
+};
+
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT61 PCI & PCMCIA Wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Ralink RT2561, RT2561s & RT2661 "
+			"PCI & PCMCIA chipset based cards");
+MODULE_DEVICE_TABLE(pci, rt61pci_device_table);
+MODULE_FIRMWARE(FIRMWARE_RT2561);
+MODULE_FIRMWARE(FIRMWARE_RT2561s);
+MODULE_FIRMWARE(FIRMWARE_RT2661);
+MODULE_LICENSE("GPL");
+
+static struct pci_driver rt61pci_driver = {
+	.name		= DRV_NAME,
+	.id_table	= rt61pci_device_table,
+	.probe		= rt2x00pci_probe,
+	.remove		= __devexit_p(rt2x00pci_remove),
+	.suspend	= rt2x00pci_suspend,
+	.resume		= rt2x00pci_resume,
+};
+
+static int __init rt61pci_init(void)
+{
+	return pci_register_driver(&rt61pci_driver);
+}
+
+static void __exit rt61pci_exit(void)
+{
+	pci_unregister_driver(&rt61pci_driver);
+}
+
+module_init(rt61pci_init);
+module_exit(rt61pci_exit);
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
new file mode 100644
index 0000000..6721d7d
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -0,0 +1,1457 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt61pci
+	Abstract: Data structures and registers for the rt61pci module.
+	Supported chipsets: RT2561, RT2561s, RT2661.
+ */
+
+#ifndef RT61PCI_H
+#define RT61PCI_H
+
+/*
+ * RF chip defines.
+ */
+#define RF5225				0x0001
+#define RF5325				0x0002
+#define RF2527				0x0003
+#define RF2529				0x0004
+
+/*
+ * Signal information.
+ * Defaul offset is required for RSSI <-> dBm conversion.
+ */
+#define MAX_SIGNAL			100
+#define MAX_RX_SSI			-1
+#define DEFAULT_RSSI_OFFSET		120
+
+/*
+ * Register layout information.
+ */
+#define CSR_REG_BASE			0x3000
+#define CSR_REG_SIZE			0x04b0
+#define EEPROM_BASE			0x0000
+#define EEPROM_SIZE			0x0100
+#define BBP_SIZE			0x0080
+#define RF_SIZE				0x0014
+
+/*
+ * PCI registers.
+ */
+
+/*
+ * PCI Configuration Header
+ */
+#define PCI_CONFIG_HEADER_VENDOR	0x0000
+#define PCI_CONFIG_HEADER_DEVICE	0x0002
+
+/*
+ * HOST_CMD_CSR: For HOST to interrupt embedded processor
+ */
+#define HOST_CMD_CSR			0x0008
+#define HOST_CMD_CSR_HOST_COMMAND	FIELD32(0x0000007f)
+#define HOST_CMD_CSR_INTERRUPT_MCU	FIELD32(0x00000080)
+
+/*
+ * MCU_CNTL_CSR
+ * SELECT_BANK: Select 8051 program bank.
+ * RESET: Enable 8051 reset state.
+ * READY: Ready state for 8051.
+ */
+#define MCU_CNTL_CSR			0x000c
+#define MCU_CNTL_CSR_SELECT_BANK	FIELD32(0x00000001)
+#define MCU_CNTL_CSR_RESET		FIELD32(0x00000002)
+#define MCU_CNTL_CSR_READY		FIELD32(0x00000004)
+
+/*
+ * SOFT_RESET_CSR
+ */
+#define SOFT_RESET_CSR			0x0010
+
+/*
+ * MCU_INT_SOURCE_CSR: MCU interrupt source/mask register.
+ */
+#define MCU_INT_SOURCE_CSR		0x0014
+#define MCU_INT_SOURCE_CSR_0		FIELD32(0x00000001)
+#define MCU_INT_SOURCE_CSR_1		FIELD32(0x00000002)
+#define MCU_INT_SOURCE_CSR_2		FIELD32(0x00000004)
+#define MCU_INT_SOURCE_CSR_3		FIELD32(0x00000008)
+#define MCU_INT_SOURCE_CSR_4		FIELD32(0x00000010)
+#define MCU_INT_SOURCE_CSR_5		FIELD32(0x00000020)
+#define MCU_INT_SOURCE_CSR_6		FIELD32(0x00000040)
+#define MCU_INT_SOURCE_CSR_7		FIELD32(0x00000080)
+#define MCU_INT_SOURCE_CSR_TWAKEUP	FIELD32(0x00000100)
+#define MCU_INT_SOURCE_CSR_TBTT_EXPIRE	FIELD32(0x00000200)
+
+/*
+ * MCU_INT_MASK_CSR: MCU interrupt source/mask register.
+ */
+#define MCU_INT_MASK_CSR		0x0018
+#define MCU_INT_MASK_CSR_0		FIELD32(0x00000001)
+#define MCU_INT_MASK_CSR_1		FIELD32(0x00000002)
+#define MCU_INT_MASK_CSR_2		FIELD32(0x00000004)
+#define MCU_INT_MASK_CSR_3		FIELD32(0x00000008)
+#define MCU_INT_MASK_CSR_4		FIELD32(0x00000010)
+#define MCU_INT_MASK_CSR_5		FIELD32(0x00000020)
+#define MCU_INT_MASK_CSR_6		FIELD32(0x00000040)
+#define MCU_INT_MASK_CSR_7		FIELD32(0x00000080)
+#define MCU_INT_MASK_CSR_TWAKEUP	FIELD32(0x00000100)
+#define MCU_INT_MASK_CSR_TBTT_EXPIRE	FIELD32(0x00000200)
+
+/*
+ * PCI_USEC_CSR
+ */
+#define PCI_USEC_CSR			0x001c
+
+/*
+ * Security key table memory.
+ * 16 entries 32-byte for shared key table
+ * 64 entries 32-byte for pairwise key table
+ * 64 entries 8-byte for pairwise ta key table
+ */
+#define SHARED_KEY_TABLE_BASE		0x1000
+#define PAIRWISE_KEY_TABLE_BASE		0x1200
+#define PAIRWISE_TA_TABLE_BASE		0x1a00
+
+struct hw_key_entry {
+	u8 key[16];
+	u8 tx_mic[8];
+	u8 rx_mic[8];
+} __attribute__ ((packed));
+
+struct hw_pairwise_ta_entry {
+	u8 address[6];
+	u8 reserved[2];
+} __attribute__ ((packed));
+
+/*
+ * Other on-chip shared memory space.
+ */
+#define HW_CIS_BASE			0x2000
+#define HW_NULL_BASE			0x2b00
+
+/*
+ * Since NULL frame won't be that long (256 byte),
+ * We steal 16 tail bytes to save debugging settings.
+ */
+#define HW_DEBUG_SETTING_BASE		0x2bf0
+
+/*
+ * On-chip BEACON frame space.
+ */
+#define HW_BEACON_BASE0			0x2c00
+#define HW_BEACON_BASE1			0x2d00
+#define HW_BEACON_BASE2			0x2e00
+#define HW_BEACON_BASE3			0x2f00
+#define HW_BEACON_OFFSET		0x0100
+
+/*
+ * HOST-MCU shared memory.
+ */
+
+/*
+ * H2M_MAILBOX_CSR: Host-to-MCU Mailbox.
+ */
+#define H2M_MAILBOX_CSR			0x2100
+#define H2M_MAILBOX_CSR_ARG0		FIELD32(0x000000ff)
+#define H2M_MAILBOX_CSR_ARG1		FIELD32(0x0000ff00)
+#define H2M_MAILBOX_CSR_CMD_TOKEN	FIELD32(0x00ff0000)
+#define H2M_MAILBOX_CSR_OWNER		FIELD32(0xff000000)
+
+/*
+ * MCU_LEDCS: LED control for MCU Mailbox.
+ */
+#define MCU_LEDCS_LED_MODE		FIELD16(0x001f)
+#define MCU_LEDCS_RADIO_STATUS		FIELD16(0x0020)
+#define MCU_LEDCS_LINK_BG_STATUS	FIELD16(0x0040)
+#define MCU_LEDCS_LINK_A_STATUS		FIELD16(0x0080)
+#define MCU_LEDCS_POLARITY_GPIO_0	FIELD16(0x0100)
+#define MCU_LEDCS_POLARITY_GPIO_1	FIELD16(0x0200)
+#define MCU_LEDCS_POLARITY_GPIO_2	FIELD16(0x0400)
+#define MCU_LEDCS_POLARITY_GPIO_3	FIELD16(0x0800)
+#define MCU_LEDCS_POLARITY_GPIO_4	FIELD16(0x1000)
+#define MCU_LEDCS_POLARITY_ACT		FIELD16(0x2000)
+#define MCU_LEDCS_POLARITY_READY_BG	FIELD16(0x4000)
+#define MCU_LEDCS_POLARITY_READY_A	FIELD16(0x8000)
+
+/*
+ * M2H_CMD_DONE_CSR.
+ */
+#define M2H_CMD_DONE_CSR		0x2104
+
+/*
+ * MCU_TXOP_ARRAY_BASE.
+ */
+#define MCU_TXOP_ARRAY_BASE		0x2110
+
+/*
+ * MAC Control/Status Registers(CSR).
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * MAC_CSR0: ASIC revision number.
+ */
+#define MAC_CSR0			0x3000
+
+/*
+ * MAC_CSR1: System control register.
+ * SOFT_RESET: Software reset bit, 1: reset, 0: normal.
+ * BBP_RESET: Hardware reset BBP.
+ * HOST_READY: Host is ready after initialization, 1: ready.
+ */
+#define MAC_CSR1			0x3004
+#define MAC_CSR1_SOFT_RESET		FIELD32(0x00000001)
+#define MAC_CSR1_BBP_RESET		FIELD32(0x00000002)
+#define MAC_CSR1_HOST_READY		FIELD32(0x00000004)
+
+/*
+ * MAC_CSR2: STA MAC register 0.
+ */
+#define MAC_CSR2			0x3008
+#define MAC_CSR2_BYTE0			FIELD32(0x000000ff)
+#define MAC_CSR2_BYTE1			FIELD32(0x0000ff00)
+#define MAC_CSR2_BYTE2			FIELD32(0x00ff0000)
+#define MAC_CSR2_BYTE3			FIELD32(0xff000000)
+
+/*
+ * MAC_CSR3: STA MAC register 1.
+ */
+#define MAC_CSR3			0x300c
+#define MAC_CSR3_BYTE4			FIELD32(0x000000ff)
+#define MAC_CSR3_BYTE5			FIELD32(0x0000ff00)
+#define MAC_CSR3_UNICAST_TO_ME_MASK	FIELD32(0x00ff0000)
+
+/*
+ * MAC_CSR4: BSSID register 0.
+ */
+#define MAC_CSR4			0x3010
+#define MAC_CSR4_BYTE0			FIELD32(0x000000ff)
+#define MAC_CSR4_BYTE1			FIELD32(0x0000ff00)
+#define MAC_CSR4_BYTE2			FIELD32(0x00ff0000)
+#define MAC_CSR4_BYTE3			FIELD32(0xff000000)
+
+/*
+ * MAC_CSR5: BSSID register 1.
+ * BSS_ID_MASK: 3: one BSSID, 0: 4 BSSID, 2 or 1: 2 BSSID.
+ */
+#define MAC_CSR5			0x3014
+#define MAC_CSR5_BYTE4			FIELD32(0x000000ff)
+#define MAC_CSR5_BYTE5			FIELD32(0x0000ff00)
+#define MAC_CSR5_BSS_ID_MASK		FIELD32(0x00ff0000)
+
+/*
+ * MAC_CSR6: Maximum frame length register.
+ */
+#define MAC_CSR6			0x3018
+#define MAC_CSR6_MAX_FRAME_UNIT		FIELD32(0x00000fff)
+
+/*
+ * MAC_CSR7: Reserved
+ */
+#define MAC_CSR7			0x301c
+
+/*
+ * MAC_CSR8: SIFS/EIFS register.
+ * All units are in US.
+ */
+#define MAC_CSR8			0x3020
+#define MAC_CSR8_SIFS			FIELD32(0x000000ff)
+#define MAC_CSR8_SIFS_AFTER_RX_OFDM	FIELD32(0x0000ff00)
+#define MAC_CSR8_EIFS			FIELD32(0xffff0000)
+
+/*
+ * MAC_CSR9: Back-Off control register.
+ * SLOT_TIME: Slot time, default is 20us for 802.11BG.
+ * CWMIN: Bit for Cwmin. default Cwmin is 31 (2^5 - 1).
+ * CWMAX: Bit for Cwmax, default Cwmax is 1023 (2^10 - 1).
+ * CW_SELECT: 1: CWmin/Cwmax select from register, 0:select from TxD.
+ */
+#define MAC_CSR9			0x3024
+#define MAC_CSR9_SLOT_TIME		FIELD32(0x000000ff)
+#define MAC_CSR9_CWMIN			FIELD32(0x00000f00)
+#define MAC_CSR9_CWMAX			FIELD32(0x0000f000)
+#define MAC_CSR9_CW_SELECT		FIELD32(0x00010000)
+
+/*
+ * MAC_CSR10: Power state configuration.
+ */
+#define MAC_CSR10			0x3028
+
+/*
+ * MAC_CSR11: Power saving transition time register.
+ * DELAY_AFTER_TBCN: Delay after Tbcn expired in units of TU.
+ * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup.
+ * WAKEUP_LATENCY: In unit of TU.
+ */
+#define MAC_CSR11			0x302c
+#define MAC_CSR11_DELAY_AFTER_TBCN	FIELD32(0x000000ff)
+#define MAC_CSR11_TBCN_BEFORE_WAKEUP	FIELD32(0x00007f00)
+#define MAC_CSR11_AUTOWAKE		FIELD32(0x00008000)
+#define MAC_CSR11_WAKEUP_LATENCY	FIELD32(0x000f0000)
+
+/*
+ * MAC_CSR12: Manual power control / status register (merge CSR20 & PWRCSR1).
+ * CURRENT_STATE: 0:sleep, 1:awake.
+ * FORCE_WAKEUP: This has higher priority than PUT_TO_SLEEP.
+ * BBP_CURRENT_STATE: 0: BBP sleep, 1: BBP awake.
+ */
+#define MAC_CSR12			0x3030
+#define MAC_CSR12_CURRENT_STATE		FIELD32(0x00000001)
+#define MAC_CSR12_PUT_TO_SLEEP		FIELD32(0x00000002)
+#define MAC_CSR12_FORCE_WAKEUP		FIELD32(0x00000004)
+#define MAC_CSR12_BBP_CURRENT_STATE	FIELD32(0x00000008)
+
+/*
+ * MAC_CSR13: GPIO.
+ */
+#define MAC_CSR13			0x3034
+#define MAC_CSR13_BIT0			FIELD32(0x00000001)
+#define MAC_CSR13_BIT1			FIELD32(0x00000002)
+#define MAC_CSR13_BIT2			FIELD32(0x00000004)
+#define MAC_CSR13_BIT3			FIELD32(0x00000008)
+#define MAC_CSR13_BIT4			FIELD32(0x00000010)
+#define MAC_CSR13_BIT5			FIELD32(0x00000020)
+#define MAC_CSR13_BIT6			FIELD32(0x00000040)
+#define MAC_CSR13_BIT7			FIELD32(0x00000080)
+#define MAC_CSR13_BIT8			FIELD32(0x00000100)
+#define MAC_CSR13_BIT9			FIELD32(0x00000200)
+#define MAC_CSR13_BIT10			FIELD32(0x00000400)
+#define MAC_CSR13_BIT11			FIELD32(0x00000800)
+#define MAC_CSR13_BIT12			FIELD32(0x00001000)
+
+/*
+ * MAC_CSR14: LED control register.
+ * ON_PERIOD: On period, default 70ms.
+ * OFF_PERIOD: Off period, default 30ms.
+ * HW_LED: HW TX activity, 1: normal OFF, 0: normal ON.
+ * SW_LED: s/w LED, 1: ON, 0: OFF.
+ * HW_LED_POLARITY: 0: active low, 1: active high.
+ */
+#define MAC_CSR14			0x3038
+#define MAC_CSR14_ON_PERIOD		FIELD32(0x000000ff)
+#define MAC_CSR14_OFF_PERIOD		FIELD32(0x0000ff00)
+#define MAC_CSR14_HW_LED		FIELD32(0x00010000)
+#define MAC_CSR14_SW_LED		FIELD32(0x00020000)
+#define MAC_CSR14_HW_LED_POLARITY	FIELD32(0x00040000)
+#define MAC_CSR14_SW_LED2		FIELD32(0x00080000)
+
+/*
+ * MAC_CSR15: NAV control.
+ */
+#define MAC_CSR15			0x303c
+
+/*
+ * TXRX control registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * TXRX_CSR0: TX/RX configuration register.
+ * TSF_OFFSET: Default is 24.
+ * AUTO_TX_SEQ: 1: ASIC auto replace sequence nr in outgoing frame.
+ * DISABLE_RX: Disable Rx engine.
+ * DROP_CRC: Drop CRC error.
+ * DROP_PHYSICAL: Drop physical error.
+ * DROP_CONTROL: Drop control frame.
+ * DROP_NOT_TO_ME: Drop not to me unicast frame.
+ * DROP_TO_DS: Drop fram ToDs bit is true.
+ * DROP_VERSION_ERROR: Drop version error frame.
+ * DROP_MULTICAST: Drop multicast frames.
+ * DROP_BORADCAST: Drop broadcast frames.
+ * ROP_ACK_CTS: Drop received ACK and CTS.
+ */
+#define TXRX_CSR0			0x3040
+#define TXRX_CSR0_RX_ACK_TIMEOUT	FIELD32(0x000001ff)
+#define TXRX_CSR0_TSF_OFFSET		FIELD32(0x00007e00)
+#define TXRX_CSR0_AUTO_TX_SEQ		FIELD32(0x00008000)
+#define TXRX_CSR0_DISABLE_RX		FIELD32(0x00010000)
+#define TXRX_CSR0_DROP_CRC		FIELD32(0x00020000)
+#define TXRX_CSR0_DROP_PHYSICAL		FIELD32(0x00040000)
+#define TXRX_CSR0_DROP_CONTROL		FIELD32(0x00080000)
+#define TXRX_CSR0_DROP_NOT_TO_ME	FIELD32(0x00100000)
+#define TXRX_CSR0_DROP_TO_DS		FIELD32(0x00200000)
+#define TXRX_CSR0_DROP_VERSION_ERROR	FIELD32(0x00400000)
+#define TXRX_CSR0_DROP_MULTICAST	FIELD32(0x00800000)
+#define TXRX_CSR0_DROP_BORADCAST	FIELD32(0x01000000)
+#define TXRX_CSR0_DROP_ACK_CTS		FIELD32(0x02000000)
+#define TXRX_CSR0_TX_WITHOUT_WAITING	FIELD32(0x04000000)
+
+/*
+ * TXRX_CSR1
+ */
+#define TXRX_CSR1			0x3044
+#define TXRX_CSR1_BBP_ID0		FIELD32(0x0000007f)
+#define TXRX_CSR1_BBP_ID0_VALID		FIELD32(0x00000080)
+#define TXRX_CSR1_BBP_ID1		FIELD32(0x00007f00)
+#define TXRX_CSR1_BBP_ID1_VALID		FIELD32(0x00008000)
+#define TXRX_CSR1_BBP_ID2		FIELD32(0x007f0000)
+#define TXRX_CSR1_BBP_ID2_VALID		FIELD32(0x00800000)
+#define TXRX_CSR1_BBP_ID3		FIELD32(0x7f000000)
+#define TXRX_CSR1_BBP_ID3_VALID		FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR2
+ */
+#define TXRX_CSR2			0x3048
+#define TXRX_CSR2_BBP_ID0		FIELD32(0x0000007f)
+#define TXRX_CSR2_BBP_ID0_VALID		FIELD32(0x00000080)
+#define TXRX_CSR2_BBP_ID1		FIELD32(0x00007f00)
+#define TXRX_CSR2_BBP_ID1_VALID		FIELD32(0x00008000)
+#define TXRX_CSR2_BBP_ID2		FIELD32(0x007f0000)
+#define TXRX_CSR2_BBP_ID2_VALID		FIELD32(0x00800000)
+#define TXRX_CSR2_BBP_ID3		FIELD32(0x7f000000)
+#define TXRX_CSR2_BBP_ID3_VALID		FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR3
+ */
+#define TXRX_CSR3			0x304c
+#define TXRX_CSR3_BBP_ID0		FIELD32(0x0000007f)
+#define TXRX_CSR3_BBP_ID0_VALID		FIELD32(0x00000080)
+#define TXRX_CSR3_BBP_ID1		FIELD32(0x00007f00)
+#define TXRX_CSR3_BBP_ID1_VALID		FIELD32(0x00008000)
+#define TXRX_CSR3_BBP_ID2		FIELD32(0x007f0000)
+#define TXRX_CSR3_BBP_ID2_VALID		FIELD32(0x00800000)
+#define TXRX_CSR3_BBP_ID3		FIELD32(0x7f000000)
+#define TXRX_CSR3_BBP_ID3_VALID		FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR4: Auto-Responder/Tx-retry register.
+ * AUTORESPOND_PREAMBLE: 0:long, 1:short preamble.
+ * OFDM_TX_RATE_DOWN: 1:enable.
+ * OFDM_TX_RATE_STEP: 0:1-step, 1: 2-step, 2:3-step, 3:4-step.
+ * OFDM_TX_FALLBACK_CCK: 0: Fallback to OFDM 6M only, 1: Fallback to CCK 1M,2M.
+ */
+#define TXRX_CSR4			0x3050
+#define TXRX_CSR4_TX_ACK_TIMEOUT	FIELD32(0x000000ff)
+#define TXRX_CSR4_CNTL_ACK_POLICY	FIELD32(0x00000700)
+#define TXRX_CSR4_ACK_CTS_PSM		FIELD32(0x00010000)
+#define TXRX_CSR4_AUTORESPOND_ENABLE	FIELD32(0x00020000)
+#define TXRX_CSR4_AUTORESPOND_PREAMBLE	FIELD32(0x00040000)
+#define TXRX_CSR4_OFDM_TX_RATE_DOWN	FIELD32(0x00080000)
+#define TXRX_CSR4_OFDM_TX_RATE_STEP	FIELD32(0x00300000)
+#define TXRX_CSR4_OFDM_TX_FALLBACK_CCK	FIELD32(0x00400000)
+#define TXRX_CSR4_LONG_RETRY_LIMIT	FIELD32(0x0f000000)
+#define TXRX_CSR4_SHORT_RETRY_LIMIT	FIELD32(0xf0000000)
+
+/*
+ * TXRX_CSR5
+ */
+#define TXRX_CSR5			0x3054
+
+/*
+ * TXRX_CSR6: ACK/CTS payload consumed time
+ */
+#define TXRX_CSR6			0x3058
+
+/*
+ * TXRX_CSR7: OFDM ACK/CTS payload consumed time for 6/9/12/18 mbps.
+ */
+#define TXRX_CSR7			0x305c
+#define TXRX_CSR7_ACK_CTS_6MBS		FIELD32(0x000000ff)
+#define TXRX_CSR7_ACK_CTS_9MBS		FIELD32(0x0000ff00)
+#define TXRX_CSR7_ACK_CTS_12MBS		FIELD32(0x00ff0000)
+#define TXRX_CSR7_ACK_CTS_18MBS		FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR8: OFDM ACK/CTS payload consumed time for 24/36/48/54 mbps.
+ */
+#define TXRX_CSR8			0x3060
+#define TXRX_CSR8_ACK_CTS_24MBS		FIELD32(0x000000ff)
+#define TXRX_CSR8_ACK_CTS_36MBS		FIELD32(0x0000ff00)
+#define TXRX_CSR8_ACK_CTS_48MBS		FIELD32(0x00ff0000)
+#define TXRX_CSR8_ACK_CTS_54MBS		FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR9: Synchronization control register.
+ * BEACON_INTERVAL: In unit of 1/16 TU.
+ * TSF_TICKING: Enable TSF auto counting.
+ * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
+ * BEACON_GEN: Enable beacon generator.
+ */
+#define TXRX_CSR9			0x3064
+#define TXRX_CSR9_BEACON_INTERVAL	FIELD32(0x0000ffff)
+#define TXRX_CSR9_TSF_TICKING		FIELD32(0x00010000)
+#define TXRX_CSR9_TSF_SYNC		FIELD32(0x00060000)
+#define TXRX_CSR9_TBTT_ENABLE		FIELD32(0x00080000)
+#define TXRX_CSR9_BEACON_GEN		FIELD32(0x00100000)
+#define TXRX_CSR9_TIMESTAMP_COMPENSATE	FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR10: BEACON alignment.
+ */
+#define TXRX_CSR10			0x3068
+
+/*
+ * TXRX_CSR11: AES mask.
+ */
+#define TXRX_CSR11			0x306c
+
+/*
+ * TXRX_CSR12: TSF low 32.
+ */
+#define TXRX_CSR12			0x3070
+#define TXRX_CSR12_LOW_TSFTIMER		FIELD32(0xffffffff)
+
+/*
+ * TXRX_CSR13: TSF high 32.
+ */
+#define TXRX_CSR13			0x3074
+#define TXRX_CSR13_HIGH_TSFTIMER	FIELD32(0xffffffff)
+
+/*
+ * TXRX_CSR14: TBTT timer.
+ */
+#define TXRX_CSR14			0x3078
+
+/*
+ * TXRX_CSR15: TKIP MIC priority byte "AND" mask.
+ */
+#define TXRX_CSR15			0x307c
+
+/*
+ * PHY control registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * PHY_CSR0: RF/PS control.
+ */
+#define PHY_CSR0			0x3080
+#define PHY_CSR0_PA_PE_BG		FIELD32(0x00010000)
+#define PHY_CSR0_PA_PE_A		FIELD32(0x00020000)
+
+/*
+ * PHY_CSR1
+ */
+#define PHY_CSR1			0x3084
+
+/*
+ * PHY_CSR2: Pre-TX BBP control.
+ */
+#define PHY_CSR2			0x3088
+
+/*
+ * PHY_CSR3: BBP serial control register.
+ * VALUE: Register value to program into BBP.
+ * REG_NUM: Selected BBP register.
+ * READ_CONTROL: 0: Write BBP, 1: Read BBP.
+ * BUSY: 1: ASIC is busy execute BBP programming.
+ */
+#define PHY_CSR3			0x308c
+#define PHY_CSR3_VALUE			FIELD32(0x000000ff)
+#define PHY_CSR3_REGNUM			FIELD32(0x00007f00)
+#define PHY_CSR3_READ_CONTROL		FIELD32(0x00008000)
+#define PHY_CSR3_BUSY			FIELD32(0x00010000)
+
+/*
+ * PHY_CSR4: RF serial control register
+ * VALUE: Register value (include register id) serial out to RF/IF chip.
+ * NUMBER_OF_BITS: Number of bits used in RFRegValue (I:20, RFMD:22).
+ * IF_SELECT: 1: select IF to program, 0: select RF to program.
+ * PLL_LD: RF PLL_LD status.
+ * BUSY: 1: ASIC is busy execute RF programming.
+ */
+#define PHY_CSR4			0x3090
+#define PHY_CSR4_VALUE			FIELD32(0x00ffffff)
+#define PHY_CSR4_NUMBER_OF_BITS		FIELD32(0x1f000000)
+#define PHY_CSR4_IF_SELECT		FIELD32(0x20000000)
+#define PHY_CSR4_PLL_LD			FIELD32(0x40000000)
+#define PHY_CSR4_BUSY			FIELD32(0x80000000)
+
+/*
+ * PHY_CSR5: RX to TX signal switch timing control.
+ */
+#define PHY_CSR5			0x3094
+#define PHY_CSR5_IQ_FLIP		FIELD32(0x00000004)
+
+/*
+ * PHY_CSR6: TX to RX signal timing control.
+ */
+#define PHY_CSR6			0x3098
+#define PHY_CSR6_IQ_FLIP		FIELD32(0x00000004)
+
+/*
+ * PHY_CSR7: TX DAC switching timing control.
+ */
+#define PHY_CSR7			0x309c
+
+/*
+ * Security control register.
+ */
+
+/*
+ * SEC_CSR0: Shared key table control.
+ */
+#define SEC_CSR0			0x30a0
+#define SEC_CSR0_BSS0_KEY0_VALID	FIELD32(0x00000001)
+#define SEC_CSR0_BSS0_KEY1_VALID	FIELD32(0x00000002)
+#define SEC_CSR0_BSS0_KEY2_VALID	FIELD32(0x00000004)
+#define SEC_CSR0_BSS0_KEY3_VALID	FIELD32(0x00000008)
+#define SEC_CSR0_BSS1_KEY0_VALID	FIELD32(0x00000010)
+#define SEC_CSR0_BSS1_KEY1_VALID	FIELD32(0x00000020)
+#define SEC_CSR0_BSS1_KEY2_VALID	FIELD32(0x00000040)
+#define SEC_CSR0_BSS1_KEY3_VALID	FIELD32(0x00000080)
+#define SEC_CSR0_BSS2_KEY0_VALID	FIELD32(0x00000100)
+#define SEC_CSR0_BSS2_KEY1_VALID	FIELD32(0x00000200)
+#define SEC_CSR0_BSS2_KEY2_VALID	FIELD32(0x00000400)
+#define SEC_CSR0_BSS2_KEY3_VALID	FIELD32(0x00000800)
+#define SEC_CSR0_BSS3_KEY0_VALID	FIELD32(0x00001000)
+#define SEC_CSR0_BSS3_KEY1_VALID	FIELD32(0x00002000)
+#define SEC_CSR0_BSS3_KEY2_VALID	FIELD32(0x00004000)
+#define SEC_CSR0_BSS3_KEY3_VALID	FIELD32(0x00008000)
+
+/*
+ * SEC_CSR1: Shared key table security mode register.
+ */
+#define SEC_CSR1			0x30a4
+#define SEC_CSR1_BSS0_KEY0_CIPHER_ALG	FIELD32(0x00000007)
+#define SEC_CSR1_BSS0_KEY1_CIPHER_ALG	FIELD32(0x00000070)
+#define SEC_CSR1_BSS0_KEY2_CIPHER_ALG	FIELD32(0x00000700)
+#define SEC_CSR1_BSS0_KEY3_CIPHER_ALG	FIELD32(0x00007000)
+#define SEC_CSR1_BSS1_KEY0_CIPHER_ALG	FIELD32(0x00070000)
+#define SEC_CSR1_BSS1_KEY1_CIPHER_ALG	FIELD32(0x00700000)
+#define SEC_CSR1_BSS1_KEY2_CIPHER_ALG	FIELD32(0x07000000)
+#define SEC_CSR1_BSS1_KEY3_CIPHER_ALG	FIELD32(0x70000000)
+
+/*
+ * Pairwise key table valid bitmap registers.
+ * SEC_CSR2: pairwise key table valid bitmap 0.
+ * SEC_CSR3: pairwise key table valid bitmap 1.
+ */
+#define SEC_CSR2			0x30a8
+#define SEC_CSR3			0x30ac
+
+/*
+ * SEC_CSR4: Pairwise key table lookup control.
+ */
+#define SEC_CSR4			0x30b0
+
+/*
+ * SEC_CSR5: shared key table security mode register.
+ */
+#define SEC_CSR5			0x30b4
+#define SEC_CSR5_BSS2_KEY0_CIPHER_ALG	FIELD32(0x00000007)
+#define SEC_CSR5_BSS2_KEY1_CIPHER_ALG	FIELD32(0x00000070)
+#define SEC_CSR5_BSS2_KEY2_CIPHER_ALG	FIELD32(0x00000700)
+#define SEC_CSR5_BSS2_KEY3_CIPHER_ALG	FIELD32(0x00007000)
+#define SEC_CSR5_BSS3_KEY0_CIPHER_ALG	FIELD32(0x00070000)
+#define SEC_CSR5_BSS3_KEY1_CIPHER_ALG	FIELD32(0x00700000)
+#define SEC_CSR5_BSS3_KEY2_CIPHER_ALG	FIELD32(0x07000000)
+#define SEC_CSR5_BSS3_KEY3_CIPHER_ALG	FIELD32(0x70000000)
+
+/*
+ * STA control registers.
+ */
+
+/*
+ * STA_CSR0: RX PLCP error count & RX FCS error count.
+ */
+#define STA_CSR0			0x30c0
+#define STA_CSR0_FCS_ERROR		FIELD32(0x0000ffff)
+#define STA_CSR0_PLCP_ERROR		FIELD32(0xffff0000)
+
+/*
+ * STA_CSR1: RX False CCA count & RX LONG frame count.
+ */
+#define STA_CSR1			0x30c4
+#define STA_CSR1_PHYSICAL_ERROR		FIELD32(0x0000ffff)
+#define STA_CSR1_FALSE_CCA_ERROR	FIELD32(0xffff0000)
+
+/*
+ * STA_CSR2: TX Beacon count and RX FIFO overflow count.
+ */
+#define STA_CSR2			0x30c8
+#define STA_CSR2_RX_FIFO_OVERFLOW_COUNT	FIELD32(0x0000ffff)
+#define STA_CSR2_RX_OVERFLOW_COUNT	FIELD32(0xffff0000)
+
+/*
+ * STA_CSR3: TX Beacon count.
+ */
+#define STA_CSR3			0x30cc
+#define STA_CSR3_TX_BEACON_COUNT	FIELD32(0x0000ffff)
+
+/*
+ * STA_CSR4: TX Result status register.
+ * VALID: 1:This register contains a valid TX result.
+ */
+#define STA_CSR4			0x30d0
+#define STA_CSR4_VALID			FIELD32(0x00000001)
+#define STA_CSR4_TX_RESULT		FIELD32(0x0000000e)
+#define STA_CSR4_RETRY_COUNT		FIELD32(0x000000f0)
+#define STA_CSR4_PID_SUBTYPE		FIELD32(0x00001f00)
+#define STA_CSR4_PID_TYPE		FIELD32(0x0000e000)
+#define STA_CSR4_TXRATE			FIELD32(0x000f0000)
+
+/*
+ * QOS control registers.
+ */
+
+/*
+ * QOS_CSR0: TXOP holder MAC address register.
+ */
+#define QOS_CSR0			0x30e0
+#define QOS_CSR0_BYTE0			FIELD32(0x000000ff)
+#define QOS_CSR0_BYTE1			FIELD32(0x0000ff00)
+#define QOS_CSR0_BYTE2			FIELD32(0x00ff0000)
+#define QOS_CSR0_BYTE3			FIELD32(0xff000000)
+
+/*
+ * QOS_CSR1: TXOP holder MAC address register.
+ */
+#define QOS_CSR1			0x30e4
+#define QOS_CSR1_BYTE4			FIELD32(0x000000ff)
+#define QOS_CSR1_BYTE5			FIELD32(0x0000ff00)
+
+/*
+ * QOS_CSR2: TXOP holder timeout register.
+ */
+#define QOS_CSR2			0x30e8
+
+/*
+ * RX QOS-CFPOLL MAC address register.
+ * QOS_CSR3: RX QOS-CFPOLL MAC address 0.
+ * QOS_CSR4: RX QOS-CFPOLL MAC address 1.
+ */
+#define QOS_CSR3			0x30ec
+#define QOS_CSR4			0x30f0
+
+/*
+ * QOS_CSR5: "QosControl" field of the RX QOS-CFPOLL.
+ */
+#define QOS_CSR5			0x30f4
+
+/*
+ * Host DMA registers.
+ */
+
+/*
+ * AC0_BASE_CSR: AC_BK base address.
+ */
+#define AC0_BASE_CSR			0x3400
+#define AC0_BASE_CSR_RING_REGISTER	FIELD32(0xffffffff)
+
+/*
+ * AC1_BASE_CSR: AC_BE base address.
+ */
+#define AC1_BASE_CSR			0x3404
+#define AC1_BASE_CSR_RING_REGISTER	FIELD32(0xffffffff)
+
+/*
+ * AC2_BASE_CSR: AC_VI base address.
+ */
+#define AC2_BASE_CSR			0x3408
+#define AC2_BASE_CSR_RING_REGISTER	FIELD32(0xffffffff)
+
+/*
+ * AC3_BASE_CSR: AC_VO base address.
+ */
+#define AC3_BASE_CSR			0x340c
+#define AC3_BASE_CSR_RING_REGISTER	FIELD32(0xffffffff)
+
+/*
+ * MGMT_BASE_CSR: MGMT ring base address.
+ */
+#define MGMT_BASE_CSR			0x3410
+#define MGMT_BASE_CSR_RING_REGISTER	FIELD32(0xffffffff)
+
+/*
+ * TX_RING_CSR0: TX Ring size for AC_BK, AC_BE, AC_VI, AC_VO.
+ */
+#define TX_RING_CSR0			0x3418
+#define TX_RING_CSR0_AC0_RING_SIZE	FIELD32(0x000000ff)
+#define TX_RING_CSR0_AC1_RING_SIZE	FIELD32(0x0000ff00)
+#define TX_RING_CSR0_AC2_RING_SIZE	FIELD32(0x00ff0000)
+#define TX_RING_CSR0_AC3_RING_SIZE	FIELD32(0xff000000)
+
+/*
+ * TX_RING_CSR1: TX Ring size for MGMT Ring, HCCA Ring
+ * TXD_SIZE: In unit of 32-bit.
+ */
+#define TX_RING_CSR1			0x341c
+#define TX_RING_CSR1_MGMT_RING_SIZE	FIELD32(0x000000ff)
+#define TX_RING_CSR1_HCCA_RING_SIZE	FIELD32(0x0000ff00)
+#define TX_RING_CSR1_TXD_SIZE		FIELD32(0x003f0000)
+
+/*
+ * AIFSN_CSR: AIFSN for each EDCA AC.
+ * AIFSN0: For AC_BK.
+ * AIFSN1: For AC_BE.
+ * AIFSN2: For AC_VI.
+ * AIFSN3: For AC_VO.
+ */
+#define AIFSN_CSR			0x3420
+#define AIFSN_CSR_AIFSN0		FIELD32(0x0000000f)
+#define AIFSN_CSR_AIFSN1		FIELD32(0x000000f0)
+#define AIFSN_CSR_AIFSN2		FIELD32(0x00000f00)
+#define AIFSN_CSR_AIFSN3		FIELD32(0x0000f000)
+
+/*
+ * CWMIN_CSR: CWmin for each EDCA AC.
+ * CWMIN0: For AC_BK.
+ * CWMIN1: For AC_BE.
+ * CWMIN2: For AC_VI.
+ * CWMIN3: For AC_VO.
+ */
+#define CWMIN_CSR			0x3424
+#define CWMIN_CSR_CWMIN0		FIELD32(0x0000000f)
+#define CWMIN_CSR_CWMIN1		FIELD32(0x000000f0)
+#define CWMIN_CSR_CWMIN2		FIELD32(0x00000f00)
+#define CWMIN_CSR_CWMIN3		FIELD32(0x0000f000)
+
+/*
+ * CWMAX_CSR: CWmax for each EDCA AC.
+ * CWMAX0: For AC_BK.
+ * CWMAX1: For AC_BE.
+ * CWMAX2: For AC_VI.
+ * CWMAX3: For AC_VO.
+ */
+#define CWMAX_CSR			0x3428
+#define CWMAX_CSR_CWMAX0		FIELD32(0x0000000f)
+#define CWMAX_CSR_CWMAX1		FIELD32(0x000000f0)
+#define CWMAX_CSR_CWMAX2		FIELD32(0x00000f00)
+#define CWMAX_CSR_CWMAX3		FIELD32(0x0000f000)
+
+/*
+ * TX_DMA_DST_CSR: TX DMA destination
+ * 0: TX ring0, 1: TX ring1, 2: TX ring2 3: invalid
+ */
+#define TX_DMA_DST_CSR			0x342c
+#define TX_DMA_DST_CSR_DEST_AC0		FIELD32(0x00000003)
+#define TX_DMA_DST_CSR_DEST_AC1		FIELD32(0x0000000c)
+#define TX_DMA_DST_CSR_DEST_AC2		FIELD32(0x00000030)
+#define TX_DMA_DST_CSR_DEST_AC3		FIELD32(0x000000c0)
+#define TX_DMA_DST_CSR_DEST_MGMT	FIELD32(0x00000300)
+
+/*
+ * TX_CNTL_CSR: KICK/Abort TX.
+ * KICK_TX_AC0: For AC_BK.
+ * KICK_TX_AC1: For AC_BE.
+ * KICK_TX_AC2: For AC_VI.
+ * KICK_TX_AC3: For AC_VO.
+ * ABORT_TX_AC0: For AC_BK.
+ * ABORT_TX_AC1: For AC_BE.
+ * ABORT_TX_AC2: For AC_VI.
+ * ABORT_TX_AC3: For AC_VO.
+ */
+#define TX_CNTL_CSR			0x3430
+#define TX_CNTL_CSR_KICK_TX_AC0		FIELD32(0x00000001)
+#define TX_CNTL_CSR_KICK_TX_AC1		FIELD32(0x00000002)
+#define TX_CNTL_CSR_KICK_TX_AC2		FIELD32(0x00000004)
+#define TX_CNTL_CSR_KICK_TX_AC3		FIELD32(0x00000008)
+#define TX_CNTL_CSR_KICK_TX_MGMT	FIELD32(0x00000010)
+#define TX_CNTL_CSR_ABORT_TX_AC0	FIELD32(0x00010000)
+#define TX_CNTL_CSR_ABORT_TX_AC1	FIELD32(0x00020000)
+#define TX_CNTL_CSR_ABORT_TX_AC2	FIELD32(0x00040000)
+#define TX_CNTL_CSR_ABORT_TX_AC3	FIELD32(0x00080000)
+#define TX_CNTL_CSR_ABORT_TX_MGMT	FIELD32(0x00100000)
+
+/*
+ * LOAD_TX_RING_CSR: Load RX de
+ */
+#define LOAD_TX_RING_CSR		0x3434
+#define LOAD_TX_RING_CSR_LOAD_TXD_AC0	FIELD32(0x00000001)
+#define LOAD_TX_RING_CSR_LOAD_TXD_AC1	FIELD32(0x00000002)
+#define LOAD_TX_RING_CSR_LOAD_TXD_AC2	FIELD32(0x00000004)
+#define LOAD_TX_RING_CSR_LOAD_TXD_AC3	FIELD32(0x00000008)
+#define LOAD_TX_RING_CSR_LOAD_TXD_MGMT	FIELD32(0x00000010)
+
+/*
+ * Several read-only registers, for debugging.
+ */
+#define AC0_TXPTR_CSR			0x3438
+#define AC1_TXPTR_CSR			0x343c
+#define AC2_TXPTR_CSR			0x3440
+#define AC3_TXPTR_CSR			0x3444
+#define MGMT_TXPTR_CSR			0x3448
+
+/*
+ * RX_BASE_CSR
+ */
+#define RX_BASE_CSR			0x3450
+#define RX_BASE_CSR_RING_REGISTER	FIELD32(0xffffffff)
+
+/*
+ * RX_RING_CSR.
+ * RXD_SIZE: In unit of 32-bit.
+ */
+#define RX_RING_CSR			0x3454
+#define RX_RING_CSR_RING_SIZE		FIELD32(0x000000ff)
+#define RX_RING_CSR_RXD_SIZE		FIELD32(0x00003f00)
+#define RX_RING_CSR_RXD_WRITEBACK_SIZE	FIELD32(0x00070000)
+
+/*
+ * RX_CNTL_CSR
+ */
+#define RX_CNTL_CSR			0x3458
+#define RX_CNTL_CSR_ENABLE_RX_DMA	FIELD32(0x00000001)
+#define RX_CNTL_CSR_LOAD_RXD		FIELD32(0x00000002)
+
+/*
+ * RXPTR_CSR: Read-only, for debugging.
+ */
+#define RXPTR_CSR			0x345c
+
+/*
+ * PCI_CFG_CSR
+ */
+#define PCI_CFG_CSR			0x3460
+
+/*
+ * BUF_FORMAT_CSR
+ */
+#define BUF_FORMAT_CSR			0x3464
+
+/*
+ * INT_SOURCE_CSR: Interrupt source register.
+ * Write one to clear corresponding bit.
+ */
+#define INT_SOURCE_CSR			0x3468
+#define INT_SOURCE_CSR_TXDONE		FIELD32(0x00000001)
+#define INT_SOURCE_CSR_RXDONE		FIELD32(0x00000002)
+#define INT_SOURCE_CSR_BEACON_DONE	FIELD32(0x00000004)
+#define INT_SOURCE_CSR_TX_ABORT_DONE	FIELD32(0x00000010)
+#define INT_SOURCE_CSR_AC0_DMA_DONE	FIELD32(0x00010000)
+#define INT_SOURCE_CSR_AC1_DMA_DONE	FIELD32(0x00020000)
+#define INT_SOURCE_CSR_AC2_DMA_DONE	FIELD32(0x00040000)
+#define INT_SOURCE_CSR_AC3_DMA_DONE	FIELD32(0x00080000)
+#define INT_SOURCE_CSR_MGMT_DMA_DONE	FIELD32(0x00100000)
+#define INT_SOURCE_CSR_HCCA_DMA_DONE	FIELD32(0x00200000)
+
+/*
+ * INT_MASK_CSR: Interrupt MASK register. 1: the interrupt is mask OFF.
+ * MITIGATION_PERIOD: Interrupt mitigation in unit of 32 PCI clock.
+ */
+#define INT_MASK_CSR			0x346c
+#define INT_MASK_CSR_TXDONE		FIELD32(0x00000001)
+#define INT_MASK_CSR_RXDONE		FIELD32(0x00000002)
+#define INT_MASK_CSR_BEACON_DONE	FIELD32(0x00000004)
+#define INT_MASK_CSR_TX_ABORT_DONE	FIELD32(0x00000010)
+#define INT_MASK_CSR_ENABLE_MITIGATION	FIELD32(0x00000080)
+#define INT_MASK_CSR_MITIGATION_PERIOD	FIELD32(0x0000ff00)
+#define INT_MASK_CSR_AC0_DMA_DONE	FIELD32(0x00010000)
+#define INT_MASK_CSR_AC1_DMA_DONE	FIELD32(0x00020000)
+#define INT_MASK_CSR_AC2_DMA_DONE	FIELD32(0x00040000)
+#define INT_MASK_CSR_AC3_DMA_DONE	FIELD32(0x00080000)
+#define INT_MASK_CSR_MGMT_DMA_DONE	FIELD32(0x00100000)
+#define INT_MASK_CSR_HCCA_DMA_DONE	FIELD32(0x00200000)
+
+/*
+ * E2PROM_CSR: EEPROM control register.
+ * RELOAD: Write 1 to reload eeprom content.
+ * TYPE_93C46: 1: 93c46, 0:93c66.
+ * LOAD_STATUS: 1:loading, 0:done.
+ */
+#define E2PROM_CSR			0x3470
+#define E2PROM_CSR_RELOAD		FIELD32(0x00000001)
+#define E2PROM_CSR_DATA_CLOCK		FIELD32(0x00000002)
+#define E2PROM_CSR_CHIP_SELECT		FIELD32(0x00000004)
+#define E2PROM_CSR_DATA_IN		FIELD32(0x00000008)
+#define E2PROM_CSR_DATA_OUT		FIELD32(0x00000010)
+#define E2PROM_CSR_TYPE_93C46		FIELD32(0x00000020)
+#define E2PROM_CSR_LOAD_STATUS		FIELD32(0x00000040)
+
+/*
+ * AC_TXOP_CSR0: AC_BK/AC_BE TXOP register.
+ * AC0_TX_OP: For AC_BK, in unit of 32us.
+ * AC1_TX_OP: For AC_BE, in unit of 32us.
+ */
+#define AC_TXOP_CSR0			0x3474
+#define AC_TXOP_CSR0_AC0_TX_OP		FIELD32(0x0000ffff)
+#define AC_TXOP_CSR0_AC1_TX_OP		FIELD32(0xffff0000)
+
+/*
+ * AC_TXOP_CSR1: AC_VO/AC_VI TXOP register.
+ * AC2_TX_OP: For AC_VI, in unit of 32us.
+ * AC3_TX_OP: For AC_VO, in unit of 32us.
+ */
+#define AC_TXOP_CSR1			0x3478
+#define AC_TXOP_CSR1_AC2_TX_OP		FIELD32(0x0000ffff)
+#define AC_TXOP_CSR1_AC3_TX_OP		FIELD32(0xffff0000)
+
+/*
+ * DMA_STATUS_CSR
+ */
+#define DMA_STATUS_CSR			0x3480
+
+/*
+ * TEST_MODE_CSR
+ */
+#define TEST_MODE_CSR			0x3484
+
+/*
+ * UART0_TX_CSR
+ */
+#define UART0_TX_CSR			0x3488
+
+/*
+ * UART0_RX_CSR
+ */
+#define UART0_RX_CSR			0x348c
+
+/*
+ * UART0_FRAME_CSR
+ */
+#define UART0_FRAME_CSR			0x3490
+
+/*
+ * UART0_BUFFER_CSR
+ */
+#define UART0_BUFFER_CSR		0x3494
+
+/*
+ * IO_CNTL_CSR
+ */
+#define IO_CNTL_CSR			0x3498
+
+/*
+ * UART_INT_SOURCE_CSR
+ */
+#define UART_INT_SOURCE_CSR		0x34a8
+
+/*
+ * UART_INT_MASK_CSR
+ */
+#define UART_INT_MASK_CSR		0x34ac
+
+/*
+ * PBF_QUEUE_CSR
+ */
+#define PBF_QUEUE_CSR			0x34b0
+
+/*
+ * Firmware DMA registers.
+ * Firmware DMA registers are dedicated for MCU usage
+ * and should not be touched by host driver.
+ * Therefore we skip the definition of these registers.
+ */
+#define FW_TX_BASE_CSR			0x34c0
+#define FW_TX_START_CSR			0x34c4
+#define FW_TX_LAST_CSR			0x34c8
+#define FW_MODE_CNTL_CSR		0x34cc
+#define FW_TXPTR_CSR			0x34d0
+
+/*
+ * 8051 firmware image.
+ */
+#define FIRMWARE_RT2561			"rt2561.bin"
+#define FIRMWARE_RT2561s		"rt2561s.bin"
+#define FIRMWARE_RT2661			"rt2661.bin"
+#define FIRMWARE_IMAGE_BASE		0x4000
+
+/*
+ * BBP registers.
+ * The wordsize of the BBP is 8 bits.
+ */
+
+/*
+ * R2
+ */
+#define BBP_R2_BG_MODE			FIELD8(0x20)
+
+/*
+ * R3
+ */
+#define BBP_R3_SMART_MODE		FIELD8(0x01)
+
+/*
+ * R4: RX antenna control
+ * FRAME_END: 1 - DPDT, 0 - SPDT (Only valid for 802.11G, RF2527 & RF2529)
+ */
+#define BBP_R4_RX_ANTENNA		FIELD8(0x03)
+#define BBP_R4_RX_FRAME_END		FIELD8(0x20)
+
+/*
+ * R77
+ */
+#define BBP_R77_PAIR			FIELD8(0x03)
+
+/*
+ * RF registers
+ */
+
+/*
+ * RF 3
+ */
+#define RF3_TXPOWER			FIELD32(0x00003e00)
+
+/*
+ * RF 4
+ */
+#define RF4_FREQ_OFFSET			FIELD32(0x0003f000)
+
+/*
+ * EEPROM content.
+ * The wordsize of the EEPROM is 16 bits.
+ */
+
+/*
+ * HW MAC address.
+ */
+#define EEPROM_MAC_ADDR_0		0x0002
+#define EEPROM_MAC_ADDR_BYTE0		FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE1		FIELD16(0xff00)
+#define EEPROM_MAC_ADDR1		0x0004
+#define EEPROM_MAC_ADDR_BYTE2		FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE3		FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_2		0x0006
+#define EEPROM_MAC_ADDR_BYTE4		FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE5		FIELD16(0xff00)
+
+/*
+ * EEPROM antenna.
+ * ANTENNA_NUM: Number of antenna's.
+ * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * FRAME_TYPE: 0: DPDT , 1: SPDT , noted this bit is valid for g only.
+ * DYN_TXAGC: Dynamic TX AGC control.
+ * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
+ * RF_TYPE: Rf_type of this adapter.
+ */
+#define EEPROM_ANTENNA			0x0010
+#define EEPROM_ANTENNA_NUM		FIELD16(0x0003)
+#define EEPROM_ANTENNA_TX_DEFAULT	FIELD16(0x000c)
+#define EEPROM_ANTENNA_RX_DEFAULT	FIELD16(0x0030)
+#define EEPROM_ANTENNA_FRAME_TYPE	FIELD16(0x0040)
+#define EEPROM_ANTENNA_DYN_TXAGC	FIELD16(0x0200)
+#define EEPROM_ANTENNA_HARDWARE_RADIO	FIELD16(0x0400)
+#define EEPROM_ANTENNA_RF_TYPE		FIELD16(0xf800)
+
+/*
+ * EEPROM NIC config.
+ * ENABLE_DIVERSITY: 1:enable, 0:disable.
+ * EXTERNAL_LNA_BG: External LNA enable for 2.4G.
+ * CARDBUS_ACCEL: 0:enable, 1:disable.
+ * EXTERNAL_LNA_A: External LNA enable for 5G.
+ */
+#define EEPROM_NIC			0x0011
+#define EEPROM_NIC_ENABLE_DIVERSITY	FIELD16(0x0001)
+#define EEPROM_NIC_TX_DIVERSITY		FIELD16(0x0002)
+#define EEPROM_NIC_TX_RX_FIXED		FIELD16(0x000c)
+#define EEPROM_NIC_EXTERNAL_LNA_BG	FIELD16(0x0010)
+#define EEPROM_NIC_CARDBUS_ACCEL	FIELD16(0x0020)
+#define EEPROM_NIC_EXTERNAL_LNA_A	FIELD16(0x0040)
+
+/*
+ * EEPROM geography.
+ * GEO_A: Default geographical setting for 5GHz band
+ * GEO: Default geographical setting.
+ */
+#define EEPROM_GEOGRAPHY		0x0012
+#define EEPROM_GEOGRAPHY_GEO_A		FIELD16(0x00ff)
+#define EEPROM_GEOGRAPHY_GEO		FIELD16(0xff00)
+
+/*
+ * EEPROM BBP.
+ */
+#define EEPROM_BBP_START		0x0013
+#define EEPROM_BBP_SIZE			16
+#define EEPROM_BBP_VALUE		FIELD16(0x00ff)
+#define EEPROM_BBP_REG_ID		FIELD16(0xff00)
+
+/*
+ * EEPROM TXPOWER 802.11G
+ */
+#define EEPROM_TXPOWER_G_START		0x0023
+#define EEPROM_TXPOWER_G_SIZE		7
+#define EEPROM_TXPOWER_G_1		FIELD16(0x00ff)
+#define EEPROM_TXPOWER_G_2		FIELD16(0xff00)
+
+/*
+ * EEPROM Frequency
+ */
+#define EEPROM_FREQ			0x002f
+#define EEPROM_FREQ_OFFSET		FIELD16(0x00ff)
+#define EEPROM_FREQ_SEQ_MASK		FIELD16(0xff00)
+#define EEPROM_FREQ_SEQ			FIELD16(0x0300)
+
+/*
+ * EEPROM LED.
+ * POLARITY_RDY_G: Polarity RDY_G setting.
+ * POLARITY_RDY_A: Polarity RDY_A setting.
+ * POLARITY_ACT: Polarity ACT setting.
+ * POLARITY_GPIO_0: Polarity GPIO0 setting.
+ * POLARITY_GPIO_1: Polarity GPIO1 setting.
+ * POLARITY_GPIO_2: Polarity GPIO2 setting.
+ * POLARITY_GPIO_3: Polarity GPIO3 setting.
+ * POLARITY_GPIO_4: Polarity GPIO4 setting.
+ * LED_MODE: Led mode.
+ */
+#define EEPROM_LED			0x0030
+#define EEPROM_LED_POLARITY_RDY_G	FIELD16(0x0001)
+#define EEPROM_LED_POLARITY_RDY_A	FIELD16(0x0002)
+#define EEPROM_LED_POLARITY_ACT		FIELD16(0x0004)
+#define EEPROM_LED_POLARITY_GPIO_0	FIELD16(0x0008)
+#define EEPROM_LED_POLARITY_GPIO_1	FIELD16(0x0010)
+#define EEPROM_LED_POLARITY_GPIO_2	FIELD16(0x0020)
+#define EEPROM_LED_POLARITY_GPIO_3	FIELD16(0x0040)
+#define EEPROM_LED_POLARITY_GPIO_4	FIELD16(0x0080)
+#define EEPROM_LED_LED_MODE		FIELD16(0x1f00)
+
+/*
+ * EEPROM TXPOWER 802.11A
+ */
+#define EEPROM_TXPOWER_A_START		0x0031
+#define EEPROM_TXPOWER_A_SIZE		12
+#define EEPROM_TXPOWER_A_1		FIELD16(0x00ff)
+#define EEPROM_TXPOWER_A_2		FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI offset 802.11BG
+ */
+#define EEPROM_RSSI_OFFSET_BG		0x004d
+#define EEPROM_RSSI_OFFSET_BG_1		FIELD16(0x00ff)
+#define EEPROM_RSSI_OFFSET_BG_2		FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI offset 802.11A
+ */
+#define EEPROM_RSSI_OFFSET_A		0x004e
+#define EEPROM_RSSI_OFFSET_A_1		FIELD16(0x00ff)
+#define EEPROM_RSSI_OFFSET_A_2		FIELD16(0xff00)
+
+/*
+ * MCU mailbox commands.
+ */
+#define MCU_SLEEP			0x30
+#define MCU_WAKEUP			0x31
+#define MCU_LED				0x50
+#define MCU_LED_STRENGTH		0x52
+
+/*
+ * DMA descriptor defines.
+ */
+#define TXD_DESC_SIZE			( 16 * sizeof(struct data_desc) )
+#define RXD_DESC_SIZE			( 16 * sizeof(struct data_desc) )
+
+/*
+ * TX descriptor format for TX, PRIO and Beacon Ring.
+ */
+
+/*
+ * Word0
+ * TKIP_MIC: ASIC appends TKIP MIC if TKIP is used.
+ * KEY_TABLE: Use per-client pairwise KEY table.
+ * KEY_INDEX:
+ * Key index (0~31) to the pairwise KEY table.
+ * 0~3 to shared KEY table 0 (BSS0).
+ * 4~7 to shared KEY table 1 (BSS1).
+ * 8~11 to shared KEY table 2 (BSS2).
+ * 12~15 to shared KEY table 3 (BSS3).
+ * BURST: Next frame belongs to same "burst" event.
+ */
+#define TXD_W0_OWNER_NIC		FIELD32(0x00000001)
+#define TXD_W0_VALID			FIELD32(0x00000002)
+#define TXD_W0_MORE_FRAG		FIELD32(0x00000004)
+#define TXD_W0_ACK			FIELD32(0x00000008)
+#define TXD_W0_TIMESTAMP		FIELD32(0x00000010)
+#define TXD_W0_OFDM			FIELD32(0x00000020)
+#define TXD_W0_IFS			FIELD32(0x00000040)
+#define TXD_W0_RETRY_MODE		FIELD32(0x00000080)
+#define TXD_W0_TKIP_MIC			FIELD32(0x00000100)
+#define TXD_W0_KEY_TABLE		FIELD32(0x00000200)
+#define TXD_W0_KEY_INDEX		FIELD32(0x0000fc00)
+#define TXD_W0_DATABYTE_COUNT		FIELD32(0x0fff0000)
+#define TXD_W0_BURST			FIELD32(0x10000000)
+#define TXD_W0_CIPHER_ALG		FIELD32(0xe0000000)
+
+/*
+ * Word1
+ * HOST_Q_ID: EDCA/HCCA queue ID.
+ * HW_SEQUENCE: MAC overwrites the frame sequence number.
+ * BUFFER_COUNT: Number of buffers in this TXD.
+ */
+#define TXD_W1_HOST_Q_ID		FIELD32(0x0000000f)
+#define TXD_W1_AIFSN			FIELD32(0x000000f0)
+#define TXD_W1_CWMIN			FIELD32(0x00000f00)
+#define TXD_W1_CWMAX			FIELD32(0x0000f000)
+#define TXD_W1_IV_OFFSET		FIELD32(0x003f0000)
+#define TXD_W1_PIGGY_BACK		FIELD32(0x01000000)
+#define TXD_W1_HW_SEQUENCE		FIELD32(0x10000000)
+#define TXD_W1_BUFFER_COUNT		FIELD32(0xe0000000)
+
+/*
+ * Word2: PLCP information
+ */
+#define TXD_W2_PLCP_SIGNAL		FIELD32(0x000000ff)
+#define TXD_W2_PLCP_SERVICE		FIELD32(0x0000ff00)
+#define TXD_W2_PLCP_LENGTH_LOW		FIELD32(0x00ff0000)
+#define TXD_W2_PLCP_LENGTH_HIGH		FIELD32(0xff000000)
+
+/*
+ * Word3
+ */
+#define TXD_W3_IV			FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define TXD_W4_EIV			FIELD32(0xffffffff)
+
+/*
+ * Word5
+ * FRAME_OFFSET: Frame start offset inside ASIC TXFIFO (after TXINFO field).
+ * TXD_W5_PID_SUBTYPE: Driver assigned packet ID index for txdone handler.
+ * TXD_W5_PID_TYPE: Driver assigned packet ID type for txdone handler.
+ * WAITING_DMA_DONE_INT: TXD been filled with data
+ * and waiting for TxDoneISR housekeeping.
+ */
+#define TXD_W5_FRAME_OFFSET		FIELD32(0x000000ff)
+#define TXD_W5_PID_SUBTYPE		FIELD32(0x00001f00)
+#define TXD_W5_PID_TYPE			FIELD32(0x0000e000)
+#define TXD_W5_TX_POWER			FIELD32(0x00ff0000)
+#define TXD_W5_WAITING_DMA_DONE_INT	FIELD32(0x01000000)
+
+/*
+ * the above 24-byte is called TXINFO and will be DMAed to MAC block
+ * through TXFIFO. MAC block use this TXINFO to control the transmission
+ * behavior of this frame.
+ * The following fields are not used by MAC block.
+ * They are used by DMA block and HOST driver only.
+ * Once a frame has been DMA to ASIC, all the following fields are useless
+ * to ASIC.
+ */
+
+/*
+ * Word6-10: Buffer physical address
+ */
+#define TXD_W6_BUFFER_PHYSICAL_ADDRESS	FIELD32(0xffffffff)
+#define TXD_W7_BUFFER_PHYSICAL_ADDRESS	FIELD32(0xffffffff)
+#define TXD_W8_BUFFER_PHYSICAL_ADDRESS	FIELD32(0xffffffff)
+#define TXD_W9_BUFFER_PHYSICAL_ADDRESS	FIELD32(0xffffffff)
+#define TXD_W10_BUFFER_PHYSICAL_ADDRESS	FIELD32(0xffffffff)
+
+/*
+ * Word11-13: Buffer length
+ */
+#define TXD_W11_BUFFER_LENGTH0		FIELD32(0x00000fff)
+#define TXD_W11_BUFFER_LENGTH1		FIELD32(0x0fff0000)
+#define TXD_W12_BUFFER_LENGTH2		FIELD32(0x00000fff)
+#define TXD_W12_BUFFER_LENGTH3		FIELD32(0x0fff0000)
+#define TXD_W13_BUFFER_LENGTH4		FIELD32(0x00000fff)
+
+/*
+ * Word14
+ */
+#define TXD_W14_SK_BUFFER		FIELD32(0xffffffff)
+
+/*
+ * Word15
+ */
+#define TXD_W15_NEXT_SK_BUFFER		FIELD32(0xffffffff)
+
+/*
+ * RX descriptor format for RX Ring.
+ */
+
+/*
+ * Word0
+ * CIPHER_ERROR: 1:ICV error, 2:MIC error, 3:invalid key.
+ * KEY_INDEX: Decryption key actually used.
+ */
+#define RXD_W0_OWNER_NIC		FIELD32(0x00000001)
+#define RXD_W0_DROP			FIELD32(0x00000002)
+#define RXD_W0_UNICAST_TO_ME		FIELD32(0x00000004)
+#define RXD_W0_MULTICAST		FIELD32(0x00000008)
+#define RXD_W0_BROADCAST		FIELD32(0x00000010)
+#define RXD_W0_MY_BSS			FIELD32(0x00000020)
+#define RXD_W0_CRC_ERROR		FIELD32(0x00000040)
+#define RXD_W0_OFDM			FIELD32(0x00000080)
+#define RXD_W0_CIPHER_ERROR		FIELD32(0x00000300)
+#define RXD_W0_KEY_INDEX		FIELD32(0x0000fc00)
+#define RXD_W0_DATABYTE_COUNT		FIELD32(0x0fff0000)
+#define RXD_W0_CIPHER_ALG		FIELD32(0xe0000000)
+
+/*
+ * Word1
+ * SIGNAL: RX raw data rate reported by BBP.
+ */
+#define RXD_W1_SIGNAL			FIELD32(0x000000ff)
+#define RXD_W1_RSSI_AGC			FIELD32(0x00001f00)
+#define RXD_W1_RSSI_LNA			FIELD32(0x00006000)
+#define RXD_W1_FRAME_OFFSET		FIELD32(0x7f000000)
+
+/*
+ * Word2
+ * IV: Received IV of originally encrypted.
+ */
+#define RXD_W2_IV			FIELD32(0xffffffff)
+
+/*
+ * Word3
+ * EIV: Received EIV of originally encrypted.
+ */
+#define RXD_W3_EIV			FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define RXD_W4_RESERVED			FIELD32(0xffffffff)
+
+/*
+ * the above 20-byte is called RXINFO and will be DMAed to MAC RX block
+ * and passed to the HOST driver.
+ * The following fields are for DMA block and HOST usage only.
+ * Can't be touched by ASIC MAC block.
+ */
+
+/*
+ * Word5
+ */
+#define RXD_W5_BUFFER_PHYSICAL_ADDRESS	FIELD32(0xffffffff)
+
+/*
+ * Word6-15: Reserved
+ */
+#define RXD_W6_RESERVED			FIELD32(0xffffffff)
+#define RXD_W7_RESERVED			FIELD32(0xffffffff)
+#define RXD_W8_RESERVED			FIELD32(0xffffffff)
+#define RXD_W9_RESERVED			FIELD32(0xffffffff)
+#define RXD_W10_RESERVED		FIELD32(0xffffffff)
+#define RXD_W11_RESERVED		FIELD32(0xffffffff)
+#define RXD_W12_RESERVED		FIELD32(0xffffffff)
+#define RXD_W13_RESERVED		FIELD32(0xffffffff)
+#define RXD_W14_RESERVED		FIELD32(0xffffffff)
+#define RXD_W15_RESERVED		FIELD32(0xffffffff)
+
+/*
+ * Macro's for converting txpower from EEPROM to dscape value
+ * and from dscape value to register value.
+ */
+#define MIN_TXPOWER	0
+#define MAX_TXPOWER	31
+#define DEFAULT_TXPOWER	24
+
+#define TXPOWER_FROM_DEV(__txpower)		\
+({						\
+	((__txpower) > MAX_TXPOWER) ?		\
+		DEFAULT_TXPOWER : (__txpower);	\
+})
+
+#define TXPOWER_TO_DEV(__txpower)			\
+({							\
+	((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER :	\
+	(((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER :	\
+	(__txpower));					\
+})
+
+#endif /* RT61PCI_H */
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
new file mode 100644
index 0000000..3e42759
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -0,0 +1,2110 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt73usb
+	Abstract: rt73usb device specific routines.
+	Supported chipsets: rt2571W & rt2671.
+ */
+
+/*
+ * Set enviroment defines for rt2x00.h
+ */
+#define DRV_NAME "rt73usb"
+
+#include <linux/delay.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "rt2x00.h"
+#include "rt2x00usb.h"
+#include "rt73usb.h"
+
+/*
+ * Register access.
+ * All access to the CSR registers will go through the methods
+ * rt73usb_register_read and rt73usb_register_write.
+ * BBP and RF register require indirect register access,
+ * and use the CSR registers BBPCSR and RFCSR to achieve this.
+ * These indirect registers work with busy bits,
+ * and we will try maximal REGISTER_BUSY_COUNT times to access
+ * the register while taking a REGISTER_BUSY_DELAY us delay
+ * between each attampt. When the busy bit is still set at that time,
+ * the access attempt is considered to have failed,
+ * and we will print an error.
+ */
+static inline void rt73usb_register_read(const struct rt2x00_dev *rt2x00dev,
+					 const unsigned int offset, u32 *value)
+{
+	__le32 reg;
+	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+				      USB_VENDOR_REQUEST_IN, offset,
+				      &reg, sizeof(u32), REGISTER_TIMEOUT);
+	*value = le32_to_cpu(reg);
+}
+
+static inline void rt73usb_register_multiread(const struct rt2x00_dev
+					      *rt2x00dev,
+					      const unsigned int offset,
+					      void *value, const u32 length)
+{
+	int timeout = REGISTER_TIMEOUT * (length / sizeof(u32));
+	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ,
+				      USB_VENDOR_REQUEST_IN, offset,
+				      value, length, timeout);
+}
+
+static inline void rt73usb_register_write(const struct rt2x00_dev *rt2x00dev,
+					  const unsigned int offset, u32 value)
+{
+	__le32 reg = cpu_to_le32(value);
+	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+				      USB_VENDOR_REQUEST_OUT, offset,
+				      &reg, sizeof(u32), REGISTER_TIMEOUT);
+}
+
+static inline void rt73usb_register_multiwrite(const struct rt2x00_dev
+					       *rt2x00dev,
+					       const unsigned int offset,
+					       void *value, const u32 length)
+{
+	int timeout = REGISTER_TIMEOUT * (length / sizeof(u32));
+	rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE,
+				      USB_VENDOR_REQUEST_OUT, offset,
+				      value, length, timeout);
+}
+
+static u32 rt73usb_bbp_check(const struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+	unsigned int i;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt73usb_register_read(rt2x00dev, PHY_CSR3, &reg);
+		if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY))
+			break;
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	return reg;
+}
+
+static void rt73usb_bbp_write(const struct rt2x00_dev *rt2x00dev,
+			      const unsigned int word, const u8 value)
+{
+	u32 reg;
+
+	/*
+	 * Wait until the BBP becomes ready.
+	 */
+	reg = rt73usb_bbp_check(rt2x00dev);
+	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+		ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n");
+		return;
+	}
+
+	/*
+	 * Write the data into the BBP.
+	 */
+	reg = 0;
+	rt2x00_set_field32(&reg, PHY_CSR3_VALUE, value);
+	rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+	rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+	rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 0);
+
+	rt73usb_register_write(rt2x00dev, PHY_CSR3, reg);
+}
+
+static void rt73usb_bbp_read(const struct rt2x00_dev *rt2x00dev,
+			     const unsigned int word, u8 *value)
+{
+	u32 reg;
+
+	/*
+	 * Wait until the BBP becomes ready.
+	 */
+	reg = rt73usb_bbp_check(rt2x00dev);
+	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+		ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+		return;
+	}
+
+	/*
+	 * Write the request into the BBP.
+	 */
+	reg = 0;
+	rt2x00_set_field32(&reg, PHY_CSR3_REGNUM, word);
+	rt2x00_set_field32(&reg, PHY_CSR3_BUSY, 1);
+	rt2x00_set_field32(&reg, PHY_CSR3_READ_CONTROL, 1);
+
+	rt73usb_register_write(rt2x00dev, PHY_CSR3, reg);
+
+	/*
+	 * Wait until the BBP becomes ready.
+	 */
+	reg = rt73usb_bbp_check(rt2x00dev);
+	if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) {
+		ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n");
+		*value = 0xff;
+		return;
+	}
+
+	*value = rt2x00_get_field32(reg, PHY_CSR3_VALUE);
+}
+
+static void rt73usb_rf_write(const struct rt2x00_dev *rt2x00dev,
+			     const unsigned int word, const u32 value)
+{
+	u32 reg;
+	unsigned int i;
+
+	if (!word)
+		return;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt73usb_register_read(rt2x00dev, PHY_CSR4, &reg);
+		if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY))
+			goto rf_write;
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n");
+	return;
+
+rf_write:
+	reg = 0;
+	rt2x00_set_field32(&reg, PHY_CSR4_VALUE, value);
+
+	/*
+	 * RF5225 and RF2527 contain 21 bits per RF register value,
+	 * all others contain 20 bits.
+	 */
+	rt2x00_set_field32(&reg, PHY_CSR4_NUMBER_OF_BITS,
+			   20 + !!(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+				   rt2x00_rf(&rt2x00dev->chip, RF2527)));
+	rt2x00_set_field32(&reg, PHY_CSR4_IF_SELECT, 0);
+	rt2x00_set_field32(&reg, PHY_CSR4_BUSY, 1);
+
+	rt73usb_register_write(rt2x00dev, PHY_CSR4, reg);
+	rt2x00_rf_write(rt2x00dev, word, value);
+}
+
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+#define CSR_OFFSET(__word)	( CSR_REG_BASE + ((__word) * sizeof(u32)) )
+
+static void rt73usb_read_csr(const struct rt2x00_dev *rt2x00dev,
+			     const unsigned int word, u32 *data)
+{
+	rt73usb_register_read(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static void rt73usb_write_csr(const struct rt2x00_dev *rt2x00dev,
+			      const unsigned int word, u32 data)
+{
+	rt73usb_register_write(rt2x00dev, CSR_OFFSET(word), data);
+}
+
+static const struct rt2x00debug rt73usb_rt2x00debug = {
+	.owner	= THIS_MODULE,
+	.csr	= {
+		.read		= rt73usb_read_csr,
+		.write		= rt73usb_write_csr,
+		.word_size	= sizeof(u32),
+		.word_count	= CSR_REG_SIZE / sizeof(u32),
+	},
+	.eeprom	= {
+		.read		= rt2x00_eeprom_read,
+		.write		= rt2x00_eeprom_write,
+		.word_size	= sizeof(u16),
+		.word_count	= EEPROM_SIZE / sizeof(u16),
+	},
+	.bbp	= {
+		.read		= rt73usb_bbp_read,
+		.write		= rt73usb_bbp_write,
+		.word_size	= sizeof(u8),
+		.word_count	= BBP_SIZE / sizeof(u8),
+	},
+	.rf	= {
+		.read		= rt2x00_rf_read,
+		.write		= rt73usb_rf_write,
+		.word_size	= sizeof(u32),
+		.word_count	= RF_SIZE / sizeof(u32),
+	},
+};
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+/*
+ * Configuration handlers.
+ */
+static void rt73usb_config_mac_addr(struct rt2x00_dev *rt2x00dev, __le32 *mac)
+{
+	u32 tmp;
+
+	tmp = le32_to_cpu(mac[1]);
+	rt2x00_set_field32(&tmp, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff);
+	mac[1] = cpu_to_le32(tmp);
+
+	rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2, mac,
+				    (2 * sizeof(__le32)));
+}
+
+static void rt73usb_config_bssid(struct rt2x00_dev *rt2x00dev, __le32 *bssid)
+{
+	u32 tmp;
+
+	tmp = le32_to_cpu(bssid[1]);
+	rt2x00_set_field32(&tmp, MAC_CSR5_BSS_ID_MASK, 3);
+	bssid[1] = cpu_to_le32(tmp);
+
+	rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, bssid,
+				    (2 * sizeof(__le32)));
+}
+
+static void rt73usb_config_type(struct rt2x00_dev *rt2x00dev, const int type,
+				const int tsf_sync)
+{
+	u32 reg;
+
+	/*
+	 * Clear current synchronisation setup.
+	 * For the Beacon base registers we only need to clear
+	 * the first byte since that byte contains the VALID and OWNER
+	 * bits which (when set to 0) will invalidate the entire beacon.
+	 */
+	rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0);
+	rt73usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0);
+	rt73usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0);
+	rt73usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0);
+	rt73usb_register_write(rt2x00dev, HW_BEACON_BASE3, 0);
+
+	/*
+	 * Enable synchronisation.
+	 */
+	rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_TICKING, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TBTT_ENABLE, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR9_TSF_SYNC, tsf_sync);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+}
+
+static void rt73usb_config_preamble(struct rt2x00_dev *rt2x00dev,
+				      const int short_preamble,
+				      const int ack_timeout,
+				      const int ack_consume_time)
+{
+	u32 reg;
+
+	/*
+	 * When in atomic context, reschedule and let rt2x00lib
+	 * call this function again.
+	 */
+	if (in_atomic()) {
+		queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->config_work);
+		return;
+	}
+
+	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR0_RX_ACK_TIMEOUT, ack_timeout);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+	rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_PREAMBLE,
+			   !!short_preamble);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+}
+
+static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev,
+				   const int basic_rate_mask)
+{
+	rt73usb_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask);
+}
+
+static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev,
+				   struct rf_channel *rf, const int txpower)
+{
+	u8 r3;
+	u8 r94;
+	u8 smart;
+
+	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower));
+	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset);
+
+	smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+		  rt2x00_rf(&rt2x00dev->chip, RF2527));
+
+	rt73usb_bbp_read(rt2x00dev, 3, &r3);
+	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart);
+	rt73usb_bbp_write(rt2x00dev, 3, r3);
+
+	r94 = 6;
+	if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94))
+		r94 += txpower - MAX_TXPOWER;
+	else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94))
+		r94 += txpower;
+	rt73usb_bbp_write(rt2x00dev, 94, r94);
+
+	rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+	rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+	rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+	rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+	rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+	rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+	rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004);
+	rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+	rt73usb_rf_write(rt2x00dev, 1, rf->rf1);
+	rt73usb_rf_write(rt2x00dev, 2, rf->rf2);
+	rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004);
+	rt73usb_rf_write(rt2x00dev, 4, rf->rf4);
+
+	udelay(10);
+}
+
+static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev,
+				   const int txpower)
+{
+	struct rf_channel rf;
+
+	rt2x00_rf_read(rt2x00dev, 1, &rf.rf1);
+	rt2x00_rf_read(rt2x00dev, 2, &rf.rf2);
+	rt2x00_rf_read(rt2x00dev, 3, &rf.rf3);
+	rt2x00_rf_read(rt2x00dev, 4, &rf.rf4);
+
+	rt73usb_config_channel(rt2x00dev, &rf, txpower);
+}
+
+static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
+				      const int antenna_tx,
+				      const int antenna_rx)
+{
+	u8 r3;
+	u8 r4;
+	u8 r77;
+
+	rt73usb_bbp_read(rt2x00dev, 3, &r3);
+	rt73usb_bbp_read(rt2x00dev, 4, &r4);
+	rt73usb_bbp_read(rt2x00dev, 77, &r77);
+
+	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0);
+
+	switch (antenna_rx) {
+	case ANTENNA_SW_DIVERSITY:
+	case ANTENNA_HW_DIVERSITY:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
+				  !!(rt2x00dev->curr_hwmode != HWMODE_A));
+		break;
+	case ANTENNA_A:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+		if (rt2x00dev->curr_hwmode == HWMODE_A)
+			rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+		else
+			rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+		break;
+	case ANTENNA_B:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+		rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0);
+
+		if (rt2x00dev->curr_hwmode == HWMODE_A)
+			rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+		else
+			rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+		break;
+	}
+
+	rt73usb_bbp_write(rt2x00dev, 77, r77);
+	rt73usb_bbp_write(rt2x00dev, 3, r3);
+	rt73usb_bbp_write(rt2x00dev, 4, r4);
+}
+
+static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
+				      const int antenna_tx,
+				      const int antenna_rx)
+{
+	u8 r3;
+	u8 r4;
+	u8 r77;
+
+	rt73usb_bbp_read(rt2x00dev, 3, &r3);
+	rt73usb_bbp_read(rt2x00dev, 4, &r4);
+	rt73usb_bbp_read(rt2x00dev, 77, &r77);
+
+	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0);
+	rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
+			  !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags));
+
+	switch (antenna_rx) {
+	case ANTENNA_SW_DIVERSITY:
+	case ANTENNA_HW_DIVERSITY:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2);
+		break;
+	case ANTENNA_A:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+		rt2x00_set_field8(&r77, BBP_R77_PAIR, 3);
+		break;
+	case ANTENNA_B:
+		rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1);
+		rt2x00_set_field8(&r77, BBP_R77_PAIR, 0);
+		break;
+	}
+
+	rt73usb_bbp_write(rt2x00dev, 77, r77);
+	rt73usb_bbp_write(rt2x00dev, 3, r3);
+	rt73usb_bbp_write(rt2x00dev, 4, r4);
+}
+
+struct antenna_sel {
+	u8 word;
+	/*
+	 * value[0] -> non-LNA
+	 * value[1] -> LNA
+	 */
+	u8 value[2];
+};
+
+static const struct antenna_sel antenna_sel_a[] = {
+	{ 96,  { 0x58, 0x78 } },
+	{ 104, { 0x38, 0x48 } },
+	{ 75,  { 0xfe, 0x80 } },
+	{ 86,  { 0xfe, 0x80 } },
+	{ 88,  { 0xfe, 0x80 } },
+	{ 35,  { 0x60, 0x60 } },
+	{ 97,  { 0x58, 0x58 } },
+	{ 98,  { 0x58, 0x58 } },
+};
+
+static const struct antenna_sel antenna_sel_bg[] = {
+	{ 96,  { 0x48, 0x68 } },
+	{ 104, { 0x2c, 0x3c } },
+	{ 75,  { 0xfe, 0x80 } },
+	{ 86,  { 0xfe, 0x80 } },
+	{ 88,  { 0xfe, 0x80 } },
+	{ 35,  { 0x50, 0x50 } },
+	{ 97,  { 0x48, 0x48 } },
+	{ 98,  { 0x48, 0x48 } },
+};
+
+static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev,
+				   const int antenna_tx, const int antenna_rx)
+{
+	const struct antenna_sel *sel;
+	unsigned int lna;
+	unsigned int i;
+	u32 reg;
+
+	rt73usb_register_read(rt2x00dev, PHY_CSR0, &reg);
+
+	if (rt2x00dev->curr_hwmode == HWMODE_A) {
+		sel = antenna_sel_a;
+		lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+
+		rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG, 0);
+		rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A, 1);
+	} else {
+		sel = antenna_sel_bg;
+		lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+
+		rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_BG, 1);
+		rt2x00_set_field32(&reg, PHY_CSR0_PA_PE_A, 0);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
+		rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]);
+
+	rt73usb_register_write(rt2x00dev, PHY_CSR0, reg);
+
+	if (rt2x00_rf(&rt2x00dev->chip, RF5226) ||
+	    rt2x00_rf(&rt2x00dev->chip, RF5225))
+		rt73usb_config_antenna_5x(rt2x00dev, antenna_tx, antenna_rx);
+	else if (rt2x00_rf(&rt2x00dev->chip, RF2528) ||
+		 rt2x00_rf(&rt2x00dev->chip, RF2527))
+		rt73usb_config_antenna_2x(rt2x00dev, antenna_tx, antenna_rx);
+}
+
+static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev,
+				    struct rt2x00lib_conf *libconf)
+{
+	u32 reg;
+
+	rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR9_SLOT_TIME, libconf->slot_time);
+	rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
+
+	rt73usb_register_read(rt2x00dev, MAC_CSR8, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR8_SIFS, libconf->sifs);
+	rt2x00_set_field32(&reg, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3);
+	rt2x00_set_field32(&reg, MAC_CSR8_EIFS, libconf->eifs);
+	rt73usb_register_write(rt2x00dev, MAC_CSR8, reg);
+
+	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+	rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR4_AUTORESPOND_ENABLE, 1);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+
+	rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_INTERVAL,
+			   libconf->conf->beacon_int * 16);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+}
+
+static void rt73usb_config(struct rt2x00_dev *rt2x00dev,
+			   const unsigned int flags,
+			   struct rt2x00lib_conf *libconf)
+{
+	if (flags & CONFIG_UPDATE_PHYMODE)
+		rt73usb_config_phymode(rt2x00dev, libconf->basic_rates);
+	if (flags & CONFIG_UPDATE_CHANNEL)
+		rt73usb_config_channel(rt2x00dev, &libconf->rf,
+				       libconf->conf->power_level);
+	if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL))
+		rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level);
+	if (flags & CONFIG_UPDATE_ANTENNA)
+		rt73usb_config_antenna(rt2x00dev, libconf->conf->antenna_sel_tx,
+				       libconf->conf->antenna_sel_rx);
+	if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT))
+		rt73usb_config_duration(rt2x00dev, libconf);
+}
+
+/*
+ * LED functions.
+ */
+static void rt73usb_enable_led(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	rt73usb_register_read(rt2x00dev, MAC_CSR14, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR14_ON_PERIOD, 70);
+	rt2x00_set_field32(&reg, MAC_CSR14_OFF_PERIOD, 30);
+	rt73usb_register_write(rt2x00dev, MAC_CSR14, reg);
+
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 1);
+	if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A)
+		rt2x00_set_field16(&rt2x00dev->led_reg,
+				   MCU_LEDCS_LINK_A_STATUS, 1);
+	else
+		rt2x00_set_field16(&rt2x00dev->led_reg,
+				   MCU_LEDCS_LINK_BG_STATUS, 1);
+
+	rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000,
+				    rt2x00dev->led_reg, REGISTER_TIMEOUT);
+}
+
+static void rt73usb_disable_led(struct rt2x00_dev *rt2x00dev)
+{
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 0);
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS, 0);
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS, 0);
+
+	rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000,
+				    rt2x00dev->led_reg, REGISTER_TIMEOUT);
+}
+
+static void rt73usb_activity_led(struct rt2x00_dev *rt2x00dev, int rssi)
+{
+	u32 led;
+
+	if (rt2x00dev->led_mode != LED_MODE_SIGNAL_STRENGTH)
+		return;
+
+	/*
+	 * Led handling requires a positive value for the rssi,
+	 * to do that correctly we need to add the correction.
+	 */
+	rssi += rt2x00dev->rssi_offset;
+
+	if (rssi <= 30)
+		led = 0;
+	else if (rssi <= 39)
+		led = 1;
+	else if (rssi <= 49)
+		led = 2;
+	else if (rssi <= 53)
+		led = 3;
+	else if (rssi <= 63)
+		led = 4;
+	else
+		led = 5;
+
+	rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, led,
+				    rt2x00dev->led_reg, REGISTER_TIMEOUT);
+}
+
+/*
+ * Link tuning
+ */
+static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	/*
+	 * Update FCS error count from register.
+	 */
+	rt73usb_register_read(rt2x00dev, STA_CSR0, &reg);
+	rt2x00dev->link.rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR);
+
+	/*
+	 * Update False CCA count from register.
+	 */
+	rt73usb_register_read(rt2x00dev, STA_CSR1, &reg);
+	reg = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
+	rt2x00dev->link.false_cca =
+	    rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR);
+}
+
+static void rt73usb_reset_tuner(struct rt2x00_dev *rt2x00dev)
+{
+	rt73usb_bbp_write(rt2x00dev, 17, 0x20);
+	rt2x00dev->link.vgc_level = 0x20;
+}
+
+static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev)
+{
+	int rssi = rt2x00_get_link_rssi(&rt2x00dev->link);
+	u8 r17;
+	u8 up_bound;
+	u8 low_bound;
+
+	/*
+	 * Update Led strength
+	 */
+	rt73usb_activity_led(rt2x00dev, rssi);
+
+	rt73usb_bbp_read(rt2x00dev, 17, &r17);
+
+	/*
+	 * Determine r17 bounds.
+	 */
+	if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+		low_bound = 0x28;
+		up_bound = 0x48;
+
+		if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
+			low_bound += 0x10;
+			up_bound += 0x10;
+		}
+	} else {
+		if (rssi > -82) {
+			low_bound = 0x1c;
+			up_bound = 0x40;
+		} else if (rssi > -84) {
+			low_bound = 0x1c;
+			up_bound = 0x20;
+		} else {
+			low_bound = 0x1c;
+			up_bound = 0x1c;
+		}
+
+		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) {
+			low_bound += 0x14;
+			up_bound += 0x10;
+		}
+	}
+
+	/*
+	 * Special big-R17 for very short distance
+	 */
+	if (rssi > -35) {
+		if (r17 != 0x60)
+			rt73usb_bbp_write(rt2x00dev, 17, 0x60);
+		return;
+	}
+
+	/*
+	 * Special big-R17 for short distance
+	 */
+	if (rssi >= -58) {
+		if (r17 != up_bound)
+			rt73usb_bbp_write(rt2x00dev, 17, up_bound);
+		return;
+	}
+
+	/*
+	 * Special big-R17 for middle-short distance
+	 */
+	if (rssi >= -66) {
+		low_bound += 0x10;
+		if (r17 != low_bound)
+			rt73usb_bbp_write(rt2x00dev, 17, low_bound);
+		return;
+	}
+
+	/*
+	 * Special mid-R17 for middle distance
+	 */
+	if (rssi >= -74) {
+		if (r17 != (low_bound + 0x10))
+			rt73usb_bbp_write(rt2x00dev, 17, low_bound + 0x08);
+		return;
+	}
+
+	/*
+	 * Special case: Change up_bound based on the rssi.
+	 * Lower up_bound when rssi is weaker then -74 dBm.
+	 */
+	up_bound -= 2 * (-74 - rssi);
+	if (low_bound > up_bound)
+		up_bound = low_bound;
+
+	if (r17 > up_bound) {
+		rt73usb_bbp_write(rt2x00dev, 17, up_bound);
+		return;
+	}
+
+	/*
+	 * r17 does not yet exceed upper limit, continue and base
+	 * the r17 tuning on the false CCA count.
+	 */
+	if (rt2x00dev->link.false_cca > 512 && r17 < up_bound) {
+		r17 += 4;
+		if (r17 > up_bound)
+			r17 = up_bound;
+		rt73usb_bbp_write(rt2x00dev, 17, r17);
+	} else if (rt2x00dev->link.false_cca < 100 && r17 > low_bound) {
+		r17 -= 4;
+		if (r17 < low_bound)
+			r17 = low_bound;
+		rt73usb_bbp_write(rt2x00dev, 17, r17);
+	}
+}
+
+/*
+ * Firmware name function.
+ */
+static char *rt73usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
+{
+	return FIRMWARE_RT2571;
+}
+
+/*
+ * Initialization functions.
+ */
+static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, void *data,
+				 const size_t len)
+{
+	unsigned int i;
+	int status;
+	u32 reg;
+	char *ptr = data;
+	char *cache;
+	int buflen;
+	int timeout;
+
+	/*
+	 * Wait for stable hardware.
+	 */
+	for (i = 0; i < 100; i++) {
+		rt73usb_register_read(rt2x00dev, MAC_CSR0, &reg);
+		if (reg)
+			break;
+		msleep(1);
+	}
+
+	if (!reg) {
+		ERROR(rt2x00dev, "Unstable hardware.\n");
+		return -EBUSY;
+	}
+
+	/*
+	 * Write firmware to device.
+	 * We setup a seperate cache for this action,
+	 * since we are going to write larger chunks of data
+	 * then normally used cache size.
+	 */
+	cache = kmalloc(CSR_CACHE_SIZE_FIRMWARE, GFP_KERNEL);
+	if (!cache) {
+		ERROR(rt2x00dev, "Failed to allocate firmware cache.\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < len; i += CSR_CACHE_SIZE_FIRMWARE) {
+		buflen = min_t(int, len - i, CSR_CACHE_SIZE_FIRMWARE);
+		timeout = REGISTER_TIMEOUT * (buflen / sizeof(u32));
+
+		memcpy(cache, ptr, buflen);
+
+		rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
+					 USB_VENDOR_REQUEST_OUT,
+					 FIRMWARE_IMAGE_BASE + i, 0x0000,
+					 cache, buflen, timeout);
+
+		ptr += buflen;
+	}
+
+	kfree(cache);
+
+	/*
+	 * Send firmware request to device to load firmware,
+	 * we need to specify a long timeout time.
+	 */
+	status = rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE,
+					     0x0000, USB_MODE_FIRMWARE,
+					     REGISTER_TIMEOUT_FIRMWARE);
+	if (status < 0) {
+		ERROR(rt2x00dev, "Failed to write Firmware to device.\n");
+		return status;
+	}
+
+	rt73usb_disable_led(rt2x00dev);
+
+	return 0;
+}
+
+static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+
+	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR0_AUTO_TX_SEQ, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR0_TX_WITHOUT_WAITING, 0);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+
+	rt73usb_register_read(rt2x00dev, TXRX_CSR1, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */
+	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID0_VALID, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1, 30); /* Rssi */
+	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID1_VALID, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2, 42); /* OFDM Rate */
+	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID2_VALID, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3, 30); /* Rssi */
+	rt2x00_set_field32(&reg, TXRX_CSR1_BBP_ID3_VALID, 1);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR1, reg);
+
+	/*
+	 * CCK TXD BBP registers
+	 */
+	rt73usb_register_read(rt2x00dev, TXRX_CSR2, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0, 13);
+	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID0_VALID, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1, 12);
+	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID1_VALID, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2, 11);
+	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID2_VALID, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3, 10);
+	rt2x00_set_field32(&reg, TXRX_CSR2_BBP_ID3_VALID, 1);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR2, reg);
+
+	/*
+	 * OFDM TXD BBP registers
+	 */
+	rt73usb_register_read(rt2x00dev, TXRX_CSR3, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0, 7);
+	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID0_VALID, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1, 6);
+	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID1_VALID, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2, 5);
+	rt2x00_set_field32(&reg, TXRX_CSR3_BBP_ID2_VALID, 1);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR3, reg);
+
+	rt73usb_register_read(rt2x00dev, TXRX_CSR7, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_6MBS, 59);
+	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_9MBS, 53);
+	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_12MBS, 49);
+	rt2x00_set_field32(&reg, TXRX_CSR7_ACK_CTS_18MBS, 46);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR7, reg);
+
+	rt73usb_register_read(rt2x00dev, TXRX_CSR8, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_24MBS, 44);
+	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_36MBS, 42);
+	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_48MBS, 42);
+	rt2x00_set_field32(&reg, TXRX_CSR8_ACK_CTS_54MBS, 42);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR8, reg);
+
+	rt73usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f);
+
+	rt73usb_register_read(rt2x00dev, MAC_CSR6, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR6_MAX_FRAME_UNIT, 0xfff);
+	rt73usb_register_write(rt2x00dev, MAC_CSR6, reg);
+
+	rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718);
+
+	if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+		return -EBUSY;
+
+	rt73usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00);
+
+	/*
+	 * Invalidate all Shared Keys (SEC_CSR0),
+	 * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5)
+	 */
+	rt73usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000);
+	rt73usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000);
+	rt73usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000);
+
+	reg = 0x000023b0;
+	if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+	    rt2x00_rf(&rt2x00dev->chip, RF2527))
+		rt2x00_set_field32(&reg, PHY_CSR1_RF_RPI, 1);
+	rt73usb_register_write(rt2x00dev, PHY_CSR1, reg);
+
+	rt73usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06);
+	rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606);
+	rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408);
+
+	rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, &reg);
+	rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC0_TX_OP, 0);
+	rt2x00_set_field32(&reg, AC_TXOP_CSR0_AC1_TX_OP, 0);
+	rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg);
+
+	rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, &reg);
+	rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC2_TX_OP, 192);
+	rt2x00_set_field32(&reg, AC_TXOP_CSR1_AC3_TX_OP, 48);
+	rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg);
+
+	rt73usb_register_read(rt2x00dev, MAC_CSR9, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR9_CW_SELECT, 0);
+	rt73usb_register_write(rt2x00dev, MAC_CSR9, reg);
+
+	/*
+	 * We must clear the error counters.
+	 * These registers are cleared on read,
+	 * so we may pass a useless variable to store the value.
+	 */
+	rt73usb_register_read(rt2x00dev, STA_CSR0, &reg);
+	rt73usb_register_read(rt2x00dev, STA_CSR1, &reg);
+	rt73usb_register_read(rt2x00dev, STA_CSR2, &reg);
+
+	/*
+	 * Reset MAC and BBP registers.
+	 */
+	rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 1);
+	rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 1);
+	rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+	rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR1_SOFT_RESET, 0);
+	rt2x00_set_field32(&reg, MAC_CSR1_BBP_RESET, 0);
+	rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+	rt73usb_register_read(rt2x00dev, MAC_CSR1, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR1_HOST_READY, 1);
+	rt73usb_register_write(rt2x00dev, MAC_CSR1, reg);
+
+	return 0;
+}
+
+static int rt73usb_init_bbp(struct rt2x00_dev *rt2x00dev)
+{
+	unsigned int i;
+	u16 eeprom;
+	u8 reg_id;
+	u8 value;
+
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt73usb_bbp_read(rt2x00dev, 0, &value);
+		if ((value != 0xff) && (value != 0x00))
+			goto continue_csr_init;
+		NOTICE(rt2x00dev, "Waiting for BBP register.\n");
+		udelay(REGISTER_BUSY_DELAY);
+	}
+
+	ERROR(rt2x00dev, "BBP register access failed, aborting.\n");
+	return -EACCES;
+
+continue_csr_init:
+	rt73usb_bbp_write(rt2x00dev, 3, 0x80);
+	rt73usb_bbp_write(rt2x00dev, 15, 0x30);
+	rt73usb_bbp_write(rt2x00dev, 21, 0xc8);
+	rt73usb_bbp_write(rt2x00dev, 22, 0x38);
+	rt73usb_bbp_write(rt2x00dev, 23, 0x06);
+	rt73usb_bbp_write(rt2x00dev, 24, 0xfe);
+	rt73usb_bbp_write(rt2x00dev, 25, 0x0a);
+	rt73usb_bbp_write(rt2x00dev, 26, 0x0d);
+	rt73usb_bbp_write(rt2x00dev, 32, 0x0b);
+	rt73usb_bbp_write(rt2x00dev, 34, 0x12);
+	rt73usb_bbp_write(rt2x00dev, 37, 0x07);
+	rt73usb_bbp_write(rt2x00dev, 39, 0xf8);
+	rt73usb_bbp_write(rt2x00dev, 41, 0x60);
+	rt73usb_bbp_write(rt2x00dev, 53, 0x10);
+	rt73usb_bbp_write(rt2x00dev, 54, 0x18);
+	rt73usb_bbp_write(rt2x00dev, 60, 0x10);
+	rt73usb_bbp_write(rt2x00dev, 61, 0x04);
+	rt73usb_bbp_write(rt2x00dev, 62, 0x04);
+	rt73usb_bbp_write(rt2x00dev, 75, 0xfe);
+	rt73usb_bbp_write(rt2x00dev, 86, 0xfe);
+	rt73usb_bbp_write(rt2x00dev, 88, 0xfe);
+	rt73usb_bbp_write(rt2x00dev, 90, 0x0f);
+	rt73usb_bbp_write(rt2x00dev, 99, 0x00);
+	rt73usb_bbp_write(rt2x00dev, 102, 0x16);
+	rt73usb_bbp_write(rt2x00dev, 107, 0x04);
+
+	DEBUG(rt2x00dev, "Start initialization from EEPROM...\n");
+	for (i = 0; i < EEPROM_BBP_SIZE; i++) {
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_BBP_START + i, &eeprom);
+
+		if (eeprom != 0xffff && eeprom != 0x0000) {
+			reg_id = rt2x00_get_field16(eeprom, EEPROM_BBP_REG_ID);
+			value = rt2x00_get_field16(eeprom, EEPROM_BBP_VALUE);
+			DEBUG(rt2x00dev, "BBP: 0x%02x, value: 0x%02x.\n",
+			      reg_id, value);
+			rt73usb_bbp_write(rt2x00dev, reg_id, value);
+		}
+	}
+	DEBUG(rt2x00dev, "...End initialization from EEPROM.\n");
+
+	return 0;
+}
+
+/*
+ * Device state switch handlers.
+ */
+static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
+			      enum dev_state state)
+{
+	u32 reg;
+
+	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DISABLE_RX,
+			   state == STATE_RADIO_RX_OFF);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+}
+
+static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev)
+{
+	/*
+	 * Initialize all registers.
+	 */
+	if (rt73usb_init_registers(rt2x00dev) ||
+	    rt73usb_init_bbp(rt2x00dev)) {
+		ERROR(rt2x00dev, "Register initialization failed.\n");
+		return -EIO;
+	}
+
+	rt2x00usb_enable_radio(rt2x00dev);
+
+	/*
+	 * Enable LED
+	 */
+	rt73usb_enable_led(rt2x00dev);
+
+	return 0;
+}
+
+static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev)
+{
+	/*
+	 * Disable LED
+	 */
+	rt73usb_disable_led(rt2x00dev);
+
+	rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818);
+
+	/*
+	 * Disable synchronisation.
+	 */
+	rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0);
+
+	rt2x00usb_disable_radio(rt2x00dev);
+}
+
+static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state)
+{
+	u32 reg;
+	unsigned int i;
+	char put_to_sleep;
+	char current_state;
+
+	put_to_sleep = (state != STATE_AWAKE);
+
+	rt73usb_register_read(rt2x00dev, MAC_CSR12, &reg);
+	rt2x00_set_field32(&reg, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep);
+	rt2x00_set_field32(&reg, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep);
+	rt73usb_register_write(rt2x00dev, MAC_CSR12, reg);
+
+	/*
+	 * Device is not guaranteed to be in the requested state yet.
+	 * We must wait until the register indicates that the
+	 * device has entered the correct state.
+	 */
+	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+		rt73usb_register_read(rt2x00dev, MAC_CSR12, &reg);
+		current_state =
+		    rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE);
+		if (current_state == !put_to_sleep)
+			return 0;
+		msleep(10);
+	}
+
+	NOTICE(rt2x00dev, "Device failed to enter state %d, "
+	       "current device state %d.\n", !put_to_sleep, current_state);
+
+	return -EBUSY;
+}
+
+static int rt73usb_set_device_state(struct rt2x00_dev *rt2x00dev,
+				    enum dev_state state)
+{
+	int retval = 0;
+
+	switch (state) {
+	case STATE_RADIO_ON:
+		retval = rt73usb_enable_radio(rt2x00dev);
+		break;
+	case STATE_RADIO_OFF:
+		rt73usb_disable_radio(rt2x00dev);
+		break;
+	case STATE_RADIO_RX_ON:
+	case STATE_RADIO_RX_OFF:
+		rt73usb_toggle_rx(rt2x00dev, state);
+		break;
+	case STATE_DEEP_SLEEP:
+	case STATE_SLEEP:
+	case STATE_STANDBY:
+	case STATE_AWAKE:
+		retval = rt73usb_set_state(rt2x00dev, state);
+		break;
+	default:
+		retval = -ENOTSUPP;
+		break;
+	}
+
+	return retval;
+}
+
+/*
+ * TX descriptor initialization
+ */
+static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
+				  struct data_desc *txd,
+				  struct txdata_entry_desc *desc,
+				  struct ieee80211_hdr *ieee80211hdr,
+				  unsigned int length,
+				  struct ieee80211_tx_control *control)
+{
+	u32 word;
+
+	/*
+	 * Start writing the descriptor words.
+	 */
+	rt2x00_desc_read(txd, 1, &word);
+	rt2x00_set_field32(&word, TXD_W1_HOST_Q_ID, desc->queue);
+	rt2x00_set_field32(&word, TXD_W1_AIFSN, desc->aifs);
+	rt2x00_set_field32(&word, TXD_W1_CWMIN, desc->cw_min);
+	rt2x00_set_field32(&word, TXD_W1_CWMAX, desc->cw_max);
+	rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER);
+	rt2x00_set_field32(&word, TXD_W1_HW_SEQUENCE, 1);
+	rt2x00_desc_write(txd, 1, word);
+
+	rt2x00_desc_read(txd, 2, &word);
+	rt2x00_set_field32(&word, TXD_W2_PLCP_SIGNAL, desc->signal);
+	rt2x00_set_field32(&word, TXD_W2_PLCP_SERVICE, desc->service);
+	rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_LOW, desc->length_low);
+	rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, desc->length_high);
+	rt2x00_desc_write(txd, 2, word);
+
+	rt2x00_desc_read(txd, 5, &word);
+	rt2x00_set_field32(&word, TXD_W5_TX_POWER,
+			   TXPOWER_TO_DEV(control->power_level));
+	rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1);
+	rt2x00_desc_write(txd, 5, word);
+
+	rt2x00_desc_read(txd, 0, &word);
+	rt2x00_set_field32(&word, TXD_W0_BURST,
+			   test_bit(ENTRY_TXD_BURST, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_VALID, 1);
+	rt2x00_set_field32(&word, TXD_W0_MORE_FRAG,
+			   test_bit(ENTRY_TXD_MORE_FRAG, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_ACK,
+			   !(control->flags & IEEE80211_TXCTL_NO_ACK));
+	rt2x00_set_field32(&word, TXD_W0_TIMESTAMP,
+			   test_bit(ENTRY_TXD_REQ_TIMESTAMP, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_OFDM,
+			   test_bit(ENTRY_TXD_OFDM_RATE, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_IFS, desc->ifs);
+	rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
+			   !!(control->flags &
+			      IEEE80211_TXCTL_LONG_RETRY_LIMIT));
+	rt2x00_set_field32(&word, TXD_W0_TKIP_MIC, 0);
+	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, length);
+	rt2x00_set_field32(&word, TXD_W0_BURST2,
+			   test_bit(ENTRY_TXD_BURST, &desc->flags));
+	rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
+	rt2x00_desc_write(txd, 0, word);
+}
+
+static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev,
+				   int maxpacket, struct sk_buff *skb)
+{
+	int length;
+
+	/*
+	 * The length _must_ be a multiple of 4,
+	 * but it must _not_ be a multiple of the USB packet size.
+	 */
+	length = roundup(skb->len, 4);
+	length += (4 * !(length % maxpacket));
+
+	return length;
+}
+
+/*
+ * TX data initialization
+ */
+static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
+				  unsigned int queue)
+{
+	u32 reg;
+
+	if (queue != IEEE80211_TX_QUEUE_BEACON)
+		return;
+
+	/*
+	 * For Wi-Fi faily generated beacons between participating stations.
+	 * Set TBTT phase adaptive adjustment step to 8us (default 16us)
+	 */
+	rt73usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008);
+
+	rt73usb_register_read(rt2x00dev, TXRX_CSR9, &reg);
+	if (!rt2x00_get_field32(reg, TXRX_CSR9_BEACON_GEN)) {
+		rt2x00_set_field32(&reg, TXRX_CSR9_BEACON_GEN, 1);
+		rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg);
+	}
+}
+
+/*
+ * RX control handlers
+ */
+static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
+{
+	u16 eeprom;
+	u8 offset;
+	u8 lna;
+
+	lna = rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_LNA);
+	switch (lna) {
+	case 3:
+		offset = 90;
+		break;
+	case 2:
+		offset = 74;
+		break;
+	case 1:
+		offset = 64;
+		break;
+	default:
+		return 0;
+	}
+
+	if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) {
+		if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
+			if (lna == 3 || lna == 2)
+				offset += 10;
+		} else {
+			if (lna == 3)
+				offset += 6;
+			else if (lna == 2)
+				offset += 8;
+		}
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
+		offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1);
+	} else {
+		if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+			offset += 14;
+
+		rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
+		offset -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
+	}
+
+	return rt2x00_get_field32(rxd_w1, RXD_W1_RSSI_AGC) * 2 - offset;
+}
+
+static void rt73usb_fill_rxdone(struct data_entry *entry,
+			        struct rxdata_entry_desc *desc)
+{
+	struct data_desc *rxd = (struct data_desc *)entry->skb->data;
+	u32 word0;
+	u32 word1;
+
+	rt2x00_desc_read(rxd, 0, &word0);
+	rt2x00_desc_read(rxd, 1, &word1);
+
+	desc->flags = 0;
+	if (rt2x00_get_field32(word0, RXD_W0_CRC_ERROR))
+		desc->flags |= RX_FLAG_FAILED_FCS_CRC;
+
+	/*
+	 * Obtain the status about this packet.
+	 */
+	desc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL);
+	desc->rssi = rt73usb_agc_to_rssi(entry->ring->rt2x00dev, word1);
+	desc->ofdm = rt2x00_get_field32(word0, RXD_W0_OFDM);
+	desc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT);
+
+	/*
+	 * Pull the skb to clear the descriptor area.
+	 */
+	skb_pull(entry->skb, entry->ring->desc_size);
+
+	return;
+}
+
+/*
+ * Device probe functions.
+ */
+static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+	u16 word;
+	u8 *mac;
+	s8 value;
+
+	rt2x00usb_eeprom_read(rt2x00dev, rt2x00dev->eeprom, EEPROM_SIZE);
+
+	/*
+	 * Start validation of the data that has been read.
+	 */
+	mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
+	if (!is_valid_ether_addr(mac)) {
+		DECLARE_MAC_BUF(macbuf);
+
+		random_ether_addr(mac);
+		EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_NUM, 2);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_TX_DEFAULT, 2);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_RX_DEFAULT, 2);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_FRAME_TYPE, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_DYN_TXAGC, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_HARDWARE_RADIO, 0);
+		rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF5226);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
+		EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_NIC_EXTERNAL_LNA, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_NIC, word);
+		EEPROM(rt2x00dev, "NIC: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_LED_POLARITY_RDY_G, 0);
+		rt2x00_set_field16(&word, EEPROM_LED_POLARITY_RDY_A, 0);
+		rt2x00_set_field16(&word, EEPROM_LED_POLARITY_ACT, 0);
+		rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_0, 0);
+		rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_1, 0);
+		rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_2, 0);
+		rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_3, 0);
+		rt2x00_set_field16(&word, EEPROM_LED_POLARITY_GPIO_4, 0);
+		rt2x00_set_field16(&word, EEPROM_LED_LED_MODE,
+				   LED_MODE_DEFAULT);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_LED, word);
+		EEPROM(rt2x00dev, "Led: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_FREQ_OFFSET, 0);
+		rt2x00_set_field16(&word, EEPROM_FREQ_SEQ, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_FREQ, word);
+		EEPROM(rt2x00dev, "Freq: 0x%04x\n", word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+		EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+	} else {
+		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_1);
+		if (value < -10 || value > 10)
+			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_1, 0);
+		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_BG_2);
+		if (value < -10 || value > 10)
+			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_BG_2, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_BG, word);
+	}
+
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &word);
+	if (word == 0xffff) {
+		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+		rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+		EEPROM(rt2x00dev, "RSSI OFFSET BG: 0x%04x\n", word);
+	} else {
+		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_1);
+		if (value < -10 || value > 10)
+			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_1, 0);
+		value = rt2x00_get_field16(word, EEPROM_RSSI_OFFSET_A_2);
+		if (value < -10 || value > 10)
+			rt2x00_set_field16(&word, EEPROM_RSSI_OFFSET_A_2, 0);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_RSSI_OFFSET_A, word);
+	}
+
+	return 0;
+}
+
+static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
+{
+	u32 reg;
+	u16 value;
+	u16 eeprom;
+
+	/*
+	 * Read EEPROM word for configuration.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &eeprom);
+
+	/*
+	 * Identify RF chipset.
+	 */
+	value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE);
+	rt73usb_register_read(rt2x00dev, MAC_CSR0, &reg);
+	rt2x00_set_chip(rt2x00dev, RT2571, value, reg);
+
+	if (!rt2x00_rev(&rt2x00dev->chip, 0x25730)) {
+		ERROR(rt2x00dev, "Invalid RT chipset detected.\n");
+		return -ENODEV;
+	}
+
+	if (!rt2x00_rf(&rt2x00dev->chip, RF5226) &&
+	    !rt2x00_rf(&rt2x00dev->chip, RF2528) &&
+	    !rt2x00_rf(&rt2x00dev->chip, RF5225) &&
+	    !rt2x00_rf(&rt2x00dev->chip, RF2527)) {
+		ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Identify default antenna configuration.
+	 */
+	rt2x00dev->hw->conf.antenna_sel_tx =
+	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TX_DEFAULT);
+	rt2x00dev->hw->conf.antenna_sel_rx =
+	    rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_DEFAULT);
+
+	/*
+	 * Read the Frame type.
+	 */
+	if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE))
+		__set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags);
+
+	/*
+	 * Read frequency offset.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
+	rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
+
+	/*
+	 * Read external LNA informations.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
+
+	if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA)) {
+		__set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+		__set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+	}
+
+	/*
+	 * Store led settings, for correct led behaviour.
+	 */
+	rt2x00_eeprom_read(rt2x00dev, EEPROM_LED, &eeprom);
+
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LED_MODE,
+			   rt2x00dev->led_mode);
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_0,
+			   rt2x00_get_field16(eeprom,
+					      EEPROM_LED_POLARITY_GPIO_0));
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_1,
+			   rt2x00_get_field16(eeprom,
+					      EEPROM_LED_POLARITY_GPIO_1));
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_2,
+			   rt2x00_get_field16(eeprom,
+					      EEPROM_LED_POLARITY_GPIO_2));
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_3,
+			   rt2x00_get_field16(eeprom,
+					      EEPROM_LED_POLARITY_GPIO_3));
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_GPIO_4,
+			   rt2x00_get_field16(eeprom,
+					      EEPROM_LED_POLARITY_GPIO_4));
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_ACT,
+			   rt2x00_get_field16(eeprom, EEPROM_LED_POLARITY_ACT));
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_BG,
+			   rt2x00_get_field16(eeprom,
+					      EEPROM_LED_POLARITY_RDY_G));
+	rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_POLARITY_READY_A,
+			   rt2x00_get_field16(eeprom,
+					      EEPROM_LED_POLARITY_RDY_A));
+
+	return 0;
+}
+
+/*
+ * RF value list for RF2528
+ * Supports: 2.4 GHz
+ */
+static const struct rf_channel rf_vals_bg_2528[] = {
+	{ 1,  0x00002c0c, 0x00000786, 0x00068255, 0x000fea0b },
+	{ 2,  0x00002c0c, 0x00000786, 0x00068255, 0x000fea1f },
+	{ 3,  0x00002c0c, 0x0000078a, 0x00068255, 0x000fea0b },
+	{ 4,  0x00002c0c, 0x0000078a, 0x00068255, 0x000fea1f },
+	{ 5,  0x00002c0c, 0x0000078e, 0x00068255, 0x000fea0b },
+	{ 6,  0x00002c0c, 0x0000078e, 0x00068255, 0x000fea1f },
+	{ 7,  0x00002c0c, 0x00000792, 0x00068255, 0x000fea0b },
+	{ 8,  0x00002c0c, 0x00000792, 0x00068255, 0x000fea1f },
+	{ 9,  0x00002c0c, 0x00000796, 0x00068255, 0x000fea0b },
+	{ 10, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea1f },
+	{ 11, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea0b },
+	{ 12, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea1f },
+	{ 13, 0x00002c0c, 0x0000079e, 0x00068255, 0x000fea0b },
+	{ 14, 0x00002c0c, 0x000007a2, 0x00068255, 0x000fea13 },
+};
+
+/*
+ * RF value list for RF5226
+ * Supports: 2.4 GHz & 5.2 GHz
+ */
+static const struct rf_channel rf_vals_5226[] = {
+	{ 1,  0x00002c0c, 0x00000786, 0x00068255, 0x000fea0b },
+	{ 2,  0x00002c0c, 0x00000786, 0x00068255, 0x000fea1f },
+	{ 3,  0x00002c0c, 0x0000078a, 0x00068255, 0x000fea0b },
+	{ 4,  0x00002c0c, 0x0000078a, 0x00068255, 0x000fea1f },
+	{ 5,  0x00002c0c, 0x0000078e, 0x00068255, 0x000fea0b },
+	{ 6,  0x00002c0c, 0x0000078e, 0x00068255, 0x000fea1f },
+	{ 7,  0x00002c0c, 0x00000792, 0x00068255, 0x000fea0b },
+	{ 8,  0x00002c0c, 0x00000792, 0x00068255, 0x000fea1f },
+	{ 9,  0x00002c0c, 0x00000796, 0x00068255, 0x000fea0b },
+	{ 10, 0x00002c0c, 0x00000796, 0x00068255, 0x000fea1f },
+	{ 11, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea0b },
+	{ 12, 0x00002c0c, 0x0000079a, 0x00068255, 0x000fea1f },
+	{ 13, 0x00002c0c, 0x0000079e, 0x00068255, 0x000fea0b },
+	{ 14, 0x00002c0c, 0x000007a2, 0x00068255, 0x000fea13 },
+
+	/* 802.11 UNI / HyperLan 2 */
+	{ 36, 0x00002c0c, 0x0000099a, 0x00098255, 0x000fea23 },
+	{ 40, 0x00002c0c, 0x000009a2, 0x00098255, 0x000fea03 },
+	{ 44, 0x00002c0c, 0x000009a6, 0x00098255, 0x000fea0b },
+	{ 48, 0x00002c0c, 0x000009aa, 0x00098255, 0x000fea13 },
+	{ 52, 0x00002c0c, 0x000009ae, 0x00098255, 0x000fea1b },
+	{ 56, 0x00002c0c, 0x000009b2, 0x00098255, 0x000fea23 },
+	{ 60, 0x00002c0c, 0x000009ba, 0x00098255, 0x000fea03 },
+	{ 64, 0x00002c0c, 0x000009be, 0x00098255, 0x000fea0b },
+
+	/* 802.11 HyperLan 2 */
+	{ 100, 0x00002c0c, 0x00000a2a, 0x000b8255, 0x000fea03 },
+	{ 104, 0x00002c0c, 0x00000a2e, 0x000b8255, 0x000fea0b },
+	{ 108, 0x00002c0c, 0x00000a32, 0x000b8255, 0x000fea13 },
+	{ 112, 0x00002c0c, 0x00000a36, 0x000b8255, 0x000fea1b },
+	{ 116, 0x00002c0c, 0x00000a3a, 0x000b8255, 0x000fea23 },
+	{ 120, 0x00002c0c, 0x00000a82, 0x000b8255, 0x000fea03 },
+	{ 124, 0x00002c0c, 0x00000a86, 0x000b8255, 0x000fea0b },
+	{ 128, 0x00002c0c, 0x00000a8a, 0x000b8255, 0x000fea13 },
+	{ 132, 0x00002c0c, 0x00000a8e, 0x000b8255, 0x000fea1b },
+	{ 136, 0x00002c0c, 0x00000a92, 0x000b8255, 0x000fea23 },
+
+	/* 802.11 UNII */
+	{ 140, 0x00002c0c, 0x00000a9a, 0x000b8255, 0x000fea03 },
+	{ 149, 0x00002c0c, 0x00000aa2, 0x000b8255, 0x000fea1f },
+	{ 153, 0x00002c0c, 0x00000aa6, 0x000b8255, 0x000fea27 },
+	{ 157, 0x00002c0c, 0x00000aae, 0x000b8255, 0x000fea07 },
+	{ 161, 0x00002c0c, 0x00000ab2, 0x000b8255, 0x000fea0f },
+	{ 165, 0x00002c0c, 0x00000ab6, 0x000b8255, 0x000fea17 },
+
+	/* MMAC(Japan)J52 ch 34,38,42,46 */
+	{ 34, 0x00002c0c, 0x0008099a, 0x000da255, 0x000d3a0b },
+	{ 38, 0x00002c0c, 0x0008099e, 0x000da255, 0x000d3a13 },
+	{ 42, 0x00002c0c, 0x000809a2, 0x000da255, 0x000d3a1b },
+	{ 46, 0x00002c0c, 0x000809a6, 0x000da255, 0x000d3a23 },
+};
+
+/*
+ * RF value list for RF5225 & RF2527
+ * Supports: 2.4 GHz & 5.2 GHz
+ */
+static const struct rf_channel rf_vals_5225_2527[] = {
+	{ 1,  0x00002ccc, 0x00004786, 0x00068455, 0x000ffa0b },
+	{ 2,  0x00002ccc, 0x00004786, 0x00068455, 0x000ffa1f },
+	{ 3,  0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa0b },
+	{ 4,  0x00002ccc, 0x0000478a, 0x00068455, 0x000ffa1f },
+	{ 5,  0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa0b },
+	{ 6,  0x00002ccc, 0x0000478e, 0x00068455, 0x000ffa1f },
+	{ 7,  0x00002ccc, 0x00004792, 0x00068455, 0x000ffa0b },
+	{ 8,  0x00002ccc, 0x00004792, 0x00068455, 0x000ffa1f },
+	{ 9,  0x00002ccc, 0x00004796, 0x00068455, 0x000ffa0b },
+	{ 10, 0x00002ccc, 0x00004796, 0x00068455, 0x000ffa1f },
+	{ 11, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa0b },
+	{ 12, 0x00002ccc, 0x0000479a, 0x00068455, 0x000ffa1f },
+	{ 13, 0x00002ccc, 0x0000479e, 0x00068455, 0x000ffa0b },
+	{ 14, 0x00002ccc, 0x000047a2, 0x00068455, 0x000ffa13 },
+
+	/* 802.11 UNI / HyperLan 2 */
+	{ 36, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa23 },
+	{ 40, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa03 },
+	{ 44, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa0b },
+	{ 48, 0x00002ccc, 0x000049aa, 0x0009be55, 0x000ffa13 },
+	{ 52, 0x00002ccc, 0x000049ae, 0x0009ae55, 0x000ffa1b },
+	{ 56, 0x00002ccc, 0x000049b2, 0x0009ae55, 0x000ffa23 },
+	{ 60, 0x00002ccc, 0x000049ba, 0x0009ae55, 0x000ffa03 },
+	{ 64, 0x00002ccc, 0x000049be, 0x0009ae55, 0x000ffa0b },
+
+	/* 802.11 HyperLan 2 */
+	{ 100, 0x00002ccc, 0x00004a2a, 0x000bae55, 0x000ffa03 },
+	{ 104, 0x00002ccc, 0x00004a2e, 0x000bae55, 0x000ffa0b },
+	{ 108, 0x00002ccc, 0x00004a32, 0x000bae55, 0x000ffa13 },
+	{ 112, 0x00002ccc, 0x00004a36, 0x000bae55, 0x000ffa1b },
+	{ 116, 0x00002ccc, 0x00004a3a, 0x000bbe55, 0x000ffa23 },
+	{ 120, 0x00002ccc, 0x00004a82, 0x000bbe55, 0x000ffa03 },
+	{ 124, 0x00002ccc, 0x00004a86, 0x000bbe55, 0x000ffa0b },
+	{ 128, 0x00002ccc, 0x00004a8a, 0x000bbe55, 0x000ffa13 },
+	{ 132, 0x00002ccc, 0x00004a8e, 0x000bbe55, 0x000ffa1b },
+	{ 136, 0x00002ccc, 0x00004a92, 0x000bbe55, 0x000ffa23 },
+
+	/* 802.11 UNII */
+	{ 140, 0x00002ccc, 0x00004a9a, 0x000bbe55, 0x000ffa03 },
+	{ 149, 0x00002ccc, 0x00004aa2, 0x000bbe55, 0x000ffa1f },
+	{ 153, 0x00002ccc, 0x00004aa6, 0x000bbe55, 0x000ffa27 },
+	{ 157, 0x00002ccc, 0x00004aae, 0x000bbe55, 0x000ffa07 },
+	{ 161, 0x00002ccc, 0x00004ab2, 0x000bbe55, 0x000ffa0f },
+	{ 165, 0x00002ccc, 0x00004ab6, 0x000bbe55, 0x000ffa17 },
+
+	/* MMAC(Japan)J52 ch 34,38,42,46 */
+	{ 34, 0x00002ccc, 0x0000499a, 0x0009be55, 0x000ffa0b },
+	{ 38, 0x00002ccc, 0x0000499e, 0x0009be55, 0x000ffa13 },
+	{ 42, 0x00002ccc, 0x000049a2, 0x0009be55, 0x000ffa1b },
+	{ 46, 0x00002ccc, 0x000049a6, 0x0009be55, 0x000ffa23 },
+};
+
+
+static void rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
+{
+	struct hw_mode_spec *spec = &rt2x00dev->spec;
+	u8 *txpower;
+	unsigned int i;
+
+	/*
+	 * Initialize all hw fields.
+	 */
+	rt2x00dev->hw->flags =
+	    IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE |
+	    IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
+	rt2x00dev->hw->extra_tx_headroom = TXD_DESC_SIZE;
+	rt2x00dev->hw->max_signal = MAX_SIGNAL;
+	rt2x00dev->hw->max_rssi = MAX_RX_SSI;
+	rt2x00dev->hw->queues = 5;
+
+	SET_IEEE80211_DEV(rt2x00dev->hw, &rt2x00dev_usb(rt2x00dev)->dev);
+	SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
+				rt2x00_eeprom_addr(rt2x00dev,
+						   EEPROM_MAC_ADDR_0));
+
+	/*
+	 * Convert tx_power array in eeprom.
+	 */
+	txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_G_START);
+	for (i = 0; i < 14; i++)
+		txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+	/*
+	 * Initialize hw_mode information.
+	 */
+	spec->num_modes = 2;
+	spec->num_rates = 12;
+	spec->tx_power_a = NULL;
+	spec->tx_power_bg = txpower;
+	spec->tx_power_default = DEFAULT_TXPOWER;
+
+	if (rt2x00_rf(&rt2x00dev->chip, RF2528)) {
+		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528);
+		spec->channels = rf_vals_bg_2528;
+	} else if (rt2x00_rf(&rt2x00dev->chip, RF5226)) {
+		spec->num_channels = ARRAY_SIZE(rf_vals_5226);
+		spec->channels = rf_vals_5226;
+	} else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) {
+		spec->num_channels = 14;
+		spec->channels = rf_vals_5225_2527;
+	} else if (rt2x00_rf(&rt2x00dev->chip, RF5225)) {
+		spec->num_channels = ARRAY_SIZE(rf_vals_5225_2527);
+		spec->channels = rf_vals_5225_2527;
+	}
+
+	if (rt2x00_rf(&rt2x00dev->chip, RF5225) ||
+	    rt2x00_rf(&rt2x00dev->chip, RF5226)) {
+		spec->num_modes = 3;
+
+		txpower = rt2x00_eeprom_addr(rt2x00dev, EEPROM_TXPOWER_A_START);
+		for (i = 0; i < 14; i++)
+			txpower[i] = TXPOWER_FROM_DEV(txpower[i]);
+
+		spec->tx_power_a = txpower;
+	}
+}
+
+static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
+{
+	int retval;
+
+	/*
+	 * Allocate eeprom data.
+	 */
+	retval = rt73usb_validate_eeprom(rt2x00dev);
+	if (retval)
+		return retval;
+
+	retval = rt73usb_init_eeprom(rt2x00dev);
+	if (retval)
+		return retval;
+
+	/*
+	 * Initialize hw specifications.
+	 */
+	rt73usb_probe_hw_mode(rt2x00dev);
+
+	/*
+	 * This device requires firmware
+	 */
+	__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
+
+	/*
+	 * Set the rssi offset.
+	 */
+	rt2x00dev->rssi_offset = DEFAULT_RSSI_OFFSET;
+
+	return 0;
+}
+
+/*
+ * IEEE80211 stack callback functions.
+ */
+static void rt73usb_configure_filter(struct ieee80211_hw *hw,
+				     unsigned int changed_flags,
+				     unsigned int *total_flags,
+				     int mc_count,
+				     struct dev_addr_list *mc_list)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	struct interface *intf = &rt2x00dev->interface;
+	u32 reg;
+
+	/*
+	 * Mask off any flags we are going to ignore from
+	 * the total_flags field.
+	 */
+	*total_flags &=
+	    FIF_ALLMULTI |
+	    FIF_FCSFAIL |
+	    FIF_PLCPFAIL |
+	    FIF_CONTROL |
+	    FIF_OTHER_BSS |
+	    FIF_PROMISC_IN_BSS;
+
+	/*
+	 * Apply some rules to the filters:
+	 * - Some filters imply different filters to be set.
+	 * - Some things we can't filter out at all.
+	 * - Some filters are set based on interface type.
+	 */
+	if (mc_count)
+		*total_flags |= FIF_ALLMULTI;
+	if (*total_flags & FIF_OTHER_BSS ||
+	    *total_flags & FIF_PROMISC_IN_BSS)
+		*total_flags |= FIF_PROMISC_IN_BSS | FIF_OTHER_BSS;
+	if (is_interface_type(intf, IEEE80211_IF_TYPE_AP))
+		*total_flags |= FIF_PROMISC_IN_BSS;
+
+	/*
+	 * Check if there is any work left for us.
+	 */
+	if (intf->filter == *total_flags)
+		return;
+	intf->filter = *total_flags;
+
+	/*
+	 * When in atomic context, reschedule and let rt2x00lib
+	 * call this function again.
+	 */
+	if (in_atomic()) {
+		queue_work(rt2x00dev->hw->workqueue, &rt2x00dev->filter_work);
+		return;
+	}
+
+	/*
+	 * Start configuration steps.
+	 * Note that the version error will always be dropped
+	 * and broadcast frames will always be accepted since
+	 * there is no filter for it at this time.
+	 */
+	rt73usb_register_read(rt2x00dev, TXRX_CSR0, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CRC,
+			   !(*total_flags & FIF_FCSFAIL));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_PHYSICAL,
+			   !(*total_flags & FIF_PLCPFAIL));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_CONTROL,
+			   !(*total_flags & FIF_CONTROL));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_NOT_TO_ME,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_TO_DS,
+			   !(*total_flags & FIF_PROMISC_IN_BSS));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_VERSION_ERROR, 1);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_MULTICAST,
+			   !(*total_flags & FIF_ALLMULTI));
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_BROADCAST, 0);
+	rt2x00_set_field32(&reg, TXRX_CSR0_DROP_ACK_CTS, 1);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg);
+}
+
+static int rt73usb_set_retry_limit(struct ieee80211_hw *hw,
+				   u32 short_retry, u32 long_retry)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	u32 reg;
+
+	rt73usb_register_read(rt2x00dev, TXRX_CSR4, &reg);
+	rt2x00_set_field32(&reg, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry);
+	rt2x00_set_field32(&reg, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg);
+
+	return 0;
+}
+
+#if 0
+/*
+ * Mac80211 demands get_tsf must be atomic.
+ * This is not possible for rt73usb since all register access
+ * functions require sleeping. Untill mac80211 no longer needs
+ * get_tsf to be atomic, this function should be disabled.
+ */
+static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	u64 tsf;
+	u32 reg;
+
+	rt73usb_register_read(rt2x00dev, TXRX_CSR13, &reg);
+	tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32;
+	rt73usb_register_read(rt2x00dev, TXRX_CSR12, &reg);
+	tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER);
+
+	return tsf;
+}
+#else
+#define rt73usb_get_tsf	NULL
+#endif
+
+static void rt73usb_reset_tsf(struct ieee80211_hw *hw)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+
+	rt73usb_register_write(rt2x00dev, TXRX_CSR12, 0);
+	rt73usb_register_write(rt2x00dev, TXRX_CSR13, 0);
+}
+
+static int rt73usb_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb,
+			  struct ieee80211_tx_control *control)
+{
+	struct rt2x00_dev *rt2x00dev = hw->priv;
+	int timeout;
+
+	/*
+	 * Just in case the ieee80211 doesn't set this,
+	 * but we need this queue set for the descriptor
+	 * initialization.
+	 */
+	control->queue = IEEE80211_TX_QUEUE_BEACON;
+
+	/*
+	 * First we create the beacon.
+	 */
+	skb_push(skb, TXD_DESC_SIZE);
+	memset(skb->data, 0, TXD_DESC_SIZE);
+
+	rt2x00lib_write_tx_desc(rt2x00dev, (struct data_desc *)skb->data,
+				(struct ieee80211_hdr *)(skb->data +
+							 TXD_DESC_SIZE),
+				skb->len - TXD_DESC_SIZE, control);
+
+	/*
+	 * Write entire beacon with descriptor to register,
+	 * and kick the beacon generator.
+	 */
+	timeout = REGISTER_TIMEOUT * (skb->len / sizeof(u32));
+	rt2x00usb_vendor_request(rt2x00dev, USB_MULTI_WRITE,
+				 USB_VENDOR_REQUEST_OUT,
+				 HW_BEACON_BASE0, 0x0000,
+				 skb->data, skb->len, timeout);
+	rt73usb_kick_tx_queue(rt2x00dev, IEEE80211_TX_QUEUE_BEACON);
+
+	return 0;
+}
+
+static const struct ieee80211_ops rt73usb_mac80211_ops = {
+	.tx			= rt2x00mac_tx,
+	.start			= rt2x00mac_start,
+	.stop			= rt2x00mac_stop,
+	.add_interface		= rt2x00mac_add_interface,
+	.remove_interface	= rt2x00mac_remove_interface,
+	.config			= rt2x00mac_config,
+	.config_interface	= rt2x00mac_config_interface,
+	.configure_filter	= rt73usb_configure_filter,
+	.get_stats		= rt2x00mac_get_stats,
+	.set_retry_limit	= rt73usb_set_retry_limit,
+	.erp_ie_changed		= rt2x00mac_erp_ie_changed,
+	.conf_tx		= rt2x00mac_conf_tx,
+	.get_tx_stats		= rt2x00mac_get_tx_stats,
+	.get_tsf		= rt73usb_get_tsf,
+	.reset_tsf		= rt73usb_reset_tsf,
+	.beacon_update		= rt73usb_beacon_update,
+};
+
+static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
+	.probe_hw		= rt73usb_probe_hw,
+	.get_firmware_name	= rt73usb_get_firmware_name,
+	.load_firmware		= rt73usb_load_firmware,
+	.initialize		= rt2x00usb_initialize,
+	.uninitialize		= rt2x00usb_uninitialize,
+	.set_device_state	= rt73usb_set_device_state,
+	.link_stats		= rt73usb_link_stats,
+	.reset_tuner		= rt73usb_reset_tuner,
+	.link_tuner		= rt73usb_link_tuner,
+	.write_tx_desc		= rt73usb_write_tx_desc,
+	.write_tx_data		= rt2x00usb_write_tx_data,
+	.get_tx_data_len	= rt73usb_get_tx_data_len,
+	.kick_tx_queue		= rt73usb_kick_tx_queue,
+	.fill_rxdone		= rt73usb_fill_rxdone,
+	.config_mac_addr	= rt73usb_config_mac_addr,
+	.config_bssid		= rt73usb_config_bssid,
+	.config_type		= rt73usb_config_type,
+	.config_preamble	= rt73usb_config_preamble,
+	.config			= rt73usb_config,
+};
+
+static const struct rt2x00_ops rt73usb_ops = {
+	.name		= DRV_NAME,
+	.rxd_size	= RXD_DESC_SIZE,
+	.txd_size	= TXD_DESC_SIZE,
+	.eeprom_size	= EEPROM_SIZE,
+	.rf_size	= RF_SIZE,
+	.lib		= &rt73usb_rt2x00_ops,
+	.hw		= &rt73usb_mac80211_ops,
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+	.debugfs	= &rt73usb_rt2x00debug,
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+};
+
+/*
+ * rt73usb module information.
+ */
+static struct usb_device_id rt73usb_device_table[] = {
+	/* AboCom */
+	{ USB_DEVICE(0x07b8, 0xb21d), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* Askey */
+	{ USB_DEVICE(0x1690, 0x0722), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* ASUS */
+	{ USB_DEVICE(0x0b05, 0x1723), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x0b05, 0x1724), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* Belkin */
+	{ USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x050d, 0x905b), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* Billionton */
+	{ USB_DEVICE(0x1631, 0xc019), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* Buffalo */
+	{ USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* CNet */
+	{ USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x1371, 0x9032), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* Conceptronic */
+	{ USB_DEVICE(0x14b2, 0x3c22), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* D-Link */
+	{ USB_DEVICE(0x07d1, 0x3c03), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x07d1, 0x3c04), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* Gemtek */
+	{ USB_DEVICE(0x15a9, 0x0004), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* Gigabyte */
+	{ USB_DEVICE(0x1044, 0x8008), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x1044, 0x800a), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* Huawei-3Com */
+	{ USB_DEVICE(0x1472, 0x0009), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* Hercules */
+	{ USB_DEVICE(0x06f8, 0xe010), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x06f8, 0xe020), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* Linksys */
+	{ USB_DEVICE(0x13b1, 0x0020), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x13b1, 0x0023), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* MSI */
+	{ USB_DEVICE(0x0db0, 0x6877), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x0db0, 0x6874), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x0db0, 0xa861), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x0db0, 0xa874), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* Ralink */
+	{ USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* Qcom */
+	{ USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x18e8, 0x6229), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x18e8, 0x6238), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* Senao */
+	{ USB_DEVICE(0x1740, 0x7100), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* Sitecom */
+	{ USB_DEVICE(0x0df6, 0x9712), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x0df6, 0x90ac), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* Surecom */
+	{ USB_DEVICE(0x0769, 0x31f3), USB_DEVICE_DATA(&rt73usb_ops) },
+	/* Planex */
+	{ USB_DEVICE(0x2019, 0xab01), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ USB_DEVICE(0x2019, 0xab50), USB_DEVICE_DATA(&rt73usb_ops) },
+	{ 0, }
+};
+
+MODULE_AUTHOR(DRV_PROJECT);
+MODULE_VERSION(DRV_VERSION);
+MODULE_DESCRIPTION("Ralink RT73 USB Wireless LAN driver.");
+MODULE_SUPPORTED_DEVICE("Ralink RT2571W & RT2671 USB chipset based cards");
+MODULE_DEVICE_TABLE(usb, rt73usb_device_table);
+MODULE_FIRMWARE(FIRMWARE_RT2571);
+MODULE_LICENSE("GPL");
+
+static struct usb_driver rt73usb_driver = {
+	.name		= DRV_NAME,
+	.id_table	= rt73usb_device_table,
+	.probe		= rt2x00usb_probe,
+	.disconnect	= rt2x00usb_disconnect,
+	.suspend	= rt2x00usb_suspend,
+	.resume		= rt2x00usb_resume,
+};
+
+static int __init rt73usb_init(void)
+{
+	return usb_register(&rt73usb_driver);
+}
+
+static void __exit rt73usb_exit(void)
+{
+	usb_deregister(&rt73usb_driver);
+}
+
+module_init(rt73usb_init);
+module_exit(rt73usb_exit);
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
new file mode 100644
index 0000000..f095151
--- /dev/null
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -0,0 +1,1024 @@
+/*
+	Copyright (C) 2004 - 2007 rt2x00 SourceForge Project
+	<http://rt2x00.serialmonkey.com>
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License
+	along with this program; if not, write to the
+	Free Software Foundation, Inc.,
+	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+	Module: rt73usb
+	Abstract: Data structures and registers for the rt73usb module.
+	Supported chipsets: rt2571W & rt2671.
+ */
+
+#ifndef RT73USB_H
+#define RT73USB_H
+
+/*
+ * RF chip defines.
+ */
+#define RF5226				0x0001
+#define RF2528				0x0002
+#define RF5225				0x0003
+#define RF2527				0x0004
+
+/*
+ * Signal information.
+ * Defaul offset is required for RSSI <-> dBm conversion.
+ */
+#define MAX_SIGNAL			100
+#define MAX_RX_SSI			-1
+#define DEFAULT_RSSI_OFFSET		120
+
+/*
+ * Register layout information.
+ */
+#define CSR_REG_BASE			0x3000
+#define CSR_REG_SIZE			0x04b0
+#define EEPROM_BASE			0x0000
+#define EEPROM_SIZE			0x0100
+#define BBP_SIZE			0x0080
+#define RF_SIZE				0x0014
+
+/*
+ * USB registers.
+ */
+
+/*
+ * MCU_LEDCS: LED control for MCU Mailbox.
+ */
+#define MCU_LEDCS_LED_MODE		FIELD16(0x001f)
+#define MCU_LEDCS_RADIO_STATUS		FIELD16(0x0020)
+#define MCU_LEDCS_LINK_BG_STATUS	FIELD16(0x0040)
+#define MCU_LEDCS_LINK_A_STATUS		FIELD16(0x0080)
+#define MCU_LEDCS_POLARITY_GPIO_0	FIELD16(0x0100)
+#define MCU_LEDCS_POLARITY_GPIO_1	FIELD16(0x0200)
+#define MCU_LEDCS_POLARITY_GPIO_2	FIELD16(0x0400)
+#define MCU_LEDCS_POLARITY_GPIO_3	FIELD16(0x0800)
+#define MCU_LEDCS_POLARITY_GPIO_4	FIELD16(0x1000)
+#define MCU_LEDCS_POLARITY_ACT		FIELD16(0x2000)
+#define MCU_LEDCS_POLARITY_READY_BG	FIELD16(0x4000)
+#define MCU_LEDCS_POLARITY_READY_A	FIELD16(0x8000)
+
+/*
+ * 8051 firmware image.
+ */
+#define FIRMWARE_RT2571			"rt73.bin"
+#define FIRMWARE_IMAGE_BASE		0x0800
+
+/*
+ * Security key table memory.
+ * 16 entries 32-byte for shared key table
+ * 64 entries 32-byte for pairwise key table
+ * 64 entries 8-byte for pairwise ta key table
+ */
+#define SHARED_KEY_TABLE_BASE		0x1000
+#define PAIRWISE_KEY_TABLE_BASE		0x1200
+#define PAIRWISE_TA_TABLE_BASE		0x1a00
+
+struct hw_key_entry {
+	u8 key[16];
+	u8 tx_mic[8];
+	u8 rx_mic[8];
+} __attribute__ ((packed));
+
+struct hw_pairwise_ta_entry {
+	u8 address[6];
+	u8 reserved[2];
+} __attribute__ ((packed));
+
+/*
+ * Since NULL frame won't be that long (256 byte),
+ * We steal 16 tail bytes to save debugging settings.
+ */
+#define HW_DEBUG_SETTING_BASE		0x2bf0
+
+/*
+ * On-chip BEACON frame space.
+ */
+#define HW_BEACON_BASE0			0x2400
+#define HW_BEACON_BASE1			0x2500
+#define HW_BEACON_BASE2			0x2600
+#define HW_BEACON_BASE3			0x2700
+
+/*
+ * MAC Control/Status Registers(CSR).
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * MAC_CSR0: ASIC revision number.
+ */
+#define MAC_CSR0			0x3000
+
+/*
+ * MAC_CSR1: System control register.
+ * SOFT_RESET: Software reset bit, 1: reset, 0: normal.
+ * BBP_RESET: Hardware reset BBP.
+ * HOST_READY: Host is ready after initialization, 1: ready.
+ */
+#define MAC_CSR1			0x3004
+#define MAC_CSR1_SOFT_RESET		FIELD32(0x00000001)
+#define MAC_CSR1_BBP_RESET		FIELD32(0x00000002)
+#define MAC_CSR1_HOST_READY		FIELD32(0x00000004)
+
+/*
+ * MAC_CSR2: STA MAC register 0.
+ */
+#define MAC_CSR2			0x3008
+#define MAC_CSR2_BYTE0			FIELD32(0x000000ff)
+#define MAC_CSR2_BYTE1			FIELD32(0x0000ff00)
+#define MAC_CSR2_BYTE2			FIELD32(0x00ff0000)
+#define MAC_CSR2_BYTE3			FIELD32(0xff000000)
+
+/*
+ * MAC_CSR3: STA MAC register 1.
+ */
+#define MAC_CSR3			0x300c
+#define MAC_CSR3_BYTE4			FIELD32(0x000000ff)
+#define MAC_CSR3_BYTE5			FIELD32(0x0000ff00)
+#define MAC_CSR3_UNICAST_TO_ME_MASK	FIELD32(0x00ff0000)
+
+/*
+ * MAC_CSR4: BSSID register 0.
+ */
+#define MAC_CSR4			0x3010
+#define MAC_CSR4_BYTE0			FIELD32(0x000000ff)
+#define MAC_CSR4_BYTE1			FIELD32(0x0000ff00)
+#define MAC_CSR4_BYTE2			FIELD32(0x00ff0000)
+#define MAC_CSR4_BYTE3			FIELD32(0xff000000)
+
+/*
+ * MAC_CSR5: BSSID register 1.
+ * BSS_ID_MASK: 3: one BSSID, 0: 4 BSSID, 2 or 1: 2 BSSID.
+ */
+#define MAC_CSR5			0x3014
+#define MAC_CSR5_BYTE4			FIELD32(0x000000ff)
+#define MAC_CSR5_BYTE5			FIELD32(0x0000ff00)
+#define MAC_CSR5_BSS_ID_MASK		FIELD32(0x00ff0000)
+
+/*
+ * MAC_CSR6: Maximum frame length register.
+ */
+#define MAC_CSR6			0x3018
+#define MAC_CSR6_MAX_FRAME_UNIT		FIELD32(0x00000fff)
+
+/*
+ * MAC_CSR7: Reserved
+ */
+#define MAC_CSR7			0x301c
+
+/*
+ * MAC_CSR8: SIFS/EIFS register.
+ * All units are in US.
+ */
+#define MAC_CSR8			0x3020
+#define MAC_CSR8_SIFS			FIELD32(0x000000ff)
+#define MAC_CSR8_SIFS_AFTER_RX_OFDM	FIELD32(0x0000ff00)
+#define MAC_CSR8_EIFS			FIELD32(0xffff0000)
+
+/*
+ * MAC_CSR9: Back-Off control register.
+ * SLOT_TIME: Slot time, default is 20us for 802.11BG.
+ * CWMIN: Bit for Cwmin. default Cwmin is 31 (2^5 - 1).
+ * CWMAX: Bit for Cwmax, default Cwmax is 1023 (2^10 - 1).
+ * CW_SELECT: 1: CWmin/Cwmax select from register, 0:select from TxD.
+ */
+#define MAC_CSR9			0x3024
+#define MAC_CSR9_SLOT_TIME		FIELD32(0x000000ff)
+#define MAC_CSR9_CWMIN			FIELD32(0x00000f00)
+#define MAC_CSR9_CWMAX			FIELD32(0x0000f000)
+#define MAC_CSR9_CW_SELECT		FIELD32(0x00010000)
+
+/*
+ * MAC_CSR10: Power state configuration.
+ */
+#define MAC_CSR10			0x3028
+
+/*
+ * MAC_CSR11: Power saving transition time register.
+ * DELAY_AFTER_TBCN: Delay after Tbcn expired in units of TU.
+ * TBCN_BEFORE_WAKEUP: Number of beacon before wakeup.
+ * WAKEUP_LATENCY: In unit of TU.
+ */
+#define MAC_CSR11			0x302c
+#define MAC_CSR11_DELAY_AFTER_TBCN	FIELD32(0x000000ff)
+#define MAC_CSR11_TBCN_BEFORE_WAKEUP	FIELD32(0x00007f00)
+#define MAC_CSR11_AUTOWAKE		FIELD32(0x00008000)
+#define MAC_CSR11_WAKEUP_LATENCY	FIELD32(0x000f0000)
+
+/*
+ * MAC_CSR12: Manual power control / status register (merge CSR20 & PWRCSR1).
+ * CURRENT_STATE: 0:sleep, 1:awake.
+ * FORCE_WAKEUP: This has higher priority than PUT_TO_SLEEP.
+ * BBP_CURRENT_STATE: 0: BBP sleep, 1: BBP awake.
+ */
+#define MAC_CSR12			0x3030
+#define MAC_CSR12_CURRENT_STATE		FIELD32(0x00000001)
+#define MAC_CSR12_PUT_TO_SLEEP		FIELD32(0x00000002)
+#define MAC_CSR12_FORCE_WAKEUP		FIELD32(0x00000004)
+#define MAC_CSR12_BBP_CURRENT_STATE	FIELD32(0x00000008)
+
+/*
+ * MAC_CSR13: GPIO.
+ */
+#define MAC_CSR13			0x3034
+
+/*
+ * MAC_CSR14: LED control register.
+ * ON_PERIOD: On period, default 70ms.
+ * OFF_PERIOD: Off period, default 30ms.
+ * HW_LED: HW TX activity, 1: normal OFF, 0: normal ON.
+ * SW_LED: s/w LED, 1: ON, 0: OFF.
+ * HW_LED_POLARITY: 0: active low, 1: active high.
+ */
+#define MAC_CSR14			0x3038
+#define MAC_CSR14_ON_PERIOD		FIELD32(0x000000ff)
+#define MAC_CSR14_OFF_PERIOD		FIELD32(0x0000ff00)
+#define MAC_CSR14_HW_LED		FIELD32(0x00010000)
+#define MAC_CSR14_SW_LED		FIELD32(0x00020000)
+#define MAC_CSR14_HW_LED_POLARITY	FIELD32(0x00040000)
+#define MAC_CSR14_SW_LED2		FIELD32(0x00080000)
+
+/*
+ * MAC_CSR15: NAV control.
+ */
+#define MAC_CSR15			0x303c
+
+/*
+ * TXRX control registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * TXRX_CSR0: TX/RX configuration register.
+ * TSF_OFFSET: Default is 24.
+ * AUTO_TX_SEQ: 1: ASIC auto replace sequence nr in outgoing frame.
+ * DISABLE_RX: Disable Rx engine.
+ * DROP_CRC: Drop CRC error.
+ * DROP_PHYSICAL: Drop physical error.
+ * DROP_CONTROL: Drop control frame.
+ * DROP_NOT_TO_ME: Drop not to me unicast frame.
+ * DROP_TO_DS: Drop fram ToDs bit is true.
+ * DROP_VERSION_ERROR: Drop version error frame.
+ * DROP_MULTICAST: Drop multicast frames.
+ * DROP_BORADCAST: Drop broadcast frames.
+ * ROP_ACK_CTS: Drop received ACK and CTS.
+ */
+#define TXRX_CSR0			0x3040
+#define TXRX_CSR0_RX_ACK_TIMEOUT	FIELD32(0x000001ff)
+#define TXRX_CSR0_TSF_OFFSET		FIELD32(0x00007e00)
+#define TXRX_CSR0_AUTO_TX_SEQ		FIELD32(0x00008000)
+#define TXRX_CSR0_DISABLE_RX		FIELD32(0x00010000)
+#define TXRX_CSR0_DROP_CRC		FIELD32(0x00020000)
+#define TXRX_CSR0_DROP_PHYSICAL		FIELD32(0x00040000)
+#define TXRX_CSR0_DROP_CONTROL		FIELD32(0x00080000)
+#define TXRX_CSR0_DROP_NOT_TO_ME	FIELD32(0x00100000)
+#define TXRX_CSR0_DROP_TO_DS		FIELD32(0x00200000)
+#define TXRX_CSR0_DROP_VERSION_ERROR	FIELD32(0x00400000)
+#define TXRX_CSR0_DROP_MULTICAST	FIELD32(0x00800000)
+#define TXRX_CSR0_DROP_BROADCAST	FIELD32(0x01000000)
+#define TXRX_CSR0_DROP_ACK_CTS		FIELD32(0x02000000)
+#define TXRX_CSR0_TX_WITHOUT_WAITING	FIELD32(0x04000000)
+
+/*
+ * TXRX_CSR1
+ */
+#define TXRX_CSR1			0x3044
+#define TXRX_CSR1_BBP_ID0		FIELD32(0x0000007f)
+#define TXRX_CSR1_BBP_ID0_VALID		FIELD32(0x00000080)
+#define TXRX_CSR1_BBP_ID1		FIELD32(0x00007f00)
+#define TXRX_CSR1_BBP_ID1_VALID		FIELD32(0x00008000)
+#define TXRX_CSR1_BBP_ID2		FIELD32(0x007f0000)
+#define TXRX_CSR1_BBP_ID2_VALID		FIELD32(0x00800000)
+#define TXRX_CSR1_BBP_ID3		FIELD32(0x7f000000)
+#define TXRX_CSR1_BBP_ID3_VALID		FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR2
+ */
+#define TXRX_CSR2			0x3048
+#define TXRX_CSR2_BBP_ID0		FIELD32(0x0000007f)
+#define TXRX_CSR2_BBP_ID0_VALID		FIELD32(0x00000080)
+#define TXRX_CSR2_BBP_ID1		FIELD32(0x00007f00)
+#define TXRX_CSR2_BBP_ID1_VALID		FIELD32(0x00008000)
+#define TXRX_CSR2_BBP_ID2		FIELD32(0x007f0000)
+#define TXRX_CSR2_BBP_ID2_VALID		FIELD32(0x00800000)
+#define TXRX_CSR2_BBP_ID3		FIELD32(0x7f000000)
+#define TXRX_CSR2_BBP_ID3_VALID		FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR3
+ */
+#define TXRX_CSR3			0x304c
+#define TXRX_CSR3_BBP_ID0		FIELD32(0x0000007f)
+#define TXRX_CSR3_BBP_ID0_VALID		FIELD32(0x00000080)
+#define TXRX_CSR3_BBP_ID1		FIELD32(0x00007f00)
+#define TXRX_CSR3_BBP_ID1_VALID		FIELD32(0x00008000)
+#define TXRX_CSR3_BBP_ID2		FIELD32(0x007f0000)
+#define TXRX_CSR3_BBP_ID2_VALID		FIELD32(0x00800000)
+#define TXRX_CSR3_BBP_ID3		FIELD32(0x7f000000)
+#define TXRX_CSR3_BBP_ID3_VALID		FIELD32(0x80000000)
+
+/*
+ * TXRX_CSR4: Auto-Responder/Tx-retry register.
+ * AUTORESPOND_PREAMBLE: 0:long, 1:short preamble.
+ * OFDM_TX_RATE_DOWN: 1:enable.
+ * OFDM_TX_RATE_STEP: 0:1-step, 1: 2-step, 2:3-step, 3:4-step.
+ * OFDM_TX_FALLBACK_CCK: 0: Fallback to OFDM 6M only, 1: Fallback to CCK 1M,2M.
+ */
+#define TXRX_CSR4			0x3050
+#define TXRX_CSR4_TX_ACK_TIMEOUT	FIELD32(0x000000ff)
+#define TXRX_CSR4_CNTL_ACK_POLICY	FIELD32(0x00000700)
+#define TXRX_CSR4_ACK_CTS_PSM		FIELD32(0x00010000)
+#define TXRX_CSR4_AUTORESPOND_ENABLE	FIELD32(0x00020000)
+#define TXRX_CSR4_AUTORESPOND_PREAMBLE	FIELD32(0x00040000)
+#define TXRX_CSR4_OFDM_TX_RATE_DOWN	FIELD32(0x00080000)
+#define TXRX_CSR4_OFDM_TX_RATE_STEP	FIELD32(0x00300000)
+#define TXRX_CSR4_OFDM_TX_FALLBACK_CCK	FIELD32(0x00400000)
+#define TXRX_CSR4_LONG_RETRY_LIMIT	FIELD32(0x0f000000)
+#define TXRX_CSR4_SHORT_RETRY_LIMIT	FIELD32(0xf0000000)
+
+/*
+ * TXRX_CSR5
+ */
+#define TXRX_CSR5			0x3054
+
+/*
+ * TXRX_CSR6: ACK/CTS payload consumed time
+ */
+#define TXRX_CSR6			0x3058
+
+/*
+ * TXRX_CSR7: OFDM ACK/CTS payload consumed time for 6/9/12/18 mbps.
+ */
+#define TXRX_CSR7			0x305c
+#define TXRX_CSR7_ACK_CTS_6MBS		FIELD32(0x000000ff)
+#define TXRX_CSR7_ACK_CTS_9MBS		FIELD32(0x0000ff00)
+#define TXRX_CSR7_ACK_CTS_12MBS		FIELD32(0x00ff0000)
+#define TXRX_CSR7_ACK_CTS_18MBS		FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR8: OFDM ACK/CTS payload consumed time for 24/36/48/54 mbps.
+ */
+#define TXRX_CSR8			0x3060
+#define TXRX_CSR8_ACK_CTS_24MBS		FIELD32(0x000000ff)
+#define TXRX_CSR8_ACK_CTS_36MBS		FIELD32(0x0000ff00)
+#define TXRX_CSR8_ACK_CTS_48MBS		FIELD32(0x00ff0000)
+#define TXRX_CSR8_ACK_CTS_54MBS		FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR9: Synchronization control register.
+ * BEACON_INTERVAL: In unit of 1/16 TU.
+ * TSF_TICKING: Enable TSF auto counting.
+ * TSF_SYNC: Tsf sync, 0: disable, 1: infra, 2: ad-hoc/master mode.
+ * BEACON_GEN: Enable beacon generator.
+ */
+#define TXRX_CSR9			0x3064
+#define TXRX_CSR9_BEACON_INTERVAL	FIELD32(0x0000ffff)
+#define TXRX_CSR9_TSF_TICKING		FIELD32(0x00010000)
+#define TXRX_CSR9_TSF_SYNC		FIELD32(0x00060000)
+#define TXRX_CSR9_TBTT_ENABLE		FIELD32(0x00080000)
+#define TXRX_CSR9_BEACON_GEN		FIELD32(0x00100000)
+#define TXRX_CSR9_TIMESTAMP_COMPENSATE	FIELD32(0xff000000)
+
+/*
+ * TXRX_CSR10: BEACON alignment.
+ */
+#define TXRX_CSR10			0x3068
+
+/*
+ * TXRX_CSR11: AES mask.
+ */
+#define TXRX_CSR11			0x306c
+
+/*
+ * TXRX_CSR12: TSF low 32.
+ */
+#define TXRX_CSR12			0x3070
+#define TXRX_CSR12_LOW_TSFTIMER		FIELD32(0xffffffff)
+
+/*
+ * TXRX_CSR13: TSF high 32.
+ */
+#define TXRX_CSR13			0x3074
+#define TXRX_CSR13_HIGH_TSFTIMER	FIELD32(0xffffffff)
+
+/*
+ * TXRX_CSR14: TBTT timer.
+ */
+#define TXRX_CSR14			0x3078
+
+/*
+ * TXRX_CSR15: TKIP MIC priority byte "AND" mask.
+ */
+#define TXRX_CSR15			0x307c
+
+/*
+ * PHY control registers.
+ * Some values are set in TU, whereas 1 TU == 1024 us.
+ */
+
+/*
+ * PHY_CSR0: RF/PS control.
+ */
+#define PHY_CSR0			0x3080
+#define PHY_CSR0_PA_PE_BG		FIELD32(0x00010000)
+#define PHY_CSR0_PA_PE_A		FIELD32(0x00020000)
+
+/*
+ * PHY_CSR1
+ */
+#define PHY_CSR1			0x3084
+#define PHY_CSR1_RF_RPI			FIELD32(0x00010000)
+
+/*
+ * PHY_CSR2: Pre-TX BBP control.
+ */
+#define PHY_CSR2			0x3088
+
+/*
+ * PHY_CSR3: BBP serial control register.
+ * VALUE: Register value to program into BBP.
+ * REG_NUM: Selected BBP register.
+ * READ_CONTROL: 0: Write BBP, 1: Read BBP.
+ * BUSY: 1: ASIC is busy execute BBP programming.
+ */
+#define PHY_CSR3			0x308c
+#define PHY_CSR3_VALUE			FIELD32(0x000000ff)
+#define PHY_CSR3_REGNUM			FIELD32(0x00007f00)
+#define PHY_CSR3_READ_CONTROL		FIELD32(0x00008000)
+#define PHY_CSR3_BUSY			FIELD32(0x00010000)
+
+/*
+ * PHY_CSR4: RF serial control register
+ * VALUE: Register value (include register id) serial out to RF/IF chip.
+ * NUMBER_OF_BITS: Number of bits used in RFRegValue (I:20, RFMD:22).
+ * IF_SELECT: 1: select IF to program, 0: select RF to program.
+ * PLL_LD: RF PLL_LD status.
+ * BUSY: 1: ASIC is busy execute RF programming.
+ */
+#define PHY_CSR4			0x3090
+#define PHY_CSR4_VALUE			FIELD32(0x00ffffff)
+#define PHY_CSR4_NUMBER_OF_BITS		FIELD32(0x1f000000)
+#define PHY_CSR4_IF_SELECT		FIELD32(0x20000000)
+#define PHY_CSR4_PLL_LD			FIELD32(0x40000000)
+#define PHY_CSR4_BUSY			FIELD32(0x80000000)
+
+/*
+ * PHY_CSR5: RX to TX signal switch timing control.
+ */
+#define PHY_CSR5			0x3094
+#define PHY_CSR5_IQ_FLIP		FIELD32(0x00000004)
+
+/*
+ * PHY_CSR6: TX to RX signal timing control.
+ */
+#define PHY_CSR6			0x3098
+#define PHY_CSR6_IQ_FLIP		FIELD32(0x00000004)
+
+/*
+ * PHY_CSR7: TX DAC switching timing control.
+ */
+#define PHY_CSR7			0x309c
+
+/*
+ * Security control register.
+ */
+
+/*
+ * SEC_CSR0: Shared key table control.
+ */
+#define SEC_CSR0			0x30a0
+#define SEC_CSR0_BSS0_KEY0_VALID	FIELD32(0x00000001)
+#define SEC_CSR0_BSS0_KEY1_VALID	FIELD32(0x00000002)
+#define SEC_CSR0_BSS0_KEY2_VALID	FIELD32(0x00000004)
+#define SEC_CSR0_BSS0_KEY3_VALID	FIELD32(0x00000008)
+#define SEC_CSR0_BSS1_KEY0_VALID	FIELD32(0x00000010)
+#define SEC_CSR0_BSS1_KEY1_VALID	FIELD32(0x00000020)
+#define SEC_CSR0_BSS1_KEY2_VALID	FIELD32(0x00000040)
+#define SEC_CSR0_BSS1_KEY3_VALID	FIELD32(0x00000080)
+#define SEC_CSR0_BSS2_KEY0_VALID	FIELD32(0x00000100)
+#define SEC_CSR0_BSS2_KEY1_VALID	FIELD32(0x00000200)
+#define SEC_CSR0_BSS2_KEY2_VALID	FIELD32(0x00000400)
+#define SEC_CSR0_BSS2_KEY3_VALID	FIELD32(0x00000800)
+#define SEC_CSR0_BSS3_KEY0_VALID	FIELD32(0x00001000)
+#define SEC_CSR0_BSS3_KEY1_VALID	FIELD32(0x00002000)
+#define SEC_CSR0_BSS3_KEY2_VALID	FIELD32(0x00004000)
+#define SEC_CSR0_BSS3_KEY3_VALID	FIELD32(0x00008000)
+
+/*
+ * SEC_CSR1: Shared key table security mode register.
+ */
+#define SEC_CSR1			0x30a4
+#define SEC_CSR1_BSS0_KEY0_CIPHER_ALG	FIELD32(0x00000007)
+#define SEC_CSR1_BSS0_KEY1_CIPHER_ALG	FIELD32(0x00000070)
+#define SEC_CSR1_BSS0_KEY2_CIPHER_ALG	FIELD32(0x00000700)
+#define SEC_CSR1_BSS0_KEY3_CIPHER_ALG	FIELD32(0x00007000)
+#define SEC_CSR1_BSS1_KEY0_CIPHER_ALG	FIELD32(0x00070000)
+#define SEC_CSR1_BSS1_KEY1_CIPHER_ALG	FIELD32(0x00700000)
+#define SEC_CSR1_BSS1_KEY2_CIPHER_ALG	FIELD32(0x07000000)
+#define SEC_CSR1_BSS1_KEY3_CIPHER_ALG	FIELD32(0x70000000)
+
+/*
+ * Pairwise key table valid bitmap registers.
+ * SEC_CSR2: pairwise key table valid bitmap 0.
+ * SEC_CSR3: pairwise key table valid bitmap 1.
+ */
+#define SEC_CSR2			0x30a8
+#define SEC_CSR3			0x30ac
+
+/*
+ * SEC_CSR4: Pairwise key table lookup control.
+ */
+#define SEC_CSR4			0x30b0
+
+/*
+ * SEC_CSR5: shared key table security mode register.
+ */
+#define SEC_CSR5			0x30b4
+#define SEC_CSR5_BSS2_KEY0_CIPHER_ALG	FIELD32(0x00000007)
+#define SEC_CSR5_BSS2_KEY1_CIPHER_ALG	FIELD32(0x00000070)
+#define SEC_CSR5_BSS2_KEY2_CIPHER_ALG	FIELD32(0x00000700)
+#define SEC_CSR5_BSS2_KEY3_CIPHER_ALG	FIELD32(0x00007000)
+#define SEC_CSR5_BSS3_KEY0_CIPHER_ALG	FIELD32(0x00070000)
+#define SEC_CSR5_BSS3_KEY1_CIPHER_ALG	FIELD32(0x00700000)
+#define SEC_CSR5_BSS3_KEY2_CIPHER_ALG	FIELD32(0x07000000)
+#define SEC_CSR5_BSS3_KEY3_CIPHER_ALG	FIELD32(0x70000000)
+
+/*
+ * STA control registers.
+ */
+
+/*
+ * STA_CSR0: RX PLCP error count & RX FCS error count.
+ */
+#define STA_CSR0			0x30c0
+#define STA_CSR0_FCS_ERROR		FIELD32(0x0000ffff)
+#define STA_CSR0_PLCP_ERROR		FIELD32(0xffff0000)
+
+/*
+ * STA_CSR1: RX False CCA count & RX LONG frame count.
+ */
+#define STA_CSR1			0x30c4
+#define STA_CSR1_PHYSICAL_ERROR		FIELD32(0x0000ffff)
+#define STA_CSR1_FALSE_CCA_ERROR	FIELD32(0xffff0000)
+
+/*
+ * STA_CSR2: TX Beacon count and RX FIFO overflow count.
+ */
+#define STA_CSR2			0x30c8
+#define STA_CSR2_RX_FIFO_OVERFLOW_COUNT	FIELD32(0x0000ffff)
+#define STA_CSR2_RX_OVERFLOW_COUNT	FIELD32(0xffff0000)
+
+/*
+ * STA_CSR3: TX Beacon count.
+ */
+#define STA_CSR3			0x30cc
+#define STA_CSR3_TX_BEACON_COUNT	FIELD32(0x0000ffff)
+
+/*
+ * STA_CSR4: TX Retry count.
+ */
+#define STA_CSR4			0x30d0
+#define STA_CSR4_TX_NO_RETRY_COUNT	FIELD32(0x0000ffff)
+#define STA_CSR4_TX_ONE_RETRY_COUNT	FIELD32(0xffff0000)
+
+/*
+ * STA_CSR5: TX Retry count.
+ */
+#define STA_CSR5			0x30d4
+#define STA_CSR4_TX_MULTI_RETRY_COUNT	FIELD32(0x0000ffff)
+#define STA_CSR4_TX_RETRY_FAIL_COUNT	FIELD32(0xffff0000)
+
+/*
+ * QOS control registers.
+ */
+
+/*
+ * QOS_CSR1: TXOP holder MAC address register.
+ */
+#define QOS_CSR1			0x30e4
+#define QOS_CSR1_BYTE4			FIELD32(0x000000ff)
+#define QOS_CSR1_BYTE5			FIELD32(0x0000ff00)
+
+/*
+ * QOS_CSR2: TXOP holder timeout register.
+ */
+#define QOS_CSR2			0x30e8
+
+/*
+ * RX QOS-CFPOLL MAC address register.
+ * QOS_CSR3: RX QOS-CFPOLL MAC address 0.
+ * QOS_CSR4: RX QOS-CFPOLL MAC address 1.
+ */
+#define QOS_CSR3			0x30ec
+#define QOS_CSR4			0x30f0
+
+/*
+ * QOS_CSR5: "QosControl" field of the RX QOS-CFPOLL.
+ */
+#define QOS_CSR5			0x30f4
+
+/*
+ * WMM Scheduler Register
+ */
+
+/*
+ * AIFSN_CSR: AIFSN for each EDCA AC.
+ * AIFSN0: For AC_BK.
+ * AIFSN1: For AC_BE.
+ * AIFSN2: For AC_VI.
+ * AIFSN3: For AC_VO.
+ */
+#define AIFSN_CSR			0x0400
+#define AIFSN_CSR_AIFSN0		FIELD32(0x0000000f)
+#define AIFSN_CSR_AIFSN1		FIELD32(0x000000f0)
+#define AIFSN_CSR_AIFSN2		FIELD32(0x00000f00)
+#define AIFSN_CSR_AIFSN3		FIELD32(0x0000f000)
+
+/*
+ * CWMIN_CSR: CWmin for each EDCA AC.
+ * CWMIN0: For AC_BK.
+ * CWMIN1: For AC_BE.
+ * CWMIN2: For AC_VI.
+ * CWMIN3: For AC_VO.
+ */
+#define CWMIN_CSR			0x0404
+#define CWMIN_CSR_CWMIN0		FIELD32(0x0000000f)
+#define CWMIN_CSR_CWMIN1		FIELD32(0x000000f0)
+#define CWMIN_CSR_CWMIN2		FIELD32(0x00000f00)
+#define CWMIN_CSR_CWMIN3		FIELD32(0x0000f000)
+
+/*
+ * CWMAX_CSR: CWmax for each EDCA AC.
+ * CWMAX0: For AC_BK.
+ * CWMAX1: For AC_BE.
+ * CWMAX2: For AC_VI.
+ * CWMAX3: For AC_VO.
+ */
+#define CWMAX_CSR			0x0408
+#define CWMAX_CSR_CWMAX0		FIELD32(0x0000000f)
+#define CWMAX_CSR_CWMAX1		FIELD32(0x000000f0)
+#define CWMAX_CSR_CWMAX2		FIELD32(0x00000f00)
+#define CWMAX_CSR_CWMAX3		FIELD32(0x0000f000)
+
+/*
+ * AC_TXOP_CSR0: AC_BK/AC_BE TXOP register.
+ * AC0_TX_OP: For AC_BK, in unit of 32us.
+ * AC1_TX_OP: For AC_BE, in unit of 32us.
+ */
+#define AC_TXOP_CSR0			0x040c
+#define AC_TXOP_CSR0_AC0_TX_OP		FIELD32(0x0000ffff)
+#define AC_TXOP_CSR0_AC1_TX_OP		FIELD32(0xffff0000)
+
+/*
+ * AC_TXOP_CSR1: AC_VO/AC_VI TXOP register.
+ * AC2_TX_OP: For AC_VI, in unit of 32us.
+ * AC3_TX_OP: For AC_VO, in unit of 32us.
+ */
+#define AC_TXOP_CSR1			0x0410
+#define AC_TXOP_CSR1_AC2_TX_OP		FIELD32(0x0000ffff)
+#define AC_TXOP_CSR1_AC3_TX_OP		FIELD32(0xffff0000)
+
+/*
+ * BBP registers.
+ * The wordsize of the BBP is 8 bits.
+ */
+
+/*
+ * R2
+ */
+#define BBP_R2_BG_MODE			FIELD8(0x20)
+
+/*
+ * R3
+ */
+#define BBP_R3_SMART_MODE		FIELD8(0x01)
+
+/*
+ * R4: RX antenna control
+ * FRAME_END: 1 - DPDT, 0 - SPDT (Only valid for 802.11G, RF2527 & RF2529)
+ */
+#define BBP_R4_RX_ANTENNA		FIELD8(0x03)
+#define BBP_R4_RX_FRAME_END		FIELD8(0x20)
+
+/*
+ * R77
+ */
+#define BBP_R77_PAIR			FIELD8(0x03)
+
+/*
+ * RF registers
+ */
+
+/*
+ * RF 3
+ */
+#define RF3_TXPOWER			FIELD32(0x00003e00)
+
+/*
+ * RF 4
+ */
+#define RF4_FREQ_OFFSET			FIELD32(0x0003f000)
+
+/*
+ * EEPROM content.
+ * The wordsize of the EEPROM is 16 bits.
+ */
+
+/*
+ * HW MAC address.
+ */
+#define EEPROM_MAC_ADDR_0		0x0002
+#define EEPROM_MAC_ADDR_BYTE0		FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE1		FIELD16(0xff00)
+#define EEPROM_MAC_ADDR1		0x0003
+#define EEPROM_MAC_ADDR_BYTE2		FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE3		FIELD16(0xff00)
+#define EEPROM_MAC_ADDR_2		0x0004
+#define EEPROM_MAC_ADDR_BYTE4		FIELD16(0x00ff)
+#define EEPROM_MAC_ADDR_BYTE5		FIELD16(0xff00)
+
+/*
+ * EEPROM antenna.
+ * ANTENNA_NUM: Number of antenna's.
+ * TX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * RX_DEFAULT: Default antenna 0: diversity, 1: A, 2: B.
+ * FRAME_TYPE: 0: DPDT , 1: SPDT , noted this bit is valid for g only.
+ * DYN_TXAGC: Dynamic TX AGC control.
+ * HARDWARE_RADIO: 1: Hardware controlled radio. Read GPIO0.
+ * RF_TYPE: Rf_type of this adapter.
+ */
+#define EEPROM_ANTENNA			0x0010
+#define EEPROM_ANTENNA_NUM		FIELD16(0x0003)
+#define EEPROM_ANTENNA_TX_DEFAULT	FIELD16(0x000c)
+#define EEPROM_ANTENNA_RX_DEFAULT	FIELD16(0x0030)
+#define EEPROM_ANTENNA_FRAME_TYPE	FIELD16(0x0040)
+#define EEPROM_ANTENNA_DYN_TXAGC	FIELD16(0x0200)
+#define EEPROM_ANTENNA_HARDWARE_RADIO	FIELD16(0x0400)
+#define EEPROM_ANTENNA_RF_TYPE		FIELD16(0xf800)
+
+/*
+ * EEPROM NIC config.
+ * EXTERNAL_LNA: External LNA.
+ */
+#define EEPROM_NIC			0x0011
+#define EEPROM_NIC_EXTERNAL_LNA		FIELD16(0x0010)
+
+/*
+ * EEPROM geography.
+ * GEO_A: Default geographical setting for 5GHz band
+ * GEO: Default geographical setting.
+ */
+#define EEPROM_GEOGRAPHY		0x0012
+#define EEPROM_GEOGRAPHY_GEO_A		FIELD16(0x00ff)
+#define EEPROM_GEOGRAPHY_GEO		FIELD16(0xff00)
+
+/*
+ * EEPROM BBP.
+ */
+#define EEPROM_BBP_START		0x0013
+#define EEPROM_BBP_SIZE			16
+#define EEPROM_BBP_VALUE		FIELD16(0x00ff)
+#define EEPROM_BBP_REG_ID		FIELD16(0xff00)
+
+/*
+ * EEPROM TXPOWER 802.11G
+ */
+#define EEPROM_TXPOWER_G_START		0x0023
+#define EEPROM_TXPOWER_G_SIZE		7
+#define EEPROM_TXPOWER_G_1		FIELD16(0x00ff)
+#define EEPROM_TXPOWER_G_2		FIELD16(0xff00)
+
+/*
+ * EEPROM Frequency
+ */
+#define EEPROM_FREQ			0x002f
+#define EEPROM_FREQ_OFFSET		FIELD16(0x00ff)
+#define EEPROM_FREQ_SEQ_MASK		FIELD16(0xff00)
+#define EEPROM_FREQ_SEQ			FIELD16(0x0300)
+
+/*
+ * EEPROM LED.
+ * POLARITY_RDY_G: Polarity RDY_G setting.
+ * POLARITY_RDY_A: Polarity RDY_A setting.
+ * POLARITY_ACT: Polarity ACT setting.
+ * POLARITY_GPIO_0: Polarity GPIO0 setting.
+ * POLARITY_GPIO_1: Polarity GPIO1 setting.
+ * POLARITY_GPIO_2: Polarity GPIO2 setting.
+ * POLARITY_GPIO_3: Polarity GPIO3 setting.
+ * POLARITY_GPIO_4: Polarity GPIO4 setting.
+ * LED_MODE: Led mode.
+ */
+#define EEPROM_LED			0x0030
+#define EEPROM_LED_POLARITY_RDY_G	FIELD16(0x0001)
+#define EEPROM_LED_POLARITY_RDY_A	FIELD16(0x0002)
+#define EEPROM_LED_POLARITY_ACT		FIELD16(0x0004)
+#define EEPROM_LED_POLARITY_GPIO_0	FIELD16(0x0008)
+#define EEPROM_LED_POLARITY_GPIO_1	FIELD16(0x0010)
+#define EEPROM_LED_POLARITY_GPIO_2	FIELD16(0x0020)
+#define EEPROM_LED_POLARITY_GPIO_3	FIELD16(0x0040)
+#define EEPROM_LED_POLARITY_GPIO_4	FIELD16(0x0080)
+#define EEPROM_LED_LED_MODE		FIELD16(0x1f00)
+
+/*
+ * EEPROM TXPOWER 802.11A
+ */
+#define EEPROM_TXPOWER_A_START		0x0031
+#define EEPROM_TXPOWER_A_SIZE		12
+#define EEPROM_TXPOWER_A_1		FIELD16(0x00ff)
+#define EEPROM_TXPOWER_A_2		FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI offset 802.11BG
+ */
+#define EEPROM_RSSI_OFFSET_BG		0x004d
+#define EEPROM_RSSI_OFFSET_BG_1		FIELD16(0x00ff)
+#define EEPROM_RSSI_OFFSET_BG_2		FIELD16(0xff00)
+
+/*
+ * EEPROM RSSI offset 802.11A
+ */
+#define EEPROM_RSSI_OFFSET_A		0x004e
+#define EEPROM_RSSI_OFFSET_A_1		FIELD16(0x00ff)
+#define EEPROM_RSSI_OFFSET_A_2		FIELD16(0xff00)
+
+/*
+ * DMA descriptor defines.
+ */
+#define TXD_DESC_SIZE			( 6 * sizeof(struct data_desc) )
+#define RXD_DESC_SIZE			( 6 * sizeof(struct data_desc) )
+
+/*
+ * TX descriptor format for TX, PRIO and Beacon Ring.
+ */
+
+/*
+ * Word0
+ * BURST: Next frame belongs to same "burst" event.
+ * TKIP_MIC: ASIC appends TKIP MIC if TKIP is used.
+ * KEY_TABLE: Use per-client pairwise KEY table.
+ * KEY_INDEX:
+ * Key index (0~31) to the pairwise KEY table.
+ * 0~3 to shared KEY table 0 (BSS0).
+ * 4~7 to shared KEY table 1 (BSS1).
+ * 8~11 to shared KEY table 2 (BSS2).
+ * 12~15 to shared KEY table 3 (BSS3).
+ * BURST2: For backward compatibility, set to same value as BURST.
+ */
+#define TXD_W0_BURST			FIELD32(0x00000001)
+#define TXD_W0_VALID			FIELD32(0x00000002)
+#define TXD_W0_MORE_FRAG		FIELD32(0x00000004)
+#define TXD_W0_ACK			FIELD32(0x00000008)
+#define TXD_W0_TIMESTAMP		FIELD32(0x00000010)
+#define TXD_W0_OFDM			FIELD32(0x00000020)
+#define TXD_W0_IFS			FIELD32(0x00000040)
+#define TXD_W0_RETRY_MODE		FIELD32(0x00000080)
+#define TXD_W0_TKIP_MIC			FIELD32(0x00000100)
+#define TXD_W0_KEY_TABLE		FIELD32(0x00000200)
+#define TXD_W0_KEY_INDEX		FIELD32(0x0000fc00)
+#define TXD_W0_DATABYTE_COUNT		FIELD32(0x0fff0000)
+#define TXD_W0_BURST2			FIELD32(0x10000000)
+#define TXD_W0_CIPHER_ALG		FIELD32(0xe0000000)
+
+/*
+ * Word1
+ * HOST_Q_ID: EDCA/HCCA queue ID.
+ * HW_SEQUENCE: MAC overwrites the frame sequence number.
+ * BUFFER_COUNT: Number of buffers in this TXD.
+ */
+#define TXD_W1_HOST_Q_ID		FIELD32(0x0000000f)
+#define TXD_W1_AIFSN			FIELD32(0x000000f0)
+#define TXD_W1_CWMIN			FIELD32(0x00000f00)
+#define TXD_W1_CWMAX			FIELD32(0x0000f000)
+#define TXD_W1_IV_OFFSET		FIELD32(0x003f0000)
+#define TXD_W1_HW_SEQUENCE		FIELD32(0x10000000)
+#define TXD_W1_BUFFER_COUNT		FIELD32(0xe0000000)
+
+/*
+ * Word2: PLCP information
+ */
+#define TXD_W2_PLCP_SIGNAL		FIELD32(0x000000ff)
+#define TXD_W2_PLCP_SERVICE		FIELD32(0x0000ff00)
+#define TXD_W2_PLCP_LENGTH_LOW		FIELD32(0x00ff0000)
+#define TXD_W2_PLCP_LENGTH_HIGH		FIELD32(0xff000000)
+
+/*
+ * Word3
+ */
+#define TXD_W3_IV			FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define TXD_W4_EIV			FIELD32(0xffffffff)
+
+/*
+ * Word5
+ * FRAME_OFFSET: Frame start offset inside ASIC TXFIFO (after TXINFO field).
+ * PACKET_ID: Driver assigned packet ID to categorize TXResult in interrupt.
+ * WAITING_DMA_DONE_INT: TXD been filled with data
+ * and waiting for TxDoneISR housekeeping.
+ */
+#define TXD_W5_FRAME_OFFSET		FIELD32(0x000000ff)
+#define TXD_W5_PACKET_ID		FIELD32(0x0000ff00)
+#define TXD_W5_TX_POWER			FIELD32(0x00ff0000)
+#define TXD_W5_WAITING_DMA_DONE_INT	FIELD32(0x01000000)
+
+/*
+ * RX descriptor format for RX Ring.
+ */
+
+/*
+ * Word0
+ * CIPHER_ERROR: 1:ICV error, 2:MIC error, 3:invalid key.
+ * KEY_INDEX: Decryption key actually used.
+ */
+#define RXD_W0_OWNER_NIC		FIELD32(0x00000001)
+#define RXD_W0_DROP			FIELD32(0x00000002)
+#define RXD_W0_UNICAST_TO_ME		FIELD32(0x00000004)
+#define RXD_W0_MULTICAST		FIELD32(0x00000008)
+#define RXD_W0_BROADCAST		FIELD32(0x00000010)
+#define RXD_W0_MY_BSS			FIELD32(0x00000020)
+#define RXD_W0_CRC_ERROR		FIELD32(0x00000040)
+#define RXD_W0_OFDM			FIELD32(0x00000080)
+#define RXD_W0_CIPHER_ERROR		FIELD32(0x00000300)
+#define RXD_W0_KEY_INDEX		FIELD32(0x0000fc00)
+#define RXD_W0_DATABYTE_COUNT		FIELD32(0x0fff0000)
+#define RXD_W0_CIPHER_ALG		FIELD32(0xe0000000)
+
+/*
+ * WORD1
+ * SIGNAL: RX raw data rate reported by BBP.
+ * RSSI: RSSI reported by BBP.
+ */
+#define RXD_W1_SIGNAL			FIELD32(0x000000ff)
+#define RXD_W1_RSSI_AGC			FIELD32(0x00001f00)
+#define RXD_W1_RSSI_LNA			FIELD32(0x00006000)
+#define RXD_W1_FRAME_OFFSET		FIELD32(0x7f000000)
+
+/*
+ * Word2
+ * IV: Received IV of originally encrypted.
+ */
+#define RXD_W2_IV			FIELD32(0xffffffff)
+
+/*
+ * Word3
+ * EIV: Received EIV of originally encrypted.
+ */
+#define RXD_W3_EIV			FIELD32(0xffffffff)
+
+/*
+ * Word4
+ */
+#define RXD_W4_RESERVED			FIELD32(0xffffffff)
+
+/*
+ * the above 20-byte is called RXINFO and will be DMAed to MAC RX block
+ * and passed to the HOST driver.
+ * The following fields are for DMA block and HOST usage only.
+ * Can't be touched by ASIC MAC block.
+ */
+
+/*
+ * Word5
+ */
+#define RXD_W5_RESERVED			FIELD32(0xffffffff)
+
+/*
+ * Macro's for converting txpower from EEPROM to dscape value
+ * and from dscape value to register value.
+ */
+#define MIN_TXPOWER	0
+#define MAX_TXPOWER	31
+#define DEFAULT_TXPOWER	24
+
+#define TXPOWER_FROM_DEV(__txpower)		\
+({						\
+	((__txpower) > MAX_TXPOWER) ?		\
+		DEFAULT_TXPOWER : (__txpower);	\
+})
+
+#define TXPOWER_TO_DEV(__txpower)			\
+({							\
+	((__txpower) <= MIN_TXPOWER) ? MIN_TXPOWER :	\
+	(((__txpower) >= MAX_TXPOWER) ? MAX_TXPOWER :	\
+	(__txpower));					\
+})
+
+#endif /* RT73USB_H */
diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h
index 6124e46..6ad322e 100644
--- a/drivers/net/wireless/rtl8187.h
+++ b/drivers/net/wireless/rtl8187.h
@@ -36,8 +36,7 @@
 };
 
 struct rtl8187_rx_hdr {
-	__le16 len;
-	__le16 rate;
+	__le32 flags;
 	u8 noise;
 	u8 signal;
 	u8 agc;
@@ -67,13 +66,14 @@
 	struct rtl818x_csr *map;
 	void (*rf_init)(struct ieee80211_hw *);
 	int mode;
+	int if_id;
 
 	/* rtl8187 specific */
 	struct ieee80211_channel channels[14];
 	struct ieee80211_rate rates[12];
 	struct ieee80211_hw_mode modes[2];
 	struct usb_device *udev;
-	u8 *hwaddr;
+	u32 rx_conf;
 	u16 txpwr_base;
 	u8 asic_rev;
 	struct sk_buff_head rx_queue;
diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c
index cea8589..0ef887d 100644
--- a/drivers/net/wireless/rtl8187_dev.c
+++ b/drivers/net/wireless/rtl8187_dev.c
@@ -36,11 +36,64 @@
 	/* Netgear */
 	{USB_DEVICE(0x0846, 0x6100)},
 	{USB_DEVICE(0x0846, 0x6a00)},
+	/* HP */
+	{USB_DEVICE(0x03f0, 0xca02)},
 	{}
 };
 
 MODULE_DEVICE_TABLE(usb, rtl8187_table);
 
+static void rtl8187_iowrite_async_cb(struct urb *urb)
+{
+	kfree(urb->context);
+	usb_free_urb(urb);
+}
+
+static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr,
+				  void *data, u16 len)
+{
+	struct usb_ctrlrequest *dr;
+	struct urb *urb;
+	struct rtl8187_async_write_data {
+		u8 data[4];
+		struct usb_ctrlrequest dr;
+	} *buf;
+
+	buf = kmalloc(sizeof(*buf), GFP_ATOMIC);
+	if (!buf)
+		return;
+
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!urb) {
+		kfree(buf);
+		return;
+	}
+
+	dr = &buf->dr;
+
+	dr->bRequestType = RTL8187_REQT_WRITE;
+	dr->bRequest = RTL8187_REQ_SET_REG;
+	dr->wValue = addr;
+	dr->wIndex = 0;
+	dr->wLength = cpu_to_le16(len);
+
+	memcpy(buf, data, len);
+
+	usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0),
+			     (unsigned char *)dr, buf, len,
+			     rtl8187_iowrite_async_cb, buf);
+	usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv,
+					   __le32 *addr, u32 val)
+{
+	__le32 buf = cpu_to_le32(val);
+
+	rtl8187_iowrite_async(priv, cpu_to_le16((unsigned long)addr),
+			      &buf, sizeof(buf));
+}
+
 void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data)
 {
 	struct rtl8187_priv *priv = dev->priv;
@@ -96,7 +149,7 @@
 	if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) {
 		tmp |= RTL8187_TX_FLAG_RTS;
 		hdr->rts_duration =
-			ieee80211_rts_duration(dev, skb->len, control);
+			ieee80211_rts_duration(dev, priv->if_id, skb->len, control);
 	}
 	if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)
 		tmp |= RTL8187_TX_FLAG_CTS;
@@ -125,6 +178,7 @@
 	struct rtl8187_rx_hdr *hdr;
 	struct ieee80211_rx_status rx_status = { 0 };
 	int rate, signal;
+	u32 flags;
 
 	spin_lock(&priv->rx_queue.lock);
 	if (skb->next)
@@ -143,10 +197,11 @@
 
 	skb_put(skb, urb->actual_length);
 	hdr = (struct rtl8187_rx_hdr *)(skb_tail_pointer(skb) - sizeof(*hdr));
-	skb_trim(skb, le16_to_cpu(hdr->len) & 0x0FFF);
+	flags = le32_to_cpu(hdr->flags);
+	skb_trim(skb, flags & 0x0FFF);
 
 	signal = hdr->agc >> 1;
-	rate = (le16_to_cpu(hdr->rate) >> 4) & 0xF;
+	rate = (flags >> 20) & 0xF;
 	if (rate > 3) {	/* OFDM rate */
 		if (signal > 90)
 			signal = 90;
@@ -169,6 +224,8 @@
 	rx_status.channel = dev->conf.channel;
 	rx_status.phymode = dev->conf.phymode;
 	rx_status.mactime = le64_to_cpu(hdr->mac_time);
+	if (flags & (1 << 13))
+		rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
 	ieee80211_rx_irqsafe(dev, skb, &rx_status);
 
 	skb = dev_alloc_skb(RTL8187_MAX_RX);
@@ -293,8 +350,6 @@
 	rtl818x_iowrite8(priv, &priv->map->GP_ENABLE, 0);
 
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
-	for (i = 0; i < ETH_ALEN; i++)
-		rtl818x_iowrite8(priv, &priv->map->MAC[i], priv->hwaddr[i]);
 
 	rtl818x_iowrite16(priv, (__le16 *)0xFFF4, 0xFFFF);
 	reg = rtl818x_ioread8(priv, &priv->map->CONFIG1);
@@ -365,7 +420,7 @@
 	rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg);
 }
 
-static int rtl8187_open(struct ieee80211_hw *dev)
+static int rtl8187_start(struct ieee80211_hw *dev)
 {
 	struct rtl8187_priv *priv = dev->priv;
 	u32 reg;
@@ -383,16 +438,13 @@
 	      RTL818X_RX_CONF_RX_AUTORESETPHY |
 	      RTL818X_RX_CONF_BSSID |
 	      RTL818X_RX_CONF_MGMT |
-	      RTL818X_RX_CONF_CTRL |
 	      RTL818X_RX_CONF_DATA |
 	      (7 << 13 /* RX FIFO threshold NONE */) |
 	      (7 << 10 /* MAX RX DMA */) |
 	      RTL818X_RX_CONF_BROADCAST |
-	      RTL818X_RX_CONF_MULTICAST |
 	      RTL818X_RX_CONF_NICMAC;
-	if (priv->mode == IEEE80211_IF_TYPE_MNTR)
-		reg |= RTL818X_RX_CONF_MONITOR;
 
+	priv->rx_conf = reg;
 	rtl818x_iowrite32(priv, &priv->map->RX_CONF, reg);
 
 	reg = rtl818x_ioread8(priv, &priv->map->CW_CONF);
@@ -419,7 +471,7 @@
 	return 0;
 }
 
-static int rtl8187_stop(struct ieee80211_hw *dev)
+static void rtl8187_stop(struct ieee80211_hw *dev)
 {
 	struct rtl8187_priv *priv = dev->priv;
 	struct rtl8187_rx_info *info;
@@ -445,28 +497,31 @@
 		usb_kill_urb(info->urb);
 		kfree_skb(skb);
 	}
-	return 0;
+	return;
 }
 
 static int rtl8187_add_interface(struct ieee80211_hw *dev,
 				 struct ieee80211_if_init_conf *conf)
 {
 	struct rtl8187_priv *priv = dev->priv;
+	int i;
 
-	/* NOTE: using IEEE80211_IF_TYPE_MGMT to indicate no mode selected */
-	if (priv->mode != IEEE80211_IF_TYPE_MGMT)
-		return -1;
+	if (priv->mode != IEEE80211_IF_TYPE_MNTR)
+		return -EOPNOTSUPP;
 
 	switch (conf->type) {
 	case IEEE80211_IF_TYPE_STA:
-	case IEEE80211_IF_TYPE_MNTR:
 		priv->mode = conf->type;
 		break;
 	default:
 		return -EOPNOTSUPP;
 	}
 
-	priv->hwaddr = conf->mac_addr;
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
+	for (i = 0; i < ETH_ALEN; i++)
+		rtl818x_iowrite8(priv, &priv->map->MAC[i],
+				 ((u8 *)conf->mac_addr)[i]);
+	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 
 	return 0;
 }
@@ -475,7 +530,7 @@
 				     struct ieee80211_if_init_conf *conf)
 {
 	struct rtl8187_priv *priv = dev->priv;
-	priv->mode = IEEE80211_IF_TYPE_MGMT;
+	priv->mode = IEEE80211_IF_TYPE_MNTR;
 }
 
 static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
@@ -510,6 +565,8 @@
 	struct rtl8187_priv *priv = dev->priv;
 	int i;
 
+	priv->if_id = if_id;
+
 	for (i = 0; i < ETH_ALEN; i++)
 		rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]);
 
@@ -521,14 +578,52 @@
 	return 0;
 }
 
+static void rtl8187_configure_filter(struct ieee80211_hw *dev,
+				     unsigned int changed_flags,
+				     unsigned int *total_flags,
+				     int mc_count, struct dev_addr_list *mc_list)
+{
+	struct rtl8187_priv *priv = dev->priv;
+
+	*total_flags = 0;
+
+	if (changed_flags & FIF_PROMISC_IN_BSS)
+		priv->rx_conf ^= RTL818X_RX_CONF_NICMAC;
+	if (changed_flags & FIF_ALLMULTI)
+		priv->rx_conf ^= RTL818X_RX_CONF_MULTICAST;
+	if (changed_flags & FIF_FCSFAIL)
+		priv->rx_conf ^= RTL818X_RX_CONF_FCS;
+	if (changed_flags & FIF_CONTROL)
+		priv->rx_conf ^= RTL818X_RX_CONF_CTRL;
+	if (changed_flags & FIF_OTHER_BSS)
+		priv->rx_conf ^= RTL818X_RX_CONF_MONITOR;
+
+	if (mc_count > 0)
+		priv->rx_conf |= RTL818X_RX_CONF_MULTICAST;
+
+	if (priv->rx_conf & RTL818X_RX_CONF_NICMAC)
+		*total_flags |= FIF_PROMISC_IN_BSS;
+	if (priv->rx_conf & RTL818X_RX_CONF_MULTICAST)
+		*total_flags |= FIF_ALLMULTI;
+	if (priv->rx_conf & RTL818X_RX_CONF_FCS)
+		*total_flags |= FIF_FCSFAIL;
+	if (priv->rx_conf & RTL818X_RX_CONF_CTRL)
+		*total_flags |= FIF_CONTROL;
+	if (priv->rx_conf & RTL818X_RX_CONF_MONITOR)
+		*total_flags |= FIF_OTHER_BSS;
+
+	rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf);
+}
+
 static const struct ieee80211_ops rtl8187_ops = {
 	.tx			= rtl8187_tx,
-	.open			= rtl8187_open,
+	.start			= rtl8187_start,
 	.stop			= rtl8187_stop,
 	.add_interface		= rtl8187_add_interface,
 	.remove_interface	= rtl8187_remove_interface,
 	.config			= rtl8187_config,
 	.config_interface	= rtl8187_config_interface,
+	.configure_filter	= rtl8187_configure_filter,
 };
 
 static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom)
@@ -572,6 +667,7 @@
 	struct ieee80211_channel *channel;
 	u16 txpwr, reg;
 	int err, i;
+	DECLARE_MAC_BUF(mac);
 
 	dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops);
 	if (!dev) {
@@ -601,11 +697,9 @@
 	priv->modes[1].rates = priv->rates;
 	priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels);
 	priv->modes[1].channels = priv->channels;
-	priv->mode = IEEE80211_IF_TYPE_MGMT;
+	priv->mode = IEEE80211_IF_TYPE_MNTR;
 	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-		     IEEE80211_HW_RX_INCLUDES_FCS |
-		     IEEE80211_HW_WEP_INCLUDE_IV |
-		     IEEE80211_HW_DATA_NULLFUNC_ACK;
+		     IEEE80211_HW_RX_INCLUDES_FCS;
 	dev->extra_tx_headroom = sizeof(struct rtl8187_tx_hdr);
 	dev->queues = 1;
 	dev->max_rssi = 65;
@@ -681,8 +775,8 @@
 		goto err_free_dev;
 	}
 
-	printk(KERN_INFO "%s: hwaddr " MAC_FMT ", rtl8187 V%d + %s\n",
-	       wiphy_name(dev->wiphy), MAC_ARG(dev->wiphy->perm_addr),
+	printk(KERN_INFO "%s: hwaddr %s, rtl8187 V%d + %s\n",
+	       wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
 	       priv->asic_rev, priv->rf_init == rtl8225_rf_init ?
 	       "rtl8225" : "rtl8225z2");
 
diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h
index 283de30..880d4be 100644
--- a/drivers/net/wireless/rtl818x.h
+++ b/drivers/net/wireless/rtl818x.h
@@ -71,6 +71,7 @@
 #define RTL818X_RX_CONF_NICMAC		(1 <<  1)
 #define RTL818X_RX_CONF_MULTICAST	(1 <<  2)
 #define RTL818X_RX_CONF_BROADCAST	(1 <<  3)
+#define RTL818X_RX_CONF_FCS		(1 <<  5)
 #define RTL818X_RX_CONF_DATA		(1 << 18)
 #define RTL818X_RX_CONF_CTRL		(1 << 19)
 #define RTL818X_RX_CONF_MGMT		(1 << 20)
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
index af70460..98df9bc 100644
--- a/drivers/net/wireless/spectrum_cs.c
+++ b/drivers/net/wireless/spectrum_cs.c
@@ -782,7 +782,6 @@
 	/* Ok, we have the configuration, prepare to register the netdev */
 	dev->base_addr = link->io.BasePort1;
 	dev->irq = link->irq.AssignedIRQ;
-	SET_MODULE_OWNER(dev);
 	card->node.major = card->node.minor = 0;
 
 	/* Reset card and download firmware */
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index ef32a5c..4bd14b3 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -107,6 +107,7 @@
 #include <linux/serialP.h>
 #include <linux/rcupdate.h>
 #include <net/arp.h>
+#include <net/net_namespace.h>
 
 #include <linux/ip.h>
 #include <linux/tcp.h>
@@ -1630,8 +1631,8 @@
  */
 
 static int strip_header(struct sk_buff *skb, struct net_device *dev,
-			unsigned short type, void *daddr, void *saddr,
-			unsigned len)
+			unsigned short type, const void *daddr,
+			const void *saddr, unsigned len)
 {
 	struct strip *strip_info = netdev_priv(dev);
 	STRIP_Header *header = (STRIP_Header *) skb_push(skb, sizeof(STRIP_Header));
@@ -1971,7 +1972,7 @@
 		      sizeof(zero_address))) {
 		struct net_device *dev;
 		read_lock_bh(&dev_base_lock);
-		for_each_netdev(dev) {
+		for_each_netdev(&init_net, dev) {
 			if (dev->type == strip_info->dev->type &&
 			    !memcmp(dev->dev_addr,
 				    &strip_info->true_dev_addr,
@@ -2496,6 +2497,11 @@
 	return 0;
 }
 
+static const struct header_ops strip_header_ops = {
+	.create = strip_header,
+	.rebuild = strip_rebuild_header,
+};
+
 /*
  * This routine is called by DDI when the
  * (dynamically assigned) device is registered
@@ -2507,8 +2513,6 @@
 	 * Finish setting up the DEVICE info.
 	 */
 
-	SET_MODULE_OWNER(dev);
-
 	dev->trans_start = 0;
 	dev->last_rx = 0;
 	dev->tx_queue_len = 30;	/* Drop after 30 frames queued */
@@ -2532,8 +2536,8 @@
 	dev->open = strip_open_low;
 	dev->stop = strip_close_low;
 	dev->hard_start_xmit = strip_xmit;
-	dev->hard_header = strip_header;
-	dev->rebuild_header = strip_rebuild_header;
+	dev->header_ops = &strip_header_ops;
+
 	dev->set_mac_address = strip_set_mac_address;
 	dev->get_stats = strip_get_stats;
 	dev->change_mtu = strip_change_mtu;
@@ -2571,7 +2575,7 @@
 		return NULL;	/* If no more memory, return */
 
 
-	strip_info = dev->priv;
+	strip_info = netdev_priv(dev);
 	strip_info->dev = dev;
 
 	strip_info->magic = STRIP_MAGIC;
@@ -2787,7 +2791,7 @@
 	/*
 	 * Register the status file with /proc
 	 */
-	proc_net_fops_create("strip", S_IFREG | S_IRUGO, &strip_seq_fops);
+	proc_net_fops_create(&init_net, "strip", S_IFREG | S_IRUGO, &strip_seq_fops);
 
 	return status;
 }
@@ -2809,7 +2813,7 @@
 	}
 
 	/* Unregister with the /proc/net file here. */
-	proc_net_remove("strip");
+	proc_net_remove(&init_net, "strip");
 
 	if ((i = tty_unregister_ldisc(N_STRIP)))
 		printk(KERN_ERR "STRIP: can't unregister line discipline (err = %d)\n", i);
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index 1cf090d6..a1f8a16 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -880,6 +880,8 @@
  */
 static void wv_psa_show(psa_t * p)
 {
+	DECLARE_MAC_BUF(mac);
+
 	printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n");
 	printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
 	       p->psa_io_base_addr_1,
@@ -891,22 +893,13 @@
 	printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
 	printk("psa_int_req_no: %d\n", p->psa_int_req_no);
 #ifdef DEBUG_SHOW_UNUSED
-	printk(KERN_DEBUG
-	       "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-	       p->psa_unused0[0], p->psa_unused0[1], p->psa_unused0[2],
-	       p->psa_unused0[3], p->psa_unused0[4], p->psa_unused0[5],
-	       p->psa_unused0[6]);
+	printk(KERN_DEBUG "psa_unused0[]: %s\n",
+	       print_mac(mac, p->psa_unused0));
 #endif				/* DEBUG_SHOW_UNUSED */
-	printk(KERN_DEBUG
-	       "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       p->psa_univ_mac_addr[0], p->psa_univ_mac_addr[1],
-	       p->psa_univ_mac_addr[2], p->psa_univ_mac_addr[3],
-	       p->psa_univ_mac_addr[4], p->psa_univ_mac_addr[5]);
-	printk(KERN_DEBUG
-	       "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       p->psa_local_mac_addr[0], p->psa_local_mac_addr[1],
-	       p->psa_local_mac_addr[2], p->psa_local_mac_addr[3],
-	       p->psa_local_mac_addr[4], p->psa_local_mac_addr[5]);
+	printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n",
+	       print_mac(mac, p->psa_univ_mac_addr));
+	printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n",
+	       print_mac(mac, p->psa_local_mac_addr));
 	printk(KERN_DEBUG "psa_univ_local_sel: %d, ",
 	       p->psa_univ_local_sel);
 	printk("psa_comp_number: %d, ", p->psa_comp_number);
@@ -1248,14 +1241,14 @@
 {				/* Name of the function */
 	int i;
 	int maxi;
+	DECLARE_MAC_BUF(mac);
 
 	printk(KERN_DEBUG
-	       "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
-	       msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
+	       "%s: %s(): dest %s, length %d\n",
+	       msg1, msg2, print_mac(mac, p), length);
 	printk(KERN_DEBUG
-	       "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
-	       msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12],
-	       p[13]);
+	       "%s: %s(): src %s, type 0x%02X%02X\n",
+	       msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]);
 
 #ifdef DEBUG_PACKET_DUMP
 
@@ -1286,7 +1279,9 @@
 	short ioaddr = dev->base_addr;
 	net_local *lp = (net_local *) dev->priv;
 	psa_t psa;
-	int i;
+#ifdef DEBUG_BASIC_SHOW
+	DECLARE_MAC_BUF(mac);
+#endif
 
 	/* Read the parameter storage area */
 	psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa));
@@ -1303,10 +1298,8 @@
 
 #ifdef DEBUG_BASIC_SHOW
 	/* Now, let's go for the basic stuff. */
-	printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr);
-	for (i = 0; i < WAVELAN_ADDR_SIZE; i++)
-		printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
-	printk(", IRQ %d", dev->irq);
+	printk(KERN_NOTICE "%s: WaveLAN at %#x, %s, IRQ %d",
+	       dev->name, ioaddr, print_mac(mac, dev->dev_addr), dev->irq);
 
 	/* Print current network ID. */
 	if (psa.psa_nwid_select)
@@ -2400,9 +2393,9 @@
 
 static const struct iw_handler_def	wavelan_handler_def =
 {
-	.num_standard	= sizeof(wavelan_handler)/sizeof(iw_handler),
-	.num_private	= sizeof(wavelan_private_handler)/sizeof(iw_handler),
-	.num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
+	.num_standard	= ARRAY_SIZE(wavelan_handler),
+	.num_private	= ARRAY_SIZE(wavelan_private_handler),
+	.num_private_args = ARRAY_SIZE(wavelan_private_args),
 	.standard	= wavelan_handler,
 	.private	= wavelan_private_handler,
 	.private_args	= wavelan_private_args,
@@ -3596,15 +3589,15 @@
 			      WAVELAN_ADDR_SIZE >> 1);
 
 #ifdef DEBUG_CONFIG_INFO
+ {
+		DECLARE_MAC_BUF(mac);
 		printk(KERN_DEBUG
 		       "%s: wv_82586_config(): set %d multicast addresses:\n",
 		       dev->name, lp->mc_count);
 		for (dmi = dev->mc_list; dmi; dmi = dmi->next)
-			printk(KERN_DEBUG
-			       " %02x:%02x:%02x:%02x:%02x:%02x\n",
-			       dmi->dmi_addr[0], dmi->dmi_addr[1],
-			       dmi->dmi_addr[2], dmi->dmi_addr[3],
-			       dmi->dmi_addr[4], dmi->dmi_addr[5]);
+			printk(KERN_DEBUG " %s\n",
+			       print_mac(mac, dmi->dmi_addr));
+ }
 #endif
 	}
 
@@ -4177,7 +4170,6 @@
 	/* Init spinlock */
 	spin_lock_init(&lp->spinlock);
 
-	SET_MODULE_OWNER(dev);
 	dev->open = wavelan_open;
 	dev->stop = wavelan_close;
 	dev->hard_start_xmit = wavelan_packet_xmit;
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 5740d4d..577c647 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -1042,6 +1042,7 @@
 static void
 wv_psa_show(psa_t *	p)
 {
+  DECLARE_MAC_BUF(mac);
   printk(KERN_DEBUG "##### wavelan psa contents: #####\n");
   printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
 	 p->psa_io_base_addr_1,
@@ -1055,29 +1056,13 @@
   printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
   printk("psa_int_req_no: %d\n", p->psa_int_req_no);
 #ifdef DEBUG_SHOW_UNUSED
-  printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
-	 p->psa_unused0[0],
-	 p->psa_unused0[1],
-	 p->psa_unused0[2],
-	 p->psa_unused0[3],
-	 p->psa_unused0[4],
-	 p->psa_unused0[5],
-	 p->psa_unused0[6]);
+  printk(KERN_DEBUG "psa_unused0[]: %s\n",
+	 print_mac(mac, p->psa_unused0));
 #endif	/* DEBUG_SHOW_UNUSED */
-  printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
-	 p->psa_univ_mac_addr[0],
-	 p->psa_univ_mac_addr[1],
-	 p->psa_univ_mac_addr[2],
-	 p->psa_univ_mac_addr[3],
-	 p->psa_univ_mac_addr[4],
-	 p->psa_univ_mac_addr[5]);
-  printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
-	 p->psa_local_mac_addr[0],
-	 p->psa_local_mac_addr[1],
-	 p->psa_local_mac_addr[2],
-	 p->psa_local_mac_addr[3],
-	 p->psa_local_mac_addr[4],
-	 p->psa_local_mac_addr[5]);
+  printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n",
+	 print_mac(mac, p->psa_univ_mac_addr));
+  printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n",
+	 print_mac(mac, p->psa_local_mac_addr));
   printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel);
   printk("psa_comp_number: %d, ", p->psa_comp_number);
   printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set);
@@ -1277,11 +1262,12 @@
 {
   int		i;
   int		maxi;
+  DECLARE_MAC_BUF(mac);
 
-  printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
-	 msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
-  printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
-	 msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]);
+  printk(KERN_DEBUG "%s: %s(): dest %s, length %d\n",
+	 msg1, msg2, print_mac(mac, p), length);
+  printk(KERN_DEBUG "%s: %s(): src %s, type 0x%02X%02X\n",
+	 msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]);
 
 #ifdef DEBUG_PACKET_DUMP
 
@@ -1312,7 +1298,7 @@
 {
   kio_addr_t	base = dev->base_addr;
   psa_t		psa;
-  int		i;
+  DECLARE_MAC_BUF(mac);
 
   /* Read the parameter storage area */
   psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
@@ -1329,10 +1315,10 @@
 
 #ifdef DEBUG_BASIC_SHOW
   /* Now, let's go for the basic stuff */
-  printk(KERN_NOTICE "%s: WaveLAN: port %#lx, irq %d, hw_addr",
-	 dev->name, base, dev->irq);
-  for(i = 0; i < WAVELAN_ADDR_SIZE; i++)
-    printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
+  printk(KERN_NOTICE "%s: WaveLAN: port %#lx, irq %d, "
+	 "hw_addr %s",
+	 dev->name, base, dev->irq,
+	 print_mac(mac, dev->dev_addr));
 
   /* Print current network id */
   if(psa.psa_nwid_select)
@@ -2719,9 +2705,9 @@
 
 static const struct iw_handler_def	wavelan_handler_def =
 {
-	.num_standard	= sizeof(wavelan_handler)/sizeof(iw_handler),
-	.num_private	= sizeof(wavelan_private_handler)/sizeof(iw_handler),
-	.num_private_args = sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
+	.num_standard	= ARRAY_SIZE(wavelan_handler),
+	.num_private	= ARRAY_SIZE(wavelan_private_handler),
+	.num_private_args = ARRAY_SIZE(wavelan_private_args),
 	.standard	= wavelan_handler,
 	.private	= wavelan_private_handler,
 	.private_args	= wavelan_private_args,
@@ -3691,12 +3677,12 @@
       int			addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count;
 
 #ifdef DEBUG_CONFIG_INFO
+      DECLARE_MAC_BUF(mac);
       printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n",
 	     dev->name, lp->mc_count);
       for(dmi=dev->mc_list; dmi; dmi=dmi->next)
-	printk(KERN_DEBUG " %02x:%02x:%02x:%02x:%02x:%02x\n",
-	       dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
-	       dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5] );
+	printk(KERN_DEBUG " %s\n",
+	       print_mac(mac, dmi->dmi_addr));
 #endif
 
       /* Initialize adapter's ethernet multicast addresses */
@@ -4577,7 +4563,6 @@
   lp->dev = dev;
 
   /* wavelan NET3 callbacks */
-  SET_MODULE_OWNER(dev);
   dev->open = &wavelan_open;
   dev->stop = &wavelan_close;
   dev->hard_start_xmit = &wavelan_packet_xmit;
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index c8b5c22..42a36b3 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -859,12 +859,11 @@
 
 static void wl3501_online(struct net_device *dev)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
+	DECLARE_MAC_BUF(mac);
 
-	printk(KERN_INFO "%s: Wireless LAN online. BSSID: "
-	       "%02X %02X %02X %02X %02X %02X\n", dev->name,
-	       this->bssid[0], this->bssid[1], this->bssid[2],
-	       this->bssid[3], this->bssid[4], this->bssid[5]);
+	printk(KERN_INFO "%s: Wireless LAN online. BSSID: %s\n",
+	       dev->name, print_mac(mac, this->bssid));
 	netif_wake_queue(dev);
 }
 
@@ -907,7 +906,7 @@
 
 static void wl3501_mgmt_join_confirm(struct net_device *dev, u16 addr)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	struct wl3501_join_confirm sig;
 
 	dprintk(3, "entry");
@@ -1046,7 +1045,7 @@
 static inline void wl3501_assoc_confirm_interrupt(struct net_device *dev,
 						  u16 addr)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	struct wl3501_assoc_confirm sig;
 
 	dprintk(3, "entry");
@@ -1075,7 +1074,7 @@
 	int morepkts;
 	u16 addr;
 	u8 sig_id;
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 
 	dprintk(3, "entry");
 loop:
@@ -1257,7 +1256,7 @@
 
 static int wl3501_close(struct net_device *dev)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	int rc = -ENODEV;
 	unsigned long flags;
 	struct pcmcia_device *link;
@@ -1289,7 +1288,7 @@
  */
 static int wl3501_reset(struct net_device *dev)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	int rc = -ENODEV;
 
 	wl3501_block_interrupt(this);
@@ -1318,7 +1317,7 @@
 
 static void wl3501_tx_timeout(struct net_device *dev)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	struct net_device_stats *stats = &this->stats;
 	unsigned long flags;
 	int rc;
@@ -1344,7 +1343,7 @@
 static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
 	int enabled, rc;
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	unsigned long flags;
 
 	spin_lock_irqsave(&this->lock, flags);
@@ -1371,7 +1370,7 @@
 static int wl3501_open(struct net_device *dev)
 {
 	int rc = -ENODEV;
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	unsigned long flags;
 	struct pcmcia_device *link;
 	link = this->p_dev;
@@ -1410,14 +1409,14 @@
 
 static struct net_device_stats *wl3501_get_stats(struct net_device *dev)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 
 	return &this->stats;
 }
 
 static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	struct iw_statistics *wstats = &this->wstats;
 	u32 value; /* size checked: it is u32 */
 
@@ -1497,7 +1496,7 @@
 static int wl3501_set_freq(struct net_device *dev, struct iw_request_info *info,
 			   union iwreq_data *wrqu, char *extra)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	int channel = wrqu->freq.m;
 	int rc = -EINVAL;
 
@@ -1511,7 +1510,7 @@
 static int wl3501_get_freq(struct net_device *dev, struct iw_request_info *info,
 			   union iwreq_data *wrqu, char *extra)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 
 	wrqu->freq.m = wl3501_chan2freq[this->chan - 1] * 100000;
 	wrqu->freq.e = 1;
@@ -1526,7 +1525,7 @@
 	if (wrqu->mode == IW_MODE_INFRA ||
 	    wrqu->mode == IW_MODE_ADHOC ||
 	    wrqu->mode == IW_MODE_AUTO) {
-		struct wl3501_card *this = dev->priv;
+		struct wl3501_card *this = netdev_priv(dev);
 
 		this->net_type = wrqu->mode;
 		rc = wl3501_reset(dev);
@@ -1537,7 +1536,7 @@
 static int wl3501_get_mode(struct net_device *dev, struct iw_request_info *info,
 			   union iwreq_data *wrqu, char *extra)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 
 	wrqu->mode = this->net_type;
 	return 0;
@@ -1546,7 +1545,7 @@
 static int wl3501_get_sens(struct net_device *dev, struct iw_request_info *info,
 			   union iwreq_data *wrqu, char *extra)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 
 	wrqu->sens.value = this->rssi;
 	wrqu->sens.disabled = !wrqu->sens.value;
@@ -1577,7 +1576,7 @@
 static int wl3501_set_wap(struct net_device *dev, struct iw_request_info *info,
 			  union iwreq_data *wrqu, char *extra)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	static const u8 bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 };
 	int rc = -EINVAL;
 
@@ -1597,7 +1596,7 @@
 static int wl3501_get_wap(struct net_device *dev, struct iw_request_info *info,
 			  union iwreq_data *wrqu, char *extra)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 
 	wrqu->ap_addr.sa_family = ARPHRD_ETHER;
 	memcpy(wrqu->ap_addr.sa_data, this->bssid, ETH_ALEN);
@@ -1616,7 +1615,7 @@
 static int wl3501_get_scan(struct net_device *dev, struct iw_request_info *info,
 			   union iwreq_data *wrqu, char *extra)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	int i;
 	char *current_ev = extra;
 	struct iw_event iwe;
@@ -1666,7 +1665,7 @@
 			    struct iw_request_info *info,
 			    union iwreq_data *wrqu, char *extra)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 
 	if (wrqu->data.flags) {
 		iw_set_mgmt_info_element(IW_MGMT_INFO_ELEMENT_SSID,
@@ -1683,7 +1682,7 @@
 			    struct iw_request_info *info,
 			    union iwreq_data *wrqu, char *extra)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	unsigned long flags;
 
 	spin_lock_irqsave(&this->lock, flags);
@@ -1697,7 +1696,7 @@
 static int wl3501_set_nick(struct net_device *dev, struct iw_request_info *info,
 			   union iwreq_data *wrqu, char *extra)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 
 	if (wrqu->data.length > sizeof(this->nick))
 		return -E2BIG;
@@ -1708,7 +1707,7 @@
 static int wl3501_get_nick(struct net_device *dev, struct iw_request_info *info,
 			   union iwreq_data *wrqu, char *extra)
 {
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 
 	strlcpy(extra, this->nick, 32);
 	wrqu->data.length = strlen(extra);
@@ -1733,7 +1732,7 @@
 				    union iwreq_data *wrqu, char *extra)
 {
 	u16 threshold; /* size checked: it is u16 */
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_RTS_THRESHOLD,
 				      &threshold, sizeof(threshold));
 	if (!rc) {
@@ -1749,7 +1748,7 @@
 				     union iwreq_data *wrqu, char *extra)
 {
 	u16 threshold; /* size checked: it is u16 */
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	int rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_FRAG_THRESHOLD,
 				      &threshold, sizeof(threshold));
 	if (!rc) {
@@ -1765,7 +1764,7 @@
 			    union iwreq_data *wrqu, char *extra)
 {
 	u16 txpow;
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	int rc = wl3501_get_mib_value(this,
 				      WL3501_MIB_ATTR_CURRENT_TX_PWR_LEVEL,
 				      &txpow, sizeof(txpow));
@@ -1787,7 +1786,7 @@
 			    union iwreq_data *wrqu, char *extra)
 {
 	u8 retry; /* size checked: it is u8 */
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	int rc = wl3501_get_mib_value(this,
 				      WL3501_MIB_ATTR_LONG_RETRY_LIMIT,
 				      &retry, sizeof(retry));
@@ -1814,7 +1813,7 @@
 			     union iwreq_data *wrqu, char *extra)
 {
 	u8 implemented, restricted, keys[100], len_keys, tocopy;
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	int rc = wl3501_get_mib_value(this,
 				      WL3501_MIB_ATTR_PRIV_OPT_IMPLEMENTED,
 				      &implemented, sizeof(implemented));
@@ -1841,7 +1840,6 @@
 	tocopy = min_t(u8, len_keys, wrqu->encoding.length);
 	tocopy = min_t(u8, tocopy, 100);
 	wrqu->encoding.length = tocopy;
-	memset(extra, 0, tocopy);
 	memcpy(extra, keys, tocopy);
 out:
 	return rc;
@@ -1852,7 +1850,7 @@
 			    union iwreq_data *wrqu, char *extra)
 {
 	u8 pwr_state;
-	struct wl3501_card *this = dev->priv;
+	struct wl3501_card *this = netdev_priv(dev);
 	int rc = wl3501_get_mib_value(this,
 				      WL3501_MIB_ATTR_CURRENT_PWR_STATE,
 				      &pwr_state, sizeof(pwr_state));
@@ -1894,7 +1892,7 @@
 };
 
 static const struct iw_handler_def wl3501_handler_def = {
-	.num_standard	= sizeof(wl3501_handler) / sizeof(iw_handler),
+	.num_standard	= ARRAY_SIZE(wl3501_handler),
 	.standard	= (iw_handler *)wl3501_handler,
 	.get_wireless_stats = wl3501_get_wireless_stats,
 };
@@ -1937,7 +1935,7 @@
 	dev->tx_timeout		= wl3501_tx_timeout;
 	dev->watchdog_timeo	= 5 * HZ;
 	dev->get_stats		= wl3501_get_stats;
-	this = dev->priv;
+	this = netdev_priv(dev);
 	this->wireless_data.spy_data = &this->spy_data;
 	this->p_dev = p_dev;
 	dev->wireless_data	= &this->wireless_data;
@@ -1967,6 +1965,7 @@
 	struct net_device *dev = link->priv;
 	int i = 0, j, last_fn, last_ret;
 	struct wl3501_card *this;
+	DECLARE_MAC_BUF(mac);
 
 	/* Try allocating IO ports.  This tries a few fixed addresses.  If you
 	 * want, you can also read the card's config table to pick addresses --
@@ -2004,9 +2003,7 @@
 		goto failed;
 	}
 
-	SET_MODULE_OWNER(dev);
-
-	this = dev->priv;
+	this = netdev_priv(dev);
 	/*
 	 * At this point, the dev_node_t structure(s) should be initialized and
 	 * arranged in a linked list at link->dev_node.
@@ -2022,14 +2019,14 @@
 	}
 	strcpy(this->node.dev_name, dev->name);
 
-	/* print probe information */
-	printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, MAC addr in flash ROM:",
-	       dev->name, this->base_addr, (int)dev->irq);
-	for (i = 0; i < 6; i++) {
+	for (i = 0; i < 6; i++)
 		dev->dev_addr[i] = ((char *)&this->mac_addr)[i];
-		printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]);
-	}
-	printk("\n");
+
+	/* print probe information */
+	printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, "
+	       "MAC addr in flash ROM:%s\n",
+	       dev->name, this->base_addr, (int)dev->irq,
+	       print_mac(mac, dev->dev_addr));
 	/*
 	 * Initialize card parameters - added by jss
 	 */
@@ -2079,7 +2076,7 @@
 {
 	struct net_device *dev = link->priv;
 
-	wl3501_pwr_mgmt(dev->priv, WL3501_SUSPEND);
+	wl3501_pwr_mgmt(netdev_priv(dev), WL3501_SUSPEND);
 	if (link->open)
 		netif_device_detach(dev);
 
@@ -2090,7 +2087,7 @@
 {
 	struct net_device *dev = link->priv;
 
-	wl3501_pwr_mgmt(dev->priv, WL3501_RESUME);
+	wl3501_pwr_mgmt(netdev_priv(dev), WL3501_RESUME);
 	if (link->open) {
 		wl3501_reset(dev);
 		netif_device_attach(dev);
diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile
index 4d50590..7a2f2a9 100644
--- a/drivers/net/wireless/zd1211rw/Makefile
+++ b/drivers/net/wireless/zd1211rw/Makefile
@@ -4,7 +4,7 @@
 		zd_mac.o zd_netdev.o \
 		zd_rf_al2230.o zd_rf_rf2959.o \
 		zd_rf_al7230b.o zd_rf_uw2453.o \
-		zd_rf.o zd_usb.o zd_util.o
+		zd_rf.o zd_usb.o
 
 ifeq ($(CONFIG_ZD1211RW_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index c39f198..f831b68 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -28,7 +28,6 @@
 #include "zd_ieee80211.h"
 #include "zd_mac.h"
 #include "zd_rf.h"
-#include "zd_util.h"
 
 void zd_chip_init(struct zd_chip *chip,
 	         struct net_device *netdev,
@@ -106,7 +105,7 @@
 {
 	int r;
 	int i;
-	zd_addr_t *a16 = (zd_addr_t *)NULL;
+	zd_addr_t *a16;
 	u16 *v16;
 	unsigned int count16;
 
@@ -377,6 +376,7 @@
 		[0] = { .addr = CR_MAC_ADDR_P1 },
 		[1] = { .addr = CR_MAC_ADDR_P2 },
 	};
+	DECLARE_MAC_BUF(mac);
 
 	reqs[0].value = (mac_addr[3] << 24)
 		      | (mac_addr[2] << 16)
@@ -386,7 +386,7 @@
 		      |  mac_addr[4];
 
 	dev_dbg_f(zd_chip_dev(chip),
-		"mac addr " MAC_FMT "\n", MAC_ARG(mac_addr));
+		"mac addr %s\n", print_mac(mac, mac_addr));
 
 	mutex_lock(&chip->mutex);
 	r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
@@ -500,8 +500,6 @@
 		return r;
 	}
 
-	dev_dbg_f(zd_chip_dev(chip),
-		"CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp & ~UNLOCK_PHY_REGS);
 	tmp &= ~UNLOCK_PHY_REGS;
 
 	r = zd_iowrite32_locked(chip, tmp, CR_REG1);
@@ -523,8 +521,6 @@
 		return r;
 	}
 
-	dev_dbg_f(zd_chip_dev(chip),
-		"CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp | UNLOCK_PHY_REGS);
 	tmp |= UNLOCK_PHY_REGS;
 
 	r = zd_iowrite32_locked(chip, tmp, CR_REG1);
@@ -841,8 +837,6 @@
 	s->atim_wnd_period = values[0];
 	s->pre_tbtt = values[1];
 	s->beacon_interval = values[2];
-	dev_dbg_f(zd_chip_dev(chip), "aw %u pt %u bi %u\n",
-		s->atim_wnd_period, s->pre_tbtt, s->beacon_interval);
 	return 0;
 }
 
@@ -864,9 +858,6 @@
 	reqs[2].addr = CR_BCN_INTERVAL;
 	reqs[2].value = s->beacon_interval;
 
-	dev_dbg_f(zd_chip_dev(chip),
-		"aw %u pt %u bi %u\n", s->atim_wnd_period, s->pre_tbtt,
-		                       s->beacon_interval);
 	return zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
 }
 
@@ -1018,19 +1009,19 @@
 	u32 value = 0;
 
 	/* Modulation bit */
-	if (ZD_CS_TYPE(rts_rate) == ZD_CS_OFDM)
+	if (ZD_MODULATION_TYPE(rts_rate) == ZD_OFDM)
 		rts_mod = ZD_RX_OFDM;
 
 	dev_dbg_f(zd_chip_dev(chip), "rts_rate=%x preamble=%x\n",
 		rts_rate, preamble);
 
-	value |= rts_rate << RTSCTS_SH_RTS_RATE;
+	value |= ZD_PURE_RATE(rts_rate) << RTSCTS_SH_RTS_RATE;
 	value |= rts_mod << RTSCTS_SH_RTS_MOD_TYPE;
 	value |= preamble << RTSCTS_SH_RTS_PMB_TYPE;
 	value |= preamble << RTSCTS_SH_CTS_PMB_TYPE;
 
 	/* We always send 11M self-CTS messages, like the vendor driver. */
-	value |= ZD_CCK_RATE_11M << RTSCTS_SH_CTS_RATE;
+	value |= ZD_PURE_RATE(ZD_CCK_RATE_11M) << RTSCTS_SH_CTS_RATE;
 	value |= ZD_RX_CCK << RTSCTS_SH_CTS_MOD_TYPE;
 
 	return zd_iowrite32_locked(chip, value, CR_RTS_CTS_RATE);
@@ -1160,16 +1151,12 @@
 static int update_pwr_int(struct zd_chip *chip, u8 channel)
 {
 	u8 value = chip->pwr_int_values[channel - 1];
-	dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_int %#04x\n",
-		 channel, value);
 	return zd_iowrite16_locked(chip, value, CR31);
 }
 
 static int update_pwr_cal(struct zd_chip *chip, u8 channel)
 {
 	u8 value = chip->pwr_cal_values[channel-1];
-	dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_cal %#04x\n",
-		 channel, value);
 	return zd_iowrite16_locked(chip, value, CR68);
 }
 
@@ -1184,9 +1171,6 @@
 	ioreqs[2].addr = CR65;
 	ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1];
 
-	dev_dbg_f(zd_chip_dev(chip),
-		"channel %d ofdm_cal 36M %#04x 48M %#04x 54M %#04x\n",
-		channel, ioreqs[0].value, ioreqs[1].value, ioreqs[2].value);
 	return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
@@ -1344,7 +1328,7 @@
 	return zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL);
 }
 
-static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size)
+static int ofdm_qual_db(u8 status_quality, u8 zd_rate, unsigned int size)
 {
 	static const u16 constants[] = {
 		715, 655, 585, 540, 470, 410, 360, 315,
@@ -1358,7 +1342,7 @@
 	/* It seems that their quality parameter is somehow per signal
 	 * and is now transferred per bit.
 	 */
-	switch (rate) {
+	switch (zd_rate) {
 	case ZD_OFDM_RATE_6M:
 	case ZD_OFDM_RATE_12M:
 	case ZD_OFDM_RATE_24M:
@@ -1385,7 +1369,7 @@
 			break;
 	}
 
-	switch (rate) {
+	switch (zd_rate) {
 	case ZD_OFDM_RATE_6M:
 	case ZD_OFDM_RATE_9M:
 		i += 3;
@@ -1409,11 +1393,11 @@
 	return i;
 }
 
-static int ofdm_qual_percent(u8 status_quality, u8 rate, unsigned int size)
+static int ofdm_qual_percent(u8 status_quality, u8 zd_rate, unsigned int size)
 {
 	int r;
 
-	r = ofdm_qual_db(status_quality, rate, size);
+	r = ofdm_qual_db(status_quality, zd_rate, size);
 	ZD_ASSERT(r >= 0);
 	if (r < 0)
 		r = 0;
@@ -1474,12 +1458,17 @@
 	return r <= 100 ? r : 100;
 }
 
+static inline u8 zd_rate_from_ofdm_plcp_header(const void *rx_frame)
+{
+	return ZD_OFDM | zd_ofdm_plcp_header_rate(rx_frame);
+}
+
 u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
 	              const struct rx_status *status)
 {
 	return (status->frame_status&ZD_RX_OFDM) ?
 		ofdm_qual_percent(status->signal_quality_ofdm,
-			          zd_ofdm_plcp_header_rate(rx_frame),
+					  zd_rate_from_ofdm_plcp_header(rx_frame),
 			          size) :
 		cck_qual_percent(status->signal_quality_cck);
 }
@@ -1495,32 +1484,32 @@
 u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status)
 {
 	static const u16 ofdm_rates[] = {
-		[ZD_OFDM_RATE_6M]  = 60,
-		[ZD_OFDM_RATE_9M]  = 90,
-		[ZD_OFDM_RATE_12M] = 120,
-		[ZD_OFDM_RATE_18M] = 180,
-		[ZD_OFDM_RATE_24M] = 240,
-		[ZD_OFDM_RATE_36M] = 360,
-		[ZD_OFDM_RATE_48M] = 480,
-		[ZD_OFDM_RATE_54M] = 540,
+		[ZD_OFDM_PLCP_RATE_6M]  = 60,
+		[ZD_OFDM_PLCP_RATE_9M]  = 90,
+		[ZD_OFDM_PLCP_RATE_12M] = 120,
+		[ZD_OFDM_PLCP_RATE_18M] = 180,
+		[ZD_OFDM_PLCP_RATE_24M] = 240,
+		[ZD_OFDM_PLCP_RATE_36M] = 360,
+		[ZD_OFDM_PLCP_RATE_48M] = 480,
+		[ZD_OFDM_PLCP_RATE_54M] = 540,
 	};
 	u16 rate;
 	if (status->frame_status & ZD_RX_OFDM) {
+		/* Deals with PLCP OFDM rate (not zd_rates) */
 		u8 ofdm_rate = zd_ofdm_plcp_header_rate(rx_frame);
 		rate = ofdm_rates[ofdm_rate & 0xf];
 	} else {
-		u8 cck_rate = zd_cck_plcp_header_rate(rx_frame);
-		switch (cck_rate) {
-		case ZD_CCK_SIGNAL_1M:
+		switch (zd_cck_plcp_header_signal(rx_frame)) {
+		case ZD_CCK_PLCP_SIGNAL_1M:
 			rate = 10;
 			break;
-		case ZD_CCK_SIGNAL_2M:
+		case ZD_CCK_PLCP_SIGNAL_2M:
 			rate = 20;
 			break;
-		case ZD_CCK_SIGNAL_5M5:
+		case ZD_CCK_PLCP_SIGNAL_5M5:
 			rate = 55;
 			break;
-		case ZD_CCK_SIGNAL_11M:
+		case ZD_CCK_PLCP_SIGNAL_11M:
 			rate = 110;
 			break;
 		default:
@@ -1638,7 +1627,5 @@
 		{ CR_GROUP_HASH_P2, hash->high },
 	};
 
-	dev_dbg_f(zd_chip_dev(chip), "hash l 0x%08x h 0x%08x\n",
-		ioreqs[0].value, ioreqs[1].value);
 	return zd_iowrite32a(chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index f469857..8009b70 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -871,11 +871,6 @@
 	return r;
 }
 
-static inline int zd_chip_set_rx_filter(struct zd_chip *chip, u32 filter)
-{
-	return zd_iowrite32(chip, CR_RX_FILTER, filter);
-}
-
 int zd_chip_lock_phy_regs(struct zd_chip *chip);
 int zd_chip_unlock_phy_regs(struct zd_chip *chip);
 
diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
index deb99d1..505b4d7 100644
--- a/drivers/net/wireless/zd1211rw/zd_def.h
+++ b/drivers/net/wireless/zd1211rw/zd_def.h
@@ -21,7 +21,6 @@
 #include <linux/kernel.h>
 #include <linux/stringify.h>
 #include <linux/device.h>
-#include <linux/kernel.h>
 
 typedef u16 __nocast zd_addr_t;
 
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
index c4f36d3..fbf6491 100644
--- a/drivers/net/wireless/zd1211rw/zd_ieee80211.h
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
@@ -43,21 +43,25 @@
 	__le16 service;
 } __attribute__((packed));
 
-static inline u8 zd_ofdm_plcp_header_rate(
-	const struct ofdm_plcp_header *header)
+static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header)
 {
 	return header->prefix[0] & 0xf;
 }
 
-/* These are referred to as zd_rates */
-#define ZD_OFDM_RATE_6M		0xb
-#define ZD_OFDM_RATE_9M		0xf
-#define ZD_OFDM_RATE_12M	0xa
-#define ZD_OFDM_RATE_18M	0xe
-#define ZD_OFDM_RATE_24M	0x9
-#define ZD_OFDM_RATE_36M	0xd
-#define ZD_OFDM_RATE_48M	0x8
-#define ZD_OFDM_RATE_54M	0xc
+/* The following defines give the encoding of the 4-bit rate field in the
+ * OFDM (802.11a/802.11g) PLCP header. Notify that these values are used to
+ * define the zd-rate values for OFDM.
+ *
+ * See the struct zd_ctrlset definition in zd_mac.h.
+ */
+#define ZD_OFDM_PLCP_RATE_6M		0xb
+#define ZD_OFDM_PLCP_RATE_9M		0xf
+#define ZD_OFDM_PLCP_RATE_12M	0xa
+#define ZD_OFDM_PLCP_RATE_18M	0xe
+#define ZD_OFDM_PLCP_RATE_24M	0x9
+#define ZD_OFDM_PLCP_RATE_36M	0xd
+#define ZD_OFDM_PLCP_RATE_48M	0x8
+#define ZD_OFDM_PLCP_RATE_54M	0xc
 
 struct cck_plcp_header {
 	u8 signal;
@@ -66,15 +70,22 @@
 	__le16 crc16;
 } __attribute__((packed));
 
-static inline u8 zd_cck_plcp_header_rate(const struct cck_plcp_header *header)
+static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header)
 {
 	return header->signal;
 }
 
-#define ZD_CCK_SIGNAL_1M	0x0a
-#define ZD_CCK_SIGNAL_2M	0x14
-#define ZD_CCK_SIGNAL_5M5	0x37
-#define ZD_CCK_SIGNAL_11M	0x6e
+/* These defines give the encodings of the signal field in the 802.11b PLCP
+ * header. The signal field gives the bit rate of the following packet. Even
+ * if technically wrong we use CCK here also for the 1 MBit/s and 2 MBit/s
+ * rate to stay consistent with Zydas and our use of the term.
+ *
+ * Notify that these values are *not* used in the zd-rates.
+ */
+#define ZD_CCK_PLCP_SIGNAL_1M	0x0a
+#define ZD_CCK_PLCP_SIGNAL_2M	0x14
+#define ZD_CCK_PLCP_SIGNAL_5M5	0x37
+#define ZD_CCK_PLCP_SIGNAL_11M	0x6e
 
 enum ieee80211_std {
 	IEEE80211B = 0x01,
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index f6c487a..a903645 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -28,7 +28,6 @@
 #include "zd_ieee80211.h"
 #include "zd_netdev.h"
 #include "zd_rf.h"
-#include "zd_util.h"
 
 static void ieee_init(struct ieee80211_device *ieee);
 static void softmac_init(struct ieee80211softmac_device *sm);
@@ -161,13 +160,33 @@
 	ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
 }
 
-static int reset_mode(struct zd_mac *mac)
+static int set_rx_filter(struct zd_mac *mac)
 {
 	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
 	u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER;
 	return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter);
 }
 
+static int set_sniffer(struct zd_mac *mac)
+{
+	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+	return zd_iowrite32(&mac->chip, CR_SNIFFER_ON,
+		ieee->iw_mode == IW_MODE_MONITOR ? 1 : 0);
+	return 0;
+}
+
+static int set_mc_hash(struct zd_mac *mac)
+{
+	struct zd_mc_hash hash;
+	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+	zd_mc_clear(&hash);
+	if (ieee->iw_mode == IW_MODE_MONITOR)
+		zd_mc_add_all(&hash);
+
+	return zd_chip_set_multicast_hash(&mac->chip, &hash);
+}
+
 int zd_mac_open(struct net_device *netdev)
 {
 	struct zd_mac *mac = zd_netdev_mac(netdev);
@@ -194,7 +213,13 @@
 	r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G);
 	if (r < 0)
 		goto disable_int;
-	r = reset_mode(mac);
+	r = set_rx_filter(mac);
+	if (r)
+		goto disable_int;
+	r = set_sniffer(mac);
+	if (r)
+		goto disable_int;
+	r = set_mc_hash(mac);
 	if (r)
 		goto disable_int;
 	r = zd_chip_switch_radio_on(chip);
@@ -263,12 +288,13 @@
 	struct sockaddr *addr = p;
 	struct zd_mac *mac = zd_netdev_mac(netdev);
 	struct zd_chip *chip = &mac->chip;
+	DECLARE_MAC_BUF(mac2);
 
 	if (!is_valid_ether_addr(addr->sa_data))
 		return -EADDRNOTAVAIL;
 
 	dev_dbg_f(zd_mac_dev(mac),
-		  "Setting MAC to " MAC_FMT "\n", MAC_ARG(addr->sa_data));
+		  "Setting MAC to %s\n", print_mac(mac2, addr->sa_data));
 
 	if (netdev->flags & IFF_UP) {
 		r = zd_write_mac_addr(chip, addr->sa_data);
@@ -298,18 +324,21 @@
 
 void zd_mac_set_multicast_list(struct net_device *dev)
 {
-	struct zd_mc_hash hash;
 	struct zd_mac *mac = zd_netdev_mac(dev);
+	struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+	struct zd_mc_hash hash;
 	struct dev_mc_list *mc;
 	unsigned long flags;
+	DECLARE_MAC_BUF(mac2);
 
-	if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI)) {
+	if (dev->flags & (IFF_PROMISC|IFF_ALLMULTI) ||
+			ieee->iw_mode == IW_MODE_MONITOR) {
 		zd_mc_add_all(&hash);
 	} else {
 		zd_mc_clear(&hash);
 		for (mc = dev->mc_list; mc; mc = mc->next) {
-			dev_dbg_f(zd_mac_dev(mac), "mc addr " MAC_FMT "\n",
-				  MAC_ARG(mc->dmi_addr));
+			dev_dbg_f(zd_mac_dev(mac), "mc addr %s\n",
+				  print_mac(mac2, mc->dmi_addr));
 			zd_mc_add_addr(&hash, mc->dmi_addr);
 		}
 	}
@@ -582,28 +611,6 @@
 	return channel;
 }
 
-/* If wrong rate is given, we are falling back to the slowest rate: 1MBit/s */
-static u8 zd_rate_typed(u8 zd_rate)
-{
-	static const u8 typed_rates[16] = {
-		[ZD_CCK_RATE_1M]	= ZD_CS_CCK|ZD_CCK_RATE_1M,
-		[ZD_CCK_RATE_2M]	= ZD_CS_CCK|ZD_CCK_RATE_2M,
-		[ZD_CCK_RATE_5_5M]	= ZD_CS_CCK|ZD_CCK_RATE_5_5M,
-		[ZD_CCK_RATE_11M]	= ZD_CS_CCK|ZD_CCK_RATE_11M,
-		[ZD_OFDM_RATE_6M]	= ZD_CS_OFDM|ZD_OFDM_RATE_6M,
-		[ZD_OFDM_RATE_9M]	= ZD_CS_OFDM|ZD_OFDM_RATE_9M,
-		[ZD_OFDM_RATE_12M]	= ZD_CS_OFDM|ZD_OFDM_RATE_12M,
-		[ZD_OFDM_RATE_18M]	= ZD_CS_OFDM|ZD_OFDM_RATE_18M,
-		[ZD_OFDM_RATE_24M]	= ZD_CS_OFDM|ZD_OFDM_RATE_24M,
-		[ZD_OFDM_RATE_36M]	= ZD_CS_OFDM|ZD_OFDM_RATE_36M,
-		[ZD_OFDM_RATE_48M]	= ZD_CS_OFDM|ZD_OFDM_RATE_48M,
-		[ZD_OFDM_RATE_54M]	= ZD_CS_OFDM|ZD_OFDM_RATE_54M,
-	};
-
-	ZD_ASSERT(ZD_CS_RATE_MASK == 0x0f);
-	return typed_rates[zd_rate & ZD_CS_RATE_MASK];
-}
-
 int zd_mac_set_mode(struct zd_mac *mac, u32 mode)
 {
 	struct ieee80211_device *ieee;
@@ -628,8 +635,12 @@
 	ieee->iw_mode = mode;
 	spin_unlock_irq(&ieee->lock);
 
-	if (netif_running(mac->netdev))
-		return reset_mode(mac);
+	if (netif_running(mac->netdev)) {
+		int r = set_rx_filter(mac);
+		if (r)
+			return r;
+		return set_sniffer(mac);
+	}
 
 	return 0;
 }
@@ -707,25 +718,30 @@
 
 static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length)
 {
+	/* ZD_PURE_RATE() must be used to remove the modulation type flag of
+	 * the zd-rate values. */
 	static const u8 rate_divisor[] = {
-		[ZD_CCK_RATE_1M]	=  1,
-		[ZD_CCK_RATE_2M]	=  2,
-		[ZD_CCK_RATE_5_5M]	= 11, /* bits must be doubled */
-		[ZD_CCK_RATE_11M]	= 11,
-		[ZD_OFDM_RATE_6M]	=  6,
-		[ZD_OFDM_RATE_9M]	=  9,
-		[ZD_OFDM_RATE_12M]	= 12,
-		[ZD_OFDM_RATE_18M]	= 18,
-		[ZD_OFDM_RATE_24M]	= 24,
-		[ZD_OFDM_RATE_36M]	= 36,
-		[ZD_OFDM_RATE_48M]	= 48,
-		[ZD_OFDM_RATE_54M]	= 54,
+		[ZD_PURE_RATE(ZD_CCK_RATE_1M)]		=  1,
+		[ZD_PURE_RATE(ZD_CCK_RATE_2M)]		=  2,
+
+		/* bits must be doubled */
+		[ZD_PURE_RATE(ZD_CCK_RATE_5_5M)]	= 11,
+
+		[ZD_PURE_RATE(ZD_CCK_RATE_11M)]		= 11,
+		[ZD_PURE_RATE(ZD_OFDM_RATE_6M)]		=  6,
+		[ZD_PURE_RATE(ZD_OFDM_RATE_9M)]		=  9,
+		[ZD_PURE_RATE(ZD_OFDM_RATE_12M)]	= 12,
+		[ZD_PURE_RATE(ZD_OFDM_RATE_18M)]	= 18,
+		[ZD_PURE_RATE(ZD_OFDM_RATE_24M)]	= 24,
+		[ZD_PURE_RATE(ZD_OFDM_RATE_36M)]	= 36,
+		[ZD_PURE_RATE(ZD_OFDM_RATE_48M)]	= 48,
+		[ZD_PURE_RATE(ZD_OFDM_RATE_54M)]	= 54,
 	};
 
 	u32 bits = (u32)tx_length * 8;
 	u32 divisor;
 
-	divisor = rate_divisor[zd_rate];
+	divisor = rate_divisor[ZD_PURE_RATE(zd_rate)];
 	if (divisor == 0)
 		return -EINVAL;
 
@@ -748,52 +764,24 @@
 	return bits/divisor;
 }
 
-enum {
-	R2M_SHORT_PREAMBLE = 0x01,
-	R2M_11A		   = 0x02,
-};
-
-static u8 zd_rate_to_modulation(u8 zd_rate, int flags)
-{
-	u8 modulation;
-
-	modulation = zd_rate_typed(zd_rate);
-	if (flags & R2M_SHORT_PREAMBLE) {
-		switch (ZD_CS_RATE(modulation)) {
-		case ZD_CCK_RATE_2M:
-		case ZD_CCK_RATE_5_5M:
-		case ZD_CCK_RATE_11M:
-			modulation |= ZD_CS_CCK_PREA_SHORT;
-			return modulation;
-		}
-	}
-	if (flags & R2M_11A) {
-		if (ZD_CS_TYPE(modulation) == ZD_CS_OFDM)
-			modulation |= ZD_CS_OFDM_MODE_11A;
-	}
-	return modulation;
-}
-
 static void cs_set_modulation(struct zd_mac *mac, struct zd_ctrlset *cs,
 	                      struct ieee80211_hdr_4addr *hdr)
 {
 	struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev);
 	u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl));
-	u8 rate, zd_rate;
+	u8 rate;
 	int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0;
 	int is_multicast = is_multicast_ether_addr(hdr->addr1);
 	int short_preamble = ieee80211softmac_short_preamble_ok(softmac,
 		is_multicast, is_mgt);
-	int flags = 0;
 
-	/* FIXME: 802.11a? */
 	rate = ieee80211softmac_suggest_txrate(softmac, is_multicast, is_mgt);
+	cs->modulation = rate_to_zd_rate(rate);
 
-	if (short_preamble)
-		flags |= R2M_SHORT_PREAMBLE;
-
-	zd_rate = rate_to_zd_rate(rate);
-	cs->modulation = zd_rate_to_modulation(zd_rate, flags);
+	/* Set short preamble bit when appropriate */
+	if (short_preamble && ZD_MODULATION_TYPE(cs->modulation) == ZD_CCK
+	    && cs->modulation != ZD_CCK_RATE_1M)
+		cs->modulation |= ZD_CCK_PREA_SHORT;
 }
 
 static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
@@ -822,7 +810,7 @@
 		cs->control |= ZD_CS_MULTICAST;
 
 	/* PS-POLL */
-	if (stype == IEEE80211_STYPE_PSPOLL)
+	if (ftype == IEEE80211_FTYPE_CTL && stype == IEEE80211_STYPE_PSPOLL)
 		cs->control |= ZD_CS_PS_POLL_FRAME;
 
 	/* Unicast data frames over the threshold should have RTS */
@@ -832,7 +820,7 @@
 		cs->control |= ZD_CS_RTS;
 
 	/* Use CTS-to-self protection if required */
-	if (ZD_CS_TYPE(cs->modulation) == ZD_CS_OFDM &&
+	if (ZD_MODULATION_TYPE(cs->modulation) == ZD_OFDM &&
 			ieee80211softmac_protection_needed(softmac)) {
 		/* FIXME: avoid sending RTS *and* self-CTS, is that correct? */
 		cs->control &= ~ZD_CS_RTS;
@@ -893,7 +881,7 @@
 	 * - see line 53 of zdinlinef.h
 	 */
 	cs->service = 0;
-	r = zd_calc_tx_length_us(&cs->service, ZD_CS_RATE(cs->modulation),
+	r = zd_calc_tx_length_us(&cs->service, ZD_RATE(cs->modulation),
 		                 le16_to_cpu(cs->tx_length));
 	if (r < 0)
 		return r;
@@ -902,7 +890,7 @@
 	if (next_frag_len == 0) {
 		cs->next_frame_length = 0;
 	} else {
-		r = zd_calc_tx_length_us(NULL, ZD_CS_RATE(cs->modulation),
+		r = zd_calc_tx_length_us(NULL, ZD_RATE(cs->modulation),
 			                 next_frag_len);
 		if (r < 0)
 			return r;
@@ -1077,7 +1065,8 @@
 {
 	const struct rx_status *status;
 
-	*pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status));
+	*pstatus = status = (struct rx_status *)
+		(buffer + (length - sizeof(struct rx_status)));
 	if (status->frame_status & ZD_RX_ERROR) {
 		struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
 		ieee->stats.rx_errors++;
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 9f9344e..1b15bde 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -40,28 +40,51 @@
 
 #define ZD_CS_RESERVED_SIZE	25
 
-/* zd_crtlset field modulation */
-#define ZD_CS_RATE_MASK		0x0f
-#define ZD_CS_TYPE_MASK		0x10
-#define ZD_CS_RATE(modulation) ((modulation) & ZD_CS_RATE_MASK)
-#define ZD_CS_TYPE(modulation) ((modulation) & ZD_CS_TYPE_MASK)
-
-#define ZD_CS_CCK		0x00
-#define ZD_CS_OFDM		0x10
-
-/* These are referred to as zd_rates */
-#define ZD_CCK_RATE_1M	0x00
-#define ZD_CCK_RATE_2M	0x01
-#define ZD_CCK_RATE_5_5M	0x02
-#define ZD_CCK_RATE_11M	0x03
-/* The rates for OFDM are encoded as in the PLCP header. Use ZD_OFDM_RATE_*.
+/* The field modulation of struct zd_ctrlset controls the bit rate, the use
+ * of short or long preambles in 802.11b (CCK mode) or the use of 802.11a or
+ * 802.11g in OFDM mode.
+ *
+ * The term zd-rate is used for the combination of the modulation type flag
+ * and the "pure" rate value.
  */
+#define ZD_PURE_RATE_MASK       0x0f
+#define ZD_MODULATION_TYPE_MASK 0x10
+#define ZD_RATE_MASK            (ZD_PURE_RATE_MASK|ZD_MODULATION_TYPE_MASK)
+#define ZD_PURE_RATE(modulation) ((modulation) & ZD_PURE_RATE_MASK)
+#define ZD_MODULATION_TYPE(modulation) ((modulation) & ZD_MODULATION_TYPE_MASK)
+#define ZD_RATE(modulation) ((modulation) & ZD_RATE_MASK)
 
-/* bit 5 is preamble (when in CCK mode), or a/g selection (when in OFDM mode) */
-#define ZD_CS_CCK_PREA_LONG	0x00
-#define ZD_CS_CCK_PREA_SHORT	0x20
-#define ZD_CS_OFDM_MODE_11G	0x00
-#define ZD_CS_OFDM_MODE_11A	0x20
+/* The two possible modulation types. Notify that 802.11b doesn't use the CCK
+ * codeing for the 1 and 2 MBit/s rate. We stay with the term here to remain
+ * consistent with uses the term at other places.
+  */
+#define ZD_CCK                  0x00
+#define ZD_OFDM                 0x10
+
+/* The ZD1211 firmware uses proprietary encodings of the 802.11b (CCK) rates.
+ * For OFDM the PLCP rate encodings are used. We combine these "pure" rates
+ * with the modulation type flag and call the resulting values zd-rates.
+ */
+#define ZD_CCK_RATE_1M          (ZD_CCK|0x00)
+#define ZD_CCK_RATE_2M          (ZD_CCK|0x01)
+#define ZD_CCK_RATE_5_5M        (ZD_CCK|0x02)
+#define ZD_CCK_RATE_11M         (ZD_CCK|0x03)
+#define ZD_OFDM_RATE_6M         (ZD_OFDM|ZD_OFDM_PLCP_RATE_6M)
+#define ZD_OFDM_RATE_9M         (ZD_OFDM|ZD_OFDM_PLCP_RATE_9M)
+#define ZD_OFDM_RATE_12M        (ZD_OFDM|ZD_OFDM_PLCP_RATE_12M)
+#define ZD_OFDM_RATE_18M        (ZD_OFDM|ZD_OFDM_PLCP_RATE_18M)
+#define ZD_OFDM_RATE_24M        (ZD_OFDM|ZD_OFDM_PLCP_RATE_24M)
+#define ZD_OFDM_RATE_36M        (ZD_OFDM|ZD_OFDM_PLCP_RATE_36M)
+#define ZD_OFDM_RATE_48M        (ZD_OFDM|ZD_OFDM_PLCP_RATE_48M)
+#define ZD_OFDM_RATE_54M        (ZD_OFDM|ZD_OFDM_PLCP_RATE_54M)
+
+/* The bit 5 of the zd_ctrlset modulation field controls the preamble in CCK
+ * mode or the 802.11a/802.11g selection in OFDM mode.
+ */
+#define ZD_CCK_PREA_LONG        0x00
+#define ZD_CCK_PREA_SHORT       0x20
+#define ZD_OFDM_MODE_11G        0x00
+#define ZD_OFDM_MODE_11A        0x20
 
 /* zd_ctrlset control field */
 #define ZD_CS_NEED_RANDOM_BACKOFF	0x01
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c
index 8bda48d..047cab3 100644
--- a/drivers/net/wireless/zd1211rw/zd_netdev.c
+++ b/drivers/net/wireless/zd1211rw/zd_netdev.c
@@ -233,7 +233,6 @@
 		return NULL;
 	}
 
-	SET_MODULE_OWNER(netdev);
 	SET_NETDEV_DEV(netdev, &intf->dev);
 
 	dev_dbg_f(&intf->dev, "netdev->flags %#06hx\n", netdev->flags);
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 28d41a2..b0684f9 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -31,7 +31,6 @@
 #include "zd_netdev.h"
 #include "zd_mac.h"
 #include "zd_usb.h"
-#include "zd_util.h"
 
 static struct usb_device_id usb_ids[] = {
 	/* ZD1211 */
@@ -55,6 +54,7 @@
 	{ USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 },
 	{ USB_DEVICE(0x0586, 0x3407), .driver_info = DEVICE_ZD1211 },
+	{ USB_DEVICE(0x129b, 0x1666), .driver_info = DEVICE_ZD1211 },
 	/* ZD1211B */
 	{ USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
@@ -72,6 +72,11 @@
 	{ USB_DEVICE(0x0586, 0x3413), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x0053, 0x5301), .driver_info = DEVICE_ZD1211B },
 	{ USB_DEVICE(0x0411, 0x00da), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x2019, 0x5303), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x129b, 0x1667), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0cde, 0x001a), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0586, 0x340a), .driver_info = DEVICE_ZD1211B },
+	{ USB_DEVICE(0x0471, 0x1237), .driver_info = DEVICE_ZD1211B },
 	/* "Driverless" devices that need ejecting */
 	{ USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
 	{ USB_DEVICE(0x0ace, 0x20ff), .driver_info = DEVICE_INSTALLER },
diff --git a/drivers/net/wireless/zd1211rw/zd_util.c b/drivers/net/wireless/zd1211rw/zd_util.c
deleted file mode 100644
index d20036c..0000000
--- a/drivers/net/wireless/zd1211rw/zd_util.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/* zd_util.c
- *
- * 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
- *
- * Utility program
- */
-
-#include "zd_def.h"
-#include "zd_util.h"
-
-#ifdef DEBUG
-static char hex(u8 v)
-{
-	v &= 0xf;
-	return (v < 10 ? '0' : 'a' - 10) + v;
-}
-
-static char hex_print(u8 c)
-{
-	return (0x20 <= c && c < 0x7f) ? c : '.';
-}
-
-static void dump_line(const u8 *bytes, size_t size)
-{
-	char c;
-	size_t i;
-
-	size = size <= 8 ? size : 8;
-	printk(KERN_DEBUG "zd1211 %p ", bytes);
-	for (i = 0; i < 8; i++) {
-		switch (i) {
-		case 1:
-		case 5:
-			c = '.';
-			break;
-		case 3:
-			c = ':';
-			break;
-		default:
-			c = ' ';
-		}
-		if (i < size) {
-			printk("%c%c%c", hex(bytes[i] >> 4), hex(bytes[i]), c);
-		} else {
-			printk("  %c", c);
-		}
-	}
-
-	for (i = 0; i < size; i++)
-		printk("%c", hex_print(bytes[i]));
-	printk("\n");
-}
-
-void zd_hexdump(const void *bytes, size_t size)
-{
-	size_t i = 0;
-
-	do {
-		dump_line((u8 *)bytes + i, size-i);
-		i += 8;
-	} while (i < size);
-}
-#endif /* DEBUG */
-
-void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size)
-{
-	if (buffer_size < tail_size)
-		return NULL;
-	return (u8 *)buffer + (buffer_size - tail_size);
-}
diff --git a/drivers/net/wireless/zd1211rw/zd_util.h b/drivers/net/wireless/zd1211rw/zd_util.h
deleted file mode 100644
index ce26f7a..0000000
--- a/drivers/net/wireless/zd1211rw/zd_util.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* zd_util.h
- *
- * 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
- */
-
-#ifndef _ZD_UTIL_H
-#define _ZD_UTIL_H
-
-void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size);
-
-#ifdef DEBUG
-void zd_hexdump(const void *bytes, size_t size);
-#else
-#define zd_hexdump(bytes, size)
-#endif /* DEBUG */
-
-#endif /* _ZD_UTIL_H */
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
new file mode 100644
index 0000000..f464b82
--- /dev/null
+++ b/drivers/net/xen-netfront.c
@@ -0,0 +1,1817 @@
+/*
+ * Virtual network driver for conversing with remote driver backends.
+ *
+ * Copyright (c) 2002-2005, K A Fraser
+ * Copyright (c) 2005, XenSource Ltd
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/if_ether.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/moduleparam.h>
+#include <linux/mm.h>
+#include <net/ip.h>
+
+#include <xen/xenbus.h>
+#include <xen/events.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+
+#include <xen/interface/io/netif.h>
+#include <xen/interface/memory.h>
+#include <xen/interface/grant_table.h>
+
+static struct ethtool_ops xennet_ethtool_ops;
+
+struct netfront_cb {
+	struct page *page;
+	unsigned offset;
+};
+
+#define NETFRONT_SKB_CB(skb)	((struct netfront_cb *)((skb)->cb))
+
+#define RX_COPY_THRESHOLD 256
+
+#define GRANT_INVALID_REF	0
+
+#define NET_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
+#define NET_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
+#define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
+
+struct netfront_info {
+	struct list_head list;
+	struct net_device *netdev;
+
+	struct napi_struct napi;
+
+	struct xen_netif_tx_front_ring tx;
+	struct xen_netif_rx_front_ring rx;
+
+	spinlock_t   tx_lock;
+	spinlock_t   rx_lock;
+
+	unsigned int evtchn;
+
+	/* Receive-ring batched refills. */
+#define RX_MIN_TARGET 8
+#define RX_DFL_MIN_TARGET 64
+#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
+	unsigned rx_min_target, rx_max_target, rx_target;
+	struct sk_buff_head rx_batch;
+
+	struct timer_list rx_refill_timer;
+
+	/*
+	 * {tx,rx}_skbs store outstanding skbuffs. Free tx_skb entries
+	 * are linked from tx_skb_freelist through skb_entry.link.
+	 *
+	 *  NB. Freelist index entries are always going to be less than
+	 *  PAGE_OFFSET, whereas pointers to skbs will always be equal or
+	 *  greater than PAGE_OFFSET: we use this property to distinguish
+	 *  them.
+	 */
+	union skb_entry {
+		struct sk_buff *skb;
+		unsigned link;
+	} tx_skbs[NET_TX_RING_SIZE];
+	grant_ref_t gref_tx_head;
+	grant_ref_t grant_tx_ref[NET_TX_RING_SIZE];
+	unsigned tx_skb_freelist;
+
+	struct sk_buff *rx_skbs[NET_RX_RING_SIZE];
+	grant_ref_t gref_rx_head;
+	grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
+
+	struct xenbus_device *xbdev;
+	int tx_ring_ref;
+	int rx_ring_ref;
+
+	unsigned long rx_pfn_array[NET_RX_RING_SIZE];
+	struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1];
+	struct mmu_update rx_mmu[NET_RX_RING_SIZE];
+};
+
+struct netfront_rx_info {
+	struct xen_netif_rx_response rx;
+	struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
+};
+
+/*
+ * Access macros for acquiring freeing slots in tx_skbs[].
+ */
+
+static void add_id_to_freelist(unsigned *head, union skb_entry *list,
+			       unsigned short id)
+{
+	list[id].link = *head;
+	*head = id;
+}
+
+static unsigned short get_id_from_freelist(unsigned *head,
+					   union skb_entry *list)
+{
+	unsigned int id = *head;
+	*head = list[id].link;
+	return id;
+}
+
+static int xennet_rxidx(RING_IDX idx)
+{
+	return idx & (NET_RX_RING_SIZE - 1);
+}
+
+static struct sk_buff *xennet_get_rx_skb(struct netfront_info *np,
+					 RING_IDX ri)
+{
+	int i = xennet_rxidx(ri);
+	struct sk_buff *skb = np->rx_skbs[i];
+	np->rx_skbs[i] = NULL;
+	return skb;
+}
+
+static grant_ref_t xennet_get_rx_ref(struct netfront_info *np,
+					    RING_IDX ri)
+{
+	int i = xennet_rxidx(ri);
+	grant_ref_t ref = np->grant_rx_ref[i];
+	np->grant_rx_ref[i] = GRANT_INVALID_REF;
+	return ref;
+}
+
+#ifdef CONFIG_SYSFS
+static int xennet_sysfs_addif(struct net_device *netdev);
+static void xennet_sysfs_delif(struct net_device *netdev);
+#else /* !CONFIG_SYSFS */
+#define xennet_sysfs_addif(dev) (0)
+#define xennet_sysfs_delif(dev) do { } while (0)
+#endif
+
+static int xennet_can_sg(struct net_device *dev)
+{
+	return dev->features & NETIF_F_SG;
+}
+
+
+static void rx_refill_timeout(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct netfront_info *np = netdev_priv(dev);
+	netif_rx_schedule(dev, &np->napi);
+}
+
+static int netfront_tx_slot_available(struct netfront_info *np)
+{
+	return ((np->tx.req_prod_pvt - np->tx.rsp_cons) <
+		(TX_MAX_TARGET - MAX_SKB_FRAGS - 2));
+}
+
+static void xennet_maybe_wake_tx(struct net_device *dev)
+{
+	struct netfront_info *np = netdev_priv(dev);
+
+	if (unlikely(netif_queue_stopped(dev)) &&
+	    netfront_tx_slot_available(np) &&
+	    likely(netif_running(dev)))
+		netif_wake_queue(dev);
+}
+
+static void xennet_alloc_rx_buffers(struct net_device *dev)
+{
+	unsigned short id;
+	struct netfront_info *np = netdev_priv(dev);
+	struct sk_buff *skb;
+	struct page *page;
+	int i, batch_target, notify;
+	RING_IDX req_prod = np->rx.req_prod_pvt;
+	grant_ref_t ref;
+	unsigned long pfn;
+	void *vaddr;
+	struct xen_netif_rx_request *req;
+
+	if (unlikely(!netif_carrier_ok(dev)))
+		return;
+
+	/*
+	 * Allocate skbuffs greedily, even though we batch updates to the
+	 * receive ring. This creates a less bursty demand on the memory
+	 * allocator, so should reduce the chance of failed allocation requests
+	 * both for ourself and for other kernel subsystems.
+	 */
+	batch_target = np->rx_target - (req_prod - np->rx.rsp_cons);
+	for (i = skb_queue_len(&np->rx_batch); i < batch_target; i++) {
+		skb = __netdev_alloc_skb(dev, RX_COPY_THRESHOLD,
+					 GFP_ATOMIC | __GFP_NOWARN);
+		if (unlikely(!skb))
+			goto no_skb;
+
+		page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
+		if (!page) {
+			kfree_skb(skb);
+no_skb:
+			/* Any skbuffs queued for refill? Force them out. */
+			if (i != 0)
+				goto refill;
+			/* Could not allocate any skbuffs. Try again later. */
+			mod_timer(&np->rx_refill_timer,
+				  jiffies + (HZ/10));
+			break;
+		}
+
+		skb_shinfo(skb)->frags[0].page = page;
+		skb_shinfo(skb)->nr_frags = 1;
+		__skb_queue_tail(&np->rx_batch, skb);
+	}
+
+	/* Is the batch large enough to be worthwhile? */
+	if (i < (np->rx_target/2)) {
+		if (req_prod > np->rx.sring->req_prod)
+			goto push;
+		return;
+	}
+
+	/* Adjust our fill target if we risked running out of buffers. */
+	if (((req_prod - np->rx.sring->rsp_prod) < (np->rx_target / 4)) &&
+	    ((np->rx_target *= 2) > np->rx_max_target))
+		np->rx_target = np->rx_max_target;
+
+ refill:
+	for (i = 0; ; i++) {
+		skb = __skb_dequeue(&np->rx_batch);
+		if (skb == NULL)
+			break;
+
+		skb->dev = dev;
+
+		id = xennet_rxidx(req_prod + i);
+
+		BUG_ON(np->rx_skbs[id]);
+		np->rx_skbs[id] = skb;
+
+		ref = gnttab_claim_grant_reference(&np->gref_rx_head);
+		BUG_ON((signed short)ref < 0);
+		np->grant_rx_ref[id] = ref;
+
+		pfn = page_to_pfn(skb_shinfo(skb)->frags[0].page);
+		vaddr = page_address(skb_shinfo(skb)->frags[0].page);
+
+		req = RING_GET_REQUEST(&np->rx, req_prod + i);
+		gnttab_grant_foreign_access_ref(ref,
+						np->xbdev->otherend_id,
+						pfn_to_mfn(pfn),
+						0);
+
+		req->id = id;
+		req->gref = ref;
+	}
+
+	wmb();		/* barrier so backend seens requests */
+
+	/* Above is a suitable barrier to ensure backend will see requests. */
+	np->rx.req_prod_pvt = req_prod + i;
+ push:
+	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
+	if (notify)
+		notify_remote_via_irq(np->netdev->irq);
+}
+
+static int xennet_open(struct net_device *dev)
+{
+	struct netfront_info *np = netdev_priv(dev);
+
+	napi_enable(&np->napi);
+
+	spin_lock_bh(&np->rx_lock);
+	if (netif_carrier_ok(dev)) {
+		xennet_alloc_rx_buffers(dev);
+		np->rx.sring->rsp_event = np->rx.rsp_cons + 1;
+		if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
+			netif_rx_schedule(dev, &np->napi);
+	}
+	spin_unlock_bh(&np->rx_lock);
+
+	xennet_maybe_wake_tx(dev);
+
+	return 0;
+}
+
+static void xennet_tx_buf_gc(struct net_device *dev)
+{
+	RING_IDX cons, prod;
+	unsigned short id;
+	struct netfront_info *np = netdev_priv(dev);
+	struct sk_buff *skb;
+
+	BUG_ON(!netif_carrier_ok(dev));
+
+	do {
+		prod = np->tx.sring->rsp_prod;
+		rmb(); /* Ensure we see responses up to 'rp'. */
+
+		for (cons = np->tx.rsp_cons; cons != prod; cons++) {
+			struct xen_netif_tx_response *txrsp;
+
+			txrsp = RING_GET_RESPONSE(&np->tx, cons);
+			if (txrsp->status == NETIF_RSP_NULL)
+				continue;
+
+			id  = txrsp->id;
+			skb = np->tx_skbs[id].skb;
+			if (unlikely(gnttab_query_foreign_access(
+				np->grant_tx_ref[id]) != 0)) {
+				printk(KERN_ALERT "xennet_tx_buf_gc: warning "
+				       "-- grant still in use by backend "
+				       "domain.\n");
+				BUG();
+			}
+			gnttab_end_foreign_access_ref(
+				np->grant_tx_ref[id], GNTMAP_readonly);
+			gnttab_release_grant_reference(
+				&np->gref_tx_head, np->grant_tx_ref[id]);
+			np->grant_tx_ref[id] = GRANT_INVALID_REF;
+			add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, id);
+			dev_kfree_skb_irq(skb);
+		}
+
+		np->tx.rsp_cons = prod;
+
+		/*
+		 * Set a new event, then check for race with update of tx_cons.
+		 * Note that it is essential to schedule a callback, no matter
+		 * how few buffers are pending. Even if there is space in the
+		 * transmit ring, higher layers may be blocked because too much
+		 * data is outstanding: in such cases notification from Xen is
+		 * likely to be the only kick that we'll get.
+		 */
+		np->tx.sring->rsp_event =
+			prod + ((np->tx.sring->req_prod - prod) >> 1) + 1;
+		mb();		/* update shared area */
+	} while ((cons == prod) && (prod != np->tx.sring->rsp_prod));
+
+	xennet_maybe_wake_tx(dev);
+}
+
+static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev,
+			      struct xen_netif_tx_request *tx)
+{
+	struct netfront_info *np = netdev_priv(dev);
+	char *data = skb->data;
+	unsigned long mfn;
+	RING_IDX prod = np->tx.req_prod_pvt;
+	int frags = skb_shinfo(skb)->nr_frags;
+	unsigned int offset = offset_in_page(data);
+	unsigned int len = skb_headlen(skb);
+	unsigned int id;
+	grant_ref_t ref;
+	int i;
+
+	/* While the header overlaps a page boundary (including being
+	   larger than a page), split it it into page-sized chunks. */
+	while (len > PAGE_SIZE - offset) {
+		tx->size = PAGE_SIZE - offset;
+		tx->flags |= NETTXF_more_data;
+		len -= tx->size;
+		data += tx->size;
+		offset = 0;
+
+		id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+		np->tx_skbs[id].skb = skb_get(skb);
+		tx = RING_GET_REQUEST(&np->tx, prod++);
+		tx->id = id;
+		ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+		BUG_ON((signed short)ref < 0);
+
+		mfn = virt_to_mfn(data);
+		gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
+						mfn, GNTMAP_readonly);
+
+		tx->gref = np->grant_tx_ref[id] = ref;
+		tx->offset = offset;
+		tx->size = len;
+		tx->flags = 0;
+	}
+
+	/* Grant backend access to each skb fragment page. */
+	for (i = 0; i < frags; i++) {
+		skb_frag_t *frag = skb_shinfo(skb)->frags + i;
+
+		tx->flags |= NETTXF_more_data;
+
+		id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+		np->tx_skbs[id].skb = skb_get(skb);
+		tx = RING_GET_REQUEST(&np->tx, prod++);
+		tx->id = id;
+		ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+		BUG_ON((signed short)ref < 0);
+
+		mfn = pfn_to_mfn(page_to_pfn(frag->page));
+		gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
+						mfn, GNTMAP_readonly);
+
+		tx->gref = np->grant_tx_ref[id] = ref;
+		tx->offset = frag->page_offset;
+		tx->size = frag->size;
+		tx->flags = 0;
+	}
+
+	np->tx.req_prod_pvt = prod;
+}
+
+static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	unsigned short id;
+	struct netfront_info *np = netdev_priv(dev);
+	struct xen_netif_tx_request *tx;
+	struct xen_netif_extra_info *extra;
+	char *data = skb->data;
+	RING_IDX i;
+	grant_ref_t ref;
+	unsigned long mfn;
+	int notify;
+	int frags = skb_shinfo(skb)->nr_frags;
+	unsigned int offset = offset_in_page(data);
+	unsigned int len = skb_headlen(skb);
+
+	frags += (offset + len + PAGE_SIZE - 1) / PAGE_SIZE;
+	if (unlikely(frags > MAX_SKB_FRAGS + 1)) {
+		printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n",
+		       frags);
+		dump_stack();
+		goto drop;
+	}
+
+	spin_lock_irq(&np->tx_lock);
+
+	if (unlikely(!netif_carrier_ok(dev) ||
+		     (frags > 1 && !xennet_can_sg(dev)) ||
+		     netif_needs_gso(dev, skb))) {
+		spin_unlock_irq(&np->tx_lock);
+		goto drop;
+	}
+
+	i = np->tx.req_prod_pvt;
+
+	id = get_id_from_freelist(&np->tx_skb_freelist, np->tx_skbs);
+	np->tx_skbs[id].skb = skb;
+
+	tx = RING_GET_REQUEST(&np->tx, i);
+
+	tx->id   = id;
+	ref = gnttab_claim_grant_reference(&np->gref_tx_head);
+	BUG_ON((signed short)ref < 0);
+	mfn = virt_to_mfn(data);
+	gnttab_grant_foreign_access_ref(
+		ref, np->xbdev->otherend_id, mfn, GNTMAP_readonly);
+	tx->gref = np->grant_tx_ref[id] = ref;
+	tx->offset = offset;
+	tx->size = len;
+	extra = NULL;
+
+	tx->flags = 0;
+	if (skb->ip_summed == CHECKSUM_PARTIAL)
+		/* local packet? */
+		tx->flags |= NETTXF_csum_blank | NETTXF_data_validated;
+	else if (skb->ip_summed == CHECKSUM_UNNECESSARY)
+		/* remote but checksummed. */
+		tx->flags |= NETTXF_data_validated;
+
+	if (skb_shinfo(skb)->gso_size) {
+		struct xen_netif_extra_info *gso;
+
+		gso = (struct xen_netif_extra_info *)
+			RING_GET_REQUEST(&np->tx, ++i);
+
+		if (extra)
+			extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE;
+		else
+			tx->flags |= NETTXF_extra_info;
+
+		gso->u.gso.size = skb_shinfo(skb)->gso_size;
+		gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
+		gso->u.gso.pad = 0;
+		gso->u.gso.features = 0;
+
+		gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
+		gso->flags = 0;
+		extra = gso;
+	}
+
+	np->tx.req_prod_pvt = i + 1;
+
+	xennet_make_frags(skb, dev, tx);
+	tx->size = skb->len;
+
+	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->tx, notify);
+	if (notify)
+		notify_remote_via_irq(np->netdev->irq);
+
+	dev->stats.tx_bytes += skb->len;
+	dev->stats.tx_packets++;
+
+	/* Note: It is not safe to access skb after xennet_tx_buf_gc()! */
+	xennet_tx_buf_gc(dev);
+
+	if (!netfront_tx_slot_available(np))
+		netif_stop_queue(dev);
+
+	spin_unlock_irq(&np->tx_lock);
+
+	return 0;
+
+ drop:
+	dev->stats.tx_dropped++;
+	dev_kfree_skb(skb);
+	return 0;
+}
+
+static int xennet_close(struct net_device *dev)
+{
+	struct netfront_info *np = netdev_priv(dev);
+	netif_stop_queue(np->netdev);
+	napi_disable(&np->napi);
+	return 0;
+}
+
+static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb,
+				grant_ref_t ref)
+{
+	int new = xennet_rxidx(np->rx.req_prod_pvt);
+
+	BUG_ON(np->rx_skbs[new]);
+	np->rx_skbs[new] = skb;
+	np->grant_rx_ref[new] = ref;
+	RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new;
+	RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref;
+	np->rx.req_prod_pvt++;
+}
+
+static int xennet_get_extras(struct netfront_info *np,
+			     struct xen_netif_extra_info *extras,
+			     RING_IDX rp)
+
+{
+	struct xen_netif_extra_info *extra;
+	struct device *dev = &np->netdev->dev;
+	RING_IDX cons = np->rx.rsp_cons;
+	int err = 0;
+
+	do {
+		struct sk_buff *skb;
+		grant_ref_t ref;
+
+		if (unlikely(cons + 1 == rp)) {
+			if (net_ratelimit())
+				dev_warn(dev, "Missing extra info\n");
+			err = -EBADR;
+			break;
+		}
+
+		extra = (struct xen_netif_extra_info *)
+			RING_GET_RESPONSE(&np->rx, ++cons);
+
+		if (unlikely(!extra->type ||
+			     extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
+			if (net_ratelimit())
+				dev_warn(dev, "Invalid extra type: %d\n",
+					extra->type);
+			err = -EINVAL;
+		} else {
+			memcpy(&extras[extra->type - 1], extra,
+			       sizeof(*extra));
+		}
+
+		skb = xennet_get_rx_skb(np, cons);
+		ref = xennet_get_rx_ref(np, cons);
+		xennet_move_rx_slot(np, skb, ref);
+	} while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE);
+
+	np->rx.rsp_cons = cons;
+	return err;
+}
+
+static int xennet_get_responses(struct netfront_info *np,
+				struct netfront_rx_info *rinfo, RING_IDX rp,
+				struct sk_buff_head *list)
+{
+	struct xen_netif_rx_response *rx = &rinfo->rx;
+	struct xen_netif_extra_info *extras = rinfo->extras;
+	struct device *dev = &np->netdev->dev;
+	RING_IDX cons = np->rx.rsp_cons;
+	struct sk_buff *skb = xennet_get_rx_skb(np, cons);
+	grant_ref_t ref = xennet_get_rx_ref(np, cons);
+	int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD);
+	int frags = 1;
+	int err = 0;
+	unsigned long ret;
+
+	if (rx->flags & NETRXF_extra_info) {
+		err = xennet_get_extras(np, extras, rp);
+		cons = np->rx.rsp_cons;
+	}
+
+	for (;;) {
+		if (unlikely(rx->status < 0 ||
+			     rx->offset + rx->status > PAGE_SIZE)) {
+			if (net_ratelimit())
+				dev_warn(dev, "rx->offset: %x, size: %u\n",
+					 rx->offset, rx->status);
+			xennet_move_rx_slot(np, skb, ref);
+			err = -EINVAL;
+			goto next;
+		}
+
+		/*
+		 * This definitely indicates a bug, either in this driver or in
+		 * the backend driver. In future this should flag the bad
+		 * situation to the system controller to reboot the backed.
+		 */
+		if (ref == GRANT_INVALID_REF) {
+			if (net_ratelimit())
+				dev_warn(dev, "Bad rx response id %d.\n",
+					 rx->id);
+			err = -EINVAL;
+			goto next;
+		}
+
+		ret = gnttab_end_foreign_access_ref(ref, 0);
+		BUG_ON(!ret);
+
+		gnttab_release_grant_reference(&np->gref_rx_head, ref);
+
+		__skb_queue_tail(list, skb);
+
+next:
+		if (!(rx->flags & NETRXF_more_data))
+			break;
+
+		if (cons + frags == rp) {
+			if (net_ratelimit())
+				dev_warn(dev, "Need more frags\n");
+			err = -ENOENT;
+			break;
+		}
+
+		rx = RING_GET_RESPONSE(&np->rx, cons + frags);
+		skb = xennet_get_rx_skb(np, cons + frags);
+		ref = xennet_get_rx_ref(np, cons + frags);
+		frags++;
+	}
+
+	if (unlikely(frags > max)) {
+		if (net_ratelimit())
+			dev_warn(dev, "Too many frags\n");
+		err = -E2BIG;
+	}
+
+	if (unlikely(err))
+		np->rx.rsp_cons = cons + frags;
+
+	return err;
+}
+
+static int xennet_set_skb_gso(struct sk_buff *skb,
+			      struct xen_netif_extra_info *gso)
+{
+	if (!gso->u.gso.size) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "GSO size must not be zero.\n");
+		return -EINVAL;
+	}
+
+	/* Currently only TCPv4 S.O. is supported. */
+	if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "Bad GSO type %d.\n", gso->u.gso.type);
+		return -EINVAL;
+	}
+
+	skb_shinfo(skb)->gso_size = gso->u.gso.size;
+	skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
+
+	/* Header must be checked, and gso_segs computed. */
+	skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
+	skb_shinfo(skb)->gso_segs = 0;
+
+	return 0;
+}
+
+static RING_IDX xennet_fill_frags(struct netfront_info *np,
+				  struct sk_buff *skb,
+				  struct sk_buff_head *list)
+{
+	struct skb_shared_info *shinfo = skb_shinfo(skb);
+	int nr_frags = shinfo->nr_frags;
+	RING_IDX cons = np->rx.rsp_cons;
+	skb_frag_t *frag = shinfo->frags + nr_frags;
+	struct sk_buff *nskb;
+
+	while ((nskb = __skb_dequeue(list))) {
+		struct xen_netif_rx_response *rx =
+			RING_GET_RESPONSE(&np->rx, ++cons);
+
+		frag->page = skb_shinfo(nskb)->frags[0].page;
+		frag->page_offset = rx->offset;
+		frag->size = rx->status;
+
+		skb->data_len += rx->status;
+
+		skb_shinfo(nskb)->nr_frags = 0;
+		kfree_skb(nskb);
+
+		frag++;
+		nr_frags++;
+	}
+
+	shinfo->nr_frags = nr_frags;
+	return cons;
+}
+
+static int skb_checksum_setup(struct sk_buff *skb)
+{
+	struct iphdr *iph;
+	unsigned char *th;
+	int err = -EPROTO;
+
+	if (skb->protocol != htons(ETH_P_IP))
+		goto out;
+
+	iph = (void *)skb->data;
+	th = skb->data + 4 * iph->ihl;
+	if (th >= skb_tail_pointer(skb))
+		goto out;
+
+	skb->csum_start = th - skb->head;
+	switch (iph->protocol) {
+	case IPPROTO_TCP:
+		skb->csum_offset = offsetof(struct tcphdr, check);
+		break;
+	case IPPROTO_UDP:
+		skb->csum_offset = offsetof(struct udphdr, check);
+		break;
+	default:
+		if (net_ratelimit())
+			printk(KERN_ERR "Attempting to checksum a non-"
+			       "TCP/UDP packet, dropping a protocol"
+			       " %d packet", iph->protocol);
+		goto out;
+	}
+
+	if ((th + skb->csum_offset + 2) > skb_tail_pointer(skb))
+		goto out;
+
+	err = 0;
+
+out:
+	return err;
+}
+
+static int handle_incoming_queue(struct net_device *dev,
+				 struct sk_buff_head *rxq)
+{
+	int packets_dropped = 0;
+	struct sk_buff *skb;
+
+	while ((skb = __skb_dequeue(rxq)) != NULL) {
+		struct page *page = NETFRONT_SKB_CB(skb)->page;
+		void *vaddr = page_address(page);
+		unsigned offset = NETFRONT_SKB_CB(skb)->offset;
+
+		memcpy(skb->data, vaddr + offset,
+		       skb_headlen(skb));
+
+		if (page != skb_shinfo(skb)->frags[0].page)
+			__free_page(page);
+
+		/* Ethernet work: Delayed to here as it peeks the header. */
+		skb->protocol = eth_type_trans(skb, dev);
+
+		if (skb->ip_summed == CHECKSUM_PARTIAL) {
+			if (skb_checksum_setup(skb)) {
+				kfree_skb(skb);
+				packets_dropped++;
+				dev->stats.rx_errors++;
+				continue;
+			}
+		}
+
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += skb->len;
+
+		/* Pass it up. */
+		netif_receive_skb(skb);
+		dev->last_rx = jiffies;
+	}
+
+	return packets_dropped;
+}
+
+static int xennet_poll(struct napi_struct *napi, int budget)
+{
+	struct netfront_info *np = container_of(napi, struct netfront_info, napi);
+	struct net_device *dev = np->netdev;
+	struct sk_buff *skb;
+	struct netfront_rx_info rinfo;
+	struct xen_netif_rx_response *rx = &rinfo.rx;
+	struct xen_netif_extra_info *extras = rinfo.extras;
+	RING_IDX i, rp;
+	int work_done;
+	struct sk_buff_head rxq;
+	struct sk_buff_head errq;
+	struct sk_buff_head tmpq;
+	unsigned long flags;
+	unsigned int len;
+	int err;
+
+	spin_lock(&np->rx_lock);
+
+	if (unlikely(!netif_carrier_ok(dev))) {
+		spin_unlock(&np->rx_lock);
+		return 0;
+	}
+
+	skb_queue_head_init(&rxq);
+	skb_queue_head_init(&errq);
+	skb_queue_head_init(&tmpq);
+
+	rp = np->rx.sring->rsp_prod;
+	rmb(); /* Ensure we see queued responses up to 'rp'. */
+
+	i = np->rx.rsp_cons;
+	work_done = 0;
+	while ((i != rp) && (work_done < budget)) {
+		memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx));
+		memset(extras, 0, sizeof(rinfo.extras));
+
+		err = xennet_get_responses(np, &rinfo, rp, &tmpq);
+
+		if (unlikely(err)) {
+err:
+			while ((skb = __skb_dequeue(&tmpq)))
+				__skb_queue_tail(&errq, skb);
+			dev->stats.rx_errors++;
+			i = np->rx.rsp_cons;
+			continue;
+		}
+
+		skb = __skb_dequeue(&tmpq);
+
+		if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
+			struct xen_netif_extra_info *gso;
+			gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
+
+			if (unlikely(xennet_set_skb_gso(skb, gso))) {
+				__skb_queue_head(&tmpq, skb);
+				np->rx.rsp_cons += skb_queue_len(&tmpq);
+				goto err;
+			}
+		}
+
+		NETFRONT_SKB_CB(skb)->page = skb_shinfo(skb)->frags[0].page;
+		NETFRONT_SKB_CB(skb)->offset = rx->offset;
+
+		len = rx->status;
+		if (len > RX_COPY_THRESHOLD)
+			len = RX_COPY_THRESHOLD;
+		skb_put(skb, len);
+
+		if (rx->status > len) {
+			skb_shinfo(skb)->frags[0].page_offset =
+				rx->offset + len;
+			skb_shinfo(skb)->frags[0].size = rx->status - len;
+			skb->data_len = rx->status - len;
+		} else {
+			skb_shinfo(skb)->frags[0].page = NULL;
+			skb_shinfo(skb)->nr_frags = 0;
+		}
+
+		i = xennet_fill_frags(np, skb, &tmpq);
+
+		/*
+		 * Truesize approximates the size of true data plus
+		 * any supervisor overheads. Adding hypervisor
+		 * overheads has been shown to significantly reduce
+		 * achievable bandwidth with the default receive
+		 * buffer size. It is therefore not wise to account
+		 * for it here.
+		 *
+		 * After alloc_skb(RX_COPY_THRESHOLD), truesize is set
+		 * to RX_COPY_THRESHOLD + the supervisor
+		 * overheads. Here, we add the size of the data pulled
+		 * in xennet_fill_frags().
+		 *
+		 * We also adjust for any unused space in the main
+		 * data area by subtracting (RX_COPY_THRESHOLD -
+		 * len). This is especially important with drivers
+		 * which split incoming packets into header and data,
+		 * using only 66 bytes of the main data area (see the
+		 * e1000 driver for example.)  On such systems,
+		 * without this last adjustement, our achievable
+		 * receive throughout using the standard receive
+		 * buffer size was cut by 25%(!!!).
+		 */
+		skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len);
+		skb->len += skb->data_len;
+
+		if (rx->flags & NETRXF_csum_blank)
+			skb->ip_summed = CHECKSUM_PARTIAL;
+		else if (rx->flags & NETRXF_data_validated)
+			skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+		__skb_queue_tail(&rxq, skb);
+
+		np->rx.rsp_cons = ++i;
+		work_done++;
+	}
+
+	while ((skb = __skb_dequeue(&errq)))
+		kfree_skb(skb);
+
+	work_done -= handle_incoming_queue(dev, &rxq);
+
+	/* If we get a callback with very few responses, reduce fill target. */
+	/* NB. Note exponential increase, linear decrease. */
+	if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) >
+	     ((3*np->rx_target) / 4)) &&
+	    (--np->rx_target < np->rx_min_target))
+		np->rx_target = np->rx_min_target;
+
+	xennet_alloc_rx_buffers(dev);
+
+	if (work_done < budget) {
+		int more_to_do = 0;
+
+		local_irq_save(flags);
+
+		RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do);
+		if (!more_to_do)
+			__netif_rx_complete(dev, napi);
+
+		local_irq_restore(flags);
+	}
+
+	spin_unlock(&np->rx_lock);
+
+	return work_done;
+}
+
+static int xennet_change_mtu(struct net_device *dev, int mtu)
+{
+	int max = xennet_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
+
+	if (mtu > max)
+		return -EINVAL;
+	dev->mtu = mtu;
+	return 0;
+}
+
+static void xennet_release_tx_bufs(struct netfront_info *np)
+{
+	struct sk_buff *skb;
+	int i;
+
+	for (i = 0; i < NET_TX_RING_SIZE; i++) {
+		/* Skip over entries which are actually freelist references */
+		if ((unsigned long)np->tx_skbs[i].skb < PAGE_OFFSET)
+			continue;
+
+		skb = np->tx_skbs[i].skb;
+		gnttab_end_foreign_access_ref(np->grant_tx_ref[i],
+					      GNTMAP_readonly);
+		gnttab_release_grant_reference(&np->gref_tx_head,
+					       np->grant_tx_ref[i]);
+		np->grant_tx_ref[i] = GRANT_INVALID_REF;
+		add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, i);
+		dev_kfree_skb_irq(skb);
+	}
+}
+
+static void xennet_release_rx_bufs(struct netfront_info *np)
+{
+	struct mmu_update      *mmu = np->rx_mmu;
+	struct multicall_entry *mcl = np->rx_mcl;
+	struct sk_buff_head free_list;
+	struct sk_buff *skb;
+	unsigned long mfn;
+	int xfer = 0, noxfer = 0, unused = 0;
+	int id, ref;
+
+	dev_warn(&np->netdev->dev, "%s: fix me for copying receiver.\n",
+			 __func__);
+	return;
+
+	skb_queue_head_init(&free_list);
+
+	spin_lock_bh(&np->rx_lock);
+
+	for (id = 0; id < NET_RX_RING_SIZE; id++) {
+		ref = np->grant_rx_ref[id];
+		if (ref == GRANT_INVALID_REF) {
+			unused++;
+			continue;
+		}
+
+		skb = np->rx_skbs[id];
+		mfn = gnttab_end_foreign_transfer_ref(ref);
+		gnttab_release_grant_reference(&np->gref_rx_head, ref);
+		np->grant_rx_ref[id] = GRANT_INVALID_REF;
+
+		if (0 == mfn) {
+			skb_shinfo(skb)->nr_frags = 0;
+			dev_kfree_skb(skb);
+			noxfer++;
+			continue;
+		}
+
+		if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+			/* Remap the page. */
+			struct page *page = skb_shinfo(skb)->frags[0].page;
+			unsigned long pfn = page_to_pfn(page);
+			void *vaddr = page_address(page);
+
+			MULTI_update_va_mapping(mcl, (unsigned long)vaddr,
+						mfn_pte(mfn, PAGE_KERNEL),
+						0);
+			mcl++;
+			mmu->ptr = ((u64)mfn << PAGE_SHIFT)
+				| MMU_MACHPHYS_UPDATE;
+			mmu->val = pfn;
+			mmu++;
+
+			set_phys_to_machine(pfn, mfn);
+		}
+		__skb_queue_tail(&free_list, skb);
+		xfer++;
+	}
+
+	dev_info(&np->netdev->dev, "%s: %d xfer, %d noxfer, %d unused\n",
+		 __func__, xfer, noxfer, unused);
+
+	if (xfer) {
+		if (!xen_feature(XENFEAT_auto_translated_physmap)) {
+			/* Do all the remapping work and M2P updates. */
+			MULTI_mmu_update(mcl, np->rx_mmu, mmu - np->rx_mmu,
+					 0, DOMID_SELF);
+			mcl++;
+			HYPERVISOR_multicall(np->rx_mcl, mcl - np->rx_mcl);
+		}
+	}
+
+	while ((skb = __skb_dequeue(&free_list)) != NULL)
+		dev_kfree_skb(skb);
+
+	spin_unlock_bh(&np->rx_lock);
+}
+
+static void xennet_uninit(struct net_device *dev)
+{
+	struct netfront_info *np = netdev_priv(dev);
+	xennet_release_tx_bufs(np);
+	xennet_release_rx_bufs(np);
+	gnttab_free_grant_references(np->gref_tx_head);
+	gnttab_free_grant_references(np->gref_rx_head);
+}
+
+static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev)
+{
+	int i, err;
+	struct net_device *netdev;
+	struct netfront_info *np;
+
+	netdev = alloc_etherdev(sizeof(struct netfront_info));
+	if (!netdev) {
+		printk(KERN_WARNING "%s> alloc_etherdev failed.\n",
+		       __func__);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	np                   = netdev_priv(netdev);
+	np->xbdev            = dev;
+
+	spin_lock_init(&np->tx_lock);
+	spin_lock_init(&np->rx_lock);
+
+	skb_queue_head_init(&np->rx_batch);
+	np->rx_target     = RX_DFL_MIN_TARGET;
+	np->rx_min_target = RX_DFL_MIN_TARGET;
+	np->rx_max_target = RX_MAX_TARGET;
+
+	init_timer(&np->rx_refill_timer);
+	np->rx_refill_timer.data = (unsigned long)netdev;
+	np->rx_refill_timer.function = rx_refill_timeout;
+
+	/* Initialise tx_skbs as a free chain containing every entry. */
+	np->tx_skb_freelist = 0;
+	for (i = 0; i < NET_TX_RING_SIZE; i++) {
+		np->tx_skbs[i].link = i+1;
+		np->grant_tx_ref[i] = GRANT_INVALID_REF;
+	}
+
+	/* Clear out rx_skbs */
+	for (i = 0; i < NET_RX_RING_SIZE; i++) {
+		np->rx_skbs[i] = NULL;
+		np->grant_rx_ref[i] = GRANT_INVALID_REF;
+	}
+
+	/* A grant for every tx ring slot */
+	if (gnttab_alloc_grant_references(TX_MAX_TARGET,
+					  &np->gref_tx_head) < 0) {
+		printk(KERN_ALERT "#### netfront can't alloc tx grant refs\n");
+		err = -ENOMEM;
+		goto exit;
+	}
+	/* A grant for every rx ring slot */
+	if (gnttab_alloc_grant_references(RX_MAX_TARGET,
+					  &np->gref_rx_head) < 0) {
+		printk(KERN_ALERT "#### netfront can't alloc rx grant refs\n");
+		err = -ENOMEM;
+		goto exit_free_tx;
+	}
+
+	netdev->open            = xennet_open;
+	netdev->hard_start_xmit = xennet_start_xmit;
+	netdev->stop            = xennet_close;
+	netif_napi_add(netdev, &np->napi, xennet_poll, 64);
+	netdev->uninit          = xennet_uninit;
+	netdev->change_mtu	= xennet_change_mtu;
+	netdev->features        = NETIF_F_IP_CSUM;
+
+	SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops);
+	SET_NETDEV_DEV(netdev, &dev->dev);
+
+	np->netdev = netdev;
+
+	netif_carrier_off(netdev);
+
+	return netdev;
+
+ exit_free_tx:
+	gnttab_free_grant_references(np->gref_tx_head);
+ exit:
+	free_netdev(netdev);
+	return ERR_PTR(err);
+}
+
+/**
+ * Entry point to this code when a new device is created.  Allocate the basic
+ * structures and the ring buffers for communication with the backend, and
+ * inform the backend of the appropriate details for those.
+ */
+static int __devinit netfront_probe(struct xenbus_device *dev,
+				    const struct xenbus_device_id *id)
+{
+	int err;
+	struct net_device *netdev;
+	struct netfront_info *info;
+
+	netdev = xennet_create_dev(dev);
+	if (IS_ERR(netdev)) {
+		err = PTR_ERR(netdev);
+		xenbus_dev_fatal(dev, err, "creating netdev");
+		return err;
+	}
+
+	info = netdev_priv(netdev);
+	dev->dev.driver_data = info;
+
+	err = register_netdev(info->netdev);
+	if (err) {
+		printk(KERN_WARNING "%s: register_netdev err=%d\n",
+		       __func__, err);
+		goto fail;
+	}
+
+	err = xennet_sysfs_addif(info->netdev);
+	if (err) {
+		unregister_netdev(info->netdev);
+		printk(KERN_WARNING "%s: add sysfs failed err=%d\n",
+		       __func__, err);
+		goto fail;
+	}
+
+	return 0;
+
+ fail:
+	free_netdev(netdev);
+	dev->dev.driver_data = NULL;
+	return err;
+}
+
+static void xennet_end_access(int ref, void *page)
+{
+	/* This frees the page as a side-effect */
+	if (ref != GRANT_INVALID_REF)
+		gnttab_end_foreign_access(ref, 0, (unsigned long)page);
+}
+
+static void xennet_disconnect_backend(struct netfront_info *info)
+{
+	/* Stop old i/f to prevent errors whilst we rebuild the state. */
+	spin_lock_bh(&info->rx_lock);
+	spin_lock_irq(&info->tx_lock);
+	netif_carrier_off(info->netdev);
+	spin_unlock_irq(&info->tx_lock);
+	spin_unlock_bh(&info->rx_lock);
+
+	if (info->netdev->irq)
+		unbind_from_irqhandler(info->netdev->irq, info->netdev);
+	info->evtchn = info->netdev->irq = 0;
+
+	/* End access and free the pages */
+	xennet_end_access(info->tx_ring_ref, info->tx.sring);
+	xennet_end_access(info->rx_ring_ref, info->rx.sring);
+
+	info->tx_ring_ref = GRANT_INVALID_REF;
+	info->rx_ring_ref = GRANT_INVALID_REF;
+	info->tx.sring = NULL;
+	info->rx.sring = NULL;
+}
+
+/**
+ * We are reconnecting to the backend, due to a suspend/resume, or a backend
+ * driver restart.  We tear down our netif structure and recreate it, but
+ * leave the device-layer structures intact so that this is transparent to the
+ * rest of the kernel.
+ */
+static int netfront_resume(struct xenbus_device *dev)
+{
+	struct netfront_info *info = dev->dev.driver_data;
+
+	dev_dbg(&dev->dev, "%s\n", dev->nodename);
+
+	xennet_disconnect_backend(info);
+	return 0;
+}
+
+static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
+{
+	char *s, *e, *macstr;
+	int i;
+
+	macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
+	if (IS_ERR(macstr))
+		return PTR_ERR(macstr);
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		mac[i] = simple_strtoul(s, &e, 16);
+		if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
+			kfree(macstr);
+			return -ENOENT;
+		}
+		s = e+1;
+	}
+
+	kfree(macstr);
+	return 0;
+}
+
+static irqreturn_t xennet_interrupt(int irq, void *dev_id)
+{
+	struct net_device *dev = dev_id;
+	struct netfront_info *np = netdev_priv(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&np->tx_lock, flags);
+
+	if (likely(netif_carrier_ok(dev))) {
+		xennet_tx_buf_gc(dev);
+		/* Under tx_lock: protects access to rx shared-ring indexes. */
+		if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx))
+			netif_rx_schedule(dev, &np->napi);
+	}
+
+	spin_unlock_irqrestore(&np->tx_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info)
+{
+	struct xen_netif_tx_sring *txs;
+	struct xen_netif_rx_sring *rxs;
+	int err;
+	struct net_device *netdev = info->netdev;
+
+	info->tx_ring_ref = GRANT_INVALID_REF;
+	info->rx_ring_ref = GRANT_INVALID_REF;
+	info->rx.sring = NULL;
+	info->tx.sring = NULL;
+	netdev->irq = 0;
+
+	err = xen_net_read_mac(dev, netdev->dev_addr);
+	if (err) {
+		xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
+		goto fail;
+	}
+
+	txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_KERNEL);
+	if (!txs) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(dev, err, "allocating tx ring page");
+		goto fail;
+	}
+	SHARED_RING_INIT(txs);
+	FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE);
+
+	err = xenbus_grant_ring(dev, virt_to_mfn(txs));
+	if (err < 0) {
+		free_page((unsigned long)txs);
+		goto fail;
+	}
+
+	info->tx_ring_ref = err;
+	rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_KERNEL);
+	if (!rxs) {
+		err = -ENOMEM;
+		xenbus_dev_fatal(dev, err, "allocating rx ring page");
+		goto fail;
+	}
+	SHARED_RING_INIT(rxs);
+	FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE);
+
+	err = xenbus_grant_ring(dev, virt_to_mfn(rxs));
+	if (err < 0) {
+		free_page((unsigned long)rxs);
+		goto fail;
+	}
+	info->rx_ring_ref = err;
+
+	err = xenbus_alloc_evtchn(dev, &info->evtchn);
+	if (err)
+		goto fail;
+
+	err = bind_evtchn_to_irqhandler(info->evtchn, xennet_interrupt,
+					IRQF_SAMPLE_RANDOM, netdev->name,
+					netdev);
+	if (err < 0)
+		goto fail;
+	netdev->irq = err;
+	return 0;
+
+ fail:
+	return err;
+}
+
+/* Common code used when first setting up, and when resuming. */
+static int talk_to_backend(struct xenbus_device *dev,
+			   struct netfront_info *info)
+{
+	const char *message;
+	struct xenbus_transaction xbt;
+	int err;
+
+	/* Create shared ring, alloc event channel. */
+	err = setup_netfront(dev, info);
+	if (err)
+		goto out;
+
+again:
+	err = xenbus_transaction_start(&xbt);
+	if (err) {
+		xenbus_dev_fatal(dev, err, "starting transaction");
+		goto destroy_ring;
+	}
+
+	err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref", "%u",
+			    info->tx_ring_ref);
+	if (err) {
+		message = "writing tx ring-ref";
+		goto abort_transaction;
+	}
+	err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref", "%u",
+			    info->rx_ring_ref);
+	if (err) {
+		message = "writing rx ring-ref";
+		goto abort_transaction;
+	}
+	err = xenbus_printf(xbt, dev->nodename,
+			    "event-channel", "%u", info->evtchn);
+	if (err) {
+		message = "writing event-channel";
+		goto abort_transaction;
+	}
+
+	err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u",
+			    1);
+	if (err) {
+		message = "writing request-rx-copy";
+		goto abort_transaction;
+	}
+
+	err = xenbus_printf(xbt, dev->nodename, "feature-rx-notify", "%d", 1);
+	if (err) {
+		message = "writing feature-rx-notify";
+		goto abort_transaction;
+	}
+
+	err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1);
+	if (err) {
+		message = "writing feature-sg";
+		goto abort_transaction;
+	}
+
+	err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1);
+	if (err) {
+		message = "writing feature-gso-tcpv4";
+		goto abort_transaction;
+	}
+
+	err = xenbus_transaction_end(xbt, 0);
+	if (err) {
+		if (err == -EAGAIN)
+			goto again;
+		xenbus_dev_fatal(dev, err, "completing transaction");
+		goto destroy_ring;
+	}
+
+	return 0;
+
+ abort_transaction:
+	xenbus_transaction_end(xbt, 1);
+	xenbus_dev_fatal(dev, err, "%s", message);
+ destroy_ring:
+	xennet_disconnect_backend(info);
+ out:
+	return err;
+}
+
+static int xennet_set_sg(struct net_device *dev, u32 data)
+{
+	if (data) {
+		struct netfront_info *np = netdev_priv(dev);
+		int val;
+
+		if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg",
+				 "%d", &val) < 0)
+			val = 0;
+		if (!val)
+			return -ENOSYS;
+	} else if (dev->mtu > ETH_DATA_LEN)
+		dev->mtu = ETH_DATA_LEN;
+
+	return ethtool_op_set_sg(dev, data);
+}
+
+static int xennet_set_tso(struct net_device *dev, u32 data)
+{
+	if (data) {
+		struct netfront_info *np = netdev_priv(dev);
+		int val;
+
+		if (xenbus_scanf(XBT_NIL, np->xbdev->otherend,
+				 "feature-gso-tcpv4", "%d", &val) < 0)
+			val = 0;
+		if (!val)
+			return -ENOSYS;
+	}
+
+	return ethtool_op_set_tso(dev, data);
+}
+
+static void xennet_set_features(struct net_device *dev)
+{
+	/* Turn off all GSO bits except ROBUST. */
+	dev->features &= (1 << NETIF_F_GSO_SHIFT) - 1;
+	dev->features |= NETIF_F_GSO_ROBUST;
+	xennet_set_sg(dev, 0);
+
+	/* We need checksum offload to enable scatter/gather and TSO. */
+	if (!(dev->features & NETIF_F_IP_CSUM))
+		return;
+
+	if (!xennet_set_sg(dev, 1))
+		xennet_set_tso(dev, 1);
+}
+
+static int xennet_connect(struct net_device *dev)
+{
+	struct netfront_info *np = netdev_priv(dev);
+	int i, requeue_idx, err;
+	struct sk_buff *skb;
+	grant_ref_t ref;
+	struct xen_netif_rx_request *req;
+	unsigned int feature_rx_copy;
+
+	err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
+			   "feature-rx-copy", "%u", &feature_rx_copy);
+	if (err != 1)
+		feature_rx_copy = 0;
+
+	if (!feature_rx_copy) {
+		dev_info(&dev->dev,
+			 "backend does not support copying recieve path");
+		return -ENODEV;
+	}
+
+	err = talk_to_backend(np->xbdev, np);
+	if (err)
+		return err;
+
+	xennet_set_features(dev);
+
+	spin_lock_bh(&np->rx_lock);
+	spin_lock_irq(&np->tx_lock);
+
+	/* Step 1: Discard all pending TX packet fragments. */
+	xennet_release_tx_bufs(np);
+
+	/* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */
+	for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) {
+		if (!np->rx_skbs[i])
+			continue;
+
+		skb = np->rx_skbs[requeue_idx] = xennet_get_rx_skb(np, i);
+		ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i);
+		req = RING_GET_REQUEST(&np->rx, requeue_idx);
+
+		gnttab_grant_foreign_access_ref(
+			ref, np->xbdev->otherend_id,
+			pfn_to_mfn(page_to_pfn(skb_shinfo(skb)->
+					       frags->page)),
+			0);
+		req->gref = ref;
+		req->id   = requeue_idx;
+
+		requeue_idx++;
+	}
+
+	np->rx.req_prod_pvt = requeue_idx;
+
+	/*
+	 * Step 3: All public and private state should now be sane.  Get
+	 * ready to start sending and receiving packets and give the driver
+	 * domain a kick because we've probably just requeued some
+	 * packets.
+	 */
+	netif_carrier_on(np->netdev);
+	notify_remote_via_irq(np->netdev->irq);
+	xennet_tx_buf_gc(dev);
+	xennet_alloc_rx_buffers(dev);
+
+	spin_unlock_irq(&np->tx_lock);
+	spin_unlock_bh(&np->rx_lock);
+
+	return 0;
+}
+
+/**
+ * Callback received when the backend's state changes.
+ */
+static void backend_changed(struct xenbus_device *dev,
+			    enum xenbus_state backend_state)
+{
+	struct netfront_info *np = dev->dev.driver_data;
+	struct net_device *netdev = np->netdev;
+
+	dev_dbg(&dev->dev, "%s\n", xenbus_strstate(backend_state));
+
+	switch (backend_state) {
+	case XenbusStateInitialising:
+	case XenbusStateInitialised:
+	case XenbusStateConnected:
+	case XenbusStateUnknown:
+	case XenbusStateClosed:
+		break;
+
+	case XenbusStateInitWait:
+		if (dev->state != XenbusStateInitialising)
+			break;
+		if (xennet_connect(netdev) != 0)
+			break;
+		xenbus_switch_state(dev, XenbusStateConnected);
+		break;
+
+	case XenbusStateClosing:
+		xenbus_frontend_closed(dev);
+		break;
+	}
+}
+
+static struct ethtool_ops xennet_ethtool_ops =
+{
+	.set_tx_csum = ethtool_op_set_tx_csum,
+	.set_sg = xennet_set_sg,
+	.set_tso = xennet_set_tso,
+	.get_link = ethtool_op_get_link,
+};
+
+#ifdef CONFIG_SYSFS
+static ssize_t show_rxbuf_min(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct net_device *netdev = to_net_dev(dev);
+	struct netfront_info *info = netdev_priv(netdev);
+
+	return sprintf(buf, "%u\n", info->rx_min_target);
+}
+
+static ssize_t store_rxbuf_min(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t len)
+{
+	struct net_device *netdev = to_net_dev(dev);
+	struct netfront_info *np = netdev_priv(netdev);
+	char *endp;
+	unsigned long target;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	target = simple_strtoul(buf, &endp, 0);
+	if (endp == buf)
+		return -EBADMSG;
+
+	if (target < RX_MIN_TARGET)
+		target = RX_MIN_TARGET;
+	if (target > RX_MAX_TARGET)
+		target = RX_MAX_TARGET;
+
+	spin_lock_bh(&np->rx_lock);
+	if (target > np->rx_max_target)
+		np->rx_max_target = target;
+	np->rx_min_target = target;
+	if (target > np->rx_target)
+		np->rx_target = target;
+
+	xennet_alloc_rx_buffers(netdev);
+
+	spin_unlock_bh(&np->rx_lock);
+	return len;
+}
+
+static ssize_t show_rxbuf_max(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct net_device *netdev = to_net_dev(dev);
+	struct netfront_info *info = netdev_priv(netdev);
+
+	return sprintf(buf, "%u\n", info->rx_max_target);
+}
+
+static ssize_t store_rxbuf_max(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t len)
+{
+	struct net_device *netdev = to_net_dev(dev);
+	struct netfront_info *np = netdev_priv(netdev);
+	char *endp;
+	unsigned long target;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	target = simple_strtoul(buf, &endp, 0);
+	if (endp == buf)
+		return -EBADMSG;
+
+	if (target < RX_MIN_TARGET)
+		target = RX_MIN_TARGET;
+	if (target > RX_MAX_TARGET)
+		target = RX_MAX_TARGET;
+
+	spin_lock_bh(&np->rx_lock);
+	if (target < np->rx_min_target)
+		np->rx_min_target = target;
+	np->rx_max_target = target;
+	if (target < np->rx_target)
+		np->rx_target = target;
+
+	xennet_alloc_rx_buffers(netdev);
+
+	spin_unlock_bh(&np->rx_lock);
+	return len;
+}
+
+static ssize_t show_rxbuf_cur(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct net_device *netdev = to_net_dev(dev);
+	struct netfront_info *info = netdev_priv(netdev);
+
+	return sprintf(buf, "%u\n", info->rx_target);
+}
+
+static struct device_attribute xennet_attrs[] = {
+	__ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf_min, store_rxbuf_min),
+	__ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf_max, store_rxbuf_max),
+	__ATTR(rxbuf_cur, S_IRUGO, show_rxbuf_cur, NULL),
+};
+
+static int xennet_sysfs_addif(struct net_device *netdev)
+{
+	int i;
+	int err;
+
+	for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) {
+		err = device_create_file(&netdev->dev,
+					   &xennet_attrs[i]);
+		if (err)
+			goto fail;
+	}
+	return 0;
+
+ fail:
+	while (--i >= 0)
+		device_remove_file(&netdev->dev, &xennet_attrs[i]);
+	return err;
+}
+
+static void xennet_sysfs_delif(struct net_device *netdev)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++)
+		device_remove_file(&netdev->dev, &xennet_attrs[i]);
+}
+
+#endif /* CONFIG_SYSFS */
+
+static struct xenbus_device_id netfront_ids[] = {
+	{ "vif" },
+	{ "" }
+};
+
+
+static int __devexit xennet_remove(struct xenbus_device *dev)
+{
+	struct netfront_info *info = dev->dev.driver_data;
+
+	dev_dbg(&dev->dev, "%s\n", dev->nodename);
+
+	unregister_netdev(info->netdev);
+
+	xennet_disconnect_backend(info);
+
+	del_timer_sync(&info->rx_refill_timer);
+
+	xennet_sysfs_delif(info->netdev);
+
+	free_netdev(info->netdev);
+
+	return 0;
+}
+
+static struct xenbus_driver netfront = {
+	.name = "vif",
+	.owner = THIS_MODULE,
+	.ids = netfront_ids,
+	.probe = netfront_probe,
+	.remove = __devexit_p(xennet_remove),
+	.resume = netfront_resume,
+	.otherend_changed = backend_changed,
+};
+
+static int __init netif_init(void)
+{
+	if (!is_running_on_xen())
+		return -ENODEV;
+
+	if (is_initial_xendomain())
+		return 0;
+
+	printk(KERN_INFO "Initialising Xen virtual ethernet driver.\n");
+
+	return xenbus_register_frontend(&netfront);
+}
+module_init(netif_init);
+
+
+static void __exit netif_exit(void)
+{
+	if (is_initial_xendomain())
+		return;
+
+	return xenbus_unregister_driver(&netfront);
+}
+module_exit(netif_exit);
+
+MODULE_DESCRIPTION("Xen virtual network device frontend");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 870c539..87f002a 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -318,7 +318,6 @@
 	dma_addr_t tx_status_dma;
 
 	struct timer_list timer;	/* Media selection timer. */
-	struct net_device_stats stats;
 	/* Frequently used and paired value: keep adjacent for cache effect. */
 	int chip_id, drv_flags;
 	struct pci_dev *pci_dev;
@@ -353,7 +352,6 @@
 static int yellowfin_rx(struct net_device *dev);
 static void yellowfin_error(struct net_device *dev, int intr_status);
 static int yellowfin_close(struct net_device *dev);
-static struct net_device_stats *yellowfin_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
 static const struct ethtool_ops ethtool_ops;
 
@@ -376,6 +374,7 @@
 #else
 	int bar = 1;
 #endif
+	DECLARE_MAC_BUF(mac);
 
 /* when built into the kernel, we only print version if device is found */
 #ifndef MODULE
@@ -392,7 +391,6 @@
 		printk (KERN_ERR PFX "cannot allocate ethernet device\n");
 		return -ENOMEM;
 	}
-	SET_MODULE_OWNER(dev);
 	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	np = netdev_priv(dev);
@@ -470,7 +468,6 @@
 	dev->open = &yellowfin_open;
 	dev->hard_start_xmit = &yellowfin_start_xmit;
 	dev->stop = &yellowfin_close;
-	dev->get_stats = &yellowfin_get_stats;
 	dev->set_multicast_list = &set_rx_mode;
 	dev->do_ioctl = &netdev_ioctl;
 	SET_ETHTOOL_OPS(dev, &ethtool_ops);
@@ -484,12 +481,10 @@
 	if (i)
 		goto err_out_unmap_status;
 
-	printk(KERN_INFO "%s: %s type %8x at %p, ",
+	printk(KERN_INFO "%s: %s type %8x at %p, %s, IRQ %d.\n",
 		   dev->name, pci_id_tbl[chip_idx].name,
-		   ioread32(ioaddr + ChipRev), ioaddr);
-	for (i = 0; i < 5; i++)
-			printk("%2.2x:", dev->dev_addr[i]);
-	printk("%2.2x, IRQ %d.\n", dev->dev_addr[i], irq);
+		   ioread32(ioaddr + ChipRev), ioaddr,
+		   print_mac(mac, dev->dev_addr), irq);
 
 	if (np->drv_flags & HasMII) {
 		int phy, phy_idx = 0;
@@ -718,7 +713,7 @@
 		netif_wake_queue (dev);		/* Typical path */
 
 	dev->trans_start = jiffies;
-	yp->stats.tx_errors++;
+	dev->stats.tx_errors++;
 }
 
 /* Initialize the Rx and Tx rings, along with various 'dev' bits. */
@@ -924,8 +919,8 @@
 			if (yp->tx_ring[entry].result_status == 0)
 				break;
 			skb = yp->tx_skbuff[entry];
-			yp->stats.tx_packets++;
-			yp->stats.tx_bytes += skb->len;
+			dev->stats.tx_packets++;
+			dev->stats.tx_bytes += skb->len;
 			/* Free the original skb. */
 			pci_unmap_single(yp->pci_dev, yp->tx_ring[entry].addr,
 				skb->len, PCI_DMA_TODEVICE);
@@ -969,20 +964,20 @@
 						printk(KERN_DEBUG "%s: Transmit error, Tx status %4.4x.\n",
 							   dev->name, tx_errs);
 #endif
-					yp->stats.tx_errors++;
-					if (tx_errs & 0xF800) yp->stats.tx_aborted_errors++;
-					if (tx_errs & 0x0800) yp->stats.tx_carrier_errors++;
-					if (tx_errs & 0x2000) yp->stats.tx_window_errors++;
-					if (tx_errs & 0x8000) yp->stats.tx_fifo_errors++;
+					dev->stats.tx_errors++;
+					if (tx_errs & 0xF800) dev->stats.tx_aborted_errors++;
+					if (tx_errs & 0x0800) dev->stats.tx_carrier_errors++;
+					if (tx_errs & 0x2000) dev->stats.tx_window_errors++;
+					if (tx_errs & 0x8000) dev->stats.tx_fifo_errors++;
 				} else {
 #ifndef final_version
 					if (yellowfin_debug > 4)
 						printk(KERN_DEBUG "%s: Normal transmit, Tx status %4.4x.\n",
 							   dev->name, tx_errs);
 #endif
-					yp->stats.tx_bytes += skb->len;
-					yp->stats.collisions += tx_errs & 15;
-					yp->stats.tx_packets++;
+					dev->stats.tx_bytes += skb->len;
+					dev->stats.collisions += tx_errs & 15;
+					dev->stats.tx_packets++;
 				}
 				/* Free the original skb. */
 				pci_unmap_single(yp->pci_dev,
@@ -1077,26 +1072,26 @@
 			if (data_size != 0)
 				printk(KERN_WARNING "%s: Oversized Ethernet frame spanned multiple buffers,"
 					   " status %4.4x, data_size %d!\n", dev->name, desc_status, data_size);
-			yp->stats.rx_length_errors++;
+			dev->stats.rx_length_errors++;
 		} else if ((yp->drv_flags & IsGigabit)  &&  (frame_status & 0x0038)) {
 			/* There was a error. */
 			if (yellowfin_debug > 3)
 				printk(KERN_DEBUG "  yellowfin_rx() Rx error was %4.4x.\n",
 					   frame_status);
-			yp->stats.rx_errors++;
-			if (frame_status & 0x0060) yp->stats.rx_length_errors++;
-			if (frame_status & 0x0008) yp->stats.rx_frame_errors++;
-			if (frame_status & 0x0010) yp->stats.rx_crc_errors++;
-			if (frame_status < 0) yp->stats.rx_dropped++;
+			dev->stats.rx_errors++;
+			if (frame_status & 0x0060) dev->stats.rx_length_errors++;
+			if (frame_status & 0x0008) dev->stats.rx_frame_errors++;
+			if (frame_status & 0x0010) dev->stats.rx_crc_errors++;
+			if (frame_status < 0) dev->stats.rx_dropped++;
 		} else if ( !(yp->drv_flags & IsGigabit)  &&
 				   ((buf_addr[data_size-1] & 0x85) || buf_addr[data_size-2] & 0xC0)) {
 			u8 status1 = buf_addr[data_size-2];
 			u8 status2 = buf_addr[data_size-1];
-			yp->stats.rx_errors++;
-			if (status1 & 0xC0) yp->stats.rx_length_errors++;
-			if (status2 & 0x03) yp->stats.rx_frame_errors++;
-			if (status2 & 0x04) yp->stats.rx_crc_errors++;
-			if (status2 & 0x80) yp->stats.rx_dropped++;
+			dev->stats.rx_errors++;
+			if (status1 & 0xC0) dev->stats.rx_length_errors++;
+			if (status2 & 0x03) dev->stats.rx_frame_errors++;
+			if (status2 & 0x04) dev->stats.rx_crc_errors++;
+			if (status2 & 0x80) dev->stats.rx_dropped++;
 #ifdef YF_PROTOTYPE		/* Support for prototype hardware errata. */
 		} else if ((yp->flags & HasMACAddrBug)  &&
 			memcmp(le32_to_cpu(yp->rx_ring_dma +
@@ -1105,11 +1100,11 @@
 			memcmp(le32_to_cpu(yp->rx_ring_dma +
 				entry*sizeof(struct yellowfin_desc)),
 				"\377\377\377\377\377\377", 6) != 0) {
-			if (bogus_rx++ == 0)
-				printk(KERN_WARNING "%s: Bad frame to %2.2x:%2.2x:%2.2x:%2.2x:"
-					   "%2.2x:%2.2x.\n",
-					   dev->name, buf_addr[0], buf_addr[1], buf_addr[2],
-					   buf_addr[3], buf_addr[4], buf_addr[5]);
+			if (bogus_rx++ == 0) {
+				DECLARE_MAC_BUF(mac);
+				printk(KERN_WARNING "%s: Bad frame to %s\n",
+					   dev->name, print_mac(mac, buf_addr));
+			}
 #endif
 		} else {
 			struct sk_buff *skb;
@@ -1146,8 +1141,8 @@
 			skb->protocol = eth_type_trans(skb, dev);
 			netif_rx(skb);
 			dev->last_rx = jiffies;
-			yp->stats.rx_packets++;
-			yp->stats.rx_bytes += pkt_len;
+			dev->stats.rx_packets++;
+			dev->stats.rx_bytes += pkt_len;
 		}
 		entry = (++yp->cur_rx) % RX_RING_SIZE;
 	}
@@ -1181,15 +1176,13 @@
 
 static void yellowfin_error(struct net_device *dev, int intr_status)
 {
-	struct yellowfin_private *yp = netdev_priv(dev);
-
 	printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
 		   dev->name, intr_status);
 	/* Hmmmmm, it's not clear what to do here. */
 	if (intr_status & (IntrTxPCIErr | IntrTxPCIFault))
-		yp->stats.tx_errors++;
+		dev->stats.tx_errors++;
 	if (intr_status & (IntrRxPCIErr | IntrRxPCIFault))
-		yp->stats.rx_errors++;
+		dev->stats.rx_errors++;
 }
 
 static int yellowfin_close(struct net_device *dev)
@@ -1281,12 +1274,6 @@
 	return 0;
 }
 
-static struct net_device_stats *yellowfin_get_stats(struct net_device *dev)
-{
-	struct yellowfin_private *yp = netdev_priv(dev);
-	return &yp->stats;
-}
-
 /* Set or clear the multicast filter for this adaptor. */
 
 static void set_rx_mode(struct net_device *dev)
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index 4032e9f..a86c022 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -128,7 +128,6 @@
 
 struct znet_private {
 	int rx_dma, tx_dma;
-	struct net_device_stats stats;
 	spinlock_t lock;
 	short sia_base, sia_size, io_size;
 	struct i82593_conf_block i593_init;
@@ -161,7 +160,6 @@
 static irqreturn_t znet_interrupt(int irq, void *dev_id);
 static void	znet_rx(struct net_device *dev);
 static int	znet_close(struct net_device *dev);
-static struct net_device_stats *net_get_stats(struct net_device *dev);
 static void hardware_init(struct net_device *dev);
 static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset);
 static void znet_tx_timeout (struct net_device *dev);
@@ -372,6 +370,7 @@
 	struct net_device *dev;
 	char *p;
 	int err = -ENOMEM;
+	DECLARE_MAC_BUF(mac);
 
 	/* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */
 	for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++)
@@ -388,22 +387,20 @@
 	if (!dev)
 		return -ENOMEM;
 
-	SET_MODULE_OWNER (dev);
-
 	znet = dev->priv;
 
 	netinfo = (struct netidblk *)p;
 	dev->base_addr = netinfo->iobase1;
 	dev->irq = netinfo->irq1;
 
-	printk(KERN_INFO "%s: ZNET at %#3lx,", dev->name, dev->base_addr);
-
 	/* The station address is in the "netidblk" at 0x0f0000. */
 	for (i = 0; i < 6; i++)
-		printk(" %2.2x", dev->dev_addr[i] = netinfo->netid[i]);
+		dev->dev_addr[i] = netinfo->netid[i];
 
-	printk(", using IRQ %d DMA %d and %d.\n", dev->irq, netinfo->dma1,
-	       netinfo->dma2);
+	printk(KERN_INFO "%s: ZNET at %#3lx, %s"
+	       ", using IRQ %d DMA %d and %d.\n",
+	       dev->name, dev->base_addr, print_mac(mac, dev->dev_addr),
+	       dev->irq, netinfo->dma1, netinfo->dma2);
 
 	if (znet_debug > 1) {
 		printk(KERN_INFO "%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n",
@@ -447,7 +444,6 @@
 	dev->open = &znet_open;
 	dev->hard_start_xmit = &znet_send_packet;
 	dev->stop = &znet_close;
-	dev->get_stats	= net_get_stats;
 	dev->set_multicast_list = &znet_set_multicast_list;
 	dev->tx_timeout = znet_tx_timeout;
 	dev->watchdog_timeo = TX_TIMEOUT;
@@ -566,7 +562,7 @@
 		ushort *tx_link = znet->tx_cur - 1;
 		ushort rnd_len = (length + 1)>>1;
 
-		znet->stats.tx_bytes+=length;
+		dev->stats.tx_bytes+=length;
 
 		if (znet->tx_cur >= znet->tx_end)
 		  znet->tx_cur = znet->tx_start;
@@ -641,20 +637,20 @@
 			tx_status = inw(ioaddr);
 			/* It's undocumented, but tx_status seems to match the i82586. */
 			if (tx_status & TX_OK) {
-				znet->stats.tx_packets++;
-				znet->stats.collisions += tx_status & TX_NCOL_MASK;
+				dev->stats.tx_packets++;
+				dev->stats.collisions += tx_status & TX_NCOL_MASK;
 			} else {
 				if (tx_status & (TX_LOST_CTS | TX_LOST_CRS))
-					znet->stats.tx_carrier_errors++;
+					dev->stats.tx_carrier_errors++;
 				if (tx_status & TX_UND_RUN)
-					znet->stats.tx_fifo_errors++;
+					dev->stats.tx_fifo_errors++;
 				if (!(tx_status & TX_HRT_BEAT))
-					znet->stats.tx_heartbeat_errors++;
+					dev->stats.tx_heartbeat_errors++;
 				if (tx_status & TX_MAX_COL)
-					znet->stats.tx_aborted_errors++;
+					dev->stats.tx_aborted_errors++;
 				/* ...and the catch-all. */
 				if ((tx_status | (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) != (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL))
-					znet->stats.tx_errors++;
+					dev->stats.tx_errors++;
 
 				/* Transceiver may be stuck if cable
 				 * was removed while emiting a
@@ -750,19 +746,19 @@
 				 this_rfp_ptr[-3]<<1);
 		/* Once again we must assume that the i82586 docs apply. */
 		if ( ! (status & RX_RCV_OK)) { /* There was an error. */
-			znet->stats.rx_errors++;
-			if (status & RX_CRC_ERR) znet->stats.rx_crc_errors++;
-			if (status & RX_ALG_ERR) znet->stats.rx_frame_errors++;
+			dev->stats.rx_errors++;
+			if (status & RX_CRC_ERR) dev->stats.rx_crc_errors++;
+			if (status & RX_ALG_ERR) dev->stats.rx_frame_errors++;
 #if 0
-			if (status & 0x0200) znet->stats.rx_over_errors++; /* Wrong. */
-			if (status & 0x0100) znet->stats.rx_fifo_errors++;
+			if (status & 0x0200) dev->stats.rx_over_errors++; /* Wrong. */
+			if (status & 0x0100) dev->stats.rx_fifo_errors++;
 #else
 			/* maz : Wild guess... */
-			if (status & RX_OVRRUN) znet->stats.rx_over_errors++;
+			if (status & RX_OVRRUN) dev->stats.rx_over_errors++;
 #endif
-			if (status & RX_SRT_FRM) znet->stats.rx_length_errors++;
+			if (status & RX_SRT_FRM) dev->stats.rx_length_errors++;
 		} else if (pkt_len > 1536) {
-			znet->stats.rx_length_errors++;
+			dev->stats.rx_length_errors++;
 		} else {
 			/* Malloc up new buffer. */
 			struct sk_buff *skb;
@@ -771,7 +767,7 @@
 			if (skb == NULL) {
 				if (znet_debug)
 				  printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);
-				znet->stats.rx_dropped++;
+				dev->stats.rx_dropped++;
 				break;
 			}
 
@@ -791,8 +787,8 @@
 		  skb->protocol=eth_type_trans(skb,dev);
 		  netif_rx(skb);
 		  dev->last_rx = jiffies;
-		  znet->stats.rx_packets++;
-		  znet->stats.rx_bytes += pkt_len;
+		  dev->stats.rx_packets++;
+		  dev->stats.rx_bytes += pkt_len;
 		}
 		znet->rx_cur = this_rfp_ptr;
 		if (znet->rx_cur >= znet->rx_end)
@@ -829,15 +825,6 @@
 	return 0;
 }
 
-/* Get the current statistics.	This may be called with the card open or
-   closed. */
-static struct net_device_stats *net_get_stats(struct net_device *dev)
-{
-	struct znet_private *znet = dev->priv;
-
-	return &znet->stats;
-}
-
 static void show_dma(struct net_device *dev)
 {
 	short ioaddr = dev->base_addr;
diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c
index d85e2ea..3926b2a 100644
--- a/drivers/net/zorro8390.c
+++ b/drivers/net/zorro8390.c
@@ -125,7 +125,6 @@
     dev = ____alloc_ei_netdev(0);
     if (!dev)
 	return -ENOMEM;
-    SET_MODULE_OWNER(dev);
     if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, DRV_NAME)) {
 	free_netdev(dev);
 	return -EBUSY;
@@ -152,6 +151,7 @@
 	0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
 	0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
     };
+    DECLARE_MAC_BUF(mac);
 
     /* Reset card. Who knows what dain-bramaged state it was left in. */
     {
@@ -191,7 +191,7 @@
 	    {0x00,	NE_EN0_RSARHI},
 	    {E8390_RREAD+E8390_START, NE_CMD},
 	};
-	for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) {
+	for (i = 0; i < ARRAY_SIZE(program_seq); i++) {
 	    z_writeb(program_seq[i].value, ioaddr + program_seq[i].offset);
 	}
     }
@@ -212,12 +212,12 @@
     i = request_irq(IRQ_AMIGA_PORTS, __ei_interrupt, IRQF_SHARED, DRV_NAME, dev);
     if (i) return i;
 
-    for(i = 0; i < ETHER_ADDR_LEN; i++) {
-#ifdef DEBUG
-	printk(" %2.2x", SA_prom[i]);
-#endif
+    for(i = 0; i < ETHER_ADDR_LEN; i++)
 	dev->dev_addr[i] = SA_prom[i];
-    }
+
+#ifdef DEBUG
+    printk("%s", print_mac(mac, dev->dev_addr));
+#endif
 
     ei_status.name = name;
     ei_status.tx_start_page = start_page;
@@ -244,10 +244,8 @@
 	return err;
     }
 
-    printk(KERN_INFO "%s: %s at 0x%08lx, Ethernet Address "
-	   "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, name, board,
-	   dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-	   dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+    printk(KERN_INFO "%s: %s at 0x%08lx, Ethernet Address %s\n",
+	   dev->name, name, board, print_mac(mac, dev->dev_addr));
 
     return 0;
 }
diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c
index 3a0a3a7..e503c9c 100644
--- a/drivers/nubus/nubus.c
+++ b/drivers/nubus/nubus.c
@@ -466,9 +466,8 @@
 		       parent->base, dir.base);
 
 	/* Actually we should probably panic if this fails */
-	if ((dev = kmalloc(sizeof(*dev), GFP_ATOMIC)) == NULL)
+	if ((dev = kzalloc(sizeof(*dev), GFP_ATOMIC)) == NULL)
 		return NULL;	
-	memset(dev, 0, sizeof(*dev));
 	dev->resid = parent->type;
 	dev->directory = dir.base;
 	dev->board = board;
@@ -800,9 +799,8 @@
 	nubus_rewind(&rp, FORMAT_BLOCK_SIZE, bytelanes);
 
 	/* Actually we should probably panic if this fails */
-	if ((board = kmalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
+	if ((board = kzalloc(sizeof(*board), GFP_ATOMIC)) == NULL)
 		return NULL;	
-	memset(board, 0, sizeof(*board));
 	board->fblock = rp;
 
 	/* Dump the format block for debugging purposes */
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
new file mode 100644
index 0000000..c03072b
--- /dev/null
+++ b/drivers/of/Kconfig
@@ -0,0 +1,3 @@
+config OF_DEVICE
+	def_bool y
+	depends on OF && (SPARC || PPC_OF)
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
new file mode 100644
index 0000000..ab9be5d
--- /dev/null
+++ b/drivers/of/Makefile
@@ -0,0 +1,2 @@
+obj-y = base.o
+obj-$(CONFIG_OF_DEVICE) += device.o platform.o
diff --git a/drivers/of/base.c b/drivers/of/base.c
new file mode 100644
index 0000000..9377f3b
--- /dev/null
+++ b/drivers/of/base.c
@@ -0,0 +1,275 @@
+/*
+ * Procedures for creating, accessing and interpreting the device tree.
+ *
+ * Paul Mackerras	August 1996.
+ * Copyright (C) 1996-2005 Paul Mackerras.
+ *
+ *  Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner.
+ *    {engebret|bergner}@us.ibm.com
+ *
+ *  Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net
+ *
+ *  Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell.
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spinlock.h>
+
+struct device_node *allnodes;
+
+/* use when traversing tree through the allnext, child, sibling,
+ * or parent members of struct device_node.
+ */
+DEFINE_RWLOCK(devtree_lock);
+
+int of_n_addr_cells(struct device_node *np)
+{
+	const int *ip;
+
+	do {
+		if (np->parent)
+			np = np->parent;
+		ip = of_get_property(np, "#address-cells", NULL);
+		if (ip)
+			return *ip;
+	} while (np->parent);
+	/* No #address-cells property for the root node */
+	return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_addr_cells);
+
+int of_n_size_cells(struct device_node *np)
+{
+	const int *ip;
+
+	do {
+		if (np->parent)
+			np = np->parent;
+		ip = of_get_property(np, "#size-cells", NULL);
+		if (ip)
+			return *ip;
+	} while (np->parent);
+	/* No #size-cells property for the root node */
+	return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_size_cells);
+
+struct property *of_find_property(const struct device_node *np,
+				  const char *name,
+				  int *lenp)
+{
+	struct property *pp;
+
+	read_lock(&devtree_lock);
+	for (pp = np->properties; pp != 0; pp = pp->next) {
+		if (of_prop_cmp(pp->name, name) == 0) {
+			if (lenp != 0)
+				*lenp = pp->length;
+			break;
+		}
+	}
+	read_unlock(&devtree_lock);
+
+	return pp;
+}
+EXPORT_SYMBOL(of_find_property);
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+const void *of_get_property(const struct device_node *np, const char *name,
+			 int *lenp)
+{
+	struct property *pp = of_find_property(np, name, lenp);
+
+	return pp ? pp->value : NULL;
+}
+EXPORT_SYMBOL(of_get_property);
+
+/** Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+int of_device_is_compatible(const struct device_node *device,
+		const char *compat)
+{
+	const char* cp;
+	int cplen, l;
+
+	cp = of_get_property(device, "compatible", &cplen);
+	if (cp == NULL)
+		return 0;
+	while (cplen > 0) {
+		if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
+			return 1;
+		l = strlen(cp) + 1;
+		cp += l;
+		cplen -= l;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(of_device_is_compatible);
+
+/**
+ *	of_get_parent - Get a node's parent if any
+ *	@node:	Node to get parent
+ *
+ *	Returns a node pointer with refcount incremented, use
+ *	of_node_put() on it when done.
+ */
+struct device_node *of_get_parent(const struct device_node *node)
+{
+	struct device_node *np;
+
+	if (!node)
+		return NULL;
+
+	read_lock(&devtree_lock);
+	np = of_node_get(node->parent);
+	read_unlock(&devtree_lock);
+	return np;
+}
+EXPORT_SYMBOL(of_get_parent);
+
+/**
+ *	of_get_next_child - Iterate a node childs
+ *	@node:	parent node
+ *	@prev:	previous child of the parent node, or NULL to get first
+ *
+ *	Returns a node pointer with refcount incremented, use
+ *	of_node_put() on it when done.
+ */
+struct device_node *of_get_next_child(const struct device_node *node,
+	struct device_node *prev)
+{
+	struct device_node *next;
+
+	read_lock(&devtree_lock);
+	next = prev ? prev->sibling : node->child;
+	for (; next; next = next->sibling)
+		if (of_node_get(next))
+			break;
+	of_node_put(prev);
+	read_unlock(&devtree_lock);
+	return next;
+}
+EXPORT_SYMBOL(of_get_next_child);
+
+/**
+ *	of_find_node_by_path - Find a node matching a full OF path
+ *	@path:	The full path to match
+ *
+ *	Returns a node pointer with refcount incremented, use
+ *	of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_path(const char *path)
+{
+	struct device_node *np = allnodes;
+
+	read_lock(&devtree_lock);
+	for (; np; np = np->allnext) {
+		if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
+		    && of_node_get(np))
+			break;
+	}
+	read_unlock(&devtree_lock);
+	return np;
+}
+EXPORT_SYMBOL(of_find_node_by_path);
+
+/**
+ *	of_find_node_by_name - Find a node by its "name" property
+ *	@from:	The node to start searching from or NULL, the node
+ *		you pass will not be searched, only the next one
+ *		will; typically, you pass what the previous call
+ *		returned. of_node_put() will be called on it
+ *	@name:	The name string to match against
+ *
+ *	Returns a node pointer with refcount incremented, use
+ *	of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_name(struct device_node *from,
+	const char *name)
+{
+	struct device_node *np;
+
+	read_lock(&devtree_lock);
+	np = from ? from->allnext : allnodes;
+	for (; np; np = np->allnext)
+		if (np->name && (of_node_cmp(np->name, name) == 0)
+		    && of_node_get(np))
+			break;
+	of_node_put(from);
+	read_unlock(&devtree_lock);
+	return np;
+}
+EXPORT_SYMBOL(of_find_node_by_name);
+
+/**
+ *	of_find_node_by_type - Find a node by its "device_type" property
+ *	@from:	The node to start searching from, or NULL to start searching
+ *		the entire device tree. The node you pass will not be
+ *		searched, only the next one will; typically, you pass
+ *		what the previous call returned. of_node_put() will be
+ *		called on from for you.
+ *	@type:	The type string to match against
+ *
+ *	Returns a node pointer with refcount incremented, use
+ *	of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_type(struct device_node *from,
+	const char *type)
+{
+	struct device_node *np;
+
+	read_lock(&devtree_lock);
+	np = from ? from->allnext : allnodes;
+	for (; np; np = np->allnext)
+		if (np->type && (of_node_cmp(np->type, type) == 0)
+		    && of_node_get(np))
+			break;
+	of_node_put(from);
+	read_unlock(&devtree_lock);
+	return np;
+}
+EXPORT_SYMBOL(of_find_node_by_type);
+
+/**
+ *	of_find_compatible_node - Find a node based on type and one of the
+ *                                tokens in its "compatible" property
+ *	@from:		The node to start searching from or NULL, the node
+ *			you pass will not be searched, only the next one
+ *			will; typically, you pass what the previous call
+ *			returned. of_node_put() will be called on it
+ *	@type:		The type string to match "device_type" or NULL to ignore
+ *	@compatible:	The string to match to one of the tokens in the device
+ *			"compatible" list.
+ *
+ *	Returns a node pointer with refcount incremented, use
+ *	of_node_put() on it when done.
+ */
+struct device_node *of_find_compatible_node(struct device_node *from,
+	const char *type, const char *compatible)
+{
+	struct device_node *np;
+
+	read_lock(&devtree_lock);
+	np = from ? from->allnext : allnodes;
+	for (; np; np = np->allnext) {
+		if (type
+		    && !(np->type && (of_node_cmp(np->type, type) == 0)))
+			continue;
+		if (of_device_is_compatible(np, compatible) && of_node_get(np))
+			break;
+	}
+	of_node_put(from);
+	read_unlock(&devtree_lock);
+	return np;
+}
+EXPORT_SYMBOL(of_find_compatible_node);
diff --git a/drivers/of/device.c b/drivers/of/device.c
new file mode 100644
index 0000000..6245f06
--- /dev/null
+++ b/drivers/of/device.c
@@ -0,0 +1,131 @@
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/slab.h>
+
+#include <asm/errno.h>
+
+/**
+ * of_match_node - Tell if an device_node has a matching of_match structure
+ * @ids: array of of device match structures to search in
+ * @node: the of device structure to match against
+ *
+ * Low level utility function used by device matching.
+ */
+const struct of_device_id *of_match_node(const struct of_device_id *matches,
+					 const struct device_node *node)
+{
+	while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
+		int match = 1;
+		if (matches->name[0])
+			match &= node->name
+				&& !strcmp(matches->name, node->name);
+		if (matches->type[0])
+			match &= node->type
+				&& !strcmp(matches->type, node->type);
+		if (matches->compatible[0])
+			match &= of_device_is_compatible(node,
+						matches->compatible);
+		if (match)
+			return matches;
+		matches++;
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(of_match_node);
+
+/**
+ * of_match_device - Tell if an of_device structure has a matching
+ * of_match structure
+ * @ids: array of of device match structures to search in
+ * @dev: the of device structure to match against
+ *
+ * Used by a driver to check whether an of_device present in the
+ * system is in its list of supported devices.
+ */
+const struct of_device_id *of_match_device(const struct of_device_id *matches,
+					const struct of_device *dev)
+{
+	if (!dev->node)
+		return NULL;
+	return of_match_node(matches, dev->node);
+}
+EXPORT_SYMBOL(of_match_device);
+
+struct of_device *of_dev_get(struct of_device *dev)
+{
+	struct device *tmp;
+
+	if (!dev)
+		return NULL;
+	tmp = get_device(&dev->dev);
+	if (tmp)
+		return to_of_device(tmp);
+	else
+		return NULL;
+}
+EXPORT_SYMBOL(of_dev_get);
+
+void of_dev_put(struct of_device *dev)
+{
+	if (dev)
+		put_device(&dev->dev);
+}
+EXPORT_SYMBOL(of_dev_put);
+
+static ssize_t dev_show_devspec(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct of_device *ofdev;
+
+	ofdev = to_of_device(dev);
+	return sprintf(buf, "%s", ofdev->node->full_name);
+}
+
+static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
+
+/**
+ * of_release_dev - free an of device structure when all users of it are finished.
+ * @dev: device that's been disconnected
+ *
+ * Will be called only by the device core when all users of this of device are
+ * done.
+ */
+void of_release_dev(struct device *dev)
+{
+	struct of_device *ofdev;
+
+	ofdev = to_of_device(dev);
+	of_node_put(ofdev->node);
+	kfree(ofdev);
+}
+EXPORT_SYMBOL(of_release_dev);
+
+int of_device_register(struct of_device *ofdev)
+{
+	int rc;
+
+	BUG_ON(ofdev->node == NULL);
+
+	rc = device_register(&ofdev->dev);
+	if (rc)
+		return rc;
+
+	rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
+	if (rc)
+		device_unregister(&ofdev->dev);
+
+	return rc;
+}
+EXPORT_SYMBOL(of_device_register);
+
+void of_device_unregister(struct of_device *ofdev)
+{
+	device_remove_file(&ofdev->dev, &dev_attr_devspec);
+	device_unregister(&ofdev->dev);
+}
+EXPORT_SYMBOL(of_device_unregister);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
new file mode 100644
index 0000000..864f09f
--- /dev/null
+++ b/drivers/of/platform.c
@@ -0,0 +1,96 @@
+/*
+ *    Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp.
+ *			 <benh@kernel.crashing.org>
+ *    and		 Arnd Bergmann, IBM Corp.
+ *    Merged from powerpc/kernel/of_platform.c and
+ *    sparc{,64}/kernel/of_device.c by Stephen Rothwell
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  as published by the Free Software Foundation; either version
+ *  2 of the License, or (at your option) any later version.
+ *
+ */
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct of_device *of_dev = to_of_device(dev);
+	struct of_platform_driver *of_drv = to_of_platform_driver(drv);
+	const struct of_device_id *matches = of_drv->match_table;
+
+	if (!matches)
+		return 0;
+
+	return of_match_device(matches, of_dev) != NULL;
+}
+
+static int of_platform_device_probe(struct device *dev)
+{
+	int error = -ENODEV;
+	struct of_platform_driver *drv;
+	struct of_device *of_dev;
+	const struct of_device_id *match;
+
+	drv = to_of_platform_driver(dev->driver);
+	of_dev = to_of_device(dev);
+
+	if (!drv->probe)
+		return error;
+
+	of_dev_get(of_dev);
+
+	match = of_match_device(drv->match_table, of_dev);
+	if (match)
+		error = drv->probe(of_dev, match);
+	if (error)
+		of_dev_put(of_dev);
+
+	return error;
+}
+
+static int of_platform_device_remove(struct device *dev)
+{
+	struct of_device *of_dev = to_of_device(dev);
+	struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+
+	if (dev->driver && drv->remove)
+		drv->remove(of_dev);
+	return 0;
+}
+
+static int of_platform_device_suspend(struct device *dev, pm_message_t state)
+{
+	struct of_device *of_dev = to_of_device(dev);
+	struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+	int error = 0;
+
+	if (dev->driver && drv->suspend)
+		error = drv->suspend(of_dev, state);
+	return error;
+}
+
+static int of_platform_device_resume(struct device * dev)
+{
+	struct of_device *of_dev = to_of_device(dev);
+	struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
+	int error = 0;
+
+	if (dev->driver && drv->resume)
+		error = drv->resume(of_dev);
+	return error;
+}
+
+int of_bus_type_init(struct bus_type *bus, const char *name)
+{
+	bus->name = name;
+	bus->match = of_platform_bus_match;
+	bus->probe = of_platform_device_probe;
+	bus->remove = of_platform_device_remove;
+	bus->suspend = of_platform_device_suspend;
+	bus->resume = of_platform_device_resume;
+	return bus_register(bus);
+}
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index edd6de9..8134c7e 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -26,8 +26,9 @@
 #include <linux/profile.h>
 #include <linux/module.h>
 #include <linux/fs.h>
+#include <linux/oprofile.h>
 #include <linux/sched.h>
- 
+
 #include "oprofile_stats.h"
 #include "event_buffer.h"
 #include "cpu_buffer.h"
diff --git a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h
index 9b6a4eb..5076ed1 100644
--- a/drivers/oprofile/event_buffer.h
+++ b/drivers/oprofile/event_buffer.h
@@ -19,28 +19,10 @@
  
 /* wake up the process sleeping on the event file */
 void wake_up_buffer_waiter(void);
- 
-/* Each escaped entry is prefixed by ESCAPE_CODE
- * then one of the following codes, then the
- * relevant data.
- */
-#define ESCAPE_CODE			~0UL
-#define CTX_SWITCH_CODE 		1
-#define CPU_SWITCH_CODE 		2
-#define COOKIE_SWITCH_CODE 		3
-#define KERNEL_ENTER_SWITCH_CODE	4
-#define KERNEL_EXIT_SWITCH_CODE		5
-#define MODULE_LOADED_CODE		6
-#define CTX_TGID_CODE			7
-#define TRACE_BEGIN_CODE		8
-#define TRACE_END_CODE			9
- 
+
 #define INVALID_COOKIE ~0UL
 #define NO_COOKIE 0UL
 
-/* add data to the event buffer */
-void add_event_entry(unsigned long data);
- 
 extern const struct file_operations event_buffer_fops;
  
 /* mutex between sync_cpu_buffers() and the
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
index e5162a6..2c64517 100644
--- a/drivers/oprofile/oprof.c
+++ b/drivers/oprofile/oprof.c
@@ -53,9 +53,24 @@
 	 * us missing task deaths and eventually oopsing
 	 * when trying to process the event buffer.
 	 */
+	if (oprofile_ops.sync_start) {
+		int sync_ret = oprofile_ops.sync_start();
+		switch (sync_ret) {
+		case 0:
+			goto post_sync;
+		case 1:
+			goto do_generic;
+		case -1:
+			goto out3;
+		default:
+			goto out3;
+		}
+	}
+do_generic:
 	if ((err = sync_start()))
 		goto out3;
 
+post_sync:
 	is_setup = 1;
 	mutex_unlock(&start_mutex);
 	return 0;
@@ -118,7 +133,20 @@
 void oprofile_shutdown(void)
 {
 	mutex_lock(&start_mutex);
+	if (oprofile_ops.sync_stop) {
+		int sync_ret = oprofile_ops.sync_stop();
+		switch (sync_ret) {
+		case 0:
+			goto post_sync;
+		case 1:
+			goto do_generic;
+		default:
+			goto post_sync;
+		}
+	}
+do_generic:
 	sync_stop();
+post_sync:
 	if (oprofile_ops.shutdown)
 		oprofile_ops.shutdown();
 	is_setup = 0;
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index e5d7ed9..a6d6b24 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -359,7 +359,7 @@
 	 * for reading should be OK */
 	read_lock(&dev_base_lock);
 	rcu_read_lock();
-	for_each_netdev(dev) {
+	for_each_netdev(&init_net, dev) {
 	    struct net_device_stats *stats;
 	    struct in_device *in_dev = __in_dev_get_rcu(dev);
 	    if (!in_dev || !in_dev->ifa_list)
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index a708c32..38cdf9f 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -73,6 +73,7 @@
 #include <linux/termios.h>
 #include <linux/tty.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 #include <linux/delay.h>
 
 #include <asm/io.h>
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index 09c93ff9..d449b15 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -35,7 +35,7 @@
 
 config PARPORT_PC
 	tristate "PC-style hardware"
-	depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV
+	depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV && (!M68K || ISA)
 	---help---
 	  You should say Y here if you have a PC-style parallel port. All
 	  IBM PC compatible computers and some Alphas have PC-style
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
index 8b7d84e..802a81d 100644
--- a/drivers/parport/parport_cs.c
+++ b/drivers/parport/parport_cs.c
@@ -105,9 +105,8 @@
     DEBUG(0, "parport_attach()\n");
 
     /* Create new parport device */
-    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    info = kzalloc(sizeof(*info), GFP_KERNEL);
     if (!info) return -ENOMEM;
-    memset(info, 0, sizeof(*info));
     link->priv = info;
     info->p_dev = link;
 
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 5d58ad5..e2be840 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -3445,7 +3445,6 @@
 		pnp_unregister_driver (&parport_pc_pnp_driver);
 	platform_driver_unregister(&parport_pc_platform_driver);
 
-	spin_lock(&ports_lock);
 	while (!list_empty(&ports_list)) {
 		struct parport_pc_private *priv;
 		struct parport *port;
@@ -3455,11 +3454,8 @@
 		if (port->dev && port->dev->bus == &platform_bus_type)
 			platform_device_unregister(
 				to_platform_device(port->dev));
-		spin_unlock(&ports_lock);
 		parport_pc_unregister_port(port);
-		spin_lock(&ports_lock);
 	}
-	spin_unlock(&ports_lock);
 }
 
 MODULE_AUTHOR("Phil Blundell, Tim Waugh, others");
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index 90ea3b8..bd6ad8b 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -324,10 +324,9 @@
 	struct parport_serial_private *priv;
 	int err;
 
-	priv = kmalloc (sizeof *priv, GFP_KERNEL);
+	priv = kzalloc (sizeof *priv, GFP_KERNEL);
 	if (!priv)
 		return -ENOMEM;
-	memset(priv, 0, sizeof(struct parport_serial_private));
 	pci_set_drvdata (dev, priv);
 
 	err = pci_enable_device (dev);
diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c
index 1c97e7d..2b5352a 100644
--- a/drivers/pci/hotplug.c
+++ b/drivers/pci/hotplug.c
@@ -3,12 +3,9 @@
 #include <linux/module.h>
 #include "pci.h"
 
-int pci_uevent(struct device *dev, char **envp, int num_envp,
-	       char *buffer, int buffer_size)
+int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct pci_dev *pdev;
-	int i = 0;
-	int length = 0;
 
 	if (!dev)
 		return -ENODEV;
@@ -17,37 +14,24 @@
 	if (!pdev)
 		return -ENODEV;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "PCI_CLASS=%04X", pdev->class))
+	if (add_uevent_var(env, "PCI_CLASS=%04X", pdev->class))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "PCI_ID=%04X:%04X", pdev->vendor, pdev->device))
+	if (add_uevent_var(env, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
+	if (add_uevent_var(env, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
 			   pdev->subsystem_device))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "PCI_SLOT_NAME=%s", pci_name(pdev)))
+	if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev)))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x",
+	if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x",
 			   pdev->vendor, pdev->device,
 			   pdev->subsystem_vendor, pdev->subsystem_device,
 			   (u8)(pdev->class >> 16), (u8)(pdev->class >> 8),
 			   (u8)(pdev->class)))
 		return -ENOMEM;
-
-	envp[i] = NULL;
-
 	return 0;
 }
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index 70db38c..56829f8 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -267,7 +267,10 @@
 
 	if (subevent == 0x80) {
 		dbg("%s: generationg bus event\n", __FUNCTION__);
-		acpi_bus_generate_event(note->device, note->event, detail);
+		acpi_bus_generate_proc_event(note->device, note->event, detail);
+		acpi_bus_generate_netlink_event(note->device->pnp.device_class,
+						  note->device->dev.bus_id,
+						  note->event, detail);
 	} else
 		note->event = event;
 }
@@ -399,7 +402,7 @@
 
 	status = acpi_get_object_info(handle, &info_buffer);
 	if (ACPI_FAILURE(status)) {
-		err("%s:  Failed to get device information", __FUNCTION__);
+		err("%s:  Failed to get device information\n", __FUNCTION__);
 		return 0;
 	}
 	info.hardware_id.value[sizeof(info.hardware_id.value) - 1] = '\0';
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
index d590a99..a96b739 100644
--- a/drivers/pci/hotplug/cpqphp_core.c
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -45,7 +45,7 @@
 
 #include "cpqphp.h"
 #include "cpqphp_nvram.h"
-#include "../../../arch/i386/pci/pci.h"	/* horrible hack showing how processor dependent we are... */
+#include "../../../arch/x86/pci/pci.h"	/* horrible hack showing how processor dependent we are... */
 
 
 /* Global variables */
@@ -549,7 +549,7 @@
 			 * slot. */
 			bus->number = tbus;
 			pci_bus_read_config_dword(bus, PCI_DEVFN(tdevice, 0),
-						PCI_REVISION_ID, &work);
+						PCI_CLASS_REVISION, &work);
 
 			if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {
 				pci_bus_read_config_dword(bus,
diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c
index 79ff6b4..3ef0a48 100644
--- a/drivers/pci/hotplug/cpqphp_ctrl.c
+++ b/drivers/pci/hotplug/cpqphp_ctrl.c
@@ -37,6 +37,7 @@
 #include <linux/smp_lock.h>
 #include <linux/pci.h>
 #include <linux/pci_hotplug.h>
+#include <linux/kthread.h>
 #include "cpqphp.h"
 
 static u32 configure_new_device(struct controller* ctrl, struct pci_func *func,
@@ -45,34 +46,20 @@
 			u8 behind_bridge, struct resource_lists *resources);
 static void interrupt_event_handler(struct controller *ctrl);
 
-static struct semaphore event_semaphore;	/* mutex for process loop (up if something to process) */
-static struct semaphore event_exit;		/* guard ensure thread has exited before calling it quits */
-static int event_finished;
-static unsigned long pushbutton_pending;	/* = 0 */
 
-/* things needed for the long_delay function */
-static struct semaphore		delay_sem;
-static wait_queue_head_t	delay_wait;
+static struct task_struct *cpqhp_event_thread;
+static unsigned long pushbutton_pending;	/* = 0 */
 
 /* delay is in jiffies to wait for */
 static void long_delay(int delay)
 {
-	DECLARE_WAITQUEUE(wait, current);
-	
-	/* only allow 1 customer into the delay queue at once
-	 * yes this makes some people wait even longer, but who really cares?
-	 * this is for _huge_ delays to make the hardware happy as the 
-	 * signals bounce around
+	/*
+	 * XXX(hch): if someone is bored please convert all callers
+	 * to call msleep_interruptible directly.  They really want
+	 * to specify timeouts in natural units and spend a lot of
+	 * effort converting them to jiffies..
 	 */
-	down (&delay_sem);
-
-	init_waitqueue_head(&delay_wait);
-
-	add_wait_queue(&delay_wait, &wait);
 	msleep_interruptible(jiffies_to_msecs(delay));
-	remove_wait_queue(&delay_wait, &wait);
-	
-	up(&delay_sem);
 }
 
 
@@ -955,8 +942,8 @@
 	}
 
 	if (schedule_flag) {
-		up(&event_semaphore);
-		dbg("Signal event_semaphore\n");
+		wake_up_process(cpqhp_event_thread);
+		dbg("Waking even thread");
 	}
 	return IRQ_HANDLED;
 }
@@ -973,16 +960,13 @@
 	struct pci_func *new_slot;
 	struct pci_func *next;
 
-	new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL);
-
+	new_slot = kzalloc(sizeof(*new_slot), GFP_KERNEL);
 	if (new_slot == NULL) {
 		/* I'm not dead yet!
 		 * You will be. */
 		return new_slot;
 	}
 
-	memset(new_slot, 0, sizeof(struct pci_func));
-
 	new_slot->next = NULL;
 	new_slot->configured = 1;
 
@@ -1738,7 +1722,7 @@
 static void pushbutton_helper_thread(unsigned long data)
 {
 	pushbutton_pending = data;
-	up(&event_semaphore);
+	wake_up_process(cpqhp_event_thread);
 }
 
 
@@ -1746,16 +1730,14 @@
 static int event_thread(void* data)
 {
 	struct controller *ctrl;
-	lock_kernel();
-	daemonize("phpd_event");
-	
-	unlock_kernel();
 
 	while (1) {
 		dbg("!!!!event_thread sleeping\n");
-		down_interruptible (&event_semaphore);
-		dbg("event_thread woken finished = %d\n", event_finished);
-		if (event_finished) break;
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule();
+
+		if (kthread_should_stop())
+			break;
 		/* Do stuff here */
 		if (pushbutton_pending)
 			cpqhp_pushbutton_thread(pushbutton_pending);
@@ -1764,38 +1746,24 @@
 				interrupt_event_handler(ctrl);
 	}
 	dbg("event_thread signals exit\n");
-	up(&event_exit);
 	return 0;
 }
 
-
 int cpqhp_event_start_thread(void)
 {
-	int pid;
-
-	/* initialize our semaphores */
-	init_MUTEX(&delay_sem);
-	init_MUTEX_LOCKED(&event_semaphore);
-	init_MUTEX_LOCKED(&event_exit);
-	event_finished=0;
-
-	pid = kernel_thread(event_thread, NULL, 0);
-	if (pid < 0) {
+	cpqhp_event_thread = kthread_run(event_thread, NULL, "phpd_event");
+	if (IS_ERR(cpqhp_event_thread)) {
 		err ("Can't start up our event thread\n");
-		return -1;
+		return PTR_ERR(cpqhp_event_thread);
 	}
-	dbg("Our event thread pid = %d\n", pid);
+
 	return 0;
 }
 
 
 void cpqhp_event_stop_thread(void)
 {
-	event_finished = 1;
-	dbg("event_thread finish command given\n");
-	up(&event_semaphore);
-	dbg("wait for event_thread to exit\n");
-	down(&event_exit);
+	kthread_stop(cpqhp_event_thread);
 }
 
 
diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c
index fc7c74d..3f6cd20 100644
--- a/drivers/pci/hotplug/cpqphp_pci.c
+++ b/drivers/pci/hotplug/cpqphp_pci.c
@@ -37,7 +37,7 @@
 #include "../pci.h"
 #include "cpqphp.h"
 #include "cpqphp_nvram.h"
-#include "../../../arch/i386/pci/pci.h"	/* horrible hack showing how processor dependent we are... */
+#include "../../../arch/x86/pci/pci.h"	/* horrible hack showing how processor dependent we are... */
 
 
 u8 cpqhp_nic_irq;
diff --git a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c
index 0316eea..a90c28d 100644
--- a/drivers/pci/hotplug/ibmphp_core.c
+++ b/drivers/pci/hotplug/ibmphp_core.c
@@ -35,7 +35,7 @@
 #include <linux/delay.h>
 #include <linux/wait.h>
 #include "../pci.h"
-#include "../../../arch/i386/pci/pci.h"	/* for struct irq_routing_table */
+#include "../../../arch/x86/pci/pci.h"	/* for struct irq_routing_table */
 #include "ibmphp.h"
 
 #define attn_on(sl)  ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNON)
diff --git a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c
index d06ccb6..c31e7bf 100644
--- a/drivers/pci/hotplug/ibmphp_hpc.c
+++ b/drivers/pci/hotplug/ibmphp_hpc.c
@@ -35,7 +35,7 @@
 #include <linux/init.h>
 #include <linux/mutex.h>
 #include <linux/sched.h>
-
+#include <linux/kthread.h>
 #include "ibmphp.h"
 
 static int to_debug = 0;
@@ -101,12 +101,11 @@
 //----------------------------------------------------------------------------
 // global variables
 //----------------------------------------------------------------------------
-static int ibmphp_shutdown;
-static int tid_poll;
 static struct mutex sem_hpcaccess;	// lock access to HPC
 static struct semaphore semOperations;	// lock all operations and
 					// access to data structures
 static struct semaphore sem_exit;	// make sure polling thread goes away
+static struct task_struct *ibmphp_poll_thread;
 //----------------------------------------------------------------------------
 // local function prototypes
 //----------------------------------------------------------------------------
@@ -116,10 +115,9 @@
 static u8 hpc_readcmdtoindex (u8, u8);
 static void get_hpc_access (void);
 static void free_hpc_access (void);
-static void poll_hpc (void);
+static int poll_hpc(void *data);
 static int process_changeinstatus (struct slot *, struct slot *);
 static int process_changeinlatch (u8, u8, struct controller *);
-static int hpc_poll_thread (void *);
 static int hpc_wait_ctlr_notworking (int, struct controller *, void __iomem *, u8 *);
 //----------------------------------------------------------------------------
 
@@ -137,8 +135,6 @@
 	init_MUTEX (&semOperations);
 	init_MUTEX_LOCKED (&sem_exit);
 	to_debug = 0;
-	ibmphp_shutdown = 0;
-	tid_poll = 0;
 
 	debug ("%s - Exit\n", __FUNCTION__);
 }
@@ -819,7 +815,7 @@
 #define POLL_LATCH_REGISTER	0
 #define POLL_SLOTS		1
 #define POLL_SLEEP		2
-static void poll_hpc (void)
+static int poll_hpc(void *data)
 {
 	struct slot myslot;
 	struct slot *pslot = NULL;
@@ -833,10 +829,7 @@
 
 	debug ("%s - Entry\n", __FUNCTION__);
 
-	while (!ibmphp_shutdown) {
-		if (ibmphp_shutdown) 
-			break;
-		
+	while (!kthread_should_stop()) {
 		/* try to get the lock to do some kind of hardware access */
 		down (&semOperations);
 
@@ -896,7 +889,7 @@
 			up (&semOperations);
 			msleep(POLL_INTERVAL_SEC * 1000);
 
-			if (ibmphp_shutdown) 
+			if (kthread_should_stop())
 				break;
 			
 			down (&semOperations);
@@ -915,6 +908,7 @@
 	}
 	up (&sem_exit);
 	debug ("%s - Exit\n", __FUNCTION__);
+	return 0;
 }
 
 
@@ -1050,47 +1044,20 @@
 }
 
 /*----------------------------------------------------------------------
-* Name:    hpc_poll_thread
-*
-* Action:  polling
-*
-* Return   0
-* Value:
-*---------------------------------------------------------------------*/
-static int hpc_poll_thread (void *data)
-{
-	debug ("%s - Entry\n", __FUNCTION__);
-
-	daemonize("hpc_poll");
-	allow_signal(SIGKILL);
-
-	poll_hpc ();
-
-	tid_poll = 0;
-	debug ("%s - Exit\n", __FUNCTION__);
-	return 0;
-}
-
-
-/*----------------------------------------------------------------------
 * Name:    ibmphp_hpc_start_poll_thread
 *
 * Action:  start polling thread
 *---------------------------------------------------------------------*/
 int __init ibmphp_hpc_start_poll_thread (void)
 {
-	int rc = 0;
-
 	debug ("%s - Entry\n", __FUNCTION__);
 
-	tid_poll = kernel_thread (hpc_poll_thread, NULL, 0);
-	if (tid_poll < 0) {
+	ibmphp_poll_thread = kthread_run(poll_hpc, NULL, "hpc_poll");
+	if (IS_ERR(ibmphp_poll_thread)) {
 		err ("%s - Error, thread not started\n", __FUNCTION__);
-		rc = -1;
+		return PTR_ERR(ibmphp_poll_thread);
 	}
-
-	debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc);
-	return rc;
+	return 0;
 }
 
 /*----------------------------------------------------------------------
@@ -1102,7 +1069,7 @@
 {
 	debug ("%s - Entry\n", __FUNCTION__);
 
-	ibmphp_shutdown = 1;
+	kthread_stop(ibmphp_poll_thread);
 	debug ("before locking operations \n");
 	ibmphp_lock_operations ();
 	debug ("after locking operations \n");
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index bd433ef..f0eba53 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -694,66 +694,6 @@
 	if ((slot == NULL) || (info == NULL))
 		return -ENODEV;
 
-	/*
-	* check all fields in the info structure, and update timestamps
-	* for the files referring to the fields that have now changed.
-	*/
-	if ((has_power_file(slot) == 0) &&
-	    (slot->info->power_status != info->power_status)) {
-		retval = sysfs_update_file(&slot->kobj,
-					   &hotplug_slot_attr_power.attr);
-		if (retval)
-			return retval;
-	}
-
-	if ((has_attention_file(slot) == 0) &&
-	    (slot->info->attention_status != info->attention_status)) {
-		retval = sysfs_update_file(&slot->kobj,
-					   &hotplug_slot_attr_attention.attr);
-		if (retval)
-			return retval;
-	}
-
-	if ((has_latch_file(slot) == 0) &&
-	    (slot->info->latch_status != info->latch_status)) {
-		retval = sysfs_update_file(&slot->kobj,
-					   &hotplug_slot_attr_latch.attr);
-		if (retval)
-			return retval;
-	}
-
-	if ((has_adapter_file(slot) == 0) &&
-	    (slot->info->adapter_status != info->adapter_status)) {
-		retval = sysfs_update_file(&slot->kobj,
-					   &hotplug_slot_attr_presence.attr);
-		if (retval)
-			return retval;
-	}
-
-	if ((has_address_file(slot) == 0) &&
-	    (slot->info->address != info->address)) {
-		retval = sysfs_update_file(&slot->kobj,
-					   &hotplug_slot_attr_address.attr);
-		if (retval)
-			return retval;
-	}
-
-	if ((has_max_bus_speed_file(slot) == 0) &&
-	    (slot->info->max_bus_speed != info->max_bus_speed)) {
-		retval = sysfs_update_file(&slot->kobj,
-					   &hotplug_slot_attr_max_bus_speed.attr);
-		if (retval)
-			return retval;
-	}
-
-	if ((has_cur_bus_speed_file(slot) == 0) &&
-	    (slot->info->cur_bus_speed != info->cur_bus_speed)) {
-		retval = sysfs_update_file(&slot->kobj,
-					   &hotplug_slot_attr_cur_bus_speed.attr);
-		if (retval)
-			return retval;
-	}
-
 	memcpy (slot->info, info, sizeof (struct hotplug_slot_info));
 
 	return 0;
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index e5d3f0b..6462ac3 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -304,8 +304,8 @@
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	hotplug_slot->info->attention_status = status;
-	
-	if (ATTN_LED(slot->ctrl->ctrlcap)) 
+
+	if (ATTN_LED(slot->ctrl->ctrlcap))
 		slot->hpc_ops->set_attention_status(slot, status);
 
 	return 0;
@@ -405,7 +405,7 @@
 	int retval;
 
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
-	
+
 	retval = slot->hpc_ops->get_max_bus_speed(slot, value);
 	if (retval < 0)
 		*value = PCI_SPEED_UNKNOWN;
@@ -419,7 +419,7 @@
 	int retval;
 
 	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
-	
+
 	retval = slot->hpc_ops->get_cur_bus_speed(slot, value);
 	if (retval < 0)
 		*value = PCI_SPEED_UNKNOWN;
@@ -434,7 +434,7 @@
 	struct slot *t_slot;
 	u8 value;
 	struct pci_dev *pdev;
-	
+
 	ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
 	if (!ctrl) {
 		err("%s : out of memory\n", __FUNCTION__);
@@ -502,23 +502,23 @@
 #ifdef CONFIG_PM
 static int pciehp_suspend (struct pcie_device *dev, pm_message_t state)
 {
-	printk("%s ENTRY\n", __FUNCTION__);	
+	printk("%s ENTRY\n", __FUNCTION__);
 	return 0;
 }
 
 static int pciehp_resume (struct pcie_device *dev)
 {
-	printk("%s ENTRY\n", __FUNCTION__);	
+	printk("%s ENTRY\n", __FUNCTION__);
 	return 0;
 }
 #endif
 
-static struct pcie_port_service_id port_pci_ids[] = { { 
-	.vendor = PCI_ANY_ID, 
+static struct pcie_port_service_id port_pci_ids[] = { {
+	.vendor = PCI_ANY_ID,
 	.device = PCI_ANY_ID,
 	.port_type = PCIE_ANY_PORT,
 	.service_type = PCIE_PORT_SERVICE_HP,
-	.driver_data =	0, 
+	.driver_data =	0,
 	}, { /* end: all zeroes */ }
 };
 static const char device_name[] = "hpdriver";
@@ -540,10 +540,6 @@
 {
 	int retval = 0;
 
-#ifdef CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
-	pciehp_poll_mode = 1;
-#endif
-
 	retval = pcie_port_service_register(&hpdriver_portdrv);
  	dbg("pcie_port_service_register = %d\n", retval);
   	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 98e541ffe..c8cb49c 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -173,7 +173,7 @@
 	return 1;
 }
 
-/* The following routines constitute the bulk of the 
+/* The following routines constitute the bulk of the
    hotplug controller logic
  */
 
@@ -181,7 +181,7 @@
 {
 	/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
 	if (POWER_CTRL(ctrl->ctrlcap)) {
-		if (pslot->hpc_ops->power_off_slot(pslot)) {   
+		if (pslot->hpc_ops->power_off_slot(pslot)) {
 			err("%s: Issue of Slot Power Off command failed\n",
 			    __FUNCTION__);
 			return;
@@ -189,7 +189,7 @@
 	}
 
 	if (PWR_LED(ctrl->ctrlcap))
-		pslot->hpc_ops->green_led_off(pslot);   
+		pslot->hpc_ops->green_led_off(pslot);
 
 	if (ATTN_LED(ctrl->ctrlcap)) {
 		if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
@@ -231,7 +231,7 @@
 		if (retval)
 			return retval;
 	}
-	
+
 	if (PWR_LED(ctrl->ctrlcap))
 		p_slot->hpc_ops->green_led_blink(p_slot);
 
@@ -548,7 +548,7 @@
 		mutex_unlock(&p_slot->ctrl->crit_sect);
 		return -ENODEV;
 	}
-	if (MRL_SENS(p_slot->ctrl->ctrlcap)) {	
+	if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
 		rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 		if (rc || getstatus) {
 			info("%s: latch open on slot(%s)\n", __FUNCTION__,
@@ -557,8 +557,8 @@
 			return -ENODEV;
 		}
 	}
-	
-	if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {	
+
+	if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
 		rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 		if (rc || getstatus) {
 			info("%s: already enabled on slot(%s)\n", __FUNCTION__,
@@ -593,7 +593,7 @@
 	/* Check to see if (latch closed, card present, power on) */
 	mutex_lock(&p_slot->ctrl->crit_sect);
 
-	if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {	
+	if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {
 		ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
 		if (ret || !getstatus) {
 			info("%s: no adapter on slot(%s)\n", __FUNCTION__,
@@ -603,7 +603,7 @@
 		}
 	}
 
-	if (MRL_SENS(p_slot->ctrl->ctrlcap)) {	
+	if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
 		ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
 		if (ret || getstatus) {
 			info("%s: latch open on slot(%s)\n", __FUNCTION__,
@@ -613,7 +613,7 @@
 		}
 	}
 
-	if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {	
+	if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
 		ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
 		if (ret || !getstatus) {
 			info("%s: already disabled slot(%s)\n", __FUNCTION__,
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 016eea9..06d025b 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -39,37 +39,6 @@
 
 #include "../pci.h"
 #include "pciehp.h"
-#ifdef DEBUG
-#define DBG_K_TRACE_ENTRY      ((unsigned int)0x00000001)	/* On function entry */
-#define DBG_K_TRACE_EXIT       ((unsigned int)0x00000002)	/* On function exit */
-#define DBG_K_INFO             ((unsigned int)0x00000004)	/* Info messages */
-#define DBG_K_ERROR            ((unsigned int)0x00000008)	/* Error messages */
-#define DBG_K_TRACE            (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
-#define DBG_K_STANDARD         (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
-/* Redefine this flagword to set debug level */
-#define DEBUG_LEVEL            DBG_K_STANDARD
-
-#define DEFINE_DBG_BUFFER     char __dbg_str_buf[256];
-
-#define DBG_PRINT( dbg_flags, args... )              \
-	do {                                             \
-	  if ( DEBUG_LEVEL & ( dbg_flags ) )             \
-	  {                                              \
-	    int len;                                     \
-	    len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
-		  __FILE__, __LINE__, __FUNCTION__ );    \
-	    sprintf( __dbg_str_buf + len, args );        \
-	    printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
-	  }                                              \
-	} while (0)
-
-#define DBG_ENTER_ROUTINE	DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
-#define DBG_LEAVE_ROUTINE	DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
-#else
-#define DEFINE_DBG_BUFFER
-#define DBG_ENTER_ROUTINE
-#define DBG_LEAVE_ROUTINE
-#endif				/* DEBUG */
 
 static atomic_t pciehp_num_controllers = ATOMIC_INIT(0);
 
@@ -160,10 +129,10 @@
 /* Link Width Encoding */
 #define LNK_X1		0x01
 #define LNK_X2		0x02
-#define LNK_X4		0x04	
+#define LNK_X4		0x04
 #define LNK_X8		0x08
 #define LNK_X12		0x0C
-#define LNK_X16		0x10	
+#define LNK_X16		0x10
 #define LNK_X32		0x20
 
 /*Field definitions of Link Status Register */
@@ -221,8 +190,6 @@
 #define EMI_STATE		0x0080
 #define EMI_STATUS_BIT		7
 
-DEFINE_DBG_BUFFER		/* Debug string buffer for entire HPC defined here */
-
 static irqreturn_t pcie_isr(int irq, void *dev_id);
 static void start_int_poll_timer(struct controller *ctrl, int sec);
 
@@ -231,14 +198,12 @@
 {
 	struct controller *ctrl = (struct controller *)data;
 
-	DBG_ENTER_ROUTINE
-
 	/* Poll for interrupt events.  regs == NULL => polling */
 	pcie_isr(0, ctrl);
 
 	init_timer(&ctrl->poll_timer);
 	if (!pciehp_poll_time)
-		pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
+		pciehp_poll_time = 2; /* default polling interval is 2 sec */
 
 	start_int_poll_timer(ctrl, pciehp_poll_time);
 }
@@ -289,8 +254,6 @@
 	u16 slot_ctrl;
 	unsigned long flags;
 
-	DBG_ENTER_ROUTINE 
-
 	mutex_lock(&ctrl->ctrl_lock);
 
 	retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
@@ -299,7 +262,7 @@
 		goto out;
 	}
 
-	if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { 
+	if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) {
 		/* After 1 sec and CMD_COMPLETED still not set, just
 		   proceed forward to issue the next command according
 		   to spec.  Just print out the error message */
@@ -332,7 +295,6 @@
 		retval = pcie_wait_cmd(ctrl);
  out:
 	mutex_unlock(&ctrl->ctrl_lock);
-	DBG_LEAVE_ROUTINE 
 	return retval;
 }
 
@@ -341,8 +303,6 @@
 	u16 lnk_status;
 	int retval = 0;
 
-	DBG_ENTER_ROUTINE 
-
 	retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
 	if (retval) {
 		err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
@@ -350,26 +310,22 @@
 	}
 
 	dbg("%s: lnk_status = %x\n", __FUNCTION__, lnk_status);
-	if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) || 
+	if ( (lnk_status & LNK_TRN) || (lnk_status & LNK_TRN_ERR) ||
 		!(lnk_status & NEG_LINK_WD)) {
 		err("%s : Link Training Error occurs \n", __FUNCTION__);
 		retval = -1;
 		return retval;
 	}
 
-	DBG_LEAVE_ROUTINE 
 	return retval;
 }
 
-
 static int hpc_get_attention_status(struct slot *slot, u8 *status)
 {
 	struct controller *ctrl = slot->ctrl;
 	u16 slot_ctrl;
 	u8 atten_led_state;
 	int retval = 0;
-	
-	DBG_ENTER_ROUTINE 
 
 	retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
 	if (retval) {
@@ -400,7 +356,6 @@
 		break;
 	}
 
-	DBG_LEAVE_ROUTINE 
 	return 0;
 }
 
@@ -410,8 +365,6 @@
 	u16 slot_ctrl;
 	u8 pwr_state;
 	int	retval = 0;
-	
-	DBG_ENTER_ROUTINE 
 
 	retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
 	if (retval) {
@@ -428,35 +381,30 @@
 		*status = 1;
 		break;
 	case 1:
-		*status = 0;	
+		*status = 0;
 		break;
 	default:
 		*status = 0xFF;
 		break;
 	}
 
-	DBG_LEAVE_ROUTINE 
 	return retval;
 }
 
-
 static int hpc_get_latch_status(struct slot *slot, u8 *status)
 {
 	struct controller *ctrl = slot->ctrl;
 	u16 slot_status;
 	int retval = 0;
 
-	DBG_ENTER_ROUTINE 
-
 	retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
 	if (retval) {
 		err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
 		return retval;
 	}
 
-	*status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1;  
+	*status = (((slot_status & MRL_STATE) >> 5) == 0) ? 0 : 1;
 
-	DBG_LEAVE_ROUTINE 
 	return 0;
 }
 
@@ -467,8 +415,6 @@
 	u8 card_state;
 	int retval = 0;
 
-	DBG_ENTER_ROUTINE 
-
 	retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
 	if (retval) {
 		err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
@@ -477,7 +423,6 @@
 	card_state = (u8)((slot_status & PRSN_STATE) >> 6);
 	*status = (card_state == 1) ? 1 : 0;
 
-	DBG_LEAVE_ROUTINE 
 	return 0;
 }
 
@@ -488,16 +433,13 @@
 	u8 pwr_fault;
 	int retval = 0;
 
-	DBG_ENTER_ROUTINE 
-
 	retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
 	if (retval) {
 		err("%s: Cannot check for power fault\n", __FUNCTION__);
 		return retval;
 	}
 	pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
-	
-	DBG_LEAVE_ROUTINE
+
 	return pwr_fault;
 }
 
@@ -507,8 +449,6 @@
 	u16 slot_status;
 	int retval = 0;
 
-	DBG_ENTER_ROUTINE
-
 	retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
 	if (retval) {
 		err("%s : Cannot check EMI status\n", __FUNCTION__);
@@ -516,7 +456,6 @@
 	}
 	*status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT;
 
-	DBG_LEAVE_ROUTINE
 	return retval;
 }
 
@@ -526,8 +465,6 @@
 	u16 cmd_mask;
 	int rc;
 
-	DBG_ENTER_ROUTINE
-
 	slot_cmd = EMI_CTRL;
 	cmd_mask = EMI_CTRL;
 	if (!pciehp_poll_mode) {
@@ -537,7 +474,7 @@
 
 	rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
 	slot->last_emi_toggle = get_seconds();
-	DBG_LEAVE_ROUTINE
+
 	return rc;
 }
 
@@ -548,8 +485,6 @@
 	u16 cmd_mask;
 	int rc;
 
-	DBG_ENTER_ROUTINE
-
 	cmd_mask = ATTN_LED_CTRL;
 	switch (value) {
 		case 0 :	/* turn off */
@@ -572,19 +507,15 @@
 	rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
 	dbg("%s: SLOTCTRL %x write cmd %x\n",
 	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
-	
-	DBG_LEAVE_ROUTINE
+
 	return rc;
 }
 
-
 static void hpc_set_green_led_on(struct slot *slot)
 {
 	struct controller *ctrl = slot->ctrl;
 	u16 slot_cmd;
 	u16 cmd_mask;
-       	
-	DBG_ENTER_ROUTINE
 
 	slot_cmd = 0x0100;
 	cmd_mask = PWR_LED_CTRL;
@@ -597,8 +528,6 @@
 
 	dbg("%s: SLOTCTRL %x write cmd %x\n",
 	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
-	DBG_LEAVE_ROUTINE
-	return;
 }
 
 static void hpc_set_green_led_off(struct slot *slot)
@@ -607,8 +536,6 @@
 	u16 slot_cmd;
 	u16 cmd_mask;
 
-	DBG_ENTER_ROUTINE
-
 	slot_cmd = 0x0300;
 	cmd_mask = PWR_LED_CTRL;
 	if (!pciehp_poll_mode) {
@@ -619,9 +546,6 @@
 	pcie_write_cmd(slot, slot_cmd, cmd_mask);
 	dbg("%s: SLOTCTRL %x write cmd %x\n",
 	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
-
-	DBG_LEAVE_ROUTINE
-	return;
 }
 
 static void hpc_set_green_led_blink(struct slot *slot)
@@ -629,8 +553,6 @@
 	struct controller *ctrl = slot->ctrl;
 	u16 slot_cmd;
 	u16 cmd_mask;
-	
-	DBG_ENTER_ROUTINE
 
 	slot_cmd = 0x0200;
 	cmd_mask = PWR_LED_CTRL;
@@ -643,14 +565,10 @@
 
 	dbg("%s: SLOTCTRL %x write cmd %x\n",
 	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
-	DBG_LEAVE_ROUTINE
-	return;
 }
 
 static void hpc_release_ctlr(struct controller *ctrl)
 {
-	DBG_ENTER_ROUTINE 
-
 	if (pciehp_poll_mode)
 		del_timer(&ctrl->poll_timer);
 	else
@@ -662,8 +580,6 @@
 	 */
 	if (atomic_dec_and_test(&pciehp_num_controllers))
 		destroy_workqueue(pciehp_wq);
-
-	DBG_LEAVE_ROUTINE
 }
 
 static int hpc_power_on_slot(struct slot * slot)
@@ -674,8 +590,6 @@
 	u16 slot_status;
 	int retval = 0;
 
-	DBG_ENTER_ROUTINE 
-
 	dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
 
 	/* Clear sticky power-fault bit from previous power failures */
@@ -719,8 +633,6 @@
 	dbg("%s: SLOTCTRL %x write cmd %x\n",
 	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
 
-	DBG_LEAVE_ROUTINE
-
 	return retval;
 }
 
@@ -731,8 +643,6 @@
 	u16 cmd_mask;
 	int retval = 0;
 
-	DBG_ENTER_ROUTINE 
-
 	dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
 
 	slot_cmd = POWER_OFF;
@@ -764,8 +674,6 @@
 	dbg("%s: SLOTCTRL %x write cmd %x\n",
 	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
 
-	DBG_LEAVE_ROUTINE
-
 	return retval;
 }
 
@@ -784,8 +692,8 @@
 		return IRQ_NONE;
 	}
 
-	intr_detect = ( ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | MRL_SENS_CHANGED |
-					PRSN_DETECT_CHANGED | CMD_COMPLETED );
+	intr_detect = (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED |
+		       MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | CMD_COMPLETED);
 
 	intr_loc = slot_status & intr_detect;
 
@@ -807,7 +715,8 @@
 
 		dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n",
 		    __FUNCTION__, temp_word);
-		temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
+		temp_word = (temp_word & ~HP_INTR_ENABLE &
+			     ~CMD_CMPL_INTR_ENABLE) | 0x00;
 		rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
 		if (rc) {
 			err("%s: Cannot write to SLOTCTRL register\n",
@@ -825,7 +734,7 @@
 		}
 		dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n",
 		    __FUNCTION__, slot_status);
-		
+
 		/* Clear command complete interrupt caused by this write */
 		temp_word = 0x1f;
 		rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
@@ -835,10 +744,10 @@
 			return IRQ_NONE;
 		}
 	}
-	
+
 	if (intr_loc & CMD_COMPLETED) {
-		/* 
-		 * Command Complete Interrupt Pending 
+		/*
+		 * Command Complete Interrupt Pending
 		 */
 		ctrl->cmd_busy = 0;
 		wake_up_interruptible(&ctrl->queue);
@@ -892,7 +801,7 @@
 			    __FUNCTION__);
 			return IRQ_NONE;
 		}
-		
+
 		/* Clear command complete interrupt caused by this write */
 		temp_word = 0x1F;
 		rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
@@ -904,19 +813,17 @@
 		dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n",
 		    __FUNCTION__, temp_word);
 	}
-	
+
 	return IRQ_HANDLED;
 }
 
-static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
+static int hpc_get_max_lnk_speed(struct slot *slot, enum pci_bus_speed *value)
 {
 	struct controller *ctrl = slot->ctrl;
 	enum pcie_link_speed lnk_speed;
 	u32	lnk_cap;
 	int retval = 0;
 
-	DBG_ENTER_ROUTINE 
-
 	retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
 	if (retval) {
 		err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
@@ -934,19 +841,18 @@
 
 	*value = lnk_speed;
 	dbg("Max link speed = %d\n", lnk_speed);
-	DBG_LEAVE_ROUTINE 
+
 	return retval;
 }
 
-static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value)
+static int hpc_get_max_lnk_width(struct slot *slot,
+				 enum pcie_link_width *value)
 {
 	struct controller *ctrl = slot->ctrl;
 	enum pcie_link_width lnk_wdth;
 	u32	lnk_cap;
 	int retval = 0;
 
-	DBG_ENTER_ROUTINE 
-
 	retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
 	if (retval) {
 		err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
@@ -985,19 +891,17 @@
 
 	*value = lnk_wdth;
 	dbg("Max link width = %d\n", lnk_wdth);
-	DBG_LEAVE_ROUTINE 
+
 	return retval;
 }
 
-static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
+static int hpc_get_cur_lnk_speed(struct slot *slot, enum pci_bus_speed *value)
 {
 	struct controller *ctrl = slot->ctrl;
 	enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN;
 	int retval = 0;
 	u16 lnk_status;
 
-	DBG_ENTER_ROUTINE 
-
 	retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
 	if (retval) {
 		err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
@@ -1015,25 +919,24 @@
 
 	*value = lnk_speed;
 	dbg("Current link speed = %d\n", lnk_speed);
-	DBG_LEAVE_ROUTINE 
+
 	return retval;
 }
 
-static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value)
+static int hpc_get_cur_lnk_width(struct slot *slot,
+				 enum pcie_link_width *value)
 {
 	struct controller *ctrl = slot->ctrl;
 	enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
 	int retval = 0;
 	u16 lnk_status;
 
-	DBG_ENTER_ROUTINE 
-
 	retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
 	if (retval) {
 		err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
 		return retval;
 	}
-	
+
 	switch ((lnk_status & 0x03F0) >> 4){
 	case 0:
 		lnk_wdth = PCIE_LNK_WIDTH_RESRV;
@@ -1066,7 +969,7 @@
 
 	*value = lnk_wdth;
 	dbg("Current link width = %d\n", lnk_wdth);
-	DBG_LEAVE_ROUTINE 
+
 	return retval;
 }
 
@@ -1085,12 +988,12 @@
 	.get_cur_bus_speed		= hpc_get_cur_lnk_speed,
 	.get_max_lnk_width		= hpc_get_max_lnk_width,
 	.get_cur_lnk_width		= hpc_get_cur_lnk_width,
-	
+
 	.query_power_fault		= hpc_query_power_fault,
 	.green_led_on			= hpc_set_green_led_on,
 	.green_led_off			= hpc_set_green_led_off,
 	.green_led_blink		= hpc_set_green_led_blink,
-	
+
 	.release_ctlr			= hpc_release_ctlr,
 	.check_lnk_status		= hpc_check_lnk_status,
 };
@@ -1138,6 +1041,7 @@
 		dbg("Trying to get hotplug control for %s \n",
 			(char *)string.pointer);
 		status = pci_osc_control_set(handle,
+				OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL |
 				OSC_PCI_EXPRESS_NATIVE_HP_CONTROL);
 		if (status == AE_NOT_FOUND)
 			status = acpi_run_oshp(handle);
@@ -1163,8 +1067,6 @@
 }
 #endif
 
-
-
 int pcie_init(struct controller * ctrl, struct pcie_device *dev)
 {
 	int rc;
@@ -1176,8 +1078,6 @@
 	u16 slot_status, slot_ctrl;
 	struct pci_dev *pdev;
 
-	DBG_ENTER_ROUTINE
-	
 	pdev = dev->port;
 	ctrl->pci_dev = pdev;	/* save pci_dev in context */
 
@@ -1201,9 +1101,11 @@
 	dbg("%s: CAPREG offset %x cap_reg %x\n",
 	    __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg);
 
-	if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040)
+	if (((cap_reg & SLOT_IMPL) == 0) ||
+	    (((cap_reg & DEV_PORT_TYPE) != 0x0040)
 		&& ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
-		dbg("%s : This is not a root port or the port is not connected to a slot\n", __FUNCTION__);
+		dbg("%s : This is not a root port or the port is not "
+		    "connected to a slot\n", __FUNCTION__);
 		goto abort_free_ctlr;
 	}
 
@@ -1236,14 +1138,15 @@
 	dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
 	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
 
-	for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
+	for (rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
 		if (pci_resource_len(pdev, rc) > 0)
 			dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc,
 			    (unsigned long long)pci_resource_start(pdev, rc),
 			    (unsigned long long)pci_resource_len(pdev, rc));
 
-	info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, 
-		pdev->subsystem_vendor, pdev->subsystem_device);
+	info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n",
+	     pdev->vendor, pdev->device,
+	     pdev->subsystem_vendor, pdev->subsystem_device);
 
 	mutex_init(&ctrl->crit_sect);
 	mutex_init(&ctrl->ctrl_lock);
@@ -1267,7 +1170,8 @@
 
 	dbg("%s: SLOTCTRL %x value read %x\n",
 	    __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
-	temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
+	temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) |
+		0x00;
 
 	rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
 	if (rc) {
@@ -1330,14 +1234,14 @@
 
 	if (ATTN_BUTTN(slot_cap))
 		intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
-	
+
 	if (POWER_CTRL(slot_cap))
 		intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE;
-	
+
 	if (MRL_SENS(slot_cap))
 		intr_enable = intr_enable | MRL_DETECT_ENABLE;
 
-	temp_word = (temp_word & ~intr_enable) | intr_enable; 
+	temp_word = (temp_word & ~intr_enable) | intr_enable;
 
 	if (pciehp_poll_mode) {
 		temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
@@ -1345,7 +1249,10 @@
 		temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
 	}
 
-	/* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
+	/*
+	 * Unmask Hot-plug Interrupt Enable for the interrupt
+	 * notification mechanism case.
+	 */
 	rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
 	if (rc) {
 		err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
@@ -1356,14 +1263,14 @@
 		err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
 		goto abort_disable_intr;
 	}
-	
+
 	temp_word =  0x1F; /* Clear all events */
 	rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
 	if (rc) {
 		err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
 		goto abort_disable_intr;
 	}
-	
+
 	if (pciehp_force) {
 		dbg("Bypassing BIOS check for pciehp use on %s\n",
 				pci_name(ctrl->pci_dev));
@@ -1375,10 +1282,9 @@
 
 	ctrl->hpc_ops = &pciehp_hpc_ops;
 
-	DBG_LEAVE_ROUTINE
 	return 0;
 
-	/* We end up here for the many possible ways to fail this API.  */
+	/* We end up here for the many possible ways to fail this API. */
 abort_disable_intr:
 	rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
 	if (!rc) {
@@ -1395,6 +1301,5 @@
 		free_irq(ctrl->pci_dev->irq, ctrl);
 
 abort_free_ctlr:
-	DBG_LEAVE_ROUTINE
 	return -1;
 }
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index 854aaea..c424ade 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -243,9 +243,10 @@
 
 int pciehp_unconfigure_device(struct slot *p_slot)
 {
-	int rc = 0;
+	int ret, rc = 0;
 	int j;
 	u8 bctl = 0;
+	u8 presence = 0;
 	struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
 
 	dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus,
@@ -263,23 +264,28 @@
 			continue;
 		}
 		if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
-			pci_read_config_byte(temp, PCI_BRIDGE_CONTROL, &bctl);
-			if (bctl & PCI_BRIDGE_CTL_VGA) {
-				err("Cannot remove display device %s\n",
+			ret = p_slot->hpc_ops->get_adapter_status(p_slot,
+								&presence);
+			if (!ret && presence) {
+				pci_read_config_byte(temp, PCI_BRIDGE_CONTROL,
+					&bctl);
+				if (bctl & PCI_BRIDGE_CTL_VGA) {
+					err("Cannot remove display device %s\n",
 						pci_name(temp));
-				pci_dev_put(temp);
-				continue;
+					pci_dev_put(temp);
+					continue;
+				}
 			}
 		}
 		pci_remove_bus_device(temp);
 		pci_dev_put(temp);
 	}
-	/* 
+	/*
 	 * Some PCI Express root ports require fixup after hot-plug operation.
 	 */
-	if (pcie_mch_quirk) 
+	if (pcie_mch_quirk)
 		pci_fixup_device(pci_fixup_final, p_slot->ctrl->pci_dev);
-	
+
 	return rc;
 }
 
diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c
index df07606..a080fed 100644
--- a/drivers/pci/hotplug/rpadlpar_sysfs.c
+++ b/drivers/pci/hotplug/rpadlpar_sysfs.c
@@ -129,17 +129,17 @@
 };
 
 struct kset dlpar_io_kset = {
-	.kobj = {.name = DLPAR_KOBJ_NAME,
-		 .ktype = &ktype_dlpar_io,
+	.kobj = {.ktype = &ktype_dlpar_io,
 		 .parent = &pci_hotplug_slots_subsys.kobj},
 	.ktype = &ktype_dlpar_io,
 };
 
 int dlpar_sysfs_init(void)
 {
+	kobject_set_name(&dlpar_io_kset.kobj, DLPAR_KOBJ_NAME);
 	if (kset_register(&dlpar_io_kset)) {
 		printk(KERN_ERR "rpadlpar_io: cannot register kset for %s\n",
-				dlpar_io_kset.kobj.name);
+				kobject_name(&dlpar_io_kset.kobj));
 		return -EINVAL;
 	}
 
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index be1df85..87e0161 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -132,7 +132,7 @@
 			pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
 		} else {
 			msg->address_hi = 0;
-			pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
+			pci_read_config_word(dev, msi_data_reg(pos, 0), &data);
 		}
 		msg->data = data;
 		break;
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index c806249..5c6a5d0 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -220,6 +220,7 @@
 }
 EXPORT_SYMBOL(pci_osc_control_set);
 
+#ifdef CONFIG_ACPI_SLEEP
 /*
  * _SxD returns the D-state with the highest power
  * (lowest D-state number) supported in the S-state "x".
@@ -245,16 +246,34 @@
  * currently we simply return _SxD, if present.
  */
 
-static int acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state)
+static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev,
+	pm_message_t state)
 {
-	/* TBD */
+	int acpi_state;
 
-	return -ENODEV;
+	acpi_state = acpi_pm_device_sleep_state(&pdev->dev,
+		device_may_wakeup(&pdev->dev), NULL);
+	if (acpi_state < 0)
+		return PCI_POWER_ERROR;
+
+	switch (acpi_state) {
+	case ACPI_STATE_D0:
+		return PCI_D0;
+	case ACPI_STATE_D1:
+		return PCI_D1;
+	case ACPI_STATE_D2:
+		return PCI_D2;
+	case ACPI_STATE_D3:
+		return PCI_D3hot;
+	}
+	return PCI_POWER_ERROR;
 }
+#endif
 
 static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
 {
 	acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
+	acpi_handle tmp;
 	static int state_conv[] = {
 		[0] = 0,
 		[1] = 1,
@@ -266,6 +285,9 @@
 
 	if (!handle)
 		return -ENODEV;
+	/* If the ACPI device has _EJ0, ignore the device */
+	if (ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp)))
+		return 0;
 	return acpi_bus_set_power(handle, acpi_state);
 }
 
@@ -320,7 +342,9 @@
 	ret = register_acpi_bus_type(&acpi_pci_bus);
 	if (ret)
 		return 0;
+#ifdef	CONFIG_ACPI_SLEEP
 	platform_pci_choose_state = acpi_pci_choose_state;
+#endif
 	platform_pci_set_power_state = acpi_pci_set_power_state;
 	return 0;
 }
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 8e58ea3..6e2760b 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -54,7 +54,6 @@
 	if (!dynid)
 		return -ENOMEM;
 
-	INIT_LIST_HEAD(&dynid->node);
 	dynid->id.vendor = vendor;
 	dynid->id.device = device;
 	dynid->id.subvendor = subvendor;
@@ -65,7 +64,7 @@
 		driver_data : 0UL;
 
 	spin_lock(&pdrv->dynids.lock);
-	list_add_tail(&pdrv->dynids.list, &dynid->node);
+	list_add_tail(&dynid->node, &pdrv->dynids.list);
 	spin_unlock(&pdrv->dynids.lock);
 
 	if (get_driver(&pdrv->driver)) {
@@ -310,7 +309,7 @@
 	/* restore the PCI config space */
 	pci_restore_state(pci_dev);
 	/* if the device was enabled before suspend, reenable */
-	retval = __pci_reenable_device(pci_dev);
+	retval = pci_reenable_device(pci_dev);
 	/* if the device was busmaster before the suspend, make it busmaster again */
 	if (pci_dev->is_busmaster)
 		pci_set_master(pci_dev);
@@ -532,8 +531,7 @@
 }
 
 #ifndef CONFIG_HOTPLUG
-int pci_uevent(struct device *dev, char **envp, int num_envp,
-	       char *buffer, int buffer_size)
+int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	return -ENODEV;
 }
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 03fd59e..728b3c8 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -17,11 +17,16 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
+#include <linux/log2.h>
 #include <asm/dma.h>	/* isa_dma_bridge_buggy */
 #include "pci.h"
 
 unsigned int pci_pm_d3_delay = 10;
 
+#ifdef CONFIG_PCI_DOMAINS
+int pci_domains_supported = 1;
+#endif
+
 #define DEFAULT_CARDBUS_IO_SIZE		(256)
 #define DEFAULT_CARDBUS_MEM_SIZE	(64*1024*1024)
 /* pci=cbmemsize=nnM,cbiosize=nn can override this */
@@ -499,7 +504,7 @@
 	return 0;
 }
 
-int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
+pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
  
 /**
  * pci_choose_state - Choose the power state of a PCI device
@@ -513,15 +518,15 @@
 
 pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
 {
-	int ret;
+	pci_power_t ret;
 
 	if (!pci_find_capability(dev, PCI_CAP_ID_PM))
 		return PCI_D0;
 
 	if (platform_pci_choose_state) {
 		ret = platform_pci_choose_state(dev, state);
-		if (ret >= 0)
-			state.event = ret;
+		if (ret != PCI_POWER_ERROR)
+			return ret;
 	}
 
 	switch (state.event) {
@@ -695,14 +700,13 @@
 }
 
 /**
- * __pci_reenable_device - Resume abandoned device
+ * pci_reenable_device - Resume abandoned device
  * @dev: PCI device to be resumed
  *
  *  Note this function is a backend of pci_default_resume and is not supposed
  *  to be called by normal code, write proper resume handler and use it instead.
  */
-int
-__pci_reenable_device(struct pci_dev *dev)
+int pci_reenable_device(struct pci_dev *dev)
 {
 	if (atomic_read(&dev->enable_cnt))
 		return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
@@ -1455,7 +1459,7 @@
 	int cap, err = -EINVAL;
 	u32 stat, cmd, v, o;
 
-	if (mmrbc < 512 || mmrbc > 4096 || (mmrbc & (mmrbc-1)))
+	if (mmrbc < 512 || mmrbc > 4096 || !is_power_of_2(mmrbc))
 		goto out;
 
 	v = ffs(mmrbc) - 10;
@@ -1517,7 +1521,7 @@
 /**
  * pcie_set_readrq - set PCI Express maximum memory read request
  * @dev: PCI device to query
- * @count: maximum memory read count in bytes
+ * @rq: maximum memory read count in bytes
  *    valid values are 128, 256, 512, 1024, 2048, 4096
  *
  * If possible sets maximum read byte count
@@ -1527,7 +1531,7 @@
 	int cap, err = -EINVAL;
 	u16 ctl, v;
 
-	if (rq < 128 || rq > 4096 || (rq & (rq-1)))
+	if (rq < 128 || rq > 4096 || !is_power_of_2(rq))
 		goto out;
 
 	v = (ffs(rq) - 8) << 12;
@@ -1567,6 +1571,13 @@
 	return bars;
 }
 
+static void __devinit pci_no_domains(void)
+{
+#ifdef CONFIG_PCI_DOMAINS
+	pci_domains_supported = 0;
+#endif
+}
+
 static int __devinit pci_init(void)
 {
 	struct pci_dev *dev = NULL;
@@ -1586,6 +1597,10 @@
 		if (*str && (str = pcibios_setup(str)) && *str) {
 			if (!strcmp(str, "nomsi")) {
 				pci_no_msi();
+			} else if (!strcmp(str, "noaer")) {
+				pci_no_aer();
+			} else if (!strcmp(str, "nodomains")) {
+				pci_no_domains();
 			} else if (!strncmp(str, "cbiosize=", 9)) {
 				pci_cardbus_io_size = memparse(str + 9, &str);
 			} else if (!strncmp(str, "cbmemsize=", 10)) {
@@ -1604,6 +1619,7 @@
 device_initcall(pci_init);
 
 EXPORT_SYMBOL_GPL(pci_restore_bars);
+EXPORT_SYMBOL(pci_reenable_device);
 EXPORT_SYMBOL(pci_enable_device_bars);
 EXPORT_SYMBOL(pci_enable_device);
 EXPORT_SYMBOL(pcim_enable_device);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 3fec13d..6fda33d 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1,19 +1,12 @@
 /* Functions internal to the PCI core code */
 
-extern int __must_check __pci_reenable_device(struct pci_dev *);
-extern int pci_uevent(struct device *dev, char **envp, int num_envp,
-		      char *buffer, int buffer_size);
+extern int pci_uevent(struct device *dev, struct kobj_uevent_env *env);
 extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
 extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
 extern void pci_cleanup_rom(struct pci_dev *dev);
-extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
-				  resource_size_t size, resource_size_t align,
-				  resource_size_t min, unsigned int type_mask,
-				  void (*alignf)(void *, struct resource *,
-					      resource_size_t, resource_size_t),
-				  void *alignf_data);
+
 /* Firmware callbacks */
-extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
+extern pci_power_t (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
 extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state);
 
 extern int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val);
@@ -36,7 +29,6 @@
 
 /* Functions for PCI Hotplug drivers to use */
 extern unsigned int pci_do_scan_bus(struct pci_bus *bus);
-extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap);
 
 extern void pci_remove_legacy_files(struct pci_bus *bus);
 
@@ -59,6 +51,12 @@
 static inline void pci_restore_msi_state(struct pci_dev *dev) {}
 #endif
 
+#ifdef CONFIG_PCIEAER
+void pci_no_aer(void);
+#else
+static inline void pci_no_aer(void) { }
+#endif
+
 static inline int pci_no_d1d2(struct pci_dev *dev)
 {
 	unsigned int parent_dstates = 0;
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 0ad92a8..287a931 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -25,13 +25,4 @@
 
 	  When in doubt, say N.
 
-config HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
-	bool "Use polling mechanism for hot-plug events (for testing purpose)"
-	depends on HOTPLUG_PCI_PCIE
-	help
-	  Say Y here if you want to use the polling mechanism for hot-plug 
-	  events for early platform testing.
-	   
-	  When in doubt, say N.
-
 source "drivers/pci/pcie/aer/Kconfig"
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index 6846fb4..7a62f7d 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -81,6 +81,13 @@
 	.reset_link	= aer_root_reset,
 };
 
+static int pcie_aer_disable;
+
+void pci_no_aer(void)
+{
+	pcie_aer_disable = 1;	/* has priority over 'forceload' */
+}
+
 /**
  * aer_irq - Root Port's ISR
  * @irq: IRQ assigned to Root Port
@@ -148,11 +155,10 @@
 {
 	struct aer_rpc *rpc;
 
-	if (!(rpc = kmalloc(sizeof(struct aer_rpc),
+	if (!(rpc = kzalloc(sizeof(struct aer_rpc),
 		GFP_KERNEL)))
 		return NULL;
 
-	memset(rpc, 0, sizeof(struct aer_rpc));
 	/*
 	 * Initialize Root lock access, e_lock, to Root Error Status Reg,
 	 * Root Error ID Reg, and Root error producer/consumer index.
@@ -328,6 +334,8 @@
  **/
 static int __init aer_service_init(void)
 {
+	if (pcie_aer_disable)
+		return -ENXIO;
 	return pcie_port_service_register(&aerdriver);
 }
 
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 34b8dae0..5db6b66 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -276,8 +276,7 @@
 			sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK);
 			if (sz) {
 				res->flags = (l & IORESOURCE_ROM_ENABLE) |
-				  IORESOURCE_MEM | IORESOURCE_PREFETCH |
-				  IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
+				  IORESOURCE_MEM | IORESOURCE_READONLY;
 				res->start = l & PCI_ROM_ADDRESS_MASK;
 				res->end = res->start + (unsigned long) sz;
 			}
@@ -285,7 +284,7 @@
 	}
 }
 
-void __devinit pci_read_bridge_bases(struct pci_bus *child)
+void pci_read_bridge_bases(struct pci_bus *child)
 {
 	struct pci_dev *dev = child->self;
 	u8 io_base_lo, io_limit_lo;
@@ -597,7 +596,7 @@
 		pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
 
 		if (!is_cardbus) {
-			child->bridge_ctl = bctl | PCI_BRIDGE_CTL_NO_ISA;
+			child->bridge_ctl = bctl;
 			/*
 			 * Adjust subordinate busnr in parent buses.
 			 * We do this before scanning for children because
@@ -653,20 +652,20 @@
 
 	sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
 
+	/* Has only triggered on CardBus, fixup is in yenta_socket */
 	while (bus->parent) {
 		if ((child->subordinate > bus->subordinate) ||
 		    (child->number > bus->subordinate) ||
 		    (child->number < bus->number) ||
 		    (child->subordinate < bus->number)) {
-			printk(KERN_WARNING "PCI: Bus #%02x (-#%02x) is "
-			       "hidden behind%s bridge #%02x (-#%02x)%s\n",
-			       child->number, child->subordinate,
-			       bus->self->transparent ? " transparent" : " ",
-			       bus->number, bus->subordinate,
-			       pcibios_assign_all_busses() ? " " :
-			       " (try 'pci=assign-busses')");
-			printk(KERN_WARNING "Please report the result to "
-			       "<bk@suse.de> to fix this permanently\n");
+			pr_debug("PCI: Bus #%02x (-#%02x) is %s"
+				"hidden behind%s bridge #%02x (-#%02x)\n",
+				child->number, child->subordinate,
+				(bus->number > child->subordinate &&
+				 bus->subordinate < child->number) ?
+					"wholly " : " partially",
+				bus->self->transparent ? " transparent" : " ",
+				bus->number, bus->subordinate);
 		}
 		bus = bus->parent;
 	}
@@ -744,22 +743,46 @@
 		 */
 		if (class == PCI_CLASS_STORAGE_IDE) {
 			u8 progif;
+			struct pci_bus_region region;
+
 			pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
 			if ((progif & 1) == 0) {
-				dev->resource[0].start = 0x1F0;
-				dev->resource[0].end = 0x1F7;
-				dev->resource[0].flags = LEGACY_IO_RESOURCE;
-				dev->resource[1].start = 0x3F6;
-				dev->resource[1].end = 0x3F6;
-				dev->resource[1].flags = LEGACY_IO_RESOURCE;
+				struct resource resource = {
+					.start = 0x1F0,
+					.end = 0x1F7,
+					.flags = LEGACY_IO_RESOURCE,
+				};
+
+				pcibios_resource_to_bus(dev, &region, &resource);
+				dev->resource[0].start = region.start;
+				dev->resource[0].end = region.end;
+				dev->resource[0].flags = resource.flags;
+				resource.start = 0x3F6;
+				resource.end = 0x3F6;
+				resource.flags = LEGACY_IO_RESOURCE;
+				pcibios_resource_to_bus(dev, &region, &resource);
+				dev->resource[1].start = region.start;
+				dev->resource[1].end = region.end;
+				dev->resource[1].flags = resource.flags;
 			}
 			if ((progif & 4) == 0) {
-				dev->resource[2].start = 0x170;
-				dev->resource[2].end = 0x177;
-				dev->resource[2].flags = LEGACY_IO_RESOURCE;
-				dev->resource[3].start = 0x376;
-				dev->resource[3].end = 0x376;
-				dev->resource[3].flags = LEGACY_IO_RESOURCE;
+				struct resource resource = {
+					.start = 0x170,
+					.end = 0x177,
+					.flags = LEGACY_IO_RESOURCE,
+				};
+
+				pcibios_resource_to_bus(dev, &region, &resource);
+				dev->resource[2].start = region.start;
+				dev->resource[2].end = region.end;
+				dev->resource[2].flags = resource.flags;
+				resource.start = 0x376;
+				resource.end = 0x376;
+				resource.flags = LEGACY_IO_RESOURCE;
+				pcibios_resource_to_bus(dev, &region, &resource);
+				dev->resource[3].start = region.start;
+				dev->resource[3].end = region.end;
+				dev->resource[3].flags = resource.flags;
 			}
 		}
 		break;
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 90adc62..716439e 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -60,7 +60,7 @@
 	 */
 
 	if (capable(CAP_SYS_ADMIN))
-		size = dev->cfg_size;
+		size = dp->size;
 	else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
 		size = 128;
 	else
@@ -129,11 +129,11 @@
 static ssize_t
 proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos)
 {
-	const struct inode *ino = file->f_path.dentry->d_inode;
+	struct inode *ino = file->f_path.dentry->d_inode;
 	const struct proc_dir_entry *dp = PDE(ino);
 	struct pci_dev *dev = dp->data;
 	int pos = *ppos;
-	int size = dev->cfg_size;
+	int size = dp->size;
 	int cnt;
 
 	if (pos >= size)
@@ -193,6 +193,7 @@
 	}
 
 	*ppos = pos;
+	i_size_write(ino, dp->size);
 	return nbytes;
 }
 
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index c559085..59d4da2 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -472,11 +472,9 @@
  */
 static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev)
 {
-	u8 rev;
 	u32 region;
 
-	pci_read_config_byte(dev, PCI_CLASS_REVISION, &rev);
-	if (rev & 0x10) {
+	if (dev->revision & 0x10) {
 		pci_read_config_dword(dev, 0x48, &region);
 		region &= PCI_BASE_ADDRESS_IO_MASK;
 		quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI");
@@ -629,12 +627,9 @@
  */
 static void __init quirk_amd_8131_mmrbc(struct pci_dev *dev)
 {
-	unsigned char revid;
-
-	pci_read_config_byte(dev, PCI_REVISION_ID, &revid);
-	if (dev->subordinate && revid <= 0x12) {
+	if (dev->subordinate && dev->revision <= 0x12) {
 		printk(KERN_INFO "AMD8131 rev %x detected, disabling PCI-X "
-				"MMRBC\n", revid);
+				"MMRBC\n", dev->revision);
 		dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MMRBC;
 	}
 }
@@ -930,38 +925,6 @@
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82375,	quirk_eisa_bridge );
 
-/*
- * On the MSI-K8T-Neo2Fir Board, the internal Soundcard is disabled
- * when a PCI-Soundcard is added. The BIOS only gives Options
- * "Disabled" and "AUTO". This Quirk Sets the corresponding
- * Register-Value to enable the Soundcard.
- *
- * FIXME: Presently this quirk will run on anything that has an 8237
- * which isn't correct, we need to check DMI tables or something in
- * order to make sure it only runs on the MSI-K8T-Neo2Fir.  Because it
- * runs everywhere at present we suppress the printk output in most
- * irrelevant cases.
- */
-static void k8t_sound_hostbridge(struct pci_dev *dev)
-{
-	unsigned char val;
-
-	pci_read_config_byte(dev, 0x50, &val);
-	if (val == 0x88 || val == 0xc8) {
-		/* Assume it's probably a MSI-K8T-Neo2Fir */
-		printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, attempting to turn soundcard ON\n");
-		pci_write_config_byte(dev, 0x50, val & (~0x40));
-
-		/* Verify the Change for Status output */
-		pci_read_config_byte(dev, 0x50, &val);
-		if (val & 0x40)
-			printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard still off\n");
-		else
-			printk(KERN_INFO "PCI: MSI-K8T-Neo2Fir, soundcard on\n");
-	}
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge);
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge);
 
 /*
  * On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge
@@ -972,8 +935,8 @@
  *
  * The SMBus PCI Device can be activated by setting a bit in the ICH LPC 
  * bridge. Unfortunately, this device has no subvendor/subdevice ID. So it 
- * becomes necessary to do this tweak in two steps -- I've chosen the Host
- * bridge as trigger.
+ * becomes necessary to do this tweak in two steps -- the chosen trigger
+ * is either the Host bridge (preferred) or on-board VGA controller.
  *
  * Note that we used to unhide the SMBus that way on Toshiba laptops
  * (Satellite A40 and Tecra M2) but then found that the thermal management
@@ -1070,6 +1033,14 @@
 			case 0x0058: /* Compaq Evo N620c */
 				asus_hides_smbus = 1;
 			}
+		else if (dev->device == PCI_DEVICE_ID_INTEL_82810_IG3)
+			switch(dev->subsystem_device) {
+			case 0xB16C: /* Compaq Deskpro EP 401963-001 (PCA# 010174) */
+				/* Motherboard doesn't have Host bridge
+				 * subvendor/subdevice IDs, therefore checking
+				 * its on-board VGA controller */
+				asus_hides_smbus = 1;
+			}
 	}
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82845_HB,	asus_hides_smbus_hostbridge );
@@ -1082,6 +1053,8 @@
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82855GM_HB,	asus_hides_smbus_hostbridge );
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge );
 
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82810_IG3,	asus_hides_smbus_hostbridge );
+
 static void asus_hides_smbus_lpc(struct pci_dev *dev)
 {
 	u16 val;
@@ -1099,12 +1072,14 @@
 			printk(KERN_INFO "PCI: Enabled i801 SMBus device\n");
 	}
 }
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801AA_0,	asus_hides_smbus_lpc );
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801DB_0,	asus_hides_smbus_lpc );
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801BA_0,	asus_hides_smbus_lpc );
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801CA_0,	asus_hides_smbus_lpc );
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801CA_12,	asus_hides_smbus_lpc );
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801DB_12,	asus_hides_smbus_lpc );
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801EB_0,	asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801AA_0,	asus_hides_smbus_lpc );
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801DB_0,	asus_hides_smbus_lpc );
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801BA_0,	asus_hides_smbus_lpc );
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801CA_0,	asus_hides_smbus_lpc );
@@ -1432,7 +1407,6 @@
 static void __devinit quirk_e100_interrupt(struct pci_dev *dev)
 {
 	u16 command;
-	u32 bar;
 	u8 __iomem *csr;
 	u8 cmd_hi;
 
@@ -1464,12 +1438,12 @@
 	 * re-enable them when it's ready.
 	 */
 	pci_read_config_word(dev, PCI_COMMAND, &command);
-	pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar);
 
-	if (!(command & PCI_COMMAND_MEMORY) || !bar)
+	if (!(command & PCI_COMMAND_MEMORY) || !pci_resource_start(dev, 0))
 		return;
 
-	csr = ioremap(bar, 8);
+	/* Convert from PCI bus to resource space.  */
+	csr = ioremap(pci_resource_start(dev, 0), 8);
 	if (!csr) {
 		printk(KERN_WARNING "PCI: Can't map %s e100 registers\n",
 			pci_name(dev));
@@ -1485,7 +1459,7 @@
 
 	iounmap(csr);
 }
-DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_e100_interrupt);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_e100_interrupt);
 
 static void __devinit fixup_rev1_53c810(struct pci_dev* dev)
 {
@@ -1650,6 +1624,9 @@
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000_PCIX, quirk_disable_all_msi);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS400_200, quirk_disable_all_msi);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS480, quirk_disable_all_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RD580, quirk_disable_all_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RX790, quirk_disable_all_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS690, quirk_disable_all_msi);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disable_all_msi);
 
 /* Disable MSI on chipsets that are known to not support it */
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 5e5191e..401e03c 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -472,7 +472,12 @@
 		break;
 
 	case PCI_CLASS_BRIDGE_PCI:
+		/* don't size subtractive decoding (transparent)
+		 * PCI-to-PCI bridges */
+		if (bus->self->transparent)
+			break;
 		pci_bridge_check_ranges(bus);
+		/* fall through */
 	default:
 		pbus_size_io(bus);
 		/* If the bridge supports prefetchable range, size it
diff --git a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c
index 568f187..05ca2ed 100644
--- a/drivers/pci/setup-irq.c
+++ b/drivers/pci/setup-irq.c
@@ -48,7 +48,7 @@
 	dev->irq = irq;
 
 	pr_debug("PCI: fixup irq: (%s) got %d\n",
-		dev->dev.kobj.name, dev->irq);
+		kobject_name(&dev->dev.kobj), dev->irq);
 
 	/* Always tell the device, so the driver knows what is
 	   the real IRQ to use; the device does not use it. */
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 7c93a10..a0aca46 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -409,6 +409,9 @@
 #endif
 	s->functions = 0;
 
+	/* give socket some time to power down */
+	msleep(100);
+
 	s->ops->get_status(s, &status);
 	if (status & SS_POWERON) {
 		printk(KERN_ERR "PCMCIA: socket %p: *** DANGER *** unable to remove socket power\n", s);
@@ -904,18 +907,14 @@
 EXPORT_SYMBOL(pcmcia_insert_card);
 
 
-static int pcmcia_socket_uevent(struct device *dev, char **envp,
-			        int num_envp, char *buffer, int buffer_size)
+static int pcmcia_socket_uevent(struct device *dev,
+				struct kobj_uevent_env *env)
 {
 	struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
-	int i = 0, length = 0;
 
-	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-			   &length, "SOCKET_NO=%u", s->sock))
+	if (add_uevent_var(env, "SOCKET_NO=%u", s->sock))
 		return -ENOMEM;
 
-	envp[i] = NULL;
-
 	return 0;
 }
 
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 143c6ef..55baa1f 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -1064,11 +1064,10 @@
 
 #ifdef CONFIG_HOTPLUG
 
-static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
-			     char *buffer, int buffer_size)
+static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct pcmcia_device *p_dev;
-	int i, length = 0;
+	int i;
 	u32 hash[4] = { 0, 0, 0, 0};
 
 	if (!dev)
@@ -1083,23 +1082,13 @@
 		hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i]));
 	}
 
-	i = 0;
-
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "SOCKET_NO=%u",
-			   p_dev->socket->sock))
+	if (add_uevent_var(env, "SOCKET_NO=%u", p_dev->socket->sock))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "DEVICE_NO=%02X",
-			   p_dev->device_no))
+	if (add_uevent_var(env, "DEVICE_NO=%02X", p_dev->device_no))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
+	if (add_uevent_var(env, "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
 			   "pa%08Xpb%08Xpc%08Xpd%08X",
 			   p_dev->has_manf_id ? p_dev->manf_id : 0,
 			   p_dev->has_card_id ? p_dev->card_id : 0,
@@ -1112,21 +1101,46 @@
 			   hash[3]))
 		return -ENOMEM;
 
-	envp[i] = NULL;
-
 	return 0;
 }
 
 #else
 
-static int pcmcia_bus_uevent(struct device *dev, char **envp, int num_envp,
-			      char *buffer, int buffer_size)
+static int pcmcia_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	return -ENODEV;
 }
 
 #endif
 
+/************************ runtime PM support ***************************/
+
+static int pcmcia_dev_suspend(struct device *dev, pm_message_t state);
+static int pcmcia_dev_resume(struct device *dev);
+
+static int runtime_suspend(struct device *dev)
+{
+	int rc;
+
+	down(&dev->sem);
+	rc = pcmcia_dev_suspend(dev, PMSG_SUSPEND);
+	up(&dev->sem);
+	if (!rc)
+		dev->power.power_state.event = PM_EVENT_SUSPEND;
+	return rc;
+}
+
+static void runtime_resume(struct device *dev)
+{
+	int rc;
+
+	down(&dev->sem);
+	rc = pcmcia_dev_resume(dev);
+	up(&dev->sem);
+	if (!rc)
+		dev->power.power_state.event = PM_EVENT_ON;
+}
+
 /************************ per-device sysfs output ***************************/
 
 #define pcmcia_device_attr(field, test, format)				\
@@ -1173,9 +1187,9 @@
                 return -EINVAL;
 
 	if ((!p_dev->suspended) && !strncmp(buf, "off", 3))
-		ret = dpm_runtime_suspend(dev, PMSG_SUSPEND);
+		ret = runtime_suspend(dev);
 	else if (p_dev->suspended && !strncmp(buf, "on", 2))
-		dpm_runtime_resume(dev);
+		runtime_resume(dev);
 
 	return ret ? ret : count;
 }
@@ -1312,10 +1326,10 @@
 	struct pcmcia_socket *skt = _data;
 	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
 
-	if (p_dev->socket != skt)
+	if (p_dev->socket != skt || p_dev->suspended)
 		return 0;
 
-	return dpm_runtime_suspend(dev, PMSG_SUSPEND);
+	return runtime_suspend(dev);
 }
 
 static int pcmcia_bus_resume_callback(struct device *dev, void * _data)
@@ -1323,10 +1337,10 @@
 	struct pcmcia_socket *skt = _data;
 	struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
 
-	if (p_dev->socket != skt)
+	if (p_dev->socket != skt || !p_dev->suspended)
 		return 0;
 
-	dpm_runtime_resume(dev);
+	runtime_resume(dev);
 
 	return 0;
 }
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index 3c45142..b019854 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -1316,7 +1316,7 @@
 MODULE_DEVICE_TABLE(of, m8xx_pcmcia_match);
 
 static struct of_platform_driver m8xx_pcmcia_driver = {
-	.name = (char *)driver_name,
+	.name = driver_name,
 	.match_table = m8xx_pcmcia_match,
 	.probe = m8xx_probe,
 	.remove = m8xx_remove,
diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c
index 383107b..f6722ba 100644
--- a/drivers/pcmcia/pxa2xx_mainstone.c
+++ b/drivers/pcmcia/pxa2xx_mainstone.c
@@ -175,7 +175,6 @@
 	if (!mst_pcmcia_device)
 		return -ENOMEM;
 
-	mst_pcmcia_device->dev.uevent_suppress = 0;
 	mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops;
 
 	ret = platform_device_add(mst_pcmcia_device);
@@ -195,3 +194,4 @@
 module_exit(mst_pcmcia_exit);
 
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
index a2daa3f..d5c33bd 100644
--- a/drivers/pcmcia/pxa2xx_sharpsl.c
+++ b/drivers/pcmcia/pxa2xx_sharpsl.c
@@ -261,7 +261,6 @@
 	if (!sharpsl_pcmcia_device)
 		return -ENOMEM;
 
-	sharpsl_pcmcia_device->dev.uevent_suppress = 0;
 	sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops;
 	sharpsl_pcmcia_device->dev.parent = platform_scoop_config->devs[0].dev;
 
@@ -284,3 +283,4 @@
 
 MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c
index dd6384b..6c0440c 100644
--- a/drivers/pnp/card.c
+++ b/drivers/pnp/card.c
@@ -2,7 +2,6 @@
  * card.c - contains functions for managing groups of PnP devices
  *
  * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
- *
  */
 
 #include <linux/module.h>
@@ -13,26 +12,31 @@
 LIST_HEAD(pnp_cards);
 static LIST_HEAD(pnp_card_drivers);
 
-
-static const struct pnp_card_device_id * match_card(struct pnp_card_driver * drv, struct pnp_card * card)
+static const struct pnp_card_device_id *match_card(struct pnp_card_driver *drv,
+						   struct pnp_card *card)
 {
-	const struct pnp_card_device_id * drv_id = drv->id_table;
-	while (*drv_id->id){
-		if (compare_pnp_id(card->id,drv_id->id)) {
+	const struct pnp_card_device_id *drv_id = drv->id_table;
+
+	while (*drv_id->id) {
+		if (compare_pnp_id(card->id, drv_id->id)) {
 			int i = 0;
+
 			for (;;) {
 				int found;
 				struct pnp_dev *dev;
-				if (i == PNP_MAX_DEVICES || ! *drv_id->devs[i].id)
+
+				if (i == PNP_MAX_DEVICES ||
+				    !*drv_id->devs[i].id)
 					return drv_id;
 				found = 0;
 				card_for_each_dev(card, dev) {
-					if (compare_pnp_id(dev->id, drv_id->devs[i].id)) {
+					if (compare_pnp_id(dev->id,
+						   drv_id->devs[i].id)) {
 						found = 1;
 						break;
 					}
 				}
-				if (! found)
+				if (!found)
 					break;
 				i++;
 			}
@@ -42,14 +46,15 @@
 	return NULL;
 }
 
-static void card_remove(struct pnp_dev * dev)
+static void card_remove(struct pnp_dev *dev)
 {
 	dev->card_link = NULL;
 }
 
-static void card_remove_first(struct pnp_dev * dev)
+static void card_remove_first(struct pnp_dev *dev)
 {
-	struct pnp_card_driver * drv = to_pnp_card_driver(dev->driver);
+	struct pnp_card_driver *drv = to_pnp_card_driver(dev->driver);
+
 	if (!dev->card || !drv)
 		return;
 	if (drv->remove)
@@ -67,7 +72,7 @@
 
 	if (!drv->probe)
 		return 0;
-	id = match_card(drv,card);
+	id = match_card(drv, card);
 	if (!id)
 		return 0;
 
@@ -94,12 +99,11 @@
  * pnp_add_card_id - adds an EISA id to the specified card
  * @id: pointer to a pnp_id structure
  * @card: pointer to the desired card
- *
  */
-
-int pnp_add_card_id(struct pnp_id *id, struct pnp_card * card)
+int pnp_add_card_id(struct pnp_id *id, struct pnp_card *card)
 {
-	struct pnp_id * ptr;
+	struct pnp_id *ptr;
+
 	if (!id)
 		return -EINVAL;
 	if (!card)
@@ -115,10 +119,11 @@
 	return 0;
 }
 
-static void pnp_free_card_ids(struct pnp_card * card)
+static void pnp_free_card_ids(struct pnp_card *card)
 {
-	struct pnp_id * id;
+	struct pnp_id *id;
 	struct pnp_id *next;
+
 	if (!card)
 		return;
 	id = card->id;
@@ -131,49 +136,55 @@
 
 static void pnp_release_card(struct device *dmdev)
 {
-	struct pnp_card * card = to_pnp_card(dmdev);
+	struct pnp_card *card = to_pnp_card(dmdev);
+
 	pnp_free_card_ids(card);
 	kfree(card);
 }
 
-
-static ssize_t pnp_show_card_name(struct device *dmdev, struct device_attribute *attr, char *buf)
+static ssize_t pnp_show_card_name(struct device *dmdev,
+				  struct device_attribute *attr, char *buf)
 {
 	char *str = buf;
 	struct pnp_card *card = to_pnp_card(dmdev);
-	str += sprintf(str,"%s\n", card->name);
+
+	str += sprintf(str, "%s\n", card->name);
 	return (str - buf);
 }
 
-static DEVICE_ATTR(name,S_IRUGO,pnp_show_card_name,NULL);
+static DEVICE_ATTR(name, S_IRUGO, pnp_show_card_name, NULL);
 
-static ssize_t pnp_show_card_ids(struct device *dmdev, struct device_attribute *attr, char *buf)
+static ssize_t pnp_show_card_ids(struct device *dmdev,
+				 struct device_attribute *attr, char *buf)
 {
 	char *str = buf;
 	struct pnp_card *card = to_pnp_card(dmdev);
-	struct pnp_id * pos = card->id;
+	struct pnp_id *pos = card->id;
 
 	while (pos) {
-		str += sprintf(str,"%s\n", pos->id);
+		str += sprintf(str, "%s\n", pos->id);
 		pos = pos->next;
 	}
 	return (str - buf);
 }
 
-static DEVICE_ATTR(card_id,S_IRUGO,pnp_show_card_ids,NULL);
+static DEVICE_ATTR(card_id, S_IRUGO, pnp_show_card_ids, NULL);
 
 static int pnp_interface_attach_card(struct pnp_card *card)
 {
-	int rc = device_create_file(&card->dev,&dev_attr_name);
-	if (rc) return rc;
+	int rc = device_create_file(&card->dev, &dev_attr_name);
 
-	rc = device_create_file(&card->dev,&dev_attr_card_id);
-	if (rc) goto err_name;
+	if (rc)
+		return rc;
+
+	rc = device_create_file(&card->dev, &dev_attr_card_id);
+	if (rc)
+		goto err_name;
 
 	return 0;
 
 err_name:
-	device_remove_file(&card->dev,&dev_attr_name);
+	device_remove_file(&card->dev, &dev_attr_name);
 	return rc;
 }
 
@@ -181,15 +192,16 @@
  * pnp_add_card - adds a PnP card to the PnP Layer
  * @card: pointer to the card to add
  */
-
-int pnp_add_card(struct pnp_card * card)
+int pnp_add_card(struct pnp_card *card)
 {
 	int error;
-	struct list_head * pos, * temp;
+	struct list_head *pos, *temp;
+
 	if (!card || !card->protocol)
 		return -EINVAL;
 
-	sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number, card->number);
+	sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number,
+		card->number);
 	card->dev.parent = &card->protocol->dev;
 	card->dev.bus = NULL;
 	card->dev.release = &pnp_release_card;
@@ -205,18 +217,21 @@
 		/* we wait until now to add devices in order to ensure the drivers
 		 * will be able to use all of the related devices on the card
 		 * without waiting any unresonable length of time */
-		list_for_each(pos,&card->devices){
+		list_for_each(pos, &card->devices) {
 			struct pnp_dev *dev = card_to_pnp_dev(pos);
 			__pnp_add_device(dev);
 		}
 
 		/* match with card drivers */
-		list_for_each_safe(pos,temp,&pnp_card_drivers){
-			struct pnp_card_driver * drv = list_entry(pos, struct pnp_card_driver, global_list);
-			card_probe(card,drv);
+		list_for_each_safe(pos, temp, &pnp_card_drivers) {
+			struct pnp_card_driver *drv =
+			    list_entry(pos, struct pnp_card_driver,
+				       global_list);
+			card_probe(card, drv);
 		}
 	} else
-		pnp_err("sysfs failure, card '%s' will be unavailable", card->dev.bus_id);
+		pnp_err("sysfs failure, card '%s' will be unavailable",
+			card->dev.bus_id);
 	return error;
 }
 
@@ -224,10 +239,10 @@
  * pnp_remove_card - removes a PnP card from the PnP Layer
  * @card: pointer to the card to remove
  */
-
-void pnp_remove_card(struct pnp_card * card)
+void pnp_remove_card(struct pnp_card *card)
 {
 	struct list_head *pos, *temp;
+
 	if (!card)
 		return;
 	device_unregister(&card->dev);
@@ -235,7 +250,7 @@
 	list_del(&card->global_list);
 	list_del(&card->protocol_list);
 	spin_unlock(&pnp_lock);
-	list_for_each_safe(pos,temp,&card->devices){
+	list_for_each_safe(pos, temp, &card->devices) {
 		struct pnp_dev *dev = card_to_pnp_dev(pos);
 		pnp_remove_card_device(dev);
 	}
@@ -246,15 +261,14 @@
  * @card: pointer to the card to add to
  * @dev: pointer to the device to add
  */
-
-int pnp_add_card_device(struct pnp_card * card, struct pnp_dev * dev)
+int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev)
 {
 	if (!card || !dev || !dev->protocol)
 		return -EINVAL;
 	dev->dev.parent = &card->dev;
 	dev->card_link = NULL;
-	snprintf(dev->dev.bus_id, BUS_ID_SIZE, "%02x:%02x.%02x", dev->protocol->number,
-		 card->number,dev->number);
+	snprintf(dev->dev.bus_id, BUS_ID_SIZE, "%02x:%02x.%02x",
+		 dev->protocol->number, card->number, dev->number);
 	spin_lock(&pnp_lock);
 	dev->card = card;
 	list_add_tail(&dev->card_list, &card->devices);
@@ -266,8 +280,7 @@
  * pnp_remove_card_device- removes a device from the specified card
  * @dev: pointer to the device to remove
  */
-
-void pnp_remove_card_device(struct pnp_dev * dev)
+void pnp_remove_card_device(struct pnp_dev *dev)
 {
 	spin_lock(&pnp_lock);
 	dev->card = NULL;
@@ -282,13 +295,14 @@
  * @id: pointer to a PnP ID structure that explains the rules for finding the device
  * @from: Starting place to search from. If NULL it will start from the begining.
  */
-
-struct pnp_dev * pnp_request_card_device(struct pnp_card_link *clink, const char * id, struct pnp_dev * from)
+struct pnp_dev *pnp_request_card_device(struct pnp_card_link *clink,
+					const char *id, struct pnp_dev *from)
 {
-	struct list_head * pos;
-	struct pnp_dev * dev;
-	struct pnp_card_driver * drv;
-	struct pnp_card * card;
+	struct list_head *pos;
+	struct pnp_dev *dev;
+	struct pnp_card_driver *drv;
+	struct pnp_card *card;
+
 	if (!clink || !id)
 		goto done;
 	card = clink->card;
@@ -302,7 +316,7 @@
 	}
 	while (pos != &card->devices) {
 		dev = card_to_pnp_dev(pos);
-		if ((!dev->card_link) && compare_pnp_id(dev->id,id))
+		if ((!dev->card_link) && compare_pnp_id(dev->id, id))
 			goto found;
 		pos = pos->next;
 	}
@@ -330,10 +344,10 @@
  * pnp_release_card_device - call this when the driver no longer needs the device
  * @dev: pointer to the PnP device stucture
  */
-
-void pnp_release_card_device(struct pnp_dev * dev)
+void pnp_release_card_device(struct pnp_dev *dev)
 {
-	struct pnp_card_driver * drv = dev->card_link->driver;
+	struct pnp_card_driver *drv = dev->card_link->driver;
+
 	if (!drv)
 		return;
 	drv->link.remove = &card_remove;
@@ -347,6 +361,7 @@
 static int card_suspend(struct pnp_dev *dev, pm_message_t state)
 {
 	struct pnp_card_link *link = dev->card_link;
+
 	if (link->pm_state.event == state.event)
 		return 0;
 	link->pm_state = state;
@@ -356,6 +371,7 @@
 static int card_resume(struct pnp_dev *dev)
 {
 	struct pnp_card_link *link = dev->card_link;
+
 	if (link->pm_state.event == PM_EVENT_ON)
 		return 0;
 	link->pm_state = PMSG_ON;
@@ -367,8 +383,7 @@
  * pnp_register_card_driver - registers a PnP card driver with the PnP Layer
  * @drv: pointer to the driver to register
  */
-
-int pnp_register_card_driver(struct pnp_card_driver * drv)
+int pnp_register_card_driver(struct pnp_card_driver *drv)
 {
 	int error;
 	struct list_head *pos, *temp;
@@ -389,9 +404,10 @@
 	list_add_tail(&drv->global_list, &pnp_card_drivers);
 	spin_unlock(&pnp_lock);
 
-	list_for_each_safe(pos,temp,&pnp_cards){
-		struct pnp_card *card = list_entry(pos, struct pnp_card, global_list);
-		card_probe(card,drv);
+	list_for_each_safe(pos, temp, &pnp_cards) {
+		struct pnp_card *card =
+		    list_entry(pos, struct pnp_card, global_list);
+		card_probe(card, drv);
 	}
 	return 0;
 }
@@ -400,8 +416,7 @@
  * pnp_unregister_card_driver - unregisters a PnP card driver from the PnP Layer
  * @drv: pointer to the driver to unregister
  */
-
-void pnp_unregister_card_driver(struct pnp_card_driver * drv)
+void pnp_unregister_card_driver(struct pnp_card_driver *drv)
 {
 	spin_lock(&pnp_lock);
 	list_del(&drv->global_list);
@@ -409,13 +424,6 @@
 	pnp_unregister_driver(&drv->link);
 }
 
-#if 0
-EXPORT_SYMBOL(pnp_add_card);
-EXPORT_SYMBOL(pnp_remove_card);
-EXPORT_SYMBOL(pnp_add_card_device);
-EXPORT_SYMBOL(pnp_remove_card_device);
-EXPORT_SYMBOL(pnp_add_card_id);
-#endif  /*  0  */
 EXPORT_SYMBOL(pnp_request_card_device);
 EXPORT_SYMBOL(pnp_release_card_device);
 EXPORT_SYMBOL(pnp_register_card_driver);
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index 3e20b1c..d5964fe 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -2,7 +2,6 @@
  * core.c - contains all core device and protocol registration functions
  *
  * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
- *
  */
 
 #include <linux/pnp.h>
@@ -18,7 +17,6 @@
 
 #include "base.h"
 
-
 static LIST_HEAD(pnp_protocols);
 LIST_HEAD(pnp_global);
 DEFINE_SPINLOCK(pnp_lock);
@@ -35,12 +33,11 @@
 {
 	void *result;
 
-	result = kmalloc(size, GFP_KERNEL);
-	if (!result){
+	result = kzalloc(size, GFP_KERNEL);
+	if (!result) {
 		printk(KERN_ERR "pnp: Out of Memory\n");
 		return NULL;
 	}
-	memset(result, 0, size);
 	return result;
 }
 
@@ -50,14 +47,10 @@
  *
  *  Ex protocols: ISAPNP, PNPBIOS, etc
  */
-
 int pnp_register_protocol(struct pnp_protocol *protocol)
 {
 	int nodenum;
-	struct list_head * pos;
-
-	if (!protocol)
-		return -EINVAL;
+	struct list_head *pos;
 
 	INIT_LIST_HEAD(&protocol->devices);
 	INIT_LIST_HEAD(&protocol->cards);
@@ -65,9 +58,9 @@
 	spin_lock(&pnp_lock);
 
 	/* assign the lowest unused number */
-	list_for_each(pos,&pnp_protocols) {
-		struct pnp_protocol * cur = to_pnp_protocol(pos);
-		if (cur->number == nodenum){
+	list_for_each(pos, &pnp_protocols) {
+		struct pnp_protocol *cur = to_pnp_protocol(pos);
+		if (cur->number == nodenum) {
 			pos = &pnp_protocols;
 			nodenum++;
 		}
@@ -84,7 +77,6 @@
 /**
  * pnp_protocol_unregister - removes a pnp protocol from the pnp layer
  * @protocol: pointer to the corresponding pnp_protocol structure
- *
  */
 void pnp_unregister_protocol(struct pnp_protocol *protocol)
 {
@@ -94,13 +86,11 @@
 	device_unregister(&protocol->dev);
 }
 
-
 static void pnp_free_ids(struct pnp_dev *dev)
 {
-	struct pnp_id * id;
-	struct pnp_id * next;
-	if (!dev)
-		return;
+	struct pnp_id *id;
+	struct pnp_id *next;
+
 	id = dev->id;
 	while (id) {
 		next = id->next;
@@ -111,7 +101,8 @@
 
 static void pnp_release_device(struct device *dmdev)
 {
-	struct pnp_dev * dev = to_pnp_dev(dmdev);
+	struct pnp_dev *dev = to_pnp_dev(dmdev);
+
 	pnp_free_option(dev->independent);
 	pnp_free_option(dev->dependent);
 	pnp_free_ids(dev);
@@ -121,6 +112,7 @@
 int __pnp_add_device(struct pnp_dev *dev)
 {
 	int ret;
+
 	pnp_fixup_device(dev);
 	dev->dev.bus = &pnp_bus_type;
 	dev->dev.dma_mask = &dev->dma_mask;
@@ -144,13 +136,13 @@
  *
  *  adds to driver model, name database, fixups, interface, etc.
  */
-
 int pnp_add_device(struct pnp_dev *dev)
 {
-	if (!dev || !dev->protocol || dev->card)
+	if (dev->card)
 		return -EINVAL;
 	dev->dev.parent = &dev->protocol->dev;
-	sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number, dev->number);
+	sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number,
+		dev->number);
 	return __pnp_add_device(dev);
 }
 
@@ -163,21 +155,6 @@
 	device_unregister(&dev->dev);
 }
 
-/**
- * pnp_remove_device - removes a pnp device from the pnp layer
- * @dev: pointer to dev to add
- *
- * this function will free all mem used by dev
- */
-#if 0
-void pnp_remove_device(struct pnp_dev *dev)
-{
-	if (!dev || dev->card)
-		return;
-	__pnp_remove_device(dev);
-}
-#endif  /*  0  */
-
 static int __init pnp_init(void)
 {
 	printk(KERN_INFO "Linux Plug and Play Support v0.97 (c) Adam Belay\n");
@@ -185,10 +162,3 @@
 }
 
 subsys_initcall(pnp_init);
-
-#if 0
-EXPORT_SYMBOL(pnp_register_protocol);
-EXPORT_SYMBOL(pnp_unregister_protocol);
-EXPORT_SYMBOL(pnp_add_device);
-EXPORT_SYMBOL(pnp_remove_device);
-#endif  /*  0  */
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index e161423..2fa64a6 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -2,7 +2,6 @@
  * driver.c - device id matching, driver model, etc.
  *
  * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
- *
  */
 
 #include <linux/string.h>
@@ -16,12 +15,11 @@
 static int compare_func(const char *ida, const char *idb)
 {
 	int i;
+
 	/* we only need to compare the last 4 chars */
-	for (i=3; i<7; i++)
-	{
+	for (i = 3; i < 7; i++) {
 		if (ida[i] != 'X' &&
-		    idb[i] != 'X' &&
-		    toupper(ida[i]) != toupper(idb[i]))
+		    idb[i] != 'X' && toupper(ida[i]) != toupper(idb[i]))
 			return 0;
 	}
 	return 1;
@@ -31,20 +29,22 @@
 {
 	if (!pos || !id || (strlen(id) != 7))
 		return 0;
-	if (memcmp(id,"ANYDEVS",7)==0)
+	if (memcmp(id, "ANYDEVS", 7) == 0)
 		return 1;
-	while (pos){
-		if (memcmp(pos->id,id,3)==0)
-			if (compare_func(pos->id,id)==1)
+	while (pos) {
+		if (memcmp(pos->id, id, 3) == 0)
+			if (compare_func(pos->id, id) == 1)
 				return 1;
 		pos = pos->next;
 	}
 	return 0;
 }
 
-static const struct pnp_device_id * match_device(struct pnp_driver *drv, struct pnp_dev *dev)
+static const struct pnp_device_id *match_device(struct pnp_driver *drv,
+						struct pnp_dev *dev)
 {
 	const struct pnp_device_id *drv_id = drv->id_table;
+
 	if (!drv_id)
 		return NULL;
 
@@ -59,7 +59,7 @@
 int pnp_device_attach(struct pnp_dev *pnp_dev)
 {
 	spin_lock(&pnp_lock);
-	if(pnp_dev->status != PNP_READY){
+	if (pnp_dev->status != PNP_READY) {
 		spin_unlock(&pnp_lock);
 		return -EBUSY;
 	}
@@ -86,7 +86,8 @@
 	pnp_dev = to_pnp_dev(dev);
 	pnp_drv = to_pnp_driver(dev->driver);
 
-	pnp_dbg("match found with the PnP device '%s' and the driver '%s'", dev->bus_id,pnp_drv->name);
+	pnp_dbg("match found with the PnP device '%s' and the driver '%s'",
+		dev->bus_id, pnp_drv->name);
 
 	error = pnp_device_attach(pnp_dev);
 	if (error < 0)
@@ -99,7 +100,7 @@
 				return error;
 		}
 	} else if ((pnp_drv->flags & PNP_DRIVER_RES_DISABLE)
-		    == PNP_DRIVER_RES_DISABLE) {
+		   == PNP_DRIVER_RES_DISABLE) {
 		error = pnp_disable_dev(pnp_dev);
 		if (error < 0)
 			return error;
@@ -110,7 +111,7 @@
 		if (dev_id != NULL)
 			error = pnp_drv->probe(pnp_dev, dev_id);
 	}
-	if (error >= 0){
+	if (error >= 0) {
 		pnp_dev->driver = pnp_drv;
 		error = 0;
 	} else
@@ -124,8 +125,8 @@
 
 static int pnp_device_remove(struct device *dev)
 {
-	struct pnp_dev * pnp_dev = to_pnp_dev(dev);
-	struct pnp_driver * drv = pnp_dev->driver;
+	struct pnp_dev *pnp_dev = to_pnp_dev(dev);
+	struct pnp_driver *drv = pnp_dev->driver;
 
 	if (drv) {
 		if (drv->remove)
@@ -138,8 +139,9 @@
 
 static int pnp_bus_match(struct device *dev, struct device_driver *drv)
 {
-	struct pnp_dev * pnp_dev = to_pnp_dev(dev);
-	struct pnp_driver * pnp_drv = to_pnp_driver(drv);
+	struct pnp_dev *pnp_dev = to_pnp_dev(dev);
+	struct pnp_driver *pnp_drv = to_pnp_driver(drv);
+
 	if (match_device(pnp_drv, pnp_dev) == NULL)
 		return 0;
 	return 1;
@@ -147,8 +149,8 @@
 
 static int pnp_bus_suspend(struct device *dev, pm_message_t state)
 {
-	struct pnp_dev * pnp_dev = to_pnp_dev(dev);
-	struct pnp_driver * pnp_drv = pnp_dev->driver;
+	struct pnp_dev *pnp_dev = to_pnp_dev(dev);
+	struct pnp_driver *pnp_drv = pnp_dev->driver;
 	int error;
 
 	if (!pnp_drv)
@@ -162,23 +164,28 @@
 
 	if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE) &&
 	    pnp_can_disable(pnp_dev)) {
-	    	error = pnp_stop_dev(pnp_dev);
-	    	if (error)
-	    		return error;
+		error = pnp_stop_dev(pnp_dev);
+		if (error)
+			return error;
 	}
 
+	if (pnp_dev->protocol && pnp_dev->protocol->suspend)
+		pnp_dev->protocol->suspend(pnp_dev, state);
 	return 0;
 }
 
 static int pnp_bus_resume(struct device *dev)
 {
-	struct pnp_dev * pnp_dev = to_pnp_dev(dev);
-	struct pnp_driver * pnp_drv = pnp_dev->driver;
+	struct pnp_dev *pnp_dev = to_pnp_dev(dev);
+	struct pnp_driver *pnp_drv = pnp_dev->driver;
 	int error;
 
 	if (!pnp_drv)
 		return 0;
 
+	if (pnp_dev->protocol && pnp_dev->protocol->resume)
+		pnp_dev->protocol->resume(pnp_dev);
+
 	if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) {
 		error = pnp_start_dev(pnp_dev);
 		if (error)
@@ -192,12 +199,12 @@
 }
 
 struct bus_type pnp_bus_type = {
-	.name	= "pnp",
-	.match	= pnp_bus_match,
-	.probe	= pnp_device_probe,
-	.remove	= pnp_device_remove,
+	.name    = "pnp",
+	.match   = pnp_bus_match,
+	.probe   = pnp_device_probe,
+	.remove  = pnp_device_remove,
 	.suspend = pnp_bus_suspend,
-	.resume = pnp_bus_resume,
+	.resume  = pnp_bus_resume,
 };
 
 int pnp_register_driver(struct pnp_driver *drv)
@@ -220,16 +227,11 @@
  * pnp_add_id - adds an EISA id to the specified device
  * @id: pointer to a pnp_id structure
  * @dev: pointer to the desired device
- *
  */
-
 int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev)
 {
 	struct pnp_id *ptr;
-	if (!id)
-		return -EINVAL;
-	if (!dev)
-		return -EINVAL;
+
 	id->next = NULL;
 	ptr = dev->id;
 	while (ptr && ptr->next)
@@ -243,8 +245,5 @@
 
 EXPORT_SYMBOL(pnp_register_driver);
 EXPORT_SYMBOL(pnp_unregister_driver);
-#if 0
-EXPORT_SYMBOL(pnp_add_id);
-#endif
 EXPORT_SYMBOL(pnp_device_attach);
 EXPORT_SYMBOL(pnp_device_detach);
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
index ac9fcd4..a0cfb75 100644
--- a/drivers/pnp/interface.c
+++ b/drivers/pnp/interface.c
@@ -3,7 +3,6 @@
  *
  * Some code, especially possible resource dumping is based on isapnp_proc.c (c) Jaroslav Kysela <perex@suse.cz>
  * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
- *
  */
 
 #include <linux/pnp.h>
@@ -29,7 +28,7 @@
 
 typedef struct pnp_info_buffer pnp_info_buffer_t;
 
-static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt,...)
+static int pnp_printf(pnp_info_buffer_t * buffer, char *fmt, ...)
 {
 	va_list args;
 	int res;
@@ -48,14 +47,18 @@
 	return res;
 }
 
-static void pnp_print_port(pnp_info_buffer_t *buffer, char *space, struct pnp_port *port)
+static void pnp_print_port(pnp_info_buffer_t * buffer, char *space,
+			   struct pnp_port *port)
 {
-	pnp_printf(buffer, "%sport 0x%x-0x%x, align 0x%x, size 0x%x, %i-bit address decoding\n",
-			space, port->min, port->max, port->align ? (port->align-1) : 0, port->size,
-			port->flags & PNP_PORT_FLAG_16BITADDR ? 16 : 10);
+	pnp_printf(buffer,
+		   "%sport 0x%x-0x%x, align 0x%x, size 0x%x, %i-bit address decoding\n",
+		   space, port->min, port->max,
+		   port->align ? (port->align - 1) : 0, port->size,
+		   port->flags & PNP_PORT_FLAG_16BITADDR ? 16 : 10);
 }
 
-static void pnp_print_irq(pnp_info_buffer_t *buffer, char *space, struct pnp_irq *irq)
+static void pnp_print_irq(pnp_info_buffer_t * buffer, char *space,
+			  struct pnp_irq *irq)
 {
 	int first = 1, i;
 
@@ -85,14 +88,15 @@
 	pnp_printf(buffer, "\n");
 }
 
-static void pnp_print_dma(pnp_info_buffer_t *buffer, char *space, struct pnp_dma *dma)
+static void pnp_print_dma(pnp_info_buffer_t * buffer, char *space,
+			  struct pnp_dma *dma)
 {
 	int first = 1, i;
 	char *s;
 
 	pnp_printf(buffer, "%sdma ", space);
 	for (i = 0; i < 8; i++)
-		if (dma->map & (1<<i)) {
+		if (dma->map & (1 << i)) {
 			if (!first) {
 				pnp_printf(buffer, ",");
 			} else {
@@ -136,12 +140,13 @@
 	pnp_printf(buffer, " %s\n", s);
 }
 
-static void pnp_print_mem(pnp_info_buffer_t *buffer, char *space, struct pnp_mem *mem)
+static void pnp_print_mem(pnp_info_buffer_t * buffer, char *space,
+			  struct pnp_mem *mem)
 {
 	char *s;
 
 	pnp_printf(buffer, "%sMemory 0x%x-0x%x, align 0x%x, size 0x%x",
-			space, mem->min, mem->max, mem->align, mem->size);
+		   space, mem->min, mem->max, mem->align, mem->size);
 	if (mem->flags & IORESOURCE_MEM_WRITEABLE)
 		pnp_printf(buffer, ", writeable");
 	if (mem->flags & IORESOURCE_MEM_CACHEABLE)
@@ -168,7 +173,7 @@
 	pnp_printf(buffer, ", %s\n", s);
 }
 
-static void pnp_print_option(pnp_info_buffer_t *buffer, char *space,
+static void pnp_print_option(pnp_info_buffer_t * buffer, char *space,
 			     struct pnp_option *option, int dep)
 {
 	char *s;
@@ -179,19 +184,19 @@
 
 	if (dep) {
 		switch (option->priority) {
-			case PNP_RES_PRIORITY_PREFERRED:
+		case PNP_RES_PRIORITY_PREFERRED:
 			s = "preferred";
 			break;
-			case PNP_RES_PRIORITY_ACCEPTABLE:
+		case PNP_RES_PRIORITY_ACCEPTABLE:
 			s = "acceptable";
 			break;
-			case PNP_RES_PRIORITY_FUNCTIONAL:
+		case PNP_RES_PRIORITY_FUNCTIONAL:
 			s = "functional";
 			break;
-			default:
+		default:
 			s = "invalid";
 		}
-		pnp_printf(buffer, "Dependent: %02i - Priority %s\n",dep, s);
+		pnp_printf(buffer, "Dependent: %02i - Priority %s\n", dep, s);
 	}
 
 	for (port = option->port; port; port = port->next)
@@ -204,16 +209,16 @@
 		pnp_print_mem(buffer, space, mem);
 }
 
-
-static ssize_t pnp_show_options(struct device *dmdev, struct device_attribute *attr, char *buf)
+static ssize_t pnp_show_options(struct device *dmdev,
+				struct device_attribute *attr, char *buf)
 {
 	struct pnp_dev *dev = to_pnp_dev(dmdev);
-	struct pnp_option * independent = dev->independent;
-	struct pnp_option * dependent = dev->dependent;
+	struct pnp_option *independent = dev->independent;
+	struct pnp_option *dependent = dev->dependent;
 	int ret, dep = 1;
 
 	pnp_info_buffer_t *buffer = (pnp_info_buffer_t *)
-				 pnp_alloc(sizeof(pnp_info_buffer_t));
+	    pnp_alloc(sizeof(pnp_info_buffer_t));
 	if (!buffer)
 		return -ENOMEM;
 
@@ -223,7 +228,7 @@
 	if (independent)
 		pnp_print_option(buffer, "", independent, 0);
 
-	while (dependent){
+	while (dependent) {
 		pnp_print_option(buffer, "   ", dependent, dep);
 		dependent = dependent->next;
 		dep++;
@@ -233,10 +238,11 @@
 	return ret;
 }
 
-static DEVICE_ATTR(options,S_IRUGO,pnp_show_options,NULL);
+static DEVICE_ATTR(options, S_IRUGO, pnp_show_options, NULL);
 
-
-static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_attribute *attr, char *buf)
+static ssize_t pnp_show_current_resources(struct device *dmdev,
+					  struct device_attribute *attr,
+					  char *buf)
 {
 	struct pnp_dev *dev = to_pnp_dev(dmdev);
 	int i, ret;
@@ -252,52 +258,56 @@
 	buffer->buffer = buf;
 	buffer->curr = buffer->buffer;
 
-	pnp_printf(buffer,"state = ");
+	pnp_printf(buffer, "state = ");
 	if (dev->active)
-		pnp_printf(buffer,"active\n");
+		pnp_printf(buffer, "active\n");
 	else
-		pnp_printf(buffer,"disabled\n");
+		pnp_printf(buffer, "disabled\n");
 
 	for (i = 0; i < PNP_MAX_PORT; i++) {
 		if (pnp_port_valid(dev, i)) {
-			pnp_printf(buffer,"io");
+			pnp_printf(buffer, "io");
 			if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED)
-				pnp_printf(buffer," disabled\n");
+				pnp_printf(buffer, " disabled\n");
 			else
-				pnp_printf(buffer," 0x%llx-0x%llx\n",
-					(unsigned long long)pnp_port_start(dev, i),
-					(unsigned long long)pnp_port_end(dev, i));
+				pnp_printf(buffer, " 0x%llx-0x%llx\n",
+					   (unsigned long long)
+					   pnp_port_start(dev, i),
+					   (unsigned long long)pnp_port_end(dev,
+									    i));
 		}
 	}
 	for (i = 0; i < PNP_MAX_MEM; i++) {
 		if (pnp_mem_valid(dev, i)) {
-			pnp_printf(buffer,"mem");
+			pnp_printf(buffer, "mem");
 			if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED)
-				pnp_printf(buffer," disabled\n");
+				pnp_printf(buffer, " disabled\n");
 			else
-				pnp_printf(buffer," 0x%llx-0x%llx\n",
-					(unsigned long long)pnp_mem_start(dev, i),
-					(unsigned long long)pnp_mem_end(dev, i));
+				pnp_printf(buffer, " 0x%llx-0x%llx\n",
+					   (unsigned long long)
+					   pnp_mem_start(dev, i),
+					   (unsigned long long)pnp_mem_end(dev,
+									   i));
 		}
 	}
 	for (i = 0; i < PNP_MAX_IRQ; i++) {
 		if (pnp_irq_valid(dev, i)) {
-			pnp_printf(buffer,"irq");
+			pnp_printf(buffer, "irq");
 			if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED)
-				pnp_printf(buffer," disabled\n");
+				pnp_printf(buffer, " disabled\n");
 			else
-				pnp_printf(buffer," %lld\n",
-					(unsigned long long)pnp_irq(dev, i));
+				pnp_printf(buffer, " %lld\n",
+					   (unsigned long long)pnp_irq(dev, i));
 		}
 	}
 	for (i = 0; i < PNP_MAX_DMA; i++) {
 		if (pnp_dma_valid(dev, i)) {
-			pnp_printf(buffer,"dma");
+			pnp_printf(buffer, "dma");
 			if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED)
-				pnp_printf(buffer," disabled\n");
+				pnp_printf(buffer, " disabled\n");
 			else
-				pnp_printf(buffer," %lld\n",
-					(unsigned long long)pnp_dma(dev, i));
+				pnp_printf(buffer, " %lld\n",
+					   (unsigned long long)pnp_dma(dev, i));
 		}
 	}
 	ret = (buffer->curr - buf);
@@ -308,55 +318,57 @@
 extern struct semaphore pnp_res_mutex;
 
 static ssize_t
-pnp_set_current_resources(struct device * dmdev, struct device_attribute *attr, const char * ubuf, size_t count)
+pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr,
+			  const char *ubuf, size_t count)
 {
 	struct pnp_dev *dev = to_pnp_dev(dmdev);
-	char	*buf = (void *)ubuf;
-	int	retval = 0;
+	char *buf = (void *)ubuf;
+	int retval = 0;
 
 	if (dev->status & PNP_ATTACHED) {
 		retval = -EBUSY;
-		pnp_info("Device %s cannot be configured because it is in use.", dev->dev.bus_id);
+		pnp_info("Device %s cannot be configured because it is in use.",
+			 dev->dev.bus_id);
 		goto done;
 	}
 
 	while (isspace(*buf))
 		++buf;
-	if (!strnicmp(buf,"disable",7)) {
+	if (!strnicmp(buf, "disable", 7)) {
 		retval = pnp_disable_dev(dev);
 		goto done;
 	}
-	if (!strnicmp(buf,"activate",8)) {
+	if (!strnicmp(buf, "activate", 8)) {
 		retval = pnp_activate_dev(dev);
 		goto done;
 	}
-	if (!strnicmp(buf,"fill",4)) {
+	if (!strnicmp(buf, "fill", 4)) {
 		if (dev->active)
 			goto done;
 		retval = pnp_auto_config_dev(dev);
 		goto done;
 	}
-	if (!strnicmp(buf,"auto",4)) {
+	if (!strnicmp(buf, "auto", 4)) {
 		if (dev->active)
 			goto done;
 		pnp_init_resource_table(&dev->res);
 		retval = pnp_auto_config_dev(dev);
 		goto done;
 	}
-	if (!strnicmp(buf,"clear",5)) {
+	if (!strnicmp(buf, "clear", 5)) {
 		if (dev->active)
 			goto done;
 		pnp_init_resource_table(&dev->res);
 		goto done;
 	}
-	if (!strnicmp(buf,"get",3)) {
+	if (!strnicmp(buf, "get", 3)) {
 		down(&pnp_res_mutex);
 		if (pnp_can_read(dev))
 			dev->protocol->get(dev, &dev->res);
 		up(&pnp_res_mutex);
 		goto done;
 	}
-	if (!strnicmp(buf,"set",3)) {
+	if (!strnicmp(buf, "set", 3)) {
 		int nport = 0, nmem = 0, nirq = 0, ndma = 0;
 		if (dev->active)
 			goto done;
@@ -366,65 +378,77 @@
 		while (1) {
 			while (isspace(*buf))
 				++buf;
-			if (!strnicmp(buf,"io",2)) {
+			if (!strnicmp(buf, "io", 2)) {
 				buf += 2;
 				while (isspace(*buf))
 					++buf;
-				dev->res.port_resource[nport].start = simple_strtoul(buf,&buf,0);
+				dev->res.port_resource[nport].start =
+				    simple_strtoul(buf, &buf, 0);
 				while (isspace(*buf))
 					++buf;
-				if(*buf == '-') {
+				if (*buf == '-') {
 					buf += 1;
 					while (isspace(*buf))
 						++buf;
-					dev->res.port_resource[nport].end = simple_strtoul(buf,&buf,0);
+					dev->res.port_resource[nport].end =
+					    simple_strtoul(buf, &buf, 0);
 				} else
-					dev->res.port_resource[nport].end = dev->res.port_resource[nport].start;
-				dev->res.port_resource[nport].flags = IORESOURCE_IO;
+					dev->res.port_resource[nport].end =
+					    dev->res.port_resource[nport].start;
+				dev->res.port_resource[nport].flags =
+				    IORESOURCE_IO;
 				nport++;
 				if (nport >= PNP_MAX_PORT)
 					break;
 				continue;
 			}
-			if (!strnicmp(buf,"mem",3)) {
+			if (!strnicmp(buf, "mem", 3)) {
 				buf += 3;
 				while (isspace(*buf))
 					++buf;
-				dev->res.mem_resource[nmem].start = simple_strtoul(buf,&buf,0);
+				dev->res.mem_resource[nmem].start =
+				    simple_strtoul(buf, &buf, 0);
 				while (isspace(*buf))
 					++buf;
-				if(*buf == '-') {
+				if (*buf == '-') {
 					buf += 1;
 					while (isspace(*buf))
 						++buf;
-					dev->res.mem_resource[nmem].end = simple_strtoul(buf,&buf,0);
+					dev->res.mem_resource[nmem].end =
+					    simple_strtoul(buf, &buf, 0);
 				} else
-					dev->res.mem_resource[nmem].end = dev->res.mem_resource[nmem].start;
-				dev->res.mem_resource[nmem].flags = IORESOURCE_MEM;
+					dev->res.mem_resource[nmem].end =
+					    dev->res.mem_resource[nmem].start;
+				dev->res.mem_resource[nmem].flags =
+				    IORESOURCE_MEM;
 				nmem++;
 				if (nmem >= PNP_MAX_MEM)
 					break;
 				continue;
 			}
-			if (!strnicmp(buf,"irq",3)) {
+			if (!strnicmp(buf, "irq", 3)) {
 				buf += 3;
 				while (isspace(*buf))
 					++buf;
 				dev->res.irq_resource[nirq].start =
-				dev->res.irq_resource[nirq].end = simple_strtoul(buf,&buf,0);
-				dev->res.irq_resource[nirq].flags = IORESOURCE_IRQ;
+				    dev->res.irq_resource[nirq].end =
+				    simple_strtoul(buf, &buf, 0);
+				dev->res.irq_resource[nirq].flags =
+				    IORESOURCE_IRQ;
 				nirq++;
 				if (nirq >= PNP_MAX_IRQ)
 					break;
 				continue;
 			}
-			if (!strnicmp(buf,"dma",3)) {
+			if (!strnicmp(buf, "dma", 3)) {
 				buf += 3;
 				while (isspace(*buf))
 					++buf;
 				dev->res.dma_resource[ndma].start =
-				dev->res.dma_resource[ndma].end = simple_strtoul(buf,&buf,0);
-				dev->res.dma_resource[ndma].flags = IORESOURCE_DMA;
+				    dev->res.dma_resource[ndma].end =
+				    simple_strtoul(buf, &buf, 0);
+				dev->res.dma_resource[ndma].flags =
+				    IORESOURCE_DMA;
 				ndma++;
 				if (ndma >= PNP_MAX_DMA)
 					break;
@@ -435,45 +459,51 @@
 		up(&pnp_res_mutex);
 		goto done;
 	}
- done:
+
+done:
 	if (retval < 0)
 		return retval;
 	return count;
 }
 
-static DEVICE_ATTR(resources,S_IRUGO | S_IWUSR,
-		   pnp_show_current_resources,pnp_set_current_resources);
+static DEVICE_ATTR(resources, S_IRUGO | S_IWUSR,
+		   pnp_show_current_resources, pnp_set_current_resources);
 
-static ssize_t pnp_show_current_ids(struct device *dmdev, struct device_attribute *attr, char *buf)
+static ssize_t pnp_show_current_ids(struct device *dmdev,
+				    struct device_attribute *attr, char *buf)
 {
 	char *str = buf;
 	struct pnp_dev *dev = to_pnp_dev(dmdev);
-	struct pnp_id * pos = dev->id;
+	struct pnp_id *pos = dev->id;
 
 	while (pos) {
-		str += sprintf(str,"%s\n", pos->id);
+		str += sprintf(str, "%s\n", pos->id);
 		pos = pos->next;
 	}
 	return (str - buf);
 }
 
-static DEVICE_ATTR(id,S_IRUGO,pnp_show_current_ids,NULL);
+static DEVICE_ATTR(id, S_IRUGO, pnp_show_current_ids, NULL);
 
 int pnp_interface_attach_device(struct pnp_dev *dev)
 {
-	int rc = device_create_file(&dev->dev,&dev_attr_options);
-	if (rc) goto err;
-	rc = device_create_file(&dev->dev,&dev_attr_resources);
-	if (rc) goto err_opt;
-	rc = device_create_file(&dev->dev,&dev_attr_id);
-	if (rc) goto err_res;
+	int rc = device_create_file(&dev->dev, &dev_attr_options);
+
+	if (rc)
+		goto err;
+	rc = device_create_file(&dev->dev, &dev_attr_resources);
+	if (rc)
+		goto err_opt;
+	rc = device_create_file(&dev->dev, &dev_attr_id);
+	if (rc)
+		goto err_res;
 
 	return 0;
 
 err_res:
-	device_remove_file(&dev->dev,&dev_attr_resources);
+	device_remove_file(&dev->dev, &dev_attr_resources);
 err_opt:
-	device_remove_file(&dev->dev,&dev_attr_options);
+	device_remove_file(&dev->dev, &dev_attr_options);
 err:
 	return rc;
 }
diff --git a/drivers/pnp/isapnp/compat.c b/drivers/pnp/isapnp/compat.c
index 0697ab8..10bdcc4 100644
--- a/drivers/pnp/isapnp/compat.c
+++ b/drivers/pnp/isapnp/compat.c
@@ -3,34 +3,30 @@
  *            the old isapnp APIs. If possible use the new APIs instead.
  *
  * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
- *
  */
- 
-/* TODO: see if more isapnp functions are needed here */
 
 #include <linux/module.h>
 #include <linux/isapnp.h>
 #include <linux/string.h>
 
-static void pnp_convert_id(char *buf, unsigned short vendor, unsigned short device)
+static void pnp_convert_id(char *buf, unsigned short vendor,
+			   unsigned short device)
 {
 	sprintf(buf, "%c%c%c%x%x%x%x",
-			'A' + ((vendor >> 2) & 0x3f) - 1,
-			'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
-			'A' + ((vendor >> 8) & 0x1f) - 1,
-			(device >> 4) & 0x0f,
-			device & 0x0f,
-			(device >> 12) & 0x0f,
-			(device >> 8) & 0x0f);
+		'A' + ((vendor >> 2) & 0x3f) - 1,
+		'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
+		'A' + ((vendor >> 8) & 0x1f) - 1,
+		(device >> 4) & 0x0f, device & 0x0f,
+		(device >> 12) & 0x0f, (device >> 8) & 0x0f);
 }
 
-struct pnp_card *pnp_find_card(unsigned short vendor,
-			       unsigned short device,
+struct pnp_card *pnp_find_card(unsigned short vendor, unsigned short device,
 			       struct pnp_card *from)
 {
 	char id[8];
 	char any[8];
 	struct list_head *list;
+
 	pnp_convert_id(id, vendor, device);
 	pnp_convert_id(any, ISAPNP_ANY_ID, ISAPNP_ANY_ID);
 
@@ -38,20 +34,20 @@
 
 	while (list != &pnp_cards) {
 		struct pnp_card *card = global_to_pnp_card(list);
-		if (compare_pnp_id(card->id,id) || (memcmp(id,any,7)==0))
+
+		if (compare_pnp_id(card->id, id) || (memcmp(id, any, 7) == 0))
 			return card;
 		list = list->next;
 	}
 	return NULL;
 }
 
-struct pnp_dev *pnp_find_dev(struct pnp_card *card,
-			     unsigned short vendor,
-			     unsigned short function,
-			     struct pnp_dev *from)
+struct pnp_dev *pnp_find_dev(struct pnp_card *card, unsigned short vendor,
+			     unsigned short function, struct pnp_dev *from)
 {
 	char id[8];
 	char any[8];
+
 	pnp_convert_id(id, vendor, function);
 	pnp_convert_id(any, ISAPNP_ANY_ID, ISAPNP_ANY_ID);
 	if (card == NULL) {	/* look for a logical device from all cards */
@@ -63,7 +59,9 @@
 
 		while (list != &pnp_global) {
 			struct pnp_dev *dev = global_to_pnp_dev(list);
-			if (compare_pnp_id(dev->id,id) || (memcmp(id,any,7)==0))
+
+			if (compare_pnp_id(dev->id, id) ||
+			    (memcmp(id, any, 7) == 0))
 				return dev;
 			list = list->next;
 		}
@@ -78,7 +76,8 @@
 		}
 		while (list != &card->devices) {
 			struct pnp_dev *dev = card_to_pnp_dev(list);
-			if (compare_pnp_id(dev->id,id))
+
+			if (compare_pnp_id(dev->id, id))
 				return dev;
 			list = list->next;
 		}
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index 914d00c..b035d60 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -47,14 +47,11 @@
 #if 0
 #define ISAPNP_REGION_OK
 #endif
-#if 0
-#define ISAPNP_DEBUG
-#endif
 
-int isapnp_disable;			/* Disable ISA PnP */
-static int isapnp_rdp;			/* Read Data Port */
-static int isapnp_reset = 1;		/* reset all PnP cards (deactivate) */
-static int isapnp_verbose = 1;		/* verbose mode */
+int isapnp_disable;		/* Disable ISA PnP */
+static int isapnp_rdp;		/* Read Data Port */
+static int isapnp_reset = 1;	/* reset all PnP cards (deactivate) */
+static int isapnp_verbose = 1;	/* verbose mode */
 
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
 MODULE_DESCRIPTION("Generic ISA Plug & Play support");
@@ -93,7 +90,6 @@
 
 static unsigned char isapnp_checksum_value;
 static DEFINE_MUTEX(isapnp_cfg_mutex);
-static int isapnp_detected;
 static int isapnp_csn_count;
 
 /* some prototypes */
@@ -126,7 +122,7 @@
 	unsigned short val;
 
 	val = isapnp_read_byte(idx);
-	val = (val << 8) + isapnp_read_byte(idx+1);
+	val = (val << 8) + isapnp_read_byte(idx + 1);
 	return val;
 }
 
@@ -139,7 +135,7 @@
 static void isapnp_write_word(unsigned char idx, unsigned short val)
 {
 	isapnp_write_byte(idx, val >> 8);
-	isapnp_write_byte(idx+1, val);
+	isapnp_write_byte(idx + 1, val);
 }
 
 static void isapnp_key(void)
@@ -193,7 +189,7 @@
 static void __init isapnp_peek(unsigned char *data, int bytes)
 {
 	int i, j;
-	unsigned char d=0;
+	unsigned char d = 0;
 
 	for (i = 1; i <= bytes; i++) {
 		for (j = 0; j < 20; j++) {
@@ -220,19 +216,18 @@
 {
 	int rdp = isapnp_rdp;
 	static int old_rdp = 0;
-	
-	if(old_rdp)
-	{
+
+	if (old_rdp) {
 		release_region(old_rdp, 1);
 		old_rdp = 0;
 	}
 	while (rdp <= 0x3ff) {
 		/*
-		 *	We cannot use NE2000 probe spaces for ISAPnP or we
-		 *	will lock up machines.
+		 *      We cannot use NE2000 probe spaces for ISAPnP or we
+		 *      will lock up machines.
 		 */
-		if ((rdp < 0x280 || rdp >  0x380) && request_region(rdp, 1, "ISAPnP"))
-		{
+		if ((rdp < 0x280 || rdp > 0x380)
+		    && request_region(rdp, 1, "ISAPnP")) {
 			isapnp_rdp = rdp;
 			old_rdp = rdp;
 			return 0;
@@ -253,7 +248,6 @@
  *	Perform an isolation. The port selection code now tries to avoid
  *	"dangerous to read" ports.
  */
-
 static int __init isapnp_isolate_rdp_select(void)
 {
 	isapnp_wait();
@@ -282,7 +276,6 @@
 /*
  *  Isolate (assign uniqued CSN) to all ISA PnP devices.
  */
-
 static int __init isapnp_isolate(void)
 {
 	unsigned char checksum = 0x6a;
@@ -305,7 +298,9 @@
 			udelay(250);
 			if (data == 0x55aa)
 				bit = 0x01;
-			checksum = ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7) | (checksum >> 1);
+			checksum =
+			    ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7)
+			    | (checksum >> 1);
 			bit = 0x00;
 		}
 		for (i = 65; i <= 72; i++) {
@@ -336,7 +331,7 @@
 		} else if (iteration > 1) {
 			break;
 		}
-	      __next:
+__next:
 		if (csn == 255)
 			break;
 		checksum = 0x6a;
@@ -351,13 +346,12 @@
 /*
  *  Read one tag from stream.
  */
-
 static int __init isapnp_read_tag(unsigned char *type, unsigned short *size)
 {
 	unsigned char tag, tmp[2];
 
 	isapnp_peek(&tag, 1);
-	if (tag == 0)				/* invalid tag */
+	if (tag == 0)		/* invalid tag */
 		return -1;
 	if (tag & 0x80) {	/* large item */
 		*type = tag;
@@ -368,7 +362,8 @@
 		*size = tag & 0x07;
 	}
 #if 0
-	printk(KERN_DEBUG "tag = 0x%x, type = 0x%x, size = %i\n", tag, *type, *size);
+	printk(KERN_DEBUG "tag = 0x%x, type = 0x%x, size = %i\n", tag, *type,
+	       *size);
 #endif
 	if (*type == 0xff && *size == 0xffff)	/* probably invalid data */
 		return -1;
@@ -378,7 +373,6 @@
 /*
  *  Skip specified number of bytes from stream.
  */
-
 static void __init isapnp_skip_bytes(int count)
 {
 	isapnp_peek(NULL, count);
@@ -387,31 +381,30 @@
 /*
  *  Parse EISA id.
  */
-
-static void isapnp_parse_id(struct pnp_dev * dev, unsigned short vendor, unsigned short device)
+static void isapnp_parse_id(struct pnp_dev *dev, unsigned short vendor,
+			    unsigned short device)
 {
-	struct pnp_id * id;
+	struct pnp_id *id;
+
 	if (!dev)
 		return;
 	id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
 	if (!id)
 		return;
 	sprintf(id->id, "%c%c%c%x%x%x%x",
-			'A' + ((vendor >> 2) & 0x3f) - 1,
-			'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
-			'A' + ((vendor >> 8) & 0x1f) - 1,
-			(device >> 4) & 0x0f,
-			device & 0x0f,
-			(device >> 12) & 0x0f,
-			(device >> 8) & 0x0f);
+		'A' + ((vendor >> 2) & 0x3f) - 1,
+		'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
+		'A' + ((vendor >> 8) & 0x1f) - 1,
+		(device >> 4) & 0x0f,
+		device & 0x0f, (device >> 12) & 0x0f, (device >> 8) & 0x0f);
 	pnp_add_id(id, dev);
 }
 
 /*
  *  Parse logical device tag.
  */
-
-static struct pnp_dev * __init isapnp_parse_device(struct pnp_card *card, int size, int number)
+static struct pnp_dev *__init isapnp_parse_device(struct pnp_card *card,
+						  int size, int number)
 {
 	unsigned char tmp[6];
 	struct pnp_dev *dev;
@@ -435,13 +428,11 @@
 	return dev;
 }
 
-
 /*
  *  Add IRQ resource to resources list.
  */
-
 static void __init isapnp_parse_irq_resource(struct pnp_option *option,
-					       int size)
+					     int size)
 {
 	unsigned char tmp[3];
 	struct pnp_irq *irq;
@@ -458,15 +449,13 @@
 	else
 		irq->flags = IORESOURCE_IRQ_HIGHEDGE;
 	pnp_register_irq_resource(option, irq);
-	return;
 }
 
 /*
  *  Add DMA resource to resources list.
  */
-
 static void __init isapnp_parse_dma_resource(struct pnp_option *option,
-                                    	       int size)
+					     int size)
 {
 	unsigned char tmp[2];
 	struct pnp_dma *dma;
@@ -478,15 +467,13 @@
 	dma->map = tmp[0];
 	dma->flags = tmp[1];
 	pnp_register_dma_resource(option, dma);
-	return;
 }
 
 /*
  *  Add port resource to resources list.
  */
-
 static void __init isapnp_parse_port_resource(struct pnp_option *option,
-						int size)
+					      int size)
 {
 	unsigned char tmp[7];
 	struct pnp_port *port;
@@ -500,16 +487,14 @@
 	port->align = tmp[5];
 	port->size = tmp[6];
 	port->flags = tmp[0] ? PNP_PORT_FLAG_16BITADDR : 0;
-	pnp_register_port_resource(option,port);
-	return;
+	pnp_register_port_resource(option, port);
 }
 
 /*
  *  Add fixed port resource to resources list.
  */
-
 static void __init isapnp_parse_fixed_port_resource(struct pnp_option *option,
-						      int size)
+						    int size)
 {
 	unsigned char tmp[3];
 	struct pnp_port *port;
@@ -522,16 +507,14 @@
 	port->size = tmp[2];
 	port->align = 0;
 	port->flags = PNP_PORT_FLAG_FIXED;
-	pnp_register_port_resource(option,port);
-	return;
+	pnp_register_port_resource(option, port);
 }
 
 /*
  *  Add memory resource to resources list.
  */
-
 static void __init isapnp_parse_mem_resource(struct pnp_option *option,
-					       int size)
+					     int size)
 {
 	unsigned char tmp[9];
 	struct pnp_mem *mem;
@@ -545,16 +528,14 @@
 	mem->align = (tmp[6] << 8) | tmp[5];
 	mem->size = ((tmp[8] << 8) | tmp[7]) << 8;
 	mem->flags = tmp[0];
-	pnp_register_mem_resource(option,mem);
-	return;
+	pnp_register_mem_resource(option, mem);
 }
 
 /*
  *  Add 32-bit memory resource to resources list.
  */
-
 static void __init isapnp_parse_mem32_resource(struct pnp_option *option,
-						 int size)
+					       int size)
 {
 	unsigned char tmp[17];
 	struct pnp_mem *mem;
@@ -565,18 +546,19 @@
 		return;
 	mem->min = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
 	mem->max = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
-	mem->align = (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9];
-	mem->size = (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13];
+	mem->align =
+	    (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9];
+	mem->size =
+	    (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13];
 	mem->flags = tmp[0];
-	pnp_register_mem_resource(option,mem);
+	pnp_register_mem_resource(option, mem);
 }
 
 /*
  *  Add 32-bit fixed memory resource to resources list.
  */
-
 static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option,
-						       int size)
+						     int size)
 {
 	unsigned char tmp[9];
 	struct pnp_mem *mem;
@@ -585,28 +567,29 @@
 	mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
 	if (!mem)
 		return;
-	mem->min = mem->max = (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
+	mem->min = mem->max =
+	    (tmp[4] << 24) | (tmp[3] << 16) | (tmp[2] << 8) | tmp[1];
 	mem->size = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
 	mem->align = 0;
 	mem->flags = tmp[0];
-	pnp_register_mem_resource(option,mem);
+	pnp_register_mem_resource(option, mem);
 }
 
 /*
  *  Parse card name for ISA PnP device.
- */ 
-
+ */
 static void __init
 isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size)
 {
 	if (name[0] == '\0') {
-		unsigned short size1 = *size >= name_max ? (name_max - 1) : *size;
+		unsigned short size1 =
+		    *size >= name_max ? (name_max - 1) : *size;
 		isapnp_peek(name, size1);
 		name[size1] = '\0';
 		*size -= size1;
 
 		/* clean whitespace from end of string */
-		while (size1 > 0  &&  name[--size1] == ' ')
+		while (size1 > 0 && name[--size1] == ' ')
 			name[size1] = '\0';
 	}
 }
@@ -614,7 +597,6 @@
 /*
  *  Parse resource map for logical device.
  */
-
 static int __init isapnp_create_device(struct pnp_card *card,
 				       unsigned short size)
 {
@@ -622,6 +604,7 @@
 	unsigned char type, tmp[17];
 	struct pnp_option *option;
 	struct pnp_dev *dev;
+
 	if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
 		return 1;
 	option = pnp_register_independent_option(dev);
@@ -629,17 +612,19 @@
 		kfree(dev);
 		return 1;
 	}
-	pnp_add_card_device(card,dev);
+	pnp_add_card_device(card, dev);
 
 	while (1) {
-		if (isapnp_read_tag(&type, &size)<0)
+		if (isapnp_read_tag(&type, &size) < 0)
 			return 1;
 		if (skip && type != _STAG_LOGDEVID && type != _STAG_END)
 			goto __skip;
 		switch (type) {
 		case _STAG_LOGDEVID:
 			if (size >= 5 && size <= 6) {
-				if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
+				if ((dev =
+				     isapnp_parse_device(card, size,
+							 number++)) == NULL)
 					return 1;
 				size = 0;
 				skip = 0;
@@ -648,7 +633,7 @@
 					kfree(dev);
 					return 1;
 				}
-				pnp_add_card_device(card,dev);
+				pnp_add_card_device(card, dev);
 			} else {
 				skip = 1;
 			}
@@ -658,7 +643,8 @@
 		case _STAG_COMPATDEVID:
 			if (size == 4 && compat < DEVICE_COUNT_COMPATIBLE) {
 				isapnp_peek(tmp, 4);
-				isapnp_parse_id(dev,(tmp[1] << 8) | tmp[0], (tmp[3] << 8) | tmp[2]);
+				isapnp_parse_id(dev, (tmp[1] << 8) | tmp[0],
+						(tmp[3] << 8) | tmp[2]);
 				compat++;
 				size = 0;
 			}
@@ -684,7 +670,7 @@
 				priority = 0x100 | tmp[0];
 				size = 0;
 			}
-			option = pnp_register_dependent_option(dev,priority);
+			option = pnp_register_dependent_option(dev, priority);
 			if (!option)
 				return 1;
 			break;
@@ -739,11 +725,13 @@
 				isapnp_skip_bytes(size);
 			return 1;
 		default:
-			printk(KERN_ERR "isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n", type, dev->number, card->number);
+			printk(KERN_ERR
+			       "isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n",
+			       type, dev->number, card->number);
 		}
-	      __skip:
-	      	if (size > 0)
-		      	isapnp_skip_bytes(size);
+__skip:
+		if (size > 0)
+			isapnp_skip_bytes(size);
 	}
 	return 0;
 }
@@ -751,14 +739,13 @@
 /*
  *  Parse resource map for ISA PnP card.
  */
-
 static void __init isapnp_parse_resource_map(struct pnp_card *card)
 {
 	unsigned char type, tmp[17];
 	unsigned short size;
 
 	while (1) {
-		if (isapnp_read_tag(&type, &size)<0)
+		if (isapnp_read_tag(&type, &size) < 0)
 			return;
 		switch (type) {
 		case _STAG_PNPVERNO:
@@ -771,7 +758,7 @@
 			break;
 		case _STAG_LOGDEVID:
 			if (size >= 5 && size <= 6) {
-				if (isapnp_create_device(card, size)==1)
+				if (isapnp_create_device(card, size) == 1)
 					return;
 				size = 0;
 			}
@@ -779,7 +766,8 @@
 		case _STAG_VENDOR:
 			break;
 		case _LTAG_ANSISTR:
-			isapnp_parse_name(card->name, sizeof(card->name), &size);
+			isapnp_parse_name(card->name, sizeof(card->name),
+					  &size);
 			break;
 		case _LTAG_UNICODESTR:
 			/* silently ignore */
@@ -792,18 +780,19 @@
 				isapnp_skip_bytes(size);
 			return;
 		default:
-			printk(KERN_ERR "isapnp: unexpected or unknown tag type 0x%x for device %i, ignored\n", type, card->number);
+			printk(KERN_ERR
+			       "isapnp: unexpected or unknown tag type 0x%x for device %i, ignored\n",
+			       type, card->number);
 		}
-	      __skip:
-	      	if (size > 0)
-		      	isapnp_skip_bytes(size);
+__skip:
+		if (size > 0)
+			isapnp_skip_bytes(size);
 	}
 }
 
 /*
  *  Compute ISA PnP checksum for first eight bytes.
  */
-
 static unsigned char __init isapnp_checksum(unsigned char *data)
 {
 	int i, j;
@@ -815,7 +804,9 @@
 			bit = 0;
 			if (b & (1 << j))
 				bit = 1;
-			checksum = ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7) | (checksum >> 1);
+			checksum =
+			    ((((checksum ^ (checksum >> 1)) & 0x01) ^ bit) << 7)
+			    | (checksum >> 1);
 		}
 	}
 	return checksum;
@@ -824,27 +815,25 @@
 /*
  *  Parse EISA id for ISA PnP card.
  */
-
-static void isapnp_parse_card_id(struct pnp_card * card, unsigned short vendor, unsigned short device)
+static void isapnp_parse_card_id(struct pnp_card *card, unsigned short vendor,
+				 unsigned short device)
 {
-	struct pnp_id * id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
+	struct pnp_id *id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
+
 	if (!id)
 		return;
 	sprintf(id->id, "%c%c%c%x%x%x%x",
-			'A' + ((vendor >> 2) & 0x3f) - 1,
-			'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
-			'A' + ((vendor >> 8) & 0x1f) - 1,
-			(device >> 4) & 0x0f,
-			device & 0x0f,
-			(device >> 12) & 0x0f,
-			(device >> 8) & 0x0f);
-	pnp_add_card_id(id,card);
+		'A' + ((vendor >> 2) & 0x3f) - 1,
+		'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
+		'A' + ((vendor >> 8) & 0x1f) - 1,
+		(device >> 4) & 0x0f,
+		device & 0x0f, (device >> 12) & 0x0f, (device >> 8) & 0x0f);
+	pnp_add_card_id(id, card);
 }
 
 /*
  *  Build device list for all present ISA PnP devices.
  */
-
 static int __init isapnp_build_device_list(void)
 {
 	int csn;
@@ -858,22 +847,29 @@
 		isapnp_peek(header, 9);
 		checksum = isapnp_checksum(header);
 #if 0
-		printk(KERN_DEBUG "vendor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
-			header[0], header[1], header[2], header[3],
-			header[4], header[5], header[6], header[7], header[8]);
+		printk(KERN_DEBUG
+		       "vendor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+		       header[0], header[1], header[2], header[3], header[4],
+		       header[5], header[6], header[7], header[8]);
 		printk(KERN_DEBUG "checksum = 0x%x\n", checksum);
 #endif
-		if ((card = kzalloc(sizeof(struct pnp_card), GFP_KERNEL)) == NULL)
+		if ((card =
+		     kzalloc(sizeof(struct pnp_card), GFP_KERNEL)) == NULL)
 			continue;
 
 		card->number = csn;
 		INIT_LIST_HEAD(&card->devices);
-		isapnp_parse_card_id(card, (header[1] << 8) | header[0], (header[3] << 8) | header[2]);
-		card->serial = (header[7] << 24) | (header[6] << 16) | (header[5] << 8) | header[4];
+		isapnp_parse_card_id(card, (header[1] << 8) | header[0],
+				     (header[3] << 8) | header[2]);
+		card->serial =
+		    (header[7] << 24) | (header[6] << 16) | (header[5] << 8) |
+		    header[4];
 		isapnp_checksum_value = 0x00;
 		isapnp_parse_resource_map(card);
 		if (isapnp_checksum_value != 0x00)
-			printk(KERN_ERR "isapnp: checksum for device %i is not valid (0x%x)\n", csn, isapnp_checksum_value);
+			printk(KERN_ERR
+			       "isapnp: checksum for device %i is not valid (0x%x)\n",
+			       csn, isapnp_checksum_value);
 		card->checksum = isapnp_checksum_value;
 		card->protocol = &isapnp_protocol;
 
@@ -890,6 +886,7 @@
 int isapnp_present(void)
 {
 	struct pnp_card *card;
+
 	pnp_for_each_card(card) {
 		if (card->protocol == &isapnp_protocol)
 			return 1;
@@ -911,13 +908,13 @@
 	/* it is possible to set RDP only in the isolation phase */
 	/*   Jens Thoms Toerring <Jens.Toerring@physik.fu-berlin.de> */
 	isapnp_write_byte(0x02, 0x04);	/* clear CSN of card */
-	mdelay(2);			/* is this necessary? */
-	isapnp_wake(csn);		/* bring card into sleep state */
-	isapnp_wake(0);			/* bring card into isolation state */
-	isapnp_set_rdp();		/* reset the RDP port */
-	udelay(1000);			/* delay 1000us */
+	mdelay(2);		/* is this necessary? */
+	isapnp_wake(csn);	/* bring card into sleep state */
+	isapnp_wake(0);		/* bring card into isolation state */
+	isapnp_set_rdp();	/* reset the RDP port */
+	udelay(1000);		/* delay 1000us */
 	isapnp_write_byte(0x06, csn);	/* reset CSN to previous value */
-	udelay(250);			/* is this necessary? */
+	udelay(250);		/* is this necessary? */
 #endif
 	if (logdev >= 0)
 		isapnp_device(logdev);
@@ -931,22 +928,18 @@
 	return 0;
 }
 
-
 /*
- *  Inititialization.
+ *  Initialization.
  */
 
-
 EXPORT_SYMBOL(isapnp_protocol);
 EXPORT_SYMBOL(isapnp_present);
 EXPORT_SYMBOL(isapnp_cfg_begin);
 EXPORT_SYMBOL(isapnp_cfg_end);
-#if 0
-EXPORT_SYMBOL(isapnp_read_byte);
-#endif
 EXPORT_SYMBOL(isapnp_write_byte);
 
-static int isapnp_read_resources(struct pnp_dev *dev, struct pnp_resource_table *res)
+static int isapnp_read_resources(struct pnp_dev *dev,
+				 struct pnp_resource_table *res)
 {
 	int tmp, ret;
 
@@ -960,33 +953,40 @@
 			res->port_resource[tmp].flags = IORESOURCE_IO;
 		}
 		for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
-			ret = isapnp_read_word(ISAPNP_CFG_MEM + (tmp << 3)) << 8;
+			ret =
+			    isapnp_read_word(ISAPNP_CFG_MEM + (tmp << 3)) << 8;
 			if (!ret)
 				continue;
 			res->mem_resource[tmp].start = ret;
 			res->mem_resource[tmp].flags = IORESOURCE_MEM;
 		}
 		for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
-			ret = (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >> 8);
+			ret =
+			    (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >>
+			     8);
 			if (!ret)
 				continue;
-			res->irq_resource[tmp].start = res->irq_resource[tmp].end = ret;
+			res->irq_resource[tmp].start =
+			    res->irq_resource[tmp].end = ret;
 			res->irq_resource[tmp].flags = IORESOURCE_IRQ;
 		}
 		for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
 			ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp);
 			if (ret == 4)
 				continue;
-			res->dma_resource[tmp].start = res->dma_resource[tmp].end = ret;
+			res->dma_resource[tmp].start =
+			    res->dma_resource[tmp].end = ret;
 			res->dma_resource[tmp].flags = IORESOURCE_DMA;
 		}
 	}
 	return 0;
 }
 
-static int isapnp_get_resources(struct pnp_dev *dev, struct pnp_resource_table * res)
+static int isapnp_get_resources(struct pnp_dev *dev,
+				struct pnp_resource_table *res)
 {
 	int ret;
+
 	pnp_init_resource_table(res);
 	isapnp_cfg_begin(dev->card->number, dev->number);
 	ret = isapnp_read_resources(dev, res);
@@ -994,24 +994,44 @@
 	return ret;
 }
 
-static int isapnp_set_resources(struct pnp_dev *dev, struct pnp_resource_table * res)
+static int isapnp_set_resources(struct pnp_dev *dev,
+				struct pnp_resource_table *res)
 {
 	int tmp;
 
 	isapnp_cfg_begin(dev->card->number, dev->number);
 	dev->active = 1;
-	for (tmp = 0; tmp < PNP_MAX_PORT && (res->port_resource[tmp].flags & (IORESOURCE_IO | IORESOURCE_UNSET)) == IORESOURCE_IO; tmp++)
-		isapnp_write_word(ISAPNP_CFG_PORT+(tmp<<1), res->port_resource[tmp].start);
-	for (tmp = 0; tmp < PNP_MAX_IRQ && (res->irq_resource[tmp].flags & (IORESOURCE_IRQ | IORESOURCE_UNSET)) == IORESOURCE_IRQ; tmp++) {
+	for (tmp = 0;
+	     tmp < PNP_MAX_PORT
+	     && (res->port_resource[tmp].
+		 flags & (IORESOURCE_IO | IORESOURCE_UNSET)) == IORESOURCE_IO;
+	     tmp++)
+		isapnp_write_word(ISAPNP_CFG_PORT + (tmp << 1),
+				  res->port_resource[tmp].start);
+	for (tmp = 0;
+	     tmp < PNP_MAX_IRQ
+	     && (res->irq_resource[tmp].
+		 flags & (IORESOURCE_IRQ | IORESOURCE_UNSET)) == IORESOURCE_IRQ;
+	     tmp++) {
 		int irq = res->irq_resource[tmp].start;
 		if (irq == 2)
 			irq = 9;
-		isapnp_write_byte(ISAPNP_CFG_IRQ+(tmp<<1), irq);
+		isapnp_write_byte(ISAPNP_CFG_IRQ + (tmp << 1), irq);
 	}
-	for (tmp = 0; tmp < PNP_MAX_DMA && (res->dma_resource[tmp].flags & (IORESOURCE_DMA | IORESOURCE_UNSET)) == IORESOURCE_DMA; tmp++)
-		isapnp_write_byte(ISAPNP_CFG_DMA+tmp, res->dma_resource[tmp].start);
-	for (tmp = 0; tmp < PNP_MAX_MEM && (res->mem_resource[tmp].flags & (IORESOURCE_MEM | IORESOURCE_UNSET)) == IORESOURCE_MEM; tmp++)
-		isapnp_write_word(ISAPNP_CFG_MEM+(tmp<<3), (res->mem_resource[tmp].start >> 8) & 0xffff);
+	for (tmp = 0;
+	     tmp < PNP_MAX_DMA
+	     && (res->dma_resource[tmp].
+		 flags & (IORESOURCE_DMA | IORESOURCE_UNSET)) == IORESOURCE_DMA;
+	     tmp++)
+		isapnp_write_byte(ISAPNP_CFG_DMA + tmp,
+				  res->dma_resource[tmp].start);
+	for (tmp = 0;
+	     tmp < PNP_MAX_MEM
+	     && (res->mem_resource[tmp].
+		 flags & (IORESOURCE_MEM | IORESOURCE_UNSET)) == IORESOURCE_MEM;
+	     tmp++)
+		isapnp_write_word(ISAPNP_CFG_MEM + (tmp << 3),
+				  (res->mem_resource[tmp].start >> 8) & 0xffff);
 	/* FIXME: We aren't handling 32bit mems properly here */
 	isapnp_activate(dev->number);
 	isapnp_cfg_end();
@@ -1020,7 +1040,7 @@
 
 static int isapnp_disable_resources(struct pnp_dev *dev)
 {
-	if (!dev || !dev->active)
+	if (!dev->active)
 		return -EINVAL;
 	isapnp_cfg_begin(dev->card->number, dev->number);
 	isapnp_deactivate(dev->number);
@@ -1030,9 +1050,9 @@
 }
 
 struct pnp_protocol isapnp_protocol = {
-	.name	= "ISA Plug and Play",
-	.get	= isapnp_get_resources,
-	.set	= isapnp_set_resources,
+	.name = "ISA Plug and Play",
+	.get = isapnp_get_resources,
+	.set = isapnp_set_resources,
 	.disable = isapnp_disable_resources,
 };
 
@@ -1043,7 +1063,6 @@
 	struct pnp_dev *dev;
 
 	if (isapnp_disable) {
-		isapnp_detected = 0;
 		printk(KERN_INFO "isapnp: ISA Plug & Play support disabled\n");
 		return 0;
 	}
@@ -1053,31 +1072,36 @@
 #endif
 #ifdef ISAPNP_REGION_OK
 	if (!request_region(_PIDXR, 1, "isapnp index")) {
-		printk(KERN_ERR "isapnp: Index Register 0x%x already used\n", _PIDXR);
+		printk(KERN_ERR "isapnp: Index Register 0x%x already used\n",
+		       _PIDXR);
 		return -EBUSY;
 	}
 #endif
 	if (!request_region(_PNPWRP, 1, "isapnp write")) {
-		printk(KERN_ERR "isapnp: Write Data Register 0x%x already used\n", _PNPWRP);
+		printk(KERN_ERR
+		       "isapnp: Write Data Register 0x%x already used\n",
+		       _PNPWRP);
 #ifdef ISAPNP_REGION_OK
 		release_region(_PIDXR, 1);
 #endif
 		return -EBUSY;
 	}
 
-	if(pnp_register_protocol(&isapnp_protocol)<0)
+	if (pnp_register_protocol(&isapnp_protocol) < 0)
 		return -EBUSY;
 
 	/*
-	 *	Print a message. The existing ISAPnP code is hanging machines
-	 *	so let the user know where.
+	 *      Print a message. The existing ISAPnP code is hanging machines
+	 *      so let the user know where.
 	 */
-	 
+
 	printk(KERN_INFO "isapnp: Scanning for PnP cards...\n");
 	if (isapnp_rdp >= 0x203 && isapnp_rdp <= 0x3ff) {
 		isapnp_rdp |= 3;
 		if (!request_region(isapnp_rdp, 1, "isapnp read")) {
-			printk(KERN_ERR "isapnp: Read Data Register 0x%x already used\n", isapnp_rdp);
+			printk(KERN_ERR
+			       "isapnp: Read Data Register 0x%x already used\n",
+			       isapnp_rdp);
 #ifdef ISAPNP_REGION_OK
 			release_region(_PIDXR, 1);
 #endif
@@ -1086,17 +1110,15 @@
 		}
 		isapnp_set_rdp();
 	}
-	isapnp_detected = 1;
 	if (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff) {
 		cards = isapnp_isolate();
-		if (cards < 0 || 
-		    (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff)) {
+		if (cards < 0 || (isapnp_rdp < 0x203 || isapnp_rdp > 0x3ff)) {
 #ifdef ISAPNP_REGION_OK
 			release_region(_PIDXR, 1);
 #endif
 			release_region(_PNPWRP, 1);
-			isapnp_detected = 0;
-			printk(KERN_INFO "isapnp: No Plug & Play device found\n");
+			printk(KERN_INFO
+			       "isapnp: No Plug & Play device found\n");
 			return 0;
 		}
 		request_region(isapnp_rdp, 1, "isapnp read");
@@ -1104,22 +1126,25 @@
 	isapnp_build_device_list();
 	cards = 0;
 
-	protocol_for_each_card(&isapnp_protocol,card) {
+	protocol_for_each_card(&isapnp_protocol, card) {
 		cards++;
 		if (isapnp_verbose) {
-			printk(KERN_INFO "isapnp: Card '%s'\n", card->name[0]?card->name:"Unknown");
+			printk(KERN_INFO "isapnp: Card '%s'\n",
+			       card->name[0] ? card->name : "Unknown");
 			if (isapnp_verbose < 2)
 				continue;
-			card_for_each_dev(card,dev) {
-				printk(KERN_INFO "isapnp:   Device '%s'\n", dev->name[0]?dev->name:"Unknown");
+			card_for_each_dev(card, dev) {
+				printk(KERN_INFO "isapnp:   Device '%s'\n",
+				       dev->name[0] ? dev->name : "Unknown");
 			}
 		}
 	}
-	if (cards) {
-		printk(KERN_INFO "isapnp: %i Plug & Play card%s detected total\n", cards, cards>1?"s":"");
-	} else {
+	if (cards)
+		printk(KERN_INFO
+		       "isapnp: %i Plug & Play card%s detected total\n", cards,
+		       cards > 1 ? "s" : "");
+	else
 		printk(KERN_INFO "isapnp: No Plug & Play card found\n");
-	}
 
 	isapnp_proc_init();
 	return 0;
@@ -1141,11 +1166,10 @@
 
 static int __init isapnp_setup_isapnp(char *str)
 {
-	(void)((get_option(&str,&isapnp_rdp) == 2) &&
-	       (get_option(&str,&isapnp_reset) == 2) &&
-	       (get_option(&str,&isapnp_verbose) == 2));
+	(void)((get_option(&str, &isapnp_rdp) == 2) &&
+	       (get_option(&str, &isapnp_reset) == 2) &&
+	       (get_option(&str, &isapnp_verbose) == 2));
 	return 1;
 }
 
 __setup("isapnp=", isapnp_setup_isapnp);
-
diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c
index 40b724e..560ccb6 100644
--- a/drivers/pnp/isapnp/proc.c
+++ b/drivers/pnp/isapnp/proc.c
@@ -2,7 +2,6 @@
  *  ISA Plug & Play support
  *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
  *
- *
  *   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
@@ -16,7 +15,6 @@
  *   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.
- *
  */
 
 #include <linux/module.h>
@@ -54,7 +52,8 @@
 	return (file->f_pos = new);
 }
 
-static ssize_t isapnp_proc_bus_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
+static ssize_t isapnp_proc_bus_read(struct file *file, char __user * buf,
+				    size_t nbytes, loff_t * ppos)
 {
 	struct inode *ino = file->f_path.dentry->d_inode;
 	struct proc_dir_entry *dp = PDE(ino);
@@ -74,7 +73,7 @@
 		return -EINVAL;
 
 	isapnp_cfg_begin(dev->card->number, dev->number);
-	for ( ; pos < 256 && cnt > 0; pos++, buf++, cnt--) {
+	for (; pos < 256 && cnt > 0; pos++, buf++, cnt--) {
 		unsigned char val;
 		val = isapnp_read_byte(pos);
 		__put_user(val, buf);
@@ -85,10 +84,9 @@
 	return nbytes;
 }
 
-static const struct file_operations isapnp_proc_bus_file_operations =
-{
-	.llseek		= isapnp_proc_bus_lseek,
-	.read		= isapnp_proc_bus_read,
+static const struct file_operations isapnp_proc_bus_file_operations = {
+	.llseek = isapnp_proc_bus_lseek,
+	.read = isapnp_proc_bus_read,
 };
 
 static int isapnp_proc_attach_device(struct pnp_dev *dev)
@@ -114,57 +112,13 @@
 	return 0;
 }
 
-#ifdef MODULE
-static int __exit isapnp_proc_detach_device(struct pnp_dev *dev)
-{
-	struct pnp_card *bus = dev->card;
-	struct proc_dir_entry *de;
-	char name[16];
-
-	if (!(de = bus->procdir))
-		return -EINVAL;
-	sprintf(name, "%02x", dev->number);
-	remove_proc_entry(name, de);
-	return 0;
-}
-
-static int __exit isapnp_proc_detach_bus(struct pnp_card *bus)
-{
-	struct proc_dir_entry *de;
-	char name[16];
-
-	if (!(de = bus->procdir))
-		return -EINVAL;
-	sprintf(name, "%02x", bus->number);
-	remove_proc_entry(name, isapnp_proc_bus_dir);
-	return 0;
-}
-#endif /* MODULE */
-
 int __init isapnp_proc_init(void)
 {
 	struct pnp_dev *dev;
+
 	isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus);
-	protocol_for_each_dev(&isapnp_protocol,dev) {
+	protocol_for_each_dev(&isapnp_protocol, dev) {
 		isapnp_proc_attach_device(dev);
 	}
 	return 0;
 }
-
-#ifdef MODULE
-int __exit isapnp_proc_done(void)
-{
-	struct pnp_dev *dev;
-	struct pnp_bus *card;
-
-	isapnp_for_each_dev(dev) {
-		isapnp_proc_detach_device(dev);
-	}
-	isapnp_for_each_card(card) {
-		isapnp_proc_detach_bus(card);
-	}
-	if (isapnp_proc_bus_dir)
-		remove_proc_entry("isapnp", proc_bus);
-	return 0;
-}
-#endif /* MODULE */
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
index 57e6ab1..0826287e 100644
--- a/drivers/pnp/manager.c
+++ b/drivers/pnp/manager.c
@@ -3,7 +3,6 @@
  *
  * based on isapnp.c resource management (c) Jaroslav Kysela <perex@suse.cz>
  * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
- *
  */
 
 #include <linux/errno.h>
@@ -22,11 +21,9 @@
 	resource_size_t *start, *end;
 	unsigned long *flags;
 
-	if (!dev || !rule)
-		return -EINVAL;
-
 	if (idx >= PNP_MAX_PORT) {
-		pnp_err("More than 4 ports is incompatible with pnp specifications.");
+		pnp_err
+		    ("More than 4 ports is incompatible with pnp specifications.");
 		/* pretend we were successful so at least the manager won't try again */
 		return 1;
 	}
@@ -41,11 +38,11 @@
 
 	/* set the initial values */
 	*flags |= rule->flags | IORESOURCE_IO;
-	*flags &=  ~IORESOURCE_UNSET;
+	*flags &= ~IORESOURCE_UNSET;
 
 	if (!rule->size) {
 		*flags |= IORESOURCE_DISABLED;
-		return 1; /* skip disabled resource requests */
+		return 1;	/* skip disabled resource requests */
 	}
 
 	*start = rule->min;
@@ -66,11 +63,9 @@
 	resource_size_t *start, *end;
 	unsigned long *flags;
 
-	if (!dev || !rule)
-		return -EINVAL;
-
 	if (idx >= PNP_MAX_MEM) {
-		pnp_err("More than 8 mems is incompatible with pnp specifications.");
+		pnp_err
+		    ("More than 8 mems is incompatible with pnp specifications.");
 		/* pretend we were successful so at least the manager won't try again */
 		return 1;
 	}
@@ -85,7 +80,7 @@
 
 	/* set the initial values */
 	*flags |= rule->flags | IORESOURCE_MEM;
-	*flags &=  ~IORESOURCE_UNSET;
+	*flags &= ~IORESOURCE_UNSET;
 
 	/* convert pnp flags to standard Linux flags */
 	if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
@@ -99,11 +94,11 @@
 
 	if (!rule->size) {
 		*flags |= IORESOURCE_DISABLED;
-		return 1; /* skip disabled resource requests */
+		return 1;	/* skip disabled resource requests */
 	}
 
 	*start = rule->min;
-	*end = *start + rule->size -1;
+	*end = *start + rule->size - 1;
 
 	/* run through until pnp_check_mem is happy */
 	while (!pnp_check_mem(dev, idx)) {
@@ -115,7 +110,7 @@
 	return 1;
 }
 
-static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx)
+static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
 {
 	resource_size_t *start, *end;
 	unsigned long *flags;
@@ -126,11 +121,9 @@
 		5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
 	};
 
-	if (!dev || !rule)
-		return -EINVAL;
-
 	if (idx >= PNP_MAX_IRQ) {
-		pnp_err("More than 2 irqs is incompatible with pnp specifications.");
+		pnp_err
+		    ("More than 2 irqs is incompatible with pnp specifications.");
 		/* pretend we were successful so at least the manager won't try again */
 		return 1;
 	}
@@ -145,11 +138,11 @@
 
 	/* set the initial values */
 	*flags |= rule->flags | IORESOURCE_IRQ;
-	*flags &=  ~IORESOURCE_UNSET;
+	*flags &= ~IORESOURCE_UNSET;
 
 	if (bitmap_empty(rule->map, PNP_IRQ_NR)) {
 		*flags |= IORESOURCE_DISABLED;
-		return 1; /* skip disabled resource requests */
+		return 1;	/* skip disabled resource requests */
 	}
 
 	/* TBD: need check for >16 IRQ */
@@ -159,9 +152,9 @@
 		return 1;
 	}
 	for (i = 0; i < 16; i++) {
-		if(test_bit(xtab[i], rule->map)) {
+		if (test_bit(xtab[i], rule->map)) {
 			*start = *end = xtab[i];
-			if(pnp_check_irq(dev, idx))
+			if (pnp_check_irq(dev, idx))
 				return 1;
 		}
 	}
@@ -179,11 +172,9 @@
 		1, 3, 5, 6, 7, 0, 2, 4
 	};
 
-	if (!dev || !rule)
-		return -EINVAL;
-
 	if (idx >= PNP_MAX_DMA) {
-		pnp_err("More than 2 dmas is incompatible with pnp specifications.");
+		pnp_err
+		    ("More than 2 dmas is incompatible with pnp specifications.");
 		/* pretend we were successful so at least the manager won't try again */
 		return 1;
 	}
@@ -198,17 +189,17 @@
 
 	/* set the initial values */
 	*flags |= rule->flags | IORESOURCE_DMA;
-	*flags &=  ~IORESOURCE_UNSET;
+	*flags &= ~IORESOURCE_UNSET;
 
 	if (!rule->map) {
 		*flags |= IORESOURCE_DISABLED;
-		return 1; /* skip disabled resource requests */
+		return 1;	/* skip disabled resource requests */
 	}
 
 	for (i = 0; i < 8; i++) {
-		if(rule->map & (1<<xtab[i])) {
+		if (rule->map & (1 << xtab[i])) {
 			*start = *end = xtab[i];
-			if(pnp_check_dma(dev, idx))
+			if (pnp_check_dma(dev, idx))
 				return 1;
 		}
 	}
@@ -218,72 +209,80 @@
 /**
  * pnp_init_resources - Resets a resource table to default values.
  * @table: pointer to the desired resource table
- *
  */
 void pnp_init_resource_table(struct pnp_resource_table *table)
 {
 	int idx;
+
 	for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
 		table->irq_resource[idx].name = NULL;
 		table->irq_resource[idx].start = -1;
 		table->irq_resource[idx].end = -1;
-		table->irq_resource[idx].flags = IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
+		table->irq_resource[idx].flags =
+		    IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
 	}
 	for (idx = 0; idx < PNP_MAX_DMA; idx++) {
 		table->dma_resource[idx].name = NULL;
 		table->dma_resource[idx].start = -1;
 		table->dma_resource[idx].end = -1;
-		table->dma_resource[idx].flags = IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
+		table->dma_resource[idx].flags =
+		    IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
 	}
 	for (idx = 0; idx < PNP_MAX_PORT; idx++) {
 		table->port_resource[idx].name = NULL;
 		table->port_resource[idx].start = 0;
 		table->port_resource[idx].end = 0;
-		table->port_resource[idx].flags = IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
+		table->port_resource[idx].flags =
+		    IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
 	}
 	for (idx = 0; idx < PNP_MAX_MEM; idx++) {
 		table->mem_resource[idx].name = NULL;
 		table->mem_resource[idx].start = 0;
 		table->mem_resource[idx].end = 0;
-		table->mem_resource[idx].flags = IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
+		table->mem_resource[idx].flags =
+		    IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
 	}
 }
 
 /**
  * pnp_clean_resources - clears resources that were not manually set
  * @res: the resources to clean
- *
  */
-static void pnp_clean_resource_table(struct pnp_resource_table * res)
+static void pnp_clean_resource_table(struct pnp_resource_table *res)
 {
 	int idx;
+
 	for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
 		if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO))
 			continue;
 		res->irq_resource[idx].start = -1;
 		res->irq_resource[idx].end = -1;
-		res->irq_resource[idx].flags = IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
+		res->irq_resource[idx].flags =
+		    IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
 	}
 	for (idx = 0; idx < PNP_MAX_DMA; idx++) {
 		if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO))
 			continue;
 		res->dma_resource[idx].start = -1;
 		res->dma_resource[idx].end = -1;
-		res->dma_resource[idx].flags = IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
+		res->dma_resource[idx].flags =
+		    IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
 	}
 	for (idx = 0; idx < PNP_MAX_PORT; idx++) {
 		if (!(res->port_resource[idx].flags & IORESOURCE_AUTO))
 			continue;
 		res->port_resource[idx].start = 0;
 		res->port_resource[idx].end = 0;
-		res->port_resource[idx].flags = IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
+		res->port_resource[idx].flags =
+		    IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
 	}
 	for (idx = 0; idx < PNP_MAX_MEM; idx++) {
 		if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO))
 			continue;
 		res->mem_resource[idx].start = 0;
 		res->mem_resource[idx].end = 0;
-		res->mem_resource[idx].flags = IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
+		res->mem_resource[idx].flags =
+		    IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
 	}
 }
 
@@ -306,7 +305,7 @@
 		return -ENODEV;
 
 	down(&pnp_res_mutex);
-	pnp_clean_resource_table(&dev->res); /* start with a fresh slate */
+	pnp_clean_resource_table(&dev->res);	/* start with a fresh slate */
 	if (dev->independent) {
 		port = dev->independent->port;
 		mem = dev->independent->mem;
@@ -341,10 +340,11 @@
 	if (depnum) {
 		struct pnp_option *dep;
 		int i;
-		for (i=1,dep=dev->dependent; i<depnum; i++, dep=dep->next)
-			if(!dep)
+		for (i = 1, dep = dev->dependent; i < depnum;
+		     i++, dep = dep->next)
+			if (!dep)
 				goto fail;
-		port =dep->port;
+		port = dep->port;
 		mem = dep->mem;
 		irq = dep->irq;
 		dma = dep->dma;
@@ -392,12 +392,12 @@
  *
  * This function can be used by drivers that want to manually set thier resources.
  */
-int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table * res, int mode)
+int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res,
+			  int mode)
 {
 	int i;
-	struct pnp_resource_table * bak;
-	if (!dev || !res)
-		return -EINVAL;
+	struct pnp_resource_table *bak;
+
 	if (!pnp_can_configure(dev))
 		return -ENODEV;
 	bak = pnp_alloc(sizeof(struct pnp_resource_table));
@@ -409,19 +409,19 @@
 	dev->res = *res;
 	if (!(mode & PNP_CONFIG_FORCE)) {
 		for (i = 0; i < PNP_MAX_PORT; i++) {
-			if(!pnp_check_port(dev,i))
+			if (!pnp_check_port(dev, i))
 				goto fail;
 		}
 		for (i = 0; i < PNP_MAX_MEM; i++) {
-			if(!pnp_check_mem(dev,i))
+			if (!pnp_check_mem(dev, i))
 				goto fail;
 		}
 		for (i = 0; i < PNP_MAX_IRQ; i++) {
-			if(!pnp_check_irq(dev,i))
+			if (!pnp_check_irq(dev, i))
 				goto fail;
 		}
 		for (i = 0; i < PNP_MAX_DMA; i++) {
-			if(!pnp_check_dma(dev,i))
+			if (!pnp_check_dma(dev, i))
 				goto fail;
 		}
 	}
@@ -440,18 +440,15 @@
 /**
  * pnp_auto_config_dev - automatically assigns resources to a device
  * @dev: pointer to the desired device
- *
  */
 int pnp_auto_config_dev(struct pnp_dev *dev)
 {
 	struct pnp_option *dep;
 	int i = 1;
 
-	if(!dev)
-		return -EINVAL;
-
-	if(!pnp_can_configure(dev)) {
-		pnp_dbg("Device %s does not support resource configuration.", dev->dev.bus_id);
+	if (!pnp_can_configure(dev)) {
+		pnp_dbg("Device %s does not support resource configuration.",
+			dev->dev.bus_id);
 		return -ENODEV;
 	}
 
@@ -476,23 +473,22 @@
  * pnp_start_dev - low-level start of the PnP device
  * @dev: pointer to the desired device
  *
- * assumes that resources have alread been allocated
+ * assumes that resources have already been allocated
  */
-
 int pnp_start_dev(struct pnp_dev *dev)
 {
 	if (!pnp_can_write(dev)) {
-		pnp_dbg("Device %s does not support activation.", dev->dev.bus_id);
+		pnp_dbg("Device %s does not support activation.",
+			dev->dev.bus_id);
 		return -EINVAL;
 	}
 
-	if (dev->protocol->set(dev, &dev->res)<0) {
+	if (dev->protocol->set(dev, &dev->res) < 0) {
 		pnp_err("Failed to activate device %s.", dev->dev.bus_id);
 		return -EIO;
 	}
 
 	pnp_info("Device %s activated.", dev->dev.bus_id);
-
 	return 0;
 }
 
@@ -502,20 +498,19 @@
  *
  * does not free resources
  */
-
 int pnp_stop_dev(struct pnp_dev *dev)
 {
 	if (!pnp_can_disable(dev)) {
-		pnp_dbg("Device %s does not support disabling.", dev->dev.bus_id);
+		pnp_dbg("Device %s does not support disabling.",
+			dev->dev.bus_id);
 		return -EINVAL;
 	}
-	if (dev->protocol->disable(dev)<0) {
+	if (dev->protocol->disable(dev) < 0) {
 		pnp_err("Failed to disable device %s.", dev->dev.bus_id);
 		return -EIO;
 	}
 
 	pnp_info("Device %s disabled.", dev->dev.bus_id);
-
 	return 0;
 }
 
@@ -529,11 +524,8 @@
 {
 	int error;
 
-	if (!dev)
-		return -EINVAL;
-	if (dev->active) {
-		return 0; /* the device is already active */
-	}
+	if (dev->active)
+		return 0;	/* the device is already active */
 
 	/* ensure resources are allocated */
 	if (pnp_auto_config_dev(dev))
@@ -544,7 +536,6 @@
 		return error;
 
 	dev->active = 1;
-
 	return 1;
 }
 
@@ -558,11 +549,8 @@
 {
 	int error;
 
-        if (!dev)
-                return -EINVAL;
-	if (!dev->active) {
-		return 0; /* the device is already disabled */
-	}
+	if (!dev->active)
+		return 0;	/* the device is already disabled */
 
 	error = pnp_stop_dev(dev);
 	if (error)
@@ -583,23 +571,16 @@
  * @resource: pointer to resource to be changed
  * @start: start of region
  * @size: size of region
- *
  */
 void pnp_resource_change(struct resource *resource, resource_size_t start,
-				resource_size_t size)
+			 resource_size_t size)
 {
-	if (resource == NULL)
-		return;
 	resource->flags &= ~(IORESOURCE_AUTO | IORESOURCE_UNSET);
 	resource->start = start;
 	resource->end = start + size - 1;
 }
 
-
 EXPORT_SYMBOL(pnp_manual_config_dev);
-#if 0
-EXPORT_SYMBOL(pnp_auto_config_dev);
-#endif
 EXPORT_SYMBOL(pnp_start_dev);
 EXPORT_SYMBOL(pnp_stop_dev);
 EXPORT_SYMBOL(pnp_activate_dev);
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index a005487..a5a3722 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -21,7 +21,10 @@
 
 #include <linux/acpi.h>
 #include <linux/pnp.h>
+#include <linux/mod_devicetable.h>
 #include <acpi/acpi_bus.h>
+#include <acpi/actypes.h>
+
 #include "pnpacpi.h"
 
 static int num = 0;
@@ -31,17 +34,19 @@
  * used by the kernel (PCI root, ...), as it is harmless and there were
  * already present in pnpbios. But there is an exception for devices that
  * have irqs (PIC, Timer) because we call acpi_register_gsi.
- * Finaly only devices that have a CRS method need to be in this list.
+ * Finally, only devices that have a CRS method need to be in this list.
  */
-static char __initdata excluded_id_list[] =
-	"PNP0C09," /* EC */
-	"PNP0C0F," /* Link device */
-	"PNP0000," /* PIC */
-	"PNP0100," /* Timer */
-	;
+static struct __initdata acpi_device_id excluded_id_list[] = {
+	{"PNP0C09", 0},		/* EC */
+	{"PNP0C0F", 0},		/* Link device */
+	{"PNP0000", 0},		/* PIC */
+	{"PNP0100", 0},		/* Timer */
+	{"", 0},
+};
+
 static inline int is_exclusive_device(struct acpi_device *dev)
 {
-	return (!acpi_match_ids(dev, excluded_id_list));
+	return (!acpi_match_device_ids(dev, excluded_id_list));
 }
 
 /*
@@ -79,15 +84,18 @@
 	str[7] = '\0';
 }
 
-static int pnpacpi_get_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
+static int pnpacpi_get_resources(struct pnp_dev *dev,
+				 struct pnp_resource_table *res)
 {
 	acpi_status status;
-	status = pnpacpi_parse_allocated_resource((acpi_handle)dev->data,
-		&dev->res);
+
+	status = pnpacpi_parse_allocated_resource((acpi_handle) dev->data,
+						  &dev->res);
 	return ACPI_FAILURE(status) ? -ENODEV : 0;
 }
 
-static int pnpacpi_set_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
+static int pnpacpi_set_resources(struct pnp_dev *dev,
+				 struct pnp_resource_table *res)
 {
 	acpi_handle handle = dev->data;
 	struct acpi_buffer buffer;
@@ -114,16 +122,36 @@
 	acpi_status status;
 
 	/* acpi_unregister_gsi(pnp_irq(dev, 0)); */
-	status = acpi_evaluate_object((acpi_handle)dev->data,
-		"_DIS", NULL, NULL);
+	status = acpi_evaluate_object((acpi_handle) dev->data,
+				      "_DIS", NULL, NULL);
 	return ACPI_FAILURE(status) ? -ENODEV : 0;
 }
 
+#ifdef CONFIG_ACPI_SLEEP
+static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
+{
+	return acpi_bus_set_power((acpi_handle) dev->data,
+				  acpi_pm_device_sleep_state(&dev->dev,
+							     device_may_wakeup
+							     (&dev->dev),
+							     NULL));
+}
+
+static int pnpacpi_resume(struct pnp_dev *dev)
+{
+	return acpi_bus_set_power((acpi_handle) dev->data, ACPI_STATE_D0);
+}
+#endif
+
 static struct pnp_protocol pnpacpi_protocol = {
-	.name	= "Plug and Play ACPI",
-	.get	= pnpacpi_get_resources,
-	.set	= pnpacpi_set_resources,
+	.name	 = "Plug and Play ACPI",
+	.get	 = pnpacpi_get_resources,
+	.set	 = pnpacpi_set_resources,
 	.disable = pnpacpi_disable_resources,
+#ifdef CONFIG_ACPI_SLEEP
+	.suspend = pnpacpi_suspend,
+	.resume = pnpacpi_resume,
+#endif
 };
 
 static int __init pnpacpi_add_device(struct acpi_device *device)
@@ -135,17 +163,17 @@
 
 	status = acpi_get_handle(device->handle, "_CRS", &temp);
 	if (ACPI_FAILURE(status) || !ispnpidacpi(acpi_device_hid(device)) ||
-		is_exclusive_device(device))
+	    is_exclusive_device(device))
 		return 0;
 
 	pnp_dbg("ACPI device : hid %s", acpi_device_hid(device));
-	dev =  kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
+	dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
 	if (!dev) {
 		pnp_err("Out of memory");
 		return -ENOMEM;
 	}
 	dev->data = device->handle;
-	/* .enabled means if the device can decode the resources */
+	/* .enabled means the device can decode the resources */
 	dev->active = device->status.enabled;
 	status = acpi_get_handle(device->handle, "_SRS", &temp);
 	if (ACPI_SUCCESS(status))
@@ -175,20 +203,23 @@
 	pnpidacpi_to_pnpid(acpi_device_hid(device), dev_id->id);
 	pnp_add_id(dev_id, dev);
 
-	if(dev->active) {
+	if (dev->active) {
 		/* parse allocated resource */
-		status = pnpacpi_parse_allocated_resource(device->handle, &dev->res);
+		status = pnpacpi_parse_allocated_resource(device->handle,
+							  &dev->res);
 		if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
-			pnp_err("PnPACPI: METHOD_NAME__CRS failure for %s", dev_id->id);
+			pnp_err("PnPACPI: METHOD_NAME__CRS failure for %s",
+				dev_id->id);
 			goto err1;
 		}
 	}
 
-	if(dev->capabilities & PNP_CONFIGURABLE) {
+	if (dev->capabilities & PNP_CONFIGURABLE) {
 		status = pnpacpi_parse_resource_option_data(device->handle,
-			dev);
+							    dev);
 		if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
-			pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s", dev_id->id);
+			pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s",
+				dev_id->id);
 			goto err1;
 		}
 	}
@@ -214,7 +245,7 @@
 	if (!dev->active)
 		pnp_init_resource_table(&dev->res);
 	pnp_add_device(dev);
-	num ++;
+	num++;
 
 	return AE_OK;
 err1:
@@ -225,7 +256,8 @@
 }
 
 static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle,
-	u32 lvl, void *context, void **rv)
+						     u32 lvl, void *context,
+						     void **rv)
 {
 	struct acpi_device *device;
 
@@ -238,23 +270,22 @@
 
 static int __init acpi_pnp_match(struct device *dev, void *_pnp)
 {
-	struct acpi_device	*acpi = to_acpi_device(dev);
-	struct pnp_dev		*pnp = _pnp;
+	struct acpi_device *acpi = to_acpi_device(dev);
+	struct pnp_dev *pnp = _pnp;
 
 	/* true means it matched */
 	return acpi->flags.hardware_id
-		&& !acpi_get_physical_device(acpi->handle)
-		&& compare_pnp_id(pnp->id, acpi->pnp.hardware_id);
+	    && !acpi_get_physical_device(acpi->handle)
+	    && compare_pnp_id(pnp->id, acpi->pnp.hardware_id);
 }
 
-static int __init acpi_pnp_find_device(struct device *dev, acpi_handle *handle)
+static int __init acpi_pnp_find_device(struct device *dev, acpi_handle * handle)
 {
-	struct device		*adev;
-	struct acpi_device	*acpi;
+	struct device *adev;
+	struct acpi_device *acpi;
 
 	adev = bus_find_device(&acpi_bus_type, NULL,
-			to_pnp_dev(dev),
-			acpi_pnp_match);
+			       to_pnp_dev(dev), acpi_pnp_match);
 	if (!adev)
 		return -ENODEV;
 
@@ -268,7 +299,7 @@
  * pnpdev->dev.archdata.acpi_handle point to its ACPI sibling.
  */
 static struct acpi_bus_type __initdata acpi_pnp_bus = {
-	.bus = &pnp_bus_type,
+	.bus	     = &pnp_bus_type,
 	.find_device = acpi_pnp_find_device,
 };
 
@@ -288,6 +319,7 @@
 	pnp_platform_devices = 1;
 	return 0;
 }
+
 subsys_initcall(pnpacpi_init);
 
 static int __init pnpacpi_setup(char *str)
@@ -298,8 +330,5 @@
 		pnpacpi_disabled = 1;
 	return 1;
 }
-__setup("pnpacpi=", pnpacpi_setup);
 
-#if 0
-EXPORT_SYMBOL(pnpacpi_protocol);
-#endif
+__setup("pnpacpi=", pnpacpi_setup);
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 118ac97..0e3b8d0 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -34,20 +34,17 @@
  */
 static int irq_flags(int triggering, int polarity)
 {
-	int flag;
 	if (triggering == ACPI_LEVEL_SENSITIVE) {
 		if (polarity == ACPI_ACTIVE_LOW)
-			flag = IORESOURCE_IRQ_LOWLEVEL;
+			return IORESOURCE_IRQ_LOWLEVEL;
 		else
-			flag = IORESOURCE_IRQ_HIGHLEVEL;
-	}
-	else {
+			return IORESOURCE_IRQ_HIGHLEVEL;
+	} else {
 		if (polarity == ACPI_ACTIVE_LOW)
-			flag = IORESOURCE_IRQ_LOWEDGE;
+			return IORESOURCE_IRQ_LOWEDGE;
 		else
-			flag = IORESOURCE_IRQ_HIGHEDGE;
+			return IORESOURCE_IRQ_HIGHEDGE;
 	}
-	return flag;
 }
 
 static void decode_irq_flags(int flag, int *triggering, int *polarity)
@@ -72,9 +69,9 @@
 	}
 }
 
-static void
-pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res, u32 gsi,
-	int triggering, int polarity, int shareable)
+static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res,
+						u32 gsi, int triggering,
+						int polarity, int shareable)
 {
 	int i = 0;
 	int irq;
@@ -83,12 +80,12 @@
 		return;
 
 	while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) &&
-			i < PNP_MAX_IRQ)
+	       i < PNP_MAX_IRQ)
 		i++;
 	if (i >= PNP_MAX_IRQ)
 		return;
 
-	res->irq_resource[i].flags = IORESOURCE_IRQ;  // Also clears _UNSET flag
+	res->irq_resource[i].flags = IORESOURCE_IRQ;	// Also clears _UNSET flag
 	res->irq_resource[i].flags |= irq_flags(triggering, polarity);
 	irq = acpi_register_gsi(gsi, triggering, polarity);
 	if (irq < 0) {
@@ -147,17 +144,19 @@
 	return flags;
 }
 
-static void
-pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table *res, u32 dma,
-	int type, int bus_master, int transfer)
+static void pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table *res,
+						u32 dma, int type,
+						int bus_master, int transfer)
 {
 	int i = 0;
+
 	while (i < PNP_MAX_DMA &&
-			!(res->dma_resource[i].flags & IORESOURCE_UNSET))
+	       !(res->dma_resource[i].flags & IORESOURCE_UNSET))
 		i++;
 	if (i < PNP_MAX_DMA) {
-		res->dma_resource[i].flags = IORESOURCE_DMA;  // Also clears _UNSET flag
-		res->dma_resource[i].flags |= dma_flags(type, bus_master, transfer);
+		res->dma_resource[i].flags = IORESOURCE_DMA;	// Also clears _UNSET flag
+		res->dma_resource[i].flags |=
+		    dma_flags(type, bus_master, transfer);
 		if (dma == -1) {
 			res->dma_resource[i].flags |= IORESOURCE_DISABLED;
 			return;
@@ -167,19 +166,19 @@
 	}
 }
 
-static void
-pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res,
-	u64 io, u64 len, int io_decode)
+static void pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res,
+					       u64 io, u64 len, int io_decode)
 {
 	int i = 0;
+
 	while (!(res->port_resource[i].flags & IORESOURCE_UNSET) &&
-			i < PNP_MAX_PORT)
+	       i < PNP_MAX_PORT)
 		i++;
 	if (i < PNP_MAX_PORT) {
-		res->port_resource[i].flags = IORESOURCE_IO;  // Also clears _UNSET flag
+		res->port_resource[i].flags = IORESOURCE_IO;	// Also clears _UNSET flag
 		if (io_decode == ACPI_DECODE_16)
 			res->port_resource[i].flags |= PNP_PORT_FLAG_16BITADDR;
-		if (len <= 0 || (io + len -1) >= 0x10003) {
+		if (len <= 0 || (io + len - 1) >= 0x10003) {
 			res->port_resource[i].flags |= IORESOURCE_DISABLED;
 			return;
 		}
@@ -188,21 +187,22 @@
 	}
 }
 
-static void
-pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res,
-	u64 mem, u64 len, int write_protect)
+static void pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res,
+						u64 mem, u64 len,
+						int write_protect)
 {
 	int i = 0;
+
 	while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) &&
-			(i < PNP_MAX_MEM))
+	       (i < PNP_MAX_MEM))
 		i++;
 	if (i < PNP_MAX_MEM) {
-		res->mem_resource[i].flags = IORESOURCE_MEM;  // Also clears _UNSET flag
+		res->mem_resource[i].flags = IORESOURCE_MEM;	// Also clears _UNSET flag
 		if (len <= 0) {
 			res->mem_resource[i].flags |= IORESOURCE_DISABLED;
 			return;
 		}
-		if(write_protect == ACPI_READ_WRITE_MEMORY)
+		if (write_protect == ACPI_READ_WRITE_MEMORY)
 			res->mem_resource[i].flags |= IORESOURCE_MEM_WRITEABLE;
 
 		res->mem_resource[i].start = mem;
@@ -210,9 +210,8 @@
 	}
 }
 
-static void
-pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table,
-	struct acpi_resource *res)
+static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table,
+						  struct acpi_resource *res)
 {
 	struct acpi_resource_address64 addr, *p = &addr;
 	acpi_status status;
@@ -220,7 +219,7 @@
 	status = acpi_resource_to_address64(res, p);
 	if (!ACPI_SUCCESS(status)) {
 		pnp_warn("PnPACPI: failed to convert resource type %d",
-			res->type);
+			 res->type);
 		return;
 	}
 
@@ -229,17 +228,19 @@
 
 	if (p->resource_type == ACPI_MEMORY_RANGE)
 		pnpacpi_parse_allocated_memresource(res_table,
-				p->minimum, p->address_length, p->info.mem.write_protect);
+			p->minimum, p->address_length,
+			p->info.mem.write_protect);
 	else if (p->resource_type == ACPI_IO_RANGE)
 		pnpacpi_parse_allocated_ioresource(res_table,
-				p->minimum, p->address_length,
-				p->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16);
+			p->minimum, p->address_length,
+			p->granularity == 0xfff ? ACPI_DECODE_10 :
+				ACPI_DECODE_16);
 }
 
 static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
-	void *data)
+					      void *data)
 {
-	struct pnp_resource_table *res_table = (struct pnp_resource_table *)data;
+	struct pnp_resource_table *res_table = data;
 	int i;
 
 	switch (res->type) {
@@ -260,17 +261,17 @@
 	case ACPI_RESOURCE_TYPE_DMA:
 		if (res->data.dma.channel_count > 0)
 			pnpacpi_parse_allocated_dmaresource(res_table,
-					res->data.dma.channels[0],
-					res->data.dma.type,
-					res->data.dma.bus_master,
-					res->data.dma.transfer);
+				res->data.dma.channels[0],
+				res->data.dma.type,
+				res->data.dma.bus_master,
+				res->data.dma.transfer);
 		break;
 
 	case ACPI_RESOURCE_TYPE_IO:
 		pnpacpi_parse_allocated_ioresource(res_table,
-				res->data.io.minimum,
-				res->data.io.address_length,
-				res->data.io.io_decode);
+			res->data.io.minimum,
+			res->data.io.address_length,
+			res->data.io.io_decode);
 		break;
 
 	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
@@ -279,9 +280,9 @@
 
 	case ACPI_RESOURCE_TYPE_FIXED_IO:
 		pnpacpi_parse_allocated_ioresource(res_table,
-				res->data.fixed_io.address,
-				res->data.fixed_io.address_length,
-				ACPI_DECODE_10);
+			res->data.fixed_io.address,
+			res->data.fixed_io.address_length,
+			ACPI_DECODE_10);
 		break;
 
 	case ACPI_RESOURCE_TYPE_VENDOR:
@@ -292,21 +293,21 @@
 
 	case ACPI_RESOURCE_TYPE_MEMORY24:
 		pnpacpi_parse_allocated_memresource(res_table,
-				res->data.memory24.minimum,
-				res->data.memory24.address_length,
-				res->data.memory24.write_protect);
+			res->data.memory24.minimum,
+			res->data.memory24.address_length,
+			res->data.memory24.write_protect);
 		break;
 	case ACPI_RESOURCE_TYPE_MEMORY32:
 		pnpacpi_parse_allocated_memresource(res_table,
-				res->data.memory32.minimum,
-				res->data.memory32.address_length,
-				res->data.memory32.write_protect);
+			res->data.memory32.minimum,
+			res->data.memory32.address_length,
+			res->data.memory32.write_protect);
 		break;
 	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
 		pnpacpi_parse_allocated_memresource(res_table,
-				res->data.fixed_memory32.address,
-				res->data.fixed_memory32.address_length,
-				res->data.fixed_memory32.write_protect);
+			res->data.fixed_memory32.address,
+			res->data.fixed_memory32.address_length,
+			res->data.fixed_memory32.write_protect);
 		break;
 	case ACPI_RESOURCE_TYPE_ADDRESS16:
 	case ACPI_RESOURCE_TYPE_ADDRESS32:
@@ -343,18 +344,21 @@
 	return AE_OK;
 }
 
-acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle, struct pnp_resource_table *res)
+acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle,
+					     struct pnp_resource_table * res)
 {
 	/* Blank the resource table values */
 	pnp_init_resource_table(res);
 
-	return acpi_walk_resources(handle, METHOD_NAME__CRS, pnpacpi_allocated_resource, res);
+	return acpi_walk_resources(handle, METHOD_NAME__CRS,
+				   pnpacpi_allocated_resource, res);
 }
 
-static void pnpacpi_parse_dma_option(struct pnp_option *option, struct acpi_resource_dma *p)
+static void pnpacpi_parse_dma_option(struct pnp_option *option,
+				     struct acpi_resource_dma *p)
 {
 	int i;
-	struct pnp_dma * dma;
+	struct pnp_dma *dma;
 
 	if (p->channel_count == 0)
 		return;
@@ -362,18 +366,16 @@
 	if (!dma)
 		return;
 
-	for(i = 0; i < p->channel_count; i++)
+	for (i = 0; i < p->channel_count; i++)
 		dma->map |= 1 << p->channels[i];
 
 	dma->flags = dma_flags(p->type, p->bus_master, p->transfer);
 
 	pnp_register_dma_resource(option, dma);
-	return;
 }
 
-
 static void pnpacpi_parse_irq_option(struct pnp_option *option,
-	struct acpi_resource_irq *p)
+				     struct acpi_resource_irq *p)
 {
 	int i;
 	struct pnp_irq *irq;
@@ -384,17 +386,16 @@
 	if (!irq)
 		return;
 
-	for(i = 0; i < p->interrupt_count; i++)
+	for (i = 0; i < p->interrupt_count; i++)
 		if (p->interrupts[i])
 			__set_bit(p->interrupts[i], irq->map);
 	irq->flags = irq_flags(p->triggering, p->polarity);
 
 	pnp_register_irq_resource(option, irq);
-	return;
 }
 
 static void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
-	struct acpi_resource_extended_irq *p)
+					 struct acpi_resource_extended_irq *p)
 {
 	int i;
 	struct pnp_irq *irq;
@@ -405,18 +406,16 @@
 	if (!irq)
 		return;
 
-	for(i = 0; i < p->interrupt_count; i++)
+	for (i = 0; i < p->interrupt_count; i++)
 		if (p->interrupts[i])
 			__set_bit(p->interrupts[i], irq->map);
 	irq->flags = irq_flags(p->triggering, p->polarity);
 
 	pnp_register_irq_resource(option, irq);
-	return;
 }
 
-static void
-pnpacpi_parse_port_option(struct pnp_option *option,
-	struct acpi_resource_io *io)
+static void pnpacpi_parse_port_option(struct pnp_option *option,
+				      struct acpi_resource_io *io)
 {
 	struct pnp_port *port;
 
@@ -430,14 +429,12 @@
 	port->align = io->alignment;
 	port->size = io->address_length;
 	port->flags = ACPI_DECODE_16 == io->io_decode ?
-		PNP_PORT_FLAG_16BITADDR : 0;
+	    PNP_PORT_FLAG_16BITADDR : 0;
 	pnp_register_port_resource(option, port);
-	return;
 }
 
-static void
-pnpacpi_parse_fixed_port_option(struct pnp_option *option,
-	struct acpi_resource_fixed_io *io)
+static void pnpacpi_parse_fixed_port_option(struct pnp_option *option,
+					    struct acpi_resource_fixed_io *io)
 {
 	struct pnp_port *port;
 
@@ -451,12 +448,10 @@
 	port->align = 0;
 	port->flags = PNP_PORT_FLAG_FIXED;
 	pnp_register_port_resource(option, port);
-	return;
 }
 
-static void
-pnpacpi_parse_mem24_option(struct pnp_option *option,
-	struct acpi_resource_memory24 *p)
+static void pnpacpi_parse_mem24_option(struct pnp_option *option,
+				       struct acpi_resource_memory24 *p)
 {
 	struct pnp_mem *mem;
 
@@ -471,15 +466,13 @@
 	mem->size = p->address_length;
 
 	mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
-			IORESOURCE_MEM_WRITEABLE : 0;
+	    IORESOURCE_MEM_WRITEABLE : 0;
 
 	pnp_register_mem_resource(option, mem);
-	return;
 }
 
-static void
-pnpacpi_parse_mem32_option(struct pnp_option *option,
-	struct acpi_resource_memory32 *p)
+static void pnpacpi_parse_mem32_option(struct pnp_option *option,
+				       struct acpi_resource_memory32 *p)
 {
 	struct pnp_mem *mem;
 
@@ -494,15 +487,13 @@
 	mem->size = p->address_length;
 
 	mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
-			IORESOURCE_MEM_WRITEABLE : 0;
+	    IORESOURCE_MEM_WRITEABLE : 0;
 
 	pnp_register_mem_resource(option, mem);
-	return;
 }
 
-static void
-pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
-	struct acpi_resource_fixed_memory32 *p)
+static void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
+					 struct acpi_resource_fixed_memory32 *p)
 {
 	struct pnp_mem *mem;
 
@@ -516,14 +507,13 @@
 	mem->align = 0;
 
 	mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
-			IORESOURCE_MEM_WRITEABLE : 0;
+	    IORESOURCE_MEM_WRITEABLE : 0;
 
 	pnp_register_mem_resource(option, mem);
-	return;
 }
 
-static void
-pnpacpi_parse_address_option(struct pnp_option *option, struct acpi_resource *r)
+static void pnpacpi_parse_address_option(struct pnp_option *option,
+					 struct acpi_resource *r)
 {
 	struct acpi_resource_address64 addr, *p = &addr;
 	acpi_status status;
@@ -532,7 +522,8 @@
 
 	status = acpi_resource_to_address64(r, p);
 	if (!ACPI_SUCCESS(status)) {
-		pnp_warn("PnPACPI: failed to convert resource type %d", r->type);
+		pnp_warn("PnPACPI: failed to convert resource type %d",
+			 r->type);
 		return;
 	}
 
@@ -547,7 +538,8 @@
 		mem->size = p->address_length;
 		mem->align = 0;
 		mem->flags = (p->info.mem.write_protect ==
-		    ACPI_READ_WRITE_MEMORY) ? IORESOURCE_MEM_WRITEABLE : 0;
+			      ACPI_READ_WRITE_MEMORY) ? IORESOURCE_MEM_WRITEABLE
+		    : 0;
 		pnp_register_mem_resource(option, mem);
 	} else if (p->resource_type == ACPI_IO_RANGE) {
 		port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
@@ -568,109 +560,107 @@
 };
 
 static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
-	void *data)
+					   void *data)
 {
 	int priority = 0;
-	struct acpipnp_parse_option_s *parse_data = (struct acpipnp_parse_option_s *)data;
+	struct acpipnp_parse_option_s *parse_data = data;
 	struct pnp_dev *dev = parse_data->dev;
 	struct pnp_option *option = parse_data->option;
 
 	switch (res->type) {
-		case ACPI_RESOURCE_TYPE_IRQ:
-			pnpacpi_parse_irq_option(option, &res->data.irq);
+	case ACPI_RESOURCE_TYPE_IRQ:
+		pnpacpi_parse_irq_option(option, &res->data.irq);
+		break;
+
+	case ACPI_RESOURCE_TYPE_DMA:
+		pnpacpi_parse_dma_option(option, &res->data.dma);
+		break;
+
+	case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+		switch (res->data.start_dpf.compatibility_priority) {
+		case ACPI_GOOD_CONFIGURATION:
+			priority = PNP_RES_PRIORITY_PREFERRED;
 			break;
 
-		case ACPI_RESOURCE_TYPE_DMA:
-			pnpacpi_parse_dma_option(option, &res->data.dma);
+		case ACPI_ACCEPTABLE_CONFIGURATION:
+			priority = PNP_RES_PRIORITY_ACCEPTABLE;
 			break;
 
-		case ACPI_RESOURCE_TYPE_START_DEPENDENT:
-			switch (res->data.start_dpf.compatibility_priority) {
-				case ACPI_GOOD_CONFIGURATION:
-					priority = PNP_RES_PRIORITY_PREFERRED;
-					break;
-
-				case ACPI_ACCEPTABLE_CONFIGURATION:
-					priority = PNP_RES_PRIORITY_ACCEPTABLE;
-					break;
-
-				case ACPI_SUB_OPTIMAL_CONFIGURATION:
-					priority = PNP_RES_PRIORITY_FUNCTIONAL;
-					break;
-				default:
-					priority = PNP_RES_PRIORITY_INVALID;
-					break;
-			}
-			/* TBD: Considering performace/robustness bits */
-			option = pnp_register_dependent_option(dev, priority);
-			if (!option)
-				return AE_ERROR;
-			parse_data->option = option;
+		case ACPI_SUB_OPTIMAL_CONFIGURATION:
+			priority = PNP_RES_PRIORITY_FUNCTIONAL;
 			break;
-
-		case ACPI_RESOURCE_TYPE_END_DEPENDENT:
-			/*only one EndDependentFn is allowed*/
-			if (!parse_data->option_independent) {
-				pnp_warn("PnPACPI: more than one EndDependentFn");
-				return AE_ERROR;
-			}
-			parse_data->option = parse_data->option_independent;
-			parse_data->option_independent = NULL;
-			break;
-
-		case ACPI_RESOURCE_TYPE_IO:
-			pnpacpi_parse_port_option(option, &res->data.io);
-			break;
-
-		case ACPI_RESOURCE_TYPE_FIXED_IO:
-			pnpacpi_parse_fixed_port_option(option,
-				&res->data.fixed_io);
-			break;
-
-		case ACPI_RESOURCE_TYPE_VENDOR:
-		case ACPI_RESOURCE_TYPE_END_TAG:
-			break;
-
-		case ACPI_RESOURCE_TYPE_MEMORY24:
-			pnpacpi_parse_mem24_option(option, &res->data.memory24);
-			break;
-
-		case ACPI_RESOURCE_TYPE_MEMORY32:
-			pnpacpi_parse_mem32_option(option, &res->data.memory32);
-			break;
-
-		case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
-			pnpacpi_parse_fixed_mem32_option(option,
-				&res->data.fixed_memory32);
-			break;
-
-		case ACPI_RESOURCE_TYPE_ADDRESS16:
-		case ACPI_RESOURCE_TYPE_ADDRESS32:
-		case ACPI_RESOURCE_TYPE_ADDRESS64:
-			pnpacpi_parse_address_option(option, res);
-			break;
-
-		case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
-			break;
-
-		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
-			pnpacpi_parse_ext_irq_option(option,
-				&res->data.extended_irq);
-			break;
-
-		case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
-			break;
-
 		default:
-			pnp_warn("PnPACPI: unknown resource type %d", res->type);
+			priority = PNP_RES_PRIORITY_INVALID;
+			break;
+		}
+		/* TBD: Consider performance/robustness bits */
+		option = pnp_register_dependent_option(dev, priority);
+		if (!option)
 			return AE_ERROR;
+		parse_data->option = option;
+		break;
+
+	case ACPI_RESOURCE_TYPE_END_DEPENDENT:
+		/*only one EndDependentFn is allowed */
+		if (!parse_data->option_independent) {
+			pnp_warn("PnPACPI: more than one EndDependentFn");
+			return AE_ERROR;
+		}
+		parse_data->option = parse_data->option_independent;
+		parse_data->option_independent = NULL;
+		break;
+
+	case ACPI_RESOURCE_TYPE_IO:
+		pnpacpi_parse_port_option(option, &res->data.io);
+		break;
+
+	case ACPI_RESOURCE_TYPE_FIXED_IO:
+		pnpacpi_parse_fixed_port_option(option, &res->data.fixed_io);
+		break;
+
+	case ACPI_RESOURCE_TYPE_VENDOR:
+	case ACPI_RESOURCE_TYPE_END_TAG:
+		break;
+
+	case ACPI_RESOURCE_TYPE_MEMORY24:
+		pnpacpi_parse_mem24_option(option, &res->data.memory24);
+		break;
+
+	case ACPI_RESOURCE_TYPE_MEMORY32:
+		pnpacpi_parse_mem32_option(option, &res->data.memory32);
+		break;
+
+	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
+		pnpacpi_parse_fixed_mem32_option(option,
+						 &res->data.fixed_memory32);
+		break;
+
+	case ACPI_RESOURCE_TYPE_ADDRESS16:
+	case ACPI_RESOURCE_TYPE_ADDRESS32:
+	case ACPI_RESOURCE_TYPE_ADDRESS64:
+		pnpacpi_parse_address_option(option, res);
+		break;
+
+	case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
+		break;
+
+	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+		pnpacpi_parse_ext_irq_option(option, &res->data.extended_irq);
+		break;
+
+	case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
+		break;
+
+	default:
+		pnp_warn("PnPACPI: unknown resource type %d", res->type);
+		return AE_ERROR;
 	}
 
 	return AE_OK;
 }
 
 acpi_status pnpacpi_parse_resource_option_data(acpi_handle handle,
-	struct pnp_dev *dev)
+					       struct pnp_dev * dev)
 {
 	acpi_status status;
 	struct acpipnp_parse_option_s parse_data;
@@ -681,7 +671,7 @@
 	parse_data.option_independent = parse_data.option;
 	parse_data.dev = dev;
 	status = acpi_walk_resources(handle, METHOD_NAME__PRS,
-		pnpacpi_option_resource, &parse_data);
+				     pnpacpi_option_resource, &parse_data);
 
 	return status;
 }
@@ -709,9 +699,9 @@
  * Set resource
  */
 static acpi_status pnpacpi_count_resources(struct acpi_resource *res,
-	void *data)
+					   void *data)
 {
-	int *res_cnt = (int *)data;
+	int *res_cnt = data;
 
 	if (pnpacpi_supported_resource(res))
 		(*res_cnt)++;
@@ -720,7 +710,7 @@
 
 static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data)
 {
-	struct acpi_resource **resource = (struct acpi_resource **)data;
+	struct acpi_resource **resource = data;
 
 	if (pnpacpi_supported_resource(res)) {
 		(*resource)->type = res->type;
@@ -732,14 +722,14 @@
 }
 
 int pnpacpi_build_resource_template(acpi_handle handle,
-	struct acpi_buffer *buffer)
+				    struct acpi_buffer *buffer)
 {
 	struct acpi_resource *resource;
 	int res_cnt = 0;
 	acpi_status status;
 
 	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
-		pnpacpi_count_resources, &res_cnt);
+				     pnpacpi_count_resources, &res_cnt);
 	if (ACPI_FAILURE(status)) {
 		pnp_err("Evaluate _CRS failed");
 		return -EINVAL;
@@ -753,7 +743,7 @@
 	pnp_dbg("Res cnt %d", res_cnt);
 	resource = (struct acpi_resource *)buffer->pointer;
 	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
-		pnpacpi_type_resources, &resource);
+				     pnpacpi_type_resources, &resource);
 	if (ACPI_FAILURE(status)) {
 		kfree(buffer->pointer);
 		pnp_err("Evaluate _CRS failed");
@@ -766,7 +756,7 @@
 }
 
 static void pnpacpi_encode_irq(struct acpi_resource *resource,
-	struct resource *p)
+			       struct resource *p)
 {
 	int triggering, polarity;
 
@@ -782,7 +772,7 @@
 }
 
 static void pnpacpi_encode_ext_irq(struct acpi_resource *resource,
-	struct resource *p)
+				   struct resource *p)
 {
 	int triggering, polarity;
 
@@ -799,32 +789,32 @@
 }
 
 static void pnpacpi_encode_dma(struct acpi_resource *resource,
-	struct resource *p)
+			       struct resource *p)
 {
 	/* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
 	switch (p->flags & IORESOURCE_DMA_SPEED_MASK) {
-		case IORESOURCE_DMA_TYPEA:
-			resource->data.dma.type = ACPI_TYPE_A;
-			break;
-		case IORESOURCE_DMA_TYPEB:
-			resource->data.dma.type = ACPI_TYPE_B;
-			break;
-		case IORESOURCE_DMA_TYPEF:
-			resource->data.dma.type = ACPI_TYPE_F;
-			break;
-		default:
-			resource->data.dma.type = ACPI_COMPATIBILITY;
+	case IORESOURCE_DMA_TYPEA:
+		resource->data.dma.type = ACPI_TYPE_A;
+		break;
+	case IORESOURCE_DMA_TYPEB:
+		resource->data.dma.type = ACPI_TYPE_B;
+		break;
+	case IORESOURCE_DMA_TYPEF:
+		resource->data.dma.type = ACPI_TYPE_F;
+		break;
+	default:
+		resource->data.dma.type = ACPI_COMPATIBILITY;
 	}
 
 	switch (p->flags & IORESOURCE_DMA_TYPE_MASK) {
-		case IORESOURCE_DMA_8BIT:
-			resource->data.dma.transfer = ACPI_TRANSFER_8;
-			break;
-		case IORESOURCE_DMA_8AND16BIT:
-			resource->data.dma.transfer = ACPI_TRANSFER_8_16;
-			break;
-		default:
-			resource->data.dma.transfer = ACPI_TRANSFER_16;
+	case IORESOURCE_DMA_8BIT:
+		resource->data.dma.transfer = ACPI_TRANSFER_8;
+		break;
+	case IORESOURCE_DMA_8AND16BIT:
+		resource->data.dma.transfer = ACPI_TRANSFER_8_16;
+		break;
+	default:
+		resource->data.dma.transfer = ACPI_TRANSFER_16;
 	}
 
 	resource->data.dma.bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
@@ -833,31 +823,31 @@
 }
 
 static void pnpacpi_encode_io(struct acpi_resource *resource,
-	struct resource *p)
+			      struct resource *p)
 {
 	/* Note: pnp_assign_port will copy pnp_port->flags into p->flags */
-	resource->data.io.io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR)?
-		ACPI_DECODE_16 : ACPI_DECODE_10;
+	resource->data.io.io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR) ?
+	    ACPI_DECODE_16 : ACPI_DECODE_10;
 	resource->data.io.minimum = p->start;
 	resource->data.io.maximum = p->end;
-	resource->data.io.alignment = 0; /* Correct? */
+	resource->data.io.alignment = 0;	/* Correct? */
 	resource->data.io.address_length = p->end - p->start + 1;
 }
 
 static void pnpacpi_encode_fixed_io(struct acpi_resource *resource,
-	struct resource *p)
+				    struct resource *p)
 {
 	resource->data.fixed_io.address = p->start;
 	resource->data.fixed_io.address_length = p->end - p->start + 1;
 }
 
 static void pnpacpi_encode_mem24(struct acpi_resource *resource,
-	struct resource *p)
+				 struct resource *p)
 {
 	/* Note: pnp_assign_mem will copy pnp_mem->flags into p->flags */
 	resource->data.memory24.write_protect =
-		(p->flags & IORESOURCE_MEM_WRITEABLE) ?
-		ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
+	    (p->flags & IORESOURCE_MEM_WRITEABLE) ?
+	    ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
 	resource->data.memory24.minimum = p->start;
 	resource->data.memory24.maximum = p->end;
 	resource->data.memory24.alignment = 0;
@@ -865,11 +855,11 @@
 }
 
 static void pnpacpi_encode_mem32(struct acpi_resource *resource,
-	struct resource *p)
+				 struct resource *p)
 {
 	resource->data.memory32.write_protect =
-		(p->flags & IORESOURCE_MEM_WRITEABLE) ?
-		ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
+	    (p->flags & IORESOURCE_MEM_WRITEABLE) ?
+	    ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
 	resource->data.memory32.minimum = p->start;
 	resource->data.memory32.maximum = p->end;
 	resource->data.memory32.alignment = 0;
@@ -877,74 +867,76 @@
 }
 
 static void pnpacpi_encode_fixed_mem32(struct acpi_resource *resource,
-	struct resource *p)
+				       struct resource *p)
 {
 	resource->data.fixed_memory32.write_protect =
-		(p->flags & IORESOURCE_MEM_WRITEABLE) ?
-		ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
+	    (p->flags & IORESOURCE_MEM_WRITEABLE) ?
+	    ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
 	resource->data.fixed_memory32.address = p->start;
 	resource->data.fixed_memory32.address_length = p->end - p->start + 1;
 }
 
 int pnpacpi_encode_resources(struct pnp_resource_table *res_table,
-	struct acpi_buffer *buffer)
+			     struct acpi_buffer *buffer)
 {
 	int i = 0;
 	/* pnpacpi_build_resource_template allocates extra mem */
-	int res_cnt = (buffer->length - 1)/sizeof(struct acpi_resource) - 1;
-	struct acpi_resource *resource = (struct acpi_resource*)buffer->pointer;
+	int res_cnt = (buffer->length - 1) / sizeof(struct acpi_resource) - 1;
+	struct acpi_resource *resource = buffer->pointer;
 	int port = 0, irq = 0, dma = 0, mem = 0;
 
 	pnp_dbg("res cnt %d", res_cnt);
 	while (i < res_cnt) {
-		switch(resource->type) {
+		switch (resource->type) {
 		case ACPI_RESOURCE_TYPE_IRQ:
 			pnp_dbg("Encode irq");
 			pnpacpi_encode_irq(resource,
-				&res_table->irq_resource[irq]);
+					   &res_table->irq_resource[irq]);
 			irq++;
 			break;
 
 		case ACPI_RESOURCE_TYPE_DMA:
 			pnp_dbg("Encode dma");
 			pnpacpi_encode_dma(resource,
-				&res_table->dma_resource[dma]);
+					   &res_table->dma_resource[dma]);
 			dma++;
 			break;
 		case ACPI_RESOURCE_TYPE_IO:
 			pnp_dbg("Encode io");
 			pnpacpi_encode_io(resource,
-				&res_table->port_resource[port]);
+					  &res_table->port_resource[port]);
 			port++;
 			break;
 		case ACPI_RESOURCE_TYPE_FIXED_IO:
 			pnp_dbg("Encode fixed io");
 			pnpacpi_encode_fixed_io(resource,
-				&res_table->port_resource[port]);
+						&res_table->
+						port_resource[port]);
 			port++;
 			break;
 		case ACPI_RESOURCE_TYPE_MEMORY24:
 			pnp_dbg("Encode mem24");
 			pnpacpi_encode_mem24(resource,
-				&res_table->mem_resource[mem]);
+					     &res_table->mem_resource[mem]);
 			mem++;
 			break;
 		case ACPI_RESOURCE_TYPE_MEMORY32:
 			pnp_dbg("Encode mem32");
 			pnpacpi_encode_mem32(resource,
-				&res_table->mem_resource[mem]);
+					     &res_table->mem_resource[mem]);
 			mem++;
 			break;
 		case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
 			pnp_dbg("Encode fixed mem32");
 			pnpacpi_encode_fixed_mem32(resource,
-				&res_table->mem_resource[mem]);
+						   &res_table->
+						   mem_resource[mem]);
 			mem++;
 			break;
 		case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
 			pnp_dbg("Encode ext irq");
 			pnpacpi_encode_ext_irq(resource,
-				&res_table->irq_resource[irq]);
+					       &res_table->irq_resource[irq]);
 			irq++;
 			break;
 		case ACPI_RESOURCE_TYPE_START_DEPENDENT:
@@ -956,7 +948,7 @@
 		case ACPI_RESOURCE_TYPE_ADDRESS64:
 		case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
 		case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
-		default: /* other type */
+		default:	/* other type */
 			pnp_warn("unknown resource type %d", resource->type);
 			return -EINVAL;
 		}
diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c
index a1f0b0b..5dba68f 100644
--- a/drivers/pnp/pnpbios/bioscalls.c
+++ b/drivers/pnp/pnpbios/bioscalls.c
@@ -1,6 +1,5 @@
 /*
  * bioscalls.c - the lowlevel layer of the PnPBIOS driver
- *
  */
 
 #include <linux/types.h>
@@ -26,11 +25,10 @@
 #include "pnpbios.h"
 
 static struct {
-	u16	offset;
-	u16	segment;
+	u16 offset;
+	u16 segment;
 } pnp_bios_callpoint;
 
-
 /*
  * These are some opcodes for a "static asmlinkage"
  * As this code is *not* executed inside the linux kernel segment, but in a
@@ -44,8 +42,7 @@
 
 asmlinkage void pnp_bios_callfunc(void);
 
-__asm__(
-	".text			\n"
+__asm__(".text			\n"
 	__ALIGN_STR "\n"
 	"pnp_bios_callfunc:\n"
 	"	pushl %edx	\n"
@@ -55,8 +52,7 @@
 	"	lcallw *pnp_bios_callpoint\n"
 	"	addl $16, %esp	\n"
 	"	lret		\n"
-	".previous		\n"
-);
+	".previous		\n");
 
 #define Q2_SET_SEL(cpu, selname, address, size) \
 do { \
@@ -78,7 +74,6 @@
 
 static spinlock_t pnp_bios_lock;
 
-
 /*
  * Support Functions
  */
@@ -97,7 +92,7 @@
 	 * PnP BIOSes are generally not terribly re-entrant.
 	 * Also, don't rely on them to save everything correctly.
 	 */
-	if(pnp_bios_is_utter_crap)
+	if (pnp_bios_is_utter_crap)
 		return PNP_FUNCTION_NOT_SUPPORTED;
 
 	cpu = get_cpu();
@@ -113,112 +108,128 @@
 	if (ts2_size)
 		Q2_SET_SEL(smp_processor_id(), PNP_TS2, ts2_base, ts2_size);
 
-	__asm__ __volatile__(
-	        "pushl %%ebp\n\t"
-		"pushl %%edi\n\t"
-		"pushl %%esi\n\t"
-		"pushl %%ds\n\t"
-		"pushl %%es\n\t"
-		"pushl %%fs\n\t"
-		"pushl %%gs\n\t"
-		"pushfl\n\t"
-		"movl %%esp, pnp_bios_fault_esp\n\t"
-		"movl $1f, pnp_bios_fault_eip\n\t"
-		"lcall %5,%6\n\t"
-		"1:popfl\n\t"
-		"popl %%gs\n\t"
-		"popl %%fs\n\t"
-		"popl %%es\n\t"
-		"popl %%ds\n\t"
-	        "popl %%esi\n\t"
-		"popl %%edi\n\t"
-		"popl %%ebp\n\t"
-		: "=a" (status)
-		: "0" ((func) | (((u32)arg1) << 16)),
-		  "b" ((arg2) | (((u32)arg3) << 16)),
-		  "c" ((arg4) | (((u32)arg5) << 16)),
-		  "d" ((arg6) | (((u32)arg7) << 16)),
-		  "i" (PNP_CS32),
-		  "i" (0)
-		: "memory"
-	);
+	__asm__ __volatile__("pushl %%ebp\n\t"
+			     "pushl %%edi\n\t"
+			     "pushl %%esi\n\t"
+			     "pushl %%ds\n\t"
+			     "pushl %%es\n\t"
+			     "pushl %%fs\n\t"
+			     "pushl %%gs\n\t"
+			     "pushfl\n\t"
+			     "movl %%esp, pnp_bios_fault_esp\n\t"
+			     "movl $1f, pnp_bios_fault_eip\n\t"
+			     "lcall %5,%6\n\t"
+			     "1:popfl\n\t"
+			     "popl %%gs\n\t"
+			     "popl %%fs\n\t"
+			     "popl %%es\n\t"
+			     "popl %%ds\n\t"
+			     "popl %%esi\n\t"
+			     "popl %%edi\n\t"
+			     "popl %%ebp\n\t":"=a"(status)
+			     :"0"((func) | (((u32) arg1) << 16)),
+			     "b"((arg2) | (((u32) arg3) << 16)),
+			     "c"((arg4) | (((u32) arg5) << 16)),
+			     "d"((arg6) | (((u32) arg7) << 16)),
+			     "i"(PNP_CS32), "i"(0)
+			     :"memory");
 	spin_unlock_irqrestore(&pnp_bios_lock, flags);
 
 	get_cpu_gdt_table(cpu)[0x40 / 8] = save_desc_40;
 	put_cpu();
 
 	/* If we get here and this is set then the PnP BIOS faulted on us. */
-	if(pnp_bios_is_utter_crap)
-	{
-		printk(KERN_ERR "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue\n");
-		printk(KERN_ERR "PnPBIOS: You may need to reboot with the \"pnpbios=off\" option to operate stably\n");
-		printk(KERN_ERR "PnPBIOS: Check with your vendor for an updated BIOS\n");
+	if (pnp_bios_is_utter_crap) {
+		printk(KERN_ERR
+		       "PnPBIOS: Warning! Your PnP BIOS caused a fatal error. Attempting to continue\n");
+		printk(KERN_ERR
+		       "PnPBIOS: You may need to reboot with the \"pnpbios=off\" option to operate stably\n");
+		printk(KERN_ERR
+		       "PnPBIOS: Check with your vendor for an updated BIOS\n");
 	}
 
 	return status;
 }
 
-void pnpbios_print_status(const char * module, u16 status)
+void pnpbios_print_status(const char *module, u16 status)
 {
-	switch(status) {
+	switch (status) {
 	case PNP_SUCCESS:
 		printk(KERN_ERR "PnPBIOS: %s: function successful\n", module);
 		break;
 	case PNP_NOT_SET_STATICALLY:
-		printk(KERN_ERR "PnPBIOS: %s: unable to set static resources\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: unable to set static resources\n",
+		       module);
 		break;
 	case PNP_UNKNOWN_FUNCTION:
-		printk(KERN_ERR "PnPBIOS: %s: invalid function number passed\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: invalid function number passed\n",
+		       module);
 		break;
 	case PNP_FUNCTION_NOT_SUPPORTED:
-		printk(KERN_ERR "PnPBIOS: %s: function not supported on this system\n", module);
+		printk(KERN_ERR
+		       "PnPBIOS: %s: function not supported on this system\n",
+		       module);
 		break;
 	case PNP_INVALID_HANDLE:
 		printk(KERN_ERR "PnPBIOS: %s: invalid handle\n", module);
 		break;
 	case PNP_BAD_PARAMETER:
-		printk(KERN_ERR "PnPBIOS: %s: invalid parameters were passed\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: invalid parameters were passed\n",
+		       module);
 		break;
 	case PNP_SET_FAILED:
-		printk(KERN_ERR "PnPBIOS: %s: unable to set resources\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: unable to set resources\n",
+		       module);
 		break;
 	case PNP_EVENTS_NOT_PENDING:
 		printk(KERN_ERR "PnPBIOS: %s: no events are pending\n", module);
 		break;
 	case PNP_SYSTEM_NOT_DOCKED:
-		printk(KERN_ERR "PnPBIOS: %s: the system is not docked\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: the system is not docked\n",
+		       module);
 		break;
 	case PNP_NO_ISA_PNP_CARDS:
-		printk(KERN_ERR "PnPBIOS: %s: no isapnp cards are installed on this system\n", module);
+		printk(KERN_ERR
+		       "PnPBIOS: %s: no isapnp cards are installed on this system\n",
+		       module);
 		break;
 	case PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES:
-		printk(KERN_ERR "PnPBIOS: %s: cannot determine the capabilities of the docking station\n", module);
+		printk(KERN_ERR
+		       "PnPBIOS: %s: cannot determine the capabilities of the docking station\n",
+		       module);
 		break;
 	case PNP_CONFIG_CHANGE_FAILED_NO_BATTERY:
-		printk(KERN_ERR "PnPBIOS: %s: unable to undock, the system does not have a battery\n", module);
+		printk(KERN_ERR
+		       "PnPBIOS: %s: unable to undock, the system does not have a battery\n",
+		       module);
 		break;
 	case PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT:
-		printk(KERN_ERR "PnPBIOS: %s: could not dock due to resource conflicts\n", module);
+		printk(KERN_ERR
+		       "PnPBIOS: %s: could not dock due to resource conflicts\n",
+		       module);
 		break;
 	case PNP_BUFFER_TOO_SMALL:
-		printk(KERN_ERR "PnPBIOS: %s: the buffer passed is too small\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: the buffer passed is too small\n",
+		       module);
 		break;
 	case PNP_USE_ESCD_SUPPORT:
 		printk(KERN_ERR "PnPBIOS: %s: use ESCD instead\n", module);
 		break;
 	case PNP_MESSAGE_NOT_SUPPORTED:
-		printk(KERN_ERR "PnPBIOS: %s: the message is unsupported\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: the message is unsupported\n",
+		       module);
 		break;
 	case PNP_HARDWARE_ERROR:
-		printk(KERN_ERR "PnPBIOS: %s: a hardware failure has occured\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: a hardware failure has occured\n",
+		       module);
 		break;
 	default:
-		printk(KERN_ERR "PnPBIOS: %s: unexpected status 0x%x\n", module, status);
+		printk(KERN_ERR "PnPBIOS: %s: unexpected status 0x%x\n", module,
+		       status);
 		break;
 	}
 }
 
-
 /*
  * PnP BIOS Low Level Calls
  */
@@ -243,19 +254,22 @@
 static int __pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
 {
 	u16 status;
+
 	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
-	status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2, PNP_TS1, PNP_DS, 0, 0,
-			       data, sizeof(struct pnp_dev_node_info), NULL, 0);
+	status = call_pnp_bios(PNP_GET_NUM_SYS_DEV_NODES, 0, PNP_TS1, 2,
+			       PNP_TS1, PNP_DS, 0, 0, data,
+			       sizeof(struct pnp_dev_node_info), NULL, 0);
 	data->no_nodes &= 0xff;
 	return status;
 }
 
 int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
 {
-	int status = __pnp_bios_dev_node_info( data );
-	if ( status )
-		pnpbios_print_status( "dev_node_info", status );
+	int status = __pnp_bios_dev_node_info(data);
+
+	if (status)
+		pnpbios_print_status("dev_node_info", status);
 	return status;
 }
 
@@ -273,17 +287,20 @@
  *               or volatile current (0) config
  * Output: *nodenum=next node or 0xff if no more nodes
  */
-static int __pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
+static int __pnp_bios_get_dev_node(u8 *nodenum, char boot,
+				   struct pnp_bios_node *data)
 {
 	u16 status;
 	u16 tmp_nodenum;
+
 	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
-	if ( !boot && pnpbios_dont_use_current_config )
+	if (!boot && pnpbios_dont_use_current_config)
 		return PNP_FUNCTION_NOT_SUPPORTED;
 	tmp_nodenum = *nodenum;
-	status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2, boot ? 2 : 1, PNP_DS, 0,
-			       &tmp_nodenum, sizeof(tmp_nodenum), data, 65536);
+	status = call_pnp_bios(PNP_GET_SYS_DEV_NODE, 0, PNP_TS1, 0, PNP_TS2,
+			       boot ? 2 : 1, PNP_DS, 0, &tmp_nodenum,
+			       sizeof(tmp_nodenum), data, 65536);
 	*nodenum = tmp_nodenum;
 	return status;
 }
@@ -291,104 +308,66 @@
 int pnp_bios_get_dev_node(u8 *nodenum, char boot, struct pnp_bios_node *data)
 {
 	int status;
-	status =  __pnp_bios_get_dev_node( nodenum, boot, data );
-	if ( status )
-		pnpbios_print_status( "get_dev_node", status );
+
+	status = __pnp_bios_get_dev_node(nodenum, boot, data);
+	if (status)
+		pnpbios_print_status("get_dev_node", status);
 	return status;
 }
 
-
 /*
  * Call PnP BIOS with function 0x02, "set system device node"
  * Input: *nodenum = desired node, 
  *        boot = whether to set nonvolatile boot (!=0)
  *               or volatile current (0) config
  */
-static int __pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
+static int __pnp_bios_set_dev_node(u8 nodenum, char boot,
+				   struct pnp_bios_node *data)
 {
 	u16 status;
+
 	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
-	if ( !boot && pnpbios_dont_use_current_config )
+	if (!boot && pnpbios_dont_use_current_config)
 		return PNP_FUNCTION_NOT_SUPPORTED;
-	status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1, boot ? 2 : 1, PNP_DS, 0, 0,
-			       data, 65536, NULL, 0);
+	status = call_pnp_bios(PNP_SET_SYS_DEV_NODE, nodenum, 0, PNP_TS1,
+			       boot ? 2 : 1, PNP_DS, 0, 0, data, 65536, NULL,
+			       0);
 	return status;
 }
 
 int pnp_bios_set_dev_node(u8 nodenum, char boot, struct pnp_bios_node *data)
 {
 	int status;
-	status =  __pnp_bios_set_dev_node( nodenum, boot, data );
-	if ( status ) {
-		pnpbios_print_status( "set_dev_node", status );
+
+	status = __pnp_bios_set_dev_node(nodenum, boot, data);
+	if (status) {
+		pnpbios_print_status("set_dev_node", status);
 		return status;
 	}
-	if ( !boot ) { /* Update devlist */
-		status =  pnp_bios_get_dev_node( &nodenum, boot, data );
-		if ( status )
+	if (!boot) {		/* Update devlist */
+		status = pnp_bios_get_dev_node(&nodenum, boot, data);
+		if (status)
 			return status;
 	}
 	return status;
 }
 
-#if needed
-/*
- * Call PnP BIOS with function 0x03, "get event"
- */
-static int pnp_bios_get_event(u16 *event)
-{
-	u16 status;
-	if (!pnp_bios_present())
-		return PNP_FUNCTION_NOT_SUPPORTED;
-	status = call_pnp_bios(PNP_GET_EVENT, 0, PNP_TS1, PNP_DS, 0, 0 ,0 ,0,
-			       event, sizeof(u16), NULL, 0);
-	return status;
-}
-#endif
-
-#if needed
-/*
- * Call PnP BIOS with function 0x04, "send message"
- */
-static int pnp_bios_send_message(u16 message)
-{
-	u16 status;
-	if (!pnp_bios_present())
-		return PNP_FUNCTION_NOT_SUPPORTED;
-	status = call_pnp_bios(PNP_SEND_MESSAGE, message, PNP_DS, 0, 0, 0, 0, 0, 0, 0, 0, 0);
-	return status;
-}
-#endif
-
 /*
  * Call PnP BIOS with function 0x05, "get docking station information"
  */
 int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
 {
 	u16 status;
-	if (!pnp_bios_present())
-		return PNP_FUNCTION_NOT_SUPPORTED;
-	status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
-			       data, sizeof(struct pnp_docking_station_info), NULL, 0);
-	return status;
-}
 
-#if needed
-/*
- * Call PnP BIOS with function 0x09, "set statically allocated resource
- * information"
- */
-static int pnp_bios_set_stat_res(char *info)
-{
-	u16 status;
 	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
-	status = call_pnp_bios(PNP_SET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
-			       info, *((u16 *) info), 0, 0);
+	status = call_pnp_bios(PNP_GET_DOCKING_STATION_INFORMATION, 0, PNP_TS1,
+			       PNP_DS, 0, 0, 0, 0, data,
+			       sizeof(struct pnp_docking_station_info), NULL,
+			       0);
 	return status;
 }
-#endif
 
 /*
  * Call PnP BIOS with function 0x0a, "get statically allocated resource
@@ -397,36 +376,23 @@
 static int __pnp_bios_get_stat_res(char *info)
 {
 	u16 status;
+
 	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
-	status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
-			       info, 65536, NULL, 0);
+	status = call_pnp_bios(PNP_GET_STATIC_ALLOCED_RES_INFO, 0, PNP_TS1,
+			       PNP_DS, 0, 0, 0, 0, info, 65536, NULL, 0);
 	return status;
 }
 
 int pnp_bios_get_stat_res(char *info)
 {
 	int status;
-	status = __pnp_bios_get_stat_res( info );
-	if ( status )
-		pnpbios_print_status( "get_stat_res", status );
-	return status;
-}
 
-#if needed
-/*
- * Call PnP BIOS with function 0x0b, "get APM id table"
- */
-static int pnp_bios_apm_id_table(char *table, u16 *size)
-{
-	u16 status;
-	if (!pnp_bios_present())
-		return PNP_FUNCTION_NOT_SUPPORTED;
-	status = call_pnp_bios(PNP_GET_APM_ID_TABLE, 0, PNP_TS2, 0, PNP_TS1, PNP_DS, 0, 0,
-			       table, *size, size, sizeof(u16));
+	status = __pnp_bios_get_stat_res(info);
+	if (status)
+		pnpbios_print_status("get_stat_res", status);
 	return status;
 }
-#endif
 
 /*
  * Call PnP BIOS with function 0x40, "get isa pnp configuration structure"
@@ -434,19 +400,22 @@
 static int __pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
 {
 	u16 status;
+
 	if (!pnp_bios_present())
 		return PNP_FUNCTION_NOT_SUPPORTED;
-	status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS, 0, 0, 0, 0,
-			       data, sizeof(struct pnp_isa_config_struc), NULL, 0);
+	status = call_pnp_bios(PNP_GET_PNP_ISA_CONFIG_STRUC, 0, PNP_TS1, PNP_DS,
+			       0, 0, 0, 0, data,
+			       sizeof(struct pnp_isa_config_struc), NULL, 0);
 	return status;
 }
 
 int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
 {
 	int status;
-	status = __pnp_bios_isapnp_config( data );
-	if ( status )
-		pnpbios_print_status( "isapnp_config", status );
+
+	status = __pnp_bios_isapnp_config(data);
+	if (status)
+		pnpbios_print_status("isapnp_config", status);
 	return status;
 }
 
@@ -456,19 +425,22 @@
 static int __pnp_bios_escd_info(struct escd_info_struc *data)
 {
 	u16 status;
+
 	if (!pnp_bios_present())
 		return ESCD_FUNCTION_NOT_SUPPORTED;
-	status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4, PNP_TS1, PNP_DS,
-			       data, sizeof(struct escd_info_struc), NULL, 0);
+	status = call_pnp_bios(PNP_GET_ESCD_INFO, 0, PNP_TS1, 2, PNP_TS1, 4,
+			       PNP_TS1, PNP_DS, data,
+			       sizeof(struct escd_info_struc), NULL, 0);
 	return status;
 }
 
 int pnp_bios_escd_info(struct escd_info_struc *data)
 {
 	int status;
-	status = __pnp_bios_escd_info( data );
-	if ( status )
-		pnpbios_print_status( "escd_info", status );
+
+	status = __pnp_bios_escd_info(data);
+	if (status)
+		pnpbios_print_status("escd_info", status);
 	return status;
 }
 
@@ -479,57 +451,42 @@
 static int __pnp_bios_read_escd(char *data, u32 nvram_base)
 {
 	u16 status;
+
 	if (!pnp_bios_present())
 		return ESCD_FUNCTION_NOT_SUPPORTED;
-	status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0,
-			       data, 65536, __va(nvram_base), 65536);
+	status = call_pnp_bios(PNP_READ_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0,
+			       0, data, 65536, __va(nvram_base), 65536);
 	return status;
 }
 
 int pnp_bios_read_escd(char *data, u32 nvram_base)
 {
 	int status;
-	status = __pnp_bios_read_escd( data, nvram_base );
-	if ( status )
-		pnpbios_print_status( "read_escd", status );
+
+	status = __pnp_bios_read_escd(data, nvram_base);
+	if (status)
+		pnpbios_print_status("read_escd", status);
 	return status;
 }
 
-#if needed
-/*
- * Call PnP BIOS function 0x43, "write ESCD"
- */
-static int pnp_bios_write_escd(char *data, u32 nvram_base)
-{
-	u16 status;
-	if (!pnp_bios_present())
-		return ESCD_FUNCTION_NOT_SUPPORTED;
-	status = call_pnp_bios(PNP_WRITE_ESCD, 0, PNP_TS1, PNP_TS2, PNP_DS, 0, 0, 0,
-			       data, 65536, __va(nvram_base), 65536);
-	return status;
-}
-#endif
-
-
-/*
- * Initialization
- */
-
 void pnpbios_calls_init(union pnp_bios_install_struct *header)
 {
 	int i;
+
 	spin_lock_init(&pnp_bios_lock);
 	pnp_bios_callpoint.offset = header->fields.pm16offset;
 	pnp_bios_callpoint.segment = PNP_CS16;
 
 	set_base(bad_bios_desc, __va((unsigned long)0x40 << 4));
 	_set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4));
- 	for (i = 0; i < NR_CPUS; i++) {
-  		struct desc_struct *gdt = get_cpu_gdt_table(i);
-  		if (!gdt)
-  			continue;
- 		set_base(gdt[GDT_ENTRY_PNPBIOS_CS32], &pnp_bios_callfunc);
- 		set_base(gdt[GDT_ENTRY_PNPBIOS_CS16], __va(header->fields.pm16cseg));
- 		set_base(gdt[GDT_ENTRY_PNPBIOS_DS], __va(header->fields.pm16dseg));
-  	}
+	for (i = 0; i < NR_CPUS; i++) {
+		struct desc_struct *gdt = get_cpu_gdt_table(i);
+		if (!gdt)
+			continue;
+		set_base(gdt[GDT_ENTRY_PNPBIOS_CS32], &pnp_bios_callfunc);
+		set_base(gdt[GDT_ENTRY_PNPBIOS_CS16],
+			 __va(header->fields.pm16cseg));
+		set_base(gdt[GDT_ENTRY_PNPBIOS_DS],
+			 __va(header->fields.pm16dseg));
+	}
 }
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 03baf1c..4e9fd37 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -32,7 +32,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
- 
+
 /* Change Log
  *
  * Adam Belay - <ambx1@neo.rr.com> - March 16, 2003
@@ -71,14 +71,13 @@
 
 #include "pnpbios.h"
 
-
 /*
  *
  * PnP BIOS INTERFACE
  *
  */
 
-static union pnp_bios_install_struct * pnp_bios_install = NULL;
+static union pnp_bios_install_struct *pnp_bios_install = NULL;
 
 int pnp_bios_present(void)
 {
@@ -101,36 +100,35 @@
 /*
  * (Much of this belongs in a shared routine somewhere)
  */
- 
 static int pnp_dock_event(int dock, struct pnp_docking_station_info *info)
 {
-	char *argv [3], **envp, *buf, *scratch;
+	char *argv[3], **envp, *buf, *scratch;
 	int i = 0, value;
 
-	if (!current->fs->root) {
+	if (!current->fs->root)
 		return -EAGAIN;
-	}
-	if (!(envp = kcalloc(20, sizeof (char *), GFP_KERNEL))) {
+	if (!(envp = kcalloc(20, sizeof(char *), GFP_KERNEL)))
 		return -ENOMEM;
-	}
 	if (!(buf = kzalloc(256, GFP_KERNEL))) {
-		kfree (envp);
+		kfree(envp);
 		return -ENOMEM;
 	}
 
-	/* FIXME: if there are actual users of this, it should be integrated into
-	 * the driver core and use the usual infrastructure like sysfs and uevents */
-	argv [0] = "/sbin/pnpbios";
-	argv [1] = "dock";
-	argv [2] = NULL;
+	/* FIXME: if there are actual users of this, it should be
+	 * integrated into the driver core and use the usual infrastructure
+	 * like sysfs and uevents
+	 */
+	argv[0] = "/sbin/pnpbios";
+	argv[1] = "dock";
+	argv[2] = NULL;
 
 	/* minimal command environment */
-	envp [i++] = "HOME=/";
-	envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+	envp[i++] = "HOME=/";
+	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
 
 #ifdef	DEBUG
 	/* hint that policy agent should enter no-stdout debug mode */
-	envp [i++] = "DEBUG=kernel";
+	envp[i++] = "DEBUG=kernel";
 #endif
 	/* extensible set of named bus-specific parameters,
 	 * supporting multiple driver selection algorithms.
@@ -138,33 +136,33 @@
 	scratch = buf;
 
 	/* action:  add, remove */
-	envp [i++] = scratch;
-	scratch += sprintf (scratch, "ACTION=%s", dock?"add":"remove") + 1;
+	envp[i++] = scratch;
+	scratch += sprintf(scratch, "ACTION=%s", dock ? "add" : "remove") + 1;
 
 	/* Report the ident for the dock */
-	envp [i++] = scratch;
-	scratch += sprintf (scratch, "DOCK=%x/%x/%x",
-		info->location_id, info->serial, info->capabilities);
+	envp[i++] = scratch;
+	scratch += sprintf(scratch, "DOCK=%x/%x/%x",
+			   info->location_id, info->serial, info->capabilities);
 	envp[i] = NULL;
-	
-	value = call_usermodehelper (argv [0], argv, envp, 0);
-	kfree (buf);
-	kfree (envp);
+
+	value = call_usermodehelper(argv [0], argv, envp, UMH_WAIT_EXEC);
+	kfree(buf);
+	kfree(envp);
 	return 0;
 }
 
 /*
  * Poll the PnP docking at regular intervals
  */
-static int pnp_dock_thread(void * unused)
+static int pnp_dock_thread(void *unused)
 {
 	static struct pnp_docking_station_info now;
 	int docked = -1, d = 0;
+
 	set_freezable();
-	while (!unloading)
-	{
+	while (!unloading) {
 		int status;
-		
+
 		/*
 		 * Poll every 2 seconds
 		 */
@@ -175,30 +173,29 @@
 
 		status = pnp_bios_dock_station_info(&now);
 
-		switch(status)
-		{
+		switch (status) {
 			/*
 			 * No dock to manage
 			 */
-			case PNP_FUNCTION_NOT_SUPPORTED:
-				complete_and_exit(&unload_sem, 0);
-			case PNP_SYSTEM_NOT_DOCKED:
-				d = 0;
-				break;
-			case PNP_SUCCESS:
-				d = 1;
-				break;
-			default:
-				pnpbios_print_status( "pnp_dock_thread", status );
-				continue;
+		case PNP_FUNCTION_NOT_SUPPORTED:
+			complete_and_exit(&unload_sem, 0);
+		case PNP_SYSTEM_NOT_DOCKED:
+			d = 0;
+			break;
+		case PNP_SUCCESS:
+			d = 1;
+			break;
+		default:
+			pnpbios_print_status("pnp_dock_thread", status);
+			continue;
 		}
-		if(d != docked)
-		{
-			if(pnp_dock_event(d, &now)==0)
-			{
+		if (d != docked) {
+			if (pnp_dock_event(d, &now) == 0) {
 				docked = d;
 #if 0
-				printk(KERN_INFO "PnPBIOS: Docking station %stached\n", docked?"at":"de");
+				printk(KERN_INFO
+				       "PnPBIOS: Docking station %stached\n",
+				       docked ? "at" : "de");
 #endif
 			}
 		}
@@ -206,21 +203,21 @@
 	complete_and_exit(&unload_sem, 0);
 }
 
-#endif   /* CONFIG_HOTPLUG */
+#endif				/* CONFIG_HOTPLUG */
 
-static int pnpbios_get_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
+static int pnpbios_get_resources(struct pnp_dev *dev,
+				 struct pnp_resource_table *res)
 {
 	u8 nodenum = dev->number;
-	struct pnp_bios_node * node;
+	struct pnp_bios_node *node;
 
-	/* just in case */
-	if(!pnpbios_is_dynamic(dev))
+	if (!pnpbios_is_dynamic(dev))
 		return -EPERM;
 
 	node = kzalloc(node_info.max_node_size, GFP_KERNEL);
 	if (!node)
 		return -1;
-	if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
+	if (pnp_bios_get_dev_node(&nodenum, (char)PNPMODE_DYNAMIC, node)) {
 		kfree(node);
 		return -ENODEV;
 	}
@@ -230,24 +227,24 @@
 	return 0;
 }
 
-static int pnpbios_set_resources(struct pnp_dev * dev, struct pnp_resource_table * res)
+static int pnpbios_set_resources(struct pnp_dev *dev,
+				 struct pnp_resource_table *res)
 {
 	u8 nodenum = dev->number;
-	struct pnp_bios_node * node;
+	struct pnp_bios_node *node;
 	int ret;
 
-	/* just in case */
 	if (!pnpbios_is_dynamic(dev))
 		return -EPERM;
 
 	node = kzalloc(node_info.max_node_size, GFP_KERNEL);
 	if (!node)
 		return -1;
-	if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
+	if (pnp_bios_get_dev_node(&nodenum, (char)PNPMODE_DYNAMIC, node)) {
 		kfree(node);
 		return -ENODEV;
 	}
-	if(pnpbios_write_resources_to_node(res, node)<0) {
+	if (pnpbios_write_resources_to_node(res, node) < 0) {
 		kfree(node);
 		return -1;
 	}
@@ -258,18 +255,19 @@
 	return ret;
 }
 
-static void pnpbios_zero_data_stream(struct pnp_bios_node * node)
+static void pnpbios_zero_data_stream(struct pnp_bios_node *node)
 {
-	unsigned char * p = (char *)node->data;
-	unsigned char * end = (char *)(node->data + node->size);
+	unsigned char *p = (char *)node->data;
+	unsigned char *end = (char *)(node->data + node->size);
 	unsigned int len;
 	int i;
+
 	while ((char *)p < (char *)end) {
-		if(p[0] & 0x80) { /* large tag */
+		if (p[0] & 0x80) {	/* large tag */
 			len = (p[2] << 8) | p[1];
 			p += 3;
 		} else {
-			if (((p[0]>>3) & 0x0f) == 0x0f)
+			if (((p[0] >> 3) & 0x0f) == 0x0f)
 				return;
 			len = p[0] & 0x07;
 			p += 1;
@@ -278,24 +276,24 @@
 			p[i] = 0;
 		p += len;
 	}
-	printk(KERN_ERR "PnPBIOS: Resource structure did not contain an end tag.\n");
+	printk(KERN_ERR
+	       "PnPBIOS: Resource structure did not contain an end tag.\n");
 }
 
 static int pnpbios_disable_resources(struct pnp_dev *dev)
 {
-	struct pnp_bios_node * node;
+	struct pnp_bios_node *node;
 	u8 nodenum = dev->number;
 	int ret;
 
-	/* just in case */
-	if(dev->flags & PNPBIOS_NO_DISABLE || !pnpbios_is_dynamic(dev))
+	if (dev->flags & PNPBIOS_NO_DISABLE || !pnpbios_is_dynamic(dev))
 		return -EPERM;
 
 	node = kzalloc(node_info.max_node_size, GFP_KERNEL);
 	if (!node)
 		return -ENOMEM;
 
-	if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node)) {
+	if (pnp_bios_get_dev_node(&nodenum, (char)PNPMODE_DYNAMIC, node)) {
 		kfree(node);
 		return -ENODEV;
 	}
@@ -311,22 +309,22 @@
 /* PnP Layer support */
 
 struct pnp_protocol pnpbios_protocol = {
-	.name	= "Plug and Play BIOS",
-	.get	= pnpbios_get_resources,
-	.set	= pnpbios_set_resources,
+	.name = "Plug and Play BIOS",
+	.get = pnpbios_get_resources,
+	.set = pnpbios_set_resources,
 	.disable = pnpbios_disable_resources,
 };
 
-static int insert_device(struct pnp_dev *dev, struct pnp_bios_node * node)
+static int insert_device(struct pnp_dev *dev, struct pnp_bios_node *node)
 {
-	struct list_head * pos;
-	struct pnp_dev * pnp_dev;
+	struct list_head *pos;
+	struct pnp_dev *pnp_dev;
 	struct pnp_id *dev_id;
 	char id[8];
 
 	/* check if the device is already added */
 	dev->number = node->handle;
-	list_for_each (pos, &pnpbios_protocol.devices){
+	list_for_each(pos, &pnpbios_protocol.devices) {
 		pnp_dev = list_entry(pos, struct pnp_dev, protocol_list);
 		if (dev->number == pnp_dev->number)
 			return -1;
@@ -336,8 +334,8 @@
 	dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
 	if (!dev_id)
 		return -1;
-	pnpid32_to_pnpid(node->eisa_id,id);
-	memcpy(dev_id->id,id,7);
+	pnpid32_to_pnpid(node->eisa_id, id);
+	memcpy(dev_id->id, id, 7);
 	pnp_add_id(dev_id, dev);
 	pnpbios_parse_data_stream(dev, node);
 	dev->active = pnp_is_active(dev);
@@ -375,35 +373,41 @@
 	if (!node)
 		return;
 
-	for(nodenum=0; nodenum<0xff; ) {
+	for (nodenum = 0; nodenum < 0xff;) {
 		u8 thisnodenum = nodenum;
 		/* eventually we will want to use PNPMODE_STATIC here but for now
 		 * dynamic will help us catch buggy bioses to add to the blacklist.
 		 */
 		if (!pnpbios_dont_use_current_config) {
-			if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_DYNAMIC, node))
+			if (pnp_bios_get_dev_node
+			    (&nodenum, (char)PNPMODE_DYNAMIC, node))
 				break;
 		} else {
-			if (pnp_bios_get_dev_node(&nodenum, (char )PNPMODE_STATIC, node))
+			if (pnp_bios_get_dev_node
+			    (&nodenum, (char)PNPMODE_STATIC, node))
 				break;
 		}
 		nodes_got++;
-		dev =  kzalloc(sizeof (struct pnp_dev), GFP_KERNEL);
+		dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
 		if (!dev)
 			break;
-		if(insert_device(dev,node)<0)
+		if (insert_device(dev, node) < 0)
 			kfree(dev);
 		else
 			devs++;
 		if (nodenum <= thisnodenum) {
-			printk(KERN_ERR "PnPBIOS: build_devlist: Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", (unsigned int)nodenum, (unsigned int)thisnodenum);
+			printk(KERN_ERR
+			       "PnPBIOS: build_devlist: Node number 0x%x is out of sequence following node 0x%x. Aborting.\n",
+			       (unsigned int)nodenum,
+			       (unsigned int)thisnodenum);
 			break;
 		}
 	}
 	kfree(node);
 
-	printk(KERN_INFO "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver\n",
-		nodes_got, nodes_got != 1 ? "s" : "", devs);
+	printk(KERN_INFO
+	       "PnPBIOS: %i node%s reported by PnP BIOS; %i recorded by driver\n",
+	       nodes_got, nodes_got != 1 ? "s" : "", devs);
 }
 
 /*
@@ -412,19 +416,18 @@
  *
  */
 
-static int pnpbios_disabled; /* = 0 */
-int pnpbios_dont_use_current_config; /* = 0 */
+static int pnpbios_disabled;
+int pnpbios_dont_use_current_config;
 
-#ifndef MODULE
 static int __init pnpbios_setup(char *str)
 {
 	int invert;
 
 	while ((str != NULL) && (*str != '\0')) {
 		if (strncmp(str, "off", 3) == 0)
-			pnpbios_disabled=1;
+			pnpbios_disabled = 1;
 		if (strncmp(str, "on", 2) == 0)
-			pnpbios_disabled=0;
+			pnpbios_disabled = 0;
 		invert = (strncmp(str, "no-", 3) == 0);
 		if (invert)
 			str += 3;
@@ -439,7 +442,6 @@
 }
 
 __setup("pnpbios=", pnpbios_setup);
-#endif
 
 /* PnP BIOS signature: "$PnP" */
 #define PNP_SIGNATURE   (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24))
@@ -453,35 +455,41 @@
 	printk(KERN_INFO "PnPBIOS: Scanning system for PnP BIOS support...\n");
 
 	/*
- 	 * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS
+	 * Search the defined area (0xf0000-0xffff0) for a valid PnP BIOS
 	 * structure and, if one is found, sets up the selectors and
 	 * entry points
 	 */
-	for (check = (union pnp_bios_install_struct *) __va(0xf0000);
-	     check < (union pnp_bios_install_struct *) __va(0xffff0);
+	for (check = (union pnp_bios_install_struct *)__va(0xf0000);
+	     check < (union pnp_bios_install_struct *)__va(0xffff0);
 	     check = (void *)check + 16) {
 		if (check->fields.signature != PNP_SIGNATURE)
 			continue;
-		printk(KERN_INFO "PnPBIOS: Found PnP BIOS installation structure at 0x%p\n", check);
+		printk(KERN_INFO
+		       "PnPBIOS: Found PnP BIOS installation structure at 0x%p\n",
+		       check);
 		length = check->fields.length;
 		if (!length) {
-			printk(KERN_ERR "PnPBIOS: installation structure is invalid, skipping\n");
+			printk(KERN_ERR
+			       "PnPBIOS: installation structure is invalid, skipping\n");
 			continue;
 		}
 		for (sum = 0, i = 0; i < length; i++)
 			sum += check->chars[i];
 		if (sum) {
-			printk(KERN_ERR "PnPBIOS: installation structure is corrupted, skipping\n");
+			printk(KERN_ERR
+			       "PnPBIOS: installation structure is corrupted, skipping\n");
 			continue;
 		}
 		if (check->fields.version < 0x10) {
-			printk(KERN_WARNING "PnPBIOS: PnP BIOS version %d.%d is not supported\n",
+			printk(KERN_WARNING
+			       "PnPBIOS: PnP BIOS version %d.%d is not supported\n",
 			       check->fields.version >> 4,
 			       check->fields.version & 15);
 			continue;
 		}
-		printk(KERN_INFO "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x\n",
-                       check->fields.version >> 4, check->fields.version & 15,
+		printk(KERN_INFO
+		       "PnPBIOS: PnP BIOS version %d.%d, entry 0x%x:0x%x, dseg 0x%x\n",
+		       check->fields.version >> 4, check->fields.version & 15,
 		       check->fields.pm16cseg, check->fields.pm16offset,
 		       check->fields.pm16dseg);
 		pnp_bios_install = check;
@@ -492,32 +500,32 @@
 	return 0;
 }
 
-static int __init exploding_pnp_bios(struct dmi_system_id *d)
+static int __init exploding_pnp_bios(const struct dmi_system_id *d)
 {
 	printk(KERN_WARNING "%s detected. Disabling PnPBIOS\n", d->ident);
 	return 0;
 }
 
 static struct dmi_system_id pnpbios_dmi_table[] __initdata = {
-	{	/* PnPBIOS GPF on boot */
-		.callback = exploding_pnp_bios,
-		.ident = "Higraded P14H",
-		.matches = {
-			DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
-			DMI_MATCH(DMI_BIOS_VERSION, "07.00T"),
-			DMI_MATCH(DMI_SYS_VENDOR, "Higraded"),
-			DMI_MATCH(DMI_PRODUCT_NAME, "P14H"),
-		},
-	},
-	{	/* PnPBIOS GPF on boot */
-		.callback = exploding_pnp_bios,
-		.ident = "ASUS P4P800",
-		.matches = {
-			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
-			DMI_MATCH(DMI_BOARD_NAME, "P4P800"),
-		},
-	},
-	{ }
+	{			/* PnPBIOS GPF on boot */
+	 .callback = exploding_pnp_bios,
+	 .ident = "Higraded P14H",
+	 .matches = {
+		     DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
+		     DMI_MATCH(DMI_BIOS_VERSION, "07.00T"),
+		     DMI_MATCH(DMI_SYS_VENDOR, "Higraded"),
+		     DMI_MATCH(DMI_PRODUCT_NAME, "P14H"),
+		     },
+	 },
+	{			/* PnPBIOS GPF on boot */
+	 .callback = exploding_pnp_bios,
+	 .ident = "ASUS P4P800",
+	 .matches = {
+		     DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc."),
+		     DMI_MATCH(DMI_BOARD_NAME, "P4P800"),
+		     },
+	 },
+	{}
 };
 
 static int __init pnpbios_init(void)
@@ -533,14 +541,13 @@
 		printk(KERN_INFO "PnPBIOS: Disabled\n");
 		return -ENODEV;
 	}
-
 #ifdef CONFIG_PNPACPI
 	if (!acpi_disabled && !pnpacpi_disabled) {
 		pnpbios_disabled = 1;
 		printk(KERN_INFO "PnPBIOS: Disabled by ACPI PNP\n");
 		return -ENODEV;
 	}
-#endif /* CONFIG_ACPI */
+#endif				/* CONFIG_ACPI */
 
 	/* scan the system for pnpbios support */
 	if (!pnpbios_probe_system())
@@ -552,14 +559,16 @@
 	/* read the node info */
 	ret = pnp_bios_dev_node_info(&node_info);
 	if (ret) {
-		printk(KERN_ERR "PnPBIOS: Unable to get node info.  Aborting.\n");
+		printk(KERN_ERR
+		       "PnPBIOS: Unable to get node info.  Aborting.\n");
 		return ret;
 	}
 
 	/* register with the pnp layer */
 	ret = pnp_register_protocol(&pnpbios_protocol);
 	if (ret) {
-		printk(KERN_ERR "PnPBIOS: Unable to register driver.  Aborting.\n");
+		printk(KERN_ERR
+		       "PnPBIOS: Unable to register driver.  Aborting.\n");
 		return ret;
 	}
 
@@ -580,6 +589,7 @@
 static int __init pnpbios_thread_init(void)
 {
 	struct task_struct *task;
+
 #if defined(CONFIG_PPC_MERGE)
 	if (check_legacy_ioport(PNPBIOS_BASE))
 		return 0;
@@ -595,48 +605,7 @@
 	return 0;
 }
 
-#ifndef MODULE
-
-/* init/main.c calls pnpbios_init early */
-
 /* Start the kernel thread later: */
 module_init(pnpbios_thread_init);
 
-#else
-
-/*
- * N.B.: Building pnpbios as a module hasn't been fully implemented
- */
-
-MODULE_LICENSE("GPL");
-
-static int __init pnpbios_init_all(void)
-{
-	int r;
-
-	r = pnpbios_init();
-	if (r)
-		return r;
-	r = pnpbios_thread_init();
-	if (r)
-		return r;
-	return 0;
-}
-
-static void __exit pnpbios_exit(void)
-{
-#ifdef CONFIG_HOTPLUG
-	unloading = 1;
-	wait_for_completion(&unload_sem);
-#endif
-	pnpbios_proc_exit();
-	/* We ought to free resources here */
-	return;
-}
-
-module_init(pnpbios_init_all);
-module_exit(pnpbios_exit);
-
-#endif
-
 EXPORT_SYMBOL(pnpbios_protocol);
diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c
index 8027073..9d9841f 100644
--- a/drivers/pnp/pnpbios/proc.c
+++ b/drivers/pnp/pnpbios/proc.c
@@ -18,9 +18,6 @@
  * The other files are human-readable.
  */
 
-//#include <pcmcia/config.h>
-//#include <pcmcia/k_compat.h>
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -37,42 +34,37 @@
 static struct proc_dir_entry *proc_pnp_boot = NULL;
 
 static int proc_read_pnpconfig(char *buf, char **start, off_t pos,
-                               int count, int *eof, void *data)
+			       int count, int *eof, void *data)
 {
 	struct pnp_isa_config_struc pnps;
 
 	if (pnp_bios_isapnp_config(&pnps))
 		return -EIO;
 	return snprintf(buf, count,
-		"structure_revision %d\n"
-		"number_of_CSNs %d\n"
-		"ISA_read_data_port 0x%x\n",
-		pnps.revision,
-		pnps.no_csns,
-		pnps.isa_rd_data_port
-	);
+			"structure_revision %d\n"
+			"number_of_CSNs %d\n"
+			"ISA_read_data_port 0x%x\n",
+			pnps.revision, pnps.no_csns, pnps.isa_rd_data_port);
 }
 
 static int proc_read_escdinfo(char *buf, char **start, off_t pos,
-                              int count, int *eof, void *data)
+			      int count, int *eof, void *data)
 {
 	struct escd_info_struc escd;
 
 	if (pnp_bios_escd_info(&escd))
 		return -EIO;
 	return snprintf(buf, count,
-		"min_ESCD_write_size %d\n"
-		"ESCD_size %d\n"
-		"NVRAM_base 0x%x\n",
-		escd.min_escd_write_size,
-		escd.escd_size,
-		escd.nv_storage_base
-	);
+			"min_ESCD_write_size %d\n"
+			"ESCD_size %d\n"
+			"NVRAM_base 0x%x\n",
+			escd.min_escd_write_size,
+			escd.escd_size, escd.nv_storage_base);
 }
 
 #define MAX_SANE_ESCD_SIZE (32*1024)
 static int proc_read_escd(char *buf, char **start, off_t pos,
-                          int count, int *eof, void *data)
+			  int count, int *eof, void *data)
 {
 	struct escd_info_struc escd;
 	char *tmpbuf;
@@ -83,30 +75,36 @@
 
 	/* sanity check */
 	if (escd.escd_size > MAX_SANE_ESCD_SIZE) {
-		printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size reported by BIOS escd_info call is too great\n");
+		printk(KERN_ERR
+		       "PnPBIOS: proc_read_escd: ESCD size reported by BIOS escd_info call is too great\n");
 		return -EFBIG;
 	}
 
 	tmpbuf = kzalloc(escd.escd_size, GFP_KERNEL);
-	if (!tmpbuf) return -ENOMEM;
+	if (!tmpbuf)
+		return -ENOMEM;
 
 	if (pnp_bios_read_escd(tmpbuf, escd.nv_storage_base)) {
 		kfree(tmpbuf);
 		return -EIO;
 	}
 
-	escd_size = (unsigned char)(tmpbuf[0]) + (unsigned char)(tmpbuf[1])*256;
+	escd_size =
+	    (unsigned char)(tmpbuf[0]) + (unsigned char)(tmpbuf[1]) * 256;
 
 	/* sanity check */
 	if (escd_size > MAX_SANE_ESCD_SIZE) {
-		printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size reported by BIOS read_escd call is too great\n");
+		printk(KERN_ERR
+		       "PnPBIOS: proc_read_escd: ESCD size reported by BIOS read_escd call is too great\n");
 		return -EFBIG;
 	}
 
 	escd_left_to_read = escd_size - pos;
-	if (escd_left_to_read < 0) escd_left_to_read = 0;
-	if (escd_left_to_read == 0) *eof = 1;
-	n = min(count,escd_left_to_read);
+	if (escd_left_to_read < 0)
+		escd_left_to_read = 0;
+	if (escd_left_to_read == 0)
+		*eof = 1;
+	n = min(count, escd_left_to_read);
 	memcpy(buf, tmpbuf + pos, n);
 	kfree(tmpbuf);
 	*start = buf;
@@ -114,17 +112,17 @@
 }
 
 static int proc_read_legacyres(char *buf, char **start, off_t pos,
-                               int count, int *eof, void *data)
+			       int count, int *eof, void *data)
 {
 	/* Assume that the following won't overflow the buffer */
-	if (pnp_bios_get_stat_res(buf)) 
+	if (pnp_bios_get_stat_res(buf))
 		return -EIO;
 
-	return count;  // FIXME: Return actual length
+	return count;		// FIXME: Return actual length
 }
 
 static int proc_read_devices(char *buf, char **start, off_t pos,
-                             int count, int *eof, void *data)
+			     int count, int *eof, void *data)
 {
 	struct pnp_bios_node *node;
 	u8 nodenum;
@@ -134,9 +132,10 @@
 		return 0;
 
 	node = kzalloc(node_info.max_node_size, GFP_KERNEL);
-	if (!node) return -ENOMEM;
+	if (!node)
+		return -ENOMEM;
 
-	for (nodenum=pos; nodenum<0xff; ) {
+	for (nodenum = pos; nodenum < 0xff;) {
 		u8 thisnodenum = nodenum;
 		/* 26 = the number of characters per line sprintf'ed */
 		if ((p - buf + 26) > count)
@@ -148,7 +147,11 @@
 			     node->type_code[0], node->type_code[1],
 			     node->type_code[2], node->flags);
 		if (nodenum <= thisnodenum) {
-			printk(KERN_ERR "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n", "PnPBIOS: proc_read_devices:", (unsigned int)nodenum, (unsigned int)thisnodenum);
+			printk(KERN_ERR
+			       "%s Node number 0x%x is out of sequence following node 0x%x. Aborting.\n",
+			       "PnPBIOS: proc_read_devices:",
+			       (unsigned int)nodenum,
+			       (unsigned int)thisnodenum);
 			*eof = 1;
 			break;
 		}
@@ -156,12 +159,12 @@
 	kfree(node);
 	if (nodenum == 0xff)
 		*eof = 1;
-	*start = (char *)((off_t)nodenum - pos);
+	*start = (char *)((off_t) nodenum - pos);
 	return p - buf;
 }
 
 static int proc_read_node(char *buf, char **start, off_t pos,
-                          int count, int *eof, void *data)
+			  int count, int *eof, void *data)
 {
 	struct pnp_bios_node *node;
 	int boot = (long)data >> 8;
@@ -169,7 +172,8 @@
 	int len;
 
 	node = kzalloc(node_info.max_node_size, GFP_KERNEL);
-	if (!node) return -ENOMEM;
+	if (!node)
+		return -ENOMEM;
 	if (pnp_bios_get_dev_node(&nodenum, boot, node)) {
 		kfree(node);
 		return -EIO;
@@ -180,8 +184,8 @@
 	return len;
 }
 
-static int proc_write_node(struct file *file, const char __user *buf,
-                           unsigned long count, void *data)
+static int proc_write_node(struct file *file, const char __user * buf,
+			   unsigned long count, void *data)
 {
 	struct pnp_bios_node *node;
 	int boot = (long)data >> 8;
@@ -213,7 +217,7 @@
 	return ret;
 }
 
-int pnpbios_interface_attach_device(struct pnp_bios_node * node)
+int pnpbios_interface_attach_device(struct pnp_bios_node *node)
 {
 	char name[3];
 	struct proc_dir_entry *ent;
@@ -222,7 +226,7 @@
 
 	if (!proc_pnp)
 		return -EIO;
-	if ( !pnpbios_dont_use_current_config ) {
+	if (!pnpbios_dont_use_current_config) {
 		ent = create_proc_entry(name, 0, proc_pnp);
 		if (ent) {
 			ent->read_proc = proc_read_node;
@@ -237,7 +241,7 @@
 	if (ent) {
 		ent->read_proc = proc_read_node;
 		ent->write_proc = proc_write_node;
-		ent->data = (void *)(long)(node->handle+0x100);
+		ent->data = (void *)(long)(node->handle + 0x100);
 		return 0;
 	}
 
@@ -249,7 +253,7 @@
  * work and the pnpbios_dont_use_current_config flag
  * should already have been set to the appropriate value
  */
-int __init pnpbios_proc_init( void )
+int __init pnpbios_proc_init(void)
 {
 	proc_pnp = proc_mkdir("pnp", proc_bus);
 	if (!proc_pnp)
@@ -258,10 +262,13 @@
 	if (!proc_pnp_boot)
 		return -EIO;
 	create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL);
-	create_proc_read_entry("configuration_info", 0, proc_pnp, proc_read_pnpconfig, NULL);
-	create_proc_read_entry("escd_info", 0, proc_pnp, proc_read_escdinfo, NULL);
+	create_proc_read_entry("configuration_info", 0, proc_pnp,
+			       proc_read_pnpconfig, NULL);
+	create_proc_read_entry("escd_info", 0, proc_pnp, proc_read_escdinfo,
+			       NULL);
 	create_proc_read_entry("escd", S_IRUSR, proc_pnp, proc_read_escd, NULL);
-	create_proc_read_entry("legacy_device_resources", 0, proc_pnp, proc_read_legacyres, NULL);
+	create_proc_read_entry("legacy_device_resources", 0, proc_pnp,
+			       proc_read_legacyres, NULL);
 
 	return 0;
 }
@@ -274,9 +281,9 @@
 	if (!proc_pnp)
 		return;
 
-	for (i=0; i<0xff; i++) {
+	for (i = 0; i < 0xff; i++) {
 		sprintf(name, "%02x", i);
-		if ( !pnpbios_dont_use_current_config )
+		if (!pnpbios_dont_use_current_config)
 			remove_proc_entry(name, proc_pnp);
 		remove_proc_entry(name, proc_pnp_boot);
 	}
@@ -287,6 +294,4 @@
 	remove_proc_entry("devices", proc_pnp);
 	remove_proc_entry("boot", proc_pnp);
 	remove_proc_entry("pnp", proc_bus);
-
-	return;
 }
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
index 3c2ab839..3fabf11 100644
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -1,6 +1,5 @@
 /*
  * rsparser.c - parses and encodes pnpbios resource data streams
- *
  */
 
 #include <linux/ctype.h>
@@ -12,8 +11,10 @@
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
 #else
-inline void pcibios_penalize_isa_irq(int irq, int active) {}
-#endif /* CONFIG_PCI */
+inline void pcibios_penalize_isa_irq(int irq, int active)
+{
+}
+#endif				/* CONFIG_PCI */
 
 #include "pnpbios.h"
 
@@ -52,75 +53,88 @@
  * Allocated Resources
  */
 
-static void
-pnpbios_parse_allocated_irqresource(struct pnp_resource_table * res, int irq)
+static void pnpbios_parse_allocated_irqresource(struct pnp_resource_table *res,
+						int irq)
 {
 	int i = 0;
-	while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_IRQ) i++;
+
+	while (!(res->irq_resource[i].flags & IORESOURCE_UNSET)
+	       && i < PNP_MAX_IRQ)
+		i++;
 	if (i < PNP_MAX_IRQ) {
-		res->irq_resource[i].flags = IORESOURCE_IRQ;  // Also clears _UNSET flag
+		res->irq_resource[i].flags = IORESOURCE_IRQ;	// Also clears _UNSET flag
 		if (irq == -1) {
 			res->irq_resource[i].flags |= IORESOURCE_DISABLED;
 			return;
 		}
 		res->irq_resource[i].start =
-		res->irq_resource[i].end = (unsigned long) irq;
+		    res->irq_resource[i].end = (unsigned long)irq;
 		pcibios_penalize_isa_irq(irq, 1);
 	}
 }
 
-static void
-pnpbios_parse_allocated_dmaresource(struct pnp_resource_table * res, int dma)
+static void pnpbios_parse_allocated_dmaresource(struct pnp_resource_table *res,
+						int dma)
 {
 	int i = 0;
+
 	while (i < PNP_MAX_DMA &&
-			!(res->dma_resource[i].flags & IORESOURCE_UNSET))
+	       !(res->dma_resource[i].flags & IORESOURCE_UNSET))
 		i++;
 	if (i < PNP_MAX_DMA) {
-		res->dma_resource[i].flags = IORESOURCE_DMA;  // Also clears _UNSET flag
+		res->dma_resource[i].flags = IORESOURCE_DMA;	// Also clears _UNSET flag
 		if (dma == -1) {
 			res->dma_resource[i].flags |= IORESOURCE_DISABLED;
 			return;
 		}
 		res->dma_resource[i].start =
-		res->dma_resource[i].end = (unsigned long) dma;
+		    res->dma_resource[i].end = (unsigned long)dma;
 	}
 }
 
-static void
-pnpbios_parse_allocated_ioresource(struct pnp_resource_table * res, int io, int len)
+static void pnpbios_parse_allocated_ioresource(struct pnp_resource_table *res,
+					       int io, int len)
 {
 	int i = 0;
-	while (!(res->port_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_PORT) i++;
+
+	while (!(res->port_resource[i].flags & IORESOURCE_UNSET)
+	       && i < PNP_MAX_PORT)
+		i++;
 	if (i < PNP_MAX_PORT) {
-		res->port_resource[i].flags = IORESOURCE_IO;  // Also clears _UNSET flag
-		if (len <= 0 || (io + len -1) >= 0x10003) {
+		res->port_resource[i].flags = IORESOURCE_IO;	// Also clears _UNSET flag
+		if (len <= 0 || (io + len - 1) >= 0x10003) {
 			res->port_resource[i].flags |= IORESOURCE_DISABLED;
 			return;
 		}
-		res->port_resource[i].start = (unsigned long) io;
+		res->port_resource[i].start = (unsigned long)io;
 		res->port_resource[i].end = (unsigned long)(io + len - 1);
 	}
 }
 
-static void
-pnpbios_parse_allocated_memresource(struct pnp_resource_table * res, int mem, int len)
+static void pnpbios_parse_allocated_memresource(struct pnp_resource_table *res,
+						int mem, int len)
 {
 	int i = 0;
-	while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) && i < PNP_MAX_MEM) i++;
+
+	while (!(res->mem_resource[i].flags & IORESOURCE_UNSET)
+	       && i < PNP_MAX_MEM)
+		i++;
 	if (i < PNP_MAX_MEM) {
-		res->mem_resource[i].flags = IORESOURCE_MEM;  // Also clears _UNSET flag
+		res->mem_resource[i].flags = IORESOURCE_MEM;	// Also clears _UNSET flag
 		if (len <= 0) {
 			res->mem_resource[i].flags |= IORESOURCE_DISABLED;
 			return;
 		}
-		res->mem_resource[i].start = (unsigned long) mem;
+		res->mem_resource[i].start = (unsigned long)mem;
 		res->mem_resource[i].end = (unsigned long)(mem + len - 1);
 	}
 }
 
-static unsigned char *
-pnpbios_parse_allocated_resource_data(unsigned char * p, unsigned char * end, struct pnp_resource_table * res)
+static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p,
+							    unsigned char *end,
+							    struct
+							    pnp_resource_table
+							    *res)
 {
 	unsigned int len, tag;
 	int io, size, mask, i;
@@ -134,12 +148,12 @@
 	while ((char *)p < (char *)end) {
 
 		/* determine the type of tag */
-		if (p[0] & LARGE_TAG) { /* large tag */
+		if (p[0] & LARGE_TAG) {	/* large tag */
 			len = (p[2] << 8) | p[1];
 			tag = p[0];
-		} else { /* small tag */
+		} else {	/* small tag */
 			len = p[0] & 0x07;
-			tag = ((p[0]>>3) & 0x0f);
+			tag = ((p[0] >> 3) & 0x0f);
 		}
 
 		switch (tag) {
@@ -147,8 +161,8 @@
 		case LARGE_TAG_MEM:
 			if (len != 9)
 				goto len_err;
-			io = *(short *) &p[4];
-			size = *(short *) &p[10];
+			io = *(short *)&p[4];
+			size = *(short *)&p[10];
 			pnpbios_parse_allocated_memresource(res, io, size);
 			break;
 
@@ -163,16 +177,16 @@
 		case LARGE_TAG_MEM32:
 			if (len != 17)
 				goto len_err;
-			io = *(int *) &p[4];
-			size = *(int *) &p[16];
+			io = *(int *)&p[4];
+			size = *(int *)&p[16];
 			pnpbios_parse_allocated_memresource(res, io, size);
 			break;
 
 		case LARGE_TAG_FIXEDMEM32:
 			if (len != 9)
 				goto len_err;
-			io = *(int *) &p[4];
-			size = *(int *) &p[8];
+			io = *(int *)&p[4];
+			size = *(int *)&p[8];
 			pnpbios_parse_allocated_memresource(res, io, size);
 			break;
 
@@ -180,9 +194,10 @@
 			if (len < 2 || len > 3)
 				goto len_err;
 			io = -1;
-			mask= p[1] + p[2]*256;
-			for (i=0;i<16;i++, mask=mask>>1)
-				if(mask & 0x01) io=i;
+			mask = p[1] + p[2] * 256;
+			for (i = 0; i < 16; i++, mask = mask >> 1)
+				if (mask & 0x01)
+					io = i;
 			pnpbios_parse_allocated_irqresource(res, io);
 			break;
 
@@ -191,15 +206,16 @@
 				goto len_err;
 			io = -1;
 			mask = p[1];
-			for (i=0;i<8;i++, mask = mask>>1)
-				if(mask & 0x01) io=i;
+			for (i = 0; i < 8; i++, mask = mask >> 1)
+				if (mask & 0x01)
+					io = i;
 			pnpbios_parse_allocated_dmaresource(res, io);
 			break;
 
 		case SMALL_TAG_PORT:
 			if (len != 7)
 				goto len_err;
-			io = p[2] + p[3] *256;
+			io = p[2] + p[3] * 256;
 			size = p[7];
 			pnpbios_parse_allocated_ioresource(res, io, size);
 			break;
@@ -218,12 +234,14 @@
 
 		case SMALL_TAG_END:
 			p = p + 2;
-        		return (unsigned char *)p;
+			return (unsigned char *)p;
 			break;
 
-		default: /* an unkown tag */
-			len_err:
-			printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
+		default:	/* an unkown tag */
+len_err:
+			printk(KERN_ERR
+			       "PnPBIOS: Unknown tag '0x%x', length '%d'.\n",
+			       tag, len);
 			break;
 		}
 
@@ -234,20 +252,21 @@
 			p += len + 1;
 	}
 
-	printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
+	printk(KERN_ERR
+	       "PnPBIOS: Resource structure does not contain an end tag.\n");
 
 	return NULL;
 }
 
-
 /*
  * Resource Configuration Options
  */
 
-static void
-pnpbios_parse_mem_option(unsigned char *p, int size, struct pnp_option *option)
+static void pnpbios_parse_mem_option(unsigned char *p, int size,
+				     struct pnp_option *option)
 {
-	struct pnp_mem * mem;
+	struct pnp_mem *mem;
+
 	mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
 	if (!mem)
 		return;
@@ -256,14 +275,14 @@
 	mem->align = (p[9] << 8) | p[8];
 	mem->size = ((p[11] << 8) | p[10]) << 8;
 	mem->flags = p[3];
-	pnp_register_mem_resource(option,mem);
-	return;
+	pnp_register_mem_resource(option, mem);
 }
 
-static void
-pnpbios_parse_mem32_option(unsigned char *p, int size, struct pnp_option *option)
+static void pnpbios_parse_mem32_option(unsigned char *p, int size,
+				       struct pnp_option *option)
 {
-	struct pnp_mem * mem;
+	struct pnp_mem *mem;
+
 	mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
 	if (!mem)
 		return;
@@ -272,14 +291,14 @@
 	mem->align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12];
 	mem->size = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16];
 	mem->flags = p[3];
-	pnp_register_mem_resource(option,mem);
-	return;
+	pnp_register_mem_resource(option, mem);
 }
 
-static void
-pnpbios_parse_fixed_mem32_option(unsigned char *p, int size, struct pnp_option *option)
+static void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size,
+					     struct pnp_option *option)
 {
-	struct pnp_mem * mem;
+	struct pnp_mem *mem;
+
 	mem = kzalloc(sizeof(struct pnp_mem), GFP_KERNEL);
 	if (!mem)
 		return;
@@ -287,14 +306,13 @@
 	mem->size = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
 	mem->align = 0;
 	mem->flags = p[3];
-	pnp_register_mem_resource(option,mem);
-	return;
+	pnp_register_mem_resource(option, mem);
 }
 
-static void
-pnpbios_parse_irq_option(unsigned char *p, int size, struct pnp_option *option)
+static void pnpbios_parse_irq_option(unsigned char *p, int size,
+				     struct pnp_option *option)
 {
-	struct pnp_irq * irq;
+	struct pnp_irq *irq;
 	unsigned long bits;
 
 	irq = kzalloc(sizeof(struct pnp_irq), GFP_KERNEL);
@@ -306,27 +324,27 @@
 		irq->flags = p[3];
 	else
 		irq->flags = IORESOURCE_IRQ_HIGHEDGE;
-	pnp_register_irq_resource(option,irq);
-	return;
+	pnp_register_irq_resource(option, irq);
 }
 
-static void
-pnpbios_parse_dma_option(unsigned char *p, int size, struct pnp_option *option)
+static void pnpbios_parse_dma_option(unsigned char *p, int size,
+				     struct pnp_option *option)
 {
-	struct pnp_dma * dma;
+	struct pnp_dma *dma;
+
 	dma = kzalloc(sizeof(struct pnp_dma), GFP_KERNEL);
 	if (!dma)
 		return;
 	dma->map = p[1];
 	dma->flags = p[2];
-	pnp_register_dma_resource(option,dma);
-	return;
+	pnp_register_dma_resource(option, dma);
 }
 
-static void
-pnpbios_parse_port_option(unsigned char *p, int size, struct pnp_option *option)
+static void pnpbios_parse_port_option(unsigned char *p, int size,
+				      struct pnp_option *option)
 {
-	struct pnp_port * port;
+	struct pnp_port *port;
+
 	port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
 	if (!port)
 		return;
@@ -335,14 +353,14 @@
 	port->align = p[6];
 	port->size = p[7];
 	port->flags = p[1] ? PNP_PORT_FLAG_16BITADDR : 0;
-	pnp_register_port_resource(option,port);
-	return;
+	pnp_register_port_resource(option, port);
 }
 
-static void
-pnpbios_parse_fixed_port_option(unsigned char *p, int size, struct pnp_option *option)
+static void pnpbios_parse_fixed_port_option(unsigned char *p, int size,
+					    struct pnp_option *option)
 {
-	struct pnp_port * port;
+	struct pnp_port *port;
+
 	port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
 	if (!port)
 		return;
@@ -350,12 +368,12 @@
 	port->size = p[3];
 	port->align = 0;
 	port->flags = PNP_PORT_FLAG_FIXED;
-	pnp_register_port_resource(option,port);
-	return;
+	pnp_register_port_resource(option, port);
 }
 
-static unsigned char *
-pnpbios_parse_resource_option_data(unsigned char * p, unsigned char * end, struct pnp_dev *dev)
+static unsigned char *pnpbios_parse_resource_option_data(unsigned char *p,
+							 unsigned char *end,
+							 struct pnp_dev *dev)
 {
 	unsigned int len, tag;
 	int priority = 0;
@@ -371,12 +389,12 @@
 	while ((char *)p < (char *)end) {
 
 		/* determine the type of tag */
-		if (p[0] & LARGE_TAG) { /* large tag */
+		if (p[0] & LARGE_TAG) {	/* large tag */
 			len = (p[2] << 8) | p[1];
 			tag = p[0];
-		} else { /* small tag */
+		} else {	/* small tag */
 			len = p[0] & 0x07;
-			tag = ((p[0]>>3) & 0x0f);
+			tag = ((p[0] >> 3) & 0x0f);
 		}
 
 		switch (tag) {
@@ -442,16 +460,19 @@
 			if (len != 0)
 				goto len_err;
 			if (option_independent == option)
-				printk(KERN_WARNING "PnPBIOS: Missing SMALL_TAG_STARTDEP tag\n");
+				printk(KERN_WARNING
+				       "PnPBIOS: Missing SMALL_TAG_STARTDEP tag\n");
 			option = option_independent;
 			break;
 
 		case SMALL_TAG_END:
-        		return p + 2;
+			return p + 2;
 
-		default: /* an unkown tag */
-			len_err:
-			printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
+		default:	/* an unkown tag */
+len_err:
+			printk(KERN_ERR
+			       "PnPBIOS: Unknown tag '0x%x', length '%d'.\n",
+			       tag, len);
 			break;
 		}
 
@@ -462,19 +483,18 @@
 			p += len + 1;
 	}
 
-	printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
+	printk(KERN_ERR
+	       "PnPBIOS: Resource structure does not contain an end tag.\n");
 
 	return NULL;
 }
 
-
 /*
  * Compatible Device IDs
  */
 
 #define HEX(id,a) hex[((id)>>a) & 15]
 #define CHAR(id,a) (0x40 + (((id)>>a) & 31))
-//
 
 void pnpid32_to_pnpid(u32 id, char *str)
 {
@@ -483,21 +503,20 @@
 	id = be32_to_cpu(id);
 	str[0] = CHAR(id, 26);
 	str[1] = CHAR(id, 21);
-	str[2] = CHAR(id,16);
+	str[2] = CHAR(id, 16);
 	str[3] = HEX(id, 12);
 	str[4] = HEX(id, 8);
 	str[5] = HEX(id, 4);
 	str[6] = HEX(id, 0);
 	str[7] = '\0';
-
-	return;
 }
-//
+
 #undef CHAR
 #undef HEX
 
-static unsigned char *
-pnpbios_parse_compatible_ids(unsigned char *p, unsigned char *end, struct pnp_dev *dev)
+static unsigned char *pnpbios_parse_compatible_ids(unsigned char *p,
+						   unsigned char *end,
+						   struct pnp_dev *dev)
 {
 	int len, tag;
 	char id[8];
@@ -509,40 +528,45 @@
 	while ((char *)p < (char *)end) {
 
 		/* determine the type of tag */
-		if (p[0] & LARGE_TAG) { /* large tag */
+		if (p[0] & LARGE_TAG) {	/* large tag */
 			len = (p[2] << 8) | p[1];
 			tag = p[0];
-		} else { /* small tag */
+		} else {	/* small tag */
 			len = p[0] & 0x07;
-			tag = ((p[0]>>3) & 0x0f);
+			tag = ((p[0] >> 3) & 0x0f);
 		}
 
 		switch (tag) {
 
 		case LARGE_TAG_ANSISTR:
-			strncpy(dev->name, p + 3, len >= PNP_NAME_LEN ? PNP_NAME_LEN - 2 : len);
-			dev->name[len >= PNP_NAME_LEN ? PNP_NAME_LEN - 1 : len] = '\0';
+			strncpy(dev->name, p + 3,
+				len >= PNP_NAME_LEN ? PNP_NAME_LEN - 2 : len);
+			dev->name[len >=
+				  PNP_NAME_LEN ? PNP_NAME_LEN - 1 : len] = '\0';
 			break;
 
-		case SMALL_TAG_COMPATDEVID: /* compatible ID */
+		case SMALL_TAG_COMPATDEVID:	/* compatible ID */
 			if (len != 4)
 				goto len_err;
-			dev_id =  kzalloc(sizeof (struct pnp_id), GFP_KERNEL);
+			dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
 			if (!dev_id)
 				return NULL;
-			pnpid32_to_pnpid(p[1] | p[2] << 8 | p[3] << 16 | p[4] << 24,id);
+			pnpid32_to_pnpid(p[1] | p[2] << 8 | p[3] << 16 | p[4] <<
+					 24, id);
 			memcpy(&dev_id->id, id, 7);
 			pnp_add_id(dev_id, dev);
 			break;
 
 		case SMALL_TAG_END:
 			p = p + 2;
-        		return (unsigned char *)p;
+			return (unsigned char *)p;
 			break;
 
-		default: /* an unkown tag */
-			len_err:
-			printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
+		default:	/* an unkown tag */
+len_err:
+			printk(KERN_ERR
+			       "PnPBIOS: Unknown tag '0x%x', length '%d'.\n",
+			       tag, len);
 			break;
 		}
 
@@ -553,33 +577,34 @@
 			p += len + 1;
 	}
 
-	printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
+	printk(KERN_ERR
+	       "PnPBIOS: Resource structure does not contain an end tag.\n");
 
 	return NULL;
 }
 
-
 /*
  * Allocated Resource Encoding
  */
 
-static void pnpbios_encode_mem(unsigned char *p, struct resource * res)
+static void pnpbios_encode_mem(unsigned char *p, struct resource *res)
 {
 	unsigned long base = res->start;
 	unsigned long len = res->end - res->start + 1;
+
 	p[4] = (base >> 8) & 0xff;
 	p[5] = ((base >> 8) >> 8) & 0xff;
 	p[6] = (base >> 8) & 0xff;
 	p[7] = ((base >> 8) >> 8) & 0xff;
 	p[10] = (len >> 8) & 0xff;
 	p[11] = ((len >> 8) >> 8) & 0xff;
-	return;
 }
 
-static void pnpbios_encode_mem32(unsigned char *p, struct resource * res)
+static void pnpbios_encode_mem32(unsigned char *p, struct resource *res)
 {
 	unsigned long base = res->start;
 	unsigned long len = res->end - res->start + 1;
+
 	p[4] = base & 0xff;
 	p[5] = (base >> 8) & 0xff;
 	p[6] = (base >> 16) & 0xff;
@@ -592,12 +617,13 @@
 	p[17] = (len >> 8) & 0xff;
 	p[18] = (len >> 16) & 0xff;
 	p[19] = (len >> 24) & 0xff;
-	return;
 }
 
-static void pnpbios_encode_fixed_mem32(unsigned char *p, struct resource * res)
-{	unsigned long base = res->start;
+static void pnpbios_encode_fixed_mem32(unsigned char *p, struct resource *res)
+{
+	unsigned long base = res->start;
 	unsigned long len = res->end - res->start + 1;
+
 	p[4] = base & 0xff;
 	p[5] = (base >> 8) & 0xff;
 	p[6] = (base >> 16) & 0xff;
@@ -606,50 +632,52 @@
 	p[9] = (len >> 8) & 0xff;
 	p[10] = (len >> 16) & 0xff;
 	p[11] = (len >> 24) & 0xff;
-	return;
 }
 
-static void pnpbios_encode_irq(unsigned char *p, struct resource * res)
+static void pnpbios_encode_irq(unsigned char *p, struct resource *res)
 {
 	unsigned long map = 0;
+
 	map = 1 << res->start;
 	p[1] = map & 0xff;
 	p[2] = (map >> 8) & 0xff;
-	return;
 }
 
-static void pnpbios_encode_dma(unsigned char *p, struct resource * res)
+static void pnpbios_encode_dma(unsigned char *p, struct resource *res)
 {
 	unsigned long map = 0;
+
 	map = 1 << res->start;
 	p[1] = map & 0xff;
-	return;
 }
 
-static void pnpbios_encode_port(unsigned char *p, struct resource * res)
+static void pnpbios_encode_port(unsigned char *p, struct resource *res)
 {
 	unsigned long base = res->start;
 	unsigned long len = res->end - res->start + 1;
+
 	p[2] = base & 0xff;
 	p[3] = (base >> 8) & 0xff;
 	p[4] = base & 0xff;
 	p[5] = (base >> 8) & 0xff;
 	p[7] = len & 0xff;
-	return;
 }
 
-static void pnpbios_encode_fixed_port(unsigned char *p, struct resource * res)
+static void pnpbios_encode_fixed_port(unsigned char *p, struct resource *res)
 {
 	unsigned long base = res->start;
 	unsigned long len = res->end - res->start + 1;
+
 	p[1] = base & 0xff;
 	p[2] = (base >> 8) & 0xff;
 	p[3] = len & 0xff;
-	return;
 }
 
-static unsigned char *
-pnpbios_encode_allocated_resource_data(unsigned char * p, unsigned char * end, struct pnp_resource_table * res)
+static unsigned char *pnpbios_encode_allocated_resource_data(unsigned char *p,
+							     unsigned char *end,
+							     struct
+							     pnp_resource_table
+							     *res)
 {
 	unsigned int len, tag;
 	int port = 0, irq = 0, dma = 0, mem = 0;
@@ -660,12 +688,12 @@
 	while ((char *)p < (char *)end) {
 
 		/* determine the type of tag */
-		if (p[0] & LARGE_TAG) { /* large tag */
+		if (p[0] & LARGE_TAG) {	/* large tag */
 			len = (p[2] << 8) | p[1];
 			tag = p[0];
-		} else { /* small tag */
+		} else {	/* small tag */
 			len = p[0] & 0x07;
-			tag = ((p[0]>>3) & 0x0f);
+			tag = ((p[0] >> 3) & 0x0f);
 		}
 
 		switch (tag) {
@@ -725,12 +753,14 @@
 
 		case SMALL_TAG_END:
 			p = p + 2;
-        		return (unsigned char *)p;
+			return (unsigned char *)p;
 			break;
 
-		default: /* an unkown tag */
-			len_err:
-			printk(KERN_ERR "PnPBIOS: Unknown tag '0x%x', length '%d'.\n", tag, len);
+		default:	/* an unkown tag */
+len_err:
+			printk(KERN_ERR
+			       "PnPBIOS: Unknown tag '0x%x', length '%d'.\n",
+			       tag, len);
 			break;
 		}
 
@@ -741,52 +771,52 @@
 			p += len + 1;
 	}
 
-	printk(KERN_ERR "PnPBIOS: Resource structure does not contain an end tag.\n");
+	printk(KERN_ERR
+	       "PnPBIOS: Resource structure does not contain an end tag.\n");
 
 	return NULL;
 }
 
-
 /*
  * Core Parsing Functions
  */
 
-int
-pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node * node)
+int pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node *node)
 {
-	unsigned char * p = (char *)node->data;
-	unsigned char * end = (char *)(node->data + node->size);
-	p = pnpbios_parse_allocated_resource_data(p,end,&dev->res);
+	unsigned char *p = (char *)node->data;
+	unsigned char *end = (char *)(node->data + node->size);
+
+	p = pnpbios_parse_allocated_resource_data(p, end, &dev->res);
 	if (!p)
 		return -EIO;
-	p = pnpbios_parse_resource_option_data(p,end,dev);
+	p = pnpbios_parse_resource_option_data(p, end, dev);
 	if (!p)
 		return -EIO;
-	p = pnpbios_parse_compatible_ids(p,end,dev);
+	p = pnpbios_parse_compatible_ids(p, end, dev);
 	if (!p)
 		return -EIO;
 	return 0;
 }
 
-int
-pnpbios_read_resources_from_node(struct pnp_resource_table *res,
-				 struct pnp_bios_node * node)
+int pnpbios_read_resources_from_node(struct pnp_resource_table *res,
+				     struct pnp_bios_node *node)
 {
-	unsigned char * p = (char *)node->data;
-	unsigned char * end = (char *)(node->data + node->size);
-	p = pnpbios_parse_allocated_resource_data(p,end,res);
+	unsigned char *p = (char *)node->data;
+	unsigned char *end = (char *)(node->data + node->size);
+
+	p = pnpbios_parse_allocated_resource_data(p, end, res);
 	if (!p)
 		return -EIO;
 	return 0;
 }
 
-int
-pnpbios_write_resources_to_node(struct pnp_resource_table *res,
-				struct pnp_bios_node * node)
+int pnpbios_write_resources_to_node(struct pnp_resource_table *res,
+				    struct pnp_bios_node *node)
 {
-	unsigned char * p = (char *)node->data;
-	unsigned char * end = (char *)(node->data + node->size);
-	p = pnpbios_encode_allocated_resource_data(p,end,res);
+	unsigned char *p = (char *)node->data;
+	unsigned char *end = (char *)(node->data + node->size);
+
+	p = pnpbios_encode_allocated_resource_data(p, end, res);
 	if (!p)
 		return -EIO;
 	return 0;
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index 7c32366..6b0cf0c 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -19,7 +19,6 @@
 #include <linux/io.h>
 #include "base.h"
 
-
 static void quirk_awe32_resources(struct pnp_dev *dev)
 {
 	struct pnp_port *port, *port2, *port3;
@@ -31,7 +30,7 @@
 	 * two extra ports (at offset 0x400 and 0x800 from the one given) by
 	 * hand.
 	 */
-	for ( ; res ; res = res->next ) {
+	for (; res; res = res->next) {
 		port2 = pnp_alloc(sizeof(struct pnp_port));
 		if (!port2)
 			return;
@@ -58,18 +57,19 @@
 	struct pnp_option *res = dev->dependent;
 	unsigned long tmp;
 
-	for ( ; res ; res = res->next ) {
+	for (; res; res = res->next) {
 
 		struct pnp_irq *irq;
 		struct pnp_dma *dma;
 
-		for( irq = res->irq; irq; irq = irq->next ) {	// Valid irqs are 5, 7, 10
+		for (irq = res->irq; irq; irq = irq->next) {	// Valid irqs are 5, 7, 10
 			tmp = 0x04A0;
 			bitmap_copy(irq->map, &tmp, 16);	// 0000 0100 1010 0000
 		}
 
-		for( dma = res->dma; dma; dma = dma->next ) // Valid 8bit dma channels are 1,3
-			if( ( dma->flags & IORESOURCE_DMA_TYPE_MASK ) == IORESOURCE_DMA_8BIT )
+		for (dma = res->dma; dma; dma = dma->next)	// Valid 8bit dma channels are 1,3
+			if ((dma->flags & IORESOURCE_DMA_TYPE_MASK) ==
+			    IORESOURCE_DMA_8BIT)
 				dma->map = 0x000A;
 	}
 	printk(KERN_INFO "pnp: CMI8330 quirk - fixing interrupts and dma\n");
@@ -79,7 +79,7 @@
 {
 	struct pnp_port *port;
 	struct pnp_option *res = dev->dependent;
-	int    changed = 0;
+	int changed = 0;
 
 	/*
 	 * The default range on the mpu port for these devices is 0x388-0x388.
@@ -87,129 +87,26 @@
 	 * auto-configured.
 	 */
 
-	for( ; res ; res = res->next ) {
+	for (; res; res = res->next) {
 		port = res->port;
-		if(!port)
+		if (!port)
 			continue;
 		port = port->next;
-		if(!port)
+		if (!port)
 			continue;
 		port = port->next;
-		if(!port)
+		if (!port)
 			continue;
-		if(port->min != port->max)
+		if (port->min != port->max)
 			continue;
 		port->max += 0x70;
 		changed = 1;
 	}
-	if(changed)
-		printk(KERN_INFO "pnp: SB audio device quirk - increasing port range\n");
-	return;
+	if (changed)
+		printk(KERN_INFO
+		       "pnp: SB audio device quirk - increasing port range\n");
 }
 
-static int quirk_smc_fir_enabled(struct pnp_dev *dev)
-{
-	unsigned long firbase;
-	u8 bank, high, low, chip;
-
-	if (!pnp_port_valid(dev, 1))
-		return 0;
-
-	firbase = pnp_port_start(dev, 1);
-
-	/* Select register bank 3 */
-	bank = inb(firbase + 7);
-	bank &= 0xf0;
-	bank |= 3;
-	outb(bank, firbase + 7);
-
-	high = inb(firbase + 0);
-	low  = inb(firbase + 1);
-	chip = inb(firbase + 2);
-
-	/* This corresponds to the check in smsc_ircc_present() */
-	if (high == 0x10 && low == 0xb8 && (chip == 0xf1 || chip == 0xf2))
-		return 1;
-
-	return 0;
-}
-
-static void quirk_smc_enable(struct pnp_dev *dev)
-{
-	struct resource fir, sir, irq;
-
-	pnp_activate_dev(dev);
-	if (quirk_smc_fir_enabled(dev))
-		return;
-
-	/*
-	 * Sometimes the BIOS claims the device is enabled, but it reports
-	 * the wrong FIR resources or doesn't properly configure ISA or LPC
-	 * bridges on the way to the device.
-	 *
-	 * HP nc6000 and nc8000/nw8000 laptops have known problems like
-	 * this.  Fortunately, they do fix things up if we auto-configure
-	 * the device using its _PRS and _SRS methods.
-	 */
-	dev_err(&dev->dev, "%s not responding at SIR 0x%lx, FIR 0x%lx; "
-		"auto-configuring\n", dev->id->id,
-		(unsigned long) pnp_port_start(dev, 0),
-		(unsigned long) pnp_port_start(dev, 1));
-
-	pnp_disable_dev(dev);
-	pnp_init_resource_table(&dev->res);
-	pnp_auto_config_dev(dev);
-	pnp_activate_dev(dev);
-	if (quirk_smc_fir_enabled(dev)) {
-		dev_err(&dev->dev, "responds at SIR 0x%lx, FIR 0x%lx\n",
-			(unsigned long) pnp_port_start(dev, 0),
-			(unsigned long) pnp_port_start(dev, 1));
-		return;
-	}
-
-	/*
-	 * The Toshiba Portege 4000 _CRS reports the FIR region first,
-	 * followed by the SIR region.  The BIOS will configure the bridge,
-	 * but only if we call _SRS with SIR first, then FIR.  It also
-	 * reports the IRQ as active high, when it is really active low.
-	 */
-	dev_err(&dev->dev, "not responding at SIR 0x%lx, FIR 0x%lx; "
-		"swapping SIR/FIR and reconfiguring\n",
-		(unsigned long) pnp_port_start(dev, 0),
-		(unsigned long) pnp_port_start(dev, 1));
-
-	/*
-	 * Clear IORESOURCE_AUTO so pnp_activate_dev() doesn't reassign
-	 * these resources any more.
-	 */
-	fir = dev->res.port_resource[0];
-	sir = dev->res.port_resource[1];
-	fir.flags &= ~IORESOURCE_AUTO;
-	sir.flags &= ~IORESOURCE_AUTO;
-
-	irq = dev->res.irq_resource[0];
-	irq.flags &= ~IORESOURCE_AUTO;
-	irq.flags &= ~IORESOURCE_BITS;
-	irq.flags |= IORESOURCE_IRQ_LOWEDGE;
-
-	pnp_disable_dev(dev);
-	dev->res.port_resource[0] = sir;
-	dev->res.port_resource[1] = fir;
-	dev->res.irq_resource[0] = irq;
-	pnp_activate_dev(dev);
-
-	if (quirk_smc_fir_enabled(dev)) {
-		dev_err(&dev->dev, "responds at SIR 0x%lx, FIR 0x%lx\n",
-			(unsigned long) pnp_port_start(dev, 0),
-			(unsigned long) pnp_port_start(dev, 1));
-		return;
-	}
-
-	dev_err(&dev->dev, "giving up; try \"smsc-ircc2.nopnp\" and "
-		"email bjorn.helgaas@hp.com\n");
-}
-
-
 /*
  *  PnP Quirks
  *  Cards or devices that need some tweaking due to incomplete resource info
@@ -217,21 +114,20 @@
 
 static struct pnp_fixup pnp_fixups[] = {
 	/* Soundblaster awe io port quirk */
-	{ "CTL0021", quirk_awe32_resources },
-	{ "CTL0022", quirk_awe32_resources },
-	{ "CTL0023", quirk_awe32_resources },
+	{"CTL0021", quirk_awe32_resources},
+	{"CTL0022", quirk_awe32_resources},
+	{"CTL0023", quirk_awe32_resources},
 	/* CMI 8330 interrupt and dma fix */
-	{ "@X@0001", quirk_cmi8330_resources },
+	{"@X@0001", quirk_cmi8330_resources},
 	/* Soundblaster audio device io port range quirk */
-	{ "CTL0001", quirk_sb16audio_resources },
-	{ "CTL0031", quirk_sb16audio_resources },
-	{ "CTL0041", quirk_sb16audio_resources },
-	{ "CTL0042", quirk_sb16audio_resources },
-	{ "CTL0043", quirk_sb16audio_resources },
-	{ "CTL0044", quirk_sb16audio_resources },
-	{ "CTL0045", quirk_sb16audio_resources },
-	{ "SMCf010", quirk_smc_enable },
-	{ "" }
+	{"CTL0001", quirk_sb16audio_resources},
+	{"CTL0031", quirk_sb16audio_resources},
+	{"CTL0041", quirk_sb16audio_resources},
+	{"CTL0042", quirk_sb16audio_resources},
+	{"CTL0043", quirk_sb16audio_resources},
+	{"CTL0044", quirk_sb16audio_resources},
+	{"CTL0045", quirk_sb16audio_resources},
+	{""}
 };
 
 void pnp_fixup_device(struct pnp_dev *dev)
@@ -239,9 +135,8 @@
 	int i = 0;
 
 	while (*pnp_fixups[i].id) {
-		if (compare_pnp_id(dev->id,pnp_fixups[i].id)) {
-			pnp_dbg("Calling quirk for %s",
-		                  dev->dev.bus_id);
+		if (compare_pnp_id(dev->id, pnp_fixups[i].id)) {
+			pnp_dbg("Calling quirk for %s", dev->dev.bus_id);
 			pnp_fixups[i].quirk_function(dev);
 		}
 		i++;
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index a685fbe..ef12869 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -3,7 +3,6 @@
  *
  * based on isapnp.c resource management (c) Jaroslav Kysela <perex@suse.cz>
  * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
- *
  */
 
 #include <linux/module.h>
@@ -20,21 +19,19 @@
 #include <linux/pnp.h>
 #include "base.h"
 
-static int pnp_reserve_irq[16] = { [0 ... 15] = -1 };	/* reserve (don't use) some IRQ */
-static int pnp_reserve_dma[8] = { [0 ... 7] = -1 };	/* reserve (don't use) some DMA */
-static int pnp_reserve_io[16] = { [0 ... 15] = -1 };	/* reserve (don't use) some I/O region */
-static int pnp_reserve_mem[16] = { [0 ... 15] = -1 };	/* reserve (don't use) some memory region */
-
+static int pnp_reserve_irq[16] = {[0 ... 15] = -1 };	/* reserve (don't use) some IRQ */
+static int pnp_reserve_dma[8] = {[0 ... 7] = -1 };	/* reserve (don't use) some DMA */
+static int pnp_reserve_io[16] = {[0 ... 15] = -1 };	/* reserve (don't use) some I/O region */
+static int pnp_reserve_mem[16] = {[0 ... 15] = -1 };	/* reserve (don't use) some memory region */
 
 /*
  * option registration
  */
 
-static struct pnp_option * pnp_build_option(int priority)
+static struct pnp_option *pnp_build_option(int priority)
 {
 	struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option));
 
-	/* check if pnp_alloc ran out of memory */
 	if (!option)
 		return NULL;
 
@@ -46,11 +43,9 @@
 	return option;
 }
 
-struct pnp_option * pnp_register_independent_option(struct pnp_dev *dev)
+struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev)
 {
 	struct pnp_option *option;
-	if (!dev)
-		return NULL;
 
 	option = pnp_build_option(PNP_RES_PRIORITY_PREFERRED);
 
@@ -61,11 +56,10 @@
 	return option;
 }
 
-struct pnp_option * pnp_register_dependent_option(struct pnp_dev *dev, int priority)
+struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
+						 int priority)
 {
 	struct pnp_option *option;
-	if (!dev)
-		return NULL;
 
 	option = pnp_build_option(priority);
 
@@ -82,10 +76,6 @@
 int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data)
 {
 	struct pnp_irq *ptr;
-	if (!option)
-		return -EINVAL;
-	if (!data)
-		return -EINVAL;
 
 	ptr = option->irq;
 	while (ptr && ptr->next)
@@ -110,10 +100,6 @@
 int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data)
 {
 	struct pnp_dma *ptr;
-	if (!option)
-		return -EINVAL;
-	if (!data)
-		return -EINVAL;
 
 	ptr = option->dma;
 	while (ptr && ptr->next)
@@ -129,10 +115,6 @@
 int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data)
 {
 	struct pnp_port *ptr;
-	if (!option)
-		return -EINVAL;
-	if (!data)
-		return -EINVAL;
 
 	ptr = option->port;
 	while (ptr && ptr->next)
@@ -148,10 +130,6 @@
 int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data)
 {
 	struct pnp_mem *ptr;
-	if (!option)
-		return -EINVAL;
-	if (!data)
-		return -EINVAL;
 
 	ptr = option->mem;
 	while (ptr && ptr->next)
@@ -222,7 +200,6 @@
 	}
 }
 
-
 /*
  * resource validity checking
  */
@@ -236,11 +213,12 @@
 #define cannot_compare(flags) \
 ((flags) & (IORESOURCE_UNSET | IORESOURCE_DISABLED))
 
-int pnp_check_port(struct pnp_dev * dev, int idx)
+int pnp_check_port(struct pnp_dev *dev, int idx)
 {
 	int tmp;
 	struct pnp_dev *tdev;
 	resource_size_t *port, *end, *tport, *tend;
+
 	port = &dev->res.port_resource[idx].start;
 	end = &dev->res.port_resource[idx].end;
 
@@ -250,8 +228,8 @@
 
 	/* check if the resource is already in use, skip if the
 	 * device is active because it itself may be in use */
-	if(!dev->active) {
-		if (__check_region(&ioport_resource, *port, length(port,end)))
+	if (!dev->active) {
+		if (__check_region(&ioport_resource, *port, length(port, end)))
 			return 0;
 	}
 
@@ -259,7 +237,7 @@
 	for (tmp = 0; tmp < 8; tmp++) {
 		int rport = pnp_reserve_io[tmp << 1];
 		int rend = pnp_reserve_io[(tmp << 1) + 1] + rport - 1;
-		if (ranged_conflict(port,end,&rport,&rend))
+		if (ranged_conflict(port, end, &rport, &rend))
 			return 0;
 	}
 
@@ -268,7 +246,7 @@
 		if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) {
 			tport = &dev->res.port_resource[tmp].start;
 			tend = &dev->res.port_resource[tmp].end;
-			if (ranged_conflict(port,end,tport,tend))
+			if (ranged_conflict(port, end, tport, tend))
 				return 0;
 		}
 	}
@@ -279,11 +257,12 @@
 			continue;
 		for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
 			if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) {
-				if (cannot_compare(tdev->res.port_resource[tmp].flags))
+				if (cannot_compare
+				    (tdev->res.port_resource[tmp].flags))
 					continue;
 				tport = &tdev->res.port_resource[tmp].start;
 				tend = &tdev->res.port_resource[tmp].end;
-				if (ranged_conflict(port,end,tport,tend))
+				if (ranged_conflict(port, end, tport, tend))
 					return 0;
 			}
 		}
@@ -292,11 +271,12 @@
 	return 1;
 }
 
-int pnp_check_mem(struct pnp_dev * dev, int idx)
+int pnp_check_mem(struct pnp_dev *dev, int idx)
 {
 	int tmp;
 	struct pnp_dev *tdev;
 	resource_size_t *addr, *end, *taddr, *tend;
+
 	addr = &dev->res.mem_resource[idx].start;
 	end = &dev->res.mem_resource[idx].end;
 
@@ -306,8 +286,8 @@
 
 	/* check if the resource is already in use, skip if the
 	 * device is active because it itself may be in use */
-	if(!dev->active) {
-		if (check_mem_region(*addr, length(addr,end)))
+	if (!dev->active) {
+		if (check_mem_region(*addr, length(addr, end)))
 			return 0;
 	}
 
@@ -315,7 +295,7 @@
 	for (tmp = 0; tmp < 8; tmp++) {
 		int raddr = pnp_reserve_mem[tmp << 1];
 		int rend = pnp_reserve_mem[(tmp << 1) + 1] + raddr - 1;
-		if (ranged_conflict(addr,end,&raddr,&rend))
+		if (ranged_conflict(addr, end, &raddr, &rend))
 			return 0;
 	}
 
@@ -324,7 +304,7 @@
 		if (dev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
 			taddr = &dev->res.mem_resource[tmp].start;
 			tend = &dev->res.mem_resource[tmp].end;
-			if (ranged_conflict(addr,end,taddr,tend))
+			if (ranged_conflict(addr, end, taddr, tend))
 				return 0;
 		}
 	}
@@ -335,11 +315,12 @@
 			continue;
 		for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
 			if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
-				if (cannot_compare(tdev->res.mem_resource[tmp].flags))
+				if (cannot_compare
+				    (tdev->res.mem_resource[tmp].flags))
 					continue;
 				taddr = &tdev->res.mem_resource[tmp].start;
 				tend = &tdev->res.mem_resource[tmp].end;
-				if (ranged_conflict(addr,end,taddr,tend))
+				if (ranged_conflict(addr, end, taddr, tend))
 					return 0;
 			}
 		}
@@ -353,11 +334,11 @@
 	return IRQ_HANDLED;
 }
 
-int pnp_check_irq(struct pnp_dev * dev, int idx)
+int pnp_check_irq(struct pnp_dev *dev, int idx)
 {
 	int tmp;
 	struct pnp_dev *tdev;
-	resource_size_t * irq = &dev->res.irq_resource[idx].start;
+	resource_size_t *irq = &dev->res.irq_resource[idx].start;
 
 	/* if the resource doesn't exist, don't complain about it */
 	if (cannot_compare(dev->res.irq_resource[idx].flags))
@@ -394,9 +375,9 @@
 
 	/* check if the resource is already in use, skip if the
 	 * device is active because it itself may be in use */
-	if(!dev->active) {
+	if (!dev->active) {
 		if (request_irq(*irq, pnp_test_handler,
-				IRQF_DISABLED|IRQF_PROBE_SHARED, "pnp", NULL))
+				IRQF_DISABLED | IRQF_PROBE_SHARED, "pnp", NULL))
 			return 0;
 		free_irq(*irq, NULL);
 	}
@@ -407,7 +388,8 @@
 			continue;
 		for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
 			if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
-				if (cannot_compare(tdev->res.irq_resource[tmp].flags))
+				if (cannot_compare
+				    (tdev->res.irq_resource[tmp].flags))
 					continue;
 				if ((tdev->res.irq_resource[tmp].start == *irq))
 					return 0;
@@ -418,12 +400,12 @@
 	return 1;
 }
 
-int pnp_check_dma(struct pnp_dev * dev, int idx)
+int pnp_check_dma(struct pnp_dev *dev, int idx)
 {
 #ifndef CONFIG_IA64
 	int tmp;
 	struct pnp_dev *tdev;
-	resource_size_t * dma = &dev->res.dma_resource[idx].start;
+	resource_size_t *dma = &dev->res.dma_resource[idx].start;
 
 	/* if the resource doesn't exist, don't complain about it */
 	if (cannot_compare(dev->res.dma_resource[idx].flags))
@@ -449,7 +431,7 @@
 
 	/* check if the resource is already in use, skip if the
 	 * device is active because it itself may be in use */
-	if(!dev->active) {
+	if (!dev->active) {
 		if (request_dma(*dma, "pnp"))
 			return 0;
 		free_dma(*dma);
@@ -461,7 +443,8 @@
 			continue;
 		for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
 			if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
-				if (cannot_compare(tdev->res.dma_resource[tmp].flags))
+				if (cannot_compare
+				    (tdev->res.dma_resource[tmp].flags))
 					continue;
 				if ((tdev->res.dma_resource[tmp].start == *dma))
 					return 0;
@@ -471,30 +454,18 @@
 
 	return 1;
 #else
-	/* IA64 hasn't legacy DMA */
+	/* IA64 does not have legacy DMA */
 	return 0;
 #endif
 }
 
-
-#if 0
-EXPORT_SYMBOL(pnp_register_dependent_option);
-EXPORT_SYMBOL(pnp_register_independent_option);
-EXPORT_SYMBOL(pnp_register_irq_resource);
-EXPORT_SYMBOL(pnp_register_dma_resource);
-EXPORT_SYMBOL(pnp_register_port_resource);
-EXPORT_SYMBOL(pnp_register_mem_resource);
-#endif  /*  0  */
-
-
 /* format is: pnp_reserve_irq=irq1[,irq2] .... */
-
 static int __init pnp_setup_reserve_irq(char *str)
 {
 	int i;
 
 	for (i = 0; i < 16; i++)
-		if (get_option(&str,&pnp_reserve_irq[i]) != 2)
+		if (get_option(&str, &pnp_reserve_irq[i]) != 2)
 			break;
 	return 1;
 }
@@ -502,13 +473,12 @@
 __setup("pnp_reserve_irq=", pnp_setup_reserve_irq);
 
 /* format is: pnp_reserve_dma=dma1[,dma2] .... */
-
 static int __init pnp_setup_reserve_dma(char *str)
 {
 	int i;
 
 	for (i = 0; i < 8; i++)
-		if (get_option(&str,&pnp_reserve_dma[i]) != 2)
+		if (get_option(&str, &pnp_reserve_dma[i]) != 2)
 			break;
 	return 1;
 }
@@ -516,13 +486,12 @@
 __setup("pnp_reserve_dma=", pnp_setup_reserve_dma);
 
 /* format is: pnp_reserve_io=io1,size1[,io2,size2] .... */
-
 static int __init pnp_setup_reserve_io(char *str)
 {
 	int i;
 
 	for (i = 0; i < 16; i++)
-		if (get_option(&str,&pnp_reserve_io[i]) != 2)
+		if (get_option(&str, &pnp_reserve_io[i]) != 2)
 			break;
 	return 1;
 }
@@ -530,13 +499,12 @@
 __setup("pnp_reserve_io=", pnp_setup_reserve_io);
 
 /* format is: pnp_reserve_mem=mem1,size1[,mem2,size2] .... */
-
 static int __init pnp_setup_reserve_mem(char *str)
 {
 	int i;
 
 	for (i = 0; i < 16; i++)
-		if (get_option(&str,&pnp_reserve_mem[i]) != 2)
+		if (get_option(&str, &pnp_reserve_mem[i]) != 2)
 			break;
 	return 1;
 }
diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c
index 946a0dc..13c608f 100644
--- a/drivers/pnp/support.c
+++ b/drivers/pnp/support.c
@@ -1,8 +1,7 @@
 /*
- * support.c - provides standard pnp functions for the use of pnp protocol drivers,
+ * support.c - standard functions for the use of pnp protocol drivers
  *
  * Copyright 2003 Adam Belay <ambx1@neo.rr.com>
- *
  */
 
 #include <linux/module.h>
@@ -11,22 +10,18 @@
 #include "base.h"
 
 /**
- * pnp_is_active - Determines if a device is active based on its current resources
+ * pnp_is_active - Determines if a device is active based on its current
+ *	resources
  * @dev: pointer to the desired PnP device
- *
  */
-
-int pnp_is_active(struct pnp_dev * dev)
+int pnp_is_active(struct pnp_dev *dev)
 {
 	if (!pnp_port_start(dev, 0) && pnp_port_len(dev, 0) <= 1 &&
 	    !pnp_mem_start(dev, 0) && pnp_mem_len(dev, 0) <= 1 &&
-	    pnp_irq(dev, 0) == -1 &&
-	    pnp_dma(dev, 0) == -1)
-	    	return 0;
+	    pnp_irq(dev, 0) == -1 && pnp_dma(dev, 0) == -1)
+		return 0;
 	else
 		return 1;
 }
 
-
-
 EXPORT_SYMBOL(pnp_is_active);
diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c
index a8a9554..a06f980 100644
--- a/drivers/pnp/system.c
+++ b/drivers/pnp/system.c
@@ -16,13 +16,14 @@
 
 static const struct pnp_device_id pnp_dev_table[] = {
 	/* General ID for reserving resources */
-	{	"PNP0c02",		0	},
+	{"PNP0c02", 0},
 	/* memory controller */
-	{	"PNP0c01",		0	},
-	{	"",			0	}
+	{"PNP0c01", 0},
+	{"", 0}
 };
 
-static void reserve_range(const char *pnpid, resource_size_t start, resource_size_t end, int port)
+static void reserve_range(const char *pnpid, resource_size_t start,
+			  resource_size_t end, int port)
 {
 	struct resource *res;
 	char *regionid;
@@ -32,9 +33,9 @@
 		return;
 	snprintf(regionid, 16, "pnp %s", pnpid);
 	if (port)
-		res = request_region(start, end-start+1, regionid);
+		res = request_region(start, end - start + 1, regionid);
 	else
-		res = request_mem_region(start, end-start+1, regionid);
+		res = request_mem_region(start, end - start + 1, regionid);
 	if (res == NULL)
 		kfree(regionid);
 	else
@@ -44,11 +45,10 @@
 	 * example do reserve stuff they know about too, so we may well
 	 * have double reservations.
 	 */
-	printk(KERN_INFO
-		"pnp: %s: %s range 0x%llx-0x%llx %s reserved\n",
-		pnpid, port ? "ioport" : "iomem",
-                (unsigned long long)start, (unsigned long long)end,
-		NULL != res ? "has been" : "could not be");
+	printk(KERN_INFO "pnp: %s: %s range 0x%llx-0x%llx %s reserved\n",
+	       pnpid, port ? "ioport" : "iomem",
+	       (unsigned long long)start, (unsigned long long)end,
+	       NULL != res ? "has been" : "could not be");
 }
 
 static void reserve_resources_of_dev(const struct pnp_dev *dev)
@@ -74,7 +74,7 @@
 			continue;	/* invalid */
 
 		reserve_range(dev->dev.bus_id, pnp_port_start(dev, i),
-			pnp_port_end(dev, i), 1);
+			      pnp_port_end(dev, i), 1);
 	}
 
 	for (i = 0; i < PNP_MAX_MEM; i++) {
@@ -82,24 +82,22 @@
 			continue;
 
 		reserve_range(dev->dev.bus_id, pnp_mem_start(dev, i),
-			pnp_mem_end(dev, i), 0);
+			      pnp_mem_end(dev, i), 0);
 	}
-
-	return;
 }
 
-static int system_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id)
+static int system_pnp_probe(struct pnp_dev *dev,
+			    const struct pnp_device_id *dev_id)
 {
 	reserve_resources_of_dev(dev);
 	return 0;
 }
 
 static struct pnp_driver system_pnp_driver = {
-	.name		= "system",
-	.id_table	= pnp_dev_table,
-	.flags		= PNP_DRIVER_RES_DO_NOT_CHANGE,
-	.probe		= system_pnp_probe,
-	.remove		= NULL,
+	.name     = "system",
+	.id_table = pnp_dev_table,
+	.flags    = PNP_DRIVER_RES_DO_NOT_CHANGE,
+	.probe    = system_pnp_probe,
 };
 
 static int __init pnp_system_init(void)
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 3f6e176..58c806e 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -38,7 +38,7 @@
 
 config BATTERY_PMU
 	tristate "Apple PMU battery"
-	depends on ADB_PMU
+	depends on PPC32 && ADB_PMU
 	help
 	  Say Y here to expose battery information on Apple machines
 	  through the generic battery class.
diff --git a/drivers/power/power_supply.h b/drivers/power/power_supply.h
index a9880d4..f38ba48 100644
--- a/drivers/power/power_supply.h
+++ b/drivers/power/power_supply.h
@@ -14,8 +14,7 @@
 
 extern int power_supply_create_attrs(struct power_supply *psy);
 extern void power_supply_remove_attrs(struct power_supply *psy);
-extern int power_supply_uevent(struct device *dev, char **envp, int num_envp,
-			       char *buffer, int buffer_size);
+extern int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env);
 
 #else
 
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index c7c4574..249f61b 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -195,11 +195,10 @@
 	return ret;
 }
 
-int power_supply_uevent(struct device *dev, char **envp, int num_envp,
-			char *buffer, int buffer_size)
+int power_supply_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct power_supply *psy = dev_get_drvdata(dev);
-	int i = 0, length = 0, ret = 0, j;
+	int ret = 0, j;
 	char *prop_buf;
 	char *attrname;
 
@@ -212,8 +211,7 @@
 
 	dev_dbg(dev, "POWER_SUPPLY_NAME=%s\n", psy->name);
 
-	ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-			     &length, "POWER_SUPPLY_NAME=%s", psy->name);
+	ret = add_uevent_var(env, "POWER_SUPPLY_NAME=%s", psy->name);
 	if (ret)
 		return ret;
 
@@ -243,9 +241,7 @@
 
 		dev_dbg(dev, "Static prop %s=%s\n", attrname, prop_buf);
 
-		ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-				     &length, "POWER_SUPPLY_%s=%s",
-				     attrname, prop_buf);
+		ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
 		kfree(attrname);
 		if (ret)
 			goto out;
@@ -282,9 +278,7 @@
 
 		dev_dbg(dev, "prop %s=%s\n", attrname, prop_buf);
 
-		ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-				     &length, "POWER_SUPPLY_%s=%s",
-				     attrname, prop_buf);
+		ret = add_uevent_var(env, "POWER_SUPPLY_%s=%s", attrname, prop_buf);
 		kfree(attrname);
 		if (ret)
 			goto out;
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index f935c1f..4442072 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -297,11 +297,10 @@
 	struct rio_switch *rswitch;
 	int result, rdid;
 
-	rdev = kmalloc(sizeof(struct rio_dev), GFP_KERNEL);
+	rdev = kzalloc(sizeof(struct rio_dev), GFP_KERNEL);
 	if (!rdev)
 		goto out;
 
-	memset(rdev, 0, sizeof(struct rio_dev));
 	rdev->net = net;
 	rio_mport_read_config_32(port, destid, hopcount, RIO_DEV_ID_CAR,
 				 &result);
@@ -801,9 +800,8 @@
 {
 	struct rio_net *net;
 
-	net = kmalloc(sizeof(struct rio_net), GFP_KERNEL);
+	net = kzalloc(sizeof(struct rio_net), GFP_KERNEL);
 	if (net) {
-		memset(net, 0, sizeof(struct rio_net));
 		INIT_LIST_HEAD(&net->node);
 		INIT_LIST_HEAD(&net->devices);
 		INIT_LIST_HEAD(&net->mports);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index cea401f..ff9e35c 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -2,15 +2,13 @@
 # RTC class/drivers configuration
 #
 
-menu "Real Time Clock"
-	depends on !S390
-
 config RTC_LIB
 	tristate
 
-config RTC_CLASS
-	tristate "RTC class"
+menuconfig RTC_CLASS
+	tristate "Real Time Clock"
 	default n
+	depends on !S390
 	select RTC_LIB
 	help
 	  Generic RTC class support. If you say yes here, you will
@@ -20,6 +18,8 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-class.
 
+if RTC_CLASS
+
 config RTC_HCTOSYS
 	bool "Set system time from RTC on startup and resume"
 	depends on RTC_CLASS = y
@@ -38,6 +38,9 @@
 	  clock, usually rtc0.  Initialization is done when the system
 	  starts up, and when it resumes from a low power state.
 
+	  The driver for this RTC device must be loaded before late_initcall
+	  functions run, so it must usually be statically linked.
+
 	  This clock should be battery-backed, so that it reads the correct
 	  time when the system boots from a power-off state.  Otherwise, your
 	  system will need an external clock source (like an NTP server).
@@ -55,11 +58,10 @@
 	  and individual RTC drivers.
 
 comment "RTC interfaces"
-	depends on RTC_CLASS
 
 config RTC_INTF_SYSFS
 	boolean "/sys/class/rtc/rtcN (sysfs)"
-	depends on RTC_CLASS && SYSFS
+	depends on SYSFS
 	default RTC_CLASS
 	help
 	  Say yes here if you want to use your RTCs using sysfs interfaces,
@@ -70,7 +72,7 @@
 
 config RTC_INTF_PROC
 	boolean "/proc/driver/rtc (procfs for rtc0)"
-	depends on RTC_CLASS && PROC_FS
+	depends on PROC_FS
 	default RTC_CLASS
 	help
 	  Say yes here if you want to use your first RTC through the proc
@@ -82,7 +84,6 @@
 
 config RTC_INTF_DEV
 	boolean "/dev/rtcN (character devices)"
-	depends on RTC_CLASS
 	default RTC_CLASS
 	help
 	  Say yes here if you want to use your RTCs using the /dev
@@ -104,7 +105,6 @@
 
 config RTC_DRV_TEST
 	tristate "Test driver/device"
-	depends on RTC_CLASS
 	help
 	  If you say yes here you get support for the
 	  RTC test driver. It's a software RTC which can be
@@ -118,11 +118,12 @@
 	  will be called rtc-test.
 
 comment "I2C RTC drivers"
-	depends on RTC_CLASS && I2C
+	depends on I2C
+
+if I2C
 
 config RTC_DRV_DS1307
 	tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00"
-	depends on RTC_CLASS && I2C
 	help
 	  If you say yes here you get support for various compatible RTC
 	  chips (often with battery backup) connected with I2C.  This driver
@@ -140,7 +141,6 @@
 
 config RTC_DRV_DS1672
 	tristate "Dallas/Maxim DS1672"
-	depends on RTC_CLASS && I2C
 	help
 	  If you say yes here you get support for the
 	  Dallas/Maxim DS1672 timekeeping chip.
@@ -150,7 +150,6 @@
 
 config RTC_DRV_MAX6900
 	tristate "Maxim 6900"
-	depends on RTC_CLASS && I2C
 	help
 	  If you say yes here you will get support for the
 	  Maxim MAX6900 I2C RTC chip.
@@ -160,7 +159,6 @@
 
 config RTC_DRV_RS5C372
 	tristate "Ricoh RS5C372A/B, RV5C386, RV5C387A"
-	depends on RTC_CLASS && I2C
 	help
 	  If you say yes here you get support for the
 	  Ricoh RS5C372A, RS5C372B, RV5C386, and RV5C387A RTC chips.
@@ -170,7 +168,6 @@
 
 config RTC_DRV_ISL1208
 	tristate "Intersil 1208"
-	depends on RTC_CLASS && I2C
 	help
 	  If you say yes here you get support for the
 	  Intersil 1208 RTC chip.
@@ -180,7 +177,6 @@
 
 config RTC_DRV_X1205
 	tristate "Xicor/Intersil X1205"
-	depends on RTC_CLASS && I2C
 	help
 	  If you say yes here you get support for the
 	  Xicor/Intersil X1205 RTC chip.
@@ -190,7 +186,6 @@
 
 config RTC_DRV_PCF8563
 	tristate "Philips PCF8563/Epson RTC8564"
-	depends on RTC_CLASS && I2C
 	help
 	  If you say yes here you get support for the
 	  Philips PCF8563 RTC chip. The Epson RTC8564
@@ -201,7 +196,6 @@
 
 config RTC_DRV_PCF8583
 	tristate "Philips PCF8583"
-	depends on RTC_CLASS && I2C
 	help
 	  If you say yes here you get support for the Philips PCF8583
 	  RTC chip found on Acorn RiscPCs. This driver supports the
@@ -214,7 +208,6 @@
 
 config RTC_DRV_M41T80
 	tristate "ST M41T80 series RTC"
-	depends on RTC_CLASS && I2C
 	help
 	  If you say Y here you will get support for the
 	  ST M41T80 RTC chips series. Currently following chips are
@@ -233,19 +226,21 @@
 
 config RTC_DRV_TWL92330
 	boolean "TI TWL92330/Menelaus"
-	depends on RTC_CLASS && I2C && MENELAUS
+	depends on MENELAUS
 	help
 	  If you say yes here you get support for the RTC on the
 	  TWL92330 "Menelaus" power mangement chip, used with OMAP2
 	  platforms.  The support is integrated with the rest of
 	  the Menelaus driver; it's not separate module.
 
+endif # I2C
+
 comment "SPI RTC drivers"
-	depends on RTC_CLASS && SPI_MASTER
+
+if SPI_MASTER
 
 config RTC_DRV_RS5C348
 	tristate "Ricoh RS5C348A/B"
-	depends on RTC_CLASS && SPI_MASTER
 	help
 	  If you say yes here you get support for the
 	  Ricoh RS5C348A and RS5C348B RTC chips.
@@ -255,7 +250,6 @@
 
 config RTC_DRV_MAX6902
 	tristate "Maxim 6902"
-	depends on RTC_CLASS && SPI_MASTER
 	help
 	  If you say yes here you will get support for the
 	  Maxim MAX6902 SPI RTC chip.
@@ -263,8 +257,9 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-max6902.
 
+endif # SPI_MASTER
+
 comment "Platform RTC drivers"
-	depends on RTC_CLASS
 
 # this 'CMOS' RTC driver is arch dependent because <asm-generic/rtc.h>
 # requires <asm/mc146818rtc.h> defining CMOS_READ/CMOS_WRITE, and a
@@ -272,8 +267,7 @@
 
 config RTC_DRV_CMOS
 	tristate "PC-style 'CMOS'"
-	depends on RTC_CLASS && (X86 || ALPHA || ARM26 || ARM \
-		|| M32R || ATARI || PPC || MIPS)
+	depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS
 	help
 	  Say "yes" here to get direct support for the real time clock
 	  found in every PC or ACPI-based system, and some other boards.
@@ -291,13 +285,12 @@
 
 config RTC_DRV_DS1216
 	tristate "Dallas DS1216"
-	depends on RTC_CLASS && SNI_RM
+	depends on SNI_RM
 	help
 	  If you say yes here you get support for the Dallas DS1216 RTC chips.
 
 config RTC_DRV_DS1553
 	tristate "Dallas DS1553"
-	depends on RTC_CLASS
 	help
 	  If you say yes here you get support for the
 	  Dallas DS1553 timekeeping chip.
@@ -305,9 +298,18 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-ds1553.
 
+config RTC_DRV_STK17TA8
+	tristate "Simtek STK17TA8"
+	depends on RTC_CLASS
+	help
+	  If you say yes here you get support for the
+	  Simtek STK17TA8 timekeeping chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-stk17ta8.
+
 config RTC_DRV_DS1742
 	tristate "Dallas DS1742/1743"
-	depends on RTC_CLASS
 	help
 	  If you say yes here you get support for the
 	  Dallas DS1742/1743 timekeeping chip.
@@ -317,7 +319,6 @@
 
 config RTC_DRV_M48T86
 	tristate "ST M48T86/Dallas DS12887"
-	depends on RTC_CLASS
 	help
 	  If you say Y here you will get support for the
 	  ST M48T86 and Dallas DS12887 RTC chips.
@@ -327,7 +328,6 @@
 
 config RTC_DRV_M48T59
 	tristate "ST M48T59"
-	depends on RTC_CLASS
 	help
 	  If you say Y here you will get support for the
 	  ST M48T59 RTC chip.
@@ -337,7 +337,6 @@
 
 config RTC_DRV_V3020
 	tristate "EM Microelectronic V3020"
-	depends on RTC_CLASS
 	help
 	  If you say yes here you will get support for the
 	  EM Microelectronic v3020 RTC chip.
@@ -346,19 +345,17 @@
 	  will be called rtc-v3020.
 
 comment "on-CPU RTC drivers"
-	depends on RTC_CLASS
 
 config RTC_DRV_OMAP
 	tristate "TI OMAP1"
-	depends on RTC_CLASS && ( \
-		ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 )
+	depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730
 	help
 	  Say "yes" here to support the real time clock on TI OMAP1 chips.
 	  This driver can also be built as a module called rtc-omap.
 
 config RTC_DRV_S3C
 	tristate "Samsung S3C series SoC RTC"
-	depends on RTC_CLASS && ARCH_S3C2410
+	depends on ARCH_S3C2410
 	help
 	  RTC (Realtime Clock) driver for the clock inbuilt into the
 	  Samsung S3C24XX series of SoCs. This can provide periodic
@@ -374,7 +371,7 @@
 
 config RTC_DRV_EP93XX
 	tristate "Cirrus Logic EP93XX"
-	depends on RTC_CLASS && ARCH_EP93XX
+	depends on ARCH_EP93XX
 	help
 	  If you say yes here you get support for the
 	  RTC embedded in the Cirrus Logic EP93XX processors.
@@ -384,7 +381,7 @@
 
 config RTC_DRV_SA1100
 	tristate "SA11x0/PXA2xx"
-	depends on RTC_CLASS && (ARCH_SA1100 || ARCH_PXA)
+	depends on ARCH_SA1100 || ARCH_PXA
 	help
 	  If you say Y here you will get access to the real time clock
 	  built into your SA11x0 or PXA2xx CPU.
@@ -394,7 +391,7 @@
 
 config RTC_DRV_SH
 	tristate "SuperH On-Chip RTC"
-	depends on RTC_CLASS && SUPERH
+	depends on RTC_CLASS && (CPU_SH3 || CPU_SH4)
 	help
 	  Say Y here to enable support for the on-chip RTC found in
 	  most SuperH processors.
@@ -404,7 +401,7 @@
 
 config RTC_DRV_VR41XX
 	tristate "NEC VR41XX"
-	depends on RTC_CLASS && CPU_VR41XX
+	depends on CPU_VR41XX
 	help
 	  If you say Y here you will get access to the real time clock
 	  built into your NEC VR41XX CPU.
@@ -414,7 +411,7 @@
 
 config RTC_DRV_PL031
 	tristate "ARM AMBA PL031 RTC"
-	depends on RTC_CLASS && ARM_AMBA
+	depends on ARM_AMBA
 	help
 	  If you say Y here you will get access to ARM AMBA
 	  PrimeCell PL031 RTC found on certain ARM SOCs.
@@ -424,20 +421,20 @@
 
 config RTC_DRV_AT32AP700X
 	tristate "AT32AP700X series RTC"
-	depends on RTC_CLASS && PLATFORM_AT32AP
+	depends on PLATFORM_AT32AP
 	help
 	  Driver for the internal RTC (Realtime Clock) on Atmel AVR32
 	  AT32AP700x family processors.
 
 config RTC_DRV_AT91RM9200
 	tristate "AT91RM9200"
-	depends on RTC_CLASS && ARCH_AT91RM9200
+	depends on ARCH_AT91RM9200
 	help
 	  Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock).
 
 config RTC_DRV_BFIN
 	tristate "Blackfin On-Chip RTC"
-	depends on RTC_CLASS && BFIN
+	depends on BFIN
 	help
 	  If you say yes here you will get support for the
 	  Blackfin On-Chip Real Time Clock.
@@ -447,8 +444,8 @@
 
 config RTC_DRV_RS5C313
 	tristate "Ricoh RS5C313"
-	depends on RTC_CLASS && SH_LANDISK
+	depends on SH_LANDISK
 	help
 	  If you say yes here you get support for the Ricoh RS5C313 RTC chips.
 
-endmenu
+endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 3109af9..d3a33aa 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -15,33 +15,36 @@
 rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
 rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
 
+# Keep the list ordered.
+
+obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
+obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
+obj-$(CONFIG_RTC_DRV_BFIN)	+= rtc-bfin.o
 obj-$(CONFIG_RTC_DRV_CMOS)	+= rtc-cmos.o
-obj-$(CONFIG_RTC_DRV_X1205)	+= rtc-x1205.o
-obj-$(CONFIG_RTC_DRV_ISL1208)	+= rtc-isl1208.o
-obj-$(CONFIG_RTC_DRV_TEST)	+= rtc-test.o
-obj-$(CONFIG_RTC_DRV_AT32AP700X)	+= rtc-at32ap700x.o
+obj-$(CONFIG_RTC_DRV_DS1216)	+= rtc-ds1216.o
 obj-$(CONFIG_RTC_DRV_DS1307)	+= rtc-ds1307.o
+obj-$(CONFIG_RTC_DRV_DS1553)	+= rtc-ds1553.o
 obj-$(CONFIG_RTC_DRV_DS1672)	+= rtc-ds1672.o
 obj-$(CONFIG_RTC_DRV_DS1742)	+= rtc-ds1742.o
+obj-$(CONFIG_RTC_DRV_EP93XX)	+= rtc-ep93xx.o
+obj-$(CONFIG_RTC_DRV_ISL1208)	+= rtc-isl1208.o
+obj-$(CONFIG_RTC_DRV_M41T80)	+= rtc-m41t80.o
+obj-$(CONFIG_RTC_DRV_M48T59)	+= rtc-m48t59.o
+obj-$(CONFIG_RTC_DRV_M48T86)	+= rtc-m48t86.o
+obj-$(CONFIG_RTC_DRV_MAX6900)	+= rtc-max6900.o
+obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o
 obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
 obj-$(CONFIG_RTC_DRV_PCF8563)	+= rtc-pcf8563.o
 obj-$(CONFIG_RTC_DRV_PCF8583)	+= rtc-pcf8583.o
+obj-$(CONFIG_RTC_DRV_PL031)	+= rtc-pl031.o
+obj-$(CONFIG_RTC_DRV_RS5C313)	+= rtc-rs5c313.o
+obj-$(CONFIG_RTC_DRV_RS5C348)	+= rtc-rs5c348.o
 obj-$(CONFIG_RTC_DRV_RS5C372)	+= rtc-rs5c372.o
 obj-$(CONFIG_RTC_DRV_S3C)	+= rtc-s3c.o
-obj-$(CONFIG_RTC_DRV_RS5C348)	+= rtc-rs5c348.o
-obj-$(CONFIG_RTC_DRV_M41T80)	+= rtc-m41t80.o
-obj-$(CONFIG_RTC_DRV_M48T86)	+= rtc-m48t86.o
-obj-$(CONFIG_RTC_DRV_DS1553)	+= rtc-ds1553.o
-obj-$(CONFIG_RTC_DRV_RS5C313)	+= rtc-rs5c313.o
-obj-$(CONFIG_RTC_DRV_EP93XX)	+= rtc-ep93xx.o
 obj-$(CONFIG_RTC_DRV_SA1100)	+= rtc-sa1100.o
-obj-$(CONFIG_RTC_DRV_VR41XX)	+= rtc-vr41xx.o
-obj-$(CONFIG_RTC_DRV_PL031)	+= rtc-pl031.o
-obj-$(CONFIG_RTC_DRV_MAX6900)	+= rtc-max6900.o
-obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o
-obj-$(CONFIG_RTC_DRV_V3020)	+= rtc-v3020.o
-obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
 obj-$(CONFIG_RTC_DRV_SH)	+= rtc-sh.o
-obj-$(CONFIG_RTC_DRV_BFIN)	+= rtc-bfin.o
-obj-$(CONFIG_RTC_DRV_M48T59)	+= rtc-m48t59.o
-obj-$(CONFIG_RTC_DRV_DS1216)	+= rtc-ds1216.o
+obj-$(CONFIG_RTC_DRV_STK17TA8)	+= rtc-stk17ta8.o
+obj-$(CONFIG_RTC_DRV_TEST)	+= rtc-test.o
+obj-$(CONFIG_RTC_DRV_V3020)	+= rtc-v3020.o
+obj-$(CONFIG_RTC_DRV_VR41XX)	+= rtc-vr41xx.o
+obj-$(CONFIG_RTC_DRV_X1205)	+= rtc-x1205.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 8b3cd31..10ab3b7 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -46,6 +46,7 @@
 {
 	struct rtc_device	*rtc = to_rtc_device(dev);
 	struct rtc_time		tm;
+	struct timespec		ts = current_kernel_time();
 
 	if (strncmp(rtc->dev.bus_id,
 				CONFIG_RTC_HCTOSYS_DEVICE,
@@ -57,8 +58,8 @@
 
 	/* RTC precision is 1 second; adjust delta for avg 1/2 sec err */
 	set_normalized_timespec(&delta,
-				xtime.tv_sec - oldtime,
-				xtime.tv_nsec - (NSEC_PER_SEC >> 1));
+				ts.tv_sec - oldtime,
+				ts.tv_nsec - (NSEC_PER_SEC >> 1));
 
 	return 0;
 }
diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c
index 260ead9..1aa709d 100644
--- a/drivers/rtc/rtc-bfin.c
+++ b/drivers/rtc/rtc-bfin.c
@@ -1,6 +1,6 @@
 /*
  * Blackfin On-Chip Real Time Clock Driver
- *  Supports BF531/BF532/BF533/BF534/BF536/BF537
+ *  Supports BF53[123]/BF53[467]/BF54[2489]
  *
  * Copyright 2004-2007 Analog Devices Inc.
  *
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index e24ea82..5d760bb 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -235,7 +235,7 @@
 	return 0;
 }
 
-static int cmos_set_freq(struct device *dev, int freq)
+static int cmos_irq_set_freq(struct device *dev, int freq)
 {
 	struct cmos_rtc	*cmos = dev_get_drvdata(dev);
 	int		f;
@@ -259,6 +259,34 @@
 	return 0;
 }
 
+static int cmos_irq_set_state(struct device *dev, int enabled)
+{
+	struct cmos_rtc	*cmos = dev_get_drvdata(dev);
+	unsigned char	rtc_control, rtc_intr;
+	unsigned long	flags;
+
+	if (!is_valid_irq(cmos->irq))
+		return -ENXIO;
+
+	spin_lock_irqsave(&rtc_lock, flags);
+	rtc_control = CMOS_READ(RTC_CONTROL);
+
+	if (enabled)
+		rtc_control |= RTC_PIE;
+	else
+		rtc_control &= ~RTC_PIE;
+
+	CMOS_WRITE(rtc_control, RTC_CONTROL);
+
+	rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
+	rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+	if (is_intr(rtc_intr))
+		rtc_update_irq(cmos->rtc, 1, rtc_intr);
+
+	spin_unlock_irqrestore(&rtc_lock, flags);
+	return 0;
+}
+
 #if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)
 
 static int
@@ -360,7 +388,8 @@
 	.read_alarm	= cmos_read_alarm,
 	.set_alarm	= cmos_set_alarm,
 	.proc		= cmos_procfs,
-	.irq_set_freq	= cmos_set_freq,
+	.irq_set_freq	= cmos_irq_set_freq,
+	.irq_set_state	= cmos_irq_set_state,
 };
 
 /*----------------------------------------------------------------*/
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 3045359..005fff3 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -348,6 +348,8 @@
 	case RTC_IRQP_SET:
 		if (ops->irq_set_freq)
 			err = rtc_irq_set_freq(rtc, rtc->irq_task, arg);
+		else
+			err = -ENOTTY;
 		break;
 
 #if 0
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 5158a62..db6f3f0 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -352,7 +352,7 @@
 		/* oscillator fault?  clear flag, and warn */
 		if (ds1307->regs[DS1307_REG_CONTROL] & DS1338_BIT_OSF) {
 			i2c_smbus_write_byte_data(client, DS1307_REG_CONTROL,
-					ds1307->regs[DS1337_REG_CONTROL]
+					ds1307->regs[DS1307_REG_CONTROL]
 					& ~DS1338_BIT_OSF);
 			dev_warn(&client->dev, "SET TIME!\n");
 			goto read_rtc;
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index f98a83a1..5ab3492 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -61,7 +61,7 @@
 struct rtc_plat_data {
 	struct rtc_device *rtc;
 	void __iomem *ioaddr;
-	unsigned long baseaddr;
+	resource_size_t baseaddr;
 	unsigned long last_jiffies;
 	int irq;
 	unsigned int irqen;
@@ -407,7 +407,7 @@
 
 static __exit void ds1553_exit(void)
 {
-	return platform_driver_unregister(&ds1553_rtc_driver);
+	platform_driver_unregister(&ds1553_rtc_driver);
 }
 
 module_init(ds1553_init);
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index d1778ae..67291b0 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -55,7 +55,7 @@
 	void __iomem *ioaddr_rtc;
 	size_t size_nvram;
 	size_t size;
-	unsigned long baseaddr;
+	resource_size_t baseaddr;
 	unsigned long last_jiffies;
 };
 
@@ -263,7 +263,7 @@
 
 static __exit void ds1742_exit(void)
 {
-	return platform_driver_unregister(&ds1742_rtc_driver);
+	platform_driver_unregister(&ds1742_rtc_driver);
 }
 
 module_init(ds1742_init);
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index 80c4a84..1cb33ca 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -892,7 +892,7 @@
 
 static struct i2c_driver m41t80_driver = {
 	.driver = {
-		.name = "m41t80",
+		.name = "rtc-m41t80",
 	},
 	.probe = m41t80_probe,
 	.remove = m41t80_remove,
diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c
index 33b7523..bf60d35 100644
--- a/drivers/rtc/rtc-m48t59.c
+++ b/drivers/rtc/rtc-m48t59.c
@@ -35,7 +35,7 @@
 struct m48t59_private {
 	void __iomem *ioaddr;
 	unsigned int size; /* iomem size */
-	unsigned int irq;
+	int irq;
 	struct rtc_device *rtc;
 	spinlock_t lock; /* serialize the NVRAM and RTC access */
 };
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
index eee4ee5..a1cd448 100644
--- a/drivers/rtc/rtc-max6900.c
+++ b/drivers/rtc/rtc-max6900.c
@@ -31,17 +31,24 @@
 #define MAX6900_REG_DW			5	/* day of week	 1-7  */
 #define MAX6900_REG_YR			6	/* year		00-99 */
 #define MAX6900_REG_CT			7	/* control */
-#define MAX6900_REG_LEN			8
+						/* register 8 is undocumented */
+#define MAX6900_REG_CENTURY		9	/* century */
+#define MAX6900_REG_LEN			10
+
+#define MAX6900_BURST_LEN		8	/* can burst r/w first 8 regs */
 
 #define MAX6900_REG_CT_WP		(1 << 7)	/* Write Protect */
 
+
 /*
  * register read/write commands
  */
 #define MAX6900_REG_CONTROL_WRITE	0x8e
-#define MAX6900_REG_BURST_READ		0xbf
-#define MAX6900_REG_BURST_WRITE		0xbe
+#define MAX6900_REG_CENTURY_WRITE	0x92
+#define MAX6900_REG_CENTURY_READ	0x93
 #define MAX6900_REG_RESERVED_READ	0x96
+#define MAX6900_REG_BURST_WRITE		0xbe
+#define MAX6900_REG_BURST_READ		0xbf
 
 #define MAX6900_IDLE_TIME_AFTER_WRITE	3	/* specification says 2.5 mS */
 
@@ -58,19 +65,32 @@
 
 static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
 {
-	u8 reg_addr[1] = { MAX6900_REG_BURST_READ };
-	struct i2c_msg msgs[2] = {
+	u8 reg_burst_read[1] = { MAX6900_REG_BURST_READ };
+	u8 reg_century_read[1] = { MAX6900_REG_CENTURY_READ };
+	struct i2c_msg msgs[4] = {
 		{
 			.addr	= client->addr,
 			.flags	= 0, /* write */
-			.len	= sizeof(reg_addr),
-			.buf	= reg_addr
+			.len	= sizeof(reg_burst_read),
+			.buf	= reg_burst_read
 		},
 		{
 			.addr	= client->addr,
 			.flags	= I2C_M_RD,
-			.len	= MAX6900_REG_LEN,
+			.len	= MAX6900_BURST_LEN,
 			.buf	= buf
+		},
+		{
+			.addr	= client->addr,
+			.flags	= 0, /* write */
+			.len	= sizeof(reg_century_read),
+			.buf	= reg_century_read
+		},
+		{
+			.addr	= client->addr,
+			.flags	= I2C_M_RD,
+			.len	= sizeof(buf[MAX6900_REG_CENTURY]),
+			.buf	= &buf[MAX6900_REG_CENTURY]
 		}
 	};
 	int rc;
@@ -86,33 +106,58 @@
 
 static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
 {
-	u8 i2c_buf[MAX6900_REG_LEN + 1] = { MAX6900_REG_BURST_WRITE };
-	struct i2c_msg msgs[1] = {
+	u8 i2c_century_buf[1 + 1] = { MAX6900_REG_CENTURY_WRITE };
+	struct i2c_msg century_msgs[1] = {
 		{
 			.addr	= client->addr,
 			.flags	= 0, /* write */
-			.len	= MAX6900_REG_LEN + 1,
-			.buf	= i2c_buf
+			.len	= sizeof(i2c_century_buf),
+			.buf	= i2c_century_buf
+		}
+	};
+	u8 i2c_burst_buf[MAX6900_BURST_LEN + 1] = { MAX6900_REG_BURST_WRITE };
+	struct i2c_msg burst_msgs[1] = {
+		{
+			.addr	= client->addr,
+			.flags	= 0, /* write */
+			.len	= sizeof(i2c_burst_buf),
+			.buf	= i2c_burst_buf
 		}
 	};
 	int rc;
 
-	memcpy(&i2c_buf[1], buf, MAX6900_REG_LEN);
-
-	rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
-	if (rc != ARRAY_SIZE(msgs)) {
-		dev_err(&client->dev, "%s: register write failed\n",
-			__FUNCTION__);
-		return -EIO;
-	}
+	/*
+	 * We have to make separate calls to i2c_transfer because of
+	 * the need to delay after each write to the chip.  Also,
+	 * we write the century byte first, since we set the write-protect
+	 * bit as part of the burst write.
+	 */
+	i2c_century_buf[1] = buf[MAX6900_REG_CENTURY];
+	rc = i2c_transfer(client->adapter, century_msgs,
+			  ARRAY_SIZE(century_msgs));
+	if (rc != ARRAY_SIZE(century_msgs))
+		goto write_failed;
 	msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
+
+	memcpy(&i2c_burst_buf[1], buf, MAX6900_BURST_LEN);
+
+	rc = i2c_transfer(client->adapter, burst_msgs, ARRAY_SIZE(burst_msgs));
+	if (rc != ARRAY_SIZE(burst_msgs))
+		goto write_failed;
+	msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
+
 	return 0;
+
+write_failed:
+	dev_err(&client->dev, "%s: register write failed\n",
+		__FUNCTION__);
+	return -EIO;
 }
 
 static int max6900_i2c_validate_client(struct i2c_client *client)
 {
 	u8 regs[MAX6900_REG_LEN];
-	u8 zero_mask[MAX6900_REG_LEN] = {
+	u8 zero_mask[] = {
 		0x80,	/* seconds */
 		0x80,	/* minutes */
 		0x40,	/* hours */
@@ -134,7 +179,7 @@
 	if (rc < 0)
 		return rc;
 
-	for (i = 0; i < MAX6900_REG_LEN; ++i) {
+	for (i = 0; i < ARRAY_SIZE(zero_mask); ++i) {
 		if (regs[i] & zero_mask[i])
 			return -ENODEV;
 	}
@@ -156,7 +201,8 @@
 	tm->tm_hour = BCD2BIN(regs[MAX6900_REG_HR] & 0x3f);
 	tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]);
 	tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1;
-	tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) + 100;
+	tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) +
+		      BCD2BIN(regs[MAX6900_REG_CENTURY]) * 100 - 1900;
 	tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]);
 
 	return 0;
@@ -189,9 +235,11 @@
 	regs[MAX6900_REG_HR] = BIN2BCD(tm->tm_hour);
 	regs[MAX6900_REG_DT] = BIN2BCD(tm->tm_mday);
 	regs[MAX6900_REG_MO] = BIN2BCD(tm->tm_mon + 1);
-	regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year - 100);
 	regs[MAX6900_REG_DW] = BIN2BCD(tm->tm_wday);
-	regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP;	/* set write protect */
+	regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year % 100);
+	regs[MAX6900_REG_CENTURY] = BIN2BCD((tm->tm_year + 1900) / 100);
+	/* set write protect */
+	regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP;
 
 	rc = max6900_i2c_write_regs(client, regs);
 	if (rc < 0)
diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c
index d941707..3e183cf 100644
--- a/drivers/rtc/rtc-max6902.c
+++ b/drivers/rtc/rtc-max6902.c
@@ -13,7 +13,7 @@
  *
  * 24-May-2006: Raphael Assenat <raph@8d.com>
  *                - Major rework
- *   				Converted to rtc_device and uses the SPI layer.
+ *				Converted to rtc_device and uses the SPI layer.
  *
  * ??-???-2005: Someone at Compulab
  *                - Initial driver creation.
@@ -259,11 +259,11 @@
 
 static struct spi_driver max6902_driver = {
 	.driver = {
-		.name 	= "max6902",
+		.name	= "rtc-max6902",
 		.bus	= &spi_bus_type,
 		.owner	= THIS_MODULE,
 	},
-	.probe 	= max6902_probe,
+	.probe	= max6902_probe,
 	.remove = __devexit_p(max6902_remove),
 };
 
diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c
index f50f3fc..8394626 100644
--- a/drivers/rtc/rtc-rs5c348.c
+++ b/drivers/rtc/rtc-rs5c348.c
@@ -226,7 +226,7 @@
 
 static struct spi_driver rs5c348_driver = {
 	.driver = {
-		.name	= "rs5c348",
+		.name	= "rtc-rs5c348",
 		.bus	= &spi_bus_type,
 		.owner	= THIS_MODULE,
 	},
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 54b6130..8c1012b 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -29,7 +29,7 @@
 
 #include <asm/mach/time.h>
 
-#include <asm/arch/regs-rtc.h>
+#include <asm/plat-s3c/regs-rtc.h>
 
 /* I have yet to find an S3C implementation with more than one
  * of these rtc blocks in */
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index e0f91df..93ee05e 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -365,6 +365,7 @@
 	/* Reset pre-scaler & stop RTC */
 	tmp = readb(rtc->regbase + RCR2);
 	tmp |= RCR2_RESET;
+	tmp &= ~RCR2_START;
 	writeb(tmp, rtc->regbase + RCR2);
 
 	writeb(BIN2BCD(tm->tm_sec),  rtc->regbase + RSECCNT);
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
new file mode 100644
index 0000000..8288b6b
--- /dev/null
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -0,0 +1,422 @@
+/*
+ * A RTC driver for the Simtek STK17TA8
+ *
+ * By Thomas Hommel <thomas.hommel@gefanuc.com>
+ *
+ * Based on the DS1553 driver from
+ * Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * 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/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_VERSION "0.1"
+
+#define RTC_REG_SIZE		0x20000
+#define RTC_OFFSET		0x1fff0
+
+#define RTC_FLAGS		(RTC_OFFSET + 0)
+#define RTC_CENTURY		(RTC_OFFSET + 1)
+#define RTC_SECONDS_ALARM	(RTC_OFFSET + 2)
+#define RTC_MINUTES_ALARM	(RTC_OFFSET + 3)
+#define RTC_HOURS_ALARM		(RTC_OFFSET + 4)
+#define RTC_DATE_ALARM		(RTC_OFFSET + 5)
+#define RTC_INTERRUPTS		(RTC_OFFSET + 6)
+#define RTC_WATCHDOG		(RTC_OFFSET + 7)
+#define RTC_CALIBRATION		(RTC_OFFSET + 8)
+#define RTC_SECONDS		(RTC_OFFSET + 9)
+#define RTC_MINUTES		(RTC_OFFSET + 10)
+#define RTC_HOURS		(RTC_OFFSET + 11)
+#define RTC_DAY			(RTC_OFFSET + 12)
+#define RTC_DATE		(RTC_OFFSET + 13)
+#define RTC_MONTH		(RTC_OFFSET + 14)
+#define RTC_YEAR		(RTC_OFFSET + 15)
+
+#define RTC_SECONDS_MASK	0x7f
+#define RTC_DAY_MASK		0x07
+#define RTC_CAL_MASK		0x3f
+
+/* Bits in the Calibration register */
+#define RTC_STOP		0x80
+
+/* Bits in the Flags register */
+#define RTC_FLAGS_AF		0x40
+#define RTC_FLAGS_PF		0x20
+#define RTC_WRITE		0x02
+#define RTC_READ		0x01
+
+/* Bits in the Interrupts register */
+#define RTC_INTS_AIE		0x40
+
+struct rtc_plat_data {
+	struct rtc_device *rtc;
+	void __iomem *ioaddr;
+	unsigned long baseaddr;
+	unsigned long last_jiffies;
+	int irq;
+	unsigned int irqen;
+	int alrm_sec;
+	int alrm_min;
+	int alrm_hour;
+	int alrm_mday;
+};
+
+static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	u8 flags;
+
+	flags = readb(pdata->ioaddr + RTC_FLAGS);
+	writeb(flags | RTC_WRITE, pdata->ioaddr + RTC_FLAGS);
+
+	writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR);
+	writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH);
+	writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
+	writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE);
+	writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS);
+	writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES);
+	writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
+	writeb(BIN2BCD((tm->tm_year + 1900) / 100), ioaddr + RTC_CENTURY);
+
+	writeb(flags & ~RTC_WRITE, pdata->ioaddr + RTC_FLAGS);
+	return 0;
+}
+
+static int stk17ta8_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	unsigned int year, month, day, hour, minute, second, week;
+	unsigned int century;
+	u8 flags;
+
+	/* give enough time to update RTC in case of continuous read */
+	if (pdata->last_jiffies == jiffies)
+		msleep(1);
+	pdata->last_jiffies = jiffies;
+
+	flags = readb(pdata->ioaddr + RTC_FLAGS);
+	writeb(flags | RTC_READ, ioaddr + RTC_FLAGS);
+	second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK;
+	minute = readb(ioaddr + RTC_MINUTES);
+	hour = readb(ioaddr + RTC_HOURS);
+	day = readb(ioaddr + RTC_DATE);
+	week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK;
+	month = readb(ioaddr + RTC_MONTH);
+	year = readb(ioaddr + RTC_YEAR);
+	century = readb(ioaddr + RTC_CENTURY);
+	writeb(flags & ~RTC_READ, ioaddr + RTC_FLAGS);
+	tm->tm_sec = BCD2BIN(second);
+	tm->tm_min = BCD2BIN(minute);
+	tm->tm_hour = BCD2BIN(hour);
+	tm->tm_mday = BCD2BIN(day);
+	tm->tm_wday = BCD2BIN(week);
+	tm->tm_mon = BCD2BIN(month) - 1;
+	/* year is 1900 + tm->tm_year */
+	tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900;
+
+	if (rtc_valid_tm(tm) < 0) {
+		dev_err(dev, "retrieved date/time is not valid.\n");
+		rtc_time_to_tm(0, tm);
+	}
+	return 0;
+}
+
+static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata)
+{
+	void __iomem *ioaddr = pdata->ioaddr;
+	unsigned long irqflags;
+	u8 flags;
+
+	spin_lock_irqsave(&pdata->rtc->irq_lock, irqflags);
+
+	flags = readb(ioaddr + RTC_FLAGS);
+	writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS);
+
+	writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
+	       0x80 : BIN2BCD(pdata->alrm_mday),
+	       ioaddr + RTC_DATE_ALARM);
+	writeb(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
+	       0x80 : BIN2BCD(pdata->alrm_hour),
+	       ioaddr + RTC_HOURS_ALARM);
+	writeb(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
+	       0x80 : BIN2BCD(pdata->alrm_min),
+	       ioaddr + RTC_MINUTES_ALARM);
+	writeb(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
+	       0x80 : BIN2BCD(pdata->alrm_sec),
+	       ioaddr + RTC_SECONDS_ALARM);
+	writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS);
+	readb(ioaddr + RTC_FLAGS);	/* clear interrupts */
+	writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS);
+	spin_unlock_irqrestore(&pdata->rtc->irq_lock, irqflags);
+}
+
+static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+	if (pdata->irq < 0)
+		return -EINVAL;
+	pdata->alrm_mday = alrm->time.tm_mday;
+	pdata->alrm_hour = alrm->time.tm_hour;
+	pdata->alrm_min = alrm->time.tm_min;
+	pdata->alrm_sec = alrm->time.tm_sec;
+	if (alrm->enabled)
+		pdata->irqen |= RTC_AF;
+	stk17ta8_rtc_update_alarm(pdata);
+	return 0;
+}
+
+static int stk17ta8_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+	if (pdata->irq < 0)
+		return -EINVAL;
+	alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
+	alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
+	alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
+	alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
+	alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
+	return 0;
+}
+
+static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	unsigned long events = RTC_IRQF;
+
+	/* read and clear interrupt */
+	if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF))
+		return IRQ_NONE;
+	if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80)
+		events |= RTC_UF;
+	else
+		events |= RTC_AF;
+	rtc_update_irq(pdata->rtc, 1, events);
+	return IRQ_HANDLED;
+}
+
+static void stk17ta8_rtc_release(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+	if (pdata->irq >= 0) {
+		pdata->irqen = 0;
+		stk17ta8_rtc_update_alarm(pdata);
+	}
+}
+
+static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd,
+			    unsigned long arg)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+	if (pdata->irq < 0)
+		return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */
+	switch (cmd) {
+	case RTC_AIE_OFF:
+		pdata->irqen &= ~RTC_AF;
+		stk17ta8_rtc_update_alarm(pdata);
+		break;
+	case RTC_AIE_ON:
+		pdata->irqen |= RTC_AF;
+		stk17ta8_rtc_update_alarm(pdata);
+		break;
+	default:
+		return -ENOIOCTLCMD;
+	}
+	return 0;
+}
+
+static const struct rtc_class_ops stk17ta8_rtc_ops = {
+	.read_time	= stk17ta8_rtc_read_time,
+	.set_time	= stk17ta8_rtc_set_time,
+	.read_alarm	= stk17ta8_rtc_read_alarm,
+	.set_alarm	= stk17ta8_rtc_set_alarm,
+	.release	= stk17ta8_rtc_release,
+	.ioctl		= stk17ta8_rtc_ioctl,
+};
+
+static ssize_t stk17ta8_nvram_read(struct kobject *kobj,
+				 struct bin_attribute *attr, char *buf,
+				 loff_t pos, size_t size)
+{
+	struct platform_device *pdev =
+		to_platform_device(container_of(kobj, struct device, kobj));
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	ssize_t count;
+
+	for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+		*buf++ = readb(ioaddr + pos++);
+	return count;
+}
+
+static ssize_t stk17ta8_nvram_write(struct kobject *kobj,
+				  struct bin_attribute *attr, char *buf,
+				  loff_t pos, size_t size)
+{
+	struct platform_device *pdev =
+		to_platform_device(container_of(kobj, struct device, kobj));
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	void __iomem *ioaddr = pdata->ioaddr;
+	ssize_t count;
+
+	for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+		writeb(*buf++, ioaddr + pos++);
+	return count;
+}
+
+static struct bin_attribute stk17ta8_nvram_attr = {
+	.attr = {
+		.name = "nvram",
+		.mode = S_IRUGO | S_IWUGO,
+		.owner = THIS_MODULE,
+	},
+	.size = RTC_OFFSET,
+	.read = stk17ta8_nvram_read,
+	.write = stk17ta8_nvram_write,
+};
+
+static int __init stk17ta8_rtc_probe(struct platform_device *pdev)
+{
+	struct rtc_device *rtc;
+	struct resource *res;
+	unsigned int cal;
+	unsigned int flags;
+	struct rtc_plat_data *pdata;
+	void __iomem *ioaddr = NULL;
+	int ret = 0;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return -ENOMEM;
+	pdata->irq = -1;
+	if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) {
+		ret = -EBUSY;
+		goto out;
+	}
+	pdata->baseaddr = res->start;
+	ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE);
+	if (!ioaddr) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	pdata->ioaddr = ioaddr;
+	pdata->irq = platform_get_irq(pdev, 0);
+
+	/* turn RTC on if it was not on */
+	cal = readb(ioaddr + RTC_CALIBRATION);
+	if (cal & RTC_STOP) {
+		cal &= RTC_CAL_MASK;
+		flags = readb(ioaddr + RTC_FLAGS);
+		writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS);
+		writeb(cal, ioaddr + RTC_CALIBRATION);
+		writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS);
+	}
+	if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF)
+		dev_warn(&pdev->dev, "voltage-low detected.\n");
+
+	if (pdata->irq >= 0) {
+		writeb(0, ioaddr + RTC_INTERRUPTS);
+		if (request_irq(pdata->irq, stk17ta8_rtc_interrupt,
+				IRQF_DISABLED | IRQF_SHARED,
+				pdev->name, pdev) < 0) {
+			dev_warn(&pdev->dev, "interrupt not available.\n");
+			pdata->irq = -1;
+		}
+	}
+
+	rtc = rtc_device_register(pdev->name, &pdev->dev,
+				  &stk17ta8_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc)) {
+		ret = PTR_ERR(rtc);
+		goto out;
+	}
+	pdata->rtc = rtc;
+	pdata->last_jiffies = jiffies;
+	platform_set_drvdata(pdev, pdata);
+	ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
+	if (ret)
+		goto out;
+	return 0;
+ out:
+	if (pdata->rtc)
+		rtc_device_unregister(pdata->rtc);
+	if (pdata->irq >= 0)
+		free_irq(pdata->irq, pdev);
+	if (ioaddr)
+		iounmap(ioaddr);
+	if (pdata->baseaddr)
+		release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+	kfree(pdata);
+	return ret;
+}
+
+static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev)
+{
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+	sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
+	rtc_device_unregister(pdata->rtc);
+	if (pdata->irq >= 0) {
+		writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
+		free_irq(pdata->irq, pdev);
+	}
+	iounmap(pdata->ioaddr);
+	release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+	kfree(pdata);
+	return 0;
+}
+
+static struct platform_driver stk17ta8_rtc_driver = {
+	.probe		= stk17ta8_rtc_probe,
+	.remove		= __devexit_p(stk17ta8_rtc_remove),
+	.driver		= {
+		.name	= "stk17ta8",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static __init int stk17ta8_init(void)
+{
+	return platform_driver_register(&stk17ta8_rtc_driver);
+}
+
+static __exit void stk17ta8_exit(void)
+{
+	return platform_driver_unregister(&stk17ta8_rtc_driver);
+}
+
+module_init(stk17ta8_init);
+module_exit(stk17ta8_exit);
+
+MODULE_AUTHOR("Thomas Hommel <thomas.hommel@gefanuc.com>");
+MODULE_DESCRIPTION("Simtek STK17TA8 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
index 3b58d3d..a6b5729 100644
--- a/drivers/rtc/rtc-v3020.c
+++ b/drivers/rtc/rtc-v3020.c
@@ -26,6 +26,7 @@
 #include <linux/types.h>
 #include <linux/bcd.h>
 #include <linux/rtc-v3020.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 
@@ -47,6 +48,7 @@
 	for (i = 0; i < 4; i++) {
 		writel((tmp & 1) << chip->leftshift, chip->ioaddress);
 		tmp >>= 1;
+		udelay(1);
 	}
 
 	/* Commands dont have data */
@@ -54,6 +56,7 @@
 		for (i = 0; i < 8; i++) {
 			writel((data & 1) << chip->leftshift, chip->ioaddress);
 			data >>= 1;
+			udelay(1);
 		}
 	}
 }
@@ -66,12 +69,14 @@
 	for (i = 0; i < 4; i++) {
 		writel((address & 1) << chip->leftshift, chip->ioaddress);
 		address >>= 1;
+		udelay(1);
 	}
 
 	for (i = 0; i < 8; i++) {
 		data >>= 1;
 		if (readl(chip->ioaddress) & (1 << chip->leftshift))
 			data |= 0x80;
+		udelay(1);
 	}
 
 	return data;
@@ -95,7 +100,7 @@
 	tmp = v3020_get_reg(chip, V3020_MONTH_DAY);
 	dt->tm_mday	= BCD2BIN(tmp);
 	tmp = v3020_get_reg(chip, V3020_MONTH);
-	dt->tm_mon	= BCD2BIN(tmp);
+	dt->tm_mon    = BCD2BIN(tmp) - 1;
 	tmp = v3020_get_reg(chip, V3020_WEEK_DAY);
 	dt->tm_wday	= BCD2BIN(tmp);
 	tmp = v3020_get_reg(chip, V3020_YEAR);
@@ -135,7 +140,7 @@
 	v3020_set_reg(chip, V3020_MINUTES, 	BIN2BCD(dt->tm_min));
 	v3020_set_reg(chip, V3020_HOURS, 	BIN2BCD(dt->tm_hour));
 	v3020_set_reg(chip, V3020_MONTH_DAY,	BIN2BCD(dt->tm_mday));
-	v3020_set_reg(chip, V3020_MONTH, 	BIN2BCD(dt->tm_mon));
+	v3020_set_reg(chip, V3020_MONTH,     BIN2BCD(dt->tm_mon + 1));
 	v3020_set_reg(chip, V3020_WEEK_DAY, 	BIN2BCD(dt->tm_wday));
 	v3020_set_reg(chip, V3020_YEAR, 	BIN2BCD(dt->tm_year % 100));
 
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index bfeca57..e6bfce6 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -1187,7 +1187,7 @@
 static void
 __dasd_process_blk_queue(struct dasd_device * device)
 {
-	request_queue_t *queue;
+	struct request_queue *queue;
 	struct request *req;
 	struct dasd_ccw_req *cqr;
 	int nr_queued;
@@ -1740,7 +1740,7 @@
  * Dasd request queue function. Called from ll_rw_blk.c
  */
 static void
-do_dasd_request(request_queue_t * queue)
+do_dasd_request(struct request_queue * queue)
 {
 	struct dasd_device *device;
 
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 6a89cef..0c67258f 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -291,7 +291,7 @@
 		dasd_page_cache =
 			kmem_cache_create("dasd_page_cache", PAGE_SIZE,
 					  PAGE_SIZE, SLAB_CACHE_DMA,
-					  NULL, NULL );
+					  NULL);
 		if (!dasd_page_cache)
 			MESSAGE(KERN_WARNING, "%s", "Failed to create slab, "
 				"fixed buffer mode disabled.");
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index eccac1c..571320ab 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -24,6 +24,7 @@
 #include <asm/s390_ext.h>
 #include <asm/todclk.h>
 #include <asm/vtoc.h>
+#include <asm/diag.h>
 
 #include "dasd_int.h"
 #include "dasd_diag.h"
@@ -471,14 +472,13 @@
 	struct dasd_ccw_req *cqr;
 	struct dasd_diag_req *dreq;
 	struct dasd_diag_bio *dbio;
-	struct bio *bio;
+	struct req_iterator iter;
 	struct bio_vec *bv;
 	char *dst;
 	unsigned int count, datasize;
 	sector_t recid, first_rec, last_rec;
 	unsigned int blksize, off;
 	unsigned char rw_cmd;
-	int i;
 
 	if (rq_data_dir(req) == READ)
 		rw_cmd = MDSK_READ_REQ;
@@ -492,13 +492,11 @@
 	last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
 	/* Check struct bio and count the number of blocks for the request. */
 	count = 0;
-	rq_for_each_bio(bio, req) {
-		bio_for_each_segment(bv, bio, i) {
-			if (bv->bv_len & (blksize - 1))
-				/* Fba can only do full blocks. */
-				return ERR_PTR(-EINVAL);
-			count += bv->bv_len >> (device->s2b_shift + 9);
-		}
+	rq_for_each_segment(bv, req, iter) {
+		if (bv->bv_len & (blksize - 1))
+			/* Fba can only do full blocks. */
+			return ERR_PTR(-EINVAL);
+		count += bv->bv_len >> (device->s2b_shift + 9);
 	}
 	/* Paranoia. */
 	if (count != last_rec - first_rec + 1)
@@ -515,18 +513,16 @@
 	dreq->block_count = count;
 	dbio = dreq->bio;
 	recid = first_rec;
-	rq_for_each_bio(bio, req) {
-		bio_for_each_segment(bv, bio, i) {
-			dst = page_address(bv->bv_page) + bv->bv_offset;
-			for (off = 0; off < bv->bv_len; off += blksize) {
-				memset(dbio, 0, sizeof (struct dasd_diag_bio));
-				dbio->type = rw_cmd;
-				dbio->block_number = recid + 1;
-				dbio->buffer = dst;
-				dbio++;
-				dst += blksize;
-				recid++;
-			}
+	rq_for_each_segment(bv, req, iter) {
+		dst = page_address(bv->bv_page) + bv->bv_offset;
+		for (off = 0; off < bv->bv_len; off += blksize) {
+			memset(dbio, 0, sizeof (struct dasd_diag_bio));
+			dbio->type = rw_cmd;
+			dbio->block_number = recid + 1;
+			dbio->buffer = dst;
+			dbio++;
+			dst += blksize;
+			recid++;
 		}
 	}
 	cqr->retries = DIAG_MAX_RETRIES;
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 418b4e6..44adf84 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -555,7 +555,7 @@
 			if (conf_data == NULL) {
 				MESSAGE(KERN_WARNING, "%s", "No configuration "
 					"data retrieved");
-				continue;	/* no errror */
+				continue;	/* no error */
 			}
 			if (conf_len != sizeof (struct dasd_eckd_confdata)) {
 				MESSAGE(KERN_WARNING,
@@ -564,7 +564,7 @@
 					conf_len,
 					sizeof (struct dasd_eckd_confdata));
 				kfree(conf_data);
-				continue;	/* no errror */
+				continue;	/* no error */
 			}
 			/* save first valid configuration data */
 			if (!conf_data_saved){
@@ -1176,7 +1176,7 @@
 	struct LO_eckd_data *LO_data;
 	struct dasd_ccw_req *cqr;
 	struct ccw1 *ccw;
-	struct bio *bio;
+	struct req_iterator iter;
 	struct bio_vec *bv;
 	char *dst;
 	unsigned int blksize, blk_per_trk, off;
@@ -1185,7 +1185,6 @@
 	sector_t first_trk, last_trk;
 	unsigned int first_offs, last_offs;
 	unsigned char cmd, rcmd;
-	int i;
 
 	private = (struct dasd_eckd_private *) device->private;
 	if (rq_data_dir(req) == READ)
@@ -1206,18 +1205,15 @@
 	/* Check struct bio and count the number of blocks for the request. */
 	count = 0;
 	cidaw = 0;
-	rq_for_each_bio(bio, req) {
-		bio_for_each_segment(bv, bio, i) {
-			if (bv->bv_len & (blksize - 1))
-				/* Eckd can only do full blocks. */
-				return ERR_PTR(-EINVAL);
-			count += bv->bv_len >> (device->s2b_shift + 9);
+	rq_for_each_segment(bv, req, iter) {
+		if (bv->bv_len & (blksize - 1))
+			/* Eckd can only do full blocks. */
+			return ERR_PTR(-EINVAL);
+		count += bv->bv_len >> (device->s2b_shift + 9);
 #if defined(CONFIG_64BIT)
-			if (idal_is_needed (page_address(bv->bv_page),
-					    bv->bv_len))
-				cidaw += bv->bv_len >> (device->s2b_shift + 9);
+		if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
+			cidaw += bv->bv_len >> (device->s2b_shift + 9);
 #endif
-		}
 	}
 	/* Paranoia. */
 	if (count != last_rec - first_rec + 1)
@@ -1257,7 +1253,7 @@
 		locate_record(ccw++, LO_data++, first_trk, first_offs + 1,
 			      last_rec - recid + 1, cmd, device, blksize);
 	}
-	rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
+	rq_for_each_segment(bv, req, iter) {
 		dst = page_address(bv->bv_page) + bv->bv_offset;
 		if (dasd_page_cache) {
 			char *copy = kmem_cache_alloc(dasd_page_cache,
@@ -1328,12 +1324,12 @@
 {
 	struct dasd_eckd_private *private;
 	struct ccw1 *ccw;
-	struct bio *bio;
+	struct req_iterator iter;
 	struct bio_vec *bv;
 	char *dst, *cda;
 	unsigned int blksize, blk_per_trk, off;
 	sector_t recid;
-	int i, status;
+	int status;
 
 	if (!dasd_page_cache)
 		goto out;
@@ -1346,7 +1342,7 @@
 	ccw++;
 	if (private->uses_cdl == 0 || recid > 2*blk_per_trk)
 		ccw++;
-	rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
+	rq_for_each_segment(bv, req, iter) {
 		dst = page_address(bv->bv_page) + bv->bv_offset;
 		for (off = 0; off < bv->bv_len; off += blksize) {
 			/* Skip locate record. */
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index da16ead..1d95822 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -234,14 +234,13 @@
 	struct LO_fba_data *LO_data;
 	struct dasd_ccw_req *cqr;
 	struct ccw1 *ccw;
-	struct bio *bio;
+	struct req_iterator iter;
 	struct bio_vec *bv;
 	char *dst;
 	int count, cidaw, cplength, datasize;
 	sector_t recid, first_rec, last_rec;
 	unsigned int blksize, off;
 	unsigned char cmd;
-	int i;
 
 	private = (struct dasd_fba_private *) device->private;
 	if (rq_data_dir(req) == READ) {
@@ -257,18 +256,15 @@
 	/* Check struct bio and count the number of blocks for the request. */
 	count = 0;
 	cidaw = 0;
-	rq_for_each_bio(bio, req) {
-		bio_for_each_segment(bv, bio, i) {
-			if (bv->bv_len & (blksize - 1))
-				/* Fba can only do full blocks. */
-				return ERR_PTR(-EINVAL);
-			count += bv->bv_len >> (device->s2b_shift + 9);
+	rq_for_each_segment(bv, req, iter) {
+		if (bv->bv_len & (blksize - 1))
+			/* Fba can only do full blocks. */
+			return ERR_PTR(-EINVAL);
+		count += bv->bv_len >> (device->s2b_shift + 9);
 #if defined(CONFIG_64BIT)
-			if (idal_is_needed (page_address(bv->bv_page),
-					    bv->bv_len))
-				cidaw += bv->bv_len / blksize;
+		if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
+			cidaw += bv->bv_len / blksize;
 #endif
-		}
 	}
 	/* Paranoia. */
 	if (count != last_rec - first_rec + 1)
@@ -304,7 +300,7 @@
 		locate_record(ccw++, LO_data++, rq_data_dir(req), 0, count);
 	}
 	recid = first_rec;
-	rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
+	rq_for_each_segment(bv, req, iter) {
 		dst = page_address(bv->bv_page) + bv->bv_offset;
 		if (dasd_page_cache) {
 			char *copy = kmem_cache_alloc(dasd_page_cache,
@@ -359,11 +355,11 @@
 {
 	struct dasd_fba_private *private;
 	struct ccw1 *ccw;
-	struct bio *bio;
+	struct req_iterator iter;
 	struct bio_vec *bv;
 	char *dst, *cda;
 	unsigned int blksize, off;
-	int i, status;
+	int status;
 
 	if (!dasd_page_cache)
 		goto out;
@@ -374,7 +370,7 @@
 	ccw++;
 	if (private->rdc_data.mode.bits.data_chain != 0)
 		ccw++;
-	rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
+	rq_for_each_segment(bv, req, iter) {
 		dst = page_address(bv->bv_page) + bv->bv_offset;
 		for (off = 0; off < bv->bv_len; off += blksize) {
 			/* Skip locate record. */
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 241294c..d427dae 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -53,6 +53,7 @@
 #include <linux/genhd.h>
 #include <linux/hdreg.h>
 #include <linux/interrupt.h>
+#include <linux/log2.h>
 #include <asm/ccwdev.h>
 #include <linux/workqueue.h>
 #include <asm/debug.h>
@@ -293,7 +294,7 @@
 struct dasd_device {
 	/* Block device stuff. */
 	struct gendisk *gdp;
-	request_queue_t *request_queue;
+	struct request_queue *request_queue;
 	spinlock_t request_queue_lock;
 	struct block_device *bdev;
         unsigned int devindex;
@@ -456,7 +457,7 @@
 static inline int
 dasd_check_blocksize(int bsize)
 {
-	if (bsize < 512 || bsize > 4096 || (bsize & (bsize - 1)) != 0)
+	if (bsize < 512 || bsize > 4096 || !is_power_of_2(bsize))
 		return -EMEDIUMTYPE;
 	return 0;
 }
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 35765f6..859f870 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -621,7 +621,7 @@
 }
 
 static int
-dcssblk_make_request(request_queue_t *q, struct bio *bio)
+dcssblk_make_request(struct request_queue *q, struct bio *bio)
 {
 	struct dcssblk_dev_info *dev_info;
 	struct bio_vec *bvec;
@@ -674,10 +674,10 @@
 		}
 		bytes_done += bvec->bv_len;
 	}
-	bio_endio(bio, bytes_done, 0);
+	bio_endio(bio, 0);
 	return 0;
 fail:
-	bio_io_error(bio, bio->bi_size);
+	bio_io_error(bio);
 	return 0;
 }
 
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index a04d912..f231bc2 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -191,7 +191,7 @@
 /*
  * Block device make request function.
  */
-static int xpram_make_request(request_queue_t *q, struct bio *bio)
+static int xpram_make_request(struct request_queue *q, struct bio *bio)
 {
 	xpram_device_t *xdev = bio->bi_bdev->bd_disk->private_data;
 	struct bio_vec *bvec;
@@ -230,12 +230,10 @@
 		}
 	}
 	set_bit(BIO_UPTODATE, &bio->bi_flags);
-	bytes = bio->bi_size;
-	bio->bi_size = 0;
-	bio->bi_end_io(bio, bytes, 0);
+	bio_endio(bio, 0);
 	return 0;
 fail:
-	bio_io_error(bio, bio->bi_size);
+	bio_io_error(bio);
 	return 0;
 }
 
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
index 3f36cb3..6430338 100644
--- a/drivers/s390/char/Kconfig
+++ b/drivers/s390/char/Kconfig
@@ -44,15 +44,9 @@
 	depends on TN3215_CONSOLE || TN3270_CONSOLE
 	default y
 
-config SCLP
-	bool "Support for SCLP"
-	depends on S390
-	help
-	  Include support for the SCLP interface to the service element.
-
 config SCLP_TTY
 	bool "Support for SCLP line mode terminal"
-	depends on SCLP
+	depends on S390
 	help
 	  Include support for IBM SCLP line-mode terminals.
 
@@ -65,7 +59,7 @@
 
 config SCLP_VT220_TTY
 	bool "Support for SCLP VT220-compatible terminal"
-	depends on SCLP
+	depends on S390
 	help
 	  Include support for an IBM SCLP VT220-compatible terminal.
 
@@ -78,7 +72,7 @@
 
 config SCLP_CPI
 	tristate "Control-Program Identification"
-	depends on SCLP
+	depends on S390
 	help
 	  This option enables the hardware console interface for system
 	  identification. This is commonly used for workload management and
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 6000bde..0e1f35c 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -667,6 +667,9 @@
 	struct raw3215_info *raw;
 	int line;
 
+	/* Console is special. */
+	if (raw3215[0] && (cdev->dev.driver_data == raw3215[0]))
+		return 0;
 	raw = kmalloc(sizeof(struct raw3215_info) +
 		      RAW3215_INBUF_SIZE, GFP_KERNEL|GFP_DMA);
 	if (raw == NULL)
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index fd34791..0b04055 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -22,6 +22,7 @@
 #include <asm/ebcdic.h>
 
 #include "raw3270.h"
+#include "tty3270.h"
 #include "ctrlchar.h"
 
 #define CON3270_OUTPUT_BUFFER_SIZE 1024
@@ -507,8 +508,6 @@
 	spin_unlock_irqrestore(&cp->view.lock,flags);
 }
 
-extern struct tty_driver *tty3270_driver;
-
 static struct tty_driver *
 con3270_device(struct console *c, int *index)
 {
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
index 268598e..20442fb 100644
--- a/drivers/s390/char/monwriter.c
+++ b/drivers/s390/char/monwriter.c
@@ -17,6 +17,7 @@
 #include <linux/miscdevice.h>
 #include <linux/ctype.h>
 #include <linux/poll.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <asm/ebcdic.h>
 #include <asm/io.h>
@@ -41,6 +42,7 @@
 	size_t hdr_to_read;
 	size_t data_to_read;
 	struct mon_buf *current_buf;
+	struct mutex thread_mutex;
 };
 
 /*
@@ -179,6 +181,7 @@
 		return -ENOMEM;
 	INIT_LIST_HEAD(&monpriv->list);
 	monpriv->hdr_to_read = sizeof(monpriv->hdr);
+	mutex_init(&monpriv->thread_mutex);
 	filp->private_data = monpriv;
 	return nonseekable_open(inode, filp);
 }
@@ -209,6 +212,7 @@
 	void *to;
 	int rc;
 
+	mutex_lock(&monpriv->thread_mutex);
 	for (written = 0; written < count; ) {
 		if (monpriv->hdr_to_read) {
 			len = min(count - written, monpriv->hdr_to_read);
@@ -247,11 +251,13 @@
 		}
 		monpriv->hdr_to_read = sizeof(monpriv->hdr);
 	}
+	mutex_unlock(&monpriv->thread_mutex);
 	return written;
 
 out_error:
 	monpriv->data_to_read = 0;
 	monpriv->hdr_to_read = sizeof(struct monwrite_hdr);
+	mutex_unlock(&monpriv->thread_mutex);
 	return rc;
 }
 
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 743944a..2edd5fb 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -21,6 +21,7 @@
 #include <asm/ccwdev.h>
 #include <asm/cio.h>
 #include <asm/ebcdic.h>
+#include <asm/diag.h>
 
 #include "raw3270.h"
 
@@ -147,8 +148,7 @@
  * Allocate a new 3270 ccw request from bootmem. Only works very
  * early in the boot process. Only con3270.c should be using this.
  */
-struct raw3270_request *
-raw3270_request_alloc_bootmem(size_t size)
+struct raw3270_request __init *raw3270_request_alloc_bootmem(size_t size)
 {
 	struct raw3270_request *rq;
 
@@ -848,8 +848,7 @@
 /*
  * Setup 3270 device configured as console.
  */
-struct raw3270 *
-raw3270_setup_console(struct ccw_device *cdev)
+struct raw3270 __init *raw3270_setup_console(struct ccw_device *cdev)
 {
 	struct raw3270 *rp;
 	char *ascebc;
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index fa62e69..25629b9 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -93,6 +93,7 @@
 #define SCLP_RETRY_INTERVAL	30
 
 static void sclp_process_queue(void);
+static void __sclp_make_read_req(void);
 static int sclp_init_mask(int calculate);
 static int sclp_init(void);
 
@@ -115,7 +116,6 @@
 	return 0;
 }
 
-static inline void __sclp_make_read_req(void);
 
 static void
 __sclp_queue_read_req(void)
@@ -318,8 +318,7 @@
 }
 
 /* Prepare read event data request. Called while sclp_lock is locked. */
-static inline void
-__sclp_make_read_req(void)
+static void __sclp_make_read_req(void)
 {
 	struct sccb_header *sccb;
 
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index 7263347..40cd21b 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -621,11 +621,24 @@
 /*
  * Initialize all relevant components and register driver with system.
  */
-static int
-__sclp_vt220_init(int early)
+static void __init __sclp_vt220_cleanup(void)
+{
+	struct list_head *page, *p;
+
+	list_for_each_safe(page, p, &sclp_vt220_empty) {
+		list_del(page);
+		if (slab_is_available())
+			free_page((unsigned long) page);
+		else
+			free_bootmem((unsigned long) page, PAGE_SIZE);
+	}
+}
+
+static int __init __sclp_vt220_init(void)
 {
 	void *page;
 	int i;
+	int num_pages;
 
 	if (sclp_vt220_initialized)
 		return 0;
@@ -642,13 +655,16 @@
 	sclp_vt220_flush_later = 0;
 
 	/* Allocate pages for output buffering */
-	for (i = 0; i < (early ? MAX_CONSOLE_PAGES : MAX_KMEM_PAGES); i++) {
-		if (early)
-			page = alloc_bootmem_low_pages(PAGE_SIZE);
-		else
+	num_pages = slab_is_available() ? MAX_KMEM_PAGES : MAX_CONSOLE_PAGES;
+	for (i = 0; i < num_pages; i++) {
+		if (slab_is_available())
 			page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
-		if (!page)
+		else
+			page = alloc_bootmem_low_pages(PAGE_SIZE);
+		if (!page) {
+			__sclp_vt220_cleanup();
 			return -ENOMEM;
+		}
 		list_add_tail((struct list_head *) page, &sclp_vt220_empty);
 	}
 	return 0;
@@ -662,14 +678,13 @@
 	.flush_chars = sclp_vt220_flush_chars,
 	.write_room = sclp_vt220_write_room,
 	.chars_in_buffer = sclp_vt220_chars_in_buffer,
-	.flush_buffer = sclp_vt220_flush_buffer
+	.flush_buffer = sclp_vt220_flush_buffer,
 };
 
 /*
  * Register driver with SCLP and Linux and initialize internal tty structures.
  */
-static int __init
-sclp_vt220_tty_init(void)
+static int __init sclp_vt220_tty_init(void)
 {
 	struct tty_driver *driver;
 	int rc;
@@ -679,18 +694,15 @@
 	driver = alloc_tty_driver(1);
 	if (!driver)
 		return -ENOMEM;
-	rc = __sclp_vt220_init(0);
-	if (rc) {
-		put_tty_driver(driver);
-		return rc;
-	}
+	rc = __sclp_vt220_init();
+	if (rc)
+		goto out_driver;
 	rc = sclp_register(&sclp_vt220_register);
 	if (rc) {
 		printk(KERN_ERR SCLP_VT220_PRINT_HEADER
 		       "could not register tty - "
 		       "sclp_register returned %d\n", rc);
-		put_tty_driver(driver);
-		return rc;
+		goto out_init;
 	}
 
 	driver->owner = THIS_MODULE;
@@ -709,14 +721,20 @@
 		printk(KERN_ERR SCLP_VT220_PRINT_HEADER
 		       "could not register tty - "
 		       "tty_register_driver returned %d\n", rc);
-		put_tty_driver(driver);
-		return rc;
+		goto out_sclp;
 	}
 	sclp_vt220_driver = driver;
 	return 0;
-}
 
-module_init(sclp_vt220_tty_init);
+out_sclp:
+	sclp_unregister(&sclp_vt220_register);
+out_init:
+	__sclp_vt220_cleanup();
+out_driver:
+	put_tty_driver(driver);
+	return rc;
+}
+__initcall(sclp_vt220_tty_init);
 
 #ifdef CONFIG_SCLP_VT220_CONSOLE
 
@@ -762,7 +780,7 @@
 
 	if (!CONSOLE_IS_SCLP)
 		return 0;
-	rc = __sclp_vt220_init(1);
+	rc = __sclp_vt220_init();
 	if (rc)
 		return rc;
 	/* Attach linux console */
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index 3b52f5c..dddf8d6 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -188,7 +188,7 @@
 {
 	struct tape_device *	device;
 	/* Block device request queue. */
-	request_queue_t *	request_queue;
+	struct request_queue *	request_queue;
 	spinlock_t		request_queue_lock;
 
 	/* Task to move entries from block request to CCS request queue. */
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c
index e765875..5b47e9cc 100644
--- a/drivers/s390/char/tape_34xx.c
+++ b/drivers/s390/char/tape_34xx.c
@@ -131,10 +131,9 @@
 {
 	struct tape_34xx_work *p;
 
-	if ((p = kmalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
+	if ((p = kzalloc(sizeof(*p), GFP_ATOMIC)) == NULL)
 		return -ENOMEM;
 
-	memset(p, 0, sizeof(*p));
 	INIT_WORK(&p->work, tape_34xx_work_handler);
 
 	p->device = tape_get_device_reference(device);
@@ -1135,21 +1134,18 @@
 {
 	struct tape_request *request;
 	struct ccw1 *ccw;
-	int count = 0, i;
+	int count = 0;
 	unsigned off;
 	char *dst;
 	struct bio_vec *bv;
-	struct bio *bio;
+	struct req_iterator iter;
 	struct tape_34xx_block_id *	start_block;
 
 	DBF_EVENT(6, "xBREDid:");
 
 	/* Count the number of blocks for the request. */
-	rq_for_each_bio(bio, req) {
-		bio_for_each_segment(bv, bio, i) {
-			count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9);
-		}
-	}
+	rq_for_each_segment(bv, req, iter)
+		count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9);
 
 	/* Allocate the ccw request. */
 	request = tape_alloc_request(3+count+1, 8);
@@ -1176,18 +1172,15 @@
 	ccw = tape_ccw_cc(ccw, NOP, 0, NULL);
 	ccw = tape_ccw_cc(ccw, NOP, 0, NULL);
 
-	rq_for_each_bio(bio, req) {
-		bio_for_each_segment(bv, bio, i) {
-			dst = kmap(bv->bv_page) + bv->bv_offset;
-			for (off = 0; off < bv->bv_len;
-			     off += TAPEBLOCK_HSEC_SIZE) {
-				ccw->flags = CCW_FLAG_CC;
-				ccw->cmd_code = READ_FORWARD;
-				ccw->count = TAPEBLOCK_HSEC_SIZE;
-				set_normalized_cda(ccw, (void*) __pa(dst));
-				ccw++;
-				dst += TAPEBLOCK_HSEC_SIZE;
-			}
+	rq_for_each_segment(bv, req, iter) {
+		dst = kmap(bv->bv_page) + bv->bv_offset;
+		for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) {
+			ccw->flags = CCW_FLAG_CC;
+			ccw->cmd_code = READ_FORWARD;
+			ccw->count = TAPEBLOCK_HSEC_SIZE;
+			set_normalized_cda(ccw, (void*) __pa(dst));
+			ccw++;
+			dst += TAPEBLOCK_HSEC_SIZE;
 		}
 	}
 
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index 7e2b2ab..da25f8e 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -623,21 +623,19 @@
 {
 	struct tape_request *request;
 	struct ccw1 *ccw;
-	int count = 0, start_block, i;
+	int count = 0, start_block;
 	unsigned off;
 	char *dst;
 	struct bio_vec *bv;
-	struct bio *bio;
+	struct req_iterator iter;
 
 	DBF_EVENT(6, "xBREDid:");
 	start_block = req->sector >> TAPEBLOCK_HSEC_S2B;
 	DBF_EVENT(6, "start_block = %i\n", start_block);
 
-	rq_for_each_bio(bio, req) {
-		bio_for_each_segment(bv, bio, i) {
-			count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9);
-		}
-	}
+	rq_for_each_segment(bv, req, iter)
+		count += bv->bv_len >> (TAPEBLOCK_HSEC_S2B + 9);
+
 	request = tape_alloc_request(2 + count + 1, 4);
 	if (IS_ERR(request))
 		return request;
@@ -653,21 +651,18 @@
 	 */
 	ccw = tape_ccw_cc(ccw, NOP, 0, NULL);
 
-	rq_for_each_bio(bio, req) {
-		bio_for_each_segment(bv, bio, i) {
-			dst = page_address(bv->bv_page) + bv->bv_offset;
-			for (off = 0; off < bv->bv_len;
-			     off += TAPEBLOCK_HSEC_SIZE) {
-				ccw->flags = CCW_FLAG_CC;
-				ccw->cmd_code = READ_FORWARD;
-				ccw->count = TAPEBLOCK_HSEC_SIZE;
-				set_normalized_cda(ccw, (void *) __pa(dst));
-				ccw++;
-				dst += TAPEBLOCK_HSEC_SIZE;
-			}
-			if (off > bv->bv_len)
-				BUG();
+	rq_for_each_segment(bv, req, iter) {
+		dst = page_address(bv->bv_page) + bv->bv_offset;
+		for (off = 0; off < bv->bv_len; off += TAPEBLOCK_HSEC_SIZE) {
+			ccw->flags = CCW_FLAG_CC;
+			ccw->cmd_code = READ_FORWARD;
+			ccw->count = TAPEBLOCK_HSEC_SIZE;
+			set_normalized_cda(ccw, (void *) __pa(dst));
+			ccw++;
+			dst += TAPEBLOCK_HSEC_SIZE;
 		}
+		if (off > bv->bv_len)
+			BUG();
 	}
 	ccw = tape_ccw_end(ccw, NOP, 0, NULL);
 	DBF_EVENT(6, "xBREDccwg\n");
@@ -713,16 +708,22 @@
 
 	c_info = &TAPE_3590_CRYPT_INFO(device);
 
-	if (sense->masst == MSENSE_UNASSOCIATED) {
+	DBF_EVENT(6, "medium state: %x:%x\n", sense->macst, sense->masst);
+	switch (sense->macst) {
+	case 0x04:
+	case 0x05:
+	case 0x06:
 		tape_med_state_set(device, MS_UNLOADED);
 		TAPE_3590_CRYPT_INFO(device).medium_status = 0;
 		return;
-	}
-	if (sense->masst != MSENSE_ASSOCIATED_MOUNT) {
-		PRINT_ERR("Unknown medium state: %x\n", sense->masst);
+	case 0x08:
+	case 0x09:
+		tape_med_state_set(device, MS_LOADED);
+		break;
+	default:
+		tape_med_state_set(device, MS_UNKNOWN);
 		return;
 	}
-	tape_med_state_set(device, MS_LOADED);
 	c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK;
 	if (sense->flags & MSENSE_CRYPT_MASK) {
 		PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags);
@@ -840,15 +841,17 @@
 		/* Probably result of halt ssch */
 		return TAPE_IO_PENDING;
 	else if (irb->scsw.dstat == 0x85)
-		/* Device Ready -> check medium state */
-		tape_3590_schedule_work(device, TO_MSEN);
-	else if (irb->scsw.dstat & DEV_STAT_ATTENTION)
+		/* Device Ready */
+		DBF_EVENT(3, "unsol.irq! tape ready: %08x\n", device->cdev_id);
+	else if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
 		tape_3590_schedule_work(device, TO_READ_ATTMSG);
-	else {
+	} else {
 		DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id);
 		PRINT_WARN("Unsolicited IRQ (Device End) caught.\n");
 		tape_dump_sense(device, NULL, irb);
 	}
+	/* check medium state */
+	tape_3590_schedule_work(device, TO_MSEN);
 	return TAPE_IO_SUCCESS;
 }
 
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index dd0ecae..eeb92e2 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -147,7 +147,7 @@
 tapeblock_requeue(struct work_struct *work) {
 	struct tape_blk_data *	blkdat;
 	struct tape_device *	device;
-	request_queue_t *	queue;
+	struct request_queue *	queue;
 	int			nr_queued;
 	struct request *	req;
 	struct list_head *	l;
@@ -194,7 +194,7 @@
  * Tape request queue function. Called from ll_rw_blk.c
  */
 static void
-tapeblock_request_fn(request_queue_t *queue)
+tapeblock_request_fn(struct request_queue *queue)
 {
 	struct tape_device *device;
 
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index bc33068..70b1980a 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -25,8 +25,8 @@
 #include <asm/ebcdic.h>
 #include <asm/uaccess.h>
 
-
 #include "raw3270.h"
+#include "tty3270.h"
 #include "keyboard.h"
 
 #define TTY3270_CHAR_BUF_SIZE 256
@@ -1338,8 +1338,11 @@
 static void
 tty3270_goto_xy(struct tty3270 *tp, int cx, int cy)
 {
-	tp->cx = min_t(int, tp->view.cols - 1, max_t(int, 0, cx));
-	cy = min_t(int, tp->view.rows - 3, max_t(int, 0, cy));
+	int max_cx = max(0, cx);
+	int max_cy = max(0, cy);
+
+	tp->cx = min_t(int, tp->view.cols - 1, max_cx);
+	cy = min_t(int, tp->view.rows - 3, max_cy);
 	if (cy != tp->cy) {
 		tty3270_convert_line(tp, tp->cy);
 		tp->cy = cy;
diff --git a/drivers/s390/char/tty3270.h b/drivers/s390/char/tty3270.h
new file mode 100644
index 0000000..799da57
--- /dev/null
+++ b/drivers/s390/char/tty3270.h
@@ -0,0 +1,16 @@
+/*
+ *  drivers/s390/char/tty3270.h
+ *
+ *    Copyright IBM Corp. 2007
+ *
+ */
+
+#ifndef __DRIVERS_S390_CHAR_TTY3270_H
+#define __DRIVERS_S390_CHAR_TTY3270_H
+
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+
+extern struct tty_driver *tty3270_driver;
+
+#endif /* __DRIVERS_S390_CHAR_TTY3270_H */
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
index e90b0f8..d70a6e6 100644
--- a/drivers/s390/char/vmur.c
+++ b/drivers/s390/char/vmur.c
@@ -14,6 +14,7 @@
 #include <asm/cio.h>
 #include <asm/ccwdev.h>
 #include <asm/debug.h>
+#include <asm/diag.h>
 
 #include "vmur.h"
 
@@ -68,8 +69,26 @@
 	.set_offline	= ur_set_offline,
 };
 
+static DEFINE_MUTEX(vmur_mutex);
+
 /*
  * Allocation, freeing, getting and putting of urdev structures
+ *
+ * Each ur device (urd) contains a reference to its corresponding ccw device
+ * (cdev) using the urd->cdev pointer. Each ccw device has a reference to the
+ * ur device using the cdev->dev.driver_data pointer.
+ *
+ * urd references:
+ * - ur_probe gets a urd reference, ur_remove drops the reference
+ *   (cdev->dev.driver_data)
+ * - ur_open gets a urd reference, ur_relase drops the reference
+ *   (urf->urd)
+ *
+ * cdev references:
+ * - urdev_alloc get a cdev reference (urd->cdev)
+ * - urdev_free drops the cdev reference (urd->cdev)
+ *
+ * Setting and clearing of cdev->dev.driver_data is protected by the ccwdev lock
  */
 static struct urdev *urdev_alloc(struct ccw_device *cdev)
 {
@@ -78,51 +97,72 @@
 	urd = kzalloc(sizeof(struct urdev), GFP_KERNEL);
 	if (!urd)
 		return NULL;
-	urd->cdev = cdev;
 	urd->reclen = cdev->id.driver_info;
 	ccw_device_get_id(cdev, &urd->dev_id);
 	mutex_init(&urd->io_mutex);
 	mutex_init(&urd->open_mutex);
+	atomic_set(&urd->ref_count,  1);
+	urd->cdev = cdev;
+	get_device(&cdev->dev);
 	return urd;
 }
 
 static void urdev_free(struct urdev *urd)
 {
+	TRACE("urdev_free: %p\n", urd);
+	if (urd->cdev)
+		put_device(&urd->cdev->dev);
 	kfree(urd);
 }
 
-/*
- * This is how the character device driver gets a reference to a
- * ur device. When this call returns successfully, a reference has
- * been taken (by get_device) on the underlying kobject. The recipient
- * of this urdev pointer must eventually drop it with urdev_put(urd)
- * which does the corresponding put_device().
- */
+static void urdev_get(struct urdev *urd)
+{
+	atomic_inc(&urd->ref_count);
+}
+
+static struct urdev *urdev_get_from_cdev(struct ccw_device *cdev)
+{
+	struct urdev *urd;
+	unsigned long flags;
+
+	spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+	urd = cdev->dev.driver_data;
+	if (urd)
+		urdev_get(urd);
+	spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+	return urd;
+}
+
 static struct urdev *urdev_get_from_devno(u16 devno)
 {
 	char bus_id[16];
 	struct ccw_device *cdev;
+	struct urdev *urd;
 
 	sprintf(bus_id, "0.0.%04x", devno);
 	cdev = get_ccwdev_by_busid(&ur_driver, bus_id);
 	if (!cdev)
 		return NULL;
-
-	return cdev->dev.driver_data;
+	urd = urdev_get_from_cdev(cdev);
+	put_device(&cdev->dev);
+	return urd;
 }
 
 static void urdev_put(struct urdev *urd)
 {
-	put_device(&urd->cdev->dev);
+	if (atomic_dec_and_test(&urd->ref_count))
+		urdev_free(urd);
 }
 
 /*
  * Low-level functions to do I/O to a ur device.
  *     alloc_chan_prog
+ *     free_chan_prog
  *     do_ur_io
  *     ur_int_handler
  *
  * alloc_chan_prog allocates and builds the channel program
+ * free_chan_prog frees memory of the channel program
  *
  * do_ur_io issues the channel program to the device and blocks waiting
  * on a completion event it publishes at urd->io_done. The function
@@ -137,6 +177,16 @@
  * address pointer that alloc_chan_prog returned.
  */
 
+static void free_chan_prog(struct ccw1 *cpa)
+{
+	struct ccw1 *ptr = cpa;
+
+	while (ptr->cda) {
+		kfree((void *)(addr_t) ptr->cda);
+		ptr++;
+	}
+	kfree(cpa);
+}
 
 /*
  * alloc_chan_prog
@@ -144,44 +194,45 @@
  * with a final NOP CCW command-chained on (which ensures that CE and DE
  * are presented together in a single interrupt instead of as separate
  * interrupts unless an incorrect length indication kicks in first). The
- * data length in each CCW is reclen. The caller must ensure that count
- * is an integral multiple of reclen.
- * The channel program pointer returned by this function must be freed
- * with kfree. The caller is responsible for checking that
- * count/reclen is not ridiculously large.
+ * data length in each CCW is reclen.
  */
-static struct ccw1 *alloc_chan_prog(char *buf, size_t count, size_t reclen)
+static struct ccw1 *alloc_chan_prog(const char __user *ubuf, int rec_count,
+				    int reclen)
 {
-	size_t num_ccws;
 	struct ccw1 *cpa;
+	void *kbuf;
 	int i;
 
-	TRACE("alloc_chan_prog(%p, %zu, %zu)\n", buf, count, reclen);
+	TRACE("alloc_chan_prog(%p, %i, %i)\n", ubuf, rec_count, reclen);
 
 	/*
 	 * We chain a NOP onto the writes to force CE+DE together.
 	 * That means we allocate room for CCWs to cover count/reclen
 	 * records plus a NOP.
 	 */
-	num_ccws = count / reclen + 1;
-	cpa = kmalloc(num_ccws * sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
+	cpa = kzalloc((rec_count + 1) * sizeof(struct ccw1),
+		      GFP_KERNEL | GFP_DMA);
 	if (!cpa)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
-	for (i = 0; count; i++) {
+	for (i = 0; i < rec_count; i++) {
 		cpa[i].cmd_code = WRITE_CCW_CMD;
 		cpa[i].flags = CCW_FLAG_CC | CCW_FLAG_SLI;
 		cpa[i].count = reclen;
-		cpa[i].cda = __pa(buf);
-		buf += reclen;
-		count -= reclen;
+		kbuf = kmalloc(reclen, GFP_KERNEL | GFP_DMA);
+		if (!kbuf) {
+			free_chan_prog(cpa);
+			return ERR_PTR(-ENOMEM);
+		}
+		cpa[i].cda = (u32)(addr_t) kbuf;
+		if (copy_from_user(kbuf, ubuf, reclen)) {
+			free_chan_prog(cpa);
+			return ERR_PTR(-EFAULT);
+		}
+		ubuf += reclen;
 	}
 	/* The following NOP CCW forces CE+DE to be presented together */
 	cpa[i].cmd_code = CCW_CMD_NOOP;
-	cpa[i].flags = 0;
-	cpa[i].count = 0;
-	cpa[i].cda = 0;
-
 	return cpa;
 }
 
@@ -189,7 +240,7 @@
 {
 	int rc;
 	struct ccw_device *cdev = urd->cdev;
-	DECLARE_COMPLETION(event);
+	DECLARE_COMPLETION_ONSTACK(event);
 
 	TRACE("do_ur_io: cpa=%p\n", cpa);
 
@@ -232,6 +283,7 @@
 		return;
 	}
 	urd = cdev->dev.driver_data;
+	BUG_ON(!urd);
 	/* On special conditions irb is an error pointer */
 	if (IS_ERR(irb))
 		urd->io_request_rc = PTR_ERR(irb);
@@ -249,9 +301,15 @@
 static ssize_t ur_attr_reclen_show(struct device *dev,
 				   struct device_attribute *attr, char *buf)
 {
-	struct urdev *urd = dev->driver_data;
+	struct urdev *urd;
+	int rc;
 
-	return sprintf(buf, "%zu\n", urd->reclen);
+	urd = urdev_get_from_cdev(to_ccwdev(dev));
+	if (!urd)
+		return -ENODEV;
+	rc = sprintf(buf, "%zu\n", urd->reclen);
+	urdev_put(urd);
+	return rc;
 }
 
 static DEVICE_ATTR(reclen, 0444, ur_attr_reclen_show, NULL);
@@ -325,24 +383,11 @@
 			size_t count, size_t reclen, loff_t *ppos)
 {
 	struct ccw1 *cpa;
-	char *buf;
 	int rc;
 
-	/* Data buffer must be under 2GB line for fmt1 CCWs: hence GFP_DMA */
-	buf = kmalloc(count, GFP_KERNEL | GFP_DMA);
-	if (!buf)
-		return -ENOMEM;
-
-	if (copy_from_user(buf, udata, count)) {
-		rc = -EFAULT;
-		goto fail_kfree_buf;
-	}
-
-	cpa = alloc_chan_prog(buf, count, reclen);
-	if (!cpa) {
-		rc = -ENOMEM;
-		goto fail_kfree_buf;
-	}
+	cpa = alloc_chan_prog(udata, count / reclen, reclen);
+	if (IS_ERR(cpa))
+		return PTR_ERR(cpa);
 
 	rc = do_ur_io(urd, cpa);
 	if (rc)
@@ -354,10 +399,9 @@
 	}
 	*ppos += count;
 	rc = count;
+
 fail_kfree_cpa:
-	kfree(cpa);
-fail_kfree_buf:
-	kfree(buf);
+	free_chan_prog(cpa);
 	return rc;
 }
 
@@ -380,31 +424,6 @@
 	return do_write(urf->urd, udata, count, urf->dev_reclen, ppos);
 }
 
-static int do_diag_14(unsigned long rx, unsigned long ry1,
-		      unsigned long subcode)
-{
-	register unsigned long _ry1 asm("2") = ry1;
-	register unsigned long _ry2 asm("3") = subcode;
-	int rc = 0;
-
-	asm volatile(
-#ifdef CONFIG_64BIT
-		"   sam31\n"
-		"   diag    %2,2,0x14\n"
-		"   sam64\n"
-#else
-		"   diag    %2,2,0x14\n"
-#endif
-		"   ipm     %0\n"
-		"   srl     %0,28\n"
-		: "=d" (rc), "+d" (_ry2)
-		: "d" (rx), "d" (_ry1)
-		: "cc");
-
-	TRACE("diag 14: subcode=0x%lx, cc=%i\n", subcode, rc);
-	return rc;
-}
-
 /*
  * diagnose code 0x14 subcode 0x0028 - position spool file to designated
  *				       record
@@ -416,7 +435,7 @@
 {
 	int cc;
 
-	cc = do_diag_14(record, devno, 0x28);
+	cc = diag14(record, devno, 0x28);
 	switch (cc) {
 	case 0:
 		return 0;
@@ -441,7 +460,7 @@
 {
 	int cc;
 
-	cc = do_diag_14((unsigned long) buf, devno, 0x00);
+	cc = diag14((unsigned long) buf, devno, 0x00);
 	switch (cc) {
 	case 0:
 		return 0;
@@ -473,7 +492,7 @@
 		return rc;
 
 	len = min((size_t) PAGE_SIZE, count);
-	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	buf = (char *) __get_free_page(GFP_KERNEL | GFP_DMA);
 	if (!buf)
 		return -ENOMEM;
 
@@ -486,7 +505,7 @@
 		}
 		if (rc)
 			goto fail;
-		if (reclen)
+		if (reclen && (copied == 0) && (*offs < PAGE_SIZE))
 			*((u16 *) &buf[FILE_RECLEN_OFFSET]) = reclen;
 		len = min(count - copied, PAGE_SIZE - res);
 		if (copy_to_user(ubuf + copied, buf + res, len)) {
@@ -500,7 +519,7 @@
 	*offs += copied;
 	rc = copied;
 fail:
-	kfree(buf);
+	free_page((unsigned long) buf);
 	return rc;
 }
 
@@ -534,7 +553,7 @@
 {
 	int cc;
 
-	cc = do_diag_14((unsigned long) buf, spid, 0xfff);
+	cc = diag14((unsigned long) buf, spid, 0xfff);
 	switch (cc) {
 	case 0:
 		return 0;
@@ -543,56 +562,97 @@
 	}
 }
 
-static int verify_device(struct urdev *urd)
+static int verify_uri_device(struct urdev *urd)
 {
-	struct file_control_block fcb;
+	struct file_control_block *fcb;
 	char *buf;
 	int rc;
 
+	fcb = kmalloc(sizeof(*fcb), GFP_KERNEL | GFP_DMA);
+	if (!fcb)
+		return -ENOMEM;
+
+	/* check for empty reader device (beginning of chain) */
+	rc = diag_read_next_file_info(fcb, 0);
+	if (rc)
+		goto fail_free_fcb;
+
+	/* if file is in hold status, we do not read it */
+	if (fcb->file_stat & (FLG_SYSTEM_HOLD | FLG_USER_HOLD)) {
+		rc = -EPERM;
+		goto fail_free_fcb;
+	}
+
+	/* open file on virtual reader	*/
+	buf = (char *) __get_free_page(GFP_KERNEL | GFP_DMA);
+	if (!buf) {
+		rc = -ENOMEM;
+		goto fail_free_fcb;
+	}
+	rc = diag_read_file(urd->dev_id.devno, buf);
+	if ((rc != 0) && (rc != -ENODATA)) /* EOF does not hurt */
+		goto fail_free_buf;
+
+	/* check if the file on top of the queue is open now */
+	rc = diag_read_next_file_info(fcb, 0);
+	if (rc)
+		goto fail_free_buf;
+	if (!(fcb->file_stat & FLG_IN_USE)) {
+		rc = -EMFILE;
+		goto fail_free_buf;
+	}
+	rc = 0;
+
+fail_free_buf:
+	free_page((unsigned long) buf);
+fail_free_fcb:
+	kfree(fcb);
+	return rc;
+}
+
+static int verify_device(struct urdev *urd)
+{
 	switch (urd->class) {
 	case DEV_CLASS_UR_O:
 		return 0; /* no check needed here */
 	case DEV_CLASS_UR_I:
-		/* check for empty reader device (beginning of chain) */
-		rc = diag_read_next_file_info(&fcb, 0);
-		if (rc)
-			return rc;
-
-		/* open file on virtual reader	*/
-		buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
-		if (!buf)
-			return -ENOMEM;
-		rc = diag_read_file(urd->dev_id.devno, buf);
-		kfree(buf);
-
-		if ((rc != 0) && (rc != -ENODATA)) /* EOF does not hurt */
-			return rc;
-		return 0;
+		return verify_uri_device(urd);
 	default:
 		return -ENOTSUPP;
 	}
 }
 
-static int get_file_reclen(struct urdev *urd)
+static int get_uri_file_reclen(struct urdev *urd)
 {
-	struct file_control_block fcb;
+	struct file_control_block *fcb;
 	int rc;
 
+	fcb = kmalloc(sizeof(*fcb), GFP_KERNEL | GFP_DMA);
+	if (!fcb)
+		return -ENOMEM;
+	rc = diag_read_next_file_info(fcb, 0);
+	if (rc)
+		goto fail_free;
+	if (fcb->file_stat & FLG_CP_DUMP)
+		rc = 0;
+	else
+		rc = fcb->rec_len;
+
+fail_free:
+	kfree(fcb);
+	return rc;
+}
+
+static int get_file_reclen(struct urdev *urd)
+{
 	switch (urd->class) {
 	case DEV_CLASS_UR_O:
 		return 0;
 	case DEV_CLASS_UR_I:
-		rc = diag_read_next_file_info(&fcb, 0);
-		if (rc)
-			return rc;
-		break;
+		return get_uri_file_reclen(urd);
 	default:
 		return -ENOTSUPP;
 	}
-	if (fcb.file_stat & FLG_CP_DUMP)
-		return 0;
-
-	return fcb.rec_len;
 }
 
 static int ur_open(struct inode *inode, struct file *file)
@@ -710,64 +770,63 @@
 
 /*
  * ccw_device infrastructure:
- *     ur_probe gets its own ref to the device (i.e. get_device),
- *     creates the struct urdev, the device attributes, sets up
- *     the interrupt handler and validates the virtual unit record device.
- *     ur_remove removes the device attributes, frees the struct urdev
- *     and drops (put_device) the ref to the device we got in ur_probe.
+ *     ur_probe creates the struct urdev (with refcount = 1), the device
+ *     attributes, sets up the interrupt handler and validates the virtual
+ *     unit record device.
+ *     ur_remove removes the device attributes and drops the reference to
+ *     struct urdev.
+ *
+ *     ur_probe, ur_remove, ur_set_online and ur_set_offline are serialized
+ *     by the vmur_mutex lock.
+ *
+ *     urd->char_device is used as indication that the online function has
+ *     been completed successfully.
  */
 static int ur_probe(struct ccw_device *cdev)
 {
 	struct urdev *urd;
 	int rc;
 
-	TRACE("ur_probe: cdev=%p state=%d\n", cdev, *(int *) cdev->private);
+	TRACE("ur_probe: cdev=%p\n", cdev);
 
-	if (!get_device(&cdev->dev))
-		return -ENODEV;
-
+	mutex_lock(&vmur_mutex);
 	urd = urdev_alloc(cdev);
 	if (!urd) {
 		rc = -ENOMEM;
-		goto fail;
+		goto fail_unlock;
 	}
+
 	rc = ur_create_attributes(&cdev->dev);
 	if (rc) {
 		rc = -ENOMEM;
-		goto fail;
+		goto fail_urdev_put;
 	}
-	cdev->dev.driver_data = urd;
 	cdev->handler = ur_int_handler;
 
 	/* validate virtual unit record device */
 	urd->class = get_urd_class(urd);
 	if (urd->class < 0) {
 		rc = urd->class;
-		goto fail;
+		goto fail_remove_attr;
 	}
 	if ((urd->class != DEV_CLASS_UR_I) && (urd->class != DEV_CLASS_UR_O)) {
 		rc = -ENOTSUPP;
-		goto fail;
+		goto fail_remove_attr;
 	}
+	spin_lock_irq(get_ccwdev_lock(cdev));
+	cdev->dev.driver_data = urd;
+	spin_unlock_irq(get_ccwdev_lock(cdev));
 
+	mutex_unlock(&vmur_mutex);
 	return 0;
 
-fail:
-	urdev_free(urd);
-	put_device(&cdev->dev);
-	return rc;
-}
-
-static void ur_remove(struct ccw_device *cdev)
-{
-	struct urdev *urd = cdev->dev.driver_data;
-
-	TRACE("ur_remove\n");
-	if (cdev->online)
-		ur_set_offline(cdev);
+fail_remove_attr:
 	ur_remove_attributes(&cdev->dev);
-	urdev_free(urd);
-	put_device(&cdev->dev);
+fail_urdev_put:
+	urdev_put(urd);
+fail_unlock:
+	mutex_unlock(&vmur_mutex);
+	return rc;
 }
 
 static int ur_set_online(struct ccw_device *cdev)
@@ -776,20 +835,29 @@
 	int minor, major, rc;
 	char node_id[16];
 
-	TRACE("ur_set_online: cdev=%p state=%d\n", cdev,
-	      *(int *) cdev->private);
+	TRACE("ur_set_online: cdev=%p\n", cdev);
 
-	if (!try_module_get(ur_driver.owner))
-		return -EINVAL;
+	mutex_lock(&vmur_mutex);
+	urd = urdev_get_from_cdev(cdev);
+	if (!urd) {
+		/* ur_remove already deleted our urd */
+		rc = -ENODEV;
+		goto fail_unlock;
+	}
 
-	urd = (struct urdev *) cdev->dev.driver_data;
+	if (urd->char_device) {
+		/* Another ur_set_online was faster */
+		rc = -EBUSY;
+		goto fail_urdev_put;
+	}
+
 	minor = urd->dev_id.devno;
 	major = MAJOR(ur_first_dev_maj_min);
 
 	urd->char_device = cdev_alloc();
 	if (!urd->char_device) {
 		rc = -ENOMEM;
-		goto fail_module_put;
+		goto fail_urdev_put;
 	}
 
 	cdev_init(urd->char_device, &ur_fops);
@@ -818,29 +886,79 @@
 		TRACE("ur_set_online: device_create rc=%d\n", rc);
 		goto fail_free_cdev;
 	}
-
+	urdev_put(urd);
+	mutex_unlock(&vmur_mutex);
 	return 0;
 
 fail_free_cdev:
 	cdev_del(urd->char_device);
-fail_module_put:
-	module_put(ur_driver.owner);
+	urd->char_device = NULL;
+fail_urdev_put:
+	urdev_put(urd);
+fail_unlock:
+	mutex_unlock(&vmur_mutex);
+	return rc;
+}
 
+static int ur_set_offline_force(struct ccw_device *cdev, int force)
+{
+	struct urdev *urd;
+	int rc;
+
+	TRACE("ur_set_offline: cdev=%p\n", cdev);
+	urd = urdev_get_from_cdev(cdev);
+	if (!urd)
+		/* ur_remove already deleted our urd */
+		return -ENODEV;
+	if (!urd->char_device) {
+		/* Another ur_set_offline was faster */
+		rc = -EBUSY;
+		goto fail_urdev_put;
+	}
+	if (!force && (atomic_read(&urd->ref_count) > 2)) {
+		/* There is still a user of urd (e.g. ur_open) */
+		TRACE("ur_set_offline: BUSY\n");
+		rc = -EBUSY;
+		goto fail_urdev_put;
+	}
+	device_destroy(vmur_class, urd->char_device->dev);
+	cdev_del(urd->char_device);
+	urd->char_device = NULL;
+	rc = 0;
+
+fail_urdev_put:
+	urdev_put(urd);
 	return rc;
 }
 
 static int ur_set_offline(struct ccw_device *cdev)
 {
-	struct urdev *urd;
+	int rc;
 
-	TRACE("ur_set_offline: cdev=%p cdev->private=%p state=%d\n",
-		cdev, cdev->private, *(int *) cdev->private);
-	urd = (struct urdev *) cdev->dev.driver_data;
-	device_destroy(vmur_class, urd->char_device->dev);
-	cdev_del(urd->char_device);
-	module_put(ur_driver.owner);
+	mutex_lock(&vmur_mutex);
+	rc = ur_set_offline_force(cdev, 0);
+	mutex_unlock(&vmur_mutex);
+	return rc;
+}
 
-	return 0;
+static void ur_remove(struct ccw_device *cdev)
+{
+	unsigned long flags;
+
+	TRACE("ur_remove\n");
+
+	mutex_lock(&vmur_mutex);
+
+	if (cdev->online)
+		ur_set_offline_force(cdev, 1);
+	ur_remove_attributes(&cdev->dev);
+
+	spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+	urdev_put(cdev->dev.driver_data);
+	cdev->dev.driver_data = NULL;
+	spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+
+	mutex_unlock(&vmur_mutex);
 }
 
 /*
diff --git a/drivers/s390/char/vmur.h b/drivers/s390/char/vmur.h
index 16d0a4e..fa95964 100644
--- a/drivers/s390/char/vmur.h
+++ b/drivers/s390/char/vmur.h
@@ -50,7 +50,10 @@
 	char  rest[200];
 } __attribute__ ((packed));
 
-#define FLG_CP_DUMP 0x10
+#define FLG_SYSTEM_HOLD	0x04
+#define FLG_CP_DUMP	0x10
+#define FLG_USER_HOLD	0x20
+#define FLG_IN_USE	0x80
 
 /*
  * A struct urdev is created for each ur device that is made available
@@ -67,6 +70,7 @@
 	size_t reclen;			/* Record length for *write* CCWs */
 	int class;			/* VM device class */
 	int io_request_rc;		/* return code from I/O request */
+	atomic_t ref_count;		/* reference counter */
 };
 
 /*
diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c
index 680b9b5..6f40fac 100644
--- a/drivers/s390/char/vmwatchdog.c
+++ b/drivers/s390/char/vmwatchdog.c
@@ -66,8 +66,8 @@
 		"0:	la	%0,0\n"
 		"1:\n"
 		EX_TABLE(0b,1b)
-		: "=d" (err) : "d"(__func), "d"(__timeout),
-		  "d"(__cmdp), "d"(__cmdl), "0" (-EINVAL) : "1", "cc");
+		: "+d" (err) : "d"(__func), "d"(__timeout),
+		  "d"(__cmdp), "d"(__cmdl) : "1", "cc");
 	return err;
 }
 
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 3712ede..7073daf 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -141,15 +141,16 @@
 
 	if (count == 0)
 		return 0;
-	flags = __raw_local_irq_stnsm(0xf8); /* switch to real mode */
+	flags = __raw_local_irq_stnsm(0xf8UL); /* switch to real mode */
 	asm volatile (
 		"0:	mvcle	%1,%2,0x0\n"
 		"1:	jo	0b\n"
 		"	lhi	%0,0x0\n"
 		"2:\n"
 		EX_TABLE(1b,2b)
-		: "+d" (rc)
-		: "d" (_dest), "d" (_src), "d" (_len1), "d" (_len2)
+		: "+d" (rc), "+d" (_dest), "+d" (_src), "+d" (_len1),
+		  "+d" (_len2), "=m" (*((long*)dest))
+		: "m" (*((long*)src))
 		: "cc", "memory");
 	__raw_local_irq_ssm(flags);
 
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index ec04048..bd5f16f 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -51,7 +51,7 @@
 		to = from;
 
 	if (from > to || to > __MAX_SUBCHANNEL || ssid > __MAX_SSID) {
-		printk (KERN_WARNING "Invalid blacklist range "
+		printk (KERN_WARNING "cio: Invalid blacklist range "
 			"0.%x.%04x to 0.%x.%04x, skipping\n",
 			ssid, from, ssid, to);
 		return;
@@ -119,7 +119,7 @@
 	return 0;
 confused:
 	strsep(str, ",\n");
-	printk(KERN_WARNING "Invalid cio_ignore parameter '%s'\n", sav);
+	printk(KERN_WARNING "cio: Invalid cio_ignore parameter '%s'\n", sav);
 	return 1;
 }
 
@@ -166,22 +166,19 @@
 					continue;
 			}
 			if (*str == '-') {
-				printk(KERN_WARNING "invalid cio_ignore "
+				printk(KERN_WARNING "cio: invalid cio_ignore "
 					"parameter '%s'\n",
 					strsep(&str, ",\n"));
 				continue;
 			}
 			if ((from_id0 != to_id0) ||
 			    (from_ssid != to_ssid)) {
-				printk(KERN_WARNING "invalid cio_ignore range "
-					"%x.%x.%04x-%x.%x.%04x\n",
-					from_id0, from_ssid, from,
-					to_id0, to_ssid, to);
+				printk(KERN_WARNING "cio: invalid cio_ignore "
+				       "range %x.%x.%04x-%x.%x.%04x\n",
+				       from_id0, from_ssid, from,
+				       to_id0, to_ssid, to);
 				continue;
 			}
-			pr_debug("blacklist_setup: adding range "
-				 "from %x.%x.%04x to %x.%x.%04x\n",
-				 from_id0, from_ssid, from, to_id0, to_ssid, to);
 			blacklist_range (ra, from, to, to_ssid);
 		}
 	}
@@ -239,7 +236,7 @@
 		 */
 		blacklist_parse_parameters (buf + 4, add);
 	} else {
-		printk (KERN_WARNING "cio_ignore: Parse error; \n"
+		printk (KERN_WARNING "cio: cio_ignore: Parse error; \n"
 			KERN_WARNING "try using 'free all|<devno-range>,"
 				     "<devno-range>,...'\n"
 			KERN_WARNING "or 'add <devno-range>,"
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index e5ccda6..5baa517 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -44,8 +44,7 @@
 	return 0;
 }
 static int
-ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer,
-		  int buffer_size)
+ccwgroup_uevent (struct device *dev, struct kobj_uevent_env *env)
 {
 	/* TODO */
 	return 0;
@@ -152,16 +151,24 @@
 	return 0;
 }
 
-/*
- * try to add a new ccwgroup device for one driver
- * argc and argv[] are a list of bus_id's of devices
- * belonging to the driver.
+/**
+ * ccwgroup_create() - create and register a ccw group device
+ * @root: parent device for the new device
+ * @creator_id: identifier of creating driver
+ * @cdrv: ccw driver of slave devices
+ * @argc: number of slave devices
+ * @argv: bus ids of slave devices
+ *
+ * Create and register a new ccw group device as a child of @root. Slave
+ * devices are obtained from the list of bus ids given in @argv[] and must all
+ * belong to @cdrv.
+ * Returns:
+ *  %0 on success and an error code on failure.
+ * Context:
+ *  non-atomic
  */
-int
-ccwgroup_create(struct device *root,
-		unsigned int creator_id,
-		struct ccw_driver *cdrv,
-		int argc, char *argv[])
+int ccwgroup_create(struct device *root, unsigned int creator_id,
+		    struct ccw_driver *cdrv, int argc, char *argv[])
 {
 	struct ccwgroup_device *gdev;
 	int i;
@@ -359,7 +366,6 @@
 	if ((ret = device_create_file(dev, &dev_attr_online)))
 		return ret;
 
-	pr_debug("%s: device %s\n", __func__, gdev->dev.bus_id);
 	ret = gdrv->probe ? gdrv->probe(gdev) : -ENODEV;
 	if (ret)
 		device_remove_file(dev, &dev_attr_online);
@@ -376,8 +382,6 @@
 	gdev = to_ccwgroupdev(dev);
 	gdrv = to_ccwgroupdrv(dev->driver);
 
-	pr_debug("%s: device %s\n", __func__, gdev->dev.bus_id);
-
 	device_remove_file(dev, &dev_attr_online);
 
 	if (gdrv && gdrv->remove)
@@ -393,8 +397,13 @@
 	.remove = ccwgroup_remove,
 };
 
-int
-ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
+/**
+ * ccwgroup_driver_register() - register a ccw group driver
+ * @cdriver: driver to be registered
+ *
+ * This function is mainly a wrapper around driver_register().
+ */
+int ccwgroup_driver_register(struct ccwgroup_driver *cdriver)
 {
 	/* register our new driver with the core */
 	cdriver->driver.bus = &ccwgroup_bus_type;
@@ -409,8 +418,13 @@
 	return 1;
 }
 
-void
-ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
+/**
+ * ccwgroup_driver_unregister() - deregister a ccw group driver
+ * @cdriver: driver to be deregistered
+ *
+ * This function is mainly a wrapper around driver_unregister().
+ */
+void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
 {
 	struct device *dev;
 
@@ -430,8 +444,16 @@
 	driver_unregister(&cdriver->driver);
 }
 
-int
-ccwgroup_probe_ccwdev(struct ccw_device *cdev)
+/**
+ * ccwgroup_probe_ccwdev() - probe function for slave devices
+ * @cdev: ccw device to be probed
+ *
+ * This is a dummy probe function for ccw devices that are slave devices in
+ * a ccw group device.
+ * Returns:
+ *  always %0
+ */
+int ccwgroup_probe_ccwdev(struct ccw_device *cdev)
 {
 	return 0;
 }
@@ -455,8 +477,15 @@
 	return NULL;
 }
 
-void
-ccwgroup_remove_ccwdev(struct ccw_device *cdev)
+/**
+ * ccwgroup_remove_ccwdev() - remove function for slave devices
+ * @cdev: ccw device to be removed
+ *
+ * This is a remove function for ccw devices that are slave devices in a ccw
+ * group device. It sets the ccw device offline and also deregisters the
+ * embedding ccw group device.
+ */
+void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
 {
 	struct ccwgroup_device *gdev;
 
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index b57d93d..42c1f46 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -14,7 +14,7 @@
 #include <linux/jiffies.h>
 #include <linux/wait.h>
 #include <linux/mutex.h>
-#include <asm/errno.h>
+#include <linux/errno.h>
 #include <asm/chpid.h>
 #include <asm/sclp.h>
 
@@ -55,7 +55,7 @@
 /* Return channel_path struct for given chpid. */
 static inline struct channel_path *chpid_to_chp(struct chp_id chpid)
 {
-	return css[chpid.cssid]->chps[chpid.id];
+	return channel_subsystems[chpid.cssid]->chps[chpid.id];
 }
 
 /* Set vary state for given chpid. */
@@ -86,7 +86,7 @@
 
 	opm = 0;
 	chp_id_init(&chpid);
-	for (i=0; i < 8; i++) {
+	for (i = 0; i < 8; i++) {
 		opm <<= 1;
 		chpid.id = sch->schib.pmcw.chpid[i];
 		if (chp_get_status(chpid) != 0)
@@ -118,17 +118,11 @@
 
 	sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid,
 		chpid.id);
-	CIO_TRACE_EVENT( 2, dbf_text);
+	CIO_TRACE_EVENT(2, dbf_text);
 
 	status = chp_get_status(chpid);
-	if (status < 0) {
-		printk(KERN_ERR "Can't vary unknown chpid %x.%02x\n",
-		       chpid.cssid, chpid.id);
-		return -EINVAL;
-	}
-
 	if (!on && !status) {
-		printk(KERN_ERR "chpid %x.%02x is already offline\n",
+		printk(KERN_ERR "cio: chpid %x.%02x is already offline\n",
 		       chpid.cssid, chpid.id);
 		return -EINVAL;
 	}
@@ -146,9 +140,11 @@
 					  char *buf, loff_t off, size_t count)
 {
 	struct channel_path *chp;
+	struct device *device;
 	unsigned int size;
 
-	chp = to_channelpath(container_of(kobj, struct device, kobj));
+	device = container_of(kobj, struct device, kobj);
+	chp = to_channelpath(device);
 	if (!chp->cmg_chars)
 		return 0;
 
@@ -199,9 +195,11 @@
 {
 	struct channel_path *chp;
 	struct channel_subsystem *css;
+	struct device *device;
 	unsigned int size;
 
-	chp = to_channelpath(container_of(kobj, struct device, kobj));
+	device = container_of(kobj, struct device, kobj);
+	chp = to_channelpath(device);
 	css = to_css(chp->dev.parent);
 
 	size = sizeof(struct cmg_entry);
@@ -359,7 +357,7 @@
 
 static DEVICE_ATTR(shared, 0444, chp_shared_show, NULL);
 
-static struct attribute * chp_attrs[] = {
+static struct attribute *chp_attrs[] = {
 	&dev_attr_status.attr,
 	&dev_attr_configure.attr,
 	&dev_attr_type.attr,
@@ -401,7 +399,7 @@
 	/* fill in status, etc. */
 	chp->chpid = chpid;
 	chp->state = 1;
-	chp->dev.parent = &css[chpid.cssid]->device;
+	chp->dev.parent = &channel_subsystems[chpid.cssid]->device;
 	chp->dev.release = chp_release;
 	snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp%x.%02x", chpid.cssid,
 		 chpid.id);
@@ -421,21 +419,14 @@
 		if (ret)
 			goto out_free;
 	} else {
-		static int msg_done;
-
-		if (!msg_done) {
-			printk(KERN_WARNING "cio: Channel measurements not "
-			       "available, continuing.\n");
-			msg_done = 1;
-		}
 		chp->cmg = -1;
 	}
 
 	/* make it known to the system */
 	ret = device_register(&chp->dev);
 	if (ret) {
-		printk(KERN_WARNING "%s: could not register %x.%02x\n",
-		       __func__, chpid.cssid, chpid.id);
+		CIO_MSG_EVENT(0, "Could not register chp%x.%02x: %d\n",
+			      chpid.cssid, chpid.id, ret);
 		goto out_free;
 	}
 	ret = sysfs_create_group(&chp->dev.kobj, &chp_attr_group);
@@ -443,18 +434,18 @@
 		device_unregister(&chp->dev);
 		goto out_free;
 	}
-	mutex_lock(&css[chpid.cssid]->mutex);
-	if (css[chpid.cssid]->cm_enabled) {
+	mutex_lock(&channel_subsystems[chpid.cssid]->mutex);
+	if (channel_subsystems[chpid.cssid]->cm_enabled) {
 		ret = chp_add_cmg_attr(chp);
 		if (ret) {
 			sysfs_remove_group(&chp->dev.kobj, &chp_attr_group);
 			device_unregister(&chp->dev);
-			mutex_unlock(&css[chpid.cssid]->mutex);
+			mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
 			goto out_free;
 		}
 	}
-	css[chpid.cssid]->chps[chpid.id] = chp;
-	mutex_unlock(&css[chpid.cssid]->mutex);
+	channel_subsystems[chpid.cssid]->chps[chpid.id] = chp;
+	mutex_unlock(&channel_subsystems[chpid.cssid]->mutex);
 	return ret;
 out_free:
 	kfree(chp);
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index ea92ac4..597c0c7 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -990,16 +990,20 @@
 	return ret;
 }
 
-static int __init
-chsc_alloc_sei_area(void)
+int __init chsc_alloc_sei_area(void)
 {
 	sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 	if (!sei_page)
-		printk(KERN_WARNING"Can't allocate page for processing of " \
-		       "chsc machine checks!\n");
+		CIO_MSG_EVENT(0, "Can't allocate page for processing of "
+			      "chsc machine checks!\n");
 	return (sei_page ? 0 : -ENOMEM);
 }
 
+void __init chsc_free_sei_area(void)
+{
+	kfree(sei_page);
+}
+
 int __init
 chsc_enable_facility(int operation_code)
 {
@@ -1051,8 +1055,6 @@
 	return ret;
 }
 
-subsys_initcall(chsc_alloc_sei_area);
-
 struct css_general_char css_general_characteristics;
 struct css_chsc_char css_chsc_characteristics;
 
@@ -1073,8 +1075,8 @@
 
 	scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
 	if (!scsc_area) {
-	        printk(KERN_WARNING"cio: Was not able to determine available" \
-		       "CHSCs due to no memory.\n");
+		CIO_MSG_EVENT(0, "Was not able to determine available"
+			      "CHSCs due to no memory.\n");
 		return -ENOMEM;
 	}
 
@@ -1083,15 +1085,15 @@
 
 	result = chsc(scsc_area);
 	if (result) {
-		printk(KERN_WARNING"cio: Was not able to determine " \
-		       "available CHSCs, cc=%i.\n", result);
+		CIO_MSG_EVENT(0, "Was not able to determine available CHSCs, "
+			      "cc=%i.\n", result);
 		result = -EIO;
 		goto exit;
 	}
 
 	if (scsc_area->response.code != 1) {
-		printk(KERN_WARNING"cio: Was not able to determine " \
-		       "available CHSCs.\n");
+		CIO_MSG_EVENT(0, "Was not able to determine "
+			      "available CHSCs.\n");
 		result = -EIO;
 		goto exit;
 	}
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index 2ad81d1..d1f5db1 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -79,6 +79,8 @@
 			     struct chsc_ssd_info *ssd);
 extern int chsc_determine_css_characteristics(void);
 extern int css_characteristics_avail;
+extern int chsc_alloc_sei_area(void);
+extern void chsc_free_sei_area(void);
 
 extern int chsc_enable_facility(int);
 struct channel_subsystem;
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index ea1defb..4690534 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -47,8 +47,8 @@
 	else if (!strcmp (parm, "no"))
 		cio_show_msg = 0;
 	else
-		printk (KERN_ERR "cio_setup : invalid cio_msg parameter '%s'",
-			parm);
+		printk(KERN_ERR "cio: cio_setup: "
+		       "invalid cio_msg parameter '%s'", parm);
 	return 1;
 }
 
@@ -80,7 +80,6 @@
 		goto out_unregister;
 	debug_register_view (cio_debug_crw_id, &debug_sprintf_view);
 	debug_set_level (cio_debug_crw_id, 2);
-	pr_debug("debugging initialized\n");
 	return 0;
 
 out_unregister:
@@ -90,7 +89,7 @@
 		debug_unregister (cio_debug_trace_id);
 	if (cio_debug_crw_id)
 		debug_unregister (cio_debug_crw_id);
-	pr_debug("could not initialize debugging\n");
+	printk(KERN_WARNING"cio: could not initialize debugging\n");
 	return -1;
 }
 
@@ -568,7 +567,7 @@
 	 */
 	if (sch->st != 0) {
 		CIO_DEBUG(KERN_INFO, 0,
-			  "Subchannel 0.%x.%04x reports "
+			  "cio: Subchannel 0.%x.%04x reports "
 			  "non-I/O subchannel type %04X\n",
 			  sch->schid.ssid, sch->schid.sch_no, sch->st);
 		/* We stop here for non-io subchannels. */
@@ -601,7 +600,7 @@
 	sch->lpm = sch->schib.pmcw.pam & sch->opm;
 
 	CIO_DEBUG(KERN_INFO, 0,
-		  "Detected device %04x on subchannel 0.%x.%04X"
+		  "cio: Detected device %04x on subchannel 0.%x.%04X"
 		  " - PIM = %02X, PAM = %02X, POM = %02X\n",
 		  sch->schib.pmcw.dev, sch->schid.ssid,
 		  sch->schid.sch_no, sch->schib.pmcw.pim,
@@ -620,6 +619,11 @@
 	sch->schib.pmcw.ena = 0;
 	if ((sch->lpm & (sch->lpm - 1)) != 0)
 		sch->schib.pmcw.mp = 1;	/* multipath mode */
+	/* clean up possible residual cmf stuff */
+	sch->schib.pmcw.mme = 0;
+	sch->schib.pmcw.mbfc = 0;
+	sch->schib.pmcw.mbi = 0;
+	sch->schib.mba = 0;
 	return 0;
 out:
 	if (!cio_is_console(schid))
@@ -766,7 +770,7 @@
 		/* unlike in 2.4, we cannot autoprobe here, since
 		 * the channel subsystem is not fully initialized.
 		 * With some luck, the HWC console can take over */
-		printk(KERN_WARNING "No ccw console found!\n");
+		printk(KERN_WARNING "cio: No ccw console found!\n");
 		return -1;
 	}
 	return console_irq;
diff --git a/drivers/s390/cio/cio_debug.h b/drivers/s390/cio/cio_debug.h
index f88844a..c9bf898 100644
--- a/drivers/s390/cio/cio_debug.h
+++ b/drivers/s390/cio/cio_debug.h
@@ -23,6 +23,8 @@
 static inline void
 CIO_HEX_EVENT(int level, void *data, int length)
 {
+	if (unlikely(!cio_debug_trace_id))
+		return;
 	while (length > 0) {
 		debug_event(cio_debug_trace_id, level, data, length);
 		length -= cio_debug_trace_id->buf_size;
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 28abd69..b960f66 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -45,7 +45,8 @@
 #include "ioasm.h"
 #include "chsc.h"
 
-/* parameter to enable cmf during boot, possible uses are:
+/*
+ * parameter to enable cmf during boot, possible uses are:
  *  "s390cmf" -- enable cmf and allocate 2 MB of ram so measuring can be
  *               used on any subchannel
  *  "s390cmf=<num>" -- enable cmf and allocate enough memory to measure
@@ -73,18 +74,20 @@
  * enum cmb_format - types of supported measurement block formats
  *
  * @CMF_BASIC:      traditional channel measurement blocks supported
- * 		    by all machines that we run on
+ *		    by all machines that we run on
  * @CMF_EXTENDED:   improved format that was introduced with the z990
- * 		    machine
- * @CMF_AUTODETECT: default: use extended format when running on a z990
- *                  or later machine, otherwise fall back to basic format
- **/
+ *		    machine
+ * @CMF_AUTODETECT: default: use extended format when running on a machine
+ *		    supporting extended format, otherwise fall back to
+ *		    basic format
+ */
 enum cmb_format {
 	CMF_BASIC,
 	CMF_EXTENDED,
 	CMF_AUTODETECT = -1,
 };
-/**
+
+/*
  * format - actual format for all measurement blocks
  *
  * The format module parameter can be set to a value of 0 (zero)
@@ -105,20 +108,21 @@
  *		either with the help of a special pool or with kmalloc
  * @free:	free memory allocated with @alloc
  * @set:	enable or disable measurement
+ * @read:	read a measurement entry at an index
  * @readall:	read a measurement block in a common format
  * @reset:	clear the data in the associated measurement block and
  *		reset its time stamp
  * @align:	align an allocated block so that the hardware can use it
  */
 struct cmb_operations {
-	int (*alloc)  (struct ccw_device*);
-	void(*free)   (struct ccw_device*);
-	int (*set)    (struct ccw_device*, u32);
-	u64 (*read)   (struct ccw_device*, int);
-	int (*readall)(struct ccw_device*, struct cmbdata *);
-	void (*reset) (struct ccw_device*);
-	void * (*align) (void *);
-
+	int  (*alloc)  (struct ccw_device *);
+	void (*free)   (struct ccw_device *);
+	int  (*set)    (struct ccw_device *, u32);
+	u64  (*read)   (struct ccw_device *, int);
+	int  (*readall)(struct ccw_device *, struct cmbdata *);
+	void (*reset)  (struct ccw_device *);
+	void *(*align) (void *);
+/* private: */
 	struct attribute_group *attr_group;
 };
 static struct cmb_operations *cmbops;
@@ -130,9 +134,11 @@
 	unsigned long long last_update;  /* when last_block was updated */
 };
 
-/* our user interface is designed in terms of nanoseconds,
+/*
+ * Our user interface is designed in terms of nanoseconds,
  * while the hardware measures total times in its own
- * unit.*/
+ * unit.
+ */
 static inline u64 time_to_nsec(u32 value)
 {
 	return ((u64)value) * 128000ull;
@@ -159,12 +165,13 @@
 	return ret;
 }
 
-/* activate or deactivate the channel monitor. When area is NULL,
+/*
+ * Activate or deactivate the channel monitor. When area is NULL,
  * the monitor is deactivated. The channel monitor needs to
  * be active in order to measure subchannels, which also need
- * to be enabled. */
-static inline void
-cmf_activate(void *area, unsigned int onoff)
+ * to be enabled.
+ */
+static inline void cmf_activate(void *area, unsigned int onoff)
 {
 	register void * __gpr2 asm("2");
 	register long __gpr1 asm("1");
@@ -175,8 +182,8 @@
 	asm("schm" : : "d" (__gpr2), "d" (__gpr1) );
 }
 
-static int
-set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address)
+static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc,
+		     unsigned long address)
 {
 	int ret;
 	int retry;
@@ -466,6 +473,7 @@
  *
  * @mem:	pointer to CMBs (only in basic measurement mode)
  * @list:	contains a linked list of all subchannels
+ * @num_channels: number of channels to be measured
  * @lock:	protect concurrent access to @mem and @list
  */
 struct cmb_area {
@@ -481,28 +489,36 @@
 	.num_channels  = 1024,
 };
 
-
 /* ****** old style CMB handling ********/
 
-/** int maxchannels
- *
+/*
  * Basic channel measurement blocks are allocated in one contiguous
  * block of memory, which can not be moved as long as any channel
  * is active. Therefore, a maximum number of subchannels needs to
  * be defined somewhere. This is a module parameter, defaulting to
  * a resonable value of 1024, or 32 kb of memory.
  * Current kernels don't allow kmalloc with more than 128kb, so the
- * maximum is 4096
+ * maximum is 4096.
  */
 
 module_param_named(maxchannels, cmb_area.num_channels, uint, 0444);
 
 /**
  * struct cmb - basic channel measurement block
+ * @ssch_rsch_count: number of ssch and rsch
+ * @sample_count: number of samples
+ * @device_connect_time: time of device connect
+ * @function_pending_time: time of function pending
+ * @device_disconnect_time: time of device disconnect
+ * @control_unit_queuing_time: time of control unit queuing
+ * @device_active_only_time: time of device active only
+ * @reserved: unused in basic measurement mode
  *
- * cmb as used by the hardware the fields are described in z/Architecture
- * Principles of Operation, chapter 17.
- * The area to be a contiguous array and may not be reallocated or freed.
+ * The measurement block as used by the hardware. The fields are described
+ * further in z/Architecture Principles of Operation, chapter 17.
+ *
+ * The cmb area made up from these blocks must be a contiguous array and may
+ * not be reallocated or freed.
  * Only one cmb area can be present in the system.
  */
 struct cmb {
@@ -516,8 +532,9 @@
 	u32 reserved[2];
 };
 
-/* insert a single device into the cmb_area list
- * called with cmb_area.lock held from alloc_cmb
+/*
+ * Insert a single device into the cmb_area list.
+ * Called with cmb_area.lock held from alloc_cmb.
  */
 static int alloc_cmb_single(struct ccw_device *cdev,
 			    struct cmb_data *cmb_data)
@@ -532,9 +549,11 @@
 		goto out;
 	}
 
-	/* find first unused cmb in cmb_area.mem.
-	 * this is a little tricky: cmb_area.list
-	 * remains sorted by ->cmb->hw_data pointers */
+	/*
+	 * Find first unused cmb in cmb_area.mem.
+	 * This is a little tricky: cmb_area.list
+	 * remains sorted by ->cmb->hw_data pointers.
+	 */
 	cmb = cmb_area.mem;
 	list_for_each_entry(node, &cmb_area.list, cmb_list) {
 		struct cmb_data *data;
@@ -558,8 +577,7 @@
 	return ret;
 }
 
-static int
-alloc_cmb (struct ccw_device *cdev)
+static int alloc_cmb(struct ccw_device *cdev)
 {
 	int ret;
 	struct cmb *mem;
@@ -594,6 +612,9 @@
 			free_pages((unsigned long)mem, get_order(size));
 		} else if (!mem) {
 			/* no luck */
+			printk(KERN_WARNING "cio: failed to allocate area "
+			       "for measuring %d subchannels\n",
+			       cmb_area.num_channels);
 			ret = -ENOMEM;
 			goto out;
 		} else {
@@ -667,7 +688,7 @@
 	return set_schib_wait(cdev, mme, 0, offset);
 }
 
-static u64 read_cmb (struct ccw_device *cdev, int index)
+static u64 read_cmb(struct ccw_device *cdev, int index)
 {
 	struct cmb *cmb;
 	u32 val;
@@ -717,7 +738,7 @@
 	return ret;
 }
 
-static int readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmb(struct ccw_device *cdev, struct cmbdata *data)
 {
 	struct cmb *cmb;
 	struct cmb_data *cmb_data;
@@ -790,14 +811,25 @@
 	.align	    = align_cmb,
 	.attr_group = &cmf_attr_group,
 };
-
+
 /* ******** extended cmb handling ********/
 
 /**
  * struct cmbe - extended channel measurement block
+ * @ssch_rsch_count: number of ssch and rsch
+ * @sample_count: number of samples
+ * @device_connect_time: time of device connect
+ * @function_pending_time: time of function pending
+ * @device_disconnect_time: time of device disconnect
+ * @control_unit_queuing_time: time of control unit queuing
+ * @device_active_only_time: time of device active only
+ * @device_busy_time: time of device busy
+ * @initial_command_response_time: initial command response time
+ * @reserved: unused
  *
- * cmb as used by the hardware, may be in any 64 bit physical location,
- * the fields are described in z/Architecture Principles of Operation,
+ * The measurement block as used by the hardware. May be in any 64 bit physical
+ * location.
+ * The fields are described further in z/Architecture Principles of Operation,
  * third edition, chapter 17.
  */
 struct cmbe {
@@ -813,10 +845,12 @@
 	u32 reserved[7];
 };
 
-/* kmalloc only guarantees 8 byte alignment, but we need cmbe
+/*
+ * kmalloc only guarantees 8 byte alignment, but we need cmbe
  * pointers to be naturally aligned. Make sure to allocate
- * enough space for two cmbes */
-static inline struct cmbe* cmbe_align(struct cmbe *c)
+ * enough space for two cmbes.
+ */
+static inline struct cmbe *cmbe_align(struct cmbe *c)
 {
 	unsigned long addr;
 	addr = ((unsigned long)c + sizeof (struct cmbe) - sizeof(long)) &
@@ -824,7 +858,7 @@
 	return (struct cmbe*)addr;
 }
 
-static int alloc_cmbe (struct ccw_device *cdev)
+static int alloc_cmbe(struct ccw_device *cdev)
 {
 	struct cmbe *cmbe;
 	struct cmb_data *cmb_data;
@@ -870,7 +904,7 @@
 	return ret;
 }
 
-static void free_cmbe (struct ccw_device *cdev)
+static void free_cmbe(struct ccw_device *cdev)
 {
 	struct cmb_data *cmb_data;
 
@@ -909,7 +943,7 @@
 }
 
 
-static u64 read_cmbe (struct ccw_device *cdev, int index)
+static u64 read_cmbe(struct ccw_device *cdev, int index)
 {
 	struct cmbe *cmb;
 	struct cmb_data *cmb_data;
@@ -967,7 +1001,7 @@
 	return ret;
 }
 
-static int readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmbe(struct ccw_device *cdev, struct cmbdata *data)
 {
 	struct cmbe *cmb;
 	struct cmb_data *cmb_data;
@@ -1044,17 +1078,16 @@
 	.align	    = align_cmbe,
 	.attr_group = &cmf_attr_group_ext,
 };
-
 
-static ssize_t
-cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx)
+static ssize_t cmb_show_attr(struct device *dev, char *buf, enum cmb_index idx)
 {
 	return sprintf(buf, "%lld\n",
 		(unsigned long long) cmf_read(to_ccwdev(dev), idx));
 }
 
-static ssize_t
-cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_show_avg_sample_interval(struct device *dev,
+					    struct device_attribute *attr,
+					    char *buf)
 {
 	struct ccw_device *cdev;
 	long interval;
@@ -1076,8 +1109,9 @@
 	return sprintf(buf, "%ld\n", interval);
 }
 
-static ssize_t
-cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_show_avg_utilization(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
 {
 	struct cmbdata data;
 	u64 utilization;
@@ -1109,14 +1143,16 @@
 }
 
 #define cmf_attr(name) \
-static ssize_t show_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \
-{ return cmb_show_attr((dev), buf, cmb_ ## name); } \
-static DEVICE_ATTR(name, 0444, show_ ## name, NULL);
+static ssize_t show_##name(struct device *dev, \
+			   struct device_attribute *attr, char *buf)	\
+{ return cmb_show_attr((dev), buf, cmb_##name); } \
+static DEVICE_ATTR(name, 0444, show_##name, NULL);
 
 #define cmf_attr_avg(name) \
-static ssize_t show_avg_ ## name (struct device * dev, struct device_attribute *attr, char * buf) \
-{ return cmb_show_attr((dev), buf, cmb_ ## name); } \
-static DEVICE_ATTR(avg_ ## name, 0444, show_avg_ ## name, NULL);
+static ssize_t show_avg_##name(struct device *dev, \
+			       struct device_attribute *attr, char *buf) \
+{ return cmb_show_attr((dev), buf, cmb_##name); } \
+static DEVICE_ATTR(avg_##name, 0444, show_avg_##name, NULL);
 
 cmf_attr(ssch_rsch_count);
 cmf_attr(sample_count);
@@ -1128,7 +1164,8 @@
 cmf_attr_avg(device_busy_time);
 cmf_attr_avg(initial_command_response_time);
 
-static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval, NULL);
+static DEVICE_ATTR(avg_sample_interval, 0444, cmb_show_avg_sample_interval,
+		   NULL);
 static DEVICE_ATTR(avg_utilization, 0444, cmb_show_avg_utilization, NULL);
 
 static struct attribute *cmf_attributes[] = {
@@ -1169,12 +1206,16 @@
 	.attrs = cmf_attributes_ext,
 };
 
-static ssize_t cmb_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t cmb_enable_show(struct device *dev,
+			       struct device_attribute *attr,
+			       char *buf)
 {
 	return sprintf(buf, "%d\n", to_ccwdev(dev)->private->cmb ? 1 : 0);
 }
 
-static ssize_t cmb_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t c)
+static ssize_t cmb_enable_store(struct device *dev,
+				struct device_attribute *attr, const char *buf,
+				size_t c)
 {
 	struct ccw_device *cdev;
 	int ret;
@@ -1185,12 +1226,12 @@
 	case '0':
 		ret = disable_cmf(cdev);
 		if (ret)
-			printk(KERN_INFO "disable_cmf failed (%d)\n", ret);
+			dev_info(&cdev->dev, "disable_cmf failed (%d)\n", ret);
 		break;
 	case '1':
 		ret = enable_cmf(cdev);
 		if (ret && ret != -EBUSY)
-			printk(KERN_INFO "enable_cmf failed (%d)\n", ret);
+			dev_info(&cdev->dev, "enable_cmf failed (%d)\n", ret);
 		break;
 	}
 
@@ -1199,9 +1240,16 @@
 
 DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store);
 
-/* enable_cmf/disable_cmf: module interface for cmf (de)activation */
-int
-enable_cmf(struct ccw_device *cdev)
+/**
+ * enable_cmf() - switch on the channel measurement for a specific device
+ *  @cdev:	The ccw device to be enabled
+ *
+ *  Returns %0 for success or a negative error value.
+ *
+ *  Context:
+ *    non-atomic
+ */
+int enable_cmf(struct ccw_device *cdev)
 {
 	int ret;
 
@@ -1222,8 +1270,16 @@
 	return ret;
 }
 
-int
-disable_cmf(struct ccw_device *cdev)
+/**
+ * disable_cmf() - switch off the channel measurement for a specific device
+ *  @cdev:	The ccw device to be disabled
+ *
+ *  Returns %0 for success or a negative error value.
+ *
+ *  Context:
+ *    non-atomic
+ */
+int disable_cmf(struct ccw_device *cdev)
 {
 	int ret;
 
@@ -1235,14 +1291,32 @@
 	return ret;
 }
 
-u64
-cmf_read(struct ccw_device *cdev, int index)
+/**
+ * cmf_read() - read one value from the current channel measurement block
+ * @cdev:	the channel to be read
+ * @index:	the index of the value to be read
+ *
+ * Returns the value read or %0 if the value cannot be read.
+ *
+ *  Context:
+ *    any
+ */
+u64 cmf_read(struct ccw_device *cdev, int index)
 {
 	return cmbops->read(cdev, index);
 }
 
-int
-cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
+/**
+ * cmf_readall() - read the current channel measurement block
+ * @cdev:	the channel to be read
+ * @data:	a pointer to a data block that will be filled
+ *
+ * Returns %0 on success, a negative error value otherwise.
+ *
+ *  Context:
+ *    any
+ */
+int cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
 {
 	return cmbops->readall(cdev, data);
 }
@@ -1254,15 +1328,16 @@
 	return cmbops->set(cdev, 2);
 }
 
-static int __init
-init_cmf(void)
+static int __init init_cmf(void)
 {
 	char *format_string;
 	char *detect_string = "parameter";
 
-	/* We cannot really autoprobe this. If the user did not give a parameter,
-	   see if we are running on z990 or up, otherwise fall back to basic mode. */
-
+	/*
+	 * If the user did not give a parameter, see if we are running on a
+	 * machine supporting extended measurement blocks, otherwise fall back
+	 * to basic mode.
+	 */
 	if (format == CMF_AUTODETECT) {
 		if (!css_characteristics_avail ||
 		    !css_general_characteristics.ext_mb) {
@@ -1279,26 +1354,19 @@
 	case CMF_BASIC:
 		format_string = "basic";
 		cmbops = &cmbops_basic;
-		if (cmb_area.num_channels > 4096 || cmb_area.num_channels < 1) {
-			printk(KERN_ERR "Basic channel measurement facility"
-					" can only use 1 to 4096 devices\n"
-			       KERN_ERR "when the cmf driver is built"
-					" as a loadable module\n");
-			return 1;
-		}
 		break;
 	case CMF_EXTENDED:
- 		format_string = "extended";
+		format_string = "extended";
 		cmbops = &cmbops_extended;
 		break;
 	default:
-		printk(KERN_ERR "Invalid format %d for channel "
+		printk(KERN_ERR "cio: Invalid format %d for channel "
 			"measurement facility\n", format);
 		return 1;
 	}
 
-	printk(KERN_INFO "Channel measurement facility using %s format (%s)\n",
-		format_string, detect_string);
+	printk(KERN_INFO "cio: Channel measurement facility using %s "
+	       "format (%s)\n", format_string, detect_string);
 	return 0;
 }
 
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index dfca0ef..5d83dd4 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/list.h>
+#include <linux/reboot.h>
 
 #include "css.h"
 #include "cio.h"
@@ -27,7 +28,7 @@
 static int need_reprobe = 0;
 static int max_ssid = 0;
 
-struct channel_subsystem *css[__MAX_CSSID + 1];
+struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1];
 
 int css_characteristics_avail = 0;
 
@@ -79,6 +80,7 @@
 	sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
 	ret = cio_modify(sch);
 	if (ret) {
+		kfree(sch->lock);
 		kfree(sch);
 		return ERR_PTR(ret);
 	}
@@ -109,7 +111,7 @@
 	}
 }
 
-int css_sch_device_register(struct subchannel *sch)
+static int css_sch_device_register(struct subchannel *sch)
 {
 	int ret;
 
@@ -176,7 +178,7 @@
 	int ret;
 
 	/* Initialize the subchannel structure */
-	sch->dev.parent = &css[0]->device;
+	sch->dev.parent = &channel_subsystems[0]->device;
 	sch->dev.bus = &css_bus_type;
 	sch->dev.release = &css_subchannel_release;
 	sch->dev.groups = subch_attr_groups;
@@ -184,8 +186,8 @@
 	/* make it known to the system */
 	ret = css_sch_device_register(sch);
 	if (ret) {
-		printk (KERN_WARNING "%s: could not register %s\n",
-			__func__, sch->dev.bus_id);
+		CIO_MSG_EVENT(0, "Could not register sch 0.%x.%04x: %d\n",
+			      sch->schid.ssid, sch->schid.sch_no, ret);
 		return ret;
 	}
 	return ret;
@@ -371,15 +373,12 @@
 	spin_lock_init(&slow_subchannel_lock);
 	slow_subchannel_set = idset_sch_new();
 	if (!slow_subchannel_set) {
-		printk(KERN_WARNING "cio: could not allocate slow subchannel "
-		       "set\n");
+		CIO_MSG_EVENT(0, "could not allocate slow subchannel set\n");
 		return -ENOMEM;
 	}
 	return 0;
 }
 
-subsys_initcall(slow_subchannel_init);
-
 static void css_slow_path_func(struct work_struct *unused)
 {
 	struct subchannel_id schid;
@@ -425,8 +424,8 @@
 	struct subchannel *sch;
 	int ret;
 
-	CIO_DEBUG(KERN_INFO, 6, "cio: reprobe 0.%x.%04x\n",
-		  schid.ssid, schid.sch_no);
+	CIO_MSG_EVENT(6, "cio: reprobe 0.%x.%04x\n",
+		      schid.ssid, schid.sch_no);
 	if (need_reprobe)
 		return -EAGAIN;
 
@@ -608,30 +607,55 @@
 {
 	u32 tod_high;
 	int ret;
+	struct channel_subsystem *css;
 
-	memset(css[nr], 0, sizeof(struct channel_subsystem));
-	css[nr]->pseudo_subchannel =
-		kzalloc(sizeof(*css[nr]->pseudo_subchannel), GFP_KERNEL);
-	if (!css[nr]->pseudo_subchannel)
+	css = channel_subsystems[nr];
+	memset(css, 0, sizeof(struct channel_subsystem));
+	css->pseudo_subchannel =
+		kzalloc(sizeof(*css->pseudo_subchannel), GFP_KERNEL);
+	if (!css->pseudo_subchannel)
 		return -ENOMEM;
-	css[nr]->pseudo_subchannel->dev.parent = &css[nr]->device;
-	css[nr]->pseudo_subchannel->dev.release = css_subchannel_release;
-	sprintf(css[nr]->pseudo_subchannel->dev.bus_id, "defunct");
-	ret = cio_create_sch_lock(css[nr]->pseudo_subchannel);
+	css->pseudo_subchannel->dev.parent = &css->device;
+	css->pseudo_subchannel->dev.release = css_subchannel_release;
+	sprintf(css->pseudo_subchannel->dev.bus_id, "defunct");
+	ret = cio_create_sch_lock(css->pseudo_subchannel);
 	if (ret) {
-		kfree(css[nr]->pseudo_subchannel);
+		kfree(css->pseudo_subchannel);
 		return ret;
 	}
-	mutex_init(&css[nr]->mutex);
-	css[nr]->valid = 1;
-	css[nr]->cssid = nr;
-	sprintf(css[nr]->device.bus_id, "css%x", nr);
-	css[nr]->device.release = channel_subsystem_release;
+	mutex_init(&css->mutex);
+	css->valid = 1;
+	css->cssid = nr;
+	sprintf(css->device.bus_id, "css%x", nr);
+	css->device.release = channel_subsystem_release;
 	tod_high = (u32) (get_clock() >> 32);
-	css_generate_pgid(css[nr], tod_high);
+	css_generate_pgid(css, tod_high);
 	return 0;
 }
 
+static int css_reboot_event(struct notifier_block *this,
+			    unsigned long event,
+			    void *ptr)
+{
+	int ret, i;
+
+	ret = NOTIFY_DONE;
+	for (i = 0; i <= __MAX_CSSID; i++) {
+		struct channel_subsystem *css;
+
+		css = channel_subsystems[i];
+		if (css->cm_enabled)
+			if (chsc_secm(css, 0))
+				ret = NOTIFY_BAD;
+	}
+
+	return ret;
+}
+
+static struct notifier_block css_reboot_notifier = {
+	.notifier_call = css_reboot_event,
+};
+
 /*
  * Now that the driver core is running, we can setup our channel subsystem.
  * The struct subchannel's are created during probing (except for the
@@ -642,9 +666,20 @@
 {
 	int ret, i;
 
-	if (chsc_determine_css_characteristics() == 0)
+	ret = chsc_determine_css_characteristics();
+	if (ret == -ENOMEM)
+		goto out; /* No need to continue. */
+	if (ret == 0)
 		css_characteristics_avail = 1;
 
+	ret = chsc_alloc_sei_area();
+	if (ret)
+		goto out;
+
+	ret = slow_subchannel_init();
+	if (ret)
+		goto out;
+
 	if ((ret = bus_register(&css_bus_type)))
 		goto out;
 
@@ -661,55 +696,71 @@
 	}
 	/* Setup css structure. */
 	for (i = 0; i <= __MAX_CSSID; i++) {
-		css[i] = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);
-		if (!css[i]) {
+		struct channel_subsystem *css;
+
+		css = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);
+		if (!css) {
 			ret = -ENOMEM;
 			goto out_unregister;
 		}
+		channel_subsystems[i] = css;
 		ret = setup_css(i);
 		if (ret)
 			goto out_free;
-		ret = device_register(&css[i]->device);
+		ret = device_register(&css->device);
 		if (ret)
 			goto out_free_all;
 		if (css_characteristics_avail &&
 		    css_chsc_characteristics.secm) {
-			ret = device_create_file(&css[i]->device,
+			ret = device_create_file(&css->device,
 						 &dev_attr_cm_enable);
 			if (ret)
 				goto out_device;
 		}
-		ret = device_register(&css[i]->pseudo_subchannel->dev);
+		ret = device_register(&css->pseudo_subchannel->dev);
 		if (ret)
 			goto out_file;
 	}
+	ret = register_reboot_notifier(&css_reboot_notifier);
+	if (ret)
+		goto out_pseudo;
 	css_init_done = 1;
 
 	ctl_set_bit(6, 28);
 
 	for_each_subchannel(__init_channel_subsystem, NULL);
 	return 0;
+out_pseudo:
+	device_unregister(&channel_subsystems[i]->pseudo_subchannel->dev);
 out_file:
-	device_remove_file(&css[i]->device, &dev_attr_cm_enable);
+	device_remove_file(&channel_subsystems[i]->device,
+			   &dev_attr_cm_enable);
 out_device:
-	device_unregister(&css[i]->device);
+	device_unregister(&channel_subsystems[i]->device);
 out_free_all:
-	kfree(css[i]->pseudo_subchannel->lock);
-	kfree(css[i]->pseudo_subchannel);
+	kfree(channel_subsystems[i]->pseudo_subchannel->lock);
+	kfree(channel_subsystems[i]->pseudo_subchannel);
 out_free:
-	kfree(css[i]);
+	kfree(channel_subsystems[i]);
 out_unregister:
 	while (i > 0) {
+		struct channel_subsystem *css;
+
 		i--;
-		device_unregister(&css[i]->pseudo_subchannel->dev);
+		css = channel_subsystems[i];
+		device_unregister(&css->pseudo_subchannel->dev);
 		if (css_characteristics_avail && css_chsc_characteristics.secm)
-			device_remove_file(&css[i]->device,
+			device_remove_file(&css->device,
 					   &dev_attr_cm_enable);
-		device_unregister(&css[i]->device);
+		device_unregister(&css->device);
 	}
 out_bus:
 	bus_unregister(&css_bus_type);
 out:
+	chsc_free_sei_area();
+	kfree(slow_subchannel_set);
+	printk(KERN_WARNING"cio: failed to initialize css driver (%d)!\n",
+	       ret);
 	return ret;
 }
 
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index ed79775..81215ef 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -139,7 +139,6 @@
  */
 extern struct bus_type css_bus_type;
 
-extern int css_sch_device_register(struct subchannel *);
 extern void css_sch_device_unregister(struct subchannel *);
 extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
 extern int css_init_done;
@@ -168,7 +167,7 @@
 #define to_css(dev) container_of(dev, struct channel_subsystem, device)
 
 extern struct bus_type css_bus_type;
-extern struct channel_subsystem *css[];
+extern struct channel_subsystem *channel_subsystems[];
 
 /* Some helper functions for disconnected state. */
 int device_is_disconnected(struct subchannel *);
@@ -192,6 +191,5 @@
 
 extern struct workqueue_struct *slow_path_wq;
 
-int subchannel_add_files (struct device *);
 extern struct attribute_group *subch_attr_groups[];
 #endif
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 001682e..7ee57f0 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -21,6 +21,7 @@
 #include <asm/ccwdev.h>
 #include <asm/cio.h>
 #include <asm/param.h>		/* HZ */
+#include <asm/cmb.h>
 
 #include "cio.h"
 #include "cio_debug.h"
@@ -78,45 +79,37 @@
 
 /* Set up environment variables for ccw device uevent. Return 0 on success,
  * non-zero otherwise. */
-static int ccw_uevent(struct device *dev, char **envp, int num_envp,
-		      char *buffer, int buffer_size)
+static int ccw_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct ccw_device *cdev = to_ccwdev(dev);
 	struct ccw_device_id *id = &(cdev->id);
-	int i = 0;
-	int len = 0;
 	int ret;
 	char modalias_buf[30];
 
 	/* CU_TYPE= */
-	ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-			     "CU_TYPE=%04X", id->cu_type);
+	ret = add_uevent_var(env, "CU_TYPE=%04X", id->cu_type);
 	if (ret)
 		return ret;
 
 	/* CU_MODEL= */
-	ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-			     "CU_MODEL=%02X", id->cu_model);
+	ret = add_uevent_var(env, "CU_MODEL=%02X", id->cu_model);
 	if (ret)
 		return ret;
 
 	/* The next two can be zero, that's ok for us */
 	/* DEV_TYPE= */
-	ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-			     "DEV_TYPE=%04X", id->dev_type);
+	ret = add_uevent_var(env, "DEV_TYPE=%04X", id->dev_type);
 	if (ret)
 		return ret;
 
 	/* DEV_MODEL= */
-	ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-			     "DEV_MODEL=%02X", id->dev_model);
+	ret = add_uevent_var(env, "DEV_MODEL=%02X", id->dev_model);
 	if (ret)
 		return ret;
 
 	/* MODALIAS=  */
 	snprint_alias(modalias_buf, sizeof(modalias_buf), id, "");
-	ret = add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-			     "MODALIAS=%s", modalias_buf);
+	ret = add_uevent_var(env, "MODALIAS=%s", modalias_buf);
 	return ret;
 }
 
@@ -338,19 +331,34 @@
 		rc = device_schedule_callback(&cdev->dev,
 					      ccw_device_remove_orphan_cb);
 		if (rc)
-			dev_info(&cdev->dev, "Couldn't unregister orphan\n");
+			CIO_MSG_EVENT(2, "Couldn't unregister orphan "
+				      "0.%x.%04x\n",
+				      cdev->private->dev_id.ssid,
+				      cdev->private->dev_id.devno);
 		return;
 	}
 	/* Deregister subchannel, which will kill the ccw device. */
 	rc = device_schedule_callback(cdev->dev.parent,
 				      ccw_device_remove_sch_cb);
 	if (rc)
-		dev_info(&cdev->dev,
-			 "Couldn't unregister disconnected device\n");
+		CIO_MSG_EVENT(2, "Couldn't unregister disconnected device "
+			      "0.%x.%04x\n",
+			      cdev->private->dev_id.ssid,
+			      cdev->private->dev_id.devno);
 }
 
-int
-ccw_device_set_offline(struct ccw_device *cdev)
+/**
+ * ccw_device_set_offline() - disable a ccw device for I/O
+ * @cdev: target ccw device
+ *
+ * This function calls the driver's set_offline() function for @cdev, if
+ * given, and then disables @cdev.
+ * Returns:
+ *   %0 on success and a negative error value on failure.
+ * Context:
+ *  enabled, ccw device lock not held
+ */
+int ccw_device_set_offline(struct ccw_device *cdev)
 {
 	int ret;
 
@@ -379,15 +387,28 @@
 	if (ret == 0)
 		wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
 	else {
-		pr_debug("ccw_device_offline returned %d, device %s\n",
-			 ret, cdev->dev.bus_id);
+		CIO_MSG_EVENT(2, "ccw_device_offline returned %d, "
+			      "device 0.%x.%04x\n",
+			      ret, cdev->private->dev_id.ssid,
+			      cdev->private->dev_id.devno);
 		cdev->online = 1;
 	}
  	return ret;
 }
 
-int
-ccw_device_set_online(struct ccw_device *cdev)
+/**
+ * ccw_device_set_online() - enable a ccw device for I/O
+ * @cdev: target ccw device
+ *
+ * This function first enables @cdev and then calls the driver's set_online()
+ * function for @cdev, if given. If set_online() returns an error, @cdev is
+ * disabled again.
+ * Returns:
+ *   %0 on success and a negative error value on failure.
+ * Context:
+ *  enabled, ccw device lock not held
+ */
+int ccw_device_set_online(struct ccw_device *cdev)
 {
 	int ret;
 
@@ -402,8 +423,10 @@
 	if (ret == 0)
 		wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
 	else {
-		pr_debug("ccw_device_online returned %d, device %s\n",
-			 ret, cdev->dev.bus_id);
+		CIO_MSG_EVENT(2, "ccw_device_online returned %d, "
+			      "device 0.%x.%04x\n",
+			      ret, cdev->private->dev_id.ssid,
+			      cdev->private->dev_id.devno);
 		return ret;
 	}
 	if (cdev->private->state != DEV_STATE_ONLINE)
@@ -417,9 +440,11 @@
 	spin_unlock_irq(cdev->ccwlock);
 	if (ret == 0)
 		wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
-	else 
-		pr_debug("ccw_device_offline returned %d, device %s\n",
-			 ret, cdev->dev.bus_id);
+	else
+		CIO_MSG_EVENT(2, "ccw_device_offline returned %d, "
+			      "device 0.%x.%04x\n",
+			      ret, cdev->private->dev_id.ssid,
+			      cdev->private->dev_id.devno);
 	return (ret == 0) ? -ENODEV : ret;
 }
 
@@ -439,9 +464,10 @@
 	if (cdev->id.cu_type == 0) {
 		ret = ccw_device_recognition(cdev);
 		if (ret) {
-			printk(KERN_WARNING"Couldn't start recognition "
-			       "for device %s (ret=%d)\n",
-			       cdev->dev.bus_id, ret);
+			CIO_MSG_EVENT(0, "Couldn't start recognition "
+				      "for device 0.%x.%04x (ret=%d)\n",
+				      cdev->private->dev_id.ssid,
+				      cdev->private->dev_id.devno, ret);
 			return ret;
 		}
 		wait_event(cdev->private->wait_q,
@@ -461,8 +487,8 @@
 	if (force && cdev->private->state == DEV_STATE_BOXED) {
 		ret = ccw_device_stlck(cdev);
 		if (ret) {
-			printk(KERN_WARNING"ccw_device_stlck for device %s "
-			       "returned %d!\n", cdev->dev.bus_id, ret);
+			dev_warn(&cdev->dev,
+				 "ccw_device_stlck returned %d!\n", ret);
 			return;
 		}
 		if (cdev->id.cu_type == 0)
@@ -893,8 +919,10 @@
 			ret = device_reprobe(&cdev->dev);
 			if (ret)
 				/* We can't do much here. */
-				dev_info(&cdev->dev, "device_reprobe() returned"
-					 " %d\n", ret);
+				CIO_MSG_EVENT(2, "device_reprobe() returned"
+					      " %d for 0.%x.%04x\n", ret,
+					      cdev->private->dev_id.ssid,
+					      cdev->private->dev_id.devno);
 		}
 		goto out;
 	}
@@ -907,8 +935,9 @@
 	/* make it known to the system */
 	ret = ccw_device_register(cdev);
 	if (ret) {
-		printk (KERN_WARNING "%s: could not register %s\n",
-			__func__, cdev->dev.bus_id);
+		CIO_MSG_EVENT(0, "Could not register ccw dev 0.%x.%04x: %d\n",
+			      cdev->private->dev_id.ssid,
+			      cdev->private->dev_id.devno, ret);
 		put_device(&cdev->dev);
 		spin_lock_irqsave(sch->lock, flags);
 		sch->dev.driver_data = NULL;
@@ -929,8 +958,7 @@
 		wake_up(&ccw_device_init_wq);
 }
 
-void
-ccw_device_call_sch_unregister(struct work_struct *work)
+static void ccw_device_call_sch_unregister(struct work_struct *work)
 {
 	struct ccw_device_private *priv;
 	struct ccw_device *cdev;
@@ -1083,6 +1111,7 @@
 		 * device, e.g. the console.
 		 */
 		cdev = sch->dev.driver_data;
+		cdev->dev.groups = ccwdev_attr_groups;
 		device_initialize(&cdev->dev);
 		ccw_device_register(cdev);
 		/*
@@ -1308,8 +1337,19 @@
 }
 
 
-struct ccw_device *
-get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id)
+/**
+ * get_ccwdev_by_busid() - obtain device from a bus id
+ * @cdrv: driver the device is owned by
+ * @bus_id: bus id of the device to be searched
+ *
+ * This function searches all devices owned by @cdrv for a device with a bus
+ * id matching @bus_id.
+ * Returns:
+ *  If a match is found, its reference count of the found device is increased
+ *  and it is returned; else %NULL is returned.
+ */
+struct ccw_device *get_ccwdev_by_busid(struct ccw_driver *cdrv,
+				       const char *bus_id)
 {
 	struct device *dev;
 	struct device_driver *drv;
@@ -1361,7 +1401,6 @@
 	struct ccw_driver *cdrv = cdev->drv;
 	int ret;
 
-	pr_debug("removing device %s\n", cdev->dev.bus_id);
 	if (cdrv->remove)
 		cdrv->remove(cdev);
 	if (cdev->online) {
@@ -1374,24 +1413,44 @@
 				   dev_fsm_final_state(cdev));
 		else
 			//FIXME: we can't fail!
-			pr_debug("ccw_device_offline returned %d, device %s\n",
-				 ret, cdev->dev.bus_id);
+			CIO_MSG_EVENT(2, "ccw_device_offline returned %d, "
+				      "device 0.%x.%04x\n",
+				      ret, cdev->private->dev_id.ssid,
+				      cdev->private->dev_id.devno);
 	}
 	ccw_device_set_timeout(cdev, 0);
 	cdev->drv = NULL;
 	return 0;
 }
 
+static void ccw_device_shutdown(struct device *dev)
+{
+	struct ccw_device *cdev;
+
+	cdev = to_ccwdev(dev);
+	if (cdev->drv && cdev->drv->shutdown)
+		cdev->drv->shutdown(cdev);
+	disable_cmf(cdev);
+}
+
 struct bus_type ccw_bus_type = {
 	.name   = "ccw",
 	.match  = ccw_bus_match,
 	.uevent = ccw_uevent,
 	.probe  = ccw_device_probe,
 	.remove = ccw_device_remove,
+	.shutdown = ccw_device_shutdown,
 };
 
-int
-ccw_driver_register (struct ccw_driver *cdriver)
+/**
+ * ccw_driver_register() - register a ccw driver
+ * @cdriver: driver to be registered
+ *
+ * This function is mainly a wrapper around driver_register().
+ * Returns:
+ *   %0 on success and a negative error value on failure.
+ */
+int ccw_driver_register(struct ccw_driver *cdriver)
 {
 	struct device_driver *drv = &cdriver->driver;
 
@@ -1401,8 +1460,13 @@
 	return driver_register(drv);
 }
 
-void
-ccw_driver_unregister (struct ccw_driver *cdriver)
+/**
+ * ccw_driver_unregister() - deregister a ccw driver
+ * @cdriver: driver to be deregistered
+ *
+ * This function is mainly a wrapper around driver_unregister().
+ */
+void ccw_driver_unregister(struct ccw_driver *cdriver)
 {
 	driver_unregister(&cdriver->driver);
 }
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index b66338b..0d40896 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -80,7 +80,6 @@
 int ccw_device_cancel_halt_clear(struct ccw_device *);
 
 void ccw_device_do_unreg_rereg(struct work_struct *);
-void ccw_device_call_sch_unregister(struct work_struct *);
 void ccw_device_move_to_orphanage(struct work_struct *);
 int ccw_device_is_orphan(struct ccw_device *);
 
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 6bba809..8867443 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -268,7 +268,7 @@
 	switch (state) {
 	case DEV_STATE_NOT_OPER:
 		CIO_DEBUG(KERN_WARNING, 2,
-			  "SenseID : unknown device %04x on subchannel "
+			  "cio: SenseID : unknown device %04x on subchannel "
 			  "0.%x.%04x\n", cdev->private->dev_id.devno,
 			  sch->schid.ssid, sch->schid.sch_no);
 		break;
@@ -293,7 +293,8 @@
 			return;
 		}
 		/* Issue device info message. */
-		CIO_DEBUG(KERN_INFO, 2, "SenseID : device 0.%x.%04x reports: "
+		CIO_DEBUG(KERN_INFO, 2,
+			  "cio: SenseID : device 0.%x.%04x reports: "
 			  "CU  Type/Mod = %04X/%02X, Dev Type/Mod = "
 			  "%04X/%02X\n",
 			  cdev->private->dev_id.ssid,
@@ -303,7 +304,7 @@
 		break;
 	case DEV_STATE_BOXED:
 		CIO_DEBUG(KERN_WARNING, 2,
-			  "SenseID : boxed device %04x on subchannel "
+			  "cio: SenseID : boxed device %04x on subchannel "
 			  "0.%x.%04x\n", cdev->private->dev_id.devno,
 			  sch->schid.ssid, sch->schid.sch_no);
 		break;
@@ -388,7 +389,7 @@
 
 	if (state == DEV_STATE_BOXED)
 		CIO_DEBUG(KERN_WARNING, 2,
-			  "Boxed device %04x on subchannel %04x\n",
+			  "cio: Boxed device %04x on subchannel %04x\n",
 			  cdev->private->dev_id.devno, sch->schid.sch_no);
 
 	if (cdev->private->flags.donotify) {
@@ -445,7 +446,8 @@
 	if (cdev->private->pgid[last].inf.ps.state1 ==
 	    SNID_STATE1_RESET)
 		/* No previous pgid found */
-		memcpy(&cdev->private->pgid[0], &css[0]->global_pgid,
+		memcpy(&cdev->private->pgid[0],
+		       &channel_subsystems[0]->global_pgid,
 		       sizeof(struct pgid));
 	else
 		/* Use existing pgid */
@@ -542,51 +544,6 @@
 }
 
 
-static void
-ccw_device_nopath_notify(struct work_struct *work)
-{
-	struct ccw_device_private *priv;
-	struct ccw_device *cdev;
-	struct subchannel *sch;
-	int ret;
-	unsigned long flags;
-
-	priv = container_of(work, struct ccw_device_private, kick_work);
-	cdev = priv->cdev;
-	spin_lock_irqsave(cdev->ccwlock, flags);
-	sch = to_subchannel(cdev->dev.parent);
-	/* Extra sanity. */
-	if (sch->lpm)
-		goto out_unlock;
-	if (sch->driver && sch->driver->notify) {
-		spin_unlock_irqrestore(cdev->ccwlock, flags);
-		ret = sch->driver->notify(&sch->dev, CIO_NO_PATH);
-		spin_lock_irqsave(cdev->ccwlock, flags);
-	} else
-		ret = 0;
-	if (!ret) {
-		if (get_device(&sch->dev)) {
-			/* Driver doesn't want to keep device. */
-			cio_disable_subchannel(sch);
-			if (get_device(&cdev->dev)) {
-				PREPARE_WORK(&cdev->private->kick_work,
-					     ccw_device_call_sch_unregister);
-				queue_work(ccw_device_work,
-					   &cdev->private->kick_work);
-			} else
-				put_device(&sch->dev);
-		}
-	} else {
-		cio_disable_subchannel(sch);
-		ccw_device_set_timeout(cdev, 0);
-		cdev->private->flags.fake_irb = 0;
-		cdev->private->state = DEV_STATE_DISCONNECTED;
-		wake_up(&cdev->private->wait_q);
-	}
-out_unlock:
-	spin_unlock_irqrestore(cdev->ccwlock, flags);
-}
-
 void
 ccw_device_verify_done(struct ccw_device *cdev, int err)
 {
@@ -630,12 +587,9 @@
 	default:
 		/* Reset oper notify indication after verify error. */
 		cdev->private->flags.donotify = 0;
-		if (cdev->online) {
-			PREPARE_WORK(&cdev->private->kick_work,
-				     ccw_device_nopath_notify);
-			queue_work(ccw_device_notify_work,
-				   &cdev->private->kick_work);
-		} else
+		if (cdev->online)
+			dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+		else
 			ccw_device_done(cdev, DEV_STATE_NOT_OPER);
 		break;
 	}
@@ -689,11 +643,7 @@
 		break;
 	default:
 		cdev->private->flags.donotify = 0;
-		if (get_device(&cdev->dev)) {
-			PREPARE_WORK(&cdev->private->kick_work,
-				     ccw_device_call_sch_unregister);
-			queue_work(ccw_device_work, &cdev->private->kick_work);
-		}
+		dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
 		ccw_device_done(cdev, DEV_STATE_NOT_OPER);
 		break;
 	}
@@ -764,59 +714,16 @@
 }
 
 /*
- * Handle not operational event while offline.
+ * Handle not operational event in non-special state.
  */
-static void
-ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event)
+static void ccw_device_generic_notoper(struct ccw_device *cdev,
+				       enum dev_event dev_event)
 {
 	struct subchannel *sch;
 
 	cdev->private->state = DEV_STATE_NOT_OPER;
 	sch = to_subchannel(cdev->dev.parent);
-	if (get_device(&cdev->dev)) {
-		PREPARE_WORK(&cdev->private->kick_work,
-			     ccw_device_call_sch_unregister);
-		queue_work(ccw_device_work, &cdev->private->kick_work);
-	}
-	wake_up(&cdev->private->wait_q);
-}
-
-/*
- * Handle not operational event while online.
- */
-static void
-ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event)
-{
-	struct subchannel *sch;
-	int ret;
-
-	sch = to_subchannel(cdev->dev.parent);
-	if (sch->driver->notify) {
-		spin_unlock_irq(cdev->ccwlock);
-		ret = sch->driver->notify(&sch->dev,
-					  sch->lpm ? CIO_GONE : CIO_NO_PATH);
-		spin_lock_irq(cdev->ccwlock);
-	} else
-		ret = 0;
-	if (ret) {
-		ccw_device_set_timeout(cdev, 0);
-		cdev->private->flags.fake_irb = 0;
-		cdev->private->state = DEV_STATE_DISCONNECTED;
-		wake_up(&cdev->private->wait_q);
-		return;
-	}
-	cdev->private->state = DEV_STATE_NOT_OPER;
-	cio_disable_subchannel(sch);
-	if (sch->schib.scsw.actl != 0) {
-		// FIXME: not-oper indication to device driver ?
-		ccw_device_call_handler(cdev);
-	}
-	if (get_device(&cdev->dev)) {
-		PREPARE_WORK(&cdev->private->kick_work,
-			     ccw_device_call_sch_unregister);
-		queue_work(ccw_device_work, &cdev->private->kick_work);
-	}
-	wake_up(&cdev->private->wait_q);
+	css_schedule_eval(sch->schid);
 }
 
 /*
@@ -914,18 +821,9 @@
 		cdev->private->state = DEV_STATE_TIMEOUT_KILL;
 		return;
 	}
-	if (ret == -ENODEV) {
-		struct subchannel *sch;
-
-		sch = to_subchannel(cdev->dev.parent);
-		if (!sch->lpm) {
-			PREPARE_WORK(&cdev->private->kick_work,
-				     ccw_device_nopath_notify);
-			queue_work(ccw_device_notify_work,
-				   &cdev->private->kick_work);
-		} else
-			dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
-	} else if (cdev->handler)
+	if (ret == -ENODEV)
+		dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
+	else if (cdev->handler)
 		cdev->handler(cdev, cdev->private->intparm,
 			      ERR_PTR(-ETIMEDOUT));
 }
@@ -946,9 +844,10 @@
 			/* Basic sense hasn't started. Try again. */
 			ccw_device_do_sense(cdev, irb);
 		else {
-			printk(KERN_INFO "Huh? %s(%s): unsolicited "
-			       "interrupt...\n",
-			       __FUNCTION__, cdev->dev.bus_id);
+			CIO_MSG_EVENT(2, "Huh? 0.%x.%04x: unsolicited "
+				      "interrupt during w4sense...\n",
+				      cdev->private->dev_id.ssid,
+				      cdev->private->dev_id.devno);
 			if (cdev->handler)
 				cdev->handler (cdev, 0, irb);
 		}
@@ -1215,8 +1114,8 @@
 static void
 ccw_device_bug(struct ccw_device *cdev, enum dev_event dev_event)
 {
-	printk(KERN_EMERG "dev_jumptable[%i][%i] == NULL\n",
-	       cdev->private->state, dev_event);
+	CIO_MSG_EVENT(0, "dev_jumptable[%i][%i] == NULL\n",
+		      cdev->private->state, dev_event);
 	BUG();
 }
 
@@ -1231,7 +1130,7 @@
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	[DEV_STATE_SENSE_PGID] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_online_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_sense_pgid_irq,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_onoff_timeout,
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
@@ -1243,50 +1142,50 @@
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	[DEV_STATE_OFFLINE] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_offline_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_offline_irq,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_nop,
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	[DEV_STATE_VERIFY] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_online_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_verify_irq,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_onoff_timeout,
 		[DEV_EVENT_VERIFY]	= ccw_device_delay_verify,
 	},
 	[DEV_STATE_ONLINE] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_online_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_irq,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_online_timeout,
 		[DEV_EVENT_VERIFY]	= ccw_device_online_verify,
 	},
 	[DEV_STATE_W4SENSE] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_online_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_w4sense,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_nop,
 		[DEV_EVENT_VERIFY]	= ccw_device_online_verify,
 	},
 	[DEV_STATE_DISBAND_PGID] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_online_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_disband_irq,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_onoff_timeout,
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	[DEV_STATE_BOXED] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_offline_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_stlck_done,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_stlck_done,
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	/* states to wait for i/o completion before doing something */
 	[DEV_STATE_CLEAR_VERIFY] = {
-		[DEV_EVENT_NOTOPER]     = ccw_device_online_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]   = ccw_device_clear_verify,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_nop,
 		[DEV_EVENT_VERIFY]	= ccw_device_nop,
 	},
 	[DEV_STATE_TIMEOUT_KILL] = {
-		[DEV_EVENT_NOTOPER]	= ccw_device_online_notoper,
+		[DEV_EVENT_NOTOPER]	= ccw_device_generic_notoper,
 		[DEV_EVENT_INTERRUPT]	= ccw_device_killing_irq,
 		[DEV_EVENT_TIMEOUT]	= ccw_device_killing_timeout,
 		[DEV_EVENT_VERIFY]	= ccw_device_nop, //FIXME
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
index 60b9347..f232832 100644
--- a/drivers/s390/cio/device_id.c
+++ b/drivers/s390/cio/device_id.c
@@ -17,6 +17,7 @@
 #include <asm/delay.h>
 #include <asm/cio.h>
 #include <asm/lowcore.h>
+#include <asm/diag.h>
 
 #include "cio.h"
 #include "cio_debug.h"
@@ -25,51 +26,6 @@
 #include "ioasm.h"
 
 /*
- * diag210 is used under VM to get information about a virtual device
- */
-int
-diag210(struct diag210 * addr)
-{
-	/*
-	 * diag 210 needs its data below the 2GB border, so we
-	 * use a static data area to be sure
-	 */
-	static struct diag210 diag210_tmp;
-	static DEFINE_SPINLOCK(diag210_lock);
-	unsigned long flags;
-	int ccode;
-
-	spin_lock_irqsave(&diag210_lock, flags);
-	diag210_tmp = *addr;
-
-#ifdef CONFIG_64BIT
-	asm volatile(
-		"	lhi	%0,-1\n"
-		"	sam31\n"
-		"	diag	%1,0,0x210\n"
-		"0:	ipm	%0\n"
-		"	srl	%0,28\n"
-		"1:	sam64\n"
-		EX_TABLE(0b,1b)
-		: "=&d" (ccode) : "a" (&diag210_tmp) : "cc", "memory");
-#else
-	asm volatile(
-		"	lhi	%0,-1\n"
-		"	diag	%1,0,0x210\n"
-		"0:	ipm	%0\n"
-		"	srl	%0,28\n"
-		"1:\n"
-		EX_TABLE(0b,1b)
-		: "=&d" (ccode) : "a" (&diag210_tmp) : "cc", "memory");
-#endif
-
-	*addr = diag210_tmp;
-	spin_unlock_irqrestore(&diag210_lock, flags);
-
-	return ccode;
-}
-
-/*
  * Input :
  *   devno - device number
  *   ps	   - pointer to sense ID data area
@@ -349,5 +305,3 @@
 		break;
 	}
 }
-
-EXPORT_SYMBOL(diag210);
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index a5d263f..7fd2dad 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -25,6 +25,16 @@
 #include "device.h"
 #include "chp.h"
 
+/**
+ * ccw_device_set_options_mask() - set some options and unset the rest
+ * @cdev: device for which the options are to be set
+ * @flags: options to be set
+ *
+ * All flags specified in @flags are set, all flags not specified in @flags
+ * are cleared.
+ * Returns:
+ *   %0 on success, -%EINVAL on an invalid flag combination.
+ */
 int ccw_device_set_options_mask(struct ccw_device *cdev, unsigned long flags)
 {
        /*
@@ -40,6 +50,15 @@
 	return 0;
 }
 
+/**
+ * ccw_device_set_options() - set some options
+ * @cdev: device for which the options are to be set
+ * @flags: options to be set
+ *
+ * All flags specified in @flags are set, the remainder is left untouched.
+ * Returns:
+ *   %0 on success, -%EINVAL if an invalid flag combination would ensue.
+ */
 int ccw_device_set_options(struct ccw_device *cdev, unsigned long flags)
 {
        /*
@@ -59,6 +78,13 @@
 	return 0;
 }
 
+/**
+ * ccw_device_clear_options() - clear some options
+ * @cdev: device for which the options are to be cleared
+ * @flags: options to be cleared
+ *
+ * All flags specified in @flags are cleared, the remainder is left untouched.
+ */
 void ccw_device_clear_options(struct ccw_device *cdev, unsigned long flags)
 {
 	cdev->private->options.fast &= (flags & CCWDEV_EARLY_NOTIFICATION) == 0;
@@ -67,8 +93,22 @@
 	cdev->private->options.force &= (flags & CCWDEV_ALLOW_FORCE) == 0;
 }
 
-int
-ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
+/**
+ * ccw_device_clear() - terminate I/O request processing
+ * @cdev: target ccw device
+ * @intparm: interruption parameter; value is only used if no I/O is
+ *	     outstanding, otherwise the intparm associated with the I/O request
+ *	     is returned
+ *
+ * ccw_device_clear() calls csch on @cdev's subchannel.
+ * Returns:
+ *  %0 on success,
+ *  -%ENODEV on device not operational,
+ *  -%EINVAL on invalid device state.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
 {
 	struct subchannel *sch;
 	int ret;
@@ -89,10 +129,33 @@
 	return ret;
 }
 
-int
-ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
-		     unsigned long intparm, __u8 lpm, __u8 key,
-		     unsigned long flags)
+/**
+ * ccw_device_start_key() - start a s390 channel program with key
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ *	     @cdev's interrupt handler. Allows a device driver to associate
+ *	     the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ *	 value of 0 will make cio use the opm.
+ * @key: storage key to be used for the I/O
+ * @flags: additional flags; defines the action to be performed for I/O
+ *	   processing.
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * Returns:
+ *  %0, if the operation was successful;
+ *  -%EBUSY, if the device is busy, or status pending;
+ *  -%EACCES, if no path specified in @lpm is operational;
+ *  -%ENODEV, if the device is not operational.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
+			 unsigned long intparm, __u8 lpm, __u8 key,
+			 unsigned long flags)
 {
 	struct subchannel *sch;
 	int ret;
@@ -135,11 +198,38 @@
 	return ret;
 }
 
-
-int
-ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
-			     unsigned long intparm, __u8 lpm, __u8 key,
-			     unsigned long flags, int expires)
+/**
+ * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ *	     @cdev's interrupt handler. Allows a device driver to associate
+ *	     the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ *	 value of 0 will make cio use the opm.
+ * @key: storage key to be used for the I/O
+ * @flags: additional flags; defines the action to be performed for I/O
+ *	   processing.
+ * @expires: timeout value in jiffies
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * This function notifies the device driver if the channel program has not
+ * completed during the time specified by @expires. If a timeout occurs, the
+ * channel program is terminated via xsch, hsch or csch, and the device's
+ * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT).
+ * Returns:
+ *  %0, if the operation was successful;
+ *  -%EBUSY, if the device is busy, or status pending;
+ *  -%EACCES, if no path specified in @lpm is operational;
+ *  -%ENODEV, if the device is not operational.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
+				 unsigned long intparm, __u8 lpm, __u8 key,
+				 unsigned long flags, int expires)
 {
 	int ret;
 
@@ -152,18 +242,67 @@
 	return ret;
 }
 
-int
-ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
-		 unsigned long intparm, __u8 lpm, unsigned long flags)
+/**
+ * ccw_device_start() - start a s390 channel program
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ *	     @cdev's interrupt handler. Allows a device driver to associate
+ *	     the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ *	 value of 0 will make cio use the opm.
+ * @flags: additional flags; defines the action to be performed for I/O
+ *	   processing.
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * Returns:
+ *  %0, if the operation was successful;
+ *  -%EBUSY, if the device is busy, or status pending;
+ *  -%EACCES, if no path specified in @lpm is operational;
+ *  -%ENODEV, if the device is not operational.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start(struct ccw_device *cdev, struct ccw1 *cpa,
+		     unsigned long intparm, __u8 lpm, unsigned long flags)
 {
 	return ccw_device_start_key(cdev, cpa, intparm, lpm,
 				    PAGE_DEFAULT_KEY, flags);
 }
 
-int
-ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
-			 unsigned long intparm, __u8 lpm, unsigned long flags,
-			 int expires)
+/**
+ * ccw_device_start_timeout() - start a s390 channel program with timeout
+ * @cdev: target ccw device
+ * @cpa: logical start address of channel program
+ * @intparm: user specific interruption parameter; will be presented back to
+ *	     @cdev's interrupt handler. Allows a device driver to associate
+ *	     the interrupt with a particular I/O request.
+ * @lpm: defines the channel path to be used for a specific I/O request. A
+ *	 value of 0 will make cio use the opm.
+ * @flags: additional flags; defines the action to be performed for I/O
+ *	   processing.
+ * @expires: timeout value in jiffies
+ *
+ * Start a S/390 channel program. When the interrupt arrives, the
+ * IRQ handler is called, either immediately, delayed (dev-end missing,
+ * or sense required) or never (no IRQ handler registered).
+ * This function notifies the device driver if the channel program has not
+ * completed during the time specified by @expires. If a timeout occurs, the
+ * channel program is terminated via xsch, hsch or csch, and the device's
+ * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT).
+ * Returns:
+ *  %0, if the operation was successful;
+ *  -%EBUSY, if the device is busy, or status pending;
+ *  -%EACCES, if no path specified in @lpm is operational;
+ *  -%ENODEV, if the device is not operational.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_start_timeout(struct ccw_device *cdev, struct ccw1 *cpa,
+			     unsigned long intparm, __u8 lpm,
+			     unsigned long flags, int expires)
 {
 	return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm,
 					    PAGE_DEFAULT_KEY, flags,
@@ -171,8 +310,23 @@
 }
 
 
-int
-ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
+/**
+ * ccw_device_halt() - halt I/O request processing
+ * @cdev: target ccw device
+ * @intparm: interruption parameter; value is only used if no I/O is
+ *	     outstanding, otherwise the intparm associated with the I/O request
+ *	     is returned
+ *
+ * ccw_device_halt() calls hsch on @cdev's subchannel.
+ * Returns:
+ *  %0 on success,
+ *  -%ENODEV on device not operational,
+ *  -%EINVAL on invalid device state,
+ *  -%EBUSY on device busy or interrupt pending.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
 {
 	struct subchannel *sch;
 	int ret;
@@ -193,8 +347,20 @@
 	return ret;
 }
 
-int
-ccw_device_resume(struct ccw_device *cdev)
+/**
+ * ccw_device_resume() - resume channel program execution
+ * @cdev: target ccw device
+ *
+ * ccw_device_resume() calls rsch on @cdev's subchannel.
+ * Returns:
+ *  %0 on success,
+ *  -%ENODEV on device not operational,
+ *  -%EINVAL on invalid device state,
+ *  -%EBUSY on device busy or interrupt pending.
+ * Context:
+ *  Interrupts disabled, ccw device lock held
+ */
+int ccw_device_resume(struct ccw_device *cdev)
 {
 	struct subchannel *sch;
 
@@ -260,11 +426,21 @@
 	return 1;
 }
 
-/*
- * Search for CIW command in extended sense data.
+/**
+ * ccw_device_get_ciw() - Search for CIW command in extended sense data.
+ * @cdev: ccw device to inspect
+ * @ct: command type to look for
+ *
+ * During SenseID, command information words (CIWs) describing special
+ * commands available to the device may have been stored in the extended
+ * sense data. This function searches for CIWs of a specified command
+ * type in the extended sense data.
+ * Returns:
+ *  %NULL if no extended sense data has been stored or if no CIW of the
+ *  specified command type could be found,
+ *  else a pointer to the CIW of the specified command type.
  */
-struct ciw *
-ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
+struct ciw *ccw_device_get_ciw(struct ccw_device *cdev, __u32 ct)
 {
 	int ciw_cnt;
 
@@ -276,8 +452,14 @@
 	return NULL;
 }
 
-__u8
-ccw_device_get_path_mask(struct ccw_device *cdev)
+/**
+ * ccw_device_get_path_mask() - get currently available paths
+ * @cdev: ccw device to be queried
+ * Returns:
+ *  %0 if no subchannel for the device is available,
+ *  else the mask of currently available paths for the ccw device's subchannel.
+ */
+__u8 ccw_device_get_path_mask(struct ccw_device *cdev)
 {
 	struct subchannel *sch;
 
@@ -288,253 +470,6 @@
 		return sch->lpm;
 }
 
-static void
-ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
-{
-	if (!ip)
-		/* unsolicited interrupt */
-		return;
-
-	/* Abuse intparm for error reporting. */
-	if (IS_ERR(irb))
-		cdev->private->intparm = -EIO;
-	else if (irb->scsw.cc == 1)
-		/* Retry for deferred condition code. */
-		cdev->private->intparm = -EAGAIN;
-	else if ((irb->scsw.dstat !=
-		  (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
-		 (irb->scsw.cstat != 0)) {
-		/*
-		 * We didn't get channel end / device end. Check if path
-		 * verification has been started; we can retry after it has
-		 * finished. We also retry unit checks except for command reject
-		 * or intervention required. Also check for long busy
-		 * conditions.
-		 */
-		 if (cdev->private->flags.doverify ||
-			 cdev->private->state == DEV_STATE_VERIFY)
-			 cdev->private->intparm = -EAGAIN;
-		else if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) &&
-			 !(irb->ecw[0] &
-			   (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)))
-			cdev->private->intparm = -EAGAIN;
-		else if ((irb->scsw.dstat & DEV_STAT_ATTENTION) &&
-			 (irb->scsw.dstat & DEV_STAT_DEV_END) &&
-			 (irb->scsw.dstat & DEV_STAT_UNIT_EXCEP))
-			cdev->private->intparm = -EAGAIN;
-		 else
-			 cdev->private->intparm = -EIO;
-			 
-	} else
-		cdev->private->intparm = 0;
-	wake_up(&cdev->private->wait_q);
-}
-
-static int
-__ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, __u8 lpm)
-{
-	int ret;
-	struct subchannel *sch;
-
-	sch = to_subchannel(cdev->dev.parent);
-	do {
-		ccw_device_set_timeout(cdev, 60 * HZ);
-		ret = cio_start (sch, ccw, lpm);
-		if (ret != 0)
-			ccw_device_set_timeout(cdev, 0);
-		if (ret == -EBUSY) {
-			/* Try again later. */
-			spin_unlock_irq(sch->lock);
-			msleep(10);
-			spin_lock_irq(sch->lock);
-			continue;
-		}
-		if (ret != 0)
-			/* Non-retryable error. */
-			break;
-		/* Wait for end of request. */
-		cdev->private->intparm = magic;
-		spin_unlock_irq(sch->lock);
-		wait_event(cdev->private->wait_q,
-			   (cdev->private->intparm == -EIO) ||
-			   (cdev->private->intparm == -EAGAIN) ||
-			   (cdev->private->intparm == 0));
-		spin_lock_irq(sch->lock);
-		/* Check at least for channel end / device end */
-		if (cdev->private->intparm == -EIO) {
-			/* Non-retryable error. */
-			ret = -EIO;
-			break;
-		}
-		if (cdev->private->intparm == 0)
-			/* Success. */
-			break;
-		/* Try again later. */
-		spin_unlock_irq(sch->lock);
-		msleep(10);
-		spin_lock_irq(sch->lock);
-	} while (1);
-
-	return ret;
-}
-
-/**
- * read_dev_chars() - read device characteristics
- * @param cdev   target ccw device
- * @param buffer pointer to buffer for rdc data
- * @param length size of rdc data
- * @returns 0 for success, negative error value on failure
- *
- * Context:
- *   called for online device, lock not held
- **/
-int
-read_dev_chars (struct ccw_device *cdev, void **buffer, int length)
-{
-	void (*handler)(struct ccw_device *, unsigned long, struct irb *);
-	struct subchannel *sch;
-	int ret;
-	struct ccw1 *rdc_ccw;
-
-	if (!cdev)
-		return -ENODEV;
-	if (!buffer || !length)
-		return -EINVAL;
-	sch = to_subchannel(cdev->dev.parent);
-
-	CIO_TRACE_EVENT (4, "rddevch");
-	CIO_TRACE_EVENT (4, sch->dev.bus_id);
-
-	rdc_ccw = kzalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
-	if (!rdc_ccw)
-		return -ENOMEM;
-	rdc_ccw->cmd_code = CCW_CMD_RDC;
-	rdc_ccw->count = length;
-	rdc_ccw->flags = CCW_FLAG_SLI;
-	ret = set_normalized_cda (rdc_ccw, (*buffer));
-	if (ret != 0) {
-		kfree(rdc_ccw);
-		return ret;
-	}
-
-	spin_lock_irq(sch->lock);
-	/* Save interrupt handler. */
-	handler = cdev->handler;
-	/* Temporarily install own handler. */
-	cdev->handler = ccw_device_wake_up;
-	if (cdev->private->state != DEV_STATE_ONLINE)
-		ret = -ENODEV;
-	else if (((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) &&
-		  !(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) ||
-		 cdev->private->flags.doverify)
-		ret = -EBUSY;
-	else
-		/* 0x00D9C4C3 == ebcdic "RDC" */
-		ret = __ccw_device_retry_loop(cdev, rdc_ccw, 0x00D9C4C3, 0);
-
-	/* Restore interrupt handler. */
-	cdev->handler = handler;
-	spin_unlock_irq(sch->lock);
-
-	clear_normalized_cda (rdc_ccw);
-	kfree(rdc_ccw);
-
-	return ret;
-}
-
-/*
- *  Read Configuration data using path mask
- */
-int
-read_conf_data_lpm (struct ccw_device *cdev, void **buffer, int *length, __u8 lpm)
-{
-	void (*handler)(struct ccw_device *, unsigned long, struct irb *);
-	struct subchannel *sch;
-	struct ciw *ciw;
-	char *rcd_buf;
-	int ret;
-	struct ccw1 *rcd_ccw;
-
-	if (!cdev)
-		return -ENODEV;
-	if (!buffer || !length)
-		return -EINVAL;
-	sch = to_subchannel(cdev->dev.parent);
-
-	CIO_TRACE_EVENT (4, "rdconf");
-	CIO_TRACE_EVENT (4, sch->dev.bus_id);
-
-	/*
-	 * scan for RCD command in extended SenseID data
-	 */
-	ciw = ccw_device_get_ciw(cdev, CIW_TYPE_RCD);
-	if (!ciw || ciw->cmd == 0)
-		return -EOPNOTSUPP;
-
-	/* Adjust requested path mask to excluded varied off paths. */
-	if (lpm) {
-		lpm &= sch->opm;
-		if (lpm == 0)
-			return -EACCES;
-	}
-
-	rcd_ccw = kzalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
-	if (!rcd_ccw)
-		return -ENOMEM;
-	rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA);
- 	if (!rcd_buf) {
-		kfree(rcd_ccw);
-		return -ENOMEM;
-	}
-	rcd_ccw->cmd_code = ciw->cmd;
-	rcd_ccw->cda = (__u32) __pa (rcd_buf);
-	rcd_ccw->count = ciw->count;
-	rcd_ccw->flags = CCW_FLAG_SLI;
-
-	spin_lock_irq(sch->lock);
-	/* Save interrupt handler. */
-	handler = cdev->handler;
-	/* Temporarily install own handler. */
-	cdev->handler = ccw_device_wake_up;
-	if (cdev->private->state != DEV_STATE_ONLINE)
-		ret = -ENODEV;
-	else if (((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) &&
-		  !(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) ||
-		 cdev->private->flags.doverify)
-		ret = -EBUSY;
-	else
-		/* 0x00D9C3C4 == ebcdic "RCD" */
-		ret = __ccw_device_retry_loop(cdev, rcd_ccw, 0x00D9C3C4, lpm);
-
-	/* Restore interrupt handler. */
-	cdev->handler = handler;
-	spin_unlock_irq(sch->lock);
-
- 	/*
- 	 * on success we update the user input parms
- 	 */
- 	if (ret) {
- 		kfree (rcd_buf);
- 		*buffer = NULL;
- 		*length = 0;
- 	} else {
-		*length = ciw->count;
-		*buffer = rcd_buf;
-	}
-	kfree(rcd_ccw);
-
-	return ret;
-}
-
-/*
- *  Read Configuration data
- */
-int
-read_conf_data (struct ccw_device *cdev, void **buffer, int *length)
-{
-	return read_conf_data_lpm (cdev, buffer, length, 0);
-}
-
 /*
  * Try to break the lock on a boxed device.
  */
@@ -604,8 +539,7 @@
 	return ret;
 }
 
-void *
-ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
+void *ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
 {
 	struct subchannel *sch;
 	struct chp_id chpid;
@@ -635,12 +569,6 @@
 	return cdev->private->schid.sch_no;
 }
 
-int
-_ccw_device_get_device_number(struct ccw_device *cdev)
-{
-	return cdev->private->dev_id.devno;
-}
-
 
 MODULE_LICENSE("GPL");
 EXPORT_SYMBOL(ccw_device_set_options_mask);
@@ -655,9 +583,5 @@
 EXPORT_SYMBOL(ccw_device_start_key);
 EXPORT_SYMBOL(ccw_device_get_ciw);
 EXPORT_SYMBOL(ccw_device_get_path_mask);
-EXPORT_SYMBOL(read_conf_data);
-EXPORT_SYMBOL(read_dev_chars);
 EXPORT_SYMBOL(_ccw_device_get_subchannel_number);
-EXPORT_SYMBOL(_ccw_device_get_device_number);
 EXPORT_SYMBOL_GPL(ccw_device_get_chp_desc);
-EXPORT_SYMBOL_GPL(read_conf_data_lpm);
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index ed026a1..40a3208 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -81,6 +81,7 @@
 static atomic_t spare_indicator_usecount;
 #define QDIO_MEMPOOL_SCSSC_ELEMENTS 2
 static mempool_t *qdio_mempool_scssc;
+static struct kmem_cache *qdio_q_cache;
 
 static debug_info_t *qdio_dbf_setup;
 static debug_info_t *qdio_dbf_sbal;
@@ -194,6 +195,8 @@
 again:
 	ccq = do_eqbs(irq->sch_token, state, q_no, start, cnt);
 	rc = qdio_check_ccq(q, ccq);
+	if ((ccq == 96) && (tmp_cnt != *cnt))
+		rc = 0;
 	if (rc == 1) {
 		QDIO_DBF_TEXT5(1,trace,"eqAGAIN");
 		goto again;
@@ -739,7 +742,8 @@
 	first_not_to_check=f+qdio_min(atomic_read(&q->number_of_buffers_used),
 				      (QDIO_MAX_BUFFERS_PER_Q-1));
 
-	if ((!q->is_iqdio_q)&&(!q->hydra_gives_outbound_pcis))
+	if (((!q->is_iqdio_q) && (!q->hydra_gives_outbound_pcis)) ||
+		 (q->queue_type == QDIO_IQDIO_QFMT_ASYNCH))
 		SYNC_MEMORY;
 
 check_next:
@@ -1020,9 +1024,9 @@
 }
 
 static void
-qdio_outbound_processing(struct qdio_q *q)
+qdio_outbound_processing(unsigned long q)
 {
-	__qdio_outbound_processing(q);
+	__qdio_outbound_processing((struct qdio_q *) q);
 }
 
 /************************* INBOUND ROUTINES *******************************/
@@ -1445,9 +1449,10 @@
 }
 
 static void
-tiqdio_inbound_processing(struct qdio_q *q)
+tiqdio_inbound_processing(unsigned long q)
 {
-	__tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount));
+	__tiqdio_inbound_processing((struct qdio_q *) q,
+				    atomic_read(&spare_indicator_usecount));
 }
 
 static void
@@ -1490,9 +1495,9 @@
 }
 
 static void
-qdio_inbound_processing(struct qdio_q *q)
+qdio_inbound_processing(unsigned long q)
 {
-	__qdio_inbound_processing(q);
+	__qdio_inbound_processing((struct qdio_q *) q);
 }
 
 /************************* MAIN ROUTINES *******************************/
@@ -1617,23 +1622,21 @@
 qdio_release_irq_memory(struct qdio_irq *irq_ptr)
 {
 	int i;
+	struct qdio_q *q;
 
-	for (i=0;i<QDIO_MAX_QUEUES_PER_IRQ;i++) {
-		if (!irq_ptr->input_qs[i])
-			goto next;
-
-		kfree(irq_ptr->input_qs[i]->slib);
-		kfree(irq_ptr->input_qs[i]);
-
-next:
-		if (!irq_ptr->output_qs[i])
-			continue;
-
-		kfree(irq_ptr->output_qs[i]->slib);
-		kfree(irq_ptr->output_qs[i]);
-
+	for (i = 0; i < QDIO_MAX_QUEUES_PER_IRQ; i++) {
+		q = irq_ptr->input_qs[i];
+		if (q) {
+			free_page((unsigned long) q->slib);
+			kmem_cache_free(qdio_q_cache, q);
+		}
+		q = irq_ptr->output_qs[i];
+		if (q) {
+			free_page((unsigned long) q->slib);
+			kmem_cache_free(qdio_q_cache, q);
+		}
 	}
-	kfree(irq_ptr->qdr);
+	free_page((unsigned long) irq_ptr->qdr);
 	free_page((unsigned long) irq_ptr);
 }
 
@@ -1680,44 +1683,35 @@
 {
 	int i;
 	struct qdio_q *q;
-	int result=-ENOMEM;
 
-	for (i=0;i<no_input_qs;i++) {
-		q = kzalloc(sizeof(struct qdio_q), GFP_KERNEL);
+	for (i = 0; i < no_input_qs; i++) {
+		q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL);
+		if (!q)
+			return -ENOMEM;
+		memset(q, 0, sizeof(*q));
 
-		if (!q) {
-			QDIO_PRINT_ERR("kmalloc of q failed!\n");
-			goto out;
-		}
-
-		q->slib = kmalloc(PAGE_SIZE, GFP_KERNEL);
+		q->slib = (struct slib *) __get_free_page(GFP_KERNEL);
 		if (!q->slib) {
-			QDIO_PRINT_ERR("kmalloc of slib failed!\n");
-			goto out;
+			kmem_cache_free(qdio_q_cache, q);
+			return -ENOMEM;
 		}
-
 		irq_ptr->input_qs[i]=q;
 	}
 
-	for (i=0;i<no_output_qs;i++) {
-		q = kzalloc(sizeof(struct qdio_q), GFP_KERNEL);
+	for (i = 0; i < no_output_qs; i++) {
+		q = kmem_cache_alloc(qdio_q_cache, GFP_KERNEL);
+		if (!q)
+			return -ENOMEM;
+		memset(q, 0, sizeof(*q));
 
-		if (!q) {
-			goto out;
-		}
-
-		q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL);
+		q->slib = (struct slib *) __get_free_page(GFP_KERNEL);
 		if (!q->slib) {
-			QDIO_PRINT_ERR("kmalloc of slib failed!\n");
-			goto out;
+			kmem_cache_free(qdio_q_cache, q);
+			return -ENOMEM;
 		}
-
 		irq_ptr->output_qs[i]=q;
 	}
-
-	result=0;
-out:
-	return result;
+	return 0;
 }
 
 static void
@@ -1767,12 +1761,15 @@
 		q->handler=input_handler;
 		q->dev_st_chg_ind=irq_ptr->dev_st_chg_ind;
 
-		q->tasklet.data=(unsigned long)q;
 		/* q->is_thinint_q isn't valid at this time, but
-		 * irq_ptr->is_thinint_irq is */
-		q->tasklet.func=(void(*)(unsigned long))
-			((irq_ptr->is_thinint_irq)?&tiqdio_inbound_processing:
-			 &qdio_inbound_processing);
+		 * irq_ptr->is_thinint_irq is
+		 */
+		if (irq_ptr->is_thinint_irq)
+			tasklet_init(&q->tasklet, tiqdio_inbound_processing,
+				     (unsigned long) q);
+		else
+			tasklet_init(&q->tasklet, qdio_inbound_processing,
+				     (unsigned long) q);
 
 		/* actually this is not used for inbound queues. yet. */
 		atomic_set(&q->busy_siga_counter,0);
@@ -1843,13 +1840,10 @@
 		q->last_move_ftc=0;
 		q->handler=output_handler;
 
-		q->tasklet.data=(unsigned long)q;
-		q->tasklet.func=(void(*)(unsigned long))
-			&qdio_outbound_processing;
-		q->timer.function=(void(*)(unsigned long))
-			&qdio_outbound_processing;
-		q->timer.data = (long)q;
-		init_timer(&q->timer);
+		tasklet_init(&q->tasklet, qdio_outbound_processing,
+			     (unsigned long) q);
+		setup_timer(&q->timer, qdio_outbound_processing,
+			    (unsigned long) q);
 
 		atomic_set(&q->busy_siga_counter,0);
 		q->timing.busy_start=0;
@@ -2985,17 +2979,17 @@
 	QDIO_DBF_HEX0(0,setup,&irq_ptr,sizeof(void*));
 
 	if (!irq_ptr) {
-		QDIO_PRINT_ERR("kmalloc of irq_ptr failed!\n");
+		QDIO_PRINT_ERR("allocation of irq_ptr failed!\n");
 		return -ENOMEM;
 	}
 
 	init_MUTEX(&irq_ptr->setting_up_sema);
 
 	/* QDR must be in DMA area since CCW data address is only 32 bit */
-	irq_ptr->qdr=kmalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA);
+	irq_ptr->qdr = (struct qdr *) __get_free_page(GFP_KERNEL | GFP_DMA);
   	if (!(irq_ptr->qdr)) {
    		free_page((unsigned long) irq_ptr);
-    		QDIO_PRINT_ERR("kmalloc of irq_ptr->qdr failed!\n");
+		QDIO_PRINT_ERR("allocation of irq_ptr->qdr failed!\n");
 		return -ENOMEM;
        	}
 	QDIO_DBF_TEXT0(0,setup,"qdr:");
@@ -3004,6 +2998,7 @@
 	if (qdio_alloc_qs(irq_ptr,
        			  init_data->no_input_qs,
 			  init_data->no_output_qs)) {
+		QDIO_PRINT_ERR("queue allocation failed!\n");
 		qdio_release_irq_memory(irq_ptr);
 		return -ENOMEM;
 	}
@@ -3732,7 +3727,7 @@
 #endif /* CONFIG_64BIT */
 		}
 	} else {
-		QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n");
+		QDIO_PRINT_ERR("QDIO performance_stats: write 0 or 1 to this file!\n");
 		return -EINVAL;
 	}
 	return count;
@@ -3895,9 +3890,19 @@
 	if (res)
 		return res;
 
+	qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q),
+					 256, 0, NULL);
+	if (!qdio_q_cache) {
+		qdio_release_qdio_memory();
+		return -ENOMEM;
+	}
+
 	res = qdio_register_dbf_views();
-	if (res)
+	if (res) {
+		kmem_cache_destroy(qdio_q_cache);
+		qdio_release_qdio_memory();
 		return res;
+	}
 
 	QDIO_DBF_TEXT0(0,setup,"initQDIO");
 	res = bus_create_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
@@ -3929,6 +3934,7 @@
 	qdio_release_qdio_memory();
 	qdio_unregister_dbf_views();
 	mempool_destroy(qdio_mempool_scssc);
+	kmem_cache_destroy(qdio_q_cache);
 	bus_remove_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
   	printk("qdio: %s: module removed\n",version);
 }
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 90bd220..67aaff3 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -458,28 +458,22 @@
  * uevent function for AP devices. It sets up a single environment
  * variable DEV_TYPE which contains the hardware device type.
  */
-static int ap_uevent (struct device *dev, char **envp, int num_envp,
-		       char *buffer, int buffer_size)
+static int ap_uevent (struct device *dev, struct kobj_uevent_env *env)
 {
 	struct ap_device *ap_dev = to_ap_dev(dev);
-	int retval = 0, length = 0, i = 0;
+	int retval = 0;
 
 	if (!ap_dev)
 		return -ENODEV;
 
 	/* Set up DEV_TYPE environment variable. */
-	retval = add_uevent_var(envp, num_envp, &i,
-				buffer, buffer_size, &length,
-				"DEV_TYPE=%04X", ap_dev->device_type);
+	retval = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type);
 	if (retval)
 		return retval;
 
 	/* Add MODALIAS= */
-	retval = add_uevent_var(envp, num_envp, &i,
-				buffer, buffer_size, &length,
-				"MODALIAS=ap:t%02X", ap_dev->device_type);
+	retval = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type);
 
-	envp[i] = NULL;
 	return retval;
 }
 
@@ -1231,8 +1225,9 @@
 {
 	int i;
 
-	for (i = 0; i < AP_DEVICES; i++)
-		ap_reset_queue(AP_MKQID(i, ap_domain_index));
+	if (ap_domain_index != -1)
+		for (i = 0; i < AP_DEVICES; i++)
+			ap_reset_queue(AP_MKQID(i, ap_domain_index));
 }
 
 static void ap_reset_all(void)
diff --git a/drivers/s390/crypto/zcrypt_mono.c b/drivers/s390/crypto/zcrypt_mono.c
index 2a9349a..44253fd 100644
--- a/drivers/s390/crypto/zcrypt_mono.c
+++ b/drivers/s390/crypto/zcrypt_mono.c
@@ -45,7 +45,7 @@
 /**
  * The module initialization code.
  */
-int __init zcrypt_init(void)
+static int __init zcrypt_init(void)
 {
 	int rc;
 
@@ -86,7 +86,7 @@
 /**
  * The module termination code.
  */
-void __exit zcrypt_exit(void)
+static void __exit zcrypt_exit(void)
 {
 	zcrypt_cex2a_exit();
 	zcrypt_pcixcc_exit();
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index 6494878..70b9ddc 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -277,7 +277,7 @@
 	};
 	struct {
 		struct type6_hdr hdr;
-		struct ica_CPRBX cprbx;
+		struct CPRBX cprbx;
 	} __attribute__((packed)) *msg = ap_msg->message;
 
 	int rcblen = CEIL4(xcRB->request_control_blk_length);
@@ -432,14 +432,17 @@
 		}
 		if (service_rc == 8 && service_rs == 770) {
 			PDEBUG("Invalid key length on PCIXCC/CEX2C\n");
-			zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
-			return -EAGAIN;
+			return -EINVAL;
 		}
 		if (service_rc == 8 && service_rs == 783) {
 			PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n");
 			zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
 			return -EAGAIN;
 		}
+		if (service_rc == 12 && service_rs == 769) {
+			PDEBUG("Invalid key on PCIXCC/CEX2C\n");
+			return -EINVAL;
+		}
 		PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n",
 		       service_rc, service_rs);
 		zdev->online = 0;
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_pcixcc.h
index a78ff30..8cb7d7a 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.h
+++ b/drivers/s390/crypto/zcrypt_pcixcc.h
@@ -28,51 +28,6 @@
 #ifndef _ZCRYPT_PCIXCC_H_
 #define _ZCRYPT_PCIXCC_H_
 
-/**
- * CPRBX
- *	  Note that all shorts and ints are big-endian.
- *	  All pointer fields are 16 bytes long, and mean nothing.
- *
- *	  A request CPRB is followed by a request_parameter_block.
- *
- *	  The request (or reply) parameter block is organized thus:
- *	    function code
- *	    VUD block
- *	    key block
- */
-struct CPRBX {
-	unsigned short cprb_len;	/* CPRB length	      220	 */
-	unsigned char  cprb_ver_id;	/* CPRB version id.   0x02	 */
-	unsigned char  pad_000[3];	/* Alignment pad bytes		 */
-	unsigned char  func_id[2];	/* function id	      0x5432	 */
-	unsigned char  cprb_flags[4];	/* Flags			 */
-	unsigned int   req_parml;	/* request parameter buffer len	 */
-	unsigned int   req_datal;	/* request data buffer		 */
-	unsigned int   rpl_msgbl;	/* reply  message block length	 */
-	unsigned int   rpld_parml;	/* replied parameter block len	 */
-	unsigned int   rpl_datal;	/* reply data block len		 */
-	unsigned int   rpld_datal;	/* replied data block len	 */
-	unsigned int   req_extbl;	/* request extension block len	 */
-	unsigned char  pad_001[4];	/* reserved			 */
-	unsigned int   rpld_extbl;	/* replied extension block len	 */
-	unsigned char  req_parmb[16];	/* request parm block 'address'	 */
-	unsigned char  req_datab[16];	/* request data block 'address'	 */
-	unsigned char  rpl_parmb[16];	/* reply parm block 'address'	 */
-	unsigned char  rpl_datab[16];	/* reply data block 'address'	 */
-	unsigned char  req_extb[16];	/* request extension block 'addr'*/
-	unsigned char  rpl_extb[16];	/* reply extension block 'addres'*/
-	unsigned short ccp_rtcode;	/* server return code		 */
-	unsigned short ccp_rscode;	/* server reason code		 */
-	unsigned int   mac_data_len;	/* Mac Data Length		 */
-	unsigned char  logon_id[8];	/* Logon Identifier		 */
-	unsigned char  mac_value[8];	/* Mac Value			 */
-	unsigned char  mac_content_flgs;/* Mac content flag byte	 */
-	unsigned char  pad_002;		/* Alignment			 */
-	unsigned short domain;		/* Domain			 */
-	unsigned char  pad_003[12];	/* Domain masks			 */
-	unsigned char  pad_004[36];	/* reserved			 */
-} __attribute__((packed));
-
 int zcrypt_pcixcc_init(void);
 void zcrypt_pcixcc_exit(void);
 
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 348bb7b..399695f 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -317,8 +317,8 @@
 		CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM);
 		return -ENOMEM;
 	}
-	privptr->p_mtc_envelope= kmalloc( MAX_ENVELOPE_SIZE, GFP_KERNEL);
-	privptr->p_env = kmalloc(sizeof(struct claw_env), GFP_KERNEL);
+	privptr->p_mtc_envelope= kzalloc( MAX_ENVELOPE_SIZE, GFP_KERNEL);
+	privptr->p_env = kzalloc(sizeof(struct claw_env), GFP_KERNEL);
         if ((privptr->p_mtc_envelope==NULL) || (privptr->p_env==NULL)) {
                 probe_error(cgdev);
 		put_device(&cgdev->dev);
@@ -327,8 +327,6 @@
 		CLAW_DBF_TEXT_(2,setup,"probex%d",-ENOMEM);
                 return -ENOMEM;
         }
-	memset(privptr->p_mtc_envelope, 0x00, MAX_ENVELOPE_SIZE);
-	memset(privptr->p_env, 0x00, sizeof(struct claw_env));
 	memcpy(privptr->p_env->adapter_name,WS_NAME_NOT_DEF,8);
 	memcpy(privptr->p_env->host_name,WS_NAME_NOT_DEF,8);
 	memcpy(privptr->p_env->api_type,WS_NAME_NOT_DEF,8);
@@ -3893,7 +3891,6 @@
 	dev->type = ARPHRD_SLIP;
 	dev->tx_queue_len = 1300;
 	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
-	SET_MODULE_OWNER(dev);
 #ifdef FUNCTRACE
         printk(KERN_INFO "%s:%s Exit\n",dev->name,__FUNCTION__);
 #endif
@@ -3924,7 +3921,7 @@
 	snprintf(p_ch->id, CLAW_ID_SIZE, "cl-%s", cdev->dev.bus_id);
 	ccw_device_get_id(cdev, &dev_id);
 	p_ch->devno = dev_id.devno;
-	if ((p_ch->irb = kmalloc(sizeof (struct irb),GFP_KERNEL)) == NULL) {
+	if ((p_ch->irb = kzalloc(sizeof (struct irb),GFP_KERNEL)) == NULL) {
 		printk(KERN_WARNING "%s Out of memory in %s for irb\n",
 			p_ch->id,__FUNCTION__);
 #ifdef FUNCTRACE
@@ -3933,7 +3930,6 @@
 #endif
 		return -ENOMEM;
 	}
-	memset(p_ch->irb, 0, sizeof (struct irb));
 #ifdef FUNCTRACE
         	printk(KERN_INFO "%s:%s Exit on line %d\n",
 			cdev->dev.bus_id,__FUNCTION__,__LINE__);
diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
index b20fd06..4499372 100644
--- a/drivers/s390/net/ctcmain.c
+++ b/drivers/s390/net/ctcmain.c
@@ -674,7 +674,7 @@
 	int first = 1;
 	int i;
 	unsigned long duration;
-	struct timespec done_stamp = xtime;
+	struct timespec done_stamp = current_kernel_time();
 
 	DBF_TEXT(trace, 4, __FUNCTION__);
 
@@ -730,7 +730,7 @@
 		spin_unlock(&ch->collect_lock);
 		ch->ccw[1].count = ch->trans_skb->len;
 		fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
-		ch->prof.send_stamp = xtime;
+		ch->prof.send_stamp = current_kernel_time();
 		rc = ccw_device_start(ch->cdev, &ch->ccw[0],
 				      (unsigned long) ch, 0xff, 0);
 		ch->prof.doios_multi++;
@@ -2281,7 +2281,7 @@
 		fsm_newstate(ch->fsm, CH_STATE_TX);
 		fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
 		spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags);
-		ch->prof.send_stamp = xtime;
+		ch->prof.send_stamp = current_kernel_time();
 		rc = ccw_device_start(ch->cdev, &ch->ccw[ccw_idx],
 				      (unsigned long) ch, 0xff, 0);
 		spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags);
@@ -2823,7 +2823,6 @@
 	dev->type = ARPHRD_SLIP;
 	dev->tx_queue_len = 100;
 	dev->flags = IFF_POINTOPOINT | IFF_NOARP;
-	SET_MODULE_OWNER(dev);
 	return dev;
 }
 
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 08a994f..0fd663b 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -1400,11 +1400,14 @@
 		PRINT_WARN("check on device %s, dstat=0x%X, cstat=0x%X \n",
 			    cdev->dev.bus_id, dstat, cstat);
 		if (rc) {
-			lcs_schedule_recovery(card);
-			wake_up(&card->wait_q);
-			return;
+			channel->state = LCS_CH_STATE_ERROR;
 		}
 	}
+	if (channel->state == LCS_CH_STATE_ERROR) {
+		lcs_schedule_recovery(card);
+		wake_up(&card->wait_q);
+		return;
+	}
 	/* How far in the ccw chain have we processed? */
 	if ((channel->state != LCS_CH_STATE_INIT) &&
 	    (irb->scsw.fctl & SCSW_FCTL_START_FUNC)) {
@@ -1708,6 +1711,8 @@
 
 	if (card->read.state != LCS_CH_STATE_STOPPED &&
 	    card->write.state != LCS_CH_STATE_STOPPED &&
+	    card->read.state != LCS_CH_STATE_ERROR &&
+	    card->write.state != LCS_CH_STATE_ERROR &&
 	    card->state == DEV_STATE_UP) {
 		lcs_clear_multicast_list(card);
 		rc = lcs_send_stoplan(card,LCS_INITIATOR_TCPIP);
@@ -2145,7 +2150,6 @@
 	card->dev->stop = lcs_stop_device;
 	card->dev->hard_start_xmit = lcs_start_xmit;
 	card->dev->get_stats = lcs_getstats;
-	SET_MODULE_OWNER(dev);
 	memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH);
 #ifdef CONFIG_IP_MULTICAST
 	if (!lcs_check_multicast_support(card))
diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h
index 0e1e4a0..8976fb0 100644
--- a/drivers/s390/net/lcs.h
+++ b/drivers/s390/net/lcs.h
@@ -138,6 +138,7 @@
 	LCS_CH_STATE_RUNNING,
 	LCS_CH_STATE_SUSPENDED,
 	LCS_CH_STATE_CLEARED,
+	LCS_CH_STATE_ERROR,
 };
 
 /**
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 3d28e1a..4d18d64 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -753,7 +753,7 @@
 
 	header.next = 0;
 	memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN);
-	conn->prof.send_stamp = xtime;
+	conn->prof.send_stamp = current_kernel_time();
 	txmsg.class = 0;
 	txmsg.tag = 0;
 	rc = iucv_message_send(conn->path, &txmsg, 0, 0,
@@ -1185,7 +1185,7 @@
 		memcpy(skb_put(nskb, NETIUCV_HDRLEN), &header,  NETIUCV_HDRLEN);
 
 		fsm_newstate(conn->fsm, CONN_STATE_TX);
-		conn->prof.send_stamp = xtime;
+		conn->prof.send_stamp = current_kernel_time();
 
 		msg.tag = 1;
 		msg.class = 0;
@@ -1904,7 +1904,6 @@
 	dev->type                = ARPHRD_SLIP;
 	dev->tx_queue_len        = NETIUCV_QUEUELEN_DEFAULT;
 	dev->flags	         = IFF_POINTOPOINT | IFF_NOARP;
-	SET_MODULE_OWNER(dev);
 }
 
 /**
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index ec18bae..8c6b72d 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -833,8 +833,7 @@
 	struct qeth_qdio_info qdio;
 	struct qeth_perf_stats perf_stats;
 	int use_hard_stop;
-	int (*orig_hard_header)(struct sk_buff *,struct net_device *,
-				unsigned short,void *,void *,unsigned);
+	const struct header_ops *orig_header_ops;
 	struct qeth_osn_info osn_info;
 	atomic_t force_alloc_skb;
 };
@@ -1178,9 +1177,9 @@
 		      char *buf)
 {
 	if (proto == QETH_PROT_IPV4)
-		return qeth_ipaddr4_to_string(addr, buf);
+		qeth_ipaddr4_to_string(addr, buf);
 	else if (proto == QETH_PROT_IPV6)
-		return qeth_ipaddr6_to_string(addr, buf);
+		qeth_ipaddr6_to_string(addr, buf);
 }
 
 static inline int
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
index 70108fb..e3c268c 100644
--- a/drivers/s390/net/qeth_eddp.c
+++ b/drivers/s390/net/qeth_eddp.c
@@ -159,13 +159,15 @@
 		buffer = buf->buffer;
 		/* fill one skb into buffer */
 		for (i = 0; i < ctx->elements_per_skb; ++i){
-			buffer->element[buf->next_element_to_fill].addr =
-				ctx->elements[element].addr;
-			buffer->element[buf->next_element_to_fill].length =
-				ctx->elements[element].length;
-			buffer->element[buf->next_element_to_fill].flags =
-				ctx->elements[element].flags;
-			buf->next_element_to_fill++;
+			if (ctx->elements[element].length != 0) {
+				buffer->element[buf->next_element_to_fill].
+				addr = ctx->elements[element].addr;
+				buffer->element[buf->next_element_to_fill].
+				length = ctx->elements[element].length;
+				buffer->element[buf->next_element_to_fill].
+				flags = ctx->elements[element].flags;
+				buf->next_element_to_fill++;
+			}
 			element++;
 			elements--;
 		}
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 57f6943..a2d08c9 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -160,6 +160,9 @@
 static void
 qeth_setadp_promisc_mode(struct qeth_card *);
 
+static int
+qeth_hard_header_parse(const struct sk_buff *skb, unsigned char *haddr);
+
 static void
 qeth_notify_processes(void)
 {
@@ -561,7 +564,7 @@
 }
 
 static int
-qeth_wait_for_threads(struct qeth_card *card, unsigned long threads);
+qeth_threads_running(struct qeth_card *card, unsigned long threads);
 
 
 static void
@@ -576,8 +579,7 @@
 	if (!card)
 		return;
 
-	if (qeth_wait_for_threads(card, 0xffffffff))
-		return;
+	wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
 
 	if (cgdev->state == CCWGROUP_ONLINE){
 		card->use_hard_stop = 1;
@@ -821,14 +823,15 @@
 again:
 	list_for_each_entry_safe(addr, tmp, &card->ip_list, entry) {
 		if (addr->is_multicast) {
+			list_del(&addr->entry);
 			spin_unlock_irqrestore(&card->ip_lock, *flags);
 			rc = qeth_deregister_addr_entry(card, addr);
 			spin_lock_irqsave(&card->ip_lock, *flags);
 			if (!rc) {
-				list_del(&addr->entry);
 				kfree(addr);
 				goto again;
-			}
+			} else
+				list_add(&addr->entry, &card->ip_list);
 		}
 	}
 }
@@ -1542,16 +1545,21 @@
 	card = CARD_FROM_CDEV(channel->ccwdev);
 
 	if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) {
-		PRINT_ERR("IDX_ACTIVATE on write channel device %s: negative "
-			  "reply\n", CARD_WDEV_ID(card));
+		if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19)
+			PRINT_ERR("IDX_ACTIVATE on write channel device %s: "
+				"adapter exclusively used by another host\n",
+				CARD_WDEV_ID(card));
+		else
+			PRINT_ERR("IDX_ACTIVATE on write channel device %s: "
+				"negative reply\n", CARD_WDEV_ID(card));
 		goto out;
 	}
 	memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2);
 	if ((temp & ~0x0100) != qeth_peer_func_level(card->info.func_level)) {
 		PRINT_WARN("IDX_ACTIVATE on write channel device %s: "
-			   "function level mismatch "
-			   "(sent: 0x%x, received: 0x%x)\n",
-			   CARD_WDEV_ID(card), card->info.func_level, temp);
+			"function level mismatch "
+			"(sent: 0x%x, received: 0x%x)\n",
+			CARD_WDEV_ID(card), card->info.func_level, temp);
 		goto out;
 	}
 	channel->state = CH_STATE_UP;
@@ -1597,8 +1605,13 @@
 			goto out;
 	}
 	if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) {
-		PRINT_ERR("IDX_ACTIVATE on read channel device %s: negative "
-			  "reply\n", CARD_RDEV_ID(card));
+		if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19)
+			PRINT_ERR("IDX_ACTIVATE on read channel device %s: "
+				"adapter exclusively used by another host\n",
+				CARD_RDEV_ID(card));
+		else
+			PRINT_ERR("IDX_ACTIVATE on read channel device %s: "
+				"negative reply\n", CARD_RDEV_ID(card));
 		goto out;
 	}
 
@@ -1613,8 +1626,8 @@
 	memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2);
 	if (temp != qeth_peer_func_level(card->info.func_level)) {
 		PRINT_WARN("IDX_ACTIVATE on read channel device %s: function "
-			   "level mismatch (sent: 0x%x, received: 0x%x)\n",
-			   CARD_RDEV_ID(card), card->info.func_level, temp);
+			"level mismatch (sent: 0x%x, received: 0x%x)\n",
+			CARD_RDEV_ID(card), card->info.func_level, temp);
 		goto out;
 	}
 	memcpy(&card->token.issuer_rm_r,
@@ -2496,7 +2509,7 @@
 	struct iphdr *ip_hdr;
 
 	QETH_DBF_TEXT(trace,5,"skbfktr");
-	skb_set_mac_header(skb, -QETH_FAKE_LL_LEN_TR);
+	skb_set_mac_header(skb, (int)-QETH_FAKE_LL_LEN_TR);
 	/* this is a fake ethernet header */
 	fake_hdr = tr_hdr(skb);
 
@@ -2689,10 +2702,15 @@
 			qeth_layer2_rebuild_skb(card, skb, hdr);
 		else if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3)
 			vlan_tag = qeth_rebuild_skb(card, skb, hdr);
-		else { /*in case of OSN*/
+		else if (hdr->hdr.osn.id == QETH_HEADER_TYPE_OSN) {
 			skb_push(skb, sizeof(struct qeth_hdr));
 			skb_copy_to_linear_data(skb, hdr,
 						sizeof(struct qeth_hdr));
+		} else { /* unknown header type */
+			dev_kfree_skb_any(skb);
+			QETH_DBF_TEXT(trace, 3, "inbunkno");
+			QETH_DBF_HEX(control, 3, hdr, QETH_DBF_CONTROL_LEN);
+			continue;
 		}
 		/* is device UP ? */
 		if (!(card->dev->flags & IFF_UP)){
@@ -2804,13 +2822,16 @@
 		if (newcount < count) {
 			/* we are in memory shortage so we switch back to
 			   traditional skb allocation and drop packages */
-			if (atomic_cmpxchg(&card->force_alloc_skb, 0, 1))
-				printk(KERN_WARNING
-					"qeth: switch to alloc skb\n");
+			if (!atomic_read(&card->force_alloc_skb) &&
+			    net_ratelimit())
+				PRINT_WARN("Switch to alloc skb\n");
+			atomic_set(&card->force_alloc_skb, 3);
 			count = newcount;
 		} else {
-			if (atomic_cmpxchg(&card->force_alloc_skb, 1, 0))
-				printk(KERN_WARNING "qeth: switch to sg\n");
+			if ((atomic_read(&card->force_alloc_skb) == 1) &&
+			    net_ratelimit())
+				PRINT_WARN("Switch to sg\n");
+			atomic_add_unless(&card->force_alloc_skb, -1, 0);
 		}
 
 		/*
@@ -3354,10 +3375,12 @@
 	while (i > 0)
 		kfree(card->qdio.out_qs[--i]);
 	kfree(card->qdio.out_qs);
+	card->qdio.out_qs = NULL;
 out_freepool:
 	qeth_free_buffer_pool(card);
 out_freeinq:
 	kfree(card->qdio.in_q);
+	card->qdio.in_q = NULL;
 out_nomem:
 	atomic_set(&card->qdio.state, QETH_QDIO_UNINITIALIZED);
 	return -ENOMEM;
@@ -3373,16 +3396,20 @@
 		QETH_QDIO_UNINITIALIZED)
 		return;
 	kfree(card->qdio.in_q);
+	card->qdio.in_q = NULL;
 	/* inbound buffer pool */
 	qeth_free_buffer_pool(card);
 	/* free outbound qdio_qs */
-	for (i = 0; i < card->qdio.no_out_queues; ++i){
-		for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j)
-			qeth_clear_output_buffer(card->qdio.out_qs[i],
-					&card->qdio.out_qs[i]->bufs[j]);
-		kfree(card->qdio.out_qs[i]);
+	if (card->qdio.out_qs) {
+		for (i = 0; i < card->qdio.no_out_queues; ++i) {
+			for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j)
+				qeth_clear_output_buffer(card->qdio.out_qs[i],
+						&card->qdio.out_qs[i]->bufs[j]);
+			kfree(card->qdio.out_qs[i]);
+		}
+		kfree(card->qdio.out_qs);
+		card->qdio.out_qs = NULL;
 	}
-	kfree(card->qdio.out_qs);
 }
 
 static void
@@ -3393,7 +3420,7 @@
 	QETH_DBF_TEXT(trace, 2, "clearqdbf");
 	/* clear outbound buffers to free skbs */
 	for (i = 0; i < card->qdio.no_out_queues; ++i)
-		if (card->qdio.out_qs[i]){
+		if (card->qdio.out_qs && card->qdio.out_qs[i]) {
 			for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j)
 				qeth_clear_output_buffer(card->qdio.out_qs[i],
 						&card->qdio.out_qs[i]->bufs[j]);
@@ -3769,8 +3796,8 @@
 /*hard_header fake function; used in case fake_ll is set */
 static int
 qeth_fake_header(struct sk_buff *skb, struct net_device *dev,
-		     unsigned short type, void *daddr, void *saddr,
-		     unsigned len)
+		 unsigned short type, const void *daddr, const void *saddr,
+		 unsigned len)
 {
 	if(dev->type == ARPHRD_IEEE802_TR){
 		struct trh_hdr *hdr;
@@ -3793,6 +3820,11 @@
 	}
 }
 
+static const struct header_ops qeth_fake_ops = {
+	.create	= qeth_fake_header,
+	.parse  = qeth_hard_header_parse,
+};
+
 static int
 qeth_send_packet(struct qeth_card *, struct sk_buff *);
 
@@ -4482,7 +4514,8 @@
 			/* check if we have enough elements (including following
 			 * free buffers) to handle eddp context */
 			if (qeth_eddp_check_buffers_for_context(queue,ctx) < 0){
-				printk("eddp tx_dropped 1\n");
+				if (net_ratelimit())
+					PRINT_WARN("eddp tx_dropped 1\n");
 				rc = -EBUSY;
 				goto out;
 			}
@@ -4553,6 +4586,53 @@
         return elements_needed;
 }
 
+static void qeth_tx_csum(struct sk_buff *skb)
+{
+	int tlen;
+
+	if (skb->protocol == htons(ETH_P_IP)) {
+		tlen = ntohs(ip_hdr(skb)->tot_len) - (ip_hdr(skb)->ihl << 2);
+		switch (ip_hdr(skb)->protocol) {
+		case IPPROTO_TCP:
+			tcp_hdr(skb)->check = 0;
+			tcp_hdr(skb)->check = csum_tcpudp_magic(
+				ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
+				tlen, ip_hdr(skb)->protocol,
+				skb_checksum(skb, skb_transport_offset(skb),
+					tlen, 0));
+			break;
+		case IPPROTO_UDP:
+			udp_hdr(skb)->check = 0;
+			udp_hdr(skb)->check = csum_tcpudp_magic(
+				ip_hdr(skb)->saddr, ip_hdr(skb)->daddr,
+				tlen, ip_hdr(skb)->protocol,
+				skb_checksum(skb, skb_transport_offset(skb),
+					tlen, 0));
+			break;
+		}
+	} else if (skb->protocol == htons(ETH_P_IPV6)) {
+		switch (ipv6_hdr(skb)->nexthdr) {
+		case IPPROTO_TCP:
+			tcp_hdr(skb)->check = 0;
+			tcp_hdr(skb)->check = csum_ipv6_magic(
+				&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
+				ipv6_hdr(skb)->payload_len,
+				ipv6_hdr(skb)->nexthdr,
+				skb_checksum(skb, skb_transport_offset(skb),
+					ipv6_hdr(skb)->payload_len, 0));
+			break;
+		case IPPROTO_UDP:
+			udp_hdr(skb)->check = 0;
+			udp_hdr(skb)->check = csum_ipv6_magic(
+				&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
+				ipv6_hdr(skb)->payload_len,
+				ipv6_hdr(skb)->nexthdr,
+				skb_checksum(skb, skb_transport_offset(skb),
+					ipv6_hdr(skb)->payload_len, 0));
+			break;
+		}
+	}
+}
 
 static int
 qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
@@ -4584,7 +4664,7 @@
 		[qeth_get_priority_queue(card, skb, ipv, cast_type)];
 	if (!card->options.layer2) {
 		ipv = qeth_get_ip_version(skb);
-		if ((card->dev->hard_header == qeth_fake_header) && ipv) {
+		if ((card->dev->header_ops == &qeth_fake_ops) && ipv) {
 			new_skb = qeth_pskb_unshare(skb, GFP_ATOMIC);
 			if (!new_skb)
 				return -ENOMEM;
@@ -4638,12 +4718,22 @@
 		elements_needed += elems;
 	}
 
+	if ((large_send == QETH_LARGE_SEND_NO) &&
+	    (skb->ip_summed == CHECKSUM_PARTIAL))
+		qeth_tx_csum(new_skb);
+
 	if (card->info.type != QETH_CARD_TYPE_IQD)
 		rc = qeth_do_send_packet(card, queue, new_skb, hdr,
 					 elements_needed, ctx);
-	else
+	else {
+		if ((!card->options.layer2) &&
+		    (ipv == 0)) {
+			__qeth_free_new_skb(skb, new_skb);
+			return -EPERM;
+		}
 		rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
 					      elements_needed, ctx);
+	}
 	if (!rc) {
 		card->stats.tx_packets++;
 		card->stats.tx_bytes += tx_bytes;
@@ -6385,20 +6475,18 @@
 static u32
 qeth_ethtool_get_tx_csum(struct net_device *dev)
 {
-	/* We may need to say that we support tx csum offload if
-	 * we do EDDP or TSO. There are discussions going on to
-	 * enforce rules in the stack and in ethtool that make
-	 * SG and TSO depend on HW_CSUM. At the moment there are
-	 * no such rules....
-	 * If we say yes here, we have to checksum outbound packets
-	 * any time. */
-	return 0;
+	return (dev->features & NETIF_F_HW_CSUM) != 0;
 }
 
 static int
 qeth_ethtool_set_tx_csum(struct net_device *dev, u32 data)
 {
-	return -EINVAL;
+	if (data)
+		dev->features |= NETIF_F_HW_CSUM;
+	else
+		dev->features &= ~NETIF_F_HW_CSUM;
+
+	return 0;
 }
 
 static u32
@@ -6488,12 +6576,16 @@
 };
 
 static int
-qeth_hard_header_parse(struct sk_buff *skb, unsigned char *haddr)
+qeth_hard_header_parse(const struct sk_buff *skb, unsigned char *haddr)
 {
-	struct qeth_card *card;
-	struct ethhdr *eth;
+	const struct qeth_card *card;
+	const struct ethhdr *eth;
+	struct net_device *dev = skb->dev;
 
-	card = qeth_get_card_from_dev(skb->dev);
+	if (dev->type != ARPHRD_IEEE802_TR)
+		return 0;
+
+	card = qeth_get_card_from_dev(dev);
 	if (card->options.layer2)
 		goto haveheader;
 #ifdef CONFIG_QETH_IPV6
@@ -6523,6 +6615,10 @@
 	return ETH_ALEN;
 }
 
+static const struct header_ops qeth_null_ops = {
+	.parse = qeth_hard_header_parse,
+};
+
 static int
 qeth_netdev_init(struct net_device *dev)
 {
@@ -6547,12 +6643,8 @@
 	dev->vlan_rx_kill_vid = qeth_vlan_rx_kill_vid;
 	dev->vlan_rx_add_vid = qeth_vlan_rx_add_vid;
 #endif
-	if (qeth_get_netdev_flags(card) & IFF_NOARP) {
-		dev->rebuild_header = NULL;
-		dev->hard_header = NULL;
-		dev->header_cache_update = NULL;
-		dev->hard_header_cache = NULL;
-	}
+	dev->header_ops = &qeth_null_ops;
+
 #ifdef CONFIG_QETH_IPV6
 	/*IPv6 address autoconfiguration stuff*/
 	if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD))
@@ -6560,11 +6652,8 @@
 #endif
 	if (card->options.fake_ll &&
 		(qeth_get_netdev_flags(card) & IFF_NOARP))
-			dev->hard_header = qeth_fake_header;
-	if (dev->type == ARPHRD_IEEE802_TR)
-		dev->hard_header_parse = NULL;
-	else
-		dev->hard_header_parse = qeth_hard_header_parse;
+			dev->header_ops = &qeth_fake_ops;
+
 	dev->set_mac_address = qeth_layer2_set_mac_address;
 	dev->flags |= qeth_get_netdev_flags(card);
 	if ((card->options.fake_broadcast) ||
@@ -6576,7 +6665,6 @@
 	dev->mtu = card->info.initial_mtu;
 	if (card->info.type != QETH_CARD_TYPE_OSN)
 		SET_ETHTOOL_OPS(dev, &qeth_ethtool_ops);
-	SET_MODULE_OWNER(dev);
 	return 0;
 }
 
@@ -6668,10 +6756,10 @@
 	}
 	/*network device will be recovered*/
 	if (card->dev) {
-		card->dev->hard_header = card->orig_hard_header;
+		card->dev->header_ops = card->orig_header_ops;
 		if (card->options.fake_ll &&
 		    (qeth_get_netdev_flags(card) & IFF_NOARP))
-			card->dev->hard_header = qeth_fake_header;
+			card->dev->header_ops = &qeth_fake_ops;
 		return 0;
 	}
 	/* at first set_online allocate netdev */
@@ -6685,7 +6773,7 @@
 		goto out;
 	}
 	card->dev->priv = card;
-	card->orig_hard_header = card->dev->hard_header;
+	card->orig_header_ops = card->dev->header_ops;
 	card->dev->type = qeth_get_arphdr_type(card->info.type,
 					       card->info.link_type);
 	card->dev->init = qeth_netdev_init;
@@ -7412,7 +7500,8 @@
 	}
 	if (rc && (card->options.large_send == QETH_LARGE_SEND_TSO)){
 		card->options.large_send = QETH_LARGE_SEND_NO;
-		card->dev->features &= ~ (NETIF_F_TSO | NETIF_F_SG);
+		card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
+						NETIF_F_HW_CSUM);
 	}
 	return rc;
 }
@@ -7552,22 +7641,26 @@
 	card->options.large_send = type;
 	switch (card->options.large_send) {
 	case QETH_LARGE_SEND_EDDP:
-		card->dev->features |= NETIF_F_TSO | NETIF_F_SG;
+		card->dev->features |= NETIF_F_TSO | NETIF_F_SG |
+					NETIF_F_HW_CSUM;
 		break;
 	case QETH_LARGE_SEND_TSO:
 		if (qeth_is_supported(card, IPA_OUTBOUND_TSO)){
-			card->dev->features |= NETIF_F_TSO | NETIF_F_SG;
+			card->dev->features |= NETIF_F_TSO | NETIF_F_SG |
+						NETIF_F_HW_CSUM;
 		} else {
 			PRINT_WARN("TSO not supported on %s. "
 				   "large_send set to 'no'.\n",
 				   card->dev->name);
-			card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG);
+			card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
+						NETIF_F_HW_CSUM);
 			card->options.large_send = QETH_LARGE_SEND_NO;
 			rc = -EOPNOTSUPP;
 		}
 		break;
 	default: /* includes QETH_LARGE_SEND_NO */
-		card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG);
+		card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
+					NETIF_F_HW_CSUM);
 		break;
 	}
 	if (card->state == CARD_STATE_UP)
@@ -8231,7 +8324,7 @@
 	if (card == NULL)
 		goto out;
 	if((card->options.layer2) ||
-	   (card->dev->hard_header == qeth_fake_header))
+	   (card->dev->header_ops == &qeth_fake_ops))
 		goto out;
 
 	rcu_read_lock();
diff --git a/drivers/s390/net/qeth_mpc.h b/drivers/s390/net/qeth_mpc.h
index 1d8083c..6de2da5 100644
--- a/drivers/s390/net/qeth_mpc.h
+++ b/drivers/s390/net/qeth_mpc.h
@@ -565,6 +565,7 @@
 #define QETH_IDX_ACT_QDIO_DEV_REALADDR(buffer) (buffer+0x20)
 #define QETH_IS_IDX_ACT_POS_REPLY(buffer) (((buffer)[0x08]&3)==2)
 #define QETH_IDX_REPLY_LEVEL(buffer) (buffer+0x12)
+#define QETH_IDX_ACT_CAUSE_CODE(buffer) (buffer)[0x09]
 
 #define PDU_ENCAPSULATION(buffer) \
 	(buffer + *(buffer + (*(buffer+0x0b)) + \
diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c
index bb0287a..2cc3f3a 100644
--- a/drivers/s390/net/qeth_sys.c
+++ b/drivers/s390/net/qeth_sys.c
@@ -1760,10 +1760,10 @@
 {
 	struct qeth_card *card = dev->driver_data;
 
-	if (card->info.type == QETH_CARD_TYPE_OSN)
-		return sysfs_remove_group(&dev->kobj,
-					  &qeth_osn_device_attr_group);
-
+	if (card->info.type == QETH_CARD_TYPE_OSN) {
+		sysfs_remove_group(&dev->kobj, &qeth_osn_device_attr_group);
+		return;
+	}
 	sysfs_remove_group(&dev->kobj, &qeth_device_attr_group);
 	sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
 	sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index a1db959..90aa53f 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -259,21 +259,21 @@
 	size = sizeof(struct zfcp_fsf_req_qtcb);
 	align = calc_alignment(size);
 	zfcp_data.fsf_req_qtcb_cache =
-		kmem_cache_create("zfcp_fsf", size, align, 0, NULL, NULL);
+		kmem_cache_create("zfcp_fsf", size, align, 0, NULL);
 	if (!zfcp_data.fsf_req_qtcb_cache)
 		goto out;
 
 	size = sizeof(struct fsf_status_read_buffer);
 	align = calc_alignment(size);
 	zfcp_data.sr_buffer_cache =
-		kmem_cache_create("zfcp_sr", size, align, 0, NULL, NULL);
+		kmem_cache_create("zfcp_sr", size, align, 0, NULL);
 	if (!zfcp_data.sr_buffer_cache)
 		goto out_sr_cache;
 
 	size = sizeof(struct zfcp_gid_pn_data);
 	align = calc_alignment(size);
 	zfcp_data.gid_pn_cache =
-		kmem_cache_create("zfcp_gid", size, align, 0, NULL, NULL);
+		kmem_cache_create("zfcp_gid", size, align, 0, NULL);
 	if (!zfcp_data.gid_pn_cache)
 		goto out_gid_cache;
 
@@ -1503,7 +1503,7 @@
 			data->ct.pool = pool;
 		}
 	} else {
-		data = kmalloc(sizeof(struct zfcp_gid_pn_data), GFP_ATOMIC);
+		data = kmem_cache_alloc(zfcp_data.gid_pn_cache, GFP_ATOMIC);
 	}
 
         if (NULL == data)
@@ -1526,15 +1526,12 @@
  * zfcp_gid_pn_buffers_free - free buffers for GID_PN nameserver request
  * @gid_pn: pointer to struct zfcp_gid_pn_data which has to be freed
  */
-static void
-zfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn)
+static void zfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn)
 {
-        if ((gid_pn->ct.pool != 0))
+	if (gid_pn->ct.pool)
 		mempool_free(gid_pn, gid_pn->ct.pool);
 	else
-                kfree(gid_pn);
-
-	return;
+		kmem_cache_free(zfcp_data.gid_pn_cache, gid_pn);
 }
 
 /**
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index 1c8f71a..c0d1c0e 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -28,7 +28,7 @@
 static int zfcp_ccw_set_online(struct ccw_device *);
 static int zfcp_ccw_set_offline(struct ccw_device *);
 static int zfcp_ccw_notify(struct ccw_device *, int);
-static void zfcp_ccw_shutdown(struct device *);
+static void zfcp_ccw_shutdown(struct ccw_device *);
 
 static struct ccw_device_id zfcp_ccw_device_id[] = {
 	{CCW_DEVICE_DEVTYPE(ZFCP_CONTROL_UNIT_TYPE,
@@ -51,9 +51,7 @@
 	.set_online  = zfcp_ccw_set_online,
 	.set_offline = zfcp_ccw_set_offline,
 	.notify      = zfcp_ccw_notify,
-	.driver      = {
-		.shutdown = zfcp_ccw_shutdown,
-	},
+	.shutdown    = zfcp_ccw_shutdown,
 };
 
 MODULE_DEVICE_TABLE(ccw, zfcp_ccw_device_id);
@@ -277,12 +275,12 @@
  * Makes sure that QDIO queues are down when the system gets stopped.
  */
 static void
-zfcp_ccw_shutdown(struct device *dev)
+zfcp_ccw_shutdown(struct ccw_device *cdev)
 {
 	struct zfcp_adapter *adapter;
 
 	down(&zfcp_data.config_sema);
-	adapter = dev_get_drvdata(dev);
+	adapter = dev_get_drvdata(&cdev->dev);
 	zfcp_erp_adapter_shutdown(adapter, 0);
 	zfcp_erp_wait(adapter);
 	up(&zfcp_data.config_sema);
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 5f32124..ffa3bf75 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -19,8 +19,8 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <asm/debug.h>
 #include <linux/ctype.h>
+#include <asm/debug.h>
 #include "zfcp_ext.h"
 
 static u32 dbfsize = 4;
@@ -35,17 +35,17 @@
 zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck)
 {
 	unsigned long long sec;
-	struct timespec xtime;
+	struct timespec dbftime;
 	int len = 0;
 
 	stck -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
 	sec = stck >> 12;
 	do_div(sec, 1000000);
-	xtime.tv_sec = sec;
+	dbftime.tv_sec = sec;
 	stck -= (sec * 1000000) << 12;
-	xtime.tv_nsec = ((stck * 1000) >> 12);
+	dbftime.tv_nsec = ((stck * 1000) >> 12);
 	len += sprintf(out_buf + len, "%-24s%011lu:%06lu\n",
-		       label, xtime.tv_sec, xtime.tv_nsec);
+		       label, dbftime.tv_sec, dbftime.tv_nsec);
 
 	return len;
 }
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 2264963..b36dfc4 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -126,6 +126,7 @@
 #define ZFCP_MIN_OUTPUT_THRESHOLD 	1	/* ignored by QDIO layer */
 
 #define QDIO_SCSI_QFMT			1	/* 1 for FSF */
+#define QBUFF_PER_PAGE			(PAGE_SIZE / sizeof(struct qdio_buffer))
 
 /********************* FSF SPECIFIC DEFINES *********************************/
 
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 4e7cb6d..16b4418 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -54,7 +54,7 @@
 static int zfcp_erp_strategy_statechange(int, u32, struct zfcp_adapter *,
 					 struct zfcp_port *,
 					 struct zfcp_unit *, int);
-static inline int zfcp_erp_strategy_statechange_detected(atomic_t *, u32);
+static int zfcp_erp_strategy_statechange_detected(atomic_t *, u32);
 static int zfcp_erp_strategy_followup_actions(int, struct zfcp_adapter *,
 					      struct zfcp_port *,
 					      struct zfcp_unit *, int);
@@ -106,8 +106,8 @@
 static void zfcp_erp_action_ready(struct zfcp_erp_action *);
 static int  zfcp_erp_action_exists(struct zfcp_erp_action *);
 
-static inline void zfcp_erp_action_to_ready(struct zfcp_erp_action *);
-static inline void zfcp_erp_action_to_running(struct zfcp_erp_action *);
+static void zfcp_erp_action_to_ready(struct zfcp_erp_action *);
+static void zfcp_erp_action_to_running(struct zfcp_erp_action *);
 
 static void zfcp_erp_memwait_handler(unsigned long);
 
@@ -952,7 +952,7 @@
  *		action gets an appropriate flag and will be processed
  *		accordingly
  */
-void zfcp_erp_timeout_handler(unsigned long data)
+static void zfcp_erp_timeout_handler(unsigned long data)
 {
 	struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data;
 	struct zfcp_adapter *adapter = erp_action->adapter;
@@ -1491,7 +1491,7 @@
 	return retval;
 }
 
-static inline int
+static int
 zfcp_erp_strategy_statechange_detected(atomic_t * target_status, u32 erp_status)
 {
 	return
@@ -1626,7 +1626,7 @@
 {
 	struct zfcp_erp_add_work *p;
 
-	p = kmalloc(sizeof(*p), GFP_KERNEL);
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
 	if (!p) {
 		ZFCP_LOG_NORMAL("error: Out of resources. Could not register "
 				"the FCP-LUN 0x%Lx connected to "
@@ -1639,7 +1639,6 @@
 	}
 
 	zfcp_unit_get(unit);
-	memset(p, 0, sizeof(*p));
 	atomic_set_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status);
 	INIT_WORK(&p->work, zfcp_erp_scsi_scan);
 	p->unit = unit;
@@ -2002,7 +2001,7 @@
  * returns:	0 - successful setup
  *		!0 - failed setup
  */
-int
+static int
 zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
 {
 	int retval;
@@ -3249,8 +3248,7 @@
 		zfcp_erp_action_dismiss(&unit->erp_action);
 }
 
-static inline void
-zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
+static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action)
 {
 	struct zfcp_adapter *adapter = erp_action->adapter;
 
@@ -3259,8 +3257,7 @@
 	list_move(&erp_action->list, &erp_action->adapter->erp_running_head);
 }
 
-static inline void
-zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
+static void zfcp_erp_action_to_ready(struct zfcp_erp_action *erp_action)
 {
 	struct zfcp_adapter *adapter = erp_action->adapter;
 
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 0eb31e1..9929997 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -1930,7 +1930,7 @@
 skip_fsfstatus:
 	send_els->status = retval;
 
-	if (send_els->handler != 0)
+	if (send_els->handler)
 		send_els->handler(send_els->handler_data);
 
 	return retval;
@@ -4154,8 +4154,9 @@
 			      fcp_rsp_iu->fcp_resid,
 			      (int) zfcp_get_fcp_dl(fcp_cmnd_iu));
 
-		scpnt->resid = fcp_rsp_iu->fcp_resid;
-		if (scpnt->request_bufflen - scpnt->resid < scpnt->underflow)
+		scsi_set_resid(scpnt, fcp_rsp_iu->fcp_resid);
+		if (scsi_bufflen(scpnt) - scsi_get_resid(scpnt) <
+		    scpnt->underflow)
 			set_host_byte(&scpnt->result, DID_ERROR);
 	}
 
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index bdf5782..c6899ef 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -36,8 +36,6 @@
 	(struct zfcp_fsf_req *, unsigned long, void *, int);
 static int zfcp_qdio_sbals_from_segment
 	(struct zfcp_fsf_req *, unsigned long, void *, unsigned long);
-static int zfcp_qdio_sbals_from_buffer
-	(struct zfcp_fsf_req *, unsigned long, void *, unsigned long, int);
 
 static qdio_handler_t zfcp_qdio_request_handler;
 static qdio_handler_t zfcp_qdio_response_handler;
@@ -47,103 +45,56 @@
 #define ZFCP_LOG_AREA                   ZFCP_LOG_AREA_QDIO
 
 /*
- * Allocates BUFFER memory to each of the pointers of the qdio_buffer_t 
- * array in the adapter struct.
- * Cur_buf is the pointer array and count can be any number of required 
- * buffers, the page-fitting arithmetic is done entirely within this funciton.
- *
- * returns:	number of buffers allocated
- * locks:       must only be called with zfcp_data.config_sema taken
- */
-static int
-zfcp_qdio_buffers_enqueue(struct qdio_buffer **cur_buf, int count)
-{
-	int buf_pos;
-	int qdio_buffers_per_page;
-	int page_pos = 0;
-	struct qdio_buffer *first_in_page = NULL;
-
-	qdio_buffers_per_page = PAGE_SIZE / sizeof (struct qdio_buffer);
-	ZFCP_LOG_TRACE("buffers_per_page=%d\n", qdio_buffers_per_page);
-
-	for (buf_pos = 0; buf_pos < count; buf_pos++) {
-		if (page_pos == 0) {
-			cur_buf[buf_pos] = (struct qdio_buffer *)
-			    get_zeroed_page(GFP_KERNEL);
-			if (cur_buf[buf_pos] == NULL) {
-				ZFCP_LOG_INFO("error: allocation of "
-					      "QDIO buffer failed \n");
-				goto out;
-			}
-			first_in_page = cur_buf[buf_pos];
-		} else {
-			cur_buf[buf_pos] = first_in_page + page_pos;
-
-		}
-		/* was initialised to zero */
-		page_pos++;
-		page_pos %= qdio_buffers_per_page;
-	}
- out:
-	return buf_pos;
-}
-
-/*
  * Frees BUFFER memory for each of the pointers of the struct qdio_buffer array
- * in the adapter struct cur_buf is the pointer array and count can be any
- * number of buffers in the array that should be freed starting from buffer 0
+ * in the adapter struct sbuf is the pointer array.
  *
  * locks:       must only be called with zfcp_data.config_sema taken
  */
 static void
-zfcp_qdio_buffers_dequeue(struct qdio_buffer **cur_buf, int count)
+zfcp_qdio_buffers_dequeue(struct qdio_buffer **sbuf)
 {
-	int buf_pos;
-	int qdio_buffers_per_page;
+	int pos;
 
-	qdio_buffers_per_page = PAGE_SIZE / sizeof (struct qdio_buffer);
-	ZFCP_LOG_TRACE("buffers_per_page=%d\n", qdio_buffers_per_page);
+	for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE)
+		free_page((unsigned long) sbuf[pos]);
+}
 
-	for (buf_pos = 0; buf_pos < count; buf_pos += qdio_buffers_per_page)
-		free_page((unsigned long) cur_buf[buf_pos]);
-	return;
+/*
+ * Allocates BUFFER memory to each of the pointers of the qdio_buffer_t
+ * array in the adapter struct.
+ * Cur_buf is the pointer array
+ *
+ * returns:	zero on success else -ENOMEM
+ * locks:       must only be called with zfcp_data.config_sema taken
+ */
+static int
+zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbuf)
+{
+	int pos;
+
+	for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE) {
+		sbuf[pos] = (struct qdio_buffer *) get_zeroed_page(GFP_KERNEL);
+		if (!sbuf[pos]) {
+			zfcp_qdio_buffers_dequeue(sbuf);
+			return -ENOMEM;
+		}
+	}
+	for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos++)
+		if (pos % QBUFF_PER_PAGE)
+			sbuf[pos] = sbuf[pos - 1] + 1;
+	return 0;
 }
 
 /* locks:       must only be called with zfcp_data.config_sema taken */
 int
 zfcp_qdio_allocate_queues(struct zfcp_adapter *adapter)
 {
-	int buffer_count;
-	int retval = 0;
+	int ret;
 
-	buffer_count =
-	    zfcp_qdio_buffers_enqueue(&(adapter->request_queue.buffer[0]),
-				      QDIO_MAX_BUFFERS_PER_Q);
-	if (buffer_count < QDIO_MAX_BUFFERS_PER_Q) {
-		ZFCP_LOG_DEBUG("only %d QDIO buffers allocated for request "
-			       "queue\n", buffer_count);
-		zfcp_qdio_buffers_dequeue(&(adapter->request_queue.buffer[0]),
-					  buffer_count);
-		retval = -ENOMEM;
-		goto out;
-	}
-
-	buffer_count =
-	    zfcp_qdio_buffers_enqueue(&(adapter->response_queue.buffer[0]),
-				      QDIO_MAX_BUFFERS_PER_Q);
-	if (buffer_count < QDIO_MAX_BUFFERS_PER_Q) {
-		ZFCP_LOG_DEBUG("only %d QDIO buffers allocated for response "
-			       "queue", buffer_count);
-		zfcp_qdio_buffers_dequeue(&(adapter->response_queue.buffer[0]),
-					  buffer_count);
-		ZFCP_LOG_TRACE("freeing request_queue buffers\n");
-		zfcp_qdio_buffers_dequeue(&(adapter->request_queue.buffer[0]),
-					  QDIO_MAX_BUFFERS_PER_Q);
-		retval = -ENOMEM;
-		goto out;
-	}
- out:
-	return retval;
+	ret = zfcp_qdio_buffers_enqueue(adapter->request_queue.buffer);
+	if (ret)
+		return ret;
+	return zfcp_qdio_buffers_enqueue(adapter->response_queue.buffer);
 }
 
 /* locks:       must only be called with zfcp_data.config_sema taken */
@@ -151,12 +102,10 @@
 zfcp_qdio_free_queues(struct zfcp_adapter *adapter)
 {
 	ZFCP_LOG_TRACE("freeing request_queue buffers\n");
-	zfcp_qdio_buffers_dequeue(&(adapter->request_queue.buffer[0]),
-				  QDIO_MAX_BUFFERS_PER_Q);
+	zfcp_qdio_buffers_dequeue(adapter->request_queue.buffer);
 
 	ZFCP_LOG_TRACE("freeing response_queue buffers\n");
-	zfcp_qdio_buffers_dequeue(&(adapter->response_queue.buffer[0]),
-				  QDIO_MAX_BUFFERS_PER_Q);
+	zfcp_qdio_buffers_dequeue(adapter->response_queue.buffer);
 }
 
 int
@@ -681,28 +630,6 @@
 
 
 /**
- * zfcp_qdio_sbals_from_buffer - fill SBALs from buffer
- * @fsf_req: request to be processed
- * @sbtype: SBALE flags
- * @buffer: data buffer
- * @length: length of buffer
- * @max_sbals: upper bound for number of SBALs to be used
- */
-static int
-zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
-			    void *buffer, unsigned long length, int max_sbals)
-{
-	struct scatterlist sg_segment;
-
-	zfcp_address_to_sg(buffer, &sg_segment);
-	sg_segment.length = length;
-
-	return zfcp_qdio_sbals_from_sg(fsf_req, sbtype, &sg_segment, 1,
-                                       max_sbals);
-}
-
-
-/**
  * zfcp_qdio_sbals_from_scsicmnd - fill SBALs from scsi command
  * @fsf_req: request to be processed
  * @sbtype: SBALE flags
@@ -713,18 +640,9 @@
 zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req,
 			      unsigned long sbtype, struct scsi_cmnd *scsi_cmnd)
 {
-	if (scsi_cmnd->use_sg) {
-		return zfcp_qdio_sbals_from_sg(fsf_req,	sbtype,
-                                               (struct scatterlist *)
-                                               scsi_cmnd->request_buffer,
-                                               scsi_cmnd->use_sg,
-                                               ZFCP_MAX_SBALS_PER_REQ);
-	} else {
-                return zfcp_qdio_sbals_from_buffer(fsf_req, sbtype,
-                                                   scsi_cmnd->request_buffer,
-                                                   scsi_cmnd->request_bufflen,
-                                                   ZFCP_MAX_SBALS_PER_REQ);
-	}
+	return zfcp_qdio_sbals_from_sg(fsf_req,	sbtype, scsi_sglist(scsi_cmnd),
+				       scsi_sg_count(scsi_cmnd),
+				       ZFCP_MAX_SBALS_PER_REQ);
 }
 
 /**
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 0acf6db..ad7eb4a 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -764,7 +764,9 @@
 		return;
 
 	ret = zfcp_fsf_exchange_port_data(NULL, adapter, data);
-	if (ret == 0) {
+	if (ret) {
+		kfree(data);
+	} else {
 		adapter->stats_reset = jiffies/HZ;
 		old_data = adapter->stats_reset_data;
 		adapter->stats_reset_data = data; /* finally freed in
diff --git a/drivers/sbus/char/Kconfig b/drivers/sbus/char/Kconfig
index 35a7316..400c65b 100644
--- a/drivers/sbus/char/Kconfig
+++ b/drivers/sbus/char/Kconfig
@@ -15,6 +15,7 @@
 
 config SUN_MOSTEK_RTC
 	tristate "Mostek real time clock support"
+	depends on SPARC32
 	help
 	  The Mostek RTC chip is used on all known Sun computers except
 	  some JavaStations. For a JavaStation you need to say Y both here
diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c
index a54e414..0bde269 100644
--- a/drivers/sbus/char/bbc_envctrl.c
+++ b/drivers/sbus/char/bbc_envctrl.c
@@ -7,6 +7,7 @@
 #include <linux/kthread.h>
 #include <linux/delay.h>
 #include <linux/kmod.h>
+#include <linux/reboot.h>
 #include <asm/oplib.h>
 #include <asm/ebus.h>
 
@@ -170,8 +171,6 @@
 static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp)
 {
 	static int shutting_down = 0;
-	static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
-	char *argv[] = { "/sbin/shutdown", "-h", "now", NULL };
 	char *type = "???";
 	s8 val = -1;
 
@@ -195,7 +194,7 @@
 	printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n");
 
 	shutting_down = 1;
-	if (call_usermodehelper("/sbin/shutdown", argv, envp, 0) < 0)
+	if (orderly_poweroff(true) < 0)
 		printk(KERN_CRIT "envctrl: shutdown execution failed\n");
 }
 
@@ -480,11 +479,12 @@
 
 static void attach_one_temp(struct linux_ebus_child *echild, int temp_idx)
 {
-	struct bbc_cpu_temperature *tp = kmalloc(sizeof(*tp), GFP_KERNEL);
+	struct bbc_cpu_temperature *tp;
 
+	tp = kzalloc(sizeof(*tp), GFP_KERNEL);
 	if (!tp)
 		return;
-	memset(tp, 0, sizeof(*tp));
+
 	tp->client = bbc_i2c_attach(echild);
 	if (!tp->client) {
 		kfree(tp);
@@ -526,11 +526,12 @@
 
 static void attach_one_fan(struct linux_ebus_child *echild, int fan_idx)
 {
-	struct bbc_fan_control *fp = kmalloc(sizeof(*fp), GFP_KERNEL);
+	struct bbc_fan_control *fp;
 
+	fp = kzalloc(sizeof(*fp), GFP_KERNEL);
 	if (!fp)
 		return;
-	memset(fp, 0, sizeof(*fp));
+
 	fp->client = bbc_i2c_attach(echild);
 	if (!fp->client) {
 		kfree(fp);
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c
index 178155b..ac8ef2c 100644
--- a/drivers/sbus/char/bbc_i2c.c
+++ b/drivers/sbus/char/bbc_i2c.c
@@ -156,10 +156,9 @@
 
 	if (!bp)
 		return NULL;
-	client = kmalloc(sizeof(*client), GFP_KERNEL);
+	client = kzalloc(sizeof(*client), GFP_KERNEL);
 	if (!client)
 		return NULL;
-	memset(client, 0, sizeof(*client));
 	client->bp = bp;
 	client->echild = echild;
 	client->bus = echild->resource[0].start;
@@ -358,13 +357,13 @@
 
 static int __init attach_one_i2c(struct linux_ebus_device *edev, int index)
 {
-	struct bbc_i2c_bus *bp = kmalloc(sizeof(*bp), GFP_KERNEL);
+	struct bbc_i2c_bus *bp;
 	struct linux_ebus_child *echild;
 	int entry;
 
+	bp = kzalloc(sizeof(*bp), GFP_KERNEL);
 	if (!bp)
 		return -ENOMEM;
-	memset(bp, 0, sizeof(*bp));
 
 	bp->i2c_control_regs = ioremap(edev->resource[0].start, 0x2);
 	if (!bp->i2c_control_regs)
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index 8328aca..dadabef 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -26,6 +26,7 @@
 #include <linux/ioport.h>
 #include <linux/miscdevice.h>
 #include <linux/kmod.h>
+#include <linux/reboot.h>
 
 #include <asm/ebus.h>
 #include <asm/uaccess.h>
@@ -966,10 +967,6 @@
 static void envctrl_do_shutdown(void)
 {
 	static int inprog = 0;
-	static char *envp[] = {	
-		"HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
-	char *argv[] = { 
-		"/sbin/shutdown", "-h", "now", NULL };	
 	int ret;
 
 	if (inprog != 0)
@@ -977,7 +974,7 @@
 
 	inprog = 1;
 	printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n");
-	ret = call_usermodehelper("/sbin/shutdown", argv, envp, 0);
+	ret = orderly_poweroff(true);
 	if (ret < 0) {
 		printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n"); 
 		inprog = 0;  /* unlikely to succeed, but we could try again */
diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
index 5157a2a..4b7079f 100644
--- a/drivers/sbus/char/jsflash.c
+++ b/drivers/sbus/char/jsflash.c
@@ -185,7 +185,7 @@
 	}
 }
 
-static void jsfd_do_request(request_queue_t *q)
+static void jsfd_do_request(struct request_queue *q)
 {
 	struct request *req;
 
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index 6afc7e5..9269f7f 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -248,6 +248,7 @@
 					buffer,inout.len);
 
 		if (copy_to_user(argp,&inout,sizeof(inout))) {
+			vfc_unlock_device(dev);
 			kfree(buffer);
 			return -EFAULT;
 		}
@@ -656,12 +657,9 @@
 	if (!cards)
 		return -ENODEV;
 
-	vfc_dev_lst = kmalloc(sizeof(struct vfc_dev *) *
-						 (cards+1),
-						 GFP_KERNEL);
+	vfc_dev_lst = kcalloc(cards + 1, sizeof(struct vfc_dev*), GFP_KERNEL);
 	if (vfc_dev_lst == NULL)
 		return -ENOMEM;
-	memset(vfc_dev_lst, 0, sizeof(struct vfc_dev *) * (cards + 1));
 	vfc_dev_lst[cards] = NULL;
 
 	ret = register_chrdev(VFC_MAJOR, vfcstr, &vfc_fops);
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index 0026433..c37d7c2 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -33,6 +33,7 @@
 
 static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
 {
+	struct dev_archdata *sd;
 	unsigned long base;
 	const void *pval;
 	int len, err;
@@ -67,6 +68,10 @@
 
 	sbus_fill_device_irq(sdev);
 
+	sd = &sdev->ofdev.dev.archdata;
+	sd->prom_node = dp;
+	sd->op = &sdev->ofdev;
+
 	sdev->ofdev.node = dp;
 	if (sdev->parent)
 		sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
@@ -205,6 +210,10 @@
 
 			sdev->bus = sbus;
 			sdev->parent = parent;
+			sdev->ofdev.dev.archdata.iommu =
+				sbus->ofdev.dev.archdata.iommu;
+			sdev->ofdev.dev.archdata.stc =
+				sbus->ofdev.dev.archdata.stc;
 
 			fill_sbus_device(dp, sdev);
 
@@ -264,6 +273,11 @@
 
 			sdev->bus = sbus;
 			sdev->parent = NULL;
+			sdev->ofdev.dev.archdata.iommu =
+				sbus->ofdev.dev.archdata.iommu;
+			sdev->ofdev.dev.archdata.stc =
+				sbus->ofdev.dev.archdata.stc;
+
 			fill_sbus_device(dev_dp, sdev);
 
 			walk_children(dev_dp, sdev, sbus);
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index 76c0909..efd9d8d 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -4,7 +4,7 @@
    Written By: Adam Radford <linuxraid@amcc.com>
    Modifications By: Tom Couch <linuxraid@amcc.com>
 
-   Copyright (C) 2004-2006 Applied Micro Circuits Corporation.
+   Copyright (C) 2004-2007 Applied Micro Circuits Corporation.
 
    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
@@ -69,6 +69,8 @@
    2.26.02.008 - Free irq handler in __twa_shutdown().
                  Serialize reset code.
                  Add support for 9650SE controllers.
+   2.26.02.009 - Fix dma mask setting to fallback to 32-bit if 64-bit fails.
+   2.26.02.010 - Add support for 9690SA controllers.
 */
 
 #include <linux/module.h>
@@ -92,7 +94,7 @@
 #include "3w-9xxx.h"
 
 /* Globals */
-#define TW_DRIVER_VERSION "2.26.02.008"
+#define TW_DRIVER_VERSION "2.26.02.010"
 static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
 static unsigned int twa_device_extension_count;
 static int twa_major = -1;
@@ -124,11 +126,11 @@
 			      unsigned short *fw_on_ctlr_branch, 
 			      unsigned short *fw_on_ctlr_build, 
 			      u32 *init_connect_result);
-static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length);
+static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length);
 static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds);
 static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds);
 static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal);
-static int twa_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset);
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev);
 static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset);
 static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg);
 static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id);
@@ -683,7 +685,7 @@
 		full_command_packet = &tw_ioctl->firmware_command;
 
 		/* Load request id and sglist for both command types */
-		twa_load_sgl(full_command_packet, request_id, dma_handle, data_buffer_length_adjusted);
+		twa_load_sgl(tw_dev, full_command_packet, request_id, dma_handle, data_buffer_length_adjusted);
 
 		memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full));
 
@@ -700,10 +702,10 @@
 		if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
 			/* Now we need to reset the board */
 			printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n",
-			       tw_dev->host->host_no, TW_DRIVER, 0xc,
+			       tw_dev->host->host_no, TW_DRIVER, 0x37,
 			       cmd);
 			retval = TW_IOCTL_ERROR_OS_EIO;
-			twa_reset_device_extension(tw_dev, 1);
+			twa_reset_device_extension(tw_dev);
 			goto out3;
 		}
 
@@ -890,7 +892,9 @@
 	}
 
 	if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
-		if ((tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9650SE) || (!test_bit(TW_IN_RESET, &tw_dev->flags)))
+		if (((tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9650SE) &&
+		     (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9690SA)) ||
+		    (!test_bit(TW_IN_RESET, &tw_dev->flags)))
 			TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing");
 		writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
 	}
@@ -935,8 +939,7 @@
 	unsigned long before;
 	int retval = 1;
 
-	if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9550SX) ||
-	    (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE)) {
+	if (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9000) {
 		before = jiffies;
 		while ((response_que_value & TW_9550SX_DRAIN_COMPLETED) != TW_9550SX_DRAIN_COMPLETED) {
 			response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR_LARGE(tw_dev));
@@ -1160,13 +1163,12 @@
 	}
 
 	/* Allocate event info space */
-	tw_dev->event_queue[0] = kmalloc(sizeof(TW_Event) * TW_Q_LENGTH, GFP_KERNEL);
+	tw_dev->event_queue[0] = kcalloc(TW_Q_LENGTH, sizeof(TW_Event), GFP_KERNEL);
 	if (!tw_dev->event_queue[0]) {
 		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed");
 		goto out;
 	}
 
-	memset(tw_dev->event_queue[0], 0, sizeof(TW_Event) * TW_Q_LENGTH);
 
 	for (i = 0; i < TW_Q_LENGTH; i++) {
 		tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event)));
@@ -1196,7 +1198,6 @@
 	u32 status_reg_value;
 	TW_Response_Queue response_que;
 	TW_Command_Full *full_command_packet;
-	TW_Command *command_packet;
 	TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
 	int handled = 0;
 
@@ -1274,7 +1275,6 @@
 			request_id = TW_RESID_OUT(response_que.response_id);
 			full_command_packet = tw_dev->command_packet_virt[request_id];
 			error = 0;
-			command_packet = &full_command_packet->command.oldcommand;
 			/* Check for command packet errors */
 			if (full_command_packet->command.newcommand.status != 0) {
 				if (tw_dev->srb[request_id] != 0) {
@@ -1353,11 +1353,15 @@
 } /* End twa_interrupt() */
 
 /* This function will load the request id and various sgls for ioctls */
-static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length)
+static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length)
 {
 	TW_Command *oldcommand;
 	TW_Command_Apache *newcommand;
 	TW_SG_Entry *sgl;
+	unsigned int pae = 0;
+
+	if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4))
+		pae = 1;
 
 	if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
 		newcommand = &full_command_packet->command.newcommand;
@@ -1373,12 +1377,14 @@
 
 		if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) {
 			/* Load the sg list */
-			sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset));
+			if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)
+				sgl = (TW_SG_Entry *)((u32 *)oldcommand+oldcommand->size - (sizeof(TW_SG_Entry)/4) + pae);
+			else
+				sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset));
 			sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1);
 			sgl->length = cpu_to_le32(length);
 
-			if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4))
-				oldcommand->size += 1;
+			oldcommand->size += pae;
 		}
 	}
 } /* End twa_load_sgl() */
@@ -1507,7 +1513,8 @@
 	command_que_value = tw_dev->command_packet_phys[request_id];
 
 	/* For 9650SE write low 4 bytes first */
-	if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) {
+	if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
+	    (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) {
 		command_que_value += TW_COMMAND_OFFSET;
 		writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev));
 	}
@@ -1538,7 +1545,8 @@
 		TW_UNMASK_COMMAND_INTERRUPT(tw_dev);
 		goto out;
 	} else {
-		if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) {
+		if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
+		    (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) {
 			/* Now write upper 4 bytes */
 			writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev) + 0x4);
 		} else {
@@ -1562,7 +1570,7 @@
 } /* End twa_post_command_packet() */
 
 /* This function will reset a device extension */
-static int twa_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset)
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev)
 {
 	int i = 0;
 	int retval = 1;
@@ -1720,7 +1728,7 @@
 	mutex_lock(&tw_dev->ioctl_lock);
 
 	/* Now reset the card and some of the device extension data */
-	if (twa_reset_device_extension(tw_dev, 0)) {
+	if (twa_reset_device_extension(tw_dev)) {
 		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset");
 		goto out;
 	}
@@ -2002,11 +2010,14 @@
 
 	pci_set_master(pdev);
 
-	retval = pci_set_dma_mask(pdev, sizeof(dma_addr_t) > 4 ? DMA_64BIT_MASK : DMA_32BIT_MASK);
-	if (retval) {
-		TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
-		goto out_disable_device;
-	}
+	if (pci_set_dma_mask(pdev, DMA_64BIT_MASK)
+	    || pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
+		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)
+		    || pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
+			TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
+			retval = -ENODEV;
+			goto out_disable_device;
+		}
 
 	host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
 	if (!host) {
@@ -2054,7 +2065,8 @@
 		goto out_iounmap;
 
 	/* Set host specific parameters */
-	if (pdev->device == PCI_DEVICE_ID_3WARE_9650SE)
+	if ((pdev->device == PCI_DEVICE_ID_3WARE_9650SE) ||
+	    (pdev->device == PCI_DEVICE_ID_3WARE_9690SA))
 		host->max_id = TW_MAX_UNITS_9650SE;
 	else
 		host->max_id = TW_MAX_UNITS;
@@ -2161,6 +2173,8 @@
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9650SE,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9690SA,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, twa_pci_tbl);
diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h
index 7901517..d14a947 100644
--- a/drivers/scsi/3w-9xxx.h
+++ b/drivers/scsi/3w-9xxx.h
@@ -4,7 +4,7 @@
    Written By: Adam Radford <linuxraid@amcc.com>
    Modifications By: Tom Couch <linuxraid@amcc.com>
 
-   Copyright (C) 2004-2006 Applied Micro Circuits Corporation.
+   Copyright (C) 2004-2007 Applied Micro Circuits Corporation.
 
    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
@@ -419,6 +419,9 @@
 #ifndef PCI_DEVICE_ID_3WARE_9650SE
 #define PCI_DEVICE_ID_3WARE_9650SE 0x1004
 #endif
+#ifndef PCI_DEVICE_ID_3WARE_9690SA
+#define PCI_DEVICE_ID_3WARE_9690SA 0x1005
+#endif
 
 /* Bitmask macros to eliminate bitfields */
 
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 3727231..6f2c71e 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -282,7 +282,7 @@
 
 config SCSI_SAS_ATTRS
 	tristate "SAS Transport Attributes"
-	depends on SCSI
+	depends on SCSI && BLK_DEV_BSG
 	help
 	  If you wish to export transport-specific information about
 	  each attached SAS device to sysfs, say Y.
@@ -291,8 +291,12 @@
 
 endmenu
 
-menu "SCSI low-level drivers"
+menuconfig SCSI_LOWLEVEL
+	bool "SCSI low-level drivers"
 	depends on SCSI!=n
+	default y
+
+if SCSI_LOWLEVEL
 
 config ISCSI_TCP
 	tristate "iSCSI Initiator over TCP/IP"
@@ -363,6 +367,7 @@
 config SCSI_7000FASST
 	tristate "7000FASST SCSI support"
 	depends on ISA && SCSI && ISA_DMA_API
+	select CHECK_SIGNATURE
 	help
 	  This driver supports the Western Digital 7000 SCSI host adapter
 	  family.  Some information is in the source:
@@ -384,6 +389,7 @@
 	tristate "Adaptec AHA152X/2825 support"
 	depends on ISA && SCSI && !64BIT
 	select SCSI_SPI_ATTRS
+	select CHECK_SIGNATURE
 	---help---
 	  This is a driver for the AHA-1510, AHA-1520, AHA-1522, and AHA-2825
 	  SCSI host adapters. It also works for the AVA-1505, but the IRQ etc.
@@ -483,7 +489,7 @@
 # All the I2O code and drivers do not seem to be 64bit safe.
 config SCSI_DPT_I2O
 	tristate "Adaptec I2O RAID support "
-	depends on !64BIT && SCSI && PCI
+	depends on !64BIT && SCSI && PCI && VIRT_TO_BUS
 	help
 	  This driver supports all of Adaptec's I2O based RAID controllers as 
 	  well as the DPT SmartRaid V cards.  This is an Adaptec maintained
@@ -579,6 +585,7 @@
 	tristate "DTC3180/3280 SCSI support"
 	depends on ISA && SCSI
 	select SCSI_SPI_ATTRS
+	select CHECK_SIGNATURE
 	help
 	  This is support for DTC 3180/3280 SCSI Host Adapters.  Please read
 	  the SCSI-HOWTO, available from
@@ -653,6 +660,7 @@
 config SCSI_FUTURE_DOMAIN
 	tristate "Future Domain 16xx SCSI/AHA-2920A support"
 	depends on (ISA || PCI) && SCSI
+	select CHECK_SIGNATURE
 	---help---
 	  This is support for Future Domain's 16-bit SCSI host adapters
 	  (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and
@@ -1320,6 +1328,7 @@
 config SCSI_SEAGATE
 	tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support"
 	depends on X86 && ISA && SCSI
+	select CHECK_SIGNATURE
 	---help---
 	  These are 8-bit SCSI controllers; the ST-01 is also supported by
 	  this driver.  It is explained in section 3.9 of the SCSI-HOWTO,
@@ -1393,6 +1402,7 @@
 	tristate "Trantor T128/T128F/T228 SCSI support"
 	depends on ISA && SCSI
 	select SCSI_SPI_ATTRS
+	select CHECK_SIGNATURE
 	---help---
 	  This is support for a SCSI host adapter. It is explained in section
 	  3.11 of the SCSI-HOWTO, available from
@@ -1557,7 +1567,7 @@
 	  built-in SCSI controller, say Y. Otherwise, say N.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called wd33c93.
+	  module will be called a3000.
 
 config A2091_SCSI
 	tristate "A2091/A590 WD33C93A support"
@@ -1567,7 +1577,7 @@
 	  say N.
 
 	  To compile this driver as a module, choose M here: the
-	  module will be called wd33c93.
+	  module will be called a2091.
 
 config GVP11_SCSI
 	tristate "GVP Series II WD33C93A support"
@@ -1800,7 +1810,7 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called libsrp.
 
-endmenu
+endif # SCSI_LOWLEVEL
 
 source "drivers/scsi/pcmcia/Kconfig"
 
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 0f86895..86a7ba7 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -132,6 +132,7 @@
 obj-$(CONFIG_SCSI_IBMVSCSIS)	+= ibmvscsi/
 obj-$(CONFIG_SCSI_HPTIOP)	+= hptiop.o
 obj-$(CONFIG_SCSI_STEX)		+= stex.o
+obj-$(CONFIG_PS3_ROM)		+= ps3rom.o
 
 obj-$(CONFIG_ARM)		+= arm/
 
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index 8b5334c..79b4df1 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -95,6 +95,8 @@
 /* The master ring of all esp hosts we are managing in this driver. */
 static struct NCR_ESP *espchain;
 int nesps = 0, esps_in_use = 0, esps_running = 0;
+EXPORT_SYMBOL(nesps);
+EXPORT_SYMBOL(esps_running);
 
 irqreturn_t esp_intr(int irq, void *dev_id);
 
@@ -524,6 +526,7 @@
 	/* Eat any bitrot in the chip and we are done... */
 	trash = esp_read(eregs->esp_intrpt);
 }
+EXPORT_SYMBOL(esp_bootup_reset);
 
 /* Allocate structure and insert basic data such as SCSI chip frequency
  * data and a pointer to the device
@@ -772,6 +775,7 @@
 		panic("Bogon ESP revision");
 	};
 }
+EXPORT_SYMBOL(esp_info);
 
 /* From Wolfgang Stanglmeier's NCR scsi driver. */
 struct info_str
@@ -902,6 +906,7 @@
 		*start = buffer;
 	return esp_host_info(esp, buffer, offset, length);
 }
+EXPORT_SYMBOL(esp_proc_info);
 
 static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
 {
@@ -3535,6 +3540,7 @@
 	if(esp->dma_irq_exit)
 		esp->dma_irq_exit(esp);
 }
+EXPORT_SYMBOL(esp_handle);
 
 #ifndef CONFIG_SMP
 irqreturn_t esp_intr(int irq, void *dev_id)
@@ -3606,11 +3612,10 @@
 int esp_slave_alloc(struct scsi_device *SDptr)
 {
 	struct esp_device *esp_dev =
-		kmalloc(sizeof(struct esp_device), GFP_ATOMIC);
+		kzalloc(sizeof(struct esp_device), GFP_ATOMIC);
 
 	if (!esp_dev)
 		return -ENOMEM;
-	memset(esp_dev, 0, sizeof(struct esp_device));
 	SDptr->hostdata = esp_dev;
 	return 0;
 }
@@ -3632,6 +3637,7 @@
 	esps_in_use--;
 	esps_running = esps_in_use;
 }
+EXPORT_SYMBOL(esp_release);
 #endif
 
 EXPORT_SYMBOL(esp_abort);
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
index f12864a..3a80897 100644
--- a/drivers/scsi/NCR_D700.c
+++ b/drivers/scsi/NCR_D700.c
@@ -181,13 +181,12 @@
 	struct Scsi_Host *host;
 	int ret;
 
-	hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL);
+	hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL);
 	if (!hostdata) {
 		printk(KERN_ERR "NCR D700: SIOP%d: Failed to allocate host"
 		       "data, detatching\n", siop);
 		return -ENOMEM;
 	}
-	memset(hostdata, 0, sizeof(*hostdata));
 
 	if (!request_region(region, 64, "NCR_D700")) {
 		printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n",
diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c
index 778844c..a8bbdc2 100644
--- a/drivers/scsi/NCR_Q720.c
+++ b/drivers/scsi/NCR_Q720.c
@@ -148,11 +148,10 @@
 	__u32 base_addr, mem_size;
 	void __iomem *mem_base;
 
-	p = kmalloc(sizeof(*p), GFP_KERNEL);
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
 	if (!p)
 		return -ENOMEM;
 
-	memset(p, 0, sizeof(*p));
 	pos2 = mca_device_read_pos(mca_dev, 2);
 	/* enable device */
 	pos2 |=  NCR_Q720_POS2_BOARD_ENABLE | NCR_Q720_POS2_INTERRUPT_ENABLE;
diff --git a/drivers/scsi/a4000t.c b/drivers/scsi/a4000t.c
index 6a57846..0c758d1 100644
--- a/drivers/scsi/a4000t.c
+++ b/drivers/scsi/a4000t.c
@@ -79,6 +79,7 @@
 		goto out_put_host;
 	}
 
+	dev_set_drvdata(dev, host);
 	scsi_scan_host(host);
 
 	return 0;
@@ -95,7 +96,7 @@
 
 static __devexit int a4000t_device_remove(struct device *dev)
 {
-	struct Scsi_Host *host = dev_to_shost(dev);
+	struct Scsi_Host *host = dev_get_drvdata(dev);
 	struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
 
 	scsi_remove_host(host);
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 0b6fd0b..6800e57 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -194,8 +194,7 @@
 	struct scsi_device *device;
 
 	if (unlikely(!scsicmd || !scsicmd->scsi_done )) {
-		dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n"))
-;
+		dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n"));
                 aac_fib_complete(fibptr);
                 aac_fib_free(fibptr);
                 return 0;
@@ -751,6 +750,101 @@
 	inqstrcpy ("V1.0", str->prl);
 }
 
+static void get_container_serial_callback(void *context, struct fib * fibptr)
+{
+	struct aac_get_serial_resp * get_serial_reply;
+	struct scsi_cmnd * scsicmd;
+
+	BUG_ON(fibptr == NULL);
+
+	scsicmd = (struct scsi_cmnd *) context;
+	if (!aac_valid_context(scsicmd, fibptr))
+		return;
+
+	get_serial_reply = (struct aac_get_serial_resp *) fib_data(fibptr);
+	/* Failure is irrelevant, using default value instead */
+	if (le32_to_cpu(get_serial_reply->status) == CT_OK) {
+		char sp[13];
+		/* EVPD bit set */
+		sp[0] = INQD_PDT_DA;
+		sp[1] = scsicmd->cmnd[2];
+		sp[2] = 0;
+		sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X",
+		  le32_to_cpu(get_serial_reply->uid));
+		aac_internal_transfer(scsicmd, sp, 0, sizeof(sp));
+	}
+
+	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+
+	aac_fib_complete(fibptr);
+	aac_fib_free(fibptr);
+	scsicmd->scsi_done(scsicmd);
+}
+
+/**
+ *	aac_get_container_serial - get container serial, none blocking.
+ */
+static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
+{
+	int status;
+	struct aac_get_serial *dinfo;
+	struct fib * cmd_fibcontext;
+	struct aac_dev * dev;
+
+	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+
+	if (!(cmd_fibcontext = aac_fib_alloc(dev)))
+		return -ENOMEM;
+
+	aac_fib_init(cmd_fibcontext);
+	dinfo = (struct aac_get_serial *) fib_data(cmd_fibcontext);
+
+	dinfo->command = cpu_to_le32(VM_ContainerConfig);
+	dinfo->type = cpu_to_le32(CT_CID_TO_32BITS_UID);
+	dinfo->cid = cpu_to_le32(scmd_id(scsicmd));
+
+	status = aac_fib_send(ContainerCommand,
+		  cmd_fibcontext,
+		  sizeof (struct aac_get_serial),
+		  FsaNormal,
+		  0, 1,
+		  (fib_callback) get_container_serial_callback,
+		  (void *) scsicmd);
+
+	/*
+	 *	Check that the command queued to the controller
+	 */
+	if (status == -EINPROGRESS) {
+		scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+		return 0;
+	}
+
+	printk(KERN_WARNING "aac_get_container_serial: aac_fib_send failed with status: %d.\n", status);
+	aac_fib_complete(cmd_fibcontext);
+	aac_fib_free(cmd_fibcontext);
+	return -1;
+}
+
+/* Function: setinqserial
+ *
+ * Arguments: [1] pointer to void [1] int
+ *
+ * Purpose: Sets SCSI Unit Serial number.
+ *          This is a fake. We should read a proper
+ *          serial number from the container. <SuSE>But
+ *          without docs it's quite hard to do it :-)
+ *          So this will have to do in the meantime.</SuSE>
+ */
+
+static int setinqserial(struct aac_dev *dev, void *data, int cid)
+{
+	/*
+	 *	This breaks array migration.
+	 */
+	return snprintf((char *)(data), sizeof(struct scsi_inq) - 4, "%08X%02X",
+			le32_to_cpu(dev->adapter_info.serial[0]), cid);
+}
+
 static void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code,
 		      u8 a_sense_code, u8 incorrect_length,
 		      u8 bit_pointer, u16 field_pointer,
@@ -1594,23 +1688,23 @@
 	if (!aac_valid_context(cmd, fibptr))
 		return;
 
-	dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n", 
+	dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n",
 				smp_processor_id(), jiffies));
 	BUG_ON(fibptr == NULL);
 
 
 	synchronizereply = fib_data(fibptr);
 	if (le32_to_cpu(synchronizereply->status) == CT_OK)
-		cmd->result = DID_OK << 16 | 
+		cmd->result = DID_OK << 16 |
 			COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
 	else {
 		struct scsi_device *sdev = cmd->device;
 		struct aac_dev *dev = fibptr->dev;
 		u32 cid = sdev_id(sdev);
-		printk(KERN_WARNING 
+		printk(KERN_WARNING
 		     "synchronize_callback: synchronize failed, status = %d\n",
 		     le32_to_cpu(synchronizereply->status));
-		cmd->result = DID_OK << 16 | 
+		cmd->result = DID_OK << 16 |
 			COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
 		set_sense((u8 *)&dev->fsa_dev[cid].sense_data,
 				    HARDWARE_ERROR,
@@ -1618,7 +1712,7 @@
 				    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
 				    0, 0);
 		memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
-		  min(sizeof(dev->fsa_dev[cid].sense_data), 
+		  min(sizeof(dev->fsa_dev[cid].sense_data),
 			  sizeof(cmd->sense_buffer)));
 	}
 
@@ -1636,6 +1730,9 @@
 	struct scsi_device *sdev = scsicmd->device;
 	int active = 0;
 	struct aac_dev *aac;
+	u64 lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) |
+		(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+	u32 count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
 	unsigned long flags;
 
 	/*
@@ -1644,7 +1741,51 @@
 	 */
 	spin_lock_irqsave(&sdev->list_lock, flags);
 	list_for_each_entry(cmd, &sdev->cmd_list, list)
-		if (cmd != scsicmd && cmd->SCp.phase == AAC_OWNER_FIRMWARE) {
+		if (cmd->SCp.phase == AAC_OWNER_FIRMWARE) {
+			u64 cmnd_lba;
+			u32 cmnd_count;
+
+			if (cmd->cmnd[0] == WRITE_6) {
+				cmnd_lba = ((cmd->cmnd[1] & 0x1F) << 16) |
+					(cmd->cmnd[2] << 8) |
+					cmd->cmnd[3];
+				cmnd_count = cmd->cmnd[4];
+				if (cmnd_count == 0)
+					cmnd_count = 256;
+			} else if (cmd->cmnd[0] == WRITE_16) {
+				cmnd_lba = ((u64)cmd->cmnd[2] << 56) |
+					((u64)cmd->cmnd[3] << 48) |
+					((u64)cmd->cmnd[4] << 40) |
+					((u64)cmd->cmnd[5] << 32) |
+					((u64)cmd->cmnd[6] << 24) |
+					(cmd->cmnd[7] << 16) |
+					(cmd->cmnd[8] << 8) |
+					cmd->cmnd[9];
+				cmnd_count = (cmd->cmnd[10] << 24) |
+					(cmd->cmnd[11] << 16) |
+					(cmd->cmnd[12] << 8) |
+					cmd->cmnd[13];
+			} else if (cmd->cmnd[0] == WRITE_12) {
+				cmnd_lba = ((u64)cmd->cmnd[2] << 24) |
+					(cmd->cmnd[3] << 16) |
+					(cmd->cmnd[4] << 8) |
+					cmd->cmnd[5];
+				cmnd_count = (cmd->cmnd[6] << 24) |
+					(cmd->cmnd[7] << 16) |
+					(cmd->cmnd[8] << 8) |
+					cmd->cmnd[9];
+			} else if (cmd->cmnd[0] == WRITE_10) {
+				cmnd_lba = ((u64)cmd->cmnd[2] << 24) |
+					(cmd->cmnd[3] << 16) |
+					(cmd->cmnd[4] << 8) |
+					cmd->cmnd[5];
+				cmnd_count = (cmd->cmnd[7] << 8) |
+					cmd->cmnd[8];
+			} else
+				continue;
+			if (((cmnd_lba + cmnd_count) < lba) ||
+			  (count && ((lba + count) < cmnd_lba)))
+				continue;
 			++active;
 			break;
 		}
@@ -1673,7 +1814,7 @@
 	synchronizecmd->command = cpu_to_le32(VM_ContainerConfig);
 	synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE);
 	synchronizecmd->cid = cpu_to_le32(scmd_id(scsicmd));
-	synchronizecmd->count = 
+	synchronizecmd->count =
 	     cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data));
 
 	/*
@@ -1695,7 +1836,7 @@
 		return 0;
 	}
 
-	printk(KERN_WARNING 
+	printk(KERN_WARNING
 		"aac_synchronize: aac_fib_send failed with status: %d.\n", status);
 	aac_fib_complete(cmd_fibcontext);
 	aac_fib_free(cmd_fibcontext);
@@ -1798,6 +1939,49 @@
 		dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid));
 		memset(&inq_data, 0, sizeof (struct inquiry_data));
 
+		if (scsicmd->cmnd[1] & 0x1 ) {
+			char *arr = (char *)&inq_data;
+
+			/* EVPD bit set */
+			arr[0] = (scmd_id(scsicmd) == host->this_id) ?
+			  INQD_PDT_PROC : INQD_PDT_DA;
+			if (scsicmd->cmnd[2] == 0) {
+				/* supported vital product data pages */
+				arr[3] = 2;
+				arr[4] = 0x0;
+				arr[5] = 0x80;
+				arr[1] = scsicmd->cmnd[2];
+				aac_internal_transfer(scsicmd, &inq_data, 0,
+				  sizeof(inq_data));
+				scsicmd->result = DID_OK << 16 |
+				  COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+			} else if (scsicmd->cmnd[2] == 0x80) {
+				/* unit serial number page */
+				arr[3] = setinqserial(dev, &arr[4],
+				  scmd_id(scsicmd));
+				arr[1] = scsicmd->cmnd[2];
+				aac_internal_transfer(scsicmd, &inq_data, 0,
+				  sizeof(inq_data));
+				return aac_get_container_serial(scsicmd);
+			} else {
+				/* vpd page not implemented */
+				scsicmd->result = DID_OK << 16 |
+				  COMMAND_COMPLETE << 8 |
+				  SAM_STAT_CHECK_CONDITION;
+				set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+				  ILLEGAL_REQUEST,
+				  SENCODE_INVALID_CDB_FIELD,
+				  ASENCODE_NO_SENSE, 0, 7, 2, 0);
+				memcpy(scsicmd->sense_buffer,
+				  &dev->fsa_dev[cid].sense_data,
+				  (sizeof(dev->fsa_dev[cid].sense_data) >
+				    sizeof(scsicmd->sense_buffer))
+				       ? sizeof(scsicmd->sense_buffer)
+				       : sizeof(dev->fsa_dev[cid].sense_data));
+			}
+			scsicmd->scsi_done(scsicmd);
+			return 0;
+		}
 		inq_data.inqd_ver = 2;	/* claim compliance to SCSI-2 */
 		inq_data.inqd_rdf = 2;	/* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
 		inq_data.inqd_len = 31;
@@ -2070,7 +2254,7 @@
 	}
 	else return -EINVAL;
 
-	qd.valid = fsa_dev_ptr[qd.cnum].valid;
+	qd.valid = fsa_dev_ptr[qd.cnum].valid != 0;
 	qd.locked = fsa_dev_ptr[qd.cnum].locked;
 	qd.deleted = fsa_dev_ptr[qd.cnum].deleted;
 
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index f1d3b66..94727b9 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,7 +12,7 @@
  *----------------------------------------------------------------------------*/
 
 #ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 2447
+# define AAC_DRIVER_BUILD 2449
 # define AAC_DRIVER_BRANCH "-ms"
 #endif
 #define MAXIMUM_NUM_CONTAINERS	32
@@ -1567,6 +1567,20 @@
 	u8		data[16];
 };
 
+#define CT_CID_TO_32BITS_UID 165
+struct aac_get_serial {
+	__le32		command;	/* VM_ContainerConfig */
+	__le32		type;		/* CT_CID_TO_32BITS_UID */
+	__le32		cid;
+};
+
+struct aac_get_serial_resp {
+	__le32		dummy0;
+	__le32		dummy1;
+	__le32		status;	/* CT_OK */
+	__le32		uid;
+};
+
 /*
  * The following command is sent to shut down each container.
  */
@@ -1793,10 +1807,10 @@
  *  	accounting for the fact capacity could be a 64 bit value
  *
  */
-static inline u32 cap_to_cyls(sector_t capacity, u32 divisor)
+static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor)
 {
 	sector_div(capacity, divisor);
-	return (u32)capacity;
+	return capacity;
 }
 
 /* SCp.phase values */
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index d510839..bb870906b 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -80,7 +80,11 @@
 
 void aac_fib_map_free(struct aac_dev *dev)
 {
-	pci_free_consistent(dev->pdev, dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB), dev->hw_fib_va, dev->hw_fib_pa);
+	pci_free_consistent(dev->pdev,
+	  dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB),
+	  dev->hw_fib_va, dev->hw_fib_pa);
+	dev->hw_fib_va = NULL;
+	dev->hw_fib_pa = 0;
 }
 
 /**
@@ -1087,8 +1091,6 @@
 	 * case.
 	 */
 	aac_fib_map_free(aac);
-	aac->hw_fib_va = NULL;
-	aac->hw_fib_pa = 0;
 	pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
 	aac->comm_addr = NULL;
 	aac->comm_phys = 0;
@@ -1098,12 +1100,12 @@
 	kfree(aac->fsa_dev);
 	aac->fsa_dev = NULL;
 	if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT) {
-		if (((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK))) ||
-		  ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_32BIT_MASK))))
+		if (((retval = pci_set_dma_mask(aac->pdev, DMA_31BIT_MASK))) ||
+		  ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_31BIT_MASK))))
 			goto out;
 	} else {
-		if (((retval = pci_set_dma_mask(aac->pdev, 0x7FFFFFFFULL))) ||
-		  ((retval = pci_set_consistent_dma_mask(aac->pdev, 0x7FFFFFFFULL))))
+		if (((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK))) ||
+		  ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_32BIT_MASK))))
 			goto out;
 	}
 	if ((retval = (*(aac_get_driver_ident(index)->init))(aac)))
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index d76e1a8..a7f42a1 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -636,6 +636,8 @@
 static int aac_cfg_ioctl(struct inode *inode,  struct file *file,
 		unsigned int cmd, unsigned long arg)
 {
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
 	return aac_do_ioctl(file->private_data, cmd, (void __user *)arg);
 }
 
@@ -689,6 +691,8 @@
 
 static long aac_compat_cfg_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 {
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
 	return aac_compat_do_ioctl((struct aac_dev *)file->private_data, cmd, arg);
 }
 #endif
@@ -822,7 +826,7 @@
 	tmp = aac_adapter_check_health(dev);
 	if ((tmp == 0) && dev->in_reset)
 		tmp = -EBUSY;
-	len = snprintf(buf, PAGE_SIZE, "0x%x", tmp);
+	len = snprintf(buf, PAGE_SIZE, "0x%x\n", tmp);
 	return len;
 }
 
@@ -1106,7 +1110,9 @@
 	__aac_shutdown(aac);
  out_unmap:
 	aac_fib_map_free(aac);
-	pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
+	if (aac->comm_addr)
+		pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr,
+		  aac->comm_phys);
 	kfree(aac->queues);
 	aac_adapter_ioremap(aac, 0);
 	kfree(aac->fibs);
@@ -1122,9 +1128,8 @@
 static void aac_shutdown(struct pci_dev *dev)
 {
 	struct Scsi_Host *shost = pci_get_drvdata(dev);
-	struct aac_dev *aac = (struct aac_dev *)shost->hostdata;
 	scsi_block_requests(shost);
-	__aac_shutdown(aac);
+	__aac_shutdown((struct aac_dev *)shost->hostdata);
 }
 
 static void __devexit aac_remove_one(struct pci_dev *pdev)
diff --git a/drivers/scsi/aacraid/nark.c b/drivers/scsi/aacraid/nark.c
index a8ace56..c55f7c8 100644
--- a/drivers/scsi/aacraid/nark.c
+++ b/drivers/scsi/aacraid/nark.c
@@ -1,11 +1,10 @@
 /*
  *	Adaptec AAC series RAID controller driver
- *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
  *
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2006-2007 Adaptec, Inc. (aacraid@adaptec.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
diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c
index 9c5fcfb..8cd6588 100644
--- a/drivers/scsi/aacraid/rkt.c
+++ b/drivers/scsi/aacraid/rkt.c
@@ -5,7 +5,7 @@
  * based on the old aacraid driver that is..
  * Adaptec aacraid device driver for Linux.
  *
- * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.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
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index ebc65b9..73eef3dc 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -472,7 +472,7 @@
 		else {
 			bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS,
 			  0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL);
-			if (!bled && (var != 0x00000001))
+			if (!bled && (var != 0x00000001) && (var != 0x3803000F))
 				bled = -EINVAL;
 		}
 		if (bled && (bled != -ETIMEDOUT))
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 2b66897..79c0b6e 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -1,4 +1,4 @@
-#define ASC_VERSION "3.3K"    /* AdvanSys Driver Version */
+#define ASC_VERSION "3.3K"	/* AdvanSys Driver Version */
 
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
@@ -802,7 +802,6 @@
 #include <linux/pci.h>
 #endif /* CONFIG_PCI */
 
-
 /*
  * --- Driver Options
  */
@@ -816,18 +815,6 @@
 /* Enable driver tracing. */
 /* #define ADVANSYS_DEBUG */
 
-
-/*
- * --- Debugging Header
- */
-
-#ifdef ADVANSYS_DEBUG
-#define STATIC
-#else /* ADVANSYS_DEBUG */
-#define STATIC static
-#endif /* ADVANSYS_DEBUG */
-
-
 /*
  * --- Asc Library Constants and Macros
  */
@@ -845,10 +832,10 @@
  * are all consistent at 8, 16, and 32 bits respectively. Pointers
  * and long types are 64 bits on Alpha and UltraSPARC.
  */
-#define ASC_PADDR __u32         /* Physical/Bus address data type. */
-#define ASC_VADDR __u32         /* Virtual address data type. */
-#define ASC_DCNT  __u32         /* Unsigned Data count type. */
-#define ASC_SDCNT __s32         /* Signed Data count type. */
+#define ASC_PADDR __u32		/* Physical/Bus address data type. */
+#define ASC_VADDR __u32		/* Virtual address data type. */
+#define ASC_DCNT  __u32		/* Unsigned Data count type. */
+#define ASC_SDCNT __s32		/* Signed Data count type. */
 
 /*
  * These macros are used to convert a virtual address to a
@@ -911,7 +898,7 @@
 #define CC_VERY_LONG_SG_LIST 0
 #define ASC_SRB2SCSIQ(srb_ptr)  (srb_ptr)
 
-#define PortAddr                 unsigned short    /* port address size  */
+#define PortAddr                 unsigned short	/* port address size  */
 #define inp(port)                inb(port)
 #define outp(port, byte)         outb((byte), (port))
 
@@ -1038,17 +1025,17 @@
 #define ASC_INQ_CLOCKING(inq)       (((inq)->info & 0x0c) >> 2)
 
 typedef struct {
-    uchar               periph;
-    uchar               devtype;
-    uchar               ver;
-    uchar               byte3;
-    uchar               add_len;
-    uchar               res1;
-    uchar               res2;
-    uchar               flags;
-    uchar               vendor_id[8];
-    uchar               product_id[16];
-    uchar               product_rev_level[4];
+	uchar periph;
+	uchar devtype;
+	uchar ver;
+	uchar byte3;
+	uchar add_len;
+	uchar res1;
+	uchar res2;
+	uchar flags;
+	uchar vendor_id[8];
+	uchar product_id[16];
+	uchar product_rev_level[4];
 } ASC_SCSI_INQUIRY;
 
 #define ASC_SG_LIST_PER_Q   7
@@ -1165,139 +1152,139 @@
 #define ASC_QNO_TO_QADDR(q_no)      ((ASC_QADR_BEG)+((int)(q_no) << 6))
 
 typedef struct asc_scsiq_1 {
-    uchar               status;
-    uchar               q_no;
-    uchar               cntl;
-    uchar               sg_queue_cnt;
-    uchar               target_id;
-    uchar               target_lun;
-    ASC_PADDR           data_addr;
-    ASC_DCNT            data_cnt;
-    ASC_PADDR           sense_addr;
-    uchar               sense_len;
-    uchar               extra_bytes;
+	uchar status;
+	uchar q_no;
+	uchar cntl;
+	uchar sg_queue_cnt;
+	uchar target_id;
+	uchar target_lun;
+	ASC_PADDR data_addr;
+	ASC_DCNT data_cnt;
+	ASC_PADDR sense_addr;
+	uchar sense_len;
+	uchar extra_bytes;
 } ASC_SCSIQ_1;
 
 typedef struct asc_scsiq_2 {
-    ASC_VADDR           srb_ptr;
-    uchar               target_ix;
-    uchar               flag;
-    uchar               cdb_len;
-    uchar               tag_code;
-    ushort              vm_id;
+	ASC_VADDR srb_ptr;
+	uchar target_ix;
+	uchar flag;
+	uchar cdb_len;
+	uchar tag_code;
+	ushort vm_id;
 } ASC_SCSIQ_2;
 
 typedef struct asc_scsiq_3 {
-    uchar               done_stat;
-    uchar               host_stat;
-    uchar               scsi_stat;
-    uchar               scsi_msg;
+	uchar done_stat;
+	uchar host_stat;
+	uchar scsi_stat;
+	uchar scsi_msg;
 } ASC_SCSIQ_3;
 
 typedef struct asc_scsiq_4 {
-    uchar               cdb[ASC_MAX_CDB_LEN];
-    uchar               y_first_sg_list_qp;
-    uchar               y_working_sg_qp;
-    uchar               y_working_sg_ix;
-    uchar               y_res;
-    ushort              x_req_count;
-    ushort              x_reconnect_rtn;
-    ASC_PADDR           x_saved_data_addr;
-    ASC_DCNT            x_saved_data_cnt;
+	uchar cdb[ASC_MAX_CDB_LEN];
+	uchar y_first_sg_list_qp;
+	uchar y_working_sg_qp;
+	uchar y_working_sg_ix;
+	uchar y_res;
+	ushort x_req_count;
+	ushort x_reconnect_rtn;
+	ASC_PADDR x_saved_data_addr;
+	ASC_DCNT x_saved_data_cnt;
 } ASC_SCSIQ_4;
 
 typedef struct asc_q_done_info {
-    ASC_SCSIQ_2         d2;
-    ASC_SCSIQ_3         d3;
-    uchar               q_status;
-    uchar               q_no;
-    uchar               cntl;
-    uchar               sense_len;
-    uchar               extra_bytes;
-    uchar               res;
-    ASC_DCNT            remain_bytes;
+	ASC_SCSIQ_2 d2;
+	ASC_SCSIQ_3 d3;
+	uchar q_status;
+	uchar q_no;
+	uchar cntl;
+	uchar sense_len;
+	uchar extra_bytes;
+	uchar res;
+	ASC_DCNT remain_bytes;
 } ASC_QDONE_INFO;
 
 typedef struct asc_sg_list {
-    ASC_PADDR           addr;
-    ASC_DCNT            bytes;
+	ASC_PADDR addr;
+	ASC_DCNT bytes;
 } ASC_SG_LIST;
 
 typedef struct asc_sg_head {
-    ushort              entry_cnt;
-    ushort              queue_cnt;
-    ushort              entry_to_copy;
-    ushort              res;
-    ASC_SG_LIST         sg_list[ASC_MAX_SG_LIST];
+	ushort entry_cnt;
+	ushort queue_cnt;
+	ushort entry_to_copy;
+	ushort res;
+	ASC_SG_LIST sg_list[ASC_MAX_SG_LIST];
 } ASC_SG_HEAD;
 
 #define ASC_MIN_SG_LIST   2
 
 typedef struct asc_min_sg_head {
-    ushort              entry_cnt;
-    ushort              queue_cnt;
-    ushort              entry_to_copy;
-    ushort              res;
-    ASC_SG_LIST         sg_list[ASC_MIN_SG_LIST];
+	ushort entry_cnt;
+	ushort queue_cnt;
+	ushort entry_to_copy;
+	ushort res;
+	ASC_SG_LIST sg_list[ASC_MIN_SG_LIST];
 } ASC_MIN_SG_HEAD;
 
 #define QCX_SORT        (0x0001)
 #define QCX_COALEASE    (0x0002)
 
 typedef struct asc_scsi_q {
-    ASC_SCSIQ_1         q1;
-    ASC_SCSIQ_2         q2;
-    uchar               *cdbptr;
-    ASC_SG_HEAD         *sg_head;
-    ushort              remain_sg_entry_cnt;
-    ushort              next_sg_index;
+	ASC_SCSIQ_1 q1;
+	ASC_SCSIQ_2 q2;
+	uchar *cdbptr;
+	ASC_SG_HEAD *sg_head;
+	ushort remain_sg_entry_cnt;
+	ushort next_sg_index;
 } ASC_SCSI_Q;
 
 typedef struct asc_scsi_req_q {
-    ASC_SCSIQ_1         r1;
-    ASC_SCSIQ_2         r2;
-    uchar               *cdbptr;
-    ASC_SG_HEAD         *sg_head;
-    uchar               *sense_ptr;
-    ASC_SCSIQ_3         r3;
-    uchar               cdb[ASC_MAX_CDB_LEN];
-    uchar               sense[ASC_MIN_SENSE_LEN];
+	ASC_SCSIQ_1 r1;
+	ASC_SCSIQ_2 r2;
+	uchar *cdbptr;
+	ASC_SG_HEAD *sg_head;
+	uchar *sense_ptr;
+	ASC_SCSIQ_3 r3;
+	uchar cdb[ASC_MAX_CDB_LEN];
+	uchar sense[ASC_MIN_SENSE_LEN];
 } ASC_SCSI_REQ_Q;
 
 typedef struct asc_scsi_bios_req_q {
-    ASC_SCSIQ_1         r1;
-    ASC_SCSIQ_2         r2;
-    uchar               *cdbptr;
-    ASC_SG_HEAD         *sg_head;
-    uchar               *sense_ptr;
-    ASC_SCSIQ_3         r3;
-    uchar               cdb[ASC_MAX_CDB_LEN];
-    uchar               sense[ASC_MIN_SENSE_LEN];
+	ASC_SCSIQ_1 r1;
+	ASC_SCSIQ_2 r2;
+	uchar *cdbptr;
+	ASC_SG_HEAD *sg_head;
+	uchar *sense_ptr;
+	ASC_SCSIQ_3 r3;
+	uchar cdb[ASC_MAX_CDB_LEN];
+	uchar sense[ASC_MIN_SENSE_LEN];
 } ASC_SCSI_BIOS_REQ_Q;
 
 typedef struct asc_risc_q {
-    uchar               fwd;
-    uchar               bwd;
-    ASC_SCSIQ_1         i1;
-    ASC_SCSIQ_2         i2;
-    ASC_SCSIQ_3         i3;
-    ASC_SCSIQ_4         i4;
+	uchar fwd;
+	uchar bwd;
+	ASC_SCSIQ_1 i1;
+	ASC_SCSIQ_2 i2;
+	ASC_SCSIQ_3 i3;
+	ASC_SCSIQ_4 i4;
 } ASC_RISC_Q;
 
 typedef struct asc_sg_list_q {
-    uchar               seq_no;
-    uchar               q_no;
-    uchar               cntl;
-    uchar               sg_head_qp;
-    uchar               sg_list_cnt;
-    uchar               sg_cur_list_cnt;
+	uchar seq_no;
+	uchar q_no;
+	uchar cntl;
+	uchar sg_head_qp;
+	uchar sg_list_cnt;
+	uchar sg_cur_list_cnt;
 } ASC_SG_LIST_Q;
 
 typedef struct asc_risc_sg_list_q {
-    uchar               fwd;
-    uchar               bwd;
-    ASC_SG_LIST_Q       sg;
-    ASC_SG_LIST         sg_list[7];
+	uchar fwd;
+	uchar bwd;
+	ASC_SG_LIST_Q sg;
+	ASC_SG_LIST sg_list[7];
 } ASC_RISC_SG_LIST_Q;
 
 #define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP  0x1000000UL
@@ -1431,25 +1418,25 @@
 #define SYN_ULTRA_XFER_NS_15  107
 
 typedef struct ext_msg {
-    uchar               msg_type;
-    uchar               msg_len;
-    uchar               msg_req;
-    union {
-        struct {
-            uchar               sdtr_xfer_period;
-            uchar               sdtr_req_ack_offset;
-        } sdtr;
-        struct {
-            uchar               wdtr_width;
-        } wdtr;
-        struct {
-            uchar               mdp_b3;
-            uchar               mdp_b2;
-            uchar               mdp_b1;
-            uchar               mdp_b0;
-        } mdp;
-    } u_ext_msg;
-    uchar               res;
+	uchar msg_type;
+	uchar msg_len;
+	uchar msg_req;
+	union {
+		struct {
+			uchar sdtr_xfer_period;
+			uchar sdtr_req_ack_offset;
+		} sdtr;
+		struct {
+			uchar wdtr_width;
+		} wdtr;
+		struct {
+			uchar mdp_b3;
+			uchar mdp_b2;
+			uchar mdp_b1;
+			uchar mdp_b0;
+		} mdp;
+	} u_ext_msg;
+	uchar res;
 } EXT_MSG;
 
 #define xfer_period     u_ext_msg.sdtr.sdtr_xfer_period
@@ -1461,24 +1448,24 @@
 #define mdp_b0          u_ext_msg.mdp_b0
 
 typedef struct asc_dvc_cfg {
-    ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
-    ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
-    ASC_SCSI_BIT_ID_TYPE disc_enable;
-    ASC_SCSI_BIT_ID_TYPE sdtr_enable;
-    uchar               chip_scsi_id;
-    uchar               isa_dma_speed;
-    uchar               isa_dma_channel;
-    uchar               chip_version;
-    ushort              lib_serial_no;
-    ushort              lib_version;
-    ushort              mcode_date;
-    ushort              mcode_version;
-    uchar               max_tag_qng[ASC_MAX_TID + 1];
-    uchar               *overrun_buf;
-    uchar               sdtr_period_offset[ASC_MAX_TID + 1];
-    ushort              pci_slot_info;
-    uchar               adapter_info[6];
-    struct device	*dev;
+	ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
+	ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
+	ASC_SCSI_BIT_ID_TYPE disc_enable;
+	ASC_SCSI_BIT_ID_TYPE sdtr_enable;
+	uchar chip_scsi_id;
+	uchar isa_dma_speed;
+	uchar isa_dma_channel;
+	uchar chip_version;
+	ushort lib_serial_no;
+	ushort lib_version;
+	ushort mcode_date;
+	ushort mcode_version;
+	uchar max_tag_qng[ASC_MAX_TID + 1];
+	uchar *overrun_buf;
+	uchar sdtr_period_offset[ASC_MAX_TID + 1];
+	ushort pci_slot_info;
+	uchar adapter_info[6];
+	struct device *dev;
 } ASC_DVC_CFG;
 
 #define ASC_DEF_DVC_CNTL       0xFFFF
@@ -1501,64 +1488,64 @@
 #define ASC_MIN_TAGGED_CMD  7
 #define ASC_MAX_SCSI_RESET_WAIT      30
 
-struct asc_dvc_var;     /* Forward Declaration. */
+struct asc_dvc_var;		/* Forward Declaration. */
 
-typedef void (* ASC_ISR_CALLBACK)(struct asc_dvc_var *, ASC_QDONE_INFO *);
-typedef int (* ASC_EXE_CALLBACK)(struct asc_dvc_var *, ASC_SCSI_Q *);
+typedef void (*ASC_ISR_CALLBACK) (struct asc_dvc_var *, ASC_QDONE_INFO *);
+typedef int (*ASC_EXE_CALLBACK) (struct asc_dvc_var *, ASC_SCSI_Q *);
 
 typedef struct asc_dvc_var {
-    PortAddr            iop_base;
-    ushort              err_code;
-    ushort              dvc_cntl;
-    ushort              bug_fix_cntl;
-    ushort              bus_type;
-    ASC_ISR_CALLBACK    isr_callback;
-    ASC_EXE_CALLBACK    exe_callback;
-    ASC_SCSI_BIT_ID_TYPE init_sdtr;
-    ASC_SCSI_BIT_ID_TYPE sdtr_done;
-    ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
-    ASC_SCSI_BIT_ID_TYPE unit_not_ready;
-    ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
-    ASC_SCSI_BIT_ID_TYPE start_motor;
-    uchar               scsi_reset_wait;
-    uchar               chip_no;
-    char                is_in_int;
-    uchar               max_total_qng;
-    uchar               cur_total_qng;
-    uchar               in_critical_cnt;
-    uchar               irq_no;
-    uchar               last_q_shortage;
-    ushort              init_state;
-    uchar               cur_dvc_qng[ASC_MAX_TID + 1];
-    uchar               max_dvc_qng[ASC_MAX_TID + 1];
-    ASC_SCSI_Q  *scsiq_busy_head[ASC_MAX_TID + 1];
-    ASC_SCSI_Q  *scsiq_busy_tail[ASC_MAX_TID + 1];
-    uchar               sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
-    ASC_DVC_CFG *cfg;
-    ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
-    char                redo_scam;
-    ushort              res2;
-    uchar               dos_int13_table[ASC_MAX_TID + 1];
-    ASC_DCNT            max_dma_count;
-    ASC_SCSI_BIT_ID_TYPE no_scam;
-    ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
-    uchar               max_sdtr_index;
-    uchar               host_init_sdtr_index;
-    struct asc_board    *drv_ptr;
-    ASC_DCNT            uc_break;
+	PortAddr iop_base;
+	ushort err_code;
+	ushort dvc_cntl;
+	ushort bug_fix_cntl;
+	ushort bus_type;
+	ASC_ISR_CALLBACK isr_callback;
+	ASC_EXE_CALLBACK exe_callback;
+	ASC_SCSI_BIT_ID_TYPE init_sdtr;
+	ASC_SCSI_BIT_ID_TYPE sdtr_done;
+	ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
+	ASC_SCSI_BIT_ID_TYPE unit_not_ready;
+	ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
+	ASC_SCSI_BIT_ID_TYPE start_motor;
+	uchar scsi_reset_wait;
+	uchar chip_no;
+	char is_in_int;
+	uchar max_total_qng;
+	uchar cur_total_qng;
+	uchar in_critical_cnt;
+	uchar irq_no;
+	uchar last_q_shortage;
+	ushort init_state;
+	uchar cur_dvc_qng[ASC_MAX_TID + 1];
+	uchar max_dvc_qng[ASC_MAX_TID + 1];
+	ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1];
+	ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1];
+	uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
+	ASC_DVC_CFG *cfg;
+	ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
+	char redo_scam;
+	ushort res2;
+	uchar dos_int13_table[ASC_MAX_TID + 1];
+	ASC_DCNT max_dma_count;
+	ASC_SCSI_BIT_ID_TYPE no_scam;
+	ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
+	uchar max_sdtr_index;
+	uchar host_init_sdtr_index;
+	struct asc_board *drv_ptr;
+	ASC_DCNT uc_break;
 } ASC_DVC_VAR;
 
 typedef struct asc_dvc_inq_info {
-    uchar               type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
+	uchar type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
 } ASC_DVC_INQ_INFO;
 
 typedef struct asc_cap_info {
-    ASC_DCNT            lba;
-    ASC_DCNT            blk_size;
+	ASC_DCNT lba;
+	ASC_DCNT blk_size;
 } ASC_CAP_INFO;
 
 typedef struct asc_cap_info_array {
-    ASC_CAP_INFO        cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
+	ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
 } ASC_CAP_INFO_ARRAY;
 
 #define ASC_MCNTL_NO_SEL_TIMEOUT  (ushort)0x0001
@@ -1603,23 +1590,23 @@
    ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4)
 
 typedef struct asceep_config {
-    ushort              cfg_lsw;
-    ushort              cfg_msw;
-    uchar               init_sdtr;
-    uchar               disc_enable;
-    uchar               use_cmd_qng;
-    uchar               start_motor;
-    uchar               max_total_qng;
-    uchar               max_tag_qng;
-    uchar               bios_scan;
-    uchar               power_up_wait;
-    uchar               no_scam;
-    uchar               id_speed; /* low order 4 bits is chip scsi id */
-                                  /* high order 4 bits is isa dma speed */
-    uchar               dos_int13_table[ASC_MAX_TID + 1];
-    uchar               adapter_info[6];
-    ushort              cntl;
-    ushort              chksum;
+	ushort cfg_lsw;
+	ushort cfg_msw;
+	uchar init_sdtr;
+	uchar disc_enable;
+	uchar use_cmd_qng;
+	uchar start_motor;
+	uchar max_total_qng;
+	uchar max_tag_qng;
+	uchar bios_scan;
+	uchar power_up_wait;
+	uchar no_scam;
+	uchar id_speed;		/* low order 4 bits is chip scsi id */
+	/* high order 4 bits is isa dma speed */
+	uchar dos_int13_table[ASC_MAX_TID + 1];
+	uchar adapter_info[6];
+	ushort cntl;
+	ushort chksum;
 } ASCEEP_CONFIG;
 
 #define ASC_PCI_CFG_LSW_SCSI_PARITY  0x0800
@@ -1827,8 +1814,8 @@
 #define ASC_MC_SAVE_DATA_WSIZE  0x40
 
 typedef struct asc_mc_saved {
-    ushort              data[ASC_MC_SAVE_DATA_WSIZE];
-    ushort              code[ASC_MC_SAVE_CODE_WSIZE];
+	ushort data[ASC_MC_SAVE_DATA_WSIZE];
+	ushort code[ASC_MC_SAVE_CODE_WSIZE];
 } ASC_MC_SAVED;
 
 #define AscGetQDoneInProgress(port)         AscReadLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B)
@@ -1900,120 +1887,113 @@
 #define AscReadChipDvcID(port)            (uchar)inp((port)+IOP_REG_ID)
 #define AscWriteChipDvcID(port, data)     outp((port)+IOP_REG_ID, data)
 
-STATIC int       AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
-STATIC int       AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
-STATIC void      AscWaitEEPRead(void);
-STATIC void      AscWaitEEPWrite(void);
-STATIC ushort    AscReadEEPWord(PortAddr, uchar);
-STATIC ushort    AscWriteEEPWord(PortAddr, uchar, ushort);
-STATIC ushort    AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
-STATIC int       AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
-STATIC int       AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
-STATIC int       AscStartChip(PortAddr);
-STATIC int       AscStopChip(PortAddr);
-STATIC void      AscSetChipIH(PortAddr, ushort);
-STATIC int       AscIsChipHalted(PortAddr);
-STATIC void      AscAckInterrupt(PortAddr);
-STATIC void      AscDisableInterrupt(PortAddr);
-STATIC void      AscEnableInterrupt(PortAddr);
-STATIC void      AscSetBank(PortAddr, uchar);
-STATIC int       AscResetChipAndScsiBus(ASC_DVC_VAR *);
+static int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
+static int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
+static void AscWaitEEPRead(void);
+static void AscWaitEEPWrite(void);
+static ushort AscReadEEPWord(PortAddr, uchar);
+static ushort AscWriteEEPWord(PortAddr, uchar, ushort);
+static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
+static int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
+static int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
+static int AscStartChip(PortAddr);
+static int AscStopChip(PortAddr);
+static void AscSetChipIH(PortAddr, ushort);
+static int AscIsChipHalted(PortAddr);
+static void AscAckInterrupt(PortAddr);
+static void AscDisableInterrupt(PortAddr);
+static void AscEnableInterrupt(PortAddr);
+static void AscSetBank(PortAddr, uchar);
+static int AscResetChipAndScsiBus(ASC_DVC_VAR *);
 #ifdef CONFIG_ISA
-STATIC ushort    AscGetIsaDmaChannel(PortAddr);
-STATIC ushort    AscSetIsaDmaChannel(PortAddr, ushort);
-STATIC uchar     AscSetIsaDmaSpeed(PortAddr, uchar);
-STATIC uchar     AscGetIsaDmaSpeed(PortAddr);
+static ushort AscGetIsaDmaChannel(PortAddr);
+static ushort AscSetIsaDmaChannel(PortAddr, ushort);
+static uchar AscSetIsaDmaSpeed(PortAddr, uchar);
+static uchar AscGetIsaDmaSpeed(PortAddr);
 #endif /* CONFIG_ISA */
-STATIC uchar     AscReadLramByte(PortAddr, ushort);
-STATIC ushort    AscReadLramWord(PortAddr, ushort);
+static uchar AscReadLramByte(PortAddr, ushort);
+static ushort AscReadLramWord(PortAddr, ushort);
 #if CC_VERY_LONG_SG_LIST
-STATIC ASC_DCNT  AscReadLramDWord(PortAddr, ushort);
+static ASC_DCNT AscReadLramDWord(PortAddr, ushort);
 #endif /* CC_VERY_LONG_SG_LIST */
-STATIC void      AscWriteLramWord(PortAddr, ushort, ushort);
-STATIC void      AscWriteLramByte(PortAddr, ushort, uchar);
-STATIC ASC_DCNT  AscMemSumLramWord(PortAddr, ushort, int);
-STATIC void      AscMemWordSetLram(PortAddr, ushort, ushort, int);
-STATIC void      AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
-STATIC void      AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
-STATIC void      AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
-STATIC ushort    AscInitAscDvcVar(ASC_DVC_VAR *);
-STATIC ushort    AscInitFromEEP(ASC_DVC_VAR *);
-STATIC ushort    AscInitFromAscDvcVar(ASC_DVC_VAR *);
-STATIC ushort    AscInitMicroCodeVar(ASC_DVC_VAR *);
-STATIC int       AscTestExternalLram(ASC_DVC_VAR *);
-STATIC uchar     AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
-STATIC uchar     AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
-STATIC void      AscSetChipSDTR(PortAddr, uchar, uchar);
-STATIC uchar     AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
-STATIC uchar     AscAllocFreeQueue(PortAddr, uchar);
-STATIC uchar     AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
-STATIC int       AscHostReqRiscHalt(PortAddr);
-STATIC int       AscStopQueueExe(PortAddr);
-STATIC int       AscSendScsiQueue(ASC_DVC_VAR *,
-                    ASC_SCSI_Q * scsiq,
-                    uchar n_q_required);
-STATIC int       AscPutReadyQueue(ASC_DVC_VAR *,
-                    ASC_SCSI_Q *, uchar);
-STATIC int       AscPutReadySgListQueue(ASC_DVC_VAR *,
-                    ASC_SCSI_Q *, uchar);
-STATIC int       AscSetChipSynRegAtID(PortAddr, uchar, uchar);
-STATIC int       AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
-STATIC ushort    AscInitLram(ASC_DVC_VAR *);
-STATIC ushort    AscInitQLinkVar(ASC_DVC_VAR *);
-STATIC int       AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
-STATIC int       AscIsrChipHalted(ASC_DVC_VAR *);
-STATIC uchar     _AscCopyLramScsiDoneQ(PortAddr, ushort,
-                    ASC_QDONE_INFO *, ASC_DCNT);
-STATIC int       AscIsrQDone(ASC_DVC_VAR *);
-STATIC int       AscCompareString(uchar *, uchar *, int);
+static void AscWriteLramWord(PortAddr, ushort, ushort);
+static void AscWriteLramByte(PortAddr, ushort, uchar);
+static ASC_DCNT AscMemSumLramWord(PortAddr, ushort, int);
+static void AscMemWordSetLram(PortAddr, ushort, ushort, int);
+static void AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
+static void AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
+static void AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
+static ushort AscInitAscDvcVar(ASC_DVC_VAR *);
+static ushort AscInitFromEEP(ASC_DVC_VAR *);
+static ushort AscInitFromAscDvcVar(ASC_DVC_VAR *);
+static ushort AscInitMicroCodeVar(ASC_DVC_VAR *);
+static int AscTestExternalLram(ASC_DVC_VAR *);
+static uchar AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
+static uchar AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
+static void AscSetChipSDTR(PortAddr, uchar, uchar);
+static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
+static uchar AscAllocFreeQueue(PortAddr, uchar);
+static uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
+static int AscHostReqRiscHalt(PortAddr);
+static int AscStopQueueExe(PortAddr);
+static int AscSendScsiQueue(ASC_DVC_VAR *,
+			    ASC_SCSI_Q *scsiq, uchar n_q_required);
+static int AscPutReadyQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
+static int AscPutReadySgListQueue(ASC_DVC_VAR *, ASC_SCSI_Q *, uchar);
+static int AscSetChipSynRegAtID(PortAddr, uchar, uchar);
+static int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
+static ushort AscInitLram(ASC_DVC_VAR *);
+static ushort AscInitQLinkVar(ASC_DVC_VAR *);
+static int AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
+static int AscIsrChipHalted(ASC_DVC_VAR *);
+static uchar _AscCopyLramScsiDoneQ(PortAddr, ushort,
+				   ASC_QDONE_INFO *, ASC_DCNT);
+static int AscIsrQDone(ASC_DVC_VAR *);
+static int AscCompareString(uchar *, uchar *, int);
 #ifdef CONFIG_ISA
-STATIC ushort    AscGetEisaChipCfg(PortAddr);
-STATIC ASC_DCNT  AscGetEisaProductID(PortAddr);
-STATIC PortAddr  AscSearchIOPortAddrEISA(PortAddr);
-STATIC PortAddr  AscSearchIOPortAddr11(PortAddr);
-STATIC PortAddr  AscSearchIOPortAddr(PortAddr, ushort);
-STATIC void      AscSetISAPNPWaitForKey(void);
+static ushort AscGetEisaChipCfg(PortAddr);
+static ASC_DCNT AscGetEisaProductID(PortAddr);
+static PortAddr AscSearchIOPortAddrEISA(PortAddr);
+static PortAddr AscSearchIOPortAddr11(PortAddr);
+static PortAddr AscSearchIOPortAddr(PortAddr, ushort);
+static void AscSetISAPNPWaitForKey(void);
 #endif /* CONFIG_ISA */
-STATIC uchar     AscGetChipScsiCtrl(PortAddr);
-STATIC uchar     AscSetChipScsiID(PortAddr, uchar);
-STATIC uchar     AscGetChipVersion(PortAddr, ushort);
-STATIC ushort    AscGetChipBusType(PortAddr);
-STATIC ASC_DCNT  AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
-STATIC int       AscFindSignature(PortAddr);
-STATIC void      AscToggleIRQAct(PortAddr);
-STATIC uchar     AscGetChipIRQ(PortAddr, ushort);
-STATIC uchar     AscSetChipIRQ(PortAddr, uchar, ushort);
-STATIC ushort    AscGetChipBiosAddress(PortAddr, ushort);
-STATIC inline ulong DvcEnterCritical(void);
-STATIC inline void DvcLeaveCritical(ulong);
+static uchar AscGetChipScsiCtrl(PortAddr);
+static uchar AscSetChipScsiID(PortAddr, uchar);
+static uchar AscGetChipVersion(PortAddr, ushort);
+static ushort AscGetChipBusType(PortAddr);
+static ASC_DCNT AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
+static int AscFindSignature(PortAddr);
+static void AscToggleIRQAct(PortAddr);
+static uchar AscGetChipIRQ(PortAddr, ushort);
+static uchar AscSetChipIRQ(PortAddr, uchar, ushort);
+static ushort AscGetChipBiosAddress(PortAddr, ushort);
+static inline ulong DvcEnterCritical(void);
+static inline void DvcLeaveCritical(ulong);
 #ifdef CONFIG_PCI
-STATIC uchar     DvcReadPCIConfigByte(ASC_DVC_VAR *, ushort);
-STATIC void      DvcWritePCIConfigByte(ASC_DVC_VAR *,
-                    ushort, uchar);
+static uchar DvcReadPCIConfigByte(ASC_DVC_VAR *, ushort);
+static void DvcWritePCIConfigByte(ASC_DVC_VAR *, ushort, uchar);
 #endif /* CONFIG_PCI */
-STATIC ushort      AscGetChipBiosAddress(PortAddr, ushort);
-STATIC void      DvcSleepMilliSecond(ASC_DCNT);
-STATIC void      DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
-STATIC void      DvcPutScsiQ(PortAddr, ushort, uchar *, int);
-STATIC void      DvcGetQinfo(PortAddr, ushort, uchar *, int);
-STATIC ushort    AscInitGetConfig(ASC_DVC_VAR *);
-STATIC ushort    AscInitSetConfig(ASC_DVC_VAR *);
-STATIC ushort    AscInitAsc1000Driver(ASC_DVC_VAR *);
-STATIC void      AscAsyncFix(ASC_DVC_VAR *, uchar,
-                    ASC_SCSI_INQUIRY *);
-STATIC int       AscTagQueuingSafe(ASC_SCSI_INQUIRY *);
-STATIC void      AscInquiryHandling(ASC_DVC_VAR *,
-                    uchar, ASC_SCSI_INQUIRY *);
-STATIC int       AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
-STATIC int       AscISR(ASC_DVC_VAR *);
-STATIC uint      AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar,
-                    uchar);
-STATIC int       AscSgListToQueue(int);
+static ushort AscGetChipBiosAddress(PortAddr, ushort);
+static void DvcSleepMilliSecond(ASC_DCNT);
+static void DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
+static void DvcPutScsiQ(PortAddr, ushort, uchar *, int);
+static void DvcGetQinfo(PortAddr, ushort, uchar *, int);
+static ushort AscInitGetConfig(ASC_DVC_VAR *);
+static ushort AscInitSetConfig(ASC_DVC_VAR *);
+static ushort AscInitAsc1000Driver(ASC_DVC_VAR *);
+static void AscAsyncFix(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
+static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *);
+static void AscInquiryHandling(ASC_DVC_VAR *, uchar, ASC_SCSI_INQUIRY *);
+static int AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
+static int AscISR(ASC_DVC_VAR *);
+static uint AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar, uchar);
+static int AscSgListToQueue(int);
 #ifdef CONFIG_ISA
-STATIC void      AscEnableIsaDma(uchar);
+static void AscEnableIsaDma(uchar);
 #endif /* CONFIG_ISA */
-STATIC ASC_DCNT  AscGetMaxDmaCount(ushort);
-static const char *advansys_info(struct Scsi_Host *shp);
+static ASC_DCNT AscGetMaxDmaCount(ushort);
+static const char *advansys_info(struct Scsi_Host *shost);
 
 /*
  * --- Adv Library Constants and Macros
@@ -2035,10 +2015,10 @@
  * are all consistent at 8, 16, and 32 bits respectively. Pointers
  * and long types are 64 bits on Alpha and UltraSPARC.
  */
-#define ADV_PADDR __u32         /* Physical address data type. */
-#define ADV_VADDR __u32         /* Virtual address data type. */
-#define ADV_DCNT  __u32         /* Unsigned Data count type. */
-#define ADV_SDCNT __s32         /* Signed Data count type. */
+#define ADV_PADDR __u32		/* Physical address data type. */
+#define ADV_VADDR __u32		/* Virtual address data type. */
+#define ADV_DCNT  __u32		/* Unsigned Data count type. */
+#define ADV_SDCNT __s32		/* Signed Data count type. */
 
 /*
  * These macros are used to convert a virtual address to a
@@ -2051,7 +2031,7 @@
 #define ADV_VADDR_TO_U32   virt_to_bus
 #define ADV_U32_TO_VADDR   bus_to_virt
 
-#define AdvPortAddr  void __iomem *     /* Virtual memory address size */
+#define AdvPortAddr  void __iomem *	/* Virtual memory address size */
 
 /*
  * Define Adv Library required memory access macros.
@@ -2103,20 +2083,20 @@
 
 #define ADV_EEP_DVC_CFG_BEGIN           (0x00)
 #define ADV_EEP_DVC_CFG_END             (0x15)
-#define ADV_EEP_DVC_CTL_BEGIN           (0x16)  /* location of OEM name */
+#define ADV_EEP_DVC_CTL_BEGIN           (0x16)	/* location of OEM name */
 #define ADV_EEP_MAX_WORD_ADDR           (0x1E)
 
 #define ADV_EEP_DELAY_MS                100
 
-#define ADV_EEPROM_BIG_ENDIAN          0x8000   /* EEPROM Bit 15 */
-#define ADV_EEPROM_BIOS_ENABLE         0x4000   /* EEPROM Bit 14 */
+#define ADV_EEPROM_BIG_ENDIAN          0x8000	/* EEPROM Bit 15 */
+#define ADV_EEPROM_BIOS_ENABLE         0x4000	/* EEPROM Bit 14 */
 /*
  * For the ASC3550 Bit 13 is Termination Polarity control bit.
  * For later ICs Bit 13 controls whether the CIS (Card Information
  * Service Section) is loaded from EEPROM.
  */
-#define ADV_EEPROM_TERM_POL            0x2000   /* EEPROM Bit 13 */
-#define ADV_EEPROM_CIS_LD              0x2000   /* EEPROM Bit 13 */
+#define ADV_EEPROM_TERM_POL            0x2000	/* EEPROM Bit 13 */
+#define ADV_EEPROM_CIS_LD              0x2000	/* EEPROM Bit 13 */
 /*
  * ASC38C1600 Bit 11
  *
@@ -2128,280 +2108,277 @@
  * INT B in the PCI Configuration Space Int Pin field. If it is 1, then
  * Function 1 will specify INT A.
  */
-#define ADV_EEPROM_INTAB               0x0800   /* EEPROM Bit 11 */
+#define ADV_EEPROM_INTAB               0x0800	/* EEPROM Bit 11 */
 
-typedef struct adveep_3550_config
-{
-                                /* Word Offset, Description */
+typedef struct adveep_3550_config {
+	/* Word Offset, Description */
 
-  ushort cfg_lsw;               /* 00 power up initialization */
-                                /*  bit 13 set - Term Polarity Control */
-                                /*  bit 14 set - BIOS Enable */
-                                /*  bit 15 set - Big Endian Mode */
-  ushort cfg_msw;               /* 01 unused      */
-  ushort disc_enable;           /* 02 disconnect enable */
-  ushort wdtr_able;             /* 03 Wide DTR able */
-  ushort sdtr_able;             /* 04 Synchronous DTR able */
-  ushort start_motor;           /* 05 send start up motor */
-  ushort tagqng_able;           /* 06 tag queuing able */
-  ushort bios_scan;             /* 07 BIOS device control */
-  ushort scam_tolerant;         /* 08 no scam */
+	ushort cfg_lsw;		/* 00 power up initialization */
+	/*  bit 13 set - Term Polarity Control */
+	/*  bit 14 set - BIOS Enable */
+	/*  bit 15 set - Big Endian Mode */
+	ushort cfg_msw;		/* 01 unused      */
+	ushort disc_enable;	/* 02 disconnect enable */
+	ushort wdtr_able;	/* 03 Wide DTR able */
+	ushort sdtr_able;	/* 04 Synchronous DTR able */
+	ushort start_motor;	/* 05 send start up motor */
+	ushort tagqng_able;	/* 06 tag queuing able */
+	ushort bios_scan;	/* 07 BIOS device control */
+	ushort scam_tolerant;	/* 08 no scam */
 
-  uchar  adapter_scsi_id;       /* 09 Host Adapter ID */
-  uchar  bios_boot_delay;       /*    power up wait */
+	uchar adapter_scsi_id;	/* 09 Host Adapter ID */
+	uchar bios_boot_delay;	/*    power up wait */
 
-  uchar  scsi_reset_delay;      /* 10 reset delay */
-  uchar  bios_id_lun;           /*    first boot device scsi id & lun */
-                                /*    high nibble is lun */
-                                /*    low nibble is scsi id */
+	uchar scsi_reset_delay;	/* 10 reset delay */
+	uchar bios_id_lun;	/*    first boot device scsi id & lun */
+	/*    high nibble is lun */
+	/*    low nibble is scsi id */
 
-  uchar  termination;           /* 11 0 - automatic */
-                                /*    1 - low off / high off */
-                                /*    2 - low off / high on */
-                                /*    3 - low on  / high on */
-                                /*    There is no low on  / high off */
+	uchar termination;	/* 11 0 - automatic */
+	/*    1 - low off / high off */
+	/*    2 - low off / high on */
+	/*    3 - low on  / high on */
+	/*    There is no low on  / high off */
 
-  uchar  reserved1;             /*    reserved byte (not used) */
+	uchar reserved1;	/*    reserved byte (not used) */
 
-  ushort bios_ctrl;             /* 12 BIOS control bits */
-                                /*  bit 0  BIOS don't act as initiator. */
-                                /*  bit 1  BIOS > 1 GB support */
-                                /*  bit 2  BIOS > 2 Disk Support */
-                                /*  bit 3  BIOS don't support removables */
-                                /*  bit 4  BIOS support bootable CD */
-                                /*  bit 5  BIOS scan enabled */
-                                /*  bit 6  BIOS support multiple LUNs */
-                                /*  bit 7  BIOS display of message */
-                                /*  bit 8  SCAM disabled */
-                                /*  bit 9  Reset SCSI bus during init. */
-                                /*  bit 10 */
-                                /*  bit 11 No verbose initialization. */
-                                /*  bit 12 SCSI parity enabled */
-                                /*  bit 13 */
-                                /*  bit 14 */
-                                /*  bit 15 */
-  ushort  ultra_able;           /* 13 ULTRA speed able */
-  ushort  reserved2;            /* 14 reserved */
-  uchar   max_host_qng;         /* 15 maximum host queuing */
-  uchar   max_dvc_qng;          /*    maximum per device queuing */
-  ushort  dvc_cntl;             /* 16 control bit for driver */
-  ushort  bug_fix;              /* 17 control bit for bug fix */
-  ushort  serial_number_word1;  /* 18 Board serial number word 1 */
-  ushort  serial_number_word2;  /* 19 Board serial number word 2 */
-  ushort  serial_number_word3;  /* 20 Board serial number word 3 */
-  ushort  check_sum;            /* 21 EEP check sum */
-  uchar   oem_name[16];         /* 22 OEM name */
-  ushort  dvc_err_code;         /* 30 last device driver error code */
-  ushort  adv_err_code;         /* 31 last uc and Adv Lib error code */
-  ushort  adv_err_addr;         /* 32 last uc error address */
-  ushort  saved_dvc_err_code;   /* 33 saved last dev. driver error code   */
-  ushort  saved_adv_err_code;   /* 34 saved last uc and Adv Lib error code */
-  ushort  saved_adv_err_addr;   /* 35 saved last uc error address         */
-  ushort  num_of_err;           /* 36 number of error */
+	ushort bios_ctrl;	/* 12 BIOS control bits */
+	/*  bit 0  BIOS don't act as initiator. */
+	/*  bit 1  BIOS > 1 GB support */
+	/*  bit 2  BIOS > 2 Disk Support */
+	/*  bit 3  BIOS don't support removables */
+	/*  bit 4  BIOS support bootable CD */
+	/*  bit 5  BIOS scan enabled */
+	/*  bit 6  BIOS support multiple LUNs */
+	/*  bit 7  BIOS display of message */
+	/*  bit 8  SCAM disabled */
+	/*  bit 9  Reset SCSI bus during init. */
+	/*  bit 10 */
+	/*  bit 11 No verbose initialization. */
+	/*  bit 12 SCSI parity enabled */
+	/*  bit 13 */
+	/*  bit 14 */
+	/*  bit 15 */
+	ushort ultra_able;	/* 13 ULTRA speed able */
+	ushort reserved2;	/* 14 reserved */
+	uchar max_host_qng;	/* 15 maximum host queuing */
+	uchar max_dvc_qng;	/*    maximum per device queuing */
+	ushort dvc_cntl;	/* 16 control bit for driver */
+	ushort bug_fix;		/* 17 control bit for bug fix */
+	ushort serial_number_word1;	/* 18 Board serial number word 1 */
+	ushort serial_number_word2;	/* 19 Board serial number word 2 */
+	ushort serial_number_word3;	/* 20 Board serial number word 3 */
+	ushort check_sum;	/* 21 EEP check sum */
+	uchar oem_name[16];	/* 22 OEM name */
+	ushort dvc_err_code;	/* 30 last device driver error code */
+	ushort adv_err_code;	/* 31 last uc and Adv Lib error code */
+	ushort adv_err_addr;	/* 32 last uc error address */
+	ushort saved_dvc_err_code;	/* 33 saved last dev. driver error code   */
+	ushort saved_adv_err_code;	/* 34 saved last uc and Adv Lib error code */
+	ushort saved_adv_err_addr;	/* 35 saved last uc error address         */
+	ushort num_of_err;	/* 36 number of error */
 } ADVEEP_3550_CONFIG;
 
-typedef struct adveep_38C0800_config
-{
-                                /* Word Offset, Description */
+typedef struct adveep_38C0800_config {
+	/* Word Offset, Description */
 
-  ushort cfg_lsw;               /* 00 power up initialization */
-                                /*  bit 13 set - Load CIS */
-                                /*  bit 14 set - BIOS Enable */
-                                /*  bit 15 set - Big Endian Mode */
-  ushort cfg_msw;               /* 01 unused      */
-  ushort disc_enable;           /* 02 disconnect enable */
-  ushort wdtr_able;             /* 03 Wide DTR able */
-  ushort sdtr_speed1;           /* 04 SDTR Speed TID 0-3 */
-  ushort start_motor;           /* 05 send start up motor */
-  ushort tagqng_able;           /* 06 tag queuing able */
-  ushort bios_scan;             /* 07 BIOS device control */
-  ushort scam_tolerant;         /* 08 no scam */
+	ushort cfg_lsw;		/* 00 power up initialization */
+	/*  bit 13 set - Load CIS */
+	/*  bit 14 set - BIOS Enable */
+	/*  bit 15 set - Big Endian Mode */
+	ushort cfg_msw;		/* 01 unused      */
+	ushort disc_enable;	/* 02 disconnect enable */
+	ushort wdtr_able;	/* 03 Wide DTR able */
+	ushort sdtr_speed1;	/* 04 SDTR Speed TID 0-3 */
+	ushort start_motor;	/* 05 send start up motor */
+	ushort tagqng_able;	/* 06 tag queuing able */
+	ushort bios_scan;	/* 07 BIOS device control */
+	ushort scam_tolerant;	/* 08 no scam */
 
-  uchar  adapter_scsi_id;       /* 09 Host Adapter ID */
-  uchar  bios_boot_delay;       /*    power up wait */
+	uchar adapter_scsi_id;	/* 09 Host Adapter ID */
+	uchar bios_boot_delay;	/*    power up wait */
 
-  uchar  scsi_reset_delay;      /* 10 reset delay */
-  uchar  bios_id_lun;           /*    first boot device scsi id & lun */
-                                /*    high nibble is lun */
-                                /*    low nibble is scsi id */
+	uchar scsi_reset_delay;	/* 10 reset delay */
+	uchar bios_id_lun;	/*    first boot device scsi id & lun */
+	/*    high nibble is lun */
+	/*    low nibble is scsi id */
 
-  uchar  termination_se;        /* 11 0 - automatic */
-                                /*    1 - low off / high off */
-                                /*    2 - low off / high on */
-                                /*    3 - low on  / high on */
-                                /*    There is no low on  / high off */
+	uchar termination_se;	/* 11 0 - automatic */
+	/*    1 - low off / high off */
+	/*    2 - low off / high on */
+	/*    3 - low on  / high on */
+	/*    There is no low on  / high off */
 
-  uchar  termination_lvd;       /* 11 0 - automatic */
-                                /*    1 - low off / high off */
-                                /*    2 - low off / high on */
-                                /*    3 - low on  / high on */
-                                /*    There is no low on  / high off */
+	uchar termination_lvd;	/* 11 0 - automatic */
+	/*    1 - low off / high off */
+	/*    2 - low off / high on */
+	/*    3 - low on  / high on */
+	/*    There is no low on  / high off */
 
-  ushort bios_ctrl;             /* 12 BIOS control bits */
-                                /*  bit 0  BIOS don't act as initiator. */
-                                /*  bit 1  BIOS > 1 GB support */
-                                /*  bit 2  BIOS > 2 Disk Support */
-                                /*  bit 3  BIOS don't support removables */
-                                /*  bit 4  BIOS support bootable CD */
-                                /*  bit 5  BIOS scan enabled */
-                                /*  bit 6  BIOS support multiple LUNs */
-                                /*  bit 7  BIOS display of message */
-                                /*  bit 8  SCAM disabled */
-                                /*  bit 9  Reset SCSI bus during init. */
-                                /*  bit 10 */
-                                /*  bit 11 No verbose initialization. */
-                                /*  bit 12 SCSI parity enabled */
-                                /*  bit 13 */
-                                /*  bit 14 */
-                                /*  bit 15 */
-  ushort  sdtr_speed2;          /* 13 SDTR speed TID 4-7 */
-  ushort  sdtr_speed3;          /* 14 SDTR speed TID 8-11 */
-  uchar   max_host_qng;         /* 15 maximum host queueing */
-  uchar   max_dvc_qng;          /*    maximum per device queuing */
-  ushort  dvc_cntl;             /* 16 control bit for driver */
-  ushort  sdtr_speed4;          /* 17 SDTR speed 4 TID 12-15 */
-  ushort  serial_number_word1;  /* 18 Board serial number word 1 */
-  ushort  serial_number_word2;  /* 19 Board serial number word 2 */
-  ushort  serial_number_word3;  /* 20 Board serial number word 3 */
-  ushort  check_sum;            /* 21 EEP check sum */
-  uchar   oem_name[16];         /* 22 OEM name */
-  ushort  dvc_err_code;         /* 30 last device driver error code */
-  ushort  adv_err_code;         /* 31 last uc and Adv Lib error code */
-  ushort  adv_err_addr;         /* 32 last uc error address */
-  ushort  saved_dvc_err_code;   /* 33 saved last dev. driver error code   */
-  ushort  saved_adv_err_code;   /* 34 saved last uc and Adv Lib error code */
-  ushort  saved_adv_err_addr;   /* 35 saved last uc error address         */
-  ushort  reserved36;           /* 36 reserved */
-  ushort  reserved37;           /* 37 reserved */
-  ushort  reserved38;           /* 38 reserved */
-  ushort  reserved39;           /* 39 reserved */
-  ushort  reserved40;           /* 40 reserved */
-  ushort  reserved41;           /* 41 reserved */
-  ushort  reserved42;           /* 42 reserved */
-  ushort  reserved43;           /* 43 reserved */
-  ushort  reserved44;           /* 44 reserved */
-  ushort  reserved45;           /* 45 reserved */
-  ushort  reserved46;           /* 46 reserved */
-  ushort  reserved47;           /* 47 reserved */
-  ushort  reserved48;           /* 48 reserved */
-  ushort  reserved49;           /* 49 reserved */
-  ushort  reserved50;           /* 50 reserved */
-  ushort  reserved51;           /* 51 reserved */
-  ushort  reserved52;           /* 52 reserved */
-  ushort  reserved53;           /* 53 reserved */
-  ushort  reserved54;           /* 54 reserved */
-  ushort  reserved55;           /* 55 reserved */
-  ushort  cisptr_lsw;           /* 56 CIS PTR LSW */
-  ushort  cisprt_msw;           /* 57 CIS PTR MSW */
-  ushort  subsysvid;            /* 58 SubSystem Vendor ID */
-  ushort  subsysid;             /* 59 SubSystem ID */
-  ushort  reserved60;           /* 60 reserved */
-  ushort  reserved61;           /* 61 reserved */
-  ushort  reserved62;           /* 62 reserved */
-  ushort  reserved63;           /* 63 reserved */
+	ushort bios_ctrl;	/* 12 BIOS control bits */
+	/*  bit 0  BIOS don't act as initiator. */
+	/*  bit 1  BIOS > 1 GB support */
+	/*  bit 2  BIOS > 2 Disk Support */
+	/*  bit 3  BIOS don't support removables */
+	/*  bit 4  BIOS support bootable CD */
+	/*  bit 5  BIOS scan enabled */
+	/*  bit 6  BIOS support multiple LUNs */
+	/*  bit 7  BIOS display of message */
+	/*  bit 8  SCAM disabled */
+	/*  bit 9  Reset SCSI bus during init. */
+	/*  bit 10 */
+	/*  bit 11 No verbose initialization. */
+	/*  bit 12 SCSI parity enabled */
+	/*  bit 13 */
+	/*  bit 14 */
+	/*  bit 15 */
+	ushort sdtr_speed2;	/* 13 SDTR speed TID 4-7 */
+	ushort sdtr_speed3;	/* 14 SDTR speed TID 8-11 */
+	uchar max_host_qng;	/* 15 maximum host queueing */
+	uchar max_dvc_qng;	/*    maximum per device queuing */
+	ushort dvc_cntl;	/* 16 control bit for driver */
+	ushort sdtr_speed4;	/* 17 SDTR speed 4 TID 12-15 */
+	ushort serial_number_word1;	/* 18 Board serial number word 1 */
+	ushort serial_number_word2;	/* 19 Board serial number word 2 */
+	ushort serial_number_word3;	/* 20 Board serial number word 3 */
+	ushort check_sum;	/* 21 EEP check sum */
+	uchar oem_name[16];	/* 22 OEM name */
+	ushort dvc_err_code;	/* 30 last device driver error code */
+	ushort adv_err_code;	/* 31 last uc and Adv Lib error code */
+	ushort adv_err_addr;	/* 32 last uc error address */
+	ushort saved_dvc_err_code;	/* 33 saved last dev. driver error code   */
+	ushort saved_adv_err_code;	/* 34 saved last uc and Adv Lib error code */
+	ushort saved_adv_err_addr;	/* 35 saved last uc error address         */
+	ushort reserved36;	/* 36 reserved */
+	ushort reserved37;	/* 37 reserved */
+	ushort reserved38;	/* 38 reserved */
+	ushort reserved39;	/* 39 reserved */
+	ushort reserved40;	/* 40 reserved */
+	ushort reserved41;	/* 41 reserved */
+	ushort reserved42;	/* 42 reserved */
+	ushort reserved43;	/* 43 reserved */
+	ushort reserved44;	/* 44 reserved */
+	ushort reserved45;	/* 45 reserved */
+	ushort reserved46;	/* 46 reserved */
+	ushort reserved47;	/* 47 reserved */
+	ushort reserved48;	/* 48 reserved */
+	ushort reserved49;	/* 49 reserved */
+	ushort reserved50;	/* 50 reserved */
+	ushort reserved51;	/* 51 reserved */
+	ushort reserved52;	/* 52 reserved */
+	ushort reserved53;	/* 53 reserved */
+	ushort reserved54;	/* 54 reserved */
+	ushort reserved55;	/* 55 reserved */
+	ushort cisptr_lsw;	/* 56 CIS PTR LSW */
+	ushort cisprt_msw;	/* 57 CIS PTR MSW */
+	ushort subsysvid;	/* 58 SubSystem Vendor ID */
+	ushort subsysid;	/* 59 SubSystem ID */
+	ushort reserved60;	/* 60 reserved */
+	ushort reserved61;	/* 61 reserved */
+	ushort reserved62;	/* 62 reserved */
+	ushort reserved63;	/* 63 reserved */
 } ADVEEP_38C0800_CONFIG;
 
-typedef struct adveep_38C1600_config
-{
-                                /* Word Offset, Description */
+typedef struct adveep_38C1600_config {
+	/* Word Offset, Description */
 
-  ushort cfg_lsw;               /* 00 power up initialization */
-                                /*  bit 11 set - Func. 0 INTB, Func. 1 INTA */
-                                /*       clear - Func. 0 INTA, Func. 1 INTB */
-                                /*  bit 13 set - Load CIS */
-                                /*  bit 14 set - BIOS Enable */
-                                /*  bit 15 set - Big Endian Mode */
-  ushort cfg_msw;               /* 01 unused */
-  ushort disc_enable;           /* 02 disconnect enable */
-  ushort wdtr_able;             /* 03 Wide DTR able */
-  ushort sdtr_speed1;           /* 04 SDTR Speed TID 0-3 */
-  ushort start_motor;           /* 05 send start up motor */
-  ushort tagqng_able;           /* 06 tag queuing able */
-  ushort bios_scan;             /* 07 BIOS device control */
-  ushort scam_tolerant;         /* 08 no scam */
+	ushort cfg_lsw;		/* 00 power up initialization */
+	/*  bit 11 set - Func. 0 INTB, Func. 1 INTA */
+	/*       clear - Func. 0 INTA, Func. 1 INTB */
+	/*  bit 13 set - Load CIS */
+	/*  bit 14 set - BIOS Enable */
+	/*  bit 15 set - Big Endian Mode */
+	ushort cfg_msw;		/* 01 unused */
+	ushort disc_enable;	/* 02 disconnect enable */
+	ushort wdtr_able;	/* 03 Wide DTR able */
+	ushort sdtr_speed1;	/* 04 SDTR Speed TID 0-3 */
+	ushort start_motor;	/* 05 send start up motor */
+	ushort tagqng_able;	/* 06 tag queuing able */
+	ushort bios_scan;	/* 07 BIOS device control */
+	ushort scam_tolerant;	/* 08 no scam */
 
-  uchar  adapter_scsi_id;       /* 09 Host Adapter ID */
-  uchar  bios_boot_delay;       /*    power up wait */
+	uchar adapter_scsi_id;	/* 09 Host Adapter ID */
+	uchar bios_boot_delay;	/*    power up wait */
 
-  uchar  scsi_reset_delay;      /* 10 reset delay */
-  uchar  bios_id_lun;           /*    first boot device scsi id & lun */
-                                /*    high nibble is lun */
-                                /*    low nibble is scsi id */
+	uchar scsi_reset_delay;	/* 10 reset delay */
+	uchar bios_id_lun;	/*    first boot device scsi id & lun */
+	/*    high nibble is lun */
+	/*    low nibble is scsi id */
 
-  uchar  termination_se;        /* 11 0 - automatic */
-                                /*    1 - low off / high off */
-                                /*    2 - low off / high on */
-                                /*    3 - low on  / high on */
-                                /*    There is no low on  / high off */
+	uchar termination_se;	/* 11 0 - automatic */
+	/*    1 - low off / high off */
+	/*    2 - low off / high on */
+	/*    3 - low on  / high on */
+	/*    There is no low on  / high off */
 
-  uchar  termination_lvd;       /* 11 0 - automatic */
-                                /*    1 - low off / high off */
-                                /*    2 - low off / high on */
-                                /*    3 - low on  / high on */
-                                /*    There is no low on  / high off */
+	uchar termination_lvd;	/* 11 0 - automatic */
+	/*    1 - low off / high off */
+	/*    2 - low off / high on */
+	/*    3 - low on  / high on */
+	/*    There is no low on  / high off */
 
-  ushort bios_ctrl;             /* 12 BIOS control bits */
-                                /*  bit 0  BIOS don't act as initiator. */
-                                /*  bit 1  BIOS > 1 GB support */
-                                /*  bit 2  BIOS > 2 Disk Support */
-                                /*  bit 3  BIOS don't support removables */
-                                /*  bit 4  BIOS support bootable CD */
-                                /*  bit 5  BIOS scan enabled */
-                                /*  bit 6  BIOS support multiple LUNs */
-                                /*  bit 7  BIOS display of message */
-                                /*  bit 8  SCAM disabled */
-                                /*  bit 9  Reset SCSI bus during init. */
-                                /*  bit 10 Basic Integrity Checking disabled */
-                                /*  bit 11 No verbose initialization. */
-                                /*  bit 12 SCSI parity enabled */
-                                /*  bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
-                                /*  bit 14 */
-                                /*  bit 15 */
-  ushort  sdtr_speed2;          /* 13 SDTR speed TID 4-7 */
-  ushort  sdtr_speed3;          /* 14 SDTR speed TID 8-11 */
-  uchar   max_host_qng;         /* 15 maximum host queueing */
-  uchar   max_dvc_qng;          /*    maximum per device queuing */
-  ushort  dvc_cntl;             /* 16 control bit for driver */
-  ushort  sdtr_speed4;          /* 17 SDTR speed 4 TID 12-15 */
-  ushort  serial_number_word1;  /* 18 Board serial number word 1 */
-  ushort  serial_number_word2;  /* 19 Board serial number word 2 */
-  ushort  serial_number_word3;  /* 20 Board serial number word 3 */
-  ushort  check_sum;            /* 21 EEP check sum */
-  uchar   oem_name[16];         /* 22 OEM name */
-  ushort  dvc_err_code;         /* 30 last device driver error code */
-  ushort  adv_err_code;         /* 31 last uc and Adv Lib error code */
-  ushort  adv_err_addr;         /* 32 last uc error address */
-  ushort  saved_dvc_err_code;   /* 33 saved last dev. driver error code   */
-  ushort  saved_adv_err_code;   /* 34 saved last uc and Adv Lib error code */
-  ushort  saved_adv_err_addr;   /* 35 saved last uc error address         */
-  ushort  reserved36;           /* 36 reserved */
-  ushort  reserved37;           /* 37 reserved */
-  ushort  reserved38;           /* 38 reserved */
-  ushort  reserved39;           /* 39 reserved */
-  ushort  reserved40;           /* 40 reserved */
-  ushort  reserved41;           /* 41 reserved */
-  ushort  reserved42;           /* 42 reserved */
-  ushort  reserved43;           /* 43 reserved */
-  ushort  reserved44;           /* 44 reserved */
-  ushort  reserved45;           /* 45 reserved */
-  ushort  reserved46;           /* 46 reserved */
-  ushort  reserved47;           /* 47 reserved */
-  ushort  reserved48;           /* 48 reserved */
-  ushort  reserved49;           /* 49 reserved */
-  ushort  reserved50;           /* 50 reserved */
-  ushort  reserved51;           /* 51 reserved */
-  ushort  reserved52;           /* 52 reserved */
-  ushort  reserved53;           /* 53 reserved */
-  ushort  reserved54;           /* 54 reserved */
-  ushort  reserved55;           /* 55 reserved */
-  ushort  cisptr_lsw;           /* 56 CIS PTR LSW */
-  ushort  cisprt_msw;           /* 57 CIS PTR MSW */
-  ushort  subsysvid;            /* 58 SubSystem Vendor ID */
-  ushort  subsysid;             /* 59 SubSystem ID */
-  ushort  reserved60;           /* 60 reserved */
-  ushort  reserved61;           /* 61 reserved */
-  ushort  reserved62;           /* 62 reserved */
-  ushort  reserved63;           /* 63 reserved */
+	ushort bios_ctrl;	/* 12 BIOS control bits */
+	/*  bit 0  BIOS don't act as initiator. */
+	/*  bit 1  BIOS > 1 GB support */
+	/*  bit 2  BIOS > 2 Disk Support */
+	/*  bit 3  BIOS don't support removables */
+	/*  bit 4  BIOS support bootable CD */
+	/*  bit 5  BIOS scan enabled */
+	/*  bit 6  BIOS support multiple LUNs */
+	/*  bit 7  BIOS display of message */
+	/*  bit 8  SCAM disabled */
+	/*  bit 9  Reset SCSI bus during init. */
+	/*  bit 10 Basic Integrity Checking disabled */
+	/*  bit 11 No verbose initialization. */
+	/*  bit 12 SCSI parity enabled */
+	/*  bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
+	/*  bit 14 */
+	/*  bit 15 */
+	ushort sdtr_speed2;	/* 13 SDTR speed TID 4-7 */
+	ushort sdtr_speed3;	/* 14 SDTR speed TID 8-11 */
+	uchar max_host_qng;	/* 15 maximum host queueing */
+	uchar max_dvc_qng;	/*    maximum per device queuing */
+	ushort dvc_cntl;	/* 16 control bit for driver */
+	ushort sdtr_speed4;	/* 17 SDTR speed 4 TID 12-15 */
+	ushort serial_number_word1;	/* 18 Board serial number word 1 */
+	ushort serial_number_word2;	/* 19 Board serial number word 2 */
+	ushort serial_number_word3;	/* 20 Board serial number word 3 */
+	ushort check_sum;	/* 21 EEP check sum */
+	uchar oem_name[16];	/* 22 OEM name */
+	ushort dvc_err_code;	/* 30 last device driver error code */
+	ushort adv_err_code;	/* 31 last uc and Adv Lib error code */
+	ushort adv_err_addr;	/* 32 last uc error address */
+	ushort saved_dvc_err_code;	/* 33 saved last dev. driver error code   */
+	ushort saved_adv_err_code;	/* 34 saved last uc and Adv Lib error code */
+	ushort saved_adv_err_addr;	/* 35 saved last uc error address         */
+	ushort reserved36;	/* 36 reserved */
+	ushort reserved37;	/* 37 reserved */
+	ushort reserved38;	/* 38 reserved */
+	ushort reserved39;	/* 39 reserved */
+	ushort reserved40;	/* 40 reserved */
+	ushort reserved41;	/* 41 reserved */
+	ushort reserved42;	/* 42 reserved */
+	ushort reserved43;	/* 43 reserved */
+	ushort reserved44;	/* 44 reserved */
+	ushort reserved45;	/* 45 reserved */
+	ushort reserved46;	/* 46 reserved */
+	ushort reserved47;	/* 47 reserved */
+	ushort reserved48;	/* 48 reserved */
+	ushort reserved49;	/* 49 reserved */
+	ushort reserved50;	/* 50 reserved */
+	ushort reserved51;	/* 51 reserved */
+	ushort reserved52;	/* 52 reserved */
+	ushort reserved53;	/* 53 reserved */
+	ushort reserved54;	/* 54 reserved */
+	ushort reserved55;	/* 55 reserved */
+	ushort cisptr_lsw;	/* 56 CIS PTR LSW */
+	ushort cisprt_msw;	/* 57 CIS PTR MSW */
+	ushort subsysvid;	/* 58 SubSystem Vendor ID */
+	ushort subsysid;	/* 59 SubSystem ID */
+	ushort reserved60;	/* 60 reserved */
+	ushort reserved61;	/* 61 reserved */
+	ushort reserved62;	/* 62 reserved */
+	ushort reserved63;	/* 63 reserved */
 } ADVEEP_38C1600_CONFIG;
 
 /*
@@ -2427,11 +2404,11 @@
 #define BIOS_CTRL_SCSI_PARITY        0x1000
 #define BIOS_CTRL_AIPP_DIS           0x2000
 
-#define ADV_3550_MEMSIZE   0x2000       /* 8 KB Internal Memory */
-#define ADV_3550_IOLEN     0x40         /* I/O Port Range in bytes */
+#define ADV_3550_MEMSIZE   0x2000	/* 8 KB Internal Memory */
+#define ADV_3550_IOLEN     0x40	/* I/O Port Range in bytes */
 
-#define ADV_38C0800_MEMSIZE  0x4000     /* 16 KB Internal Memory */
-#define ADV_38C0800_IOLEN    0x100      /* I/O Port Range in bytes */
+#define ADV_38C0800_MEMSIZE  0x4000	/* 16 KB Internal Memory */
+#define ADV_38C0800_IOLEN    0x100	/* I/O Port Range in bytes */
 
 /*
  * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
@@ -2440,9 +2417,9 @@
  *
  * #define ADV_38C1600_MEMSIZE  0x8000L   * 32 KB Internal Memory *
  */
-#define ADV_38C1600_MEMSIZE  0x4000   /* 16 KB Internal Memory */
-#define ADV_38C1600_IOLEN    0x100     /* I/O Port Range 256 bytes */
-#define ADV_38C1600_MEMLEN   0x1000    /* Memory Range 4KB bytes */
+#define ADV_38C1600_MEMSIZE  0x4000	/* 16 KB Internal Memory */
+#define ADV_38C1600_IOLEN    0x100	/* I/O Port Range 256 bytes */
+#define ADV_38C1600_MEMLEN   0x1000	/* Memory Range 4KB bytes */
 
 /*
  * Byte I/O register address from base of 'iop_base'.
@@ -2515,39 +2492,39 @@
 /*
  * Word I/O register address from base of 'iop_base'.
  */
-#define IOPW_CHIP_ID_0          0x00  /* CID0  */
-#define IOPW_CTRL_REG           0x02  /* CC    */
-#define IOPW_RAM_ADDR           0x04  /* LA    */
-#define IOPW_RAM_DATA           0x06  /* LD    */
+#define IOPW_CHIP_ID_0          0x00	/* CID0  */
+#define IOPW_CTRL_REG           0x02	/* CC    */
+#define IOPW_RAM_ADDR           0x04	/* LA    */
+#define IOPW_RAM_DATA           0x06	/* LD    */
 #define IOPW_RES_ADDR_08        0x08
-#define IOPW_RISC_CSR           0x0A  /* CSR   */
-#define IOPW_SCSI_CFG0          0x0C  /* CFG0  */
-#define IOPW_SCSI_CFG1          0x0E  /* CFG1  */
+#define IOPW_RISC_CSR           0x0A	/* CSR   */
+#define IOPW_SCSI_CFG0          0x0C	/* CFG0  */
+#define IOPW_SCSI_CFG1          0x0E	/* CFG1  */
 #define IOPW_RES_ADDR_10        0x10
-#define IOPW_SEL_MASK           0x12  /* SM    */
+#define IOPW_SEL_MASK           0x12	/* SM    */
 #define IOPW_RES_ADDR_14        0x14
-#define IOPW_FLASH_ADDR         0x16  /* FA    */
+#define IOPW_FLASH_ADDR         0x16	/* FA    */
 #define IOPW_RES_ADDR_18        0x18
-#define IOPW_EE_CMD             0x1A  /* EC    */
-#define IOPW_EE_DATA            0x1C  /* ED    */
-#define IOPW_SFIFO_CNT          0x1E  /* SFC   */
+#define IOPW_EE_CMD             0x1A	/* EC    */
+#define IOPW_EE_DATA            0x1C	/* ED    */
+#define IOPW_SFIFO_CNT          0x1E	/* SFC   */
 #define IOPW_RES_ADDR_20        0x20
-#define IOPW_Q_BASE             0x22  /* QB    */
-#define IOPW_QP                 0x24  /* QP    */
-#define IOPW_IX                 0x26  /* IX    */
-#define IOPW_SP                 0x28  /* SP    */
-#define IOPW_PC                 0x2A  /* PC    */
+#define IOPW_Q_BASE             0x22	/* QB    */
+#define IOPW_QP                 0x24	/* QP    */
+#define IOPW_IX                 0x26	/* IX    */
+#define IOPW_SP                 0x28	/* SP    */
+#define IOPW_PC                 0x2A	/* PC    */
 #define IOPW_RES_ADDR_2C        0x2C
 #define IOPW_RES_ADDR_2E        0x2E
-#define IOPW_SCSI_DATA          0x30  /* SD    */
-#define IOPW_SCSI_DATA_HSHK     0x32  /* SDH   */
-#define IOPW_SCSI_CTRL          0x34  /* SC    */
-#define IOPW_HSHK_CFG           0x36  /* HCFG  */
-#define IOPW_SXFR_STATUS        0x36  /* SXS   */
-#define IOPW_SXFR_CNTL          0x38  /* SXL   */
-#define IOPW_SXFR_CNTH          0x3A  /* SXH   */
+#define IOPW_SCSI_DATA          0x30	/* SD    */
+#define IOPW_SCSI_DATA_HSHK     0x32	/* SDH   */
+#define IOPW_SCSI_CTRL          0x34	/* SC    */
+#define IOPW_HSHK_CFG           0x36	/* HCFG  */
+#define IOPW_SXFR_STATUS        0x36	/* SXS   */
+#define IOPW_SXFR_CNTL          0x38	/* SXL   */
+#define IOPW_SXFR_CNTH          0x3A	/* SXH   */
 #define IOPW_RES_ADDR_3C        0x3C
-#define IOPW_RFIFO_DATA         0x3E  /* RFD   */
+#define IOPW_RFIFO_DATA         0x3E	/* RFD   */
 
 /*
  * Doubleword I/O register address from base of 'iop_base'.
@@ -2621,36 +2598,36 @@
 /*
  * SCSI_CFG0 Register bit definitions
  */
-#define TIMER_MODEAB    0xC000  /* Watchdog, Second, and Select. Timer Ctrl. */
-#define PARITY_EN       0x2000  /* Enable SCSI Parity Error detection */
-#define EVEN_PARITY     0x1000  /* Select Even Parity */
-#define WD_LONG         0x0800  /* Watchdog Interval, 1: 57 min, 0: 13 sec */
-#define QUEUE_128       0x0400  /* Queue Size, 1: 128 byte, 0: 64 byte */
-#define PRIM_MODE       0x0100  /* Primitive SCSI mode */
-#define SCAM_EN         0x0080  /* Enable SCAM selection */
-#define SEL_TMO_LONG    0x0040  /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
-#define CFRM_ID         0x0020  /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
-#define OUR_ID_EN       0x0010  /* Enable OUR_ID bits */
-#define OUR_ID          0x000F  /* SCSI ID */
+#define TIMER_MODEAB    0xC000	/* Watchdog, Second, and Select. Timer Ctrl. */
+#define PARITY_EN       0x2000	/* Enable SCSI Parity Error detection */
+#define EVEN_PARITY     0x1000	/* Select Even Parity */
+#define WD_LONG         0x0800	/* Watchdog Interval, 1: 57 min, 0: 13 sec */
+#define QUEUE_128       0x0400	/* Queue Size, 1: 128 byte, 0: 64 byte */
+#define PRIM_MODE       0x0100	/* Primitive SCSI mode */
+#define SCAM_EN         0x0080	/* Enable SCAM selection */
+#define SEL_TMO_LONG    0x0040	/* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
+#define CFRM_ID         0x0020	/* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
+#define OUR_ID_EN       0x0010	/* Enable OUR_ID bits */
+#define OUR_ID          0x000F	/* SCSI ID */
 
 /*
  * SCSI_CFG1 Register bit definitions
  */
-#define BIG_ENDIAN      0x8000  /* Enable Big Endian Mode MIO:15, EEP:15 */
-#define TERM_POL        0x2000  /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
-#define SLEW_RATE       0x1000  /* SCSI output buffer slew rate */
-#define FILTER_SEL      0x0C00  /* Filter Period Selection */
-#define  FLTR_DISABLE    0x0000  /* Input Filtering Disabled */
-#define  FLTR_11_TO_20NS 0x0800  /* Input Filtering 11ns to 20ns */
-#define  FLTR_21_TO_39NS 0x0C00  /* Input Filtering 21ns to 39ns */
-#define ACTIVE_DBL      0x0200  /* Disable Active Negation */
-#define DIFF_MODE       0x0100  /* SCSI differential Mode (Read-Only) */
-#define DIFF_SENSE      0x0080  /* 1: No SE cables, 0: SE cable (Read-Only) */
-#define TERM_CTL_SEL    0x0040  /* Enable TERM_CTL_H and TERM_CTL_L */
-#define TERM_CTL        0x0030  /* External SCSI Termination Bits */
-#define  TERM_CTL_H      0x0020  /* Enable External SCSI Upper Termination */
-#define  TERM_CTL_L      0x0010  /* Enable External SCSI Lower Termination */
-#define CABLE_DETECT    0x000F  /* External SCSI Cable Connection Status */
+#define BIG_ENDIAN      0x8000	/* Enable Big Endian Mode MIO:15, EEP:15 */
+#define TERM_POL        0x2000	/* Terminator Polarity Ctrl. MIO:13, EEP:13 */
+#define SLEW_RATE       0x1000	/* SCSI output buffer slew rate */
+#define FILTER_SEL      0x0C00	/* Filter Period Selection */
+#define  FLTR_DISABLE    0x0000	/* Input Filtering Disabled */
+#define  FLTR_11_TO_20NS 0x0800	/* Input Filtering 11ns to 20ns */
+#define  FLTR_21_TO_39NS 0x0C00	/* Input Filtering 21ns to 39ns */
+#define ACTIVE_DBL      0x0200	/* Disable Active Negation */
+#define DIFF_MODE       0x0100	/* SCSI differential Mode (Read-Only) */
+#define DIFF_SENSE      0x0080	/* 1: No SE cables, 0: SE cable (Read-Only) */
+#define TERM_CTL_SEL    0x0040	/* Enable TERM_CTL_H and TERM_CTL_L */
+#define TERM_CTL        0x0030	/* External SCSI Termination Bits */
+#define  TERM_CTL_H      0x0020	/* Enable External SCSI Upper Termination */
+#define  TERM_CTL_L      0x0010	/* Enable External SCSI Lower Termination */
+#define CABLE_DETECT    0x000F	/* External SCSI Cable Connection Status */
 
 /*
  * Addendum for ASC-38C0800 Chip
@@ -2663,24 +2640,23 @@
  * Also each ASC-38C1600 function or channel uses only cable bits [5:4]
  * and [1:0]. Bits [14], [7:6], [3:2] are unused.
  */
-#define DIS_TERM_DRV    0x4000  /* 1: Read c_det[3:0], 0: cannot read */
-#define HVD_LVD_SE      0x1C00  /* Device Detect Bits */
-#define  HVD             0x1000  /* HVD Device Detect */
-#define  LVD             0x0800  /* LVD Device Detect */
-#define  SE              0x0400  /* SE Device Detect */
-#define TERM_LVD        0x00C0  /* LVD Termination Bits */
-#define  TERM_LVD_HI     0x0080  /* Enable LVD Upper Termination */
-#define  TERM_LVD_LO     0x0040  /* Enable LVD Lower Termination */
-#define TERM_SE         0x0030  /* SE Termination Bits */
-#define  TERM_SE_HI      0x0020  /* Enable SE Upper Termination */
-#define  TERM_SE_LO      0x0010  /* Enable SE Lower Termination */
-#define C_DET_LVD       0x000C  /* LVD Cable Detect Bits */
-#define  C_DET3          0x0008  /* Cable Detect for LVD External Wide */
-#define  C_DET2          0x0004  /* Cable Detect for LVD Internal Wide */
-#define C_DET_SE        0x0003  /* SE Cable Detect Bits */
-#define  C_DET1          0x0002  /* Cable Detect for SE Internal Wide */
-#define  C_DET0          0x0001  /* Cable Detect for SE Internal Narrow */
-
+#define DIS_TERM_DRV    0x4000	/* 1: Read c_det[3:0], 0: cannot read */
+#define HVD_LVD_SE      0x1C00	/* Device Detect Bits */
+#define  HVD             0x1000	/* HVD Device Detect */
+#define  LVD             0x0800	/* LVD Device Detect */
+#define  SE              0x0400	/* SE Device Detect */
+#define TERM_LVD        0x00C0	/* LVD Termination Bits */
+#define  TERM_LVD_HI     0x0080	/* Enable LVD Upper Termination */
+#define  TERM_LVD_LO     0x0040	/* Enable LVD Lower Termination */
+#define TERM_SE         0x0030	/* SE Termination Bits */
+#define  TERM_SE_HI      0x0020	/* Enable SE Upper Termination */
+#define  TERM_SE_LO      0x0010	/* Enable SE Lower Termination */
+#define C_DET_LVD       0x000C	/* LVD Cable Detect Bits */
+#define  C_DET3          0x0008	/* Cable Detect for LVD External Wide */
+#define  C_DET2          0x0004	/* Cable Detect for LVD Internal Wide */
+#define C_DET_SE        0x0003	/* SE Cable Detect Bits */
+#define  C_DET1          0x0002	/* Cable Detect for SE Internal Wide */
+#define  C_DET0          0x0001	/* Cable Detect for SE Internal Narrow */
 
 #define CABLE_ILLEGAL_A 0x7
     /* x 0 0 0  | on  on | Illegal (all 3 connectors are used) */
@@ -2691,39 +2667,39 @@
 /*
  * MEM_CFG Register bit definitions
  */
-#define BIOS_EN         0x40    /* BIOS Enable MIO:14,EEP:14 */
-#define FAST_EE_CLK     0x20    /* Diagnostic Bit */
-#define RAM_SZ          0x1C    /* Specify size of RAM to RISC */
-#define  RAM_SZ_2KB      0x00    /* 2 KB */
-#define  RAM_SZ_4KB      0x04    /* 4 KB */
-#define  RAM_SZ_8KB      0x08    /* 8 KB */
-#define  RAM_SZ_16KB     0x0C    /* 16 KB */
-#define  RAM_SZ_32KB     0x10    /* 32 KB */
-#define  RAM_SZ_64KB     0x14    /* 64 KB */
+#define BIOS_EN         0x40	/* BIOS Enable MIO:14,EEP:14 */
+#define FAST_EE_CLK     0x20	/* Diagnostic Bit */
+#define RAM_SZ          0x1C	/* Specify size of RAM to RISC */
+#define  RAM_SZ_2KB      0x00	/* 2 KB */
+#define  RAM_SZ_4KB      0x04	/* 4 KB */
+#define  RAM_SZ_8KB      0x08	/* 8 KB */
+#define  RAM_SZ_16KB     0x0C	/* 16 KB */
+#define  RAM_SZ_32KB     0x10	/* 32 KB */
+#define  RAM_SZ_64KB     0x14	/* 64 KB */
 
 /*
  * DMA_CFG0 Register bit definitions
  *
  * This register is only accessible to the host.
  */
-#define BC_THRESH_ENB   0x80    /* PCI DMA Start Conditions */
-#define FIFO_THRESH     0x70    /* PCI DMA FIFO Threshold */
-#define  FIFO_THRESH_16B  0x00   /* 16 bytes */
-#define  FIFO_THRESH_32B  0x20   /* 32 bytes */
-#define  FIFO_THRESH_48B  0x30   /* 48 bytes */
-#define  FIFO_THRESH_64B  0x40   /* 64 bytes */
-#define  FIFO_THRESH_80B  0x50   /* 80 bytes (default) */
-#define  FIFO_THRESH_96B  0x60   /* 96 bytes */
-#define  FIFO_THRESH_112B 0x70   /* 112 bytes */
-#define START_CTL       0x0C    /* DMA start conditions */
-#define  START_CTL_TH    0x00    /* Wait threshold level (default) */
-#define  START_CTL_ID    0x04    /* Wait SDMA/SBUS idle */
-#define  START_CTL_THID  0x08    /* Wait threshold and SDMA/SBUS idle */
-#define  START_CTL_EMFU  0x0C    /* Wait SDMA FIFO empty/full */
-#define READ_CMD        0x03    /* Memory Read Method */
-#define  READ_CMD_MR     0x00    /* Memory Read */
-#define  READ_CMD_MRL    0x02    /* Memory Read Long */
-#define  READ_CMD_MRM    0x03    /* Memory Read Multiple (default) */
+#define BC_THRESH_ENB   0x80	/* PCI DMA Start Conditions */
+#define FIFO_THRESH     0x70	/* PCI DMA FIFO Threshold */
+#define  FIFO_THRESH_16B  0x00	/* 16 bytes */
+#define  FIFO_THRESH_32B  0x20	/* 32 bytes */
+#define  FIFO_THRESH_48B  0x30	/* 48 bytes */
+#define  FIFO_THRESH_64B  0x40	/* 64 bytes */
+#define  FIFO_THRESH_80B  0x50	/* 80 bytes (default) */
+#define  FIFO_THRESH_96B  0x60	/* 96 bytes */
+#define  FIFO_THRESH_112B 0x70	/* 112 bytes */
+#define START_CTL       0x0C	/* DMA start conditions */
+#define  START_CTL_TH    0x00	/* Wait threshold level (default) */
+#define  START_CTL_ID    0x04	/* Wait SDMA/SBUS idle */
+#define  START_CTL_THID  0x08	/* Wait threshold and SDMA/SBUS idle */
+#define  START_CTL_EMFU  0x0C	/* Wait SDMA FIFO empty/full */
+#define READ_CMD        0x03	/* Memory Read Method */
+#define  READ_CMD_MR     0x00	/* Memory Read */
+#define  READ_CMD_MRL    0x02	/* Memory Read Long */
+#define  READ_CMD_MRM    0x03	/* Memory Read Multiple (default) */
 
 /*
  * ASC-38C0800 RAM BIST Register bit definitions
@@ -2747,7 +2723,7 @@
  * IOPB_PCI_INT_CFG Bit Field Definitions
  */
 
-#define INTAB_LD        0x80    /* Value loaded from EEPROM Bit 11. */
+#define INTAB_LD        0x80	/* Value loaded from EEPROM Bit 11. */
 
 /*
  * Bit 1 can be set to change the interrupt for the Function to operate in
@@ -2780,53 +2756,52 @@
 #define ADV_BUSY        0
 #define ADV_ERROR       (-1)
 
-
 /*
  * ADV_DVC_VAR 'warn_code' values
  */
-#define ASC_WARN_BUSRESET_ERROR         0x0001 /* SCSI Bus Reset error */
-#define ASC_WARN_EEPROM_CHKSUM          0x0002 /* EEP check sum error */
-#define ASC_WARN_EEPROM_TERMINATION     0x0004 /* EEP termination bad field */
-#define ASC_WARN_SET_PCI_CONFIG_SPACE   0x0080 /* PCI config space set error */
-#define ASC_WARN_ERROR                  0xFFFF /* ADV_ERROR return */
+#define ASC_WARN_BUSRESET_ERROR         0x0001	/* SCSI Bus Reset error */
+#define ASC_WARN_EEPROM_CHKSUM          0x0002	/* EEP check sum error */
+#define ASC_WARN_EEPROM_TERMINATION     0x0004	/* EEP termination bad field */
+#define ASC_WARN_SET_PCI_CONFIG_SPACE   0x0080	/* PCI config space set error */
+#define ASC_WARN_ERROR                  0xFFFF	/* ADV_ERROR return */
 
-#define ADV_MAX_TID                     15 /* max. target identifier */
-#define ADV_MAX_LUN                     7  /* max. logical unit number */
+#define ADV_MAX_TID                     15	/* max. target identifier */
+#define ADV_MAX_LUN                     7	/* max. logical unit number */
 
 /*
  * Error code values are set in ADV_DVC_VAR 'err_code'.
  */
-#define ASC_IERR_WRITE_EEPROM       0x0001 /* write EEPROM error */
-#define ASC_IERR_MCODE_CHKSUM       0x0002 /* micro code check sum error */
-#define ASC_IERR_NO_CARRIER         0x0004 /* No more carrier memory. */
-#define ASC_IERR_START_STOP_CHIP    0x0008 /* start/stop chip failed */
-#define ASC_IERR_CHIP_VERSION       0x0040 /* wrong chip version */
-#define ASC_IERR_SET_SCSI_ID        0x0080 /* set SCSI ID failed */
-#define ASC_IERR_HVD_DEVICE         0x0100 /* HVD attached to LVD connector. */
-#define ASC_IERR_BAD_SIGNATURE      0x0200 /* signature not found */
-#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
-#define ASC_IERR_SINGLE_END_DEVICE  0x0800 /* Single-end used w/differential */
-#define ASC_IERR_REVERSED_CABLE     0x1000 /* Narrow flat cable reversed */
-#define ASC_IERR_BIST_PRE_TEST      0x2000 /* BIST pre-test error */
-#define ASC_IERR_BIST_RAM_TEST      0x4000 /* BIST RAM test error */
-#define ASC_IERR_BAD_CHIPTYPE       0x8000 /* Invalid 'chip_type' setting. */
+#define ASC_IERR_WRITE_EEPROM       0x0001	/* write EEPROM error */
+#define ASC_IERR_MCODE_CHKSUM       0x0002	/* micro code check sum error */
+#define ASC_IERR_NO_CARRIER         0x0004	/* No more carrier memory. */
+#define ASC_IERR_START_STOP_CHIP    0x0008	/* start/stop chip failed */
+#define ASC_IERR_CHIP_VERSION       0x0040	/* wrong chip version */
+#define ASC_IERR_SET_SCSI_ID        0x0080	/* set SCSI ID failed */
+#define ASC_IERR_HVD_DEVICE         0x0100	/* HVD attached to LVD connector. */
+#define ASC_IERR_BAD_SIGNATURE      0x0200	/* signature not found */
+#define ASC_IERR_ILLEGAL_CONNECTION 0x0400	/* Illegal cable connection */
+#define ASC_IERR_SINGLE_END_DEVICE  0x0800	/* Single-end used w/differential */
+#define ASC_IERR_REVERSED_CABLE     0x1000	/* Narrow flat cable reversed */
+#define ASC_IERR_BIST_PRE_TEST      0x2000	/* BIST pre-test error */
+#define ASC_IERR_BIST_RAM_TEST      0x4000	/* BIST RAM test error */
+#define ASC_IERR_BAD_CHIPTYPE       0x8000	/* Invalid 'chip_type' setting. */
 
 /*
  * Fixed locations of microcode operating variables.
  */
-#define ASC_MC_CODE_BEGIN_ADDR          0x0028 /* microcode start address */
-#define ASC_MC_CODE_END_ADDR            0x002A /* microcode end address */
-#define ASC_MC_CODE_CHK_SUM             0x002C /* microcode code checksum */
-#define ASC_MC_VERSION_DATE             0x0038 /* microcode version */
-#define ASC_MC_VERSION_NUM              0x003A /* microcode number */
-#define ASC_MC_BIOSMEM                  0x0040 /* BIOS RISC Memory Start */
-#define ASC_MC_BIOSLEN                  0x0050 /* BIOS RISC Memory Length */
-#define ASC_MC_BIOS_SIGNATURE           0x0058 /* BIOS Signature 0x55AA */
-#define ASC_MC_BIOS_VERSION             0x005A /* BIOS Version (2 bytes) */
-#define ASC_MC_SDTR_SPEED1              0x0090 /* SDTR Speed for TID 0-3 */
-#define ASC_MC_SDTR_SPEED2              0x0092 /* SDTR Speed for TID 4-7 */
-#define ASC_MC_SDTR_SPEED3              0x0094 /* SDTR Speed for TID 8-11 */
-#define ASC_MC_SDTR_SPEED4              0x0096 /* SDTR Speed for TID 12-15 */
+#define ASC_MC_CODE_BEGIN_ADDR          0x0028	/* microcode start address */
+#define ASC_MC_CODE_END_ADDR            0x002A	/* microcode end address */
+#define ASC_MC_CODE_CHK_SUM             0x002C	/* microcode code checksum */
+#define ASC_MC_VERSION_DATE             0x0038	/* microcode version */
+#define ASC_MC_VERSION_NUM              0x003A	/* microcode number */
+#define ASC_MC_BIOSMEM                  0x0040	/* BIOS RISC Memory Start */
+#define ASC_MC_BIOSLEN                  0x0050	/* BIOS RISC Memory Length */
+#define ASC_MC_BIOS_SIGNATURE           0x0058	/* BIOS Signature 0x55AA */
+#define ASC_MC_BIOS_VERSION             0x005A	/* BIOS Version (2 bytes) */
+#define ASC_MC_SDTR_SPEED1              0x0090	/* SDTR Speed for TID 0-3 */
+#define ASC_MC_SDTR_SPEED2              0x0092	/* SDTR Speed for TID 4-7 */
+#define ASC_MC_SDTR_SPEED3              0x0094	/* SDTR Speed for TID 8-11 */
+#define ASC_MC_SDTR_SPEED4              0x0096	/* SDTR Speed for TID 12-15 */
 #define ASC_MC_CHIP_TYPE                0x009A
 #define ASC_MC_INTRB_CODE               0x009B
 #define ASC_MC_WDTR_ABLE                0x009C
@@ -2844,9 +2819,9 @@
 #define ASC_MC_NUMBER_OF_QUEUED_CMD     0x00C0
 #define ASC_MC_NUMBER_OF_MAX_CMD        0x00D0
 #define ASC_MC_DEVICE_HSHK_CFG_TABLE    0x0100
-#define ASC_MC_CONTROL_FLAG             0x0122 /* Microcode control flag. */
+#define ASC_MC_CONTROL_FLAG             0x0122	/* Microcode control flag. */
 #define ASC_MC_WDTR_DONE                0x0124
-#define ASC_MC_CAM_MODE_MASK            0x015E /* CAM mode TID bitmask. */
+#define ASC_MC_CAM_MODE_MASK            0x015E	/* CAM mode TID bitmask. */
 #define ASC_MC_ICQ                      0x0160
 #define ASC_MC_IRQ                      0x0164
 #define ASC_MC_PPR_ABLE                 0x017A
@@ -2865,8 +2840,8 @@
  * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
  * and handled by the microcode.
  */
-#define CONTROL_FLAG_IGNORE_PERR        0x0001 /* Ignore DMA Parity Errors */
-#define CONTROL_FLAG_ENABLE_AIPP        0x0002 /* Enabled AIPP checking. */
+#define CONTROL_FLAG_IGNORE_PERR        0x0001	/* Ignore DMA Parity Errors */
+#define CONTROL_FLAG_ENABLE_AIPP        0x0002	/* Enabled AIPP checking. */
 
 /*
  * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
@@ -2875,45 +2850,44 @@
 #define HSHK_CFG_RATE           0x0F00
 #define HSHK_CFG_OFFSET         0x001F
 
-#define ASC_DEF_MAX_HOST_QNG    0xFD /* Max. number of host commands (253) */
-#define ASC_DEF_MIN_HOST_QNG    0x10 /* Min. number of host commands (16) */
-#define ASC_DEF_MAX_DVC_QNG     0x3F /* Max. number commands per device (63) */
-#define ASC_DEF_MIN_DVC_QNG     0x04 /* Min. number commands per device (4) */
+#define ASC_DEF_MAX_HOST_QNG    0xFD	/* Max. number of host commands (253) */
+#define ASC_DEF_MIN_HOST_QNG    0x10	/* Min. number of host commands (16) */
+#define ASC_DEF_MAX_DVC_QNG     0x3F	/* Max. number commands per device (63) */
+#define ASC_DEF_MIN_DVC_QNG     0x04	/* Min. number commands per device (4) */
 
-#define ASC_QC_DATA_CHECK  0x01 /* Require ASC_QC_DATA_OUT set or clear. */
-#define ASC_QC_DATA_OUT    0x02 /* Data out DMA transfer. */
-#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
-#define ASC_QC_NO_OVERRUN  0x08 /* Don't report overrun. */
-#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
+#define ASC_QC_DATA_CHECK  0x01	/* Require ASC_QC_DATA_OUT set or clear. */
+#define ASC_QC_DATA_OUT    0x02	/* Data out DMA transfer. */
+#define ASC_QC_START_MOTOR 0x04	/* Send auto-start motor before request. */
+#define ASC_QC_NO_OVERRUN  0x08	/* Don't report overrun. */
+#define ASC_QC_FREEZE_TIDQ 0x10	/* Freeze TID queue after request. XXX TBD */
 
-#define ASC_QSC_NO_DISC     0x01 /* Don't allow disconnect for request. */
-#define ASC_QSC_NO_TAGMSG   0x02 /* Don't allow tag queuing for request. */
-#define ASC_QSC_NO_SYNC     0x04 /* Don't use Synch. transfer on request. */
-#define ASC_QSC_NO_WIDE     0x08 /* Don't use Wide transfer on request. */
-#define ASC_QSC_REDO_DTR    0x10 /* Renegotiate WDTR/SDTR before request. */
+#define ASC_QSC_NO_DISC     0x01	/* Don't allow disconnect for request. */
+#define ASC_QSC_NO_TAGMSG   0x02	/* Don't allow tag queuing for request. */
+#define ASC_QSC_NO_SYNC     0x04	/* Don't use Synch. transfer on request. */
+#define ASC_QSC_NO_WIDE     0x08	/* Don't use Wide transfer on request. */
+#define ASC_QSC_REDO_DTR    0x10	/* Renegotiate WDTR/SDTR before request. */
 /*
  * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
  * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
  */
-#define ASC_QSC_HEAD_TAG    0x40 /* Use Head Tag Message (0x21). */
-#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
+#define ASC_QSC_HEAD_TAG    0x40	/* Use Head Tag Message (0x21). */
+#define ASC_QSC_ORDERED_TAG 0x80	/* Use Ordered Tag Message (0x22). */
 
 /*
  * All fields here are accessed by the board microcode and need to be
  * little-endian.
  */
-typedef struct adv_carr_t
-{
-    ADV_VADDR   carr_va;       /* Carrier Virtual Address */
-    ADV_PADDR   carr_pa;       /* Carrier Physical Address */
-    ADV_VADDR   areq_vpa;      /* ASC_SCSI_REQ_Q Virtual or Physical Address */
-    /*
-     * next_vpa [31:4]            Carrier Virtual or Physical Next Pointer
-     *
-     * next_vpa [3:1]             Reserved Bits
-     * next_vpa [0]               Done Flag set in Response Queue.
-     */
-    ADV_VADDR   next_vpa;
+typedef struct adv_carr_t {
+	ADV_VADDR carr_va;	/* Carrier Virtual Address */
+	ADV_PADDR carr_pa;	/* Carrier Physical Address */
+	ADV_VADDR areq_vpa;	/* ASC_SCSI_REQ_Q Virtual or Physical Address */
+	/*
+	 * next_vpa [31:4]            Carrier Virtual or Physical Next Pointer
+	 *
+	 * next_vpa [3:1]             Reserved Bits
+	 * next_vpa [0]               Done Flag set in Response Queue.
+	 */
+	ADV_VADDR next_vpa;
 } ADV_CARR_T;
 
 /*
@@ -2940,13 +2914,13 @@
  * The Adv Library should limit use to the lower nibble (4 bits) of
  * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
  */
-#define ADV_POLL_REQUEST                0x01   /* poll for request completion */
-#define ADV_SCSIQ_DONE                  0x02   /* request done */
-#define ADV_DONT_RETRY                  0x08   /* don't do retry */
+#define ADV_POLL_REQUEST                0x01	/* poll for request completion */
+#define ADV_SCSIQ_DONE                  0x02	/* request done */
+#define ADV_DONT_RETRY                  0x08	/* don't do retry */
 
-#define ADV_CHIP_ASC3550          0x01   /* Ultra-Wide IC */
-#define ADV_CHIP_ASC38C0800       0x02   /* Ultra2-Wide/LVD IC */
-#define ADV_CHIP_ASC38C1600       0x03   /* Ultra3-Wide/LVD2 IC */
+#define ADV_CHIP_ASC3550          0x01	/* Ultra-Wide IC */
+#define ADV_CHIP_ASC38C0800       0x02	/* Ultra2-Wide/LVD IC */
+#define ADV_CHIP_ASC38C1600       0x03	/* Ultra3-Wide/LVD2 IC */
 
 /*
  * Adapter temporary configuration structure
@@ -2960,30 +2934,30 @@
  *  value of the field is never reset.
  */
 typedef struct adv_dvc_cfg {
-  ushort disc_enable;       /* enable disconnection */
-  uchar  chip_version;      /* chip version */
-  uchar  termination;       /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
-  ushort lib_version;       /* Adv Library version number */
-  ushort control_flag;      /* Microcode Control Flag */
-  ushort mcode_date;        /* Microcode date */
-  ushort mcode_version;     /* Microcode version */
-  ushort pci_slot_info;     /* high byte device/function number */
-                            /* bits 7-3 device num., bits 2-0 function num. */
-                            /* low byte bus num. */
-  ushort serial1;           /* EEPROM serial number word 1 */
-  ushort serial2;           /* EEPROM serial number word 2 */
-  ushort serial3;           /* EEPROM serial number word 3 */
-  struct device *dev;  /* pointer to the pci dev structure for this board */
+	ushort disc_enable;	/* enable disconnection */
+	uchar chip_version;	/* chip version */
+	uchar termination;	/* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
+	ushort lib_version;	/* Adv Library version number */
+	ushort control_flag;	/* Microcode Control Flag */
+	ushort mcode_date;	/* Microcode date */
+	ushort mcode_version;	/* Microcode version */
+	ushort pci_slot_info;	/* high byte device/function number */
+	/* bits 7-3 device num., bits 2-0 function num. */
+	/* low byte bus num. */
+	ushort serial1;		/* EEPROM serial number word 1 */
+	ushort serial2;		/* EEPROM serial number word 2 */
+	ushort serial3;		/* EEPROM serial number word 3 */
+	struct device *dev;	/* pointer to the pci dev structure for this board */
 } ADV_DVC_CFG;
 
 struct adv_dvc_var;
 struct adv_scsi_req_q;
 
-typedef void (* ADV_ISR_CALLBACK)
-    (struct adv_dvc_var *, struct adv_scsi_req_q *);
+typedef void (*ADV_ISR_CALLBACK)
+ (struct adv_dvc_var *, struct adv_scsi_req_q *);
 
-typedef void (* ADV_ASYNC_CALLBACK)
-    (struct adv_dvc_var *, uchar);
+typedef void (*ADV_ASYNC_CALLBACK)
+ (struct adv_dvc_var *, uchar);
 
 /*
  * Adapter operation variable structure.
@@ -2998,55 +2972,55 @@
  *  of the feature, the field is cleared.
  */
 typedef struct adv_dvc_var {
-  AdvPortAddr iop_base;   /* I/O port address */
-  ushort err_code;        /* fatal error code */
-  ushort bios_ctrl;       /* BIOS control word, EEPROM word 12 */
-  ADV_ISR_CALLBACK isr_callback;
-  ADV_ASYNC_CALLBACK async_callback;
-  ushort wdtr_able;       /* try WDTR for a device */
-  ushort sdtr_able;       /* try SDTR for a device */
-  ushort ultra_able;      /* try SDTR Ultra speed for a device */
-  ushort sdtr_speed1;     /* EEPROM SDTR Speed for TID 0-3   */
-  ushort sdtr_speed2;     /* EEPROM SDTR Speed for TID 4-7   */
-  ushort sdtr_speed3;     /* EEPROM SDTR Speed for TID 8-11  */
-  ushort sdtr_speed4;     /* EEPROM SDTR Speed for TID 12-15 */
-  ushort tagqng_able;     /* try tagged queuing with a device */
-  ushort ppr_able;        /* PPR message capable per TID bitmask. */
-  uchar  max_dvc_qng;     /* maximum number of tagged commands per device */
-  ushort start_motor;     /* start motor command allowed */
-  uchar  scsi_reset_wait; /* delay in seconds after scsi bus reset */
-  uchar  chip_no;         /* should be assigned by caller */
-  uchar  max_host_qng;    /* maximum number of Q'ed command allowed */
-  uchar  irq_no;          /* IRQ number */
-  ushort no_scam;         /* scam_tolerant of EEPROM */
-  struct asc_board *drv_ptr; /* driver pointer to private structure */
-  uchar  chip_scsi_id;    /* chip SCSI target ID */
-  uchar  chip_type;
-  uchar  bist_err_code;
-  ADV_CARR_T *carrier_buf;
-  ADV_CARR_T *carr_freelist; /* Carrier free list. */
-  ADV_CARR_T *icq_sp;  /* Initiator command queue stopper pointer. */
-  ADV_CARR_T *irq_sp;  /* Initiator response queue stopper pointer. */
-  ushort carr_pending_cnt;    /* Count of pending carriers. */
- /*
-  * Note: The following fields will not be used after initialization. The
-  * driver may discard the buffer after initialization is done.
-  */
-  ADV_DVC_CFG *cfg; /* temporary configuration structure  */
+	AdvPortAddr iop_base;	/* I/O port address */
+	ushort err_code;	/* fatal error code */
+	ushort bios_ctrl;	/* BIOS control word, EEPROM word 12 */
+	ADV_ISR_CALLBACK isr_callback;
+	ADV_ASYNC_CALLBACK async_callback;
+	ushort wdtr_able;	/* try WDTR for a device */
+	ushort sdtr_able;	/* try SDTR for a device */
+	ushort ultra_able;	/* try SDTR Ultra speed for a device */
+	ushort sdtr_speed1;	/* EEPROM SDTR Speed for TID 0-3   */
+	ushort sdtr_speed2;	/* EEPROM SDTR Speed for TID 4-7   */
+	ushort sdtr_speed3;	/* EEPROM SDTR Speed for TID 8-11  */
+	ushort sdtr_speed4;	/* EEPROM SDTR Speed for TID 12-15 */
+	ushort tagqng_able;	/* try tagged queuing with a device */
+	ushort ppr_able;	/* PPR message capable per TID bitmask. */
+	uchar max_dvc_qng;	/* maximum number of tagged commands per device */
+	ushort start_motor;	/* start motor command allowed */
+	uchar scsi_reset_wait;	/* delay in seconds after scsi bus reset */
+	uchar chip_no;		/* should be assigned by caller */
+	uchar max_host_qng;	/* maximum number of Q'ed command allowed */
+	uchar irq_no;		/* IRQ number */
+	ushort no_scam;		/* scam_tolerant of EEPROM */
+	struct asc_board *drv_ptr;	/* driver pointer to private structure */
+	uchar chip_scsi_id;	/* chip SCSI target ID */
+	uchar chip_type;
+	uchar bist_err_code;
+	ADV_CARR_T *carrier_buf;
+	ADV_CARR_T *carr_freelist;	/* Carrier free list. */
+	ADV_CARR_T *icq_sp;	/* Initiator command queue stopper pointer. */
+	ADV_CARR_T *irq_sp;	/* Initiator response queue stopper pointer. */
+	ushort carr_pending_cnt;	/* Count of pending carriers. */
+	/*
+	 * Note: The following fields will not be used after initialization. The
+	 * driver may discard the buffer after initialization is done.
+	 */
+	ADV_DVC_CFG *cfg;	/* temporary configuration structure  */
 } ADV_DVC_VAR;
 
 #define NO_OF_SG_PER_BLOCK              15
 
 typedef struct asc_sg_block {
-    uchar reserved1;
-    uchar reserved2;
-    uchar reserved3;
-    uchar sg_cnt;                     /* Valid entries in block. */
-    ADV_PADDR sg_ptr;                 /* Pointer to next sg block. */
-    struct  {
-        ADV_PADDR sg_addr;                  /* SG element address. */
-        ADV_DCNT  sg_count;                 /* SG element count. */
-    } sg_list[NO_OF_SG_PER_BLOCK];
+	uchar reserved1;
+	uchar reserved2;
+	uchar reserved3;
+	uchar sg_cnt;		/* Valid entries in block. */
+	ADV_PADDR sg_ptr;	/* Pointer to next sg block. */
+	struct {
+		ADV_PADDR sg_addr;	/* SG element address. */
+		ADV_DCNT sg_count;	/* SG element count. */
+	} sg_list[NO_OF_SG_PER_BLOCK];
 } ADV_SG_BLOCK;
 
 /*
@@ -3061,37 +3035,37 @@
  * order.
  */
 typedef struct adv_scsi_req_q {
-    uchar       cntl;           /* Ucode flags and state (ASC_MC_QC_*). */
-    uchar       target_cmd;
-    uchar       target_id;      /* Device target identifier. */
-    uchar       target_lun;     /* Device target logical unit number. */
-    ADV_PADDR   data_addr;      /* Data buffer physical address. */
-    ADV_DCNT    data_cnt;       /* Data count. Ucode sets to residual. */
-    ADV_PADDR   sense_addr;
-    ADV_PADDR   carr_pa;
-    uchar       mflag;
-    uchar       sense_len;
-    uchar       cdb_len;        /* SCSI CDB length. Must <= 16 bytes. */
-    uchar       scsi_cntl;
-    uchar       done_status;    /* Completion status. */
-    uchar       scsi_status;    /* SCSI status byte. */
-    uchar       host_status;    /* Ucode host status. */
-    uchar       sg_working_ix;
-    uchar       cdb[12];        /* SCSI CDB bytes 0-11. */
-    ADV_PADDR   sg_real_addr;   /* SG list physical address. */
-    ADV_PADDR   scsiq_rptr;
-    uchar       cdb16[4];       /* SCSI CDB bytes 12-15. */
-    ADV_VADDR   scsiq_ptr;
-    ADV_VADDR   carr_va;
-    /*
-     * End of microcode structure - 60 bytes. The rest of the structure
-     * is used by the Adv Library and ignored by the microcode.
-     */
-    ADV_VADDR   srb_ptr;
-    ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
-    char        *vdata_addr;   /* Data buffer virtual address. */
-    uchar       a_flag;
-    uchar       pad[2];        /* Pad out to a word boundary. */
+	uchar cntl;		/* Ucode flags and state (ASC_MC_QC_*). */
+	uchar target_cmd;
+	uchar target_id;	/* Device target identifier. */
+	uchar target_lun;	/* Device target logical unit number. */
+	ADV_PADDR data_addr;	/* Data buffer physical address. */
+	ADV_DCNT data_cnt;	/* Data count. Ucode sets to residual. */
+	ADV_PADDR sense_addr;
+	ADV_PADDR carr_pa;
+	uchar mflag;
+	uchar sense_len;
+	uchar cdb_len;		/* SCSI CDB length. Must <= 16 bytes. */
+	uchar scsi_cntl;
+	uchar done_status;	/* Completion status. */
+	uchar scsi_status;	/* SCSI status byte. */
+	uchar host_status;	/* Ucode host status. */
+	uchar sg_working_ix;
+	uchar cdb[12];		/* SCSI CDB bytes 0-11. */
+	ADV_PADDR sg_real_addr;	/* SG list physical address. */
+	ADV_PADDR scsiq_rptr;
+	uchar cdb16[4];		/* SCSI CDB bytes 12-15. */
+	ADV_VADDR scsiq_ptr;
+	ADV_VADDR carr_va;
+	/*
+	 * End of microcode structure - 60 bytes. The rest of the structure
+	 * is used by the Adv Library and ignored by the microcode.
+	 */
+	ADV_VADDR srb_ptr;
+	ADV_SG_BLOCK *sg_list_ptr;	/* SG list virtual address. */
+	char *vdata_addr;	/* Data buffer virtual address. */
+	uchar a_flag;
+	uchar pad[2];		/* Pad out to a word boundary. */
 } ADV_SCSI_REQ_Q;
 
 /*
@@ -3103,8 +3077,8 @@
 #define IDLE_CMD_SEND_INT            0x0004
 #define IDLE_CMD_ABORT               0x0008
 #define IDLE_CMD_DEVICE_RESET        0x0010
-#define IDLE_CMD_SCSI_RESET_START    0x0020 /* Assert SCSI Bus Reset */
-#define IDLE_CMD_SCSI_RESET_END      0x0040 /* Deassert SCSI Bus Reset */
+#define IDLE_CMD_SCSI_RESET_START    0x0020	/* Assert SCSI Bus Reset */
+#define IDLE_CMD_SCSI_RESET_END      0x0040	/* Deassert SCSI Bus Reset */
 #define IDLE_CMD_SCSIREQ             0x0080
 
 #define IDLE_CMD_STATUS_SUCCESS      0x0001
@@ -3118,60 +3092,59 @@
 /*
  * Wait loop time out values.
  */
-#define SCSI_WAIT_10_SEC             10UL    /* 10 seconds */
-#define SCSI_WAIT_100_MSEC           100UL   /* 100 milliseconds */
-#define SCSI_US_PER_MSEC             1000    /* microseconds per millisecond */
-#define SCSI_MS_PER_SEC              1000UL  /* milliseconds per second */
-#define SCSI_MAX_RETRY               10      /* retry count */
+#define SCSI_WAIT_10_SEC             10UL	/* 10 seconds */
+#define SCSI_WAIT_100_MSEC           100UL	/* 100 milliseconds */
+#define SCSI_US_PER_MSEC             1000	/* microseconds per millisecond */
+#define SCSI_MS_PER_SEC              1000UL	/* milliseconds per second */
+#define SCSI_MAX_RETRY               10	/* retry count */
 
-#define ADV_ASYNC_RDMA_FAILURE          0x01 /* Fatal RDMA failure. */
-#define ADV_ASYNC_SCSI_BUS_RESET_DET    0x02 /* Detected SCSI Bus Reset. */
-#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
-#define ADV_RDMA_IN_CARR_AND_Q_INVALID  0x04 /* RDMAed-in data invalid. */
+#define ADV_ASYNC_RDMA_FAILURE          0x01	/* Fatal RDMA failure. */
+#define ADV_ASYNC_SCSI_BUS_RESET_DET    0x02	/* Detected SCSI Bus Reset. */
+#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03	/* Carrier Ready failure. */
+#define ADV_RDMA_IN_CARR_AND_Q_INVALID  0x04	/* RDMAed-in data invalid. */
 
-
-#define ADV_HOST_SCSI_BUS_RESET      0x80 /* Host Initiated SCSI Bus Reset. */
+#define ADV_HOST_SCSI_BUS_RESET      0x80	/* Host Initiated SCSI Bus Reset. */
 
 /*
  * Device drivers must define the following functions.
  */
-STATIC inline ulong DvcEnterCritical(void);
-STATIC inline void  DvcLeaveCritical(ulong);
-STATIC void  DvcSleepMilliSecond(ADV_DCNT);
-STATIC uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort);
-STATIC void  DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar);
-STATIC ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
-                uchar *, ASC_SDCNT *, int);
-STATIC void  DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
+static inline ulong DvcEnterCritical(void);
+static inline void DvcLeaveCritical(ulong);
+static void DvcSleepMilliSecond(ADV_DCNT);
+static uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort);
+static void DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar);
+static ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
+			       uchar *, ASC_SDCNT *, int);
+static void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
 
 /*
  * Adv Library functions available to drivers.
  */
-STATIC int     AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-STATIC int     AdvISR(ADV_DVC_VAR *);
-STATIC int     AdvInitGetConfig(ADV_DVC_VAR *);
-STATIC int     AdvInitAsc3550Driver(ADV_DVC_VAR *);
-STATIC int     AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
-STATIC int     AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
-STATIC int     AdvResetChipAndSB(ADV_DVC_VAR *);
-STATIC int     AdvResetSB(ADV_DVC_VAR *asc_dvc);
+static int AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+static int AdvISR(ADV_DVC_VAR *);
+static int AdvInitGetConfig(ADV_DVC_VAR *);
+static int AdvInitAsc3550Driver(ADV_DVC_VAR *);
+static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
+static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
+static int AdvResetChipAndSB(ADV_DVC_VAR *);
+static int AdvResetSB(ADV_DVC_VAR *asc_dvc);
 
 /*
  * Internal Adv Library functions.
  */
-STATIC int    AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
-STATIC void   AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-STATIC int    AdvInitFrom3550EEP(ADV_DVC_VAR *);
-STATIC int    AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
-STATIC int    AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
-STATIC ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
-STATIC void   AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
-STATIC ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
-STATIC void   AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
-STATIC ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
-STATIC void   AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
-STATIC void   AdvWaitEEPCmd(AdvPortAddr);
-STATIC ushort AdvReadEEPWord(AdvPortAddr, int);
+static int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
+static void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+static int AdvInitFrom3550EEP(ADV_DVC_VAR *);
+static int AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
+static int AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
+static ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
+static void AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
+static ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
+static void AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
+static ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
+static void AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
+static void AdvWaitEEPCmd(AdvPortAddr);
+static ushort AdvReadEEPWord(AdvPortAddr, int);
 
 /*
  * PCI Bus Definitions
@@ -3241,7 +3214,6 @@
 #define AdvWriteWordAutoIncLram(iop_base, word) \
      (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
 
-
 /*
  * Define macro to check for Condor signature.
  *
@@ -3313,7 +3285,7 @@
  * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
  */
 
-#define QD_NO_STATUS         0x00       /* Request not completed yet. */
+#define QD_NO_STATUS         0x00	/* Request not completed yet. */
 #define QD_NO_ERROR          0x01
 #define QD_ABORTED_BY_HOST   0x02
 #define QD_WITH_ERROR        0x04
@@ -3323,30 +3295,29 @@
 #define QHSTA_M_DATA_OVER_RUN       0x12
 #define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
 #define QHSTA_M_QUEUE_ABORTED       0x15
-#define QHSTA_M_SXFR_SDMA_ERR       0x16 /* SXFR_STATUS SCSI DMA Error */
-#define QHSTA_M_SXFR_SXFR_PERR      0x17 /* SXFR_STATUS SCSI Bus Parity Error */
-#define QHSTA_M_RDMA_PERR           0x18 /* RISC PCI DMA parity error */
-#define QHSTA_M_SXFR_OFF_UFLW       0x19 /* SXFR_STATUS Offset Underflow */
-#define QHSTA_M_SXFR_OFF_OFLW       0x20 /* SXFR_STATUS Offset Overflow */
-#define QHSTA_M_SXFR_WD_TMO         0x21 /* SXFR_STATUS Watchdog Timeout */
-#define QHSTA_M_SXFR_DESELECTED     0x22 /* SXFR_STATUS Deselected */
+#define QHSTA_M_SXFR_SDMA_ERR       0x16	/* SXFR_STATUS SCSI DMA Error */
+#define QHSTA_M_SXFR_SXFR_PERR      0x17	/* SXFR_STATUS SCSI Bus Parity Error */
+#define QHSTA_M_RDMA_PERR           0x18	/* RISC PCI DMA parity error */
+#define QHSTA_M_SXFR_OFF_UFLW       0x19	/* SXFR_STATUS Offset Underflow */
+#define QHSTA_M_SXFR_OFF_OFLW       0x20	/* SXFR_STATUS Offset Overflow */
+#define QHSTA_M_SXFR_WD_TMO         0x21	/* SXFR_STATUS Watchdog Timeout */
+#define QHSTA_M_SXFR_DESELECTED     0x22	/* SXFR_STATUS Deselected */
 /* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
-#define QHSTA_M_SXFR_XFR_OFLW       0x12 /* SXFR_STATUS Transfer Overflow */
-#define QHSTA_M_SXFR_XFR_PH_ERR     0x24 /* SXFR_STATUS Transfer Phase Error */
-#define QHSTA_M_SXFR_UNKNOWN_ERROR  0x25 /* SXFR_STATUS Unknown Error */
-#define QHSTA_M_SCSI_BUS_RESET      0x30 /* Request aborted from SBR */
-#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
-#define QHSTA_M_BUS_DEVICE_RESET    0x32 /* Request aborted from BDR */
-#define QHSTA_M_DIRECTION_ERR       0x35 /* Data Phase mismatch */
-#define QHSTA_M_DIRECTION_ERR_HUNG  0x36 /* Data Phase mismatch and bus hang */
+#define QHSTA_M_SXFR_XFR_OFLW       0x12	/* SXFR_STATUS Transfer Overflow */
+#define QHSTA_M_SXFR_XFR_PH_ERR     0x24	/* SXFR_STATUS Transfer Phase Error */
+#define QHSTA_M_SXFR_UNKNOWN_ERROR  0x25	/* SXFR_STATUS Unknown Error */
+#define QHSTA_M_SCSI_BUS_RESET      0x30	/* Request aborted from SBR */
+#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31	/* Request aborted from unsol. SBR */
+#define QHSTA_M_BUS_DEVICE_RESET    0x32	/* Request aborted from BDR */
+#define QHSTA_M_DIRECTION_ERR       0x35	/* Data Phase mismatch */
+#define QHSTA_M_DIRECTION_ERR_HUNG  0x36	/* Data Phase mismatch and bus hang */
 #define QHSTA_M_WTM_TIMEOUT         0x41
 #define QHSTA_M_BAD_CMPL_STATUS_IN  0x42
 #define QHSTA_M_NO_AUTO_REQ_SENSE   0x43
 #define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
-#define QHSTA_M_INVALID_DEVICE      0x45 /* Bad target ID */
-#define QHSTA_M_FROZEN_TIDQ         0x46 /* TID Queue frozen. */
-#define QHSTA_M_SGBACKUP_ERROR      0x47 /* Scatter-Gather backup error */
-
+#define QHSTA_M_INVALID_DEVICE      0x45	/* Bad target ID */
+#define QHSTA_M_FROZEN_TIDQ         0x46	/* TID Queue frozen. */
+#define QHSTA_M_SGBACKUP_ERROR      0x47	/* Scatter-Gather backup error */
 
 /*
  * Default EEPROM Configuration structure defined in a_init.c.
@@ -3358,12 +3329,12 @@
 /*
  * DvcGetPhyAddr() flag arguments
  */
-#define ADV_IS_SCSIQ_FLAG       0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
-#define ADV_ASCGETSGLIST_VADDR  0x02 /* 'addr' is AscGetSGList() virtual addr */
-#define ADV_IS_SENSE_FLAG       0x04 /* 'addr' is sense virtual pointer */
-#define ADV_IS_DATA_FLAG        0x08 /* 'addr' is data virtual pointer */
-#define ADV_IS_SGLIST_FLAG      0x10 /* 'addr' is sglist virtual pointer */
-#define ADV_IS_CARRIER_FLAG     0x20 /* 'addr' is ADV_CARR_T pointer */
+#define ADV_IS_SCSIQ_FLAG       0x01	/* 'addr' is ASC_SCSI_REQ_Q pointer */
+#define ADV_ASCGETSGLIST_VADDR  0x02	/* 'addr' is AscGetSGList() virtual addr */
+#define ADV_IS_SENSE_FLAG       0x04	/* 'addr' is sense virtual pointer */
+#define ADV_IS_DATA_FLAG        0x08	/* 'addr' is data virtual pointer */
+#define ADV_IS_SGLIST_FLAG      0x10	/* 'addr' is sglist virtual pointer */
+#define ADV_IS_CARRIER_FLAG     0x20	/* 'addr' is ADV_CARR_T pointer */
 
 /* Return the address that is aligned at the next doubleword >= to 'addr'. */
 #define ADV_8BALIGN(addr)      (((ulong) (addr) + 0x7) & ~0x7)
@@ -3413,43 +3384,42 @@
 #define ADV_INQ_CLOCKING(inq)       (((inq)->info & 0x0c) >> 2)
 
 typedef struct {
-  uchar periph;                 /* peripheral device type [0:4] */
-                                /* peripheral qualifier [5:7] */
-  uchar devtype;                /* device type modifier (for SCSI I) [0:6] */
-                                /* RMB - removable medium bit [7] */
-  uchar ver;                    /* ANSI approved version [0:2] */
-                                /* ECMA version [3:5] */
-                                /* ISO version [6:7] */
-  uchar byte3;                  /* response data format [0:3] */
-                                /* 0 SCSI 1 */
-                                /* 1 CCS */
-                                /* 2 SCSI-2 */
-                                /* 3-F reserved */
-                                /* reserved [4:5] */
-                                /* terminate I/O process bit (see 5.6.22) [6] */
-                                /* asynch. event notification (processor) [7] */
-  uchar add_len;                /* additional length */
-  uchar res1;                   /* reserved */
-  uchar res2;                   /* reserved */
-  uchar flags;                  /* soft reset implemented [0] */
-                                /* command queuing [1] */
-                                /* reserved [2] */
-                                /* linked command for this logical unit [3] */
-                                /* synchronous data transfer [4] */
-                                /* wide bus 16 bit data transfer [5] */
-                                /* wide bus 32 bit data transfer [6] */
-                                /* relative addressing mode [7] */
-  uchar vendor_id[8];           /* vendor identification */
-  uchar product_id[16];         /* product identification */
-  uchar product_rev_level[4];   /* product revision level */
-  uchar vendor_specific[20];    /* vendor specific */
-  uchar info;                   /* information unit supported [0] */
-                                /* quick arbitrate supported [1] */
-                                /* clocking field [2:3] */
-                                /* reserved [4:7] */
-  uchar res3;                   /* reserved */
-} ADV_SCSI_INQUIRY; /* 58 bytes */
-
+	uchar periph;		/* peripheral device type [0:4] */
+	/* peripheral qualifier [5:7] */
+	uchar devtype;		/* device type modifier (for SCSI I) [0:6] */
+	/* RMB - removable medium bit [7] */
+	uchar ver;		/* ANSI approved version [0:2] */
+	/* ECMA version [3:5] */
+	/* ISO version [6:7] */
+	uchar byte3;		/* response data format [0:3] */
+	/* 0 SCSI 1 */
+	/* 1 CCS */
+	/* 2 SCSI-2 */
+	/* 3-F reserved */
+	/* reserved [4:5] */
+	/* terminate I/O process bit (see 5.6.22) [6] */
+	/* asynch. event notification (processor) [7] */
+	uchar add_len;		/* additional length */
+	uchar res1;		/* reserved */
+	uchar res2;		/* reserved */
+	uchar flags;		/* soft reset implemented [0] */
+	/* command queuing [1] */
+	/* reserved [2] */
+	/* linked command for this logical unit [3] */
+	/* synchronous data transfer [4] */
+	/* wide bus 16 bit data transfer [5] */
+	/* wide bus 32 bit data transfer [6] */
+	/* relative addressing mode [7] */
+	uchar vendor_id[8];	/* vendor identification */
+	uchar product_id[16];	/* product identification */
+	uchar product_rev_level[4];	/* product revision level */
+	uchar vendor_specific[20];	/* vendor specific */
+	uchar info;		/* information unit supported [0] */
+	/* quick arbitrate supported [1] */
+	/* clocking field [2:3] */
+	/* reserved [4:7] */
+	uchar res3;		/* reserved */
+} ADV_SCSI_INQUIRY;		/* 58 bytes */
 
 /*
  * --- Driver Constants and Macros
@@ -3464,15 +3434,15 @@
 
 /* asc_board_t flags */
 #define ASC_HOST_IN_RESET       0x01
-#define ASC_IS_WIDE_BOARD       0x04    /* AdvanSys Wide Board */
+#define ASC_IS_WIDE_BOARD       0x04	/* AdvanSys Wide Board */
 #define ASC_SELECT_QUEUE_DEPTHS 0x08
 
 #define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
 #define ASC_WIDE_BOARD(boardp)   ((boardp)->flags & ASC_IS_WIDE_BOARD)
 
-#define NO_ISA_DMA              0xff        /* No ISA DMA Channel Used */
+#define NO_ISA_DMA              0xff	/* No ISA DMA Channel Used */
 
-#define ASC_INFO_SIZE           128            /* advansys_info() line size */
+#define ASC_INFO_SIZE           128	/* advansys_info() line size */
 
 #ifdef CONFIG_PROC_FS
 /* /proc/scsi/advansys/[0...] related definitions */
@@ -3514,7 +3484,7 @@
  *  REQPTIME(reqp) - reqp's time stamp value
  *  REQTIMESTAMP() - system time stamp value
  */
-typedef struct scsi_cmnd     REQ, *REQP;
+typedef struct scsi_cmnd REQ, *REQP;
 #define REQPNEXT(reqp)       ((REQP) ((reqp)->host_scribble))
 #define REQPNEXTP(reqp)      ((REQP *) &((reqp)->host_scribble))
 #define REQPTID(reqp)        ((reqp)->device->id)
@@ -3564,17 +3534,17 @@
 #define PCI_MAX_SLOT            0x1F
 #define PCI_MAX_BUS             0xFF
 #define PCI_IOADDRESS_MASK      0xFFFE
-#define ASC_PCI_DEVICE_ID_CNT   6       /* PCI Device ID count. */
+#define ASC_PCI_DEVICE_ID_CNT   6	/* PCI Device ID count. */
 
 #ifndef ADVANSYS_STATS
-#define ASC_STATS(shp, counter)
-#define ASC_STATS_ADD(shp, counter, count)
+#define ASC_STATS(shost, counter)
+#define ASC_STATS_ADD(shost, counter, count)
 #else /* ADVANSYS_STATS */
-#define ASC_STATS(shp, counter) \
-    (ASC_BOARDP(shp)->asc_stats.counter++)
+#define ASC_STATS(shost, counter) \
+    (ASC_BOARDP(shost)->asc_stats.counter++)
 
-#define ASC_STATS_ADD(shp, counter, count) \
-    (ASC_BOARDP(shp)->asc_stats.counter += (count))
+#define ASC_STATS_ADD(shost, counter, count) \
+    (ASC_BOARDP(shost)->asc_stats.counter += (count))
 #endif /* ADVANSYS_STATS */
 
 #define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
@@ -3617,7 +3587,6 @@
         printk((s), (a1), (a2), (a3), (a4)); \
     }
 
-
 #ifndef ADVANSYS_DEBUG
 
 #define ASC_DBG(lvl, s)
@@ -3746,7 +3715,6 @@
 
 #endif /* ADVANSYS_ASSERT */
 
-
 /*
  * --- Driver Structures
  */
@@ -3755,27 +3723,27 @@
 
 /* Per board statistics structure */
 struct asc_stats {
-    /* Driver Entrypoint Statistics */
-    ADV_DCNT queuecommand;    /* # calls to advansys_queuecommand() */
-    ADV_DCNT reset;           /* # calls to advansys_eh_bus_reset() */
-    ADV_DCNT biosparam;       /* # calls to advansys_biosparam() */
-    ADV_DCNT interrupt;       /* # advansys_interrupt() calls */
-    ADV_DCNT callback;        /* # calls to asc/adv_isr_callback() */
-    ADV_DCNT done;            /* # calls to request's scsi_done function */
-    ADV_DCNT build_error;     /* # asc/adv_build_req() ASC_ERROR returns. */
-    ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
-    ADV_DCNT adv_build_nosg;  /* # adv_build_req() adv_sgblk_t alloc. fail. */
-    /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
-    ADV_DCNT exe_noerror;     /* # ASC_NOERROR returns. */
-    ADV_DCNT exe_busy;        /* # ASC_BUSY returns. */
-    ADV_DCNT exe_error;       /* # ASC_ERROR returns. */
-    ADV_DCNT exe_unknown;     /* # unknown returns. */
-    /* Data Transfer Statistics */
-    ADV_DCNT cont_cnt;        /* # non-scatter-gather I/O requests received */
-    ADV_DCNT cont_xfer;       /* # contiguous transfer 512-bytes */
-    ADV_DCNT sg_cnt;          /* # scatter-gather I/O requests received */
-    ADV_DCNT sg_elem;         /* # scatter-gather elements */
-    ADV_DCNT sg_xfer;         /* # scatter-gather transfer 512-bytes */
+	/* Driver Entrypoint Statistics */
+	ADV_DCNT queuecommand;	/* # calls to advansys_queuecommand() */
+	ADV_DCNT reset;		/* # calls to advansys_eh_bus_reset() */
+	ADV_DCNT biosparam;	/* # calls to advansys_biosparam() */
+	ADV_DCNT interrupt;	/* # advansys_interrupt() calls */
+	ADV_DCNT callback;	/* # calls to asc/adv_isr_callback() */
+	ADV_DCNT done;		/* # calls to request's scsi_done function */
+	ADV_DCNT build_error;	/* # asc/adv_build_req() ASC_ERROR returns. */
+	ADV_DCNT adv_build_noreq;	/* # adv_build_req() adv_req_t alloc. fail. */
+	ADV_DCNT adv_build_nosg;	/* # adv_build_req() adv_sgblk_t alloc. fail. */
+	/* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
+	ADV_DCNT exe_noerror;	/* # ASC_NOERROR returns. */
+	ADV_DCNT exe_busy;	/* # ASC_BUSY returns. */
+	ADV_DCNT exe_error;	/* # ASC_ERROR returns. */
+	ADV_DCNT exe_unknown;	/* # unknown returns. */
+	/* Data Transfer Statistics */
+	ADV_DCNT cont_cnt;	/* # non-scatter-gather I/O requests received */
+	ADV_DCNT cont_xfer;	/* # contiguous transfer 512-bytes */
+	ADV_DCNT sg_cnt;	/* # scatter-gather I/O requests received */
+	ADV_DCNT sg_elem;	/* # scatter-gather elements */
+	ADV_DCNT sg_xfer;	/* # scatter-gather transfer 512-bytes */
 };
 #endif /* ADVANSYS_STATS */
 
@@ -3783,17 +3751,17 @@
  * Request queuing structure
  */
 typedef struct asc_queue {
-    ADV_SCSI_BIT_ID_TYPE  q_tidmask;                /* queue mask */
-    REQP                  q_first[ADV_MAX_TID+1];   /* first queued request */
-    REQP                  q_last[ADV_MAX_TID+1];    /* last queued request */
+	ADV_SCSI_BIT_ID_TYPE q_tidmask;	/* queue mask */
+	REQP q_first[ADV_MAX_TID + 1];	/* first queued request */
+	REQP q_last[ADV_MAX_TID + 1];	/* last queued request */
 #ifdef ADVANSYS_STATS
-    short                 q_cur_cnt[ADV_MAX_TID+1]; /* current queue count */
-    short                 q_max_cnt[ADV_MAX_TID+1]; /* maximum queue count */
-    ADV_DCNT              q_tot_cnt[ADV_MAX_TID+1]; /* total enqueue count */
-    ADV_DCNT              q_tot_tim[ADV_MAX_TID+1]; /* total time queued */
-    ushort                q_max_tim[ADV_MAX_TID+1]; /* maximum time queued */
-    ushort                q_min_tim[ADV_MAX_TID+1]; /* minimum time queued */
-#endif /* ADVANSYS_STATS */
+	short q_cur_cnt[ADV_MAX_TID + 1];	/* current queue count */
+	short q_max_cnt[ADV_MAX_TID + 1];	/* maximum queue count */
+	ADV_DCNT q_tot_cnt[ADV_MAX_TID + 1];	/* total enqueue count */
+	ADV_DCNT q_tot_tim[ADV_MAX_TID + 1];	/* total time queued */
+	ushort q_max_tim[ADV_MAX_TID + 1];	/* maximum time queued */
+	ushort q_min_tim[ADV_MAX_TID + 1];	/* minimum time queued */
+#endif				/* ADVANSYS_STATS */
 } asc_queue_t;
 
 /*
@@ -3814,17 +3782,17 @@
  * Both structures must be 32 byte aligned.
  */
 typedef struct adv_sgblk {
-    ADV_SG_BLOCK        sg_block;     /* Sgblock structure. */
-    uchar               align[32];    /* Sgblock structure padding. */
-    struct adv_sgblk    *next_sgblkp; /* Next scatter-gather structure. */
+	ADV_SG_BLOCK sg_block;	/* Sgblock structure. */
+	uchar align[32];	/* Sgblock structure padding. */
+	struct adv_sgblk *next_sgblkp;	/* Next scatter-gather structure. */
 } adv_sgblk_t;
 
 typedef struct adv_req {
-    ADV_SCSI_REQ_Q      scsi_req_q;   /* Adv Library request structure. */
-    uchar               align[32];    /* Request structure padding. */
-    struct scsi_cmnd	*cmndp;       /* Mid-Level SCSI command pointer. */
-    adv_sgblk_t         *sgblkp;      /* Adv Library scatter-gather pointer. */
-    struct adv_req      *next_reqp;   /* Next Request Structure. */
+	ADV_SCSI_REQ_Q scsi_req_q;	/* Adv Library request structure. */
+	uchar align[32];	/* Request structure padding. */
+	struct scsi_cmnd *cmndp;	/* Mid-Level SCSI command pointer. */
+	adv_sgblk_t *sgblkp;	/* Adv Library scatter-gather pointer. */
+	struct adv_req *next_reqp;	/* Next Request Structure. */
 } adv_req_t;
 
 /*
@@ -3835,113 +3803,109 @@
  * field. It is guaranteed to be allocated from DMA-able memory.
  */
 typedef struct asc_board {
-    int                  id;                    /* Board Id */
-    uint                 flags;                 /* Board flags */
-    union {
-        ASC_DVC_VAR      asc_dvc_var;           /* Narrow board */
-        ADV_DVC_VAR      adv_dvc_var;           /* Wide board */
-    } dvc_var;
-    union {
-        ASC_DVC_CFG      asc_dvc_cfg;           /* Narrow board */
-        ADV_DVC_CFG      adv_dvc_cfg;           /* Wide board */
-    } dvc_cfg;
-    ushort               asc_n_io_port;         /* Number I/O ports. */
-    asc_queue_t          active;                /* Active command queue */
-    asc_queue_t          waiting;               /* Waiting command queue */
-    asc_queue_t          done;                  /* Done command queue */
-    ADV_SCSI_BIT_ID_TYPE init_tidmask;          /* Target init./valid mask */
-    struct scsi_device	*device[ADV_MAX_TID+1]; /* Mid-Level Scsi Device */
-    ushort               reqcnt[ADV_MAX_TID+1]; /* Starvation request count */
-    ADV_SCSI_BIT_ID_TYPE queue_full;            /* Queue full mask */
-    ushort               queue_full_cnt[ADV_MAX_TID+1]; /* Queue full count */
-    union {
-        ASCEEP_CONFIG         asc_eep;          /* Narrow EEPROM config. */
-        ADVEEP_3550_CONFIG    adv_3550_eep;     /* 3550 EEPROM config. */
-        ADVEEP_38C0800_CONFIG adv_38C0800_eep;  /* 38C0800 EEPROM config. */
-        ADVEEP_38C1600_CONFIG adv_38C1600_eep;  /* 38C1600 EEPROM config. */
-    } eep_config;
-    ulong                last_reset;            /* Saved last reset time */
-    spinlock_t lock;                            /* Board spinlock */
+	int id;			/* Board Id */
+	uint flags;		/* Board flags */
+	union {
+		ASC_DVC_VAR asc_dvc_var;	/* Narrow board */
+		ADV_DVC_VAR adv_dvc_var;	/* Wide board */
+	} dvc_var;
+	union {
+		ASC_DVC_CFG asc_dvc_cfg;	/* Narrow board */
+		ADV_DVC_CFG adv_dvc_cfg;	/* Wide board */
+	} dvc_cfg;
+	ushort asc_n_io_port;	/* Number I/O ports. */
+	asc_queue_t active;	/* Active command queue */
+	asc_queue_t waiting;	/* Waiting command queue */
+	asc_queue_t done;	/* Done command queue */
+	ADV_SCSI_BIT_ID_TYPE init_tidmask;	/* Target init./valid mask */
+	struct scsi_device *device[ADV_MAX_TID + 1];	/* Mid-Level Scsi Device */
+	ushort reqcnt[ADV_MAX_TID + 1];	/* Starvation request count */
+	ADV_SCSI_BIT_ID_TYPE queue_full;	/* Queue full mask */
+	ushort queue_full_cnt[ADV_MAX_TID + 1];	/* Queue full count */
+	union {
+		ASCEEP_CONFIG asc_eep;	/* Narrow EEPROM config. */
+		ADVEEP_3550_CONFIG adv_3550_eep;	/* 3550 EEPROM config. */
+		ADVEEP_38C0800_CONFIG adv_38C0800_eep;	/* 38C0800 EEPROM config. */
+		ADVEEP_38C1600_CONFIG adv_38C1600_eep;	/* 38C1600 EEPROM config. */
+	} eep_config;
+	ulong last_reset;	/* Saved last reset time */
+	spinlock_t lock;	/* Board spinlock */
 #ifdef CONFIG_PROC_FS
-    /* /proc/scsi/advansys/[0...] */
-    char                 *prtbuf;               /* /proc print buffer */
-#endif /* CONFIG_PROC_FS */
+	/* /proc/scsi/advansys/[0...] */
+	char *prtbuf;		/* /proc print buffer */
+#endif				/* CONFIG_PROC_FS */
 #ifdef ADVANSYS_STATS
-    struct asc_stats     asc_stats;             /* Board statistics */
-#endif /* ADVANSYS_STATS */
-    /*
-     * The following fields are used only for Narrow Boards.
-     */
-    /* The following three structures must be in DMA-able memory. */
-    ASC_SCSI_REQ_Q       scsireqq;
-    ASC_CAP_INFO         cap_info;
-    ASC_SCSI_INQUIRY     inquiry;
-    uchar                sdtr_data[ASC_MAX_TID+1]; /* SDTR information */
-    /*
-     * The following fields are used only for Wide Boards.
-     */
-    void                 __iomem *ioremap_addr; /* I/O Memory remap address. */
-    ushort               ioport;                /* I/O Port address. */
-    ADV_CARR_T           *orig_carrp;           /* ADV_CARR_T memory block. */
-    adv_req_t            *orig_reqp;            /* adv_req_t memory block. */
-    adv_req_t            *adv_reqp;             /* Request structures. */
-    adv_sgblk_t          *adv_sgblkp;           /* Scatter-gather structures. */
-    ushort               bios_signature;        /* BIOS Signature. */
-    ushort               bios_version;          /* BIOS Version. */
-    ushort               bios_codeseg;          /* BIOS Code Segment. */
-    ushort               bios_codelen;          /* BIOS Code Segment Length. */
+	struct asc_stats asc_stats;	/* Board statistics */
+#endif				/* ADVANSYS_STATS */
+	/*
+	 * The following fields are used only for Narrow Boards.
+	 */
+	/* The following three structures must be in DMA-able memory. */
+	ASC_SCSI_REQ_Q scsireqq;
+	ASC_CAP_INFO cap_info;
+	ASC_SCSI_INQUIRY inquiry;
+	uchar sdtr_data[ASC_MAX_TID + 1];	/* SDTR information */
+	/*
+	 * The following fields are used only for Wide Boards.
+	 */
+	void __iomem *ioremap_addr;	/* I/O Memory remap address. */
+	ushort ioport;		/* I/O Port address. */
+	ADV_CARR_T *orig_carrp;	/* ADV_CARR_T memory block. */
+	adv_req_t *orig_reqp;	/* adv_req_t memory block. */
+	adv_req_t *adv_reqp;	/* Request structures. */
+	adv_sgblk_t *adv_sgblkp;	/* Scatter-gather structures. */
+	ushort bios_signature;	/* BIOS Signature. */
+	ushort bios_version;	/* BIOS Version. */
+	ushort bios_codeseg;	/* BIOS Code Segment. */
+	ushort bios_codelen;	/* BIOS Code Segment Length. */
 } asc_board_t;
 
 /*
  * PCI configuration structures
  */
-typedef struct _PCI_DATA_
-{
-    uchar    type;
-    uchar    bus;
-    uchar    slot;
-    uchar    func;
-    uchar    offset;
+typedef struct _PCI_DATA_ {
+	uchar type;
+	uchar bus;
+	uchar slot;
+	uchar func;
+	uchar offset;
 } PCI_DATA;
 
-typedef struct _PCI_DEVICE_
-{
-    ushort   vendorID;
-    ushort   deviceID;
-    ushort   slotNumber;
-    ushort   slotFound;
-    uchar    busNumber;
-    uchar    maxBusNumber;
-    uchar    devFunc;
-    ushort   startSlot;
-    ushort   endSlot;
-    uchar    bridge;
-    uchar    type;
+typedef struct _PCI_DEVICE_ {
+	ushort vendorID;
+	ushort deviceID;
+	ushort slotNumber;
+	ushort slotFound;
+	uchar busNumber;
+	uchar maxBusNumber;
+	uchar devFunc;
+	ushort startSlot;
+	ushort endSlot;
+	uchar bridge;
+	uchar type;
 } PCI_DEVICE;
 
-typedef struct _PCI_CONFIG_SPACE_
-{
-    ushort   vendorID;
-    ushort   deviceID;
-    ushort   command;
-    ushort   status;
-    uchar    revision;
-    uchar    classCode[3];
-    uchar    cacheSize;
-    uchar    latencyTimer;
-    uchar    headerType;
-    uchar    bist;
-    ADV_PADDR baseAddress[6];
-    ushort   reserved[4];
-    ADV_PADDR optionRomAddr;
-    ushort   reserved2[4];
-    uchar    irqLine;
-    uchar    irqPin;
-    uchar    minGnt;
-    uchar    maxLatency;
+typedef struct _PCI_CONFIG_SPACE_ {
+	ushort vendorID;
+	ushort deviceID;
+	ushort command;
+	ushort status;
+	uchar revision;
+	uchar classCode[3];
+	uchar cacheSize;
+	uchar latencyTimer;
+	uchar headerType;
+	uchar bist;
+	ADV_PADDR baseAddress[6];
+	ushort reserved[4];
+	ADV_PADDR optionRomAddr;
+	ushort reserved2[4];
+	uchar irqLine;
+	uchar irqPin;
+	uchar minGnt;
+	uchar maxLatency;
 } PCI_CONFIG_SPACE;
 
-
 /*
  * --- Driver Data
  */
@@ -3949,44 +3913,42 @@
 /* Note: All driver global data should be initialized. */
 
 /* Number of boards detected in system. */
-STATIC int asc_board_count = 0;
-STATIC struct Scsi_Host    *asc_host[ASC_NUM_BOARD_SUPPORTED] = { NULL };
+static int asc_board_count = 0;
+static struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { NULL };
 
 /* Overrun buffer used by all narrow boards. */
-STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
+static uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
 
 /*
  * Global structures required to issue a command.
  */
-STATIC ASC_SCSI_Q asc_scsi_q = { { 0 } };
-STATIC ASC_SG_HEAD asc_sg_head = { 0 };
+static ASC_SCSI_Q asc_scsi_q = { {0} };
+static ASC_SG_HEAD asc_sg_head = { 0 };
 
 /* List of supported bus types. */
-STATIC ushort asc_bus[ASC_NUM_BUS] __initdata = {
-    ASC_IS_ISA,
-    ASC_IS_VL,
-    ASC_IS_EISA,
-    ASC_IS_PCI,
+static ushort asc_bus[ASC_NUM_BUS] __initdata = {
+	ASC_IS_ISA,
+	ASC_IS_VL,
+	ASC_IS_EISA,
+	ASC_IS_PCI,
 };
 
-STATIC int asc_iopflag = ASC_FALSE;
-STATIC int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
+static int asc_iopflag = ASC_FALSE;
+static int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
 
 #ifdef ADVANSYS_DEBUG
-STATIC char *
-asc_bus_name[ASC_NUM_BUS] = {
-    "ASC_IS_ISA",
-    "ASC_IS_VL",
-    "ASC_IS_EISA",
-    "ASC_IS_PCI",
+static char *asc_bus_name[ASC_NUM_BUS] = {
+	"ASC_IS_ISA",
+	"ASC_IS_VL",
+	"ASC_IS_EISA",
+	"ASC_IS_PCI",
 };
 
-STATIC int          asc_dbglvl = 3;
+static int asc_dbglvl = 3;
 #endif /* ADVANSYS_DEBUG */
 
 /* Declaration for Asc Library internal data referenced by driver. */
-STATIC PortAddr     _asc_def_iop_base[];
-
+static PortAddr _asc_def_iop_base[];
 
 /*
  * --- Driver Function Prototypes
@@ -3994,62 +3956,61 @@
  * advansys.h contains function prototypes for functions global to Linux.
  */
 
-STATIC irqreturn_t advansys_interrupt(int, void *);
-STATIC int	  advansys_slave_configure(struct scsi_device *);
-STATIC void       asc_scsi_done_list(struct scsi_cmnd *);
-STATIC int        asc_execute_scsi_cmnd(struct scsi_cmnd *);
-STATIC int        asc_build_req(asc_board_t *, struct scsi_cmnd *);
-STATIC int        adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
-STATIC int        adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
-STATIC void       asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
-STATIC void       adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
-STATIC void       adv_async_callback(ADV_DVC_VAR *, uchar);
-STATIC void       asc_enqueue(asc_queue_t *, REQP, int);
-STATIC REQP       asc_dequeue(asc_queue_t *, int);
-STATIC REQP       asc_dequeue_list(asc_queue_t *, REQP *, int);
-STATIC int        asc_rmqueue(asc_queue_t *, REQP);
-STATIC void       asc_execute_queue(asc_queue_t *);
+static irqreturn_t advansys_interrupt(int, void *);
+static int advansys_slave_configure(struct scsi_device *);
+static void asc_scsi_done_list(struct scsi_cmnd *);
+static int asc_execute_scsi_cmnd(struct scsi_cmnd *);
+static int asc_build_req(asc_board_t *, struct scsi_cmnd *);
+static int adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
+static int adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
+static void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
+static void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+static void adv_async_callback(ADV_DVC_VAR *, uchar);
+static void asc_enqueue(asc_queue_t *, REQP, int);
+static REQP asc_dequeue(asc_queue_t *, int);
+static REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
+static int asc_rmqueue(asc_queue_t *, REQP);
+static void asc_execute_queue(asc_queue_t *);
 #ifdef CONFIG_PROC_FS
-STATIC int        asc_proc_copy(off_t, off_t, char *, int , char *, int);
-STATIC int        asc_prt_board_devices(struct Scsi_Host *, char *, int);
-STATIC int        asc_prt_adv_bios(struct Scsi_Host *, char *, int);
-STATIC int        asc_get_eeprom_string(ushort *serialnum, uchar *cp);
-STATIC int        asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
-STATIC int        asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
-STATIC int        asc_prt_driver_conf(struct Scsi_Host *, char *, int);
-STATIC int        asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
-STATIC int        asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
-STATIC int        asc_prt_line(char *, int, char *fmt, ...);
+static int asc_proc_copy(off_t, off_t, char *, int, char *, int);
+static int asc_prt_board_devices(struct Scsi_Host *, char *, int);
+static int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
+static int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
+static int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
+static int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
+static int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
+static int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
+static int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
+static int asc_prt_line(char *, int, char *fmt, ...);
 #endif /* CONFIG_PROC_FS */
 
 /* Declaration for Asc Library internal functions referenced by driver. */
-STATIC int          AscFindSignature(PortAddr);
-STATIC ushort       AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
+static int AscFindSignature(PortAddr);
+static ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
 
 /* Statistics function prototypes. */
 #ifdef ADVANSYS_STATS
 #ifdef CONFIG_PROC_FS
-STATIC int          asc_prt_board_stats(struct Scsi_Host *, char *, int);
-STATIC int          asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
+static int asc_prt_board_stats(struct Scsi_Host *, char *, int);
+static int asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
 #endif /* CONFIG_PROC_FS */
 #endif /* ADVANSYS_STATS */
 
 /* Debug function prototypes. */
 #ifdef ADVANSYS_DEBUG
-STATIC void         asc_prt_scsi_host(struct Scsi_Host *);
-STATIC void         asc_prt_scsi_cmnd(struct scsi_cmnd *);
-STATIC void         asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
-STATIC void         asc_prt_asc_dvc_var(ASC_DVC_VAR *);
-STATIC void         asc_prt_asc_scsi_q(ASC_SCSI_Q *);
-STATIC void         asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
-STATIC void         asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
-STATIC void         asc_prt_adv_dvc_var(ADV_DVC_VAR *);
-STATIC void         asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
-STATIC void         asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
-STATIC void         asc_prt_hex(char *f, uchar *, int);
+static void asc_prt_scsi_host(struct Scsi_Host *);
+static void asc_prt_scsi_cmnd(struct scsi_cmnd *);
+static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
+static void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
+static void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
+static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
+static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
+static void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
+static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
+static void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
+static void asc_prt_hex(char *f, uchar *, int);
 #endif /* ADVANSYS_DEBUG */
 
-
 #ifdef CONFIG_PROC_FS
 /*
  * advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
@@ -4073,1391 +4034,212 @@
  */
 static int
 advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
-		off_t offset, int length, int inout)
+		   off_t offset, int length, int inout)
 {
-    struct Scsi_Host    *shp;
-    asc_board_t         *boardp;
-    int                 i;
-    char                *cp;
-    int			cplen;
-    int                 cnt;
-    int                 totcnt;
-    int                 leftlen;
-    char                *curbuf;
-    off_t               advoffset;
+	struct Scsi_Host *shp;
+	asc_board_t *boardp;
+	int i;
+	char *cp;
+	int cplen;
+	int cnt;
+	int totcnt;
+	int leftlen;
+	char *curbuf;
+	off_t advoffset;
 #ifdef ADVANSYS_STATS
-    int                 tgt_id;
+	int tgt_id;
 #endif /* ADVANSYS_STATS */
 
-    ASC_DBG(1, "advansys_proc_info: begin\n");
+	ASC_DBG(1, "advansys_proc_info: begin\n");
 
-    /*
-     * User write not supported.
-     */
-    if (inout == TRUE) {
-        return(-ENOSYS);
-    }
+	/*
+	 * User write not supported.
+	 */
+	if (inout == TRUE) {
+		return (-ENOSYS);
+	}
 
-    /*
-     * User read of /proc/scsi/advansys/[0...] file.
-     */
+	/*
+	 * User read of /proc/scsi/advansys/[0...] file.
+	 */
 
-    /* Find the specified board. */
-    for (i = 0; i < asc_board_count; i++) {
-        if (asc_host[i]->host_no == shost->host_no) {
-            break;
-        }
-    }
-    if (i == asc_board_count) {
-        return(-ENOENT);
-    }
+	/* Find the specified board. */
+	for (i = 0; i < asc_board_count; i++) {
+		if (asc_host[i]->host_no == shost->host_no) {
+			break;
+		}
+	}
+	if (i == asc_board_count) {
+		return (-ENOENT);
+	}
 
-    shp = asc_host[i];
-    boardp = ASC_BOARDP(shp);
+	shp = asc_host[i];
+	boardp = ASC_BOARDP(shp);
 
-    /* Copy read data starting at the beginning of the buffer. */
-    *start = buffer;
-    curbuf = buffer;
-    advoffset = 0;
-    totcnt = 0;
-    leftlen = length;
+	/* Copy read data starting at the beginning of the buffer. */
+	*start = buffer;
+	curbuf = buffer;
+	advoffset = 0;
+	totcnt = 0;
+	leftlen = length;
 
-    /*
-     * Get board configuration information.
-     *
-     * advansys_info() returns the board string from its own static buffer.
-     */
-    cp = (char *) advansys_info(shp);
-    strcat(cp, "\n");
-    cplen = strlen(cp);
-    /* Copy board information. */
-    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-    totcnt += cnt;
-    leftlen -= cnt;
-    if (leftlen == 0) {
-        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-        return totcnt;
-    }
-    advoffset += cplen;
-    curbuf += cnt;
+	/*
+	 * Get board configuration information.
+	 *
+	 * advansys_info() returns the board string from its own static buffer.
+	 */
+	cp = (char *)advansys_info(shp);
+	strcat(cp, "\n");
+	cplen = strlen(cp);
+	/* Copy board information. */
+	cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+	totcnt += cnt;
+	leftlen -= cnt;
+	if (leftlen == 0) {
+		ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+		return totcnt;
+	}
+	advoffset += cplen;
+	curbuf += cnt;
 
-    /*
-     * Display Wide Board BIOS Information.
-     */
-    if (ASC_WIDE_BOARD(boardp)) {
-        cp = boardp->prtbuf;
-        cplen = asc_prt_adv_bios(shp, cp, ASC_PRTBUF_SIZE);
-        ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
-        cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-        totcnt += cnt;
-        leftlen -= cnt;
-        if (leftlen == 0) {
-            ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-            return totcnt;
-        }
-        advoffset += cplen;
-        curbuf += cnt;
-    }
+	/*
+	 * Display Wide Board BIOS Information.
+	 */
+	if (ASC_WIDE_BOARD(boardp)) {
+		cp = boardp->prtbuf;
+		cplen = asc_prt_adv_bios(shp, cp, ASC_PRTBUF_SIZE);
+		ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+		cnt =
+		    asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
+				  cplen);
+		totcnt += cnt;
+		leftlen -= cnt;
+		if (leftlen == 0) {
+			ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+			return totcnt;
+		}
+		advoffset += cplen;
+		curbuf += cnt;
+	}
 
-    /*
-     * Display driver information for each device attached to the board.
-     */
-    cp = boardp->prtbuf;
-    cplen = asc_prt_board_devices(shp, cp, ASC_PRTBUF_SIZE);
-    ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
-    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-    totcnt += cnt;
-    leftlen -= cnt;
-    if (leftlen == 0) {
-        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-        return totcnt;
-    }
-    advoffset += cplen;
-    curbuf += cnt;
+	/*
+	 * Display driver information for each device attached to the board.
+	 */
+	cp = boardp->prtbuf;
+	cplen = asc_prt_board_devices(shp, cp, ASC_PRTBUF_SIZE);
+	ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+	cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+	totcnt += cnt;
+	leftlen -= cnt;
+	if (leftlen == 0) {
+		ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+		return totcnt;
+	}
+	advoffset += cplen;
+	curbuf += cnt;
 
-    /*
-     * Display EEPROM configuration for the board.
-     */
-    cp = boardp->prtbuf;
-    if (ASC_NARROW_BOARD(boardp)) {
-        cplen = asc_prt_asc_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
-    } else {
-        cplen = asc_prt_adv_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
-    }
-    ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
-    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-    totcnt += cnt;
-    leftlen -= cnt;
-    if (leftlen == 0) {
-        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-        return totcnt;
-    }
-    advoffset += cplen;
-    curbuf += cnt;
+	/*
+	 * Display EEPROM configuration for the board.
+	 */
+	cp = boardp->prtbuf;
+	if (ASC_NARROW_BOARD(boardp)) {
+		cplen = asc_prt_asc_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
+	} else {
+		cplen = asc_prt_adv_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
+	}
+	ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+	cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+	totcnt += cnt;
+	leftlen -= cnt;
+	if (leftlen == 0) {
+		ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+		return totcnt;
+	}
+	advoffset += cplen;
+	curbuf += cnt;
 
-    /*
-     * Display driver configuration and information for the board.
-     */
-    cp = boardp->prtbuf;
-    cplen = asc_prt_driver_conf(shp, cp, ASC_PRTBUF_SIZE);
-    ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
-    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-    totcnt += cnt;
-    leftlen -= cnt;
-    if (leftlen == 0) {
-        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-        return totcnt;
-    }
-    advoffset += cplen;
-    curbuf += cnt;
+	/*
+	 * Display driver configuration and information for the board.
+	 */
+	cp = boardp->prtbuf;
+	cplen = asc_prt_driver_conf(shp, cp, ASC_PRTBUF_SIZE);
+	ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+	cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+	totcnt += cnt;
+	leftlen -= cnt;
+	if (leftlen == 0) {
+		ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+		return totcnt;
+	}
+	advoffset += cplen;
+	curbuf += cnt;
 
 #ifdef ADVANSYS_STATS
-    /*
-     * Display driver statistics for the board.
-     */
-    cp = boardp->prtbuf;
-    cplen = asc_prt_board_stats(shp, cp, ASC_PRTBUF_SIZE);
-    ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
-    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-    totcnt += cnt;
-    leftlen -= cnt;
-    if (leftlen == 0) {
-        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-        return totcnt;
-    }
-    advoffset += cplen;
-    curbuf += cnt;
+	/*
+	 * Display driver statistics for the board.
+	 */
+	cp = boardp->prtbuf;
+	cplen = asc_prt_board_stats(shp, cp, ASC_PRTBUF_SIZE);
+	ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
+	cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+	totcnt += cnt;
+	leftlen -= cnt;
+	if (leftlen == 0) {
+		ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+		return totcnt;
+	}
+	advoffset += cplen;
+	curbuf += cnt;
 
-    /*
-     * Display driver statistics for each target.
-     */
-    for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
-      cp = boardp->prtbuf;
-      cplen = asc_prt_target_stats(shp, tgt_id, cp, ASC_PRTBUF_SIZE);
-      ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
-      cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-      totcnt += cnt;
-      leftlen -= cnt;
-      if (leftlen == 0) {
-        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-        return totcnt;
-      }
-      advoffset += cplen;
-      curbuf += cnt;
-    }
+	/*
+	 * Display driver statistics for each target.
+	 */
+	for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
+		cp = boardp->prtbuf;
+		cplen = asc_prt_target_stats(shp, tgt_id, cp, ASC_PRTBUF_SIZE);
+		ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
+		cnt =
+		    asc_proc_copy(advoffset, offset, curbuf, leftlen, cp,
+				  cplen);
+		totcnt += cnt;
+		leftlen -= cnt;
+		if (leftlen == 0) {
+			ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+			return totcnt;
+		}
+		advoffset += cplen;
+		curbuf += cnt;
+	}
 #endif /* ADVANSYS_STATS */
 
-    /*
-     * Display Asc Library dynamic configuration information
-     * for the board.
-     */
-    cp = boardp->prtbuf;
-    if (ASC_NARROW_BOARD(boardp)) {
-        cplen = asc_prt_asc_board_info(shp, cp, ASC_PRTBUF_SIZE);
-    } else {
-        cplen = asc_prt_adv_board_info(shp, cp, ASC_PRTBUF_SIZE);
-    }
-    ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
-    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
-    totcnt += cnt;
-    leftlen -= cnt;
-    if (leftlen == 0) {
-        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
-        return totcnt;
-    }
-    advoffset += cplen;
-    curbuf += cnt;
+	/*
+	 * Display Asc Library dynamic configuration information
+	 * for the board.
+	 */
+	cp = boardp->prtbuf;
+	if (ASC_NARROW_BOARD(boardp)) {
+		cplen = asc_prt_asc_board_info(shp, cp, ASC_PRTBUF_SIZE);
+	} else {
+		cplen = asc_prt_adv_board_info(shp, cp, ASC_PRTBUF_SIZE);
+	}
+	ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+	cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+	totcnt += cnt;
+	leftlen -= cnt;
+	if (leftlen == 0) {
+		ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+		return totcnt;
+	}
+	advoffset += cplen;
+	curbuf += cnt;
 
-    ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+	ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
 
-    return totcnt;
+	return totcnt;
 }
 #endif /* CONFIG_PROC_FS */
 
 /*
- * advansys_detect()
- *
- * Detect function for AdvanSys adapters.
- *
- * Argument is a pointer to the host driver's scsi_hosts entry.
- *
- * Return number of adapters found.
- *
- * Note: Because this function is called during system initialization
- * it must not call SCSI mid-level functions including scsi_malloc()
- * and scsi_free().
- */
-static int __init
-advansys_detect(struct scsi_host_template *tpnt)
-{
-    static int          detect_called = ASC_FALSE;
-    int                 iop;
-    int                 bus;
-    struct Scsi_Host    *shp = NULL;
-    asc_board_t         *boardp = NULL;
-    ASC_DVC_VAR         *asc_dvc_varp = NULL;
-    ADV_DVC_VAR         *adv_dvc_varp = NULL;
-    adv_sgblk_t         *sgp = NULL;
-    int                 ioport = 0;
-    int                 share_irq = FALSE;
-    int                 iolen = 0;
-    struct device	*dev = NULL;
-#ifdef CONFIG_PCI
-    int                 pci_init_search = 0;
-    struct pci_dev      *pci_devicep[ASC_NUM_BOARD_SUPPORTED];
-    int                 pci_card_cnt_max = 0;
-    int                 pci_card_cnt = 0;
-    struct pci_dev      *pci_devp = NULL;
-    int                 pci_device_id_cnt = 0;
-    unsigned int        pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
-                                    PCI_DEVICE_ID_ASP_1200A,
-                                    PCI_DEVICE_ID_ASP_ABP940,
-                                    PCI_DEVICE_ID_ASP_ABP940U,
-                                    PCI_DEVICE_ID_ASP_ABP940UW,
-                                    PCI_DEVICE_ID_38C0800_REV1,
-                                    PCI_DEVICE_ID_38C1600_REV1
-                        };
-    ADV_PADDR           pci_memory_address;
-#endif /* CONFIG_PCI */
-    int                 warn_code, err_code;
-    int                 ret;
-
-    if (detect_called == ASC_FALSE) {
-        detect_called = ASC_TRUE;
-    } else {
-        printk("AdvanSys SCSI: advansys_detect() multiple calls ignored\n");
-        return 0;
-    }
-
-    ASC_DBG(1, "advansys_detect: begin\n");
-
-    asc_board_count = 0;
-
-    /*
-     * If I/O port probing has been modified, then verify and
-     * clean-up the 'asc_ioport' list.
-     */
-    if (asc_iopflag == ASC_TRUE) {
-        for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
-            ASC_DBG2(1, "advansys_detect: asc_ioport[%d] 0x%x\n",
-                ioport, asc_ioport[ioport]);
-            if (asc_ioport[ioport] != 0) {
-                for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX; iop++) {
-                    if (_asc_def_iop_base[iop] == asc_ioport[ioport]) {
-                        break;
-                    }
-                }
-                if (iop == ASC_IOADR_TABLE_MAX_IX) {
-                    printk(
-"AdvanSys SCSI: specified I/O Port 0x%X is invalid\n",
-                        asc_ioport[ioport]);
-                    asc_ioport[ioport] = 0;
-                }
-            }
-        }
-        ioport = 0;
-    }
-
-    for (bus = 0; bus < ASC_NUM_BUS; bus++) {
-
-        ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n",
-            bus, asc_bus_name[bus]);
-        iop = 0;
-
-        while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) {
-
-            ASC_DBG1(2, "advansys_detect: asc_board_count %d\n",
-                asc_board_count);
-
-            switch (asc_bus[bus]) {
-            case ASC_IS_ISA:
-            case ASC_IS_VL:
-#ifdef CONFIG_ISA
-                if (asc_iopflag == ASC_FALSE) {
-                    iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
-                } else {
-                    /*
-                     * ISA and VL I/O port scanning has either been
-                     * eliminated or limited to selected ports on
-                     * the LILO command line, /etc/lilo.conf, or
-                     * by setting variables when the module was loaded.
-                     */
-                    ASC_DBG(1, "advansys_detect: I/O port scanning modified\n");
-                ioport_try_again:
-                    iop = 0;
-                    for (; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
-                        if ((iop = asc_ioport[ioport]) != 0) {
-                            break;
-                        }
-                    }
-                    if (iop) {
-                        ASC_DBG1(1,
-                                "advansys_detect: probing I/O port 0x%x...\n",
-                            iop);
-			if (!request_region(iop, ASC_IOADR_GAP, "advansys")){
-                            printk(
-"AdvanSys SCSI: specified I/O Port 0x%X is busy\n", iop);
-                            /* Don't try this I/O port twice. */
-                            asc_ioport[ioport] = 0;
-                            goto ioport_try_again;
-                        } else if (AscFindSignature(iop) == ASC_FALSE) {
-                            printk(
-"AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n", iop);
-                            /* Don't try this I/O port twice. */
-			    release_region(iop, ASC_IOADR_GAP);
-                            asc_ioport[ioport] = 0;
-                            goto ioport_try_again;
-                        } else {
-                            /*
-                             * If this isn't an ISA board, then it must be
-                             * a VL board. If currently looking an ISA
-                             * board is being looked for then try for
-                             * another ISA board in 'asc_ioport'.
-                             */
-                            if (asc_bus[bus] == ASC_IS_ISA &&
-                                (AscGetChipVersion(iop, ASC_IS_ISA) &
-                                 ASC_CHIP_VER_ISA_BIT) == 0) {
-                                 /*
-                                  * Don't clear 'asc_ioport[ioport]'. Try
-                                  * this board again for VL. Increment
-                                  * 'ioport' past this board.
-                                  */
-                                 ioport++;
-				 release_region(iop, ASC_IOADR_GAP);
-                                 goto ioport_try_again;
-                            }
-                        }
-                        /*
-                         * This board appears good, don't try the I/O port
-                         * again by clearing its value. Increment 'ioport'
-                         * for the next iteration.
-                         */
-                        asc_ioport[ioport++] = 0;
-                    }
-                }
-#endif /* CONFIG_ISA */
-                break;
-
-            case ASC_IS_EISA:
-#ifdef CONFIG_ISA
-                iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
-#endif /* CONFIG_ISA */
-                break;
-
-            case ASC_IS_PCI:
-#ifdef CONFIG_PCI
-                if (pci_init_search == 0) {
-                    int i, j;
-
-                    pci_init_search = 1;
-
-                    /* Find all PCI cards. */
-                    while (pci_device_id_cnt < ASC_PCI_DEVICE_ID_CNT) {
-                        if ((pci_devp = pci_find_device(PCI_VENDOR_ID_ASP,
-                            pci_device_id[pci_device_id_cnt], pci_devp)) ==
-                            NULL) {
-                            pci_device_id_cnt++;
-                        } else {
-                            if (pci_enable_device(pci_devp) == 0) {
-                                pci_devicep[pci_card_cnt_max++] = pci_devp;
-                            }
-                        }
-                    }
-
-                    /*
-                     * Sort PCI cards in ascending order by PCI Bus, Slot,
-                     * and Device Number.
-                     */
-                    for (i = 0; i < pci_card_cnt_max - 1; i++)
-                    {
-                        for (j = i + 1; j < pci_card_cnt_max; j++) {
-                            if ((pci_devicep[j]->bus->number <
-                                 pci_devicep[i]->bus->number) ||
-                                ((pci_devicep[j]->bus->number ==
-                                  pci_devicep[i]->bus->number) &&
-                                  (pci_devicep[j]->devfn <
-                                   pci_devicep[i]->devfn))) {
-                                pci_devp = pci_devicep[i];
-                                pci_devicep[i] = pci_devicep[j];
-                                pci_devicep[j] = pci_devp;
-                            }
-                        }
-                    }
-
-                    pci_card_cnt = 0;
-                } else {
-                    pci_card_cnt++;
-                }
-
-                if (pci_card_cnt == pci_card_cnt_max) {
-                    iop = 0;
-                } else {
-                    pci_devp = pci_devicep[pci_card_cnt];
-
-                    ASC_DBG2(2,
-                        "advansys_detect: devfn %d, bus number %d\n",
-                        pci_devp->devfn, pci_devp->bus->number);
-                    iop = pci_resource_start(pci_devp, 0);
-                    ASC_DBG2(1,
-                        "advansys_detect: vendorID %X, deviceID %X\n",
-                        pci_devp->vendor, pci_devp->device);
-                    ASC_DBG2(2, "advansys_detect: iop %X, irqLine %d\n",
-                        iop, pci_devp->irq);
-                }
-		if(pci_devp)
-		    dev = &pci_devp->dev;
-
-#endif /* CONFIG_PCI */
-                break;
-
-            default:
-                ASC_PRINT1("advansys_detect: unknown bus type: %d\n",
-                    asc_bus[bus]);
-                break;
-            }
-            ASC_DBG1(1, "advansys_detect: iop 0x%x\n", iop);
-
-            /*
-             * Adapter not found, try next bus type.
-             */
-            if (iop == 0) {
-                break;
-            }
-
-            /*
-             * Adapter found.
-             *
-             * Register the adapter, get its configuration, and
-             * initialize it.
-             */
-            ASC_DBG(2, "advansys_detect: scsi_register()\n");
-            shp = scsi_register(tpnt, sizeof(asc_board_t));
-
-            if (shp == NULL) {
-                continue;
-            }
-
-            /* Save a pointer to the Scsi_Host of each board found. */
-            asc_host[asc_board_count++] = shp;
-
-            /* Initialize private per board data */
-            boardp = ASC_BOARDP(shp);
-            memset(boardp, 0, sizeof(asc_board_t));
-            boardp->id = asc_board_count - 1;
-
-            /* Initialize spinlock. */
-            spin_lock_init(&boardp->lock);
-
-            /*
-             * Handle both narrow and wide boards.
-             *
-             * If a Wide board was detected, set the board structure
-             * wide board flag. Set-up the board structure based on
-             * the board type.
-             */
-#ifdef CONFIG_PCI
-            if (asc_bus[bus] == ASC_IS_PCI &&
-                (pci_devp->device == PCI_DEVICE_ID_ASP_ABP940UW ||
-                 pci_devp->device == PCI_DEVICE_ID_38C0800_REV1 ||
-                 pci_devp->device == PCI_DEVICE_ID_38C1600_REV1))
-            {
-                boardp->flags |= ASC_IS_WIDE_BOARD;
-            }
-#endif /* CONFIG_PCI */
-
-            if (ASC_NARROW_BOARD(boardp)) {
-                ASC_DBG(1, "advansys_detect: narrow board\n");
-                asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
-                asc_dvc_varp->bus_type = asc_bus[bus];
-                asc_dvc_varp->drv_ptr = boardp;
-                asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
-                asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
-                asc_dvc_varp->iop_base = iop;
-                asc_dvc_varp->isr_callback = asc_isr_callback;
-            } else {
-                ASC_DBG(1, "advansys_detect: wide board\n");
-                adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
-                adv_dvc_varp->drv_ptr = boardp;
-                adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
-                adv_dvc_varp->isr_callback = adv_isr_callback;
-                adv_dvc_varp->async_callback = adv_async_callback;
-#ifdef CONFIG_PCI
-                if (pci_devp->device == PCI_DEVICE_ID_ASP_ABP940UW)
-                {
-                    ASC_DBG(1, "advansys_detect: ASC-3550\n");
-                    adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
-                } else if (pci_devp->device == PCI_DEVICE_ID_38C0800_REV1)
-                {
-                    ASC_DBG(1, "advansys_detect: ASC-38C0800\n");
-                    adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
-                } else
-                {
-                    ASC_DBG(1, "advansys_detect: ASC-38C1600\n");
-                    adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
-                }
-#endif /* CONFIG_PCI */
-
-                /*
-                 * Map the board's registers into virtual memory for
-                 * PCI slave access. Only memory accesses are used to
-                 * access the board's registers.
-                 *
-                 * Note: The PCI register base address is not always
-                 * page aligned, but the address passed to ioremap()
-                 * must be page aligned. It is guaranteed that the
-                 * PCI register base address will not cross a page
-                 * boundary.
-                 */
-                if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
-                {
-                    iolen = ADV_3550_IOLEN;
-                } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
-                {
-                    iolen = ADV_38C0800_IOLEN;
-                } else
-                {
-                    iolen = ADV_38C1600_IOLEN;
-                }
-#ifdef CONFIG_PCI
-                pci_memory_address = pci_resource_start(pci_devp, 1);
-                ASC_DBG1(1, "advansys_detect: pci_memory_address: 0x%lx\n",
-                    (ulong) pci_memory_address);
-                if ((boardp->ioremap_addr =
-                    ioremap(pci_memory_address & PAGE_MASK,
-                         PAGE_SIZE)) == 0) {
-                   ASC_PRINT3(
-"advansys_detect: board %d: ioremap(%x, %d) returned NULL\n",
-                       boardp->id, pci_memory_address, iolen);
-                   scsi_unregister(shp);
-                   asc_board_count--;
-                   continue;
-                }
-                ASC_DBG1(1, "advansys_detect: ioremap_addr: 0x%lx\n",
-                    (ulong) boardp->ioremap_addr);
-                adv_dvc_varp->iop_base = (AdvPortAddr)
-                    (boardp->ioremap_addr +
-                     (pci_memory_address - (pci_memory_address & PAGE_MASK)));
-                ASC_DBG1(1, "advansys_detect: iop_base: 0x%lx\n",
-                    adv_dvc_varp->iop_base);
-#endif /* CONFIG_PCI */
-
-                /*
-                 * Even though it isn't used to access wide boards, other
-                 * than for the debug line below, save I/O Port address so
-                 * that it can be reported.
-                 */
-                boardp->ioport = iop;
-
-                ASC_DBG2(1,
-"advansys_detect: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
-                    (ushort) inp(iop + 1), (ushort) inpw(iop));
-            }
-
-#ifdef CONFIG_PROC_FS
-            /*
-             * Allocate buffer for printing information from
-             * /proc/scsi/advansys/[0...].
-             */
-            if ((boardp->prtbuf =
-                kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) {
-                ASC_PRINT3(
-"advansys_detect: board %d: kmalloc(%d, %d) returned NULL\n",
-                    boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC);
-                scsi_unregister(shp);
-                asc_board_count--;
-                continue;
-            }
-#endif /* CONFIG_PROC_FS */
-
-            if (ASC_NARROW_BOARD(boardp)) {
-		asc_dvc_varp->cfg->dev = dev;
-		/*
-                 * Set the board bus type and PCI IRQ before
-                 * calling AscInitGetConfig().
-                 */
-                switch (asc_dvc_varp->bus_type) {
-#ifdef CONFIG_ISA
-                case ASC_IS_ISA:
-                    shp->unchecked_isa_dma = TRUE;
-                    share_irq = FALSE;
-                    break;
-                case ASC_IS_VL:
-                    shp->unchecked_isa_dma = FALSE;
-                    share_irq = FALSE;
-                    break;
-                case ASC_IS_EISA:
-                    shp->unchecked_isa_dma = FALSE;
-                    share_irq = TRUE;
-                    break;
-#endif /* CONFIG_ISA */
-#ifdef CONFIG_PCI
-                case ASC_IS_PCI:
-                    shp->irq = asc_dvc_varp->irq_no = pci_devp->irq;
-                    asc_dvc_varp->cfg->pci_slot_info =
-                        ASC_PCI_MKID(pci_devp->bus->number,
-                            PCI_SLOT(pci_devp->devfn),
-                            PCI_FUNC(pci_devp->devfn));
-                    shp->unchecked_isa_dma = FALSE;
-                    share_irq = TRUE;
-                    break;
-#endif /* CONFIG_PCI */
-                default:
-                    ASC_PRINT2(
-"advansys_detect: board %d: unknown adapter type: %d\n",
-                        boardp->id, asc_dvc_varp->bus_type);
-                    shp->unchecked_isa_dma = TRUE;
-                    share_irq = FALSE;
-                    break;
-                }
-            } else {
-                adv_dvc_varp->cfg->dev = dev;
-                /*
-                 * For Wide boards set PCI information before calling
-                 * AdvInitGetConfig().
-                 */
-#ifdef CONFIG_PCI
-                shp->irq = adv_dvc_varp->irq_no = pci_devp->irq;
-                adv_dvc_varp->cfg->pci_slot_info =
-                    ASC_PCI_MKID(pci_devp->bus->number,
-                        PCI_SLOT(pci_devp->devfn),
-                        PCI_FUNC(pci_devp->devfn));
-                shp->unchecked_isa_dma = FALSE;
-                share_irq = TRUE;
-#endif /* CONFIG_PCI */
-            }
-
-            /*
-             * Read the board configuration.
-             */
-            if (ASC_NARROW_BOARD(boardp)) {
-                 /*
-                  * NOTE: AscInitGetConfig() may change the board's
-                  * bus_type value. The asc_bus[bus] value should no
-                  * longer be used. If the bus_type field must be
-                  * referenced only use the bit-wise AND operator "&".
-                  */
-                ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n");
-                switch(ret = AscInitGetConfig(asc_dvc_varp)) {
-                case 0:    /* No error */
-                    break;
-                case ASC_WARN_IO_PORT_ROTATE:
-                    ASC_PRINT1(
-"AscInitGetConfig: board %d: I/O port address modified\n",
-                        boardp->id);
-                    break;
-                case ASC_WARN_AUTO_CONFIG:
-                    ASC_PRINT1(
-"AscInitGetConfig: board %d: I/O port increment switch enabled\n",
-                        boardp->id);
-                    break;
-                case ASC_WARN_EEPROM_CHKSUM:
-                    ASC_PRINT1(
-"AscInitGetConfig: board %d: EEPROM checksum error\n",
-                        boardp->id);
-                    break;
-                case ASC_WARN_IRQ_MODIFIED:
-                    ASC_PRINT1(
-"AscInitGetConfig: board %d: IRQ modified\n",
-                        boardp->id);
-                    break;
-                case ASC_WARN_CMD_QNG_CONFLICT:
-                    ASC_PRINT1(
-"AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
-                        boardp->id);
-                    break;
-                default:
-                    ASC_PRINT2(
-"AscInitGetConfig: board %d: unknown warning: 0x%x\n",
-                        boardp->id, ret);
-                    break;
-                }
-                if ((err_code = asc_dvc_varp->err_code) != 0) {
-                    ASC_PRINT3(
-"AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
-                        boardp->id, asc_dvc_varp->init_state,
-                        asc_dvc_varp->err_code);
-                }
-            } else {
-                ASC_DBG(2, "advansys_detect: AdvInitGetConfig()\n");
-                if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
-                    ASC_PRINT2("AdvInitGetConfig: board %d: warning: 0x%x\n",
-                        boardp->id, ret);
-                }
-                if ((err_code = adv_dvc_varp->err_code) != 0) {
-                    ASC_PRINT2(
-"AdvInitGetConfig: board %d error: err_code 0x%x\n",
-                        boardp->id, adv_dvc_varp->err_code);
-                }
-            }
-
-            if (err_code != 0) {
-#ifdef CONFIG_PROC_FS
-                kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
-                scsi_unregister(shp);
-                asc_board_count--;
-                continue;
-            }
-
-            /*
-             * Save the EEPROM configuration so that it can be displayed
-             * from /proc/scsi/advansys/[0...].
-             */
-            if (ASC_NARROW_BOARD(boardp)) {
-
-                ASCEEP_CONFIG *ep;
-
-                /*
-                 * Set the adapter's target id bit in the 'init_tidmask' field.
-                 */
-                boardp->init_tidmask |=
-                    ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
-
-                /*
-                 * Save EEPROM settings for the board.
-                 */
-                ep = &boardp->eep_config.asc_eep;
-
-                ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
-                ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
-                ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
-                ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
-                ep->start_motor = asc_dvc_varp->start_motor;
-                ep->cntl = asc_dvc_varp->dvc_cntl;
-                ep->no_scam = asc_dvc_varp->no_scam;
-                ep->max_total_qng = asc_dvc_varp->max_total_qng;
-                ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
-                /* 'max_tag_qng' is set to the same value for every device. */
-                ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
-                ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
-                ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
-                ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
-                ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
-                ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
-                ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
-
-               /*
-                * Modify board configuration.
-                */
-                ASC_DBG(2, "advansys_detect: AscInitSetConfig()\n");
-                switch (ret = AscInitSetConfig(asc_dvc_varp)) {
-                case 0:    /* No error. */
-                    break;
-                case ASC_WARN_IO_PORT_ROTATE:
-                    ASC_PRINT1(
-"AscInitSetConfig: board %d: I/O port address modified\n",
-                        boardp->id);
-                    break;
-                case ASC_WARN_AUTO_CONFIG:
-                    ASC_PRINT1(
-"AscInitSetConfig: board %d: I/O port increment switch enabled\n",
-                        boardp->id);
-                    break;
-                case ASC_WARN_EEPROM_CHKSUM:
-                    ASC_PRINT1(
-"AscInitSetConfig: board %d: EEPROM checksum error\n",
-                        boardp->id);
-                    break;
-                case ASC_WARN_IRQ_MODIFIED:
-                    ASC_PRINT1(
-"AscInitSetConfig: board %d: IRQ modified\n",
-                        boardp->id);
-                    break;
-                case ASC_WARN_CMD_QNG_CONFLICT:
-                    ASC_PRINT1(
-"AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
-                        boardp->id);
-                    break;
-                default:
-                    ASC_PRINT2(
-"AscInitSetConfig: board %d: unknown warning: 0x%x\n",
-                        boardp->id, ret);
-                    break;
-                }
-                if (asc_dvc_varp->err_code != 0) {
-                    ASC_PRINT3(
-"AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
-                        boardp->id, asc_dvc_varp->init_state,
-                        asc_dvc_varp->err_code);
-#ifdef CONFIG_PROC_FS
-                    kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
-                    scsi_unregister(shp);
-                    asc_board_count--;
-                    continue;
-                }
-
-                /*
-                 * Finish initializing the 'Scsi_Host' structure.
-                 */
-                /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
-                if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
-                    shp->irq = asc_dvc_varp->irq_no;
-                }
-            } else {
-                ADVEEP_3550_CONFIG      *ep_3550;
-                ADVEEP_38C0800_CONFIG   *ep_38C0800;
-                ADVEEP_38C1600_CONFIG   *ep_38C1600;
-
-                /*
-                 * Save Wide EEP Configuration Information.
-                 */
-                if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
-                {
-                    ep_3550 = &boardp->eep_config.adv_3550_eep;
-
-                    ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
-                    ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
-                    ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
-                    ep_3550->termination = adv_dvc_varp->cfg->termination;
-                    ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
-                    ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
-                    ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
-                    ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
-                    ep_3550->ultra_able = adv_dvc_varp->ultra_able;
-                    ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
-                    ep_3550->start_motor = adv_dvc_varp->start_motor;
-                    ep_3550->scsi_reset_delay = adv_dvc_varp->scsi_reset_wait;
-                    ep_3550->serial_number_word1 =
-                        adv_dvc_varp->cfg->serial1;
-                    ep_3550->serial_number_word2 =
-                        adv_dvc_varp->cfg->serial2;
-                    ep_3550->serial_number_word3 =
-                        adv_dvc_varp->cfg->serial3;
-                } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
-                {
-                    ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
-
-                    ep_38C0800->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
-                    ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
-                    ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
-                    ep_38C0800->termination_lvd =
-                        adv_dvc_varp->cfg->termination;
-                    ep_38C0800->disc_enable = adv_dvc_varp->cfg->disc_enable;
-                    ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
-                    ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
-                    ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
-                    ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
-                    ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
-                    ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
-                    ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
-                    ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
-                    ep_38C0800->start_motor = adv_dvc_varp->start_motor;
-                    ep_38C0800->scsi_reset_delay =
-                        adv_dvc_varp->scsi_reset_wait;
-                    ep_38C0800->serial_number_word1 =
-                        adv_dvc_varp->cfg->serial1;
-                    ep_38C0800->serial_number_word2 =
-                        adv_dvc_varp->cfg->serial2;
-                    ep_38C0800->serial_number_word3 =
-                        adv_dvc_varp->cfg->serial3;
-                } else
-                {
-                    ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
-
-                    ep_38C1600->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
-                    ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
-                    ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
-                    ep_38C1600->termination_lvd =
-                        adv_dvc_varp->cfg->termination;
-                    ep_38C1600->disc_enable = adv_dvc_varp->cfg->disc_enable;
-                    ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
-                    ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
-                    ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
-                    ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
-                    ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
-                    ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
-                    ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
-                    ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
-                    ep_38C1600->start_motor = adv_dvc_varp->start_motor;
-                    ep_38C1600->scsi_reset_delay =
-                        adv_dvc_varp->scsi_reset_wait;
-                    ep_38C1600->serial_number_word1 =
-                        adv_dvc_varp->cfg->serial1;
-                    ep_38C1600->serial_number_word2 =
-                        adv_dvc_varp->cfg->serial2;
-                    ep_38C1600->serial_number_word3 =
-                        adv_dvc_varp->cfg->serial3;
-                }
-
-                /*
-                 * Set the adapter's target id bit in the 'init_tidmask' field.
-                 */
-                boardp->init_tidmask |=
-                    ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
-
-                /*
-                 * Finish initializing the 'Scsi_Host' structure.
-                 */
-                shp->irq = adv_dvc_varp->irq_no;
-            }
-
-            /*
-             * Channels are numbered beginning with 0. For AdvanSys one host
-             * structure supports one channel. Multi-channel boards have a
-             * separate host structure for each channel.
-             */
-            shp->max_channel = 0;
-            if (ASC_NARROW_BOARD(boardp)) {
-                shp->max_id = ASC_MAX_TID + 1;
-                shp->max_lun = ASC_MAX_LUN + 1;
-
-                shp->io_port = asc_dvc_varp->iop_base;
-                boardp->asc_n_io_port = ASC_IOADR_GAP;
-                shp->this_id = asc_dvc_varp->cfg->chip_scsi_id;
-
-                /* Set maximum number of queues the adapter can handle. */
-                shp->can_queue = asc_dvc_varp->max_total_qng;
-            } else {
-                shp->max_id = ADV_MAX_TID + 1;
-                shp->max_lun = ADV_MAX_LUN + 1;
-
-                /*
-                 * Save the I/O Port address and length even though
-                 * I/O ports are not used to access Wide boards.
-                 * Instead the Wide boards are accessed with
-                 * PCI Memory Mapped I/O.
-                 */
-                shp->io_port = iop;
-                boardp->asc_n_io_port = iolen;
-
-                shp->this_id = adv_dvc_varp->chip_scsi_id;
-
-                /* Set maximum number of queues the adapter can handle. */
-                shp->can_queue = adv_dvc_varp->max_host_qng;
-            }
-
-            /*
-             * 'n_io_port' currently is one byte.
-             *
-             * Set a value to 'n_io_port', but never referenced it because
-             * it may be truncated.
-             */
-            shp->n_io_port = boardp->asc_n_io_port <= 255 ?
-                boardp->asc_n_io_port : 255;
-
-            /*
-             * Following v1.3.89, 'cmd_per_lun' is no longer needed
-             * and should be set to zero.
-             *
-             * But because of a bug introduced in v1.3.89 if the driver is
-             * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
-             * SCSI function 'allocate_device' will panic. To allow the driver
-             * to work as a module in these kernels set 'cmd_per_lun' to 1.
-	     *
-	     * Note: This is wrong.  cmd_per_lun should be set to the depth
-	     * you want on untagged devices always.
-#ifdef MODULE
-             */
-            shp->cmd_per_lun = 1;
-/* #else
-            shp->cmd_per_lun = 0;
-#endif */
-
-            /*
-             * Set the maximum number of scatter-gather elements the
-             * adapter can handle.
-             */
-            if (ASC_NARROW_BOARD(boardp)) {
-                /*
-                 * Allow two commands with 'sg_tablesize' scatter-gather
-                 * elements to be executed simultaneously. This value is
-                 * the theoretical hardware limit. It may be decreased
-                 * below.
-                 */
-                shp->sg_tablesize =
-                    (((asc_dvc_varp->max_total_qng - 2) / 2) *
-                    ASC_SG_LIST_PER_Q) + 1;
-            } else {
-                shp->sg_tablesize = ADV_MAX_SG_LIST;
-            }
-
-            /*
-             * The value of 'sg_tablesize' can not exceed the SCSI
-             * mid-level driver definition of SG_ALL. SG_ALL also
-             * must not be exceeded, because it is used to define the
-             * size of the scatter-gather table in 'struct asc_sg_head'.
-             */
-            if (shp->sg_tablesize > SG_ALL) {
-                shp->sg_tablesize = SG_ALL;
-            }
-
-            ASC_DBG1(1, "advansys_detect: sg_tablesize: %d\n",
-                shp->sg_tablesize);
-
-            /* BIOS start address. */
-            if (ASC_NARROW_BOARD(boardp)) {
-                shp->base =
-                        ((ulong) AscGetChipBiosAddress(
-                            asc_dvc_varp->iop_base,
-                            asc_dvc_varp->bus_type));
-            } else {
-                /*
-                 * Fill-in BIOS board variables. The Wide BIOS saves
-                 * information in LRAM that is used by the driver.
-                 */
-                AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_SIGNATURE,
-                    boardp->bios_signature);
-                AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_VERSION,
-                    boardp->bios_version);
-                AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_CODESEG,
-                    boardp->bios_codeseg);
-                AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_CODELEN,
-                    boardp->bios_codelen);
-
-                ASC_DBG2(1,
-                    "advansys_detect: bios_signature 0x%x, bios_version 0x%x\n",
-                    boardp->bios_signature, boardp->bios_version);
-
-                ASC_DBG2(1,
-                    "advansys_detect: bios_codeseg 0x%x, bios_codelen 0x%x\n",
-                    boardp->bios_codeseg, boardp->bios_codelen);
-
-                /*
-                 * If the BIOS saved a valid signature, then fill in
-                 * the BIOS code segment base address.
-                 */
-                if (boardp->bios_signature == 0x55AA) {
-                    /*
-                     * Convert x86 realmode code segment to a linear
-                     * address by shifting left 4.
-                     */
-                    shp->base = ((ulong) boardp->bios_codeseg << 4);
-                } else {
-                    shp->base = 0;
-                }
-            }
-
-            /*
-             * Register Board Resources - I/O Port, DMA, IRQ
-             */
-
-            /*
-             * Register I/O port range.
-             *
-             * For Wide boards the I/O ports are not used to access
-             * the board, but request the region anyway.
-             *
-             * 'shp->n_io_port' is not referenced, because it may be truncated.
-             */
-            ASC_DBG2(2,
-                "advansys_detect: request_region port 0x%lx, len 0x%x\n",
-                (ulong) shp->io_port, boardp->asc_n_io_port);
-            if (request_region(shp->io_port, boardp->asc_n_io_port,
-                               "advansys") == NULL) {
-                ASC_PRINT3(
-"advansys_detect: board %d: request_region() failed, port 0x%lx, len 0x%x\n",
-                    boardp->id, (ulong) shp->io_port, boardp->asc_n_io_port);
-#ifdef CONFIG_PROC_FS
-                kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
-                scsi_unregister(shp);
-                asc_board_count--;
-                continue;
-            }
-
-            /* Register DMA Channel for Narrow boards. */
-            shp->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
-#ifdef CONFIG_ISA
-            if (ASC_NARROW_BOARD(boardp)) {
-                /* Register DMA channel for ISA bus. */
-                if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
-                    shp->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
-                    if ((ret =
-                         request_dma(shp->dma_channel, "advansys")) != 0) {
-                        ASC_PRINT3(
-"advansys_detect: board %d: request_dma() %d failed %d\n",
-                            boardp->id, shp->dma_channel, ret);
-                        release_region(shp->io_port, boardp->asc_n_io_port);
-#ifdef CONFIG_PROC_FS
-                        kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
-                        scsi_unregister(shp);
-                        asc_board_count--;
-                        continue;
-                    }
-                    AscEnableIsaDma(shp->dma_channel);
-                }
-            }
-#endif /* CONFIG_ISA */
-
-            /* Register IRQ Number. */
-            ASC_DBG1(2, "advansys_detect: request_irq() %d\n", shp->irq);
-           /*
-            * If request_irq() fails with the IRQF_DISABLED flag set,
-            * then try again without the IRQF_DISABLED flag set. This
-            * allows IRQ sharing to work even with other drivers that
-            * do not set the IRQF_DISABLED flag.
-            *
-            * If IRQF_DISABLED is not set, then interrupts are enabled
-            * before the driver interrupt function is called.
-            */
-            if (((ret = request_irq(shp->irq, advansys_interrupt,
-                            IRQF_DISABLED | (share_irq == TRUE ? IRQF_SHARED : 0),
-                            "advansys", boardp)) != 0) &&
-                ((ret = request_irq(shp->irq, advansys_interrupt,
-                            (share_irq == TRUE ? IRQF_SHARED : 0),
-                            "advansys", boardp)) != 0))
-            {
-                if (ret == -EBUSY) {
-                    ASC_PRINT2(
-"advansys_detect: board %d: request_irq(): IRQ 0x%x already in use.\n",
-                        boardp->id, shp->irq);
-                } else if (ret == -EINVAL) {
-                    ASC_PRINT2(
-"advansys_detect: board %d: request_irq(): IRQ 0x%x not valid.\n",
-                        boardp->id, shp->irq);
-                } else {
-                    ASC_PRINT3(
-"advansys_detect: board %d: request_irq(): IRQ 0x%x failed with %d\n",
-                        boardp->id, shp->irq, ret);
-                }
-                release_region(shp->io_port, boardp->asc_n_io_port);
-                iounmap(boardp->ioremap_addr);
-                if (shp->dma_channel != NO_ISA_DMA) {
-                    free_dma(shp->dma_channel);
-                }
-#ifdef CONFIG_PROC_FS
-                kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
-                scsi_unregister(shp);
-                asc_board_count--;
-                continue;
-            }
-
-            /*
-             * Initialize board RISC chip and enable interrupts.
-             */
-            if (ASC_NARROW_BOARD(boardp)) {
-                ASC_DBG(2, "advansys_detect: AscInitAsc1000Driver()\n");
-                warn_code = AscInitAsc1000Driver(asc_dvc_varp);
-                err_code = asc_dvc_varp->err_code;
-
-                if (warn_code || err_code) {
-                    ASC_PRINT4(
-"advansys_detect: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
-                        boardp->id, asc_dvc_varp->init_state,
-                        warn_code, err_code);
-                }
-            } else {
-                ADV_CARR_T      *carrp;
-                int             req_cnt = 0;
-                adv_req_t       *reqp = NULL;
-                int             sg_cnt = 0;
-
-                /*
-                 * Allocate buffer carrier structures. The total size
-                 * is about 4 KB, so allocate all at once.
-                 */
-                carrp =
-                    (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC);
-                ASC_DBG1(1, "advansys_detect: carrp 0x%lx\n", (ulong) carrp);
-
-                if (carrp == NULL) {
-                    goto kmalloc_error;
-                }
-
-                /*
-                 * Allocate up to 'max_host_qng' request structures for
-                 * the Wide board. The total size is about 16 KB, so
-                 * allocate all at once. If the allocation fails decrement
-                 * and try again.
-                 */
-                for (req_cnt = adv_dvc_varp->max_host_qng;
-                    req_cnt > 0; req_cnt--) {
-
-                    reqp = (adv_req_t *)
-                        kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC);
-
-                    ASC_DBG3(1,
-                        "advansys_detect: reqp 0x%lx, req_cnt %d, bytes %lu\n",
-                        (ulong) reqp, req_cnt,
-                        (ulong) sizeof(adv_req_t) * req_cnt);
-
-                    if (reqp != NULL) {
-                        break;
-                    }
-                }
-                if (reqp == NULL)
-                {
-                    goto kmalloc_error;
-                }
-
-                /*
-                 * Allocate up to ADV_TOT_SG_BLOCK request structures for
-                 * the Wide board. Each structure is about 136 bytes.
-                 */
-                boardp->adv_sgblkp = NULL;
-                for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
-
-                    sgp = (adv_sgblk_t *)
-                        kmalloc(sizeof(adv_sgblk_t), GFP_ATOMIC);
-
-                    if (sgp == NULL) {
-                        break;
-                    }
-
-                    sgp->next_sgblkp = boardp->adv_sgblkp;
-                    boardp->adv_sgblkp = sgp;
-
-                }
-                ASC_DBG3(1,
-                    "advansys_detect: sg_cnt %d * %u = %u bytes\n",
-                    sg_cnt, sizeof(adv_sgblk_t),
-                    (unsigned) (sizeof(adv_sgblk_t) * sg_cnt));
-
-                /*
-                 * If no request structures or scatter-gather structures could
-                 * be allocated, then return an error. Otherwise continue with
-                 * initialization.
-                 */
-    kmalloc_error:
-                if (carrp == NULL)
-                {
-                    ASC_PRINT1(
-"advansys_detect: board %d error: failed to kmalloc() carrier buffer.\n",
-                        boardp->id);
-                    err_code = ADV_ERROR;
-                } else if (reqp == NULL) {
-                    kfree(carrp);
-                    ASC_PRINT1(
-"advansys_detect: board %d error: failed to kmalloc() adv_req_t buffer.\n",
-                        boardp->id);
-                    err_code = ADV_ERROR;
-                } else if (boardp->adv_sgblkp == NULL) {
-                    kfree(carrp);
-                    kfree(reqp);
-                    ASC_PRINT1(
-"advansys_detect: board %d error: failed to kmalloc() adv_sgblk_t buffers.\n",
-                        boardp->id);
-                    err_code = ADV_ERROR;
-                } else {
-
-                    /* Save carrier buffer pointer. */
-                    boardp->orig_carrp = carrp;
-
-                    /*
-                     * Save original pointer for kfree() in case the
-                     * driver is built as a module and can be unloaded.
-                     */
-                    boardp->orig_reqp = reqp;
-
-                    adv_dvc_varp->carrier_buf = carrp;
-
-                    /*
-                     * Point 'adv_reqp' to the request structures and
-                     * link them together.
-                     */
-                    req_cnt--;
-                    reqp[req_cnt].next_reqp = NULL;
-                    for (; req_cnt > 0; req_cnt--) {
-                        reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
-                    }
-                    boardp->adv_reqp = &reqp[0];
-
-                    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
-                    {
-                        ASC_DBG(2,
-                            "advansys_detect: AdvInitAsc3550Driver()\n");
-                        warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
-                    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
-                        ASC_DBG(2,
-                            "advansys_detect: AdvInitAsc38C0800Driver()\n");
-                        warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
-                    } else {
-                        ASC_DBG(2,
-                            "advansys_detect: AdvInitAsc38C1600Driver()\n");
-                        warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
-                    }
-                    err_code = adv_dvc_varp->err_code;
-
-                    if (warn_code || err_code) {
-                        ASC_PRINT3(
-"advansys_detect: board %d error: warn 0x%x, error 0x%x\n",
-                            boardp->id, warn_code, err_code);
-                    }
-                }
-            }
-
-            if (err_code != 0) {
-                release_region(shp->io_port, boardp->asc_n_io_port);
-                if (ASC_WIDE_BOARD(boardp)) {
-                    iounmap(boardp->ioremap_addr);
-                    kfree(boardp->orig_carrp);
-                    boardp->orig_carrp = NULL;
-                    if (boardp->orig_reqp) {
-                        kfree(boardp->orig_reqp);
-                        boardp->orig_reqp = boardp->adv_reqp = NULL;
-                    }
-                    while ((sgp = boardp->adv_sgblkp) != NULL)
-                    {
-                        boardp->adv_sgblkp = sgp->next_sgblkp;
-                        kfree(sgp);
-                    }
-                }
-                if (shp->dma_channel != NO_ISA_DMA) {
-                    free_dma(shp->dma_channel);
-                }
-#ifdef CONFIG_PROC_FS
-                kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
-                free_irq(shp->irq, boardp);
-                scsi_unregister(shp);
-                asc_board_count--;
-                continue;
-            }
-            ASC_DBG_PRT_SCSI_HOST(2, shp);
-        }
-    }
-
-    ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n", asc_board_count);
-    return asc_board_count;
-}
-
-/*
- * advansys_release()
- *
- * Release resources allocated for a single AdvanSys adapter.
- */
-static int
-advansys_release(struct Scsi_Host *shp)
-{
-    asc_board_t    *boardp;
-
-    ASC_DBG(1, "advansys_release: begin\n");
-    boardp = ASC_BOARDP(shp);
-    free_irq(shp->irq, boardp);
-    if (shp->dma_channel != NO_ISA_DMA) {
-        ASC_DBG(1, "advansys_release: free_dma()\n");
-        free_dma(shp->dma_channel);
-    }
-    release_region(shp->io_port, boardp->asc_n_io_port);
-    if (ASC_WIDE_BOARD(boardp)) {
-        adv_sgblk_t    *sgp = NULL;
-
-        iounmap(boardp->ioremap_addr);
-        kfree(boardp->orig_carrp);
-        boardp->orig_carrp = NULL;
-        if (boardp->orig_reqp) {
-            kfree(boardp->orig_reqp);
-            boardp->orig_reqp = boardp->adv_reqp = NULL;
-        }
-        while ((sgp = boardp->adv_sgblkp) != NULL)
-        {
-            boardp->adv_sgblkp = sgp->next_sgblkp;
-            kfree(sgp);
-        }
-    }
-#ifdef CONFIG_PROC_FS
-    ASC_ASSERT(boardp->prtbuf != NULL);
-    kfree(boardp->prtbuf);
-#endif /* CONFIG_PROC_FS */
-    scsi_unregister(shp);
-    ASC_DBG(1, "advansys_release: end\n");
-    return 0;
-}
-
-/*
  * advansys_info()
  *
  * Return suitable for printing on the console with the argument
@@ -5466,91 +4248,87 @@
  * Note: The information line should not exceed ASC_INFO_SIZE bytes,
  * otherwise the static 'info' array will be overrun.
  */
-static const char *
-advansys_info(struct Scsi_Host *shp)
+static const char *advansys_info(struct Scsi_Host *shost)
 {
-    static char     info[ASC_INFO_SIZE];
-    asc_board_t     *boardp;
-    ASC_DVC_VAR     *asc_dvc_varp;
-    ADV_DVC_VAR     *adv_dvc_varp;
-    char            *busname;
-    int             iolen;
-    char            *widename = NULL;
+	static char info[ASC_INFO_SIZE];
+	asc_board_t *boardp;
+	ASC_DVC_VAR *asc_dvc_varp;
+	ADV_DVC_VAR *adv_dvc_varp;
+	char *busname;
+	int iolen;
+	char *widename = NULL;
 
-    boardp = ASC_BOARDP(shp);
-    if (ASC_NARROW_BOARD(boardp)) {
-        asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
-        ASC_DBG(1, "advansys_info: begin\n");
-        if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
-            if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) == ASC_IS_ISAPNP) {
-                busname = "ISA PnP";
-            } else {
-                busname = "ISA";
-            }
-            /* Don't reference 'shp->n_io_port'; It may be truncated. */
-            sprintf(info,
-"AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
-                ASC_VERSION, busname,
-                (ulong) shp->io_port,
-                (ulong) shp->io_port + boardp->asc_n_io_port - 1,
-                shp->irq, shp->dma_channel);
-        } else {
-            if (asc_dvc_varp->bus_type & ASC_IS_VL) {
-                busname = "VL";
-            } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
-                busname = "EISA";
-            } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
-                if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
-                    == ASC_IS_PCI_ULTRA) {
-                    busname = "PCI Ultra";
-                } else {
-                    busname = "PCI";
-                }
-            } else {
-                busname = "?";
-                ASC_PRINT2( "advansys_info: board %d: unknown bus type %d\n",
-                    boardp->id, asc_dvc_varp->bus_type);
-            }
-            /* Don't reference 'shp->n_io_port'; It may be truncated. */
-            sprintf(info,
-                "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
-                ASC_VERSION, busname,
-                (ulong) shp->io_port,
-                (ulong) shp->io_port + boardp->asc_n_io_port - 1,
-                shp->irq);
-        }
-    } else {
-        /*
-         * Wide Adapter Information
-         *
-         * Memory-mapped I/O is used instead of I/O space to access
-         * the adapter, but display the I/O Port range. The Memory
-         * I/O address is displayed through the driver /proc file.
-         */
-        adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
-        if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
-        {
-            iolen = ADV_3550_IOLEN;
-            widename = "Ultra-Wide";
-        } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
-        {
-            iolen = ADV_38C0800_IOLEN;
-            widename = "Ultra2-Wide";
-        } else
-        {
-            iolen = ADV_38C1600_IOLEN;
-            widename = "Ultra3-Wide";
-        }
-        sprintf(info, "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
-            ASC_VERSION,
-            widename,
-            (ulong) adv_dvc_varp->iop_base,
-            (ulong) adv_dvc_varp->iop_base + iolen - 1,
-            shp->irq);
-    }
-    ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
-    ASC_DBG(1, "advansys_info: end\n");
-    return info;
+	boardp = ASC_BOARDP(shost);
+	if (ASC_NARROW_BOARD(boardp)) {
+		asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+		ASC_DBG(1, "advansys_info: begin\n");
+		if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+			if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) ==
+			    ASC_IS_ISAPNP) {
+				busname = "ISA PnP";
+			} else {
+				busname = "ISA";
+			}
+			/* Don't reference 'shost->n_io_port'; It may be truncated. */
+			sprintf(info,
+				"AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
+				ASC_VERSION, busname,
+				(ulong)shost->io_port,
+				(ulong)shost->io_port + boardp->asc_n_io_port -
+				1, shost->irq, shost->dma_channel);
+		} else {
+			if (asc_dvc_varp->bus_type & ASC_IS_VL) {
+				busname = "VL";
+			} else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
+				busname = "EISA";
+			} else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
+				if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
+				    == ASC_IS_PCI_ULTRA) {
+					busname = "PCI Ultra";
+				} else {
+					busname = "PCI";
+				}
+			} else {
+				busname = "?";
+				ASC_PRINT2
+				    ("advansys_info: board %d: unknown bus type %d\n",
+				     boardp->id, asc_dvc_varp->bus_type);
+			}
+			/* Don't reference 'shost->n_io_port'; It may be truncated. */
+			sprintf(info,
+				"AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
+				ASC_VERSION, busname,
+				(ulong)shost->io_port,
+				(ulong)shost->io_port + boardp->asc_n_io_port -
+				1, shost->irq);
+		}
+	} else {
+		/*
+		 * Wide Adapter Information
+		 *
+		 * Memory-mapped I/O is used instead of I/O space to access
+		 * the adapter, but display the I/O Port range. The Memory
+		 * I/O address is displayed through the driver /proc file.
+		 */
+		adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+		if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+			iolen = ADV_3550_IOLEN;
+			widename = "Ultra-Wide";
+		} else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+			iolen = ADV_38C0800_IOLEN;
+			widename = "Ultra2-Wide";
+		} else {
+			iolen = ADV_38C1600_IOLEN;
+			widename = "Ultra3-Wide";
+		}
+		sprintf(info,
+			"AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
+			ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base,
+			(ulong)adv_dvc_varp->iop_base + iolen - 1, shost->irq);
+	}
+	ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
+	ASC_DBG(1, "advansys_info: end\n");
+	return info;
 }
 
 /*
@@ -5560,82 +4338,82 @@
  * in the 'scp' result field.
  */
 static int
-advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
+advansys_queuecommand(struct scsi_cmnd *scp, void (*done) (struct scsi_cmnd *))
 {
-    struct Scsi_Host    *shp;
-    asc_board_t         *boardp;
-    ulong               flags;
-    struct scsi_cmnd           *done_scp;
+	struct Scsi_Host *shost;
+	asc_board_t *boardp;
+	ulong flags;
+	struct scsi_cmnd *done_scp;
 
-    shp = scp->device->host;
-    boardp = ASC_BOARDP(shp);
-    ASC_STATS(shp, queuecommand);
+	shost = scp->device->host;
+	boardp = ASC_BOARDP(shost);
+	ASC_STATS(shost, queuecommand);
 
-    /* host_lock taken by mid-level prior to call but need to protect */
-    /* against own ISR */
-    spin_lock_irqsave(&boardp->lock, flags);
+	/* host_lock taken by mid-level prior to call but need to protect */
+	/* against own ISR */
+	spin_lock_irqsave(&boardp->lock, flags);
 
-    /*
-     * Block new commands while handling a reset or abort request.
-     */
-    if (boardp->flags & ASC_HOST_IN_RESET) {
-        ASC_DBG1(1,
-            "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
-            (ulong) scp);
-        scp->result = HOST_BYTE(DID_RESET);
+	/*
+	 * Block new commands while handling a reset or abort request.
+	 */
+	if (boardp->flags & ASC_HOST_IN_RESET) {
+		ASC_DBG1(1,
+			 "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
+			 (ulong)scp);
+		scp->result = HOST_BYTE(DID_RESET);
 
-        /*
-         * Add blocked requests to the board's 'done' queue. The queued
-         * requests will be completed at the end of the abort or reset
-         * handling.
-         */
-        asc_enqueue(&boardp->done, scp, ASC_BACK);
+		/*
+		 * Add blocked requests to the board's 'done' queue. The queued
+		 * requests will be completed at the end of the abort or reset
+		 * handling.
+		 */
+		asc_enqueue(&boardp->done, scp, ASC_BACK);
+		spin_unlock_irqrestore(&boardp->lock, flags);
+		return 0;
+	}
+
+	/*
+	 * Attempt to execute any waiting commands for the board.
+	 */
+	if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+		ASC_DBG(1,
+			"advansys_queuecommand: before asc_execute_queue() waiting\n");
+		asc_execute_queue(&boardp->waiting);
+	}
+
+	/*
+	 * Save the function pointer to Linux mid-level 'done' function
+	 * and attempt to execute the command.
+	 *
+	 * If ASC_NOERROR is returned the request has been added to the
+	 * board's 'active' queue and will be completed by the interrupt
+	 * handler.
+	 *
+	 * If ASC_BUSY is returned add the request to the board's per
+	 * target waiting list. This is the first time the request has
+	 * been tried. Add it to the back of the waiting list. It will be
+	 * retried later.
+	 *
+	 * If an error occurred, the request will have been placed on the
+	 * board's 'done' queue and must be completed before returning.
+	 */
+	scp->scsi_done = done;
+	switch (asc_execute_scsi_cmnd(scp)) {
+	case ASC_NOERROR:
+		break;
+	case ASC_BUSY:
+		asc_enqueue(&boardp->waiting, scp, ASC_BACK);
+		break;
+	case ASC_ERROR:
+	default:
+		done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
+		/* Interrupts could be enabled here. */
+		asc_scsi_done_list(done_scp);
+		break;
+	}
 	spin_unlock_irqrestore(&boardp->lock, flags);
-        return 0;
-    }
 
-    /*
-     * Attempt to execute any waiting commands for the board.
-     */
-    if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
-        ASC_DBG(1,
-            "advansys_queuecommand: before asc_execute_queue() waiting\n");
-        asc_execute_queue(&boardp->waiting);
-    }
-
-    /*
-     * Save the function pointer to Linux mid-level 'done' function
-     * and attempt to execute the command.
-     *
-     * If ASC_NOERROR is returned the request has been added to the
-     * board's 'active' queue and will be completed by the interrupt
-     * handler.
-     *
-     * If ASC_BUSY is returned add the request to the board's per
-     * target waiting list. This is the first time the request has
-     * been tried. Add it to the back of the waiting list. It will be
-     * retried later.
-     *
-     * If an error occurred, the request will have been placed on the
-     * board's 'done' queue and must be completed before returning.
-     */
-    scp->scsi_done = done;
-    switch (asc_execute_scsi_cmnd(scp)) {
-    case ASC_NOERROR:
-        break;
-    case ASC_BUSY:
-        asc_enqueue(&boardp->waiting, scp, ASC_BACK);
-        break;
-    case ASC_ERROR:
-    default:
-        done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
-        /* Interrupts could be enabled here. */
-        asc_scsi_done_list(done_scp);
-        break;
-    }
-    spin_unlock_irqrestore(&boardp->lock, flags);
-
-    return 0;
+	return 0;
 }
 
 /*
@@ -5647,178 +4425,187 @@
  * sleeping is allowed and no locking other than for host structures is
  * required. Returns SUCCESS or FAILED.
  */
-static int
-advansys_reset(struct scsi_cmnd *scp)
+static int advansys_reset(struct scsi_cmnd *scp)
 {
-    struct Scsi_Host     *shp;
-    asc_board_t          *boardp;
-    ASC_DVC_VAR          *asc_dvc_varp;
-    ADV_DVC_VAR          *adv_dvc_varp;
-    ulong                flags;
-    struct scsi_cmnd            *done_scp = NULL, *last_scp = NULL;
-    struct scsi_cmnd            *tscp, *new_last_scp;
-    int                  status;
-    int                  ret = SUCCESS;
+	struct Scsi_Host *shost;
+	asc_board_t *boardp;
+	ASC_DVC_VAR *asc_dvc_varp;
+	ADV_DVC_VAR *adv_dvc_varp;
+	ulong flags;
+	struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
+	struct scsi_cmnd *tscp, *new_last_scp;
+	int status;
+	int ret = SUCCESS;
 
-    ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong) scp);
+	ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong)scp);
 
 #ifdef ADVANSYS_STATS
-    if (scp->device->host != NULL) {
-        ASC_STATS(scp->device->host, reset);
-    }
+	if (scp->device->host != NULL) {
+		ASC_STATS(scp->device->host, reset);
+	}
 #endif /* ADVANSYS_STATS */
 
-    if ((shp = scp->device->host) == NULL) {
-        scp->result = HOST_BYTE(DID_ERROR);
-        return FAILED;
-    }
+	if ((shost = scp->device->host) == NULL) {
+		scp->result = HOST_BYTE(DID_ERROR);
+		return FAILED;
+	}
 
-    boardp = ASC_BOARDP(shp);
+	boardp = ASC_BOARDP(shost);
 
-    ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
-        boardp->id);
-    /*
-     * Check for re-entrancy.
-     */
-    spin_lock_irqsave(&boardp->lock, flags);
-    if (boardp->flags & ASC_HOST_IN_RESET) {
+	ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
+		   boardp->id);
+	/*
+	 * Check for re-entrancy.
+	 */
+	spin_lock_irqsave(&boardp->lock, flags);
+	if (boardp->flags & ASC_HOST_IN_RESET) {
+		spin_unlock_irqrestore(&boardp->lock, flags);
+		return FAILED;
+	}
+	boardp->flags |= ASC_HOST_IN_RESET;
 	spin_unlock_irqrestore(&boardp->lock, flags);
-        return FAILED;
-    }
-    boardp->flags |= ASC_HOST_IN_RESET;
-    spin_unlock_irqrestore(&boardp->lock, flags);
 
-    if (ASC_NARROW_BOARD(boardp)) {
-        /*
-         * Narrow Board
-         */
-        asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+	if (ASC_NARROW_BOARD(boardp)) {
+		/*
+		 * Narrow Board
+		 */
+		asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
 
-        /*
-         * Reset the chip and SCSI bus.
-         */
-        ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
-        status = AscInitAsc1000Driver(asc_dvc_varp);
+		/*
+		 * Reset the chip and SCSI bus.
+		 */
+		ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
+		status = AscInitAsc1000Driver(asc_dvc_varp);
 
-        /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
-        if (asc_dvc_varp->err_code) {
-            ASC_PRINT2(
-                "advansys_reset: board %d: SCSI bus reset error: 0x%x\n",
-                boardp->id, asc_dvc_varp->err_code);
-            ret = FAILED;
-        } else if (status) {
-            ASC_PRINT2(
-                "advansys_reset: board %d: SCSI bus reset warning: 0x%x\n",
-                boardp->id, status);
-        } else {
-            ASC_PRINT1(
-                "advansys_reset: board %d: SCSI bus reset successful.\n",
-                boardp->id);
-        }
+		/* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
+		if (asc_dvc_varp->err_code) {
+			ASC_PRINT2
+			    ("advansys_reset: board %d: SCSI bus reset error: 0x%x\n",
+			     boardp->id, asc_dvc_varp->err_code);
+			ret = FAILED;
+		} else if (status) {
+			ASC_PRINT2
+			    ("advansys_reset: board %d: SCSI bus reset warning: 0x%x\n",
+			     boardp->id, status);
+		} else {
+			ASC_PRINT1
+			    ("advansys_reset: board %d: SCSI bus reset successful.\n",
+			     boardp->id);
+		}
 
-        ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
-	spin_lock_irqsave(&boardp->lock, flags);
+		ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
+		spin_lock_irqsave(&boardp->lock, flags);
 
-    } else {
-        /*
-         * Wide Board
-         *
-         * If the suggest reset bus flags are set, then reset the bus.
-         * Otherwise only reset the device.
-         */
-        adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+	} else {
+		/*
+		 * Wide Board
+		 *
+		 * If the suggest reset bus flags are set, then reset the bus.
+		 * Otherwise only reset the device.
+		 */
+		adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
 
-        /*
-         * Reset the target's SCSI bus.
-         */
-        ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
-        switch (AdvResetChipAndSB(adv_dvc_varp)) {
-        case ASC_TRUE:
-            ASC_PRINT1("advansys_reset: board %d: SCSI bus reset successful.\n",
-                boardp->id);
-            break;
-        case ASC_FALSE:
-        default:
-            ASC_PRINT1("advansys_reset: board %d: SCSI bus reset error.\n",
-                boardp->id);
-            ret = FAILED;
-            break;
-        }
-	spin_lock_irqsave(&boardp->lock, flags);
-        (void) AdvISR(adv_dvc_varp);
-    }
-    /* Board lock is held. */
+		/*
+		 * Reset the target's SCSI bus.
+		 */
+		ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
+		switch (AdvResetChipAndSB(adv_dvc_varp)) {
+		case ASC_TRUE:
+			ASC_PRINT1
+			    ("advansys_reset: board %d: SCSI bus reset successful.\n",
+			     boardp->id);
+			break;
+		case ASC_FALSE:
+		default:
+			ASC_PRINT1
+			    ("advansys_reset: board %d: SCSI bus reset error.\n",
+			     boardp->id);
+			ret = FAILED;
+			break;
+		}
+		spin_lock_irqsave(&boardp->lock, flags);
+		(void)AdvISR(adv_dvc_varp);
+	}
+	/* Board lock is held. */
 
-    /*
-     * Dequeue all board 'done' requests. A pointer to the last request
-     * is returned in 'last_scp'.
-     */
-    done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
+	/*
+	 * Dequeue all board 'done' requests. A pointer to the last request
+	 * is returned in 'last_scp'.
+	 */
+	done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
 
-    /*
-     * Dequeue all board 'active' requests for all devices and set
-     * the request status to DID_RESET. A pointer to the last request
-     * is returned in 'last_scp'.
-     */
-    if (done_scp == NULL) {
-        done_scp = asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL);
-        for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
-            tscp->result = HOST_BYTE(DID_RESET);
-        }
-    } else {
-        /* Append to 'done_scp' at the end with 'last_scp'. */
-        ASC_ASSERT(last_scp != NULL);
-        last_scp->host_scribble = (unsigned char *)asc_dequeue_list(
-			&boardp->active, &new_last_scp, ASC_TID_ALL);
-        if (new_last_scp != NULL) {
-            ASC_ASSERT(REQPNEXT(last_scp) != NULL);
-            for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
-                tscp->result = HOST_BYTE(DID_RESET);
-            }
-            last_scp = new_last_scp;
-        }
-    }
+	/*
+	 * Dequeue all board 'active' requests for all devices and set
+	 * the request status to DID_RESET. A pointer to the last request
+	 * is returned in 'last_scp'.
+	 */
+	if (done_scp == NULL) {
+		done_scp =
+		    asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL);
+		for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
+			tscp->result = HOST_BYTE(DID_RESET);
+		}
+	} else {
+		/* Append to 'done_scp' at the end with 'last_scp'. */
+		ASC_ASSERT(last_scp != NULL);
+		last_scp->host_scribble =
+		    (unsigned char *)asc_dequeue_list(&boardp->active,
+						      &new_last_scp,
+						      ASC_TID_ALL);
+		if (new_last_scp != NULL) {
+			ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+			for (tscp = REQPNEXT(last_scp); tscp;
+			     tscp = REQPNEXT(tscp)) {
+				tscp->result = HOST_BYTE(DID_RESET);
+			}
+			last_scp = new_last_scp;
+		}
+	}
 
-    /*
-     * Dequeue all 'waiting' requests and set the request status
-     * to DID_RESET.
-     */
-    if (done_scp == NULL) {
-        done_scp = asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL);
-        for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
-            tscp->result = HOST_BYTE(DID_RESET);
-        }
-    } else {
-        /* Append to 'done_scp' at the end with 'last_scp'. */
-        ASC_ASSERT(last_scp != NULL);
-        last_scp->host_scribble = (unsigned char *)asc_dequeue_list(
-			&boardp->waiting, &new_last_scp, ASC_TID_ALL);
-        if (new_last_scp != NULL) {
-            ASC_ASSERT(REQPNEXT(last_scp) != NULL);
-            for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
-                tscp->result = HOST_BYTE(DID_RESET);
-            }
-            last_scp = new_last_scp;
-        }
-    }
+	/*
+	 * Dequeue all 'waiting' requests and set the request status
+	 * to DID_RESET.
+	 */
+	if (done_scp == NULL) {
+		done_scp =
+		    asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL);
+		for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
+			tscp->result = HOST_BYTE(DID_RESET);
+		}
+	} else {
+		/* Append to 'done_scp' at the end with 'last_scp'. */
+		ASC_ASSERT(last_scp != NULL);
+		last_scp->host_scribble =
+		    (unsigned char *)asc_dequeue_list(&boardp->waiting,
+						      &new_last_scp,
+						      ASC_TID_ALL);
+		if (new_last_scp != NULL) {
+			ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+			for (tscp = REQPNEXT(last_scp); tscp;
+			     tscp = REQPNEXT(tscp)) {
+				tscp->result = HOST_BYTE(DID_RESET);
+			}
+			last_scp = new_last_scp;
+		}
+	}
 
-    /* Save the time of the most recently completed reset. */
-    boardp->last_reset = jiffies;
+	/* Save the time of the most recently completed reset. */
+	boardp->last_reset = jiffies;
 
-    /* Clear reset flag. */
-    boardp->flags &= ~ASC_HOST_IN_RESET;
-    spin_unlock_irqrestore(&boardp->lock, flags);
+	/* Clear reset flag. */
+	boardp->flags &= ~ASC_HOST_IN_RESET;
+	spin_unlock_irqrestore(&boardp->lock, flags);
 
-    /*
-     * Complete all the 'done_scp' requests.
-     */
-    if (done_scp != NULL) {
-        asc_scsi_done_list(done_scp);
-    }
+	/*
+	 * Complete all the 'done_scp' requests.
+	 */
+	if (done_scp != NULL) {
+		asc_scsi_done_list(done_scp);
+	}
 
-    ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
+	ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
 
-    return ret;
+	return ret;
 }
 
 /*
@@ -5834,71 +4621,70 @@
  */
 static int
 advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
-		sector_t capacity, int ip[])
+		   sector_t capacity, int ip[])
 {
-    asc_board_t     *boardp;
+	asc_board_t *boardp;
 
-    ASC_DBG(1, "advansys_biosparam: begin\n");
-    ASC_STATS(sdev->host, biosparam);
-    boardp = ASC_BOARDP(sdev->host);
-    if (ASC_NARROW_BOARD(boardp)) {
-        if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
-             ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
-                ip[0] = 255;
-                ip[1] = 63;
-        } else {
-                ip[0] = 64;
-                ip[1] = 32;
-        }
-    } else {
-        if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
-             BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
-                ip[0] = 255;
-                ip[1] = 63;
-        } else {
-                ip[0] = 64;
-                ip[1] = 32;
-        }
-    }
-    ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
-    ASC_DBG(1, "advansys_biosparam: end\n");
-    return 0;
+	ASC_DBG(1, "advansys_biosparam: begin\n");
+	ASC_STATS(sdev->host, biosparam);
+	boardp = ASC_BOARDP(sdev->host);
+	if (ASC_NARROW_BOARD(boardp)) {
+		if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
+		     ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
+			ip[0] = 255;
+			ip[1] = 63;
+		} else {
+			ip[0] = 64;
+			ip[1] = 32;
+		}
+	} else {
+		if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
+		     BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
+			ip[0] = 255;
+			ip[1] = 63;
+		} else {
+			ip[0] = 64;
+			ip[1] = 32;
+		}
+	}
+	ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
+	ASC_DBG(1, "advansys_biosparam: end\n");
+	return 0;
 }
 
-/*
- * --- Loadable Driver Support
- */
+static int __init advansys_detect(struct scsi_host_template *tpnt);
+static int advansys_release(struct Scsi_Host *shp);
 
 static struct scsi_host_template driver_template = {
-    .proc_name                  = "advansys",
+	.proc_name = "advansys",
 #ifdef CONFIG_PROC_FS
-    .proc_info                  = advansys_proc_info,
+	.proc_info = advansys_proc_info,
 #endif
-    .name                       = "advansys",
-    .detect                     = advansys_detect, 
-    .release                    = advansys_release,
-    .info                       = advansys_info,
-    .queuecommand               = advansys_queuecommand,
-    .eh_bus_reset_handler	= advansys_reset,
-    .bios_param                 = advansys_biosparam,
-    .slave_configure		= advansys_slave_configure,
-    /*
-     * Because the driver may control an ISA adapter 'unchecked_isa_dma'
-     * must be set. The flag will be cleared in advansys_detect for non-ISA
-     * adapters. Refer to the comment in scsi_module.c for more information.
-     */
-    .unchecked_isa_dma          = 1,
-    /*
-     * All adapters controlled by this driver are capable of large
-     * scatter-gather lists. According to the mid-level SCSI documentation
-     * this obviates any performance gain provided by setting
-     * 'use_clustering'. But empirically while CPU utilization is increased
-     * by enabling clustering, I/O throughput increases as well.
-     */
-    .use_clustering             = ENABLE_CLUSTERING,
+	.name = "advansys",
+	.detect = advansys_detect,
+	.release = advansys_release,
+	.info = advansys_info,
+	.queuecommand = advansys_queuecommand,
+	.eh_bus_reset_handler = advansys_reset,
+	.bios_param = advansys_biosparam,
+	.slave_configure = advansys_slave_configure,
+	/*
+	 * Because the driver may control an ISA adapter 'unchecked_isa_dma'
+	 * must be set. The flag will be cleared in advansys_detect for non-ISA
+	 * adapters. Refer to the comment in scsi_module.c for more information.
+	 */
+	.unchecked_isa_dma = 1,
+	/*
+	 * All adapters controlled by this driver are capable of large
+	 * scatter-gather lists. According to the mid-level SCSI documentation
+	 * this obviates any performance gain provided by setting
+	 * 'use_clustering'. But empirically while CPU utilization is increased
+	 * by enabling clustering, I/O throughput increases as well.
+	 */
+	.use_clustering = ENABLE_CLUSTERING,
 };
-#include "scsi_module.c"
 
+#include "scsi_module.c"
 
 /*
  * --- Miscellaneous Driver Functions
@@ -5913,130 +4699,138 @@
  * to the AdvanSys driver which is for a device sharing an interrupt with
  * an AdvanSys adapter.
  */
-STATIC irqreturn_t
-advansys_interrupt(int irq, void *dev_id)
+static irqreturn_t advansys_interrupt(int irq, void *dev_id)
 {
-    ulong           flags;
-    int             i;
-    asc_board_t     *boardp;
-    struct scsi_cmnd       *done_scp = NULL, *last_scp = NULL;
-    struct scsi_cmnd       *new_last_scp;
-    struct Scsi_Host *shp;
+	ulong flags;
+	int i;
+	asc_board_t *boardp;
+	struct scsi_cmnd *done_scp = NULL, *last_scp = NULL;
+	struct scsi_cmnd *new_last_scp;
+	struct Scsi_Host *shost;
 
-    ASC_DBG(1, "advansys_interrupt: begin\n");
+	ASC_DBG(1, "advansys_interrupt: begin\n");
 
-    /*
-     * Check for interrupts on all boards.
-     * AscISR() will call asc_isr_callback().
-     */
-    for (i = 0; i < asc_board_count; i++) {
-	shp = asc_host[i];
-        boardp = ASC_BOARDP(shp);
-        ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
-            i, (ulong) boardp);
-        spin_lock_irqsave(&boardp->lock, flags);
-        if (ASC_NARROW_BOARD(boardp)) {
-            /*
-             * Narrow Board
-             */
-            if (AscIsIntPending(shp->io_port)) {
-                ASC_STATS(shp, interrupt);
-                ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
-                AscISR(&boardp->dvc_var.asc_dvc_var);
-            }
-        } else {
-            /*
-             * Wide Board
-             */
-            ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
-            if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
-                ASC_STATS(shp, interrupt);
-            }
-        }
+	/*
+	 * Check for interrupts on all boards.
+	 * AscISR() will call asc_isr_callback().
+	 */
+	for (i = 0; i < asc_board_count; i++) {
+		shost = asc_host[i];
+		boardp = ASC_BOARDP(shost);
+		ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
+			 i, (ulong)boardp);
+		spin_lock_irqsave(&boardp->lock, flags);
+		if (ASC_NARROW_BOARD(boardp)) {
+			/*
+			 * Narrow Board
+			 */
+			if (AscIsIntPending(shost->io_port)) {
+				ASC_STATS(shost, interrupt);
+				ASC_DBG(1,
+					"advansys_interrupt: before AscISR()\n");
+				AscISR(&boardp->dvc_var.asc_dvc_var);
+			}
+		} else {
+			/*
+			 * Wide Board
+			 */
+			ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
+			if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
+				ASC_STATS(shost, interrupt);
+			}
+		}
 
-        /*
-         * Start waiting requests and create a list of completed requests.
-         *
-         * If a reset request is being performed for the board, the reset
-         * handler will complete pending requests after it has completed.
-         */
-        if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
-            ASC_DBG2(1, "advansys_interrupt: done_scp 0x%lx, last_scp 0x%lx\n",
-                (ulong) done_scp, (ulong) last_scp);
+		/*
+		 * Start waiting requests and create a list of completed requests.
+		 *
+		 * If a reset request is being performed for the board, the reset
+		 * handler will complete pending requests after it has completed.
+		 */
+		if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
+			ASC_DBG2(1,
+				 "advansys_interrupt: done_scp 0x%lx, last_scp 0x%lx\n",
+				 (ulong)done_scp, (ulong)last_scp);
 
-            /* Start any waiting commands for the board. */
-            if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
-                ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
-                asc_execute_queue(&boardp->waiting);
-            }
+			/* Start any waiting commands for the board. */
+			if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+				ASC_DBG(1,
+					"advansys_interrupt: before asc_execute_queue()\n");
+				asc_execute_queue(&boardp->waiting);
+			}
 
-             /*
-              * Add to the list of requests that must be completed.
-              *
-              * 'done_scp' will always be NULL on the first iteration
-              * of this loop. 'last_scp' is set at the same time as
-              * 'done_scp'.
-              */
-            if (done_scp == NULL) {
-                done_scp = asc_dequeue_list(&boardp->done, &last_scp,
-                    ASC_TID_ALL);
-            } else {
-                ASC_ASSERT(last_scp != NULL);
-                last_scp->host_scribble = (unsigned char *)asc_dequeue_list(
-			&boardp->done, &new_last_scp, ASC_TID_ALL);
-                if (new_last_scp != NULL) {
-                    ASC_ASSERT(REQPNEXT(last_scp) != NULL);
-                    last_scp = new_last_scp;
-                }
-            }
-        }
-        spin_unlock_irqrestore(&boardp->lock, flags);
-    }
+			/*
+			 * Add to the list of requests that must be completed.
+			 *
+			 * 'done_scp' will always be NULL on the first iteration
+			 * of this loop. 'last_scp' is set at the same time as
+			 * 'done_scp'.
+			 */
+			if (done_scp == NULL) {
+				done_scp =
+				    asc_dequeue_list(&boardp->done, &last_scp,
+						     ASC_TID_ALL);
+			} else {
+				ASC_ASSERT(last_scp != NULL);
+				last_scp->host_scribble =
+				    (unsigned char *)asc_dequeue_list(&boardp->
+								      done,
+								      &new_last_scp,
+								      ASC_TID_ALL);
+				if (new_last_scp != NULL) {
+					ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+					last_scp = new_last_scp;
+				}
+			}
+		}
+		spin_unlock_irqrestore(&boardp->lock, flags);
+	}
 
-    /*
-     * If interrupts were enabled on entry, then they
-     * are now enabled here.
-     *
-     * Complete all requests on the done list.
-     */
+	/*
+	 * If interrupts were enabled on entry, then they
+	 * are now enabled here.
+	 *
+	 * Complete all requests on the done list.
+	 */
 
-    asc_scsi_done_list(done_scp);
+	asc_scsi_done_list(done_scp);
 
-    ASC_DBG(1, "advansys_interrupt: end\n");
-    return IRQ_HANDLED;
+	ASC_DBG(1, "advansys_interrupt: end\n");
+	return IRQ_HANDLED;
 }
 
 /*
  * Set the number of commands to queue per device for the
  * specified host adapter.
  */
-STATIC int
-advansys_slave_configure(struct scsi_device *device)
+static int advansys_slave_configure(struct scsi_device *device)
 {
-    asc_board_t        *boardp;
+	asc_board_t *boardp;
 
-    boardp = ASC_BOARDP(device->host);
-    boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
-    /*
-     * Save a pointer to the device and set its initial/maximum
-     * queue depth.  Only save the pointer for a lun0 dev though.
-     */
-    if(device->lun == 0)
-        boardp->device[device->id] = device;
-    if(device->tagged_supported) {
-        if (ASC_NARROW_BOARD(boardp)) {
-	    scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
-                boardp->dvc_var.asc_dvc_var.max_dvc_qng[device->id]);
-        } else {
-	    scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
-                boardp->dvc_var.adv_dvc_var.max_dvc_qng);
-        }
-    } else {
-	scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
-    }
-    ASC_DBG4(1, "advansys_slave_configure: device 0x%lx, boardp 0x%lx, id %d, depth %d\n",
-            (ulong) device, (ulong) boardp, device->id, device->queue_depth);
-    return 0;
+	boardp = ASC_BOARDP(device->host);
+	boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
+	/*
+	 * Save a pointer to the device and set its initial/maximum
+	 * queue depth.  Only save the pointer for a lun0 dev though.
+	 */
+	if (device->lun == 0)
+		boardp->device[device->id] = device;
+	if (device->tagged_supported) {
+		if (ASC_NARROW_BOARD(boardp)) {
+			scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
+						boardp->dvc_var.asc_dvc_var.
+						max_dvc_qng[device->id]);
+		} else {
+			scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
+						boardp->dvc_var.adv_dvc_var.
+						max_dvc_qng);
+		}
+	} else {
+		scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
+	}
+	ASC_DBG4(1,
+		 "advansys_slave_configure: device 0x%lx, boardp 0x%lx, id %d, depth %d\n",
+		 (ulong)device, (ulong)boardp, device->id, device->queue_depth);
+	return 0;
 }
 
 /*
@@ -6045,43 +4839,44 @@
  *
  * Interrupts can be enabled on entry.
  */
-STATIC void
-asc_scsi_done_list(struct scsi_cmnd *scp)
+static void asc_scsi_done_list(struct scsi_cmnd *scp)
 {
-    struct scsi_cmnd    *tscp;
+	struct scsi_cmnd *tscp;
 
-    ASC_DBG(2, "asc_scsi_done_list: begin\n");
-    while (scp != NULL) {
-	asc_board_t *boardp;
-	struct device *dev;
+	ASC_DBG(2, "asc_scsi_done_list: begin\n");
+	while (scp != NULL) {
+		asc_board_t *boardp;
+		struct device *dev;
 
-        ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong) scp);
-        tscp = REQPNEXT(scp);
-        scp->host_scribble = NULL;
+		ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong)scp);
+		tscp = REQPNEXT(scp);
+		scp->host_scribble = NULL;
 
-	boardp = ASC_BOARDP(scp->device->host);
+		boardp = ASC_BOARDP(scp->device->host);
 
-	if (ASC_NARROW_BOARD(boardp))
-	    dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
-	else
-	    dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
+		if (ASC_NARROW_BOARD(boardp))
+			dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
+		else
+			dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
 
-	if (scp->use_sg)
-	    dma_unmap_sg(dev, (struct scatterlist *)scp->request_buffer,
-			 scp->use_sg, scp->sc_data_direction);
-	else if (scp->request_bufflen)
-	    dma_unmap_single(dev, scp->SCp.dma_handle,
-			     scp->request_bufflen, scp->sc_data_direction);
+		if (scp->use_sg)
+			dma_unmap_sg(dev,
+				     (struct scatterlist *)scp->request_buffer,
+				     scp->use_sg, scp->sc_data_direction);
+		else if (scp->request_bufflen)
+			dma_unmap_single(dev, scp->SCp.dma_handle,
+					 scp->request_bufflen,
+					 scp->sc_data_direction);
 
-        ASC_STATS(scp->device->host, done);
-        ASC_ASSERT(scp->scsi_done != NULL);
+		ASC_STATS(scp->device->host, done);
+		ASC_ASSERT(scp->scsi_done != NULL);
 
-        scp->scsi_done(scp);
+		scp->scsi_done(scp);
 
-        scp = tscp;
-    }
-    ASC_DBG(2, "asc_scsi_done_list: done\n");
-    return;
+		scp = tscp;
+	}
+	ASC_DBG(2, "asc_scsi_done_list: done\n");
+	return;
 }
 
 /*
@@ -6130,168 +4925,170 @@
  * If ASC_BUSY is returned the request will be enqueued by the
  * caller on the target's waiting queue and re-tried later.
  */
-STATIC int
-asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
+static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
 {
-    asc_board_t        *boardp;
-    ASC_DVC_VAR        *asc_dvc_varp;
-    ADV_DVC_VAR        *adv_dvc_varp;
-    ADV_SCSI_REQ_Q     *adv_scsiqp;
-    struct scsi_device *device;
-    int                ret;
+	asc_board_t *boardp;
+	ASC_DVC_VAR *asc_dvc_varp;
+	ADV_DVC_VAR *adv_dvc_varp;
+	ADV_SCSI_REQ_Q *adv_scsiqp;
+	struct scsi_device *device;
+	int ret;
 
-    ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
-        (ulong) scp, (ulong) scp->scsi_done);
+	ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
+		 (ulong)scp, (ulong)scp->scsi_done);
 
-    boardp = ASC_BOARDP(scp->device->host);
-    device = boardp->device[scp->device->id];
+	boardp = ASC_BOARDP(scp->device->host);
+	device = boardp->device[scp->device->id];
 
-    if (ASC_NARROW_BOARD(boardp)) {
-        /*
-         * Build and execute Narrow Board request.
-         */
+	if (ASC_NARROW_BOARD(boardp)) {
+		/*
+		 * Build and execute Narrow Board request.
+		 */
 
-        asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+		asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
 
-        /*
-         * Build Asc Library request structure using the
-         * global structures 'asc_scsi_req' and 'asc_sg_head'.
-         *
-         * If an error is returned, then the request has been
-         * queued on the board done queue. It will be completed
-         * by the caller.
-         *
-         * asc_build_req() can not return ASC_BUSY.
-         */
-        if (asc_build_req(boardp, scp) == ASC_ERROR) {
-            ASC_STATS(scp->device->host, build_error);
-            return ASC_ERROR;
-        }
+		/*
+		 * Build Asc Library request structure using the
+		 * global structures 'asc_scsi_req' and 'asc_sg_head'.
+		 *
+		 * If an error is returned, then the request has been
+		 * queued on the board done queue. It will be completed
+		 * by the caller.
+		 *
+		 * asc_build_req() can not return ASC_BUSY.
+		 */
+		if (asc_build_req(boardp, scp) == ASC_ERROR) {
+			ASC_STATS(scp->device->host, build_error);
+			return ASC_ERROR;
+		}
 
-        /*
-         * Execute the command. If there is no error, add the command
-         * to the active queue.
-         */
-        switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
-        case ASC_NOERROR:
-            ASC_STATS(scp->device->host, exe_noerror);
-            /*
-             * Increment monotonically increasing per device successful
-             * request counter. Wrapping doesn't matter.
-             */
-            boardp->reqcnt[scp->device->id]++;
-            asc_enqueue(&boardp->active, scp, ASC_BACK);
-            ASC_DBG(1,
-                "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
-            break;
-        case ASC_BUSY:
-            /*
-             * Caller will enqueue request on the target's waiting queue
-             * and retry later.
-             */
-            ASC_STATS(scp->device->host, exe_busy);
-            break;
-        case ASC_ERROR:
-            ASC_PRINT2(
-"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
-                boardp->id, asc_dvc_varp->err_code);
-            ASC_STATS(scp->device->host, exe_error);
-            scp->result = HOST_BYTE(DID_ERROR);
-            asc_enqueue(&boardp->done, scp, ASC_BACK);
-            break;
-        default:
-            ASC_PRINT2(
-"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n",
-                boardp->id, asc_dvc_varp->err_code);
-            ASC_STATS(scp->device->host, exe_unknown);
-            scp->result = HOST_BYTE(DID_ERROR);
-            asc_enqueue(&boardp->done, scp, ASC_BACK);
-            break;
-        }
-    } else {
-        /*
-         * Build and execute Wide Board request.
-         */
-        adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+		/*
+		 * Execute the command. If there is no error, add the command
+		 * to the active queue.
+		 */
+		switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
+		case ASC_NOERROR:
+			ASC_STATS(scp->device->host, exe_noerror);
+			/*
+			 * Increment monotonically increasing per device successful
+			 * request counter. Wrapping doesn't matter.
+			 */
+			boardp->reqcnt[scp->device->id]++;
+			asc_enqueue(&boardp->active, scp, ASC_BACK);
+			ASC_DBG(1,
+				"asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
+			break;
+		case ASC_BUSY:
+			/*
+			 * Caller will enqueue request on the target's waiting queue
+			 * and retry later.
+			 */
+			ASC_STATS(scp->device->host, exe_busy);
+			break;
+		case ASC_ERROR:
+			ASC_PRINT2
+			    ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
+			     boardp->id, asc_dvc_varp->err_code);
+			ASC_STATS(scp->device->host, exe_error);
+			scp->result = HOST_BYTE(DID_ERROR);
+			asc_enqueue(&boardp->done, scp, ASC_BACK);
+			break;
+		default:
+			ASC_PRINT2
+			    ("asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n",
+			     boardp->id, asc_dvc_varp->err_code);
+			ASC_STATS(scp->device->host, exe_unknown);
+			scp->result = HOST_BYTE(DID_ERROR);
+			asc_enqueue(&boardp->done, scp, ASC_BACK);
+			break;
+		}
+	} else {
+		/*
+		 * Build and execute Wide Board request.
+		 */
+		adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
 
-        /*
-         * Build and get a pointer to an Adv Library request structure.
-         *
-         * If the request is successfully built then send it below,
-         * otherwise return with an error.
-         */
-        switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
-        case ASC_NOERROR:
-            ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n");
-            break;
-        case ASC_BUSY:
-            ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n");
-            /*
-             * If busy is returned the request has not been enqueued.
-             * It will be enqueued by the caller on the target's waiting
-             * queue and retried later.
-             *
-             * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg'
-             * count wide board busy conditions. They are updated in
-             * adv_build_req and adv_get_sglist, respectively.
-             */
-            return ASC_BUSY;
-        case ASC_ERROR:
-             /* 
-              * If an error is returned, then the request has been
-              * queued on the board done queue. It will be completed
-              * by the caller.
-              */
-        default:
-            ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n");
-            ASC_STATS(scp->device->host, build_error);
-            return ASC_ERROR;
-        }
+		/*
+		 * Build and get a pointer to an Adv Library request structure.
+		 *
+		 * If the request is successfully built then send it below,
+		 * otherwise return with an error.
+		 */
+		switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
+		case ASC_NOERROR:
+			ASC_DBG(3,
+				"asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n");
+			break;
+		case ASC_BUSY:
+			ASC_DBG(1,
+				"asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n");
+			/*
+			 * If busy is returned the request has not been enqueued.
+			 * It will be enqueued by the caller on the target's waiting
+			 * queue and retried later.
+			 *
+			 * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg'
+			 * count wide board busy conditions. They are updated in
+			 * adv_build_req and adv_get_sglist, respectively.
+			 */
+			return ASC_BUSY;
+		case ASC_ERROR:
+			/* 
+			 * If an error is returned, then the request has been
+			 * queued on the board done queue. It will be completed
+			 * by the caller.
+			 */
+		default:
+			ASC_DBG(1,
+				"asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n");
+			ASC_STATS(scp->device->host, build_error);
+			return ASC_ERROR;
+		}
 
-        /*
-         * Execute the command. If there is no error, add the command
-         * to the active queue.
-         */
-        switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
-        case ASC_NOERROR:
-            ASC_STATS(scp->device->host, exe_noerror);
-            /*
-             * Increment monotonically increasing per device successful
-             * request counter. Wrapping doesn't matter.
-             */
-            boardp->reqcnt[scp->device->id]++;
-            asc_enqueue(&boardp->active, scp, ASC_BACK);
-            ASC_DBG(1,
-                "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n");
-            break;
-        case ASC_BUSY:
-            /*
-             * Caller will enqueue request on the target's waiting queue
-             * and retry later.
-             */
-            ASC_STATS(scp->device->host, exe_busy);
-            break;
-        case ASC_ERROR:
-            ASC_PRINT2(
-"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
-                boardp->id, adv_dvc_varp->err_code);
-            ASC_STATS(scp->device->host, exe_error);
-            scp->result = HOST_BYTE(DID_ERROR);
-            asc_enqueue(&boardp->done, scp, ASC_BACK);
-            break;
-        default:
-            ASC_PRINT2(
-"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n",
-                boardp->id, adv_dvc_varp->err_code);
-            ASC_STATS(scp->device->host, exe_unknown);
-            scp->result = HOST_BYTE(DID_ERROR);
-            asc_enqueue(&boardp->done, scp, ASC_BACK);
-            break;
-        }
-    }
+		/*
+		 * Execute the command. If there is no error, add the command
+		 * to the active queue.
+		 */
+		switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
+		case ASC_NOERROR:
+			ASC_STATS(scp->device->host, exe_noerror);
+			/*
+			 * Increment monotonically increasing per device successful
+			 * request counter. Wrapping doesn't matter.
+			 */
+			boardp->reqcnt[scp->device->id]++;
+			asc_enqueue(&boardp->active, scp, ASC_BACK);
+			ASC_DBG(1,
+				"asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n");
+			break;
+		case ASC_BUSY:
+			/*
+			 * Caller will enqueue request on the target's waiting queue
+			 * and retry later.
+			 */
+			ASC_STATS(scp->device->host, exe_busy);
+			break;
+		case ASC_ERROR:
+			ASC_PRINT2
+			    ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
+			     boardp->id, adv_dvc_varp->err_code);
+			ASC_STATS(scp->device->host, exe_error);
+			scp->result = HOST_BYTE(DID_ERROR);
+			asc_enqueue(&boardp->done, scp, ASC_BACK);
+			break;
+		default:
+			ASC_PRINT2
+			    ("asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n",
+			     boardp->id, adv_dvc_varp->err_code);
+			ASC_STATS(scp->device->host, exe_unknown);
+			scp->result = HOST_BYTE(DID_ERROR);
+			asc_enqueue(&boardp->done, scp, ASC_BACK);
+			break;
+		}
+	}
 
-    ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
-    return ret;
+	ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
+	return ret;
 }
 
 /*
@@ -6303,131 +5100,140 @@
  * If an error occurs, then queue the request on the board done
  * queue and return ASC_ERROR.
  */
-STATIC int
-asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
+static int asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
 {
-    struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
+	struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
 
-    /*
-     * Mutually exclusive access is required to 'asc_scsi_q' and
-     * 'asc_sg_head' until after the request is started.
-     */
-    memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
+	/*
+	 * Mutually exclusive access is required to 'asc_scsi_q' and
+	 * 'asc_sg_head' until after the request is started.
+	 */
+	memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
 
-    /*
-     * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
-     */
-    asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
+	/*
+	 * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
+	 */
+	asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
 
-    /*
-     * Build the ASC_SCSI_Q request.
-     *
-     * For narrow boards a CDB length maximum of 12 bytes
-     * is supported.
-     */
-    if (scp->cmd_len > ASC_MAX_CDB_LEN) {
-        ASC_PRINT3(
-"asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN  %d\n",
-            boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN);
-        scp->result = HOST_BYTE(DID_ERROR);
-        asc_enqueue(&boardp->done, scp, ASC_BACK);
-        return ASC_ERROR;
-    }
-    asc_scsi_q.cdbptr = &scp->cmnd[0];
-    asc_scsi_q.q2.cdb_len = scp->cmd_len;
-    asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
-    asc_scsi_q.q1.target_lun = scp->device->lun;
-    asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
-    asc_scsi_q.q1.sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
-    asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
+	/*
+	 * Build the ASC_SCSI_Q request.
+	 *
+	 * For narrow boards a CDB length maximum of 12 bytes
+	 * is supported.
+	 */
+	if (scp->cmd_len > ASC_MAX_CDB_LEN) {
+		ASC_PRINT3
+		    ("asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN  %d\n",
+		     boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN);
+		scp->result = HOST_BYTE(DID_ERROR);
+		asc_enqueue(&boardp->done, scp, ASC_BACK);
+		return ASC_ERROR;
+	}
+	asc_scsi_q.cdbptr = &scp->cmnd[0];
+	asc_scsi_q.q2.cdb_len = scp->cmd_len;
+	asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
+	asc_scsi_q.q1.target_lun = scp->device->lun;
+	asc_scsi_q.q2.target_ix =
+	    ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
+	asc_scsi_q.q1.sense_addr =
+	    cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
+	asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
 
-    /*
-     * If there are any outstanding requests for the current target,
-     * then every 255th request send an ORDERED request. This heuristic
-     * tries to retain the benefit of request sorting while preventing
-     * request starvation. 255 is the max number of tags or pending commands
-     * a device may have outstanding.
-     *
-     * The request count is incremented below for every successfully
-     * started request.
-     *
-     */
-    if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
-        (boardp->reqcnt[scp->device->id] % 255) == 0) {
-        asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
-    } else {
-        asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
-    }
+	/*
+	 * If there are any outstanding requests for the current target,
+	 * then every 255th request send an ORDERED request. This heuristic
+	 * tries to retain the benefit of request sorting while preventing
+	 * request starvation. 255 is the max number of tags or pending commands
+	 * a device may have outstanding.
+	 *
+	 * The request count is incremented below for every successfully
+	 * started request.
+	 *
+	 */
+	if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
+	    (boardp->reqcnt[scp->device->id] % 255) == 0) {
+		asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
+	} else {
+		asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
+	}
 
-    /*
-     * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
-     * buffer command.
-     */
-    if (scp->use_sg == 0) {
-        /*
-         * CDB request of single contiguous buffer.
-         */
-        ASC_STATS(scp->device->host, cont_cnt);
-	scp->SCp.dma_handle = scp->request_bufflen ?
-	    dma_map_single(dev, scp->request_buffer,
-			   scp->request_bufflen, scp->sc_data_direction) : 0;
-	asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
-        asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
-        ASC_STATS_ADD(scp->device->host, cont_xfer,
-                      ASC_CEILING(scp->request_bufflen, 512));
-        asc_scsi_q.q1.sg_queue_cnt = 0;
-        asc_scsi_q.sg_head = NULL;
-    } else {
-        /*
-         * CDB scatter-gather request list.
-         */
-        int                     sgcnt;
-	int			use_sg;
-        struct scatterlist      *slp;
+	/*
+	 * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
+	 * buffer command.
+	 */
+	if (scp->use_sg == 0) {
+		/*
+		 * CDB request of single contiguous buffer.
+		 */
+		ASC_STATS(scp->device->host, cont_cnt);
+		scp->SCp.dma_handle = scp->request_bufflen ?
+		    dma_map_single(dev, scp->request_buffer,
+				   scp->request_bufflen,
+				   scp->sc_data_direction) : 0;
+		asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
+		asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
+		ASC_STATS_ADD(scp->device->host, cont_xfer,
+			      ASC_CEILING(scp->request_bufflen, 512));
+		asc_scsi_q.q1.sg_queue_cnt = 0;
+		asc_scsi_q.sg_head = NULL;
+	} else {
+		/*
+		 * CDB scatter-gather request list.
+		 */
+		int sgcnt;
+		int use_sg;
+		struct scatterlist *slp;
 
-	slp = (struct scatterlist *)scp->request_buffer;
-	use_sg = dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
+		slp = (struct scatterlist *)scp->request_buffer;
+		use_sg =
+		    dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
 
-	if (use_sg > scp->device->host->sg_tablesize) {
-            ASC_PRINT3(
-"asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
-		boardp->id, use_sg, scp->device->host->sg_tablesize);
-	    dma_unmap_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
-            scp->result = HOST_BYTE(DID_ERROR);
-            asc_enqueue(&boardp->done, scp, ASC_BACK);
-            return ASC_ERROR;
-        }
+		if (use_sg > scp->device->host->sg_tablesize) {
+			ASC_PRINT3
+			    ("asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
+			     boardp->id, use_sg,
+			     scp->device->host->sg_tablesize);
+			dma_unmap_sg(dev, slp, scp->use_sg,
+				     scp->sc_data_direction);
+			scp->result = HOST_BYTE(DID_ERROR);
+			asc_enqueue(&boardp->done, scp, ASC_BACK);
+			return ASC_ERROR;
+		}
 
-        ASC_STATS(scp->device->host, sg_cnt);
+		ASC_STATS(scp->device->host, sg_cnt);
 
-        /*
-         * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
-         * structure to point to it.
-         */
-        memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
+		/*
+		 * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
+		 * structure to point to it.
+		 */
+		memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
 
-        asc_scsi_q.q1.cntl |= QC_SG_HEAD;
-        asc_scsi_q.sg_head = &asc_sg_head;
-        asc_scsi_q.q1.data_cnt = 0;
-        asc_scsi_q.q1.data_addr = 0;
-        /* This is a byte value, otherwise it would need to be swapped. */
-	asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
-        ASC_STATS_ADD(scp->device->host, sg_elem, asc_sg_head.entry_cnt);
+		asc_scsi_q.q1.cntl |= QC_SG_HEAD;
+		asc_scsi_q.sg_head = &asc_sg_head;
+		asc_scsi_q.q1.data_cnt = 0;
+		asc_scsi_q.q1.data_addr = 0;
+		/* This is a byte value, otherwise it would need to be swapped. */
+		asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
+		ASC_STATS_ADD(scp->device->host, sg_elem,
+			      asc_sg_head.entry_cnt);
 
-        /*
-         * Convert scatter-gather list into ASC_SG_HEAD list.
-         */
-	for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
-	    asc_sg_head.sg_list[sgcnt].addr = cpu_to_le32(sg_dma_address(slp));
-	    asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(sg_dma_len(slp));
-	    ASC_STATS_ADD(scp->device->host, sg_xfer, ASC_CEILING(sg_dma_len(slp), 512));
-        }
-    }
+		/*
+		 * Convert scatter-gather list into ASC_SG_HEAD list.
+		 */
+		for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
+			asc_sg_head.sg_list[sgcnt].addr =
+			    cpu_to_le32(sg_dma_address(slp));
+			asc_sg_head.sg_list[sgcnt].bytes =
+			    cpu_to_le32(sg_dma_len(slp));
+			ASC_STATS_ADD(scp->device->host, sg_xfer,
+				      ASC_CEILING(sg_dma_len(slp), 512));
+		}
+	}
 
-    ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
-    ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+	ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
+	ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
 
-    return ASC_NOERROR;
+	return ASC_NOERROR;
 }
 
 /*
@@ -6440,162 +5246,168 @@
  * microcode for DMA addresses or math operations are byte swapped
  * to little-endian order.
  */
-STATIC int
+static int
 adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
-    ADV_SCSI_REQ_Q **adv_scsiqpp)
+	      ADV_SCSI_REQ_Q **adv_scsiqpp)
 {
-    adv_req_t           *reqp;
-    ADV_SCSI_REQ_Q      *scsiqp;
-    int                 i;
-    int                 ret;
-    struct device	*dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
+	adv_req_t *reqp;
+	ADV_SCSI_REQ_Q *scsiqp;
+	int i;
+	int ret;
+	struct device *dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
 
-    /*
-     * Allocate an adv_req_t structure from the board to execute
-     * the command.
-     */
-    if (boardp->adv_reqp == NULL) {
-        ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
-        ASC_STATS(scp->device->host, adv_build_noreq);
-        return ASC_BUSY;
-    } else {
-        reqp = boardp->adv_reqp;
-        boardp->adv_reqp = reqp->next_reqp;
-        reqp->next_reqp = NULL;
-    }
-
-    /*
-     * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
-     */
-    scsiqp = (ADV_SCSI_REQ_Q *) ADV_32BALIGN(&reqp->scsi_req_q);
-
-    /*
-     * Initialize the structure.
-     */
-    scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
-
-    /*
-     * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
-     */
-    scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
-
-    /*
-     * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
-     */
-    reqp->cmndp = scp;
-
-    /*
-     * Build the ADV_SCSI_REQ_Q request.
-     */
-
-    /*
-     * Set CDB length and copy it to the request structure.
-     * For wide  boards a CDB length maximum of 16 bytes
-     * is supported.
-     */
-    if (scp->cmd_len > ADV_MAX_CDB_LEN) {
-        ASC_PRINT3(
-"adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN  %d\n",
-            boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
-        scp->result = HOST_BYTE(DID_ERROR);
-        asc_enqueue(&boardp->done, scp, ASC_BACK);
-        return ASC_ERROR;
-    }
-    scsiqp->cdb_len = scp->cmd_len;
-    /* Copy first 12 CDB bytes to cdb[]. */
-    for (i = 0; i < scp->cmd_len && i < 12; i++) {
-        scsiqp->cdb[i] = scp->cmnd[i];
-    }
-    /* Copy last 4 CDB bytes, if present, to cdb16[]. */
-    for (; i < scp->cmd_len; i++) {
-        scsiqp->cdb16[i - 12] = scp->cmnd[i];
-    }
-
-    scsiqp->target_id = scp->device->id;
-    scsiqp->target_lun = scp->device->lun;
-
-    scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
-    scsiqp->sense_len = sizeof(scp->sense_buffer);
-
-    /*
-     * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
-     * buffer command.
-     */
-
-    scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
-    scsiqp->vdata_addr = scp->request_buffer;
-    scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
-
-    if (scp->use_sg == 0) {
-        /*
-         * CDB request of single contiguous buffer.
-         */
-        reqp->sgblkp = NULL;
-	scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
-	if (scp->request_bufflen) {
-	    scsiqp->vdata_addr = scp->request_buffer;
-	    scp->SCp.dma_handle =
-	        dma_map_single(dev, scp->request_buffer,
-			       scp->request_bufflen, scp->sc_data_direction);
+	/*
+	 * Allocate an adv_req_t structure from the board to execute
+	 * the command.
+	 */
+	if (boardp->adv_reqp == NULL) {
+		ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
+		ASC_STATS(scp->device->host, adv_build_noreq);
+		return ASC_BUSY;
 	} else {
-	    scsiqp->vdata_addr = NULL;
-	    scp->SCp.dma_handle = 0;
+		reqp = boardp->adv_reqp;
+		boardp->adv_reqp = reqp->next_reqp;
+		reqp->next_reqp = NULL;
 	}
-	scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
-        scsiqp->sg_list_ptr = NULL;
-        scsiqp->sg_real_addr = 0;
-        ASC_STATS(scp->device->host, cont_cnt);
-        ASC_STATS_ADD(scp->device->host, cont_xfer,
-                      ASC_CEILING(scp->request_bufflen, 512));
-    } else {
-        /*
-         * CDB scatter-gather request list.
-         */
-	struct scatterlist *slp;
-	int use_sg;
 
-	slp = (struct scatterlist *)scp->request_buffer;
-	use_sg = dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
+	/*
+	 * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
+	 */
+	scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
 
-	if (use_sg > ADV_MAX_SG_LIST) {
-            ASC_PRINT3(
-"adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
-		boardp->id, use_sg, scp->device->host->sg_tablesize);
-	    dma_unmap_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
-            scp->result = HOST_BYTE(DID_ERROR);
-            asc_enqueue(&boardp->done, scp, ASC_BACK);
+	/*
+	 * Initialize the structure.
+	 */
+	scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
 
-            /*
-             * Free the 'adv_req_t' structure by adding it back to the
-             * board free list.
-             */
-            reqp->next_reqp = boardp->adv_reqp;
-            boardp->adv_reqp = reqp;
+	/*
+	 * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
+	 */
+	scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
 
-            return ASC_ERROR;
-        }
+	/*
+	 * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
+	 */
+	reqp->cmndp = scp;
 
-	if ((ret = adv_get_sglist(boardp, reqp, scp, use_sg)) != ADV_SUCCESS) {
-            /*
-             * Free the adv_req_t structure by adding it back to the
-             * board free list.
-             */
-            reqp->next_reqp = boardp->adv_reqp;
-            boardp->adv_reqp = reqp;
+	/*
+	 * Build the ADV_SCSI_REQ_Q request.
+	 */
 
-            return ret;
-        }
+	/*
+	 * Set CDB length and copy it to the request structure.
+	 * For wide  boards a CDB length maximum of 16 bytes
+	 * is supported.
+	 */
+	if (scp->cmd_len > ADV_MAX_CDB_LEN) {
+		ASC_PRINT3
+		    ("adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN  %d\n",
+		     boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
+		scp->result = HOST_BYTE(DID_ERROR);
+		asc_enqueue(&boardp->done, scp, ASC_BACK);
+		return ASC_ERROR;
+	}
+	scsiqp->cdb_len = scp->cmd_len;
+	/* Copy first 12 CDB bytes to cdb[]. */
+	for (i = 0; i < scp->cmd_len && i < 12; i++) {
+		scsiqp->cdb[i] = scp->cmnd[i];
+	}
+	/* Copy last 4 CDB bytes, if present, to cdb16[]. */
+	for (; i < scp->cmd_len; i++) {
+		scsiqp->cdb16[i - 12] = scp->cmnd[i];
+	}
 
-        ASC_STATS(scp->device->host, sg_cnt);
-	ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
-    }
+	scsiqp->target_id = scp->device->id;
+	scsiqp->target_lun = scp->device->lun;
 
-    ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
-    ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+	scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
+	scsiqp->sense_len = sizeof(scp->sense_buffer);
 
-    *adv_scsiqpp = scsiqp;
+	/*
+	 * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
+	 * buffer command.
+	 */
 
-    return ASC_NOERROR;
+	scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
+	scsiqp->vdata_addr = scp->request_buffer;
+	scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
+
+	if (scp->use_sg == 0) {
+		/*
+		 * CDB request of single contiguous buffer.
+		 */
+		reqp->sgblkp = NULL;
+		scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
+		if (scp->request_bufflen) {
+			scsiqp->vdata_addr = scp->request_buffer;
+			scp->SCp.dma_handle =
+			    dma_map_single(dev, scp->request_buffer,
+					   scp->request_bufflen,
+					   scp->sc_data_direction);
+		} else {
+			scsiqp->vdata_addr = NULL;
+			scp->SCp.dma_handle = 0;
+		}
+		scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
+		scsiqp->sg_list_ptr = NULL;
+		scsiqp->sg_real_addr = 0;
+		ASC_STATS(scp->device->host, cont_cnt);
+		ASC_STATS_ADD(scp->device->host, cont_xfer,
+			      ASC_CEILING(scp->request_bufflen, 512));
+	} else {
+		/*
+		 * CDB scatter-gather request list.
+		 */
+		struct scatterlist *slp;
+		int use_sg;
+
+		slp = (struct scatterlist *)scp->request_buffer;
+		use_sg =
+		    dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
+
+		if (use_sg > ADV_MAX_SG_LIST) {
+			ASC_PRINT3
+			    ("adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
+			     boardp->id, use_sg,
+			     scp->device->host->sg_tablesize);
+			dma_unmap_sg(dev, slp, scp->use_sg,
+				     scp->sc_data_direction);
+			scp->result = HOST_BYTE(DID_ERROR);
+			asc_enqueue(&boardp->done, scp, ASC_BACK);
+
+			/*
+			 * Free the 'adv_req_t' structure by adding it back to the
+			 * board free list.
+			 */
+			reqp->next_reqp = boardp->adv_reqp;
+			boardp->adv_reqp = reqp;
+
+			return ASC_ERROR;
+		}
+
+		if ((ret =
+		     adv_get_sglist(boardp, reqp, scp,
+				    use_sg)) != ADV_SUCCESS) {
+			/*
+			 * Free the adv_req_t structure by adding it back to the
+			 * board free list.
+			 */
+			reqp->next_reqp = boardp->adv_reqp;
+			boardp->adv_reqp = reqp;
+
+			return ret;
+		}
+
+		ASC_STATS(scp->device->host, sg_cnt);
+		ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
+	}
+
+	ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
+	ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+
+	*adv_scsiqpp = scsiqp;
+
+	return ASC_NOERROR;
 }
 
 /*
@@ -6610,108 +5422,109 @@
  *      ADV_SUCCESS(1) - SG List successfully created
  *      ADV_ERROR(-1) - SG List creation failed
  */
-STATIC int
-adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp, int use_sg)
+static int
+adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp,
+	       int use_sg)
 {
-    adv_sgblk_t         *sgblkp;
-    ADV_SCSI_REQ_Q      *scsiqp;
-    struct scatterlist  *slp;
-    int                 sg_elem_cnt;
-    ADV_SG_BLOCK        *sg_block, *prev_sg_block;
-    ADV_PADDR           sg_block_paddr;
-    int                 i;
+	adv_sgblk_t *sgblkp;
+	ADV_SCSI_REQ_Q *scsiqp;
+	struct scatterlist *slp;
+	int sg_elem_cnt;
+	ADV_SG_BLOCK *sg_block, *prev_sg_block;
+	ADV_PADDR sg_block_paddr;
+	int i;
 
-    scsiqp = (ADV_SCSI_REQ_Q *) ADV_32BALIGN(&reqp->scsi_req_q);
-    slp = (struct scatterlist *) scp->request_buffer;
-    sg_elem_cnt = use_sg;
-    prev_sg_block = NULL;
-    reqp->sgblkp = NULL;
+	scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q);
+	slp = (struct scatterlist *)scp->request_buffer;
+	sg_elem_cnt = use_sg;
+	prev_sg_block = NULL;
+	reqp->sgblkp = NULL;
 
-    do
-    {
-        /*
-         * Allocate a 'adv_sgblk_t' structure from the board free
-         * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
-         * (15) scatter-gather elements.
-         */
-        if ((sgblkp = boardp->adv_sgblkp) == NULL) {
-            ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
-            ASC_STATS(scp->device->host, adv_build_nosg);
+	do {
+		/*
+		 * Allocate a 'adv_sgblk_t' structure from the board free
+		 * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
+		 * (15) scatter-gather elements.
+		 */
+		if ((sgblkp = boardp->adv_sgblkp) == NULL) {
+			ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
+			ASC_STATS(scp->device->host, adv_build_nosg);
 
-            /*
-             * Allocation failed. Free 'adv_sgblk_t' structures already
-             * allocated for the request.
-             */
-            while ((sgblkp = reqp->sgblkp) != NULL)
-            {
-                /* Remove 'sgblkp' from the request list. */
-                reqp->sgblkp = sgblkp->next_sgblkp;
+			/*
+			 * Allocation failed. Free 'adv_sgblk_t' structures already
+			 * allocated for the request.
+			 */
+			while ((sgblkp = reqp->sgblkp) != NULL) {
+				/* Remove 'sgblkp' from the request list. */
+				reqp->sgblkp = sgblkp->next_sgblkp;
 
-                /* Add 'sgblkp' to the board free list. */
-                sgblkp->next_sgblkp = boardp->adv_sgblkp;
-                boardp->adv_sgblkp = sgblkp;
-            }
-            return ASC_BUSY;
-        } else {
-            /* Complete 'adv_sgblk_t' board allocation. */
-            boardp->adv_sgblkp = sgblkp->next_sgblkp;
-            sgblkp->next_sgblkp = NULL;
+				/* Add 'sgblkp' to the board free list. */
+				sgblkp->next_sgblkp = boardp->adv_sgblkp;
+				boardp->adv_sgblkp = sgblkp;
+			}
+			return ASC_BUSY;
+		} else {
+			/* Complete 'adv_sgblk_t' board allocation. */
+			boardp->adv_sgblkp = sgblkp->next_sgblkp;
+			sgblkp->next_sgblkp = NULL;
 
-            /*
-             * Get 8 byte aligned virtual and physical addresses for
-             * the allocated ADV_SG_BLOCK structure.
-             */
-            sg_block = (ADV_SG_BLOCK *) ADV_8BALIGN(&sgblkp->sg_block);
-            sg_block_paddr = virt_to_bus(sg_block);
+			/*
+			 * Get 8 byte aligned virtual and physical addresses for
+			 * the allocated ADV_SG_BLOCK structure.
+			 */
+			sg_block =
+			    (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block);
+			sg_block_paddr = virt_to_bus(sg_block);
 
-            /*
-             * Check if this is the first 'adv_sgblk_t' for the request.
-             */
-            if (reqp->sgblkp == NULL)
-            {
-                /* Request's first scatter-gather block. */
-                reqp->sgblkp = sgblkp;
+			/*
+			 * Check if this is the first 'adv_sgblk_t' for the request.
+			 */
+			if (reqp->sgblkp == NULL) {
+				/* Request's first scatter-gather block. */
+				reqp->sgblkp = sgblkp;
 
-                /*
-                 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
-                 * address pointers.
-                 */
-                scsiqp->sg_list_ptr = sg_block;
-                scsiqp->sg_real_addr = cpu_to_le32(sg_block_paddr);
-            } else
-            {
-                /* Request's second or later scatter-gather block. */
-                sgblkp->next_sgblkp = reqp->sgblkp;
-                reqp->sgblkp = sgblkp;
+				/*
+				 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
+				 * address pointers.
+				 */
+				scsiqp->sg_list_ptr = sg_block;
+				scsiqp->sg_real_addr =
+				    cpu_to_le32(sg_block_paddr);
+			} else {
+				/* Request's second or later scatter-gather block. */
+				sgblkp->next_sgblkp = reqp->sgblkp;
+				reqp->sgblkp = sgblkp;
 
-                /*
-                 * Point the previous ADV_SG_BLOCK structure to
-                 * the newly allocated ADV_SG_BLOCK structure.
-                 */
-                ASC_ASSERT(prev_sg_block != NULL);
-                prev_sg_block->sg_ptr = cpu_to_le32(sg_block_paddr);
-            }
-        }
+				/*
+				 * Point the previous ADV_SG_BLOCK structure to
+				 * the newly allocated ADV_SG_BLOCK structure.
+				 */
+				ASC_ASSERT(prev_sg_block != NULL);
+				prev_sg_block->sg_ptr =
+				    cpu_to_le32(sg_block_paddr);
+			}
+		}
 
-        for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
-        {
-	    sg_block->sg_list[i].sg_addr = cpu_to_le32(sg_dma_address(slp));
-	    sg_block->sg_list[i].sg_count = cpu_to_le32(sg_dma_len(slp));
-	    ASC_STATS_ADD(scp->device->host, sg_xfer, ASC_CEILING(sg_dma_len(slp), 512));
+		for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
+			sg_block->sg_list[i].sg_addr =
+			    cpu_to_le32(sg_dma_address(slp));
+			sg_block->sg_list[i].sg_count =
+			    cpu_to_le32(sg_dma_len(slp));
+			ASC_STATS_ADD(scp->device->host, sg_xfer,
+				      ASC_CEILING(sg_dma_len(slp), 512));
 
-            if (--sg_elem_cnt == 0)
-            {   /* Last ADV_SG_BLOCK and scatter-gather entry. */
-                sg_block->sg_cnt = i + 1;
-                sg_block->sg_ptr = 0L;    /* Last ADV_SG_BLOCK in list. */
-                return ADV_SUCCESS;
-            }
-            slp++;
-        }
-        sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
-        prev_sg_block = sg_block;
-    }
-    while (1);
-    /* NOTREACHED */
+			if (--sg_elem_cnt == 0) {	/* Last ADV_SG_BLOCK and scatter-gather entry. */
+				sg_block->sg_cnt = i + 1;
+				sg_block->sg_ptr = 0L;	/* Last ADV_SG_BLOCK in list. */
+				return ADV_SUCCESS;
+			}
+			slp++;
+		}
+		sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
+		prev_sg_block = sg_block;
+	}
+	while (1);
+	/* NOTREACHED */
 }
 
 /*
@@ -6719,165 +5532,171 @@
  *
  * Interrupt callback function for the Narrow SCSI Asc Library.
  */
-STATIC void
-asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
+static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
 {
-    asc_board_t         *boardp;
-    struct scsi_cmnd           *scp;
-    struct Scsi_Host    *shp;
-    int                 i;
+	asc_board_t *boardp;
+	struct scsi_cmnd *scp;
+	struct Scsi_Host *shost;
+	int i;
 
-    ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
-        (ulong) asc_dvc_varp, (ulong) qdonep);
-    ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
+	ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
+		 (ulong)asc_dvc_varp, (ulong)qdonep);
+	ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
 
-    /*
-     * Get the struct scsi_cmnd structure and Scsi_Host structure for the
-     * command that has been completed.
-     */
-    scp = (struct scsi_cmnd *) ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
-    ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong) scp);
+	/*
+	 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
+	 * command that has been completed.
+	 */
+	scp = (struct scsi_cmnd *)ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
+	ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong)scp);
 
-    if (scp == NULL) {
-        ASC_PRINT("asc_isr_callback: scp is NULL\n");
-        return;
-    }
-    ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+	if (scp == NULL) {
+		ASC_PRINT("asc_isr_callback: scp is NULL\n");
+		return;
+	}
+	ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
 
-    /*
-     * If the request's host pointer is not valid, display a
-     * message and return.
-     */
-    shp = scp->device->host;
-    for (i = 0; i < asc_board_count; i++) {
-        if (asc_host[i] == shp) {
-            break;
-        }
-    }
-    if (i == asc_board_count) {
-        ASC_PRINT2(
-            "asc_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
-            (ulong) scp, (ulong) shp);
-        return;
-    }
+	/*
+	 * If the request's host pointer is not valid, display a
+	 * message and return.
+	 */
+	shost = scp->device->host;
+	for (i = 0; i < asc_board_count; i++) {
+		if (asc_host[i] == shost) {
+			break;
+		}
+	}
+	if (i == asc_board_count) {
+		ASC_PRINT2
+		    ("asc_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
+		     (ulong)scp, (ulong)shost);
+		return;
+	}
 
-    ASC_STATS(shp, callback);
-    ASC_DBG1(1, "asc_isr_callback: shp 0x%lx\n", (ulong) shp);
+	ASC_STATS(shost, callback);
+	ASC_DBG1(1, "asc_isr_callback: shost 0x%lx\n", (ulong)shost);
 
-    /*
-     * If the request isn't found on the active queue, it may
-     * have been removed to handle a reset request.
-     * Display a message and return.
-     */
-    boardp = ASC_BOARDP(shp);
-    ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
-    if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
-        ASC_PRINT2(
-            "asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
-            boardp->id, (ulong) scp);
-        return;
-    }
+	/*
+	 * If the request isn't found on the active queue, it may
+	 * have been removed to handle a reset request.
+	 * Display a message and return.
+	 */
+	boardp = ASC_BOARDP(shost);
+	ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
+	if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
+		ASC_PRINT2
+		    ("asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
+		     boardp->id, (ulong)scp);
+		return;
+	}
 
-    /*
-     * 'qdonep' contains the command's ending status.
-     */
-    switch (qdonep->d3.done_stat) {
-    case QD_NO_ERROR:
-        ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
-        scp->result = 0;
+	/*
+	 * 'qdonep' contains the command's ending status.
+	 */
+	switch (qdonep->d3.done_stat) {
+	case QD_NO_ERROR:
+		ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
+		scp->result = 0;
 
-        /*
-         * If an INQUIRY command completed successfully, then call
-         * the AscInquiryHandling() function to set-up the device.
-         */
-        if (scp->cmnd[0] == INQUIRY && scp->device->lun == 0 &&
-            (scp->request_bufflen - qdonep->remain_bytes) >= 8)
-        {
-            AscInquiryHandling(asc_dvc_varp, scp->device->id & 0x7,
-                (ASC_SCSI_INQUIRY *) scp->request_buffer);
-        }
+		/*
+		 * If an INQUIRY command completed successfully, then call
+		 * the AscInquiryHandling() function to set-up the device.
+		 */
+		if (scp->cmnd[0] == INQUIRY && scp->device->lun == 0 &&
+		    (scp->request_bufflen - qdonep->remain_bytes) >= 8) {
+			AscInquiryHandling(asc_dvc_varp, scp->device->id & 0x7,
+					   (ASC_SCSI_INQUIRY *)scp->
+					   request_buffer);
+		}
 
-        /*
-         * Check for an underrun condition.
-         *
-         * If there was no error and an underrun condition, then
-         * then return the number of underrun bytes.
-         */
-        if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
-            qdonep->remain_bytes <= scp->request_bufflen) {
-            ASC_DBG1(1, "asc_isr_callback: underrun condition %u bytes\n",
-            (unsigned) qdonep->remain_bytes);
-            scp->resid = qdonep->remain_bytes;
-        }
-        break;
+		/*
+		 * Check for an underrun condition.
+		 *
+		 * If there was no error and an underrun condition, then
+		 * then return the number of underrun bytes.
+		 */
+		if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
+		    qdonep->remain_bytes <= scp->request_bufflen) {
+			ASC_DBG1(1,
+				 "asc_isr_callback: underrun condition %u bytes\n",
+				 (unsigned)qdonep->remain_bytes);
+			scp->resid = qdonep->remain_bytes;
+		}
+		break;
 
-    case QD_WITH_ERROR:
-        ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
-        switch (qdonep->d3.host_stat) {
-        case QHSTA_NO_ERROR:
-            if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
-                ASC_DBG(2, "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
-                ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
-                    sizeof(scp->sense_buffer));
-                /*
-                 * Note: The 'status_byte()' macro used by target drivers
-                 * defined in scsi.h shifts the status byte returned by
-                 * host drivers right by 1 bit. This is why target drivers
-                 * also use right shifted status byte definitions. For
-                 * instance target drivers use CHECK_CONDITION, defined to
-                 * 0x1, instead of the SCSI defined check condition value
-                 * of 0x2. Host drivers are supposed to return the status
-                 * byte as it is defined by SCSI.
-                 */
-                scp->result = DRIVER_BYTE(DRIVER_SENSE) |
-                    STATUS_BYTE(qdonep->d3.scsi_stat);
-            } else {
-                scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
-            }
-            break;
+	case QD_WITH_ERROR:
+		ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
+		switch (qdonep->d3.host_stat) {
+		case QHSTA_NO_ERROR:
+			if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
+				ASC_DBG(2,
+					"asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
+				ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+						  sizeof(scp->sense_buffer));
+				/*
+				 * Note: The 'status_byte()' macro used by target drivers
+				 * defined in scsi.h shifts the status byte returned by
+				 * host drivers right by 1 bit. This is why target drivers
+				 * also use right shifted status byte definitions. For
+				 * instance target drivers use CHECK_CONDITION, defined to
+				 * 0x1, instead of the SCSI defined check condition value
+				 * of 0x2. Host drivers are supposed to return the status
+				 * byte as it is defined by SCSI.
+				 */
+				scp->result = DRIVER_BYTE(DRIVER_SENSE) |
+				    STATUS_BYTE(qdonep->d3.scsi_stat);
+			} else {
+				scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
+			}
+			break;
 
-        default:
-            /* QHSTA error occurred */
-            ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
-                qdonep->d3.host_stat);
-            scp->result = HOST_BYTE(DID_BAD_TARGET);
-            break;
-        }
-        break;
+		default:
+			/* QHSTA error occurred */
+			ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
+				 qdonep->d3.host_stat);
+			scp->result = HOST_BYTE(DID_BAD_TARGET);
+			break;
+		}
+		break;
 
-    case QD_ABORTED_BY_HOST:
-        ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
-        scp->result = HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.scsi_msg) |
-                STATUS_BYTE(qdonep->d3.scsi_stat);
-        break;
+	case QD_ABORTED_BY_HOST:
+		ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
+		scp->result =
+		    HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.
+						    scsi_msg) |
+		    STATUS_BYTE(qdonep->d3.scsi_stat);
+		break;
 
-    default:
-        ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n", qdonep->d3.done_stat);
-        scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) |
-                STATUS_BYTE(qdonep->d3.scsi_stat);
-        break;
-    }
+	default:
+		ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n",
+			 qdonep->d3.done_stat);
+		scp->result =
+		    HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.
+						    scsi_msg) |
+		    STATUS_BYTE(qdonep->d3.scsi_stat);
+		break;
+	}
 
-    /*
-     * If the 'init_tidmask' bit isn't already set for the target and the
-     * current request finished normally, then set the bit for the target
-     * to indicate that a device is present.
-     */
-    if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
-        qdonep->d3.done_stat == QD_NO_ERROR &&
-        qdonep->d3.host_stat == QHSTA_NO_ERROR) {
-        boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
-    }
+	/*
+	 * If the 'init_tidmask' bit isn't already set for the target and the
+	 * current request finished normally, then set the bit for the target
+	 * to indicate that a device is present.
+	 */
+	if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
+	    qdonep->d3.done_stat == QD_NO_ERROR &&
+	    qdonep->d3.host_stat == QHSTA_NO_ERROR) {
+		boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
+	}
 
-    /*
-     * Because interrupts may be enabled by the 'struct scsi_cmnd' done
-     * function, add the command to the end of the board's done queue.
-     * The done function for the command will be called from
-     * advansys_interrupt().
-     */
-    asc_enqueue(&boardp->done, scp, ASC_BACK);
+	/*
+	 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
+	 * function, add the command to the end of the board's done queue.
+	 * The done function for the command will be called from
+	 * advansys_interrupt().
+	 */
+	asc_enqueue(&boardp->done, scp, ASC_BACK);
 
-    return;
+	return;
 }
 
 /*
@@ -6885,238 +5704,240 @@
  *
  * Callback function for the Wide SCSI Adv Library.
  */
-STATIC void
-adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
+static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
 {
-    asc_board_t         *boardp;
-    adv_req_t           *reqp;
-    adv_sgblk_t         *sgblkp;
-    struct scsi_cmnd           *scp;
-    struct Scsi_Host    *shp;
-    int                 i;
-    ADV_DCNT            resid_cnt;
+	asc_board_t *boardp;
+	adv_req_t *reqp;
+	adv_sgblk_t *sgblkp;
+	struct scsi_cmnd *scp;
+	struct Scsi_Host *shost;
+	int i;
+	ADV_DCNT resid_cnt;
 
+	ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
+		 (ulong)adv_dvc_varp, (ulong)scsiqp);
+	ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
 
-    ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
-        (ulong) adv_dvc_varp, (ulong) scsiqp);
-    ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
+	/*
+	 * Get the adv_req_t structure for the command that has been
+	 * completed. The adv_req_t structure actually contains the
+	 * completed ADV_SCSI_REQ_Q structure.
+	 */
+	reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr);
+	ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong)reqp);
+	if (reqp == NULL) {
+		ASC_PRINT("adv_isr_callback: reqp is NULL\n");
+		return;
+	}
 
-    /*
-     * Get the adv_req_t structure for the command that has been
-     * completed. The adv_req_t structure actually contains the
-     * completed ADV_SCSI_REQ_Q structure.
-     */
-    reqp = (adv_req_t *) ADV_U32_TO_VADDR(scsiqp->srb_ptr);
-    ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong) reqp);
-    if (reqp == NULL) {
-        ASC_PRINT("adv_isr_callback: reqp is NULL\n");
-        return;
-    }
+	/*
+	 * Get the struct scsi_cmnd structure and Scsi_Host structure for the
+	 * command that has been completed.
+	 *
+	 * Note: The adv_req_t request structure and adv_sgblk_t structure,
+	 * if any, are dropped, because a board structure pointer can not be
+	 * determined.
+	 */
+	scp = reqp->cmndp;
+	ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong)scp);
+	if (scp == NULL) {
+		ASC_PRINT
+		    ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
+		return;
+	}
+	ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
 
-    /*
-     * Get the struct scsi_cmnd structure and Scsi_Host structure for the
-     * command that has been completed.
-     *
-     * Note: The adv_req_t request structure and adv_sgblk_t structure,
-     * if any, are dropped, because a board structure pointer can not be
-     * determined.
-     */
-    scp = reqp->cmndp;
-    ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong) scp);
-    if (scp == NULL) {
-        ASC_PRINT("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
-        return;
-    }
-    ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+	/*
+	 * If the request's host pointer is not valid, display a message
+	 * and return.
+	 */
+	shost = scp->device->host;
+	for (i = 0; i < asc_board_count; i++) {
+		if (asc_host[i] == shost) {
+			break;
+		}
+	}
+	/*
+	 * Note: If the host structure is not found, the adv_req_t request
+	 * structure and adv_sgblk_t structure, if any, is dropped.
+	 */
+	if (i == asc_board_count) {
+		ASC_PRINT2
+		    ("adv_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
+		     (ulong)scp, (ulong)shost);
+		return;
+	}
 
-    /*
-     * If the request's host pointer is not valid, display a message
-     * and return.
-     */
-    shp = scp->device->host;
-    for (i = 0; i < asc_board_count; i++) {
-        if (asc_host[i] == shp) {
-            break;
-        }
-    }
-    /*
-     * Note: If the host structure is not found, the adv_req_t request
-     * structure and adv_sgblk_t structure, if any, is dropped.
-     */
-    if (i == asc_board_count) {
-        ASC_PRINT2(
-            "adv_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
-            (ulong) scp, (ulong) shp);
-        return;
-    }
+	ASC_STATS(shost, callback);
+	ASC_DBG1(1, "adv_isr_callback: shost 0x%lx\n", (ulong)shost);
 
-    ASC_STATS(shp, callback);
-    ASC_DBG1(1, "adv_isr_callback: shp 0x%lx\n", (ulong) shp);
+	/*
+	 * If the request isn't found on the active queue, it may have been
+	 * removed to handle a reset request. Display a message and return.
+	 *
+	 * Note: Because the structure may still be in use don't attempt
+	 * to free the adv_req_t and adv_sgblk_t, if any, structures.
+	 */
+	boardp = ASC_BOARDP(shost);
+	ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
+	if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
+		ASC_PRINT2
+		    ("adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
+		     boardp->id, (ulong)scp);
+		return;
+	}
 
-    /*
-     * If the request isn't found on the active queue, it may have been
-     * removed to handle a reset request. Display a message and return.
-     *
-     * Note: Because the structure may still be in use don't attempt
-     * to free the adv_req_t and adv_sgblk_t, if any, structures.
-     */
-    boardp = ASC_BOARDP(shp);
-    ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
-    if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
-        ASC_PRINT2(
-            "adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
-            boardp->id, (ulong) scp);
-        return;
-    }
+	/*
+	 * 'done_status' contains the command's ending status.
+	 */
+	switch (scsiqp->done_status) {
+	case QD_NO_ERROR:
+		ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
+		scp->result = 0;
 
-    /*
-     * 'done_status' contains the command's ending status.
-     */
-    switch (scsiqp->done_status) {
-    case QD_NO_ERROR:
-        ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
-        scp->result = 0;
+		/*
+		 * Check for an underrun condition.
+		 *
+		 * If there was no error and an underrun condition, then
+		 * then return the number of underrun bytes.
+		 */
+		resid_cnt = le32_to_cpu(scsiqp->data_cnt);
+		if (scp->request_bufflen != 0 && resid_cnt != 0 &&
+		    resid_cnt <= scp->request_bufflen) {
+			ASC_DBG1(1,
+				 "adv_isr_callback: underrun condition %lu bytes\n",
+				 (ulong)resid_cnt);
+			scp->resid = resid_cnt;
+		}
+		break;
 
-        /*
-         * Check for an underrun condition.
-         *
-         * If there was no error and an underrun condition, then
-         * then return the number of underrun bytes.
-         */
-        resid_cnt = le32_to_cpu(scsiqp->data_cnt);
-        if (scp->request_bufflen != 0 && resid_cnt != 0 &&
-            resid_cnt <= scp->request_bufflen) {
-            ASC_DBG1(1, "adv_isr_callback: underrun condition %lu bytes\n",
-                (ulong) resid_cnt);
-            scp->resid = resid_cnt;
-        }
-        break;
+	case QD_WITH_ERROR:
+		ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
+		switch (scsiqp->host_status) {
+		case QHSTA_NO_ERROR:
+			if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
+				ASC_DBG(2,
+					"adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
+				ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+						  sizeof(scp->sense_buffer));
+				/*
+				 * Note: The 'status_byte()' macro used by target drivers
+				 * defined in scsi.h shifts the status byte returned by
+				 * host drivers right by 1 bit. This is why target drivers
+				 * also use right shifted status byte definitions. For
+				 * instance target drivers use CHECK_CONDITION, defined to
+				 * 0x1, instead of the SCSI defined check condition value
+				 * of 0x2. Host drivers are supposed to return the status
+				 * byte as it is defined by SCSI.
+				 */
+				scp->result = DRIVER_BYTE(DRIVER_SENSE) |
+				    STATUS_BYTE(scsiqp->scsi_status);
+			} else {
+				scp->result = STATUS_BYTE(scsiqp->scsi_status);
+			}
+			break;
 
-    case QD_WITH_ERROR:
-        ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
-        switch (scsiqp->host_status) {
-        case QHSTA_NO_ERROR:
-            if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
-                ASC_DBG(2, "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
-                ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
-                    sizeof(scp->sense_buffer));
-                /*
-                 * Note: The 'status_byte()' macro used by target drivers
-                 * defined in scsi.h shifts the status byte returned by
-                 * host drivers right by 1 bit. This is why target drivers
-                 * also use right shifted status byte definitions. For
-                 * instance target drivers use CHECK_CONDITION, defined to
-                 * 0x1, instead of the SCSI defined check condition value
-                 * of 0x2. Host drivers are supposed to return the status
-                 * byte as it is defined by SCSI.
-                 */
-                scp->result = DRIVER_BYTE(DRIVER_SENSE) |
-                    STATUS_BYTE(scsiqp->scsi_status);
-            } else {
-                scp->result = STATUS_BYTE(scsiqp->scsi_status);
-            }
-            break;
+		default:
+			/* Some other QHSTA error occurred. */
+			ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
+				 scsiqp->host_status);
+			scp->result = HOST_BYTE(DID_BAD_TARGET);
+			break;
+		}
+		break;
 
-        default:
-            /* Some other QHSTA error occurred. */
-            ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
-                scsiqp->host_status);
-            scp->result = HOST_BYTE(DID_BAD_TARGET);
-            break;
-        }
-        break;
+	case QD_ABORTED_BY_HOST:
+		ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
+		scp->result =
+		    HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
+		break;
 
-    case QD_ABORTED_BY_HOST:
-        ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
-        scp->result = HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
-        break;
+	default:
+		ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n",
+			 scsiqp->done_status);
+		scp->result =
+		    HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
+		break;
+	}
 
-    default:
-        ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n", scsiqp->done_status);
-        scp->result = HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
-        break;
-    }
+	/*
+	 * If the 'init_tidmask' bit isn't already set for the target and the
+	 * current request finished normally, then set the bit for the target
+	 * to indicate that a device is present.
+	 */
+	if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
+	    scsiqp->done_status == QD_NO_ERROR &&
+	    scsiqp->host_status == QHSTA_NO_ERROR) {
+		boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
+	}
 
-    /*
-     * If the 'init_tidmask' bit isn't already set for the target and the
-     * current request finished normally, then set the bit for the target
-     * to indicate that a device is present.
-     */
-    if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
-        scsiqp->done_status == QD_NO_ERROR &&
-        scsiqp->host_status == QHSTA_NO_ERROR) {
-        boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
-    }
+	/*
+	 * Because interrupts may be enabled by the 'struct scsi_cmnd' done
+	 * function, add the command to the end of the board's done queue.
+	 * The done function for the command will be called from
+	 * advansys_interrupt().
+	 */
+	asc_enqueue(&boardp->done, scp, ASC_BACK);
 
-    /*
-     * Because interrupts may be enabled by the 'struct scsi_cmnd' done
-     * function, add the command to the end of the board's done queue.
-     * The done function for the command will be called from
-     * advansys_interrupt().
-     */
-    asc_enqueue(&boardp->done, scp, ASC_BACK);
+	/*
+	 * Free all 'adv_sgblk_t' structures allocated for the request.
+	 */
+	while ((sgblkp = reqp->sgblkp) != NULL) {
+		/* Remove 'sgblkp' from the request list. */
+		reqp->sgblkp = sgblkp->next_sgblkp;
 
-    /*
-     * Free all 'adv_sgblk_t' structures allocated for the request.
-     */
-    while ((sgblkp = reqp->sgblkp) != NULL)
-    {
-        /* Remove 'sgblkp' from the request list. */
-        reqp->sgblkp = sgblkp->next_sgblkp;
+		/* Add 'sgblkp' to the board free list. */
+		sgblkp->next_sgblkp = boardp->adv_sgblkp;
+		boardp->adv_sgblkp = sgblkp;
+	}
 
-        /* Add 'sgblkp' to the board free list. */
-        sgblkp->next_sgblkp = boardp->adv_sgblkp;
-        boardp->adv_sgblkp = sgblkp;
-    }
+	/*
+	 * Free the adv_req_t structure used with the command by adding
+	 * it back to the board free list.
+	 */
+	reqp->next_reqp = boardp->adv_reqp;
+	boardp->adv_reqp = reqp;
 
-    /*
-     * Free the adv_req_t structure used with the command by adding
-     * it back to the board free list.
-     */
-    reqp->next_reqp = boardp->adv_reqp;
-    boardp->adv_reqp = reqp;
+	ASC_DBG(1, "adv_isr_callback: done\n");
 
-    ASC_DBG(1, "adv_isr_callback: done\n");
-
-    return;
+	return;
 }
 
 /*
  * adv_async_callback() - Adv Library asynchronous event callback function.
  */
-STATIC void
-adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
+static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
 {
-    switch (code)
-    {
-    case ADV_ASYNC_SCSI_BUS_RESET_DET:
-        /*
-         * The firmware detected a SCSI Bus reset.
-         */
-        ASC_DBG(0, "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
-        break;
+	switch (code) {
+	case ADV_ASYNC_SCSI_BUS_RESET_DET:
+		/*
+		 * The firmware detected a SCSI Bus reset.
+		 */
+		ASC_DBG(0,
+			"adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
+		break;
 
-    case ADV_ASYNC_RDMA_FAILURE:
-        /*
-         * Handle RDMA failure by resetting the SCSI Bus and
-         * possibly the chip if it is unresponsive. Log the error
-         * with a unique code.
-         */
-        ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
-        AdvResetChipAndSB(adv_dvc_varp);
-        break;
+	case ADV_ASYNC_RDMA_FAILURE:
+		/*
+		 * Handle RDMA failure by resetting the SCSI Bus and
+		 * possibly the chip if it is unresponsive. Log the error
+		 * with a unique code.
+		 */
+		ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
+		AdvResetChipAndSB(adv_dvc_varp);
+		break;
 
-    case ADV_HOST_SCSI_BUS_RESET:
-        /*
-         * Host generated SCSI bus reset occurred.
-         */
-        ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
-        break;
+	case ADV_HOST_SCSI_BUS_RESET:
+		/*
+		 * Host generated SCSI bus reset occurred.
+		 */
+		ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
+		break;
 
-    default:
-        ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
-        break;
-    }
+	default:
+		ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
+		break;
+	}
 }
 
 /*
@@ -7127,50 +5948,50 @@
  *
  * 'REQPNEXT(reqp)' returns reqp's next pointer.
  */
-STATIC void
-asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
+static void asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
 {
-    int        tid;
+	int tid;
 
-    ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
-        (ulong) ascq, (ulong) reqp, flag);
-    ASC_ASSERT(reqp != NULL);
-    ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
-    tid = REQPTID(reqp);
-    ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
-    if (flag == ASC_FRONT) {
-        reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
-        ascq->q_first[tid] = reqp;
-        /* If the queue was empty, set the last pointer. */
-        if (ascq->q_last[tid] == NULL) {
-            ascq->q_last[tid] = reqp;
-        }
-    } else { /* ASC_BACK */
-        if (ascq->q_last[tid] != NULL) {
-            ascq->q_last[tid]->host_scribble = (unsigned char *)reqp;
-        }
-        ascq->q_last[tid] = reqp;
-        reqp->host_scribble = NULL;
-        /* If the queue was empty, set the first pointer. */
-        if (ascq->q_first[tid] == NULL) {
-            ascq->q_first[tid] = reqp;
-        }
-    }
-    /* The queue has at least one entry, set its bit. */
-    ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
+	ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
+		 (ulong)ascq, (ulong)reqp, flag);
+	ASC_ASSERT(reqp != NULL);
+	ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
+	tid = REQPTID(reqp);
+	ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
+	if (flag == ASC_FRONT) {
+		reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
+		ascq->q_first[tid] = reqp;
+		/* If the queue was empty, set the last pointer. */
+		if (ascq->q_last[tid] == NULL) {
+			ascq->q_last[tid] = reqp;
+		}
+	} else {		/* ASC_BACK */
+		if (ascq->q_last[tid] != NULL) {
+			ascq->q_last[tid]->host_scribble =
+			    (unsigned char *)reqp;
+		}
+		ascq->q_last[tid] = reqp;
+		reqp->host_scribble = NULL;
+		/* If the queue was empty, set the first pointer. */
+		if (ascq->q_first[tid] == NULL) {
+			ascq->q_first[tid] = reqp;
+		}
+	}
+	/* The queue has at least one entry, set its bit. */
+	ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
 #ifdef ADVANSYS_STATS
-    /* Maintain request queue statistics. */
-    ascq->q_tot_cnt[tid]++;
-    ascq->q_cur_cnt[tid]++;
-    if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
-        ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
-        ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
-            tid, ascq->q_max_cnt[tid]);
-    }
-    REQPTIME(reqp) = REQTIMESTAMP();
+	/* Maintain request queue statistics. */
+	ascq->q_tot_cnt[tid]++;
+	ascq->q_cur_cnt[tid]++;
+	if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
+		ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
+		ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
+			 tid, ascq->q_max_cnt[tid]);
+	}
+	REQPTIME(reqp) = REQTIMESTAMP();
 #endif /* ADVANSYS_STATS */
-    ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong) reqp);
-    return;
+	ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong)reqp);
+	return;
 }
 
 /*
@@ -7180,31 +6001,30 @@
  *
  * 'REQPNEXT(reqp)' returns reqp's next pointer.
  */
-STATIC REQP
-asc_dequeue(asc_queue_t *ascq, int tid)
+static REQP asc_dequeue(asc_queue_t *ascq, int tid)
 {
-    REQP    reqp;
+	REQP reqp;
 
-    ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong) ascq, tid);
-    ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
-    if ((reqp = ascq->q_first[tid]) != NULL) {
-        ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
-        ascq->q_first[tid] = REQPNEXT(reqp);
-        /* If the queue is empty, clear its bit and the last pointer. */
-        if (ascq->q_first[tid] == NULL) {
-            ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
-            ASC_ASSERT(ascq->q_last[tid] == reqp);
-            ascq->q_last[tid] = NULL;
-        }
+	ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
+	ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
+	if ((reqp = ascq->q_first[tid]) != NULL) {
+		ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
+		ascq->q_first[tid] = REQPNEXT(reqp);
+		/* If the queue is empty, clear its bit and the last pointer. */
+		if (ascq->q_first[tid] == NULL) {
+			ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
+			ASC_ASSERT(ascq->q_last[tid] == reqp);
+			ascq->q_last[tid] = NULL;
+		}
 #ifdef ADVANSYS_STATS
-        /* Maintain request queue statistics. */
-        ascq->q_cur_cnt[tid]--;
-        ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
-        REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
+		/* Maintain request queue statistics. */
+		ascq->q_cur_cnt[tid]--;
+		ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
+		REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
 #endif /* ADVANSYS_STATS */
-    }
-    ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong) reqp);
-    return reqp;
+	}
+	ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong)reqp);
+	return reqp;
 }
 
 /*
@@ -7227,74 +6047,76 @@
  * Unfortunately collecting queuing time statistics adds overhead to
  * the function that isn't inherent to the function's algorithm.
  */
-STATIC REQP
-asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
+static REQP asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
 {
-    REQP    firstp, lastp;
-    int     i;
+	REQP firstp, lastp;
+	int i;
 
-    ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong) ascq, tid);
-    ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
+	ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong)ascq, tid);
+	ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
 
-    /*
-     * If 'tid' is not ASC_TID_ALL, return requests only for
-     * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
-     * requests for all tids.
-     */
-    if (tid != ASC_TID_ALL) {
-        /* Return all requests for the specified 'tid'. */
-        if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
-            /* List is empty; Set first and last return pointers to NULL. */
-            firstp = lastp = NULL;
-        } else {
-            firstp = ascq->q_first[tid];
-            lastp = ascq->q_last[tid];
-            ascq->q_first[tid] = ascq->q_last[tid] = NULL;
-            ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
+	/*
+	 * If 'tid' is not ASC_TID_ALL, return requests only for
+	 * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
+	 * requests for all tids.
+	 */
+	if (tid != ASC_TID_ALL) {
+		/* Return all requests for the specified 'tid'. */
+		if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
+			/* List is empty; Set first and last return pointers to NULL. */
+			firstp = lastp = NULL;
+		} else {
+			firstp = ascq->q_first[tid];
+			lastp = ascq->q_last[tid];
+			ascq->q_first[tid] = ascq->q_last[tid] = NULL;
+			ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
 #ifdef ADVANSYS_STATS
-            {
-                REQP reqp;
-                ascq->q_cur_cnt[tid] = 0;
-                for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
-                    REQTIMESTAT("asc_dequeue_list", ascq, reqp, tid);
-                }
-            }
+			{
+				REQP reqp;
+				ascq->q_cur_cnt[tid] = 0;
+				for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
+					REQTIMESTAT("asc_dequeue_list", ascq,
+						    reqp, tid);
+				}
+			}
 #endif /* ADVANSYS_STATS */
-        }
-    } else {
-        /* Return all requests for all tids. */
-        firstp = lastp = NULL;
-        for (i = 0; i <= ADV_MAX_TID; i++) {
-            if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
-                if (firstp == NULL) {
-                    firstp = ascq->q_first[i];
-                    lastp = ascq->q_last[i];
-                } else {
-                    ASC_ASSERT(lastp != NULL);
-                    lastp->host_scribble = (unsigned char *)ascq->q_first[i];
-                    lastp = ascq->q_last[i];
-                }
-                ascq->q_first[i] = ascq->q_last[i] = NULL;
-                ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
+		}
+	} else {
+		/* Return all requests for all tids. */
+		firstp = lastp = NULL;
+		for (i = 0; i <= ADV_MAX_TID; i++) {
+			if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
+				if (firstp == NULL) {
+					firstp = ascq->q_first[i];
+					lastp = ascq->q_last[i];
+				} else {
+					ASC_ASSERT(lastp != NULL);
+					lastp->host_scribble =
+					    (unsigned char *)ascq->q_first[i];
+					lastp = ascq->q_last[i];
+				}
+				ascq->q_first[i] = ascq->q_last[i] = NULL;
+				ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
 #ifdef ADVANSYS_STATS
-                ascq->q_cur_cnt[i] = 0;
+				ascq->q_cur_cnt[i] = 0;
 #endif /* ADVANSYS_STATS */
-            }
-        }
+			}
+		}
 #ifdef ADVANSYS_STATS
-        {
-            REQP reqp;
-            for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
-                REQTIMESTAT("asc_dequeue_list", ascq, reqp, reqp->device->id);
-            }
-        }
+		{
+			REQP reqp;
+			for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
+				REQTIMESTAT("asc_dequeue_list", ascq, reqp,
+					    reqp->device->id);
+			}
+		}
 #endif /* ADVANSYS_STATS */
-    }
-    if (lastpp) {
-        *lastpp = lastp;
-    }
-    ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong) firstp);
-    return firstp;
+	}
+	if (lastpp) {
+		*lastpp = lastp;
+	}
+	ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong)firstp);
+	return firstp;
 }
 
 /*
@@ -7307,67 +6129,67 @@
  * Return ASC_TRUE if the command was found and removed,
  * otherwise return ASC_FALSE.
  */
-STATIC int
-asc_rmqueue(asc_queue_t *ascq, REQP reqp)
+static int asc_rmqueue(asc_queue_t *ascq, REQP reqp)
 {
-    REQP        currp, prevp;
-    int         tid;
-    int         ret = ASC_FALSE;
+	REQP currp, prevp;
+	int tid;
+	int ret = ASC_FALSE;
 
-    ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
-        (ulong) ascq, (ulong) reqp);
-    ASC_ASSERT(reqp != NULL);
+	ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
+		 (ulong)ascq, (ulong)reqp);
+	ASC_ASSERT(reqp != NULL);
 
-    tid = REQPTID(reqp);
-    ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
+	tid = REQPTID(reqp);
+	ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
 
-    /*
-     * Handle the common case of 'reqp' being the first
-     * entry on the queue.
-     */
-    if (reqp == ascq->q_first[tid]) {
-        ret = ASC_TRUE;
-        ascq->q_first[tid] = REQPNEXT(reqp);
-        /* If the queue is now empty, clear its bit and the last pointer. */
-        if (ascq->q_first[tid] == NULL) {
-            ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
-            ASC_ASSERT(ascq->q_last[tid] == reqp);
-            ascq->q_last[tid] = NULL;
-        }
-    } else if (ascq->q_first[tid] != NULL) {
-        ASC_ASSERT(ascq->q_last[tid] != NULL);
-        /*
-         * Because the case of 'reqp' being the first entry has been
-         * handled above and it is known the queue is not empty, if
-         * 'reqp' is found on the queue it is guaranteed the queue will
-         * not become empty and that 'q_first[tid]' will not be changed.
-         *
-         * Set 'prevp' to the first entry, 'currp' to the second entry,
-         * and search for 'reqp'.
-         */
-        for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
-             currp; prevp = currp, currp = REQPNEXT(currp)) {
-            if (currp == reqp) {
-                ret = ASC_TRUE;
-                prevp->host_scribble = (unsigned char *)REQPNEXT(currp);
-                reqp->host_scribble = NULL;
-                if (ascq->q_last[tid] == reqp) {
-                    ascq->q_last[tid] = prevp;
-                }
-                break;
-            }
-        }
-    }
+	/*
+	 * Handle the common case of 'reqp' being the first
+	 * entry on the queue.
+	 */
+	if (reqp == ascq->q_first[tid]) {
+		ret = ASC_TRUE;
+		ascq->q_first[tid] = REQPNEXT(reqp);
+		/* If the queue is now empty, clear its bit and the last pointer. */
+		if (ascq->q_first[tid] == NULL) {
+			ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
+			ASC_ASSERT(ascq->q_last[tid] == reqp);
+			ascq->q_last[tid] = NULL;
+		}
+	} else if (ascq->q_first[tid] != NULL) {
+		ASC_ASSERT(ascq->q_last[tid] != NULL);
+		/*
+		 * Because the case of 'reqp' being the first entry has been
+		 * handled above and it is known the queue is not empty, if
+		 * 'reqp' is found on the queue it is guaranteed the queue will
+		 * not become empty and that 'q_first[tid]' will not be changed.
+		 *
+		 * Set 'prevp' to the first entry, 'currp' to the second entry,
+		 * and search for 'reqp'.
+		 */
+		for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
+		     currp; prevp = currp, currp = REQPNEXT(currp)) {
+			if (currp == reqp) {
+				ret = ASC_TRUE;
+				prevp->host_scribble =
+				    (unsigned char *)REQPNEXT(currp);
+				reqp->host_scribble = NULL;
+				if (ascq->q_last[tid] == reqp) {
+					ascq->q_last[tid] = prevp;
+				}
+				break;
+			}
+		}
+	}
 #ifdef ADVANSYS_STATS
-    /* Maintain request queue statistics. */
-    if (ret == ASC_TRUE) {
-        ascq->q_cur_cnt[tid]--;
-        REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
-    }
-    ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
+	/* Maintain request queue statistics. */
+	if (ret == ASC_TRUE) {
+		ascq->q_cur_cnt[tid]--;
+		REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
+	}
+	ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
 #endif /* ADVANSYS_STATS */
-    ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong) reqp, ret);
-    return ret;
+	ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong)reqp, ret);
+	return ret;
 }
 
 /*
@@ -7375,37 +6197,38 @@
  *
  * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
  */
-STATIC void
-asc_execute_queue(asc_queue_t *ascq)
+static void asc_execute_queue(asc_queue_t *ascq)
 {
-    ADV_SCSI_BIT_ID_TYPE    scan_tidmask;
-    REQP                    reqp;
-    int                     i;
+	ADV_SCSI_BIT_ID_TYPE scan_tidmask;
+	REQP reqp;
+	int i;
 
-    ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong) ascq);
-    /*
-     * Execute queued commands for devices attached to
-     * the current board in round-robin fashion.
-     */
-    scan_tidmask = ascq->q_tidmask;
-    do {
-        for (i = 0; i <= ADV_MAX_TID; i++) {
-            if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
-                if ((reqp = asc_dequeue(ascq, i)) == NULL) {
-                    scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
-                } else if (asc_execute_scsi_cmnd((struct scsi_cmnd *) reqp)
-                            == ASC_BUSY) {
-                    scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
-                    /*
-                     * The request returned ASC_BUSY. Enqueue at the front of
-                     * target's waiting list to maintain correct ordering.
-                     */
-                    asc_enqueue(ascq, reqp, ASC_FRONT);
-                }
-            }
-        }
-    } while (scan_tidmask);
-    return;
+	ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong)ascq);
+	/*
+	 * Execute queued commands for devices attached to
+	 * the current board in round-robin fashion.
+	 */
+	scan_tidmask = ascq->q_tidmask;
+	do {
+		for (i = 0; i <= ADV_MAX_TID; i++) {
+			if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
+				if ((reqp = asc_dequeue(ascq, i)) == NULL) {
+					scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
+				} else
+				    if (asc_execute_scsi_cmnd
+					((struct scsi_cmnd *)reqp)
+					== ASC_BUSY) {
+					scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
+					/*
+					 * The request returned ASC_BUSY. Enqueue at the front of
+					 * target's waiting list to maintain correct ordering.
+					 */
+					asc_enqueue(ascq, reqp, ASC_FRONT);
+				}
+			}
+		}
+	} while (scan_tidmask);
+	return;
 }
 
 #ifdef CONFIG_PROC_FS
@@ -7420,102 +6243,102 @@
  * Return the number of characters copied into 'cp'. No more than
  * 'cplen' characters will be copied to 'cp'.
  */
-STATIC int
-asc_prt_board_devices(struct Scsi_Host *shp, char *cp, int cplen)
+static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen)
 {
-    asc_board_t        *boardp;
-    int                leftlen;
-    int                totlen;
-    int                len;
-    int                chip_scsi_id;
-    int                i;
+	asc_board_t *boardp;
+	int leftlen;
+	int totlen;
+	int len;
+	int chip_scsi_id;
+	int i;
 
-    boardp = ASC_BOARDP(shp);
-    leftlen = cplen;
-    totlen = len = 0;
+	boardp = ASC_BOARDP(shost);
+	leftlen = cplen;
+	totlen = len = 0;
 
-    len = asc_prt_line(cp, leftlen,
-"\nDevice Information for AdvanSys SCSI Host %d:\n", shp->host_no);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   "\nDevice Information for AdvanSys SCSI Host %d:\n",
+			   shost->host_no);
+	ASC_PRT_NEXT();
 
-    if (ASC_NARROW_BOARD(boardp)) {
-        chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
-    } else {
-        chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
-    }
+	if (ASC_NARROW_BOARD(boardp)) {
+		chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
+	} else {
+		chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+	}
 
-    len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ADV_MAX_TID; i++) {
-        if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
-            len = asc_prt_line(cp, leftlen, " %X,", i);
-            ASC_PRT_NEXT();
-        }
-    }
-    len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ADV_MAX_TID; i++) {
+		if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
+			len = asc_prt_line(cp, leftlen, " %X,", i);
+			ASC_PRT_NEXT();
+		}
+	}
+	len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
+	ASC_PRT_NEXT();
 
-    return totlen;
+	return totlen;
 }
 
 /*
  * Display Wide Board BIOS Information.
  */
-STATIC int
-asc_prt_adv_bios(struct Scsi_Host *shp, char *cp, int cplen)
+static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen)
 {
-    asc_board_t        *boardp;
-    int                leftlen;
-    int                totlen;
-    int                len;
-    ushort             major, minor, letter;
+	asc_board_t *boardp;
+	int leftlen;
+	int totlen;
+	int len;
+	ushort major, minor, letter;
 
-    boardp = ASC_BOARDP(shp);
-    leftlen = cplen;
-    totlen = len = 0;
+	boardp = ASC_BOARDP(shost);
+	leftlen = cplen;
+	totlen = len = 0;
 
-    len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
+	ASC_PRT_NEXT();
 
-    /*
-     * If the BIOS saved a valid signature, then fill in
-     * the BIOS code segment base address.
-     */
-    if (boardp->bios_signature != 0x55AA) {
-        len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
-        ASC_PRT_NEXT();
-        len = asc_prt_line(cp, leftlen,
-"BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
-        ASC_PRT_NEXT();
-        len = asc_prt_line(cp, leftlen,
-"can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
-        ASC_PRT_NEXT();
-    } else {
-        major = (boardp->bios_version >> 12) & 0xF;
-        minor = (boardp->bios_version >> 8) & 0xF;
-        letter = (boardp->bios_version & 0xFF);
+	/*
+	 * If the BIOS saved a valid signature, then fill in
+	 * the BIOS code segment base address.
+	 */
+	if (boardp->bios_signature != 0x55AA) {
+		len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
+		ASC_PRT_NEXT();
+		len = asc_prt_line(cp, leftlen,
+				   "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
+		ASC_PRT_NEXT();
+		len = asc_prt_line(cp, leftlen,
+				   "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
+		ASC_PRT_NEXT();
+	} else {
+		major = (boardp->bios_version >> 12) & 0xF;
+		minor = (boardp->bios_version >> 8) & 0xF;
+		letter = (boardp->bios_version & 0xFF);
 
-        len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
-            major, minor, letter >= 26 ? '?' : letter + 'A');
-        ASC_PRT_NEXT();
+		len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
+				   major, minor,
+				   letter >= 26 ? '?' : letter + 'A');
+		ASC_PRT_NEXT();
 
-        /*
-         * Current available ROM BIOS release is 3.1I for UW
-         * and 3.2I for U2W. This code doesn't differentiate
-         * UW and U2W boards.
-         */
-        if (major < 3 || (major <= 3 && minor < 1) ||
-            (major <= 3 && minor <= 1 && letter < ('I'- 'A'))) {
-            len = asc_prt_line(cp, leftlen,
-"Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
-            ASC_PRT_NEXT();
-            len = asc_prt_line(cp, leftlen,
-"ftp://ftp.connectcom.net/pub\n");
-            ASC_PRT_NEXT();
-        }
-    }
+		/*
+		 * Current available ROM BIOS release is 3.1I for UW
+		 * and 3.2I for U2W. This code doesn't differentiate
+		 * UW and U2W boards.
+		 */
+		if (major < 3 || (major <= 3 && minor < 1) ||
+		    (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
+			len = asc_prt_line(cp, leftlen,
+					   "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
+			ASC_PRT_NEXT();
+			len = asc_prt_line(cp, leftlen,
+					   "ftp://ftp.connectcom.net/pub\n");
+			ASC_PRT_NEXT();
+		}
+	}
 
-    return totlen;
+	return totlen;
 }
 
 /*
@@ -7541,80 +6364,79 @@
  *
  * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
  */
-STATIC int
-asc_get_eeprom_string(ushort *serialnum, uchar *cp)
+static int asc_get_eeprom_string(ushort *serialnum, uchar *cp)
 {
-    ushort      w, num;
+	ushort w, num;
 
-    if ((serialnum[1] & 0xFE00) != ((ushort) 0xAA << 8)) {
-        return ASC_FALSE;
-    } else {
-        /*
-         * First word - 6 digits.
-         */
-        w = serialnum[0];
+	if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) {
+		return ASC_FALSE;
+	} else {
+		/*
+		 * First word - 6 digits.
+		 */
+		w = serialnum[0];
 
-        /* Product type - 1st digit. */
-        if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
-            /* Product type is P=Prototype */
-            *cp += 0x8;
-        }
-        cp++;
+		/* Product type - 1st digit. */
+		if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
+			/* Product type is P=Prototype */
+			*cp += 0x8;
+		}
+		cp++;
 
-        /* Manufacturing location - 2nd digit. */
-        *cp++ = 'A' + ((w & 0x1C00) >> 10);
+		/* Manufacturing location - 2nd digit. */
+		*cp++ = 'A' + ((w & 0x1C00) >> 10);
 
-        /* Product ID - 3rd, 4th digits. */
-        num = w & 0x3FF;
-        *cp++ = '0' + (num / 100);
-        num %= 100;
-        *cp++ = '0' + (num / 10);
+		/* Product ID - 3rd, 4th digits. */
+		num = w & 0x3FF;
+		*cp++ = '0' + (num / 100);
+		num %= 100;
+		*cp++ = '0' + (num / 10);
 
-        /* Product revision - 5th digit. */
-        *cp++ = 'A' + (num % 10);
+		/* Product revision - 5th digit. */
+		*cp++ = 'A' + (num % 10);
 
-        /*
-         * Second word
-         */
-        w = serialnum[1];
+		/*
+		 * Second word
+		 */
+		w = serialnum[1];
 
-        /*
-         * Year - 6th digit.
-         *
-         * If bit 15 of third word is set, then the
-         * last digit of the year is greater than 7.
-         */
-        if (serialnum[2] & 0x8000) {
-            *cp++ = '8' + ((w & 0x1C0) >> 6);
-        } else {
-            *cp++ = '0' + ((w & 0x1C0) >> 6);
-        }
+		/*
+		 * Year - 6th digit.
+		 *
+		 * If bit 15 of third word is set, then the
+		 * last digit of the year is greater than 7.
+		 */
+		if (serialnum[2] & 0x8000) {
+			*cp++ = '8' + ((w & 0x1C0) >> 6);
+		} else {
+			*cp++ = '0' + ((w & 0x1C0) >> 6);
+		}
 
-        /* Week of year - 7th, 8th digits. */
-        num = w & 0x003F;
-        *cp++ = '0' + num / 10;
-        num %= 10;
-        *cp++ = '0' + num;
+		/* Week of year - 7th, 8th digits. */
+		num = w & 0x003F;
+		*cp++ = '0' + num / 10;
+		num %= 10;
+		*cp++ = '0' + num;
 
-        /*
-         * Third word
-         */
-        w = serialnum[2] & 0x7FFF;
+		/*
+		 * Third word
+		 */
+		w = serialnum[2] & 0x7FFF;
 
-        /* Serial number - 9th digit. */
-        *cp++ = 'A' + (w / 1000);
+		/* Serial number - 9th digit. */
+		*cp++ = 'A' + (w / 1000);
 
-        /* 10th, 11th, 12th digits. */
-        num = w % 1000;
-        *cp++ = '0' + num / 100;
-        num %= 100;
-        *cp++ = '0' + num / 10;
-        num %= 10;
-        *cp++ = '0' + num;
+		/* 10th, 11th, 12th digits. */
+		num = w % 1000;
+		*cp++ = '0' + num / 100;
+		num %= 100;
+		*cp++ = '0' + num / 10;
+		num %= 10;
+		*cp++ = '0' + num;
 
-        *cp = '\0';     /* Null Terminate the string. */
-        return ASC_TRUE;
-    }
+		*cp = '\0';	/* Null Terminate the string. */
+		return ASC_TRUE;
+	}
 }
 
 /*
@@ -7628,122 +6450,127 @@
  * Return the number of characters copied into 'cp'. No more than
  * 'cplen' characters will be copied to 'cp'.
  */
-STATIC int
-asc_prt_asc_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
+static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
 {
-    asc_board_t        *boardp;
-    ASC_DVC_VAR        *asc_dvc_varp;
-    int                leftlen;
-    int                totlen;
-    int                len;
-    ASCEEP_CONFIG      *ep;
-    int                i;
+	asc_board_t *boardp;
+	ASC_DVC_VAR *asc_dvc_varp;
+	int leftlen;
+	int totlen;
+	int len;
+	ASCEEP_CONFIG *ep;
+	int i;
 #ifdef CONFIG_ISA
-    int                isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
+	int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
 #endif /* CONFIG_ISA */
-    uchar              serialstr[13];
+	uchar serialstr[13];
 
-    boardp = ASC_BOARDP(shp);
-    asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
-    ep = &boardp->eep_config.asc_eep;
+	boardp = ASC_BOARDP(shost);
+	asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+	ep = &boardp->eep_config.asc_eep;
 
-    leftlen = cplen;
-    totlen = len = 0;
+	leftlen = cplen;
+	totlen = len = 0;
 
-    len = asc_prt_line(cp, leftlen,
-"\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
+			   shost->host_no);
+	ASC_PRT_NEXT();
 
-    if (asc_get_eeprom_string((ushort *) &ep->adapter_info[0], serialstr) ==
-        ASC_TRUE) {
-        len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr);
-        ASC_PRT_NEXT();
-    } else {
-        if (ep->adapter_info[5] == 0xBB) {
-            len = asc_prt_line(cp, leftlen,
-                " Default Settings Used for EEPROM-less Adapter.\n");
-            ASC_PRT_NEXT();
-        } else {
-            len = asc_prt_line(cp, leftlen,
-                " Serial Number Signature Not Present.\n");
-            ASC_PRT_NEXT();
-        }
-    }
+	if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr)
+	    == ASC_TRUE) {
+		len =
+		    asc_prt_line(cp, leftlen, " Serial Number: %s\n",
+				 serialstr);
+		ASC_PRT_NEXT();
+	} else {
+		if (ep->adapter_info[5] == 0xBB) {
+			len = asc_prt_line(cp, leftlen,
+					   " Default Settings Used for EEPROM-less Adapter.\n");
+			ASC_PRT_NEXT();
+		} else {
+			len = asc_prt_line(cp, leftlen,
+					   " Serial Number Signature Not Present.\n");
+			ASC_PRT_NEXT();
+		}
+	}
 
-    len = asc_prt_line(cp, leftlen,
-" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
-        ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng, ep->max_tag_qng);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+			   ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng,
+			   ep->max_tag_qng);
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" cntl 0x%x, no_scam 0x%x\n",
-        ep->cntl, ep->no_scam);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" Target ID:           ");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ASC_MAX_TID; i++) {
-        len = asc_prt_line(cp, leftlen, " %d", i);
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen, " Target ID:           ");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		len = asc_prt_line(cp, leftlen, " %d", i);
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" Disconnects:         ");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ASC_MAX_TID; i++) {
-        len = asc_prt_line(cp, leftlen, " %c",
-            (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen, " Disconnects:         ");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		len = asc_prt_line(cp, leftlen, " %c",
+				   (ep->
+				    disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+				   'N');
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" Command Queuing:     ");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ASC_MAX_TID; i++) {
-        len = asc_prt_line(cp, leftlen, " %c",
-            (ep->use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen, " Command Queuing:     ");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		len = asc_prt_line(cp, leftlen, " %c",
+				   (ep->
+				    use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+				   'N');
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" Start Motor:         ");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ASC_MAX_TID; i++) {
-        len = asc_prt_line(cp, leftlen, " %c",
-            (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen, " Start Motor:         ");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		len = asc_prt_line(cp, leftlen, " %c",
+				   (ep->
+				    start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+				   'N');
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" Synchronous Transfer:");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ASC_MAX_TID; i++) {
-        len = asc_prt_line(cp, leftlen, " %c",
-            (ep->init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		len = asc_prt_line(cp, leftlen, " %c",
+				   (ep->
+				    init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+				   'N');
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
 #ifdef CONFIG_ISA
-    if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
-        len = asc_prt_line(cp, leftlen,
-" Host ISA DMA speed:   %d MB/S\n",
-            isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
-        ASC_PRT_NEXT();
-    }
+	if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+		len = asc_prt_line(cp, leftlen,
+				   " Host ISA DMA speed:   %d MB/S\n",
+				   isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
+		ASC_PRT_NEXT();
+	}
 #endif /* CONFIG_ISA */
 
-     return totlen;
+	return totlen;
 }
 
 /*
@@ -7757,300 +6584,282 @@
  * Return the number of characters copied into 'cp'. No more than
  * 'cplen' characters will be copied to 'cp'.
  */
-STATIC int
-asc_prt_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
+static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen)
 {
-    asc_board_t                 *boardp;
-    ADV_DVC_VAR                 *adv_dvc_varp;
-    int                         leftlen;
-    int                         totlen;
-    int                         len;
-    int                         i;
-    char                        *termstr;
-    uchar                       serialstr[13];
-    ADVEEP_3550_CONFIG          *ep_3550 = NULL;
-    ADVEEP_38C0800_CONFIG       *ep_38C0800 = NULL;
-    ADVEEP_38C1600_CONFIG       *ep_38C1600 = NULL;
-    ushort                      word;
-    ushort                      *wordp;
-    ushort                      sdtr_speed = 0;
+	asc_board_t *boardp;
+	ADV_DVC_VAR *adv_dvc_varp;
+	int leftlen;
+	int totlen;
+	int len;
+	int i;
+	char *termstr;
+	uchar serialstr[13];
+	ADVEEP_3550_CONFIG *ep_3550 = NULL;
+	ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL;
+	ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL;
+	ushort word;
+	ushort *wordp;
+	ushort sdtr_speed = 0;
 
-    boardp = ASC_BOARDP(shp);
-    adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
-    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
-    {
-        ep_3550 = &boardp->eep_config.adv_3550_eep;
-    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
-    {
-        ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
-    } else
-    {
-        ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
-    }
+	boardp = ASC_BOARDP(shost);
+	adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+	if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+		ep_3550 = &boardp->eep_config.adv_3550_eep;
+	} else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+		ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
+	} else {
+		ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
+	}
 
-    leftlen = cplen;
-    totlen = len = 0;
+	leftlen = cplen;
+	totlen = len = 0;
 
-    len = asc_prt_line(cp, leftlen,
-"\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   "\nEEPROM Settings for AdvanSys SCSI Host %d:\n",
+			   shost->host_no);
+	ASC_PRT_NEXT();
 
-    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
-    {
-        wordp = &ep_3550->serial_number_word1;
-    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
-    {
-        wordp = &ep_38C0800->serial_number_word1;
-    } else
-    {
-        wordp = &ep_38C1600->serial_number_word1;
-    }
+	if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+		wordp = &ep_3550->serial_number_word1;
+	} else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+		wordp = &ep_38C0800->serial_number_word1;
+	} else {
+		wordp = &ep_38C1600->serial_number_word1;
+	}
 
-    if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
-        len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr);
-        ASC_PRT_NEXT();
-    } else {
-        len = asc_prt_line(cp, leftlen,
-            " Serial Number Signature Not Present.\n");
-        ASC_PRT_NEXT();
-    }
+	if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
+		len =
+		    asc_prt_line(cp, leftlen, " Serial Number: %s\n",
+				 serialstr);
+		ASC_PRT_NEXT();
+	} else {
+		len = asc_prt_line(cp, leftlen,
+				   " Serial Number Signature Not Present.\n");
+		ASC_PRT_NEXT();
+	}
 
-    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
-    {
-        len = asc_prt_line(cp, leftlen,
-" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
-            ep_3550->adapter_scsi_id, ep_3550->max_host_qng,
-            ep_3550->max_dvc_qng);
-        ASC_PRT_NEXT();
-    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
-    {
-        len = asc_prt_line(cp, leftlen,
-" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
-            ep_38C0800->adapter_scsi_id, ep_38C0800->max_host_qng,
-            ep_38C0800->max_dvc_qng);
-        ASC_PRT_NEXT();
-    } else
-    {
-        len = asc_prt_line(cp, leftlen,
-" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
-            ep_38C1600->adapter_scsi_id, ep_38C1600->max_host_qng,
-            ep_38C1600->max_dvc_qng);
-        ASC_PRT_NEXT();
-    }
-    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
-    {
-        word = ep_3550->termination;
-    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
-    {
-        word = ep_38C0800->termination_lvd;
-    } else
-    {
-        word = ep_38C1600->termination_lvd;
-    }
-    switch (word) {
-        case 1:
-            termstr = "Low Off/High Off";
-            break;
-        case 2:
-            termstr = "Low Off/High On";
-            break;
-        case 3:
-            termstr = "Low On/High On";
-            break;
-        default:
-        case 0:
-            termstr = "Automatic";
-            break;
-    }
+	if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+		len = asc_prt_line(cp, leftlen,
+				   " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+				   ep_3550->adapter_scsi_id,
+				   ep_3550->max_host_qng, ep_3550->max_dvc_qng);
+		ASC_PRT_NEXT();
+	} else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+		len = asc_prt_line(cp, leftlen,
+				   " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+				   ep_38C0800->adapter_scsi_id,
+				   ep_38C0800->max_host_qng,
+				   ep_38C0800->max_dvc_qng);
+		ASC_PRT_NEXT();
+	} else {
+		len = asc_prt_line(cp, leftlen,
+				   " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+				   ep_38C1600->adapter_scsi_id,
+				   ep_38C1600->max_host_qng,
+				   ep_38C1600->max_dvc_qng);
+		ASC_PRT_NEXT();
+	}
+	if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+		word = ep_3550->termination;
+	} else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+		word = ep_38C0800->termination_lvd;
+	} else {
+		word = ep_38C1600->termination_lvd;
+	}
+	switch (word) {
+	case 1:
+		termstr = "Low Off/High Off";
+		break;
+	case 2:
+		termstr = "Low Off/High On";
+		break;
+	case 3:
+		termstr = "Low On/High On";
+		break;
+	default:
+	case 0:
+		termstr = "Automatic";
+		break;
+	}
 
-    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
-    {
-        len = asc_prt_line(cp, leftlen,
-" termination: %u (%s), bios_ctrl: 0x%x\n",
-            ep_3550->termination, termstr, ep_3550->bios_ctrl);
-        ASC_PRT_NEXT();
-    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
-    {
-        len = asc_prt_line(cp, leftlen,
-" termination: %u (%s), bios_ctrl: 0x%x\n",
-            ep_38C0800->termination_lvd, termstr, ep_38C0800->bios_ctrl);
-        ASC_PRT_NEXT();
-    } else
-    {
-        len = asc_prt_line(cp, leftlen,
-" termination: %u (%s), bios_ctrl: 0x%x\n",
-            ep_38C1600->termination_lvd, termstr, ep_38C1600->bios_ctrl);
-        ASC_PRT_NEXT();
-    }
+	if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+		len = asc_prt_line(cp, leftlen,
+				   " termination: %u (%s), bios_ctrl: 0x%x\n",
+				   ep_3550->termination, termstr,
+				   ep_3550->bios_ctrl);
+		ASC_PRT_NEXT();
+	} else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+		len = asc_prt_line(cp, leftlen,
+				   " termination: %u (%s), bios_ctrl: 0x%x\n",
+				   ep_38C0800->termination_lvd, termstr,
+				   ep_38C0800->bios_ctrl);
+		ASC_PRT_NEXT();
+	} else {
+		len = asc_prt_line(cp, leftlen,
+				   " termination: %u (%s), bios_ctrl: 0x%x\n",
+				   ep_38C1600->termination_lvd, termstr,
+				   ep_38C1600->bios_ctrl);
+		ASC_PRT_NEXT();
+	}
 
-    len = asc_prt_line(cp, leftlen,
-" Target ID:           ");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ADV_MAX_TID; i++) {
-        len = asc_prt_line(cp, leftlen, " %X", i);
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen, " Target ID:           ");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ADV_MAX_TID; i++) {
+		len = asc_prt_line(cp, leftlen, " %X", i);
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
-    {
-        word = ep_3550->disc_enable;
-    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
-    {
-        word = ep_38C0800->disc_enable;
-    } else
-    {
-        word = ep_38C1600->disc_enable;
-    }
-    len = asc_prt_line(cp, leftlen,
-" Disconnects:         ");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ADV_MAX_TID; i++) {
-        len = asc_prt_line(cp, leftlen, " %c",
-            (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+	if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+		word = ep_3550->disc_enable;
+	} else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+		word = ep_38C0800->disc_enable;
+	} else {
+		word = ep_38C1600->disc_enable;
+	}
+	len = asc_prt_line(cp, leftlen, " Disconnects:         ");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ADV_MAX_TID; i++) {
+		len = asc_prt_line(cp, leftlen, " %c",
+				   (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
-    {
-        word = ep_3550->tagqng_able;
-    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
-    {
-        word = ep_38C0800->tagqng_able;
-    } else
-    {
-        word = ep_38C1600->tagqng_able;
-    }
-    len = asc_prt_line(cp, leftlen,
-" Command Queuing:     ");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ADV_MAX_TID; i++) {
-        len = asc_prt_line(cp, leftlen, " %c",
-            (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+	if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+		word = ep_3550->tagqng_able;
+	} else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+		word = ep_38C0800->tagqng_able;
+	} else {
+		word = ep_38C1600->tagqng_able;
+	}
+	len = asc_prt_line(cp, leftlen, " Command Queuing:     ");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ADV_MAX_TID; i++) {
+		len = asc_prt_line(cp, leftlen, " %c",
+				   (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
-    {
-        word = ep_3550->start_motor;
-    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
-    {
-        word = ep_38C0800->start_motor;
-    } else
-    {
-        word = ep_38C1600->start_motor;
-    }
-    len = asc_prt_line(cp, leftlen,
-" Start Motor:         ");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ADV_MAX_TID; i++) {
-        len = asc_prt_line(cp, leftlen, " %c",
-            (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+	if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+		word = ep_3550->start_motor;
+	} else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+		word = ep_38C0800->start_motor;
+	} else {
+		word = ep_38C1600->start_motor;
+	}
+	len = asc_prt_line(cp, leftlen, " Start Motor:         ");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ADV_MAX_TID; i++) {
+		len = asc_prt_line(cp, leftlen, " %c",
+				   (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
-    {
-        len = asc_prt_line(cp, leftlen,
-" Synchronous Transfer:");
-        ASC_PRT_NEXT();
-        for (i = 0; i <= ADV_MAX_TID; i++) {
-            len = asc_prt_line(cp, leftlen, " %c",
-                (ep_3550->sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-            ASC_PRT_NEXT();
-        }
-        len = asc_prt_line(cp, leftlen, "\n");
-        ASC_PRT_NEXT();
-    }
+	if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+		len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
+		ASC_PRT_NEXT();
+		for (i = 0; i <= ADV_MAX_TID; i++) {
+			len = asc_prt_line(cp, leftlen, " %c",
+					   (ep_3550->
+					    sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
+					   'Y' : 'N');
+			ASC_PRT_NEXT();
+		}
+		len = asc_prt_line(cp, leftlen, "\n");
+		ASC_PRT_NEXT();
+	}
 
-    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
-    {
-        len = asc_prt_line(cp, leftlen,
-" Ultra Transfer:      ");
-    ASC_PRT_NEXT();
-        for (i = 0; i <= ADV_MAX_TID; i++) {
-            len = asc_prt_line(cp, leftlen, " %c",
-                (ep_3550->ultra_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-            ASC_PRT_NEXT();
-        }
-        len = asc_prt_line(cp, leftlen, "\n");
-        ASC_PRT_NEXT();
-    }
+	if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+		len = asc_prt_line(cp, leftlen, " Ultra Transfer:      ");
+		ASC_PRT_NEXT();
+		for (i = 0; i <= ADV_MAX_TID; i++) {
+			len = asc_prt_line(cp, leftlen, " %c",
+					   (ep_3550->
+					    ultra_able & ADV_TID_TO_TIDMASK(i))
+					   ? 'Y' : 'N');
+			ASC_PRT_NEXT();
+		}
+		len = asc_prt_line(cp, leftlen, "\n");
+		ASC_PRT_NEXT();
+	}
 
-    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
-    {
-        word = ep_3550->wdtr_able;
-    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
-    {
-        word = ep_38C0800->wdtr_able;
-    } else
-    {
-        word = ep_38C1600->wdtr_able;
-    }
-    len = asc_prt_line(cp, leftlen,
-" Wide Transfer:       ");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ADV_MAX_TID; i++) {
-        len = asc_prt_line(cp, leftlen, " %c",
-            (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+	if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+		word = ep_3550->wdtr_able;
+	} else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+		word = ep_38C0800->wdtr_able;
+	} else {
+		word = ep_38C1600->wdtr_able;
+	}
+	len = asc_prt_line(cp, leftlen, " Wide Transfer:       ");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ADV_MAX_TID; i++) {
+		len = asc_prt_line(cp, leftlen, " %c",
+				   (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
-        adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600)
-    {
-        len = asc_prt_line(cp, leftlen,
-" Synchronous Transfer Speed (Mhz):\n  ");
-        ASC_PRT_NEXT();
-        for (i = 0; i <= ADV_MAX_TID; i++) {
-            char *speed_str;
+	if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
+	    adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
+		len = asc_prt_line(cp, leftlen,
+				   " Synchronous Transfer Speed (Mhz):\n  ");
+		ASC_PRT_NEXT();
+		for (i = 0; i <= ADV_MAX_TID; i++) {
+			char *speed_str;
 
-            if (i == 0)
-            {
-                sdtr_speed = adv_dvc_varp->sdtr_speed1;
-            } else if (i == 4)
-            {
-                sdtr_speed = adv_dvc_varp->sdtr_speed2;
-            } else if (i == 8)
-            {
-                sdtr_speed = adv_dvc_varp->sdtr_speed3;
-            } else if (i == 12)
-            {
-                sdtr_speed = adv_dvc_varp->sdtr_speed4;
-            }
-            switch (sdtr_speed & ADV_MAX_TID)
-            {
-                case 0:  speed_str = "Off"; break;
-                case 1:  speed_str = "  5"; break;
-                case 2:  speed_str = " 10"; break;
-                case 3:  speed_str = " 20"; break;
-                case 4:  speed_str = " 40"; break;
-                case 5:  speed_str = " 80"; break;
-                default: speed_str = "Unk"; break;
-            }
-            len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
-            ASC_PRT_NEXT();
-            if (i == 7)
-            {
-                len = asc_prt_line(cp, leftlen, "\n  ");
-                ASC_PRT_NEXT();
-            }
-            sdtr_speed >>= 4;
-        }
-        len = asc_prt_line(cp, leftlen, "\n");
-        ASC_PRT_NEXT();
-    }
+			if (i == 0) {
+				sdtr_speed = adv_dvc_varp->sdtr_speed1;
+			} else if (i == 4) {
+				sdtr_speed = adv_dvc_varp->sdtr_speed2;
+			} else if (i == 8) {
+				sdtr_speed = adv_dvc_varp->sdtr_speed3;
+			} else if (i == 12) {
+				sdtr_speed = adv_dvc_varp->sdtr_speed4;
+			}
+			switch (sdtr_speed & ADV_MAX_TID) {
+			case 0:
+				speed_str = "Off";
+				break;
+			case 1:
+				speed_str = "  5";
+				break;
+			case 2:
+				speed_str = " 10";
+				break;
+			case 3:
+				speed_str = " 20";
+				break;
+			case 4:
+				speed_str = " 40";
+				break;
+			case 5:
+				speed_str = " 80";
+				break;
+			default:
+				speed_str = "Unk";
+				break;
+			}
+			len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
+			ASC_PRT_NEXT();
+			if (i == 7) {
+				len = asc_prt_line(cp, leftlen, "\n  ");
+				ASC_PRT_NEXT();
+			}
+			sdtr_speed >>= 4;
+		}
+		len = asc_prt_line(cp, leftlen, "\n");
+		ASC_PRT_NEXT();
+	}
 
-    return totlen;
+	return totlen;
 }
 
 /*
@@ -8062,60 +6871,60 @@
  * Return the number of characters copied into 'cp'. No more than
  * 'cplen' characters will be copied to 'cp'.
  */
-STATIC int
-asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
+static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen)
 {
-    asc_board_t            *boardp;
-    int                    leftlen;
-    int                    totlen;
-    int                    len;
-    int                    chip_scsi_id;
+	asc_board_t *boardp;
+	int leftlen;
+	int totlen;
+	int len;
+	int chip_scsi_id;
 
-    boardp = ASC_BOARDP(shp);
+	boardp = ASC_BOARDP(shost);
 
-    leftlen = cplen;
-    totlen = len = 0;
+	leftlen = cplen;
+	totlen = len = 0;
 
-    len = asc_prt_line(cp, leftlen,
-"\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
-        shp->host_no);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
+			   shost->host_no);
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
-        shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun,
-        shp->max_channel);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
+			   shost->host_busy, shost->last_reset, shost->max_id,
+			   shost->max_lun, shost->max_channel);
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
-        shp->unique_id, shp->can_queue, shp->this_id, shp->sg_tablesize,
-        shp->cmd_per_lun);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
+			   shost->unique_id, shost->can_queue, shost->this_id,
+			   shost->sg_tablesize, shost->cmd_per_lun);
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" unchecked_isa_dma %d, use_clustering %d\n",
-        shp->unchecked_isa_dma, shp->use_clustering);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   " unchecked_isa_dma %d, use_clustering %d\n",
+			   shost->unchecked_isa_dma, shost->use_clustering);
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
-        boardp->flags, boardp->last_reset, jiffies, boardp->asc_n_io_port);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
+			   boardp->flags, boardp->last_reset, jiffies,
+			   boardp->asc_n_io_port);
+	ASC_PRT_NEXT();
 
-     /* 'shp->n_io_port' may be truncated because it is only one byte. */
-    len = asc_prt_line(cp, leftlen,
-" io_port 0x%x, n_io_port 0x%x\n",
-        shp->io_port, shp->n_io_port);
-    ASC_PRT_NEXT();
+	/* 'shost->n_io_port' may be truncated because it is only one byte. */
+	len = asc_prt_line(cp, leftlen,
+			   " io_port 0x%x, n_io_port 0x%x\n",
+			   shost->io_port, shost->n_io_port);
+	ASC_PRT_NEXT();
 
-    if (ASC_NARROW_BOARD(boardp)) {
-        chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
-    } else {
-        chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
-    }
+	if (ASC_NARROW_BOARD(boardp)) {
+		chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
+	} else {
+		chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+	}
 
-    return totlen;
+	return totlen;
 }
 
 /*
@@ -8129,178 +6938,181 @@
  * Return the number of characters copied into 'cp'. No more than
  * 'cplen' characters will be copied to 'cp'.
  */
-STATIC int
-asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen)
+static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen)
 {
-    asc_board_t            *boardp;
-    int                    chip_scsi_id;
-    int                    leftlen;
-    int                    totlen;
-    int                    len;
-    ASC_DVC_VAR            *v;
-    ASC_DVC_CFG            *c;
-    int                    i;
-    int                    renegotiate = 0;
+	asc_board_t *boardp;
+	int chip_scsi_id;
+	int leftlen;
+	int totlen;
+	int len;
+	ASC_DVC_VAR *v;
+	ASC_DVC_CFG *c;
+	int i;
+	int renegotiate = 0;
 
-    boardp = ASC_BOARDP(shp);
-    v = &boardp->dvc_var.asc_dvc_var;
-    c = &boardp->dvc_cfg.asc_dvc_cfg;
-    chip_scsi_id = c->chip_scsi_id;
+	boardp = ASC_BOARDP(shost);
+	v = &boardp->dvc_var.asc_dvc_var;
+	c = &boardp->dvc_cfg.asc_dvc_cfg;
+	chip_scsi_id = c->chip_scsi_id;
 
-    leftlen = cplen;
-    totlen = len = 0;
+	leftlen = cplen;
+	totlen = len = 0;
 
-    len = asc_prt_line(cp, leftlen,
-"\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
-    shp->host_no);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
+			   shost->host_no);
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
-        c->chip_version, c->lib_version, c->lib_serial_no, c->mcode_date);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   " chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
+			   c->chip_version, c->lib_version, c->lib_serial_no,
+			   c->mcode_date);
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" mcode_version 0x%x, err_code %u\n",
-         c->mcode_version, v->err_code);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   " mcode_version 0x%x, err_code %u\n",
+			   c->mcode_version, v->err_code);
+	ASC_PRT_NEXT();
 
-    /* Current number of commands waiting for the host. */
-    len = asc_prt_line(cp, leftlen,
-" Total Command Pending: %d\n", v->cur_total_qng);
-    ASC_PRT_NEXT();
+	/* Current number of commands waiting for the host. */
+	len = asc_prt_line(cp, leftlen,
+			   " Total Command Pending: %d\n", v->cur_total_qng);
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" Command Queuing:");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ASC_MAX_TID; i++) {
-        if ((chip_scsi_id == i) ||
-            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-            continue;
-        }
-        len = asc_prt_line(cp, leftlen, " %X:%c",
-            i, (v->use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen, " Command Queuing:");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		if ((chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+			continue;
+		}
+		len = asc_prt_line(cp, leftlen, " %X:%c",
+				   i,
+				   (v->
+				    use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ?
+				   'Y' : 'N');
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    /* Current number of commands waiting for a device. */
-    len = asc_prt_line(cp, leftlen,
-" Command Queue Pending:");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ASC_MAX_TID; i++) {
-        if ((chip_scsi_id == i) ||
-            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-            continue;
-        }
-        len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+	/* Current number of commands waiting for a device. */
+	len = asc_prt_line(cp, leftlen, " Command Queue Pending:");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		if ((chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+			continue;
+		}
+		len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    /* Current limit on number of commands that can be sent to a device. */
-    len = asc_prt_line(cp, leftlen,
-" Command Queue Limit:");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ASC_MAX_TID; i++) {
-        if ((chip_scsi_id == i) ||
-            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-            continue;
-        }
-        len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+	/* Current limit on number of commands that can be sent to a device. */
+	len = asc_prt_line(cp, leftlen, " Command Queue Limit:");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		if ((chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+			continue;
+		}
+		len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    /* Indicate whether the device has returned queue full status. */
-    len = asc_prt_line(cp, leftlen,
-" Command Queue Full:");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ASC_MAX_TID; i++) {
-        if ((chip_scsi_id == i) ||
-            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-            continue;
-        }
-        if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
-            len = asc_prt_line(cp, leftlen, " %X:Y-%d",
-                i, boardp->queue_full_cnt[i]);
-        } else {
-            len = asc_prt_line(cp, leftlen, " %X:N", i);
-        }
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+	/* Indicate whether the device has returned queue full status. */
+	len = asc_prt_line(cp, leftlen, " Command Queue Full:");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		if ((chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+			continue;
+		}
+		if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
+			len = asc_prt_line(cp, leftlen, " %X:Y-%d",
+					   i, boardp->queue_full_cnt[i]);
+		} else {
+			len = asc_prt_line(cp, leftlen, " %X:N", i);
+		}
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" Synchronous Transfer:");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ASC_MAX_TID; i++) {
-        if ((chip_scsi_id == i) ||
-            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-            continue;
-        }
-        len = asc_prt_line(cp, leftlen, " %X:%c",
-            i, (v->sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen, " Synchronous Transfer:");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		if ((chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+			continue;
+		}
+		len = asc_prt_line(cp, leftlen, " %X:%c",
+				   i,
+				   (v->
+				    sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+				   'N');
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    for (i = 0; i <= ASC_MAX_TID; i++) {
-        uchar syn_period_ix;
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		uchar syn_period_ix;
 
-        if ((chip_scsi_id == i) ||
-            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
-            ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
-            continue;
-        }
+		if ((chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
+		    ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
+			continue;
+		}
 
-        len = asc_prt_line(cp, leftlen, "  %X:", i);
-        ASC_PRT_NEXT();
+		len = asc_prt_line(cp, leftlen, "  %X:", i);
+		ASC_PRT_NEXT();
 
-        if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0)
-        {
-            len = asc_prt_line(cp, leftlen, " Asynchronous");
-            ASC_PRT_NEXT();
-        } else
-        {
-            syn_period_ix =
-                (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - 1);
+		if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
+			len = asc_prt_line(cp, leftlen, " Asynchronous");
+			ASC_PRT_NEXT();
+		} else {
+			syn_period_ix =
+			    (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
+							   1);
 
-            len = asc_prt_line(cp, leftlen,
-                " Transfer Period Factor: %d (%d.%d Mhz),",
-                v->sdtr_period_tbl[syn_period_ix],
-                250 / v->sdtr_period_tbl[syn_period_ix],
-                ASC_TENTHS(250, v->sdtr_period_tbl[syn_period_ix]));
-            ASC_PRT_NEXT();
+			len = asc_prt_line(cp, leftlen,
+					   " Transfer Period Factor: %d (%d.%d Mhz),",
+					   v->sdtr_period_tbl[syn_period_ix],
+					   250 /
+					   v->sdtr_period_tbl[syn_period_ix],
+					   ASC_TENTHS(250,
+						      v->
+						      sdtr_period_tbl
+						      [syn_period_ix]));
+			ASC_PRT_NEXT();
 
-            len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
-                boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET);
-            ASC_PRT_NEXT();
-        }
+			len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
+					   boardp->
+					   sdtr_data[i] & ASC_SYN_MAX_OFFSET);
+			ASC_PRT_NEXT();
+		}
 
-        if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
-            len = asc_prt_line(cp, leftlen, "*\n");
-            renegotiate = 1;
-        } else
-        {
-            len = asc_prt_line(cp, leftlen, "\n");
-        }
-        ASC_PRT_NEXT();
-    }
+		if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+			len = asc_prt_line(cp, leftlen, "*\n");
+			renegotiate = 1;
+		} else {
+			len = asc_prt_line(cp, leftlen, "\n");
+		}
+		ASC_PRT_NEXT();
+	}
 
-    if (renegotiate)
-    {
-        len = asc_prt_line(cp, leftlen,
-            " * = Re-negotiation pending before next command.\n");
-        ASC_PRT_NEXT();
-    }
+	if (renegotiate) {
+		len = asc_prt_line(cp, leftlen,
+				   " * = Re-negotiation pending before next command.\n");
+		ASC_PRT_NEXT();
+	}
 
-    return totlen;
+	return totlen;
 }
 
 /*
@@ -8314,237 +7126,242 @@
  * Return the number of characters copied into 'cp'. No more than
  * 'cplen' characters will be copied to 'cp'.
  */
-STATIC int
-asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen)
+static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen)
 {
-    asc_board_t            *boardp;
-    int                    leftlen;
-    int                    totlen;
-    int                    len;
-    int                    i;
-    ADV_DVC_VAR            *v;
-    ADV_DVC_CFG            *c;
-    AdvPortAddr            iop_base;
-    ushort                 chip_scsi_id;
-    ushort                 lramword;
-    uchar                  lrambyte;
-    ushort                 tagqng_able;
-    ushort                 sdtr_able, wdtr_able;
-    ushort                 wdtr_done, sdtr_done;
-    ushort                 period = 0;
-    int                    renegotiate = 0;
+	asc_board_t *boardp;
+	int leftlen;
+	int totlen;
+	int len;
+	int i;
+	ADV_DVC_VAR *v;
+	ADV_DVC_CFG *c;
+	AdvPortAddr iop_base;
+	ushort chip_scsi_id;
+	ushort lramword;
+	uchar lrambyte;
+	ushort tagqng_able;
+	ushort sdtr_able, wdtr_able;
+	ushort wdtr_done, sdtr_done;
+	ushort period = 0;
+	int renegotiate = 0;
 
-    boardp = ASC_BOARDP(shp);
-    v = &boardp->dvc_var.adv_dvc_var;
-    c = &boardp->dvc_cfg.adv_dvc_cfg;
-    iop_base = v->iop_base;
-    chip_scsi_id = v->chip_scsi_id;
+	boardp = ASC_BOARDP(shost);
+	v = &boardp->dvc_var.adv_dvc_var;
+	c = &boardp->dvc_cfg.adv_dvc_cfg;
+	iop_base = v->iop_base;
+	chip_scsi_id = v->chip_scsi_id;
 
-    leftlen = cplen;
-    totlen = len = 0;
+	leftlen = cplen;
+	totlen = len = 0;
 
-    len = asc_prt_line(cp, leftlen,
-"\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
-    shp->host_no);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
+			   shost->host_no);
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" iop_base 0x%lx, cable_detect: %X, err_code %u\n",
-         v->iop_base,
-         AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1) & CABLE_DETECT,
-         v->err_code);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   " iop_base 0x%lx, cable_detect: %X, err_code %u\n",
+			   v->iop_base,
+			   AdvReadWordRegister(iop_base,
+					       IOPW_SCSI_CFG1) & CABLE_DETECT,
+			   v->err_code);
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
-        c->chip_version, c->lib_version, c->mcode_date, c->mcode_version);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   " chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
+			   c->chip_version, c->lib_version, c->mcode_date,
+			   c->mcode_version);
+	ASC_PRT_NEXT();
 
-    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
-    len = asc_prt_line(cp, leftlen,
-" Queuing Enabled:");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ADV_MAX_TID; i++) {
-        if ((chip_scsi_id == i) ||
-            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-            continue;
-        }
+	AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+	len = asc_prt_line(cp, leftlen, " Queuing Enabled:");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ADV_MAX_TID; i++) {
+		if ((chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+			continue;
+		}
 
-        len = asc_prt_line(cp, leftlen, " %X:%c",
-            i, (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+		len = asc_prt_line(cp, leftlen, " %X:%c",
+				   i,
+				   (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+				   'N');
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" Queue Limit:");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ADV_MAX_TID; i++) {
-        if ((chip_scsi_id == i) ||
-            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-            continue;
-        }
+	len = asc_prt_line(cp, leftlen, " Queue Limit:");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ADV_MAX_TID; i++) {
+		if ((chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+			continue;
+		}
 
-        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i, lrambyte);
+		AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i,
+				lrambyte);
 
-        len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+		len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" Command Pending:");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ADV_MAX_TID; i++) {
-        if ((chip_scsi_id == i) ||
-            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-            continue;
-        }
+	len = asc_prt_line(cp, leftlen, " Command Pending:");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ADV_MAX_TID; i++) {
+		if ((chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+			continue;
+		}
 
-        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i, lrambyte);
+		AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i,
+				lrambyte);
 
-        len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+		len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
-    len = asc_prt_line(cp, leftlen,
-" Wide Enabled:");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ADV_MAX_TID; i++) {
-        if ((chip_scsi_id == i) ||
-            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-            continue;
-        }
+	AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+	len = asc_prt_line(cp, leftlen, " Wide Enabled:");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ADV_MAX_TID; i++) {
+		if ((chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+			continue;
+		}
 
-        len = asc_prt_line(cp, leftlen, " %X:%c",
-            i, (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+		len = asc_prt_line(cp, leftlen, " %X:%c",
+				   i,
+				   (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+				   'N');
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
-    len = asc_prt_line(cp, leftlen,
-" Transfer Bit Width:");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ADV_MAX_TID; i++) {
-        if ((chip_scsi_id == i) ||
-            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-            continue;
-        }
+	AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
+	len = asc_prt_line(cp, leftlen, " Transfer Bit Width:");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ADV_MAX_TID; i++) {
+		if ((chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+			continue;
+		}
 
-        AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
-            lramword);
+		AdvReadWordLram(iop_base,
+				ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
+				lramword);
 
-        len = asc_prt_line(cp, leftlen, " %X:%d",
-            i, (lramword & 0x8000) ? 16 : 8);
-        ASC_PRT_NEXT();
+		len = asc_prt_line(cp, leftlen, " %X:%d",
+				   i, (lramword & 0x8000) ? 16 : 8);
+		ASC_PRT_NEXT();
 
-        if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
-            (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
-            len = asc_prt_line(cp, leftlen, "*");
-            ASC_PRT_NEXT();
-            renegotiate = 1;
-        }
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+		if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
+		    (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+			len = asc_prt_line(cp, leftlen, "*");
+			ASC_PRT_NEXT();
+			renegotiate = 1;
+		}
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-    len = asc_prt_line(cp, leftlen,
-" Synchronous Enabled:");
-    ASC_PRT_NEXT();
-    for (i = 0; i <= ADV_MAX_TID; i++) {
-        if ((chip_scsi_id == i) ||
-            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
-            continue;
-        }
+	AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+	len = asc_prt_line(cp, leftlen, " Synchronous Enabled:");
+	ASC_PRT_NEXT();
+	for (i = 0; i <= ADV_MAX_TID; i++) {
+		if ((chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+			continue;
+		}
 
-        len = asc_prt_line(cp, leftlen, " %X:%c",
-            i, (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
-        ASC_PRT_NEXT();
-    }
-    len = asc_prt_line(cp, leftlen, "\n");
-    ASC_PRT_NEXT();
+		len = asc_prt_line(cp, leftlen, " %X:%c",
+				   i,
+				   (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' :
+				   'N');
+		ASC_PRT_NEXT();
+	}
+	len = asc_prt_line(cp, leftlen, "\n");
+	ASC_PRT_NEXT();
 
-    AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
-    for (i = 0; i <= ADV_MAX_TID; i++) {
+	AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
+	for (i = 0; i <= ADV_MAX_TID; i++) {
 
-        AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
-            lramword);
-        lramword &= ~0x8000;
+		AdvReadWordLram(iop_base,
+				ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
+				lramword);
+		lramword &= ~0x8000;
 
-        if ((chip_scsi_id == i) ||
-            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
-            ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
-            continue;
-        }
+		if ((chip_scsi_id == i) ||
+		    ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
+		    ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
+			continue;
+		}
 
-        len = asc_prt_line(cp, leftlen, "  %X:", i);
-        ASC_PRT_NEXT();
+		len = asc_prt_line(cp, leftlen, "  %X:", i);
+		ASC_PRT_NEXT();
 
-        if ((lramword & 0x1F) == 0) /* Check for REQ/ACK Offset 0. */
-        {
-            len = asc_prt_line(cp, leftlen, " Asynchronous");
-            ASC_PRT_NEXT();
-        } else
-        {
-            len = asc_prt_line(cp, leftlen, " Transfer Period Factor: ");
-            ASC_PRT_NEXT();
+		if ((lramword & 0x1F) == 0) {	/* Check for REQ/ACK Offset 0. */
+			len = asc_prt_line(cp, leftlen, " Asynchronous");
+			ASC_PRT_NEXT();
+		} else {
+			len =
+			    asc_prt_line(cp, leftlen,
+					 " Transfer Period Factor: ");
+			ASC_PRT_NEXT();
 
-            if ((lramword & 0x1F00) == 0x1100) /* 80 Mhz */
-            {
-                len = asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
-                ASC_PRT_NEXT();
-            } else if ((lramword & 0x1F00) == 0x1000) /* 40 Mhz */
-            {
-                len = asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
-                ASC_PRT_NEXT();
-            } else /* 20 Mhz or below. */
-            {
-                period = (((lramword >> 8) * 25) + 50)/4;
+			if ((lramword & 0x1F00) == 0x1100) {	/* 80 Mhz */
+				len =
+				    asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
+				ASC_PRT_NEXT();
+			} else if ((lramword & 0x1F00) == 0x1000) {	/* 40 Mhz */
+				len =
+				    asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
+				ASC_PRT_NEXT();
+			} else {	/* 20 Mhz or below. */
 
-                if (period == 0) /* Should never happen. */
-                {
-                    len = asc_prt_line(cp, leftlen, "%d (? Mhz), ");
-                    ASC_PRT_NEXT();
-                } else
-                {
-                    len = asc_prt_line(cp, leftlen,
-                        "%d (%d.%d Mhz),",
-                        period, 250/period, ASC_TENTHS(250, period));
-                    ASC_PRT_NEXT();
-                }
-            }
+				period = (((lramword >> 8) * 25) + 50) / 4;
 
-            len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
-                lramword & 0x1F);
-            ASC_PRT_NEXT();
-        }
+				if (period == 0) {	/* Should never happen. */
+					len =
+					    asc_prt_line(cp, leftlen,
+							 "%d (? Mhz), ");
+					ASC_PRT_NEXT();
+				} else {
+					len = asc_prt_line(cp, leftlen,
+							   "%d (%d.%d Mhz),",
+							   period, 250 / period,
+							   ASC_TENTHS(250,
+								      period));
+					ASC_PRT_NEXT();
+				}
+			}
 
-        if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
-            len = asc_prt_line(cp, leftlen, "*\n");
-            renegotiate = 1;
-        } else
-        {
-            len = asc_prt_line(cp, leftlen, "\n");
-        }
-        ASC_PRT_NEXT();
-    }
+			len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
+					   lramword & 0x1F);
+			ASC_PRT_NEXT();
+		}
 
-    if (renegotiate)
-    {
-        len = asc_prt_line(cp, leftlen,
-            " * = Re-negotiation pending before next command.\n");
-        ASC_PRT_NEXT();
-    }
+		if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+			len = asc_prt_line(cp, leftlen, "*\n");
+			renegotiate = 1;
+		} else {
+			len = asc_prt_line(cp, leftlen, "\n");
+		}
+		ASC_PRT_NEXT();
+	}
 
-    return totlen;
+	if (renegotiate) {
+		len = asc_prt_line(cp, leftlen,
+				   " * = Re-negotiation pending before next command.\n");
+		ASC_PRT_NEXT();
+	}
+
+	return totlen;
 }
 
 /*
@@ -8553,30 +7370,30 @@
  * Copy proc information to a read buffer taking into account the current
  * read offset in the file and the remaining space in the read buffer.
  */
-STATIC int
+static int
 asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
-              char *cp, int cplen)
+	      char *cp, int cplen)
 {
-    int cnt = 0;
+	int cnt = 0;
 
-    ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
-            (unsigned) offset, (unsigned) advoffset, cplen);
-    if (offset <= advoffset) {
-        /* Read offset below current offset, copy everything. */
-        cnt = min(cplen, leftlen);
-        ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
-                (ulong) curbuf, (ulong) cp, cnt);
-        memcpy(curbuf, cp, cnt);
-    } else if (offset < advoffset + cplen) {
-        /* Read offset within current range, partial copy. */
-        cnt = (advoffset + cplen) - offset;
-        cp = (cp + cplen) - cnt;
-        cnt = min(cnt, leftlen);
-        ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
-                (ulong) curbuf, (ulong) cp, cnt);
-        memcpy(curbuf, cp, cnt);
-    }
-    return cnt;
+	ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
+		 (unsigned)offset, (unsigned)advoffset, cplen);
+	if (offset <= advoffset) {
+		/* Read offset below current offset, copy everything. */
+		cnt = min(cplen, leftlen);
+		ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
+			 (ulong)curbuf, (ulong)cp, cnt);
+		memcpy(curbuf, cp, cnt);
+	} else if (offset < advoffset + cplen) {
+		/* Read offset within current range, partial copy. */
+		cnt = (advoffset + cplen) - offset;
+		cp = (cp + cplen) - cnt;
+		cnt = min(cnt, leftlen);
+		ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
+			 (ulong)curbuf, (ulong)cp, cnt);
+		memcpy(curbuf, cp, cnt);
+	}
+	return cnt;
 }
 
 /*
@@ -8590,29 +7407,27 @@
  * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
  * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
  */
-STATIC int
-asc_prt_line(char *buf, int buflen, char *fmt, ...)
+static int asc_prt_line(char *buf, int buflen, char *fmt, ...)
 {
-    va_list        args;
-    int            ret;
-    char           s[ASC_PRTLINE_SIZE];
+	va_list args;
+	int ret;
+	char s[ASC_PRTLINE_SIZE];
 
-    va_start(args, fmt);
-    ret = vsprintf(s, fmt, args);
-    ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
-    if (buf == NULL) {
-        (void) printk(s);
-        ret = 0;
-    } else {
-        ret = min(buflen, ret);
-        memcpy(buf, s, ret);
-    }
-    va_end(args);
-    return ret;
+	va_start(args, fmt);
+	ret = vsprintf(s, fmt, args);
+	ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
+	if (buf == NULL) {
+		(void)printk(s);
+		ret = 0;
+	} else {
+		ret = min(buflen, ret);
+		memcpy(buf, s, ret);
+	}
+	va_end(args);
+	return ret;
 }
 #endif /* CONFIG_PROC_FS */
 
-
 /*
  * --- Functions Required by the Asc Library
  */
@@ -8623,31 +7438,28 @@
  * from a timer interrupt, because this function may be
  * called when interrupts are disabled.
  */
-STATIC void
-DvcSleepMilliSecond(ADV_DCNT n)
+static void DvcSleepMilliSecond(ADV_DCNT n)
 {
-    ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong) n);
-    mdelay(n);
+	ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong)n);
+	mdelay(n);
 }
 
 /*
  * Currently and inline noop but leave as a placeholder.
  * Leave DvcEnterCritical() as a noop placeholder.
  */
-STATIC inline ulong
-DvcEnterCritical(void)
+static inline ulong DvcEnterCritical(void)
 {
-    return 0;
+	return 0;
 }
 
 /*
  * Critical sections are all protected by the board spinlock.
  * Leave DvcLeaveCritical() as a noop placeholder.
  */
-STATIC inline void
-DvcLeaveCritical(ulong flags)
+static inline void DvcLeaveCritical(ulong flags)
 {
-    return;
+	return;
 }
 
 /*
@@ -8660,20 +7472,20 @@
  * Description:
  *     Output an ASC_SCSI_Q structure to the chip
  */
-STATIC void
+static void
 DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
 {
-    int    i;
+	int i;
 
-    ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
-    AscSetChipLramAddr(iop_base, s_addr);
-    for (i = 0; i < 2 * words; i += 2) {
-        if (i == 4 || i == 20) {
-            continue;
-        }
-        outpw(iop_base + IOP_RAM_DATA,
-            ((ushort) outbuf[i + 1] << 8) | outbuf[i]);
-    }
+	ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
+	AscSetChipLramAddr(iop_base, s_addr);
+	for (i = 0; i < 2 * words; i += 2) {
+		if (i == 4 || i == 20) {
+			continue;
+		}
+		outpw(iop_base + IOP_RAM_DATA,
+		      ((ushort)outbuf[i + 1] << 8) | outbuf[i]);
+	}
 }
 
 /*
@@ -8686,52 +7498,46 @@
  * Description:
  *     Input an ASC_QDONE_INFO structure from the chip
  */
-STATIC void
+static void
 DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
 {
-    int    i;
-    ushort word;
+	int i;
+	ushort word;
 
-    AscSetChipLramAddr(iop_base, s_addr);
-    for (i = 0; i < 2 * words; i += 2) {
-        if (i == 10) {
-            continue;
-        }
-        word = inpw(iop_base + IOP_RAM_DATA);
-        inbuf[i] = word & 0xff;
-        inbuf[i + 1] = (word >> 8) & 0xff;
-    }
-    ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
+	AscSetChipLramAddr(iop_base, s_addr);
+	for (i = 0; i < 2 * words; i += 2) {
+		if (i == 10) {
+			continue;
+		}
+		word = inpw(iop_base + IOP_RAM_DATA);
+		inbuf[i] = word & 0xff;
+		inbuf[i + 1] = (word >> 8) & 0xff;
+	}
+	ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
 }
 
 /*
  * Read a PCI configuration byte.
  */
-STATIC uchar __init
-DvcReadPCIConfigByte(
-        ASC_DVC_VAR *asc_dvc,
-        ushort offset)
+static uchar __init DvcReadPCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset)
 {
 #ifdef CONFIG_PCI
-    uchar byte_data;
-    pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
-    return byte_data;
+	uchar byte_data;
+	pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
+	return byte_data;
 #else /* !defined(CONFIG_PCI) */
-    return 0;
+	return 0;
 #endif /* !defined(CONFIG_PCI) */
 }
 
 /*
  * Write a PCI configuration byte.
  */
-STATIC void __init
-DvcWritePCIConfigByte(
-        ASC_DVC_VAR *asc_dvc,
-        ushort offset,
-        uchar  byte_data)
+static void __init
+DvcWritePCIConfigByte(ASC_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
 {
 #ifdef CONFIG_PCI
-    pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
+	pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
 #endif /* CONFIG_PCI */
 }
 
@@ -8739,51 +7545,43 @@
  * Return the BIOS address of the adapter at the specified
  * I/O port and with the specified bus type.
  */
-STATIC ushort __init
-AscGetChipBiosAddress(
-        PortAddr iop_base,
-        ushort bus_type)
+static ushort __init AscGetChipBiosAddress(PortAddr iop_base, ushort bus_type)
 {
-    ushort  cfg_lsw;
-    ushort  bios_addr;
+	ushort cfg_lsw;
+	ushort bios_addr;
 
-    /*
-     * The PCI BIOS is re-located by the motherboard BIOS. Because
-     * of this the driver can not determine where a PCI BIOS is
-     * loaded and executes.
-     */
-    if (bus_type & ASC_IS_PCI)
-    {
-        return(0);
-    }
-
+	/*
+	 * The PCI BIOS is re-located by the motherboard BIOS. Because
+	 * of this the driver can not determine where a PCI BIOS is
+	 * loaded and executes.
+	 */
+	if (bus_type & ASC_IS_PCI) {
+		return (0);
+	}
 #ifdef CONFIG_ISA
-    if((bus_type & ASC_IS_EISA) != 0)
-    {
-        cfg_lsw = AscGetEisaChipCfg(iop_base);
-        cfg_lsw &= 0x000F;
-        bios_addr = (ushort)(ASC_BIOS_MIN_ADDR  +
-                                (cfg_lsw * ASC_BIOS_BANK_SIZE));
-        return(bios_addr);
-    }/* if */
+	if ((bus_type & ASC_IS_EISA) != 0) {
+		cfg_lsw = AscGetEisaChipCfg(iop_base);
+		cfg_lsw &= 0x000F;
+		bios_addr = (ushort)(ASC_BIOS_MIN_ADDR +
+				     (cfg_lsw * ASC_BIOS_BANK_SIZE));
+		return (bios_addr);
+	}			/* if */
 #endif /* CONFIG_ISA */
 
-    cfg_lsw = AscGetChipCfgLsw(iop_base);
+	cfg_lsw = AscGetChipCfgLsw(iop_base);
 
-    /*
-    *  ISA PnP uses the top bit as the 32K BIOS flag
-    */
-    if (bus_type == ASC_IS_ISAPNP)
-    {
-        cfg_lsw &= 0x7FFF;
-    }/* if */
-
-    bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
-            ASC_BIOS_MIN_ADDR);
-    return(bios_addr);
+	/*
+	 *  ISA PnP uses the top bit as the 32K BIOS flag
+	 */
+	if (bus_type == ASC_IS_ISAPNP) {
+		cfg_lsw &= 0x7FFF;
+	}
+	/* if */
+	bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
+			     ASC_BIOS_MIN_ADDR);
+	return (bios_addr);
 }
 
-
 /*
  * --- Functions Required by the Adv Library
  */
@@ -8801,49 +7599,44 @@
  */
 ADV_PADDR
 DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
-        uchar *vaddr, ADV_SDCNT *lenp, int flag)
+	      uchar *vaddr, ADV_SDCNT *lenp, int flag)
 {
-    ADV_PADDR           paddr;
+	ADV_PADDR paddr;
 
-    paddr = virt_to_bus(vaddr);
+	paddr = virt_to_bus(vaddr);
 
-    ASC_DBG4(4,
-        "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
-        (ulong) vaddr, (ulong) lenp, (ulong) *((ulong *) lenp), (ulong) paddr);
+	ASC_DBG4(4,
+		 "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
+		 (ulong)vaddr, (ulong)lenp, (ulong)*((ulong *)lenp),
+		 (ulong)paddr);
 
-    return paddr;
+	return paddr;
 }
 
 /*
  * Read a PCI configuration byte.
  */
-STATIC uchar __init
-DvcAdvReadPCIConfigByte(
-        ADV_DVC_VAR *asc_dvc,
-        ushort offset)
+static uchar __init DvcAdvReadPCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset)
 {
 #ifdef CONFIG_PCI
-    uchar byte_data;
-    pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
-    return byte_data;
+	uchar byte_data;
+	pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
+	return byte_data;
 #else /* CONFIG_PCI */
-    return 0;
+	return 0;
 #endif /* CONFIG_PCI */
 }
 
 /*
  * Write a PCI configuration byte.
  */
-STATIC void __init
-DvcAdvWritePCIConfigByte(
-        ADV_DVC_VAR *asc_dvc,
-        ushort offset,
-        uchar  byte_data)
+static void __init
+DvcAdvWritePCIConfigByte(ADV_DVC_VAR *asc_dvc, ushort offset, uchar byte_data)
 {
 #ifdef CONFIG_PCI
-    pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
+	pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
 #else /* CONFIG_PCI */
-    return;
+	return;
 #endif /* CONFIG_PCI */
 }
 
@@ -8862,97 +7655,98 @@
  * Return the number of characters copied into 'cp'. No more than
  * 'cplen' characters will be copied to 'cp'.
  */
-STATIC int
-asc_prt_board_stats(struct Scsi_Host *shp, char *cp, int cplen)
+static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen)
 {
-    int                    leftlen;
-    int                    totlen;
-    int                    len;
-    struct asc_stats       *s;
-    asc_board_t            *boardp;
+	int leftlen;
+	int totlen;
+	int len;
+	struct asc_stats *s;
+	asc_board_t *boardp;
 
-    leftlen = cplen;
-    totlen = len = 0;
+	leftlen = cplen;
+	totlen = len = 0;
 
-    boardp = ASC_BOARDP(shp);
-    s = &boardp->asc_stats;
+	boardp = ASC_BOARDP(shost);
+	s = &boardp->asc_stats;
 
-    len = asc_prt_line(cp, leftlen,
-"\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n", shp->host_no);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n",
+			   shost->host_no);
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
-        s->queuecommand, s->reset, s->biosparam, s->interrupt);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
+			   s->queuecommand, s->reset, s->biosparam,
+			   s->interrupt);
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
-        s->callback, s->done, s->build_error, s->adv_build_noreq,
-        s->adv_build_nosg);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
+			   s->callback, s->done, s->build_error,
+			   s->adv_build_noreq, s->adv_build_nosg);
+	ASC_PRT_NEXT();
 
-    len = asc_prt_line(cp, leftlen,
-" exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
-        s->exe_noerror, s->exe_busy, s->exe_error, s->exe_unknown);
-    ASC_PRT_NEXT();
+	len = asc_prt_line(cp, leftlen,
+			   " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
+			   s->exe_noerror, s->exe_busy, s->exe_error,
+			   s->exe_unknown);
+	ASC_PRT_NEXT();
 
-    /*
-     * Display data transfer statistics.
-     */
-    if (s->cont_cnt > 0) {
-        len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
-        ASC_PRT_NEXT();
+	/*
+	 * Display data transfer statistics.
+	 */
+	if (s->cont_cnt > 0) {
+		len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
+		ASC_PRT_NEXT();
 
-        len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
-                    s->cont_xfer/2,
-                    ASC_TENTHS(s->cont_xfer, 2));
-        ASC_PRT_NEXT();
+		len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
+				   s->cont_xfer / 2,
+				   ASC_TENTHS(s->cont_xfer, 2));
+		ASC_PRT_NEXT();
 
-        /* Contiguous transfer average size */
-        len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
-                    (s->cont_xfer/2)/s->cont_cnt,
-                    ASC_TENTHS((s->cont_xfer/2), s->cont_cnt));
-        ASC_PRT_NEXT();
-    }
+		/* Contiguous transfer average size */
+		len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
+				   (s->cont_xfer / 2) / s->cont_cnt,
+				   ASC_TENTHS((s->cont_xfer / 2), s->cont_cnt));
+		ASC_PRT_NEXT();
+	}
 
-    if (s->sg_cnt > 0) {
+	if (s->sg_cnt > 0) {
 
-        len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
-                    s->sg_cnt, s->sg_elem);
-        ASC_PRT_NEXT();
+		len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
+				   s->sg_cnt, s->sg_elem);
+		ASC_PRT_NEXT();
 
-        len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
-                    s->sg_xfer/2,
-                    ASC_TENTHS(s->sg_xfer, 2));
-        ASC_PRT_NEXT();
+		len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
+				   s->sg_xfer / 2, ASC_TENTHS(s->sg_xfer, 2));
+		ASC_PRT_NEXT();
 
-        /* Scatter gather transfer statistics */
-        len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
-                    s->sg_elem/s->sg_cnt,
-                    ASC_TENTHS(s->sg_elem, s->sg_cnt));
-        ASC_PRT_NEXT();
+		/* Scatter gather transfer statistics */
+		len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
+				   s->sg_elem / s->sg_cnt,
+				   ASC_TENTHS(s->sg_elem, s->sg_cnt));
+		ASC_PRT_NEXT();
 
-        len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
-                    (s->sg_xfer/2)/s->sg_elem,
-                    ASC_TENTHS((s->sg_xfer/2), s->sg_elem));
-        ASC_PRT_NEXT();
+		len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
+				   (s->sg_xfer / 2) / s->sg_elem,
+				   ASC_TENTHS((s->sg_xfer / 2), s->sg_elem));
+		ASC_PRT_NEXT();
 
-        len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
-                    (s->sg_xfer/2)/s->sg_cnt,
-                    ASC_TENTHS((s->sg_xfer/2), s->sg_cnt));
-        ASC_PRT_NEXT();
-    }
+		len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
+				   (s->sg_xfer / 2) / s->sg_cnt,
+				   ASC_TENTHS((s->sg_xfer / 2), s->sg_cnt));
+		ASC_PRT_NEXT();
+	}
 
-    /*
-     * Display request queuing statistics.
-     */
-    len = asc_prt_line(cp, leftlen,
-" Active and Waiting Request Queues (Time Unit: %d HZ):\n", HZ);
-    ASC_PRT_NEXT();
+	/*
+	 * Display request queuing statistics.
+	 */
+	len = asc_prt_line(cp, leftlen,
+			   " Active and Waiting Request Queues (Time Unit: %d HZ):\n",
+			   HZ);
+	ASC_PRT_NEXT();
 
-
-     return totlen;
+	return totlen;
 }
 
 /*
@@ -8967,70 +7761,89 @@
  * Return the number of characters copied into 'cp'. No more than
  * 'cplen' characters will be copied to 'cp'.
  */
-STATIC int
-asc_prt_target_stats(struct Scsi_Host *shp, int tgt_id, char *cp, int cplen)
+static int
+asc_prt_target_stats(struct Scsi_Host *shost, int tgt_id, char *cp, int cplen)
 {
-    int                    leftlen;
-    int                    totlen;
-    int                    len;
-    struct asc_stats       *s;
-    ushort                 chip_scsi_id;
-    asc_board_t            *boardp;
-    asc_queue_t            *active;
-    asc_queue_t            *waiting;
+	int leftlen;
+	int totlen;
+	int len;
+	struct asc_stats *s;
+	ushort chip_scsi_id;
+	asc_board_t *boardp;
+	asc_queue_t *active;
+	asc_queue_t *waiting;
 
-    leftlen = cplen;
-    totlen = len = 0;
+	leftlen = cplen;
+	totlen = len = 0;
 
-    boardp = ASC_BOARDP(shp);
-    s = &boardp->asc_stats;
+	boardp = ASC_BOARDP(shost);
+	s = &boardp->asc_stats;
 
-    active = &ASC_BOARDP(shp)->active;
-    waiting = &ASC_BOARDP(shp)->waiting;
+	active = &ASC_BOARDP(shost)->active;
+	waiting = &ASC_BOARDP(shost)->waiting;
 
-    if (ASC_NARROW_BOARD(boardp)) {
-        chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
-    } else {
-        chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
-    }
+	if (ASC_NARROW_BOARD(boardp)) {
+		chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
+	} else {
+		chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+	}
 
-    if ((chip_scsi_id == tgt_id) ||
-        ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
-        return 0;
-    }
+	if ((chip_scsi_id == tgt_id) ||
+	    ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
+		return 0;
+	}
 
-    do {
-        if (active->q_tot_cnt[tgt_id] > 0 || waiting->q_tot_cnt[tgt_id] > 0) {
-            len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
-            ASC_PRT_NEXT();
+	do {
+		if (active->q_tot_cnt[tgt_id] > 0
+		    || waiting->q_tot_cnt[tgt_id] > 0) {
+			len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
+			ASC_PRT_NEXT();
 
-            len = asc_prt_line(cp, leftlen,
-"   active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
-                active->q_cur_cnt[tgt_id], active->q_max_cnt[tgt_id],
-                active->q_tot_cnt[tgt_id],
-                active->q_min_tim[tgt_id], active->q_max_tim[tgt_id],
-                (active->q_tot_cnt[tgt_id] == 0) ? 0 :
-                (active->q_tot_tim[tgt_id]/active->q_tot_cnt[tgt_id]),
-                (active->q_tot_cnt[tgt_id] == 0) ? 0 :
-                ASC_TENTHS(active->q_tot_tim[tgt_id],
-                active->q_tot_cnt[tgt_id]));
-             ASC_PRT_NEXT();
+			len = asc_prt_line(cp, leftlen,
+					   "   active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
+					   active->q_cur_cnt[tgt_id],
+					   active->q_max_cnt[tgt_id],
+					   active->q_tot_cnt[tgt_id],
+					   active->q_min_tim[tgt_id],
+					   active->q_max_tim[tgt_id],
+					   (active->q_tot_cnt[tgt_id] ==
+					    0) ? 0 : (active->
+						      q_tot_tim[tgt_id] /
+						      active->
+						      q_tot_cnt[tgt_id]),
+					   (active->q_tot_cnt[tgt_id] ==
+					    0) ? 0 : ASC_TENTHS(active->
+								q_tot_tim
+								[tgt_id],
+								active->
+								q_tot_cnt
+								[tgt_id]));
+			ASC_PRT_NEXT();
 
-             len = asc_prt_line(cp, leftlen,
-"   waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
-                waiting->q_cur_cnt[tgt_id], waiting->q_max_cnt[tgt_id],
-                waiting->q_tot_cnt[tgt_id],
-                waiting->q_min_tim[tgt_id], waiting->q_max_tim[tgt_id],
-                (waiting->q_tot_cnt[tgt_id] == 0) ? 0 :
-                (waiting->q_tot_tim[tgt_id]/waiting->q_tot_cnt[tgt_id]),
-                (waiting->q_tot_cnt[tgt_id] == 0) ? 0 :
-                ASC_TENTHS(waiting->q_tot_tim[tgt_id],
-                waiting->q_tot_cnt[tgt_id]));
-             ASC_PRT_NEXT();
-        }
-    } while (0);
+			len = asc_prt_line(cp, leftlen,
+					   "   waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
+					   waiting->q_cur_cnt[tgt_id],
+					   waiting->q_max_cnt[tgt_id],
+					   waiting->q_tot_cnt[tgt_id],
+					   waiting->q_min_tim[tgt_id],
+					   waiting->q_max_tim[tgt_id],
+					   (waiting->q_tot_cnt[tgt_id] ==
+					    0) ? 0 : (waiting->
+						      q_tot_tim[tgt_id] /
+						      waiting->
+						      q_tot_cnt[tgt_id]),
+					   (waiting->q_tot_cnt[tgt_id] ==
+					    0) ? 0 : ASC_TENTHS(waiting->
+								q_tot_tim
+								[tgt_id],
+								waiting->
+								q_tot_cnt
+								[tgt_id]));
+			ASC_PRT_NEXT();
+		}
+	} while (0);
 
-     return totlen;
+	return totlen;
 }
 #endif /* CONFIG_PROC_FS */
 #endif /* ADVANSYS_STATS */
@@ -9039,207 +7852,181 @@
 /*
  * asc_prt_scsi_host()
  */
-STATIC void
-asc_prt_scsi_host(struct Scsi_Host *s)
+static void asc_prt_scsi_host(struct Scsi_Host *s)
 {
-    asc_board_t         *boardp;
+	asc_board_t *boardp;
 
-    boardp = ASC_BOARDP(s);
+	boardp = ASC_BOARDP(s);
 
-    printk("Scsi_Host at addr 0x%lx\n", (ulong) s);
-    printk(
-" host_busy %u, host_no %d, last_reset %d,\n",
-        s->host_busy, s->host_no,
-        (unsigned) s->last_reset);
+	printk("Scsi_Host at addr 0x%lx\n", (ulong)s);
+	printk(" host_busy %u, host_no %d, last_reset %d,\n",
+	       s->host_busy, s->host_no, (unsigned)s->last_reset);
 
-    printk(
-" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
-        (ulong) s->base, (ulong) s->io_port, s->n_io_port, s->irq);
+	printk(" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
+	       (ulong)s->base, (ulong)s->io_port, s->n_io_port, s->irq);
 
-    printk(
-" dma_channel %d, this_id %d, can_queue %d,\n",
-        s->dma_channel, s->this_id, s->can_queue);
+	printk(" dma_channel %d, this_id %d, can_queue %d,\n",
+	       s->dma_channel, s->this_id, s->can_queue);
 
-    printk(
-" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
-        s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
+	printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
+	       s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
 
-    if (ASC_NARROW_BOARD(boardp)) {
-        asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
-        asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
-    } else {
-        asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
-        asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
-    }
+	if (ASC_NARROW_BOARD(boardp)) {
+		asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
+		asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
+	} else {
+		asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
+		asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
+	}
 }
 
 /*
  * asc_prt_scsi_cmnd()
  */
-STATIC void
-asc_prt_scsi_cmnd(struct scsi_cmnd *s)
+static void asc_prt_scsi_cmnd(struct scsi_cmnd *s)
 {
-    printk("struct scsi_cmnd at addr 0x%lx\n", (ulong) s);
+	printk("struct scsi_cmnd at addr 0x%lx\n", (ulong)s);
 
-    printk(
-" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
-        (ulong) s->device->host, (ulong) s->device, s->device->id, s->device->lun,
-        s->device->channel);
+	printk(" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
+	       (ulong)s->device->host, (ulong)s->device, s->device->id,
+	       s->device->lun, s->device->channel);
 
-    asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
+	asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
 
-    printk (
-"sc_data_direction %u, resid %d\n",
-        s->sc_data_direction, s->resid);
+	printk("sc_data_direction %u, resid %d\n",
+	       s->sc_data_direction, s->resid);
 
-    printk(
-" use_sg %u, sglist_len %u\n",
-        s->use_sg, s->sglist_len);
+	printk(" use_sg %u, sglist_len %u\n", s->use_sg, s->sglist_len);
 
-    printk(
-" serial_number 0x%x, retries %d, allowed %d\n",
-        (unsigned) s->serial_number, s->retries, s->allowed);
+	printk(" serial_number 0x%x, retries %d, allowed %d\n",
+	       (unsigned)s->serial_number, s->retries, s->allowed);
 
-    printk(
-" timeout_per_command %d\n",
-        s->timeout_per_command);
+	printk(" timeout_per_command %d\n", s->timeout_per_command);
 
-    printk(
-" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
-        (ulong) s->scsi_done, (ulong) s->done,
-        (ulong) s->host_scribble, s->result);
+	printk
+	    (" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
+	     (ulong)s->scsi_done, (ulong)s->done, (ulong)s->host_scribble,
+	     s->result);
 
-    printk(
-" tag %u, pid %u\n",
-        (unsigned) s->tag, (unsigned) s->pid);
+	printk(" tag %u, pid %u\n", (unsigned)s->tag, (unsigned)s->pid);
 }
 
 /*
  * asc_prt_asc_dvc_var()
  */
-STATIC void
-asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
+static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
 {
-    printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong) h);
+	printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h);
 
-    printk(
-" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n",
-        h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
+	printk
+	    (" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n",
+	     h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
 
-    printk(
-" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n",
-        h->bus_type, (ulong) h->isr_callback, (ulong) h->exe_callback,
-        (unsigned) h->init_sdtr);
+	printk
+	    (" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n",
+	     h->bus_type, (ulong)h->isr_callback, (ulong)h->exe_callback,
+	     (unsigned)h->init_sdtr);
 
-    printk(
-" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n",
-        (unsigned) h->sdtr_done, (unsigned) h->use_tagged_qng,
-        (unsigned) h->unit_not_ready, (unsigned) h->chip_no);
+	printk
+	    (" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n",
+	     (unsigned)h->sdtr_done, (unsigned)h->use_tagged_qng,
+	     (unsigned)h->unit_not_ready, (unsigned)h->chip_no);
 
-    printk(
-" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n",
-        (unsigned) h->queue_full_or_busy, (unsigned) h->start_motor,
-        (unsigned) h->scsi_reset_wait);
+	printk
+	    (" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n",
+	     (unsigned)h->queue_full_or_busy, (unsigned)h->start_motor,
+	     (unsigned)h->scsi_reset_wait);
 
-    printk(
-" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n",
-        (unsigned) h->is_in_int, (unsigned) h->max_total_qng,
-        (unsigned) h->cur_total_qng, (unsigned) h->in_critical_cnt);
+	printk
+	    (" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n",
+	     (unsigned)h->is_in_int, (unsigned)h->max_total_qng,
+	     (unsigned)h->cur_total_qng, (unsigned)h->in_critical_cnt);
 
-    printk(
-" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n",
-        (unsigned) h->last_q_shortage, (unsigned) h->init_state,
-        (unsigned) h->no_scam, (unsigned) h->pci_fix_asyn_xfer);
+	printk
+	    (" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n",
+	     (unsigned)h->last_q_shortage, (unsigned)h->init_state,
+	     (unsigned)h->no_scam, (unsigned)h->pci_fix_asyn_xfer);
 
-    printk(
-" cfg 0x%lx, irq_no 0x%x\n",
-        (ulong) h->cfg, (unsigned) h->irq_no);
+	printk(" cfg 0x%lx, irq_no 0x%x\n", (ulong)h->cfg, (unsigned)h->irq_no);
 }
 
 /*
  * asc_prt_asc_dvc_cfg()
  */
-STATIC void
-asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
+static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
 {
-    printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong) h);
+	printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h);
 
-    printk(
-" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
-            h->can_tagged_qng, h->cmd_qng_enabled);
-    printk(
-" disc_enable 0x%x, sdtr_enable 0x%x,\n",
-            h->disc_enable, h->sdtr_enable);
+	printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
+	       h->can_tagged_qng, h->cmd_qng_enabled);
+	printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n",
+	       h->disc_enable, h->sdtr_enable);
 
-    printk(
-" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
-             h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
-             h->chip_version);
+	printk
+	    (" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
+	     h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
+	     h->chip_version);
 
-    printk(
-" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
-	   to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
-	   h->mcode_date);
+	printk
+	    (" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
+	     to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
+	     h->mcode_date);
 
-    printk(
-" mcode_version %d, overrun_buf 0x%lx\n",
-            h->mcode_version, (ulong) h->overrun_buf);
+	printk(" mcode_version %d, overrun_buf 0x%lx\n",
+	       h->mcode_version, (ulong)h->overrun_buf);
 }
 
 /*
  * asc_prt_asc_scsi_q()
  */
-STATIC void
-asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
+static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
 {
-    ASC_SG_HEAD    *sgp;
-    int i;
+	ASC_SG_HEAD *sgp;
+	int i;
 
-    printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong) q);
+	printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q);
 
-    printk(
-" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
-            q->q2.target_ix, q->q1.target_lun,
-            (ulong) q->q2.srb_ptr, q->q2.tag_code);
+	printk
+	    (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
+	     q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr,
+	     q->q2.tag_code);
 
-    printk(
-" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
-            (ulong) le32_to_cpu(q->q1.data_addr),
-            (ulong) le32_to_cpu(q->q1.data_cnt),
-            (ulong) le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
+	printk
+	    (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
+	     (ulong)le32_to_cpu(q->q1.data_addr),
+	     (ulong)le32_to_cpu(q->q1.data_cnt),
+	     (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
 
-    printk(
-" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
-            (ulong) q->cdbptr, q->q2.cdb_len,
-            (ulong) q->sg_head, q->q1.sg_queue_cnt);
+	printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
+	       (ulong)q->cdbptr, q->q2.cdb_len,
+	       (ulong)q->sg_head, q->q1.sg_queue_cnt);
 
-    if (q->sg_head) {
-        sgp = q->sg_head;
-        printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong) sgp);
-        printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt, sgp->queue_cnt);
-        for (i = 0; i < sgp->entry_cnt; i++) {
-            printk(" [%u]: addr 0x%lx, bytes %lu\n",
-                i, (ulong) le32_to_cpu(sgp->sg_list[i].addr),
-                (ulong) le32_to_cpu(sgp->sg_list[i].bytes));
-        }
+	if (q->sg_head) {
+		sgp = q->sg_head;
+		printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp);
+		printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt,
+		       sgp->queue_cnt);
+		for (i = 0; i < sgp->entry_cnt; i++) {
+			printk(" [%u]: addr 0x%lx, bytes %lu\n",
+			       i, (ulong)le32_to_cpu(sgp->sg_list[i].addr),
+			       (ulong)le32_to_cpu(sgp->sg_list[i].bytes));
+		}
 
-    }
+	}
 }
 
 /*
  * asc_prt_asc_qdone_info()
  */
-STATIC void
-asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
+static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
 {
-    printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong) q);
-    printk(
-" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
-            (ulong) q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
-            q->d2.tag_code);
-    printk(
-" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
-            q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
+	printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q);
+	printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
+	       (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
+	       q->d2.tag_code);
+	printk
+	    (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
+	     q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
 }
 
 /*
@@ -9247,41 +8034,33 @@
  *
  * Display an ADV_DVC_VAR structure.
  */
-STATIC void
-asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
+static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
 {
-    printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong) h);
+	printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h);
 
-    printk(
-"  iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
-        (ulong) h->iop_base, h->err_code, (unsigned) h->ultra_able);
+	printk("  iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
+	       (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able);
 
-    printk(
-"  isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
-        (ulong) h->isr_callback, (unsigned) h->sdtr_able,
-        (unsigned) h->wdtr_able);
+	printk("  isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
+	       (ulong)h->isr_callback, (unsigned)h->sdtr_able,
+	       (unsigned)h->wdtr_able);
 
-    printk(
-"  start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
-        (unsigned) h->start_motor,
-        (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no);
+	printk("  start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
+	       (unsigned)h->start_motor,
+	       (unsigned)h->scsi_reset_wait, (unsigned)h->irq_no);
 
-    printk(
-"  max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
-        (unsigned) h->max_host_qng, (unsigned) h->max_dvc_qng,
-        (ulong) h->carr_freelist);
+	printk("  max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
+	       (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng,
+	       (ulong)h->carr_freelist);
 
-    printk(
-"  icq_sp 0x%lx, irq_sp 0x%lx\n",
-        (ulong) h->icq_sp, (ulong) h->irq_sp);
+	printk("  icq_sp 0x%lx, irq_sp 0x%lx\n",
+	       (ulong)h->icq_sp, (ulong)h->irq_sp);
 
-    printk(
-"  no_scam 0x%x, tagqng_able 0x%x\n",
-        (unsigned) h->no_scam, (unsigned) h->tagqng_able);
+	printk("  no_scam 0x%x, tagqng_able 0x%x\n",
+	       (unsigned)h->no_scam, (unsigned)h->tagqng_able);
 
-    printk(
-"  chip_scsi_id 0x%x, cfg 0x%lx\n",
-        (unsigned) h->chip_scsi_id, (ulong) h->cfg);
+	printk("  chip_scsi_id 0x%x, cfg 0x%lx\n",
+	       (unsigned)h->chip_scsi_id, (ulong)h->cfg);
 }
 
 /*
@@ -9289,26 +8068,21 @@
  *
  * Display an ADV_DVC_CFG structure.
  */
-STATIC void
-asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
+static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
 {
-    printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong) h);
+	printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h);
 
-    printk(
-"  disc_enable 0x%x, termination 0x%x\n",
-        h->disc_enable, h->termination);
+	printk("  disc_enable 0x%x, termination 0x%x\n",
+	       h->disc_enable, h->termination);
 
-    printk(
-"  chip_version 0x%x, mcode_date 0x%x\n",
-        h->chip_version, h->mcode_date);
+	printk("  chip_version 0x%x, mcode_date 0x%x\n",
+	       h->chip_version, h->mcode_date);
 
-    printk(
-"  mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
-       h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
+	printk("  mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
+	       h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
 
-    printk(
-"  control_flag 0x%x, pci_slot_info 0x%x\n",
-       h->control_flag, h->pci_slot_info);
+	printk("  control_flag 0x%x, pci_slot_info 0x%x\n",
+	       h->control_flag, h->pci_slot_info);
 }
 
 /*
@@ -9316,60 +8090,54 @@
  *
  * Display an ADV_SCSI_REQ_Q structure.
  */
-STATIC void
-asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
+static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
 {
-    int                 sg_blk_cnt;
-    struct asc_sg_block *sg_ptr;
+	int sg_blk_cnt;
+	struct asc_sg_block *sg_ptr;
 
-    printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong) q);
+	printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q);
 
-    printk(
-"  target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
-            q->target_id, q->target_lun, (ulong) q->srb_ptr, q->a_flag);
+	printk("  target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
+	       q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag);
 
-    printk("  cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
-            q->cntl, (ulong) le32_to_cpu(q->data_addr), (ulong) q->vdata_addr);
+	printk("  cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
+	       q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr);
 
-    printk(
-"  data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
-            (ulong) le32_to_cpu(q->data_cnt),
-            (ulong) le32_to_cpu(q->sense_addr), q->sense_len);
+	printk("  data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
+	       (ulong)le32_to_cpu(q->data_cnt),
+	       (ulong)le32_to_cpu(q->sense_addr), q->sense_len);
 
-    printk(
-"  cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
-            q->cdb_len, q->done_status, q->host_status, q->scsi_status);
+	printk
+	    ("  cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
+	     q->cdb_len, q->done_status, q->host_status, q->scsi_status);
 
-    printk(
-"  sg_working_ix 0x%x, target_cmd %u\n",
-            q->sg_working_ix, q->target_cmd);
+	printk("  sg_working_ix 0x%x, target_cmd %u\n",
+	       q->sg_working_ix, q->target_cmd);
 
-    printk(
-"  scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
-            (ulong) le32_to_cpu(q->scsiq_rptr),
-            (ulong) le32_to_cpu(q->sg_real_addr), (ulong) q->sg_list_ptr);
+	printk("  scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
+	       (ulong)le32_to_cpu(q->scsiq_rptr),
+	       (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr);
 
-    /* Display the request's ADV_SG_BLOCK structures. */
-    if (q->sg_list_ptr != NULL)
-    {
-        sg_blk_cnt = 0;
-        while (1) {
-            /*
-             * 'sg_ptr' is a physical address. Convert it to a virtual
-             * address by indexing 'sg_blk_cnt' into the virtual address
-             * array 'sg_list_ptr'.
-             *
-             * XXX - Assumes all SG physical blocks are virtually contiguous.
-             */
-            sg_ptr = &(((ADV_SG_BLOCK *) (q->sg_list_ptr))[sg_blk_cnt]);
-            asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
-            if (sg_ptr->sg_ptr == 0)
-            {
-                break;
-            }
-            sg_blk_cnt++;
-        }
-    }
+	/* Display the request's ADV_SG_BLOCK structures. */
+	if (q->sg_list_ptr != NULL) {
+		sg_blk_cnt = 0;
+		while (1) {
+			/*
+			 * 'sg_ptr' is a physical address. Convert it to a virtual
+			 * address by indexing 'sg_blk_cnt' into the virtual address
+			 * array 'sg_list_ptr'.
+			 *
+			 * XXX - Assumes all SG physical blocks are virtually contiguous.
+			 */
+			sg_ptr =
+			    &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]);
+			asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
+			if (sg_ptr->sg_ptr == 0) {
+				break;
+			}
+			sg_blk_cnt++;
+		}
+	}
 }
 
 /*
@@ -9377,24 +8145,23 @@
  *
  * Display an ADV_SG_BLOCK structure.
  */
-STATIC void
-asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
+static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
 {
-    int i;
+	int i;
 
-    printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
-        (ulong) b, sgblockno);
-    printk("  sg_cnt %u, sg_ptr 0x%lx\n",
-        b->sg_cnt, (ulong) le32_to_cpu(b->sg_ptr));
-    ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
-    if (b->sg_ptr != 0)
-    {
-        ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
-    }
-    for (i = 0; i < b->sg_cnt; i++) {
-        printk("  [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
-            i, (ulong) b->sg_list[i].sg_addr, (ulong) b->sg_list[i].sg_count);
-    }
+	printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
+	       (ulong)b, sgblockno);
+	printk("  sg_cnt %u, sg_ptr 0x%lx\n",
+	       b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr));
+	ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
+	if (b->sg_ptr != 0) {
+		ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
+	}
+	for (i = 0; i < b->sg_cnt; i++) {
+		printk("  [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
+		       i, (ulong)b->sg_list[i].sg_addr,
+		       (ulong)b->sg_list[i].sg_count);
+	}
 }
 
 /*
@@ -9403,55 +8170,55 @@
  * Print hexadecimal output in 4 byte groupings 32 bytes
  * or 8 double-words per line.
  */
-STATIC void
-asc_prt_hex(char *f, uchar *s, int l)
+static void asc_prt_hex(char *f, uchar *s, int l)
 {
-    int            i;
-    int            j;
-    int            k;
-    int            m;
+	int i;
+	int j;
+	int k;
+	int m;
 
-    printk("%s: (%d bytes)\n", f, l);
+	printk("%s: (%d bytes)\n", f, l);
 
-    for (i = 0; i < l; i += 32) {
+	for (i = 0; i < l; i += 32) {
 
-        /* Display a maximum of 8 double-words per line. */
-        if ((k = (l - i) / 4) >= 8) {
-            k = 8;
-            m = 0;
-        } else {
-            m = (l - i) % 4;
-        }
+		/* Display a maximum of 8 double-words per line. */
+		if ((k = (l - i) / 4) >= 8) {
+			k = 8;
+			m = 0;
+		} else {
+			m = (l - i) % 4;
+		}
 
-        for (j = 0; j < k; j++) {
-            printk(" %2.2X%2.2X%2.2X%2.2X",
-                (unsigned) s[i+(j*4)], (unsigned) s[i+(j*4)+1],
-                (unsigned) s[i+(j*4)+2], (unsigned) s[i+(j*4)+3]);
-        }
+		for (j = 0; j < k; j++) {
+			printk(" %2.2X%2.2X%2.2X%2.2X",
+			       (unsigned)s[i + (j * 4)],
+			       (unsigned)s[i + (j * 4) + 1],
+			       (unsigned)s[i + (j * 4) + 2],
+			       (unsigned)s[i + (j * 4) + 3]);
+		}
 
-        switch (m) {
-        case 0:
-        default:
-            break;
-        case 1:
-            printk(" %2.2X",
-                (unsigned) s[i+(j*4)]);
-            break;
-        case 2:
-            printk(" %2.2X%2.2X",
-                (unsigned) s[i+(j*4)],
-                (unsigned) s[i+(j*4)+1]);
-            break;
-        case 3:
-            printk(" %2.2X%2.2X%2.2X",
-                (unsigned) s[i+(j*4)+1],
-                (unsigned) s[i+(j*4)+2],
-                (unsigned) s[i+(j*4)+3]);
-            break;
-        }
+		switch (m) {
+		case 0:
+		default:
+			break;
+		case 1:
+			printk(" %2.2X", (unsigned)s[i + (j * 4)]);
+			break;
+		case 2:
+			printk(" %2.2X%2.2X",
+			       (unsigned)s[i + (j * 4)],
+			       (unsigned)s[i + (j * 4) + 1]);
+			break;
+		case 3:
+			printk(" %2.2X%2.2X%2.2X",
+			       (unsigned)s[i + (j * 4) + 1],
+			       (unsigned)s[i + (j * 4) + 2],
+			       (unsigned)s[i + (j * 4) + 3]);
+			break;
+		}
 
-        printk("\n");
-    }
+		printk("\n");
+	}
 }
 #endif /* ADVANSYS_DEBUG */
 
@@ -9459,3380 +8226,3400 @@
  * --- Asc Library Functions
  */
 
-STATIC ushort __init
-AscGetEisaChipCfg(
-                     PortAddr iop_base)
+static ushort __init AscGetEisaChipCfg(PortAddr iop_base)
 {
-    PortAddr            eisa_cfg_iop;
+	PortAddr eisa_cfg_iop;
 
-    eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
-      (PortAddr) (ASC_EISA_CFG_IOP_MASK);
-    return (inpw(eisa_cfg_iop));
+	eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
+	    (PortAddr) (ASC_EISA_CFG_IOP_MASK);
+	return (inpw(eisa_cfg_iop));
 }
 
-STATIC uchar __init
-AscSetChipScsiID(
-                    PortAddr iop_base,
-                    uchar new_host_id
-)
+static uchar __init AscSetChipScsiID(PortAddr iop_base, uchar new_host_id)
 {
-    ushort              cfg_lsw;
+	ushort cfg_lsw;
 
-    if (AscGetChipScsiID(iop_base) == new_host_id) {
-        return (new_host_id);
-    }
-    cfg_lsw = AscGetChipCfgLsw(iop_base);
-    cfg_lsw &= 0xF8FF;
-    cfg_lsw |= (ushort) ((new_host_id & ASC_MAX_TID) << 8);
-    AscSetChipCfgLsw(iop_base, cfg_lsw);
-    return (AscGetChipScsiID(iop_base));
+	if (AscGetChipScsiID(iop_base) == new_host_id) {
+		return (new_host_id);
+	}
+	cfg_lsw = AscGetChipCfgLsw(iop_base);
+	cfg_lsw &= 0xF8FF;
+	cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8);
+	AscSetChipCfgLsw(iop_base, cfg_lsw);
+	return (AscGetChipScsiID(iop_base));
 }
 
-STATIC uchar __init
-AscGetChipScsiCtrl(
-		PortAddr iop_base)
+static uchar __init AscGetChipScsiCtrl(PortAddr iop_base)
 {
-    uchar               sc;
+	uchar sc;
 
-    AscSetBank(iop_base, 1);
-    sc = inp(iop_base + IOP_REG_SC);
-    AscSetBank(iop_base, 0);
-    return (sc);
+	AscSetBank(iop_base, 1);
+	sc = inp(iop_base + IOP_REG_SC);
+	AscSetBank(iop_base, 0);
+	return (sc);
 }
 
-STATIC uchar __init
-AscGetChipVersion(
-                     PortAddr iop_base,
-                     ushort bus_type
-)
+static uchar __init AscGetChipVersion(PortAddr iop_base, ushort bus_type)
 {
-    if ((bus_type & ASC_IS_EISA) != 0) {
-        PortAddr            eisa_iop;
-        uchar               revision;
-        eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
-          (PortAddr) ASC_EISA_REV_IOP_MASK;
-        revision = inp(eisa_iop);
-        return ((uchar) ((ASC_CHIP_MIN_VER_EISA - 1) + revision));
-    }
-    return (AscGetChipVerNo(iop_base));
+	if ((bus_type & ASC_IS_EISA) != 0) {
+		PortAddr eisa_iop;
+		uchar revision;
+		eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
+		    (PortAddr) ASC_EISA_REV_IOP_MASK;
+		revision = inp(eisa_iop);
+		return ((uchar)((ASC_CHIP_MIN_VER_EISA - 1) + revision));
+	}
+	return (AscGetChipVerNo(iop_base));
 }
 
-STATIC ushort __init
-AscGetChipBusType(
-                     PortAddr iop_base)
+static ushort __init AscGetChipBusType(PortAddr iop_base)
 {
-    ushort              chip_ver;
+	ushort chip_ver;
 
-    chip_ver = AscGetChipVerNo(iop_base);
-    if (
-           (chip_ver >= ASC_CHIP_MIN_VER_VL)
-           && (chip_ver <= ASC_CHIP_MAX_VER_VL)
-) {
-        if (
-               ((iop_base & 0x0C30) == 0x0C30)
-               || ((iop_base & 0x0C50) == 0x0C50)
-) {
-            return (ASC_IS_EISA);
-        }
-        return (ASC_IS_VL);
-    }
-    if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
-        (chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
-        if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
-            return (ASC_IS_ISAPNP);
-        }
-        return (ASC_IS_ISA);
-    } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
-               (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
-        return (ASC_IS_PCI);
-    }
-    return (0);
+	chip_ver = AscGetChipVerNo(iop_base);
+	if ((chip_ver >= ASC_CHIP_MIN_VER_VL)
+	    && (chip_ver <= ASC_CHIP_MAX_VER_VL)
+	    ) {
+		if (((iop_base & 0x0C30) == 0x0C30)
+		    || ((iop_base & 0x0C50) == 0x0C50)
+		    ) {
+			return (ASC_IS_EISA);
+		}
+		return (ASC_IS_VL);
+	}
+	if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
+	    (chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
+		if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
+			return (ASC_IS_ISAPNP);
+		}
+		return (ASC_IS_ISA);
+	} else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
+		   (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
+		return (ASC_IS_PCI);
+	}
+	return (0);
 }
 
-STATIC ASC_DCNT
-AscLoadMicroCode(
-                    PortAddr iop_base,
-                    ushort s_addr,
-                    uchar *mcode_buf,
-                    ushort mcode_size
-)
+static ASC_DCNT
+AscLoadMicroCode(PortAddr iop_base,
+		 ushort s_addr, uchar *mcode_buf, ushort mcode_size)
 {
-    ASC_DCNT            chksum;
-    ushort              mcode_word_size;
-    ushort              mcode_chksum;
+	ASC_DCNT chksum;
+	ushort mcode_word_size;
+	ushort mcode_chksum;
 
-    /* Write the microcode buffer starting at LRAM address 0. */
-    mcode_word_size = (ushort) (mcode_size >> 1);
-    AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
-    AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
+	/* Write the microcode buffer starting at LRAM address 0. */
+	mcode_word_size = (ushort)(mcode_size >> 1);
+	AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
+	AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
 
-    chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
-    ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong) chksum);
-    mcode_chksum = (ushort) AscMemSumLramWord(iop_base,
-          (ushort) ASC_CODE_SEC_BEG,
-          (ushort) ((mcode_size - s_addr - (ushort) ASC_CODE_SEC_BEG) / 2));
-    ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
-        (ulong) mcode_chksum);
-    AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
-    AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
-    return (chksum);
+	chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
+	ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong)chksum);
+	mcode_chksum = (ushort)AscMemSumLramWord(iop_base,
+						 (ushort)ASC_CODE_SEC_BEG,
+						 (ushort)((mcode_size -
+							   s_addr - (ushort)
+							   ASC_CODE_SEC_BEG) /
+							  2));
+	ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
+		 (ulong)mcode_chksum);
+	AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
+	AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
+	return (chksum);
 }
 
-STATIC int
-AscFindSignature(
-                    PortAddr iop_base
-)
+static int AscFindSignature(PortAddr iop_base)
 {
-    ushort              sig_word;
+	ushort sig_word;
 
-    ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
-        iop_base, AscGetChipSignatureByte(iop_base));
-    if (AscGetChipSignatureByte(iop_base) == (uchar) ASC_1000_ID1B) {
-        ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
-            iop_base, AscGetChipSignatureWord(iop_base));
-        sig_word = AscGetChipSignatureWord(iop_base);
-        if ((sig_word == (ushort) ASC_1000_ID0W) ||
-            (sig_word == (ushort) ASC_1000_ID0W_FIX)) {
-            return (1);
-        }
-    }
-    return (0);
+	ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
+		 iop_base, AscGetChipSignatureByte(iop_base));
+	if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) {
+		ASC_DBG2(1,
+			 "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
+			 iop_base, AscGetChipSignatureWord(iop_base));
+		sig_word = AscGetChipSignatureWord(iop_base);
+		if ((sig_word == (ushort)ASC_1000_ID0W) ||
+		    (sig_word == (ushort)ASC_1000_ID0W_FIX)) {
+			return (1);
+		}
+	}
+	return (0);
 }
 
-STATIC PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __initdata =
-{
-    0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4,
-    ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
+static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __initdata = {
+	0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4,
+	ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
 };
 
 #ifdef CONFIG_ISA
-STATIC uchar _isa_pnp_inited __initdata = 0;
+static uchar _isa_pnp_inited __initdata = 0;
 
-STATIC PortAddr __init
-AscSearchIOPortAddr(
-                       PortAddr iop_beg,
-                       ushort bus_type)
+static PortAddr __init AscSearchIOPortAddr(PortAddr iop_beg, ushort bus_type)
 {
-    if (bus_type & ASC_IS_VL) {
-        while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
-            if (AscGetChipVersion(iop_beg, bus_type) <= ASC_CHIP_MAX_VER_VL) {
-                return (iop_beg);
-            }
-        }
-        return (0);
-    }
-    if (bus_type & ASC_IS_ISA) {
-        if (_isa_pnp_inited == 0) {
-            AscSetISAPNPWaitForKey();
-            _isa_pnp_inited++;
-        }
-        while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
-            if ((AscGetChipVersion(iop_beg, bus_type) & ASC_CHIP_VER_ISA_BIT) != 0) {
-                return (iop_beg);
-            }
-        }
-        return (0);
-    }
-    if (bus_type & ASC_IS_EISA) {
-        if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) {
-            return (iop_beg);
-        }
-        return (0);
-    }
-    return (0);
+	if (bus_type & ASC_IS_VL) {
+		while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
+			if (AscGetChipVersion(iop_beg, bus_type) <=
+			    ASC_CHIP_MAX_VER_VL) {
+				return (iop_beg);
+			}
+		}
+		return (0);
+	}
+	if (bus_type & ASC_IS_ISA) {
+		if (_isa_pnp_inited == 0) {
+			AscSetISAPNPWaitForKey();
+			_isa_pnp_inited++;
+		}
+		while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
+			if ((AscGetChipVersion(iop_beg, bus_type) &
+			     ASC_CHIP_VER_ISA_BIT) != 0) {
+				return (iop_beg);
+			}
+		}
+		return (0);
+	}
+	if (bus_type & ASC_IS_EISA) {
+		if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) {
+			return (iop_beg);
+		}
+		return (0);
+	}
+	return (0);
 }
 
-STATIC PortAddr __init
-AscSearchIOPortAddr11(
-                         PortAddr s_addr
-)
+static PortAddr __init AscSearchIOPortAddr11(PortAddr s_addr)
 {
-    int                 i;
-    PortAddr            iop_base;
+	int i;
+	PortAddr iop_base;
 
-    for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) {
-        if (_asc_def_iop_base[i] > s_addr) {
-            break;
-        }
-    }
-    for (; i < ASC_IOADR_TABLE_MAX_IX; i++) {
-        iop_base = _asc_def_iop_base[i];
-	if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")){
-            ASC_DBG1(1,
-               "AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n",
-                     iop_base);
-            continue;
-        }
-        ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n", iop_base);
-	release_region(iop_base, ASC_IOADR_GAP);
-        if (AscFindSignature(iop_base)) {
-            return (iop_base);
-        }
-    }
-    return (0);
+	for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) {
+		if (_asc_def_iop_base[i] > s_addr) {
+			break;
+		}
+	}
+	for (; i < ASC_IOADR_TABLE_MAX_IX; i++) {
+		iop_base = _asc_def_iop_base[i];
+		if (!request_region(iop_base, ASC_IOADR_GAP, "advansys")) {
+			ASC_DBG1(1,
+				 "AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n",
+				 iop_base);
+			continue;
+		}
+		ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n",
+			 iop_base);
+		release_region(iop_base, ASC_IOADR_GAP);
+		if (AscFindSignature(iop_base)) {
+			return (iop_base);
+		}
+	}
+	return (0);
 }
 
-STATIC void __init
-AscSetISAPNPWaitForKey(void)
+static void __init AscSetISAPNPWaitForKey(void)
 {
-    outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
-    outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
-    return;
+	outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
+	outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
+	return;
 }
 #endif /* CONFIG_ISA */
 
-STATIC void __init
-AscToggleIRQAct(
-                   PortAddr iop_base
-)
+static void __init AscToggleIRQAct(PortAddr iop_base)
 {
-    AscSetChipStatus(iop_base, CIW_IRQ_ACT);
-    AscSetChipStatus(iop_base, 0);
-    return;
+	AscSetChipStatus(iop_base, CIW_IRQ_ACT);
+	AscSetChipStatus(iop_base, 0);
+	return;
 }
 
-STATIC uchar __init
-AscGetChipIRQ(
-                 PortAddr iop_base,
-                 ushort bus_type)
+static uchar __init AscGetChipIRQ(PortAddr iop_base, ushort bus_type)
 {
-    ushort              cfg_lsw;
-    uchar               chip_irq;
+	ushort cfg_lsw;
+	uchar chip_irq;
 
-    if ((bus_type & ASC_IS_EISA) != 0) {
-        cfg_lsw = AscGetEisaChipCfg(iop_base);
-        chip_irq = (uchar) (((cfg_lsw >> 8) & 0x07) + 10);
-        if ((chip_irq == 13) || (chip_irq > 15)) {
-            return (0);
-        }
-        return (chip_irq);
-    }
-    if ((bus_type & ASC_IS_VL) != 0) {
-        cfg_lsw = AscGetChipCfgLsw(iop_base);
-        chip_irq = (uchar) (((cfg_lsw >> 2) & 0x07));
-        if ((chip_irq == 0) ||
-            (chip_irq == 4) ||
-            (chip_irq == 7)) {
-            return (0);
-        }
-        return ((uchar) (chip_irq + (ASC_MIN_IRQ_NO - 1)));
-    }
-    cfg_lsw = AscGetChipCfgLsw(iop_base);
-    chip_irq = (uchar) (((cfg_lsw >> 2) & 0x03));
-    if (chip_irq == 3)
-        chip_irq += (uchar) 2;
-    return ((uchar) (chip_irq + ASC_MIN_IRQ_NO));
+	if ((bus_type & ASC_IS_EISA) != 0) {
+		cfg_lsw = AscGetEisaChipCfg(iop_base);
+		chip_irq = (uchar)(((cfg_lsw >> 8) & 0x07) + 10);
+		if ((chip_irq == 13) || (chip_irq > 15)) {
+			return (0);
+		}
+		return (chip_irq);
+	}
+	if ((bus_type & ASC_IS_VL) != 0) {
+		cfg_lsw = AscGetChipCfgLsw(iop_base);
+		chip_irq = (uchar)(((cfg_lsw >> 2) & 0x07));
+		if ((chip_irq == 0) || (chip_irq == 4) || (chip_irq == 7)) {
+			return (0);
+		}
+		return ((uchar)(chip_irq + (ASC_MIN_IRQ_NO - 1)));
+	}
+	cfg_lsw = AscGetChipCfgLsw(iop_base);
+	chip_irq = (uchar)(((cfg_lsw >> 2) & 0x03));
+	if (chip_irq == 3)
+		chip_irq += (uchar)2;
+	return ((uchar)(chip_irq + ASC_MIN_IRQ_NO));
 }
 
-STATIC uchar __init
-AscSetChipIRQ(
-                 PortAddr iop_base,
-                 uchar irq_no,
-                 ushort bus_type)
+static uchar __init
+AscSetChipIRQ(PortAddr iop_base, uchar irq_no, ushort bus_type)
 {
-    ushort              cfg_lsw;
+	ushort cfg_lsw;
 
-    if ((bus_type & ASC_IS_VL) != 0) {
-        if (irq_no != 0) {
-            if ((irq_no < ASC_MIN_IRQ_NO) || (irq_no > ASC_MAX_IRQ_NO)) {
-                irq_no = 0;
-            } else {
-                irq_no -= (uchar) ((ASC_MIN_IRQ_NO - 1));
-            }
-        }
-        cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE3);
-        cfg_lsw |= (ushort) 0x0010;
-        AscSetChipCfgLsw(iop_base, cfg_lsw);
-        AscToggleIRQAct(iop_base);
-        cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE0);
-        cfg_lsw |= (ushort) ((irq_no & 0x07) << 2);
-        AscSetChipCfgLsw(iop_base, cfg_lsw);
-        AscToggleIRQAct(iop_base);
-        return (AscGetChipIRQ(iop_base, bus_type));
-    }
-    if ((bus_type & (ASC_IS_ISA)) != 0) {
-        if (irq_no == 15)
-            irq_no -= (uchar) 2;
-        irq_no -= (uchar) ASC_MIN_IRQ_NO;
-        cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFF3);
-        cfg_lsw |= (ushort) ((irq_no & 0x03) << 2);
-        AscSetChipCfgLsw(iop_base, cfg_lsw);
-        return (AscGetChipIRQ(iop_base, bus_type));
-    }
-    return (0);
+	if ((bus_type & ASC_IS_VL) != 0) {
+		if (irq_no != 0) {
+			if ((irq_no < ASC_MIN_IRQ_NO)
+			    || (irq_no > ASC_MAX_IRQ_NO)) {
+				irq_no = 0;
+			} else {
+				irq_no -= (uchar)((ASC_MIN_IRQ_NO - 1));
+			}
+		}
+		cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE3);
+		cfg_lsw |= (ushort)0x0010;
+		AscSetChipCfgLsw(iop_base, cfg_lsw);
+		AscToggleIRQAct(iop_base);
+		cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFE0);
+		cfg_lsw |= (ushort)((irq_no & 0x07) << 2);
+		AscSetChipCfgLsw(iop_base, cfg_lsw);
+		AscToggleIRQAct(iop_base);
+		return (AscGetChipIRQ(iop_base, bus_type));
+	}
+	if ((bus_type & (ASC_IS_ISA)) != 0) {
+		if (irq_no == 15)
+			irq_no -= (uchar)2;
+		irq_no -= (uchar)ASC_MIN_IRQ_NO;
+		cfg_lsw = (ushort)(AscGetChipCfgLsw(iop_base) & 0xFFF3);
+		cfg_lsw |= (ushort)((irq_no & 0x03) << 2);
+		AscSetChipCfgLsw(iop_base, cfg_lsw);
+		return (AscGetChipIRQ(iop_base, bus_type));
+	}
+	return (0);
 }
 
 #ifdef CONFIG_ISA
-STATIC void __init
-AscEnableIsaDma(
-                   uchar dma_channel)
+static void __init AscEnableIsaDma(uchar dma_channel)
 {
-    if (dma_channel < 4) {
-        outp(0x000B, (ushort) (0xC0 | dma_channel));
-        outp(0x000A, dma_channel);
-    } else if (dma_channel < 8) {
-        outp(0x00D6, (ushort) (0xC0 | (dma_channel - 4)));
-        outp(0x00D4, (ushort) (dma_channel - 4));
-    }
-    return;
+	if (dma_channel < 4) {
+		outp(0x000B, (ushort)(0xC0 | dma_channel));
+		outp(0x000A, dma_channel);
+	} else if (dma_channel < 8) {
+		outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4)));
+		outp(0x00D4, (ushort)(dma_channel - 4));
+	}
+	return;
 }
 #endif /* CONFIG_ISA */
 
-STATIC int
-AscIsrChipHalted(
-                    ASC_DVC_VAR *asc_dvc
-)
+static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc)
 {
-    EXT_MSG             ext_msg;
-    EXT_MSG             out_msg;
-    ushort              halt_q_addr;
-    int                 sdtr_accept;
-    ushort              int_halt_code;
-    ASC_SCSI_BIT_ID_TYPE scsi_busy;
-    ASC_SCSI_BIT_ID_TYPE target_id;
-    PortAddr            iop_base;
-    uchar               tag_code;
-    uchar               q_status;
-    uchar               halt_qp;
-    uchar               sdtr_data;
-    uchar               target_ix;
-    uchar               q_cntl, tid_no;
-    uchar               cur_dvc_qng;
-    uchar               asyn_sdtr;
-    uchar               scsi_status;
-    asc_board_t         *boardp;
+	EXT_MSG ext_msg;
+	EXT_MSG out_msg;
+	ushort halt_q_addr;
+	int sdtr_accept;
+	ushort int_halt_code;
+	ASC_SCSI_BIT_ID_TYPE scsi_busy;
+	ASC_SCSI_BIT_ID_TYPE target_id;
+	PortAddr iop_base;
+	uchar tag_code;
+	uchar q_status;
+	uchar halt_qp;
+	uchar sdtr_data;
+	uchar target_ix;
+	uchar q_cntl, tid_no;
+	uchar cur_dvc_qng;
+	uchar asyn_sdtr;
+	uchar scsi_status;
+	asc_board_t *boardp;
 
-    ASC_ASSERT(asc_dvc->drv_ptr != NULL);
-    boardp = asc_dvc->drv_ptr;
+	ASC_ASSERT(asc_dvc->drv_ptr != NULL);
+	boardp = asc_dvc->drv_ptr;
 
-    iop_base = asc_dvc->iop_base;
-    int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
+	iop_base = asc_dvc->iop_base;
+	int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
 
-    halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
-    halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
-    target_ix = AscReadLramByte(iop_base,
-                   (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TARGET_IX));
-    q_cntl = AscReadLramByte(iop_base,
-                        (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL));
-    tid_no = ASC_TIX_TO_TID(target_ix);
-    target_id = (uchar) ASC_TID_TO_TARGET_ID(tid_no);
-    if (asc_dvc->pci_fix_asyn_xfer & target_id) {
-        asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
-    } else {
-        asyn_sdtr = 0;
-    }
-    if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
-        if (asc_dvc->pci_fix_asyn_xfer & target_id) {
-            AscSetChipSDTR(iop_base, 0, tid_no);
-            boardp->sdtr_data[tid_no] = 0;
-        }
-        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-        return (0);
-    } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
-        if (asc_dvc->pci_fix_asyn_xfer & target_id) {
-            AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
-            boardp->sdtr_data[tid_no] = asyn_sdtr;
-        }
-        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-        return (0);
-    } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
+	halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
+	halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
+	target_ix = AscReadLramByte(iop_base,
+				    (ushort)(halt_q_addr +
+					     (ushort)ASC_SCSIQ_B_TARGET_IX));
+	q_cntl =
+	    AscReadLramByte(iop_base,
+			    (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL));
+	tid_no = ASC_TIX_TO_TID(target_ix);
+	target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no);
+	if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+		asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
+	} else {
+		asyn_sdtr = 0;
+	}
+	if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
+		if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+			AscSetChipSDTR(iop_base, 0, tid_no);
+			boardp->sdtr_data[tid_no] = 0;
+		}
+		AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+		return (0);
+	} else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
+		if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+			AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+			boardp->sdtr_data[tid_no] = asyn_sdtr;
+		}
+		AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+		return (0);
+	} else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
 
-        AscMemWordCopyPtrFromLram(iop_base,
-                               ASCV_MSGIN_BEG,
-                               (uchar *) &ext_msg,
-                               sizeof(EXT_MSG) >> 1);
+		AscMemWordCopyPtrFromLram(iop_base,
+					  ASCV_MSGIN_BEG,
+					  (uchar *)&ext_msg,
+					  sizeof(EXT_MSG) >> 1);
 
-        if (ext_msg.msg_type == MS_EXTEND &&
-            ext_msg.msg_req == MS_SDTR_CODE &&
-            ext_msg.msg_len == MS_SDTR_LEN) {
-            sdtr_accept = TRUE;
-            if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
+		if (ext_msg.msg_type == MS_EXTEND &&
+		    ext_msg.msg_req == MS_SDTR_CODE &&
+		    ext_msg.msg_len == MS_SDTR_LEN) {
+			sdtr_accept = TRUE;
+			if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
 
-                sdtr_accept = FALSE;
-                ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
-            }
-            if ((ext_msg.xfer_period <
-                 asc_dvc->sdtr_period_tbl[asc_dvc->host_init_sdtr_index]) ||
-                (ext_msg.xfer_period >
-                 asc_dvc->sdtr_period_tbl[asc_dvc->max_sdtr_index])) {
-                sdtr_accept = FALSE;
-                ext_msg.xfer_period =
-                    asc_dvc->sdtr_period_tbl[asc_dvc->host_init_sdtr_index];
-            }
-            if (sdtr_accept) {
-                sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
-                                           ext_msg.req_ack_offset);
-                if ((sdtr_data == 0xFF)) {
+				sdtr_accept = FALSE;
+				ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
+			}
+			if ((ext_msg.xfer_period <
+			     asc_dvc->sdtr_period_tbl[asc_dvc->
+						      host_init_sdtr_index])
+			    || (ext_msg.xfer_period >
+				asc_dvc->sdtr_period_tbl[asc_dvc->
+							 max_sdtr_index])) {
+				sdtr_accept = FALSE;
+				ext_msg.xfer_period =
+				    asc_dvc->sdtr_period_tbl[asc_dvc->
+							     host_init_sdtr_index];
+			}
+			if (sdtr_accept) {
+				sdtr_data =
+				    AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
+						   ext_msg.req_ack_offset);
+				if ((sdtr_data == 0xFF)) {
 
-                    q_cntl |= QC_MSG_OUT;
-                    asc_dvc->init_sdtr &= ~target_id;
-                    asc_dvc->sdtr_done &= ~target_id;
-                    AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
-                    boardp->sdtr_data[tid_no] = asyn_sdtr;
-                }
-            }
-            if (ext_msg.req_ack_offset == 0) {
+					q_cntl |= QC_MSG_OUT;
+					asc_dvc->init_sdtr &= ~target_id;
+					asc_dvc->sdtr_done &= ~target_id;
+					AscSetChipSDTR(iop_base, asyn_sdtr,
+						       tid_no);
+					boardp->sdtr_data[tid_no] = asyn_sdtr;
+				}
+			}
+			if (ext_msg.req_ack_offset == 0) {
 
-                q_cntl &= ~QC_MSG_OUT;
-                asc_dvc->init_sdtr &= ~target_id;
-                asc_dvc->sdtr_done &= ~target_id;
-                AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
-            } else {
-                if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
+				q_cntl &= ~QC_MSG_OUT;
+				asc_dvc->init_sdtr &= ~target_id;
+				asc_dvc->sdtr_done &= ~target_id;
+				AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+			} else {
+				if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
 
-                    q_cntl &= ~QC_MSG_OUT;
-                    asc_dvc->sdtr_done |= target_id;
-                    asc_dvc->init_sdtr |= target_id;
-                    asc_dvc->pci_fix_asyn_xfer &= ~target_id;
-                    sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
-                                               ext_msg.req_ack_offset);
-                    AscSetChipSDTR(iop_base, sdtr_data, tid_no);
-                    boardp->sdtr_data[tid_no] = sdtr_data;
-                } else {
+					q_cntl &= ~QC_MSG_OUT;
+					asc_dvc->sdtr_done |= target_id;
+					asc_dvc->init_sdtr |= target_id;
+					asc_dvc->pci_fix_asyn_xfer &=
+					    ~target_id;
+					sdtr_data =
+					    AscCalSDTRData(asc_dvc,
+							   ext_msg.xfer_period,
+							   ext_msg.
+							   req_ack_offset);
+					AscSetChipSDTR(iop_base, sdtr_data,
+						       tid_no);
+					boardp->sdtr_data[tid_no] = sdtr_data;
+				} else {
 
-                    q_cntl |= QC_MSG_OUT;
-                    AscMsgOutSDTR(asc_dvc,
-                                  ext_msg.xfer_period,
-                                  ext_msg.req_ack_offset);
-                    asc_dvc->pci_fix_asyn_xfer &= ~target_id;
-                    sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
-                                               ext_msg.req_ack_offset);
-                    AscSetChipSDTR(iop_base, sdtr_data, tid_no);
-                    boardp->sdtr_data[tid_no] = sdtr_data;
-                    asc_dvc->sdtr_done |= target_id;
-                    asc_dvc->init_sdtr |= target_id;
-                }
-            }
+					q_cntl |= QC_MSG_OUT;
+					AscMsgOutSDTR(asc_dvc,
+						      ext_msg.xfer_period,
+						      ext_msg.req_ack_offset);
+					asc_dvc->pci_fix_asyn_xfer &=
+					    ~target_id;
+					sdtr_data =
+					    AscCalSDTRData(asc_dvc,
+							   ext_msg.xfer_period,
+							   ext_msg.
+							   req_ack_offset);
+					AscSetChipSDTR(iop_base, sdtr_data,
+						       tid_no);
+					boardp->sdtr_data[tid_no] = sdtr_data;
+					asc_dvc->sdtr_done |= target_id;
+					asc_dvc->init_sdtr |= target_id;
+				}
+			}
 
-            AscWriteLramByte(iop_base,
-                         (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
-                             q_cntl);
-            AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-            return (0);
-        } else if (ext_msg.msg_type == MS_EXTEND &&
-                   ext_msg.msg_req == MS_WDTR_CODE &&
-                   ext_msg.msg_len == MS_WDTR_LEN) {
+			AscWriteLramByte(iop_base,
+					 (ushort)(halt_q_addr +
+						  (ushort)ASC_SCSIQ_B_CNTL),
+					 q_cntl);
+			AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+			return (0);
+		} else if (ext_msg.msg_type == MS_EXTEND &&
+			   ext_msg.msg_req == MS_WDTR_CODE &&
+			   ext_msg.msg_len == MS_WDTR_LEN) {
 
-            ext_msg.wdtr_width = 0;
-            AscMemWordCopyPtrToLram(iop_base,
-                                 ASCV_MSGOUT_BEG,
-                                 (uchar *) &ext_msg,
-                                 sizeof(EXT_MSG) >> 1);
-            q_cntl |= QC_MSG_OUT;
-            AscWriteLramByte(iop_base,
-                         (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
-                             q_cntl);
-            AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-            return (0);
-        } else {
+			ext_msg.wdtr_width = 0;
+			AscMemWordCopyPtrToLram(iop_base,
+						ASCV_MSGOUT_BEG,
+						(uchar *)&ext_msg,
+						sizeof(EXT_MSG) >> 1);
+			q_cntl |= QC_MSG_OUT;
+			AscWriteLramByte(iop_base,
+					 (ushort)(halt_q_addr +
+						  (ushort)ASC_SCSIQ_B_CNTL),
+					 q_cntl);
+			AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+			return (0);
+		} else {
 
-            ext_msg.msg_type = MESSAGE_REJECT;
-            AscMemWordCopyPtrToLram(iop_base,
-                                 ASCV_MSGOUT_BEG,
-                                 (uchar *) &ext_msg,
-                                 sizeof(EXT_MSG) >> 1);
-            q_cntl |= QC_MSG_OUT;
-            AscWriteLramByte(iop_base,
-                         (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
-                             q_cntl);
-            AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-            return (0);
-        }
-    } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
+			ext_msg.msg_type = MESSAGE_REJECT;
+			AscMemWordCopyPtrToLram(iop_base,
+						ASCV_MSGOUT_BEG,
+						(uchar *)&ext_msg,
+						sizeof(EXT_MSG) >> 1);
+			q_cntl |= QC_MSG_OUT;
+			AscWriteLramByte(iop_base,
+					 (ushort)(halt_q_addr +
+						  (ushort)ASC_SCSIQ_B_CNTL),
+					 q_cntl);
+			AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+			return (0);
+		}
+	} else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
 
-        q_cntl |= QC_REQ_SENSE;
+		q_cntl |= QC_REQ_SENSE;
 
-        if ((asc_dvc->init_sdtr & target_id) != 0) {
+		if ((asc_dvc->init_sdtr & target_id) != 0) {
 
-            asc_dvc->sdtr_done &= ~target_id;
+			asc_dvc->sdtr_done &= ~target_id;
 
-            sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
-            q_cntl |= QC_MSG_OUT;
-            AscMsgOutSDTR(asc_dvc,
-                          asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) &
-                           (uchar) (asc_dvc->max_sdtr_index - 1)],
-                          (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
-        }
+			sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
+			q_cntl |= QC_MSG_OUT;
+			AscMsgOutSDTR(asc_dvc,
+				      asc_dvc->
+				      sdtr_period_tbl[(sdtr_data >> 4) &
+						      (uchar)(asc_dvc->
+							      max_sdtr_index -
+							      1)],
+				      (uchar)(sdtr_data & (uchar)
+					      ASC_SYN_MAX_OFFSET));
+		}
 
-        AscWriteLramByte(iop_base,
-                         (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
-                         q_cntl);
+		AscWriteLramByte(iop_base,
+				 (ushort)(halt_q_addr +
+					  (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
 
-        tag_code = AscReadLramByte(iop_base,
-                    (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE));
-        tag_code &= 0xDC;
-        if (
-               (asc_dvc->pci_fix_asyn_xfer & target_id)
-               && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
-) {
+		tag_code = AscReadLramByte(iop_base,
+					   (ushort)(halt_q_addr + (ushort)
+						    ASC_SCSIQ_B_TAG_CODE));
+		tag_code &= 0xDC;
+		if ((asc_dvc->pci_fix_asyn_xfer & target_id)
+		    && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
+		    ) {
 
-            tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
-                         | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
+			tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
+				     | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
 
-        }
-        AscWriteLramByte(iop_base,
-                     (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE),
-                         tag_code);
+		}
+		AscWriteLramByte(iop_base,
+				 (ushort)(halt_q_addr +
+					  (ushort)ASC_SCSIQ_B_TAG_CODE),
+				 tag_code);
 
-        q_status = AscReadLramByte(iop_base,
-                      (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS));
-        q_status |= (QS_READY | QS_BUSY);
-        AscWriteLramByte(iop_base,
-                       (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS),
-                         q_status);
+		q_status = AscReadLramByte(iop_base,
+					   (ushort)(halt_q_addr + (ushort)
+						    ASC_SCSIQ_B_STATUS));
+		q_status |= (QS_READY | QS_BUSY);
+		AscWriteLramByte(iop_base,
+				 (ushort)(halt_q_addr +
+					  (ushort)ASC_SCSIQ_B_STATUS),
+				 q_status);
 
-        scsi_busy = AscReadLramByte(iop_base,
-                                    (ushort) ASCV_SCSIBUSY_B);
-        scsi_busy &= ~target_id;
-        AscWriteLramByte(iop_base, (ushort) ASCV_SCSIBUSY_B, scsi_busy);
+		scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B);
+		scsi_busy &= ~target_id;
+		AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy);
 
-        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-        return (0);
-    } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
+		AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+		return (0);
+	} else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
 
-        AscMemWordCopyPtrFromLram(iop_base,
-                               ASCV_MSGOUT_BEG,
-                               (uchar *) &out_msg,
-                               sizeof(EXT_MSG) >> 1);
+		AscMemWordCopyPtrFromLram(iop_base,
+					  ASCV_MSGOUT_BEG,
+					  (uchar *)&out_msg,
+					  sizeof(EXT_MSG) >> 1);
 
-        if ((out_msg.msg_type == MS_EXTEND) &&
-            (out_msg.msg_len == MS_SDTR_LEN) &&
-            (out_msg.msg_req == MS_SDTR_CODE)) {
+		if ((out_msg.msg_type == MS_EXTEND) &&
+		    (out_msg.msg_len == MS_SDTR_LEN) &&
+		    (out_msg.msg_req == MS_SDTR_CODE)) {
 
-            asc_dvc->init_sdtr &= ~target_id;
-            asc_dvc->sdtr_done &= ~target_id;
-            AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
-            boardp->sdtr_data[tid_no] = asyn_sdtr;
-        }
-        q_cntl &= ~QC_MSG_OUT;
-        AscWriteLramByte(iop_base,
-                         (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
-                         q_cntl);
-        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-        return (0);
-    } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
+			asc_dvc->init_sdtr &= ~target_id;
+			asc_dvc->sdtr_done &= ~target_id;
+			AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+			boardp->sdtr_data[tid_no] = asyn_sdtr;
+		}
+		q_cntl &= ~QC_MSG_OUT;
+		AscWriteLramByte(iop_base,
+				 (ushort)(halt_q_addr +
+					  (ushort)ASC_SCSIQ_B_CNTL), q_cntl);
+		AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+		return (0);
+	} else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
 
-        scsi_status = AscReadLramByte(iop_base,
-          (ushort) ((ushort) halt_q_addr + (ushort) ASC_SCSIQ_SCSI_STATUS));
-        cur_dvc_qng = AscReadLramByte(iop_base,
-                     (ushort) ((ushort) ASC_QADR_BEG + (ushort) target_ix));
-        if ((cur_dvc_qng > 0) &&
-            (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
+		scsi_status = AscReadLramByte(iop_base,
+					      (ushort)((ushort)halt_q_addr +
+						       (ushort)
+						       ASC_SCSIQ_SCSI_STATUS));
+		cur_dvc_qng =
+		    AscReadLramByte(iop_base,
+				    (ushort)((ushort)ASC_QADR_BEG +
+					     (ushort)target_ix));
+		if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
 
-            scsi_busy = AscReadLramByte(iop_base,
-                                        (ushort) ASCV_SCSIBUSY_B);
-            scsi_busy |= target_id;
-            AscWriteLramByte(iop_base,
-                             (ushort) ASCV_SCSIBUSY_B, scsi_busy);
-            asc_dvc->queue_full_or_busy |= target_id;
+			scsi_busy = AscReadLramByte(iop_base,
+						    (ushort)ASCV_SCSIBUSY_B);
+			scsi_busy |= target_id;
+			AscWriteLramByte(iop_base,
+					 (ushort)ASCV_SCSIBUSY_B, scsi_busy);
+			asc_dvc->queue_full_or_busy |= target_id;
 
-            if (scsi_status == SAM_STAT_TASK_SET_FULL) {
-                if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
-                    cur_dvc_qng -= 1;
-                    asc_dvc->max_dvc_qng[tid_no] = cur_dvc_qng;
+			if (scsi_status == SAM_STAT_TASK_SET_FULL) {
+				if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
+					cur_dvc_qng -= 1;
+					asc_dvc->max_dvc_qng[tid_no] =
+					    cur_dvc_qng;
 
-                    AscWriteLramByte(iop_base,
-                          (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG +
-                           (ushort) tid_no),
-                          cur_dvc_qng);
+					AscWriteLramByte(iop_base,
+							 (ushort)((ushort)
+								  ASCV_MAX_DVC_QNG_BEG
+								  + (ushort)
+								  tid_no),
+							 cur_dvc_qng);
 
-                    /*
-                     * Set the device queue depth to the number of
-                     * active requests when the QUEUE FULL condition
-                     * was encountered.
-                     */
-                    boardp->queue_full |= target_id;
-                    boardp->queue_full_cnt[tid_no] = cur_dvc_qng;
-                }
-            }
-        }
-        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-        return (0);
-    }
+					/*
+					 * Set the device queue depth to the number of
+					 * active requests when the QUEUE FULL condition
+					 * was encountered.
+					 */
+					boardp->queue_full |= target_id;
+					boardp->queue_full_cnt[tid_no] =
+					    cur_dvc_qng;
+				}
+			}
+		}
+		AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+		return (0);
+	}
 #if CC_VERY_LONG_SG_LIST
-    else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC)
-    {
-        uchar              q_no;
-        ushort             q_addr;
-        uchar              sg_wk_q_no;
-        uchar              first_sg_wk_q_no;
-        ASC_SCSI_Q         *scsiq; /* Ptr to driver request. */
-        ASC_SG_HEAD        *sg_head; /* Ptr to driver SG request. */
-        ASC_SG_LIST_Q      scsi_sg_q; /* Structure written to queue. */
-        ushort             sg_list_dwords;
-        ushort             sg_entry_cnt;
-        uchar              next_qp;
-        int                i;
+	else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) {
+		uchar q_no;
+		ushort q_addr;
+		uchar sg_wk_q_no;
+		uchar first_sg_wk_q_no;
+		ASC_SCSI_Q *scsiq;	/* Ptr to driver request. */
+		ASC_SG_HEAD *sg_head;	/* Ptr to driver SG request. */
+		ASC_SG_LIST_Q scsi_sg_q;	/* Structure written to queue. */
+		ushort sg_list_dwords;
+		ushort sg_entry_cnt;
+		uchar next_qp;
+		int i;
 
-        q_no = AscReadLramByte(iop_base, (ushort) ASCV_REQ_SG_LIST_QP);
-        if (q_no == ASC_QLINK_END)
-        {
-            return(0);
-        }
+		q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP);
+		if (q_no == ASC_QLINK_END) {
+			return (0);
+		}
 
-        q_addr = ASC_QNO_TO_QADDR(q_no);
+		q_addr = ASC_QNO_TO_QADDR(q_no);
 
-        /*
-         * Convert the request's SRB pointer to a host ASC_SCSI_REQ
-         * structure pointer using a macro provided by the driver.
-         * The ASC_SCSI_REQ pointer provides a pointer to the
-         * host ASC_SG_HEAD structure.
-         */
-        /* Read request's SRB pointer. */
-        scsiq = (ASC_SCSI_Q *)
-           ASC_SRB2SCSIQ(
-               ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
-               (ushort) (q_addr + ASC_SCSIQ_D_SRBPTR))));
+		/*
+		 * Convert the request's SRB pointer to a host ASC_SCSI_REQ
+		 * structure pointer using a macro provided by the driver.
+		 * The ASC_SCSI_REQ pointer provides a pointer to the
+		 * host ASC_SG_HEAD structure.
+		 */
+		/* Read request's SRB pointer. */
+		scsiq = (ASC_SCSI_Q *)
+		    ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
+								    (ushort)
+								    (q_addr +
+								     ASC_SCSIQ_D_SRBPTR))));
 
-        /*
-         * Get request's first and working SG queue.
-         */
-        sg_wk_q_no = AscReadLramByte(iop_base,
-            (ushort) (q_addr + ASC_SCSIQ_B_SG_WK_QP));
+		/*
+		 * Get request's first and working SG queue.
+		 */
+		sg_wk_q_no = AscReadLramByte(iop_base,
+					     (ushort)(q_addr +
+						      ASC_SCSIQ_B_SG_WK_QP));
 
-        first_sg_wk_q_no = AscReadLramByte(iop_base,
-            (ushort) (q_addr + ASC_SCSIQ_B_FIRST_SG_WK_QP));
+		first_sg_wk_q_no = AscReadLramByte(iop_base,
+						   (ushort)(q_addr +
+							    ASC_SCSIQ_B_FIRST_SG_WK_QP));
 
-        /*
-         * Reset request's working SG queue back to the
-         * first SG queue.
-         */
-        AscWriteLramByte(iop_base,
-            (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SG_WK_QP),
-            first_sg_wk_q_no);
+		/*
+		 * Reset request's working SG queue back to the
+		 * first SG queue.
+		 */
+		AscWriteLramByte(iop_base,
+				 (ushort)(q_addr +
+					  (ushort)ASC_SCSIQ_B_SG_WK_QP),
+				 first_sg_wk_q_no);
 
-        sg_head = scsiq->sg_head;
+		sg_head = scsiq->sg_head;
 
-        /*
-         * Set sg_entry_cnt to the number of SG elements
-         * that will be completed on this interrupt.
-         *
-         * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
-         * SG elements. The data_cnt and data_addr fields which
-         * add 1 to the SG element capacity are not used when
-         * restarting SG handling after a halt.
-         */
-        if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1))
-        {
-             sg_entry_cnt = ASC_MAX_SG_LIST - 1;
+		/*
+		 * Set sg_entry_cnt to the number of SG elements
+		 * that will be completed on this interrupt.
+		 *
+		 * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
+		 * SG elements. The data_cnt and data_addr fields which
+		 * add 1 to the SG element capacity are not used when
+		 * restarting SG handling after a halt.
+		 */
+		if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) {
+			sg_entry_cnt = ASC_MAX_SG_LIST - 1;
 
-             /*
-              * Keep track of remaining number of SG elements that will
-              * need to be handled on the next interrupt.
-              */
-             scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
-        } else
-        {
-             sg_entry_cnt = scsiq->remain_sg_entry_cnt;
-             scsiq->remain_sg_entry_cnt = 0;
-        }
+			/*
+			 * Keep track of remaining number of SG elements that will
+			 * need to be handled on the next interrupt.
+			 */
+			scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
+		} else {
+			sg_entry_cnt = scsiq->remain_sg_entry_cnt;
+			scsiq->remain_sg_entry_cnt = 0;
+		}
 
-        /*
-         * Copy SG elements into the list of allocated SG queues.
-         *
-         * Last index completed is saved in scsiq->next_sg_index.
-         */
-        next_qp = first_sg_wk_q_no;
-        q_addr = ASC_QNO_TO_QADDR(next_qp);
-        scsi_sg_q.sg_head_qp = q_no;
-        scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
-        for( i = 0; i < sg_head->queue_cnt; i++)
-        {
-             scsi_sg_q.seq_no = i + 1;
-             if (sg_entry_cnt > ASC_SG_LIST_PER_Q)
-             {
-                 sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2);
-                 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
-                 /*
-                  * After very first SG queue RISC FW uses next
-                  * SG queue first element then checks sg_list_cnt
-                  * against zero and then decrements, so set
-                  * sg_list_cnt 1 less than number of SG elements
-                  * in each SG queue.
-                  */
-                 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
-                 scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
-             } else {
-                 /*
-                  * This is the last SG queue in the list of
-                  * allocated SG queues. If there are more
-                  * SG elements than will fit in the allocated
-                  * queues, then set the QCSG_SG_XFER_MORE flag.
-                  */
-                 if (scsiq->remain_sg_entry_cnt != 0)
-                 {
-                     scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
-                 } else
-                 {
-                     scsi_sg_q.cntl |= QCSG_SG_XFER_END;
-                 }
-                 /* equals sg_entry_cnt * 2 */
-                 sg_list_dwords = sg_entry_cnt << 1;
-                 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
-                 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
-                 sg_entry_cnt = 0;
-             }
+		/*
+		 * Copy SG elements into the list of allocated SG queues.
+		 *
+		 * Last index completed is saved in scsiq->next_sg_index.
+		 */
+		next_qp = first_sg_wk_q_no;
+		q_addr = ASC_QNO_TO_QADDR(next_qp);
+		scsi_sg_q.sg_head_qp = q_no;
+		scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
+		for (i = 0; i < sg_head->queue_cnt; i++) {
+			scsi_sg_q.seq_no = i + 1;
+			if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
+				sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
+				sg_entry_cnt -= ASC_SG_LIST_PER_Q;
+				/*
+				 * After very first SG queue RISC FW uses next
+				 * SG queue first element then checks sg_list_cnt
+				 * against zero and then decrements, so set
+				 * sg_list_cnt 1 less than number of SG elements
+				 * in each SG queue.
+				 */
+				scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
+				scsi_sg_q.sg_cur_list_cnt =
+				    ASC_SG_LIST_PER_Q - 1;
+			} else {
+				/*
+				 * This is the last SG queue in the list of
+				 * allocated SG queues. If there are more
+				 * SG elements than will fit in the allocated
+				 * queues, then set the QCSG_SG_XFER_MORE flag.
+				 */
+				if (scsiq->remain_sg_entry_cnt != 0) {
+					scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
+				} else {
+					scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+				}
+				/* equals sg_entry_cnt * 2 */
+				sg_list_dwords = sg_entry_cnt << 1;
+				scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
+				scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
+				sg_entry_cnt = 0;
+			}
 
-             scsi_sg_q.q_no = next_qp;
-             AscMemWordCopyPtrToLram(iop_base,
-                          q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
-                          (uchar *) &scsi_sg_q,
-                          sizeof(ASC_SG_LIST_Q) >> 1);
+			scsi_sg_q.q_no = next_qp;
+			AscMemWordCopyPtrToLram(iop_base,
+						q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
+						(uchar *)&scsi_sg_q,
+						sizeof(ASC_SG_LIST_Q) >> 1);
 
-             AscMemDWordCopyPtrToLram(iop_base,
-                          q_addr + ASC_SGQ_LIST_BEG,
-                          (uchar *) &sg_head->sg_list[scsiq->next_sg_index],
-                          sg_list_dwords);
+			AscMemDWordCopyPtrToLram(iop_base,
+						 q_addr + ASC_SGQ_LIST_BEG,
+						 (uchar *)&sg_head->
+						 sg_list[scsiq->next_sg_index],
+						 sg_list_dwords);
 
-             scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
+			scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
 
-             /*
-              * If the just completed SG queue contained the
-              * last SG element, then no more SG queues need
-              * to be written.
-              */
-             if (scsi_sg_q.cntl & QCSG_SG_XFER_END)
-             {
-                 break;
-             }
+			/*
+			 * If the just completed SG queue contained the
+			 * last SG element, then no more SG queues need
+			 * to be written.
+			 */
+			if (scsi_sg_q.cntl & QCSG_SG_XFER_END) {
+				break;
+			}
 
-             next_qp = AscReadLramByte( iop_base,
-                          ( ushort )( q_addr+ASC_SCSIQ_B_FWD ) );
-             q_addr = ASC_QNO_TO_QADDR( next_qp );
-        }
+			next_qp = AscReadLramByte(iop_base,
+						  (ushort)(q_addr +
+							   ASC_SCSIQ_B_FWD));
+			q_addr = ASC_QNO_TO_QADDR(next_qp);
+		}
 
-        /*
-         * Clear the halt condition so the RISC will be restarted
-         * after the return.
-         */
-        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-        return(0);
-    }
+		/*
+		 * Clear the halt condition so the RISC will be restarted
+		 * after the return.
+		 */
+		AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+		return (0);
+	}
 #endif /* CC_VERY_LONG_SG_LIST */
-    return (0);
+	return (0);
 }
 
-STATIC uchar
-_AscCopyLramScsiDoneQ(
-                         PortAddr iop_base,
-                         ushort q_addr,
-                         ASC_QDONE_INFO * scsiq,
-                         ASC_DCNT max_dma_count
-)
+static uchar
+_AscCopyLramScsiDoneQ(PortAddr iop_base,
+		      ushort q_addr,
+		      ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count)
 {
-    ushort              _val;
-    uchar               sg_queue_cnt;
+	ushort _val;
+	uchar sg_queue_cnt;
 
-    DvcGetQinfo(iop_base,
-                q_addr + ASC_SCSIQ_DONE_INFO_BEG,
-                (uchar *) scsiq,
-                (sizeof (ASC_SCSIQ_2) + sizeof (ASC_SCSIQ_3)) / 2);
+	DvcGetQinfo(iop_base,
+		    q_addr + ASC_SCSIQ_DONE_INFO_BEG,
+		    (uchar *)scsiq,
+		    (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2);
 
-    _val = AscReadLramWord(iop_base,
-                           (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS));
-    scsiq->q_status = (uchar) _val;
-    scsiq->q_no = (uchar) (_val >> 8);
-    _val = AscReadLramWord(iop_base,
-                           (ushort) (q_addr + (ushort) ASC_SCSIQ_B_CNTL));
-    scsiq->cntl = (uchar) _val;
-    sg_queue_cnt = (uchar) (_val >> 8);
-    _val = AscReadLramWord(iop_base,
-                        (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SENSE_LEN));
-    scsiq->sense_len = (uchar) _val;
-    scsiq->extra_bytes = (uchar) (_val >> 8);
+	_val = AscReadLramWord(iop_base,
+			       (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS));
+	scsiq->q_status = (uchar)_val;
+	scsiq->q_no = (uchar)(_val >> 8);
+	_val = AscReadLramWord(iop_base,
+			       (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL));
+	scsiq->cntl = (uchar)_val;
+	sg_queue_cnt = (uchar)(_val >> 8);
+	_val = AscReadLramWord(iop_base,
+			       (ushort)(q_addr +
+					(ushort)ASC_SCSIQ_B_SENSE_LEN));
+	scsiq->sense_len = (uchar)_val;
+	scsiq->extra_bytes = (uchar)(_val >> 8);
 
-    /*
-     * Read high word of remain bytes from alternate location.
-     */
-    scsiq->remain_bytes = (((ADV_DCNT) AscReadLramWord( iop_base,
-                      (ushort) (q_addr+ (ushort) ASC_SCSIQ_W_ALT_DC1))) << 16);
-    /*
-     * Read low word of remain bytes from original location.
-     */
-    scsiq->remain_bytes += AscReadLramWord(iop_base,
-        (ushort) (q_addr+ (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT));
+	/*
+	 * Read high word of remain bytes from alternate location.
+	 */
+	scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base,
+							  (ushort)(q_addr +
+								   (ushort)
+								   ASC_SCSIQ_W_ALT_DC1)))
+			       << 16);
+	/*
+	 * Read low word of remain bytes from original location.
+	 */
+	scsiq->remain_bytes += AscReadLramWord(iop_base,
+					       (ushort)(q_addr + (ushort)
+							ASC_SCSIQ_DW_REMAIN_XFER_CNT));
 
-    scsiq->remain_bytes &= max_dma_count;
-    return (sg_queue_cnt);
+	scsiq->remain_bytes &= max_dma_count;
+	return (sg_queue_cnt);
 }
 
-STATIC int
-AscIsrQDone(
-               ASC_DVC_VAR *asc_dvc
-)
+static int AscIsrQDone(ASC_DVC_VAR *asc_dvc)
 {
-    uchar               next_qp;
-    uchar               n_q_used;
-    uchar               sg_list_qp;
-    uchar               sg_queue_cnt;
-    uchar               q_cnt;
-    uchar               done_q_tail;
-    uchar               tid_no;
-    ASC_SCSI_BIT_ID_TYPE scsi_busy;
-    ASC_SCSI_BIT_ID_TYPE target_id;
-    PortAddr            iop_base;
-    ushort              q_addr;
-    ushort              sg_q_addr;
-    uchar               cur_target_qng;
-    ASC_QDONE_INFO      scsiq_buf;
-    ASC_QDONE_INFO *scsiq;
-    int                 false_overrun;
-    ASC_ISR_CALLBACK    asc_isr_callback;
+	uchar next_qp;
+	uchar n_q_used;
+	uchar sg_list_qp;
+	uchar sg_queue_cnt;
+	uchar q_cnt;
+	uchar done_q_tail;
+	uchar tid_no;
+	ASC_SCSI_BIT_ID_TYPE scsi_busy;
+	ASC_SCSI_BIT_ID_TYPE target_id;
+	PortAddr iop_base;
+	ushort q_addr;
+	ushort sg_q_addr;
+	uchar cur_target_qng;
+	ASC_QDONE_INFO scsiq_buf;
+	ASC_QDONE_INFO *scsiq;
+	int false_overrun;
+	ASC_ISR_CALLBACK asc_isr_callback;
 
-    iop_base = asc_dvc->iop_base;
-    asc_isr_callback = asc_dvc->isr_callback;
-    n_q_used = 1;
-    scsiq = (ASC_QDONE_INFO *) & scsiq_buf;
-    done_q_tail = (uchar) AscGetVarDoneQTail(iop_base);
-    q_addr = ASC_QNO_TO_QADDR(done_q_tail);
-    next_qp = AscReadLramByte(iop_base,
-                              (ushort) (q_addr + (ushort) ASC_SCSIQ_B_FWD));
-    if (next_qp != ASC_QLINK_END) {
-        AscPutVarDoneQTail(iop_base, next_qp);
-        q_addr = ASC_QNO_TO_QADDR(next_qp);
-        sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
-            asc_dvc->max_dma_count);
-        AscWriteLramByte(iop_base,
-                         (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
-             (uchar) (scsiq->q_status & (uchar) ~ (QS_READY | QS_ABORTED)));
-        tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
-        target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
-        if ((scsiq->cntl & QC_SG_HEAD) != 0) {
-            sg_q_addr = q_addr;
-            sg_list_qp = next_qp;
-            for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
-                sg_list_qp = AscReadLramByte(iop_base,
-                           (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_FWD));
-                sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
-                if (sg_list_qp == ASC_QLINK_END) {
-                    AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SG_Q_LINKS);
-                    scsiq->d3.done_stat = QD_WITH_ERROR;
-                    scsiq->d3.host_stat = QHSTA_D_QDONE_SG_LIST_CORRUPTED;
-                    goto FATAL_ERR_QDONE;
-                }
-                AscWriteLramByte(iop_base,
-                         (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_STATUS),
-                                 QS_FREE);
-            }
-            n_q_used = sg_queue_cnt + 1;
-            AscPutVarDoneQTail(iop_base, sg_list_qp);
-        }
-        if (asc_dvc->queue_full_or_busy & target_id) {
-            cur_target_qng = AscReadLramByte(iop_base,
-            (ushort) ((ushort) ASC_QADR_BEG + (ushort) scsiq->d2.target_ix));
-            if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
-                scsi_busy = AscReadLramByte(iop_base,
-                                            (ushort) ASCV_SCSIBUSY_B);
-                scsi_busy &= ~target_id;
-                AscWriteLramByte(iop_base,
-                                 (ushort) ASCV_SCSIBUSY_B, scsi_busy);
-                asc_dvc->queue_full_or_busy &= ~target_id;
-            }
-        }
-        if (asc_dvc->cur_total_qng >= n_q_used) {
-            asc_dvc->cur_total_qng -= n_q_used;
-            if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
-                asc_dvc->cur_dvc_qng[tid_no]--;
-            }
-        } else {
-            AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
-            scsiq->d3.done_stat = QD_WITH_ERROR;
-            goto FATAL_ERR_QDONE;
-        }
-        if ((scsiq->d2.srb_ptr == 0UL) ||
-            ((scsiq->q_status & QS_ABORTED) != 0)) {
-            return (0x11);
-        } else if (scsiq->q_status == QS_DONE) {
-            false_overrun = FALSE;
-            if (scsiq->extra_bytes != 0) {
-                scsiq->remain_bytes += (ADV_DCNT) scsiq->extra_bytes;
-            }
-            if (scsiq->d3.done_stat == QD_WITH_ERROR) {
-                if (scsiq->d3.host_stat == QHSTA_M_DATA_OVER_RUN) {
-                    if ((scsiq->cntl & (QC_DATA_IN | QC_DATA_OUT)) == 0) {
-                        scsiq->d3.done_stat = QD_NO_ERROR;
-                        scsiq->d3.host_stat = QHSTA_NO_ERROR;
-                    } else if (false_overrun) {
-                        scsiq->d3.done_stat = QD_NO_ERROR;
-                        scsiq->d3.host_stat = QHSTA_NO_ERROR;
-                    }
-                } else if (scsiq->d3.host_stat ==
-                           QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
-                    AscStopChip(iop_base);
-                    AscSetChipControl(iop_base,
-                        (uchar) (CC_SCSI_RESET | CC_HALT));
-                    DvcDelayNanoSecond(asc_dvc, 60000);
-                    AscSetChipControl(iop_base, CC_HALT);
-                    AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
-                    AscSetChipStatus(iop_base, 0);
-                    AscSetChipControl(iop_base, 0);
-                }
-            }
-            if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
-                (*asc_isr_callback) (asc_dvc, scsiq);
-            } else {
-                if ((AscReadLramByte(iop_base,
-                          (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG)) ==
-                     START_STOP)) {
-                    asc_dvc->unit_not_ready &= ~target_id;
-                    if (scsiq->d3.done_stat != QD_NO_ERROR) {
-                        asc_dvc->start_motor &= ~target_id;
-                    }
-                }
-            }
-            return (1);
-        } else {
-            AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
-          FATAL_ERR_QDONE:
-            if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
-                (*asc_isr_callback) (asc_dvc, scsiq);
-            }
-            return (0x80);
-        }
-    }
-    return (0);
+	iop_base = asc_dvc->iop_base;
+	asc_isr_callback = asc_dvc->isr_callback;
+	n_q_used = 1;
+	scsiq = (ASC_QDONE_INFO *)&scsiq_buf;
+	done_q_tail = (uchar)AscGetVarDoneQTail(iop_base);
+	q_addr = ASC_QNO_TO_QADDR(done_q_tail);
+	next_qp = AscReadLramByte(iop_base,
+				  (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD));
+	if (next_qp != ASC_QLINK_END) {
+		AscPutVarDoneQTail(iop_base, next_qp);
+		q_addr = ASC_QNO_TO_QADDR(next_qp);
+		sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
+						     asc_dvc->max_dma_count);
+		AscWriteLramByte(iop_base,
+				 (ushort)(q_addr +
+					  (ushort)ASC_SCSIQ_B_STATUS),
+				 (uchar)(scsiq->
+					 q_status & (uchar)~(QS_READY |
+							     QS_ABORTED)));
+		tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
+		target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
+		if ((scsiq->cntl & QC_SG_HEAD) != 0) {
+			sg_q_addr = q_addr;
+			sg_list_qp = next_qp;
+			for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
+				sg_list_qp = AscReadLramByte(iop_base,
+							     (ushort)(sg_q_addr
+								      + (ushort)
+								      ASC_SCSIQ_B_FWD));
+				sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
+				if (sg_list_qp == ASC_QLINK_END) {
+					AscSetLibErrorCode(asc_dvc,
+							   ASCQ_ERR_SG_Q_LINKS);
+					scsiq->d3.done_stat = QD_WITH_ERROR;
+					scsiq->d3.host_stat =
+					    QHSTA_D_QDONE_SG_LIST_CORRUPTED;
+					goto FATAL_ERR_QDONE;
+				}
+				AscWriteLramByte(iop_base,
+						 (ushort)(sg_q_addr + (ushort)
+							  ASC_SCSIQ_B_STATUS),
+						 QS_FREE);
+			}
+			n_q_used = sg_queue_cnt + 1;
+			AscPutVarDoneQTail(iop_base, sg_list_qp);
+		}
+		if (asc_dvc->queue_full_or_busy & target_id) {
+			cur_target_qng = AscReadLramByte(iop_base,
+							 (ushort)((ushort)
+								  ASC_QADR_BEG
+								  + (ushort)
+								  scsiq->d2.
+								  target_ix));
+			if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
+				scsi_busy = AscReadLramByte(iop_base, (ushort)
+							    ASCV_SCSIBUSY_B);
+				scsi_busy &= ~target_id;
+				AscWriteLramByte(iop_base,
+						 (ushort)ASCV_SCSIBUSY_B,
+						 scsi_busy);
+				asc_dvc->queue_full_or_busy &= ~target_id;
+			}
+		}
+		if (asc_dvc->cur_total_qng >= n_q_used) {
+			asc_dvc->cur_total_qng -= n_q_used;
+			if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
+				asc_dvc->cur_dvc_qng[tid_no]--;
+			}
+		} else {
+			AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
+			scsiq->d3.done_stat = QD_WITH_ERROR;
+			goto FATAL_ERR_QDONE;
+		}
+		if ((scsiq->d2.srb_ptr == 0UL) ||
+		    ((scsiq->q_status & QS_ABORTED) != 0)) {
+			return (0x11);
+		} else if (scsiq->q_status == QS_DONE) {
+			false_overrun = FALSE;
+			if (scsiq->extra_bytes != 0) {
+				scsiq->remain_bytes +=
+				    (ADV_DCNT)scsiq->extra_bytes;
+			}
+			if (scsiq->d3.done_stat == QD_WITH_ERROR) {
+				if (scsiq->d3.host_stat ==
+				    QHSTA_M_DATA_OVER_RUN) {
+					if ((scsiq->
+					     cntl & (QC_DATA_IN | QC_DATA_OUT))
+					    == 0) {
+						scsiq->d3.done_stat =
+						    QD_NO_ERROR;
+						scsiq->d3.host_stat =
+						    QHSTA_NO_ERROR;
+					} else if (false_overrun) {
+						scsiq->d3.done_stat =
+						    QD_NO_ERROR;
+						scsiq->d3.host_stat =
+						    QHSTA_NO_ERROR;
+					}
+				} else if (scsiq->d3.host_stat ==
+					   QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
+					AscStopChip(iop_base);
+					AscSetChipControl(iop_base,
+							  (uchar)(CC_SCSI_RESET
+								  | CC_HALT));
+					DvcDelayNanoSecond(asc_dvc, 60000);
+					AscSetChipControl(iop_base, CC_HALT);
+					AscSetChipStatus(iop_base,
+							 CIW_CLR_SCSI_RESET_INT);
+					AscSetChipStatus(iop_base, 0);
+					AscSetChipControl(iop_base, 0);
+				}
+			}
+			if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
+				(*asc_isr_callback) (asc_dvc, scsiq);
+			} else {
+				if ((AscReadLramByte(iop_base,
+						     (ushort)(q_addr + (ushort)
+							      ASC_SCSIQ_CDB_BEG))
+				     == START_STOP)) {
+					asc_dvc->unit_not_ready &= ~target_id;
+					if (scsiq->d3.done_stat != QD_NO_ERROR) {
+						asc_dvc->start_motor &=
+						    ~target_id;
+					}
+				}
+			}
+			return (1);
+		} else {
+			AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
+ FATAL_ERR_QDONE:
+			if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
+				(*asc_isr_callback) (asc_dvc, scsiq);
+			}
+			return (0x80);
+		}
+	}
+	return (0);
 }
 
-STATIC int
-AscISR(
-          ASC_DVC_VAR *asc_dvc
-)
+static int AscISR(ASC_DVC_VAR *asc_dvc)
 {
-    ASC_CS_TYPE         chipstat;
-    PortAddr            iop_base;
-    ushort              saved_ram_addr;
-    uchar               ctrl_reg;
-    uchar               saved_ctrl_reg;
-    int                 int_pending;
-    int                 status;
-    uchar               host_flag;
+	ASC_CS_TYPE chipstat;
+	PortAddr iop_base;
+	ushort saved_ram_addr;
+	uchar ctrl_reg;
+	uchar saved_ctrl_reg;
+	int int_pending;
+	int status;
+	uchar host_flag;
 
-    iop_base = asc_dvc->iop_base;
-    int_pending = FALSE;
+	iop_base = asc_dvc->iop_base;
+	int_pending = FALSE;
 
-    if (AscIsIntPending(iop_base) == 0)
-    {
-        return int_pending;
-    }
+	if (AscIsIntPending(iop_base) == 0) {
+		return int_pending;
+	}
 
-    if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
-        || (asc_dvc->isr_callback == 0)
-) {
-        return (ERR);
-    }
-    if (asc_dvc->in_critical_cnt != 0) {
-        AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
-        return (ERR);
-    }
-    if (asc_dvc->is_in_int) {
-        AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
-        return (ERR);
-    }
-    asc_dvc->is_in_int = TRUE;
-    ctrl_reg = AscGetChipControl(iop_base);
-    saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
-                                   CC_SINGLE_STEP | CC_DIAG | CC_TEST));
-    chipstat = AscGetChipStatus(iop_base);
-    if (chipstat & CSW_SCSI_RESET_LATCH) {
-        if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
-            int i = 10;
-            int_pending = TRUE;
-            asc_dvc->sdtr_done = 0;
-            saved_ctrl_reg &= (uchar) (~CC_HALT);
-            while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) &&
-                   (i-- > 0))
-            {
-                  DvcSleepMilliSecond(100);
-            }
-            AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
-            AscSetChipControl(iop_base, CC_HALT);
-            AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
-            AscSetChipStatus(iop_base, 0);
-            chipstat = AscGetChipStatus(iop_base);
-        }
-    }
-    saved_ram_addr = AscGetChipLramAddr(iop_base);
-    host_flag = AscReadLramByte(iop_base,
-        ASCV_HOST_FLAG_B) & (uchar) (~ASC_HOST_FLAG_IN_ISR);
-    AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
-                     (uchar) (host_flag | (uchar) ASC_HOST_FLAG_IN_ISR));
-    if ((chipstat & CSW_INT_PENDING)
-        || (int_pending)
-) {
-        AscAckInterrupt(iop_base);
-        int_pending = TRUE;
-        if ((chipstat & CSW_HALTED) &&
-            (ctrl_reg & CC_SINGLE_STEP)) {
-            if (AscIsrChipHalted(asc_dvc) == ERR) {
-                goto ISR_REPORT_QDONE_FATAL_ERROR;
-            } else {
-                saved_ctrl_reg &= (uchar) (~CC_HALT);
-            }
-        } else {
-          ISR_REPORT_QDONE_FATAL_ERROR:
-            if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
-                while (((status = AscIsrQDone(asc_dvc)) & 0x01) != 0) {
-                }
-            } else {
-                do {
-                    if ((status = AscIsrQDone(asc_dvc)) == 1) {
-                        break;
-                    }
-                } while (status == 0x11);
-            }
-            if ((status & 0x80) != 0)
-                int_pending = ERR;
-        }
-    }
-    AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
-    AscSetChipLramAddr(iop_base, saved_ram_addr);
-    AscSetChipControl(iop_base, saved_ctrl_reg);
-    asc_dvc->is_in_int = FALSE;
-    return (int_pending);
+	if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
+	    || (asc_dvc->isr_callback == 0)
+	    ) {
+		return (ERR);
+	}
+	if (asc_dvc->in_critical_cnt != 0) {
+		AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
+		return (ERR);
+	}
+	if (asc_dvc->is_in_int) {
+		AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
+		return (ERR);
+	}
+	asc_dvc->is_in_int = TRUE;
+	ctrl_reg = AscGetChipControl(iop_base);
+	saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
+				       CC_SINGLE_STEP | CC_DIAG | CC_TEST));
+	chipstat = AscGetChipStatus(iop_base);
+	if (chipstat & CSW_SCSI_RESET_LATCH) {
+		if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
+			int i = 10;
+			int_pending = TRUE;
+			asc_dvc->sdtr_done = 0;
+			saved_ctrl_reg &= (uchar)(~CC_HALT);
+			while ((AscGetChipStatus(iop_base) &
+				CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) {
+				DvcSleepMilliSecond(100);
+			}
+			AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
+			AscSetChipControl(iop_base, CC_HALT);
+			AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
+			AscSetChipStatus(iop_base, 0);
+			chipstat = AscGetChipStatus(iop_base);
+		}
+	}
+	saved_ram_addr = AscGetChipLramAddr(iop_base);
+	host_flag = AscReadLramByte(iop_base,
+				    ASCV_HOST_FLAG_B) &
+	    (uchar)(~ASC_HOST_FLAG_IN_ISR);
+	AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
+			 (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR));
+	if ((chipstat & CSW_INT_PENDING)
+	    || (int_pending)
+	    ) {
+		AscAckInterrupt(iop_base);
+		int_pending = TRUE;
+		if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) {
+			if (AscIsrChipHalted(asc_dvc) == ERR) {
+				goto ISR_REPORT_QDONE_FATAL_ERROR;
+			} else {
+				saved_ctrl_reg &= (uchar)(~CC_HALT);
+			}
+		} else {
+ ISR_REPORT_QDONE_FATAL_ERROR:
+			if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
+				while (((status =
+					 AscIsrQDone(asc_dvc)) & 0x01) != 0) {
+				}
+			} else {
+				do {
+					if ((status =
+					     AscIsrQDone(asc_dvc)) == 1) {
+						break;
+					}
+				} while (status == 0x11);
+			}
+			if ((status & 0x80) != 0)
+				int_pending = ERR;
+		}
+	}
+	AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
+	AscSetChipLramAddr(iop_base, saved_ram_addr);
+	AscSetChipControl(iop_base, saved_ctrl_reg);
+	asc_dvc->is_in_int = FALSE;
+	return (int_pending);
 }
 
 /* Microcode buffer is kept after initialization for error recovery. */
-STATIC uchar _asc_mcode_buf[] =
-{
-  0x01,  0x03,  0x01,  0x19,  0x0F,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0xC3,  0x12,  0x0D,  0x05,  0x01,  0x00,  0x00,  0x00,  0x00,  0xFF,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x00,  0xFF,  0x80,  0xFF,  0xFF,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
-  0x00,  0x00,  0x00,  0x23,  0x00,  0x00,  0x00,  0x00,  0x00,  0x07,  0x00,  0xFF,  0x00,  0x00,  0x00,  0x00,
-  0xFF,  0xFF,  0xFF,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0xE4,  0x88,  0x00,  0x00,  0x00,  0x00,
-  0x80,  0x73,  0x48,  0x04,  0x36,  0x00,  0x00,  0xA2,  0xC2,  0x00,  0x80,  0x73,  0x03,  0x23,  0x36,  0x40,
-  0xB6,  0x00,  0x36,  0x00,  0x05,  0xD6,  0x0C,  0xD2,  0x12,  0xDA,  0x00,  0xA2,  0xC2,  0x00,  0x92,  0x80,
-  0x1E,  0x98,  0x50,  0x00,  0xF5,  0x00,  0x48,  0x98,  0xDF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,
-  0x4F,  0x00,  0xF5,  0x00,  0x48,  0x98,  0xEF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,  0x80,  0x62,
-  0x92,  0x80,  0x00,  0x46,  0x15,  0xEE,  0x13,  0xEA,  0x02,  0x01,  0x09,  0xD8,  0xCD,  0x04,  0x4D,  0x00,
-  0x00,  0xA3,  0xD6,  0x00,  0xA6,  0x97,  0x7F,  0x23,  0x04,  0x61,  0x84,  0x01,  0xE6,  0x84,  0xD2,  0xC1,
-  0x80,  0x73,  0xCD,  0x04,  0x4D,  0x00,  0x00,  0xA3,  0xDA,  0x01,  0xA6,  0x97,  0xC6,  0x81,  0xC2,  0x88,
-  0x80,  0x73,  0x80,  0x77,  0x00,  0x01,  0x01,  0xA1,  0xFE,  0x00,  0x4F,  0x00,  0x84,  0x97,  0x07,  0xA6,
-  0x08,  0x01,  0x00,  0x33,  0x03,  0x00,  0xC2,  0x88,  0x03,  0x03,  0x01,  0xDE,  0xC2,  0x88,  0xCE,  0x00,
-  0x69,  0x60,  0xCE,  0x00,  0x02,  0x03,  0x4A,  0x60,  0x00,  0xA2,  0x78,  0x01,  0x80,  0x63,  0x07,  0xA6,
-  0x24,  0x01,  0x78,  0x81,  0x03,  0x03,  0x80,  0x63,  0xE2,  0x00,  0x07,  0xA6,  0x34,  0x01,  0x00,  0x33,
-  0x04,  0x00,  0xC2,  0x88,  0x03,  0x07,  0x02,  0x01,  0x04,  0xCA,  0x0D,  0x23,  0x68,  0x98,  0x4D,  0x04,
-  0x04,  0x85,  0x05,  0xD8,  0x0D,  0x23,  0x68,  0x98,  0xCD,  0x04,  0x15,  0x23,  0xF8,  0x88,  0xFB,  0x23,
-  0x02,  0x61,  0x82,  0x01,  0x80,  0x63,  0x02,  0x03,  0x06,  0xA3,  0x62,  0x01,  0x00,  0x33,  0x0A,  0x00,
-  0xC2,  0x88,  0x4E,  0x00,  0x07,  0xA3,  0x6E,  0x01,  0x00,  0x33,  0x0B,  0x00,  0xC2,  0x88,  0xCD,  0x04,
-  0x36,  0x2D,  0x00,  0x33,  0x1A,  0x00,  0xC2,  0x88,  0x50,  0x04,  0x88,  0x81,  0x06,  0xAB,  0x82,  0x01,
-  0x88,  0x81,  0x4E,  0x00,  0x07,  0xA3,  0x92,  0x01,  0x50,  0x00,  0x00,  0xA3,  0x3C,  0x01,  0x00,  0x05,
-  0x7C,  0x81,  0x46,  0x97,  0x02,  0x01,  0x05,  0xC6,  0x04,  0x23,  0xA0,  0x01,  0x15,  0x23,  0xA1,  0x01,
-  0xBE,  0x81,  0xFD,  0x23,  0x02,  0x61,  0x82,  0x01,  0x0A,  0xDA,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,
-  0xB4,  0x01,  0x80,  0x63,  0xCD,  0x04,  0x36,  0x2D,  0x00,  0x33,  0x1B,  0x00,  0xC2,  0x88,  0x06,  0x23,
-  0x68,  0x98,  0xCD,  0x04,  0xE6,  0x84,  0x06,  0x01,  0x00,  0xA2,  0xD4,  0x01,  0x57,  0x60,  0x00,  0xA0,
-  0xDA,  0x01,  0xE6,  0x84,  0x80,  0x23,  0xA0,  0x01,  0xE6,  0x84,  0x80,  0x73,  0x4B,  0x00,  0x06,  0x61,
-  0x00,  0xA2,  0x00,  0x02,  0x04,  0x01,  0x0C,  0xDE,  0x02,  0x01,  0x03,  0xCC,  0x4F,  0x00,  0x84,  0x97,
-  0xFC,  0x81,  0x08,  0x23,  0x02,  0x41,  0x82,  0x01,  0x4F,  0x00,  0x62,  0x97,  0x48,  0x04,  0x84,  0x80,
-  0xF0,  0x97,  0x00,  0x46,  0x56,  0x00,  0x03,  0xC0,  0x01,  0x23,  0xE8,  0x00,  0x81,  0x73,  0x06,  0x29,
-  0x03,  0x42,  0x06,  0xE2,  0x03,  0xEE,  0x6B,  0xEB,  0x11,  0x23,  0xF8,  0x88,  0x04,  0x98,  0xF0,  0x80,
-  0x80,  0x73,  0x80,  0x77,  0x07,  0xA4,  0x2A,  0x02,  0x7C,  0x95,  0x06,  0xA6,  0x34,  0x02,  0x03,  0xA6,
-  0x4C,  0x04,  0x46,  0x82,  0x04,  0x01,  0x03,  0xD8,  0xB4,  0x98,  0x6A,  0x96,  0x46,  0x82,  0xFE,  0x95,
-  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0xB6,  0x2D,  0x02,  0xA6,  0x6C,  0x02,  0x07,  0xA6,  0x5A,  0x02,
-  0x06,  0xA6,  0x5E,  0x02,  0x03,  0xA6,  0x62,  0x02,  0xC2,  0x88,  0x7C,  0x95,  0x48,  0x82,  0x60,  0x96,
-  0x48,  0x82,  0x04,  0x23,  0xA0,  0x01,  0x14,  0x23,  0xA1,  0x01,  0x3C,  0x84,  0x04,  0x01,  0x0C,  0xDC,
-  0xE0,  0x23,  0x25,  0x61,  0xEF,  0x00,  0x14,  0x01,  0x4F,  0x04,  0xA8,  0x01,  0x6F,  0x00,  0xA5,  0x01,
-  0x03,  0x23,  0xA4,  0x01,  0x06,  0x23,  0x9C,  0x01,  0x24,  0x2B,  0x1C,  0x01,  0x02,  0xA6,  0xAA,  0x02,
-  0x07,  0xA6,  0x5A,  0x02,  0x06,  0xA6,  0x5E,  0x02,  0x03,  0xA6,  0x20,  0x04,  0x01,  0xA6,  0xB4,  0x02,
-  0x00,  0xA6,  0xB4,  0x02,  0x00,  0x33,  0x12,  0x00,  0xC2,  0x88,  0x00,  0x0E,  0x80,  0x63,  0x00,  0x43,
-  0x00,  0xA0,  0x8C,  0x02,  0x4D,  0x04,  0x04,  0x01,  0x0B,  0xDC,  0xE7,  0x23,  0x04,  0x61,  0x84,  0x01,
-  0x10,  0x31,  0x12,  0x35,  0x14,  0x01,  0xEC,  0x00,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0xEA,  0x82,
-  0x18,  0x23,  0x04,  0x61,  0x18,  0xA0,  0xE2,  0x02,  0x04,  0x01,  0xA2,  0xC8,  0x00,  0x33,  0x1F,  0x00,
-  0xC2,  0x88,  0x08,  0x31,  0x0A,  0x35,  0x0C,  0x39,  0x0E,  0x3D,  0x7E,  0x98,  0xB6,  0x2D,  0x01,  0xA6,
-  0x14,  0x03,  0x00,  0xA6,  0x14,  0x03,  0x07,  0xA6,  0x0C,  0x03,  0x06,  0xA6,  0x10,  0x03,  0x03,  0xA6,
-  0x20,  0x04,  0x02,  0xA6,  0x6C,  0x02,  0x00,  0x33,  0x33,  0x00,  0xC2,  0x88,  0x7C,  0x95,  0xEE,  0x82,
-  0x60,  0x96,  0xEE,  0x82,  0x82,  0x98,  0x80,  0x42,  0x7E,  0x98,  0x64,  0xE4,  0x04,  0x01,  0x2D,  0xC8,
-  0x31,  0x05,  0x07,  0x01,  0x00,  0xA2,  0x54,  0x03,  0x00,  0x43,  0x87,  0x01,  0x05,  0x05,  0x86,  0x98,
-  0x7E,  0x98,  0x00,  0xA6,  0x16,  0x03,  0x07,  0xA6,  0x4C,  0x03,  0x03,  0xA6,  0x3C,  0x04,  0x06,  0xA6,
-  0x50,  0x03,  0x01,  0xA6,  0x16,  0x03,  0x00,  0x33,  0x25,  0x00,  0xC2,  0x88,  0x7C,  0x95,  0x32,  0x83,
-  0x60,  0x96,  0x32,  0x83,  0x04,  0x01,  0x10,  0xCE,  0x07,  0xC8,  0x05,  0x05,  0xEB,  0x04,  0x00,  0x33,
-  0x00,  0x20,  0xC0,  0x20,  0x81,  0x62,  0x72,  0x83,  0x00,  0x01,  0x05,  0x05,  0xFF,  0xA2,  0x7A,  0x03,
-  0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,  0x2E,  0x83,  0x05,  0x05,  0x15,  0x01,  0x00,  0xA2,  0x9A,  0x03,
-  0xEC,  0x00,  0x6E,  0x00,  0x95,  0x01,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0x01,  0xA6,  0x96,  0x03,
-  0x00,  0xA6,  0x96,  0x03,  0x10,  0x84,  0x80,  0x42,  0x7E,  0x98,  0x01,  0xA6,  0xA4,  0x03,  0x00,  0xA6,
-  0xBC,  0x03,  0x10,  0x84,  0xA8,  0x98,  0x80,  0x42,  0x01,  0xA6,  0xA4,  0x03,  0x07,  0xA6,  0xB2,  0x03,
-  0xD4,  0x83,  0x7C,  0x95,  0xA8,  0x83,  0x00,  0x33,  0x2F,  0x00,  0xC2,  0x88,  0xA8,  0x98,  0x80,  0x42,
-  0x00,  0xA6,  0xBC,  0x03,  0x07,  0xA6,  0xCA,  0x03,  0xD4,  0x83,  0x7C,  0x95,  0xC0,  0x83,  0x00,  0x33,
-  0x26,  0x00,  0xC2,  0x88,  0x38,  0x2B,  0x80,  0x32,  0x80,  0x36,  0x04,  0x23,  0xA0,  0x01,  0x12,  0x23,
-  0xA1,  0x01,  0x10,  0x84,  0x07,  0xF0,  0x06,  0xA4,  0xF4,  0x03,  0x80,  0x6B,  0x80,  0x67,  0x05,  0x23,
-  0x83,  0x03,  0x80,  0x63,  0x03,  0xA6,  0x0E,  0x04,  0x07,  0xA6,  0x06,  0x04,  0x06,  0xA6,  0x0A,  0x04,
-  0x00,  0x33,  0x17,  0x00,  0xC2,  0x88,  0x7C,  0x95,  0xF4,  0x83,  0x60,  0x96,  0xF4,  0x83,  0x20,  0x84,
-  0x07,  0xF0,  0x06,  0xA4,  0x20,  0x04,  0x80,  0x6B,  0x80,  0x67,  0x05,  0x23,  0x83,  0x03,  0x80,  0x63,
-  0xB6,  0x2D,  0x03,  0xA6,  0x3C,  0x04,  0x07,  0xA6,  0x34,  0x04,  0x06,  0xA6,  0x38,  0x04,  0x00,  0x33,
-  0x30,  0x00,  0xC2,  0x88,  0x7C,  0x95,  0x20,  0x84,  0x60,  0x96,  0x20,  0x84,  0x1D,  0x01,  0x06,  0xCC,
-  0x00,  0x33,  0x00,  0x84,  0xC0,  0x20,  0x00,  0x23,  0xEA,  0x00,  0x81,  0x62,  0xA2,  0x0D,  0x80,  0x63,
-  0x07,  0xA6,  0x5A,  0x04,  0x00,  0x33,  0x18,  0x00,  0xC2,  0x88,  0x03,  0x03,  0x80,  0x63,  0xA3,  0x01,
-  0x07,  0xA4,  0x64,  0x04,  0x23,  0x01,  0x00,  0xA2,  0x86,  0x04,  0x0A,  0xA0,  0x76,  0x04,  0xE0,  0x00,
-  0x00,  0x33,  0x1D,  0x00,  0xC2,  0x88,  0x0B,  0xA0,  0x82,  0x04,  0xE0,  0x00,  0x00,  0x33,  0x1E,  0x00,
-  0xC2,  0x88,  0x42,  0x23,  0xF8,  0x88,  0x00,  0x23,  0x22,  0xA3,  0xE6,  0x04,  0x08,  0x23,  0x22,  0xA3,
-  0xA2,  0x04,  0x28,  0x23,  0x22,  0xA3,  0xAE,  0x04,  0x02,  0x23,  0x22,  0xA3,  0xC4,  0x04,  0x42,  0x23,
-  0xF8,  0x88,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,  0xAE,  0x04,  0x45,  0x23,  0xF8,  0x88,  0x04,  0x98,
-  0x00,  0xA2,  0xC0,  0x04,  0xB4,  0x98,  0x00,  0x33,  0x00,  0x82,  0xC0,  0x20,  0x81,  0x62,  0xE8,  0x81,
-  0x47,  0x23,  0xF8,  0x88,  0x04,  0x01,  0x0B,  0xDE,  0x04,  0x98,  0xB4,  0x98,  0x00,  0x33,  0x00,  0x81,
-  0xC0,  0x20,  0x81,  0x62,  0x14,  0x01,  0x00,  0xA0,  0x00,  0x02,  0x43,  0x23,  0xF8,  0x88,  0x04,  0x23,
-  0xA0,  0x01,  0x44,  0x23,  0xA1,  0x01,  0x80,  0x73,  0x4D,  0x00,  0x03,  0xA3,  0xF4,  0x04,  0x00,  0x33,
-  0x27,  0x00,  0xC2,  0x88,  0x04,  0x01,  0x04,  0xDC,  0x02,  0x23,  0xA2,  0x01,  0x04,  0x23,  0xA0,  0x01,
-  0x04,  0x98,  0x26,  0x95,  0x4B,  0x00,  0xF6,  0x00,  0x4F,  0x04,  0x4F,  0x00,  0x00,  0xA3,  0x22,  0x05,
-  0x00,  0x05,  0x76,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x1C,  0x05,  0x0A,  0x85,  0x46,  0x97,  0xCD,  0x04,
-  0x24,  0x85,  0x48,  0x04,  0x84,  0x80,  0x02,  0x01,  0x03,  0xDA,  0x80,  0x23,  0x82,  0x01,  0x34,  0x85,
-  0x02,  0x23,  0xA0,  0x01,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x40,  0x05,  0x1D,  0x01,  0x04,  0xD6,
-  0xFF,  0x23,  0x86,  0x41,  0x4B,  0x60,  0xCB,  0x00,  0xFF,  0x23,  0x80,  0x01,  0x49,  0x00,  0x81,  0x01,
-  0x04,  0x01,  0x02,  0xC8,  0x30,  0x01,  0x80,  0x01,  0xF7,  0x04,  0x03,  0x01,  0x49,  0x04,  0x80,  0x01,
-  0xC9,  0x00,  0x00,  0x05,  0x00,  0x01,  0xFF,  0xA0,  0x60,  0x05,  0x77,  0x04,  0x01,  0x23,  0xEA,  0x00,
-  0x5D,  0x00,  0xFE,  0xC7,  0x00,  0x62,  0x00,  0x23,  0xEA,  0x00,  0x00,  0x63,  0x07,  0xA4,  0xF8,  0x05,
-  0x03,  0x03,  0x02,  0xA0,  0x8E,  0x05,  0xF4,  0x85,  0x00,  0x33,  0x2D,  0x00,  0xC2,  0x88,  0x04,  0xA0,
-  0xB8,  0x05,  0x80,  0x63,  0x00,  0x23,  0xDF,  0x00,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,  0xA4,  0x05,
-  0x1D,  0x01,  0x06,  0xD6,  0x02,  0x23,  0x02,  0x41,  0x82,  0x01,  0x50,  0x00,  0x62,  0x97,  0x04,  0x85,
-  0x04,  0x23,  0x02,  0x41,  0x82,  0x01,  0x04,  0x85,  0x08,  0xA0,  0xBE,  0x05,  0xF4,  0x85,  0x03,  0xA0,
-  0xC4,  0x05,  0xF4,  0x85,  0x01,  0xA0,  0xCE,  0x05,  0x88,  0x00,  0x80,  0x63,  0xCC,  0x86,  0x07,  0xA0,
-  0xEE,  0x05,  0x5F,  0x00,  0x00,  0x2B,  0xDF,  0x08,  0x00,  0xA2,  0xE6,  0x05,  0x80,  0x67,  0x80,  0x63,
-  0x01,  0xA2,  0x7A,  0x06,  0x7C,  0x85,  0x06,  0x23,  0x68,  0x98,  0x48,  0x23,  0xF8,  0x88,  0x07,  0x23,
-  0x80,  0x00,  0x06,  0x87,  0x80,  0x63,  0x7C,  0x85,  0x00,  0x23,  0xDF,  0x00,  0x00,  0x63,  0x4A,  0x00,
-  0x06,  0x61,  0x00,  0xA2,  0x36,  0x06,  0x1D,  0x01,  0x16,  0xD4,  0xC0,  0x23,  0x07,  0x41,  0x83,  0x03,
-  0x80,  0x63,  0x06,  0xA6,  0x1C,  0x06,  0x00,  0x33,  0x37,  0x00,  0xC2,  0x88,  0x1D,  0x01,  0x01,  0xD6,
-  0x20,  0x23,  0x63,  0x60,  0x83,  0x03,  0x80,  0x63,  0x02,  0x23,  0xDF,  0x00,  0x07,  0xA6,  0x7C,  0x05,
-  0xEF,  0x04,  0x6F,  0x00,  0x00,  0x63,  0x4B,  0x00,  0x06,  0x41,  0xCB,  0x00,  0x52,  0x00,  0x06,  0x61,
-  0x00,  0xA2,  0x4E,  0x06,  0x1D,  0x01,  0x03,  0xCA,  0xC0,  0x23,  0x07,  0x41,  0x00,  0x63,  0x1D,  0x01,
-  0x04,  0xCC,  0x00,  0x33,  0x00,  0x83,  0xC0,  0x20,  0x81,  0x62,  0x80,  0x23,  0x07,  0x41,  0x00,  0x63,
-  0x80,  0x67,  0x08,  0x23,  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,  0x01,  0x23,  0xDF,  0x00,  0x06,  0xA6,
-  0x84,  0x06,  0x07,  0xA6,  0x7C,  0x05,  0x80,  0x67,  0x80,  0x63,  0x00,  0x33,  0x00,  0x40,  0xC0,  0x20,
-  0x81,  0x62,  0x00,  0x63,  0x00,  0x00,  0xFE,  0x95,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,  0x94,  0x06,
-  0x07,  0xA6,  0x7C,  0x05,  0x00,  0x00,  0x01,  0xA0,  0x14,  0x07,  0x00,  0x2B,  0x40,  0x0E,  0x80,  0x63,
-  0x01,  0x00,  0x06,  0xA6,  0xAA,  0x06,  0x07,  0xA6,  0x7C,  0x05,  0x40,  0x0E,  0x80,  0x63,  0x00,  0x43,
-  0x00,  0xA0,  0xA2,  0x06,  0x06,  0xA6,  0xBC,  0x06,  0x07,  0xA6,  0x7C,  0x05,  0x80,  0x67,  0x40,  0x0E,
-  0x80,  0x63,  0x07,  0xA6,  0x7C,  0x05,  0x00,  0x23,  0xDF,  0x00,  0x00,  0x63,  0x07,  0xA6,  0xD6,  0x06,
-  0x00,  0x33,  0x2A,  0x00,  0xC2,  0x88,  0x03,  0x03,  0x80,  0x63,  0x89,  0x00,  0x0A,  0x2B,  0x07,  0xA6,
-  0xE8,  0x06,  0x00,  0x33,  0x29,  0x00,  0xC2,  0x88,  0x00,  0x43,  0x00,  0xA2,  0xF4,  0x06,  0xC0,  0x0E,
-  0x80,  0x63,  0xDE,  0x86,  0xC0,  0x0E,  0x00,  0x33,  0x00,  0x80,  0xC0,  0x20,  0x81,  0x62,  0x04,  0x01,
-  0x02,  0xDA,  0x80,  0x63,  0x7C,  0x85,  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,  0x8C,  0x06,  0x00,  0x33,
-  0x2C,  0x00,  0xC2,  0x88,  0x0C,  0xA2,  0x2E,  0x07,  0xFE,  0x95,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,
-  0x2C,  0x07,  0x07,  0xA6,  0x7C,  0x05,  0x00,  0x33,  0x3D,  0x00,  0xC2,  0x88,  0x00,  0x00,  0x80,  0x67,
-  0x83,  0x03,  0x80,  0x63,  0x0C,  0xA0,  0x44,  0x07,  0x07,  0xA6,  0x7C,  0x05,  0xBF,  0x23,  0x04,  0x61,
-  0x84,  0x01,  0xE6,  0x84,  0x00,  0x63,  0xF0,  0x04,  0x01,  0x01,  0xF1,  0x00,  0x00,  0x01,  0xF2,  0x00,
-  0x01,  0x05,  0x80,  0x01,  0x72,  0x04,  0x71,  0x00,  0x81,  0x01,  0x70,  0x04,  0x80,  0x05,  0x81,  0x05,
-  0x00,  0x63,  0xF0,  0x04,  0xF2,  0x00,  0x72,  0x04,  0x01,  0x01,  0xF1,  0x00,  0x70,  0x00,  0x81,  0x01,
-  0x70,  0x04,  0x71,  0x00,  0x81,  0x01,  0x72,  0x00,  0x80,  0x01,  0x71,  0x04,  0x70,  0x00,  0x80,  0x01,
-  0x70,  0x04,  0x00,  0x63,  0xF0,  0x04,  0xF2,  0x00,  0x72,  0x04,  0x00,  0x01,  0xF1,  0x00,  0x70,  0x00,
-  0x80,  0x01,  0x70,  0x04,  0x71,  0x00,  0x80,  0x01,  0x72,  0x00,  0x81,  0x01,  0x71,  0x04,  0x70,  0x00,
-  0x81,  0x01,  0x70,  0x04,  0x00,  0x63,  0x00,  0x23,  0xB3,  0x01,  0x83,  0x05,  0xA3,  0x01,  0xA2,  0x01,
-  0xA1,  0x01,  0x01,  0x23,  0xA0,  0x01,  0x00,  0x01,  0xC8,  0x00,  0x03,  0xA1,  0xC4,  0x07,  0x00,  0x33,
-  0x07,  0x00,  0xC2,  0x88,  0x80,  0x05,  0x81,  0x05,  0x04,  0x01,  0x11,  0xC8,  0x48,  0x00,  0xB0,  0x01,
-  0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,  0x05,  0x01,  0x48,  0x04,  0x00,  0x43,  0x00,  0xA2,  0xE4,  0x07,
-  0x00,  0x05,  0xDA,  0x87,  0x00,  0x01,  0xC8,  0x00,  0xFF,  0x23,  0x80,  0x01,  0x05,  0x05,  0x00,  0x63,
-  0xF7,  0x04,  0x1A,  0x09,  0xF6,  0x08,  0x6E,  0x04,  0x00,  0x02,  0x80,  0x43,  0x76,  0x08,  0x80,  0x02,
-  0x77,  0x04,  0x00,  0x63,  0xF7,  0x04,  0x1A,  0x09,  0xF6,  0x08,  0x6E,  0x04,  0x00,  0x02,  0x00,  0xA0,
-  0x14,  0x08,  0x16,  0x88,  0x00,  0x43,  0x76,  0x08,  0x80,  0x02,  0x77,  0x04,  0x00,  0x63,  0xF3,  0x04,
-  0x00,  0x23,  0xF4,  0x00,  0x74,  0x00,  0x80,  0x43,  0xF4,  0x00,  0xCF,  0x40,  0x00,  0xA2,  0x44,  0x08,
-  0x74,  0x04,  0x02,  0x01,  0xF7,  0xC9,  0xF6,  0xD9,  0x00,  0x01,  0x01,  0xA1,  0x24,  0x08,  0x04,  0x98,
-  0x26,  0x95,  0x24,  0x88,  0x73,  0x04,  0x00,  0x63,  0xF3,  0x04,  0x75,  0x04,  0x5A,  0x88,  0x02,  0x01,
-  0x04,  0xD8,  0x46,  0x97,  0x04,  0x98,  0x26,  0x95,  0x4A,  0x88,  0x75,  0x00,  0x00,  0xA3,  0x64,  0x08,
-  0x00,  0x05,  0x4E,  0x88,  0x73,  0x04,  0x00,  0x63,  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,  0x76,  0x08,
-  0x00,  0x33,  0x3E,  0x00,  0xC2,  0x88,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,  0x38,  0x2B,
-  0x9C,  0x88,  0x38,  0x2B,  0x92,  0x88,  0x32,  0x09,  0x31,  0x05,  0x92,  0x98,  0x05,  0x05,  0xB2,  0x09,
-  0x00,  0x63,  0x00,  0x32,  0x00,  0x36,  0x00,  0x3A,  0x00,  0x3E,  0x00,  0x63,  0x80,  0x32,  0x80,  0x36,
-  0x80,  0x3A,  0x80,  0x3E,  0xB4,  0x3D,  0x00,  0x63,  0x38,  0x2B,  0x40,  0x32,  0x40,  0x36,  0x40,  0x3A,
-  0x40,  0x3E,  0x00,  0x63,  0x5A,  0x20,  0xC9,  0x40,  0x00,  0xA0,  0xB4,  0x08,  0x5D,  0x00,  0xFE,  0xC3,
-  0x00,  0x63,  0x80,  0x73,  0xE6,  0x20,  0x02,  0x23,  0xE8,  0x00,  0x82,  0x73,  0xFF,  0xFD,  0x80,  0x73,
-  0x13,  0x23,  0xF8,  0x88,  0x66,  0x20,  0xC0,  0x20,  0x04,  0x23,  0xA0,  0x01,  0xA1,  0x23,  0xA1,  0x01,
-  0x81,  0x62,  0xE2,  0x88,  0x80,  0x73,  0x80,  0x77,  0x68,  0x00,  0x00,  0xA2,  0x80,  0x00,  0x03,  0xC2,
-  0xF1,  0xC7,  0x41,  0x23,  0xF8,  0x88,  0x11,  0x23,  0xA1,  0x01,  0x04,  0x23,  0xA0,  0x01,  0xE6,  0x84,
+static uchar _asc_mcode_buf[] = {
+	0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xC3, 0x12, 0x0D, 0x05, 0x01, 0x00, 0x00, 0x00,
+	0x00, 0xFF, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF,
+	0x00, 0x00, 0x00, 0x00,
+	0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88,
+	0x00, 0x00, 0x00, 0x00,
+	0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73,
+	0x03, 0x23, 0x36, 0x40,
+	0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2,
+	0xC2, 0x00, 0x92, 0x80,
+	0x1E, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xDF, 0x23, 0x36, 0x60,
+	0xB6, 0x00, 0x92, 0x80,
+	0x4F, 0x00, 0xF5, 0x00, 0x48, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00,
+	0x92, 0x80, 0x80, 0x62,
+	0x92, 0x80, 0x00, 0x46, 0x15, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8,
+	0xCD, 0x04, 0x4D, 0x00,
+	0x00, 0xA3, 0xD6, 0x00, 0xA6, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01,
+	0xE6, 0x84, 0xD2, 0xC1,
+	0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x01, 0xA6, 0x97,
+	0xC6, 0x81, 0xC2, 0x88,
+	0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0xFE, 0x00, 0x4F, 0x00,
+	0x84, 0x97, 0x07, 0xA6,
+	0x08, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x01, 0xDE,
+	0xC2, 0x88, 0xCE, 0x00,
+	0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x78, 0x01,
+	0x80, 0x63, 0x07, 0xA6,
+	0x24, 0x01, 0x78, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6,
+	0x34, 0x01, 0x00, 0x33,
+	0x04, 0x00, 0xC2, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23,
+	0x68, 0x98, 0x4D, 0x04,
+	0x04, 0x85, 0x05, 0xD8, 0x0D, 0x23, 0x68, 0x98, 0xCD, 0x04, 0x15, 0x23,
+	0xF8, 0x88, 0xFB, 0x23,
+	0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x62, 0x01,
+	0x00, 0x33, 0x0A, 0x00,
+	0xC2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0B, 0x00,
+	0xC2, 0x88, 0xCD, 0x04,
+	0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x88, 0x81,
+	0x06, 0xAB, 0x82, 0x01,
+	0x88, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x92, 0x01, 0x50, 0x00, 0x00, 0xA3,
+	0x3C, 0x01, 0x00, 0x05,
+	0x7C, 0x81, 0x46, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01,
+	0x15, 0x23, 0xA1, 0x01,
+	0xBE, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00,
+	0x06, 0x61, 0x00, 0xA0,
+	0xB4, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00,
+	0xC2, 0x88, 0x06, 0x23,
+	0x68, 0x98, 0xCD, 0x04, 0xE6, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xD4, 0x01,
+	0x57, 0x60, 0x00, 0xA0,
+	0xDA, 0x01, 0xE6, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xE6, 0x84, 0x80, 0x73,
+	0x4B, 0x00, 0x06, 0x61,
+	0x00, 0xA2, 0x00, 0x02, 0x04, 0x01, 0x0C, 0xDE, 0x02, 0x01, 0x03, 0xCC,
+	0x4F, 0x00, 0x84, 0x97,
+	0xFC, 0x81, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x62, 0x97,
+	0x48, 0x04, 0x84, 0x80,
+	0xF0, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00,
+	0x81, 0x73, 0x06, 0x29,
+	0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x6B, 0xEB, 0x11, 0x23, 0xF8, 0x88,
+	0x04, 0x98, 0xF0, 0x80,
+	0x80, 0x73, 0x80, 0x77, 0x07, 0xA4, 0x2A, 0x02, 0x7C, 0x95, 0x06, 0xA6,
+	0x34, 0x02, 0x03, 0xA6,
+	0x4C, 0x04, 0x46, 0x82, 0x04, 0x01, 0x03, 0xD8, 0xB4, 0x98, 0x6A, 0x96,
+	0x46, 0x82, 0xFE, 0x95,
+	0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x6C, 0x02,
+	0x07, 0xA6, 0x5A, 0x02,
+	0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x62, 0x02, 0xC2, 0x88, 0x7C, 0x95,
+	0x48, 0x82, 0x60, 0x96,
+	0x48, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x3C, 0x84,
+	0x04, 0x01, 0x0C, 0xDC,
+	0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01,
+	0x6F, 0x00, 0xA5, 0x01,
+	0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01,
+	0x02, 0xA6, 0xAA, 0x02,
+	0x07, 0xA6, 0x5A, 0x02, 0x06, 0xA6, 0x5E, 0x02, 0x03, 0xA6, 0x20, 0x04,
+	0x01, 0xA6, 0xB4, 0x02,
+	0x00, 0xA6, 0xB4, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E,
+	0x80, 0x63, 0x00, 0x43,
+	0x00, 0xA0, 0x8C, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23,
+	0x04, 0x61, 0x84, 0x01,
+	0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F,
+	0x00, 0x00, 0xEA, 0x82,
+	0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0xA2, 0xC8,
+	0x00, 0x33, 0x1F, 0x00,
+	0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x7E, 0x98,
+	0xB6, 0x2D, 0x01, 0xA6,
+	0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6,
+	0x10, 0x03, 0x03, 0xA6,
+	0x20, 0x04, 0x02, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88,
+	0x7C, 0x95, 0xEE, 0x82,
+	0x60, 0x96, 0xEE, 0x82, 0x82, 0x98, 0x80, 0x42, 0x7E, 0x98, 0x64, 0xE4,
+	0x04, 0x01, 0x2D, 0xC8,
+	0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01,
+	0x05, 0x05, 0x86, 0x98,
+	0x7E, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6,
+	0x3C, 0x04, 0x06, 0xA6,
+	0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88,
+	0x7C, 0x95, 0x32, 0x83,
+	0x60, 0x96, 0x32, 0x83, 0x04, 0x01, 0x10, 0xCE, 0x07, 0xC8, 0x05, 0x05,
+	0xEB, 0x04, 0x00, 0x33,
+	0x00, 0x20, 0xC0, 0x20, 0x81, 0x62, 0x72, 0x83, 0x00, 0x01, 0x05, 0x05,
+	0xFF, 0xA2, 0x7A, 0x03,
+	0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, 0x05, 0x05, 0x15, 0x01,
+	0x00, 0xA2, 0x9A, 0x03,
+	0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00,
+	0x01, 0xA6, 0x96, 0x03,
+	0x00, 0xA6, 0x96, 0x03, 0x10, 0x84, 0x80, 0x42, 0x7E, 0x98, 0x01, 0xA6,
+	0xA4, 0x03, 0x00, 0xA6,
+	0xBC, 0x03, 0x10, 0x84, 0xA8, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA4, 0x03,
+	0x07, 0xA6, 0xB2, 0x03,
+	0xD4, 0x83, 0x7C, 0x95, 0xA8, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xC2, 0x88,
+	0xA8, 0x98, 0x80, 0x42,
+	0x00, 0xA6, 0xBC, 0x03, 0x07, 0xA6, 0xCA, 0x03, 0xD4, 0x83, 0x7C, 0x95,
+	0xC0, 0x83, 0x00, 0x33,
+	0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23,
+	0xA0, 0x01, 0x12, 0x23,
+	0xA1, 0x01, 0x10, 0x84, 0x07, 0xF0, 0x06, 0xA4, 0xF4, 0x03, 0x80, 0x6B,
+	0x80, 0x67, 0x05, 0x23,
+	0x83, 0x03, 0x80, 0x63, 0x03, 0xA6, 0x0E, 0x04, 0x07, 0xA6, 0x06, 0x04,
+	0x06, 0xA6, 0x0A, 0x04,
+	0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0xF4, 0x83, 0x60, 0x96,
+	0xF4, 0x83, 0x20, 0x84,
+	0x07, 0xF0, 0x06, 0xA4, 0x20, 0x04, 0x80, 0x6B, 0x80, 0x67, 0x05, 0x23,
+	0x83, 0x03, 0x80, 0x63,
+	0xB6, 0x2D, 0x03, 0xA6, 0x3C, 0x04, 0x07, 0xA6, 0x34, 0x04, 0x06, 0xA6,
+	0x38, 0x04, 0x00, 0x33,
+	0x30, 0x00, 0xC2, 0x88, 0x7C, 0x95, 0x20, 0x84, 0x60, 0x96, 0x20, 0x84,
+	0x1D, 0x01, 0x06, 0xCC,
+	0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62,
+	0xA2, 0x0D, 0x80, 0x63,
+	0x07, 0xA6, 0x5A, 0x04, 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03,
+	0x80, 0x63, 0xA3, 0x01,
+	0x07, 0xA4, 0x64, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x86, 0x04, 0x0A, 0xA0,
+	0x76, 0x04, 0xE0, 0x00,
+	0x00, 0x33, 0x1D, 0x00, 0xC2, 0x88, 0x0B, 0xA0, 0x82, 0x04, 0xE0, 0x00,
+	0x00, 0x33, 0x1E, 0x00,
+	0xC2, 0x88, 0x42, 0x23, 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xE6, 0x04,
+	0x08, 0x23, 0x22, 0xA3,
+	0xA2, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xAE, 0x04, 0x02, 0x23, 0x22, 0xA3,
+	0xC4, 0x04, 0x42, 0x23,
+	0xF8, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xAE, 0x04, 0x45, 0x23,
+	0xF8, 0x88, 0x04, 0x98,
+	0x00, 0xA2, 0xC0, 0x04, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20,
+	0x81, 0x62, 0xE8, 0x81,
+	0x47, 0x23, 0xF8, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0x04, 0x98, 0xB4, 0x98,
+	0x00, 0x33, 0x00, 0x81,
+	0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x00, 0x02, 0x43, 0x23,
+	0xF8, 0x88, 0x04, 0x23,
+	0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3,
+	0xF4, 0x04, 0x00, 0x33,
+	0x27, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01,
+	0x04, 0x23, 0xA0, 0x01,
+	0x04, 0x98, 0x26, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00,
+	0x00, 0xA3, 0x22, 0x05,
+	0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x1C, 0x05, 0x0A, 0x85,
+	0x46, 0x97, 0xCD, 0x04,
+	0x24, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23,
+	0x82, 0x01, 0x34, 0x85,
+	0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x40, 0x05,
+	0x1D, 0x01, 0x04, 0xD6,
+	0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01,
+	0x49, 0x00, 0x81, 0x01,
+	0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01,
+	0x49, 0x04, 0x80, 0x01,
+	0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x60, 0x05, 0x77, 0x04,
+	0x01, 0x23, 0xEA, 0x00,
+	0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63,
+	0x07, 0xA4, 0xF8, 0x05,
+	0x03, 0x03, 0x02, 0xA0, 0x8E, 0x05, 0xF4, 0x85, 0x00, 0x33, 0x2D, 0x00,
+	0xC2, 0x88, 0x04, 0xA0,
+	0xB8, 0x05, 0x80, 0x63, 0x00, 0x23, 0xDF, 0x00, 0x4A, 0x00, 0x06, 0x61,
+	0x00, 0xA2, 0xA4, 0x05,
+	0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00,
+	0x62, 0x97, 0x04, 0x85,
+	0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0x04, 0x85, 0x08, 0xA0, 0xBE, 0x05,
+	0xF4, 0x85, 0x03, 0xA0,
+	0xC4, 0x05, 0xF4, 0x85, 0x01, 0xA0, 0xCE, 0x05, 0x88, 0x00, 0x80, 0x63,
+	0xCC, 0x86, 0x07, 0xA0,
+	0xEE, 0x05, 0x5F, 0x00, 0x00, 0x2B, 0xDF, 0x08, 0x00, 0xA2, 0xE6, 0x05,
+	0x80, 0x67, 0x80, 0x63,
+	0x01, 0xA2, 0x7A, 0x06, 0x7C, 0x85, 0x06, 0x23, 0x68, 0x98, 0x48, 0x23,
+	0xF8, 0x88, 0x07, 0x23,
+	0x80, 0x00, 0x06, 0x87, 0x80, 0x63, 0x7C, 0x85, 0x00, 0x23, 0xDF, 0x00,
+	0x00, 0x63, 0x4A, 0x00,
+	0x06, 0x61, 0x00, 0xA2, 0x36, 0x06, 0x1D, 0x01, 0x16, 0xD4, 0xC0, 0x23,
+	0x07, 0x41, 0x83, 0x03,
+	0x80, 0x63, 0x06, 0xA6, 0x1C, 0x06, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88,
+	0x1D, 0x01, 0x01, 0xD6,
+	0x20, 0x23, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x02, 0x23, 0xDF, 0x00,
+	0x07, 0xA6, 0x7C, 0x05,
+	0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00,
+	0x52, 0x00, 0x06, 0x61,
+	0x00, 0xA2, 0x4E, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41,
+	0x00, 0x63, 0x1D, 0x01,
+	0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23,
+	0x07, 0x41, 0x00, 0x63,
+	0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x01, 0x23,
+	0xDF, 0x00, 0x06, 0xA6,
+	0x84, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x80, 0x67, 0x80, 0x63, 0x00, 0x33,
+	0x00, 0x40, 0xC0, 0x20,
+	0x81, 0x62, 0x00, 0x63, 0x00, 0x00, 0xFE, 0x95, 0x83, 0x03, 0x80, 0x63,
+	0x06, 0xA6, 0x94, 0x06,
+	0x07, 0xA6, 0x7C, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x14, 0x07, 0x00, 0x2B,
+	0x40, 0x0E, 0x80, 0x63,
+	0x01, 0x00, 0x06, 0xA6, 0xAA, 0x06, 0x07, 0xA6, 0x7C, 0x05, 0x40, 0x0E,
+	0x80, 0x63, 0x00, 0x43,
+	0x00, 0xA0, 0xA2, 0x06, 0x06, 0xA6, 0xBC, 0x06, 0x07, 0xA6, 0x7C, 0x05,
+	0x80, 0x67, 0x40, 0x0E,
+	0x80, 0x63, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x23, 0xDF, 0x00, 0x00, 0x63,
+	0x07, 0xA6, 0xD6, 0x06,
+	0x00, 0x33, 0x2A, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00,
+	0x0A, 0x2B, 0x07, 0xA6,
+	0xE8, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, 0x00, 0xA2,
+	0xF4, 0x06, 0xC0, 0x0E,
+	0x80, 0x63, 0xDE, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20,
+	0x81, 0x62, 0x04, 0x01,
+	0x02, 0xDA, 0x80, 0x63, 0x7C, 0x85, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
+	0x8C, 0x06, 0x00, 0x33,
+	0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x2E, 0x07, 0xFE, 0x95, 0x83, 0x03,
+	0x80, 0x63, 0x06, 0xA6,
+	0x2C, 0x07, 0x07, 0xA6, 0x7C, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88,
+	0x00, 0x00, 0x80, 0x67,
+	0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x44, 0x07, 0x07, 0xA6, 0x7C, 0x05,
+	0xBF, 0x23, 0x04, 0x61,
+	0x84, 0x01, 0xE6, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00,
+	0x00, 0x01, 0xF2, 0x00,
+	0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04,
+	0x80, 0x05, 0x81, 0x05,
+	0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00,
+	0x70, 0x00, 0x81, 0x01,
+	0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04,
+	0x70, 0x00, 0x80, 0x01,
+	0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01,
+	0xF1, 0x00, 0x70, 0x00,
+	0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01,
+	0x71, 0x04, 0x70, 0x00,
+	0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05,
+	0xA3, 0x01, 0xA2, 0x01,
+	0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1,
+	0xC4, 0x07, 0x00, 0x33,
+	0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8,
+	0x48, 0x00, 0xB0, 0x01,
+	0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43,
+	0x00, 0xA2, 0xE4, 0x07,
+	0x00, 0x05, 0xDA, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01,
+	0x05, 0x05, 0x00, 0x63,
+	0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43,
+	0x76, 0x08, 0x80, 0x02,
+	0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04,
+	0x00, 0x02, 0x00, 0xA0,
+	0x14, 0x08, 0x16, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04,
+	0x00, 0x63, 0xF3, 0x04,
+	0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40,
+	0x00, 0xA2, 0x44, 0x08,
+	0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1,
+	0x24, 0x08, 0x04, 0x98,
+	0x26, 0x95, 0x24, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04,
+	0x5A, 0x88, 0x02, 0x01,
+	0x04, 0xD8, 0x46, 0x97, 0x04, 0x98, 0x26, 0x95, 0x4A, 0x88, 0x75, 0x00,
+	0x00, 0xA3, 0x64, 0x08,
+	0x00, 0x05, 0x4E, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63,
+	0x06, 0xA6, 0x76, 0x08,
+	0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63,
+	0x00, 0x63, 0x38, 0x2B,
+	0x9C, 0x88, 0x38, 0x2B, 0x92, 0x88, 0x32, 0x09, 0x31, 0x05, 0x92, 0x98,
+	0x05, 0x05, 0xB2, 0x09,
+	0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63,
+	0x80, 0x32, 0x80, 0x36,
+	0x80, 0x3A, 0x80, 0x3E, 0xB4, 0x3D, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32,
+	0x40, 0x36, 0x40, 0x3A,
+	0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08,
+	0x5D, 0x00, 0xFE, 0xC3,
+	0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73,
+	0xFF, 0xFD, 0x80, 0x73,
+	0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01,
+	0xA1, 0x23, 0xA1, 0x01,
+	0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2,
+	0x80, 0x00, 0x03, 0xC2,
+	0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23,
+	0xA0, 0x01, 0xE6, 0x84,
 };
 
-STATIC ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
-STATIC ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
+static ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
+static ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
 
 #define ASC_SYN_OFFSET_ONE_DISABLE_LIST  16
-STATIC uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] =
-{
-    INQUIRY,
-    REQUEST_SENSE,
-    READ_CAPACITY,
-    READ_TOC,
-    MODE_SELECT,
-    MODE_SENSE,
-    MODE_SELECT_10,
-    MODE_SENSE_10,
-    0xFF,
-    0xFF,
-    0xFF,
-    0xFF,
-    0xFF,
-    0xFF,
-    0xFF,
-    0xFF
+static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = {
+	INQUIRY,
+	REQUEST_SENSE,
+	READ_CAPACITY,
+	READ_TOC,
+	MODE_SELECT,
+	MODE_SENSE,
+	MODE_SELECT_10,
+	MODE_SENSE_10,
+	0xFF,
+	0xFF,
+	0xFF,
+	0xFF,
+	0xFF,
+	0xFF,
+	0xFF,
+	0xFF
 };
 
-STATIC int
-AscExeScsiQueue(
-                   ASC_DVC_VAR *asc_dvc,
-                   ASC_SCSI_Q *scsiq
-)
+static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq)
 {
-    PortAddr            iop_base;
-    ulong               last_int_level;
-    int                 sta;
-    int                 n_q_required;
-    int                 disable_syn_offset_one_fix;
-    int                 i;
-    ASC_PADDR           addr;
-    ASC_EXE_CALLBACK    asc_exe_callback;
-    ushort              sg_entry_cnt = 0;
-    ushort              sg_entry_cnt_minus_one = 0;
-    uchar               target_ix;
-    uchar               tid_no;
-    uchar               sdtr_data;
-    uchar               extra_bytes;
-    uchar               scsi_cmd;
-    uchar               disable_cmd;
-    ASC_SG_HEAD         *sg_head;
-    ASC_DCNT            data_cnt;
+	PortAddr iop_base;
+	ulong last_int_level;
+	int sta;
+	int n_q_required;
+	int disable_syn_offset_one_fix;
+	int i;
+	ASC_PADDR addr;
+	ASC_EXE_CALLBACK asc_exe_callback;
+	ushort sg_entry_cnt = 0;
+	ushort sg_entry_cnt_minus_one = 0;
+	uchar target_ix;
+	uchar tid_no;
+	uchar sdtr_data;
+	uchar extra_bytes;
+	uchar scsi_cmd;
+	uchar disable_cmd;
+	ASC_SG_HEAD *sg_head;
+	ASC_DCNT data_cnt;
 
-    iop_base = asc_dvc->iop_base;
-    sg_head = scsiq->sg_head;
-    asc_exe_callback = asc_dvc->exe_callback;
-    if (asc_dvc->err_code != 0)
-        return (ERR);
-    if (scsiq == (ASC_SCSI_Q *) 0L) {
-        AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
-        return (ERR);
-    }
-    scsiq->q1.q_no = 0;
-    if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
-        scsiq->q1.extra_bytes = 0;
-    }
-    sta = 0;
-    target_ix = scsiq->q2.target_ix;
-    tid_no = ASC_TIX_TO_TID(target_ix);
-    n_q_required = 1;
-    if (scsiq->cdbptr[0] == REQUEST_SENSE) {
-        if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
-            asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
-            sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
-            AscMsgOutSDTR(asc_dvc,
-                          asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) &
-                          (uchar) (asc_dvc->max_sdtr_index - 1)],
-                          (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
-            scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
-        }
-    }
-    last_int_level = DvcEnterCritical();
-    if (asc_dvc->in_critical_cnt != 0) {
-        DvcLeaveCritical(last_int_level);
-        AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
-        return (ERR);
-    }
-    asc_dvc->in_critical_cnt++;
-    if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
-        if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
-            asc_dvc->in_critical_cnt--;
-            DvcLeaveCritical(last_int_level);
-            return (ERR);
-        }
+	iop_base = asc_dvc->iop_base;
+	sg_head = scsiq->sg_head;
+	asc_exe_callback = asc_dvc->exe_callback;
+	if (asc_dvc->err_code != 0)
+		return (ERR);
+	if (scsiq == (ASC_SCSI_Q *)0L) {
+		AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
+		return (ERR);
+	}
+	scsiq->q1.q_no = 0;
+	if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
+		scsiq->q1.extra_bytes = 0;
+	}
+	sta = 0;
+	target_ix = scsiq->q2.target_ix;
+	tid_no = ASC_TIX_TO_TID(target_ix);
+	n_q_required = 1;
+	if (scsiq->cdbptr[0] == REQUEST_SENSE) {
+		if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
+			asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
+			sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
+			AscMsgOutSDTR(asc_dvc,
+				      asc_dvc->
+				      sdtr_period_tbl[(sdtr_data >> 4) &
+						      (uchar)(asc_dvc->
+							      max_sdtr_index -
+							      1)],
+				      (uchar)(sdtr_data & (uchar)
+					      ASC_SYN_MAX_OFFSET));
+			scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
+		}
+	}
+	last_int_level = DvcEnterCritical();
+	if (asc_dvc->in_critical_cnt != 0) {
+		DvcLeaveCritical(last_int_level);
+		AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
+		return (ERR);
+	}
+	asc_dvc->in_critical_cnt++;
+	if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
+		if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
+			asc_dvc->in_critical_cnt--;
+			DvcLeaveCritical(last_int_level);
+			return (ERR);
+		}
 #if !CC_VERY_LONG_SG_LIST
-        if (sg_entry_cnt > ASC_MAX_SG_LIST)
-        {
-            asc_dvc->in_critical_cnt--;
-            DvcLeaveCritical(last_int_level);
-            return(ERR);
-        }
+		if (sg_entry_cnt > ASC_MAX_SG_LIST) {
+			asc_dvc->in_critical_cnt--;
+			DvcLeaveCritical(last_int_level);
+			return (ERR);
+		}
 #endif /* !CC_VERY_LONG_SG_LIST */
-        if (sg_entry_cnt == 1) {
-            scsiq->q1.data_addr = (ADV_PADDR) sg_head->sg_list[0].addr;
-            scsiq->q1.data_cnt = (ADV_DCNT) sg_head->sg_list[0].bytes;
-            scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
-        }
-        sg_entry_cnt_minus_one = sg_entry_cnt - 1;
-    }
-    scsi_cmd = scsiq->cdbptr[0];
-    disable_syn_offset_one_fix = FALSE;
-    if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
-        !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
-        if (scsiq->q1.cntl & QC_SG_HEAD) {
-            data_cnt = 0;
-            for (i = 0; i < sg_entry_cnt; i++) {
-                data_cnt += (ADV_DCNT) le32_to_cpu(sg_head->sg_list[i].bytes);
-            }
-        } else {
-            data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
-        }
-        if (data_cnt != 0UL) {
-            if (data_cnt < 512UL) {
-                disable_syn_offset_one_fix = TRUE;
-            } else {
-                for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST; i++) {
-                    disable_cmd = _syn_offset_one_disable_cmd[i];
-                    if (disable_cmd == 0xFF) {
-                        break;
-                    }
-                    if (scsi_cmd == disable_cmd) {
-                        disable_syn_offset_one_fix = TRUE;
-                        break;
-                    }
-                }
-            }
-        }
-    }
-    if (disable_syn_offset_one_fix) {
-        scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
-        scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
-                               ASC_TAG_FLAG_DISABLE_DISCONNECT);
-    } else {
-        scsiq->q2.tag_code &= 0x27;
-    }
-    if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
-        if (asc_dvc->bug_fix_cntl) {
-            if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
-                if ((scsi_cmd == READ_6) ||
-                    (scsi_cmd == READ_10)) {
-                    addr =
-                        (ADV_PADDR) le32_to_cpu(
-                            sg_head->sg_list[sg_entry_cnt_minus_one].addr) +
-                        (ADV_DCNT) le32_to_cpu(
-                            sg_head->sg_list[sg_entry_cnt_minus_one].bytes);
-                    extra_bytes = (uchar) ((ushort) addr & 0x0003);
-                    if ((extra_bytes != 0) &&
-                        ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES)
-                         == 0)) {
-                        scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
-                        scsiq->q1.extra_bytes = extra_bytes;
-                        data_cnt = le32_to_cpu(
-                            sg_head->sg_list[sg_entry_cnt_minus_one].bytes);
-                        data_cnt -= (ASC_DCNT) extra_bytes;
-                        sg_head->sg_list[sg_entry_cnt_minus_one].bytes =
-                            cpu_to_le32(data_cnt);
-                    }
-                }
-            }
-        }
-        sg_head->entry_to_copy = sg_head->entry_cnt;
+		if (sg_entry_cnt == 1) {
+			scsiq->q1.data_addr =
+			    (ADV_PADDR)sg_head->sg_list[0].addr;
+			scsiq->q1.data_cnt =
+			    (ADV_DCNT)sg_head->sg_list[0].bytes;
+			scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
+		}
+		sg_entry_cnt_minus_one = sg_entry_cnt - 1;
+	}
+	scsi_cmd = scsiq->cdbptr[0];
+	disable_syn_offset_one_fix = FALSE;
+	if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
+	    !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
+		if (scsiq->q1.cntl & QC_SG_HEAD) {
+			data_cnt = 0;
+			for (i = 0; i < sg_entry_cnt; i++) {
+				data_cnt +=
+				    (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i].
+							  bytes);
+			}
+		} else {
+			data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
+		}
+		if (data_cnt != 0UL) {
+			if (data_cnt < 512UL) {
+				disable_syn_offset_one_fix = TRUE;
+			} else {
+				for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST;
+				     i++) {
+					disable_cmd =
+					    _syn_offset_one_disable_cmd[i];
+					if (disable_cmd == 0xFF) {
+						break;
+					}
+					if (scsi_cmd == disable_cmd) {
+						disable_syn_offset_one_fix =
+						    TRUE;
+						break;
+					}
+				}
+			}
+		}
+	}
+	if (disable_syn_offset_one_fix) {
+		scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
+		scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
+				       ASC_TAG_FLAG_DISABLE_DISCONNECT);
+	} else {
+		scsiq->q2.tag_code &= 0x27;
+	}
+	if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
+		if (asc_dvc->bug_fix_cntl) {
+			if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
+				if ((scsi_cmd == READ_6) ||
+				    (scsi_cmd == READ_10)) {
+					addr =
+					    (ADV_PADDR)le32_to_cpu(sg_head->
+								   sg_list
+								   [sg_entry_cnt_minus_one].
+								   addr) +
+					    (ADV_DCNT)le32_to_cpu(sg_head->
+								  sg_list
+								  [sg_entry_cnt_minus_one].
+								  bytes);
+					extra_bytes =
+					    (uchar)((ushort)addr & 0x0003);
+					if ((extra_bytes != 0)
+					    &&
+					    ((scsiq->q2.
+					      tag_code &
+					      ASC_TAG_FLAG_EXTRA_BYTES)
+					     == 0)) {
+						scsiq->q2.tag_code |=
+						    ASC_TAG_FLAG_EXTRA_BYTES;
+						scsiq->q1.extra_bytes =
+						    extra_bytes;
+						data_cnt =
+						    le32_to_cpu(sg_head->
+								sg_list
+								[sg_entry_cnt_minus_one].
+								bytes);
+						data_cnt -=
+						    (ASC_DCNT) extra_bytes;
+						sg_head->
+						    sg_list
+						    [sg_entry_cnt_minus_one].
+						    bytes =
+						    cpu_to_le32(data_cnt);
+					}
+				}
+			}
+		}
+		sg_head->entry_to_copy = sg_head->entry_cnt;
 #if CC_VERY_LONG_SG_LIST
-        /*
-         * Set the sg_entry_cnt to the maximum possible. The rest of
-         * the SG elements will be copied when the RISC completes the
-         * SG elements that fit and halts.
-         */
-        if (sg_entry_cnt > ASC_MAX_SG_LIST)
-        {
-             sg_entry_cnt = ASC_MAX_SG_LIST;
-        }
+		/*
+		 * Set the sg_entry_cnt to the maximum possible. The rest of
+		 * the SG elements will be copied when the RISC completes the
+		 * SG elements that fit and halts.
+		 */
+		if (sg_entry_cnt > ASC_MAX_SG_LIST) {
+			sg_entry_cnt = ASC_MAX_SG_LIST;
+		}
 #endif /* CC_VERY_LONG_SG_LIST */
-        n_q_required = AscSgListToQueue(sg_entry_cnt);
-        if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
-            (uint) n_q_required) || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
-            if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
-                                        n_q_required)) == 1) {
-                asc_dvc->in_critical_cnt--;
-                if (asc_exe_callback != 0) {
-                    (*asc_exe_callback) (asc_dvc, scsiq);
-                }
-                DvcLeaveCritical(last_int_level);
-                return (sta);
-            }
-        }
-    } else {
-        if (asc_dvc->bug_fix_cntl) {
-            if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
-                if ((scsi_cmd == READ_6) ||
-                    (scsi_cmd == READ_10)) {
-                    addr = le32_to_cpu(scsiq->q1.data_addr) +
-                        le32_to_cpu(scsiq->q1.data_cnt);
-                    extra_bytes = (uchar) ((ushort) addr & 0x0003);
-                    if ((extra_bytes != 0) &&
-                        ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES)
-                          == 0)) {
-                        data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
-                        if (((ushort) data_cnt & 0x01FF) == 0) {
-                            scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
-                            data_cnt -= (ASC_DCNT) extra_bytes;
-                            scsiq->q1.data_cnt = cpu_to_le32(data_cnt);
-                            scsiq->q1.extra_bytes = extra_bytes;
-                        }
-                    }
-                }
-            }
-        }
-        n_q_required = 1;
-        if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
-            ((scsiq->q1.cntl & QC_URGENT) != 0)) {
-            if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
-                                        n_q_required)) == 1) {
-                asc_dvc->in_critical_cnt--;
-                if (asc_exe_callback != 0) {
-                    (*asc_exe_callback) (asc_dvc, scsiq);
-                }
-                DvcLeaveCritical(last_int_level);
-                return (sta);
-            }
-        }
-    }
-    asc_dvc->in_critical_cnt--;
-    DvcLeaveCritical(last_int_level);
-    return (sta);
+		n_q_required = AscSgListToQueue(sg_entry_cnt);
+		if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
+		     (uint) n_q_required)
+		    || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
+			if ((sta =
+			     AscSendScsiQueue(asc_dvc, scsiq,
+					      n_q_required)) == 1) {
+				asc_dvc->in_critical_cnt--;
+				if (asc_exe_callback != 0) {
+					(*asc_exe_callback) (asc_dvc, scsiq);
+				}
+				DvcLeaveCritical(last_int_level);
+				return (sta);
+			}
+		}
+	} else {
+		if (asc_dvc->bug_fix_cntl) {
+			if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
+				if ((scsi_cmd == READ_6) ||
+				    (scsi_cmd == READ_10)) {
+					addr =
+					    le32_to_cpu(scsiq->q1.data_addr) +
+					    le32_to_cpu(scsiq->q1.data_cnt);
+					extra_bytes =
+					    (uchar)((ushort)addr & 0x0003);
+					if ((extra_bytes != 0)
+					    &&
+					    ((scsiq->q2.
+					      tag_code &
+					      ASC_TAG_FLAG_EXTRA_BYTES)
+					     == 0)) {
+						data_cnt =
+						    le32_to_cpu(scsiq->q1.
+								data_cnt);
+						if (((ushort)data_cnt & 0x01FF)
+						    == 0) {
+							scsiq->q2.tag_code |=
+							    ASC_TAG_FLAG_EXTRA_BYTES;
+							data_cnt -= (ASC_DCNT)
+							    extra_bytes;
+							scsiq->q1.data_cnt =
+							    cpu_to_le32
+							    (data_cnt);
+							scsiq->q1.extra_bytes =
+							    extra_bytes;
+						}
+					}
+				}
+			}
+		}
+		n_q_required = 1;
+		if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
+		    ((scsiq->q1.cntl & QC_URGENT) != 0)) {
+			if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
+						    n_q_required)) == 1) {
+				asc_dvc->in_critical_cnt--;
+				if (asc_exe_callback != 0) {
+					(*asc_exe_callback) (asc_dvc, scsiq);
+				}
+				DvcLeaveCritical(last_int_level);
+				return (sta);
+			}
+		}
+	}
+	asc_dvc->in_critical_cnt--;
+	DvcLeaveCritical(last_int_level);
+	return (sta);
 }
 
-STATIC int
-AscSendScsiQueue(
-                    ASC_DVC_VAR *asc_dvc,
-                    ASC_SCSI_Q *scsiq,
-                    uchar n_q_required
-)
+static int
+AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required)
 {
-    PortAddr            iop_base;
-    uchar               free_q_head;
-    uchar               next_qp;
-    uchar               tid_no;
-    uchar               target_ix;
-    int                 sta;
+	PortAddr iop_base;
+	uchar free_q_head;
+	uchar next_qp;
+	uchar tid_no;
+	uchar target_ix;
+	int sta;
 
-    iop_base = asc_dvc->iop_base;
-    target_ix = scsiq->q2.target_ix;
-    tid_no = ASC_TIX_TO_TID(target_ix);
-    sta = 0;
-    free_q_head = (uchar) AscGetVarFreeQHead(iop_base);
-    if (n_q_required > 1) {
-        if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
-                                       free_q_head, (uchar) (n_q_required)))
-            != (uchar) ASC_QLINK_END) {
-            asc_dvc->last_q_shortage = 0;
-            scsiq->sg_head->queue_cnt = n_q_required - 1;
-            scsiq->q1.q_no = free_q_head;
-            if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
-                                              free_q_head)) == 1) {
-                AscPutVarFreeQHead(iop_base, next_qp);
-                asc_dvc->cur_total_qng += (uchar) (n_q_required);
-                asc_dvc->cur_dvc_qng[tid_no]++;
-            }
-            return (sta);
-        }
-    } else if (n_q_required == 1) {
-        if ((next_qp = AscAllocFreeQueue(iop_base,
-                                         free_q_head)) != ASC_QLINK_END) {
-            scsiq->q1.q_no = free_q_head;
-            if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
-                                        free_q_head)) == 1) {
-                AscPutVarFreeQHead(iop_base, next_qp);
-                asc_dvc->cur_total_qng++;
-                asc_dvc->cur_dvc_qng[tid_no]++;
-            }
-            return (sta);
-        }
-    }
-    return (sta);
+	iop_base = asc_dvc->iop_base;
+	target_ix = scsiq->q2.target_ix;
+	tid_no = ASC_TIX_TO_TID(target_ix);
+	sta = 0;
+	free_q_head = (uchar)AscGetVarFreeQHead(iop_base);
+	if (n_q_required > 1) {
+		if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
+							 free_q_head, (uchar)
+							 (n_q_required)))
+		    != (uchar)ASC_QLINK_END) {
+			asc_dvc->last_q_shortage = 0;
+			scsiq->sg_head->queue_cnt = n_q_required - 1;
+			scsiq->q1.q_no = free_q_head;
+			if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
+							  free_q_head)) == 1) {
+				AscPutVarFreeQHead(iop_base, next_qp);
+				asc_dvc->cur_total_qng += (uchar)(n_q_required);
+				asc_dvc->cur_dvc_qng[tid_no]++;
+			}
+			return (sta);
+		}
+	} else if (n_q_required == 1) {
+		if ((next_qp = AscAllocFreeQueue(iop_base,
+						 free_q_head)) !=
+		    ASC_QLINK_END) {
+			scsiq->q1.q_no = free_q_head;
+			if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
+						    free_q_head)) == 1) {
+				AscPutVarFreeQHead(iop_base, next_qp);
+				asc_dvc->cur_total_qng++;
+				asc_dvc->cur_dvc_qng[tid_no]++;
+			}
+			return (sta);
+		}
+	}
+	return (sta);
 }
 
-STATIC int
-AscSgListToQueue(
-                    int sg_list
-)
+static int AscSgListToQueue(int sg_list)
 {
-    int                 n_sg_list_qs;
+	int n_sg_list_qs;
 
-    n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
-    if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
-        n_sg_list_qs++;
-    return (n_sg_list_qs + 1);
+	n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
+	if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
+		n_sg_list_qs++;
+	return (n_sg_list_qs + 1);
 }
 
-
-STATIC uint
-AscGetNumOfFreeQueue(
-                        ASC_DVC_VAR *asc_dvc,
-                        uchar target_ix,
-                        uchar n_qs
-)
+static uint
+AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs)
 {
-    uint                cur_used_qs;
-    uint                cur_free_qs;
-    ASC_SCSI_BIT_ID_TYPE target_id;
-    uchar               tid_no;
+	uint cur_used_qs;
+	uint cur_free_qs;
+	ASC_SCSI_BIT_ID_TYPE target_id;
+	uchar tid_no;
 
-    target_id = ASC_TIX_TO_TARGET_ID(target_ix);
-    tid_no = ASC_TIX_TO_TID(target_ix);
-    if ((asc_dvc->unit_not_ready & target_id) ||
-        (asc_dvc->queue_full_or_busy & target_id)) {
-        return (0);
-    }
-    if (n_qs == 1) {
-        cur_used_qs = (uint) asc_dvc->cur_total_qng +
-          (uint) asc_dvc->last_q_shortage +
-          (uint) ASC_MIN_FREE_Q;
-    } else {
-        cur_used_qs = (uint) asc_dvc->cur_total_qng +
-          (uint) ASC_MIN_FREE_Q;
-    }
-    if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
-        cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
-        if (asc_dvc->cur_dvc_qng[tid_no] >=
-            asc_dvc->max_dvc_qng[tid_no]) {
-            return (0);
-        }
-        return (cur_free_qs);
-    }
-    if (n_qs > 1) {
-        if ((n_qs > asc_dvc->last_q_shortage) && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
-            asc_dvc->last_q_shortage = n_qs;
-        }
-    }
-    return (0);
+	target_id = ASC_TIX_TO_TARGET_ID(target_ix);
+	tid_no = ASC_TIX_TO_TID(target_ix);
+	if ((asc_dvc->unit_not_ready & target_id) ||
+	    (asc_dvc->queue_full_or_busy & target_id)) {
+		return (0);
+	}
+	if (n_qs == 1) {
+		cur_used_qs = (uint) asc_dvc->cur_total_qng +
+		    (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q;
+	} else {
+		cur_used_qs = (uint) asc_dvc->cur_total_qng +
+		    (uint) ASC_MIN_FREE_Q;
+	}
+	if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
+		cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
+		if (asc_dvc->cur_dvc_qng[tid_no] >=
+		    asc_dvc->max_dvc_qng[tid_no]) {
+			return (0);
+		}
+		return (cur_free_qs);
+	}
+	if (n_qs > 1) {
+		if ((n_qs > asc_dvc->last_q_shortage)
+		    && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
+			asc_dvc->last_q_shortage = n_qs;
+		}
+	}
+	return (0);
 }
 
-STATIC int
-AscPutReadyQueue(
-                    ASC_DVC_VAR *asc_dvc,
-                    ASC_SCSI_Q *scsiq,
-                    uchar q_no
-)
+static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
 {
-    ushort              q_addr;
-    uchar               tid_no;
-    uchar               sdtr_data;
-    uchar               syn_period_ix;
-    uchar               syn_offset;
-    PortAddr            iop_base;
+	ushort q_addr;
+	uchar tid_no;
+	uchar sdtr_data;
+	uchar syn_period_ix;
+	uchar syn_offset;
+	PortAddr iop_base;
 
-    iop_base = asc_dvc->iop_base;
-    if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
-        ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
-        tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
-        sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
-        syn_period_ix = (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
-        syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
-        AscMsgOutSDTR(asc_dvc,
-                      asc_dvc->sdtr_period_tbl[syn_period_ix],
-                      syn_offset);
-        scsiq->q1.cntl |= QC_MSG_OUT;
-    }
-    q_addr = ASC_QNO_TO_QADDR(q_no);
-    if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
-        scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG ;
-    }
-    scsiq->q1.status = QS_FREE;
-    AscMemWordCopyPtrToLram(iop_base,
-                         q_addr + ASC_SCSIQ_CDB_BEG,
-                         (uchar *) scsiq->cdbptr,
-                         scsiq->q2.cdb_len >> 1);
+	iop_base = asc_dvc->iop_base;
+	if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
+	    ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
+		tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
+		sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
+		syn_period_ix =
+		    (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
+		syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
+		AscMsgOutSDTR(asc_dvc,
+			      asc_dvc->sdtr_period_tbl[syn_period_ix],
+			      syn_offset);
+		scsiq->q1.cntl |= QC_MSG_OUT;
+	}
+	q_addr = ASC_QNO_TO_QADDR(q_no);
+	if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
+		scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
+	}
+	scsiq->q1.status = QS_FREE;
+	AscMemWordCopyPtrToLram(iop_base,
+				q_addr + ASC_SCSIQ_CDB_BEG,
+				(uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1);
 
-    DvcPutScsiQ(iop_base,
-                q_addr + ASC_SCSIQ_CPY_BEG,
-                (uchar *) &scsiq->q1.cntl,
-                ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
-    AscWriteLramWord(iop_base,
-                     (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
-             (ushort) (((ushort) scsiq->q1.q_no << 8) | (ushort) QS_READY));
-    return (1);
+	DvcPutScsiQ(iop_base,
+		    q_addr + ASC_SCSIQ_CPY_BEG,
+		    (uchar *)&scsiq->q1.cntl,
+		    ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
+	AscWriteLramWord(iop_base,
+			 (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS),
+			 (ushort)(((ushort)scsiq->q1.
+				   q_no << 8) | (ushort)QS_READY));
+	return (1);
 }
 
-STATIC int
-AscPutReadySgListQueue(
-                          ASC_DVC_VAR *asc_dvc,
-                          ASC_SCSI_Q *scsiq,
-                          uchar q_no
-)
+static int
+AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no)
 {
-    int                 sta;
-    int                 i;
-    ASC_SG_HEAD *sg_head;
-    ASC_SG_LIST_Q       scsi_sg_q;
-    ASC_DCNT            saved_data_addr;
-    ASC_DCNT            saved_data_cnt;
-    PortAddr            iop_base;
-    ushort              sg_list_dwords;
-    ushort              sg_index;
-    ushort              sg_entry_cnt;
-    ushort              q_addr;
-    uchar               next_qp;
+	int sta;
+	int i;
+	ASC_SG_HEAD *sg_head;
+	ASC_SG_LIST_Q scsi_sg_q;
+	ASC_DCNT saved_data_addr;
+	ASC_DCNT saved_data_cnt;
+	PortAddr iop_base;
+	ushort sg_list_dwords;
+	ushort sg_index;
+	ushort sg_entry_cnt;
+	ushort q_addr;
+	uchar next_qp;
 
-    iop_base = asc_dvc->iop_base;
-    sg_head = scsiq->sg_head;
-    saved_data_addr = scsiq->q1.data_addr;
-    saved_data_cnt = scsiq->q1.data_cnt;
-    scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
-    scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
+	iop_base = asc_dvc->iop_base;
+	sg_head = scsiq->sg_head;
+	saved_data_addr = scsiq->q1.data_addr;
+	saved_data_cnt = scsiq->q1.data_cnt;
+	scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
+	scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
 #if CC_VERY_LONG_SG_LIST
-    /*
-     * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
-     * then not all SG elements will fit in the allocated queues.
-     * The rest of the SG elements will be copied when the RISC
-     * completes the SG elements that fit and halts.
-     */
-    if (sg_head->entry_cnt > ASC_MAX_SG_LIST)
-    {
-         /*
-          * Set sg_entry_cnt to be the number of SG elements that
-          * will fit in the allocated SG queues. It is minus 1, because
-          * the first SG element is handled above. ASC_MAX_SG_LIST is
-          * already inflated by 1 to account for this. For example it
-          * may be 50 which is 1 + 7 queues * 7 SG elements.
-          */
-         sg_entry_cnt = ASC_MAX_SG_LIST - 1;
+	/*
+	 * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
+	 * then not all SG elements will fit in the allocated queues.
+	 * The rest of the SG elements will be copied when the RISC
+	 * completes the SG elements that fit and halts.
+	 */
+	if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
+		/*
+		 * Set sg_entry_cnt to be the number of SG elements that
+		 * will fit in the allocated SG queues. It is minus 1, because
+		 * the first SG element is handled above. ASC_MAX_SG_LIST is
+		 * already inflated by 1 to account for this. For example it
+		 * may be 50 which is 1 + 7 queues * 7 SG elements.
+		 */
+		sg_entry_cnt = ASC_MAX_SG_LIST - 1;
 
-         /*
-          * Keep track of remaining number of SG elements that will
-          * need to be handled from a_isr.c.
-          */
-         scsiq->remain_sg_entry_cnt = sg_head->entry_cnt - ASC_MAX_SG_LIST;
-    } else
-    {
+		/*
+		 * Keep track of remaining number of SG elements that will
+		 * need to be handled from a_isr.c.
+		 */
+		scsiq->remain_sg_entry_cnt =
+		    sg_head->entry_cnt - ASC_MAX_SG_LIST;
+	} else {
 #endif /* CC_VERY_LONG_SG_LIST */
-         /*
-          * Set sg_entry_cnt to be the number of SG elements that
-          * will fit in the allocated SG queues. It is minus 1, because
-          * the first SG element is handled above.
-          */
-         sg_entry_cnt = sg_head->entry_cnt - 1;
+		/*
+		 * Set sg_entry_cnt to be the number of SG elements that
+		 * will fit in the allocated SG queues. It is minus 1, because
+		 * the first SG element is handled above.
+		 */
+		sg_entry_cnt = sg_head->entry_cnt - 1;
 #if CC_VERY_LONG_SG_LIST
-    }
+	}
 #endif /* CC_VERY_LONG_SG_LIST */
-    if (sg_entry_cnt != 0) {
-        scsiq->q1.cntl |= QC_SG_HEAD;
-        q_addr = ASC_QNO_TO_QADDR(q_no);
-        sg_index = 1;
-        scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
-        scsi_sg_q.sg_head_qp = q_no;
-        scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
-        for (i = 0; i < sg_head->queue_cnt; i++) {
-            scsi_sg_q.seq_no = i + 1;
-            if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
-                sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2);
-                sg_entry_cnt -= ASC_SG_LIST_PER_Q;
-                if (i == 0) {
-                    scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q;
-                    scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q;
-                } else {
-                    scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
-                    scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
-                }
-            } else {
+	if (sg_entry_cnt != 0) {
+		scsiq->q1.cntl |= QC_SG_HEAD;
+		q_addr = ASC_QNO_TO_QADDR(q_no);
+		sg_index = 1;
+		scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
+		scsi_sg_q.sg_head_qp = q_no;
+		scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
+		for (i = 0; i < sg_head->queue_cnt; i++) {
+			scsi_sg_q.seq_no = i + 1;
+			if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
+				sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2);
+				sg_entry_cnt -= ASC_SG_LIST_PER_Q;
+				if (i == 0) {
+					scsi_sg_q.sg_list_cnt =
+					    ASC_SG_LIST_PER_Q;
+					scsi_sg_q.sg_cur_list_cnt =
+					    ASC_SG_LIST_PER_Q;
+				} else {
+					scsi_sg_q.sg_list_cnt =
+					    ASC_SG_LIST_PER_Q - 1;
+					scsi_sg_q.sg_cur_list_cnt =
+					    ASC_SG_LIST_PER_Q - 1;
+				}
+			} else {
 #if CC_VERY_LONG_SG_LIST
-                /*
-                 * This is the last SG queue in the list of
-                 * allocated SG queues. If there are more
-                 * SG elements than will fit in the allocated
-                 * queues, then set the QCSG_SG_XFER_MORE flag.
-                 */
-                if (sg_head->entry_cnt > ASC_MAX_SG_LIST)
-                {
-                    scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
-                } else
-                {
+				/*
+				 * This is the last SG queue in the list of
+				 * allocated SG queues. If there are more
+				 * SG elements than will fit in the allocated
+				 * queues, then set the QCSG_SG_XFER_MORE flag.
+				 */
+				if (sg_head->entry_cnt > ASC_MAX_SG_LIST) {
+					scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
+				} else {
 #endif /* CC_VERY_LONG_SG_LIST */
-                    scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+					scsi_sg_q.cntl |= QCSG_SG_XFER_END;
 #if CC_VERY_LONG_SG_LIST
-                }
+				}
 #endif /* CC_VERY_LONG_SG_LIST */
-                sg_list_dwords = sg_entry_cnt << 1;
-                if (i == 0) {
-                    scsi_sg_q.sg_list_cnt = sg_entry_cnt;
-                    scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt;
-                } else {
-                    scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
-                    scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
-                }
-                sg_entry_cnt = 0;
-            }
-            next_qp = AscReadLramByte(iop_base,
-                                      (ushort) (q_addr + ASC_SCSIQ_B_FWD));
-            scsi_sg_q.q_no = next_qp;
-            q_addr = ASC_QNO_TO_QADDR(next_qp);
-            AscMemWordCopyPtrToLram(iop_base,
-                                q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
-                                (uchar *) &scsi_sg_q,
-                                sizeof(ASC_SG_LIST_Q) >> 1);
-            AscMemDWordCopyPtrToLram(iop_base,
-                                q_addr + ASC_SGQ_LIST_BEG,
-                                (uchar *) &sg_head->sg_list[sg_index],
-                                sg_list_dwords);
-            sg_index += ASC_SG_LIST_PER_Q;
-            scsiq->next_sg_index = sg_index;
-        }
-    } else {
-        scsiq->q1.cntl &= ~QC_SG_HEAD;
-    }
-    sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
-    scsiq->q1.data_addr = saved_data_addr;
-    scsiq->q1.data_cnt = saved_data_cnt;
-    return (sta);
+				sg_list_dwords = sg_entry_cnt << 1;
+				if (i == 0) {
+					scsi_sg_q.sg_list_cnt = sg_entry_cnt;
+					scsi_sg_q.sg_cur_list_cnt =
+					    sg_entry_cnt;
+				} else {
+					scsi_sg_q.sg_list_cnt =
+					    sg_entry_cnt - 1;
+					scsi_sg_q.sg_cur_list_cnt =
+					    sg_entry_cnt - 1;
+				}
+				sg_entry_cnt = 0;
+			}
+			next_qp = AscReadLramByte(iop_base,
+						  (ushort)(q_addr +
+							   ASC_SCSIQ_B_FWD));
+			scsi_sg_q.q_no = next_qp;
+			q_addr = ASC_QNO_TO_QADDR(next_qp);
+			AscMemWordCopyPtrToLram(iop_base,
+						q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
+						(uchar *)&scsi_sg_q,
+						sizeof(ASC_SG_LIST_Q) >> 1);
+			AscMemDWordCopyPtrToLram(iop_base,
+						 q_addr + ASC_SGQ_LIST_BEG,
+						 (uchar *)&sg_head->
+						 sg_list[sg_index],
+						 sg_list_dwords);
+			sg_index += ASC_SG_LIST_PER_Q;
+			scsiq->next_sg_index = sg_index;
+		}
+	} else {
+		scsiq->q1.cntl &= ~QC_SG_HEAD;
+	}
+	sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
+	scsiq->q1.data_addr = saved_data_addr;
+	scsiq->q1.data_cnt = saved_data_cnt;
+	return (sta);
 }
 
-STATIC int
-AscSetRunChipSynRegAtID(
-                           PortAddr iop_base,
-                           uchar tid_no,
-                           uchar sdtr_data
-)
+static int
+AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data)
 {
-    int                 sta = FALSE;
+	int sta = FALSE;
 
-    if (AscHostReqRiscHalt(iop_base)) {
-        sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
-        AscStartChip(iop_base);
-        return (sta);
-    }
-    return (sta);
+	if (AscHostReqRiscHalt(iop_base)) {
+		sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
+		AscStartChip(iop_base);
+		return (sta);
+	}
+	return (sta);
 }
 
-STATIC int
-AscSetChipSynRegAtID(
-                        PortAddr iop_base,
-                        uchar id,
-                        uchar sdtr_data
-)
+static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data)
 {
-    ASC_SCSI_BIT_ID_TYPE org_id;
-    int                 i;
-    int                 sta = TRUE;
+	ASC_SCSI_BIT_ID_TYPE org_id;
+	int i;
+	int sta = TRUE;
 
-    AscSetBank(iop_base, 1);
-    org_id = AscReadChipDvcID(iop_base);
-    for (i = 0; i <= ASC_MAX_TID; i++) {
-        if (org_id == (0x01 << i))
-            break;
-    }
-    org_id = (ASC_SCSI_BIT_ID_TYPE) i;
-    AscWriteChipDvcID(iop_base, id);
-    if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
-        AscSetBank(iop_base, 0);
-        AscSetChipSyn(iop_base, sdtr_data);
-        if (AscGetChipSyn(iop_base) != sdtr_data) {
-            sta = FALSE;
-        }
-    } else {
-        sta = FALSE;
-    }
-    AscSetBank(iop_base, 1);
-    AscWriteChipDvcID(iop_base, org_id);
-    AscSetBank(iop_base, 0);
-    return (sta);
+	AscSetBank(iop_base, 1);
+	org_id = AscReadChipDvcID(iop_base);
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		if (org_id == (0x01 << i))
+			break;
+	}
+	org_id = (ASC_SCSI_BIT_ID_TYPE) i;
+	AscWriteChipDvcID(iop_base, id);
+	if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
+		AscSetBank(iop_base, 0);
+		AscSetChipSyn(iop_base, sdtr_data);
+		if (AscGetChipSyn(iop_base) != sdtr_data) {
+			sta = FALSE;
+		}
+	} else {
+		sta = FALSE;
+	}
+	AscSetBank(iop_base, 1);
+	AscWriteChipDvcID(iop_base, org_id);
+	AscSetBank(iop_base, 0);
+	return (sta);
 }
 
-STATIC ushort
-AscInitLram(
-               ASC_DVC_VAR *asc_dvc
-)
+static ushort AscInitLram(ASC_DVC_VAR *asc_dvc)
 {
-    uchar               i;
-    ushort              s_addr;
-    PortAddr            iop_base;
-    ushort              warn_code;
+	uchar i;
+	ushort s_addr;
+	PortAddr iop_base;
+	ushort warn_code;
 
-    iop_base = asc_dvc->iop_base;
-    warn_code = 0;
-    AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
-               (ushort) (((int) (asc_dvc->max_total_qng + 2 + 1) * 64) >> 1)
-);
-    i = ASC_MIN_ACTIVE_QNO;
-    s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
-    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
-                     (uchar) (i + 1));
-    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
-                     (uchar) (asc_dvc->max_total_qng));
-    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
-                     (uchar) i);
-    i++;
-    s_addr += ASC_QBLK_SIZE;
-    for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
-        AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
-                         (uchar) (i + 1));
-        AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
-                         (uchar) (i - 1));
-        AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
-                         (uchar) i);
-    }
-    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
-                     (uchar) ASC_QLINK_END);
-    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
-                     (uchar) (asc_dvc->max_total_qng - 1));
-    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
-                     (uchar) asc_dvc->max_total_qng);
-    i++;
-    s_addr += ASC_QBLK_SIZE;
-    for (; i <= (uchar) (asc_dvc->max_total_qng + 3);
-         i++, s_addr += ASC_QBLK_SIZE) {
-        AscWriteLramByte(iop_base,
-                         (ushort) (s_addr + (ushort) ASC_SCSIQ_B_FWD), i);
-        AscWriteLramByte(iop_base,
-                         (ushort) (s_addr + (ushort) ASC_SCSIQ_B_BWD), i);
-        AscWriteLramByte(iop_base,
-                         (ushort) (s_addr + (ushort) ASC_SCSIQ_B_QNO), i);
-    }
-    return (warn_code);
+	iop_base = asc_dvc->iop_base;
+	warn_code = 0;
+	AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
+			  (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) *
+				    64) >> 1)
+	    );
+	i = ASC_MIN_ACTIVE_QNO;
+	s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
+	AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
+			 (uchar)(i + 1));
+	AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
+			 (uchar)(asc_dvc->max_total_qng));
+	AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
+			 (uchar)i);
+	i++;
+	s_addr += ASC_QBLK_SIZE;
+	for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
+		AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
+				 (uchar)(i + 1));
+		AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
+				 (uchar)(i - 1));
+		AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
+				 (uchar)i);
+	}
+	AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD),
+			 (uchar)ASC_QLINK_END);
+	AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD),
+			 (uchar)(asc_dvc->max_total_qng - 1));
+	AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO),
+			 (uchar)asc_dvc->max_total_qng);
+	i++;
+	s_addr += ASC_QBLK_SIZE;
+	for (; i <= (uchar)(asc_dvc->max_total_qng + 3);
+	     i++, s_addr += ASC_QBLK_SIZE) {
+		AscWriteLramByte(iop_base,
+				 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i);
+		AscWriteLramByte(iop_base,
+				 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i);
+		AscWriteLramByte(iop_base,
+				 (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i);
+	}
+	return (warn_code);
 }
 
-STATIC ushort
-AscInitQLinkVar(
-                   ASC_DVC_VAR *asc_dvc
-)
+static ushort AscInitQLinkVar(ASC_DVC_VAR *asc_dvc)
 {
-    PortAddr            iop_base;
-    int                 i;
-    ushort              lram_addr;
+	PortAddr iop_base;
+	int i;
+	ushort lram_addr;
 
-    iop_base = asc_dvc->iop_base;
-    AscPutRiscVarFreeQHead(iop_base, 1);
-    AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
-    AscPutVarFreeQHead(iop_base, 1);
-    AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
-    AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
-                     (uchar) ((int) asc_dvc->max_total_qng + 1));
-    AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
-                     (uchar) ((int) asc_dvc->max_total_qng + 2));
-    AscWriteLramByte(iop_base, (ushort) ASCV_TOTAL_READY_Q_B,
-                     asc_dvc->max_total_qng);
-    AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
-    AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
-    AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
-    AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
-    AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
-    AscPutQDoneInProgress(iop_base, 0);
-    lram_addr = ASC_QADR_BEG;
-    for (i = 0; i < 32; i++, lram_addr += 2) {
-        AscWriteLramWord(iop_base, lram_addr, 0);
-    }
-    return (0);
+	iop_base = asc_dvc->iop_base;
+	AscPutRiscVarFreeQHead(iop_base, 1);
+	AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
+	AscPutVarFreeQHead(iop_base, 1);
+	AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
+	AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
+			 (uchar)((int)asc_dvc->max_total_qng + 1));
+	AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
+			 (uchar)((int)asc_dvc->max_total_qng + 2));
+	AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B,
+			 asc_dvc->max_total_qng);
+	AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
+	AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+	AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
+	AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
+	AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
+	AscPutQDoneInProgress(iop_base, 0);
+	lram_addr = ASC_QADR_BEG;
+	for (i = 0; i < 32; i++, lram_addr += 2) {
+		AscWriteLramWord(iop_base, lram_addr, 0);
+	}
+	return (0);
 }
 
-STATIC int
-AscSetLibErrorCode(
-                      ASC_DVC_VAR *asc_dvc,
-                      ushort err_code
-)
+static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code)
 {
-    if (asc_dvc->err_code == 0) {
-        asc_dvc->err_code = err_code;
-        AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
-                         err_code);
-    }
-    return (err_code);
+	if (asc_dvc->err_code == 0) {
+		asc_dvc->err_code = err_code;
+		AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
+				 err_code);
+	}
+	return (err_code);
 }
 
-
-STATIC uchar
-AscMsgOutSDTR(
-                 ASC_DVC_VAR *asc_dvc,
-                 uchar sdtr_period,
-                 uchar sdtr_offset
-)
+static uchar
+AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset)
 {
-    EXT_MSG             sdtr_buf;
-    uchar               sdtr_period_index;
-    PortAddr            iop_base;
+	EXT_MSG sdtr_buf;
+	uchar sdtr_period_index;
+	PortAddr iop_base;
 
-    iop_base = asc_dvc->iop_base;
-    sdtr_buf.msg_type = MS_EXTEND;
-    sdtr_buf.msg_len = MS_SDTR_LEN;
-    sdtr_buf.msg_req = MS_SDTR_CODE;
-    sdtr_buf.xfer_period = sdtr_period;
-    sdtr_offset &= ASC_SYN_MAX_OFFSET;
-    sdtr_buf.req_ack_offset = sdtr_offset;
-    if ((sdtr_period_index =
-         AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
-        asc_dvc->max_sdtr_index) {
-        AscMemWordCopyPtrToLram(iop_base,
-                             ASCV_MSGOUT_BEG,
-                             (uchar *) &sdtr_buf,
-                             sizeof (EXT_MSG) >> 1);
-        return ((sdtr_period_index << 4) | sdtr_offset);
-    } else {
+	iop_base = asc_dvc->iop_base;
+	sdtr_buf.msg_type = MS_EXTEND;
+	sdtr_buf.msg_len = MS_SDTR_LEN;
+	sdtr_buf.msg_req = MS_SDTR_CODE;
+	sdtr_buf.xfer_period = sdtr_period;
+	sdtr_offset &= ASC_SYN_MAX_OFFSET;
+	sdtr_buf.req_ack_offset = sdtr_offset;
+	if ((sdtr_period_index =
+	     AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
+	    asc_dvc->max_sdtr_index) {
+		AscMemWordCopyPtrToLram(iop_base,
+					ASCV_MSGOUT_BEG,
+					(uchar *)&sdtr_buf,
+					sizeof(EXT_MSG) >> 1);
+		return ((sdtr_period_index << 4) | sdtr_offset);
+	} else {
 
-        sdtr_buf.req_ack_offset = 0;
-        AscMemWordCopyPtrToLram(iop_base,
-                             ASCV_MSGOUT_BEG,
-                             (uchar *) &sdtr_buf,
-                             sizeof (EXT_MSG) >> 1);
-        return (0);
-    }
+		sdtr_buf.req_ack_offset = 0;
+		AscMemWordCopyPtrToLram(iop_base,
+					ASCV_MSGOUT_BEG,
+					(uchar *)&sdtr_buf,
+					sizeof(EXT_MSG) >> 1);
+		return (0);
+	}
 }
 
-STATIC uchar
-AscCalSDTRData(
-                  ASC_DVC_VAR *asc_dvc,
-                  uchar sdtr_period,
-                  uchar syn_offset
-)
+static uchar
+AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset)
 {
-    uchar               byte;
-    uchar               sdtr_period_ix;
+	uchar byte;
+	uchar sdtr_period_ix;
 
-    sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
-    if (
-           (sdtr_period_ix > asc_dvc->max_sdtr_index)
-) {
-        return (0xFF);
-    }
-    byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
-    return (byte);
+	sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
+	if ((sdtr_period_ix > asc_dvc->max_sdtr_index)
+	    ) {
+		return (0xFF);
+	}
+	byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
+	return (byte);
 }
 
-STATIC void
-AscSetChipSDTR(
-                  PortAddr iop_base,
-                  uchar sdtr_data,
-                  uchar tid_no
-)
+static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no)
 {
-    AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
-    AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
-    return;
+	AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
+	AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
+	return;
 }
 
-STATIC uchar
-AscGetSynPeriodIndex(
-                        ASC_DVC_VAR *asc_dvc,
-                        uchar syn_time
-)
+static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time)
 {
-    uchar             *period_table;
-    int                 max_index;
-    int                 min_index;
-    int                 i;
+	uchar *period_table;
+	int max_index;
+	int min_index;
+	int i;
 
-    period_table = asc_dvc->sdtr_period_tbl;
-    max_index = (int) asc_dvc->max_sdtr_index;
-    min_index = (int)asc_dvc->host_init_sdtr_index;
-    if ((syn_time <= period_table[max_index])) {
-        for (i = min_index; i < (max_index - 1); i++) {
-            if (syn_time <= period_table[i]) {
-                return ((uchar) i);
-            }
-        }
-        return ((uchar) max_index);
-    } else {
-        return ((uchar) (max_index + 1));
-    }
+	period_table = asc_dvc->sdtr_period_tbl;
+	max_index = (int)asc_dvc->max_sdtr_index;
+	min_index = (int)asc_dvc->host_init_sdtr_index;
+	if ((syn_time <= period_table[max_index])) {
+		for (i = min_index; i < (max_index - 1); i++) {
+			if (syn_time <= period_table[i]) {
+				return ((uchar)i);
+			}
+		}
+		return ((uchar)max_index);
+	} else {
+		return ((uchar)(max_index + 1));
+	}
 }
 
-STATIC uchar
-AscAllocFreeQueue(
-                     PortAddr iop_base,
-                     uchar free_q_head
-)
+static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head)
 {
-    ushort              q_addr;
-    uchar               next_qp;
-    uchar               q_status;
+	ushort q_addr;
+	uchar next_qp;
+	uchar q_status;
 
-    q_addr = ASC_QNO_TO_QADDR(free_q_head);
-    q_status = (uchar) AscReadLramByte(iop_base,
-                                    (ushort) (q_addr + ASC_SCSIQ_B_STATUS));
-    next_qp = AscReadLramByte(iop_base,
-                              (ushort) (q_addr + ASC_SCSIQ_B_FWD));
-    if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
-        return (next_qp);
-    }
-    return (ASC_QLINK_END);
+	q_addr = ASC_QNO_TO_QADDR(free_q_head);
+	q_status = (uchar)AscReadLramByte(iop_base,
+					  (ushort)(q_addr +
+						   ASC_SCSIQ_B_STATUS));
+	next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD));
+	if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
+		return (next_qp);
+	}
+	return (ASC_QLINK_END);
 }
 
-STATIC uchar
-AscAllocMultipleFreeQueue(
-                             PortAddr iop_base,
-                             uchar free_q_head,
-                             uchar n_free_q
-)
+static uchar
+AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q)
 {
-    uchar               i;
+	uchar i;
 
-    for (i = 0; i < n_free_q; i++) {
-        if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
-            == ASC_QLINK_END) {
-            return (ASC_QLINK_END);
-        }
-    }
-    return (free_q_head);
+	for (i = 0; i < n_free_q; i++) {
+		if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
+		    == ASC_QLINK_END) {
+			return (ASC_QLINK_END);
+		}
+	}
+	return (free_q_head);
 }
 
-STATIC int
-AscHostReqRiscHalt(
-                      PortAddr iop_base
-)
+static int AscHostReqRiscHalt(PortAddr iop_base)
 {
-    int                 count = 0;
-    int                 sta = 0;
-    uchar               saved_stop_code;
+	int count = 0;
+	int sta = 0;
+	uchar saved_stop_code;
 
-    if (AscIsChipHalted(iop_base))
-        return (1);
-    saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
-    AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
-                     ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP
-);
-    do {
-        if (AscIsChipHalted(iop_base)) {
-            sta = 1;
-            break;
-        }
-        DvcSleepMilliSecond(100);
-    } while (count++ < 20);
-    AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
-    return (sta);
+	if (AscIsChipHalted(iop_base))
+		return (1);
+	saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
+	AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+			 ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP);
+	do {
+		if (AscIsChipHalted(iop_base)) {
+			sta = 1;
+			break;
+		}
+		DvcSleepMilliSecond(100);
+	} while (count++ < 20);
+	AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
+	return (sta);
 }
 
-STATIC int
-AscStopQueueExe(
-                   PortAddr iop_base
-)
+static int AscStopQueueExe(PortAddr iop_base)
 {
-    int                 count = 0;
+	int count = 0;
 
-    if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
-        AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
-                         ASC_STOP_REQ_RISC_STOP);
-        do {
-            if (
-                   AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
-                   ASC_STOP_ACK_RISC_STOP) {
-                return (1);
-            }
-            DvcSleepMilliSecond(100);
-        } while (count++ < 20);
-    }
-    return (0);
+	if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
+		AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+				 ASC_STOP_REQ_RISC_STOP);
+		do {
+			if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
+			    ASC_STOP_ACK_RISC_STOP) {
+				return (1);
+			}
+			DvcSleepMilliSecond(100);
+		} while (count++ < 20);
+	}
+	return (0);
 }
 
-STATIC void
-DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
+static void DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
 {
-    udelay(micro_sec);
+	udelay(micro_sec);
 }
 
-STATIC void
-DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
+static void DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
 {
-    udelay((nano_sec + 999)/1000);
+	udelay((nano_sec + 999) / 1000);
 }
 
 #ifdef CONFIG_ISA
-STATIC ASC_DCNT __init
-AscGetEisaProductID(
-                       PortAddr iop_base)
+static ASC_DCNT __init AscGetEisaProductID(PortAddr iop_base)
 {
-    PortAddr            eisa_iop;
-    ushort              product_id_high, product_id_low;
-    ASC_DCNT            product_id;
+	PortAddr eisa_iop;
+	ushort product_id_high, product_id_low;
+	ASC_DCNT product_id;
 
-    eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK;
-    product_id_low = inpw(eisa_iop);
-    product_id_high = inpw(eisa_iop + 2);
-    product_id = ((ASC_DCNT) product_id_high << 16) |
-        (ASC_DCNT) product_id_low;
-    return (product_id);
+	eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK;
+	product_id_low = inpw(eisa_iop);
+	product_id_high = inpw(eisa_iop + 2);
+	product_id = ((ASC_DCNT) product_id_high << 16) |
+	    (ASC_DCNT) product_id_low;
+	return (product_id);
 }
 
-STATIC PortAddr __init
-AscSearchIOPortAddrEISA(
-                           PortAddr iop_base)
+static PortAddr __init AscSearchIOPortAddrEISA(PortAddr iop_base)
 {
-    ASC_DCNT            eisa_product_id;
+	ASC_DCNT eisa_product_id;
 
-    if (iop_base == 0) {
-        iop_base = ASC_EISA_MIN_IOP_ADDR;
-    } else {
-        if (iop_base == ASC_EISA_MAX_IOP_ADDR)
-            return (0);
-        if ((iop_base & 0x0050) == 0x0050) {
-            iop_base += ASC_EISA_BIG_IOP_GAP;
-        } else {
-            iop_base += ASC_EISA_SMALL_IOP_GAP;
-        }
-    }
-    while (iop_base <= ASC_EISA_MAX_IOP_ADDR) {
-        eisa_product_id = AscGetEisaProductID(iop_base);
-        if ((eisa_product_id == ASC_EISA_ID_740) ||
-            (eisa_product_id == ASC_EISA_ID_750)) {
-            if (AscFindSignature(iop_base)) {
-                inpw(iop_base + 4);
-                return (iop_base);
-            }
-        }
-        if (iop_base == ASC_EISA_MAX_IOP_ADDR)
-            return (0);
-        if ((iop_base & 0x0050) == 0x0050) {
-            iop_base += ASC_EISA_BIG_IOP_GAP;
-        } else {
-            iop_base += ASC_EISA_SMALL_IOP_GAP;
-        }
-    }
-    return (0);
+	if (iop_base == 0) {
+		iop_base = ASC_EISA_MIN_IOP_ADDR;
+	} else {
+		if (iop_base == ASC_EISA_MAX_IOP_ADDR)
+			return (0);
+		if ((iop_base & 0x0050) == 0x0050) {
+			iop_base += ASC_EISA_BIG_IOP_GAP;
+		} else {
+			iop_base += ASC_EISA_SMALL_IOP_GAP;
+		}
+	}
+	while (iop_base <= ASC_EISA_MAX_IOP_ADDR) {
+		eisa_product_id = AscGetEisaProductID(iop_base);
+		if ((eisa_product_id == ASC_EISA_ID_740) ||
+		    (eisa_product_id == ASC_EISA_ID_750)) {
+			if (AscFindSignature(iop_base)) {
+				inpw(iop_base + 4);
+				return (iop_base);
+			}
+		}
+		if (iop_base == ASC_EISA_MAX_IOP_ADDR)
+			return (0);
+		if ((iop_base & 0x0050) == 0x0050) {
+			iop_base += ASC_EISA_BIG_IOP_GAP;
+		} else {
+			iop_base += ASC_EISA_SMALL_IOP_GAP;
+		}
+	}
+	return (0);
 }
 #endif /* CONFIG_ISA */
 
-STATIC int
-AscStartChip(
-                PortAddr iop_base
-)
+static int AscStartChip(PortAddr iop_base)
 {
-    AscSetChipControl(iop_base, 0);
-    if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
-        return (0);
-    }
-    return (1);
+	AscSetChipControl(iop_base, 0);
+	if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
+		return (0);
+	}
+	return (1);
 }
 
-STATIC int
-AscStopChip(
-               PortAddr iop_base
-)
+static int AscStopChip(PortAddr iop_base)
 {
-    uchar               cc_val;
+	uchar cc_val;
 
-    cc_val = AscGetChipControl(iop_base) & (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
-    AscSetChipControl(iop_base, (uchar) (cc_val | CC_HALT));
-    AscSetChipIH(iop_base, INS_HALT);
-    AscSetChipIH(iop_base, INS_RFLAG_WTM);
-    if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
-        return (0);
-    }
-    return (1);
+	cc_val =
+	    AscGetChipControl(iop_base) &
+	    (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
+	AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT));
+	AscSetChipIH(iop_base, INS_HALT);
+	AscSetChipIH(iop_base, INS_RFLAG_WTM);
+	if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
+		return (0);
+	}
+	return (1);
 }
 
-STATIC int
-AscIsChipHalted(
-                   PortAddr iop_base
-)
+static int AscIsChipHalted(PortAddr iop_base)
 {
-    if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
-        if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
-            return (1);
-        }
-    }
-    return (0);
+	if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
+		if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
+			return (1);
+		}
+	}
+	return (0);
 }
 
-STATIC void
-AscSetChipIH(
-                PortAddr iop_base,
-                ushort ins_code
-)
+static void AscSetChipIH(PortAddr iop_base, ushort ins_code)
 {
-    AscSetBank(iop_base, 1);
-    AscWriteChipIH(iop_base, ins_code);
-    AscSetBank(iop_base, 0);
-    return;
+	AscSetBank(iop_base, 1);
+	AscWriteChipIH(iop_base, ins_code);
+	AscSetBank(iop_base, 0);
+	return;
 }
 
-STATIC void
-AscAckInterrupt(
-                   PortAddr iop_base
-)
+static void AscAckInterrupt(PortAddr iop_base)
 {
-    uchar               host_flag;
-    uchar               risc_flag;
-    ushort              loop;
+	uchar host_flag;
+	uchar risc_flag;
+	ushort loop;
 
-    loop = 0;
-    do {
-        risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
-        if (loop++ > 0x7FFF) {
-            break;
-        }
-    } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
-    host_flag = AscReadLramByte(iop_base, ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
-    AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
-                     (uchar) (host_flag | ASC_HOST_FLAG_ACK_INT));
-    AscSetChipStatus(iop_base, CIW_INT_ACK);
-    loop = 0;
-    while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
-        AscSetChipStatus(iop_base, CIW_INT_ACK);
-        if (loop++ > 3) {
-            break;
-        }
-    }
-    AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
-    return;
+	loop = 0;
+	do {
+		risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
+		if (loop++ > 0x7FFF) {
+			break;
+		}
+	} while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
+	host_flag =
+	    AscReadLramByte(iop_base,
+			    ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
+	AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
+			 (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT));
+	AscSetChipStatus(iop_base, CIW_INT_ACK);
+	loop = 0;
+	while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
+		AscSetChipStatus(iop_base, CIW_INT_ACK);
+		if (loop++ > 3) {
+			break;
+		}
+	}
+	AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
+	return;
 }
 
-STATIC void
-AscDisableInterrupt(
-                       PortAddr iop_base
-)
+static void AscDisableInterrupt(PortAddr iop_base)
 {
-    ushort              cfg;
+	ushort cfg;
 
-    cfg = AscGetChipCfgLsw(iop_base);
-    AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
-    return;
+	cfg = AscGetChipCfgLsw(iop_base);
+	AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
+	return;
 }
 
-STATIC void
-AscEnableInterrupt(
-                      PortAddr iop_base
-)
+static void AscEnableInterrupt(PortAddr iop_base)
 {
-    ushort              cfg;
+	ushort cfg;
 
-    cfg = AscGetChipCfgLsw(iop_base);
-    AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
-    return;
+	cfg = AscGetChipCfgLsw(iop_base);
+	AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
+	return;
 }
 
-
-
-STATIC void
-AscSetBank(
-              PortAddr iop_base,
-              uchar bank
-)
+static void AscSetBank(PortAddr iop_base, uchar bank)
 {
-    uchar               val;
+	uchar val;
 
-    val = AscGetChipControl(iop_base) &
-      (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET | CC_CHIP_RESET));
-    if (bank == 1) {
-        val |= CC_BANK_ONE;
-    } else if (bank == 2) {
-        val |= CC_DIAG | CC_BANK_ONE;
-    } else {
-        val &= ~CC_BANK_ONE;
-    }
-    AscSetChipControl(iop_base, val);
-    return;
+	val = AscGetChipControl(iop_base) &
+	    (~
+	     (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET |
+	      CC_CHIP_RESET));
+	if (bank == 1) {
+		val |= CC_BANK_ONE;
+	} else if (bank == 2) {
+		val |= CC_DIAG | CC_BANK_ONE;
+	} else {
+		val &= ~CC_BANK_ONE;
+	}
+	AscSetChipControl(iop_base, val);
+	return;
 }
 
-STATIC int
-AscResetChipAndScsiBus(
-                          ASC_DVC_VAR *asc_dvc
-)
+static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc)
 {
-    PortAddr    iop_base;
-    int         i = 10;
+	PortAddr iop_base;
+	int i = 10;
 
-    iop_base = asc_dvc->iop_base;
-    while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) && (i-- > 0))
-    {
-          DvcSleepMilliSecond(100);
-    }
-    AscStopChip(iop_base);
-    AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
-    DvcDelayNanoSecond(asc_dvc, 60000);
-    AscSetChipIH(iop_base, INS_RFLAG_WTM);
-    AscSetChipIH(iop_base, INS_HALT);
-    AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
-    AscSetChipControl(iop_base, CC_HALT);
-    DvcSleepMilliSecond(200);
-    AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
-    AscSetChipStatus(iop_base, 0);
-    return (AscIsChipHalted(iop_base));
+	iop_base = asc_dvc->iop_base;
+	while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE)
+	       && (i-- > 0)) {
+		DvcSleepMilliSecond(100);
+	}
+	AscStopChip(iop_base);
+	AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
+	DvcDelayNanoSecond(asc_dvc, 60000);
+	AscSetChipIH(iop_base, INS_RFLAG_WTM);
+	AscSetChipIH(iop_base, INS_HALT);
+	AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
+	AscSetChipControl(iop_base, CC_HALT);
+	DvcSleepMilliSecond(200);
+	AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
+	AscSetChipStatus(iop_base, 0);
+	return (AscIsChipHalted(iop_base));
 }
 
-STATIC ASC_DCNT __init
-AscGetMaxDmaCount(
-                     ushort bus_type)
+static ASC_DCNT __init AscGetMaxDmaCount(ushort bus_type)
 {
-    if (bus_type & ASC_IS_ISA)
-        return (ASC_MAX_ISA_DMA_COUNT);
-    else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
-        return (ASC_MAX_VL_DMA_COUNT);
-    return (ASC_MAX_PCI_DMA_COUNT);
+	if (bus_type & ASC_IS_ISA)
+		return (ASC_MAX_ISA_DMA_COUNT);
+	else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
+		return (ASC_MAX_VL_DMA_COUNT);
+	return (ASC_MAX_PCI_DMA_COUNT);
 }
 
 #ifdef CONFIG_ISA
-STATIC ushort __init
-AscGetIsaDmaChannel(
-                       PortAddr iop_base)
+static ushort __init AscGetIsaDmaChannel(PortAddr iop_base)
 {
-    ushort              channel;
+	ushort channel;
 
-    channel = AscGetChipCfgLsw(iop_base) & 0x0003;
-    if (channel == 0x03)
-        return (0);
-    else if (channel == 0x00)
-        return (7);
-    return (channel + 4);
+	channel = AscGetChipCfgLsw(iop_base) & 0x0003;
+	if (channel == 0x03)
+		return (0);
+	else if (channel == 0x00)
+		return (7);
+	return (channel + 4);
 }
 
-STATIC ushort __init
-AscSetIsaDmaChannel(
-                       PortAddr iop_base,
-                       ushort dma_channel)
+static ushort __init AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel)
 {
-    ushort              cfg_lsw;
-    uchar               value;
+	ushort cfg_lsw;
+	uchar value;
 
-    if ((dma_channel >= 5) && (dma_channel <= 7)) {
-        if (dma_channel == 7)
-            value = 0x00;
-        else
-            value = dma_channel - 4;
-        cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
-        cfg_lsw |= value;
-        AscSetChipCfgLsw(iop_base, cfg_lsw);
-        return (AscGetIsaDmaChannel(iop_base));
-    }
-    return (0);
+	if ((dma_channel >= 5) && (dma_channel <= 7)) {
+		if (dma_channel == 7)
+			value = 0x00;
+		else
+			value = dma_channel - 4;
+		cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
+		cfg_lsw |= value;
+		AscSetChipCfgLsw(iop_base, cfg_lsw);
+		return (AscGetIsaDmaChannel(iop_base));
+	}
+	return (0);
 }
 
-STATIC uchar __init
-AscSetIsaDmaSpeed(
-                     PortAddr iop_base,
-                     uchar speed_value)
+static uchar __init AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value)
 {
-    speed_value &= 0x07;
-    AscSetBank(iop_base, 1);
-    AscWriteChipDmaSpeed(iop_base, speed_value);
-    AscSetBank(iop_base, 0);
-    return (AscGetIsaDmaSpeed(iop_base));
+	speed_value &= 0x07;
+	AscSetBank(iop_base, 1);
+	AscWriteChipDmaSpeed(iop_base, speed_value);
+	AscSetBank(iop_base, 0);
+	return (AscGetIsaDmaSpeed(iop_base));
 }
 
-STATIC uchar __init
-AscGetIsaDmaSpeed(
-                     PortAddr iop_base
-)
+static uchar __init AscGetIsaDmaSpeed(PortAddr iop_base)
 {
-    uchar               speed_value;
+	uchar speed_value;
 
-    AscSetBank(iop_base, 1);
-    speed_value = AscReadChipDmaSpeed(iop_base);
-    speed_value &= 0x07;
-    AscSetBank(iop_base, 0);
-    return (speed_value);
+	AscSetBank(iop_base, 1);
+	speed_value = AscReadChipDmaSpeed(iop_base);
+	speed_value &= 0x07;
+	AscSetBank(iop_base, 0);
+	return (speed_value);
 }
 #endif /* CONFIG_ISA */
 
-STATIC ushort __init
-AscReadPCIConfigWord(
-    ASC_DVC_VAR *asc_dvc,
-    ushort pci_config_offset)
+static ushort __init
+AscReadPCIConfigWord(ASC_DVC_VAR *asc_dvc, ushort pci_config_offset)
 {
-    uchar       lsb, msb;
+	uchar lsb, msb;
 
-    lsb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset);
-    msb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset + 1);
-    return ((ushort) ((msb << 8) | lsb));
+	lsb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset);
+	msb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset + 1);
+	return ((ushort)((msb << 8) | lsb));
 }
 
-STATIC ushort __init
-AscInitGetConfig(
-        ASC_DVC_VAR *asc_dvc
-)
+static ushort __init AscInitGetConfig(ASC_DVC_VAR *asc_dvc)
 {
-    ushort              warn_code;
-    PortAddr            iop_base;
-    ushort              PCIDeviceID;
-    ushort              PCIVendorID;
-    uchar               PCIRevisionID;
-    uchar               prevCmdRegBits;
+	ushort warn_code;
+	PortAddr iop_base;
+	ushort PCIDeviceID;
+	ushort PCIVendorID;
+	uchar PCIRevisionID;
+	uchar prevCmdRegBits;
 
-    warn_code = 0;
-    iop_base = asc_dvc->iop_base;
-    asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
-    if (asc_dvc->err_code != 0) {
-        return (UW_ERR);
-    }
-    if (asc_dvc->bus_type == ASC_IS_PCI) {
-        PCIVendorID = AscReadPCIConfigWord(asc_dvc,
-                                    AscPCIConfigVendorIDRegister);
+	warn_code = 0;
+	iop_base = asc_dvc->iop_base;
+	asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
+	if (asc_dvc->err_code != 0) {
+		return (UW_ERR);
+	}
+	if (asc_dvc->bus_type == ASC_IS_PCI) {
+		PCIVendorID = AscReadPCIConfigWord(asc_dvc,
+						   AscPCIConfigVendorIDRegister);
 
-        PCIDeviceID = AscReadPCIConfigWord(asc_dvc,
-                                    AscPCIConfigDeviceIDRegister);
+		PCIDeviceID = AscReadPCIConfigWord(asc_dvc,
+						   AscPCIConfigDeviceIDRegister);
 
-        PCIRevisionID = DvcReadPCIConfigByte(asc_dvc,
-                                    AscPCIConfigRevisionIDRegister);
+		PCIRevisionID = DvcReadPCIConfigByte(asc_dvc,
+						     AscPCIConfigRevisionIDRegister);
 
-        if (PCIVendorID != PCI_VENDOR_ID_ASP) {
-            warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
-        }
-        prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc,
-                                    AscPCIConfigCommandRegister);
+		if (PCIVendorID != PCI_VENDOR_ID_ASP) {
+			warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+		}
+		prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc,
+						      AscPCIConfigCommandRegister);
 
-        if ((prevCmdRegBits & AscPCICmdRegBits_IOMemBusMaster) !=
-            AscPCICmdRegBits_IOMemBusMaster) {
-            DvcWritePCIConfigByte(asc_dvc,
-                            AscPCIConfigCommandRegister,
-                            (prevCmdRegBits |
-                             AscPCICmdRegBits_IOMemBusMaster));
+		if ((prevCmdRegBits & AscPCICmdRegBits_IOMemBusMaster) !=
+		    AscPCICmdRegBits_IOMemBusMaster) {
+			DvcWritePCIConfigByte(asc_dvc,
+					      AscPCIConfigCommandRegister,
+					      (prevCmdRegBits |
+					       AscPCICmdRegBits_IOMemBusMaster));
 
-            if ((DvcReadPCIConfigByte(asc_dvc,
-                                AscPCIConfigCommandRegister)
-                 & AscPCICmdRegBits_IOMemBusMaster)
-                != AscPCICmdRegBits_IOMemBusMaster) {
-                warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
-            }
-        }
-        if ((PCIDeviceID == PCI_DEVICE_ID_ASP_1200A) ||
-            (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940)) {
-            DvcWritePCIConfigByte(asc_dvc,
-                            AscPCIConfigLatencyTimer, 0x00);
-            if (DvcReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer)
-                != 0x00) {
-                warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
-            }
-        } else if (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940U) {
-            if (DvcReadPCIConfigByte(asc_dvc,
-                                AscPCIConfigLatencyTimer) < 0x20) {
-                DvcWritePCIConfigByte(asc_dvc,
-                                    AscPCIConfigLatencyTimer, 0x20);
+			if ((DvcReadPCIConfigByte(asc_dvc,
+						  AscPCIConfigCommandRegister)
+			     & AscPCICmdRegBits_IOMemBusMaster)
+			    != AscPCICmdRegBits_IOMemBusMaster) {
+				warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+			}
+		}
+		if ((PCIDeviceID == PCI_DEVICE_ID_ASP_1200A) ||
+		    (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940)) {
+			DvcWritePCIConfigByte(asc_dvc,
+					      AscPCIConfigLatencyTimer, 0x00);
+			if (DvcReadPCIConfigByte
+			    (asc_dvc, AscPCIConfigLatencyTimer)
+			    != 0x00) {
+				warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+			}
+		} else if (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940U) {
+			if (DvcReadPCIConfigByte(asc_dvc,
+						 AscPCIConfigLatencyTimer) <
+			    0x20) {
+				DvcWritePCIConfigByte(asc_dvc,
+						      AscPCIConfigLatencyTimer,
+						      0x20);
 
-                if (DvcReadPCIConfigByte(asc_dvc,
-                                    AscPCIConfigLatencyTimer) < 0x20) {
-                    warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
-                }
-            }
-        }
-    }
+				if (DvcReadPCIConfigByte(asc_dvc,
+							 AscPCIConfigLatencyTimer)
+				    < 0x20) {
+					warn_code |=
+					    ASC_WARN_SET_PCI_CONFIG_SPACE;
+				}
+			}
+		}
+	}
 
-    if (AscFindSignature(iop_base)) {
-        warn_code |= AscInitAscDvcVar(asc_dvc);
-        warn_code |= AscInitFromEEP(asc_dvc);
-        asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
-        if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) {
-            asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
-        }
-    } else {
-        asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
-    }
-    return(warn_code);
+	if (AscFindSignature(iop_base)) {
+		warn_code |= AscInitAscDvcVar(asc_dvc);
+		warn_code |= AscInitFromEEP(asc_dvc);
+		asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
+		if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) {
+			asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
+		}
+	} else {
+		asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+	}
+	return (warn_code);
 }
 
-STATIC ushort __init
-AscInitSetConfig(
-                    ASC_DVC_VAR *asc_dvc
-)
+static ushort __init AscInitSetConfig(ASC_DVC_VAR *asc_dvc)
 {
-    ushort              warn_code = 0;
+	ushort warn_code = 0;
 
-    asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
-    if (asc_dvc->err_code != 0)
-        return (UW_ERR);
-    if (AscFindSignature(asc_dvc->iop_base)) {
-        warn_code |= AscInitFromAscDvcVar(asc_dvc);
-        asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
-    } else {
-        asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
-    }
-    return (warn_code);
+	asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
+	if (asc_dvc->err_code != 0)
+		return (UW_ERR);
+	if (AscFindSignature(asc_dvc->iop_base)) {
+		warn_code |= AscInitFromAscDvcVar(asc_dvc);
+		asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
+	} else {
+		asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+	}
+	return (warn_code);
 }
 
-STATIC ushort __init
-AscInitFromAscDvcVar(
-                        ASC_DVC_VAR *asc_dvc
-)
+static ushort __init AscInitFromAscDvcVar(ASC_DVC_VAR *asc_dvc)
 {
-    PortAddr            iop_base;
-    ushort              cfg_msw;
-    ushort              warn_code;
-    ushort              pci_device_id = 0;
+	PortAddr iop_base;
+	ushort cfg_msw;
+	ushort warn_code;
+	ushort pci_device_id = 0;
 
-    iop_base = asc_dvc->iop_base;
+	iop_base = asc_dvc->iop_base;
 #ifdef CONFIG_PCI
-    if (asc_dvc->cfg->dev)
-        pci_device_id = to_pci_dev(asc_dvc->cfg->dev)->device;
+	if (asc_dvc->cfg->dev)
+		pci_device_id = to_pci_dev(asc_dvc->cfg->dev)->device;
 #endif
-    warn_code = 0;
-    cfg_msw = AscGetChipCfgMsw(iop_base);
-    if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
-        cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
-        warn_code |= ASC_WARN_CFG_MSW_RECOVER;
-        AscSetChipCfgMsw(iop_base, cfg_msw);
-    }
-    if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
-        asc_dvc->cfg->cmd_qng_enabled) {
-        asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
-        warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
-    }
-    if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
-        warn_code |= ASC_WARN_AUTO_CONFIG;
-    }
-    if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
-        if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
-            != asc_dvc->irq_no) {
-            asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
-        }
-    }
-    if (asc_dvc->bus_type & ASC_IS_PCI) {
-        cfg_msw &= 0xFFC0;
-        AscSetChipCfgMsw(iop_base, cfg_msw);
-        if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
-        } else {
-            if ((pci_device_id == PCI_DEVICE_ID_ASP_1200A) ||
-                (pci_device_id == PCI_DEVICE_ID_ASP_ABP940)) {
-                asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
-                asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
-            }
-        }
-    } else if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
-        if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
-            == ASC_CHIP_VER_ASYN_BUG) {
-            asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
-        }
-    }
-    if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
-        asc_dvc->cfg->chip_scsi_id) {
-        asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
-    }
+	warn_code = 0;
+	cfg_msw = AscGetChipCfgMsw(iop_base);
+	if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
+		cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
+		warn_code |= ASC_WARN_CFG_MSW_RECOVER;
+		AscSetChipCfgMsw(iop_base, cfg_msw);
+	}
+	if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
+	    asc_dvc->cfg->cmd_qng_enabled) {
+		asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
+		warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
+	}
+	if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
+		warn_code |= ASC_WARN_AUTO_CONFIG;
+	}
+	if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
+		if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
+		    != asc_dvc->irq_no) {
+			asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
+		}
+	}
+	if (asc_dvc->bus_type & ASC_IS_PCI) {
+		cfg_msw &= 0xFFC0;
+		AscSetChipCfgMsw(iop_base, cfg_msw);
+		if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
+		} else {
+			if ((pci_device_id == PCI_DEVICE_ID_ASP_1200A) ||
+			    (pci_device_id == PCI_DEVICE_ID_ASP_ABP940)) {
+				asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
+				asc_dvc->bug_fix_cntl |=
+				    ASC_BUG_FIX_ASYN_USE_SYN;
+			}
+		}
+	} else if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
+		if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
+		    == ASC_CHIP_VER_ASYN_BUG) {
+			asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
+		}
+	}
+	if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
+	    asc_dvc->cfg->chip_scsi_id) {
+		asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
+	}
 #ifdef CONFIG_ISA
-    if (asc_dvc->bus_type & ASC_IS_ISA) {
-        AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
-        AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
-    }
+	if (asc_dvc->bus_type & ASC_IS_ISA) {
+		AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
+		AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
+	}
 #endif /* CONFIG_ISA */
-    return (warn_code);
+	return (warn_code);
 }
 
-STATIC ushort
-AscInitAsc1000Driver(
-                        ASC_DVC_VAR *asc_dvc
-)
+static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc)
 {
-    ushort              warn_code;
-    PortAddr            iop_base;
+	ushort warn_code;
+	PortAddr iop_base;
 
-    iop_base = asc_dvc->iop_base;
-    warn_code = 0;
-    if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
-        !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
-        AscResetChipAndScsiBus(asc_dvc);
-        DvcSleepMilliSecond((ASC_DCNT)
-            ((ushort) asc_dvc->scsi_reset_wait * 1000));
-    }
-    asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
-    if (asc_dvc->err_code != 0)
-        return (UW_ERR);
-    if (!AscFindSignature(asc_dvc->iop_base)) {
-        asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
-        return (warn_code);
-    }
-    AscDisableInterrupt(iop_base);
-    warn_code |= AscInitLram(asc_dvc);
-    if (asc_dvc->err_code != 0)
-        return (UW_ERR);
-    ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
-        (ulong) _asc_mcode_chksum);
-    if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
-                         _asc_mcode_size) != _asc_mcode_chksum) {
-        asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
-        return (warn_code);
-    }
-    warn_code |= AscInitMicroCodeVar(asc_dvc);
-    asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
-    AscEnableInterrupt(iop_base);
-    return (warn_code);
+	iop_base = asc_dvc->iop_base;
+	warn_code = 0;
+	if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
+	    !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
+		AscResetChipAndScsiBus(asc_dvc);
+		DvcSleepMilliSecond((ASC_DCNT)
+				    ((ushort)asc_dvc->scsi_reset_wait * 1000));
+	}
+	asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
+	if (asc_dvc->err_code != 0)
+		return (UW_ERR);
+	if (!AscFindSignature(asc_dvc->iop_base)) {
+		asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+		return (warn_code);
+	}
+	AscDisableInterrupt(iop_base);
+	warn_code |= AscInitLram(asc_dvc);
+	if (asc_dvc->err_code != 0)
+		return (UW_ERR);
+	ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
+		 (ulong)_asc_mcode_chksum);
+	if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
+			     _asc_mcode_size) != _asc_mcode_chksum) {
+		asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+		return (warn_code);
+	}
+	warn_code |= AscInitMicroCodeVar(asc_dvc);
+	asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
+	AscEnableInterrupt(iop_base);
+	return (warn_code);
 }
 
-STATIC ushort __init
-AscInitAscDvcVar(
-                    ASC_DVC_VAR *asc_dvc)
+static ushort __init AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc)
 {
-    int                 i;
-    PortAddr            iop_base;
-    ushort              warn_code;
-    uchar               chip_version;
+	int i;
+	PortAddr iop_base;
+	ushort warn_code;
+	uchar chip_version;
 
-    iop_base = asc_dvc->iop_base;
-    warn_code = 0;
-    asc_dvc->err_code = 0;
-    if ((asc_dvc->bus_type &
-         (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
-        asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
-    }
-    AscSetChipControl(iop_base, CC_HALT);
-    AscSetChipStatus(iop_base, 0);
-    asc_dvc->bug_fix_cntl = 0;
-    asc_dvc->pci_fix_asyn_xfer = 0;
-    asc_dvc->pci_fix_asyn_xfer_always = 0;
-    /* asc_dvc->init_state initalized in AscInitGetConfig(). */
-    asc_dvc->sdtr_done = 0;
-    asc_dvc->cur_total_qng = 0;
-    asc_dvc->is_in_int = 0;
-    asc_dvc->in_critical_cnt = 0;
-    asc_dvc->last_q_shortage = 0;
-    asc_dvc->use_tagged_qng = 0;
-    asc_dvc->no_scam = 0;
-    asc_dvc->unit_not_ready = 0;
-    asc_dvc->queue_full_or_busy = 0;
-    asc_dvc->redo_scam = 0;
-    asc_dvc->res2 = 0;
-    asc_dvc->host_init_sdtr_index = 0;
-    asc_dvc->cfg->can_tagged_qng = 0;
-    asc_dvc->cfg->cmd_qng_enabled = 0;
-    asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
-    asc_dvc->init_sdtr = 0;
-    asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
-    asc_dvc->scsi_reset_wait = 3;
-    asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
-    asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
-    asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
-    asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
-    asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
-    asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
-    asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
-      ASC_LIB_VERSION_MINOR;
-    chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
-    asc_dvc->cfg->chip_version = chip_version;
-    asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
-    asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
-    asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
-    asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
-    asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
-    asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
-    asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
-    asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
-    asc_dvc->max_sdtr_index = 7;
-    if ((asc_dvc->bus_type & ASC_IS_PCI) &&
-        (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
-        asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
-        asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
-        asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
-        asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
-        asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
-        asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
-        asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
-        asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
-        asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
-        asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
-        asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
-        asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
-        asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
-        asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
-        asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
-        asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
-        asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
-        asc_dvc->max_sdtr_index = 15;
-        if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150)
-        {
-            AscSetExtraControl(iop_base,
-                (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
-        } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
-            AscSetExtraControl(iop_base,
-                (SEC_ACTIVE_NEGATE | SEC_ENABLE_FILTER));
-        }
-    }
-    if (asc_dvc->bus_type == ASC_IS_PCI) {
-           AscSetExtraControl(iop_base, (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
-    }
+	iop_base = asc_dvc->iop_base;
+	warn_code = 0;
+	asc_dvc->err_code = 0;
+	if ((asc_dvc->bus_type &
+	     (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
+		asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
+	}
+	AscSetChipControl(iop_base, CC_HALT);
+	AscSetChipStatus(iop_base, 0);
+	asc_dvc->bug_fix_cntl = 0;
+	asc_dvc->pci_fix_asyn_xfer = 0;
+	asc_dvc->pci_fix_asyn_xfer_always = 0;
+	/* asc_dvc->init_state initalized in AscInitGetConfig(). */
+	asc_dvc->sdtr_done = 0;
+	asc_dvc->cur_total_qng = 0;
+	asc_dvc->is_in_int = 0;
+	asc_dvc->in_critical_cnt = 0;
+	asc_dvc->last_q_shortage = 0;
+	asc_dvc->use_tagged_qng = 0;
+	asc_dvc->no_scam = 0;
+	asc_dvc->unit_not_ready = 0;
+	asc_dvc->queue_full_or_busy = 0;
+	asc_dvc->redo_scam = 0;
+	asc_dvc->res2 = 0;
+	asc_dvc->host_init_sdtr_index = 0;
+	asc_dvc->cfg->can_tagged_qng = 0;
+	asc_dvc->cfg->cmd_qng_enabled = 0;
+	asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
+	asc_dvc->init_sdtr = 0;
+	asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
+	asc_dvc->scsi_reset_wait = 3;
+	asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
+	asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
+	asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
+	asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
+	asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
+	asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
+	asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
+	    ASC_LIB_VERSION_MINOR;
+	chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
+	asc_dvc->cfg->chip_version = chip_version;
+	asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
+	asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
+	asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
+	asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
+	asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
+	asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
+	asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
+	asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
+	asc_dvc->max_sdtr_index = 7;
+	if ((asc_dvc->bus_type & ASC_IS_PCI) &&
+	    (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
+		asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
+		asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
+		asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
+		asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
+		asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
+		asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
+		asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
+		asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
+		asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
+		asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
+		asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
+		asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
+		asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
+		asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
+		asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
+		asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
+		asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
+		asc_dvc->max_sdtr_index = 15;
+		if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) {
+			AscSetExtraControl(iop_base,
+					   (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
+		} else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
+			AscSetExtraControl(iop_base,
+					   (SEC_ACTIVE_NEGATE |
+					    SEC_ENABLE_FILTER));
+		}
+	}
+	if (asc_dvc->bus_type == ASC_IS_PCI) {
+		AscSetExtraControl(iop_base,
+				   (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
+	}
 
-    asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
-    if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
-        AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
-        asc_dvc->bus_type = ASC_IS_ISAPNP;
-    }
+	asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
+	if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
+		AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
+		asc_dvc->bus_type = ASC_IS_ISAPNP;
+	}
 #ifdef CONFIG_ISA
-    if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
-        asc_dvc->cfg->isa_dma_channel = (uchar) AscGetIsaDmaChannel(iop_base);
-    }
+	if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
+		asc_dvc->cfg->isa_dma_channel =
+		    (uchar)AscGetIsaDmaChannel(iop_base);
+	}
 #endif /* CONFIG_ISA */
-    for (i = 0; i <= ASC_MAX_TID; i++) {
-        asc_dvc->cur_dvc_qng[i] = 0;
-        asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
-        asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *) 0L;
-        asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *) 0L;
-        asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
-    }
-    return (warn_code);
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		asc_dvc->cur_dvc_qng[i] = 0;
+		asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
+		asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L;
+		asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L;
+		asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
+	}
+	return (warn_code);
 }
 
-STATIC ushort __init
-AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
+static ushort __init AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
 {
-    ASCEEP_CONFIG       eep_config_buf;
-    ASCEEP_CONFIG       *eep_config;
-    PortAddr            iop_base;
-    ushort              chksum;
-    ushort              warn_code;
-    ushort              cfg_msw, cfg_lsw;
-    int                 i;
-    int                 write_eep = 0;
+	ASCEEP_CONFIG eep_config_buf;
+	ASCEEP_CONFIG *eep_config;
+	PortAddr iop_base;
+	ushort chksum;
+	ushort warn_code;
+	ushort cfg_msw, cfg_lsw;
+	int i;
+	int write_eep = 0;
 
-    iop_base = asc_dvc->iop_base;
-    warn_code = 0;
-    AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
-    AscStopQueueExe(iop_base);
-    if ((AscStopChip(iop_base) == FALSE) ||
-        (AscGetChipScsiCtrl(iop_base) != 0)) {
-        asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
-        AscResetChipAndScsiBus(asc_dvc);
-        DvcSleepMilliSecond((ASC_DCNT)
-            ((ushort) asc_dvc->scsi_reset_wait * 1000));
-    }
-    if (AscIsChipHalted(iop_base) == FALSE) {
-        asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
-        return (warn_code);
-    }
-    AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
-    if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
-        asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
-        return (warn_code);
-    }
-    eep_config = (ASCEEP_CONFIG *) &eep_config_buf;
-    cfg_msw = AscGetChipCfgMsw(iop_base);
-    cfg_lsw = AscGetChipCfgLsw(iop_base);
-    if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
-        cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
-        warn_code |= ASC_WARN_CFG_MSW_RECOVER;
-        AscSetChipCfgMsw(iop_base, cfg_msw);
-    }
-    chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
-    ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
-    if (chksum == 0) {
-        chksum = 0xaa55;
-    }
-    if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
-        warn_code |= ASC_WARN_AUTO_CONFIG;
-        if (asc_dvc->cfg->chip_version == 3) {
-            if (eep_config->cfg_lsw != cfg_lsw) {
-                warn_code |= ASC_WARN_EEPROM_RECOVER;
-                eep_config->cfg_lsw = AscGetChipCfgLsw(iop_base);
-            }
-            if (eep_config->cfg_msw != cfg_msw) {
-                warn_code |= ASC_WARN_EEPROM_RECOVER;
-                eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
-            }
-        }
-    }
-    eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
-    eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
-    ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
-        eep_config->chksum);
-    if (chksum != eep_config->chksum) {
-            if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
-                    ASC_CHIP_VER_PCI_ULTRA_3050 )
-            {
-                ASC_DBG(1,
-"AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
-                eep_config->init_sdtr = 0xFF;
-                eep_config->disc_enable = 0xFF;
-                eep_config->start_motor = 0xFF;
-                eep_config->use_cmd_qng = 0;
-                eep_config->max_total_qng = 0xF0;
-                eep_config->max_tag_qng = 0x20;
-                eep_config->cntl = 0xBFFF;
-                ASC_EEP_SET_CHIP_ID(eep_config, 7);
-                eep_config->no_scam = 0;
-                eep_config->adapter_info[0] = 0;
-                eep_config->adapter_info[1] = 0;
-                eep_config->adapter_info[2] = 0;
-                eep_config->adapter_info[3] = 0;
-                eep_config->adapter_info[4] = 0;
-                /* Indicate EEPROM-less board. */
-                eep_config->adapter_info[5] = 0xBB;
-            } else {
-                ASC_PRINT(
-"AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
-                write_eep = 1;
-                warn_code |= ASC_WARN_EEPROM_CHKSUM;
-            }
-    }
-    asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
-    asc_dvc->cfg->disc_enable = eep_config->disc_enable;
-    asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
-    asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
-    asc_dvc->start_motor = eep_config->start_motor;
-    asc_dvc->dvc_cntl = eep_config->cntl;
-    asc_dvc->no_scam = eep_config->no_scam;
-    asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
-    asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
-    asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
-    asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
-    asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
-    asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
-    if (!AscTestExternalLram(asc_dvc)) {
-        if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA)) {
-            eep_config->max_total_qng = ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
-            eep_config->max_tag_qng = ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
-        } else {
-            eep_config->cfg_msw |= 0x0800;
-            cfg_msw |= 0x0800;
-            AscSetChipCfgMsw(iop_base, cfg_msw);
-            eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
-            eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
-        }
-    } else {
-    }
-    if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
-        eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
-    }
-    if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
-        eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
-    }
-    if (eep_config->max_tag_qng > eep_config->max_total_qng) {
-        eep_config->max_tag_qng = eep_config->max_total_qng;
-    }
-    if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
-        eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
-    }
-    asc_dvc->max_total_qng = eep_config->max_total_qng;
-    if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
-        eep_config->use_cmd_qng) {
-        eep_config->disc_enable = eep_config->use_cmd_qng;
-        warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
-    }
-    if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
-        asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
-    }
-    ASC_EEP_SET_CHIP_ID(eep_config, ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
-    asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
-    if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
-        !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
-        asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
-    }
+	iop_base = asc_dvc->iop_base;
+	warn_code = 0;
+	AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
+	AscStopQueueExe(iop_base);
+	if ((AscStopChip(iop_base) == FALSE) ||
+	    (AscGetChipScsiCtrl(iop_base) != 0)) {
+		asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
+		AscResetChipAndScsiBus(asc_dvc);
+		DvcSleepMilliSecond((ASC_DCNT)
+				    ((ushort)asc_dvc->scsi_reset_wait * 1000));
+	}
+	if (AscIsChipHalted(iop_base) == FALSE) {
+		asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
+		return (warn_code);
+	}
+	AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+	if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+		asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
+		return (warn_code);
+	}
+	eep_config = (ASCEEP_CONFIG *)&eep_config_buf;
+	cfg_msw = AscGetChipCfgMsw(iop_base);
+	cfg_lsw = AscGetChipCfgLsw(iop_base);
+	if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
+		cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
+		warn_code |= ASC_WARN_CFG_MSW_RECOVER;
+		AscSetChipCfgMsw(iop_base, cfg_msw);
+	}
+	chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
+	ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
+	if (chksum == 0) {
+		chksum = 0xaa55;
+	}
+	if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
+		warn_code |= ASC_WARN_AUTO_CONFIG;
+		if (asc_dvc->cfg->chip_version == 3) {
+			if (eep_config->cfg_lsw != cfg_lsw) {
+				warn_code |= ASC_WARN_EEPROM_RECOVER;
+				eep_config->cfg_lsw =
+				    AscGetChipCfgLsw(iop_base);
+			}
+			if (eep_config->cfg_msw != cfg_msw) {
+				warn_code |= ASC_WARN_EEPROM_RECOVER;
+				eep_config->cfg_msw =
+				    AscGetChipCfgMsw(iop_base);
+			}
+		}
+	}
+	eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
+	eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
+	ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
+		 eep_config->chksum);
+	if (chksum != eep_config->chksum) {
+		if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
+		    ASC_CHIP_VER_PCI_ULTRA_3050) {
+			ASC_DBG(1,
+				"AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
+			eep_config->init_sdtr = 0xFF;
+			eep_config->disc_enable = 0xFF;
+			eep_config->start_motor = 0xFF;
+			eep_config->use_cmd_qng = 0;
+			eep_config->max_total_qng = 0xF0;
+			eep_config->max_tag_qng = 0x20;
+			eep_config->cntl = 0xBFFF;
+			ASC_EEP_SET_CHIP_ID(eep_config, 7);
+			eep_config->no_scam = 0;
+			eep_config->adapter_info[0] = 0;
+			eep_config->adapter_info[1] = 0;
+			eep_config->adapter_info[2] = 0;
+			eep_config->adapter_info[3] = 0;
+			eep_config->adapter_info[4] = 0;
+			/* Indicate EEPROM-less board. */
+			eep_config->adapter_info[5] = 0xBB;
+		} else {
+			ASC_PRINT
+			    ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
+			write_eep = 1;
+			warn_code |= ASC_WARN_EEPROM_CHKSUM;
+		}
+	}
+	asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
+	asc_dvc->cfg->disc_enable = eep_config->disc_enable;
+	asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
+	asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
+	asc_dvc->start_motor = eep_config->start_motor;
+	asc_dvc->dvc_cntl = eep_config->cntl;
+	asc_dvc->no_scam = eep_config->no_scam;
+	asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
+	asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
+	asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
+	asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
+	asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
+	asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
+	if (!AscTestExternalLram(asc_dvc)) {
+		if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) ==
+		     ASC_IS_PCI_ULTRA)) {
+			eep_config->max_total_qng =
+			    ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
+			eep_config->max_tag_qng =
+			    ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
+		} else {
+			eep_config->cfg_msw |= 0x0800;
+			cfg_msw |= 0x0800;
+			AscSetChipCfgMsw(iop_base, cfg_msw);
+			eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
+			eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
+		}
+	} else {
+	}
+	if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
+		eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
+	}
+	if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
+		eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
+	}
+	if (eep_config->max_tag_qng > eep_config->max_total_qng) {
+		eep_config->max_tag_qng = eep_config->max_total_qng;
+	}
+	if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
+		eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
+	}
+	asc_dvc->max_total_qng = eep_config->max_total_qng;
+	if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
+	    eep_config->use_cmd_qng) {
+		eep_config->disc_enable = eep_config->use_cmd_qng;
+		warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
+	}
+	if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
+		asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
+	}
+	ASC_EEP_SET_CHIP_ID(eep_config,
+			    ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
+	asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
+	if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
+	    !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
+		asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
+	}
 
-    for (i = 0; i <= ASC_MAX_TID; i++) {
-        asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
-        asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
-        asc_dvc->cfg->sdtr_period_offset[i] =
-            (uchar) (ASC_DEF_SDTR_OFFSET |
-                     (asc_dvc->host_init_sdtr_index << 4));
-    }
-    eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
-    if (write_eep) {
-        if ((i = AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type)) !=
-             0) {
-                ASC_PRINT1(
-"AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n", i);
-        } else {
-                ASC_PRINT("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
-        }
-    }
-    return (warn_code);
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
+		asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
+		asc_dvc->cfg->sdtr_period_offset[i] =
+		    (uchar)(ASC_DEF_SDTR_OFFSET |
+			    (asc_dvc->host_init_sdtr_index << 4));
+	}
+	eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
+	if (write_eep) {
+		if ((i =
+		     AscSetEEPConfig(iop_base, eep_config,
+				     asc_dvc->bus_type)) != 0) {
+			ASC_PRINT1
+			    ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n",
+			     i);
+		} else {
+			ASC_PRINT
+			    ("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
+		}
+	}
+	return (warn_code);
 }
 
-STATIC ushort
-AscInitMicroCodeVar(
-                       ASC_DVC_VAR *asc_dvc
-)
+static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc)
 {
-    int                 i;
-    ushort              warn_code;
-    PortAddr            iop_base;
-    ASC_PADDR           phy_addr;
-    ASC_DCNT            phy_size;
+	int i;
+	ushort warn_code;
+	PortAddr iop_base;
+	ASC_PADDR phy_addr;
+	ASC_DCNT phy_size;
 
-    iop_base = asc_dvc->iop_base;
-    warn_code = 0;
-    for (i = 0; i <= ASC_MAX_TID; i++) {
-        AscPutMCodeInitSDTRAtID(iop_base, i,
-                                asc_dvc->cfg->sdtr_period_offset[i]
-);
-    }
+	iop_base = asc_dvc->iop_base;
+	warn_code = 0;
+	for (i = 0; i <= ASC_MAX_TID; i++) {
+		AscPutMCodeInitSDTRAtID(iop_base, i,
+					asc_dvc->cfg->sdtr_period_offset[i]
+		    );
+	}
 
-    AscInitQLinkVar(asc_dvc);
-    AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
-                     asc_dvc->cfg->disc_enable);
-    AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
-                     ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
+	AscInitQLinkVar(asc_dvc);
+	AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
+			 asc_dvc->cfg->disc_enable);
+	AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
+			 ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
 
-    /* Align overrun buffer on an 8 byte boundary. */
-    phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
-    phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
-    AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
-        (uchar *) &phy_addr, 1);
-    phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
-    AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
-        (uchar *) &phy_size, 1);
+	/* Align overrun buffer on an 8 byte boundary. */
+	phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
+	phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
+	AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
+				 (uchar *)&phy_addr, 1);
+	phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
+	AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
+				 (uchar *)&phy_size, 1);
 
-    asc_dvc->cfg->mcode_date =
-        AscReadLramWord(iop_base, (ushort) ASCV_MC_DATE_W);
-    asc_dvc->cfg->mcode_version =
-        AscReadLramWord(iop_base, (ushort) ASCV_MC_VER_W);
+	asc_dvc->cfg->mcode_date =
+	    AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W);
+	asc_dvc->cfg->mcode_version =
+	    AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W);
 
-    AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
-    if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
-        asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
-        return (warn_code);
-    }
-    if (AscStartChip(iop_base) != 1) {
-        asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
-        return (warn_code);
-    }
+	AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+	if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+		asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
+		return (warn_code);
+	}
+	if (AscStartChip(iop_base) != 1) {
+		asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
+		return (warn_code);
+	}
 
-    return (warn_code);
+	return (warn_code);
 }
 
-STATIC int __init
-AscTestExternalLram(
-                       ASC_DVC_VAR *asc_dvc)
+static int __init AscTestExternalLram(ASC_DVC_VAR *asc_dvc)
 {
-    PortAddr            iop_base;
-    ushort              q_addr;
-    ushort              saved_word;
-    int                 sta;
+	PortAddr iop_base;
+	ushort q_addr;
+	ushort saved_word;
+	int sta;
 
-    iop_base = asc_dvc->iop_base;
-    sta = 0;
-    q_addr = ASC_QNO_TO_QADDR(241);
-    saved_word = AscReadLramWord(iop_base, q_addr);
-    AscSetChipLramAddr(iop_base, q_addr);
-    AscSetChipLramData(iop_base, 0x55AA);
-    DvcSleepMilliSecond(10);
-    AscSetChipLramAddr(iop_base, q_addr);
-    if (AscGetChipLramData(iop_base) == 0x55AA) {
-        sta = 1;
-        AscWriteLramWord(iop_base, q_addr, saved_word);
-    }
-    return (sta);
+	iop_base = asc_dvc->iop_base;
+	sta = 0;
+	q_addr = ASC_QNO_TO_QADDR(241);
+	saved_word = AscReadLramWord(iop_base, q_addr);
+	AscSetChipLramAddr(iop_base, q_addr);
+	AscSetChipLramData(iop_base, 0x55AA);
+	DvcSleepMilliSecond(10);
+	AscSetChipLramAddr(iop_base, q_addr);
+	if (AscGetChipLramData(iop_base) == 0x55AA) {
+		sta = 1;
+		AscWriteLramWord(iop_base, q_addr, saved_word);
+	}
+	return (sta);
 }
 
-STATIC int __init
-AscWriteEEPCmdReg(
-                     PortAddr iop_base,
-                     uchar cmd_reg
-)
+static int __init AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg)
 {
-    uchar               read_back;
-    int                 retry;
+	uchar read_back;
+	int retry;
 
-    retry = 0;
-    while (TRUE) {
-        AscSetChipEEPCmd(iop_base, cmd_reg);
-        DvcSleepMilliSecond(1);
-        read_back = AscGetChipEEPCmd(iop_base);
-        if (read_back == cmd_reg) {
-            return (1);
-        }
-        if (retry++ > ASC_EEP_MAX_RETRY) {
-            return (0);
-        }
-    }
+	retry = 0;
+	while (TRUE) {
+		AscSetChipEEPCmd(iop_base, cmd_reg);
+		DvcSleepMilliSecond(1);
+		read_back = AscGetChipEEPCmd(iop_base);
+		if (read_back == cmd_reg) {
+			return (1);
+		}
+		if (retry++ > ASC_EEP_MAX_RETRY) {
+			return (0);
+		}
+	}
 }
 
-STATIC int __init
-AscWriteEEPDataReg(
-                      PortAddr iop_base,
-                      ushort data_reg
-)
+static int __init AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg)
 {
-    ushort              read_back;
-    int                 retry;
+	ushort read_back;
+	int retry;
 
-    retry = 0;
-    while (TRUE) {
-        AscSetChipEEPData(iop_base, data_reg);
-        DvcSleepMilliSecond(1);
-        read_back = AscGetChipEEPData(iop_base);
-        if (read_back == data_reg) {
-            return (1);
-        }
-        if (retry++ > ASC_EEP_MAX_RETRY) {
-            return (0);
-        }
-    }
+	retry = 0;
+	while (TRUE) {
+		AscSetChipEEPData(iop_base, data_reg);
+		DvcSleepMilliSecond(1);
+		read_back = AscGetChipEEPData(iop_base);
+		if (read_back == data_reg) {
+			return (1);
+		}
+		if (retry++ > ASC_EEP_MAX_RETRY) {
+			return (0);
+		}
+	}
 }
 
-STATIC void __init
-AscWaitEEPRead(void)
+static void __init AscWaitEEPRead(void)
 {
-    DvcSleepMilliSecond(1);
-    return;
+	DvcSleepMilliSecond(1);
+	return;
 }
 
-STATIC void __init
-AscWaitEEPWrite(void)
+static void __init AscWaitEEPWrite(void)
 {
-    DvcSleepMilliSecond(20);
-    return;
+	DvcSleepMilliSecond(20);
+	return;
 }
 
-STATIC ushort __init
-AscReadEEPWord(
-                  PortAddr iop_base,
-                  uchar addr)
+static ushort __init AscReadEEPWord(PortAddr iop_base, uchar addr)
 {
-    ushort              read_wval;
-    uchar               cmd_reg;
+	ushort read_wval;
+	uchar cmd_reg;
 
-    AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
-    AscWaitEEPRead();
-    cmd_reg = addr | ASC_EEP_CMD_READ;
-    AscWriteEEPCmdReg(iop_base, cmd_reg);
-    AscWaitEEPRead();
-    read_wval = AscGetChipEEPData(iop_base);
-    AscWaitEEPRead();
-    return (read_wval);
+	AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
+	AscWaitEEPRead();
+	cmd_reg = addr | ASC_EEP_CMD_READ;
+	AscWriteEEPCmdReg(iop_base, cmd_reg);
+	AscWaitEEPRead();
+	read_wval = AscGetChipEEPData(iop_base);
+	AscWaitEEPRead();
+	return (read_wval);
 }
 
-STATIC ushort __init
-AscWriteEEPWord(
-                   PortAddr iop_base,
-                   uchar addr,
-                   ushort word_val)
+static ushort __init
+AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val)
 {
-    ushort              read_wval;
+	ushort read_wval;
 
-    read_wval = AscReadEEPWord(iop_base, addr);
-    if (read_wval != word_val) {
-        AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
-        AscWaitEEPRead();
-        AscWriteEEPDataReg(iop_base, word_val);
-        AscWaitEEPRead();
-        AscWriteEEPCmdReg(iop_base,
-                          (uchar) ((uchar) ASC_EEP_CMD_WRITE | addr));
-        AscWaitEEPWrite();
-        AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
-        AscWaitEEPRead();
-        return (AscReadEEPWord(iop_base, addr));
-    }
-    return (read_wval);
+	read_wval = AscReadEEPWord(iop_base, addr);
+	if (read_wval != word_val) {
+		AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
+		AscWaitEEPRead();
+		AscWriteEEPDataReg(iop_base, word_val);
+		AscWaitEEPRead();
+		AscWriteEEPCmdReg(iop_base,
+				  (uchar)((uchar)ASC_EEP_CMD_WRITE | addr));
+		AscWaitEEPWrite();
+		AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
+		AscWaitEEPRead();
+		return (AscReadEEPWord(iop_base, addr));
+	}
+	return (read_wval);
 }
 
-STATIC ushort __init
-AscGetEEPConfig(
-                   PortAddr iop_base,
-                   ASCEEP_CONFIG * cfg_buf, ushort bus_type)
+static ushort __init
+AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
 {
-    ushort              wval;
-    ushort              sum;
-    ushort              *wbuf;
-    int                 cfg_beg;
-    int                 cfg_end;
-    int                 uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
-    int                 s_addr;
+	ushort wval;
+	ushort sum;
+	ushort *wbuf;
+	int cfg_beg;
+	int cfg_end;
+	int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
+	int s_addr;
 
-    wbuf = (ushort *) cfg_buf;
-    sum = 0;
-    /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
-    for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
-        *wbuf = AscReadEEPWord(iop_base, (uchar) s_addr);
-        sum += *wbuf;
-    }
-    if (bus_type & ASC_IS_VL) {
-        cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
-        cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
-    } else {
-        cfg_beg = ASC_EEP_DVC_CFG_BEG;
-        cfg_end = ASC_EEP_MAX_DVC_ADDR;
-    }
-    for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
-        wval = AscReadEEPWord( iop_base, ( uchar )s_addr ) ;
-        if (s_addr <= uchar_end_in_config) {
-            /*
-             * Swap all char fields - must unswap bytes already swapped
-             * by AscReadEEPWord().
-             */
-            *wbuf = le16_to_cpu(wval);
-        } else {
-            /* Don't swap word field at the end - cntl field. */
-            *wbuf = wval;
-        }
-        sum += wval; /* Checksum treats all EEPROM data as words. */
-    }
-    /*
-     * Read the checksum word which will be compared against 'sum'
-     * by the caller. Word field already swapped.
-     */
-    *wbuf = AscReadEEPWord(iop_base, (uchar) s_addr);
-    return (sum);
+	wbuf = (ushort *)cfg_buf;
+	sum = 0;
+	/* Read two config words; Byte-swapping done by AscReadEEPWord(). */
+	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+		*wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
+		sum += *wbuf;
+	}
+	if (bus_type & ASC_IS_VL) {
+		cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+		cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+	} else {
+		cfg_beg = ASC_EEP_DVC_CFG_BEG;
+		cfg_end = ASC_EEP_MAX_DVC_ADDR;
+	}
+	for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+		wval = AscReadEEPWord(iop_base, (uchar)s_addr);
+		if (s_addr <= uchar_end_in_config) {
+			/*
+			 * Swap all char fields - must unswap bytes already swapped
+			 * by AscReadEEPWord().
+			 */
+			*wbuf = le16_to_cpu(wval);
+		} else {
+			/* Don't swap word field at the end - cntl field. */
+			*wbuf = wval;
+		}
+		sum += wval;	/* Checksum treats all EEPROM data as words. */
+	}
+	/*
+	 * Read the checksum word which will be compared against 'sum'
+	 * by the caller. Word field already swapped.
+	 */
+	*wbuf = AscReadEEPWord(iop_base, (uchar)s_addr);
+	return (sum);
 }
 
-STATIC int __init
-AscSetEEPConfigOnce(
-                       PortAddr iop_base,
-                       ASCEEP_CONFIG * cfg_buf, ushort bus_type)
+static int __init
+AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
 {
-    int                 n_error;
-    ushort              *wbuf;
-    ushort              word;
-    ushort              sum;
-    int                 s_addr;
-    int                 cfg_beg;
-    int                 cfg_end;
-    int                 uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
+	int n_error;
+	ushort *wbuf;
+	ushort word;
+	ushort sum;
+	int s_addr;
+	int cfg_beg;
+	int cfg_end;
+	int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
 
+	wbuf = (ushort *)cfg_buf;
+	n_error = 0;
+	sum = 0;
+	/* Write two config words; AscWriteEEPWord() will swap bytes. */
+	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+		sum += *wbuf;
+		if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
+			n_error++;
+		}
+	}
+	if (bus_type & ASC_IS_VL) {
+		cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+		cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+	} else {
+		cfg_beg = ASC_EEP_DVC_CFG_BEG;
+		cfg_end = ASC_EEP_MAX_DVC_ADDR;
+	}
+	for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+		if (s_addr <= uchar_end_in_config) {
+			/*
+			 * This is a char field. Swap char fields before they are
+			 * swapped again by AscWriteEEPWord().
+			 */
+			word = cpu_to_le16(*wbuf);
+			if (word !=
+			    AscWriteEEPWord(iop_base, (uchar)s_addr, word)) {
+				n_error++;
+			}
+		} else {
+			/* Don't swap word field at the end - cntl field. */
+			if (*wbuf !=
+			    AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) {
+				n_error++;
+			}
+		}
+		sum += *wbuf;	/* Checksum calculated from word values. */
+	}
+	/* Write checksum word. It will be swapped by AscWriteEEPWord(). */
+	*wbuf = sum;
+	if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) {
+		n_error++;
+	}
 
-    wbuf = (ushort *) cfg_buf;
-    n_error = 0;
-    sum = 0;
-    /* Write two config words; AscWriteEEPWord() will swap bytes. */
-    for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
-        sum += *wbuf;
-        if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) {
-            n_error++;
-        }
-    }
-    if (bus_type & ASC_IS_VL) {
-        cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
-        cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
-    } else {
-        cfg_beg = ASC_EEP_DVC_CFG_BEG;
-        cfg_end = ASC_EEP_MAX_DVC_ADDR;
-    }
-    for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
-        if (s_addr <= uchar_end_in_config) {
-            /*
-             * This is a char field. Swap char fields before they are
-             * swapped again by AscWriteEEPWord().
-             */
-            word = cpu_to_le16(*wbuf);
-            if (word != AscWriteEEPWord( iop_base, (uchar) s_addr, word)) {
-                n_error++;
-            }
-        } else {
-            /* Don't swap word field at the end - cntl field. */
-            if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) {
-                n_error++;
-            }
-        }
-        sum += *wbuf; /* Checksum calculated from word values. */
-    }
-    /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
-    *wbuf = sum;
-    if (sum != AscWriteEEPWord(iop_base, (uchar) s_addr, sum)) {
-        n_error++;
-    }
-
-    /* Read EEPROM back again. */
-    wbuf = (ushort *) cfg_buf;
-    /*
-     * Read two config words; Byte-swapping done by AscReadEEPWord().
-     */
-    for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
-        if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) {
-            n_error++;
-        }
-    }
-    if (bus_type & ASC_IS_VL) {
-        cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
-        cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
-    } else {
-        cfg_beg = ASC_EEP_DVC_CFG_BEG;
-        cfg_end = ASC_EEP_MAX_DVC_ADDR;
-    }
-    for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
-        if (s_addr <= uchar_end_in_config) {
-            /*
-             * Swap all char fields. Must unswap bytes already swapped
-             * by AscReadEEPWord().
-             */
-            word = le16_to_cpu(AscReadEEPWord(iop_base, (uchar) s_addr));
-        } else {
-            /* Don't swap word field at the end - cntl field. */
-            word = AscReadEEPWord(iop_base, (uchar) s_addr);
-        }
-        if (*wbuf != word) {
-            n_error++;
-        }
-    }
-    /* Read checksum; Byte swapping not needed. */
-    if (AscReadEEPWord(iop_base, (uchar) s_addr) != sum) {
-        n_error++;
-    }
-    return (n_error);
+	/* Read EEPROM back again. */
+	wbuf = (ushort *)cfg_buf;
+	/*
+	 * Read two config words; Byte-swapping done by AscReadEEPWord().
+	 */
+	for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+		if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) {
+			n_error++;
+		}
+	}
+	if (bus_type & ASC_IS_VL) {
+		cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+		cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+	} else {
+		cfg_beg = ASC_EEP_DVC_CFG_BEG;
+		cfg_end = ASC_EEP_MAX_DVC_ADDR;
+	}
+	for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+		if (s_addr <= uchar_end_in_config) {
+			/*
+			 * Swap all char fields. Must unswap bytes already swapped
+			 * by AscReadEEPWord().
+			 */
+			word =
+			    le16_to_cpu(AscReadEEPWord
+					(iop_base, (uchar)s_addr));
+		} else {
+			/* Don't swap word field at the end - cntl field. */
+			word = AscReadEEPWord(iop_base, (uchar)s_addr);
+		}
+		if (*wbuf != word) {
+			n_error++;
+		}
+	}
+	/* Read checksum; Byte swapping not needed. */
+	if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) {
+		n_error++;
+	}
+	return (n_error);
 }
 
-STATIC int __init
-AscSetEEPConfig(
-                   PortAddr iop_base,
-                   ASCEEP_CONFIG * cfg_buf, ushort bus_type
-)
+static int __init
+AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type)
 {
-    int            retry;
-    int            n_error;
+	int retry;
+	int n_error;
 
-    retry = 0;
-    while (TRUE) {
-        if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
-                                           bus_type)) == 0) {
-            break;
-        }
-        if (++retry > ASC_EEP_MAX_RETRY) {
-            break;
-        }
-    }
-    return (n_error);
+	retry = 0;
+	while (TRUE) {
+		if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
+						   bus_type)) == 0) {
+			break;
+		}
+		if (++retry > ASC_EEP_MAX_RETRY) {
+			break;
+		}
+	}
+	return (n_error);
 }
 
-STATIC void
-AscAsyncFix(
-               ASC_DVC_VAR *asc_dvc,
-               uchar tid_no,
-               ASC_SCSI_INQUIRY *inq)
+static void
+AscAsyncFix(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
 {
-    uchar                       dvc_type;
-    ASC_SCSI_BIT_ID_TYPE        tid_bits;
+	uchar dvc_type;
+	ASC_SCSI_BIT_ID_TYPE tid_bits;
 
-    dvc_type = ASC_INQ_DVC_TYPE(inq);
-    tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
+	dvc_type = ASC_INQ_DVC_TYPE(inq);
+	tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
 
-    if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN)
-    {
-        if (!(asc_dvc->init_sdtr & tid_bits))
-        {
-            if ((dvc_type == TYPE_ROM) &&
-                (AscCompareString((uchar *) inq->vendor_id,
-                    (uchar *) "HP ", 3) == 0))
-            {
-                asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
-            }
-            asc_dvc->pci_fix_asyn_xfer |= tid_bits;
-            if ((dvc_type == TYPE_PROCESSOR) ||
-                (dvc_type == TYPE_SCANNER) ||
-                (dvc_type == TYPE_ROM) ||
-                (dvc_type == TYPE_TAPE))
-            {
-                asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
-            }
+	if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) {
+		if (!(asc_dvc->init_sdtr & tid_bits)) {
+			if ((dvc_type == TYPE_ROM) &&
+			    (AscCompareString((uchar *)inq->vendor_id,
+					      (uchar *)"HP ", 3) == 0)) {
+				asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
+			}
+			asc_dvc->pci_fix_asyn_xfer |= tid_bits;
+			if ((dvc_type == TYPE_PROCESSOR) ||
+			    (dvc_type == TYPE_SCANNER) ||
+			    (dvc_type == TYPE_ROM) || (dvc_type == TYPE_TAPE)) {
+				asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
+			}
 
-            if (asc_dvc->pci_fix_asyn_xfer & tid_bits)
-            {
-                AscSetRunChipSynRegAtID(asc_dvc->iop_base, tid_no,
-                    ASYN_SDTR_DATA_FIX_PCI_REV_AB);
-            }
-        }
-    }
-    return;
+			if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
+				AscSetRunChipSynRegAtID(asc_dvc->iop_base,
+							tid_no,
+							ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+			}
+		}
+	}
+	return;
 }
 
-STATIC int
-AscTagQueuingSafe(ASC_SCSI_INQUIRY *inq)
+static int AscTagQueuingSafe(ASC_SCSI_INQUIRY *inq)
 {
-    if ((inq->add_len >= 32) &&
-        (AscCompareString((uchar *) inq->vendor_id,
-            (uchar *) "QUANTUM XP34301", 15) == 0) &&
-        (AscCompareString((uchar *) inq->product_rev_level,
-            (uchar *) "1071", 4) == 0))
-    {
-        return 0;
-    }
-    return 1;
+	if ((inq->add_len >= 32) &&
+	    (AscCompareString((uchar *)inq->vendor_id,
+			      (uchar *)"QUANTUM XP34301", 15) == 0) &&
+	    (AscCompareString((uchar *)inq->product_rev_level,
+			      (uchar *)"1071", 4) == 0)) {
+		return 0;
+	}
+	return 1;
 }
 
-STATIC void
-AscInquiryHandling(ASC_DVC_VAR *asc_dvc,
-                   uchar tid_no, ASC_SCSI_INQUIRY *inq)
+static void
+AscInquiryHandling(ASC_DVC_VAR *asc_dvc, uchar tid_no, ASC_SCSI_INQUIRY *inq)
 {
-    ASC_SCSI_BIT_ID_TYPE tid_bit = ASC_TIX_TO_TARGET_ID(tid_no);
-    ASC_SCSI_BIT_ID_TYPE orig_init_sdtr, orig_use_tagged_qng;
+	ASC_SCSI_BIT_ID_TYPE tid_bit = ASC_TIX_TO_TARGET_ID(tid_no);
+	ASC_SCSI_BIT_ID_TYPE orig_init_sdtr, orig_use_tagged_qng;
 
-    orig_init_sdtr = asc_dvc->init_sdtr;
-    orig_use_tagged_qng = asc_dvc->use_tagged_qng;
+	orig_init_sdtr = asc_dvc->init_sdtr;
+	orig_use_tagged_qng = asc_dvc->use_tagged_qng;
 
-    asc_dvc->init_sdtr &= ~tid_bit;
-    asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
-    asc_dvc->use_tagged_qng &= ~tid_bit;
+	asc_dvc->init_sdtr &= ~tid_bit;
+	asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
+	asc_dvc->use_tagged_qng &= ~tid_bit;
 
-    if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) {
-        if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) {
-            asc_dvc->init_sdtr |= tid_bit;
-        }
-        if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) &&
-             ASC_INQ_CMD_QUEUE(inq)) {
-            if (AscTagQueuingSafe(inq)) {
-                asc_dvc->use_tagged_qng |= tid_bit;
-                asc_dvc->cfg->can_tagged_qng |= tid_bit;
-            }
-        }
-    }
-    if (orig_use_tagged_qng != asc_dvc->use_tagged_qng) {
-        AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
-                         asc_dvc->cfg->disc_enable);
-        AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
-                         asc_dvc->use_tagged_qng);
-        AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
-                         asc_dvc->cfg->can_tagged_qng);
+	if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) {
+		if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) {
+			asc_dvc->init_sdtr |= tid_bit;
+		}
+		if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) &&
+		    ASC_INQ_CMD_QUEUE(inq)) {
+			if (AscTagQueuingSafe(inq)) {
+				asc_dvc->use_tagged_qng |= tid_bit;
+				asc_dvc->cfg->can_tagged_qng |= tid_bit;
+			}
+		}
+	}
+	if (orig_use_tagged_qng != asc_dvc->use_tagged_qng) {
+		AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
+				 asc_dvc->cfg->disc_enable);
+		AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
+				 asc_dvc->use_tagged_qng);
+		AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
+				 asc_dvc->cfg->can_tagged_qng);
 
-        asc_dvc->max_dvc_qng[tid_no] =
-          asc_dvc->cfg->max_tag_qng[tid_no];
-        AscWriteLramByte(asc_dvc->iop_base,
-                         (ushort) (ASCV_MAX_DVC_QNG_BEG + tid_no),
-                         asc_dvc->max_dvc_qng[tid_no]);
-    }
-    if (orig_init_sdtr != asc_dvc->init_sdtr) {
-        AscAsyncFix(asc_dvc, tid_no, inq);
-    }
-    return;
+		asc_dvc->max_dvc_qng[tid_no] =
+		    asc_dvc->cfg->max_tag_qng[tid_no];
+		AscWriteLramByte(asc_dvc->iop_base,
+				 (ushort)(ASCV_MAX_DVC_QNG_BEG + tid_no),
+				 asc_dvc->max_dvc_qng[tid_no]);
+	}
+	if (orig_init_sdtr != asc_dvc->init_sdtr) {
+		AscAsyncFix(asc_dvc, tid_no, inq);
+	}
+	return;
 }
 
-STATIC int
-AscCompareString(
-                    uchar *str1,
-                    uchar *str2,
-                    int len
-)
+static int AscCompareString(uchar *str1, uchar *str2, int len)
 {
-    int                 i;
-    int                 diff;
+	int i;
+	int diff;
 
-    for (i = 0; i < len; i++) {
-        diff = (int) (str1[i] - str2[i]);
-        if (diff != 0)
-            return (diff);
-    }
-    return (0);
+	for (i = 0; i < len; i++) {
+		diff = (int)(str1[i] - str2[i]);
+		if (diff != 0)
+			return (diff);
+	}
+	return (0);
 }
 
-STATIC uchar
-AscReadLramByte(
-                   PortAddr iop_base,
-                   ushort addr
-)
+static uchar AscReadLramByte(PortAddr iop_base, ushort addr)
 {
-    uchar               byte_data;
-    ushort              word_data;
+	uchar byte_data;
+	ushort word_data;
 
-    if (isodd_word(addr)) {
-        AscSetChipLramAddr(iop_base, addr - 1);
-        word_data = AscGetChipLramData(iop_base);
-        byte_data = (uchar) ((word_data >> 8) & 0xFF);
-    } else {
-        AscSetChipLramAddr(iop_base, addr);
-        word_data = AscGetChipLramData(iop_base);
-        byte_data = (uchar) (word_data & 0xFF);
-    }
-    return (byte_data);
+	if (isodd_word(addr)) {
+		AscSetChipLramAddr(iop_base, addr - 1);
+		word_data = AscGetChipLramData(iop_base);
+		byte_data = (uchar)((word_data >> 8) & 0xFF);
+	} else {
+		AscSetChipLramAddr(iop_base, addr);
+		word_data = AscGetChipLramData(iop_base);
+		byte_data = (uchar)(word_data & 0xFF);
+	}
+	return (byte_data);
 }
-STATIC ushort
-AscReadLramWord(
-                   PortAddr iop_base,
-                   ushort addr
-)
-{
-    ushort              word_data;
 
-    AscSetChipLramAddr(iop_base, addr);
-    word_data = AscGetChipLramData(iop_base);
-    return (word_data);
+static ushort AscReadLramWord(PortAddr iop_base, ushort addr)
+{
+	ushort word_data;
+
+	AscSetChipLramAddr(iop_base, addr);
+	word_data = AscGetChipLramData(iop_base);
+	return (word_data);
 }
 
 #if CC_VERY_LONG_SG_LIST
-STATIC ASC_DCNT
-AscReadLramDWord(
-                    PortAddr iop_base,
-                    ushort addr
-)
+static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr)
 {
-    ushort              val_low, val_high;
-    ASC_DCNT            dword_data;
+	ushort val_low, val_high;
+	ASC_DCNT dword_data;
 
-    AscSetChipLramAddr(iop_base, addr);
-    val_low = AscGetChipLramData(iop_base);
-    val_high = AscGetChipLramData(iop_base);
-    dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
-    return (dword_data);
+	AscSetChipLramAddr(iop_base, addr);
+	val_low = AscGetChipLramData(iop_base);
+	val_high = AscGetChipLramData(iop_base);
+	dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
+	return (dword_data);
 }
 #endif /* CC_VERY_LONG_SG_LIST */
 
-STATIC void
-AscWriteLramWord(
-                    PortAddr iop_base,
-                    ushort addr,
-                    ushort word_val
-)
+static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val)
 {
-    AscSetChipLramAddr(iop_base, addr);
-    AscSetChipLramData(iop_base, word_val);
-    return;
+	AscSetChipLramAddr(iop_base, addr);
+	AscSetChipLramData(iop_base, word_val);
+	return;
 }
 
-STATIC void
-AscWriteLramByte(
-                    PortAddr iop_base,
-                    ushort addr,
-                    uchar byte_val
-)
+static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val)
 {
-    ushort              word_data;
+	ushort word_data;
 
-    if (isodd_word(addr)) {
-        addr--;
-        word_data = AscReadLramWord(iop_base, addr);
-        word_data &= 0x00FF;
-        word_data |= (((ushort) byte_val << 8) & 0xFF00);
-    } else {
-        word_data = AscReadLramWord(iop_base, addr);
-        word_data &= 0xFF00;
-        word_data |= ((ushort) byte_val & 0x00FF);
-    }
-    AscWriteLramWord(iop_base, addr, word_data);
-    return;
+	if (isodd_word(addr)) {
+		addr--;
+		word_data = AscReadLramWord(iop_base, addr);
+		word_data &= 0x00FF;
+		word_data |= (((ushort)byte_val << 8) & 0xFF00);
+	} else {
+		word_data = AscReadLramWord(iop_base, addr);
+		word_data &= 0xFF00;
+		word_data |= ((ushort)byte_val & 0x00FF);
+	}
+	AscWriteLramWord(iop_base, addr, word_data);
+	return;
 }
 
 /*
@@ -12841,30 +11628,26 @@
  * The source data is assumed to be in little-endian order in memory
  * and is maintained in little-endian order when written to LRAM.
  */
-STATIC void
-AscMemWordCopyPtrToLram(
-                        PortAddr iop_base,
-                        ushort s_addr,
-                        uchar *s_buffer,
-                        int words
-)
+static void
+AscMemWordCopyPtrToLram(PortAddr iop_base,
+			ushort s_addr, uchar *s_buffer, int words)
 {
-    int    i;
+	int i;
 
-    AscSetChipLramAddr(iop_base, s_addr);
-    for (i = 0; i < 2 * words; i += 2) {
-        /*
-         * On a little-endian system the second argument below
-         * produces a little-endian ushort which is written to
-         * LRAM in little-endian order. On a big-endian system
-         * the second argument produces a big-endian ushort which
-         * is "transparently" byte-swapped by outpw() and written
-         * in little-endian order to LRAM.
-         */
-        outpw(iop_base + IOP_RAM_DATA,
-            ((ushort) s_buffer[i + 1] << 8) | s_buffer[i]);
-    }
-    return;
+	AscSetChipLramAddr(iop_base, s_addr);
+	for (i = 0; i < 2 * words; i += 2) {
+		/*
+		 * On a little-endian system the second argument below
+		 * produces a little-endian ushort which is written to
+		 * LRAM in little-endian order. On a big-endian system
+		 * the second argument produces a big-endian ushort which
+		 * is "transparently" byte-swapped by outpw() and written
+		 * in little-endian order to LRAM.
+		 */
+		outpw(iop_base + IOP_RAM_DATA,
+		      ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);
+	}
+	return;
 }
 
 /*
@@ -12873,24 +11656,18 @@
  * The source data is assumed to be in little-endian order in memory
  * and is maintained in little-endian order when writen to LRAM.
  */
-STATIC void
-AscMemDWordCopyPtrToLram(
-                         PortAddr iop_base,
-                         ushort s_addr,
-                         uchar *s_buffer,
-                         int dwords
-)
+static void
+AscMemDWordCopyPtrToLram(PortAddr iop_base,
+			 ushort s_addr, uchar *s_buffer, int dwords)
 {
-    int       i;
+	int i;
 
-    AscSetChipLramAddr(iop_base, s_addr);
-    for (i = 0; i < 4 * dwords; i += 4) {
-        outpw(iop_base + IOP_RAM_DATA,
-            ((ushort) s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
-        outpw(iop_base + IOP_RAM_DATA,
-            ((ushort) s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
-    }
-    return;
+	AscSetChipLramAddr(iop_base, s_addr);
+	for (i = 0; i < 4 * dwords; i += 4) {
+		outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]);	/* LSW */
+		outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]);	/* MSW */
+	}
+	return;
 }
 
 /*
@@ -12899,61 +11676,46 @@
  * The source data is assumed to be in little-endian order in LRAM
  * and is maintained in little-endian order when written to memory.
  */
-STATIC void
-AscMemWordCopyPtrFromLram(
-                          PortAddr iop_base,
-                          ushort s_addr,
-                          uchar *d_buffer,
-                          int words
-)
+static void
+AscMemWordCopyPtrFromLram(PortAddr iop_base,
+			  ushort s_addr, uchar *d_buffer, int words)
 {
-    int i;
-    ushort word;
+	int i;
+	ushort word;
 
-    AscSetChipLramAddr(iop_base, s_addr);
-    for (i = 0; i < 2 * words; i += 2) {
-        word = inpw(iop_base + IOP_RAM_DATA);
-        d_buffer[i] = word & 0xff;
-        d_buffer[i + 1] = (word >> 8) & 0xff;
-    }
-    return;
+	AscSetChipLramAddr(iop_base, s_addr);
+	for (i = 0; i < 2 * words; i += 2) {
+		word = inpw(iop_base + IOP_RAM_DATA);
+		d_buffer[i] = word & 0xff;
+		d_buffer[i + 1] = (word >> 8) & 0xff;
+	}
+	return;
 }
 
-STATIC ASC_DCNT
-AscMemSumLramWord(
-                     PortAddr iop_base,
-                     ushort s_addr,
-                     int words
-)
+static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words)
 {
-    ASC_DCNT         sum;
-    int              i;
+	ASC_DCNT sum;
+	int i;
 
-    sum = 0L;
-    for (i = 0; i < words; i++, s_addr += 2) {
-        sum += AscReadLramWord(iop_base, s_addr);
-    }
-    return (sum);
+	sum = 0L;
+	for (i = 0; i < words; i++, s_addr += 2) {
+		sum += AscReadLramWord(iop_base, s_addr);
+	}
+	return (sum);
 }
 
-STATIC void
-AscMemWordSetLram(
-                     PortAddr iop_base,
-                     ushort s_addr,
-                     ushort set_wval,
-                     int words
-)
+static void
+AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words)
 {
-    int             i;
+	int i;
 
-    AscSetChipLramAddr(iop_base, s_addr);
-    for (i = 0; i < words; i++) {
-        AscSetChipLramData(iop_base, set_wval);
-    }
-    return;
+	AscSetChipLramAddr(iop_base, s_addr);
+	for (i = 0; i < words; i++) {
+		AscSetChipLramData(iop_base, set_wval);
+	}
+	return;
 }
 
-
 /*
  * --- Adv Library Functions
  */
@@ -12961,1076 +11723,2112 @@
 /* a_mcode.h */
 
 /* Microcode buffer is kept after initialization for error recovery. */
-STATIC unsigned char _adv_asc3550_buf[] = {
-  0x00,  0x00,  0x00,  0xf2,  0x00,  0xf0,  0x00,  0x16,  0x18,  0xe4,  0x00,  0xfc,  0x01,  0x00,  0x48,  0xe4,
-  0xbe,  0x18,  0x18,  0x80,  0x03,  0xf6,  0x02,  0x00,  0x00,  0xfa,  0xff,  0xff,  0x28,  0x0e,  0x9e,  0xe7,
-  0xff,  0x00,  0x82,  0xe7,  0x00,  0xea,  0x00,  0xf6,  0x01,  0xe6,  0x09,  0xe7,  0x55,  0xf0,  0x01,  0xf6,
-  0x01,  0xfa,  0x08,  0x00,  0x03,  0x00,  0x04,  0x00,  0x18,  0xf4,  0x10,  0x00,  0x00,  0xec,  0x85,  0xf0,
-  0xbc,  0x00,  0xd5,  0xf0,  0x8e,  0x0c,  0x38,  0x54,  0x00,  0xe6,  0x1e,  0xf0,  0x86,  0xf0,  0xb4,  0x00,
-  0x98,  0x57,  0xd0,  0x01,  0x0c,  0x1c,  0x3e,  0x1c,  0x0c,  0x00,  0xbb,  0x00,  0xaa,  0x18,  0x02,  0x80,
-  0x32,  0xf0,  0x01,  0xfc,  0x88,  0x0c,  0xc6,  0x12,  0x02,  0x13,  0x18,  0x40,  0x00,  0x57,  0x01,  0xea,
-  0x3c,  0x00,  0x6c,  0x01,  0x6e,  0x01,  0x04,  0x12,  0x3e,  0x57,  0x00,  0x80,  0x03,  0xe6,  0xb6,  0x00,
-  0xc0,  0x00,  0x01,  0x01,  0x3e,  0x01,  0xda,  0x0f,  0x22,  0x10,  0x08,  0x12,  0x02,  0x4a,  0xb9,  0x54,
-  0x03,  0x58,  0x1b,  0x80,  0x30,  0xe4,  0x4b,  0xe4,  0x20,  0x00,  0x32,  0x00,  0x3e,  0x00,  0x80,  0x00,
-  0x24,  0x01,  0x3c,  0x01,  0x68,  0x01,  0x6a,  0x01,  0x70,  0x01,  0x72,  0x01,  0x74,  0x01,  0x76,  0x01,
-  0x78,  0x01,  0x62,  0x0a,  0x92,  0x0c,  0x2c,  0x10,  0x2e,  0x10,  0x06,  0x13,  0x4c,  0x1c,  0xbb,  0x55,
-  0x3c,  0x56,  0x04,  0x80,  0x4a,  0xe4,  0x02,  0xee,  0x5b,  0xf0,  0xb1,  0xf0,  0x03,  0xf7,  0x06,  0xf7,
-  0x03,  0xfc,  0x0f,  0x00,  0x40,  0x00,  0xbe,  0x00,  0x00,  0x01,  0xb0,  0x08,  0x30,  0x13,  0x64,  0x15,
-  0x32,  0x1c,  0x38,  0x1c,  0x4e,  0x1c,  0x10,  0x44,  0x02,  0x48,  0x00,  0x4c,  0x04,  0xea,  0x5d,  0xf0,
-  0x04,  0xf6,  0x02,  0xfc,  0x05,  0x00,  0x34,  0x00,  0x36,  0x00,  0x98,  0x00,  0xcc,  0x00,  0x20,  0x01,
-  0x4e,  0x01,  0x4e,  0x0b,  0x1e,  0x0e,  0x0c,  0x10,  0x0a,  0x12,  0x04,  0x13,  0x40,  0x13,  0x30,  0x1c,
-  0x00,  0x4e,  0xbd,  0x56,  0x06,  0x83,  0x00,  0xdc,  0x05,  0xf0,  0x09,  0xf0,  0x59,  0xf0,  0xa7,  0xf0,
-  0xb8,  0xf0,  0x0e,  0xf7,  0x06,  0x00,  0x19,  0x00,  0x33,  0x00,  0x9b,  0x00,  0xa4,  0x00,  0xb5,  0x00,
-  0xba,  0x00,  0xd0,  0x00,  0xe1,  0x00,  0xe7,  0x00,  0xde,  0x03,  0x56,  0x0a,  0x14,  0x0e,  0x02,  0x10,
-  0x04,  0x10,  0x0a,  0x10,  0x36,  0x10,  0x0a,  0x13,  0x12,  0x13,  0x52,  0x13,  0x10,  0x15,  0x14,  0x15,
-  0xac,  0x16,  0x20,  0x1c,  0x34,  0x1c,  0x36,  0x1c,  0x08,  0x44,  0x38,  0x44,  0x91,  0x44,  0x0a,  0x45,
-  0x48,  0x46,  0x01,  0x48,  0x68,  0x54,  0x83,  0x55,  0xb0,  0x57,  0x01,  0x58,  0x83,  0x59,  0x05,  0xe6,
-  0x0b,  0xf0,  0x0c,  0xf0,  0x5c,  0xf0,  0x4b,  0xf4,  0x04,  0xf8,  0x05,  0xf8,  0x02,  0xfa,  0x03,  0xfa,
-  0x04,  0xfc,  0x05,  0xfc,  0x07,  0x00,  0x0a,  0x00,  0x0d,  0x00,  0x1c,  0x00,  0x9e,  0x00,  0xa8,  0x00,
-  0xaa,  0x00,  0xb9,  0x00,  0xe0,  0x00,  0x22,  0x01,  0x26,  0x01,  0x79,  0x01,  0x7a,  0x01,  0xc0,  0x01,
-  0xc2,  0x01,  0x7c,  0x02,  0x5a,  0x03,  0xea,  0x04,  0xe8,  0x07,  0x68,  0x08,  0x69,  0x08,  0xba,  0x08,
-  0xe9,  0x09,  0x06,  0x0b,  0x3a,  0x0e,  0x00,  0x10,  0x1a,  0x10,  0xed,  0x10,  0xf1,  0x10,  0x06,  0x12,
-  0x0c,  0x13,  0x16,  0x13,  0x1e,  0x13,  0x82,  0x13,  0x42,  0x14,  0xd6,  0x14,  0x8a,  0x15,  0xc6,  0x17,
-  0xd2,  0x17,  0x6b,  0x18,  0x12,  0x1c,  0x46,  0x1c,  0x9c,  0x32,  0x00,  0x40,  0x0e,  0x47,  0x48,  0x47,
-  0x41,  0x48,  0x89,  0x48,  0x80,  0x4c,  0x00,  0x54,  0x44,  0x55,  0xe5,  0x55,  0x14,  0x56,  0x77,  0x57,
-  0xbf,  0x57,  0x40,  0x5c,  0x06,  0x80,  0x08,  0x90,  0x03,  0xa1,  0xfe,  0x9c,  0xf0,  0x29,  0x02,  0xfe,
-  0xb8,  0x0c,  0xff,  0x10,  0x00,  0x00,  0xd0,  0xfe,  0xcc,  0x18,  0x00,  0xcf,  0xfe,  0x80,  0x01,  0xff,
-  0x03,  0x00,  0x00,  0xfe,  0x93,  0x15,  0xfe,  0x0f,  0x05,  0xff,  0x38,  0x00,  0x00,  0xfe,  0x57,  0x24,
-  0x00,  0xfe,  0x48,  0x00,  0x4f,  0xff,  0x04,  0x00,  0x00,  0x10,  0xff,  0x09,  0x00,  0x00,  0xff,  0x08,
-  0x01,  0x01,  0xff,  0x08,  0xff,  0xff,  0xff,  0x27,  0x00,  0x00,  0xff,  0x10,  0xff,  0xff,  0xff,  0x0f,
-  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,  0xff,  0x21,  0x00,  0x00,  0xfe,  0x04,  0xf7,  0xcf,
-  0x2a,  0x67,  0x0b,  0x01,  0xfe,  0xce,  0x0e,  0xfe,  0x04,  0xf7,  0xcf,  0x67,  0x0b,  0x3c,  0x2a,  0xfe,
-  0x3d,  0xf0,  0xfe,  0x02,  0x02,  0xfe,  0x20,  0xf0,  0x9c,  0xfe,  0x91,  0xf0,  0xfe,  0xf0,  0x01,  0xfe,
-  0x90,  0xf0,  0xfe,  0xf0,  0x01,  0xfe,  0x8f,  0xf0,  0x9c,  0x05,  0x51,  0x3b,  0x02,  0xfe,  0xd4,  0x0c,
-  0x01,  0xfe,  0x44,  0x0d,  0xfe,  0xdd,  0x12,  0xfe,  0xfc,  0x10,  0xfe,  0x28,  0x1c,  0x05,  0xfe,  0xa6,
-  0x00,  0xfe,  0xd3,  0x12,  0x47,  0x18,  0xfe,  0xa6,  0x00,  0xb5,  0xfe,  0x48,  0xf0,  0xfe,  0x86,  0x02,
-  0xfe,  0x49,  0xf0,  0xfe,  0xa0,  0x02,  0xfe,  0x4a,  0xf0,  0xfe,  0xbe,  0x02,  0xfe,  0x46,  0xf0,  0xfe,
-  0x50,  0x02,  0xfe,  0x47,  0xf0,  0xfe,  0x56,  0x02,  0xfe,  0x43,  0xf0,  0xfe,  0x44,  0x02,  0xfe,  0x44,
-  0xf0,  0xfe,  0x48,  0x02,  0xfe,  0x45,  0xf0,  0xfe,  0x4c,  0x02,  0x17,  0x0b,  0xa0,  0x17,  0x06,  0x18,
-  0x96,  0x02,  0x29,  0xfe,  0x00,  0x1c,  0xde,  0xfe,  0x02,  0x1c,  0xdd,  0xfe,  0x1e,  0x1c,  0xfe,  0xe9,
-  0x10,  0x01,  0xfe,  0x20,  0x17,  0xfe,  0xe7,  0x10,  0xfe,  0x06,  0xfc,  0xc7,  0x0a,  0x6b,  0x01,  0x9e,
-  0x02,  0x29,  0x14,  0x4d,  0x37,  0x97,  0x01,  0xfe,  0x64,  0x0f,  0x0a,  0x6b,  0x01,  0x82,  0xfe,  0xbd,
-  0x10,  0x0a,  0x6b,  0x01,  0x82,  0xfe,  0xad,  0x10,  0xfe,  0x16,  0x1c,  0xfe,  0x58,  0x1c,  0x17,  0x06,
-  0x18,  0x96,  0x2a,  0x25,  0x29,  0xfe,  0x3d,  0xf0,  0xfe,  0x02,  0x02,  0x21,  0xfe,  0x94,  0x02,  0xfe,
-  0x5a,  0x1c,  0xea,  0xfe,  0x14,  0x1c,  0x14,  0xfe,  0x30,  0x00,  0x37,  0x97,  0x01,  0xfe,  0x54,  0x0f,
-  0x17,  0x06,  0x18,  0x96,  0x02,  0xd0,  0x1e,  0x20,  0x07,  0x10,  0x34,  0xfe,  0x69,  0x10,  0x17,  0x06,
-  0x18,  0x96,  0xfe,  0x04,  0xec,  0x20,  0x46,  0x3d,  0x12,  0x20,  0xfe,  0x05,  0xf6,  0xc7,  0x01,  0xfe,
-  0x52,  0x16,  0x09,  0x4a,  0x4c,  0x35,  0x11,  0x2d,  0x3c,  0x8a,  0x01,  0xe6,  0x02,  0x29,  0x0a,  0x40,
-  0x01,  0x0e,  0x07,  0x00,  0x5d,  0x01,  0x6f,  0xfe,  0x18,  0x10,  0xfe,  0x41,  0x58,  0x0a,  0x99,  0x01,
-  0x0e,  0xfe,  0xc8,  0x54,  0x64,  0xfe,  0x0c,  0x03,  0x01,  0xe6,  0x02,  0x29,  0x2a,  0x46,  0xfe,  0x02,
-  0xe8,  0x27,  0xf8,  0xfe,  0x9e,  0x43,  0xf7,  0xfe,  0x27,  0xf0,  0xfe,  0xdc,  0x01,  0xfe,  0x07,  0x4b,
-  0xfe,  0x20,  0xf0,  0x9c,  0xfe,  0x40,  0x1c,  0x25,  0xd2,  0xfe,  0x26,  0xf0,  0xfe,  0x56,  0x03,  0xfe,
-  0xa0,  0xf0,  0xfe,  0x44,  0x03,  0xfe,  0x11,  0xf0,  0x9c,  0xfe,  0xef,  0x10,  0xfe,  0x9f,  0xf0,  0xfe,
-  0x64,  0x03,  0xeb,  0x0f,  0xfe,  0x11,  0x00,  0x02,  0x5a,  0x2a,  0xfe,  0x48,  0x1c,  0xeb,  0x09,  0x04,
-  0x1d,  0xfe,  0x18,  0x13,  0x23,  0x1e,  0x98,  0xac,  0x12,  0x98,  0x0a,  0x40,  0x01,  0x0e,  0xac,  0x75,
-  0x01,  0xfe,  0xbc,  0x15,  0x11,  0xca,  0x25,  0xd2,  0xfe,  0x01,  0xf0,  0xd2,  0xfe,  0x82,  0xf0,  0xfe,
-  0x92,  0x03,  0xec,  0x11,  0xfe,  0xe4,  0x00,  0x65,  0xfe,  0xa4,  0x03,  0x25,  0x32,  0x1f,  0xfe,  0xb4,
-  0x03,  0x01,  0x43,  0xfe,  0x06,  0xf0,  0xfe,  0xc4,  0x03,  0x8d,  0x81,  0xfe,  0x0a,  0xf0,  0xfe,  0x7a,
-  0x06,  0x02,  0x22,  0x05,  0x6b,  0x28,  0x16,  0xfe,  0xf6,  0x04,  0x14,  0x2c,  0x01,  0x33,  0x8f,  0xfe,
-  0x66,  0x02,  0x02,  0xd1,  0xeb,  0x2a,  0x67,  0x1a,  0xfe,  0x67,  0x1b,  0xf8,  0xf7,  0xfe,  0x48,  0x1c,
-  0x70,  0x01,  0x6e,  0x87,  0x0a,  0x40,  0x01,  0x0e,  0x07,  0x00,  0x16,  0xd3,  0x0a,  0xca,  0x01,  0x0e,
-  0x74,  0x60,  0x59,  0x76,  0x27,  0x05,  0x6b,  0x28,  0xfe,  0x10,  0x12,  0x14,  0x2c,  0x01,  0x33,  0x8f,
-  0xfe,  0x66,  0x02,  0x02,  0xd1,  0xbc,  0x7d,  0xbd,  0x7f,  0x25,  0x22,  0x65,  0xfe,  0x3c,  0x04,  0x1f,
-  0xfe,  0x38,  0x04,  0x68,  0xfe,  0xa0,  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x4e,  0x12,  0x2b,  0xff,  0x02,
-  0x00,  0x10,  0x01,  0x08,  0x1f,  0xfe,  0xe0,  0x04,  0x2b,  0x01,  0x08,  0x1f,  0x22,  0x30,  0x2e,  0xd5,
-  0xfe,  0x4c,  0x44,  0xfe,  0x4c,  0x12,  0x60,  0xfe,  0x44,  0x48,  0x13,  0x2c,  0xfe,  0x4c,  0x54,  0x64,
-  0xd3,  0x46,  0x76,  0x27,  0xfa,  0xef,  0xfe,  0x62,  0x13,  0x09,  0x04,  0x1d,  0xfe,  0x2a,  0x13,  0x2f,
-  0x07,  0x7e,  0xa5,  0xfe,  0x20,  0x10,  0x13,  0x2c,  0xfe,  0x4c,  0x54,  0x64,  0xd3,  0xfa,  0xef,  0x86,
-  0x09,  0x04,  0x1d,  0xfe,  0x08,  0x13,  0x2f,  0x07,  0x7e,  0x6e,  0x09,  0x04,  0x1d,  0xfe,  0x1c,  0x12,
-  0x14,  0x92,  0x09,  0x04,  0x06,  0x3b,  0x14,  0xc4,  0x01,  0x33,  0x8f,  0xfe,  0x70,  0x0c,  0x02,  0x22,
-  0x2b,  0x11,  0xfe,  0xe6,  0x00,  0xfe,  0x1c,  0x90,  0xf9,  0x03,  0x14,  0x92,  0x01,  0x33,  0x02,  0x29,
-  0xfe,  0x42,  0x5b,  0x67,  0x1a,  0xfe,  0x46,  0x59,  0xf8,  0xf7,  0xfe,  0x87,  0x80,  0xfe,  0x31,  0xe4,
-  0x4f,  0x09,  0x04,  0x0b,  0xfe,  0x78,  0x13,  0xfe,  0x20,  0x80,  0x07,  0x1a,  0xfe,  0x70,  0x12,  0x49,
-  0x04,  0x06,  0xfe,  0x60,  0x13,  0x05,  0xfe,  0xa2,  0x00,  0x28,  0x16,  0xfe,  0x80,  0x05,  0xfe,  0x31,
-  0xe4,  0x6a,  0x49,  0x04,  0x0b,  0xfe,  0x4a,  0x13,  0x05,  0xfe,  0xa0,  0x00,  0x28,  0xfe,  0x42,  0x12,
-  0x5e,  0x01,  0x08,  0x25,  0x32,  0xf1,  0x01,  0x08,  0x26,  0xfe,  0x98,  0x05,  0x11,  0xfe,  0xe3,  0x00,
-  0x23,  0x49,  0xfe,  0x4a,  0xf0,  0xfe,  0x6a,  0x05,  0xfe,  0x49,  0xf0,  0xfe,  0x64,  0x05,  0x83,  0x24,
-  0xfe,  0x21,  0x00,  0xa1,  0x24,  0xfe,  0x22,  0x00,  0xa0,  0x24,  0x4c,  0xfe,  0x09,  0x48,  0x01,  0x08,
-  0x26,  0xfe,  0x98,  0x05,  0xfe,  0xe2,  0x08,  0x49,  0x04,  0xc5,  0x3b,  0x01,  0x86,  0x24,  0x06,  0x12,
-  0xcc,  0x37,  0xfe,  0x27,  0x01,  0x09,  0x04,  0x1d,  0xfe,  0x22,  0x12,  0x47,  0x01,  0xa7,  0x14,  0x92,
-  0x09,  0x04,  0x06,  0x3b,  0x14,  0xc4,  0x01,  0x33,  0x8f,  0xfe,  0x70,  0x0c,  0x02,  0x22,  0x05,  0xfe,
-  0x9c,  0x00,  0x28,  0xfe,  0x3e,  0x12,  0x05,  0x50,  0x28,  0xfe,  0x36,  0x13,  0x47,  0x01,  0xa7,  0x26,
-  0xfe,  0x08,  0x06,  0x0a,  0x06,  0x49,  0x04,  0x19,  0xfe,  0x02,  0x12,  0x5f,  0x01,  0xfe,  0xaa,  0x14,
-  0x1f,  0xfe,  0xfe,  0x05,  0x11,  0x9a,  0x01,  0x43,  0x11,  0xfe,  0xe5,  0x00,  0x05,  0x50,  0xb4,  0x0c,
-  0x50,  0x05,  0xc6,  0x28,  0xfe,  0x62,  0x12,  0x05,  0x3f,  0x28,  0xfe,  0x5a,  0x13,  0x01,  0xfe,  0x14,
-  0x18,  0x01,  0xfe,  0x66,  0x18,  0xfe,  0x43,  0x48,  0xb7,  0x19,  0x13,  0x6c,  0xff,  0x02,  0x00,  0x57,
-  0x48,  0x8b,  0x1c,  0x3d,  0x85,  0xb7,  0x69,  0x47,  0x01,  0xa7,  0x26,  0xfe,  0x72,  0x06,  0x49,  0x04,
-  0x1b,  0xdf,  0x89,  0x0a,  0x4d,  0x01,  0xfe,  0xd8,  0x14,  0x1f,  0xfe,  0x68,  0x06,  0x11,  0x9a,  0x01,
-  0x43,  0x11,  0xfe,  0xe5,  0x00,  0x05,  0x3f,  0xb4,  0x0c,  0x3f,  0x17,  0x06,  0x01,  0xa7,  0xec,  0x72,
-  0x70,  0x01,  0x6e,  0x87,  0x11,  0xfe,  0xe2,  0x00,  0x01,  0x08,  0x25,  0x32,  0xfe,  0x0a,  0xf0,  0xfe,
-  0xa6,  0x06,  0x8c,  0xfe,  0x5c,  0x07,  0xfe,  0x06,  0xf0,  0xfe,  0x64,  0x07,  0x8d,  0x81,  0x02,  0x22,
-  0x09,  0x04,  0x0b,  0xfe,  0x2e,  0x12,  0x15,  0x1a,  0x01,  0x08,  0x15,  0x00,  0x01,  0x08,  0x15,  0x00,
-  0x01,  0x08,  0x15,  0x00,  0x01,  0x08,  0xfe,  0x99,  0xa4,  0x01,  0x08,  0x15,  0x00,  0x02,  0xfe,  0x32,
-  0x08,  0x61,  0x04,  0x1b,  0xfe,  0x38,  0x12,  0x09,  0x04,  0x1b,  0x6e,  0x15,  0xfe,  0x1b,  0x00,  0x01,
-  0x08,  0x15,  0x00,  0x01,  0x08,  0x15,  0x00,  0x01,  0x08,  0x15,  0x00,  0x01,  0x08,  0x15,  0x06,  0x01,
-  0x08,  0x15,  0x00,  0x02,  0xd9,  0x66,  0x4c,  0xfe,  0x3a,  0x55,  0x5f,  0xfe,  0x9a,  0x81,  0x4b,  0x1d,
-  0xba,  0xfe,  0x32,  0x07,  0x0a,  0x1d,  0xfe,  0x09,  0x6f,  0xaf,  0xfe,  0xca,  0x45,  0xfe,  0x32,  0x12,
-  0x62,  0x2c,  0x85,  0x66,  0x7b,  0x01,  0x08,  0x25,  0x32,  0xfe,  0x0a,  0xf0,  0xfe,  0x32,  0x07,  0x8d,
-  0x81,  0x8c,  0xfe,  0x5c,  0x07,  0x02,  0x22,  0x01,  0x43,  0x02,  0xfe,  0x8a,  0x06,  0x15,  0x19,  0x02,
-  0xfe,  0x8a,  0x06,  0xfe,  0x9c,  0xf7,  0xd4,  0xfe,  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x77,  0xfe,  0xca,
-  0x07,  0x0c,  0x54,  0x18,  0x55,  0x09,  0x4a,  0x6a,  0x35,  0x1e,  0x20,  0x07,  0x10,  0xfe,  0x0e,  0x12,
-  0x74,  0xfe,  0x80,  0x80,  0x37,  0x20,  0x63,  0x27,  0xfe,  0x06,  0x10,  0xfe,  0x83,  0xe7,  0xc4,  0xa1,
-  0xfe,  0x03,  0x40,  0x09,  0x4a,  0x4f,  0x35,  0x01,  0xa8,  0xad,  0xfe,  0x1f,  0x40,  0x12,  0x58,  0x01,
-  0xa5,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0xfe,  0x44,  0x51,  0xfe,  0xc6,  0x51,  0x83,  0xfb,  0xfe,
-  0x8a,  0x90,  0x0c,  0x52,  0x18,  0x53,  0xfe,  0x0c,  0x90,  0xfe,  0x8e,  0x90,  0xfe,  0x40,  0x50,  0xfe,
-  0xc2,  0x50,  0x0c,  0x39,  0x18,  0x3a,  0xfe,  0x4a,  0x10,  0x09,  0x04,  0x6a,  0xfe,  0x2a,  0x12,  0xfe,
-  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x0c,  0x54,  0x18,  0x55,  0x09,  0x04,  0x4f,  0x85,  0x01,  0xa8,  0xfe,
-  0x1f,  0x80,  0x12,  0x58,  0xfe,  0x44,  0x90,  0xfe,  0xc6,  0x90,  0x0c,  0x56,  0x18,  0x57,  0xfb,  0xfe,
-  0x8a,  0x90,  0x0c,  0x52,  0x18,  0x53,  0xfe,  0x40,  0x90,  0xfe,  0xc2,  0x90,  0x0c,  0x39,  0x18,  0x3a,
-  0x0c,  0x38,  0x18,  0x4e,  0x09,  0x4a,  0x19,  0x35,  0x2a,  0x13,  0xfe,  0x4e,  0x11,  0x65,  0xfe,  0x48,
-  0x08,  0xfe,  0x9e,  0xf0,  0xfe,  0x5c,  0x08,  0xb1,  0x16,  0x32,  0x2a,  0x73,  0xdd,  0xb8,  0xfe,  0x80,
-  0x08,  0xb9,  0xfe,  0x9e,  0x08,  0x8c,  0xfe,  0x74,  0x08,  0xfe,  0x06,  0xf0,  0xfe,  0x7a,  0x08,  0x8d,
-  0x81,  0x02,  0x22,  0x01,  0x43,  0xfe,  0xc9,  0x10,  0x15,  0x19,  0xfe,  0xc9,  0x10,  0x61,  0x04,  0x06,
-  0xfe,  0x10,  0x12,  0x61,  0x04,  0x0b,  0x45,  0x09,  0x04,  0x0b,  0xfe,  0x68,  0x12,  0xfe,  0x2e,  0x1c,
-  0x02,  0xfe,  0x24,  0x0a,  0x61,  0x04,  0x06,  0x45,  0x61,  0x04,  0x0b,  0xfe,  0x52,  0x12,  0xfe,  0x2c,
-  0x1c,  0xfe,  0xaa,  0xf0,  0xfe,  0x1e,  0x09,  0xfe,  0xac,  0xf0,  0xfe,  0xbe,  0x08,  0xfe,  0x8a,  0x10,
-  0xaa,  0xfe,  0xf3,  0x10,  0xfe,  0xad,  0xf0,  0xfe,  0xca,  0x08,  0x02,  0xfe,  0x24,  0x0a,  0xab,  0xfe,
-  0xe7,  0x10,  0xfe,  0x2b,  0xf0,  0x9d,  0xe9,  0x1c,  0xfe,  0x00,  0xfe,  0xfe,  0x1c,  0x12,  0xb5,  0xfe,
-  0xd2,  0xf0,  0x9d,  0xfe,  0x76,  0x18,  0x1c,  0x1a,  0x16,  0x9d,  0x05,  0xcb,  0x1c,  0x06,  0x16,  0x9d,
-  0xb8,  0x6d,  0xb9,  0x6d,  0xaa,  0xab,  0xfe,  0xb1,  0x10,  0x70,  0x5e,  0x2b,  0x14,  0x92,  0x01,  0x33,
-  0x0f,  0xfe,  0x35,  0x00,  0xfe,  0x01,  0xf0,  0x5a,  0x0f,  0x7c,  0x02,  0x5a,  0xfe,  0x74,  0x18,  0x1c,
-  0xfe,  0x00,  0xf8,  0x16,  0x6d,  0x67,  0x1b,  0x01,  0xfe,  0x44,  0x0d,  0x3b,  0x01,  0xe6,  0x1e,  0x27,
-  0x74,  0x67,  0x1a,  0x02,  0x6d,  0x09,  0x04,  0x0b,  0x21,  0xfe,  0x06,  0x0a,  0x09,  0x04,  0x6a,  0xfe,
-  0x82,  0x12,  0x09,  0x04,  0x19,  0xfe,  0x66,  0x13,  0x1e,  0x58,  0xac,  0xfc,  0xfe,  0x83,  0x80,  0xfe,
-  0xc8,  0x44,  0xfe,  0x2e,  0x13,  0xfe,  0x04,  0x91,  0xfe,  0x86,  0x91,  0x63,  0x27,  0xfe,  0x40,  0x59,
-  0xfe,  0xc1,  0x59,  0x77,  0xd7,  0x05,  0x54,  0x31,  0x55,  0x0c,  0x7b,  0x18,  0x7c,  0xbe,  0x54,  0xbf,
-  0x55,  0x01,  0xa8,  0xad,  0x63,  0x27,  0x12,  0x58,  0xc0,  0x38,  0xc1,  0x4e,  0x79,  0x56,  0x68,  0x57,
-  0xf4,  0xf5,  0xfe,  0x04,  0xfa,  0x38,  0xfe,  0x05,  0xfa,  0x4e,  0x01,  0xa5,  0xa2,  0x23,  0x0c,  0x7b,
-  0x0c,  0x7c,  0x79,  0x56,  0x68,  0x57,  0xfe,  0x12,  0x10,  0x09,  0x04,  0x19,  0x16,  0xd7,  0x79,  0x39,
-  0x68,  0x3a,  0x09,  0x04,  0xfe,  0xf7,  0x00,  0x35,  0x05,  0x52,  0x31,  0x53,  0xfe,  0x10,  0x58,  0xfe,
-  0x91,  0x58,  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0x02,  0x6d,  0x09,  0x04,  0x19,  0x16,  0xd7,  0x09,
-  0x04,  0xfe,  0xf7,  0x00,  0x35,  0xfe,  0x3a,  0x55,  0xfe,  0x19,  0x81,  0x5f,  0xfe,  0x10,  0x90,  0xfe,
-  0x92,  0x90,  0xfe,  0xd7,  0x10,  0x2f,  0x07,  0x9b,  0x16,  0xfe,  0xc6,  0x08,  0x11,  0x9b,  0x09,  0x04,
-  0x0b,  0xfe,  0x14,  0x13,  0x05,  0x39,  0x31,  0x3a,  0x77,  0xfe,  0xc6,  0x08,  0xfe,  0x0c,  0x58,  0xfe,
-  0x8d,  0x58,  0x02,  0x6d,  0x23,  0x47,  0xfe,  0x19,  0x80,  0xde,  0x09,  0x04,  0x0b,  0xfe,  0x1a,  0x12,
-  0xfe,  0x6c,  0x19,  0xfe,  0x19,  0x41,  0xe9,  0xb5,  0xfe,  0xd1,  0xf0,  0xd9,  0x14,  0x7a,  0x01,  0x33,
-  0x0f,  0xfe,  0x44,  0x00,  0xfe,  0x8e,  0x10,  0xfe,  0x6c,  0x19,  0xbe,  0x39,  0xfe,  0xed,  0x19,  0xbf,
-  0x3a,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0xe9,  0x1c,  0xfe,  0x00,  0xff,  0x34,  0xfe,  0x74,  0x10,
-  0xb5,  0xfe,  0xd2,  0xf0,  0xfe,  0xb2,  0x0a,  0xfe,  0x76,  0x18,  0x1c,  0x1a,  0x84,  0x05,  0xcb,  0x1c,
-  0x06,  0xfe,  0x08,  0x13,  0x0f,  0xfe,  0x16,  0x00,  0x02,  0x5a,  0xfe,  0xd1,  0xf0,  0xfe,  0xc4,  0x0a,
-  0x14,  0x7a,  0x01,  0x33,  0x0f,  0xfe,  0x17,  0x00,  0xfe,  0x42,  0x10,  0xfe,  0xce,  0xf0,  0xfe,  0xca,
-  0x0a,  0xfe,  0x3c,  0x10,  0xfe,  0xcd,  0xf0,  0xfe,  0xd6,  0x0a,  0x0f,  0xfe,  0x22,  0x00,  0x02,  0x5a,
-  0xfe,  0xcb,  0xf0,  0xfe,  0xe2,  0x0a,  0x0f,  0xfe,  0x24,  0x00,  0x02,  0x5a,  0xfe,  0xd0,  0xf0,  0xfe,
-  0xec,  0x0a,  0x0f,  0x93,  0xdc,  0xfe,  0xcf,  0xf0,  0xfe,  0xf6,  0x0a,  0x0f,  0x4c,  0xfe,  0x10,  0x10,
-  0xfe,  0xcc,  0xf0,  0xd9,  0x61,  0x04,  0x19,  0x3b,  0x0f,  0xfe,  0x12,  0x00,  0x2a,  0x13,  0xfe,  0x4e,
-  0x11,  0x65,  0xfe,  0x0c,  0x0b,  0xfe,  0x9e,  0xf0,  0xfe,  0x20,  0x0b,  0xb1,  0x16,  0x32,  0x2a,  0x73,
-  0xdd,  0xb8,  0x22,  0xb9,  0x22,  0x2a,  0xec,  0x65,  0xfe,  0x2c,  0x0b,  0x25,  0x32,  0x8c,  0xfe,  0x48,
-  0x0b,  0x8d,  0x81,  0xb8,  0xd4,  0xb9,  0xd4,  0x02,  0x22,  0x01,  0x43,  0xfe,  0xdb,  0x10,  0x11,  0xfe,
-  0xe8,  0x00,  0xaa,  0xab,  0x70,  0xbc,  0x7d,  0xbd,  0x7f,  0xfe,  0x89,  0xf0,  0x22,  0x30,  0x2e,  0xd8,
-  0xbc,  0x7d,  0xbd,  0x7f,  0x01,  0x08,  0x1f,  0x22,  0x30,  0x2e,  0xd6,  0xb1,  0x45,  0x0f,  0xfe,  0x42,
-  0x00,  0x02,  0x5a,  0x78,  0x06,  0xfe,  0x81,  0x49,  0x16,  0xfe,  0x38,  0x0c,  0x09,  0x04,  0x0b,  0xfe,
-  0x44,  0x13,  0x0f,  0x00,  0x4b,  0x0b,  0xfe,  0x54,  0x12,  0x4b,  0xfe,  0x28,  0x00,  0x21,  0xfe,  0xa6,
-  0x0c,  0x0a,  0x40,  0x01,  0x0e,  0x07,  0x00,  0x5d,  0x3e,  0xfe,  0x28,  0x00,  0xfe,  0xe2,  0x10,  0x01,
-  0xe7,  0x01,  0xe8,  0x0a,  0x99,  0x01,  0xfe,  0x32,  0x0e,  0x59,  0x11,  0x2d,  0x01,  0x6f,  0x02,  0x29,
-  0x0f,  0xfe,  0x44,  0x00,  0x4b,  0x0b,  0xdf,  0x3e,  0x0b,  0xfe,  0xb4,  0x10,  0x01,  0x86,  0x3e,  0x0b,
-  0xfe,  0xaa,  0x10,  0x01,  0x86,  0xfe,  0x19,  0x82,  0xfe,  0x34,  0x46,  0xa3,  0x3e,  0x0b,  0x0f,  0xfe,
-  0x43,  0x00,  0xfe,  0x96,  0x10,  0x09,  0x4a,  0x0b,  0x35,  0x01,  0xe7,  0x01,  0xe8,  0x59,  0x11,  0x2d,
-  0x01,  0x6f,  0x67,  0x0b,  0x59,  0x3c,  0x8a,  0x02,  0xfe,  0x2a,  0x03,  0x09,  0x04,  0x0b,  0x84,  0x3e,
-  0x0b,  0x0f,  0x00,  0xfe,  0x5c,  0x10,  0x61,  0x04,  0x1b,  0xfe,  0x58,  0x12,  0x09,  0x04,  0x1b,  0xfe,
-  0x50,  0x13,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x5c,  0x0c,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,
-  0xf0,  0xfe,  0x62,  0x0c,  0x09,  0x4a,  0x1b,  0x35,  0xfe,  0xa9,  0x10,  0x0f,  0xfe,  0x15,  0x00,  0xfe,
-  0x04,  0xe6,  0x0b,  0x5f,  0x5c,  0x0f,  0xfe,  0x13,  0x00,  0xfe,  0x10,  0x10,  0x0f,  0xfe,  0x47,  0x00,
-  0xa1,  0x0f,  0xfe,  0x41,  0x00,  0xa0,  0x0f,  0xfe,  0x24,  0x00,  0x87,  0xaa,  0xab,  0x70,  0x05,  0x6b,
-  0x28,  0x21,  0xd1,  0x5f,  0xfe,  0x04,  0xe6,  0x1b,  0xfe,  0x9d,  0x41,  0xfe,  0x1c,  0x42,  0x59,  0x01,
-  0xda,  0x02,  0x29,  0xea,  0x14,  0x0b,  0x37,  0x95,  0xa9,  0x14,  0xfe,  0x31,  0x00,  0x37,  0x97,  0x01,
-  0xfe,  0x54,  0x0f,  0x02,  0xd0,  0x3c,  0xfe,  0x06,  0xec,  0xc9,  0xee,  0x3e,  0x1d,  0xfe,  0xce,  0x45,
-  0x34,  0x3c,  0xfe,  0x06,  0xea,  0xc9,  0xfe,  0x47,  0x4b,  0x89,  0xfe,  0x75,  0x57,  0x05,  0x51,  0xfe,
-  0x98,  0x56,  0xfe,  0x38,  0x12,  0x0a,  0x42,  0x01,  0x0e,  0xfe,  0x44,  0x48,  0x46,  0x09,  0x04,  0x1d,
-  0xfe,  0x1a,  0x13,  0x0a,  0x40,  0x01,  0x0e,  0x47,  0xfe,  0x41,  0x58,  0x0a,  0x99,  0x01,  0x0e,  0xfe,
-  0x49,  0x54,  0x8e,  0xfe,  0x2a,  0x0d,  0x02,  0xfe,  0x2a,  0x03,  0x0a,  0x51,  0xfe,  0xee,  0x14,  0xee,
-  0x3e,  0x1d,  0xfe,  0xce,  0x45,  0x34,  0x3c,  0xfe,  0xce,  0x47,  0xfe,  0xad,  0x13,  0x02,  0x29,  0x1e,
-  0x20,  0x07,  0x10,  0xfe,  0x9e,  0x12,  0x23,  0x12,  0x4d,  0x12,  0x94,  0x12,  0xce,  0x1e,  0x2d,  0x47,
-  0x37,  0x2d,  0xb1,  0xe0,  0xfe,  0xbc,  0xf0,  0xfe,  0xec,  0x0d,  0x13,  0x06,  0x12,  0x4d,  0x01,  0xfe,
-  0xe2,  0x15,  0x05,  0xfe,  0x38,  0x01,  0x31,  0xfe,  0x3a,  0x01,  0x77,  0xfe,  0xf0,  0x0d,  0xfe,  0x02,
-  0xec,  0xce,  0x62,  0x00,  0x5d,  0xfe,  0x04,  0xec,  0x20,  0x46,  0xfe,  0x05,  0xf6,  0xfe,  0x34,  0x01,
-  0x01,  0xfe,  0x52,  0x16,  0xfb,  0xfe,  0x48,  0xf4,  0x0d,  0xfe,  0x18,  0x13,  0xaf,  0xfe,  0x02,  0xea,
-  0xce,  0x62,  0x7a,  0xfe,  0xc5,  0x13,  0x14,  0x1b,  0x37,  0x95,  0xa9,  0x5c,  0x05,  0xfe,  0x38,  0x01,
-  0x1c,  0xfe,  0xf0,  0xff,  0x0c,  0xfe,  0x60,  0x01,  0x05,  0xfe,  0x3a,  0x01,  0x0c,  0xfe,  0x62,  0x01,
-  0x3d,  0x12,  0x20,  0x24,  0x06,  0x12,  0x2d,  0x11,  0x2d,  0x8a,  0x13,  0x06,  0x03,  0x23,  0x03,  0x1e,
-  0x4d,  0xfe,  0xf7,  0x12,  0x1e,  0x94,  0xac,  0x12,  0x94,  0x07,  0x7a,  0xfe,  0x71,  0x13,  0xfe,  0x24,
-  0x1c,  0x14,  0x1a,  0x37,  0x95,  0xa9,  0xfe,  0xd9,  0x10,  0xb6,  0xfe,  0x03,  0xdc,  0xfe,  0x73,  0x57,
-  0xfe,  0x80,  0x5d,  0x03,  0xb6,  0xfe,  0x03,  0xdc,  0xfe,  0x5b,  0x57,  0xfe,  0x80,  0x5d,  0x03,  0xfe,
-  0x03,  0x57,  0xb6,  0x23,  0xfe,  0x00,  0xcc,  0x03,  0xfe,  0x03,  0x57,  0xb6,  0x75,  0x03,  0x09,  0x04,
-  0x4c,  0xfe,  0x22,  0x13,  0xfe,  0x1c,  0x80,  0x07,  0x06,  0xfe,  0x1a,  0x13,  0xfe,  0x1e,  0x80,  0xe1,
-  0xfe,  0x1d,  0x80,  0xa4,  0xfe,  0x0c,  0x90,  0xfe,  0x0e,  0x13,  0xfe,  0x0e,  0x90,  0xa3,  0xfe,  0x3c,
-  0x90,  0xfe,  0x30,  0xf4,  0x0b,  0xfe,  0x3c,  0x50,  0xa0,  0x01,  0xfe,  0x82,  0x16,  0x2f,  0x07,  0x2d,
-  0xe0,  0x01,  0xfe,  0xbc,  0x15,  0x09,  0x04,  0x1d,  0x45,  0x01,  0xe7,  0x01,  0xe8,  0x11,  0xfe,  0xe9,
-  0x00,  0x09,  0x04,  0x4c,  0xfe,  0x2c,  0x13,  0x01,  0xfe,  0x14,  0x16,  0xfe,  0x1e,  0x1c,  0xfe,  0x14,
-  0x90,  0xfe,  0x96,  0x90,  0x0c,  0xfe,  0x64,  0x01,  0x18,  0xfe,  0x66,  0x01,  0x09,  0x04,  0x4f,  0xfe,
-  0x12,  0x12,  0xfe,  0x03,  0x80,  0x74,  0xfe,  0x01,  0xec,  0x20,  0xfe,  0x80,  0x40,  0x12,  0x20,  0x63,
-  0x27,  0x11,  0xc8,  0x59,  0x1e,  0x20,  0xed,  0x76,  0x20,  0x03,  0xfe,  0x08,  0x1c,  0x05,  0xfe,  0xac,
-  0x00,  0xfe,  0x06,  0x58,  0x05,  0xfe,  0xae,  0x00,  0xfe,  0x07,  0x58,  0x05,  0xfe,  0xb0,  0x00,  0xfe,
-  0x08,  0x58,  0x05,  0xfe,  0xb2,  0x00,  0xfe,  0x09,  0x58,  0xfe,  0x0a,  0x1c,  0x24,  0x69,  0x12,  0xc9,
-  0x23,  0x0c,  0x50,  0x0c,  0x3f,  0x13,  0x40,  0x48,  0x5f,  0x17,  0x1d,  0xfe,  0x90,  0x4d,  0xfe,  0x91,
-  0x54,  0x21,  0xfe,  0x08,  0x0f,  0x3e,  0x10,  0x13,  0x42,  0x48,  0x17,  0x4c,  0xfe,  0x90,  0x4d,  0xfe,
-  0x91,  0x54,  0x21,  0xfe,  0x1e,  0x0f,  0x24,  0x10,  0x12,  0x20,  0x78,  0x2c,  0x46,  0x1e,  0x20,  0xed,
-  0x76,  0x20,  0x11,  0xc8,  0xf6,  0xfe,  0xd6,  0xf0,  0xfe,  0x32,  0x0f,  0xea,  0x70,  0xfe,  0x14,  0x1c,
-  0xfe,  0x10,  0x1c,  0xfe,  0x18,  0x1c,  0x03,  0x3c,  0xfe,  0x0c,  0x14,  0xee,  0xfe,  0x07,  0xe6,  0x1d,
-  0xfe,  0xce,  0x47,  0xfe,  0xf5,  0x13,  0x03,  0x01,  0x86,  0x78,  0x2c,  0x46,  0xfa,  0xef,  0xfe,  0x42,
-  0x13,  0x2f,  0x07,  0x2d,  0xfe,  0x34,  0x13,  0x0a,  0x42,  0x01,  0x0e,  0xb0,  0xfe,  0x36,  0x12,  0xf0,
-  0xfe,  0x45,  0x48,  0x01,  0xe3,  0xfe,  0x00,  0xcc,  0xb0,  0xfe,  0xf3,  0x13,  0x3d,  0x75,  0x07,  0x10,
-  0xa3,  0x0a,  0x80,  0x01,  0x0e,  0xfe,  0x80,  0x5c,  0x01,  0x6f,  0xfe,  0x0e,  0x10,  0x07,  0x7e,  0x45,
-  0xf6,  0xfe,  0xd6,  0xf0,  0xfe,  0x6c,  0x0f,  0x03,  0xfe,  0x44,  0x58,  0x74,  0xfe,  0x01,  0xec,  0x97,
-  0xfe,  0x9e,  0x40,  0xfe,  0x9d,  0xe7,  0x00,  0xfe,  0x9c,  0xe7,  0x1b,  0x76,  0x27,  0x01,  0xda,  0xfe,
-  0xdd,  0x10,  0x2a,  0xbc,  0x7d,  0xbd,  0x7f,  0x30,  0x2e,  0xd5,  0x07,  0x1b,  0xfe,  0x48,  0x12,  0x07,
-  0x0b,  0xfe,  0x56,  0x12,  0x07,  0x1a,  0xfe,  0x30,  0x12,  0x07,  0xc2,  0x16,  0xfe,  0x3e,  0x11,  0x07,
-  0xfe,  0x23,  0x00,  0x16,  0xfe,  0x4a,  0x11,  0x07,  0x06,  0x16,  0xfe,  0xa8,  0x11,  0x07,  0x19,  0xfe,
-  0x12,  0x12,  0x07,  0x00,  0x16,  0x22,  0x14,  0xc2,  0x01,  0x33,  0x9f,  0x2b,  0x01,  0x08,  0x8c,  0x43,
-  0x03,  0x2b,  0xfe,  0x62,  0x08,  0x0a,  0xca,  0x01,  0xfe,  0x32,  0x0e,  0x11,  0x7e,  0x02,  0x29,  0x2b,
-  0x2f,  0x07,  0x9b,  0xfe,  0xd9,  0x13,  0x79,  0x39,  0x68,  0x3a,  0x77,  0xfe,  0xfc,  0x10,  0x09,  0x04,
-  0x6a,  0xfe,  0x72,  0x12,  0xc0,  0x38,  0xc1,  0x4e,  0xf4,  0xf5,  0x8e,  0xfe,  0xc6,  0x10,  0x1e,  0x58,
-  0xfe,  0x26,  0x13,  0x05,  0x7b,  0x31,  0x7c,  0x77,  0xfe,  0x82,  0x0c,  0x0c,  0x54,  0x18,  0x55,  0x23,
-  0x0c,  0x7b,  0x0c,  0x7c,  0x01,  0xa8,  0x24,  0x69,  0x73,  0x12,  0x58,  0x01,  0xa5,  0xc0,  0x38,  0xc1,
-  0x4e,  0xfe,  0x04,  0x55,  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,  0x38,  0xfe,  0x05,  0xfa,  0x4e,  0xfe,
-  0x91,  0x10,  0x05,  0x56,  0x31,  0x57,  0xfe,  0x40,  0x56,  0xfe,  0xe1,  0x56,  0x0c,  0x56,  0x18,  0x57,
-  0x83,  0xc0,  0x38,  0xc1,  0x4e,  0xf4,  0xf5,  0x05,  0x52,  0x31,  0x53,  0xfe,  0x00,  0x56,  0xfe,  0xa1,
-  0x56,  0x0c,  0x52,  0x18,  0x53,  0x09,  0x04,  0x6a,  0xfe,  0x1e,  0x12,  0x1e,  0x58,  0xfe,  0x1f,  0x40,
-  0x05,  0x54,  0x31,  0x55,  0xfe,  0x2c,  0x50,  0xfe,  0xae,  0x50,  0x05,  0x56,  0x31,  0x57,  0xfe,  0x44,
-  0x50,  0xfe,  0xc6,  0x50,  0x05,  0x52,  0x31,  0x53,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0x05,  0x39,
-  0x31,  0x3a,  0xfe,  0x40,  0x50,  0xfe,  0xc2,  0x50,  0x02,  0x5c,  0x24,  0x06,  0x12,  0xcd,  0x02,  0x5b,
-  0x2b,  0x01,  0x08,  0x1f,  0x44,  0x30,  0x2e,  0xd5,  0x07,  0x06,  0x21,  0x44,  0x2f,  0x07,  0x9b,  0x21,
-  0x5b,  0x01,  0x6e,  0x1c,  0x3d,  0x16,  0x44,  0x09,  0x04,  0x0b,  0xe2,  0x79,  0x39,  0x68,  0x3a,  0xfe,
-  0x0a,  0x55,  0x34,  0xfe,  0x8b,  0x55,  0xbe,  0x39,  0xbf,  0x3a,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,
-  0x02,  0x5b,  0xfe,  0x19,  0x81,  0xaf,  0xfe,  0x19,  0x41,  0x02,  0x5b,  0x2b,  0x01,  0x08,  0x25,  0x32,
-  0x1f,  0xa2,  0x30,  0x2e,  0xd8,  0x4b,  0x1a,  0xfe,  0xa6,  0x12,  0x4b,  0x0b,  0x3b,  0x02,  0x44,  0x01,
-  0x08,  0x25,  0x32,  0x1f,  0xa2,  0x30,  0x2e,  0xd6,  0x07,  0x1a,  0x21,  0x44,  0x01,  0x08,  0x1f,  0xa2,
-  0x30,  0x2e,  0xfe,  0xe8,  0x09,  0xfe,  0xc2,  0x49,  0x60,  0x05,  0xfe,  0x9c,  0x00,  0x28,  0x84,  0x49,
-  0x04,  0x19,  0x34,  0x9f,  0xfe,  0xbb,  0x45,  0x4b,  0x00,  0x45,  0x3e,  0x06,  0x78,  0x3d,  0xfe,  0xda,
-  0x14,  0x01,  0x6e,  0x87,  0xfe,  0x4b,  0x45,  0xe2,  0x2f,  0x07,  0x9a,  0xe1,  0x05,  0xc6,  0x28,  0x84,
-  0x05,  0x3f,  0x28,  0x34,  0x5e,  0x02,  0x5b,  0xfe,  0xc0,  0x5d,  0xfe,  0xf8,  0x14,  0xfe,  0x03,  0x17,
-  0x05,  0x50,  0xb4,  0x0c,  0x50,  0x5e,  0x2b,  0x01,  0x08,  0x26,  0x5c,  0x01,  0xfe,  0xaa,  0x14,  0x02,
-  0x5c,  0x01,  0x08,  0x25,  0x32,  0x1f,  0x44,  0x30,  0x2e,  0xd6,  0x07,  0x06,  0x21,  0x44,  0x01,  0xfe,
-  0x8e,  0x13,  0xfe,  0x42,  0x58,  0xfe,  0x82,  0x14,  0xfe,  0xa4,  0x14,  0x87,  0xfe,  0x4a,  0xf4,  0x0b,
-  0x16,  0x44,  0xfe,  0x4a,  0xf4,  0x06,  0xfe,  0x0c,  0x12,  0x2f,  0x07,  0x9a,  0x85,  0x02,  0x5b,  0x05,
-  0x3f,  0xb4,  0x0c,  0x3f,  0x5e,  0x2b,  0x01,  0x08,  0x26,  0x5c,  0x01,  0xfe,  0xd8,  0x14,  0x02,  0x5c,
-  0x13,  0x06,  0x65,  0xfe,  0xca,  0x12,  0x26,  0xfe,  0xe0,  0x12,  0x72,  0xf1,  0x01,  0x08,  0x23,  0x72,
-  0x03,  0x8f,  0xfe,  0xdc,  0x12,  0x25,  0xfe,  0xdc,  0x12,  0x1f,  0xfe,  0xca,  0x12,  0x5e,  0x2b,  0x01,
-  0x08,  0xfe,  0xd5,  0x10,  0x13,  0x6c,  0xff,  0x02,  0x00,  0x57,  0x48,  0x8b,  0x1c,  0xfe,  0xff,  0x7f,
-  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x13,  0x6c,  0xff,  0x02,  0x00,  0x57,  0x48,  0x8b,  0x1c,
-  0x3d,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x13,  0x6c,  0xff,  0x02,  0x00,  0x57,  0x48,  0x8b,
-  0x03,  0x13,  0x6c,  0xff,  0x02,  0x00,  0x57,  0x48,  0x8b,  0xfe,  0x0b,  0x58,  0x03,  0x0a,  0x50,  0x01,
-  0x82,  0x0a,  0x3f,  0x01,  0x82,  0x03,  0xfc,  0x1c,  0x10,  0xff,  0x03,  0x00,  0x54,  0xfe,  0x00,  0xf4,
-  0x19,  0x48,  0xfe,  0x00,  0x7d,  0xfe,  0x01,  0x7d,  0xfe,  0x02,  0x7d,  0xfe,  0x03,  0x7c,  0x63,  0x27,
-  0x0c,  0x52,  0x18,  0x53,  0xbe,  0x56,  0xbf,  0x57,  0x03,  0xfe,  0x62,  0x08,  0xfe,  0x82,  0x4a,  0xfe,
-  0xe1,  0x1a,  0xfe,  0x83,  0x5a,  0x74,  0x03,  0x01,  0xfe,  0x14,  0x18,  0xfe,  0x42,  0x48,  0x5f,  0x60,
-  0x89,  0x01,  0x08,  0x1f,  0xfe,  0xa2,  0x14,  0x30,  0x2e,  0xd8,  0x01,  0x08,  0x1f,  0xfe,  0xa2,  0x14,
-  0x30,  0x2e,  0xfe,  0xe8,  0x0a,  0xfe,  0xc1,  0x59,  0x05,  0xc6,  0x28,  0xfe,  0xcc,  0x12,  0x49,  0x04,
-  0x1b,  0xfe,  0xc4,  0x13,  0x23,  0x62,  0x1b,  0xe2,  0x4b,  0xc3,  0x64,  0xfe,  0xe8,  0x13,  0x3b,  0x13,
-  0x06,  0x17,  0xc3,  0x78,  0xdb,  0xfe,  0x78,  0x10,  0xff,  0x02,  0x83,  0x55,  0xa1,  0xff,  0x02,  0x83,
-  0x55,  0x62,  0x1a,  0xa4,  0xbb,  0xfe,  0x30,  0x00,  0x8e,  0xe4,  0x17,  0x2c,  0x13,  0x06,  0xfe,  0x56,
-  0x10,  0x62,  0x0b,  0xe1,  0xbb,  0xfe,  0x64,  0x00,  0x8e,  0xe4,  0x0a,  0xfe,  0x64,  0x00,  0x17,  0x93,
-  0x13,  0x06,  0xfe,  0x28,  0x10,  0x62,  0x06,  0xfe,  0x60,  0x13,  0xbb,  0xfe,  0xc8,  0x00,  0x8e,  0xe4,
-  0x0a,  0xfe,  0xc8,  0x00,  0x17,  0x4d,  0x13,  0x06,  0x83,  0xbb,  0xfe,  0x90,  0x01,  0xba,  0xfe,  0x4e,
-  0x14,  0x89,  0xfe,  0x12,  0x10,  0xfe,  0x43,  0xf4,  0x94,  0xfe,  0x56,  0xf0,  0xfe,  0x60,  0x14,  0xfe,
-  0x04,  0xf4,  0x6c,  0xfe,  0x43,  0xf4,  0x93,  0xfe,  0xf3,  0x10,  0xf9,  0x01,  0xfe,  0x22,  0x13,  0x1c,
-  0x3d,  0xfe,  0x10,  0x13,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x69,  0xba,  0xfe,  0x9c,  0x14,  0xb7,
-  0x69,  0xfe,  0x1c,  0x10,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x19,  0xba,  0xfe,  0x9c,  0x14,  0xb7,
-  0x19,  0x83,  0x60,  0x23,  0xfe,  0x4d,  0xf4,  0x00,  0xdf,  0x89,  0x13,  0x06,  0xfe,  0xb4,  0x56,  0xfe,
-  0xc3,  0x58,  0x03,  0x60,  0x13,  0x0b,  0x03,  0x15,  0x06,  0x01,  0x08,  0x26,  0xe5,  0x15,  0x0b,  0x01,
-  0x08,  0x26,  0xe5,  0x15,  0x1a,  0x01,  0x08,  0x26,  0xe5,  0x72,  0xfe,  0x89,  0x49,  0x01,  0x08,  0x03,
-  0x15,  0x06,  0x01,  0x08,  0x26,  0xa6,  0x15,  0x1a,  0x01,  0x08,  0x26,  0xa6,  0x15,  0x06,  0x01,  0x08,
-  0x26,  0xa6,  0xfe,  0x89,  0x49,  0x01,  0x08,  0x26,  0xa6,  0x72,  0xfe,  0x89,  0x4a,  0x01,  0x08,  0x03,
-  0x60,  0x03,  0x1e,  0xcc,  0x07,  0x06,  0xfe,  0x44,  0x13,  0xad,  0x12,  0xcc,  0xfe,  0x49,  0xf4,  0x00,
-  0x3b,  0x72,  0x9f,  0x5e,  0xfe,  0x01,  0xec,  0xfe,  0x27,  0x01,  0xf1,  0x01,  0x08,  0x2f,  0x07,  0xfe,
-  0xe3,  0x00,  0xfe,  0x20,  0x13,  0x1f,  0xfe,  0x5a,  0x15,  0x23,  0x12,  0xcd,  0x01,  0x43,  0x1e,  0xcd,
-  0x07,  0x06,  0x45,  0x09,  0x4a,  0x06,  0x35,  0x03,  0x0a,  0x42,  0x01,  0x0e,  0xed,  0x88,  0x07,  0x10,
-  0xa4,  0x0a,  0x80,  0x01,  0x0e,  0x88,  0x0a,  0x51,  0x01,  0x9e,  0x03,  0x0a,  0x80,  0x01,  0x0e,  0x88,
-  0xfe,  0x80,  0xe7,  0x10,  0x07,  0x10,  0x84,  0xfe,  0x45,  0x58,  0x01,  0xe3,  0x88,  0x03,  0x0a,  0x42,
-  0x01,  0x0e,  0x88,  0x0a,  0x51,  0x01,  0x9e,  0x03,  0x0a,  0x42,  0x01,  0x0e,  0xfe,  0x80,  0x80,  0xf2,
-  0xfe,  0x49,  0xe4,  0x10,  0xa4,  0x0a,  0x80,  0x01,  0x0e,  0xf2,  0x0a,  0x51,  0x01,  0x82,  0x03,  0x17,
-  0x10,  0x71,  0x66,  0xfe,  0x60,  0x01,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x24,  0x1c,  0xfe,
-  0x1d,  0xf7,  0x1d,  0x90,  0xfe,  0xf6,  0x15,  0x01,  0xfe,  0xfc,  0x16,  0xe0,  0x91,  0x1d,  0x66,  0xfe,
-  0x2c,  0x01,  0xfe,  0x2f,  0x19,  0x03,  0xae,  0x21,  0xfe,  0xe6,  0x15,  0xfe,  0xda,  0x10,  0x17,  0x10,
-  0x71,  0x05,  0xfe,  0x64,  0x01,  0xfe,  0x00,  0xf4,  0x19,  0xfe,  0x18,  0x58,  0x05,  0xfe,  0x66,  0x01,
-  0xfe,  0x19,  0x58,  0x91,  0x19,  0xfe,  0x3c,  0x90,  0xfe,  0x30,  0xf4,  0x06,  0xfe,  0x3c,  0x50,  0x66,
-  0xfe,  0x38,  0x00,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0x19,  0x90,  0xfe,  0x40,  0x16,  0xfe,  0xb6,
-  0x14,  0x34,  0x03,  0xae,  0x21,  0xfe,  0x18,  0x16,  0xfe,  0x9c,  0x10,  0x17,  0x10,  0x71,  0xfe,  0x83,
-  0x5a,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x1d,  0xf7,  0x38,  0x90,  0xfe,  0x62,  0x16,  0xfe,
-  0x94,  0x14,  0xfe,  0x10,  0x13,  0x91,  0x38,  0x66,  0x1b,  0xfe,  0xaf,  0x19,  0xfe,  0x98,  0xe7,  0x00,
-  0x03,  0xae,  0x21,  0xfe,  0x56,  0x16,  0xfe,  0x6c,  0x10,  0x17,  0x10,  0x71,  0xfe,  0x30,  0xbc,  0xfe,
-  0xb2,  0xbc,  0x91,  0xc5,  0x66,  0x1b,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0xc5,  0x90,  0xfe,  0x9a,
-  0x16,  0xfe,  0x5c,  0x14,  0x34,  0x03,  0xae,  0x21,  0xfe,  0x86,  0x16,  0xfe,  0x42,  0x10,  0xfe,  0x02,
-  0xf6,  0x10,  0x71,  0xfe,  0x18,  0xfe,  0x54,  0xfe,  0x19,  0xfe,  0x55,  0xfc,  0xfe,  0x1d,  0xf7,  0x4f,
-  0x90,  0xfe,  0xc0,  0x16,  0xfe,  0x36,  0x14,  0xfe,  0x1c,  0x13,  0x91,  0x4f,  0x47,  0xfe,  0x83,  0x58,
-  0xfe,  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x10,  0xfe,  0x81,  0xe7,  0x10,  0x11,  0xfe,  0xdd,  0x00,  0x63,
-  0x27,  0x03,  0x63,  0x27,  0xfe,  0x12,  0x45,  0x21,  0xfe,  0xb0,  0x16,  0x14,  0x06,  0x37,  0x95,  0xa9,
-  0x02,  0x29,  0xfe,  0x39,  0xf0,  0xfe,  0x04,  0x17,  0x23,  0x03,  0xfe,  0x7e,  0x18,  0x1c,  0x1a,  0x5d,
-  0x13,  0x0d,  0x03,  0x71,  0x05,  0xcb,  0x1c,  0x06,  0xfe,  0xef,  0x12,  0xfe,  0xe1,  0x10,  0x78,  0x2c,
-  0x46,  0x2f,  0x07,  0x2d,  0xfe,  0x3c,  0x13,  0xfe,  0x82,  0x14,  0xfe,  0x42,  0x13,  0x3c,  0x8a,  0x0a,
-  0x42,  0x01,  0x0e,  0xb0,  0xfe,  0x3e,  0x12,  0xf0,  0xfe,  0x45,  0x48,  0x01,  0xe3,  0xfe,  0x00,  0xcc,
-  0xb0,  0xfe,  0xf3,  0x13,  0x3d,  0x75,  0x07,  0x10,  0xa3,  0x0a,  0x80,  0x01,  0x0e,  0xf2,  0x01,  0x6f,
-  0xfe,  0x16,  0x10,  0x07,  0x7e,  0x85,  0xfe,  0x40,  0x14,  0xfe,  0x24,  0x12,  0xf6,  0xfe,  0xd6,  0xf0,
-  0xfe,  0x24,  0x17,  0x17,  0x0b,  0x03,  0xfe,  0x9c,  0xe7,  0x0b,  0x0f,  0xfe,  0x15,  0x00,  0x59,  0x76,
-  0x27,  0x01,  0xda,  0x17,  0x06,  0x03,  0x3c,  0x8a,  0x09,  0x4a,  0x1d,  0x35,  0x11,  0x2d,  0x01,  0x6f,
-  0x17,  0x06,  0x03,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,  0x79,  0xc7,  0x68,  0xc8,  0xfe,  0x48,  0x55,
-  0x34,  0xfe,  0xc9,  0x55,  0x03,  0x1e,  0x98,  0x73,  0x12,  0x98,  0x03,  0x0a,  0x99,  0x01,  0x0e,  0xf0,
-  0x0a,  0x40,  0x01,  0x0e,  0xfe,  0x49,  0x44,  0x16,  0xfe,  0xf0,  0x17,  0x73,  0x75,  0x03,  0x0a,  0x42,
-  0x01,  0x0e,  0x07,  0x10,  0x45,  0x0a,  0x51,  0x01,  0x9e,  0x0a,  0x40,  0x01,  0x0e,  0x73,  0x75,  0x03,
-  0xfe,  0x4e,  0xe4,  0x1a,  0x64,  0xfe,  0x24,  0x18,  0x05,  0xfe,  0x90,  0x00,  0xfe,  0x3a,  0x45,  0x5b,
-  0xfe,  0x4e,  0xe4,  0xc2,  0x64,  0xfe,  0x36,  0x18,  0x05,  0xfe,  0x92,  0x00,  0xfe,  0x02,  0xe6,  0x1b,
-  0xdc,  0xfe,  0x4e,  0xe4,  0xfe,  0x0b,  0x00,  0x64,  0xfe,  0x48,  0x18,  0x05,  0xfe,  0x94,  0x00,  0xfe,
-  0x02,  0xe6,  0x19,  0xfe,  0x08,  0x10,  0x05,  0xfe,  0x96,  0x00,  0xfe,  0x02,  0xe6,  0x2c,  0xfe,  0x4e,
-  0x45,  0xfe,  0x0c,  0x12,  0xaf,  0xff,  0x04,  0x68,  0x54,  0xde,  0x1c,  0x69,  0x03,  0x07,  0x7a,  0xfe,
-  0x5a,  0xf0,  0xfe,  0x74,  0x18,  0x24,  0xfe,  0x09,  0x00,  0xfe,  0x34,  0x10,  0x07,  0x1b,  0xfe,  0x5a,
-  0xf0,  0xfe,  0x82,  0x18,  0x24,  0xc3,  0xfe,  0x26,  0x10,  0x07,  0x1a,  0x5d,  0x24,  0x2c,  0xdc,  0x07,
-  0x0b,  0x5d,  0x24,  0x93,  0xfe,  0x0e,  0x10,  0x07,  0x06,  0x5d,  0x24,  0x4d,  0x9f,  0xad,  0x03,  0x14,
-  0xfe,  0x09,  0x00,  0x01,  0x33,  0xfe,  0x04,  0xfe,  0x7d,  0x05,  0x7f,  0xf9,  0x03,  0x25,  0xfe,  0xca,
-  0x18,  0xfe,  0x14,  0xf0,  0x08,  0x65,  0xfe,  0xc6,  0x18,  0x03,  0xff,  0x1a,  0x00,  0x00,
+static unsigned char _adv_asc3550_buf[] = {
+	0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0x16, 0x18, 0xe4, 0x00, 0xfc,
+	0x01, 0x00, 0x48, 0xe4,
+	0xbe, 0x18, 0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0x00, 0xfa, 0xff, 0xff,
+	0x28, 0x0e, 0x9e, 0xe7,
+	0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x00, 0xf6, 0x01, 0xe6, 0x09, 0xe7,
+	0x55, 0xf0, 0x01, 0xf6,
+	0x01, 0xfa, 0x08, 0x00, 0x03, 0x00, 0x04, 0x00, 0x18, 0xf4, 0x10, 0x00,
+	0x00, 0xec, 0x85, 0xf0,
+	0xbc, 0x00, 0xd5, 0xf0, 0x8e, 0x0c, 0x38, 0x54, 0x00, 0xe6, 0x1e, 0xf0,
+	0x86, 0xf0, 0xb4, 0x00,
+	0x98, 0x57, 0xd0, 0x01, 0x0c, 0x1c, 0x3e, 0x1c, 0x0c, 0x00, 0xbb, 0x00,
+	0xaa, 0x18, 0x02, 0x80,
+	0x32, 0xf0, 0x01, 0xfc, 0x88, 0x0c, 0xc6, 0x12, 0x02, 0x13, 0x18, 0x40,
+	0x00, 0x57, 0x01, 0xea,
+	0x3c, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12, 0x3e, 0x57, 0x00, 0x80,
+	0x03, 0xe6, 0xb6, 0x00,
+	0xc0, 0x00, 0x01, 0x01, 0x3e, 0x01, 0xda, 0x0f, 0x22, 0x10, 0x08, 0x12,
+	0x02, 0x4a, 0xb9, 0x54,
+	0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4, 0x20, 0x00, 0x32, 0x00,
+	0x3e, 0x00, 0x80, 0x00,
+	0x24, 0x01, 0x3c, 0x01, 0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01,
+	0x74, 0x01, 0x76, 0x01,
+	0x78, 0x01, 0x62, 0x0a, 0x92, 0x0c, 0x2c, 0x10, 0x2e, 0x10, 0x06, 0x13,
+	0x4c, 0x1c, 0xbb, 0x55,
+	0x3c, 0x56, 0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0xb1, 0xf0,
+	0x03, 0xf7, 0x06, 0xf7,
+	0x03, 0xfc, 0x0f, 0x00, 0x40, 0x00, 0xbe, 0x00, 0x00, 0x01, 0xb0, 0x08,
+	0x30, 0x13, 0x64, 0x15,
+	0x32, 0x1c, 0x38, 0x1c, 0x4e, 0x1c, 0x10, 0x44, 0x02, 0x48, 0x00, 0x4c,
+	0x04, 0xea, 0x5d, 0xf0,
+	0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x34, 0x00, 0x36, 0x00, 0x98, 0x00,
+	0xcc, 0x00, 0x20, 0x01,
+	0x4e, 0x01, 0x4e, 0x0b, 0x1e, 0x0e, 0x0c, 0x10, 0x0a, 0x12, 0x04, 0x13,
+	0x40, 0x13, 0x30, 0x1c,
+	0x00, 0x4e, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
+	0x59, 0xf0, 0xa7, 0xf0,
+	0xb8, 0xf0, 0x0e, 0xf7, 0x06, 0x00, 0x19, 0x00, 0x33, 0x00, 0x9b, 0x00,
+	0xa4, 0x00, 0xb5, 0x00,
+	0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00, 0xe7, 0x00, 0xde, 0x03, 0x56, 0x0a,
+	0x14, 0x0e, 0x02, 0x10,
+	0x04, 0x10, 0x0a, 0x10, 0x36, 0x10, 0x0a, 0x13, 0x12, 0x13, 0x52, 0x13,
+	0x10, 0x15, 0x14, 0x15,
+	0xac, 0x16, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c, 0x08, 0x44, 0x38, 0x44,
+	0x91, 0x44, 0x0a, 0x45,
+	0x48, 0x46, 0x01, 0x48, 0x68, 0x54, 0x83, 0x55, 0xb0, 0x57, 0x01, 0x58,
+	0x83, 0x59, 0x05, 0xe6,
+	0x0b, 0xf0, 0x0c, 0xf0, 0x5c, 0xf0, 0x4b, 0xf4, 0x04, 0xf8, 0x05, 0xf8,
+	0x02, 0xfa, 0x03, 0xfa,
+	0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x1c, 0x00,
+	0x9e, 0x00, 0xa8, 0x00,
+	0xaa, 0x00, 0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01,
+	0x7a, 0x01, 0xc0, 0x01,
+	0xc2, 0x01, 0x7c, 0x02, 0x5a, 0x03, 0xea, 0x04, 0xe8, 0x07, 0x68, 0x08,
+	0x69, 0x08, 0xba, 0x08,
+	0xe9, 0x09, 0x06, 0x0b, 0x3a, 0x0e, 0x00, 0x10, 0x1a, 0x10, 0xed, 0x10,
+	0xf1, 0x10, 0x06, 0x12,
+	0x0c, 0x13, 0x16, 0x13, 0x1e, 0x13, 0x82, 0x13, 0x42, 0x14, 0xd6, 0x14,
+	0x8a, 0x15, 0xc6, 0x17,
+	0xd2, 0x17, 0x6b, 0x18, 0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40,
+	0x0e, 0x47, 0x48, 0x47,
+	0x41, 0x48, 0x89, 0x48, 0x80, 0x4c, 0x00, 0x54, 0x44, 0x55, 0xe5, 0x55,
+	0x14, 0x56, 0x77, 0x57,
+	0xbf, 0x57, 0x40, 0x5c, 0x06, 0x80, 0x08, 0x90, 0x03, 0xa1, 0xfe, 0x9c,
+	0xf0, 0x29, 0x02, 0xfe,
+	0xb8, 0x0c, 0xff, 0x10, 0x00, 0x00, 0xd0, 0xfe, 0xcc, 0x18, 0x00, 0xcf,
+	0xfe, 0x80, 0x01, 0xff,
+	0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
+	0x00, 0xfe, 0x57, 0x24,
+	0x00, 0xfe, 0x48, 0x00, 0x4f, 0xff, 0x04, 0x00, 0x00, 0x10, 0xff, 0x09,
+	0x00, 0x00, 0xff, 0x08,
+	0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
+	0xff, 0xff, 0xff, 0x0f,
+	0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
+	0xfe, 0x04, 0xf7, 0xcf,
+	0x2a, 0x67, 0x0b, 0x01, 0xfe, 0xce, 0x0e, 0xfe, 0x04, 0xf7, 0xcf, 0x67,
+	0x0b, 0x3c, 0x2a, 0xfe,
+	0x3d, 0xf0, 0xfe, 0x02, 0x02, 0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x91, 0xf0,
+	0xfe, 0xf0, 0x01, 0xfe,
+	0x90, 0xf0, 0xfe, 0xf0, 0x01, 0xfe, 0x8f, 0xf0, 0x9c, 0x05, 0x51, 0x3b,
+	0x02, 0xfe, 0xd4, 0x0c,
+	0x01, 0xfe, 0x44, 0x0d, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
+	0x1c, 0x05, 0xfe, 0xa6,
+	0x00, 0xfe, 0xd3, 0x12, 0x47, 0x18, 0xfe, 0xa6, 0x00, 0xb5, 0xfe, 0x48,
+	0xf0, 0xfe, 0x86, 0x02,
+	0xfe, 0x49, 0xf0, 0xfe, 0xa0, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xbe, 0x02,
+	0xfe, 0x46, 0xf0, 0xfe,
+	0x50, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x56, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
+	0x44, 0x02, 0xfe, 0x44,
+	0xf0, 0xfe, 0x48, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x4c, 0x02, 0x17, 0x0b,
+	0xa0, 0x17, 0x06, 0x18,
+	0x96, 0x02, 0x29, 0xfe, 0x00, 0x1c, 0xde, 0xfe, 0x02, 0x1c, 0xdd, 0xfe,
+	0x1e, 0x1c, 0xfe, 0xe9,
+	0x10, 0x01, 0xfe, 0x20, 0x17, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xc7,
+	0x0a, 0x6b, 0x01, 0x9e,
+	0x02, 0x29, 0x14, 0x4d, 0x37, 0x97, 0x01, 0xfe, 0x64, 0x0f, 0x0a, 0x6b,
+	0x01, 0x82, 0xfe, 0xbd,
+	0x10, 0x0a, 0x6b, 0x01, 0x82, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
+	0x58, 0x1c, 0x17, 0x06,
+	0x18, 0x96, 0x2a, 0x25, 0x29, 0xfe, 0x3d, 0xf0, 0xfe, 0x02, 0x02, 0x21,
+	0xfe, 0x94, 0x02, 0xfe,
+	0x5a, 0x1c, 0xea, 0xfe, 0x14, 0x1c, 0x14, 0xfe, 0x30, 0x00, 0x37, 0x97,
+	0x01, 0xfe, 0x54, 0x0f,
+	0x17, 0x06, 0x18, 0x96, 0x02, 0xd0, 0x1e, 0x20, 0x07, 0x10, 0x34, 0xfe,
+	0x69, 0x10, 0x17, 0x06,
+	0x18, 0x96, 0xfe, 0x04, 0xec, 0x20, 0x46, 0x3d, 0x12, 0x20, 0xfe, 0x05,
+	0xf6, 0xc7, 0x01, 0xfe,
+	0x52, 0x16, 0x09, 0x4a, 0x4c, 0x35, 0x11, 0x2d, 0x3c, 0x8a, 0x01, 0xe6,
+	0x02, 0x29, 0x0a, 0x40,
+	0x01, 0x0e, 0x07, 0x00, 0x5d, 0x01, 0x6f, 0xfe, 0x18, 0x10, 0xfe, 0x41,
+	0x58, 0x0a, 0x99, 0x01,
+	0x0e, 0xfe, 0xc8, 0x54, 0x64, 0xfe, 0x0c, 0x03, 0x01, 0xe6, 0x02, 0x29,
+	0x2a, 0x46, 0xfe, 0x02,
+	0xe8, 0x27, 0xf8, 0xfe, 0x9e, 0x43, 0xf7, 0xfe, 0x27, 0xf0, 0xfe, 0xdc,
+	0x01, 0xfe, 0x07, 0x4b,
+	0xfe, 0x20, 0xf0, 0x9c, 0xfe, 0x40, 0x1c, 0x25, 0xd2, 0xfe, 0x26, 0xf0,
+	0xfe, 0x56, 0x03, 0xfe,
+	0xa0, 0xf0, 0xfe, 0x44, 0x03, 0xfe, 0x11, 0xf0, 0x9c, 0xfe, 0xef, 0x10,
+	0xfe, 0x9f, 0xf0, 0xfe,
+	0x64, 0x03, 0xeb, 0x0f, 0xfe, 0x11, 0x00, 0x02, 0x5a, 0x2a, 0xfe, 0x48,
+	0x1c, 0xeb, 0x09, 0x04,
+	0x1d, 0xfe, 0x18, 0x13, 0x23, 0x1e, 0x98, 0xac, 0x12, 0x98, 0x0a, 0x40,
+	0x01, 0x0e, 0xac, 0x75,
+	0x01, 0xfe, 0xbc, 0x15, 0x11, 0xca, 0x25, 0xd2, 0xfe, 0x01, 0xf0, 0xd2,
+	0xfe, 0x82, 0xf0, 0xfe,
+	0x92, 0x03, 0xec, 0x11, 0xfe, 0xe4, 0x00, 0x65, 0xfe, 0xa4, 0x03, 0x25,
+	0x32, 0x1f, 0xfe, 0xb4,
+	0x03, 0x01, 0x43, 0xfe, 0x06, 0xf0, 0xfe, 0xc4, 0x03, 0x8d, 0x81, 0xfe,
+	0x0a, 0xf0, 0xfe, 0x7a,
+	0x06, 0x02, 0x22, 0x05, 0x6b, 0x28, 0x16, 0xfe, 0xf6, 0x04, 0x14, 0x2c,
+	0x01, 0x33, 0x8f, 0xfe,
+	0x66, 0x02, 0x02, 0xd1, 0xeb, 0x2a, 0x67, 0x1a, 0xfe, 0x67, 0x1b, 0xf8,
+	0xf7, 0xfe, 0x48, 0x1c,
+	0x70, 0x01, 0x6e, 0x87, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x16, 0xd3,
+	0x0a, 0xca, 0x01, 0x0e,
+	0x74, 0x60, 0x59, 0x76, 0x27, 0x05, 0x6b, 0x28, 0xfe, 0x10, 0x12, 0x14,
+	0x2c, 0x01, 0x33, 0x8f,
+	0xfe, 0x66, 0x02, 0x02, 0xd1, 0xbc, 0x7d, 0xbd, 0x7f, 0x25, 0x22, 0x65,
+	0xfe, 0x3c, 0x04, 0x1f,
+	0xfe, 0x38, 0x04, 0x68, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e,
+	0x12, 0x2b, 0xff, 0x02,
+	0x00, 0x10, 0x01, 0x08, 0x1f, 0xfe, 0xe0, 0x04, 0x2b, 0x01, 0x08, 0x1f,
+	0x22, 0x30, 0x2e, 0xd5,
+	0xfe, 0x4c, 0x44, 0xfe, 0x4c, 0x12, 0x60, 0xfe, 0x44, 0x48, 0x13, 0x2c,
+	0xfe, 0x4c, 0x54, 0x64,
+	0xd3, 0x46, 0x76, 0x27, 0xfa, 0xef, 0xfe, 0x62, 0x13, 0x09, 0x04, 0x1d,
+	0xfe, 0x2a, 0x13, 0x2f,
+	0x07, 0x7e, 0xa5, 0xfe, 0x20, 0x10, 0x13, 0x2c, 0xfe, 0x4c, 0x54, 0x64,
+	0xd3, 0xfa, 0xef, 0x86,
+	0x09, 0x04, 0x1d, 0xfe, 0x08, 0x13, 0x2f, 0x07, 0x7e, 0x6e, 0x09, 0x04,
+	0x1d, 0xfe, 0x1c, 0x12,
+	0x14, 0x92, 0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe,
+	0x70, 0x0c, 0x02, 0x22,
+	0x2b, 0x11, 0xfe, 0xe6, 0x00, 0xfe, 0x1c, 0x90, 0xf9, 0x03, 0x14, 0x92,
+	0x01, 0x33, 0x02, 0x29,
+	0xfe, 0x42, 0x5b, 0x67, 0x1a, 0xfe, 0x46, 0x59, 0xf8, 0xf7, 0xfe, 0x87,
+	0x80, 0xfe, 0x31, 0xe4,
+	0x4f, 0x09, 0x04, 0x0b, 0xfe, 0x78, 0x13, 0xfe, 0x20, 0x80, 0x07, 0x1a,
+	0xfe, 0x70, 0x12, 0x49,
+	0x04, 0x06, 0xfe, 0x60, 0x13, 0x05, 0xfe, 0xa2, 0x00, 0x28, 0x16, 0xfe,
+	0x80, 0x05, 0xfe, 0x31,
+	0xe4, 0x6a, 0x49, 0x04, 0x0b, 0xfe, 0x4a, 0x13, 0x05, 0xfe, 0xa0, 0x00,
+	0x28, 0xfe, 0x42, 0x12,
+	0x5e, 0x01, 0x08, 0x25, 0x32, 0xf1, 0x01, 0x08, 0x26, 0xfe, 0x98, 0x05,
+	0x11, 0xfe, 0xe3, 0x00,
+	0x23, 0x49, 0xfe, 0x4a, 0xf0, 0xfe, 0x6a, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
+	0x64, 0x05, 0x83, 0x24,
+	0xfe, 0x21, 0x00, 0xa1, 0x24, 0xfe, 0x22, 0x00, 0xa0, 0x24, 0x4c, 0xfe,
+	0x09, 0x48, 0x01, 0x08,
+	0x26, 0xfe, 0x98, 0x05, 0xfe, 0xe2, 0x08, 0x49, 0x04, 0xc5, 0x3b, 0x01,
+	0x86, 0x24, 0x06, 0x12,
+	0xcc, 0x37, 0xfe, 0x27, 0x01, 0x09, 0x04, 0x1d, 0xfe, 0x22, 0x12, 0x47,
+	0x01, 0xa7, 0x14, 0x92,
+	0x09, 0x04, 0x06, 0x3b, 0x14, 0xc4, 0x01, 0x33, 0x8f, 0xfe, 0x70, 0x0c,
+	0x02, 0x22, 0x05, 0xfe,
+	0x9c, 0x00, 0x28, 0xfe, 0x3e, 0x12, 0x05, 0x50, 0x28, 0xfe, 0x36, 0x13,
+	0x47, 0x01, 0xa7, 0x26,
+	0xfe, 0x08, 0x06, 0x0a, 0x06, 0x49, 0x04, 0x19, 0xfe, 0x02, 0x12, 0x5f,
+	0x01, 0xfe, 0xaa, 0x14,
+	0x1f, 0xfe, 0xfe, 0x05, 0x11, 0x9a, 0x01, 0x43, 0x11, 0xfe, 0xe5, 0x00,
+	0x05, 0x50, 0xb4, 0x0c,
+	0x50, 0x05, 0xc6, 0x28, 0xfe, 0x62, 0x12, 0x05, 0x3f, 0x28, 0xfe, 0x5a,
+	0x13, 0x01, 0xfe, 0x14,
+	0x18, 0x01, 0xfe, 0x66, 0x18, 0xfe, 0x43, 0x48, 0xb7, 0x19, 0x13, 0x6c,
+	0xff, 0x02, 0x00, 0x57,
+	0x48, 0x8b, 0x1c, 0x3d, 0x85, 0xb7, 0x69, 0x47, 0x01, 0xa7, 0x26, 0xfe,
+	0x72, 0x06, 0x49, 0x04,
+	0x1b, 0xdf, 0x89, 0x0a, 0x4d, 0x01, 0xfe, 0xd8, 0x14, 0x1f, 0xfe, 0x68,
+	0x06, 0x11, 0x9a, 0x01,
+	0x43, 0x11, 0xfe, 0xe5, 0x00, 0x05, 0x3f, 0xb4, 0x0c, 0x3f, 0x17, 0x06,
+	0x01, 0xa7, 0xec, 0x72,
+	0x70, 0x01, 0x6e, 0x87, 0x11, 0xfe, 0xe2, 0x00, 0x01, 0x08, 0x25, 0x32,
+	0xfe, 0x0a, 0xf0, 0xfe,
+	0xa6, 0x06, 0x8c, 0xfe, 0x5c, 0x07, 0xfe, 0x06, 0xf0, 0xfe, 0x64, 0x07,
+	0x8d, 0x81, 0x02, 0x22,
+	0x09, 0x04, 0x0b, 0xfe, 0x2e, 0x12, 0x15, 0x1a, 0x01, 0x08, 0x15, 0x00,
+	0x01, 0x08, 0x15, 0x00,
+	0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08, 0x15,
+	0x00, 0x02, 0xfe, 0x32,
+	0x08, 0x61, 0x04, 0x1b, 0xfe, 0x38, 0x12, 0x09, 0x04, 0x1b, 0x6e, 0x15,
+	0xfe, 0x1b, 0x00, 0x01,
+	0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01, 0x08, 0x15, 0x00, 0x01,
+	0x08, 0x15, 0x06, 0x01,
+	0x08, 0x15, 0x00, 0x02, 0xd9, 0x66, 0x4c, 0xfe, 0x3a, 0x55, 0x5f, 0xfe,
+	0x9a, 0x81, 0x4b, 0x1d,
+	0xba, 0xfe, 0x32, 0x07, 0x0a, 0x1d, 0xfe, 0x09, 0x6f, 0xaf, 0xfe, 0xca,
+	0x45, 0xfe, 0x32, 0x12,
+	0x62, 0x2c, 0x85, 0x66, 0x7b, 0x01, 0x08, 0x25, 0x32, 0xfe, 0x0a, 0xf0,
+	0xfe, 0x32, 0x07, 0x8d,
+	0x81, 0x8c, 0xfe, 0x5c, 0x07, 0x02, 0x22, 0x01, 0x43, 0x02, 0xfe, 0x8a,
+	0x06, 0x15, 0x19, 0x02,
+	0xfe, 0x8a, 0x06, 0xfe, 0x9c, 0xf7, 0xd4, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
+	0x90, 0x77, 0xfe, 0xca,
+	0x07, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x4a, 0x6a, 0x35, 0x1e, 0x20, 0x07,
+	0x10, 0xfe, 0x0e, 0x12,
+	0x74, 0xfe, 0x80, 0x80, 0x37, 0x20, 0x63, 0x27, 0xfe, 0x06, 0x10, 0xfe,
+	0x83, 0xe7, 0xc4, 0xa1,
+	0xfe, 0x03, 0x40, 0x09, 0x4a, 0x4f, 0x35, 0x01, 0xa8, 0xad, 0xfe, 0x1f,
+	0x40, 0x12, 0x58, 0x01,
+	0xa5, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6,
+	0x51, 0x83, 0xfb, 0xfe,
+	0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x0c, 0x90, 0xfe, 0x8e, 0x90,
+	0xfe, 0x40, 0x50, 0xfe,
+	0xc2, 0x50, 0x0c, 0x39, 0x18, 0x3a, 0xfe, 0x4a, 0x10, 0x09, 0x04, 0x6a,
+	0xfe, 0x2a, 0x12, 0xfe,
+	0x2c, 0x90, 0xfe, 0xae, 0x90, 0x0c, 0x54, 0x18, 0x55, 0x09, 0x04, 0x4f,
+	0x85, 0x01, 0xa8, 0xfe,
+	0x1f, 0x80, 0x12, 0x58, 0xfe, 0x44, 0x90, 0xfe, 0xc6, 0x90, 0x0c, 0x56,
+	0x18, 0x57, 0xfb, 0xfe,
+	0x8a, 0x90, 0x0c, 0x52, 0x18, 0x53, 0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90,
+	0x0c, 0x39, 0x18, 0x3a,
+	0x0c, 0x38, 0x18, 0x4e, 0x09, 0x4a, 0x19, 0x35, 0x2a, 0x13, 0xfe, 0x4e,
+	0x11, 0x65, 0xfe, 0x48,
+	0x08, 0xfe, 0x9e, 0xf0, 0xfe, 0x5c, 0x08, 0xb1, 0x16, 0x32, 0x2a, 0x73,
+	0xdd, 0xb8, 0xfe, 0x80,
+	0x08, 0xb9, 0xfe, 0x9e, 0x08, 0x8c, 0xfe, 0x74, 0x08, 0xfe, 0x06, 0xf0,
+	0xfe, 0x7a, 0x08, 0x8d,
+	0x81, 0x02, 0x22, 0x01, 0x43, 0xfe, 0xc9, 0x10, 0x15, 0x19, 0xfe, 0xc9,
+	0x10, 0x61, 0x04, 0x06,
+	0xfe, 0x10, 0x12, 0x61, 0x04, 0x0b, 0x45, 0x09, 0x04, 0x0b, 0xfe, 0x68,
+	0x12, 0xfe, 0x2e, 0x1c,
+	0x02, 0xfe, 0x24, 0x0a, 0x61, 0x04, 0x06, 0x45, 0x61, 0x04, 0x0b, 0xfe,
+	0x52, 0x12, 0xfe, 0x2c,
+	0x1c, 0xfe, 0xaa, 0xf0, 0xfe, 0x1e, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0xbe,
+	0x08, 0xfe, 0x8a, 0x10,
+	0xaa, 0xfe, 0xf3, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0xca, 0x08, 0x02, 0xfe,
+	0x24, 0x0a, 0xab, 0xfe,
+	0xe7, 0x10, 0xfe, 0x2b, 0xf0, 0x9d, 0xe9, 0x1c, 0xfe, 0x00, 0xfe, 0xfe,
+	0x1c, 0x12, 0xb5, 0xfe,
+	0xd2, 0xf0, 0x9d, 0xfe, 0x76, 0x18, 0x1c, 0x1a, 0x16, 0x9d, 0x05, 0xcb,
+	0x1c, 0x06, 0x16, 0x9d,
+	0xb8, 0x6d, 0xb9, 0x6d, 0xaa, 0xab, 0xfe, 0xb1, 0x10, 0x70, 0x5e, 0x2b,
+	0x14, 0x92, 0x01, 0x33,
+	0x0f, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x5a, 0x0f, 0x7c, 0x02, 0x5a,
+	0xfe, 0x74, 0x18, 0x1c,
+	0xfe, 0x00, 0xf8, 0x16, 0x6d, 0x67, 0x1b, 0x01, 0xfe, 0x44, 0x0d, 0x3b,
+	0x01, 0xe6, 0x1e, 0x27,
+	0x74, 0x67, 0x1a, 0x02, 0x6d, 0x09, 0x04, 0x0b, 0x21, 0xfe, 0x06, 0x0a,
+	0x09, 0x04, 0x6a, 0xfe,
+	0x82, 0x12, 0x09, 0x04, 0x19, 0xfe, 0x66, 0x13, 0x1e, 0x58, 0xac, 0xfc,
+	0xfe, 0x83, 0x80, 0xfe,
+	0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91, 0xfe, 0x86, 0x91, 0x63,
+	0x27, 0xfe, 0x40, 0x59,
+	0xfe, 0xc1, 0x59, 0x77, 0xd7, 0x05, 0x54, 0x31, 0x55, 0x0c, 0x7b, 0x18,
+	0x7c, 0xbe, 0x54, 0xbf,
+	0x55, 0x01, 0xa8, 0xad, 0x63, 0x27, 0x12, 0x58, 0xc0, 0x38, 0xc1, 0x4e,
+	0x79, 0x56, 0x68, 0x57,
+	0xf4, 0xf5, 0xfe, 0x04, 0xfa, 0x38, 0xfe, 0x05, 0xfa, 0x4e, 0x01, 0xa5,
+	0xa2, 0x23, 0x0c, 0x7b,
+	0x0c, 0x7c, 0x79, 0x56, 0x68, 0x57, 0xfe, 0x12, 0x10, 0x09, 0x04, 0x19,
+	0x16, 0xd7, 0x79, 0x39,
+	0x68, 0x3a, 0x09, 0x04, 0xfe, 0xf7, 0x00, 0x35, 0x05, 0x52, 0x31, 0x53,
+	0xfe, 0x10, 0x58, 0xfe,
+	0x91, 0x58, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x02, 0x6d, 0x09, 0x04,
+	0x19, 0x16, 0xd7, 0x09,
+	0x04, 0xfe, 0xf7, 0x00, 0x35, 0xfe, 0x3a, 0x55, 0xfe, 0x19, 0x81, 0x5f,
+	0xfe, 0x10, 0x90, 0xfe,
+	0x92, 0x90, 0xfe, 0xd7, 0x10, 0x2f, 0x07, 0x9b, 0x16, 0xfe, 0xc6, 0x08,
+	0x11, 0x9b, 0x09, 0x04,
+	0x0b, 0xfe, 0x14, 0x13, 0x05, 0x39, 0x31, 0x3a, 0x77, 0xfe, 0xc6, 0x08,
+	0xfe, 0x0c, 0x58, 0xfe,
+	0x8d, 0x58, 0x02, 0x6d, 0x23, 0x47, 0xfe, 0x19, 0x80, 0xde, 0x09, 0x04,
+	0x0b, 0xfe, 0x1a, 0x12,
+	0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xe9, 0xb5, 0xfe, 0xd1, 0xf0, 0xd9,
+	0x14, 0x7a, 0x01, 0x33,
+	0x0f, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19, 0xbe, 0x39,
+	0xfe, 0xed, 0x19, 0xbf,
+	0x3a, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xe9, 0x1c, 0xfe, 0x00, 0xff,
+	0x34, 0xfe, 0x74, 0x10,
+	0xb5, 0xfe, 0xd2, 0xf0, 0xfe, 0xb2, 0x0a, 0xfe, 0x76, 0x18, 0x1c, 0x1a,
+	0x84, 0x05, 0xcb, 0x1c,
+	0x06, 0xfe, 0x08, 0x13, 0x0f, 0xfe, 0x16, 0x00, 0x02, 0x5a, 0xfe, 0xd1,
+	0xf0, 0xfe, 0xc4, 0x0a,
+	0x14, 0x7a, 0x01, 0x33, 0x0f, 0xfe, 0x17, 0x00, 0xfe, 0x42, 0x10, 0xfe,
+	0xce, 0xf0, 0xfe, 0xca,
+	0x0a, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xd6, 0x0a, 0x0f, 0xfe,
+	0x22, 0x00, 0x02, 0x5a,
+	0xfe, 0xcb, 0xf0, 0xfe, 0xe2, 0x0a, 0x0f, 0xfe, 0x24, 0x00, 0x02, 0x5a,
+	0xfe, 0xd0, 0xf0, 0xfe,
+	0xec, 0x0a, 0x0f, 0x93, 0xdc, 0xfe, 0xcf, 0xf0, 0xfe, 0xf6, 0x0a, 0x0f,
+	0x4c, 0xfe, 0x10, 0x10,
+	0xfe, 0xcc, 0xf0, 0xd9, 0x61, 0x04, 0x19, 0x3b, 0x0f, 0xfe, 0x12, 0x00,
+	0x2a, 0x13, 0xfe, 0x4e,
+	0x11, 0x65, 0xfe, 0x0c, 0x0b, 0xfe, 0x9e, 0xf0, 0xfe, 0x20, 0x0b, 0xb1,
+	0x16, 0x32, 0x2a, 0x73,
+	0xdd, 0xb8, 0x22, 0xb9, 0x22, 0x2a, 0xec, 0x65, 0xfe, 0x2c, 0x0b, 0x25,
+	0x32, 0x8c, 0xfe, 0x48,
+	0x0b, 0x8d, 0x81, 0xb8, 0xd4, 0xb9, 0xd4, 0x02, 0x22, 0x01, 0x43, 0xfe,
+	0xdb, 0x10, 0x11, 0xfe,
+	0xe8, 0x00, 0xaa, 0xab, 0x70, 0xbc, 0x7d, 0xbd, 0x7f, 0xfe, 0x89, 0xf0,
+	0x22, 0x30, 0x2e, 0xd8,
+	0xbc, 0x7d, 0xbd, 0x7f, 0x01, 0x08, 0x1f, 0x22, 0x30, 0x2e, 0xd6, 0xb1,
+	0x45, 0x0f, 0xfe, 0x42,
+	0x00, 0x02, 0x5a, 0x78, 0x06, 0xfe, 0x81, 0x49, 0x16, 0xfe, 0x38, 0x0c,
+	0x09, 0x04, 0x0b, 0xfe,
+	0x44, 0x13, 0x0f, 0x00, 0x4b, 0x0b, 0xfe, 0x54, 0x12, 0x4b, 0xfe, 0x28,
+	0x00, 0x21, 0xfe, 0xa6,
+	0x0c, 0x0a, 0x40, 0x01, 0x0e, 0x07, 0x00, 0x5d, 0x3e, 0xfe, 0x28, 0x00,
+	0xfe, 0xe2, 0x10, 0x01,
+	0xe7, 0x01, 0xe8, 0x0a, 0x99, 0x01, 0xfe, 0x32, 0x0e, 0x59, 0x11, 0x2d,
+	0x01, 0x6f, 0x02, 0x29,
+	0x0f, 0xfe, 0x44, 0x00, 0x4b, 0x0b, 0xdf, 0x3e, 0x0b, 0xfe, 0xb4, 0x10,
+	0x01, 0x86, 0x3e, 0x0b,
+	0xfe, 0xaa, 0x10, 0x01, 0x86, 0xfe, 0x19, 0x82, 0xfe, 0x34, 0x46, 0xa3,
+	0x3e, 0x0b, 0x0f, 0xfe,
+	0x43, 0x00, 0xfe, 0x96, 0x10, 0x09, 0x4a, 0x0b, 0x35, 0x01, 0xe7, 0x01,
+	0xe8, 0x59, 0x11, 0x2d,
+	0x01, 0x6f, 0x67, 0x0b, 0x59, 0x3c, 0x8a, 0x02, 0xfe, 0x2a, 0x03, 0x09,
+	0x04, 0x0b, 0x84, 0x3e,
+	0x0b, 0x0f, 0x00, 0xfe, 0x5c, 0x10, 0x61, 0x04, 0x1b, 0xfe, 0x58, 0x12,
+	0x09, 0x04, 0x1b, 0xfe,
+	0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x5c, 0x0c, 0xfe,
+	0x1c, 0x1c, 0xfe, 0x9d,
+	0xf0, 0xfe, 0x62, 0x0c, 0x09, 0x4a, 0x1b, 0x35, 0xfe, 0xa9, 0x10, 0x0f,
+	0xfe, 0x15, 0x00, 0xfe,
+	0x04, 0xe6, 0x0b, 0x5f, 0x5c, 0x0f, 0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10,
+	0x0f, 0xfe, 0x47, 0x00,
+	0xa1, 0x0f, 0xfe, 0x41, 0x00, 0xa0, 0x0f, 0xfe, 0x24, 0x00, 0x87, 0xaa,
+	0xab, 0x70, 0x05, 0x6b,
+	0x28, 0x21, 0xd1, 0x5f, 0xfe, 0x04, 0xe6, 0x1b, 0xfe, 0x9d, 0x41, 0xfe,
+	0x1c, 0x42, 0x59, 0x01,
+	0xda, 0x02, 0x29, 0xea, 0x14, 0x0b, 0x37, 0x95, 0xa9, 0x14, 0xfe, 0x31,
+	0x00, 0x37, 0x97, 0x01,
+	0xfe, 0x54, 0x0f, 0x02, 0xd0, 0x3c, 0xfe, 0x06, 0xec, 0xc9, 0xee, 0x3e,
+	0x1d, 0xfe, 0xce, 0x45,
+	0x34, 0x3c, 0xfe, 0x06, 0xea, 0xc9, 0xfe, 0x47, 0x4b, 0x89, 0xfe, 0x75,
+	0x57, 0x05, 0x51, 0xfe,
+	0x98, 0x56, 0xfe, 0x38, 0x12, 0x0a, 0x42, 0x01, 0x0e, 0xfe, 0x44, 0x48,
+	0x46, 0x09, 0x04, 0x1d,
+	0xfe, 0x1a, 0x13, 0x0a, 0x40, 0x01, 0x0e, 0x47, 0xfe, 0x41, 0x58, 0x0a,
+	0x99, 0x01, 0x0e, 0xfe,
+	0x49, 0x54, 0x8e, 0xfe, 0x2a, 0x0d, 0x02, 0xfe, 0x2a, 0x03, 0x0a, 0x51,
+	0xfe, 0xee, 0x14, 0xee,
+	0x3e, 0x1d, 0xfe, 0xce, 0x45, 0x34, 0x3c, 0xfe, 0xce, 0x47, 0xfe, 0xad,
+	0x13, 0x02, 0x29, 0x1e,
+	0x20, 0x07, 0x10, 0xfe, 0x9e, 0x12, 0x23, 0x12, 0x4d, 0x12, 0x94, 0x12,
+	0xce, 0x1e, 0x2d, 0x47,
+	0x37, 0x2d, 0xb1, 0xe0, 0xfe, 0xbc, 0xf0, 0xfe, 0xec, 0x0d, 0x13, 0x06,
+	0x12, 0x4d, 0x01, 0xfe,
+	0xe2, 0x15, 0x05, 0xfe, 0x38, 0x01, 0x31, 0xfe, 0x3a, 0x01, 0x77, 0xfe,
+	0xf0, 0x0d, 0xfe, 0x02,
+	0xec, 0xce, 0x62, 0x00, 0x5d, 0xfe, 0x04, 0xec, 0x20, 0x46, 0xfe, 0x05,
+	0xf6, 0xfe, 0x34, 0x01,
+	0x01, 0xfe, 0x52, 0x16, 0xfb, 0xfe, 0x48, 0xf4, 0x0d, 0xfe, 0x18, 0x13,
+	0xaf, 0xfe, 0x02, 0xea,
+	0xce, 0x62, 0x7a, 0xfe, 0xc5, 0x13, 0x14, 0x1b, 0x37, 0x95, 0xa9, 0x5c,
+	0x05, 0xfe, 0x38, 0x01,
+	0x1c, 0xfe, 0xf0, 0xff, 0x0c, 0xfe, 0x60, 0x01, 0x05, 0xfe, 0x3a, 0x01,
+	0x0c, 0xfe, 0x62, 0x01,
+	0x3d, 0x12, 0x20, 0x24, 0x06, 0x12, 0x2d, 0x11, 0x2d, 0x8a, 0x13, 0x06,
+	0x03, 0x23, 0x03, 0x1e,
+	0x4d, 0xfe, 0xf7, 0x12, 0x1e, 0x94, 0xac, 0x12, 0x94, 0x07, 0x7a, 0xfe,
+	0x71, 0x13, 0xfe, 0x24,
+	0x1c, 0x14, 0x1a, 0x37, 0x95, 0xa9, 0xfe, 0xd9, 0x10, 0xb6, 0xfe, 0x03,
+	0xdc, 0xfe, 0x73, 0x57,
+	0xfe, 0x80, 0x5d, 0x03, 0xb6, 0xfe, 0x03, 0xdc, 0xfe, 0x5b, 0x57, 0xfe,
+	0x80, 0x5d, 0x03, 0xfe,
+	0x03, 0x57, 0xb6, 0x23, 0xfe, 0x00, 0xcc, 0x03, 0xfe, 0x03, 0x57, 0xb6,
+	0x75, 0x03, 0x09, 0x04,
+	0x4c, 0xfe, 0x22, 0x13, 0xfe, 0x1c, 0x80, 0x07, 0x06, 0xfe, 0x1a, 0x13,
+	0xfe, 0x1e, 0x80, 0xe1,
+	0xfe, 0x1d, 0x80, 0xa4, 0xfe, 0x0c, 0x90, 0xfe, 0x0e, 0x13, 0xfe, 0x0e,
+	0x90, 0xa3, 0xfe, 0x3c,
+	0x90, 0xfe, 0x30, 0xf4, 0x0b, 0xfe, 0x3c, 0x50, 0xa0, 0x01, 0xfe, 0x82,
+	0x16, 0x2f, 0x07, 0x2d,
+	0xe0, 0x01, 0xfe, 0xbc, 0x15, 0x09, 0x04, 0x1d, 0x45, 0x01, 0xe7, 0x01,
+	0xe8, 0x11, 0xfe, 0xe9,
+	0x00, 0x09, 0x04, 0x4c, 0xfe, 0x2c, 0x13, 0x01, 0xfe, 0x14, 0x16, 0xfe,
+	0x1e, 0x1c, 0xfe, 0x14,
+	0x90, 0xfe, 0x96, 0x90, 0x0c, 0xfe, 0x64, 0x01, 0x18, 0xfe, 0x66, 0x01,
+	0x09, 0x04, 0x4f, 0xfe,
+	0x12, 0x12, 0xfe, 0x03, 0x80, 0x74, 0xfe, 0x01, 0xec, 0x20, 0xfe, 0x80,
+	0x40, 0x12, 0x20, 0x63,
+	0x27, 0x11, 0xc8, 0x59, 0x1e, 0x20, 0xed, 0x76, 0x20, 0x03, 0xfe, 0x08,
+	0x1c, 0x05, 0xfe, 0xac,
+	0x00, 0xfe, 0x06, 0x58, 0x05, 0xfe, 0xae, 0x00, 0xfe, 0x07, 0x58, 0x05,
+	0xfe, 0xb0, 0x00, 0xfe,
+	0x08, 0x58, 0x05, 0xfe, 0xb2, 0x00, 0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c,
+	0x24, 0x69, 0x12, 0xc9,
+	0x23, 0x0c, 0x50, 0x0c, 0x3f, 0x13, 0x40, 0x48, 0x5f, 0x17, 0x1d, 0xfe,
+	0x90, 0x4d, 0xfe, 0x91,
+	0x54, 0x21, 0xfe, 0x08, 0x0f, 0x3e, 0x10, 0x13, 0x42, 0x48, 0x17, 0x4c,
+	0xfe, 0x90, 0x4d, 0xfe,
+	0x91, 0x54, 0x21, 0xfe, 0x1e, 0x0f, 0x24, 0x10, 0x12, 0x20, 0x78, 0x2c,
+	0x46, 0x1e, 0x20, 0xed,
+	0x76, 0x20, 0x11, 0xc8, 0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x32, 0x0f, 0xea,
+	0x70, 0xfe, 0x14, 0x1c,
+	0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x03, 0x3c, 0xfe, 0x0c, 0x14, 0xee,
+	0xfe, 0x07, 0xe6, 0x1d,
+	0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x03, 0x01, 0x86, 0x78, 0x2c, 0x46,
+	0xfa, 0xef, 0xfe, 0x42,
+	0x13, 0x2f, 0x07, 0x2d, 0xfe, 0x34, 0x13, 0x0a, 0x42, 0x01, 0x0e, 0xb0,
+	0xfe, 0x36, 0x12, 0xf0,
+	0xfe, 0x45, 0x48, 0x01, 0xe3, 0xfe, 0x00, 0xcc, 0xb0, 0xfe, 0xf3, 0x13,
+	0x3d, 0x75, 0x07, 0x10,
+	0xa3, 0x0a, 0x80, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x6f, 0xfe, 0x0e,
+	0x10, 0x07, 0x7e, 0x45,
+	0xf6, 0xfe, 0xd6, 0xf0, 0xfe, 0x6c, 0x0f, 0x03, 0xfe, 0x44, 0x58, 0x74,
+	0xfe, 0x01, 0xec, 0x97,
+	0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1b, 0x76,
+	0x27, 0x01, 0xda, 0xfe,
+	0xdd, 0x10, 0x2a, 0xbc, 0x7d, 0xbd, 0x7f, 0x30, 0x2e, 0xd5, 0x07, 0x1b,
+	0xfe, 0x48, 0x12, 0x07,
+	0x0b, 0xfe, 0x56, 0x12, 0x07, 0x1a, 0xfe, 0x30, 0x12, 0x07, 0xc2, 0x16,
+	0xfe, 0x3e, 0x11, 0x07,
+	0xfe, 0x23, 0x00, 0x16, 0xfe, 0x4a, 0x11, 0x07, 0x06, 0x16, 0xfe, 0xa8,
+	0x11, 0x07, 0x19, 0xfe,
+	0x12, 0x12, 0x07, 0x00, 0x16, 0x22, 0x14, 0xc2, 0x01, 0x33, 0x9f, 0x2b,
+	0x01, 0x08, 0x8c, 0x43,
+	0x03, 0x2b, 0xfe, 0x62, 0x08, 0x0a, 0xca, 0x01, 0xfe, 0x32, 0x0e, 0x11,
+	0x7e, 0x02, 0x29, 0x2b,
+	0x2f, 0x07, 0x9b, 0xfe, 0xd9, 0x13, 0x79, 0x39, 0x68, 0x3a, 0x77, 0xfe,
+	0xfc, 0x10, 0x09, 0x04,
+	0x6a, 0xfe, 0x72, 0x12, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x8e, 0xfe,
+	0xc6, 0x10, 0x1e, 0x58,
+	0xfe, 0x26, 0x13, 0x05, 0x7b, 0x31, 0x7c, 0x77, 0xfe, 0x82, 0x0c, 0x0c,
+	0x54, 0x18, 0x55, 0x23,
+	0x0c, 0x7b, 0x0c, 0x7c, 0x01, 0xa8, 0x24, 0x69, 0x73, 0x12, 0x58, 0x01,
+	0xa5, 0xc0, 0x38, 0xc1,
+	0x4e, 0xfe, 0x04, 0x55, 0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x38, 0xfe,
+	0x05, 0xfa, 0x4e, 0xfe,
+	0x91, 0x10, 0x05, 0x56, 0x31, 0x57, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56,
+	0x0c, 0x56, 0x18, 0x57,
+	0x83, 0xc0, 0x38, 0xc1, 0x4e, 0xf4, 0xf5, 0x05, 0x52, 0x31, 0x53, 0xfe,
+	0x00, 0x56, 0xfe, 0xa1,
+	0x56, 0x0c, 0x52, 0x18, 0x53, 0x09, 0x04, 0x6a, 0xfe, 0x1e, 0x12, 0x1e,
+	0x58, 0xfe, 0x1f, 0x40,
+	0x05, 0x54, 0x31, 0x55, 0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x05, 0x56,
+	0x31, 0x57, 0xfe, 0x44,
+	0x50, 0xfe, 0xc6, 0x50, 0x05, 0x52, 0x31, 0x53, 0xfe, 0x08, 0x50, 0xfe,
+	0x8a, 0x50, 0x05, 0x39,
+	0x31, 0x3a, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x02, 0x5c, 0x24, 0x06,
+	0x12, 0xcd, 0x02, 0x5b,
+	0x2b, 0x01, 0x08, 0x1f, 0x44, 0x30, 0x2e, 0xd5, 0x07, 0x06, 0x21, 0x44,
+	0x2f, 0x07, 0x9b, 0x21,
+	0x5b, 0x01, 0x6e, 0x1c, 0x3d, 0x16, 0x44, 0x09, 0x04, 0x0b, 0xe2, 0x79,
+	0x39, 0x68, 0x3a, 0xfe,
+	0x0a, 0x55, 0x34, 0xfe, 0x8b, 0x55, 0xbe, 0x39, 0xbf, 0x3a, 0xfe, 0x0c,
+	0x51, 0xfe, 0x8e, 0x51,
+	0x02, 0x5b, 0xfe, 0x19, 0x81, 0xaf, 0xfe, 0x19, 0x41, 0x02, 0x5b, 0x2b,
+	0x01, 0x08, 0x25, 0x32,
+	0x1f, 0xa2, 0x30, 0x2e, 0xd8, 0x4b, 0x1a, 0xfe, 0xa6, 0x12, 0x4b, 0x0b,
+	0x3b, 0x02, 0x44, 0x01,
+	0x08, 0x25, 0x32, 0x1f, 0xa2, 0x30, 0x2e, 0xd6, 0x07, 0x1a, 0x21, 0x44,
+	0x01, 0x08, 0x1f, 0xa2,
+	0x30, 0x2e, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x60, 0x05, 0xfe, 0x9c,
+	0x00, 0x28, 0x84, 0x49,
+	0x04, 0x19, 0x34, 0x9f, 0xfe, 0xbb, 0x45, 0x4b, 0x00, 0x45, 0x3e, 0x06,
+	0x78, 0x3d, 0xfe, 0xda,
+	0x14, 0x01, 0x6e, 0x87, 0xfe, 0x4b, 0x45, 0xe2, 0x2f, 0x07, 0x9a, 0xe1,
+	0x05, 0xc6, 0x28, 0x84,
+	0x05, 0x3f, 0x28, 0x34, 0x5e, 0x02, 0x5b, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8,
+	0x14, 0xfe, 0x03, 0x17,
+	0x05, 0x50, 0xb4, 0x0c, 0x50, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01,
+	0xfe, 0xaa, 0x14, 0x02,
+	0x5c, 0x01, 0x08, 0x25, 0x32, 0x1f, 0x44, 0x30, 0x2e, 0xd6, 0x07, 0x06,
+	0x21, 0x44, 0x01, 0xfe,
+	0x8e, 0x13, 0xfe, 0x42, 0x58, 0xfe, 0x82, 0x14, 0xfe, 0xa4, 0x14, 0x87,
+	0xfe, 0x4a, 0xf4, 0x0b,
+	0x16, 0x44, 0xfe, 0x4a, 0xf4, 0x06, 0xfe, 0x0c, 0x12, 0x2f, 0x07, 0x9a,
+	0x85, 0x02, 0x5b, 0x05,
+	0x3f, 0xb4, 0x0c, 0x3f, 0x5e, 0x2b, 0x01, 0x08, 0x26, 0x5c, 0x01, 0xfe,
+	0xd8, 0x14, 0x02, 0x5c,
+	0x13, 0x06, 0x65, 0xfe, 0xca, 0x12, 0x26, 0xfe, 0xe0, 0x12, 0x72, 0xf1,
+	0x01, 0x08, 0x23, 0x72,
+	0x03, 0x8f, 0xfe, 0xdc, 0x12, 0x25, 0xfe, 0xdc, 0x12, 0x1f, 0xfe, 0xca,
+	0x12, 0x5e, 0x2b, 0x01,
+	0x08, 0xfe, 0xd5, 0x10, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b,
+	0x1c, 0xfe, 0xff, 0x7f,
+	0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02, 0x00,
+	0x57, 0x48, 0x8b, 0x1c,
+	0x3d, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x03, 0x13, 0x6c, 0xff, 0x02,
+	0x00, 0x57, 0x48, 0x8b,
+	0x03, 0x13, 0x6c, 0xff, 0x02, 0x00, 0x57, 0x48, 0x8b, 0xfe, 0x0b, 0x58,
+	0x03, 0x0a, 0x50, 0x01,
+	0x82, 0x0a, 0x3f, 0x01, 0x82, 0x03, 0xfc, 0x1c, 0x10, 0xff, 0x03, 0x00,
+	0x54, 0xfe, 0x00, 0xf4,
+	0x19, 0x48, 0xfe, 0x00, 0x7d, 0xfe, 0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe,
+	0x03, 0x7c, 0x63, 0x27,
+	0x0c, 0x52, 0x18, 0x53, 0xbe, 0x56, 0xbf, 0x57, 0x03, 0xfe, 0x62, 0x08,
+	0xfe, 0x82, 0x4a, 0xfe,
+	0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x74, 0x03, 0x01, 0xfe, 0x14, 0x18, 0xfe,
+	0x42, 0x48, 0x5f, 0x60,
+	0x89, 0x01, 0x08, 0x1f, 0xfe, 0xa2, 0x14, 0x30, 0x2e, 0xd8, 0x01, 0x08,
+	0x1f, 0xfe, 0xa2, 0x14,
+	0x30, 0x2e, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59, 0x05, 0xc6, 0x28, 0xfe,
+	0xcc, 0x12, 0x49, 0x04,
+	0x1b, 0xfe, 0xc4, 0x13, 0x23, 0x62, 0x1b, 0xe2, 0x4b, 0xc3, 0x64, 0xfe,
+	0xe8, 0x13, 0x3b, 0x13,
+	0x06, 0x17, 0xc3, 0x78, 0xdb, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55,
+	0xa1, 0xff, 0x02, 0x83,
+	0x55, 0x62, 0x1a, 0xa4, 0xbb, 0xfe, 0x30, 0x00, 0x8e, 0xe4, 0x17, 0x2c,
+	0x13, 0x06, 0xfe, 0x56,
+	0x10, 0x62, 0x0b, 0xe1, 0xbb, 0xfe, 0x64, 0x00, 0x8e, 0xe4, 0x0a, 0xfe,
+	0x64, 0x00, 0x17, 0x93,
+	0x13, 0x06, 0xfe, 0x28, 0x10, 0x62, 0x06, 0xfe, 0x60, 0x13, 0xbb, 0xfe,
+	0xc8, 0x00, 0x8e, 0xe4,
+	0x0a, 0xfe, 0xc8, 0x00, 0x17, 0x4d, 0x13, 0x06, 0x83, 0xbb, 0xfe, 0x90,
+	0x01, 0xba, 0xfe, 0x4e,
+	0x14, 0x89, 0xfe, 0x12, 0x10, 0xfe, 0x43, 0xf4, 0x94, 0xfe, 0x56, 0xf0,
+	0xfe, 0x60, 0x14, 0xfe,
+	0x04, 0xf4, 0x6c, 0xfe, 0x43, 0xf4, 0x93, 0xfe, 0xf3, 0x10, 0xf9, 0x01,
+	0xfe, 0x22, 0x13, 0x1c,
+	0x3d, 0xfe, 0x10, 0x13, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x69, 0xba,
+	0xfe, 0x9c, 0x14, 0xb7,
+	0x69, 0xfe, 0x1c, 0x10, 0xfe, 0x00, 0x17, 0xfe, 0x4d, 0xe4, 0x19, 0xba,
+	0xfe, 0x9c, 0x14, 0xb7,
+	0x19, 0x83, 0x60, 0x23, 0xfe, 0x4d, 0xf4, 0x00, 0xdf, 0x89, 0x13, 0x06,
+	0xfe, 0xb4, 0x56, 0xfe,
+	0xc3, 0x58, 0x03, 0x60, 0x13, 0x0b, 0x03, 0x15, 0x06, 0x01, 0x08, 0x26,
+	0xe5, 0x15, 0x0b, 0x01,
+	0x08, 0x26, 0xe5, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xe5, 0x72, 0xfe, 0x89,
+	0x49, 0x01, 0x08, 0x03,
+	0x15, 0x06, 0x01, 0x08, 0x26, 0xa6, 0x15, 0x1a, 0x01, 0x08, 0x26, 0xa6,
+	0x15, 0x06, 0x01, 0x08,
+	0x26, 0xa6, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x26, 0xa6, 0x72, 0xfe, 0x89,
+	0x4a, 0x01, 0x08, 0x03,
+	0x60, 0x03, 0x1e, 0xcc, 0x07, 0x06, 0xfe, 0x44, 0x13, 0xad, 0x12, 0xcc,
+	0xfe, 0x49, 0xf4, 0x00,
+	0x3b, 0x72, 0x9f, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xf1, 0x01,
+	0x08, 0x2f, 0x07, 0xfe,
+	0xe3, 0x00, 0xfe, 0x20, 0x13, 0x1f, 0xfe, 0x5a, 0x15, 0x23, 0x12, 0xcd,
+	0x01, 0x43, 0x1e, 0xcd,
+	0x07, 0x06, 0x45, 0x09, 0x4a, 0x06, 0x35, 0x03, 0x0a, 0x42, 0x01, 0x0e,
+	0xed, 0x88, 0x07, 0x10,
+	0xa4, 0x0a, 0x80, 0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a,
+	0x80, 0x01, 0x0e, 0x88,
+	0xfe, 0x80, 0xe7, 0x10, 0x07, 0x10, 0x84, 0xfe, 0x45, 0x58, 0x01, 0xe3,
+	0x88, 0x03, 0x0a, 0x42,
+	0x01, 0x0e, 0x88, 0x0a, 0x51, 0x01, 0x9e, 0x03, 0x0a, 0x42, 0x01, 0x0e,
+	0xfe, 0x80, 0x80, 0xf2,
+	0xfe, 0x49, 0xe4, 0x10, 0xa4, 0x0a, 0x80, 0x01, 0x0e, 0xf2, 0x0a, 0x51,
+	0x01, 0x82, 0x03, 0x17,
+	0x10, 0x71, 0x66, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde,
+	0xfe, 0x24, 0x1c, 0xfe,
+	0x1d, 0xf7, 0x1d, 0x90, 0xfe, 0xf6, 0x15, 0x01, 0xfe, 0xfc, 0x16, 0xe0,
+	0x91, 0x1d, 0x66, 0xfe,
+	0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x03, 0xae, 0x21, 0xfe, 0xe6, 0x15, 0xfe,
+	0xda, 0x10, 0x17, 0x10,
+	0x71, 0x05, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x19, 0xfe, 0x18, 0x58,
+	0x05, 0xfe, 0x66, 0x01,
+	0xfe, 0x19, 0x58, 0x91, 0x19, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4, 0x06,
+	0xfe, 0x3c, 0x50, 0x66,
+	0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x19, 0x90, 0xfe,
+	0x40, 0x16, 0xfe, 0xb6,
+	0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x18, 0x16, 0xfe, 0x9c, 0x10, 0x17,
+	0x10, 0x71, 0xfe, 0x83,
+	0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7, 0x38, 0x90,
+	0xfe, 0x62, 0x16, 0xfe,
+	0x94, 0x14, 0xfe, 0x10, 0x13, 0x91, 0x38, 0x66, 0x1b, 0xfe, 0xaf, 0x19,
+	0xfe, 0x98, 0xe7, 0x00,
+	0x03, 0xae, 0x21, 0xfe, 0x56, 0x16, 0xfe, 0x6c, 0x10, 0x17, 0x10, 0x71,
+	0xfe, 0x30, 0xbc, 0xfe,
+	0xb2, 0xbc, 0x91, 0xc5, 0x66, 0x1b, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
+	0xc5, 0x90, 0xfe, 0x9a,
+	0x16, 0xfe, 0x5c, 0x14, 0x34, 0x03, 0xae, 0x21, 0xfe, 0x86, 0x16, 0xfe,
+	0x42, 0x10, 0xfe, 0x02,
+	0xf6, 0x10, 0x71, 0xfe, 0x18, 0xfe, 0x54, 0xfe, 0x19, 0xfe, 0x55, 0xfc,
+	0xfe, 0x1d, 0xf7, 0x4f,
+	0x90, 0xfe, 0xc0, 0x16, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13, 0x91, 0x4f,
+	0x47, 0xfe, 0x83, 0x58,
+	0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x10, 0xfe, 0x81, 0xe7, 0x10, 0x11,
+	0xfe, 0xdd, 0x00, 0x63,
+	0x27, 0x03, 0x63, 0x27, 0xfe, 0x12, 0x45, 0x21, 0xfe, 0xb0, 0x16, 0x14,
+	0x06, 0x37, 0x95, 0xa9,
+	0x02, 0x29, 0xfe, 0x39, 0xf0, 0xfe, 0x04, 0x17, 0x23, 0x03, 0xfe, 0x7e,
+	0x18, 0x1c, 0x1a, 0x5d,
+	0x13, 0x0d, 0x03, 0x71, 0x05, 0xcb, 0x1c, 0x06, 0xfe, 0xef, 0x12, 0xfe,
+	0xe1, 0x10, 0x78, 0x2c,
+	0x46, 0x2f, 0x07, 0x2d, 0xfe, 0x3c, 0x13, 0xfe, 0x82, 0x14, 0xfe, 0x42,
+	0x13, 0x3c, 0x8a, 0x0a,
+	0x42, 0x01, 0x0e, 0xb0, 0xfe, 0x3e, 0x12, 0xf0, 0xfe, 0x45, 0x48, 0x01,
+	0xe3, 0xfe, 0x00, 0xcc,
+	0xb0, 0xfe, 0xf3, 0x13, 0x3d, 0x75, 0x07, 0x10, 0xa3, 0x0a, 0x80, 0x01,
+	0x0e, 0xf2, 0x01, 0x6f,
+	0xfe, 0x16, 0x10, 0x07, 0x7e, 0x85, 0xfe, 0x40, 0x14, 0xfe, 0x24, 0x12,
+	0xf6, 0xfe, 0xd6, 0xf0,
+	0xfe, 0x24, 0x17, 0x17, 0x0b, 0x03, 0xfe, 0x9c, 0xe7, 0x0b, 0x0f, 0xfe,
+	0x15, 0x00, 0x59, 0x76,
+	0x27, 0x01, 0xda, 0x17, 0x06, 0x03, 0x3c, 0x8a, 0x09, 0x4a, 0x1d, 0x35,
+	0x11, 0x2d, 0x01, 0x6f,
+	0x17, 0x06, 0x03, 0xfe, 0x38, 0x90, 0xfe, 0xba, 0x90, 0x79, 0xc7, 0x68,
+	0xc8, 0xfe, 0x48, 0x55,
+	0x34, 0xfe, 0xc9, 0x55, 0x03, 0x1e, 0x98, 0x73, 0x12, 0x98, 0x03, 0x0a,
+	0x99, 0x01, 0x0e, 0xf0,
+	0x0a, 0x40, 0x01, 0x0e, 0xfe, 0x49, 0x44, 0x16, 0xfe, 0xf0, 0x17, 0x73,
+	0x75, 0x03, 0x0a, 0x42,
+	0x01, 0x0e, 0x07, 0x10, 0x45, 0x0a, 0x51, 0x01, 0x9e, 0x0a, 0x40, 0x01,
+	0x0e, 0x73, 0x75, 0x03,
+	0xfe, 0x4e, 0xe4, 0x1a, 0x64, 0xfe, 0x24, 0x18, 0x05, 0xfe, 0x90, 0x00,
+	0xfe, 0x3a, 0x45, 0x5b,
+	0xfe, 0x4e, 0xe4, 0xc2, 0x64, 0xfe, 0x36, 0x18, 0x05, 0xfe, 0x92, 0x00,
+	0xfe, 0x02, 0xe6, 0x1b,
+	0xdc, 0xfe, 0x4e, 0xe4, 0xfe, 0x0b, 0x00, 0x64, 0xfe, 0x48, 0x18, 0x05,
+	0xfe, 0x94, 0x00, 0xfe,
+	0x02, 0xe6, 0x19, 0xfe, 0x08, 0x10, 0x05, 0xfe, 0x96, 0x00, 0xfe, 0x02,
+	0xe6, 0x2c, 0xfe, 0x4e,
+	0x45, 0xfe, 0x0c, 0x12, 0xaf, 0xff, 0x04, 0x68, 0x54, 0xde, 0x1c, 0x69,
+	0x03, 0x07, 0x7a, 0xfe,
+	0x5a, 0xf0, 0xfe, 0x74, 0x18, 0x24, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
+	0x07, 0x1b, 0xfe, 0x5a,
+	0xf0, 0xfe, 0x82, 0x18, 0x24, 0xc3, 0xfe, 0x26, 0x10, 0x07, 0x1a, 0x5d,
+	0x24, 0x2c, 0xdc, 0x07,
+	0x0b, 0x5d, 0x24, 0x93, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x5d, 0x24, 0x4d,
+	0x9f, 0xad, 0x03, 0x14,
+	0xfe, 0x09, 0x00, 0x01, 0x33, 0xfe, 0x04, 0xfe, 0x7d, 0x05, 0x7f, 0xf9,
+	0x03, 0x25, 0xfe, 0xca,
+	0x18, 0xfe, 0x14, 0xf0, 0x08, 0x65, 0xfe, 0xc6, 0x18, 0x03, 0xff, 0x1a,
+	0x00, 0x00,
 };
 
-STATIC unsigned short _adv_asc3550_size =
-        sizeof(_adv_asc3550_buf); /* 0x13AD */
-STATIC ADV_DCNT _adv_asc3550_chksum =
-        0x04D52DDDUL; /* Expanded little-endian checksum. */
+static unsigned short _adv_asc3550_size = sizeof(_adv_asc3550_buf);	/* 0x13AD */
+static ADV_DCNT _adv_asc3550_chksum = 0x04D52DDDUL;	/* Expanded little-endian checksum. */
 
 /* Microcode buffer is kept after initialization for error recovery. */
-STATIC unsigned char _adv_asc38C0800_buf[] = {
-  0x00,  0x00,  0x00,  0xf2,  0x00,  0xf0,  0x00,  0xfc,  0x00,  0x16,  0x18,  0xe4,  0x01,  0x00,  0x48,  0xe4,
-  0x18,  0x80,  0x03,  0xf6,  0x02,  0x00,  0xce,  0x19,  0x00,  0xfa,  0xff,  0xff,  0x1c,  0x0f,  0x00,  0xf6,
-  0x9e,  0xe7,  0xff,  0x00,  0x82,  0xe7,  0x00,  0xea,  0x01,  0xfa,  0x01,  0xe6,  0x09,  0xe7,  0x55,  0xf0,
-  0x01,  0xf6,  0x03,  0x00,  0x04,  0x00,  0x10,  0x00,  0x1e,  0xf0,  0x85,  0xf0,  0x18,  0xf4,  0x08,  0x00,
-  0xbc,  0x00,  0x38,  0x54,  0x00,  0xec,  0xd5,  0xf0,  0x82,  0x0d,  0x00,  0xe6,  0x86,  0xf0,  0xb1,  0xf0,
-  0x98,  0x57,  0x01,  0xfc,  0xb4,  0x00,  0xd4,  0x01,  0x0c,  0x1c,  0x3e,  0x1c,  0x3c,  0x00,  0xbb,  0x00,
-  0x00,  0x10,  0xba,  0x19,  0x02,  0x80,  0x32,  0xf0,  0x7c,  0x0d,  0x02,  0x13,  0xba,  0x13,  0x18,  0x40,
-  0x00,  0x57,  0x01,  0xea,  0x02,  0xfc,  0x03,  0xfc,  0x3e,  0x00,  0x6c,  0x01,  0x6e,  0x01,  0x74,  0x01,
-  0x76,  0x01,  0xb9,  0x54,  0x3e,  0x57,  0x00,  0x80,  0x03,  0xe6,  0xb6,  0x00,  0xc0,  0x00,  0x01,  0x01,
-  0x3e,  0x01,  0x7a,  0x01,  0xca,  0x08,  0xce,  0x10,  0x16,  0x11,  0x04,  0x12,  0x08,  0x12,  0x02,  0x4a,
-  0xbb,  0x55,  0x3c,  0x56,  0x03,  0x58,  0x1b,  0x80,  0x30,  0xe4,  0x4b,  0xe4,  0x5d,  0xf0,  0x02,  0xfa,
-  0x20,  0x00,  0x32,  0x00,  0x40,  0x00,  0x80,  0x00,  0x24,  0x01,  0x3c,  0x01,  0x68,  0x01,  0x6a,  0x01,
-  0x70,  0x01,  0x72,  0x01,  0x78,  0x01,  0x7c,  0x01,  0x62,  0x0a,  0x86,  0x0d,  0x06,  0x13,  0x4c,  0x1c,
-  0x04,  0x80,  0x4a,  0xe4,  0x02,  0xee,  0x5b,  0xf0,  0x03,  0xf7,  0x0c,  0x00,  0x0f,  0x00,  0x47,  0x00,
-  0xbe,  0x00,  0x00,  0x01,  0x20,  0x11,  0x5c,  0x16,  0x32,  0x1c,  0x38,  0x1c,  0x4e,  0x1c,  0x10,  0x44,
-  0x00,  0x4c,  0x04,  0xea,  0x5c,  0xf0,  0xa7,  0xf0,  0x04,  0xf6,  0x03,  0xfa,  0x05,  0x00,  0x34,  0x00,
-  0x36,  0x00,  0x98,  0x00,  0xcc,  0x00,  0x20,  0x01,  0x4e,  0x01,  0x4a,  0x0b,  0x42,  0x0c,  0x12,  0x0f,
-  0x0c,  0x10,  0x22,  0x11,  0x0a,  0x12,  0x04,  0x13,  0x30,  0x1c,  0x02,  0x48,  0x00,  0x4e,  0x42,  0x54,
-  0x44,  0x55,  0xbd,  0x56,  0x06,  0x83,  0x00,  0xdc,  0x05,  0xf0,  0x09,  0xf0,  0x59,  0xf0,  0xb8,  0xf0,
-  0x4b,  0xf4,  0x06,  0xf7,  0x0e,  0xf7,  0x04,  0xfc,  0x05,  0xfc,  0x06,  0x00,  0x19,  0x00,  0x33,  0x00,
-  0x9b,  0x00,  0xa4,  0x00,  0xb5,  0x00,  0xba,  0x00,  0xd0,  0x00,  0xe1,  0x00,  0xe7,  0x00,  0xe2,  0x03,
-  0x08,  0x0f,  0x02,  0x10,  0x04,  0x10,  0x0a,  0x10,  0x0a,  0x13,  0x0c,  0x13,  0x12,  0x13,  0x24,  0x14,
-  0x34,  0x14,  0x04,  0x16,  0x08,  0x16,  0xa4,  0x17,  0x20,  0x1c,  0x34,  0x1c,  0x36,  0x1c,  0x08,  0x44,
-  0x38,  0x44,  0x91,  0x44,  0x0a,  0x45,  0x48,  0x46,  0x01,  0x48,  0x68,  0x54,  0x3a,  0x55,  0x83,  0x55,
-  0xe5,  0x55,  0xb0,  0x57,  0x01,  0x58,  0x83,  0x59,  0x05,  0xe6,  0x0b,  0xf0,  0x0c,  0xf0,  0x04,  0xf8,
-  0x05,  0xf8,  0x07,  0x00,  0x0a,  0x00,  0x1c,  0x00,  0x1e,  0x00,  0x9e,  0x00,  0xa8,  0x00,  0xaa,  0x00,
-  0xb9,  0x00,  0xe0,  0x00,  0x22,  0x01,  0x26,  0x01,  0x79,  0x01,  0x7e,  0x01,  0xc4,  0x01,  0xc6,  0x01,
-  0x80,  0x02,  0x5e,  0x03,  0xee,  0x04,  0x9a,  0x06,  0xf8,  0x07,  0x62,  0x08,  0x68,  0x08,  0x69,  0x08,
-  0xd6,  0x08,  0xe9,  0x09,  0xfa,  0x0b,  0x2e,  0x0f,  0x12,  0x10,  0x1a,  0x10,  0xed,  0x10,  0xf1,  0x10,
-  0x2a,  0x11,  0x06,  0x12,  0x0c,  0x12,  0x3e,  0x12,  0x10,  0x13,  0x16,  0x13,  0x1e,  0x13,  0x46,  0x14,
-  0x76,  0x14,  0x82,  0x14,  0x36,  0x15,  0xca,  0x15,  0x6b,  0x18,  0xbe,  0x18,  0xca,  0x18,  0xe6,  0x19,
-  0x12,  0x1c,  0x46,  0x1c,  0x9c,  0x32,  0x00,  0x40,  0x0e,  0x47,  0xfe,  0x9c,  0xf0,  0x2b,  0x02,  0xfe,
-  0xac,  0x0d,  0xff,  0x10,  0x00,  0x00,  0xd7,  0xfe,  0xe8,  0x19,  0x00,  0xd6,  0xfe,  0x84,  0x01,  0xff,
-  0x03,  0x00,  0x00,  0xfe,  0x93,  0x15,  0xfe,  0x0f,  0x05,  0xff,  0x38,  0x00,  0x00,  0xfe,  0x57,  0x24,
-  0x00,  0xfe,  0x4c,  0x00,  0x5b,  0xff,  0x04,  0x00,  0x00,  0x11,  0xff,  0x09,  0x00,  0x00,  0xff,  0x08,
-  0x01,  0x01,  0xff,  0x08,  0xff,  0xff,  0xff,  0x27,  0x00,  0x00,  0xff,  0x10,  0xff,  0xff,  0xff,  0x11,
-  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,  0xff,  0x21,  0x00,  0x00,  0xfe,  0x04,  0xf7,  0xd6,
-  0x2c,  0x99,  0x0a,  0x01,  0xfe,  0xc2,  0x0f,  0xfe,  0x04,  0xf7,  0xd6,  0x99,  0x0a,  0x42,  0x2c,  0xfe,
-  0x3d,  0xf0,  0xfe,  0x06,  0x02,  0xfe,  0x20,  0xf0,  0xa7,  0xfe,  0x91,  0xf0,  0xfe,  0xf4,  0x01,  0xfe,
-  0x90,  0xf0,  0xfe,  0xf4,  0x01,  0xfe,  0x8f,  0xf0,  0xa7,  0x03,  0x5d,  0x4d,  0x02,  0xfe,  0xc8,  0x0d,
-  0x01,  0xfe,  0x38,  0x0e,  0xfe,  0xdd,  0x12,  0xfe,  0xfc,  0x10,  0xfe,  0x28,  0x1c,  0x03,  0xfe,  0xa6,
-  0x00,  0xfe,  0xd3,  0x12,  0x41,  0x14,  0xfe,  0xa6,  0x00,  0xc2,  0xfe,  0x48,  0xf0,  0xfe,  0x8a,  0x02,
-  0xfe,  0x49,  0xf0,  0xfe,  0xa4,  0x02,  0xfe,  0x4a,  0xf0,  0xfe,  0xc2,  0x02,  0xfe,  0x46,  0xf0,  0xfe,
-  0x54,  0x02,  0xfe,  0x47,  0xf0,  0xfe,  0x5a,  0x02,  0xfe,  0x43,  0xf0,  0xfe,  0x48,  0x02,  0xfe,  0x44,
-  0xf0,  0xfe,  0x4c,  0x02,  0xfe,  0x45,  0xf0,  0xfe,  0x50,  0x02,  0x18,  0x0a,  0xaa,  0x18,  0x06,  0x14,
-  0xa1,  0x02,  0x2b,  0xfe,  0x00,  0x1c,  0xe7,  0xfe,  0x02,  0x1c,  0xe6,  0xfe,  0x1e,  0x1c,  0xfe,  0xe9,
-  0x10,  0x01,  0xfe,  0x18,  0x18,  0xfe,  0xe7,  0x10,  0xfe,  0x06,  0xfc,  0xce,  0x09,  0x70,  0x01,  0xa8,
-  0x02,  0x2b,  0x15,  0x59,  0x39,  0xa2,  0x01,  0xfe,  0x58,  0x10,  0x09,  0x70,  0x01,  0x87,  0xfe,  0xbd,
-  0x10,  0x09,  0x70,  0x01,  0x87,  0xfe,  0xad,  0x10,  0xfe,  0x16,  0x1c,  0xfe,  0x58,  0x1c,  0x18,  0x06,
-  0x14,  0xa1,  0x2c,  0x1c,  0x2b,  0xfe,  0x3d,  0xf0,  0xfe,  0x06,  0x02,  0x23,  0xfe,  0x98,  0x02,  0xfe,
-  0x5a,  0x1c,  0xf8,  0xfe,  0x14,  0x1c,  0x15,  0xfe,  0x30,  0x00,  0x39,  0xa2,  0x01,  0xfe,  0x48,  0x10,
-  0x18,  0x06,  0x14,  0xa1,  0x02,  0xd7,  0x22,  0x20,  0x07,  0x11,  0x35,  0xfe,  0x69,  0x10,  0x18,  0x06,
-  0x14,  0xa1,  0xfe,  0x04,  0xec,  0x20,  0x4f,  0x43,  0x13,  0x20,  0xfe,  0x05,  0xf6,  0xce,  0x01,  0xfe,
-  0x4a,  0x17,  0x08,  0x54,  0x58,  0x37,  0x12,  0x2f,  0x42,  0x92,  0x01,  0xfe,  0x82,  0x16,  0x02,  0x2b,
-  0x09,  0x46,  0x01,  0x0e,  0x07,  0x00,  0x66,  0x01,  0x73,  0xfe,  0x18,  0x10,  0xfe,  0x41,  0x58,  0x09,
-  0xa4,  0x01,  0x0e,  0xfe,  0xc8,  0x54,  0x6b,  0xfe,  0x10,  0x03,  0x01,  0xfe,  0x82,  0x16,  0x02,  0x2b,
-  0x2c,  0x4f,  0xfe,  0x02,  0xe8,  0x2a,  0xfe,  0xbf,  0x57,  0xfe,  0x9e,  0x43,  0xfe,  0x77,  0x57,  0xfe,
-  0x27,  0xf0,  0xfe,  0xe0,  0x01,  0xfe,  0x07,  0x4b,  0xfe,  0x20,  0xf0,  0xa7,  0xfe,  0x40,  0x1c,  0x1c,
-  0xd9,  0xfe,  0x26,  0xf0,  0xfe,  0x5a,  0x03,  0xfe,  0xa0,  0xf0,  0xfe,  0x48,  0x03,  0xfe,  0x11,  0xf0,
-  0xa7,  0xfe,  0xef,  0x10,  0xfe,  0x9f,  0xf0,  0xfe,  0x68,  0x03,  0xf9,  0x10,  0xfe,  0x11,  0x00,  0x02,
-  0x65,  0x2c,  0xfe,  0x48,  0x1c,  0xf9,  0x08,  0x05,  0x1b,  0xfe,  0x18,  0x13,  0x21,  0x22,  0xa3,  0xb7,
-  0x13,  0xa3,  0x09,  0x46,  0x01,  0x0e,  0xb7,  0x78,  0x01,  0xfe,  0xb4,  0x16,  0x12,  0xd1,  0x1c,  0xd9,
-  0xfe,  0x01,  0xf0,  0xd9,  0xfe,  0x82,  0xf0,  0xfe,  0x96,  0x03,  0xfa,  0x12,  0xfe,  0xe4,  0x00,  0x27,
-  0xfe,  0xa8,  0x03,  0x1c,  0x34,  0x1d,  0xfe,  0xb8,  0x03,  0x01,  0x4b,  0xfe,  0x06,  0xf0,  0xfe,  0xc8,
-  0x03,  0x95,  0x86,  0xfe,  0x0a,  0xf0,  0xfe,  0x8a,  0x06,  0x02,  0x24,  0x03,  0x70,  0x28,  0x17,  0xfe,
-  0xfa,  0x04,  0x15,  0x6d,  0x01,  0x36,  0x7b,  0xfe,  0x6a,  0x02,  0x02,  0xd8,  0xf9,  0x2c,  0x99,  0x19,
-  0xfe,  0x67,  0x1b,  0xfe,  0xbf,  0x57,  0xfe,  0x77,  0x57,  0xfe,  0x48,  0x1c,  0x74,  0x01,  0xaf,  0x8c,
-  0x09,  0x46,  0x01,  0x0e,  0x07,  0x00,  0x17,  0xda,  0x09,  0xd1,  0x01,  0x0e,  0x8d,  0x51,  0x64,  0x79,
-  0x2a,  0x03,  0x70,  0x28,  0xfe,  0x10,  0x12,  0x15,  0x6d,  0x01,  0x36,  0x7b,  0xfe,  0x6a,  0x02,  0x02,
-  0xd8,  0xc7,  0x81,  0xc8,  0x83,  0x1c,  0x24,  0x27,  0xfe,  0x40,  0x04,  0x1d,  0xfe,  0x3c,  0x04,  0x3b,
-  0xfe,  0xa0,  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x4e,  0x12,  0x2d,  0xff,  0x02,  0x00,  0x10,  0x01,  0x0b,
-  0x1d,  0xfe,  0xe4,  0x04,  0x2d,  0x01,  0x0b,  0x1d,  0x24,  0x33,  0x31,  0xde,  0xfe,  0x4c,  0x44,  0xfe,
-  0x4c,  0x12,  0x51,  0xfe,  0x44,  0x48,  0x0f,  0x6f,  0xfe,  0x4c,  0x54,  0x6b,  0xda,  0x4f,  0x79,  0x2a,
-  0xfe,  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x62,  0x13,  0x08,  0x05,  0x1b,  0xfe,  0x2a,  0x13,  0x32,
-  0x07,  0x82,  0xfe,  0x52,  0x13,  0xfe,  0x20,  0x10,  0x0f,  0x6f,  0xfe,  0x4c,  0x54,  0x6b,  0xda,  0xfe,
-  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x40,  0x13,  0x08,  0x05,  0x1b,  0xfe,  0x08,  0x13,  0x32,  0x07,
-  0x82,  0xfe,  0x30,  0x13,  0x08,  0x05,  0x1b,  0xfe,  0x1c,  0x12,  0x15,  0x9d,  0x08,  0x05,  0x06,  0x4d,
-  0x15,  0xfe,  0x0d,  0x00,  0x01,  0x36,  0x7b,  0xfe,  0x64,  0x0d,  0x02,  0x24,  0x2d,  0x12,  0xfe,  0xe6,
-  0x00,  0xfe,  0x1c,  0x90,  0xfe,  0x40,  0x5c,  0x04,  0x15,  0x9d,  0x01,  0x36,  0x02,  0x2b,  0xfe,  0x42,
-  0x5b,  0x99,  0x19,  0xfe,  0x46,  0x59,  0xfe,  0xbf,  0x57,  0xfe,  0x77,  0x57,  0xfe,  0x87,  0x80,  0xfe,
-  0x31,  0xe4,  0x5b,  0x08,  0x05,  0x0a,  0xfe,  0x84,  0x13,  0xfe,  0x20,  0x80,  0x07,  0x19,  0xfe,  0x7c,
-  0x12,  0x53,  0x05,  0x06,  0xfe,  0x6c,  0x13,  0x03,  0xfe,  0xa2,  0x00,  0x28,  0x17,  0xfe,  0x90,  0x05,
-  0xfe,  0x31,  0xe4,  0x5a,  0x53,  0x05,  0x0a,  0xfe,  0x56,  0x13,  0x03,  0xfe,  0xa0,  0x00,  0x28,  0xfe,
-  0x4e,  0x12,  0x67,  0xff,  0x02,  0x00,  0x10,  0x27,  0xfe,  0x48,  0x05,  0x1c,  0x34,  0xfe,  0x89,  0x48,
-  0xff,  0x02,  0x00,  0x10,  0x27,  0xfe,  0x56,  0x05,  0x26,  0xfe,  0xa8,  0x05,  0x12,  0xfe,  0xe3,  0x00,
-  0x21,  0x53,  0xfe,  0x4a,  0xf0,  0xfe,  0x76,  0x05,  0xfe,  0x49,  0xf0,  0xfe,  0x70,  0x05,  0x88,  0x25,
-  0xfe,  0x21,  0x00,  0xab,  0x25,  0xfe,  0x22,  0x00,  0xaa,  0x25,  0x58,  0xfe,  0x09,  0x48,  0xff,  0x02,
-  0x00,  0x10,  0x27,  0xfe,  0x86,  0x05,  0x26,  0xfe,  0xa8,  0x05,  0xfe,  0xe2,  0x08,  0x53,  0x05,  0xcb,
-  0x4d,  0x01,  0xb0,  0x25,  0x06,  0x13,  0xd3,  0x39,  0xfe,  0x27,  0x01,  0x08,  0x05,  0x1b,  0xfe,  0x22,
-  0x12,  0x41,  0x01,  0xb2,  0x15,  0x9d,  0x08,  0x05,  0x06,  0x4d,  0x15,  0xfe,  0x0d,  0x00,  0x01,  0x36,
-  0x7b,  0xfe,  0x64,  0x0d,  0x02,  0x24,  0x03,  0xfe,  0x9c,  0x00,  0x28,  0xeb,  0x03,  0x5c,  0x28,  0xfe,
-  0x36,  0x13,  0x41,  0x01,  0xb2,  0x26,  0xfe,  0x18,  0x06,  0x09,  0x06,  0x53,  0x05,  0x1f,  0xfe,  0x02,
-  0x12,  0x50,  0x01,  0xfe,  0x9e,  0x15,  0x1d,  0xfe,  0x0e,  0x06,  0x12,  0xa5,  0x01,  0x4b,  0x12,  0xfe,
-  0xe5,  0x00,  0x03,  0x5c,  0xc1,  0x0c,  0x5c,  0x03,  0xcd,  0x28,  0xfe,  0x62,  0x12,  0x03,  0x45,  0x28,
-  0xfe,  0x5a,  0x13,  0x01,  0xfe,  0x0c,  0x19,  0x01,  0xfe,  0x76,  0x19,  0xfe,  0x43,  0x48,  0xc4,  0xcc,
-  0x0f,  0x71,  0xff,  0x02,  0x00,  0x57,  0x52,  0x93,  0x1e,  0x43,  0x8b,  0xc4,  0x6e,  0x41,  0x01,  0xb2,
-  0x26,  0xfe,  0x82,  0x06,  0x53,  0x05,  0x1a,  0xe9,  0x91,  0x09,  0x59,  0x01,  0xfe,  0xcc,  0x15,  0x1d,
-  0xfe,  0x78,  0x06,  0x12,  0xa5,  0x01,  0x4b,  0x12,  0xfe,  0xe5,  0x00,  0x03,  0x45,  0xc1,  0x0c,  0x45,
-  0x18,  0x06,  0x01,  0xb2,  0xfa,  0x76,  0x74,  0x01,  0xaf,  0x8c,  0x12,  0xfe,  0xe2,  0x00,  0x27,  0xdb,
-  0x1c,  0x34,  0xfe,  0x0a,  0xf0,  0xfe,  0xb6,  0x06,  0x94,  0xfe,  0x6c,  0x07,  0xfe,  0x06,  0xf0,  0xfe,
-  0x74,  0x07,  0x95,  0x86,  0x02,  0x24,  0x08,  0x05,  0x0a,  0xfe,  0x2e,  0x12,  0x16,  0x19,  0x01,  0x0b,
-  0x16,  0x00,  0x01,  0x0b,  0x16,  0x00,  0x01,  0x0b,  0x16,  0x00,  0x01,  0x0b,  0xfe,  0x99,  0xa4,  0x01,
-  0x0b,  0x16,  0x00,  0x02,  0xfe,  0x42,  0x08,  0x68,  0x05,  0x1a,  0xfe,  0x38,  0x12,  0x08,  0x05,  0x1a,
-  0xfe,  0x30,  0x13,  0x16,  0xfe,  0x1b,  0x00,  0x01,  0x0b,  0x16,  0x00,  0x01,  0x0b,  0x16,  0x00,  0x01,
-  0x0b,  0x16,  0x00,  0x01,  0x0b,  0x16,  0x06,  0x01,  0x0b,  0x16,  0x00,  0x02,  0xe2,  0x6c,  0x58,  0xbe,
-  0x50,  0xfe,  0x9a,  0x81,  0x55,  0x1b,  0x7a,  0xfe,  0x42,  0x07,  0x09,  0x1b,  0xfe,  0x09,  0x6f,  0xba,
-  0xfe,  0xca,  0x45,  0xfe,  0x32,  0x12,  0x69,  0x6d,  0x8b,  0x6c,  0x7f,  0x27,  0xfe,  0x54,  0x07,  0x1c,
-  0x34,  0xfe,  0x0a,  0xf0,  0xfe,  0x42,  0x07,  0x95,  0x86,  0x94,  0xfe,  0x6c,  0x07,  0x02,  0x24,  0x01,
-  0x4b,  0x02,  0xdb,  0x16,  0x1f,  0x02,  0xdb,  0xfe,  0x9c,  0xf7,  0xdc,  0xfe,  0x2c,  0x90,  0xfe,  0xae,
-  0x90,  0x56,  0xfe,  0xda,  0x07,  0x0c,  0x60,  0x14,  0x61,  0x08,  0x54,  0x5a,  0x37,  0x22,  0x20,  0x07,
-  0x11,  0xfe,  0x0e,  0x12,  0x8d,  0xfe,  0x80,  0x80,  0x39,  0x20,  0x6a,  0x2a,  0xfe,  0x06,  0x10,  0xfe,
-  0x83,  0xe7,  0xfe,  0x48,  0x00,  0xab,  0xfe,  0x03,  0x40,  0x08,  0x54,  0x5b,  0x37,  0x01,  0xb3,  0xb8,
-  0xfe,  0x1f,  0x40,  0x13,  0x62,  0x01,  0xef,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0xfe,  0x44,  0x51,
-  0xfe,  0xc6,  0x51,  0x88,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,  0x0c,  0x5e,  0x14,  0x5f,  0xfe,  0x0c,
-  0x90,  0xfe,  0x8e,  0x90,  0xfe,  0x40,  0x50,  0xfe,  0xc2,  0x50,  0x0c,  0x3d,  0x14,  0x3e,  0xfe,  0x4a,
-  0x10,  0x08,  0x05,  0x5a,  0xfe,  0x2a,  0x12,  0xfe,  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x0c,  0x60,  0x14,
-  0x61,  0x08,  0x05,  0x5b,  0x8b,  0x01,  0xb3,  0xfe,  0x1f,  0x80,  0x13,  0x62,  0xfe,  0x44,  0x90,  0xfe,
-  0xc6,  0x90,  0x0c,  0x3f,  0x14,  0x40,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,  0x0c,  0x5e,  0x14,  0x5f,
-  0xfe,  0x40,  0x90,  0xfe,  0xc2,  0x90,  0x0c,  0x3d,  0x14,  0x3e,  0x0c,  0x2e,  0x14,  0x3c,  0x21,  0x0c,
-  0x49,  0x0c,  0x63,  0x08,  0x54,  0x1f,  0x37,  0x2c,  0x0f,  0xfe,  0x4e,  0x11,  0x27,  0xdd,  0xfe,  0x9e,
-  0xf0,  0xfe,  0x76,  0x08,  0xbc,  0x17,  0x34,  0x2c,  0x77,  0xe6,  0xc5,  0xfe,  0x9a,  0x08,  0xc6,  0xfe,
-  0xb8,  0x08,  0x94,  0xfe,  0x8e,  0x08,  0xfe,  0x06,  0xf0,  0xfe,  0x94,  0x08,  0x95,  0x86,  0x02,  0x24,
-  0x01,  0x4b,  0xfe,  0xc9,  0x10,  0x16,  0x1f,  0xfe,  0xc9,  0x10,  0x68,  0x05,  0x06,  0xfe,  0x10,  0x12,
-  0x68,  0x05,  0x0a,  0x4e,  0x08,  0x05,  0x0a,  0xfe,  0x90,  0x12,  0xfe,  0x2e,  0x1c,  0x02,  0xfe,  0x18,
-  0x0b,  0x68,  0x05,  0x06,  0x4e,  0x68,  0x05,  0x0a,  0xfe,  0x7a,  0x12,  0xfe,  0x2c,  0x1c,  0xfe,  0xaa,
-  0xf0,  0xfe,  0xd2,  0x09,  0xfe,  0xac,  0xf0,  0xfe,  0x00,  0x09,  0x02,  0xfe,  0xde,  0x09,  0xfe,  0xb7,
-  0xf0,  0xfe,  0xfc,  0x08,  0xfe,  0x02,  0xf6,  0x1a,  0x50,  0xfe,  0x70,  0x18,  0xfe,  0xf1,  0x18,  0xfe,
-  0x40,  0x55,  0xfe,  0xe1,  0x55,  0xfe,  0x10,  0x58,  0xfe,  0x91,  0x58,  0xfe,  0x14,  0x59,  0xfe,  0x95,
-  0x59,  0x1c,  0x85,  0xfe,  0x8c,  0xf0,  0xfe,  0xfc,  0x08,  0xfe,  0xac,  0xf0,  0xfe,  0xf0,  0x08,  0xb5,
-  0xfe,  0xcb,  0x10,  0xfe,  0xad,  0xf0,  0xfe,  0x0c,  0x09,  0x02,  0xfe,  0x18,  0x0b,  0xb6,  0xfe,  0xbf,
-  0x10,  0xfe,  0x2b,  0xf0,  0x85,  0xf4,  0x1e,  0xfe,  0x00,  0xfe,  0xfe,  0x1c,  0x12,  0xc2,  0xfe,  0xd2,
-  0xf0,  0x85,  0xfe,  0x76,  0x18,  0x1e,  0x19,  0x17,  0x85,  0x03,  0xd2,  0x1e,  0x06,  0x17,  0x85,  0xc5,
-  0x4a,  0xc6,  0x4a,  0xb5,  0xb6,  0xfe,  0x89,  0x10,  0x74,  0x67,  0x2d,  0x15,  0x9d,  0x01,  0x36,  0x10,
-  0xfe,  0x35,  0x00,  0xfe,  0x01,  0xf0,  0x65,  0x10,  0x80,  0x02,  0x65,  0xfe,  0x98,  0x80,  0xfe,  0x19,
-  0xe4,  0x0a,  0xfe,  0x1a,  0x12,  0x51,  0xfe,  0x19,  0x82,  0xfe,  0x6c,  0x18,  0xfe,  0x44,  0x54,  0xbe,
-  0xfe,  0x19,  0x81,  0xfe,  0x74,  0x18,  0x8f,  0x90,  0x17,  0xfe,  0xce,  0x08,  0x02,  0x4a,  0x08,  0x05,
-  0x5a,  0xec,  0x03,  0x2e,  0x29,  0x3c,  0x0c,  0x3f,  0x14,  0x40,  0x9b,  0x2e,  0x9c,  0x3c,  0xfe,  0x6c,
-  0x18,  0xfe,  0xed,  0x18,  0xfe,  0x44,  0x54,  0xfe,  0xe5,  0x54,  0x3a,  0x3f,  0x3b,  0x40,  0x03,  0x49,
-  0x29,  0x63,  0x8f,  0xfe,  0xe3,  0x54,  0xfe,  0x74,  0x18,  0xfe,  0xf5,  0x18,  0x8f,  0xfe,  0xe3,  0x54,
-  0x90,  0xc0,  0x56,  0xfe,  0xce,  0x08,  0x02,  0x4a,  0xfe,  0x37,  0xf0,  0xfe,  0xda,  0x09,  0xfe,  0x8b,
-  0xf0,  0xfe,  0x60,  0x09,  0x02,  0x4a,  0x08,  0x05,  0x0a,  0x23,  0xfe,  0xfa,  0x0a,  0x3a,  0x49,  0x3b,
-  0x63,  0x56,  0xfe,  0x3e,  0x0a,  0x0f,  0xfe,  0xc0,  0x07,  0x41,  0x98,  0x00,  0xad,  0xfe,  0x01,  0x59,
-  0xfe,  0x52,  0xf0,  0xfe,  0x0c,  0x0a,  0x8f,  0x7a,  0xfe,  0x24,  0x0a,  0x3a,  0x49,  0x8f,  0xfe,  0xe3,
-  0x54,  0x57,  0x49,  0x7d,  0x63,  0xfe,  0x14,  0x58,  0xfe,  0x95,  0x58,  0x02,  0x4a,  0x3a,  0x49,  0x3b,
-  0x63,  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0xbe,  0x57,  0x49,  0x57,  0x63,  0x02,  0x4a,  0x08,  0x05,
-  0x5a,  0xfe,  0x82,  0x12,  0x08,  0x05,  0x1f,  0xfe,  0x66,  0x13,  0x22,  0x62,  0xb7,  0xfe,  0x03,  0xa1,
-  0xfe,  0x83,  0x80,  0xfe,  0xc8,  0x44,  0xfe,  0x2e,  0x13,  0xfe,  0x04,  0x91,  0xfe,  0x86,  0x91,  0x6a,
-  0x2a,  0xfe,  0x40,  0x59,  0xfe,  0xc1,  0x59,  0x56,  0xe0,  0x03,  0x60,  0x29,  0x61,  0x0c,  0x7f,  0x14,
-  0x80,  0x57,  0x60,  0x7d,  0x61,  0x01,  0xb3,  0xb8,  0x6a,  0x2a,  0x13,  0x62,  0x9b,  0x2e,  0x9c,  0x3c,
-  0x3a,  0x3f,  0x3b,  0x40,  0x90,  0xc0,  0xfe,  0x04,  0xfa,  0x2e,  0xfe,  0x05,  0xfa,  0x3c,  0x01,  0xef,
-  0xfe,  0x36,  0x10,  0x21,  0x0c,  0x7f,  0x0c,  0x80,  0x3a,  0x3f,  0x3b,  0x40,  0xe4,  0x08,  0x05,  0x1f,
-  0x17,  0xe0,  0x3a,  0x3d,  0x3b,  0x3e,  0x08,  0x05,  0xfe,  0xf7,  0x00,  0x37,  0x03,  0x5e,  0x29,  0x5f,
-  0xfe,  0x10,  0x58,  0xfe,  0x91,  0x58,  0x57,  0x49,  0x7d,  0x63,  0x02,  0xfe,  0xf4,  0x09,  0x08,  0x05,
-  0x1f,  0x17,  0xe0,  0x08,  0x05,  0xfe,  0xf7,  0x00,  0x37,  0xbe,  0xfe,  0x19,  0x81,  0x50,  0xfe,  0x10,
-  0x90,  0xfe,  0x92,  0x90,  0xfe,  0xd3,  0x10,  0x32,  0x07,  0xa6,  0x17,  0xfe,  0x08,  0x09,  0x12,  0xa6,
-  0x08,  0x05,  0x0a,  0xfe,  0x14,  0x13,  0x03,  0x3d,  0x29,  0x3e,  0x56,  0xfe,  0x08,  0x09,  0xfe,  0x0c,
-  0x58,  0xfe,  0x8d,  0x58,  0x02,  0x4a,  0x21,  0x41,  0xfe,  0x19,  0x80,  0xe7,  0x08,  0x05,  0x0a,  0xfe,
-  0x1a,  0x12,  0xfe,  0x6c,  0x19,  0xfe,  0x19,  0x41,  0xf4,  0xc2,  0xfe,  0xd1,  0xf0,  0xe2,  0x15,  0x7e,
-  0x01,  0x36,  0x10,  0xfe,  0x44,  0x00,  0xfe,  0x8e,  0x10,  0xfe,  0x6c,  0x19,  0x57,  0x3d,  0xfe,  0xed,
-  0x19,  0x7d,  0x3e,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0xf4,  0x1e,  0xfe,  0x00,  0xff,  0x35,  0xfe,
-  0x74,  0x10,  0xc2,  0xfe,  0xd2,  0xf0,  0xfe,  0xa6,  0x0b,  0xfe,  0x76,  0x18,  0x1e,  0x19,  0x8a,  0x03,
-  0xd2,  0x1e,  0x06,  0xfe,  0x08,  0x13,  0x10,  0xfe,  0x16,  0x00,  0x02,  0x65,  0xfe,  0xd1,  0xf0,  0xfe,
-  0xb8,  0x0b,  0x15,  0x7e,  0x01,  0x36,  0x10,  0xfe,  0x17,  0x00,  0xfe,  0x42,  0x10,  0xfe,  0xce,  0xf0,
-  0xfe,  0xbe,  0x0b,  0xfe,  0x3c,  0x10,  0xfe,  0xcd,  0xf0,  0xfe,  0xca,  0x0b,  0x10,  0xfe,  0x22,  0x00,
-  0x02,  0x65,  0xfe,  0xcb,  0xf0,  0xfe,  0xd6,  0x0b,  0x10,  0xfe,  0x24,  0x00,  0x02,  0x65,  0xfe,  0xd0,
-  0xf0,  0xfe,  0xe0,  0x0b,  0x10,  0x9e,  0xe5,  0xfe,  0xcf,  0xf0,  0xfe,  0xea,  0x0b,  0x10,  0x58,  0xfe,
-  0x10,  0x10,  0xfe,  0xcc,  0xf0,  0xe2,  0x68,  0x05,  0x1f,  0x4d,  0x10,  0xfe,  0x12,  0x00,  0x2c,  0x0f,
-  0xfe,  0x4e,  0x11,  0x27,  0xfe,  0x00,  0x0c,  0xfe,  0x9e,  0xf0,  0xfe,  0x14,  0x0c,  0xbc,  0x17,  0x34,
-  0x2c,  0x77,  0xe6,  0xc5,  0x24,  0xc6,  0x24,  0x2c,  0xfa,  0x27,  0xfe,  0x20,  0x0c,  0x1c,  0x34,  0x94,
-  0xfe,  0x3c,  0x0c,  0x95,  0x86,  0xc5,  0xdc,  0xc6,  0xdc,  0x02,  0x24,  0x01,  0x4b,  0xfe,  0xdb,  0x10,
-  0x12,  0xfe,  0xe8,  0x00,  0xb5,  0xb6,  0x74,  0xc7,  0x81,  0xc8,  0x83,  0xfe,  0x89,  0xf0,  0x24,  0x33,
-  0x31,  0xe1,  0xc7,  0x81,  0xc8,  0x83,  0x27,  0xfe,  0x66,  0x0c,  0x1d,  0x24,  0x33,  0x31,  0xdf,  0xbc,
-  0x4e,  0x10,  0xfe,  0x42,  0x00,  0x02,  0x65,  0x7c,  0x06,  0xfe,  0x81,  0x49,  0x17,  0xfe,  0x2c,  0x0d,
-  0x08,  0x05,  0x0a,  0xfe,  0x44,  0x13,  0x10,  0x00,  0x55,  0x0a,  0xfe,  0x54,  0x12,  0x55,  0xfe,  0x28,
-  0x00,  0x23,  0xfe,  0x9a,  0x0d,  0x09,  0x46,  0x01,  0x0e,  0x07,  0x00,  0x66,  0x44,  0xfe,  0x28,  0x00,
-  0xfe,  0xe2,  0x10,  0x01,  0xf5,  0x01,  0xf6,  0x09,  0xa4,  0x01,  0xfe,  0x26,  0x0f,  0x64,  0x12,  0x2f,
-  0x01,  0x73,  0x02,  0x2b,  0x10,  0xfe,  0x44,  0x00,  0x55,  0x0a,  0xe9,  0x44,  0x0a,  0xfe,  0xb4,  0x10,
-  0x01,  0xb0,  0x44,  0x0a,  0xfe,  0xaa,  0x10,  0x01,  0xb0,  0xfe,  0x19,  0x82,  0xfe,  0x34,  0x46,  0xac,
-  0x44,  0x0a,  0x10,  0xfe,  0x43,  0x00,  0xfe,  0x96,  0x10,  0x08,  0x54,  0x0a,  0x37,  0x01,  0xf5,  0x01,
-  0xf6,  0x64,  0x12,  0x2f,  0x01,  0x73,  0x99,  0x0a,  0x64,  0x42,  0x92,  0x02,  0xfe,  0x2e,  0x03,  0x08,
-  0x05,  0x0a,  0x8a,  0x44,  0x0a,  0x10,  0x00,  0xfe,  0x5c,  0x10,  0x68,  0x05,  0x1a,  0xfe,  0x58,  0x12,
-  0x08,  0x05,  0x1a,  0xfe,  0x50,  0x13,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x50,  0x0d,  0xfe,
-  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x56,  0x0d,  0x08,  0x54,  0x1a,  0x37,  0xfe,  0xa9,  0x10,  0x10,
-  0xfe,  0x15,  0x00,  0xfe,  0x04,  0xe6,  0x0a,  0x50,  0xfe,  0x2e,  0x10,  0x10,  0xfe,  0x13,  0x00,  0xfe,
-  0x10,  0x10,  0x10,  0x6f,  0xab,  0x10,  0xfe,  0x41,  0x00,  0xaa,  0x10,  0xfe,  0x24,  0x00,  0x8c,  0xb5,
-  0xb6,  0x74,  0x03,  0x70,  0x28,  0x23,  0xd8,  0x50,  0xfe,  0x04,  0xe6,  0x1a,  0xfe,  0x9d,  0x41,  0xfe,
-  0x1c,  0x42,  0x64,  0x01,  0xe3,  0x02,  0x2b,  0xf8,  0x15,  0x0a,  0x39,  0xa0,  0xb4,  0x15,  0xfe,  0x31,
-  0x00,  0x39,  0xa2,  0x01,  0xfe,  0x48,  0x10,  0x02,  0xd7,  0x42,  0xfe,  0x06,  0xec,  0xd0,  0xfc,  0x44,
-  0x1b,  0xfe,  0xce,  0x45,  0x35,  0x42,  0xfe,  0x06,  0xea,  0xd0,  0xfe,  0x47,  0x4b,  0x91,  0xfe,  0x75,
-  0x57,  0x03,  0x5d,  0xfe,  0x98,  0x56,  0xfe,  0x38,  0x12,  0x09,  0x48,  0x01,  0x0e,  0xfe,  0x44,  0x48,
-  0x4f,  0x08,  0x05,  0x1b,  0xfe,  0x1a,  0x13,  0x09,  0x46,  0x01,  0x0e,  0x41,  0xfe,  0x41,  0x58,  0x09,
-  0xa4,  0x01,  0x0e,  0xfe,  0x49,  0x54,  0x96,  0xfe,  0x1e,  0x0e,  0x02,  0xfe,  0x2e,  0x03,  0x09,  0x5d,
-  0xfe,  0xee,  0x14,  0xfc,  0x44,  0x1b,  0xfe,  0xce,  0x45,  0x35,  0x42,  0xfe,  0xce,  0x47,  0xfe,  0xad,
-  0x13,  0x02,  0x2b,  0x22,  0x20,  0x07,  0x11,  0xfe,  0x9e,  0x12,  0x21,  0x13,  0x59,  0x13,  0x9f,  0x13,
-  0xd5,  0x22,  0x2f,  0x41,  0x39,  0x2f,  0xbc,  0xad,  0xfe,  0xbc,  0xf0,  0xfe,  0xe0,  0x0e,  0x0f,  0x06,
-  0x13,  0x59,  0x01,  0xfe,  0xda,  0x16,  0x03,  0xfe,  0x38,  0x01,  0x29,  0xfe,  0x3a,  0x01,  0x56,  0xfe,
-  0xe4,  0x0e,  0xfe,  0x02,  0xec,  0xd5,  0x69,  0x00,  0x66,  0xfe,  0x04,  0xec,  0x20,  0x4f,  0xfe,  0x05,
-  0xf6,  0xfe,  0x34,  0x01,  0x01,  0xfe,  0x4a,  0x17,  0xfe,  0x08,  0x90,  0xfe,  0x48,  0xf4,  0x0d,  0xfe,
-  0x18,  0x13,  0xba,  0xfe,  0x02,  0xea,  0xd5,  0x69,  0x7e,  0xfe,  0xc5,  0x13,  0x15,  0x1a,  0x39,  0xa0,
-  0xb4,  0xfe,  0x2e,  0x10,  0x03,  0xfe,  0x38,  0x01,  0x1e,  0xfe,  0xf0,  0xff,  0x0c,  0xfe,  0x60,  0x01,
-  0x03,  0xfe,  0x3a,  0x01,  0x0c,  0xfe,  0x62,  0x01,  0x43,  0x13,  0x20,  0x25,  0x06,  0x13,  0x2f,  0x12,
-  0x2f,  0x92,  0x0f,  0x06,  0x04,  0x21,  0x04,  0x22,  0x59,  0xfe,  0xf7,  0x12,  0x22,  0x9f,  0xb7,  0x13,
-  0x9f,  0x07,  0x7e,  0xfe,  0x71,  0x13,  0xfe,  0x24,  0x1c,  0x15,  0x19,  0x39,  0xa0,  0xb4,  0xfe,  0xd9,
-  0x10,  0xc3,  0xfe,  0x03,  0xdc,  0xfe,  0x73,  0x57,  0xfe,  0x80,  0x5d,  0x04,  0xc3,  0xfe,  0x03,  0xdc,
-  0xfe,  0x5b,  0x57,  0xfe,  0x80,  0x5d,  0x04,  0xfe,  0x03,  0x57,  0xc3,  0x21,  0xfe,  0x00,  0xcc,  0x04,
-  0xfe,  0x03,  0x57,  0xc3,  0x78,  0x04,  0x08,  0x05,  0x58,  0xfe,  0x22,  0x13,  0xfe,  0x1c,  0x80,  0x07,
-  0x06,  0xfe,  0x1a,  0x13,  0xfe,  0x1e,  0x80,  0xed,  0xfe,  0x1d,  0x80,  0xae,  0xfe,  0x0c,  0x90,  0xfe,
-  0x0e,  0x13,  0xfe,  0x0e,  0x90,  0xac,  0xfe,  0x3c,  0x90,  0xfe,  0x30,  0xf4,  0x0a,  0xfe,  0x3c,  0x50,
-  0xaa,  0x01,  0xfe,  0x7a,  0x17,  0x32,  0x07,  0x2f,  0xad,  0x01,  0xfe,  0xb4,  0x16,  0x08,  0x05,  0x1b,
-  0x4e,  0x01,  0xf5,  0x01,  0xf6,  0x12,  0xfe,  0xe9,  0x00,  0x08,  0x05,  0x58,  0xfe,  0x2c,  0x13,  0x01,
-  0xfe,  0x0c,  0x17,  0xfe,  0x1e,  0x1c,  0xfe,  0x14,  0x90,  0xfe,  0x96,  0x90,  0x0c,  0xfe,  0x64,  0x01,
-  0x14,  0xfe,  0x66,  0x01,  0x08,  0x05,  0x5b,  0xfe,  0x12,  0x12,  0xfe,  0x03,  0x80,  0x8d,  0xfe,  0x01,
-  0xec,  0x20,  0xfe,  0x80,  0x40,  0x13,  0x20,  0x6a,  0x2a,  0x12,  0xcf,  0x64,  0x22,  0x20,  0xfb,  0x79,
-  0x20,  0x04,  0xfe,  0x08,  0x1c,  0x03,  0xfe,  0xac,  0x00,  0xfe,  0x06,  0x58,  0x03,  0xfe,  0xae,  0x00,
+static unsigned char _adv_asc38C0800_buf[] = {
+	0x00, 0x00, 0x00, 0xf2, 0x00, 0xf0, 0x00, 0xfc, 0x00, 0x16, 0x18, 0xe4,
+	0x01, 0x00, 0x48, 0xe4,
+	0x18, 0x80, 0x03, 0xf6, 0x02, 0x00, 0xce, 0x19, 0x00, 0xfa, 0xff, 0xff,
+	0x1c, 0x0f, 0x00, 0xf6,
+	0x9e, 0xe7, 0xff, 0x00, 0x82, 0xe7, 0x00, 0xea, 0x01, 0xfa, 0x01, 0xe6,
+	0x09, 0xe7, 0x55, 0xf0,
+	0x01, 0xf6, 0x03, 0x00, 0x04, 0x00, 0x10, 0x00, 0x1e, 0xf0, 0x85, 0xf0,
+	0x18, 0xf4, 0x08, 0x00,
+	0xbc, 0x00, 0x38, 0x54, 0x00, 0xec, 0xd5, 0xf0, 0x82, 0x0d, 0x00, 0xe6,
+	0x86, 0xf0, 0xb1, 0xf0,
+	0x98, 0x57, 0x01, 0xfc, 0xb4, 0x00, 0xd4, 0x01, 0x0c, 0x1c, 0x3e, 0x1c,
+	0x3c, 0x00, 0xbb, 0x00,
+	0x00, 0x10, 0xba, 0x19, 0x02, 0x80, 0x32, 0xf0, 0x7c, 0x0d, 0x02, 0x13,
+	0xba, 0x13, 0x18, 0x40,
+	0x00, 0x57, 0x01, 0xea, 0x02, 0xfc, 0x03, 0xfc, 0x3e, 0x00, 0x6c, 0x01,
+	0x6e, 0x01, 0x74, 0x01,
+	0x76, 0x01, 0xb9, 0x54, 0x3e, 0x57, 0x00, 0x80, 0x03, 0xe6, 0xb6, 0x00,
+	0xc0, 0x00, 0x01, 0x01,
+	0x3e, 0x01, 0x7a, 0x01, 0xca, 0x08, 0xce, 0x10, 0x16, 0x11, 0x04, 0x12,
+	0x08, 0x12, 0x02, 0x4a,
+	0xbb, 0x55, 0x3c, 0x56, 0x03, 0x58, 0x1b, 0x80, 0x30, 0xe4, 0x4b, 0xe4,
+	0x5d, 0xf0, 0x02, 0xfa,
+	0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x80, 0x00, 0x24, 0x01, 0x3c, 0x01,
+	0x68, 0x01, 0x6a, 0x01,
+	0x70, 0x01, 0x72, 0x01, 0x78, 0x01, 0x7c, 0x01, 0x62, 0x0a, 0x86, 0x0d,
+	0x06, 0x13, 0x4c, 0x1c,
+	0x04, 0x80, 0x4a, 0xe4, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x0c, 0x00,
+	0x0f, 0x00, 0x47, 0x00,
+	0xbe, 0x00, 0x00, 0x01, 0x20, 0x11, 0x5c, 0x16, 0x32, 0x1c, 0x38, 0x1c,
+	0x4e, 0x1c, 0x10, 0x44,
+	0x00, 0x4c, 0x04, 0xea, 0x5c, 0xf0, 0xa7, 0xf0, 0x04, 0xf6, 0x03, 0xfa,
+	0x05, 0x00, 0x34, 0x00,
+	0x36, 0x00, 0x98, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01, 0x4a, 0x0b,
+	0x42, 0x0c, 0x12, 0x0f,
+	0x0c, 0x10, 0x22, 0x11, 0x0a, 0x12, 0x04, 0x13, 0x30, 0x1c, 0x02, 0x48,
+	0x00, 0x4e, 0x42, 0x54,
+	0x44, 0x55, 0xbd, 0x56, 0x06, 0x83, 0x00, 0xdc, 0x05, 0xf0, 0x09, 0xf0,
+	0x59, 0xf0, 0xb8, 0xf0,
+	0x4b, 0xf4, 0x06, 0xf7, 0x0e, 0xf7, 0x04, 0xfc, 0x05, 0xfc, 0x06, 0x00,
+	0x19, 0x00, 0x33, 0x00,
+	0x9b, 0x00, 0xa4, 0x00, 0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe1, 0x00,
+	0xe7, 0x00, 0xe2, 0x03,
+	0x08, 0x0f, 0x02, 0x10, 0x04, 0x10, 0x0a, 0x10, 0x0a, 0x13, 0x0c, 0x13,
+	0x12, 0x13, 0x24, 0x14,
+	0x34, 0x14, 0x04, 0x16, 0x08, 0x16, 0xa4, 0x17, 0x20, 0x1c, 0x34, 0x1c,
+	0x36, 0x1c, 0x08, 0x44,
+	0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x01, 0x48, 0x68, 0x54,
+	0x3a, 0x55, 0x83, 0x55,
+	0xe5, 0x55, 0xb0, 0x57, 0x01, 0x58, 0x83, 0x59, 0x05, 0xe6, 0x0b, 0xf0,
+	0x0c, 0xf0, 0x04, 0xf8,
+	0x05, 0xf8, 0x07, 0x00, 0x0a, 0x00, 0x1c, 0x00, 0x1e, 0x00, 0x9e, 0x00,
+	0xa8, 0x00, 0xaa, 0x00,
+	0xb9, 0x00, 0xe0, 0x00, 0x22, 0x01, 0x26, 0x01, 0x79, 0x01, 0x7e, 0x01,
+	0xc4, 0x01, 0xc6, 0x01,
+	0x80, 0x02, 0x5e, 0x03, 0xee, 0x04, 0x9a, 0x06, 0xf8, 0x07, 0x62, 0x08,
+	0x68, 0x08, 0x69, 0x08,
+	0xd6, 0x08, 0xe9, 0x09, 0xfa, 0x0b, 0x2e, 0x0f, 0x12, 0x10, 0x1a, 0x10,
+	0xed, 0x10, 0xf1, 0x10,
+	0x2a, 0x11, 0x06, 0x12, 0x0c, 0x12, 0x3e, 0x12, 0x10, 0x13, 0x16, 0x13,
+	0x1e, 0x13, 0x46, 0x14,
+	0x76, 0x14, 0x82, 0x14, 0x36, 0x15, 0xca, 0x15, 0x6b, 0x18, 0xbe, 0x18,
+	0xca, 0x18, 0xe6, 0x19,
+	0x12, 0x1c, 0x46, 0x1c, 0x9c, 0x32, 0x00, 0x40, 0x0e, 0x47, 0xfe, 0x9c,
+	0xf0, 0x2b, 0x02, 0xfe,
+	0xac, 0x0d, 0xff, 0x10, 0x00, 0x00, 0xd7, 0xfe, 0xe8, 0x19, 0x00, 0xd6,
+	0xfe, 0x84, 0x01, 0xff,
+	0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
+	0x00, 0xfe, 0x57, 0x24,
+	0x00, 0xfe, 0x4c, 0x00, 0x5b, 0xff, 0x04, 0x00, 0x00, 0x11, 0xff, 0x09,
+	0x00, 0x00, 0xff, 0x08,
+	0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
+	0xff, 0xff, 0xff, 0x11,
+	0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
+	0xfe, 0x04, 0xf7, 0xd6,
+	0x2c, 0x99, 0x0a, 0x01, 0xfe, 0xc2, 0x0f, 0xfe, 0x04, 0xf7, 0xd6, 0x99,
+	0x0a, 0x42, 0x2c, 0xfe,
+	0x3d, 0xf0, 0xfe, 0x06, 0x02, 0xfe, 0x20, 0xf0, 0xa7, 0xfe, 0x91, 0xf0,
+	0xfe, 0xf4, 0x01, 0xfe,
+	0x90, 0xf0, 0xfe, 0xf4, 0x01, 0xfe, 0x8f, 0xf0, 0xa7, 0x03, 0x5d, 0x4d,
+	0x02, 0xfe, 0xc8, 0x0d,
+	0x01, 0xfe, 0x38, 0x0e, 0xfe, 0xdd, 0x12, 0xfe, 0xfc, 0x10, 0xfe, 0x28,
+	0x1c, 0x03, 0xfe, 0xa6,
+	0x00, 0xfe, 0xd3, 0x12, 0x41, 0x14, 0xfe, 0xa6, 0x00, 0xc2, 0xfe, 0x48,
+	0xf0, 0xfe, 0x8a, 0x02,
+	0xfe, 0x49, 0xf0, 0xfe, 0xa4, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc2, 0x02,
+	0xfe, 0x46, 0xf0, 0xfe,
+	0x54, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x5a, 0x02, 0xfe, 0x43, 0xf0, 0xfe,
+	0x48, 0x02, 0xfe, 0x44,
+	0xf0, 0xfe, 0x4c, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x50, 0x02, 0x18, 0x0a,
+	0xaa, 0x18, 0x06, 0x14,
+	0xa1, 0x02, 0x2b, 0xfe, 0x00, 0x1c, 0xe7, 0xfe, 0x02, 0x1c, 0xe6, 0xfe,
+	0x1e, 0x1c, 0xfe, 0xe9,
+	0x10, 0x01, 0xfe, 0x18, 0x18, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc, 0xce,
+	0x09, 0x70, 0x01, 0xa8,
+	0x02, 0x2b, 0x15, 0x59, 0x39, 0xa2, 0x01, 0xfe, 0x58, 0x10, 0x09, 0x70,
+	0x01, 0x87, 0xfe, 0xbd,
+	0x10, 0x09, 0x70, 0x01, 0x87, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c, 0xfe,
+	0x58, 0x1c, 0x18, 0x06,
+	0x14, 0xa1, 0x2c, 0x1c, 0x2b, 0xfe, 0x3d, 0xf0, 0xfe, 0x06, 0x02, 0x23,
+	0xfe, 0x98, 0x02, 0xfe,
+	0x5a, 0x1c, 0xf8, 0xfe, 0x14, 0x1c, 0x15, 0xfe, 0x30, 0x00, 0x39, 0xa2,
+	0x01, 0xfe, 0x48, 0x10,
+	0x18, 0x06, 0x14, 0xa1, 0x02, 0xd7, 0x22, 0x20, 0x07, 0x11, 0x35, 0xfe,
+	0x69, 0x10, 0x18, 0x06,
+	0x14, 0xa1, 0xfe, 0x04, 0xec, 0x20, 0x4f, 0x43, 0x13, 0x20, 0xfe, 0x05,
+	0xf6, 0xce, 0x01, 0xfe,
+	0x4a, 0x17, 0x08, 0x54, 0x58, 0x37, 0x12, 0x2f, 0x42, 0x92, 0x01, 0xfe,
+	0x82, 0x16, 0x02, 0x2b,
+	0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66, 0x01, 0x73, 0xfe, 0x18, 0x10,
+	0xfe, 0x41, 0x58, 0x09,
+	0xa4, 0x01, 0x0e, 0xfe, 0xc8, 0x54, 0x6b, 0xfe, 0x10, 0x03, 0x01, 0xfe,
+	0x82, 0x16, 0x02, 0x2b,
+	0x2c, 0x4f, 0xfe, 0x02, 0xe8, 0x2a, 0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43,
+	0xfe, 0x77, 0x57, 0xfe,
+	0x27, 0xf0, 0xfe, 0xe0, 0x01, 0xfe, 0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xa7,
+	0xfe, 0x40, 0x1c, 0x1c,
+	0xd9, 0xfe, 0x26, 0xf0, 0xfe, 0x5a, 0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x48,
+	0x03, 0xfe, 0x11, 0xf0,
+	0xa7, 0xfe, 0xef, 0x10, 0xfe, 0x9f, 0xf0, 0xfe, 0x68, 0x03, 0xf9, 0x10,
+	0xfe, 0x11, 0x00, 0x02,
+	0x65, 0x2c, 0xfe, 0x48, 0x1c, 0xf9, 0x08, 0x05, 0x1b, 0xfe, 0x18, 0x13,
+	0x21, 0x22, 0xa3, 0xb7,
+	0x13, 0xa3, 0x09, 0x46, 0x01, 0x0e, 0xb7, 0x78, 0x01, 0xfe, 0xb4, 0x16,
+	0x12, 0xd1, 0x1c, 0xd9,
+	0xfe, 0x01, 0xf0, 0xd9, 0xfe, 0x82, 0xf0, 0xfe, 0x96, 0x03, 0xfa, 0x12,
+	0xfe, 0xe4, 0x00, 0x27,
+	0xfe, 0xa8, 0x03, 0x1c, 0x34, 0x1d, 0xfe, 0xb8, 0x03, 0x01, 0x4b, 0xfe,
+	0x06, 0xf0, 0xfe, 0xc8,
+	0x03, 0x95, 0x86, 0xfe, 0x0a, 0xf0, 0xfe, 0x8a, 0x06, 0x02, 0x24, 0x03,
+	0x70, 0x28, 0x17, 0xfe,
+	0xfa, 0x04, 0x15, 0x6d, 0x01, 0x36, 0x7b, 0xfe, 0x6a, 0x02, 0x02, 0xd8,
+	0xf9, 0x2c, 0x99, 0x19,
+	0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0xfe, 0x48, 0x1c,
+	0x74, 0x01, 0xaf, 0x8c,
+	0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x17, 0xda, 0x09, 0xd1, 0x01, 0x0e,
+	0x8d, 0x51, 0x64, 0x79,
+	0x2a, 0x03, 0x70, 0x28, 0xfe, 0x10, 0x12, 0x15, 0x6d, 0x01, 0x36, 0x7b,
+	0xfe, 0x6a, 0x02, 0x02,
+	0xd8, 0xc7, 0x81, 0xc8, 0x83, 0x1c, 0x24, 0x27, 0xfe, 0x40, 0x04, 0x1d,
+	0xfe, 0x3c, 0x04, 0x3b,
+	0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x4e, 0x12, 0x2d, 0xff, 0x02,
+	0x00, 0x10, 0x01, 0x0b,
+	0x1d, 0xfe, 0xe4, 0x04, 0x2d, 0x01, 0x0b, 0x1d, 0x24, 0x33, 0x31, 0xde,
+	0xfe, 0x4c, 0x44, 0xfe,
+	0x4c, 0x12, 0x51, 0xfe, 0x44, 0x48, 0x0f, 0x6f, 0xfe, 0x4c, 0x54, 0x6b,
+	0xda, 0x4f, 0x79, 0x2a,
+	0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x62, 0x13, 0x08, 0x05, 0x1b,
+	0xfe, 0x2a, 0x13, 0x32,
+	0x07, 0x82, 0xfe, 0x52, 0x13, 0xfe, 0x20, 0x10, 0x0f, 0x6f, 0xfe, 0x4c,
+	0x54, 0x6b, 0xda, 0xfe,
+	0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x40, 0x13, 0x08, 0x05, 0x1b, 0xfe,
+	0x08, 0x13, 0x32, 0x07,
+	0x82, 0xfe, 0x30, 0x13, 0x08, 0x05, 0x1b, 0xfe, 0x1c, 0x12, 0x15, 0x9d,
+	0x08, 0x05, 0x06, 0x4d,
+	0x15, 0xfe, 0x0d, 0x00, 0x01, 0x36, 0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24,
+	0x2d, 0x12, 0xfe, 0xe6,
+	0x00, 0xfe, 0x1c, 0x90, 0xfe, 0x40, 0x5c, 0x04, 0x15, 0x9d, 0x01, 0x36,
+	0x02, 0x2b, 0xfe, 0x42,
+	0x5b, 0x99, 0x19, 0xfe, 0x46, 0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
+	0xfe, 0x87, 0x80, 0xfe,
+	0x31, 0xe4, 0x5b, 0x08, 0x05, 0x0a, 0xfe, 0x84, 0x13, 0xfe, 0x20, 0x80,
+	0x07, 0x19, 0xfe, 0x7c,
+	0x12, 0x53, 0x05, 0x06, 0xfe, 0x6c, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x28,
+	0x17, 0xfe, 0x90, 0x05,
+	0xfe, 0x31, 0xe4, 0x5a, 0x53, 0x05, 0x0a, 0xfe, 0x56, 0x13, 0x03, 0xfe,
+	0xa0, 0x00, 0x28, 0xfe,
+	0x4e, 0x12, 0x67, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x48, 0x05, 0x1c,
+	0x34, 0xfe, 0x89, 0x48,
+	0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x56, 0x05, 0x26, 0xfe, 0xa8, 0x05,
+	0x12, 0xfe, 0xe3, 0x00,
+	0x21, 0x53, 0xfe, 0x4a, 0xf0, 0xfe, 0x76, 0x05, 0xfe, 0x49, 0xf0, 0xfe,
+	0x70, 0x05, 0x88, 0x25,
+	0xfe, 0x21, 0x00, 0xab, 0x25, 0xfe, 0x22, 0x00, 0xaa, 0x25, 0x58, 0xfe,
+	0x09, 0x48, 0xff, 0x02,
+	0x00, 0x10, 0x27, 0xfe, 0x86, 0x05, 0x26, 0xfe, 0xa8, 0x05, 0xfe, 0xe2,
+	0x08, 0x53, 0x05, 0xcb,
+	0x4d, 0x01, 0xb0, 0x25, 0x06, 0x13, 0xd3, 0x39, 0xfe, 0x27, 0x01, 0x08,
+	0x05, 0x1b, 0xfe, 0x22,
+	0x12, 0x41, 0x01, 0xb2, 0x15, 0x9d, 0x08, 0x05, 0x06, 0x4d, 0x15, 0xfe,
+	0x0d, 0x00, 0x01, 0x36,
+	0x7b, 0xfe, 0x64, 0x0d, 0x02, 0x24, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0xeb,
+	0x03, 0x5c, 0x28, 0xfe,
+	0x36, 0x13, 0x41, 0x01, 0xb2, 0x26, 0xfe, 0x18, 0x06, 0x09, 0x06, 0x53,
+	0x05, 0x1f, 0xfe, 0x02,
+	0x12, 0x50, 0x01, 0xfe, 0x9e, 0x15, 0x1d, 0xfe, 0x0e, 0x06, 0x12, 0xa5,
+	0x01, 0x4b, 0x12, 0xfe,
+	0xe5, 0x00, 0x03, 0x5c, 0xc1, 0x0c, 0x5c, 0x03, 0xcd, 0x28, 0xfe, 0x62,
+	0x12, 0x03, 0x45, 0x28,
+	0xfe, 0x5a, 0x13, 0x01, 0xfe, 0x0c, 0x19, 0x01, 0xfe, 0x76, 0x19, 0xfe,
+	0x43, 0x48, 0xc4, 0xcc,
+	0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0x8b, 0xc4,
+	0x6e, 0x41, 0x01, 0xb2,
+	0x26, 0xfe, 0x82, 0x06, 0x53, 0x05, 0x1a, 0xe9, 0x91, 0x09, 0x59, 0x01,
+	0xfe, 0xcc, 0x15, 0x1d,
+	0xfe, 0x78, 0x06, 0x12, 0xa5, 0x01, 0x4b, 0x12, 0xfe, 0xe5, 0x00, 0x03,
+	0x45, 0xc1, 0x0c, 0x45,
+	0x18, 0x06, 0x01, 0xb2, 0xfa, 0x76, 0x74, 0x01, 0xaf, 0x8c, 0x12, 0xfe,
+	0xe2, 0x00, 0x27, 0xdb,
+	0x1c, 0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0xb6, 0x06, 0x94, 0xfe, 0x6c, 0x07,
+	0xfe, 0x06, 0xf0, 0xfe,
+	0x74, 0x07, 0x95, 0x86, 0x02, 0x24, 0x08, 0x05, 0x0a, 0xfe, 0x2e, 0x12,
+	0x16, 0x19, 0x01, 0x0b,
+	0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01, 0x0b,
+	0xfe, 0x99, 0xa4, 0x01,
+	0x0b, 0x16, 0x00, 0x02, 0xfe, 0x42, 0x08, 0x68, 0x05, 0x1a, 0xfe, 0x38,
+	0x12, 0x08, 0x05, 0x1a,
+	0xfe, 0x30, 0x13, 0x16, 0xfe, 0x1b, 0x00, 0x01, 0x0b, 0x16, 0x00, 0x01,
+	0x0b, 0x16, 0x00, 0x01,
+	0x0b, 0x16, 0x00, 0x01, 0x0b, 0x16, 0x06, 0x01, 0x0b, 0x16, 0x00, 0x02,
+	0xe2, 0x6c, 0x58, 0xbe,
+	0x50, 0xfe, 0x9a, 0x81, 0x55, 0x1b, 0x7a, 0xfe, 0x42, 0x07, 0x09, 0x1b,
+	0xfe, 0x09, 0x6f, 0xba,
+	0xfe, 0xca, 0x45, 0xfe, 0x32, 0x12, 0x69, 0x6d, 0x8b, 0x6c, 0x7f, 0x27,
+	0xfe, 0x54, 0x07, 0x1c,
+	0x34, 0xfe, 0x0a, 0xf0, 0xfe, 0x42, 0x07, 0x95, 0x86, 0x94, 0xfe, 0x6c,
+	0x07, 0x02, 0x24, 0x01,
+	0x4b, 0x02, 0xdb, 0x16, 0x1f, 0x02, 0xdb, 0xfe, 0x9c, 0xf7, 0xdc, 0xfe,
+	0x2c, 0x90, 0xfe, 0xae,
+	0x90, 0x56, 0xfe, 0xda, 0x07, 0x0c, 0x60, 0x14, 0x61, 0x08, 0x54, 0x5a,
+	0x37, 0x22, 0x20, 0x07,
+	0x11, 0xfe, 0x0e, 0x12, 0x8d, 0xfe, 0x80, 0x80, 0x39, 0x20, 0x6a, 0x2a,
+	0xfe, 0x06, 0x10, 0xfe,
+	0x83, 0xe7, 0xfe, 0x48, 0x00, 0xab, 0xfe, 0x03, 0x40, 0x08, 0x54, 0x5b,
+	0x37, 0x01, 0xb3, 0xb8,
+	0xfe, 0x1f, 0x40, 0x13, 0x62, 0x01, 0xef, 0xfe, 0x08, 0x50, 0xfe, 0x8a,
+	0x50, 0xfe, 0x44, 0x51,
+	0xfe, 0xc6, 0x51, 0x88, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90, 0x0c, 0x5e,
+	0x14, 0x5f, 0xfe, 0x0c,
+	0x90, 0xfe, 0x8e, 0x90, 0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x0c, 0x3d,
+	0x14, 0x3e, 0xfe, 0x4a,
+	0x10, 0x08, 0x05, 0x5a, 0xfe, 0x2a, 0x12, 0xfe, 0x2c, 0x90, 0xfe, 0xae,
+	0x90, 0x0c, 0x60, 0x14,
+	0x61, 0x08, 0x05, 0x5b, 0x8b, 0x01, 0xb3, 0xfe, 0x1f, 0x80, 0x13, 0x62,
+	0xfe, 0x44, 0x90, 0xfe,
+	0xc6, 0x90, 0x0c, 0x3f, 0x14, 0x40, 0xfe, 0x08, 0x90, 0xfe, 0x8a, 0x90,
+	0x0c, 0x5e, 0x14, 0x5f,
+	0xfe, 0x40, 0x90, 0xfe, 0xc2, 0x90, 0x0c, 0x3d, 0x14, 0x3e, 0x0c, 0x2e,
+	0x14, 0x3c, 0x21, 0x0c,
+	0x49, 0x0c, 0x63, 0x08, 0x54, 0x1f, 0x37, 0x2c, 0x0f, 0xfe, 0x4e, 0x11,
+	0x27, 0xdd, 0xfe, 0x9e,
+	0xf0, 0xfe, 0x76, 0x08, 0xbc, 0x17, 0x34, 0x2c, 0x77, 0xe6, 0xc5, 0xfe,
+	0x9a, 0x08, 0xc6, 0xfe,
+	0xb8, 0x08, 0x94, 0xfe, 0x8e, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x94, 0x08,
+	0x95, 0x86, 0x02, 0x24,
+	0x01, 0x4b, 0xfe, 0xc9, 0x10, 0x16, 0x1f, 0xfe, 0xc9, 0x10, 0x68, 0x05,
+	0x06, 0xfe, 0x10, 0x12,
+	0x68, 0x05, 0x0a, 0x4e, 0x08, 0x05, 0x0a, 0xfe, 0x90, 0x12, 0xfe, 0x2e,
+	0x1c, 0x02, 0xfe, 0x18,
+	0x0b, 0x68, 0x05, 0x06, 0x4e, 0x68, 0x05, 0x0a, 0xfe, 0x7a, 0x12, 0xfe,
+	0x2c, 0x1c, 0xfe, 0xaa,
+	0xf0, 0xfe, 0xd2, 0x09, 0xfe, 0xac, 0xf0, 0xfe, 0x00, 0x09, 0x02, 0xfe,
+	0xde, 0x09, 0xfe, 0xb7,
+	0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0x02, 0xf6, 0x1a, 0x50, 0xfe, 0x70, 0x18,
+	0xfe, 0xf1, 0x18, 0xfe,
+	0x40, 0x55, 0xfe, 0xe1, 0x55, 0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0xfe,
+	0x14, 0x59, 0xfe, 0x95,
+	0x59, 0x1c, 0x85, 0xfe, 0x8c, 0xf0, 0xfe, 0xfc, 0x08, 0xfe, 0xac, 0xf0,
+	0xfe, 0xf0, 0x08, 0xb5,
+	0xfe, 0xcb, 0x10, 0xfe, 0xad, 0xf0, 0xfe, 0x0c, 0x09, 0x02, 0xfe, 0x18,
+	0x0b, 0xb6, 0xfe, 0xbf,
+	0x10, 0xfe, 0x2b, 0xf0, 0x85, 0xf4, 0x1e, 0xfe, 0x00, 0xfe, 0xfe, 0x1c,
+	0x12, 0xc2, 0xfe, 0xd2,
+	0xf0, 0x85, 0xfe, 0x76, 0x18, 0x1e, 0x19, 0x17, 0x85, 0x03, 0xd2, 0x1e,
+	0x06, 0x17, 0x85, 0xc5,
+	0x4a, 0xc6, 0x4a, 0xb5, 0xb6, 0xfe, 0x89, 0x10, 0x74, 0x67, 0x2d, 0x15,
+	0x9d, 0x01, 0x36, 0x10,
+	0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x65, 0x10, 0x80, 0x02, 0x65, 0xfe,
+	0x98, 0x80, 0xfe, 0x19,
+	0xe4, 0x0a, 0xfe, 0x1a, 0x12, 0x51, 0xfe, 0x19, 0x82, 0xfe, 0x6c, 0x18,
+	0xfe, 0x44, 0x54, 0xbe,
+	0xfe, 0x19, 0x81, 0xfe, 0x74, 0x18, 0x8f, 0x90, 0x17, 0xfe, 0xce, 0x08,
+	0x02, 0x4a, 0x08, 0x05,
+	0x5a, 0xec, 0x03, 0x2e, 0x29, 0x3c, 0x0c, 0x3f, 0x14, 0x40, 0x9b, 0x2e,
+	0x9c, 0x3c, 0xfe, 0x6c,
+	0x18, 0xfe, 0xed, 0x18, 0xfe, 0x44, 0x54, 0xfe, 0xe5, 0x54, 0x3a, 0x3f,
+	0x3b, 0x40, 0x03, 0x49,
+	0x29, 0x63, 0x8f, 0xfe, 0xe3, 0x54, 0xfe, 0x74, 0x18, 0xfe, 0xf5, 0x18,
+	0x8f, 0xfe, 0xe3, 0x54,
+	0x90, 0xc0, 0x56, 0xfe, 0xce, 0x08, 0x02, 0x4a, 0xfe, 0x37, 0xf0, 0xfe,
+	0xda, 0x09, 0xfe, 0x8b,
+	0xf0, 0xfe, 0x60, 0x09, 0x02, 0x4a, 0x08, 0x05, 0x0a, 0x23, 0xfe, 0xfa,
+	0x0a, 0x3a, 0x49, 0x3b,
+	0x63, 0x56, 0xfe, 0x3e, 0x0a, 0x0f, 0xfe, 0xc0, 0x07, 0x41, 0x98, 0x00,
+	0xad, 0xfe, 0x01, 0x59,
+	0xfe, 0x52, 0xf0, 0xfe, 0x0c, 0x0a, 0x8f, 0x7a, 0xfe, 0x24, 0x0a, 0x3a,
+	0x49, 0x8f, 0xfe, 0xe3,
+	0x54, 0x57, 0x49, 0x7d, 0x63, 0xfe, 0x14, 0x58, 0xfe, 0x95, 0x58, 0x02,
+	0x4a, 0x3a, 0x49, 0x3b,
+	0x63, 0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0xbe, 0x57, 0x49, 0x57, 0x63,
+	0x02, 0x4a, 0x08, 0x05,
+	0x5a, 0xfe, 0x82, 0x12, 0x08, 0x05, 0x1f, 0xfe, 0x66, 0x13, 0x22, 0x62,
+	0xb7, 0xfe, 0x03, 0xa1,
+	0xfe, 0x83, 0x80, 0xfe, 0xc8, 0x44, 0xfe, 0x2e, 0x13, 0xfe, 0x04, 0x91,
+	0xfe, 0x86, 0x91, 0x6a,
+	0x2a, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x56, 0xe0, 0x03, 0x60, 0x29,
+	0x61, 0x0c, 0x7f, 0x14,
+	0x80, 0x57, 0x60, 0x7d, 0x61, 0x01, 0xb3, 0xb8, 0x6a, 0x2a, 0x13, 0x62,
+	0x9b, 0x2e, 0x9c, 0x3c,
+	0x3a, 0x3f, 0x3b, 0x40, 0x90, 0xc0, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05,
+	0xfa, 0x3c, 0x01, 0xef,
+	0xfe, 0x36, 0x10, 0x21, 0x0c, 0x7f, 0x0c, 0x80, 0x3a, 0x3f, 0x3b, 0x40,
+	0xe4, 0x08, 0x05, 0x1f,
+	0x17, 0xe0, 0x3a, 0x3d, 0x3b, 0x3e, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37,
+	0x03, 0x5e, 0x29, 0x5f,
+	0xfe, 0x10, 0x58, 0xfe, 0x91, 0x58, 0x57, 0x49, 0x7d, 0x63, 0x02, 0xfe,
+	0xf4, 0x09, 0x08, 0x05,
+	0x1f, 0x17, 0xe0, 0x08, 0x05, 0xfe, 0xf7, 0x00, 0x37, 0xbe, 0xfe, 0x19,
+	0x81, 0x50, 0xfe, 0x10,
+	0x90, 0xfe, 0x92, 0x90, 0xfe, 0xd3, 0x10, 0x32, 0x07, 0xa6, 0x17, 0xfe,
+	0x08, 0x09, 0x12, 0xa6,
+	0x08, 0x05, 0x0a, 0xfe, 0x14, 0x13, 0x03, 0x3d, 0x29, 0x3e, 0x56, 0xfe,
+	0x08, 0x09, 0xfe, 0x0c,
+	0x58, 0xfe, 0x8d, 0x58, 0x02, 0x4a, 0x21, 0x41, 0xfe, 0x19, 0x80, 0xe7,
+	0x08, 0x05, 0x0a, 0xfe,
+	0x1a, 0x12, 0xfe, 0x6c, 0x19, 0xfe, 0x19, 0x41, 0xf4, 0xc2, 0xfe, 0xd1,
+	0xf0, 0xe2, 0x15, 0x7e,
+	0x01, 0x36, 0x10, 0xfe, 0x44, 0x00, 0xfe, 0x8e, 0x10, 0xfe, 0x6c, 0x19,
+	0x57, 0x3d, 0xfe, 0xed,
+	0x19, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51, 0xf4, 0x1e, 0xfe,
+	0x00, 0xff, 0x35, 0xfe,
+	0x74, 0x10, 0xc2, 0xfe, 0xd2, 0xf0, 0xfe, 0xa6, 0x0b, 0xfe, 0x76, 0x18,
+	0x1e, 0x19, 0x8a, 0x03,
+	0xd2, 0x1e, 0x06, 0xfe, 0x08, 0x13, 0x10, 0xfe, 0x16, 0x00, 0x02, 0x65,
+	0xfe, 0xd1, 0xf0, 0xfe,
+	0xb8, 0x0b, 0x15, 0x7e, 0x01, 0x36, 0x10, 0xfe, 0x17, 0x00, 0xfe, 0x42,
+	0x10, 0xfe, 0xce, 0xf0,
+	0xfe, 0xbe, 0x0b, 0xfe, 0x3c, 0x10, 0xfe, 0xcd, 0xf0, 0xfe, 0xca, 0x0b,
+	0x10, 0xfe, 0x22, 0x00,
+	0x02, 0x65, 0xfe, 0xcb, 0xf0, 0xfe, 0xd6, 0x0b, 0x10, 0xfe, 0x24, 0x00,
+	0x02, 0x65, 0xfe, 0xd0,
+	0xf0, 0xfe, 0xe0, 0x0b, 0x10, 0x9e, 0xe5, 0xfe, 0xcf, 0xf0, 0xfe, 0xea,
+	0x0b, 0x10, 0x58, 0xfe,
+	0x10, 0x10, 0xfe, 0xcc, 0xf0, 0xe2, 0x68, 0x05, 0x1f, 0x4d, 0x10, 0xfe,
+	0x12, 0x00, 0x2c, 0x0f,
+	0xfe, 0x4e, 0x11, 0x27, 0xfe, 0x00, 0x0c, 0xfe, 0x9e, 0xf0, 0xfe, 0x14,
+	0x0c, 0xbc, 0x17, 0x34,
+	0x2c, 0x77, 0xe6, 0xc5, 0x24, 0xc6, 0x24, 0x2c, 0xfa, 0x27, 0xfe, 0x20,
+	0x0c, 0x1c, 0x34, 0x94,
+	0xfe, 0x3c, 0x0c, 0x95, 0x86, 0xc5, 0xdc, 0xc6, 0xdc, 0x02, 0x24, 0x01,
+	0x4b, 0xfe, 0xdb, 0x10,
+	0x12, 0xfe, 0xe8, 0x00, 0xb5, 0xb6, 0x74, 0xc7, 0x81, 0xc8, 0x83, 0xfe,
+	0x89, 0xf0, 0x24, 0x33,
+	0x31, 0xe1, 0xc7, 0x81, 0xc8, 0x83, 0x27, 0xfe, 0x66, 0x0c, 0x1d, 0x24,
+	0x33, 0x31, 0xdf, 0xbc,
+	0x4e, 0x10, 0xfe, 0x42, 0x00, 0x02, 0x65, 0x7c, 0x06, 0xfe, 0x81, 0x49,
+	0x17, 0xfe, 0x2c, 0x0d,
+	0x08, 0x05, 0x0a, 0xfe, 0x44, 0x13, 0x10, 0x00, 0x55, 0x0a, 0xfe, 0x54,
+	0x12, 0x55, 0xfe, 0x28,
+	0x00, 0x23, 0xfe, 0x9a, 0x0d, 0x09, 0x46, 0x01, 0x0e, 0x07, 0x00, 0x66,
+	0x44, 0xfe, 0x28, 0x00,
+	0xfe, 0xe2, 0x10, 0x01, 0xf5, 0x01, 0xf6, 0x09, 0xa4, 0x01, 0xfe, 0x26,
+	0x0f, 0x64, 0x12, 0x2f,
+	0x01, 0x73, 0x02, 0x2b, 0x10, 0xfe, 0x44, 0x00, 0x55, 0x0a, 0xe9, 0x44,
+	0x0a, 0xfe, 0xb4, 0x10,
+	0x01, 0xb0, 0x44, 0x0a, 0xfe, 0xaa, 0x10, 0x01, 0xb0, 0xfe, 0x19, 0x82,
+	0xfe, 0x34, 0x46, 0xac,
+	0x44, 0x0a, 0x10, 0xfe, 0x43, 0x00, 0xfe, 0x96, 0x10, 0x08, 0x54, 0x0a,
+	0x37, 0x01, 0xf5, 0x01,
+	0xf6, 0x64, 0x12, 0x2f, 0x01, 0x73, 0x99, 0x0a, 0x64, 0x42, 0x92, 0x02,
+	0xfe, 0x2e, 0x03, 0x08,
+	0x05, 0x0a, 0x8a, 0x44, 0x0a, 0x10, 0x00, 0xfe, 0x5c, 0x10, 0x68, 0x05,
+	0x1a, 0xfe, 0x58, 0x12,
+	0x08, 0x05, 0x1a, 0xfe, 0x50, 0x13, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0,
+	0xfe, 0x50, 0x0d, 0xfe,
+	0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x56, 0x0d, 0x08, 0x54, 0x1a, 0x37,
+	0xfe, 0xa9, 0x10, 0x10,
+	0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0a, 0x50, 0xfe, 0x2e, 0x10, 0x10,
+	0xfe, 0x13, 0x00, 0xfe,
+	0x10, 0x10, 0x10, 0x6f, 0xab, 0x10, 0xfe, 0x41, 0x00, 0xaa, 0x10, 0xfe,
+	0x24, 0x00, 0x8c, 0xb5,
+	0xb6, 0x74, 0x03, 0x70, 0x28, 0x23, 0xd8, 0x50, 0xfe, 0x04, 0xe6, 0x1a,
+	0xfe, 0x9d, 0x41, 0xfe,
+	0x1c, 0x42, 0x64, 0x01, 0xe3, 0x02, 0x2b, 0xf8, 0x15, 0x0a, 0x39, 0xa0,
+	0xb4, 0x15, 0xfe, 0x31,
+	0x00, 0x39, 0xa2, 0x01, 0xfe, 0x48, 0x10, 0x02, 0xd7, 0x42, 0xfe, 0x06,
+	0xec, 0xd0, 0xfc, 0x44,
+	0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe, 0x06, 0xea, 0xd0, 0xfe, 0x47,
+	0x4b, 0x91, 0xfe, 0x75,
+	0x57, 0x03, 0x5d, 0xfe, 0x98, 0x56, 0xfe, 0x38, 0x12, 0x09, 0x48, 0x01,
+	0x0e, 0xfe, 0x44, 0x48,
+	0x4f, 0x08, 0x05, 0x1b, 0xfe, 0x1a, 0x13, 0x09, 0x46, 0x01, 0x0e, 0x41,
+	0xfe, 0x41, 0x58, 0x09,
+	0xa4, 0x01, 0x0e, 0xfe, 0x49, 0x54, 0x96, 0xfe, 0x1e, 0x0e, 0x02, 0xfe,
+	0x2e, 0x03, 0x09, 0x5d,
+	0xfe, 0xee, 0x14, 0xfc, 0x44, 0x1b, 0xfe, 0xce, 0x45, 0x35, 0x42, 0xfe,
+	0xce, 0x47, 0xfe, 0xad,
+	0x13, 0x02, 0x2b, 0x22, 0x20, 0x07, 0x11, 0xfe, 0x9e, 0x12, 0x21, 0x13,
+	0x59, 0x13, 0x9f, 0x13,
+	0xd5, 0x22, 0x2f, 0x41, 0x39, 0x2f, 0xbc, 0xad, 0xfe, 0xbc, 0xf0, 0xfe,
+	0xe0, 0x0e, 0x0f, 0x06,
+	0x13, 0x59, 0x01, 0xfe, 0xda, 0x16, 0x03, 0xfe, 0x38, 0x01, 0x29, 0xfe,
+	0x3a, 0x01, 0x56, 0xfe,
+	0xe4, 0x0e, 0xfe, 0x02, 0xec, 0xd5, 0x69, 0x00, 0x66, 0xfe, 0x04, 0xec,
+	0x20, 0x4f, 0xfe, 0x05,
+	0xf6, 0xfe, 0x34, 0x01, 0x01, 0xfe, 0x4a, 0x17, 0xfe, 0x08, 0x90, 0xfe,
+	0x48, 0xf4, 0x0d, 0xfe,
+	0x18, 0x13, 0xba, 0xfe, 0x02, 0xea, 0xd5, 0x69, 0x7e, 0xfe, 0xc5, 0x13,
+	0x15, 0x1a, 0x39, 0xa0,
+	0xb4, 0xfe, 0x2e, 0x10, 0x03, 0xfe, 0x38, 0x01, 0x1e, 0xfe, 0xf0, 0xff,
+	0x0c, 0xfe, 0x60, 0x01,
+	0x03, 0xfe, 0x3a, 0x01, 0x0c, 0xfe, 0x62, 0x01, 0x43, 0x13, 0x20, 0x25,
+	0x06, 0x13, 0x2f, 0x12,
+	0x2f, 0x92, 0x0f, 0x06, 0x04, 0x21, 0x04, 0x22, 0x59, 0xfe, 0xf7, 0x12,
+	0x22, 0x9f, 0xb7, 0x13,
+	0x9f, 0x07, 0x7e, 0xfe, 0x71, 0x13, 0xfe, 0x24, 0x1c, 0x15, 0x19, 0x39,
+	0xa0, 0xb4, 0xfe, 0xd9,
+	0x10, 0xc3, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x04,
+	0xc3, 0xfe, 0x03, 0xdc,
+	0xfe, 0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x04, 0xfe, 0x03, 0x57, 0xc3, 0x21,
+	0xfe, 0x00, 0xcc, 0x04,
+	0xfe, 0x03, 0x57, 0xc3, 0x78, 0x04, 0x08, 0x05, 0x58, 0xfe, 0x22, 0x13,
+	0xfe, 0x1c, 0x80, 0x07,
+	0x06, 0xfe, 0x1a, 0x13, 0xfe, 0x1e, 0x80, 0xed, 0xfe, 0x1d, 0x80, 0xae,
+	0xfe, 0x0c, 0x90, 0xfe,
+	0x0e, 0x13, 0xfe, 0x0e, 0x90, 0xac, 0xfe, 0x3c, 0x90, 0xfe, 0x30, 0xf4,
+	0x0a, 0xfe, 0x3c, 0x50,
+	0xaa, 0x01, 0xfe, 0x7a, 0x17, 0x32, 0x07, 0x2f, 0xad, 0x01, 0xfe, 0xb4,
+	0x16, 0x08, 0x05, 0x1b,
+	0x4e, 0x01, 0xf5, 0x01, 0xf6, 0x12, 0xfe, 0xe9, 0x00, 0x08, 0x05, 0x58,
+	0xfe, 0x2c, 0x13, 0x01,
+	0xfe, 0x0c, 0x17, 0xfe, 0x1e, 0x1c, 0xfe, 0x14, 0x90, 0xfe, 0x96, 0x90,
+	0x0c, 0xfe, 0x64, 0x01,
+	0x14, 0xfe, 0x66, 0x01, 0x08, 0x05, 0x5b, 0xfe, 0x12, 0x12, 0xfe, 0x03,
+	0x80, 0x8d, 0xfe, 0x01,
+	0xec, 0x20, 0xfe, 0x80, 0x40, 0x13, 0x20, 0x6a, 0x2a, 0x12, 0xcf, 0x64,
+	0x22, 0x20, 0xfb, 0x79,
+	0x20, 0x04, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe, 0x06, 0x58,
+	0x03, 0xfe, 0xae, 0x00,
 
-  0xfe,  0x07,  0x58,  0x03,  0xfe,  0xb0,  0x00,  0xfe,  0x08,  0x58,  0x03,  0xfe,  0xb2,  0x00,  0xfe,  0x09,
-  0x58,  0xfe,  0x0a,  0x1c,  0x25,  0x6e,  0x13,  0xd0,  0x21,  0x0c,  0x5c,  0x0c,  0x45,  0x0f,  0x46,  0x52,
-  0x50,  0x18,  0x1b,  0xfe,  0x90,  0x4d,  0xfe,  0x91,  0x54,  0x23,  0xfe,  0xfc,  0x0f,  0x44,  0x11,  0x0f,
-  0x48,  0x52,  0x18,  0x58,  0xfe,  0x90,  0x4d,  0xfe,  0x91,  0x54,  0x23,  0xe4,  0x25,  0x11,  0x13,  0x20,
-  0x7c,  0x6f,  0x4f,  0x22,  0x20,  0xfb,  0x79,  0x20,  0x12,  0xcf,  0xfe,  0x14,  0x56,  0xfe,  0xd6,  0xf0,
-  0xfe,  0x26,  0x10,  0xf8,  0x74,  0xfe,  0x14,  0x1c,  0xfe,  0x10,  0x1c,  0xfe,  0x18,  0x1c,  0x04,  0x42,
-  0xfe,  0x0c,  0x14,  0xfc,  0xfe,  0x07,  0xe6,  0x1b,  0xfe,  0xce,  0x47,  0xfe,  0xf5,  0x13,  0x04,  0x01,
-  0xb0,  0x7c,  0x6f,  0x4f,  0xfe,  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x42,  0x13,  0x32,  0x07,  0x2f,
-  0xfe,  0x34,  0x13,  0x09,  0x48,  0x01,  0x0e,  0xbb,  0xfe,  0x36,  0x12,  0xfe,  0x41,  0x48,  0xfe,  0x45,
-  0x48,  0x01,  0xf0,  0xfe,  0x00,  0xcc,  0xbb,  0xfe,  0xf3,  0x13,  0x43,  0x78,  0x07,  0x11,  0xac,  0x09,
-  0x84,  0x01,  0x0e,  0xfe,  0x80,  0x5c,  0x01,  0x73,  0xfe,  0x0e,  0x10,  0x07,  0x82,  0x4e,  0xfe,  0x14,
-  0x56,  0xfe,  0xd6,  0xf0,  0xfe,  0x60,  0x10,  0x04,  0xfe,  0x44,  0x58,  0x8d,  0xfe,  0x01,  0xec,  0xa2,
-  0xfe,  0x9e,  0x40,  0xfe,  0x9d,  0xe7,  0x00,  0xfe,  0x9c,  0xe7,  0x1a,  0x79,  0x2a,  0x01,  0xe3,  0xfe,
-  0xdd,  0x10,  0x2c,  0xc7,  0x81,  0xc8,  0x83,  0x33,  0x31,  0xde,  0x07,  0x1a,  0xfe,  0x48,  0x12,  0x07,
-  0x0a,  0xfe,  0x56,  0x12,  0x07,  0x19,  0xfe,  0x30,  0x12,  0x07,  0xc9,  0x17,  0xfe,  0x32,  0x12,  0x07,
-  0xfe,  0x23,  0x00,  0x17,  0xeb,  0x07,  0x06,  0x17,  0xfe,  0x9c,  0x12,  0x07,  0x1f,  0xfe,  0x12,  0x12,
-  0x07,  0x00,  0x17,  0x24,  0x15,  0xc9,  0x01,  0x36,  0xa9,  0x2d,  0x01,  0x0b,  0x94,  0x4b,  0x04,  0x2d,
-  0xdd,  0x09,  0xd1,  0x01,  0xfe,  0x26,  0x0f,  0x12,  0x82,  0x02,  0x2b,  0x2d,  0x32,  0x07,  0xa6,  0xfe,
-  0xd9,  0x13,  0x3a,  0x3d,  0x3b,  0x3e,  0x56,  0xfe,  0xf0,  0x11,  0x08,  0x05,  0x5a,  0xfe,  0x72,  0x12,
-  0x9b,  0x2e,  0x9c,  0x3c,  0x90,  0xc0,  0x96,  0xfe,  0xba,  0x11,  0x22,  0x62,  0xfe,  0x26,  0x13,  0x03,
-  0x7f,  0x29,  0x80,  0x56,  0xfe,  0x76,  0x0d,  0x0c,  0x60,  0x14,  0x61,  0x21,  0x0c,  0x7f,  0x0c,  0x80,
-  0x01,  0xb3,  0x25,  0x6e,  0x77,  0x13,  0x62,  0x01,  0xef,  0x9b,  0x2e,  0x9c,  0x3c,  0xfe,  0x04,  0x55,
-  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,  0x2e,  0xfe,  0x05,  0xfa,  0x3c,  0xfe,  0x91,  0x10,  0x03,  0x3f,
-  0x29,  0x40,  0xfe,  0x40,  0x56,  0xfe,  0xe1,  0x56,  0x0c,  0x3f,  0x14,  0x40,  0x88,  0x9b,  0x2e,  0x9c,
-  0x3c,  0x90,  0xc0,  0x03,  0x5e,  0x29,  0x5f,  0xfe,  0x00,  0x56,  0xfe,  0xa1,  0x56,  0x0c,  0x5e,  0x14,
-  0x5f,  0x08,  0x05,  0x5a,  0xfe,  0x1e,  0x12,  0x22,  0x62,  0xfe,  0x1f,  0x40,  0x03,  0x60,  0x29,  0x61,
-  0xfe,  0x2c,  0x50,  0xfe,  0xae,  0x50,  0x03,  0x3f,  0x29,  0x40,  0xfe,  0x44,  0x50,  0xfe,  0xc6,  0x50,
-  0x03,  0x5e,  0x29,  0x5f,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0x03,  0x3d,  0x29,  0x3e,  0xfe,  0x40,
-  0x50,  0xfe,  0xc2,  0x50,  0x02,  0x89,  0x25,  0x06,  0x13,  0xd4,  0x02,  0x72,  0x2d,  0x01,  0x0b,  0x1d,
-  0x4c,  0x33,  0x31,  0xde,  0x07,  0x06,  0x23,  0x4c,  0x32,  0x07,  0xa6,  0x23,  0x72,  0x01,  0xaf,  0x1e,
-  0x43,  0x17,  0x4c,  0x08,  0x05,  0x0a,  0xee,  0x3a,  0x3d,  0x3b,  0x3e,  0xfe,  0x0a,  0x55,  0x35,  0xfe,
-  0x8b,  0x55,  0x57,  0x3d,  0x7d,  0x3e,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0x02,  0x72,  0xfe,  0x19,
-  0x81,  0xba,  0xfe,  0x19,  0x41,  0x02,  0x72,  0x2d,  0x01,  0x0b,  0x1c,  0x34,  0x1d,  0xe8,  0x33,  0x31,
-  0xe1,  0x55,  0x19,  0xfe,  0xa6,  0x12,  0x55,  0x0a,  0x4d,  0x02,  0x4c,  0x01,  0x0b,  0x1c,  0x34,  0x1d,
-  0xe8,  0x33,  0x31,  0xdf,  0x07,  0x19,  0x23,  0x4c,  0x01,  0x0b,  0x1d,  0xe8,  0x33,  0x31,  0xfe,  0xe8,
-  0x09,  0xfe,  0xc2,  0x49,  0x51,  0x03,  0xfe,  0x9c,  0x00,  0x28,  0x8a,  0x53,  0x05,  0x1f,  0x35,  0xa9,
-  0xfe,  0xbb,  0x45,  0x55,  0x00,  0x4e,  0x44,  0x06,  0x7c,  0x43,  0xfe,  0xda,  0x14,  0x01,  0xaf,  0x8c,
-  0xfe,  0x4b,  0x45,  0xee,  0x32,  0x07,  0xa5,  0xed,  0x03,  0xcd,  0x28,  0x8a,  0x03,  0x45,  0x28,  0x35,
-  0x67,  0x02,  0x72,  0xfe,  0xc0,  0x5d,  0xfe,  0xf8,  0x14,  0xfe,  0x03,  0x17,  0x03,  0x5c,  0xc1,  0x0c,
-  0x5c,  0x67,  0x2d,  0x01,  0x0b,  0x26,  0x89,  0x01,  0xfe,  0x9e,  0x15,  0x02,  0x89,  0x01,  0x0b,  0x1c,
-  0x34,  0x1d,  0x4c,  0x33,  0x31,  0xdf,  0x07,  0x06,  0x23,  0x4c,  0x01,  0xf1,  0xfe,  0x42,  0x58,  0xf1,
-  0xfe,  0xa4,  0x14,  0x8c,  0xfe,  0x4a,  0xf4,  0x0a,  0x17,  0x4c,  0xfe,  0x4a,  0xf4,  0x06,  0xea,  0x32,
-  0x07,  0xa5,  0x8b,  0x02,  0x72,  0x03,  0x45,  0xc1,  0x0c,  0x45,  0x67,  0x2d,  0x01,  0x0b,  0x26,  0x89,
-  0x01,  0xfe,  0xcc,  0x15,  0x02,  0x89,  0x0f,  0x06,  0x27,  0xfe,  0xbe,  0x13,  0x26,  0xfe,  0xd4,  0x13,
-  0x76,  0xfe,  0x89,  0x48,  0x01,  0x0b,  0x21,  0x76,  0x04,  0x7b,  0xfe,  0xd0,  0x13,  0x1c,  0xfe,  0xd0,
-  0x13,  0x1d,  0xfe,  0xbe,  0x13,  0x67,  0x2d,  0x01,  0x0b,  0xfe,  0xd5,  0x10,  0x0f,  0x71,  0xff,  0x02,
-  0x00,  0x57,  0x52,  0x93,  0x1e,  0xfe,  0xff,  0x7f,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x04,  0x0f,
-  0x71,  0xff,  0x02,  0x00,  0x57,  0x52,  0x93,  0x1e,  0x43,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x04,
-  0x0f,  0x71,  0xff,  0x02,  0x00,  0x57,  0x52,  0x93,  0x04,  0x0f,  0x71,  0xff,  0x02,  0x00,  0x57,  0x52,
-  0x93,  0xfe,  0x0b,  0x58,  0x04,  0x09,  0x5c,  0x01,  0x87,  0x09,  0x45,  0x01,  0x87,  0x04,  0xfe,  0x03,
-  0xa1,  0x1e,  0x11,  0xff,  0x03,  0x00,  0x54,  0xfe,  0x00,  0xf4,  0x1f,  0x52,  0xfe,  0x00,  0x7d,  0xfe,
-  0x01,  0x7d,  0xfe,  0x02,  0x7d,  0xfe,  0x03,  0x7c,  0x6a,  0x2a,  0x0c,  0x5e,  0x14,  0x5f,  0x57,  0x3f,
-  0x7d,  0x40,  0x04,  0xdd,  0xfe,  0x82,  0x4a,  0xfe,  0xe1,  0x1a,  0xfe,  0x83,  0x5a,  0x8d,  0x04,  0x01,
-  0xfe,  0x0c,  0x19,  0xfe,  0x42,  0x48,  0x50,  0x51,  0x91,  0x01,  0x0b,  0x1d,  0xfe,  0x96,  0x15,  0x33,
-  0x31,  0xe1,  0x01,  0x0b,  0x1d,  0xfe,  0x96,  0x15,  0x33,  0x31,  0xfe,  0xe8,  0x0a,  0xfe,  0xc1,  0x59,
-  0x03,  0xcd,  0x28,  0xfe,  0xcc,  0x12,  0x53,  0x05,  0x1a,  0xfe,  0xc4,  0x13,  0x21,  0x69,  0x1a,  0xee,
-  0x55,  0xca,  0x6b,  0xfe,  0xdc,  0x14,  0x4d,  0x0f,  0x06,  0x18,  0xca,  0x7c,  0x30,  0xfe,  0x78,  0x10,
-  0xff,  0x02,  0x83,  0x55,  0xab,  0xff,  0x02,  0x83,  0x55,  0x69,  0x19,  0xae,  0x98,  0xfe,  0x30,  0x00,
-  0x96,  0xf2,  0x18,  0x6d,  0x0f,  0x06,  0xfe,  0x56,  0x10,  0x69,  0x0a,  0xed,  0x98,  0xfe,  0x64,  0x00,
-  0x96,  0xf2,  0x09,  0xfe,  0x64,  0x00,  0x18,  0x9e,  0x0f,  0x06,  0xfe,  0x28,  0x10,  0x69,  0x06,  0xfe,
-  0x60,  0x13,  0x98,  0xfe,  0xc8,  0x00,  0x96,  0xf2,  0x09,  0xfe,  0xc8,  0x00,  0x18,  0x59,  0x0f,  0x06,
-  0x88,  0x98,  0xfe,  0x90,  0x01,  0x7a,  0xfe,  0x42,  0x15,  0x91,  0xe4,  0xfe,  0x43,  0xf4,  0x9f,  0xfe,
-  0x56,  0xf0,  0xfe,  0x54,  0x15,  0xfe,  0x04,  0xf4,  0x71,  0xfe,  0x43,  0xf4,  0x9e,  0xfe,  0xf3,  0x10,
-  0xfe,  0x40,  0x5c,  0x01,  0xfe,  0x16,  0x14,  0x1e,  0x43,  0xec,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,
-  0x6e,  0x7a,  0xfe,  0x90,  0x15,  0xc4,  0x6e,  0xfe,  0x1c,  0x10,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,
-  0xcc,  0x7a,  0xfe,  0x90,  0x15,  0xc4,  0xcc,  0x88,  0x51,  0x21,  0xfe,  0x4d,  0xf4,  0x00,  0xe9,  0x91,
-  0x0f,  0x06,  0xfe,  0xb4,  0x56,  0xfe,  0xc3,  0x58,  0x04,  0x51,  0x0f,  0x0a,  0x04,  0x16,  0x06,  0x01,
-  0x0b,  0x26,  0xf3,  0x16,  0x0a,  0x01,  0x0b,  0x26,  0xf3,  0x16,  0x19,  0x01,  0x0b,  0x26,  0xf3,  0x76,
-  0xfe,  0x89,  0x49,  0x01,  0x0b,  0x04,  0x16,  0x06,  0x01,  0x0b,  0x26,  0xb1,  0x16,  0x19,  0x01,  0x0b,
-  0x26,  0xb1,  0x16,  0x06,  0x01,  0x0b,  0x26,  0xb1,  0xfe,  0x89,  0x49,  0x01,  0x0b,  0x26,  0xb1,  0x76,
-  0xfe,  0x89,  0x4a,  0x01,  0x0b,  0x04,  0x51,  0x04,  0x22,  0xd3,  0x07,  0x06,  0xfe,  0x48,  0x13,  0xb8,
-  0x13,  0xd3,  0xfe,  0x49,  0xf4,  0x00,  0x4d,  0x76,  0xa9,  0x67,  0xfe,  0x01,  0xec,  0xfe,  0x27,  0x01,
-  0xfe,  0x89,  0x48,  0xff,  0x02,  0x00,  0x10,  0x27,  0xfe,  0x2e,  0x16,  0x32,  0x07,  0xfe,  0xe3,  0x00,
-  0xfe,  0x20,  0x13,  0x1d,  0xfe,  0x52,  0x16,  0x21,  0x13,  0xd4,  0x01,  0x4b,  0x22,  0xd4,  0x07,  0x06,
-  0x4e,  0x08,  0x54,  0x06,  0x37,  0x04,  0x09,  0x48,  0x01,  0x0e,  0xfb,  0x8e,  0x07,  0x11,  0xae,  0x09,
-  0x84,  0x01,  0x0e,  0x8e,  0x09,  0x5d,  0x01,  0xa8,  0x04,  0x09,  0x84,  0x01,  0x0e,  0x8e,  0xfe,  0x80,
-  0xe7,  0x11,  0x07,  0x11,  0x8a,  0xfe,  0x45,  0x58,  0x01,  0xf0,  0x8e,  0x04,  0x09,  0x48,  0x01,  0x0e,
-  0x8e,  0x09,  0x5d,  0x01,  0xa8,  0x04,  0x09,  0x48,  0x01,  0x0e,  0xfe,  0x80,  0x80,  0xfe,  0x80,  0x4c,
-  0xfe,  0x49,  0xe4,  0x11,  0xae,  0x09,  0x84,  0x01,  0x0e,  0xfe,  0x80,  0x4c,  0x09,  0x5d,  0x01,  0x87,
-  0x04,  0x18,  0x11,  0x75,  0x6c,  0xfe,  0x60,  0x01,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x24,
-  0x1c,  0xfe,  0x1d,  0xf7,  0x1b,  0x97,  0xfe,  0xee,  0x16,  0x01,  0xfe,  0xf4,  0x17,  0xad,  0x9a,  0x1b,
-  0x6c,  0xfe,  0x2c,  0x01,  0xfe,  0x2f,  0x19,  0x04,  0xb9,  0x23,  0xfe,  0xde,  0x16,  0xfe,  0xda,  0x10,
-  0x18,  0x11,  0x75,  0x03,  0xfe,  0x64,  0x01,  0xfe,  0x00,  0xf4,  0x1f,  0xfe,  0x18,  0x58,  0x03,  0xfe,
-  0x66,  0x01,  0xfe,  0x19,  0x58,  0x9a,  0x1f,  0xfe,  0x3c,  0x90,  0xfe,  0x30,  0xf4,  0x06,  0xfe,  0x3c,
-  0x50,  0x6c,  0xfe,  0x38,  0x00,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0x1f,  0x97,  0xfe,  0x38,  0x17,
-  0xfe,  0xb6,  0x14,  0x35,  0x04,  0xb9,  0x23,  0xfe,  0x10,  0x17,  0xfe,  0x9c,  0x10,  0x18,  0x11,  0x75,
-  0xfe,  0x83,  0x5a,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x1d,  0xf7,  0x2e,  0x97,  0xfe,  0x5a,
-  0x17,  0xfe,  0x94,  0x14,  0xec,  0x9a,  0x2e,  0x6c,  0x1a,  0xfe,  0xaf,  0x19,  0xfe,  0x98,  0xe7,  0x00,
-  0x04,  0xb9,  0x23,  0xfe,  0x4e,  0x17,  0xfe,  0x6c,  0x10,  0x18,  0x11,  0x75,  0xfe,  0x30,  0xbc,  0xfe,
-  0xb2,  0xbc,  0x9a,  0xcb,  0x6c,  0x1a,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0xcb,  0x97,  0xfe,  0x92,
-  0x17,  0xfe,  0x5c,  0x14,  0x35,  0x04,  0xb9,  0x23,  0xfe,  0x7e,  0x17,  0xfe,  0x42,  0x10,  0xfe,  0x02,
-  0xf6,  0x11,  0x75,  0xfe,  0x18,  0xfe,  0x60,  0xfe,  0x19,  0xfe,  0x61,  0xfe,  0x03,  0xa1,  0xfe,  0x1d,
-  0xf7,  0x5b,  0x97,  0xfe,  0xb8,  0x17,  0xfe,  0x36,  0x14,  0xfe,  0x1c,  0x13,  0x9a,  0x5b,  0x41,  0xfe,
-  0x83,  0x58,  0xfe,  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x11,  0xfe,  0x81,  0xe7,  0x11,  0x12,  0xfe,  0xdd,
-  0x00,  0x6a,  0x2a,  0x04,  0x6a,  0x2a,  0xfe,  0x12,  0x45,  0x23,  0xfe,  0xa8,  0x17,  0x15,  0x06,  0x39,
-  0xa0,  0xb4,  0x02,  0x2b,  0xfe,  0x39,  0xf0,  0xfe,  0xfc,  0x17,  0x21,  0x04,  0xfe,  0x7e,  0x18,  0x1e,
-  0x19,  0x66,  0x0f,  0x0d,  0x04,  0x75,  0x03,  0xd2,  0x1e,  0x06,  0xfe,  0xef,  0x12,  0xfe,  0xe1,  0x10,
-  0x7c,  0x6f,  0x4f,  0x32,  0x07,  0x2f,  0xfe,  0x3c,  0x13,  0xf1,  0xfe,  0x42,  0x13,  0x42,  0x92,  0x09,
-  0x48,  0x01,  0x0e,  0xbb,  0xeb,  0xfe,  0x41,  0x48,  0xfe,  0x45,  0x48,  0x01,  0xf0,  0xfe,  0x00,  0xcc,
-  0xbb,  0xfe,  0xf3,  0x13,  0x43,  0x78,  0x07,  0x11,  0xac,  0x09,  0x84,  0x01,  0x0e,  0xfe,  0x80,  0x4c,
-  0x01,  0x73,  0xfe,  0x16,  0x10,  0x07,  0x82,  0x8b,  0xfe,  0x40,  0x14,  0xfe,  0x24,  0x12,  0xfe,  0x14,
-  0x56,  0xfe,  0xd6,  0xf0,  0xfe,  0x1c,  0x18,  0x18,  0x0a,  0x04,  0xfe,  0x9c,  0xe7,  0x0a,  0x10,  0xfe,
-  0x15,  0x00,  0x64,  0x79,  0x2a,  0x01,  0xe3,  0x18,  0x06,  0x04,  0x42,  0x92,  0x08,  0x54,  0x1b,  0x37,
-  0x12,  0x2f,  0x01,  0x73,  0x18,  0x06,  0x04,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,  0x3a,  0xce,  0x3b,
-  0xcf,  0xfe,  0x48,  0x55,  0x35,  0xfe,  0xc9,  0x55,  0x04,  0x22,  0xa3,  0x77,  0x13,  0xa3,  0x04,  0x09,
-  0xa4,  0x01,  0x0e,  0xfe,  0x41,  0x48,  0x09,  0x46,  0x01,  0x0e,  0xfe,  0x49,  0x44,  0x17,  0xfe,  0xe8,
-  0x18,  0x77,  0x78,  0x04,  0x09,  0x48,  0x01,  0x0e,  0x07,  0x11,  0x4e,  0x09,  0x5d,  0x01,  0xa8,  0x09,
-  0x46,  0x01,  0x0e,  0x77,  0x78,  0x04,  0xfe,  0x4e,  0xe4,  0x19,  0x6b,  0xfe,  0x1c,  0x19,  0x03,  0xfe,
-  0x90,  0x00,  0xfe,  0x3a,  0x45,  0xfe,  0x2c,  0x10,  0xfe,  0x4e,  0xe4,  0xc9,  0x6b,  0xfe,  0x2e,  0x19,
-  0x03,  0xfe,  0x92,  0x00,  0xfe,  0x02,  0xe6,  0x1a,  0xe5,  0xfe,  0x4e,  0xe4,  0xfe,  0x0b,  0x00,  0x6b,
-  0xfe,  0x40,  0x19,  0x03,  0xfe,  0x94,  0x00,  0xfe,  0x02,  0xe6,  0x1f,  0xfe,  0x08,  0x10,  0x03,  0xfe,
-  0x96,  0x00,  0xfe,  0x02,  0xe6,  0x6d,  0xfe,  0x4e,  0x45,  0xea,  0xba,  0xff,  0x04,  0x68,  0x54,  0xe7,
-  0x1e,  0x6e,  0xfe,  0x08,  0x1c,  0xfe,  0x67,  0x19,  0xfe,  0x0a,  0x1c,  0xfe,  0x1a,  0xf4,  0xfe,  0x00,
-  0x04,  0xea,  0xfe,  0x48,  0xf4,  0x19,  0x7a,  0xfe,  0x74,  0x19,  0x0f,  0x19,  0x04,  0x07,  0x7e,  0xfe,
-  0x5a,  0xf0,  0xfe,  0x84,  0x19,  0x25,  0xfe,  0x09,  0x00,  0xfe,  0x34,  0x10,  0x07,  0x1a,  0xfe,  0x5a,
-  0xf0,  0xfe,  0x92,  0x19,  0x25,  0xca,  0xfe,  0x26,  0x10,  0x07,  0x19,  0x66,  0x25,  0x6d,  0xe5,  0x07,
-  0x0a,  0x66,  0x25,  0x9e,  0xfe,  0x0e,  0x10,  0x07,  0x06,  0x66,  0x25,  0x59,  0xa9,  0xb8,  0x04,  0x15,
-  0xfe,  0x09,  0x00,  0x01,  0x36,  0xfe,  0x04,  0xfe,  0x81,  0x03,  0x83,  0xfe,  0x40,  0x5c,  0x04,  0x1c,
-  0xf7,  0xfe,  0x14,  0xf0,  0x0b,  0x27,  0xfe,  0xd6,  0x19,  0x1c,  0xf7,  0x7b,  0xf7,  0xfe,  0x82,  0xf0,
-  0xfe,  0xda,  0x19,  0x04,  0xff,  0xcc,  0x00,  0x00,
+	0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58, 0x03, 0xfe,
+	0xb2, 0x00, 0xfe, 0x09,
+	0x58, 0xfe, 0x0a, 0x1c, 0x25, 0x6e, 0x13, 0xd0, 0x21, 0x0c, 0x5c, 0x0c,
+	0x45, 0x0f, 0x46, 0x52,
+	0x50, 0x18, 0x1b, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xfe, 0xfc,
+	0x0f, 0x44, 0x11, 0x0f,
+	0x48, 0x52, 0x18, 0x58, 0xfe, 0x90, 0x4d, 0xfe, 0x91, 0x54, 0x23, 0xe4,
+	0x25, 0x11, 0x13, 0x20,
+	0x7c, 0x6f, 0x4f, 0x22, 0x20, 0xfb, 0x79, 0x20, 0x12, 0xcf, 0xfe, 0x14,
+	0x56, 0xfe, 0xd6, 0xf0,
+	0xfe, 0x26, 0x10, 0xf8, 0x74, 0xfe, 0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe,
+	0x18, 0x1c, 0x04, 0x42,
+	0xfe, 0x0c, 0x14, 0xfc, 0xfe, 0x07, 0xe6, 0x1b, 0xfe, 0xce, 0x47, 0xfe,
+	0xf5, 0x13, 0x04, 0x01,
+	0xb0, 0x7c, 0x6f, 0x4f, 0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42,
+	0x13, 0x32, 0x07, 0x2f,
+	0xfe, 0x34, 0x13, 0x09, 0x48, 0x01, 0x0e, 0xbb, 0xfe, 0x36, 0x12, 0xfe,
+	0x41, 0x48, 0xfe, 0x45,
+	0x48, 0x01, 0xf0, 0xfe, 0x00, 0xcc, 0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78,
+	0x07, 0x11, 0xac, 0x09,
+	0x84, 0x01, 0x0e, 0xfe, 0x80, 0x5c, 0x01, 0x73, 0xfe, 0x0e, 0x10, 0x07,
+	0x82, 0x4e, 0xfe, 0x14,
+	0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x60, 0x10, 0x04, 0xfe, 0x44, 0x58, 0x8d,
+	0xfe, 0x01, 0xec, 0xa2,
+	0xfe, 0x9e, 0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x1a, 0x79,
+	0x2a, 0x01, 0xe3, 0xfe,
+	0xdd, 0x10, 0x2c, 0xc7, 0x81, 0xc8, 0x83, 0x33, 0x31, 0xde, 0x07, 0x1a,
+	0xfe, 0x48, 0x12, 0x07,
+	0x0a, 0xfe, 0x56, 0x12, 0x07, 0x19, 0xfe, 0x30, 0x12, 0x07, 0xc9, 0x17,
+	0xfe, 0x32, 0x12, 0x07,
+	0xfe, 0x23, 0x00, 0x17, 0xeb, 0x07, 0x06, 0x17, 0xfe, 0x9c, 0x12, 0x07,
+	0x1f, 0xfe, 0x12, 0x12,
+	0x07, 0x00, 0x17, 0x24, 0x15, 0xc9, 0x01, 0x36, 0xa9, 0x2d, 0x01, 0x0b,
+	0x94, 0x4b, 0x04, 0x2d,
+	0xdd, 0x09, 0xd1, 0x01, 0xfe, 0x26, 0x0f, 0x12, 0x82, 0x02, 0x2b, 0x2d,
+	0x32, 0x07, 0xa6, 0xfe,
+	0xd9, 0x13, 0x3a, 0x3d, 0x3b, 0x3e, 0x56, 0xfe, 0xf0, 0x11, 0x08, 0x05,
+	0x5a, 0xfe, 0x72, 0x12,
+	0x9b, 0x2e, 0x9c, 0x3c, 0x90, 0xc0, 0x96, 0xfe, 0xba, 0x11, 0x22, 0x62,
+	0xfe, 0x26, 0x13, 0x03,
+	0x7f, 0x29, 0x80, 0x56, 0xfe, 0x76, 0x0d, 0x0c, 0x60, 0x14, 0x61, 0x21,
+	0x0c, 0x7f, 0x0c, 0x80,
+	0x01, 0xb3, 0x25, 0x6e, 0x77, 0x13, 0x62, 0x01, 0xef, 0x9b, 0x2e, 0x9c,
+	0x3c, 0xfe, 0x04, 0x55,
+	0xfe, 0xa5, 0x55, 0xfe, 0x04, 0xfa, 0x2e, 0xfe, 0x05, 0xfa, 0x3c, 0xfe,
+	0x91, 0x10, 0x03, 0x3f,
+	0x29, 0x40, 0xfe, 0x40, 0x56, 0xfe, 0xe1, 0x56, 0x0c, 0x3f, 0x14, 0x40,
+	0x88, 0x9b, 0x2e, 0x9c,
+	0x3c, 0x90, 0xc0, 0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x00, 0x56, 0xfe, 0xa1,
+	0x56, 0x0c, 0x5e, 0x14,
+	0x5f, 0x08, 0x05, 0x5a, 0xfe, 0x1e, 0x12, 0x22, 0x62, 0xfe, 0x1f, 0x40,
+	0x03, 0x60, 0x29, 0x61,
+	0xfe, 0x2c, 0x50, 0xfe, 0xae, 0x50, 0x03, 0x3f, 0x29, 0x40, 0xfe, 0x44,
+	0x50, 0xfe, 0xc6, 0x50,
+	0x03, 0x5e, 0x29, 0x5f, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x3d,
+	0x29, 0x3e, 0xfe, 0x40,
+	0x50, 0xfe, 0xc2, 0x50, 0x02, 0x89, 0x25, 0x06, 0x13, 0xd4, 0x02, 0x72,
+	0x2d, 0x01, 0x0b, 0x1d,
+	0x4c, 0x33, 0x31, 0xde, 0x07, 0x06, 0x23, 0x4c, 0x32, 0x07, 0xa6, 0x23,
+	0x72, 0x01, 0xaf, 0x1e,
+	0x43, 0x17, 0x4c, 0x08, 0x05, 0x0a, 0xee, 0x3a, 0x3d, 0x3b, 0x3e, 0xfe,
+	0x0a, 0x55, 0x35, 0xfe,
+	0x8b, 0x55, 0x57, 0x3d, 0x7d, 0x3e, 0xfe, 0x0c, 0x51, 0xfe, 0x8e, 0x51,
+	0x02, 0x72, 0xfe, 0x19,
+	0x81, 0xba, 0xfe, 0x19, 0x41, 0x02, 0x72, 0x2d, 0x01, 0x0b, 0x1c, 0x34,
+	0x1d, 0xe8, 0x33, 0x31,
+	0xe1, 0x55, 0x19, 0xfe, 0xa6, 0x12, 0x55, 0x0a, 0x4d, 0x02, 0x4c, 0x01,
+	0x0b, 0x1c, 0x34, 0x1d,
+	0xe8, 0x33, 0x31, 0xdf, 0x07, 0x19, 0x23, 0x4c, 0x01, 0x0b, 0x1d, 0xe8,
+	0x33, 0x31, 0xfe, 0xe8,
+	0x09, 0xfe, 0xc2, 0x49, 0x51, 0x03, 0xfe, 0x9c, 0x00, 0x28, 0x8a, 0x53,
+	0x05, 0x1f, 0x35, 0xa9,
+	0xfe, 0xbb, 0x45, 0x55, 0x00, 0x4e, 0x44, 0x06, 0x7c, 0x43, 0xfe, 0xda,
+	0x14, 0x01, 0xaf, 0x8c,
+	0xfe, 0x4b, 0x45, 0xee, 0x32, 0x07, 0xa5, 0xed, 0x03, 0xcd, 0x28, 0x8a,
+	0x03, 0x45, 0x28, 0x35,
+	0x67, 0x02, 0x72, 0xfe, 0xc0, 0x5d, 0xfe, 0xf8, 0x14, 0xfe, 0x03, 0x17,
+	0x03, 0x5c, 0xc1, 0x0c,
+	0x5c, 0x67, 0x2d, 0x01, 0x0b, 0x26, 0x89, 0x01, 0xfe, 0x9e, 0x15, 0x02,
+	0x89, 0x01, 0x0b, 0x1c,
+	0x34, 0x1d, 0x4c, 0x33, 0x31, 0xdf, 0x07, 0x06, 0x23, 0x4c, 0x01, 0xf1,
+	0xfe, 0x42, 0x58, 0xf1,
+	0xfe, 0xa4, 0x14, 0x8c, 0xfe, 0x4a, 0xf4, 0x0a, 0x17, 0x4c, 0xfe, 0x4a,
+	0xf4, 0x06, 0xea, 0x32,
+	0x07, 0xa5, 0x8b, 0x02, 0x72, 0x03, 0x45, 0xc1, 0x0c, 0x45, 0x67, 0x2d,
+	0x01, 0x0b, 0x26, 0x89,
+	0x01, 0xfe, 0xcc, 0x15, 0x02, 0x89, 0x0f, 0x06, 0x27, 0xfe, 0xbe, 0x13,
+	0x26, 0xfe, 0xd4, 0x13,
+	0x76, 0xfe, 0x89, 0x48, 0x01, 0x0b, 0x21, 0x76, 0x04, 0x7b, 0xfe, 0xd0,
+	0x13, 0x1c, 0xfe, 0xd0,
+	0x13, 0x1d, 0xfe, 0xbe, 0x13, 0x67, 0x2d, 0x01, 0x0b, 0xfe, 0xd5, 0x10,
+	0x0f, 0x71, 0xff, 0x02,
+	0x00, 0x57, 0x52, 0x93, 0x1e, 0xfe, 0xff, 0x7f, 0xfe, 0x30, 0x56, 0xfe,
+	0x00, 0x5c, 0x04, 0x0f,
+	0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x1e, 0x43, 0xfe, 0x30, 0x56,
+	0xfe, 0x00, 0x5c, 0x04,
+	0x0f, 0x71, 0xff, 0x02, 0x00, 0x57, 0x52, 0x93, 0x04, 0x0f, 0x71, 0xff,
+	0x02, 0x00, 0x57, 0x52,
+	0x93, 0xfe, 0x0b, 0x58, 0x04, 0x09, 0x5c, 0x01, 0x87, 0x09, 0x45, 0x01,
+	0x87, 0x04, 0xfe, 0x03,
+	0xa1, 0x1e, 0x11, 0xff, 0x03, 0x00, 0x54, 0xfe, 0x00, 0xf4, 0x1f, 0x52,
+	0xfe, 0x00, 0x7d, 0xfe,
+	0x01, 0x7d, 0xfe, 0x02, 0x7d, 0xfe, 0x03, 0x7c, 0x6a, 0x2a, 0x0c, 0x5e,
+	0x14, 0x5f, 0x57, 0x3f,
+	0x7d, 0x40, 0x04, 0xdd, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83,
+	0x5a, 0x8d, 0x04, 0x01,
+	0xfe, 0x0c, 0x19, 0xfe, 0x42, 0x48, 0x50, 0x51, 0x91, 0x01, 0x0b, 0x1d,
+	0xfe, 0x96, 0x15, 0x33,
+	0x31, 0xe1, 0x01, 0x0b, 0x1d, 0xfe, 0x96, 0x15, 0x33, 0x31, 0xfe, 0xe8,
+	0x0a, 0xfe, 0xc1, 0x59,
+	0x03, 0xcd, 0x28, 0xfe, 0xcc, 0x12, 0x53, 0x05, 0x1a, 0xfe, 0xc4, 0x13,
+	0x21, 0x69, 0x1a, 0xee,
+	0x55, 0xca, 0x6b, 0xfe, 0xdc, 0x14, 0x4d, 0x0f, 0x06, 0x18, 0xca, 0x7c,
+	0x30, 0xfe, 0x78, 0x10,
+	0xff, 0x02, 0x83, 0x55, 0xab, 0xff, 0x02, 0x83, 0x55, 0x69, 0x19, 0xae,
+	0x98, 0xfe, 0x30, 0x00,
+	0x96, 0xf2, 0x18, 0x6d, 0x0f, 0x06, 0xfe, 0x56, 0x10, 0x69, 0x0a, 0xed,
+	0x98, 0xfe, 0x64, 0x00,
+	0x96, 0xf2, 0x09, 0xfe, 0x64, 0x00, 0x18, 0x9e, 0x0f, 0x06, 0xfe, 0x28,
+	0x10, 0x69, 0x06, 0xfe,
+	0x60, 0x13, 0x98, 0xfe, 0xc8, 0x00, 0x96, 0xf2, 0x09, 0xfe, 0xc8, 0x00,
+	0x18, 0x59, 0x0f, 0x06,
+	0x88, 0x98, 0xfe, 0x90, 0x01, 0x7a, 0xfe, 0x42, 0x15, 0x91, 0xe4, 0xfe,
+	0x43, 0xf4, 0x9f, 0xfe,
+	0x56, 0xf0, 0xfe, 0x54, 0x15, 0xfe, 0x04, 0xf4, 0x71, 0xfe, 0x43, 0xf4,
+	0x9e, 0xfe, 0xf3, 0x10,
+	0xfe, 0x40, 0x5c, 0x01, 0xfe, 0x16, 0x14, 0x1e, 0x43, 0xec, 0xfe, 0x00,
+	0x17, 0xfe, 0x4d, 0xe4,
+	0x6e, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0x6e, 0xfe, 0x1c, 0x10, 0xfe, 0x00,
+	0x17, 0xfe, 0x4d, 0xe4,
+	0xcc, 0x7a, 0xfe, 0x90, 0x15, 0xc4, 0xcc, 0x88, 0x51, 0x21, 0xfe, 0x4d,
+	0xf4, 0x00, 0xe9, 0x91,
+	0x0f, 0x06, 0xfe, 0xb4, 0x56, 0xfe, 0xc3, 0x58, 0x04, 0x51, 0x0f, 0x0a,
+	0x04, 0x16, 0x06, 0x01,
+	0x0b, 0x26, 0xf3, 0x16, 0x0a, 0x01, 0x0b, 0x26, 0xf3, 0x16, 0x19, 0x01,
+	0x0b, 0x26, 0xf3, 0x76,
+	0xfe, 0x89, 0x49, 0x01, 0x0b, 0x04, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1,
+	0x16, 0x19, 0x01, 0x0b,
+	0x26, 0xb1, 0x16, 0x06, 0x01, 0x0b, 0x26, 0xb1, 0xfe, 0x89, 0x49, 0x01,
+	0x0b, 0x26, 0xb1, 0x76,
+	0xfe, 0x89, 0x4a, 0x01, 0x0b, 0x04, 0x51, 0x04, 0x22, 0xd3, 0x07, 0x06,
+	0xfe, 0x48, 0x13, 0xb8,
+	0x13, 0xd3, 0xfe, 0x49, 0xf4, 0x00, 0x4d, 0x76, 0xa9, 0x67, 0xfe, 0x01,
+	0xec, 0xfe, 0x27, 0x01,
+	0xfe, 0x89, 0x48, 0xff, 0x02, 0x00, 0x10, 0x27, 0xfe, 0x2e, 0x16, 0x32,
+	0x07, 0xfe, 0xe3, 0x00,
+	0xfe, 0x20, 0x13, 0x1d, 0xfe, 0x52, 0x16, 0x21, 0x13, 0xd4, 0x01, 0x4b,
+	0x22, 0xd4, 0x07, 0x06,
+	0x4e, 0x08, 0x54, 0x06, 0x37, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfb, 0x8e,
+	0x07, 0x11, 0xae, 0x09,
+	0x84, 0x01, 0x0e, 0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x84, 0x01,
+	0x0e, 0x8e, 0xfe, 0x80,
+	0xe7, 0x11, 0x07, 0x11, 0x8a, 0xfe, 0x45, 0x58, 0x01, 0xf0, 0x8e, 0x04,
+	0x09, 0x48, 0x01, 0x0e,
+	0x8e, 0x09, 0x5d, 0x01, 0xa8, 0x04, 0x09, 0x48, 0x01, 0x0e, 0xfe, 0x80,
+	0x80, 0xfe, 0x80, 0x4c,
+	0xfe, 0x49, 0xe4, 0x11, 0xae, 0x09, 0x84, 0x01, 0x0e, 0xfe, 0x80, 0x4c,
+	0x09, 0x5d, 0x01, 0x87,
+	0x04, 0x18, 0x11, 0x75, 0x6c, 0xfe, 0x60, 0x01, 0xfe, 0x18, 0xdf, 0xfe,
+	0x19, 0xde, 0xfe, 0x24,
+	0x1c, 0xfe, 0x1d, 0xf7, 0x1b, 0x97, 0xfe, 0xee, 0x16, 0x01, 0xfe, 0xf4,
+	0x17, 0xad, 0x9a, 0x1b,
+	0x6c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x04, 0xb9, 0x23, 0xfe, 0xde,
+	0x16, 0xfe, 0xda, 0x10,
+	0x18, 0x11, 0x75, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x1f, 0xfe,
+	0x18, 0x58, 0x03, 0xfe,
+	0x66, 0x01, 0xfe, 0x19, 0x58, 0x9a, 0x1f, 0xfe, 0x3c, 0x90, 0xfe, 0x30,
+	0xf4, 0x06, 0xfe, 0x3c,
+	0x50, 0x6c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7, 0x1f,
+	0x97, 0xfe, 0x38, 0x17,
+	0xfe, 0xb6, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x10, 0x17, 0xfe, 0x9c,
+	0x10, 0x18, 0x11, 0x75,
+	0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe, 0x1d, 0xf7,
+	0x2e, 0x97, 0xfe, 0x5a,
+	0x17, 0xfe, 0x94, 0x14, 0xec, 0x9a, 0x2e, 0x6c, 0x1a, 0xfe, 0xaf, 0x19,
+	0xfe, 0x98, 0xe7, 0x00,
+	0x04, 0xb9, 0x23, 0xfe, 0x4e, 0x17, 0xfe, 0x6c, 0x10, 0x18, 0x11, 0x75,
+	0xfe, 0x30, 0xbc, 0xfe,
+	0xb2, 0xbc, 0x9a, 0xcb, 0x6c, 0x1a, 0xfe, 0x0f, 0x79, 0xfe, 0x1c, 0xf7,
+	0xcb, 0x97, 0xfe, 0x92,
+	0x17, 0xfe, 0x5c, 0x14, 0x35, 0x04, 0xb9, 0x23, 0xfe, 0x7e, 0x17, 0xfe,
+	0x42, 0x10, 0xfe, 0x02,
+	0xf6, 0x11, 0x75, 0xfe, 0x18, 0xfe, 0x60, 0xfe, 0x19, 0xfe, 0x61, 0xfe,
+	0x03, 0xa1, 0xfe, 0x1d,
+	0xf7, 0x5b, 0x97, 0xfe, 0xb8, 0x17, 0xfe, 0x36, 0x14, 0xfe, 0x1c, 0x13,
+	0x9a, 0x5b, 0x41, 0xfe,
+	0x83, 0x58, 0xfe, 0xaf, 0x19, 0xfe, 0x80, 0xe7, 0x11, 0xfe, 0x81, 0xe7,
+	0x11, 0x12, 0xfe, 0xdd,
+	0x00, 0x6a, 0x2a, 0x04, 0x6a, 0x2a, 0xfe, 0x12, 0x45, 0x23, 0xfe, 0xa8,
+	0x17, 0x15, 0x06, 0x39,
+	0xa0, 0xb4, 0x02, 0x2b, 0xfe, 0x39, 0xf0, 0xfe, 0xfc, 0x17, 0x21, 0x04,
+	0xfe, 0x7e, 0x18, 0x1e,
+	0x19, 0x66, 0x0f, 0x0d, 0x04, 0x75, 0x03, 0xd2, 0x1e, 0x06, 0xfe, 0xef,
+	0x12, 0xfe, 0xe1, 0x10,
+	0x7c, 0x6f, 0x4f, 0x32, 0x07, 0x2f, 0xfe, 0x3c, 0x13, 0xf1, 0xfe, 0x42,
+	0x13, 0x42, 0x92, 0x09,
+	0x48, 0x01, 0x0e, 0xbb, 0xeb, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01,
+	0xf0, 0xfe, 0x00, 0xcc,
+	0xbb, 0xfe, 0xf3, 0x13, 0x43, 0x78, 0x07, 0x11, 0xac, 0x09, 0x84, 0x01,
+	0x0e, 0xfe, 0x80, 0x4c,
+	0x01, 0x73, 0xfe, 0x16, 0x10, 0x07, 0x82, 0x8b, 0xfe, 0x40, 0x14, 0xfe,
+	0x24, 0x12, 0xfe, 0x14,
+	0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0x1c, 0x18, 0x18, 0x0a, 0x04, 0xfe, 0x9c,
+	0xe7, 0x0a, 0x10, 0xfe,
+	0x15, 0x00, 0x64, 0x79, 0x2a, 0x01, 0xe3, 0x18, 0x06, 0x04, 0x42, 0x92,
+	0x08, 0x54, 0x1b, 0x37,
+	0x12, 0x2f, 0x01, 0x73, 0x18, 0x06, 0x04, 0xfe, 0x38, 0x90, 0xfe, 0xba,
+	0x90, 0x3a, 0xce, 0x3b,
+	0xcf, 0xfe, 0x48, 0x55, 0x35, 0xfe, 0xc9, 0x55, 0x04, 0x22, 0xa3, 0x77,
+	0x13, 0xa3, 0x04, 0x09,
+	0xa4, 0x01, 0x0e, 0xfe, 0x41, 0x48, 0x09, 0x46, 0x01, 0x0e, 0xfe, 0x49,
+	0x44, 0x17, 0xfe, 0xe8,
+	0x18, 0x77, 0x78, 0x04, 0x09, 0x48, 0x01, 0x0e, 0x07, 0x11, 0x4e, 0x09,
+	0x5d, 0x01, 0xa8, 0x09,
+	0x46, 0x01, 0x0e, 0x77, 0x78, 0x04, 0xfe, 0x4e, 0xe4, 0x19, 0x6b, 0xfe,
+	0x1c, 0x19, 0x03, 0xfe,
+	0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe, 0x4e, 0xe4, 0xc9,
+	0x6b, 0xfe, 0x2e, 0x19,
+	0x03, 0xfe, 0x92, 0x00, 0xfe, 0x02, 0xe6, 0x1a, 0xe5, 0xfe, 0x4e, 0xe4,
+	0xfe, 0x0b, 0x00, 0x6b,
+	0xfe, 0x40, 0x19, 0x03, 0xfe, 0x94, 0x00, 0xfe, 0x02, 0xe6, 0x1f, 0xfe,
+	0x08, 0x10, 0x03, 0xfe,
+	0x96, 0x00, 0xfe, 0x02, 0xe6, 0x6d, 0xfe, 0x4e, 0x45, 0xea, 0xba, 0xff,
+	0x04, 0x68, 0x54, 0xe7,
+	0x1e, 0x6e, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c, 0xfe,
+	0x1a, 0xf4, 0xfe, 0x00,
+	0x04, 0xea, 0xfe, 0x48, 0xf4, 0x19, 0x7a, 0xfe, 0x74, 0x19, 0x0f, 0x19,
+	0x04, 0x07, 0x7e, 0xfe,
+	0x5a, 0xf0, 0xfe, 0x84, 0x19, 0x25, 0xfe, 0x09, 0x00, 0xfe, 0x34, 0x10,
+	0x07, 0x1a, 0xfe, 0x5a,
+	0xf0, 0xfe, 0x92, 0x19, 0x25, 0xca, 0xfe, 0x26, 0x10, 0x07, 0x19, 0x66,
+	0x25, 0x6d, 0xe5, 0x07,
+	0x0a, 0x66, 0x25, 0x9e, 0xfe, 0x0e, 0x10, 0x07, 0x06, 0x66, 0x25, 0x59,
+	0xa9, 0xb8, 0x04, 0x15,
+	0xfe, 0x09, 0x00, 0x01, 0x36, 0xfe, 0x04, 0xfe, 0x81, 0x03, 0x83, 0xfe,
+	0x40, 0x5c, 0x04, 0x1c,
+	0xf7, 0xfe, 0x14, 0xf0, 0x0b, 0x27, 0xfe, 0xd6, 0x19, 0x1c, 0xf7, 0x7b,
+	0xf7, 0xfe, 0x82, 0xf0,
+	0xfe, 0xda, 0x19, 0x04, 0xff, 0xcc, 0x00, 0x00,
 };
 
-STATIC unsigned short _adv_asc38C0800_size =
-        sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
-STATIC ADV_DCNT _adv_asc38C0800_chksum =
-        0x050D3FD8UL; /* Expanded little-endian checksum. */
+static unsigned short _adv_asc38C0800_size = sizeof(_adv_asc38C0800_buf);	/* 0x14E1 */
+static ADV_DCNT _adv_asc38C0800_chksum = 0x050D3FD8UL;	/* Expanded little-endian checksum. */
 
 /* Microcode buffer is kept after initialization for error recovery. */
-STATIC unsigned char _adv_asc38C1600_buf[] = {
-  0x00,  0x00,  0x00,  0xf2,  0x00,  0x16,  0x00,  0xfc,  0x00,  0x10,  0x00,  0xf0,  0x18,  0xe4,  0x01,  0x00,
-  0x04,  0x1e,  0x48,  0xe4,  0x03,  0xf6,  0xf7,  0x13,  0x2e,  0x1e,  0x02,  0x00,  0x07,  0x17,  0xc0,  0x5f,
-  0x00,  0xfa,  0xff,  0xff,  0x04,  0x00,  0x00,  0xf6,  0x09,  0xe7,  0x82,  0xe7,  0x85,  0xf0,  0x86,  0xf0,
-  0x4e,  0x10,  0x9e,  0xe7,  0xff,  0x00,  0x55,  0xf0,  0x01,  0xf6,  0x03,  0x00,  0x98,  0x57,  0x01,  0xe6,
-  0x00,  0xea,  0x00,  0xec,  0x01,  0xfa,  0x18,  0xf4,  0x08,  0x00,  0xf0,  0x1d,  0x38,  0x54,  0x32,  0xf0,
-  0x10,  0x00,  0xc2,  0x0e,  0x1e,  0xf0,  0xd5,  0xf0,  0xbc,  0x00,  0x4b,  0xe4,  0x00,  0xe6,  0xb1,  0xf0,
-  0xb4,  0x00,  0x02,  0x13,  0x3e,  0x1c,  0xc8,  0x47,  0x3e,  0x00,  0xd8,  0x01,  0x06,  0x13,  0x0c,  0x1c,
-  0x5e,  0x1e,  0x00,  0x57,  0xc8,  0x57,  0x01,  0xfc,  0xbc,  0x0e,  0xa2,  0x12,  0xb9,  0x54,  0x00,  0x80,
-  0x62,  0x0a,  0x5a,  0x12,  0xc8,  0x15,  0x3e,  0x1e,  0x18,  0x40,  0xbd,  0x56,  0x03,  0xe6,  0x01,  0xea,
-  0x5c,  0xf0,  0x0f,  0x00,  0x20,  0x00,  0x6c,  0x01,  0x6e,  0x01,  0x04,  0x12,  0x04,  0x13,  0xbb,  0x55,
-  0x3c,  0x56,  0x3e,  0x57,  0x03,  0x58,  0x4a,  0xe4,  0x40,  0x00,  0xb6,  0x00,  0xbb,  0x00,  0xc0,  0x00,
-  0x00,  0x01,  0x01,  0x01,  0x3e,  0x01,  0x58,  0x0a,  0x44,  0x10,  0x0a,  0x12,  0x4c,  0x1c,  0x4e,  0x1c,
-  0x02,  0x4a,  0x30,  0xe4,  0x05,  0xe6,  0x0c,  0x00,  0x3c,  0x00,  0x80,  0x00,  0x24,  0x01,  0x3c,  0x01,
-  0x68,  0x01,  0x6a,  0x01,  0x70,  0x01,  0x72,  0x01,  0x74,  0x01,  0x76,  0x01,  0x78,  0x01,  0x7c,  0x01,
-  0xc6,  0x0e,  0x0c,  0x10,  0xac,  0x12,  0xae,  0x12,  0x16,  0x1a,  0x32,  0x1c,  0x6e,  0x1e,  0x02,  0x48,
-  0x3a,  0x55,  0xc9,  0x57,  0x02,  0xee,  0x5b,  0xf0,  0x03,  0xf7,  0x06,  0xf7,  0x03,  0xfc,  0x06,  0x00,
-  0x1e,  0x00,  0xbe,  0x00,  0xe1,  0x00,  0x0c,  0x12,  0x18,  0x1a,  0x70,  0x1a,  0x30,  0x1c,  0x38,  0x1c,
-  0x10,  0x44,  0x00,  0x4c,  0xb0,  0x57,  0x40,  0x5c,  0x4d,  0xe4,  0x04,  0xea,  0x5d,  0xf0,  0xa7,  0xf0,
-  0x04,  0xf6,  0x02,  0xfc,  0x05,  0x00,  0x09,  0x00,  0x19,  0x00,  0x32,  0x00,  0x33,  0x00,  0x34,  0x00,
-  0x36,  0x00,  0x98,  0x00,  0x9e,  0x00,  0xcc,  0x00,  0x20,  0x01,  0x4e,  0x01,  0x79,  0x01,  0x3c,  0x09,
-  0x68,  0x0d,  0x02,  0x10,  0x04,  0x10,  0x3a,  0x10,  0x08,  0x12,  0x0a,  0x13,  0x40,  0x16,  0x50,  0x16,
-  0x00,  0x17,  0x4a,  0x19,  0x00,  0x4e,  0x00,  0x54,  0x01,  0x58,  0x00,  0xdc,  0x05,  0xf0,  0x09,  0xf0,
-  0x59,  0xf0,  0xb8,  0xf0,  0x48,  0xf4,  0x0e,  0xf7,  0x0a,  0x00,  0x9b,  0x00,  0x9c,  0x00,  0xa4,  0x00,
-  0xb5,  0x00,  0xba,  0x00,  0xd0,  0x00,  0xe7,  0x00,  0xf0,  0x03,  0x69,  0x08,  0xe9,  0x09,  0x5c,  0x0c,
-  0xb6,  0x12,  0xbc,  0x19,  0xd8,  0x1b,  0x20,  0x1c,  0x34,  0x1c,  0x36,  0x1c,  0x42,  0x1d,  0x08,  0x44,
-  0x38,  0x44,  0x91,  0x44,  0x0a,  0x45,  0x48,  0x46,  0x89,  0x48,  0x68,  0x54,  0x83,  0x55,  0x83,  0x59,
-  0x31,  0xe4,  0x02,  0xe6,  0x07,  0xf0,  0x08,  0xf0,  0x0b,  0xf0,  0x0c,  0xf0,  0x4b,  0xf4,  0x04,  0xf8,
-  0x05,  0xf8,  0x02,  0xfa,  0x03,  0xfa,  0x04,  0xfc,  0x05,  0xfc,  0x07,  0x00,  0xa8,  0x00,  0xaa,  0x00,
-  0xb9,  0x00,  0xe0,  0x00,  0xe5,  0x00,  0x22,  0x01,  0x26,  0x01,  0x60,  0x01,  0x7a,  0x01,  0x82,  0x01,
-  0xc8,  0x01,  0xca,  0x01,  0x86,  0x02,  0x6a,  0x03,  0x18,  0x05,  0xb2,  0x07,  0x68,  0x08,  0x10,  0x0d,
-  0x06,  0x10,  0x0a,  0x10,  0x0e,  0x10,  0x12,  0x10,  0x60,  0x10,  0xed,  0x10,  0xf3,  0x10,  0x06,  0x12,
-  0x10,  0x12,  0x1e,  0x12,  0x0c,  0x13,  0x0e,  0x13,  0x10,  0x13,  0xfe,  0x9c,  0xf0,  0x35,  0x05,  0xfe,
-  0xec,  0x0e,  0xff,  0x10,  0x00,  0x00,  0xe9,  0xfe,  0x34,  0x1f,  0x00,  0xe8,  0xfe,  0x88,  0x01,  0xff,
-  0x03,  0x00,  0x00,  0xfe,  0x93,  0x15,  0xfe,  0x0f,  0x05,  0xff,  0x38,  0x00,  0x00,  0xfe,  0x57,  0x24,
-  0x00,  0xfe,  0x4c,  0x00,  0x65,  0xff,  0x04,  0x00,  0x00,  0x1a,  0xff,  0x09,  0x00,  0x00,  0xff,  0x08,
-  0x01,  0x01,  0xff,  0x08,  0xff,  0xff,  0xff,  0x27,  0x00,  0x00,  0xff,  0x10,  0xff,  0xff,  0xff,  0x13,
-  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,  0xff,  0x21,  0x00,  0x00,  0xfe,  0x04,  0xf7,  0xe8,
-  0x37,  0x7d,  0x0d,  0x01,  0xfe,  0x4a,  0x11,  0xfe,  0x04,  0xf7,  0xe8,  0x7d,  0x0d,  0x51,  0x37,  0xfe,
-  0x3d,  0xf0,  0xfe,  0x0c,  0x02,  0xfe,  0x20,  0xf0,  0xbc,  0xfe,  0x91,  0xf0,  0xfe,  0xf8,  0x01,  0xfe,
-  0x90,  0xf0,  0xfe,  0xf8,  0x01,  0xfe,  0x8f,  0xf0,  0xbc,  0x03,  0x67,  0x4d,  0x05,  0xfe,  0x08,  0x0f,
-  0x01,  0xfe,  0x78,  0x0f,  0xfe,  0xdd,  0x12,  0x05,  0xfe,  0x0e,  0x03,  0xfe,  0x28,  0x1c,  0x03,  0xfe,
-  0xa6,  0x00,  0xfe,  0xd1,  0x12,  0x3e,  0x22,  0xfe,  0xa6,  0x00,  0xac,  0xfe,  0x48,  0xf0,  0xfe,  0x90,
-  0x02,  0xfe,  0x49,  0xf0,  0xfe,  0xaa,  0x02,  0xfe,  0x4a,  0xf0,  0xfe,  0xc8,  0x02,  0xfe,  0x46,  0xf0,
-  0xfe,  0x5a,  0x02,  0xfe,  0x47,  0xf0,  0xfe,  0x60,  0x02,  0xfe,  0x43,  0xf0,  0xfe,  0x4e,  0x02,  0xfe,
-  0x44,  0xf0,  0xfe,  0x52,  0x02,  0xfe,  0x45,  0xf0,  0xfe,  0x56,  0x02,  0x1c,  0x0d,  0xa2,  0x1c,  0x07,
-  0x22,  0xb7,  0x05,  0x35,  0xfe,  0x00,  0x1c,  0xfe,  0xf1,  0x10,  0xfe,  0x02,  0x1c,  0xf5,  0xfe,  0x1e,
-  0x1c,  0xfe,  0xe9,  0x10,  0x01,  0x5f,  0xfe,  0xe7,  0x10,  0xfe,  0x06,  0xfc,  0xde,  0x0a,  0x81,  0x01,
-  0xa3,  0x05,  0x35,  0x1f,  0x95,  0x47,  0xb8,  0x01,  0xfe,  0xe4,  0x11,  0x0a,  0x81,  0x01,  0x5c,  0xfe,
-  0xbd,  0x10,  0x0a,  0x81,  0x01,  0x5c,  0xfe,  0xad,  0x10,  0xfe,  0x16,  0x1c,  0xfe,  0x58,  0x1c,  0x1c,
-  0x07,  0x22,  0xb7,  0x37,  0x2a,  0x35,  0xfe,  0x3d,  0xf0,  0xfe,  0x0c,  0x02,  0x2b,  0xfe,  0x9e,  0x02,
-  0xfe,  0x5a,  0x1c,  0xfe,  0x12,  0x1c,  0xfe,  0x14,  0x1c,  0x1f,  0xfe,  0x30,  0x00,  0x47,  0xb8,  0x01,
-  0xfe,  0xd4,  0x11,  0x1c,  0x07,  0x22,  0xb7,  0x05,  0xe9,  0x21,  0x2c,  0x09,  0x1a,  0x31,  0xfe,  0x69,
-  0x10,  0x1c,  0x07,  0x22,  0xb7,  0xfe,  0x04,  0xec,  0x2c,  0x60,  0x01,  0xfe,  0x1e,  0x1e,  0x20,  0x2c,
-  0xfe,  0x05,  0xf6,  0xde,  0x01,  0xfe,  0x62,  0x1b,  0x01,  0x0c,  0x61,  0x4a,  0x44,  0x15,  0x56,  0x51,
-  0x01,  0xfe,  0x9e,  0x1e,  0x01,  0xfe,  0x96,  0x1a,  0x05,  0x35,  0x0a,  0x57,  0x01,  0x18,  0x09,  0x00,
-  0x36,  0x01,  0x85,  0xfe,  0x18,  0x10,  0xfe,  0x41,  0x58,  0x0a,  0xba,  0x01,  0x18,  0xfe,  0xc8,  0x54,
-  0x7b,  0xfe,  0x1c,  0x03,  0x01,  0xfe,  0x96,  0x1a,  0x05,  0x35,  0x37,  0x60,  0xfe,  0x02,  0xe8,  0x30,
-  0xfe,  0xbf,  0x57,  0xfe,  0x9e,  0x43,  0xfe,  0x77,  0x57,  0xfe,  0x27,  0xf0,  0xfe,  0xe4,  0x01,  0xfe,
-  0x07,  0x4b,  0xfe,  0x20,  0xf0,  0xbc,  0xfe,  0x40,  0x1c,  0x2a,  0xeb,  0xfe,  0x26,  0xf0,  0xfe,  0x66,
-  0x03,  0xfe,  0xa0,  0xf0,  0xfe,  0x54,  0x03,  0xfe,  0x11,  0xf0,  0xbc,  0xfe,  0xef,  0x10,  0xfe,  0x9f,
-  0xf0,  0xfe,  0x74,  0x03,  0xfe,  0x46,  0x1c,  0x19,  0xfe,  0x11,  0x00,  0x05,  0x70,  0x37,  0xfe,  0x48,
-  0x1c,  0xfe,  0x46,  0x1c,  0x01,  0x0c,  0x06,  0x28,  0xfe,  0x18,  0x13,  0x26,  0x21,  0xb9,  0xc7,  0x20,
-  0xb9,  0x0a,  0x57,  0x01,  0x18,  0xc7,  0x89,  0x01,  0xfe,  0xc8,  0x1a,  0x15,  0xe1,  0x2a,  0xeb,  0xfe,
-  0x01,  0xf0,  0xeb,  0xfe,  0x82,  0xf0,  0xfe,  0xa4,  0x03,  0xfe,  0x9c,  0x32,  0x15,  0xfe,  0xe4,  0x00,
-  0x2f,  0xfe,  0xb6,  0x03,  0x2a,  0x3c,  0x16,  0xfe,  0xc6,  0x03,  0x01,  0x41,  0xfe,  0x06,  0xf0,  0xfe,
-  0xd6,  0x03,  0xaf,  0xa0,  0xfe,  0x0a,  0xf0,  0xfe,  0xa2,  0x07,  0x05,  0x29,  0x03,  0x81,  0x1e,  0x1b,
-  0xfe,  0x24,  0x05,  0x1f,  0x63,  0x01,  0x42,  0x8f,  0xfe,  0x70,  0x02,  0x05,  0xea,  0xfe,  0x46,  0x1c,
-  0x37,  0x7d,  0x1d,  0xfe,  0x67,  0x1b,  0xfe,  0xbf,  0x57,  0xfe,  0x77,  0x57,  0xfe,  0x48,  0x1c,  0x75,
-  0x01,  0xa6,  0x86,  0x0a,  0x57,  0x01,  0x18,  0x09,  0x00,  0x1b,  0xec,  0x0a,  0xe1,  0x01,  0x18,  0x77,
-  0x50,  0x40,  0x8d,  0x30,  0x03,  0x81,  0x1e,  0xf8,  0x1f,  0x63,  0x01,  0x42,  0x8f,  0xfe,  0x70,  0x02,
-  0x05,  0xea,  0xd7,  0x99,  0xd8,  0x9c,  0x2a,  0x29,  0x2f,  0xfe,  0x4e,  0x04,  0x16,  0xfe,  0x4a,  0x04,
-  0x7e,  0xfe,  0xa0,  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x54,  0x12,  0x32,  0xff,  0x02,  0x00,  0x10,  0x01,
-  0x08,  0x16,  0xfe,  0x02,  0x05,  0x32,  0x01,  0x08,  0x16,  0x29,  0x27,  0x25,  0xee,  0xfe,  0x4c,  0x44,
-  0xfe,  0x58,  0x12,  0x50,  0xfe,  0x44,  0x48,  0x13,  0x34,  0xfe,  0x4c,  0x54,  0x7b,  0xec,  0x60,  0x8d,
-  0x30,  0x01,  0xfe,  0x4e,  0x1e,  0xfe,  0x48,  0x47,  0xfe,  0x7c,  0x13,  0x01,  0x0c,  0x06,  0x28,  0xfe,
-  0x32,  0x13,  0x01,  0x43,  0x09,  0x9b,  0xfe,  0x68,  0x13,  0xfe,  0x26,  0x10,  0x13,  0x34,  0xfe,  0x4c,
-  0x54,  0x7b,  0xec,  0x01,  0xfe,  0x4e,  0x1e,  0xfe,  0x48,  0x47,  0xfe,  0x54,  0x13,  0x01,  0x0c,  0x06,
-  0x28,  0xa5,  0x01,  0x43,  0x09,  0x9b,  0xfe,  0x40,  0x13,  0x01,  0x0c,  0x06,  0x28,  0xf9,  0x1f,  0x7f,
-  0x01,  0x0c,  0x06,  0x07,  0x4d,  0x1f,  0xfe,  0x0d,  0x00,  0x01,  0x42,  0x8f,  0xfe,  0xa4,  0x0e,  0x05,
-  0x29,  0x32,  0x15,  0xfe,  0xe6,  0x00,  0x0f,  0xfe,  0x1c,  0x90,  0x04,  0xfe,  0x9c,  0x93,  0x3a,  0x0b,
-  0x0e,  0x8b,  0x02,  0x1f,  0x7f,  0x01,  0x42,  0x05,  0x35,  0xfe,  0x42,  0x5b,  0x7d,  0x1d,  0xfe,  0x46,
-  0x59,  0xfe,  0xbf,  0x57,  0xfe,  0x77,  0x57,  0x0f,  0xfe,  0x87,  0x80,  0x04,  0xfe,  0x87,  0x83,  0xfe,
-  0xc9,  0x47,  0x0b,  0x0e,  0xd0,  0x65,  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x98,  0x13,  0x0f,  0xfe,  0x20,
-  0x80,  0x04,  0xfe,  0xa0,  0x83,  0x33,  0x0b,  0x0e,  0x09,  0x1d,  0xfe,  0x84,  0x12,  0x01,  0x38,  0x06,
-  0x07,  0xfe,  0x70,  0x13,  0x03,  0xfe,  0xa2,  0x00,  0x1e,  0x1b,  0xfe,  0xda,  0x05,  0xd0,  0x54,  0x01,
-  0x38,  0x06,  0x0d,  0xfe,  0x58,  0x13,  0x03,  0xfe,  0xa0,  0x00,  0x1e,  0xfe,  0x50,  0x12,  0x5e,  0xff,
-  0x02,  0x00,  0x10,  0x2f,  0xfe,  0x90,  0x05,  0x2a,  0x3c,  0xcc,  0xff,  0x02,  0x00,  0x10,  0x2f,  0xfe,
-  0x9e,  0x05,  0x17,  0xfe,  0xf4,  0x05,  0x15,  0xfe,  0xe3,  0x00,  0x26,  0x01,  0x38,  0xfe,  0x4a,  0xf0,
-  0xfe,  0xc0,  0x05,  0xfe,  0x49,  0xf0,  0xfe,  0xba,  0x05,  0x71,  0x2e,  0xfe,  0x21,  0x00,  0xf1,  0x2e,
-  0xfe,  0x22,  0x00,  0xa2,  0x2e,  0x4a,  0xfe,  0x09,  0x48,  0xff,  0x02,  0x00,  0x10,  0x2f,  0xfe,  0xd0,
-  0x05,  0x17,  0xfe,  0xf4,  0x05,  0xfe,  0xe2,  0x08,  0x01,  0x38,  0x06,  0xfe,  0x1c,  0x00,  0x4d,  0x01,
-  0xa7,  0x2e,  0x07,  0x20,  0xe4,  0x47,  0xfe,  0x27,  0x01,  0x01,  0x0c,  0x06,  0x28,  0xfe,  0x24,  0x12,
-  0x3e,  0x01,  0x84,  0x1f,  0x7f,  0x01,  0x0c,  0x06,  0x07,  0x4d,  0x1f,  0xfe,  0x0d,  0x00,  0x01,  0x42,
-  0x8f,  0xfe,  0xa4,  0x0e,  0x05,  0x29,  0x03,  0xe6,  0x1e,  0xfe,  0xca,  0x13,  0x03,  0xb6,  0x1e,  0xfe,
-  0x40,  0x12,  0x03,  0x66,  0x1e,  0xfe,  0x38,  0x13,  0x3e,  0x01,  0x84,  0x17,  0xfe,  0x72,  0x06,  0x0a,
-  0x07,  0x01,  0x38,  0x06,  0x24,  0xfe,  0x02,  0x12,  0x4f,  0x01,  0xfe,  0x56,  0x19,  0x16,  0xfe,  0x68,
-  0x06,  0x15,  0x82,  0x01,  0x41,  0x15,  0xe2,  0x03,  0x66,  0x8a,  0x10,  0x66,  0x03,  0x9a,  0x1e,  0xfe,
-  0x70,  0x12,  0x03,  0x55,  0x1e,  0xfe,  0x68,  0x13,  0x01,  0xc6,  0x09,  0x12,  0x48,  0xfe,  0x92,  0x06,
-  0x2e,  0x12,  0x01,  0xfe,  0xac,  0x1d,  0xfe,  0x43,  0x48,  0x62,  0x80,  0x13,  0x58,  0xff,  0x02,  0x00,
-  0x57,  0x52,  0xad,  0x23,  0x3f,  0x4e,  0x62,  0x49,  0x3e,  0x01,  0x84,  0x17,  0xfe,  0xea,  0x06,  0x01,
-  0x38,  0x06,  0x12,  0xf7,  0x45,  0x0a,  0x95,  0x01,  0xfe,  0x84,  0x19,  0x16,  0xfe,  0xe0,  0x06,  0x15,
-  0x82,  0x01,  0x41,  0x15,  0xe2,  0x03,  0x55,  0x8a,  0x10,  0x55,  0x1c,  0x07,  0x01,  0x84,  0xfe,  0xae,
-  0x10,  0x03,  0x6f,  0x1e,  0xfe,  0x9e,  0x13,  0x3e,  0x01,  0x84,  0x03,  0x9a,  0x1e,  0xfe,  0x1a,  0x12,
-  0x01,  0x38,  0x06,  0x12,  0xfc,  0x01,  0xc6,  0x01,  0xfe,  0xac,  0x1d,  0xfe,  0x43,  0x48,  0x62,  0x80,
-  0xf0,  0x45,  0x0a,  0x95,  0x03,  0xb6,  0x1e,  0xf8,  0x01,  0x38,  0x06,  0x24,  0x36,  0xfe,  0x02,  0xf6,
-  0x07,  0x71,  0x78,  0x8c,  0x00,  0x4d,  0x62,  0x49,  0x3e,  0x2d,  0x93,  0x4e,  0xd0,  0x0d,  0x17,  0xfe,
-  0x9a,  0x07,  0x01,  0xfe,  0xc0,  0x19,  0x16,  0xfe,  0x90,  0x07,  0x26,  0x20,  0x9e,  0x15,  0x82,  0x01,
-  0x41,  0x15,  0xe2,  0x21,  0x9e,  0x09,  0x07,  0xfb,  0x03,  0xe6,  0xfe,  0x58,  0x57,  0x10,  0xe6,  0x05,
-  0xfe,  0x2a,  0x06,  0x03,  0x6f,  0x8a,  0x10,  0x6f,  0x1c,  0x07,  0x01,  0x84,  0xfe,  0x9c,  0x32,  0x5f,
-  0x75,  0x01,  0xa6,  0x86,  0x15,  0xfe,  0xe2,  0x00,  0x2f,  0xed,  0x2a,  0x3c,  0xfe,  0x0a,  0xf0,  0xfe,
-  0xce,  0x07,  0xae,  0xfe,  0x96,  0x08,  0xfe,  0x06,  0xf0,  0xfe,  0x9e,  0x08,  0xaf,  0xa0,  0x05,  0x29,
-  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x2e,  0x12,  0x14,  0x1d,  0x01,  0x08,  0x14,  0x00,  0x01,  0x08,  0x14,
-  0x00,  0x01,  0x08,  0x14,  0x00,  0x01,  0x08,  0xfe,  0x99,  0xa4,  0x01,  0x08,  0x14,  0x00,  0x05,  0xfe,
-  0xc6,  0x09,  0x01,  0x76,  0x06,  0x12,  0xfe,  0x3a,  0x12,  0x01,  0x0c,  0x06,  0x12,  0xfe,  0x30,  0x13,
-  0x14,  0xfe,  0x1b,  0x00,  0x01,  0x08,  0x14,  0x00,  0x01,  0x08,  0x14,  0x00,  0x01,  0x08,  0x14,  0x00,
-  0x01,  0x08,  0x14,  0x07,  0x01,  0x08,  0x14,  0x00,  0x05,  0xef,  0x7c,  0x4a,  0x78,  0x4f,  0x0f,  0xfe,
-  0x9a,  0x81,  0x04,  0xfe,  0x9a,  0x83,  0xfe,  0xcb,  0x47,  0x0b,  0x0e,  0x2d,  0x28,  0x48,  0xfe,  0x6c,
-  0x08,  0x0a,  0x28,  0xfe,  0x09,  0x6f,  0xca,  0xfe,  0xca,  0x45,  0xfe,  0x32,  0x12,  0x53,  0x63,  0x4e,
-  0x7c,  0x97,  0x2f,  0xfe,  0x7e,  0x08,  0x2a,  0x3c,  0xfe,  0x0a,  0xf0,  0xfe,  0x6c,  0x08,  0xaf,  0xa0,
-  0xae,  0xfe,  0x96,  0x08,  0x05,  0x29,  0x01,  0x41,  0x05,  0xed,  0x14,  0x24,  0x05,  0xed,  0xfe,  0x9c,
-  0xf7,  0x9f,  0x01,  0xfe,  0xae,  0x1e,  0xfe,  0x18,  0x58,  0x01,  0xfe,  0xbe,  0x1e,  0xfe,  0x99,  0x58,
-  0xfe,  0x78,  0x18,  0xfe,  0xf9,  0x18,  0x8e,  0xfe,  0x16,  0x09,  0x10,  0x6a,  0x22,  0x6b,  0x01,  0x0c,
-  0x61,  0x54,  0x44,  0x21,  0x2c,  0x09,  0x1a,  0xf8,  0x77,  0x01,  0xfe,  0x7e,  0x1e,  0x47,  0x2c,  0x7a,
-  0x30,  0xf0,  0xfe,  0x83,  0xe7,  0xfe,  0x3f,  0x00,  0x71,  0xfe,  0x03,  0x40,  0x01,  0x0c,  0x61,  0x65,
-  0x44,  0x01,  0xc2,  0xc8,  0xfe,  0x1f,  0x40,  0x20,  0x6e,  0x01,  0xfe,  0x6a,  0x16,  0xfe,  0x08,  0x50,
-  0xfe,  0x8a,  0x50,  0xfe,  0x44,  0x51,  0xfe,  0xc6,  0x51,  0xfe,  0x10,  0x10,  0x01,  0xfe,  0xce,  0x1e,
-  0x01,  0xfe,  0xde,  0x1e,  0x10,  0x68,  0x22,  0x69,  0x01,  0xfe,  0xee,  0x1e,  0x01,  0xfe,  0xfe,  0x1e,
-  0xfe,  0x40,  0x50,  0xfe,  0xc2,  0x50,  0x10,  0x4b,  0x22,  0x4c,  0xfe,  0x8a,  0x10,  0x01,  0x0c,  0x06,
-  0x54,  0xfe,  0x50,  0x12,  0x01,  0xfe,  0xae,  0x1e,  0x01,  0xfe,  0xbe,  0x1e,  0x10,  0x6a,  0x22,  0x6b,
-  0x01,  0x0c,  0x06,  0x65,  0x4e,  0x01,  0xc2,  0x0f,  0xfe,  0x1f,  0x80,  0x04,  0xfe,  0x9f,  0x83,  0x33,
-  0x0b,  0x0e,  0x20,  0x6e,  0x0f,  0xfe,  0x44,  0x90,  0x04,  0xfe,  0xc4,  0x93,  0x3a,  0x0b,  0xfe,  0xc6,
-  0x90,  0x04,  0xfe,  0xc6,  0x93,  0x79,  0x0b,  0x0e,  0x10,  0x6c,  0x22,  0x6d,  0x01,  0xfe,  0xce,  0x1e,
-  0x01,  0xfe,  0xde,  0x1e,  0x10,  0x68,  0x22,  0x69,  0x0f,  0xfe,  0x40,  0x90,  0x04,  0xfe,  0xc0,  0x93,
-  0x3a,  0x0b,  0xfe,  0xc2,  0x90,  0x04,  0xfe,  0xc2,  0x93,  0x79,  0x0b,  0x0e,  0x10,  0x4b,  0x22,  0x4c,
-  0x10,  0x64,  0x22,  0x34,  0x01,  0x0c,  0x61,  0x24,  0x44,  0x37,  0x13,  0xfe,  0x4e,  0x11,  0x2f,  0xfe,
-  0xde,  0x09,  0xfe,  0x9e,  0xf0,  0xfe,  0xf2,  0x09,  0xfe,  0x01,  0x48,  0x1b,  0x3c,  0x37,  0x88,  0xf5,
-  0xd4,  0xfe,  0x1e,  0x0a,  0xd5,  0xfe,  0x42,  0x0a,  0xd2,  0xfe,  0x1e,  0x0a,  0xd3,  0xfe,  0x42,  0x0a,
-  0xae,  0xfe,  0x12,  0x0a,  0xfe,  0x06,  0xf0,  0xfe,  0x18,  0x0a,  0xaf,  0xa0,  0x05,  0x29,  0x01,  0x41,
-  0xfe,  0xc1,  0x10,  0x14,  0x24,  0xfe,  0xc1,  0x10,  0x01,  0x76,  0x06,  0x07,  0xfe,  0x14,  0x12,  0x01,
-  0x76,  0x06,  0x0d,  0x5d,  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x74,  0x12,  0xfe,  0x2e,  0x1c,  0x05,  0xfe,
-  0x1a,  0x0c,  0x01,  0x76,  0x06,  0x07,  0x5d,  0x01,  0x76,  0x06,  0x0d,  0x41,  0xfe,  0x2c,  0x1c,  0xfe,
-  0xaa,  0xf0,  0xfe,  0xce,  0x0a,  0xfe,  0xac,  0xf0,  0xfe,  0x66,  0x0a,  0xfe,  0x92,  0x10,  0xc4,  0xf6,
-  0xfe,  0xad,  0xf0,  0xfe,  0x72,  0x0a,  0x05,  0xfe,  0x1a,  0x0c,  0xc5,  0xfe,  0xe7,  0x10,  0xfe,  0x2b,
-  0xf0,  0xbf,  0xfe,  0x6b,  0x18,  0x23,  0xfe,  0x00,  0xfe,  0xfe,  0x1c,  0x12,  0xac,  0xfe,  0xd2,  0xf0,
-  0xbf,  0xfe,  0x76,  0x18,  0x23,  0x1d,  0x1b,  0xbf,  0x03,  0xe3,  0x23,  0x07,  0x1b,  0xbf,  0xd4,  0x5b,
-  0xd5,  0x5b,  0xd2,  0x5b,  0xd3,  0x5b,  0xc4,  0xc5,  0xfe,  0xa9,  0x10,  0x75,  0x5e,  0x32,  0x1f,  0x7f,
-  0x01,  0x42,  0x19,  0xfe,  0x35,  0x00,  0xfe,  0x01,  0xf0,  0x70,  0x19,  0x98,  0x05,  0x70,  0xfe,  0x74,
-  0x18,  0x23,  0xfe,  0x00,  0xf8,  0x1b,  0x5b,  0x7d,  0x12,  0x01,  0xfe,  0x78,  0x0f,  0x4d,  0x01,  0xfe,
-  0x96,  0x1a,  0x21,  0x30,  0x77,  0x7d,  0x1d,  0x05,  0x5b,  0x01,  0x0c,  0x06,  0x0d,  0x2b,  0xfe,  0xe2,
-  0x0b,  0x01,  0x0c,  0x06,  0x54,  0xfe,  0xa6,  0x12,  0x01,  0x0c,  0x06,  0x24,  0xfe,  0x88,  0x13,  0x21,
-  0x6e,  0xc7,  0x01,  0xfe,  0x1e,  0x1f,  0x0f,  0xfe,  0x83,  0x80,  0x04,  0xfe,  0x83,  0x83,  0xfe,  0xc9,
-  0x47,  0x0b,  0x0e,  0xfe,  0xc8,  0x44,  0xfe,  0x42,  0x13,  0x0f,  0xfe,  0x04,  0x91,  0x04,  0xfe,  0x84,
-  0x93,  0xfe,  0xca,  0x57,  0x0b,  0xfe,  0x86,  0x91,  0x04,  0xfe,  0x86,  0x93,  0xfe,  0xcb,  0x57,  0x0b,
-  0x0e,  0x7a,  0x30,  0xfe,  0x40,  0x59,  0xfe,  0xc1,  0x59,  0x8e,  0x40,  0x03,  0x6a,  0x3b,  0x6b,  0x10,
-  0x97,  0x22,  0x98,  0xd9,  0x6a,  0xda,  0x6b,  0x01,  0xc2,  0xc8,  0x7a,  0x30,  0x20,  0x6e,  0xdb,  0x64,
-  0xdc,  0x34,  0x91,  0x6c,  0x7e,  0x6d,  0xfe,  0x44,  0x55,  0xfe,  0xe5,  0x55,  0xfe,  0x04,  0xfa,  0x64,
-  0xfe,  0x05,  0xfa,  0x34,  0x01,  0xfe,  0x6a,  0x16,  0xa3,  0x26,  0x10,  0x97,  0x10,  0x98,  0x91,  0x6c,
-  0x7e,  0x6d,  0xfe,  0x14,  0x10,  0x01,  0x0c,  0x06,  0x24,  0x1b,  0x40,  0x91,  0x4b,  0x7e,  0x4c,  0x01,
-  0x0c,  0x06,  0xfe,  0xf7,  0x00,  0x44,  0x03,  0x68,  0x3b,  0x69,  0xfe,  0x10,  0x58,  0xfe,  0x91,  0x58,
-  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0x05,  0x5b,  0x01,  0x0c,  0x06,  0x24,  0x1b,  0x40,  0x01,  0x0c,
-  0x06,  0xfe,  0xf7,  0x00,  0x44,  0x78,  0x01,  0xfe,  0x8e,  0x1e,  0x4f,  0x0f,  0xfe,  0x10,  0x90,  0x04,
-  0xfe,  0x90,  0x93,  0x3a,  0x0b,  0xfe,  0x92,  0x90,  0x04,  0xfe,  0x92,  0x93,  0x79,  0x0b,  0x0e,  0xfe,
-  0xbd,  0x10,  0x01,  0x43,  0x09,  0xbb,  0x1b,  0xfe,  0x6e,  0x0a,  0x15,  0xbb,  0x01,  0x0c,  0x06,  0x0d,
-  0xfe,  0x14,  0x13,  0x03,  0x4b,  0x3b,  0x4c,  0x8e,  0xfe,  0x6e,  0x0a,  0xfe,  0x0c,  0x58,  0xfe,  0x8d,
-  0x58,  0x05,  0x5b,  0x26,  0x3e,  0x0f,  0xfe,  0x19,  0x80,  0x04,  0xfe,  0x99,  0x83,  0x33,  0x0b,  0x0e,
-  0xfe,  0xe5,  0x10,  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x1a,  0x12,  0xfe,  0x6c,  0x19,  0xfe,  0x19,  0x41,
-  0xfe,  0x6b,  0x18,  0xac,  0xfe,  0xd1,  0xf0,  0xef,  0x1f,  0x92,  0x01,  0x42,  0x19,  0xfe,  0x44,  0x00,
-  0xfe,  0x90,  0x10,  0xfe,  0x6c,  0x19,  0xd9,  0x4b,  0xfe,  0xed,  0x19,  0xda,  0x4c,  0xfe,  0x0c,  0x51,
-  0xfe,  0x8e,  0x51,  0xfe,  0x6b,  0x18,  0x23,  0xfe,  0x00,  0xff,  0x31,  0xfe,  0x76,  0x10,  0xac,  0xfe,
-  0xd2,  0xf0,  0xfe,  0xba,  0x0c,  0xfe,  0x76,  0x18,  0x23,  0x1d,  0x5d,  0x03,  0xe3,  0x23,  0x07,  0xfe,
-  0x08,  0x13,  0x19,  0xfe,  0x16,  0x00,  0x05,  0x70,  0xfe,  0xd1,  0xf0,  0xfe,  0xcc,  0x0c,  0x1f,  0x92,
-  0x01,  0x42,  0x19,  0xfe,  0x17,  0x00,  0x5c,  0xfe,  0xce,  0xf0,  0xfe,  0xd2,  0x0c,  0xfe,  0x3e,  0x10,
-  0xfe,  0xcd,  0xf0,  0xfe,  0xde,  0x0c,  0x19,  0xfe,  0x22,  0x00,  0x05,  0x70,  0xfe,  0xcb,  0xf0,  0xfe,
-  0xea,  0x0c,  0x19,  0xfe,  0x24,  0x00,  0x05,  0x70,  0xfe,  0xd0,  0xf0,  0xfe,  0xf4,  0x0c,  0x19,  0x94,
-  0xfe,  0x1c,  0x10,  0xfe,  0xcf,  0xf0,  0xfe,  0xfe,  0x0c,  0x19,  0x4a,  0xf3,  0xfe,  0xcc,  0xf0,  0xef,
-  0x01,  0x76,  0x06,  0x24,  0x4d,  0x19,  0xfe,  0x12,  0x00,  0x37,  0x13,  0xfe,  0x4e,  0x11,  0x2f,  0xfe,
-  0x16,  0x0d,  0xfe,  0x9e,  0xf0,  0xfe,  0x2a,  0x0d,  0xfe,  0x01,  0x48,  0x1b,  0x3c,  0x37,  0x88,  0xf5,
-  0xd4,  0x29,  0xd5,  0x29,  0xd2,  0x29,  0xd3,  0x29,  0x37,  0xfe,  0x9c,  0x32,  0x2f,  0xfe,  0x3e,  0x0d,
-  0x2a,  0x3c,  0xae,  0xfe,  0x62,  0x0d,  0xaf,  0xa0,  0xd4,  0x9f,  0xd5,  0x9f,  0xd2,  0x9f,  0xd3,  0x9f,
-  0x05,  0x29,  0x01,  0x41,  0xfe,  0xd3,  0x10,  0x15,  0xfe,  0xe8,  0x00,  0xc4,  0xc5,  0x75,  0xd7,  0x99,
-  0xd8,  0x9c,  0xfe,  0x89,  0xf0,  0x29,  0x27,  0x25,  0xbe,  0xd7,  0x99,  0xd8,  0x9c,  0x2f,  0xfe,  0x8c,
-  0x0d,  0x16,  0x29,  0x27,  0x25,  0xbd,  0xfe,  0x01,  0x48,  0xa4,  0x19,  0xfe,  0x42,  0x00,  0x05,  0x70,
-  0x90,  0x07,  0xfe,  0x81,  0x49,  0x1b,  0xfe,  0x64,  0x0e,  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x44,  0x13,
-  0x19,  0x00,  0x2d,  0x0d,  0xfe,  0x54,  0x12,  0x2d,  0xfe,  0x28,  0x00,  0x2b,  0xfe,  0xda,  0x0e,  0x0a,
-  0x57,  0x01,  0x18,  0x09,  0x00,  0x36,  0x46,  0xfe,  0x28,  0x00,  0xfe,  0xfa,  0x10,  0x01,  0xfe,  0xf4,
-  0x1c,  0x01,  0xfe,  0x00,  0x1d,  0x0a,  0xba,  0x01,  0xfe,  0x58,  0x10,  0x40,  0x15,  0x56,  0x01,  0x85,
-  0x05,  0x35,  0x19,  0xfe,  0x44,  0x00,  0x2d,  0x0d,  0xf7,  0x46,  0x0d,  0xfe,  0xcc,  0x10,  0x01,  0xa7,
-  0x46,  0x0d,  0xfe,  0xc2,  0x10,  0x01,  0xa7,  0x0f,  0xfe,  0x19,  0x82,  0x04,  0xfe,  0x99,  0x83,  0xfe,
-  0xcc,  0x47,  0x0b,  0x0e,  0xfe,  0x34,  0x46,  0xa5,  0x46,  0x0d,  0x19,  0xfe,  0x43,  0x00,  0xfe,  0xa2,
-  0x10,  0x01,  0x0c,  0x61,  0x0d,  0x44,  0x01,  0xfe,  0xf4,  0x1c,  0x01,  0xfe,  0x00,  0x1d,  0x40,  0x15,
-  0x56,  0x01,  0x85,  0x7d,  0x0d,  0x40,  0x51,  0x01,  0xfe,  0x9e,  0x1e,  0x05,  0xfe,  0x3a,  0x03,  0x01,
-  0x0c,  0x06,  0x0d,  0x5d,  0x46,  0x0d,  0x19,  0x00,  0xfe,  0x62,  0x10,  0x01,  0x76,  0x06,  0x12,  0xfe,
-  0x5c,  0x12,  0x01,  0x0c,  0x06,  0x12,  0xfe,  0x52,  0x13,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,
-  0x8e,  0x0e,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x94,  0x0e,  0x01,  0x0c,  0x61,  0x12,  0x44,
-  0xfe,  0x9f,  0x10,  0x19,  0xfe,  0x15,  0x00,  0xfe,  0x04,  0xe6,  0x0d,  0x4f,  0xfe,  0x2e,  0x10,  0x19,
-  0xfe,  0x13,  0x00,  0xfe,  0x10,  0x10,  0x19,  0xfe,  0x47,  0x00,  0xf1,  0x19,  0xfe,  0x41,  0x00,  0xa2,
-  0x19,  0xfe,  0x24,  0x00,  0x86,  0xc4,  0xc5,  0x75,  0x03,  0x81,  0x1e,  0x2b,  0xea,  0x4f,  0xfe,  0x04,
-  0xe6,  0x12,  0xfe,  0x9d,  0x41,  0xfe,  0x1c,  0x42,  0x40,  0x01,  0xf4,  0x05,  0x35,  0xfe,  0x12,  0x1c,
-  0x1f,  0x0d,  0x47,  0xb5,  0xc3,  0x1f,  0xfe,  0x31,  0x00,  0x47,  0xb8,  0x01,  0xfe,  0xd4,  0x11,  0x05,
-  0xe9,  0x51,  0xfe,  0x06,  0xec,  0xe0,  0xfe,  0x0e,  0x47,  0x46,  0x28,  0xfe,  0xce,  0x45,  0x31,  0x51,
-  0xfe,  0x06,  0xea,  0xe0,  0xfe,  0x47,  0x4b,  0x45,  0xfe,  0x75,  0x57,  0x03,  0x67,  0xfe,  0x98,  0x56,
-  0xfe,  0x38,  0x12,  0x0a,  0x5a,  0x01,  0x18,  0xfe,  0x44,  0x48,  0x60,  0x01,  0x0c,  0x06,  0x28,  0xfe,
-  0x18,  0x13,  0x0a,  0x57,  0x01,  0x18,  0x3e,  0xfe,  0x41,  0x58,  0x0a,  0xba,  0xfe,  0xfa,  0x14,  0xfe,
-  0x49,  0x54,  0xb0,  0xfe,  0x5e,  0x0f,  0x05,  0xfe,  0x3a,  0x03,  0x0a,  0x67,  0xfe,  0xe0,  0x14,  0xfe,
-  0x0e,  0x47,  0x46,  0x28,  0xfe,  0xce,  0x45,  0x31,  0x51,  0xfe,  0xce,  0x47,  0xfe,  0xad,  0x13,  0x05,
-  0x35,  0x21,  0x2c,  0x09,  0x1a,  0xfe,  0x98,  0x12,  0x26,  0x20,  0x96,  0x20,  0xe7,  0xfe,  0x08,  0x1c,
-  0xfe,  0x7c,  0x19,  0xfe,  0xfd,  0x19,  0xfe,  0x0a,  0x1c,  0x03,  0xe5,  0xfe,  0x48,  0x55,  0xa5,  0x3b,
-  0xfe,  0x62,  0x01,  0xfe,  0xc9,  0x55,  0x31,  0xfe,  0x74,  0x10,  0x01,  0xfe,  0xf0,  0x1a,  0x03,  0xfe,
-  0x38,  0x01,  0x3b,  0xfe,  0x3a,  0x01,  0x8e,  0xfe,  0x1e,  0x10,  0xfe,  0x02,  0xec,  0xe7,  0x53,  0x00,
-  0x36,  0xfe,  0x04,  0xec,  0x2c,  0x60,  0xfe,  0x05,  0xf6,  0xfe,  0x34,  0x01,  0x01,  0xfe,  0x62,  0x1b,
-  0x01,  0xfe,  0xce,  0x1e,  0xb2,  0x11,  0xfe,  0x18,  0x13,  0xca,  0xfe,  0x02,  0xea,  0xe7,  0x53,  0x92,
-  0xfe,  0xc3,  0x13,  0x1f,  0x12,  0x47,  0xb5,  0xc3,  0xfe,  0x2a,  0x10,  0x03,  0xfe,  0x38,  0x01,  0x23,
-  0xfe,  0xf0,  0xff,  0x10,  0xe5,  0x03,  0xfe,  0x3a,  0x01,  0x10,  0xfe,  0x62,  0x01,  0x01,  0xfe,  0x1e,
-  0x1e,  0x20,  0x2c,  0x15,  0x56,  0x01,  0xfe,  0x9e,  0x1e,  0x13,  0x07,  0x02,  0x26,  0x02,  0x21,  0x96,
-  0xc7,  0x20,  0x96,  0x09,  0x92,  0xfe,  0x79,  0x13,  0x1f,  0x1d,  0x47,  0xb5,  0xc3,  0xfe,  0xe1,  0x10,
-  0xcf,  0xfe,  0x03,  0xdc,  0xfe,  0x73,  0x57,  0xfe,  0x80,  0x5d,  0x02,  0xcf,  0xfe,  0x03,  0xdc,  0xfe,
-  0x5b,  0x57,  0xfe,  0x80,  0x5d,  0x02,  0xfe,  0x03,  0x57,  0xcf,  0x26,  0xfe,  0x00,  0xcc,  0x02,  0xfe,
-  0x03,  0x57,  0xcf,  0x89,  0x02,  0x01,  0x0c,  0x06,  0x4a,  0xfe,  0x4e,  0x13,  0x0f,  0xfe,  0x1c,  0x80,
-  0x04,  0xfe,  0x9c,  0x83,  0x33,  0x0b,  0x0e,  0x09,  0x07,  0xfe,  0x3a,  0x13,  0x0f,  0xfe,  0x1e,  0x80,
-  0x04,  0xfe,  0x9e,  0x83,  0x33,  0x0b,  0x0e,  0xfe,  0x2a,  0x13,  0x0f,  0xfe,  0x1d,  0x80,  0x04,  0xfe,
-  0x9d,  0x83,  0xfe,  0xf9,  0x13,  0x0e,  0xfe,  0x1c,  0x13,  0x01,  0xfe,  0xee,  0x1e,  0xac,  0xfe,  0x14,
-  0x13,  0x01,  0xfe,  0xfe,  0x1e,  0xfe,  0x81,  0x58,  0xfa,  0x01,  0xfe,  0x0e,  0x1f,  0xfe,  0x30,  0xf4,
-  0x0d,  0xfe,  0x3c,  0x50,  0xa2,  0x01,  0xfe,  0x92,  0x1b,  0x01,  0x43,  0x09,  0x56,  0xfb,  0x01,  0xfe,
-  0xc8,  0x1a,  0x01,  0x0c,  0x06,  0x28,  0xa4,  0x01,  0xfe,  0xf4,  0x1c,  0x01,  0xfe,  0x00,  0x1d,  0x15,
-  0xfe,  0xe9,  0x00,  0x01,  0x0c,  0x06,  0x4a,  0xfe,  0x4e,  0x13,  0x01,  0xfe,  0x22,  0x1b,  0xfe,  0x1e,
-  0x1c,  0x0f,  0xfe,  0x14,  0x90,  0x04,  0xfe,  0x94,  0x93,  0x3a,  0x0b,  0xfe,  0x96,  0x90,  0x04,  0xfe,
-  0x96,  0x93,  0x79,  0x0b,  0x0e,  0x10,  0xfe,  0x64,  0x01,  0x22,  0xfe,  0x66,  0x01,  0x01,  0x0c,  0x06,
-  0x65,  0xf9,  0x0f,  0xfe,  0x03,  0x80,  0x04,  0xfe,  0x83,  0x83,  0x33,  0x0b,  0x0e,  0x77,  0xfe,  0x01,
-  0xec,  0x2c,  0xfe,  0x80,  0x40,  0x20,  0x2c,  0x7a,  0x30,  0x15,  0xdf,  0x40,  0x21,  0x2c,  0xfe,  0x00,
-  0x40,  0x8d,  0x2c,  0x02,  0xfe,  0x08,  0x1c,  0x03,  0xfe,  0xac,  0x00,  0xfe,  0x06,  0x58,  0x03,  0xfe,
-  0xae,  0x00,  0xfe,  0x07,  0x58,  0x03,  0xfe,  0xb0,  0x00,  0xfe,  0x08,  0x58,  0x03,  0xfe,  0xb2,  0x00,
-  0xfe,  0x09,  0x58,  0xfe,  0x0a,  0x1c,  0x2e,  0x49,  0x20,  0xe0,  0x26,  0x10,  0x66,  0x10,  0x55,  0x10,
-  0x6f,  0x13,  0x57,  0x52,  0x4f,  0x1c,  0x28,  0xfe,  0x90,  0x4d,  0xfe,  0x91,  0x54,  0x2b,  0xfe,  0x88,
-  0x11,  0x46,  0x1a,  0x13,  0x5a,  0x52,  0x1c,  0x4a,  0xfe,  0x90,  0x4d,  0xfe,  0x91,  0x54,  0x2b,  0xfe,
-  0x9e,  0x11,  0x2e,  0x1a,  0x20,  0x2c,  0x90,  0x34,  0x60,  0x21,  0x2c,  0xfe,  0x00,  0x40,  0x8d,  0x2c,
-  0x15,  0xdf,  0xfe,  0x14,  0x56,  0xfe,  0xd6,  0xf0,  0xfe,  0xb2,  0x11,  0xfe,  0x12,  0x1c,  0x75,  0xfe,
-  0x14,  0x1c,  0xfe,  0x10,  0x1c,  0xfe,  0x18,  0x1c,  0x02,  0x51,  0xfe,  0x0c,  0x14,  0xfe,  0x0e,  0x47,
-  0xfe,  0x07,  0xe6,  0x28,  0xfe,  0xce,  0x47,  0xfe,  0xf5,  0x13,  0x02,  0x01,  0xa7,  0x90,  0x34,  0x60,
-  0xfe,  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x42,  0x13,  0xfe,  0x02,  0x80,  0x09,  0x56,  0xfe,  0x34,
-  0x13,  0x0a,  0x5a,  0x01,  0x18,  0xcb,  0xfe,  0x36,  0x12,  0xfe,  0x41,  0x48,  0xfe,  0x45,  0x48,  0x01,
-  0xfe,  0xb2,  0x16,  0xfe,  0x00,  0xcc,  0xcb,  0xfe,  0xf3,  0x13,  0x3f,  0x89,  0x09,  0x1a,  0xa5,  0x0a,
-  0x9d,  0x01,  0x18,  0xfe,  0x80,  0x5c,  0x01,  0x85,  0xf2,  0x09,  0x9b,  0xa4,  0xfe,  0x14,  0x56,  0xfe,
-  0xd6,  0xf0,  0xfe,  0xec,  0x11,  0x02,  0xfe,  0x44,  0x58,  0x77,  0xfe,  0x01,  0xec,  0xb8,  0xfe,  0x9e,
-  0x40,  0xfe,  0x9d,  0xe7,  0x00,  0xfe,  0x9c,  0xe7,  0x12,  0x8d,  0x30,  0x01,  0xf4,  0xfe,  0xdd,  0x10,
-  0x37,  0xd7,  0x99,  0xd8,  0x9c,  0x27,  0x25,  0xee,  0x09,  0x12,  0xfe,  0x48,  0x12,  0x09,  0x0d,  0xfe,
-  0x56,  0x12,  0x09,  0x1d,  0xfe,  0x30,  0x12,  0x09,  0xdd,  0x1b,  0xfe,  0xc4,  0x13,  0x09,  0xfe,  0x23,
-  0x00,  0x1b,  0xfe,  0xd0,  0x13,  0x09,  0x07,  0x1b,  0xfe,  0x34,  0x14,  0x09,  0x24,  0xfe,  0x12,  0x12,
-  0x09,  0x00,  0x1b,  0x29,  0x1f,  0xdd,  0x01,  0x42,  0xa1,  0x32,  0x01,  0x08,  0xae,  0x41,  0x02,  0x32,
-  0xfe,  0x62,  0x08,  0x0a,  0xe1,  0x01,  0xfe,  0x58,  0x10,  0x15,  0x9b,  0x05,  0x35,  0x32,  0x01,  0x43,
-  0x09,  0xbb,  0xfe,  0xd7,  0x13,  0x91,  0x4b,  0x7e,  0x4c,  0x8e,  0xfe,  0x80,  0x13,  0x01,  0x0c,  0x06,
-  0x54,  0xfe,  0x72,  0x12,  0xdb,  0x64,  0xdc,  0x34,  0xfe,  0x44,  0x55,  0xfe,  0xe5,  0x55,  0xb0,  0xfe,
-  0x4a,  0x13,  0x21,  0x6e,  0xfe,  0x26,  0x13,  0x03,  0x97,  0x3b,  0x98,  0x8e,  0xfe,  0xb6,  0x0e,  0x10,
-  0x6a,  0x22,  0x6b,  0x26,  0x10,  0x97,  0x10,  0x98,  0x01,  0xc2,  0x2e,  0x49,  0x88,  0x20,  0x6e,  0x01,
-  0xfe,  0x6a,  0x16,  0xdb,  0x64,  0xdc,  0x34,  0xfe,  0x04,  0x55,  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,
-  0x64,  0xfe,  0x05,  0xfa,  0x34,  0xfe,  0x8f,  0x10,  0x03,  0x6c,  0x3b,  0x6d,  0xfe,  0x40,  0x56,  0xfe,
-  0xe1,  0x56,  0x10,  0x6c,  0x22,  0x6d,  0x71,  0xdb,  0x64,  0xdc,  0x34,  0xfe,  0x44,  0x55,  0xfe,  0xe5,
-  0x55,  0x03,  0x68,  0x3b,  0x69,  0xfe,  0x00,  0x56,  0xfe,  0xa1,  0x56,  0x10,  0x68,  0x22,  0x69,  0x01,
-  0x0c,  0x06,  0x54,  0xf9,  0x21,  0x6e,  0xfe,  0x1f,  0x40,  0x03,  0x6a,  0x3b,  0x6b,  0xfe,  0x2c,  0x50,
-  0xfe,  0xae,  0x50,  0x03,  0x6c,  0x3b,  0x6d,  0xfe,  0x44,  0x50,  0xfe,  0xc6,  0x50,  0x03,  0x68,  0x3b,
-  0x69,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0x03,  0x4b,  0x3b,  0x4c,  0xfe,  0x40,  0x50,  0xfe,  0xc2,
-  0x50,  0x05,  0x73,  0x2e,  0x07,  0x20,  0x9e,  0x05,  0x72,  0x32,  0x01,  0x08,  0x16,  0x3d,  0x27,  0x25,
-  0xee,  0x09,  0x07,  0x2b,  0x3d,  0x01,  0x43,  0x09,  0xbb,  0x2b,  0x72,  0x01,  0xa6,  0x23,  0x3f,  0x1b,
-  0x3d,  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x1e,  0x13,  0x91,  0x4b,  0x7e,  0x4c,  0xfe,  0x0a,  0x55,  0x31,
-  0xfe,  0x8b,  0x55,  0xd9,  0x4b,  0xda,  0x4c,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0x05,  0x72,  0x01,
-  0xfe,  0x8e,  0x1e,  0xca,  0xfe,  0x19,  0x41,  0x05,  0x72,  0x32,  0x01,  0x08,  0x2a,  0x3c,  0x16,  0xc0,
-  0x27,  0x25,  0xbe,  0x2d,  0x1d,  0xc0,  0x2d,  0x0d,  0x83,  0x2d,  0x7f,  0x1b,  0xfe,  0x66,  0x15,  0x05,
-  0x3d,  0x01,  0x08,  0x2a,  0x3c,  0x16,  0xc0,  0x27,  0x25,  0xbd,  0x09,  0x1d,  0x2b,  0x3d,  0x01,  0x08,
-  0x16,  0xc0,  0x27,  0x25,  0xfe,  0xe8,  0x09,  0xfe,  0xc2,  0x49,  0x50,  0x03,  0xb6,  0x1e,  0x83,  0x01,
-  0x38,  0x06,  0x24,  0x31,  0xa1,  0xfe,  0xbb,  0x45,  0x2d,  0x00,  0xa4,  0x46,  0x07,  0x90,  0x3f,  0x01,
-  0xfe,  0xf8,  0x15,  0x01,  0xa6,  0x86,  0xfe,  0x4b,  0x45,  0xfe,  0x20,  0x13,  0x01,  0x43,  0x09,  0x82,
-  0xfe,  0x16,  0x13,  0x03,  0x9a,  0x1e,  0x5d,  0x03,  0x55,  0x1e,  0x31,  0x5e,  0x05,  0x72,  0xfe,  0xc0,
-  0x5d,  0x01,  0xa7,  0xfe,  0x03,  0x17,  0x03,  0x66,  0x8a,  0x10,  0x66,  0x5e,  0x32,  0x01,  0x08,  0x17,
-  0x73,  0x01,  0xfe,  0x56,  0x19,  0x05,  0x73,  0x01,  0x08,  0x2a,  0x3c,  0x16,  0x3d,  0x27,  0x25,  0xbd,
-  0x09,  0x07,  0x2b,  0x3d,  0x01,  0xfe,  0xbe,  0x16,  0xfe,  0x42,  0x58,  0xfe,  0xe8,  0x14,  0x01,  0xa6,
-  0x86,  0xfe,  0x4a,  0xf4,  0x0d,  0x1b,  0x3d,  0xfe,  0x4a,  0xf4,  0x07,  0xfe,  0x0e,  0x12,  0x01,  0x43,
-  0x09,  0x82,  0x4e,  0x05,  0x72,  0x03,  0x55,  0x8a,  0x10,  0x55,  0x5e,  0x32,  0x01,  0x08,  0x17,  0x73,
-  0x01,  0xfe,  0x84,  0x19,  0x05,  0x73,  0x01,  0x08,  0x2a,  0x3c,  0x16,  0x3d,  0x27,  0x25,  0xbd,  0x09,
-  0x12,  0x2b,  0x3d,  0x01,  0xfe,  0xe8,  0x17,  0x8b,  0xfe,  0xaa,  0x14,  0xfe,  0xb6,  0x14,  0x86,  0xa8,
-  0xb2,  0x0d,  0x1b,  0x3d,  0xb2,  0x07,  0xfe,  0x0e,  0x12,  0x01,  0x43,  0x09,  0x82,  0x4e,  0x05,  0x72,
-  0x03,  0x6f,  0x8a,  0x10,  0x6f,  0x5e,  0x32,  0x01,  0x08,  0x17,  0x73,  0x01,  0xfe,  0xc0,  0x19,  0x05,
-  0x73,  0x13,  0x07,  0x2f,  0xfe,  0xcc,  0x15,  0x17,  0xfe,  0xe2,  0x15,  0x5f,  0xcc,  0x01,  0x08,  0x26,
-  0x5f,  0x02,  0x8f,  0xfe,  0xde,  0x15,  0x2a,  0xfe,  0xde,  0x15,  0x16,  0xfe,  0xcc,  0x15,  0x5e,  0x32,
-  0x01,  0x08,  0xfe,  0xd5,  0x10,  0x13,  0x58,  0xff,  0x02,  0x00,  0x57,  0x52,  0xad,  0x23,  0xfe,  0xff,
-  0x7f,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x02,  0x13,  0x58,  0xff,  0x02,  0x00,  0x57,  0x52,  0xad,
-  0x23,  0x3f,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x02,  0x13,  0x58,  0xff,  0x02,  0x00,  0x57,  0x52,
-  0xad,  0x02,  0x13,  0x58,  0xff,  0x02,  0x00,  0x57,  0x52,  0xfe,  0x00,  0x5e,  0x02,  0x13,  0x58,  0xff,
-  0x02,  0x00,  0x57,  0x52,  0xad,  0xfe,  0x0b,  0x58,  0x02,  0x0a,  0x66,  0x01,  0x5c,  0x0a,  0x55,  0x01,
-  0x5c,  0x0a,  0x6f,  0x01,  0x5c,  0x02,  0x01,  0xfe,  0x1e,  0x1f,  0x23,  0x1a,  0xff,  0x03,  0x00,  0x54,
-  0xfe,  0x00,  0xf4,  0x24,  0x52,  0x0f,  0xfe,  0x00,  0x7c,  0x04,  0xfe,  0x07,  0x7c,  0x3a,  0x0b,  0x0e,
-  0xfe,  0x00,  0x71,  0xfe,  0xf9,  0x18,  0xfe,  0x7a,  0x19,  0xfe,  0xfb,  0x19,  0xfe,  0x1a,  0xf7,  0x00,
-  0xfe,  0x1b,  0xf7,  0x00,  0x7a,  0x30,  0x10,  0x68,  0x22,  0x69,  0xd9,  0x6c,  0xda,  0x6d,  0x02,  0xfe,
-  0x62,  0x08,  0xfe,  0x82,  0x4a,  0xfe,  0xe1,  0x1a,  0xfe,  0x83,  0x5a,  0x77,  0x02,  0x01,  0xc6,  0xfe,
-  0x42,  0x48,  0x4f,  0x50,  0x45,  0x01,  0x08,  0x16,  0xfe,  0xe0,  0x17,  0x27,  0x25,  0xbe,  0x01,  0x08,
-  0x16,  0xfe,  0xe0,  0x17,  0x27,  0x25,  0xfe,  0xe8,  0x0a,  0xfe,  0xc1,  0x59,  0x03,  0x9a,  0x1e,  0xfe,
-  0xda,  0x12,  0x01,  0x38,  0x06,  0x12,  0xfe,  0xd0,  0x13,  0x26,  0x53,  0x12,  0x48,  0xfe,  0x08,  0x17,
-  0xd1,  0x12,  0x53,  0x12,  0xfe,  0x1e,  0x13,  0x2d,  0xb4,  0x7b,  0xfe,  0x26,  0x17,  0x4d,  0x13,  0x07,
-  0x1c,  0xb4,  0x90,  0x04,  0xfe,  0x78,  0x10,  0xff,  0x02,  0x83,  0x55,  0xf1,  0xff,  0x02,  0x83,  0x55,
-  0x53,  0x1d,  0xfe,  0x12,  0x13,  0xd6,  0xfe,  0x30,  0x00,  0xb0,  0xfe,  0x80,  0x17,  0x1c,  0x63,  0x13,
-  0x07,  0xfe,  0x56,  0x10,  0x53,  0x0d,  0xfe,  0x16,  0x13,  0xd6,  0xfe,  0x64,  0x00,  0xb0,  0xfe,  0x80,
-  0x17,  0x0a,  0xfe,  0x64,  0x00,  0x1c,  0x94,  0x13,  0x07,  0xfe,  0x28,  0x10,  0x53,  0x07,  0xfe,  0x60,
-  0x13,  0xd6,  0xfe,  0xc8,  0x00,  0xb0,  0xfe,  0x80,  0x17,  0x0a,  0xfe,  0xc8,  0x00,  0x1c,  0x95,  0x13,
-  0x07,  0x71,  0xd6,  0xfe,  0x90,  0x01,  0x48,  0xfe,  0x8c,  0x17,  0x45,  0xf3,  0xfe,  0x43,  0xf4,  0x96,
-  0xfe,  0x56,  0xf0,  0xfe,  0x9e,  0x17,  0xfe,  0x04,  0xf4,  0x58,  0xfe,  0x43,  0xf4,  0x94,  0xf6,  0x8b,
-  0x01,  0xfe,  0x24,  0x16,  0x23,  0x3f,  0xfc,  0xa8,  0x8c,  0x49,  0x48,  0xfe,  0xda,  0x17,  0x62,  0x49,
-  0xfe,  0x1c,  0x10,  0xa8,  0x8c,  0x80,  0x48,  0xfe,  0xda,  0x17,  0x62,  0x80,  0x71,  0x50,  0x26,  0xfe,
-  0x4d,  0xf4,  0x00,  0xf7,  0x45,  0x13,  0x07,  0xfe,  0xb4,  0x56,  0xfe,  0xc3,  0x58,  0x02,  0x50,  0x13,
-  0x0d,  0x02,  0x50,  0x3e,  0x78,  0x4f,  0x45,  0x01,  0x08,  0x16,  0xa9,  0x27,  0x25,  0xbe,  0xfe,  0x03,
-  0xea,  0xfe,  0x7e,  0x01,  0x01,  0x08,  0x16,  0xa9,  0x27,  0x25,  0xfe,  0xe9,  0x0a,  0x01,  0x08,  0x16,
-  0xa9,  0x27,  0x25,  0xfe,  0xe9,  0x0a,  0xfe,  0x05,  0xea,  0xfe,  0x7f,  0x01,  0x01,  0x08,  0x16,  0xa9,
-  0x27,  0x25,  0xfe,  0x69,  0x09,  0xfe,  0x02,  0xea,  0xfe,  0x80,  0x01,  0x01,  0x08,  0x16,  0xa9,  0x27,
-  0x25,  0xfe,  0xe8,  0x08,  0x47,  0xfe,  0x81,  0x01,  0x03,  0xb6,  0x1e,  0x83,  0x01,  0x38,  0x06,  0x24,
-  0x31,  0xa2,  0x78,  0xf2,  0x53,  0x07,  0x36,  0xfe,  0x34,  0xf4,  0x3f,  0xa1,  0x78,  0x03,  0x9a,  0x1e,
-  0x83,  0x01,  0x38,  0x06,  0x12,  0x31,  0xf0,  0x4f,  0x45,  0xfe,  0x90,  0x10,  0xfe,  0x40,  0x5a,  0x23,
-  0x3f,  0xfb,  0x8c,  0x49,  0x48,  0xfe,  0xaa,  0x18,  0x62,  0x49,  0x71,  0x8c,  0x80,  0x48,  0xfe,  0xaa,
-  0x18,  0x62,  0x80,  0xfe,  0xb4,  0x56,  0xfe,  0x40,  0x5d,  0x01,  0xc6,  0x01,  0xfe,  0xac,  0x1d,  0xfe,
-  0x02,  0x17,  0xfe,  0xc8,  0x45,  0xfe,  0x5a,  0xf0,  0xfe,  0xc0,  0x18,  0xfe,  0x43,  0x48,  0x2d,  0x93,
-  0x36,  0xfe,  0x34,  0xf4,  0xfe,  0x00,  0x11,  0xfe,  0x40,  0x10,  0x2d,  0xb4,  0x36,  0xfe,  0x34,  0xf4,
-  0x04,  0xfe,  0x34,  0x10,  0x2d,  0xfe,  0x0b,  0x00,  0x36,  0x46,  0x63,  0xfe,  0x28,  0x10,  0xfe,  0xc0,
-  0x49,  0xff,  0x02,  0x00,  0x54,  0xb2,  0xfe,  0x90,  0x01,  0x48,  0xfe,  0xfa,  0x18,  0x45,  0xfe,  0x1c,
-  0xf4,  0x3f,  0xf3,  0xfe,  0x40,  0xf4,  0x96,  0xfe,  0x56,  0xf0,  0xfe,  0x0c,  0x19,  0xfe,  0x04,  0xf4,
-  0x58,  0xfe,  0x40,  0xf4,  0x94,  0xf6,  0x3e,  0x2d,  0x93,  0x4e,  0xd0,  0x0d,  0x21,  0xfe,  0x7f,  0x01,
-  0xfe,  0xc8,  0x46,  0xfe,  0x24,  0x13,  0x8c,  0x00,  0x5d,  0x26,  0x21,  0xfe,  0x7e,  0x01,  0xfe,  0xc8,
-  0x45,  0xfe,  0x14,  0x13,  0x21,  0xfe,  0x80,  0x01,  0xfe,  0x48,  0x45,  0xfa,  0x21,  0xfe,  0x81,  0x01,
-  0xfe,  0xc8,  0x44,  0x4e,  0x26,  0x02,  0x13,  0x07,  0x02,  0x78,  0x45,  0x50,  0x13,  0x0d,  0x02,  0x14,
-  0x07,  0x01,  0x08,  0x17,  0xfe,  0x82,  0x19,  0x14,  0x0d,  0x01,  0x08,  0x17,  0xfe,  0x82,  0x19,  0x14,
-  0x1d,  0x01,  0x08,  0x17,  0xfe,  0x82,  0x19,  0x5f,  0xfe,  0x89,  0x49,  0x01,  0x08,  0x02,  0x14,  0x07,
-  0x01,  0x08,  0x17,  0xc1,  0x14,  0x1d,  0x01,  0x08,  0x17,  0xc1,  0x14,  0x07,  0x01,  0x08,  0x17,  0xc1,
-  0xfe,  0x89,  0x49,  0x01,  0x08,  0x17,  0xc1,  0x5f,  0xfe,  0x89,  0x4a,  0x01,  0x08,  0x02,  0x50,  0x02,
-  0x14,  0x07,  0x01,  0x08,  0x17,  0x74,  0x14,  0x7f,  0x01,  0x08,  0x17,  0x74,  0x14,  0x12,  0x01,  0x08,
-  0x17,  0x74,  0xfe,  0x89,  0x49,  0x01,  0x08,  0x17,  0x74,  0x14,  0x00,  0x01,  0x08,  0x17,  0x74,  0xfe,
-  0x89,  0x4a,  0x01,  0x08,  0x17,  0x74,  0xfe,  0x09,  0x49,  0x01,  0x08,  0x17,  0x74,  0x5f,  0xcc,  0x01,
-  0x08,  0x02,  0x21,  0xe4,  0x09,  0x07,  0xfe,  0x4c,  0x13,  0xc8,  0x20,  0xe4,  0xfe,  0x49,  0xf4,  0x00,
-  0x4d,  0x5f,  0xa1,  0x5e,  0xfe,  0x01,  0xec,  0xfe,  0x27,  0x01,  0xcc,  0xff,  0x02,  0x00,  0x10,  0x2f,
-  0xfe,  0x3e,  0x1a,  0x01,  0x43,  0x09,  0xfe,  0xe3,  0x00,  0xfe,  0x22,  0x13,  0x16,  0xfe,  0x64,  0x1a,
-  0x26,  0x20,  0x9e,  0x01,  0x41,  0x21,  0x9e,  0x09,  0x07,  0x5d,  0x01,  0x0c,  0x61,  0x07,  0x44,  0x02,
-  0x0a,  0x5a,  0x01,  0x18,  0xfe,  0x00,  0x40,  0xaa,  0x09,  0x1a,  0xfe,  0x12,  0x13,  0x0a,  0x9d,  0x01,
-  0x18,  0xaa,  0x0a,  0x67,  0x01,  0xa3,  0x02,  0x0a,  0x9d,  0x01,  0x18,  0xaa,  0xfe,  0x80,  0xe7,  0x1a,
-  0x09,  0x1a,  0x5d,  0xfe,  0x45,  0x58,  0x01,  0xfe,  0xb2,  0x16,  0xaa,  0x02,  0x0a,  0x5a,  0x01,  0x18,
-  0xaa,  0x0a,  0x67,  0x01,  0xa3,  0x02,  0x0a,  0x5a,  0x01,  0x18,  0x01,  0xfe,  0x7e,  0x1e,  0xfe,  0x80,
-  0x4c,  0xfe,  0x49,  0xe4,  0x1a,  0xfe,  0x12,  0x13,  0x0a,  0x9d,  0x01,  0x18,  0xfe,  0x80,  0x4c,  0x0a,
-  0x67,  0x01,  0x5c,  0x02,  0x1c,  0x1a,  0x87,  0x7c,  0xe5,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,
-  0x24,  0x1c,  0xfe,  0x1d,  0xf7,  0x28,  0xb1,  0xfe,  0x04,  0x1b,  0x01,  0xfe,  0x2a,  0x1c,  0xfa,  0xb3,
-  0x28,  0x7c,  0xfe,  0x2c,  0x01,  0xfe,  0x2f,  0x19,  0x02,  0xc9,  0x2b,  0xfe,  0xf4,  0x1a,  0xfe,  0xfa,
-  0x10,  0x1c,  0x1a,  0x87,  0x03,  0xfe,  0x64,  0x01,  0xfe,  0x00,  0xf4,  0x24,  0xfe,  0x18,  0x58,  0x03,
-  0xfe,  0x66,  0x01,  0xfe,  0x19,  0x58,  0xb3,  0x24,  0x01,  0xfe,  0x0e,  0x1f,  0xfe,  0x30,  0xf4,  0x07,
-  0xfe,  0x3c,  0x50,  0x7c,  0xfe,  0x38,  0x00,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0x24,  0xb1,  0xfe,
-  0x50,  0x1b,  0xfe,  0xd4,  0x14,  0x31,  0x02,  0xc9,  0x2b,  0xfe,  0x26,  0x1b,  0xfe,  0xba,  0x10,  0x1c,
-  0x1a,  0x87,  0xfe,  0x83,  0x5a,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x1d,  0xf7,  0x54,  0xb1,
-  0xfe,  0x72,  0x1b,  0xfe,  0xb2,  0x14,  0xfc,  0xb3,  0x54,  0x7c,  0x12,  0xfe,  0xaf,  0x19,  0xfe,  0x98,
-  0xe7,  0x00,  0x02,  0xc9,  0x2b,  0xfe,  0x66,  0x1b,  0xfe,  0x8a,  0x10,  0x1c,  0x1a,  0x87,  0x8b,  0x0f,
-  0xfe,  0x30,  0x90,  0x04,  0xfe,  0xb0,  0x93,  0x3a,  0x0b,  0xfe,  0x18,  0x58,  0xfe,  0x32,  0x90,  0x04,
-  0xfe,  0xb2,  0x93,  0x3a,  0x0b,  0xfe,  0x19,  0x58,  0x0e,  0xa8,  0xb3,  0x4a,  0x7c,  0x12,  0xfe,  0x0f,
-  0x79,  0xfe,  0x1c,  0xf7,  0x4a,  0xb1,  0xfe,  0xc6,  0x1b,  0xfe,  0x5e,  0x14,  0x31,  0x02,  0xc9,  0x2b,
-  0xfe,  0x96,  0x1b,  0x5c,  0xfe,  0x02,  0xf6,  0x1a,  0x87,  0xfe,  0x18,  0xfe,  0x6a,  0xfe,  0x19,  0xfe,
-  0x6b,  0x01,  0xfe,  0x1e,  0x1f,  0xfe,  0x1d,  0xf7,  0x65,  0xb1,  0xfe,  0xee,  0x1b,  0xfe,  0x36,  0x14,
-  0xfe,  0x1c,  0x13,  0xb3,  0x65,  0x3e,  0xfe,  0x83,  0x58,  0xfe,  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x1a,
-  0xfe,  0x81,  0xe7,  0x1a,  0x15,  0xfe,  0xdd,  0x00,  0x7a,  0x30,  0x02,  0x7a,  0x30,  0xfe,  0x12,  0x45,
-  0x2b,  0xfe,  0xdc,  0x1b,  0x1f,  0x07,  0x47,  0xb5,  0xc3,  0x05,  0x35,  0xfe,  0x39,  0xf0,  0x75,  0x26,
-  0x02,  0xfe,  0x7e,  0x18,  0x23,  0x1d,  0x36,  0x13,  0x11,  0x02,  0x87,  0x03,  0xe3,  0x23,  0x07,  0xfe,
-  0xef,  0x12,  0xfe,  0xe1,  0x10,  0x90,  0x34,  0x60,  0xfe,  0x02,  0x80,  0x09,  0x56,  0xfe,  0x3c,  0x13,
-  0xfe,  0x82,  0x14,  0xfe,  0x42,  0x13,  0x51,  0xfe,  0x06,  0x83,  0x0a,  0x5a,  0x01,  0x18,  0xcb,  0xfe,
-  0x3e,  0x12,  0xfe,  0x41,  0x48,  0xfe,  0x45,  0x48,  0x01,  0xfe,  0xb2,  0x16,  0xfe,  0x00,  0xcc,  0xcb,
-  0xfe,  0xf3,  0x13,  0x3f,  0x89,  0x09,  0x1a,  0xa5,  0x0a,  0x9d,  0x01,  0x18,  0xfe,  0x80,  0x4c,  0x01,
-  0x85,  0xfe,  0x16,  0x10,  0x09,  0x9b,  0x4e,  0xfe,  0x40,  0x14,  0xfe,  0x24,  0x12,  0xfe,  0x14,  0x56,
-  0xfe,  0xd6,  0xf0,  0xfe,  0x52,  0x1c,  0x1c,  0x0d,  0x02,  0xfe,  0x9c,  0xe7,  0x0d,  0x19,  0xfe,  0x15,
-  0x00,  0x40,  0x8d,  0x30,  0x01,  0xf4,  0x1c,  0x07,  0x02,  0x51,  0xfe,  0x06,  0x83,  0xfe,  0x18,  0x80,
-  0x61,  0x28,  0x44,  0x15,  0x56,  0x01,  0x85,  0x1c,  0x07,  0x02,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,
-  0x91,  0xde,  0x7e,  0xdf,  0xfe,  0x48,  0x55,  0x31,  0xfe,  0xc9,  0x55,  0x02,  0x21,  0xb9,  0x88,  0x20,
-  0xb9,  0x02,  0x0a,  0xba,  0x01,  0x18,  0xfe,  0x41,  0x48,  0x0a,  0x57,  0x01,  0x18,  0xfe,  0x49,  0x44,
-  0x1b,  0xfe,  0x1e,  0x1d,  0x88,  0x89,  0x02,  0x0a,  0x5a,  0x01,  0x18,  0x09,  0x1a,  0xa4,  0x0a,  0x67,
-  0x01,  0xa3,  0x0a,  0x57,  0x01,  0x18,  0x88,  0x89,  0x02,  0xfe,  0x4e,  0xe4,  0x1d,  0x7b,  0xfe,  0x52,
-  0x1d,  0x03,  0xfe,  0x90,  0x00,  0xfe,  0x3a,  0x45,  0xfe,  0x2c,  0x10,  0xfe,  0x4e,  0xe4,  0xdd,  0x7b,
-  0xfe,  0x64,  0x1d,  0x03,  0xfe,  0x92,  0x00,  0xd1,  0x12,  0xfe,  0x1a,  0x10,  0xfe,  0x4e,  0xe4,  0xfe,
-  0x0b,  0x00,  0x7b,  0xfe,  0x76,  0x1d,  0x03,  0xfe,  0x94,  0x00,  0xd1,  0x24,  0xfe,  0x08,  0x10,  0x03,
-  0xfe,  0x96,  0x00,  0xd1,  0x63,  0xfe,  0x4e,  0x45,  0x83,  0xca,  0xff,  0x04,  0x68,  0x54,  0xfe,  0xf1,
-  0x10,  0x23,  0x49,  0xfe,  0x08,  0x1c,  0xfe,  0x67,  0x19,  0xfe,  0x0a,  0x1c,  0xfe,  0x1a,  0xf4,  0xfe,
-  0x00,  0x04,  0x83,  0xb2,  0x1d,  0x48,  0xfe,  0xaa,  0x1d,  0x13,  0x1d,  0x02,  0x09,  0x92,  0xfe,  0x5a,
-  0xf0,  0xfe,  0xba,  0x1d,  0x2e,  0x93,  0xfe,  0x34,  0x10,  0x09,  0x12,  0xfe,  0x5a,  0xf0,  0xfe,  0xc8,
-  0x1d,  0x2e,  0xb4,  0xfe,  0x26,  0x10,  0x09,  0x1d,  0x36,  0x2e,  0x63,  0xfe,  0x1a,  0x10,  0x09,  0x0d,
-  0x36,  0x2e,  0x94,  0xf2,  0x09,  0x07,  0x36,  0x2e,  0x95,  0xa1,  0xc8,  0x02,  0x1f,  0x93,  0x01,  0x42,
-  0xfe,  0x04,  0xfe,  0x99,  0x03,  0x9c,  0x8b,  0x02,  0x2a,  0xfe,  0x1c,  0x1e,  0xfe,  0x14,  0xf0,  0x08,
-  0x2f,  0xfe,  0x0c,  0x1e,  0x2a,  0xfe,  0x1c,  0x1e,  0x8f,  0xfe,  0x1c,  0x1e,  0xfe,  0x82,  0xf0,  0xfe,
-  0x10,  0x1e,  0x02,  0x0f,  0x3f,  0x04,  0xfe,  0x80,  0x83,  0x33,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x18,
-  0x80,  0x04,  0xfe,  0x98,  0x83,  0x33,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x02,  0x80,  0x04,  0xfe,  0x82,
-  0x83,  0x33,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x06,  0x80,  0x04,  0xfe,  0x86,  0x83,  0x33,  0x0b,  0x0e,
-  0x02,  0x0f,  0xfe,  0x1b,  0x80,  0x04,  0xfe,  0x9b,  0x83,  0x33,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x04,
-  0x80,  0x04,  0xfe,  0x84,  0x83,  0x33,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x80,  0x80,  0x04,  0xfe,  0x80,
-  0x83,  0xfe,  0xc9,  0x47,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x19,  0x81,  0x04,  0xfe,  0x99,  0x83,  0xfe,
-  0xca,  0x47,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x06,  0x83,  0x04,  0xfe,  0x86,  0x83,  0xfe,  0xce,  0x47,
-  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x2c,  0x90,  0x04,  0xfe,  0xac,  0x93,  0x3a,  0x0b,  0x0e,  0x02,  0x0f,
-  0xfe,  0xae,  0x90,  0x04,  0xfe,  0xae,  0x93,  0x79,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x08,  0x90,  0x04,
-  0xfe,  0x88,  0x93,  0x3a,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x8a,  0x90,  0x04,  0xfe,  0x8a,  0x93,  0x79,
-  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x0c,  0x90,  0x04,  0xfe,  0x8c,  0x93,  0x3a,  0x0b,  0x0e,  0x02,  0x0f,
-  0xfe,  0x8e,  0x90,  0x04,  0xfe,  0x8e,  0x93,  0x79,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x3c,  0x90,  0x04,
-  0xfe,  0xbc,  0x93,  0x3a,  0x0b,  0x0e,  0x02,  0x8b,  0x0f,  0xfe,  0x03,  0x80,  0x04,  0xfe,  0x83,  0x83,
-  0x33,  0x0b,  0x77,  0x0e,  0xa8,  0x02,  0xff,  0x66,  0x00,  0x00,
+static unsigned char _adv_asc38C1600_buf[] = {
+	0x00, 0x00, 0x00, 0xf2, 0x00, 0x16, 0x00, 0xfc, 0x00, 0x10, 0x00, 0xf0,
+	0x18, 0xe4, 0x01, 0x00,
+	0x04, 0x1e, 0x48, 0xe4, 0x03, 0xf6, 0xf7, 0x13, 0x2e, 0x1e, 0x02, 0x00,
+	0x07, 0x17, 0xc0, 0x5f,
+	0x00, 0xfa, 0xff, 0xff, 0x04, 0x00, 0x00, 0xf6, 0x09, 0xe7, 0x82, 0xe7,
+	0x85, 0xf0, 0x86, 0xf0,
+	0x4e, 0x10, 0x9e, 0xe7, 0xff, 0x00, 0x55, 0xf0, 0x01, 0xf6, 0x03, 0x00,
+	0x98, 0x57, 0x01, 0xe6,
+	0x00, 0xea, 0x00, 0xec, 0x01, 0xfa, 0x18, 0xf4, 0x08, 0x00, 0xf0, 0x1d,
+	0x38, 0x54, 0x32, 0xf0,
+	0x10, 0x00, 0xc2, 0x0e, 0x1e, 0xf0, 0xd5, 0xf0, 0xbc, 0x00, 0x4b, 0xe4,
+	0x00, 0xe6, 0xb1, 0xf0,
+	0xb4, 0x00, 0x02, 0x13, 0x3e, 0x1c, 0xc8, 0x47, 0x3e, 0x00, 0xd8, 0x01,
+	0x06, 0x13, 0x0c, 0x1c,
+	0x5e, 0x1e, 0x00, 0x57, 0xc8, 0x57, 0x01, 0xfc, 0xbc, 0x0e, 0xa2, 0x12,
+	0xb9, 0x54, 0x00, 0x80,
+	0x62, 0x0a, 0x5a, 0x12, 0xc8, 0x15, 0x3e, 0x1e, 0x18, 0x40, 0xbd, 0x56,
+	0x03, 0xe6, 0x01, 0xea,
+	0x5c, 0xf0, 0x0f, 0x00, 0x20, 0x00, 0x6c, 0x01, 0x6e, 0x01, 0x04, 0x12,
+	0x04, 0x13, 0xbb, 0x55,
+	0x3c, 0x56, 0x3e, 0x57, 0x03, 0x58, 0x4a, 0xe4, 0x40, 0x00, 0xb6, 0x00,
+	0xbb, 0x00, 0xc0, 0x00,
+	0x00, 0x01, 0x01, 0x01, 0x3e, 0x01, 0x58, 0x0a, 0x44, 0x10, 0x0a, 0x12,
+	0x4c, 0x1c, 0x4e, 0x1c,
+	0x02, 0x4a, 0x30, 0xe4, 0x05, 0xe6, 0x0c, 0x00, 0x3c, 0x00, 0x80, 0x00,
+	0x24, 0x01, 0x3c, 0x01,
+	0x68, 0x01, 0x6a, 0x01, 0x70, 0x01, 0x72, 0x01, 0x74, 0x01, 0x76, 0x01,
+	0x78, 0x01, 0x7c, 0x01,
+	0xc6, 0x0e, 0x0c, 0x10, 0xac, 0x12, 0xae, 0x12, 0x16, 0x1a, 0x32, 0x1c,
+	0x6e, 0x1e, 0x02, 0x48,
+	0x3a, 0x55, 0xc9, 0x57, 0x02, 0xee, 0x5b, 0xf0, 0x03, 0xf7, 0x06, 0xf7,
+	0x03, 0xfc, 0x06, 0x00,
+	0x1e, 0x00, 0xbe, 0x00, 0xe1, 0x00, 0x0c, 0x12, 0x18, 0x1a, 0x70, 0x1a,
+	0x30, 0x1c, 0x38, 0x1c,
+	0x10, 0x44, 0x00, 0x4c, 0xb0, 0x57, 0x40, 0x5c, 0x4d, 0xe4, 0x04, 0xea,
+	0x5d, 0xf0, 0xa7, 0xf0,
+	0x04, 0xf6, 0x02, 0xfc, 0x05, 0x00, 0x09, 0x00, 0x19, 0x00, 0x32, 0x00,
+	0x33, 0x00, 0x34, 0x00,
+	0x36, 0x00, 0x98, 0x00, 0x9e, 0x00, 0xcc, 0x00, 0x20, 0x01, 0x4e, 0x01,
+	0x79, 0x01, 0x3c, 0x09,
+	0x68, 0x0d, 0x02, 0x10, 0x04, 0x10, 0x3a, 0x10, 0x08, 0x12, 0x0a, 0x13,
+	0x40, 0x16, 0x50, 0x16,
+	0x00, 0x17, 0x4a, 0x19, 0x00, 0x4e, 0x00, 0x54, 0x01, 0x58, 0x00, 0xdc,
+	0x05, 0xf0, 0x09, 0xf0,
+	0x59, 0xf0, 0xb8, 0xf0, 0x48, 0xf4, 0x0e, 0xf7, 0x0a, 0x00, 0x9b, 0x00,
+	0x9c, 0x00, 0xa4, 0x00,
+	0xb5, 0x00, 0xba, 0x00, 0xd0, 0x00, 0xe7, 0x00, 0xf0, 0x03, 0x69, 0x08,
+	0xe9, 0x09, 0x5c, 0x0c,
+	0xb6, 0x12, 0xbc, 0x19, 0xd8, 0x1b, 0x20, 0x1c, 0x34, 0x1c, 0x36, 0x1c,
+	0x42, 0x1d, 0x08, 0x44,
+	0x38, 0x44, 0x91, 0x44, 0x0a, 0x45, 0x48, 0x46, 0x89, 0x48, 0x68, 0x54,
+	0x83, 0x55, 0x83, 0x59,
+	0x31, 0xe4, 0x02, 0xe6, 0x07, 0xf0, 0x08, 0xf0, 0x0b, 0xf0, 0x0c, 0xf0,
+	0x4b, 0xf4, 0x04, 0xf8,
+	0x05, 0xf8, 0x02, 0xfa, 0x03, 0xfa, 0x04, 0xfc, 0x05, 0xfc, 0x07, 0x00,
+	0xa8, 0x00, 0xaa, 0x00,
+	0xb9, 0x00, 0xe0, 0x00, 0xe5, 0x00, 0x22, 0x01, 0x26, 0x01, 0x60, 0x01,
+	0x7a, 0x01, 0x82, 0x01,
+	0xc8, 0x01, 0xca, 0x01, 0x86, 0x02, 0x6a, 0x03, 0x18, 0x05, 0xb2, 0x07,
+	0x68, 0x08, 0x10, 0x0d,
+	0x06, 0x10, 0x0a, 0x10, 0x0e, 0x10, 0x12, 0x10, 0x60, 0x10, 0xed, 0x10,
+	0xf3, 0x10, 0x06, 0x12,
+	0x10, 0x12, 0x1e, 0x12, 0x0c, 0x13, 0x0e, 0x13, 0x10, 0x13, 0xfe, 0x9c,
+	0xf0, 0x35, 0x05, 0xfe,
+	0xec, 0x0e, 0xff, 0x10, 0x00, 0x00, 0xe9, 0xfe, 0x34, 0x1f, 0x00, 0xe8,
+	0xfe, 0x88, 0x01, 0xff,
+	0x03, 0x00, 0x00, 0xfe, 0x93, 0x15, 0xfe, 0x0f, 0x05, 0xff, 0x38, 0x00,
+	0x00, 0xfe, 0x57, 0x24,
+	0x00, 0xfe, 0x4c, 0x00, 0x65, 0xff, 0x04, 0x00, 0x00, 0x1a, 0xff, 0x09,
+	0x00, 0x00, 0xff, 0x08,
+	0x01, 0x01, 0xff, 0x08, 0xff, 0xff, 0xff, 0x27, 0x00, 0x00, 0xff, 0x10,
+	0xff, 0xff, 0xff, 0x13,
+	0x00, 0x00, 0xfe, 0x78, 0x56, 0xfe, 0x34, 0x12, 0xff, 0x21, 0x00, 0x00,
+	0xfe, 0x04, 0xf7, 0xe8,
+	0x37, 0x7d, 0x0d, 0x01, 0xfe, 0x4a, 0x11, 0xfe, 0x04, 0xf7, 0xe8, 0x7d,
+	0x0d, 0x51, 0x37, 0xfe,
+	0x3d, 0xf0, 0xfe, 0x0c, 0x02, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x91, 0xf0,
+	0xfe, 0xf8, 0x01, 0xfe,
+	0x90, 0xf0, 0xfe, 0xf8, 0x01, 0xfe, 0x8f, 0xf0, 0xbc, 0x03, 0x67, 0x4d,
+	0x05, 0xfe, 0x08, 0x0f,
+	0x01, 0xfe, 0x78, 0x0f, 0xfe, 0xdd, 0x12, 0x05, 0xfe, 0x0e, 0x03, 0xfe,
+	0x28, 0x1c, 0x03, 0xfe,
+	0xa6, 0x00, 0xfe, 0xd1, 0x12, 0x3e, 0x22, 0xfe, 0xa6, 0x00, 0xac, 0xfe,
+	0x48, 0xf0, 0xfe, 0x90,
+	0x02, 0xfe, 0x49, 0xf0, 0xfe, 0xaa, 0x02, 0xfe, 0x4a, 0xf0, 0xfe, 0xc8,
+	0x02, 0xfe, 0x46, 0xf0,
+	0xfe, 0x5a, 0x02, 0xfe, 0x47, 0xf0, 0xfe, 0x60, 0x02, 0xfe, 0x43, 0xf0,
+	0xfe, 0x4e, 0x02, 0xfe,
+	0x44, 0xf0, 0xfe, 0x52, 0x02, 0xfe, 0x45, 0xf0, 0xfe, 0x56, 0x02, 0x1c,
+	0x0d, 0xa2, 0x1c, 0x07,
+	0x22, 0xb7, 0x05, 0x35, 0xfe, 0x00, 0x1c, 0xfe, 0xf1, 0x10, 0xfe, 0x02,
+	0x1c, 0xf5, 0xfe, 0x1e,
+	0x1c, 0xfe, 0xe9, 0x10, 0x01, 0x5f, 0xfe, 0xe7, 0x10, 0xfe, 0x06, 0xfc,
+	0xde, 0x0a, 0x81, 0x01,
+	0xa3, 0x05, 0x35, 0x1f, 0x95, 0x47, 0xb8, 0x01, 0xfe, 0xe4, 0x11, 0x0a,
+	0x81, 0x01, 0x5c, 0xfe,
+	0xbd, 0x10, 0x0a, 0x81, 0x01, 0x5c, 0xfe, 0xad, 0x10, 0xfe, 0x16, 0x1c,
+	0xfe, 0x58, 0x1c, 0x1c,
+	0x07, 0x22, 0xb7, 0x37, 0x2a, 0x35, 0xfe, 0x3d, 0xf0, 0xfe, 0x0c, 0x02,
+	0x2b, 0xfe, 0x9e, 0x02,
+	0xfe, 0x5a, 0x1c, 0xfe, 0x12, 0x1c, 0xfe, 0x14, 0x1c, 0x1f, 0xfe, 0x30,
+	0x00, 0x47, 0xb8, 0x01,
+	0xfe, 0xd4, 0x11, 0x1c, 0x07, 0x22, 0xb7, 0x05, 0xe9, 0x21, 0x2c, 0x09,
+	0x1a, 0x31, 0xfe, 0x69,
+	0x10, 0x1c, 0x07, 0x22, 0xb7, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0x01, 0xfe,
+	0x1e, 0x1e, 0x20, 0x2c,
+	0xfe, 0x05, 0xf6, 0xde, 0x01, 0xfe, 0x62, 0x1b, 0x01, 0x0c, 0x61, 0x4a,
+	0x44, 0x15, 0x56, 0x51,
+	0x01, 0xfe, 0x9e, 0x1e, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x0a, 0x57,
+	0x01, 0x18, 0x09, 0x00,
+	0x36, 0x01, 0x85, 0xfe, 0x18, 0x10, 0xfe, 0x41, 0x58, 0x0a, 0xba, 0x01,
+	0x18, 0xfe, 0xc8, 0x54,
+	0x7b, 0xfe, 0x1c, 0x03, 0x01, 0xfe, 0x96, 0x1a, 0x05, 0x35, 0x37, 0x60,
+	0xfe, 0x02, 0xe8, 0x30,
+	0xfe, 0xbf, 0x57, 0xfe, 0x9e, 0x43, 0xfe, 0x77, 0x57, 0xfe, 0x27, 0xf0,
+	0xfe, 0xe4, 0x01, 0xfe,
+	0x07, 0x4b, 0xfe, 0x20, 0xf0, 0xbc, 0xfe, 0x40, 0x1c, 0x2a, 0xeb, 0xfe,
+	0x26, 0xf0, 0xfe, 0x66,
+	0x03, 0xfe, 0xa0, 0xf0, 0xfe, 0x54, 0x03, 0xfe, 0x11, 0xf0, 0xbc, 0xfe,
+	0xef, 0x10, 0xfe, 0x9f,
+	0xf0, 0xfe, 0x74, 0x03, 0xfe, 0x46, 0x1c, 0x19, 0xfe, 0x11, 0x00, 0x05,
+	0x70, 0x37, 0xfe, 0x48,
+	0x1c, 0xfe, 0x46, 0x1c, 0x01, 0x0c, 0x06, 0x28, 0xfe, 0x18, 0x13, 0x26,
+	0x21, 0xb9, 0xc7, 0x20,
+	0xb9, 0x0a, 0x57, 0x01, 0x18, 0xc7, 0x89, 0x01, 0xfe, 0xc8, 0x1a, 0x15,
+	0xe1, 0x2a, 0xeb, 0xfe,
+	0x01, 0xf0, 0xeb, 0xfe, 0x82, 0xf0, 0xfe, 0xa4, 0x03, 0xfe, 0x9c, 0x32,
+	0x15, 0xfe, 0xe4, 0x00,
+	0x2f, 0xfe, 0xb6, 0x03, 0x2a, 0x3c, 0x16, 0xfe, 0xc6, 0x03, 0x01, 0x41,
+	0xfe, 0x06, 0xf0, 0xfe,
+	0xd6, 0x03, 0xaf, 0xa0, 0xfe, 0x0a, 0xf0, 0xfe, 0xa2, 0x07, 0x05, 0x29,
+	0x03, 0x81, 0x1e, 0x1b,
+	0xfe, 0x24, 0x05, 0x1f, 0x63, 0x01, 0x42, 0x8f, 0xfe, 0x70, 0x02, 0x05,
+	0xea, 0xfe, 0x46, 0x1c,
+	0x37, 0x7d, 0x1d, 0xfe, 0x67, 0x1b, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57,
+	0xfe, 0x48, 0x1c, 0x75,
+	0x01, 0xa6, 0x86, 0x0a, 0x57, 0x01, 0x18, 0x09, 0x00, 0x1b, 0xec, 0x0a,
+	0xe1, 0x01, 0x18, 0x77,
+	0x50, 0x40, 0x8d, 0x30, 0x03, 0x81, 0x1e, 0xf8, 0x1f, 0x63, 0x01, 0x42,
+	0x8f, 0xfe, 0x70, 0x02,
+	0x05, 0xea, 0xd7, 0x99, 0xd8, 0x9c, 0x2a, 0x29, 0x2f, 0xfe, 0x4e, 0x04,
+	0x16, 0xfe, 0x4a, 0x04,
+	0x7e, 0xfe, 0xa0, 0x00, 0xfe, 0x9b, 0x57, 0xfe, 0x54, 0x12, 0x32, 0xff,
+	0x02, 0x00, 0x10, 0x01,
+	0x08, 0x16, 0xfe, 0x02, 0x05, 0x32, 0x01, 0x08, 0x16, 0x29, 0x27, 0x25,
+	0xee, 0xfe, 0x4c, 0x44,
+	0xfe, 0x58, 0x12, 0x50, 0xfe, 0x44, 0x48, 0x13, 0x34, 0xfe, 0x4c, 0x54,
+	0x7b, 0xec, 0x60, 0x8d,
+	0x30, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x7c, 0x13, 0x01,
+	0x0c, 0x06, 0x28, 0xfe,
+	0x32, 0x13, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x68, 0x13, 0xfe, 0x26, 0x10,
+	0x13, 0x34, 0xfe, 0x4c,
+	0x54, 0x7b, 0xec, 0x01, 0xfe, 0x4e, 0x1e, 0xfe, 0x48, 0x47, 0xfe, 0x54,
+	0x13, 0x01, 0x0c, 0x06,
+	0x28, 0xa5, 0x01, 0x43, 0x09, 0x9b, 0xfe, 0x40, 0x13, 0x01, 0x0c, 0x06,
+	0x28, 0xf9, 0x1f, 0x7f,
+	0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe, 0x0d, 0x00, 0x01, 0x42, 0x8f,
+	0xfe, 0xa4, 0x0e, 0x05,
+	0x29, 0x32, 0x15, 0xfe, 0xe6, 0x00, 0x0f, 0xfe, 0x1c, 0x90, 0x04, 0xfe,
+	0x9c, 0x93, 0x3a, 0x0b,
+	0x0e, 0x8b, 0x02, 0x1f, 0x7f, 0x01, 0x42, 0x05, 0x35, 0xfe, 0x42, 0x5b,
+	0x7d, 0x1d, 0xfe, 0x46,
+	0x59, 0xfe, 0xbf, 0x57, 0xfe, 0x77, 0x57, 0x0f, 0xfe, 0x87, 0x80, 0x04,
+	0xfe, 0x87, 0x83, 0xfe,
+	0xc9, 0x47, 0x0b, 0x0e, 0xd0, 0x65, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x98,
+	0x13, 0x0f, 0xfe, 0x20,
+	0x80, 0x04, 0xfe, 0xa0, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x1d, 0xfe, 0x84,
+	0x12, 0x01, 0x38, 0x06,
+	0x07, 0xfe, 0x70, 0x13, 0x03, 0xfe, 0xa2, 0x00, 0x1e, 0x1b, 0xfe, 0xda,
+	0x05, 0xd0, 0x54, 0x01,
+	0x38, 0x06, 0x0d, 0xfe, 0x58, 0x13, 0x03, 0xfe, 0xa0, 0x00, 0x1e, 0xfe,
+	0x50, 0x12, 0x5e, 0xff,
+	0x02, 0x00, 0x10, 0x2f, 0xfe, 0x90, 0x05, 0x2a, 0x3c, 0xcc, 0xff, 0x02,
+	0x00, 0x10, 0x2f, 0xfe,
+	0x9e, 0x05, 0x17, 0xfe, 0xf4, 0x05, 0x15, 0xfe, 0xe3, 0x00, 0x26, 0x01,
+	0x38, 0xfe, 0x4a, 0xf0,
+	0xfe, 0xc0, 0x05, 0xfe, 0x49, 0xf0, 0xfe, 0xba, 0x05, 0x71, 0x2e, 0xfe,
+	0x21, 0x00, 0xf1, 0x2e,
+	0xfe, 0x22, 0x00, 0xa2, 0x2e, 0x4a, 0xfe, 0x09, 0x48, 0xff, 0x02, 0x00,
+	0x10, 0x2f, 0xfe, 0xd0,
+	0x05, 0x17, 0xfe, 0xf4, 0x05, 0xfe, 0xe2, 0x08, 0x01, 0x38, 0x06, 0xfe,
+	0x1c, 0x00, 0x4d, 0x01,
+	0xa7, 0x2e, 0x07, 0x20, 0xe4, 0x47, 0xfe, 0x27, 0x01, 0x01, 0x0c, 0x06,
+	0x28, 0xfe, 0x24, 0x12,
+	0x3e, 0x01, 0x84, 0x1f, 0x7f, 0x01, 0x0c, 0x06, 0x07, 0x4d, 0x1f, 0xfe,
+	0x0d, 0x00, 0x01, 0x42,
+	0x8f, 0xfe, 0xa4, 0x0e, 0x05, 0x29, 0x03, 0xe6, 0x1e, 0xfe, 0xca, 0x13,
+	0x03, 0xb6, 0x1e, 0xfe,
+	0x40, 0x12, 0x03, 0x66, 0x1e, 0xfe, 0x38, 0x13, 0x3e, 0x01, 0x84, 0x17,
+	0xfe, 0x72, 0x06, 0x0a,
+	0x07, 0x01, 0x38, 0x06, 0x24, 0xfe, 0x02, 0x12, 0x4f, 0x01, 0xfe, 0x56,
+	0x19, 0x16, 0xfe, 0x68,
+	0x06, 0x15, 0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x66, 0x8a, 0x10, 0x66,
+	0x03, 0x9a, 0x1e, 0xfe,
+	0x70, 0x12, 0x03, 0x55, 0x1e, 0xfe, 0x68, 0x13, 0x01, 0xc6, 0x09, 0x12,
+	0x48, 0xfe, 0x92, 0x06,
+	0x2e, 0x12, 0x01, 0xfe, 0xac, 0x1d, 0xfe, 0x43, 0x48, 0x62, 0x80, 0x13,
+	0x58, 0xff, 0x02, 0x00,
+	0x57, 0x52, 0xad, 0x23, 0x3f, 0x4e, 0x62, 0x49, 0x3e, 0x01, 0x84, 0x17,
+	0xfe, 0xea, 0x06, 0x01,
+	0x38, 0x06, 0x12, 0xf7, 0x45, 0x0a, 0x95, 0x01, 0xfe, 0x84, 0x19, 0x16,
+	0xfe, 0xe0, 0x06, 0x15,
+	0x82, 0x01, 0x41, 0x15, 0xe2, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x1c, 0x07,
+	0x01, 0x84, 0xfe, 0xae,
+	0x10, 0x03, 0x6f, 0x1e, 0xfe, 0x9e, 0x13, 0x3e, 0x01, 0x84, 0x03, 0x9a,
+	0x1e, 0xfe, 0x1a, 0x12,
+	0x01, 0x38, 0x06, 0x12, 0xfc, 0x01, 0xc6, 0x01, 0xfe, 0xac, 0x1d, 0xfe,
+	0x43, 0x48, 0x62, 0x80,
+	0xf0, 0x45, 0x0a, 0x95, 0x03, 0xb6, 0x1e, 0xf8, 0x01, 0x38, 0x06, 0x24,
+	0x36, 0xfe, 0x02, 0xf6,
+	0x07, 0x71, 0x78, 0x8c, 0x00, 0x4d, 0x62, 0x49, 0x3e, 0x2d, 0x93, 0x4e,
+	0xd0, 0x0d, 0x17, 0xfe,
+	0x9a, 0x07, 0x01, 0xfe, 0xc0, 0x19, 0x16, 0xfe, 0x90, 0x07, 0x26, 0x20,
+	0x9e, 0x15, 0x82, 0x01,
+	0x41, 0x15, 0xe2, 0x21, 0x9e, 0x09, 0x07, 0xfb, 0x03, 0xe6, 0xfe, 0x58,
+	0x57, 0x10, 0xe6, 0x05,
+	0xfe, 0x2a, 0x06, 0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x1c, 0x07, 0x01, 0x84,
+	0xfe, 0x9c, 0x32, 0x5f,
+	0x75, 0x01, 0xa6, 0x86, 0x15, 0xfe, 0xe2, 0x00, 0x2f, 0xed, 0x2a, 0x3c,
+	0xfe, 0x0a, 0xf0, 0xfe,
+	0xce, 0x07, 0xae, 0xfe, 0x96, 0x08, 0xfe, 0x06, 0xf0, 0xfe, 0x9e, 0x08,
+	0xaf, 0xa0, 0x05, 0x29,
+	0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x2e, 0x12, 0x14, 0x1d, 0x01, 0x08, 0x14,
+	0x00, 0x01, 0x08, 0x14,
+	0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0xfe, 0x99, 0xa4, 0x01, 0x08,
+	0x14, 0x00, 0x05, 0xfe,
+	0xc6, 0x09, 0x01, 0x76, 0x06, 0x12, 0xfe, 0x3a, 0x12, 0x01, 0x0c, 0x06,
+	0x12, 0xfe, 0x30, 0x13,
+	0x14, 0xfe, 0x1b, 0x00, 0x01, 0x08, 0x14, 0x00, 0x01, 0x08, 0x14, 0x00,
+	0x01, 0x08, 0x14, 0x00,
+	0x01, 0x08, 0x14, 0x07, 0x01, 0x08, 0x14, 0x00, 0x05, 0xef, 0x7c, 0x4a,
+	0x78, 0x4f, 0x0f, 0xfe,
+	0x9a, 0x81, 0x04, 0xfe, 0x9a, 0x83, 0xfe, 0xcb, 0x47, 0x0b, 0x0e, 0x2d,
+	0x28, 0x48, 0xfe, 0x6c,
+	0x08, 0x0a, 0x28, 0xfe, 0x09, 0x6f, 0xca, 0xfe, 0xca, 0x45, 0xfe, 0x32,
+	0x12, 0x53, 0x63, 0x4e,
+	0x7c, 0x97, 0x2f, 0xfe, 0x7e, 0x08, 0x2a, 0x3c, 0xfe, 0x0a, 0xf0, 0xfe,
+	0x6c, 0x08, 0xaf, 0xa0,
+	0xae, 0xfe, 0x96, 0x08, 0x05, 0x29, 0x01, 0x41, 0x05, 0xed, 0x14, 0x24,
+	0x05, 0xed, 0xfe, 0x9c,
+	0xf7, 0x9f, 0x01, 0xfe, 0xae, 0x1e, 0xfe, 0x18, 0x58, 0x01, 0xfe, 0xbe,
+	0x1e, 0xfe, 0x99, 0x58,
+	0xfe, 0x78, 0x18, 0xfe, 0xf9, 0x18, 0x8e, 0xfe, 0x16, 0x09, 0x10, 0x6a,
+	0x22, 0x6b, 0x01, 0x0c,
+	0x61, 0x54, 0x44, 0x21, 0x2c, 0x09, 0x1a, 0xf8, 0x77, 0x01, 0xfe, 0x7e,
+	0x1e, 0x47, 0x2c, 0x7a,
+	0x30, 0xf0, 0xfe, 0x83, 0xe7, 0xfe, 0x3f, 0x00, 0x71, 0xfe, 0x03, 0x40,
+	0x01, 0x0c, 0x61, 0x65,
+	0x44, 0x01, 0xc2, 0xc8, 0xfe, 0x1f, 0x40, 0x20, 0x6e, 0x01, 0xfe, 0x6a,
+	0x16, 0xfe, 0x08, 0x50,
+	0xfe, 0x8a, 0x50, 0xfe, 0x44, 0x51, 0xfe, 0xc6, 0x51, 0xfe, 0x10, 0x10,
+	0x01, 0xfe, 0xce, 0x1e,
+	0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x01, 0xfe, 0xee, 0x1e,
+	0x01, 0xfe, 0xfe, 0x1e,
+	0xfe, 0x40, 0x50, 0xfe, 0xc2, 0x50, 0x10, 0x4b, 0x22, 0x4c, 0xfe, 0x8a,
+	0x10, 0x01, 0x0c, 0x06,
+	0x54, 0xfe, 0x50, 0x12, 0x01, 0xfe, 0xae, 0x1e, 0x01, 0xfe, 0xbe, 0x1e,
+	0x10, 0x6a, 0x22, 0x6b,
+	0x01, 0x0c, 0x06, 0x65, 0x4e, 0x01, 0xc2, 0x0f, 0xfe, 0x1f, 0x80, 0x04,
+	0xfe, 0x9f, 0x83, 0x33,
+	0x0b, 0x0e, 0x20, 0x6e, 0x0f, 0xfe, 0x44, 0x90, 0x04, 0xfe, 0xc4, 0x93,
+	0x3a, 0x0b, 0xfe, 0xc6,
+	0x90, 0x04, 0xfe, 0xc6, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0x6c, 0x22, 0x6d,
+	0x01, 0xfe, 0xce, 0x1e,
+	0x01, 0xfe, 0xde, 0x1e, 0x10, 0x68, 0x22, 0x69, 0x0f, 0xfe, 0x40, 0x90,
+	0x04, 0xfe, 0xc0, 0x93,
+	0x3a, 0x0b, 0xfe, 0xc2, 0x90, 0x04, 0xfe, 0xc2, 0x93, 0x79, 0x0b, 0x0e,
+	0x10, 0x4b, 0x22, 0x4c,
+	0x10, 0x64, 0x22, 0x34, 0x01, 0x0c, 0x61, 0x24, 0x44, 0x37, 0x13, 0xfe,
+	0x4e, 0x11, 0x2f, 0xfe,
+	0xde, 0x09, 0xfe, 0x9e, 0xf0, 0xfe, 0xf2, 0x09, 0xfe, 0x01, 0x48, 0x1b,
+	0x3c, 0x37, 0x88, 0xf5,
+	0xd4, 0xfe, 0x1e, 0x0a, 0xd5, 0xfe, 0x42, 0x0a, 0xd2, 0xfe, 0x1e, 0x0a,
+	0xd3, 0xfe, 0x42, 0x0a,
+	0xae, 0xfe, 0x12, 0x0a, 0xfe, 0x06, 0xf0, 0xfe, 0x18, 0x0a, 0xaf, 0xa0,
+	0x05, 0x29, 0x01, 0x41,
+	0xfe, 0xc1, 0x10, 0x14, 0x24, 0xfe, 0xc1, 0x10, 0x01, 0x76, 0x06, 0x07,
+	0xfe, 0x14, 0x12, 0x01,
+	0x76, 0x06, 0x0d, 0x5d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x74, 0x12, 0xfe,
+	0x2e, 0x1c, 0x05, 0xfe,
+	0x1a, 0x0c, 0x01, 0x76, 0x06, 0x07, 0x5d, 0x01, 0x76, 0x06, 0x0d, 0x41,
+	0xfe, 0x2c, 0x1c, 0xfe,
+	0xaa, 0xf0, 0xfe, 0xce, 0x0a, 0xfe, 0xac, 0xf0, 0xfe, 0x66, 0x0a, 0xfe,
+	0x92, 0x10, 0xc4, 0xf6,
+	0xfe, 0xad, 0xf0, 0xfe, 0x72, 0x0a, 0x05, 0xfe, 0x1a, 0x0c, 0xc5, 0xfe,
+	0xe7, 0x10, 0xfe, 0x2b,
+	0xf0, 0xbf, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xfe, 0xfe, 0x1c, 0x12,
+	0xac, 0xfe, 0xd2, 0xf0,
+	0xbf, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x1b, 0xbf, 0x03, 0xe3, 0x23, 0x07,
+	0x1b, 0xbf, 0xd4, 0x5b,
+	0xd5, 0x5b, 0xd2, 0x5b, 0xd3, 0x5b, 0xc4, 0xc5, 0xfe, 0xa9, 0x10, 0x75,
+	0x5e, 0x32, 0x1f, 0x7f,
+	0x01, 0x42, 0x19, 0xfe, 0x35, 0x00, 0xfe, 0x01, 0xf0, 0x70, 0x19, 0x98,
+	0x05, 0x70, 0xfe, 0x74,
+	0x18, 0x23, 0xfe, 0x00, 0xf8, 0x1b, 0x5b, 0x7d, 0x12, 0x01, 0xfe, 0x78,
+	0x0f, 0x4d, 0x01, 0xfe,
+	0x96, 0x1a, 0x21, 0x30, 0x77, 0x7d, 0x1d, 0x05, 0x5b, 0x01, 0x0c, 0x06,
+	0x0d, 0x2b, 0xfe, 0xe2,
+	0x0b, 0x01, 0x0c, 0x06, 0x54, 0xfe, 0xa6, 0x12, 0x01, 0x0c, 0x06, 0x24,
+	0xfe, 0x88, 0x13, 0x21,
+	0x6e, 0xc7, 0x01, 0xfe, 0x1e, 0x1f, 0x0f, 0xfe, 0x83, 0x80, 0x04, 0xfe,
+	0x83, 0x83, 0xfe, 0xc9,
+	0x47, 0x0b, 0x0e, 0xfe, 0xc8, 0x44, 0xfe, 0x42, 0x13, 0x0f, 0xfe, 0x04,
+	0x91, 0x04, 0xfe, 0x84,
+	0x93, 0xfe, 0xca, 0x57, 0x0b, 0xfe, 0x86, 0x91, 0x04, 0xfe, 0x86, 0x93,
+	0xfe, 0xcb, 0x57, 0x0b,
+	0x0e, 0x7a, 0x30, 0xfe, 0x40, 0x59, 0xfe, 0xc1, 0x59, 0x8e, 0x40, 0x03,
+	0x6a, 0x3b, 0x6b, 0x10,
+	0x97, 0x22, 0x98, 0xd9, 0x6a, 0xda, 0x6b, 0x01, 0xc2, 0xc8, 0x7a, 0x30,
+	0x20, 0x6e, 0xdb, 0x64,
+	0xdc, 0x34, 0x91, 0x6c, 0x7e, 0x6d, 0xfe, 0x44, 0x55, 0xfe, 0xe5, 0x55,
+	0xfe, 0x04, 0xfa, 0x64,
+	0xfe, 0x05, 0xfa, 0x34, 0x01, 0xfe, 0x6a, 0x16, 0xa3, 0x26, 0x10, 0x97,
+	0x10, 0x98, 0x91, 0x6c,
+	0x7e, 0x6d, 0xfe, 0x14, 0x10, 0x01, 0x0c, 0x06, 0x24, 0x1b, 0x40, 0x91,
+	0x4b, 0x7e, 0x4c, 0x01,
+	0x0c, 0x06, 0xfe, 0xf7, 0x00, 0x44, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x10,
+	0x58, 0xfe, 0x91, 0x58,
+	0xfe, 0x14, 0x59, 0xfe, 0x95, 0x59, 0x05, 0x5b, 0x01, 0x0c, 0x06, 0x24,
+	0x1b, 0x40, 0x01, 0x0c,
+	0x06, 0xfe, 0xf7, 0x00, 0x44, 0x78, 0x01, 0xfe, 0x8e, 0x1e, 0x4f, 0x0f,
+	0xfe, 0x10, 0x90, 0x04,
+	0xfe, 0x90, 0x93, 0x3a, 0x0b, 0xfe, 0x92, 0x90, 0x04, 0xfe, 0x92, 0x93,
+	0x79, 0x0b, 0x0e, 0xfe,
+	0xbd, 0x10, 0x01, 0x43, 0x09, 0xbb, 0x1b, 0xfe, 0x6e, 0x0a, 0x15, 0xbb,
+	0x01, 0x0c, 0x06, 0x0d,
+	0xfe, 0x14, 0x13, 0x03, 0x4b, 0x3b, 0x4c, 0x8e, 0xfe, 0x6e, 0x0a, 0xfe,
+	0x0c, 0x58, 0xfe, 0x8d,
+	0x58, 0x05, 0x5b, 0x26, 0x3e, 0x0f, 0xfe, 0x19, 0x80, 0x04, 0xfe, 0x99,
+	0x83, 0x33, 0x0b, 0x0e,
+	0xfe, 0xe5, 0x10, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1a, 0x12, 0xfe, 0x6c,
+	0x19, 0xfe, 0x19, 0x41,
+	0xfe, 0x6b, 0x18, 0xac, 0xfe, 0xd1, 0xf0, 0xef, 0x1f, 0x92, 0x01, 0x42,
+	0x19, 0xfe, 0x44, 0x00,
+	0xfe, 0x90, 0x10, 0xfe, 0x6c, 0x19, 0xd9, 0x4b, 0xfe, 0xed, 0x19, 0xda,
+	0x4c, 0xfe, 0x0c, 0x51,
+	0xfe, 0x8e, 0x51, 0xfe, 0x6b, 0x18, 0x23, 0xfe, 0x00, 0xff, 0x31, 0xfe,
+	0x76, 0x10, 0xac, 0xfe,
+	0xd2, 0xf0, 0xfe, 0xba, 0x0c, 0xfe, 0x76, 0x18, 0x23, 0x1d, 0x5d, 0x03,
+	0xe3, 0x23, 0x07, 0xfe,
+	0x08, 0x13, 0x19, 0xfe, 0x16, 0x00, 0x05, 0x70, 0xfe, 0xd1, 0xf0, 0xfe,
+	0xcc, 0x0c, 0x1f, 0x92,
+	0x01, 0x42, 0x19, 0xfe, 0x17, 0x00, 0x5c, 0xfe, 0xce, 0xf0, 0xfe, 0xd2,
+	0x0c, 0xfe, 0x3e, 0x10,
+	0xfe, 0xcd, 0xf0, 0xfe, 0xde, 0x0c, 0x19, 0xfe, 0x22, 0x00, 0x05, 0x70,
+	0xfe, 0xcb, 0xf0, 0xfe,
+	0xea, 0x0c, 0x19, 0xfe, 0x24, 0x00, 0x05, 0x70, 0xfe, 0xd0, 0xf0, 0xfe,
+	0xf4, 0x0c, 0x19, 0x94,
+	0xfe, 0x1c, 0x10, 0xfe, 0xcf, 0xf0, 0xfe, 0xfe, 0x0c, 0x19, 0x4a, 0xf3,
+	0xfe, 0xcc, 0xf0, 0xef,
+	0x01, 0x76, 0x06, 0x24, 0x4d, 0x19, 0xfe, 0x12, 0x00, 0x37, 0x13, 0xfe,
+	0x4e, 0x11, 0x2f, 0xfe,
+	0x16, 0x0d, 0xfe, 0x9e, 0xf0, 0xfe, 0x2a, 0x0d, 0xfe, 0x01, 0x48, 0x1b,
+	0x3c, 0x37, 0x88, 0xf5,
+	0xd4, 0x29, 0xd5, 0x29, 0xd2, 0x29, 0xd3, 0x29, 0x37, 0xfe, 0x9c, 0x32,
+	0x2f, 0xfe, 0x3e, 0x0d,
+	0x2a, 0x3c, 0xae, 0xfe, 0x62, 0x0d, 0xaf, 0xa0, 0xd4, 0x9f, 0xd5, 0x9f,
+	0xd2, 0x9f, 0xd3, 0x9f,
+	0x05, 0x29, 0x01, 0x41, 0xfe, 0xd3, 0x10, 0x15, 0xfe, 0xe8, 0x00, 0xc4,
+	0xc5, 0x75, 0xd7, 0x99,
+	0xd8, 0x9c, 0xfe, 0x89, 0xf0, 0x29, 0x27, 0x25, 0xbe, 0xd7, 0x99, 0xd8,
+	0x9c, 0x2f, 0xfe, 0x8c,
+	0x0d, 0x16, 0x29, 0x27, 0x25, 0xbd, 0xfe, 0x01, 0x48, 0xa4, 0x19, 0xfe,
+	0x42, 0x00, 0x05, 0x70,
+	0x90, 0x07, 0xfe, 0x81, 0x49, 0x1b, 0xfe, 0x64, 0x0e, 0x01, 0x0c, 0x06,
+	0x0d, 0xfe, 0x44, 0x13,
+	0x19, 0x00, 0x2d, 0x0d, 0xfe, 0x54, 0x12, 0x2d, 0xfe, 0x28, 0x00, 0x2b,
+	0xfe, 0xda, 0x0e, 0x0a,
+	0x57, 0x01, 0x18, 0x09, 0x00, 0x36, 0x46, 0xfe, 0x28, 0x00, 0xfe, 0xfa,
+	0x10, 0x01, 0xfe, 0xf4,
+	0x1c, 0x01, 0xfe, 0x00, 0x1d, 0x0a, 0xba, 0x01, 0xfe, 0x58, 0x10, 0x40,
+	0x15, 0x56, 0x01, 0x85,
+	0x05, 0x35, 0x19, 0xfe, 0x44, 0x00, 0x2d, 0x0d, 0xf7, 0x46, 0x0d, 0xfe,
+	0xcc, 0x10, 0x01, 0xa7,
+	0x46, 0x0d, 0xfe, 0xc2, 0x10, 0x01, 0xa7, 0x0f, 0xfe, 0x19, 0x82, 0x04,
+	0xfe, 0x99, 0x83, 0xfe,
+	0xcc, 0x47, 0x0b, 0x0e, 0xfe, 0x34, 0x46, 0xa5, 0x46, 0x0d, 0x19, 0xfe,
+	0x43, 0x00, 0xfe, 0xa2,
+	0x10, 0x01, 0x0c, 0x61, 0x0d, 0x44, 0x01, 0xfe, 0xf4, 0x1c, 0x01, 0xfe,
+	0x00, 0x1d, 0x40, 0x15,
+	0x56, 0x01, 0x85, 0x7d, 0x0d, 0x40, 0x51, 0x01, 0xfe, 0x9e, 0x1e, 0x05,
+	0xfe, 0x3a, 0x03, 0x01,
+	0x0c, 0x06, 0x0d, 0x5d, 0x46, 0x0d, 0x19, 0x00, 0xfe, 0x62, 0x10, 0x01,
+	0x76, 0x06, 0x12, 0xfe,
+	0x5c, 0x12, 0x01, 0x0c, 0x06, 0x12, 0xfe, 0x52, 0x13, 0xfe, 0x1c, 0x1c,
+	0xfe, 0x9d, 0xf0, 0xfe,
+	0x8e, 0x0e, 0xfe, 0x1c, 0x1c, 0xfe, 0x9d, 0xf0, 0xfe, 0x94, 0x0e, 0x01,
+	0x0c, 0x61, 0x12, 0x44,
+	0xfe, 0x9f, 0x10, 0x19, 0xfe, 0x15, 0x00, 0xfe, 0x04, 0xe6, 0x0d, 0x4f,
+	0xfe, 0x2e, 0x10, 0x19,
+	0xfe, 0x13, 0x00, 0xfe, 0x10, 0x10, 0x19, 0xfe, 0x47, 0x00, 0xf1, 0x19,
+	0xfe, 0x41, 0x00, 0xa2,
+	0x19, 0xfe, 0x24, 0x00, 0x86, 0xc4, 0xc5, 0x75, 0x03, 0x81, 0x1e, 0x2b,
+	0xea, 0x4f, 0xfe, 0x04,
+	0xe6, 0x12, 0xfe, 0x9d, 0x41, 0xfe, 0x1c, 0x42, 0x40, 0x01, 0xf4, 0x05,
+	0x35, 0xfe, 0x12, 0x1c,
+	0x1f, 0x0d, 0x47, 0xb5, 0xc3, 0x1f, 0xfe, 0x31, 0x00, 0x47, 0xb8, 0x01,
+	0xfe, 0xd4, 0x11, 0x05,
+	0xe9, 0x51, 0xfe, 0x06, 0xec, 0xe0, 0xfe, 0x0e, 0x47, 0x46, 0x28, 0xfe,
+	0xce, 0x45, 0x31, 0x51,
+	0xfe, 0x06, 0xea, 0xe0, 0xfe, 0x47, 0x4b, 0x45, 0xfe, 0x75, 0x57, 0x03,
+	0x67, 0xfe, 0x98, 0x56,
+	0xfe, 0x38, 0x12, 0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x44, 0x48, 0x60, 0x01,
+	0x0c, 0x06, 0x28, 0xfe,
+	0x18, 0x13, 0x0a, 0x57, 0x01, 0x18, 0x3e, 0xfe, 0x41, 0x58, 0x0a, 0xba,
+	0xfe, 0xfa, 0x14, 0xfe,
+	0x49, 0x54, 0xb0, 0xfe, 0x5e, 0x0f, 0x05, 0xfe, 0x3a, 0x03, 0x0a, 0x67,
+	0xfe, 0xe0, 0x14, 0xfe,
+	0x0e, 0x47, 0x46, 0x28, 0xfe, 0xce, 0x45, 0x31, 0x51, 0xfe, 0xce, 0x47,
+	0xfe, 0xad, 0x13, 0x05,
+	0x35, 0x21, 0x2c, 0x09, 0x1a, 0xfe, 0x98, 0x12, 0x26, 0x20, 0x96, 0x20,
+	0xe7, 0xfe, 0x08, 0x1c,
+	0xfe, 0x7c, 0x19, 0xfe, 0xfd, 0x19, 0xfe, 0x0a, 0x1c, 0x03, 0xe5, 0xfe,
+	0x48, 0x55, 0xa5, 0x3b,
+	0xfe, 0x62, 0x01, 0xfe, 0xc9, 0x55, 0x31, 0xfe, 0x74, 0x10, 0x01, 0xfe,
+	0xf0, 0x1a, 0x03, 0xfe,
+	0x38, 0x01, 0x3b, 0xfe, 0x3a, 0x01, 0x8e, 0xfe, 0x1e, 0x10, 0xfe, 0x02,
+	0xec, 0xe7, 0x53, 0x00,
+	0x36, 0xfe, 0x04, 0xec, 0x2c, 0x60, 0xfe, 0x05, 0xf6, 0xfe, 0x34, 0x01,
+	0x01, 0xfe, 0x62, 0x1b,
+	0x01, 0xfe, 0xce, 0x1e, 0xb2, 0x11, 0xfe, 0x18, 0x13, 0xca, 0xfe, 0x02,
+	0xea, 0xe7, 0x53, 0x92,
+	0xfe, 0xc3, 0x13, 0x1f, 0x12, 0x47, 0xb5, 0xc3, 0xfe, 0x2a, 0x10, 0x03,
+	0xfe, 0x38, 0x01, 0x23,
+	0xfe, 0xf0, 0xff, 0x10, 0xe5, 0x03, 0xfe, 0x3a, 0x01, 0x10, 0xfe, 0x62,
+	0x01, 0x01, 0xfe, 0x1e,
+	0x1e, 0x20, 0x2c, 0x15, 0x56, 0x01, 0xfe, 0x9e, 0x1e, 0x13, 0x07, 0x02,
+	0x26, 0x02, 0x21, 0x96,
+	0xc7, 0x20, 0x96, 0x09, 0x92, 0xfe, 0x79, 0x13, 0x1f, 0x1d, 0x47, 0xb5,
+	0xc3, 0xfe, 0xe1, 0x10,
+	0xcf, 0xfe, 0x03, 0xdc, 0xfe, 0x73, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xcf,
+	0xfe, 0x03, 0xdc, 0xfe,
+	0x5b, 0x57, 0xfe, 0x80, 0x5d, 0x02, 0xfe, 0x03, 0x57, 0xcf, 0x26, 0xfe,
+	0x00, 0xcc, 0x02, 0xfe,
+	0x03, 0x57, 0xcf, 0x89, 0x02, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13,
+	0x0f, 0xfe, 0x1c, 0x80,
+	0x04, 0xfe, 0x9c, 0x83, 0x33, 0x0b, 0x0e, 0x09, 0x07, 0xfe, 0x3a, 0x13,
+	0x0f, 0xfe, 0x1e, 0x80,
+	0x04, 0xfe, 0x9e, 0x83, 0x33, 0x0b, 0x0e, 0xfe, 0x2a, 0x13, 0x0f, 0xfe,
+	0x1d, 0x80, 0x04, 0xfe,
+	0x9d, 0x83, 0xfe, 0xf9, 0x13, 0x0e, 0xfe, 0x1c, 0x13, 0x01, 0xfe, 0xee,
+	0x1e, 0xac, 0xfe, 0x14,
+	0x13, 0x01, 0xfe, 0xfe, 0x1e, 0xfe, 0x81, 0x58, 0xfa, 0x01, 0xfe, 0x0e,
+	0x1f, 0xfe, 0x30, 0xf4,
+	0x0d, 0xfe, 0x3c, 0x50, 0xa2, 0x01, 0xfe, 0x92, 0x1b, 0x01, 0x43, 0x09,
+	0x56, 0xfb, 0x01, 0xfe,
+	0xc8, 0x1a, 0x01, 0x0c, 0x06, 0x28, 0xa4, 0x01, 0xfe, 0xf4, 0x1c, 0x01,
+	0xfe, 0x00, 0x1d, 0x15,
+	0xfe, 0xe9, 0x00, 0x01, 0x0c, 0x06, 0x4a, 0xfe, 0x4e, 0x13, 0x01, 0xfe,
+	0x22, 0x1b, 0xfe, 0x1e,
+	0x1c, 0x0f, 0xfe, 0x14, 0x90, 0x04, 0xfe, 0x94, 0x93, 0x3a, 0x0b, 0xfe,
+	0x96, 0x90, 0x04, 0xfe,
+	0x96, 0x93, 0x79, 0x0b, 0x0e, 0x10, 0xfe, 0x64, 0x01, 0x22, 0xfe, 0x66,
+	0x01, 0x01, 0x0c, 0x06,
+	0x65, 0xf9, 0x0f, 0xfe, 0x03, 0x80, 0x04, 0xfe, 0x83, 0x83, 0x33, 0x0b,
+	0x0e, 0x77, 0xfe, 0x01,
+	0xec, 0x2c, 0xfe, 0x80, 0x40, 0x20, 0x2c, 0x7a, 0x30, 0x15, 0xdf, 0x40,
+	0x21, 0x2c, 0xfe, 0x00,
+	0x40, 0x8d, 0x2c, 0x02, 0xfe, 0x08, 0x1c, 0x03, 0xfe, 0xac, 0x00, 0xfe,
+	0x06, 0x58, 0x03, 0xfe,
+	0xae, 0x00, 0xfe, 0x07, 0x58, 0x03, 0xfe, 0xb0, 0x00, 0xfe, 0x08, 0x58,
+	0x03, 0xfe, 0xb2, 0x00,
+	0xfe, 0x09, 0x58, 0xfe, 0x0a, 0x1c, 0x2e, 0x49, 0x20, 0xe0, 0x26, 0x10,
+	0x66, 0x10, 0x55, 0x10,
+	0x6f, 0x13, 0x57, 0x52, 0x4f, 0x1c, 0x28, 0xfe, 0x90, 0x4d, 0xfe, 0x91,
+	0x54, 0x2b, 0xfe, 0x88,
+	0x11, 0x46, 0x1a, 0x13, 0x5a, 0x52, 0x1c, 0x4a, 0xfe, 0x90, 0x4d, 0xfe,
+	0x91, 0x54, 0x2b, 0xfe,
+	0x9e, 0x11, 0x2e, 0x1a, 0x20, 0x2c, 0x90, 0x34, 0x60, 0x21, 0x2c, 0xfe,
+	0x00, 0x40, 0x8d, 0x2c,
+	0x15, 0xdf, 0xfe, 0x14, 0x56, 0xfe, 0xd6, 0xf0, 0xfe, 0xb2, 0x11, 0xfe,
+	0x12, 0x1c, 0x75, 0xfe,
+	0x14, 0x1c, 0xfe, 0x10, 0x1c, 0xfe, 0x18, 0x1c, 0x02, 0x51, 0xfe, 0x0c,
+	0x14, 0xfe, 0x0e, 0x47,
+	0xfe, 0x07, 0xe6, 0x28, 0xfe, 0xce, 0x47, 0xfe, 0xf5, 0x13, 0x02, 0x01,
+	0xa7, 0x90, 0x34, 0x60,
+	0xfe, 0x06, 0x80, 0xfe, 0x48, 0x47, 0xfe, 0x42, 0x13, 0xfe, 0x02, 0x80,
+	0x09, 0x56, 0xfe, 0x34,
+	0x13, 0x0a, 0x5a, 0x01, 0x18, 0xcb, 0xfe, 0x36, 0x12, 0xfe, 0x41, 0x48,
+	0xfe, 0x45, 0x48, 0x01,
+	0xfe, 0xb2, 0x16, 0xfe, 0x00, 0xcc, 0xcb, 0xfe, 0xf3, 0x13, 0x3f, 0x89,
+	0x09, 0x1a, 0xa5, 0x0a,
+	0x9d, 0x01, 0x18, 0xfe, 0x80, 0x5c, 0x01, 0x85, 0xf2, 0x09, 0x9b, 0xa4,
+	0xfe, 0x14, 0x56, 0xfe,
+	0xd6, 0xf0, 0xfe, 0xec, 0x11, 0x02, 0xfe, 0x44, 0x58, 0x77, 0xfe, 0x01,
+	0xec, 0xb8, 0xfe, 0x9e,
+	0x40, 0xfe, 0x9d, 0xe7, 0x00, 0xfe, 0x9c, 0xe7, 0x12, 0x8d, 0x30, 0x01,
+	0xf4, 0xfe, 0xdd, 0x10,
+	0x37, 0xd7, 0x99, 0xd8, 0x9c, 0x27, 0x25, 0xee, 0x09, 0x12, 0xfe, 0x48,
+	0x12, 0x09, 0x0d, 0xfe,
+	0x56, 0x12, 0x09, 0x1d, 0xfe, 0x30, 0x12, 0x09, 0xdd, 0x1b, 0xfe, 0xc4,
+	0x13, 0x09, 0xfe, 0x23,
+	0x00, 0x1b, 0xfe, 0xd0, 0x13, 0x09, 0x07, 0x1b, 0xfe, 0x34, 0x14, 0x09,
+	0x24, 0xfe, 0x12, 0x12,
+	0x09, 0x00, 0x1b, 0x29, 0x1f, 0xdd, 0x01, 0x42, 0xa1, 0x32, 0x01, 0x08,
+	0xae, 0x41, 0x02, 0x32,
+	0xfe, 0x62, 0x08, 0x0a, 0xe1, 0x01, 0xfe, 0x58, 0x10, 0x15, 0x9b, 0x05,
+	0x35, 0x32, 0x01, 0x43,
+	0x09, 0xbb, 0xfe, 0xd7, 0x13, 0x91, 0x4b, 0x7e, 0x4c, 0x8e, 0xfe, 0x80,
+	0x13, 0x01, 0x0c, 0x06,
+	0x54, 0xfe, 0x72, 0x12, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x44, 0x55, 0xfe,
+	0xe5, 0x55, 0xb0, 0xfe,
+	0x4a, 0x13, 0x21, 0x6e, 0xfe, 0x26, 0x13, 0x03, 0x97, 0x3b, 0x98, 0x8e,
+	0xfe, 0xb6, 0x0e, 0x10,
+	0x6a, 0x22, 0x6b, 0x26, 0x10, 0x97, 0x10, 0x98, 0x01, 0xc2, 0x2e, 0x49,
+	0x88, 0x20, 0x6e, 0x01,
+	0xfe, 0x6a, 0x16, 0xdb, 0x64, 0xdc, 0x34, 0xfe, 0x04, 0x55, 0xfe, 0xa5,
+	0x55, 0xfe, 0x04, 0xfa,
+	0x64, 0xfe, 0x05, 0xfa, 0x34, 0xfe, 0x8f, 0x10, 0x03, 0x6c, 0x3b, 0x6d,
+	0xfe, 0x40, 0x56, 0xfe,
+	0xe1, 0x56, 0x10, 0x6c, 0x22, 0x6d, 0x71, 0xdb, 0x64, 0xdc, 0x34, 0xfe,
+	0x44, 0x55, 0xfe, 0xe5,
+	0x55, 0x03, 0x68, 0x3b, 0x69, 0xfe, 0x00, 0x56, 0xfe, 0xa1, 0x56, 0x10,
+	0x68, 0x22, 0x69, 0x01,
+	0x0c, 0x06, 0x54, 0xf9, 0x21, 0x6e, 0xfe, 0x1f, 0x40, 0x03, 0x6a, 0x3b,
+	0x6b, 0xfe, 0x2c, 0x50,
+	0xfe, 0xae, 0x50, 0x03, 0x6c, 0x3b, 0x6d, 0xfe, 0x44, 0x50, 0xfe, 0xc6,
+	0x50, 0x03, 0x68, 0x3b,
+	0x69, 0xfe, 0x08, 0x50, 0xfe, 0x8a, 0x50, 0x03, 0x4b, 0x3b, 0x4c, 0xfe,
+	0x40, 0x50, 0xfe, 0xc2,
+	0x50, 0x05, 0x73, 0x2e, 0x07, 0x20, 0x9e, 0x05, 0x72, 0x32, 0x01, 0x08,
+	0x16, 0x3d, 0x27, 0x25,
+	0xee, 0x09, 0x07, 0x2b, 0x3d, 0x01, 0x43, 0x09, 0xbb, 0x2b, 0x72, 0x01,
+	0xa6, 0x23, 0x3f, 0x1b,
+	0x3d, 0x01, 0x0c, 0x06, 0x0d, 0xfe, 0x1e, 0x13, 0x91, 0x4b, 0x7e, 0x4c,
+	0xfe, 0x0a, 0x55, 0x31,
+	0xfe, 0x8b, 0x55, 0xd9, 0x4b, 0xda, 0x4c, 0xfe, 0x0c, 0x51, 0xfe, 0x8e,
+	0x51, 0x05, 0x72, 0x01,
+	0xfe, 0x8e, 0x1e, 0xca, 0xfe, 0x19, 0x41, 0x05, 0x72, 0x32, 0x01, 0x08,
+	0x2a, 0x3c, 0x16, 0xc0,
+	0x27, 0x25, 0xbe, 0x2d, 0x1d, 0xc0, 0x2d, 0x0d, 0x83, 0x2d, 0x7f, 0x1b,
+	0xfe, 0x66, 0x15, 0x05,
+	0x3d, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0xc0, 0x27, 0x25, 0xbd, 0x09, 0x1d,
+	0x2b, 0x3d, 0x01, 0x08,
+	0x16, 0xc0, 0x27, 0x25, 0xfe, 0xe8, 0x09, 0xfe, 0xc2, 0x49, 0x50, 0x03,
+	0xb6, 0x1e, 0x83, 0x01,
+	0x38, 0x06, 0x24, 0x31, 0xa1, 0xfe, 0xbb, 0x45, 0x2d, 0x00, 0xa4, 0x46,
+	0x07, 0x90, 0x3f, 0x01,
+	0xfe, 0xf8, 0x15, 0x01, 0xa6, 0x86, 0xfe, 0x4b, 0x45, 0xfe, 0x20, 0x13,
+	0x01, 0x43, 0x09, 0x82,
+	0xfe, 0x16, 0x13, 0x03, 0x9a, 0x1e, 0x5d, 0x03, 0x55, 0x1e, 0x31, 0x5e,
+	0x05, 0x72, 0xfe, 0xc0,
+	0x5d, 0x01, 0xa7, 0xfe, 0x03, 0x17, 0x03, 0x66, 0x8a, 0x10, 0x66, 0x5e,
+	0x32, 0x01, 0x08, 0x17,
+	0x73, 0x01, 0xfe, 0x56, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16,
+	0x3d, 0x27, 0x25, 0xbd,
+	0x09, 0x07, 0x2b, 0x3d, 0x01, 0xfe, 0xbe, 0x16, 0xfe, 0x42, 0x58, 0xfe,
+	0xe8, 0x14, 0x01, 0xa6,
+	0x86, 0xfe, 0x4a, 0xf4, 0x0d, 0x1b, 0x3d, 0xfe, 0x4a, 0xf4, 0x07, 0xfe,
+	0x0e, 0x12, 0x01, 0x43,
+	0x09, 0x82, 0x4e, 0x05, 0x72, 0x03, 0x55, 0x8a, 0x10, 0x55, 0x5e, 0x32,
+	0x01, 0x08, 0x17, 0x73,
+	0x01, 0xfe, 0x84, 0x19, 0x05, 0x73, 0x01, 0x08, 0x2a, 0x3c, 0x16, 0x3d,
+	0x27, 0x25, 0xbd, 0x09,
+	0x12, 0x2b, 0x3d, 0x01, 0xfe, 0xe8, 0x17, 0x8b, 0xfe, 0xaa, 0x14, 0xfe,
+	0xb6, 0x14, 0x86, 0xa8,
+	0xb2, 0x0d, 0x1b, 0x3d, 0xb2, 0x07, 0xfe, 0x0e, 0x12, 0x01, 0x43, 0x09,
+	0x82, 0x4e, 0x05, 0x72,
+	0x03, 0x6f, 0x8a, 0x10, 0x6f, 0x5e, 0x32, 0x01, 0x08, 0x17, 0x73, 0x01,
+	0xfe, 0xc0, 0x19, 0x05,
+	0x73, 0x13, 0x07, 0x2f, 0xfe, 0xcc, 0x15, 0x17, 0xfe, 0xe2, 0x15, 0x5f,
+	0xcc, 0x01, 0x08, 0x26,
+	0x5f, 0x02, 0x8f, 0xfe, 0xde, 0x15, 0x2a, 0xfe, 0xde, 0x15, 0x16, 0xfe,
+	0xcc, 0x15, 0x5e, 0x32,
+	0x01, 0x08, 0xfe, 0xd5, 0x10, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52,
+	0xad, 0x23, 0xfe, 0xff,
+	0x7f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff, 0x02,
+	0x00, 0x57, 0x52, 0xad,
+	0x23, 0x3f, 0xfe, 0x30, 0x56, 0xfe, 0x00, 0x5c, 0x02, 0x13, 0x58, 0xff,
+	0x02, 0x00, 0x57, 0x52,
+	0xad, 0x02, 0x13, 0x58, 0xff, 0x02, 0x00, 0x57, 0x52, 0xfe, 0x00, 0x5e,
+	0x02, 0x13, 0x58, 0xff,
+	0x02, 0x00, 0x57, 0x52, 0xad, 0xfe, 0x0b, 0x58, 0x02, 0x0a, 0x66, 0x01,
+	0x5c, 0x0a, 0x55, 0x01,
+	0x5c, 0x0a, 0x6f, 0x01, 0x5c, 0x02, 0x01, 0xfe, 0x1e, 0x1f, 0x23, 0x1a,
+	0xff, 0x03, 0x00, 0x54,
+	0xfe, 0x00, 0xf4, 0x24, 0x52, 0x0f, 0xfe, 0x00, 0x7c, 0x04, 0xfe, 0x07,
+	0x7c, 0x3a, 0x0b, 0x0e,
+	0xfe, 0x00, 0x71, 0xfe, 0xf9, 0x18, 0xfe, 0x7a, 0x19, 0xfe, 0xfb, 0x19,
+	0xfe, 0x1a, 0xf7, 0x00,
+	0xfe, 0x1b, 0xf7, 0x00, 0x7a, 0x30, 0x10, 0x68, 0x22, 0x69, 0xd9, 0x6c,
+	0xda, 0x6d, 0x02, 0xfe,
+	0x62, 0x08, 0xfe, 0x82, 0x4a, 0xfe, 0xe1, 0x1a, 0xfe, 0x83, 0x5a, 0x77,
+	0x02, 0x01, 0xc6, 0xfe,
+	0x42, 0x48, 0x4f, 0x50, 0x45, 0x01, 0x08, 0x16, 0xfe, 0xe0, 0x17, 0x27,
+	0x25, 0xbe, 0x01, 0x08,
+	0x16, 0xfe, 0xe0, 0x17, 0x27, 0x25, 0xfe, 0xe8, 0x0a, 0xfe, 0xc1, 0x59,
+	0x03, 0x9a, 0x1e, 0xfe,
+	0xda, 0x12, 0x01, 0x38, 0x06, 0x12, 0xfe, 0xd0, 0x13, 0x26, 0x53, 0x12,
+	0x48, 0xfe, 0x08, 0x17,
+	0xd1, 0x12, 0x53, 0x12, 0xfe, 0x1e, 0x13, 0x2d, 0xb4, 0x7b, 0xfe, 0x26,
+	0x17, 0x4d, 0x13, 0x07,
+	0x1c, 0xb4, 0x90, 0x04, 0xfe, 0x78, 0x10, 0xff, 0x02, 0x83, 0x55, 0xf1,
+	0xff, 0x02, 0x83, 0x55,
+	0x53, 0x1d, 0xfe, 0x12, 0x13, 0xd6, 0xfe, 0x30, 0x00, 0xb0, 0xfe, 0x80,
+	0x17, 0x1c, 0x63, 0x13,
+	0x07, 0xfe, 0x56, 0x10, 0x53, 0x0d, 0xfe, 0x16, 0x13, 0xd6, 0xfe, 0x64,
+	0x00, 0xb0, 0xfe, 0x80,
+	0x17, 0x0a, 0xfe, 0x64, 0x00, 0x1c, 0x94, 0x13, 0x07, 0xfe, 0x28, 0x10,
+	0x53, 0x07, 0xfe, 0x60,
+	0x13, 0xd6, 0xfe, 0xc8, 0x00, 0xb0, 0xfe, 0x80, 0x17, 0x0a, 0xfe, 0xc8,
+	0x00, 0x1c, 0x95, 0x13,
+	0x07, 0x71, 0xd6, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0x8c, 0x17, 0x45, 0xf3,
+	0xfe, 0x43, 0xf4, 0x96,
+	0xfe, 0x56, 0xf0, 0xfe, 0x9e, 0x17, 0xfe, 0x04, 0xf4, 0x58, 0xfe, 0x43,
+	0xf4, 0x94, 0xf6, 0x8b,
+	0x01, 0xfe, 0x24, 0x16, 0x23, 0x3f, 0xfc, 0xa8, 0x8c, 0x49, 0x48, 0xfe,
+	0xda, 0x17, 0x62, 0x49,
+	0xfe, 0x1c, 0x10, 0xa8, 0x8c, 0x80, 0x48, 0xfe, 0xda, 0x17, 0x62, 0x80,
+	0x71, 0x50, 0x26, 0xfe,
+	0x4d, 0xf4, 0x00, 0xf7, 0x45, 0x13, 0x07, 0xfe, 0xb4, 0x56, 0xfe, 0xc3,
+	0x58, 0x02, 0x50, 0x13,
+	0x0d, 0x02, 0x50, 0x3e, 0x78, 0x4f, 0x45, 0x01, 0x08, 0x16, 0xa9, 0x27,
+	0x25, 0xbe, 0xfe, 0x03,
+	0xea, 0xfe, 0x7e, 0x01, 0x01, 0x08, 0x16, 0xa9, 0x27, 0x25, 0xfe, 0xe9,
+	0x0a, 0x01, 0x08, 0x16,
+	0xa9, 0x27, 0x25, 0xfe, 0xe9, 0x0a, 0xfe, 0x05, 0xea, 0xfe, 0x7f, 0x01,
+	0x01, 0x08, 0x16, 0xa9,
+	0x27, 0x25, 0xfe, 0x69, 0x09, 0xfe, 0x02, 0xea, 0xfe, 0x80, 0x01, 0x01,
+	0x08, 0x16, 0xa9, 0x27,
+	0x25, 0xfe, 0xe8, 0x08, 0x47, 0xfe, 0x81, 0x01, 0x03, 0xb6, 0x1e, 0x83,
+	0x01, 0x38, 0x06, 0x24,
+	0x31, 0xa2, 0x78, 0xf2, 0x53, 0x07, 0x36, 0xfe, 0x34, 0xf4, 0x3f, 0xa1,
+	0x78, 0x03, 0x9a, 0x1e,
+	0x83, 0x01, 0x38, 0x06, 0x12, 0x31, 0xf0, 0x4f, 0x45, 0xfe, 0x90, 0x10,
+	0xfe, 0x40, 0x5a, 0x23,
+	0x3f, 0xfb, 0x8c, 0x49, 0x48, 0xfe, 0xaa, 0x18, 0x62, 0x49, 0x71, 0x8c,
+	0x80, 0x48, 0xfe, 0xaa,
+	0x18, 0x62, 0x80, 0xfe, 0xb4, 0x56, 0xfe, 0x40, 0x5d, 0x01, 0xc6, 0x01,
+	0xfe, 0xac, 0x1d, 0xfe,
+	0x02, 0x17, 0xfe, 0xc8, 0x45, 0xfe, 0x5a, 0xf0, 0xfe, 0xc0, 0x18, 0xfe,
+	0x43, 0x48, 0x2d, 0x93,
+	0x36, 0xfe, 0x34, 0xf4, 0xfe, 0x00, 0x11, 0xfe, 0x40, 0x10, 0x2d, 0xb4,
+	0x36, 0xfe, 0x34, 0xf4,
+	0x04, 0xfe, 0x34, 0x10, 0x2d, 0xfe, 0x0b, 0x00, 0x36, 0x46, 0x63, 0xfe,
+	0x28, 0x10, 0xfe, 0xc0,
+	0x49, 0xff, 0x02, 0x00, 0x54, 0xb2, 0xfe, 0x90, 0x01, 0x48, 0xfe, 0xfa,
+	0x18, 0x45, 0xfe, 0x1c,
+	0xf4, 0x3f, 0xf3, 0xfe, 0x40, 0xf4, 0x96, 0xfe, 0x56, 0xf0, 0xfe, 0x0c,
+	0x19, 0xfe, 0x04, 0xf4,
+	0x58, 0xfe, 0x40, 0xf4, 0x94, 0xf6, 0x3e, 0x2d, 0x93, 0x4e, 0xd0, 0x0d,
+	0x21, 0xfe, 0x7f, 0x01,
+	0xfe, 0xc8, 0x46, 0xfe, 0x24, 0x13, 0x8c, 0x00, 0x5d, 0x26, 0x21, 0xfe,
+	0x7e, 0x01, 0xfe, 0xc8,
+	0x45, 0xfe, 0x14, 0x13, 0x21, 0xfe, 0x80, 0x01, 0xfe, 0x48, 0x45, 0xfa,
+	0x21, 0xfe, 0x81, 0x01,
+	0xfe, 0xc8, 0x44, 0x4e, 0x26, 0x02, 0x13, 0x07, 0x02, 0x78, 0x45, 0x50,
+	0x13, 0x0d, 0x02, 0x14,
+	0x07, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x14, 0x0d, 0x01, 0x08, 0x17,
+	0xfe, 0x82, 0x19, 0x14,
+	0x1d, 0x01, 0x08, 0x17, 0xfe, 0x82, 0x19, 0x5f, 0xfe, 0x89, 0x49, 0x01,
+	0x08, 0x02, 0x14, 0x07,
+	0x01, 0x08, 0x17, 0xc1, 0x14, 0x1d, 0x01, 0x08, 0x17, 0xc1, 0x14, 0x07,
+	0x01, 0x08, 0x17, 0xc1,
+	0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0xc1, 0x5f, 0xfe, 0x89, 0x4a, 0x01,
+	0x08, 0x02, 0x50, 0x02,
+	0x14, 0x07, 0x01, 0x08, 0x17, 0x74, 0x14, 0x7f, 0x01, 0x08, 0x17, 0x74,
+	0x14, 0x12, 0x01, 0x08,
+	0x17, 0x74, 0xfe, 0x89, 0x49, 0x01, 0x08, 0x17, 0x74, 0x14, 0x00, 0x01,
+	0x08, 0x17, 0x74, 0xfe,
+	0x89, 0x4a, 0x01, 0x08, 0x17, 0x74, 0xfe, 0x09, 0x49, 0x01, 0x08, 0x17,
+	0x74, 0x5f, 0xcc, 0x01,
+	0x08, 0x02, 0x21, 0xe4, 0x09, 0x07, 0xfe, 0x4c, 0x13, 0xc8, 0x20, 0xe4,
+	0xfe, 0x49, 0xf4, 0x00,
+	0x4d, 0x5f, 0xa1, 0x5e, 0xfe, 0x01, 0xec, 0xfe, 0x27, 0x01, 0xcc, 0xff,
+	0x02, 0x00, 0x10, 0x2f,
+	0xfe, 0x3e, 0x1a, 0x01, 0x43, 0x09, 0xfe, 0xe3, 0x00, 0xfe, 0x22, 0x13,
+	0x16, 0xfe, 0x64, 0x1a,
+	0x26, 0x20, 0x9e, 0x01, 0x41, 0x21, 0x9e, 0x09, 0x07, 0x5d, 0x01, 0x0c,
+	0x61, 0x07, 0x44, 0x02,
+	0x0a, 0x5a, 0x01, 0x18, 0xfe, 0x00, 0x40, 0xaa, 0x09, 0x1a, 0xfe, 0x12,
+	0x13, 0x0a, 0x9d, 0x01,
+	0x18, 0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x9d, 0x01, 0x18, 0xaa,
+	0xfe, 0x80, 0xe7, 0x1a,
+	0x09, 0x1a, 0x5d, 0xfe, 0x45, 0x58, 0x01, 0xfe, 0xb2, 0x16, 0xaa, 0x02,
+	0x0a, 0x5a, 0x01, 0x18,
+	0xaa, 0x0a, 0x67, 0x01, 0xa3, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x01, 0xfe,
+	0x7e, 0x1e, 0xfe, 0x80,
+	0x4c, 0xfe, 0x49, 0xe4, 0x1a, 0xfe, 0x12, 0x13, 0x0a, 0x9d, 0x01, 0x18,
+	0xfe, 0x80, 0x4c, 0x0a,
+	0x67, 0x01, 0x5c, 0x02, 0x1c, 0x1a, 0x87, 0x7c, 0xe5, 0xfe, 0x18, 0xdf,
+	0xfe, 0x19, 0xde, 0xfe,
+	0x24, 0x1c, 0xfe, 0x1d, 0xf7, 0x28, 0xb1, 0xfe, 0x04, 0x1b, 0x01, 0xfe,
+	0x2a, 0x1c, 0xfa, 0xb3,
+	0x28, 0x7c, 0xfe, 0x2c, 0x01, 0xfe, 0x2f, 0x19, 0x02, 0xc9, 0x2b, 0xfe,
+	0xf4, 0x1a, 0xfe, 0xfa,
+	0x10, 0x1c, 0x1a, 0x87, 0x03, 0xfe, 0x64, 0x01, 0xfe, 0x00, 0xf4, 0x24,
+	0xfe, 0x18, 0x58, 0x03,
+	0xfe, 0x66, 0x01, 0xfe, 0x19, 0x58, 0xb3, 0x24, 0x01, 0xfe, 0x0e, 0x1f,
+	0xfe, 0x30, 0xf4, 0x07,
+	0xfe, 0x3c, 0x50, 0x7c, 0xfe, 0x38, 0x00, 0xfe, 0x0f, 0x79, 0xfe, 0x1c,
+	0xf7, 0x24, 0xb1, 0xfe,
+	0x50, 0x1b, 0xfe, 0xd4, 0x14, 0x31, 0x02, 0xc9, 0x2b, 0xfe, 0x26, 0x1b,
+	0xfe, 0xba, 0x10, 0x1c,
+	0x1a, 0x87, 0xfe, 0x83, 0x5a, 0xfe, 0x18, 0xdf, 0xfe, 0x19, 0xde, 0xfe,
+	0x1d, 0xf7, 0x54, 0xb1,
+	0xfe, 0x72, 0x1b, 0xfe, 0xb2, 0x14, 0xfc, 0xb3, 0x54, 0x7c, 0x12, 0xfe,
+	0xaf, 0x19, 0xfe, 0x98,
+	0xe7, 0x00, 0x02, 0xc9, 0x2b, 0xfe, 0x66, 0x1b, 0xfe, 0x8a, 0x10, 0x1c,
+	0x1a, 0x87, 0x8b, 0x0f,
+	0xfe, 0x30, 0x90, 0x04, 0xfe, 0xb0, 0x93, 0x3a, 0x0b, 0xfe, 0x18, 0x58,
+	0xfe, 0x32, 0x90, 0x04,
+	0xfe, 0xb2, 0x93, 0x3a, 0x0b, 0xfe, 0x19, 0x58, 0x0e, 0xa8, 0xb3, 0x4a,
+	0x7c, 0x12, 0xfe, 0x0f,
+	0x79, 0xfe, 0x1c, 0xf7, 0x4a, 0xb1, 0xfe, 0xc6, 0x1b, 0xfe, 0x5e, 0x14,
+	0x31, 0x02, 0xc9, 0x2b,
+	0xfe, 0x96, 0x1b, 0x5c, 0xfe, 0x02, 0xf6, 0x1a, 0x87, 0xfe, 0x18, 0xfe,
+	0x6a, 0xfe, 0x19, 0xfe,
+	0x6b, 0x01, 0xfe, 0x1e, 0x1f, 0xfe, 0x1d, 0xf7, 0x65, 0xb1, 0xfe, 0xee,
+	0x1b, 0xfe, 0x36, 0x14,
+	0xfe, 0x1c, 0x13, 0xb3, 0x65, 0x3e, 0xfe, 0x83, 0x58, 0xfe, 0xaf, 0x19,
+	0xfe, 0x80, 0xe7, 0x1a,
+	0xfe, 0x81, 0xe7, 0x1a, 0x15, 0xfe, 0xdd, 0x00, 0x7a, 0x30, 0x02, 0x7a,
+	0x30, 0xfe, 0x12, 0x45,
+	0x2b, 0xfe, 0xdc, 0x1b, 0x1f, 0x07, 0x47, 0xb5, 0xc3, 0x05, 0x35, 0xfe,
+	0x39, 0xf0, 0x75, 0x26,
+	0x02, 0xfe, 0x7e, 0x18, 0x23, 0x1d, 0x36, 0x13, 0x11, 0x02, 0x87, 0x03,
+	0xe3, 0x23, 0x07, 0xfe,
+	0xef, 0x12, 0xfe, 0xe1, 0x10, 0x90, 0x34, 0x60, 0xfe, 0x02, 0x80, 0x09,
+	0x56, 0xfe, 0x3c, 0x13,
+	0xfe, 0x82, 0x14, 0xfe, 0x42, 0x13, 0x51, 0xfe, 0x06, 0x83, 0x0a, 0x5a,
+	0x01, 0x18, 0xcb, 0xfe,
+	0x3e, 0x12, 0xfe, 0x41, 0x48, 0xfe, 0x45, 0x48, 0x01, 0xfe, 0xb2, 0x16,
+	0xfe, 0x00, 0xcc, 0xcb,
+	0xfe, 0xf3, 0x13, 0x3f, 0x89, 0x09, 0x1a, 0xa5, 0x0a, 0x9d, 0x01, 0x18,
+	0xfe, 0x80, 0x4c, 0x01,
+	0x85, 0xfe, 0x16, 0x10, 0x09, 0x9b, 0x4e, 0xfe, 0x40, 0x14, 0xfe, 0x24,
+	0x12, 0xfe, 0x14, 0x56,
+	0xfe, 0xd6, 0xf0, 0xfe, 0x52, 0x1c, 0x1c, 0x0d, 0x02, 0xfe, 0x9c, 0xe7,
+	0x0d, 0x19, 0xfe, 0x15,
+	0x00, 0x40, 0x8d, 0x30, 0x01, 0xf4, 0x1c, 0x07, 0x02, 0x51, 0xfe, 0x06,
+	0x83, 0xfe, 0x18, 0x80,
+	0x61, 0x28, 0x44, 0x15, 0x56, 0x01, 0x85, 0x1c, 0x07, 0x02, 0xfe, 0x38,
+	0x90, 0xfe, 0xba, 0x90,
+	0x91, 0xde, 0x7e, 0xdf, 0xfe, 0x48, 0x55, 0x31, 0xfe, 0xc9, 0x55, 0x02,
+	0x21, 0xb9, 0x88, 0x20,
+	0xb9, 0x02, 0x0a, 0xba, 0x01, 0x18, 0xfe, 0x41, 0x48, 0x0a, 0x57, 0x01,
+	0x18, 0xfe, 0x49, 0x44,
+	0x1b, 0xfe, 0x1e, 0x1d, 0x88, 0x89, 0x02, 0x0a, 0x5a, 0x01, 0x18, 0x09,
+	0x1a, 0xa4, 0x0a, 0x67,
+	0x01, 0xa3, 0x0a, 0x57, 0x01, 0x18, 0x88, 0x89, 0x02, 0xfe, 0x4e, 0xe4,
+	0x1d, 0x7b, 0xfe, 0x52,
+	0x1d, 0x03, 0xfe, 0x90, 0x00, 0xfe, 0x3a, 0x45, 0xfe, 0x2c, 0x10, 0xfe,
+	0x4e, 0xe4, 0xdd, 0x7b,
+	0xfe, 0x64, 0x1d, 0x03, 0xfe, 0x92, 0x00, 0xd1, 0x12, 0xfe, 0x1a, 0x10,
+	0xfe, 0x4e, 0xe4, 0xfe,
+	0x0b, 0x00, 0x7b, 0xfe, 0x76, 0x1d, 0x03, 0xfe, 0x94, 0x00, 0xd1, 0x24,
+	0xfe, 0x08, 0x10, 0x03,
+	0xfe, 0x96, 0x00, 0xd1, 0x63, 0xfe, 0x4e, 0x45, 0x83, 0xca, 0xff, 0x04,
+	0x68, 0x54, 0xfe, 0xf1,
+	0x10, 0x23, 0x49, 0xfe, 0x08, 0x1c, 0xfe, 0x67, 0x19, 0xfe, 0x0a, 0x1c,
+	0xfe, 0x1a, 0xf4, 0xfe,
+	0x00, 0x04, 0x83, 0xb2, 0x1d, 0x48, 0xfe, 0xaa, 0x1d, 0x13, 0x1d, 0x02,
+	0x09, 0x92, 0xfe, 0x5a,
+	0xf0, 0xfe, 0xba, 0x1d, 0x2e, 0x93, 0xfe, 0x34, 0x10, 0x09, 0x12, 0xfe,
+	0x5a, 0xf0, 0xfe, 0xc8,
+	0x1d, 0x2e, 0xb4, 0xfe, 0x26, 0x10, 0x09, 0x1d, 0x36, 0x2e, 0x63, 0xfe,
+	0x1a, 0x10, 0x09, 0x0d,
+	0x36, 0x2e, 0x94, 0xf2, 0x09, 0x07, 0x36, 0x2e, 0x95, 0xa1, 0xc8, 0x02,
+	0x1f, 0x93, 0x01, 0x42,
+	0xfe, 0x04, 0xfe, 0x99, 0x03, 0x9c, 0x8b, 0x02, 0x2a, 0xfe, 0x1c, 0x1e,
+	0xfe, 0x14, 0xf0, 0x08,
+	0x2f, 0xfe, 0x0c, 0x1e, 0x2a, 0xfe, 0x1c, 0x1e, 0x8f, 0xfe, 0x1c, 0x1e,
+	0xfe, 0x82, 0xf0, 0xfe,
+	0x10, 0x1e, 0x02, 0x0f, 0x3f, 0x04, 0xfe, 0x80, 0x83, 0x33, 0x0b, 0x0e,
+	0x02, 0x0f, 0xfe, 0x18,
+	0x80, 0x04, 0xfe, 0x98, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x02,
+	0x80, 0x04, 0xfe, 0x82,
+	0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x80, 0x04, 0xfe, 0x86,
+	0x83, 0x33, 0x0b, 0x0e,
+	0x02, 0x0f, 0xfe, 0x1b, 0x80, 0x04, 0xfe, 0x9b, 0x83, 0x33, 0x0b, 0x0e,
+	0x02, 0x0f, 0xfe, 0x04,
+	0x80, 0x04, 0xfe, 0x84, 0x83, 0x33, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x80,
+	0x80, 0x04, 0xfe, 0x80,
+	0x83, 0xfe, 0xc9, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x19, 0x81, 0x04,
+	0xfe, 0x99, 0x83, 0xfe,
+	0xca, 0x47, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x06, 0x83, 0x04, 0xfe, 0x86,
+	0x83, 0xfe, 0xce, 0x47,
+	0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x2c, 0x90, 0x04, 0xfe, 0xac, 0x93, 0x3a,
+	0x0b, 0x0e, 0x02, 0x0f,
+	0xfe, 0xae, 0x90, 0x04, 0xfe, 0xae, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
+	0xfe, 0x08, 0x90, 0x04,
+	0xfe, 0x88, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x8a, 0x90, 0x04,
+	0xfe, 0x8a, 0x93, 0x79,
+	0x0b, 0x0e, 0x02, 0x0f, 0xfe, 0x0c, 0x90, 0x04, 0xfe, 0x8c, 0x93, 0x3a,
+	0x0b, 0x0e, 0x02, 0x0f,
+	0xfe, 0x8e, 0x90, 0x04, 0xfe, 0x8e, 0x93, 0x79, 0x0b, 0x0e, 0x02, 0x0f,
+	0xfe, 0x3c, 0x90, 0x04,
+	0xfe, 0xbc, 0x93, 0x3a, 0x0b, 0x0e, 0x02, 0x8b, 0x0f, 0xfe, 0x03, 0x80,
+	0x04, 0xfe, 0x83, 0x83,
+	0x33, 0x0b, 0x77, 0x0e, 0xa8, 0x02, 0xff, 0x66, 0x00, 0x00,
 };
 
-STATIC unsigned short _adv_asc38C1600_size =
-        sizeof(_adv_asc38C1600_buf); /* 0x1673 */
-STATIC ADV_DCNT _adv_asc38C1600_chksum =
-        0x0604EF77UL; /* Expanded little-endian checksum. */
+static unsigned short _adv_asc38C1600_size = sizeof(_adv_asc38C1600_buf);	/* 0x1673 */
+static ADV_DCNT _adv_asc38C1600_chksum = 0x0604EF77UL;	/* Expanded little-endian checksum. */
 
 /* a_init.c */
 /*
@@ -14049,340 +13847,340 @@
  * on big-endian platforms so char fields read as words are actually being
  * unswapped on big-endian platforms.
  */
-STATIC ADVEEP_3550_CONFIG
-Default_3550_EEPROM_Config __initdata = {
-    ADV_EEPROM_BIOS_ENABLE,     /* cfg_lsw */
-    0x0000,                     /* cfg_msw */
-    0xFFFF,                     /* disc_enable */
-    0xFFFF,                     /* wdtr_able */
-    0xFFFF,                     /* sdtr_able */
-    0xFFFF,                     /* start_motor */
-    0xFFFF,                     /* tagqng_able */
-    0xFFFF,                     /* bios_scan */
-    0,                          /* scam_tolerant */
-    7,                          /* adapter_scsi_id */
-    0,                          /* bios_boot_delay */
-    3,                          /* scsi_reset_delay */
-    0,                          /* bios_id_lun */
-    0,                          /* termination */
-    0,                          /* reserved1 */
-    0xFFE7,                     /* bios_ctrl */
-    0xFFFF,                     /* ultra_able */
-    0,                          /* reserved2 */
-    ASC_DEF_MAX_HOST_QNG,       /* max_host_qng */
-    ASC_DEF_MAX_DVC_QNG,        /* max_dvc_qng */
-    0,                          /* dvc_cntl */
-    0,                          /* bug_fix */
-    0,                          /* serial_number_word1 */
-    0,                          /* serial_number_word2 */
-    0,                          /* serial_number_word3 */
-    0,                          /* check_sum */
-    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* oem_name[16] */
-    0,                          /* dvc_err_code */
-    0,                          /* adv_err_code */
-    0,                          /* adv_err_addr */
-    0,                          /* saved_dvc_err_code */
-    0,                          /* saved_adv_err_code */
-    0,                          /* saved_adv_err_addr */
-    0                           /* num_of_err */
+static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __initdata = {
+	ADV_EEPROM_BIOS_ENABLE,	/* cfg_lsw */
+	0x0000,			/* cfg_msw */
+	0xFFFF,			/* disc_enable */
+	0xFFFF,			/* wdtr_able */
+	0xFFFF,			/* sdtr_able */
+	0xFFFF,			/* start_motor */
+	0xFFFF,			/* tagqng_able */
+	0xFFFF,			/* bios_scan */
+	0,			/* scam_tolerant */
+	7,			/* adapter_scsi_id */
+	0,			/* bios_boot_delay */
+	3,			/* scsi_reset_delay */
+	0,			/* bios_id_lun */
+	0,			/* termination */
+	0,			/* reserved1 */
+	0xFFE7,			/* bios_ctrl */
+	0xFFFF,			/* ultra_able */
+	0,			/* reserved2 */
+	ASC_DEF_MAX_HOST_QNG,	/* max_host_qng */
+	ASC_DEF_MAX_DVC_QNG,	/* max_dvc_qng */
+	0,			/* dvc_cntl */
+	0,			/* bug_fix */
+	0,			/* serial_number_word1 */
+	0,			/* serial_number_word2 */
+	0,			/* serial_number_word3 */
+	0,			/* check_sum */
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+	,			/* oem_name[16] */
+	0,			/* dvc_err_code */
+	0,			/* adv_err_code */
+	0,			/* adv_err_addr */
+	0,			/* saved_dvc_err_code */
+	0,			/* saved_adv_err_code */
+	0,			/* saved_adv_err_addr */
+	0			/* num_of_err */
 };
 
-STATIC ADVEEP_3550_CONFIG
-ADVEEP_3550_Config_Field_IsChar __initdata = {
-    0,                          /* cfg_lsw */
-    0,                          /* cfg_msw */
-    0,                          /* -disc_enable */
-    0,                          /* wdtr_able */
-    0,                          /* sdtr_able */
-    0,                          /* start_motor */
-    0,                          /* tagqng_able */
-    0,                          /* bios_scan */
-    0,                          /* scam_tolerant */
-    1,                          /* adapter_scsi_id */
-    1,                          /* bios_boot_delay */
-    1,                          /* scsi_reset_delay */
-    1,                          /* bios_id_lun */
-    1,                          /* termination */
-    1,                          /* reserved1 */
-    0,                          /* bios_ctrl */
-    0,                          /* ultra_able */
-    0,                          /* reserved2 */
-    1,                          /* max_host_qng */
-    1,                          /* max_dvc_qng */
-    0,                          /* dvc_cntl */
-    0,                          /* bug_fix */
-    0,                          /* serial_number_word1 */
-    0,                          /* serial_number_word2 */
-    0,                          /* serial_number_word3 */
-    0,                          /* check_sum */
-    { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* oem_name[16] */
-    0,                          /* dvc_err_code */
-    0,                          /* adv_err_code */
-    0,                          /* adv_err_addr */
-    0,                          /* saved_dvc_err_code */
-    0,                          /* saved_adv_err_code */
-    0,                          /* saved_adv_err_addr */
-    0                           /* num_of_err */
+static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __initdata = {
+	0,			/* cfg_lsw */
+	0,			/* cfg_msw */
+	0,			/* -disc_enable */
+	0,			/* wdtr_able */
+	0,			/* sdtr_able */
+	0,			/* start_motor */
+	0,			/* tagqng_able */
+	0,			/* bios_scan */
+	0,			/* scam_tolerant */
+	1,			/* adapter_scsi_id */
+	1,			/* bios_boot_delay */
+	1,			/* scsi_reset_delay */
+	1,			/* bios_id_lun */
+	1,			/* termination */
+	1,			/* reserved1 */
+	0,			/* bios_ctrl */
+	0,			/* ultra_able */
+	0,			/* reserved2 */
+	1,			/* max_host_qng */
+	1,			/* max_dvc_qng */
+	0,			/* dvc_cntl */
+	0,			/* bug_fix */
+	0,			/* serial_number_word1 */
+	0,			/* serial_number_word2 */
+	0,			/* serial_number_word3 */
+	0,			/* check_sum */
+	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+	,			/* oem_name[16] */
+	0,			/* dvc_err_code */
+	0,			/* adv_err_code */
+	0,			/* adv_err_addr */
+	0,			/* saved_dvc_err_code */
+	0,			/* saved_adv_err_code */
+	0,			/* saved_adv_err_addr */
+	0			/* num_of_err */
 };
 
-STATIC ADVEEP_38C0800_CONFIG
-Default_38C0800_EEPROM_Config __initdata = {
-    ADV_EEPROM_BIOS_ENABLE,     /* 00 cfg_lsw */
-    0x0000,                     /* 01 cfg_msw */
-    0xFFFF,                     /* 02 disc_enable */
-    0xFFFF,                     /* 03 wdtr_able */
-    0x4444,                     /* 04 sdtr_speed1 */
-    0xFFFF,                     /* 05 start_motor */
-    0xFFFF,                     /* 06 tagqng_able */
-    0xFFFF,                     /* 07 bios_scan */
-    0,                          /* 08 scam_tolerant */
-    7,                          /* 09 adapter_scsi_id */
-    0,                          /*    bios_boot_delay */
-    3,                          /* 10 scsi_reset_delay */
-    0,                          /*    bios_id_lun */
-    0,                          /* 11 termination_se */
-    0,                          /*    termination_lvd */
-    0xFFE7,                     /* 12 bios_ctrl */
-    0x4444,                     /* 13 sdtr_speed2 */
-    0x4444,                     /* 14 sdtr_speed3 */
-    ASC_DEF_MAX_HOST_QNG,       /* 15 max_host_qng */
-    ASC_DEF_MAX_DVC_QNG,        /*    max_dvc_qng */
-    0,                          /* 16 dvc_cntl */
-    0x4444,                     /* 17 sdtr_speed4 */
-    0,                          /* 18 serial_number_word1 */
-    0,                          /* 19 serial_number_word2 */
-    0,                          /* 20 serial_number_word3 */
-    0,                          /* 21 check_sum */
-    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* 22-29 oem_name[16] */
-    0,                          /* 30 dvc_err_code */
-    0,                          /* 31 adv_err_code */
-    0,                          /* 32 adv_err_addr */
-    0,                          /* 33 saved_dvc_err_code */
-    0,                          /* 34 saved_adv_err_code */
-    0,                          /* 35 saved_adv_err_addr */
-    0,                          /* 36 reserved */
-    0,                          /* 37 reserved */
-    0,                          /* 38 reserved */
-    0,                          /* 39 reserved */
-    0,                          /* 40 reserved */
-    0,                          /* 41 reserved */
-    0,                          /* 42 reserved */
-    0,                          /* 43 reserved */
-    0,                          /* 44 reserved */
-    0,                          /* 45 reserved */
-    0,                          /* 46 reserved */
-    0,                          /* 47 reserved */
-    0,                          /* 48 reserved */
-    0,                          /* 49 reserved */
-    0,                          /* 50 reserved */
-    0,                          /* 51 reserved */
-    0,                          /* 52 reserved */
-    0,                          /* 53 reserved */
-    0,                          /* 54 reserved */
-    0,                          /* 55 reserved */
-    0,                          /* 56 cisptr_lsw */
-    0,                          /* 57 cisprt_msw */
-    PCI_VENDOR_ID_ASP,          /* 58 subsysvid */
-    PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
-    0,                          /* 60 reserved */
-    0,                          /* 61 reserved */
-    0,                          /* 62 reserved */
-    0                           /* 63 reserved */
+static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __initdata = {
+	ADV_EEPROM_BIOS_ENABLE,	/* 00 cfg_lsw */
+	0x0000,			/* 01 cfg_msw */
+	0xFFFF,			/* 02 disc_enable */
+	0xFFFF,			/* 03 wdtr_able */
+	0x4444,			/* 04 sdtr_speed1 */
+	0xFFFF,			/* 05 start_motor */
+	0xFFFF,			/* 06 tagqng_able */
+	0xFFFF,			/* 07 bios_scan */
+	0,			/* 08 scam_tolerant */
+	7,			/* 09 adapter_scsi_id */
+	0,			/*    bios_boot_delay */
+	3,			/* 10 scsi_reset_delay */
+	0,			/*    bios_id_lun */
+	0,			/* 11 termination_se */
+	0,			/*    termination_lvd */
+	0xFFE7,			/* 12 bios_ctrl */
+	0x4444,			/* 13 sdtr_speed2 */
+	0x4444,			/* 14 sdtr_speed3 */
+	ASC_DEF_MAX_HOST_QNG,	/* 15 max_host_qng */
+	ASC_DEF_MAX_DVC_QNG,	/*    max_dvc_qng */
+	0,			/* 16 dvc_cntl */
+	0x4444,			/* 17 sdtr_speed4 */
+	0,			/* 18 serial_number_word1 */
+	0,			/* 19 serial_number_word2 */
+	0,			/* 20 serial_number_word3 */
+	0,			/* 21 check_sum */
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+	,			/* 22-29 oem_name[16] */
+	0,			/* 30 dvc_err_code */
+	0,			/* 31 adv_err_code */
+	0,			/* 32 adv_err_addr */
+	0,			/* 33 saved_dvc_err_code */
+	0,			/* 34 saved_adv_err_code */
+	0,			/* 35 saved_adv_err_addr */
+	0,			/* 36 reserved */
+	0,			/* 37 reserved */
+	0,			/* 38 reserved */
+	0,			/* 39 reserved */
+	0,			/* 40 reserved */
+	0,			/* 41 reserved */
+	0,			/* 42 reserved */
+	0,			/* 43 reserved */
+	0,			/* 44 reserved */
+	0,			/* 45 reserved */
+	0,			/* 46 reserved */
+	0,			/* 47 reserved */
+	0,			/* 48 reserved */
+	0,			/* 49 reserved */
+	0,			/* 50 reserved */
+	0,			/* 51 reserved */
+	0,			/* 52 reserved */
+	0,			/* 53 reserved */
+	0,			/* 54 reserved */
+	0,			/* 55 reserved */
+	0,			/* 56 cisptr_lsw */
+	0,			/* 57 cisprt_msw */
+	PCI_VENDOR_ID_ASP,	/* 58 subsysvid */
+	PCI_DEVICE_ID_38C0800_REV1,	/* 59 subsysid */
+	0,			/* 60 reserved */
+	0,			/* 61 reserved */
+	0,			/* 62 reserved */
+	0			/* 63 reserved */
 };
 
-STATIC ADVEEP_38C0800_CONFIG
-ADVEEP_38C0800_Config_Field_IsChar __initdata = {
-    0,                          /* 00 cfg_lsw */
-    0,                          /* 01 cfg_msw */
-    0,                          /* 02 disc_enable */
-    0,                          /* 03 wdtr_able */
-    0,                          /* 04 sdtr_speed1 */
-    0,                          /* 05 start_motor */
-    0,                          /* 06 tagqng_able */
-    0,                          /* 07 bios_scan */
-    0,                          /* 08 scam_tolerant */
-    1,                          /* 09 adapter_scsi_id */
-    1,                          /*    bios_boot_delay */
-    1,                          /* 10 scsi_reset_delay */
-    1,                          /*    bios_id_lun */
-    1,                          /* 11 termination_se */
-    1,                          /*    termination_lvd */
-    0,                          /* 12 bios_ctrl */
-    0,                          /* 13 sdtr_speed2 */
-    0,                          /* 14 sdtr_speed3 */
-    1,                          /* 15 max_host_qng */
-    1,                          /*    max_dvc_qng */
-    0,                          /* 16 dvc_cntl */
-    0,                          /* 17 sdtr_speed4 */
-    0,                          /* 18 serial_number_word1 */
-    0,                          /* 19 serial_number_word2 */
-    0,                          /* 20 serial_number_word3 */
-    0,                          /* 21 check_sum */
-    { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* 22-29 oem_name[16] */
-    0,                          /* 30 dvc_err_code */
-    0,                          /* 31 adv_err_code */
-    0,                          /* 32 adv_err_addr */
-    0,                          /* 33 saved_dvc_err_code */
-    0,                          /* 34 saved_adv_err_code */
-    0,                          /* 35 saved_adv_err_addr */
-    0,                          /* 36 reserved */
-    0,                          /* 37 reserved */
-    0,                          /* 38 reserved */
-    0,                          /* 39 reserved */
-    0,                          /* 40 reserved */
-    0,                          /* 41 reserved */
-    0,                          /* 42 reserved */
-    0,                          /* 43 reserved */
-    0,                          /* 44 reserved */
-    0,                          /* 45 reserved */
-    0,                          /* 46 reserved */
-    0,                          /* 47 reserved */
-    0,                          /* 48 reserved */
-    0,                          /* 49 reserved */
-    0,                          /* 50 reserved */
-    0,                          /* 51 reserved */
-    0,                          /* 52 reserved */
-    0,                          /* 53 reserved */
-    0,                          /* 54 reserved */
-    0,                          /* 55 reserved */
-    0,                          /* 56 cisptr_lsw */
-    0,                          /* 57 cisprt_msw */
-    0,                          /* 58 subsysvid */
-    0,                          /* 59 subsysid */
-    0,                          /* 60 reserved */
-    0,                          /* 61 reserved */
-    0,                          /* 62 reserved */
-    0                           /* 63 reserved */
+static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __initdata = {
+	0,			/* 00 cfg_lsw */
+	0,			/* 01 cfg_msw */
+	0,			/* 02 disc_enable */
+	0,			/* 03 wdtr_able */
+	0,			/* 04 sdtr_speed1 */
+	0,			/* 05 start_motor */
+	0,			/* 06 tagqng_able */
+	0,			/* 07 bios_scan */
+	0,			/* 08 scam_tolerant */
+	1,			/* 09 adapter_scsi_id */
+	1,			/*    bios_boot_delay */
+	1,			/* 10 scsi_reset_delay */
+	1,			/*    bios_id_lun */
+	1,			/* 11 termination_se */
+	1,			/*    termination_lvd */
+	0,			/* 12 bios_ctrl */
+	0,			/* 13 sdtr_speed2 */
+	0,			/* 14 sdtr_speed3 */
+	1,			/* 15 max_host_qng */
+	1,			/*    max_dvc_qng */
+	0,			/* 16 dvc_cntl */
+	0,			/* 17 sdtr_speed4 */
+	0,			/* 18 serial_number_word1 */
+	0,			/* 19 serial_number_word2 */
+	0,			/* 20 serial_number_word3 */
+	0,			/* 21 check_sum */
+	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+	,			/* 22-29 oem_name[16] */
+	0,			/* 30 dvc_err_code */
+	0,			/* 31 adv_err_code */
+	0,			/* 32 adv_err_addr */
+	0,			/* 33 saved_dvc_err_code */
+	0,			/* 34 saved_adv_err_code */
+	0,			/* 35 saved_adv_err_addr */
+	0,			/* 36 reserved */
+	0,			/* 37 reserved */
+	0,			/* 38 reserved */
+	0,			/* 39 reserved */
+	0,			/* 40 reserved */
+	0,			/* 41 reserved */
+	0,			/* 42 reserved */
+	0,			/* 43 reserved */
+	0,			/* 44 reserved */
+	0,			/* 45 reserved */
+	0,			/* 46 reserved */
+	0,			/* 47 reserved */
+	0,			/* 48 reserved */
+	0,			/* 49 reserved */
+	0,			/* 50 reserved */
+	0,			/* 51 reserved */
+	0,			/* 52 reserved */
+	0,			/* 53 reserved */
+	0,			/* 54 reserved */
+	0,			/* 55 reserved */
+	0,			/* 56 cisptr_lsw */
+	0,			/* 57 cisprt_msw */
+	0,			/* 58 subsysvid */
+	0,			/* 59 subsysid */
+	0,			/* 60 reserved */
+	0,			/* 61 reserved */
+	0,			/* 62 reserved */
+	0			/* 63 reserved */
 };
 
-STATIC ADVEEP_38C1600_CONFIG
-Default_38C1600_EEPROM_Config __initdata = {
-    ADV_EEPROM_BIOS_ENABLE,     /* 00 cfg_lsw */
-    0x0000,                     /* 01 cfg_msw */
-    0xFFFF,                     /* 02 disc_enable */
-    0xFFFF,                     /* 03 wdtr_able */
-    0x5555,                     /* 04 sdtr_speed1 */
-    0xFFFF,                     /* 05 start_motor */
-    0xFFFF,                     /* 06 tagqng_able */
-    0xFFFF,                     /* 07 bios_scan */
-    0,                          /* 08 scam_tolerant */
-    7,                          /* 09 adapter_scsi_id */
-    0,                          /*    bios_boot_delay */
-    3,                          /* 10 scsi_reset_delay */
-    0,                          /*    bios_id_lun */
-    0,                          /* 11 termination_se */
-    0,                          /*    termination_lvd */
-    0xFFE7,                     /* 12 bios_ctrl */
-    0x5555,                     /* 13 sdtr_speed2 */
-    0x5555,                     /* 14 sdtr_speed3 */
-    ASC_DEF_MAX_HOST_QNG,       /* 15 max_host_qng */
-    ASC_DEF_MAX_DVC_QNG,        /*    max_dvc_qng */
-    0,                          /* 16 dvc_cntl */
-    0x5555,                     /* 17 sdtr_speed4 */
-    0,                          /* 18 serial_number_word1 */
-    0,                          /* 19 serial_number_word2 */
-    0,                          /* 20 serial_number_word3 */
-    0,                          /* 21 check_sum */
-    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* 22-29 oem_name[16] */
-    0,                          /* 30 dvc_err_code */
-    0,                          /* 31 adv_err_code */
-    0,                          /* 32 adv_err_addr */
-    0,                          /* 33 saved_dvc_err_code */
-    0,                          /* 34 saved_adv_err_code */
-    0,                          /* 35 saved_adv_err_addr */
-    0,                          /* 36 reserved */
-    0,                          /* 37 reserved */
-    0,                          /* 38 reserved */
-    0,                          /* 39 reserved */
-    0,                          /* 40 reserved */
-    0,                          /* 41 reserved */
-    0,                          /* 42 reserved */
-    0,                          /* 43 reserved */
-    0,                          /* 44 reserved */
-    0,                          /* 45 reserved */
-    0,                          /* 46 reserved */
-    0,                          /* 47 reserved */
-    0,                          /* 48 reserved */
-    0,                          /* 49 reserved */
-    0,                          /* 50 reserved */
-    0,                          /* 51 reserved */
-    0,                          /* 52 reserved */
-    0,                          /* 53 reserved */
-    0,                          /* 54 reserved */
-    0,                          /* 55 reserved */
-    0,                          /* 56 cisptr_lsw */
-    0,                          /* 57 cisprt_msw */
-    PCI_VENDOR_ID_ASP,          /* 58 subsysvid */
-    PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
-    0,                          /* 60 reserved */
-    0,                          /* 61 reserved */
-    0,                          /* 62 reserved */
-    0                           /* 63 reserved */
+static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __initdata = {
+	ADV_EEPROM_BIOS_ENABLE,	/* 00 cfg_lsw */
+	0x0000,			/* 01 cfg_msw */
+	0xFFFF,			/* 02 disc_enable */
+	0xFFFF,			/* 03 wdtr_able */
+	0x5555,			/* 04 sdtr_speed1 */
+	0xFFFF,			/* 05 start_motor */
+	0xFFFF,			/* 06 tagqng_able */
+	0xFFFF,			/* 07 bios_scan */
+	0,			/* 08 scam_tolerant */
+	7,			/* 09 adapter_scsi_id */
+	0,			/*    bios_boot_delay */
+	3,			/* 10 scsi_reset_delay */
+	0,			/*    bios_id_lun */
+	0,			/* 11 termination_se */
+	0,			/*    termination_lvd */
+	0xFFE7,			/* 12 bios_ctrl */
+	0x5555,			/* 13 sdtr_speed2 */
+	0x5555,			/* 14 sdtr_speed3 */
+	ASC_DEF_MAX_HOST_QNG,	/* 15 max_host_qng */
+	ASC_DEF_MAX_DVC_QNG,	/*    max_dvc_qng */
+	0,			/* 16 dvc_cntl */
+	0x5555,			/* 17 sdtr_speed4 */
+	0,			/* 18 serial_number_word1 */
+	0,			/* 19 serial_number_word2 */
+	0,			/* 20 serial_number_word3 */
+	0,			/* 21 check_sum */
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+	,			/* 22-29 oem_name[16] */
+	0,			/* 30 dvc_err_code */
+	0,			/* 31 adv_err_code */
+	0,			/* 32 adv_err_addr */
+	0,			/* 33 saved_dvc_err_code */
+	0,			/* 34 saved_adv_err_code */
+	0,			/* 35 saved_adv_err_addr */
+	0,			/* 36 reserved */
+	0,			/* 37 reserved */
+	0,			/* 38 reserved */
+	0,			/* 39 reserved */
+	0,			/* 40 reserved */
+	0,			/* 41 reserved */
+	0,			/* 42 reserved */
+	0,			/* 43 reserved */
+	0,			/* 44 reserved */
+	0,			/* 45 reserved */
+	0,			/* 46 reserved */
+	0,			/* 47 reserved */
+	0,			/* 48 reserved */
+	0,			/* 49 reserved */
+	0,			/* 50 reserved */
+	0,			/* 51 reserved */
+	0,			/* 52 reserved */
+	0,			/* 53 reserved */
+	0,			/* 54 reserved */
+	0,			/* 55 reserved */
+	0,			/* 56 cisptr_lsw */
+	0,			/* 57 cisprt_msw */
+	PCI_VENDOR_ID_ASP,	/* 58 subsysvid */
+	PCI_DEVICE_ID_38C1600_REV1,	/* 59 subsysid */
+	0,			/* 60 reserved */
+	0,			/* 61 reserved */
+	0,			/* 62 reserved */
+	0			/* 63 reserved */
 };
 
-STATIC ADVEEP_38C1600_CONFIG
-ADVEEP_38C1600_Config_Field_IsChar __initdata = {
-    0,                          /* 00 cfg_lsw */
-    0,                          /* 01 cfg_msw */
-    0,                          /* 02 disc_enable */
-    0,                          /* 03 wdtr_able */
-    0,                          /* 04 sdtr_speed1 */
-    0,                          /* 05 start_motor */
-    0,                          /* 06 tagqng_able */
-    0,                          /* 07 bios_scan */
-    0,                          /* 08 scam_tolerant */
-    1,                          /* 09 adapter_scsi_id */
-    1,                          /*    bios_boot_delay */
-    1,                          /* 10 scsi_reset_delay */
-    1,                          /*    bios_id_lun */
-    1,                          /* 11 termination_se */
-    1,                          /*    termination_lvd */
-    0,                          /* 12 bios_ctrl */
-    0,                          /* 13 sdtr_speed2 */
-    0,                          /* 14 sdtr_speed3 */
-    1,                          /* 15 max_host_qng */
-    1,                          /*    max_dvc_qng */
-    0,                          /* 16 dvc_cntl */
-    0,                          /* 17 sdtr_speed4 */
-    0,                          /* 18 serial_number_word1 */
-    0,                          /* 19 serial_number_word2 */
-    0,                          /* 20 serial_number_word3 */
-    0,                          /* 21 check_sum */
-    { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* 22-29 oem_name[16] */
-    0,                          /* 30 dvc_err_code */
-    0,                          /* 31 adv_err_code */
-    0,                          /* 32 adv_err_addr */
-    0,                          /* 33 saved_dvc_err_code */
-    0,                          /* 34 saved_adv_err_code */
-    0,                          /* 35 saved_adv_err_addr */
-    0,                          /* 36 reserved */
-    0,                          /* 37 reserved */
-    0,                          /* 38 reserved */
-    0,                          /* 39 reserved */
-    0,                          /* 40 reserved */
-    0,                          /* 41 reserved */
-    0,                          /* 42 reserved */
-    0,                          /* 43 reserved */
-    0,                          /* 44 reserved */
-    0,                          /* 45 reserved */
-    0,                          /* 46 reserved */
-    0,                          /* 47 reserved */
-    0,                          /* 48 reserved */
-    0,                          /* 49 reserved */
-    0,                          /* 50 reserved */
-    0,                          /* 51 reserved */
-    0,                          /* 52 reserved */
-    0,                          /* 53 reserved */
-    0,                          /* 54 reserved */
-    0,                          /* 55 reserved */
-    0,                          /* 56 cisptr_lsw */
-    0,                          /* 57 cisprt_msw */
-    0,                          /* 58 subsysvid */
-    0,                          /* 59 subsysid */
-    0,                          /* 60 reserved */
-    0,                          /* 61 reserved */
-    0,                          /* 62 reserved */
-    0                           /* 63 reserved */
+static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __initdata = {
+	0,			/* 00 cfg_lsw */
+	0,			/* 01 cfg_msw */
+	0,			/* 02 disc_enable */
+	0,			/* 03 wdtr_able */
+	0,			/* 04 sdtr_speed1 */
+	0,			/* 05 start_motor */
+	0,			/* 06 tagqng_able */
+	0,			/* 07 bios_scan */
+	0,			/* 08 scam_tolerant */
+	1,			/* 09 adapter_scsi_id */
+	1,			/*    bios_boot_delay */
+	1,			/* 10 scsi_reset_delay */
+	1,			/*    bios_id_lun */
+	1,			/* 11 termination_se */
+	1,			/*    termination_lvd */
+	0,			/* 12 bios_ctrl */
+	0,			/* 13 sdtr_speed2 */
+	0,			/* 14 sdtr_speed3 */
+	1,			/* 15 max_host_qng */
+	1,			/*    max_dvc_qng */
+	0,			/* 16 dvc_cntl */
+	0,			/* 17 sdtr_speed4 */
+	0,			/* 18 serial_number_word1 */
+	0,			/* 19 serial_number_word2 */
+	0,			/* 20 serial_number_word3 */
+	0,			/* 21 check_sum */
+	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
+	,			/* 22-29 oem_name[16] */
+	0,			/* 30 dvc_err_code */
+	0,			/* 31 adv_err_code */
+	0,			/* 32 adv_err_addr */
+	0,			/* 33 saved_dvc_err_code */
+	0,			/* 34 saved_adv_err_code */
+	0,			/* 35 saved_adv_err_addr */
+	0,			/* 36 reserved */
+	0,			/* 37 reserved */
+	0,			/* 38 reserved */
+	0,			/* 39 reserved */
+	0,			/* 40 reserved */
+	0,			/* 41 reserved */
+	0,			/* 42 reserved */
+	0,			/* 43 reserved */
+	0,			/* 44 reserved */
+	0,			/* 45 reserved */
+	0,			/* 46 reserved */
+	0,			/* 47 reserved */
+	0,			/* 48 reserved */
+	0,			/* 49 reserved */
+	0,			/* 50 reserved */
+	0,			/* 51 reserved */
+	0,			/* 52 reserved */
+	0,			/* 53 reserved */
+	0,			/* 54 reserved */
+	0,			/* 55 reserved */
+	0,			/* 56 cisptr_lsw */
+	0,			/* 57 cisprt_msw */
+	0,			/* 58 subsysvid */
+	0,			/* 59 subsysid */
+	0,			/* 60 reserved */
+	0,			/* 61 reserved */
+	0,			/* 62 reserved */
+	0			/* 63 reserved */
 };
 
 /*
@@ -14393,136 +14191,128 @@
  * For a non-fatal error return a warning code. If there are no warnings
  * then 0 is returned.
  */
-STATIC int __init
-AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
+static int __init AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
 {
-    ushort      warn_code;
-    AdvPortAddr iop_base;
-    uchar       pci_cmd_reg;
-    int         status;
+	ushort warn_code;
+	AdvPortAddr iop_base;
+	uchar pci_cmd_reg;
+	int status;
 
-    warn_code = 0;
-    asc_dvc->err_code = 0;
-    iop_base = asc_dvc->iop_base;
+	warn_code = 0;
+	asc_dvc->err_code = 0;
+	iop_base = asc_dvc->iop_base;
 
-    /*
-     * PCI Command Register
-     *
-     * Note: AscPCICmdRegBits_BusMastering definition (0x0007) includes
-     * I/O Space Control, Memory Space Control and Bus Master Control bits.
-     */
+	/*
+	 * PCI Command Register
+	 *
+	 * Note: AscPCICmdRegBits_BusMastering definition (0x0007) includes
+	 * I/O Space Control, Memory Space Control and Bus Master Control bits.
+	 */
 
-    if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc,
-                            AscPCIConfigCommandRegister))
-         & AscPCICmdRegBits_BusMastering)
-        != AscPCICmdRegBits_BusMastering)
-    {
-        pci_cmd_reg |= AscPCICmdRegBits_BusMastering;
+	if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc,
+						    AscPCIConfigCommandRegister))
+	     & AscPCICmdRegBits_BusMastering)
+	    != AscPCICmdRegBits_BusMastering) {
+		pci_cmd_reg |= AscPCICmdRegBits_BusMastering;
 
-        DvcAdvWritePCIConfigByte(asc_dvc,
-                AscPCIConfigCommandRegister, pci_cmd_reg);
+		DvcAdvWritePCIConfigByte(asc_dvc,
+					 AscPCIConfigCommandRegister,
+					 pci_cmd_reg);
 
-        if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister))
-             & AscPCICmdRegBits_BusMastering)
-            != AscPCICmdRegBits_BusMastering)
-        {
-            warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
-        }
-    }
+		if (((DvcAdvReadPCIConfigByte
+		      (asc_dvc, AscPCIConfigCommandRegister))
+		     & AscPCICmdRegBits_BusMastering)
+		    != AscPCICmdRegBits_BusMastering) {
+			warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+		}
+	}
 
-    /*
-     * PCI Latency Timer
-     *
-     * If the "latency timer" register is 0x20 or above, then we don't need
-     * to change it.  Otherwise, set it to 0x20 (i.e. set it to 0x20 if it
-     * comes up less than 0x20).
-     */
-    if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) {
-        DvcAdvWritePCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer, 0x20);
-        if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20)
-        {
-            warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
-        }
-    }
+	/*
+	 * PCI Latency Timer
+	 *
+	 * If the "latency timer" register is 0x20 or above, then we don't need
+	 * to change it.  Otherwise, set it to 0x20 (i.e. set it to 0x20 if it
+	 * comes up less than 0x20).
+	 */
+	if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) {
+		DvcAdvWritePCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer,
+					 0x20);
+		if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) <
+		    0x20) {
+			warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+		}
+	}
 
-    /*
-     * Save the state of the PCI Configuration Command Register
-     * "Parity Error Response Control" Bit. If the bit is clear (0),
-     * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
-     * DMA parity errors.
-     */
-    asc_dvc->cfg->control_flag = 0;
-    if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)
-         & AscPCICmdRegBits_ParErrRespCtrl)) == 0)
-    {
-        asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
-    }
+	/*
+	 * Save the state of the PCI Configuration Command Register
+	 * "Parity Error Response Control" Bit. If the bit is clear (0),
+	 * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
+	 * DMA parity errors.
+	 */
+	asc_dvc->cfg->control_flag = 0;
+	if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)
+	      & AscPCICmdRegBits_ParErrRespCtrl)) == 0) {
+		asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
+	}
 
-    asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
-      ADV_LIB_VERSION_MINOR;
-    asc_dvc->cfg->chip_version =
-      AdvGetChipVersion(iop_base, asc_dvc->bus_type);
+	asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
+	    ADV_LIB_VERSION_MINOR;
+	asc_dvc->cfg->chip_version =
+	    AdvGetChipVersion(iop_base, asc_dvc->bus_type);
 
-    ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
-        (ushort) AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
-        (ushort) ADV_CHIP_ID_BYTE);
+	ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
+		 (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
+		 (ushort)ADV_CHIP_ID_BYTE);
 
-    ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
-        (ushort) AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
-        (ushort) ADV_CHIP_ID_WORD);
+	ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
+		 (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
+		 (ushort)ADV_CHIP_ID_WORD);
 
-    /*
-     * Reset the chip to start and allow register writes.
-     */
-    if (AdvFindSignature(iop_base) == 0)
-    {
-        asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
-        return ADV_ERROR;
-    }
-    else {
-        /*
-         * The caller must set 'chip_type' to a valid setting.
-         */
-        if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
-            asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
-            asc_dvc->chip_type != ADV_CHIP_ASC38C1600)
-        {
-            asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
-            return ADV_ERROR;
-        }
+	/*
+	 * Reset the chip to start and allow register writes.
+	 */
+	if (AdvFindSignature(iop_base) == 0) {
+		asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+		return ADV_ERROR;
+	} else {
+		/*
+		 * The caller must set 'chip_type' to a valid setting.
+		 */
+		if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
+		    asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
+		    asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
+			asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
+			return ADV_ERROR;
+		}
 
-        /*
-         * Reset Chip.
-         */
-        AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
-            ADV_CTRL_REG_CMD_RESET);
-        DvcSleepMilliSecond(100);
-        AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
-            ADV_CTRL_REG_CMD_WR_IO_REG);
+		/*
+		 * Reset Chip.
+		 */
+		AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+				     ADV_CTRL_REG_CMD_RESET);
+		DvcSleepMilliSecond(100);
+		AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+				     ADV_CTRL_REG_CMD_WR_IO_REG);
 
-        if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
-        {
-            if ((status = AdvInitFrom38C1600EEP(asc_dvc)) == ADV_ERROR)
-            {
-                return ADV_ERROR;
-            }
-        } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
-        {
-            if ((status = AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR)
-            {
-                return ADV_ERROR;
-            }
-        } else
-        {
-            if ((status = AdvInitFrom3550EEP(asc_dvc)) == ADV_ERROR)
-            {
-                return ADV_ERROR;
-            }
-        }
-        warn_code |= status;
-    }
+		if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+			if ((status =
+			     AdvInitFrom38C1600EEP(asc_dvc)) == ADV_ERROR) {
+				return ADV_ERROR;
+			}
+		} else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+			if ((status =
+			     AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR) {
+				return ADV_ERROR;
+			}
+		} else {
+			if ((status = AdvInitFrom3550EEP(asc_dvc)) == ADV_ERROR) {
+				return ADV_ERROR;
+			}
+		}
+		warn_code |= status;
+	}
 
-    return warn_code;
+	return warn_code;
 }
 
 /*
@@ -14535,574 +14325,563 @@
  *
  * Needed after initialization for error recovery.
  */
-STATIC int
-AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
+static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
 {
-    AdvPortAddr iop_base;
-    ushort      warn_code;
-    ADV_DCNT    sum;
-    int         begin_addr;
-    int         end_addr;
-    ushort      code_sum;
-    int         word;
-    int         j;
-    int         adv_asc3550_expanded_size;
-    ADV_CARR_T  *carrp;
-    ADV_DCNT    contig_len;
-    ADV_SDCNT   buf_size;
-    ADV_PADDR   carr_paddr;
-    int         i;
-    ushort      scsi_cfg1;
-    uchar       tid;
-    ushort      bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */
-    ushort      wdtr_able = 0, sdtr_able, tagqng_able;
-    uchar       max_cmd[ADV_MAX_TID + 1];
+	AdvPortAddr iop_base;
+	ushort warn_code;
+	ADV_DCNT sum;
+	int begin_addr;
+	int end_addr;
+	ushort code_sum;
+	int word;
+	int j;
+	int adv_asc3550_expanded_size;
+	ADV_CARR_T *carrp;
+	ADV_DCNT contig_len;
+	ADV_SDCNT buf_size;
+	ADV_PADDR carr_paddr;
+	int i;
+	ushort scsi_cfg1;
+	uchar tid;
+	ushort bios_mem[ASC_MC_BIOSLEN / 2];	/* BIOS RISC Memory 0x40-0x8F. */
+	ushort wdtr_able = 0, sdtr_able, tagqng_able;
+	uchar max_cmd[ADV_MAX_TID + 1];
 
-    /* If there is already an error, don't continue. */
-    if (asc_dvc->err_code != 0)
-    {
-        return ADV_ERROR;
-    }
+	/* If there is already an error, don't continue. */
+	if (asc_dvc->err_code != 0) {
+		return ADV_ERROR;
+	}
 
-    /*
-     * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
-     */
-    if (asc_dvc->chip_type != ADV_CHIP_ASC3550)
-    {
-        asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
-        return ADV_ERROR;
-    }
+	/*
+	 * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
+	 */
+	if (asc_dvc->chip_type != ADV_CHIP_ASC3550) {
+		asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
+		return ADV_ERROR;
+	}
 
-    warn_code = 0;
-    iop_base = asc_dvc->iop_base;
+	warn_code = 0;
+	iop_base = asc_dvc->iop_base;
 
-    /*
-     * Save the RISC memory BIOS region before writing the microcode.
-     * The BIOS may already be loaded and using its RISC LRAM region
-     * so its region must be saved and restored.
-     *
-     * Note: This code makes the assumption, which is currently true,
-     * that a chip reset does not clear RISC LRAM.
-     */
-    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
-    {
-        AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
-    }
+	/*
+	 * Save the RISC memory BIOS region before writing the microcode.
+	 * The BIOS may already be loaded and using its RISC LRAM region
+	 * so its region must be saved and restored.
+	 *
+	 * Note: This code makes the assumption, which is currently true,
+	 * that a chip reset does not clear RISC LRAM.
+	 */
+	for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+		AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+				bios_mem[i]);
+	}
 
-    /*
-     * Save current per TID negotiated values.
-     */
-    if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
-    {
-        ushort  bios_version, major, minor;
+	/*
+	 * Save current per TID negotiated values.
+	 */
+	if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) {
+		ushort bios_version, major, minor;
 
-        bios_version = bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM)/2];
-        major = (bios_version  >> 12) & 0xF;
-        minor = (bios_version  >> 8) & 0xF;
-        if (major < 3 || (major == 3 && minor == 1))
-        {
-            /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
-            AdvReadWordLram(iop_base, 0x120, wdtr_able);
-        } else
-        {
-            AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
-        }
-    }
-    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
-    for (tid = 0; tid <= ADV_MAX_TID; tid++)
-    {
-        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
-            max_cmd[tid]);
-    }
+		bios_version =
+		    bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2];
+		major = (bios_version >> 12) & 0xF;
+		minor = (bios_version >> 8) & 0xF;
+		if (major < 3 || (major == 3 && minor == 1)) {
+			/* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
+			AdvReadWordLram(iop_base, 0x120, wdtr_able);
+		} else {
+			AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+		}
+	}
+	AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+	AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+	for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+		AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+				max_cmd[tid]);
+	}
 
-    /*
-     * Load the Microcode
-     *
-     * Write the microcode image to RISC memory starting at address 0.
-     */
-    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
-    /* Assume the following compressed format of the microcode buffer:
-     *
-     *  254 word (508 byte) table indexed by byte code followed
-     *  by the following byte codes:
-     *
-     *    1-Byte Code:
-     *      00: Emit word 0 in table.
-     *      01: Emit word 1 in table.
-     *      .
-     *      FD: Emit word 253 in table.
-     *
-     *    Multi-Byte Code:
-     *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
-     *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
-     */
-    word = 0;
-    for (i = 253 * 2; i < _adv_asc3550_size; i++)
-    {
-        if (_adv_asc3550_buf[i] == 0xff)
-        {
-            for (j = 0; j < _adv_asc3550_buf[i + 1]; j++)
-            {
-                AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                    _adv_asc3550_buf[i + 3] << 8) |
-                _adv_asc3550_buf[i + 2]));
-                word++;
-            }
-            i += 3;
-        } else if (_adv_asc3550_buf[i] == 0xfe)
-        {
-            AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                _adv_asc3550_buf[i + 2] << 8) |
-                _adv_asc3550_buf[i + 1]));
-            i += 2;
-            word++;
-        } else
-        {
-            AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) |
-                _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
-            word++;
-        }
-    }
+	/*
+	 * Load the Microcode
+	 *
+	 * Write the microcode image to RISC memory starting at address 0.
+	 */
+	AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+	/* Assume the following compressed format of the microcode buffer:
+	 *
+	 *  254 word (508 byte) table indexed by byte code followed
+	 *  by the following byte codes:
+	 *
+	 *    1-Byte Code:
+	 *      00: Emit word 0 in table.
+	 *      01: Emit word 1 in table.
+	 *      .
+	 *      FD: Emit word 253 in table.
+	 *
+	 *    Multi-Byte Code:
+	 *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+	 *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+	 */
+	word = 0;
+	for (i = 253 * 2; i < _adv_asc3550_size; i++) {
+		if (_adv_asc3550_buf[i] == 0xff) {
+			for (j = 0; j < _adv_asc3550_buf[i + 1]; j++) {
+				AdvWriteWordAutoIncLram(iop_base, (((ushort)
+								    _adv_asc3550_buf
+								    [i +
+								     3] << 8) |
+								   _adv_asc3550_buf
+								   [i + 2]));
+				word++;
+			}
+			i += 3;
+		} else if (_adv_asc3550_buf[i] == 0xfe) {
+			AdvWriteWordAutoIncLram(iop_base, (((ushort)
+							    _adv_asc3550_buf[i +
+									     2]
+							    << 8) |
+							   _adv_asc3550_buf[i +
+									    1]));
+			i += 2;
+			word++;
+		} else {
+			AdvWriteWordAutoIncLram(iop_base, (((ushort)
+							    _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) | _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
+			word++;
+		}
+	}
 
-    /*
-     * Set 'word' for later use to clear the rest of memory and save
-     * the expanded mcode size.
-     */
-    word *= 2;
-    adv_asc3550_expanded_size = word;
+	/*
+	 * Set 'word' for later use to clear the rest of memory and save
+	 * the expanded mcode size.
+	 */
+	word *= 2;
+	adv_asc3550_expanded_size = word;
 
-    /*
-     * Clear the rest of ASC-3550 Internal RAM (8KB).
-     */
-    for (; word < ADV_3550_MEMSIZE; word += 2)
-    {
-        AdvWriteWordAutoIncLram(iop_base, 0);
-    }
+	/*
+	 * Clear the rest of ASC-3550 Internal RAM (8KB).
+	 */
+	for (; word < ADV_3550_MEMSIZE; word += 2) {
+		AdvWriteWordAutoIncLram(iop_base, 0);
+	}
 
-    /*
-     * Verify the microcode checksum.
-     */
-    sum = 0;
-    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+	/*
+	 * Verify the microcode checksum.
+	 */
+	sum = 0;
+	AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
 
-    for (word = 0; word < adv_asc3550_expanded_size; word += 2)
-    {
-        sum += AdvReadWordAutoIncLram(iop_base);
-    }
+	for (word = 0; word < adv_asc3550_expanded_size; word += 2) {
+		sum += AdvReadWordAutoIncLram(iop_base);
+	}
 
-    if (sum != _adv_asc3550_chksum)
-    {
-        asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
-        return ADV_ERROR;
-    }
+	if (sum != _adv_asc3550_chksum) {
+		asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+		return ADV_ERROR;
+	}
 
-    /*
-     * Restore the RISC memory BIOS region.
-     */
-    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
-    {
-        AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
-    }
+	/*
+	 * Restore the RISC memory BIOS region.
+	 */
+	for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+		AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+				 bios_mem[i]);
+	}
 
-    /*
-     * Calculate and write the microcode code checksum to the microcode
-     * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
-     */
-    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
-    AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
-    code_sum = 0;
-    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
-    for (word = begin_addr; word < end_addr; word += 2)
-    {
-        code_sum += AdvReadWordAutoIncLram(iop_base);
-    }
-    AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+	/*
+	 * Calculate and write the microcode code checksum to the microcode
+	 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+	 */
+	AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+	AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+	code_sum = 0;
+	AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+	for (word = begin_addr; word < end_addr; word += 2) {
+		code_sum += AdvReadWordAutoIncLram(iop_base);
+	}
+	AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
 
-    /*
-     * Read and save microcode version and date.
-     */
-    AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
-    AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
+	/*
+	 * Read and save microcode version and date.
+	 */
+	AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
+			asc_dvc->cfg->mcode_date);
+	AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
+			asc_dvc->cfg->mcode_version);
 
-    /*
-     * Set the chip type to indicate the ASC3550.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
+	/*
+	 * Set the chip type to indicate the ASC3550.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
 
-    /*
-     * If the PCI Configuration Command Register "Parity Error Response
-     * Control" Bit was clear (0), then set the microcode variable
-     * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
-     * to ignore DMA parity errors.
-     */
-    if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
-    {
-        AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
-        word |= CONTROL_FLAG_IGNORE_PERR;
-        AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
-    }
+	/*
+	 * If the PCI Configuration Command Register "Parity Error Response
+	 * Control" Bit was clear (0), then set the microcode variable
+	 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+	 * to ignore DMA parity errors.
+	 */
+	if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
+		AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+		word |= CONTROL_FLAG_IGNORE_PERR;
+		AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+	}
 
-    /*
-     * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
-     * threshold of 128 bytes. This register is only accessible to the host.
-     */
-    AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
-        START_CTL_EMFU | READ_CMD_MRM);
+	/*
+	 * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
+	 * threshold of 128 bytes. This register is only accessible to the host.
+	 */
+	AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+			     START_CTL_EMFU | READ_CMD_MRM);
 
-    /*
-     * Microcode operating variables for WDTR, SDTR, and command tag
-     * queuing will be set in AdvInquiryHandling() based on what a
-     * device reports it is capable of in Inquiry byte 7.
-     *
-     * If SCSI Bus Resets have been disabled, then directly set
-     * SDTR and WDTR from the EEPROM configuration. This will allow
-     * the BIOS and warm boot to work without a SCSI bus hang on
-     * the Inquiry caused by host and target mismatched DTR values.
-     * Without the SCSI Bus Reset, before an Inquiry a device can't
-     * be assumed to be in Asynchronous, Narrow mode.
-     */
-    if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0)
-    {
-        AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able);
-        AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able);
-    }
+	/*
+	 * Microcode operating variables for WDTR, SDTR, and command tag
+	 * queuing will be set in AdvInquiryHandling() based on what a
+	 * device reports it is capable of in Inquiry byte 7.
+	 *
+	 * If SCSI Bus Resets have been disabled, then directly set
+	 * SDTR and WDTR from the EEPROM configuration. This will allow
+	 * the BIOS and warm boot to work without a SCSI bus hang on
+	 * the Inquiry caused by host and target mismatched DTR values.
+	 * Without the SCSI Bus Reset, before an Inquiry a device can't
+	 * be assumed to be in Asynchronous, Narrow mode.
+	 */
+	if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
+		AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
+				 asc_dvc->wdtr_able);
+		AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
+				 asc_dvc->sdtr_able);
+	}
 
-    /*
-     * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
-     * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
-     * bitmask. These values determine the maximum SDTR speed negotiated
-     * with a device.
-     *
-     * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
-     * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
-     * without determining here whether the device supports SDTR.
-     *
-     * 4-bit speed  SDTR speed name
-     * ===========  ===============
-     * 0000b (0x0)  SDTR disabled
-     * 0001b (0x1)  5 Mhz
-     * 0010b (0x2)  10 Mhz
-     * 0011b (0x3)  20 Mhz (Ultra)
-     * 0100b (0x4)  40 Mhz (LVD/Ultra2)
-     * 0101b (0x5)  80 Mhz (LVD2/Ultra3)
-     * 0110b (0x6)  Undefined
-     * .
-     * 1111b (0xF)  Undefined
-     */
-    word = 0;
-    for (tid = 0; tid <= ADV_MAX_TID; tid++)
-    {
-        if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able)
-        {
-            /* Set Ultra speed for TID 'tid'. */
-            word |= (0x3 << (4 * (tid % 4)));
-        } else
-        {
-            /* Set Fast speed for TID 'tid'. */
-            word |= (0x2 << (4 * (tid % 4)));
-        }
-        if (tid == 3) /* Check if done with sdtr_speed1. */
-        {
-            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
-            word = 0;
-        } else if (tid == 7) /* Check if done with sdtr_speed2. */
-        {
-            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
-            word = 0;
-        } else if (tid == 11) /* Check if done with sdtr_speed3. */
-        {
-            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
-            word = 0;
-        } else if (tid == 15) /* Check if done with sdtr_speed4. */
-        {
-            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
-            /* End of loop. */
-        }
-    }
+	/*
+	 * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
+	 * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
+	 * bitmask. These values determine the maximum SDTR speed negotiated
+	 * with a device.
+	 *
+	 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+	 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+	 * without determining here whether the device supports SDTR.
+	 *
+	 * 4-bit speed  SDTR speed name
+	 * ===========  ===============
+	 * 0000b (0x0)  SDTR disabled
+	 * 0001b (0x1)  5 Mhz
+	 * 0010b (0x2)  10 Mhz
+	 * 0011b (0x3)  20 Mhz (Ultra)
+	 * 0100b (0x4)  40 Mhz (LVD/Ultra2)
+	 * 0101b (0x5)  80 Mhz (LVD2/Ultra3)
+	 * 0110b (0x6)  Undefined
+	 * .
+	 * 1111b (0xF)  Undefined
+	 */
+	word = 0;
+	for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+		if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) {
+			/* Set Ultra speed for TID 'tid'. */
+			word |= (0x3 << (4 * (tid % 4)));
+		} else {
+			/* Set Fast speed for TID 'tid'. */
+			word |= (0x2 << (4 * (tid % 4)));
+		}
+		if (tid == 3) {	/* Check if done with sdtr_speed1. */
+			AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
+			word = 0;
+		} else if (tid == 7) {	/* Check if done with sdtr_speed2. */
+			AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
+			word = 0;
+		} else if (tid == 11) {	/* Check if done with sdtr_speed3. */
+			AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
+			word = 0;
+		} else if (tid == 15) {	/* Check if done with sdtr_speed4. */
+			AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
+			/* End of loop. */
+		}
+	}
 
-    /*
-     * Set microcode operating variable for the disconnect per TID bitmask.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
+	/*
+	 * Set microcode operating variable for the disconnect per TID bitmask.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
+			 asc_dvc->cfg->disc_enable);
 
-    /*
-     * Set SCSI_CFG0 Microcode Default Value.
-     *
-     * The microcode will set the SCSI_CFG0 register using this value
-     * after it is started below.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
-        PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
-        asc_dvc->chip_scsi_id);
+	/*
+	 * Set SCSI_CFG0 Microcode Default Value.
+	 *
+	 * The microcode will set the SCSI_CFG0 register using this value
+	 * after it is started below.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+			 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+			 asc_dvc->chip_scsi_id);
 
-    /*
-     * Determine SCSI_CFG1 Microcode Default Value.
-     *
-     * The microcode will set the SCSI_CFG1 register using this value
-     * after it is started below.
-     */
+	/*
+	 * Determine SCSI_CFG1 Microcode Default Value.
+	 *
+	 * The microcode will set the SCSI_CFG1 register using this value
+	 * after it is started below.
+	 */
 
-    /* Read current SCSI_CFG1 Register value. */
-    scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+	/* Read current SCSI_CFG1 Register value. */
+	scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
 
-    /*
-     * If all three connectors are in use, return an error.
-     */
-    if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
-        (scsi_cfg1 & CABLE_ILLEGAL_B) == 0)
-    {
-            asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
-            return ADV_ERROR;
-    }
+	/*
+	 * If all three connectors are in use, return an error.
+	 */
+	if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
+	    (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) {
+		asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
+		return ADV_ERROR;
+	}
 
-    /*
-     * If the internal narrow cable is reversed all of the SCSI_CTRL
-     * register signals will be set. Check for and return an error if
-     * this condition is found.
-     */
-    if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07)
-    {
-        asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
-        return ADV_ERROR;
-    }
+	/*
+	 * If the internal narrow cable is reversed all of the SCSI_CTRL
+	 * register signals will be set. Check for and return an error if
+	 * this condition is found.
+	 */
+	if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
+		asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+		return ADV_ERROR;
+	}
 
-    /*
-     * If this is a differential board and a single-ended device
-     * is attached to one of the connectors, return an error.
-     */
-    if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0)
-    {
-        asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
-        return ADV_ERROR;
-    }
+	/*
+	 * If this is a differential board and a single-ended device
+	 * is attached to one of the connectors, return an error.
+	 */
+	if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) {
+		asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
+		return ADV_ERROR;
+	}
 
-    /*
-     * If automatic termination control is enabled, then set the
-     * termination value based on a table listed in a_condor.h.
-     *
-     * If manual termination was specified with an EEPROM setting
-     * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
-     * is ready to be 'ored' into SCSI_CFG1.
-     */
-    if (asc_dvc->cfg->termination == 0)
-    {
-        /*
-         * The software always controls termination by setting TERM_CTL_SEL.
-         * If TERM_CTL_SEL were set to 0, the hardware would set termination.
-         */
-        asc_dvc->cfg->termination |= TERM_CTL_SEL;
+	/*
+	 * If automatic termination control is enabled, then set the
+	 * termination value based on a table listed in a_condor.h.
+	 *
+	 * If manual termination was specified with an EEPROM setting
+	 * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
+	 * is ready to be 'ored' into SCSI_CFG1.
+	 */
+	if (asc_dvc->cfg->termination == 0) {
+		/*
+		 * The software always controls termination by setting TERM_CTL_SEL.
+		 * If TERM_CTL_SEL were set to 0, the hardware would set termination.
+		 */
+		asc_dvc->cfg->termination |= TERM_CTL_SEL;
 
-        switch(scsi_cfg1 & CABLE_DETECT)
-        {
-            /* TERM_CTL_H: on, TERM_CTL_L: on */
-            case 0x3: case 0x7: case 0xB: case 0xD: case 0xE: case 0xF:
-                asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
-                break;
+		switch (scsi_cfg1 & CABLE_DETECT) {
+			/* TERM_CTL_H: on, TERM_CTL_L: on */
+		case 0x3:
+		case 0x7:
+		case 0xB:
+		case 0xD:
+		case 0xE:
+		case 0xF:
+			asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
+			break;
 
-            /* TERM_CTL_H: on, TERM_CTL_L: off */
-            case 0x1: case 0x5: case 0x9: case 0xA: case 0xC:
-                asc_dvc->cfg->termination |= TERM_CTL_H;
-                break;
+			/* TERM_CTL_H: on, TERM_CTL_L: off */
+		case 0x1:
+		case 0x5:
+		case 0x9:
+		case 0xA:
+		case 0xC:
+			asc_dvc->cfg->termination |= TERM_CTL_H;
+			break;
 
-            /* TERM_CTL_H: off, TERM_CTL_L: off */
-            case 0x2: case 0x6:
-                break;
-        }
-    }
+			/* TERM_CTL_H: off, TERM_CTL_L: off */
+		case 0x2:
+		case 0x6:
+			break;
+		}
+	}
 
-    /*
-     * Clear any set TERM_CTL_H and TERM_CTL_L bits.
-     */
-    scsi_cfg1 &= ~TERM_CTL;
+	/*
+	 * Clear any set TERM_CTL_H and TERM_CTL_L bits.
+	 */
+	scsi_cfg1 &= ~TERM_CTL;
 
-    /*
-     * Invert the TERM_CTL_H and TERM_CTL_L bits and then
-     * set 'scsi_cfg1'. The TERM_POL bit does not need to be
-     * referenced, because the hardware internally inverts
-     * the Termination High and Low bits if TERM_POL is set.
-     */
-    scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
+	/*
+	 * Invert the TERM_CTL_H and TERM_CTL_L bits and then
+	 * set 'scsi_cfg1'. The TERM_POL bit does not need to be
+	 * referenced, because the hardware internally inverts
+	 * the Termination High and Low bits if TERM_POL is set.
+	 */
+	scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
 
-    /*
-     * Set SCSI_CFG1 Microcode Default Value
-     *
-     * Set filter value and possibly modified termination control
-     * bits in the Microcode SCSI_CFG1 Register Value.
-     *
-     * The microcode will set the SCSI_CFG1 register using this value
-     * after it is started below.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
-        FLTR_DISABLE | scsi_cfg1);
+	/*
+	 * Set SCSI_CFG1 Microcode Default Value
+	 *
+	 * Set filter value and possibly modified termination control
+	 * bits in the Microcode SCSI_CFG1 Register Value.
+	 *
+	 * The microcode will set the SCSI_CFG1 register using this value
+	 * after it is started below.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
+			 FLTR_DISABLE | scsi_cfg1);
 
-    /*
-     * Set MEM_CFG Microcode Default Value
-     *
-     * The microcode will set the MEM_CFG register using this value
-     * after it is started below.
-     *
-     * MEM_CFG may be accessed as a word or byte, but only bits 0-7
-     * are defined.
-     *
-     * ASC-3550 has 8KB internal memory.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
-        BIOS_EN | RAM_SZ_8KB);
+	/*
+	 * Set MEM_CFG Microcode Default Value
+	 *
+	 * The microcode will set the MEM_CFG register using this value
+	 * after it is started below.
+	 *
+	 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+	 * are defined.
+	 *
+	 * ASC-3550 has 8KB internal memory.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+			 BIOS_EN | RAM_SZ_8KB);
 
-    /*
-     * Set SEL_MASK Microcode Default Value
-     *
-     * The microcode will set the SEL_MASK register using this value
-     * after it is started below.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
-        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+	/*
+	 * Set SEL_MASK Microcode Default Value
+	 *
+	 * The microcode will set the SEL_MASK register using this value
+	 * after it is started below.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+			 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
 
-    /*
-     * Build carrier freelist.
-     *
-     * Driver must have already allocated memory and set 'carrier_buf'.
-     */
-    ASC_ASSERT(asc_dvc->carrier_buf != NULL);
+	/*
+	 * Build carrier freelist.
+	 *
+	 * Driver must have already allocated memory and set 'carrier_buf'.
+	 */
+	ASC_ASSERT(asc_dvc->carrier_buf != NULL);
 
-    carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
-    asc_dvc->carr_freelist = NULL;
-    if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf)
-    {
-        buf_size = ADV_CARRIER_BUFSIZE;
-    } else
-    {
-        buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
-    }
+	carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+	asc_dvc->carr_freelist = NULL;
+	if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
+		buf_size = ADV_CARRIER_BUFSIZE;
+	} else {
+		buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+	}
 
-    do {
-        /*
-         * Get physical address of the carrier 'carrp'.
-         */
-        contig_len = sizeof(ADV_CARR_T);
-        carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
-            (ADV_SDCNT *) &contig_len, ADV_IS_CARRIER_FLAG));
+	do {
+		/*
+		 * Get physical address of the carrier 'carrp'.
+		 */
+		contig_len = sizeof(ADV_CARR_T);
+		carr_paddr =
+		    cpu_to_le32(DvcGetPhyAddr
+				(asc_dvc, NULL, (uchar *)carrp,
+				 (ADV_SDCNT *)&contig_len,
+				 ADV_IS_CARRIER_FLAG));
 
-        buf_size -= sizeof(ADV_CARR_T);
+		buf_size -= sizeof(ADV_CARR_T);
 
-        /*
-         * If the current carrier is not physically contiguous, then
-         * maybe there was a page crossing. Try the next carrier aligned
-         * start address.
-         */
-        if (contig_len < sizeof(ADV_CARR_T))
-        {
-            carrp++;
-            continue;
-        }
+		/*
+		 * If the current carrier is not physically contiguous, then
+		 * maybe there was a page crossing. Try the next carrier aligned
+		 * start address.
+		 */
+		if (contig_len < sizeof(ADV_CARR_T)) {
+			carrp++;
+			continue;
+		}
 
-        carrp->carr_pa = carr_paddr;
-        carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
+		carrp->carr_pa = carr_paddr;
+		carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
 
-        /*
-         * Insert the carrier at the beginning of the freelist.
-         */
-        carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
-        asc_dvc->carr_freelist = carrp;
+		/*
+		 * Insert the carrier at the beginning of the freelist.
+		 */
+		carrp->next_vpa =
+		    cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+		asc_dvc->carr_freelist = carrp;
 
-        carrp++;
-    }
-    while (buf_size > 0);
+		carrp++;
+	}
+	while (buf_size > 0);
 
-    /*
-     * Set-up the Host->RISC Initiator Command Queue (ICQ).
-     */
+	/*
+	 * Set-up the Host->RISC Initiator Command Queue (ICQ).
+	 */
 
-    if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL)
-    {
-        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
-        return ADV_ERROR;
-    }
-    asc_dvc->carr_freelist = (ADV_CARR_T *)
-        ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+	if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
+		asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+		return ADV_ERROR;
+	}
+	asc_dvc->carr_freelist = (ADV_CARR_T *)
+	    ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
 
-    /*
-     * The first command issued will be placed in the stopper carrier.
-     */
-    asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+	/*
+	 * The first command issued will be placed in the stopper carrier.
+	 */
+	asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
 
-    /*
-     * Set RISC ICQ physical address start value.
-     */
-    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+	/*
+	 * Set RISC ICQ physical address start value.
+	 */
+	AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
 
-    /*
-     * Set-up the RISC->Host Initiator Response Queue (IRQ).
-     */
-    if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL)
-    {
-        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
-        return ADV_ERROR;
-    }
-    asc_dvc->carr_freelist = (ADV_CARR_T *)
-         ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+	/*
+	 * Set-up the RISC->Host Initiator Response Queue (IRQ).
+	 */
+	if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
+		asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+		return ADV_ERROR;
+	}
+	asc_dvc->carr_freelist = (ADV_CARR_T *)
+	    ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
 
-    /*
-     * The first command completed by the RISC will be placed in
-     * the stopper.
-     *
-     * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
-     * completed the RISC will set the ASC_RQ_STOPPER bit.
-     */
-    asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+	/*
+	 * The first command completed by the RISC will be placed in
+	 * the stopper.
+	 *
+	 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+	 * completed the RISC will set the ASC_RQ_STOPPER bit.
+	 */
+	asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
 
-    /*
-     * Set RISC IRQ physical address start value.
-     */
-    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
-    asc_dvc->carr_pending_cnt = 0;
+	/*
+	 * Set RISC IRQ physical address start value.
+	 */
+	AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+	asc_dvc->carr_pending_cnt = 0;
 
-    AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
-        (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
+	AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+			     (ADV_INTR_ENABLE_HOST_INTR |
+			      ADV_INTR_ENABLE_GLOBAL_INTR));
 
-    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
-    AdvWriteWordRegister(iop_base, IOPW_PC, word);
+	AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+	AdvWriteWordRegister(iop_base, IOPW_PC, word);
 
-    /* finally, finally, gentlemen, start your engine */
-    AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+	/* finally, finally, gentlemen, start your engine */
+	AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
 
-    /*
-     * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
-     * Resets should be performed. The RISC has to be running
-     * to issue a SCSI Bus Reset.
-     */
-    if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
-    {
-        /*
-         * If the BIOS Signature is present in memory, restore the
-         * BIOS Handshake Configuration Table and do not perform
-         * a SCSI Bus Reset.
-         */
-        if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
-        {
-            /*
-             * Restore per TID negotiated values.
-             */
-            AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
-            AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-            AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
-            for (tid = 0; tid <= ADV_MAX_TID; tid++)
-            {
-                AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
-                    max_cmd[tid]);
-            }
-        } else
-        {
-            if (AdvResetSB(asc_dvc) != ADV_TRUE)
-            {
-                warn_code = ASC_WARN_BUSRESET_ERROR;
-            }
-        }
-    }
+	/*
+	 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+	 * Resets should be performed. The RISC has to be running
+	 * to issue a SCSI Bus Reset.
+	 */
+	if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
+		/*
+		 * If the BIOS Signature is present in memory, restore the
+		 * BIOS Handshake Configuration Table and do not perform
+		 * a SCSI Bus Reset.
+		 */
+		if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
+		    0x55AA) {
+			/*
+			 * Restore per TID negotiated values.
+			 */
+			AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+			AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+			AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+					 tagqng_able);
+			for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+				AdvWriteByteLram(iop_base,
+						 ASC_MC_NUMBER_OF_MAX_CMD + tid,
+						 max_cmd[tid]);
+			}
+		} else {
+			if (AdvResetSB(asc_dvc) != ADV_TRUE) {
+				warn_code = ASC_WARN_BUSRESET_ERROR;
+			}
+		}
+	}
 
-    return warn_code;
+	return warn_code;
 }
 
 /*
@@ -15115,619 +14894,610 @@
  *
  * Needed after initialization for error recovery.
  */
-STATIC int
-AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
+static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
 {
-    AdvPortAddr iop_base;
-    ushort      warn_code;
-    ADV_DCNT    sum;
-    int         begin_addr;
-    int         end_addr;
-    ushort      code_sum;
-    int         word;
-    int         j;
-    int         adv_asc38C0800_expanded_size;
-    ADV_CARR_T  *carrp;
-    ADV_DCNT    contig_len;
-    ADV_SDCNT   buf_size;
-    ADV_PADDR   carr_paddr;
-    int         i;
-    ushort      scsi_cfg1;
-    uchar       byte;
-    uchar       tid;
-    ushort      bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */
-    ushort      wdtr_able, sdtr_able, tagqng_able;
-    uchar       max_cmd[ADV_MAX_TID + 1];
+	AdvPortAddr iop_base;
+	ushort warn_code;
+	ADV_DCNT sum;
+	int begin_addr;
+	int end_addr;
+	ushort code_sum;
+	int word;
+	int j;
+	int adv_asc38C0800_expanded_size;
+	ADV_CARR_T *carrp;
+	ADV_DCNT contig_len;
+	ADV_SDCNT buf_size;
+	ADV_PADDR carr_paddr;
+	int i;
+	ushort scsi_cfg1;
+	uchar byte;
+	uchar tid;
+	ushort bios_mem[ASC_MC_BIOSLEN / 2];	/* BIOS RISC Memory 0x40-0x8F. */
+	ushort wdtr_able, sdtr_able, tagqng_able;
+	uchar max_cmd[ADV_MAX_TID + 1];
 
-    /* If there is already an error, don't continue. */
-    if (asc_dvc->err_code != 0)
-    {
-        return ADV_ERROR;
-    }
+	/* If there is already an error, don't continue. */
+	if (asc_dvc->err_code != 0) {
+		return ADV_ERROR;
+	}
 
-    /*
-     * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
-     */
-    if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800)
-    {
-        asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
-        return ADV_ERROR;
-    }
+	/*
+	 * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
+	 */
+	if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) {
+		asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+		return ADV_ERROR;
+	}
 
-    warn_code = 0;
-    iop_base = asc_dvc->iop_base;
+	warn_code = 0;
+	iop_base = asc_dvc->iop_base;
 
-    /*
-     * Save the RISC memory BIOS region before writing the microcode.
-     * The BIOS may already be loaded and using its RISC LRAM region
-     * so its region must be saved and restored.
-     *
-     * Note: This code makes the assumption, which is currently true,
-     * that a chip reset does not clear RISC LRAM.
-     */
-    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
-    {
-        AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
-    }
+	/*
+	 * Save the RISC memory BIOS region before writing the microcode.
+	 * The BIOS may already be loaded and using its RISC LRAM region
+	 * so its region must be saved and restored.
+	 *
+	 * Note: This code makes the assumption, which is currently true,
+	 * that a chip reset does not clear RISC LRAM.
+	 */
+	for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+		AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+				bios_mem[i]);
+	}
 
-    /*
-     * Save current per TID negotiated values.
-     */
-    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
-    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
-    for (tid = 0; tid <= ADV_MAX_TID; tid++)
-    {
-        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
-            max_cmd[tid]);
-    }
+	/*
+	 * Save current per TID negotiated values.
+	 */
+	AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+	AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+	AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+	for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+		AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+				max_cmd[tid]);
+	}
 
-    /*
-     * RAM BIST (RAM Built-In Self Test)
-     *
-     * Address : I/O base + offset 0x38h register (byte).
-     * Function: Bit 7-6(RW) : RAM mode
-     *                          Normal Mode   : 0x00
-     *                          Pre-test Mode : 0x40
-     *                          RAM Test Mode : 0x80
-     *           Bit 5       : unused
-     *           Bit 4(RO)   : Done bit
-     *           Bit 3-0(RO) : Status
-     *                          Host Error    : 0x08
-     *                          Int_RAM Error : 0x04
-     *                          RISC Error    : 0x02
-     *                          SCSI Error    : 0x01
-     *                          No Error      : 0x00
-     *
-     * Note: RAM BIST code should be put right here, before loading the
-     * microcode and after saving the RISC memory BIOS region.
-     */
+	/*
+	 * RAM BIST (RAM Built-In Self Test)
+	 *
+	 * Address : I/O base + offset 0x38h register (byte).
+	 * Function: Bit 7-6(RW) : RAM mode
+	 *                          Normal Mode   : 0x00
+	 *                          Pre-test Mode : 0x40
+	 *                          RAM Test Mode : 0x80
+	 *           Bit 5       : unused
+	 *           Bit 4(RO)   : Done bit
+	 *           Bit 3-0(RO) : Status
+	 *                          Host Error    : 0x08
+	 *                          Int_RAM Error : 0x04
+	 *                          RISC Error    : 0x02
+	 *                          SCSI Error    : 0x01
+	 *                          No Error      : 0x00
+	 *
+	 * Note: RAM BIST code should be put right here, before loading the
+	 * microcode and after saving the RISC memory BIOS region.
+	 */
 
-    /*
-     * LRAM Pre-test
-     *
-     * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
-     * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
-     * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
-     * to NORMAL_MODE, return an error too.
-     */
-    for (i = 0; i < 2; i++)
-    {
-        AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
-        DvcSleepMilliSecond(10);  /* Wait for 10ms before reading back. */
-        byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
-        if ((byte & RAM_TEST_DONE) == 0 || (byte & 0x0F) != PRE_TEST_VALUE)
-        {
-            asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
-            return ADV_ERROR;
-        }
+	/*
+	 * LRAM Pre-test
+	 *
+	 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
+	 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
+	 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
+	 * to NORMAL_MODE, return an error too.
+	 */
+	for (i = 0; i < 2; i++) {
+		AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
+		DvcSleepMilliSecond(10);	/* Wait for 10ms before reading back. */
+		byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+		if ((byte & RAM_TEST_DONE) == 0
+		    || (byte & 0x0F) != PRE_TEST_VALUE) {
+			asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+			return ADV_ERROR;
+		}
 
-        AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
-        DvcSleepMilliSecond(10);  /* Wait for 10ms before reading back. */
-        if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
-            != NORMAL_VALUE)
-        {
-            asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
-            return ADV_ERROR;
-        }
-    }
+		AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+		DvcSleepMilliSecond(10);	/* Wait for 10ms before reading back. */
+		if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
+		    != NORMAL_VALUE) {
+			asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+			return ADV_ERROR;
+		}
+	}
 
-    /*
-     * LRAM Test - It takes about 1.5 ms to run through the test.
-     *
-     * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
-     * If Done bit not set or Status not 0, save register byte, set the
-     * err_code, and return an error.
-     */
-    AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
-    DvcSleepMilliSecond(10);  /* Wait for 10ms before checking status. */
+	/*
+	 * LRAM Test - It takes about 1.5 ms to run through the test.
+	 *
+	 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
+	 * If Done bit not set or Status not 0, save register byte, set the
+	 * err_code, and return an error.
+	 */
+	AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
+	DvcSleepMilliSecond(10);	/* Wait for 10ms before checking status. */
 
-    byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
-    if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0)
-    {
-        /* Get here if Done bit not set or Status not 0. */
-        asc_dvc->bist_err_code = byte;  /* for BIOS display message */
-        asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
-        return ADV_ERROR;
-    }
+	byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+	if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
+		/* Get here if Done bit not set or Status not 0. */
+		asc_dvc->bist_err_code = byte;	/* for BIOS display message */
+		asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
+		return ADV_ERROR;
+	}
 
-    /* We need to reset back to normal mode after LRAM test passes. */
-    AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+	/* We need to reset back to normal mode after LRAM test passes. */
+	AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
 
-    /*
-     * Load the Microcode
-     *
-     * Write the microcode image to RISC memory starting at address 0.
-     *
-     */
-    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+	/*
+	 * Load the Microcode
+	 *
+	 * Write the microcode image to RISC memory starting at address 0.
+	 *
+	 */
+	AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
 
-    /* Assume the following compressed format of the microcode buffer:
-     *
-     *  254 word (508 byte) table indexed by byte code followed
-     *  by the following byte codes:
-     *
-     *    1-Byte Code:
-     *      00: Emit word 0 in table.
-     *      01: Emit word 1 in table.
-     *      .
-     *      FD: Emit word 253 in table.
-     *
-     *    Multi-Byte Code:
-     *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
-     *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
-     */
-    word = 0;
-    for (i = 253 * 2; i < _adv_asc38C0800_size; i++)
-    {
-        if (_adv_asc38C0800_buf[i] == 0xff)
-        {
-            for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++)
-            {
-                AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                    _adv_asc38C0800_buf[i + 3] << 8) |
-                    _adv_asc38C0800_buf[i + 2]));
-                word++;
-            }
-            i += 3;
-        } else if (_adv_asc38C0800_buf[i] == 0xfe)
-        {
-            AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                _adv_asc38C0800_buf[i + 2] << 8) |
-                _adv_asc38C0800_buf[i + 1]));
-            i += 2;
-            word++;
-        } else
-        {
-            AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) |
-                _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
-            word++;
-        }
-    }
+	/* Assume the following compressed format of the microcode buffer:
+	 *
+	 *  254 word (508 byte) table indexed by byte code followed
+	 *  by the following byte codes:
+	 *
+	 *    1-Byte Code:
+	 *      00: Emit word 0 in table.
+	 *      01: Emit word 1 in table.
+	 *      .
+	 *      FD: Emit word 253 in table.
+	 *
+	 *    Multi-Byte Code:
+	 *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+	 *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+	 */
+	word = 0;
+	for (i = 253 * 2; i < _adv_asc38C0800_size; i++) {
+		if (_adv_asc38C0800_buf[i] == 0xff) {
+			for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++) {
+				AdvWriteWordAutoIncLram(iop_base, (((ushort)
+								    _adv_asc38C0800_buf
+								    [i +
+								     3] << 8) |
+								   _adv_asc38C0800_buf
+								   [i + 2]));
+				word++;
+			}
+			i += 3;
+		} else if (_adv_asc38C0800_buf[i] == 0xfe) {
+			AdvWriteWordAutoIncLram(iop_base, (((ushort)
+							    _adv_asc38C0800_buf
+							    [i +
+							     2] << 8) |
+							   _adv_asc38C0800_buf[i
+									       +
+									       1]));
+			i += 2;
+			word++;
+		} else {
+			AdvWriteWordAutoIncLram(iop_base, (((ushort)
+							    _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) | _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
+			word++;
+		}
+	}
 
-    /*
-     * Set 'word' for later use to clear the rest of memory and save
-     * the expanded mcode size.
-     */
-    word *= 2;
-    adv_asc38C0800_expanded_size = word;
+	/*
+	 * Set 'word' for later use to clear the rest of memory and save
+	 * the expanded mcode size.
+	 */
+	word *= 2;
+	adv_asc38C0800_expanded_size = word;
 
-    /*
-     * Clear the rest of ASC-38C0800 Internal RAM (16KB).
-     */
-    for (; word < ADV_38C0800_MEMSIZE; word += 2)
-    {
-        AdvWriteWordAutoIncLram(iop_base, 0);
-    }
+	/*
+	 * Clear the rest of ASC-38C0800 Internal RAM (16KB).
+	 */
+	for (; word < ADV_38C0800_MEMSIZE; word += 2) {
+		AdvWriteWordAutoIncLram(iop_base, 0);
+	}
 
-    /*
-     * Verify the microcode checksum.
-     */
-    sum = 0;
-    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+	/*
+	 * Verify the microcode checksum.
+	 */
+	sum = 0;
+	AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
 
-    for (word = 0; word < adv_asc38C0800_expanded_size; word += 2)
-    {
-        sum += AdvReadWordAutoIncLram(iop_base);
-    }
-    ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
+	for (word = 0; word < adv_asc38C0800_expanded_size; word += 2) {
+		sum += AdvReadWordAutoIncLram(iop_base);
+	}
+	ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
 
-    ASC_DBG2(1,
-        "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
-        (ulong) sum, (ulong) _adv_asc38C0800_chksum);
+	ASC_DBG2(1,
+		 "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
+		 (ulong)sum, (ulong)_adv_asc38C0800_chksum);
 
-    if (sum != _adv_asc38C0800_chksum)
-    {
-        asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
-        return ADV_ERROR;
-    }
+	if (sum != _adv_asc38C0800_chksum) {
+		asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+		return ADV_ERROR;
+	}
 
-    /*
-     * Restore the RISC memory BIOS region.
-     */
-    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
-    {
-        AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
-    }
+	/*
+	 * Restore the RISC memory BIOS region.
+	 */
+	for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+		AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+				 bios_mem[i]);
+	}
 
-    /*
-     * Calculate and write the microcode code checksum to the microcode
-     * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
-     */
-    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
-    AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
-    code_sum = 0;
-    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
-    for (word = begin_addr; word < end_addr; word += 2)
-    {
-        code_sum += AdvReadWordAutoIncLram(iop_base);
-    }
-    AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+	/*
+	 * Calculate and write the microcode code checksum to the microcode
+	 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+	 */
+	AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+	AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+	code_sum = 0;
+	AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+	for (word = begin_addr; word < end_addr; word += 2) {
+		code_sum += AdvReadWordAutoIncLram(iop_base);
+	}
+	AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
 
-    /*
-     * Read microcode version and date.
-     */
-    AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
-    AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
+	/*
+	 * Read microcode version and date.
+	 */
+	AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
+			asc_dvc->cfg->mcode_date);
+	AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
+			asc_dvc->cfg->mcode_version);
 
-    /*
-     * Set the chip type to indicate the ASC38C0800.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
+	/*
+	 * Set the chip type to indicate the ASC38C0800.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
 
-    /*
-     * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
-     * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
-     * cable detection and then we are able to read C_DET[3:0].
-     *
-     * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
-     * Microcode Default Value' section below.
-     */
-    scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
-    AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, scsi_cfg1 | DIS_TERM_DRV);
+	/*
+	 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
+	 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
+	 * cable detection and then we are able to read C_DET[3:0].
+	 *
+	 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
+	 * Microcode Default Value' section below.
+	 */
+	scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+	AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
+			     scsi_cfg1 | DIS_TERM_DRV);
 
-    /*
-     * If the PCI Configuration Command Register "Parity Error Response
-     * Control" Bit was clear (0), then set the microcode variable
-     * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
-     * to ignore DMA parity errors.
-     */
-    if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
-    {
-        AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
-        word |= CONTROL_FLAG_IGNORE_PERR;
-        AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
-    }
+	/*
+	 * If the PCI Configuration Command Register "Parity Error Response
+	 * Control" Bit was clear (0), then set the microcode variable
+	 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+	 * to ignore DMA parity errors.
+	 */
+	if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
+		AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+		word |= CONTROL_FLAG_IGNORE_PERR;
+		AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+	}
 
-    /*
-     * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
-     * bits for the default FIFO threshold.
-     *
-     * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
-     *
-     * For DMA Errata #4 set the BC_THRESH_ENB bit.
-     */
-    AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
-        BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
+	/*
+	 * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
+	 * bits for the default FIFO threshold.
+	 *
+	 * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
+	 *
+	 * For DMA Errata #4 set the BC_THRESH_ENB bit.
+	 */
+	AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+			     BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH |
+			     READ_CMD_MRM);
 
-    /*
-     * Microcode operating variables for WDTR, SDTR, and command tag
-     * queuing will be set in AdvInquiryHandling() based on what a
-     * device reports it is capable of in Inquiry byte 7.
-     *
-     * If SCSI Bus Resets have been disabled, then directly set
-     * SDTR and WDTR from the EEPROM configuration. This will allow
-     * the BIOS and warm boot to work without a SCSI bus hang on
-     * the Inquiry caused by host and target mismatched DTR values.
-     * Without the SCSI Bus Reset, before an Inquiry a device can't
-     * be assumed to be in Asynchronous, Narrow mode.
-     */
-    if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0)
-    {
-        AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able);
-        AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able);
-    }
+	/*
+	 * Microcode operating variables for WDTR, SDTR, and command tag
+	 * queuing will be set in AdvInquiryHandling() based on what a
+	 * device reports it is capable of in Inquiry byte 7.
+	 *
+	 * If SCSI Bus Resets have been disabled, then directly set
+	 * SDTR and WDTR from the EEPROM configuration. This will allow
+	 * the BIOS and warm boot to work without a SCSI bus hang on
+	 * the Inquiry caused by host and target mismatched DTR values.
+	 * Without the SCSI Bus Reset, before an Inquiry a device can't
+	 * be assumed to be in Asynchronous, Narrow mode.
+	 */
+	if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
+		AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
+				 asc_dvc->wdtr_able);
+		AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
+				 asc_dvc->sdtr_able);
+	}
 
-    /*
-     * Set microcode operating variables for DISC and SDTR_SPEED1,
-     * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
-     * configuration values.
-     *
-     * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
-     * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
-     * without determining here whether the device supports SDTR.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
-    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
-    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
-    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
-    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
+	/*
+	 * Set microcode operating variables for DISC and SDTR_SPEED1,
+	 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
+	 * configuration values.
+	 *
+	 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+	 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+	 * without determining here whether the device supports SDTR.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
+			 asc_dvc->cfg->disc_enable);
+	AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
+	AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
+	AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
+	AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
 
-    /*
-     * Set SCSI_CFG0 Microcode Default Value.
-     *
-     * The microcode will set the SCSI_CFG0 register using this value
-     * after it is started below.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
-        PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
-        asc_dvc->chip_scsi_id);
+	/*
+	 * Set SCSI_CFG0 Microcode Default Value.
+	 *
+	 * The microcode will set the SCSI_CFG0 register using this value
+	 * after it is started below.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+			 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+			 asc_dvc->chip_scsi_id);
 
-    /*
-     * Determine SCSI_CFG1 Microcode Default Value.
-     *
-     * The microcode will set the SCSI_CFG1 register using this value
-     * after it is started below.
-     */
+	/*
+	 * Determine SCSI_CFG1 Microcode Default Value.
+	 *
+	 * The microcode will set the SCSI_CFG1 register using this value
+	 * after it is started below.
+	 */
 
-    /* Read current SCSI_CFG1 Register value. */
-    scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+	/* Read current SCSI_CFG1 Register value. */
+	scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
 
-    /*
-     * If the internal narrow cable is reversed all of the SCSI_CTRL
-     * register signals will be set. Check for and return an error if
-     * this condition is found.
-     */
-    if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07)
-    {
-        asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
-        return ADV_ERROR;
-    }
+	/*
+	 * If the internal narrow cable is reversed all of the SCSI_CTRL
+	 * register signals will be set. Check for and return an error if
+	 * this condition is found.
+	 */
+	if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
+		asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+		return ADV_ERROR;
+	}
 
-    /*
-     * All kind of combinations of devices attached to one of four connectors
-     * are acceptable except HVD device attached. For example, LVD device can
-     * be attached to SE connector while SE device attached to LVD connector.
-     * If LVD device attached to SE connector, it only runs up to Ultra speed.
-     *
-     * If an HVD device is attached to one of LVD connectors, return an error.
-     * However, there is no way to detect HVD device attached to SE connectors.
-     */
-    if (scsi_cfg1 & HVD)
-    {
-        asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
-        return ADV_ERROR;
-    }
+	/*
+	 * All kind of combinations of devices attached to one of four connectors
+	 * are acceptable except HVD device attached. For example, LVD device can
+	 * be attached to SE connector while SE device attached to LVD connector.
+	 * If LVD device attached to SE connector, it only runs up to Ultra speed.
+	 *
+	 * If an HVD device is attached to one of LVD connectors, return an error.
+	 * However, there is no way to detect HVD device attached to SE connectors.
+	 */
+	if (scsi_cfg1 & HVD) {
+		asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
+		return ADV_ERROR;
+	}
 
-    /*
-     * If either SE or LVD automatic termination control is enabled, then
-     * set the termination value based on a table listed in a_condor.h.
-     *
-     * If manual termination was specified with an EEPROM setting then
-     * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
-     * be 'ored' into SCSI_CFG1.
-     */
-    if ((asc_dvc->cfg->termination & TERM_SE) == 0)
-    {
-        /* SE automatic termination control is enabled. */
-        switch(scsi_cfg1 & C_DET_SE)
-        {
-            /* TERM_SE_HI: on, TERM_SE_LO: on */
-            case 0x1: case 0x2: case 0x3:
-                asc_dvc->cfg->termination |= TERM_SE;
-                break;
+	/*
+	 * If either SE or LVD automatic termination control is enabled, then
+	 * set the termination value based on a table listed in a_condor.h.
+	 *
+	 * If manual termination was specified with an EEPROM setting then
+	 * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
+	 * be 'ored' into SCSI_CFG1.
+	 */
+	if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
+		/* SE automatic termination control is enabled. */
+		switch (scsi_cfg1 & C_DET_SE) {
+			/* TERM_SE_HI: on, TERM_SE_LO: on */
+		case 0x1:
+		case 0x2:
+		case 0x3:
+			asc_dvc->cfg->termination |= TERM_SE;
+			break;
 
-            /* TERM_SE_HI: on, TERM_SE_LO: off */
-            case 0x0:
-                asc_dvc->cfg->termination |= TERM_SE_HI;
-                break;
-        }
-    }
+			/* TERM_SE_HI: on, TERM_SE_LO: off */
+		case 0x0:
+			asc_dvc->cfg->termination |= TERM_SE_HI;
+			break;
+		}
+	}
 
-    if ((asc_dvc->cfg->termination & TERM_LVD) == 0)
-    {
-        /* LVD automatic termination control is enabled. */
-        switch(scsi_cfg1 & C_DET_LVD)
-        {
-            /* TERM_LVD_HI: on, TERM_LVD_LO: on */
-            case 0x4: case 0x8: case 0xC:
-                asc_dvc->cfg->termination |= TERM_LVD;
-                break;
+	if ((asc_dvc->cfg->termination & TERM_LVD) == 0) {
+		/* LVD automatic termination control is enabled. */
+		switch (scsi_cfg1 & C_DET_LVD) {
+			/* TERM_LVD_HI: on, TERM_LVD_LO: on */
+		case 0x4:
+		case 0x8:
+		case 0xC:
+			asc_dvc->cfg->termination |= TERM_LVD;
+			break;
 
-            /* TERM_LVD_HI: off, TERM_LVD_LO: off */
-            case 0x0:
-                break;
-        }
-    }
+			/* TERM_LVD_HI: off, TERM_LVD_LO: off */
+		case 0x0:
+			break;
+		}
+	}
 
-    /*
-     * Clear any set TERM_SE and TERM_LVD bits.
-     */
-    scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
+	/*
+	 * Clear any set TERM_SE and TERM_LVD bits.
+	 */
+	scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
 
-    /*
-     * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
-     */
-    scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
+	/*
+	 * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
+	 */
+	scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
 
-    /*
-     * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
-     * and set possibly modified termination control bits in the Microcode
-     * SCSI_CFG1 Register Value.
-     */
-    scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
+	/*
+	 * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
+	 * and set possibly modified termination control bits in the Microcode
+	 * SCSI_CFG1 Register Value.
+	 */
+	scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
 
-    /*
-     * Set SCSI_CFG1 Microcode Default Value
-     *
-     * Set possibly modified termination control and reset DIS_TERM_DRV
-     * bits in the Microcode SCSI_CFG1 Register Value.
-     *
-     * The microcode will set the SCSI_CFG1 register using this value
-     * after it is started below.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
+	/*
+	 * Set SCSI_CFG1 Microcode Default Value
+	 *
+	 * Set possibly modified termination control and reset DIS_TERM_DRV
+	 * bits in the Microcode SCSI_CFG1 Register Value.
+	 *
+	 * The microcode will set the SCSI_CFG1 register using this value
+	 * after it is started below.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
 
-    /*
-     * Set MEM_CFG Microcode Default Value
-     *
-     * The microcode will set the MEM_CFG register using this value
-     * after it is started below.
-     *
-     * MEM_CFG may be accessed as a word or byte, but only bits 0-7
-     * are defined.
-     *
-     * ASC-38C0800 has 16KB internal memory.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
-        BIOS_EN | RAM_SZ_16KB);
+	/*
+	 * Set MEM_CFG Microcode Default Value
+	 *
+	 * The microcode will set the MEM_CFG register using this value
+	 * after it is started below.
+	 *
+	 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+	 * are defined.
+	 *
+	 * ASC-38C0800 has 16KB internal memory.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+			 BIOS_EN | RAM_SZ_16KB);
 
-    /*
-     * Set SEL_MASK Microcode Default Value
-     *
-     * The microcode will set the SEL_MASK register using this value
-     * after it is started below.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
-        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+	/*
+	 * Set SEL_MASK Microcode Default Value
+	 *
+	 * The microcode will set the SEL_MASK register using this value
+	 * after it is started below.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+			 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
 
-    /*
-     * Build the carrier freelist.
-     *
-     * Driver must have already allocated memory and set 'carrier_buf'.
-     */
-    ASC_ASSERT(asc_dvc->carrier_buf != NULL);
+	/*
+	 * Build the carrier freelist.
+	 *
+	 * Driver must have already allocated memory and set 'carrier_buf'.
+	 */
+	ASC_ASSERT(asc_dvc->carrier_buf != NULL);
 
-    carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
-    asc_dvc->carr_freelist = NULL;
-    if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf)
-    {
-        buf_size = ADV_CARRIER_BUFSIZE;
-    } else
-    {
-        buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
-    }
+	carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+	asc_dvc->carr_freelist = NULL;
+	if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
+		buf_size = ADV_CARRIER_BUFSIZE;
+	} else {
+		buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+	}
 
-    do {
-        /*
-         * Get physical address for the carrier 'carrp'.
-         */
-        contig_len = sizeof(ADV_CARR_T);
-        carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
-            (ADV_SDCNT *) &contig_len, ADV_IS_CARRIER_FLAG));
+	do {
+		/*
+		 * Get physical address for the carrier 'carrp'.
+		 */
+		contig_len = sizeof(ADV_CARR_T);
+		carr_paddr =
+		    cpu_to_le32(DvcGetPhyAddr
+				(asc_dvc, NULL, (uchar *)carrp,
+				 (ADV_SDCNT *)&contig_len,
+				 ADV_IS_CARRIER_FLAG));
 
-        buf_size -= sizeof(ADV_CARR_T);
+		buf_size -= sizeof(ADV_CARR_T);
 
-        /*
-         * If the current carrier is not physically contiguous, then
-         * maybe there was a page crossing. Try the next carrier aligned
-         * start address.
-         */
-        if (contig_len < sizeof(ADV_CARR_T))
-        {
-            carrp++;
-            continue;
-        }
+		/*
+		 * If the current carrier is not physically contiguous, then
+		 * maybe there was a page crossing. Try the next carrier aligned
+		 * start address.
+		 */
+		if (contig_len < sizeof(ADV_CARR_T)) {
+			carrp++;
+			continue;
+		}
 
-        carrp->carr_pa = carr_paddr;
-        carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
+		carrp->carr_pa = carr_paddr;
+		carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
 
-        /*
-         * Insert the carrier at the beginning of the freelist.
-         */
-        carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
-        asc_dvc->carr_freelist = carrp;
+		/*
+		 * Insert the carrier at the beginning of the freelist.
+		 */
+		carrp->next_vpa =
+		    cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+		asc_dvc->carr_freelist = carrp;
 
-        carrp++;
-    }
-    while (buf_size > 0);
+		carrp++;
+	}
+	while (buf_size > 0);
 
-    /*
-     * Set-up the Host->RISC Initiator Command Queue (ICQ).
-     */
+	/*
+	 * Set-up the Host->RISC Initiator Command Queue (ICQ).
+	 */
 
-    if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL)
-    {
-        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
-        return ADV_ERROR;
-    }
-    asc_dvc->carr_freelist = (ADV_CARR_T *)
-        ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+	if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
+		asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+		return ADV_ERROR;
+	}
+	asc_dvc->carr_freelist = (ADV_CARR_T *)
+	    ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
 
-    /*
-     * The first command issued will be placed in the stopper carrier.
-     */
-    asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+	/*
+	 * The first command issued will be placed in the stopper carrier.
+	 */
+	asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
 
-    /*
-     * Set RISC ICQ physical address start value.
-     * carr_pa is LE, must be native before write
-     */
-    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+	/*
+	 * Set RISC ICQ physical address start value.
+	 * carr_pa is LE, must be native before write
+	 */
+	AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
 
-    /*
-     * Set-up the RISC->Host Initiator Response Queue (IRQ).
-     */
-    if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL)
-    {
-        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
-        return ADV_ERROR;
-    }
-    asc_dvc->carr_freelist = (ADV_CARR_T *)
-        ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+	/*
+	 * Set-up the RISC->Host Initiator Response Queue (IRQ).
+	 */
+	if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
+		asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+		return ADV_ERROR;
+	}
+	asc_dvc->carr_freelist = (ADV_CARR_T *)
+	    ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
 
-    /*
-     * The first command completed by the RISC will be placed in
-     * the stopper.
-     *
-     * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
-     * completed the RISC will set the ASC_RQ_STOPPER bit.
-     */
-    asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+	/*
+	 * The first command completed by the RISC will be placed in
+	 * the stopper.
+	 *
+	 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+	 * completed the RISC will set the ASC_RQ_STOPPER bit.
+	 */
+	asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
 
-    /*
-     * Set RISC IRQ physical address start value.
-     *
-     * carr_pa is LE, must be native before write *
-     */
-    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
-    asc_dvc->carr_pending_cnt = 0;
+	/*
+	 * Set RISC IRQ physical address start value.
+	 *
+	 * carr_pa is LE, must be native before write *
+	 */
+	AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+	asc_dvc->carr_pending_cnt = 0;
 
-    AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
-        (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
+	AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+			     (ADV_INTR_ENABLE_HOST_INTR |
+			      ADV_INTR_ENABLE_GLOBAL_INTR));
 
-    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
-    AdvWriteWordRegister(iop_base, IOPW_PC, word);
+	AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+	AdvWriteWordRegister(iop_base, IOPW_PC, word);
 
-    /* finally, finally, gentlemen, start your engine */
-    AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+	/* finally, finally, gentlemen, start your engine */
+	AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
 
-    /*
-     * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
-     * Resets should be performed. The RISC has to be running
-     * to issue a SCSI Bus Reset.
-     */
-    if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
-    {
-        /*
-         * If the BIOS Signature is present in memory, restore the
-         * BIOS Handshake Configuration Table and do not perform
-         * a SCSI Bus Reset.
-         */
-        if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
-        {
-            /*
-             * Restore per TID negotiated values.
-             */
-            AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
-            AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-            AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
-            for (tid = 0; tid <= ADV_MAX_TID; tid++)
-            {
-                AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
-                    max_cmd[tid]);
-            }
-        } else
-        {
-            if (AdvResetSB(asc_dvc) != ADV_TRUE)
-            {
-                warn_code = ASC_WARN_BUSRESET_ERROR;
-            }
-        }
-    }
+	/*
+	 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+	 * Resets should be performed. The RISC has to be running
+	 * to issue a SCSI Bus Reset.
+	 */
+	if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
+		/*
+		 * If the BIOS Signature is present in memory, restore the
+		 * BIOS Handshake Configuration Table and do not perform
+		 * a SCSI Bus Reset.
+		 */
+		if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
+		    0x55AA) {
+			/*
+			 * Restore per TID negotiated values.
+			 */
+			AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+			AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+			AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+					 tagqng_able);
+			for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+				AdvWriteByteLram(iop_base,
+						 ASC_MC_NUMBER_OF_MAX_CMD + tid,
+						 max_cmd[tid]);
+			}
+		} else {
+			if (AdvResetSB(asc_dvc) != ADV_TRUE) {
+				warn_code = ASC_WARN_BUSRESET_ERROR;
+			}
+		}
+	}
 
-    return warn_code;
+	return warn_code;
 }
 
 /*
@@ -15740,630 +15510,617 @@
  *
  * Needed after initialization for error recovery.
  */
-STATIC int
-AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
+static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
 {
-    AdvPortAddr iop_base;
-    ushort      warn_code;
-    ADV_DCNT    sum;
-    int         begin_addr;
-    int         end_addr;
-    ushort      code_sum;
-    long        word;
-    int         j;
-    int         adv_asc38C1600_expanded_size;
-    ADV_CARR_T  *carrp;
-    ADV_DCNT    contig_len;
-    ADV_SDCNT   buf_size;
-    ADV_PADDR   carr_paddr;
-    int         i;
-    ushort      scsi_cfg1;
-    uchar       byte;
-    uchar       tid;
-    ushort      bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */
-    ushort      wdtr_able, sdtr_able, ppr_able, tagqng_able;
-    uchar       max_cmd[ASC_MAX_TID + 1];
+	AdvPortAddr iop_base;
+	ushort warn_code;
+	ADV_DCNT sum;
+	int begin_addr;
+	int end_addr;
+	ushort code_sum;
+	long word;
+	int j;
+	int adv_asc38C1600_expanded_size;
+	ADV_CARR_T *carrp;
+	ADV_DCNT contig_len;
+	ADV_SDCNT buf_size;
+	ADV_PADDR carr_paddr;
+	int i;
+	ushort scsi_cfg1;
+	uchar byte;
+	uchar tid;
+	ushort bios_mem[ASC_MC_BIOSLEN / 2];	/* BIOS RISC Memory 0x40-0x8F. */
+	ushort wdtr_able, sdtr_able, ppr_able, tagqng_able;
+	uchar max_cmd[ASC_MAX_TID + 1];
 
-    /* If there is already an error, don't continue. */
-    if (asc_dvc->err_code != 0)
-    {
-        return ADV_ERROR;
-    }
+	/* If there is already an error, don't continue. */
+	if (asc_dvc->err_code != 0) {
+		return ADV_ERROR;
+	}
 
-    /*
-     * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
-     */
-    if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600)
-    {
-        asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
-        return ADV_ERROR;
-    }
+	/*
+	 * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
+	 */
+	if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) {
+		asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+		return ADV_ERROR;
+	}
 
-    warn_code = 0;
-    iop_base = asc_dvc->iop_base;
+	warn_code = 0;
+	iop_base = asc_dvc->iop_base;
 
-    /*
-     * Save the RISC memory BIOS region before writing the microcode.
-     * The BIOS may already be loaded and using its RISC LRAM region
-     * so its region must be saved and restored.
-     *
-     * Note: This code makes the assumption, which is currently true,
-     * that a chip reset does not clear RISC LRAM.
-     */
-    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
-    {
-        AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
-    }
+	/*
+	 * Save the RISC memory BIOS region before writing the microcode.
+	 * The BIOS may already be loaded and using its RISC LRAM region
+	 * so its region must be saved and restored.
+	 *
+	 * Note: This code makes the assumption, which is currently true,
+	 * that a chip reset does not clear RISC LRAM.
+	 */
+	for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+		AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+				bios_mem[i]);
+	}
 
-    /*
-     * Save current per TID negotiated values.
-     */
-    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
-    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-    AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
-    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
-    for (tid = 0; tid <= ASC_MAX_TID; tid++)
-    {
-        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
-            max_cmd[tid]);
-    }
+	/*
+	 * Save current per TID negotiated values.
+	 */
+	AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+	AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+	AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+	AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+	for (tid = 0; tid <= ASC_MAX_TID; tid++) {
+		AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+				max_cmd[tid]);
+	}
 
-    /*
-     * RAM BIST (Built-In Self Test)
-     *
-     * Address : I/O base + offset 0x38h register (byte).
-     * Function: Bit 7-6(RW) : RAM mode
-     *                          Normal Mode   : 0x00
-     *                          Pre-test Mode : 0x40
-     *                          RAM Test Mode : 0x80
-     *           Bit 5       : unused
-     *           Bit 4(RO)   : Done bit
-     *           Bit 3-0(RO) : Status
-     *                          Host Error    : 0x08
-     *                          Int_RAM Error : 0x04
-     *                          RISC Error    : 0x02
-     *                          SCSI Error    : 0x01
-     *                          No Error      : 0x00
-     *
-     * Note: RAM BIST code should be put right here, before loading the
-     * microcode and after saving the RISC memory BIOS region.
-     */
+	/*
+	 * RAM BIST (Built-In Self Test)
+	 *
+	 * Address : I/O base + offset 0x38h register (byte).
+	 * Function: Bit 7-6(RW) : RAM mode
+	 *                          Normal Mode   : 0x00
+	 *                          Pre-test Mode : 0x40
+	 *                          RAM Test Mode : 0x80
+	 *           Bit 5       : unused
+	 *           Bit 4(RO)   : Done bit
+	 *           Bit 3-0(RO) : Status
+	 *                          Host Error    : 0x08
+	 *                          Int_RAM Error : 0x04
+	 *                          RISC Error    : 0x02
+	 *                          SCSI Error    : 0x01
+	 *                          No Error      : 0x00
+	 *
+	 * Note: RAM BIST code should be put right here, before loading the
+	 * microcode and after saving the RISC memory BIOS region.
+	 */
 
-    /*
-     * LRAM Pre-test
-     *
-     * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
-     * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
-     * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
-     * to NORMAL_MODE, return an error too.
-     */
-    for (i = 0; i < 2; i++)
-    {
-        AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
-        DvcSleepMilliSecond(10);  /* Wait for 10ms before reading back. */
-        byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
-        if ((byte & RAM_TEST_DONE) == 0 || (byte & 0x0F) != PRE_TEST_VALUE)
-        {
-            asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
-            return ADV_ERROR;
-        }
+	/*
+	 * LRAM Pre-test
+	 *
+	 * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
+	 * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
+	 * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
+	 * to NORMAL_MODE, return an error too.
+	 */
+	for (i = 0; i < 2; i++) {
+		AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
+		DvcSleepMilliSecond(10);	/* Wait for 10ms before reading back. */
+		byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+		if ((byte & RAM_TEST_DONE) == 0
+		    || (byte & 0x0F) != PRE_TEST_VALUE) {
+			asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+			return ADV_ERROR;
+		}
 
-        AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
-        DvcSleepMilliSecond(10);  /* Wait for 10ms before reading back. */
-        if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
-            != NORMAL_VALUE)
-        {
-            asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
-            return ADV_ERROR;
-        }
-    }
+		AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+		DvcSleepMilliSecond(10);	/* Wait for 10ms before reading back. */
+		if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
+		    != NORMAL_VALUE) {
+			asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+			return ADV_ERROR;
+		}
+	}
 
-    /*
-     * LRAM Test - It takes about 1.5 ms to run through the test.
-     *
-     * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
-     * If Done bit not set or Status not 0, save register byte, set the
-     * err_code, and return an error.
-     */
-    AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
-    DvcSleepMilliSecond(10);  /* Wait for 10ms before checking status. */
+	/*
+	 * LRAM Test - It takes about 1.5 ms to run through the test.
+	 *
+	 * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
+	 * If Done bit not set or Status not 0, save register byte, set the
+	 * err_code, and return an error.
+	 */
+	AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
+	DvcSleepMilliSecond(10);	/* Wait for 10ms before checking status. */
 
-    byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
-    if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0)
-    {
-        /* Get here if Done bit not set or Status not 0. */
-        asc_dvc->bist_err_code = byte;  /* for BIOS display message */
-        asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
-        return ADV_ERROR;
-    }
+	byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+	if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) {
+		/* Get here if Done bit not set or Status not 0. */
+		asc_dvc->bist_err_code = byte;	/* for BIOS display message */
+		asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
+		return ADV_ERROR;
+	}
 
-    /* We need to reset back to normal mode after LRAM test passes. */
-    AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+	/* We need to reset back to normal mode after LRAM test passes. */
+	AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
 
-    /*
-     * Load the Microcode
-     *
-     * Write the microcode image to RISC memory starting at address 0.
-     *
-     */
-    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+	/*
+	 * Load the Microcode
+	 *
+	 * Write the microcode image to RISC memory starting at address 0.
+	 *
+	 */
+	AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
 
-    /*
-     * Assume the following compressed format of the microcode buffer:
-     *
-     *  254 word (508 byte) table indexed by byte code followed
-     *  by the following byte codes:
-     *
-     *    1-Byte Code:
-     *      00: Emit word 0 in table.
-     *      01: Emit word 1 in table.
-     *      .
-     *      FD: Emit word 253 in table.
-     *
-     *    Multi-Byte Code:
-     *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
-     *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
-     */
-    word = 0;
-    for (i = 253 * 2; i < _adv_asc38C1600_size; i++)
-    {
-        if (_adv_asc38C1600_buf[i] == 0xff)
-        {
-            for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++)
-            {
-                AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                     _adv_asc38C1600_buf[i + 3] << 8) |
-                     _adv_asc38C1600_buf[i + 2]));
-                word++;
-            }
-           i += 3;
-        } else if (_adv_asc38C1600_buf[i] == 0xfe)
-        {
-                AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                     _adv_asc38C1600_buf[i + 2] << 8) |
-                     _adv_asc38C1600_buf[i + 1]));
-            i += 2;
-            word++;
-        } else
-        {
-            AdvWriteWordAutoIncLram(iop_base, (((ushort)
-                 _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) |
-                 _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
-            word++;
-        }
-    }
+	/*
+	 * Assume the following compressed format of the microcode buffer:
+	 *
+	 *  254 word (508 byte) table indexed by byte code followed
+	 *  by the following byte codes:
+	 *
+	 *    1-Byte Code:
+	 *      00: Emit word 0 in table.
+	 *      01: Emit word 1 in table.
+	 *      .
+	 *      FD: Emit word 253 in table.
+	 *
+	 *    Multi-Byte Code:
+	 *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+	 *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+	 */
+	word = 0;
+	for (i = 253 * 2; i < _adv_asc38C1600_size; i++) {
+		if (_adv_asc38C1600_buf[i] == 0xff) {
+			for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++) {
+				AdvWriteWordAutoIncLram(iop_base, (((ushort)
+								    _adv_asc38C1600_buf
+								    [i +
+								     3] << 8) |
+								   _adv_asc38C1600_buf
+								   [i + 2]));
+				word++;
+			}
+			i += 3;
+		} else if (_adv_asc38C1600_buf[i] == 0xfe) {
+			AdvWriteWordAutoIncLram(iop_base, (((ushort)
+							    _adv_asc38C1600_buf
+							    [i +
+							     2] << 8) |
+							   _adv_asc38C1600_buf[i
+									       +
+									       1]));
+			i += 2;
+			word++;
+		} else {
+			AdvWriteWordAutoIncLram(iop_base, (((ushort)
+							    _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) | _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
+			word++;
+		}
+	}
 
-    /*
-     * Set 'word' for later use to clear the rest of memory and save
-     * the expanded mcode size.
-     */
-    word *= 2;
-    adv_asc38C1600_expanded_size = word;
+	/*
+	 * Set 'word' for later use to clear the rest of memory and save
+	 * the expanded mcode size.
+	 */
+	word *= 2;
+	adv_asc38C1600_expanded_size = word;
 
-    /*
-     * Clear the rest of ASC-38C1600 Internal RAM (32KB).
-     */
-    for (; word < ADV_38C1600_MEMSIZE; word += 2)
-    {
-        AdvWriteWordAutoIncLram(iop_base, 0);
-    }
+	/*
+	 * Clear the rest of ASC-38C1600 Internal RAM (32KB).
+	 */
+	for (; word < ADV_38C1600_MEMSIZE; word += 2) {
+		AdvWriteWordAutoIncLram(iop_base, 0);
+	}
 
-    /*
-     * Verify the microcode checksum.
-     */
-    sum = 0;
-    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+	/*
+	 * Verify the microcode checksum.
+	 */
+	sum = 0;
+	AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
 
-    for (word = 0; word < adv_asc38C1600_expanded_size; word += 2)
-    {
-        sum += AdvReadWordAutoIncLram(iop_base);
-    }
+	for (word = 0; word < adv_asc38C1600_expanded_size; word += 2) {
+		sum += AdvReadWordAutoIncLram(iop_base);
+	}
 
-    if (sum != _adv_asc38C1600_chksum)
-    {
-        asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
-        return ADV_ERROR;
-    }
+	if (sum != _adv_asc38C1600_chksum) {
+		asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+		return ADV_ERROR;
+	}
 
-    /*
-     * Restore the RISC memory BIOS region.
-     */
-    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
-    {
-        AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
-    }
+	/*
+	 * Restore the RISC memory BIOS region.
+	 */
+	for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) {
+		AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i),
+				 bios_mem[i]);
+	}
 
-    /*
-     * Calculate and write the microcode code checksum to the microcode
-     * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
-     */
-    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
-    AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
-    code_sum = 0;
-    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
-    for (word = begin_addr; word < end_addr; word += 2)
-    {
-        code_sum += AdvReadWordAutoIncLram(iop_base);
-    }
-    AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+	/*
+	 * Calculate and write the microcode code checksum to the microcode
+	 * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+	 */
+	AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+	AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+	code_sum = 0;
+	AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+	for (word = begin_addr; word < end_addr; word += 2) {
+		code_sum += AdvReadWordAutoIncLram(iop_base);
+	}
+	AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
 
-    /*
-     * Read microcode version and date.
-     */
-    AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
-    AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
+	/*
+	 * Read microcode version and date.
+	 */
+	AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE,
+			asc_dvc->cfg->mcode_date);
+	AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM,
+			asc_dvc->cfg->mcode_version);
 
-    /*
-     * Set the chip type to indicate the ASC38C1600.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
+	/*
+	 * Set the chip type to indicate the ASC38C1600.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
 
-    /*
-     * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
-     * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
-     * cable detection and then we are able to read C_DET[3:0].
-     *
-     * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
-     * Microcode Default Value' section below.
-     */
-    scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
-    AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, scsi_cfg1 | DIS_TERM_DRV);
+	/*
+	 * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
+	 * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
+	 * cable detection and then we are able to read C_DET[3:0].
+	 *
+	 * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
+	 * Microcode Default Value' section below.
+	 */
+	scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+	AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1,
+			     scsi_cfg1 | DIS_TERM_DRV);
 
-    /*
-     * If the PCI Configuration Command Register "Parity Error Response
-     * Control" Bit was clear (0), then set the microcode variable
-     * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
-     * to ignore DMA parity errors.
-     */
-    if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
-    {
-        AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
-        word |= CONTROL_FLAG_IGNORE_PERR;
-        AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
-    }
+	/*
+	 * If the PCI Configuration Command Register "Parity Error Response
+	 * Control" Bit was clear (0), then set the microcode variable
+	 * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+	 * to ignore DMA parity errors.
+	 */
+	if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) {
+		AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+		word |= CONTROL_FLAG_IGNORE_PERR;
+		AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+	}
 
-    /*
-     * If the BIOS control flag AIPP (Asynchronous Information
-     * Phase Protection) disable bit is not set, then set the firmware
-     * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
-     * AIPP checking and encoding.
-     */
-    if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0)
-    {
-        AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
-        word |= CONTROL_FLAG_ENABLE_AIPP;
-        AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
-    }
+	/*
+	 * If the BIOS control flag AIPP (Asynchronous Information
+	 * Phase Protection) disable bit is not set, then set the firmware
+	 * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
+	 * AIPP checking and encoding.
+	 */
+	if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) {
+		AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+		word |= CONTROL_FLAG_ENABLE_AIPP;
+		AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+	}
 
-    /*
-     * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
-     * and START_CTL_TH [3:2].
-     */
-    AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
-        FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
+	/*
+	 * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
+	 * and START_CTL_TH [3:2].
+	 */
+	AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+			     FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
 
-    /*
-     * Microcode operating variables for WDTR, SDTR, and command tag
-     * queuing will be set in AdvInquiryHandling() based on what a
-     * device reports it is capable of in Inquiry byte 7.
-     *
-     * If SCSI Bus Resets have been disabled, then directly set
-     * SDTR and WDTR from the EEPROM configuration. This will allow
-     * the BIOS and warm boot to work without a SCSI bus hang on
-     * the Inquiry caused by host and target mismatched DTR values.
-     * Without the SCSI Bus Reset, before an Inquiry a device can't
-     * be assumed to be in Asynchronous, Narrow mode.
-     */
-    if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0)
-    {
-        AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able);
-        AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able);
-    }
+	/*
+	 * Microcode operating variables for WDTR, SDTR, and command tag
+	 * queuing will be set in AdvInquiryHandling() based on what a
+	 * device reports it is capable of in Inquiry byte 7.
+	 *
+	 * If SCSI Bus Resets have been disabled, then directly set
+	 * SDTR and WDTR from the EEPROM configuration. This will allow
+	 * the BIOS and warm boot to work without a SCSI bus hang on
+	 * the Inquiry caused by host and target mismatched DTR values.
+	 * Without the SCSI Bus Reset, before an Inquiry a device can't
+	 * be assumed to be in Asynchronous, Narrow mode.
+	 */
+	if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) {
+		AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
+				 asc_dvc->wdtr_able);
+		AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
+				 asc_dvc->sdtr_able);
+	}
 
-    /*
-     * Set microcode operating variables for DISC and SDTR_SPEED1,
-     * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
-     * configuration values.
-     *
-     * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
-     * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
-     * without determining here whether the device supports SDTR.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
-    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
-    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
-    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
-    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
+	/*
+	 * Set microcode operating variables for DISC and SDTR_SPEED1,
+	 * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
+	 * configuration values.
+	 *
+	 * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+	 * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+	 * without determining here whether the device supports SDTR.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE,
+			 asc_dvc->cfg->disc_enable);
+	AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
+	AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
+	AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
+	AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
 
-    /*
-     * Set SCSI_CFG0 Microcode Default Value.
-     *
-     * The microcode will set the SCSI_CFG0 register using this value
-     * after it is started below.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
-        PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
-        asc_dvc->chip_scsi_id);
+	/*
+	 * Set SCSI_CFG0 Microcode Default Value.
+	 *
+	 * The microcode will set the SCSI_CFG0 register using this value
+	 * after it is started below.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+			 PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+			 asc_dvc->chip_scsi_id);
 
-    /*
-     * Calculate SCSI_CFG1 Microcode Default Value.
-     *
-     * The microcode will set the SCSI_CFG1 register using this value
-     * after it is started below.
-     *
-     * Each ASC-38C1600 function has only two cable detect bits.
-     * The bus mode override bits are in IOPB_SOFT_OVER_WR.
-     */
-    scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+	/*
+	 * Calculate SCSI_CFG1 Microcode Default Value.
+	 *
+	 * The microcode will set the SCSI_CFG1 register using this value
+	 * after it is started below.
+	 *
+	 * Each ASC-38C1600 function has only two cable detect bits.
+	 * The bus mode override bits are in IOPB_SOFT_OVER_WR.
+	 */
+	scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
 
-    /*
-     * If the cable is reversed all of the SCSI_CTRL register signals
-     * will be set. Check for and return an error if this condition is
-     * found.
-     */
-    if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07)
-    {
-        asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
-        return ADV_ERROR;
-    }
+	/*
+	 * If the cable is reversed all of the SCSI_CTRL register signals
+	 * will be set. Check for and return an error if this condition is
+	 * found.
+	 */
+	if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) {
+		asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+		return ADV_ERROR;
+	}
 
-    /*
-     * Each ASC-38C1600 function has two connectors. Only an HVD device
-     * can not be connected to either connector. An LVD device or SE device
-     * may be connected to either connecor. If an SE device is connected,
-     * then at most Ultra speed (20 Mhz) can be used on both connectors.
-     *
-     * If an HVD device is attached, return an error.
-     */
-    if (scsi_cfg1 & HVD)
-    {
-        asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
-        return ADV_ERROR;
-    }
+	/*
+	 * Each ASC-38C1600 function has two connectors. Only an HVD device
+	 * can not be connected to either connector. An LVD device or SE device
+	 * may be connected to either connecor. If an SE device is connected,
+	 * then at most Ultra speed (20 Mhz) can be used on both connectors.
+	 *
+	 * If an HVD device is attached, return an error.
+	 */
+	if (scsi_cfg1 & HVD) {
+		asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
+		return ADV_ERROR;
+	}
 
-    /*
-     * Each function in the ASC-38C1600 uses only the SE cable detect and
-     * termination because there are two connectors for each function. Each
-     * function may use either LVD or SE mode. Corresponding the SE automatic
-     * termination control EEPROM bits are used for each function. Each
-     * function has its own EEPROM. If SE automatic control is enabled for
-     * the function, then set the termination value based on a table listed
-     * in a_condor.h.
-     *
-     * If manual termination is specified in the EEPROM for the function,
-     * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
-     * ready to be 'ored' into SCSI_CFG1.
-     */
-    if ((asc_dvc->cfg->termination & TERM_SE) == 0)
-    {
-        /* SE automatic termination control is enabled. */
-        switch(scsi_cfg1 & C_DET_SE)
-        {
-            /* TERM_SE_HI: on, TERM_SE_LO: on */
-            case 0x1: case 0x2: case 0x3:
-                asc_dvc->cfg->termination |= TERM_SE;
-                break;
+	/*
+	 * Each function in the ASC-38C1600 uses only the SE cable detect and
+	 * termination because there are two connectors for each function. Each
+	 * function may use either LVD or SE mode. Corresponding the SE automatic
+	 * termination control EEPROM bits are used for each function. Each
+	 * function has its own EEPROM. If SE automatic control is enabled for
+	 * the function, then set the termination value based on a table listed
+	 * in a_condor.h.
+	 *
+	 * If manual termination is specified in the EEPROM for the function,
+	 * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
+	 * ready to be 'ored' into SCSI_CFG1.
+	 */
+	if ((asc_dvc->cfg->termination & TERM_SE) == 0) {
+		/* SE automatic termination control is enabled. */
+		switch (scsi_cfg1 & C_DET_SE) {
+			/* TERM_SE_HI: on, TERM_SE_LO: on */
+		case 0x1:
+		case 0x2:
+		case 0x3:
+			asc_dvc->cfg->termination |= TERM_SE;
+			break;
 
-            case 0x0:
-                if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0)
-                {
-                    /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
-                }
-                else
-                {
-                    /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
-                    asc_dvc->cfg->termination |= TERM_SE_HI;
-                }
-                break;
-        }
-    }
+		case 0x0:
+			if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0) {
+				/* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
+			} else {
+				/* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
+				asc_dvc->cfg->termination |= TERM_SE_HI;
+			}
+			break;
+		}
+	}
 
-    /*
-     * Clear any set TERM_SE bits.
-     */
-    scsi_cfg1 &= ~TERM_SE;
+	/*
+	 * Clear any set TERM_SE bits.
+	 */
+	scsi_cfg1 &= ~TERM_SE;
 
-    /*
-     * Invert the TERM_SE bits and then set 'scsi_cfg1'.
-     */
-    scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
+	/*
+	 * Invert the TERM_SE bits and then set 'scsi_cfg1'.
+	 */
+	scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
 
-    /*
-     * Clear Big Endian and Terminator Polarity bits and set possibly
-     * modified termination control bits in the Microcode SCSI_CFG1
-     * Register Value.
-     *
-     * Big Endian bit is not used even on big endian machines.
-     */
-    scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
+	/*
+	 * Clear Big Endian and Terminator Polarity bits and set possibly
+	 * modified termination control bits in the Microcode SCSI_CFG1
+	 * Register Value.
+	 *
+	 * Big Endian bit is not used even on big endian machines.
+	 */
+	scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
 
-    /*
-     * Set SCSI_CFG1 Microcode Default Value
-     *
-     * Set possibly modified termination control bits in the Microcode
-     * SCSI_CFG1 Register Value.
-     *
-     * The microcode will set the SCSI_CFG1 register using this value
-     * after it is started below.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
+	/*
+	 * Set SCSI_CFG1 Microcode Default Value
+	 *
+	 * Set possibly modified termination control bits in the Microcode
+	 * SCSI_CFG1 Register Value.
+	 *
+	 * The microcode will set the SCSI_CFG1 register using this value
+	 * after it is started below.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
 
-    /*
-     * Set MEM_CFG Microcode Default Value
-     *
-     * The microcode will set the MEM_CFG register using this value
-     * after it is started below.
-     *
-     * MEM_CFG may be accessed as a word or byte, but only bits 0-7
-     * are defined.
-     *
-     * ASC-38C1600 has 32KB internal memory.
-     *
-     * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
-     * out a special 16K Adv Library and Microcode version. After the issue
-     * resolved, we should turn back to the 32K support. Both a_condor.h and
-     * mcode.sas files also need to be updated.
-     *
-     * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
-     *  BIOS_EN | RAM_SZ_32KB);
-     */
-     AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, BIOS_EN | RAM_SZ_16KB);
+	/*
+	 * Set MEM_CFG Microcode Default Value
+	 *
+	 * The microcode will set the MEM_CFG register using this value
+	 * after it is started below.
+	 *
+	 * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+	 * are defined.
+	 *
+	 * ASC-38C1600 has 32KB internal memory.
+	 *
+	 * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
+	 * out a special 16K Adv Library and Microcode version. After the issue
+	 * resolved, we should turn back to the 32K support. Both a_condor.h and
+	 * mcode.sas files also need to be updated.
+	 *
+	 * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+	 *  BIOS_EN | RAM_SZ_32KB);
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+			 BIOS_EN | RAM_SZ_16KB);
 
-    /*
-     * Set SEL_MASK Microcode Default Value
-     *
-     * The microcode will set the SEL_MASK register using this value
-     * after it is started below.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
-        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+	/*
+	 * Set SEL_MASK Microcode Default Value
+	 *
+	 * The microcode will set the SEL_MASK register using this value
+	 * after it is started below.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+			 ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
 
-    /*
-     * Build the carrier freelist.
-     *
-     * Driver must have already allocated memory and set 'carrier_buf'.
-     */
+	/*
+	 * Build the carrier freelist.
+	 *
+	 * Driver must have already allocated memory and set 'carrier_buf'.
+	 */
 
-    ASC_ASSERT(asc_dvc->carrier_buf != NULL);
+	ASC_ASSERT(asc_dvc->carrier_buf != NULL);
 
-    carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
-    asc_dvc->carr_freelist = NULL;
-    if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf)
-    {
-        buf_size = ADV_CARRIER_BUFSIZE;
-    } else
-    {
-        buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
-    }
+	carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+	asc_dvc->carr_freelist = NULL;
+	if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf) {
+		buf_size = ADV_CARRIER_BUFSIZE;
+	} else {
+		buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+	}
 
-    do {
-        /*
-         * Get physical address for the carrier 'carrp'.
-         */
-        contig_len = sizeof(ADV_CARR_T);
-        carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
-            (ADV_SDCNT *) &contig_len, ADV_IS_CARRIER_FLAG));
+	do {
+		/*
+		 * Get physical address for the carrier 'carrp'.
+		 */
+		contig_len = sizeof(ADV_CARR_T);
+		carr_paddr =
+		    cpu_to_le32(DvcGetPhyAddr
+				(asc_dvc, NULL, (uchar *)carrp,
+				 (ADV_SDCNT *)&contig_len,
+				 ADV_IS_CARRIER_FLAG));
 
-        buf_size -= sizeof(ADV_CARR_T);
+		buf_size -= sizeof(ADV_CARR_T);
 
-        /*
-         * If the current carrier is not physically contiguous, then
-         * maybe there was a page crossing. Try the next carrier aligned
-         * start address.
-         */
-        if (contig_len < sizeof(ADV_CARR_T))
-        {
-            carrp++;
-            continue;
-        }
+		/*
+		 * If the current carrier is not physically contiguous, then
+		 * maybe there was a page crossing. Try the next carrier aligned
+		 * start address.
+		 */
+		if (contig_len < sizeof(ADV_CARR_T)) {
+			carrp++;
+			continue;
+		}
 
-        carrp->carr_pa = carr_paddr;
-        carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
+		carrp->carr_pa = carr_paddr;
+		carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
 
-        /*
-         * Insert the carrier at the beginning of the freelist.
-         */
-        carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
-        asc_dvc->carr_freelist = carrp;
+		/*
+		 * Insert the carrier at the beginning of the freelist.
+		 */
+		carrp->next_vpa =
+		    cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+		asc_dvc->carr_freelist = carrp;
 
-        carrp++;
-    }
-    while (buf_size > 0);
+		carrp++;
+	}
+	while (buf_size > 0);
 
-    /*
-     * Set-up the Host->RISC Initiator Command Queue (ICQ).
-     */
-    if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL)
-    {
-        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
-        return ADV_ERROR;
-    }
-    asc_dvc->carr_freelist = (ADV_CARR_T *)
-        ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+	/*
+	 * Set-up the Host->RISC Initiator Command Queue (ICQ).
+	 */
+	if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) {
+		asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+		return ADV_ERROR;
+	}
+	asc_dvc->carr_freelist = (ADV_CARR_T *)
+	    ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
 
-    /*
-     * The first command issued will be placed in the stopper carrier.
-     */
-    asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+	/*
+	 * The first command issued will be placed in the stopper carrier.
+	 */
+	asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
 
-    /*
-     * Set RISC ICQ physical address start value. Initialize the
-     * COMMA register to the same value otherwise the RISC will
-     * prematurely detect a command is available.
-     */
-    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
-    AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
-        le32_to_cpu(asc_dvc->icq_sp->carr_pa));
+	/*
+	 * Set RISC ICQ physical address start value. Initialize the
+	 * COMMA register to the same value otherwise the RISC will
+	 * prematurely detect a command is available.
+	 */
+	AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+	AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
+			      le32_to_cpu(asc_dvc->icq_sp->carr_pa));
 
-    /*
-     * Set-up the RISC->Host Initiator Response Queue (IRQ).
-     */
-    if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL)
-    {
-        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
-        return ADV_ERROR;
-    }
-    asc_dvc->carr_freelist = (ADV_CARR_T *)
-        ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+	/*
+	 * Set-up the RISC->Host Initiator Response Queue (IRQ).
+	 */
+	if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) {
+		asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+		return ADV_ERROR;
+	}
+	asc_dvc->carr_freelist = (ADV_CARR_T *)
+	    ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
 
-    /*
-     * The first command completed by the RISC will be placed in
-     * the stopper.
-     *
-     * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
-     * completed the RISC will set the ASC_RQ_STOPPER bit.
-     */
-    asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+	/*
+	 * The first command completed by the RISC will be placed in
+	 * the stopper.
+	 *
+	 * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+	 * completed the RISC will set the ASC_RQ_STOPPER bit.
+	 */
+	asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
 
-    /*
-     * Set RISC IRQ physical address start value.
-     */
-    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
-    asc_dvc->carr_pending_cnt = 0;
+	/*
+	 * Set RISC IRQ physical address start value.
+	 */
+	AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+	asc_dvc->carr_pending_cnt = 0;
 
-    AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
-        (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
-    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
-    AdvWriteWordRegister(iop_base, IOPW_PC, word);
+	AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+			     (ADV_INTR_ENABLE_HOST_INTR |
+			      ADV_INTR_ENABLE_GLOBAL_INTR));
+	AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+	AdvWriteWordRegister(iop_base, IOPW_PC, word);
 
-    /* finally, finally, gentlemen, start your engine */
-    AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+	/* finally, finally, gentlemen, start your engine */
+	AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
 
-    /*
-     * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
-     * Resets should be performed. The RISC has to be running
-     * to issue a SCSI Bus Reset.
-     */
-    if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
-    {
-        /*
-         * If the BIOS Signature is present in memory, restore the
-         * per TID microcode operating variables.
-         */
-        if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
-        {
-            /*
-             * Restore per TID negotiated values.
-             */
-            AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
-            AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-            AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
-            AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
-            for (tid = 0; tid <= ASC_MAX_TID; tid++)
-            {
-                AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
-                    max_cmd[tid]);
-            }
-        } else
-        {
-            if (AdvResetSB(asc_dvc) != ADV_TRUE)
-            {
-                warn_code = ASC_WARN_BUSRESET_ERROR;
-            }
-        }
-    }
+	/*
+	 * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+	 * Resets should be performed. The RISC has to be running
+	 * to issue a SCSI Bus Reset.
+	 */
+	if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) {
+		/*
+		 * If the BIOS Signature is present in memory, restore the
+		 * per TID microcode operating variables.
+		 */
+		if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] ==
+		    0x55AA) {
+			/*
+			 * Restore per TID negotiated values.
+			 */
+			AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+			AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+			AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+			AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+					 tagqng_able);
+			for (tid = 0; tid <= ASC_MAX_TID; tid++) {
+				AdvWriteByteLram(iop_base,
+						 ASC_MC_NUMBER_OF_MAX_CMD + tid,
+						 max_cmd[tid]);
+			}
+		} else {
+			if (AdvResetSB(asc_dvc) != ADV_TRUE) {
+				warn_code = ASC_WARN_BUSRESET_ERROR;
+			}
+		}
+	}
 
-    return warn_code;
+	return warn_code;
 }
 
 /*
@@ -16378,164 +16135,146 @@
  *
  * Note: Chip is stopped on entry.
  */
-STATIC int __init
-AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
+static int __init AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
 {
-    AdvPortAddr         iop_base;
-    ushort              warn_code;
-    ADVEEP_3550_CONFIG  eep_config;
-    int                 i;
+	AdvPortAddr iop_base;
+	ushort warn_code;
+	ADVEEP_3550_CONFIG eep_config;
+	int i;
 
-    iop_base = asc_dvc->iop_base;
+	iop_base = asc_dvc->iop_base;
 
-    warn_code = 0;
+	warn_code = 0;
 
-    /*
-     * Read the board's EEPROM configuration.
-     *
-     * Set default values if a bad checksum is found.
-     */
-    if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
-    {
-        warn_code |= ASC_WARN_EEPROM_CHKSUM;
+	/*
+	 * Read the board's EEPROM configuration.
+	 *
+	 * Set default values if a bad checksum is found.
+	 */
+	if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) {
+		warn_code |= ASC_WARN_EEPROM_CHKSUM;
 
-        /*
-         * Set EEPROM default values.
-         */
-        for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++)
-        {
-            *((uchar *) &eep_config + i) =
-                *((uchar *) &Default_3550_EEPROM_Config + i);
-        }
+		/*
+		 * Set EEPROM default values.
+		 */
+		for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++) {
+			*((uchar *)&eep_config + i) =
+			    *((uchar *)&Default_3550_EEPROM_Config + i);
+		}
 
-        /*
-         * Assume the 6 byte board serial number that was read
-         * from EEPROM is correct even if the EEPROM checksum
-         * failed.
-         */
-        eep_config.serial_number_word3 =
-            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
+		/*
+		 * Assume the 6 byte board serial number that was read
+		 * from EEPROM is correct even if the EEPROM checksum
+		 * failed.
+		 */
+		eep_config.serial_number_word3 =
+		    AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
 
-        eep_config.serial_number_word2 =
-            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
+		eep_config.serial_number_word2 =
+		    AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
 
-        eep_config.serial_number_word1 =
-            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
+		eep_config.serial_number_word1 =
+		    AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
 
-        AdvSet3550EEPConfig(iop_base, &eep_config);
-    }
-    /*
-     * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
-     * EEPROM configuration that was read.
-     *
-     * This is the mapping of EEPROM fields to Adv Library fields.
-     */
-    asc_dvc->wdtr_able = eep_config.wdtr_able;
-    asc_dvc->sdtr_able = eep_config.sdtr_able;
-    asc_dvc->ultra_able = eep_config.ultra_able;
-    asc_dvc->tagqng_able = eep_config.tagqng_able;
-    asc_dvc->cfg->disc_enable = eep_config.disc_enable;
-    asc_dvc->max_host_qng = eep_config.max_host_qng;
-    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
-    asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
-    asc_dvc->start_motor = eep_config.start_motor;
-    asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
-    asc_dvc->bios_ctrl = eep_config.bios_ctrl;
-    asc_dvc->no_scam = eep_config.scam_tolerant;
-    asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
-    asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
-    asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
+		AdvSet3550EEPConfig(iop_base, &eep_config);
+	}
+	/*
+	 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
+	 * EEPROM configuration that was read.
+	 *
+	 * This is the mapping of EEPROM fields to Adv Library fields.
+	 */
+	asc_dvc->wdtr_able = eep_config.wdtr_able;
+	asc_dvc->sdtr_able = eep_config.sdtr_able;
+	asc_dvc->ultra_able = eep_config.ultra_able;
+	asc_dvc->tagqng_able = eep_config.tagqng_able;
+	asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+	asc_dvc->max_host_qng = eep_config.max_host_qng;
+	asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+	asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
+	asc_dvc->start_motor = eep_config.start_motor;
+	asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+	asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+	asc_dvc->no_scam = eep_config.scam_tolerant;
+	asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
+	asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
+	asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
 
-    /*
-     * Set the host maximum queuing (max. 253, min. 16) and the per device
-     * maximum queuing (max. 63, min. 4).
-     */
-    if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG)
-    {
-        eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
-    } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG)
-    {
-        /* If the value is zero, assume it is uninitialized. */
-        if (eep_config.max_host_qng == 0)
-        {
-            eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
-        } else
-        {
-            eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
-        }
-    }
+	/*
+	 * Set the host maximum queuing (max. 253, min. 16) and the per device
+	 * maximum queuing (max. 63, min. 4).
+	 */
+	if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
+		eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+	} else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
+		/* If the value is zero, assume it is uninitialized. */
+		if (eep_config.max_host_qng == 0) {
+			eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+		} else {
+			eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+		}
+	}
 
-    if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG)
-    {
-        eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
-    } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG)
-    {
-        /* If the value is zero, assume it is uninitialized. */
-        if (eep_config.max_dvc_qng == 0)
-        {
-            eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
-        } else
-        {
-            eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
-        }
-    }
+	if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
+		eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+	} else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
+		/* If the value is zero, assume it is uninitialized. */
+		if (eep_config.max_dvc_qng == 0) {
+			eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+		} else {
+			eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+		}
+	}
 
-    /*
-     * If 'max_dvc_qng' is greater than 'max_host_qng', then
-     * set 'max_dvc_qng' to 'max_host_qng'.
-     */
-    if (eep_config.max_dvc_qng > eep_config.max_host_qng)
-    {
-        eep_config.max_dvc_qng = eep_config.max_host_qng;
-    }
+	/*
+	 * If 'max_dvc_qng' is greater than 'max_host_qng', then
+	 * set 'max_dvc_qng' to 'max_host_qng'.
+	 */
+	if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
+		eep_config.max_dvc_qng = eep_config.max_host_qng;
+	}
 
-    /*
-     * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
-     * values based on possibly adjusted EEPROM values.
-     */
-    asc_dvc->max_host_qng = eep_config.max_host_qng;
-    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+	/*
+	 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
+	 * values based on possibly adjusted EEPROM values.
+	 */
+	asc_dvc->max_host_qng = eep_config.max_host_qng;
+	asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
 
+	/*
+	 * If the EEPROM 'termination' field is set to automatic (0), then set
+	 * the ADV_DVC_CFG 'termination' field to automatic also.
+	 *
+	 * If the termination is specified with a non-zero 'termination'
+	 * value check that a legal value is set and set the ADV_DVC_CFG
+	 * 'termination' field appropriately.
+	 */
+	if (eep_config.termination == 0) {
+		asc_dvc->cfg->termination = 0;	/* auto termination */
+	} else {
+		/* Enable manual control with low off / high off. */
+		if (eep_config.termination == 1) {
+			asc_dvc->cfg->termination = TERM_CTL_SEL;
 
-    /*
-     * If the EEPROM 'termination' field is set to automatic (0), then set
-     * the ADV_DVC_CFG 'termination' field to automatic also.
-     *
-     * If the termination is specified with a non-zero 'termination'
-     * value check that a legal value is set and set the ADV_DVC_CFG
-     * 'termination' field appropriately.
-     */
-    if (eep_config.termination == 0)
-    {
-        asc_dvc->cfg->termination = 0;    /* auto termination */
-    } else
-    {
-        /* Enable manual control with low off / high off. */
-        if (eep_config.termination == 1)
-        {
-            asc_dvc->cfg->termination = TERM_CTL_SEL;
+			/* Enable manual control with low off / high on. */
+		} else if (eep_config.termination == 2) {
+			asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
 
-        /* Enable manual control with low off / high on. */
-        } else if (eep_config.termination == 2)
-        {
-            asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
+			/* Enable manual control with low on / high on. */
+		} else if (eep_config.termination == 3) {
+			asc_dvc->cfg->termination =
+			    TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
+		} else {
+			/*
+			 * The EEPROM 'termination' field contains a bad value. Use
+			 * automatic termination instead.
+			 */
+			asc_dvc->cfg->termination = 0;
+			warn_code |= ASC_WARN_EEPROM_TERMINATION;
+		}
+	}
 
-        /* Enable manual control with low on / high on. */
-        } else if (eep_config.termination == 3)
-        {
-            asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
-        } else
-        {
-            /*
-             * The EEPROM 'termination' field contains a bad value. Use
-             * automatic termination instead.
-             */
-            asc_dvc->cfg->termination = 0;
-            warn_code |= ASC_WARN_EEPROM_TERMINATION;
-        }
-    }
-
-    return warn_code;
+	return warn_code;
 }
 
 /*
@@ -16550,225 +16289,195 @@
  *
  * Note: Chip is stopped on entry.
  */
-STATIC int __init
-AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
+static int __init AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
 {
-    AdvPortAddr              iop_base;
-    ushort                   warn_code;
-    ADVEEP_38C0800_CONFIG    eep_config;
-    int                      i;
-    uchar                    tid, termination;
-    ushort                   sdtr_speed = 0;
+	AdvPortAddr iop_base;
+	ushort warn_code;
+	ADVEEP_38C0800_CONFIG eep_config;
+	int i;
+	uchar tid, termination;
+	ushort sdtr_speed = 0;
 
-    iop_base = asc_dvc->iop_base;
+	iop_base = asc_dvc->iop_base;
 
-    warn_code = 0;
+	warn_code = 0;
 
-    /*
-     * Read the board's EEPROM configuration.
-     *
-     * Set default values if a bad checksum is found.
-     */
-    if (AdvGet38C0800EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
-    {
-        warn_code |= ASC_WARN_EEPROM_CHKSUM;
+	/*
+	 * Read the board's EEPROM configuration.
+	 *
+	 * Set default values if a bad checksum is found.
+	 */
+	if (AdvGet38C0800EEPConfig(iop_base, &eep_config) !=
+	    eep_config.check_sum) {
+		warn_code |= ASC_WARN_EEPROM_CHKSUM;
 
-        /*
-         * Set EEPROM default values.
-         */
-        for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++)
-        {
-            *((uchar *) &eep_config + i) =
-                *((uchar *) &Default_38C0800_EEPROM_Config + i);
-        }
+		/*
+		 * Set EEPROM default values.
+		 */
+		for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++) {
+			*((uchar *)&eep_config + i) =
+			    *((uchar *)&Default_38C0800_EEPROM_Config + i);
+		}
 
-        /*
-         * Assume the 6 byte board serial number that was read
-         * from EEPROM is correct even if the EEPROM checksum
-         * failed.
-         */
-        eep_config.serial_number_word3 =
-            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
+		/*
+		 * Assume the 6 byte board serial number that was read
+		 * from EEPROM is correct even if the EEPROM checksum
+		 * failed.
+		 */
+		eep_config.serial_number_word3 =
+		    AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
 
-        eep_config.serial_number_word2 =
-            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
+		eep_config.serial_number_word2 =
+		    AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
 
-        eep_config.serial_number_word1 =
-            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
+		eep_config.serial_number_word1 =
+		    AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
 
-        AdvSet38C0800EEPConfig(iop_base, &eep_config);
-    }
-    /*
-     * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
-     * EEPROM configuration that was read.
-     *
-     * This is the mapping of EEPROM fields to Adv Library fields.
-     */
-    asc_dvc->wdtr_able = eep_config.wdtr_able;
-    asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
-    asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
-    asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
-    asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
-    asc_dvc->tagqng_able = eep_config.tagqng_able;
-    asc_dvc->cfg->disc_enable = eep_config.disc_enable;
-    asc_dvc->max_host_qng = eep_config.max_host_qng;
-    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
-    asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
-    asc_dvc->start_motor = eep_config.start_motor;
-    asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
-    asc_dvc->bios_ctrl = eep_config.bios_ctrl;
-    asc_dvc->no_scam = eep_config.scam_tolerant;
-    asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
-    asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
-    asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
+		AdvSet38C0800EEPConfig(iop_base, &eep_config);
+	}
+	/*
+	 * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
+	 * EEPROM configuration that was read.
+	 *
+	 * This is the mapping of EEPROM fields to Adv Library fields.
+	 */
+	asc_dvc->wdtr_able = eep_config.wdtr_able;
+	asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
+	asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
+	asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
+	asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
+	asc_dvc->tagqng_able = eep_config.tagqng_able;
+	asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+	asc_dvc->max_host_qng = eep_config.max_host_qng;
+	asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+	asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
+	asc_dvc->start_motor = eep_config.start_motor;
+	asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+	asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+	asc_dvc->no_scam = eep_config.scam_tolerant;
+	asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
+	asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
+	asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
 
-    /*
-     * For every Target ID if any of its 'sdtr_speed[1234]' bits
-     * are set, then set an 'sdtr_able' bit for it.
-     */
-    asc_dvc->sdtr_able = 0;
-    for (tid = 0; tid <= ADV_MAX_TID; tid++)
-    {
-        if (tid == 0)
-        {
-            sdtr_speed = asc_dvc->sdtr_speed1;
-        } else if (tid == 4)
-        {
-            sdtr_speed = asc_dvc->sdtr_speed2;
-        } else if (tid == 8)
-        {
-            sdtr_speed = asc_dvc->sdtr_speed3;
-        } else if (tid == 12)
-        {
-            sdtr_speed = asc_dvc->sdtr_speed4;
-        }
-        if (sdtr_speed & ADV_MAX_TID)
-        {
-            asc_dvc->sdtr_able |= (1 << tid);
-        }
-        sdtr_speed >>= 4;
-    }
+	/*
+	 * For every Target ID if any of its 'sdtr_speed[1234]' bits
+	 * are set, then set an 'sdtr_able' bit for it.
+	 */
+	asc_dvc->sdtr_able = 0;
+	for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+		if (tid == 0) {
+			sdtr_speed = asc_dvc->sdtr_speed1;
+		} else if (tid == 4) {
+			sdtr_speed = asc_dvc->sdtr_speed2;
+		} else if (tid == 8) {
+			sdtr_speed = asc_dvc->sdtr_speed3;
+		} else if (tid == 12) {
+			sdtr_speed = asc_dvc->sdtr_speed4;
+		}
+		if (sdtr_speed & ADV_MAX_TID) {
+			asc_dvc->sdtr_able |= (1 << tid);
+		}
+		sdtr_speed >>= 4;
+	}
 
-    /*
-     * Set the host maximum queuing (max. 253, min. 16) and the per device
-     * maximum queuing (max. 63, min. 4).
-     */
-    if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG)
-    {
-        eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
-    } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG)
-    {
-        /* If the value is zero, assume it is uninitialized. */
-        if (eep_config.max_host_qng == 0)
-        {
-            eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
-        } else
-        {
-            eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
-        }
-    }
+	/*
+	 * Set the host maximum queuing (max. 253, min. 16) and the per device
+	 * maximum queuing (max. 63, min. 4).
+	 */
+	if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
+		eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+	} else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
+		/* If the value is zero, assume it is uninitialized. */
+		if (eep_config.max_host_qng == 0) {
+			eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+		} else {
+			eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+		}
+	}
 
-    if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG)
-    {
-        eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
-    } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG)
-    {
-        /* If the value is zero, assume it is uninitialized. */
-        if (eep_config.max_dvc_qng == 0)
-        {
-            eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
-        } else
-        {
-            eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
-        }
-    }
+	if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
+		eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+	} else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
+		/* If the value is zero, assume it is uninitialized. */
+		if (eep_config.max_dvc_qng == 0) {
+			eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+		} else {
+			eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+		}
+	}
 
-    /*
-     * If 'max_dvc_qng' is greater than 'max_host_qng', then
-     * set 'max_dvc_qng' to 'max_host_qng'.
-     */
-    if (eep_config.max_dvc_qng > eep_config.max_host_qng)
-    {
-        eep_config.max_dvc_qng = eep_config.max_host_qng;
-    }
+	/*
+	 * If 'max_dvc_qng' is greater than 'max_host_qng', then
+	 * set 'max_dvc_qng' to 'max_host_qng'.
+	 */
+	if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
+		eep_config.max_dvc_qng = eep_config.max_host_qng;
+	}
 
-    /*
-     * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
-     * values based on possibly adjusted EEPROM values.
-     */
-    asc_dvc->max_host_qng = eep_config.max_host_qng;
-    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+	/*
+	 * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
+	 * values based on possibly adjusted EEPROM values.
+	 */
+	asc_dvc->max_host_qng = eep_config.max_host_qng;
+	asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
 
-    /*
-     * If the EEPROM 'termination' field is set to automatic (0), then set
-     * the ADV_DVC_CFG 'termination' field to automatic also.
-     *
-     * If the termination is specified with a non-zero 'termination'
-     * value check that a legal value is set and set the ADV_DVC_CFG
-     * 'termination' field appropriately.
-     */
-    if (eep_config.termination_se == 0)
-    {
-        termination = 0;                         /* auto termination for SE */
-    } else
-    {
-        /* Enable manual control with low off / high off. */
-        if (eep_config.termination_se == 1)
-        {
-            termination = 0;
+	/*
+	 * If the EEPROM 'termination' field is set to automatic (0), then set
+	 * the ADV_DVC_CFG 'termination' field to automatic also.
+	 *
+	 * If the termination is specified with a non-zero 'termination'
+	 * value check that a legal value is set and set the ADV_DVC_CFG
+	 * 'termination' field appropriately.
+	 */
+	if (eep_config.termination_se == 0) {
+		termination = 0;	/* auto termination for SE */
+	} else {
+		/* Enable manual control with low off / high off. */
+		if (eep_config.termination_se == 1) {
+			termination = 0;
 
-        /* Enable manual control with low off / high on. */
-        } else if (eep_config.termination_se == 2)
-        {
-            termination = TERM_SE_HI;
+			/* Enable manual control with low off / high on. */
+		} else if (eep_config.termination_se == 2) {
+			termination = TERM_SE_HI;
 
-        /* Enable manual control with low on / high on. */
-        } else if (eep_config.termination_se == 3)
-        {
-            termination = TERM_SE;
-        } else
-        {
-            /*
-             * The EEPROM 'termination_se' field contains a bad value.
-             * Use automatic termination instead.
-             */
-            termination = 0;
-            warn_code |= ASC_WARN_EEPROM_TERMINATION;
-        }
-    }
+			/* Enable manual control with low on / high on. */
+		} else if (eep_config.termination_se == 3) {
+			termination = TERM_SE;
+		} else {
+			/*
+			 * The EEPROM 'termination_se' field contains a bad value.
+			 * Use automatic termination instead.
+			 */
+			termination = 0;
+			warn_code |= ASC_WARN_EEPROM_TERMINATION;
+		}
+	}
 
-    if (eep_config.termination_lvd == 0)
-    {
-        asc_dvc->cfg->termination = termination; /* auto termination for LVD */
-    } else
-    {
-        /* Enable manual control with low off / high off. */
-        if (eep_config.termination_lvd == 1)
-        {
-            asc_dvc->cfg->termination = termination;
+	if (eep_config.termination_lvd == 0) {
+		asc_dvc->cfg->termination = termination;	/* auto termination for LVD */
+	} else {
+		/* Enable manual control with low off / high off. */
+		if (eep_config.termination_lvd == 1) {
+			asc_dvc->cfg->termination = termination;
 
-        /* Enable manual control with low off / high on. */
-        } else if (eep_config.termination_lvd == 2)
-        {
-            asc_dvc->cfg->termination = termination | TERM_LVD_HI;
+			/* Enable manual control with low off / high on. */
+		} else if (eep_config.termination_lvd == 2) {
+			asc_dvc->cfg->termination = termination | TERM_LVD_HI;
 
-        /* Enable manual control with low on / high on. */
-        } else if (eep_config.termination_lvd == 3)
-        {
-            asc_dvc->cfg->termination =
-                termination | TERM_LVD;
-        } else
-        {
-            /*
-             * The EEPROM 'termination_lvd' field contains a bad value.
-             * Use automatic termination instead.
-             */
-            asc_dvc->cfg->termination = termination;
-            warn_code |= ASC_WARN_EEPROM_TERMINATION;
-        }
-    }
+			/* Enable manual control with low on / high on. */
+		} else if (eep_config.termination_lvd == 3) {
+			asc_dvc->cfg->termination = termination | TERM_LVD;
+		} else {
+			/*
+			 * The EEPROM 'termination_lvd' field contains a bad value.
+			 * Use automatic termination instead.
+			 */
+			asc_dvc->cfg->termination = termination;
+			warn_code |= ASC_WARN_EEPROM_TERMINATION;
+		}
+	}
 
-    return warn_code;
+	return warn_code;
 }
 
 /*
@@ -16783,265 +16492,240 @@
  *
  * Note: Chip is stopped on entry.
  */
-STATIC int __init
-AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
+static int __init AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
 {
-    AdvPortAddr              iop_base;
-    ushort                   warn_code;
-    ADVEEP_38C1600_CONFIG    eep_config;
-    int                      i;
-    uchar                    tid, termination;
-    ushort                   sdtr_speed = 0;
+	AdvPortAddr iop_base;
+	ushort warn_code;
+	ADVEEP_38C1600_CONFIG eep_config;
+	int i;
+	uchar tid, termination;
+	ushort sdtr_speed = 0;
 
-    iop_base = asc_dvc->iop_base;
+	iop_base = asc_dvc->iop_base;
 
-    warn_code = 0;
+	warn_code = 0;
 
-    /*
-     * Read the board's EEPROM configuration.
-     *
-     * Set default values if a bad checksum is found.
-     */
-    if (AdvGet38C1600EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
-    {
-        warn_code |= ASC_WARN_EEPROM_CHKSUM;
+	/*
+	 * Read the board's EEPROM configuration.
+	 *
+	 * Set default values if a bad checksum is found.
+	 */
+	if (AdvGet38C1600EEPConfig(iop_base, &eep_config) !=
+	    eep_config.check_sum) {
+		warn_code |= ASC_WARN_EEPROM_CHKSUM;
 
-        /*
-         * Set EEPROM default values.
-         */
-        for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++)
-        {
-            if (i == 1 && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) != 0)
-            {
-                /*
-                 * Set Function 1 EEPROM Word 0 MSB
-                 *
-                 * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
-                 * EEPROM bits.
-                 *
-                 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
-                 * old Mac system booting problem. The Expansion ROM must
-                 * be disabled in Function 1 for these systems.
-                 *
-                 */
-                *((uchar *) &eep_config + i) =
-                ((*((uchar *) &Default_38C1600_EEPROM_Config + i)) &
-                    (~(((ADV_EEPROM_BIOS_ENABLE | ADV_EEPROM_INTAB) >> 8) &
-                     0xFF)));
+		/*
+		 * Set EEPROM default values.
+		 */
+		for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++) {
+			if (i == 1
+			    && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) !=
+			    0) {
+				/*
+				 * Set Function 1 EEPROM Word 0 MSB
+				 *
+				 * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
+				 * EEPROM bits.
+				 *
+				 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
+				 * old Mac system booting problem. The Expansion ROM must
+				 * be disabled in Function 1 for these systems.
+				 *
+				 */
+				*((uchar *)&eep_config + i) =
+				    ((*
+				      ((uchar *)&Default_38C1600_EEPROM_Config
+				       +
+				       i)) &
+				     (~
+				      (((ADV_EEPROM_BIOS_ENABLE |
+					 ADV_EEPROM_INTAB) >> 8) & 0xFF)));
 
-                /*
-                 * Set the INTAB (bit 11) if the GPIO 0 input indicates
-                 * the Function 1 interrupt line is wired to INTA.
-                 *
-                 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
-                 *   1 - Function 1 interrupt line wired to INT A.
-                 *   0 - Function 1 interrupt line wired to INT B.
-                 *
-                 * Note: Adapter boards always have Function 0 wired to INTA.
-                 * Put all 5 GPIO bits in input mode and then read
-                 * their input values.
-                 */
-                AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, 0);
-                if (AdvReadByteRegister(iop_base, IOPB_GPIO_DATA) & 0x01)
-                {
-                    /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
-                *((uchar *) &eep_config + i) |=
-                    ((ADV_EEPROM_INTAB >> 8) & 0xFF);
-                }
-            }
-            else
-            {
-                *((uchar *) &eep_config + i) =
-                *((uchar *) &Default_38C1600_EEPROM_Config + i);
-            }
-        }
+				/*
+				 * Set the INTAB (bit 11) if the GPIO 0 input indicates
+				 * the Function 1 interrupt line is wired to INTA.
+				 *
+				 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
+				 *   1 - Function 1 interrupt line wired to INT A.
+				 *   0 - Function 1 interrupt line wired to INT B.
+				 *
+				 * Note: Adapter boards always have Function 0 wired to INTA.
+				 * Put all 5 GPIO bits in input mode and then read
+				 * their input values.
+				 */
+				AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL,
+						     0);
+				if (AdvReadByteRegister
+				    (iop_base, IOPB_GPIO_DATA) & 0x01) {
+					/* Function 1 interrupt wired to INTA; Set EEPROM bit. */
+					*((uchar *)&eep_config + i) |=
+					    ((ADV_EEPROM_INTAB >> 8) & 0xFF);
+				}
+			} else {
+				*((uchar *)&eep_config + i) =
+				    *((uchar *)&Default_38C1600_EEPROM_Config
+				      + i);
+			}
+		}
 
-        /*
-         * Assume the 6 byte board serial number that was read
-         * from EEPROM is correct even if the EEPROM checksum
-         * failed.
-         */
-        eep_config.serial_number_word3 =
-            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
+		/*
+		 * Assume the 6 byte board serial number that was read
+		 * from EEPROM is correct even if the EEPROM checksum
+		 * failed.
+		 */
+		eep_config.serial_number_word3 =
+		    AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
 
-        eep_config.serial_number_word2 =
-            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
+		eep_config.serial_number_word2 =
+		    AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
 
-        eep_config.serial_number_word1 =
-            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
+		eep_config.serial_number_word1 =
+		    AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
 
-        AdvSet38C1600EEPConfig(iop_base, &eep_config);
-    }
+		AdvSet38C1600EEPConfig(iop_base, &eep_config);
+	}
 
-    /*
-     * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
-     * EEPROM configuration that was read.
-     *
-     * This is the mapping of EEPROM fields to Adv Library fields.
-     */
-    asc_dvc->wdtr_able = eep_config.wdtr_able;
-    asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
-    asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
-    asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
-    asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
-    asc_dvc->ppr_able = 0;
-    asc_dvc->tagqng_able = eep_config.tagqng_able;
-    asc_dvc->cfg->disc_enable = eep_config.disc_enable;
-    asc_dvc->max_host_qng = eep_config.max_host_qng;
-    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
-    asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
-    asc_dvc->start_motor = eep_config.start_motor;
-    asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
-    asc_dvc->bios_ctrl = eep_config.bios_ctrl;
-    asc_dvc->no_scam = eep_config.scam_tolerant;
+	/*
+	 * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
+	 * EEPROM configuration that was read.
+	 *
+	 * This is the mapping of EEPROM fields to Adv Library fields.
+	 */
+	asc_dvc->wdtr_able = eep_config.wdtr_able;
+	asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
+	asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
+	asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
+	asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
+	asc_dvc->ppr_able = 0;
+	asc_dvc->tagqng_able = eep_config.tagqng_able;
+	asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+	asc_dvc->max_host_qng = eep_config.max_host_qng;
+	asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+	asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
+	asc_dvc->start_motor = eep_config.start_motor;
+	asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+	asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+	asc_dvc->no_scam = eep_config.scam_tolerant;
 
-    /*
-     * For every Target ID if any of its 'sdtr_speed[1234]' bits
-     * are set, then set an 'sdtr_able' bit for it.
-     */
-    asc_dvc->sdtr_able = 0;
-    for (tid = 0; tid <= ASC_MAX_TID; tid++)
-    {
-        if (tid == 0)
-        {
-            sdtr_speed = asc_dvc->sdtr_speed1;
-        } else if (tid == 4)
-        {
-            sdtr_speed = asc_dvc->sdtr_speed2;
-        } else if (tid == 8)
-        {
-            sdtr_speed = asc_dvc->sdtr_speed3;
-        } else if (tid == 12)
-        {
-            sdtr_speed = asc_dvc->sdtr_speed4;
-        }
-        if (sdtr_speed & ASC_MAX_TID)
-        {
-            asc_dvc->sdtr_able |= (1 << tid);
-        }
-        sdtr_speed >>= 4;
-    }
+	/*
+	 * For every Target ID if any of its 'sdtr_speed[1234]' bits
+	 * are set, then set an 'sdtr_able' bit for it.
+	 */
+	asc_dvc->sdtr_able = 0;
+	for (tid = 0; tid <= ASC_MAX_TID; tid++) {
+		if (tid == 0) {
+			sdtr_speed = asc_dvc->sdtr_speed1;
+		} else if (tid == 4) {
+			sdtr_speed = asc_dvc->sdtr_speed2;
+		} else if (tid == 8) {
+			sdtr_speed = asc_dvc->sdtr_speed3;
+		} else if (tid == 12) {
+			sdtr_speed = asc_dvc->sdtr_speed4;
+		}
+		if (sdtr_speed & ASC_MAX_TID) {
+			asc_dvc->sdtr_able |= (1 << tid);
+		}
+		sdtr_speed >>= 4;
+	}
 
-    /*
-     * Set the host maximum queuing (max. 253, min. 16) and the per device
-     * maximum queuing (max. 63, min. 4).
-     */
-    if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG)
-    {
-        eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
-    } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG)
-    {
-        /* If the value is zero, assume it is uninitialized. */
-        if (eep_config.max_host_qng == 0)
-        {
-            eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
-        } else
-        {
-            eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
-        }
-    }
+	/*
+	 * Set the host maximum queuing (max. 253, min. 16) and the per device
+	 * maximum queuing (max. 63, min. 4).
+	 */
+	if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) {
+		eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+	} else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) {
+		/* If the value is zero, assume it is uninitialized. */
+		if (eep_config.max_host_qng == 0) {
+			eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+		} else {
+			eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+		}
+	}
 
-    if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG)
-    {
-        eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
-    } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG)
-    {
-        /* If the value is zero, assume it is uninitialized. */
-        if (eep_config.max_dvc_qng == 0)
-        {
-            eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
-        } else
-        {
-            eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
-        }
-    }
+	if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) {
+		eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+	} else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) {
+		/* If the value is zero, assume it is uninitialized. */
+		if (eep_config.max_dvc_qng == 0) {
+			eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+		} else {
+			eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+		}
+	}
 
-    /*
-     * If 'max_dvc_qng' is greater than 'max_host_qng', then
-     * set 'max_dvc_qng' to 'max_host_qng'.
-     */
-    if (eep_config.max_dvc_qng > eep_config.max_host_qng)
-    {
-        eep_config.max_dvc_qng = eep_config.max_host_qng;
-    }
+	/*
+	 * If 'max_dvc_qng' is greater than 'max_host_qng', then
+	 * set 'max_dvc_qng' to 'max_host_qng'.
+	 */
+	if (eep_config.max_dvc_qng > eep_config.max_host_qng) {
+		eep_config.max_dvc_qng = eep_config.max_host_qng;
+	}
 
-    /*
-     * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
-     * values based on possibly adjusted EEPROM values.
-     */
-    asc_dvc->max_host_qng = eep_config.max_host_qng;
-    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+	/*
+	 * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
+	 * values based on possibly adjusted EEPROM values.
+	 */
+	asc_dvc->max_host_qng = eep_config.max_host_qng;
+	asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
 
-    /*
-     * If the EEPROM 'termination' field is set to automatic (0), then set
-     * the ASC_DVC_CFG 'termination' field to automatic also.
-     *
-     * If the termination is specified with a non-zero 'termination'
-     * value check that a legal value is set and set the ASC_DVC_CFG
-     * 'termination' field appropriately.
-     */
-    if (eep_config.termination_se == 0)
-    {
-        termination = 0;                         /* auto termination for SE */
-    } else
-    {
-        /* Enable manual control with low off / high off. */
-        if (eep_config.termination_se == 1)
-        {
-            termination = 0;
+	/*
+	 * If the EEPROM 'termination' field is set to automatic (0), then set
+	 * the ASC_DVC_CFG 'termination' field to automatic also.
+	 *
+	 * If the termination is specified with a non-zero 'termination'
+	 * value check that a legal value is set and set the ASC_DVC_CFG
+	 * 'termination' field appropriately.
+	 */
+	if (eep_config.termination_se == 0) {
+		termination = 0;	/* auto termination for SE */
+	} else {
+		/* Enable manual control with low off / high off. */
+		if (eep_config.termination_se == 1) {
+			termination = 0;
 
-        /* Enable manual control with low off / high on. */
-        } else if (eep_config.termination_se == 2)
-        {
-            termination = TERM_SE_HI;
+			/* Enable manual control with low off / high on. */
+		} else if (eep_config.termination_se == 2) {
+			termination = TERM_SE_HI;
 
-        /* Enable manual control with low on / high on. */
-        } else if (eep_config.termination_se == 3)
-        {
-            termination = TERM_SE;
-        } else
-        {
-            /*
-             * The EEPROM 'termination_se' field contains a bad value.
-             * Use automatic termination instead.
-             */
-            termination = 0;
-            warn_code |= ASC_WARN_EEPROM_TERMINATION;
-        }
-    }
+			/* Enable manual control with low on / high on. */
+		} else if (eep_config.termination_se == 3) {
+			termination = TERM_SE;
+		} else {
+			/*
+			 * The EEPROM 'termination_se' field contains a bad value.
+			 * Use automatic termination instead.
+			 */
+			termination = 0;
+			warn_code |= ASC_WARN_EEPROM_TERMINATION;
+		}
+	}
 
-    if (eep_config.termination_lvd == 0)
-    {
-        asc_dvc->cfg->termination = termination; /* auto termination for LVD */
-    } else
-    {
-        /* Enable manual control with low off / high off. */
-        if (eep_config.termination_lvd == 1)
-        {
-            asc_dvc->cfg->termination = termination;
+	if (eep_config.termination_lvd == 0) {
+		asc_dvc->cfg->termination = termination;	/* auto termination for LVD */
+	} else {
+		/* Enable manual control with low off / high off. */
+		if (eep_config.termination_lvd == 1) {
+			asc_dvc->cfg->termination = termination;
 
-        /* Enable manual control with low off / high on. */
-        } else if (eep_config.termination_lvd == 2)
-        {
-            asc_dvc->cfg->termination = termination | TERM_LVD_HI;
+			/* Enable manual control with low off / high on. */
+		} else if (eep_config.termination_lvd == 2) {
+			asc_dvc->cfg->termination = termination | TERM_LVD_HI;
 
-        /* Enable manual control with low on / high on. */
-        } else if (eep_config.termination_lvd == 3)
-        {
-            asc_dvc->cfg->termination =
-                termination | TERM_LVD;
-        } else
-        {
-            /*
-             * The EEPROM 'termination_lvd' field contains a bad value.
-             * Use automatic termination instead.
-             */
-            asc_dvc->cfg->termination = termination;
-            warn_code |= ASC_WARN_EEPROM_TERMINATION;
-        }
-    }
+			/* Enable manual control with low on / high on. */
+		} else if (eep_config.termination_lvd == 3) {
+			asc_dvc->cfg->termination = termination | TERM_LVD;
+		} else {
+			/*
+			 * The EEPROM 'termination_lvd' field contains a bad value.
+			 * Use automatic termination instead.
+			 */
+			asc_dvc->cfg->termination = termination;
+			warn_code |= ASC_WARN_EEPROM_TERMINATION;
+		}
+	}
 
-    return warn_code;
+	return warn_code;
 }
 
 /*
@@ -17049,45 +16733,42 @@
  *
  * Return a checksum based on the EEPROM configuration read.
  */
-STATIC ushort __init
+static ushort __init
 AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
 {
-    ushort              wval, chksum;
-    ushort              *wbuf;
-    int                 eep_addr;
-    ushort              *charfields;
+	ushort wval, chksum;
+	ushort *wbuf;
+	int eep_addr;
+	ushort *charfields;
 
-    charfields = (ushort *) &ADVEEP_3550_Config_Field_IsChar;
-    wbuf = (ushort *) cfg_buf;
-    chksum = 0;
+	charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
+	wbuf = (ushort *)cfg_buf;
+	chksum = 0;
 
-    for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
-         eep_addr < ADV_EEP_DVC_CFG_END;
-         eep_addr++, wbuf++)
-    {
-        wval = AdvReadEEPWord(iop_base, eep_addr);
-        chksum += wval; /* Checksum is calculated from word values. */
-        if (*charfields++) {
-            *wbuf = le16_to_cpu(wval);
-        } else {
-            *wbuf = wval;
-        }
-    }
-    /* Read checksum word. */
-    *wbuf = AdvReadEEPWord(iop_base, eep_addr);
-    wbuf++; charfields++;
+	for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+	     eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
+		wval = AdvReadEEPWord(iop_base, eep_addr);
+		chksum += wval;	/* Checksum is calculated from word values. */
+		if (*charfields++) {
+			*wbuf = le16_to_cpu(wval);
+		} else {
+			*wbuf = wval;
+		}
+	}
+	/* Read checksum word. */
+	*wbuf = AdvReadEEPWord(iop_base, eep_addr);
+	wbuf++;
+	charfields++;
 
-    /* Read rest of EEPROM not covered by the checksum. */
-    for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
-         eep_addr < ADV_EEP_MAX_WORD_ADDR;
-         eep_addr++, wbuf++)
-    {
-        *wbuf = AdvReadEEPWord(iop_base, eep_addr);
-        if (*charfields++) {
-            *wbuf = le16_to_cpu(*wbuf);
-        }
-    }
-    return chksum;
+	/* Read rest of EEPROM not covered by the checksum. */
+	for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+	     eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
+		*wbuf = AdvReadEEPWord(iop_base, eep_addr);
+		if (*charfields++) {
+			*wbuf = le16_to_cpu(*wbuf);
+		}
+	}
+	return chksum;
 }
 
 /*
@@ -17095,46 +16776,42 @@
  *
  * Return a checksum based on the EEPROM configuration read.
  */
-STATIC ushort __init
-AdvGet38C0800EEPConfig(AdvPortAddr iop_base,
-                       ADVEEP_38C0800_CONFIG *cfg_buf)
+static ushort __init
+AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
 {
-    ushort              wval, chksum;
-    ushort              *wbuf;
-    int                 eep_addr;
-    ushort              *charfields;
+	ushort wval, chksum;
+	ushort *wbuf;
+	int eep_addr;
+	ushort *charfields;
 
-    charfields = (ushort *) &ADVEEP_38C0800_Config_Field_IsChar;
-    wbuf = (ushort *) cfg_buf;
-    chksum = 0;
+	charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
+	wbuf = (ushort *)cfg_buf;
+	chksum = 0;
 
-    for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
-         eep_addr < ADV_EEP_DVC_CFG_END;
-         eep_addr++, wbuf++)
-    {
-        wval = AdvReadEEPWord(iop_base, eep_addr);
-        chksum += wval; /* Checksum is calculated from word values. */
-        if (*charfields++) {
-            *wbuf = le16_to_cpu(wval);
-        } else {
-            *wbuf = wval;
-        }
-    }
-    /* Read checksum word. */
-    *wbuf = AdvReadEEPWord(iop_base, eep_addr);
-    wbuf++; charfields++;
+	for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+	     eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
+		wval = AdvReadEEPWord(iop_base, eep_addr);
+		chksum += wval;	/* Checksum is calculated from word values. */
+		if (*charfields++) {
+			*wbuf = le16_to_cpu(wval);
+		} else {
+			*wbuf = wval;
+		}
+	}
+	/* Read checksum word. */
+	*wbuf = AdvReadEEPWord(iop_base, eep_addr);
+	wbuf++;
+	charfields++;
 
-    /* Read rest of EEPROM not covered by the checksum. */
-    for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
-         eep_addr < ADV_EEP_MAX_WORD_ADDR;
-         eep_addr++, wbuf++)
-    {
-        *wbuf = AdvReadEEPWord(iop_base, eep_addr);
-        if (*charfields++) {
-            *wbuf = le16_to_cpu(*wbuf);
-        }
-    }
-    return chksum;
+	/* Read rest of EEPROM not covered by the checksum. */
+	for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+	     eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
+		*wbuf = AdvReadEEPWord(iop_base, eep_addr);
+		if (*charfields++) {
+			*wbuf = le16_to_cpu(*wbuf);
+		}
+	}
+	return chksum;
 }
 
 /*
@@ -17142,81 +16819,74 @@
  *
  * Return a checksum based on the EEPROM configuration read.
  */
-STATIC ushort __init
-AdvGet38C1600EEPConfig(AdvPortAddr iop_base,
-                       ADVEEP_38C1600_CONFIG *cfg_buf)
+static ushort __init
+AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
 {
-    ushort              wval, chksum;
-    ushort              *wbuf;
-    int                 eep_addr;
-    ushort              *charfields;
+	ushort wval, chksum;
+	ushort *wbuf;
+	int eep_addr;
+	ushort *charfields;
 
-    charfields = (ushort*) &ADVEEP_38C1600_Config_Field_IsChar;
-    wbuf = (ushort *) cfg_buf;
-    chksum = 0;
+	charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
+	wbuf = (ushort *)cfg_buf;
+	chksum = 0;
 
-    for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
-         eep_addr < ADV_EEP_DVC_CFG_END;
-         eep_addr++, wbuf++)
-    {
-        wval = AdvReadEEPWord(iop_base, eep_addr);
-        chksum += wval; /* Checksum is calculated from word values. */
-        if (*charfields++) {
-            *wbuf = le16_to_cpu(wval);
-        } else {
-            *wbuf = wval;
-        }
-    }
-    /* Read checksum word. */
-    *wbuf = AdvReadEEPWord(iop_base, eep_addr);
-    wbuf++; charfields++;
+	for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+	     eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) {
+		wval = AdvReadEEPWord(iop_base, eep_addr);
+		chksum += wval;	/* Checksum is calculated from word values. */
+		if (*charfields++) {
+			*wbuf = le16_to_cpu(wval);
+		} else {
+			*wbuf = wval;
+		}
+	}
+	/* Read checksum word. */
+	*wbuf = AdvReadEEPWord(iop_base, eep_addr);
+	wbuf++;
+	charfields++;
 
-    /* Read rest of EEPROM not covered by the checksum. */
-    for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
-         eep_addr < ADV_EEP_MAX_WORD_ADDR;
-         eep_addr++, wbuf++)
-    {
-        *wbuf = AdvReadEEPWord(iop_base, eep_addr);
-        if (*charfields++) {
-            *wbuf = le16_to_cpu(*wbuf);
-        }
-    }
-    return chksum;
+	/* Read rest of EEPROM not covered by the checksum. */
+	for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+	     eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) {
+		*wbuf = AdvReadEEPWord(iop_base, eep_addr);
+		if (*charfields++) {
+			*wbuf = le16_to_cpu(*wbuf);
+		}
+	}
+	return chksum;
 }
 
 /*
  * Read the EEPROM from specified location
  */
-STATIC ushort __init
-AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
+static ushort __init AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
 {
-    AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
-        ASC_EEP_CMD_READ | eep_word_addr);
-    AdvWaitEEPCmd(iop_base);
-    return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
+	AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+			     ASC_EEP_CMD_READ | eep_word_addr);
+	AdvWaitEEPCmd(iop_base);
+	return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
 }
 
 /*
  * Wait for EEPROM command to complete
  */
-STATIC void __init
-AdvWaitEEPCmd(AdvPortAddr iop_base)
+static void __init AdvWaitEEPCmd(AdvPortAddr iop_base)
 {
-    int eep_delay_ms;
+	int eep_delay_ms;
 
-    for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++)
-    {
-        if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE)
-        {
-            break;
-        }
-        DvcSleepMilliSecond(1);
-    }
-    if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) == 0)
-    {
-        ASC_ASSERT(0);
-    }
-    return;
+	for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) {
+		if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) &
+		    ASC_EEP_CMD_DONE) {
+			break;
+		}
+		DvcSleepMilliSecond(1);
+	}
+	if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) ==
+	    0) {
+		ASC_ASSERT(0);
+	}
+	return;
 }
 
 /*
@@ -17225,201 +16895,202 @@
 void __init
 AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
 {
-    ushort *wbuf;
-    ushort addr, chksum;
-    ushort *charfields;
+	ushort *wbuf;
+	ushort addr, chksum;
+	ushort *charfields;
 
-    wbuf = (ushort *) cfg_buf;
-    charfields = (ushort *) &ADVEEP_3550_Config_Field_IsChar;
-    chksum = 0;
+	wbuf = (ushort *)cfg_buf;
+	charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar;
+	chksum = 0;
 
-    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
-    AdvWaitEEPCmd(iop_base);
+	AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+	AdvWaitEEPCmd(iop_base);
 
-    /*
-     * Write EEPROM from word 0 to word 20.
-     */
-    for (addr = ADV_EEP_DVC_CFG_BEGIN;
-         addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++)
-    {
-        ushort word;
+	/*
+	 * Write EEPROM from word 0 to word 20.
+	 */
+	for (addr = ADV_EEP_DVC_CFG_BEGIN;
+	     addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
+		ushort word;
 
-        if (*charfields++) {
-            word = cpu_to_le16(*wbuf);
-        } else {
-            word = *wbuf;
-        }
-        chksum += *wbuf; /* Checksum is calculated from word values. */
-        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
-        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
-        AdvWaitEEPCmd(iop_base);
-        DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
-    }
+		if (*charfields++) {
+			word = cpu_to_le16(*wbuf);
+		} else {
+			word = *wbuf;
+		}
+		chksum += *wbuf;	/* Checksum is calculated from word values. */
+		AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+		AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+				     ASC_EEP_CMD_WRITE | addr);
+		AdvWaitEEPCmd(iop_base);
+		DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
+	}
 
-    /*
-     * Write EEPROM checksum at word 21.
-     */
-    AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
-    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
-    AdvWaitEEPCmd(iop_base);
-    wbuf++; charfields++;
+	/*
+	 * Write EEPROM checksum at word 21.
+	 */
+	AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+	AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+	AdvWaitEEPCmd(iop_base);
+	wbuf++;
+	charfields++;
 
-    /*
-     * Write EEPROM OEM name at words 22 to 29.
-     */
-    for (addr = ADV_EEP_DVC_CTL_BEGIN;
-         addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++)
-    {
-        ushort word;
+	/*
+	 * Write EEPROM OEM name at words 22 to 29.
+	 */
+	for (addr = ADV_EEP_DVC_CTL_BEGIN;
+	     addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
+		ushort word;
 
-        if (*charfields++) {
-            word = cpu_to_le16(*wbuf);
-        } else {
-            word = *wbuf;
-        }
-        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
-        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
-        AdvWaitEEPCmd(iop_base);
-    }
-    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
-    AdvWaitEEPCmd(iop_base);
-    return;
+		if (*charfields++) {
+			word = cpu_to_le16(*wbuf);
+		} else {
+			word = *wbuf;
+		}
+		AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+		AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+				     ASC_EEP_CMD_WRITE | addr);
+		AdvWaitEEPCmd(iop_base);
+	}
+	AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+	AdvWaitEEPCmd(iop_base);
+	return;
 }
 
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
 void __init
-AdvSet38C0800EEPConfig(AdvPortAddr iop_base,
-                       ADVEEP_38C0800_CONFIG *cfg_buf)
+AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf)
 {
-    ushort *wbuf;
-    ushort *charfields;
-    ushort addr, chksum;
+	ushort *wbuf;
+	ushort *charfields;
+	ushort addr, chksum;
 
-    wbuf = (ushort *) cfg_buf;
-    charfields = (ushort *) &ADVEEP_38C0800_Config_Field_IsChar;
-    chksum = 0;
+	wbuf = (ushort *)cfg_buf;
+	charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar;
+	chksum = 0;
 
-    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
-    AdvWaitEEPCmd(iop_base);
+	AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+	AdvWaitEEPCmd(iop_base);
 
-    /*
-     * Write EEPROM from word 0 to word 20.
-     */
-    for (addr = ADV_EEP_DVC_CFG_BEGIN;
-         addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++)
-    {
-        ushort word;
+	/*
+	 * Write EEPROM from word 0 to word 20.
+	 */
+	for (addr = ADV_EEP_DVC_CFG_BEGIN;
+	     addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
+		ushort word;
 
-        if (*charfields++) {
-            word = cpu_to_le16(*wbuf);
-        } else {
-            word = *wbuf;
-        }
-        chksum += *wbuf; /* Checksum is calculated from word values. */
-        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
-        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
-        AdvWaitEEPCmd(iop_base);
-        DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
-    }
+		if (*charfields++) {
+			word = cpu_to_le16(*wbuf);
+		} else {
+			word = *wbuf;
+		}
+		chksum += *wbuf;	/* Checksum is calculated from word values. */
+		AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+		AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+				     ASC_EEP_CMD_WRITE | addr);
+		AdvWaitEEPCmd(iop_base);
+		DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
+	}
 
-    /*
-     * Write EEPROM checksum at word 21.
-     */
-    AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
-    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
-    AdvWaitEEPCmd(iop_base);
-    wbuf++; charfields++;
+	/*
+	 * Write EEPROM checksum at word 21.
+	 */
+	AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+	AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+	AdvWaitEEPCmd(iop_base);
+	wbuf++;
+	charfields++;
 
-    /*
-     * Write EEPROM OEM name at words 22 to 29.
-     */
-    for (addr = ADV_EEP_DVC_CTL_BEGIN;
-         addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++)
-    {
-        ushort word;
+	/*
+	 * Write EEPROM OEM name at words 22 to 29.
+	 */
+	for (addr = ADV_EEP_DVC_CTL_BEGIN;
+	     addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
+		ushort word;
 
-        if (*charfields++) {
-            word = cpu_to_le16(*wbuf);
-        } else {
-            word = *wbuf;
-        }
-        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
-        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
-        AdvWaitEEPCmd(iop_base);
-    }
-    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
-    AdvWaitEEPCmd(iop_base);
-    return;
+		if (*charfields++) {
+			word = cpu_to_le16(*wbuf);
+		} else {
+			word = *wbuf;
+		}
+		AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+		AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+				     ASC_EEP_CMD_WRITE | addr);
+		AdvWaitEEPCmd(iop_base);
+	}
+	AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+	AdvWaitEEPCmd(iop_base);
+	return;
 }
 
 /*
  * Write the EEPROM from 'cfg_buf'.
  */
 void __init
-AdvSet38C1600EEPConfig(AdvPortAddr iop_base,
-                       ADVEEP_38C1600_CONFIG *cfg_buf)
+AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf)
 {
-    ushort              *wbuf;
-    ushort              *charfields;
-    ushort              addr, chksum;
+	ushort *wbuf;
+	ushort *charfields;
+	ushort addr, chksum;
 
-    wbuf = (ushort *) cfg_buf;
-    charfields = (ushort *) &ADVEEP_38C1600_Config_Field_IsChar;
-    chksum = 0;
+	wbuf = (ushort *)cfg_buf;
+	charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar;
+	chksum = 0;
 
-    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
-    AdvWaitEEPCmd(iop_base);
+	AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+	AdvWaitEEPCmd(iop_base);
 
-    /*
-     * Write EEPROM from word 0 to word 20.
-     */
-    for (addr = ADV_EEP_DVC_CFG_BEGIN;
-         addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++)
-    {
-        ushort word;
+	/*
+	 * Write EEPROM from word 0 to word 20.
+	 */
+	for (addr = ADV_EEP_DVC_CFG_BEGIN;
+	     addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) {
+		ushort word;
 
-        if (*charfields++) {
-            word = cpu_to_le16(*wbuf);
-        } else {
-            word = *wbuf;
-        }
-        chksum += *wbuf; /* Checksum is calculated from word values. */
-        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
-        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
-        AdvWaitEEPCmd(iop_base);
-        DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
-    }
+		if (*charfields++) {
+			word = cpu_to_le16(*wbuf);
+		} else {
+			word = *wbuf;
+		}
+		chksum += *wbuf;	/* Checksum is calculated from word values. */
+		AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+		AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+				     ASC_EEP_CMD_WRITE | addr);
+		AdvWaitEEPCmd(iop_base);
+		DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
+	}
 
-    /*
-     * Write EEPROM checksum at word 21.
-     */
-    AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
-    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
-    AdvWaitEEPCmd(iop_base);
-    wbuf++; charfields++;
+	/*
+	 * Write EEPROM checksum at word 21.
+	 */
+	AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+	AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+	AdvWaitEEPCmd(iop_base);
+	wbuf++;
+	charfields++;
 
-    /*
-     * Write EEPROM OEM name at words 22 to 29.
-     */
-    for (addr = ADV_EEP_DVC_CTL_BEGIN;
-         addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++)
-    {
-        ushort word;
+	/*
+	 * Write EEPROM OEM name at words 22 to 29.
+	 */
+	for (addr = ADV_EEP_DVC_CTL_BEGIN;
+	     addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) {
+		ushort word;
 
-        if (*charfields++) {
-            word = cpu_to_le16(*wbuf);
-        } else {
-            word = *wbuf;
-        }
-        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
-        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
-        AdvWaitEEPCmd(iop_base);
-    }
-    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
-    AdvWaitEEPCmd(iop_base);
-    return;
+		if (*charfields++) {
+			word = cpu_to_le16(*wbuf);
+		} else {
+			word = *wbuf;
+		}
+		AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+		AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+				     ASC_EEP_CMD_WRITE | addr);
+		AdvWaitEEPCmd(iop_base);
+	}
+	AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+	AdvWaitEEPCmd(iop_base);
+	return;
 }
 
 /* a_advlib.c */
@@ -17444,126 +17115,120 @@
  *      ADV_ERROR(-1) -  Invalid ADV_SCSI_REQ_Q request structure
  *                       host IC error.
  */
-STATIC int
-AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc,
-                ADV_SCSI_REQ_Q *scsiq)
+static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
 {
-    ulong                  last_int_level;
-    AdvPortAddr            iop_base;
-    ADV_DCNT               req_size;
-    ADV_PADDR              req_paddr;
-    ADV_CARR_T             *new_carrp;
+	ulong last_int_level;
+	AdvPortAddr iop_base;
+	ADV_DCNT req_size;
+	ADV_PADDR req_paddr;
+	ADV_CARR_T *new_carrp;
 
-    ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
+	ASC_ASSERT(scsiq != NULL);	/* 'scsiq' should never be NULL. */
 
-    /*
-     * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
-     */
-    if (scsiq->target_id > ADV_MAX_TID)
-    {
-        scsiq->host_status = QHSTA_M_INVALID_DEVICE;
-        scsiq->done_status = QD_WITH_ERROR;
-        return ADV_ERROR;
-    }
+	/*
+	 * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
+	 */
+	if (scsiq->target_id > ADV_MAX_TID) {
+		scsiq->host_status = QHSTA_M_INVALID_DEVICE;
+		scsiq->done_status = QD_WITH_ERROR;
+		return ADV_ERROR;
+	}
 
-    iop_base = asc_dvc->iop_base;
+	iop_base = asc_dvc->iop_base;
 
-    last_int_level = DvcEnterCritical();
+	last_int_level = DvcEnterCritical();
 
-    /*
-     * Allocate a carrier ensuring at least one carrier always
-     * remains on the freelist and initialize fields.
-     */
-    if ((new_carrp = asc_dvc->carr_freelist) == NULL)
-    {
-       DvcLeaveCritical(last_int_level);
-       return ADV_BUSY;
-    }
-    asc_dvc->carr_freelist = (ADV_CARR_T *)
-        ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
-    asc_dvc->carr_pending_cnt++;
+	/*
+	 * Allocate a carrier ensuring at least one carrier always
+	 * remains on the freelist and initialize fields.
+	 */
+	if ((new_carrp = asc_dvc->carr_freelist) == NULL) {
+		DvcLeaveCritical(last_int_level);
+		return ADV_BUSY;
+	}
+	asc_dvc->carr_freelist = (ADV_CARR_T *)
+	    ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
+	asc_dvc->carr_pending_cnt++;
 
-    /*
-     * Set the carrier to be a stopper by setting 'next_vpa'
-     * to the stopper value. The current stopper will be changed
-     * below to point to the new stopper.
-     */
-    new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+	/*
+	 * Set the carrier to be a stopper by setting 'next_vpa'
+	 * to the stopper value. The current stopper will be changed
+	 * below to point to the new stopper.
+	 */
+	new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
 
-    /*
-     * Clear the ADV_SCSI_REQ_Q done flag.
-     */
-    scsiq->a_flag &= ~ADV_SCSIQ_DONE;
+	/*
+	 * Clear the ADV_SCSI_REQ_Q done flag.
+	 */
+	scsiq->a_flag &= ~ADV_SCSIQ_DONE;
 
-    req_size = sizeof(ADV_SCSI_REQ_Q);
-    req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *) scsiq,
-        (ADV_SDCNT *) &req_size, ADV_IS_SCSIQ_FLAG);
+	req_size = sizeof(ADV_SCSI_REQ_Q);
+	req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *)scsiq,
+				  (ADV_SDCNT *)&req_size, ADV_IS_SCSIQ_FLAG);
 
-    ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
-    ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
+	ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
+	ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
 
-    /* Wait for assertion before making little-endian */
-    req_paddr = cpu_to_le32(req_paddr);
+	/* Wait for assertion before making little-endian */
+	req_paddr = cpu_to_le32(req_paddr);
 
-    /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
-    scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
-    scsiq->scsiq_rptr = req_paddr;
+	/* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
+	scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
+	scsiq->scsiq_rptr = req_paddr;
 
-    scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
-    /*
-     * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
-     * order during initialization.
-     */
-    scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
+	scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
+	/*
+	 * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
+	 * order during initialization.
+	 */
+	scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
 
-   /*
-    * Use the current stopper to send the ADV_SCSI_REQ_Q command to
-    * the microcode. The newly allocated stopper will become the new
-    * stopper.
-    */
-    asc_dvc->icq_sp->areq_vpa = req_paddr;
+	/*
+	 * Use the current stopper to send the ADV_SCSI_REQ_Q command to
+	 * the microcode. The newly allocated stopper will become the new
+	 * stopper.
+	 */
+	asc_dvc->icq_sp->areq_vpa = req_paddr;
 
-    /*
-     * Set the 'next_vpa' pointer for the old stopper to be the
-     * physical address of the new stopper. The RISC can only
-     * follow physical addresses.
-     */
-    asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
+	/*
+	 * Set the 'next_vpa' pointer for the old stopper to be the
+	 * physical address of the new stopper. The RISC can only
+	 * follow physical addresses.
+	 */
+	asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
 
-    /*
-     * Set the host adapter stopper pointer to point to the new carrier.
-     */
-    asc_dvc->icq_sp = new_carrp;
+	/*
+	 * Set the host adapter stopper pointer to point to the new carrier.
+	 */
+	asc_dvc->icq_sp = new_carrp;
 
-    if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
-        asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
-    {
-        /*
-         * Tickle the RISC to tell it to read its Command Queue Head pointer.
-         */
-        AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
-        if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
-        {
-            /*
-             * Clear the tickle value. In the ASC-3550 the RISC flag
-             * command 'clr_tickle_a' does not work unless the host
-             * value is cleared.
-             */
-            AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
-        }
-    } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
-    {
-        /*
-         * Notify the RISC a carrier is ready by writing the physical
-         * address of the new carrier stopper to the COMMA register.
-         */
-        AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
-                le32_to_cpu(new_carrp->carr_pa));
-    }
+	if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
+	    asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+		/*
+		 * Tickle the RISC to tell it to read its Command Queue Head pointer.
+		 */
+		AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
+		if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
+			/*
+			 * Clear the tickle value. In the ASC-3550 the RISC flag
+			 * command 'clr_tickle_a' does not work unless the host
+			 * value is cleared.
+			 */
+			AdvWriteByteRegister(iop_base, IOPB_TICKLE,
+					     ADV_TICKLE_NOP);
+		}
+	} else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+		/*
+		 * Notify the RISC a carrier is ready by writing the physical
+		 * address of the new carrier stopper to the COMMA register.
+		 */
+		AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
+				      le32_to_cpu(new_carrp->carr_pa));
+	}
 
-    DvcLeaveCritical(last_int_level);
+	DvcLeaveCritical(last_int_level);
 
-    return ADV_SUCCESS;
+	return ADV_SUCCESS;
 }
 
 /*
@@ -17575,42 +17240,39 @@
  *      ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
  *                      may be hung which requires driver recovery.
  */
-STATIC int
-AdvResetSB(ADV_DVC_VAR *asc_dvc)
+static int AdvResetSB(ADV_DVC_VAR *asc_dvc)
 {
-    int         status;
+	int status;
 
-    /*
-     * Send the SCSI Bus Reset idle start idle command which asserts
-     * the SCSI Bus Reset signal.
-     */
-    status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET_START, 0L);
-    if (status != ADV_TRUE)
-    {
-        return status;
-    }
+	/*
+	 * Send the SCSI Bus Reset idle start idle command which asserts
+	 * the SCSI Bus Reset signal.
+	 */
+	status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L);
+	if (status != ADV_TRUE) {
+		return status;
+	}
 
-    /*
-     * Delay for the specified SCSI Bus Reset hold time.
-     *
-     * The hold time delay is done on the host because the RISC has no
-     * microsecond accurate timer.
-     */
-    DvcDelayMicroSecond(asc_dvc, (ushort) ASC_SCSI_RESET_HOLD_TIME_US);
+	/*
+	 * Delay for the specified SCSI Bus Reset hold time.
+	 *
+	 * The hold time delay is done on the host because the RISC has no
+	 * microsecond accurate timer.
+	 */
+	DvcDelayMicroSecond(asc_dvc, (ushort)ASC_SCSI_RESET_HOLD_TIME_US);
 
-    /*
-     * Send the SCSI Bus Reset end idle command which de-asserts
-     * the SCSI Bus Reset signal and purges any pending requests.
-     */
-    status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET_END, 0L);
-    if (status != ADV_TRUE)
-    {
-        return status;
-    }
+	/*
+	 * Send the SCSI Bus Reset end idle command which de-asserts
+	 * the SCSI Bus Reset signal and purges any pending requests.
+	 */
+	status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L);
+	if (status != ADV_TRUE) {
+		return status;
+	}
 
-    DvcSleepMilliSecond((ADV_DCNT) asc_dvc->scsi_reset_wait * 1000);
+	DvcSleepMilliSecond((ADV_DCNT)asc_dvc->scsi_reset_wait * 1000);
 
-    return status;
+	return status;
 }
 
 /*
@@ -17620,99 +17282,89 @@
  *      ADV_TRUE(1) -   Chip re-initialization and SCSI Bus Reset successful.
  *      ADV_FALSE(0) -  Chip re-initialization and SCSI Bus Reset failure.
  */
-STATIC int
-AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
+static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
 {
-    int         status;
-    ushort      wdtr_able, sdtr_able, tagqng_able;
-    ushort      ppr_able = 0;
-    uchar       tid, max_cmd[ADV_MAX_TID + 1];
-    AdvPortAddr iop_base;
-    ushort      bios_sig;
+	int status;
+	ushort wdtr_able, sdtr_able, tagqng_able;
+	ushort ppr_able = 0;
+	uchar tid, max_cmd[ADV_MAX_TID + 1];
+	AdvPortAddr iop_base;
+	ushort bios_sig;
 
-    iop_base = asc_dvc->iop_base;
+	iop_base = asc_dvc->iop_base;
 
-    /*
-     * Save current per TID negotiated values.
-     */
-    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
-    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-    if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
-    {
-        AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
-    }
-    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
-    for (tid = 0; tid <= ADV_MAX_TID; tid++)
-    {
-        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
-            max_cmd[tid]);
-    }
+	/*
+	 * Save current per TID negotiated values.
+	 */
+	AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+	AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+	if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+		AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+	}
+	AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+	for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+		AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+				max_cmd[tid]);
+	}
 
-    /*
-     * Force the AdvInitAsc3550/38C0800Driver() function to
-     * perform a SCSI Bus Reset by clearing the BIOS signature word.
-     * The initialization functions assumes a SCSI Bus Reset is not
-     * needed if the BIOS signature word is present.
-     */
-    AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
-    AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
+	/*
+	 * Force the AdvInitAsc3550/38C0800Driver() function to
+	 * perform a SCSI Bus Reset by clearing the BIOS signature word.
+	 * The initialization functions assumes a SCSI Bus Reset is not
+	 * needed if the BIOS signature word is present.
+	 */
+	AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+	AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
 
-    /*
-     * Stop chip and reset it.
-     */
-    AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
-    AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
-    DvcSleepMilliSecond(100);
-    AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_WR_IO_REG);
+	/*
+	 * Stop chip and reset it.
+	 */
+	AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
+	AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
+	DvcSleepMilliSecond(100);
+	AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+			     ADV_CTRL_REG_CMD_WR_IO_REG);
 
-    /*
-     * Reset Adv Library error code, if any, and try
-     * re-initializing the chip.
-     */
-    asc_dvc->err_code = 0;
-    if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
-    {
-        status = AdvInitAsc38C1600Driver(asc_dvc);
-    }
-    else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
-    {
-        status = AdvInitAsc38C0800Driver(asc_dvc);
-    } else
-    {
-        status = AdvInitAsc3550Driver(asc_dvc);
-    }
+	/*
+	 * Reset Adv Library error code, if any, and try
+	 * re-initializing the chip.
+	 */
+	asc_dvc->err_code = 0;
+	if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+		status = AdvInitAsc38C1600Driver(asc_dvc);
+	} else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+		status = AdvInitAsc38C0800Driver(asc_dvc);
+	} else {
+		status = AdvInitAsc3550Driver(asc_dvc);
+	}
 
-    /* Translate initialization return value to status value. */
-    if (status == 0)
-    {
-        status = ADV_TRUE;
-    } else
-    {
-        status = ADV_FALSE;
-    }
+	/* Translate initialization return value to status value. */
+	if (status == 0) {
+		status = ADV_TRUE;
+	} else {
+		status = ADV_FALSE;
+	}
 
-    /*
-     * Restore the BIOS signature word.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+	/*
+	 * Restore the BIOS signature word.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
 
-    /*
-     * Restore per TID negotiated values.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
-    AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
-    if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
-    {
-        AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
-    }
-    AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
-    for (tid = 0; tid <= ADV_MAX_TID; tid++)
-    {
-        AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
-            max_cmd[tid]);
-    }
+	/*
+	 * Restore per TID negotiated values.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+	AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+	if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) {
+		AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+	}
+	AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+	for (tid = 0; tid <= ADV_MAX_TID; tid++) {
+		AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+				 max_cmd[tid]);
+	}
 
-    return status;
+	return status;
 }
 
 /*
@@ -17734,158 +17386,151 @@
  *   ADV_TRUE(1) - interrupt was pending
  *   ADV_FALSE(0) - no interrupt was pending
  */
-STATIC int
-AdvISR(ADV_DVC_VAR *asc_dvc)
+static int AdvISR(ADV_DVC_VAR *asc_dvc)
 {
-    AdvPortAddr                 iop_base;
-    uchar                       int_stat;
-    ushort                      target_bit;
-    ADV_CARR_T                  *free_carrp;
-    ADV_VADDR                   irq_next_vpa;
-    int                         flags;
-    ADV_SCSI_REQ_Q              *scsiq;
+	AdvPortAddr iop_base;
+	uchar int_stat;
+	ushort target_bit;
+	ADV_CARR_T *free_carrp;
+	ADV_VADDR irq_next_vpa;
+	int flags;
+	ADV_SCSI_REQ_Q *scsiq;
 
-    flags = DvcEnterCritical();
+	flags = DvcEnterCritical();
 
-    iop_base = asc_dvc->iop_base;
+	iop_base = asc_dvc->iop_base;
 
-    /* Reading the register clears the interrupt. */
-    int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
+	/* Reading the register clears the interrupt. */
+	int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
 
-    if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
-         ADV_INTR_STATUS_INTRC)) == 0)
-    {
-        DvcLeaveCritical(flags);
-        return ADV_FALSE;
-    }
+	if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
+			 ADV_INTR_STATUS_INTRC)) == 0) {
+		DvcLeaveCritical(flags);
+		return ADV_FALSE;
+	}
 
-    /*
-     * Notify the driver of an asynchronous microcode condition by
-     * calling the ADV_DVC_VAR.async_callback function. The function
-     * is passed the microcode ASC_MC_INTRB_CODE byte value.
-     */
-    if (int_stat & ADV_INTR_STATUS_INTRB)
-    {
-        uchar intrb_code;
+	/*
+	 * Notify the driver of an asynchronous microcode condition by
+	 * calling the ADV_DVC_VAR.async_callback function. The function
+	 * is passed the microcode ASC_MC_INTRB_CODE byte value.
+	 */
+	if (int_stat & ADV_INTR_STATUS_INTRB) {
+		uchar intrb_code;
 
-        AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
+		AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
 
-        if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
-            asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
-        {
-            if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
-                asc_dvc->carr_pending_cnt != 0)
-            {
-                AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
-                if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
-                {
-                    AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
-                }
-            }
-        }
+		if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
+		    asc_dvc->chip_type == ADV_CHIP_ASC38C0800) {
+			if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
+			    asc_dvc->carr_pending_cnt != 0) {
+				AdvWriteByteRegister(iop_base, IOPB_TICKLE,
+						     ADV_TICKLE_A);
+				if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
+					AdvWriteByteRegister(iop_base,
+							     IOPB_TICKLE,
+							     ADV_TICKLE_NOP);
+				}
+			}
+		}
 
-        if (asc_dvc->async_callback != 0)
-        {
-            (*asc_dvc->async_callback)(asc_dvc, intrb_code);
-        }
-    }
+		if (asc_dvc->async_callback != 0) {
+			(*asc_dvc->async_callback) (asc_dvc, intrb_code);
+		}
+	}
 
-    /*
-     * Check if the IRQ stopper carrier contains a completed request.
-     */
-    while (((irq_next_vpa =
-             le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0)
-    {
-        /*
-         * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
-         * The RISC will have set 'areq_vpa' to a virtual address.
-         *
-         * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
-         * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
-         * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
-         * in AdvExeScsiQueue().
-         */
-        scsiq = (ADV_SCSI_REQ_Q *)
-            ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
+	/*
+	 * Check if the IRQ stopper carrier contains a completed request.
+	 */
+	while (((irq_next_vpa =
+		 le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) {
+		/*
+		 * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
+		 * The RISC will have set 'areq_vpa' to a virtual address.
+		 *
+		 * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
+		 * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
+		 * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
+		 * in AdvExeScsiQueue().
+		 */
+		scsiq = (ADV_SCSI_REQ_Q *)
+		    ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
 
-        /*
-         * Request finished with good status and the queue was not
-         * DMAed to host memory by the firmware. Set all status fields
-         * to indicate good status.
-         */
-        if ((irq_next_vpa & ASC_RQ_GOOD) != 0)
-        {
-            scsiq->done_status = QD_NO_ERROR;
-            scsiq->host_status = scsiq->scsi_status = 0;
-            scsiq->data_cnt = 0L;
-        }
+		/*
+		 * Request finished with good status and the queue was not
+		 * DMAed to host memory by the firmware. Set all status fields
+		 * to indicate good status.
+		 */
+		if ((irq_next_vpa & ASC_RQ_GOOD) != 0) {
+			scsiq->done_status = QD_NO_ERROR;
+			scsiq->host_status = scsiq->scsi_status = 0;
+			scsiq->data_cnt = 0L;
+		}
 
-        /*
-         * Advance the stopper pointer to the next carrier
-         * ignoring the lower four bits. Free the previous
-         * stopper carrier.
-         */
-        free_carrp = asc_dvc->irq_sp;
-        asc_dvc->irq_sp = (ADV_CARR_T *)
-            ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
+		/*
+		 * Advance the stopper pointer to the next carrier
+		 * ignoring the lower four bits. Free the previous
+		 * stopper carrier.
+		 */
+		free_carrp = asc_dvc->irq_sp;
+		asc_dvc->irq_sp = (ADV_CARR_T *)
+		    ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
 
-        free_carrp->next_vpa =
-                cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
-        asc_dvc->carr_freelist = free_carrp;
-        asc_dvc->carr_pending_cnt--;
+		free_carrp->next_vpa =
+		    cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+		asc_dvc->carr_freelist = free_carrp;
+		asc_dvc->carr_pending_cnt--;
 
-        ASC_ASSERT(scsiq != NULL);
-        target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
+		ASC_ASSERT(scsiq != NULL);
+		target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
 
-        /*
-         * Clear request microcode control flag.
-         */
-        scsiq->cntl = 0;
+		/*
+		 * Clear request microcode control flag.
+		 */
+		scsiq->cntl = 0;
 
-        /*
-         * If the command that completed was a SCSI INQUIRY and
-         * LUN 0 was sent the command, then process the INQUIRY
-         * command information for the device.
-         *
-         * Note: If data returned were either VPD or CmdDt data,
-         * don't process the INQUIRY command information for
-         * the device, otherwise may erroneously set *_able bits.
-         */
-        if (scsiq->done_status == QD_NO_ERROR &&
-            scsiq->cdb[0] == INQUIRY &&
-            scsiq->target_lun == 0 &&
-            (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT)
-                == ADV_INQ_RTN_STD_INQUIRY_DATA)
-        {
-            AdvInquiryHandling(asc_dvc, scsiq);
-        }
+		/*
+		 * If the command that completed was a SCSI INQUIRY and
+		 * LUN 0 was sent the command, then process the INQUIRY
+		 * command information for the device.
+		 *
+		 * Note: If data returned were either VPD or CmdDt data,
+		 * don't process the INQUIRY command information for
+		 * the device, otherwise may erroneously set *_able bits.
+		 */
+		if (scsiq->done_status == QD_NO_ERROR &&
+		    scsiq->cdb[0] == INQUIRY &&
+		    scsiq->target_lun == 0 &&
+		    (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT)
+		    == ADV_INQ_RTN_STD_INQUIRY_DATA) {
+			AdvInquiryHandling(asc_dvc, scsiq);
+		}
 
-        /*
-         * Notify the driver of the completed request by passing
-         * the ADV_SCSI_REQ_Q pointer to its callback function.
-         */
-        scsiq->a_flag |= ADV_SCSIQ_DONE;
-        (*asc_dvc->isr_callback)(asc_dvc, scsiq);
-        /*
-         * Note: After the driver callback function is called, 'scsiq'
-         * can no longer be referenced.
-         *
-         * Fall through and continue processing other completed
-         * requests...
-         */
+		/*
+		 * Notify the driver of the completed request by passing
+		 * the ADV_SCSI_REQ_Q pointer to its callback function.
+		 */
+		scsiq->a_flag |= ADV_SCSIQ_DONE;
+		(*asc_dvc->isr_callback) (asc_dvc, scsiq);
+		/*
+		 * Note: After the driver callback function is called, 'scsiq'
+		 * can no longer be referenced.
+		 *
+		 * Fall through and continue processing other completed
+		 * requests...
+		 */
 
-        /*
-         * Disable interrupts again in case the driver inadvertently
-         * enabled interrupts in its callback function.
-         *
-         * The DvcEnterCritical() return value is ignored, because
-         * the 'flags' saved when AdvISR() was first entered will be
-         * used to restore the interrupt flag on exit.
-         */
-        (void) DvcEnterCritical();
-    }
-    DvcLeaveCritical(flags);
-    return ADV_TRUE;
+		/*
+		 * Disable interrupts again in case the driver inadvertently
+		 * enabled interrupts in its callback function.
+		 *
+		 * The DvcEnterCritical() return value is ignored, because
+		 * the 'flags' saved when AdvISR() was first entered will be
+		 * used to restore the interrupt flag on exit.
+		 */
+		(void)DvcEnterCritical();
+	}
+	DvcLeaveCritical(flags);
+	return ADV_TRUE;
 }
 
 /*
@@ -17902,71 +17547,67 @@
  *   ADV_FALSE - command failed
  *   ADV_ERROR - command timed out
  */
-STATIC int
+static int
 AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
-               ushort idle_cmd,
-               ADV_DCNT idle_cmd_parameter)
+	       ushort idle_cmd, ADV_DCNT idle_cmd_parameter)
 {
-    ulong       last_int_level;
-    int         result;
-    ADV_DCNT    i, j;
-    AdvPortAddr iop_base;
+	ulong last_int_level;
+	int result;
+	ADV_DCNT i, j;
+	AdvPortAddr iop_base;
 
-    last_int_level = DvcEnterCritical();
+	last_int_level = DvcEnterCritical();
 
-    iop_base = asc_dvc->iop_base;
+	iop_base = asc_dvc->iop_base;
 
-    /*
-     * Clear the idle command status which is set by the microcode
-     * to a non-zero value to indicate when the command is completed.
-     * The non-zero result is one of the IDLE_CMD_STATUS_* values
-     * defined in a_advlib.h.
-     */
-    AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort) 0);
+	/*
+	 * Clear the idle command status which is set by the microcode
+	 * to a non-zero value to indicate when the command is completed.
+	 * The non-zero result is one of the IDLE_CMD_STATUS_* values
+	 * defined in a_advlib.h.
+	 */
+	AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0);
 
-    /*
-     * Write the idle command value after the idle command parameter
-     * has been written to avoid a race condition. If the order is not
-     * followed, the microcode may process the idle command before the
-     * parameters have been written to LRAM.
-     */
-    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
-        cpu_to_le32(idle_cmd_parameter));
-    AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
+	/*
+	 * Write the idle command value after the idle command parameter
+	 * has been written to avoid a race condition. If the order is not
+	 * followed, the microcode may process the idle command before the
+	 * parameters have been written to LRAM.
+	 */
+	AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
+				cpu_to_le32(idle_cmd_parameter));
+	AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
 
-    /*
-     * Tickle the RISC to tell it to process the idle command.
-     */
-    AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
-    if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
-    {
-        /*
-         * Clear the tickle value. In the ASC-3550 the RISC flag
-         * command 'clr_tickle_b' does not work unless the host
-         * value is cleared.
-         */
-        AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
-    }
+	/*
+	 * Tickle the RISC to tell it to process the idle command.
+	 */
+	AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
+	if (asc_dvc->chip_type == ADV_CHIP_ASC3550) {
+		/*
+		 * Clear the tickle value. In the ASC-3550 the RISC flag
+		 * command 'clr_tickle_b' does not work unless the host
+		 * value is cleared.
+		 */
+		AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
+	}
 
-    /* Wait for up to 100 millisecond for the idle command to timeout. */
-    for (i = 0; i < SCSI_WAIT_100_MSEC; i++)
-    {
-        /* Poll once each microsecond for command completion. */
-        for (j = 0; j < SCSI_US_PER_MSEC; j++)
-        {
-            AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, result);
-            if (result != 0)
-            {
-                DvcLeaveCritical(last_int_level);
-                return result;
-            }
-            DvcDelayMicroSecond(asc_dvc, (ushort) 1);
-        }
-    }
+	/* Wait for up to 100 millisecond for the idle command to timeout. */
+	for (i = 0; i < SCSI_WAIT_100_MSEC; i++) {
+		/* Poll once each microsecond for command completion. */
+		for (j = 0; j < SCSI_US_PER_MSEC; j++) {
+			AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS,
+					result);
+			if (result != 0) {
+				DvcLeaveCritical(last_int_level);
+				return result;
+			}
+			DvcDelayMicroSecond(asc_dvc, (ushort)1);
+		}
+	}
 
-    ASC_ASSERT(0); /* The idle command should never timeout. */
-    DvcLeaveCritical(last_int_level);
-    return ADV_ERROR;
+	ASC_ASSERT(0);		/* The idle command should never timeout. */
+	DvcLeaveCritical(last_int_level);
+	return ADV_ERROR;
 }
 
 /*
@@ -17976,179 +17617,1415 @@
  * microcode operating variables that affect WDTR, SDTR, and Tag
  * Queuing.
  */
-STATIC void
-AdvInquiryHandling(
-    ADV_DVC_VAR                 *asc_dvc,
-    ADV_SCSI_REQ_Q              *scsiq)
+static void AdvInquiryHandling(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq)
 {
-    AdvPortAddr                 iop_base;
-    uchar                       tid;
-    ADV_SCSI_INQUIRY            *inq;
-    ushort                      tidmask;
-    ushort                      cfg_word;
+	AdvPortAddr iop_base;
+	uchar tid;
+	ADV_SCSI_INQUIRY *inq;
+	ushort tidmask;
+	ushort cfg_word;
 
-    /*
-     * AdvInquiryHandling() requires up to INQUIRY information Byte 7
-     * to be available.
-     *
-     * If less than 8 bytes of INQUIRY information were requested or less
-     * than 8 bytes were transferred, then return. cdb[4] is the request
-     * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
-     * microcode to the transfer residual count.
-     */
+	/*
+	 * AdvInquiryHandling() requires up to INQUIRY information Byte 7
+	 * to be available.
+	 *
+	 * If less than 8 bytes of INQUIRY information were requested or less
+	 * than 8 bytes were transferred, then return. cdb[4] is the request
+	 * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
+	 * microcode to the transfer residual count.
+	 */
 
-    if (scsiq->cdb[4] < 8 ||
-        (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8)
-    {
-        return;
-    }
+	if (scsiq->cdb[4] < 8 ||
+	    (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8) {
+		return;
+	}
 
-    iop_base = asc_dvc->iop_base;
-    tid = scsiq->target_id;
+	iop_base = asc_dvc->iop_base;
+	tid = scsiq->target_id;
 
-    inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr;
+	inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr;
 
-    /*
-     * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
-     */
-    if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2)
-    {
-        return;
-    } else
-    {
-        /*
-         * INQUIRY Byte 7 Handling
-         *
-         * Use a device's INQUIRY byte 7 to determine whether it
-         * supports WDTR, SDTR, and Tag Queuing. If the feature
-         * is enabled in the EEPROM and the device supports the
-         * feature, then enable it in the microcode.
-         */
+	/*
+	 * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
+	 */
+	if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2) {
+		return;
+	} else {
+		/*
+		 * INQUIRY Byte 7 Handling
+		 *
+		 * Use a device's INQUIRY byte 7 to determine whether it
+		 * supports WDTR, SDTR, and Tag Queuing. If the feature
+		 * is enabled in the EEPROM and the device supports the
+		 * feature, then enable it in the microcode.
+		 */
 
-        tidmask = ADV_TID_TO_TIDMASK(tid);
+		tidmask = ADV_TID_TO_TIDMASK(tid);
 
-        /*
-         * Wide Transfers
-         *
-         * If the EEPROM enabled WDTR for the device and the device
-         * supports wide bus (16 bit) transfers, then turn on the
-         * device's 'wdtr_able' bit and write the new value to the
-         * microcode.
-         */
-        if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq))
-        {
-            AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
-            if ((cfg_word & tidmask) == 0)
-            {
-                cfg_word |= tidmask;
-                AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
+		/*
+		 * Wide Transfers
+		 *
+		 * If the EEPROM enabled WDTR for the device and the device
+		 * supports wide bus (16 bit) transfers, then turn on the
+		 * device's 'wdtr_able' bit and write the new value to the
+		 * microcode.
+		 */
+		if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq)) {
+			AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
+			if ((cfg_word & tidmask) == 0) {
+				cfg_word |= tidmask;
+				AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE,
+						 cfg_word);
 
-                /*
-                 * Clear the microcode "SDTR negotiation" and "WDTR
-                 * negotiation" done indicators for the target to cause
-                 * it to negotiate with the new setting set above.
-                 * WDTR when accepted causes the target to enter
-                 * asynchronous mode, so SDTR must be negotiated.
-                 */
-                AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
-                cfg_word &= ~tidmask;
-                AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
-                AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
-                cfg_word &= ~tidmask;
-                AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
-            }
-        }
+				/*
+				 * Clear the microcode "SDTR negotiation" and "WDTR
+				 * negotiation" done indicators for the target to cause
+				 * it to negotiate with the new setting set above.
+				 * WDTR when accepted causes the target to enter
+				 * asynchronous mode, so SDTR must be negotiated.
+				 */
+				AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
+						cfg_word);
+				cfg_word &= ~tidmask;
+				AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
+						 cfg_word);
+				AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE,
+						cfg_word);
+				cfg_word &= ~tidmask;
+				AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE,
+						 cfg_word);
+			}
+		}
 
-        /*
-         * Synchronous Transfers
-         *
-         * If the EEPROM enabled SDTR for the device and the device
-         * supports synchronous transfers, then turn on the device's
-         * 'sdtr_able' bit. Write the new value to the microcode.
-         */
-        if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq))
-        {
-            AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
-            if ((cfg_word & tidmask) == 0)
-            {
-                cfg_word |= tidmask;
-                AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
+		/*
+		 * Synchronous Transfers
+		 *
+		 * If the EEPROM enabled SDTR for the device and the device
+		 * supports synchronous transfers, then turn on the device's
+		 * 'sdtr_able' bit. Write the new value to the microcode.
+		 */
+		if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq)) {
+			AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
+			if ((cfg_word & tidmask) == 0) {
+				cfg_word |= tidmask;
+				AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE,
+						 cfg_word);
 
-                /*
-                 * Clear the microcode "SDTR negotiation" done indicator
-                 * for the target to cause it to negotiate with the new
-                 * setting set above.
-                 */
-                AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
-                cfg_word &= ~tidmask;
-                AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
-            }
-        }
-        /*
-         * If the Inquiry data included enough space for the SPI-3
-         * Clocking field, then check if DT mode is supported.
-         */
-        if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 &&
-            (scsiq->cdb[4] >= 57 ||
-            (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57))
-        {
-            /*
-             * PPR (Parallel Protocol Request) Capable
-             *
-             * If the device supports DT mode, then it must be PPR capable.
-             * The PPR message will be used in place of the SDTR and WDTR
-             * messages to negotiate synchronous speed and offset, transfer
-             * width, and protocol options.
-             */
-            if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY)
-            {
-                AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, asc_dvc->ppr_able);
-                asc_dvc->ppr_able |= tidmask;
-                AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, asc_dvc->ppr_able);
-            }
-        }
+				/*
+				 * Clear the microcode "SDTR negotiation" done indicator
+				 * for the target to cause it to negotiate with the new
+				 * setting set above.
+				 */
+				AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE,
+						cfg_word);
+				cfg_word &= ~tidmask;
+				AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE,
+						 cfg_word);
+			}
+		}
+		/*
+		 * If the Inquiry data included enough space for the SPI-3
+		 * Clocking field, then check if DT mode is supported.
+		 */
+		if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 &&
+		    (scsiq->cdb[4] >= 57 ||
+		     (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57)) {
+			/*
+			 * PPR (Parallel Protocol Request) Capable
+			 *
+			 * If the device supports DT mode, then it must be PPR capable.
+			 * The PPR message will be used in place of the SDTR and WDTR
+			 * messages to negotiate synchronous speed and offset, transfer
+			 * width, and protocol options.
+			 */
+			if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY) {
+				AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE,
+						asc_dvc->ppr_able);
+				asc_dvc->ppr_able |= tidmask;
+				AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE,
+						 asc_dvc->ppr_able);
+			}
+		}
 
-        /*
-         * If the EEPROM enabled Tag Queuing for the device and the
-         * device supports Tag Queueing, then turn on the device's
-         * 'tagqng_enable' bit in the microcode and set the microcode
-         * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
-         * value.
-         *
-         * Tag Queuing is disabled for the BIOS which runs in polled
-         * mode and would see no benefit from Tag Queuing. Also by
-         * disabling Tag Queuing in the BIOS devices with Tag Queuing
-         * bugs will at least work with the BIOS.
-         */
-        if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq))
-        {
-            AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
-            cfg_word |= tidmask;
-            AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
+		/*
+		 * If the EEPROM enabled Tag Queuing for the device and the
+		 * device supports Tag Queueing, then turn on the device's
+		 * 'tagqng_enable' bit in the microcode and set the microcode
+		 * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
+		 * value.
+		 *
+		 * Tag Queuing is disabled for the BIOS which runs in polled
+		 * mode and would see no benefit from Tag Queuing. Also by
+		 * disabling Tag Queuing in the BIOS devices with Tag Queuing
+		 * bugs will at least work with the BIOS.
+		 */
+		if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq)) {
+			AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
+			cfg_word |= tidmask;
+			AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE,
+					 cfg_word);
 
-            AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
-                asc_dvc->max_dvc_qng);
-        }
-    }
+			AdvWriteByteLram(iop_base,
+					 ASC_MC_NUMBER_OF_MAX_CMD + tid,
+					 asc_dvc->max_dvc_qng);
+		}
+	}
 }
+
 MODULE_LICENSE("Dual BSD/GPL");
 
+static struct Scsi_Host *__devinit
+advansys_board_found(int iop, struct device *dev, int bus_type)
+{
+	struct Scsi_Host *shost;
+	struct pci_dev *pdev = bus_type == ASC_IS_PCI ? to_pci_dev(dev) : NULL;
+	asc_board_t *boardp;
+	ASC_DVC_VAR *asc_dvc_varp = NULL;
+	ADV_DVC_VAR *adv_dvc_varp = NULL;
+	adv_sgblk_t *sgp = NULL;
+	int share_irq = FALSE;
+	int iolen = 0;
+	ADV_PADDR pci_memory_address;
+	int warn_code, err_code;
+	int ret;
+
+	/*
+	 * Adapter found.
+	 *
+	 * Register the adapter, get its configuration, and
+	 * initialize it.
+	 */
+	ASC_DBG(2, "advansys_board_found: scsi_register()\n");
+	shost = scsi_register(&driver_template, sizeof(asc_board_t));
+
+	if (!shost)
+		return NULL;
+
+	/* Save a pointer to the Scsi_Host of each board found. */
+	asc_host[asc_board_count++] = shost;
+
+	/* Initialize private per board data */
+	boardp = ASC_BOARDP(shost);
+	memset(boardp, 0, sizeof(asc_board_t));
+	boardp->id = asc_board_count - 1;
+
+	/* Initialize spinlock. */
+	spin_lock_init(&boardp->lock);
+
+	/*
+	 * Handle both narrow and wide boards.
+	 *
+	 * If a Wide board was detected, set the board structure
+	 * wide board flag. Set-up the board structure based on
+	 * the board type.
+	 */
+#ifdef CONFIG_PCI
+	if (bus_type == ASC_IS_PCI &&
+	    (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW ||
+	     pdev->device == PCI_DEVICE_ID_38C0800_REV1 ||
+	     pdev->device == PCI_DEVICE_ID_38C1600_REV1)) {
+		boardp->flags |= ASC_IS_WIDE_BOARD;
+	}
+#endif /* CONFIG_PCI */
+
+	if (ASC_NARROW_BOARD(boardp)) {
+		ASC_DBG(1, "advansys_board_found: narrow board\n");
+		asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+		asc_dvc_varp->bus_type = bus_type;
+		asc_dvc_varp->drv_ptr = boardp;
+		asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
+		asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
+		asc_dvc_varp->iop_base = iop;
+		asc_dvc_varp->isr_callback = asc_isr_callback;
+	} else {
+		ASC_DBG(1, "advansys_board_found: wide board\n");
+		adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+		adv_dvc_varp->drv_ptr = boardp;
+		adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
+		adv_dvc_varp->isr_callback = adv_isr_callback;
+		adv_dvc_varp->async_callback = adv_async_callback;
+#ifdef CONFIG_PCI
+		if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) {
+			ASC_DBG(1, "advansys_board_found: ASC-3550\n");
+			adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
+		} else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) {
+			ASC_DBG(1, "advansys_board_found: ASC-38C0800\n");
+			adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
+		} else {
+			ASC_DBG(1, "advansys_board_found: ASC-38C1600\n");
+			adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
+		}
+#endif /* CONFIG_PCI */
+
+		/*
+		 * Map the board's registers into virtual memory for
+		 * PCI slave access. Only memory accesses are used to
+		 * access the board's registers.
+		 *
+		 * Note: The PCI register base address is not always
+		 * page aligned, but the address passed to ioremap()
+		 * must be page aligned. It is guaranteed that the
+		 * PCI register base address will not cross a page
+		 * boundary.
+		 */
+		if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+			iolen = ADV_3550_IOLEN;
+		} else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+			iolen = ADV_38C0800_IOLEN;
+		} else {
+			iolen = ADV_38C1600_IOLEN;
+		}
+#ifdef CONFIG_PCI
+		pci_memory_address = pci_resource_start(pdev, 1);
+		ASC_DBG1(1,
+			 "advansys_board_found: pci_memory_address: 0x%lx\n",
+			 (ulong)pci_memory_address);
+		if ((boardp->ioremap_addr =
+		     ioremap(pci_memory_address & PAGE_MASK, PAGE_SIZE)) == 0) {
+			ASC_PRINT3
+			    ("advansys_board_found: board %d: ioremap(%x, %d) returned NULL\n",
+			     boardp->id, pci_memory_address, iolen);
+			scsi_unregister(shost);
+			asc_board_count--;
+			return NULL;
+		}
+		ASC_DBG1(1,
+			 "advansys_board_found: ioremap_addr: 0x%lx\n",
+			 (ulong)boardp->ioremap_addr);
+		adv_dvc_varp->iop_base = (AdvPortAddr)
+		    (boardp->ioremap_addr +
+		     (pci_memory_address - (pci_memory_address & PAGE_MASK)));
+		ASC_DBG1(1,
+			 "advansys_board_found: iop_base: 0x%lx\n",
+			 adv_dvc_varp->iop_base);
+#endif /* CONFIG_PCI */
+
+		/*
+		 * Even though it isn't used to access wide boards, other
+		 * than for the debug line below, save I/O Port address so
+		 * that it can be reported.
+		 */
+		boardp->ioport = iop;
+
+		ASC_DBG2(1,
+			 "advansys_board_found: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
+			 (ushort)inp(iop + 1), (ushort)inpw(iop));
+	}
+
+#ifdef CONFIG_PROC_FS
+	/*
+	 * Allocate buffer for printing information from
+	 * /proc/scsi/advansys/[0...].
+	 */
+	if ((boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) {
+		ASC_PRINT3
+		    ("advansys_board_found: board %d: kmalloc(%d, %d) returned NULL\n",
+		     boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC);
+		scsi_unregister(shost);
+		asc_board_count--;
+		return NULL;
+	}
+#endif /* CONFIG_PROC_FS */
+
+	if (ASC_NARROW_BOARD(boardp)) {
+		asc_dvc_varp->cfg->dev = dev;
+		/*
+		 * Set the board bus type and PCI IRQ before
+		 * calling AscInitGetConfig().
+		 */
+		switch (asc_dvc_varp->bus_type) {
+#ifdef CONFIG_ISA
+		case ASC_IS_ISA:
+			shost->unchecked_isa_dma = TRUE;
+			share_irq = FALSE;
+			break;
+		case ASC_IS_VL:
+			shost->unchecked_isa_dma = FALSE;
+			share_irq = FALSE;
+			break;
+		case ASC_IS_EISA:
+			shost->unchecked_isa_dma = FALSE;
+			share_irq = TRUE;
+			break;
+#endif /* CONFIG_ISA */
+#ifdef CONFIG_PCI
+		case ASC_IS_PCI:
+			shost->irq = asc_dvc_varp->irq_no = pdev->irq;
+			asc_dvc_varp->cfg->pci_slot_info =
+			    ASC_PCI_MKID(pdev->bus->number,
+					 PCI_SLOT(pdev->devfn),
+					 PCI_FUNC(pdev->devfn));
+			shost->unchecked_isa_dma = FALSE;
+			share_irq = TRUE;
+			break;
+#endif /* CONFIG_PCI */
+		default:
+			ASC_PRINT2
+			    ("advansys_board_found: board %d: unknown adapter type: %d\n",
+			     boardp->id, asc_dvc_varp->bus_type);
+			shost->unchecked_isa_dma = TRUE;
+			share_irq = FALSE;
+			break;
+		}
+	} else {
+		adv_dvc_varp->cfg->dev = dev;
+		/*
+		 * For Wide boards set PCI information before calling
+		 * AdvInitGetConfig().
+		 */
+#ifdef CONFIG_PCI
+		shost->irq = adv_dvc_varp->irq_no = pdev->irq;
+		adv_dvc_varp->cfg->pci_slot_info =
+		    ASC_PCI_MKID(pdev->bus->number,
+				 PCI_SLOT(pdev->devfn),
+				 PCI_FUNC(pdev->devfn));
+		shost->unchecked_isa_dma = FALSE;
+		share_irq = TRUE;
+#endif /* CONFIG_PCI */
+	}
+
+	/*
+	 * Read the board configuration.
+	 */
+	if (ASC_NARROW_BOARD(boardp)) {
+		/*
+		 * NOTE: AscInitGetConfig() may change the board's
+		 * bus_type value. The bus_type value should no
+		 * longer be used. If the bus_type field must be
+		 * referenced only use the bit-wise AND operator "&".
+		 */
+		ASC_DBG(2, "advansys_board_found: AscInitGetConfig()\n");
+		switch (ret = AscInitGetConfig(asc_dvc_varp)) {
+		case 0:	/* No error */
+			break;
+		case ASC_WARN_IO_PORT_ROTATE:
+			ASC_PRINT1
+			    ("AscInitGetConfig: board %d: I/O port address modified\n",
+			     boardp->id);
+			break;
+		case ASC_WARN_AUTO_CONFIG:
+			ASC_PRINT1
+			    ("AscInitGetConfig: board %d: I/O port increment switch enabled\n",
+			     boardp->id);
+			break;
+		case ASC_WARN_EEPROM_CHKSUM:
+			ASC_PRINT1
+			    ("AscInitGetConfig: board %d: EEPROM checksum error\n",
+			     boardp->id);
+			break;
+		case ASC_WARN_IRQ_MODIFIED:
+			ASC_PRINT1
+			    ("AscInitGetConfig: board %d: IRQ modified\n",
+			     boardp->id);
+			break;
+		case ASC_WARN_CMD_QNG_CONFLICT:
+			ASC_PRINT1
+			    ("AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
+			     boardp->id);
+			break;
+		default:
+			ASC_PRINT2
+			    ("AscInitGetConfig: board %d: unknown warning: 0x%x\n",
+			     boardp->id, ret);
+			break;
+		}
+		if ((err_code = asc_dvc_varp->err_code) != 0) {
+			ASC_PRINT3
+			    ("AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
+			     boardp->id,
+			     asc_dvc_varp->init_state, asc_dvc_varp->err_code);
+		}
+	} else {
+		ASC_DBG(2, "advansys_board_found: AdvInitGetConfig()\n");
+		if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
+			ASC_PRINT2
+			    ("AdvInitGetConfig: board %d: warning: 0x%x\n",
+			     boardp->id, ret);
+		}
+		if ((err_code = adv_dvc_varp->err_code) != 0) {
+			ASC_PRINT2
+			    ("AdvInitGetConfig: board %d error: err_code 0x%x\n",
+			     boardp->id, adv_dvc_varp->err_code);
+		}
+	}
+
+	if (err_code != 0) {
+#ifdef CONFIG_PROC_FS
+		kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+		scsi_unregister(shost);
+		asc_board_count--;
+		return NULL;
+	}
+
+	/*
+	 * Save the EEPROM configuration so that it can be displayed
+	 * from /proc/scsi/advansys/[0...].
+	 */
+	if (ASC_NARROW_BOARD(boardp)) {
+
+		ASCEEP_CONFIG *ep;
+
+		/*
+		 * Set the adapter's target id bit in the 'init_tidmask' field.
+		 */
+		boardp->init_tidmask |=
+		    ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
+
+		/*
+		 * Save EEPROM settings for the board.
+		 */
+		ep = &boardp->eep_config.asc_eep;
+
+		ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
+		ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
+		ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
+		ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
+		ep->start_motor = asc_dvc_varp->start_motor;
+		ep->cntl = asc_dvc_varp->dvc_cntl;
+		ep->no_scam = asc_dvc_varp->no_scam;
+		ep->max_total_qng = asc_dvc_varp->max_total_qng;
+		ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
+		/* 'max_tag_qng' is set to the same value for every device. */
+		ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
+		ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
+		ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
+		ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
+		ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
+		ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
+		ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
+
+		/*
+		 * Modify board configuration.
+		 */
+		ASC_DBG(2, "advansys_board_found: AscInitSetConfig()\n");
+		switch (ret = AscInitSetConfig(asc_dvc_varp)) {
+		case 0:	/* No error. */
+			break;
+		case ASC_WARN_IO_PORT_ROTATE:
+			ASC_PRINT1
+			    ("AscInitSetConfig: board %d: I/O port address modified\n",
+			     boardp->id);
+			break;
+		case ASC_WARN_AUTO_CONFIG:
+			ASC_PRINT1
+			    ("AscInitSetConfig: board %d: I/O port increment switch enabled\n",
+			     boardp->id);
+			break;
+		case ASC_WARN_EEPROM_CHKSUM:
+			ASC_PRINT1
+			    ("AscInitSetConfig: board %d: EEPROM checksum error\n",
+			     boardp->id);
+			break;
+		case ASC_WARN_IRQ_MODIFIED:
+			ASC_PRINT1
+			    ("AscInitSetConfig: board %d: IRQ modified\n",
+			     boardp->id);
+			break;
+		case ASC_WARN_CMD_QNG_CONFLICT:
+			ASC_PRINT1
+			    ("AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
+			     boardp->id);
+			break;
+		default:
+			ASC_PRINT2
+			    ("AscInitSetConfig: board %d: unknown warning: 0x%x\n",
+			     boardp->id, ret);
+			break;
+		}
+		if (asc_dvc_varp->err_code != 0) {
+			ASC_PRINT3
+			    ("AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
+			     boardp->id,
+			     asc_dvc_varp->init_state, asc_dvc_varp->err_code);
+#ifdef CONFIG_PROC_FS
+			kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+			scsi_unregister(shost);
+			asc_board_count--;
+			return NULL;
+		}
+
+		/*
+		 * Finish initializing the 'Scsi_Host' structure.
+		 */
+		/* AscInitSetConfig() will set the IRQ for non-PCI boards. */
+		if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
+			shost->irq = asc_dvc_varp->irq_no;
+		}
+	} else {
+		ADVEEP_3550_CONFIG *ep_3550;
+		ADVEEP_38C0800_CONFIG *ep_38C0800;
+		ADVEEP_38C1600_CONFIG *ep_38C1600;
+
+		/*
+		 * Save Wide EEP Configuration Information.
+		 */
+		if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+			ep_3550 = &boardp->eep_config.adv_3550_eep;
+
+			ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
+			ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
+			ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+			ep_3550->termination = adv_dvc_varp->cfg->termination;
+			ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
+			ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
+			ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
+			ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
+			ep_3550->ultra_able = adv_dvc_varp->ultra_able;
+			ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
+			ep_3550->start_motor = adv_dvc_varp->start_motor;
+			ep_3550->scsi_reset_delay =
+			    adv_dvc_varp->scsi_reset_wait;
+			ep_3550->serial_number_word1 =
+			    adv_dvc_varp->cfg->serial1;
+			ep_3550->serial_number_word2 =
+			    adv_dvc_varp->cfg->serial2;
+			ep_3550->serial_number_word3 =
+			    adv_dvc_varp->cfg->serial3;
+		} else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+			ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
+
+			ep_38C0800->adapter_scsi_id =
+			    adv_dvc_varp->chip_scsi_id;
+			ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
+			ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+			ep_38C0800->termination_lvd =
+			    adv_dvc_varp->cfg->termination;
+			ep_38C0800->disc_enable =
+			    adv_dvc_varp->cfg->disc_enable;
+			ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
+			ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
+			ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
+			ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
+			ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
+			ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
+			ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
+			ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
+			ep_38C0800->start_motor = adv_dvc_varp->start_motor;
+			ep_38C0800->scsi_reset_delay =
+			    adv_dvc_varp->scsi_reset_wait;
+			ep_38C0800->serial_number_word1 =
+			    adv_dvc_varp->cfg->serial1;
+			ep_38C0800->serial_number_word2 =
+			    adv_dvc_varp->cfg->serial2;
+			ep_38C0800->serial_number_word3 =
+			    adv_dvc_varp->cfg->serial3;
+		} else {
+			ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
+
+			ep_38C1600->adapter_scsi_id =
+			    adv_dvc_varp->chip_scsi_id;
+			ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
+			ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+			ep_38C1600->termination_lvd =
+			    adv_dvc_varp->cfg->termination;
+			ep_38C1600->disc_enable =
+			    adv_dvc_varp->cfg->disc_enable;
+			ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
+			ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
+			ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
+			ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
+			ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
+			ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
+			ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
+			ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
+			ep_38C1600->start_motor = adv_dvc_varp->start_motor;
+			ep_38C1600->scsi_reset_delay =
+			    adv_dvc_varp->scsi_reset_wait;
+			ep_38C1600->serial_number_word1 =
+			    adv_dvc_varp->cfg->serial1;
+			ep_38C1600->serial_number_word2 =
+			    adv_dvc_varp->cfg->serial2;
+			ep_38C1600->serial_number_word3 =
+			    adv_dvc_varp->cfg->serial3;
+		}
+
+		/*
+		 * Set the adapter's target id bit in the 'init_tidmask' field.
+		 */
+		boardp->init_tidmask |=
+		    ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
+
+		/*
+		 * Finish initializing the 'Scsi_Host' structure.
+		 */
+		shost->irq = adv_dvc_varp->irq_no;
+	}
+
+	/*
+	 * Channels are numbered beginning with 0. For AdvanSys one host
+	 * structure supports one channel. Multi-channel boards have a
+	 * separate host structure for each channel.
+	 */
+	shost->max_channel = 0;
+	if (ASC_NARROW_BOARD(boardp)) {
+		shost->max_id = ASC_MAX_TID + 1;
+		shost->max_lun = ASC_MAX_LUN + 1;
+
+		shost->io_port = asc_dvc_varp->iop_base;
+		boardp->asc_n_io_port = ASC_IOADR_GAP;
+		shost->this_id = asc_dvc_varp->cfg->chip_scsi_id;
+
+		/* Set maximum number of queues the adapter can handle. */
+		shost->can_queue = asc_dvc_varp->max_total_qng;
+	} else {
+		shost->max_id = ADV_MAX_TID + 1;
+		shost->max_lun = ADV_MAX_LUN + 1;
+
+		/*
+		 * Save the I/O Port address and length even though
+		 * I/O ports are not used to access Wide boards.
+		 * Instead the Wide boards are accessed with
+		 * PCI Memory Mapped I/O.
+		 */
+		shost->io_port = iop;
+		boardp->asc_n_io_port = iolen;
+
+		shost->this_id = adv_dvc_varp->chip_scsi_id;
+
+		/* Set maximum number of queues the adapter can handle. */
+		shost->can_queue = adv_dvc_varp->max_host_qng;
+	}
+
+	/*
+	 * 'n_io_port' currently is one byte.
+	 *
+	 * Set a value to 'n_io_port', but never referenced it because
+	 * it may be truncated.
+	 */
+	shost->n_io_port = boardp->asc_n_io_port <= 255 ?
+	    boardp->asc_n_io_port : 255;
+
+	/*
+	 * Following v1.3.89, 'cmd_per_lun' is no longer needed
+	 * and should be set to zero.
+	 *
+	 * But because of a bug introduced in v1.3.89 if the driver is
+	 * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
+	 * SCSI function 'allocate_device' will panic. To allow the driver
+	 * to work as a module in these kernels set 'cmd_per_lun' to 1.
+	 *
+	 * Note: This is wrong.  cmd_per_lun should be set to the depth
+	 * you want on untagged devices always.
+	 #ifdef MODULE
+	 */
+	shost->cmd_per_lun = 1;
+/* #else
+            shost->cmd_per_lun = 0;
+#endif */
+
+	/*
+	 * Set the maximum number of scatter-gather elements the
+	 * adapter can handle.
+	 */
+	if (ASC_NARROW_BOARD(boardp)) {
+		/*
+		 * Allow two commands with 'sg_tablesize' scatter-gather
+		 * elements to be executed simultaneously. This value is
+		 * the theoretical hardware limit. It may be decreased
+		 * below.
+		 */
+		shost->sg_tablesize =
+		    (((asc_dvc_varp->max_total_qng - 2) / 2) *
+		     ASC_SG_LIST_PER_Q) + 1;
+	} else {
+		shost->sg_tablesize = ADV_MAX_SG_LIST;
+	}
+
+	/*
+	 * The value of 'sg_tablesize' can not exceed the SCSI
+	 * mid-level driver definition of SG_ALL. SG_ALL also
+	 * must not be exceeded, because it is used to define the
+	 * size of the scatter-gather table in 'struct asc_sg_head'.
+	 */
+	if (shost->sg_tablesize > SG_ALL) {
+		shost->sg_tablesize = SG_ALL;
+	}
+
+	ASC_DBG1(1, "advansys_board_found: sg_tablesize: %d\n", shost->sg_tablesize);
+
+	/* BIOS start address. */
+	if (ASC_NARROW_BOARD(boardp)) {
+		shost->base = ((ulong)
+			     AscGetChipBiosAddress(asc_dvc_varp->
+						   iop_base,
+						   asc_dvc_varp->bus_type));
+	} else {
+		/*
+		 * Fill-in BIOS board variables. The Wide BIOS saves
+		 * information in LRAM that is used by the driver.
+		 */
+		AdvReadWordLram(adv_dvc_varp->iop_base,
+				BIOS_SIGNATURE, boardp->bios_signature);
+		AdvReadWordLram(adv_dvc_varp->iop_base,
+				BIOS_VERSION, boardp->bios_version);
+		AdvReadWordLram(adv_dvc_varp->iop_base,
+				BIOS_CODESEG, boardp->bios_codeseg);
+		AdvReadWordLram(adv_dvc_varp->iop_base,
+				BIOS_CODELEN, boardp->bios_codelen);
+
+		ASC_DBG2(1,
+			 "advansys_board_found: bios_signature 0x%x, bios_version 0x%x\n",
+			 boardp->bios_signature, boardp->bios_version);
+
+		ASC_DBG2(1,
+			 "advansys_board_found: bios_codeseg 0x%x, bios_codelen 0x%x\n",
+			 boardp->bios_codeseg, boardp->bios_codelen);
+
+		/*
+		 * If the BIOS saved a valid signature, then fill in
+		 * the BIOS code segment base address.
+		 */
+		if (boardp->bios_signature == 0x55AA) {
+			/*
+			 * Convert x86 realmode code segment to a linear
+			 * address by shifting left 4.
+			 */
+			shost->base = ((ulong)boardp->bios_codeseg << 4);
+		} else {
+			shost->base = 0;
+		}
+	}
+
+	/*
+	 * Register Board Resources - I/O Port, DMA, IRQ
+	 */
+
+	/*
+	 * Register I/O port range.
+	 *
+	 * For Wide boards the I/O ports are not used to access
+	 * the board, but request the region anyway.
+	 *
+	 * 'shost->n_io_port' is not referenced, because it may be truncated.
+	 */
+	ASC_DBG2(2,
+		 "advansys_board_found: request_region port 0x%lx, len 0x%x\n",
+		 (ulong)shost->io_port, boardp->asc_n_io_port);
+	if (request_region(shost->io_port, boardp->asc_n_io_port,
+			   "advansys") == NULL) {
+		ASC_PRINT3
+		    ("advansys_board_found: board %d: request_region() failed, port 0x%lx, len 0x%x\n",
+		     boardp->id, (ulong)shost->io_port, boardp->asc_n_io_port);
+#ifdef CONFIG_PROC_FS
+		kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+		scsi_unregister(shost);
+		asc_board_count--;
+		return NULL;
+	}
+
+	/* Register DMA Channel for Narrow boards. */
+	shost->dma_channel = NO_ISA_DMA;	/* Default to no ISA DMA. */
+#ifdef CONFIG_ISA
+	if (ASC_NARROW_BOARD(boardp)) {
+		/* Register DMA channel for ISA bus. */
+		if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+			shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
+			if ((ret =
+			     request_dma(shost->dma_channel, "advansys")) != 0) {
+				ASC_PRINT3
+				    ("advansys_board_found: board %d: request_dma() %d failed %d\n",
+				     boardp->id, shost->dma_channel, ret);
+				release_region(shost->io_port,
+					       boardp->asc_n_io_port);
+#ifdef CONFIG_PROC_FS
+				kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+				scsi_unregister(shost);
+				asc_board_count--;
+				return NULL;
+			}
+			AscEnableIsaDma(shost->dma_channel);
+		}
+	}
+#endif /* CONFIG_ISA */
+
+	/* Register IRQ Number. */
+	ASC_DBG1(2, "advansys_board_found: request_irq() %d\n", shost->irq);
+	/*
+	 * If request_irq() fails with the IRQF_DISABLED flag set,
+	 * then try again without the IRQF_DISABLED flag set. This
+	 * allows IRQ sharing to work even with other drivers that
+	 * do not set the IRQF_DISABLED flag.
+	 *
+	 * If IRQF_DISABLED is not set, then interrupts are enabled
+	 * before the driver interrupt function is called.
+	 */
+	if (((ret = request_irq(shost->irq, advansys_interrupt,
+				IRQF_DISABLED | (share_irq ==
+						 TRUE ?
+						 IRQF_SHARED :
+						 0), "advansys", boardp)) != 0)
+	    &&
+	    ((ret =
+	      request_irq(shost->irq, advansys_interrupt,
+			  (share_irq == TRUE ? IRQF_SHARED : 0),
+			  "advansys", boardp)) != 0)) {
+		if (ret == -EBUSY) {
+			ASC_PRINT2
+			    ("advansys_board_found: board %d: request_irq(): IRQ 0x%x already in use.\n",
+			     boardp->id, shost->irq);
+		} else if (ret == -EINVAL) {
+			ASC_PRINT2
+			    ("advansys_board_found: board %d: request_irq(): IRQ 0x%x not valid.\n",
+			     boardp->id, shost->irq);
+		} else {
+			ASC_PRINT3
+			    ("advansys_board_found: board %d: request_irq(): IRQ 0x%x failed with %d\n",
+			     boardp->id, shost->irq, ret);
+		}
+		release_region(shost->io_port, boardp->asc_n_io_port);
+		iounmap(boardp->ioremap_addr);
+		if (shost->dma_channel != NO_ISA_DMA) {
+			free_dma(shost->dma_channel);
+		}
+#ifdef CONFIG_PROC_FS
+		kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+		scsi_unregister(shost);
+		asc_board_count--;
+		return NULL;
+	}
+
+	/*
+	 * Initialize board RISC chip and enable interrupts.
+	 */
+	if (ASC_NARROW_BOARD(boardp)) {
+		ASC_DBG(2, "advansys_board_found: AscInitAsc1000Driver()\n");
+		warn_code = AscInitAsc1000Driver(asc_dvc_varp);
+		err_code = asc_dvc_varp->err_code;
+
+		if (warn_code || err_code) {
+			ASC_PRINT4
+			    ("advansys_board_found: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
+			     boardp->id,
+			     asc_dvc_varp->init_state, warn_code, err_code);
+		}
+	} else {
+		ADV_CARR_T *carrp;
+		int req_cnt = 0;
+		adv_req_t *reqp = NULL;
+		int sg_cnt = 0;
+
+		/*
+		 * Allocate buffer carrier structures. The total size
+		 * is about 4 KB, so allocate all at once.
+		 */
+		carrp = (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC);
+		ASC_DBG1(1, "advansys_board_found: carrp 0x%lx\n", (ulong)carrp);
+
+		if (carrp == NULL) {
+			goto kmalloc_error;
+		}
+
+		/*
+		 * Allocate up to 'max_host_qng' request structures for
+		 * the Wide board. The total size is about 16 KB, so
+		 * allocate all at once. If the allocation fails decrement
+		 * and try again.
+		 */
+		for (req_cnt = adv_dvc_varp->max_host_qng;
+		     req_cnt > 0; req_cnt--) {
+
+			reqp = (adv_req_t *)
+			    kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC);
+
+			ASC_DBG3(1,
+				 "advansys_board_found: reqp 0x%lx, req_cnt %d, bytes %lu\n",
+				 (ulong)reqp, req_cnt,
+				 (ulong)sizeof(adv_req_t) * req_cnt);
+
+			if (reqp != NULL) {
+				break;
+			}
+		}
+		if (reqp == NULL) {
+			goto kmalloc_error;
+		}
+
+		/*
+		 * Allocate up to ADV_TOT_SG_BLOCK request structures for
+		 * the Wide board. Each structure is about 136 bytes.
+		 */
+		boardp->adv_sgblkp = NULL;
+		for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
+
+			sgp = (adv_sgblk_t *)
+			    kmalloc(sizeof(adv_sgblk_t), GFP_ATOMIC);
+
+			if (sgp == NULL) {
+				break;
+			}
+
+			sgp->next_sgblkp = boardp->adv_sgblkp;
+			boardp->adv_sgblkp = sgp;
+
+		}
+		ASC_DBG3(1,
+			 "advansys_board_found: sg_cnt %d * %u = %u bytes\n",
+			 sg_cnt, sizeof(adv_sgblk_t),
+			 (unsigned)(sizeof(adv_sgblk_t) * sg_cnt));
+
+		/*
+		 * If no request structures or scatter-gather structures could
+		 * be allocated, then return an error. Otherwise continue with
+		 * initialization.
+		 */
+ kmalloc_error:
+		if (carrp == NULL) {
+			ASC_PRINT1
+			    ("advansys_board_found: board %d error: failed to kmalloc() carrier buffer.\n",
+			     boardp->id);
+			err_code = ADV_ERROR;
+		} else if (reqp == NULL) {
+			kfree(carrp);
+			ASC_PRINT1
+			    ("advansys_board_found: board %d error: failed to kmalloc() adv_req_t buffer.\n",
+			     boardp->id);
+			err_code = ADV_ERROR;
+		} else if (boardp->adv_sgblkp == NULL) {
+			kfree(carrp);
+			kfree(reqp);
+			ASC_PRINT1
+			    ("advansys_board_found: board %d error: failed to kmalloc() adv_sgblk_t buffers.\n",
+			     boardp->id);
+			err_code = ADV_ERROR;
+		} else {
+
+			/* Save carrier buffer pointer. */
+			boardp->orig_carrp = carrp;
+
+			/*
+			 * Save original pointer for kfree() in case the
+			 * driver is built as a module and can be unloaded.
+			 */
+			boardp->orig_reqp = reqp;
+
+			adv_dvc_varp->carrier_buf = carrp;
+
+			/*
+			 * Point 'adv_reqp' to the request structures and
+			 * link them together.
+			 */
+			req_cnt--;
+			reqp[req_cnt].next_reqp = NULL;
+			for (; req_cnt > 0; req_cnt--) {
+				reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
+			}
+			boardp->adv_reqp = &reqp[0];
+
+			if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
+				ASC_DBG(2,
+					"advansys_board_found: AdvInitAsc3550Driver()\n");
+				warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
+			} else if (adv_dvc_varp->chip_type ==
+				   ADV_CHIP_ASC38C0800) {
+				ASC_DBG(2,
+					"advansys_board_found: AdvInitAsc38C0800Driver()\n");
+				warn_code =
+				    AdvInitAsc38C0800Driver(adv_dvc_varp);
+			} else {
+				ASC_DBG(2,
+					"advansys_board_found: AdvInitAsc38C1600Driver()\n");
+				warn_code =
+				    AdvInitAsc38C1600Driver(adv_dvc_varp);
+			}
+			err_code = adv_dvc_varp->err_code;
+
+			if (warn_code || err_code) {
+				ASC_PRINT3
+				    ("advansys_board_found: board %d error: warn 0x%x, error 0x%x\n",
+				     boardp->id, warn_code, err_code);
+			}
+		}
+	}
+
+	if (err_code != 0) {
+		release_region(shost->io_port, boardp->asc_n_io_port);
+		if (ASC_WIDE_BOARD(boardp)) {
+			iounmap(boardp->ioremap_addr);
+			kfree(boardp->orig_carrp);
+			boardp->orig_carrp = NULL;
+			if (boardp->orig_reqp) {
+				kfree(boardp->orig_reqp);
+				boardp->orig_reqp = boardp->adv_reqp = NULL;
+			}
+			while ((sgp = boardp->adv_sgblkp) != NULL) {
+				boardp->adv_sgblkp = sgp->next_sgblkp;
+				kfree(sgp);
+			}
+		}
+		if (shost->dma_channel != NO_ISA_DMA) {
+			free_dma(shost->dma_channel);
+		}
+#ifdef CONFIG_PROC_FS
+		kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+		free_irq(shost->irq, boardp);
+		scsi_unregister(shost);
+		asc_board_count--;
+		return NULL;
+	}
+	ASC_DBG_PRT_SCSI_HOST(2, shost);
+
+	return shost;
+}
+
+/*
+ * advansys_detect()
+ *
+ * Detect function for AdvanSys adapters.
+ *
+ * Argument is a pointer to the host driver's scsi_hosts entry.
+ *
+ * Return number of adapters found.
+ *
+ * Note: Because this function is called during system initialization
+ * it must not call SCSI mid-level functions including scsi_malloc()
+ * and scsi_free().
+ */
+static int __init advansys_detect(struct scsi_host_template *tpnt)
+{
+	static int detect_called = ASC_FALSE;
+	int iop;
+	int bus;
+	int ioport = 0;
+	struct device *dev = NULL;
+#ifdef CONFIG_PCI
+	int pci_init_search = 0;
+	struct pci_dev *pci_devicep[ASC_NUM_BOARD_SUPPORTED];
+	int pci_card_cnt_max = 0;
+	int pci_card_cnt = 0;
+	struct pci_dev *pdev = NULL;
+	int pci_device_id_cnt = 0;
+	unsigned int pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
+		PCI_DEVICE_ID_ASP_1200A,
+		PCI_DEVICE_ID_ASP_ABP940,
+		PCI_DEVICE_ID_ASP_ABP940U,
+		PCI_DEVICE_ID_ASP_ABP940UW,
+		PCI_DEVICE_ID_38C0800_REV1,
+		PCI_DEVICE_ID_38C1600_REV1
+	};
+#endif /* CONFIG_PCI */
+
+	if (detect_called == ASC_FALSE) {
+		detect_called = ASC_TRUE;
+	} else {
+		printk
+		    ("AdvanSys SCSI: advansys_detect() multiple calls ignored\n");
+		return 0;
+	}
+
+	ASC_DBG(1, "advansys_detect: begin\n");
+
+	asc_board_count = 0;
+
+	/*
+	 * If I/O port probing has been modified, then verify and
+	 * clean-up the 'asc_ioport' list.
+	 */
+	if (asc_iopflag == ASC_TRUE) {
+		for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
+			ASC_DBG2(1, "advansys_detect: asc_ioport[%d] 0x%x\n",
+				 ioport, asc_ioport[ioport]);
+			if (asc_ioport[ioport] != 0) {
+				for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX;
+				     iop++) {
+					if (_asc_def_iop_base[iop] ==
+					    asc_ioport[ioport]) {
+						break;
+					}
+				}
+				if (iop == ASC_IOADR_TABLE_MAX_IX) {
+					printk
+					    ("AdvanSys SCSI: specified I/O Port 0x%X is invalid\n",
+					     asc_ioport[ioport]);
+					asc_ioport[ioport] = 0;
+				}
+			}
+		}
+		ioport = 0;
+	}
+
+	for (bus = 0; bus < ASC_NUM_BUS; bus++) {
+
+		ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n",
+			 bus, asc_bus_name[bus]);
+		iop = 0;
+
+		while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) {
+
+			ASC_DBG1(2, "advansys_detect: asc_board_count %d\n",
+				 asc_board_count);
+
+			switch (asc_bus[bus]) {
+			case ASC_IS_ISA:
+			case ASC_IS_VL:
+#ifdef CONFIG_ISA
+				if (asc_iopflag == ASC_FALSE) {
+					iop =
+					    AscSearchIOPortAddr(iop,
+								asc_bus[bus]);
+				} else {
+					/*
+					 * ISA and VL I/O port scanning has either been
+					 * eliminated or limited to selected ports on
+					 * the LILO command line, /etc/lilo.conf, or
+					 * by setting variables when the module was loaded.
+					 */
+					ASC_DBG(1,
+						"advansys_detect: I/O port scanning modified\n");
+ ioport_try_again:
+					iop = 0;
+					for (; ioport < ASC_NUM_IOPORT_PROBE;
+					     ioport++) {
+						if ((iop =
+						     asc_ioport[ioport]) != 0) {
+							break;
+						}
+					}
+					if (iop) {
+						ASC_DBG1(1,
+							 "advansys_detect: probing I/O port 0x%x...\n",
+							 iop);
+						if (!request_region
+						    (iop, ASC_IOADR_GAP,
+						     "advansys")) {
+							printk
+							    ("AdvanSys SCSI: specified I/O Port 0x%X is busy\n",
+							     iop);
+							/* Don't try this I/O port twice. */
+							asc_ioport[ioport] = 0;
+							goto ioport_try_again;
+						} else if (AscFindSignature(iop)
+							   == ASC_FALSE) {
+							printk
+							    ("AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n",
+							     iop);
+							/* Don't try this I/O port twice. */
+							release_region(iop,
+								       ASC_IOADR_GAP);
+							asc_ioport[ioport] = 0;
+							goto ioport_try_again;
+						} else {
+							/*
+							 * If this isn't an ISA board, then it must be
+							 * a VL board. If currently looking an ISA
+							 * board is being looked for then try for
+							 * another ISA board in 'asc_ioport'.
+							 */
+							if (asc_bus[bus] ==
+							    ASC_IS_ISA
+							    &&
+							    (AscGetChipVersion
+							     (iop,
+							      ASC_IS_ISA) &
+							     ASC_CHIP_VER_ISA_BIT)
+							    == 0) {
+								/*
+								 * Don't clear 'asc_ioport[ioport]'. Try
+								 * this board again for VL. Increment
+								 * 'ioport' past this board.
+								 */
+								ioport++;
+								release_region
+								    (iop,
+								     ASC_IOADR_GAP);
+								goto ioport_try_again;
+							}
+						}
+						/*
+						 * This board appears good, don't try the I/O port
+						 * again by clearing its value. Increment 'ioport'
+						 * for the next iteration.
+						 */
+						asc_ioport[ioport++] = 0;
+					}
+				}
+#endif /* CONFIG_ISA */
+				break;
+
+			case ASC_IS_EISA:
+#ifdef CONFIG_ISA
+				iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
+#endif /* CONFIG_ISA */
+				break;
+
+			case ASC_IS_PCI:
+#ifdef CONFIG_PCI
+				if (pci_init_search == 0) {
+					int i, j;
+
+					pci_init_search = 1;
+
+					/* Find all PCI cards. */
+					while (pci_device_id_cnt <
+					       ASC_PCI_DEVICE_ID_CNT) {
+						if ((pdev =
+						     pci_find_device
+						     (PCI_VENDOR_ID_ASP,
+						      pci_device_id
+						      [pci_device_id_cnt],
+						      pdev)) == NULL) {
+							pci_device_id_cnt++;
+						} else {
+							if (pci_enable_device
+							    (pdev) == 0) {
+								pci_devicep
+								    [pci_card_cnt_max++]
+								    = pdev;
+							}
+						}
+					}
+
+					/*
+					 * Sort PCI cards in ascending order by PCI Bus, Slot,
+					 * and Device Number.
+					 */
+					for (i = 0; i < pci_card_cnt_max - 1;
+					     i++) {
+						for (j = i + 1;
+						     j < pci_card_cnt_max;
+						     j++) {
+							if ((pci_devicep[j]->
+							     bus->number <
+							     pci_devicep[i]->
+							     bus->number)
+							    ||
+							    ((pci_devicep[j]->
+							      bus->number ==
+							      pci_devicep[i]->
+							      bus->number)
+							     &&
+							     (pci_devicep[j]->
+							      devfn <
+							      pci_devicep[i]->
+							      devfn))) {
+								pdev =
+								    pci_devicep
+								    [i];
+								pci_devicep[i] =
+								    pci_devicep
+								    [j];
+								pci_devicep[j] =
+								    pdev;
+							}
+						}
+					}
+
+					pci_card_cnt = 0;
+				} else {
+					pci_card_cnt++;
+				}
+
+				if (pci_card_cnt == pci_card_cnt_max) {
+					iop = 0;
+				} else {
+					pdev = pci_devicep[pci_card_cnt];
+
+					ASC_DBG2(2,
+						 "advansys_detect: devfn %d, bus number %d\n",
+						 pdev->devfn,
+						 pdev->bus->number);
+					iop = pci_resource_start(pdev, 0);
+					ASC_DBG2(1,
+						 "advansys_detect: vendorID %X, deviceID %X\n",
+						 pdev->vendor,
+						 pdev->device);
+					ASC_DBG2(2,
+						 "advansys_detect: iop %X, irqLine %d\n",
+						 iop, pdev->irq);
+				}
+				if (pdev)
+					dev = &pdev->dev;
+
+#endif /* CONFIG_PCI */
+				break;
+
+			default:
+				ASC_PRINT1
+				    ("advansys_detect: unknown bus type: %d\n",
+				     asc_bus[bus]);
+				break;
+			}
+			ASC_DBG1(1, "advansys_detect: iop 0x%x\n", iop);
+
+			/*
+			 * Adapter not found, try next bus type.
+			 */
+			if (iop == 0) {
+				break;
+			}
+
+			advansys_board_found(iop, dev, asc_bus[bus]);
+		}
+	}
+
+	ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n",
+		 asc_board_count);
+	return asc_board_count;
+}
+
+/*
+ * advansys_release()
+ *
+ * Release resources allocated for a single AdvanSys adapter.
+ */
+static int advansys_release(struct Scsi_Host *shost)
+{
+	asc_board_t *boardp;
+
+	ASC_DBG(1, "advansys_release: begin\n");
+	boardp = ASC_BOARDP(shost);
+	free_irq(shost->irq, boardp);
+	if (shost->dma_channel != NO_ISA_DMA) {
+		ASC_DBG(1, "advansys_release: free_dma()\n");
+		free_dma(shost->dma_channel);
+	}
+	release_region(shost->io_port, boardp->asc_n_io_port);
+	if (ASC_WIDE_BOARD(boardp)) {
+		adv_sgblk_t *sgp = NULL;
+
+		iounmap(boardp->ioremap_addr);
+		kfree(boardp->orig_carrp);
+		boardp->orig_carrp = NULL;
+		if (boardp->orig_reqp) {
+			kfree(boardp->orig_reqp);
+			boardp->orig_reqp = boardp->adv_reqp = NULL;
+		}
+		while ((sgp = boardp->adv_sgblkp) != NULL) {
+			boardp->adv_sgblkp = sgp->next_sgblkp;
+			kfree(sgp);
+		}
+	}
+#ifdef CONFIG_PROC_FS
+	ASC_ASSERT(boardp->prtbuf != NULL);
+	kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+	scsi_unregister(shost);
+	ASC_DBG(1, "advansys_release: end\n");
+	return 0;
+}
+
 #ifdef CONFIG_PCI
 /* PCI Devices supported by this driver */
 static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
-	{ PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
-	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{ PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
-	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{ PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
-	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{ PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
-	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{ PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
-	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{ PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
-	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{ }
+	{PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{}
 };
+
 MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
 #endif /* CONFIG_PCI */
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 85f2394..d30a307 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -289,18 +289,18 @@
 		if(spin_is_locked(&QLOCK)) { \
 			DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
 		} \
-		DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
 		spin_lock_irqsave(&QLOCK,flags); \
-		DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
 		QLOCKER=__FUNCTION__; \
 		QLOCKERL=__LINE__; \
 	} while(0)
 
 #define DO_UNLOCK(flags)	\
 	do { \
-		DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
+		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
 		spin_unlock_irqrestore(&QLOCK,flags); \
-		DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+		DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
 		QLOCKER="(not locked)"; \
 		QLOCKERL=0; \
 	} while(0)
@@ -322,6 +322,12 @@
                         (cmd) ? ((cmd)->device->id & 0x0f) : -1, \
 			(cmd) ? ((cmd)->device->lun & 0x07) : -1
 
+static inline void
+CMD_INC_RESID(struct scsi_cmnd *cmd, int inc)
+{
+	scsi_set_resid(cmd, scsi_get_resid(cmd) + inc);
+}
+
 #define DELAY_DEFAULT 1000
 
 #if defined(PCMCIA)
@@ -552,14 +558,11 @@
 struct aha152x_scdata {
 	Scsi_Cmnd *next;	/* next sc in queue */
 	struct completion *done;/* semaphore to block on */
-	unsigned char cmd_len;
-	unsigned char cmnd[MAX_COMMAND_SIZE];
-	unsigned short use_sg;
-	unsigned request_bufflen;
-	void *request_buffer;
+	unsigned char aha_orig_cmd_len;
+	unsigned char aha_orig_cmnd[MAX_COMMAND_SIZE];
+	int aha_orig_resid;
 };
 
-
 /* access macros for hostdata */
 
 #define HOSTDATA(shpnt)		((struct aha152x_hostdata *) &shpnt->hostdata)
@@ -978,15 +981,15 @@
 #if defined(AHA152X_DEBUG)
 	if (HOSTDATA(shpnt)->debug & debug_queue) {
 		printk(INFO_LEAD "queue: %p; cmd_len=%d pieces=%d size=%u cmnd=",
-		       CMDINFO(SCpnt), SCpnt, SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen);
+		       CMDINFO(SCpnt), SCpnt, SCpnt->cmd_len,
+		       scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
 		__scsi_print_command(SCpnt->cmnd);
 	}
 #endif
 
 	SCpnt->scsi_done	= done;
-	SCpnt->resid 		= SCpnt->request_bufflen;
 	SCpnt->SCp.phase	= not_issued | phase;
-	SCpnt->SCp.Status	= CHECK_CONDITION;
+	SCpnt->SCp.Status	= 0x1; /* Ilegal status by SCSI standard */
 	SCpnt->SCp.Message	= 0;
 	SCpnt->SCp.have_data_in	= 0;
 	SCpnt->SCp.sent_command	= 0;
@@ -997,20 +1000,11 @@
 			return FAILED;
 		}
 	} else {
-		struct aha152x_scdata *sc;
-
 		SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
 		if(SCpnt->host_scribble==0) {
 			printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt));
 			return FAILED;
 		}
-
-		sc = SCDATA(SCpnt);
-		memcpy(sc->cmnd, SCpnt->cmnd, sizeof(sc->cmnd));
-		sc->request_buffer  = SCpnt->request_buffer;
-		sc->request_bufflen = SCpnt->request_bufflen;
-		sc->use_sg          = SCpnt->use_sg;
-		sc->cmd_len         = SCpnt->cmd_len;
 	}
 
 	SCNEXT(SCpnt)		= NULL;
@@ -1022,16 +1016,25 @@
 	   SCp.buffer           : next buffer
 	   SCp.buffers_residual : left buffers in list
 	   SCp.phase            : current state of the command */
-	if (SCpnt->use_sg) {
-		SCpnt->SCp.buffer           = (struct scatterlist *) SCpnt->request_buffer;
-		SCpnt->SCp.ptr              = SG_ADDRESS(SCpnt->SCp.buffer);
-		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
-		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
-	} else {
-		SCpnt->SCp.ptr              = (char *) SCpnt->request_buffer;
-		SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
+
+	if ((phase & (check_condition|resetting)) || !scsi_sglist(SCpnt)) {
+		if (phase & check_condition) {
+			SCpnt->SCp.ptr           = SCpnt->sense_buffer;
+			SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer);
+			scsi_set_resid(SCpnt, sizeof(SCpnt->sense_buffer));
+		} else {
+			SCpnt->SCp.ptr           = NULL;
+			SCpnt->SCp.this_residual = 0;
+			scsi_set_resid(SCpnt, 0);
+		}
 		SCpnt->SCp.buffer           = NULL;
 		SCpnt->SCp.buffers_residual = 0;
+	} else {
+		scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
+		SCpnt->SCp.buffer           = scsi_sglist(SCpnt);
+		SCpnt->SCp.ptr              = SG_ADDRESS(SCpnt->SCp.buffer);
+		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
+		SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
 	}
 
 	DO_LOCK(flags);
@@ -1150,9 +1153,6 @@
 	DECLARE_COMPLETION(done);
 	int ret, issued, disconnected;
 	unsigned char old_cmd_len = SCpnt->cmd_len;
-	unsigned short old_use_sg = SCpnt->use_sg;
-	void *old_buffer = SCpnt->request_buffer;
-	unsigned old_bufflen = SCpnt->request_bufflen;
 	unsigned long flags;
 	unsigned long timeleft;
 
@@ -1174,9 +1174,6 @@
 	DO_UNLOCK(flags);
 
 	SCpnt->cmd_len         = 0;
-	SCpnt->use_sg          = 0;
-	SCpnt->request_buffer  = NULL;
-	SCpnt->request_bufflen = 0;
 
 	aha152x_internal_queue(SCpnt, &done, resetting, reset_done);
 
@@ -1189,9 +1186,6 @@
 	}
 
 	SCpnt->cmd_len         = old_cmd_len;
-	SCpnt->use_sg          = old_use_sg;
-  	SCpnt->request_buffer  = old_buffer;
-       	SCpnt->request_bufflen = old_bufflen;
 
 	DO_LOCK(flags);
 
@@ -1531,8 +1525,8 @@
 			/* target sent DISCONNECT */
 			DPRINTK(debug_selection, DEBUG_LEAD "target disconnected at %d/%d\n",
 				CMDINFO(CURRENT_SC),
-				CURRENT_SC->resid,
-				CURRENT_SC->request_bufflen);
+				scsi_get_resid(CURRENT_SC),
+				scsi_bufflen(CURRENT_SC));
 #if defined(AHA152X_STAT)
 			HOSTDATA(shpnt)->disconnections++;
 #endif
@@ -1568,18 +1562,16 @@
 #endif
 
 			/* restore old command */
-			memcpy(cmd->cmnd, sc->cmnd, sizeof(sc->cmnd));
-			cmd->request_buffer  = sc->request_buffer;
-			cmd->request_bufflen = sc->request_bufflen;
-			cmd->use_sg          = sc->use_sg;
-			cmd->cmd_len         = sc->cmd_len;
+			memcpy(cmd->cmnd, sc->aha_orig_cmnd, sizeof(cmd->cmnd));
+			cmd->cmd_len = sc->aha_orig_cmd_len;
+			scsi_set_resid(cmd, sc->aha_orig_resid);
 
-			cmd->SCp.Status = 0x02;
+			cmd->SCp.Status = SAM_STAT_CHECK_CONDITION;
 
 			HOSTDATA(shpnt)->commands--;
 			if (!HOSTDATA(shpnt)->commands)
 				SETPORT(PORTA, 0);	/* turn led off */
-		} else if(DONE_SC->SCp.Status==0x02) {
+		} else if(DONE_SC->SCp.Status==SAM_STAT_CHECK_CONDITION) {
 #if defined(AHA152X_STAT)
 			HOSTDATA(shpnt)->busfree_with_check_condition++;
 #endif
@@ -1587,13 +1579,23 @@
 			DPRINTK(debug_eh, ERR_LEAD "CHECK CONDITION found\n", CMDINFO(DONE_SC));
 #endif
 
-			if(!(DONE_SC->SCp.Status & not_issued)) {
+			if(!(DONE_SC->SCp.phase & not_issued)) {
+				struct aha152x_scdata *sc;
 				Scsi_Cmnd *ptr = DONE_SC;
 				DONE_SC=NULL;
 #if 0
 				DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr));
 #endif
 
+				/* save old command */
+				sc = SCDATA(ptr);
+				/* It was allocated in aha152x_internal_queue? */
+				BUG_ON(!sc);
+				memcpy(sc->aha_orig_cmnd, ptr->cmnd,
+				                            sizeof(ptr->cmnd));
+				sc->aha_orig_cmd_len = ptr->cmd_len;
+				sc->aha_orig_resid = scsi_get_resid(ptr);
+
 				ptr->cmnd[0]         = REQUEST_SENSE;
 				ptr->cmnd[1]         = 0;
 				ptr->cmnd[2]         = 0;
@@ -1601,10 +1603,7 @@
 				ptr->cmnd[4]         = sizeof(ptr->sense_buffer);
 				ptr->cmnd[5]         = 0;
 				ptr->cmd_len         = 6;
-				ptr->use_sg          = 0; 
-				ptr->request_buffer  = ptr->sense_buffer;
-				ptr->request_bufflen = sizeof(ptr->sense_buffer);
-			
+
 				DO_UNLOCK(flags);
 				aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done);
 				DO_LOCK(flags);
@@ -2180,7 +2179,8 @@
 	DATA_LEN=0;
 	DPRINTK(debug_datai,
 		DEBUG_LEAD "datai_init: request_bufflen=%d resid=%d\n",
-		CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+		CMDINFO(CURRENT_SC), scsi_bufflen(CURRENT_SC),
+		scsi_get_resid(CURRENT_SC));
 }
 
 static void datai_run(struct Scsi_Host *shpnt)
@@ -2293,11 +2293,12 @@
 
 static void datai_end(struct Scsi_Host *shpnt)
 {
-	CURRENT_SC->resid -= GETSTCNT();
+	CMD_INC_RESID(CURRENT_SC, -GETSTCNT());
 
 	DPRINTK(debug_datai,
 		DEBUG_LEAD "datai_end: request_bufflen=%d resid=%d stcnt=%d\n",
-		CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid, GETSTCNT());
+		CMDINFO(CURRENT_SC), scsi_bufflen(CURRENT_SC),
+		scsi_get_resid(CURRENT_SC), GETSTCNT());
 
 	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
 	SETPORT(DMACNTRL0, 0);
@@ -2318,11 +2319,12 @@
 	SETPORT(SIMODE0, 0);
 	SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE );
 
-	DATA_LEN = CURRENT_SC->resid;
+	DATA_LEN = scsi_get_resid(CURRENT_SC);
 
 	DPRINTK(debug_datao,
 		DEBUG_LEAD "datao_init: request_bufflen=%d; resid=%d\n",
-		CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+		CMDINFO(CURRENT_SC), scsi_bufflen(CURRENT_SC),
+		scsi_get_resid(CURRENT_SC));
 }
 
 static void datao_run(struct Scsi_Host *shpnt)
@@ -2346,7 +2348,7 @@
 			SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT);
 			SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++);
 			CURRENT_SC->SCp.this_residual--;
-			CURRENT_SC->resid--;
+			CMD_INC_RESID(CURRENT_SC, -1);
 			SETPORT(DMACNTRL0,WRITE_READ|ENDMA);
 		}
 
@@ -2355,7 +2357,7 @@
 			outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
 			CURRENT_SC->SCp.ptr           += 2 * data_count;
 			CURRENT_SC->SCp.this_residual -= 2 * data_count;
-			CURRENT_SC->resid             -= 2 * data_count;
+			CMD_INC_RESID(CURRENT_SC, -2 * data_count);
 	  	}
 
 		if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
@@ -2381,35 +2383,34 @@
 static void datao_end(struct Scsi_Host *shpnt)
 {
 	if(TESTLO(DMASTAT, DFIFOEMP)) {
-		int data_count = (DATA_LEN - CURRENT_SC->resid) - GETSTCNT();
+		int data_count = (DATA_LEN - scsi_get_resid(CURRENT_SC)) -
+		                                                    GETSTCNT();
 
 		DPRINTK(debug_datao, DEBUG_LEAD "datao: %d bytes to resend (%d written, %d transferred)\n",
 			CMDINFO(CURRENT_SC),
 			data_count,
-			DATA_LEN-CURRENT_SC->resid,
+			DATA_LEN - scsi_get_resid(CURRENT_SC),
 			GETSTCNT());
 
-		CURRENT_SC->resid += data_count;
+		CMD_INC_RESID(CURRENT_SC, data_count);
 
-		if(CURRENT_SC->use_sg) {
-			data_count -= CURRENT_SC->SCp.ptr - SG_ADDRESS(CURRENT_SC->SCp.buffer);
-			while(data_count>0) {
-				CURRENT_SC->SCp.buffer--;
-				CURRENT_SC->SCp.buffers_residual++;
-				data_count -= CURRENT_SC->SCp.buffer->length;
-			}
-			CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer) - data_count;
-			CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length + data_count;
-		} else {
-			CURRENT_SC->SCp.ptr           -= data_count;
-			CURRENT_SC->SCp.this_residual += data_count;
+		data_count -= CURRENT_SC->SCp.ptr -
+		                             SG_ADDRESS(CURRENT_SC->SCp.buffer);
+		while(data_count>0) {
+			CURRENT_SC->SCp.buffer--;
+			CURRENT_SC->SCp.buffers_residual++;
+			data_count -= CURRENT_SC->SCp.buffer->length;
 		}
+		CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) -
+		                                                     data_count;
+		CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length +
+		                                                     data_count;
 	}
 
 	DPRINTK(debug_datao, DEBUG_LEAD "datao_end: request_bufflen=%d; resid=%d; stcnt=%d\n",
 		CMDINFO(CURRENT_SC),
-		CURRENT_SC->request_bufflen,
-		CURRENT_SC->resid,
+		scsi_bufflen(CURRENT_SC),
+		scsi_get_resid(CURRENT_SC),
 		GETSTCNT());
 
 	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
@@ -2936,7 +2937,7 @@
 	__scsi_print_command(ptr->cmnd);
 
 	printk(KERN_DEBUG "); request_bufflen=%d; resid=%d; phase |",
-	       ptr->request_bufflen, ptr->resid);
+	       scsi_bufflen(ptr), scsi_get_resid(ptr));
 
 	if (ptr->SCp.phase & not_issued)
 		printk("not issued|");
@@ -3006,7 +3007,8 @@
 		SPRINTF("0x%02x ", ptr->cmnd[i]);
 
 	SPRINTF("); resid=%d; residual=%d; buffers=%d; phase |",
-		ptr->resid, ptr->SCp.this_residual, ptr->SCp.buffers_residual);
+		scsi_get_resid(ptr), ptr->SCp.this_residual,
+		ptr->SCp.buffers_residual);
 
 	if (ptr->SCp.phase & not_issued)
 		SPRINTF("not issued|");
@@ -3395,7 +3397,7 @@
 	PDEBUG(debug_datai, "data in");
 	PDEBUG(debug_datao, "data out");
 	PDEBUG(debug_eh, "eh");
-	PDEBUG(debug_locks, "locks");
+	PDEBUG(debug_locking, "locks");
 	PDEBUG(debug_phases, "phases");
 
 	SPRINTF("\n");
@@ -3474,6 +3476,12 @@
 	return thislength < length ? thislength : length;
 }
 
+static int aha152x_adjust_queue(struct scsi_device *device)
+{
+	blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH);
+	return 0;
+}
+
 static struct scsi_host_template aha152x_driver_template = {
 	.module				= THIS_MODULE,
 	.name				= AHA152X_REVID,
@@ -3490,6 +3498,7 @@
 	.sg_tablesize			= SG_ALL,
 	.cmd_per_lun			= 1,
 	.use_clustering			= DISABLE_CLUSTERING,
+	.slave_alloc			= aha152x_adjust_queue,
 };
 
 #if !defined(PCMCIA)
diff --git a/drivers/scsi/aha152x.h b/drivers/scsi/aha152x.h
index d2add24..ac4bfa438b 100644
--- a/drivers/scsi/aha152x.h
+++ b/drivers/scsi/aha152x.h
@@ -298,7 +298,7 @@
 enum {
   debug_procinfo  = 0x0001,
   debug_queue     = 0x0002,
-  debug_locks     = 0x0004,
+  debug_locking   = 0x0004,
   debug_intr      = 0x0008,
   debug_selection = 0x0010,
   debug_msgo      = 0x0020,
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 286ab83..a055a96 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -2284,9 +2284,12 @@
 	if (period < 8)
 		period = 8;
 	if (period < 10) {
-		ppr_options |= MSG_EXT_PPR_DT_REQ;
-		if (period == 8)
-			ppr_options |= MSG_EXT_PPR_IU_REQ;
+		if (spi_max_width(starget)) {
+			ppr_options |= MSG_EXT_PPR_DT_REQ;
+			if (period == 8)
+				ppr_options |= MSG_EXT_PPR_IU_REQ;
+		} else
+			period = 10;
 	}
 
 	dt = ppr_options & MSG_EXT_PPR_DT_REQ;
@@ -2365,7 +2368,7 @@
 		printf("%s: %s DT\n", ahd_name(ahd), 
 		       dt ? "enabling" : "disabling");
 #endif
-	if (dt) {
+	if (dt && spi_max_width(starget)) {
 		ppr_options |= MSG_EXT_PPR_DT_REQ;
 		if (!width)
 			ahd_linux_set_width(starget, 1);
@@ -2447,7 +2450,7 @@
 		       iu ? "enabling" : "disabling");
 #endif
 
-	if (iu) {
+	if (iu && spi_max_width(starget)) {
 		ppr_options |= MSG_EXT_PPR_IU_REQ;
 		ppr_options |= MSG_EXT_PPR_DT_REQ; /* IU requires DT */
 	}
@@ -2487,7 +2490,7 @@
 		       rdstrm  ? "enabling" : "disabling");
 #endif
 
-	if (rdstrm)
+	if (rdstrm && spi_max_width(starget))
 		ppr_options |= MSG_EXT_PPR_RD_STRM;
 
 	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
@@ -2523,7 +2526,7 @@
 		       wrflow ? "enabling" : "disabling");
 #endif
 
-	if (wrflow)
+	if (wrflow && spi_max_width(starget))
 		ppr_options |= MSG_EXT_PPR_WR_FLOW;
 
 	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
@@ -2567,7 +2570,7 @@
 		       rti ? "enabling" : "disabling");
 #endif
 
-	if (rti)
+	if (rti && spi_max_width(starget))
 		ppr_options |= MSG_EXT_PPR_RTI;
 
 	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
@@ -2603,7 +2606,7 @@
 		       pcomp ? "Enable" : "Disable");
 #endif
 
-	if (pcomp) {
+	if (pcomp && spi_max_width(starget)) {
 		uint8_t precomp;
 
 		if (ahd->unit < ARRAY_SIZE(aic79xx_iocell_info)) {
@@ -2647,7 +2650,7 @@
 	unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ;
 	unsigned long flags;
 
-	if (hold)
+	if (hold && spi_max_width(starget))
 		ppr_options |= MSG_EXT_PPR_HOLD_MCS;
 
 	ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
index 75733b0..f350b5e 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -1701,7 +1701,16 @@
 	if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0
 	 && maxsync < AHC_SYNCRATE_ULTRA2)
 		maxsync = AHC_SYNCRATE_ULTRA2;
-	
+
+	/* Now set the maxsync based on the card capabilities
+	 * DT is already done above */
+	if ((ahc->features & (AHC_DT | AHC_ULTRA2)) == 0
+	    && maxsync < AHC_SYNCRATE_ULTRA)
+		maxsync = AHC_SYNCRATE_ULTRA;
+	if ((ahc->features & (AHC_DT | AHC_ULTRA2 | AHC_ULTRA)) == 0
+	    && maxsync < AHC_SYNCRATE_FAST)
+		maxsync = AHC_SYNCRATE_FAST;
+
 	for (syncrate = &ahc_syncrates[maxsync];
 	     syncrate->rate != NULL;
 	     syncrate++) {
@@ -1765,6 +1774,17 @@
 	else
 		scsirate &= SXFR;
 
+	/* now set maxsync based on card capabilities */
+	if ((ahc->features & AHC_DT) == 0 && maxsync < AHC_SYNCRATE_ULTRA2)
+		maxsync = AHC_SYNCRATE_ULTRA2;
+	if ((ahc->features & (AHC_DT | AHC_ULTRA2)) == 0
+	    && maxsync < AHC_SYNCRATE_ULTRA)
+		maxsync = AHC_SYNCRATE_ULTRA;
+	if ((ahc->features & (AHC_DT | AHC_ULTRA2 | AHC_ULTRA)) == 0
+	    && maxsync < AHC_SYNCRATE_FAST)
+		maxsync = AHC_SYNCRATE_FAST;
+
+
 	syncrate = &ahc_syncrates[maxsync];
 	while (syncrate->rate != NULL) {
 
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 1803ab6..2e9c38f 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -2317,8 +2317,13 @@
 
 	if (period < 9)
 		period = 9;	/* 12.5ns is our minimum */
-	if (period == 9)
-		ppr_options |= MSG_EXT_PPR_DT_REQ;
+	if (period == 9) {
+		if (spi_max_width(starget))
+			ppr_options |= MSG_EXT_PPR_DT_REQ;
+		else
+			/* need wide for DT and need DT for 12.5 ns */
+			period = 10;
+	}
 
 	ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0,
 			    starget->channel + 'A', ROLE_INITIATOR);
@@ -2381,7 +2386,7 @@
 	unsigned long flags;
 	struct ahc_syncrate *syncrate;
 
-	if (dt) {
+	if (dt && spi_max_width(starget)) {
 		ppr_options |= MSG_EXT_PPR_DT_REQ;
 		if (!width)
 			ahc_linux_set_width(starget, 1);
diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c
index c520e5b..3dce618 100644
--- a/drivers/scsi/aic94xx/aic94xx_dev.c
+++ b/drivers/scsi/aic94xx/aic94xx_dev.c
@@ -126,7 +126,7 @@
 		if (w76 & 0x100) /* NCQ? */
 			qdepth = (w75 & 0x1F) + 1;
 		asd_ddbsite_write_dword(asd_ha, ddb, SATA_TAG_ALLOC_MASK,
-					(1<<qdepth)-1);
+					(1ULL<<qdepth)-1);
 		asd_ddbsite_write_byte(asd_ha, ddb, NUM_SATA_TAGS, qdepth);
 	}
 	if (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM ||
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index 1c0d757..63bcde2 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -81,6 +81,9 @@
 	.use_clustering		= ENABLE_CLUSTERING,
 	.eh_device_reset_handler	= sas_eh_device_reset_handler,
 	.eh_bus_reset_handler	= sas_eh_bus_reset_handler,
+	.slave_alloc		= sas_slave_alloc,
+	.target_destroy		= sas_target_destroy,
+	.ioctl			= sas_ioctl,
 };
 
 static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha)
@@ -462,7 +465,7 @@
 					    sizeof(struct asd_dma_tok),
 					    0,
 					    SLAB_HWCACHE_ALIGN,
-					    NULL, NULL);
+					    NULL);
 		if (!asd_dma_token_cache) {
 			asd_printk("couldn't create dma token cache\n");
 			return -ENOMEM;
@@ -474,7 +477,7 @@
 						   sizeof(struct asd_ascb),
 						   0,
 						   SLAB_HWCACHE_ALIGN,
-						   NULL, NULL);
+						   NULL);
 		if (!asd_ascb_cache) {
 			asd_printk("couldn't create ascb cache\n");
 			goto Err;
@@ -583,7 +586,7 @@
 		goto Err;
 	}
 	asd_ha->pcidev = dev;
-	asd_ha->sas_ha.pcidev = asd_ha->pcidev;
+	asd_ha->sas_ha.dev = &asd_ha->pcidev->dev;
 	asd_ha->sas_ha.lldd_ha = asd_ha;
 
 	asd_ha->name = asd_dev->name;
@@ -602,8 +605,6 @@
 		goto Err_free;
 	}
 
-
-
 	err = asd_dev->setup(asd_ha);
 	if (err)
 		goto Err_free;
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
index e2ad5be..ab13824 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -74,8 +74,13 @@
 		return 0;
 	}
 
-	num_sg = pci_map_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
-			    task->data_dir);
+	/* STP tasks come from libata which has already mapped
+	 * the SG list */
+	if (sas_protocol_ata(task->task_proto))
+		num_sg = task->num_scatter;
+	else
+		num_sg = pci_map_sg(asd_ha->pcidev, task->scatter,
+				    task->num_scatter, task->data_dir);
 	if (num_sg == 0)
 		return -ENOMEM;
 
@@ -120,8 +125,9 @@
 
 	return 0;
 err_unmap:
-	pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
-		     task->data_dir);
+	if (sas_protocol_ata(task->task_proto))
+		pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
+			     task->data_dir);
 	return res;
 }
 
@@ -142,8 +148,9 @@
 	}
 
 	asd_free_coherent(asd_ha, ascb->sg_arr);
-	pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
-		     task->data_dir);
+	if (task->task_proto != SAS_PROTOCOL_STP)
+		pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
+			     task->data_dir);
 }
 
 /* ---------- Task complete tasklet ---------- */
@@ -391,7 +398,6 @@
 
 	scb->ata_task.total_xfer_len = cpu_to_le32(task->total_xfer_len);
 	scb->ata_task.fis = task->ata_task.fis;
-	scb->ata_task.fis.fis_type = 0x27;
 	if (likely(!task->ata_task.device_control_reg_update))
 		scb->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
 	scb->ata_task.fis.flags &= 0xF0; /* PM_PORT field shall be 0 */
@@ -445,7 +451,7 @@
 	struct scb *scb;
 
 	pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_req, 1,
-		   PCI_DMA_FROMDEVICE);
+		   PCI_DMA_TODEVICE);
 	pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_resp, 1,
 		   PCI_DMA_FROMDEVICE);
 
@@ -480,7 +486,7 @@
 
 	BUG_ON(!task);
 	pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_req, 1,
-		     PCI_DMA_FROMDEVICE);
+		     PCI_DMA_TODEVICE);
 	pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_resp, 1,
 		     PCI_DMA_FROMDEVICE);
 }
diff --git a/drivers/scsi/arm/Kconfig b/drivers/scsi/arm/Kconfig
index d006a8c..7236143 100644
--- a/drivers/scsi/arm/Kconfig
+++ b/drivers/scsi/arm/Kconfig
@@ -74,15 +74,6 @@
 	  This enables support for the Cumana SCSI I card. If you have an
 	  Acorn system with one of these, say Y. If unsure, say N.
 
-config SCSI_ECOSCSI
-	tristate "EcoScsi support (EXPERIMENTAL)"
-	depends on ARCH_ACORN && EXPERIMENTAL && (ARCH_ARC || ARCH_A5K) && SCSI
-	select SCSI_SPI_ATTRS
-	help
-	  This enables support for the EcoSCSI card -- a small card that sits
-	  in the Econet socket. If you have an Acorn system with one of these,
-	  say Y. If unsure, say N.
-
 config SCSI_OAK1
 	tristate "Oak SCSI support (EXPERIMENTAL)"
 	depends on ARCH_ACORN && EXPERIMENTAL && SCSI
diff --git a/drivers/scsi/arm/Makefile b/drivers/scsi/arm/Makefile
index e8db179..16c3e86 100644
--- a/drivers/scsi/arm/Makefile
+++ b/drivers/scsi/arm/Makefile
@@ -8,7 +8,6 @@
 obj-$(CONFIG_SCSI_ARXESCSI)	+= arxescsi.o fas216.o queue.o msgqueue.o
 obj-$(CONFIG_SCSI_CUMANA_1)	+= cumana_1.o
 obj-$(CONFIG_SCSI_CUMANA_2)	+= cumana_2.o fas216.o queue.o msgqueue.o
-obj-$(CONFIG_SCSI_ECOSCSI)	+= ecoscsi.o
 obj-$(CONFIG_SCSI_OAK1)		+= oak.o
 obj-$(CONFIG_SCSI_POWERTECSCSI)	+= powertec.o fas216.o queue.o msgqueue.o
 obj-$(CONFIG_SCSI_EESOXSCSI)	+= eesox.o fas216.o queue.o msgqueue.o
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index cf9a21c..49d838e 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -24,7 +24,7 @@
 
 #define CUMANASCSI_PUBLIC_RELEASE 1
 
-#define NCR5380_implementation_fields	int port, ctrl
+#define priv(host)			((struct NCR5380_hostdata *)(host)->hostdata)
 #define NCR5380_local_declare()		struct Scsi_Host *_instance
 #define NCR5380_setup(instance)		_instance = instance
 #define NCR5380_read(reg)		cumanascsi_read(_instance, reg)
@@ -33,6 +33,11 @@
 #define NCR5380_queue_command		cumanascsi_queue_command
 #define NCR5380_proc_info		cumanascsi_proc_info
 
+#define NCR5380_implementation_fields	\
+	unsigned ctrl;			\
+	void __iomem *base;		\
+	void __iomem *dma
+
 #define BOARD_NORMAL	0
 #define BOARD_NCR53C400	1
 
@@ -47,193 +52,163 @@
 	return "";
 }
 
-#ifdef NOT_EFFICIENT
-#define CTRL(p,v)     outb(*ctrl = (v), (p) - 577)
-#define STAT(p)       inb((p)+1)
-#define IN(p)         inb((p))
-#define OUT(v,p)      outb((v), (p))
-#else
-#define CTRL(p,v)	(p[-2308] = (*ctrl = (v)))
-#define STAT(p)		(p[4])
-#define IN(p)		(*(p))
-#define IN2(p)		((unsigned short)(*(volatile unsigned long *)(p)))
-#define OUT(v,p)	(*(p) = (v))
-#define OUT2(v,p)	(*((volatile unsigned long *)(p)) = (v))
-#endif
-#define L(v)		(((v)<<16)|((v) & 0x0000ffff))
-#define H(v)		(((v)>>16)|((v) & 0xffff0000))
+#define CTRL	0x16fc
+#define STAT	0x2004
+#define L(v)	(((v)<<16)|((v) & 0x0000ffff))
+#define H(v)	(((v)>>16)|((v) & 0xffff0000))
 
 static inline int
-NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr, int len)
+NCR5380_pwrite(struct Scsi_Host *host, unsigned char *addr, int len)
 {
-  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
-  int oldctrl = *ctrl;
   unsigned long *laddr;
-#ifdef NOT_EFFICIENT
-  int iobase = instance->io_port;
-  int dma_io = iobase & ~(0x3C0000>>2);
-#else
-  volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
-  volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000);
-#endif
+  void __iomem *dma = priv(host)->dma + 0x2000;
 
   if(!len) return 0;
 
-  CTRL(iobase, 0x02);
+  writeb(0x02, priv(host)->base + CTRL);
   laddr = (unsigned long *)addr;
   while(len >= 32)
   {
-    int status;
+    unsigned int status;
     unsigned long v;
-    status = STAT(iobase);
+    status = readb(priv(host)->base + STAT);
     if(status & 0x80)
       goto end;
     if(!(status & 0x40))
       continue;
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
+    v=*laddr++; writew(L(v), dma); writew(H(v), dma);
     len -= 32;
     if(len == 0)
       break;
   }
 
   addr = (unsigned char *)laddr;
-  CTRL(iobase, 0x12);
+  writeb(0x12, priv(host)->base + CTRL);
+
   while(len > 0)
   {
-    int status;
-    status = STAT(iobase);
+    unsigned int status;
+    status = readb(priv(host)->base + STAT);
     if(status & 0x80)
       goto end;
     if(status & 0x40)
     {
-      OUT(*addr++, dma_io);
+      writeb(*addr++, dma);
       if(--len == 0)
         break;
     }
 
-    status = STAT(iobase);
+    status = readb(priv(host)->base + STAT);
     if(status & 0x80)
       goto end;
     if(status & 0x40)
     {
-      OUT(*addr++, dma_io);
+      writeb(*addr++, dma);
       if(--len == 0)
         break;
     }
   }
 end:
-  CTRL(iobase, oldctrl|0x40);
+  writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL);
   return len;
 }
 
 static inline int
-NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr, int len)
+NCR5380_pread(struct Scsi_Host *host, unsigned char *addr, int len)
 {
-  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
-  int oldctrl = *ctrl;
   unsigned long *laddr;
-#ifdef NOT_EFFICIENT
-  int iobase = instance->io_port;
-  int dma_io = iobase & ~(0x3C0000>>2);
-#else
-  volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
-  volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000);
-#endif
+  void __iomem *dma = priv(host)->dma + 0x2000;
 
   if(!len) return 0;
 
-  CTRL(iobase, 0x00);
+  writeb(0x00, priv(host)->base + CTRL);
   laddr = (unsigned long *)addr;
   while(len >= 32)
   {
-    int status;
-    status = STAT(iobase);
+    unsigned int status;
+    status = readb(priv(host)->base + STAT);
     if(status & 0x80)
       goto end;
     if(!(status & 0x40))
       continue;
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    *laddr++ = readw(dma) | (readw(dma) << 16);
+    *laddr++ = readw(dma) | (readw(dma) << 16);
+    *laddr++ = readw(dma) | (readw(dma) << 16);
+    *laddr++ = readw(dma) | (readw(dma) << 16);
+    *laddr++ = readw(dma) | (readw(dma) << 16);
+    *laddr++ = readw(dma) | (readw(dma) << 16);
+    *laddr++ = readw(dma) | (readw(dma) << 16);
+    *laddr++ = readw(dma) | (readw(dma) << 16);
     len -= 32;
     if(len == 0)
       break;
   }
 
   addr = (unsigned char *)laddr;
-  CTRL(iobase, 0x10);
+  writeb(0x10, priv(host)->base + CTRL);
+
   while(len > 0)
   {
-    int status;
-    status = STAT(iobase);
+    unsigned int status;
+    status = readb(priv(host)->base + STAT);
     if(status & 0x80)
       goto end;
     if(status & 0x40)
     {
-      *addr++ = IN(dma_io);
+      *addr++ = readb(dma);
       if(--len == 0)
         break;
     }
 
-    status = STAT(iobase);
+    status = readb(priv(host)->base + STAT);
     if(status & 0x80)
       goto end;
     if(status & 0x40)
     {
-      *addr++ = IN(dma_io);
+      *addr++ = readb(dma);
       if(--len == 0)
         break;
     }
   }
 end:
-  CTRL(iobase, oldctrl|0x40);
+  writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL);
   return len;
 }
 
-#undef STAT
-#undef CTRL
-#undef IN
-#undef OUT
-
-#define CTRL(p,v) outb(*ctrl = (v), (p) - 577)
-
-static char cumanascsi_read(struct Scsi_Host *instance, int reg)
+static unsigned char cumanascsi_read(struct Scsi_Host *host, unsigned int reg)
 {
-	unsigned int iobase = instance->io_port;
-	int i;
-	int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+	void __iomem *base = priv(host)->base;
+	unsigned char val;
 
-	CTRL(iobase, 0);
-	i = inb(iobase + 64 + reg);
-	CTRL(iobase, 0x40);
+	writeb(0, base + CTRL);
 
-	return i;
+	val = readb(base + 0x2100 + (reg << 2));
+
+	priv(host)->ctrl = 0x40;
+	writeb(0x40, base + CTRL);
+
+	return val;
 }
 
-static void cumanascsi_write(struct Scsi_Host *instance, int reg, int value)
+static void cumanascsi_write(struct Scsi_Host *host, unsigned int reg, unsigned int value)
 {
-	int iobase = instance->io_port;
-	int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+	void __iomem *base = priv(host)->base;
 
-	CTRL(iobase, 0);
-	outb(value, iobase + 64 + reg);
-	CTRL(iobase, 0x40);
+	writeb(0, base + CTRL);
+
+	writeb(value, base + 0x2100 + (reg << 2));
+
+	priv(host)->ctrl = 0x40;
+	writeb(0x40, base + CTRL);
 }
 
-#undef CTRL
-
 #include "../NCR5380.c"
 
 static struct scsi_host_template cumanascsi_template = {
@@ -256,32 +231,46 @@
 cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
 	struct Scsi_Host *host;
-	int ret = -ENOMEM;
+	int ret;
 
-	host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
-	if (!host)
+	ret = ecard_request_resources(ec);
+	if (ret)
 		goto out;
 
-        host->io_port = ecard_address(ec, ECARD_IOC, ECARD_SLOW) + 0x800;
+	host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
+	if (!host) {
+		ret = -ENOMEM;
+		goto out_release;
+	}
+
+	priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW),
+				   ecard_resource_len(ec, ECARD_RES_IOCSLOW));
+	priv(host)->dma = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
+				  ecard_resource_len(ec, ECARD_RES_MEMC));
+	if (!priv(host)->base || !priv(host)->dma) {
+		ret = -ENOMEM;
+		goto out_unmap;
+	}
+
 	host->irq = ec->irq;
 
 	NCR5380_init(host, 0);
 
+        priv(host)->ctrl = 0;
+        writeb(0, priv(host)->base + CTRL);
+
 	host->n_io_port = 255;
 	if (!(request_region(host->io_port, host->n_io_port, "CumanaSCSI-1"))) {
 		ret = -EBUSY;
-		goto out_free;
+		goto out_unmap;
 	}
 
-        ((struct NCR5380_hostdata *)host->hostdata)->ctrl = 0;
-        outb(0x00, host->io_port - 577);
-
 	ret = request_irq(host->irq, cumanascsi_intr, IRQF_DISABLED,
 			  "CumanaSCSI-1", host);
 	if (ret) {
 		printk("scsi%d: IRQ%d not free: %d\n",
 		    host->host_no, host->irq, ret);
-		goto out_release;
+		goto out_unmap;
 	}
 
 	printk("scsi%d: at port 0x%08lx irq %d",
@@ -301,10 +290,12 @@
 
  out_free_irq:
 	free_irq(host->irq, host);
- out_release:
-	release_region(host->io_port, host->n_io_port);
- out_free:
+ out_unmap:
+	iounmap(priv(host)->base);
+	iounmap(priv(host)->dma);
 	scsi_host_put(host);
+ out_release:
+	ecard_release_resources(ec);
  out:
 	return ret;
 }
@@ -318,8 +309,10 @@
 	scsi_remove_host(host);
 	free_irq(host->irq, host);
 	NCR5380_exit(host);
-	release_region(host->io_port, host->n_io_port);
+	iounmap(priv(host)->base);
+	iounmap(priv(host)->dma);
 	scsi_host_put(host);
+	ecard_release_resources(ec);
 }
 
 static const struct ecard_id cumanascsi1_cids[] = {
diff --git a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c
deleted file mode 100644
index 378e7af..0000000
--- a/drivers/scsi/arm/ecoscsi.c
+++ /dev/null
@@ -1,236 +0,0 @@
-#define AUTOSENSE
-/* #define PSEUDO_DMA */
-
-/*
- * EcoSCSI Generic NCR5380 driver
- *
- * Copyright 1995, Russell King
- *
- * ALPHA RELEASE 1.
- *
- * For more information, please consult
- *
- * NCR 5380 Family
- * SCSI Protocol Controller
- * Databook
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * 1+ (719) 578-3400
- * 1+ (800) 334-5454
- */
-
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/blkdev.h>
-
-#include <asm/io.h>
-#include <asm/system.h>
-
-#include "../scsi.h"
-#include <scsi/scsi_host.h>
-
-#define NCR5380_implementation_fields	int port, ctrl
-#define NCR5380_local_declare()		struct Scsi_Host *_instance
-#define NCR5380_setup(instance)		_instance = instance
-
-#define NCR5380_read(reg)		ecoscsi_read(_instance, reg)
-#define NCR5380_write(reg, value)	ecoscsi_write(_instance, reg, value)
-
-#define NCR5380_intr			ecoscsi_intr
-#define NCR5380_queue_command		ecoscsi_queue_command
-#define NCR5380_proc_info		ecoscsi_proc_info
-
-#include "../NCR5380.h"
-
-#define ECOSCSI_PUBLIC_RELEASE 1
-
-static char ecoscsi_read(struct Scsi_Host *instance, int reg)
-{
-  int iobase = instance->io_port;
-  outb(reg | 8, iobase);
-  return inb(iobase + 1);
-}
-
-static void ecoscsi_write(struct Scsi_Host *instance, int reg, int value)
-{
-  int iobase = instance->io_port;
-  outb(reg | 8, iobase);
-  outb(value, iobase + 1);
-}
-
-/*
- * Function : ecoscsi_setup(char *str, int *ints)
- *
- * Purpose : LILO command line initialization of the overrides array,
- *
- * Inputs : str - unused, ints - array of integer parameters with ints[0]
- *	equal to the number of ints.
- *
- */
-
-void ecoscsi_setup(char *str, int *ints)
-{
-}
-
-const char * ecoscsi_info (struct Scsi_Host *spnt)
-{
-	return "";
-}
-
-#if 0
-#define STAT(p) inw(p + 144)
-
-static inline int NCR5380_pwrite(struct Scsi_Host *host, unsigned char *addr,
-              int len)
-{
-  int iobase = host->io_port;
-printk("writing %p len %d\n",addr, len);
-  if(!len) return -1;
-
-  while(1)
-  {
-    int status;
-    while(((status = STAT(iobase)) & 0x100)==0);
-  }
-}
-
-static inline int NCR5380_pread(struct Scsi_Host *host, unsigned char *addr,
-              int len)
-{
-  int iobase = host->io_port;
-  int iobase2= host->io_port + 0x100;
-  unsigned char *start = addr;
-  int s;
-printk("reading %p len %d\n",addr, len);
-  outb(inb(iobase + 128), iobase + 135);
-  while(len > 0)
-  {
-    int status,b,i, timeout;
-    timeout = 0x07FFFFFF;
-    while(((status = STAT(iobase)) & 0x100)==0)
-    {
-      timeout--;
-      if(status & 0x200 || !timeout)
-      {
-        printk("status = %p\n",status);
-        outb(0, iobase + 135);
-        return 1;
-      }
-    }
-    if(len >= 128)
-    {
-      for(i=0; i<64; i++)
-      {
-        b = inw(iobase + 136);
-        *addr++ = b;
-        *addr++ = b>>8;
-      }
-      len -= 128;
-    }
-    else
-    {
-      b = inw(iobase + 136);
-      *addr ++ = b;
-      len -= 1;
-      if(len)
-        *addr ++ = b>>8;
-      len -= 1;
-    }
-  }
-  outb(0, iobase + 135);
-  printk("first bytes = %02X %02X %02X %20X %02X %02X %02X\n",*start, start[1], start[2], start[3], start[4], start[5], start[6]);
-  return 1;
-}
-#endif
-#undef STAT
-
-#define BOARD_NORMAL	0
-#define BOARD_NCR53C400	1
-
-#include "../NCR5380.c"
-
-static struct scsi_host_template ecoscsi_template =  {
-	.module		= THIS_MODULE,
-	.name		= "Serial Port EcoSCSI NCR5380",
-	.proc_name	= "ecoscsi",
-	.info		= ecoscsi_info,
-	.queuecommand	= ecoscsi_queue_command,
-	.eh_abort_handler	= NCR5380_abort,
-	.eh_bus_reset_handler	= NCR5380_bus_reset,
-	.can_queue	= 16,
-	.this_id	= 7,
-	.sg_tablesize	= SG_ALL,
-	.cmd_per_lun	= 2,
-	.use_clustering	= DISABLE_CLUSTERING
-};
-
-static struct Scsi_Host *host;
-
-static int __init ecoscsi_init(void)
-{
-
-	host = scsi_host_alloc(tpnt, sizeof(struct NCR5380_hostdata));
-	if (!host)
-		return 0;
-
-	host->io_port = 0x80ce8000;
-	host->n_io_port = 144;
-	host->irq = IRQ_NONE;
-
-	if (!(request_region(host->io_port, host->n_io_port, "ecoscsi")) )
-		goto unregister_scsi;
-
-	ecoscsi_write(host, MODE_REG, 0x20);		/* Is it really SCSI? */
-	if (ecoscsi_read(host, MODE_REG) != 0x20) /* Write to a reg.    */
-		goto release_reg;
-
-	ecoscsi_write(host, MODE_REG, 0x00 );		/* it back.	      */
-	if (ecoscsi_read(host, MODE_REG) != 0x00)
-		goto release_reg;
-
-	NCR5380_init(host, 0);
-
-	printk("scsi%d: at port 0x%08lx irqs disabled", host->host_no, host->io_port);
-	printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
-		host->can_queue, host->cmd_per_lun, ECOSCSI_PUBLIC_RELEASE);
-	printk("\nscsi%d:", host->host_no);
-	NCR5380_print_options(host);
-	printk("\n");
-
-	scsi_add_host(host, NULL); /* XXX handle failure */
-	scsi_scan_host(host);
-	return 0;
-
-release_reg:
-	release_region(host->io_port, host->n_io_port);
-unregister_scsi:
-	scsi_host_put(host);
-	return -ENODEV;
-}
-
-static void __exit ecoscsi_exit(void)
-{
-	scsi_remove_host(host);
-
-	if (shpnt->irq != IRQ_NONE)
-		free_irq(shpnt->irq, NULL);
-	NCR5380_exit(host);
-	if (shpnt->io_port)
-		release_region(shpnt->io_port, shpnt->n_io_port);
-
-	scsi_host_put(host);
-	return 0;
-}
-
-module_init(ecoscsi_init);
-module_exit(ecoscsi_exit);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("Econet-SCSI driver for Acorn machines");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c
index c21b839..849cdf8 100644
--- a/drivers/scsi/arm/oak.c
+++ b/drivers/scsi/arm/oak.c
@@ -23,15 +23,18 @@
 
 #define OAKSCSI_PUBLIC_RELEASE 1
 
-#define NCR5380_read(reg)		oakscsi_read(_instance, reg)
-#define NCR5380_write(reg, value)	oakscsi_write(_instance, reg, value)
+#define priv(host)			((struct NCR5380_hostdata *)(host)->hostdata)
+#define NCR5380_local_declare()		void __iomem *_base
+#define NCR5380_setup(host)		_base = priv(host)->base
+
+#define NCR5380_read(reg)		readb(_base + ((reg) << 2))
+#define NCR5380_write(reg, value)	writeb(value, _base + ((reg) << 2))
 #define NCR5380_intr			oakscsi_intr
 #define NCR5380_queue_command		oakscsi_queue_command
 #define NCR5380_proc_info		oakscsi_proc_info
 
-#define NCR5380_implementation_fields	int port, ctrl
-#define NCR5380_local_declare()		struct Scsi_Host *_instance
-#define NCR5380_setup(instance)		_instance = instance
+#define NCR5380_implementation_fields	\
+	void __iomem *base
 
 #define BOARD_NORMAL	0
 #define BOARD_NCR53C400	1
@@ -39,60 +42,62 @@
 #include "../NCR5380.h"
 
 #undef START_DMA_INITIATOR_RECEIVE_REG
-#define START_DMA_INITIATOR_RECEIVE_REG (7 + 128)
+#define START_DMA_INITIATOR_RECEIVE_REG	(128 + 7)
 
 const char * oakscsi_info (struct Scsi_Host *spnt)
 {
 	return "";
 }
 
-#define STAT(p)   inw(p + 144)
-extern void inswb(int from, void *to, int len);
+#define STAT	((128 + 16) << 2)
+#define DATA	((128 + 8) << 2)
 
 static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
               int len)
 {
-  int iobase = instance->io_port;
+  void __iomem *base = priv(instance)->base;
+
 printk("writing %p len %d\n",addr, len);
   if(!len) return -1;
 
   while(1)
   {
     int status;
-    while(((status = STAT(iobase)) & 0x100)==0);
+    while (((status = readw(base + STAT)) & 0x100)==0);
   }
 }
 
 static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
               int len)
 {
-  int iobase = instance->io_port;
+  void __iomem *base = priv(instance)->base;
 printk("reading %p len %d\n", addr, len);
   while(len > 0)
   {
-    int status, timeout;
+    unsigned int status, timeout;
     unsigned long b;
     
     timeout = 0x01FFFFFF;
     
-    while(((status = STAT(iobase)) & 0x100)==0)
+    while (((status = readw(base + STAT)) & 0x100)==0)
     {
       timeout--;
       if(status & 0x200 || !timeout)
       {
-        printk("status = %08X\n",status);
+        printk("status = %08X\n", status);
         return 1;
       }
     }
+
     if(len >= 128)
     {
-      inswb(iobase + 136, addr, 128);
+      readsw(base + DATA, addr, 128);
       addr += 128;
       len -= 128;
     }
     else
     {
-      b = (unsigned long) inw(iobase + 136);
+      b = (unsigned long) readw(base + DATA);
       *addr ++ = b;
       len -= 1;
       if(len)
@@ -103,10 +108,8 @@
   return 0;
 }
 
-#define oakscsi_read(instance,reg)	(inb((instance)->io_port + (reg)))
-#define oakscsi_write(instance,reg,val)	(outb((val), (instance)->io_port + (reg)))
-
 #undef STAT
+#undef DATA
 
 #include "../NCR5380.c"
 
@@ -132,18 +135,26 @@
 	struct Scsi_Host *host;
 	int ret = -ENOMEM;
 
-	host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata));
-	if (!host)
+	ret = ecard_request_resources(ec);
+	if (ret)
 		goto out;
 
-	host->io_port = ecard_address(ec, ECARD_MEMC, 0);
+	host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata));
+	if (!host) {
+		ret = -ENOMEM;
+		goto release;
+	}
+
+	priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC),
+				   ecard_resource_len(ec, ECARD_RES_MEMC));
+	if (!priv(host)->base) {
+		ret = -ENOMEM;
+		goto unreg;
+	}
+
 	host->irq = IRQ_NONE;
 	host->n_io_port = 255;
 
-	ret = -EBUSY;
-	if (!request_region (host->io_port, host->n_io_port, "Oak SCSI"))
-		goto unreg;
-
 	NCR5380_init(host, 0);
 
 	printk("scsi%d: at port 0x%08lx irqs disabled",
@@ -156,15 +167,17 @@
 
 	ret = scsi_add_host(host, &ec->dev);
 	if (ret)
-		goto out_release;
+		goto out_unmap;
 
 	scsi_scan_host(host);
 	goto out;
 
- out_release:
-	release_region(host->io_port, host->n_io_port);
+ out_unmap:
+	iounmap(priv(host)->base);
  unreg:
 	scsi_host_put(host);
+ release:
+	ecard_release_resources(ec);
  out:
 	return ret;
 }
@@ -177,8 +190,9 @@
 	scsi_remove_host(host);
 
 	NCR5380_exit(host);
-	release_region(host->io_port, host->n_io_port);
+	iounmap(priv(host)->base);
 	scsi_host_put(host);
+	ecard_release_resources(ec);
 }
 
 static const struct ecard_id oakscsi_cids[] = {
diff --git a/drivers/scsi/bvme6000_scsi.c b/drivers/scsi/bvme6000_scsi.c
index 012cdea..cac3540 100644
--- a/drivers/scsi/bvme6000_scsi.c
+++ b/drivers/scsi/bvme6000_scsi.c
@@ -74,6 +74,7 @@
 		goto out_put_host;
 	}
 
+	dev_set_drvdata(dev, host);
 	scsi_scan_host(host);
 
 	return 0;
@@ -89,7 +90,7 @@
 static __devexit int
 bvme6000_device_remove(struct device *dev)
 {
-	struct Scsi_Host *host = dev_to_shost(dev);
+	struct Scsi_Host *host = dev_get_drvdata(dev);
 	struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
 
 	scsi_remove_host(host);
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 2e2362d..502732a 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -173,20 +173,20 @@
 };
 MODULE_DEVICE_TABLE(pci,dptids);
 
-static int adpt_detect(struct scsi_host_template* sht)
+static void adpt_exit(void);
+
+static int adpt_detect(void)
 {
 	struct pci_dev *pDev = NULL;
 	adpt_hba* pHba;
 
-	adpt_init();
-
 	PINFO("Detecting Adaptec I2O RAID controllers...\n");
 
         /* search for all Adatpec I2O RAID cards */
 	while ((pDev = pci_get_device( PCI_DPT_VENDOR_ID, PCI_ANY_ID, pDev))) {
 		if(pDev->device == PCI_DPT_DEVICE_ID ||
 		   pDev->device == PCI_DPT_RAPTOR_DEVICE_ID){
-			if(adpt_install_hba(sht, pDev) ){
+			if(adpt_install_hba(pDev) ){
 				PERROR("Could not Init an I2O RAID device\n");
 				PERROR("Will not try to detect others.\n");
 				return hba_count-1;
@@ -248,34 +248,33 @@
 	}
 
 	for (pHba = hba_chain; pHba; pHba = pHba->next) {
-		if( adpt_scsi_register(pHba,sht) < 0){
+		if (adpt_scsi_register(pHba) < 0) {
 			adpt_i2o_delete_hba(pHba);
 			continue;
 		}
 		pHba->initialized = TRUE;
 		pHba->state &= ~DPTI_STATE_RESET;
+		scsi_scan_host(pHba->host);
 	}
 
 	// Register our control device node
 	// nodes will need to be created in /dev to access this
 	// the nodes can not be created from within the driver
 	if (hba_count && register_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER, &adpt_fops)) {
-		adpt_i2o_sys_shutdown();
+		adpt_exit();
 		return 0;
 	}
 	return hba_count;
 }
 
 
-/*
- * scsi_unregister will be called AFTER we return. 
- */
-static int adpt_release(struct Scsi_Host *host)
+static int adpt_release(adpt_hba *pHba)
 {
-	adpt_hba* pHba = (adpt_hba*) host->hostdata[0];
+	struct Scsi_Host *shost = pHba->host;
+	scsi_remove_host(shost);
 //	adpt_i2o_quiesce_hba(pHba);
 	adpt_i2o_delete_hba(pHba);
-	scsi_unregister(host);
+	scsi_host_put(shost);
 	return 0;
 }
 
@@ -882,7 +881,7 @@
 #endif
 
 
-static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev) 
+static int adpt_install_hba(struct pci_dev* pDev)
 {
 
 	adpt_hba* pHba = NULL;
@@ -1031,8 +1030,6 @@
 
 
 	mutex_lock(&adpt_configuration_lock);
-	// scsi_unregister calls our adpt_release which
-	// does a quiese
 	if(pHba->host){
 		free_irq(pHba->host->irq, pHba);
 	}
@@ -1084,17 +1081,6 @@
 }
 
 
-static int adpt_init(void)
-{
-	printk("Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n");
-#ifdef REBOOT_NOTIFIER
-	register_reboot_notifier(&adpt_reboot_notifier);
-#endif
-
-	return 0;
-}
-
-
 static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u32 lun)
 {
 	struct adpt_device* d;
@@ -2180,37 +2166,6 @@
 }
 
 
-static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht)
-{
-	struct Scsi_Host *host = NULL;
-
-	host = scsi_register(sht, sizeof(adpt_hba*));
-	if (host == NULL) {
-		printk ("%s: scsi_register returned NULL\n",pHba->name);
-		return -1;
-	}
-	host->hostdata[0] = (unsigned long)pHba;
-	pHba->host = host;
-
-	host->irq = pHba->pDev->irq;
-	/* no IO ports, so don't have to set host->io_port and 
-	 * host->n_io_port
-	 */
-	host->io_port = 0;
-	host->n_io_port = 0;
-				/* see comments in scsi_host.h */
-	host->max_id = 16;
-	host->max_lun = 256;
-	host->max_channel = pHba->top_scsi_channel + 1;
-	host->cmd_per_lun = 1;
-	host->unique_id = (uint) pHba;
-	host->sg_tablesize = pHba->sg_tablesize;
-	host->can_queue = pHba->post_fifo_size;
-
-	return 0;
-}
-
-
 static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd)
 {
 	adpt_hba* pHba;
@@ -3329,12 +3284,10 @@
 
 #endif
 
-static struct scsi_host_template driver_template = {
+static struct scsi_host_template adpt_template = {
 	.name			= "dpt_i2o",
 	.proc_name		= "dpt_i2o",
 	.proc_info		= adpt_proc_info,
-	.detect			= adpt_detect,	
-	.release		= adpt_release,
 	.info			= adpt_info,
 	.queuecommand		= adpt_queue,
 	.eh_abort_handler	= adpt_abort,
@@ -3348,5 +3301,62 @@
 	.cmd_per_lun		= 1,
 	.use_clustering		= ENABLE_CLUSTERING,
 };
-#include "scsi_module.c"
+
+static s32 adpt_scsi_register(adpt_hba* pHba)
+{
+	struct Scsi_Host *host;
+
+	host = scsi_host_alloc(&adpt_template, sizeof(adpt_hba*));
+	if (host == NULL) {
+		printk ("%s: scsi_host_alloc returned NULL\n",pHba->name);
+		return -1;
+	}
+	host->hostdata[0] = (unsigned long)pHba;
+	pHba->host = host;
+
+	host->irq = pHba->pDev->irq;
+	/* no IO ports, so don't have to set host->io_port and
+	 * host->n_io_port
+	 */
+	host->io_port = 0;
+	host->n_io_port = 0;
+				/* see comments in scsi_host.h */
+	host->max_id = 16;
+	host->max_lun = 256;
+	host->max_channel = pHba->top_scsi_channel + 1;
+	host->cmd_per_lun = 1;
+	host->unique_id = (uint) pHba;
+	host->sg_tablesize = pHba->sg_tablesize;
+	host->can_queue = pHba->post_fifo_size;
+
+	if (scsi_add_host(host, &pHba->pDev->dev)) {
+		scsi_host_put(host);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int __init adpt_init(void)
+{
+	int count;
+
+	printk("Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n");
+#ifdef REBOOT_NOTIFIER
+	register_reboot_notifier(&adpt_reboot_notifier);
+#endif
+
+	count = adpt_detect();
+
+	return count > 0 ? 0 : -ENODEV;
+}
+
+static void __exit adpt_exit(void)
+{
+	while (hba_chain)
+		adpt_release(hba_chain);
+}
+
+module_init(adpt_init);
+module_exit(adpt_exit);
 MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
index fd79068..0892f6c 100644
--- a/drivers/scsi/dpti.h
+++ b/drivers/scsi/dpti.h
@@ -28,11 +28,9 @@
  * SCSI interface function Prototypes
  */
 
-static int adpt_detect(struct scsi_host_template * sht);
 static int adpt_queue(struct scsi_cmnd * cmd, void (*cmdcomplete) (struct scsi_cmnd *));
 static int adpt_abort(struct scsi_cmnd * cmd);
 static int adpt_reset(struct scsi_cmnd* cmd);
-static int adpt_release(struct Scsi_Host *host);
 static int adpt_slave_configure(struct scsi_device *);
 
 static const char *adpt_info(struct Scsi_Host *pSHost);
@@ -49,8 +47,6 @@
 
 #define DPT_DRIVER_NAME	"Adaptec I2O RAID"
 
-#ifndef HOSTS_C
-
 #include "dpt/sys_info.h"
 #include <linux/wait.h>
 #include "dpt/dpti_i2o.h"
@@ -289,7 +285,7 @@
 static s32 adpt_i2o_hrt_get(adpt_hba* pHba);
 static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_device* dptdevice);
 static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd);
-static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht);
+static s32 adpt_scsi_register(adpt_hba* pHba);
 static s32 adpt_hba_reset(adpt_hba* pHba);
 static s32 adpt_i2o_reset_hba(adpt_hba* pHba);
 static s32 adpt_rescan(adpt_hba* pHba);
@@ -299,7 +295,7 @@
 static void adpt_inquiry(adpt_hba* pHba);
 static void adpt_fail_posted_scbs(adpt_hba* pHba);
 static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u32 lun);
-static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev) ;
+static int adpt_install_hba(struct pci_dev* pDev) ;
 static int adpt_i2o_online_hba(adpt_hba* pHba);
 static void adpt_i2o_post_wait_complete(u32, int);
 static int adpt_i2o_systab_send(adpt_hba* pHba);
@@ -343,5 +339,4 @@
 #define FW_DEBUG_BLED_OFFSET       8
 
 #define FW_DEBUG_FLAGS_NO_HEADERS_B    0x01
-#endif				/* !HOSTS_C */
 #endif				/* _DPT_H */
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 77b06a9..95cf7b6 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -2314,6 +2314,7 @@
 	esp->host->transportt = esp_transport_template;
 	esp->host->max_lun = ESP_MAX_LUN;
 	esp->host->cmd_per_lun = 2;
+	esp->host->unique_id = instance;
 
 	esp_set_clock_params(esp);
 
@@ -2337,7 +2338,7 @@
 	if (err)
 		return err;
 
-	esp->host->unique_id = instance++;
+	instance++;
 
 	scsi_scan_host(esp->host);
 
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index d0b95ce..55e4d2d 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -902,11 +902,6 @@
             return;
         /* GDT PCI controller found, resources are already in pdev */
         pcistr[*cnt].pdev = pdev;
-        pcistr[*cnt].vendor_id = vendor;
-        pcistr[*cnt].device_id = device;
-        pcistr[*cnt].subdevice_id = pdev->subsystem_device;
-        pcistr[*cnt].bus = pdev->bus->number;
-        pcistr[*cnt].device_fn = pdev->devfn;
         pcistr[*cnt].irq = pdev->irq;
         base0 = pci_resource_flags(pdev, 0);
         base1 = pci_resource_flags(pdev, 1);
@@ -926,7 +921,8 @@
             pcistr[*cnt].io    = pci_resource_start(pdev, 1);
         }
         TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n",
-                pcistr[*cnt].bus, PCI_SLOT(pcistr[*cnt].device_fn), 
+                pcistr[*cnt].pdev->bus->number,
+		PCI_SLOT(pcistr[*cnt].pdev->devfn),
                 pcistr[*cnt].irq, pcistr[*cnt].dpmem));
         (*cnt)++;
     }       
@@ -946,20 +942,20 @@
         changed = FALSE;
         for (i = 0; i < cnt-1; ++i) {
             if (!reverse_scan) {
-                if ((pcistr[i].bus > pcistr[i+1].bus) ||
-                    (pcistr[i].bus == pcistr[i+1].bus &&
-                     PCI_SLOT(pcistr[i].device_fn) > 
-                     PCI_SLOT(pcistr[i+1].device_fn))) {
+                if ((pcistr[i].pdev->bus->number > pcistr[i+1].pdev->bus->number) ||
+                    (pcistr[i].pdev->bus->number == pcistr[i+1].pdev->bus->number &&
+                     PCI_SLOT(pcistr[i].pdev->devfn) >
+                     PCI_SLOT(pcistr[i+1].pdev->devfn))) {
                     temp = pcistr[i];
                     pcistr[i] = pcistr[i+1];
                     pcistr[i+1] = temp;
                     changed = TRUE;
                 }
             } else {
-                if ((pcistr[i].bus < pcistr[i+1].bus) ||
-                    (pcistr[i].bus == pcistr[i+1].bus &&
-                     PCI_SLOT(pcistr[i].device_fn) < 
-                     PCI_SLOT(pcistr[i+1].device_fn))) {
+                if ((pcistr[i].pdev->bus->number < pcistr[i+1].pdev->bus->number) ||
+                    (pcistr[i].pdev->bus->number == pcistr[i+1].pdev->bus->number &&
+                     PCI_SLOT(pcistr[i].pdev->devfn) <
+                     PCI_SLOT(pcistr[i+1].pdev->devfn))) {
                     temp = pcistr[i];
                     pcistr[i] = pcistr[i+1];
                     pcistr[i+1] = temp;
@@ -1176,17 +1172,16 @@
 
     TRACE(("gdth_init_pci()\n"));
 
-    if (pcistr->vendor_id == PCI_VENDOR_ID_INTEL)
+    if (pcistr->pdev->vendor == PCI_VENDOR_ID_INTEL)
         ha->oem_id = OEM_ID_INTEL;
     else
         ha->oem_id = OEM_ID_ICP;
-    ha->brd_phys = (pcistr->bus << 8) | (pcistr->device_fn & 0xf8);
-    ha->stype = (ulong32)pcistr->device_id;
-    ha->subdevice_id = pcistr->subdevice_id;
+    ha->brd_phys = (pcistr->pdev->bus->number << 8) | (pcistr->pdev->devfn & 0xf8);
+    ha->stype = (ulong32)pcistr->pdev->device;
     ha->irq = pcistr->irq;
     ha->pdev = pcistr->pdev;
     
-    if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6000B) {  /* GDT6000/B */
+    if (ha->pdev->device <= PCI_DEVICE_ID_VORTEX_GDT6000B) {  /* GDT6000/B */
         TRACE2(("init_pci() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq));
         ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6_dpram_str));
         if (ha->brd == NULL) {
@@ -1293,7 +1288,7 @@
 
         ha->dma64_support = 0;
 
-    } else if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6555) { /* GDT6110, ... */
+    } else if (ha->pdev->device <= PCI_DEVICE_ID_VORTEX_GDT6555) { /* GDT6110, ... */
         ha->plx = (gdt6c_plx_regs *)pcistr->io;
         TRACE2(("init_pci_new() dpmem %lx irq %d\n",
             pcistr->dpmem,ha->irq));
@@ -4601,7 +4596,8 @@
         }
         /* controller found and initialized */
         printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n",
-               pcistr[ctr].bus,PCI_SLOT(pcistr[ctr].device_fn),ha->irq);
+               pcistr[ctr].pdev->bus->number,
+	       PCI_SLOT(pcistr[ctr].pdev->devfn), ha->irq);
 
         if (request_irq(ha->irq, gdth_interrupt,
                         IRQF_DISABLED|IRQF_SHARED, "gdth", ha))
@@ -4637,7 +4633,7 @@
 #endif
         ha->scratch_busy = FALSE;
         ha->req_first = NULL;
-        ha->tid_cnt = pcistr[ctr].device_id >= 0x200 ? MAXID : MAX_HDRIVES;
+        ha->tid_cnt = pcistr[ctr].pdev->device >= 0x200 ? MAXID : MAX_HDRIVES;
         if (max_ids > 0 && max_ids < ha->tid_cnt)
             ha->tid_cnt = max_ids;
         for (i=0; i<GDTH_MAXCMDS; ++i)
@@ -4810,7 +4806,7 @@
     } else if (ha->type == GDT_ISA) {
         return("GDT2000/2020");
     } else if (ha->type == GDT_PCI) {
-        switch (ha->stype) {
+        switch (ha->pdev->device) {
           case PCI_DEVICE_ID_VORTEX_GDT60x0:
             return("GDT6000/6020/6050");
           case PCI_DEVICE_ID_VORTEX_GDT6000B:
@@ -5448,12 +5444,12 @@
                 ctrt.type = 
                     (ha->oem_id == OEM_ID_INTEL ? 0xfd : 0xfe);
                 if (ha->stype >= 0x300)
-                    ctrt.ext_type = 0x6000 | ha->subdevice_id;
+                    ctrt.ext_type = 0x6000 | ha->pdev->subsystem_device;
                 else 
                     ctrt.ext_type = 0x6000 | ha->stype;
             }
-            ctrt.device_id = ha->stype;
-            ctrt.sub_device_id = ha->subdevice_id;
+            ctrt.device_id = ha->pdev->device;
+            ctrt.sub_device_id = ha->pdev->subsystem_device;
         }
         ctrt.info = ha->brd_phys;
         ctrt.oem_id = ha->oem_id;
diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
index 8c29eaf..3742330 100644
--- a/drivers/scsi/gdth.h
+++ b/drivers/scsi/gdth.h
@@ -845,11 +845,6 @@
 /* PCI resources */
 typedef struct {
     struct pci_dev      *pdev;
-    ushort              vendor_id;              /* vendor (ICP, Intel, ..) */
-    ushort              device_id;              /* device ID (0,..,9) */
-    ushort              subdevice_id;           /* sub device ID */
-    unchar              bus;                    /* PCI bus */
-    unchar              device_fn;              /* PCI device/function no. */
     ulong               dpmem;                  /* DPRAM address */
     ulong               io;                     /* IO address */
     ulong               io_mm;                  /* IO address mem. mapped */
@@ -862,7 +857,6 @@
     ushort              oem_id;                 /* OEM */
     ushort              type;                   /* controller class */
     ulong32             stype;                  /* subtype (PCI: device ID) */
-    ushort              subdevice_id;           /* sub device ID (PCI) */
     ushort              fw_vers;                /* firmware version */
     ushort              cache_feat;             /* feat. cache serv. (s/g,..)*/
     ushort              raw_feat;               /* feat. raw service (s/g,..)*/
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index bd8e7f3..96bc312 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -220,7 +220,7 @@
 	get_device(&shost->shost_gendev);
 
 	if (shost->transportt->host_size &&
-	    (shost->shost_data = kmalloc(shost->transportt->host_size,
+	    (shost->shost_data = kzalloc(shost->transportt->host_size,
 					 GFP_KERNEL)) == NULL)
 		goto out_del_classdev;
 
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 5870866..5ecc63d 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -393,12 +393,6 @@
 		return 1;
 	else if (sg_mapped < 0)
 		return 0;
-	else if (sg_mapped > SG_ALL) {
-		printk(KERN_ERR
-		       "ibmvscsi: More than %d mapped sg entries, got %d\n",
-		       SG_ALL, sg_mapped);
-		return 0;
-	}
 
 	set_srp_direction(cmd, srp_cmd, sg_mapped);
 
@@ -708,8 +702,7 @@
 	struct srp_cmd *srp_cmd;
 	struct srp_event_struct *evt_struct;
 	struct srp_indirect_buf *indirect;
-	struct ibmvscsi_host_data *hostdata =
-		(struct ibmvscsi_host_data *)&cmnd->device->host->hostdata;
+	struct ibmvscsi_host_data *hostdata = shost_priv(cmnd->device->host);
 	u16 lun = lun_from_dev(cmnd->device);
 	u8 out_fmt, in_fmt;
 
@@ -960,8 +953,7 @@
  */
 static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
 {
-	struct ibmvscsi_host_data *hostdata =
-	    (struct ibmvscsi_host_data *)cmd->device->host->hostdata;
+	struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
 	struct srp_tsk_mgmt *tsk_mgmt;
 	struct srp_event_struct *evt;
 	struct srp_event_struct *tmp_evt, *found_evt;
@@ -1084,9 +1076,7 @@
  */
 static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
 {
-	struct ibmvscsi_host_data *hostdata =
-	    (struct ibmvscsi_host_data *)cmd->device->host->hostdata;
-
+	struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
 	struct srp_tsk_mgmt *tsk_mgmt;
 	struct srp_event_struct *evt;
 	struct srp_event_struct *tmp_evt, *pos;
@@ -1183,8 +1173,7 @@
 static int ibmvscsi_eh_host_reset_handler(struct scsi_cmnd *cmd)
 {
 	unsigned long wait_switch = 0;
-	struct ibmvscsi_host_data *hostdata =
-		(struct ibmvscsi_host_data *)cmd->device->host->hostdata;
+	struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host);
 
 	dev_err(hostdata->dev, "Resetting connection due to error recovery\n");
 
@@ -1412,8 +1401,7 @@
 static ssize_t show_host_srp_version(struct class_device *class_dev, char *buf)
 {
 	struct Scsi_Host *shost = class_to_shost(class_dev);
-	struct ibmvscsi_host_data *hostdata =
-	    (struct ibmvscsi_host_data *)shost->hostdata;
+	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
 	int len;
 
 	len = snprintf(buf, PAGE_SIZE, "%s\n",
@@ -1433,8 +1421,7 @@
 					char *buf)
 {
 	struct Scsi_Host *shost = class_to_shost(class_dev);
-	struct ibmvscsi_host_data *hostdata =
-	    (struct ibmvscsi_host_data *)shost->hostdata;
+	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
 	int len;
 
 	len = snprintf(buf, PAGE_SIZE, "%s\n",
@@ -1454,8 +1441,7 @@
 					  char *buf)
 {
 	struct Scsi_Host *shost = class_to_shost(class_dev);
-	struct ibmvscsi_host_data *hostdata =
-	    (struct ibmvscsi_host_data *)shost->hostdata;
+	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
 	int len;
 
 	len = snprintf(buf, PAGE_SIZE, "%d\n",
@@ -1474,8 +1460,7 @@
 static ssize_t show_host_mad_version(struct class_device *class_dev, char *buf)
 {
 	struct Scsi_Host *shost = class_to_shost(class_dev);
-	struct ibmvscsi_host_data *hostdata =
-	    (struct ibmvscsi_host_data *)shost->hostdata;
+	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
 	int len;
 
 	len = snprintf(buf, PAGE_SIZE, "%d\n",
@@ -1494,8 +1479,7 @@
 static ssize_t show_host_os_type(struct class_device *class_dev, char *buf)
 {
 	struct Scsi_Host *shost = class_to_shost(class_dev);
-	struct ibmvscsi_host_data *hostdata =
-	    (struct ibmvscsi_host_data *)shost->hostdata;
+	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
 	int len;
 
 	len = snprintf(buf, PAGE_SIZE, "%d\n", hostdata->madapter_info.os_type);
@@ -1513,8 +1497,7 @@
 static ssize_t show_host_config(struct class_device *class_dev, char *buf)
 {
 	struct Scsi_Host *shost = class_to_shost(class_dev);
-	struct ibmvscsi_host_data *hostdata =
-	    (struct ibmvscsi_host_data *)shost->hostdata;
+	struct ibmvscsi_host_data *hostdata = shost_priv(shost);
 
 	/* returns null-terminated host config data */
 	if (ibmvscsi_do_host_config(hostdata, buf, PAGE_SIZE) == 0)
@@ -1582,7 +1565,7 @@
 		goto scsi_host_alloc_failed;
 	}
 
-	hostdata = (struct ibmvscsi_host_data *)host->hostdata;
+	hostdata = shost_priv(host);
 	memset(hostdata, 0x00, sizeof(*hostdata));
 	INIT_LIST_HEAD(&hostdata->sent);
 	hostdata->host = host;
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index bb90df8..1cc01ac 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -328,17 +328,15 @@
 	u8             *buf;
 
 	/* stuff a sense request in front of our current request */
-	pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC);
-	rq = kmalloc (sizeof (struct request), GFP_ATOMIC);
-	buf = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_ATOMIC);
-	if (pc == NULL || rq == NULL || buf == NULL) {
+	pc = kzalloc(sizeof(idescsi_pc_t), GFP_ATOMIC);
+	rq = kmalloc(sizeof(struct request), GFP_ATOMIC);
+	buf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_ATOMIC);
+	if (!pc || !rq || !buf) {
 		kfree(buf);
 		kfree(rq);
 		kfree(pc);
 		return -ENOMEM;
 	}
-	memset (pc, 0, sizeof (idescsi_pc_t));
-	memset (buf, 0, SCSI_SENSE_BUFFERSIZE);
 	ide_init_drive_cmd(rq);
 	rq->special = (char *) pc;
 	pc->rq = rq;
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index 0464c18..005d2b0 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -1159,11 +1159,10 @@
 
 	init_waitqueue_head(&waiting);
 
-	dev = kmalloc(sizeof(imm_struct), GFP_KERNEL);
+	dev = kzalloc(sizeof(imm_struct), GFP_KERNEL);
 	if (!dev)
 		return -ENOMEM;
 
-	memset(dev, 0, sizeof(imm_struct));
 
 	dev->base = -1;
 	dev->mode = IMM_AUTODETECT;
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index f142eaf..b41dfb5 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3829,18 +3829,18 @@
 
 /**
  * ipr_sata_reset - Reset the SATA port
- * @ap:		SATA port to reset
+ * @link:	SATA link to reset
  * @classes:	class of the attached device
  *
- * This function issues a SATA phy reset to the affected ATA port.
+ * This function issues a SATA phy reset to the affected ATA link.
  *
  * Return value:
  *	0 on success / non-zero on failure
  **/
-static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes,
+static int ipr_sata_reset(struct ata_link *link, unsigned int *classes,
 				unsigned long deadline)
 {
-	struct ipr_sata_port *sata_port = ap->private_data;
+	struct ipr_sata_port *sata_port = link->ap->private_data;
 	struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
 	struct ipr_resource_entry *res;
 	unsigned long lock_flags = 0;
@@ -4981,22 +4981,22 @@
 	rc = ipr_device_reset(ioa_cfg, res);
 
 	if (rc) {
-		ap->ops->port_disable(ap);
+		ata_port_disable(ap);
 		goto out_unlock;
 	}
 
 	switch(res->cfgte.proto) {
 	case IPR_PROTO_SATA:
 	case IPR_PROTO_SAS_STP:
-		ap->device[0].class = ATA_DEV_ATA;
+		ap->link.device[0].class = ATA_DEV_ATA;
 		break;
 	case IPR_PROTO_SATA_ATAPI:
 	case IPR_PROTO_SAS_STP_ATAPI:
-		ap->device[0].class = ATA_DEV_ATAPI;
+		ap->link.device[0].class = ATA_DEV_ATAPI;
 		break;
 	default:
-		ap->device[0].class = ATA_DEV_UNKNOWN;
-		ap->ops->port_disable(ap);
+		ap->link.device[0].class = ATA_DEV_UNKNOWN;
+		ata_port_disable(ap);
 		break;
 	};
 
@@ -5262,7 +5262,6 @@
 }
 
 static struct ata_port_operations ipr_sata_ops = {
-	.port_disable = ata_port_disable,
 	.check_status = ipr_ata_check_status,
 	.check_altstatus = ipr_ata_check_altstatus,
 	.dev_select = ata_noop_dev_select,
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 9f8ed6b..492a51b 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -7068,14 +7068,13 @@
 	subdevice_id = pci_dev->subsystem_device;
 
 	/* found a controller */
-	ha = kmalloc(sizeof (ips_ha_t), GFP_KERNEL);
+	ha = kzalloc(sizeof (ips_ha_t), GFP_KERNEL);
 	if (ha == NULL) {
 		IPS_PRINTK(KERN_WARNING, pci_dev,
 			   "Unable to allocate temporary ha struct\n");
 		return -1;
 	}
 
-	memset(ha, 0, sizeof (ips_ha_t));
 
 	ips_sh[index] = NULL;
 	ips_ha[index] = ha;
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index aebcd5f..a21455d 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -1885,7 +1885,7 @@
 	struct sockaddr_in *sin;
 	int rc = 0, len;
 
-	addr = kmalloc(GFP_KERNEL, sizeof(*addr));
+	addr = kmalloc(sizeof(*addr), GFP_KERNEL);
 	if (!addr)
 		return -ENOMEM;
 
@@ -2216,11 +2216,13 @@
 
 static int iscsi_tcp_slave_configure(struct scsi_device *sdev)
 {
+	blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_ANY);
 	blk_queue_dma_alignment(sdev->request_queue, 0);
 	return 0;
 }
 
 static struct scsi_host_template iscsi_sht = {
+	.module			= THIS_MODULE,
 	.name			= "iSCSI Initiator over TCP/IP",
 	.queuecommand           = iscsi_queuecommand,
 	.change_queue_depth	= iscsi_change_queue_depth,
diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c
index 5c32a69..3126824 100644
--- a/drivers/scsi/lasi700.c
+++ b/drivers/scsi/lasi700.c
@@ -101,13 +101,12 @@
 	struct NCR_700_Host_Parameters *hostdata;
 	struct Scsi_Host *host;
 
-	hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL);
+	hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL);
 	if (!hostdata) {
 		printk(KERN_ERR "%s: Failed to allocate host data\n",
 		       dev->dev.bus_id);
 		return -ENOMEM;
 	}
-	memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
 
 	hostdata->dev = &dev->dev;
 	dma_set_mask(&dev->dev, DMA_32BIT_MASK);
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 4d85ce1..efceed4 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -596,9 +596,16 @@
 	nop->cmdsn = cpu_to_be32(session->cmdsn);
 	if (hdr->itt != RESERVED_ITT) {
 		hdr->itt = build_itt(mtask->itt, conn->id, session->age);
+		/*
+		 * TODO: We always use immediate, so we never hit this.
+		 * If we start to send tmfs or nops as non-immediate then
+		 * we should start checking the cmdsn numbers for mgmt tasks.
+		 */
 		if (conn->c_stage == ISCSI_CONN_STARTED &&
-		    !(hdr->opcode & ISCSI_OP_IMMEDIATE))
+		    !(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
+			session->queued_cmdsn++;
 			session->cmdsn++;
+		}
 	}
 
 	if (session->tt->init_mgmt_task)
@@ -641,9 +648,11 @@
 	/*
 	 * Check for iSCSI window and take care of CmdSN wrap-around
 	 */
-	if (!iscsi_sna_lte(session->cmdsn, session->max_cmdsn)) {
-		debug_scsi("iSCSI CmdSN closed. MaxCmdSN %u CmdSN %u\n",
-			   session->max_cmdsn, session->cmdsn);
+	if (!iscsi_sna_lte(session->queued_cmdsn, session->max_cmdsn)) {
+		debug_scsi("iSCSI CmdSN closed. ExpCmdSn %u MaxCmdSN %u "
+			   "CmdSN %u/%u\n", session->exp_cmdsn,
+			   session->max_cmdsn, session->cmdsn,
+			   session->queued_cmdsn);
 		return -ENOSPC;
 	}
 	return 0;
@@ -722,23 +731,25 @@
 
 	/* process command queue */
 	while (!list_empty(&conn->xmitqueue)) {
-		rc = iscsi_check_cmdsn_window_closed(conn);
-		if (rc) {
-			spin_unlock_bh(&conn->session->lock);
-			return rc;
-		}
 		/*
 		 * iscsi tcp may readd the task to the xmitqueue to send
 		 * write data
 		 */
 		conn->ctask = list_entry(conn->xmitqueue.next,
 					 struct iscsi_cmd_task, running);
-		if (conn->ctask->state == ISCSI_TASK_PENDING) {
+		switch (conn->ctask->state) {
+		case ISCSI_TASK_ABORTING:
+			break;
+		case ISCSI_TASK_PENDING:
 			iscsi_prep_scsi_cmd_pdu(conn->ctask);
 			conn->session->tt->init_cmd_task(conn->ctask);
+			/* fall through */
+		default:
+			conn->ctask->state = ISCSI_TASK_RUNNING;
+			break;
 		}
-		conn->ctask->state = ISCSI_TASK_RUNNING;
 		list_move_tail(conn->xmitqueue.next, &conn->run_list);
+
 		rc = iscsi_xmit_ctask(conn);
 		if (rc)
 			goto again;
@@ -834,12 +845,6 @@
 		goto fault;
 	}
 
-	/*
-	 * We check this here and in data xmit, because if we get to the point
-	 * that this check is hitting the window then we have enough IO in
-	 * flight and enough IO waiting to be transmitted it is better
-	 * to let the scsi/block layer queue up.
-	 */
 	if (iscsi_check_cmdsn_window_closed(conn)) {
 		reason = FAILURE_WINDOW_CLOSED;
 		goto reject;
@@ -850,6 +855,8 @@
 		reason = FAILURE_OOM;
 		goto reject;
 	}
+	session->queued_cmdsn++;
+
 	sc->SCp.phase = session->age;
 	sc->SCp.ptr = (char *)ctask;
 
@@ -1049,7 +1056,9 @@
 	ctask->mtask = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
 					    NULL, 0);
 	if (!ctask->mtask) {
+		spin_unlock_bh(&session->lock);
 		iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+		spin_lock_bh(&session->lock)
 		debug_scsi("abort sent failure [itt 0x%x]\n", ctask->itt);
 		return -EPERM;
 	}
@@ -1066,6 +1075,7 @@
 		debug_scsi("abort set timeout [itt 0x%x]\n", ctask->itt);
 	}
 	spin_unlock_bh(&session->lock);
+	mutex_unlock(&session->eh_mutex);
 	scsi_queue_work(session->host, &conn->xmitwork);
 
 	/*
@@ -1083,6 +1093,7 @@
 	if (signal_pending(current))
 		flush_signals(current);
 	del_timer_sync(&conn->tmabort_timer);
+	mutex_lock(&session->eh_mutex);
 	spin_lock_bh(&session->lock);
 	return 0;
 }
@@ -1140,7 +1151,13 @@
 	if (!sc)
 		return;
 
-	if (ctask->state != ISCSI_TASK_PENDING)
+	if (ctask->state == ISCSI_TASK_PENDING)
+		/*
+		 * cmd never made it to the xmit thread, so we should not count
+		 * the cmd in the sequencing
+		 */
+		conn->session->queued_cmdsn--;
+	else
 		conn->session->tt->cleanup_cmd_task(conn, ctask);
 	iscsi_ctask_mtask_cleanup(ctask);
 
@@ -1152,31 +1169,45 @@
 	__iscsi_put_ctask(ctask);
 }
 
+static void iscsi_suspend_tx(struct iscsi_conn *conn)
+{
+	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+	scsi_flush_work(conn->session->host);
+}
+
+static void iscsi_start_tx(struct iscsi_conn *conn)
+{
+	clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+	scsi_queue_work(conn->session->host, &conn->xmitwork);
+}
+
 int iscsi_eh_abort(struct scsi_cmnd *sc)
 {
+	struct Scsi_Host *host = sc->device->host;
+	struct iscsi_session *session = iscsi_hostdata(host->hostdata);
 	struct iscsi_cmd_task *ctask;
 	struct iscsi_conn *conn;
-	struct iscsi_session *session;
 	int rc;
 
+	mutex_lock(&session->eh_mutex);
+	spin_lock_bh(&session->lock);
 	/*
 	 * if session was ISCSI_STATE_IN_RECOVERY then we may not have
 	 * got the command.
 	 */
 	if (!sc->SCp.ptr) {
 		debug_scsi("sc never reached iscsi layer or it completed.\n");
+		spin_unlock_bh(&session->lock);
+		mutex_unlock(&session->eh_mutex);
 		return SUCCESS;
 	}
 
 	ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
 	conn = ctask->conn;
-	session = conn->session;
 
 	conn->eh_abort_cnt++;
 	debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
 
-	spin_lock_bh(&session->lock);
-
 	/*
 	 * If we are not logged in or we have started a new session
 	 * then let the host reset code handle this
@@ -1213,6 +1244,7 @@
 	switch (conn->tmabort_state) {
 	case TMABORT_SUCCESS:
 		spin_unlock_bh(&session->lock);
+		iscsi_suspend_tx(conn);
 		/*
 		 * clean up task if aborted. grab the recv lock as a writer
 		 */
@@ -1221,11 +1253,7 @@
 		fail_command(conn, ctask, DID_ABORT << 16);
 		spin_unlock(&session->lock);
 		write_unlock_bh(conn->recv_lock);
-		/*
-		 * make sure xmit thread is not still touching the
-		 * ctask/scsi_cmnd
-		 */
-		scsi_flush_work(session->host);
+		iscsi_start_tx(conn);
 		goto success_unlocked;
 	case TMABORT_NOT_FOUND:
 		if (!ctask->sc) {
@@ -1245,12 +1273,14 @@
 	spin_unlock_bh(&session->lock);
 success_unlocked:
 	debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
+	mutex_unlock(&session->eh_mutex);
 	return SUCCESS;
 
 failed:
 	spin_unlock_bh(&session->lock);
 failed_unlocked:
 	debug_scsi("abort failed [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
+	mutex_unlock(&session->eh_mutex);
 	return FAILED;
 }
 EXPORT_SYMBOL_GPL(iscsi_eh_abort);
@@ -1392,11 +1422,12 @@
 	session->state = ISCSI_STATE_FREE;
 	session->mgmtpool_max = ISCSI_MGMT_CMDS_MAX;
 	session->cmds_max = cmds_max;
-	session->cmdsn = initial_cmdsn;
+	session->queued_cmdsn = session->cmdsn = initial_cmdsn;
 	session->exp_cmdsn = initial_cmdsn + 1;
 	session->max_cmdsn = initial_cmdsn + 1;
 	session->max_r2t = 1;
 	session->tt = iscsit;
+	mutex_init(&session->eh_mutex);
 
 	/* initialize SCSI PDU commands pool */
 	if (iscsi_pool_init(&session->cmdpool, session->cmds_max,
@@ -1473,6 +1504,7 @@
 	struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
 	struct module *owner = cls_session->transport->owner;
 
+	iscsi_unblock_session(cls_session);
 	scsi_remove_host(shost);
 
 	iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
@@ -1615,11 +1647,8 @@
 	kfree(conn->persistent_address);
 	__kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask,
 		    sizeof(void*));
-	if (session->leadconn == conn) {
+	if (session->leadconn == conn)
 		session->leadconn = NULL;
-		/* no connections exits.. reset sequencing */
-		session->cmdsn = session->max_cmdsn = session->exp_cmdsn = 1;
-	}
 	spin_unlock_bh(&session->lock);
 
 	kfifo_free(conn->mgmtqueue);
@@ -1649,6 +1678,7 @@
 	spin_lock_bh(&session->lock);
 	conn->c_stage = ISCSI_CONN_STARTED;
 	session->state = ISCSI_STATE_LOGGED_IN;
+	session->queued_cmdsn = session->cmdsn;
 
 	switch(conn->stop_stage) {
 	case STOP_CONN_RECOVER:
@@ -1731,9 +1761,22 @@
 {
 	int old_stop_stage;
 
+	mutex_lock(&session->eh_mutex);
 	spin_lock_bh(&session->lock);
 	if (conn->stop_stage == STOP_CONN_TERM) {
 		spin_unlock_bh(&session->lock);
+		mutex_unlock(&session->eh_mutex);
+		return;
+	}
+
+	/*
+	 * The LLD either freed/unset the lock on us, or userspace called
+	 * stop but did not create a proper connection (connection was never
+	 * bound or it was unbound then stop was called).
+	 */
+	if (!conn->recv_lock) {
+		spin_unlock_bh(&session->lock);
+		mutex_unlock(&session->eh_mutex);
 		return;
 	}
 
@@ -1750,9 +1793,9 @@
 	old_stop_stage = conn->stop_stage;
 	conn->stop_stage = flag;
 	conn->c_stage = ISCSI_CONN_STOPPED;
-	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
 	spin_unlock_bh(&session->lock);
-	scsi_flush_work(session->host);
+
+	iscsi_suspend_tx(conn);
 
 	write_lock_bh(conn->recv_lock);
 	set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
@@ -1781,6 +1824,7 @@
 	fail_all_commands(conn);
 	flush_control_queues(session, conn);
 	spin_unlock_bh(&session->lock);
+	mutex_unlock(&session->eh_mutex);
 }
 
 void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig
index aafdc92f..c01a40d 100644
--- a/drivers/scsi/libsas/Kconfig
+++ b/drivers/scsi/libsas/Kconfig
@@ -30,6 +30,14 @@
 	  This provides transport specific helpers for SAS drivers which
 	  use the domain device construct (like the aic94xxx).
 
+config SCSI_SAS_ATA
+	bool "ATA support for libsas (requires libata)"
+	depends on SCSI_SAS_LIBSAS
+	depends on ATA = y || ATA = SCSI_SAS_LIBSAS
+	help
+		Builds in ATA support into libsas.  Will necessitate
+		the loading of libata along with libsas.
+
 config SCSI_SAS_LIBSAS_DEBUG
 	bool "Compile the SAS Domain Transport Attributes in debug mode"
 	default y
diff --git a/drivers/scsi/libsas/Makefile b/drivers/scsi/libsas/Makefile
index 44d972a..fd387b9 100644
--- a/drivers/scsi/libsas/Makefile
+++ b/drivers/scsi/libsas/Makefile
@@ -34,3 +34,4 @@
 		sas_discover.o \
 		sas_expander.o \
 		sas_scsi_host.o
+libsas-$(CONFIG_SCSI_SAS_ATA) +=	sas_ata.o
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
new file mode 100644
index 0000000..0829b55
--- /dev/null
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -0,0 +1,816 @@
+/*
+ * Support for SATA devices on Serial Attached SCSI (SAS) controllers
+ *
+ * Copyright (C) 2006 IBM Corporation
+ *
+ * Written by: Darrick J. Wong <djwong@us.ibm.com>, IBM Corporation
+ *
+ * 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/scatterlist.h>
+
+#include <scsi/sas_ata.h>
+#include "sas_internal.h"
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+#include "../scsi_sas_internal.h"
+#include "../scsi_transport_api.h"
+#include <scsi/scsi_eh.h>
+
+static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts)
+{
+	/* Cheesy attempt to translate SAS errors into ATA.  Hah! */
+
+	/* transport error */
+	if (ts->resp == SAS_TASK_UNDELIVERED)
+		return AC_ERR_ATA_BUS;
+
+	/* ts->resp == SAS_TASK_COMPLETE */
+	/* task delivered, what happened afterwards? */
+	switch (ts->stat) {
+		case SAS_DEV_NO_RESPONSE:
+			return AC_ERR_TIMEOUT;
+
+		case SAS_INTERRUPTED:
+		case SAS_PHY_DOWN:
+		case SAS_NAK_R_ERR:
+			return AC_ERR_ATA_BUS;
+
+
+		case SAS_DATA_UNDERRUN:
+			/*
+			 * Some programs that use the taskfile interface
+			 * (smartctl in particular) can cause underrun
+			 * problems.  Ignore these errors, perhaps at our
+			 * peril.
+			 */
+			return 0;
+
+		case SAS_DATA_OVERRUN:
+		case SAS_QUEUE_FULL:
+		case SAS_DEVICE_UNKNOWN:
+		case SAS_SG_ERR:
+			return AC_ERR_INVALID;
+
+		case SAM_CHECK_COND:
+		case SAS_OPEN_TO:
+		case SAS_OPEN_REJECT:
+			SAS_DPRINTK("%s: Saw error %d.  What to do?\n",
+				    __FUNCTION__, ts->stat);
+			return AC_ERR_OTHER;
+
+		case SAS_ABORTED_TASK:
+			return AC_ERR_DEV;
+
+		case SAS_PROTO_RESPONSE:
+			/* This means the ending_fis has the error
+			 * value; return 0 here to collect it */
+			return 0;
+		default:
+			return 0;
+	}
+}
+
+static void sas_ata_task_done(struct sas_task *task)
+{
+	struct ata_queued_cmd *qc = task->uldd_task;
+	struct domain_device *dev;
+	struct task_status_struct *stat = &task->task_status;
+	struct ata_task_resp *resp = (struct ata_task_resp *)stat->buf;
+	struct sas_ha_struct *sas_ha;
+	enum ata_completion_errors ac;
+	unsigned long flags;
+
+	if (!qc)
+		goto qc_already_gone;
+
+	dev = qc->ap->private_data;
+	sas_ha = dev->port->ha;
+
+	spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
+	if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_GOOD) {
+		ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf);
+		qc->err_mask |= ac_err_mask(dev->sata_dev.tf.command);
+		dev->sata_dev.sstatus = resp->sstatus;
+		dev->sata_dev.serror = resp->serror;
+		dev->sata_dev.scontrol = resp->scontrol;
+	} else if (stat->stat != SAM_STAT_GOOD) {
+		ac = sas_to_ata_err(stat);
+		if (ac) {
+			SAS_DPRINTK("%s: SAS error %x\n", __FUNCTION__,
+				    stat->stat);
+			/* We saw a SAS error. Send a vague error. */
+			qc->err_mask = ac;
+			dev->sata_dev.tf.feature = 0x04; /* status err */
+			dev->sata_dev.tf.command = ATA_ERR;
+		}
+	}
+
+	qc->lldd_task = NULL;
+	if (qc->scsicmd)
+		ASSIGN_SAS_TASK(qc->scsicmd, NULL);
+	ata_qc_complete(qc);
+	spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
+
+	/*
+	 * If the sas_task has an ata qc, a scsi_cmnd and the aborted
+	 * flag is set, then we must have come in via the libsas EH
+	 * functions.  When we exit this function, we need to put the
+	 * scsi_cmnd on the list of finished errors.  The ata_qc_complete
+	 * call cleans up the libata side of things but we're protected
+	 * from the scsi_cmnd going away because the scsi_cmnd is owned
+	 * by the EH, making libata's call to scsi_done a NOP.
+	 */
+	spin_lock_irqsave(&task->task_state_lock, flags);
+	if (qc->scsicmd && task->task_state_flags & SAS_TASK_STATE_ABORTED)
+		scsi_eh_finish_cmd(qc->scsicmd, &sas_ha->eh_done_q);
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+qc_already_gone:
+	list_del_init(&task->list);
+	sas_free_task(task);
+}
+
+static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
+{
+	int res;
+	struct sas_task *task;
+	struct domain_device *dev = qc->ap->private_data;
+	struct sas_ha_struct *sas_ha = dev->port->ha;
+	struct Scsi_Host *host = sas_ha->core.shost;
+	struct sas_internal *i = to_sas_internal(host->transportt);
+	struct scatterlist *sg;
+	unsigned int num = 0;
+	unsigned int xfer = 0;
+
+	task = sas_alloc_task(GFP_ATOMIC);
+	if (!task)
+		return AC_ERR_SYSTEM;
+	task->dev = dev;
+	task->task_proto = SAS_PROTOCOL_STP;
+	task->task_done = sas_ata_task_done;
+
+	if (qc->tf.command == ATA_CMD_FPDMA_WRITE ||
+	    qc->tf.command == ATA_CMD_FPDMA_READ) {
+		/* Need to zero out the tag libata assigned us */
+		qc->tf.nsect = 0;
+	}
+
+	ata_tf_to_fis(&qc->tf, 1, 0, (u8*)&task->ata_task.fis);
+	task->uldd_task = qc;
+	if (is_atapi_taskfile(&qc->tf)) {
+		memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len);
+		task->total_xfer_len = qc->nbytes + qc->pad_len;
+		task->num_scatter = qc->pad_len ? qc->n_elem + 1 : qc->n_elem;
+	} else {
+		ata_for_each_sg(sg, qc) {
+			num++;
+			xfer += sg->length;
+		}
+
+		task->total_xfer_len = xfer;
+		task->num_scatter = num;
+	}
+
+	task->data_dir = qc->dma_dir;
+	task->scatter = qc->__sg;
+	task->ata_task.retry_count = 1;
+	task->task_state_flags = SAS_TASK_STATE_PENDING;
+	qc->lldd_task = task;
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_NCQ:
+		task->ata_task.use_ncq = 1;
+		/* fall through */
+	case ATA_PROT_ATAPI_DMA:
+	case ATA_PROT_DMA:
+		task->ata_task.dma_xfer = 1;
+		break;
+	}
+
+	if (qc->scsicmd)
+		ASSIGN_SAS_TASK(qc->scsicmd, task);
+
+	if (sas_ha->lldd_max_execute_num < 2)
+		res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC);
+	else
+		res = sas_queue_up(task);
+
+	/* Examine */
+	if (res) {
+		SAS_DPRINTK("lldd_execute_task returned: %d\n", res);
+
+		if (qc->scsicmd)
+			ASSIGN_SAS_TASK(qc->scsicmd, NULL);
+		sas_free_task(task);
+		return AC_ERR_SYSTEM;
+	}
+
+	return 0;
+}
+
+static u8 sas_ata_check_status(struct ata_port *ap)
+{
+	struct domain_device *dev = ap->private_data;
+	return dev->sata_dev.tf.command;
+}
+
+static void sas_ata_phy_reset(struct ata_port *ap)
+{
+	struct domain_device *dev = ap->private_data;
+	struct sas_internal *i =
+		to_sas_internal(dev->port->ha->core.shost->transportt);
+	int res = 0;
+
+	if (i->dft->lldd_I_T_nexus_reset)
+		res = i->dft->lldd_I_T_nexus_reset(dev);
+
+	if (res)
+		SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __FUNCTION__);
+
+	switch (dev->sata_dev.command_set) {
+		case ATA_COMMAND_SET:
+			SAS_DPRINTK("%s: Found ATA device.\n", __FUNCTION__);
+			ap->link.device[0].class = ATA_DEV_ATA;
+			break;
+		case ATAPI_COMMAND_SET:
+			SAS_DPRINTK("%s: Found ATAPI device.\n", __FUNCTION__);
+			ap->link.device[0].class = ATA_DEV_ATAPI;
+			break;
+		default:
+			SAS_DPRINTK("%s: Unknown SATA command set: %d.\n",
+				    __FUNCTION__,
+				    dev->sata_dev.command_set);
+			ap->link.device[0].class = ATA_DEV_UNKNOWN;
+			break;
+	}
+
+	ap->cbl = ATA_CBL_SATA;
+}
+
+static void sas_ata_post_internal(struct ata_queued_cmd *qc)
+{
+	if (qc->flags & ATA_QCFLAG_FAILED)
+		qc->err_mask |= AC_ERR_OTHER;
+
+	if (qc->err_mask) {
+		/*
+		 * Find the sas_task and kill it.  By this point,
+		 * libata has decided to kill the qc, so we needn't
+		 * bother with sas_ata_task_done.  But we still
+		 * ought to abort the task.
+		 */
+		struct sas_task *task = qc->lldd_task;
+		unsigned long flags;
+
+		qc->lldd_task = NULL;
+		if (task) {
+			/* Should this be a AT(API) device reset? */
+			spin_lock_irqsave(&task->task_state_lock, flags);
+			task->task_state_flags |= SAS_TASK_NEED_DEV_RESET;
+			spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+			task->uldd_task = NULL;
+			__sas_task_abort(task);
+		}
+	}
+}
+
+static void sas_ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct domain_device *dev = ap->private_data;
+	memcpy(tf, &dev->sata_dev.tf, sizeof (*tf));
+}
+
+static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
+			      u32 val)
+{
+	struct domain_device *dev = ap->private_data;
+
+	SAS_DPRINTK("STUB %s\n", __FUNCTION__);
+	switch (sc_reg_in) {
+		case SCR_STATUS:
+			dev->sata_dev.sstatus = val;
+			break;
+		case SCR_CONTROL:
+			dev->sata_dev.scontrol = val;
+			break;
+		case SCR_ERROR:
+			dev->sata_dev.serror = val;
+			break;
+		case SCR_ACTIVE:
+			dev->sata_dev.ap->link.sactive = val;
+			break;
+		default:
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in,
+			    u32 *val)
+{
+	struct domain_device *dev = ap->private_data;
+
+	SAS_DPRINTK("STUB %s\n", __FUNCTION__);
+	switch (sc_reg_in) {
+		case SCR_STATUS:
+			*val = dev->sata_dev.sstatus;
+			return 0;
+		case SCR_CONTROL:
+			*val = dev->sata_dev.scontrol;
+			return 0;
+		case SCR_ERROR:
+			*val = dev->sata_dev.serror;
+			return 0;
+		case SCR_ACTIVE:
+			*val = dev->sata_dev.ap->link.sactive;
+			return 0;
+		default:
+			return -EINVAL;
+	}
+}
+
+static struct ata_port_operations sas_sata_ops = {
+	.check_status		= sas_ata_check_status,
+	.check_altstatus	= sas_ata_check_status,
+	.dev_select		= ata_noop_dev_select,
+	.phy_reset		= sas_ata_phy_reset,
+	.post_internal_cmd	= sas_ata_post_internal,
+	.tf_read		= sas_ata_tf_read,
+	.qc_prep		= ata_noop_qc_prep,
+	.qc_issue		= sas_ata_qc_issue,
+	.port_start		= ata_sas_port_start,
+	.port_stop		= ata_sas_port_stop,
+	.scr_read		= sas_ata_scr_read,
+	.scr_write		= sas_ata_scr_write
+};
+
+static struct ata_port_info sata_port_info = {
+	.flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET |
+		ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ,
+	.pio_mask = 0x1f, /* PIO0-4 */
+	.mwdma_mask = 0x07, /* MWDMA0-2 */
+	.udma_mask = ATA_UDMA6,
+	.port_ops = &sas_sata_ops
+};
+
+int sas_ata_init_host_and_port(struct domain_device *found_dev,
+			       struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+	struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
+	struct ata_port *ap;
+
+	ata_host_init(&found_dev->sata_dev.ata_host,
+		      ha->dev,
+		      sata_port_info.flags,
+		      &sas_sata_ops);
+	ap = ata_sas_port_alloc(&found_dev->sata_dev.ata_host,
+				&sata_port_info,
+				shost);
+	if (!ap) {
+		SAS_DPRINTK("ata_sas_port_alloc failed.\n");
+		return -ENODEV;
+	}
+
+	ap->private_data = found_dev;
+	ap->cbl = ATA_CBL_SATA;
+	ap->scsi_host = shost;
+	found_dev->sata_dev.ap = ap;
+
+	return 0;
+}
+
+void sas_ata_task_abort(struct sas_task *task)
+{
+	struct ata_queued_cmd *qc = task->uldd_task;
+	struct completion *waiting;
+
+	/* Bounce SCSI-initiated commands to the SCSI EH */
+	if (qc->scsicmd) {
+		scsi_req_abort_cmd(qc->scsicmd);
+		scsi_schedule_eh(qc->scsicmd->device->host);
+		return;
+	}
+
+	/* Internal command, fake a timeout and complete. */
+	qc->flags &= ~ATA_QCFLAG_ACTIVE;
+	qc->flags |= ATA_QCFLAG_FAILED;
+	qc->err_mask |= AC_ERR_TIMEOUT;
+	waiting = qc->private_data;
+	complete(waiting);
+}
+
+static void sas_task_timedout(unsigned long _task)
+{
+	struct sas_task *task = (void *) _task;
+	unsigned long flags;
+
+	spin_lock_irqsave(&task->task_state_lock, flags);
+	if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+		task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+	spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+	complete(&task->completion);
+}
+
+static void sas_disc_task_done(struct sas_task *task)
+{
+	if (!del_timer(&task->timer))
+		return;
+	complete(&task->completion);
+}
+
+#define SAS_DEV_TIMEOUT 10
+
+/**
+ * sas_execute_task -- Basic task processing for discovery
+ * @task: the task to be executed
+ * @buffer: pointer to buffer to do I/O
+ * @size: size of @buffer
+ * @dma_dir: DMA direction.  DMA_xxx
+ */
+static int sas_execute_task(struct sas_task *task, void *buffer, int size,
+			    enum dma_data_direction dma_dir)
+{
+	int res = 0;
+	struct scatterlist *scatter = NULL;
+	struct task_status_struct *ts = &task->task_status;
+	int num_scatter = 0;
+	int retries = 0;
+	struct sas_internal *i =
+		to_sas_internal(task->dev->port->ha->core.shost->transportt);
+
+	if (dma_dir != DMA_NONE) {
+		scatter = kzalloc(sizeof(*scatter), GFP_KERNEL);
+		if (!scatter)
+			goto out;
+
+		sg_init_one(scatter, buffer, size);
+		num_scatter = 1;
+	}
+
+	task->task_proto = task->dev->tproto;
+	task->scatter = scatter;
+	task->num_scatter = num_scatter;
+	task->total_xfer_len = size;
+	task->data_dir = dma_dir;
+	task->task_done = sas_disc_task_done;
+	if (dma_dir != DMA_NONE &&
+	    sas_protocol_ata(task->task_proto)) {
+		task->num_scatter = dma_map_sg(task->dev->port->ha->dev,
+					       task->scatter,
+					       task->num_scatter,
+					       task->data_dir);
+	}
+
+	for (retries = 0; retries < 5; retries++) {
+		task->task_state_flags = SAS_TASK_STATE_PENDING;
+		init_completion(&task->completion);
+
+		task->timer.data = (unsigned long) task;
+		task->timer.function = sas_task_timedout;
+		task->timer.expires = jiffies + SAS_DEV_TIMEOUT*HZ;
+		add_timer(&task->timer);
+
+		res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
+		if (res) {
+			del_timer(&task->timer);
+			SAS_DPRINTK("executing SAS discovery task failed:%d\n",
+				    res);
+			goto ex_err;
+		}
+		wait_for_completion(&task->completion);
+		res = -ETASK;
+		if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+			int res2;
+			SAS_DPRINTK("task aborted, flags:0x%x\n",
+				    task->task_state_flags);
+			res2 = i->dft->lldd_abort_task(task);
+			SAS_DPRINTK("came back from abort task\n");
+			if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+				if (res2 == TMF_RESP_FUNC_COMPLETE)
+					continue; /* Retry the task */
+				else
+					goto ex_err;
+			}
+		}
+		if (task->task_status.stat == SAM_BUSY ||
+			   task->task_status.stat == SAM_TASK_SET_FULL ||
+			   task->task_status.stat == SAS_QUEUE_FULL) {
+			SAS_DPRINTK("task: q busy, sleeping...\n");
+			schedule_timeout_interruptible(HZ);
+		} else if (task->task_status.stat == SAM_CHECK_COND) {
+			struct scsi_sense_hdr shdr;
+
+			if (!scsi_normalize_sense(ts->buf, ts->buf_valid_size,
+						  &shdr)) {
+				SAS_DPRINTK("couldn't normalize sense\n");
+				continue;
+			}
+			if ((shdr.sense_key == 6 && shdr.asc == 0x29) ||
+			    (shdr.sense_key == 2 && shdr.asc == 4 &&
+			     shdr.ascq == 1)) {
+				SAS_DPRINTK("device %016llx LUN: %016llx "
+					    "powering up or not ready yet, "
+					    "sleeping...\n",
+					    SAS_ADDR(task->dev->sas_addr),
+					    SAS_ADDR(task->ssp_task.LUN));
+
+				schedule_timeout_interruptible(5*HZ);
+			} else if (shdr.sense_key == 1) {
+				res = 0;
+				break;
+			} else if (shdr.sense_key == 5) {
+				break;
+			} else {
+				SAS_DPRINTK("dev %016llx LUN: %016llx "
+					    "sense key:0x%x ASC:0x%x ASCQ:0x%x"
+					    "\n",
+					    SAS_ADDR(task->dev->sas_addr),
+					    SAS_ADDR(task->ssp_task.LUN),
+					    shdr.sense_key,
+					    shdr.asc, shdr.ascq);
+			}
+		} else if (task->task_status.resp != SAS_TASK_COMPLETE ||
+			   task->task_status.stat != SAM_GOOD) {
+			SAS_DPRINTK("task finished with resp:0x%x, "
+				    "stat:0x%x\n",
+				    task->task_status.resp,
+				    task->task_status.stat);
+			goto ex_err;
+		} else {
+			res = 0;
+			break;
+		}
+	}
+ex_err:
+	if (dma_dir != DMA_NONE) {
+		if (sas_protocol_ata(task->task_proto))
+			dma_unmap_sg(task->dev->port->ha->dev,
+				     task->scatter, task->num_scatter,
+				     task->data_dir);
+		kfree(scatter);
+	}
+out:
+	return res;
+}
+
+/* ---------- SATA ---------- */
+
+static void sas_get_ata_command_set(struct domain_device *dev)
+{
+	struct dev_to_host_fis *fis =
+		(struct dev_to_host_fis *) dev->frame_rcvd;
+
+	if ((fis->sector_count == 1 && /* ATA */
+	     fis->lbal         == 1 &&
+	     fis->lbam         == 0 &&
+	     fis->lbah         == 0 &&
+	     fis->device       == 0)
+	    ||
+	    (fis->sector_count == 0 && /* CE-ATA (mATA) */
+	     fis->lbal         == 0 &&
+	     fis->lbam         == 0xCE &&
+	     fis->lbah         == 0xAA &&
+	     (fis->device & ~0x10) == 0))
+
+		dev->sata_dev.command_set = ATA_COMMAND_SET;
+
+	else if ((fis->interrupt_reason == 1 &&	/* ATAPI */
+		  fis->lbal             == 1 &&
+		  fis->byte_count_low   == 0x14 &&
+		  fis->byte_count_high  == 0xEB &&
+		  (fis->device & ~0x10) == 0))
+
+		dev->sata_dev.command_set = ATAPI_COMMAND_SET;
+
+	else if ((fis->sector_count == 1 && /* SEMB */
+		  fis->lbal         == 1 &&
+		  fis->lbam         == 0x3C &&
+		  fis->lbah         == 0xC3 &&
+		  fis->device       == 0)
+		||
+		 (fis->interrupt_reason == 1 &&	/* SATA PM */
+		  fis->lbal             == 1 &&
+		  fis->byte_count_low   == 0x69 &&
+		  fis->byte_count_high  == 0x96 &&
+		  (fis->device & ~0x10) == 0))
+
+		/* Treat it as a superset? */
+		dev->sata_dev.command_set = ATAPI_COMMAND_SET;
+}
+
+/**
+ * sas_issue_ata_cmd -- Basic SATA command processing for discovery
+ * @dev: the device to send the command to
+ * @command: the command register
+ * @features: the features register
+ * @buffer: pointer to buffer to do I/O
+ * @size: size of @buffer
+ * @dma_dir: DMA direction.  DMA_xxx
+ */
+static int sas_issue_ata_cmd(struct domain_device *dev, u8 command,
+			     u8 features, void *buffer, int size,
+			     enum dma_data_direction dma_dir)
+{
+	int res = 0;
+	struct sas_task *task;
+	struct dev_to_host_fis *d2h_fis = (struct dev_to_host_fis *)
+		&dev->frame_rcvd[0];
+
+	res = -ENOMEM;
+	task = sas_alloc_task(GFP_KERNEL);
+	if (!task)
+		goto out;
+
+	task->dev = dev;
+
+	task->ata_task.fis.fis_type = 0x27;
+	task->ata_task.fis.command = command;
+	task->ata_task.fis.features = features;
+	task->ata_task.fis.device = d2h_fis->device;
+	task->ata_task.retry_count = 1;
+
+	res = sas_execute_task(task, buffer, size, dma_dir);
+
+	sas_free_task(task);
+out:
+	return res;
+}
+
+static void sas_sata_propagate_sas_addr(struct domain_device *dev)
+{
+	unsigned long flags;
+	struct asd_sas_port *port = dev->port;
+	struct asd_sas_phy  *phy;
+
+	BUG_ON(dev->parent);
+
+	memcpy(port->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
+	spin_lock_irqsave(&port->phy_list_lock, flags);
+	list_for_each_entry(phy, &port->phy_list, port_phy_el)
+		memcpy(phy->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
+	spin_unlock_irqrestore(&port->phy_list_lock, flags);
+}
+
+#define ATA_IDENTIFY_DEV         0xEC
+#define ATA_IDENTIFY_PACKET_DEV  0xA1
+#define ATA_SET_FEATURES         0xEF
+#define ATA_FEATURE_PUP_STBY_SPIN_UP 0x07
+
+/**
+ * sas_discover_sata_dev -- discover a STP/SATA device (SATA_DEV)
+ * @dev: STP/SATA device of interest (ATA/ATAPI)
+ *
+ * The LLDD has already been notified of this device, so that we can
+ * send FISes to it.  Here we try to get IDENTIFY DEVICE or IDENTIFY
+ * PACKET DEVICE, if ATAPI device, so that the LLDD can fine-tune its
+ * performance for this device.
+ */
+static int sas_discover_sata_dev(struct domain_device *dev)
+{
+	int     res;
+	__le16  *identify_x;
+	u8      command;
+
+	identify_x = kzalloc(512, GFP_KERNEL);
+	if (!identify_x)
+		return -ENOMEM;
+
+	if (dev->sata_dev.command_set == ATA_COMMAND_SET) {
+		dev->sata_dev.identify_device = identify_x;
+		command = ATA_IDENTIFY_DEV;
+	} else {
+		dev->sata_dev.identify_packet_device = identify_x;
+		command = ATA_IDENTIFY_PACKET_DEV;
+	}
+
+	res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
+				DMA_FROM_DEVICE);
+	if (res)
+		goto out_err;
+
+	/* lives on the media? */
+	if (le16_to_cpu(identify_x[0]) & 4) {
+		/* incomplete response */
+		SAS_DPRINTK("sending SET FEATURE/PUP_STBY_SPIN_UP to "
+			    "dev %llx\n", SAS_ADDR(dev->sas_addr));
+		if (!le16_to_cpu(identify_x[83] & (1<<6)))
+			goto cont1;
+		res = sas_issue_ata_cmd(dev, ATA_SET_FEATURES,
+					ATA_FEATURE_PUP_STBY_SPIN_UP,
+					NULL, 0, DMA_NONE);
+		if (res)
+			goto cont1;
+
+		schedule_timeout_interruptible(5*HZ); /* More time? */
+		res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
+					DMA_FROM_DEVICE);
+		if (res)
+			goto out_err;
+	}
+cont1:
+	/* Get WWN */
+	if (dev->port->oob_mode != SATA_OOB_MODE) {
+		memcpy(dev->sas_addr, dev->sata_dev.rps_resp.rps.stp_sas_addr,
+		       SAS_ADDR_SIZE);
+	} else if (dev->sata_dev.command_set == ATA_COMMAND_SET &&
+		   (le16_to_cpu(dev->sata_dev.identify_device[108]) & 0xF000)
+		   == 0x5000) {
+		int i;
+
+		for (i = 0; i < 4; i++) {
+			dev->sas_addr[2*i] =
+	     (le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0xFF00) >> 8;
+			dev->sas_addr[2*i+1] =
+	      le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0x00FF;
+		}
+	}
+	sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
+	if (!dev->parent)
+		sas_sata_propagate_sas_addr(dev);
+
+	/* XXX Hint: register this SATA device with SATL.
+	   When this returns, dev->sata_dev->lu is alive and
+	   present.
+	sas_satl_register_dev(dev);
+	*/
+
+	sas_fill_in_rphy(dev, dev->rphy);
+
+	return 0;
+out_err:
+	dev->sata_dev.identify_packet_device = NULL;
+	dev->sata_dev.identify_device = NULL;
+	kfree(identify_x);
+	return res;
+}
+
+static int sas_discover_sata_pm(struct domain_device *dev)
+{
+	return -ENODEV;
+}
+
+/**
+ * sas_discover_sata -- discover an STP/SATA domain device
+ * @dev: pointer to struct domain_device of interest
+ *
+ * First we notify the LLDD of this device, so we can send frames to
+ * it.  Then depending on the type of device we call the appropriate
+ * discover functions.  Once device discover is done, we notify the
+ * LLDD so that it can fine-tune its parameters for the device, by
+ * removing it and then adding it.  That is, the second time around,
+ * the driver would have certain fields, that it is looking at, set.
+ * Finally we initialize the kobj so that the device can be added to
+ * the system at registration time.  Devices directly attached to a HA
+ * port, have no parents.  All other devices do, and should have their
+ * "parent" pointer set appropriately before calling this function.
+ */
+int sas_discover_sata(struct domain_device *dev)
+{
+	int res;
+
+	sas_get_ata_command_set(dev);
+
+	res = sas_notify_lldd_dev_found(dev);
+	if (res)
+		return res;
+
+	switch (dev->dev_type) {
+	case SATA_DEV:
+		res = sas_discover_sata_dev(dev);
+		break;
+	case SATA_PM:
+		res = sas_discover_sata_pm(dev);
+		break;
+	default:
+		break;
+	}
+	sas_notify_lldd_dev_gone(dev);
+	if (!res) {
+		sas_notify_lldd_dev_found(dev);
+		res = sas_rphy_add(dev->rphy);
+	}
+
+	return res;
+}
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
index a65598b..7ef0afc 100644
--- a/drivers/scsi/libsas/sas_discover.c
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -22,7 +22,6 @@
  *
  */
 
-#include <linux/pci.h>
 #include <linux/scatterlist.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_eh.h>
@@ -55,149 +54,6 @@
         }
 }
 
-static void sas_task_timedout(unsigned long _task)
-{
-	struct sas_task *task = (void *) _task;
-	unsigned long flags;
-
-	spin_lock_irqsave(&task->task_state_lock, flags);
-	if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
-		task->task_state_flags |= SAS_TASK_STATE_ABORTED;
-	spin_unlock_irqrestore(&task->task_state_lock, flags);
-
-	complete(&task->completion);
-}
-
-static void sas_disc_task_done(struct sas_task *task)
-{
-	if (!del_timer(&task->timer))
-		return;
-	complete(&task->completion);
-}
-
-#define SAS_DEV_TIMEOUT 10
-
-/**
- * sas_execute_task -- Basic task processing for discovery
- * @task: the task to be executed
- * @buffer: pointer to buffer to do I/O
- * @size: size of @buffer
- * @pci_dma_dir: PCI_DMA_...
- */
-static int sas_execute_task(struct sas_task *task, void *buffer, int size,
-			    int pci_dma_dir)
-{
-	int res = 0;
-	struct scatterlist *scatter = NULL;
-	struct task_status_struct *ts = &task->task_status;
-	int num_scatter = 0;
-	int retries = 0;
-	struct sas_internal *i =
-		to_sas_internal(task->dev->port->ha->core.shost->transportt);
-
-	if (pci_dma_dir != PCI_DMA_NONE) {
-		scatter = kzalloc(sizeof(*scatter), GFP_KERNEL);
-		if (!scatter)
-			goto out;
-
-		sg_init_one(scatter, buffer, size);
-		num_scatter = 1;
-	}
-
-	task->task_proto = task->dev->tproto;
-	task->scatter = scatter;
-	task->num_scatter = num_scatter;
-	task->total_xfer_len = size;
-	task->data_dir = pci_dma_dir;
-	task->task_done = sas_disc_task_done;
-
-	for (retries = 0; retries < 5; retries++) {
-		task->task_state_flags = SAS_TASK_STATE_PENDING;
-		init_completion(&task->completion);
-
-		task->timer.data = (unsigned long) task;
-		task->timer.function = sas_task_timedout;
-		task->timer.expires = jiffies + SAS_DEV_TIMEOUT*HZ;
-		add_timer(&task->timer);
-
-		res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
-		if (res) {
-			del_timer(&task->timer);
-			SAS_DPRINTK("executing SAS discovery task failed:%d\n",
-				    res);
-			goto ex_err;
-		}
-		wait_for_completion(&task->completion);
-		res = -ETASK;
-		if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
-			int res2;
-			SAS_DPRINTK("task aborted, flags:0x%x\n",
-				    task->task_state_flags);
-			res2 = i->dft->lldd_abort_task(task);
-			SAS_DPRINTK("came back from abort task\n");
-			if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
-				if (res2 == TMF_RESP_FUNC_COMPLETE)
-					continue; /* Retry the task */
-				else
-					goto ex_err;
-			}
-		}
-		if (task->task_status.stat == SAM_BUSY ||
-			   task->task_status.stat == SAM_TASK_SET_FULL ||
-			   task->task_status.stat == SAS_QUEUE_FULL) {
-			SAS_DPRINTK("task: q busy, sleeping...\n");
-			schedule_timeout_interruptible(HZ);
-		} else if (task->task_status.stat == SAM_CHECK_COND) {
-			struct scsi_sense_hdr shdr;
-
-			if (!scsi_normalize_sense(ts->buf, ts->buf_valid_size,
-						  &shdr)) {
-				SAS_DPRINTK("couldn't normalize sense\n");
-				continue;
-			}
-			if ((shdr.sense_key == 6 && shdr.asc == 0x29) ||
-			    (shdr.sense_key == 2 && shdr.asc == 4 &&
-			     shdr.ascq == 1)) {
-				SAS_DPRINTK("device %016llx LUN: %016llx "
-					    "powering up or not ready yet, "
-					    "sleeping...\n",
-					    SAS_ADDR(task->dev->sas_addr),
-					    SAS_ADDR(task->ssp_task.LUN));
-
-				schedule_timeout_interruptible(5*HZ);
-			} else if (shdr.sense_key == 1) {
-				res = 0;
-				break;
-			} else if (shdr.sense_key == 5) {
-				break;
-			} else {
-				SAS_DPRINTK("dev %016llx LUN: %016llx "
-					    "sense key:0x%x ASC:0x%x ASCQ:0x%x"
-					    "\n",
-					    SAS_ADDR(task->dev->sas_addr),
-					    SAS_ADDR(task->ssp_task.LUN),
-					    shdr.sense_key,
-					    shdr.asc, shdr.ascq);
-			}
-		} else if (task->task_status.resp != SAS_TASK_COMPLETE ||
-			   task->task_status.stat != SAM_GOOD) {
-			SAS_DPRINTK("task finished with resp:0x%x, "
-				    "stat:0x%x\n",
-				    task->task_status.resp,
-				    task->task_status.stat);
-			goto ex_err;
-		} else {
-			res = 0;
-			break;
-		}
-	}
-ex_err:
-	if (pci_dma_dir != PCI_DMA_NONE)
-		kfree(scatter);
-out:
-	return res;
-}
-
 /* ---------- Domain device discovery ---------- */
 
 /**
@@ -255,6 +111,7 @@
 
 	switch (dev->dev_type) {
 	case SAS_END_DEV:
+	case SATA_DEV:
 		rphy = sas_end_device_alloc(port->port);
 		break;
 	case EDGE_DEV:
@@ -265,7 +122,6 @@
 		rphy = sas_expander_alloc(port->port,
 					  SAS_FANOUT_EXPANDER_DEVICE);
 		break;
-	case SATA_DEV:
 	default:
 		printk("ERROR: Unidentified device type %d\n", dev->dev_type);
 		rphy = NULL;
@@ -292,207 +148,15 @@
 	port->disc.max_level = 0;
 
 	dev->rphy = rphy;
-	spin_lock(&port->dev_list_lock);
+	spin_lock_irq(&port->dev_list_lock);
 	list_add_tail(&dev->dev_list_node, &port->dev_list);
-	spin_unlock(&port->dev_list_lock);
+	spin_unlock_irq(&port->dev_list_lock);
 
 	return 0;
 }
 
 /* ---------- Discover and Revalidate ---------- */
 
-/* ---------- SATA ---------- */
-
-static void sas_get_ata_command_set(struct domain_device *dev)
-{
-	struct dev_to_host_fis *fis =
-		(struct dev_to_host_fis *) dev->frame_rcvd;
-
-	if ((fis->sector_count == 1 && /* ATA */
-	     fis->lbal         == 1 &&
-	     fis->lbam         == 0 &&
-	     fis->lbah         == 0 &&
-	     fis->device       == 0)
-	    ||
-	    (fis->sector_count == 0 && /* CE-ATA (mATA) */
-	     fis->lbal         == 0 &&
-	     fis->lbam         == 0xCE &&
-	     fis->lbah         == 0xAA &&
-	     (fis->device & ~0x10) == 0))
-
-		dev->sata_dev.command_set = ATA_COMMAND_SET;
-
-	else if ((fis->interrupt_reason == 1 &&	/* ATAPI */
-		  fis->lbal             == 1 &&
-		  fis->byte_count_low   == 0x14 &&
-		  fis->byte_count_high  == 0xEB &&
-		  (fis->device & ~0x10) == 0))
-
-		dev->sata_dev.command_set = ATAPI_COMMAND_SET;
-
-	else if ((fis->sector_count == 1 && /* SEMB */
-		  fis->lbal         == 1 &&
-		  fis->lbam         == 0x3C &&
-		  fis->lbah         == 0xC3 &&
-		  fis->device       == 0)
-		||
-		 (fis->interrupt_reason == 1 &&	/* SATA PM */
-		  fis->lbal             == 1 &&
-		  fis->byte_count_low   == 0x69 &&
-		  fis->byte_count_high  == 0x96 &&
-		  (fis->device & ~0x10) == 0))
-
-		/* Treat it as a superset? */
-		dev->sata_dev.command_set = ATAPI_COMMAND_SET;
-}
-
-/**
- * sas_issue_ata_cmd -- Basic SATA command processing for discovery
- * @dev: the device to send the command to
- * @command: the command register
- * @features: the features register
- * @buffer: pointer to buffer to do I/O
- * @size: size of @buffer
- * @pci_dma_dir: PCI_DMA_...
- */
-static int sas_issue_ata_cmd(struct domain_device *dev, u8 command,
-			     u8 features, void *buffer, int size,
-			     int pci_dma_dir)
-{
-	int res = 0;
-	struct sas_task *task;
-	struct dev_to_host_fis *d2h_fis = (struct dev_to_host_fis *)
-		&dev->frame_rcvd[0];
-
-	res = -ENOMEM;
-	task = sas_alloc_task(GFP_KERNEL);
-	if (!task)
-		goto out;
-
-	task->dev = dev;
-
-	task->ata_task.fis.command = command;
-	task->ata_task.fis.features = features;
-	task->ata_task.fis.device = d2h_fis->device;
-	task->ata_task.retry_count = 1;
-
-	res = sas_execute_task(task, buffer, size, pci_dma_dir);
-
-	sas_free_task(task);
-out:
-	return res;
-}
-
-static void sas_sata_propagate_sas_addr(struct domain_device *dev)
-{
-	unsigned long flags;
-	struct asd_sas_port *port = dev->port;
-	struct asd_sas_phy  *phy;
-
-	BUG_ON(dev->parent);
-
-	memcpy(port->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
-	spin_lock_irqsave(&port->phy_list_lock, flags);
-	list_for_each_entry(phy, &port->phy_list, port_phy_el)
-		memcpy(phy->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
-	spin_unlock_irqrestore(&port->phy_list_lock, flags);
-}
-
-#define ATA_IDENTIFY_DEV         0xEC
-#define ATA_IDENTIFY_PACKET_DEV  0xA1
-#define ATA_SET_FEATURES         0xEF
-#define ATA_FEATURE_PUP_STBY_SPIN_UP 0x07
-
-/**
- * sas_discover_sata_dev -- discover a STP/SATA device (SATA_DEV)
- * @dev: STP/SATA device of interest (ATA/ATAPI)
- *
- * The LLDD has already been notified of this device, so that we can
- * send FISes to it.  Here we try to get IDENTIFY DEVICE or IDENTIFY
- * PACKET DEVICE, if ATAPI device, so that the LLDD can fine-tune its
- * performance for this device.
- */
-static int sas_discover_sata_dev(struct domain_device *dev)
-{
-	int     res;
-	__le16  *identify_x;
-	u8      command;
-
-	identify_x = kzalloc(512, GFP_KERNEL);
-	if (!identify_x)
-		return -ENOMEM;
-
-	if (dev->sata_dev.command_set == ATA_COMMAND_SET) {
-		dev->sata_dev.identify_device = identify_x;
-		command = ATA_IDENTIFY_DEV;
-	} else {
-		dev->sata_dev.identify_packet_device = identify_x;
-		command = ATA_IDENTIFY_PACKET_DEV;
-	}
-
-	res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
-				PCI_DMA_FROMDEVICE);
-	if (res)
-		goto out_err;
-
-	/* lives on the media? */
-	if (le16_to_cpu(identify_x[0]) & 4) {
-		/* incomplete response */
-		SAS_DPRINTK("sending SET FEATURE/PUP_STBY_SPIN_UP to "
-			    "dev %llx\n", SAS_ADDR(dev->sas_addr));
-		if (!le16_to_cpu(identify_x[83] & (1<<6)))
-			goto cont1;
-		res = sas_issue_ata_cmd(dev, ATA_SET_FEATURES,
-					ATA_FEATURE_PUP_STBY_SPIN_UP,
-					NULL, 0, PCI_DMA_NONE);
-		if (res)
-			goto cont1;
-
-		schedule_timeout_interruptible(5*HZ); /* More time? */
-		res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
-					PCI_DMA_FROMDEVICE);
-		if (res)
-			goto out_err;
-	}
-cont1:
-	/* Get WWN */
-	if (dev->port->oob_mode != SATA_OOB_MODE) {
-		memcpy(dev->sas_addr, dev->sata_dev.rps_resp.rps.stp_sas_addr,
-		       SAS_ADDR_SIZE);
-	} else if (dev->sata_dev.command_set == ATA_COMMAND_SET &&
-		   (le16_to_cpu(dev->sata_dev.identify_device[108]) & 0xF000)
-		   == 0x5000) {
-		int i;
-
-		for (i = 0; i < 4; i++) {
-			dev->sas_addr[2*i] =
-	     (le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0xFF00) >> 8;
-			dev->sas_addr[2*i+1] =
-	      le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0x00FF;
-		}
-	}
-	sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
-	if (!dev->parent)
-		sas_sata_propagate_sas_addr(dev);
-
-	/* XXX Hint: register this SATA device with SATL.
-	   When this returns, dev->sata_dev->lu is alive and
-	   present.
-	sas_satl_register_dev(dev);
-	*/
-	return 0;
-out_err:
-	dev->sata_dev.identify_packet_device = NULL;
-	dev->sata_dev.identify_device = NULL;
-	kfree(identify_x);
-	return res;
-}
-
-static int sas_discover_sata_pm(struct domain_device *dev)
-{
-	return -ENODEV;
-}
-
 int sas_notify_lldd_dev_found(struct domain_device *dev)
 {
 	int res = 0;
@@ -505,7 +169,7 @@
 		if (res) {
 			printk("sas: driver on pcidev %s cannot handle "
 			       "device %llx, error:%d\n",
-			       pci_name(sas_ha->pcidev),
+			       sas_ha->dev->bus_id,
 			       SAS_ADDR(dev->sas_addr), res);
 		}
 	}
@@ -525,60 +189,6 @@
 
 /* ---------- Common/dispatchers ---------- */
 
-/**
- * sas_discover_sata -- discover an STP/SATA domain device
- * @dev: pointer to struct domain_device of interest
- *
- * First we notify the LLDD of this device, so we can send frames to
- * it.  Then depending on the type of device we call the appropriate
- * discover functions.  Once device discover is done, we notify the
- * LLDD so that it can fine-tune its parameters for the device, by
- * removing it and then adding it.  That is, the second time around,
- * the driver would have certain fields, that it is looking at, set.
- * Finally we initialize the kobj so that the device can be added to
- * the system at registration time.  Devices directly attached to a HA
- * port, have no parents.  All other devices do, and should have their
- * "parent" pointer set appropriately before calling this function.
- */
-int sas_discover_sata(struct domain_device *dev)
-{
-	int res;
-
-	sas_get_ata_command_set(dev);
-
-	res = sas_notify_lldd_dev_found(dev);
-	if (res)
-		goto out_err2;
-
-	switch (dev->dev_type) {
-	case SATA_DEV:
-		res = sas_discover_sata_dev(dev);
-		break;
-	case SATA_PM:
-		res = sas_discover_sata_pm(dev);
-		break;
-	default:
-		break;
-	}
-	if (res)
-		goto out_err;
-
-	sas_notify_lldd_dev_gone(dev);
-	res = sas_notify_lldd_dev_found(dev);
-	if (res)
-		goto out_err2;
-
-	res = sas_rphy_add(dev->rphy);
-	if (res)
-		goto out_err;
-
-	return res;
-
-out_err:
-	sas_notify_lldd_dev_gone(dev);
-out_err2:
-	return res;
-}
 
 /**
  * sas_discover_end_dev -- discover an end device (SSP, etc)
@@ -685,11 +295,14 @@
 	case FANOUT_DEV:
 		error = sas_discover_root_expander(dev);
 		break;
+#ifdef CONFIG_SCSI_SAS_ATA
 	case SATA_DEV:
 	case SATA_PM:
 		error = sas_discover_sata(dev);
 		break;
+#endif
 	default:
+		error = -ENXIO;
 		SAS_DPRINTK("unhandled device %d\n", dev->dev_type);
 		break;
 	}
@@ -698,9 +311,9 @@
 		sas_rphy_free(dev->rphy);
 		dev->rphy = NULL;
 
-		spin_lock(&port->dev_list_lock);
+		spin_lock_irq(&port->dev_list_lock);
 		list_del_init(&dev->dev_list_node);
-		spin_unlock(&port->dev_list_lock);
+		spin_unlock_irq(&port->dev_list_lock);
 
 		kfree(dev); /* not kobject_register-ed yet */
 		port->port_dev = NULL;
diff --git a/drivers/scsi/libsas/sas_dump.c b/drivers/scsi/libsas/sas_dump.c
index f1246d2..bf34a23 100644
--- a/drivers/scsi/libsas/sas_dump.c
+++ b/drivers/scsi/libsas/sas_dump.c
@@ -56,7 +56,7 @@
 
 void sas_dprint_hae(struct sas_ha_struct *sas_ha, enum ha_event he)
 {
-	SAS_DPRINTK("ha %s: %s event\n", pci_name(sas_ha->pcidev),
+	SAS_DPRINTK("ha %s: %s event\n", sas_ha->dev->bus_id,
 		    sas_hae_str[he]);
 }
 
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 23e90c5..8727436 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -23,6 +23,7 @@
  */
 
 #include <linux/scatterlist.h>
+#include <linux/blkdev.h>
 
 #include "sas_internal.h"
 
@@ -36,14 +37,6 @@
 			     u8 *sas_addr, int include);
 static int sas_disable_routing(struct domain_device *dev,  u8 *sas_addr);
 
-#if 0
-/* FIXME: smp needs to migrate into the sas class */
-static ssize_t smp_portal_read(struct kobject *, struct bin_attribute *,
-			       char *, loff_t, size_t);
-static ssize_t smp_portal_write(struct kobject *, struct bin_attribute *,
-				char *, loff_t, size_t);
-#endif
-
 /* ---------- SMP task management ---------- */
 
 static void smp_task_timedout(unsigned long _task)
@@ -220,6 +213,36 @@
 #define DISCOVER_REQ_SIZE  16
 #define DISCOVER_RESP_SIZE 56
 
+static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req,
+				      u8 *disc_resp, int single)
+{
+	int i, res;
+
+	disc_req[9] = single;
+	for (i = 1 ; i < 3; i++) {
+		struct discover_resp *dr;
+
+		res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
+				       disc_resp, DISCOVER_RESP_SIZE);
+		if (res)
+			return res;
+		/* This is detecting a failure to transmit inital
+		 * dev to host FIS as described in section G.5 of
+		 * sas-2 r 04b */
+		dr = &((struct smp_resp *)disc_resp)->disc;
+		if (!(dr->attached_dev_type == 0 &&
+		      dr->attached_sata_dev))
+			break;
+		/* In order to generate the dev to host FIS, we
+		 * send a link reset to the expander port */
+		sas_smp_phy_control(dev, single, PHY_FUNC_LINK_RESET, NULL);
+		/* Wait for the reset to trigger the negotiation */
+		msleep(500);
+	}
+	sas_set_ex_phy(dev, single, disc_resp);
+	return 0;
+}
+
 static int sas_ex_phy_discover(struct domain_device *dev, int single)
 {
 	struct expander_device *ex = &dev->ex_dev;
@@ -240,23 +263,15 @@
 	disc_req[1] = SMP_DISCOVER;
 
 	if (0 <= single && single < ex->num_phys) {
-		disc_req[9] = single;
-		res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
-				       disc_resp, DISCOVER_RESP_SIZE);
-		if (res)
-			goto out_err;
-		sas_set_ex_phy(dev, single, disc_resp);
+		res = sas_ex_phy_discover_helper(dev, disc_req, disc_resp, single);
 	} else {
 		int i;
 
 		for (i = 0; i < ex->num_phys; i++) {
-			disc_req[9] = i;
-			res = smp_execute_task(dev, disc_req,
-					       DISCOVER_REQ_SIZE, disc_resp,
-					       DISCOVER_RESP_SIZE);
+			res = sas_ex_phy_discover_helper(dev, disc_req,
+							 disc_resp, i);
 			if (res)
 				goto out_err;
-			sas_set_ex_phy(dev, i, disc_resp);
 		}
 	}
 out_err:
@@ -492,14 +507,21 @@
 int sas_smp_get_phy_events(struct sas_phy *phy)
 {
 	int res;
+	u8 *req;
+	u8 *resp;
 	struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
 	struct domain_device *dev = sas_find_dev_by_rphy(rphy);
-	u8 *req = alloc_smp_req(RPEL_REQ_SIZE);
-	u8 *resp = kzalloc(RPEL_RESP_SIZE, GFP_KERNEL);
 
-	if (!resp)
+	req = alloc_smp_req(RPEL_REQ_SIZE);
+	if (!req)
 		return -ENOMEM;
 
+	resp = alloc_smp_resp(RPEL_RESP_SIZE);
+	if (!resp) {
+		kfree(req);
+		return -ENOMEM;
+	}
+
 	req[1] = SMP_REPORT_PHY_ERR_LOG;
 	req[9] = phy->number;
 
@@ -520,6 +542,8 @@
 
 }
 
+#ifdef CONFIG_SCSI_SAS_ATA
+
 #define RPS_REQ_SIZE  16
 #define RPS_RESP_SIZE 60
 
@@ -529,6 +553,7 @@
 {
 	int res;
 	u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE);
+	u8 *resp = (u8 *)rps_resp;
 
 	if (!rps_req)
 		return -ENOMEM;
@@ -539,9 +564,30 @@
 	res = smp_execute_task(dev, rps_req, RPS_REQ_SIZE,
 			            rps_resp, RPS_RESP_SIZE);
 
+	/* 0x34 is the FIS type for the D2H fis.  There's a potential
+	 * standards cockup here.  sas-2 explicitly specifies the FIS
+	 * should be encoded so that FIS type is in resp[24].
+	 * However, some expanders endian reverse this.  Undo the
+	 * reversal here */
+	if (!res && resp[27] == 0x34 && resp[24] != 0x34) {
+		int i;
+
+		for (i = 0; i < 5; i++) {
+			int j = 24 + (i*4);
+			u8 a, b;
+			a = resp[j + 0];
+			b = resp[j + 1];
+			resp[j + 0] = resp[j + 3];
+			resp[j + 1] = resp[j + 2];
+			resp[j + 2] = b;
+			resp[j + 3] = a;
+		}
+	}
+
 	kfree(rps_req);
-	return 0;
+	return res;
 }
+#endif
 
 static void sas_ex_get_linkrate(struct domain_device *parent,
 				       struct domain_device *child,
@@ -609,6 +655,7 @@
 	}
 	sas_ex_get_linkrate(parent, child, phy);
 
+#ifdef CONFIG_SCSI_SAS_ATA
 	if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) {
 		child->dev_type = SATA_DEV;
 		if (phy->attached_tproto & SAS_PROTO_STP)
@@ -625,16 +672,30 @@
 		}
 		memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis,
 		       sizeof(struct dev_to_host_fis));
+
+		rphy = sas_end_device_alloc(phy->port);
+		if (unlikely(!rphy))
+			goto out_free;
+
 		sas_init_dev(child);
+
+		child->rphy = rphy;
+
+		spin_lock_irq(&parent->port->dev_list_lock);
+		list_add_tail(&child->dev_list_node, &parent->port->dev_list);
+		spin_unlock_irq(&parent->port->dev_list_lock);
+
 		res = sas_discover_sata(child);
 		if (res) {
 			SAS_DPRINTK("sas_discover_sata() for device %16llx at "
 				    "%016llx:0x%x returned 0x%x\n",
 				    SAS_ADDR(child->sas_addr),
 				    SAS_ADDR(parent->sas_addr), phy_id, res);
-			goto out_free;
+			goto out_list_del;
 		}
-	} else if (phy->attached_tproto & SAS_PROTO_SSP) {
+	} else
+#endif
+	  if (phy->attached_tproto & SAS_PROTO_SSP) {
 		child->dev_type = SAS_END_DEV;
 		rphy = sas_end_device_alloc(phy->port);
 		/* FIXME: error handling */
@@ -646,9 +707,9 @@
 		child->rphy = rphy;
 		sas_fill_in_rphy(child, rphy);
 
-		spin_lock(&parent->port->dev_list_lock);
+		spin_lock_irq(&parent->port->dev_list_lock);
 		list_add_tail(&child->dev_list_node, &parent->port->dev_list);
-		spin_unlock(&parent->port->dev_list_lock);
+		spin_unlock_irq(&parent->port->dev_list_lock);
 
 		res = sas_discover_end_dev(child);
 		if (res) {
@@ -662,6 +723,7 @@
 		SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n",
 			    phy->attached_tproto, SAS_ADDR(parent->sas_addr),
 			    phy_id);
+		goto out_free;
 	}
 
 	list_add_tail(&child->siblings, &parent_ex->children);
@@ -761,9 +823,9 @@
 	sas_fill_in_rphy(child, rphy);
 	sas_rphy_add(rphy);
 
-	spin_lock(&parent->port->dev_list_lock);
+	spin_lock_irq(&parent->port->dev_list_lock);
 	list_add_tail(&child->dev_list_node, &parent->port->dev_list);
-	spin_unlock(&parent->port->dev_list_lock);
+	spin_unlock_irq(&parent->port->dev_list_lock);
 
 	res = sas_discover_expander(child);
 	if (res) {
@@ -1359,30 +1421,6 @@
 	return 0;
 }
 
-#if 0
-#define SMP_BIN_ATTR_NAME "smp_portal"
-
-static void sas_ex_smp_hook(struct domain_device *dev)
-{
-	struct expander_device *ex_dev = &dev->ex_dev;
-	struct bin_attribute *bin_attr = &ex_dev->smp_bin_attr;
-
-	memset(bin_attr, 0, sizeof(*bin_attr));
-
-	bin_attr->attr.name = SMP_BIN_ATTR_NAME;
-	bin_attr->attr.mode = 0600;
-
-	bin_attr->size = 0;
-	bin_attr->private = NULL;
-	bin_attr->read = smp_portal_read;
-	bin_attr->write= smp_portal_write;
-	bin_attr->mmap = NULL;
-
-	ex_dev->smp_portal_pid = -1;
-	init_MUTEX(&ex_dev->smp_sema);
-}
-#endif
-
 /**
  * sas_discover_expander -- expander discovery
  * @ex: pointer to expander domain device
@@ -1844,76 +1882,50 @@
 	return res;
 }
 
-#if 0
-/* ---------- SMP portal ---------- */
-
-static ssize_t smp_portal_write(struct kobject *kobj,
-				struct bin_attribute *bin_attr,
-				char *buf, loff_t offs, size_t size)
+int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
+		    struct request *req)
 {
-	struct domain_device *dev = to_dom_device(kobj);
-	struct expander_device *ex = &dev->ex_dev;
+	struct domain_device *dev;
+	int ret, type;
+	struct request *rsp = req->next_rq;
 
-	if (offs != 0)
-		return -EFBIG;
-	else if (size == 0)
-		return 0;
-
-	down_interruptible(&ex->smp_sema);
-	if (ex->smp_req)
-		kfree(ex->smp_req);
-	ex->smp_req = kzalloc(size, GFP_USER);
-	if (!ex->smp_req) {
-		up(&ex->smp_sema);
-		return -ENOMEM;
-	}
-	memcpy(ex->smp_req, buf, size);
-	ex->smp_req_size = size;
-	ex->smp_portal_pid = current->pid;
-	up(&ex->smp_sema);
-
-	return size;
-}
-
-static ssize_t smp_portal_read(struct kobject *kobj,
-			       struct bin_attribute *bin_attr,
-			       char *buf, loff_t offs, size_t size)
-{
-	struct domain_device *dev = to_dom_device(kobj);
-	struct expander_device *ex = &dev->ex_dev;
-	u8 *smp_resp;
-	int res = -EINVAL;
-
-	/* XXX: sysfs gives us an offset of 0x10 or 0x8 while in fact
-	 *  it should be 0.
-	 */
-
-	down_interruptible(&ex->smp_sema);
-	if (!ex->smp_req || ex->smp_portal_pid != current->pid)
-		goto out;
-
-	res = 0;
-	if (size == 0)
-		goto out;
-
-	res = -ENOMEM;
-	smp_resp = alloc_smp_resp(size);
-	if (!smp_resp)
-		goto out;
-	res = smp_execute_task(dev, ex->smp_req, ex->smp_req_size,
-			       smp_resp, size);
-	if (!res) {
-		memcpy(buf, smp_resp, size);
-		res = size;
+	if (!rsp) {
+		printk("%s: space for a smp response is missing\n",
+		       __FUNCTION__);
+		return -EINVAL;
 	}
 
-	kfree(smp_resp);
-out:
-	kfree(ex->smp_req);
-	ex->smp_req = NULL;
-	ex->smp_req_size = 0;
-	ex->smp_portal_pid = -1;
-	up(&ex->smp_sema);
-	return res;
+	/* no rphy means no smp target support (ie aic94xx host) */
+	if (!rphy) {
+		printk("%s: can we send a smp request to a host?\n",
+		       __FUNCTION__);
+		return -EINVAL;
+	}
+	type = rphy->identify.device_type;
+
+	if (type != SAS_EDGE_EXPANDER_DEVICE &&
+	    type != SAS_FANOUT_EXPANDER_DEVICE) {
+		printk("%s: can we send a smp request to a device?\n",
+		       __FUNCTION__);
+		return -EINVAL;
+	}
+
+	dev = sas_find_dev_by_rphy(rphy);
+	if (!dev) {
+		printk("%s: fail to find a domain_device?\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	/* do we need to support multiple segments? */
+	if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
+		printk("%s: multiple segments req %u %u, rsp %u %u\n",
+		       __FUNCTION__, req->bio->bi_vcnt, req->data_len,
+		       rsp->bio->bi_vcnt, rsp->data_len);
+		return -EINVAL;
+	}
+
+	ret = smp_execute_task(dev, bio_data(req->bio), req->data_len,
+			       bio_data(rsp->bio), rsp->data_len);
+
+	return ret;
 }
-#endif
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index 965698c..9cd5abe 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -259,6 +259,7 @@
 	.phy_reset = sas_phy_reset,
 	.set_phy_speed = sas_set_phy_speed,
 	.get_linkerrors = sas_get_linkerrors,
+	.smp_handler = sas_smp_handler,
 };
 
 struct scsi_transport_template *
@@ -292,7 +293,7 @@
 static int __init sas_class_init(void)
 {
 	sas_task_cache = kmem_cache_create("sas_task", sizeof(struct sas_task),
-					   0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+					   0, SLAB_HWCACHE_ALIGN, NULL);
 	if (!sas_task_cache)
 		return -ENOMEM;
 
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index a78638d..2b8213b 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -39,6 +39,9 @@
 #define SAS_DPRINTK(fmt, ...)
 #endif
 
+#define TO_SAS_TASK(_scsi_cmd)  ((void *)(_scsi_cmd)->host_scribble)
+#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)
+
 void sas_scsi_recover_host(struct Scsi_Host *shost);
 
 int sas_show_class(enum sas_class class, char *buf);
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 9c5342e..7663841 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -34,6 +34,7 @@
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_transport_sas.h>
+#include <scsi/sas_ata.h>
 #include "../scsi_sas_internal.h"
 #include "../scsi_transport_api.h"
 #include "../scsi_priv.h"
@@ -42,12 +43,10 @@
 #include <linux/blkdev.h>
 #include <linux/freezer.h>
 #include <linux/scatterlist.h>
+#include <linux/libata.h>
 
 /* ---------- SCSI Host glue ---------- */
 
-#define TO_SAS_TASK(_scsi_cmd)  ((void *)(_scsi_cmd)->host_scribble)
-#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)
-
 static void sas_scsi_task_done(struct sas_task *task)
 {
 	struct task_status_struct *ts = &task->task_status;
@@ -172,7 +171,7 @@
 	return task;
 }
 
-static int sas_queue_up(struct sas_task *task)
+int sas_queue_up(struct sas_task *task)
 {
 	struct sas_ha_struct *sas_ha = task->dev->port->ha;
 	struct scsi_core *core = &sas_ha->core;
@@ -213,6 +212,16 @@
 		struct sas_ha_struct *sas_ha = dev->port->ha;
 		struct sas_task *task;
 
+		if (dev_is_sata(dev)) {
+			unsigned long flags;
+
+			spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
+			res = ata_sas_queuecmd(cmd, scsi_done,
+					       dev->sata_dev.ap);
+			spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
+			goto out;
+		}
+
 		res = -ENOMEM;
 		task = sas_create_task(cmd, dev, GFP_ATOMIC);
 		if (!task)
@@ -684,6 +693,16 @@
 	return EH_NOT_HANDLED;
 }
 
+int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+{
+	struct domain_device *dev = sdev_to_domain_dev(sdev);
+
+	if (dev_is_sata(dev))
+		return ata_scsi_ioctl(sdev, cmd, arg);
+
+	return -EINVAL;
+}
+
 struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy)
 {
 	struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent);
@@ -723,10 +742,17 @@
 int sas_target_alloc(struct scsi_target *starget)
 {
 	struct domain_device *found_dev = sas_find_target(starget);
+	int res;
 
 	if (!found_dev)
 		return -ENODEV;
 
+	if (dev_is_sata(found_dev)) {
+		res = sas_ata_init_host_and_port(found_dev, starget);
+		if (res)
+			return res;
+	}
+
 	starget->hostdata = found_dev;
 	return 0;
 }
@@ -741,6 +767,11 @@
 
 	BUG_ON(dev->rphy->identify.device_type != SAS_END_DEVICE);
 
+	if (dev_is_sata(dev)) {
+		ata_sas_slave_configure(scsi_dev, dev->sata_dev.ap);
+		return 0;
+	}
+
 	sas_ha = dev->port->ha;
 
 	sas_read_port_mode_page(scsi_dev);
@@ -764,6 +795,10 @@
 
 void sas_slave_destroy(struct scsi_device *scsi_dev)
 {
+	struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
+
+	if (dev_is_sata(dev))
+		ata_port_disable(dev->sata_dev.ap);
 }
 
 int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth)
@@ -980,10 +1015,38 @@
 		return;
 	}
 
+	if (dev_is_sata(task->dev)) {
+		sas_ata_task_abort(task);
+		return;
+	}
+
 	scsi_req_abort_cmd(sc);
 	scsi_schedule_eh(sc->device->host);
 }
 
+int sas_slave_alloc(struct scsi_device *scsi_dev)
+{
+	struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
+
+	if (dev_is_sata(dev))
+		return ata_sas_port_init(dev->sata_dev.ap);
+
+	return 0;
+}
+
+void sas_target_destroy(struct scsi_target *starget)
+{
+	struct domain_device *found_dev = sas_find_target(starget);
+
+	if (!found_dev)
+		return;
+
+	if (dev_is_sata(found_dev))
+		ata_sas_port_destroy(found_dev->sata_dev.ap);
+
+	return;
+}
+
 EXPORT_SYMBOL_GPL(sas_queuecommand);
 EXPORT_SYMBOL_GPL(sas_target_alloc);
 EXPORT_SYMBOL_GPL(sas_slave_configure);
@@ -997,3 +1060,6 @@
 EXPORT_SYMBOL_GPL(sas_phy_enable);
 EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler);
 EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler);
+EXPORT_SYMBOL_GPL(sas_slave_alloc);
+EXPORT_SYMBOL_GPL(sas_target_destroy);
+EXPORT_SYMBOL_GPL(sas_ioctl);
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index f8f64d6..ba3ecab 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -45,7 +45,7 @@
 #define LPFC_DISC_IOCB_BUFF_COUNT 20
 
 #define LPFC_HB_MBOX_INTERVAL   5	/* Heart beat interval in seconds. */
-#define LPFC_HB_MBOX_TIMEOUT    30 	/* Heart beat timeout  in seconds. */
+#define LPFC_HB_MBOX_TIMEOUT    30	/* Heart beat timeout  in seconds. */
 
 /* Define macros for 64 bit support */
 #define putPaddrLow(addr)    ((uint32_t) (0xffffffff & (u64)(addr)))
@@ -78,6 +78,7 @@
 
 struct hbq_dmabuf {
 	struct lpfc_dmabuf dbuf;
+	uint32_t size;
 	uint32_t tag;
 };
 
@@ -329,13 +330,30 @@
 #define FC_LOADING		0x1	/* HBA in process of loading drvr */
 #define FC_UNLOADING		0x2	/* HBA in process of unloading drvr */
 	char  *vname;		        /* Application assigned name */
+
+	/* Vport Config Parameters */
+	uint32_t cfg_scan_down;
+	uint32_t cfg_lun_queue_depth;
+	uint32_t cfg_nodev_tmo;
+	uint32_t cfg_devloss_tmo;
+	uint32_t cfg_restrict_login;
+	uint32_t cfg_peer_port_login;
+	uint32_t cfg_fcp_class;
+	uint32_t cfg_use_adisc;
+	uint32_t cfg_fdmi_on;
+	uint32_t cfg_discovery_threads;
+	uint32_t cfg_log_verbose;
+	uint32_t cfg_max_luns;
+
+	uint32_t dev_loss_tmo_changed;
+
 	struct fc_vport *fc_vport;
 
 #ifdef CONFIG_LPFC_DEBUG_FS
 	struct dentry *debug_disc_trc;
 	struct dentry *debug_nodelist;
 	struct dentry *vport_debugfs_root;
-	struct lpfc_disc_trc *disc_trc;
+	struct lpfc_debugfs_trc *disc_trc;
 	atomic_t disc_trc_cnt;
 #endif
 };
@@ -345,17 +363,25 @@
 	uint32_t next_hbqPutIdx;  /* Index to next HBQ slot to use */
 	uint32_t hbqPutIdx;	  /* HBQ slot to use */
 	uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */
+	void    *hbq_virt;	  /* Virtual ptr to this hbq */
+	struct list_head hbq_buffer_list;  /* buffers assigned to this HBQ */
+				  /* Callback for HBQ buffer allocation */
+	struct hbq_dmabuf *(*hbq_alloc_buffer) (struct lpfc_hba *);
+				  /* Callback for HBQ buffer free */
+	void               (*hbq_free_buffer) (struct lpfc_hba *,
+					       struct hbq_dmabuf *);
 };
 
-#define LPFC_MAX_HBQS  16
-/* this matches the possition in the lpfc_hbq_defs array */
+#define LPFC_MAX_HBQS  4
+/* this matches the position in the lpfc_hbq_defs array */
 #define LPFC_ELS_HBQ	0
+#define LPFC_EXTRA_HBQ	1
 
 struct lpfc_hba {
 	struct lpfc_sli sli;
 	uint32_t sli_rev;		/* SLI2 or SLI3 */
 	uint32_t sli3_options;		/* Mask of enabled SLI3 options */
-#define LPFC_SLI3_ENABLED 	 0x01
+#define LPFC_SLI3_ENABLED	 0x01
 #define LPFC_SLI3_HBQ_ENABLED	 0x02
 #define LPFC_SLI3_NPIV_ENABLED	 0x04
 #define LPFC_SLI3_VPORT_TEARDOWN 0x08
@@ -364,7 +390,7 @@
 
 	enum hba_state link_state;
 	uint32_t link_flag;	/* link state flags */
-#define LS_LOOPBACK_MODE      0x1 	/* NPort is in Loopback mode */
+#define LS_LOOPBACK_MODE      0x1	/* NPort is in Loopback mode */
 					/* This flag is set while issuing */
 					/* INIT_LINK mailbox command */
 #define LS_NPIV_FAB_SUPPORTED 0x2	/* Fabric supports NPIV */
@@ -413,28 +439,16 @@
 	uint8_t  wwpn[8];
 	uint32_t RandomData[7];
 
-	uint32_t cfg_log_verbose;
-	uint32_t cfg_lun_queue_depth;
-	uint32_t cfg_nodev_tmo;
-	uint32_t cfg_devloss_tmo;
-	uint32_t cfg_hba_queue_depth;
-	uint32_t cfg_peer_port_login;
-	uint32_t cfg_vport_restrict_login;
-	uint32_t cfg_npiv_enable;
-	uint32_t cfg_fcp_class;
-	uint32_t cfg_use_adisc;
+	/* HBA Config Parameters */
 	uint32_t cfg_ack0;
+	uint32_t cfg_enable_npiv;
 	uint32_t cfg_topology;
-	uint32_t cfg_scan_down;
 	uint32_t cfg_link_speed;
 	uint32_t cfg_cr_delay;
 	uint32_t cfg_cr_count;
 	uint32_t cfg_multi_ring_support;
 	uint32_t cfg_multi_ring_rctl;
 	uint32_t cfg_multi_ring_type;
-	uint32_t cfg_fdmi_on;
-	uint32_t cfg_discovery_threads;
-	uint32_t cfg_max_luns;
 	uint32_t cfg_poll;
 	uint32_t cfg_poll_tmo;
 	uint32_t cfg_use_msi;
@@ -442,8 +456,8 @@
 	uint32_t cfg_sg_dma_buf_size;
 	uint64_t cfg_soft_wwnn;
 	uint64_t cfg_soft_wwpn;
+	uint32_t cfg_hba_queue_depth;
 
-	uint32_t dev_loss_tmo_changed;
 
 	lpfc_vpd_t vpd;		/* vital product data */
 
@@ -457,7 +471,6 @@
 	wait_queue_head_t    *work_wait;
 	struct task_struct   *worker_thread;
 
-	struct list_head hbq_buffer_list;
 	uint32_t hbq_count;	        /* Count of configured HBQs */
 	struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies  */
 
@@ -526,12 +539,14 @@
 	mempool_t *nlp_mem_pool;
 
 	struct fc_host_statistics link_stats;
+	uint8_t using_msi;
 
 	struct list_head port_list;
-	struct lpfc_vport *pport; /* physical lpfc_vport pointer */
-	uint16_t max_vpi;	/* Maximum virtual nports */
-#define LPFC_MAX_VPI 100  /* Max number of VPorts supported */
-	unsigned long *vpi_bmask; /* vpi allocation table */
+	struct lpfc_vport *pport;	/* physical lpfc_vport pointer */
+	uint16_t max_vpi;		/* Maximum virtual nports */
+#define LPFC_MAX_VPI 100		/* Max number of VPI supported */
+#define LPFC_MAX_VPORTS (LPFC_MAX_VPI+1)/* Max number of VPorts supported */
+	unsigned long *vpi_bmask;	/* vpi allocation table */
 
 	/* Data structure used by fabric iocb scheduler */
 	struct list_head fabric_iocb_list;
@@ -547,6 +562,11 @@
 #ifdef CONFIG_LPFC_DEBUG_FS
 	struct dentry *hba_debugfs_root;
 	atomic_t debugfs_vport_count;
+	struct dentry *debug_hbqinfo;
+	struct dentry *debug_dumpslim;
+	struct dentry *debug_slow_ring_trc;
+	struct lpfc_debugfs_trc *slow_ring_trc;
+	atomic_t slow_ring_trc_cnt;
 #endif
 
 	/* Fields used for heart beat. */
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 860a52c..80a1121 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -68,12 +68,6 @@
 }
 
 static ssize_t
-management_version_show(struct class_device *cdev, char *buf)
-{
-	return snprintf(buf, PAGE_SIZE, DFC_API_VERSION "\n");
-}
-
-static ssize_t
 lpfc_info_show(struct class_device *cdev, char *buf)
 {
 	struct Scsi_Host *host = class_to_shost(cdev);
@@ -319,9 +313,8 @@
 			if (cnt++ > 3000) {
 				lpfc_printf_log(phba,
 					KERN_WARNING, LOG_INIT,
-					"%d:0466 Outstanding IO when "
-					"bringing Adapter offline\n",
-					phba->brd_no);
+					"0466 Outstanding IO when "
+					"bringing Adapter offline\n");
 				break;
 			}
 		}
@@ -437,7 +430,7 @@
 		return -EIO;
 }
 
-int
+static int
 lpfc_get_hba_info(struct lpfc_hba *phba,
 		  uint32_t *mxri, uint32_t *axri,
 		  uint32_t *mrpi, uint32_t *arpi,
@@ -694,9 +687,8 @@
 		return 0;\
 	}\
 	lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \
-			"%d:0449 lpfc_"#attr" attribute cannot be set to %d, "\
-			"allowed range is ["#minval", "#maxval"]\n", \
-			phba->brd_no, val); \
+			"0449 lpfc_"#attr" attribute cannot be set to %d, "\
+			"allowed range is ["#minval", "#maxval"]\n", val); \
 	phba->cfg_##attr = default;\
 	return -EINVAL;\
 }
@@ -710,9 +702,8 @@
 		return 0;\
 	}\
 	lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \
-			"%d:0450 lpfc_"#attr" attribute cannot be set to %d, "\
-			"allowed range is ["#minval", "#maxval"]\n", \
-			phba->brd_no, val); \
+			"0450 lpfc_"#attr" attribute cannot be set to %d, "\
+			"allowed range is ["#minval", "#maxval"]\n", val); \
 	return -EINVAL;\
 }
 
@@ -734,6 +725,75 @@
 		return -EINVAL;\
 }
 
+#define lpfc_vport_param_show(attr)	\
+static ssize_t \
+lpfc_##attr##_show(struct class_device *cdev, char *buf) \
+{ \
+	struct Scsi_Host  *shost = class_to_shost(cdev);\
+	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
+	int val = 0;\
+	val = vport->cfg_##attr;\
+	return snprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_##attr);\
+}
+
+#define lpfc_vport_param_hex_show(attr)	\
+static ssize_t \
+lpfc_##attr##_show(struct class_device *cdev, char *buf) \
+{ \
+	struct Scsi_Host  *shost = class_to_shost(cdev);\
+	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
+	int val = 0;\
+	val = vport->cfg_##attr;\
+	return snprintf(buf, PAGE_SIZE, "%#x\n", vport->cfg_##attr);\
+}
+
+#define lpfc_vport_param_init(attr, default, minval, maxval)	\
+static int \
+lpfc_##attr##_init(struct lpfc_vport *vport, int val) \
+{ \
+	if (val >= minval && val <= maxval) {\
+		vport->cfg_##attr = val;\
+		return 0;\
+	}\
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \
+			 "0449 lpfc_"#attr" attribute cannot be set to %d, "\
+			 "allowed range is ["#minval", "#maxval"]\n", val); \
+	vport->cfg_##attr = default;\
+	return -EINVAL;\
+}
+
+#define lpfc_vport_param_set(attr, default, minval, maxval)	\
+static int \
+lpfc_##attr##_set(struct lpfc_vport *vport, int val) \
+{ \
+	if (val >= minval && val <= maxval) {\
+		vport->cfg_##attr = val;\
+		return 0;\
+	}\
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \
+			 "0450 lpfc_"#attr" attribute cannot be set to %d, "\
+			 "allowed range is ["#minval", "#maxval"]\n", val); \
+	return -EINVAL;\
+}
+
+#define lpfc_vport_param_store(attr)	\
+static ssize_t \
+lpfc_##attr##_store(struct class_device *cdev, const char *buf, size_t count) \
+{ \
+	struct Scsi_Host  *shost = class_to_shost(cdev);\
+	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\
+	int val=0;\
+	if (!isdigit(buf[0]))\
+		return -EINVAL;\
+	if (sscanf(buf, "%i", &val) != 1)\
+		return -EINVAL;\
+	if (lpfc_##attr##_set(vport, val) == 0) \
+		return strlen(buf);\
+	else \
+		return -EINVAL;\
+}
+
+
 #define LPFC_ATTR(name, defval, minval, maxval, desc) \
 static int lpfc_##name = defval;\
 module_param(lpfc_##name, int, 0);\
@@ -778,6 +838,50 @@
 static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
 			 lpfc_##name##_show, lpfc_##name##_store)
 
+#define LPFC_VPORT_ATTR(name, defval, minval, maxval, desc) \
+static int lpfc_##name = defval;\
+module_param(lpfc_##name, int, 0);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_vport_param_init(name, defval, minval, maxval)
+
+#define LPFC_VPORT_ATTR_R(name, defval, minval, maxval, desc) \
+static int lpfc_##name = defval;\
+module_param(lpfc_##name, int, 0);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_vport_param_show(name)\
+lpfc_vport_param_init(name, defval, minval, maxval)\
+static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
+
+#define LPFC_VPORT_ATTR_RW(name, defval, minval, maxval, desc) \
+static int lpfc_##name = defval;\
+module_param(lpfc_##name, int, 0);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_vport_param_show(name)\
+lpfc_vport_param_init(name, defval, minval, maxval)\
+lpfc_vport_param_set(name, defval, minval, maxval)\
+lpfc_vport_param_store(name)\
+static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
+			 lpfc_##name##_show, lpfc_##name##_store)
+
+#define LPFC_VPORT_ATTR_HEX_R(name, defval, minval, maxval, desc) \
+static int lpfc_##name = defval;\
+module_param(lpfc_##name, int, 0);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_vport_param_hex_show(name)\
+lpfc_vport_param_init(name, defval, minval, maxval)\
+static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL)
+
+#define LPFC_VPORT_ATTR_HEX_RW(name, defval, minval, maxval, desc) \
+static int lpfc_##name = defval;\
+module_param(lpfc_##name, int, 0);\
+MODULE_PARM_DESC(lpfc_##name, desc);\
+lpfc_vport_param_hex_show(name)\
+lpfc_vport_param_init(name, defval, minval, maxval)\
+lpfc_vport_param_set(name, defval, minval, maxval)\
+lpfc_vport_param_store(name)\
+static CLASS_DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\
+			 lpfc_##name##_show, lpfc_##name##_store)
+
 static CLASS_DEVICE_ATTR(info, S_IRUGO, lpfc_info_show, NULL);
 static CLASS_DEVICE_ATTR(serialnum, S_IRUGO, lpfc_serialnum_show, NULL);
 static CLASS_DEVICE_ATTR(modeldesc, S_IRUGO, lpfc_modeldesc_show, NULL);
@@ -794,8 +898,6 @@
 static CLASS_DEVICE_ATTR(nport_evt_cnt, S_IRUGO, lpfc_nport_evt_cnt_show, NULL);
 static CLASS_DEVICE_ATTR(lpfc_drvr_version, S_IRUGO, lpfc_drvr_version_show,
 			 NULL);
-static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show,
-			 NULL);
 static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR,
 			 lpfc_board_mode_show, lpfc_board_mode_store);
 static CLASS_DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset);
@@ -908,17 +1010,15 @@
 	stat1 = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
 	if (stat1)
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-			"%d:0463 lpfc_soft_wwpn attribute set failed to reinit "
-			"adapter - %d\n", phba->brd_no, stat1);
-
+				"0463 lpfc_soft_wwpn attribute set failed to "
+				"reinit adapter - %d\n", stat1);
 	init_completion(&online_compl);
 	lpfc_workq_post_event(phba, &stat2, &online_compl, LPFC_EVT_ONLINE);
 	wait_for_completion(&online_compl);
 	if (stat2)
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-			"%d:0464 lpfc_soft_wwpn attribute set failed to reinit "
-			"adapter - %d\n", phba->brd_no, stat2);
-
+				"0464 lpfc_soft_wwpn attribute set failed to "
+				"reinit adapter - %d\n", stat2);
 	return (stat1 || stat2) ? -EIO : count;
 }
 static CLASS_DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,\
@@ -927,8 +1027,8 @@
 static ssize_t
 lpfc_soft_wwnn_show(struct class_device *cdev, char *buf)
 {
-	struct Scsi_Host *host = class_to_shost(cdev);
-	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+	struct Scsi_Host *shost = class_to_shost(cdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
 	return snprintf(buf, PAGE_SIZE, "0x%llx\n",
 			(unsigned long long)phba->cfg_soft_wwnn);
 }
@@ -937,8 +1037,8 @@
 static ssize_t
 lpfc_soft_wwnn_store(struct class_device *cdev, const char *buf, size_t count)
 {
-	struct Scsi_Host *host = class_to_shost(cdev);
-	struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+	struct Scsi_Host *shost = class_to_shost(cdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
 	unsigned int i, j, cnt=count;
 	u8 wwnn[8];
 
@@ -1002,7 +1102,7 @@
 		 " 2 - select SLI-2 even on SLI-3 capable HBAs,"
 		 " 3 - select SLI-3");
 
-LPFC_ATTR_R(npiv_enable, 0, 0, 1, "Enable NPIV functionality");
+LPFC_ATTR_R(enable_npiv, 0, 0, 1, "Enable NPIV functionality");
 
 /*
 # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
@@ -1019,90 +1119,75 @@
 {
 	struct Scsi_Host  *shost = class_to_shost(cdev);
 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
-	struct lpfc_hba   *phba = vport->phba;
 	int val = 0;
-	val = phba->cfg_devloss_tmo;
-	return snprintf(buf, PAGE_SIZE, "%d\n",
-			phba->cfg_devloss_tmo);
+	val = vport->cfg_devloss_tmo;
+	return snprintf(buf, PAGE_SIZE, "%d\n",	vport->cfg_devloss_tmo);
 }
 
 static int
-lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val)
+lpfc_nodev_tmo_init(struct lpfc_vport *vport, int val)
 {
-	static int warned;
-	if (phba->cfg_devloss_tmo !=  LPFC_DEF_DEVLOSS_TMO) {
-		phba->cfg_nodev_tmo = phba->cfg_devloss_tmo;
-		if (!warned && val != LPFC_DEF_DEVLOSS_TMO) {
-			warned = 1;
-			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-					"%d:0402 Ignoring nodev_tmo module "
-					"parameter because devloss_tmo is"
-					" set.\n",
-					phba->brd_no);
-		}
+	if (vport->cfg_devloss_tmo != LPFC_DEF_DEVLOSS_TMO) {
+		vport->cfg_nodev_tmo = vport->cfg_devloss_tmo;
+		if (val != LPFC_DEF_DEVLOSS_TMO)
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+					 "0402 Ignoring nodev_tmo module "
+					 "parameter because devloss_tmo is "
+					 "set.\n");
 		return 0;
 	}
 
 	if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
-		phba->cfg_nodev_tmo = val;
-		phba->cfg_devloss_tmo = val;
+		vport->cfg_nodev_tmo = val;
+		vport->cfg_devloss_tmo = val;
 		return 0;
 	}
-	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-			"%d:0400 lpfc_nodev_tmo attribute cannot be set to %d, "
-			"allowed range is [%d, %d]\n",
-			phba->brd_no, val,
-			LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO);
-	phba->cfg_nodev_tmo = LPFC_DEF_DEVLOSS_TMO;
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+			 "0400 lpfc_nodev_tmo attribute cannot be set to"
+			 " %d, allowed range is [%d, %d]\n",
+			 val, LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO);
+	vport->cfg_nodev_tmo = LPFC_DEF_DEVLOSS_TMO;
 	return -EINVAL;
 }
 
 static void
-lpfc_update_rport_devloss_tmo(struct lpfc_hba *phba)
+lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport)
 {
-	struct lpfc_vport *vport;
 	struct Scsi_Host  *shost;
 	struct lpfc_nodelist  *ndlp;
 
-	list_for_each_entry(vport, &phba->port_list, listentry) {
-		shost = lpfc_shost_from_vport(vport);
-		spin_lock_irq(shost->host_lock);
-		list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp)
-			if (ndlp->rport)
-				ndlp->rport->dev_loss_tmo =
-					phba->cfg_devloss_tmo;
-		spin_unlock_irq(shost->host_lock);
-	}
+	shost = lpfc_shost_from_vport(vport);
+	spin_lock_irq(shost->host_lock);
+	list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp)
+		if (ndlp->rport)
+			ndlp->rport->dev_loss_tmo = vport->cfg_devloss_tmo;
+	spin_unlock_irq(shost->host_lock);
 }
 
 static int
-lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
+lpfc_nodev_tmo_set(struct lpfc_vport *vport, int val)
 {
-	if (phba->dev_loss_tmo_changed ||
-		(lpfc_devloss_tmo != LPFC_DEF_DEVLOSS_TMO)) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"%d:0401 Ignoring change to nodev_tmo "
-				"because devloss_tmo is set.\n",
-				phba->brd_no);
+	if (vport->dev_loss_tmo_changed ||
+	    (lpfc_devloss_tmo != LPFC_DEF_DEVLOSS_TMO)) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+				 "0401 Ignoring change to nodev_tmo "
+				 "because devloss_tmo is set.\n");
 		return 0;
 	}
-
 	if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
-		phba->cfg_nodev_tmo = val;
-		phba->cfg_devloss_tmo = val;
-		lpfc_update_rport_devloss_tmo(phba);
+		vport->cfg_nodev_tmo = val;
+		vport->cfg_devloss_tmo = val;
+		lpfc_update_rport_devloss_tmo(vport);
 		return 0;
 	}
-
-	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-			"%d:0403 lpfc_nodev_tmo attribute cannot be set to %d, "
-			"allowed range is [%d, %d]\n",
-			phba->brd_no, val, LPFC_MIN_DEVLOSS_TMO,
-			LPFC_MAX_DEVLOSS_TMO);
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+			 "0403 lpfc_nodev_tmo attribute cannot be set to"
+			 "%d, allowed range is [%d, %d]\n",
+			 val, LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO);
 	return -EINVAL;
 }
 
-lpfc_param_store(nodev_tmo)
+lpfc_vport_param_store(nodev_tmo)
 
 static CLASS_DEVICE_ATTR(lpfc_nodev_tmo, S_IRUGO | S_IWUSR,
 			 lpfc_nodev_tmo_show, lpfc_nodev_tmo_store);
@@ -1116,29 +1201,28 @@
 MODULE_PARM_DESC(lpfc_devloss_tmo,
 		 "Seconds driver will hold I/O waiting "
 		 "for a device to come back");
-lpfc_param_init(devloss_tmo, LPFC_DEF_DEVLOSS_TMO,
-		LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO)
-lpfc_param_show(devloss_tmo)
+lpfc_vport_param_init(devloss_tmo, LPFC_DEF_DEVLOSS_TMO,
+		      LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO)
+lpfc_vport_param_show(devloss_tmo)
 static int
-lpfc_devloss_tmo_set(struct lpfc_hba *phba, int val)
+lpfc_devloss_tmo_set(struct lpfc_vport *vport, int val)
 {
 	if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
-		phba->cfg_nodev_tmo = val;
-		phba->cfg_devloss_tmo = val;
-		phba->dev_loss_tmo_changed = 1;
-		lpfc_update_rport_devloss_tmo(phba);
+		vport->cfg_nodev_tmo = val;
+		vport->cfg_devloss_tmo = val;
+		vport->dev_loss_tmo_changed = 1;
+		lpfc_update_rport_devloss_tmo(vport);
 		return 0;
 	}
 
-	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-			"%d:0404 lpfc_devloss_tmo attribute cannot be set to"
-			" %d, allowed range is [%d, %d]\n",
-			phba->brd_no, val, LPFC_MIN_DEVLOSS_TMO,
-			LPFC_MAX_DEVLOSS_TMO);
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+			 "0404 lpfc_devloss_tmo attribute cannot be set to"
+			 " %d, allowed range is [%d, %d]\n",
+			 val, LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO);
 	return -EINVAL;
 }
 
-lpfc_param_store(devloss_tmo)
+lpfc_vport_param_store(devloss_tmo)
 static CLASS_DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR,
 	lpfc_devloss_tmo_show, lpfc_devloss_tmo_store);
 
@@ -1160,14 +1244,15 @@
 # LOG_LIBDFC                    0x2000     LIBDFC events
 # LOG_ALL_MSG                   0xffff     LOG all messages
 */
-LPFC_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffff, "Verbose logging bit-mask");
+LPFC_VPORT_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffff,
+		       "Verbose logging bit-mask");
 
 /*
 # lun_queue_depth:  This parameter is used to limit the number of outstanding
 # commands per FCP LUN. Value range is [1,128]. Default value is 30.
 */
-LPFC_ATTR_R(lun_queue_depth, 30, 1, 128,
-	    "Max number of FCP commands we can queue to a specific LUN");
+LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 128,
+		  "Max number of FCP commands we can queue to a specific LUN");
 
 /*
 # hba_queue_depth:  This parameter is used to limit the number of outstanding
@@ -1188,12 +1273,12 @@
 # are allowed to login to each other.
 # Default value of this parameter is 0.
 */
-LPFC_ATTR_R(peer_port_login, 0, 0, 1,
-	    "Allow peer ports on the same physical port to login to each "
-	    "other.");
+LPFC_VPORT_ATTR_R(peer_port_login, 0, 0, 1,
+		  "Allow peer ports on the same physical port to login to each "
+		  "other.");
 
 /*
-# vport_restrict_login:  This parameter allows/prevents logins
+# restrict_login:  This parameter allows/prevents logins
 # between Virtual Ports and remote initiators.
 # When this parameter is not set (0) Virtual Ports will accept PLOGIs from
 # other initiators and will attempt to PLOGI all remote ports.
@@ -1203,8 +1288,55 @@
 # This parameter does not restrict logins to Fabric resident remote ports.
 # Default value of this parameter is 1.
 */
-LPFC_ATTR_RW(vport_restrict_login, 1, 0, 1,
-	    "Restrict virtual ports login to remote initiators.");
+static int lpfc_restrict_login = 1;
+module_param(lpfc_restrict_login, int, 0);
+MODULE_PARM_DESC(lpfc_restrict_login,
+		 "Restrict virtual ports login to remote initiators.");
+lpfc_vport_param_show(restrict_login);
+
+static int
+lpfc_restrict_login_init(struct lpfc_vport *vport, int val)
+{
+	if (val < 0 || val > 1) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+				 "0449 lpfc_restrict_login attribute cannot "
+				 "be set to %d, allowed range is [0, 1]\n",
+				 val);
+		vport->cfg_restrict_login = 1;
+		return -EINVAL;
+	}
+	if (vport->port_type == LPFC_PHYSICAL_PORT) {
+		vport->cfg_restrict_login = 0;
+		return 0;
+	}
+	vport->cfg_restrict_login = val;
+	return 0;
+}
+
+static int
+lpfc_restrict_login_set(struct lpfc_vport *vport, int val)
+{
+	if (val < 0 || val > 1) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+				 "0450 lpfc_restrict_login attribute cannot "
+				 "be set to %d, allowed range is [0, 1]\n",
+				 val);
+		vport->cfg_restrict_login = 1;
+		return -EINVAL;
+	}
+	if (vport->port_type == LPFC_PHYSICAL_PORT && val != 0) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+				 "0468 lpfc_restrict_login must be 0 for "
+				 "Physical ports.\n");
+		vport->cfg_restrict_login = 0;
+		return 0;
+	}
+	vport->cfg_restrict_login = val;
+	return 0;
+}
+lpfc_vport_param_store(restrict_login);
+static CLASS_DEVICE_ATTR(lpfc_restrict_login, S_IRUGO | S_IWUSR,
+			 lpfc_restrict_login_show, lpfc_restrict_login_store);
 
 /*
 # Some disk devices have a "select ID" or "select Target" capability.
@@ -1223,8 +1355,8 @@
 # and will not work across a fabric. Also this parameter will take
 # effect only in the case when ALPA map is not available.)
 */
-LPFC_ATTR_R(scan_down, 1, 0, 1,
-	     "Start scanning for devices from highest ALPA to lowest");
+LPFC_VPORT_ATTR_R(scan_down, 1, 0, 1,
+		  "Start scanning for devices from highest ALPA to lowest");
 
 /*
 # lpfc_topology:  link topology for init link
@@ -1255,15 +1387,15 @@
 # lpfc_fcp_class:  Determines FC class to use for the FCP protocol.
 # Value range is [2,3]. Default value is 3.
 */
-LPFC_ATTR_R(fcp_class, 3, 2, 3,
-	     "Select Fibre Channel class of service for FCP sequences");
+LPFC_VPORT_ATTR_R(fcp_class, 3, 2, 3,
+		  "Select Fibre Channel class of service for FCP sequences");
 
 /*
 # lpfc_use_adisc: Use ADISC for FCP rediscovery instead of PLOGI. Value range
 # is [0,1]. Default value is 0.
 */
-LPFC_ATTR_RW(use_adisc, 0, 0, 1,
-	     "Use ADISC on rediscovery to authenticate FCP devices");
+LPFC_VPORT_ATTR_RW(use_adisc, 0, 0, 1,
+		   "Use ADISC on rediscovery to authenticate FCP devices");
 
 /*
 # lpfc_ack0: Use ACK0, instead of ACK1 for class 2 acknowledgement. Value
@@ -1315,13 +1447,13 @@
 #       2 = support FDMI with attribute of hostname
 # Value range [0,2]. Default value is 0.
 */
-LPFC_ATTR_RW(fdmi_on, 0, 0, 2, "Enable FDMI support");
+LPFC_VPORT_ATTR_RW(fdmi_on, 0, 0, 2, "Enable FDMI support");
 
 /*
 # Specifies the maximum number of ELS cmds we can have outstanding (for
 # discovery). Value range is [1,64]. Default value = 32.
 */
-LPFC_ATTR(discovery_threads, 32, 1, 64, "Maximum number of ELS commands "
+LPFC_VPORT_ATTR(discovery_threads, 32, 1, 64, "Maximum number of ELS commands "
 		 "during discovery");
 
 /*
@@ -1329,8 +1461,7 @@
 # Value range is [0,65535]. Default value is 255.
 # NOTE: The SCSI layer might probe all allowed LUN on some old targets.
 */
-LPFC_ATTR_R(max_luns, 255, 0, 65535,
-	     "Maximum allowed LUN");
+LPFC_VPORT_ATTR_R(max_luns, 255, 0, 65535, "Maximum allowed LUN");
 
 /*
 # lpfc_poll_tmo: .Milliseconds driver will wait between polling FCP ring.
@@ -1367,7 +1498,6 @@
 	&class_device_attr_lpfc_lun_queue_depth,
 	&class_device_attr_lpfc_hba_queue_depth,
 	&class_device_attr_lpfc_peer_port_login,
-	&class_device_attr_lpfc_vport_restrict_login,
 	&class_device_attr_lpfc_nodev_tmo,
 	&class_device_attr_lpfc_devloss_tmo,
 	&class_device_attr_lpfc_fcp_class,
@@ -1383,9 +1513,8 @@
 	&class_device_attr_lpfc_multi_ring_type,
 	&class_device_attr_lpfc_fdmi_on,
 	&class_device_attr_lpfc_max_luns,
-	&class_device_attr_lpfc_npiv_enable,
+	&class_device_attr_lpfc_enable_npiv,
 	&class_device_attr_nport_evt_cnt,
-	&class_device_attr_management_version,
 	&class_device_attr_board_mode,
 	&class_device_attr_max_vpi,
 	&class_device_attr_used_vpi,
@@ -1404,6 +1533,28 @@
 	NULL,
 };
 
+struct class_device_attribute *lpfc_vport_attrs[] = {
+	&class_device_attr_info,
+	&class_device_attr_state,
+	&class_device_attr_num_discovered_ports,
+	&class_device_attr_lpfc_drvr_version,
+
+	&class_device_attr_lpfc_log_verbose,
+	&class_device_attr_lpfc_lun_queue_depth,
+	&class_device_attr_lpfc_nodev_tmo,
+	&class_device_attr_lpfc_devloss_tmo,
+	&class_device_attr_lpfc_hba_queue_depth,
+	&class_device_attr_lpfc_peer_port_login,
+	&class_device_attr_lpfc_restrict_login,
+	&class_device_attr_lpfc_fcp_class,
+	&class_device_attr_lpfc_use_adisc,
+	&class_device_attr_lpfc_fdmi_on,
+	&class_device_attr_lpfc_max_luns,
+	&class_device_attr_nport_evt_cnt,
+	&class_device_attr_npiv_info,
+	NULL,
+};
+
 static ssize_t
 sysfs_ctlreg_write(struct kobject *kobj, struct bin_attribute *bin_attr,
 		   char *buf, loff_t off, size_t count)
@@ -2243,7 +2394,6 @@
 	.get_starget_port_name = lpfc_get_starget_port_name,
 	.show_starget_port_name = 1,
 
-	.issue_fc_host_lip = lpfc_issue_lip,
 	.dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
 	.terminate_rport_io = lpfc_terminate_rport_io,
 
@@ -2253,39 +2403,25 @@
 void
 lpfc_get_cfgparam(struct lpfc_hba *phba)
 {
-	lpfc_log_verbose_init(phba, lpfc_log_verbose);
 	lpfc_cr_delay_init(phba, lpfc_cr_delay);
 	lpfc_cr_count_init(phba, lpfc_cr_count);
 	lpfc_multi_ring_support_init(phba, lpfc_multi_ring_support);
 	lpfc_multi_ring_rctl_init(phba, lpfc_multi_ring_rctl);
 	lpfc_multi_ring_type_init(phba, lpfc_multi_ring_type);
-	lpfc_lun_queue_depth_init(phba, lpfc_lun_queue_depth);
-	lpfc_fcp_class_init(phba, lpfc_fcp_class);
-	lpfc_use_adisc_init(phba, lpfc_use_adisc);
 	lpfc_ack0_init(phba, lpfc_ack0);
 	lpfc_topology_init(phba, lpfc_topology);
-	lpfc_scan_down_init(phba, lpfc_scan_down);
 	lpfc_link_speed_init(phba, lpfc_link_speed);
-	lpfc_fdmi_on_init(phba, lpfc_fdmi_on);
-	lpfc_discovery_threads_init(phba, lpfc_discovery_threads);
-	lpfc_max_luns_init(phba, lpfc_max_luns);
 	lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
-	lpfc_peer_port_login_init(phba, lpfc_peer_port_login);
-	lpfc_npiv_enable_init(phba, lpfc_npiv_enable);
-	lpfc_vport_restrict_login_init(phba, lpfc_vport_restrict_login);
+	lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
 	lpfc_use_msi_init(phba, lpfc_use_msi);
-	lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo);
-	lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo);
 	phba->cfg_poll = lpfc_poll;
 	phba->cfg_soft_wwnn = 0L;
 	phba->cfg_soft_wwpn = 0L;
-
 	/*
 	 * The total number of segments is the configuration value plus 2
 	 * since the IOCB need a command and response bde.
 	 */
 	phba->cfg_sg_seg_cnt = LPFC_SG_SEG_CNT + 2;
-
 	/*
 	 * Since the sg_tablesize is module parameter, the sg_dma_buf_size
 	 * used to create the sg_dma_buf_pool must be dynamically calculated
@@ -2293,9 +2429,24 @@
 	phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) +
 			sizeof(struct fcp_rsp) +
 			(phba->cfg_sg_seg_cnt * sizeof(struct ulp_bde64));
-
-
 	lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
+	return;
+}
 
+void
+lpfc_get_vport_cfgparam(struct lpfc_vport *vport)
+{
+	lpfc_log_verbose_init(vport, lpfc_log_verbose);
+	lpfc_lun_queue_depth_init(vport, lpfc_lun_queue_depth);
+	lpfc_devloss_tmo_init(vport, lpfc_devloss_tmo);
+	lpfc_nodev_tmo_init(vport, lpfc_nodev_tmo);
+	lpfc_peer_port_login_init(vport, lpfc_peer_port_login);
+	lpfc_restrict_login_init(vport, lpfc_restrict_login);
+	lpfc_fcp_class_init(vport, lpfc_fcp_class);
+	lpfc_use_adisc_init(vport, lpfc_use_adisc);
+	lpfc_fdmi_on_init(vport, lpfc_fdmi_on);
+	lpfc_discovery_threads_init(vport, lpfc_discovery_threads);
+	lpfc_max_luns_init(vport, lpfc_max_luns);
+	lpfc_scan_down_init(vport, lpfc_scan_down);
 	return;
 }
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index e19d1a7..a599e15 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -40,6 +40,7 @@
 void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *);
 void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
 
+struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t);
 void lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove);
 int lpfc_linkdown(struct lpfc_hba *);
 void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -101,7 +102,7 @@
 int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
 int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
 int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *,
-		     struct lpfc_nodelist *, LPFC_MBOXQ_t *, uint8_t);
+		     struct lpfc_nodelist *, LPFC_MBOXQ_t *);
 int lpfc_els_rsp_reject(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *,
 			struct lpfc_nodelist *, LPFC_MBOXQ_t *);
 int lpfc_els_rsp_adisc_acc(struct lpfc_vport *, struct lpfc_iocbq *,
@@ -117,6 +118,7 @@
 int lpfc_els_handle_rscn(struct lpfc_vport *);
 void lpfc_els_flush_rscn(struct lpfc_vport *);
 int lpfc_rscn_payload_check(struct lpfc_vport *, uint32_t);
+void lpfc_els_flush_all_cmd(struct lpfc_hba *);
 void lpfc_els_flush_cmd(struct lpfc_vport *);
 int lpfc_els_disc_adisc(struct lpfc_vport *);
 int lpfc_els_disc_plogi(struct lpfc_vport *);
@@ -161,9 +163,11 @@
 void lpfc_mbox_cmpl_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
 int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
 
-void lpfc_config_hbq(struct lpfc_hba *, struct lpfc_hbq_init *, uint32_t ,
-		     LPFC_MBOXQ_t *);
+void lpfc_config_hbq(struct lpfc_hba *, uint32_t, struct lpfc_hbq_init *,
+	uint32_t , LPFC_MBOXQ_t *);
 struct lpfc_hbq_entry * lpfc_sli_next_hbq_slot(struct lpfc_hba *, uint32_t);
+struct hbq_dmabuf *lpfc_els_hbq_alloc(struct lpfc_hba *);
+void lpfc_els_hbq_free(struct lpfc_hba *, struct hbq_dmabuf *);
 
 int lpfc_mem_alloc(struct lpfc_hba *);
 void lpfc_mem_free(struct lpfc_hba *);
@@ -200,6 +204,7 @@
 struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
 					     struct lpfc_sli_ring *,
 					     dma_addr_t);
+int lpfc_sli_hbq_count(void);
 int lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *, uint32_t);
 int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t);
 void lpfc_sli_hbqbuf_free_all(struct lpfc_hba *);
@@ -207,10 +212,9 @@
 int lpfc_sli_hbq_size(void);
 int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *,
 			       struct lpfc_iocbq *);
-int lpfc_sli_sum_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
-		      uint64_t, lpfc_ctx_cmd);
-int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
-			uint64_t, uint32_t, lpfc_ctx_cmd);
+int lpfc_sli_sum_iocb(struct lpfc_vport *, uint16_t, uint64_t, lpfc_ctx_cmd);
+int lpfc_sli_abort_iocb(struct lpfc_vport *, struct lpfc_sli_ring *, uint16_t,
+			uint64_t, lpfc_ctx_cmd);
 
 void lpfc_mbox_timeout(unsigned long);
 void lpfc_mbox_timeout_handler(struct lpfc_hba *);
@@ -234,8 +238,6 @@
 			     struct lpfc_iocbq * cmdiocb,
 			     struct lpfc_iocbq * rspiocb);
 
-void *lpfc_hbq_alloc(struct lpfc_hba *, int, dma_addr_t *);
-void lpfc_hbq_free(struct lpfc_hba *, void *, dma_addr_t);
 void lpfc_sli_free_hbq(struct lpfc_hba *, struct hbq_dmabuf *);
 
 void *lpfc_mbuf_alloc(struct lpfc_hba *, int, dma_addr_t *);
@@ -248,10 +250,13 @@
 int lpfc_scan_finished(struct Scsi_Host *, unsigned long);
 
 void lpfc_get_cfgparam(struct lpfc_hba *);
+void lpfc_get_vport_cfgparam(struct lpfc_vport *);
 int lpfc_alloc_sysfs_attr(struct lpfc_vport *);
 void lpfc_free_sysfs_attr(struct lpfc_vport *);
 extern struct class_device_attribute *lpfc_hba_attrs[];
+extern struct class_device_attribute *lpfc_vport_attrs[];
 extern struct scsi_host_template lpfc_template;
+extern struct scsi_host_template lpfc_vport_template;
 extern struct fc_function_template lpfc_transport_functions;
 extern struct fc_function_template lpfc_vport_transport_functions;
 extern int lpfc_sli_mode;
@@ -260,7 +265,7 @@
 void lpfc_terminate_rport_io(struct fc_rport *);
 void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport);
 
-struct lpfc_vport *lpfc_create_port(struct lpfc_hba *, int, struct fc_vport *);
+struct lpfc_vport *lpfc_create_port(struct lpfc_hba *, int, struct device *);
 int  lpfc_vport_disable(struct fc_vport *fc_vport, bool disable);
 void lpfc_mbx_unreg_vpi(struct lpfc_vport *);
 void destroy_port(struct lpfc_vport *);
@@ -271,6 +276,9 @@
 extern void lpfc_debugfs_terminate(struct lpfc_vport *);
 extern void lpfc_debugfs_disc_trc(struct lpfc_vport *, int, char *, uint32_t,
 	uint32_t, uint32_t);
+extern void lpfc_debugfs_slow_ring_trc(struct lpfc_hba *, char *, uint32_t,
+	uint32_t, uint32_t);
+extern struct lpfc_hbq_init *lpfc_hbq_defs[];
 
 /* Interface exported by fabric iocb scheduler */
 int lpfc_issue_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index ae9d6f38..c701e4d 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -257,6 +257,10 @@
 {
 	struct lpfc_dmabuf *buf_ptr;
 
+	if (ctiocb->context_un.ndlp) {
+		lpfc_nlp_put(ctiocb->context_un.ndlp);
+		ctiocb->context_un.ndlp = NULL;
+	}
 	if (ctiocb->context1) {
 		buf_ptr = (struct lpfc_dmabuf *) ctiocb->context1;
 		lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
@@ -314,6 +318,7 @@
 	/* Save for completion so we can release these resources */
 	geniocb->context1 = (uint8_t *) inp;
 	geniocb->context2 = (uint8_t *) outp;
+	geniocb->context_un.ndlp = ndlp;
 
 	/* Fill in payload, bp points to frame payload */
 	icmd->ulpCommand = CMD_GEN_REQUEST64_CR;
@@ -341,11 +346,11 @@
 	}
 
 	/* Issue GEN REQ IOCB for NPORT <did> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0119 Issue GEN REQ IOCB to NPORT x%x "
-			"Data: x%x x%x\n", phba->brd_no, vport->vpi,
-			ndlp->nlp_DID, icmd->ulpIoTag,
-			vport->port_state);
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0119 Issue GEN REQ IOCB to NPORT x%x "
+			 "Data: x%x x%x\n",
+			 ndlp->nlp_DID, icmd->ulpIoTag,
+			 vport->port_state);
 	geniocb->iocb_cmpl = cmpl;
 	geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT;
 	geniocb->vport = vport;
@@ -390,17 +395,19 @@
 	return 0;
 }
 
-static struct lpfc_vport *
+struct lpfc_vport *
 lpfc_find_vport_by_did(struct lpfc_hba *phba, uint32_t did) {
-
 	struct lpfc_vport *vport_curr;
+	unsigned long flags;
 
+	spin_lock_irqsave(&phba->hbalock, flags);
 	list_for_each_entry(vport_curr, &phba->port_list, listentry) {
-		if ((vport_curr->fc_myDID) &&
-			(vport_curr->fc_myDID == did))
+		if ((vport_curr->fc_myDID) && (vport_curr->fc_myDID == did)) {
+			spin_unlock_irqrestore(&phba->hbalock, flags);
 			return vport_curr;
+		}
 	}
-
+	spin_unlock_irqrestore(&phba->hbalock, flags);
 	return NULL;
 }
 
@@ -449,10 +456,10 @@
 			 */
 			if ((Did != vport->fc_myDID) &&
 			    ((lpfc_find_vport_by_did(phba, Did) == NULL) ||
-			     phba->cfg_peer_port_login)) {
+			     vport->cfg_peer_port_login)) {
 				if ((vport->port_type != LPFC_NPIV_PORT) ||
 				    (vport->fc_flag & FC_RFF_NOT_SUPPORTED) ||
-				    (!phba->cfg_vport_restrict_login)) {
+				    (!vport->cfg_restrict_login)) {
 					ndlp = lpfc_setup_disc_node(vport, Did);
 					if (ndlp) {
 						lpfc_debugfs_disc_trc(vport,
@@ -462,14 +469,13 @@
 						Did, ndlp->nlp_flag,
 						vport->fc_flag);
 
-						lpfc_printf_log(phba, KERN_INFO,
+						lpfc_printf_vlog(vport,
+							KERN_INFO,
 							LOG_DISCOVERY,
-							"%d (%d):0238 Process "
+							"0238 Process "
 							"x%x NameServer Rsp"
 							"Data: x%x x%x x%x\n",
-							phba->brd_no,
-							vport->vpi, Did,
-							ndlp->nlp_flag,
+							Did, ndlp->nlp_flag,
 							vport->fc_flag,
 							vport->fc_rscn_id_cnt);
 					} else {
@@ -480,14 +486,13 @@
 						Did, vport->fc_flag,
 						vport->fc_rscn_id_cnt);
 
-						lpfc_printf_log(phba, KERN_INFO,
+						lpfc_printf_vlog(vport,
+							KERN_INFO,
 							LOG_DISCOVERY,
-							"%d (%d):0239 Skip x%x "
+							"0239 Skip x%x "
 							"NameServer Rsp Data: "
 							"x%x x%x\n",
-							phba->brd_no,
-							vport->vpi, Did,
-							vport->fc_flag,
+							Did, vport->fc_flag,
 							vport->fc_rscn_id_cnt);
 					}
 
@@ -514,14 +519,13 @@
 						Did, vport->fc_flag,
 						vport->fc_rscn_id_cnt);
 
-						lpfc_printf_log(phba, KERN_INFO,
+						lpfc_printf_vlog(vport,
+							KERN_INFO,
 							LOG_DISCOVERY,
-							"%d (%d):0245 Skip x%x "
+							"0245 Skip x%x "
 							"NameServer Rsp Data: "
 							"x%x x%x\n",
-							phba->brd_no,
-							vport->vpi, Did,
-							vport->fc_flag,
+							Did, vport->fc_flag,
 							vport->fc_rscn_id_cnt);
 					}
 				}
@@ -549,8 +553,12 @@
 	struct lpfc_dmabuf *bmp;
 	struct lpfc_dmabuf *outp;
 	struct lpfc_sli_ct_request *CTrsp;
+	struct lpfc_nodelist *ndlp;
 	int rc;
 
+	/* First save ndlp, before we overwrite it */
+	ndlp = cmdiocb->context_un.ndlp;
+
 	/* we pass cmdiocb to state machine which needs rspiocb as well */
 	cmdiocb->context_un.rsp_iocb = rspiocb;
 
@@ -568,9 +576,8 @@
 
 
 	if (lpfc_els_chk_latt(vport) || lpfc_error_lost_link(irsp)) {
-		lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-				"%d (%d):0216 Link event during NS query\n",
-				phba->brd_no, vport->vpi);
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+				 "0216 Link event during NS query\n");
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 		goto out;
 	}
@@ -588,46 +595,61 @@
 				goto out;
 		}
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-			"%d (%d):0257 GID_FT Query error: 0x%x 0x%x\n",
-			phba->brd_no, vport->vpi, irsp->ulpStatus,
-			vport->fc_ns_retry);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				 "0257 GID_FT Query error: 0x%x 0x%x\n",
+				 irsp->ulpStatus, vport->fc_ns_retry);
 	} else {
 		/* Good status, continue checking */
 		CTrsp = (struct lpfc_sli_ct_request *) outp->virt;
 		if (CTrsp->CommandResponse.bits.CmdRsp ==
 		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
-			lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-					"%d (%d):0208 NameServer Rsp "
-					"Data: x%x\n",
-					phba->brd_no, vport->vpi,
-					vport->fc_flag);
+			lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+					 "0208 NameServer Rsp Data: x%x\n",
+					 vport->fc_flag);
 			lpfc_ns_rsp(vport, outp,
 				    (uint32_t) (irsp->un.genreq64.bdl.bdeSize));
 		} else if (CTrsp->CommandResponse.bits.CmdRsp ==
 			   be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
 			/* NameServer Rsp Error */
-			lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-					"%d (%d):0240 NameServer Rsp Error "
+			if ((CTrsp->ReasonCode == SLI_CT_UNABLE_TO_PERFORM_REQ)
+			    && (CTrsp->Explanation == SLI_CT_NO_FC4_TYPES)) {
+				lpfc_printf_vlog(vport, KERN_INFO,
+					LOG_DISCOVERY,
+					"0269 No NameServer Entries "
 					"Data: x%x x%x x%x x%x\n",
-					phba->brd_no, vport->vpi,
 					CTrsp->CommandResponse.bits.CmdRsp,
 					(uint32_t) CTrsp->ReasonCode,
 					(uint32_t) CTrsp->Explanation,
 					vport->fc_flag);
 
-			lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+				lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
+				"GID_FT no entry  cmd:x%x rsn:x%x exp:x%x",
+				(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
+				(uint32_t) CTrsp->ReasonCode,
+				(uint32_t) CTrsp->Explanation);
+			} else {
+				lpfc_printf_vlog(vport, KERN_INFO,
+					LOG_DISCOVERY,
+					"0240 NameServer Rsp Error "
+					"Data: x%x x%x x%x x%x\n",
+					CTrsp->CommandResponse.bits.CmdRsp,
+					(uint32_t) CTrsp->ReasonCode,
+					(uint32_t) CTrsp->Explanation,
+					vport->fc_flag);
+
+				lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
 				"GID_FT rsp err1  cmd:x%x rsn:x%x exp:x%x",
 				(uint32_t)CTrsp->CommandResponse.bits.CmdRsp,
 				(uint32_t) CTrsp->ReasonCode,
 				(uint32_t) CTrsp->Explanation);
+			}
+
 
 		} else {
 			/* NameServer Rsp Error */
-			lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-					"%d (%d):0241 NameServer Rsp Error "
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+					"0241 NameServer Rsp Error "
 					"Data: x%x x%x x%x x%x\n",
-					phba->brd_no, vport->vpi,
 					CTrsp->CommandResponse.bits.CmdRsp,
 					(uint32_t) CTrsp->ReasonCode,
 					(uint32_t) CTrsp->Explanation,
@@ -661,11 +683,12 @@
 		lpfc_disc_start(vport);
 	}
 out:
+	cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */
 	lpfc_ct_free_iocb(phba, cmdiocb);
 	return;
 }
 
-void
+static void
 lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
 			struct lpfc_iocbq *rspiocb)
 {
@@ -695,40 +718,37 @@
 		    be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
 			if ((fbits & FC4_FEATURE_INIT) &&
 			    !(fbits & FC4_FEATURE_TARGET)) {
-				lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-						"%d (%d):0245 Skip x%x GFF "
-						"NameServer Rsp Data: (init) "
-						"x%x x%x\n", phba->brd_no,
-						vport->vpi, did, fbits,
-						vport->fc_rscn_id_cnt);
+				lpfc_printf_vlog(vport, KERN_INFO,
+						 LOG_DISCOVERY,
+						 "0270 Skip x%x GFF "
+						 "NameServer Rsp Data: (init) "
+						 "x%x x%x\n", did, fbits,
+						 vport->fc_rscn_id_cnt);
 				goto out;
 			}
 		}
 	}
 	else {
-		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-				"%d (%d):0267 NameServer GFF Rsp"
-				" x%x Error (%d %d) Data: x%x x%x\n",
-				phba->brd_no, vport->vpi, did,
-				irsp->ulpStatus, irsp->un.ulpWord[4],
-				vport->fc_flag, vport->fc_rscn_id_cnt)
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+				 "0267 NameServer GFF Rsp "
+				 "x%x Error (%d %d) Data: x%x x%x\n",
+				 did, irsp->ulpStatus, irsp->un.ulpWord[4],
+				 vport->fc_flag, vport->fc_rscn_id_cnt)
 	}
 
 	/* This is a target port, unregistered port, or the GFF_ID failed */
 	ndlp = lpfc_setup_disc_node(vport, did);
 	if (ndlp) {
-		lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-				"%d (%d):0242 Process x%x GFF "
-				"NameServer Rsp Data: x%x x%x x%x\n",
-				phba->brd_no, vport->vpi,
-				did, ndlp->nlp_flag, vport->fc_flag,
-				vport->fc_rscn_id_cnt);
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+				 "0242 Process x%x GFF "
+				 "NameServer Rsp Data: x%x x%x x%x\n",
+				 did, ndlp->nlp_flag, vport->fc_flag,
+				 vport->fc_rscn_id_cnt);
 	} else {
-		lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-				"%d (%d):0243 Skip x%x GFF "
-				"NameServer Rsp Data: x%x x%x\n",
-				phba->brd_no, vport->vpi, did,
-				vport->fc_flag,	vport->fc_rscn_id_cnt);
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+				 "0243 Skip x%x GFF "
+				 "NameServer Rsp Data: x%x x%x\n", did,
+				 vport->fc_flag, vport->fc_rscn_id_cnt);
 	}
 out:
 	/* Link up / RSCN discovery */
@@ -766,10 +786,14 @@
 	struct lpfc_dmabuf *outp;
 	IOCB_t *irsp;
 	struct lpfc_sli_ct_request *CTrsp;
+	struct lpfc_nodelist *ndlp;
 	int cmdcode, rc;
 	uint8_t retry;
 	uint32_t latt;
 
+	/* First save ndlp, before we overwrite it */
+	ndlp = cmdiocb->context_un.ndlp;
+
 	/* we pass cmdiocb to state machine which needs rspiocb as well */
 	cmdiocb->context_un.rsp_iocb = rspiocb;
 
@@ -784,22 +808,21 @@
 	latt = lpfc_els_chk_latt(vport);
 
 	/* RFT request completes status <ulpStatus> CmdRsp <CmdRsp> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			"%d (%d):0209 RFT request completes, latt %d, "
-			"ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n",
-			phba->brd_no, vport->vpi, latt, irsp->ulpStatus,
-			CTrsp->CommandResponse.bits.CmdRsp,
-			cmdiocb->iocb.ulpContext, cmdiocb->iocb.ulpIoTag);
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+			 "0209 RFT request completes, latt %d, "
+			 "ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n",
+			 latt, irsp->ulpStatus,
+			 CTrsp->CommandResponse.bits.CmdRsp,
+			 cmdiocb->iocb.ulpContext, cmdiocb->iocb.ulpIoTag);
 
 	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT,
 		"CT cmd cmpl:     status:x%x/x%x cmd:x%x",
 		irsp->ulpStatus, irsp->un.ulpWord[4], cmdcode);
 
 	if (irsp->ulpStatus) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-			"%d (%d):0268 NS cmd %x Error (%d %d)\n",
-			phba->brd_no, vport->vpi, cmdcode,
-			irsp->ulpStatus, irsp->un.ulpWord[4]);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+				 "0268 NS cmd %x Error (%d %d)\n",
+				 cmdcode, irsp->ulpStatus, irsp->un.ulpWord[4]);
 
 		if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
 			((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) ||
@@ -811,15 +834,15 @@
 			goto out;
 
 		retry++;
-		lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-				"%d (%d):0216 Retrying NS cmd %x\n",
-				phba->brd_no, vport->vpi, cmdcode);
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+				 "0216 Retrying NS cmd %x\n", cmdcode);
 		rc = lpfc_ns_cmd(vport, cmdcode, retry, 0);
 		if (rc == 0)
 			goto out;
 	}
 
 out:
+	cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */
 	lpfc_ct_free_iocb(phba, cmdiocb);
 	return;
 }
@@ -862,7 +885,7 @@
 	return;
 }
 
-int
+static int
 lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol,
 	size_t size)
 {
@@ -957,10 +980,9 @@
 	}
 
 	/* NameServer Req */
-	lpfc_printf_log(phba, KERN_INFO ,LOG_DISCOVERY,
-			"%d (%d):0236 NameServer Req Data: x%x x%x x%x\n",
-			phba->brd_no, vport->vpi, cmdcode, vport->fc_flag,
-			vport->fc_rscn_id_cnt);
+	lpfc_printf_vlog(vport, KERN_INFO ,LOG_DISCOVERY,
+			 "0236 NameServer Req Data: x%x x%x x%x\n",
+			 cmdcode, vport->fc_flag, vport->fc_rscn_id_cnt);
 
 	bpl = (struct ulp_bde64 *) bmp->virt;
 	memset(bpl, 0, sizeof(struct ulp_bde64));
@@ -1059,6 +1081,7 @@
 		cmpl = lpfc_cmpl_ct_cmd_rff_id;
 		break;
 	}
+	lpfc_nlp_get(ndlp);
 
 	if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) {
 		/* On success, The cmpl function will free the buffers */
@@ -1069,6 +1092,7 @@
 	}
 
 	rc=6;
+	lpfc_nlp_put(ndlp);
 	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
 ns_cmd_free_bmp:
 	kfree(bmp);
@@ -1077,10 +1101,9 @@
 ns_cmd_free_mp:
 	kfree(mp);
 ns_cmd_exit:
-	lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-		"%d (%d):0266 Issue NameServer Req x%x err %d Data: x%x x%x\n",
-			phba->brd_no, vport->vpi, cmdcode, rc, vport->fc_flag,
-			vport->fc_rscn_id_cnt);
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+			 "0266 Issue NameServer Req x%x err %d Data: x%x x%x\n",
+			 cmdcode, rc, vport->fc_flag, vport->fc_rscn_id_cnt);
 	return 1;
 }
 
@@ -1106,12 +1129,11 @@
 		irsp->ulpStatus, irsp->un.ulpWord[4], latt);
 
 	if (latt || irsp->ulpStatus) {
-		lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			        "%d (%d):0229 FDMI cmd %04x failed, latt = %d "
-				"ulpStatus: x%x, rid x%x\n",
-			        phba->brd_no, vport->vpi,
-				be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus,
-				irsp->un.ulpWord[4]);
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+				 "0229 FDMI cmd %04x failed, latt = %d "
+				 "ulpStatus: x%x, rid x%x\n",
+				 be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus,
+				 irsp->un.ulpWord[4]);
 		lpfc_ct_free_iocb(phba, cmdiocb);
 		return;
 	}
@@ -1119,10 +1141,9 @@
 	ndlp = lpfc_findnode_did(vport, FDMI_DID);
 	if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) {
 		/* FDMI rsp failed */
-		lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			        "%d (%d):0220 FDMI rsp failed Data: x%x\n",
-			        phba->brd_no, vport->vpi,
-				be16_to_cpu(fdmi_cmd));
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+				 "0220 FDMI rsp failed Data: x%x\n",
+				 be16_to_cpu(fdmi_cmd));
 	}
 
 	switch (be16_to_cpu(fdmi_cmd)) {
@@ -1185,11 +1206,9 @@
 	INIT_LIST_HEAD(&bmp->list);
 
 	/* FDMI request */
-	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			"%d (%d):0218 FDMI Request Data: x%x x%x x%x\n",
-			phba->brd_no, vport->vpi, vport->fc_flag,
-			vport->port_state, cmdcode);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+			 "0218 FDMI Request Data: x%x x%x x%x\n",
+			 vport->fc_flag, vport->port_state, cmdcode);
 	CtReq = (struct lpfc_sli_ct_request *) mp->virt;
 
 	memset(CtReq, 0, sizeof(struct lpfc_sli_ct_request));
@@ -1449,7 +1468,7 @@
 			pab->ab.EntryCnt++;
 			size += FOURBYTES + len;
 
-			if (phba->cfg_fdmi_on == 2) {
+			if (vport->cfg_fdmi_on == 2) {
 				/* #6 Port attribute entry */
 				ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab +
 							  size);
@@ -1499,10 +1518,12 @@
 	bpl->tus.w = le32_to_cpu(bpl->tus.w);
 
 	cmpl = lpfc_cmpl_ct_cmd_fdmi;
+	lpfc_nlp_get(ndlp);
 
 	if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP, 0))
 		return 0;
 
+	lpfc_nlp_put(ndlp);
 	lpfc_mbuf_free(phba, bmp->virt, bmp->phys);
 fdmi_cmd_free_bmp:
 	kfree(bmp);
@@ -1512,9 +1533,9 @@
 	kfree(mp);
 fdmi_cmd_exit:
 	/* Issue FDMI request failed */
-	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-		        "%d (%d):0244 Issue FDMI request failed Data: x%x\n",
-		        phba->brd_no, vport->vpi, cmdcode);
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+			 "0244 Issue FDMI request failed Data: x%x\n",
+			 cmdcode);
 	return 1;
 }
 
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 673cfe1..2e3c01b 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -71,15 +71,22 @@
  * lpfc_debugfs_mask_disc_trc=Y  Where Y is an event mask as defined in
  *                               lpfc_debugfs.h .
  */
-static int lpfc_debugfs_enable = 0;
+static int lpfc_debugfs_enable = 1;
 module_param(lpfc_debugfs_enable, int, 0);
 MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services");
 
-static int lpfc_debugfs_max_disc_trc = 0;  /* This MUST be a power of 2 */
+/* This MUST be a power of 2 */
+static int lpfc_debugfs_max_disc_trc = 0;
 module_param(lpfc_debugfs_max_disc_trc, int, 0);
 MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc,
 	"Set debugfs discovery trace depth");
 
+/* This MUST be a power of 2 */
+static int lpfc_debugfs_max_slow_ring_trc = 0;
+module_param(lpfc_debugfs_max_slow_ring_trc, int, 0);
+MODULE_PARM_DESC(lpfc_debugfs_max_slow_ring_trc,
+	"Set debugfs slow ring trace depth");
+
 static int lpfc_debugfs_mask_disc_trc = 0;
 module_param(lpfc_debugfs_mask_disc_trc, int, 0);
 MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
@@ -87,28 +94,34 @@
 
 #include <linux/debugfs.h>
 
-/* size of discovery_trace output line */
-#define LPFC_DISC_TRC_ENTRY_SIZE 80
+/* size of output line, for discovery_trace and slow_ring_trace */
+#define LPFC_DEBUG_TRC_ENTRY_SIZE 100
 
 /* nodelist output buffer size */
 #define LPFC_NODELIST_SIZE 8192
 #define LPFC_NODELIST_ENTRY_SIZE 120
 
+/* dumpslim output buffer size */
+#define LPFC_DUMPSLIM_SIZE 4096
+
+/* hbqinfo output buffer size */
+#define LPFC_HBQINFO_SIZE 8192
+
 struct lpfc_debug {
 	char *buffer;
 	int  len;
 };
 
-atomic_t lpfc_debugfs_disc_trc_cnt = ATOMIC_INIT(0);
-unsigned long lpfc_debugfs_start_time = 0L;
+static atomic_t lpfc_debugfs_seq_trc_cnt = ATOMIC_INIT(0);
+static unsigned long lpfc_debugfs_start_time = 0L;
 
 static int
 lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
 {
 	int i, index, len, enable;
 	uint32_t ms;
-	struct lpfc_disc_trc *dtp;
-	char buffer[80];
+	struct lpfc_debugfs_trc *dtp;
+	char buffer[LPFC_DEBUG_TRC_ENTRY_SIZE];
 
 
 	enable = lpfc_debugfs_enable;
@@ -122,7 +135,8 @@
 		if (!dtp->fmt)
 			continue;
 		ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
-		snprintf(buffer, 80, "%010d:%010d ms:%s\n",
+		snprintf(buffer,
+			LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
 			dtp->seq_cnt, ms, dtp->fmt);
 		len +=  snprintf(buf+len, size-len, buffer,
 			dtp->data1, dtp->data2, dtp->data3);
@@ -132,7 +146,8 @@
 		if (!dtp->fmt)
 			continue;
 		ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
-		snprintf(buffer, 80, "%010d:%010d ms:%s\n",
+		snprintf(buffer,
+			LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
 			dtp->seq_cnt, ms, dtp->fmt);
 		len +=  snprintf(buf+len, size-len, buffer,
 			dtp->data1, dtp->data2, dtp->data3);
@@ -143,6 +158,236 @@
 }
 
 static int
+lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size)
+{
+	int i, index, len, enable;
+	uint32_t ms;
+	struct lpfc_debugfs_trc *dtp;
+	char buffer[LPFC_DEBUG_TRC_ENTRY_SIZE];
+
+
+	enable = lpfc_debugfs_enable;
+	lpfc_debugfs_enable = 0;
+
+	len = 0;
+	index = (atomic_read(&phba->slow_ring_trc_cnt) + 1) &
+		(lpfc_debugfs_max_slow_ring_trc - 1);
+	for (i = index; i < lpfc_debugfs_max_slow_ring_trc; i++) {
+		dtp = phba->slow_ring_trc + i;
+		if (!dtp->fmt)
+			continue;
+		ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
+		snprintf(buffer,
+			LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
+			dtp->seq_cnt, ms, dtp->fmt);
+		len +=  snprintf(buf+len, size-len, buffer,
+			dtp->data1, dtp->data2, dtp->data3);
+	}
+	for (i = 0; i < index; i++) {
+		dtp = phba->slow_ring_trc + i;
+		if (!dtp->fmt)
+			continue;
+		ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
+		snprintf(buffer,
+			LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n",
+			dtp->seq_cnt, ms, dtp->fmt);
+		len +=  snprintf(buf+len, size-len, buffer,
+			dtp->data1, dtp->data2, dtp->data3);
+	}
+
+	lpfc_debugfs_enable = enable;
+	return len;
+}
+
+static int lpfc_debugfs_last_hbq = -1;
+
+static int
+lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size)
+{
+	int len = 0;
+	int cnt, i, j, found, posted, low;
+	uint32_t phys, raw_index, getidx;
+	struct lpfc_hbq_init *hip;
+	struct hbq_s *hbqs;
+	struct lpfc_hbq_entry *hbqe;
+	struct lpfc_dmabuf *d_buf;
+	struct hbq_dmabuf *hbq_buf;
+
+	cnt = LPFC_HBQINFO_SIZE;
+	spin_lock_irq(&phba->hbalock);
+
+	/* toggle between multiple hbqs, if any */
+	i = lpfc_sli_hbq_count();
+	if (i > 1) {
+		 lpfc_debugfs_last_hbq++;
+		 if (lpfc_debugfs_last_hbq >= i)
+			lpfc_debugfs_last_hbq = 0;
+	}
+	else
+		lpfc_debugfs_last_hbq = 0;
+
+	i = lpfc_debugfs_last_hbq;
+
+	len +=  snprintf(buf+len, size-len, "HBQ %d Info\n", i);
+
+	hbqs =  &phba->hbqs[i];
+	posted = 0;
+	list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list)
+		posted++;
+
+	hip =  lpfc_hbq_defs[i];
+	len +=  snprintf(buf+len, size-len,
+		"idx:%d prof:%d rn:%d bufcnt:%d icnt:%d acnt:%d posted %d\n",
+		hip->hbq_index, hip->profile, hip->rn,
+		hip->buffer_count, hip->init_count, hip->add_count, posted);
+
+	raw_index = phba->hbq_get[i];
+	getidx = le32_to_cpu(raw_index);
+	len +=  snprintf(buf+len, size-len,
+		"entrys:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n",
+		hbqs->entry_count, hbqs->hbqPutIdx, hbqs->next_hbqPutIdx,
+		hbqs->local_hbqGetIdx, getidx);
+
+	hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt;
+	for (j=0; j<hbqs->entry_count; j++) {
+		len +=  snprintf(buf+len, size-len,
+			"%03d: %08x %04x %05x ", j,
+			hbqe->bde.addrLow, hbqe->bde.tus.w, hbqe->buffer_tag);
+
+		i = 0;
+		found = 0;
+
+		/* First calculate if slot has an associated posted buffer */
+		low = hbqs->hbqPutIdx - posted;
+		if (low >= 0) {
+			if ((j >= hbqs->hbqPutIdx) || (j < low)) {
+				len +=  snprintf(buf+len, size-len, "Unused\n");
+				goto skipit;
+			}
+		}
+		else {
+			if ((j >= hbqs->hbqPutIdx) &&
+				(j < (hbqs->entry_count+low))) {
+				len +=  snprintf(buf+len, size-len, "Unused\n");
+				goto skipit;
+			}
+		}
+
+		/* Get the Buffer info for the posted buffer */
+		list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) {
+			hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
+			phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff);
+			if (phys == hbqe->bde.addrLow) {
+				len +=  snprintf(buf+len, size-len,
+					"Buf%d: %p %06x\n", i,
+					hbq_buf->dbuf.virt, hbq_buf->tag);
+				found = 1;
+				break;
+			}
+			i++;
+		}
+		if (!found) {
+			len +=  snprintf(buf+len, size-len, "No DMAinfo?\n");
+		}
+skipit:
+		hbqe++;
+		if (len > LPFC_HBQINFO_SIZE - 54)
+			break;
+	}
+	spin_unlock_irq(&phba->hbalock);
+	return len;
+}
+
+static int
+lpfc_debugfs_dumpslim_data(struct lpfc_hba *phba, char *buf, int size)
+{
+	int len = 0;
+	int cnt, i, off;
+	uint32_t word0, word1, word2, word3;
+	uint32_t *ptr;
+	struct lpfc_pgp *pgpp;
+	struct lpfc_sli *psli = &phba->sli;
+	struct lpfc_sli_ring *pring;
+
+	cnt = LPFC_DUMPSLIM_SIZE;
+	off = 0;
+	spin_lock_irq(&phba->hbalock);
+
+	len +=  snprintf(buf+len, size-len, "SLIM Mailbox\n");
+	ptr = (uint32_t *)phba->slim2p;
+	i = sizeof(MAILBOX_t);
+	while (i > 0) {
+		len +=  snprintf(buf+len, size-len,
+		"%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+		off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
+		*(ptr+5), *(ptr+6), *(ptr+7));
+		ptr += 8;
+		i -= (8 * sizeof(uint32_t));
+		off += (8 * sizeof(uint32_t));
+	}
+
+	len +=  snprintf(buf+len, size-len, "SLIM PCB\n");
+	ptr = (uint32_t *)&phba->slim2p->pcb;
+	i = sizeof(PCB_t);
+	while (i > 0) {
+		len +=  snprintf(buf+len, size-len,
+		"%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+		off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4),
+		*(ptr+5), *(ptr+6), *(ptr+7));
+		ptr += 8;
+		i -= (8 * sizeof(uint32_t));
+		off += (8 * sizeof(uint32_t));
+	}
+
+	pgpp = (struct lpfc_pgp *)&phba->slim2p->mbx.us.s3_pgp.port;
+	pring = &psli->ring[0];
+	len +=  snprintf(buf+len, size-len,
+		"Ring 0: CMD GetInx:%d (Max:%d Next:%d Local:%d flg:x%x)  "
+		"RSP PutInx:%d Max:%d\n",
+		pgpp->cmdGetInx, pring->numCiocb,
+		pring->next_cmdidx, pring->local_getidx, pring->flag,
+		pgpp->rspPutInx, pring->numRiocb);
+	pgpp++;
+
+	pring = &psli->ring[1];
+	len +=  snprintf(buf+len, size-len,
+		"Ring 1: CMD GetInx:%d (Max:%d Next:%d Local:%d flg:x%x)  "
+		"RSP PutInx:%d Max:%d\n",
+		pgpp->cmdGetInx, pring->numCiocb,
+		pring->next_cmdidx, pring->local_getidx, pring->flag,
+		pgpp->rspPutInx, pring->numRiocb);
+	pgpp++;
+
+	pring = &psli->ring[2];
+	len +=  snprintf(buf+len, size-len,
+		"Ring 2: CMD GetInx:%d (Max:%d Next:%d Local:%d flg:x%x)  "
+		"RSP PutInx:%d Max:%d\n",
+		pgpp->cmdGetInx, pring->numCiocb,
+		pring->next_cmdidx, pring->local_getidx, pring->flag,
+		pgpp->rspPutInx, pring->numRiocb);
+	pgpp++;
+
+	pring = &psli->ring[3];
+	len +=  snprintf(buf+len, size-len,
+		"Ring 3: CMD GetInx:%d (Max:%d Next:%d Local:%d flg:x%x)  "
+		"RSP PutInx:%d Max:%d\n",
+		pgpp->cmdGetInx, pring->numCiocb,
+		pring->next_cmdidx, pring->local_getidx, pring->flag,
+		pgpp->rspPutInx, pring->numRiocb);
+
+
+	ptr = (uint32_t *)&phba->slim2p->mbx.us.s3_pgp.hbq_get;
+	word0 = readl(phba->HAregaddr);
+	word1 = readl(phba->CAregaddr);
+	word2 = readl(phba->HSregaddr);
+	word3 = readl(phba->HCregaddr);
+	len +=  snprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x HC:%08x\n",
+	word0, word1, word2, word3);
+	spin_unlock_irq(&phba->hbalock);
+	return len;
+}
+
+static int
 lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
 {
 	int len = 0;
@@ -204,7 +449,7 @@
 		len +=  snprintf(buf+len, size-len, "RPI:%03d flag:x%08x ",
 			ndlp->nlp_rpi, ndlp->nlp_flag);
 		if (!ndlp->nlp_type)
-			len +=  snprintf(buf+len, size-len, "UNKNOWN_TYPE");
+			len +=  snprintf(buf+len, size-len, "UNKNOWN_TYPE ");
 		if (ndlp->nlp_type & NLP_FC_NODE)
 			len +=  snprintf(buf+len, size-len, "FC_NODE ");
 		if (ndlp->nlp_type & NLP_FABRIC)
@@ -213,7 +458,9 @@
 			len +=  snprintf(buf+len, size-len, "FCP_TGT sid:%d ",
 				ndlp->nlp_sid);
 		if (ndlp->nlp_type & NLP_FCP_INITIATOR)
-			len +=  snprintf(buf+len, size-len, "FCP_INITIATOR");
+			len +=  snprintf(buf+len, size-len, "FCP_INITIATOR ");
+		len += snprintf(buf+len, size-len, "refcnt:%x",
+			atomic_read(&ndlp->kref.refcount));
 		len +=  snprintf(buf+len, size-len, "\n");
 	}
 	spin_unlock_irq(shost->host_lock);
@@ -227,7 +474,7 @@
 	uint32_t data1, uint32_t data2, uint32_t data3)
 {
 #ifdef CONFIG_LPFC_DEBUG_FS
-	struct lpfc_disc_trc *dtp;
+	struct lpfc_debugfs_trc *dtp;
 	int index;
 
 	if (!(lpfc_debugfs_mask_disc_trc & mask))
@@ -244,7 +491,32 @@
 	dtp->data1 = data1;
 	dtp->data2 = data2;
 	dtp->data3 = data3;
-	dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_disc_trc_cnt);
+	dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_seq_trc_cnt);
+	dtp->jif = jiffies;
+#endif
+	return;
+}
+
+inline void
+lpfc_debugfs_slow_ring_trc(struct lpfc_hba *phba, char *fmt,
+	uint32_t data1, uint32_t data2, uint32_t data3)
+{
+#ifdef CONFIG_LPFC_DEBUG_FS
+	struct lpfc_debugfs_trc *dtp;
+	int index;
+
+	if (!lpfc_debugfs_enable || !lpfc_debugfs_max_slow_ring_trc ||
+		!phba || !phba->slow_ring_trc)
+		return;
+
+	index = atomic_inc_return(&phba->slow_ring_trc_cnt) &
+		(lpfc_debugfs_max_slow_ring_trc - 1);
+	dtp = phba->slow_ring_trc + index;
+	dtp->fmt = fmt;
+	dtp->data1 = data1;
+	dtp->data2 = data2;
+	dtp->data3 = data3;
+	dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_seq_trc_cnt);
 	dtp->jif = jiffies;
 #endif
 	return;
@@ -269,7 +541,7 @@
 		goto out;
 
 	/* Round to page boundry */
-	size =  (lpfc_debugfs_max_disc_trc * LPFC_DISC_TRC_ENTRY_SIZE);
+	size =  (lpfc_debugfs_max_disc_trc * LPFC_DEBUG_TRC_ENTRY_SIZE);
 	size = PAGE_ALIGN(size);
 
 	debug->buffer = kmalloc(size, GFP_KERNEL);
@@ -287,6 +559,95 @@
 }
 
 static int
+lpfc_debugfs_slow_ring_trc_open(struct inode *inode, struct file *file)
+{
+	struct lpfc_hba *phba = inode->i_private;
+	struct lpfc_debug *debug;
+	int size;
+	int rc = -ENOMEM;
+
+	if (!lpfc_debugfs_max_slow_ring_trc) {
+		 rc = -ENOSPC;
+		goto out;
+	}
+
+	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+	if (!debug)
+		goto out;
+
+	/* Round to page boundry */
+	size =  (lpfc_debugfs_max_slow_ring_trc * LPFC_DEBUG_TRC_ENTRY_SIZE);
+	size = PAGE_ALIGN(size);
+
+	debug->buffer = kmalloc(size, GFP_KERNEL);
+	if (!debug->buffer) {
+		kfree(debug);
+		goto out;
+	}
+
+	debug->len = lpfc_debugfs_slow_ring_trc_data(phba, debug->buffer, size);
+	file->private_data = debug;
+
+	rc = 0;
+out:
+	return rc;
+}
+
+static int
+lpfc_debugfs_hbqinfo_open(struct inode *inode, struct file *file)
+{
+	struct lpfc_hba *phba = inode->i_private;
+	struct lpfc_debug *debug;
+	int rc = -ENOMEM;
+
+	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+	if (!debug)
+		goto out;
+
+	/* Round to page boundry */
+	debug->buffer = kmalloc(LPFC_HBQINFO_SIZE, GFP_KERNEL);
+	if (!debug->buffer) {
+		kfree(debug);
+		goto out;
+	}
+
+	debug->len = lpfc_debugfs_hbqinfo_data(phba, debug->buffer,
+		LPFC_HBQINFO_SIZE);
+	file->private_data = debug;
+
+	rc = 0;
+out:
+	return rc;
+}
+
+static int
+lpfc_debugfs_dumpslim_open(struct inode *inode, struct file *file)
+{
+	struct lpfc_hba *phba = inode->i_private;
+	struct lpfc_debug *debug;
+	int rc = -ENOMEM;
+
+	debug = kmalloc(sizeof(*debug), GFP_KERNEL);
+	if (!debug)
+		goto out;
+
+	/* Round to page boundry */
+	debug->buffer = kmalloc(LPFC_DUMPSLIM_SIZE, GFP_KERNEL);
+	if (!debug->buffer) {
+		kfree(debug);
+		goto out;
+	}
+
+	debug->len = lpfc_debugfs_dumpslim_data(phba, debug->buffer,
+		LPFC_DUMPSLIM_SIZE);
+	file->private_data = debug;
+
+	rc = 0;
+out:
+	return rc;
+}
+
+static int
 lpfc_debugfs_nodelist_open(struct inode *inode, struct file *file)
 {
 	struct lpfc_vport *vport = inode->i_private;
@@ -372,6 +733,33 @@
 	.release =      lpfc_debugfs_release,
 };
 
+#undef lpfc_debugfs_op_hbqinfo
+static struct file_operations lpfc_debugfs_op_hbqinfo = {
+	.owner =        THIS_MODULE,
+	.open =         lpfc_debugfs_hbqinfo_open,
+	.llseek =       lpfc_debugfs_lseek,
+	.read =         lpfc_debugfs_read,
+	.release =      lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_dumpslim
+static struct file_operations lpfc_debugfs_op_dumpslim = {
+	.owner =        THIS_MODULE,
+	.open =         lpfc_debugfs_dumpslim_open,
+	.llseek =       lpfc_debugfs_lseek,
+	.read =         lpfc_debugfs_read,
+	.release =      lpfc_debugfs_release,
+};
+
+#undef lpfc_debugfs_op_slow_ring_trc
+static struct file_operations lpfc_debugfs_op_slow_ring_trc = {
+	.owner =        THIS_MODULE,
+	.open =         lpfc_debugfs_slow_ring_trc_open,
+	.llseek =       lpfc_debugfs_lseek,
+	.read =         lpfc_debugfs_read,
+	.release =      lpfc_debugfs_release,
+};
+
 static struct dentry *lpfc_debugfs_root = NULL;
 static atomic_t lpfc_debugfs_hba_count;
 #endif
@@ -387,6 +775,116 @@
 	if (!lpfc_debugfs_enable)
 		return;
 
+	/* Setup lpfc root directory */
+	if (!lpfc_debugfs_root) {
+		lpfc_debugfs_root = debugfs_create_dir("lpfc", NULL);
+		atomic_set(&lpfc_debugfs_hba_count, 0);
+		if (!lpfc_debugfs_root) {
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+					 "0409 Cannot create debugfs root\n");
+			goto debug_failed;
+		}
+	}
+	if (!lpfc_debugfs_start_time)
+		lpfc_debugfs_start_time = jiffies;
+
+	/* Setup lpfcX directory for specific HBA */
+	snprintf(name, sizeof(name), "lpfc%d", phba->brd_no);
+	if (!phba->hba_debugfs_root) {
+		phba->hba_debugfs_root =
+			debugfs_create_dir(name, lpfc_debugfs_root);
+		if (!phba->hba_debugfs_root) {
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+					 "0409 Cannot create debugfs hba\n");
+			goto debug_failed;
+		}
+		atomic_inc(&lpfc_debugfs_hba_count);
+		atomic_set(&phba->debugfs_vport_count, 0);
+
+		/* Setup hbqinfo */
+		snprintf(name, sizeof(name), "hbqinfo");
+		phba->debug_hbqinfo =
+			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+				 phba->hba_debugfs_root,
+				 phba, &lpfc_debugfs_op_hbqinfo);
+		if (!phba->debug_hbqinfo) {
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+				"0409 Cannot create debugfs hbqinfo\n");
+			goto debug_failed;
+		}
+
+		/* Setup dumpslim */
+		snprintf(name, sizeof(name), "dumpslim");
+		phba->debug_dumpslim =
+			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+				 phba->hba_debugfs_root,
+				 phba, &lpfc_debugfs_op_dumpslim);
+		if (!phba->debug_dumpslim) {
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+				"0409 Cannot create debugfs dumpslim\n");
+			goto debug_failed;
+		}
+
+		/* Setup slow ring trace */
+		if (lpfc_debugfs_max_slow_ring_trc) {
+			num = lpfc_debugfs_max_slow_ring_trc - 1;
+			if (num & lpfc_debugfs_max_slow_ring_trc) {
+				/* Change to be a power of 2 */
+				num = lpfc_debugfs_max_slow_ring_trc;
+				i = 0;
+				while (num > 1) {
+					num = num >> 1;
+					i++;
+				}
+				lpfc_debugfs_max_slow_ring_trc = (1 << i);
+				printk(KERN_ERR
+				       "lpfc_debugfs_max_disc_trc changed to "
+				       "%d\n", lpfc_debugfs_max_disc_trc);
+			}
+		}
+
+
+		snprintf(name, sizeof(name), "slow_ring_trace");
+		phba->debug_slow_ring_trc =
+			debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
+				 phba->hba_debugfs_root,
+				 phba, &lpfc_debugfs_op_slow_ring_trc);
+		if (!phba->debug_slow_ring_trc) {
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+					 "0409 Cannot create debugfs "
+					 "slow_ring_trace\n");
+			goto debug_failed;
+		}
+		if (!phba->slow_ring_trc) {
+			phba->slow_ring_trc = kmalloc(
+				(sizeof(struct lpfc_debugfs_trc) *
+				lpfc_debugfs_max_slow_ring_trc),
+				GFP_KERNEL);
+			if (!phba->slow_ring_trc) {
+				lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+						 "0409 Cannot create debugfs "
+						 "slow_ring buffer\n");
+				goto debug_failed;
+			}
+			atomic_set(&phba->slow_ring_trc_cnt, 0);
+			memset(phba->slow_ring_trc, 0,
+				(sizeof(struct lpfc_debugfs_trc) *
+				lpfc_debugfs_max_slow_ring_trc));
+		}
+	}
+
+	snprintf(name, sizeof(name), "vport%d", vport->vpi);
+	if (!vport->vport_debugfs_root) {
+		vport->vport_debugfs_root =
+			debugfs_create_dir(name, phba->hba_debugfs_root);
+		if (!vport->vport_debugfs_root) {
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+					 "0409 Cant create debugfs");
+			goto debug_failed;
+		}
+		atomic_inc(&phba->debugfs_vport_count);
+	}
+
 	if (lpfc_debugfs_max_disc_trc) {
 		num = lpfc_debugfs_max_disc_trc - 1;
 		if (num & lpfc_debugfs_max_disc_trc) {
@@ -399,48 +897,24 @@
 			}
 			lpfc_debugfs_max_disc_trc = (1 << i);
 			printk(KERN_ERR
-				"lpfc_debugfs_max_disc_trc changed to %d\n",
-				lpfc_debugfs_max_disc_trc);
+			       "lpfc_debugfs_max_disc_trc changed to %d\n",
+			       lpfc_debugfs_max_disc_trc);
 		}
 	}
 
-	if (!lpfc_debugfs_root) {
-		lpfc_debugfs_root = debugfs_create_dir("lpfc", NULL);
-		atomic_set(&lpfc_debugfs_hba_count, 0);
-		if (!lpfc_debugfs_root)
-			goto debug_failed;
-	}
-
-	snprintf(name, sizeof(name), "lpfc%d", phba->brd_no);
-	if (!phba->hba_debugfs_root) {
-		phba->hba_debugfs_root =
-			debugfs_create_dir(name, lpfc_debugfs_root);
-		if (!phba->hba_debugfs_root)
-			goto debug_failed;
-		atomic_inc(&lpfc_debugfs_hba_count);
-		atomic_set(&phba->debugfs_vport_count, 0);
-	}
-
-	snprintf(name, sizeof(name), "vport%d", vport->vpi);
-	if (!vport->vport_debugfs_root) {
-		vport->vport_debugfs_root =
-			debugfs_create_dir(name, phba->hba_debugfs_root);
-		if (!vport->vport_debugfs_root)
-			goto debug_failed;
-		atomic_inc(&phba->debugfs_vport_count);
-	}
-
-	if (!lpfc_debugfs_start_time)
-		lpfc_debugfs_start_time = jiffies;
-
 	vport->disc_trc = kmalloc(
-		(sizeof(struct lpfc_disc_trc) * lpfc_debugfs_max_disc_trc),
+		(sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc),
 		GFP_KERNEL);
 
-	if (!vport->disc_trc)
+	if (!vport->disc_trc) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+				 "0409 Cannot create debugfs disc trace "
+				 "buffer\n");
 		goto debug_failed;
+	}
+	atomic_set(&vport->disc_trc_cnt, 0);
 	memset(vport->disc_trc, 0,
-		(sizeof(struct lpfc_disc_trc) * lpfc_debugfs_max_disc_trc));
+		(sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc));
 
 	snprintf(name, sizeof(name), "discovery_trace");
 	vport->debug_disc_trc =
@@ -448,9 +922,9 @@
 				 vport->vport_debugfs_root,
 				 vport, &lpfc_debugfs_op_disc_trc);
 	if (!vport->debug_disc_trc) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"%d:0409 Cannot create debugfs",
-				phba->brd_no);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+				 "0409 Cannot create debugfs "
+				 "discovery_trace\n");
 		goto debug_failed;
 	}
 	snprintf(name, sizeof(name), "nodelist");
@@ -459,9 +933,8 @@
 				 vport->vport_debugfs_root,
 				 vport, &lpfc_debugfs_op_nodelist);
 	if (!vport->debug_nodelist) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"%d:0409 Cannot create debugfs",
-				phba->brd_no);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
+				 "0409 Cant create debugfs nodelist");
 		goto debug_failed;
 	}
 debug_failed:
@@ -488,21 +961,45 @@
 		debugfs_remove(vport->debug_nodelist); /* nodelist */
 		vport->debug_nodelist = NULL;
 	}
+
 	if (vport->vport_debugfs_root) {
 		debugfs_remove(vport->vport_debugfs_root); /* vportX */
 		vport->vport_debugfs_root = NULL;
 		atomic_dec(&phba->debugfs_vport_count);
 	}
 	if (atomic_read(&phba->debugfs_vport_count) == 0) {
-		debugfs_remove(vport->phba->hba_debugfs_root); /* lpfcX */
-		vport->phba->hba_debugfs_root = NULL;
-		atomic_dec(&lpfc_debugfs_hba_count);
+
+		if (phba->debug_hbqinfo) {
+			debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */
+			phba->debug_hbqinfo = NULL;
+		}
+		if (phba->debug_dumpslim) {
+			debugfs_remove(phba->debug_dumpslim); /* dumpslim */
+			phba->debug_dumpslim = NULL;
+		}
+		if (phba->slow_ring_trc) {
+			kfree(phba->slow_ring_trc);
+			phba->slow_ring_trc = NULL;
+		}
+		if (phba->debug_slow_ring_trc) {
+			/* slow_ring_trace */
+			debugfs_remove(phba->debug_slow_ring_trc);
+			phba->debug_slow_ring_trc = NULL;
+		}
+
+		if (phba->hba_debugfs_root) {
+			debugfs_remove(phba->hba_debugfs_root); /* lpfcX */
+			phba->hba_debugfs_root = NULL;
+			atomic_dec(&lpfc_debugfs_hba_count);
+		}
+
 		if (atomic_read(&lpfc_debugfs_hba_count) == 0) {
 			debugfs_remove(lpfc_debugfs_root); /* lpfc */
 			lpfc_debugfs_root = NULL;
 		}
 	}
 #endif
+	return;
 }
 
 
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.h b/drivers/scsi/lpfc/lpfc_debugfs.h
index fffb678..31e86a5 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.h
+++ b/drivers/scsi/lpfc/lpfc_debugfs.h
@@ -22,7 +22,7 @@
 #define _H_LPFC_DEBUG_FS
 
 #ifdef CONFIG_LPFC_DEBUG_FS
-struct lpfc_disc_trc {
+struct lpfc_debugfs_trc {
 	char *fmt;
 	uint32_t data1;
 	uint32_t data2;
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 33fbc16..8085900 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -63,10 +63,10 @@
 		return 0;
 
 	/* Pending Link Event during Discovery */
-	lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-			"%d (%d):0237 Pending Link Event during "
-			"Discovery: State x%x\n",
-			phba->brd_no, vport->vpi,  phba->pport->port_state);
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+			 "0237 Pending Link Event during "
+			 "Discovery: State x%x\n",
+			 phba->pport->port_state);
 
 	/* CLEAR_LA should re-enable link attention events and
 	 * we should then imediately take a LATT event. The
@@ -196,9 +196,7 @@
 		bpl->tus.w = le32_to_cpu(bpl->tus.w);
 	}
 
-	/* Save for completion so we can release these resources */
-	if (elscmd != ELS_CMD_LS_RJT)
-		elsiocb->context1 = lpfc_nlp_get(ndlp);
+	elsiocb->context1 = lpfc_nlp_get(ndlp);
 	elsiocb->context2 = pcmd;
 	elsiocb->context3 = pbuflist;
 	elsiocb->retry = retry;
@@ -208,23 +206,21 @@
 	if (prsp) {
 		list_add(&prsp->list, &pcmd->list);
 	}
-
 	if (expectRsp) {
 		/* Xmit ELS command <elsCmd> to remote NPORT <did> */
-		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-				"%d (%d):0116 Xmit ELS command x%x to remote "
-				"NPORT x%x I/O tag: x%x, port state: x%x\n",
-				phba->brd_no, vport->vpi,  elscmd, did,
-				elsiocb->iotag, vport->port_state);
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+				 "0116 Xmit ELS command x%x to remote "
+				 "NPORT x%x I/O tag: x%x, port state: x%x\n",
+				 elscmd, did, elsiocb->iotag,
+				 vport->port_state);
 	} else {
 		/* Xmit ELS response <elsCmd> to remote NPORT <did> */
-		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-				"%d (%d):0117 Xmit ELS response x%x to remote "
-				"NPORT x%x I/O tag: x%x, size: x%x\n",
-				phba->brd_no, vport->vpi, elscmd,
-				ndlp->nlp_DID, elsiocb->iotag, cmdSize);
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+				 "0117 Xmit ELS response x%x to remote "
+				 "NPORT x%x I/O tag: x%x, size: x%x\n",
+				 elscmd, ndlp->nlp_DID, elsiocb->iotag,
+				 cmdSize);
 	}
-
 	return elsiocb;
 }
 
@@ -285,9 +281,8 @@
 
 fail:
 	lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-	lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-		"%d (%d):0249 Cannot issue Register Fabric login\n",
-		phba->brd_no, vport->vpi);
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+		"0249 Cannot issue Register Fabric login\n");
 	return -ENXIO;
 }
 
@@ -340,20 +335,19 @@
 
 	if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
 		if (sp->cmn.response_multiple_NPort) {
-			lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_VPORT,
-					"%d:1816 FLOGI NPIV supported, "
-					"response data 0x%x\n",
-					phba->brd_no,
-					sp->cmn.response_multiple_NPort);
+			lpfc_printf_vlog(vport, KERN_WARNING,
+					 LOG_ELS | LOG_VPORT,
+					 "1816 FLOGI NPIV supported, "
+					 "response data 0x%x\n",
+					 sp->cmn.response_multiple_NPort);
 			phba->link_flag |= LS_NPIV_FAB_SUPPORTED;
-
 		} else {
 			/* Because we asked f/w for NPIV it still expects us
-			   to call reg_vnpid atleast for the physcial host */
-			lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_VPORT,
-					"%d:1817 Fabric does not support NPIV "
-					"- configuring single port mode.\n",
-					phba->brd_no);
+			to call reg_vnpid atleast for the physcial host */
+			lpfc_printf_vlog(vport, KERN_WARNING,
+					 LOG_ELS | LOG_VPORT,
+					 "1817 Fabric does not support NPIV "
+					 "- configuring single port mode.\n");
 			phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED;
 		}
 	}
@@ -518,16 +512,15 @@
 		 * alpa map would take too long otherwise.
 		 */
 		if (phba->alpa_map[0] == 0) {
-			phba->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
+			vport->cfg_discovery_threads = LPFC_MAX_DISC_THREADS;
 		}
 
 		/* FLOGI failure */
-		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-				"%d (%d):0100 FLOGI failure Data: x%x x%x "
-				"x%x\n",
-				phba->brd_no, vport->vpi,
-				irsp->ulpStatus, irsp->un.ulpWord[4],
-				irsp->ulpTimeout);
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+				 "0100 FLOGI failure Data: x%x x%x "
+				 "x%x\n",
+				 irsp->ulpStatus, irsp->un.ulpWord[4],
+				 irsp->ulpTimeout);
 		goto flogifail;
 	}
 
@@ -540,12 +533,11 @@
 	sp = prsp->virt + sizeof(uint32_t);
 
 	/* FLOGI completes successfully */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0101 FLOGI completes sucessfully "
-			"Data: x%x x%x x%x x%x\n",
-			phba->brd_no, vport->vpi,
-			irsp->un.ulpWord[4], sp->cmn.e_d_tov,
-			sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution);
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0101 FLOGI completes sucessfully "
+			 "Data: x%x x%x x%x x%x\n",
+			 irsp->un.ulpWord[4], sp->cmn.e_d_tov,
+			 sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution);
 
 	if (vport->port_state == LPFC_FLOGI) {
 		/*
@@ -662,8 +654,8 @@
 
 	/* Abort outstanding I/O on NPort <nlp_DID> */
 	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			"%d:0201 Abort outstanding I/O on NPort x%x\n",
-			phba->brd_no, Fabric_DID);
+			"0201 Abort outstanding I/O on NPort x%x\n",
+			Fabric_DID);
 
 	pring = &phba->sli.ring[LPFC_ELS_RING];
 
@@ -736,18 +728,16 @@
 lpfc_more_plogi(struct lpfc_vport *vport)
 {
 	int sentplogi;
-	struct lpfc_hba *phba = vport->phba;
 
 	if (vport->num_disc_nodes)
 		vport->num_disc_nodes--;
 
 	/* Continue discovery with <num_disc_nodes> PLOGIs to go */
-	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			"%d (%d):0232 Continue discovery with %d PLOGIs to go "
-			"Data: x%x x%x x%x\n",
-			phba->brd_no, vport->vpi, vport->num_disc_nodes,
-			vport->fc_plogi_cnt, vport->fc_flag, vport->port_state);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+			 "0232 Continue discovery with %d PLOGIs to go "
+			 "Data: x%x x%x x%x\n",
+			 vport->num_disc_nodes, vport->fc_plogi_cnt,
+			 vport->fc_flag, vport->port_state);
 	/* Check to see if there are more PLOGIs to be sent */
 	if (vport->fc_flag & FC_NLP_MORE)
 		/* go thru NPR nodes and issue any remaining ELS PLOGIs */
@@ -833,11 +823,12 @@
 
 	ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID);
 	if (!ndlp) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-			"%d (%d):0136 PLOGI completes to NPort x%x "
-			"with no ndlp. Data: x%x x%x x%x\n",
-			phba->brd_no, vport->vpi, irsp->un.elsreq64.remoteID,
-			irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpIoTag);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				 "0136 PLOGI completes to NPort x%x "
+				 "with no ndlp. Data: x%x x%x x%x\n",
+				 irsp->un.elsreq64.remoteID,
+				 irsp->ulpStatus, irsp->un.ulpWord[4],
+				 irsp->ulpIoTag);
 		goto out;
 	}
 
@@ -851,13 +842,11 @@
 	rc   = 0;
 
 	/* PLOGI completes to NPort <nlp_DID> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0102 PLOGI completes to NPort x%x "
-			"Data: x%x x%x x%x x%x x%x\n",
-			phba->brd_no, vport->vpi, ndlp->nlp_DID,
-			irsp->ulpStatus, irsp->un.ulpWord[4],
-			irsp->ulpTimeout, disc, vport->num_disc_nodes);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0102 PLOGI completes to NPort x%x "
+			 "Data: x%x x%x x%x x%x x%x\n",
+			 ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
+			 irsp->ulpTimeout, disc, vport->num_disc_nodes);
 	/* Check to see if link went down during discovery */
 	if (lpfc_els_chk_latt(vport)) {
 		spin_lock_irq(shost->host_lock);
@@ -881,17 +870,14 @@
 			}
 			goto out;
 		}
-
 		/* PLOGI failed */
 		if (ndlp->nlp_DID == NameServer_DID) {
 			lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-			lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-				"%d (%d):0250 Nameserver login error: "
-				"0x%x / 0x%x\n",
-				phba->brd_no, vport->vpi,
-				irsp->ulpStatus, irsp->un.ulpWord[4]);
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+					 "0250 Nameserver login error: "
+					 "0x%x / 0x%x\n",
+					 irsp->ulpStatus, irsp->un.ulpWord[4]);
 		}
-
 		/* Do not call DSM for lpfc_els_abort'ed ELS cmds */
 		if (lpfc_error_lost_link(irsp)) {
 			rc = NLP_STE_FREED_NODE;
@@ -1017,14 +1003,12 @@
 		"PRLI cmpl:       status:x%x/x%x did:x%x",
 		irsp->ulpStatus, irsp->un.ulpWord[4],
 		ndlp->nlp_DID);
-
 	/* PRLI completes to NPort <nlp_DID> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0103 PRLI completes to NPort x%x "
-			"Data: x%x x%x x%x x%x\n",
-			phba->brd_no, vport->vpi, ndlp->nlp_DID,
-			irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout,
-			vport->num_disc_nodes);
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0103 PRLI completes to NPort x%x "
+			 "Data: x%x x%x x%x x%x\n",
+			 ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
+			 irsp->ulpTimeout, vport->num_disc_nodes);
 
 	vport->fc_prli_sent--;
 	/* Check to see if link went down during discovery */
@@ -1129,18 +1113,15 @@
 lpfc_more_adisc(struct lpfc_vport *vport)
 {
 	int sentadisc;
-	struct lpfc_hba *phba = vport->phba;
 
 	if (vport->num_disc_nodes)
 		vport->num_disc_nodes--;
-
 	/* Continue discovery with <num_disc_nodes> ADISCs to go */
-	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			"%d (%d):0210 Continue discovery with %d ADISCs to go "
-			"Data: x%x x%x x%x\n",
-			phba->brd_no, vport->vpi, vport->num_disc_nodes,
-			vport->fc_adisc_cnt, vport->fc_flag, vport->port_state);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+			 "0210 Continue discovery with %d ADISCs to go "
+			 "Data: x%x x%x x%x\n",
+			 vport->num_disc_nodes, vport->fc_adisc_cnt,
+			 vport->fc_flag, vport->port_state);
 	/* Check to see if there are more ADISCs to be sent */
 	if (vport->fc_flag & FC_NLP_MORE) {
 		lpfc_set_disctmo(vport);
@@ -1206,15 +1187,12 @@
 	disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
 	ndlp->nlp_flag &= ~(NLP_ADISC_SND | NLP_NPR_2B_DISC);
 	spin_unlock_irq(shost->host_lock);
-
 	/* ADISC completes to NPort <nlp_DID> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0104 ADISC completes to NPort x%x "
-			"Data: x%x x%x x%x x%x x%x\n",
-			phba->brd_no, vport->vpi, ndlp->nlp_DID,
-			irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout,
-			disc, vport->num_disc_nodes);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0104 ADISC completes to NPort x%x "
+			 "Data: x%x x%x x%x x%x x%x\n",
+			 ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
+			 irsp->ulpTimeout, disc, vport->num_disc_nodes);
 	/* Check to see if link went down during discovery */
 	if (lpfc_els_chk_latt(vport)) {
 		spin_lock_irq(shost->host_lock);
@@ -1374,15 +1352,12 @@
 		"LOGO cmpl:       status:x%x/x%x did:x%x",
 		irsp->ulpStatus, irsp->un.ulpWord[4],
 		ndlp->nlp_DID);
-
 	/* LOGO completes to NPort <nlp_DID> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0105 LOGO completes to NPort x%x "
-			"Data: x%x x%x x%x x%x\n",
-			phba->brd_no, vport->vpi, ndlp->nlp_DID,
-			irsp->ulpStatus, irsp->un.ulpWord[4], irsp->ulpTimeout,
-			vport->num_disc_nodes);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0105 LOGO completes to NPort x%x "
+			 "Data: x%x x%x x%x x%x\n",
+			 ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4],
+			 irsp->ulpTimeout, vport->num_disc_nodes);
 	/* Check to see if link went down during discovery */
 	if (lpfc_els_chk_latt(vport))
 		goto out;
@@ -1488,15 +1463,11 @@
 		"ELS cmd cmpl:    status:x%x/x%x did:x%x",
 		irsp->ulpStatus, irsp->un.ulpWord[4],
 		irsp->un.elsreq64.remoteID);
-
 	/* ELS cmd tag <ulpIoTag> completes */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0106 ELS cmd tag x%x completes Data: x%x x%x "
-			"x%x\n",
-			phba->brd_no, vport->vpi,
-			irsp->ulpIoTag, irsp->ulpStatus,
-			irsp->un.ulpWord[4], irsp->ulpTimeout);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0106 ELS cmd tag x%x completes Data: x%x x%x x%x\n",
+			 irsp->ulpIoTag, irsp->ulpStatus,
+			 irsp->un.ulpWord[4], irsp->ulpTimeout);
 	/* Check to see if link went down during discovery */
 	lpfc_els_chk_latt(vport);
 	lpfc_els_free_iocb(phba, cmdiocb);
@@ -1831,13 +1802,15 @@
 		case IOERR_ILLEGAL_COMMAND:
 			if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) &&
 			    (cmd == ELS_CMD_FDISC)) {
-				lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-				"%d (%d):0124 FDISC failed (3/6) retrying...\n",
-					phba->brd_no, vport->vpi);
+				lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+						 "0124 FDISC failed (3/6) "
+						 "retrying...\n");
 				lpfc_mbx_unreg_vpi(vport);
 				retry = 1;
-				/* Always retry for this case */
-				cmdiocb->retry = 0;
+				/* FDISC retry policy */
+				maxretry = 48;
+				if (cmdiocb->retry >= 32)
+					delay = 1000;
 			}
 			break;
 
@@ -1898,10 +1871,10 @@
 			if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
 			  (cmd == ELS_CMD_FDISC) &&
 			  (stat.un.b.lsRjtRsnCodeExp == LSEXP_OUT_OF_RESOURCE)){
-				lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-				"%d (%d):0125 FDISC Failed (x%x)."
-				" Fabric out of resources\n",
-				phba->brd_no, vport->vpi, stat.un.lsRjtError);
+				lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+						 "0125 FDISC Failed (x%x). "
+						 "Fabric out of resources\n",
+						 stat.un.lsRjtError);
 				lpfc_vport_set_state(vport,
 						     FC_VPORT_NO_FABRIC_RSCS);
 			}
@@ -1913,8 +1886,10 @@
 				delay = 1000;
 				maxretry = 48;
 			} else if (cmd == ELS_CMD_FDISC) {
-				/* Always retry for this case */
-				cmdiocb->retry = 0;
+				/* FDISC retry policy */
+				maxretry = 48;
+				if (cmdiocb->retry >= 32)
+					delay = 1000;
 			}
 			retry = 1;
 			break;
@@ -1926,10 +1901,10 @@
 			  ((stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_PNAME) ||
 			  (stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_NPORT_ID))
 			  ) {
-				lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-				"%d (%d):0123 FDISC Failed (x%x)."
-				" Fabric Detected Bad WWN\n",
-				phba->brd_no, vport->vpi, stat.un.lsRjtError);
+				lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+						 "0123 FDISC Failed (x%x). "
+						 "Fabric Detected Bad WWN\n",
+						 stat.un.lsRjtError);
 				lpfc_vport_set_state(vport,
 						     FC_VPORT_FABRIC_REJ_WWN);
 			}
@@ -1959,11 +1934,10 @@
 	if (retry) {
 
 		/* Retry ELS command <elsCmd> to remote NPORT <did> */
-		lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-				"%d (%d):0107 Retry ELS command x%x to remote "
-				"NPORT x%x Data: x%x x%x\n",
-				phba->brd_no, vport->vpi,
-				cmd, did, cmdiocb->retry, delay);
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+				 "0107 Retry ELS command x%x to remote "
+				 "NPORT x%x Data: x%x x%x\n",
+				 cmd, did, cmdiocb->retry, delay);
 
 		if (((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) &&
 			((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) ||
@@ -2031,14 +2005,12 @@
 			return 1;
 		}
 	}
-
 	/* No retry ELS command <elsCmd> to remote NPORT <did> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0108 No retry ELS command x%x to remote "
-			"NPORT x%x Data: x%x\n",
-			phba->brd_no, vport->vpi,
-			cmd, did, cmdiocb->retry);
-
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+			 "0108 No retry ELS command x%x to remote "
+			 "NPORT x%x Retried:%d Error:x%x/%x\n",
+			 cmd, did, cmdiocb->retry, irsp->ulpStatus,
+			 irsp->un.ulpWord[4]);
 	return 0;
 }
 
@@ -2087,14 +2059,12 @@
 	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
 		"ACC LOGO cmpl:   status:x%x/x%x did:x%x",
 		irsp->ulpStatus, irsp->un.ulpWord[4], ndlp->nlp_DID);
-
 	/* ACC to LOGO completes to NPort <nlp_DID> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0109 ACC to LOGO completes to NPort x%x "
-			"Data: x%x x%x x%x\n",
-			phba->brd_no, vport->vpi, ndlp->nlp_DID,
-			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0109 ACC to LOGO completes to NPort x%x "
+			 "Data: x%x x%x x%x\n",
+			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+			 ndlp->nlp_rpi);
 	switch (ndlp->nlp_state) {
 	case NLP_STE_UNUSED_NODE:	/* node is just allocated */
 		lpfc_drop_node(vport, ndlp);
@@ -2153,20 +2123,17 @@
 	}
 
 	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
-		"ACC cmpl:        status:x%x/x%x did:x%x",
+		"ELS rsp cmpl:    status:x%x/x%x did:x%x",
 		irsp->ulpStatus, irsp->un.ulpWord[4],
-		irsp->un.rcvels.remoteID);
-
+		cmdiocb->iocb.un.elsreq64.remoteID);
 	/* ELS response tag <ulpIoTag> completes */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0110 ELS response tag x%x completes "
-			"Data: x%x x%x x%x x%x x%x x%x x%x\n",
-			phba->brd_no, vport->vpi,
-			cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus,
-			rspiocb->iocb.un.ulpWord[4], rspiocb->iocb.ulpTimeout,
-			ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
-			ndlp->nlp_rpi);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0110 ELS response tag x%x completes "
+			 "Data: x%x x%x x%x x%x x%x x%x x%x\n",
+			 cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus,
+			 rspiocb->iocb.un.ulpWord[4], rspiocb->iocb.ulpTimeout,
+			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+			 ndlp->nlp_rpi);
 	if (mbox) {
 		if ((rspiocb->iocb.ulpStatus == 0)
 		    && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) {
@@ -2219,7 +2186,7 @@
 int
 lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag,
 		 struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp,
-		 LPFC_MBOXQ_t *mbox, uint8_t newnode)
+		 LPFC_MBOXQ_t *mbox)
 {
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_hba  *phba = vport->phba;
@@ -2305,20 +2272,13 @@
 	default:
 		return 1;
 	}
-
-	if (newnode) {
-		lpfc_nlp_put(ndlp);
-		elsiocb->context1 = NULL;
-	}
-
 	/* Xmit ELS ACC response tag <ulpIoTag> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
-			"DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
-			phba->brd_no, vport->vpi, elsiocb->iotag,
-			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
-			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0128 Xmit ELS ACC response tag x%x, XRI: x%x, "
+			 "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n",
+			 elsiocb->iotag, elsiocb->iocb.ulpContext,
+			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+			 ndlp->nlp_rpi);
 	if (ndlp->nlp_flag & NLP_LOGO_ACC) {
 		spin_lock_irq(shost->host_lock);
 		ndlp->nlp_flag &= ~NLP_LOGO_ACC;
@@ -2370,20 +2330,17 @@
 	pcmd += sizeof(uint32_t);
 	*((uint32_t *) (pcmd)) = rejectError;
 
-	if (mbox) {
+	if (mbox)
 		elsiocb->context_un.mbox = mbox;
-		elsiocb->context1 = lpfc_nlp_get(ndlp);
-	}
 
 	/* Xmit ELS RJT <err> response tag <ulpIoTag> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0129 Xmit ELS RJT x%x response tag x%x "
-			"xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
-			"rpi x%x\n",
-			phba->brd_no, vport->vpi, rejectError, elsiocb->iotag,
-			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
-			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0129 Xmit ELS RJT x%x response tag x%x "
+			 "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
+			 "rpi x%x\n",
+			 rejectError, elsiocb->iotag,
+			 elsiocb->iocb.ulpContext, ndlp->nlp_DID,
+			 ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
 	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
 		"Issue LS_RJT:    did:x%x flg:x%x err:x%x",
 		ndlp->nlp_DID, ndlp->nlp_flag, rejectError);
@@ -2391,6 +2348,15 @@
 	phba->fc_stat.elsXmitLSRJT++;
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
 	rc = lpfc_sli_issue_iocb(phba, pring, elsiocb, 0);
+
+	/* If the node is in the UNUSED state, and we are sending
+	 * a reject, we are done with it.  Release driver reference
+	 * count here.  The outstanding els will release its reference on
+	 * completion and the node can be freed then.
+	 */
+	if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
+		lpfc_nlp_put(ndlp);
+
 	if (rc == IOCB_ERROR) {
 		lpfc_els_free_iocb(phba, elsiocb);
 		return 1;
@@ -2423,13 +2389,12 @@
 	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */
 
 	/* Xmit ADISC ACC response tag <ulpIoTag> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0130 Xmit ADISC ACC response iotag x%x xri: "
-			"x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n",
-			phba->brd_no, vport->vpi, elsiocb->iotag,
-			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
-			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0130 Xmit ADISC ACC response iotag x%x xri: "
+			 "x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n",
+			 elsiocb->iotag, elsiocb->iocb.ulpContext,
+			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+			 ndlp->nlp_rpi);
 	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
 	*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
@@ -2483,15 +2448,13 @@
 	icmd = &elsiocb->iocb;
 	oldcmd = &oldiocb->iocb;
 	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */
-
 	/* Xmit PRLI ACC response tag <ulpIoTag> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0131 Xmit PRLI ACC response tag x%x xri x%x, "
-			"did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
-			phba->brd_no, vport->vpi, elsiocb->iotag,
-			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
-			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0131 Xmit PRLI ACC response tag x%x xri x%x, "
+			 "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+			 elsiocb->iotag, elsiocb->iocb.ulpContext,
+			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+			 ndlp->nlp_rpi);
 	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
 	*((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK));
@@ -2565,16 +2528,11 @@
 	icmd = &elsiocb->iocb;
 	oldcmd = &oldiocb->iocb;
 	icmd->ulpContext = oldcmd->ulpContext;	/* Xri */
-
 	/* Xmit RNID ACC response tag <ulpIoTag> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0132 Xmit RNID ACC response tag x%x "
-			"xri x%x\n",
-			phba->brd_no, vport->vpi, elsiocb->iotag,
-			elsiocb->iocb.ulpContext);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0132 Xmit RNID ACC response tag x%x xri x%x\n",
+			 elsiocb->iotag, elsiocb->iocb.ulpContext);
 	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
-
 	*((uint32_t *) (pcmd)) = ELS_CMD_ACC;
 	pcmd += sizeof(uint32_t);
 
@@ -2641,7 +2599,7 @@
 			sentadisc++;
 			vport->num_disc_nodes++;
 			if (vport->num_disc_nodes >=
-			    vport->phba->cfg_discovery_threads) {
+			    vport->cfg_discovery_threads) {
 				spin_lock_irq(shost->host_lock);
 				vport->fc_flag |= FC_NLP_MORE;
 				spin_unlock_irq(shost->host_lock);
@@ -2676,7 +2634,7 @@
 			sentplogi++;
 			vport->num_disc_nodes++;
 			if (vport->num_disc_nodes >=
-			    vport->phba->cfg_discovery_threads) {
+			    vport->cfg_discovery_threads) {
 				spin_lock_irq(shost->host_lock);
 				vport->fc_flag |= FC_NLP_MORE;
 				spin_unlock_irq(shost->host_lock);
@@ -2717,7 +2675,6 @@
 	D_ID rscn_did;
 	uint32_t *lp;
 	uint32_t payload_len, i;
-	struct lpfc_hba *phba = vport->phba;
 
 	ns_did.un.word = did;
 
@@ -2752,12 +2709,10 @@
 				break;
 			default:
 				/* Unknown Identifier in RSCN node */
-				lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-						"%d (%d):0217 Unknown "
-						"Identifier in RSCN payload "
-						"Data: x%x\n",
-						phba->brd_no, vport->vpi,
-						rscn_did.un.word);
+				lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+						 "0217 Unknown Identifier in "
+						 "RSCN payload Data: x%x\n",
+						 rscn_did.un.word);
 			case 3:	/* Whole Fabric effected */
 				return did;
 			}
@@ -2796,12 +2751,11 @@
 
 static int
 lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
-		  struct lpfc_nodelist *ndlp, uint8_t newnode)
+		  struct lpfc_nodelist *ndlp)
 {
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_hba  *phba = vport->phba;
 	struct lpfc_dmabuf *pcmd;
-	struct lpfc_vport *next_vport;
 	uint32_t *lp, *datap;
 	IOCB_t *icmd;
 	uint32_t payload_len, length, nportid, *cmd;
@@ -2815,13 +2769,10 @@
 
 	payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK);
 	payload_len -= sizeof(uint32_t);	/* take off word 0 */
-
 	/* RSCN received */
-	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			"%d (%d):0214 RSCN received Data: x%x x%x x%x x%x\n",
-			phba->brd_no, vport->vpi, vport->fc_flag, payload_len,
-			*lp, rscn_cnt);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+			 "0214 RSCN received Data: x%x x%x x%x x%x\n",
+			 vport->fc_flag, payload_len, *lp, rscn_cnt);
 	for (i = 0; i < payload_len/sizeof(uint32_t); i++)
 		fc_host_post_event(shost, fc_get_event_number(),
 			FCH_EVT_RSCN, lp[i]);
@@ -2834,8 +2785,7 @@
 			"RCV RSCN ignore: did:x%x/ste:x%x flg:x%x",
 			ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag);
 
-		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
-				 newnode);
+		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
 		return 0;
 	}
 
@@ -2843,7 +2793,7 @@
 	 * just ACC and ignore it.
 	 */
 	if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
-		!(phba->cfg_peer_port_login)) {
+		!(vport->cfg_peer_port_login)) {
 		i = payload_len;
 		datap = lp;
 		while (i > 0) {
@@ -2851,28 +2801,23 @@
 			nportid = ((be32_to_cpu(nportid)) & Mask_DID);
 			i -= sizeof(uint32_t);
 			rscn_id++;
-			list_for_each_entry(next_vport, &phba->port_list,
-				listentry) {
-				if (nportid == next_vport->fc_myDID) {
-					hba_id++;
-					break;
-				}
-			}
+			if (lpfc_find_vport_by_did(phba, nportid))
+				hba_id++;
 		}
 		if (rscn_id == hba_id) {
 			/* ALL NPortIDs in RSCN are on HBA */
-			lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			  "%d (%d):0214 Ignore RSCN Data: x%x x%x x%x x%x\n",
-			  phba->brd_no, vport->vpi, vport->fc_flag, payload_len,
-			  *lp, rscn_cnt);
-
+			lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+					 "0214 Ignore RSCN "
+					 "Data: x%x x%x x%x x%x\n",
+					 vport->fc_flag, payload_len,
+					 *lp, rscn_cnt);
 			lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
 				"RCV RSCN vport:  did:x%x/ste:x%x flg:x%x",
 				ndlp->nlp_DID, vport->port_state,
 				ndlp->nlp_flag);
 
 			lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb,
-				ndlp, NULL, newnode);
+				ndlp, NULL);
 			return 0;
 		}
 	}
@@ -2911,27 +2856,24 @@
 			}
 
 			/* Deferred RSCN */
-			lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-					"%d (%d):0235 Deferred RSCN "
-					"Data: x%x x%x x%x\n",
-					phba->brd_no, vport->vpi,
-					vport->fc_rscn_id_cnt, vport->fc_flag,
-					vport->port_state);
+			lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+					 "0235 Deferred RSCN "
+					 "Data: x%x x%x x%x\n",
+					 vport->fc_rscn_id_cnt, vport->fc_flag,
+					 vport->port_state);
 		} else {
 			spin_lock_irq(shost->host_lock);
 			vport->fc_flag |= FC_RSCN_DISCOVERY;
 			spin_unlock_irq(shost->host_lock);
 			/* ReDiscovery RSCN */
-			lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-					"%d (%d):0234 ReDiscovery RSCN "
-					"Data: x%x x%x x%x\n",
-					phba->brd_no, vport->vpi,
-					vport->fc_rscn_id_cnt, vport->fc_flag,
-					vport->port_state);
+			lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+					 "0234 ReDiscovery RSCN "
+					 "Data: x%x x%x x%x\n",
+					 vport->fc_rscn_id_cnt, vport->fc_flag,
+					 vport->port_state);
 		}
 		/* Send back ACC */
-		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL,
-								newnode);
+		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
 
 		/* send RECOVERY event for ALL nodes that match RSCN payload */
 		lpfc_rscn_recovery_check(vport);
@@ -2956,7 +2898,7 @@
 	lpfc_set_disctmo(vport);
 
 	/* Send back ACC */
-	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, newnode);
+	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
 
 	/* send RECOVERY event for ALL nodes that match RSCN payload */
 	lpfc_rscn_recovery_check(vport);
@@ -2980,11 +2922,10 @@
 	lpfc_set_disctmo(vport);
 
 	/* RSCN processed */
-	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			"%d (%d):0215 RSCN processed Data: x%x x%x x%x x%x\n",
-			phba->brd_no, vport->vpi,
-			vport->fc_flag, 0, vport->fc_rscn_id_cnt,
-			vport->port_state);
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+			 "0215 RSCN processed Data: x%x x%x x%x x%x\n",
+			 vport->fc_flag, 0, vport->fc_rscn_id_cnt,
+			 vport->port_state);
 
 	/* To process RSCN, first compare RSCN data with NameServer */
 	vport->fc_ns_retry = 0;
@@ -3026,7 +2967,7 @@
 
 static int
 lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
-		   struct lpfc_nodelist *ndlp, uint8_t newnode)
+		   struct lpfc_nodelist *ndlp)
 {
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 	struct lpfc_hba  *phba = vport->phba;
@@ -3052,10 +2993,10 @@
 
 		/* An FLOGI ELS command <elsCmd> was received from DID <did> in
 		   Loop Mode */
-		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-				"%d (%d):0113 An FLOGI ELS command x%x was "
-				"received from DID x%x in Loop Mode\n",
-				phba->brd_no, vport->vpi, cmd, did);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				 "0113 An FLOGI ELS command x%x was "
+				 "received from DID x%x in Loop Mode\n",
+				 cmd, did);
 		return 1;
 	}
 
@@ -3109,7 +3050,7 @@
 	}
 
 	/* Send back ACC */
-	lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, newnode);
+	lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
 
 	return 0;
 }
@@ -3226,16 +3167,13 @@
 	rps_rsp->primSeqErrCnt = be32_to_cpu(mb->un.varRdLnk.primSeqErrCnt);
 	rps_rsp->invalidXmitWord = be32_to_cpu(mb->un.varRdLnk.invalidXmitWord);
 	rps_rsp->crcCnt = be32_to_cpu(mb->un.varRdLnk.crcCnt);
-
 	/* Xmit ELS RPS ACC response tag <ulpIoTag> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0118 Xmit ELS RPS ACC response tag x%x "
-			"xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
-			"rpi x%x\n",
-			phba->brd_no, ndlp->vport->vpi, elsiocb->iotag,
-			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
-			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
-
+	lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS,
+			 "0118 Xmit ELS RPS ACC response tag x%x xri x%x, "
+			 "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n",
+			 elsiocb->iotag, elsiocb->iocb.ulpContext,
+			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+			 ndlp->nlp_rpi);
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
 	phba->fc_stat.elsXmitACC++;
 	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR)
@@ -3337,21 +3275,16 @@
 	rpl_rsp.port_num_blk.portID = be32_to_cpu(vport->fc_myDID);
 	memcpy(&rpl_rsp.port_num_blk.portName, &vport->fc_portname,
 	    sizeof(struct lpfc_name));
-
 	memcpy(pcmd, &rpl_rsp, cmdsize - sizeof(uint32_t));
-
-
 	/* Xmit ELS RPL ACC response tag <ulpIoTag> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0120 Xmit ELS RPL ACC response tag x%x "
-			"xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
-			"rpi x%x\n",
-			phba->brd_no, vport->vpi, elsiocb->iotag,
-			elsiocb->iocb.ulpContext, ndlp->nlp_DID,
-			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0120 Xmit ELS RPL ACC response tag x%x "
+			 "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, "
+			 "rpi x%x\n",
+			 elsiocb->iotag, elsiocb->iocb.ulpContext,
+			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+			 ndlp->nlp_rpi);
 	elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp;
-
 	phba->fc_stat.elsXmitACC++;
 	if (lpfc_sli_issue_iocb(phba, pring, elsiocb, 0) == IOCB_ERROR) {
 		lpfc_els_free_iocb(phba, elsiocb);
@@ -3404,7 +3337,6 @@
 lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
 		  struct lpfc_nodelist *ndlp)
 {
-	struct lpfc_hba *phba = vport->phba;
 	struct lpfc_dmabuf *pcmd;
 	uint32_t *lp;
 	IOCB_t *icmd;
@@ -3418,12 +3350,9 @@
 
 	cmd = *lp++;
 	fp = (FARP *) lp;
-
 	/* FARP-REQ received from DID <did> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0601 FARP-REQ received from DID x%x\n",
-			phba->brd_no, vport->vpi, did);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0601 FARP-REQ received from DID x%x\n", did);
 	/* We will only support match on WWPN or WWNN */
 	if (fp->Mflags & ~(FARP_MATCH_NODE | FARP_MATCH_PORT)) {
 		return 0;
@@ -3471,7 +3400,6 @@
 	uint32_t *lp;
 	IOCB_t *icmd;
 	uint32_t cmd, did;
-	struct lpfc_hba *phba = vport->phba;
 
 	icmd = &cmdiocb->iocb;
 	did = icmd->un.elsreq64.remoteID;
@@ -3480,11 +3408,10 @@
 
 	cmd = *lp++;
 	/* FARP-RSP received from DID <did> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0600 FARP-RSP received from DID x%x\n",
-			phba->brd_no, vport->vpi, did);
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0600 FARP-RSP received from DID x%x\n", did);
 	/* ACCEPT the Farp resp request */
-	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
 
 	return 0;
 }
@@ -3502,10 +3429,8 @@
 	struct lpfc_hba *phba = vport->phba;
 
 	/* FAN received */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0265 FAN received\n",
-			phba->brd_no, vport->vpi);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0265 FAN received\n");
 	icmd = &cmdiocb->iocb;
 	did = icmd->un.elsreq64.remoteID;
 	pcmd = (struct lpfc_dmabuf *)cmdiocb->context2;
@@ -3664,13 +3589,10 @@
 			if (ndlp)
 				remote_ID = ndlp->nlp_DID;
 		}
-
-		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-				"%d (%d):0127 ELS timeout Data: x%x x%x x%x "
-				"x%x\n",
-				phba->brd_no, vport->vpi, els_command,
-				remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
-
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				 "0127 ELS timeout Data: x%x x%x x%x "
+				 "x%x\n", els_command,
+				 remote_ID, cmd->ulpCommand, cmd->ulpIoTag);
 		lpfc_sli_issue_abort_iotag(phba, pring, piocb);
 	}
 	spin_unlock_irq(&phba->hbalock);
@@ -3741,6 +3663,50 @@
 	return;
 }
 
+void
+lpfc_els_flush_all_cmd(struct lpfc_hba  *phba)
+{
+	LIST_HEAD(completions);
+	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
+	struct lpfc_iocbq *tmp_iocb, *piocb;
+	IOCB_t *cmd = NULL;
+
+	lpfc_fabric_abort_hba(phba);
+	spin_lock_irq(&phba->hbalock);
+	list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) {
+		cmd = &piocb->iocb;
+		if (piocb->iocb_flag & LPFC_IO_LIBDFC)
+			continue;
+		/* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */
+		if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
+		    cmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
+		    cmd->ulpCommand == CMD_CLOSE_XRI_CN ||
+		    cmd->ulpCommand == CMD_ABORT_XRI_CN)
+			continue;
+		list_move_tail(&piocb->list, &completions);
+		pring->txq_cnt--;
+	}
+	list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) {
+		if (piocb->iocb_flag & LPFC_IO_LIBDFC)
+			continue;
+		lpfc_sli_issue_abort_iotag(phba, pring, piocb);
+	}
+	spin_unlock_irq(&phba->hbalock);
+	while (!list_empty(&completions)) {
+		piocb = list_get_first(&completions, struct lpfc_iocbq, list);
+		cmd = &piocb->iocb;
+		list_del_init(&piocb->list);
+		if (!piocb->iocb_cmpl)
+			lpfc_sli_release_iocbq(phba, piocb);
+		else {
+			cmd->ulpStatus = IOSTAT_LOCAL_REJECT;
+			cmd->un.ulpWord[4] = IOERR_SLI_ABORTED;
+			(piocb->iocb_cmpl) (phba, piocb, piocb);
+		}
+	}
+	return;
+}
+
 static void
 lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 		      struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb)
@@ -3801,11 +3767,9 @@
 		cmd &= ELS_CMD_MASK;
 	}
 	/* ELS command <elsCmd> received from NPORT <did> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0112 ELS command x%x received from NPORT x%x "
-			"Data: x%x\n", phba->brd_no, vport->vpi, cmd, did,
-			vport->port_state);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0112 ELS command x%x received from NPORT x%x "
+			 "Data: x%x\n", cmd, did, vport->port_state);
 	switch (cmd) {
 	case ELS_CMD_PLOGI:
 		lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL,
@@ -3829,7 +3793,7 @@
 			did, vport->port_state, ndlp->nlp_flag);
 
 		phba->fc_stat.elsRcvFLOGI++;
-		lpfc_els_rcv_flogi(vport, elsiocb, ndlp, newnode);
+		lpfc_els_rcv_flogi(vport, elsiocb, ndlp);
 		if (newnode)
 			lpfc_drop_node(vport, ndlp);
 		break;
@@ -3859,7 +3823,7 @@
 		break;
 	case ELS_CMD_RSCN:
 		phba->fc_stat.elsRcvRSCN++;
-		lpfc_els_rcv_rscn(vport, elsiocb, ndlp, newnode);
+		lpfc_els_rcv_rscn(vport, elsiocb, ndlp);
 		if (newnode)
 			lpfc_drop_node(vport, ndlp);
 		break;
@@ -3974,10 +3938,9 @@
 		rjt_err = LSRJT_INVALID_CMD;
 
 		/* Unknown ELS command <elsCmd> received from NPORT <did> */
-		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-				"%d (%d):0115 Unknown ELS command x%x "
-				"received from NPORT x%x\n",
-				phba->brd_no, vport->vpi, cmd, did);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				 "0115 Unknown ELS command x%x "
+				 "received from NPORT x%x\n", cmd, did);
 		if (newnode)
 			lpfc_drop_node(vport, ndlp);
 		break;
@@ -3990,19 +3953,16 @@
 		stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
 		lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp,
 			NULL);
-		if (newnode)
-			lpfc_drop_node(vport, ndlp);
 	}
 
 	return;
 
 dropit:
 	lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-			"%d (%d):0111 Dropping received ELS cmd "
+			"(%d):0111 Dropping received ELS cmd "
 			"Data: x%x x%x x%x\n",
-			phba->brd_no, vport ? vport->vpi : 0xffff,
-			icmd->ulpStatus, icmd->un.ulpWord[4],
-			icmd->ulpTimeout);
+			vport ? vport->vpi : 0xffff, icmd->ulpStatus,
+			icmd->un.ulpWord[4], icmd->ulpTimeout);
 	phba->fc_stat.elsRcvDrop++;
 }
 
@@ -4010,11 +3970,16 @@
 lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi)
 {
 	struct lpfc_vport *vport;
+	unsigned long flags;
 
+	spin_lock_irqsave(&phba->hbalock, flags);
 	list_for_each_entry(vport, &phba->port_list, listentry) {
-		if (vport->vpi == vpi)
+		if (vport->vpi == vpi) {
+			spin_unlock_irqrestore(&phba->hbalock, flags);
 			return vport;
+		}
 	}
+	spin_unlock_irqrestore(&phba->hbalock, flags);
 	return NULL;
 }
 
@@ -4109,9 +4074,8 @@
 				return;
 			}
 			lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-			lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-				"%d (%d):0251 NameServer login: no memory\n",
-				phba->brd_no, vport->vpi);
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+					 "0251 NameServer login: no memory\n");
 			return;
 		}
 		lpfc_nlp_init(vport, ndlp, NameServer_DID);
@@ -4122,13 +4086,12 @@
 
 	if (lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0)) {
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-			"%d (%d):0252 Cannot issue NameServer login\n",
-			phba->brd_no, vport->vpi);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				 "0252 Cannot issue NameServer login\n");
 		return;
 	}
 
-	if (phba->cfg_fdmi_on) {
+	if (vport->cfg_fdmi_on) {
 		ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool,
 					  GFP_KERNEL);
 		if (ndlp_fdmi) {
@@ -4155,9 +4118,9 @@
 	lpfc_nlp_put(ndlp);
 
 	if (mb->mbxStatus) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
-				"%d (%d):0915 Register VPI failed: 0x%x\n",
-				phba->brd_no, vport->vpi, mb->mbxStatus);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+				 "0915 Register VPI failed: 0x%x\n",
+				 mb->mbxStatus);
 
 		switch (mb->mbxStatus) {
 		case 0x11:	/* unsupported feature */
@@ -4206,17 +4169,14 @@
 			vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
 
 			lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-
-			lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
-				"%d (%d):0253 Register VPI: Cannot send mbox\n",
-				phba->brd_no, vport->vpi);
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+				"0253 Register VPI: Can't send mbox\n");
 		}
 	} else {
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 
-		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
-			"%d (%d):0254 Register VPI: no memory\n",
-			phba->brd_no, vport->vpi);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+				 "0254 Register VPI: no memory\n");
 
 		vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
 		lpfc_nlp_put(ndlp);
@@ -4235,11 +4195,10 @@
 	IOCB_t *irsp = &rspiocb->iocb;
 	struct lpfc_iocbq *piocb;
 
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-		"%d (%d):0123 FDISC completes. x%x/x%x prevDID: x%x\n",
-		phba->brd_no, vport->vpi,
-		irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0123 FDISC completes. x%x/x%x prevDID: x%x\n",
+			 irsp->ulpStatus, irsp->un.ulpWord[4],
+			 vport->fc_prevDID);
 	/* Since all FDISCs are being single threaded, we
 	 * must reset the discovery timer for ALL vports
 	 * waiting to send FDISC when one completes.
@@ -4256,13 +4215,10 @@
 		/* Check for retry */
 		if (lpfc_els_retry(phba, cmdiocb, rspiocb))
 			goto out;
-
 		/* FDISC failed */
-		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-			"%d (%d):0124 FDISC failed. (%d/%d)\n",
-			phba->brd_no, vport->vpi,
-			irsp->ulpStatus, irsp->un.ulpWord[4]);
-
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				 "0124 FDISC failed. (%d/%d)\n",
+				 irsp->ulpStatus, irsp->un.ulpWord[4]);
 		if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING)
 			lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 
@@ -4328,10 +4284,8 @@
 				     ELS_CMD_FDISC);
 	if (!elsiocb) {
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-
-		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-			"%d (%d):0255 Issue FDISC: no IOCB\n",
-			phba->brd_no, vport->vpi);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				 "0255 Issue FDISC: no IOCB\n");
 		return 1;
 	}
 
@@ -4377,11 +4331,8 @@
 	if (rc == IOCB_ERROR) {
 		lpfc_els_free_iocb(phba, elsiocb);
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-
-		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-			"%d (%d):0256 Issue FDISC: Cannot send IOCB\n",
-			phba->brd_no, vport->vpi);
-
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				 "0256 Issue FDISC: Cannot send IOCB\n");
 		return 1;
 	}
 	lpfc_vport_set_state(vport, FC_VPORT_INITIALIZING);
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index f2f4639..c81c2b3 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -83,10 +83,17 @@
 		ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag);
 
 	if (ndlp->nlp_sid != NLP_NO_SID) {
-		lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
-			ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
+		lpfc_sli_abort_iocb(ndlp->vport,
+			&phba->sli.ring[phba->sli.fcp_ring],
+			ndlp->nlp_sid, 0, LPFC_CTX_TGT);
 	}
 
+	/*
+	 * A device is normally blocked for rediscovery and unblocked when
+	 * devloss timeout happens.  In case a vport is removed or driver
+	 * unloaded before devloss timeout happens, we need to unblock here.
+	 */
+	scsi_target_unblock(&rport->dev);
 	return;
 }
 
@@ -194,32 +201,30 @@
 	if (ndlp->nlp_sid != NLP_NO_SID) {
 		warn_on = 1;
 		/* flush the target */
-		lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
-				    ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
+		lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring],
+				    ndlp->nlp_sid, 0, LPFC_CTX_TGT);
 	}
 	if (vport->load_flag & FC_UNLOADING)
 		warn_on = 0;
 
 	if (warn_on) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-				"%d (%d):0203 Devloss timeout on "
-				"WWPN %x:%x:%x:%x:%x:%x:%x:%x "
-				"NPort x%x Data: x%x x%x x%x\n",
-				phba->brd_no, vport->vpi,
-				*name, *(name+1), *(name+2), *(name+3),
-				*(name+4), *(name+5), *(name+6), *(name+7),
-				ndlp->nlp_DID, ndlp->nlp_flag,
-				ndlp->nlp_state, ndlp->nlp_rpi);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+				 "0203 Devloss timeout on "
+				 "WWPN %x:%x:%x:%x:%x:%x:%x:%x "
+				 "NPort x%x Data: x%x x%x x%x\n",
+				 *name, *(name+1), *(name+2), *(name+3),
+				 *(name+4), *(name+5), *(name+6), *(name+7),
+				 ndlp->nlp_DID, ndlp->nlp_flag,
+				 ndlp->nlp_state, ndlp->nlp_rpi);
 	} else {
-		lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-				"%d (%d):0204 Devloss timeout on "
-				"WWPN %x:%x:%x:%x:%x:%x:%x:%x "
-				"NPort x%x Data: x%x x%x x%x\n",
-				phba->brd_no, vport->vpi,
-				*name, *(name+1), *(name+2), *(name+3),
-				*(name+4), *(name+5), *(name+6), *(name+7),
-				ndlp->nlp_DID, ndlp->nlp_flag,
-				ndlp->nlp_state, ndlp->nlp_rpi);
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+				 "0204 Devloss timeout on "
+				 "WWPN %x:%x:%x:%x:%x:%x:%x:%x "
+				 "NPort x%x Data: x%x x%x x%x\n",
+				 *name, *(name+1), *(name+2), *(name+3),
+				 *(name+4), *(name+5), *(name+6), *(name+7),
+				 ndlp->nlp_DID, ndlp->nlp_flag,
+				 ndlp->nlp_state, ndlp->nlp_rpi);
 	}
 
 	if (!(vport->load_flag & FC_UNLOADING) &&
@@ -344,12 +349,14 @@
 
 }
 
-void
+static void
 lpfc_work_done(struct lpfc_hba *phba)
 {
 	struct lpfc_sli_ring *pring;
 	uint32_t ha_copy, status, control, work_port_events;
+	struct lpfc_vport **vports;
 	struct lpfc_vport *vport;
+	int i;
 
 	spin_lock_irq(&phba->hbalock);
 	ha_copy = phba->work_ha;
@@ -364,48 +371,41 @@
 
 	if (ha_copy & HA_LATT)
 		lpfc_handle_latt(phba);
-
-	spin_lock_irq(&phba->hbalock);
-	list_for_each_entry(vport, &phba->port_list, listentry) {
-		struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
-
-		if (!scsi_host_get(shost)) {
-			continue;
+	vports = lpfc_create_vport_work_array(phba);
+	if (vports != NULL)
+		for(i = 0; i < LPFC_MAX_VPORTS; i++) {
+			/*
+			 * We could have no vports in array if unloading, so if
+			 * this happens then just use the pport
+			 */
+			if (vports[i] == NULL && i == 0)
+				vport = phba->pport;
+			else
+				vport = vports[i];
+			if (vport == NULL)
+				break;
+			work_port_events = vport->work_port_events;
+			if (work_port_events & WORKER_DISC_TMO)
+				lpfc_disc_timeout_handler(vport);
+			if (work_port_events & WORKER_ELS_TMO)
+				lpfc_els_timeout_handler(vport);
+			if (work_port_events & WORKER_HB_TMO)
+				lpfc_hb_timeout_handler(phba);
+			if (work_port_events & WORKER_MBOX_TMO)
+				lpfc_mbox_timeout_handler(phba);
+			if (work_port_events & WORKER_FABRIC_BLOCK_TMO)
+				lpfc_unblock_fabric_iocbs(phba);
+			if (work_port_events & WORKER_FDMI_TMO)
+				lpfc_fdmi_timeout_handler(vport);
+			if (work_port_events & WORKER_RAMP_DOWN_QUEUE)
+				lpfc_ramp_down_queue_handler(phba);
+			if (work_port_events & WORKER_RAMP_UP_QUEUE)
+				lpfc_ramp_up_queue_handler(phba);
+			spin_lock_irq(&vport->work_port_lock);
+			vport->work_port_events &= ~work_port_events;
+			spin_unlock_irq(&vport->work_port_lock);
 		}
-		spin_unlock_irq(&phba->hbalock);
-		work_port_events = vport->work_port_events;
-
-		if (work_port_events & WORKER_DISC_TMO)
-			lpfc_disc_timeout_handler(vport);
-
-		if (work_port_events & WORKER_ELS_TMO)
-			lpfc_els_timeout_handler(vport);
-
-		if (work_port_events & WORKER_HB_TMO)
-			lpfc_hb_timeout_handler(phba);
-
-		if (work_port_events & WORKER_MBOX_TMO)
-			lpfc_mbox_timeout_handler(phba);
-
-		if (work_port_events & WORKER_FABRIC_BLOCK_TMO)
-			lpfc_unblock_fabric_iocbs(phba);
-
-		if (work_port_events & WORKER_FDMI_TMO)
-			lpfc_fdmi_timeout_handler(vport);
-
-		if (work_port_events & WORKER_RAMP_DOWN_QUEUE)
-			lpfc_ramp_down_queue_handler(phba);
-
-		if (work_port_events & WORKER_RAMP_UP_QUEUE)
-			lpfc_ramp_up_queue_handler(phba);
-
-		spin_lock_irq(&vport->work_port_lock);
-		vport->work_port_events &= ~work_port_events;
-		spin_unlock_irq(&vport->work_port_lock);
-		scsi_host_put(shost);
-		spin_lock_irq(&phba->hbalock);
-	}
-	spin_unlock_irq(&phba->hbalock);
+	lpfc_destroy_vport_work_array(vports);
 
 	pring = &phba->sli.ring[LPFC_ELS_RING];
 	status = (ha_copy & (HA_RXMASK  << (4*LPFC_ELS_RING)));
@@ -426,10 +426,19 @@
 		spin_lock_irq(&phba->hbalock);
 		control = readl(phba->HCregaddr);
 		if (!(control & (HC_R0INT_ENA << LPFC_ELS_RING))) {
+			lpfc_debugfs_slow_ring_trc(phba,
+				"WRK Enable ring: cntl:x%x hacopy:x%x",
+				control, ha_copy, 0);
+
 			control |= (HC_R0INT_ENA << LPFC_ELS_RING);
 			writel(control, phba->HCregaddr);
 			readl(phba->HCregaddr); /* flush */
 		}
+		else {
+			lpfc_debugfs_slow_ring_trc(phba,
+				"WRK Ring ok:     cntl:x%x hacopy:x%x",
+				control, ha_copy, 0);
+		}
 		spin_unlock_irq(&phba->hbalock);
 	}
 	lpfc_work_list_done(phba);
@@ -439,32 +448,22 @@
 check_work_wait_done(struct lpfc_hba *phba)
 {
 	struct lpfc_vport *vport;
-	struct lpfc_sli_ring *pring;
+	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
 	int rc = 0;
 
 	spin_lock_irq(&phba->hbalock);
 	list_for_each_entry(vport, &phba->port_list, listentry) {
 		if (vport->work_port_events) {
 			rc = 1;
-			goto exit;
+			break;
 		}
 	}
-
-	if (phba->work_ha || (!list_empty(&phba->work_list)) ||
-	    kthread_should_stop()) {
+	if (rc || phba->work_ha || (!list_empty(&phba->work_list)) ||
+	    kthread_should_stop() || pring->flag & LPFC_DEFERRED_RING_EVENT) {
 		rc = 1;
-		goto exit;
-	}
-
-	pring = &phba->sli.ring[LPFC_ELS_RING];
-	if (pring->flag & LPFC_DEFERRED_RING_EVENT)
-		rc = 1;
-exit:
-	if (rc)
 		phba->work_found++;
-	else
+	} else
 		phba->work_found = 0;
-
 	spin_unlock_irq(&phba->hbalock);
 	return rc;
 }
@@ -592,7 +591,6 @@
 
 	/* free any ndlp's on unused list */
 	list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp)
-				/* free any ndlp's in unused state */
 		if (ndlp->nlp_state == NLP_STE_UNUSED_NODE)
 			lpfc_drop_node(vport, ndlp);
 
@@ -605,8 +603,9 @@
 {
 	struct lpfc_vport *vport = phba->pport;
 	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
-	struct lpfc_vport *port_iterator;
+	struct lpfc_vport **vports;
 	LPFC_MBOXQ_t          *mb;
+	int i;
 
 	if (phba->link_state == LPFC_LINK_DOWN) {
 		return 0;
@@ -617,13 +616,13 @@
 		phba->pport->fc_flag &= ~FC_LBIT;
 	}
 	spin_unlock_irq(&phba->hbalock);
-
-	list_for_each_entry(port_iterator, &phba->port_list, listentry) {
-
-				/* Issue a LINK DOWN event to all nodes */
-		lpfc_linkdown_port(port_iterator);
-	}
-
+	vports = lpfc_create_vport_work_array(phba);
+	if (vports != NULL)
+		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+			/* Issue a LINK DOWN event to all nodes */
+			lpfc_linkdown_port(vports[i]);
+		}
+	lpfc_destroy_vport_work_array(vports);
 	/* Clean up any firmware default rpi's */
 	mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (mb) {
@@ -724,7 +723,8 @@
 static int
 lpfc_linkup(struct lpfc_hba *phba)
 {
-	struct lpfc_vport *vport;
+	struct lpfc_vport **vports;
+	int i;
 
 	phba->link_state = LPFC_LINK_UP;
 
@@ -732,9 +732,11 @@
 	clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags);
 	del_timer_sync(&phba->fabric_block_timer);
 
-	list_for_each_entry(vport, &phba->port_list, listentry) {
-		lpfc_linkup_port(vport);
-	}
+	vports = lpfc_create_vport_work_array(phba);
+	if (vports != NULL)
+		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++)
+			lpfc_linkup_port(vports[i]);
+	lpfc_destroy_vport_work_array(vports);
 	if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
 		lpfc_issue_clear_la(phba, phba->pport);
 
@@ -764,12 +766,10 @@
 	/* Check for error */
 	if ((mb->mbxStatus) && (mb->mbxStatus != 0x1601)) {
 		/* CLEAR_LA mbox error <mbxStatus> state <hba_state> */
-		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
-				"%d (%d):0320 CLEAR_LA mbxStatus error x%x hba "
-				"state x%x\n",
-				phba->brd_no, vport->vpi, mb->mbxStatus,
-				vport->port_state);
-
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+				 "0320 CLEAR_LA mbxStatus error x%x hba "
+				 "state x%x\n",
+				 mb->mbxStatus, vport->port_state);
 		phba->link_state = LPFC_HBA_ERROR;
 		goto out;
 	}
@@ -801,10 +801,8 @@
 
 out:
 	/* Device Discovery completes */
-	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			"%d (%d):0225 Device Discovery completes\n",
-			phba->brd_no, vport->vpi);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+			 "0225 Device Discovery completes\n");
 	mempool_free(pmb, phba->mbox_mem_pool);
 
 	spin_lock_irq(shost->host_lock);
@@ -861,19 +859,17 @@
 	return;
 
 out:
-	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
-			"%d (%d):0306 CONFIG_LINK mbxStatus error x%x "
-			"HBA state x%x\n",
-			phba->brd_no, vport->vpi, pmb->mb.mbxStatus,
-			vport->port_state);
-
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+			 "0306 CONFIG_LINK mbxStatus error x%x "
+			 "HBA state x%x\n",
+			 pmb->mb.mbxStatus, vport->port_state);
 	mempool_free(pmb, phba->mbox_mem_pool);
 
 	lpfc_linkdown(phba);
 
-	lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-			"%d (%d):0200 CONFIG_LINK bad hba state x%x\n",
-			phba->brd_no, vport->vpi, vport->port_state);
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+			 "0200 CONFIG_LINK bad hba state x%x\n",
+			 vport->port_state);
 
 	lpfc_issue_clear_la(phba, vport);
 	return;
@@ -890,12 +886,10 @@
 	/* Check for error */
 	if (mb->mbxStatus) {
 		/* READ_SPARAM mbox error <mbxStatus> state <hba_state> */
-		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
-				"%d (%d):0319 READ_SPARAM mbxStatus error x%x "
-				"hba state x%x>\n",
-				phba->brd_no, vport->vpi, mb->mbxStatus,
-				vport->port_state);
-
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+				 "0319 READ_SPARAM mbxStatus error x%x "
+				 "hba state x%x>\n",
+				 mb->mbxStatus, vport->port_state);
 		lpfc_linkdown(phba);
 		goto out;
 	}
@@ -978,7 +972,7 @@
 		if (i == 0) {
 			phba->alpa_map[0] = 0;
 		} else {
-			if (phba->cfg_log_verbose & LOG_LINK_EVENT) {
+			if (vport->cfg_log_verbose & LOG_LINK_EVENT) {
 				int numalpa, j, k;
 				union {
 					uint8_t pamap[16];
@@ -1004,10 +998,9 @@
 					lpfc_printf_log(phba,
 							KERN_WARNING,
 							LOG_LINK_EVENT,
-							"%d:1304 Link Up Event "
+							"1304 Link Up Event "
 							"ALPA map Data: x%x "
 							"x%x x%x x%x\n",
-							phba->brd_no,
 							un.pa.wd1, un.pa.wd2,
 							un.pa.wd3, un.pa.wd4);
 				}
@@ -1015,7 +1008,7 @@
 		}
 	} else {
 		if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
-			if (phba->max_vpi && phba->cfg_npiv_enable &&
+			if (phba->max_vpi && phba->cfg_enable_npiv &&
 			   (phba->sli_rev == 3))
 				phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED;
 		}
@@ -1055,11 +1048,9 @@
 	}
 out:
 	lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
-		"%d (%d):0263 Discovery Mailbox error: state: 0x%x : %p %p\n",
-		phba->brd_no, vport->vpi,
-		vport->port_state, sparam_mbox, cfglink_mbox);
-
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+			 "0263 Discovery Mailbox error: state: 0x%x : %p %p\n",
+			 vport->port_state, sparam_mbox, cfglink_mbox);
 	lpfc_issue_clear_la(phba, vport);
 	return;
 }
@@ -1100,8 +1091,8 @@
 	/* Check for error */
 	if (mb->mbxStatus) {
 		lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
-				"%d:1307 READ_LA mbox error x%x state x%x\n",
-				phba->brd_no, mb->mbxStatus, vport->port_state);
+				"1307 READ_LA mbox error x%x state x%x\n",
+				mb->mbxStatus, vport->port_state);
 		lpfc_mbx_issue_link_down(phba);
 		phba->link_state = LPFC_HBA_ERROR;
 		goto lpfc_mbx_cmpl_read_la_free_mbuf;
@@ -1132,26 +1123,26 @@
 		phba->fc_stat.LinkUp++;
 		if (phba->link_flag & LS_LOOPBACK_MODE) {
 			lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
-				"%d:1306 Link Up Event in loop back mode "
-				"x%x received Data: x%x x%x x%x x%x\n",
-				phba->brd_no, la->eventTag, phba->fc_eventTag,
-				la->granted_AL_PA, la->UlnkSpeed,
-				phba->alpa_map[0]);
+					"1306 Link Up Event in loop back mode "
+					"x%x received Data: x%x x%x x%x x%x\n",
+					la->eventTag, phba->fc_eventTag,
+					la->granted_AL_PA, la->UlnkSpeed,
+					phba->alpa_map[0]);
 		} else {
 			lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
-				"%d:1303 Link Up Event x%x received "
-				"Data: x%x x%x x%x x%x\n",
-				phba->brd_no, la->eventTag, phba->fc_eventTag,
-				la->granted_AL_PA, la->UlnkSpeed,
-				phba->alpa_map[0]);
+					"1303 Link Up Event x%x received "
+					"Data: x%x x%x x%x x%x\n",
+					la->eventTag, phba->fc_eventTag,
+					la->granted_AL_PA, la->UlnkSpeed,
+					phba->alpa_map[0]);
 		}
 		lpfc_mbx_process_link_up(phba, la);
 	} else {
 		phba->fc_stat.LinkDown++;
 		lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
-				"%d:1305 Link Down Event x%x received "
+				"1305 Link Down Event x%x received "
 				"Data: x%x x%x x%x\n",
-				phba->brd_no, la->eventTag, phba->fc_eventTag,
+				la->eventTag, phba->fc_eventTag,
 				phba->pport->port_state, vport->fc_flag);
 		lpfc_mbx_issue_link_down(phba);
 	}
@@ -1199,10 +1190,9 @@
 	case 0x0011:
 	case 0x0020:
 	case 0x9700:
-		lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-				"%d (%d):0911 cmpl_unreg_vpi, "
-				"mb status = 0x%x\n",
-				phba->brd_no, vport->vpi, mb->mbxStatus);
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+				 "0911 cmpl_unreg_vpi, mb status = 0x%x\n",
+				 mb->mbxStatus);
 		break;
 	}
 	vport->unreg_vpi_cmpl = VPORT_OK;
@@ -1231,9 +1221,8 @@
 	mbox->mbox_cmpl = lpfc_mbx_cmpl_unreg_vpi;
 	rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB));
 	if (rc == MBX_NOT_FINISHED) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_VPORT,
-				"%d (%d):1800 Could not issue unreg_vpi\n",
-				phba->brd_no, vport->vpi);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT,
+				 "1800 Could not issue unreg_vpi\n");
 		mempool_free(mbox, phba->mbox_mem_pool);
 		vport->unreg_vpi_cmpl = VPORT_ERROR;
 	}
@@ -1250,9 +1239,9 @@
 	case 0x0011:
 	case 0x9601:
 	case 0x9602:
-		lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-				"%d (%d):0912 cmpl_reg_vpi, mb status = 0x%x\n",
-				phba->brd_no, vport->vpi, mb->mbxStatus);
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+				 "0912 cmpl_reg_vpi, mb status = 0x%x\n",
+				 mb->mbxStatus);
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 		spin_lock_irq(shost->host_lock);
 		vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP);
@@ -1289,15 +1278,15 @@
 lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
 {
 	struct lpfc_vport *vport = pmb->vport;
-	struct lpfc_vport *next_vport;
 	MAILBOX_t *mb = &pmb->mb;
 	struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1);
 	struct lpfc_nodelist *ndlp;
-	ndlp = (struct lpfc_nodelist *) pmb->context2;
+	struct lpfc_vport **vports;
+	int i;
 
+	ndlp = (struct lpfc_nodelist *) pmb->context2;
 	pmb->context1 = NULL;
 	pmb->context2 = NULL;
-
 	if (mb->mbxStatus) {
 		lpfc_mbuf_free(phba, mp->virt, mp->phys);
 		kfree(mp);
@@ -1314,10 +1303,9 @@
 		}
 
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-		lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
-			"%d (%d):0258 Register Fabric login error: 0x%x\n",
-			phba->brd_no, vport->vpi, mb->mbxStatus);
-
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+				 "0258 Register Fabric login error: 0x%x\n",
+				 mb->mbxStatus);
 		return;
 	}
 
@@ -1328,21 +1316,26 @@
 	lpfc_nlp_put(ndlp);	/* Drop the reference from the mbox */
 
 	if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
-		list_for_each_entry(next_vport, &phba->port_list, listentry) {
-			if (next_vport->port_type == LPFC_PHYSICAL_PORT)
-				continue;
-
-			if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
-				lpfc_initial_fdisc(next_vport);
-			else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
-				lpfc_vport_set_state(vport,
-						     FC_VPORT_NO_FABRIC_SUPP);
-				lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-						"%d (%d):0259 No NPIV Fabric "
-						"support\n",
-						phba->brd_no, vport->vpi);
+		vports = lpfc_create_vport_work_array(phba);
+		if (vports != NULL)
+			for(i = 0;
+			    i < LPFC_MAX_VPORTS && vports[i] != NULL;
+			    i++) {
+				if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
+					continue;
+				if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
+					lpfc_initial_fdisc(vports[i]);
+				else if (phba->sli3_options &
+						LPFC_SLI3_NPIV_ENABLED) {
+					lpfc_vport_set_state(vports[i],
+						FC_VPORT_NO_FABRIC_SUPP);
+					lpfc_printf_vlog(vport, KERN_ERR,
+							 LOG_ELS,
+							"0259 No NPIV "
+							"Fabric support\n");
+				}
 			}
-		}
+		lpfc_destroy_vport_work_array(vports);
 		lpfc_do_scr_ns_plogi(phba, vport);
 	}
 
@@ -1386,9 +1379,9 @@
 			return;
 		}
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-			"%d (%d):0260 Register NameServer error: 0x%x\n",
-			phba->brd_no, vport->vpi, mb->mbxStatus);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				 "0260 Register NameServer error: 0x%x\n",
+				 mb->mbxStatus);
 		return;
 	}
 
@@ -1598,7 +1591,7 @@
 		[NLP_STE_NPR_NODE] = "NPR",
 	};
 
-	if (state < ARRAY_SIZE(states) && states[state])
+	if (state < NLP_STE_MAX_STATE && states[state])
 		strlcpy(buffer, states[state], size);
 	else
 		snprintf(buffer, size, "unknown (%d)", state);
@@ -1613,12 +1606,11 @@
 	int  old_state = ndlp->nlp_state;
 	char name1[16], name2[16];
 
-	lpfc_printf_log(vport->phba, KERN_INFO, LOG_NODE,
-			"%d (%d):0904 NPort state transition x%06x, %s -> %s\n",
-			vport->phba->brd_no, vport->vpi,
-			ndlp->nlp_DID,
-			lpfc_nlp_state_name(name1, sizeof(name1), old_state),
-			lpfc_nlp_state_name(name2, sizeof(name2), state));
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+			 "0904 NPort state transition x%06x, %s -> %s\n",
+			 ndlp->nlp_DID,
+			 lpfc_nlp_state_name(name1, sizeof(name1), old_state),
+			 lpfc_nlp_state_name(name2, sizeof(name2), state));
 
 	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE,
 		"node statechg    did:x%x old:%d ste:%d",
@@ -1664,16 +1656,7 @@
 void
 lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 {
-	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-
-	if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0)
-		lpfc_cancel_retry_delay_tmo(vport, ndlp);
-	if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp))
-		lpfc_nlp_counters(vport, ndlp->nlp_state, -1);
-	spin_lock_irq(shost->host_lock);
-	list_del_init(&ndlp->nlp_listp);
-	ndlp->nlp_flag &= ~NLP_TARGET_REMOVE;
-	spin_unlock_irq(shost->host_lock);
+	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
 	lpfc_nlp_put(ndlp);
 }
 
@@ -1710,12 +1693,12 @@
 	spin_unlock_irq(shost->host_lock);
 
 	/* Start Discovery Timer state <hba_state> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			"%d (%d):0247 Start Discovery Timer state x%x "
-			"Data: x%x x%lx x%x x%x\n",
-			phba->brd_no, vport->vpi, vport->port_state, tmo,
-			(unsigned long)&vport->fc_disctmo, vport->fc_plogi_cnt,
-			vport->fc_adisc_cnt);
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+			 "0247 Start Discovery Timer state x%x "
+			 "Data: x%x x%lx x%x x%x\n",
+			 vport->port_state, tmo,
+			 (unsigned long)&vport->fc_disctmo, vport->fc_plogi_cnt,
+			 vport->fc_adisc_cnt);
 
 	return;
 }
@@ -1727,7 +1710,6 @@
 lpfc_can_disctmo(struct lpfc_vport *vport)
 {
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-	struct lpfc_hba  *phba = vport->phba;
 	unsigned long iflags;
 
 	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD,
@@ -1746,13 +1728,11 @@
 	}
 
 	/* Cancel Discovery Timer state <hba_state> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			"%d (%d):0248 Cancel Discovery Timer state x%x "
-			"Data: x%x x%x x%x\n",
-			phba->brd_no, vport->vpi, vport->port_state,
-			vport->fc_flag, vport->fc_plogi_cnt,
-			vport->fc_adisc_cnt);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+			 "0248 Cancel Discovery Timer state x%x "
+			 "Data: x%x x%x x%x\n",
+			 vport->port_state, vport->fc_flag,
+			 vport->fc_plogi_cnt, vport->fc_adisc_cnt);
 	return 0;
 }
 
@@ -1935,10 +1915,9 @@
 		rc = lpfc_sli_issue_mbox(phba, mbox,
 					 (MBX_NOWAIT | MBX_STOP_IOCB));
 		if (rc == MBX_NOT_FINISHED) {
-			lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_VPORT,
-					"%d (%d):1815 Could not issue "
-					"unreg_did (default rpis)\n",
-					phba->brd_no, vport->vpi);
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT,
+					 "1815 Could not issue "
+					 "unreg_did (default rpis)\n");
 			mempool_free(mbox, phba->mbox_mem_pool);
 		}
 	}
@@ -1957,12 +1936,11 @@
 	struct lpfc_dmabuf *mp;
 
 	/* Cleanup node for NPort <nlp_DID> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-			"%d (%d):0900 Cleanup node for NPort x%x "
-			"Data: x%x x%x x%x\n",
-			phba->brd_no, vport->vpi, ndlp->nlp_DID, ndlp->nlp_flag,
-			ndlp->nlp_state, ndlp->nlp_rpi);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+			 "0900 Cleanup node for NPort x%x "
+			 "Data: x%x x%x x%x\n",
+			 ndlp->nlp_DID, ndlp->nlp_flag,
+			 ndlp->nlp_state, ndlp->nlp_rpi);
 	lpfc_dequeue_node(vport, ndlp);
 
 	/* cleanup any ndlp on mbox q waiting for reglogin cmpl */
@@ -2094,7 +2072,6 @@
 static struct lpfc_nodelist *
 __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did)
 {
-	struct lpfc_hba  *phba = vport->phba;
 	struct lpfc_nodelist *ndlp;
 	uint32_t data1;
 
@@ -2104,20 +2081,18 @@
 				 ((uint32_t) ndlp->nlp_xri << 16) |
 				 ((uint32_t) ndlp->nlp_type << 8) |
 				 ((uint32_t) ndlp->nlp_rpi & 0xff));
-			lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-					"%d (%d):0929 FIND node DID "
-					" Data: x%p x%x x%x x%x\n",
-					phba->brd_no, vport->vpi,
-					ndlp, ndlp->nlp_DID,
-					ndlp->nlp_flag, data1);
+			lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+					 "0929 FIND node DID "
+					 "Data: x%p x%x x%x x%x\n",
+					 ndlp, ndlp->nlp_DID,
+					 ndlp->nlp_flag, data1);
 			return ndlp;
 		}
 	}
 
 	/* FIND node did <did> NOT FOUND */
-	lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
-			"%d (%d):0932 FIND node did x%x NOT FOUND.\n",
-			phba->brd_no, vport->vpi, did);
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
+			 "0932 FIND node did x%x NOT FOUND.\n", did);
 	return NULL;
 }
 
@@ -2208,7 +2183,7 @@
 			/* If cfg_scan_down is set, start from highest
 			 * ALPA (0xef) to lowest (0x1).
 			 */
-			if (phba->cfg_scan_down)
+			if (vport->cfg_scan_down)
 				index = j;
 			else
 				index = FC_MAXLOOP - j - 1;
@@ -2309,12 +2284,11 @@
 	vport->num_disc_nodes = 0;
 
 	/* Start Discovery state <hba_state> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			"%d (%d):0202 Start Discovery hba state x%x "
-			"Data: x%x x%x x%x\n",
-			phba->brd_no, vport->vpi, vport->port_state,
-			vport->fc_flag, vport->fc_plogi_cnt,
-			vport->fc_adisc_cnt);
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+			 "0202 Start Discovery hba state x%x "
+			 "Data: x%x x%x x%x\n",
+			 vport->port_state, vport->fc_flag, vport->fc_plogi_cnt,
+			 vport->fc_adisc_cnt);
 
 	/* First do ADISCs - if any */
 	num_sent = lpfc_els_disc_adisc(vport);
@@ -2532,10 +2506,8 @@
 	 * FAN
 	 */
 				/* FAN timeout */
-		lpfc_printf_log(phba, KERN_WARNING, LOG_DISCOVERY,
-				"%d (%d):0221 FAN timeout\n",
-				phba->brd_no, vport->vpi);
-
+		lpfc_printf_vlog(vport, KERN_WARNING, LOG_DISCOVERY,
+				 "0221 FAN timeout\n");
 		/* Start discovery by sending FLOGI, clean up old rpis */
 		list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes,
 					 nlp_listp) {
@@ -2562,10 +2534,9 @@
 	case LPFC_FLOGI:
 	/* port_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */
 		/* Initial FLOGI timeout */
-		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-				"%d (%d):0222 Initial %s timeout\n",
-				phba->brd_no, vport->vpi,
-				vport->vpi ? "FLOGI" : "FDISC");
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+				 "0222 Initial %s timeout\n",
+				 vport->vpi ? "FLOGI" : "FDISC");
 
 		/* Assume no Fabric and go on with discovery.
 		 * Check for outstanding ELS FLOGI to abort.
@@ -2581,11 +2552,9 @@
 	case LPFC_FABRIC_CFG_LINK:
 	/* hba_state is identically LPFC_FABRIC_CFG_LINK while waiting for
 	   NameServer login */
-		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-				"%d (%d):0223 Timeout while waiting for "
-				"NameServer login\n",
-				phba->brd_no, vport->vpi);
-
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+				 "0223 Timeout while waiting for "
+				 "NameServer login\n");
 		/* Next look for NameServer ndlp */
 		ndlp = lpfc_findnode_did(vport, NameServer_DID);
 		if (ndlp)
@@ -2596,11 +2565,10 @@
 
 	case LPFC_NS_QRY:
 	/* Check for wait for NameServer Rsp timeout */
-		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-				"%d (%d):0224 NameServer Query timeout "
-				"Data: x%x x%x\n",
-				phba->brd_no, vport->vpi,
-				vport->fc_ns_retry, LPFC_MAX_NS_RETRY);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+				 "0224 NameServer Query timeout "
+				 "Data: x%x x%x\n",
+				 vport->fc_ns_retry, LPFC_MAX_NS_RETRY);
 
 		if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) {
 			/* Try it one more time */
@@ -2627,10 +2595,9 @@
 		/* Setup and issue mailbox INITIALIZE LINK command */
 		initlinkmbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 		if (!initlinkmbox) {
-			lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-					"%d (%d):0206 Device Discovery "
-					"completion error\n",
-					phba->brd_no, vport->vpi);
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+					 "0206 Device Discovery "
+					 "completion error\n");
 			phba->link_state = LPFC_HBA_ERROR;
 			break;
 		}
@@ -2651,9 +2618,8 @@
 
 	case LPFC_DISC_AUTH:
 	/* Node Authentication timeout */
-		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-				"%d (%d):0227 Node Authentication timeout\n",
-				phba->brd_no, vport->vpi);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+				 "0227 Node Authentication timeout\n");
 		lpfc_disc_flush_list(vport);
 
 		/*
@@ -2670,11 +2636,10 @@
 
 	case LPFC_VPORT_READY:
 		if (vport->fc_flag & FC_RSCN_MODE) {
-			lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-					"%d (%d):0231 RSCN timeout Data: x%x "
-					"x%x\n",
-					phba->brd_no, vport->vpi,
-					vport->fc_ns_retry, LPFC_MAX_NS_RETRY);
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+					 "0231 RSCN timeout Data: x%x "
+					 "x%x\n",
+					 vport->fc_ns_retry, LPFC_MAX_NS_RETRY);
 
 			/* Cleanup any outstanding ELS commands */
 			lpfc_els_flush_cmd(vport);
@@ -2685,20 +2650,17 @@
 		break;
 
 	default:
-		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-				"%d (%d):0229 Unexpected discovery timeout, "
-				"vport State x%x\n",
-				phba->brd_no, vport->vpi, vport->port_state);
-
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+				 "0229 Unexpected discovery timeout, "
+				 "vport State x%x\n", vport->port_state);
 		break;
 	}
 
 	switch (phba->link_state) {
 	case LPFC_CLEAR_LA:
 				/* CLEAR LA timeout */
-		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-				"%d (%d):0228 CLEAR LA timeout\n",
-				phba->brd_no, vport->vpi);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+				 "0228 CLEAR LA timeout\n");
 		clrlaerr = 1;
 		break;
 
@@ -2709,10 +2671,9 @@
 	case LPFC_LINK_DOWN:
 	case LPFC_LINK_UP:
 	case LPFC_HBA_ERROR:
-		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-				"%d (%d):0230 Unexpected timeout, hba link "
-				"state x%x\n",
-				phba->brd_no, vport->vpi, phba->link_state);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+				 "0230 Unexpected timeout, hba link "
+				 "state x%x\n", phba->link_state);
 		clrlaerr = 1;
 		break;
 
@@ -2757,7 +2718,7 @@
 	 * fdmi-on=2 (supporting RPA/hostnmae)
 	 */
 
-	if (phba->cfg_fdmi_on == 1)
+	if (vport->cfg_fdmi_on == 1)
 		lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA);
 	else
 		mod_timer(&vport->fc_fdmitmo, jiffies + HZ * 60);
@@ -2854,32 +2815,6 @@
 }
 
 void
-lpfc_dev_loss_delay(unsigned long ptr)
-{
-	struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) ptr;
-	struct lpfc_vport *vport = ndlp->vport;
-	struct lpfc_hba   *phba = vport->phba;
-	struct lpfc_work_evt  *evtp = &ndlp->dev_loss_evt;
-	unsigned long flags;
-
-	evtp = &ndlp->dev_loss_evt;
-
-	spin_lock_irqsave(&phba->hbalock, flags);
-	if (!list_empty(&evtp->evt_listp)) {
-		spin_unlock_irqrestore(&phba->hbalock, flags);
-		return;
-	}
-
-	evtp->evt_arg1  = ndlp;
-	evtp->evt       = LPFC_EVT_DEV_LOSS_DELAY;
-	list_add_tail(&evtp->evt_listp, &phba->work_list);
-	if (phba->work_wait)
-		lpfc_worker_wake_up(phba);
-	spin_unlock_irqrestore(&phba->hbalock, flags);
-	return;
-}
-
-void
 lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 	      uint32_t did)
 {
@@ -2902,7 +2837,7 @@
 	return;
 }
 
-void
+static void
 lpfc_nlp_release(struct kref *kref)
 {
 	struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist,
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index c2fb59f..451accd 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -150,7 +150,11 @@
 		struct gff_acc {
 			uint8_t fbits[128];
 		} gff_acc;
+#ifdef __BIG_ENDIAN_BITFIELD
+#define FCP_TYPE_FEATURE_OFFSET 7
+#else	/*  __LITTLE_ENDIAN_BITFIELD */
 #define FCP_TYPE_FEATURE_OFFSET 4
+#endif
 		struct rff {
 			uint32_t PortId;
 			uint8_t reserved[2];
@@ -805,7 +809,7 @@
 	} un;
 } RNID;
 
-typedef struct  _RPS {  	/* Structure is in Big Endian format */
+typedef struct  _RPS {		/* Structure is in Big Endian format */
 	union {
 		uint32_t portNum;
 		struct lpfc_name portName;
@@ -823,7 +827,7 @@
 	uint32_t crcCnt;
 } RPS_RSP;
 
-typedef struct  _RPL {  	/* Structure is in Big Endian format */
+typedef struct  _RPL {		/* Structure is in Big Endian format */
 	uint32_t maxsize;
 	uint32_t index;
 } RPL;
@@ -834,7 +838,7 @@
 	struct lpfc_name portName;
 } PORT_NUM_BLK;
 
-typedef struct  _RPL_RSP { 	/* Structure is in Big Endian format */
+typedef struct  _RPL_RSP {	/* Structure is in Big Endian format */
 	uint32_t listLen;
 	uint32_t index;
 	PORT_NUM_BLK port_num_blk;
@@ -2613,8 +2617,8 @@
 	LOAD_SM_VAR varLdSM;		/* cmd =  1 (LOAD_SM)        */
 	READ_NV_VAR varRDnvp;		/* cmd =  2 (READ_NVPARMS)   */
 	WRITE_NV_VAR varWTnvp;		/* cmd =  3 (WRITE_NVPARMS)  */
-	BIU_DIAG_VAR varBIUdiag; 	/* cmd =  4 (RUN_BIU_DIAG)   */
-	INIT_LINK_VAR varInitLnk; 	/* cmd =  5 (INIT_LINK)      */
+	BIU_DIAG_VAR varBIUdiag;	/* cmd =  4 (RUN_BIU_DIAG)   */
+	INIT_LINK_VAR varInitLnk;	/* cmd =  5 (INIT_LINK)      */
 	DOWN_LINK_VAR varDwnLnk;	/* cmd =  6 (DOWN_LINK)      */
 	CONFIG_LINK varCfgLnk;		/* cmd =  7 (CONFIG_LINK)    */
 	PART_SLIM_VAR varSlim;		/* cmd =  8 (PART_SLIM)      */
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index f81f85e..414350a 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -53,8 +53,6 @@
 static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
 static DEFINE_IDR(lpfc_hba_index);
 
-
-
 /************************************************************************/
 /*                                                                      */
 /*    lpfc_config_port_prep                                             */
@@ -107,10 +105,9 @@
 
 		if (rc != MBX_SUCCESS) {
 			lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
-					"%d:0324 Config Port initialization "
+					"0324 Config Port initialization "
 					"error, mbxCmd x%x READ_NVPARM, "
 					"mbxStatus x%x\n",
-					phba->brd_no,
 					mb->mbxCommand, mb->mbxStatus);
 			mempool_free(pmb, phba->mbox_mem_pool);
 			return -ERESTART;
@@ -128,9 +125,8 @@
 	rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
 	if (rc != MBX_SUCCESS) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"%d:0439 Adapter failed to init, mbxCmd x%x "
+				"0439 Adapter failed to init, mbxCmd x%x "
 				"READ_REV, mbxStatus x%x\n",
-				phba->brd_no,
 				mb->mbxCommand, mb->mbxStatus);
 		mempool_free( pmb, phba->mbox_mem_pool);
 		return -ERESTART;
@@ -144,9 +140,8 @@
 	if (mb->un.varRdRev.rr == 0) {
 		vp->rev.rBit = 0;
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"%d:0440 Adapter failed to init, READ_REV has "
-				"missing revision information.\n",
-				phba->brd_no);
+				"0440 Adapter failed to init, READ_REV has "
+				"missing revision information.\n");
 		mempool_free(pmb, phba->mbox_mem_pool);
 		return -ERESTART;
 	}
@@ -197,9 +192,8 @@
 
 		if (rc != MBX_SUCCESS) {
 			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-					"%d:0441 VPD not present on adapter, "
+					"0441 VPD not present on adapter, "
 					"mbxCmd x%x DUMP VPD, mbxStatus x%x\n",
-					phba->brd_no,
 					mb->mbxCommand, mb->mbxStatus);
 			mb->un.varDmp.word_cnt = 0;
 		}
@@ -253,9 +247,8 @@
 	pmb->vport = vport;
 	if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"%d:0448 Adapter failed init, mbxCmd x%x "
+				"0448 Adapter failed init, mbxCmd x%x "
 				"READ_SPARM mbxStatus x%x\n",
-				phba->brd_no,
 				mb->mbxCommand, mb->mbxStatus);
 		phba->link_state = LPFC_HBA_ERROR;
 		mp = (struct lpfc_dmabuf *) pmb->context1;
@@ -312,9 +305,8 @@
 	pmb->vport = vport;
 	if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"%d:0453 Adapter failed to init, mbxCmd x%x "
+				"0453 Adapter failed to init, mbxCmd x%x "
 				"READ_CONFIG, mbxStatus x%x\n",
-				phba->brd_no,
 				mb->mbxCommand, mb->mbxStatus);
 		phba->link_state = LPFC_HBA_ERROR;
 		mempool_free( pmb, phba->mbox_mem_pool);
@@ -344,9 +336,8 @@
 		&& !(phba->lmt & LMT_10Gb))) {
 		/* Reset link speed to auto */
 		lpfc_printf_log(phba, KERN_WARNING, LOG_LINK_EVENT,
-			"%d:1302 Invalid speed for this board: "
+			"1302 Invalid speed for this board: "
 			"Reset link speed to auto: x%x\n",
-			phba->brd_no,
 			phba->cfg_link_speed);
 			phba->cfg_link_speed = LINK_SPEED_AUTO;
 	}
@@ -402,9 +393,8 @@
 	lpfc_set_loopback_flag(phba);
 	if (rc != MBX_SUCCESS) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"%d:0454 Adapter failed to init, mbxCmd x%x "
+				"0454 Adapter failed to init, mbxCmd x%x "
 				"INIT_LINK, mbxStatus x%x\n",
-				phba->brd_no,
 				mb->mbxCommand, mb->mbxStatus);
 
 		/* Clear all interrupt enable conditions */
@@ -437,16 +427,11 @@
 int
 lpfc_hba_down_prep(struct lpfc_hba *phba)
 {
-	struct lpfc_vport *vport = phba->pport;
-
 	/* Disable interrupts */
 	writel(0, phba->HCregaddr);
 	readl(phba->HCregaddr); /* flush */
 
-	list_for_each_entry(vport, &phba->port_list, listentry) {
-		lpfc_cleanup_discovery_resources(vport);
-	}
-
+	lpfc_cleanup_discovery_resources(phba->pport);
 	return 0;
 }
 
@@ -518,7 +503,7 @@
 	mempool_free(pmboxq, phba->mbox_mem_pool);
 	if (!(phba->pport->fc_flag & FC_OFFLINE_MODE) &&
 		!(phba->link_state == LPFC_HBA_ERROR) &&
-		!(phba->pport->fc_flag & FC_UNLOADING))
+		!(phba->pport->load_flag & FC_UNLOADING))
 		mod_timer(&phba->hb_tmofunc,
 			jiffies + HZ * LPFC_HB_MBOX_INTERVAL);
 	return;
@@ -532,7 +517,7 @@
 	struct lpfc_sli *psli = &phba->sli;
 
 	if ((phba->link_state == LPFC_HBA_ERROR) ||
-		(phba->pport->fc_flag & FC_UNLOADING) ||
+		(phba->pport->load_flag & FC_UNLOADING) ||
 		(phba->pport->fc_flag & FC_OFFLINE_MODE))
 		return;
 
@@ -586,8 +571,8 @@
 		 * need to take the HBA offline.
 		 */
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-			"%d:0459 Adapter heartbeat failure, taking "
-			"this port offline.\n", phba->brd_no);
+				"0459 Adapter heartbeat failure, taking "
+				"this port offline.\n");
 
 		spin_lock_irq(&phba->hbalock);
 		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
@@ -615,9 +600,10 @@
 	struct lpfc_vport *vport = phba->pport;
 	struct lpfc_sli   *psli = &phba->sli;
 	struct lpfc_sli_ring  *pring;
-	struct lpfc_vport *port_iterator;
+	struct lpfc_vport **vports;
 	uint32_t event_data;
 	struct Scsi_Host  *shost;
+	int i;
 
 	/* If the pci channel is offline, ignore possible errors,
 	 * since we cannot communicate with the pci card anyway. */
@@ -628,18 +614,21 @@
 	    phba->work_hs & HS_FFER5) {
 		/* Re-establishing Link */
 		lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT,
-				"%d:1301 Re-establishing Link "
+				"1301 Re-establishing Link "
 				"Data: x%x x%x x%x\n",
-				phba->brd_no, phba->work_hs,
+				phba->work_hs,
 				phba->work_status[0], phba->work_status[1]);
-		list_for_each_entry(port_iterator, &phba->port_list,
-				    listentry) {
-			shost = lpfc_shost_from_vport(port_iterator);
-
-			spin_lock_irq(shost->host_lock);
-			port_iterator->fc_flag |= FC_ESTABLISH_LINK;
-			spin_unlock_irq(shost->host_lock);
-		}
+		vports = lpfc_create_vport_work_array(phba);
+		if (vports != NULL)
+			for(i = 0;
+			    i < LPFC_MAX_VPORTS && vports[i] != NULL;
+			    i++){
+				shost = lpfc_shost_from_vport(vports[i]);
+				spin_lock_irq(shost->host_lock);
+				vports[i]->fc_flag |= FC_ESTABLISH_LINK;
+				spin_unlock_irq(shost->host_lock);
+			}
+		lpfc_destroy_vport_work_array(vports);
 		spin_lock_irq(&phba->hbalock);
 		psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
 		spin_unlock_irq(&phba->hbalock);
@@ -673,9 +662,9 @@
 		 *  twice. This is the adapter hardware error path.
 		 */
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"%d:0457 Adapter Hardware Error "
+				"0457 Adapter Hardware Error "
 				"Data: x%x x%x x%x\n",
-				phba->brd_no, phba->work_hs,
+				phba->work_hs,
 				phba->work_status[0], phba->work_status[1]);
 
 		event_data = FC_REG_DUMP_EVENT;
@@ -708,7 +697,6 @@
 {
 	struct lpfc_vport *vport = phba->pport;
 	struct lpfc_sli   *psli = &phba->sli;
-	struct lpfc_vport *port_iterator;
 	LPFC_MBOXQ_t *pmb;
 	volatile uint32_t control;
 	struct lpfc_dmabuf *mp;
@@ -729,8 +717,7 @@
 	rc = -EIO;
 
 	/* Cleanup any outstanding ELS commands */
-	list_for_each_entry(port_iterator, &phba->port_list, listentry)
-		lpfc_els_flush_cmd(port_iterator);
+	lpfc_els_flush_all_cmd(phba);
 
 	psli->slistat.link_event++;
 	lpfc_read_la(phba, pmb, mp);
@@ -773,8 +760,7 @@
 	/* The other case is an error from issue_mbox */
 	if (rc == -ENOMEM)
 		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
-			        "%d:0300 READ_LA: no buffers\n",
-				phba->brd_no);
+			        "0300 READ_LA: no buffers\n");
 
 	return;
 }
@@ -799,8 +785,7 @@
 
 	/* Vital Product */
 	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-			"%d:0455 Vital Product Data: x%x x%x x%x x%x\n",
-			phba->brd_no,
+			"0455 Vital Product Data: x%x x%x x%x x%x\n",
 			(uint32_t) vpd[0], (uint32_t) vpd[1], (uint32_t) vpd[2],
 			(uint32_t) vpd[3]);
 	while (!finished && (index < (len - 4))) {
@@ -1313,22 +1298,25 @@
 lpfc_establish_link_tmo(unsigned long ptr)
 {
 	struct lpfc_hba   *phba = (struct lpfc_hba *) ptr;
-	struct lpfc_vport *vport = phba->pport;
+	struct lpfc_vport **vports;
 	unsigned long iflag;
+	int i;
 
 	/* Re-establishing Link, timer expired */
 	lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
-			"%d:1300 Re-establishing Link, timer expired "
+			"1300 Re-establishing Link, timer expired "
 			"Data: x%x x%x\n",
-			phba->brd_no, vport->fc_flag,
-			vport->port_state);
-	list_for_each_entry(vport, &phba->port_list, listentry) {
-		struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-
-		spin_lock_irqsave(shost->host_lock, iflag);
-		vport->fc_flag &= ~FC_ESTABLISH_LINK;
-		spin_unlock_irqrestore(shost->host_lock, iflag);
-	}
+			phba->pport->fc_flag, phba->pport->port_state);
+	vports = lpfc_create_vport_work_array(phba);
+	if (vports != NULL)
+		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+			struct Scsi_Host *shost;
+			shost = lpfc_shost_from_vport(vports[i]);
+			spin_lock_irqsave(shost->host_lock, iflag);
+			vports[i]->fc_flag &= ~FC_ESTABLISH_LINK;
+			spin_unlock_irqrestore(shost->host_lock, iflag);
+		}
+	lpfc_destroy_vport_work_array(vports);
 }
 
 void
@@ -1343,12 +1331,9 @@
 static void
 lpfc_stop_phba_timers(struct lpfc_hba *phba)
 {
-	struct lpfc_vport *vport;
-
 	del_timer_sync(&phba->fcp_poll_timer);
 	del_timer_sync(&phba->fc_estabtmo);
-	list_for_each_entry(vport, &phba->port_list, listentry)
-		lpfc_stop_vport_timers(vport);
+	lpfc_stop_vport_timers(phba->pport);
 	del_timer_sync(&phba->sli.mbox_tmo);
 	del_timer_sync(&phba->fabric_block_timer);
 	phba->hb_outstanding = 0;
@@ -1360,6 +1345,8 @@
 lpfc_online(struct lpfc_hba *phba)
 {
 	struct lpfc_vport *vport = phba->pport;
+	struct lpfc_vport **vports;
+	int i;
 
 	if (!phba)
 		return 0;
@@ -1368,8 +1355,7 @@
 		return 0;
 
 	lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
-		       "%d:0458 Bring Adapter online\n",
-		       phba->brd_no);
+			"0458 Bring Adapter online\n");
 
 	lpfc_block_mgmt_io(phba);
 
@@ -1383,14 +1369,18 @@
 		return 1;
 	}
 
-	list_for_each_entry(vport, &phba->port_list, listentry) {
-		struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
-		spin_lock_irq(shost->host_lock);
-		vport->fc_flag &= ~FC_OFFLINE_MODE;
-		if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
-			vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
-		spin_unlock_irq(shost->host_lock);
-	}
+	vports = lpfc_create_vport_work_array(phba);
+	if (vports != NULL)
+		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+			struct Scsi_Host *shost;
+			shost = lpfc_shost_from_vport(vports[i]);
+			spin_lock_irq(shost->host_lock);
+			vports[i]->fc_flag &= ~FC_OFFLINE_MODE;
+			if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
+				vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
+			spin_unlock_irq(shost->host_lock);
+		}
+		lpfc_destroy_vport_work_array(vports);
 
 	lpfc_unblock_mgmt_io(phba);
 	return 0;
@@ -1440,39 +1430,39 @@
 void
 lpfc_offline(struct lpfc_hba *phba)
 {
-	struct lpfc_vport *vport = phba->pport;
-	struct Scsi_Host  *shost = lpfc_shost_from_vport(vport);
-	struct lpfc_vport *port_iterator;
+	struct Scsi_Host  *shost;
+	struct lpfc_vport **vports;
+	int i;
 
-	if (vport->fc_flag & FC_OFFLINE_MODE)
+	if (phba->pport->fc_flag & FC_OFFLINE_MODE)
 		return;
 
 	/* stop all timers associated with this hba */
 	lpfc_stop_phba_timers(phba);
-	list_for_each_entry(port_iterator, &phba->port_list, listentry) {
-		port_iterator->work_port_events = 0;
-	}
-
+	vports = lpfc_create_vport_work_array(phba);
+	if (vports != NULL)
+		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++)
+			lpfc_stop_vport_timers(vports[i]);
+	lpfc_destroy_vport_work_array(vports);
 	lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
-		       "%d:0460 Bring Adapter offline\n",
-		       phba->brd_no);
-
+			"0460 Bring Adapter offline\n");
 	/* Bring down the SLI Layer and cleanup.  The HBA is offline
 	   now.  */
 	lpfc_sli_hba_down(phba);
 	spin_lock_irq(&phba->hbalock);
 	phba->work_ha = 0;
-	vport->fc_flag |= FC_OFFLINE_MODE;
 	spin_unlock_irq(&phba->hbalock);
-	list_for_each_entry(port_iterator, &phba->port_list, listentry) {
-		shost = lpfc_shost_from_vport(port_iterator);
-
-		lpfc_cleanup(port_iterator);
-		spin_lock_irq(shost->host_lock);
-		vport->work_port_events = 0;
-		vport->fc_flag |= FC_OFFLINE_MODE;
-		spin_unlock_irq(shost->host_lock);
-	}
+	vports = lpfc_create_vport_work_array(phba);
+	if (vports != NULL)
+		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+			shost = lpfc_shost_from_vport(vports[i]);
+			lpfc_cleanup(vports[i]);
+			spin_lock_irq(shost->host_lock);
+			vports[i]->work_port_events = 0;
+			vports[i]->fc_flag |= FC_OFFLINE_MODE;
+			spin_unlock_irq(shost->host_lock);
+		}
+	lpfc_destroy_vport_work_array(vports);
 }
 
 /******************************************************************************
@@ -1509,15 +1499,19 @@
 	return 0;
 }
 
-
 struct lpfc_vport *
-lpfc_create_port(struct lpfc_hba *phba, int instance, struct fc_vport *fc_vport)
+lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)
 {
 	struct lpfc_vport *vport;
 	struct Scsi_Host  *shost;
 	int error = 0;
 
-	shost = scsi_host_alloc(&lpfc_template, sizeof(struct lpfc_vport));
+	if (dev != &phba->pcidev->dev)
+		shost = scsi_host_alloc(&lpfc_vport_template,
+					sizeof(struct lpfc_vport));
+	else
+		shost = scsi_host_alloc(&lpfc_template,
+					sizeof(struct lpfc_vport));
 	if (!shost)
 		goto out;
 
@@ -1527,9 +1521,10 @@
 	vport->load_flag |= FC_LOADING;
 	vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
 
+	lpfc_get_vport_cfgparam(vport);
 	shost->unique_id = instance;
 	shost->max_id = LPFC_MAX_TARGET;
-	shost->max_lun = phba->cfg_max_luns;
+	shost->max_lun = vport->cfg_max_luns;
 	shost->this_id = -1;
 	shost->max_cmd_len = 16;
 	/*
@@ -1538,7 +1533,7 @@
 	 * max xri value determined in hba setup.
 	 */
 	shost->can_queue = phba->cfg_hba_queue_depth - 10;
-	if (fc_vport != NULL) {
+	if (dev != &phba->pcidev->dev) {
 		shost->transportt = lpfc_vport_transport_template;
 		vport->port_type = LPFC_NPIV_PORT;
 	} else {
@@ -1562,15 +1557,13 @@
 	vport->els_tmofunc.function = lpfc_els_timeout;
 	vport->els_tmofunc.data = (unsigned long)vport;
 
-	if (fc_vport != NULL) {
-		error = scsi_add_host(shost, &fc_vport->dev);
-	} else {
-		error = scsi_add_host(shost, &phba->pcidev->dev);
-	}
+	error = scsi_add_host(shost, dev);
 	if (error)
 		goto out_put_shost;
 
+	spin_lock_irq(&phba->hbalock);
 	list_add_tail(&vport->listentry, &phba->port_list);
+	spin_unlock_irq(&phba->hbalock);
 	return vport;
 
 out_put_shost:
@@ -1625,23 +1618,21 @@
 
 	spin_lock_irq(shost->host_lock);
 
-	if (vport->fc_flag & FC_UNLOADING) {
+	if (vport->load_flag & FC_UNLOADING) {
 		stat = 1;
 		goto finished;
 	}
 	if (time >= 30 * HZ) {
 		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-				"%d:0461 Scanning longer than 30 "
-				"seconds.  Continuing initialization\n",
-				phba->brd_no);
+				"0461 Scanning longer than 30 "
+				"seconds.  Continuing initialization\n");
 		stat = 1;
 		goto finished;
 	}
 	if (time >= 15 * HZ && phba->link_state <= LPFC_LINK_DOWN) {
 		lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-				"%d:0465 Link down longer than 15 "
-				"seconds.  Continuing initialization\n",
-				phba->brd_no);
+				"0465 Link down longer than 15 "
+				"seconds.  Continuing initialization\n");
 		stat = 1;
 		goto finished;
 	}
@@ -1704,7 +1695,7 @@
 
 	fc_host_max_npiv_vports(shost) = phba->max_vpi;
 	spin_lock_irq(shost->host_lock);
-	vport->fc_flag &= ~FC_LOADING;
+	vport->load_flag &= ~FC_LOADING;
 	spin_unlock_irq(shost->host_lock);
 }
 
@@ -1716,9 +1707,10 @@
 	struct lpfc_sli   *psli;
 	struct lpfc_iocbq *iocbq_entry = NULL, *iocbq_next = NULL;
 	struct Scsi_Host  *shost = NULL;
+	void *ptr;
 	unsigned long bar0map_len, bar2map_len;
 	int error = -ENODEV;
-	int i;
+	int  i, hbq_count;
 	uint16_t iotag;
 
 	if (pci_enable_device(pdev))
@@ -1739,7 +1731,6 @@
 		goto out_free_phba;
 
 	INIT_LIST_HEAD(&phba->port_list);
-	INIT_LIST_HEAD(&phba->hbq_buffer_list);
 	/*
 	 * Get all the module params for configuring this host and then
 	 * establish the host.
@@ -1817,6 +1808,17 @@
 	if (!phba->hbqslimp.virt)
 		goto out_free_slim;
 
+	hbq_count = lpfc_sli_hbq_count();
+	ptr = phba->hbqslimp.virt;
+	for (i = 0; i < hbq_count; ++i) {
+		phba->hbqs[i].hbq_virt = ptr;
+		INIT_LIST_HEAD(&phba->hbqs[i].hbq_buffer_list);
+		ptr += (lpfc_hbq_defs[i]->entry_count *
+			sizeof(struct lpfc_hbq_entry));
+	}
+	phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_els_hbq_alloc;
+	phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer  = lpfc_els_hbq_free;
+
 	memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size());
 
 	/* Initialize the SLI Layer to run with lpfc HBAs. */
@@ -1830,7 +1832,7 @@
 	/* Initialize and populate the iocb list per host.  */
 	INIT_LIST_HEAD(&phba->lpfc_iocb_list);
 	for (i = 0; i < LPFC_IOCB_LIST_CNT; i++) {
-		iocbq_entry = kmalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL);
+		iocbq_entry = kzalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL);
 		if (iocbq_entry == NULL) {
 			printk(KERN_ERR "%s: only allocated %d iocbs of "
 				"expected %d count. Unloading driver.\n",
@@ -1839,7 +1841,6 @@
 			goto out_free_iocbq;
 		}
 
-		memset(iocbq_entry, 0, sizeof(struct lpfc_iocbq));
 		iotag = lpfc_sli_next_iotag(phba, iocbq_entry);
 		if (iotag == 0) {
 			kfree (iocbq_entry);
@@ -1881,7 +1882,7 @@
 	/* Initialize list of fabric iocbs */
 	INIT_LIST_HEAD(&phba->fabric_iocb_list);
 
-	vport = lpfc_create_port(phba, phba->brd_no, NULL);
+	vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev);
 	if (!vport)
 		goto out_kthread_stop;
 
@@ -1893,18 +1894,19 @@
 
 	if (phba->cfg_use_msi) {
 		error = pci_enable_msi(phba->pcidev);
-		if (error)
-			lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "%d:0452 "
-					"Enable MSI failed, continuing with "
-					"IRQ\n", phba->brd_no);
+		if (!error)
+			phba->using_msi = 1;
+		else
+			lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+					"0452 Enable MSI failed, continuing "
+					"with IRQ\n");
 	}
 
 	error =	request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED,
 			    LPFC_DRIVER_NAME, phba);
 	if (error) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-			"%d:0451 Enable interrupt handler failed\n",
-			phba->brd_no);
+			"0451 Enable interrupt handler failed\n");
 		goto out_disable_msi;
 	}
 
@@ -1941,14 +1943,15 @@
 out_remove_device:
 	lpfc_free_sysfs_attr(vport);
 	spin_lock_irq(shost->host_lock);
-	vport->fc_flag |= FC_UNLOADING;
+	vport->load_flag |= FC_UNLOADING;
 	spin_unlock_irq(shost->host_lock);
 out_free_irq:
 	lpfc_stop_phba_timers(phba);
 	phba->pport->work_port_events = 0;
 	free_irq(phba->pcidev->irq, phba);
 out_disable_msi:
-	pci_disable_msi(phba->pcidev);
+	if (phba->using_msi)
+		pci_disable_msi(phba->pcidev);
 	destroy_port(vport);
 out_kthread_stop:
 	kthread_stop(phba->worker_thread);
@@ -1990,16 +1993,15 @@
 	struct Scsi_Host  *shost = pci_get_drvdata(pdev);
 	struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 	struct lpfc_hba   *phba = vport->phba;
-	struct lpfc_vport *port_iterator;
-	list_for_each_entry(port_iterator, &phba->port_list, listentry)
-		port_iterator->load_flag |= FC_UNLOADING;
+	spin_lock_irq(&phba->hbalock);
+	vport->load_flag |= FC_UNLOADING;
+	spin_unlock_irq(&phba->hbalock);
 
 	kfree(vport->vname);
 	lpfc_free_sysfs_attr(vport);
 
 	fc_remove_host(shost);
 	scsi_remove_host(shost);
-
 	/*
 	 * Bring down the SLI Layer. This step disable all interrupts,
 	 * clears the rings, discards all mailbox commands, and resets
@@ -2013,7 +2015,6 @@
 	list_del_init(&vport->listentry);
 	spin_unlock_irq(&phba->hbalock);
 
-
 	lpfc_debugfs_terminate(vport);
 	lpfc_cleanup(vport);
 
@@ -2021,7 +2022,8 @@
 
 	/* Release the irq reservation */
 	free_irq(phba->pcidev->irq, phba);
-	pci_disable_msi(phba->pcidev);
+	if (phba->using_msi)
+		pci_disable_msi(phba->pcidev);
 
 	pci_set_drvdata(pdev, NULL);
 	scsi_host_put(shost);
@@ -2063,8 +2065,8 @@
 static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev,
 				pci_channel_state_t state)
 {
-	struct Scsi_Host *host = pci_get_drvdata(pdev);
-	struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata;
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
 	struct lpfc_sli *psli = &phba->sli;
 	struct lpfc_sli_ring  *pring;
 
@@ -2080,6 +2082,11 @@
 	pring = &psli->ring[psli->fcp_ring];
 	lpfc_sli_abort_iocb_ring(phba, pring);
 
+	/* Release the irq reservation */
+	free_irq(phba->pcidev->irq, phba);
+	if (phba->using_msi)
+		pci_disable_msi(phba->pcidev);
+
 	/* Request a slot reset. */
 	return PCI_ERS_RESULT_NEED_RESET;
 }
@@ -2092,8 +2099,8 @@
  */
 static pci_ers_result_t lpfc_io_slot_reset(struct pci_dev *pdev)
 {
-	struct Scsi_Host *host = pci_get_drvdata(pdev);
-	struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata;
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
 	struct lpfc_sli *psli = &phba->sli;
 	int bars = pci_select_bars(pdev, IORESOURCE_MEM);
 
@@ -2107,9 +2114,9 @@
 	pci_set_master(pdev);
 
 	/* Re-establishing Link */
-	spin_lock_irq(host->host_lock);
+	spin_lock_irq(shost->host_lock);
 	phba->pport->fc_flag |= FC_ESTABLISH_LINK;
-	spin_unlock_irq(host->host_lock);
+	spin_unlock_irq(shost->host_lock);
 
 	spin_lock_irq(&phba->hbalock);
 	psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
@@ -2132,8 +2139,8 @@
  */
 static void lpfc_io_resume(struct pci_dev *pdev)
 {
-	struct Scsi_Host *host = pci_get_drvdata(pdev);
-	struct lpfc_hba *phba = (struct lpfc_hba *)host->hostdata;
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba;
 
 	if (lpfc_online(phba) == 0) {
 		mod_timer(&phba->fc_estabtmo, jiffies + HZ * 60);
diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h
index 8a6ceff..626e4d8 100644
--- a/drivers/scsi/lpfc/lpfc_logmsg.h
+++ b/drivers/scsi/lpfc/lpfc_logmsg.h
@@ -33,6 +33,12 @@
 #define LOG_VPORT                     0x4000	/* NPIV events */
 #define LOG_ALL_MSG                   0xffff	/* LOG all messages */
 
+#define lpfc_printf_vlog(vport, level, mask, fmt, arg...) \
+	{ if (((mask) &(vport)->cfg_log_verbose) || (level[1] <= '3')) \
+		dev_printk(level, &((vport)->phba->pcidev)->dev, "%d:(%d):" \
+			   fmt, (vport)->phba->brd_no, vport->vpi, ##arg); }
+
 #define lpfc_printf_log(phba, level, mask, fmt, arg...) \
-	{ if (((mask) &(phba)->cfg_log_verbose) || (level[1] <= '3')) \
-		dev_printk(level, &((phba)->pcidev)->dev, fmt, ##arg); }
+	{ if (((mask) &(phba)->pport->cfg_log_verbose) || (level[1] <= '3')) \
+		dev_printk(level, &((phba)->pcidev)->dev, "%d:" \
+			   fmt, phba->brd_no, ##arg); }
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index 8f42fbf..a5927336 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -275,11 +275,8 @@
 		kfree(mp);
 		mb->mbxCommand = MBX_READ_SPARM64;
 		/* READ_SPARAM: no buffers */
-		lpfc_printf_log(phba,
-			        KERN_WARNING,
-			        LOG_MBOX,
-			        "%d:0301 READ_SPARAM: no buffers\n",
-			        phba->brd_no);
+		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
+			        "0301 READ_SPARAM: no buffers\n");
 		return (1);
 	}
 	INIT_LIST_HEAD(&mp->list);
@@ -378,9 +375,8 @@
 		mb->mbxCommand = MBX_REG_LOGIN64;
 		/* REG_LOGIN: no buffers */
 		lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX,
-				"%d (%d):0302 REG_LOGIN: no buffers, DID x%x, "
-				"flag x%x\n",
-				phba->brd_no, vpi, did, flag);
+				"0302 REG_LOGIN: no buffers, VPI:%d DID:x%x, "
+				"flag x%x\n", vpi, did, flag);
 		return (1);
 	}
 	INIT_LIST_HEAD(&mp->list);
@@ -564,7 +560,8 @@
 }
 
 void
-lpfc_config_hbq(struct lpfc_hba *phba, struct lpfc_hbq_init *hbq_desc,
+lpfc_config_hbq(struct lpfc_hba *phba, uint32_t id,
+		 struct lpfc_hbq_init *hbq_desc,
 		uint32_t hbq_entry_index, LPFC_MBOXQ_t *pmb)
 {
 	int i;
@@ -572,6 +569,7 @@
 	struct config_hbq_var *hbqmb = &mb->un.varCfgHbq;
 
 	memset(pmb, 0, sizeof (LPFC_MBOXQ_t));
+	hbqmb->hbqId = id;
 	hbqmb->entry_count = hbq_desc->entry_count;   /* # entries in HBQ */
 	hbqmb->recvNotify = hbq_desc->rn;             /* Receive
 						       * Notification */
@@ -691,8 +689,8 @@
 
 	if (phba->sli_rev == 3 && phba->vpd.sli3Feat.cerbm) {
 		mb->un.varCfgPort.cerbm = 1; /* Request HBQs */
-		mb->un.varCfgPort.max_hbq = 1; /* Requesting 2 HBQs */
-		if (phba->max_vpi && phba->cfg_npiv_enable &&
+		mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count();
+		if (phba->max_vpi && phba->cfg_enable_npiv &&
 		    phba->vpd.sli3Feat.cmv) {
 			mb->un.varCfgPort.max_vpi = phba->max_vpi;
 			mb->un.varCfgPort.cmv = 1;
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 3594c46..43c3b8a 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -231,21 +231,34 @@
 	return;
 }
 
-void *
-lpfc_hbq_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle)
+struct hbq_dmabuf *
+lpfc_els_hbq_alloc(struct lpfc_hba *phba)
 {
-	void *ret;
-	ret = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_ATOMIC, handle);
-	return ret;
+	struct hbq_dmabuf *hbqbp;
+
+	hbqbp = kmalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL);
+	if (!hbqbp)
+		return NULL;
+
+	hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_KERNEL,
+					  &hbqbp->dbuf.phys);
+	if (!hbqbp->dbuf.virt) {
+		kfree(hbqbp);
+		return NULL;
+	}
+	hbqbp->size = LPFC_BPL_SIZE;
+	return hbqbp;
 }
 
 void
-lpfc_hbq_free(struct lpfc_hba *phba, void *virt, dma_addr_t dma)
+lpfc_els_hbq_free(struct lpfc_hba *phba, struct hbq_dmabuf *hbqbp)
 {
-	pci_pool_free(phba->lpfc_hbq_pool, virt, dma);
+	pci_pool_free(phba->lpfc_hbq_pool, hbqbp->dbuf.virt, hbqbp->dbuf.phys);
+	kfree(hbqbp);
 	return;
 }
 
+/* This is ONLY called for the LPFC_ELS_HBQ */
 void
 lpfc_in_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp)
 {
@@ -254,9 +267,8 @@
 	if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) {
 		hbq_entry = container_of(mp, struct hbq_dmabuf, dbuf);
 		if (hbq_entry->tag == -1) {
-			lpfc_hbq_free(phba, hbq_entry->dbuf.virt,
-				      hbq_entry->dbuf.phys);
-			kfree(hbq_entry);
+			(phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer)
+				(phba, hbq_entry);
 		} else {
 			lpfc_sli_free_hbq(phba, hbq_entry);
 		}
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index bca2f5c..880af0c 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -133,15 +133,15 @@
 	memcpy(&ndlp->nlp_portname, &sp->portName, sizeof (struct lpfc_name));
 	return 1;
 bad_service_param:
-	lpfc_printf_log(vport->phba, KERN_ERR, LOG_DISCOVERY,
-			"%d (%d):0207 Device %x "
-			"(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x) sent "
-			"invalid service parameters.  Ignoring device.\n",
-			vport->phba->brd_no, ndlp->vport->vpi, ndlp->nlp_DID,
-			sp->nodeName.u.wwn[0], sp->nodeName.u.wwn[1],
-			sp->nodeName.u.wwn[2], sp->nodeName.u.wwn[3],
-			sp->nodeName.u.wwn[4], sp->nodeName.u.wwn[5],
-			sp->nodeName.u.wwn[6], sp->nodeName.u.wwn[7]);
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+			 "0207 Device %x "
+			 "(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x) sent "
+			 "invalid service parameters.  Ignoring device.\n",
+			 ndlp->nlp_DID,
+			 sp->nodeName.u.wwn[0], sp->nodeName.u.wwn[1],
+			 sp->nodeName.u.wwn[2], sp->nodeName.u.wwn[3],
+			 sp->nodeName.u.wwn[4], sp->nodeName.u.wwn[5],
+			 sp->nodeName.u.wwn[6], sp->nodeName.u.wwn[7]);
 	return 0;
 }
 
@@ -194,11 +194,11 @@
 	IOCB_t *cmd;
 
 	/* Abort outstanding I/O on NPort <nlp_DID> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			"%d (%d):0205 Abort outstanding I/O on NPort x%x "
-			"Data: x%x x%x x%x\n",
-			phba->brd_no, ndlp->vport->vpi, ndlp->nlp_DID,
-			ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi);
+	lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_DISCOVERY,
+			 "0205 Abort outstanding I/O on NPort x%x "
+			 "Data: x%x x%x x%x\n",
+			 ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state,
+			 ndlp->nlp_rpi);
 
 	lpfc_fabric_abort_nport(ndlp);
 
@@ -298,13 +298,12 @@
 	icmd = &cmdiocb->iocb;
 
 	/* PLOGI chkparm OK */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0114 PLOGI chkparm OK Data: x%x x%x x%x x%x\n",
-			phba->brd_no, vport->vpi,
-			ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag,
-			ndlp->nlp_rpi);
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0114 PLOGI chkparm OK Data: x%x x%x x%x x%x\n",
+			 ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag,
+			 ndlp->nlp_rpi);
 
-	if (phba->cfg_fcp_class == 2 && sp->cls2.classValid)
+	if (vport->cfg_fcp_class == 2 && sp->cls2.classValid)
 		ndlp->nlp_fcp_info |= CLASS2;
 	else
 		ndlp->nlp_fcp_info |= CLASS3;
@@ -330,7 +329,7 @@
 	case  NLP_STE_PRLI_ISSUE:
 	case  NLP_STE_UNMAPPED_NODE:
 	case  NLP_STE_MAPPED_NODE:
-		lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL, 0);
+		lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL);
 		return 1;
 	}
 
@@ -392,7 +391,7 @@
 	}
 
 	if ((vport->port_type == LPFC_NPIV_PORT &&
-	      phba->cfg_vport_restrict_login)) {
+	     vport->cfg_restrict_login)) {
 
 		/* In order to preserve RPIs, we want to cleanup
 		 * the default RPI the firmware created to rcv
@@ -408,7 +407,7 @@
 			ndlp, mbox);
 		return 1;
 	}
-	lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0);
+	lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox);
 	return 1;
 
 out:
@@ -452,7 +451,7 @@
 			lpfc_els_rsp_adisc_acc(vport, cmdiocb, ndlp);
 		} else {
 			lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp,
-					 NULL, 0);
+					 NULL);
 		}
 		return 1;
 	}
@@ -489,9 +488,9 @@
 	ndlp->nlp_flag |= NLP_LOGO_ACC;
 	spin_unlock_irq(shost->host_lock);
 	if (els_cmd == ELS_CMD_PRLO)
-		lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
+		lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
 	else
-		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
 
 	if (!(ndlp->nlp_type & NLP_FABRIC) ||
 	    (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) {
@@ -564,10 +563,14 @@
 lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
 {
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-	struct lpfc_hba  *phba = vport->phba;
+
+	if (!ndlp->nlp_rpi) {
+		ndlp->nlp_flag &= ~NLP_NPR_ADISC;
+		return 0;
+	}
 
 	/* Check config parameter use-adisc or FCP-2 */
-	if ((phba->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) ||
+	if ((vport->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) ||
 	    ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) {
 		spin_lock_irq(shost->host_lock);
 		ndlp->nlp_flag |= NLP_NPR_ADISC;
@@ -583,12 +586,11 @@
 lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 		  void *arg, uint32_t evt)
 {
-	lpfc_printf_log(vport->phba, KERN_ERR, LOG_DISCOVERY,
-			"%d (%d):0253 Illegal State Transition: node x%x "
-			"event x%x, state x%x Data: x%x x%x\n",
-			vport->phba->brd_no, vport->vpi,
-			ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
-			ndlp->nlp_flag);
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+			 "0253 Illegal State Transition: node x%x "
+			 "event x%x, state x%x Data: x%x x%x\n",
+			 ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi,
+			 ndlp->nlp_flag);
 	return ndlp->nlp_state;
 }
 
@@ -630,7 +632,7 @@
 	spin_lock_irq(shost->host_lock);
 	ndlp->nlp_flag |= NLP_LOGO_ACC;
 	spin_unlock_irq(shost->host_lock);
-	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
 	lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE);
 
 	return ndlp->nlp_state;
@@ -726,7 +728,7 @@
 	lpfc_els_abort(phba, ndlp);
 
 	if (evt == NLP_EVT_RCV_LOGO) {
-		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+		lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
 	} else {
 		lpfc_issue_els_logo(vport, ndlp, 0);
 	}
@@ -778,16 +780,12 @@
 	sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
 	if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3))
 		goto out;
-
 	/* PLOGI chkparm OK */
-	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (%d):0121 PLOGI chkparm OK "
-			"Data: x%x x%x x%x x%x\n",
-			phba->brd_no, vport->vpi,
-			ndlp->nlp_DID, ndlp->nlp_state,
-			ndlp->nlp_flag, ndlp->nlp_rpi);
-
-	if (phba->cfg_fcp_class == 2 && (sp->cls2.classValid))
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
+			 "0121 PLOGI chkparm OK Data: x%x x%x x%x x%x\n",
+			 ndlp->nlp_DID, ndlp->nlp_state,
+			 ndlp->nlp_flag, ndlp->nlp_rpi);
+	if (vport->cfg_fcp_class == 2 && (sp->cls2.classValid))
 		ndlp->nlp_fcp_info |= CLASS2;
 	else
 		ndlp->nlp_fcp_info |= CLASS3;
@@ -806,10 +804,9 @@
 
 	mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 	if (!mbox) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-			"%d (%d):0133 PLOGI: no memory for reg_login "
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+			"0133 PLOGI: no memory for reg_login "
 			"Data: x%x x%x x%x x%x\n",
-			phba->brd_no, vport->vpi,
 			ndlp->nlp_DID, ndlp->nlp_state,
 			ndlp->nlp_flag, ndlp->nlp_rpi);
 		goto out;
@@ -844,30 +841,27 @@
 		kfree(mp);
 		mempool_free(mbox, phba->mbox_mem_pool);
 
-		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-			"%d (%d):0134 PLOGI: cannot issue reg_login "
-			"Data: x%x x%x x%x x%x\n",
-			phba->brd_no, vport->vpi,
-			ndlp->nlp_DID, ndlp->nlp_state,
-			ndlp->nlp_flag, ndlp->nlp_rpi);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				 "0134 PLOGI: cannot issue reg_login "
+				 "Data: x%x x%x x%x x%x\n",
+				 ndlp->nlp_DID, ndlp->nlp_state,
+				 ndlp->nlp_flag, ndlp->nlp_rpi);
 	} else {
 		mempool_free(mbox, phba->mbox_mem_pool);
 
-		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-			"%d (%d):0135 PLOGI: cannot format reg_login "
-			"Data: x%x x%x x%x x%x\n",
-			phba->brd_no, vport->vpi,
-			ndlp->nlp_DID, ndlp->nlp_state,
-			ndlp->nlp_flag, ndlp->nlp_rpi);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				 "0135 PLOGI: cannot format reg_login "
+				 "Data: x%x x%x x%x x%x\n",
+				 ndlp->nlp_DID, ndlp->nlp_state,
+				 ndlp->nlp_flag, ndlp->nlp_rpi);
 	}
 
 
 out:
 	if (ndlp->nlp_DID == NameServer_DID) {
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
-		lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-			"%d (%d):0261 Cannot Register NameServer login\n",
-			phba->brd_no, vport->vpi);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+				 "0261 Cannot Register NameServer login\n");
 	}
 
 	/* Free this node since the driver cannot login or has the wrong
@@ -1178,7 +1172,7 @@
 	struct lpfc_iocbq *cmdiocb;
 
 	cmdiocb = (struct lpfc_iocbq *) arg;
-	lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
+	lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
 	return ndlp->nlp_state;
 }
 
@@ -1189,19 +1183,15 @@
 				  uint32_t evt)
 {
 	struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
-	struct lpfc_hba  *phba = vport->phba;
 	LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
 	MAILBOX_t *mb = &pmb->mb;
 	uint32_t did  = mb->un.varWords[1];
 
 	if (mb->mbxStatus) {
 		/* RegLogin failed */
-		lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
-				"%d (%d):0246 RegLogin failed Data: x%x x%x "
-				"x%x\n",
-				phba->brd_no, vport->vpi,
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
+				"0246 RegLogin failed Data: x%x x%x x%x\n",
 				did, mb->mbxStatus, vport->port_state);
-
 		/*
 		 * If RegLogin failed due to lack of HBA resources do not
 		 * retry discovery.
@@ -1337,7 +1327,7 @@
 {
 	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
 
-	lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
+	lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
 	return ndlp->nlp_state;
 }
 
@@ -1358,7 +1348,7 @@
 	irsp = &rspiocb->iocb;
 	if (irsp->ulpStatus) {
 		if ((vport->port_type == LPFC_NPIV_PORT) &&
-			phba->cfg_vport_restrict_login) {
+		    vport->cfg_restrict_login) {
 			goto out;
 		}
 		ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE;
@@ -1380,7 +1370,7 @@
 	}
 	if (!(ndlp->nlp_type & NLP_FCP_TARGET) &&
 	    (vport->port_type == LPFC_NPIV_PORT) &&
-	     phba->cfg_vport_restrict_login) {
+	     vport->cfg_restrict_login) {
 out:
 		spin_lock_irq(shost->host_lock);
 		ndlp->nlp_flag |= NLP_TARGET_REMOVE;
@@ -1529,7 +1519,7 @@
 {
 	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
 
-	lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL, 0);
+	lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL);
 	return ndlp->nlp_state;
 }
 
@@ -1600,8 +1590,8 @@
 	struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
 
 	/* flush the target */
-	lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
-			    ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
+	lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring],
+			    ndlp->nlp_sid, 0, LPFC_CTX_TGT);
 
 	/* Treat like rcv logo */
 	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO);
@@ -1734,7 +1724,7 @@
 	ndlp->nlp_flag |= NLP_LOGO_ACC;
 	spin_unlock_irq(shost->host_lock);
 
-	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL, 0);
+	lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL);
 
 	if ((ndlp->nlp_flag & NLP_DELAY_TMO) == 0) {
 		mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
@@ -2047,7 +2037,6 @@
 lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 			void *arg, uint32_t evt)
 {
-	struct lpfc_hba  *phba = vport->phba;
 	uint32_t cur_state, rc;
 	uint32_t(*func) (struct lpfc_vport *, struct lpfc_nodelist *, void *,
 			 uint32_t);
@@ -2056,11 +2045,10 @@
 	cur_state = ndlp->nlp_state;
 
 	/* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			"%d (%d):0211 DSM in event x%x on NPort x%x in "
-			"state %d Data: x%x\n",
-			phba->brd_no, vport->vpi,
-			evt, ndlp->nlp_DID, cur_state, ndlp->nlp_flag);
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+			 "0211 DSM in event x%x on NPort x%x in "
+			 "state %d Data: x%x\n",
+			 evt, ndlp->nlp_DID, cur_state, ndlp->nlp_flag);
 
 	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
 		 "DSM in:          evt:%d ste:%d did:x%x",
@@ -2070,11 +2058,9 @@
 	rc = (func) (vport, ndlp, arg, evt);
 
 	/* DSM out state <rc> on NPort <nlp_DID> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
-			"%d (%d):0212 DSM out state %d on NPort x%x "
-			"Data: x%x\n",
-			phba->brd_no, vport->vpi,
-			rc, ndlp->nlp_DID, ndlp->nlp_flag);
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
+			 "0212 DSM out state %d on NPort x%x Data: x%x\n",
+			 rc, ndlp->nlp_DID, ndlp->nlp_flag);
 
 	lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM,
 		 "DSM out:         ste:%d did:x%x flg:x%x",
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 8f45bbc..17d7dc0 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -84,22 +84,21 @@
  * SCSI command completion.
  */
 static inline void
-lpfc_rampup_queue_depth(struct lpfc_hba *phba,
+lpfc_rampup_queue_depth(struct lpfc_vport  *vport,
 			struct scsi_device *sdev)
 {
 	unsigned long flags;
+	struct lpfc_hba *phba = vport->phba;
 	atomic_inc(&phba->num_cmd_success);
 
-	if (phba->cfg_lun_queue_depth <= sdev->queue_depth)
+	if (vport->cfg_lun_queue_depth <= sdev->queue_depth)
 		return;
-
 	spin_lock_irqsave(&phba->hbalock, flags);
 	if (((phba->last_ramp_up_time + QUEUE_RAMP_UP_INTERVAL) > jiffies) ||
 	 ((phba->last_rsrc_error_time + QUEUE_RAMP_UP_INTERVAL ) > jiffies)) {
 		spin_unlock_irqrestore(&phba->hbalock, flags);
 		return;
 	}
-
 	phba->last_ramp_up_time = jiffies;
 	spin_unlock_irqrestore(&phba->hbalock, flags);
 
@@ -119,43 +118,40 @@
 void
 lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
 {
-	struct lpfc_vport *vport;
-	struct Scsi_Host  *host;
+	struct lpfc_vport **vports;
+	struct Scsi_Host  *shost;
 	struct scsi_device *sdev;
 	unsigned long new_queue_depth;
 	unsigned long num_rsrc_err, num_cmd_success;
+	int i;
 
 	num_rsrc_err = atomic_read(&phba->num_rsrc_err);
 	num_cmd_success = atomic_read(&phba->num_cmd_success);
 
-	spin_lock_irq(&phba->hbalock);
-	list_for_each_entry(vport, &phba->port_list, listentry) {
-		host = lpfc_shost_from_vport(vport);
-		if (!scsi_host_get(host))
-			continue;
-
-		spin_unlock_irq(&phba->hbalock);
-
-		shost_for_each_device(sdev, host) {
-			new_queue_depth = sdev->queue_depth * num_rsrc_err /
-			(num_rsrc_err + num_cmd_success);
-			if (!new_queue_depth)
-				new_queue_depth = sdev->queue_depth - 1;
-			else
+	vports = lpfc_create_vport_work_array(phba);
+	if (vports != NULL)
+		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+			shost = lpfc_shost_from_vport(vports[i]);
+			shost_for_each_device(sdev, shost) {
 				new_queue_depth =
-					sdev->queue_depth - new_queue_depth;
-
-			if (sdev->ordered_tags)
-				scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
-					new_queue_depth);
-			else
-				scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
-					new_queue_depth);
+					sdev->queue_depth * num_rsrc_err /
+					(num_rsrc_err + num_cmd_success);
+				if (!new_queue_depth)
+					new_queue_depth = sdev->queue_depth - 1;
+				else
+					new_queue_depth = sdev->queue_depth -
+								new_queue_depth;
+				if (sdev->ordered_tags)
+					scsi_adjust_queue_depth(sdev,
+							MSG_ORDERED_TAG,
+							new_queue_depth);
+				else
+					scsi_adjust_queue_depth(sdev,
+							MSG_SIMPLE_TAG,
+							new_queue_depth);
+			}
 		}
-		spin_lock_irq(&phba->hbalock);
-		scsi_host_put(host);
-	}
-	spin_unlock_irq(&phba->hbalock);
+	lpfc_destroy_vport_work_array(vports);
 	atomic_set(&phba->num_rsrc_err, 0);
 	atomic_set(&phba->num_cmd_success, 0);
 }
@@ -163,29 +159,27 @@
 void
 lpfc_ramp_up_queue_handler(struct lpfc_hba *phba)
 {
-	struct lpfc_vport *vport;
-	struct Scsi_Host  *host;
+	struct lpfc_vport **vports;
+	struct Scsi_Host  *shost;
 	struct scsi_device *sdev;
+	int i;
 
-	spin_lock_irq(&phba->hbalock);
-	list_for_each_entry(vport, &phba->port_list, listentry) {
-		host = lpfc_shost_from_vport(vport);
-		if (!scsi_host_get(host))
-			continue;
-
-		spin_unlock_irq(&phba->hbalock);
-		shost_for_each_device(sdev, host) {
-			if (sdev->ordered_tags)
-				scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
-					sdev->queue_depth+1);
-			else
-				scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
-					sdev->queue_depth+1);
+	vports = lpfc_create_vport_work_array(phba);
+	if (vports != NULL)
+		for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
+			shost = lpfc_shost_from_vport(vports[i]);
+			shost_for_each_device(sdev, shost) {
+				if (sdev->ordered_tags)
+					scsi_adjust_queue_depth(sdev,
+							MSG_ORDERED_TAG,
+							sdev->queue_depth+1);
+				else
+					scsi_adjust_queue_depth(sdev,
+							MSG_SIMPLE_TAG,
+							sdev->queue_depth+1);
+			}
 		}
-		spin_lock_irq(&phba->hbalock);
-		scsi_host_put(host);
-	}
-	spin_unlock_irq(&phba->hbalock);
+	lpfc_destroy_vport_work_array(vports);
 	atomic_set(&phba->num_rsrc_err, 0);
 	atomic_set(&phba->num_cmd_success, 0);
 }
@@ -411,9 +405,7 @@
 	struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
 	struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd;
 	struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp;
-	struct lpfc_hba *phba = vport->phba;
 	uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm;
-	uint32_t vpi = vport->vpi;
 	uint32_t resp_info = fcprsp->rspStatus2;
 	uint32_t scsi_status = fcprsp->rspStatus3;
 	uint32_t *lp;
@@ -445,15 +437,15 @@
 	if (!scsi_status && (resp_info & RESID_UNDER))
 		logit = LOG_FCP;
 
-	lpfc_printf_log(phba, KERN_WARNING, logit,
-			"%d (%d):0730 FCP command x%x failed: x%x SNS x%x x%x "
-			"Data: x%x x%x x%x x%x x%x\n",
-			phba->brd_no, vpi, cmnd->cmnd[0], scsi_status,
-			be32_to_cpu(*lp), be32_to_cpu(*(lp + 3)), resp_info,
-			be32_to_cpu(fcprsp->rspResId),
-			be32_to_cpu(fcprsp->rspSnsLen),
-			be32_to_cpu(fcprsp->rspRspLen),
-			fcprsp->rspInfo3);
+	lpfc_printf_vlog(vport, KERN_WARNING, logit,
+			 "0730 FCP command x%x failed: x%x SNS x%x x%x "
+			 "Data: x%x x%x x%x x%x x%x\n",
+			 cmnd->cmnd[0], scsi_status,
+			 be32_to_cpu(*lp), be32_to_cpu(*(lp + 3)), resp_info,
+			 be32_to_cpu(fcprsp->rspResId),
+			 be32_to_cpu(fcprsp->rspSnsLen),
+			 be32_to_cpu(fcprsp->rspRspLen),
+			 fcprsp->rspInfo3);
 
 	if (resp_info & RSP_LEN_VALID) {
 		rsplen = be32_to_cpu(fcprsp->rspRspLen);
@@ -468,12 +460,12 @@
 	if (resp_info & RESID_UNDER) {
 		scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId));
 
-		lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
-				"%d (%d):0716 FCP Read Underrun, expected %d, "
-				"residual %d Data: x%x x%x x%x\n",
-				phba->brd_no, vpi, be32_to_cpu(fcpcmd->fcpDl),
-				scsi_get_resid(cmnd), fcpi_parm, cmnd->cmnd[0],
-				cmnd->underflow);
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
+				 "0716 FCP Read Underrun, expected %d, "
+				 "residual %d Data: x%x x%x x%x\n",
+				 be32_to_cpu(fcpcmd->fcpDl),
+				 scsi_get_resid(cmnd), fcpi_parm, cmnd->cmnd[0],
+				 cmnd->underflow);
 
 		/*
 		 * If there is an under run check if under run reported by
@@ -483,14 +475,13 @@
 		if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) &&
 			fcpi_parm &&
 			(scsi_get_resid(cmnd) != fcpi_parm)) {
-			lpfc_printf_log(phba, KERN_WARNING,
-					LOG_FCP | LOG_FCP_ERROR,
-					"%d (%d):0735 FCP Read Check Error "
-					"and Underrun Data: x%x x%x x%x x%x\n",
-					phba->brd_no, vpi,
-					be32_to_cpu(fcpcmd->fcpDl),
-					scsi_get_resid(cmnd), fcpi_parm,
-					cmnd->cmnd[0]);
+			lpfc_printf_vlog(vport, KERN_WARNING,
+					 LOG_FCP | LOG_FCP_ERROR,
+					 "0735 FCP Read Check Error "
+					 "and Underrun Data: x%x x%x x%x x%x\n",
+					 be32_to_cpu(fcpcmd->fcpDl),
+					 scsi_get_resid(cmnd), fcpi_parm,
+					 cmnd->cmnd[0]);
 			scsi_set_resid(cmnd, scsi_bufflen(cmnd));
 			host_status = DID_ERROR;
 		}
@@ -504,21 +495,19 @@
 		    (scsi_status == SAM_STAT_GOOD) &&
 		    (scsi_bufflen(cmnd) - scsi_get_resid(cmnd)
 		     < cmnd->underflow)) {
-			lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
-					"%d (%d):0717 FCP command x%x residual "
-					"underrun converted to error "
-					"Data: x%x x%x x%x\n",
-					phba->brd_no, vpi, cmnd->cmnd[0],
-					scsi_bufflen(cmnd),
-					scsi_get_resid(cmnd), cmnd->underflow);
+			lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
+					 "0717 FCP command x%x residual "
+					 "underrun converted to error "
+					 "Data: x%x x%x x%x\n",
+					 cmnd->cmnd[0], scsi_bufflen(cmnd),
+					 scsi_get_resid(cmnd), cmnd->underflow);
 			host_status = DID_ERROR;
 		}
 	} else if (resp_info & RESID_OVER) {
-		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
-				"%d (%d):0720 FCP command x%x residual "
-				"overrun error. Data: x%x x%x \n",
-				phba->brd_no, vpi, cmnd->cmnd[0],
-				scsi_bufflen(cmnd), scsi_get_resid(cmnd));
+		lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+				 "0720 FCP command x%x residual overrun error. "
+				 "Data: x%x x%x \n", cmnd->cmnd[0],
+				 scsi_bufflen(cmnd), scsi_get_resid(cmnd));
 		host_status = DID_ERROR;
 
 	/*
@@ -527,13 +516,12 @@
 	 */
 	} else if ((scsi_status == SAM_STAT_GOOD) && fcpi_parm &&
 			(cmnd->sc_data_direction == DMA_FROM_DEVICE)) {
-		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR,
-				"%d (%d):0734 FCP Read Check Error Data: "
-				"x%x x%x x%x x%x\n",
-				phba->brd_no, vpi,
-				be32_to_cpu(fcpcmd->fcpDl),
-				be32_to_cpu(fcprsp->rspResId),
-				fcpi_parm, cmnd->cmnd[0]);
+		lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR,
+				 "0734 FCP Read Check Error Data: "
+				 "x%x x%x x%x x%x\n",
+				 be32_to_cpu(fcpcmd->fcpDl),
+				 be32_to_cpu(fcprsp->rspResId),
+				 fcpi_parm, cmnd->cmnd[0]);
 		host_status = DID_ERROR;
 		scsi_set_resid(cmnd, scsi_bufflen(cmnd));
 	}
@@ -552,9 +540,6 @@
 	struct lpfc_rport_data *rdata = lpfc_cmd->rdata;
 	struct lpfc_nodelist *pnode = rdata->pnode;
 	struct scsi_cmnd *cmd = lpfc_cmd->pCmd;
-	uint32_t vpi = (lpfc_cmd->cur_iocbq.vport
-			? lpfc_cmd->cur_iocbq.vport->vpi
-			: 0);
 	int result;
 	struct scsi_device *sdev, *tmp_sdev;
 	int depth = 0;
@@ -569,15 +554,15 @@
 		else if (lpfc_cmd->status >= IOSTAT_CNT)
 			lpfc_cmd->status = IOSTAT_DEFAULT;
 
-		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
-				"%d (%d):0729 FCP cmd x%x failed <%d/%d> "
-				"status: x%x result: x%x Data: x%x x%x\n",
-				phba->brd_no, vpi, cmd->cmnd[0],
-				cmd->device ? cmd->device->id : 0xffff,
-				cmd->device ? cmd->device->lun : 0xffff,
-				lpfc_cmd->status, lpfc_cmd->result,
-				pIocbOut->iocb.ulpContext,
-				lpfc_cmd->cur_iocbq.iocb.ulpIoTag);
+		lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+				 "0729 FCP cmd x%x failed <%d/%d> "
+				 "status: x%x result: x%x Data: x%x x%x\n",
+				 cmd->cmnd[0],
+				 cmd->device ? cmd->device->id : 0xffff,
+				 cmd->device ? cmd->device->lun : 0xffff,
+				 lpfc_cmd->status, lpfc_cmd->result,
+				 pIocbOut->iocb.ulpContext,
+				 lpfc_cmd->cur_iocbq.iocb.ulpIoTag);
 
 		switch (lpfc_cmd->status) {
 		case IOSTAT_FCP_RSP_ERROR:
@@ -610,13 +595,12 @@
 	if (cmd->result || lpfc_cmd->fcp_rsp->rspSnsLen) {
 		uint32_t *lp = (uint32_t *)cmd->sense_buffer;
 
-		lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
-				"%d (%d):0710 Iodone <%d/%d> cmd %p, error "
-				"x%x SNS x%x x%x Data: x%x x%x\n",
-				phba->brd_no, vpi, cmd->device->id,
-				cmd->device->lun, cmd, cmd->result,
-				*lp, *(lp + 3), cmd->retries,
-				scsi_get_resid(cmd));
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
+				 "0710 Iodone <%d/%d> cmd %p, error "
+				 "x%x SNS x%x x%x Data: x%x x%x\n",
+				 cmd->device->id, cmd->device->lun, cmd,
+				 cmd->result, *lp, *(lp + 3), cmd->retries,
+				 scsi_get_resid(cmd));
 	}
 
 	result = cmd->result;
@@ -631,16 +615,16 @@
 
 
 	if (!result)
-		lpfc_rampup_queue_depth(phba, sdev);
+		lpfc_rampup_queue_depth(vport, sdev);
 
 	if (!result && pnode != NULL &&
 	   ((jiffies - pnode->last_ramp_up_time) >
 		LPFC_Q_RAMP_UP_INTERVAL * HZ) &&
 	   ((jiffies - pnode->last_q_full_time) >
 		LPFC_Q_RAMP_UP_INTERVAL * HZ) &&
-	   (phba->cfg_lun_queue_depth > sdev->queue_depth)) {
+	   (vport->cfg_lun_queue_depth > sdev->queue_depth)) {
 		shost_for_each_device(tmp_sdev, sdev->host) {
-			if (phba->cfg_lun_queue_depth > tmp_sdev->queue_depth) {
+			if (vport->cfg_lun_queue_depth > tmp_sdev->queue_depth){
 				if (tmp_sdev->id != sdev->id)
 					continue;
 				if (tmp_sdev->ordered_tags)
@@ -680,10 +664,9 @@
 			depth = sdev->host->cmd_per_lun;
 
 		if (depth) {
-			lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
-					"%d (%d):0711 detected queue full - "
-					"lun queue depth  adjusted to %d.\n",
-					phba->brd_no, vpi, depth);
+			lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+					 "0711 detected queue full - lun queue "
+					 "depth adjusted to %d.\n", depth);
 		}
 	}
 
@@ -853,12 +836,9 @@
 		return FAILED;
 
 	/* Issue Target Reset to TGT <num> */
-	lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
-			"%d (%d):0702 Issue Target Reset to TGT %d "
-			"Data: x%x x%x\n",
-			phba->brd_no, vport->vpi, tgt_id,
-			rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
+			 "0702 Issue Target Reset to TGT %d Data: x%x x%x\n",
+			 tgt_id, rdata->pnode->nlp_rpi, rdata->pnode->nlp_flag);
 	ret = lpfc_sli_issue_iocb_wait(phba,
 				       &phba->sli.ring[phba->sli.fcp_ring],
 				       iocbq, iocbqrsp, lpfc_cmd->timeout);
@@ -965,10 +945,9 @@
 	if (lpfc_cmd == NULL) {
 		lpfc_adjust_queue_depth(phba);
 
-		lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
-				"%d (%d):0707 driver's buffer pool is empty, "
-				"IO busied\n",
-				phba->brd_no, vport->vpi);
+		lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
+				 "0707 driver's buffer pool is empty, "
+				 "IO busied\n");
 		goto out_host_busy;
 	}
 
@@ -1103,28 +1082,25 @@
 
 		schedule_timeout_uninterruptible(LPFC_ABORT_WAIT * HZ);
 		if (++loop_count
-		    > (2 * phba->cfg_devloss_tmo)/LPFC_ABORT_WAIT)
+		    > (2 * vport->cfg_devloss_tmo)/LPFC_ABORT_WAIT)
 			break;
 	}
 
 	if (lpfc_cmd->pCmd == cmnd) {
 		ret = FAILED;
-		lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-				"%d (%d):0748 abort handler timed out waiting "
-				"for abort to complete: ret %#x, ID %d, "
-				"LUN %d, snum %#lx\n",
-				phba->brd_no, vport->vpi, ret,
-				cmnd->device->id, cmnd->device->lun,
-				cmnd->serial_number);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+				 "0748 abort handler timed out waiting "
+				 "for abort to complete: ret %#x, ID %d, "
+				 "LUN %d, snum %#lx\n",
+				 ret, cmnd->device->id, cmnd->device->lun,
+				 cmnd->serial_number);
 	}
 
  out:
-	lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
-			"%d (%d):0749 SCSI Layer I/O Abort Request "
-			"Status x%x ID %d LUN %d snum %#lx\n",
-			phba->brd_no, vport->vpi, ret, cmnd->device->id,
-			cmnd->device->lun, cmnd->serial_number);
-
+	lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+			 "0749 SCSI Layer I/O Abort Request Status x%x ID %d "
+			 "LUN %d snum %#lx\n", ret, cmnd->device->id,
+			 cmnd->device->lun, cmnd->serial_number);
 	return ret;
 }
 
@@ -1158,12 +1134,11 @@
 			loopcnt++;
 			rdata = cmnd->device->hostdata;
 			if (!rdata ||
-				(loopcnt > ((phba->cfg_devloss_tmo * 2) + 1))) {
-				lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-						"%d (%d):0721 LUN Reset rport "
-						"failure: cnt x%x rdata x%p\n",
-						phba->brd_no, vport->vpi,
-						loopcnt, rdata);
+				(loopcnt > ((vport->cfg_devloss_tmo * 2) + 1))){
+				lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+						 "0721 LUN Reset rport "
+						 "failure: cnt x%x rdata x%p\n",
+						 loopcnt, rdata);
 				goto out;
 			}
 			pnode = rdata->pnode;
@@ -1193,12 +1168,10 @@
 	if (iocbqrsp == NULL)
 		goto out_free_scsi_buf;
 
-	lpfc_printf_log(phba, KERN_INFO, LOG_FCP,
-			"%d (%d):0703 Issue target reset to TGT %d LUN %d "
-			"rpi x%x nlp_flag x%x\n",
-			phba->brd_no, vport->vpi, cmnd->device->id,
-			cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag);
-
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP,
+			 "0703 Issue target reset to TGT %d LUN %d "
+			 "rpi x%x nlp_flag x%x\n", cmnd->device->id,
+			 cmnd->device->lun, pnode->nlp_rpi, pnode->nlp_flag);
 	iocb_status = lpfc_sli_issue_iocb_wait(phba,
 				       &phba->sli.ring[phba->sli.fcp_ring],
 				       iocbq, iocbqrsp, lpfc_cmd->timeout);
@@ -1221,33 +1194,28 @@
 	 * Unfortunately, some targets do not abide by this forcing the driver
 	 * to double check.
 	 */
-	cnt = lpfc_sli_sum_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
-				cmnd->device->id, cmnd->device->lun,
+	cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id, cmnd->device->lun,
 				LPFC_CTX_LUN);
 	if (cnt)
-		lpfc_sli_abort_iocb(phba,
-				    &phba->sli.ring[phba->sli.fcp_ring],
+		lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring],
 				    cmnd->device->id, cmnd->device->lun,
-				    0, LPFC_CTX_LUN);
+				    LPFC_CTX_LUN);
 	loopcnt = 0;
 	while(cnt) {
 		schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ);
 
 		if (++loopcnt
-		    > (2 * phba->cfg_devloss_tmo)/LPFC_RESET_WAIT)
+		    > (2 * vport->cfg_devloss_tmo)/LPFC_RESET_WAIT)
 			break;
 
-		cnt = lpfc_sli_sum_iocb(phba,
-					&phba->sli.ring[phba->sli.fcp_ring],
-					cmnd->device->id, cmnd->device->lun,
-					LPFC_CTX_LUN);
+		cnt = lpfc_sli_sum_iocb(vport, cmnd->device->id,
+					cmnd->device->lun, LPFC_CTX_LUN);
 	}
 
 	if (cnt) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-				"%d (%d):0719 device reset I/O flush failure: "
-				"cnt x%x\n",
-				phba->brd_no, vport->vpi, cnt);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+				 "0719 device reset I/O flush failure: "
+				 "cnt x%x\n", cnt);
 		ret = FAILED;
 	}
 
@@ -1255,12 +1223,11 @@
 	if (iocb_status != IOCB_TIMEDOUT) {
 		lpfc_release_scsi_buf(phba, lpfc_cmd);
 	}
-	lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-			"%d (%d):0713 SCSI layer issued device reset (%d, %d) "
-			"return x%x status x%x result x%x\n",
-			phba->brd_no, vport->vpi, cmnd->device->id,
-			cmnd->device->lun, ret, cmd_status, cmd_result);
-
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+			 "0713 SCSI layer issued device reset (%d, %d) "
+			 "return x%x status x%x result x%x\n",
+			 cmnd->device->id, cmnd->device->lun, ret,
+			 cmd_status, cmd_result);
 out:
 	return ret;
 }
@@ -1311,10 +1278,9 @@
 					  cmnd->device->lun,
 					  ndlp->rport->dd_data);
 		if (ret != SUCCESS) {
-			lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-					"%d (%d):0700 Bus Reset on target %d "
-					"failed\n",
-					phba->brd_no, vport->vpi, i);
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+					 "0700 Bus Reset on target %d failed\n",
+					 i);
 			err_count++;
 			break;
 		}
@@ -1333,35 +1299,30 @@
 	 * the targets.  Unfortunately, some targets do not abide by
 	 * this forcing the driver to double check.
 	 */
-	cnt = lpfc_sli_sum_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
-				0, 0, LPFC_CTX_HOST);
+	cnt = lpfc_sli_sum_iocb(vport, 0, 0, LPFC_CTX_HOST);
 	if (cnt)
-		lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
-				    0, 0, 0, LPFC_CTX_HOST);
+		lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring],
+				    0, 0, LPFC_CTX_HOST);
 	loopcnt = 0;
 	while(cnt) {
 		schedule_timeout_uninterruptible(LPFC_RESET_WAIT*HZ);
 
 		if (++loopcnt
-		    > (2 * phba->cfg_devloss_tmo)/LPFC_RESET_WAIT)
+		    > (2 * vport->cfg_devloss_tmo)/LPFC_RESET_WAIT)
 			break;
 
-		cnt = lpfc_sli_sum_iocb(phba,
-					&phba->sli.ring[phba->sli.fcp_ring],
-					0, 0, LPFC_CTX_HOST);
+		cnt = lpfc_sli_sum_iocb(vport, 0, 0, LPFC_CTX_HOST);
 	}
 
 	if (cnt) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-				"%d (%d):0715 Bus Reset I/O flush failure: "
-				"cnt x%x left x%x\n",
-				phba->brd_no, vport->vpi, cnt, i);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+				 "0715 Bus Reset I/O flush failure: "
+				 "cnt x%x left x%x\n", cnt, i);
 		ret = FAILED;
 	}
 
-	lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-			"%d (%d):0714 SCSI layer issued Bus Reset Data: x%x\n",
-			phba->brd_no, vport->vpi, ret);
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+			 "0714 SCSI layer issued Bus Reset Data: x%x\n", ret);
 out:
 	return ret;
 }
@@ -1390,36 +1351,32 @@
 	 * extra.  This list of scsi bufs exists for the lifetime of the driver.
 	 */
 	total = phba->total_scsi_bufs;
-	num_to_alloc = phba->cfg_lun_queue_depth + 2;
+	num_to_alloc = vport->cfg_lun_queue_depth + 2;
 
 	/* Allow some exchanges to be available always to complete discovery */
 	if (total >= phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) {
-		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
-				"%d (%d):0704 At limitation of %d "
-				"preallocated command buffers\n",
-				phba->brd_no, vport->vpi, total);
+		lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+				 "0704 At limitation of %d preallocated "
+				 "command buffers\n", total);
 		return 0;
-
 	/* Allow some exchanges to be available always to complete discovery */
 	} else if (total + num_to_alloc >
 		phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) {
-		lpfc_printf_log(phba, KERN_WARNING, LOG_FCP,
-				"%d (%d):0705 Allocation request of %d "
-				"command buffers will exceed max of %d.  "
-				"Reducing allocation request to %d.\n",
-				phba->brd_no, vport->vpi, num_to_alloc,
-				phba->cfg_hba_queue_depth,
-				(phba->cfg_hba_queue_depth - total));
+		lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
+				 "0705 Allocation request of %d "
+				 "command buffers will exceed max of %d.  "
+				 "Reducing allocation request to %d.\n",
+				 num_to_alloc, phba->cfg_hba_queue_depth,
+				 (phba->cfg_hba_queue_depth - total));
 		num_to_alloc = phba->cfg_hba_queue_depth - total;
 	}
 
 	for (i = 0; i < num_to_alloc; i++) {
 		scsi_buf = lpfc_new_scsi_buf(vport);
 		if (!scsi_buf) {
-			lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
-					"%d (%d):0706 Failed to allocate "
-					"command buffer\n",
-					phba->brd_no, vport->vpi);
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP,
+					 "0706 Failed to allocate "
+					 "command buffer\n");
 			break;
 		}
 
@@ -1439,9 +1396,9 @@
 	struct fc_rport   *rport = starget_to_rport(sdev->sdev_target);
 
 	if (sdev->tagged_supported)
-		scsi_activate_tcq(sdev, phba->cfg_lun_queue_depth);
+		scsi_activate_tcq(sdev, vport->cfg_lun_queue_depth);
 	else
-		scsi_deactivate_tcq(sdev, phba->cfg_lun_queue_depth);
+		scsi_deactivate_tcq(sdev, vport->cfg_lun_queue_depth);
 
 	/*
 	 * Initialize the fc transport attributes for the target
@@ -1449,7 +1406,7 @@
 	 * target pointer is stored in the starget_data for the
 	 * driver's sysfs entry point functions.
 	 */
-	rport->dev_loss_tmo = phba->cfg_devloss_tmo;
+	rport->dev_loss_tmo = vport->cfg_devloss_tmo;
 
 	if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
 		lpfc_sli_poll_fcp_ring(phba);
@@ -1487,3 +1444,23 @@
 	.shost_attrs		= lpfc_hba_attrs,
 	.max_sectors		= 0xFFFF,
 };
+
+struct scsi_host_template lpfc_vport_template = {
+	.module			= THIS_MODULE,
+	.name			= LPFC_DRIVER_NAME,
+	.info			= lpfc_info,
+	.queuecommand		= lpfc_queuecommand,
+	.eh_abort_handler	= lpfc_abort_handler,
+	.eh_device_reset_handler= lpfc_device_reset_handler,
+	.eh_bus_reset_handler	= lpfc_bus_reset_handler,
+	.slave_alloc		= lpfc_slave_alloc,
+	.slave_configure	= lpfc_slave_configure,
+	.slave_destroy		= lpfc_slave_destroy,
+	.scan_finished		= lpfc_scan_finished,
+	.this_id		= -1,
+	.sg_tablesize		= LPFC_SG_SEG_CNT,
+	.cmd_per_lun		= LPFC_CMD_PER_LUN,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.shost_attrs		= lpfc_vport_attrs,
+	.max_sectors		= 0xFFFF,
+};
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index f4d5a6b..ce5ff2b 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -49,9 +49,8 @@
 			lpfc_printf_log(phba, \
 				KERN_INFO, \
 				LOG_MBOX | LOG_SLI, \
-				"%d (%d):0311 Mailbox command x%x cannot " \
+				"(%d):0311 Mailbox command x%x cannot " \
 				"issue Data: x%x x%x x%x\n", \
-				phba->brd_no, \
 				pmbox->vport ? pmbox->vport->vpi : 0, \
 				pmbox->mb.mbxCommand,		\
 				phba->pport->port_state,	\
@@ -231,13 +230,11 @@
 		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
 		if (rc != MBX_SUCCESS) {
 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-					"%d:0446 Adapter failed to init (%d), "
+					"0446 Adapter failed to init (%d), "
 					"mbxCmd x%x CFG_RING, mbxStatus x%x, "
 					"ring %d\n",
-					phba->brd_no, rc,
-					pmbox->mbxCommand,
-					pmbox->mbxStatus,
-					i);
+					rc, pmbox->mbxCommand,
+					pmbox->mbxStatus, i);
 			phba->link_state = LPFC_HBA_ERROR;
 			ret = -ENXIO;
 			break;
@@ -296,9 +293,9 @@
 
 		if (unlikely(pring->local_getidx >= max_cmd_idx)) {
 			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-					"%d:0315 Ring %d issue: portCmdGet %d "
+					"0315 Ring %d issue: portCmdGet %d "
 					"is bigger then cmd ring %d\n",
-					phba->brd_no, pring->ringno,
+					pring->ringno,
 					pring->local_getidx, max_cmd_idx);
 
 			phba->link_state = LPFC_HBA_ERROR;
@@ -366,7 +363,7 @@
 			if (psli->iocbq_lookup)
 				memcpy(new_arr, old_arr,
 				       ((psli->last_iotag  + 1) *
-	 				sizeof (struct lpfc_iocbq *)));
+					sizeof (struct lpfc_iocbq *)));
 			psli->iocbq_lookup = new_arr;
 			psli->iocbq_lookup_len = new_len;
 			psli->last_iotag = iotag;
@@ -380,8 +377,8 @@
 		spin_unlock_irq(&phba->hbalock);
 
 	lpfc_printf_log(phba, KERN_ERR,LOG_SLI,
-			"%d:0318 Failed to allocate IOTAG.last IOTAG is %d\n",
-			phba->brd_no, psli->last_iotag);
+			"0318 Failed to allocate IOTAG.last IOTAG is %d\n",
+			psli->last_iotag);
 
 	return 0;
 }
@@ -395,6 +392,14 @@
 	 */
 	nextiocb->iocb.ulpIoTag = (nextiocb->iocb_cmpl) ? nextiocb->iotag : 0;
 
+	if (pring->ringno == LPFC_ELS_RING) {
+		lpfc_debugfs_slow_ring_trc(phba,
+			"IOCB cmd ring:   wd4:x%08x wd6:x%08x wd7:x%08x",
+			*(((uint32_t *) &nextiocb->iocb) + 4),
+			*(((uint32_t *) &nextiocb->iocb) + 6),
+			*(((uint32_t *) &nextiocb->iocb) + 7));
+	}
+
 	/*
 	 * Issue iocb command to adapter
 	 */
@@ -527,10 +532,9 @@
 		if (unlikely(hbqp->local_hbqGetIdx >= hbqp->entry_count)) {
 			lpfc_printf_log(phba, KERN_ERR,
 					LOG_SLI | LOG_VPORT,
-					"%d:1802 HBQ %d: local_hbqGetIdx "
+					"1802 HBQ %d: local_hbqGetIdx "
 					"%u is > than hbqp->entry_count %u\n",
-					phba->brd_no, hbqno,
-					hbqp->local_hbqGetIdx,
+					hbqno, hbqp->local_hbqGetIdx,
 					hbqp->entry_count);
 
 			phba->link_state = LPFC_HBA_ERROR;
@@ -541,7 +545,8 @@
 			return NULL;
 	}
 
-	return (struct lpfc_hbq_entry *) phba->hbqslimp.virt + hbqp->hbqPutIdx;
+	return (struct lpfc_hbq_entry *) phba->hbqs[hbqno].hbq_virt +
+			hbqp->hbqPutIdx;
 }
 
 void
@@ -549,18 +554,21 @@
 {
 	struct lpfc_dmabuf *dmabuf, *next_dmabuf;
 	struct hbq_dmabuf *hbq_buf;
+	int i, hbq_count;
 
+	hbq_count = lpfc_sli_hbq_count();
 	/* Return all memory used by all HBQs */
-	list_for_each_entry_safe(dmabuf, next_dmabuf,
-				 &phba->hbq_buffer_list, list) {
-		hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf);
-		list_del(&hbq_buf->dbuf.list);
-		lpfc_hbq_free(phba, hbq_buf->dbuf.virt, hbq_buf->dbuf.phys);
-		kfree(hbq_buf);
+	for (i = 0; i < hbq_count; ++i) {
+		list_for_each_entry_safe(dmabuf, next_dmabuf,
+				&phba->hbqs[i].hbq_buffer_list, list) {
+			hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf);
+			list_del(&hbq_buf->dbuf.list);
+			(phba->hbqs[i].hbq_free_buffer)(phba, hbq_buf);
+		}
 	}
 }
 
-static void
+static struct lpfc_hbq_entry *
 lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno,
 			 struct hbq_dmabuf *hbq_buf)
 {
@@ -574,7 +582,7 @@
 
 		hbqe->bde.addrHigh = le32_to_cpu(putPaddrHigh(physaddr));
 		hbqe->bde.addrLow  = le32_to_cpu(putPaddrLow(physaddr));
-		hbqe->bde.tus.f.bdeSize = FCELSSIZE;
+		hbqe->bde.tus.f.bdeSize = hbq_buf->size;
 		hbqe->bde.tus.f.bdeFlags = 0;
 		hbqe->bde.tus.w = le32_to_cpu(hbqe->bde.tus.w);
 		hbqe->buffer_tag = le32_to_cpu(hbq_buf->tag);
@@ -583,8 +591,9 @@
 		writel(hbqp->hbqPutIdx, phba->hbq_put + hbqno);
 				/* flush */
 		readl(phba->hbq_put + hbqno);
-		list_add_tail(&hbq_buf->dbuf.list, &phba->hbq_buffer_list);
+		list_add_tail(&hbq_buf->dbuf.list, &hbqp->hbq_buffer_list);
 	}
+	return hbqe;
 }
 
 static struct lpfc_hbq_init lpfc_els_hbq = {
@@ -592,22 +601,38 @@
 	.entry_count = 200,
 	.mask_count = 0,
 	.profile = 0,
-	.ring_mask = 1 << LPFC_ELS_RING,
+	.ring_mask = (1 << LPFC_ELS_RING),
 	.buffer_count = 0,
 	.init_count = 20,
 	.add_count = 5,
 };
 
-static struct lpfc_hbq_init *lpfc_hbq_defs[] = {
-	&lpfc_els_hbq,
+static struct lpfc_hbq_init lpfc_extra_hbq = {
+	.rn = 1,
+	.entry_count = 200,
+	.mask_count = 0,
+	.profile = 0,
+	.ring_mask = (1 << LPFC_EXTRA_RING),
+	.buffer_count = 0,
+	.init_count = 0,
+	.add_count = 5,
 };
 
-int
+struct lpfc_hbq_init *lpfc_hbq_defs[] = {
+	&lpfc_els_hbq,
+	&lpfc_extra_hbq,
+};
+
+static int
 lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count)
 {
 	uint32_t i, start, end;
 	struct hbq_dmabuf *hbq_buffer;
 
+	if (!phba->hbqs[hbqno].hbq_alloc_buffer) {
+		return 0;
+	}
+
 	start = lpfc_hbq_defs[hbqno]->buffer_count;
 	end = count + lpfc_hbq_defs[hbqno]->buffer_count;
 	if (end > lpfc_hbq_defs[hbqno]->entry_count) {
@@ -616,17 +641,14 @@
 
 	/* Populate HBQ entries */
 	for (i = start; i < end; i++) {
-		hbq_buffer = kmalloc(sizeof(struct hbq_dmabuf),
-				     GFP_KERNEL);
+		hbq_buffer = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba);
 		if (!hbq_buffer)
 			return 1;
-		hbq_buffer->dbuf.virt = lpfc_hbq_alloc(phba, MEM_PRI,
-							&hbq_buffer->dbuf.phys);
-		if (hbq_buffer->dbuf.virt == NULL)
-			return 1;
 		hbq_buffer->tag = (i | (hbqno << 16));
-		lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer);
-		lpfc_hbq_defs[hbqno]->buffer_count++;
+		if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer))
+			lpfc_hbq_defs[hbqno]->buffer_count++;
+		else
+			(phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
 	}
 	return 0;
 }
@@ -650,28 +672,34 @@
 {
 	struct lpfc_dmabuf *d_buf;
 	struct hbq_dmabuf *hbq_buf;
+	uint32_t hbqno;
 
-	list_for_each_entry(d_buf, &phba->hbq_buffer_list, list) {
+	hbqno = tag >> 16;
+	if (hbqno > LPFC_MAX_HBQS)
+		return NULL;
+
+	list_for_each_entry(d_buf, &phba->hbqs[hbqno].hbq_buffer_list, list) {
 		hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf);
-		if ((hbq_buf->tag & 0xffff) == tag) {
+		if (hbq_buf->tag == tag) {
 			return hbq_buf;
 		}
 	}
 	lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT,
-			"%d:1803 Bad hbq tag. Data: x%x x%x\n",
-			phba->brd_no, tag,
-			lpfc_hbq_defs[tag >> 16]->buffer_count);
+			"1803 Bad hbq tag. Data: x%x x%x\n",
+			tag, lpfc_hbq_defs[tag >> 16]->buffer_count);
 	return NULL;
 }
 
 void
-lpfc_sli_free_hbq(struct lpfc_hba *phba, struct hbq_dmabuf *sp)
+lpfc_sli_free_hbq(struct lpfc_hba *phba, struct hbq_dmabuf *hbq_buffer)
 {
 	uint32_t hbqno;
 
-	if (sp) {
-		hbqno = sp->tag >> 16;
-		lpfc_sli_hbq_to_firmware(phba, hbqno, sp);
+	if (hbq_buffer) {
+		hbqno = hbq_buffer->tag >> 16;
+		if (!lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) {
+			(phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer);
+		}
 	}
 }
 
@@ -837,12 +865,10 @@
 		 */
 		if (lpfc_sli_chk_mbx_command(pmbox->mbxCommand) ==
 		    MBX_SHUTDOWN) {
-
 			/* Unknow mailbox command compl */
 			lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
-					"%d (%d):0323 Unknown Mailbox command "
+					"(%d):0323 Unknown Mailbox command "
 					"%x Cmpl\n",
-					phba->brd_no,
 					pmb->vport ? pmb->vport->vpi : 0,
 					pmbox->mbxCommand);
 			phba->link_state = LPFC_HBA_ERROR;
@@ -857,10 +883,9 @@
 				/* Mbox cmd cmpl error - RETRYing */
 				lpfc_printf_log(phba, KERN_INFO,
 						LOG_MBOX | LOG_SLI,
-						"%d (%d):0305 Mbox cmd cmpl "
+						"(%d):0305 Mbox cmd cmpl "
 						"error - RETRYing Data: x%x "
 						"x%x x%x x%x\n",
-						phba->brd_no,
 						pmb->vport ? pmb->vport->vpi :0,
 						pmbox->mbxCommand,
 						pmbox->mbxStatus,
@@ -879,9 +904,8 @@
 
 		/* Mailbox cmd <cmd> Cmpl <cmpl> */
 		lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
-				"%d (%d):0307 Mailbox cmd x%x Cmpl x%p "
+				"(%d):0307 Mailbox cmd x%x Cmpl x%p "
 				"Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x\n",
-				phba->brd_no,
 				pmb->vport ? pmb->vport->vpi : 0,
 				pmbox->mbxCommand,
 				pmb->mbox_cmpl,
@@ -905,21 +929,26 @@
 lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
 {
 	struct hbq_dmabuf *hbq_entry, *new_hbq_entry;
+	uint32_t hbqno;
+	void *virt;		/* virtual address ptr */
+	dma_addr_t phys;	/* mapped address */
 
 	hbq_entry = lpfc_sli_hbqbuf_find(phba, tag);
 	if (hbq_entry == NULL)
 		return NULL;
 	list_del(&hbq_entry->dbuf.list);
-	new_hbq_entry = kmalloc(sizeof(struct hbq_dmabuf), GFP_ATOMIC);
+
+	hbqno = tag >> 16;
+	new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba);
 	if (new_hbq_entry == NULL)
 		return &hbq_entry->dbuf;
-	new_hbq_entry->dbuf = hbq_entry->dbuf;
 	new_hbq_entry->tag = -1;
-	hbq_entry->dbuf.virt = lpfc_hbq_alloc(phba, 0, &hbq_entry->dbuf.phys);
-	if (hbq_entry->dbuf.virt == NULL) {
-		kfree(new_hbq_entry);
-		return &hbq_entry->dbuf;
-	}
+	phys = new_hbq_entry->dbuf.phys;
+	virt = new_hbq_entry->dbuf.virt;
+	new_hbq_entry->dbuf.phys = hbq_entry->dbuf.phys;
+	new_hbq_entry->dbuf.virt = hbq_entry->dbuf.virt;
+	hbq_entry->dbuf.phys = phys;
+	hbq_entry->dbuf.virt = virt;
 	lpfc_sli_free_hbq(phba, hbq_entry);
 	return &new_hbq_entry->dbuf;
 }
@@ -965,7 +994,7 @@
 						irsp->un.ulpWord[3]);
 		if (irsp->ulpBdeCount == 2)
 			saveq->context3 = lpfc_sli_replace_hbqbuff(phba,
-						irsp->un.ulpWord[15]);
+						irsp->unsli3.sli3Words[7]);
 	}
 
 	/* unSolicited Responses */
@@ -996,12 +1025,9 @@
 		/* Ring <ringno> handler: unexpected
 		   Rctl <Rctl> Type <Type> received */
 		lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
-				"%d:0313 Ring %d handler: unexpected Rctl x%x "
+				"0313 Ring %d handler: unexpected Rctl x%x "
 				"Type x%x received\n",
-				phba->brd_no,
-				pring->ringno,
-				Rctl,
-				Type);
+				pring->ringno, Rctl, Type);
 	}
 	return 1;
 }
@@ -1024,10 +1050,9 @@
 	}
 
 	lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-			"%d:0317 iotag x%x is out off "
+			"0317 iotag x%x is out off "
 			"range: max iotag x%x wd0 x%x\n",
-			phba->brd_no, iotag,
-			phba->sli.last_iotag,
+			iotag, phba->sli.last_iotag,
 			*(((uint32_t *) &prspiocb->iocb) + 7));
 	return NULL;
 }
@@ -1075,18 +1100,16 @@
 			 * Ring <ringno> handler: unexpected completion IoTag
 			 * <IoTag>
 			 */
-			lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
-					"%d (%d):0322 Ring %d handler: "
-					"unexpected completion IoTag x%x "
-					"Data: x%x x%x x%x x%x\n",
-					phba->brd_no,
-					cmdiocbp->vport->vpi,
-					pring->ringno,
-					saveq->iocb.ulpIoTag,
-					saveq->iocb.ulpStatus,
-					saveq->iocb.un.ulpWord[4],
-					saveq->iocb.ulpCommand,
-					saveq->iocb.ulpContext);
+			lpfc_printf_vlog(cmdiocbp->vport, KERN_WARNING, LOG_SLI,
+					 "0322 Ring %d handler: "
+					 "unexpected completion IoTag x%x "
+					 "Data: x%x x%x x%x x%x\n",
+					 pring->ringno,
+					 saveq->iocb.ulpIoTag,
+					 saveq->iocb.ulpStatus,
+					 saveq->iocb.un.ulpWord[4],
+					 saveq->iocb.ulpCommand,
+					 saveq->iocb.ulpContext);
 		}
 	}
 
@@ -1104,10 +1127,9 @@
 	 * rsp ring <portRspMax>
 	 */
 	lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-			"%d:0312 Ring %d handler: portRspPut %d "
+			"0312 Ring %d handler: portRspPut %d "
 			"is bigger then rsp ring %d\n",
-			phba->brd_no, pring->ringno,
-			le32_to_cpu(pgp->rspPutInx),
+			pring->ringno, le32_to_cpu(pgp->rspPutInx),
 			pring->numRiocb);
 
 	phba->link_state = LPFC_HBA_ERROR;
@@ -1177,9 +1199,9 @@
 		if (unlikely(irsp->ulpStatus)) {
 			/* Rsp ring <ringno> error: IOCB */
 			lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
-					"%d:0326 Rsp Ring %d error: IOCB Data: "
+					"0326 Rsp Ring %d error: IOCB Data: "
 					"x%x x%x x%x x%x x%x x%x x%x x%x\n",
-					phba->brd_no, pring->ringno,
+					pring->ringno,
 					irsp->un.ulpWord[0],
 					irsp->un.ulpWord[1],
 					irsp->un.ulpWord[2],
@@ -1199,9 +1221,9 @@
 			 */
 			if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) {
 				lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-						"%d:0314 IOCB cmd 0x%x"
-						" processed. Skipping"
-						" completion", phba->brd_no,
+						"0314 IOCB cmd 0x%x "
+						"processed. Skipping "
+						"completion",
 						irsp->ulpCommand);
 				break;
 			}
@@ -1226,10 +1248,9 @@
 			} else {
 				/* Unknown IOCB command */
 				lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-						"%d:0321 Unknown IOCB command "
+						"0321 Unknown IOCB command "
 						"Data: x%x, x%x x%x x%x x%x\n",
-						phba->brd_no, type,
-						irsp->ulpCommand,
+						type, irsp->ulpCommand,
 						irsp->ulpStatus,
 						irsp->ulpIoTag,
 						irsp->ulpContext);
@@ -1353,9 +1374,9 @@
 
 			/* Rsp ring <ringno> error: IOCB */
 			lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
-					"%d:0336 Rsp Ring %d error: IOCB Data: "
+					"0336 Rsp Ring %d error: IOCB Data: "
 					"x%x x%x x%x x%x x%x x%x x%x x%x\n",
-					phba->brd_no, pring->ringno,
+					pring->ringno,
 					irsp->un.ulpWord[0],
 					irsp->un.ulpWord[1],
 					irsp->un.ulpWord[2],
@@ -1375,10 +1396,9 @@
 			 */
 			if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) {
 				lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-						"%d:0333 IOCB cmd 0x%x"
+						"0333 IOCB cmd 0x%x"
 						" processed. Skipping"
 						" completion\n",
-						phba->brd_no,
 						irsp->ulpCommand);
 				break;
 			}
@@ -1415,10 +1435,9 @@
 			} else {
 				/* Unknown IOCB command */
 				lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-						"%d:0334 Unknown IOCB command "
+						"0334 Unknown IOCB command "
 						"Data: x%x, x%x x%x x%x x%x\n",
-						phba->brd_no, type,
-						irsp->ulpCommand,
+						type, irsp->ulpCommand,
 						irsp->ulpStatus,
 						irsp->ulpIoTag,
 						irsp->ulpContext);
@@ -1496,10 +1515,9 @@
 		 * rsp ring <portRspMax>
 		 */
 		lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-				"%d:0303 Ring %d handler: portRspPut %d "
+				"0303 Ring %d handler: portRspPut %d "
 				"is bigger then rsp ring %d\n",
-				phba->brd_no, pring->ringno, portRspPut,
-				portRspMax);
+				pring->ringno, portRspPut, portRspMax);
 
 		phba->link_state = LPFC_HBA_ERROR;
 		spin_unlock_irqrestore(&phba->hbalock, iflag);
@@ -1542,6 +1560,14 @@
 		if (++pring->rspidx >= portRspMax)
 			pring->rspidx = 0;
 
+		if (pring->ringno == LPFC_ELS_RING) {
+			lpfc_debugfs_slow_ring_trc(phba,
+			"IOCB rsp ring:   wd4:x%08x wd6:x%08x wd7:x%08x",
+				*(((uint32_t *) irsp) + 4),
+				*(((uint32_t *) irsp) + 6),
+				*(((uint32_t *) irsp) + 7));
+		}
+
 		writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx);
 
 		if (list_empty(&(pring->iocb_continueq))) {
@@ -1580,13 +1606,12 @@
 			if (irsp->ulpStatus) {
 				/* Rsp ring <ringno> error: IOCB */
 				lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
-						"%d:0328 Rsp Ring %d error: "
+						"0328 Rsp Ring %d error: "
 						"IOCB Data: "
 						"x%x x%x x%x x%x "
 						"x%x x%x x%x x%x "
 						"x%x x%x x%x x%x "
 						"x%x x%x x%x x%x\n",
-						phba->brd_no,
 						pring->ringno,
 						irsp->un.ulpWord[0],
 						irsp->un.ulpWord[1],
@@ -1661,10 +1686,9 @@
 				} else {
 					/* Unknown IOCB command */
 					lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-							"%d:0335 Unknown IOCB "
+							"0335 Unknown IOCB "
 							"command Data: x%x "
 							"x%x x%x x%x\n",
-							phba->brd_no,
 							irsp->ulpCommand,
 							irsp->ulpStatus,
 							irsp->ulpIoTag,
@@ -1892,8 +1916,8 @@
 
 	/* Kill HBA */
 	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-			"%d:0329 Kill HBA Data: x%x x%x\n",
-			phba->brd_no, phba->pport->port_state, psli->sli_flag);
+			"0329 Kill HBA Data: x%x x%x\n",
+			phba->pport->port_state, psli->sli_flag);
 
 	if ((pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
 						  GFP_KERNEL)) == 0)
@@ -1966,7 +1990,7 @@
 
 	/* Reset HBA */
 	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-			"%d:0325 Reset HBA Data: x%x x%x\n", phba->brd_no,
+			"0325 Reset HBA Data: x%x x%x\n",
 			phba->pport->port_state, psli->sli_flag);
 
 	/* perform board reset */
@@ -2021,7 +2045,7 @@
 
 	/* Restart HBA */
 	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-			"%d:0337 Restart HBA Data: x%x x%x\n", phba->brd_no,
+			"0337 Restart HBA Data: x%x x%x\n",
 			phba->pport->port_state, psli->sli_flag);
 
 	word0 = 0;
@@ -2086,9 +2110,8 @@
 			/* Adapter failed to init, timeout, status reg
 			   <status> */
 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-					"%d:0436 Adapter failed to init, "
-					"timeout, status reg x%x\n",
-					phba->brd_no, status);
+					"0436 Adapter failed to init, "
+					"timeout, status reg x%x\n", status);
 			phba->link_state = LPFC_HBA_ERROR;
 			return -ETIMEDOUT;
 		}
@@ -2099,10 +2122,8 @@
 			/* Adapter failed to init, chipset, status reg
 			   <status> */
 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-					"%d:0437 Adapter failed to init, "
-					"chipset, status reg x%x\n",
-					phba->brd_no,
-					status);
+					"0437 Adapter failed to init, "
+					"chipset, status reg x%x\n", status);
 			phba->link_state = LPFC_HBA_ERROR;
 			return -EIO;
 		}
@@ -2129,10 +2150,8 @@
 		/* ERROR: During chipset initialization */
 		/* Adapter failed to init, chipset, status reg <status> */
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"%d:0438 Adapter failed to init, chipset, "
-				"status reg x%x\n",
-				phba->brd_no,
-				status);
+				"0438 Adapter failed to init, chipset, "
+				"status reg x%x\n", status);
 		phba->link_state = LPFC_HBA_ERROR;
 		return -EIO;
 	}
@@ -2147,7 +2166,7 @@
 	return 0;
 }
 
-static int
+int
 lpfc_sli_hbq_count(void)
 {
 	return ARRAY_SIZE(lpfc_hbq_defs);
@@ -2200,8 +2219,8 @@
 		phba->hbqs[hbqno].local_hbqGetIdx   = 0;
 		phba->hbqs[hbqno].entry_count =
 			lpfc_hbq_defs[hbqno]->entry_count;
-		lpfc_config_hbq(phba, lpfc_hbq_defs[hbqno], hbq_entry_index,
-				pmb);
+		lpfc_config_hbq(phba, hbqno, lpfc_hbq_defs[hbqno],
+			hbq_entry_index, pmb);
 		hbq_entry_index += phba->hbqs[hbqno].entry_count;
 
 		if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
@@ -2210,9 +2229,9 @@
 
 			lpfc_printf_log(phba, KERN_ERR,
 					LOG_SLI | LOG_VPORT,
-					"%d:1805 Adapter failed to init. "
+					"1805 Adapter failed to init. "
 					"Data: x%x x%x x%x\n",
-					phba->brd_no, pmbox->mbxCommand,
+					pmbox->mbxCommand,
 					pmbox->mbxStatus, hbqno);
 
 			phba->link_state = LPFC_HBA_ERROR;
@@ -2279,10 +2298,9 @@
 		rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
 		if (rc != MBX_SUCCESS) {
 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"%d:0442 Adapter failed to init, mbxCmd x%x "
+				"0442 Adapter failed to init, mbxCmd x%x "
 				"CONFIG_PORT, mbxStatus x%x Data: x%x\n",
-				phba->brd_no, pmb->mb.mbxCommand,
-				pmb->mb.mbxStatus, 0);
+				pmb->mb.mbxCommand, pmb->mb.mbxStatus, 0);
 			spin_lock_irq(&phba->hbalock);
 			phba->sli.sli_flag &= ~LPFC_SLI2_ACTIVE;
 			spin_unlock_irq(&phba->hbalock);
@@ -2321,11 +2339,11 @@
 
 	switch (lpfc_sli_mode) {
 	case 2:
-		if (phba->cfg_npiv_enable) {
+		if (phba->cfg_enable_npiv) {
 			lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
-				"%d:1824 NPIV enabled: Override lpfc_sli_mode "
+				"1824 NPIV enabled: Override lpfc_sli_mode "
 				"parameter (%d) to auto (0).\n",
-				phba->brd_no, lpfc_sli_mode);
+				lpfc_sli_mode);
 			break;
 		}
 		mode = 2;
@@ -2335,9 +2353,8 @@
 		break;
 	default:
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
-				"%d:1819 Unrecognized lpfc_sli_mode "
-				"parameter: %d.\n",
-				phba->brd_no, lpfc_sli_mode);
+				"1819 Unrecognized lpfc_sli_mode "
+				"parameter: %d.\n", lpfc_sli_mode);
 
 		break;
 	}
@@ -2345,9 +2362,8 @@
 	rc = lpfc_do_config_port(phba, mode);
 	if (rc && lpfc_sli_mode == 3)
 		lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
-				"%d:1820 Unable to select SLI-3.  "
-				"Not supported by adapter.\n",
-				phba->brd_no);
+				"1820 Unable to select SLI-3.  "
+				"Not supported by adapter.\n");
 	if (rc && mode != 2)
 		rc = lpfc_do_config_port(phba, 2);
 	if (rc)
@@ -2366,8 +2382,8 @@
 	}
 
 	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-			"%d:0444 Firmware in SLI %x mode. Max_vpi %d\n",
-			phba->brd_no, phba->sli_rev, phba->max_vpi);
+			"0444 Firmware in SLI %x mode. Max_vpi %d\n",
+			phba->sli_rev, phba->max_vpi);
 	rc = lpfc_sli_ring_map(phba);
 
 	if (rc)
@@ -2392,8 +2408,7 @@
 lpfc_sli_hba_setup_error:
 	phba->link_state = LPFC_HBA_ERROR;
 	lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
-			"%d:0445 Firmware initialization failed\n",
-			phba->brd_no);
+			"0445 Firmware initialization failed\n");
 	return rc;
 }
 
@@ -2445,9 +2460,7 @@
 
 	/* Mbox cmd <mbxCommand> timeout */
 	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
-			"%d:0310 Mailbox command x%x timeout Data: x%x x%x "
-			"x%p\n",
-			phba->brd_no,
+			"0310 Mailbox command x%x timeout Data: x%x x%x x%p\n",
 			mb->mbxCommand,
 			phba->pport->port_state,
 			phba->sli.sli_flag,
@@ -2470,8 +2483,7 @@
 	lpfc_sli_abort_iocb_ring(phba, pring);
 
 	lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
-			"%d:0316 Resetting board due to mailbox timeout\n",
-			phba->brd_no);
+			"0316 Resetting board due to mailbox timeout\n");
 	/*
 	 * lpfc_offline calls lpfc_sli_hba_down which will clean up
 	 * on oustanding mailbox commands.
@@ -2502,8 +2514,7 @@
 		if(!pmbox->vport) {
 			lpfc_printf_log(phba, KERN_ERR,
 					LOG_MBOX | LOG_VPORT,
-					"%d:1806 Mbox x%x failed. No vport\n",
-					phba->brd_no,
+					"1806 Mbox x%x failed. No vport\n",
 					pmbox->mb.mbxCommand);
 			dump_stack();
 			return MBXERR_ERROR;
@@ -2580,9 +2591,8 @@
 
 		/* Mbox cmd issue - BUSY */
 		lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
-				"%d (%d):0308 Mbox cmd issue - BUSY Data: "
+				"(%d):0308 Mbox cmd issue - BUSY Data: "
 				"x%x x%x x%x x%x\n",
-				phba->brd_no,
 				pmbox->vport ? pmbox->vport->vpi : 0xffffff,
 				mb->mbxCommand, phba->pport->port_state,
 				psli->sli_flag, flag);
@@ -2644,9 +2654,9 @@
 
 	/* Mailbox cmd <cmd> issue */
 	lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI,
-			"%d (%d):0309 Mailbox cmd x%x issue Data: x%x x%x "
+			"(%d):0309 Mailbox cmd x%x issue Data: x%x x%x "
 			"x%x\n",
-			phba->brd_no, pmbox->vport ? pmbox->vport->vpi : 0,
+			pmbox->vport ? pmbox->vport->vpi : 0,
 			mb->mbxCommand, phba->pport->port_state,
 			psli->sli_flag, flag);
 
@@ -2848,8 +2858,7 @@
 	   (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) {
 		lpfc_printf_log(phba, KERN_ERR,
 				LOG_SLI | LOG_VPORT,
-				"%d:1807 IOCB x%x failed. No vport\n",
-				phba->brd_no,
+				"1807 IOCB x%x failed. No vport\n",
 				piocb->iocb.ulpCommand);
 		dump_stack();
 		return IOCB_ERROR;
@@ -3080,11 +3089,10 @@
 	}
 	if (totiocbsize > MAX_SLIM_IOCB_SIZE) {
 		/* Too many cmd / rsp ring entries in SLI2 SLIM */
-		lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-				"%d:0462 Too many cmd / rsp ring entries in "
-				"SLI2 SLIM Data: x%x x%lx\n",
-				phba->brd_no, totiocbsize,
-				(unsigned long) MAX_SLIM_IOCB_SIZE);
+		printk(KERN_ERR "%d:0462 Too many cmd / rsp ring entries in "
+		       "SLI2 SLIM Data: x%x x%lx\n",
+		       phba->brd_no, totiocbsize,
+		       (unsigned long) MAX_SLIM_IOCB_SIZE);
 	}
 	if (phba->cfg_multi_ring_support == 2)
 		lpfc_extra_ring_setup(phba);
@@ -3305,9 +3313,9 @@
 
 	spin_unlock_irq(&phba->hbalock);
 	lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
-			"%d:0410 Cannot find virtual addr for mapped buf on "
+			"0410 Cannot find virtual addr for mapped buf on "
 			"ring %d Data x%llx x%p x%p x%x\n",
-			phba->brd_no, pring->ringno, (unsigned long long)phys,
+			pring->ringno, (unsigned long long)phys,
 			slp->next, slp->prev, pring->postbufq_cnt);
 	return NULL;
 }
@@ -3332,12 +3340,11 @@
 			abort_iocb = phba->sli.iocbq_lookup[abort_iotag];
 
 		lpfc_printf_log(phba, KERN_INFO, LOG_ELS | LOG_SLI,
-				"%d:0327 Cannot abort els iocb %p "
+				"0327 Cannot abort els iocb %p "
 				"with tag %x context %x, abort status %x, "
 				"abort code %x\n",
-				phba->brd_no, abort_iocb, abort_iotag,
-				abort_context, irsp->ulpStatus,
-				irsp->un.ulpWord[4]);
+				abort_iocb, abort_iotag, abort_context,
+				irsp->ulpStatus, irsp->un.ulpWord[4]);
 
 		/*
 		 * make sure we have the right iocbq before taking it
@@ -3371,9 +3378,9 @@
 
 	/* ELS cmd tag <ulpIoTag> completes */
 	lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
-			"%d (X):0133 Ignoring ELS cmd tag x%x completion Data: "
+			"0133 Ignoring ELS cmd tag x%x completion Data: "
 			"x%x x%x x%x\n",
-			phba->brd_no, irsp->ulpIoTag, irsp->ulpStatus,
+			irsp->ulpIoTag, irsp->ulpStatus,
 			irsp->un.ulpWord[4], irsp->ulpTimeout);
 	if (cmdiocb->iocb.ulpCommand == CMD_GEN_REQUEST64_CR)
 		lpfc_ct_free_iocb(phba, cmdiocb);
@@ -3439,12 +3446,11 @@
 
 	abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl;
 
-	lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-			"%d (%d):0339 Abort xri x%x, original iotag x%x, "
-			"abort cmd iotag x%x\n",
-			phba->brd_no, vport->vpi,
-			iabt->un.acxri.abortContextTag,
-			iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
+	lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
+			 "0339 Abort xri x%x, original iotag x%x, "
+			 "abort cmd iotag x%x\n",
+			 iabt->un.acxri.abortContextTag,
+			 iabt->un.acxri.abortIoTag, abtsiocbp->iotag);
 	retval = __lpfc_sli_issue_iocb(phba, pring, abtsiocbp, 0);
 
 abort_iotag_exit:
@@ -3457,8 +3463,8 @@
 }
 
 static int
-lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, uint16_t tgt_id,
-			   uint64_t lun_id, uint32_t ctx,
+lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport,
+			   uint16_t tgt_id, uint64_t lun_id,
 			   lpfc_ctx_cmd ctx_cmd)
 {
 	struct lpfc_scsi_buf *lpfc_cmd;
@@ -3468,6 +3474,9 @@
 	if (!(iocbq->iocb_flag &  LPFC_IO_FCP))
 		return rc;
 
+	if (iocbq->vport != vport)
+		return rc;
+
 	lpfc_cmd = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq);
 	cmnd = lpfc_cmd->pCmd;
 
@@ -3484,10 +3493,6 @@
 		if (cmnd->device->id == tgt_id)
 			rc = 0;
 		break;
-	case LPFC_CTX_CTX:
-		if (iocbq->iocb.ulpContext == ctx)
-			rc = 0;
-		break;
 	case LPFC_CTX_HOST:
 		rc = 0;
 		break;
@@ -3501,17 +3506,18 @@
 }
 
 int
-lpfc_sli_sum_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
-		  uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd ctx_cmd)
+lpfc_sli_sum_iocb(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id,
+		  lpfc_ctx_cmd ctx_cmd)
 {
+	struct lpfc_hba *phba = vport->phba;
 	struct lpfc_iocbq *iocbq;
 	int sum, i;
 
 	for (i = 1, sum = 0; i <= phba->sli.last_iotag; i++) {
 		iocbq = phba->sli.iocbq_lookup[i];
 
-		if (lpfc_sli_validate_fcp_iocb (iocbq, tgt_id, lun_id,
-						0, ctx_cmd) == 0)
+		if (lpfc_sli_validate_fcp_iocb (iocbq, vport, tgt_id, lun_id,
+						ctx_cmd) == 0)
 			sum++;
 	}
 
@@ -3527,10 +3533,10 @@
 }
 
 int
-lpfc_sli_abort_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
-		    uint16_t tgt_id, uint64_t lun_id, uint32_t ctx,
-		    lpfc_ctx_cmd abort_cmd)
+lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
+		    uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd abort_cmd)
 {
+	struct lpfc_hba *phba = vport->phba;
 	struct lpfc_iocbq *iocbq;
 	struct lpfc_iocbq *abtsiocb;
 	IOCB_t *cmd = NULL;
@@ -3540,7 +3546,7 @@
 	for (i = 1; i <= phba->sli.last_iotag; i++) {
 		iocbq = phba->sli.iocbq_lookup[i];
 
-		if (lpfc_sli_validate_fcp_iocb(iocbq, tgt_id, lun_id, 0,
+		if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id,
 					       abort_cmd) != 0)
 			continue;
 
@@ -3647,25 +3653,23 @@
 
 		if (piocb->iocb_flag & LPFC_IO_WAKE) {
 			lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-					"%d:0331 IOCB wake signaled\n",
-					phba->brd_no);
+					"0331 IOCB wake signaled\n");
 		} else if (timeleft == 0) {
 			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-					"%d:0338 IOCB wait timeout error - no "
-					"wake response Data x%x\n",
-					phba->brd_no, timeout);
+					"0338 IOCB wait timeout error - no "
+					"wake response Data x%x\n", timeout);
 			retval = IOCB_TIMEDOUT;
 		} else {
 			lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
-					"%d:0330 IOCB wake NOT set, "
-					"Data x%x x%lx\n", phba->brd_no,
+					"0330 IOCB wake NOT set, "
+					"Data x%x x%lx\n",
 					timeout, (timeleft / jiffies));
 			retval = IOCB_TIMEDOUT;
 		}
 	} else {
 		lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
-				"%d:0332 IOCB wait issue failed, Data x%x\n",
-				phba->brd_no, retval);
+				":0332 IOCB wait issue failed, Data x%x\n",
+				retval);
 		retval = IOCB_ERROR;
 	}
 
@@ -3850,12 +3854,33 @@
 			if (status & HA_RXMASK) {
 				spin_lock(&phba->hbalock);
 				control = readl(phba->HCregaddr);
+
+				lpfc_debugfs_slow_ring_trc(phba,
+				"ISR slow ring:   ctl:x%x stat:x%x isrcnt:x%x",
+				control, status,
+				(uint32_t)phba->sli.slistat.sli_intr);
+
 				if (control & (HC_R0INT_ENA << LPFC_ELS_RING)) {
+					lpfc_debugfs_slow_ring_trc(phba,
+						"ISR Disable ring:"
+						"pwork:x%x hawork:x%x wait:x%x",
+						phba->work_ha, work_ha_copy,
+						(uint32_t)((unsigned long)
+						phba->work_wait));
+
 					control &=
 					    ~(HC_R0INT_ENA << LPFC_ELS_RING);
 					writel(control, phba->HCregaddr);
 					readl(phba->HCregaddr); /* flush */
 				}
+				else {
+					lpfc_debugfs_slow_ring_trc(phba,
+						"ISR slow ring:   pwork:"
+						"x%x hawork:x%x wait:x%x",
+						phba->work_ha, work_ha_copy,
+						(uint32_t)((unsigned long)
+						phba->work_wait));
+				}
 				spin_unlock(&phba->hbalock);
 			}
 		}
@@ -3895,12 +3920,10 @@
 				 */
 				lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX |
 						LOG_SLI,
-						"%d (%d):0304 Stray Mailbox "
+						"(%d):0304 Stray Mailbox "
 						"Interrupt mbxCommand x%x "
 						"mbxStatus x%x\n",
-						phba->brd_no,
-						(vport
-						 ? vport->vpi : 0),
+						(vport ? vport->vpi : 0),
 						pmbox->mbxCommand,
 						pmbox->mbxStatus);
 			}
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index 76058505..51b2b6b 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -26,7 +26,6 @@
 typedef enum _lpfc_ctx_cmd {
 	LPFC_CTX_LUN,
 	LPFC_CTX_TGT,
-	LPFC_CTX_CTX,
 	LPFC_CTX_HOST
 } lpfc_ctx_cmd;
 
@@ -54,9 +53,10 @@
 	void *context2;		/* caller context information */
 	void *context3;		/* caller context information */
 	union {
-		wait_queue_head_t  *wait_queue;
-		struct lpfc_iocbq  *rsp_iocb;
-		struct lpfcMboxq   *mbox;
+		wait_queue_head_t    *wait_queue;
+		struct lpfc_iocbq    *rsp_iocb;
+		struct lpfcMboxq     *mbox;
+		struct lpfc_nodelist *ndlp;
 	} context_un;
 
 	void (*fabric_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *,
@@ -143,7 +143,7 @@
 	uint16_t numCiocb;	/* number of command iocb's per ring */
 	uint16_t numRiocb;	/* number of rsp iocb's per ring */
 	uint16_t sizeCiocb;	/* Size of command iocb's in this ring */
-	uint16_t sizeRiocb; 	/* Size of response iocb's in this ring */
+	uint16_t sizeRiocb;	/* Size of response iocb's in this ring */
 
 	uint32_t fast_iotag;	/* max fastlookup based iotag           */
 	uint32_t iotag_ctr;	/* keeps track of the next iotag to use */
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index a5bc79e..0081f49 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,12 +18,10 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.2.1"
+#define LPFC_DRIVER_VERSION "8.2.2"
 
 #define LPFC_DRIVER_NAME "lpfc"
 
 #define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \
 		LPFC_DRIVER_VERSION
 #define LPFC_COPYRIGHT "Copyright(c) 2004-2007 Emulex.  All rights reserved."
-
-#define DFC_API_VERSION "0.0.0"
diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c
index 85797db..dcb415e 100644
--- a/drivers/scsi/lpfc/lpfc_vport.c
+++ b/drivers/scsi/lpfc/lpfc_vport.c
@@ -125,11 +125,10 @@
 	pmb->vport = vport;
 	rc = lpfc_sli_issue_mbox_wait(phba, pmb, phba->fc_ratov * 2);
 	if (rc != MBX_SUCCESS) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT,
-				"%d (%d):1818 VPort failed init, mbxCmd x%x "
-				"READ_SPARM mbxStatus x%x, rc = x%x\n",
-				phba->brd_no, vport->vpi,
-				mb->mbxCommand, mb->mbxStatus, rc);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT,
+				 "1818 VPort failed init, mbxCmd x%x "
+				 "READ_SPARM mbxStatus x%x, rc = x%x\n",
+				 mb->mbxCommand, mb->mbxStatus, rc);
 		lpfc_mbuf_free(phba, mp->virt, mp->phys);
 		kfree(mp);
 		if (rc != MBX_TIMEOUT)
@@ -162,9 +161,9 @@
 		return 1;
 
 	lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
-			"%d:1822 Invalid %s: %02x:%02x:%02x:%02x:"
+			"1822 Invalid %s: %02x:%02x:%02x:%02x:"
 			"%02x:%02x:%02x:%02x\n",
-			phba->brd_no, name_type,
+			name_type,
 			wwn->u.wwn[0], wwn->u.wwn[1],
 			wwn->u.wwn[2], wwn->u.wwn[3],
 			wwn->u.wwn[4], wwn->u.wwn[5],
@@ -176,16 +175,21 @@
 lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport)
 {
 	struct lpfc_vport *vport;
+	unsigned long flags;
 
+	spin_lock_irqsave(&phba->hbalock, flags);
 	list_for_each_entry(vport, &phba->port_list, listentry) {
 		if (vport == new_vport)
 			continue;
 		/* If they match, return not unique */
 		if (memcmp(&vport->fc_sparam.portName,
-			&new_vport->fc_sparam.portName,
-			sizeof(struct lpfc_name)) == 0)
+			   &new_vport->fc_sparam.portName,
+			   sizeof(struct lpfc_name)) == 0) {
+			spin_unlock_irqrestore(&phba->hbalock, flags);
 			return 0;
+		}
 	}
+	spin_unlock_irqrestore(&phba->hbalock, flags);
 	return 1;
 }
 
@@ -193,8 +197,8 @@
 lpfc_vport_create(struct fc_vport *fc_vport, bool disable)
 {
 	struct lpfc_nodelist *ndlp;
-	struct lpfc_vport *pport =
-		(struct lpfc_vport *) fc_vport->shost->hostdata;
+	struct Scsi_Host *shost = fc_vport->shost;
+	struct lpfc_vport *pport = (struct lpfc_vport *) shost->hostdata;
 	struct lpfc_hba   *phba = pport->phba;
 	struct lpfc_vport *vport = NULL;
 	int instance;
@@ -204,9 +208,9 @@
 	if ((phba->sli_rev < 3) ||
 		!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
-				"%d:1808 Create VPORT failed: "
+				"1808 Create VPORT failed: "
 				"NPIV is not enabled: SLImode:%d\n",
-				phba->brd_no, phba->sli_rev);
+				phba->sli_rev);
 		rc = VPORT_INVAL;
 		goto error_out;
 	}
@@ -214,9 +218,9 @@
 	vpi = lpfc_alloc_vpi(phba);
 	if (vpi == 0) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
-				"%d:1809 Create VPORT failed: "
+				"1809 Create VPORT failed: "
 				"Max VPORTs (%d) exceeded\n",
-				phba->brd_no, phba->max_vpi);
+				phba->max_vpi);
 		rc = VPORT_NORESOURCES;
 		goto error_out;
 	}
@@ -225,18 +229,17 @@
 	/* Assign an unused board number */
 	if ((instance = lpfc_get_instance()) < 0) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
-				"%d:1810 Create VPORT failed: Cannot get "
-				"instance number\n", phba->brd_no);
+				"1810 Create VPORT failed: Cannot get "
+				"instance number\n");
 		lpfc_free_vpi(phba, vpi);
 		rc = VPORT_NORESOURCES;
 		goto error_out;
 	}
 
-	vport = lpfc_create_port(phba, instance, fc_vport);
+	vport = lpfc_create_port(phba, instance, &fc_vport->dev);
 	if (!vport) {
 		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
-				"%d:1811 Create VPORT failed: vpi x%x\n",
-				phba->brd_no, vpi);
+				"1811 Create VPORT failed: vpi x%x\n", vpi);
 		lpfc_free_vpi(phba, vpi);
 		rc = VPORT_NORESOURCES;
 		goto error_out;
@@ -246,10 +249,9 @@
 	lpfc_debugfs_initialize(vport);
 
 	if (lpfc_vport_sparm(phba, vport)) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
-				"%d:1813 Create VPORT failed: vpi:%d "
-				"Cannot get sparam\n",
-				phba->brd_no, vpi);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+				 "1813 Create VPORT failed. "
+				 "Cannot get sparam\n");
 		lpfc_free_vpi(phba, vpi);
 		destroy_port(vport);
 		rc = VPORT_NORESOURCES;
@@ -269,10 +271,9 @@
 
 	if (!lpfc_valid_wwn_format(phba, &vport->fc_sparam.nodeName, "WWNN") ||
 	    !lpfc_valid_wwn_format(phba, &vport->fc_sparam.portName, "WWPN")) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
-				"%d:1821 Create VPORT failed: vpi:%d "
-				"Invalid WWN format\n",
-				phba->brd_no, vpi);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+				 "1821 Create VPORT failed. "
+				 "Invalid WWN format\n");
 		lpfc_free_vpi(phba, vpi);
 		destroy_port(vport);
 		rc = VPORT_INVAL;
@@ -280,10 +281,9 @@
 	}
 
 	if (!lpfc_unique_wwpn(phba, vport)) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
-				"%d:1823 Create VPORT failed: vpi:%d "
-				"Duplicate WWN on HBA\n",
-				phba->brd_no, vpi);
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+				 "1823 Create VPORT failed. "
+				 "Duplicate WWN on HBA\n");
 		lpfc_free_vpi(phba, vpi);
 		destroy_port(vport);
 		rc = VPORT_INVAL;
@@ -315,10 +315,8 @@
 			lpfc_initial_fdisc(vport);
 		} else {
 			lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
-			lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-					"%d (%d):0262 No NPIV Fabric "
-					"support\n",
-					phba->brd_no, vport->vpi);
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+					 "0262 No NPIV Fabric support\n");
 		}
 	} else {
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
@@ -326,12 +324,14 @@
 	rc = VPORT_OK;
 
 out:
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+			"1825 Vport Created.\n");
 	lpfc_host_attrib_init(lpfc_shost_from_vport(vport));
 error_out:
 	return rc;
 }
 
-int
+static int
 disable_vport(struct fc_vport *fc_vport)
 {
 	struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
@@ -371,10 +371,12 @@
 	lpfc_mbx_unreg_vpi(vport);
 
 	lpfc_vport_set_state(vport, FC_VPORT_DISABLED);
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+			 "1826 Vport Disabled.\n");
 	return VPORT_OK;
 }
 
-int
+static int
 enable_vport(struct fc_vport *fc_vport)
 {
 	struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
@@ -400,15 +402,14 @@
 			lpfc_initial_fdisc(vport);
 		} else {
 			lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP);
-			lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
-					"%d (%d):0264 No NPIV Fabric "
-					"support\n",
-					phba->brd_no, vport->vpi);
+			lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+					 "0264 No NPIV Fabric support\n");
 		}
 	} else {
 		lpfc_vport_set_state(vport, FC_VPORT_FAILED);
 	}
-
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+			 "1827 Vport Enabled.\n");
 	return VPORT_OK;
 }
 
@@ -431,8 +432,29 @@
 	struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
 	struct lpfc_hba   *phba = vport->phba;
 	long timeout;
-	int rc = VPORT_ERROR;
 
+	if (vport->port_type == LPFC_PHYSICAL_PORT) {
+		lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+				 "1812 vport_delete failed: Cannot delete "
+				 "physical host\n");
+		return VPORT_ERROR;
+	}
+	/*
+	 * If we are not unloading the driver then prevent the vport_delete
+	 * from happening until after this vport's discovery is finished.
+	 */
+	if (!(phba->pport->load_flag & FC_UNLOADING)) {
+		int check_count = 0;
+		while (check_count < ((phba->fc_ratov * 3) + 3) &&
+		       vport->port_state > LPFC_VPORT_FAILED &&
+		       vport->port_state < LPFC_VPORT_READY) {
+			check_count++;
+			msleep(1000);
+		}
+		if (vport->port_state > LPFC_VPORT_FAILED &&
+		    vport->port_state < LPFC_VPORT_READY)
+			return -EAGAIN;
+	}
 	/*
 	 * This is a bit of a mess.  We want to ensure the shost doesn't get
 	 * torn down until we're done with the embedded lpfc_vport structure.
@@ -450,16 +472,9 @@
 	 */
 	if (!scsi_host_get(shost) || !scsi_host_get(shost))
 		return VPORT_INVAL;
-
-	if (vport->port_type == LPFC_PHYSICAL_PORT) {
-		lpfc_printf_log(phba, KERN_ERR, LOG_VPORT,
-				"%d:1812 vport_delete failed: Cannot delete "
-				"physical host\n", phba->brd_no);
-		goto out;
-	}
-
+	spin_lock_irq(&phba->hbalock);
 	vport->load_flag |= FC_UNLOADING;
-
+	spin_unlock_irq(&phba->hbalock);
 	kfree(vport->vname);
 	lpfc_debugfs_terminate(vport);
 	fc_remove_host(lpfc_shost_from_vport(vport));
@@ -511,13 +526,46 @@
 	spin_lock_irq(&phba->hbalock);
 	list_del_init(&vport->listentry);
 	spin_unlock_irq(&phba->hbalock);
-
-	rc = VPORT_OK;
-out:
+	lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT,
+			 "1828 Vport Deleted.\n");
 	scsi_host_put(shost);
-	return rc;
+	return VPORT_OK;
 }
 
-
 EXPORT_SYMBOL(lpfc_vport_create);
 EXPORT_SYMBOL(lpfc_vport_delete);
+
+struct lpfc_vport **
+lpfc_create_vport_work_array(struct lpfc_hba *phba)
+{
+	struct lpfc_vport *port_iterator;
+	struct lpfc_vport **vports;
+	int index = 0;
+	vports = kzalloc(LPFC_MAX_VPORTS * sizeof(struct lpfc_vport *),
+			 GFP_KERNEL);
+	if (vports == NULL)
+		return NULL;
+	spin_lock_irq(&phba->hbalock);
+	list_for_each_entry(port_iterator, &phba->port_list, listentry) {
+		if (!scsi_host_get(lpfc_shost_from_vport(port_iterator))) {
+			lpfc_printf_vlog(port_iterator, KERN_WARNING, LOG_VPORT,
+					 "1801 Create vport work array FAILED: "
+					 "cannot do scsi_host_get\n");
+			continue;
+		}
+		vports[index++] = port_iterator;
+	}
+	spin_unlock_irq(&phba->hbalock);
+	return vports;
+}
+
+void
+lpfc_destroy_vport_work_array(struct lpfc_vport **vports)
+{
+	int i;
+	if (vports == NULL)
+		return;
+	for (i=0; vports[i] != NULL && i < LPFC_MAX_VPORTS; i++)
+		scsi_host_put(lpfc_shost_from_vport(vports[i]));
+	kfree(vports);
+}
diff --git a/drivers/scsi/lpfc/lpfc_vport.h b/drivers/scsi/lpfc/lpfc_vport.h
index f223550..91da177 100644
--- a/drivers/scsi/lpfc/lpfc_vport.h
+++ b/drivers/scsi/lpfc/lpfc_vport.h
@@ -88,6 +88,8 @@
 int lpfc_vport_delete(struct fc_vport *);
 int lpfc_vport_getinfo(struct Scsi_Host *, struct vport_info *);
 int lpfc_vport_tgt_remove(struct Scsi_Host *, uint, uint);
+struct lpfc_vport **lpfc_create_vport_work_array(struct lpfc_hba *);
+void lpfc_destroy_vport_work_array(struct lpfc_vport **);
 
 /*
  *  queuecommand  VPORT-specific return codes. Specified in  the host byte code.
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 3907f67..da56163 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -1753,6 +1753,14 @@
 
 	*len = 0;
 
+	if (scsi_sg_count(cmd) == 1 && !adapter->has_64bit_addr) {
+		sg = scsi_sglist(cmd);
+		scb->dma_h_bulkdata = sg_dma_address(sg);
+		*buf = (u32)scb->dma_h_bulkdata;
+		*len = sg_dma_len(sg);
+		return 0;
+	}
+
 	scsi_for_each_sg(cmd, sg, sgcnt, idx) {
 		if (adapter->has_64bit_addr) {
 			scb->sgl64[idx].address = sg_dma_address(sg);
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index c46685a..c6a53dc 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -454,7 +454,7 @@
 	pci_set_master(pdev);
 
 	// Allocate the per driver initialization structure
-	adapter = kmalloc(sizeof(adapter_t), GFP_KERNEL);
+	adapter = kzalloc(sizeof(adapter_t), GFP_KERNEL);
 
 	if (adapter == NULL) {
 		con_log(CL_ANN, (KERN_WARNING
@@ -462,7 +462,6 @@
 
 		goto out_probe_one;
 	}
-	memset(adapter, 0, sizeof(adapter_t));
 
 
 	// set up PCI related soft state and other pre-known parameters
@@ -746,10 +745,9 @@
 	 * Allocate and initialize the init data structure for mailbox
 	 * controllers
 	 */
-	raid_dev = kmalloc(sizeof(mraid_device_t), GFP_KERNEL);
+	raid_dev = kzalloc(sizeof(mraid_device_t), GFP_KERNEL);
 	if (raid_dev == NULL) return -1;
 
-	memset(raid_dev, 0, sizeof(mraid_device_t));
 
 	/*
 	 * Attach the adapter soft state to raid device soft state
@@ -1050,8 +1048,7 @@
 	 * since the calling routine does not yet know the number of available
 	 * commands.
 	 */
-	adapter->kscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_SCSI_CMDS,
-			GFP_KERNEL);
+	adapter->kscb_list = kcalloc(MBOX_MAX_SCSI_CMDS, sizeof(scb_t), GFP_KERNEL);
 
 	if (adapter->kscb_list == NULL) {
 		con_log(CL_ANN, (KERN_WARNING
@@ -1059,7 +1056,6 @@
 			__LINE__));
 		goto out_free_ibuf;
 	}
-	memset(adapter->kscb_list, 0, sizeof(scb_t) * MBOX_MAX_SCSI_CMDS);
 
 	// memory allocation for our command packets
 	if (megaraid_mbox_setup_dma_pools(adapter) != 0) {
@@ -3495,8 +3491,7 @@
 	int		i;
 
 	// Allocate memory for the base list of scb for management module.
-	adapter->uscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_USER_CMDS,
-			GFP_KERNEL);
+	adapter->uscb_list = kcalloc(MBOX_MAX_USER_CMDS, sizeof(scb_t), GFP_KERNEL);
 
 	if (adapter->uscb_list == NULL) {
 		con_log(CL_ANN, (KERN_WARNING
@@ -3504,7 +3499,6 @@
 			__LINE__));
 		return -1;
 	}
-	memset(adapter->uscb_list, 0, sizeof(scb_t) * MBOX_MAX_USER_CMDS);
 
 
 	// Initialize the synchronization parameters for resources for
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
index 84d9c27..b6587a6 100644
--- a/drivers/scsi/megaraid/megaraid_mm.c
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -890,12 +890,11 @@
 	if (lld_adp->drvr_type != DRVRTYPE_MBOX)
 		return (-EINVAL);
 
-	adapter = kmalloc(sizeof(mraid_mmadp_t), GFP_KERNEL);
+	adapter = kzalloc(sizeof(mraid_mmadp_t), GFP_KERNEL);
 
 	if (!adapter)
 		return -ENOMEM;
 
-	memset(adapter, 0, sizeof(mraid_mmadp_t));
 
 	adapter->unique_id	= lld_adp->unique_id;
 	adapter->drvr_type	= lld_adp->drvr_type;
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index b7f2e61..ebb948c 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -1636,15 +1636,13 @@
 	 * Allocate the dynamic array first and then allocate individual
 	 * commands.
 	 */
-	instance->cmd_list = kmalloc(sizeof(struct megasas_cmd *) * max_cmd,
-				     GFP_KERNEL);
+	instance->cmd_list = kcalloc(max_cmd, sizeof(struct megasas_cmd*), GFP_KERNEL);
 
 	if (!instance->cmd_list) {
 		printk(KERN_DEBUG "megasas: out of memory\n");
 		return -ENOMEM;
 	}
 
-	memset(instance->cmd_list, 0, sizeof(struct megasas_cmd *) * max_cmd);
 
 	for (i = 0; i < max_cmd; i++) {
 		instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd),
diff --git a/drivers/scsi/mvme16x_scsi.c b/drivers/scsi/mvme16x_scsi.c
index d6ef22a..1bdddad 100644
--- a/drivers/scsi/mvme16x_scsi.c
+++ b/drivers/scsi/mvme16x_scsi.c
@@ -89,6 +89,7 @@
 		out_be32(0xfff4202c, v);
 	}
 
+	dev_set_drvdata(dev, host);
 	scsi_scan_host(host);
 
 	return 0;
@@ -104,7 +105,7 @@
 static __devexit int
 mvme16x_device_remove(struct device *dev)
 {
-	struct Scsi_Host *host = dev_to_shost(dev);
+	struct Scsi_Host *host = dev_get_drvdata(dev);
 	struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
 
 	/* Disable scsi chip ints */
diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig
index 7dd787f..fa481b5 100644
--- a/drivers/scsi/pcmcia/Kconfig
+++ b/drivers/scsi/pcmcia/Kconfig
@@ -2,9 +2,12 @@
 # PCMCIA SCSI adapter configuration
 #
 
-menu "PCMCIA SCSI adapter support"
+menuconfig SCSI_LOWLEVEL_PCMCIA
+	bool "PCMCIA SCSI adapter support"
 	depends on SCSI!=n && PCMCIA!=n
 
+if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA
+
 config PCMCIA_AHA152X
 	tristate "Adaptec AHA152X PCMCIA support"
 	depends on !64BIT
@@ -77,4 +80,4 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called sym53c500_cs.
 
-endmenu
+endif # SCSI_LOWLEVEL_PCMCIA
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
index 370802d..2dd0dc9 100644
--- a/drivers/scsi/pcmcia/aha152x_stub.c
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -106,9 +106,8 @@
     DEBUG(0, "aha152x_attach()\n");
 
     /* Create new SCSI device */
-    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    info = kzalloc(sizeof(*info), GFP_KERNEL);
     if (!info) return -ENOMEM;
-    memset(info, 0, sizeof(*info));
     info->p_dev = link;
     link->priv = info;
 
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index c6f8c6e..445cfbb 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -1602,9 +1602,8 @@
 	nsp_dbg(NSP_DEBUG_INIT, "in");
 
 	/* Create new SCSI device */
-	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
 	if (info == NULL) { return -ENOMEM; }
-	memset(info, 0, sizeof(*info));
 	info->p_dev = link;
 	link->priv = info;
 	data->ScsiInfo = info;
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
index 697cfb7..67c5a58 100644
--- a/drivers/scsi/pcmcia/qlogic_stub.c
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -162,10 +162,9 @@
 	DEBUG(0, "qlogic_attach()\n");
 
 	/* Create new SCSI device */
-	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
-	memset(info, 0, sizeof(*info));
 	info->p_dev = link;
 	link->priv = info;
 	link->io.NumPorts1 = 16;
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index 2695b71..961839e 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -875,10 +875,9 @@
 	DEBUG(0, "SYM53C500_attach()\n");
 
 	/* Create new SCSI device */
-	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
 	if (!info)
 		return -ENOMEM;
-	memset(info, 0, sizeof(*info));
 	info->p_dev = link;
 	link->priv = info;
 	link->io.NumPorts1 = 16;
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index 2f1fa1e..67b6d76 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -1014,10 +1014,9 @@
 	int modes, ppb, ppb_hi;
 	int err = -ENOMEM;
 
-	dev = kmalloc(sizeof(ppa_struct), GFP_KERNEL);
+	dev = kzalloc(sizeof(ppa_struct), GFP_KERNEL);
 	if (!dev)
 		return -ENOMEM;
-	memset(dev, 0, sizeof(ppa_struct));
 	dev->base = -1;
 	dev->mode = PPA_AUTODETECT;
 	dev->recon_tmo = PPA_RECON_TMO;
diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c
new file mode 100644
index 0000000..b50f1e1
--- /dev/null
+++ b/drivers/scsi/ps3rom.c
@@ -0,0 +1,533 @@
+/*
+ * PS3 BD/DVD/CD-ROM Storage Driver
+ *
+ * Copyright (C) 2007 Sony Computer Entertainment Inc.
+ * Copyright 2007 Sony Corp.
+ *
+ * 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; version 2 of the License.
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/cdrom.h>
+#include <linux/highmem.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include <asm/lv1call.h>
+#include <asm/ps3stor.h>
+
+
+#define DEVICE_NAME			"ps3rom"
+
+#define BOUNCE_SIZE			(64*1024)
+
+#define PS3ROM_MAX_SECTORS		(BOUNCE_SIZE / CD_FRAMESIZE)
+
+
+struct ps3rom_private {
+	struct ps3_storage_device *dev;
+	struct scsi_cmnd *curr_cmd;
+};
+
+
+#define LV1_STORAGE_SEND_ATAPI_COMMAND	(1)
+
+struct lv1_atapi_cmnd_block {
+	u8	pkt[32];	/* packet command block           */
+	u32	pktlen;		/* should be 12 for ATAPI 8020    */
+	u32	blocks;
+	u32	block_size;
+	u32	proto;		/* transfer mode                  */
+	u32	in_out;		/* transfer direction             */
+	u64	buffer;		/* parameter except command block */
+	u32	arglen;		/* length above                   */
+};
+
+enum lv1_atapi_proto {
+	NON_DATA_PROTO     = 0,
+	PIO_DATA_IN_PROTO  = 1,
+	PIO_DATA_OUT_PROTO = 2,
+	DMA_PROTO = 3
+};
+
+enum lv1_atapi_in_out {
+	DIR_WRITE = 0,		/* memory -> device */
+	DIR_READ = 1		/* device -> memory */
+};
+
+
+static int ps3rom_slave_configure(struct scsi_device *scsi_dev)
+{
+	struct ps3rom_private *priv = shost_priv(scsi_dev->host);
+	struct ps3_storage_device *dev = priv->dev;
+
+	dev_dbg(&dev->sbd.core, "%s:%u: id %u, lun %u, channel %u\n", __func__,
+		__LINE__, scsi_dev->id, scsi_dev->lun, scsi_dev->channel);
+
+	/*
+	 * ATAPI SFF8020 devices use MODE_SENSE_10,
+	 * so we can prohibit MODE_SENSE_6
+	 */
+	scsi_dev->use_10_for_ms = 1;
+
+	/* we don't support {READ,WRITE}_6 */
+	scsi_dev->use_10_for_rw = 1;
+
+	return 0;
+}
+
+/*
+ * copy data from device into scatter/gather buffer
+ */
+static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf)
+{
+	int k, req_len, act_len, len, active;
+	void *kaddr;
+	struct scatterlist *sgpnt;
+	unsigned int buflen;
+
+	buflen = cmd->request_bufflen;
+	if (!buflen)
+		return 0;
+
+	if (!cmd->request_buffer)
+		return -1;
+
+	sgpnt = cmd->request_buffer;
+	active = 1;
+	for (k = 0, req_len = 0, act_len = 0; k < cmd->use_sg; ++k, ++sgpnt) {
+		if (active) {
+			kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
+			len = sgpnt->length;
+			if ((req_len + len) > buflen) {
+				active = 0;
+				len = buflen - req_len;
+			}
+			memcpy(kaddr + sgpnt->offset, buf + req_len, len);
+			flush_kernel_dcache_page(sgpnt->page);
+			kunmap_atomic(kaddr, KM_IRQ0);
+			act_len += len;
+		}
+		req_len += sgpnt->length;
+	}
+	cmd->resid = req_len - act_len;
+	return 0;
+}
+
+/*
+ * copy data from scatter/gather into device's buffer
+ */
+static int fetch_to_dev_buffer(struct scsi_cmnd *cmd, void *buf)
+{
+	int k, req_len, len, fin;
+	void *kaddr;
+	struct scatterlist *sgpnt;
+	unsigned int buflen;
+
+	buflen = cmd->request_bufflen;
+	if (!buflen)
+		return 0;
+
+	if (!cmd->request_buffer)
+		return -1;
+
+	sgpnt = cmd->request_buffer;
+	for (k = 0, req_len = 0, fin = 0; k < cmd->use_sg; ++k, ++sgpnt) {
+		kaddr = kmap_atomic(sgpnt->page, KM_IRQ0);
+		len = sgpnt->length;
+		if ((req_len + len) > buflen) {
+			len = buflen - req_len;
+			fin = 1;
+		}
+		memcpy(buf + req_len, kaddr + sgpnt->offset, len);
+		kunmap_atomic(kaddr, KM_IRQ0);
+		if (fin)
+			return req_len + len;
+		req_len += sgpnt->length;
+	}
+	return req_len;
+}
+
+static int ps3rom_atapi_request(struct ps3_storage_device *dev,
+				struct scsi_cmnd *cmd)
+{
+	struct lv1_atapi_cmnd_block atapi_cmnd;
+	unsigned char opcode = cmd->cmnd[0];
+	int res;
+	u64 lpar;
+
+	dev_dbg(&dev->sbd.core, "%s:%u: send ATAPI command 0x%02x\n", __func__,
+		__LINE__, opcode);
+
+	memset(&atapi_cmnd, 0, sizeof(struct lv1_atapi_cmnd_block));
+	memcpy(&atapi_cmnd.pkt, cmd->cmnd, 12);
+	atapi_cmnd.pktlen = 12;
+	atapi_cmnd.block_size = 1; /* transfer size is block_size * blocks */
+	atapi_cmnd.blocks = atapi_cmnd.arglen = cmd->request_bufflen;
+	atapi_cmnd.buffer = dev->bounce_lpar;
+
+	switch (cmd->sc_data_direction) {
+	case DMA_FROM_DEVICE:
+		if (cmd->request_bufflen >= CD_FRAMESIZE)
+			atapi_cmnd.proto = DMA_PROTO;
+		else
+			atapi_cmnd.proto = PIO_DATA_IN_PROTO;
+		atapi_cmnd.in_out = DIR_READ;
+		break;
+
+	case DMA_TO_DEVICE:
+		if (cmd->request_bufflen >= CD_FRAMESIZE)
+			atapi_cmnd.proto = DMA_PROTO;
+		else
+			atapi_cmnd.proto = PIO_DATA_OUT_PROTO;
+		atapi_cmnd.in_out = DIR_WRITE;
+		res = fetch_to_dev_buffer(cmd, dev->bounce_buf);
+		if (res < 0)
+			return DID_ERROR << 16;
+		break;
+
+	default:
+		atapi_cmnd.proto = NON_DATA_PROTO;
+		break;
+	}
+
+	lpar = ps3_mm_phys_to_lpar(__pa(&atapi_cmnd));
+	res = lv1_storage_send_device_command(dev->sbd.dev_id,
+					      LV1_STORAGE_SEND_ATAPI_COMMAND,
+					      lpar, sizeof(atapi_cmnd),
+					      atapi_cmnd.buffer,
+					      atapi_cmnd.arglen, &dev->tag);
+	if (res == LV1_DENIED_BY_POLICY) {
+		dev_dbg(&dev->sbd.core,
+			"%s:%u: ATAPI command 0x%02x denied by policy\n",
+			__func__, __LINE__, opcode);
+		return DID_ERROR << 16;
+	}
+
+	if (res) {
+		dev_err(&dev->sbd.core,
+			"%s:%u: ATAPI command 0x%02x failed %d\n", __func__,
+			__LINE__, opcode, res);
+		return DID_ERROR << 16;
+	}
+
+	return 0;
+}
+
+static inline unsigned int srb10_lba(const struct scsi_cmnd *cmd)
+{
+	return cmd->cmnd[2] << 24 | cmd->cmnd[3] << 16 | cmd->cmnd[4] << 8 |
+	       cmd->cmnd[5];
+}
+
+static inline unsigned int srb10_len(const struct scsi_cmnd *cmd)
+{
+	return cmd->cmnd[7] << 8 | cmd->cmnd[8];
+}
+
+static int ps3rom_read_request(struct ps3_storage_device *dev,
+			       struct scsi_cmnd *cmd, u32 start_sector,
+			       u32 sectors)
+{
+	int res;
+
+	dev_dbg(&dev->sbd.core, "%s:%u: read %u sectors starting at %u\n",
+		__func__, __LINE__, sectors, start_sector);
+
+	res = lv1_storage_read(dev->sbd.dev_id,
+			       dev->regions[dev->region_idx].id, start_sector,
+			       sectors, 0, dev->bounce_lpar, &dev->tag);
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: read failed %d\n", __func__,
+			__LINE__, res);
+		return DID_ERROR << 16;
+	}
+
+	return 0;
+}
+
+static int ps3rom_write_request(struct ps3_storage_device *dev,
+				struct scsi_cmnd *cmd, u32 start_sector,
+				u32 sectors)
+{
+	int res;
+
+	dev_dbg(&dev->sbd.core, "%s:%u: write %u sectors starting at %u\n",
+		__func__, __LINE__, sectors, start_sector);
+
+	res = fetch_to_dev_buffer(cmd, dev->bounce_buf);
+	if (res < 0)
+		return DID_ERROR << 16;
+
+	res = lv1_storage_write(dev->sbd.dev_id,
+				dev->regions[dev->region_idx].id, start_sector,
+				sectors, 0, dev->bounce_lpar, &dev->tag);
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: write failed %d\n", __func__,
+			__LINE__, res);
+		return DID_ERROR << 16;
+	}
+
+	return 0;
+}
+
+static int ps3rom_queuecommand(struct scsi_cmnd *cmd,
+			       void (*done)(struct scsi_cmnd *))
+{
+	struct ps3rom_private *priv = shost_priv(cmd->device->host);
+	struct ps3_storage_device *dev = priv->dev;
+	unsigned char opcode;
+	int res;
+
+#ifdef DEBUG
+	scsi_print_command(cmd);
+#endif
+
+	priv->curr_cmd = cmd;
+	cmd->scsi_done = done;
+
+	opcode = cmd->cmnd[0];
+	/*
+	 * While we can submit READ/WRITE SCSI commands as ATAPI commands,
+	 * it's recommended for various reasons (performance, error handling,
+	 * ...) to use lv1_storage_{read,write}() instead
+	 */
+	switch (opcode) {
+	case READ_10:
+		res = ps3rom_read_request(dev, cmd, srb10_lba(cmd),
+					  srb10_len(cmd));
+		break;
+
+	case WRITE_10:
+		res = ps3rom_write_request(dev, cmd, srb10_lba(cmd),
+					   srb10_len(cmd));
+		break;
+
+	default:
+		res = ps3rom_atapi_request(dev, cmd);
+		break;
+	}
+
+	if (res) {
+		memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+		cmd->result = res;
+		cmd->sense_buffer[0] = 0x70;
+		cmd->sense_buffer[2] = ILLEGAL_REQUEST;
+		priv->curr_cmd = NULL;
+		cmd->scsi_done(cmd);
+	}
+
+	return 0;
+}
+
+static int decode_lv1_status(u64 status, unsigned char *sense_key,
+			     unsigned char *asc, unsigned char *ascq)
+{
+	if (((status >> 24) & 0xff) != SAM_STAT_CHECK_CONDITION)
+		return -1;
+
+	*sense_key = (status >> 16) & 0xff;
+	*asc       = (status >>  8) & 0xff;
+	*ascq      =  status        & 0xff;
+	return 0;
+}
+
+static irqreturn_t ps3rom_interrupt(int irq, void *data)
+{
+	struct ps3_storage_device *dev = data;
+	struct Scsi_Host *host;
+	struct ps3rom_private *priv;
+	struct scsi_cmnd *cmd;
+	int res;
+	u64 tag, status;
+	unsigned char sense_key, asc, ascq;
+
+	res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
+	/*
+	 * status = -1 may mean that ATAPI transport completed OK, but
+	 * ATAPI command itself resulted CHECK CONDITION
+	 * so, upper layer should issue REQUEST_SENSE to check the sense data
+	 */
+
+	if (tag != dev->tag)
+		dev_err(&dev->sbd.core,
+			"%s:%u: tag mismatch, got %lx, expected %lx\n",
+			__func__, __LINE__, tag, dev->tag);
+
+	if (res) {
+		dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n",
+			__func__, __LINE__, res, status);
+		return IRQ_HANDLED;
+	}
+
+	host = dev->sbd.core.driver_data;
+	priv = shost_priv(host);
+	cmd = priv->curr_cmd;
+
+	if (!status) {
+		/* OK, completed */
+		if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
+			res = fill_from_dev_buffer(cmd, dev->bounce_buf);
+			if (res) {
+				cmd->result = DID_ERROR << 16;
+				goto done;
+			}
+		}
+		cmd->result = DID_OK << 16;
+		goto done;
+	}
+
+	if (cmd->cmnd[0] == REQUEST_SENSE) {
+		/* SCSI spec says request sense should never get error */
+		dev_err(&dev->sbd.core, "%s:%u: end error without autosense\n",
+			__func__, __LINE__);
+		cmd->result = DID_ERROR << 16 | SAM_STAT_CHECK_CONDITION;
+		goto done;
+	}
+
+	if (decode_lv1_status(status, &sense_key, &asc, &ascq)) {
+		cmd->result = DID_ERROR << 16;
+		goto done;
+	}
+
+	cmd->sense_buffer[0]  = 0x70;
+	cmd->sense_buffer[2]  = sense_key;
+	cmd->sense_buffer[7]  = 16 - 6;
+	cmd->sense_buffer[12] = asc;
+	cmd->sense_buffer[13] = ascq;
+	cmd->result = SAM_STAT_CHECK_CONDITION;
+
+done:
+	priv->curr_cmd = NULL;
+	cmd->scsi_done(cmd);
+	return IRQ_HANDLED;
+}
+
+static struct scsi_host_template ps3rom_host_template = {
+	.name =			DEVICE_NAME,
+	.slave_configure =	ps3rom_slave_configure,
+	.queuecommand =		ps3rom_queuecommand,
+	.can_queue =		1,
+	.this_id =		7,
+	.sg_tablesize =		SG_ALL,
+	.cmd_per_lun =		1,
+	.emulated =             1,		/* only sg driver uses this */
+	.max_sectors =		PS3ROM_MAX_SECTORS,
+	.use_clustering =	ENABLE_CLUSTERING,
+	.module =		THIS_MODULE,
+};
+
+
+static int __devinit ps3rom_probe(struct ps3_system_bus_device *_dev)
+{
+	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+	int error;
+	struct Scsi_Host *host;
+	struct ps3rom_private *priv;
+
+	if (dev->blk_size != CD_FRAMESIZE) {
+		dev_err(&dev->sbd.core,
+			"%s:%u: cannot handle block size %lu\n", __func__,
+			__LINE__, dev->blk_size);
+		return -EINVAL;
+	}
+
+	dev->bounce_size = BOUNCE_SIZE;
+	dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA);
+	if (!dev->bounce_buf)
+		return -ENOMEM;
+
+	error = ps3stor_setup(dev, ps3rom_interrupt);
+	if (error)
+		goto fail_free_bounce;
+
+	host = scsi_host_alloc(&ps3rom_host_template,
+			       sizeof(struct ps3rom_private));
+	if (!host) {
+		dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed\n",
+			__func__, __LINE__);
+		goto fail_teardown;
+	}
+
+	priv = shost_priv(host);
+	dev->sbd.core.driver_data = host;
+	priv->dev = dev;
+
+	/* One device/LUN per SCSI bus */
+	host->max_id = 1;
+	host->max_lun = 1;
+
+	error = scsi_add_host(host, &dev->sbd.core);
+	if (error) {
+		dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed %d\n",
+			__func__, __LINE__, error);
+		error = -ENODEV;
+		goto fail_host_put;
+	}
+
+	scsi_scan_host(host);
+	return 0;
+
+fail_host_put:
+	scsi_host_put(host);
+	dev->sbd.core.driver_data = NULL;
+fail_teardown:
+	ps3stor_teardown(dev);
+fail_free_bounce:
+	kfree(dev->bounce_buf);
+	return error;
+}
+
+static int ps3rom_remove(struct ps3_system_bus_device *_dev)
+{
+	struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+	struct Scsi_Host *host = dev->sbd.core.driver_data;
+
+	scsi_remove_host(host);
+	ps3stor_teardown(dev);
+	scsi_host_put(host);
+	dev->sbd.core.driver_data = NULL;
+	kfree(dev->bounce_buf);
+	return 0;
+}
+
+static struct ps3_system_bus_driver ps3rom = {
+	.match_id	= PS3_MATCH_ID_STOR_ROM,
+	.core.name	= DEVICE_NAME,
+	.core.owner	= THIS_MODULE,
+	.probe		= ps3rom_probe,
+	.remove		= ps3rom_remove
+};
+
+
+static int __init ps3rom_init(void)
+{
+	return ps3_system_bus_driver_register(&ps3rom);
+}
+
+static void __exit ps3rom_exit(void)
+{
+	ps3_system_bus_driver_unregister(&ps3rom);
+}
+
+module_init(ps3rom_init);
+module_exit(ps3rom_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PS3 BD/DVD/CD-ROM Storage Driver");
+MODULE_AUTHOR("Sony Corporation");
+MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_ROM);
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 3eb2208..0f2a9f5 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -91,18 +91,20 @@
 {
 	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
 	    struct device, kobj)));
-	unsigned long	flags;
+	int		size = ha->nvram_size;
+	char		*nvram_cache = ha->nvram;
 
-	if (!capable(CAP_SYS_ADMIN) || off != 0)
+	if (!capable(CAP_SYS_ADMIN) || off > size || count == 0)
 		return 0;
+	if (off + count > size) {
+		size -= off;
+		count = size;
+	}
 
-	/* Read NVRAM. */
-	spin_lock_irqsave(&ha->hardware_lock, flags);
-	ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->nvram_base,
-	    ha->nvram_size);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	/* Read NVRAM data from cache. */
+	memcpy(buf, &nvram_cache[off], count);
 
-	return ha->nvram_size;
+	return count;
 }
 
 static ssize_t
@@ -119,7 +121,7 @@
 		return 0;
 
 	/* Checksum NVRAM. */
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+	if (IS_FWI2_CAPABLE(ha)) {
 		uint32_t *iter;
 		uint32_t chksum;
 
@@ -143,7 +145,9 @@
 
 	/* Write NVRAM. */
 	spin_lock_irqsave(&ha->hardware_lock, flags);
-	ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count);
+	ha->isp_ops->write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count);
+	ha->isp_ops->read_nvram(ha, (uint8_t *)&ha->nvram, ha->nvram_base,
+	    count);
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
@@ -206,7 +210,7 @@
 		.name = "optrom",
 		.mode = S_IRUSR | S_IWUSR,
 	},
-	.size = OPTROM_SIZE_24XX,
+	.size = 0,
 	.read = qla2x00_sysfs_read_optrom,
 	.write = qla2x00_sysfs_write_optrom,
 };
@@ -252,7 +256,7 @@
 		}
 
 		memset(ha->optrom_buffer, 0, ha->optrom_size);
-		ha->isp_ops.read_optrom(ha, ha->optrom_buffer, 0,
+		ha->isp_ops->read_optrom(ha, ha->optrom_buffer, 0,
 		    ha->optrom_size);
 		break;
 	case 2:
@@ -275,7 +279,7 @@
 		if (ha->optrom_state != QLA_SWRITING)
 			break;
 
-		ha->isp_ops.write_optrom(ha, ha->optrom_buffer, 0,
+		ha->isp_ops->write_optrom(ha, ha->optrom_buffer, 0,
 		    ha->optrom_size);
 		break;
 	}
@@ -298,17 +302,20 @@
 {
 	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
 	    struct device, kobj)));
-	unsigned long flags;
+	int           size = ha->vpd_size;
+	char          *vpd_cache = ha->vpd;
 
-	if (!capable(CAP_SYS_ADMIN) || off != 0)
+	if (!capable(CAP_SYS_ADMIN) || off > size || count == 0)
 		return 0;
+	if (off + count > size) {
+		size -= off;
+		count = size;
+	}
 
-	/* Read NVRAM. */
-	spin_lock_irqsave(&ha->hardware_lock, flags);
-	ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->vpd_base, ha->vpd_size);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	/* Read NVRAM data from cache. */
+	memcpy(buf, &vpd_cache[off], count);
 
-	return ha->vpd_size;
+	return count;
 }
 
 static ssize_t
@@ -325,7 +332,8 @@
 
 	/* Write NVRAM. */
 	spin_lock_irqsave(&ha->hardware_lock, flags);
-	ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->vpd_base, count);
+	ha->isp_ops->write_nvram(ha, (uint8_t *)buf, ha->vpd_base, count);
+	ha->isp_ops->read_nvram(ha, (uint8_t *)ha->vpd, ha->vpd_base, count);
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	return count;
@@ -410,7 +418,7 @@
 	int ret;
 
 	for (iter = bin_file_entries; iter->name; iter++) {
-		if (iter->is4GBp_only && (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)))
+		if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha))
 			continue;
 
 		ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
@@ -429,7 +437,7 @@
 	struct sysfs_entry *iter;
 
 	for (iter = bin_file_entries; iter->name; iter++) {
-		if (iter->is4GBp_only && (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)))
+		if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha))
 			continue;
 
 		sysfs_remove_bin_file(&host->shost_gendev.kobj,
@@ -437,7 +445,7 @@
 	}
 
 	if (ha->beacon_blink_led == 1)
-		ha->isp_ops.beacon_off(ha);
+		ha->isp_ops->beacon_off(ha);
 }
 
 /* Scsi_Host attributes. */
@@ -455,7 +463,7 @@
 	char fw_str[30];
 
 	return snprintf(buf, PAGE_SIZE, "%s\n",
-	    ha->isp_ops.fw_version_str(ha, fw_str));
+	    ha->isp_ops->fw_version_str(ha, fw_str));
 }
 
 static ssize_t
@@ -507,7 +515,7 @@
 	char pci_info[30];
 
 	return snprintf(buf, PAGE_SIZE, "%s\n",
-	    ha->isp_ops.pci_info_str(ha, pci_info));
+	    ha->isp_ops->pci_info_str(ha, pci_info));
 }
 
 static ssize_t
@@ -652,9 +660,9 @@
 		return -EINVAL;
 
 	if (val)
-		rval = ha->isp_ops.beacon_on(ha);
+		rval = ha->isp_ops->beacon_on(ha);
 	else
-		rval = ha->isp_ops.beacon_off(ha);
+		rval = ha->isp_ops->beacon_off(ha);
 
 	if (rval != QLA_SUCCESS)
 		count = 0;
@@ -898,7 +906,7 @@
 	pfc_host_stat = &ha->fc_host_stat;
 	memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics));
 
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+	if (IS_FWI2_CAPABLE(ha)) {
 		rval = qla24xx_get_isp_stats(ha, (uint32_t *)&stat_buf,
 		    sizeof(stat_buf) / 4, mb_stat);
 	} else if (atomic_read(&ha->loop_state) == LOOP_READY &&
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 996c47a..c668034 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -37,6 +37,121 @@
 	return ptr + (ha->response_q_length * sizeof(response_t));
 }
 
+static int
+qla2xxx_dump_memory(scsi_qla_host_t *ha, uint32_t *code_ram,
+    uint32_t cram_size, uint32_t *ext_mem, void **nxt)
+{
+	int rval;
+	uint32_t cnt, stat, timer, risc_address, ext_mem_cnt;
+	uint16_t mb[4];
+	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+	rval = QLA_SUCCESS;
+	risc_address = ext_mem_cnt = 0;
+	memset(mb, 0, sizeof(mb));
+
+	/* Code RAM. */
+	risc_address = 0x20000;
+	WRT_REG_WORD(&reg->mailbox0, MBC_READ_RAM_EXTENDED);
+	clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+
+	for (cnt = 0; cnt < cram_size / 4 && rval == QLA_SUCCESS;
+	    cnt++, risc_address++) {
+		WRT_REG_WORD(&reg->mailbox1, LSW(risc_address));
+		WRT_REG_WORD(&reg->mailbox8, MSW(risc_address));
+		RD_REG_WORD(&reg->mailbox8);
+		WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
+
+		for (timer = 6000000; timer; timer--) {
+			/* Check for pending interrupts. */
+			stat = RD_REG_DWORD(&reg->host_status);
+			if (stat & HSRX_RISC_INT) {
+				stat &= 0xff;
+
+				if (stat == 0x1 || stat == 0x2 ||
+				    stat == 0x10 || stat == 0x11) {
+					set_bit(MBX_INTERRUPT,
+					    &ha->mbx_cmd_flags);
+
+					mb[0] = RD_REG_WORD(&reg->mailbox0);
+					mb[2] = RD_REG_WORD(&reg->mailbox2);
+					mb[3] = RD_REG_WORD(&reg->mailbox3);
+
+					WRT_REG_DWORD(&reg->hccr,
+					    HCCRX_CLR_RISC_INT);
+					RD_REG_DWORD(&reg->hccr);
+					break;
+				}
+
+				/* Clear this intr; it wasn't a mailbox intr */
+				WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
+				RD_REG_DWORD(&reg->hccr);
+			}
+			udelay(5);
+		}
+
+		if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
+			rval = mb[0] & MBS_MASK;
+			code_ram[cnt] = htonl((mb[3] << 16) | mb[2]);
+		} else {
+			rval = QLA_FUNCTION_FAILED;
+		}
+	}
+
+	if (rval == QLA_SUCCESS) {
+		/* External Memory. */
+		risc_address = 0x100000;
+		ext_mem_cnt = ha->fw_memory_size - 0x100000 + 1;
+		WRT_REG_WORD(&reg->mailbox0, MBC_READ_RAM_EXTENDED);
+		clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+	}
+	for (cnt = 0; cnt < ext_mem_cnt && rval == QLA_SUCCESS;
+	    cnt++, risc_address++) {
+		WRT_REG_WORD(&reg->mailbox1, LSW(risc_address));
+		WRT_REG_WORD(&reg->mailbox8, MSW(risc_address));
+		RD_REG_WORD(&reg->mailbox8);
+		WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
+
+		for (timer = 6000000; timer; timer--) {
+			/* Check for pending interrupts. */
+			stat = RD_REG_DWORD(&reg->host_status);
+			if (stat & HSRX_RISC_INT) {
+				stat &= 0xff;
+
+				if (stat == 0x1 || stat == 0x2 ||
+				    stat == 0x10 || stat == 0x11) {
+					set_bit(MBX_INTERRUPT,
+					    &ha->mbx_cmd_flags);
+
+					mb[0] = RD_REG_WORD(&reg->mailbox0);
+					mb[2] = RD_REG_WORD(&reg->mailbox2);
+					mb[3] = RD_REG_WORD(&reg->mailbox3);
+
+					WRT_REG_DWORD(&reg->hccr,
+					    HCCRX_CLR_RISC_INT);
+					RD_REG_DWORD(&reg->hccr);
+					break;
+				}
+
+				/* Clear this intr; it wasn't a mailbox intr */
+				WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
+				RD_REG_DWORD(&reg->hccr);
+			}
+			udelay(5);
+		}
+
+		if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
+			rval = mb[0] & MBS_MASK;
+			ext_mem[cnt] = htonl((mb[3] << 16) | mb[2]);
+		} else {
+			rval = QLA_FUNCTION_FAILED;
+		}
+	}
+
+	*nxt = rval == QLA_SUCCESS ? &ext_mem[cnt]: NULL;
+	return rval;
+}
+
 /**
  * qla2300_fw_dump() - Dumps binary data from the 2300 firmware.
  * @ha: HA context
@@ -633,11 +748,10 @@
 qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
 {
 	int		rval;
-	uint32_t	cnt, timer;
+	uint32_t	cnt;
 	uint32_t	risc_address;
-	uint16_t	mb[4], wd;
+	uint16_t	mb0, wd;
 
-	uint32_t	stat;
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 	uint32_t __iomem *dmp_reg;
 	uint32_t	*iter_reg;
@@ -645,10 +759,9 @@
 	unsigned long	flags;
 	struct qla24xx_fw_dump *fw;
 	uint32_t	ext_mem_cnt;
-	void		*eft;
+	void		*nxt;
 
 	risc_address = ext_mem_cnt = 0;
-	memset(mb, 0, sizeof(mb));
 	flags = 0;
 
 	if (!hardware_locked)
@@ -701,250 +814,236 @@
 		/* Shadow registers. */
 		WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
 		RD_REG_DWORD(&reg->iobase_addr);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-		WRT_REG_DWORD(dmp_reg, 0xB0000000);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-		fw->shadow_reg[0] = htonl(RD_REG_DWORD(dmp_reg));
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
+		fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
 
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-		WRT_REG_DWORD(dmp_reg, 0xB0100000);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-		fw->shadow_reg[1] = htonl(RD_REG_DWORD(dmp_reg));
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
+		fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
 
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-		WRT_REG_DWORD(dmp_reg, 0xB0200000);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-		fw->shadow_reg[2] = htonl(RD_REG_DWORD(dmp_reg));
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
+		fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
 
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-		WRT_REG_DWORD(dmp_reg, 0xB0300000);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-		fw->shadow_reg[3] = htonl(RD_REG_DWORD(dmp_reg));
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
+		fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
 
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-		WRT_REG_DWORD(dmp_reg, 0xB0400000);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-		fw->shadow_reg[4] = htonl(RD_REG_DWORD(dmp_reg));
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
+		fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
 
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-		WRT_REG_DWORD(dmp_reg, 0xB0500000);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-		fw->shadow_reg[5] = htonl(RD_REG_DWORD(dmp_reg));
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
+		fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
 
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
-		WRT_REG_DWORD(dmp_reg, 0xB0600000);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
-		fw->shadow_reg[6] = htonl(RD_REG_DWORD(dmp_reg));
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
+		fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
 
 		/* Mailbox registers. */
-		mbx_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		mbx_reg = &reg->mailbox0;
 		for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
 			fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
 
 		/* Transfer sequence registers. */
 		iter_reg = fw->xseq_gp_reg;
 		WRT_REG_DWORD(&reg->iobase_addr, 0xBF00);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xBF10);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xBF20);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xBF30);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xBF40);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xBF50);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xBF60);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xBF70);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xBFE0);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < sizeof(fw->xseq_0_reg) / 4; cnt++)
 			fw->xseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xBFF0);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++)
 			fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
 
 		/* Receive sequence registers. */
 		iter_reg = fw->rseq_gp_reg;
 		WRT_REG_DWORD(&reg->iobase_addr, 0xFF00);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xFF10);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xFF20);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xFF30);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xFF40);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xFF50);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xFF60);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xFF70);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xFFD0);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < sizeof(fw->rseq_0_reg) / 4; cnt++)
 			fw->rseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xFFE0);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++)
 			fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0xFFF0);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++)
 			fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
 
 		/* Command DMA registers. */
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7100);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++)
 			fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
 
 		/* Queues. */
 		iter_reg = fw->req0_dma_reg;
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7200);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 8; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4);
+		dmp_reg = &reg->iobase_q;
 		for (cnt = 0; cnt < 7; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		iter_reg = fw->resp0_dma_reg;
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7300);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 8; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4);
+		dmp_reg = &reg->iobase_q;
 		for (cnt = 0; cnt < 7; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		iter_reg = fw->req1_dma_reg;
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7400);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 8; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4);
+		dmp_reg = &reg->iobase_q;
 		for (cnt = 0; cnt < 7; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		/* Transmit DMA registers. */
 		iter_reg = fw->xmt0_dma_reg;
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7600);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7610);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		iter_reg = fw->xmt1_dma_reg;
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7620);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7630);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		iter_reg = fw->xmt2_dma_reg;
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7640);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7650);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		iter_reg = fw->xmt3_dma_reg;
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7660);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7670);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		iter_reg = fw->xmt4_dma_reg;
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7680);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7690);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x76A0);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++)
 			fw->xmt_data_dma_reg[cnt] =
 			    htonl(RD_REG_DWORD(dmp_reg++));
@@ -952,221 +1051,221 @@
 		/* Receive DMA registers. */
 		iter_reg = fw->rcvt0_data_dma_reg;
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7700);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7710);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		iter_reg = fw->rcvt1_data_dma_reg;
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7720);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x7730);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		/* RISC registers. */
 		iter_reg = fw->risc_gp_reg;
 		WRT_REG_DWORD(&reg->iobase_addr, 0x0F00);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x0F10);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x0F20);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x0F30);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x0F40);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x0F50);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x0F60);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		/* Local memory controller registers. */
 		iter_reg = fw->lmc_reg;
 		WRT_REG_DWORD(&reg->iobase_addr, 0x3000);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x3010);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x3020);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x3030);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x3040);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x3050);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x3060);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		/* Fibre Protocol Module registers. */
 		iter_reg = fw->fpm_hdw_reg;
 		WRT_REG_DWORD(&reg->iobase_addr, 0x4000);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x4010);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x4020);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x4030);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x4040);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x4050);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x4060);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x4070);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x4080);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x4090);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x40A0);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x40B0);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		/* Frame Buffer registers. */
 		iter_reg = fw->fb_hdw_reg;
 		WRT_REG_DWORD(&reg->iobase_addr, 0x6000);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x6010);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x6020);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x6030);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x6040);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x6100);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x6130);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x6150);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x6170);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x6190);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
 		WRT_REG_DWORD(&reg->iobase_addr, 0x61B0);
-		dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
+		dmp_reg = &reg->iobase_window;
 		for (cnt = 0; cnt < 16; cnt++)
 			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
 
@@ -1187,10 +1286,10 @@
 
 		udelay(100);
 		/* Wait for firmware to complete NVRAM accesses. */
-		mb[0] = (uint32_t) RD_REG_WORD(&reg->mailbox0);
-		for (cnt = 10000 ; cnt && mb[0]; cnt--) {
+		mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+		for (cnt = 10000 ; cnt && mb0; cnt--) {
 			udelay(5);
-			mb[0] = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+			mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
 			barrier();
 		}
 
@@ -1214,110 +1313,14 @@
 			rval = QLA_FUNCTION_TIMEOUT;
 	}
 
-	/* Memory. */
-	if (rval == QLA_SUCCESS) {
-		/* Code RAM. */
-		risc_address = 0x20000;
-		WRT_REG_WORD(&reg->mailbox0, MBC_READ_RAM_EXTENDED);
-		clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-	}
-	for (cnt = 0; cnt < sizeof(fw->code_ram) / 4 && rval == QLA_SUCCESS;
-	    cnt++, risc_address++) {
-		WRT_REG_WORD(&reg->mailbox1, LSW(risc_address));
-		WRT_REG_WORD(&reg->mailbox8, MSW(risc_address));
-		RD_REG_WORD(&reg->mailbox8);
-		WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
-
-		for (timer = 6000000; timer; timer--) {
-			/* Check for pending interrupts. */
-			stat = RD_REG_DWORD(&reg->host_status);
-			if (stat & HSRX_RISC_INT) {
-				stat &= 0xff;
-
-				if (stat == 0x1 || stat == 0x2 ||
-				    stat == 0x10 || stat == 0x11) {
-					set_bit(MBX_INTERRUPT,
-					    &ha->mbx_cmd_flags);
-
-					mb[0] = RD_REG_WORD(&reg->mailbox0);
-					mb[2] = RD_REG_WORD(&reg->mailbox2);
-					mb[3] = RD_REG_WORD(&reg->mailbox3);
-
-					WRT_REG_DWORD(&reg->hccr,
-					    HCCRX_CLR_RISC_INT);
-					RD_REG_DWORD(&reg->hccr);
-					break;
-				}
-
-				/* Clear this intr; it wasn't a mailbox intr */
-				WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
-				RD_REG_DWORD(&reg->hccr);
-			}
-			udelay(5);
-		}
-
-		if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
-			rval = mb[0] & MBS_MASK;
-			fw->code_ram[cnt] = htonl((mb[3] << 16) | mb[2]);
-		} else {
-			rval = QLA_FUNCTION_FAILED;
-		}
-	}
+	if (rval == QLA_SUCCESS)
+		rval = qla2xxx_dump_memory(ha, fw->code_ram,
+		    sizeof(fw->code_ram), fw->ext_mem, &nxt);
 
 	if (rval == QLA_SUCCESS) {
-		/* External Memory. */
-		risc_address = 0x100000;
-		ext_mem_cnt = ha->fw_memory_size - 0x100000 + 1;
-		WRT_REG_WORD(&reg->mailbox0, MBC_READ_RAM_EXTENDED);
-		clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
-	}
-	for (cnt = 0; cnt < ext_mem_cnt && rval == QLA_SUCCESS;
-	    cnt++, risc_address++) {
-		WRT_REG_WORD(&reg->mailbox1, LSW(risc_address));
-		WRT_REG_WORD(&reg->mailbox8, MSW(risc_address));
-		RD_REG_WORD(&reg->mailbox8);
-		WRT_REG_DWORD(&reg->hccr, HCCRX_SET_HOST_INT);
-
-		for (timer = 6000000; timer; timer--) {
-			/* Check for pending interrupts. */
-			stat = RD_REG_DWORD(&reg->host_status);
-			if (stat & HSRX_RISC_INT) {
-				stat &= 0xff;
-
-				if (stat == 0x1 || stat == 0x2 ||
-				    stat == 0x10 || stat == 0x11) {
-					set_bit(MBX_INTERRUPT,
-					    &ha->mbx_cmd_flags);
-
-					mb[0] = RD_REG_WORD(&reg->mailbox0);
-					mb[2] = RD_REG_WORD(&reg->mailbox2);
-					mb[3] = RD_REG_WORD(&reg->mailbox3);
-
-					WRT_REG_DWORD(&reg->hccr,
-					    HCCRX_CLR_RISC_INT);
-					RD_REG_DWORD(&reg->hccr);
-					break;
-				}
-
-				/* Clear this intr; it wasn't a mailbox intr */
-				WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
-				RD_REG_DWORD(&reg->hccr);
-			}
-			udelay(5);
-		}
-
-		if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
-			rval = mb[0] & MBS_MASK;
-			fw->ext_mem[cnt] = htonl((mb[3] << 16) | mb[2]);
-		} else {
-			rval = QLA_FUNCTION_FAILED;
-		}
-	}
-
-	if (rval == QLA_SUCCESS) {
-		eft = qla2xxx_copy_queues(ha, &fw->ext_mem[cnt]);
+		nxt = qla2xxx_copy_queues(ha, nxt);
 		if (ha->eft)
-			memcpy(eft, ha->eft, ntohl(ha->fw_dump->eft_size));
+			memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
 	}
 
 	if (rval != QLA_SUCCESS) {
@@ -1337,6 +1340,709 @@
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 }
 
+void
+qla25xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
+{
+	int		rval;
+	uint32_t	cnt;
+	uint32_t	risc_address;
+	uint16_t	mb0, wd;
+
+	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+	uint32_t __iomem *dmp_reg;
+	uint32_t	*iter_reg;
+	uint16_t __iomem *mbx_reg;
+	unsigned long	flags;
+	struct qla25xx_fw_dump *fw;
+	uint32_t	ext_mem_cnt;
+	void		*nxt;
+
+	risc_address = ext_mem_cnt = 0;
+	flags = 0;
+
+	if (!hardware_locked)
+		spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	if (!ha->fw_dump) {
+		qla_printk(KERN_WARNING, ha,
+		    "No buffer available for dump!!!\n");
+		goto qla25xx_fw_dump_failed;
+	}
+
+	if (ha->fw_dumped) {
+		qla_printk(KERN_WARNING, ha,
+		    "Firmware has been previously dumped (%p) -- ignoring "
+		    "request...\n", ha->fw_dump);
+		goto qla25xx_fw_dump_failed;
+	}
+	fw = &ha->fw_dump->isp.isp25;
+	qla2xxx_prep_dump(ha, ha->fw_dump);
+
+	rval = QLA_SUCCESS;
+	fw->host_status = htonl(RD_REG_DWORD(&reg->host_status));
+
+	/* Pause RISC. */
+	if ((RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0) {
+		WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET |
+		    HCCRX_CLR_HOST_INT);
+		RD_REG_DWORD(&reg->hccr);		/* PCI Posting. */
+		WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_PAUSE);
+		for (cnt = 30000;
+		    (RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0 &&
+		    rval == QLA_SUCCESS; cnt--) {
+			if (cnt)
+				udelay(100);
+			else
+				rval = QLA_FUNCTION_TIMEOUT;
+		}
+	}
+
+	if (rval == QLA_SUCCESS) {
+		/* Host interface registers. */
+		dmp_reg = (uint32_t __iomem *)(reg + 0);
+		for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
+			fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+		/* Disable interrupts. */
+		WRT_REG_DWORD(&reg->ictrl, 0);
+		RD_REG_DWORD(&reg->ictrl);
+
+		/* Shadow registers. */
+		WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
+		RD_REG_DWORD(&reg->iobase_addr);
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0000000);
+		fw->shadow_reg[0] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0100000);
+		fw->shadow_reg[1] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0200000);
+		fw->shadow_reg[2] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0300000);
+		fw->shadow_reg[3] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0400000);
+		fw->shadow_reg[4] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0500000);
+		fw->shadow_reg[5] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0600000);
+		fw->shadow_reg[6] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0700000);
+		fw->shadow_reg[7] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0800000);
+		fw->shadow_reg[8] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0900000);
+		fw->shadow_reg[9] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+		WRT_REG_DWORD(&reg->iobase_select, 0xB0A00000);
+		fw->shadow_reg[10] = htonl(RD_REG_DWORD(&reg->iobase_sdata));
+
+		/* RISC I/O register. */
+		WRT_REG_DWORD(&reg->iobase_addr, 0x0010);
+		RD_REG_DWORD(&reg->iobase_addr);
+		fw->risc_io_reg = htonl(RD_REG_DWORD(&reg->iobase_window));
+
+		/* Mailbox registers. */
+		mbx_reg = &reg->mailbox0;
+		for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
+			fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
+
+		/* Transfer sequence registers. */
+		iter_reg = fw->xseq_gp_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0xBF00);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xBF10);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xBF20);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xBF30);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xBF40);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xBF50);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xBF60);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xBF70);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		iter_reg = fw->xseq_0_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0xBFC0);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xBFD0);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xBFE0);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xBFF0);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++)
+			fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+		/* Receive sequence registers. */
+		iter_reg = fw->rseq_gp_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0xFF00);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xFF10);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xFF20);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xFF30);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xFF40);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xFF50);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xFF60);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xFF70);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		iter_reg = fw->rseq_0_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0xFFC0);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xFFD0);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xFFE0);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++)
+			fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xFFF0);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++)
+			fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+		/* Auxiliary sequence registers. */
+		iter_reg = fw->aseq_gp_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0xB000);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xB010);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xB020);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xB030);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xB040);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xB050);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xB060);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xB070);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		iter_reg = fw->aseq_0_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0xB0C0);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xB0D0);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xB0E0);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < sizeof(fw->aseq_1_reg) / 4; cnt++)
+			fw->aseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0xB0F0);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < sizeof(fw->aseq_2_reg) / 4; cnt++)
+			fw->aseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+		/* Command DMA registers. */
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7100);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++)
+			fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
+
+		/* Queues. */
+		iter_reg = fw->req0_dma_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7200);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 8; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		dmp_reg = &reg->iobase_q;
+		for (cnt = 0; cnt < 7; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		iter_reg = fw->resp0_dma_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7300);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 8; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		dmp_reg = &reg->iobase_q;
+		for (cnt = 0; cnt < 7; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		iter_reg = fw->req1_dma_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7400);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 8; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		dmp_reg = &reg->iobase_q;
+		for (cnt = 0; cnt < 7; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		/* Transmit DMA registers. */
+		iter_reg = fw->xmt0_dma_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7600);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7610);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		iter_reg = fw->xmt1_dma_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7620);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7630);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		iter_reg = fw->xmt2_dma_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7640);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7650);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		iter_reg = fw->xmt3_dma_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7660);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7670);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		iter_reg = fw->xmt4_dma_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7680);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7690);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x76A0);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++)
+			fw->xmt_data_dma_reg[cnt] =
+			    htonl(RD_REG_DWORD(dmp_reg++));
+
+		/* Receive DMA registers. */
+		iter_reg = fw->rcvt0_data_dma_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7700);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7710);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		iter_reg = fw->rcvt1_data_dma_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7720);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x7730);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		/* RISC registers. */
+		iter_reg = fw->risc_gp_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0x0F00);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x0F10);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x0F20);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x0F30);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x0F40);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x0F50);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x0F60);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		/* Local memory controller registers. */
+		iter_reg = fw->lmc_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0x3000);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x3010);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x3020);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x3030);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x3040);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x3050);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x3060);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x3070);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		/* Fibre Protocol Module registers. */
+		iter_reg = fw->fpm_hdw_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0x4000);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x4010);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x4020);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x4030);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x4040);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x4050);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x4060);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x4070);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x4080);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x4090);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x40A0);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x40B0);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		/* Frame Buffer registers. */
+		iter_reg = fw->fb_hdw_reg;
+		WRT_REG_DWORD(&reg->iobase_addr, 0x6000);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x6010);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x6020);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x6030);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x6040);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x6100);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x6130);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x6150);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x6170);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x6190);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x61B0);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		WRT_REG_DWORD(&reg->iobase_addr, 0x6F00);
+		dmp_reg = &reg->iobase_window;
+		for (cnt = 0; cnt < 16; cnt++)
+			*iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
+
+		/* Reset RISC. */
+		WRT_REG_DWORD(&reg->ctrl_status,
+		    CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
+		for (cnt = 0; cnt < 30000; cnt++) {
+			if ((RD_REG_DWORD(&reg->ctrl_status) &
+			    CSRX_DMA_ACTIVE) == 0)
+				break;
+
+			udelay(10);
+		}
+
+		WRT_REG_DWORD(&reg->ctrl_status,
+		    CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
+		pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
+
+		udelay(100);
+		/* Wait for firmware to complete NVRAM accesses. */
+		mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+		for (cnt = 10000 ; cnt && mb0; cnt--) {
+			udelay(5);
+			mb0 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
+			barrier();
+		}
+
+		/* Wait for soft-reset to complete. */
+		for (cnt = 0; cnt < 30000; cnt++) {
+			if ((RD_REG_DWORD(&reg->ctrl_status) &
+			    CSRX_ISP_SOFT_RESET) == 0)
+				break;
+
+			udelay(10);
+		}
+		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
+		RD_REG_DWORD(&reg->hccr);             /* PCI Posting. */
+	}
+
+	for (cnt = 30000; RD_REG_WORD(&reg->mailbox0) != 0 &&
+	    rval == QLA_SUCCESS; cnt--) {
+		if (cnt)
+			udelay(100);
+		else
+			rval = QLA_FUNCTION_TIMEOUT;
+	}
+
+	if (rval == QLA_SUCCESS)
+		rval = qla2xxx_dump_memory(ha, fw->code_ram,
+		    sizeof(fw->code_ram), fw->ext_mem, &nxt);
+
+	if (rval == QLA_SUCCESS) {
+		nxt = qla2xxx_copy_queues(ha, nxt);
+		if (ha->eft)
+			memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size));
+	}
+
+	if (rval != QLA_SUCCESS) {
+		qla_printk(KERN_WARNING, ha,
+		    "Failed to dump firmware (%x)!!!\n", rval);
+		ha->fw_dumped = 0;
+
+	} else {
+		qla_printk(KERN_INFO, ha,
+		    "Firmware dump saved to temp buffer (%ld/%p).\n",
+		    ha->host_no, ha->fw_dump);
+		ha->fw_dumped = 1;
+	}
+
+qla25xx_fw_dump_failed:
+	if (!hardware_locked)
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
 /****************************************************************************/
 /*                         Driver Debug Functions.                          */
 /****************************************************************************/
@@ -1344,21 +2050,18 @@
 void
 qla2x00_dump_regs(scsi_qla_host_t *ha)
 {
+	int i;
 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+	struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
+	uint16_t __iomem *mbx_reg;
+
+	mbx_reg = IS_FWI2_CAPABLE(ha) ? &reg24->mailbox0:
+	    MAILBOX_REG(ha, reg, 0);
 
 	printk("Mailbox registers:\n");
-	printk("scsi(%ld): mbox 0 0x%04x \n",
-	    ha->host_no, RD_MAILBOX_REG(ha, reg, 0));
-	printk("scsi(%ld): mbox 1 0x%04x \n",
-	    ha->host_no, RD_MAILBOX_REG(ha, reg, 1));
-	printk("scsi(%ld): mbox 2 0x%04x \n",
-	    ha->host_no, RD_MAILBOX_REG(ha, reg, 2));
-	printk("scsi(%ld): mbox 3 0x%04x \n",
-	    ha->host_no, RD_MAILBOX_REG(ha, reg, 3));
-	printk("scsi(%ld): mbox 4 0x%04x \n",
-	    ha->host_no, RD_MAILBOX_REG(ha, reg, 4));
-	printk("scsi(%ld): mbox 5 0x%04x \n",
-	    ha->host_no, RD_MAILBOX_REG(ha, reg, 5));
+	for (i = 0; i < 6; i++)
+		printk("scsi(%ld): mbox %d 0x%04x \n", ha->host_no, i,
+		    RD_REG_WORD(mbx_reg++));
 }
 
 
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index 49dffeb..cca4b0d 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -213,6 +213,43 @@
 	uint32_t ext_mem[1];
 };
 
+struct qla25xx_fw_dump {
+	uint32_t host_status;
+	uint32_t host_reg[32];
+	uint32_t shadow_reg[11];
+	uint32_t risc_io_reg;
+	uint16_t mailbox_reg[32];
+	uint32_t xseq_gp_reg[128];
+	uint32_t xseq_0_reg[48];
+	uint32_t xseq_1_reg[16];
+	uint32_t rseq_gp_reg[128];
+	uint32_t rseq_0_reg[32];
+	uint32_t rseq_1_reg[16];
+	uint32_t rseq_2_reg[16];
+	uint32_t aseq_gp_reg[128];
+	uint32_t aseq_0_reg[32];
+	uint32_t aseq_1_reg[16];
+	uint32_t aseq_2_reg[16];
+	uint32_t cmd_dma_reg[16];
+	uint32_t req0_dma_reg[15];
+	uint32_t resp0_dma_reg[15];
+	uint32_t req1_dma_reg[15];
+	uint32_t xmt0_dma_reg[32];
+	uint32_t xmt1_dma_reg[32];
+	uint32_t xmt2_dma_reg[32];
+	uint32_t xmt3_dma_reg[32];
+	uint32_t xmt4_dma_reg[32];
+	uint32_t xmt_data_dma_reg[16];
+	uint32_t rcvt0_data_dma_reg[32];
+	uint32_t rcvt1_data_dma_reg[32];
+	uint32_t risc_gp_reg[128];
+	uint32_t lmc_reg[128];
+	uint32_t fpm_hdw_reg[192];
+	uint32_t fb_hdw_reg[192];
+	uint32_t code_ram[0x2000];
+	uint32_t ext_mem[1];
+};
+
 #define EFT_NUM_BUFFERS		4
 #define EFT_BYTES_PER_BUFFER	0x4000
 #define EFT_SIZE		((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS))
@@ -246,5 +283,6 @@
 		struct qla2100_fw_dump isp21;
 		struct qla2300_fw_dump isp23;
 		struct qla24xx_fw_dump isp24;
+		struct qla25xx_fw_dump isp25;
 	} isp;
 };
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index a1ca590..c196486 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -1502,7 +1502,6 @@
 	uint8_t node_name[WWN_SIZE];
 	uint8_t port_name[WWN_SIZE];
 	uint8_t fabric_port_name[WWN_SIZE];
-	uint16_t fp_speeds;
 	uint16_t fp_speed;
 } sw_info_t;
 
@@ -1711,6 +1710,14 @@
 #define FDMI_PORT_OS_DEVICE_NAME	5
 #define FDMI_PORT_HOST_NAME		6
 
+#define FDMI_PORT_SPEED_1GB		0x1
+#define FDMI_PORT_SPEED_2GB		0x2
+#define FDMI_PORT_SPEED_10GB		0x4
+#define FDMI_PORT_SPEED_4GB		0x8
+#define FDMI_PORT_SPEED_8GB		0x10
+#define FDMI_PORT_SPEED_16GB		0x20
+#define FDMI_PORT_SPEED_UNKNOWN		0x8000
+
 struct ct_fdmi_port_attr {
 	uint16_t type;
 	uint16_t len;
@@ -2201,6 +2208,7 @@
 #define	SWITCH_FOUND			BIT_3
 #define	DFLG_NO_CABLE			BIT_4
 
+#define PCI_DEVICE_ID_QLOGIC_ISP2532	0x2532
 	uint32_t	device_type;
 #define DT_ISP2100			BIT_0
 #define DT_ISP2200			BIT_1
@@ -2213,8 +2221,11 @@
 #define DT_ISP2432			BIT_8
 #define DT_ISP5422			BIT_9
 #define DT_ISP5432			BIT_10
-#define DT_ISP_LAST			(DT_ISP5432 << 1)
+#define DT_ISP2532			BIT_11
+#define DT_ISP_LAST			(DT_ISP2532 << 1)
 
+#define DT_IIDMA			BIT_26
+#define DT_FWI2				BIT_27
 #define DT_ZIO_SUPPORTED		BIT_28
 #define DT_OEM_001			BIT_29
 #define DT_ISP2200A			BIT_30
@@ -2232,12 +2243,16 @@
 #define IS_QLA2432(ha)	(DT_MASK(ha) & DT_ISP2432)
 #define IS_QLA5422(ha)	(DT_MASK(ha) & DT_ISP5422)
 #define IS_QLA5432(ha)	(DT_MASK(ha) & DT_ISP5432)
+#define IS_QLA2532(ha)	(DT_MASK(ha) & DT_ISP2532)
 
 #define IS_QLA23XX(ha)	(IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \
     			 IS_QLA6312(ha) || IS_QLA6322(ha))
 #define IS_QLA24XX(ha)	(IS_QLA2422(ha) || IS_QLA2432(ha))
 #define IS_QLA54XX(ha)	(IS_QLA5422(ha) || IS_QLA5432(ha))
+#define IS_QLA25XX(ha)	(IS_QLA2532(ha))
 
+#define IS_IIDMA_CAPABLE(ha)	((ha)->device_type & DT_IIDMA)
+#define IS_FWI2_CAPABLE(ha)	((ha)->device_type & DT_FWI2)
 #define IS_ZIO_SUPPORTED(ha)	((ha)->device_type & DT_ZIO_SUPPORTED)
 #define IS_OEM_001(ha)		((ha)->device_type & DT_OEM_001)
 #define HAS_EXTENDED_IDS(ha)	((ha)->device_type & DT_EXTENDED_IDS)
@@ -2274,7 +2289,7 @@
 	uint16_t        rsp_ring_index;     /* Current index. */
 	uint16_t	response_q_length;
 
-	struct isp_operations isp_ops;
+	struct isp_operations *isp_ops;
 
 	/* Outstandings ISP commands. */
 	srb_t		*outstanding_cmds[MAX_OUTSTANDING_COMMANDS];
@@ -2298,6 +2313,7 @@
 #define PORT_SPEED_1GB	0x00
 #define PORT_SPEED_2GB	0x01
 #define PORT_SPEED_4GB	0x03
+#define PORT_SPEED_8GB	0x04
 	uint16_t	link_data_rate;		/* F/W operating speed */
 
 	uint8_t		current_topology;
@@ -2323,10 +2339,14 @@
 	uint8_t		serial2;
 
 	/* NVRAM configuration data */
+#define MAX_NVRAM_SIZE	4096
+#define VPD_OFFSET	MAX_NVRAM_SIZE / 2
 	uint16_t	nvram_size;
 	uint16_t	nvram_base;
+	void		*nvram;
 	uint16_t	vpd_size;
 	uint16_t	vpd_base;
+	void		*vpd;
 
 	uint16_t	loop_reset_delay;
 	uint8_t		retry_count;
@@ -2564,6 +2584,7 @@
 #define OPTROM_SIZE_2300	0x20000
 #define OPTROM_SIZE_2322	0x100000
 #define OPTROM_SIZE_24XX	0x100000
+#define OPTROM_SIZE_25XX	0x200000
 
 #include "qla_gbl.h"
 #include "qla_dbg.h"
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 63a11fe..99fe496 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -8,14 +8,17 @@
 #define __QLA_FW_H
 
 #define MBS_CHECKSUM_ERROR	0x4010
+#define MBS_INVALID_PRODUCT_KEY	0x4020
 
 /*
  * Firmware Options.
  */
 #define FO1_ENABLE_PUREX	BIT_10
 #define FO1_DISABLE_LED_CTRL	BIT_6
+#define FO1_ENABLE_8016		BIT_0
 #define FO2_ENABLE_SEL_CLASS2	BIT_5
 #define FO3_NO_ABTS_ON_LINKDOWN	BIT_14
+#define FO3_HOLD_STS_IOCB	BIT_12
 
 /*
  * Port Database structure definition for ISP 24xx.
@@ -341,7 +344,9 @@
 	 * BIT 10 = Reserved
 	 * BIT 11 = Enable FC-SP Security
 	 * BIT 12 = FC Tape Enable
-	 * BIT 13-31 = Reserved
+	 * BIT 13 = Reserved
+	 * BIT 14 = Enable Target PRLI Control
+	 * BIT 15-31 = Reserved
 	 */
 	uint32_t firmware_options_2;
 
@@ -363,7 +368,8 @@
 	 * BIT 13 = Data Rate bit 0
 	 * BIT 14 = Data Rate bit 1
 	 * BIT 15 = Data Rate bit 2
-	 * BIT 16-31 = Reserved
+	 * BIT 16 = Enable 75 ohm Termination Select
+	 * BIT 17-31 = Reserved
 	 */
 	uint32_t firmware_options_3;
 
@@ -435,6 +441,7 @@
 #define TMF_LUN_RESET		BIT_12
 #define TMF_CLEAR_TASK_SET	BIT_10
 #define TMF_ABORT_TASK_SET	BIT_9
+#define TMF_DSD_LIST_ENABLE	BIT_2
 #define TMF_READ_DATA		BIT_1
 #define TMF_WRITE_DATA		BIT_0
 
@@ -589,7 +596,7 @@
 #define EST_SOFI3		(1 << 4)
 #define EST_SOFI2		(3 << 4)
 
-	uint32_t rx_xchg_address[2];	/* Receive exchange address. */
+	uint32_t rx_xchg_address;	/* Receive exchange address. */
 	uint16_t rx_dsd_count;
 
 	uint8_t opcode;
@@ -650,6 +657,7 @@
 
 	uint16_t control_flags;		/* Control flags. */
 					/* Modifiers. */
+#define LCF_INCLUDE_SNS		BIT_10	/* Include SNS (FFFFFC) during LOGO. */
 #define LCF_FCP2_OVERRIDE	BIT_9	/* Set/Reset word 3 of PRLI. */
 #define LCF_CLASS_2		BIT_8	/* Enable class 2 during PLOGI. */
 #define LCF_FREE_NPORT		BIT_7	/* Release NPORT handle after LOGO. */
@@ -779,6 +787,15 @@
 #define FA_RISC_CODE_ADDR	0x20000
 #define FA_RISC_CODE_SEGMENTS	2
 
+#define FA_FW_AREA_ADDR		0x40000
+#define FA_VPD_NVRAM_ADDR	0x48000
+#define FA_FEATURE_ADDR		0x4C000
+#define FA_FLASH_DESCR_ADDR	0x50000
+#define FA_HW_EVENT_ADDR	0x54000
+#define FA_BOOT_LOG_ADDR	0x58000
+#define FA_FW_DUMP0_ADDR	0x60000
+#define FA_FW_DUMP1_ADDR	0x70000
+
 	uint32_t flash_data;		/* Flash/NVRAM BIOS data. */
 
 	uint32_t ctrl_status;		/* Control/Status. */
@@ -859,10 +876,13 @@
 #define HCCRX_CLR_RISC_INT	0xA0000000
 
 	uint32_t gpiod;			/* GPIO Data register. */
+
 					/* LED update mask. */
 #define GPDX_LED_UPDATE_MASK	(BIT_20|BIT_19|BIT_18)
 					/* Data update mask. */
 #define GPDX_DATA_UPDATE_MASK	(BIT_17|BIT_16)
+					/* Data update mask. */
+#define GPDX_DATA_UPDATE_2_MASK	(BIT_28|BIT_27|BIT_26|BIT_17|BIT_16)
 					/* LED control mask. */
 #define GPDX_LED_COLOR_MASK	(BIT_4|BIT_3|BIT_2)
 					/* LED bit values. Color names as
@@ -877,6 +897,8 @@
 	uint32_t gpioe;			/* GPIO Enable register. */
 					/* Enable update mask. */
 #define GPEX_ENABLE_UPDATE_MASK	(BIT_17|BIT_16)
+					/* Enable update mask. */
+#define GPEX_ENABLE_UPDATE_2_MASK (BIT_28|BIT_27|BIT_26|BIT_17|BIT_16)
 					/* Enable. */
 #define GPEX_ENABLE		(BIT_1|BIT_0)
 
@@ -916,6 +938,14 @@
 	uint16_t mailbox29;
 	uint16_t mailbox30;
 	uint16_t mailbox31;
+
+	uint32_t iobase_window;
+	uint32_t unused_4[8];		/* Gap. */
+	uint32_t iobase_q;
+	uint32_t unused_5[2];		/* Gap. */
+	uint32_t iobase_select;
+	uint32_t unused_6[2];		/* Gap. */
+	uint32_t iobase_sdata;
 };
 
 /* MID Support ***************************************************************/
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index b44eff2..aa1e411 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -17,6 +17,7 @@
 extern int qla2100_pci_config(struct scsi_qla_host *);
 extern int qla2300_pci_config(struct scsi_qla_host *);
 extern int qla24xx_pci_config(scsi_qla_host_t *);
+extern int qla25xx_pci_config(scsi_qla_host_t *);
 extern void qla2x00_reset_chip(struct scsi_qla_host *);
 extern void qla24xx_reset_chip(struct scsi_qla_host *);
 extern int qla2x00_chip_diag(struct scsi_qla_host *);
@@ -281,6 +282,10 @@
     uint32_t);
 extern int qla24xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
     uint32_t);
+extern uint8_t *qla25xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
+    uint32_t);
+extern int qla25xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t,
+    uint32_t);
 
 extern int qla2x00_beacon_on(struct scsi_qla_host *);
 extern int qla2x00_beacon_off(struct scsi_qla_host *);
@@ -307,6 +312,7 @@
 extern void qla2100_fw_dump(scsi_qla_host_t *, int);
 extern void qla2300_fw_dump(scsi_qla_host_t *, int);
 extern void qla24xx_fw_dump(scsi_qla_host_t *, int);
+extern void qla25xx_fw_dump(scsi_qla_host_t *, int);
 extern void qla2x00_dump_regs(scsi_qla_host_t *);
 extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
 extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *);
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index a086b3f..a7e2358 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -127,7 +127,7 @@
 		DEBUG2_3(printk("scsi(%ld): %s failed, error status (%x).\n",
 		    ha->host_no, routine, ms_pkt->entry_status));
 	} else {
-		if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+		if (IS_FWI2_CAPABLE(ha))
 			comp_status = le16_to_cpu(
 			    ((struct ct_entry_24xx *)ms_pkt)->comp_status);
 		else
@@ -180,7 +180,8 @@
 
 	/* Issue GA_NXT */
 	/* Prepare common MS IOCB */
-	ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GA_NXT_REQ_SIZE, GA_NXT_RSP_SIZE);
+	ms_pkt = ha->isp_ops->prep_ms_iocb(ha, GA_NXT_REQ_SIZE,
+	    GA_NXT_RSP_SIZE);
 
 	/* Prepare CT request */
 	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GA_NXT_CMD,
@@ -266,7 +267,8 @@
 
 	/* Issue GID_PT */
 	/* Prepare common MS IOCB */
-	ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GID_PT_REQ_SIZE, GID_PT_RSP_SIZE);
+	ms_pkt = ha->isp_ops->prep_ms_iocb(ha, GID_PT_REQ_SIZE,
+	    GID_PT_RSP_SIZE);
 
 	/* Prepare CT request */
 	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GID_PT_CMD,
@@ -293,6 +295,8 @@
 			list[i].d_id.b.domain = gid_data->port_id[0];
 			list[i].d_id.b.area = gid_data->port_id[1];
 			list[i].d_id.b.al_pa = gid_data->port_id[2];
+			memset(list[i].fabric_port_name, 0, WWN_SIZE);
+			list[i].fp_speed = PORT_SPEED_UNKNOWN;
 
 			/* Last one exit. */
 			if (gid_data->control_byte & BIT_7) {
@@ -338,7 +342,7 @@
 	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
 		/* Issue GPN_ID */
 		/* Prepare common MS IOCB */
-		ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GPN_ID_REQ_SIZE,
+		ms_pkt = ha->isp_ops->prep_ms_iocb(ha, GPN_ID_REQ_SIZE,
 		    GPN_ID_RSP_SIZE);
 
 		/* Prepare CT request */
@@ -399,7 +403,7 @@
 	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
 		/* Issue GNN_ID */
 		/* Prepare common MS IOCB */
-		ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GNN_ID_REQ_SIZE,
+		ms_pkt = ha->isp_ops->prep_ms_iocb(ha, GNN_ID_REQ_SIZE,
 		    GNN_ID_RSP_SIZE);
 
 		/* Prepare CT request */
@@ -473,7 +477,8 @@
 
 	/* Issue RFT_ID */
 	/* Prepare common MS IOCB */
-	ms_pkt = ha->isp_ops.prep_ms_iocb(ha, RFT_ID_REQ_SIZE, RFT_ID_RSP_SIZE);
+	ms_pkt = ha->isp_ops->prep_ms_iocb(ha, RFT_ID_REQ_SIZE,
+	    RFT_ID_RSP_SIZE);
 
 	/* Prepare CT request */
 	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFT_ID_CMD,
@@ -528,7 +533,8 @@
 
 	/* Issue RFF_ID */
 	/* Prepare common MS IOCB */
-	ms_pkt = ha->isp_ops.prep_ms_iocb(ha, RFF_ID_REQ_SIZE, RFF_ID_RSP_SIZE);
+	ms_pkt = ha->isp_ops->prep_ms_iocb(ha, RFF_ID_REQ_SIZE,
+	    RFF_ID_RSP_SIZE);
 
 	/* Prepare CT request */
 	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFF_ID_CMD,
@@ -582,7 +588,8 @@
 
 	/* Issue RNN_ID */
 	/* Prepare common MS IOCB */
-	ms_pkt = ha->isp_ops.prep_ms_iocb(ha, RNN_ID_REQ_SIZE, RNN_ID_RSP_SIZE);
+	ms_pkt = ha->isp_ops->prep_ms_iocb(ha, RNN_ID_REQ_SIZE,
+	    RNN_ID_RSP_SIZE);
 
 	/* Prepare CT request */
 	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RNN_ID_CMD,
@@ -645,7 +652,7 @@
 	/* Issue RSNN_NN */
 	/* Prepare common MS IOCB */
 	/*   Request size adjusted after CT preparation */
-	ms_pkt = ha->isp_ops.prep_ms_iocb(ha, 0, RSNN_NN_RSP_SIZE);
+	ms_pkt = ha->isp_ops->prep_ms_iocb(ha, 0, RSNN_NN_RSP_SIZE);
 
 	/* Prepare CT request */
 	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RSNN_NN_CMD,
@@ -1102,7 +1109,7 @@
 	if (ha->flags.management_server_logged_in)
 		return ret;
 
-	ha->isp_ops.fabric_login(ha, ha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa,
+	ha->isp_ops->fabric_login(ha, ha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa,
 	    mb, BIT_1);
 	if (mb[0] != MBS_COMMAND_COMPLETE) {
 		DEBUG2_13(printk("%s(%ld): Failed MANAGEMENT_SERVER login: "
@@ -1198,7 +1205,7 @@
 	ms_iocb_entry_t *ms_pkt = ha->ms_iocb;
 	struct ct_entry_24xx *ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
 
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+	if (IS_FWI2_CAPABLE(ha)) {
 		ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
 		ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
 	} else {
@@ -1253,7 +1260,7 @@
 	/* Issue RHBA */
 	/* Prepare common MS IOCB */
 	/*   Request size adjusted after CT preparation */
-	ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, 0, RHBA_RSP_SIZE);
+	ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(ha, 0, RHBA_RSP_SIZE);
 
 	/* Prepare CT request */
 	ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RHBA_CMD,
@@ -1373,7 +1380,7 @@
 	/* Firmware version */
 	eiter = (struct ct_fdmi_hba_attr *) (entries + size);
 	eiter->type = __constant_cpu_to_be16(FDMI_HBA_FIRMWARE_VERSION);
-	ha->isp_ops.fw_version_str(ha, eiter->a.fw_version);
+	ha->isp_ops->fw_version_str(ha, eiter->a.fw_version);
 	alen = strlen(eiter->a.fw_version);
 	alen += (alen & 3) ? (4 - (alen & 3)) : 4;
 	eiter->len = cpu_to_be16(4 + alen);
@@ -1439,7 +1446,7 @@
 
 	/* Issue RPA */
 	/* Prepare common MS IOCB */
-	ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, DHBA_REQ_SIZE,
+	ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(ha, DHBA_REQ_SIZE,
 	    DHBA_RSP_SIZE);
 
 	/* Prepare CT request */
@@ -1497,7 +1504,7 @@
 	/* Issue RPA */
 	/* Prepare common MS IOCB */
 	/*   Request size adjusted after CT preparation */
-	ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, 0, RPA_RSP_SIZE);
+	ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(ha, 0, RPA_RSP_SIZE);
 
 	/* Prepare CT request */
 	ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RPA_CMD,
@@ -1527,12 +1534,20 @@
 	eiter = (struct ct_fdmi_port_attr *) (entries + size);
 	eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED);
 	eiter->len = __constant_cpu_to_be16(4 + 4);
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
-		eiter->a.sup_speed = __constant_cpu_to_be32(4);
+	if (IS_QLA25XX(ha))
+		eiter->a.sup_speed = __constant_cpu_to_be32(
+		    FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB|
+		    FDMI_PORT_SPEED_4GB|FDMI_PORT_SPEED_8GB);
+	else if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+		eiter->a.sup_speed = __constant_cpu_to_be32(
+		    FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB|
+		    FDMI_PORT_SPEED_4GB);
 	else if (IS_QLA23XX(ha))
-		eiter->a.sup_speed = __constant_cpu_to_be32(2);
+		eiter->a.sup_speed =__constant_cpu_to_be32(
+		    FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB);
 	else
-		eiter->a.sup_speed = __constant_cpu_to_be32(1);
+		eiter->a.sup_speed = __constant_cpu_to_be32(
+		    FDMI_PORT_SPEED_1GB);
 	size += 4 + 4;
 
 	DEBUG13(printk("%s(%ld): SUPPORTED_SPEED=%x.\n", __func__, ha->host_no,
@@ -1543,14 +1558,25 @@
 	eiter->type = __constant_cpu_to_be16(FDMI_PORT_CURRENT_SPEED);
 	eiter->len = __constant_cpu_to_be16(4 + 4);
 	switch (ha->link_data_rate) {
-	case 0:
-		eiter->a.cur_speed = __constant_cpu_to_be32(1);
+	case PORT_SPEED_1GB:
+		eiter->a.cur_speed =
+		    __constant_cpu_to_be32(FDMI_PORT_SPEED_1GB);
 		break;
-	case 1:
-		eiter->a.cur_speed = __constant_cpu_to_be32(2);
+	case PORT_SPEED_2GB:
+		eiter->a.cur_speed =
+		    __constant_cpu_to_be32(FDMI_PORT_SPEED_2GB);
 		break;
-	case 3:
-		eiter->a.cur_speed = __constant_cpu_to_be32(4);
+	case PORT_SPEED_4GB:
+		eiter->a.cur_speed =
+		    __constant_cpu_to_be32(FDMI_PORT_SPEED_4GB);
+		break;
+	case PORT_SPEED_8GB:
+		eiter->a.cur_speed =
+		    __constant_cpu_to_be32(FDMI_PORT_SPEED_8GB);
+		break;
+	default:
+		eiter->a.cur_speed =
+		    __constant_cpu_to_be32(FDMI_PORT_SPEED_UNKNOWN);
 		break;
 	}
 	size += 4 + 4;
@@ -1562,7 +1588,7 @@
 	eiter = (struct ct_fdmi_port_attr *) (entries + size);
 	eiter->type = __constant_cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE);
 	eiter->len = __constant_cpu_to_be16(4 + 4);
-	max_frame_size = IS_QLA24XX(ha) || IS_QLA54XX(ha) ?
+	max_frame_size = IS_FWI2_CAPABLE(ha) ?
 		(uint32_t) icb24->frame_payload_size:
 		(uint32_t) ha->init_cb->frame_payload_size;
 	eiter->a.max_frame_size = cpu_to_be32(max_frame_size);
@@ -1678,15 +1704,13 @@
 	struct ct_sns_req	*ct_req;
 	struct ct_sns_rsp	*ct_rsp;
 
-	if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+	if (!IS_IIDMA_CAPABLE(ha))
 		return QLA_FUNCTION_FAILED;
 
 	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
 		/* Issue GFPN_ID */
-		memset(list[i].fabric_port_name, 0, WWN_SIZE);
-
 		/* Prepare common MS IOCB */
-		ms_pkt = ha->isp_ops.prep_ms_iocb(ha, GFPN_ID_REQ_SIZE,
+		ms_pkt = ha->isp_ops->prep_ms_iocb(ha, GFPN_ID_REQ_SIZE,
 		    GFPN_ID_RSP_SIZE);
 
 		/* Prepare CT request */
@@ -1786,7 +1810,7 @@
 	struct ct_sns_req	*ct_req;
 	struct ct_sns_rsp	*ct_rsp;
 
-	if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+	if (!IS_IIDMA_CAPABLE(ha))
 		return QLA_FUNCTION_FAILED;
 	if (!ha->flags.gpsc_supported)
 		return QLA_FUNCTION_FAILED;
@@ -1797,8 +1821,6 @@
 
 	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
 		/* Issue GFPN_ID */
-		list[i].fp_speeds = list[i].fp_speed = 0;
-
 		/* Prepare common MS IOCB */
 		ms_pkt = qla24xx_prep_ms_fm_iocb(ha, GPSC_REQ_SIZE,
 		    GPSC_RSP_SIZE);
@@ -1834,9 +1856,21 @@
 			}
 			rval = QLA_FUNCTION_FAILED;
 		} else {
-			/* Save portname */
-			list[i].fp_speeds = ct_rsp->rsp.gpsc.speeds;
-			list[i].fp_speed = ct_rsp->rsp.gpsc.speed;
+			/* Save port-speed */
+			switch (be16_to_cpu(ct_rsp->rsp.gpsc.speed)) {
+			case BIT_15:
+				list[i].fp_speed = PORT_SPEED_1GB;
+				break;
+			case BIT_14:
+				list[i].fp_speed = PORT_SPEED_2GB;
+				break;
+			case BIT_13:
+				list[i].fp_speed = PORT_SPEED_4GB;
+				break;
+			case BIT_11:
+				list[i].fp_speed = PORT_SPEED_8GB;
+				break;
+			}
 
 			DEBUG2_3(printk("scsi(%ld): GPSC ext entry - "
 			    "fpn %02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x "
@@ -1849,8 +1883,8 @@
 			    list[i].fabric_port_name[5],
 			    list[i].fabric_port_name[6],
 			    list[i].fabric_port_name[7],
-			    be16_to_cpu(list[i].fp_speeds),
-			    be16_to_cpu(list[i].fp_speed)));
+			    be16_to_cpu(ct_rsp->rsp.gpsc.speeds),
+			    be16_to_cpu(ct_rsp->rsp.gpsc.speed)));
 		}
 
 		/* Last device exit. */
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index cc6ebb6..1a058ec 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -79,20 +79,20 @@
 	set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
 
 	qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
-	rval = ha->isp_ops.pci_config(ha);
+	rval = ha->isp_ops->pci_config(ha);
 	if (rval) {
 		DEBUG2(printk("scsi(%ld): Unable to configure PCI space.\n",
 		    ha->host_no));
 		return (rval);
 	}
 
-	ha->isp_ops.reset_chip(ha);
+	ha->isp_ops->reset_chip(ha);
 
-	ha->isp_ops.get_flash_version(ha, ha->request_ring);
+	ha->isp_ops->get_flash_version(ha, ha->request_ring);
 
 	qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
 
-	ha->isp_ops.nvram_config(ha);
+	ha->isp_ops->nvram_config(ha);
 
 	if (ha->flags.disable_serdes) {
 		/* Mask HBA via NVRAM settings? */
@@ -108,7 +108,7 @@
 	qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
 
 	if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
-		rval = ha->isp_ops.chip_diag(ha);
+		rval = ha->isp_ops->chip_diag(ha);
 		if (rval)
 			return (rval);
 		rval = qla2x00_setup_chip(ha);
@@ -129,14 +129,13 @@
 int
 qla2100_pci_config(scsi_qla_host_t *ha)
 {
-	int ret;
 	uint16_t w;
 	uint32_t d;
 	unsigned long flags;
 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
 	pci_set_master(ha->pdev);
-	ret = pci_set_mwi(ha->pdev);
+	pci_try_set_mwi(ha->pdev);
 
 	pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
 	w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
@@ -164,7 +163,6 @@
 int
 qla2300_pci_config(scsi_qla_host_t *ha)
 {
-	int		ret;
 	uint16_t	w;
 	uint32_t	d;
 	unsigned long   flags = 0;
@@ -172,7 +170,7 @@
 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
 	pci_set_master(ha->pdev);
-	ret = pci_set_mwi(ha->pdev);
+	pci_try_set_mwi(ha->pdev);
 
 	pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
 	w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
@@ -250,15 +248,13 @@
 int
 qla24xx_pci_config(scsi_qla_host_t *ha)
 {
-	int ret;
 	uint16_t w;
 	uint32_t d;
 	unsigned long flags = 0;
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
-	int pcix_cmd_reg, pcie_dctl_reg;
 
 	pci_set_master(ha->pdev);
-	ret = pci_set_mwi(ha->pdev);
+	pci_try_set_mwi(ha->pdev);
 
 	pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
 	w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
@@ -268,28 +264,12 @@
 	pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
 
 	/* PCI-X -- adjust Maximum Memory Read Byte Count (2048). */
-	pcix_cmd_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX);
-	if (pcix_cmd_reg) {
-		uint16_t pcix_cmd;
-
-		pcix_cmd_reg += PCI_X_CMD;
-		pci_read_config_word(ha->pdev, pcix_cmd_reg, &pcix_cmd);
-		pcix_cmd &= ~PCI_X_CMD_MAX_READ;
-		pcix_cmd |= 0x0008;
-		pci_write_config_word(ha->pdev, pcix_cmd_reg, pcix_cmd);
-	}
+	if (pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX))
+		pcix_set_mmrbc(ha->pdev, 2048);
 
 	/* PCIe -- adjust Maximum Read Request Size (2048). */
-	pcie_dctl_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
-	if (pcie_dctl_reg) {
-		uint16_t pcie_dctl;
-
-		pcie_dctl_reg += PCI_EXP_DEVCTL;
-		pci_read_config_word(ha->pdev, pcie_dctl_reg, &pcie_dctl);
-		pcie_dctl &= ~PCI_EXP_DEVCTL_READRQ;
-		pcie_dctl |= 0x4000;
-		pci_write_config_word(ha->pdev, pcie_dctl_reg, pcie_dctl);
-	}
+	if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
+		pcie_set_readrq(ha->pdev, 2048);
 
 	/* Reset expansion ROM address decode enable */
 	pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
@@ -307,6 +287,40 @@
 }
 
 /**
+ * qla25xx_pci_config() - Setup ISP25xx PCI configuration registers.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+int
+qla25xx_pci_config(scsi_qla_host_t *ha)
+{
+	uint16_t w;
+	uint32_t d;
+
+	pci_set_master(ha->pdev);
+	pci_try_set_mwi(ha->pdev);
+
+	pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
+	w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+	w &= ~PCI_COMMAND_INTX_DISABLE;
+	pci_write_config_word(ha->pdev, PCI_COMMAND, w);
+
+	/* PCIe -- adjust Maximum Read Request Size (2048). */
+	if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
+		pcie_set_readrq(ha->pdev, 2048);
+
+	/* Reset expansion ROM address decode enable */
+	pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
+	d &= ~PCI_ROM_ADDRESS_ENABLE;
+	pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
+
+	ha->chip_revision = ha->pdev->revision;
+
+	return QLA_SUCCESS;
+}
+
+/**
  * qla2x00_isp_firmware() - Choose firmware image.
  * @ha: HA context
  *
@@ -351,7 +365,7 @@
 	uint32_t	cnt;
 	uint16_t	cmd;
 
-	ha->isp_ops.disable_intrs(ha);
+	ha->isp_ops->disable_intrs(ha);
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 
@@ -551,7 +565,7 @@
 void
 qla24xx_reset_chip(scsi_qla_host_t *ha)
 {
-	ha->isp_ops.disable_intrs(ha);
+	ha->isp_ops->disable_intrs(ha);
 
 	/* Perform RISC reset. */
 	qla24xx_reset_risc(ha);
@@ -736,8 +750,10 @@
 		fixed_size = offsetof(struct qla2300_fw_dump, data_ram);
 		mem_size = (ha->fw_memory_size - 0x11000 + 1) *
 		    sizeof(uint16_t);
-	} else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
-		fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
+	} else if (IS_FWI2_CAPABLE(ha)) {
+		fixed_size = IS_QLA25XX(ha) ?
+		    offsetof(struct qla25xx_fw_dump, ext_mem):
+		    offsetof(struct qla24xx_fw_dump, ext_mem);
 		mem_size = (ha->fw_memory_size - 0x100000 + 1) *
 		    sizeof(uint32_t);
 
@@ -879,7 +895,7 @@
 	uint32_t srisc_address = 0;
 
 	/* Load firmware sequences */
-	rval = ha->isp_ops.load_risc(ha, &srisc_address);
+	rval = ha->isp_ops->load_risc(ha, &srisc_address);
 	if (rval == QLA_SUCCESS) {
 		DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC "
 		    "code.\n", ha->host_no));
@@ -1130,12 +1146,12 @@
 	/* Initialize response queue entries */
 	qla2x00_init_response_q_entries(ha);
 
-	ha->isp_ops.config_rings(ha);
+	ha->isp_ops->config_rings(ha);
 
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
 	/* Update any ISP specific firmware options before initialization. */
-	ha->isp_ops.update_fw_options(ha);
+	ha->isp_ops->update_fw_options(ha);
 
 	DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no));
 
@@ -1445,8 +1461,8 @@
 	uint16_t        cnt;
 	uint8_t         *dptr1, *dptr2;
 	init_cb_t       *icb = ha->init_cb;
-	nvram_t         *nv = (nvram_t *)ha->request_ring;
-	uint8_t         *ptr = (uint8_t *)ha->request_ring;
+	nvram_t         *nv = ha->nvram;
+	uint8_t         *ptr = ha->nvram;
 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
 	rval = QLA_SUCCESS;
@@ -1459,13 +1475,12 @@
 			ha->nvram_base = 0x80;
 
 	/* Get NVRAM data and calculate checksum. */
-	ha->isp_ops.read_nvram(ha, ptr, ha->nvram_base, ha->nvram_size);
+	ha->isp_ops->read_nvram(ha, ptr, ha->nvram_base, ha->nvram_size);
 	for (cnt = 0, chksum = 0; cnt < ha->nvram_size; cnt++)
 		chksum += *ptr++;
 
 	DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
-	DEBUG5(qla2x00_dump_buffer((uint8_t *)ha->request_ring,
-	    ha->nvram_size));
+	DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
 
 	/* Bad NVRAM data, set defaults parameters. */
 	if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
@@ -2064,17 +2079,7 @@
 		}
 
 		/* Base iIDMA settings on HBA port speed. */
-		switch (ha->link_data_rate) {
-		case PORT_SPEED_1GB:
-			fcport->fp_speed = cpu_to_be16(BIT_15);
-			break;
-		case PORT_SPEED_2GB:
-			fcport->fp_speed = cpu_to_be16(BIT_14);
-			break;
-		case PORT_SPEED_4GB:
-			fcport->fp_speed = cpu_to_be16(BIT_13);
-			break;
-		}
+		fcport->fp_speed = ha->link_data_rate;
 
 		qla2x00_update_fcport(ha, fcport);
 
@@ -2115,38 +2120,25 @@
 qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
 {
 #define LS_UNKNOWN      2
-	static char *link_speeds[5] = { "1", "2", "?", "4" };
+	static char *link_speeds[5] = { "1", "2", "?", "4", "8" };
 	int rval;
-	uint16_t port_speed, mb[6];
+	uint16_t mb[6];
 
-	if (!IS_QLA24XX(ha))
+	if (!IS_IIDMA_CAPABLE(ha))
 		return;
 
-	switch (be16_to_cpu(fcport->fp_speed)) {
-	case BIT_15:
-		port_speed = PORT_SPEED_1GB;
-		break;
-	case BIT_14:
-		port_speed = PORT_SPEED_2GB;
-		break;
-	case BIT_13:
-		port_speed = PORT_SPEED_4GB;
-		break;
-	default:
+	if (fcport->fp_speed == PORT_SPEED_UNKNOWN) {
 		DEBUG2(printk("scsi(%ld): %02x%02x%02x%02x%02x%02x%02x%02x -- "
-		    "unsupported FM port operating speed (%04x).\n",
+		    "unsupported FM port operating speed.\n",
 		    ha->host_no, fcport->port_name[0], fcport->port_name[1],
 		    fcport->port_name[2], fcport->port_name[3],
 		    fcport->port_name[4], fcport->port_name[5],
-		    fcport->port_name[6], fcport->port_name[7],
-		    be16_to_cpu(fcport->fp_speed)));
-		port_speed = PORT_SPEED_UNKNOWN;
-		break;
-	}
-	if (port_speed == PORT_SPEED_UNKNOWN)
+		    fcport->port_name[6], fcport->port_name[7]));
 		return;
+	}
 
-	rval = qla2x00_set_idma_speed(ha, fcport->loop_id, port_speed, mb);
+	rval = qla2x00_set_idma_speed(ha, fcport->loop_id, fcport->fp_speed,
+	    mb);
 	if (rval != QLA_SUCCESS) {
 		DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA "
 		    "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n",
@@ -2154,12 +2146,12 @@
 		    fcport->port_name[2], fcport->port_name[3],
 		    fcport->port_name[4], fcport->port_name[5],
 		    fcport->port_name[6], fcport->port_name[7], rval,
-		    port_speed, mb[0], mb[1]));
+		    fcport->fp_speed, mb[0], mb[1]));
 	} else {
 		DEBUG2(qla_printk(KERN_INFO, ha,
 		    "iIDMA adjusted to %s GB/s on "
 		    "%02x%02x%02x%02x%02x%02x%02x%02x.\n",
-		    link_speeds[port_speed], fcport->port_name[0],
+		    link_speeds[fcport->fp_speed], fcport->port_name[0],
 		    fcport->port_name[1], fcport->port_name[2],
 		    fcport->port_name[3], fcport->port_name[4],
 		    fcport->port_name[5], fcport->port_name[6],
@@ -2267,7 +2259,7 @@
 	scsi_qla_host_t *pha = to_qla_parent(ha);
 
 	/* If FL port exists, then SNS is present */
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+	if (IS_FWI2_CAPABLE(ha))
 		loop_id = NPH_F_PORT;
 	else
 		loop_id = SNS_FL_PORT;
@@ -2294,11 +2286,11 @@
 			qla2x00_fdmi_register(ha);
 
 		/* Ensure we are logged into the SNS. */
-		if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+		if (IS_FWI2_CAPABLE(ha))
 			loop_id = NPH_SNS;
 		else
 			loop_id = SIMPLE_NAME_SERVER;
-		ha->isp_ops.fabric_login(ha, loop_id, 0xff, 0xff,
+		ha->isp_ops->fabric_login(ha, loop_id, 0xff, 0xff,
 		    0xfc, mb, BIT_1 | BIT_0);
 		if (mb[0] != MBS_COMMAND_COMPLETE) {
 			DEBUG2(qla_printk(KERN_INFO, ha,
@@ -2355,7 +2347,7 @@
 				    (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
 				    fcport->port_type != FCT_INITIATOR &&
 				    fcport->port_type != FCT_BROADCAST) {
-					ha->isp_ops.fabric_logout(ha,
+					ha->isp_ops->fabric_logout(ha,
 					    fcport->loop_id,
 					    fcport->d_id.b.domain,
 					    fcport->d_id.b.area,
@@ -2664,7 +2656,7 @@
 			    (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
 			    fcport->port_type != FCT_INITIATOR &&
 			    fcport->port_type != FCT_BROADCAST) {
-				ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+				ha->isp_ops->fabric_logout(ha, fcport->loop_id,
 				    fcport->d_id.b.domain, fcport->d_id.b.area,
 				    fcport->d_id.b.al_pa);
 				fcport->loop_id = FC_NO_LOOP_ID;
@@ -2919,7 +2911,7 @@
 			opts |= BIT_1;
 		rval = qla2x00_get_port_database(ha, fcport, opts);
 		if (rval != QLA_SUCCESS) {
-			ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+			ha->isp_ops->fabric_logout(ha, fcport->loop_id,
 			    fcport->d_id.b.domain, fcport->d_id.b.area,
 			    fcport->d_id.b.al_pa);
 			qla2x00_mark_device_lost(ha, fcport, 1, 0);
@@ -2964,7 +2956,7 @@
 		    fcport->d_id.b.area, fcport->d_id.b.al_pa));
 
 		/* Login fcport on switch. */
-		ha->isp_ops.fabric_login(ha, fcport->loop_id,
+		ha->isp_ops->fabric_login(ha, fcport->loop_id,
 		    fcport->d_id.b.domain, fcport->d_id.b.area,
 		    fcport->d_id.b.al_pa, mb, BIT_0);
 		if (mb[0] == MBS_PORT_ID_USED) {
@@ -3032,7 +3024,7 @@
 			 * dead.
 			 */
 			*next_loopid = fcport->loop_id;
-			ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+			ha->isp_ops->fabric_logout(ha, fcport->loop_id,
 			    fcport->d_id.b.domain, fcport->d_id.b.area,
 			    fcport->d_id.b.al_pa);
 			qla2x00_mark_device_lost(ha, fcport, 1, 0);
@@ -3050,7 +3042,7 @@
 			    fcport->d_id.b.al_pa, fcport->loop_id, jiffies));
 
 			*next_loopid = fcport->loop_id;
-			ha->isp_ops.fabric_logout(ha, fcport->loop_id,
+			ha->isp_ops->fabric_logout(ha, fcport->loop_id,
 			    fcport->d_id.b.domain, fcport->d_id.b.area,
 			    fcport->d_id.b.al_pa);
 			fcport->loop_id = FC_NO_LOOP_ID;
@@ -3206,7 +3198,7 @@
 
 		qla_printk(KERN_INFO, ha,
 		    "Performing ISP error recovery - ha= %p.\n", ha);
-		ha->isp_ops.reset_chip(ha);
+		ha->isp_ops->reset_chip(ha);
 
 		atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
 		if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
@@ -3232,9 +3224,9 @@
 		}
 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-		ha->isp_ops.get_flash_version(ha, ha->request_ring);
+		ha->isp_ops->get_flash_version(ha, ha->request_ring);
 
-		ha->isp_ops.nvram_config(ha);
+		ha->isp_ops->nvram_config(ha);
 
 		if (!qla2x00_restart_isp(ha)) {
 			clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
@@ -3249,7 +3241,7 @@
 
 			ha->flags.online = 1;
 
-			ha->isp_ops.enable_intrs(ha);
+			ha->isp_ops->enable_intrs(ha);
 
 			ha->isp_abort_cnt = 0;
 			clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
@@ -3274,7 +3266,7 @@
 					 * The next call disables the board
 					 * completely.
 					 */
-					ha->isp_ops.reset_adapter(ha);
+					ha->isp_ops->reset_adapter(ha);
 					ha->flags.online = 0;
 					clear_bit(ISP_ABORT_RETRY,
 					    &ha->dpc_flags);
@@ -3331,7 +3323,7 @@
 	/* If firmware needs to be loaded */
 	if (qla2x00_isp_firmware(ha)) {
 		ha->flags.online = 0;
-		if (!(status = ha->isp_ops.chip_diag(ha))) {
+		if (!(status = ha->isp_ops->chip_diag(ha))) {
 			if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
 				status = qla2x00_setup_chip(ha);
 				goto done;
@@ -3339,7 +3331,8 @@
 
 			spin_lock_irqsave(&ha->hardware_lock, flags);
 
-			if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) {
+			if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha) &&
+			    !IS_QLA25XX(ha)) {
 				/*
 				 * Disable SRAM, Instruction RAM and GP RAM
 				 * parity.
@@ -3355,7 +3348,8 @@
 
 			spin_lock_irqsave(&ha->hardware_lock, flags);
 
-			if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) {
+			if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha) &&
+			    !IS_QLA25XX(ha)) {
 				/* Enable proper parity */
 				if (IS_QLA2300(ha))
 					/* SRAM parity */
@@ -3423,7 +3417,7 @@
 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
 	ha->flags.online = 0;
-	ha->isp_ops.disable_intrs(ha);
+	ha->isp_ops->disable_intrs(ha);
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
@@ -3440,7 +3434,7 @@
 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 
 	ha->flags.online = 0;
-	ha->isp_ops.disable_intrs(ha);
+	ha->isp_ops->disable_intrs(ha);
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
@@ -3484,7 +3478,7 @@
 
 	rval = QLA_SUCCESS;
 	icb = (struct init_cb_24xx *)ha->init_cb;
-	nv = (struct nvram_24xx *)ha->request_ring;
+	nv = ha->nvram;
 
 	/* Determine NVRAM starting address. */
 	ha->nvram_size = sizeof(struct nvram_24xx);
@@ -3496,16 +3490,20 @@
 		ha->vpd_base = FA_NVRAM_VPD1_ADDR;
 	}
 
-	/* Get NVRAM data and calculate checksum. */
+	/* Get VPD data into cache */
+	ha->vpd = ha->nvram + VPD_OFFSET;
+	ha->isp_ops->read_nvram(ha, (uint8_t *)ha->vpd,
+	    ha->nvram_base - FA_NVRAM_FUNC0_ADDR, FA_NVRAM_VPD_SIZE * 4);
+
+	/* Get NVRAM data into cache and calculate checksum. */
 	dptr = (uint32_t *)nv;
-	ha->isp_ops.read_nvram(ha, (uint8_t *)dptr, ha->nvram_base,
+	ha->isp_ops->read_nvram(ha, (uint8_t *)dptr, ha->nvram_base,
 	    ha->nvram_size);
 	for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
 		chksum += le32_to_cpu(*dptr++);
 
 	DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
-	DEBUG5(qla2x00_dump_buffer((uint8_t *)ha->request_ring,
-	    ha->nvram_size));
+	DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
 
 	/* Bad NVRAM data, set defaults parameters. */
 	if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
@@ -4012,7 +4010,7 @@
 {
 	int ret, retries;
 
-	if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+	if (!IS_FWI2_CAPABLE(ha))
 		return;
 	if (!ha->fw_major_version)
 		return;
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index d3023338..8e3b044 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -104,7 +104,7 @@
 static inline void
 qla2x00_poll(scsi_qla_host_t *ha)
 {
-	ha->isp_ops.intr_handler(0, ha);
+	ha->isp_ops->intr_handler(0, ha);
 }
 
 static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *);
@@ -163,7 +163,7 @@
 static inline int
 qla2x00_is_reserved_id(scsi_qla_host_t *ha, uint16_t loop_id)
 {
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+	if (IS_FWI2_CAPABLE(ha))
 		return (loop_id > NPH_LAST_HANDLE);
 
 	return ((loop_id > ha->last_loop_id && loop_id < SNS_FIRST_LOOP_ID) ||
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index c71863f..3a5e78c 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -326,7 +326,7 @@
 	tot_dsds = nseg;
 
 	/* Calculate the number of request entries needed. */
-	req_cnt = ha->isp_ops.calc_req_entries(tot_dsds);
+	req_cnt = ha->isp_ops->calc_req_entries(tot_dsds);
 	if (ha->req_q_cnt < (req_cnt + 2)) {
 		cnt = RD_REG_WORD_RELAXED(ISP_REQ_Q_OUT(ha, reg));
 		if (ha->req_ring_index < cnt)
@@ -364,7 +364,7 @@
 	cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
 
 	/* Build IOCB segments */
-	ha->isp_ops.build_iocbs(sp, cmd_pkt, tot_dsds);
+	ha->isp_ops->build_iocbs(sp, cmd_pkt, tot_dsds);
 
 	/* Set total data segment count. */
 	cmd_pkt->entry_count = (uint8_t)req_cnt;
@@ -432,7 +432,7 @@
 	mrk->entry_type = MARKER_TYPE;
 	mrk->modifier = type;
 	if (type != MK_SYNC_ALL) {
-		if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+		if (IS_FWI2_CAPABLE(ha)) {
 			mrk24 = (struct mrk_entry_24xx *) mrk;
 			mrk24->nport_handle = cpu_to_le16(loop_id);
 			mrk24->lun[1] = LSB(lun);
@@ -487,7 +487,7 @@
 	for (timer = HZ; timer; timer--) {
 		if ((req_cnt + 2) >= ha->req_q_cnt) {
 			/* Calculate number of free request entries. */
-			if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+			if (IS_FWI2_CAPABLE(ha))
 				cnt = (uint16_t)RD_REG_DWORD(
 				    &reg->isp24.req_q_out);
 			else
@@ -561,7 +561,7 @@
 		ha->request_ring_ptr++;
 
 	/* Set chip new ring index. */
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+	if (IS_FWI2_CAPABLE(ha)) {
 		WRT_REG_DWORD(&reg->isp24.req_q_in, ha->req_ring_index);
 		RD_REG_DWORD_RELAXED(&reg->isp24.req_q_in);
 	} else {
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 0ba4c8d..eecae99 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -143,7 +143,7 @@
 			WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
 			RD_REG_WORD(&reg->hccr);
 
-			ha->isp_ops.fw_dump(ha, 1);
+			ha->isp_ops->fw_dump(ha, 1);
 			set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
 			break;
 		} else if ((stat & HSR_RISC_INT) == 0)
@@ -247,7 +247,7 @@
 qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
 {
 #define LS_UNKNOWN	2
-	static char	*link_speeds[5] = { "1", "2", "?", "4", "10" };
+	static char	*link_speeds[5] = { "1", "2", "?", "4", "8" };
 	char		*link_speed;
 	uint16_t	handle_cnt;
 	uint16_t	cnt;
@@ -334,9 +334,9 @@
 		    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n",
 		    mb[1], mb[2], mb[3]);
 
-		ha->isp_ops.fw_dump(ha, 1);
+		ha->isp_ops->fw_dump(ha, 1);
 
-		if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+		if (IS_FWI2_CAPABLE(ha)) {
 			if (mb[1] == 0 && mb[2] == 0) {
 				qla_printk(KERN_ERR, ha,
 				    "Unrecoverable Hardware Error: adapter "
@@ -490,6 +490,7 @@
 		set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
 
 		ha->flags.gpsc_supported = 1;
+		ha->flags.management_server_logged_in = 0;
 		break;
 
 	case MBA_CHG_IN_CONNECTION:	/* Change in connection mode */
@@ -601,7 +602,7 @@
 		    "scsi(%ld): [R|Z]IO update completion.\n",
 		    ha->host_no));
 
-		if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+		if (IS_FWI2_CAPABLE(ha))
 			qla24xx_process_response_queue(ha);
 		else
 			qla2x00_process_response_queue(ha);
@@ -823,7 +824,7 @@
 
 	sts = (sts_entry_t *) pkt;
 	sts24 = (struct sts_entry_24xx *) pkt;
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+	if (IS_FWI2_CAPABLE(ha)) {
 		comp_status = le16_to_cpu(sts24->comp_status);
 		scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
 	} else {
@@ -872,7 +873,7 @@
 	fcport = sp->fcport;
 
 	sense_len = rsp_info_len = resid_len = fw_resid_len = 0;
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+	if (IS_FWI2_CAPABLE(ha)) {
 		sense_len = le32_to_cpu(sts24->sense_len);
 		rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
 		resid_len = le32_to_cpu(sts24->rsp_residual_count);
@@ -891,7 +892,7 @@
 	/* Check for any FCP transport errors. */
 	if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
 		/* Sense data lies beyond any FCP RESPONSE data. */
-		if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+		if (IS_FWI2_CAPABLE(ha))
 			sense_data += rsp_info_len;
 		if (rsp_info_len > 3 && rsp_info[3]) {
 			DEBUG2(printk("scsi(%ld:%d:%d:%d) FCP I/O protocol "
@@ -990,7 +991,7 @@
 	case CS_DATA_UNDERRUN:
 		resid = resid_len;
 		/* Use F/W calculated residual length. */
-		if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+		if (IS_FWI2_CAPABLE(ha))
 			resid = fw_resid_len;
 
 		if (scsi_status & SS_RESIDUAL_UNDER) {
@@ -1062,6 +1063,25 @@
 			    cp->device->id, cp->device->lun, cp,
 			    cp->serial_number));
 
+			/*
+			 * In case of a Underrun condition, set both the lscsi
+			 * status and the completion status to appropriate
+			 * values.
+			 */
+			if (resid &&
+			    ((unsigned)(scsi_bufflen(cp) - resid) <
+			     cp->underflow)) {
+				DEBUG2(qla_printk(KERN_INFO, ha,
+				    "scsi(%ld:%d:%d:%d): Mid-layer underflow "
+				    "detected (%x of %x bytes)...returning "
+				    "error status.\n", ha->host_no,
+				    cp->device->channel, cp->device->id,
+				    cp->device->lun, resid,
+				    scsi_bufflen(cp)));
+
+				cp->result = DID_ERROR << 16 | lscsi_status;
+			}
+
 			if (sense_len)
 				DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
 				    CMD_ACTUAL_SNSLEN(cp)));
@@ -1166,7 +1186,7 @@
 	case CS_TIMEOUT:
 		cp->result = DID_BUS_BUSY << 16;
 
-		if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+		if (IS_FWI2_CAPABLE(ha)) {
 			DEBUG2(printk(KERN_INFO
 			    "scsi(%ld:%d:%d:%d): TIMEOUT status detected "
 			    "0x%x-0x%x\n", ha->host_no, cp->device->channel,
@@ -1235,7 +1255,7 @@
 		}
 
 		/* Move sense data. */
-		if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+		if (IS_FWI2_CAPABLE(ha))
 			host_to_fcp_swap(pkt->data, sizeof(pkt->data));
 		memcpy(sp->request_sense_ptr, pkt->data, sense_sz);
 		DEBUG5(qla2x00_dump_buffer(sp->request_sense_ptr, sense_sz));
@@ -1483,7 +1503,7 @@
 
 			qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
 			    "Dumping firmware!\n", hccr);
-			ha->isp_ops.fw_dump(ha, 1);
+			ha->isp_ops->fw_dump(ha, 1);
 			set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
 			break;
 		} else if ((stat & HSRX_RISC_INT) == 0)
@@ -1617,7 +1637,7 @@
 
 			qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
 			    "Dumping firmware!\n", hccr);
-			ha->isp_ops.fw_dump(ha, 1);
+			ha->isp_ops->fw_dump(ha, 1);
 			set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
 			break;
 		} else if ((stat & HSRX_RISC_INT) == 0)
@@ -1739,11 +1759,11 @@
 	int ret;
 
 	/* If possible, enable MSI-X. */
-	if (!IS_QLA2432(ha))
+	if (!IS_QLA2432(ha) && !IS_QLA2532(ha))
 		goto skip_msix;
 
-        if (ha->chip_revision < QLA_MSIX_CHIP_REV_24XX ||
-	    !QLA_MSIX_FW_MODE_1(ha->fw_attributes)) {
+        if (IS_QLA2432(ha) && (ha->chip_revision < QLA_MSIX_CHIP_REV_24XX ||
+	    !QLA_MSIX_FW_MODE_1(ha->fw_attributes))) {
 		DEBUG2(qla_printk(KERN_WARNING, ha,
 		    "MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n",
 		    ha->chip_revision, ha->fw_attributes));
@@ -1762,7 +1782,7 @@
 	    "MSI-X: Falling back-to INTa mode -- %d.\n", ret);
 skip_msix:
 
-	if (!IS_QLA24XX(ha))
+	if (!IS_QLA24XX(ha) && !IS_QLA2532(ha))
 		goto skip_msi;
 
 	ret = pci_enable_msi(ha->pdev);
@@ -1772,7 +1792,7 @@
 	}
 skip_msi:
 
-	ret = request_irq(ha->pdev->irq, ha->isp_ops.intr_handler,
+	ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
 	    IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha);
 	if (!ret) {
 		ha->flags.inta_enabled = 1;
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 2cd0cff..d3746ec 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -90,7 +90,7 @@
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 
 	/* Load mailbox registers. */
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+	if (IS_FWI2_CAPABLE(ha))
 		optr = (uint16_t __iomem *)&reg->isp24.mailbox0;
 	else
 		optr = (uint16_t __iomem *)MAILBOX_REG(ha, &reg->isp, 0);
@@ -154,7 +154,7 @@
 
 		set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
 
-		if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+		if (IS_FWI2_CAPABLE(ha))
 			WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_SET_HOST_INT);
 		else
 			WRT_REG_WORD(&reg->isp.hccr, HCCR_SET_HOST_INT);
@@ -175,7 +175,7 @@
 		DEBUG3_11(printk("%s(%ld): cmd=%x POLLING MODE.\n", __func__,
 		    ha->host_no, command));
 
-		if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+		if (IS_FWI2_CAPABLE(ha))
 			WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_SET_HOST_INT);
 		else
 			WRT_REG_WORD(&reg->isp.hccr, HCCR_SET_HOST_INT);
@@ -228,7 +228,7 @@
 		uint16_t mb0;
 		uint32_t ictrl;
 
-		if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+		if (IS_FWI2_CAPABLE(ha)) {
 			mb0 = RD_REG_WORD(&reg->isp24.mailbox0);
 			ictrl = RD_REG_DWORD(&reg->isp24.ictrl);
 		} else {
@@ -322,7 +322,7 @@
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
-	if (MSW(risc_addr) || IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+	if (MSW(risc_addr) || IS_FWI2_CAPABLE(ha)) {
 		mcp->mb[0] = MBC_LOAD_RISC_RAM_EXTENDED;
 		mcp->mb[8] = MSW(risc_addr);
 		mcp->out_mb = MBX_8|MBX_0;
@@ -336,7 +336,7 @@
 	mcp->mb[6] = MSW(MSD(req_dma));
 	mcp->mb[7] = LSW(MSD(req_dma));
 	mcp->out_mb |= MBX_7|MBX_6|MBX_3|MBX_2|MBX_1;
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+	if (IS_FWI2_CAPABLE(ha)) {
 		mcp->mb[4] = MSW(risc_code_size);
 		mcp->mb[5] = LSW(risc_code_size);
 		mcp->out_mb |= MBX_5|MBX_4;
@@ -387,7 +387,7 @@
 	mcp->mb[0] = MBC_EXECUTE_FIRMWARE;
 	mcp->out_mb = MBX_0;
 	mcp->in_mb = MBX_0;
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+	if (IS_FWI2_CAPABLE(ha)) {
 		mcp->mb[1] = MSW(risc_addr);
 		mcp->mb[2] = LSW(risc_addr);
 		mcp->mb[3] = 0;
@@ -410,7 +410,7 @@
 		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n", __func__,
 		    ha->host_no, rval, mcp->mb[0]));
 	} else {
-		if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+		if (IS_FWI2_CAPABLE(ha)) {
 			DEBUG11(printk("%s(%ld): done exchanges=%x.\n",
 			    __func__, ha->host_no, mcp->mb[1]));
 		} else {
@@ -551,7 +551,7 @@
 	mcp->mb[3] = fwopts[3];
 	mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
 	mcp->in_mb = MBX_0;
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+	if (IS_FWI2_CAPABLE(ha)) {
 		mcp->in_mb |= MBX_1;
 	} else {
 		mcp->mb[10] = fwopts[10];
@@ -664,7 +664,7 @@
 	mcp->mb[0] = MBC_VERIFY_CHECKSUM;
 	mcp->out_mb = MBX_0;
 	mcp->in_mb = MBX_0;
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+	if (IS_FWI2_CAPABLE(ha)) {
 		mcp->mb[1] = MSW(risc_addr);
 		mcp->mb[2] = LSW(risc_addr);
 		mcp->out_mb |= MBX_2|MBX_1;
@@ -681,8 +681,8 @@
 
 	if (rval != QLA_SUCCESS) {
 		DEBUG2_3_11(printk("%s(%ld): failed=%x chk sum=%x.\n", __func__,
-		    ha->host_no, rval, (IS_QLA24XX(ha) || IS_QLA54XX(ha) ?
-		    (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1])));
+		    ha->host_no, rval, IS_FWI2_CAPABLE(ha) ?
+		    (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1]));
 	} else {
 		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
 	}
@@ -739,7 +739,7 @@
 
 		/* Mask reserved bits. */
 		sts_entry->entry_status &=
-		    IS_QLA24XX(ha) || IS_QLA54XX(ha) ? RF_MASK_24XX :RF_MASK;
+		    IS_FWI2_CAPABLE(ha) ? RF_MASK_24XX :RF_MASK;
 	}
 
 	return rval;
@@ -1085,7 +1085,7 @@
 	memset(pd, 0, max(PORT_DATABASE_SIZE, PORT_DATABASE_24XX_SIZE));
 
 	mcp->mb[0] = MBC_GET_PORT_DATABASE;
-	if (opt != 0 && !IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+	if (opt != 0 && !IS_FWI2_CAPABLE(ha))
 		mcp->mb[0] = MBC_ENHANCED_GET_PORT_DATABASE;
 	mcp->mb[2] = MSW(pd_dma);
 	mcp->mb[3] = LSW(pd_dma);
@@ -1094,7 +1094,7 @@
 	mcp->mb[9] = ha->vp_idx;
 	mcp->out_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
 	mcp->in_mb = MBX_0;
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+	if (IS_FWI2_CAPABLE(ha)) {
 		mcp->mb[1] = fcport->loop_id;
 		mcp->mb[10] = opt;
 		mcp->out_mb |= MBX_10|MBX_1;
@@ -1107,15 +1107,15 @@
 		mcp->mb[1] = fcport->loop_id << 8 | opt;
 		mcp->out_mb |= MBX_1;
 	}
-	mcp->buf_size = (IS_QLA24XX(ha) || IS_QLA54XX(ha) ?
-	    PORT_DATABASE_24XX_SIZE : PORT_DATABASE_SIZE);
+	mcp->buf_size = IS_FWI2_CAPABLE(ha) ?
+	    PORT_DATABASE_24XX_SIZE : PORT_DATABASE_SIZE;
 	mcp->flags = MBX_DMA_IN;
 	mcp->tov = (ha->login_timeout * 2) + (ha->login_timeout / 2);
 	rval = qla2x00_mailbox_command(ha, mcp);
 	if (rval != QLA_SUCCESS)
 		goto gpd_error_out;
 
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+	if (IS_FWI2_CAPABLE(ha)) {
 		pd24 = (struct port_database_24xx *) pd;
 
 		/* Check for logged in state. */
@@ -1333,7 +1333,7 @@
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
 
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+	if (IS_FWI2_CAPABLE(ha)) {
 		mcp->mb[0] = MBC_LIP_FULL_LOGIN;
 		mcp->mb[1] = BIT_6;
 		mcp->mb[2] = 0;
@@ -1637,7 +1637,7 @@
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
 
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
+	if (IS_FWI2_CAPABLE(ha))
 		return qla24xx_login_fabric(ha, fcport->loop_id,
 		    fcport->d_id.b.domain, fcport->d_id.b.area,
 		    fcport->d_id.b.al_pa, mb_ret, opt);
@@ -1821,7 +1821,7 @@
 	    ha->host_no));
 
 	mcp->mb[0] = MBC_LIP_FULL_LOGIN;
-	mcp->mb[1] = IS_QLA24XX(ha) || IS_QLA54XX(ha) ? BIT_3: 0;
+	mcp->mb[1] = IS_FWI2_CAPABLE(ha) ? BIT_3: 0;
 	mcp->mb[2] = 0;
 	mcp->mb[3] = 0;
 	mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
@@ -1871,7 +1871,7 @@
 
 	mcp->mb[0] = MBC_GET_ID_LIST;
 	mcp->out_mb = MBX_0;
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+	if (IS_FWI2_CAPABLE(ha)) {
 		mcp->mb[2] = MSW(id_list_dma);
 		mcp->mb[3] = LSW(id_list_dma);
 		mcp->mb[6] = MSW(MSD(id_list_dma));
@@ -2063,7 +2063,7 @@
 	mcp->mb[7] = LSW(MSD(stat_buf_dma));
 	mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
 	mcp->in_mb = MBX_0;
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+	if (IS_FWI2_CAPABLE(ha)) {
 		mcp->mb[1] = loop_id;
 		mcp->mb[4] = 0;
 		mcp->mb[10] = 0;
@@ -2334,7 +2334,7 @@
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
 
-	if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+	if (!IS_FWI2_CAPABLE(ha))
 		return QLA_FUNCTION_FAILED;
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
@@ -2444,7 +2444,7 @@
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
 
-	if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+	if (!IS_FWI2_CAPABLE(ha))
 		return QLA_FUNCTION_FAILED;
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
@@ -2474,7 +2474,7 @@
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
 
-	if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+	if (!IS_FWI2_CAPABLE(ha))
 		return QLA_FUNCTION_FAILED;
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
@@ -2514,7 +2514,7 @@
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
 
-	if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+	if (!IS_FWI2_CAPABLE(ha))
 		return QLA_FUNCTION_FAILED;
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
@@ -2552,7 +2552,7 @@
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
 
-	if (!IS_QLA24XX(ha))
+	if (!IS_IIDMA_CAPABLE(ha))
 		return QLA_FUNCTION_FAILED;
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
@@ -2595,7 +2595,7 @@
 	mbx_cmd_t mc;
 	mbx_cmd_t *mcp = &mc;
 
-	if (!IS_QLA24XX(ha))
+	if (!IS_IIDMA_CAPABLE(ha))
 		return QLA_FUNCTION_FAILED;
 
 	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index b5a77b0..acca898 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -265,6 +265,8 @@
 		strcpy(str, "PCIe (");
 		if (lspeed == 1)
 			strcat(str, "2.5Gb/s ");
+		else if (lspeed == 2)
+			strcat(str, "5.0Gb/s ");
 		else
 			strcat(str, "<unknown> ");
 		snprintf(lwstr, sizeof(lwstr), "x%d)", lwidth);
@@ -343,6 +345,12 @@
 		strcat(str, "[IP] ");
 	if (ha->fw_attributes & BIT_2)
 		strcat(str, "[Multi-ID] ");
+	if (ha->fw_attributes & BIT_3)
+		strcat(str, "[SB-2] ");
+	if (ha->fw_attributes & BIT_4)
+		strcat(str, "[T10 CRC] ");
+	if (ha->fw_attributes & BIT_5)
+		strcat(str, "[VI] ");
 	if (ha->fw_attributes & BIT_13)
 		strcat(str, "[Experimental]");
 	return str;
@@ -681,7 +689,7 @@
 		DEBUG3(qla2x00_print_scsi_cmd(cmd));
 
 		spin_unlock_irqrestore(&pha->hardware_lock, flags);
-		if (ha->isp_ops.abort_command(ha, sp)) {
+		if (ha->isp_ops->abort_command(ha, sp)) {
 			DEBUG2(printk("%s(%ld): abort_command "
 			    "mbx failed.\n", __func__, ha->host_no));
 		} else {
@@ -813,7 +821,7 @@
 #if defined(LOGOUT_AFTER_DEVICE_RESET)
 		if (ret == SUCCESS) {
 			if (fcport->flags & FC_FABRIC_DEVICE) {
-				ha->isp_ops.fabric_logout(ha, fcport->loop_id);
+				ha->isp_ops->fabric_logout(ha, fcport->loop_id);
 				qla2x00_mark_device_lost(ha, fcport, 0, 0);
 			}
 		}
@@ -1105,7 +1113,7 @@
 qla2x00_device_reset(scsi_qla_host_t *ha, fc_port_t *reset_fcport)
 {
 	/* Abort Target command will clear Reservation */
-	return ha->isp_ops.abort_target(reset_fcport);
+	return ha->isp_ops->abort_target(reset_fcport);
 }
 
 static int
@@ -1184,8 +1192,8 @@
 		    !pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) {
 			/* Ok, a 64bit DMA mask is applicable. */
 			ha->flags.enable_64bit_addressing = 1;
-			ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_64;
-			ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_64;
+			ha->isp_ops->calc_req_entries = qla2x00_calc_iocbs_64;
+			ha->isp_ops->build_iocbs = qla2x00_build_scsi_iocbs_64;
 			return;
 		}
 	}
@@ -1194,6 +1202,193 @@
 	pci_set_consistent_dma_mask(ha->pdev, DMA_32BIT_MASK);
 }
 
+static void
+qla2x00_enable_intrs(scsi_qla_host_t *ha)
+{
+	unsigned long flags = 0;
+	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	ha->interrupts_on = 1;
+	/* enable risc and host interrupts */
+	WRT_REG_WORD(&reg->ictrl, ICR_EN_INT | ICR_EN_RISC);
+	RD_REG_WORD(&reg->ictrl);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+}
+
+static void
+qla2x00_disable_intrs(scsi_qla_host_t *ha)
+{
+	unsigned long flags = 0;
+	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	ha->interrupts_on = 0;
+	/* disable risc and host interrupts */
+	WRT_REG_WORD(&reg->ictrl, 0);
+	RD_REG_WORD(&reg->ictrl);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+static void
+qla24xx_enable_intrs(scsi_qla_host_t *ha)
+{
+	unsigned long flags = 0;
+	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	ha->interrupts_on = 1;
+	WRT_REG_DWORD(&reg->ictrl, ICRX_EN_RISC_INT);
+	RD_REG_DWORD(&reg->ictrl);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+static void
+qla24xx_disable_intrs(scsi_qla_host_t *ha)
+{
+	unsigned long flags = 0;
+	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	ha->interrupts_on = 0;
+	WRT_REG_DWORD(&reg->ictrl, 0);
+	RD_REG_DWORD(&reg->ictrl);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+static struct isp_operations qla2100_isp_ops = {
+	.pci_config		= qla2100_pci_config,
+	.reset_chip		= qla2x00_reset_chip,
+	.chip_diag		= qla2x00_chip_diag,
+	.config_rings		= qla2x00_config_rings,
+	.reset_adapter		= qla2x00_reset_adapter,
+	.nvram_config		= qla2x00_nvram_config,
+	.update_fw_options	= qla2x00_update_fw_options,
+	.load_risc		= qla2x00_load_risc,
+	.pci_info_str		= qla2x00_pci_info_str,
+	.fw_version_str		= qla2x00_fw_version_str,
+	.intr_handler		= qla2100_intr_handler,
+	.enable_intrs		= qla2x00_enable_intrs,
+	.disable_intrs		= qla2x00_disable_intrs,
+	.abort_command		= qla2x00_abort_command,
+	.abort_target		= qla2x00_abort_target,
+	.fabric_login		= qla2x00_login_fabric,
+	.fabric_logout		= qla2x00_fabric_logout,
+	.calc_req_entries	= qla2x00_calc_iocbs_32,
+	.build_iocbs		= qla2x00_build_scsi_iocbs_32,
+	.prep_ms_iocb		= qla2x00_prep_ms_iocb,
+	.prep_ms_fdmi_iocb	= qla2x00_prep_ms_fdmi_iocb,
+	.read_nvram		= qla2x00_read_nvram_data,
+	.write_nvram		= qla2x00_write_nvram_data,
+	.fw_dump		= qla2100_fw_dump,
+	.beacon_on		= NULL,
+	.beacon_off		= NULL,
+	.beacon_blink		= NULL,
+	.read_optrom		= qla2x00_read_optrom_data,
+	.write_optrom		= qla2x00_write_optrom_data,
+	.get_flash_version	= qla2x00_get_flash_version,
+};
+
+static struct isp_operations qla2300_isp_ops = {
+	.pci_config		= qla2300_pci_config,
+	.reset_chip		= qla2x00_reset_chip,
+	.chip_diag		= qla2x00_chip_diag,
+	.config_rings		= qla2x00_config_rings,
+	.reset_adapter		= qla2x00_reset_adapter,
+	.nvram_config		= qla2x00_nvram_config,
+	.update_fw_options	= qla2x00_update_fw_options,
+	.load_risc		= qla2x00_load_risc,
+	.pci_info_str		= qla2x00_pci_info_str,
+	.fw_version_str		= qla2x00_fw_version_str,
+	.intr_handler		= qla2300_intr_handler,
+	.enable_intrs		= qla2x00_enable_intrs,
+	.disable_intrs		= qla2x00_disable_intrs,
+	.abort_command		= qla2x00_abort_command,
+	.abort_target		= qla2x00_abort_target,
+	.fabric_login		= qla2x00_login_fabric,
+	.fabric_logout		= qla2x00_fabric_logout,
+	.calc_req_entries	= qla2x00_calc_iocbs_32,
+	.build_iocbs		= qla2x00_build_scsi_iocbs_32,
+	.prep_ms_iocb		= qla2x00_prep_ms_iocb,
+	.prep_ms_fdmi_iocb	= qla2x00_prep_ms_fdmi_iocb,
+	.read_nvram		= qla2x00_read_nvram_data,
+	.write_nvram		= qla2x00_write_nvram_data,
+	.fw_dump		= qla2300_fw_dump,
+	.beacon_on		= qla2x00_beacon_on,
+	.beacon_off		= qla2x00_beacon_off,
+	.beacon_blink		= qla2x00_beacon_blink,
+	.read_optrom		= qla2x00_read_optrom_data,
+	.write_optrom		= qla2x00_write_optrom_data,
+	.get_flash_version	= qla2x00_get_flash_version,
+};
+
+static struct isp_operations qla24xx_isp_ops = {
+	.pci_config		= qla24xx_pci_config,
+	.reset_chip		= qla24xx_reset_chip,
+	.chip_diag		= qla24xx_chip_diag,
+	.config_rings		= qla24xx_config_rings,
+	.reset_adapter		= qla24xx_reset_adapter,
+	.nvram_config		= qla24xx_nvram_config,
+	.update_fw_options	= qla24xx_update_fw_options,
+	.load_risc		= qla24xx_load_risc,
+	.pci_info_str		= qla24xx_pci_info_str,
+	.fw_version_str		= qla24xx_fw_version_str,
+	.intr_handler		= qla24xx_intr_handler,
+	.enable_intrs		= qla24xx_enable_intrs,
+	.disable_intrs		= qla24xx_disable_intrs,
+	.abort_command		= qla24xx_abort_command,
+	.abort_target		= qla24xx_abort_target,
+	.fabric_login		= qla24xx_login_fabric,
+	.fabric_logout		= qla24xx_fabric_logout,
+	.calc_req_entries	= NULL,
+	.build_iocbs		= NULL,
+	.prep_ms_iocb		= qla24xx_prep_ms_iocb,
+	.prep_ms_fdmi_iocb	= qla24xx_prep_ms_fdmi_iocb,
+	.read_nvram		= qla24xx_read_nvram_data,
+	.write_nvram		= qla24xx_write_nvram_data,
+	.fw_dump		= qla24xx_fw_dump,
+	.beacon_on		= qla24xx_beacon_on,
+	.beacon_off		= qla24xx_beacon_off,
+	.beacon_blink		= qla24xx_beacon_blink,
+	.read_optrom		= qla24xx_read_optrom_data,
+	.write_optrom		= qla24xx_write_optrom_data,
+	.get_flash_version	= qla24xx_get_flash_version,
+};
+
+static struct isp_operations qla25xx_isp_ops = {
+	.pci_config		= qla25xx_pci_config,
+	.reset_chip		= qla24xx_reset_chip,
+	.chip_diag		= qla24xx_chip_diag,
+	.config_rings		= qla24xx_config_rings,
+	.reset_adapter		= qla24xx_reset_adapter,
+	.nvram_config		= qla24xx_nvram_config,
+	.update_fw_options	= qla24xx_update_fw_options,
+	.load_risc		= qla24xx_load_risc,
+	.pci_info_str		= qla24xx_pci_info_str,
+	.fw_version_str		= qla24xx_fw_version_str,
+	.intr_handler		= qla24xx_intr_handler,
+	.enable_intrs		= qla24xx_enable_intrs,
+	.disable_intrs		= qla24xx_disable_intrs,
+	.abort_command		= qla24xx_abort_command,
+	.abort_target		= qla24xx_abort_target,
+	.fabric_login		= qla24xx_login_fabric,
+	.fabric_logout		= qla24xx_fabric_logout,
+	.calc_req_entries	= NULL,
+	.build_iocbs		= NULL,
+	.prep_ms_iocb		= qla24xx_prep_ms_iocb,
+	.prep_ms_fdmi_iocb	= qla24xx_prep_ms_fdmi_iocb,
+	.read_nvram		= qla25xx_read_nvram_data,
+	.write_nvram		= qla25xx_write_nvram_data,
+	.fw_dump		= qla25xx_fw_dump,
+	.beacon_on		= qla24xx_beacon_on,
+	.beacon_off		= qla24xx_beacon_off,
+	.beacon_blink		= qla24xx_beacon_blink,
+	.read_optrom		= qla24xx_read_optrom_data,
+	.write_optrom		= qla24xx_write_optrom_data,
+	.get_flash_version	= qla24xx_get_flash_version,
+};
+
 static inline void
 qla2x00_set_isp_flags(scsi_qla_host_t *ha)
 {
@@ -1238,19 +1433,32 @@
 	case PCI_DEVICE_ID_QLOGIC_ISP2422:
 		ha->device_type |= DT_ISP2422;
 		ha->device_type |= DT_ZIO_SUPPORTED;
+		ha->device_type |= DT_FWI2;
+		ha->device_type |= DT_IIDMA;
 		ha->fw_srisc_address = RISC_START_ADDRESS_2400;
 		break;
 	case PCI_DEVICE_ID_QLOGIC_ISP2432:
 		ha->device_type |= DT_ISP2432;
 		ha->device_type |= DT_ZIO_SUPPORTED;
+		ha->device_type |= DT_FWI2;
+		ha->device_type |= DT_IIDMA;
 		ha->fw_srisc_address = RISC_START_ADDRESS_2400;
 		break;
 	case PCI_DEVICE_ID_QLOGIC_ISP5422:
 		ha->device_type |= DT_ISP5422;
+		ha->device_type |= DT_FWI2;
 		ha->fw_srisc_address = RISC_START_ADDRESS_2400;
 		break;
 	case PCI_DEVICE_ID_QLOGIC_ISP5432:
 		ha->device_type |= DT_ISP5432;
+		ha->device_type |= DT_FWI2;
+		ha->fw_srisc_address = RISC_START_ADDRESS_2400;
+		break;
+	case PCI_DEVICE_ID_QLOGIC_ISP2532:
+		ha->device_type |= DT_ISP2532;
+		ha->device_type |= DT_ZIO_SUPPORTED;
+		ha->device_type |= DT_FWI2;
+		ha->device_type |= DT_IIDMA;
 		ha->fw_srisc_address = RISC_START_ADDRESS_2400;
 		break;
 	}
@@ -1323,61 +1531,6 @@
 }
 
 static void
-qla2x00_enable_intrs(scsi_qla_host_t *ha)
-{
-	unsigned long flags = 0;
-	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
-
-	spin_lock_irqsave(&ha->hardware_lock, flags);
-	ha->interrupts_on = 1;
-	/* enable risc and host interrupts */
-	WRT_REG_WORD(&reg->ictrl, ICR_EN_INT | ICR_EN_RISC);
-	RD_REG_WORD(&reg->ictrl);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
-
-}
-
-static void
-qla2x00_disable_intrs(scsi_qla_host_t *ha)
-{
-	unsigned long flags = 0;
-	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
-
-	spin_lock_irqsave(&ha->hardware_lock, flags);
-	ha->interrupts_on = 0;
-	/* disable risc and host interrupts */
-	WRT_REG_WORD(&reg->ictrl, 0);
-	RD_REG_WORD(&reg->ictrl);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
-
-static void
-qla24xx_enable_intrs(scsi_qla_host_t *ha)
-{
-	unsigned long flags = 0;
-	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
-
-	spin_lock_irqsave(&ha->hardware_lock, flags);
-	ha->interrupts_on = 1;
-	WRT_REG_DWORD(&reg->ictrl, ICRX_EN_RISC_INT);
-	RD_REG_DWORD(&reg->ictrl);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
-
-static void
-qla24xx_disable_intrs(scsi_qla_host_t *ha)
-{
-	unsigned long flags = 0;
-	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
-
-	spin_lock_irqsave(&ha->hardware_lock, flags);
-	ha->interrupts_on = 0;
-	WRT_REG_DWORD(&reg->ictrl, 0);
-	RD_REG_DWORD(&reg->ictrl);
-	spin_unlock_irqrestore(&ha->hardware_lock, flags);
-}
-
-static void
 qla2xxx_scan_start(struct Scsi_Host *shost)
 {
 	scsi_qla_host_t *ha = (scsi_qla_host_t *)shost->hostdata;
@@ -1411,7 +1564,7 @@
 	struct Scsi_Host *host;
 	scsi_qla_host_t *ha;
 	unsigned long	flags = 0;
-	char pci_info[20];
+	char pci_info[30];
 	char fw_str[30];
 	struct scsi_host_template *sht;
 
@@ -1422,7 +1575,8 @@
 	if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 ||
 	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 ||
 	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 ||
-	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432)
+	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 ||
+	    pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532)
 		sht = &qla24xx_driver_template;
 	host = scsi_host_alloc(sht, sizeof(scsi_qla_host_t));
 	if (host == NULL) {
@@ -1466,33 +1620,6 @@
 		ha->max_q_depth = ql2xmaxqdepth;
 
 	/* Assign ISP specific operations. */
-	ha->isp_ops.pci_config		= qla2100_pci_config;
-	ha->isp_ops.reset_chip		= qla2x00_reset_chip;
-	ha->isp_ops.chip_diag		= qla2x00_chip_diag;
-	ha->isp_ops.config_rings	= qla2x00_config_rings;
-	ha->isp_ops.reset_adapter	= qla2x00_reset_adapter;
-	ha->isp_ops.nvram_config	= qla2x00_nvram_config;
-	ha->isp_ops.update_fw_options	= qla2x00_update_fw_options;
-	ha->isp_ops.load_risc		= qla2x00_load_risc;
-	ha->isp_ops.pci_info_str	= qla2x00_pci_info_str;
-	ha->isp_ops.fw_version_str	= qla2x00_fw_version_str;
-	ha->isp_ops.intr_handler	= qla2100_intr_handler;
-	ha->isp_ops.enable_intrs	= qla2x00_enable_intrs;
-	ha->isp_ops.disable_intrs	= qla2x00_disable_intrs;
-	ha->isp_ops.abort_command	= qla2x00_abort_command;
-	ha->isp_ops.abort_target	= qla2x00_abort_target;
-	ha->isp_ops.fabric_login	= qla2x00_login_fabric;
-	ha->isp_ops.fabric_logout	= qla2x00_fabric_logout;
-	ha->isp_ops.calc_req_entries	= qla2x00_calc_iocbs_32;
-	ha->isp_ops.build_iocbs		= qla2x00_build_scsi_iocbs_32;
-	ha->isp_ops.prep_ms_iocb	= qla2x00_prep_ms_iocb;
-	ha->isp_ops.prep_ms_fdmi_iocb	= qla2x00_prep_ms_fdmi_iocb;
-	ha->isp_ops.read_nvram		= qla2x00_read_nvram_data;
-	ha->isp_ops.write_nvram		= qla2x00_write_nvram_data;
-	ha->isp_ops.fw_dump		= qla2100_fw_dump;
-	ha->isp_ops.read_optrom		= qla2x00_read_optrom_data;
-	ha->isp_ops.write_optrom	= qla2x00_write_optrom_data;
-	ha->isp_ops.get_flash_version	= qla2x00_get_flash_version;
 	if (IS_QLA2100(ha)) {
 		host->max_id = MAX_TARGETS_2100;
 		ha->mbx_count = MAILBOX_REGISTER_COUNT_2100;
@@ -1501,6 +1628,7 @@
 		ha->last_loop_id = SNS_LAST_LOOP_ID_2100;
 		host->sg_tablesize = 32;
 		ha->gid_list_info_size = 4;
+		ha->isp_ops = &qla2100_isp_ops;
 	} else if (IS_QLA2200(ha)) {
 		host->max_id = MAX_TARGETS_2200;
 		ha->mbx_count = MAILBOX_REGISTER_COUNT;
@@ -1508,21 +1636,17 @@
 		ha->response_q_length = RESPONSE_ENTRY_CNT_2100;
 		ha->last_loop_id = SNS_LAST_LOOP_ID_2100;
 		ha->gid_list_info_size = 4;
+		ha->isp_ops = &qla2100_isp_ops;
 	} else if (IS_QLA23XX(ha)) {
 		host->max_id = MAX_TARGETS_2200;
 		ha->mbx_count = MAILBOX_REGISTER_COUNT;
 		ha->request_q_length = REQUEST_ENTRY_CNT_2200;
 		ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
 		ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
-		ha->isp_ops.pci_config = qla2300_pci_config;
-		ha->isp_ops.intr_handler = qla2300_intr_handler;
-		ha->isp_ops.fw_dump = qla2300_fw_dump;
-		ha->isp_ops.beacon_on = qla2x00_beacon_on;
-		ha->isp_ops.beacon_off = qla2x00_beacon_off;
-		ha->isp_ops.beacon_blink = qla2x00_beacon_blink;
 		ha->gid_list_info_size = 6;
 		if (IS_QLA2322(ha) || IS_QLA6322(ha))
 			ha->optrom_size = OPTROM_SIZE_2322;
+		ha->isp_ops = &qla2300_isp_ops;
 	} else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
 		host->max_id = MAX_TARGETS_2200;
 		ha->mbx_count = MAILBOX_REGISTER_COUNT;
@@ -1531,36 +1655,20 @@
 		ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
 		ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
 		ha->mgmt_svr_loop_id = 10 + ha->vp_idx;
-		ha->isp_ops.pci_config = qla24xx_pci_config;
-		ha->isp_ops.reset_chip = qla24xx_reset_chip;
-		ha->isp_ops.chip_diag = qla24xx_chip_diag;
-		ha->isp_ops.config_rings = qla24xx_config_rings;
-		ha->isp_ops.reset_adapter = qla24xx_reset_adapter;
-		ha->isp_ops.nvram_config = qla24xx_nvram_config;
-		ha->isp_ops.update_fw_options = qla24xx_update_fw_options;
-		ha->isp_ops.load_risc = qla24xx_load_risc;
-		ha->isp_ops.pci_info_str = qla24xx_pci_info_str;
-		ha->isp_ops.fw_version_str = qla24xx_fw_version_str;
-		ha->isp_ops.intr_handler = qla24xx_intr_handler;
-		ha->isp_ops.enable_intrs = qla24xx_enable_intrs;
-		ha->isp_ops.disable_intrs = qla24xx_disable_intrs;
-		ha->isp_ops.abort_command = qla24xx_abort_command;
-		ha->isp_ops.abort_target = qla24xx_abort_target;
-		ha->isp_ops.fabric_login = qla24xx_login_fabric;
-		ha->isp_ops.fabric_logout = qla24xx_fabric_logout;
-		ha->isp_ops.prep_ms_iocb = qla24xx_prep_ms_iocb;
-		ha->isp_ops.prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb;
-		ha->isp_ops.read_nvram = qla24xx_read_nvram_data;
-		ha->isp_ops.write_nvram = qla24xx_write_nvram_data;
-		ha->isp_ops.fw_dump = qla24xx_fw_dump;
-		ha->isp_ops.read_optrom	= qla24xx_read_optrom_data;
-		ha->isp_ops.write_optrom = qla24xx_write_optrom_data;
-		ha->isp_ops.beacon_on = qla24xx_beacon_on;
-		ha->isp_ops.beacon_off = qla24xx_beacon_off;
-		ha->isp_ops.beacon_blink = qla24xx_beacon_blink;
-		ha->isp_ops.get_flash_version = qla24xx_get_flash_version;
 		ha->gid_list_info_size = 8;
 		ha->optrom_size = OPTROM_SIZE_24XX;
+		ha->isp_ops = &qla24xx_isp_ops;
+	} else if (IS_QLA25XX(ha)) {
+		host->max_id = MAX_TARGETS_2200;
+		ha->mbx_count = MAILBOX_REGISTER_COUNT;
+		ha->request_q_length = REQUEST_ENTRY_CNT_24XX;
+		ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
+		ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
+		ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
+		ha->mgmt_svr_loop_id = 10 + ha->vp_idx;
+		ha->gid_list_info_size = 8;
+		ha->optrom_size = OPTROM_SIZE_25XX;
+		ha->isp_ops = &qla25xx_isp_ops;
 	}
 	host->can_queue = ha->request_q_length + 128;
 
@@ -1628,11 +1736,11 @@
 	DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",
 	    ha->host_no, ha));
 
-	ha->isp_ops.disable_intrs(ha);
+	ha->isp_ops->disable_intrs(ha);
 
 	spin_lock_irqsave(&ha->hardware_lock, flags);
 	reg = ha->iobase;
-	if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+	if (IS_FWI2_CAPABLE(ha)) {
 		WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_HOST_INT);
 		WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_RISC_INT);
 	} else {
@@ -1654,7 +1762,7 @@
 	}
 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-	ha->isp_ops.enable_intrs(ha);
+	ha->isp_ops->enable_intrs(ha);
 
 	pci_set_drvdata(pdev, ha);
 
@@ -1679,9 +1787,9 @@
 	    "  ISP%04X: %s @ %s hdma%c, host#=%ld, fw=%s\n",
 	    qla2x00_version_str, ha->model_number,
 	    ha->model_desc ? ha->model_desc: "", pdev->device,
-	    ha->isp_ops.pci_info_str(ha, pci_info), pci_name(pdev),
+	    ha->isp_ops->pci_info_str(ha, pci_info), pci_name(pdev),
 	    ha->flags.enable_64bit_addressing ? '+': '-', ha->host_no,
-	    ha->isp_ops.fw_version_str(ha, fw_str));
+	    ha->isp_ops->fw_version_str(ha, fw_str));
 
 	return 0;
 
@@ -1747,7 +1855,7 @@
 
 	/* turn-off interrupts on the card */
 	if (ha->interrupts_on)
-		ha->isp_ops.disable_intrs(ha);
+		ha->isp_ops->disable_intrs(ha);
 
 	qla2x00_mem_free(ha);
 
@@ -2025,7 +2133,7 @@
 			}
 			memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt));
 
-			if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+			if (IS_FWI2_CAPABLE(ha)) {
 				/*
 				 * Get consistent memory allocated for SFP
 				 * block.
@@ -2046,6 +2154,19 @@
 			}
 		}
 
+		/* Get memory for cached NVRAM */
+		ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL);
+		if (ha->nvram == NULL) {
+			/* error */
+			qla_printk(KERN_WARNING, ha,
+			    "Memory Allocation failed - nvram cache\n");
+
+			qla2x00_mem_free(ha);
+			msleep(100);
+
+			continue;
+		}
+
 		/* Done all allocations without any error. */
 		status = 0;
 
@@ -2158,6 +2279,7 @@
 	ha->fw_dump_reading = 0;
 
 	vfree(ha->optrom_buffer);
+	kfree(ha->nvram);
 }
 
 /*
@@ -2305,7 +2427,7 @@
 					if (fcport->flags & FCF_FABRIC_DEVICE) {
 						if (fcport->flags &
 						    FCF_TAPE_PRESENT)
-							ha->isp_ops.fabric_logout(
+							ha->isp_ops->fabric_logout(
 							    ha, fcport->loop_id,
 							    fcport->d_id.b.domain,
 							    fcport->d_id.b.area,
@@ -2385,10 +2507,10 @@
 		}
 
 		if (!ha->interrupts_on)
-			ha->isp_ops.enable_intrs(ha);
+			ha->isp_ops->enable_intrs(ha);
 
 		if (test_and_clear_bit(BEACON_BLINK_NEEDED, &ha->dpc_flags))
-			ha->isp_ops.beacon_blink(ha);
+			ha->isp_ops->beacon_blink(ha);
 
 		qla2x00_do_dpc_all_vps(ha);
 
@@ -2617,18 +2739,20 @@
 
 /* Firmware interface routines. */
 
-#define FW_BLOBS	5
+#define FW_BLOBS	6
 #define FW_ISP21XX	0
 #define FW_ISP22XX	1
 #define FW_ISP2300	2
 #define FW_ISP2322	3
 #define FW_ISP24XX	4
+#define FW_ISP25XX	5
 
 #define FW_FILE_ISP21XX	"ql2100_fw.bin"
 #define FW_FILE_ISP22XX	"ql2200_fw.bin"
 #define FW_FILE_ISP2300	"ql2300_fw.bin"
 #define FW_FILE_ISP2322	"ql2322_fw.bin"
 #define FW_FILE_ISP24XX	"ql2400_fw.bin"
+#define FW_FILE_ISP25XX	"ql2500_fw.bin"
 
 static DECLARE_MUTEX(qla_fw_lock);
 
@@ -2638,6 +2762,7 @@
 	{ .name = FW_FILE_ISP2300, .segs = { 0x800, 0 }, },
 	{ .name = FW_FILE_ISP2322, .segs = { 0x800, 0x1c000, 0x1e000, 0 }, },
 	{ .name = FW_FILE_ISP24XX, },
+	{ .name = FW_FILE_ISP25XX, },
 };
 
 struct fw_blob *
@@ -2656,6 +2781,8 @@
 		blob = &qla_fw_blobs[FW_ISP2322];
 	} else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
 		blob = &qla_fw_blobs[FW_ISP24XX];
+	} else if (IS_QLA25XX(ha)) {
+		blob = &qla_fw_blobs[FW_ISP25XX];
 	}
 
 	down(&qla_fw_lock);
@@ -2699,6 +2826,7 @@
 	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2432) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5422) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) },
 	{ 0 },
 };
 MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
@@ -2723,7 +2851,7 @@
 
 	/* Allocate cache for SRBs. */
 	srb_cachep = kmem_cache_create("qla2xxx_srbs", sizeof(srb_t), 0,
-	    SLAB_HWCACHE_ALIGN, NULL, NULL);
+	    SLAB_HWCACHE_ALIGN, NULL);
 	if (srb_cachep == NULL) {
 		printk(KERN_ERR
 		    "qla2xxx: Unable to allocate SRB cache...Failing load!\n");
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
index 206bda0..a925a3f 100644
--- a/drivers/scsi/qla2xxx/qla_sup.c
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -766,6 +766,29 @@
 	return ret;
 }
 
+uint8_t *
+qla25xx_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
+    uint32_t bytes)
+{
+	uint32_t i;
+	uint32_t *dwptr;
+
+	/* Dword reads to flash. */
+	dwptr = (uint32_t *)buf;
+	for (i = 0; i < bytes >> 2; i++, naddr++)
+		dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha,
+		    flash_data_to_access_addr(FA_VPD_NVRAM_ADDR | naddr)));
+
+	return buf;
+}
+
+int
+qla25xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr,
+    uint32_t bytes)
+{
+	return qla24xx_write_flash_data(ha, (uint32_t *)buf,
+	    FA_VPD_NVRAM_ADDR | naddr, bytes >> 2);
+}
 
 static inline void
 qla2x00_flip_colors(scsi_qla_host_t *ha, uint16_t *pflags)
@@ -919,7 +942,7 @@
 	else
 		ha->beacon_color_state = QLA_LED_GRN_ON;
 
-	ha->isp_ops.beacon_blink(ha);	/* This turns green LED off */
+	ha->isp_ops->beacon_blink(ha);	/* This turns green LED off */
 
 	ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;
 	ha->fw_options[1] &= ~FO1_DISABLE_GPIO6_7;
@@ -1031,7 +1054,7 @@
 	ha->beacon_blink_led = 0;
 	ha->beacon_color_state = QLA_LED_ALL_ON;
 
-	ha->isp_ops.beacon_blink(ha);	/* Will flip to all off. */
+	ha->isp_ops->beacon_blink(ha);	/* Will flip to all off. */
 
 	/* Give control back to firmware. */
 	spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -1419,7 +1442,7 @@
 
 	/* Suspend HBA. */
 	scsi_block_requests(ha->host);
-	ha->isp_ops.disable_intrs(ha);
+	ha->isp_ops->disable_intrs(ha);
 	set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
 
 	/* Pause RISC. */
@@ -1705,7 +1728,7 @@
 {
 	/* Suspend HBA. */
 	scsi_block_requests(ha->host);
-	ha->isp_ops.disable_intrs(ha);
+	ha->isp_ops->disable_intrs(ha);
 	set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
 
 	/* Go with read. */
@@ -1713,7 +1736,7 @@
 
 	/* Resume HBA. */
 	clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
-	ha->isp_ops.enable_intrs(ha);
+	ha->isp_ops->enable_intrs(ha);
 	scsi_unblock_requests(ha->host);
 
 	return buf;
@@ -1727,7 +1750,7 @@
 
 	/* Suspend HBA. */
 	scsi_block_requests(ha->host);
-	ha->isp_ops.disable_intrs(ha);
+	ha->isp_ops->disable_intrs(ha);
 	set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
 
 	/* Go with write. */
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index fd2f10a..18095b9 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.02.00-k1"
+#define QLA2XXX_VERSION      "8.02.00-k3"
 
 #define QLA_DRIVER_MAJOR_VER	8
 #define QLA_DRIVER_MINOR_VER	2
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index e69160a..b1d565c 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -1677,7 +1677,7 @@
 
 	/* Allocate cache for SRBs. */
 	srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0,
-				       SLAB_HWCACHE_ALIGN, NULL, NULL);
+				       SLAB_HWCACHE_ALIGN, NULL);
 	if (srb_cachep == NULL) {
 		printk(KERN_ERR
 		       "%s: Unable to allocate SRB cache..."
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index c4195ea..5948872 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -193,7 +193,8 @@
 		cpu_relax();
 	}
 	if (!loop_count)
-		printk(KERN_EMERG "qlogicpti: mbox_command loop timeout #1\n");
+		printk(KERN_EMERG "qlogicpti%d: mbox_command loop timeout #1\n",
+		       qpti->qpti_id);
 
 	/* Write mailbox command registers. */
 	switch (mbox_param[param[0]] >> 4) {
@@ -224,8 +225,8 @@
 	       (sbus_readw(qpti->qregs + HCCTRL) & HCCTRL_CRIRQ))
 		udelay(20);
 	if (!loop_count)
-		printk(KERN_EMERG "qlogicpti: mbox_command[%04x] loop timeout #2\n",
-		       param[0]);
+		printk(KERN_EMERG "qlogicpti%d: mbox_command[%04x] loop timeout #2\n",
+		       qpti->qpti_id, param[0]);
 
 	/* Wait for SBUS semaphore to get set. */
 	loop_count = DEFAULT_LOOP_COUNT;
@@ -238,16 +239,16 @@
 			break;
 	}
 	if (!loop_count)
-		printk(KERN_EMERG "qlogicpti: mbox_command[%04x] loop timeout #3\n",
-		       param[0]);
+		printk(KERN_EMERG "qlogicpti%d: mbox_command[%04x] loop timeout #3\n",
+		       qpti->qpti_id, param[0]);
 
 	/* Wait for MBOX busy condition to go away. */
 	loop_count = DEFAULT_LOOP_COUNT;
 	while (--loop_count && (sbus_readw(qpti->qregs + MBOX0) == 0x04))
 		udelay(20);
 	if (!loop_count)
-		printk(KERN_EMERG "qlogicpti: mbox_command[%04x] loop timeout #4\n",
-		       param[0]);
+		printk(KERN_EMERG "qlogicpti%d: mbox_command[%04x] loop timeout #4\n",
+		       qpti->qpti_id, param[0]);
 
 	/* Read back output parameters. */
 	switch (mbox_param[param[0]] & 0xf) {
@@ -342,7 +343,8 @@
 	while (--loop_count && ((sbus_readw(qpti->qregs + MBOX0) & 0xff) == 0x04))
 		udelay(20);
 	if (!loop_count)
-		printk(KERN_EMERG "qlogicpti: reset_hardware loop timeout\n");
+		printk(KERN_EMERG "qlogicpti%d: reset_hardware loop timeout\n",
+		       qpti->qpti_id);
 
 	sbus_writew(HCCTRL_PAUSE, qpti->qregs + HCCTRL);
 	set_sbus_cfg1(qpti);
@@ -721,12 +723,12 @@
 			IRQF_SHARED, "Qlogic/PTI", qpti))
 		goto fail;
 
-	printk("qpti%d: IRQ %d ", qpti->qpti_id, qpti->irq);
+	printk("qlogicpti%d: IRQ %d ", qpti->qpti_id, qpti->irq);
 
 	return 0;
 
 fail:
-	printk("qpti%d: Cannot acquire irq line\n", qpti->qpti_id);
+	printk("qlogicpti%d: Cannot acquire irq line\n", qpti->qpti_id);
 	return -1;
 }
 
@@ -1210,7 +1212,7 @@
 		host_status = DID_OK;
 		break;
 	      default:
-		printk(KERN_EMERG "qpti%d: unknown completion status 0x%04x\n",
+		printk(KERN_EMERG "qlogicpti%d: unknown completion status 0x%04x\n",
 		       id, sts->completion_status);
 		host_status = DID_ERROR;
 		break;
@@ -1329,8 +1331,8 @@
 	u32 cmd_cookie;
 	int i;
 
-	printk(KERN_WARNING "qlogicpti : Aborting cmd for tgt[%d] lun[%d]\n",
-	       (int)Cmnd->device->id, (int)Cmnd->device->lun);
+	printk(KERN_WARNING "qlogicpti%d: Aborting cmd for tgt[%d] lun[%d]\n",
+	       qpti->qpti_id, (int)Cmnd->device->id, (int)Cmnd->device->lun);
 
 	qlogicpti_disable_irqs(qpti);
 
@@ -1348,7 +1350,8 @@
 	param[3] = cmd_cookie & 0xffff;
 	if (qlogicpti_mbox_command(qpti, param, 0) ||
 	    (param[0] != MBOX_COMMAND_COMPLETE)) {
-		printk(KERN_EMERG "qlogicpti : scsi abort failure: %x\n", param[0]);
+		printk(KERN_EMERG "qlogicpti%d: scsi abort failure: %x\n",
+		       qpti->qpti_id, param[0]);
 		return_status = FAILED;
 	}
 
@@ -1364,7 +1367,8 @@
 	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
 	int return_status = SUCCESS;
 
-	printk(KERN_WARNING "qlogicpti : Resetting SCSI bus!\n");
+	printk(KERN_WARNING "qlogicpti%d: Resetting SCSI bus!\n",
+	       qpti->qpti_id);
 
 	qlogicpti_disable_irqs(qpti);
 
@@ -1372,7 +1376,8 @@
 	param[1] = qpti->host_param.bus_reset_delay;
 	if (qlogicpti_mbox_command(qpti, param, 0) ||
 	   (param[0] != MBOX_COMMAND_COMPLETE)) {
-		printk(KERN_EMERG "qlogicisp : scsi bus reset failure: %x\n", param[0]);
+		printk(KERN_EMERG "qlogicisp%d: scsi bus reset failure: %x\n",
+		       qpti->qpti_id, param[0]);
 		return_status = FAILED;
 	}
 
@@ -1454,22 +1459,25 @@
 	if (qlogicpti_reset_hardware(host))
 		goto fail_unmap_queues;
 
-	if (scsi_add_host(host, &dev->dev))
-		goto fail_unmap_queues;
-
 	printk("(Firmware v%d.%d.%d)", qpti->fware_majrev,
 	       qpti->fware_minrev, qpti->fware_micrev);
 
 	fcode = of_get_property(dp, "isp-fcode", NULL);
 	if (fcode && fcode[0])
-		printk("(Firmware %s)", fcode);
+		printk("(FCode %s)", fcode);
 	if (of_find_property(dp, "differential", NULL) != NULL)
 		qpti->differential = 1;
 			
-	printk (" [%s Wide, using %s interface]\n",
+	printk("\nqlogicpti%d: [%s Wide, using %s interface]\n",
+		qpti->qpti_id,
 		(qpti->ultra ? "Ultra" : "Fast"),
 		(qpti->differential ? "differential" : "single ended"));
 
+	if (scsi_add_host(host, &dev->dev)) {
+		printk("qlogicpti%d: Failed scsi_add_host\n", qpti->qpti_id);
+		goto fail_unmap_queues;
+	}
+
 	dev_set_drvdata(&sdev->ofdev.dev, qpti);
 
 	qpti_chain_add(qpti);
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index a691dda..a5de1a8 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -288,7 +288,7 @@
 	if (!pool->users) {
 		pool->slab = kmem_cache_create(pool->name,
 				sizeof(struct scsi_cmnd), 0,
-				pool->slab_flags, NULL, NULL);
+				pool->slab_flags, NULL);
 		if (!pool->slab)
 			goto fail;
 	}
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 4cd9c58..4947dfe 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -2875,7 +2875,7 @@
 
 	init_all_queued();
 
-	sdebug_driver_template.proc_name = (char *)sdebug_proc_name;
+	sdebug_driver_template.proc_name = sdebug_proc_name;
 
 	host_to_add = scsi_debug_add_host;
         scsi_debug_add_host = 0;
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index 19c44f0..e2ea739 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -154,6 +154,9 @@
 	{"EMC",  "Invista", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
 	{"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
 	{"EMULEX", "MD21/S2     ESDI", NULL, BLIST_SINGLELUN},
+	{"easyRAID", "16P", NULL, BLIST_NOREPORTLUN},
+	{"easyRAID", "X6P", NULL, BLIST_NOREPORTLUN},
+	{"easyRAID", "F8", NULL, BLIST_NOREPORTLUN},
 	{"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
 	{"Generic", "USB SD Reader", "1.00", BLIST_FORCELUN | BLIST_INQUIRY_36},
 	{"Generic", "USB Storage-SMC", "0180", BLIST_FORCELUN | BLIST_INQUIRY_36},
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 1f5a07b..604f4d7 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -263,25 +263,12 @@
 		bio->bi_rw |= (1 << BIO_RW);
 	blk_queue_bounce(q, &bio);
 
-	if (!rq->bio)
-		blk_rq_bio_prep(q, rq, bio);
-	else if (!ll_back_merge_fn(q, rq, bio))
-		return -EINVAL;
-	else {
-		rq->biotail->bi_next = bio;
-		rq->biotail = bio;
-	}
-
-	return 0;
+	return blk_rq_append_bio(q, rq, bio);
 }
 
-static int scsi_bi_endio(struct bio *bio, unsigned int bytes_done, int error)
+static void scsi_bi_endio(struct bio *bio, int error)
 {
-	if (bio->bi_size)
-		return 1;
-
 	bio_put(bio);
-	return 0;
 }
 
 /**
@@ -337,7 +324,7 @@
 			if (bio->bi_vcnt >= nr_vecs) {
 				err = scsi_merge_bio(rq, bio);
 				if (err) {
-					bio_endio(bio, bio->bi_size, 0);
+					bio_endio(bio, 0);
 					goto free_bios;
 				}
 				bio = NULL;
@@ -359,7 +346,7 @@
 		/*
 		 * call endio instead of bio_put incase it was bounced
 		 */
-		bio_endio(bio, bio->bi_size, 0);
+		bio_endio(bio, 0);
 	}
 
 	return err;
@@ -654,7 +641,7 @@
 static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
 					  int bytes, int requeue)
 {
-	request_queue_t *q = cmd->device->request_queue;
+	struct request_queue *q = cmd->device->request_queue;
 	struct request *req = cmd->request;
 	unsigned long flags;
 
@@ -818,7 +805,7 @@
 {
 	int result = cmd->result;
 	int this_count = cmd->request_bufflen;
-	request_queue_t *q = cmd->device->request_queue;
+	struct request_queue *q = cmd->device->request_queue;
 	struct request *req = cmd->request;
 	int clear_errors = 1;
 	struct scsi_sense_hdr sshdr;
@@ -1038,22 +1025,6 @@
 	return BLKPREP_KILL;
 }
 
-static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk,
-			       sector_t *error_sector)
-{
-	struct scsi_device *sdev = q->queuedata;
-	struct scsi_driver *drv;
-
-	if (sdev->sdev_state != SDEV_RUNNING)
-		return -ENXIO;
-
-	drv = *(struct scsi_driver **) disk->private_data;
-	if (drv->issue_flush)
-		return drv->issue_flush(&sdev->sdev_gendev, error_sector);
-
-	return -EOPNOTSUPP;
-}
-
 static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev,
 		struct request *req)
 {
@@ -1340,7 +1311,7 @@
 /*
  * Kill a request for a dead device
  */
-static void scsi_kill_request(struct request *req, request_queue_t *q)
+static void scsi_kill_request(struct request *req, struct request_queue *q)
 {
 	struct scsi_cmnd *cmd = req->special;
 	struct scsi_device *sdev = cmd->device;
@@ -1596,7 +1567,6 @@
 		return NULL;
 
 	blk_queue_prep_rq(q, scsi_prep_fn);
-	blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
 	blk_queue_softirq_done(q, scsi_softirq_done);
 	return q;
 }
@@ -1661,7 +1631,7 @@
 
 	scsi_io_context_cache = kmem_cache_create("scsi_io_context",
 					sizeof(struct scsi_io_context),
-					0, 0, NULL, NULL);
+					0, 0, NULL);
 	if (!scsi_io_context_cache) {
 		printk(KERN_ERR "SCSI: can't init scsi io context cache\n");
 		return -ENOMEM;
@@ -1672,7 +1642,7 @@
 		int size = sgp->size * sizeof(struct scatterlist);
 
 		sgp->slab = kmem_cache_create(sgp->name, size, 0,
-				SLAB_HWCACHE_ALIGN, NULL, NULL);
+				SLAB_HWCACHE_ALIGN, NULL);
 		if (!sgp->slab) {
 			printk(KERN_ERR "SCSI: can't init sg slab %s\n",
 					sgp->name);
@@ -2119,7 +2089,7 @@
 int
 scsi_internal_device_block(struct scsi_device *sdev)
 {
-	request_queue_t *q = sdev->request_queue;
+	struct request_queue *q = sdev->request_queue;
 	unsigned long flags;
 	int err = 0;
 
@@ -2159,7 +2129,7 @@
 int
 scsi_internal_device_unblock(struct scsi_device *sdev)
 {
-	request_queue_t *q = sdev->request_queue; 
+	struct request_queue *q = sdev->request_queue; 
 	int err;
 	unsigned long flags;
 	
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
index 4bf9aa547..40579ed 100644
--- a/drivers/scsi/scsi_netlink.c
+++ b/drivers/scsi/scsi_netlink.c
@@ -64,7 +64,7 @@
 
 		if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) {
 			err = -EBADMSG;
-			goto next_msg;
+			return;
 		}
 
 		hdr = NLMSG_DATA(nlh);
@@ -99,27 +99,6 @@
 
 
 /**
- * scsi_nl_rcv_msg -
- *    Receive handler for a socket. Extracts a received message buffer from
- *    the socket, and starts message processing.
- *
- * @sk:		socket
- * @len:	unused
- *
- **/
-static void
-scsi_nl_rcv(struct sock *sk, int len)
-{
-	struct sk_buff *skb;
-
-	while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
-		scsi_nl_rcv_msg(skb);
-		kfree_skb(skb);
-	}
-}
-
-
-/**
  * scsi_nl_rcv_event -
  *    Event handler for a netlink socket.
  *
@@ -167,8 +146,8 @@
 		return;
 	}
 
-	scsi_nl_sock = netlink_kernel_create(NETLINK_SCSITRANSPORT,
-				SCSI_NL_GRP_CNT, scsi_nl_rcv, NULL,
+	scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT,
+				SCSI_NL_GRP_CNT, scsi_nl_rcv_msg, NULL,
 				THIS_MODULE);
 	if (!scsi_nl_sock) {
 		printk(KERN_ERR "%s: register of recieve handler failed\n",
diff --git a/drivers/scsi/scsi_sysctl.c b/drivers/scsi/scsi_sysctl.c
index 6cfaaa2..63a30f5 100644
--- a/drivers/scsi/scsi_sysctl.c
+++ b/drivers/scsi/scsi_sysctl.c
@@ -9,6 +9,7 @@
 #include <linux/sysctl.h>
 
 #include "scsi_logging.h"
+#include "scsi_priv.h"
 
 
 static ctl_table scsi_table[] = {
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index ed72086..ede9986 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -16,6 +16,7 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsi_transport.h>
+#include <scsi/scsi_driver.h>
 
 #include "scsi_priv.h"
 #include "scsi_logging.h"
@@ -276,16 +277,11 @@
 	return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
 }
 
-static int scsi_bus_uevent(struct device *dev, char **envp, int num_envp,
-		           char *buffer, int buffer_size)
+static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct scsi_device *sdev = to_scsi_device(dev);
-	int i = 0;
-	int length = 0;
 
-	add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-		       "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
-	envp[i] = NULL;
+	add_uevent_var(env, "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type);
 	return 0;
 }
 
@@ -714,6 +710,7 @@
 int scsi_sysfs_add_sdev(struct scsi_device *sdev)
 {
 	int error, i;
+	struct request_queue *rq = sdev->request_queue;
 
 	if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0)
 		return error;
@@ -733,6 +730,17 @@
 	/* take a reference for the sdev_classdev; this is
 	 * released by the sdev_class .release */
 	get_device(&sdev->sdev_gendev);
+
+	error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL);
+
+	if (error)
+		sdev_printk(KERN_INFO, sdev,
+			    "Failed to register bsg queue, errno=%d\n", error);
+
+	/* we're treating error on bsg register as non-fatal, so pretend
+	 * nothing went wrong */
+	error = 0;
+
 	if (sdev->host->hostt->sdev_attrs) {
 		for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) {
 			error = attr_add(&sdev->sdev_gendev,
@@ -779,6 +787,7 @@
 	if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
 		return;
 
+	bsg_unregister_queue(sdev->request_queue);
 	class_device_unregister(&sdev->sdev_classdev);
 	transport_remove_device(dev);
 	device_del(dev);
@@ -803,7 +812,7 @@
 }
 EXPORT_SYMBOL(scsi_remove_device);
 
-void __scsi_remove_target(struct scsi_target *starget)
+static void __scsi_remove_target(struct scsi_target *starget)
 {
 	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 	unsigned long flags;
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index 2570f48..371b69c 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -585,7 +585,7 @@
 
 	scsi_tgt_cmd_cache = kmem_cache_create("scsi_tgt_cmd",
 					       sizeof(struct scsi_tgt_cmd),
-					       0, 0, NULL, NULL);
+					       0, 0, NULL);
 	if (!scsi_tgt_cmd_cache)
 		return -ENOMEM;
 
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index e882570..4705725 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -2358,7 +2358,7 @@
  * Notes:
  *	This routine assumes no locks are held on entry.
  **/
-struct fc_rport *
+static struct fc_rport *
 fc_rport_create(struct Scsi_Host *shost, int channel,
 	struct fc_rport_identifiers  *ids)
 {
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 34c1860..5428d15 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -1097,61 +1097,49 @@
 }
 
 /*
- * Get message from skb (based on rtnetlink_rcv_skb).  Each message is
- * processed by iscsi_if_recv_msg.  Malformed skbs with wrong lengths or
- * invalid creds are discarded silently.
+ * Get message from skb.  Each message is processed by iscsi_if_recv_msg.
+ * Malformed skbs with wrong lengths or invalid creds are not processed.
  */
 static void
-iscsi_if_rx(struct sock *sk, int len)
+iscsi_if_rx(struct sk_buff *skb)
 {
-	struct sk_buff *skb;
-
 	mutex_lock(&rx_queue_mutex);
-	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
-		if (NETLINK_CREDS(skb)->uid) {
-			skb_pull(skb, skb->len);
-			goto free_skb;
+	while (skb->len >= NLMSG_SPACE(0)) {
+		int err;
+		uint32_t rlen;
+		struct nlmsghdr	*nlh;
+		struct iscsi_uevent *ev;
+
+		nlh = nlmsg_hdr(skb);
+		if (nlh->nlmsg_len < sizeof(*nlh) ||
+		    skb->len < nlh->nlmsg_len) {
+			break;
 		}
 
-		while (skb->len >= NLMSG_SPACE(0)) {
-			int err;
-			uint32_t rlen;
-			struct nlmsghdr	*nlh;
-			struct iscsi_uevent *ev;
+		ev = NLMSG_DATA(nlh);
+		rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+		if (rlen > skb->len)
+			rlen = skb->len;
 
-			nlh = nlmsg_hdr(skb);
-			if (nlh->nlmsg_len < sizeof(*nlh) ||
-			    skb->len < nlh->nlmsg_len) {
+		err = iscsi_if_recv_msg(skb, nlh);
+		if (err) {
+			ev->type = ISCSI_KEVENT_IF_ERROR;
+			ev->iferror = err;
+		}
+		do {
+			/*
+			 * special case for GET_STATS:
+			 * on success - sending reply and stats from
+			 * inside of if_recv_msg(),
+			 * on error - fall through.
+			 */
+			if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
 				break;
-			}
-
-			ev = NLMSG_DATA(nlh);
-			rlen = NLMSG_ALIGN(nlh->nlmsg_len);
-			if (rlen > skb->len)
-				rlen = skb->len;
-
-			err = iscsi_if_recv_msg(skb, nlh);
-			if (err) {
-				ev->type = ISCSI_KEVENT_IF_ERROR;
-				ev->iferror = err;
-			}
-			do {
-				/*
-				 * special case for GET_STATS:
-				 * on success - sending reply and stats from
-				 * inside of if_recv_msg(),
-				 * on error - fall through.
-				 */
-				if (ev->type == ISCSI_UEVENT_GET_STATS && !err)
-					break;
-				err = iscsi_if_send_reply(
-					NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
-					nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
-			} while (err < 0 && err != -ECONNREFUSED);
-			skb_pull(skb, rlen);
-		}
-free_skb:
-		kfree_skb(skb);
+			err = iscsi_if_send_reply(
+				NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq,
+				nlh->nlmsg_type, 0, 0, ev, sizeof(*ev));
+		} while (err < 0 && err != -ECONNREFUSED);
+		skb_pull(skb, rlen);
 	}
 	mutex_unlock(&rx_queue_mutex);
 }
@@ -1523,7 +1511,7 @@
 	if (err)
 		goto unregister_conn_class;
 
-	nls = netlink_kernel_create(NETLINK_ISCSI, 1, iscsi_if_rx, NULL,
+	nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx, NULL,
 			THIS_MODULE);
 	if (!nls) {
 		err = -ENOBUFS;
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index b2ef71a..3120f4b 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -29,6 +29,8 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/blkdev.h>
+#include <linux/bsg.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_device.h>
@@ -40,6 +42,7 @@
 struct sas_host_attrs {
 	struct list_head rphy_list;
 	struct mutex lock;
+	struct request_queue *q;
 	u32 next_target_id;
 	u32 next_expander_id;
 	int next_port_id;
@@ -152,6 +155,106 @@
 sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
 sas_bitfield_name_set(linkspeed, sas_linkspeed_names)
 
+static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost,
+			    struct sas_rphy *rphy)
+{
+	struct request *req;
+	int ret;
+	int (*handler)(struct Scsi_Host *, struct sas_rphy *, struct request *);
+
+	while (!blk_queue_plugged(q)) {
+		req = elv_next_request(q);
+		if (!req)
+			break;
+
+		blkdev_dequeue_request(req);
+
+		spin_unlock_irq(q->queue_lock);
+
+		handler = to_sas_internal(shost->transportt)->f->smp_handler;
+		ret = handler(shost, rphy, req);
+
+		spin_lock_irq(q->queue_lock);
+
+		req->end_io(req, ret);
+	}
+}
+
+static void sas_host_smp_request(struct request_queue *q)
+{
+	sas_smp_request(q, (struct Scsi_Host *)q->queuedata, NULL);
+}
+
+static void sas_non_host_smp_request(struct request_queue *q)
+{
+	struct sas_rphy *rphy = q->queuedata;
+	sas_smp_request(q, rphy_to_shost(rphy), rphy);
+}
+
+static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
+{
+	struct request_queue *q;
+	int error;
+	struct device *dev;
+	char namebuf[BUS_ID_SIZE];
+	const char *name;
+
+	if (!to_sas_internal(shost->transportt)->f->smp_handler) {
+		printk("%s can't handle SMP requests\n", shost->hostt->name);
+		return 0;
+	}
+
+	if (rphy) {
+		q = blk_init_queue(sas_non_host_smp_request, NULL);
+		dev = &rphy->dev;
+		name = dev->bus_id;
+	} else {
+		q = blk_init_queue(sas_host_smp_request, NULL);
+		dev = &shost->shost_gendev;
+		snprintf(namebuf, sizeof(namebuf),
+			 "sas_host%d", shost->host_no);
+		name = namebuf;
+	}
+	if (!q)
+		return -ENOMEM;
+
+	error = bsg_register_queue(q, dev, name);
+	if (error) {
+		blk_cleanup_queue(q);
+		return -ENOMEM;
+	}
+
+	if (rphy)
+		rphy->q = q;
+	else
+		to_sas_host_attrs(shost)->q = q;
+
+	if (rphy)
+		q->queuedata = rphy;
+	else
+		q->queuedata = shost;
+
+	set_bit(QUEUE_FLAG_BIDI, &q->queue_flags);
+
+	return 0;
+}
+
+static void sas_bsg_remove(struct Scsi_Host *shost, struct sas_rphy *rphy)
+{
+	struct request_queue *q;
+
+	if (rphy)
+		q = rphy->q;
+	else
+		q = to_sas_host_attrs(shost)->q;
+
+	if (!q)
+		return;
+
+	bsg_unregister_queue(q);
+	blk_cleanup_queue(q);
+}
+
 /*
  * SAS host attributes
  */
@@ -167,11 +270,26 @@
 	sas_host->next_target_id = 0;
 	sas_host->next_expander_id = 0;
 	sas_host->next_port_id = 0;
+
+	if (sas_bsg_initialize(shost, NULL))
+		dev_printk(KERN_ERR, dev, "fail to a bsg device %d\n",
+			   shost->host_no);
+
+	return 0;
+}
+
+static int sas_host_remove(struct transport_container *tc, struct device *dev,
+			   struct class_device *cdev)
+{
+	struct Scsi_Host *shost = dev_to_shost(dev);
+
+	sas_bsg_remove(shost, NULL);
+
 	return 0;
 }
 
 static DECLARE_TRANSPORT_CLASS(sas_host_class,
-		"sas_host", sas_host_setup, NULL, NULL);
+		"sas_host", sas_host_setup, sas_host_remove, NULL);
 
 static int sas_host_match(struct attribute_container *cont,
 			    struct device *dev)
@@ -1287,6 +1405,9 @@
 		return error;
 	transport_add_device(&rphy->dev);
 	transport_configure_device(&rphy->dev);
+	if (sas_bsg_initialize(shost, rphy))
+		printk("fail to a bsg device %s\n", rphy->dev.bus_id);
+
 
 	mutex_lock(&sas_host->lock);
 	list_add_tail(&rphy->list, &sas_host->rphy_list);
@@ -1329,6 +1450,8 @@
 	list_del(&rphy->list);
 	mutex_unlock(&sas_host->lock);
 
+	sas_bsg_remove(shost, rphy);
+
 	transport_destroy_device(dev);
 
 	put_device(dev);
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index 6f56f87..4df21c9 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -787,10 +787,12 @@
 	struct scsi_target *starget = sdev->sdev_target;
 	struct Scsi_Host *shost = sdev->host;
 	int len = sdev->inquiry_len;
+	int min_period = spi_min_period(starget);
+	int max_width = spi_max_width(starget);
 	/* first set us up for narrow async */
 	DV_SET(offset, 0);
 	DV_SET(width, 0);
-	
+
 	if (spi_dv_device_compare_inquiry(sdev, buffer, buffer, DV_LOOPS)
 	    != SPI_COMPARE_SUCCESS) {
 		starget_printk(KERN_ERR, starget, "Domain Validation Initial Inquiry Failed\n");
@@ -798,9 +800,13 @@
 		return;
 	}
 
+	if (!scsi_device_wide(sdev)) {
+		spi_max_width(starget) = 0;
+		max_width = 0;
+	}
+
 	/* test width */
-	if (i->f->set_width && spi_max_width(starget) &&
-	    scsi_device_wide(sdev)) {
+	if (i->f->set_width && max_width) {
 		i->f->set_width(starget, 1);
 
 		if (spi_dv_device_compare_inquiry(sdev, buffer,
@@ -809,6 +815,11 @@
 		    != SPI_COMPARE_SUCCESS) {
 			starget_printk(KERN_ERR, starget, "Wide Transfers Fail\n");
 			i->f->set_width(starget, 0);
+			/* Make sure we don't force wide back on by asking
+			 * for a transfer period that requires it */
+			max_width = 0;
+			if (min_period < 10)
+				min_period = 10;
 		}
 	}
 
@@ -828,7 +839,8 @@
 
 	/* now set up to the maximum */
 	DV_SET(offset, spi_max_offset(starget));
-	DV_SET(period, spi_min_period(starget));
+	DV_SET(period, min_period);
+
 	/* try QAS requests; this should be harmless to set if the
 	 * target supports it */
 	if (scsi_device_qas(sdev)) {
@@ -837,14 +849,14 @@
 		DV_SET(qas, 0);
 	}
 
-	if (scsi_device_ius(sdev) && spi_min_period(starget) < 9) {
+	if (scsi_device_ius(sdev) && min_period < 9) {
 		/* This u320 (or u640). Set IU transfers */
 		DV_SET(iu, 1);
 		/* Then set the optional parameters */
 		DV_SET(rd_strm, 1);
 		DV_SET(wr_flow, 1);
 		DV_SET(rti, 1);
-		if (spi_min_period(starget) == 8)
+		if (min_period == 8)
 			DV_SET(pcomp_en, 1);
 	} else {
 		DV_SET(iu, 0);
@@ -862,6 +874,10 @@
 	} else {
 		DV_SET(dt, 1);
 	}
+	/* set width last because it will pull all the other
+	 * parameters down to required values */
+	DV_SET(width, max_width);
+
 	/* Do the read only INQUIRY tests */
 	spi_dv_retrain(sdev, buffer, buffer + sdev->inquiry_len,
 		       spi_dv_device_compare_inquiry);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 424d557..2c6116f 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -241,7 +241,6 @@
 	},
 	.rescan			= sd_rescan,
 	.init_command		= sd_init_command,
-	.issue_flush		= sd_issue_flush,
 };
 
 /*
@@ -800,10 +799,17 @@
 	return 0;
 }
 
-static int sd_issue_flush(struct device *dev, sector_t *error_sector)
+static int sd_issue_flush(struct request_queue *q, struct gendisk *disk,
+			  sector_t *error_sector)
 {
 	int ret = 0;
-	struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);
+	struct scsi_device *sdp = q->queuedata;
+	struct scsi_disk *sdkp;
+
+	if (sdp->sdev_state != SDEV_RUNNING)
+		return -ENXIO;
+
+	sdkp = scsi_disk_get_from_dev(&sdp->sdev_gendev);
 
 	if (!sdkp)
                return -ENODEV;
@@ -814,7 +820,7 @@
 	return ret;
 }
 
-static void sd_prepare_flush(request_queue_t *q, struct request *rq)
+static void sd_prepare_flush(struct request_queue *q, struct request *rq)
 {
 	memset(rq->cmd, 0, sizeof(rq->cmd));
 	rq->cmd_type = REQ_TYPE_BLOCK_PC;
@@ -1285,7 +1291,7 @@
 		 */
 		int hard_sector = sector_size;
 		sector_t sz = (sdkp->capacity/2) * (hard_sector/256);
-		request_queue_t *queue = sdp->request_queue;
+		struct request_queue *queue = sdp->request_queue;
 		sector_t mb = sz;
 
 		blk_queue_hardsect_size(queue, hard_sector);
@@ -1663,6 +1669,8 @@
 
 	sd_revalidate_disk(gd);
 
+	blk_queue_issue_flush_fn(sdp->request_queue, sd_issue_flush);
+
 	gd->driverfs_dev = &sdp->sdev_gendev;
 	gd->flags = GENHD_FL_DRIVERFS;
 	if (sdp->removable)
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
index ff62e97..ce80fa9 100644
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -420,7 +420,7 @@
 #define ULOOP( i ) for (clock = i*8;;)
 #define TIMEOUT (!(clock--))
 
-int __init seagate_st0x_detect (struct scsi_host_template * tpnt)
+static int __init seagate_st0x_detect (struct scsi_host_template * tpnt)
 {
 	struct Scsi_Host *instance;
 	int i, j;
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
index 018c65f..d63d229 100644
--- a/drivers/scsi/sim710.c
+++ b/drivers/scsi/sim710.c
@@ -100,7 +100,7 @@
 {
 	struct Scsi_Host * host = NULL;
 	struct NCR_700_Host_Parameters *hostdata =
-		kmalloc(sizeof(struct NCR_700_Host_Parameters),	GFP_KERNEL);
+		kzalloc(sizeof(struct NCR_700_Host_Parameters),	GFP_KERNEL);
 
 	printk(KERN_NOTICE "sim710: %s\n", dev->bus_id);
 	printk(KERN_NOTICE "sim710: irq = %d, clock = %d, base = 0x%lx, scsi_id = %d\n",
@@ -110,7 +110,6 @@
 		printk(KERN_ERR "sim710: Failed to allocate host data\n");
 		goto out;
 	}
-	memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
 
 	if(request_region(base_addr, 64, "sim710") == NULL) {
 		printk(KERN_ERR "sim710: Failed to reserve IO region 0x%lx\n",
@@ -139,6 +138,7 @@
 		goto out_put_host;
 	}
 
+	dev_set_drvdata(dev, host);
 	scsi_scan_host(host);
 
 	return 0;
@@ -156,7 +156,7 @@
 static __devexit int
 sim710_device_remove(struct device *dev)
 {
-	struct Scsi_Host *host = dev_to_shost(dev);
+	struct Scsi_Host *host = dev_get_drvdata(dev);
 	struct NCR_700_Host_Parameters *hostdata =
 		(struct NCR_700_Host_Parameters *)host->hostdata[0];
 
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 5143c89..902eb11 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -175,7 +175,7 @@
  * an inode for that to work, and we do not always have one.
  */
 
-int sr_media_change(struct cdrom_device_info *cdi, int slot)
+static int sr_media_change(struct cdrom_device_info *cdi, int slot)
 {
 	struct scsi_cd *cd = cdi->handle;
 	int retval;
@@ -624,7 +624,7 @@
 	unsigned char *buffer;
 	int the_result, retries = 3;
 	int sector_size;
-	request_queue_t *queue;
+	struct request_queue *queue;
 
 	buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
 	if (!buffer)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index a4f7b84..73c44cb 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -1485,7 +1485,7 @@
 	struct st_buffer *STbp;
 	char *name = tape_name(STp);
 
-	if (down_interruptible(&STp->lock))
+	if (mutex_lock_interruptible(&STp->lock))
 		return -ERESTARTSYS;
 
 	retval = rw_checks(STp, filp, count);
@@ -1736,7 +1736,7 @@
 	if (SRpnt != NULL)
 		st_release_request(SRpnt);
 	release_buffering(STp, 0);
-	up(&STp->lock);
+	mutex_unlock(&STp->lock);
 
 	return retval;
 }
@@ -1942,7 +1942,7 @@
 	struct st_buffer *STbp = STp->buffer;
 	DEB( char *name = tape_name(STp); )
 
-	if (down_interruptible(&STp->lock))
+	if (mutex_lock_interruptible(&STp->lock))
 		return -ERESTARTSYS;
 
 	retval = rw_checks(STp, filp, count);
@@ -2069,7 +2069,7 @@
 		release_buffering(STp, 1);
 		STbp->buffer_bytes = 0;
 	}
-	up(&STp->lock);
+	mutex_unlock(&STp->lock);
 
 	return retval;
 }
@@ -3226,7 +3226,7 @@
 	char *name = tape_name(STp);
 	void __user *p = (void __user *)arg;
 
-	if (down_interruptible(&STp->lock))
+	if (mutex_lock_interruptible(&STp->lock))
 		return -ERESTARTSYS;
 
         DEB(
@@ -3537,7 +3537,7 @@
 			retval = (-EFAULT);
 		goto out;
 	}
-	up(&STp->lock);
+	mutex_unlock(&STp->lock);
 	switch (cmd_in) {
 		case SCSI_IOCTL_GET_IDLUN:
 		case SCSI_IOCTL_GET_BUS_NUMBER:
@@ -3563,7 +3563,7 @@
 	return retval;
 
  out:
-	up(&STp->lock);
+	mutex_unlock(&STp->lock);
 	return retval;
 }
 
@@ -4029,7 +4029,7 @@
 
 	tpnt->density_changed = tpnt->compression_changed =
 	    tpnt->blksize_changed = 0;
-	init_MUTEX(&tpnt->lock);
+	mutex_init(&tpnt->lock);
 
 	st_nr_dev++;
 	write_unlock(&st_dev_arr_lock);
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index 50f3deb..6c80757 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -3,6 +3,7 @@
 #define _ST_H
 
 #include <linux/completion.h>
+#include <linux/mutex.h>
 #include <linux/kref.h>
 #include <scsi/scsi_cmnd.h>
 
@@ -98,7 +99,7 @@
 struct scsi_tape {
 	struct scsi_driver *driver;
 	struct scsi_device *device;
-	struct semaphore lock;	/* For serialization */
+	struct mutex lock;	/* For serialization */
 	struct completion wait;	/* For SCSI commands */
 	struct st_buffer *buffer;
 
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 15a5145..3db2232 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -2033,7 +2033,7 @@
 	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C875,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C1510,
-	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, /* new */
+	  PCI_ANY_ID, PCI_ANY_ID,  PCI_CLASS_STORAGE_SCSI<<8,  0xffff00, 0UL }, /* new */
 	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C895A,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C875A,
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index 14cba1c..5db1520 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -2082,10 +2082,9 @@
 	uint id = scsi_device->id;
 	uint lun = scsi_device->lun;
 
-	pDCB = kmalloc(sizeof(struct dc390_dcb), GFP_KERNEL);
+	pDCB = kzalloc(sizeof(struct dc390_dcb), GFP_KERNEL);
 	if (!pDCB)
 		return -ENOMEM;
-	memset(pDCB, 0, sizeof(struct dc390_dcb));
 
 	if (!pACB->DCBCnt++) {
 		pACB->pLinkDCB = pDCB;
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index fa4e08e..b92ff04 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -89,6 +89,8 @@
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 
+#include <asm/irq.h>
+
 #include "wd33c93.h"
 
 #define optimum_sx_per(hostdata) (hostdata)->sx_table[1].period_ns
@@ -1762,7 +1764,7 @@
 static char setup_used[MAX_SETUP_ARGS];
 static int done_setup = 0;
 
-int
+static int
 wd33c93_setup(char *str)
 {
 	int i;
diff --git a/drivers/scsi/zorro7xx.c b/drivers/scsi/zorro7xx.c
index 5070387..c822deb 100644
--- a/drivers/scsi/zorro7xx.c
+++ b/drivers/scsi/zorro7xx.c
@@ -130,6 +130,7 @@
 		goto out_put_host;
 	}
 
+	zorro_set_drvdata(z, host);
 	scsi_scan_host(host);
 
 	return 0;
@@ -148,7 +149,7 @@
 
 static __devexit void zorro7xx_remove_one(struct zorro_dev *z)
 {
-	struct Scsi_Host *host = dev_to_shost(&z->dev);
+	struct Scsi_Host *host = zorro_get_drvdata(z);
 	struct NCR_700_Host_Parameters *hostdata = shost_priv(host);
 
 	scsi_remove_host(host);
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index cad426c..aad4012 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -33,7 +33,6 @@
 #include <linux/keyboard.h>
 #include <linux/init.h>
 #include <linux/pm.h>
-#include <linux/pm_legacy.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
 
@@ -401,9 +400,9 @@
 	return IRQ_HANDLED;
 }
 
-static void do_softint(void *private)
+static void do_softint(struct work_struct *work)
 {
-	struct m68k_serial	*info = (struct m68k_serial *) private;
+	struct m68k_serial	*info = container_of(work, struct m68k_serial, tqueue);
 	struct tty_struct	*tty;
 	
 	tty = info->tty;
@@ -425,9 +424,9 @@
  * 	do_serial_hangup() -> tty->hangup() -> rs_hangup()
  * 
  */
-static void do_serial_hangup(void *private)
+static void do_serial_hangup(struct work_struct *work)
 {
-	struct m68k_serial	*info = (struct m68k_serial *) private;
+	struct m68k_serial	*info = container_of(work, struct m68k_serial, tqueue_hangup);
 	struct tty_struct	*tty;
 	
 	tty = info->tty;
@@ -1324,59 +1323,6 @@
 	printk("MC68328 serial driver version 1.00\n");
 }
 
-#ifdef CONFIG_PM_LEGACY
-/* Serial Power management
- *  The console (currently fixed at line 0) is a special case for power
- *  management because the kernel is so chatty. The console will be 
- *  explicitly disabled my our power manager as the last minute, so we won't
- *  mess with it here.
- */
-static struct pm_dev *serial_pm[NR_PORTS];
-
-static int serial_pm_callback(struct pm_dev *dev, pm_request_t request, void *data)
-{
-	struct m68k_serial *info = (struct m68k_serial *)dev->data;
-
-	if(info == NULL)
-		return -1;
-
-	/* special case for line 0 - pm restores it */
-	if(info->line == 0)
-		return 0; 
-
-	switch (request) {
-	case PM_SUSPEND:
-		shutdown(info);
-		break;
-
-	case PM_RESUME:
-		startup(info);
-		break;
-	}
-	return 0;
-}
-
-void shutdown_console(void)
-{
-	struct m68k_serial *info = &m68k_soft[0];
-
-	/* HACK: wait a bit for any pending printk's to be dumped */
-	{
-		int i = 10000;
-		while(i--);
-	}
-
-	shutdown(info);
-}
-
-void startup_console(void)
-{
-	struct m68k_serial *info = &m68k_soft[0];
-	startup(info);
-}
-#endif /* CONFIG_PM_LEGACY */
-
-
 static const struct tty_operations rs_ops = {
 	.open = rs_open,
 	.close = rs_close,
@@ -1444,8 +1390,8 @@
 	    info->event = 0;
 	    info->count = 0;
 	    info->blocked_open = 0;
-	    INIT_WORK(&info->tqueue, do_softint, info);
-	    INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info);
+	    INIT_WORK(&info->tqueue, do_softint);
+	    INIT_WORK(&info->tqueue_hangup, do_serial_hangup);
 	    init_waitqueue_head(&info->open_wait);
 	    init_waitqueue_head(&info->close_wait);
 	    info->line = i;
@@ -1467,11 +1413,6 @@
 			    IRQ_FLG_STD,
 			    "M68328_UART", NULL))
                 panic("Unable to attach 68328 serial interrupt\n");
-#ifdef CONFIG_PM_LEGACY
-	    serial_pm[i] = pm_register(PM_SYS_DEV, PM_SYS_COM, serial_pm_callback);
-	    if (serial_pm[i])
-		    serial_pm[i]->data = info;
-#endif
 	}
 	local_irq_restore(flags);
 	return 0;
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 0b3ec38..f94109c 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -129,7 +129,16 @@
 	unsigned char		mcr;
 	unsigned char		mcr_mask;	/* mask of user bits */
 	unsigned char		mcr_force;	/* mask of forced bits */
-	unsigned char		lsr_break_flag;
+
+	/*
+	 * Some bits in registers are cleared on a read, so they must
+	 * be saved whenever the register is read but the bits will not
+	 * be immediately processed.
+	 */
+#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
+	unsigned char		lsr_saved_flags;
+#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
+	unsigned char		msr_saved_flags;
 
 	/*
 	 * We provide a per-port pm hook.
@@ -1238,6 +1247,7 @@
 		if (up->bugs & UART_BUG_TXEN) {
 			unsigned char lsr, iir;
 			lsr = serial_in(up, UART_LSR);
+			up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
 			iir = serial_in(up, UART_IIR) & 0x0f;
 			if ((up->port.type == PORT_RM9000) ?
 				(lsr & UART_LSR_THRE &&
@@ -1290,18 +1300,10 @@
 		flag = TTY_NORMAL;
 		up->port.icount.rx++;
 
-#ifdef CONFIG_SERIAL_8250_CONSOLE
-		/*
-		 * Recover the break flag from console xmit
-		 */
-		if (up->port.line == up->port.cons->index) {
-			lsr |= up->lsr_break_flag;
-			up->lsr_break_flag = 0;
-		}
-#endif
+		lsr |= up->lsr_saved_flags;
+		up->lsr_saved_flags = 0;
 
-		if (unlikely(lsr & (UART_LSR_BI | UART_LSR_PE |
-				    UART_LSR_FE | UART_LSR_OE))) {
+		if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
 			/*
 			 * For statistics only
 			 */
@@ -1392,6 +1394,8 @@
 {
 	unsigned int status = serial_in(up, UART_MSR);
 
+	status |= up->msr_saved_flags;
+	up->msr_saved_flags = 0;
 	if (status & UART_MSR_ANY_DELTA && up->ier & UART_IER_MSI &&
 	    up->port.info != NULL) {
 		if (status & UART_MSR_TERI)
@@ -1591,7 +1595,8 @@
 static void serial8250_backup_timeout(unsigned long data)
 {
 	struct uart_8250_port *up = (struct uart_8250_port *)data;
-	unsigned int iir, ier = 0;
+	unsigned int iir, ier = 0, lsr;
+	unsigned long flags;
 
 	/*
 	 * Must disable interrupts or else we risk racing with the interrupt
@@ -1610,9 +1615,13 @@
 	 * the "Diva" UART used on the management processor on many HP
 	 * ia64 and parisc boxes.
 	 */
+	spin_lock_irqsave(&up->port.lock, flags);
+	lsr = serial_in(up, UART_LSR);
+	up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
+	spin_unlock_irqrestore(&up->port.lock, flags);
 	if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
 	    (!uart_circ_empty(&up->port.info->xmit) || up->port.x_char) &&
-	    (serial_in(up, UART_LSR) & UART_LSR_THRE)) {
+	    (lsr & UART_LSR_THRE)) {
 		iir &= ~(UART_IIR_ID | UART_IIR_NO_INT);
 		iir |= UART_IIR_THRI;
 	}
@@ -1631,13 +1640,14 @@
 {
 	struct uart_8250_port *up = (struct uart_8250_port *)port;
 	unsigned long flags;
-	unsigned int ret;
+	unsigned int lsr;
 
 	spin_lock_irqsave(&up->port.lock, flags);
-	ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
+	lsr = serial_in(up, UART_LSR);
+	up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
 	spin_unlock_irqrestore(&up->port.lock, flags);
 
-	return ret;
+	return lsr & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
 }
 
 static unsigned int serial8250_get_mctrl(struct uart_port *port)
@@ -1708,8 +1718,7 @@
 	do {
 		status = serial_in(up, UART_LSR);
 
-		if (status & UART_LSR_BI)
-			up->lsr_break_flag = UART_LSR_BI;
+		up->lsr_saved_flags |= status & LSR_SAVE_FLAGS;
 
 		if (--tmout == 0)
 			break;
@@ -1718,8 +1727,12 @@
 
 	/* Wait up to 1s for flow control if necessary */
 	if (up->port.flags & UPF_CONS_FLOW) {
-		tmout = 1000000;
-		while (!(serial_in(up, UART_MSR) & UART_MSR_CTS) && --tmout) {
+		unsigned int tmout;
+		for (tmout = 1000000; tmout; tmout--) {
+			unsigned int msr = serial_in(up, UART_MSR);
+			up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
+			if (msr & UART_MSR_CTS)
+				break;
 			udelay(1);
 			touch_nmi_watchdog();
 		}
@@ -1889,6 +1902,18 @@
 	spin_unlock_irqrestore(&up->port.lock, flags);
 
 	/*
+	 * Clear the interrupt registers again for luck, and clear the
+	 * saved flags to avoid getting false values from polling
+	 * routines or the previous session.
+	 */
+	serial_inp(up, UART_LSR);
+	serial_inp(up, UART_RX);
+	serial_inp(up, UART_IIR);
+	serial_inp(up, UART_MSR);
+	up->lsr_saved_flags = 0;
+	up->msr_saved_flags = 0;
+
+	/*
 	 * Finally, enable interrupts.  Note: Modem status interrupts
 	 * are set via set_termios(), which will be occurring imminently
 	 * anyway, so we don't enable them here.
@@ -1906,14 +1931,6 @@
 		(void) inb_p(icp);
 	}
 
-	/*
-	 * And clear the interrupt registers again for luck.
-	 */
-	(void) serial_inp(up, UART_LSR);
-	(void) serial_inp(up, UART_RX);
-	(void) serial_inp(up, UART_IIR);
-	(void) serial_inp(up, UART_MSR);
-
 	return 0;
 }
 
@@ -2484,6 +2501,16 @@
 	wait_for_xmitr(up, BOTH_EMPTY);
 	serial_out(up, UART_IER, ier);
 
+	/*
+	 *	The receive handling will happen properly because the
+	 *	receive ready bit will still be set; it is not cleared
+	 *	on read.  However, modem control will not, we must
+	 *	call it if we have saved something in the saved flags
+	 *	while processing with interrupts off.
+	 */
+	if (up->msr_saved_flags)
+		check_modem_status(up);
+
 	if (locked)
 		spin_unlock(&up->port.lock);
 	local_irq_restore(flags);
@@ -2514,7 +2541,7 @@
 	return uart_set_options(port, co, baud, parity, bits, flow);
 }
 
-static int __init serial8250_console_early_setup(void)
+static int serial8250_console_early_setup(void)
 {
 	return serial8250_find_port_for_earlycon();
 }
@@ -2650,8 +2677,9 @@
 		ret = serial8250_register_port(&port);
 		if (ret < 0) {
 			dev_err(&dev->dev, "unable to register port at index %d "
-				"(IO%lx MEM%lx IRQ%d): %d\n", i,
-				p->iobase, p->mapbase, p->irq, ret);
+				"(IO%lx MEM%llx IRQ%d): %d\n", i,
+				p->iobase, (unsigned long long)p->mapbase,
+				p->irq, ret);
 		}
 	}
 	return 0;
diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c
index 947c205..4d4c9f0 100644
--- a/drivers/serial/8250_early.c
+++ b/drivers/serial/8250_early.c
@@ -151,8 +151,9 @@
 #else
 		port->membase = ioremap(port->mapbase, 64);
 		if (!port->membase) {
-			printk(KERN_ERR "%s: Couldn't ioremap 0x%lx\n",
-				__FUNCTION__, port->mapbase);
+			printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n",
+				__FUNCTION__,
+			       (unsigned long long)port->mapbase);
 			return -ENOMEM;
 		}
 #endif
@@ -175,9 +176,10 @@
 			device->baud);
 	}
 
-	printk(KERN_INFO "Early serial console at %s 0x%lx (options '%s')\n",
+	printk(KERN_INFO "Early serial console at %s 0x%llx (options '%s')\n",
 		mmio ? "MMIO" : "I/O port",
-		mmio ? port->mapbase : (unsigned long) port->iobase,
+		mmio ? (unsigned long long) port->mapbase
+	             : (unsigned long long) port->iobase,
 		device->options);
 	return 0;
 }
@@ -225,7 +227,7 @@
 	return 0;
 }
 
-int __init serial8250_find_port_for_earlycon(void)
+int serial8250_find_port_for_earlycon(void)
 {
 	struct early_serial8250_device *device = &early_device;
 	struct uart_port *port = &device->port;
diff --git a/drivers/serial/8250_hp300.c b/drivers/serial/8250_hp300.c
index 53e81a4..2cf0953 100644
--- a/drivers/serial/8250_hp300.c
+++ b/drivers/serial/8250_hp300.c
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/serial_8250.h>
 #include <linux/delay.h>
 #include <linux/dio.h>
 #include <linux/console.h>
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 6d7d616..1ea1ed8 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -580,6 +580,138 @@
 	return num_serial;
 }
 
+/*
+ * ITE support by Niels de Vos <niels.devos@wincor-nixdorf.com>
+ *
+ * These chips are available with optionally one parallel port and up to
+ * two serial ports. Unfortunately they all have the same product id.
+ *
+ * Basic configuration is done over a region of 32 I/O ports. The base
+ * ioport is called INTA or INTC, depending on docs/other drivers.
+ *
+ * The region of the 32 I/O ports is configured in POSIO0R...
+ */
+
+/* registers */
+#define ITE_887x_MISCR		0x9c
+#define ITE_887x_INTCBAR	0x78
+#define ITE_887x_UARTBAR	0x7c
+#define ITE_887x_PS0BAR		0x10
+#define ITE_887x_POSIO0		0x60
+
+/* I/O space size */
+#define ITE_887x_IOSIZE		32
+/* I/O space size (bits 26-24; 8 bytes = 011b) */
+#define ITE_887x_POSIO_IOSIZE_8		(3 << 24)
+/* I/O space size (bits 26-24; 32 bytes = 101b) */
+#define ITE_887x_POSIO_IOSIZE_32	(5 << 24)
+/* Decoding speed (1 = slow, 2 = medium, 3 = fast) */
+#define ITE_887x_POSIO_SPEED		(3 << 29)
+/* enable IO_Space bit */
+#define ITE_887x_POSIO_ENABLE		(1 << 31)
+
+static int pci_ite887x_init(struct pci_dev *dev)
+{
+	/* inta_addr are the configuration addresses of the ITE */
+	static const short inta_addr[] = { 0x2a0, 0x2c0, 0x220, 0x240, 0x1e0,
+							0x200, 0x280, 0 };
+	int ret, i, type;
+	struct resource *iobase = NULL;
+	u32 miscr, uartbar, ioport;
+
+	/* search for the base-ioport */
+	i = 0;
+	while (inta_addr[i] && iobase == NULL) {
+		iobase = request_region(inta_addr[i], ITE_887x_IOSIZE,
+								"ite887x");
+		if (iobase != NULL) {
+			/* write POSIO0R - speed | size | ioport */
+			pci_write_config_dword(dev, ITE_887x_POSIO0,
+				ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED |
+				ITE_887x_POSIO_IOSIZE_32 | inta_addr[i]);
+			/* write INTCBAR - ioport */
+			pci_write_config_dword(dev, ITE_887x_INTCBAR, inta_addr[i]);
+			ret = inb(inta_addr[i]);
+			if (ret != 0xff) {
+				/* ioport connected */
+				break;
+			}
+			release_region(iobase->start, ITE_887x_IOSIZE);
+			iobase = NULL;
+		}
+		i++;
+	}
+
+	if (!inta_addr[i]) {
+		printk(KERN_ERR "ite887x: could not find iobase\n");
+		return -ENODEV;
+	}
+
+	/* start of undocumented type checking (see parport_pc.c) */
+	type = inb(iobase->start + 0x18) & 0x0f;
+
+	switch (type) {
+	case 0x2:	/* ITE8871 (1P) */
+	case 0xa:	/* ITE8875 (1P) */
+		ret = 0;
+		break;
+	case 0xe:	/* ITE8872 (2S1P) */
+		ret = 2;
+		break;
+	case 0x6:	/* ITE8873 (1S) */
+		ret = 1;
+		break;
+	case 0x8:	/* ITE8874 (2S) */
+		ret = 2;
+		break;
+	default:
+		moan_device("Unknown ITE887x", dev);
+		ret = -ENODEV;
+	}
+
+	/* configure all serial ports */
+	for (i = 0; i < ret; i++) {
+		/* read the I/O port from the device */
+		pci_read_config_dword(dev, ITE_887x_PS0BAR + (0x4 * (i + 1)),
+								&ioport);
+		ioport &= 0x0000FF00;	/* the actual base address */
+		pci_write_config_dword(dev, ITE_887x_POSIO0 + (0x4 * (i + 1)),
+			ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED |
+			ITE_887x_POSIO_IOSIZE_8 | ioport);
+
+		/* write the ioport to the UARTBAR */
+		pci_read_config_dword(dev, ITE_887x_UARTBAR, &uartbar);
+		uartbar &= ~(0xffff << (16 * i));	/* clear half the reg */
+		uartbar |= (ioport << (16 * i));	/* set the ioport */
+		pci_write_config_dword(dev, ITE_887x_UARTBAR, uartbar);
+
+		/* get current config */
+		pci_read_config_dword(dev, ITE_887x_MISCR, &miscr);
+		/* disable interrupts (UARTx_Routing[3:0]) */
+		miscr &= ~(0xf << (12 - 4 * i));
+		/* activate the UART (UARTx_En) */
+		miscr |= 1 << (23 - i);
+		/* write new config with activated UART */
+		pci_write_config_dword(dev, ITE_887x_MISCR, miscr);
+	}
+
+	if (ret <= 0) {
+		/* the device has no UARTs if we get here */
+		release_region(iobase->start, ITE_887x_IOSIZE);
+	}
+
+	return ret;
+}
+
+static void __devexit pci_ite887x_exit(struct pci_dev *dev)
+{
+	u32 ioport;
+	/* the ioport is bit 0-15 in POSIO0R */
+	pci_read_config_dword(dev, ITE_887x_POSIO0, &ioport);
+	ioport &= 0xffff;
+	release_region(ioport, ITE_887x_IOSIZE);
+}
+
 static int
 pci_default_setup(struct serial_private *priv, struct pciserial_board *board,
 		  struct uart_port *port, int idx)
@@ -653,6 +785,18 @@
 		.setup		= pci_default_setup,
 	},
 	/*
+	 * ITE
+	 */
+	{
+		.vendor		= PCI_VENDOR_ID_ITE,
+		.device		= PCI_DEVICE_ID_ITE_8872,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.init		= pci_ite887x_init,
+		.setup		= pci_default_setup,
+		.exit		= __devexit_p(pci_ite887x_exit),
+	},
+	/*
 	 * Panacom
 	 */
 	{
@@ -933,6 +1077,7 @@
 
 	pbn_b1_2_1250000,
 
+	pbn_b1_bt_1_115200,
 	pbn_b1_bt_2_921600,
 
 	pbn_b1_1_1382400,
@@ -976,7 +1121,6 @@
 	pbn_oxsemi,
 	pbn_intel_i960,
 	pbn_sgi_ioc3,
-	pbn_nec_nile4,
 	pbn_computone_4,
 	pbn_computone_6,
 	pbn_computone_8,
@@ -984,6 +1128,7 @@
 	pbn_exar_XR17C152,
 	pbn_exar_XR17C154,
 	pbn_exar_XR17C158,
+	pbn_pasemi_1682M,
 };
 
 /*
@@ -1212,6 +1357,13 @@
 		.uart_offset	= 8,
 	},
 
+	[pbn_b1_bt_1_115200] = {
+		.flags		= FL_BASE1|FL_BASE_BARS,
+		.num_ports	= 1,
+		.base_baud	= 115200,
+		.uart_offset	= 8,
+	},
+
 	[pbn_b1_bt_2_921600] = {
 		.flags		= FL_BASE1|FL_BASE_BARS,
 		.num_ports	= 2,
@@ -1443,18 +1595,6 @@
 	},
 
 	/*
-	 * NEC Vrc-5074 (Nile 4) builtin UART.
-	 */
-	[pbn_nec_nile4] = {
-		.flags		= FL_BASE0,
-		.num_ports	= 1,
-		.base_baud	= 520833,
-		.uart_offset	= 8 << 3,
-		.reg_shift	= 3,
-		.first_offset	= 0x300,
-	},
-
-	/*
 	 * Computone - uses IOMEM.
 	 */
 	[pbn_computone_4] = {
@@ -1511,6 +1651,18 @@
 		.base_baud	= 921600,
 		.uart_offset	= 0x200,
 	},
+	/*
+	 * PA Semi PWRficient PA6T-1682M on-chip UART
+	 */
+	[pbn_pasemi_1682M] = {
+		.flags		= FL_BASE0,
+		.num_ports	= 1,
+		.base_baud	= 8333333,
+	},
+};
+
+static const struct pci_device_id softmodem_blacklist[] = {
+	{ PCI_VDEVICE ( AL, 0x5457 ), }, /* ALi Corporation M5457 AC'97 Modem */
 };
 
 /*
@@ -1521,6 +1673,7 @@
 static int __devinit
 serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
 {
+	const struct pci_device_id *blacklist;
 	int num_iomem, num_port, first_port = -1, i;
 	
 	/*
@@ -1535,6 +1688,18 @@
 	    (dev->class & 0xff) > 6)
 		return -ENODEV;
 
+	/*
+	 * Do not access blacklisted devices that are known not to
+	 * feature serial ports.
+	 */
+	for (blacklist = softmodem_blacklist;
+	     blacklist < softmodem_blacklist + ARRAY_SIZE(softmodem_blacklist);
+	     blacklist++) {
+		if (dev->vendor == blacklist->vendor &&
+		    dev->device == blacklist->device)
+			return -ENODEV;
+	}
+
 	num_iomem = num_port = 0;
 	for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
 		if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
@@ -2345,13 +2510,6 @@
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 		pbn_b2_1_115200 },
 
-	/*
-	 * NEC Vrc-5074 (Nile 4) builtin UART.
-	 */
-	{	PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-		pbn_nec_nile4 },
-
 	{	PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM2,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 		pbn_b3_2_115200 },
@@ -2384,6 +2542,13 @@
 	{	PCI_VENDOR_ID_TOPIC, PCI_DEVICE_ID_TOPIC_TP560,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
 		pbn_b0_1_115200 },
+	/*
+	 * ITE
+	 */
+	{	PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8872,
+		PCI_ANY_ID, PCI_ANY_ID,
+		0, 0,
+		pbn_b1_bt_1_115200 },
 
 	/*
 	 * IntaShield IS-200
@@ -2402,6 +2567,13 @@
 		PCI_SUBVENDOR_ID_PERLE, PCI_SUBDEVICE_ID_PCI_RAS8,
 		0, 0, pbn_b2_8_921600 },
 	/*
+	 * PA Semi PA6T-1682M on-chip UART
+	 */
+	{	PCI_VENDOR_ID_PASEMI, 0xa004,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+		pbn_pasemi_1682M },
+
+	/*
 	 * These entries match devices with class COMMUNICATION_SERIAL,
 	 * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
 	 */
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 7fa413d..d6ae38e 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -88,21 +88,17 @@
 	depends on SERIAL_8250 && PCI
 	default SERIAL_8250
 	help
-	  Say Y here if you have PCI serial ports.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called 8250_pci.
+	  This builds standard PCI serial support. You may be able to
+	  disable this feature if you only need legacy serial support.
+	  Saves about 9K.
 
 config SERIAL_8250_PNP
 	tristate "8250/16550 PNP device support" if EMBEDDED
 	depends on SERIAL_8250 && PNP
 	default SERIAL_8250
 	help
-	  Say Y here if you have serial ports described by PNPBIOS or ACPI.
-	  These are typically ports built into the system board.
-
-	  To compile this driver as a module, choose M here: the module
-	  will be called 8250_pnp.
+	  This builds standard PNP serial support. You may be able to
+	  disable this feature if you only need legacy serial support.
 
 config SERIAL_8250_HP300
 	tristate
@@ -486,6 +482,36 @@
 
 	  If unsure, say Y.
 
+config SERIAL_ZS
+	tristate "DECstation Z85C30 serial support"
+	depends on MACH_DECSTATION
+	select SERIAL_CORE
+	default y
+	---help---
+	  Support for the Zilog 85C350 serial communications controller used
+	  for serial ports in newer DECstation systems.  These include the
+	  DECsystem 5900 and all models of the DECstation and DECsystem 5000
+	  systems except from model 200.
+
+	  If unsure, say Y.  To compile this driver as a module, choose M here:
+	  the module will be called zs.
+
+config SERIAL_ZS_CONSOLE
+	bool "Support for console on a DECstation Z85C30 serial port"
+	depends on SERIAL_ZS=y
+	select SERIAL_CORE_CONSOLE
+	default y
+	---help---
+	  If you say Y here, it will be possible to use a serial port as the
+	  system console (the system console is the device which receives all
+	  kernel messages and warnings and which allows logins in single user
+	  mode).
+
+	  Note that the firmware uses ttyS1 as the serial console on the
+	  Maxine and ttyS3 on the others using this driver.
+
+	  If unsure, say Y.
+
 config SERIAL_21285
 	tristate "DC21285 serial port support"
 	depends on ARM && FOOTBRIDGE
@@ -585,7 +611,7 @@
 
 config SERIAL_BFIN_CONSOLE
 	bool "Console on Blackfin serial port"
-	depends on SERIAL_BFIN
+	depends on SERIAL_BFIN=y
 	select SERIAL_CORE_CONSOLE
 
 choice
@@ -806,10 +832,10 @@
 	    4. Change the kernel command console parameter to: console=ttyB0
 
 config SERIAL_MUX_CONSOLE
-        bool "Support for console on serial MUX"
-        depends on SERIAL_MUX
+	bool "Support for console on serial MUX"
+	depends on SERIAL_MUX=y
 	select SERIAL_CORE_CONSOLE
-        default y
+	default y
 
 config PDC_CONSOLE
 	bool "PDC software console support"
@@ -960,6 +986,31 @@
 	  PowerMac machines.
 	  Say Y or M if you want to be able to these serial ports.
 
+config SERIAL_PMACZILOG_TTYS
+	bool "Use ttySn device nodes for Zilog z85c30"
+	depends on SERIAL_PMACZILOG
+	help
+	  The pmac_zilog driver for the z85C30 chip on many powermacs
+	  historically used the device numbers for /dev/ttySn.  The
+	  8250 serial port driver also uses these numbers, which means
+	  the two drivers being unable to coexist; you could not use
+	  both z85C30 and 8250 type ports at the same time.
+
+	  If this option is not selected, the pmac_zilog driver will
+	  use the device numbers allocated for /dev/ttyPZn.  This allows
+	  the pmac_zilog and 8250 drivers to co-exist, but may cause
+	  existing userspace setups to break.  Programs that need to
+	  access the built-in serial ports on powermacs will need to
+	  be reconfigured to use /dev/ttyPZn instead of /dev/ttySn.
+
+	  If you enable this option, any z85c30 ports in the system will
+	  be registered as ttyS0 onwards as in the past, and you will be
+	  unable to use the 8250 module for PCMCIA or other 16C550-style
+	  UARTs.
+
+	  Say N unless you need the z85c30 ports on your powermac
+	  to appear as /dev/ttySn.
+
 config SERIAL_PMACZILOG_CONSOLE
 	bool "Console on PowerMac z85c30 serial port"
 	depends on SERIAL_PMACZILOG=y
@@ -1165,7 +1216,7 @@
 
 config SERIAL_VR41XX_CONSOLE
 	bool "Enable NEC VR4100 series Serial Interface Unit console"
-	depends on SERIAL_VR41XX
+	depends on SERIAL_VR41XX=y
 	select SERIAL_CORE_CONSOLE
 	help
 	  If you have a NEC VR4100 series processor and you want to use
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index c48cdd6..af6377d 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -43,6 +43,7 @@
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
 obj-$(CONFIG_SERIAL_LH7A40X) += serial_lh7a40x.o
 obj-$(CONFIG_SERIAL_DZ) += dz.o
+obj-$(CONFIG_SERIAL_ZS) += zs.o
 obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
 obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
 obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index 954073c..72229df 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -716,7 +716,7 @@
 		goto out;
 	}
 
-	uap = kmalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
+	uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
 	if (uap == NULL) {
 		ret = -ENOMEM;
 		goto out;
@@ -728,7 +728,6 @@
 		goto free;
 	}
 
-	memset(uap, 0, sizeof(struct uart_amba_port));
 	uap->clk = clk_get(&dev->dev, "UARTCLK");
 	if (IS_ERR(uap->clk)) {
 		ret = PTR_ERR(uap->clk);
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 66c92bc..6f475b6 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -86,10 +86,8 @@
 {
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
 
-#ifdef CONFIG_BF54x
 	while (!(UART_GET_LSR(uart) & TEMT))
 		continue;
-#endif
 
 #ifdef CONFIG_SERIAL_BFIN_DMA
 	disable_dma(uart->tx_dma_channel);
@@ -128,8 +126,8 @@
 	ier = UART_GET_IER(uart);
 	ier |= ETBEI;
 	UART_PUT_IER(uart, ier);
-	bfin_serial_tx_chars(uart);
 #endif
+	bfin_serial_tx_chars(uart);
 #endif
 }
 
@@ -139,18 +137,21 @@
 static void bfin_serial_stop_rx(struct uart_port *port)
 {
 	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+#ifdef	CONFIG_KGDB_UART
+	if (uart->port.line != CONFIG_KGDB_UART_PORT) {
+#endif
 #ifdef CONFIG_BF54x
 	UART_CLEAR_IER(uart, ERBFI);
 #else
 	unsigned short ier;
 
 	ier = UART_GET_IER(uart);
-#ifdef	CONFIG_KGDB_UART
-	if (uart->port.line != CONFIG_KGDB_UART_PORT)
-#endif
 	ier &= ~ERBFI;
 	UART_PUT_IER(uart, ier);
 #endif
+#ifdef	CONFIG_KGDB_UART
+	}
+#endif
 }
 
 /*
@@ -173,12 +174,15 @@
 		uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
 	
 	while (!(UART_GET_LSR(uart) & THRE)) {
-		__builtin_bfin_ssync();
+		SSYNC();
 	}
+
+#ifndef CONFIG_BF54x
 	UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));
-	__builtin_bfin_ssync();
+	SSYNC();
+#endif
 	UART_PUT_CHAR(uart, (unsigned char)chr);
-	__builtin_bfin_ssync();
+	SSYNC();
 }
 
 int kgdb_get_debug_char(void)
@@ -192,12 +196,14 @@
 		uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
 	
 	while(!(UART_GET_LSR(uart) & DR)) {
-		__builtin_bfin_ssync();
+		SSYNC();
 	}
+#ifndef CONFIG_BF54x
 	UART_PUT_LCR(uart, UART_GET_LCR(uart)&(~DLAB));
-	__builtin_bfin_ssync();
+	SSYNC();
+#endif
 	chr = UART_GET_CHAR(uart);
-	__builtin_bfin_ssync();
+	SSYNC();
 
 	return chr;
 }
@@ -225,12 +231,10 @@
 {
 	struct tty_struct *tty = uart->port.info->tty;
 	unsigned int status, ch, flg;
+	static int in_break = 0;
 #ifdef CONFIG_KGDB_UART
 	struct pt_regs *regs = get_irq_regs();
 #endif
-#ifdef BF533_FAMILY
-	static int in_break = 0;
-#endif
 
 	status = UART_GET_LSR(uart);
  	ch = UART_GET_CHAR(uart);
@@ -256,29 +260,30 @@
 		}
 	}
 #endif
- 
-#ifdef BF533_FAMILY
-	/* The BF533 family of processors have a nice misbehavior where
-	 * they continuously generate characters for a "single" break.
-	 * We have to basically ignore this flood until the "next" valid
-	 * character comes across.  All other Blackfin families operate
-	 * properly though.
-	 */
-	if (in_break) {
-		if (ch != 0) {
-			in_break = 0;
-			ch = UART_GET_CHAR(uart);
-			if (bfin_revid() < 5)
+
+	if (ANOMALY_05000230) {
+		/* The BF533 family of processors have a nice misbehavior where
+		 * they continuously generate characters for a "single" break.
+		 * We have to basically ignore this flood until the "next" valid
+		 * character comes across.  All other Blackfin families operate
+		 * properly though.
+		 * Note: While Anomaly 05000230 does not directly address this,
+		 *       the changes that went in for it also fixed this issue.
+		 */
+		if (in_break) {
+			if (ch != 0) {
+				in_break = 0;
+				ch = UART_GET_CHAR(uart);
+				if (bfin_revid() < 5)
+					return;
+			} else
 				return;
-		} else
-			return;
+		}
 	}
-#endif
 
 	if (status & BI) {
-#ifdef BF533_FAMILY
-		in_break = 1;
-#endif
+		if (ANOMALY_05000230)
+			in_break = 1;
 		uart->port.icount.brk++;
 		if (uart_handle_break(&uart->port))
 			goto ignore_char;
@@ -697,17 +702,19 @@
 	uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
 	add_timer(&(uart->rx_dma_timer));
 #else
-# ifdef	CONFIG_KGDB_UART
-	if (uart->port.line != CONFIG_KGDB_UART_PORT && request_irq
-# else
-	if (request_irq
-# endif
-	    (uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
+	if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
 	     "BFIN_UART_RX", uart)) {
+# ifdef	CONFIG_KGDB_UART
+		if (uart->port.line != CONFIG_KGDB_UART_PORT) {
+# endif
 		printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
 		return -EBUSY;
+# ifdef	CONFIG_KGDB_UART
+		}
+# endif
 	}
 
+
 	if (request_irq
 	    (uart->port.irq+1, bfin_serial_tx_int, IRQF_DISABLED,
 	     "BFIN_UART_TX", uart)) {
@@ -962,30 +969,6 @@
 }
 
 #ifdef CONFIG_SERIAL_BFIN_CONSOLE
-static void bfin_serial_console_putchar(struct uart_port *port, int ch)
-{
-	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-	while (!(UART_GET_LSR(uart) & THRE))
-		barrier();
-	UART_PUT_CHAR(uart, ch);
-	SSYNC();
-}
-
-/*
- * Interrupts are disabled on entering
- */
-static void
-bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
-{
-	struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
-	int flags = 0;
-
-	spin_lock_irqsave(&uart->port.lock, flags);
-	uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
-	spin_unlock_irqrestore(&uart->port.lock, flags);
-
-}
-
 /*
  * If the port was already initialised (eg, by a boot loader),
  * try to determine the current setup.
@@ -1038,19 +1021,25 @@
 	}
 	pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits);
 }
+#endif
+
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
+static struct uart_driver bfin_serial_reg;
 
 static int __init
 bfin_serial_console_setup(struct console *co, char *options)
 {
 	struct bfin_serial_port *uart;
+# ifdef CONFIG_SERIAL_BFIN_CONSOLE
 	int baud = 57600;
 	int bits = 8;
 	int parity = 'n';
-#ifdef CONFIG_SERIAL_BFIN_CTSRTS
+#  ifdef CONFIG_SERIAL_BFIN_CTSRTS
 	int flow = 'r';
-#else
+#  else
 	int flow = 'n';
-#endif
+#  endif
+# endif
 
 	/*
 	 * Check whether an invalid uart number has been specified, and
@@ -1061,15 +1050,45 @@
 		co->index = 0;
 	uart = &bfin_serial_ports[co->index];
 
+# ifdef CONFIG_SERIAL_BFIN_CONSOLE
 	if (options)
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
 	else
 		bfin_serial_console_get_options(uart, &baud, &parity, &bits);
 
 	return uart_set_options(&uart->port, co, baud, parity, bits, flow);
+# else
+	return 0;
+# endif
+}
+#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||
+				 defined (CONFIG_EARLY_PRINTK) */
+
+#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+static void bfin_serial_console_putchar(struct uart_port *port, int ch)
+{
+	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+	while (!(UART_GET_LSR(uart) & THRE))
+		barrier();
+	UART_PUT_CHAR(uart, ch);
+	SSYNC();
 }
 
-static struct uart_driver bfin_serial_reg;
+/*
+ * Interrupts are disabled on entering
+ */
+static void
+bfin_serial_console_write(struct console *co, const char *s, unsigned int count)
+{
+	struct bfin_serial_port *uart = &bfin_serial_ports[co->index];
+	int flags = 0;
+
+	spin_lock_irqsave(&uart->port.lock, flags);
+	uart_console_write(&uart->port, s, count, bfin_serial_console_putchar);
+	spin_unlock_irqrestore(&uart->port.lock, flags);
+
+}
+
 static struct console bfin_serial_console = {
 	.name		= BFIN_SERIAL_NAME,
 	.write		= bfin_serial_console_write,
@@ -1095,7 +1114,64 @@
 #define BFIN_SERIAL_CONSOLE	&bfin_serial_console
 #else
 #define BFIN_SERIAL_CONSOLE	NULL
-#endif
+#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
+
+
+#ifdef CONFIG_EARLY_PRINTK
+static __init void early_serial_putc(struct uart_port *port, int ch)
+{
+	unsigned timeout = 0xffff;
+	struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+	while ((!(UART_GET_LSR(uart) & THRE)) && --timeout)
+		cpu_relax();
+	UART_PUT_CHAR(uart, ch);
+}
+
+static __init void early_serial_write(struct console *con, const char *s,
+					unsigned int n)
+{
+	struct bfin_serial_port *uart = &bfin_serial_ports[con->index];
+	unsigned int i;
+
+	for (i = 0; i < n; i++, s++) {
+		if (*s == '\n')
+			early_serial_putc(&uart->port, '\r');
+		early_serial_putc(&uart->port, *s);
+	}
+}
+
+static struct __init console bfin_early_serial_console = {
+	.name = "early_BFuart",
+	.write = early_serial_write,
+	.device = uart_console_device,
+	.flags = CON_PRINTBUFFER,
+	.setup = bfin_serial_console_setup,
+	.index = -1,
+	.data  = &bfin_serial_reg,
+};
+
+struct console __init *bfin_earlyserial_init(unsigned int port,
+						unsigned int cflag)
+{
+	struct bfin_serial_port *uart;
+	struct ktermios t;
+
+	if (port == -1 || port >= nr_ports)
+		port = 0;
+	bfin_serial_init_ports();
+	bfin_early_serial_console.index = port;
+	uart = &bfin_serial_ports[port];
+	t.c_cflag = cflag;
+	t.c_iflag = 0;
+	t.c_oflag = 0;
+	t.c_lflag = ICANON;
+	t.c_line = port;
+	bfin_serial_set_termios(&uart->port, &t, &t);
+	return &bfin_early_serial_console;
+}
+
+#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
 
 static struct uart_driver bfin_serial_reg = {
 	.owner			= THIS_MODULE,
@@ -1182,7 +1258,7 @@
 	int ret;
 #ifdef CONFIG_KGDB_UART
 	struct bfin_serial_port *uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-	struct termios t;
+	struct ktermios t;
 #endif
 
 	pr_info("Serial: Blackfin serial driver\n");
@@ -1199,11 +1275,15 @@
 	}
 #ifdef CONFIG_KGDB_UART
 	if (uart->port.cons->index != CONFIG_KGDB_UART_PORT) {
-		request_irq(uart->port.irq, bfin_serial_int,
+		request_irq(uart->port.irq, bfin_serial_rx_int,
 			IRQF_DISABLED, "BFIN_UART_RX", uart);
 		pr_info("Request irq for kgdb uart port\n");
+#ifdef CONFIG_BF54x
+		UART_SET_IER(uart, ERBFI);
+#else
 		UART_PUT_IER(uart, UART_GET_IER(uart) | ERBFI);
-		__builtin_bfin_ssync();
+#endif
+		SSYNC();
 		t.c_cflag = CS8|B57600;
 		t.c_iflag = 0;
 		t.c_oflag = 0;
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h
index a8f894c..32b9737 100644
--- a/drivers/serial/cpm_uart/cpm_uart.h
+++ b/drivers/serial/cpm_uart/cpm_uart.h
@@ -56,21 +56,21 @@
 	u16			rx_fifosize;
 	u16			tx_nrfifos;
 	u16			tx_fifosize;
-	smc_t			*smcp;
-	smc_uart_t		*smcup;
-	scc_t			*sccp;
-	scc_uart_t		*sccup;
-	volatile cbd_t		*rx_bd_base;
-	volatile cbd_t		*rx_cur;
-	volatile cbd_t		*tx_bd_base;
-	volatile cbd_t		*tx_cur;
+	smc_t __iomem		*smcp;
+	smc_uart_t __iomem	*smcup;
+	scc_t __iomem		*sccp;
+	scc_uart_t __iomem	*sccup;
+	cbd_t __iomem		*rx_bd_base;
+	cbd_t __iomem		*rx_cur;
+	cbd_t __iomem		*tx_bd_base;
+	cbd_t __iomem		*tx_cur;
 	unsigned char		*tx_buf;
 	unsigned char		*rx_buf;
 	u32			flags;
 	void			(*set_lineif)(struct uart_cpm_port *);
 	u8			brg;
 	uint			 dp_addr;
-	void			*mem_addr;
+	void 			*mem_addr;
 	dma_addr_t		 dma_addr;
 	u32			mem_size;
 	/* helpers */
@@ -80,14 +80,18 @@
 	int			is_portb;
 	/* wait on close if needed */
 	int 			wait_closing;
+	/* value to combine with opcode to form cpm command */
+	u32			command;
 };
 
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
 extern int cpm_uart_port_map[UART_NR];
+#endif
 extern int cpm_uart_nr;
 extern struct uart_cpm_port cpm_uart_ports[UART_NR];
 
 /* these are located in their respective files */
-void cpm_line_cr_cmd(int line, int cmd);
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd);
 int cpm_uart_init_portdesc(void);
 int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con);
 void cpm_uart_freebuf(struct uart_cpm_port *pinfo);
@@ -102,34 +106,36 @@
 /*
    virtual to phys transtalion
 */
-static inline unsigned long cpu2cpm_addr(void* addr, struct uart_cpm_port *pinfo)
+static inline unsigned long cpu2cpm_addr(void *addr,
+                                         struct uart_cpm_port *pinfo)
 {
 	int offset;
 	u32 val = (u32)addr;
+	u32 mem = (u32)pinfo->mem_addr;
 	/* sane check */
-	if (likely((val >= (u32)pinfo->mem_addr)) &&
-			(val<((u32)pinfo->mem_addr + pinfo->mem_size))) {
-		offset = val - (u32)pinfo->mem_addr;
-		return pinfo->dma_addr+offset;
+	if (likely(val >= mem && val < mem + pinfo->mem_size)) {
+		offset = val - mem;
+		return pinfo->dma_addr + offset;
 	}
 	/* something nasty happened */
 	BUG();
 	return 0;
 }
 
-static inline void *cpm2cpu_addr(unsigned long addr, struct uart_cpm_port *pinfo)
+static inline void *cpm2cpu_addr(unsigned long addr,
+                                 struct uart_cpm_port *pinfo)
 {
 	int offset;
 	u32 val = addr;
+	u32 dma = (u32)pinfo->dma_addr;
 	/* sane check */
-	if (likely((val >= pinfo->dma_addr) &&
-			(val<(pinfo->dma_addr + pinfo->mem_size)))) {
-		offset = val - (u32)pinfo->dma_addr;
-		return (void*)(pinfo->mem_addr+offset);
+	if (likely(val >= dma && val < dma + pinfo->mem_size)) {
+		offset = val - dma;
+		return pinfo->mem_addr + offset;
 	}
 	/* something nasty happened */
 	BUG();
-	return 0;
+	return NULL;
 }
 
 
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index cefde58..b5e4478 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -10,7 +10,7 @@
  *  Maintainer: Kumar Gala (galak@kernel.crashing.org) (CPM2)
  *              Pantelis Antoniou (panto@intracom.gr) (CPM1)
  *
- *  Copyright (C) 2004 Freescale Semiconductor, Inc.
+ *  Copyright (C) 2004, 2007 Freescale Semiconductor, Inc.
  *            (C) 2004 Intracom, S.A.
  *            (C) 2005-2006 MontaVista Software, Inc.
  * 		Vitaly Bordug <vbordug@ru.mvista.com>
@@ -47,6 +47,11 @@
 #include <asm/irq.h>
 #include <asm/delay.h>
 #include <asm/fs_pd.h>
+#include <asm/udbg.h>
+
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+#include <linux/of_platform.h>
+#endif
 
 #if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
@@ -57,12 +62,6 @@
 
 #include "cpm_uart.h"
 
-/***********************************************************************/
-
-/* Track which ports are configured as uarts */
-int cpm_uart_port_map[UART_NR];
-/* How many ports did we config as uarts */
-int cpm_uart_nr = 0;
 
 /**************************************************************/
 
@@ -73,6 +72,11 @@
 
 /**************************************************************/
 
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
+/* Track which ports are configured as uarts */
+int cpm_uart_port_map[UART_NR];
+/* How many ports did we config as uarts */
+int cpm_uart_nr;
 
 /* Place-holder for board-specific stuff */
 struct platform_device* __attribute__ ((weak)) __init
@@ -119,6 +123,7 @@
 	/* not found or invalid argument */
 	return -1;
 }
+#endif
 
 /*
  * Check, if transmit buffers are processed
@@ -126,14 +131,14 @@
 static unsigned int cpm_uart_tx_empty(struct uart_port *port)
 {
 	struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-	volatile cbd_t *bdp = pinfo->tx_bd_base;
+	cbd_t __iomem *bdp = pinfo->tx_bd_base;
 	int ret = 0;
 
 	while (1) {
-		if (bdp->cbd_sc & BD_SC_READY)
+		if (in_be16(&bdp->cbd_sc) & BD_SC_READY)
 			break;
 
-		if (bdp->cbd_sc & BD_SC_WRAP) {
+		if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP) {
 			ret = TIOCSER_TEMT;
 			break;
 		}
@@ -162,15 +167,15 @@
 static void cpm_uart_stop_tx(struct uart_port *port)
 {
 	struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-	volatile smc_t *smcp = pinfo->smcp;
-	volatile scc_t *sccp = pinfo->sccp;
+	smc_t __iomem *smcp = pinfo->smcp;
+	scc_t __iomem *sccp = pinfo->sccp;
 
 	pr_debug("CPM uart[%d]:stop tx\n", port->line);
 
 	if (IS_SMC(pinfo))
-		smcp->smc_smcm &= ~SMCM_TX;
+		clrbits8(&smcp->smc_smcm, SMCM_TX);
 	else
-		sccp->scc_sccm &= ~UART_SCCM_TX;
+		clrbits16(&sccp->scc_sccm, UART_SCCM_TX);
 }
 
 /*
@@ -179,24 +184,24 @@
 static void cpm_uart_start_tx(struct uart_port *port)
 {
 	struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-	volatile smc_t *smcp = pinfo->smcp;
-	volatile scc_t *sccp = pinfo->sccp;
+	smc_t __iomem *smcp = pinfo->smcp;
+	scc_t __iomem *sccp = pinfo->sccp;
 
 	pr_debug("CPM uart[%d]:start tx\n", port->line);
 
 	if (IS_SMC(pinfo)) {
-		if (smcp->smc_smcm & SMCM_TX)
+		if (in_8(&smcp->smc_smcm) & SMCM_TX)
 			return;
 	} else {
-		if (sccp->scc_sccm & UART_SCCM_TX)
+		if (in_be16(&sccp->scc_sccm) & UART_SCCM_TX)
 			return;
 	}
 
 	if (cpm_uart_tx_pump(port) != 0) {
 		if (IS_SMC(pinfo)) {
-			smcp->smc_smcm |= SMCM_TX;
+			setbits8(&smcp->smc_smcm, SMCM_TX);
 		} else {
-			sccp->scc_sccm |= UART_SCCM_TX;
+			setbits16(&sccp->scc_sccm, UART_SCCM_TX);
 		}
 	}
 }
@@ -207,15 +212,15 @@
 static void cpm_uart_stop_rx(struct uart_port *port)
 {
 	struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-	volatile smc_t *smcp = pinfo->smcp;
-	volatile scc_t *sccp = pinfo->sccp;
+	smc_t __iomem *smcp = pinfo->smcp;
+	scc_t __iomem *sccp = pinfo->sccp;
 
 	pr_debug("CPM uart[%d]:stop rx\n", port->line);
 
 	if (IS_SMC(pinfo))
-		smcp->smc_smcm &= ~SMCM_RX;
+		clrbits8(&smcp->smc_smcm, SMCM_RX);
 	else
-		sccp->scc_sccm &= ~UART_SCCM_RX;
+		clrbits16(&sccp->scc_sccm, UART_SCCM_RX);
 }
 
 /*
@@ -232,15 +237,14 @@
 static void cpm_uart_break_ctl(struct uart_port *port, int break_state)
 {
 	struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-	int line = pinfo - cpm_uart_ports;
 
 	pr_debug("CPM uart[%d]:break ctrl, break_state: %d\n", port->line,
 		break_state);
 
 	if (break_state)
-		cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
+		cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
 	else
-		cpm_line_cr_cmd(line, CPM_CR_RESTART_TX);
+		cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX);
 }
 
 /*
@@ -259,10 +263,11 @@
 static void cpm_uart_int_rx(struct uart_port *port)
 {
 	int i;
-	unsigned char ch, *cp;
+	unsigned char ch;
+	u8 *cp;
 	struct tty_struct *tty = port->info->tty;
 	struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-	volatile cbd_t *bdp;
+	cbd_t __iomem *bdp;
 	u16 status;
 	unsigned int flg;
 
@@ -274,13 +279,13 @@
 	bdp = pinfo->rx_cur;
 	for (;;) {
 		/* get status */
-		status = bdp->cbd_sc;
+		status = in_be16(&bdp->cbd_sc);
 		/* If this one is empty, return happy */
 		if (status & BD_SC_EMPTY)
 			break;
 
 		/* get number of characters, and check spce in flip-buffer */
-		i = bdp->cbd_datlen;
+		i = in_be16(&bdp->cbd_datlen);
 
 		/* If we have not enough room in tty flip buffer, then we try
 		 * later, which will be the next rx-interrupt or a timeout
@@ -291,7 +296,7 @@
 		}
 
 		/* get pointer */
-		cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
+		cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
 
 		/* loop through the buffer */
 		while (i-- > 0) {
@@ -311,10 +316,11 @@
 		}		/* End while (i--) */
 
 		/* This BD is ready to be used again. Clear status. get next */
-		bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID);
-		bdp->cbd_sc |= BD_SC_EMPTY;
+		clrbits16(&bdp->cbd_sc, BD_SC_BR | BD_SC_FR | BD_SC_PR |
+		                        BD_SC_OV | BD_SC_ID);
+		setbits16(&bdp->cbd_sc, BD_SC_EMPTY);
 
-		if (bdp->cbd_sc & BD_SC_WRAP)
+		if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
 			bdp = pinfo->rx_bd_base;
 		else
 			bdp++;
@@ -322,7 +328,7 @@
 	} /* End for (;;) */
 
 	/* Write back buffer pointer */
-	pinfo->rx_cur = (volatile cbd_t *) bdp;
+	pinfo->rx_cur = bdp;
 
 	/* activate BH processing */
 	tty_flip_buffer_push(tty);
@@ -376,14 +382,14 @@
 	u8 events;
 	struct uart_port *port = (struct uart_port *)data;
 	struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-	volatile smc_t *smcp = pinfo->smcp;
-	volatile scc_t *sccp = pinfo->sccp;
+	smc_t __iomem *smcp = pinfo->smcp;
+	scc_t __iomem *sccp = pinfo->sccp;
 
 	pr_debug("CPM uart[%d]:IRQ\n", port->line);
 
 	if (IS_SMC(pinfo)) {
-		events = smcp->smc_smce;
-		smcp->smc_smce = events;
+		events = in_8(&smcp->smc_smce);
+		out_8(&smcp->smc_smce, events);
 		if (events & SMCM_BRKE)
 			uart_handle_break(port);
 		if (events & SMCM_RX)
@@ -391,8 +397,8 @@
 		if (events & SMCM_TX)
 			cpm_uart_int_tx(port);
 	} else {
-		events = sccp->scc_scce;
-		sccp->scc_scce = events;
+		events = in_be16(&sccp->scc_scce);
+		out_be16(&sccp->scc_scce, events);
 		if (events & UART_SCCM_BRKE)
 			uart_handle_break(port);
 		if (events & UART_SCCM_RX)
@@ -407,7 +413,6 @@
 {
 	int retval;
 	struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-	int line = pinfo - cpm_uart_ports;
 
 	pr_debug("CPM uart[%d]:startup\n", port->line);
 
@@ -418,15 +423,15 @@
 
 	/* Startup rx-int */
 	if (IS_SMC(pinfo)) {
-		pinfo->smcp->smc_smcm |= SMCM_RX;
-		pinfo->smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
+		setbits8(&pinfo->smcp->smc_smcm, SMCM_RX);
+		setbits16(&pinfo->smcp->smc_smcmr, (SMCMR_REN | SMCMR_TEN));
 	} else {
-		pinfo->sccp->scc_sccm |= UART_SCCM_RX;
-		pinfo->sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+		setbits16(&pinfo->sccp->scc_sccm, UART_SCCM_RX);
+		setbits32(&pinfo->sccp->scc_gsmrl, (SCC_GSMRL_ENR | SCC_GSMRL_ENT));
 	}
 
 	if (!(pinfo->flags & FLAG_CONSOLE))
-		cpm_line_cr_cmd(line,CPM_CR_INIT_TRX);
+		cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
 	return 0;
 }
 
@@ -442,7 +447,6 @@
 static void cpm_uart_shutdown(struct uart_port *port)
 {
 	struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-	int line = pinfo - cpm_uart_ports;
 
 	pr_debug("CPM uart[%d]:shutdown\n", port->line);
 
@@ -462,20 +466,20 @@
 
 		/* Stop uarts */
 		if (IS_SMC(pinfo)) {
-			volatile smc_t *smcp = pinfo->smcp;
-			smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
-			smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
+			smc_t __iomem *smcp = pinfo->smcp;
+			clrbits16(&smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
+			clrbits8(&smcp->smc_smcm, SMCM_RX | SMCM_TX);
 		} else {
-			volatile scc_t *sccp = pinfo->sccp;
-			sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
-			sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
+			scc_t __iomem *sccp = pinfo->sccp;
+			clrbits32(&sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+			clrbits16(&sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
 		}
 
 		/* Shut them really down and reinit buffer descriptors */
 		if (IS_SMC(pinfo))
-			cpm_line_cr_cmd(line, CPM_CR_STOP_TX);
+			cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
 		else
-			cpm_line_cr_cmd(line, CPM_CR_GRA_STOP_TX);
+			cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX);
 
 		cpm_uart_initbd(pinfo);
 	}
@@ -490,8 +494,8 @@
 	u16 cval, scval, prev_mode;
 	int bits, sbits;
 	struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
-	volatile smc_t *smcp = pinfo->smcp;
-	volatile scc_t *sccp = pinfo->sccp;
+	smc_t __iomem *smcp = pinfo->smcp;
+	scc_t __iomem *sccp = pinfo->sccp;
 
 	pr_debug("CPM uart[%d]:set_termios\n", port->line);
 
@@ -586,16 +590,15 @@
 		 * enables, because we want to put them back if they were
 		 * present.
 		 */
-		prev_mode = smcp->smc_smcmr;
-		smcp->smc_smcmr = smcr_mk_clen(bits) | cval | SMCMR_SM_UART;
-		smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
+		prev_mode = in_be16(&smcp->smc_smcmr);
+		out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits) | cval | SMCMR_SM_UART);
+		setbits16(&smcp->smc_smcmr, (prev_mode & (SMCMR_REN | SMCMR_TEN)));
 	} else {
-		sccp->scc_psmr = (sbits << 12) | scval;
+		out_be16(&sccp->scc_psmr, (sbits << 12) | scval);
 	}
 
 	cpm_set_brg(pinfo->brg - 1, baud);
 	spin_unlock_irqrestore(&port->lock, flags);
-
 }
 
 static const char *cpm_uart_type(struct uart_port *port)
@@ -629,8 +632,8 @@
  */
 static int cpm_uart_tx_pump(struct uart_port *port)
 {
-	volatile cbd_t *bdp;
-	unsigned char *p;
+	cbd_t __iomem *bdp;
+	u8 *p;
 	int count;
 	struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
 	struct circ_buf *xmit = &port->info->xmit;
@@ -640,13 +643,14 @@
 		/* Pick next descriptor and fill from buffer */
 		bdp = pinfo->tx_cur;
 
-		p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
+		p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
 
 		*p++ = port->x_char;
-		bdp->cbd_datlen = 1;
-		bdp->cbd_sc |= BD_SC_READY;
+
+		out_be16(&bdp->cbd_datlen, 1);
+		setbits16(&bdp->cbd_sc, BD_SC_READY);
 		/* Get next BD. */
-		if (bdp->cbd_sc & BD_SC_WRAP)
+		if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
 			bdp = pinfo->tx_bd_base;
 		else
 			bdp++;
@@ -665,9 +669,10 @@
 	/* Pick next descriptor and fill from buffer */
 	bdp = pinfo->tx_cur;
 
-	while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) {
+	while (!(in_be16(&bdp->cbd_sc) & BD_SC_READY) &&
+	       xmit->tail != xmit->head) {
 		count = 0;
-		p = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
+		p = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
 		while (count < pinfo->tx_fifosize) {
 			*p++ = xmit->buf[xmit->tail];
 			xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
@@ -676,11 +681,10 @@
 			if (xmit->head == xmit->tail)
 				break;
 		}
-		bdp->cbd_datlen = count;
-		bdp->cbd_sc |= BD_SC_READY;
-		eieio();
+		out_be16(&bdp->cbd_datlen, count);
+		setbits16(&bdp->cbd_sc, BD_SC_READY);
 		/* Get next BD. */
-		if (bdp->cbd_sc & BD_SC_WRAP)
+		if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
 			bdp = pinfo->tx_bd_base;
 		else
 			bdp++;
@@ -705,7 +709,7 @@
 {
 	int i;
 	u8 *mem_addr;
-	volatile cbd_t *bdp;
+	cbd_t __iomem *bdp;
 
 	pr_debug("CPM uart[%d]:initbd\n", pinfo->port.line);
 
@@ -716,13 +720,13 @@
 	mem_addr = pinfo->mem_addr;
 	bdp = pinfo->rx_cur = pinfo->rx_bd_base;
 	for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) {
-		bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
-		bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT;
+		out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+		out_be16(&bdp->cbd_sc, BD_SC_EMPTY | BD_SC_INTRPT);
 		mem_addr += pinfo->rx_fifosize;
 	}
 
-	bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
-	bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
+	out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+	out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT);
 
 	/* Set the physical address of the host memory
 	 * buffers in the buffer descriptors, and the
@@ -731,20 +735,19 @@
 	mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize);
 	bdp = pinfo->tx_cur = pinfo->tx_bd_base;
 	for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) {
-		bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
-		bdp->cbd_sc = BD_SC_INTRPT;
+		out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+		out_be16(&bdp->cbd_sc, BD_SC_INTRPT);
 		mem_addr += pinfo->tx_fifosize;
 	}
 
-	bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr, pinfo);
-	bdp->cbd_sc = BD_SC_WRAP | BD_SC_INTRPT;
+	out_be32(&bdp->cbd_bufaddr, cpu2cpm_addr(mem_addr, pinfo));
+	out_be16(&bdp->cbd_sc, BD_SC_WRAP | BD_SC_INTRPT);
 }
 
 static void cpm_uart_init_scc(struct uart_cpm_port *pinfo)
 {
-	int line = pinfo - cpm_uart_ports;
-	volatile scc_t *scp;
-	volatile scc_uart_t *sup;
+	scc_t __iomem *scp;
+	scc_uart_t __iomem *sup;
 
 	pr_debug("CPM uart[%d]:init_scc\n", pinfo->port.line);
 
@@ -752,8 +755,10 @@
 	sup = pinfo->sccup;
 
 	/* Store address */
-	pinfo->sccup->scc_genscc.scc_rbase = (unsigned char *)pinfo->rx_bd_base - DPRAM_BASE;
-	pinfo->sccup->scc_genscc.scc_tbase = (unsigned char *)pinfo->tx_bd_base - DPRAM_BASE;
+	out_be16(&pinfo->sccup->scc_genscc.scc_rbase,
+	         (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE);
+	out_be16(&pinfo->sccup->scc_genscc.scc_tbase,
+	         (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
 
 	/* Set up the uart parameters in the
 	 * parameter ram.
@@ -761,51 +766,50 @@
 
 	cpm_set_scc_fcr(sup);
 
-	sup->scc_genscc.scc_mrblr = pinfo->rx_fifosize;
-	sup->scc_maxidl = pinfo->rx_fifosize;
-	sup->scc_brkcr = 1;
-	sup->scc_parec = 0;
-	sup->scc_frmec = 0;
-	sup->scc_nosec = 0;
-	sup->scc_brkec = 0;
-	sup->scc_uaddr1 = 0;
-	sup->scc_uaddr2 = 0;
-	sup->scc_toseq = 0;
-	sup->scc_char1 = 0x8000;
-	sup->scc_char2 = 0x8000;
-	sup->scc_char3 = 0x8000;
-	sup->scc_char4 = 0x8000;
-	sup->scc_char5 = 0x8000;
-	sup->scc_char6 = 0x8000;
-	sup->scc_char7 = 0x8000;
-	sup->scc_char8 = 0x8000;
-	sup->scc_rccm = 0xc0ff;
+	out_be16(&sup->scc_genscc.scc_mrblr, pinfo->rx_fifosize);
+	out_be16(&sup->scc_maxidl, pinfo->rx_fifosize);
+	out_be16(&sup->scc_brkcr, 1);
+	out_be16(&sup->scc_parec, 0);
+	out_be16(&sup->scc_frmec, 0);
+	out_be16(&sup->scc_nosec, 0);
+	out_be16(&sup->scc_brkec, 0);
+	out_be16(&sup->scc_uaddr1, 0);
+	out_be16(&sup->scc_uaddr2, 0);
+	out_be16(&sup->scc_toseq, 0);
+	out_be16(&sup->scc_char1, 0x8000);
+	out_be16(&sup->scc_char2, 0x8000);
+	out_be16(&sup->scc_char3, 0x8000);
+	out_be16(&sup->scc_char4, 0x8000);
+	out_be16(&sup->scc_char5, 0x8000);
+	out_be16(&sup->scc_char6, 0x8000);
+	out_be16(&sup->scc_char7, 0x8000);
+	out_be16(&sup->scc_char8, 0x8000);
+	out_be16(&sup->scc_rccm, 0xc0ff);
 
 	/* Send the CPM an initialize command.
 	 */
-	cpm_line_cr_cmd(line, CPM_CR_INIT_TRX);
+	cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
 
 	/* Set UART mode, 8 bit, no parity, one stop.
 	 * Enable receive and transmit.
 	 */
-	scp->scc_gsmrh = 0;
-	scp->scc_gsmrl =
-	    (SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+	out_be32(&scp->scc_gsmrh, 0);
+	out_be32(&scp->scc_gsmrl,
+	         SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
 
 	/* Enable rx interrupts  and clear all pending events.  */
-	scp->scc_sccm = 0;
-	scp->scc_scce = 0xffff;
-	scp->scc_dsr = 0x7e7e;
-	scp->scc_psmr = 0x3000;
+	out_be16(&scp->scc_sccm, 0);
+	out_be16(&scp->scc_scce, 0xffff);
+	out_be16(&scp->scc_dsr, 0x7e7e);
+	out_be16(&scp->scc_psmr, 0x3000);
 
-	scp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+	setbits32(&scp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
 }
 
 static void cpm_uart_init_smc(struct uart_cpm_port *pinfo)
 {
-	int line = pinfo - cpm_uart_ports;
-	volatile smc_t *sp;
-	volatile smc_uart_t *up;
+	smc_t __iomem *sp;
+	smc_uart_t __iomem *up;
 
 	pr_debug("CPM uart[%d]:init_smc\n", pinfo->port.line);
 
@@ -813,19 +817,21 @@
 	up = pinfo->smcup;
 
 	/* Store address */
-	pinfo->smcup->smc_rbase = (u_char *)pinfo->rx_bd_base - DPRAM_BASE;
-	pinfo->smcup->smc_tbase = (u_char *)pinfo->tx_bd_base - DPRAM_BASE;
+	out_be16(&pinfo->smcup->smc_rbase,
+	         (u8 __iomem *)pinfo->rx_bd_base - DPRAM_BASE);
+	out_be16(&pinfo->smcup->smc_tbase,
+	         (u8 __iomem *)pinfo->tx_bd_base - DPRAM_BASE);
 
 /*
  *  In case SMC1 is being relocated...
  */
 #if defined (CONFIG_I2C_SPI_SMC1_UCODE_PATCH)
-	up->smc_rbptr = pinfo->smcup->smc_rbase;
-	up->smc_tbptr = pinfo->smcup->smc_tbase;
-	up->smc_rstate = 0;
-	up->smc_tstate = 0;
-	up->smc_brkcr = 1;              /* number of break chars */
-	up->smc_brkec = 0;
+	out_be16(&up->smc_rbptr, in_be16(&pinfo->smcup->smc_rbase));
+	out_be16(&up->smc_tbptr, in_be16(&pinfo->smcup->smc_tbase));
+	out_be32(&up->smc_rstate, 0);
+	out_be32(&up->smc_tstate, 0);
+	out_be16(&up->smc_brkcr, 1);              /* number of break chars */
+	out_be16(&up->smc_brkec, 0);
 #endif
 
 	/* Set up the uart parameters in the
@@ -834,24 +840,24 @@
 	cpm_set_smc_fcr(up);
 
 	/* Using idle charater time requires some additional tuning.  */
-	up->smc_mrblr = pinfo->rx_fifosize;
-	up->smc_maxidl = pinfo->rx_fifosize;
-	up->smc_brklen = 0;
-	up->smc_brkec = 0;
-	up->smc_brkcr = 1;
+	out_be16(&up->smc_mrblr, pinfo->rx_fifosize);
+	out_be16(&up->smc_maxidl, pinfo->rx_fifosize);
+	out_be16(&up->smc_brklen, 0);
+	out_be16(&up->smc_brkec, 0);
+	out_be16(&up->smc_brkcr, 1);
 
-	cpm_line_cr_cmd(line, CPM_CR_INIT_TRX);
+	cpm_line_cr_cmd(pinfo, CPM_CR_INIT_TRX);
 
 	/* Set UART mode, 8 bit, no parity, one stop.
 	 * Enable receive and transmit.
 	 */
-	sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
+	out_be16(&sp->smc_smcmr, smcr_mk_clen(9) | SMCMR_SM_UART);
 
 	/* Enable only rx interrupts clear all pending events. */
-	sp->smc_smcm = 0;
-	sp->smc_smce = 0xff;
+	out_8(&sp->smc_smcm, 0);
+	out_8(&sp->smc_smce, 0xff);
 
-	sp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
+	setbits16(&sp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
 }
 
 /*
@@ -869,11 +875,11 @@
 		return 0;
 
 	if (IS_SMC(pinfo)) {
-		pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
-		pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+		clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX);
+		clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
 	} else {
-		pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
-		pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+		clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
+		clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
 	}
 
 	ret = cpm_uart_allocbuf(pinfo, 0);
@@ -929,6 +935,86 @@
 	.verify_port	= cpm_uart_verify_port,
 };
 
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+struct uart_cpm_port cpm_uart_ports[UART_NR];
+
+static int cpm_uart_init_port(struct device_node *np,
+                              struct uart_cpm_port *pinfo)
+{
+	const u32 *data;
+	void __iomem *mem, *pram;
+	int len;
+	int ret;
+
+	data = of_get_property(np, "fsl,cpm-brg", &len);
+	if (!data || len != 4) {
+		printk(KERN_ERR "CPM UART %s has no/invalid "
+		                "fsl,cpm-brg property.\n", np->name);
+		return -EINVAL;
+	}
+	pinfo->brg = *data;
+
+	data = of_get_property(np, "fsl,cpm-command", &len);
+	if (!data || len != 4) {
+		printk(KERN_ERR "CPM UART %s has no/invalid "
+		                "fsl,cpm-command property.\n", np->name);
+		return -EINVAL;
+	}
+	pinfo->command = *data;
+
+	mem = of_iomap(np, 0);
+	if (!mem)
+		return -ENOMEM;
+
+	pram = of_iomap(np, 1);
+	if (!pram) {
+		ret = -ENOMEM;
+		goto out_mem;
+	}
+
+	if (of_device_is_compatible(np, "fsl,cpm1-scc-uart") ||
+	    of_device_is_compatible(np, "fsl,cpm2-scc-uart")) {
+		pinfo->sccp = mem;
+		pinfo->sccup = pram;
+	} else if (of_device_is_compatible(np, "fsl,cpm1-smc-uart") ||
+	           of_device_is_compatible(np, "fsl,cpm2-smc-uart")) {
+		pinfo->flags |= FLAG_SMC;
+		pinfo->smcp = mem;
+		pinfo->smcup = pram;
+	} else {
+		ret = -ENODEV;
+		goto out_pram;
+	}
+
+	pinfo->tx_nrfifos = TX_NUM_FIFO;
+	pinfo->tx_fifosize = TX_BUF_SIZE;
+	pinfo->rx_nrfifos = RX_NUM_FIFO;
+	pinfo->rx_fifosize = RX_BUF_SIZE;
+
+	pinfo->port.uartclk = ppc_proc_freq;
+	pinfo->port.mapbase = (unsigned long)mem;
+	pinfo->port.type = PORT_CPM;
+	pinfo->port.ops = &cpm_uart_pops,
+	pinfo->port.iotype = UPIO_MEM;
+	spin_lock_init(&pinfo->port.lock);
+
+	pinfo->port.irq = of_irq_to_resource(np, 0, NULL);
+	if (pinfo->port.irq == NO_IRQ) {
+		ret = -EINVAL;
+		goto out_pram;
+	}
+
+	return cpm_uart_request_port(&pinfo->port);
+
+out_pram:
+	iounmap(pram);
+out_mem:
+	iounmap(mem);
+	return ret;
+}
+
+#else
+
 struct uart_cpm_port cpm_uart_ports[UART_NR] = {
 	[UART_SMC1] = {
 		.port = {
@@ -1072,6 +1158,7 @@
 
 	return 0;
 }
+#endif
 
 #ifdef CONFIG_SERIAL_CPM_CONSOLE
 /*
@@ -1083,11 +1170,15 @@
 static void cpm_uart_console_write(struct console *co, const char *s,
 				   u_int count)
 {
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+	struct uart_cpm_port *pinfo = &cpm_uart_ports[co->index];
+#else
 	struct uart_cpm_port *pinfo =
 	    &cpm_uart_ports[cpm_uart_port_map[co->index]];
+#endif
 	unsigned int i;
-	volatile cbd_t *bdp, *bdbase;
-	volatile unsigned char *cp;
+	cbd_t __iomem *bdp, *bdbase;
+	unsigned char *cp;
 
 	/* Get the address of the host memory buffer.
 	 */
@@ -1105,37 +1196,36 @@
 		 * Ready indicates output is ready, and xmt is doing
 		 * that, not that it is ready for us to send.
 		 */
-		while ((bdp->cbd_sc & BD_SC_READY) != 0)
+		while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
 			;
 
 		/* Send the character out.
 		 * If the buffer address is in the CPM DPRAM, don't
 		 * convert it.
 		 */
-		cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
-
+		cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
 		*cp = *s;
 
-		bdp->cbd_datlen = 1;
-		bdp->cbd_sc |= BD_SC_READY;
+		out_be16(&bdp->cbd_datlen, 1);
+		setbits16(&bdp->cbd_sc, BD_SC_READY);
 
-		if (bdp->cbd_sc & BD_SC_WRAP)
+		if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
 			bdp = bdbase;
 		else
 			bdp++;
 
 		/* if a LF, also do CR... */
 		if (*s == 10) {
-			while ((bdp->cbd_sc & BD_SC_READY) != 0)
+			while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
 				;
 
-			cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
-
+			cp = cpm2cpu_addr(in_be32(&bdp->cbd_bufaddr), pinfo);
 			*cp = 13;
-			bdp->cbd_datlen = 1;
-			bdp->cbd_sc |= BD_SC_READY;
 
-			if (bdp->cbd_sc & BD_SC_WRAP)
+			out_be16(&bdp->cbd_datlen, 1);
+			setbits16(&bdp->cbd_sc, BD_SC_READY);
+
+			if (in_be16(&bdp->cbd_sc) & BD_SC_WRAP)
 				bdp = bdbase;
 			else
 				bdp++;
@@ -1146,22 +1236,56 @@
 	 * Finally, Wait for transmitter & holding register to empty
 	 *  and restore the IER
 	 */
-	while ((bdp->cbd_sc & BD_SC_READY) != 0)
+	while ((in_be16(&bdp->cbd_sc) & BD_SC_READY) != 0)
 		;
 
-	pinfo->tx_cur = (volatile cbd_t *) bdp;
+	pinfo->tx_cur = bdp;
 }
 
 
 static int __init cpm_uart_console_setup(struct console *co, char *options)
 {
-	struct uart_port *port;
-	struct uart_cpm_port *pinfo;
 	int baud = 38400;
 	int bits = 8;
 	int parity = 'n';
 	int flow = 'n';
 	int ret;
+	struct uart_cpm_port *pinfo;
+	struct uart_port *port;
+
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+	struct device_node *np = NULL;
+	int i = 0;
+
+	if (co->index >= UART_NR) {
+		printk(KERN_ERR "cpm_uart: console index %d too high\n",
+		       co->index);
+		return -ENODEV;
+	}
+
+	do {
+		np = of_find_node_by_type(np, "serial");
+		if (!np)
+			return -ENODEV;
+
+		if (!of_device_is_compatible(np, "fsl,cpm1-smc-uart") &&
+		    !of_device_is_compatible(np, "fsl,cpm1-scc-uart") &&
+		    !of_device_is_compatible(np, "fsl,cpm2-smc-uart") &&
+		    !of_device_is_compatible(np, "fsl,cpm2-scc-uart"))
+			i--;
+	} while (i++ != co->index);
+
+	pinfo = &cpm_uart_ports[co->index];
+
+	pinfo->flags |= FLAG_CONSOLE;
+	port = &pinfo->port;
+
+	ret = cpm_uart_init_port(np, pinfo);
+	of_node_put(np);
+	if (ret)
+		return ret;
+
+#else
 
 	struct fs_uart_platform_info *pdata;
 	struct platform_device* pdev = early_uart_get_pdev(co->index);
@@ -1188,6 +1312,7 @@
 	}
 
 	pinfo->flags |= FLAG_CONSOLE;
+#endif
 
 	if (options) {
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -1196,12 +1321,18 @@
 			baud = 9600;
 	}
 
+#ifdef CONFIG_PPC_EARLY_DEBUG_CPM
+	udbg_putc = NULL;
+#endif
+
+	cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
+
 	if (IS_SMC(pinfo)) {
-		pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
-		pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+		clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX);
+		clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
 	} else {
-		pinfo->sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
-		pinfo->sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+		clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
+		clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
 	}
 
 	ret = cpm_uart_allocbuf(pinfo, 1);
@@ -1217,6 +1348,7 @@
 		cpm_uart_init_scc(pinfo);
 
 	uart_set_options(port, co, baud, parity, bits, flow);
+	cpm_line_cr_cmd(pinfo, CPM_CR_RESTART_TX);
 
 	return 0;
 }
@@ -1232,7 +1364,7 @@
 	.data		= &cpm_reg,
 };
 
-int __init cpm_uart_console_init(void)
+static int __init cpm_uart_console_init(void)
 {
 	register_console(&cpm_scc_uart_console);
 	return 0;
@@ -1252,7 +1384,81 @@
 	.major		= SERIAL_CPM_MAJOR,
 	.minor		= SERIAL_CPM_MINOR,
 	.cons		= CPM_UART_CONSOLE,
+	.nr		= UART_NR,
 };
+
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+static int probe_index;
+
+static int __devinit cpm_uart_probe(struct of_device *ofdev,
+                                    const struct of_device_id *match)
+{
+	int index = probe_index++;
+	struct uart_cpm_port *pinfo = &cpm_uart_ports[index];
+	int ret;
+
+	pinfo->port.line = index;
+
+	if (index >= UART_NR)
+		return -ENODEV;
+
+	dev_set_drvdata(&ofdev->dev, pinfo);
+
+	ret = cpm_uart_init_port(ofdev->node, pinfo);
+	if (ret)
+		return ret;
+
+	return uart_add_one_port(&cpm_reg, &pinfo->port);
+}
+
+static int __devexit cpm_uart_remove(struct of_device *ofdev)
+{
+	struct uart_cpm_port *pinfo = dev_get_drvdata(&ofdev->dev);
+	return uart_remove_one_port(&cpm_reg, &pinfo->port);
+}
+
+static struct of_device_id cpm_uart_match[] = {
+	{
+		.compatible = "fsl,cpm1-smc-uart",
+	},
+	{
+		.compatible = "fsl,cpm1-scc-uart",
+	},
+	{
+		.compatible = "fsl,cpm2-smc-uart",
+	},
+	{
+		.compatible = "fsl,cpm2-scc-uart",
+	},
+	{}
+};
+
+static struct of_platform_driver cpm_uart_driver = {
+	.name = "cpm_uart",
+	.match_table = cpm_uart_match,
+	.probe = cpm_uart_probe,
+	.remove = cpm_uart_remove,
+ };
+
+static int __init cpm_uart_init(void)
+{
+	int ret = uart_register_driver(&cpm_reg);
+	if (ret)
+		return ret;
+
+	ret = of_register_platform_driver(&cpm_uart_driver);
+	if (ret)
+		uart_unregister_driver(&cpm_reg);
+
+	return ret;
+}
+
+static void __exit cpm_uart_exit(void)
+{
+	of_unregister_platform_driver(&cpm_uart_driver);
+	uart_unregister_driver(&cpm_reg);
+}
+#else
 static int cpm_uart_drv_probe(struct device *dev)
 {
 	struct platform_device  *pdev = to_platform_device(dev);
@@ -1380,6 +1586,7 @@
 	driver_unregister(&cpm_smc_uart_driver);
 	uart_unregister_driver(&cpm_reg);
 }
+#endif
 
 module_init(cpm_uart_init);
 module_exit(cpm_uart_exit);
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
index 8c6324e..52fb044 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
@@ -49,9 +49,20 @@
 
 /**************************************************************/
 
-void cpm_line_cr_cmd(int line, int cmd)
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
+{
+	u16 __iomem *cpcr = &cpmp->cp_cpcr;
+
+	out_be16(cpcr, port->command | (cmd << 8) | CPM_CR_FLG);
+	while (in_be16(cpcr) & CPM_CR_FLG)
+		;
+}
+#else
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
 {
 	ushort val;
+	int line = port - cpm_uart_ports;
 	volatile cpm8xx_t *cp = cpmp;
 
 	switch (line) {
@@ -114,6 +125,7 @@
 	/* XXX SCC4: insert port configuration here */
 	pinfo->brg = 4;
 }
+#endif
 
 /*
  * Allocate DP-Ram and memory buffers. We need to allocate a transmit and
@@ -167,7 +179,7 @@
 	pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
 						       * pinfo->rx_fifosize);
 
-	pinfo->rx_bd_base = (volatile cbd_t *)dp_mem;
+	pinfo->rx_bd_base = (cbd_t __iomem __force *)dp_mem;
 	pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
 
 	return 0;
@@ -184,6 +196,7 @@
 	cpm_dpfree(pinfo->dp_addr);
 }
 
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
 /* Setup any dynamic params in the uart desc */
 int cpm_uart_init_portdesc(void)
 {
@@ -279,3 +292,4 @@
 #endif
 	return 0;
 }
+#endif
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
index a99e45e..9b5465f 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
@@ -13,30 +13,32 @@
 #include <asm/commproc.h>
 
 /* defines for IRQs */
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
 #define SMC1_IRQ	(CPM_IRQ_OFFSET + CPMVEC_SMC1)
 #define SMC2_IRQ	(CPM_IRQ_OFFSET + CPMVEC_SMC2)
 #define SCC1_IRQ	(CPM_IRQ_OFFSET + CPMVEC_SCC1)
 #define SCC2_IRQ	(CPM_IRQ_OFFSET + CPMVEC_SCC2)
 #define SCC3_IRQ	(CPM_IRQ_OFFSET + CPMVEC_SCC3)
 #define SCC4_IRQ	(CPM_IRQ_OFFSET + CPMVEC_SCC4)
+#endif
 
 static inline void cpm_set_brg(int brg, int baud)
 {
 	cpm_setbrg(brg, baud);
 }
 
-static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup)
+static inline void cpm_set_scc_fcr(scc_uart_t __iomem * sup)
 {
-	sup->scc_genscc.scc_rfcr = SMC_EB;
-	sup->scc_genscc.scc_tfcr = SMC_EB;
+	out_8(&sup->scc_genscc.scc_rfcr, SMC_EB);
+	out_8(&sup->scc_genscc.scc_tfcr, SMC_EB);
 }
 
-static inline void cpm_set_smc_fcr(volatile smc_uart_t * up)
+static inline void cpm_set_smc_fcr(smc_uart_t __iomem * up)
 {
-	up->smc_rfcr = SMC_EB;
-	up->smc_tfcr = SMC_EB;
+	out_8(&up->smc_rfcr, SMC_EB);
+	out_8(&up->smc_tfcr, SMC_EB);
 }
 
-#define DPRAM_BASE	((unsigned char *)&cpmp->cp_dpmem[0])
+#define DPRAM_BASE	((u8 __iomem __force *)cpm_dpram_addr(0))
 
 #endif
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
index 7b61d80..882dbc1 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -49,9 +49,22 @@
 
 /**************************************************************/
 
-void cpm_line_cr_cmd(int line, int cmd)
+#ifdef CONFIG_PPC_CPM_NEW_BINDING
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
+{
+	cpm_cpm2_t __iomem *cp = cpm2_map(im_cpm);
+
+	out_be32(&cp->cp_cpcr, port->command | cmd | CPM_CR_FLG);
+	while (in_be32(&cp->cp_cpcr) & CPM_CR_FLG)
+		;
+
+	cpm2_unmap(cp);
+}
+#else
+void cpm_line_cr_cmd(struct uart_cpm_port *port, int cmd)
 {
 	ulong val;
+	int line = port - cpm_uart_ports;
 	volatile cpm_cpm2_t *cp = cpm2_map(im_cpm);
 
 
@@ -211,6 +224,7 @@
 	cpm2_unmap(cpmux);
 	cpm2_unmap(io);
 }
+#endif
 
 /*
  * Allocate DP-Ram and memory buffers. We need to allocate a transmit and 
@@ -221,7 +235,7 @@
 int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
 {
 	int dpmemsz, memsz;
-	u8 *dp_mem;
+	u8 __iomem *dp_mem;
 	unsigned long dp_offset;
 	u8 *mem_addr;
 	dma_addr_t dma_addr = 0;
@@ -264,7 +278,7 @@
 	pinfo->tx_buf = pinfo->rx_buf + L1_CACHE_ALIGN(pinfo->rx_nrfifos
 						       * pinfo->rx_fifosize);
 
-	pinfo->rx_bd_base = (volatile cbd_t *)dp_mem;
+	pinfo->rx_bd_base = (cbd_t __iomem *)dp_mem;
 	pinfo->tx_bd_base = pinfo->rx_bd_base + pinfo->rx_nrfifos;
 
 	return 0;
@@ -275,12 +289,13 @@
 	dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
 					       pinfo->rx_fifosize) +
 			  L1_CACHE_ALIGN(pinfo->tx_nrfifos *
-					 pinfo->tx_fifosize), pinfo->mem_addr,
+					 pinfo->tx_fifosize), (void __force *)pinfo->mem_addr,
 			  pinfo->dma_addr);
 
 	cpm_dpfree(pinfo->dp_addr);
 }
 
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
 /* Setup any dynamic params in the uart desc */
 int cpm_uart_init_portdesc(void)
 {
@@ -386,3 +401,4 @@
 
 	return 0;
 }
+#endif
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
index 1b3219f..40006a7 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
@@ -13,30 +13,32 @@
 #include <asm/cpm2.h>
 
 /* defines for IRQs */
+#ifndef CONFIG_PPC_CPM_NEW_BINDING
 #define SMC1_IRQ	SIU_INT_SMC1
 #define SMC2_IRQ	SIU_INT_SMC2
 #define SCC1_IRQ	SIU_INT_SCC1
 #define SCC2_IRQ	SIU_INT_SCC2
 #define SCC3_IRQ	SIU_INT_SCC3
 #define SCC4_IRQ	SIU_INT_SCC4
+#endif
 
 static inline void cpm_set_brg(int brg, int baud)
 {
 	cpm_setbrg(brg, baud);
 }
 
-static inline void cpm_set_scc_fcr(volatile scc_uart_t * sup)
+static inline void cpm_set_scc_fcr(scc_uart_t __iomem *sup)
 {
-	sup->scc_genscc.scc_rfcr = CPMFCR_GBL | CPMFCR_EB;
-	sup->scc_genscc.scc_tfcr = CPMFCR_GBL | CPMFCR_EB;
+	out_8(&sup->scc_genscc.scc_rfcr, CPMFCR_GBL | CPMFCR_EB);
+	out_8(&sup->scc_genscc.scc_tfcr, CPMFCR_GBL | CPMFCR_EB);
 }
 
-static inline void cpm_set_smc_fcr(volatile smc_uart_t * up)
+static inline void cpm_set_smc_fcr(smc_uart_t __iomem *up)
 {
-	up->smc_rfcr = CPMFCR_GBL | CPMFCR_EB;
-	up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB;
+	out_8(&up->smc_rfcr, CPMFCR_GBL | CPMFCR_EB);
+	out_8(&up->smc_tfcr, CPMFCR_GBL | CPMFCR_EB);
 }
 
-#define DPRAM_BASE	((unsigned char *)cpm_dpram_addr(0))
+#define DPRAM_BASE	((u8 __iomem __force *)cpm_dpram_addr(0))
 
 #endif
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index e42faa4..dc19671 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -1114,8 +1114,8 @@
 
 static void __exit imx_serial_exit(void)
 {
-	uart_unregister_driver(&imx_reg);
 	platform_driver_unregister(&serial_imx_driver);
+	uart_unregister_driver(&imx_reg);
 }
 
 module_init(imx_serial_init);
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 35f8b86..035cca0 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -1051,7 +1051,7 @@
 	/* If the slot is already occupied, then swap slots */
 	if (mpc52xx_uart_nodes[idx] && (free_idx != -1))
 		mpc52xx_uart_nodes[free_idx] = mpc52xx_uart_nodes[idx];
-	mpc52xx_uart_nodes[i] = np;
+	mpc52xx_uart_nodes[idx] = np;
 }
 
 static void
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
index 00924fe..4d643c9 100644
--- a/drivers/serial/mpsc.c
+++ b/drivers/serial/mpsc.c
@@ -74,10 +74,6 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 
-#if defined(CONFIG_SERIAL_MPSC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
 #define	MPSC_NUM_CTLRS		2
 
 /*
@@ -97,9 +93,8 @@
 #define	MPSC_TXBE_SIZE		dma_get_cache_alignment()
 #define	MPSC_TXB_SIZE		(MPSC_TXR_ENTRIES * MPSC_TXBE_SIZE)
 
-#define	MPSC_DMA_ALLOC_SIZE	(MPSC_RXR_SIZE + MPSC_RXB_SIZE +	\
-				MPSC_TXR_SIZE + MPSC_TXB_SIZE +		\
-				dma_get_cache_alignment() /* for alignment */)
+#define	MPSC_DMA_ALLOC_SIZE	(MPSC_RXR_SIZE + MPSC_RXB_SIZE + MPSC_TXR_SIZE \
+		+ MPSC_TXB_SIZE + dma_get_cache_alignment() /* for alignment */)
 
 /* Rx and Tx Ring entry descriptors -- assume entry size is <= cacheline size */
 struct mpsc_rx_desc {
@@ -270,8 +265,8 @@
 #define	SDMA_DESC_CMDSTAT_EI		(1<<23)
 #define	SDMA_DESC_CMDSTAT_O		(1<<31)
 
-#define SDMA_DESC_DFLT			(SDMA_DESC_CMDSTAT_O |	\
-					SDMA_DESC_CMDSTAT_EI)
+#define SDMA_DESC_DFLT			(SDMA_DESC_CMDSTAT_O \
+		| SDMA_DESC_CMDSTAT_EI)
 
 #define	SDMA_SDC_RFT			(1<<0)
 #define	SDMA_SDC_SFM			(1<<1)
@@ -295,10 +290,10 @@
 #define	SDMA_1_CAUSE_TXBUF		(1<<10)
 #define	SDMA_1_CAUSE_TXEND		(1<<11)
 
-#define	SDMA_CAUSE_RX_MASK	(SDMA_0_CAUSE_RXBUF | SDMA_0_CAUSE_RXERR | \
-	SDMA_1_CAUSE_RXBUF | SDMA_1_CAUSE_RXERR)
-#define	SDMA_CAUSE_TX_MASK	(SDMA_0_CAUSE_TXBUF | SDMA_0_CAUSE_TXEND | \
-	SDMA_1_CAUSE_TXBUF | SDMA_1_CAUSE_TXEND)
+#define	SDMA_CAUSE_RX_MASK	(SDMA_0_CAUSE_RXBUF | SDMA_0_CAUSE_RXERR \
+		| SDMA_1_CAUSE_RXBUF | SDMA_1_CAUSE_RXERR)
+#define	SDMA_CAUSE_TX_MASK	(SDMA_0_CAUSE_TXBUF | SDMA_0_CAUSE_TXEND \
+		| SDMA_1_CAUSE_TXBUF | SDMA_1_CAUSE_TXEND)
 
 /* SDMA Interrupt registers */
 #define	SDMA_INTR_CAUSE			0x0000
@@ -312,11 +307,11 @@
  * Define how this driver is known to the outside (we've been assigned a
  * range on the "Low-density serial ports" major).
  */
-#define MPSC_MAJOR		204
-#define MPSC_MINOR_START	44
-#define	MPSC_DRIVER_NAME	"MPSC"
-#define	MPSC_DEV_NAME		"ttyMM"
-#define	MPSC_VERSION		"1.00"
+#define MPSC_MAJOR			204
+#define MPSC_MINOR_START		44
+#define	MPSC_DRIVER_NAME		"MPSC"
+#define	MPSC_DEV_NAME			"ttyMM"
+#define	MPSC_VERSION			"1.00"
 
 static struct mpsc_port_info mpsc_ports[MPSC_NUM_CTLRS];
 static struct mpsc_shared_regs mpsc_shared_regs;
@@ -332,8 +327,7 @@
  *
  ******************************************************************************
  */
-static void
-mpsc_brg_init(struct mpsc_port_info *pi, u32 clk_src)
+static void mpsc_brg_init(struct mpsc_port_info *pi, u32 clk_src)
 {
 	u32	v;
 
@@ -349,11 +343,9 @@
 
 	writel(readl(pi->brg_base + BRG_BTR) & 0xffff0000,
 		pi->brg_base + BRG_BTR);
-	return;
 }
 
-static void
-mpsc_brg_enable(struct mpsc_port_info *pi)
+static void mpsc_brg_enable(struct mpsc_port_info *pi)
 {
 	u32	v;
 
@@ -363,11 +355,9 @@
 	if (pi->mirror_regs)
 		pi->BRG_BCR_m = v;
 	writel(v, pi->brg_base + BRG_BCR);
-	return;
 }
 
-static void
-mpsc_brg_disable(struct mpsc_port_info *pi)
+static void mpsc_brg_disable(struct mpsc_port_info *pi)
 {
 	u32	v;
 
@@ -377,21 +367,19 @@
 	if (pi->mirror_regs)
 		pi->BRG_BCR_m = v;
 	writel(v, pi->brg_base + BRG_BCR);
-	return;
 }
 
-static inline void
-mpsc_set_baudrate(struct mpsc_port_info *pi, u32 baud)
+/*
+ * To set the baud, we adjust the CDV field in the BRG_BCR reg.
+ * From manual: Baud = clk / ((CDV+1)*2) ==> CDV = (clk / (baud*2)) - 1.
+ * However, the input clock is divided by 16 in the MPSC b/c of how
+ * 'MPSC_MMCRH' was set up so we have to divide the 'clk' used in our
+ * calculation by 16 to account for that.  So the real calculation
+ * that accounts for the way the mpsc is set up is:
+ * CDV = (clk / (baud*2*16)) - 1 ==> CDV = (clk / (baud << 5)) - 1.
+ */
+static void mpsc_set_baudrate(struct mpsc_port_info *pi, u32 baud)
 {
-	/*
-	 * To set the baud, we adjust the CDV field in the BRG_BCR reg.
-	 * From manual: Baud = clk / ((CDV+1)*2) ==> CDV = (clk / (baud*2)) - 1.
-	 * However, the input clock is divided by 16 in the MPSC b/c of how
-	 * 'MPSC_MMCRH' was set up so we have to divide the 'clk' used in our
-	 * calculation by 16 to account for that.  So the real calculation
-	 * that accounts for the way the mpsc is set up is:
-	 * CDV = (clk / (baud*2*16)) - 1 ==> CDV = (clk / (baud << 5)) - 1.
-	 */
 	u32	cdv = (pi->port.uartclk / (baud << 5)) - 1;
 	u32	v;
 
@@ -403,8 +391,6 @@
 		pi->BRG_BCR_m = v;
 	writel(v, pi->brg_base + BRG_BCR);
 	mpsc_brg_enable(pi);
-
-	return;
 }
 
 /*
@@ -415,13 +401,12 @@
  ******************************************************************************
  */
 
-static void
-mpsc_sdma_burstsize(struct mpsc_port_info *pi, u32 burst_size)
+static void mpsc_sdma_burstsize(struct mpsc_port_info *pi, u32 burst_size)
 {
 	u32	v;
 
 	pr_debug("mpsc_sdma_burstsize[%d]: burst_size: %d\n",
-	    pi->port.line, burst_size);
+			pi->port.line, burst_size);
 
 	burst_size >>= 3; /* Divide by 8 b/c reg values are 8-byte chunks */
 
@@ -436,11 +421,9 @@
 
 	writel((readl(pi->sdma_base + SDMA_SDC) & (0x3 << 12)) | (v << 12),
 		pi->sdma_base + SDMA_SDC);
-	return;
 }
 
-static void
-mpsc_sdma_init(struct mpsc_port_info *pi, u32 burst_size)
+static void mpsc_sdma_init(struct mpsc_port_info *pi, u32 burst_size)
 {
 	pr_debug("mpsc_sdma_init[%d]: burst_size: %d\n", pi->port.line,
 		burst_size);
@@ -448,11 +431,9 @@
 	writel((readl(pi->sdma_base + SDMA_SDC) & 0x3ff) | 0x03f,
 		pi->sdma_base + SDMA_SDC);
 	mpsc_sdma_burstsize(pi, burst_size);
-	return;
 }
 
-static inline u32
-mpsc_sdma_intr_mask(struct mpsc_port_info *pi, u32 mask)
+static u32 mpsc_sdma_intr_mask(struct mpsc_port_info *pi, u32 mask)
 {
 	u32	old, v;
 
@@ -475,15 +456,14 @@
 	return old & 0xf;
 }
 
-static inline void
-mpsc_sdma_intr_unmask(struct mpsc_port_info *pi, u32 mask)
+static void mpsc_sdma_intr_unmask(struct mpsc_port_info *pi, u32 mask)
 {
 	u32	v;
 
 	pr_debug("mpsc_sdma_intr_unmask[%d]: mask: 0x%x\n", pi->port.line,mask);
 
-	v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m :
-		readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
+	v = (pi->mirror_regs) ? pi->shared_regs->SDMA_INTR_MASK_m
+		: readl(pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
 
 	mask &= 0xf;
 	if (pi->port.line)
@@ -493,41 +473,35 @@
 	if (pi->mirror_regs)
 		pi->shared_regs->SDMA_INTR_MASK_m = v;
 	writel(v, pi->shared_regs->sdma_intr_base + SDMA_INTR_MASK);
-	return;
 }
 
-static inline void
-mpsc_sdma_intr_ack(struct mpsc_port_info *pi)
+static void mpsc_sdma_intr_ack(struct mpsc_port_info *pi)
 {
 	pr_debug("mpsc_sdma_intr_ack[%d]: Acknowledging IRQ\n", pi->port.line);
 
 	if (pi->mirror_regs)
 		pi->shared_regs->SDMA_INTR_CAUSE_m = 0;
-	writeb(0x00, pi->shared_regs->sdma_intr_base + SDMA_INTR_CAUSE +
-	       pi->port.line);
-	return;
+	writeb(0x00, pi->shared_regs->sdma_intr_base + SDMA_INTR_CAUSE
+			+ pi->port.line);
 }
 
-static inline void
-mpsc_sdma_set_rx_ring(struct mpsc_port_info *pi, struct mpsc_rx_desc *rxre_p)
+static void mpsc_sdma_set_rx_ring(struct mpsc_port_info *pi,
+		struct mpsc_rx_desc *rxre_p)
 {
 	pr_debug("mpsc_sdma_set_rx_ring[%d]: rxre_p: 0x%x\n",
-		pi->port.line, (u32) rxre_p);
+		pi->port.line, (u32)rxre_p);
 
 	writel((u32)rxre_p, pi->sdma_base + SDMA_SCRDP);
-	return;
 }
 
-static inline void
-mpsc_sdma_set_tx_ring(struct mpsc_port_info *pi, struct mpsc_tx_desc *txre_p)
+static void mpsc_sdma_set_tx_ring(struct mpsc_port_info *pi,
+		struct mpsc_tx_desc *txre_p)
 {
 	writel((u32)txre_p, pi->sdma_base + SDMA_SFTDP);
 	writel((u32)txre_p, pi->sdma_base + SDMA_SCTDP);
-	return;
 }
 
-static inline void
-mpsc_sdma_cmd(struct mpsc_port_info *pi, u32 val)
+static void mpsc_sdma_cmd(struct mpsc_port_info *pi, u32 val)
 {
 	u32	v;
 
@@ -539,46 +513,40 @@
 	wmb();
 	writel(v, pi->sdma_base + SDMA_SDCM);
 	wmb();
-	return;
 }
 
-static inline uint
-mpsc_sdma_tx_active(struct mpsc_port_info *pi)
+static uint mpsc_sdma_tx_active(struct mpsc_port_info *pi)
 {
 	return readl(pi->sdma_base + SDMA_SDCM) & SDMA_SDCM_TXD;
 }
 
-static inline void
-mpsc_sdma_start_tx(struct mpsc_port_info *pi)
+static void mpsc_sdma_start_tx(struct mpsc_port_info *pi)
 {
 	struct mpsc_tx_desc *txre, *txre_p;
 
 	/* If tx isn't running & there's a desc ready to go, start it */
 	if (!mpsc_sdma_tx_active(pi)) {
-		txre = (struct mpsc_tx_desc *)(pi->txr +
-			(pi->txr_tail * MPSC_TXRE_SIZE));
-		dma_cache_sync(pi->port.dev, (void *) txre, MPSC_TXRE_SIZE, DMA_FROM_DEVICE);
+		txre = (struct mpsc_tx_desc *)(pi->txr
+				+ (pi->txr_tail * MPSC_TXRE_SIZE));
+		dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
+				DMA_FROM_DEVICE);
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
 		if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
 			invalidate_dcache_range((ulong)txre,
-				(ulong)txre + MPSC_TXRE_SIZE);
+					(ulong)txre + MPSC_TXRE_SIZE);
 #endif
 
 		if (be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O) {
-			txre_p = (struct mpsc_tx_desc *)(pi->txr_p +
-							 (pi->txr_tail *
-							  MPSC_TXRE_SIZE));
+			txre_p = (struct mpsc_tx_desc *)
+				(pi->txr_p + (pi->txr_tail * MPSC_TXRE_SIZE));
 
 			mpsc_sdma_set_tx_ring(pi, txre_p);
 			mpsc_sdma_cmd(pi, SDMA_SDCM_STD | SDMA_SDCM_TXD);
 		}
 	}
-
-	return;
 }
 
-static inline void
-mpsc_sdma_stop(struct mpsc_port_info *pi)
+static void mpsc_sdma_stop(struct mpsc_port_info *pi)
 {
 	pr_debug("mpsc_sdma_stop[%d]: Stopping SDMA\n", pi->port.line);
 
@@ -593,8 +561,6 @@
 	/* Disable interrupts */
 	mpsc_sdma_intr_mask(pi, 0xf);
 	mpsc_sdma_intr_ack(pi);
-
-	return;
 }
 
 /*
@@ -605,8 +571,7 @@
  ******************************************************************************
  */
 
-static void
-mpsc_hw_init(struct mpsc_port_info *pi)
+static void mpsc_hw_init(struct mpsc_port_info *pi)
 {
 	u32	v;
 
@@ -628,8 +593,7 @@
 		v = (v & ~0xf0f) | 0x100;
 		pi->shared_regs->MPSC_TCRR_m = v;
 		writel(v, pi->shared_regs->mpsc_routing_base + MPSC_TCRR);
-	}
-	else {
+	} else {
 		v = readl(pi->shared_regs->mpsc_routing_base + MPSC_MRR);
 		v &= ~0x1c7;
 		writel(v, pi->shared_regs->mpsc_routing_base + MPSC_MRR);
@@ -646,7 +610,7 @@
 	/* Put MPSC in UART mode & enabel Tx/Rx egines */
 	writel(0x000004c4, pi->mpsc_base + MPSC_MMCRL);
 
-	/* No preamble, 16x divider, low-latency,  */
+	/* No preamble, 16x divider, low-latency, */
 	writel(0x04400400, pi->mpsc_base + MPSC_MMCRH);
 
 	if (pi->mirror_regs) {
@@ -663,12 +627,9 @@
 	writel(0, pi->mpsc_base + MPSC_CHR_8);
 	writel(0, pi->mpsc_base + MPSC_CHR_9);
 	writel(0, pi->mpsc_base + MPSC_CHR_10);
-
-	return;
 }
 
-static inline void
-mpsc_enter_hunt(struct mpsc_port_info *pi)
+static void mpsc_enter_hunt(struct mpsc_port_info *pi)
 {
 	pr_debug("mpsc_enter_hunt[%d]: Hunting...\n", pi->port.line);
 
@@ -677,20 +638,16 @@
 			pi->mpsc_base + MPSC_CHR_2);
 		/* Erratum prevents reading CHR_2 so just delay for a while */
 		udelay(100);
-	}
-	else {
+	} else {
 		writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_EH,
-			pi->mpsc_base + MPSC_CHR_2);
+				pi->mpsc_base + MPSC_CHR_2);
 
 		while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_EH)
 			udelay(10);
 	}
-
-	return;
 }
 
-static inline void
-mpsc_freeze(struct mpsc_port_info *pi)
+static void mpsc_freeze(struct mpsc_port_info *pi)
 {
 	u32	v;
 
@@ -703,11 +660,9 @@
 	if (pi->mirror_regs)
 		pi->MPSC_MPCR_m = v;
 	writel(v, pi->mpsc_base + MPSC_MPCR);
-	return;
 }
 
-static inline void
-mpsc_unfreeze(struct mpsc_port_info *pi)
+static void mpsc_unfreeze(struct mpsc_port_info *pi)
 {
 	u32	v;
 
@@ -720,11 +675,9 @@
 	writel(v, pi->mpsc_base + MPSC_MPCR);
 
 	pr_debug("mpsc_unfreeze[%d]: Unfrozen\n", pi->port.line);
-	return;
 }
 
-static inline void
-mpsc_set_char_length(struct mpsc_port_info *pi, u32 len)
+static void mpsc_set_char_length(struct mpsc_port_info *pi, u32 len)
 {
 	u32	v;
 
@@ -737,11 +690,9 @@
 	if (pi->mirror_regs)
 		pi->MPSC_MPCR_m = v;
 	writel(v, pi->mpsc_base + MPSC_MPCR);
-	return;
 }
 
-static inline void
-mpsc_set_stop_bit_length(struct mpsc_port_info *pi, u32 len)
+static void mpsc_set_stop_bit_length(struct mpsc_port_info *pi, u32 len)
 {
 	u32	v;
 
@@ -756,11 +707,9 @@
 	if (pi->mirror_regs)
 		pi->MPSC_MPCR_m = v;
 	writel(v, pi->mpsc_base + MPSC_MPCR);
-	return;
 }
 
-static inline void
-mpsc_set_parity(struct mpsc_port_info *pi, u32 p)
+static void mpsc_set_parity(struct mpsc_port_info *pi, u32 p)
 {
 	u32	v;
 
@@ -775,7 +724,6 @@
 	if (pi->mirror_regs)
 		pi->MPSC_CHR_2_m = v;
 	writel(v, pi->mpsc_base + MPSC_CHR_2);
-	return;
 }
 
 /*
@@ -786,8 +734,7 @@
  ******************************************************************************
  */
 
-static void
-mpsc_init_hw(struct mpsc_port_info *pi)
+static void mpsc_init_hw(struct mpsc_port_info *pi)
 {
 	pr_debug("mpsc_init_hw[%d]: Initializing\n", pi->port.line);
 
@@ -796,12 +743,9 @@
 	mpsc_sdma_init(pi, dma_get_cache_alignment());	/* burst a cacheline */
 	mpsc_sdma_stop(pi);
 	mpsc_hw_init(pi);
-
-	return;
 }
 
-static int
-mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
+static int mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
 {
 	int rc = 0;
 
@@ -812,11 +756,10 @@
 		if (!dma_supported(pi->port.dev, 0xffffffff)) {
 			printk(KERN_ERR "MPSC: Inadequate DMA support\n");
 			rc = -ENXIO;
-		}
-		else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev,
-			MPSC_DMA_ALLOC_SIZE, &pi->dma_region_p, GFP_KERNEL))
-			== NULL) {
-
+		} else if ((pi->dma_region = dma_alloc_noncoherent(pi->port.dev,
+						MPSC_DMA_ALLOC_SIZE,
+						&pi->dma_region_p, GFP_KERNEL))
+				== NULL) {
 			printk(KERN_ERR "MPSC: Can't alloc Desc region\n");
 			rc = -ENOMEM;
 		}
@@ -825,23 +768,19 @@
 	return rc;
 }
 
-static void
-mpsc_free_ring_mem(struct mpsc_port_info *pi)
+static void mpsc_free_ring_mem(struct mpsc_port_info *pi)
 {
 	pr_debug("mpsc_free_ring_mem[%d]: Freeing ring mem\n", pi->port.line);
 
 	if (pi->dma_region) {
 		dma_free_noncoherent(pi->port.dev, MPSC_DMA_ALLOC_SIZE,
-			  pi->dma_region, pi->dma_region_p);
+				pi->dma_region, pi->dma_region_p);
 		pi->dma_region = NULL;
-		pi->dma_region_p = (dma_addr_t) NULL;
+		pi->dma_region_p = (dma_addr_t)NULL;
 	}
-
-	return;
 }
 
-static void
-mpsc_init_rings(struct mpsc_port_info *pi)
+static void mpsc_init_rings(struct mpsc_port_info *pi)
 {
 	struct mpsc_rx_desc *rxre;
 	struct mpsc_tx_desc *txre;
@@ -859,8 +798,8 @@
 	 * Descriptors & buffers are multiples of cacheline size and must be
 	 * cacheline aligned.
 	 */
-	dp = ALIGN((u32) pi->dma_region, dma_get_cache_alignment());
-	dp_p = ALIGN((u32) pi->dma_region_p, dma_get_cache_alignment());
+	dp = ALIGN((u32)pi->dma_region, dma_get_cache_alignment());
+	dp_p = ALIGN((u32)pi->dma_region_p, dma_get_cache_alignment());
 
 	/*
 	 * Partition dma region into rx ring descriptor, rx buffers,
@@ -871,8 +810,8 @@
 	dp += MPSC_RXR_SIZE;
 	dp_p += MPSC_RXR_SIZE;
 
-	pi->rxb = (u8 *) dp;
-	pi->rxb_p = (u8 *) dp_p;
+	pi->rxb = (u8 *)dp;
+	pi->rxb_p = (u8 *)dp_p;
 	dp += MPSC_RXB_SIZE;
 	dp_p += MPSC_RXB_SIZE;
 
@@ -883,8 +822,8 @@
 	dp += MPSC_TXR_SIZE;
 	dp_p += MPSC_TXR_SIZE;
 
-	pi->txb = (u8 *) dp;
-	pi->txb_p = (u8 *) dp_p;
+	pi->txb = (u8 *)dp;
+	pi->txb_p = (u8 *)dp_p;
 
 	pi->txr_head = 0;
 	pi->txr_tail = 0;
@@ -900,10 +839,9 @@
 
 		rxre->bufsize = cpu_to_be16(MPSC_RXBE_SIZE);
 		rxre->bytecnt = cpu_to_be16(0);
-		rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O |
-					    SDMA_DESC_CMDSTAT_EI |
-					    SDMA_DESC_CMDSTAT_F |
-					    SDMA_DESC_CMDSTAT_L);
+		rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O
+				| SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F
+				| SDMA_DESC_CMDSTAT_L);
 		rxre->link = cpu_to_be32(dp_p + MPSC_RXRE_SIZE);
 		rxre->buf_ptr = cpu_to_be32(bp_p);
 
@@ -933,19 +871,19 @@
 	}
 	txre->link = cpu_to_be32(pi->txr_p);	/* Wrap last back to first */
 
-	dma_cache_sync(pi->port.dev, (void *) pi->dma_region, MPSC_DMA_ALLOC_SIZE,
-		DMA_BIDIRECTIONAL);
+	dma_cache_sync(pi->port.dev, (void *)pi->dma_region,
+			MPSC_DMA_ALLOC_SIZE, DMA_BIDIRECTIONAL);
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
 		if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
 			flush_dcache_range((ulong)pi->dma_region,
-				(ulong)pi->dma_region + MPSC_DMA_ALLOC_SIZE);
+					(ulong)pi->dma_region
+					+ MPSC_DMA_ALLOC_SIZE);
 #endif
 
 	return;
 }
 
-static void
-mpsc_uninit_rings(struct mpsc_port_info *pi)
+static void mpsc_uninit_rings(struct mpsc_port_info *pi)
 {
 	pr_debug("mpsc_uninit_rings[%d]: Uninitializing rings\n",pi->port.line);
 
@@ -963,12 +901,9 @@
 	pi->txb_p = NULL;
 	pi->txr_head = 0;
 	pi->txr_tail = 0;
-
-	return;
 }
 
-static int
-mpsc_make_ready(struct mpsc_port_info *pi)
+static int mpsc_make_ready(struct mpsc_port_info *pi)
 {
 	int rc;
 
@@ -993,8 +928,7 @@
  ******************************************************************************
  */
 
-static inline int
-mpsc_rx_intr(struct mpsc_port_info *pi)
+static int mpsc_rx_intr(struct mpsc_port_info *pi)
 {
 	struct mpsc_rx_desc *rxre;
 	struct tty_struct *tty = pi->port.info->tty;
@@ -1007,21 +941,24 @@
 
 	rxre = (struct mpsc_rx_desc *)(pi->rxr + (pi->rxr_posn*MPSC_RXRE_SIZE));
 
-	dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
+	dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
+			DMA_FROM_DEVICE);
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
 	if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
 		invalidate_dcache_range((ulong)rxre,
-			(ulong)rxre + MPSC_RXRE_SIZE);
+				(ulong)rxre + MPSC_RXRE_SIZE);
 #endif
 
 	/*
 	 * Loop through Rx descriptors handling ones that have been completed.
 	 */
-	while (!((cmdstat = be32_to_cpu(rxre->cmdstat)) & SDMA_DESC_CMDSTAT_O)){
+	while (!((cmdstat = be32_to_cpu(rxre->cmdstat))
+				& SDMA_DESC_CMDSTAT_O)) {
 		bytes_in = be16_to_cpu(rxre->bytecnt);
 
 		/* Following use of tty struct directly is deprecated */
-		if (unlikely(tty_buffer_request_room(tty, bytes_in) < bytes_in)) {
+		if (unlikely(tty_buffer_request_room(tty, bytes_in)
+					< bytes_in)) {
 			if (tty->low_latency)
 				tty_flip_buffer_push(tty);
 			/*
@@ -1031,11 +968,12 @@
 		}
 
 		bp = pi->rxb + (pi->rxr_posn * MPSC_RXBE_SIZE);
-		dma_cache_sync(pi->port.dev, (void *) bp, MPSC_RXBE_SIZE, DMA_FROM_DEVICE);
+		dma_cache_sync(pi->port.dev, (void *)bp, MPSC_RXBE_SIZE,
+				DMA_FROM_DEVICE);
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
 		if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
 			invalidate_dcache_range((ulong)bp,
-				(ulong)bp + MPSC_RXBE_SIZE);
+					(ulong)bp + MPSC_RXBE_SIZE);
 #endif
 
 		/*
@@ -1046,8 +984,9 @@
 		 * we'll assume there is no data in the buffer.
 		 * If there is...it gets lost.
 		 */
-		if (unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR |
-			SDMA_DESC_CMDSTAT_FR | SDMA_DESC_CMDSTAT_OR))) {
+		if (unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR
+						| SDMA_DESC_CMDSTAT_FR
+						| SDMA_DESC_CMDSTAT_OR))) {
 
 			pi->port.icount.rx++;
 
@@ -1056,11 +995,11 @@
 
 				if (uart_handle_break(&pi->port))
 					goto next_frame;
-			}
-			else if (cmdstat & SDMA_DESC_CMDSTAT_FR)/* Framing */
+			} else if (cmdstat & SDMA_DESC_CMDSTAT_FR) {
 				pi->port.icount.frame++;
-			else if (cmdstat & SDMA_DESC_CMDSTAT_OR) /* Overrun */
+			} else if (cmdstat & SDMA_DESC_CMDSTAT_OR) {
 				pi->port.icount.overrun++;
+			}
 
 			cmdstat &= pi->port.read_status_mask;
 
@@ -1080,12 +1019,12 @@
 			goto next_frame;
 		}
 
-		if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR |
-			SDMA_DESC_CMDSTAT_FR | SDMA_DESC_CMDSTAT_OR))) &&
-			!(cmdstat & pi->port.ignore_status_mask))
-
+		if ((unlikely(cmdstat & (SDMA_DESC_CMDSTAT_BR
+						| SDMA_DESC_CMDSTAT_FR
+						| SDMA_DESC_CMDSTAT_OR)))
+				&& !(cmdstat & pi->port.ignore_status_mask)) {
 			tty_insert_flip_char(tty, *bp, flag);
-		else {
+		} else {
 			for (i=0; i<bytes_in; i++)
 				tty_insert_flip_char(tty, *bp++, TTY_NORMAL);
 
@@ -1095,29 +1034,29 @@
 next_frame:
 		rxre->bytecnt = cpu_to_be16(0);
 		wmb();
-		rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O |
-					    SDMA_DESC_CMDSTAT_EI |
-					    SDMA_DESC_CMDSTAT_F |
-					    SDMA_DESC_CMDSTAT_L);
+		rxre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O
+				| SDMA_DESC_CMDSTAT_EI | SDMA_DESC_CMDSTAT_F
+				| SDMA_DESC_CMDSTAT_L);
 		wmb();
-		dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE, DMA_BIDIRECTIONAL);
+		dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
+				DMA_BIDIRECTIONAL);
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
 		if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
 			flush_dcache_range((ulong)rxre,
-				(ulong)rxre + MPSC_RXRE_SIZE);
+					(ulong)rxre + MPSC_RXRE_SIZE);
 #endif
 
 		/* Advance to next descriptor */
 		pi->rxr_posn = (pi->rxr_posn + 1) & (MPSC_RXR_ENTRIES - 1);
-		rxre = (struct mpsc_rx_desc *)(pi->rxr +
-			(pi->rxr_posn * MPSC_RXRE_SIZE));
-		dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE, DMA_FROM_DEVICE);
+		rxre = (struct mpsc_rx_desc *)
+			(pi->rxr + (pi->rxr_posn * MPSC_RXRE_SIZE));
+		dma_cache_sync(pi->port.dev, (void *)rxre, MPSC_RXRE_SIZE,
+				DMA_FROM_DEVICE);
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
 		if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
 			invalidate_dcache_range((ulong)rxre,
-				(ulong)rxre + MPSC_RXRE_SIZE);
+					(ulong)rxre + MPSC_RXRE_SIZE);
 #endif
-
 		rc = 1;
 	}
 
@@ -1129,42 +1068,38 @@
 	return rc;
 }
 
-static inline void
-mpsc_setup_tx_desc(struct mpsc_port_info *pi, u32 count, u32 intr)
+static void mpsc_setup_tx_desc(struct mpsc_port_info *pi, u32 count, u32 intr)
 {
 	struct mpsc_tx_desc *txre;
 
-	txre = (struct mpsc_tx_desc *)(pi->txr +
-		(pi->txr_head * MPSC_TXRE_SIZE));
+	txre = (struct mpsc_tx_desc *)(pi->txr
+			+ (pi->txr_head * MPSC_TXRE_SIZE));
 
 	txre->bytecnt = cpu_to_be16(count);
 	txre->shadow = txre->bytecnt;
 	wmb();			/* ensure cmdstat is last field updated */
-	txre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O | SDMA_DESC_CMDSTAT_F |
-				    SDMA_DESC_CMDSTAT_L | ((intr) ?
-							   SDMA_DESC_CMDSTAT_EI
-							   : 0));
+	txre->cmdstat = cpu_to_be32(SDMA_DESC_CMDSTAT_O | SDMA_DESC_CMDSTAT_F
+			| SDMA_DESC_CMDSTAT_L
+			| ((intr) ? SDMA_DESC_CMDSTAT_EI : 0));
 	wmb();
-	dma_cache_sync(pi->port.dev, (void *) txre, MPSC_TXRE_SIZE, DMA_BIDIRECTIONAL);
+	dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
+			DMA_BIDIRECTIONAL);
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
 	if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
 		flush_dcache_range((ulong)txre,
-			(ulong)txre + MPSC_TXRE_SIZE);
+				(ulong)txre + MPSC_TXRE_SIZE);
 #endif
-
-	return;
 }
 
-static inline void
-mpsc_copy_tx_data(struct mpsc_port_info *pi)
+static void mpsc_copy_tx_data(struct mpsc_port_info *pi)
 {
 	struct circ_buf *xmit = &pi->port.info->xmit;
 	u8 *bp;
 	u32 i;
 
 	/* Make sure the desc ring isn't full */
-	while (CIRC_CNT(pi->txr_head, pi->txr_tail, MPSC_TXR_ENTRIES) <
-	       (MPSC_TXR_ENTRIES - 1)) {
+	while (CIRC_CNT(pi->txr_head, pi->txr_tail, MPSC_TXR_ENTRIES)
+			< (MPSC_TXR_ENTRIES - 1)) {
 		if (pi->port.x_char) {
 			/*
 			 * Ideally, we should use the TCS field in
@@ -1178,11 +1113,11 @@
 			*bp = pi->port.x_char;
 			pi->port.x_char = 0;
 			i = 1;
-		}
-		else if (!uart_circ_empty(xmit) && !uart_tx_stopped(&pi->port)){
-			i = min((u32) MPSC_TXBE_SIZE,
-				(u32) uart_circ_chars_pending(xmit));
-			i = min(i, (u32) CIRC_CNT_TO_END(xmit->head, xmit->tail,
+		} else if (!uart_circ_empty(xmit)
+				&& !uart_tx_stopped(&pi->port)) {
+			i = min((u32)MPSC_TXBE_SIZE,
+				(u32)uart_circ_chars_pending(xmit));
+			i = min(i, (u32)CIRC_CNT_TO_END(xmit->head, xmit->tail,
 				UART_XMIT_SIZE));
 			bp = pi->txb + (pi->txr_head * MPSC_TXBE_SIZE);
 			memcpy(bp, &xmit->buf[xmit->tail], i);
@@ -1190,27 +1125,25 @@
 
 			if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 				uart_write_wakeup(&pi->port);
-		}
-		else /* All tx data copied into ring bufs */
+		} else { /* All tx data copied into ring bufs */
 			return;
+		}
 
-		dma_cache_sync(pi->port.dev, (void *) bp, MPSC_TXBE_SIZE, DMA_BIDIRECTIONAL);
+		dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE,
+				DMA_BIDIRECTIONAL);
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
 		if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
 			flush_dcache_range((ulong)bp,
-				(ulong)bp + MPSC_TXBE_SIZE);
+					(ulong)bp + MPSC_TXBE_SIZE);
 #endif
 		mpsc_setup_tx_desc(pi, i, 1);
 
 		/* Advance to next descriptor */
 		pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1);
 	}
-
-	return;
 }
 
-static inline int
-mpsc_tx_intr(struct mpsc_port_info *pi)
+static int mpsc_tx_intr(struct mpsc_port_info *pi)
 {
 	struct mpsc_tx_desc *txre;
 	int rc = 0;
@@ -1219,14 +1152,15 @@
 	spin_lock_irqsave(&pi->tx_lock, iflags);
 
 	if (!mpsc_sdma_tx_active(pi)) {
-		txre = (struct mpsc_tx_desc *)(pi->txr +
-			(pi->txr_tail * MPSC_TXRE_SIZE));
+		txre = (struct mpsc_tx_desc *)(pi->txr
+				+ (pi->txr_tail * MPSC_TXRE_SIZE));
 
-		dma_cache_sync(pi->port.dev, (void *) txre, MPSC_TXRE_SIZE, DMA_FROM_DEVICE);
+		dma_cache_sync(pi->port.dev, (void *)txre, MPSC_TXRE_SIZE,
+				DMA_FROM_DEVICE);
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
 		if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
 			invalidate_dcache_range((ulong)txre,
-				(ulong)txre + MPSC_TXRE_SIZE);
+					(ulong)txre + MPSC_TXRE_SIZE);
 #endif
 
 		while (!(be32_to_cpu(txre->cmdstat) & SDMA_DESC_CMDSTAT_O)) {
@@ -1238,14 +1172,14 @@
 			if (pi->txr_head == pi->txr_tail)
 				break;
 
-			txre = (struct mpsc_tx_desc *)(pi->txr +
-				(pi->txr_tail * MPSC_TXRE_SIZE));
-			dma_cache_sync(pi->port.dev, (void *) txre, MPSC_TXRE_SIZE,
-				DMA_FROM_DEVICE);
+			txre = (struct mpsc_tx_desc *)(pi->txr
+					+ (pi->txr_tail * MPSC_TXRE_SIZE));
+			dma_cache_sync(pi->port.dev, (void *)txre,
+					MPSC_TXRE_SIZE, DMA_FROM_DEVICE);
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
 			if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
 				invalidate_dcache_range((ulong)txre,
-					(ulong)txre + MPSC_TXRE_SIZE);
+						(ulong)txre + MPSC_TXRE_SIZE);
 #endif
 		}
 
@@ -1262,8 +1196,7 @@
  * the interrupt, then handle any completed Rx/Tx descriptors.  When done
  * handling those descriptors, we restart the Rx/Tx engines if they're stopped.
  */
-static irqreturn_t
-mpsc_sdma_intr(int irq, void *dev_id)
+static irqreturn_t mpsc_sdma_intr(int irq, void *dev_id)
 {
 	struct mpsc_port_info *pi = dev_id;
 	ulong iflags;
@@ -1290,8 +1223,7 @@
  *
  ******************************************************************************
  */
-static uint
-mpsc_tx_empty(struct uart_port *port)
+static uint mpsc_tx_empty(struct uart_port *port)
 {
 	struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
 	ulong iflags;
@@ -1304,21 +1236,18 @@
 	return rc;
 }
 
-static void
-mpsc_set_mctrl(struct uart_port *port, uint mctrl)
+static void mpsc_set_mctrl(struct uart_port *port, uint mctrl)
 {
 	/* Have no way to set modem control lines AFAICT */
-	return;
 }
 
-static uint
-mpsc_get_mctrl(struct uart_port *port)
+static uint mpsc_get_mctrl(struct uart_port *port)
 {
 	struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
 	u32 mflags, status;
 
-	status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m :
-		readl(pi->mpsc_base + MPSC_CHR_10);
+	status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m
+		: readl(pi->mpsc_base + MPSC_CHR_10);
 
 	mflags = 0;
 	if (status & 0x1)
@@ -1329,19 +1258,16 @@
 	return mflags | TIOCM_DSR;	/* No way to tell if DSR asserted */
 }
 
-static void
-mpsc_stop_tx(struct uart_port *port)
+static void mpsc_stop_tx(struct uart_port *port)
 {
 	struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
 
 	pr_debug("mpsc_stop_tx[%d]\n", port->line);
 
 	mpsc_freeze(pi);
-	return;
 }
 
-static void
-mpsc_start_tx(struct uart_port *port)
+static void mpsc_start_tx(struct uart_port *port)
 {
 	struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
 	unsigned long iflags;
@@ -1355,42 +1281,45 @@
 	spin_unlock_irqrestore(&pi->tx_lock, iflags);
 
 	pr_debug("mpsc_start_tx[%d]\n", port->line);
-	return;
 }
 
-static void
-mpsc_start_rx(struct mpsc_port_info *pi)
+static void mpsc_start_rx(struct mpsc_port_info *pi)
 {
 	pr_debug("mpsc_start_rx[%d]: Starting...\n", pi->port.line);
 
-	/* Issue a Receive Abort to clear any receive errors */
-	writel(MPSC_CHR_2_RA, pi->mpsc_base + MPSC_CHR_2);
 	if (pi->rcv_data) {
 		mpsc_enter_hunt(pi);
 		mpsc_sdma_cmd(pi, SDMA_SDCM_ERD);
 	}
-	return;
 }
 
-static void
-mpsc_stop_rx(struct uart_port *port)
+static void mpsc_stop_rx(struct uart_port *port)
 {
 	struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
 
 	pr_debug("mpsc_stop_rx[%d]: Stopping...\n", port->line);
 
+	if (pi->mirror_regs) {
+		writel(pi->MPSC_CHR_2_m | MPSC_CHR_2_RA,
+				pi->mpsc_base + MPSC_CHR_2);
+		/* Erratum prevents reading CHR_2 so just delay for a while */
+		udelay(100);
+	} else {
+		writel(readl(pi->mpsc_base + MPSC_CHR_2) | MPSC_CHR_2_RA,
+				pi->mpsc_base + MPSC_CHR_2);
+
+		while (readl(pi->mpsc_base + MPSC_CHR_2) & MPSC_CHR_2_RA)
+			udelay(10);
+	}
+
 	mpsc_sdma_cmd(pi, SDMA_SDCM_AR);
-	return;
 }
 
-static void
-mpsc_enable_ms(struct uart_port *port)
+static void mpsc_enable_ms(struct uart_port *port)
 {
-	return;			/* Not supported */
 }
 
-static void
-mpsc_break_ctl(struct uart_port *port, int ctl)
+static void mpsc_break_ctl(struct uart_port *port, int ctl)
 {
 	struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
 	ulong	flags;
@@ -1403,12 +1332,9 @@
 		pi->MPSC_CHR_1_m = v;
 	writel(v, pi->mpsc_base + MPSC_CHR_1);
 	spin_unlock_irqrestore(&pi->port.lock, flags);
-
-	return;
 }
 
-static int
-mpsc_startup(struct uart_port *port)
+static int mpsc_startup(struct uart_port *port)
 {
 	struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
 	u32 flag = 0;
@@ -1426,20 +1352,19 @@
 			flag = IRQF_SHARED;
 
 		if (request_irq(pi->port.irq, mpsc_sdma_intr, flag,
-				"mpsc-sdma", pi))
+					"mpsc-sdma", pi))
 			printk(KERN_ERR "MPSC: Can't get SDMA IRQ %d\n",
-			       pi->port.irq);
+					pi->port.irq);
 
 		mpsc_sdma_intr_unmask(pi, 0xf);
-		mpsc_sdma_set_rx_ring(pi, (struct mpsc_rx_desc *)(pi->rxr_p +
-			(pi->rxr_posn * MPSC_RXRE_SIZE)));
+		mpsc_sdma_set_rx_ring(pi, (struct mpsc_rx_desc *)(pi->rxr_p
+					+ (pi->rxr_posn * MPSC_RXRE_SIZE)));
 	}
 
 	return rc;
 }
 
-static void
-mpsc_shutdown(struct uart_port *port)
+static void mpsc_shutdown(struct uart_port *port)
 {
 	struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
 
@@ -1447,11 +1372,9 @@
 
 	mpsc_sdma_stop(pi);
 	free_irq(pi->port.irq, pi);
-	return;
 }
 
-static void
-mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
+static void mpsc_set_termios(struct uart_port *port, struct ktermios *termios,
 		 struct ktermios *old)
 {
 	struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
@@ -1508,12 +1431,11 @@
 	mpsc_set_baudrate(pi, baud);
 
 	/* Characters/events to read */
-	pi->rcv_data = 1;
 	pi->port.read_status_mask = SDMA_DESC_CMDSTAT_OR;
 
 	if (termios->c_iflag & INPCK)
-		pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE |
-		    SDMA_DESC_CMDSTAT_FR;
+		pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_PE
+			| SDMA_DESC_CMDSTAT_FR;
 
 	if (termios->c_iflag & (BRKINT | PARMRK))
 		pi->port.read_status_mask |= SDMA_DESC_CMDSTAT_BR;
@@ -1522,8 +1444,8 @@
 	pi->port.ignore_status_mask = 0;
 
 	if (termios->c_iflag & IGNPAR)
-		pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_PE |
-		    SDMA_DESC_CMDSTAT_FR;
+		pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_PE
+			| SDMA_DESC_CMDSTAT_FR;
 
 	if (termios->c_iflag & IGNBRK) {
 		pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_BR;
@@ -1532,32 +1454,32 @@
 			pi->port.ignore_status_mask |= SDMA_DESC_CMDSTAT_OR;
 	}
 
-	/* Ignore all chars if CREAD not set */
-	if (!(termios->c_cflag & CREAD))
+	if ((termios->c_cflag & CREAD)) {
+		if (!pi->rcv_data) {
+			pi->rcv_data = 1;
+			mpsc_start_rx(pi);
+		}
+	} else if (pi->rcv_data) {
+		mpsc_stop_rx(port);
 		pi->rcv_data = 0;
-	else
-		mpsc_start_rx(pi);
+	}
 
 	spin_unlock_irqrestore(&pi->port.lock, flags);
-	return;
 }
 
-static const char *
-mpsc_type(struct uart_port *port)
+static const char *mpsc_type(struct uart_port *port)
 {
 	pr_debug("mpsc_type[%d]: port type: %s\n", port->line,MPSC_DRIVER_NAME);
 	return MPSC_DRIVER_NAME;
 }
 
-static int
-mpsc_request_port(struct uart_port *port)
+static int mpsc_request_port(struct uart_port *port)
 {
 	/* Should make chip/platform specific call */
 	return 0;
 }
 
-static void
-mpsc_release_port(struct uart_port *port)
+static void mpsc_release_port(struct uart_port *port)
 {
 	struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
 
@@ -1566,18 +1488,13 @@
 		mpsc_free_ring_mem(pi);
 		pi->ready = 0;
 	}
-
-	return;
 }
 
-static void
-mpsc_config_port(struct uart_port *port, int flags)
+static void mpsc_config_port(struct uart_port *port, int flags)
 {
-	return;
 }
 
-static int
-mpsc_verify_port(struct uart_port *port, struct serial_struct *ser)
+static int mpsc_verify_port(struct uart_port *port, struct serial_struct *ser)
 {
 	struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
 	int rc = 0;
@@ -1603,22 +1520,22 @@
 }
 
 static struct uart_ops mpsc_pops = {
-	.tx_empty     = mpsc_tx_empty,
-	.set_mctrl    = mpsc_set_mctrl,
-	.get_mctrl    = mpsc_get_mctrl,
-	.stop_tx      = mpsc_stop_tx,
-	.start_tx     = mpsc_start_tx,
-	.stop_rx      = mpsc_stop_rx,
-	.enable_ms    = mpsc_enable_ms,
-	.break_ctl    = mpsc_break_ctl,
-	.startup      = mpsc_startup,
-	.shutdown     = mpsc_shutdown,
-	.set_termios  = mpsc_set_termios,
-	.type         = mpsc_type,
-	.release_port = mpsc_release_port,
-	.request_port = mpsc_request_port,
-	.config_port  = mpsc_config_port,
-	.verify_port  = mpsc_verify_port,
+	.tx_empty	= mpsc_tx_empty,
+	.set_mctrl	= mpsc_set_mctrl,
+	.get_mctrl	= mpsc_get_mctrl,
+	.stop_tx	= mpsc_stop_tx,
+	.start_tx	= mpsc_start_tx,
+	.stop_rx	= mpsc_stop_rx,
+	.enable_ms	= mpsc_enable_ms,
+	.break_ctl	= mpsc_break_ctl,
+	.startup	= mpsc_startup,
+	.shutdown	= mpsc_shutdown,
+	.set_termios	= mpsc_set_termios,
+	.type		= mpsc_type,
+	.release_port	= mpsc_release_port,
+	.request_port	= mpsc_request_port,
+	.config_port	= mpsc_config_port,
+	.verify_port	= mpsc_verify_port,
 };
 
 /*
@@ -1630,8 +1547,7 @@
  */
 
 #ifdef CONFIG_SERIAL_MPSC_CONSOLE
-static void
-mpsc_console_write(struct console *co, const char *s, uint count)
+static void mpsc_console_write(struct console *co, const char *s, uint count)
 {
 	struct mpsc_port_info *pi = &mpsc_ports[co->index];
 	u8 *bp, *dp, add_cr = 0;
@@ -1660,8 +1576,7 @@
 			if (add_cr) {
 				*(dp++) = '\r';
 				add_cr = 0;
-			}
-			else {
+			} else {
 				*(dp++) = *s;
 
 				if (*(s++) == '\n') { /* add '\r' after '\n' */
@@ -1673,11 +1588,12 @@
 			count--;
 		}
 
-		dma_cache_sync(pi->port.dev, (void *) bp, MPSC_TXBE_SIZE, DMA_BIDIRECTIONAL);
+		dma_cache_sync(pi->port.dev, (void *)bp, MPSC_TXBE_SIZE,
+				DMA_BIDIRECTIONAL);
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
 		if (pi->cache_mgmt) /* GT642[46]0 Res #COMM-2 */
 			flush_dcache_range((ulong)bp,
-				(ulong)bp + MPSC_TXBE_SIZE);
+					(ulong)bp + MPSC_TXBE_SIZE);
 #endif
 		mpsc_setup_tx_desc(pi, i, 0);
 		pi->txr_head = (pi->txr_head + 1) & (MPSC_TXR_ENTRIES - 1);
@@ -1690,11 +1606,9 @@
 	}
 
 	spin_unlock_irqrestore(&pi->tx_lock, iflags);
-	return;
 }
 
-static int __init
-mpsc_console_setup(struct console *co, char *options)
+static int __init mpsc_console_setup(struct console *co, char *options)
 {
 	struct mpsc_port_info *pi;
 	int baud, bits, parity, flow;
@@ -1723,17 +1637,16 @@
 }
 
 static struct console mpsc_console = {
-	.name   = MPSC_DEV_NAME,
-	.write  = mpsc_console_write,
-	.device = uart_console_device,
-	.setup  = mpsc_console_setup,
-	.flags  = CON_PRINTBUFFER,
-	.index  = -1,
-	.data   = &mpsc_reg,
+	.name	= MPSC_DEV_NAME,
+	.write	= mpsc_console_write,
+	.device	= uart_console_device,
+	.setup	= mpsc_console_setup,
+	.flags	= CON_PRINTBUFFER,
+	.index	= -1,
+	.data	= &mpsc_reg,
 };
 
-static int __init
-mpsc_late_console_init(void)
+static int __init mpsc_late_console_init(void)
 {
 	pr_debug("mpsc_late_console_init: Enter\n");
 
@@ -1755,43 +1668,40 @@
  *
  ******************************************************************************
  */
-static void
-mpsc_resource_err(char *s)
+static void mpsc_resource_err(char *s)
 {
 	printk(KERN_WARNING "MPSC: Platform device resource error in %s\n", s);
-	return;
 }
 
-static int
-mpsc_shared_map_regs(struct platform_device *pd)
+static int mpsc_shared_map_regs(struct platform_device *pd)
 {
 	struct resource	*r;
 
 	if ((r = platform_get_resource(pd, IORESOURCE_MEM,
-		MPSC_ROUTING_BASE_ORDER)) && request_mem_region(r->start,
-		MPSC_ROUTING_REG_BLOCK_SIZE, "mpsc_routing_regs")) {
-
+					MPSC_ROUTING_BASE_ORDER))
+			&& request_mem_region(r->start,
+				MPSC_ROUTING_REG_BLOCK_SIZE,
+				"mpsc_routing_regs")) {
 		mpsc_shared_regs.mpsc_routing_base = ioremap(r->start,
-			MPSC_ROUTING_REG_BLOCK_SIZE);
+				MPSC_ROUTING_REG_BLOCK_SIZE);
 		mpsc_shared_regs.mpsc_routing_base_p = r->start;
-	}
-	else {
+	} else {
 		mpsc_resource_err("MPSC routing base");
 		return -ENOMEM;
 	}
 
 	if ((r = platform_get_resource(pd, IORESOURCE_MEM,
-		MPSC_SDMA_INTR_BASE_ORDER)) && request_mem_region(r->start,
-		MPSC_SDMA_INTR_REG_BLOCK_SIZE, "sdma_intr_regs")) {
-
+					MPSC_SDMA_INTR_BASE_ORDER))
+			&& request_mem_region(r->start,
+				MPSC_SDMA_INTR_REG_BLOCK_SIZE,
+				"sdma_intr_regs")) {
 		mpsc_shared_regs.sdma_intr_base = ioremap(r->start,
 			MPSC_SDMA_INTR_REG_BLOCK_SIZE);
 		mpsc_shared_regs.sdma_intr_base_p = r->start;
-	}
-	else {
+	} else {
 		iounmap(mpsc_shared_regs.mpsc_routing_base);
 		release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
-			MPSC_ROUTING_REG_BLOCK_SIZE);
+				MPSC_ROUTING_REG_BLOCK_SIZE);
 		mpsc_resource_err("SDMA intr base");
 		return -ENOMEM;
 	}
@@ -1799,18 +1709,17 @@
 	return 0;
 }
 
-static void
-mpsc_shared_unmap_regs(void)
+static void mpsc_shared_unmap_regs(void)
 {
 	if (!mpsc_shared_regs.mpsc_routing_base) {
 		iounmap(mpsc_shared_regs.mpsc_routing_base);
 		release_mem_region(mpsc_shared_regs.mpsc_routing_base_p,
-			MPSC_ROUTING_REG_BLOCK_SIZE);
+				MPSC_ROUTING_REG_BLOCK_SIZE);
 	}
 	if (!mpsc_shared_regs.sdma_intr_base) {
 		iounmap(mpsc_shared_regs.sdma_intr_base);
 		release_mem_region(mpsc_shared_regs.sdma_intr_base_p,
-			MPSC_SDMA_INTR_REG_BLOCK_SIZE);
+				MPSC_SDMA_INTR_REG_BLOCK_SIZE);
 	}
 
 	mpsc_shared_regs.mpsc_routing_base = NULL;
@@ -1818,19 +1727,17 @@
 
 	mpsc_shared_regs.mpsc_routing_base_p = 0;
 	mpsc_shared_regs.sdma_intr_base_p = 0;
-
-	return;
 }
 
-static int
-mpsc_shared_drv_probe(struct platform_device *dev)
+static int mpsc_shared_drv_probe(struct platform_device *dev)
 {
 	struct mpsc_shared_pdata	*pdata;
 	int				 rc = -ENODEV;
 
 	if (dev->id == 0) {
-		if (!(rc = mpsc_shared_map_regs(dev)))  {
-			pdata = (struct mpsc_shared_pdata *)dev->dev.platform_data;
+		if (!(rc = mpsc_shared_map_regs(dev))) {
+			pdata = (struct mpsc_shared_pdata *)
+				dev->dev.platform_data;
 
 			mpsc_shared_regs.MPSC_MRR_m = pdata->mrr_val;
 			mpsc_shared_regs.MPSC_RCRR_m= pdata->rcrr_val;
@@ -1847,8 +1754,7 @@
 	return rc;
 }
 
-static int
-mpsc_shared_drv_remove(struct platform_device *dev)
+static int mpsc_shared_drv_remove(struct platform_device *dev)
 {
 	int	rc = -ENODEV;
 
@@ -1869,7 +1775,7 @@
 	.probe	= mpsc_shared_drv_probe,
 	.remove	= mpsc_shared_drv_remove,
 	.driver	= {
-		.name = MPSC_SHARED_NAME,
+		.name	= MPSC_SHARED_NAME,
 	},
 };
 
@@ -1881,55 +1787,51 @@
  ******************************************************************************
  */
 static struct uart_driver mpsc_reg = {
-	.owner       = THIS_MODULE,
-	.driver_name = MPSC_DRIVER_NAME,
-	.dev_name    = MPSC_DEV_NAME,
-	.major       = MPSC_MAJOR,
-	.minor       = MPSC_MINOR_START,
-	.nr          = MPSC_NUM_CTLRS,
-	.cons        = MPSC_CONSOLE,
+	.owner		= THIS_MODULE,
+	.driver_name	= MPSC_DRIVER_NAME,
+	.dev_name	= MPSC_DEV_NAME,
+	.major		= MPSC_MAJOR,
+	.minor		= MPSC_MINOR_START,
+	.nr		= MPSC_NUM_CTLRS,
+	.cons		= MPSC_CONSOLE,
 };
 
-static int
-mpsc_drv_map_regs(struct mpsc_port_info *pi, struct platform_device *pd)
+static int mpsc_drv_map_regs(struct mpsc_port_info *pi,
+		struct platform_device *pd)
 {
 	struct resource	*r;
 
-	if ((r = platform_get_resource(pd, IORESOURCE_MEM, MPSC_BASE_ORDER)) &&
-		request_mem_region(r->start, MPSC_REG_BLOCK_SIZE, "mpsc_regs")){
-
+	if ((r = platform_get_resource(pd, IORESOURCE_MEM, MPSC_BASE_ORDER))
+			&& request_mem_region(r->start, MPSC_REG_BLOCK_SIZE,
+			"mpsc_regs")) {
 		pi->mpsc_base = ioremap(r->start, MPSC_REG_BLOCK_SIZE);
 		pi->mpsc_base_p = r->start;
-	}
-	else {
+	} else {
 		mpsc_resource_err("MPSC base");
-		return -ENOMEM;
+		goto err;
 	}
 
 	if ((r = platform_get_resource(pd, IORESOURCE_MEM,
-		MPSC_SDMA_BASE_ORDER)) && request_mem_region(r->start,
-		MPSC_SDMA_REG_BLOCK_SIZE, "sdma_regs")) {
-
+					MPSC_SDMA_BASE_ORDER))
+			&& request_mem_region(r->start,
+				MPSC_SDMA_REG_BLOCK_SIZE, "sdma_regs")) {
 		pi->sdma_base = ioremap(r->start,MPSC_SDMA_REG_BLOCK_SIZE);
 		pi->sdma_base_p = r->start;
-	}
-	else {
+	} else {
 		mpsc_resource_err("SDMA base");
 		if (pi->mpsc_base) {
 			iounmap(pi->mpsc_base);
 			pi->mpsc_base = NULL;
 		}
-		return -ENOMEM;
+		goto err;
 	}
 
 	if ((r = platform_get_resource(pd,IORESOURCE_MEM,MPSC_BRG_BASE_ORDER))
-		&& request_mem_region(r->start, MPSC_BRG_REG_BLOCK_SIZE,
-		"brg_regs")) {
-
+			&& request_mem_region(r->start,
+				MPSC_BRG_REG_BLOCK_SIZE, "brg_regs")) {
 		pi->brg_base = ioremap(r->start, MPSC_BRG_REG_BLOCK_SIZE);
 		pi->brg_base_p = r->start;
-	}
-	else {
+	} else {
 		mpsc_resource_err("BRG base");
 		if (pi->mpsc_base) {
 			iounmap(pi->mpsc_base);
@@ -1939,14 +1841,15 @@
 			iounmap(pi->sdma_base);
 			pi->sdma_base = NULL;
 		}
-		return -ENOMEM;
+		goto err;
 	}
-
 	return 0;
+
+err:
+	return -ENOMEM;
 }
 
-static void
-mpsc_drv_unmap_regs(struct mpsc_port_info *pi)
+static void mpsc_drv_unmap_regs(struct mpsc_port_info *pi)
 {
 	if (!pi->mpsc_base) {
 		iounmap(pi->mpsc_base);
@@ -1968,13 +1871,10 @@
 	pi->mpsc_base_p = 0;
 	pi->sdma_base_p = 0;
 	pi->brg_base_p = 0;
-
-	return;
 }
 
-static void
-mpsc_drv_get_platform_data(struct mpsc_port_info *pi,
-	struct platform_device *pd, int num)
+static void mpsc_drv_get_platform_data(struct mpsc_port_info *pi,
+		struct platform_device *pd, int num)
 {
 	struct mpsc_pdata	*pdata;
 
@@ -2009,12 +1909,9 @@
 	pi->shared_regs = &mpsc_shared_regs;
 
 	pi->port.irq = platform_get_irq(pd, 0);
-
-	return;
 }
 
-static int
-mpsc_drv_probe(struct platform_device *dev)
+static int mpsc_drv_probe(struct platform_device *dev)
 {
 	struct mpsc_port_info	*pi;
 	int			rc = -ENODEV;
@@ -2030,47 +1927,46 @@
 			if (!(rc = mpsc_make_ready(pi))) {
 				spin_lock_init(&pi->tx_lock);
 				if (!(rc = uart_add_one_port(&mpsc_reg,
-					&pi->port)))
+								&pi->port))) {
 					rc = 0;
-				else {
-					mpsc_release_port(
-						(struct uart_port *)pi);
+				} else {
+					mpsc_release_port((struct uart_port *)
+							pi);
 					mpsc_drv_unmap_regs(pi);
 				}
-			}
-			else
+			} else {
 				mpsc_drv_unmap_regs(pi);
+			}
 		}
 	}
 
 	return rc;
 }
 
-static int
-mpsc_drv_remove(struct platform_device *dev)
+static int mpsc_drv_remove(struct platform_device *dev)
 {
 	pr_debug("mpsc_drv_exit: Removing MPSC %d\n", dev->id);
 
 	if (dev->id < MPSC_NUM_CTLRS) {
 		uart_remove_one_port(&mpsc_reg, &mpsc_ports[dev->id].port);
-		mpsc_release_port((struct uart_port *)&mpsc_ports[dev->id].port);
+		mpsc_release_port((struct uart_port *)
+				&mpsc_ports[dev->id].port);
 		mpsc_drv_unmap_regs(&mpsc_ports[dev->id]);
 		return 0;
-	}
-	else
+	} else {
 		return -ENODEV;
+	}
 }
 
 static struct platform_driver mpsc_driver = {
 	.probe	= mpsc_drv_probe,
 	.remove	= mpsc_drv_remove,
 	.driver	= {
-		.name = MPSC_CTLR_NAME,
+		.name	= MPSC_CTLR_NAME,
 	},
 };
 
-static int __init
-mpsc_drv_init(void)
+static int __init mpsc_drv_init(void)
 {
 	int	rc;
 
@@ -2085,24 +1981,21 @@
 				platform_driver_unregister(&mpsc_shared_driver);
 				uart_unregister_driver(&mpsc_reg);
 			}
-		}
-		else
+		} else {
 			uart_unregister_driver(&mpsc_reg);
+		}
 	}
 
 	return rc;
-
 }
 
-static void __exit
-mpsc_drv_exit(void)
+static void __exit mpsc_drv_exit(void)
 {
 	platform_driver_unregister(&mpsc_driver);
 	platform_driver_unregister(&mpsc_shared_driver);
 	uart_unregister_driver(&mpsc_reg);
 	memset(mpsc_ports, 0, sizeof(mpsc_ports));
 	memset(&mpsc_shared_regs, 0, sizeof(mpsc_shared_regs));
-	return;
 }
 
 module_init(mpsc_drv_init);
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 0fa9f67..794bd0f 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -88,6 +88,16 @@
 
 #define PWRDBG(fmt, arg...)	printk(KERN_DEBUG fmt , ## arg)
 
+#ifdef CONFIG_SERIAL_PMACZILOG_TTYS
+#define PMACZILOG_MAJOR		TTY_MAJOR
+#define PMACZILOG_MINOR		64
+#define PMACZILOG_NAME		"ttyS"
+#else
+#define PMACZILOG_MAJOR		204
+#define PMACZILOG_MINOR		192
+#define PMACZILOG_NAME		"ttyPZ"
+#endif
+
 
 /*
  * For the sake of early serial console, we can do a pre-probe
@@ -99,9 +109,10 @@
 
 static struct uart_driver pmz_uart_reg = {
 	.owner		=	THIS_MODULE,
-	.driver_name	=	"ttyS",
-	.dev_name	=	"ttyS",
-	.major		=	TTY_MAJOR,
+	.driver_name	=	PMACZILOG_NAME,
+	.dev_name	=	PMACZILOG_NAME,
+	.major		=	PMACZILOG_MAJOR,
+	.minor		=	PMACZILOG_MINOR,
 };
 
 
@@ -1587,7 +1598,7 @@
 	if (pm_state.event == mdev->ofdev.dev.power.power_state.event)
 		return 0;
 
-	pmz_debug("suspend, switching to state %d\n", pm_state);
+	pmz_debug("suspend, switching to state %d\n", pm_state.event);
 
 	state = pmz_uart_reg.state + uap->port.line;
 
@@ -1778,7 +1789,7 @@
 static int __init pmz_console_setup(struct console *co, char *options);
 
 static struct console pmz_console = {
-	.name	=	"ttyS",
+	.name	=	PMACZILOG_NAME,
 	.write	=	pmz_console_write,
 	.device	=	uart_console_device,
 	.setup	=	pmz_console_setup,
@@ -1802,7 +1813,6 @@
 	
 	pmz_uart_reg.nr = pmz_ports_count;
 	pmz_uart_reg.cons = PMACZILOG_CONSOLE;
-	pmz_uart_reg.minor = 64;
 
 	/*
 	 * Register this driver with the serial core
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 10bc020..3f26c4b 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -78,7 +78,7 @@
 
 #include <asm/hardware.h>
 
-#include <asm/arch/regs-serial.h>
+#include <asm/plat-s3c/regs-serial.h>
 #include <asm/arch/regs-gpio.h>
 
 /* structures */
diff --git a/drivers/serial/sb1250-duart.c b/drivers/serial/sb1250-duart.c
index 1d9d728..2d6c08b 100644
--- a/drivers/serial/sb1250-duart.c
+++ b/drivers/serial/sb1250-duart.c
@@ -25,6 +25,7 @@
 #define SUPPORT_SYSRQ
 #endif
 
+#include <linux/compiler.h>
 #include <linux/console.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
@@ -57,6 +58,12 @@
 #define SBD_CTRLREGS(line)	A_BCM1480_DUART_CTRLREG((line), 0)
 #define SBD_INT(line)		(K_BCM1480_INT_UART_0 + (line))
 
+#define DUART_CHANREG_SPACING	BCM1480_DUART_CHANREG_SPACING
+
+#define R_DUART_IMRREG(line)	R_BCM1480_DUART_IMRREG(line)
+#define R_DUART_INCHREG(line)	R_BCM1480_DUART_INCHREG(line)
+#define R_DUART_ISRREG(line)	R_BCM1480_DUART_ISRREG(line)
+
 #elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X)
 #include <asm/sibyte/sb1250_regs.h>
 #include <asm/sibyte/sb1250_int.h>
@@ -103,8 +110,6 @@
 
 static struct sbd_duart sbd_duarts[DUART_MAX_CHIP];
 
-#define __unused __attribute__((__unused__))
-
 
 /*
  * Reading and writing SB1250 DUART registers.
@@ -204,12 +209,12 @@
 	return loops;
 }
 
-static int __unused sbd_transmit_ready(struct sbd_port *sport)
+static int __maybe_unused sbd_transmit_ready(struct sbd_port *sport)
 {
 	return read_sbdchn(sport, R_DUART_STATUS) & M_DUART_TX_RDY;
 }
 
-static int __unused sbd_transmit_drain(struct sbd_port *sport)
+static int __maybe_unused sbd_transmit_drain(struct sbd_port *sport)
 {
 	int loops = 10000;
 
@@ -664,7 +669,7 @@
 
 static int sbd_map_port(struct uart_port *uport)
 {
-	static const char *err = KERN_ERR "sbd: Cannot map MMIO\n";
+	const char *err = KERN_ERR "sbd: Cannot map MMIO\n";
 	struct sbd_port *sport = to_sport(uport);
 	struct sbd_duart *duart = sport->duart;
 
@@ -691,8 +696,7 @@
 
 static int sbd_request_port(struct uart_port *uport)
 {
-	static const char *err = KERN_ERR
-				 "sbd: Unable to reserve MMIO resource\n";
+	const char *err = KERN_ERR "sbd: Unable to reserve MMIO resource\n";
 	struct sbd_duart *duart = to_sport(uport)->duart;
 	int map_guard;
 	int ret = 0;
@@ -755,7 +759,7 @@
 }
 
 
-static struct uart_ops sbd_ops = {
+static const struct uart_ops sbd_ops = {
 	.tx_empty	= sbd_tx_empty,
 	.set_mctrl	= sbd_set_mctrl,
 	.get_mctrl	= sbd_get_mctrl,
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 9c57486..a055f58 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -626,7 +626,7 @@
 	tmp.hub6	    = port->hub6;
 	tmp.io_type         = port->iotype;
 	tmp.iomem_reg_shift = port->regshift;
-	tmp.iomem_base      = (void *)port->mapbase;
+	tmp.iomem_base      = (void *)(unsigned long)port->mapbase;
 
 	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
 		return -EFAULT;
@@ -1146,11 +1146,14 @@
 
 	/*
 	 * These are the bits that are used to setup various
-	 * flags in the low level driver.
+	 * flags in the low level driver. We can ignore the Bfoo
+	 * bits in c_cflag; c_[io]speed will always be set
+	 * appropriately by set_termios() in tty_ioctl.c
 	 */
 #define RELEVANT_IFLAG(iflag)	((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
 	if ((cflag ^ old_termios->c_cflag) == 0 &&
+	    tty->termios->c_ospeed == old_termios->c_ospeed &&
+	    tty->termios->c_ispeed == old_termios->c_ispeed &&
 	    RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
 		return;
 
@@ -1666,10 +1669,11 @@
 		return 0;
 
 	mmio = port->iotype >= UPIO_MEM;
-	ret = sprintf(buf, "%d: uart:%s %s%08lX irq:%d",
+	ret = sprintf(buf, "%d: uart:%s %s%08llX irq:%d",
 			port->line, uart_type(port),
 			mmio ? "mmio:0x" : "port:",
-			mmio ? port->mapbase : (unsigned long) port->iobase,
+			mmio ? (unsigned long long)port->mapbase
+		             : (unsigned long long) port->iobase,
 			port->irq);
 
 	if (port->type == PORT_UNKNOWN) {
@@ -2069,7 +2073,7 @@
 	case UPIO_TSI:
 	case UPIO_DWAPB:
 		snprintf(address, sizeof(address),
-			 "MMIO 0x%lx", port->mapbase);
+			 "MMIO 0x%llx", (unsigned long long)port->mapbase);
 		break;
 	default:
 		strlcpy(address, "*unknown*", sizeof(address));
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index a0ea435..7c8d78f 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -943,6 +943,7 @@
 	PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
 	PCMCIA_MFC_DEVICE_PROD_ID12(2,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
 	PCMCIA_MFC_DEVICE_PROD_ID12(3,"Elan","Serial Port: SL432",0x3beb8cf2,0x1cce7ac4),
+	PCMCIA_DEVICE_MANF_CARD(0x0279, 0x950b),
 	/* too generic */
 	/* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
 	/* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index 1deb576..0930e2a 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -37,7 +37,7 @@
 
 #include <asm/io.h>
 
-static char *serial_version = "1.09";
+static char *serial_version = "1.10";
 static char *serial_name = "TX39/49 Serial driver";
 
 #define PASS_LIMIT	256
@@ -436,8 +436,10 @@
 	struct uart_txx9_port *up = (struct uart_txx9_port *)port;
 	unsigned int ret;
 
-	ret =  ((sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS)
-		| ((sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS);
+	/* no modem control lines */
+	ret = TIOCM_CAR | TIOCM_DSR;
+	ret |= (sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS;
+	ret |= (sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS;
 
 	return ret;
 }
@@ -557,6 +559,12 @@
 	unsigned long flags;
 	unsigned int baud, quot;
 
+	/*
+	 * We don't support modem control lines.
+	 */
+	termios->c_cflag &= ~(HUPCL | CMSPAR);
+	termios->c_cflag |= CLOCAL;
+
 	cval = sio_in(up, TXX9_SILCR);
 	/* byte size and parity */
 	cval &= ~TXX9_SILCR_UMODE_MASK;
@@ -1043,8 +1051,9 @@
 		ret = serial_txx9_register_port(&port);
 		if (ret < 0) {
 			dev_err(&dev->dev, "unable to register port at index %d "
-				"(IO%x MEM%lx IRQ%d): %d\n", i,
-				p->iobase, p->mapbase, p->irq, ret);
+				"(IO%x MEM%llx IRQ%d): %d\n", i,
+				p->iobase, (unsigned long long)p->mapbase,
+				p->irq, ret);
 		}
 	}
 	return 0;
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 672cd10..053fca4 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -12,6 +12,7 @@
  *   Modified to support multiple serial ports. Stuart Menefy (May 2000).
  *   Modified to support SecureEdge. David McCullough (2002)
  *   Modified to support SH7300 SCIF. Takashi Kusuda (Jun 2003).
+ *   Removed SH7300 support (Jul 2007).
  *
  * This file is subject to the terms and conditions of the GNU General Public
  * License.  See the file "COPYING" in the main directory of this archive
@@ -289,13 +290,7 @@
 #endif
 
 #if defined(SCIF_ONLY) || defined(SCI_AND_SCIF)
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) 
-/* SH7300 doesn't use RTS/CTS */
-static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
-{
-	sci_out(port, SCFCR, 0);
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
+#if defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
 static void sci_init_pins_scif(struct uart_port* port, unsigned int cflag)
 {
 	unsigned int fcr_val = 0;
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index 247fb66..cf75466 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -9,6 +9,7 @@
  *  Modified to support multiple serial ports. Stuart Menefy (May 2000).
  *  Modified to support SH7300(SH-Mobile) SCIF. Takashi Kusuda (Jun 2003).
  *  Modified to support H8/300 Series Yoshinori Sato (Feb 2004).
+ *  Removed SH7300 support (Jul 2007).
  */
 #include <linux/serial_core.h>
 #include <asm/io.h>
@@ -23,13 +24,10 @@
 #endif
 #endif
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7708)
-# define SCSPTR 0xffffff7c /* 8 bit */
-# define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
-# define SCI_ONLY
-#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7709) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7706)
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7708) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)
 # define SCPCR  0xA4000116 /* 16 bit SCI and SCIF */
 # define SCPDR  0xA4000136 /* 8  bit SCI and SCIF */
 # define SCSCR_INIT(port)          0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
@@ -73,11 +71,6 @@
 # define SCIF_ORER 0x0001  /* overrun error bit */
 # define SCSCR_INIT(port)          0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
 # define SCIF_ONLY
-#elif defined(CONFIG_CPU_SUBTYPE_SH7300)
-# define SCPCR  0xA4050116        /* 16 bit SCIF */
-# define SCPDR  0xA4050136        /* 16 bit SCIF */
-# define SCSCR_INIT(port)  0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
-# define SCIF_ONLY
 #elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712)
 # define SCSPTR0 0xA4400000	  /* 16 bit SCIF */
 # define SCI_NPORTS 2
@@ -86,12 +79,6 @@
 # define PBCR 0xa4050102
 # define SCSCR_INIT(port)          0x3B
 # define SCIF_ONLY
-#elif defined(CONFIG_CPU_SUBTYPE_SH73180)
-# define SCPDR  0xA4050138        /* 16 bit SCIF */
-# define SCSPTR2 SCPDR
-# define SCIF_ORER 0x0001   /* overrun error bit */
-# define SCSCR_INIT(port)  0x0038 /* TIE=0,RIE=0,TE=1,RE=1 */
-# define SCIF_ONLY
 #elif defined(CONFIG_CPU_SUBTYPE_SH7343)
 # define SCSPTR0 0xffe00010	/* 16 bit SCIF */
 # define SCSPTR1 0xffe10010	/* 16 bit SCIF */
@@ -230,7 +217,7 @@
 #define SCIF_RDF   0x0002 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
 #define SCIF_DR    0x0001 /* 7705 SCIF, 7707 SCIF, 7709 SCIF, 7750 SCIF */
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
 #define SCIF_ORER    0x0200
 #define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK | SCIF_ORER)
 #define SCIF_RFDC_MASK 0x007f
@@ -259,7 +246,7 @@
 # define SCxSR_ERRORS(port)		SCIF_ERRORS
 # define SCxSR_RDxF(port)               SCIF_RDF
 # define SCxSR_TDxE(port)               SCIF_TDFE
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
 # define SCxSR_ORER(port)		SCIF_ORER
 #else
 # define SCxSR_ORER(port)		0x0000
@@ -267,13 +254,13 @@
 # define SCxSR_FER(port)		SCIF_FER
 # define SCxSR_PER(port)		SCIF_PER
 # define SCxSR_BRK(port)		SCIF_BRK
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
 # define SCxSR_RDxF_CLEAR(port)         (sci_in(port,SCxSR)&0xfffc)
 # define SCxSR_ERROR_CLEAR(port)        (sci_in(port,SCxSR)&0xfd73)
 # define SCxSR_TDxE_CLEAR(port)         (sci_in(port,SCxSR)&0xffdf)
 # define SCxSR_BREAK_CLEAR(port)        (sci_in(port,SCxSR)&0xffe3)
 #else
-/* SH7705 can also use this, clearing is same between 7705 and 7709 and 7300 */
+/* SH7705 can also use this, clearing is same between 7705 and 7709 */
 # define SCxSR_RDxF_CLEAR(port)		0x00fc
 # define SCxSR_ERROR_CLEAR(port)	0x0073
 # define SCxSR_TDxE_CLEAR(port)		0x00df
@@ -375,8 +362,7 @@
   CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
 #define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
 	  CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
-#elif defined(CONFIG_CPU_SUBTYPE_SH7300) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7705) 
+#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
 #define SCIF_FNS(name, scif_offset, scif_size) \
   CPU_SCIF_FNS(name, scif_offset, scif_size)
 #else
@@ -402,8 +388,7 @@
   CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
 #endif
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7705) 
+#if defined(CONFIG_CPU_SUBTYPE_SH7705)
 
 SCIF_FNS(SCSMR,  0x00, 16)
 SCIF_FNS(SCBRR,  0x04,  8)
@@ -485,16 +470,10 @@
 };
 #endif
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7708)
-static inline int sci_rxd_in(struct uart_port *port)
-{
-	if (port->mapbase == 0xfffffe80)
-		return ctrl_inb(SCSPTR)&0x01 ? 1 : 0; /* SCI */
-	return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7709) || \
-      defined(CONFIG_CPU_SUBTYPE_SH7706)
+#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7708) || \
+    defined(CONFIG_CPU_SUBTYPE_SH7709)
 static inline int sci_rxd_in(struct uart_port *port)
 {
 	if (port->mapbase == 0xfffffe80)
@@ -562,18 +541,6 @@
 		return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
 	return 1;
 }
-#elif defined(CONFIG_CPU_SUBTYPE_SH7300)
-static inline int sci_rxd_in(struct uart_port *port)
-{
-        if (port->mapbase == 0xa4430000)
-                return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCIF0 */
-        return 1;
-}
-#elif defined(CONFIG_CPU_SUBTYPE_SH73180)
-static inline int sci_rxd_in(struct uart_port *port)
-{
-	return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCIF0 */
-}
 #elif defined(CONFIG_CPU_SUBTYPE_SH7343)
 static inline int sci_rxd_in(struct uart_port *port)
 {
@@ -721,8 +688,7 @@
  * -- Mitch Davis - 15 Jul 2000
  */
 
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7780) || \
+#if defined(CONFIG_CPU_SUBTYPE_SH7780) || \
     defined(CONFIG_CPU_SUBTYPE_SH7785)
 #define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(16*bps)-1)
 #elif defined(CONFIG_CPU_SUBTYPE_SH7705)
diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c
index b45ba53..70a09a3 100644
--- a/drivers/serial/suncore.c
+++ b/drivers/serial/suncore.c
@@ -16,9 +16,10 @@
 #include <linux/tty.h>
 #include <linux/errno.h>
 #include <linux/string.h>
+#include <linux/serial_core.h>
 #include <linux/init.h>
 
-#include <asm/oplib.h>
+#include <asm/prom.h>
 
 #include "suncore.h"
 
@@ -26,92 +27,60 @@
 
 EXPORT_SYMBOL(sunserial_current_minor);
 
+int sunserial_console_match(struct console *con, struct device_node *dp,
+			    struct uart_driver *drv, int line)
+{
+	int off;
+
+	if (!con || of_console_device != dp)
+		return 0;
+
+	off = 0;
+	if (of_console_options &&
+	    *of_console_options == 'b')
+		off = 1;
+
+	if ((line & 1) != off)
+		return 0;
+
+	con->index = line;
+	drv->cons = con;
+	add_preferred_console(con->name, line, NULL);
+
+	return 1;
+}
+EXPORT_SYMBOL(sunserial_console_match);
+
 void
 sunserial_console_termios(struct console *con)
 {
-	char mode[16], buf[16], *s;
+	struct device_node *dp;
+	const char *od, *mode, *s;
 	char mode_prop[] = "ttyX-mode";
-	char cd_prop[]   = "ttyX-ignore-cd";
-	char dtr_prop[]  = "ttyX-rts-dtr-off";
-	char *ssp_console_modes_prop = "ssp-console-modes";
 	int baud, bits, stop, cflag;
 	char parity;
-	int carrier = 0;
-	int rtsdtr = 1;
-	int topnd, nd;
 
-	if (!serial_console)
-		return;
+	dp = of_find_node_by_path("/options");
+	od = of_get_property(dp, "output-device", NULL);
+	if (!strcmp(od, "rsc")) {
+		mode = of_get_property(of_console_device,
+				       "ssp-console-modes", NULL);
+		if (!mode)
+			mode = "115200,8,n,1,-";
+	} else {
+		char c;
 
-	switch (serial_console) {
-	case PROMDEV_OTTYA:
-		mode_prop[3] = 'a';
-		cd_prop[3] = 'a';
-		dtr_prop[3] = 'a';
-		break;
+		c = 'a';
+		if (of_console_options)
+			c = *of_console_options;
 
-	case PROMDEV_OTTYB:
-		mode_prop[3] = 'b';
-		cd_prop[3] = 'b';
-		dtr_prop[3] = 'b';
-		break;
+		mode_prop[3] = c;
 
-	case PROMDEV_ORSC:
-
-		nd = prom_pathtoinode("rsc");
-		if (!nd) {
-			strcpy(mode, "115200,8,n,1,-");
-			goto no_options;
-		}
-
-		if (!prom_node_has_property(nd, ssp_console_modes_prop)) {
-			strcpy(mode, "115200,8,n,1,-");
-			goto no_options;
-		}
-
-		memset(mode, 0, sizeof(mode));
-		prom_getstring(nd, ssp_console_modes_prop, mode, sizeof(mode));
-		goto no_options;
-
-	default:
-		strcpy(mode, "9600,8,n,1,-");
-		goto no_options;
+		mode = of_get_property(dp, mode_prop, NULL);
+		if (!mode)
+			mode = "9600,8,n,1,-";
 	}
 
-	topnd = prom_getchild(prom_root_node);
-	nd = prom_searchsiblings(topnd, "options");
-	if (!nd) {
-		strcpy(mode, "9600,8,n,1,-");
-		goto no_options;
-	}
-
-	if (!prom_node_has_property(nd, mode_prop)) {
-		strcpy(mode, "9600,8,n,1,-");
-		goto no_options;
-	}
-
-	memset(mode, 0, sizeof(mode));
-	prom_getstring(nd, mode_prop, mode, sizeof(mode));
-
-	if (prom_node_has_property(nd, cd_prop)) {
-		memset(buf, 0, sizeof(buf));
-		prom_getstring(nd, cd_prop, buf, sizeof(buf));
-		if (!strcmp(buf, "false"))
-			carrier = 1;
-
-		/* XXX: this is unused below. */
-	}
-
-	if (prom_node_has_property(nd, dtr_prop)) {
-		memset(buf, 0, sizeof(buf));
-		prom_getstring(nd, dtr_prop, buf, sizeof(buf));
-		if (!strcmp(buf, "false"))
-			rtsdtr = 0;
-
-		/* XXX: this is unused below. */
-	}
-
-no_options:
 	cflag = CREAD | HUPCL | CLOCAL;
 
 	s = mode;
diff --git a/drivers/serial/suncore.h b/drivers/serial/suncore.h
index 513916a..829d7d6 100644
--- a/drivers/serial/suncore.h
+++ b/drivers/serial/suncore.h
@@ -24,6 +24,8 @@
 
 extern int sunserial_current_minor;
 
+extern int sunserial_console_match(struct console *, struct device_node *,
+				   struct uart_driver *, int);
 extern void sunserial_console_termios(struct console *);
 
 #endif /* !(_SERIAL_SUN_H) */
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index d82be42..8ff900b 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -520,16 +520,6 @@
 	.data	=	&sunhv_reg,
 };
 
-static inline struct console *SUNHV_CONSOLE(void)
-{
-	if (con_is_present())
-		return NULL;
-
-	sunhv_console.index = 0;
-
-	return &sunhv_console;
-}
-
 static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match)
 {
 	struct uart_port *port;
@@ -582,7 +572,8 @@
 	sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64;
 	sunserial_current_minor += 1;
 
-	sunhv_reg.cons = SUNHV_CONSOLE();
+	sunserial_console_match(&sunhv_console, op->node,
+				&sunhv_reg, port->line);
 
 	err = uart_add_one_port(&sunhv_reg, port);
 	if (err)
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 8a0f9e4..ff610c2 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -38,7 +38,7 @@
 #include <asm/prom.h>
 #include <asm/of_device.h>
 
-#if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#if defined(CONFIG_SERIAL_SUNSAB_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
 #endif
 
@@ -58,6 +58,7 @@
 	unsigned char			interrupt_mask1;/* ISR1 masking		*/
 	unsigned char			pvr_dtr_bit;	/* Which PVR bit is DTR */
 	unsigned char			pvr_dsr_bit;	/* Which PVR bit is DSR */
+	unsigned int			gis_shift;
 	int				type;		/* SAB82532 version	*/
 
 	/* Setting configuration bits while the transmitter is active
@@ -305,13 +306,15 @@
 	struct tty_struct *tty;
 	union sab82532_irq_status status;
 	unsigned long flags;
+	unsigned char gis;
 
 	spin_lock_irqsave(&up->port.lock, flags);
 
 	status.stat = 0;
-	if (readb(&up->regs->r.gis) & SAB82532_GIS_ISA0)
+	gis = readb(&up->regs->r.gis) >> up->gis_shift;
+	if (gis & 1)
 		status.sreg.isr0 = readb(&up->regs->r.isr0);
-	if (readb(&up->regs->r.gis) & SAB82532_GIS_ISA1)
+	if (gis & 2)
 		status.sreg.isr1 = readb(&up->regs->r.isr1);
 
 	tty = NULL;
@@ -327,35 +330,6 @@
 			transmit_chars(up, &status);
 	}
 
-	spin_unlock(&up->port.lock);
-
-	if (tty)
-		tty_flip_buffer_push(tty);
-
-	up++;
-
-	spin_lock(&up->port.lock);
-
-	status.stat = 0;
-	if (readb(&up->regs->r.gis) & SAB82532_GIS_ISB0)
-		status.sreg.isr0 = readb(&up->regs->r.isr0);
-	if (readb(&up->regs->r.gis) & SAB82532_GIS_ISB1)
-		status.sreg.isr1 = readb(&up->regs->r.isr1);
-
-	tty = NULL;
-	if (status.stat) {
-		if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |
-					 SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) ||
-		    (status.sreg.isr1 & SAB82532_ISR1_BRK))
-
-			tty = receive_chars(up, &status);
-		if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) ||
-		    (status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC)))
-			check_status(up, &status);
-		if (status.sreg.isr1 & (SAB82532_ISR1_ALLS | SAB82532_ISR1_XPR))
-			transmit_chars(up, &status);
-	}
-
 	spin_unlock_irqrestore(&up->port.lock, flags);
 
 	if (tty)
@@ -539,6 +513,10 @@
 	struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
 	unsigned long flags;
 	unsigned char tmp;
+	int err = request_irq(up->port.irq, sunsab_interrupt,
+			      IRQF_SHARED, "sab", up);
+	if (err)
+		return err;
 
 	spin_lock_irqsave(&up->port.lock, flags);
 
@@ -641,6 +619,7 @@
 #endif
 
 	spin_unlock_irqrestore(&up->port.lock, flags);
+	free_irq(up->port.irq, up);
 }
 
 /*
@@ -968,22 +947,6 @@
 
 static inline struct console *SUNSAB_CONSOLE(void)
 {
-	int i;
-
-	if (con_is_present())
-		return NULL;
-
-	for (i = 0; i < num_channels; i++) {
-		int this_minor = sunsab_reg.minor + i;
-
-		if ((this_minor - 64) == (serial_console - 1))
-			break;
-	}
-	if (i == num_channels)
-		return NULL;
-
-	sunsab_console.index = i;
-
 	return &sunsab_console;
 }
 #else
@@ -1024,9 +987,11 @@
 	if ((up->port.line & 0x1) == 0) {
 		up->pvr_dsr_bit = (1 << 0);
 		up->pvr_dtr_bit = (1 << 1);
+		up->gis_shift = 2;
 	} else {
 		up->pvr_dsr_bit = (1 << 3);
 		up->pvr_dtr_bit = (1 << 2);
+		up->gis_shift = 0;
 	}
 	up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4);
 	writeb(up->cached_pvr, &up->regs->w.pvr);
@@ -1039,19 +1004,6 @@
 	up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT;
 	up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT;
 
-	if (!(up->port.line & 0x01)) {
-		int err;
-
-		err = request_irq(up->port.irq, sunsab_interrupt,
-				  IRQF_SHARED, "sab", up);
-		if (err) {
-			of_iounmap(&op->resource[0],
-				   up->port.membase,
-				   sizeof(union sab82532_async_regs));
-			return err;
-		}
-	}
-
 	return 0;
 }
 
@@ -1067,47 +1019,60 @@
 			      0,
 			      (inst * 2) + 0);
 	if (err)
-		return err;
+		goto out;
 
 	err = sunsab_init_one(&up[1], op,
 			      sizeof(union sab82532_async_regs),
 			      (inst * 2) + 1);
-	if (err) {
-		of_iounmap(&op->resource[0],
-			   up[0].port.membase,
-			   sizeof(union sab82532_async_regs));
-		free_irq(up[0].port.irq, &up[0]);
-		return err;
-	}
+	if (err)
+		goto out1;
 
-	uart_add_one_port(&sunsab_reg, &up[0].port);
-	uart_add_one_port(&sunsab_reg, &up[1].port);
+	sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+				&sunsab_reg, up[0].port.line);
+
+	sunserial_console_match(SUNSAB_CONSOLE(), op->node,
+				&sunsab_reg, up[1].port.line);
+
+	err = uart_add_one_port(&sunsab_reg, &up[0].port);
+	if (err)
+		goto out2;
+
+	err = uart_add_one_port(&sunsab_reg, &up[1].port);
+	if (err)
+		goto out3;
 
 	dev_set_drvdata(&op->dev, &up[0]);
 
 	inst++;
 
 	return 0;
-}
 
-static void __devexit sab_remove_one(struct uart_sunsab_port *up)
-{
-	struct of_device *op = to_of_device(up->port.dev);
-
-	uart_remove_one_port(&sunsab_reg, &up->port);
-	if (!(up->port.line & 1))
-		free_irq(up->port.irq, up);
+out3:
+	uart_remove_one_port(&sunsab_reg, &up[0].port);
+out2:
 	of_iounmap(&op->resource[0],
-		   up->port.membase,
+		   up[1].port.membase,
 		   sizeof(union sab82532_async_regs));
+out1:
+	of_iounmap(&op->resource[0],
+		   up[0].port.membase,
+		   sizeof(union sab82532_async_regs));
+out:
+	return err;
 }
 
 static int __devexit sab_remove(struct of_device *op)
 {
 	struct uart_sunsab_port *up = dev_get_drvdata(&op->dev);
 
-	sab_remove_one(&up[0]);
-	sab_remove_one(&up[1]);
+	uart_remove_one_port(&sunsab_reg, &up[1].port);
+	uart_remove_one_port(&sunsab_reg, &up[0].port);
+	of_iounmap(&op->resource[0],
+		   up[1].port.membase,
+		   sizeof(union sab82532_async_regs));
+	of_iounmap(&op->resource[0],
+		   up[0].port.membase,
+		   sizeof(union sab82532_async_regs));
 
 	dev_set_drvdata(&op->dev, NULL);
 
@@ -1154,6 +1119,7 @@
 
 		sunsab_reg.minor = sunserial_current_minor;
 		sunsab_reg.nr = num_channels;
+		sunsab_reg.cons = SUNSAB_CONSOLE();
 
 		err = uart_register_driver(&sunsab_reg);
 		if (err) {
@@ -1164,7 +1130,6 @@
 		}
 
 		sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64;
-		sunsab_reg.cons = SUNSAB_CONSOLE();
 		sunserial_current_minor += num_channels;
 	}
 
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 26d720b..e074943 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -1198,10 +1198,11 @@
 	if (up->port.type == PORT_UNKNOWN)
 		return -ENODEV;
 
-	printk("%s: %s port at %lx, irq %u\n",
+	printk("%s: %s port at %llx, irq %u\n",
 	       to_of_device(up->port.dev)->node->full_name,
 	       (up->su_type == SU_PORT_KBD) ? "Keyboard" : "Mouse",
-	       up->port.mapbase, up->port.irq);
+	       (unsigned long long) up->port.mapbase,
+	       up->port.irq);
 
 #ifdef CONFIG_SERIO
 	serio = &up->serio;
@@ -1371,28 +1372,12 @@
  *	Register console.
  */
 
-static inline struct console *SUNSU_CONSOLE(int num_uart)
+static inline struct console *SUNSU_CONSOLE(void)
 {
-	int i;
-
-	if (con_is_present())
-		return NULL;
-
-	for (i = 0; i < num_uart; i++) {
-		int this_minor = sunsu_reg.minor + i;
-
-		if ((this_minor - 64) == (serial_console - 1))
-			break;
-	}
-	if (i == num_uart)
-		return NULL;
-
-	sunsu_console.index = i;
-
 	return &sunsu_console;
 }
 #else
-#define SUNSU_CONSOLE(num_uart)		(NULL)
+#define SUNSU_CONSOLE()			(NULL)
 #define sunsu_serial_console_init()	do { } while (0)
 #endif
 
@@ -1482,6 +1467,8 @@
 
 	up->port.ops = &sunsu_pops;
 
+	sunserial_console_match(SUNSU_CONSOLE(), dp,
+				&sunsu_reg, up->port.line);
 	err = uart_add_one_port(&sunsu_reg, &up->port);
 	if (err)
 		goto out_unmap;
@@ -1572,7 +1559,6 @@
 			return err;
 		sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64;
 		sunserial_current_minor += num_uart;
-		sunsu_reg.cons = SUNSU_CONSOLE(num_uart);
 	}
 
 	err = of_register_driver(&su_driver, &of_bus_type);
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 0a3e10a..283bef0 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1226,23 +1226,6 @@
 
 static inline struct console *SUNZILOG_CONSOLE(void)
 {
-	int i;
-
-	if (con_is_present())
-		return NULL;
-
-	for (i = 0; i < NUM_CHANNELS; i++) {
-		int this_minor = sunzilog_reg.minor + i;
-
-		if ((this_minor - 64) == (serial_console - 1))
-			break;
-	}
-	if (i == NUM_CHANNELS)
-		return NULL;
-
-	sunzilog_console_ops.index = i;
-	sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
-
 	return &sunzilog_console_ops;
 }
 
@@ -1428,12 +1411,18 @@
 	sunzilog_init_hw(&up[1]);
 
 	if (!keyboard_mouse) {
+		if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+					    &sunzilog_reg, up[0].port.line))
+			up->flags |= SUNZILOG_FLAG_IS_CONS;
 		err = uart_add_one_port(&sunzilog_reg, &up[0].port);
 		if (err) {
 			of_iounmap(&op->resource[0],
 				   rp, sizeof(struct zilog_layout));
 			return err;
 		}
+		if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
+					    &sunzilog_reg, up[1].port.line))
+			up->flags |= SUNZILOG_FLAG_IS_CONS;
 		err = uart_add_one_port(&sunzilog_reg, &up[1].port);
 		if (err) {
 			uart_remove_one_port(&sunzilog_reg, &up[0].port);
@@ -1442,14 +1431,16 @@
 			return err;
 		}
 	} else {
-		printk(KERN_INFO "%s: Keyboard at MMIO 0x%lx (irq = %d) "
+		printk(KERN_INFO "%s: Keyboard at MMIO 0x%llx (irq = %d) "
 		       "is a %s\n",
-		       op->dev.bus_id, up[0].port.mapbase, op->irqs[0],
-		       sunzilog_type (&up[0].port));
-		printk(KERN_INFO "%s: Mouse at MMIO 0x%lx (irq = %d) "
+		       op->dev.bus_id,
+		       (unsigned long long) up[0].port.mapbase,
+		       op->irqs[0], sunzilog_type(&up[0].port));
+		printk(KERN_INFO "%s: Mouse at MMIO 0x%llx (irq = %d) "
 		       "is a %s\n",
-		       op->dev.bus_id, up[1].port.mapbase, op->irqs[0],
-		       sunzilog_type (&up[1].port));
+		       op->dev.bus_id,
+		       (unsigned long long) up[1].port.mapbase,
+		       op->irqs[0], sunzilog_type(&up[1].port));
 	}
 
 	dev_set_drvdata(&op->dev, &up[0]);
@@ -1531,7 +1522,6 @@
 			goto out_free_tables;
 
 		sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
-		sunzilog_reg.cons = SUNZILOG_CONSOLE();
 
 		sunserial_current_minor += uart_count;
 	}
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index f5051cf..dfef83f 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -1,7 +1,8 @@
 /*
  * uartlite.c: Serial driver for Xilinx uartlite serial controller
  *
- * Peter Korsgaard <jacmet@sunsite.dk>
+ * Copyright (C) 2006 Peter Korsgaard <jacmet@sunsite.dk>
+ * Copyright (C) 2007 Secret Lab Technologies Ltd.
  *
  * This file is licensed under the terms of the GNU General Public License
  * version 2.  This program is licensed "as is" without any warranty of any
@@ -17,14 +18,23 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <asm/io.h>
+#if defined(CONFIG_OF)
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#endif
 
+#define ULITE_NAME		"ttyUL"
 #define ULITE_MAJOR		204
 #define ULITE_MINOR		187
 #define ULITE_NR_UARTS		4
 
-/* For register details see datasheet:
-   http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf
-*/
+/* ---------------------------------------------------------------------
+ * Register definitions
+ *
+ * For register details see datasheet:
+ * http://www.xilinx.com/bvdocs/ipcenter/data_sheet/opb_uartlite.pdf
+ */
+
 #define ULITE_RX		0x00
 #define ULITE_TX		0x04
 #define ULITE_STATUS		0x08
@@ -46,7 +56,11 @@
 #define ULITE_CONTROL_IE	0x10
 
 
-static struct uart_port ports[ULITE_NR_UARTS];
+static struct uart_port ulite_ports[ULITE_NR_UARTS];
+
+/* ---------------------------------------------------------------------
+ * Core UART driver operations
+ */
 
 static int ulite_receive(struct uart_port *port, int stat)
 {
@@ -307,6 +321,10 @@
 	.verify_port	= ulite_verify_port
 };
 
+/* ---------------------------------------------------------------------
+ * Console driver operations
+ */
+
 #ifdef CONFIG_SERIAL_UARTLITE_CONSOLE
 static void ulite_console_wait_tx(struct uart_port *port)
 {
@@ -329,7 +347,7 @@
 static void ulite_console_write(struct console *co, const char *s,
 				unsigned int count)
 {
-	struct uart_port *port = &ports[co->index];
+	struct uart_port *port = &ulite_ports[co->index];
 	unsigned long flags;
 	unsigned int ier;
 	int locked = 1;
@@ -355,6 +373,31 @@
 		spin_unlock_irqrestore(&port->lock, flags);
 }
 
+#if defined(CONFIG_OF)
+static inline void __init ulite_console_of_find_device(int id)
+{
+	struct device_node *np;
+	struct resource res;
+	const unsigned int *of_id;
+	int rc;
+
+	for_each_compatible_node(np, NULL, "xilinx,uartlite") {
+		of_id = of_get_property(np, "port-number", NULL);
+		if ((!of_id) || (*of_id != id))
+			continue;
+
+		rc = of_address_to_resource(np, 0, &res);
+		if (rc)
+			continue;
+
+		ulite_ports[id].mapbase = res.start;
+		return;
+	}
+}
+#else /* CONFIG_OF */
+static inline void __init ulite_console_of_find_device(int id) { /* do nothing */ }
+#endif /* CONFIG_OF */
+
 static int __init ulite_console_setup(struct console *co, char *options)
 {
 	struct uart_port *port;
@@ -366,11 +409,23 @@
 	if (co->index < 0 || co->index >= ULITE_NR_UARTS)
 		return -EINVAL;
 
-	port = &ports[co->index];
+	port = &ulite_ports[co->index];
+
+	/* Check if it is an OF device */
+	if (!port->mapbase)
+		ulite_console_of_find_device(co->index);
+
+	/* Do we have a device now? */
+	if (!port->mapbase) {
+		pr_debug("console on ttyUL%i not present\n", co->index);
+		return -ENODEV;
+	}
 
 	/* not initialized yet? */
-	if (!port->membase)
-		return -ENODEV;
+	if (!port->membase) {
+		if (ulite_request_port(port))
+			return -ENODEV;
+	}
 
 	if (options)
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -381,7 +436,7 @@
 static struct uart_driver ulite_uart_driver;
 
 static struct console ulite_console = {
-	.name	= "ttyUL",
+	.name	= ULITE_NAME,
 	.write	= ulite_console_write,
 	.device	= uart_console_device,
 	.setup	= ulite_console_setup,
@@ -403,7 +458,7 @@
 static struct uart_driver ulite_uart_driver = {
 	.owner		= THIS_MODULE,
 	.driver_name	= "uartlite",
-	.dev_name	= "ttyUL",
+	.dev_name	= ULITE_NAME,
 	.major		= ULITE_MAJOR,
 	.minor		= ULITE_MINOR,
 	.nr		= ULITE_NR_UARTS,
@@ -412,16 +467,96 @@
 #endif
 };
 
+/* ---------------------------------------------------------------------
+ * Port assignment functions (mapping devices to uart_port structures)
+ */
+
+/** ulite_assign: register a uartlite device with the driver
+ *
+ * @dev: pointer to device structure
+ * @id: requested id number.  Pass -1 for automatic port assignment
+ * @base: base address of uartlite registers
+ * @irq: irq number for uartlite
+ *
+ * Returns: 0 on success, <0 otherwise
+ */
+static int __devinit ulite_assign(struct device *dev, int id, u32 base, int irq)
+{
+	struct uart_port *port;
+	int rc;
+
+	/* if id = -1; then scan for a free id and use that */
+	if (id < 0) {
+		for (id = 0; id < ULITE_NR_UARTS; id++)
+			if (ulite_ports[id].mapbase == 0)
+				break;
+	}
+	if (id < 0 || id >= ULITE_NR_UARTS) {
+		dev_err(dev, "%s%i too large\n", ULITE_NAME, id);
+		return -EINVAL;
+	}
+
+	if ((ulite_ports[id].mapbase) && (ulite_ports[id].mapbase != base)) {
+		dev_err(dev, "cannot assign to %s%i; it is already in use\n",
+			ULITE_NAME, id);
+		return -EBUSY;
+	}
+
+	port = &ulite_ports[id];
+
+	spin_lock_init(&port->lock);
+	port->fifosize = 16;
+	port->regshift = 2;
+	port->iotype = UPIO_MEM;
+	port->iobase = 1; /* mark port in use */
+	port->mapbase = base;
+	port->membase = NULL;
+	port->ops = &ulite_ops;
+	port->irq = irq;
+	port->flags = UPF_BOOT_AUTOCONF;
+	port->dev = dev;
+	port->type = PORT_UNKNOWN;
+	port->line = id;
+
+	dev_set_drvdata(dev, port);
+
+	/* Register the port */
+	rc = uart_add_one_port(&ulite_uart_driver, port);
+	if (rc) {
+		dev_err(dev, "uart_add_one_port() failed; err=%i\n", rc);
+		port->mapbase = 0;
+		dev_set_drvdata(dev, NULL);
+		return rc;
+	}
+
+	return 0;
+}
+
+/** ulite_release: register a uartlite device with the driver
+ *
+ * @dev: pointer to device structure
+ */
+static int __devinit ulite_release(struct device *dev)
+{
+	struct uart_port *port = dev_get_drvdata(dev);
+	int rc = 0;
+
+	if (port) {
+		rc = uart_remove_one_port(&ulite_uart_driver, port);
+		dev_set_drvdata(dev, NULL);
+		port->mapbase = 0;
+	}
+
+	return rc;
+}
+
+/* ---------------------------------------------------------------------
+ * Platform bus binding
+ */
+
 static int __devinit ulite_probe(struct platform_device *pdev)
 {
 	struct resource *res, *res2;
-	struct uart_port *port;
-
-	if (pdev->id < 0 || pdev->id >= ULITE_NR_UARTS)
-		return -EINVAL;
-
-	if (ports[pdev->id].membase)
-		return -EBUSY;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res)
@@ -431,40 +566,12 @@
 	if (!res2)
 		return -ENODEV;
 
-	port = &ports[pdev->id];
-
-	port->fifosize	= 16;
-	port->regshift	= 2;
-	port->iotype	= UPIO_MEM;
-	port->iobase	= 1; /* mark port in use */
-	port->mapbase	= res->start;
-	port->membase	= NULL;
-	port->ops	= &ulite_ops;
-	port->irq	= res2->start;
-	port->flags	= UPF_BOOT_AUTOCONF;
-	port->dev	= &pdev->dev;
-	port->type	= PORT_UNKNOWN;
-	port->line	= pdev->id;
-
-	uart_add_one_port(&ulite_uart_driver, port);
-	platform_set_drvdata(pdev, port);
-
-	return 0;
+	return ulite_assign(&pdev->dev, pdev->id, res->start, res2->start);
 }
 
 static int ulite_remove(struct platform_device *pdev)
 {
-	struct uart_port *port = platform_get_drvdata(pdev);
-
-	platform_set_drvdata(pdev, NULL);
-
-	if (port)
-		uart_remove_one_port(&ulite_uart_driver, port);
-
-	/* mark port as free */
-	port->membase = NULL;
-
-	return 0;
+	return ulite_release(&pdev->dev);
 }
 
 static struct platform_driver ulite_platform_driver = {
@@ -476,24 +583,109 @@
 		   },
 };
 
+/* ---------------------------------------------------------------------
+ * OF bus bindings
+ */
+#if defined(CONFIG_OF)
+static int __devinit
+ulite_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+	struct resource res;
+	const unsigned int *id;
+	int irq, rc;
+
+	dev_dbg(&op->dev, "%s(%p, %p)\n", __FUNCTION__, op, match);
+
+	rc = of_address_to_resource(op->node, 0, &res);
+	if (rc) {
+		dev_err(&op->dev, "invalid address\n");
+		return rc;
+	}
+
+	irq = irq_of_parse_and_map(op->node, 0);
+
+	id = of_get_property(op->node, "port-number", NULL);
+
+	return ulite_assign(&op->dev, id ? *id : -1, res.start+3, irq);
+}
+
+static int __devexit ulite_of_remove(struct of_device *op)
+{
+	return ulite_release(&op->dev);
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id __devinit ulite_of_match[] = {
+	{ .type = "serial", .compatible = "xilinx,uartlite", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, ulite_of_match);
+
+static struct of_platform_driver ulite_of_driver = {
+	.owner = THIS_MODULE,
+	.name = "uartlite",
+	.match_table = ulite_of_match,
+	.probe = ulite_of_probe,
+	.remove = __devexit_p(ulite_of_remove),
+	.driver = {
+		.name = "uartlite",
+	},
+};
+
+/* Registration helpers to keep the number of #ifdefs to a minimum */
+static inline int __init ulite_of_register(void)
+{
+	pr_debug("uartlite: calling of_register_platform_driver()\n");
+	return of_register_platform_driver(&ulite_of_driver);
+}
+
+static inline void __exit ulite_of_unregister(void)
+{
+	of_unregister_platform_driver(&ulite_of_driver);
+}
+#else /* CONFIG_OF */
+/* CONFIG_OF not enabled; do nothing helpers */
+static inline int __init ulite_of_register(void) { return 0; }
+static inline void __exit ulite_of_unregister(void) { }
+#endif /* CONFIG_OF */
+
+/* ---------------------------------------------------------------------
+ * Module setup/teardown
+ */
+
 int __init ulite_init(void)
 {
 	int ret;
 
+	pr_debug("uartlite: calling uart_register_driver()\n");
 	ret = uart_register_driver(&ulite_uart_driver);
 	if (ret)
-		return ret;
+		goto err_uart;
 
+	ret = ulite_of_register();
+	if (ret)
+		goto err_of;
+
+	pr_debug("uartlite: calling platform_driver_register()\n");
 	ret = platform_driver_register(&ulite_platform_driver);
 	if (ret)
-		uart_unregister_driver(&ulite_uart_driver);
+		goto err_plat;
 
+	return 0;
+
+err_plat:
+	ulite_of_unregister();
+err_of:
+	uart_unregister_driver(&ulite_uart_driver);
+err_uart:
+	printk(KERN_ERR "registering uartlite driver failed: err=%i", ret);
 	return ret;
 }
 
 void __exit ulite_exit(void)
 {
 	platform_driver_unregister(&ulite_platform_driver);
+	ulite_of_unregister();
 	uart_unregister_driver(&ulite_uart_driver);
 }
 
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c
index 85309ac..6fd51b0 100644
--- a/drivers/serial/vr41xx_siu.c
+++ b/drivers/serial/vr41xx_siu.c
@@ -65,7 +65,9 @@
 	},
 };
 
+#ifdef CONFIG_SERIAL_VR41XX_CONSOLE
 static uint8_t lsr_break_flag[SIU_PORTS_MAX];
+#endif
 
 #define siu_read(port, offset)		readb((port)->membase + (offset))
 #define siu_write(port, offset, value)	writeb((value), (port)->membase + (offset))
@@ -782,7 +784,7 @@
 	siu_write(port, UART_IER, ier);
 }
 
-static int siu_console_setup(struct console *con, char *options)
+static int __init siu_console_setup(struct console *con, char *options)
 {
 	struct uart_port *port;
 	int baud = 9600;
@@ -800,7 +802,8 @@
 		port->membase = ioremap(port->mapbase, siu_port_size(port));
 	}
 
-	vr41xx_select_siu_interface(SIU_INTERFACE_RS232C);
+	if (port->type == PORT_VR41XX_SIU)
+		vr41xx_select_siu_interface(SIU_INTERFACE_RS232C);
 
 	if (options != NULL)
 		uart_parse_options(options, &baud, &parity, &bits, &flow);
diff --git a/drivers/serial/zs.c b/drivers/serial/zs.c
new file mode 100644
index 0000000..65f1294
--- /dev/null
+++ b/drivers/serial/zs.c
@@ -0,0 +1,1287 @@
+/*
+ * zs.c: Serial port driver for IOASIC DECstations.
+ *
+ * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
+ * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
+ *
+ * DECstation changes
+ * Copyright (C) 1998-2000 Harald Koerfgen
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007  Maciej W. Rozycki
+ *
+ * For the rest of the code the original Copyright applies:
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ *
+ * Note: for IOASIC systems the wiring is as follows:
+ *
+ * mouse/keyboard:
+ * DIN-7 MJ-4  signal        SCC
+ * 2     1     TxD       <-  A.TxD
+ * 3     4     RxD       ->  A.RxD
+ *
+ * EIA-232/EIA-423:
+ * DB-25 MMJ-6 signal        SCC
+ * 2     2     TxD       <-  B.TxD
+ * 3     5     RxD       ->  B.RxD
+ * 4           RTS       <- ~A.RTS
+ * 5           CTS       -> ~B.CTS
+ * 6     6     DSR       -> ~A.SYNC
+ * 8           CD        -> ~B.DCD
+ * 12          DSRS(DCE) -> ~A.CTS  (*)
+ * 15          TxC       ->  B.TxC
+ * 17          RxC       ->  B.RxC
+ * 20    1     DTR       <- ~A.DTR
+ * 22          RI        -> ~A.DCD
+ * 23          DSRS(DTE) <- ~B.RTS
+ *
+ * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE)
+ *     is shared with DSRS(DTE) at pin 23.
+ *
+ * As you can immediately notice the wiring of the RTS, DTR and DSR signals
+ * is a bit odd.  This makes the handling of port B unnecessarily
+ * complicated and prevents the use of some automatic modes of operation.
+ */
+
+#if defined(CONFIG_SERIAL_ZS_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/bug.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irqflags.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/spinlock.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/types.h>
+
+#include <asm/atomic.h>
+#include <asm/system.h>
+
+#include <asm/dec/interrupts.h>
+#include <asm/dec/ioasic_addrs.h>
+#include <asm/dec/system.h>
+
+#include "zs.h"
+
+
+MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>");
+MODULE_DESCRIPTION("DECstation Z85C30 serial driver");
+MODULE_LICENSE("GPL");
+
+
+static char zs_name[] __initdata = "DECstation Z85C30 serial driver version ";
+static char zs_version[] __initdata = "0.10";
+
+/*
+ * It would be nice to dynamically allocate everything that
+ * depends on ZS_NUM_SCCS, so we could support any number of
+ * Z85C30s, but for now...
+ */
+#define ZS_NUM_SCCS	2		/* Max # of ZS chips supported.  */
+#define ZS_NUM_CHAN	2		/* 2 channels per chip.  */
+#define ZS_CHAN_A	0		/* Index of the channel A.  */
+#define ZS_CHAN_B	1		/* Index of the channel B.  */
+#define ZS_CHAN_IO_SIZE 8		/* IOMEM space size.  */
+#define ZS_CHAN_IO_STRIDE 4		/* Register alignment.  */
+#define ZS_CHAN_IO_OFFSET 1		/* The SCC resides on the high byte
+					   of the 16-bit IOBUS.  */
+#define ZS_CLOCK        7372800 	/* Z85C30 PCLK input clock rate.  */
+
+#define to_zport(uport) container_of(uport, struct zs_port, port)
+
+struct zs_parms {
+	resource_size_t scc[ZS_NUM_SCCS];
+	int irq[ZS_NUM_SCCS];
+};
+
+static struct zs_scc zs_sccs[ZS_NUM_SCCS];
+
+static u8 zs_init_regs[ZS_NUM_REGS] __initdata = {
+	0,				/* write 0 */
+	PAR_SPEC,			/* write 1 */
+	0,				/* write 2 */
+	0,				/* write 3 */
+	X16CLK | SB1,			/* write 4 */
+	0,				/* write 5 */
+	0, 0, 0,			/* write 6, 7, 8 */
+	MIE | DLC | NV,			/* write 9 */
+	NRZ,				/* write 10 */
+	TCBR | RCBR,			/* write 11 */
+	0, 0,				/* BRG time constant, write 12 + 13 */
+	BRSRC | BRENABL,		/* write 14 */
+	0,				/* write 15 */
+};
+
+/*
+ * Debugging.
+ */
+#undef ZS_DEBUG_REGS
+
+
+/*
+ * Reading and writing Z85C30 registers.
+ */
+static void recovery_delay(void)
+{
+	udelay(2);
+}
+
+static u8 read_zsreg(struct zs_port *zport, int reg)
+{
+	void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET;
+	u8 retval;
+
+	if (reg != 0) {
+		writeb(reg & 0xf, control);
+		fast_iob();
+		recovery_delay();
+	}
+	retval = readb(control);
+	recovery_delay();
+	return retval;
+}
+
+static void write_zsreg(struct zs_port *zport, int reg, u8 value)
+{
+	void __iomem *control = zport->port.membase + ZS_CHAN_IO_OFFSET;
+
+	if (reg != 0) {
+		writeb(reg & 0xf, control);
+		fast_iob(); recovery_delay();
+	}
+	writeb(value, control);
+	fast_iob();
+	recovery_delay();
+	return;
+}
+
+static u8 read_zsdata(struct zs_port *zport)
+{
+	void __iomem *data = zport->port.membase +
+			     ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET;
+	u8 retval;
+
+	retval = readb(data);
+	recovery_delay();
+	return retval;
+}
+
+static void write_zsdata(struct zs_port *zport, u8 value)
+{
+	void __iomem *data = zport->port.membase +
+			     ZS_CHAN_IO_STRIDE + ZS_CHAN_IO_OFFSET;
+
+	writeb(value, data);
+	fast_iob();
+	recovery_delay();
+	return;
+}
+
+#ifdef ZS_DEBUG_REGS
+void zs_dump(void)
+{
+	struct zs_port *zport;
+	int i, j;
+
+	for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
+		zport = &zs_sccs[i / ZS_NUM_CHAN].zport[i % ZS_NUM_CHAN];
+
+		if (!zport->scc)
+			continue;
+
+		for (j = 0; j < 16; j++)
+			printk("W%-2d = 0x%02x\t", j, zport->regs[j]);
+		printk("\n");
+		for (j = 0; j < 16; j++)
+			printk("R%-2d = 0x%02x\t", j, read_zsreg(zport, j));
+		printk("\n\n");
+	}
+}
+#endif
+
+
+static void zs_spin_lock_cond_irq(spinlock_t *lock, int irq)
+{
+	if (irq)
+		spin_lock_irq(lock);
+	else
+		spin_lock(lock);
+}
+
+static void zs_spin_unlock_cond_irq(spinlock_t *lock, int irq)
+{
+	if (irq)
+		spin_unlock_irq(lock);
+	else
+		spin_unlock(lock);
+}
+
+static int zs_receive_drain(struct zs_port *zport)
+{
+	int loops = 10000;
+
+	while ((read_zsreg(zport, R0) & Rx_CH_AV) && loops--)
+		read_zsdata(zport);
+	return loops;
+}
+
+static int zs_transmit_drain(struct zs_port *zport, int irq)
+{
+	struct zs_scc *scc = zport->scc;
+	int loops = 10000;
+
+	while (!(read_zsreg(zport, R0) & Tx_BUF_EMP) && loops--) {
+		zs_spin_unlock_cond_irq(&scc->zlock, irq);
+		udelay(2);
+		zs_spin_lock_cond_irq(&scc->zlock, irq);
+	}
+	return loops;
+}
+
+static int zs_line_drain(struct zs_port *zport, int irq)
+{
+	struct zs_scc *scc = zport->scc;
+	int loops = 10000;
+
+	while (!(read_zsreg(zport, R1) & ALL_SNT) && loops--) {
+		zs_spin_unlock_cond_irq(&scc->zlock, irq);
+		udelay(2);
+		zs_spin_lock_cond_irq(&scc->zlock, irq);
+	}
+	return loops;
+}
+
+
+static void load_zsregs(struct zs_port *zport, u8 *regs, int irq)
+{
+	/* Let the current transmission finish.  */
+	zs_line_drain(zport, irq);
+	/* Load 'em up.  */
+	write_zsreg(zport, R3, regs[3] & ~RxENABLE);
+	write_zsreg(zport, R5, regs[5] & ~TxENAB);
+	write_zsreg(zport, R4, regs[4]);
+	write_zsreg(zport, R9, regs[9]);
+	write_zsreg(zport, R1, regs[1]);
+	write_zsreg(zport, R2, regs[2]);
+	write_zsreg(zport, R10, regs[10]);
+	write_zsreg(zport, R14, regs[14] & ~BRENABL);
+	write_zsreg(zport, R11, regs[11]);
+	write_zsreg(zport, R12, regs[12]);
+	write_zsreg(zport, R13, regs[13]);
+	write_zsreg(zport, R14, regs[14]);
+	write_zsreg(zport, R15, regs[15]);
+	if (regs[3] & RxENABLE)
+		write_zsreg(zport, R3, regs[3]);
+	if (regs[5] & TxENAB)
+		write_zsreg(zport, R5, regs[5]);
+	return;
+}
+
+
+/*
+ * Status handling routines.
+ */
+
+/*
+ * zs_tx_empty() -- get the transmitter empty status
+ *
+ * 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 unsigned int zs_tx_empty(struct uart_port *uport)
+{
+	struct zs_port *zport = to_zport(uport);
+	struct zs_scc *scc = zport->scc;
+	unsigned long flags;
+	u8 status;
+
+	spin_lock_irqsave(&scc->zlock, flags);
+	status = read_zsreg(zport, R1);
+	spin_unlock_irqrestore(&scc->zlock, flags);
+
+	return status & ALL_SNT ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int zs_raw_get_ab_mctrl(struct zs_port *zport_a,
+					struct zs_port *zport_b)
+{
+	u8 status_a, status_b;
+	unsigned int mctrl;
+
+	status_a = read_zsreg(zport_a, R0);
+	status_b = read_zsreg(zport_b, R0);
+
+	mctrl = ((status_b & CTS) ? TIOCM_CTS : 0) |
+		((status_b & DCD) ? TIOCM_CAR : 0) |
+		((status_a & DCD) ? TIOCM_RNG : 0) |
+		((status_a & SYNC_HUNT) ? TIOCM_DSR : 0);
+
+	return mctrl;
+}
+
+static unsigned int zs_raw_get_mctrl(struct zs_port *zport)
+{
+	struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
+
+	return zport != zport_a ? zs_raw_get_ab_mctrl(zport_a, zport) : 0;
+}
+
+static unsigned int zs_raw_xor_mctrl(struct zs_port *zport)
+{
+	struct zs_port *zport_a = &zport->scc->zport[ZS_CHAN_A];
+	unsigned int mmask, mctrl, delta;
+	u8 mask_a, mask_b;
+
+	if (zport == zport_a)
+		return 0;
+
+	mask_a = zport_a->regs[15];
+	mask_b = zport->regs[15];
+
+	mmask = ((mask_b & CTSIE) ? TIOCM_CTS : 0) |
+		((mask_b & DCDIE) ? TIOCM_CAR : 0) |
+		((mask_a & DCDIE) ? TIOCM_RNG : 0) |
+		((mask_a & SYNCIE) ? TIOCM_DSR : 0);
+
+	mctrl = zport->mctrl;
+	if (mmask) {
+		mctrl &= ~mmask;
+		mctrl |= zs_raw_get_ab_mctrl(zport_a, zport) & mmask;
+	}
+
+	delta = mctrl ^ zport->mctrl;
+	if (delta)
+		zport->mctrl = mctrl;
+
+	return delta;
+}
+
+static unsigned int zs_get_mctrl(struct uart_port *uport)
+{
+	struct zs_port *zport = to_zport(uport);
+	struct zs_scc *scc = zport->scc;
+	unsigned int mctrl;
+
+	spin_lock(&scc->zlock);
+	mctrl = zs_raw_get_mctrl(zport);
+	spin_unlock(&scc->zlock);
+
+	return mctrl;
+}
+
+static void zs_set_mctrl(struct uart_port *uport, unsigned int mctrl)
+{
+	struct zs_port *zport = to_zport(uport);
+	struct zs_scc *scc = zport->scc;
+	struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+	u8 oldloop, newloop;
+
+	spin_lock(&scc->zlock);
+	if (zport != zport_a) {
+		if (mctrl & TIOCM_DTR)
+			zport_a->regs[5] |= DTR;
+		else
+			zport_a->regs[5] &= ~DTR;
+		if (mctrl & TIOCM_RTS)
+			zport_a->regs[5] |= RTS;
+		else
+			zport_a->regs[5] &= ~RTS;
+		write_zsreg(zport_a, R5, zport_a->regs[5]);
+	}
+
+	/* Rarely modified, so don't poke at hardware unless necessary. */
+	oldloop = zport->regs[14];
+	newloop = oldloop;
+	if (mctrl & TIOCM_LOOP)
+		newloop |= LOOPBAK;
+	else
+		newloop &= ~LOOPBAK;
+	if (newloop != oldloop) {
+		zport->regs[14] = newloop;
+		write_zsreg(zport, R14, zport->regs[14]);
+	}
+	spin_unlock(&scc->zlock);
+}
+
+static void zs_raw_stop_tx(struct zs_port *zport)
+{
+	write_zsreg(zport, R0, RES_Tx_P);
+	zport->tx_stopped = 1;
+}
+
+static void zs_stop_tx(struct uart_port *uport)
+{
+	struct zs_port *zport = to_zport(uport);
+	struct zs_scc *scc = zport->scc;
+
+	spin_lock(&scc->zlock);
+	zs_raw_stop_tx(zport);
+	spin_unlock(&scc->zlock);
+}
+
+static void zs_raw_transmit_chars(struct zs_port *);
+
+static void zs_start_tx(struct uart_port *uport)
+{
+	struct zs_port *zport = to_zport(uport);
+	struct zs_scc *scc = zport->scc;
+
+	spin_lock(&scc->zlock);
+	if (zport->tx_stopped) {
+		zs_transmit_drain(zport, 0);
+		zport->tx_stopped = 0;
+		zs_raw_transmit_chars(zport);
+	}
+	spin_unlock(&scc->zlock);
+}
+
+static void zs_stop_rx(struct uart_port *uport)
+{
+	struct zs_port *zport = to_zport(uport);
+	struct zs_scc *scc = zport->scc;
+	struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+
+	spin_lock(&scc->zlock);
+	zport->regs[15] &= ~BRKIE;
+	zport->regs[1] &= ~(RxINT_MASK | TxINT_ENAB);
+	zport->regs[1] |= RxINT_DISAB;
+
+	if (zport != zport_a) {
+		/* A-side DCD tracks RI and SYNC tracks DSR.  */
+		zport_a->regs[15] &= ~(DCDIE | SYNCIE);
+		write_zsreg(zport_a, R15, zport_a->regs[15]);
+		if (!(zport_a->regs[15] & BRKIE)) {
+			zport_a->regs[1] &= ~EXT_INT_ENAB;
+			write_zsreg(zport_a, R1, zport_a->regs[1]);
+		}
+
+		/* This-side DCD tracks DCD and CTS tracks CTS.  */
+		zport->regs[15] &= ~(DCDIE | CTSIE);
+		zport->regs[1] &= ~EXT_INT_ENAB;
+	} else {
+		/* DCD tracks RI and SYNC tracks DSR for the B side.  */
+		if (!(zport->regs[15] & (DCDIE | SYNCIE)))
+			zport->regs[1] &= ~EXT_INT_ENAB;
+	}
+
+	write_zsreg(zport, R15, zport->regs[15]);
+	write_zsreg(zport, R1, zport->regs[1]);
+	spin_unlock(&scc->zlock);
+}
+
+static void zs_enable_ms(struct uart_port *uport)
+{
+	struct zs_port *zport = to_zport(uport);
+	struct zs_scc *scc = zport->scc;
+	struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+
+	if (zport == zport_a)
+		return;
+
+	spin_lock(&scc->zlock);
+
+	/* Clear Ext interrupts if not being handled already.  */
+	if (!(zport_a->regs[1] & EXT_INT_ENAB))
+		write_zsreg(zport_a, R0, RES_EXT_INT);
+
+	/* A-side DCD tracks RI and SYNC tracks DSR.  */
+	zport_a->regs[1] |= EXT_INT_ENAB;
+	zport_a->regs[15] |= DCDIE | SYNCIE;
+
+	/* This-side DCD tracks DCD and CTS tracks CTS.  */
+	zport->regs[15] |= DCDIE | CTSIE;
+
+	zs_raw_xor_mctrl(zport);
+
+	write_zsreg(zport_a, R1, zport_a->regs[1]);
+	write_zsreg(zport_a, R15, zport_a->regs[15]);
+	write_zsreg(zport, R15, zport->regs[15]);
+	spin_unlock(&scc->zlock);
+}
+
+static void zs_break_ctl(struct uart_port *uport, int break_state)
+{
+	struct zs_port *zport = to_zport(uport);
+	struct zs_scc *scc = zport->scc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&scc->zlock, flags);
+	if (break_state == -1)
+		zport->regs[5] |= SND_BRK;
+	else
+		zport->regs[5] &= ~SND_BRK;
+	write_zsreg(zport, R5, zport->regs[5]);
+	spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+
+/*
+ * Interrupt handling routines.
+ */
+#define Rx_BRK 0x0100			/* BREAK event software flag.  */
+#define Rx_SYS 0x0200			/* SysRq event software flag.  */
+
+static void zs_receive_chars(struct zs_port *zport)
+{
+	struct uart_port *uport = &zport->port;
+	struct zs_scc *scc = zport->scc;
+	struct uart_icount *icount;
+	unsigned int avail, status, ch, flag;
+	int count;
+
+	for (count = 16; count; count--) {
+		spin_lock(&scc->zlock);
+		avail = read_zsreg(zport, R0) & Rx_CH_AV;
+		spin_unlock(&scc->zlock);
+		if (!avail)
+			break;
+
+		spin_lock(&scc->zlock);
+		status = read_zsreg(zport, R1) & (Rx_OVR | FRM_ERR | PAR_ERR);
+		ch = read_zsdata(zport);
+		spin_unlock(&scc->zlock);
+
+		flag = TTY_NORMAL;
+
+		icount = &uport->icount;
+		icount->rx++;
+
+		/* Handle the null char got when BREAK is removed.  */
+		if (!ch)
+			status |= zport->tty_break;
+		if (unlikely(status &
+			     (Rx_OVR | FRM_ERR | PAR_ERR | Rx_SYS | Rx_BRK))) {
+			zport->tty_break = 0;
+
+			/* Reset the error indication.  */
+			if (status & (Rx_OVR | FRM_ERR | PAR_ERR)) {
+				spin_lock(&scc->zlock);
+				write_zsreg(zport, R0, ERR_RES);
+				spin_unlock(&scc->zlock);
+			}
+
+			if (status & (Rx_SYS | Rx_BRK)) {
+				icount->brk++;
+				/* SysRq discards the null char.  */
+				if (status & Rx_SYS)
+					continue;
+			} else if (status & FRM_ERR)
+				icount->frame++;
+			else if (status & PAR_ERR)
+				icount->parity++;
+			if (status & Rx_OVR)
+				icount->overrun++;
+
+			status &= uport->read_status_mask;
+			if (status & Rx_BRK)
+				flag = TTY_BREAK;
+			else if (status & FRM_ERR)
+				flag = TTY_FRAME;
+			else if (status & PAR_ERR)
+				flag = TTY_PARITY;
+		}
+
+		if (uart_handle_sysrq_char(uport, ch))
+			continue;
+
+		uart_insert_char(uport, status, Rx_OVR, ch, flag);
+	}
+
+	tty_flip_buffer_push(uport->info->tty);
+}
+
+static void zs_raw_transmit_chars(struct zs_port *zport)
+{
+	struct circ_buf *xmit = &zport->port.info->xmit;
+
+	/* XON/XOFF chars.  */
+	if (zport->port.x_char) {
+		write_zsdata(zport, zport->port.x_char);
+		zport->port.icount.tx++;
+		zport->port.x_char = 0;
+		return;
+	}
+
+	/* If nothing to do or stopped or hardware stopped.  */
+	if (uart_circ_empty(xmit) || uart_tx_stopped(&zport->port)) {
+		zs_raw_stop_tx(zport);
+		return;
+	}
+
+	/* Send char.  */
+	write_zsdata(zport, xmit->buf[xmit->tail]);
+	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+	zport->port.icount.tx++;
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(&zport->port);
+
+	/* Are we are done?  */
+	if (uart_circ_empty(xmit))
+		zs_raw_stop_tx(zport);
+}
+
+static void zs_transmit_chars(struct zs_port *zport)
+{
+	struct zs_scc *scc = zport->scc;
+
+	spin_lock(&scc->zlock);
+	zs_raw_transmit_chars(zport);
+	spin_unlock(&scc->zlock);
+}
+
+static void zs_status_handle(struct zs_port *zport, struct zs_port *zport_a)
+{
+	struct uart_port *uport = &zport->port;
+	struct zs_scc *scc = zport->scc;
+	unsigned int delta;
+	u8 status, brk;
+
+	spin_lock(&scc->zlock);
+
+	/* Get status from Read Register 0.  */
+	status = read_zsreg(zport, R0);
+
+	if (zport->regs[15] & BRKIE) {
+		brk = status & BRK_ABRT;
+		if (brk && !zport->brk) {
+			spin_unlock(&scc->zlock);
+			if (uart_handle_break(uport))
+				zport->tty_break = Rx_SYS;
+			else
+				zport->tty_break = Rx_BRK;
+			spin_lock(&scc->zlock);
+		}
+		zport->brk = brk;
+	}
+
+	if (zport != zport_a) {
+		delta = zs_raw_xor_mctrl(zport);
+		spin_unlock(&scc->zlock);
+
+		if (delta & TIOCM_CTS)
+			uart_handle_cts_change(uport,
+					       zport->mctrl & TIOCM_CTS);
+		if (delta & TIOCM_CAR)
+			uart_handle_dcd_change(uport,
+					       zport->mctrl & TIOCM_CAR);
+		if (delta & TIOCM_RNG)
+			uport->icount.dsr++;
+		if (delta & TIOCM_DSR)
+			uport->icount.rng++;
+
+		if (delta)
+			wake_up_interruptible(&uport->info->delta_msr_wait);
+
+		spin_lock(&scc->zlock);
+	}
+
+	/* Clear the status condition...  */
+	write_zsreg(zport, R0, RES_EXT_INT);
+
+	spin_unlock(&scc->zlock);
+}
+
+/*
+ * This is the Z85C30 driver's generic interrupt routine.
+ */
+static irqreturn_t zs_interrupt(int irq, void *dev_id)
+{
+	struct zs_scc *scc = dev_id;
+	struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+	struct zs_port *zport_b = &scc->zport[ZS_CHAN_B];
+	irqreturn_t status = IRQ_NONE;
+	u8 zs_intreg;
+	int count;
+
+	/*
+	 * 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...
+	 */
+	for (count = 16; count; count--) {
+		spin_lock(&scc->zlock);
+		zs_intreg = read_zsreg(zport_a, R3);
+		spin_unlock(&scc->zlock);
+		if (!zs_intreg)
+			break;
+
+		/*
+		 * We do not like losing characters, so we prioritise
+		 * interrupt sources a little bit differently than
+		 * the SCC would, was it allowed to.
+		 */
+		if (zs_intreg & CHBRxIP)
+			zs_receive_chars(zport_b);
+		if (zs_intreg & CHARxIP)
+			zs_receive_chars(zport_a);
+		if (zs_intreg & CHBEXT)
+			zs_status_handle(zport_b, zport_a);
+		if (zs_intreg & CHAEXT)
+			zs_status_handle(zport_a, zport_a);
+		if (zs_intreg & CHBTxIP)
+			zs_transmit_chars(zport_b);
+		if (zs_intreg & CHATxIP)
+			zs_transmit_chars(zport_a);
+
+		status = IRQ_HANDLED;
+	}
+
+	return status;
+}
+
+
+/*
+ * Finally, routines used to initialize the serial port.
+ */
+static int zs_startup(struct uart_port *uport)
+{
+	struct zs_port *zport = to_zport(uport);
+	struct zs_scc *scc = zport->scc;
+	unsigned long flags;
+	int irq_guard;
+	int ret;
+
+	irq_guard = atomic_add_return(1, &scc->irq_guard);
+	if (irq_guard == 1) {
+		ret = request_irq(zport->port.irq, zs_interrupt,
+				  IRQF_SHARED, "scc", scc);
+		if (ret) {
+			atomic_add(-1, &scc->irq_guard);
+			printk(KERN_ERR "zs: can't get irq %d\n",
+			       zport->port.irq);
+			return ret;
+		}
+	}
+
+	spin_lock_irqsave(&scc->zlock, flags);
+
+	/* Clear the receive FIFO.  */
+	zs_receive_drain(zport);
+
+	/* Clear the interrupt registers.  */
+	write_zsreg(zport, R0, ERR_RES);
+	write_zsreg(zport, R0, RES_Tx_P);
+	/* But Ext only if not being handled already.  */
+	if (!(zport->regs[1] & EXT_INT_ENAB))
+		write_zsreg(zport, R0, RES_EXT_INT);
+
+	/* Finally, enable sequencing and interrupts.  */
+	zport->regs[1] &= ~RxINT_MASK;
+	zport->regs[1] |= RxINT_ALL | TxINT_ENAB | EXT_INT_ENAB;
+	zport->regs[3] |= RxENABLE;
+	zport->regs[5] |= TxENAB;
+	zport->regs[15] |= BRKIE;
+	write_zsreg(zport, R1, zport->regs[1]);
+	write_zsreg(zport, R3, zport->regs[3]);
+	write_zsreg(zport, R5, zport->regs[5]);
+	write_zsreg(zport, R15, zport->regs[15]);
+
+	/* Record the current state of RR0.  */
+	zport->mctrl = zs_raw_get_mctrl(zport);
+	zport->brk = read_zsreg(zport, R0) & BRK_ABRT;
+
+	zport->tx_stopped = 1;
+
+	spin_unlock_irqrestore(&scc->zlock, flags);
+
+	return 0;
+}
+
+static void zs_shutdown(struct uart_port *uport)
+{
+	struct zs_port *zport = to_zport(uport);
+	struct zs_scc *scc = zport->scc;
+	unsigned long flags;
+	int irq_guard;
+
+	spin_lock_irqsave(&scc->zlock, flags);
+
+	zport->regs[5] &= ~TxENAB;
+	zport->regs[3] &= ~RxENABLE;
+	write_zsreg(zport, R5, zport->regs[5]);
+	write_zsreg(zport, R3, zport->regs[3]);
+
+	spin_unlock_irqrestore(&scc->zlock, flags);
+
+	irq_guard = atomic_add_return(-1, &scc->irq_guard);
+	if (!irq_guard)
+		free_irq(zport->port.irq, scc);
+}
+
+
+static void zs_reset(struct zs_port *zport)
+{
+	struct zs_scc *scc = zport->scc;
+	int irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&scc->zlock, flags);
+	irq = !irqs_disabled_flags(flags);
+	if (!scc->initialised) {
+		/* Reset the pointer first, just in case...  */
+		read_zsreg(zport, R0);
+		/* And let the current transmission finish.  */
+		zs_line_drain(zport, irq);
+		write_zsreg(zport, R9, FHWRES);
+		udelay(10);
+		write_zsreg(zport, R9, 0);
+		scc->initialised = 1;
+	}
+	load_zsregs(zport, zport->regs, irq);
+	spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+static void zs_set_termios(struct uart_port *uport, struct ktermios *termios,
+			   struct ktermios *old_termios)
+{
+	struct zs_port *zport = to_zport(uport);
+	struct zs_scc *scc = zport->scc;
+	struct zs_port *zport_a = &scc->zport[ZS_CHAN_A];
+	int irq;
+	unsigned int baud, brg;
+	unsigned long flags;
+
+	spin_lock_irqsave(&scc->zlock, flags);
+	irq = !irqs_disabled_flags(flags);
+
+	/* Byte size.  */
+	zport->regs[3] &= ~RxNBITS_MASK;
+	zport->regs[5] &= ~TxNBITS_MASK;
+	switch (termios->c_cflag & CSIZE) {
+	case CS5:
+		zport->regs[3] |= Rx5;
+		zport->regs[5] |= Tx5;
+		break;
+	case CS6:
+		zport->regs[3] |= Rx6;
+		zport->regs[5] |= Tx6;
+		break;
+	case CS7:
+		zport->regs[3] |= Rx7;
+		zport->regs[5] |= Tx7;
+		break;
+	case CS8:
+	default:
+		zport->regs[3] |= Rx8;
+		zport->regs[5] |= Tx8;
+		break;
+	}
+
+	/* Parity and stop bits.  */
+	zport->regs[4] &= ~(XCLK_MASK | SB_MASK | PAR_ENA | PAR_EVEN);
+	if (termios->c_cflag & CSTOPB)
+		zport->regs[4] |= SB2;
+	else
+		zport->regs[4] |= SB1;
+	if (termios->c_cflag & PARENB)
+		zport->regs[4] |= PAR_ENA;
+	if (!(termios->c_cflag & PARODD))
+		zport->regs[4] |= PAR_EVEN;
+	switch (zport->clk_mode) {
+	case 64:
+		zport->regs[4] |= X64CLK;
+		break;
+	case 32:
+		zport->regs[4] |= X32CLK;
+		break;
+	case 16:
+		zport->regs[4] |= X16CLK;
+		break;
+	case 1:
+		zport->regs[4] |= X1CLK;
+		break;
+	default:
+		BUG();
+	}
+
+	baud = uart_get_baud_rate(uport, termios, old_termios, 0,
+				  uport->uartclk / zport->clk_mode / 4);
+
+	brg = ZS_BPS_TO_BRG(baud, uport->uartclk / zport->clk_mode);
+	zport->regs[12] = brg & 0xff;
+	zport->regs[13] = (brg >> 8) & 0xff;
+
+	uart_update_timeout(uport, termios->c_cflag, baud);
+
+	uport->read_status_mask = Rx_OVR;
+	if (termios->c_iflag & INPCK)
+		uport->read_status_mask |= FRM_ERR | PAR_ERR;
+	if (termios->c_iflag & (BRKINT | PARMRK))
+		uport->read_status_mask |= Rx_BRK;
+
+	uport->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		uport->ignore_status_mask |= FRM_ERR | PAR_ERR;
+	if (termios->c_iflag & IGNBRK) {
+		uport->ignore_status_mask |= Rx_BRK;
+		if (termios->c_iflag & IGNPAR)
+			uport->ignore_status_mask |= Rx_OVR;
+	}
+
+	if (termios->c_cflag & CREAD)
+		zport->regs[3] |= RxENABLE;
+	else
+		zport->regs[3] &= ~RxENABLE;
+
+	if (zport != zport_a) {
+		if (!(termios->c_cflag & CLOCAL)) {
+			zport->regs[15] |= DCDIE;
+		} else
+			zport->regs[15] &= ~DCDIE;
+		if (termios->c_cflag & CRTSCTS) {
+			zport->regs[15] |= CTSIE;
+		} else
+			zport->regs[15] &= ~CTSIE;
+		zs_raw_xor_mctrl(zport);
+	}
+
+	/* Load up the new values.  */
+	load_zsregs(zport, zport->regs, irq);
+
+	spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+
+static const char *zs_type(struct uart_port *uport)
+{
+	return "Z85C30 SCC";
+}
+
+static void zs_release_port(struct uart_port *uport)
+{
+	iounmap(uport->membase);
+	uport->membase = 0;
+	release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE);
+}
+
+static int zs_map_port(struct uart_port *uport)
+{
+	if (!uport->membase)
+		uport->membase = ioremap_nocache(uport->mapbase,
+						 ZS_CHAN_IO_SIZE);
+	if (!uport->membase) {
+		printk(KERN_ERR "zs: Cannot map MMIO\n");
+		return -ENOMEM;
+	}
+	return 0;
+}
+
+static int zs_request_port(struct uart_port *uport)
+{
+	int ret;
+
+	if (!request_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE, "scc")) {
+		printk(KERN_ERR "zs: Unable to reserve MMIO resource\n");
+		return -EBUSY;
+	}
+	ret = zs_map_port(uport);
+	if (ret) {
+		release_mem_region(uport->mapbase, ZS_CHAN_IO_SIZE);
+		return ret;
+	}
+	return 0;
+}
+
+static void zs_config_port(struct uart_port *uport, int flags)
+{
+	struct zs_port *zport = to_zport(uport);
+
+	if (flags & UART_CONFIG_TYPE) {
+		if (zs_request_port(uport))
+			return;
+
+		uport->type = PORT_ZS;
+
+		zs_reset(zport);
+	}
+}
+
+static int zs_verify_port(struct uart_port *uport, struct serial_struct *ser)
+{
+	struct zs_port *zport = to_zport(uport);
+	int ret = 0;
+
+	if (ser->type != PORT_UNKNOWN && ser->type != PORT_ZS)
+		ret = -EINVAL;
+	if (ser->irq != uport->irq)
+		ret = -EINVAL;
+	if (ser->baud_base != uport->uartclk / zport->clk_mode / 4)
+		ret = -EINVAL;
+	return ret;
+}
+
+
+static struct uart_ops zs_ops = {
+	.tx_empty	= zs_tx_empty,
+	.set_mctrl	= zs_set_mctrl,
+	.get_mctrl	= zs_get_mctrl,
+	.stop_tx	= zs_stop_tx,
+	.start_tx	= zs_start_tx,
+	.stop_rx	= zs_stop_rx,
+	.enable_ms	= zs_enable_ms,
+	.break_ctl	= zs_break_ctl,
+	.startup	= zs_startup,
+	.shutdown	= zs_shutdown,
+	.set_termios	= zs_set_termios,
+	.type		= zs_type,
+	.release_port	= zs_release_port,
+	.request_port	= zs_request_port,
+	.config_port	= zs_config_port,
+	.verify_port	= zs_verify_port,
+};
+
+/*
+ * Initialize Z85C30 port structures.
+ */
+static int __init zs_probe_sccs(void)
+{
+	static int probed;
+	struct zs_parms zs_parms;
+	int chip, side, irq;
+	int n_chips = 0;
+	int i;
+
+	if (probed)
+		return 0;
+
+	irq = dec_interrupt[DEC_IRQ_SCC0];
+	if (irq >= 0) {
+		zs_parms.scc[n_chips] = IOASIC_SCC0;
+		zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC0];
+		n_chips++;
+	}
+	irq = dec_interrupt[DEC_IRQ_SCC1];
+	if (irq >= 0) {
+		zs_parms.scc[n_chips] = IOASIC_SCC1;
+		zs_parms.irq[n_chips] = dec_interrupt[DEC_IRQ_SCC1];
+		n_chips++;
+	}
+	if (!n_chips)
+		return -ENXIO;
+
+	probed = 1;
+
+	for (chip = 0; chip < n_chips; chip++) {
+		spin_lock_init(&zs_sccs[chip].zlock);
+		for (side = 0; side < ZS_NUM_CHAN; side++) {
+			struct zs_port *zport = &zs_sccs[chip].zport[side];
+			struct uart_port *uport = &zport->port;
+
+			zport->scc	= &zs_sccs[chip];
+			zport->clk_mode	= 16;
+
+			uport->irq	= zs_parms.irq[chip];
+			uport->uartclk	= ZS_CLOCK;
+			uport->fifosize	= 1;
+			uport->iotype	= UPIO_MEM;
+			uport->flags	= UPF_BOOT_AUTOCONF;
+			uport->ops	= &zs_ops;
+			uport->line	= chip * ZS_NUM_CHAN + side;
+			uport->mapbase	= dec_kn_slot_base +
+					  zs_parms.scc[chip] +
+					  (side ^ ZS_CHAN_B) * ZS_CHAN_IO_SIZE;
+
+			for (i = 0; i < ZS_NUM_REGS; i++)
+				zport->regs[i] = zs_init_regs[i];
+		}
+	}
+
+	return 0;
+}
+
+
+#ifdef CONFIG_SERIAL_ZS_CONSOLE
+static void zs_console_putchar(struct uart_port *uport, int ch)
+{
+	struct zs_port *zport = to_zport(uport);
+	struct zs_scc *scc = zport->scc;
+	int irq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&scc->zlock, flags);
+	irq = !irqs_disabled_flags(flags);
+	if (zs_transmit_drain(zport, irq))
+		write_zsdata(zport, ch);
+	spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ */
+static void zs_console_write(struct console *co, const char *s,
+			     unsigned int count)
+{
+	int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN;
+	struct zs_port *zport = &zs_sccs[chip].zport[side];
+	struct zs_scc *scc = zport->scc;
+	unsigned long flags;
+	u8 txint, txenb;
+	int irq;
+
+	/* Disable transmit interrupts and enable the transmitter. */
+	spin_lock_irqsave(&scc->zlock, flags);
+	txint = zport->regs[1];
+	txenb = zport->regs[5];
+	if (txint & TxINT_ENAB) {
+		zport->regs[1] = txint & ~TxINT_ENAB;
+		write_zsreg(zport, R1, zport->regs[1]);
+	}
+	if (!(txenb & TxENAB)) {
+		zport->regs[5] = txenb | TxENAB;
+		write_zsreg(zport, R5, zport->regs[5]);
+	}
+	spin_unlock_irqrestore(&scc->zlock, flags);
+
+	uart_console_write(&zport->port, s, count, zs_console_putchar);
+
+	/* Restore transmit interrupts and the transmitter enable. */
+	spin_lock_irqsave(&scc->zlock, flags);
+	irq = !irqs_disabled_flags(flags);
+	zs_line_drain(zport, irq);
+	if (!(txenb & TxENAB)) {
+		zport->regs[5] &= ~TxENAB;
+		write_zsreg(zport, R5, zport->regs[5]);
+	}
+	if (txint & TxINT_ENAB) {
+		zport->regs[1] |= TxINT_ENAB;
+		write_zsreg(zport, R1, zport->regs[1]);
+	}
+	spin_unlock_irqrestore(&scc->zlock, flags);
+}
+
+/*
+ * Setup serial console baud/bits/parity.  We do two things here:
+ * - construct a cflag setting for the first uart_open()
+ * - initialise the serial port
+ * Return non-zero if we didn't find a serial port.
+ */
+static int __init zs_console_setup(struct console *co, char *options)
+{
+	int chip = co->index / ZS_NUM_CHAN, side = co->index % ZS_NUM_CHAN;
+	struct zs_port *zport = &zs_sccs[chip].zport[side];
+	struct uart_port *uport = &zport->port;
+	int baud = 9600;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+	int ret;
+
+	ret = zs_map_port(uport);
+	if (ret)
+		return ret;
+
+	zs_reset(zport);
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+	return uart_set_options(uport, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver zs_reg;
+static struct console zs_console = {
+	.name	= "ttyS",
+	.write	= zs_console_write,
+	.device	= uart_console_device,
+	.setup	= zs_console_setup,
+	.flags	= CON_PRINTBUFFER,
+	.index	= -1,
+	.data	= &zs_reg,
+};
+
+/*
+ *	Register console.
+ */
+static int __init zs_serial_console_init(void)
+{
+	int ret;
+
+	ret = zs_probe_sccs();
+	if (ret)
+		return ret;
+	register_console(&zs_console);
+
+	return 0;
+}
+
+console_initcall(zs_serial_console_init);
+
+#define SERIAL_ZS_CONSOLE	&zs_console
+#else
+#define SERIAL_ZS_CONSOLE	NULL
+#endif /* CONFIG_SERIAL_ZS_CONSOLE */
+
+static struct uart_driver zs_reg = {
+	.owner			= THIS_MODULE,
+	.driver_name		= "serial",
+	.dev_name		= "ttyS",
+	.major			= TTY_MAJOR,
+	.minor			= 64,
+	.nr			= ZS_NUM_SCCS * ZS_NUM_CHAN,
+	.cons			= SERIAL_ZS_CONSOLE,
+};
+
+/* zs_init inits the driver. */
+static int __init zs_init(void)
+{
+	int i, ret;
+
+	pr_info("%s%s\n", zs_name, zs_version);
+
+	/* Find out how many Z85C30 SCCs we have.  */
+	ret = zs_probe_sccs();
+	if (ret)
+		return ret;
+
+	ret = uart_register_driver(&zs_reg);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < ZS_NUM_SCCS * ZS_NUM_CHAN; i++) {
+		struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
+		struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
+		struct uart_port *uport = &zport->port;
+
+		if (zport->scc)
+			uart_add_one_port(&zs_reg, uport);
+	}
+
+	return 0;
+}
+
+static void __exit zs_exit(void)
+{
+	int i;
+
+	for (i = ZS_NUM_SCCS * ZS_NUM_CHAN - 1; i >= 0; i--) {
+		struct zs_scc *scc = &zs_sccs[i / ZS_NUM_CHAN];
+		struct zs_port *zport = &scc->zport[i % ZS_NUM_CHAN];
+		struct uart_port *uport = &zport->port;
+
+		if (zport->scc)
+			uart_remove_one_port(&zs_reg, uport);
+	}
+
+	uart_unregister_driver(&zs_reg);
+}
+
+module_init(zs_init);
+module_exit(zs_exit);
diff --git a/drivers/serial/zs.h b/drivers/serial/zs.h
new file mode 100644
index 0000000..aa921b5
--- /dev/null
+++ b/drivers/serial/zs.h
@@ -0,0 +1,284 @@
+/*
+ * zs.h: Definitions for the DECstation Z85C30 serial driver.
+ *
+ * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
+ * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen.
+ *
+ * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 2004, 2005, 2007  Maciej W. Rozycki
+ */
+#ifndef _SERIAL_ZS_H
+#define _SERIAL_ZS_H
+
+#ifdef __KERNEL__
+
+#define ZS_NUM_REGS 16
+
+/*
+ * This is our internal structure for each serial port's state.
+ */
+struct zs_port {
+	struct zs_scc	*scc;			/* Containing SCC.  */
+	struct uart_port port;			/* Underlying UART.  */
+
+	int		clk_mode;		/* May be 1, 16, 32, or 64.  */
+
+	unsigned int	tty_break;		/* Set on BREAK condition.  */
+	int		tx_stopped;		/* Output is suspended.  */
+
+	unsigned int	mctrl;			/* State of modem lines.  */
+	u8		brk;			/* BREAK state from RR0.  */
+
+	u8		regs[ZS_NUM_REGS];	/* Channel write registers.  */
+};
+
+/*
+ * Per-SCC state for locking and the interrupt handler.
+ */
+struct zs_scc {
+	struct zs_port	zport[2];
+	spinlock_t	zlock;
+	atomic_t	irq_guard;
+	int		initialised;
+};
+
+#endif /* __KERNEL__ */
+
+/*
+ * Conversion routines to/from brg time constants from/to bits per second.
+ */
+#define ZS_BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
+#define ZS_BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
+
+/*
+ * The Zilog register set.
+ */
+
+/* Write Register 0 (Command) */
+#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 (Tx/Rx/Ext Int Enable and WAIT/DMA Commands) */
+#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 RxINT_ALL	0x10	/* Int on all Rx Characters or error */
+#define RxINT_ERR	0x18	/* Int on error only */
+#define RxINT_MASK	0x18
+
+#define WT_RDY_RT	0x20	/* Wait/Ready on R/T */
+#define WT_FN_RDYFN	0x40	/* Wait/FN/Ready FN */
+#define WT_RDY_ENAB	0x80	/* Wait/Ready Enable */
+
+/* Write Register 2 (Interrupt Vector) */
+
+/* Write Register 3 (Receive Parameters and Control) */
+#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 (Transmit/Receive Miscellaneous Parameters and Modes) */
+#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 (Transmit Parameters and Controls) */
+#define TxCRC_ENAB	0x1	/* Tx CRC Enable */
+#define RTS		0x2	/* RTS */
+#define SDLC_CRC	0x4	/* SDLC/CRC-16 */
+#define TxENAB		0x8	/* Tx Enable */
+#define SND_BRK		0x10	/* Send Break */
+#define Tx5		0x0	/* Tx 5 bits (or less)/character */
+#define Tx7		0x20	/* Tx 7 bits/character */
+#define Tx6		0x40	/* Tx 6 bits/character */
+#define Tx8		0x60	/* Tx 8 bits/character */
+#define TxNBITS_MASK	0x60
+#define DTR		0x80	/* DTR */
+
+/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
+
+/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
+
+/* Write Register 8 (Transmit Buffer) */
+
+/* Write Register 9 (Master Interrupt Control) */
+#define VIS		1	/* Vector Includes Status */
+#define NV		2	/* No Vector */
+#define DLC		4	/* Disable Lower Chain */
+#define MIE		8	/* Master Interrupt Enable */
+#define STATHI		0x10	/* Status high */
+#define SOFTACK		0x20	/* Software Interrupt Acknowledge */
+#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 (Miscellaneous Transmitter/Receiver 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 (Miscellaneous 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 WR7P_EN		1	/* WR7 Prime SDLC Feature Enable */
+#define ZCIE		2	/* Zero count IE */
+#define DCDIE		8	/* DCD IE */
+#define SYNCIE		0x10	/* Sync/hunt IE */
+#define CTSIE		0x20	/* CTS IE */
+#define TxUIE		0x40	/* Tx Underrun/EOM IE */
+#define BRKIE		0x80	/* Break/Abort IE */
+
+
+/* Read Register 0 (Transmit/Receive Buffer Status and External Status) */
+#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 (Special Receive Condition Status) */
+#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 (Interrupt Vector (WR2) -- channel A).  */
+
+/* Read Register 2 (Modified Interrupt Vector -- channel B).  */
+
+/* Read Register 3 (Interrupt Pending Bits -- channel 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 6 (SDLC FIFO Status and Byte Count LSB) */
+
+/* Read Register 7 (SDLC FIFO Status and Byte Count MSB) */
+
+/* Read Register 8 (Receive Data) */
+
+/* Read Register 10 (Miscellaneous 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 (WR12)) */
+
+/* Read Register 13 (Upper Byte of Baud Rate Generator Constant (WR13) */
+
+/* Read Register 15 (External/Status Interrupt Control (WR15)) */
+
+#endif /* _SERIAL_ZS_H */
diff --git a/drivers/sh/superhyway/superhyway.c b/drivers/sh/superhyway/superhyway.c
index 94b2290..7d873b3 100644
--- a/drivers/sh/superhyway/superhyway.c
+++ b/drivers/sh/superhyway/superhyway.c
@@ -56,11 +56,10 @@
 	struct superhyway_device *dev = sdev;
 
 	if (!dev) {
-		dev = kmalloc(sizeof(struct superhyway_device), GFP_KERNEL);
+		dev = kzalloc(sizeof(struct superhyway_device), GFP_KERNEL);
 		if (!dev)
 			return -ENOMEM;
 
-		memset(dev, 0, sizeof(struct superhyway_device));
 	}
 
 	dev->bus = bus;
diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c
index 2dd6eed..29fcd6d 100644
--- a/drivers/sn/ioc3.c
+++ b/drivers/sn/ioc3.c
@@ -629,7 +629,7 @@
 #endif
 
 	/* Set up per-IOC3 data */
-	idd = kmalloc(sizeof(struct ioc3_driver_data), GFP_KERNEL);
+	idd = kzalloc(sizeof(struct ioc3_driver_data), GFP_KERNEL);
 	if (!idd) {
 		printk(KERN_WARNING
 		       "%s: Failed to allocate IOC3 data for pci_dev %s.\n",
@@ -637,7 +637,6 @@
 		ret = -ENODEV;
 		goto out_idd;
 	}
-	memset(idd, 0, sizeof(struct ioc3_driver_data));
 	spin_lock_init(&idd->ir_lock);
 	spin_lock_init(&idd->gpio_lock);
 	idd->pdev = pdev;
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index ad14405..b046974 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -251,7 +251,7 @@
 		xfer->rx_dma = dma_map_single(dev,
 				xfer->rx_buf, xfer->len,
 				DMA_FROM_DEVICE);
-		if (dma_mapping_error(xfer->tx_dma)) {
+		if (dma_mapping_error(xfer->rx_dma)) {
 			if (xfer->tx_buf)
 				dma_unmap_single(dev,
 						xfer->tx_dma, xfer->len,
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 018884d..bcb8dd5 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -67,14 +67,11 @@
 	return strncmp(spi->modalias, drv->name, BUS_ID_SIZE) == 0;
 }
 
-static int spi_uevent(struct device *dev, char **envp, int num_envp,
-		char *buffer, int buffer_size)
+static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	const struct spi_device		*spi = to_spi_device(dev);
 
-	envp[0] = buffer;
-	snprintf(buffer, buffer_size, "MODALIAS=%s", spi->modalias);
-	envp[1] = NULL;
+	add_uevent_var(env, "MODALIAS=%s", spi->modalias);
 	return 0;
 }
 
@@ -200,6 +197,8 @@
  * platforms may not be able to use spi_register_board_info though, and
  * this is exported so that for example a USB or parport based adapter
  * driver could add devices (which it would learn about out-of-band).
+ *
+ * Returns the new device, or NULL.
  */
 struct spi_device *spi_new_device(struct spi_master *master,
 				  struct spi_board_info *chip)
@@ -208,7 +207,20 @@
 	struct device		*dev = master->cdev.dev;
 	int			status;
 
-	/* NOTE:  caller did any chip->bus_num checks necessary */
+	/* NOTE:  caller did any chip->bus_num checks necessary.
+	 *
+	 * Also, unless we change the return value convention to use
+	 * error-or-pointer (not NULL-or-pointer), troubleshootability
+	 * suggests syslogged diagnostics are best here (ugh).
+	 */
+
+	/* Chipselects are numbered 0..max; validate. */
+	if (chip->chip_select >= master->num_chipselect) {
+		dev_err(dev, "cs%d > max %d\n",
+			chip->chip_select,
+			master->num_chipselect);
+		return NULL;
+	}
 
 	if (!spi_master_get(master))
 		return NULL;
@@ -236,10 +248,10 @@
 	proxy->controller_state = NULL;
 	proxy->dev.release = spidev_release;
 
-	/* drivers may modify this default i/o setup */
+	/* drivers may modify this initial i/o setup */
 	status = master->setup(proxy);
 	if (status < 0) {
-		dev_dbg(dev, "can't %s %s, status %d\n",
+		dev_err(dev, "can't %s %s, status %d\n",
 				"setup", proxy->dev.bus_id, status);
 		goto fail;
 	}
@@ -249,7 +261,7 @@
 	 */
 	status = device_register(&proxy->dev);
 	if (status < 0) {
-		dev_dbg(dev, "can't %s %s, status %d\n",
+		dev_err(dev, "can't %s %s, status %d\n",
 				"add", proxy->dev.bus_id, status);
 		goto fail;
 	}
@@ -303,11 +315,9 @@
  * creates board info from kernel command lines
  */
 
-static void __init_or_module
-scan_boardinfo(struct spi_master *master)
+static void scan_boardinfo(struct spi_master *master)
 {
 	struct boardinfo	*bi;
-	struct device		*dev = master->cdev.dev;
 
 	mutex_lock(&board_lock);
 	list_for_each_entry(bi, &board_list, list) {
@@ -317,17 +327,9 @@
 		for (n = bi->n_board_info; n > 0; n--, chip++) {
 			if (chip->bus_num != master->bus_num)
 				continue;
-			/* some controllers only have one chip, so they
-			 * might not use chipselects.  otherwise, the
-			 * chipselects are numbered 0..max.
+			/* NOTE: this relies on spi_new_device to
+			 * issue diagnostics when given bogus inputs
 			 */
-			if (chip->chip_select >= master->num_chipselect
-					&& master->num_chipselect) {
-				dev_dbg(dev, "cs%d > max %d\n",
-					chip->chip_select,
-					master->num_chipselect);
-				continue;
-			}
 			(void) spi_new_device(master, chip);
 		}
 	}
@@ -420,8 +422,17 @@
 	if (!dev)
 		return -ENODEV;
 
+	/* even if it's just one always-selected device, there must
+	 * be at least one chipselect
+	 */
+	if (master->num_chipselect == 0)
+		return -EINVAL;
+
 	/* convention:  dynamically assigned bus IDs count down from the max */
 	if (master->bus_num < 0) {
+		/* FIXME switch to an IDR based scheme, something like
+		 * I2C now uses, so we can't run out of "dynamic" IDs
+		 */
 		master->bus_num = atomic_dec_return(&dyn_bus_id);
 		dynamic = 1;
 	}
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 48587c2..f540ed7 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -1303,8 +1303,9 @@
 #define bfin5xx_spi_resume NULL
 #endif				/* CONFIG_PM */
 
+MODULE_ALIAS("bfin-spi-master");	/* for platform bus hotplug */
 static struct platform_driver bfin5xx_spi_driver = {
-	.driver 	= {
+	.driver	= {
 		.name	= "bfin-spi-master",
 		.owner	= THIS_MODULE,
 	},
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index aee9ad6..bd9177f 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -1735,7 +1735,7 @@
 
 static struct platform_driver driver = {
 	.driver = {
-		.name = "imx-spi",
+		.name = "spi_imx",
 		.bus = &platform_bus_type,
 		.owner = THIS_MODULE,
 	},
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
index 3295cfc..32cda77 100644
--- a/drivers/spi/spi_mpc83xx.c
+++ b/drivers/spi/spi_mpc83xx.c
@@ -39,6 +39,7 @@
 };
 
 /* SPI Controller mode register definitions */
+#define	SPMODE_LOOP		(1 << 30)
 #define	SPMODE_CI_INACTIVEHIGH	(1 << 29)
 #define	SPMODE_CP_BEGIN_EDGECLK	(1 << 28)
 #define	SPMODE_DIV16		(1 << 27)
@@ -85,7 +86,7 @@
 
 	unsigned nsecs;		/* (clock cycle time)/2 */
 
-	u32 sysclk;
+	u32 spibrg;		/* SPIBRG input clock */
 	u32 rx_shift;		/* RX data reg shift when in qe mode */
 	u32 tx_shift;		/* TX data reg shift when in qe mode */
 
@@ -147,35 +148,48 @@
 	if (value == BITBANG_CS_ACTIVE) {
 		u32 regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
 		u32 len = spi->bits_per_word;
+		u8 pm;
+
 		if (len == 32)
 			len = 0;
 		else
 			len = len - 1;
 
 		/* mask out bits we are going to set */
-		regval &= ~0x38ff0000;
+		regval &= ~(SPMODE_CP_BEGIN_EDGECLK | SPMODE_CI_INACTIVEHIGH
+				| SPMODE_LEN(0xF) | SPMODE_DIV16
+				| SPMODE_PM(0xF) | SPMODE_REV | SPMODE_LOOP);
 
 		if (spi->mode & SPI_CPHA)
 			regval |= SPMODE_CP_BEGIN_EDGECLK;
 		if (spi->mode & SPI_CPOL)
 			regval |= SPMODE_CI_INACTIVEHIGH;
+		if (!(spi->mode & SPI_LSB_FIRST))
+			regval |= SPMODE_REV;
+		if (spi->mode & SPI_LOOP)
+			regval |= SPMODE_LOOP;
 
 		regval |= SPMODE_LEN(len);
 
-		if ((mpc83xx_spi->sysclk / spi->max_speed_hz) >= 64) {
-			u8 pm = mpc83xx_spi->sysclk / (spi->max_speed_hz * 64);
+		if ((mpc83xx_spi->spibrg / spi->max_speed_hz) >= 64) {
+			pm = mpc83xx_spi->spibrg / (spi->max_speed_hz * 64) - 1;
 			if (pm > 0x0f) {
-				printk(KERN_WARNING "MPC83xx SPI: SPICLK can't be less then a SYSCLK/1024!\n"
-						"Requested SPICLK is %d Hz. Will use %d Hz instead.\n",
-						spi->max_speed_hz, mpc83xx_spi->sysclk / 1024);
+				dev_err(&spi->dev, "Requested speed is too "
+					"low: %d Hz. Will use %d Hz instead.\n",
+					spi->max_speed_hz,
+					mpc83xx_spi->spibrg / 1024);
 				pm = 0x0f;
 			}
 			regval |= SPMODE_PM(pm) | SPMODE_DIV16;
 		} else {
-			u8 pm = mpc83xx_spi->sysclk / (spi->max_speed_hz * 4);
+			pm = mpc83xx_spi->spibrg / (spi->max_speed_hz * 4);
+			if (pm)
+				pm--;
 			regval |= SPMODE_PM(pm);
 		}
 
+		/* Turn off SPI unit prior changing mode */
+		mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, 0);
 		mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
 		if (mpc83xx_spi->activate_cs)
 			mpc83xx_spi->activate_cs(spi->chip_select, pol);
@@ -231,6 +245,14 @@
 	} else
 		return -EINVAL;
 
+	if (mpc83xx_spi->qe_mode && spi->mode & SPI_LSB_FIRST) {
+		mpc83xx_spi->tx_shift = 0;
+		if (bits_per_word <= 8)
+			mpc83xx_spi->rx_shift = 8;
+		else
+			mpc83xx_spi->rx_shift = 0;
+	}
+
 	/* nsecs = (clock period)/2 */
 	if (!hz)
 		hz = spi->max_speed_hz;
@@ -245,17 +267,22 @@
 
 	regval = mpc83xx_spi_read_reg(&mpc83xx_spi->base->mode);
 
-	/* Mask out bits_per_wordgth */
-	regval &= 0xff0fffff;
+	/* mask out bits we are going to set */
+	regval &= ~(SPMODE_LEN(0xF) | SPMODE_REV);
 	regval |= SPMODE_LEN(bits_per_word);
+	if (!(spi->mode & SPI_LSB_FIRST))
+		regval |= SPMODE_REV;
 
+	/* Turn off SPI unit prior changing mode */
+	mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, 0);
 	mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
 
 	return 0;
 }
 
 /* the spi->mode bits understood by this driver: */
-#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
+#define MODEBITS	(SPI_CPOL | SPI_CPHA | SPI_CS_HIGH \
+			| SPI_LSB_FIRST | SPI_LOOP)
 
 static int mpc83xx_spi_setup(struct spi_device *spi)
 {
@@ -357,11 +384,8 @@
 
 	mpc83xx_spi->count -= 1;
 	if (mpc83xx_spi->count) {
-		if (mpc83xx_spi->tx) {
-			u32 word = mpc83xx_spi->get_tx(mpc83xx_spi);
-			mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit,
-					      word);
-		}
+		u32 word = mpc83xx_spi->get_tx(mpc83xx_spi);
+		mpc83xx_spi_write_reg(&mpc83xx_spi->base->transmit, word);
 	} else {
 		complete(&mpc83xx_spi->done);
 	}
@@ -407,13 +431,17 @@
 	mpc83xx_spi->bitbang.chipselect = mpc83xx_spi_chipselect;
 	mpc83xx_spi->bitbang.setup_transfer = mpc83xx_spi_setup_transfer;
 	mpc83xx_spi->bitbang.txrx_bufs = mpc83xx_spi_bufs;
-	mpc83xx_spi->sysclk = pdata->sysclk;
 	mpc83xx_spi->activate_cs = pdata->activate_cs;
 	mpc83xx_spi->deactivate_cs = pdata->deactivate_cs;
 	mpc83xx_spi->qe_mode = pdata->qe_mode;
 	mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
 	mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
 
+	if (mpc83xx_spi->qe_mode)
+		mpc83xx_spi->spibrg = pdata->sysclk / 2;
+	else
+		mpc83xx_spi->spibrg = pdata->sysclk;
+
 	mpc83xx_spi->rx_shift = 0;
 	mpc83xx_spi->tx_shift = 0;
 	if (mpc83xx_spi->qe_mode) {
@@ -499,6 +527,7 @@
 	return 0;
 }
 
+MODULE_ALIAS("mpc83xx_spi");			/* for platform bus hotplug */
 static struct platform_driver mpc83xx_spi_driver = {
 	.probe = mpc83xx_spi_probe,
 	.remove = __devexit_p(mpc83xx_spi_remove),
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index 7071ff8..e9b683f 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -28,7 +28,7 @@
 #include <asm/hardware.h>
 
 #include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-spi.h>
+#include <asm/plat-s3c24xx/regs-spi.h>
 #include <asm/arch/spi.h>
 
 struct s3c24xx_spi {
@@ -427,6 +427,7 @@
 #define s3c24xx_spi_resume  NULL
 #endif
 
+MODULE_ALIAS("s3c2410_spi");			/* for platform bus hotplug */
 static struct platform_driver s3c24xx_spidrv = {
 	.probe		= s3c24xx_spi_probe,
 	.remove		= s3c24xx_spi_remove,
diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c
index 611ac22..0fa25e2 100644
--- a/drivers/spi/spi_s3c24xx_gpio.c
+++ b/drivers/spi/spi_s3c24xx_gpio.c
@@ -180,7 +180,7 @@
         .suspend	= s3c2410_spigpio_suspend,
         .resume		= s3c2410_spigpio_resume,
         .driver		= {
-		.name	= "s3c24xx-spi-gpio",
+		.name	= "spi_s3c24xx_gpio",
 		.owner	= THIS_MODULE,
         },
 };
diff --git a/drivers/spi/spi_txx9.c b/drivers/spi/spi_txx9.c
index 08e981c..b7f4bb2 100644
--- a/drivers/spi/spi_txx9.c
+++ b/drivers/spi/spi_txx9.c
@@ -453,7 +453,7 @@
 static struct platform_driver txx9spi_driver = {
 	.remove = __exit_p(txx9spi_remove),
 	.driver = {
-		.name = "txx9spi",
+		.name = "spi_txx9",
 		.owner = THIS_MODULE,
 	},
 };
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 38b60ad..c55459c 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -55,9 +55,16 @@
 static unsigned long	minors[N_SPI_MINORS / BITS_PER_LONG];
 
 
-/* Bit masks for spi_device.mode management */
-#define SPI_MODE_MASK			(SPI_CPHA | SPI_CPOL)
-
+/* Bit masks for spi_device.mode management.  Note that incorrect
+ * settings for CS_HIGH and 3WIRE can cause *lots* of trouble for other
+ * devices on a shared bus:  CS_HIGH, because this device will be
+ * active when it shouldn't be;  3WIRE, because when active it won't
+ * behave as it should.
+ *
+ * REVISIT should changing those two modes be privileged?
+ */
+#define SPI_MODE_MASK		(SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
+				| SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP)
 
 struct spidev_data {
 	struct device		dev;
@@ -176,7 +183,9 @@
 
 		if (u_tmp->rx_buf) {
 			k_tmp->rx_buf = buf;
-			if (!access_ok(VERIFY_WRITE, u_tmp->rx_buf, u_tmp->len))
+			if (!access_ok(VERIFY_WRITE, (u8 __user *)
+						(ptrdiff_t) u_tmp->rx_buf,
+						u_tmp->len))
 				goto done;
 		}
 		if (u_tmp->tx_buf) {
diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
index f0bf9a6..5d04f52 100644
--- a/drivers/spi/xilinx_spi.c
+++ b/drivers/spi/xilinx_spi.c
@@ -21,7 +21,7 @@
 
 #include <syslib/virtex_devices.h>
 
-#define XILINX_SPI_NAME "xspi"
+#define XILINX_SPI_NAME "xilinx_spi"
 
 /* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
  * Product Specification", DS464
diff --git a/drivers/ssb/Kconfig b/drivers/ssb/Kconfig
new file mode 100644
index 0000000..b4a5e5e
--- /dev/null
+++ b/drivers/ssb/Kconfig
@@ -0,0 +1,117 @@
+menu "Sonics Silicon Backplane"
+
+config SSB_POSSIBLE
+	bool
+	depends on HAS_IOMEM
+	default y
+
+config SSB
+	tristate "Sonics Silicon Backplane support"
+	depends on SSB_POSSIBLE
+	help
+	  Support for the Sonics Silicon Backplane bus.
+	  You only need to enable this option, if you are
+	  configuring a kernel for an embedded system with
+	  this bus.
+	  It will be auto-selected if needed in other
+	  environments.
+
+	  The module will be called ssb.
+
+	  If unsure, say N.
+
+config SSB_PCIHOST_POSSIBLE
+	bool
+	depends on SSB && PCI
+	default y
+
+config SSB_PCIHOST
+	bool "Support for SSB on PCI-bus host"
+	depends on SSB_PCIHOST_POSSIBLE
+	default y
+	help
+	  Support for a Sonics Silicon Backplane on top
+	  of a PCI device.
+
+	  If unsure, say Y
+
+config SSB_PCMCIAHOST_POSSIBLE
+	bool
+	depends on SSB && PCMCIA && EXPERIMENTAL
+	default y
+
+config SSB_PCMCIAHOST
+	bool "Support for SSB on PCMCIA-bus host (EXPERIMENTAL)"
+	depends on SSB_PCMCIAHOST_POSSIBLE
+	help
+	  Support for a Sonics Silicon Backplane on top
+	  of a PCMCIA device.
+
+	  If unsure, say N
+
+config SSB_SILENT
+	bool "No SSB kernel messages"
+	depends on SSB && EMBEDDED
+	help
+	  This option turns off all Sonics Silicon Backplane printks.
+	  Note that you won't be able to identify problems, once
+	  messages are turned off.
+	  This might only be desired for production kernels on
+	  embedded devices to reduce the kernel size.
+
+	  Say N
+
+config SSB_DEBUG
+	bool "SSB debugging"
+	depends on SSB && !SSB_SILENT
+	help
+	  This turns on additional runtime checks and debugging
+	  messages. Turn this on for SSB troubleshooting.
+
+	  If unsure, say N
+
+config SSB_SERIAL
+	bool
+	depends on SSB
+	# ChipCommon and ExtIf serial support routines.
+
+config SSB_DRIVER_PCICORE_POSSIBLE
+	bool
+	depends on SSB_PCIHOST
+	default y
+
+config SSB_DRIVER_PCICORE
+	bool "SSB PCI core driver"
+	depends on SSB_DRIVER_PCICORE_POSSIBLE
+	help
+	  Driver for the Sonics Silicon Backplane attached
+	  Broadcom PCI core.
+
+	  If unsure, say Y
+
+config SSB_PCICORE_HOSTMODE
+	bool "Hostmode support for SSB PCI core (EXPERIMENTAL)"
+	depends on SSB_DRIVER_PCICORE && SSB_DRIVER_MIPS && EXPERIMENTAL
+	help
+	  PCIcore hostmode operation (external PCI bus).
+
+config SSB_DRIVER_MIPS
+	bool "SSB Broadcom MIPS core driver (EXPERIMENTAL)"
+	depends on SSB && MIPS && EXPERIMENTAL
+	select SSB_SERIAL
+	help
+	  Driver for the Sonics Silicon Backplane attached
+	  Broadcom MIPS core.
+
+	  If unsure, say N
+
+config SSB_DRIVER_EXTIF
+	bool "SSB Broadcom EXTIF core driver (EXPERIMENTAL)"
+	depends on SSB_DRIVER_MIPS && EXPERIMENTAL
+	help
+	  Driver for the Sonics Silicon Backplane attached
+	  Broadcom EXTIF core.
+
+	  If unsure, say N
+
+endmenu
diff --git a/drivers/ssb/Makefile b/drivers/ssb/Makefile
new file mode 100644
index 0000000..7be3975
--- /dev/null
+++ b/drivers/ssb/Makefile
@@ -0,0 +1,18 @@
+# core
+ssb-y					+= main.o scan.o
+
+# host support
+ssb-$(CONFIG_SSB_PCIHOST)		+= pci.o pcihost_wrapper.o
+ssb-$(CONFIG_SSB_PCMCIAHOST)		+= pcmcia.o
+
+# built-in drivers
+ssb-y					+= driver_chipcommon.o
+ssb-$(CONFIG_SSB_DRIVER_MIPS)		+= driver_mipscore.o
+ssb-$(CONFIG_SSB_DRIVER_EXTIF)		+= driver_extif.o
+ssb-$(CONFIG_SSB_DRIVER_PCICORE)	+= driver_pcicore.o
+
+# b43 pci-ssb-bridge driver
+# Not strictly a part of SSB, but kept here for convenience
+ssb-$(CONFIG_SSB_PCIHOST)		+= b43_pci_bridge.o
+
+obj-$(CONFIG_SSB)			+= ssb.o
diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c
new file mode 100644
index 0000000..f145d8a
--- /dev/null
+++ b/drivers/ssb/b43_pci_bridge.c
@@ -0,0 +1,48 @@
+/*
+ * Broadcom 43xx PCI-SSB bridge module
+ *
+ * This technically is a seperate PCI driver module, but
+ * because of its small size we include it in the SSB core
+ * instead of creating a standalone module.
+ *
+ * Copyright 2007  Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/pci.h>
+#include <linux/ssb/ssb.h>
+
+#include "ssb_private.h"
+
+
+static const struct pci_device_id b43_pci_bridge_tbl[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4301) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4307) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4311) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4312) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4318) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) },
+	{ 0, },
+};
+MODULE_DEVICE_TABLE(pci, b43_pci_bridge_tbl);
+
+static struct pci_driver b43_pci_bridge_driver = {
+	.name = "b43-pci-bridge",
+	.id_table = b43_pci_bridge_tbl,
+};
+
+
+int __init b43_pci_ssb_bridge_init(void)
+{
+	return ssb_pcihost_register(&b43_pci_bridge_driver);
+}
+
+void __exit b43_pci_ssb_bridge_exit(void)
+{
+	ssb_pcihost_unregister(&b43_pci_bridge_driver);
+}
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
new file mode 100644
index 0000000..6fbf1c5
--- /dev/null
+++ b/drivers/ssb/driver_chipcommon.c
@@ -0,0 +1,445 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom ChipCommon core driver
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_regs.h>
+#include <linux/pci.h>
+
+#include "ssb_private.h"
+
+
+/* Clock sources */
+enum ssb_clksrc {
+	/* PCI clock */
+	SSB_CHIPCO_CLKSRC_PCI,
+	/* Crystal slow clock oscillator */
+	SSB_CHIPCO_CLKSRC_XTALOS,
+	/* Low power oscillator */
+	SSB_CHIPCO_CLKSRC_LOPWROS,
+};
+
+
+static inline u32 chipco_read32(struct ssb_chipcommon *cc,
+				u16 offset)
+{
+	return ssb_read32(cc->dev, offset);
+}
+
+static inline void chipco_write32(struct ssb_chipcommon *cc,
+				  u16 offset,
+				  u32 value)
+{
+	ssb_write32(cc->dev, offset, value);
+}
+
+static inline void chipco_write32_masked(struct ssb_chipcommon *cc, u16 offset,
+					 u32 mask, u32 value)
+{
+	value &= mask;
+	value |= chipco_read32(cc, offset) & ~mask;
+	chipco_write32(cc, offset, value);
+}
+
+void ssb_chipco_set_clockmode(struct ssb_chipcommon *cc,
+			      enum ssb_clkmode mode)
+{
+	struct ssb_device *ccdev = cc->dev;
+	struct ssb_bus *bus;
+	u32 tmp;
+
+	if (!ccdev)
+		return;
+	bus = ccdev->bus;
+	/* chipcommon cores prior to rev6 don't support dynamic clock control */
+	if (ccdev->id.revision < 6)
+		return;
+	/* chipcommon cores rev10 are a whole new ball game */
+	if (ccdev->id.revision >= 10)
+		return;
+	if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
+		return;
+
+	switch (mode) {
+	case SSB_CLKMODE_SLOW:
+		tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+		tmp |= SSB_CHIPCO_SLOWCLKCTL_FSLOW;
+		chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
+		break;
+	case SSB_CLKMODE_FAST:
+		ssb_pci_xtal(bus, SSB_GPIO_XTAL, 1); /* Force crystal on */
+		tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+		tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
+		tmp |= SSB_CHIPCO_SLOWCLKCTL_IPLL;
+		chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
+		break;
+	case SSB_CLKMODE_DYNAMIC:
+		tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+		tmp &= ~SSB_CHIPCO_SLOWCLKCTL_FSLOW;
+		tmp &= ~SSB_CHIPCO_SLOWCLKCTL_IPLL;
+		tmp &= ~SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
+		if ((tmp & SSB_CHIPCO_SLOWCLKCTL_SRC) != SSB_CHIPCO_SLOWCLKCTL_SRC_XTAL)
+			tmp |= SSB_CHIPCO_SLOWCLKCTL_ENXTAL;
+		chipco_write32(cc, SSB_CHIPCO_SLOWCLKCTL, tmp);
+
+		/* for dynamic control, we have to release our xtal_pu "force on" */
+		if (tmp & SSB_CHIPCO_SLOWCLKCTL_ENXTAL)
+			ssb_pci_xtal(bus, SSB_GPIO_XTAL, 0);
+		break;
+	default:
+		SSB_WARN_ON(1);
+	}
+}
+
+/* Get the Slow Clock Source */
+static enum ssb_clksrc chipco_pctl_get_slowclksrc(struct ssb_chipcommon *cc)
+{
+	struct ssb_bus *bus = cc->dev->bus;
+	u32 uninitialized_var(tmp);
+
+	if (cc->dev->id.revision < 6) {
+		if (bus->bustype == SSB_BUSTYPE_SSB ||
+		    bus->bustype == SSB_BUSTYPE_PCMCIA)
+			return SSB_CHIPCO_CLKSRC_XTALOS;
+		if (bus->bustype == SSB_BUSTYPE_PCI) {
+			pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &tmp);
+			if (tmp & 0x10)
+				return SSB_CHIPCO_CLKSRC_PCI;
+			return SSB_CHIPCO_CLKSRC_XTALOS;
+		}
+	}
+	if (cc->dev->id.revision < 10) {
+		tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+		tmp &= 0x7;
+		if (tmp == 0)
+			return SSB_CHIPCO_CLKSRC_LOPWROS;
+		if (tmp == 1)
+			return SSB_CHIPCO_CLKSRC_XTALOS;
+		if (tmp == 2)
+			return SSB_CHIPCO_CLKSRC_PCI;
+	}
+
+	return SSB_CHIPCO_CLKSRC_XTALOS;
+}
+
+/* Get maximum or minimum (depending on get_max flag) slowclock frequency. */
+static int chipco_pctl_clockfreqlimit(struct ssb_chipcommon *cc, int get_max)
+{
+	int uninitialized_var(limit);
+	enum ssb_clksrc clocksrc;
+	int divisor = 1;
+	u32 tmp;
+
+	clocksrc = chipco_pctl_get_slowclksrc(cc);
+	if (cc->dev->id.revision < 6) {
+		switch (clocksrc) {
+		case SSB_CHIPCO_CLKSRC_PCI:
+			divisor = 64;
+			break;
+		case SSB_CHIPCO_CLKSRC_XTALOS:
+			divisor = 32;
+			break;
+		default:
+			SSB_WARN_ON(1);
+		}
+	} else if (cc->dev->id.revision < 10) {
+		switch (clocksrc) {
+		case SSB_CHIPCO_CLKSRC_LOPWROS:
+			break;
+		case SSB_CHIPCO_CLKSRC_XTALOS:
+		case SSB_CHIPCO_CLKSRC_PCI:
+			tmp = chipco_read32(cc, SSB_CHIPCO_SLOWCLKCTL);
+			divisor = (tmp >> 16) + 1;
+			divisor *= 4;
+			break;
+		}
+	} else {
+		tmp = chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL);
+		divisor = (tmp >> 16) + 1;
+		divisor *= 4;
+	}
+
+	switch (clocksrc) {
+	case SSB_CHIPCO_CLKSRC_LOPWROS:
+		if (get_max)
+			limit = 43000;
+		else
+			limit = 25000;
+		break;
+	case SSB_CHIPCO_CLKSRC_XTALOS:
+		if (get_max)
+			limit = 20200000;
+		else
+			limit = 19800000;
+		break;
+	case SSB_CHIPCO_CLKSRC_PCI:
+		if (get_max)
+			limit = 34000000;
+		else
+			limit = 25000000;
+		break;
+	}
+	limit /= divisor;
+
+	return limit;
+}
+
+static void chipco_powercontrol_init(struct ssb_chipcommon *cc)
+{
+	struct ssb_bus *bus = cc->dev->bus;
+
+	if (bus->chip_id == 0x4321) {
+		if (bus->chip_rev == 0)
+			chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0x3A4);
+		else if (bus->chip_rev == 1)
+			chipco_write32(cc, SSB_CHIPCO_CHIPCTL, 0xA4);
+	}
+
+	if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
+		return;
+
+	if (cc->dev->id.revision >= 10) {
+		/* Set Idle Power clock rate to 1Mhz */
+		chipco_write32(cc, SSB_CHIPCO_SYSCLKCTL,
+			       (chipco_read32(cc, SSB_CHIPCO_SYSCLKCTL) &
+				0x0000FFFF) | 0x00040000);
+	} else {
+		int maxfreq;
+
+		maxfreq = chipco_pctl_clockfreqlimit(cc, 1);
+		chipco_write32(cc, SSB_CHIPCO_PLLONDELAY,
+			       (maxfreq * 150 + 999999) / 1000000);
+		chipco_write32(cc, SSB_CHIPCO_FREFSELDELAY,
+			       (maxfreq * 15 + 999999) / 1000000);
+	}
+}
+
+static void calc_fast_powerup_delay(struct ssb_chipcommon *cc)
+{
+	struct ssb_bus *bus = cc->dev->bus;
+	int minfreq;
+	unsigned int tmp;
+	u32 pll_on_delay;
+
+	if (bus->bustype != SSB_BUSTYPE_PCI)
+		return;
+	if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
+		return;
+
+	minfreq = chipco_pctl_clockfreqlimit(cc, 0);
+	pll_on_delay = chipco_read32(cc, SSB_CHIPCO_PLLONDELAY);
+	tmp = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq;
+	SSB_WARN_ON(tmp & ~0xFFFF);
+
+	cc->fast_pwrup_delay = tmp;
+}
+
+void ssb_chipcommon_init(struct ssb_chipcommon *cc)
+{
+	if (!cc->dev)
+		return; /* We don't have a ChipCommon */
+	chipco_powercontrol_init(cc);
+	ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
+	calc_fast_powerup_delay(cc);
+}
+
+void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state)
+{
+	if (!cc->dev)
+		return;
+	ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW);
+}
+
+void ssb_chipco_resume(struct ssb_chipcommon *cc)
+{
+	if (!cc->dev)
+		return;
+	chipco_powercontrol_init(cc);
+	ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
+}
+
+/* Get the processor clock */
+void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,
+                             u32 *plltype, u32 *n, u32 *m)
+{
+	*n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
+	*plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
+	switch (*plltype) {
+	case SSB_PLLTYPE_2:
+	case SSB_PLLTYPE_4:
+	case SSB_PLLTYPE_6:
+	case SSB_PLLTYPE_7:
+		*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS);
+		break;
+	case SSB_PLLTYPE_3:
+		/* 5350 uses m2 to control mips */
+		*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2);
+		break;
+	default:
+		*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB);
+		break;
+	}
+}
+
+/* Get the bus clock */
+void ssb_chipco_get_clockcontrol(struct ssb_chipcommon *cc,
+				 u32 *plltype, u32 *n, u32 *m)
+{
+	*n = chipco_read32(cc, SSB_CHIPCO_CLOCK_N);
+	*plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
+	switch (*plltype) {
+	case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
+		*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_MIPS);
+		break;
+	case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
+		if (cc->dev->bus->chip_id != 0x5365) {
+			*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_M2);
+			break;
+		}
+		/* Fallthough */
+	default:
+		*m = chipco_read32(cc, SSB_CHIPCO_CLOCK_SB);
+	}
+}
+
+void ssb_chipco_timing_init(struct ssb_chipcommon *cc,
+			    unsigned long ns)
+{
+	struct ssb_device *dev = cc->dev;
+	struct ssb_bus *bus = dev->bus;
+	u32 tmp;
+
+	/* set register for external IO to control LED. */
+	chipco_write32(cc, SSB_CHIPCO_PROG_CFG, 0x11);
+	tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT;		/* Waitcount-3 = 10ns */
+	tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT;	/* Waitcount-1 = 40ns */
+	tmp |= DIV_ROUND_UP(240, ns);				/* Waitcount-0 = 240ns */
+	chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp);	/* 0x01020a0c for a 100Mhz clock */
+
+	/* Set timing for the flash */
+	tmp = DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_3_SHIFT;	/* Waitcount-3 = 10nS */
+	tmp |= DIV_ROUND_UP(10, ns) << SSB_FLASH_WCNT_1_SHIFT;	/* Waitcount-1 = 10nS */
+	tmp |= DIV_ROUND_UP(120, ns);				/* Waitcount-0 = 120nS */
+	if ((bus->chip_id == 0x5365) ||
+	    (dev->id.revision < 9))
+		chipco_write32(cc, SSB_CHIPCO_FLASH_WAITCNT, tmp);
+	if ((bus->chip_id == 0x5365) ||
+	    (dev->id.revision < 9) ||
+	    ((bus->chip_id == 0x5350) && (bus->chip_rev == 0)))
+		chipco_write32(cc, SSB_CHIPCO_PCMCIA_MEMWAIT, tmp);
+
+	if (bus->chip_id == 0x5350) {
+		/* Enable EXTIF */
+		tmp = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT;	  /* Waitcount-3 = 10ns */
+		tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT;  /* Waitcount-2 = 20ns */
+		tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT; /* Waitcount-1 = 100ns */
+		tmp |= DIV_ROUND_UP(120, ns);			  /* Waitcount-0 = 120ns */
+		chipco_write32(cc, SSB_CHIPCO_PROG_WAITCNT, tmp); /* 0x01020a0c for a 100Mhz clock */
+	}
+}
+
+/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
+void ssb_chipco_watchdog_timer_set(struct ssb_chipcommon *cc, u32 ticks)
+{
+	/* instant NMI */
+	chipco_write32(cc, SSB_CHIPCO_WATCHDOG, ticks);
+}
+
+u32 ssb_chipco_gpio_in(struct ssb_chipcommon *cc, u32 mask)
+{
+	return chipco_read32(cc, SSB_CHIPCO_GPIOIN) & mask;
+}
+
+void ssb_chipco_gpio_out(struct ssb_chipcommon *cc, u32 mask, u32 value)
+{
+	chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUT, mask, value);
+}
+
+void ssb_chipco_gpio_outen(struct ssb_chipcommon *cc, u32 mask, u32 value)
+{
+	chipco_write32_masked(cc, SSB_CHIPCO_GPIOOUTEN, mask, value);
+}
+
+#ifdef CONFIG_SSB_SERIAL
+int ssb_chipco_serial_init(struct ssb_chipcommon *cc,
+			   struct ssb_serial_port *ports)
+{
+	struct ssb_bus *bus = cc->dev->bus;
+	int nr_ports = 0;
+	u32 plltype;
+	unsigned int irq;
+	u32 baud_base, div;
+	u32 i, n;
+
+	plltype = (cc->capabilities & SSB_CHIPCO_CAP_PLLT);
+	irq = ssb_mips_irq(cc->dev);
+
+	if (plltype == SSB_PLLTYPE_1) {
+		/* PLL clock */
+		baud_base = ssb_calc_clock_rate(plltype,
+						chipco_read32(cc, SSB_CHIPCO_CLOCK_N),
+						chipco_read32(cc, SSB_CHIPCO_CLOCK_M2));
+		div = 1;
+	} else {
+		if (cc->dev->id.revision >= 11) {
+			/* Fixed ALP clock */
+			baud_base = 20000000;
+			div = 1;
+			/* Set the override bit so we don't divide it */
+			chipco_write32(cc, SSB_CHIPCO_CORECTL,
+				       SSB_CHIPCO_CORECTL_UARTCLK0);
+		} else if (cc->dev->id.revision >= 3) {
+			/* Internal backplane clock */
+			baud_base = ssb_clockspeed(bus);
+			div = chipco_read32(cc, SSB_CHIPCO_CLKDIV)
+			      & SSB_CHIPCO_CLKDIV_UART;
+		} else {
+			/* Fixed internal backplane clock */
+			baud_base = 88000000;
+			div = 48;
+		}
+
+		/* Clock source depends on strapping if UartClkOverride is unset */
+		if ((cc->dev->id.revision > 0) &&
+		    !(chipco_read32(cc, SSB_CHIPCO_CORECTL) & SSB_CHIPCO_CORECTL_UARTCLK0)) {
+			if ((cc->capabilities & SSB_CHIPCO_CAP_UARTCLK) ==
+			    SSB_CHIPCO_CAP_UARTCLK_INT) {
+				/* Internal divided backplane clock */
+				baud_base /= div;
+			} else {
+				/* Assume external clock of 1.8432 MHz */
+				baud_base = 1843200;
+			}
+		}
+	}
+
+	/* Determine the registers of the UARTs */
+	n = (cc->capabilities & SSB_CHIPCO_CAP_NRUART);
+	for (i = 0; i < n; i++) {
+		void __iomem *cc_mmio;
+		void __iomem *uart_regs;
+
+		cc_mmio = cc->dev->bus->mmio + (cc->dev->core_index * SSB_CORE_SIZE);
+		uart_regs = cc_mmio + SSB_CHIPCO_UART0_DATA;
+		/* Offset changed at after rev 0 */
+		if (cc->dev->id.revision == 0)
+			uart_regs += (i * 8);
+		else
+			uart_regs += (i * 256);
+
+		nr_ports++;
+		ports[i].regs = uart_regs;
+		ports[i].irq = irq;
+		ports[i].baud_base = baud_base;
+		ports[i].reg_shift = 0;
+	}
+
+	return nr_ports;
+}
+#endif /* CONFIG_SSB_SERIAL */
diff --git a/drivers/ssb/driver_extif.c b/drivers/ssb/driver_extif.c
new file mode 100644
index 0000000..fe55eb8
--- /dev/null
+++ b/drivers/ssb/driver_extif.c
@@ -0,0 +1,129 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom EXTIF core driver
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ * Copyright 2006, 2007, Felix Fietkau <nbd@openwrt.org>
+ * Copyright 2007, Aurelien Jarno <aurelien@aurel32.net>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+
+#include "ssb_private.h"
+
+
+static inline u32 extif_read32(struct ssb_extif *extif, u16 offset)
+{
+	return ssb_read32(extif->dev, offset);
+}
+
+static inline void extif_write32(struct ssb_extif *extif, u16 offset, u32 value)
+{
+	ssb_write32(extif->dev, offset, value);
+}
+
+static inline void extif_write32_masked(struct ssb_extif *extif, u16 offset,
+					u32 mask, u32 value)
+{
+	value &= mask;
+	value |= extif_read32(extif, offset) & ~mask;
+	extif_write32(extif, offset, value);
+}
+
+#ifdef CONFIG_SSB_SERIAL
+static bool serial_exists(u8 *regs)
+{
+	u8 save_mcr, msr = 0;
+
+	if (regs) {
+		save_mcr = regs[UART_MCR];
+		regs[UART_MCR] = (UART_MCR_LOOP | UART_MCR_OUT2 | UART_MCR_RTS);
+		msr = regs[UART_MSR] & (UART_MSR_DCD | UART_MSR_RI
+					| UART_MSR_CTS | UART_MSR_DSR);
+		regs[UART_MCR] = save_mcr;
+	}
+	return (msr == (UART_MSR_DCD | UART_MSR_CTS));
+}
+
+int ssb_extif_serial_init(struct ssb_extif *extif, struct ssb_serial_port *ports)
+{
+	u32 i, nr_ports = 0;
+
+	/* Disable GPIO interrupt initially */
+	extif_write32(extif, SSB_EXTIF_GPIO_INTPOL, 0);
+	extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 0);
+
+	for (i = 0; i < 2; i++) {
+		void __iomem *uart_regs;
+
+		uart_regs = ioremap_nocache(SSB_EUART, 16);
+		if (uart_regs) {
+			uart_regs += (i * 8);
+
+			if (serial_exists(uart_regs) && ports) {
+				extif_write32(extif, SSB_EXTIF_GPIO_INTMASK, 2);
+
+				nr_ports++;
+				ports[i].regs = uart_regs;
+				ports[i].irq = 2;
+				ports[i].baud_base = 13500000;
+				ports[i].reg_shift = 0;
+			}
+			iounmap(uart_regs);
+		}
+	}
+	return nr_ports;
+}
+#endif /* CONFIG_SSB_SERIAL */
+
+void ssb_extif_timing_init(struct ssb_extif *extif, unsigned long ns)
+{
+	u32 tmp;
+
+	/* Initialize extif so we can get to the LEDs and external UART */
+	extif_write32(extif, SSB_EXTIF_PROG_CFG, SSB_EXTCFG_EN);
+
+	/* Set timing for the flash */
+	tmp  = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT;
+	tmp |= DIV_ROUND_UP(40, ns) << SSB_PROG_WCNT_1_SHIFT;
+	tmp |= DIV_ROUND_UP(120, ns);
+	extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp);
+
+	/* Set programmable interface timing for external uart */
+	tmp  = DIV_ROUND_UP(10, ns) << SSB_PROG_WCNT_3_SHIFT;
+	tmp |= DIV_ROUND_UP(20, ns) << SSB_PROG_WCNT_2_SHIFT;
+	tmp |= DIV_ROUND_UP(100, ns) << SSB_PROG_WCNT_1_SHIFT;
+	tmp |= DIV_ROUND_UP(120, ns);
+	extif_write32(extif, SSB_EXTIF_PROG_WAITCNT, tmp);
+}
+
+void ssb_extif_get_clockcontrol(struct ssb_extif *extif,
+				u32 *pll_type, u32 *n, u32 *m)
+{
+	*pll_type = SSB_PLLTYPE_1;
+	*n = extif_read32(extif, SSB_EXTIF_CLOCK_N);
+	*m = extif_read32(extif, SSB_EXTIF_CLOCK_SB);
+}
+
+u32 ssb_extif_gpio_in(struct ssb_extif *extif, u32 mask)
+{
+	return extif_read32(extif, SSB_EXTIF_GPIO_IN) & mask;
+}
+
+void ssb_extif_gpio_out(struct ssb_extif *extif, u32 mask, u32 value)
+{
+	return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUT(0),
+				   mask, value);
+}
+
+void ssb_extif_gpio_outen(struct ssb_extif *extif, u32 mask, u32 value)
+{
+	return extif_write32_masked(extif, SSB_EXTIF_GPIO_OUTEN(0),
+				   mask, value);
+}
+
diff --git a/drivers/ssb/driver_mipscore.c b/drivers/ssb/driver_mipscore.c
new file mode 100644
index 0000000..ab8691a
--- /dev/null
+++ b/drivers/ssb/driver_mipscore.c
@@ -0,0 +1,223 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom MIPS core driver
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/time.h>
+
+#include "ssb_private.h"
+
+
+static inline u32 mips_read32(struct ssb_mipscore *mcore,
+			      u16 offset)
+{
+	return ssb_read32(mcore->dev, offset);
+}
+
+static inline void mips_write32(struct ssb_mipscore *mcore,
+				u16 offset,
+				u32 value)
+{
+	ssb_write32(mcore->dev, offset, value);
+}
+
+static const u32 ipsflag_irq_mask[] = {
+	0,
+	SSB_IPSFLAG_IRQ1,
+	SSB_IPSFLAG_IRQ2,
+	SSB_IPSFLAG_IRQ3,
+	SSB_IPSFLAG_IRQ4,
+};
+
+static const u32 ipsflag_irq_shift[] = {
+	0,
+	SSB_IPSFLAG_IRQ1_SHIFT,
+	SSB_IPSFLAG_IRQ2_SHIFT,
+	SSB_IPSFLAG_IRQ3_SHIFT,
+	SSB_IPSFLAG_IRQ4_SHIFT,
+};
+
+static inline u32 ssb_irqflag(struct ssb_device *dev)
+{
+	return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
+}
+
+/* Get the MIPS IRQ assignment for a specified device.
+ * If unassigned, 0 is returned.
+ */
+unsigned int ssb_mips_irq(struct ssb_device *dev)
+{
+	struct ssb_bus *bus = dev->bus;
+	u32 irqflag;
+	u32 ipsflag;
+	u32 tmp;
+	unsigned int irq;
+
+	irqflag = ssb_irqflag(dev);
+	ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG);
+	for (irq = 1; irq <= 4; irq++) {
+		tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]);
+		if (tmp == irqflag)
+			break;
+	}
+	if (irq	== 5)
+		irq = 0;
+
+	return irq;
+}
+
+static void clear_irq(struct ssb_bus *bus, unsigned int irq)
+{
+	struct ssb_device *dev = bus->mipscore.dev;
+
+	/* Clear the IRQ in the MIPScore backplane registers */
+	if (irq == 0) {
+		ssb_write32(dev, SSB_INTVEC, 0);
+	} else {
+		ssb_write32(dev, SSB_IPSFLAG,
+			    ssb_read32(dev, SSB_IPSFLAG) |
+			    ipsflag_irq_mask[irq]);
+	}
+}
+
+static void set_irq(struct ssb_device *dev, unsigned int irq)
+{
+	unsigned int oldirq = ssb_mips_irq(dev);
+	struct ssb_bus *bus = dev->bus;
+	struct ssb_device *mdev = bus->mipscore.dev;
+	u32 irqflag = ssb_irqflag(dev);
+
+	dev->irq = irq + 2;
+
+	ssb_dprintk(KERN_INFO PFX
+		    "set_irq: core 0x%04x, irq %d => %d\n",
+		    dev->id.coreid, oldirq, irq);
+	/* clear the old irq */
+	if (oldirq == 0)
+		ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
+	else
+		clear_irq(bus, oldirq);
+
+	/* assign the new one */
+	if (irq == 0)
+		ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
+
+	irqflag <<= ipsflag_irq_shift[irq];
+	irqflag |= (ssb_read32(mdev, SSB_IPSFLAG) & ~ipsflag_irq_mask[irq]);
+	ssb_write32(mdev, SSB_IPSFLAG, irqflag);
+}
+
+static void ssb_mips_serial_init(struct ssb_mipscore *mcore)
+{
+	struct ssb_bus *bus = mcore->dev->bus;
+
+	if (bus->extif.dev)
+		mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports);
+	else if (bus->chipco.dev)
+		mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports);
+	else
+		mcore->nr_serial_ports = 0;
+}
+
+static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
+{
+	struct ssb_bus *bus = mcore->dev->bus;
+
+	mcore->flash_buswidth = 2;
+	if (bus->chipco.dev) {
+		mcore->flash_window = 0x1c000000;
+		mcore->flash_window_size = 0x02000000;
+		if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
+		               & SSB_CHIPCO_CFG_DS16) == 0)
+			mcore->flash_buswidth = 1;
+	} else {
+		mcore->flash_window = 0x1fc00000;
+		mcore->flash_window_size = 0x00400000;
+	}
+}
+
+u32 ssb_cpu_clock(struct ssb_mipscore *mcore)
+{
+	struct ssb_bus *bus = mcore->dev->bus;
+	u32 pll_type, n, m, rate = 0;
+
+	if (bus->extif.dev) {
+		ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m);
+	} else if (bus->chipco.dev) {
+		ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m);
+	} else
+		return 0;
+
+	if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) {
+		rate = 200000000;
+	} else {
+		rate = ssb_calc_clock_rate(pll_type, n, m);
+	}
+
+	if (pll_type == SSB_PLLTYPE_6) {
+		rate *= 2;
+	}
+
+	return rate;
+}
+
+void ssb_mipscore_init(struct ssb_mipscore *mcore)
+{
+	struct ssb_bus *bus = mcore->dev->bus;
+	struct ssb_device *dev;
+	unsigned long hz, ns;
+	unsigned int irq, i;
+
+	if (!mcore->dev)
+		return; /* We don't have a MIPS core */
+
+	ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n");
+
+	hz = ssb_clockspeed(bus);
+	if (!hz)
+		hz = 100000000;
+	ns = 1000000000 / hz;
+
+	if (bus->extif.dev)
+		ssb_extif_timing_init(&bus->extif, ns);
+	else if (bus->chipco.dev)
+		ssb_chipco_timing_init(&bus->chipco, ns);
+
+	/* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */
+	for (irq = 2, i = 0; i < bus->nr_devices; i++) {
+		dev = &(bus->devices[i]);
+		dev->irq = ssb_mips_irq(dev) + 2;
+		switch (dev->id.coreid) {
+		case SSB_DEV_USB11_HOST:
+			/* shouldn't need a separate irq line for non-4710, most of them have a proper
+			 * external usb controller on the pci */
+			if ((bus->chip_id == 0x4710) && (irq <= 4)) {
+				set_irq(dev, irq++);
+				break;
+			}
+			/* fallthrough */
+		case SSB_DEV_PCI:
+		case SSB_DEV_ETHERNET:
+		case SSB_DEV_80211:
+		case SSB_DEV_USB20_HOST:
+			/* These devices get their own IRQ line if available, the rest goes on IRQ0 */
+			if (irq <= 4) {
+				set_irq(dev, irq++);
+				break;
+			}
+		}
+	}
+
+	ssb_mips_serial_init(mcore);
+	ssb_mips_flash_detect(mcore);
+}
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
new file mode 100644
index 0000000..2faaa90
--- /dev/null
+++ b/drivers/ssb/driver_pcicore.c
@@ -0,0 +1,576 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom PCI-core driver
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "ssb_private.h"
+
+
+static inline
+u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset)
+{
+	return ssb_read32(pc->dev, offset);
+}
+
+static inline
+void pcicore_write32(struct ssb_pcicore *pc, u16 offset, u32 value)
+{
+	ssb_write32(pc->dev, offset, value);
+}
+
+/**************************************************
+ * Code for hostmode operation.
+ **************************************************/
+
+#ifdef CONFIG_SSB_PCICORE_HOSTMODE
+
+#include <asm/paccess.h>
+/* Probe a 32bit value on the bus and catch bus exceptions.
+ * Returns nonzero on a bus exception.
+ * This is MIPS specific */
+#define mips_busprobe32(val, addr)	get_dbe((val), ((u32 *)(addr)))
+
+/* Assume one-hot slot wiring */
+#define SSB_PCI_SLOT_MAX	16
+
+/* Global lock is OK, as we won't have more than one extpci anyway. */
+static DEFINE_SPINLOCK(cfgspace_lock);
+/* Core to access the external PCI config space. Can only have one. */
+static struct ssb_pcicore *extpci_core;
+
+static u32 ssb_pcicore_pcibus_iobase = 0x100;
+static u32 ssb_pcicore_pcibus_membase = SSB_PCI_DMA;
+
+int pcibios_plat_dev_init(struct pci_dev *d)
+{
+	struct resource *res;
+	int pos, size;
+	u32 *base;
+
+	ssb_printk(KERN_INFO "PCI: Fixing up device %s\n",
+		   pci_name(d));
+
+	/* Fix up resource bases */
+	for (pos = 0; pos < 6; pos++) {
+		res = &d->resource[pos];
+		if (res->flags & IORESOURCE_IO)
+			base = &ssb_pcicore_pcibus_iobase;
+		else
+			base = &ssb_pcicore_pcibus_membase;
+		if (res->end) {
+			size = res->end - res->start + 1;
+			if (*base & (size - 1))
+				*base = (*base + size) & ~(size - 1);
+			res->start = *base;
+			res->end = res->start + size - 1;
+			*base += size;
+			pci_write_config_dword(d, PCI_BASE_ADDRESS_0 + (pos << 2), res->start);
+		}
+		/* Fix up PCI bridge BAR0 only */
+		if (d->bus->number == 0 && PCI_SLOT(d->devfn) == 0)
+			break;
+	}
+	/* Fix up interrupt lines */
+	d->irq = ssb_mips_irq(extpci_core->dev) + 2;
+	pci_write_config_byte(d, PCI_INTERRUPT_LINE, d->irq);
+
+	return 0;
+}
+
+static void __init ssb_fixup_pcibridge(struct pci_dev *dev)
+{
+	if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) != 0)
+		return;
+
+	ssb_printk(KERN_INFO "PCI: fixing up bridge\n");
+
+	/* Enable PCI bridge bus mastering and memory space */
+	pci_set_master(dev);
+	pcibios_enable_device(dev, ~0);
+
+	/* Enable PCI bridge BAR1 prefetch and burst */
+	pci_write_config_dword(dev, SSB_BAR1_CONTROL, 3);
+
+	/* Make sure our latency is high enough to handle the devices behind us */
+	pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xa8);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, ssb_fixup_pcibridge);
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+	return ssb_mips_irq(extpci_core->dev) + 2;
+}
+
+static u32 get_cfgspace_addr(struct ssb_pcicore *pc,
+			     unsigned int bus, unsigned int dev,
+			     unsigned int func, unsigned int off)
+{
+	u32 addr = 0;
+	u32 tmp;
+
+	if (unlikely(pc->cardbusmode && dev > 1))
+		goto out;
+	if (bus == 0) {
+		/* Type 0 transaction */
+		if (unlikely(dev >= SSB_PCI_SLOT_MAX))
+			goto out;
+		/* Slide the window */
+		tmp = SSB_PCICORE_SBTOPCI_CFG0;
+		tmp |= ((1 << (dev + 16)) & SSB_PCICORE_SBTOPCI1_MASK);
+		pcicore_write32(pc, SSB_PCICORE_SBTOPCI1, tmp);
+		/* Calculate the address */
+		addr = SSB_PCI_CFG;
+		addr |= ((1 << (dev + 16)) & ~SSB_PCICORE_SBTOPCI1_MASK);
+		addr |= (func << 8);
+		addr |= (off & ~3);
+	} else {
+		/* Type 1 transaction */
+		pcicore_write32(pc, SSB_PCICORE_SBTOPCI1,
+				SSB_PCICORE_SBTOPCI_CFG1);
+		/* Calculate the address */
+		addr = SSB_PCI_CFG;
+		addr |= (bus << 16);
+		addr |= (dev << 11);
+		addr |= (func << 8);
+		addr |= (off & ~3);
+	}
+out:
+	return addr;
+}
+
+static int ssb_extpci_read_config(struct ssb_pcicore *pc,
+				  unsigned int bus, unsigned int dev,
+				  unsigned int func, unsigned int off,
+				  void *buf, int len)
+{
+	int err = -EINVAL;
+	u32 addr, val;
+	void __iomem *mmio;
+
+	SSB_WARN_ON(!pc->hostmode);
+	if (unlikely(len != 1 && len != 2 && len != 4))
+		goto out;
+	addr = get_cfgspace_addr(pc, bus, dev, func, off);
+	if (unlikely(!addr))
+		goto out;
+	err = -ENOMEM;
+	mmio = ioremap_nocache(addr, len);
+	if (!mmio)
+		goto out;
+
+	if (mips_busprobe32(val, mmio)) {
+		val = 0xffffffff;
+		goto unmap;
+	}
+
+	val = readl(mmio);
+	val >>= (8 * (off & 3));
+
+	switch (len) {
+	case 1:
+		*((u8 *)buf) = (u8)val;
+		break;
+	case 2:
+		*((u16 *)buf) = (u16)val;
+		break;
+	case 4:
+		*((u32 *)buf) = (u32)val;
+		break;
+	}
+	err = 0;
+unmap:
+	iounmap(mmio);
+out:
+	return err;
+}
+
+static int ssb_extpci_write_config(struct ssb_pcicore *pc,
+				   unsigned int bus, unsigned int dev,
+				   unsigned int func, unsigned int off,
+				   const void *buf, int len)
+{
+	int err = -EINVAL;
+	u32 addr, val = 0;
+	void __iomem *mmio;
+
+	SSB_WARN_ON(!pc->hostmode);
+	if (unlikely(len != 1 && len != 2 && len != 4))
+		goto out;
+	addr = get_cfgspace_addr(pc, bus, dev, func, off);
+	if (unlikely(!addr))
+		goto out;
+	err = -ENOMEM;
+	mmio = ioremap_nocache(addr, len);
+	if (!mmio)
+		goto out;
+
+	if (mips_busprobe32(val, mmio)) {
+		val = 0xffffffff;
+		goto unmap;
+	}
+
+	switch (len) {
+	case 1:
+		val = readl(mmio);
+		val &= ~(0xFF << (8 * (off & 3)));
+		val |= *((const u8 *)buf) << (8 * (off & 3));
+		break;
+	case 2:
+		val = readl(mmio);
+		val &= ~(0xFFFF << (8 * (off & 3)));
+		val |= *((const u16 *)buf) << (8 * (off & 3));
+		break;
+	case 4:
+		val = *((const u32 *)buf);
+		break;
+	}
+	writel(val, mmio);
+
+	err = 0;
+unmap:
+	iounmap(mmio);
+out:
+	return err;
+}
+
+static int ssb_pcicore_read_config(struct pci_bus *bus, unsigned int devfn,
+				   int reg, int size, u32 *val)
+{
+	unsigned long flags;
+	int err;
+
+	spin_lock_irqsave(&cfgspace_lock, flags);
+	err = ssb_extpci_read_config(extpci_core, bus->number, PCI_SLOT(devfn),
+				     PCI_FUNC(devfn), reg, val, size);
+	spin_unlock_irqrestore(&cfgspace_lock, flags);
+
+	return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+static int ssb_pcicore_write_config(struct pci_bus *bus, unsigned int devfn,
+				    int reg, int size, u32 val)
+{
+	unsigned long flags;
+	int err;
+
+	spin_lock_irqsave(&cfgspace_lock, flags);
+	err = ssb_extpci_write_config(extpci_core, bus->number, PCI_SLOT(devfn),
+				      PCI_FUNC(devfn), reg, &val, size);
+	spin_unlock_irqrestore(&cfgspace_lock, flags);
+
+	return err ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops ssb_pcicore_pciops = {
+	.read	= ssb_pcicore_read_config,
+	.write	= ssb_pcicore_write_config,
+};
+
+static struct resource ssb_pcicore_mem_resource = {
+	.name	= "SSB PCIcore external memory",
+	.start	= SSB_PCI_DMA,
+	.end	= SSB_PCI_DMA + SSB_PCI_DMA_SZ - 1,
+	.flags	= IORESOURCE_MEM,
+};
+
+static struct resource ssb_pcicore_io_resource = {
+	.name	= "SSB PCIcore external I/O",
+	.start	= 0x100,
+	.end	= 0x7FF,
+	.flags	= IORESOURCE_IO,
+};
+
+static struct pci_controller ssb_pcicore_controller = {
+	.pci_ops	= &ssb_pcicore_pciops,
+	.io_resource	= &ssb_pcicore_io_resource,
+	.mem_resource	= &ssb_pcicore_mem_resource,
+	.mem_offset	= 0x24000000,
+};
+
+static void ssb_pcicore_init_hostmode(struct ssb_pcicore *pc)
+{
+	u32 val;
+
+	if (WARN_ON(extpci_core))
+		return;
+	extpci_core = pc;
+
+	ssb_dprintk(KERN_INFO PFX "PCIcore in host mode found\n");
+	/* Reset devices on the external PCI bus */
+	val = SSB_PCICORE_CTL_RST_OE;
+	val |= SSB_PCICORE_CTL_CLK_OE;
+	pcicore_write32(pc, SSB_PCICORE_CTL, val);
+	val |= SSB_PCICORE_CTL_CLK; /* Clock on */
+	pcicore_write32(pc, SSB_PCICORE_CTL, val);
+	udelay(150); /* Assertion time demanded by the PCI standard */
+	val |= SSB_PCICORE_CTL_RST; /* Deassert RST# */
+	pcicore_write32(pc, SSB_PCICORE_CTL, val);
+	val = SSB_PCICORE_ARBCTL_INTERN;
+	pcicore_write32(pc, SSB_PCICORE_ARBCTL, val);
+	udelay(1); /* Assertion time demanded by the PCI standard */
+
+	/*TODO cardbus mode */
+
+	/* 64MB I/O window */
+	pcicore_write32(pc, SSB_PCICORE_SBTOPCI0,
+			SSB_PCICORE_SBTOPCI_IO);
+	/* 64MB config space */
+	pcicore_write32(pc, SSB_PCICORE_SBTOPCI1,
+			SSB_PCICORE_SBTOPCI_CFG0);
+	/* 1GB memory window */
+	pcicore_write32(pc, SSB_PCICORE_SBTOPCI2,
+			SSB_PCICORE_SBTOPCI_MEM | SSB_PCI_DMA);
+
+	/* Enable PCI bridge BAR0 prefetch and burst */
+	val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
+	ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2);
+	/* Clear error conditions */
+	val = 0;
+	ssb_extpci_write_config(pc, 0, 0, 0, PCI_STATUS, &val, 2);
+
+	/* Enable PCI interrupts */
+	pcicore_write32(pc, SSB_PCICORE_IMASK,
+			SSB_PCICORE_IMASK_INTA);
+
+	/* Ok, ready to run, register it to the system.
+	 * The following needs change, if we want to port hostmode
+	 * to non-MIPS platform. */
+	set_io_port_base((unsigned long)ioremap_nocache(SSB_PCI_MEM, 0x04000000));
+	/* Give some time to the PCI controller to configure itself with the new
+	 * values. Not waiting at this point causes crashes of the machine. */
+	mdelay(10);
+	register_pci_controller(&ssb_pcicore_controller);
+}
+
+static int pcicore_is_in_hostmode(struct ssb_pcicore *pc)
+{
+	struct ssb_bus *bus = pc->dev->bus;
+	u16 chipid_top;
+	u32 tmp;
+
+	chipid_top = (bus->chip_id & 0xFF00);
+	if (chipid_top != 0x4700 &&
+	    chipid_top != 0x5300)
+		return 0;
+
+	if (bus->sprom.r1.boardflags_lo & SSB_PCICORE_BFL_NOPCI)
+		return 0;
+
+	/* The 200-pin BCM4712 package does not bond out PCI. Even when
+	 * PCI is bonded out, some boards may leave the pins floating. */
+	if (bus->chip_id == 0x4712) {
+		if (bus->chip_package == SSB_CHIPPACK_BCM4712S)
+			return 0;
+		if (bus->chip_package == SSB_CHIPPACK_BCM4712M)
+			return 0;
+	}
+	if (bus->chip_id == 0x5350)
+		return 0;
+
+	return !mips_busprobe32(tmp, (bus->mmio + (pc->dev->core_index * SSB_CORE_SIZE)));
+}
+#endif /* CONFIG_SSB_PCICORE_HOSTMODE */
+
+
+/**************************************************
+ * Generic and Clientmode operation code.
+ **************************************************/
+
+static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc)
+{
+	/* Disable PCI interrupts. */
+	ssb_write32(pc->dev, SSB_INTVEC, 0);
+}
+
+void ssb_pcicore_init(struct ssb_pcicore *pc)
+{
+	struct ssb_device *dev = pc->dev;
+	struct ssb_bus *bus;
+
+	if (!dev)
+		return;
+	bus = dev->bus;
+	if (!ssb_device_is_enabled(dev))
+		ssb_device_enable(dev, 0);
+
+#ifdef CONFIG_SSB_PCICORE_HOSTMODE
+	pc->hostmode = pcicore_is_in_hostmode(pc);
+	if (pc->hostmode)
+		ssb_pcicore_init_hostmode(pc);
+#endif /* CONFIG_SSB_PCICORE_HOSTMODE */
+	if (!pc->hostmode)
+		ssb_pcicore_init_clientmode(pc);
+}
+
+static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address)
+{
+	pcicore_write32(pc, 0x130, address);
+	return pcicore_read32(pc, 0x134);
+}
+
+static void ssb_pcie_write(struct ssb_pcicore *pc, u32 address, u32 data)
+{
+	pcicore_write32(pc, 0x130, address);
+	pcicore_write32(pc, 0x134, data);
+}
+
+static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
+				u8 address, u16 data)
+{
+	const u16 mdio_control = 0x128;
+	const u16 mdio_data = 0x12C;
+	u32 v;
+	int i;
+
+	v = 0x80; /* Enable Preamble Sequence */
+	v |= 0x2; /* MDIO Clock Divisor */
+	pcicore_write32(pc, mdio_control, v);
+
+	v = (1 << 30); /* Start of Transaction */
+	v |= (1 << 28); /* Write Transaction */
+	v |= (1 << 17); /* Turnaround */
+	v |= (u32)device << 22;
+	v |= (u32)address << 18;
+	v |= data;
+	pcicore_write32(pc, mdio_data, v);
+	/* Wait for the device to complete the transaction */
+	udelay(10);
+	for (i = 0; i < 10; i++) {
+		v = pcicore_read32(pc, mdio_control);
+		if (v & 0x100 /* Trans complete */)
+			break;
+		msleep(1);
+	}
+	pcicore_write32(pc, mdio_control, 0);
+}
+
+static void ssb_broadcast_value(struct ssb_device *dev,
+				u32 address, u32 data)
+{
+	/* This is used for both, PCI and ChipCommon core, so be careful. */
+	BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR);
+	BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA);
+
+	ssb_write32(dev, SSB_PCICORE_BCAST_ADDR, address);
+	ssb_read32(dev, SSB_PCICORE_BCAST_ADDR); /* flush */
+	ssb_write32(dev, SSB_PCICORE_BCAST_DATA, data);
+	ssb_read32(dev, SSB_PCICORE_BCAST_DATA); /* flush */
+}
+
+static void ssb_commit_settings(struct ssb_bus *bus)
+{
+	struct ssb_device *dev;
+
+	dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev;
+	if (WARN_ON(!dev))
+		return;
+	/* This forces an update of the cached registers. */
+	ssb_broadcast_value(dev, 0xFD8, 0);
+}
+
+int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
+				   struct ssb_device *dev)
+{
+	struct ssb_device *pdev = pc->dev;
+	struct ssb_bus *bus;
+	int err = 0;
+	u32 tmp;
+
+	might_sleep();
+
+	if (!pdev)
+		goto out;
+	bus = pdev->bus;
+
+	/* Enable interrupts for this device. */
+	if (bus->host_pci &&
+	    ((pdev->id.revision >= 6) || (pdev->id.coreid == SSB_DEV_PCIE))) {
+		u32 coremask;
+
+		/* Calculate the "coremask" for the device. */
+		coremask = (1 << dev->core_index);
+
+		err = pci_read_config_dword(bus->host_pci, SSB_PCI_IRQMASK, &tmp);
+		if (err)
+			goto out;
+		tmp |= coremask << 8;
+		err = pci_write_config_dword(bus->host_pci, SSB_PCI_IRQMASK, tmp);
+		if (err)
+			goto out;
+	} else {
+		u32 intvec;
+
+		intvec = ssb_read32(pdev, SSB_INTVEC);
+		if ((bus->chip_id & 0xFF00) == 0x4400) {
+			/* Workaround: On the BCM44XX the BPFLAG routing
+			 * bit is wrong. Use a hardcoded constant. */
+			intvec |= 0x00000002;
+		} else {
+			tmp = ssb_read32(dev, SSB_TPSFLAG);
+			tmp &= SSB_TPSFLAG_BPFLAG;
+			intvec |= tmp;
+		}
+		ssb_write32(pdev, SSB_INTVEC, intvec);
+	}
+
+	/* Setup PCIcore operation. */
+	if (pc->setup_done)
+		goto out;
+	if (pdev->id.coreid == SSB_DEV_PCI) {
+		tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
+		tmp |= SSB_PCICORE_SBTOPCI_PREF;
+		tmp |= SSB_PCICORE_SBTOPCI_BURST;
+		pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
+
+		if (pdev->id.revision < 5) {
+			tmp = ssb_read32(pdev, SSB_IMCFGLO);
+			tmp &= ~SSB_IMCFGLO_SERTO;
+			tmp |= 2;
+			tmp &= ~SSB_IMCFGLO_REQTO;
+			tmp |= 3 << SSB_IMCFGLO_REQTO_SHIFT;
+			ssb_write32(pdev, SSB_IMCFGLO, tmp);
+			ssb_commit_settings(bus);
+		} else if (pdev->id.revision >= 11) {
+			tmp = pcicore_read32(pc, SSB_PCICORE_SBTOPCI2);
+			tmp |= SSB_PCICORE_SBTOPCI_MRM;
+			pcicore_write32(pc, SSB_PCICORE_SBTOPCI2, tmp);
+		}
+	} else {
+		WARN_ON(pdev->id.coreid != SSB_DEV_PCIE);
+		//TODO: Better make defines for all these magic PCIE values.
+		if ((pdev->id.revision == 0) || (pdev->id.revision == 1)) {
+			/* TLP Workaround register. */
+			tmp = ssb_pcie_read(pc, 0x4);
+			tmp |= 0x8;
+			ssb_pcie_write(pc, 0x4, tmp);
+		}
+		if (pdev->id.revision == 0) {
+			const u8 serdes_rx_device = 0x1F;
+
+			ssb_pcie_mdio_write(pc, serdes_rx_device,
+					    2 /* Timer */, 0x8128);
+			ssb_pcie_mdio_write(pc, serdes_rx_device,
+					    6 /* CDR */, 0x0100);
+			ssb_pcie_mdio_write(pc, serdes_rx_device,
+					    7 /* CDR BW */, 0x1466);
+		} else if (pdev->id.revision == 1) {
+			/* DLLP Link Control register. */
+			tmp = ssb_pcie_read(pc, 0x100);
+			tmp |= 0x40;
+			ssb_pcie_write(pc, 0x100, tmp);
+		}
+	}
+	pc->setup_done = 1;
+out:
+	return err;
+}
+EXPORT_SYMBOL(ssb_pcicore_dev_irqvecs_enable);
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
new file mode 100644
index 0000000..74d5182db
--- /dev/null
+++ b/drivers/ssb/main.c
@@ -0,0 +1,1162 @@
+/*
+ * Sonics Silicon Backplane
+ * Subsystem core
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "ssb_private.h"
+
+#include <linux/delay.h>
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_regs.h>
+#include <linux/dma-mapping.h>
+#include <linux/pci.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+
+MODULE_DESCRIPTION("Sonics Silicon Backplane driver");
+MODULE_LICENSE("GPL");
+
+
+/* Temporary list of yet-to-be-attached buses */
+static LIST_HEAD(attach_queue);
+/* List if running buses */
+static LIST_HEAD(buses);
+/* Software ID counter */
+static unsigned int next_busnumber;
+/* buses_mutes locks the two buslists and the next_busnumber.
+ * Don't lock this directly, but use ssb_buses_[un]lock() below. */
+static DEFINE_MUTEX(buses_mutex);
+
+/* There are differences in the codeflow, if the bus is
+ * initialized from early boot, as various needed services
+ * are not available early. This is a mechanism to delay
+ * these initializations to after early boot has finished.
+ * It's also used to avoid mutex locking, as that's not
+ * available and needed early. */
+static bool ssb_is_early_boot = 1;
+
+static void ssb_buses_lock(void);
+static void ssb_buses_unlock(void);
+
+
+#ifdef CONFIG_SSB_PCIHOST
+struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev)
+{
+	struct ssb_bus *bus;
+
+	ssb_buses_lock();
+	list_for_each_entry(bus, &buses, list) {
+		if (bus->bustype == SSB_BUSTYPE_PCI &&
+		    bus->host_pci == pdev)
+			goto found;
+	}
+	bus = NULL;
+found:
+	ssb_buses_unlock();
+
+	return bus;
+}
+#endif /* CONFIG_SSB_PCIHOST */
+
+static struct ssb_device *ssb_device_get(struct ssb_device *dev)
+{
+	if (dev)
+		get_device(dev->dev);
+	return dev;
+}
+
+static void ssb_device_put(struct ssb_device *dev)
+{
+	if (dev)
+		put_device(dev->dev);
+}
+
+static int ssb_bus_resume(struct ssb_bus *bus)
+{
+	int err;
+
+	ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
+	err = ssb_pcmcia_init(bus);
+	if (err) {
+		/* No need to disable XTAL, as we don't have one on PCMCIA. */
+		return err;
+	}
+	ssb_chipco_resume(&bus->chipco);
+
+	return 0;
+}
+
+static int ssb_device_resume(struct device *dev)
+{
+	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+	struct ssb_driver *ssb_drv;
+	struct ssb_bus *bus;
+	int err = 0;
+
+	bus = ssb_dev->bus;
+	if (bus->suspend_cnt == bus->nr_devices) {
+		err = ssb_bus_resume(bus);
+		if (err)
+			return err;
+	}
+	bus->suspend_cnt--;
+	if (dev->driver) {
+		ssb_drv = drv_to_ssb_drv(dev->driver);
+		if (ssb_drv && ssb_drv->resume)
+			err = ssb_drv->resume(ssb_dev);
+		if (err)
+			goto out;
+	}
+out:
+	return err;
+}
+
+static void ssb_bus_suspend(struct ssb_bus *bus, pm_message_t state)
+{
+	ssb_chipco_suspend(&bus->chipco, state);
+	ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0);
+
+	/* Reset HW state information in memory, so that HW is
+	 * completely reinitialized on resume. */
+	bus->mapped_device = NULL;
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+	bus->pcicore.setup_done = 0;
+#endif
+#ifdef CONFIG_SSB_DEBUG
+	bus->powered_up = 0;
+#endif
+}
+
+static int ssb_device_suspend(struct device *dev, pm_message_t state)
+{
+	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+	struct ssb_driver *ssb_drv;
+	struct ssb_bus *bus;
+	int err = 0;
+
+	if (dev->driver) {
+		ssb_drv = drv_to_ssb_drv(dev->driver);
+		if (ssb_drv && ssb_drv->suspend)
+			err = ssb_drv->suspend(ssb_dev, state);
+		if (err)
+			goto out;
+	}
+
+	bus = ssb_dev->bus;
+	bus->suspend_cnt++;
+	if (bus->suspend_cnt == bus->nr_devices) {
+		/* All devices suspended. Shutdown the bus. */
+		ssb_bus_suspend(bus, state);
+	}
+
+out:
+	return err;
+}
+
+#ifdef CONFIG_SSB_PCIHOST
+int ssb_devices_freeze(struct ssb_bus *bus)
+{
+	struct ssb_device *dev;
+	struct ssb_driver *drv;
+	int err = 0;
+	int i;
+	pm_message_t state = PMSG_FREEZE;
+
+	/* First check that we are capable to freeze all devices. */
+	for (i = 0; i < bus->nr_devices; i++) {
+		dev = &(bus->devices[i]);
+		if (!dev->dev ||
+		    !dev->dev->driver ||
+		    !device_is_registered(dev->dev))
+			continue;
+		drv = drv_to_ssb_drv(dev->dev->driver);
+		if (!drv)
+			continue;
+		if (!drv->suspend) {
+			/* Nope, can't suspend this one. */
+			return -EOPNOTSUPP;
+		}
+	}
+	/* Now suspend all devices */
+	for (i = 0; i < bus->nr_devices; i++) {
+		dev = &(bus->devices[i]);
+		if (!dev->dev ||
+		    !dev->dev->driver ||
+		    !device_is_registered(dev->dev))
+			continue;
+		drv = drv_to_ssb_drv(dev->dev->driver);
+		if (!drv)
+			continue;
+		err = drv->suspend(dev, state);
+		if (err) {
+			ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n",
+				   dev->dev->bus_id);
+			goto err_unwind;
+		}
+	}
+
+	return 0;
+err_unwind:
+	for (i--; i >= 0; i--) {
+		dev = &(bus->devices[i]);
+		if (!dev->dev ||
+		    !dev->dev->driver ||
+		    !device_is_registered(dev->dev))
+			continue;
+		drv = drv_to_ssb_drv(dev->dev->driver);
+		if (!drv)
+			continue;
+		if (drv->resume)
+			drv->resume(dev);
+	}
+	return err;
+}
+
+int ssb_devices_thaw(struct ssb_bus *bus)
+{
+	struct ssb_device *dev;
+	struct ssb_driver *drv;
+	int err;
+	int i;
+
+	for (i = 0; i < bus->nr_devices; i++) {
+		dev = &(bus->devices[i]);
+		if (!dev->dev ||
+		    !dev->dev->driver ||
+		    !device_is_registered(dev->dev))
+			continue;
+		drv = drv_to_ssb_drv(dev->dev->driver);
+		if (!drv)
+			continue;
+		if (SSB_WARN_ON(!drv->resume))
+			continue;
+		err = drv->resume(dev);
+		if (err) {
+			ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n",
+				   dev->dev->bus_id);
+		}
+	}
+
+	return 0;
+}
+#endif /* CONFIG_SSB_PCIHOST */
+
+static void ssb_device_shutdown(struct device *dev)
+{
+	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+	struct ssb_driver *ssb_drv;
+
+	if (!dev->driver)
+		return;
+	ssb_drv = drv_to_ssb_drv(dev->driver);
+	if (ssb_drv && ssb_drv->shutdown)
+		ssb_drv->shutdown(ssb_dev);
+}
+
+static int ssb_device_remove(struct device *dev)
+{
+	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+	struct ssb_driver *ssb_drv = drv_to_ssb_drv(dev->driver);
+
+	if (ssb_drv && ssb_drv->remove)
+		ssb_drv->remove(ssb_dev);
+	ssb_device_put(ssb_dev);
+
+	return 0;
+}
+
+static int ssb_device_probe(struct device *dev)
+{
+	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+	struct ssb_driver *ssb_drv = drv_to_ssb_drv(dev->driver);
+	int err = 0;
+
+	ssb_device_get(ssb_dev);
+	if (ssb_drv && ssb_drv->probe)
+		err = ssb_drv->probe(ssb_dev, &ssb_dev->id);
+	if (err)
+		ssb_device_put(ssb_dev);
+
+	return err;
+}
+
+static int ssb_match_devid(const struct ssb_device_id *tabid,
+			   const struct ssb_device_id *devid)
+{
+	if ((tabid->vendor != devid->vendor) &&
+	    tabid->vendor != SSB_ANY_VENDOR)
+		return 0;
+	if ((tabid->coreid != devid->coreid) &&
+	    tabid->coreid != SSB_ANY_ID)
+		return 0;
+	if ((tabid->revision != devid->revision) &&
+	    tabid->revision != SSB_ANY_REV)
+		return 0;
+	return 1;
+}
+
+static int ssb_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+	struct ssb_driver *ssb_drv = drv_to_ssb_drv(drv);
+	const struct ssb_device_id *id;
+
+	for (id = ssb_drv->id_table;
+	     id->vendor || id->coreid || id->revision;
+	     id++) {
+		if (ssb_match_devid(id, &ssb_dev->id))
+			return 1; /* found */
+	}
+
+	return 0;
+}
+
+static int ssb_device_uevent(struct device *dev, char **envp, int num_envp,
+			     char *buffer, int buffer_size)
+{
+	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev);
+	int ret, i = 0, length = 0;
+
+	if (!dev)
+		return -ENODEV;
+
+	ret = add_uevent_var(envp, num_envp, &i,
+			     buffer, buffer_size, &length,
+			     "MODALIAS=ssb:v%04Xid%04Xrev%02X",
+			     ssb_dev->id.vendor, ssb_dev->id.coreid,
+			     ssb_dev->id.revision);
+	envp[i] = NULL;
+
+	return ret;
+}
+
+static struct bus_type ssb_bustype = {
+	.name		= "ssb",
+	.match		= ssb_bus_match,
+	.probe		= ssb_device_probe,
+	.remove		= ssb_device_remove,
+	.shutdown	= ssb_device_shutdown,
+	.suspend	= ssb_device_suspend,
+	.resume		= ssb_device_resume,
+	.uevent		= ssb_device_uevent,
+};
+
+static void ssb_buses_lock(void)
+{
+	/* See the comment at the ssb_is_early_boot definition */
+	if (!ssb_is_early_boot)
+		mutex_lock(&buses_mutex);
+}
+
+static void ssb_buses_unlock(void)
+{
+	/* See the comment at the ssb_is_early_boot definition */
+	if (!ssb_is_early_boot)
+		mutex_unlock(&buses_mutex);
+}
+
+static void ssb_devices_unregister(struct ssb_bus *bus)
+{
+	struct ssb_device *sdev;
+	int i;
+
+	for (i = bus->nr_devices - 1; i >= 0; i--) {
+		sdev = &(bus->devices[i]);
+		if (sdev->dev)
+			device_unregister(sdev->dev);
+	}
+}
+
+void ssb_bus_unregister(struct ssb_bus *bus)
+{
+	ssb_buses_lock();
+	ssb_devices_unregister(bus);
+	list_del(&bus->list);
+	ssb_buses_unlock();
+
+	/* ssb_pcmcia_exit(bus); */
+	ssb_pci_exit(bus);
+	ssb_iounmap(bus);
+}
+EXPORT_SYMBOL(ssb_bus_unregister);
+
+static void ssb_release_dev(struct device *dev)
+{
+	struct __ssb_dev_wrapper *devwrap;
+
+	devwrap = container_of(dev, struct __ssb_dev_wrapper, dev);
+	kfree(devwrap);
+}
+
+static int ssb_devices_register(struct ssb_bus *bus)
+{
+	struct ssb_device *sdev;
+	struct device *dev;
+	struct __ssb_dev_wrapper *devwrap;
+	int i, err = 0;
+	int dev_idx = 0;
+
+	for (i = 0; i < bus->nr_devices; i++) {
+		sdev = &(bus->devices[i]);
+
+		/* We don't register SSB-system devices to the kernel,
+		 * as the drivers for them are built into SSB. */
+		switch (sdev->id.coreid) {
+		case SSB_DEV_CHIPCOMMON:
+		case SSB_DEV_PCI:
+		case SSB_DEV_PCIE:
+		case SSB_DEV_PCMCIA:
+		case SSB_DEV_MIPS:
+		case SSB_DEV_MIPS_3302:
+		case SSB_DEV_EXTIF:
+			continue;
+		}
+
+		devwrap = kzalloc(sizeof(*devwrap), GFP_KERNEL);
+		if (!devwrap) {
+			ssb_printk(KERN_ERR PFX
+				   "Could not allocate device\n");
+			err = -ENOMEM;
+			goto error;
+		}
+		dev = &devwrap->dev;
+		devwrap->sdev = sdev;
+
+		dev->release = ssb_release_dev;
+		dev->bus = &ssb_bustype;
+		snprintf(dev->bus_id, sizeof(dev->bus_id),
+			 "ssb%u:%d", bus->busnumber, dev_idx);
+
+		switch (bus->bustype) {
+		case SSB_BUSTYPE_PCI:
+#ifdef CONFIG_SSB_PCIHOST
+			sdev->irq = bus->host_pci->irq;
+			dev->parent = &bus->host_pci->dev;
+#endif
+			break;
+		case SSB_BUSTYPE_PCMCIA:
+#ifdef CONFIG_SSB_PCMCIAHOST
+			dev->parent = &bus->host_pcmcia->dev;
+#endif
+			break;
+		case SSB_BUSTYPE_SSB:
+			break;
+		}
+
+		sdev->dev = dev;
+		err = device_register(dev);
+		if (err) {
+			ssb_printk(KERN_ERR PFX
+				   "Could not register %s\n",
+				   dev->bus_id);
+			/* Set dev to NULL to not unregister
+			 * dev on error unwinding. */
+			sdev->dev = NULL;
+			kfree(devwrap);
+			goto error;
+		}
+		dev_idx++;
+	}
+
+	return 0;
+error:
+	/* Unwind the already registered devices. */
+	ssb_devices_unregister(bus);
+	return err;
+}
+
+/* Needs ssb_buses_lock() */
+static int ssb_attach_queued_buses(void)
+{
+	struct ssb_bus *bus, *n;
+	int err = 0;
+	int drop_them_all = 0;
+
+	list_for_each_entry_safe(bus, n, &attach_queue, list) {
+		if (drop_them_all) {
+			list_del(&bus->list);
+			continue;
+		}
+		/* Can't init the PCIcore in ssb_bus_register(), as that
+		 * is too early in boot for embedded systems
+		 * (no udelay() available). So do it here in attach stage.
+		 */
+		err = ssb_bus_powerup(bus, 0);
+		if (err)
+			goto error;
+		ssb_pcicore_init(&bus->pcicore);
+		ssb_bus_may_powerdown(bus);
+
+		err = ssb_devices_register(bus);
+error:
+		if (err) {
+			drop_them_all = 1;
+			list_del(&bus->list);
+			continue;
+		}
+		list_move_tail(&bus->list, &buses);
+	}
+
+	return err;
+}
+
+static u16 ssb_ssb_read16(struct ssb_device *dev, u16 offset)
+{
+	struct ssb_bus *bus = dev->bus;
+
+	offset += dev->core_index * SSB_CORE_SIZE;
+	return readw(bus->mmio + offset);
+}
+
+static u32 ssb_ssb_read32(struct ssb_device *dev, u16 offset)
+{
+	struct ssb_bus *bus = dev->bus;
+
+	offset += dev->core_index * SSB_CORE_SIZE;
+	return readl(bus->mmio + offset);
+}
+
+static void ssb_ssb_write16(struct ssb_device *dev, u16 offset, u16 value)
+{
+	struct ssb_bus *bus = dev->bus;
+
+	offset += dev->core_index * SSB_CORE_SIZE;
+	writew(value, bus->mmio + offset);
+}
+
+static void ssb_ssb_write32(struct ssb_device *dev, u16 offset, u32 value)
+{
+	struct ssb_bus *bus = dev->bus;
+
+	offset += dev->core_index * SSB_CORE_SIZE;
+	writel(value, bus->mmio + offset);
+}
+
+/* Ops for the plain SSB bus without a host-device (no PCI or PCMCIA). */
+static const struct ssb_bus_ops ssb_ssb_ops = {
+	.read16		= ssb_ssb_read16,
+	.read32		= ssb_ssb_read32,
+	.write16	= ssb_ssb_write16,
+	.write32	= ssb_ssb_write32,
+};
+
+static int ssb_fetch_invariants(struct ssb_bus *bus,
+				ssb_invariants_func_t get_invariants)
+{
+	struct ssb_init_invariants iv;
+	int err;
+
+	memset(&iv, 0, sizeof(iv));
+	err = get_invariants(bus, &iv);
+	if (err)
+		goto out;
+	memcpy(&bus->boardinfo, &iv.boardinfo, sizeof(iv.boardinfo));
+	memcpy(&bus->sprom, &iv.sprom, sizeof(iv.sprom));
+out:
+	return err;
+}
+
+static int ssb_bus_register(struct ssb_bus *bus,
+			    ssb_invariants_func_t get_invariants,
+			    unsigned long baseaddr)
+{
+	int err;
+
+	spin_lock_init(&bus->bar_lock);
+	INIT_LIST_HEAD(&bus->list);
+
+	/* Powerup the bus */
+	err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
+	if (err)
+		goto out;
+	ssb_buses_lock();
+	bus->busnumber = next_busnumber;
+	/* Scan for devices (cores) */
+	err = ssb_bus_scan(bus, baseaddr);
+	if (err)
+		goto err_disable_xtal;
+
+	/* Init PCI-host device (if any) */
+	err = ssb_pci_init(bus);
+	if (err)
+		goto err_unmap;
+	/* Init PCMCIA-host device (if any) */
+	err = ssb_pcmcia_init(bus);
+	if (err)
+		goto err_pci_exit;
+
+	/* Initialize basic system devices (if available) */
+	err = ssb_bus_powerup(bus, 0);
+	if (err)
+		goto err_pcmcia_exit;
+	ssb_chipcommon_init(&bus->chipco);
+	ssb_mipscore_init(&bus->mipscore);
+	err = ssb_fetch_invariants(bus, get_invariants);
+	if (err) {
+		ssb_bus_may_powerdown(bus);
+		goto err_pcmcia_exit;
+	}
+	ssb_bus_may_powerdown(bus);
+
+	/* Queue it for attach.
+	 * See the comment at the ssb_is_early_boot definition. */
+	list_add_tail(&bus->list, &attach_queue);
+	if (!ssb_is_early_boot) {
+		/* This is not early boot, so we must attach the bus now */
+		err = ssb_attach_queued_buses();
+		if (err)
+			goto err_dequeue;
+	}
+	next_busnumber++;
+	ssb_buses_unlock();
+
+out:
+	return err;
+
+err_dequeue:
+	list_del(&bus->list);
+err_pcmcia_exit:
+/*	ssb_pcmcia_exit(bus); */
+err_pci_exit:
+	ssb_pci_exit(bus);
+err_unmap:
+	ssb_iounmap(bus);
+err_disable_xtal:
+	ssb_buses_unlock();
+	ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0);
+	return err;
+}
+
+#ifdef CONFIG_SSB_PCIHOST
+int ssb_bus_pcibus_register(struct ssb_bus *bus,
+			    struct pci_dev *host_pci)
+{
+	int err;
+
+	bus->bustype = SSB_BUSTYPE_PCI;
+	bus->host_pci = host_pci;
+	bus->ops = &ssb_pci_ops;
+
+	err = ssb_bus_register(bus, ssb_pci_get_invariants, 0);
+	if (!err) {
+		ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
+			   "PCI device %s\n", host_pci->dev.bus_id);
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(ssb_bus_pcibus_register);
+#endif /* CONFIG_SSB_PCIHOST */
+
+#ifdef CONFIG_SSB_PCMCIAHOST
+int ssb_bus_pcmciabus_register(struct ssb_bus *bus,
+			       struct pcmcia_device *pcmcia_dev,
+			       unsigned long baseaddr)
+{
+	int err;
+
+	bus->bustype = SSB_BUSTYPE_PCMCIA;
+	bus->host_pcmcia = pcmcia_dev;
+	bus->ops = &ssb_pcmcia_ops;
+
+	err = ssb_bus_register(bus, ssb_pcmcia_get_invariants, baseaddr);
+	if (!err) {
+		ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on "
+			   "PCMCIA device %s\n", pcmcia_dev->devname);
+	}
+
+	return err;
+}
+EXPORT_SYMBOL(ssb_bus_pcmciabus_register);
+#endif /* CONFIG_SSB_PCMCIAHOST */
+
+int ssb_bus_ssbbus_register(struct ssb_bus *bus,
+			    unsigned long baseaddr,
+			    ssb_invariants_func_t get_invariants)
+{
+	int err;
+
+	bus->bustype = SSB_BUSTYPE_SSB;
+	bus->ops = &ssb_ssb_ops;
+
+	err = ssb_bus_register(bus, get_invariants, baseaddr);
+	if (!err) {
+		ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found at "
+			   "address 0x%08lX\n", baseaddr);
+	}
+
+	return err;
+}
+
+int __ssb_driver_register(struct ssb_driver *drv, struct module *owner)
+{
+	drv->drv.name = drv->name;
+	drv->drv.bus = &ssb_bustype;
+	drv->drv.owner = owner;
+
+	return driver_register(&drv->drv);
+}
+EXPORT_SYMBOL(__ssb_driver_register);
+
+void ssb_driver_unregister(struct ssb_driver *drv)
+{
+	driver_unregister(&drv->drv);
+}
+EXPORT_SYMBOL(ssb_driver_unregister);
+
+void ssb_set_devtypedata(struct ssb_device *dev, void *data)
+{
+	struct ssb_bus *bus = dev->bus;
+	struct ssb_device *ent;
+	int i;
+
+	for (i = 0; i < bus->nr_devices; i++) {
+		ent = &(bus->devices[i]);
+		if (ent->id.vendor != dev->id.vendor)
+			continue;
+		if (ent->id.coreid != dev->id.coreid)
+			continue;
+
+		ent->devtypedata = data;
+	}
+}
+EXPORT_SYMBOL(ssb_set_devtypedata);
+
+static u32 clkfactor_f6_resolve(u32 v)
+{
+	/* map the magic values */
+	switch (v) {
+	case SSB_CHIPCO_CLK_F6_2:
+		return 2;
+	case SSB_CHIPCO_CLK_F6_3:
+		return 3;
+	case SSB_CHIPCO_CLK_F6_4:
+		return 4;
+	case SSB_CHIPCO_CLK_F6_5:
+		return 5;
+	case SSB_CHIPCO_CLK_F6_6:
+		return 6;
+	case SSB_CHIPCO_CLK_F6_7:
+		return 7;
+	}
+	return 0;
+}
+
+/* Calculate the speed the backplane would run at a given set of clockcontrol values */
+u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m)
+{
+	u32 n1, n2, clock, m1, m2, m3, mc;
+
+	n1 = (n & SSB_CHIPCO_CLK_N1);
+	n2 = ((n & SSB_CHIPCO_CLK_N2) >> SSB_CHIPCO_CLK_N2_SHIFT);
+
+	switch (plltype) {
+	case SSB_PLLTYPE_6: /* 100/200 or 120/240 only */
+		if (m & SSB_CHIPCO_CLK_T6_MMASK)
+			return SSB_CHIPCO_CLK_T6_M0;
+		return SSB_CHIPCO_CLK_T6_M1;
+	case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
+	case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
+	case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
+	case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */
+		n1 = clkfactor_f6_resolve(n1);
+		n2 += SSB_CHIPCO_CLK_F5_BIAS;
+		break;
+	case SSB_PLLTYPE_2: /* 48Mhz, 4 dividers */
+		n1 += SSB_CHIPCO_CLK_T2_BIAS;
+		n2 += SSB_CHIPCO_CLK_T2_BIAS;
+		SSB_WARN_ON(!((n1 >= 2) && (n1 <= 7)));
+		SSB_WARN_ON(!((n2 >= 5) && (n2 <= 23)));
+		break;
+	case SSB_PLLTYPE_5: /* 25Mhz, 4 dividers */
+		return 100000000;
+	default:
+		SSB_WARN_ON(1);
+	}
+
+	switch (plltype) {
+	case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
+	case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */
+		clock = SSB_CHIPCO_CLK_BASE2 * n1 * n2;
+		break;
+	default:
+		clock = SSB_CHIPCO_CLK_BASE1 * n1 * n2;
+	}
+	if (!clock)
+		return 0;
+
+	m1 = (m & SSB_CHIPCO_CLK_M1);
+	m2 = ((m & SSB_CHIPCO_CLK_M2) >> SSB_CHIPCO_CLK_M2_SHIFT);
+	m3 = ((m & SSB_CHIPCO_CLK_M3) >> SSB_CHIPCO_CLK_M3_SHIFT);
+	mc = ((m & SSB_CHIPCO_CLK_MC) >> SSB_CHIPCO_CLK_MC_SHIFT);
+
+	switch (plltype) {
+	case SSB_PLLTYPE_1: /* 48Mhz base, 3 dividers */
+	case SSB_PLLTYPE_3: /* 25Mhz, 2 dividers */
+	case SSB_PLLTYPE_4: /* 48Mhz, 4 dividers */
+	case SSB_PLLTYPE_7: /* 25Mhz, 4 dividers */
+		m1 = clkfactor_f6_resolve(m1);
+		if ((plltype == SSB_PLLTYPE_1) ||
+		    (plltype == SSB_PLLTYPE_3))
+			m2 += SSB_CHIPCO_CLK_F5_BIAS;
+		else
+			m2 = clkfactor_f6_resolve(m2);
+		m3 = clkfactor_f6_resolve(m3);
+
+		switch (mc) {
+		case SSB_CHIPCO_CLK_MC_BYPASS:
+			return clock;
+		case SSB_CHIPCO_CLK_MC_M1:
+			return (clock / m1);
+		case SSB_CHIPCO_CLK_MC_M1M2:
+			return (clock / (m1 * m2));
+		case SSB_CHIPCO_CLK_MC_M1M2M3:
+			return (clock / (m1 * m2 * m3));
+		case SSB_CHIPCO_CLK_MC_M1M3:
+			return (clock / (m1 * m3));
+		}
+		return 0;
+	case SSB_PLLTYPE_2:
+		m1 += SSB_CHIPCO_CLK_T2_BIAS;
+		m2 += SSB_CHIPCO_CLK_T2M2_BIAS;
+		m3 += SSB_CHIPCO_CLK_T2_BIAS;
+		SSB_WARN_ON(!((m1 >= 2) && (m1 <= 7)));
+		SSB_WARN_ON(!((m2 >= 3) && (m2 <= 10)));
+		SSB_WARN_ON(!((m3 >= 2) && (m3 <= 7)));
+
+		if (!(mc & SSB_CHIPCO_CLK_T2MC_M1BYP))
+			clock /= m1;
+		if (!(mc & SSB_CHIPCO_CLK_T2MC_M2BYP))
+			clock /= m2;
+		if (!(mc & SSB_CHIPCO_CLK_T2MC_M3BYP))
+			clock /= m3;
+		return clock;
+	default:
+		SSB_WARN_ON(1);
+	}
+	return 0;
+}
+
+/* Get the current speed the backplane is running at */
+u32 ssb_clockspeed(struct ssb_bus *bus)
+{
+	u32 rate;
+	u32 plltype;
+	u32 clkctl_n, clkctl_m;
+
+	if (ssb_extif_available(&bus->extif))
+		ssb_extif_get_clockcontrol(&bus->extif, &plltype,
+					   &clkctl_n, &clkctl_m);
+	else if (bus->chipco.dev)
+		ssb_chipco_get_clockcontrol(&bus->chipco, &plltype,
+					    &clkctl_n, &clkctl_m);
+	else
+		return 0;
+
+	if (bus->chip_id == 0x5365) {
+		rate = 100000000;
+	} else {
+		rate = ssb_calc_clock_rate(plltype, clkctl_n, clkctl_m);
+		if (plltype == SSB_PLLTYPE_3) /* 25Mhz, 2 dividers */
+			rate /= 2;
+	}
+
+	return rate;
+}
+EXPORT_SYMBOL(ssb_clockspeed);
+
+static u32 ssb_tmslow_reject_bitmask(struct ssb_device *dev)
+{
+	/* The REJECT bit changed position in TMSLOW between
+	 * Backplane revisions. */
+	switch (ssb_read32(dev, SSB_IDLOW) & SSB_IDLOW_SSBREV) {
+	case SSB_IDLOW_SSBREV_22:
+		return SSB_TMSLOW_REJECT_22;
+	case SSB_IDLOW_SSBREV_23:
+		return SSB_TMSLOW_REJECT_23;
+	default:
+		WARN_ON(1);
+	}
+	return (SSB_TMSLOW_REJECT_22 | SSB_TMSLOW_REJECT_23);
+}
+
+int ssb_device_is_enabled(struct ssb_device *dev)
+{
+	u32 val;
+	u32 reject;
+
+	reject = ssb_tmslow_reject_bitmask(dev);
+	val = ssb_read32(dev, SSB_TMSLOW);
+	val &= SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET | reject;
+
+	return (val == SSB_TMSLOW_CLOCK);
+}
+EXPORT_SYMBOL(ssb_device_is_enabled);
+
+static void ssb_flush_tmslow(struct ssb_device *dev)
+{
+	/* Make _really_ sure the device has finished the TMSLOW
+	 * register write transaction, as we risk running into
+	 * a machine check exception otherwise.
+	 * Do this by reading the register back to commit the
+	 * PCI write and delay an additional usec for the device
+	 * to react to the change. */
+	ssb_read32(dev, SSB_TMSLOW);
+	udelay(1);
+}
+
+void ssb_device_enable(struct ssb_device *dev, u32 core_specific_flags)
+{
+	u32 val;
+
+	ssb_device_disable(dev, core_specific_flags);
+	ssb_write32(dev, SSB_TMSLOW,
+		    SSB_TMSLOW_RESET | SSB_TMSLOW_CLOCK |
+		    SSB_TMSLOW_FGC | core_specific_flags);
+	ssb_flush_tmslow(dev);
+
+	/* Clear SERR if set. This is a hw bug workaround. */
+	if (ssb_read32(dev, SSB_TMSHIGH) & SSB_TMSHIGH_SERR)
+		ssb_write32(dev, SSB_TMSHIGH, 0);
+
+	val = ssb_read32(dev, SSB_IMSTATE);
+	if (val & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) {
+		val &= ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO);
+		ssb_write32(dev, SSB_IMSTATE, val);
+	}
+
+	ssb_write32(dev, SSB_TMSLOW,
+		    SSB_TMSLOW_CLOCK | SSB_TMSLOW_FGC |
+		    core_specific_flags);
+	ssb_flush_tmslow(dev);
+
+	ssb_write32(dev, SSB_TMSLOW, SSB_TMSLOW_CLOCK |
+		    core_specific_flags);
+	ssb_flush_tmslow(dev);
+}
+EXPORT_SYMBOL(ssb_device_enable);
+
+/* Wait for a bit in a register to get set or unset.
+ * timeout is in units of ten-microseconds */
+static int ssb_wait_bit(struct ssb_device *dev, u16 reg, u32 bitmask,
+			int timeout, int set)
+{
+	int i;
+	u32 val;
+
+	for (i = 0; i < timeout; i++) {
+		val = ssb_read32(dev, reg);
+		if (set) {
+			if (val & bitmask)
+				return 0;
+		} else {
+			if (!(val & bitmask))
+				return 0;
+		}
+		udelay(10);
+	}
+	printk(KERN_ERR PFX "Timeout waiting for bitmask %08X on "
+			    "register %04X to %s.\n",
+	       bitmask, reg, (set ? "set" : "clear"));
+
+	return -ETIMEDOUT;
+}
+
+void ssb_device_disable(struct ssb_device *dev, u32 core_specific_flags)
+{
+	u32 reject;
+
+	if (ssb_read32(dev, SSB_TMSLOW) & SSB_TMSLOW_RESET)
+		return;
+
+	reject = ssb_tmslow_reject_bitmask(dev);
+	ssb_write32(dev, SSB_TMSLOW, reject | SSB_TMSLOW_CLOCK);
+	ssb_wait_bit(dev, SSB_TMSLOW, reject, 1000, 1);
+	ssb_wait_bit(dev, SSB_TMSHIGH, SSB_TMSHIGH_BUSY, 1000, 0);
+	ssb_write32(dev, SSB_TMSLOW,
+		    SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
+		    reject | SSB_TMSLOW_RESET |
+		    core_specific_flags);
+	ssb_flush_tmslow(dev);
+
+	ssb_write32(dev, SSB_TMSLOW,
+		    reject | SSB_TMSLOW_RESET |
+		    core_specific_flags);
+	ssb_flush_tmslow(dev);
+}
+EXPORT_SYMBOL(ssb_device_disable);
+
+u32 ssb_dma_translation(struct ssb_device *dev)
+{
+	switch (dev->bus->bustype) {
+	case SSB_BUSTYPE_SSB:
+		return 0;
+	case SSB_BUSTYPE_PCI:
+	case SSB_BUSTYPE_PCMCIA:
+		return SSB_PCI_DMA;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(ssb_dma_translation);
+
+int ssb_dma_set_mask(struct ssb_device *ssb_dev, u64 mask)
+{
+	struct device *dev = ssb_dev->dev;
+
+#ifdef CONFIG_SSB_PCIHOST
+	if (ssb_dev->bus->bustype == SSB_BUSTYPE_PCI &&
+	    !dma_supported(dev, mask))
+		return -EIO;
+#endif
+	dev->coherent_dma_mask = mask;
+	dev->dma_mask = &dev->coherent_dma_mask;
+
+	return 0;
+}
+EXPORT_SYMBOL(ssb_dma_set_mask);
+
+int ssb_bus_may_powerdown(struct ssb_bus *bus)
+{
+	struct ssb_chipcommon *cc;
+	int err = 0;
+
+	/* On buses where more than one core may be working
+	 * at a time, we must not powerdown stuff if there are
+	 * still cores that may want to run. */
+	if (bus->bustype == SSB_BUSTYPE_SSB)
+		goto out;
+
+	cc = &bus->chipco;
+	ssb_chipco_set_clockmode(cc, SSB_CLKMODE_SLOW);
+	err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0);
+	if (err)
+		goto error;
+out:
+#ifdef CONFIG_SSB_DEBUG
+	bus->powered_up = 0;
+#endif
+	return err;
+error:
+	ssb_printk(KERN_ERR PFX "Bus powerdown failed\n");
+	goto out;
+}
+EXPORT_SYMBOL(ssb_bus_may_powerdown);
+
+int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl)
+{
+	struct ssb_chipcommon *cc;
+	int err;
+	enum ssb_clkmode mode;
+
+	err = ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1);
+	if (err)
+		goto error;
+	cc = &bus->chipco;
+	mode = dynamic_pctl ? SSB_CLKMODE_DYNAMIC : SSB_CLKMODE_FAST;
+	ssb_chipco_set_clockmode(cc, mode);
+
+#ifdef CONFIG_SSB_DEBUG
+	bus->powered_up = 1;
+#endif
+	return 0;
+error:
+	ssb_printk(KERN_ERR PFX "Bus powerup failed\n");
+	return err;
+}
+EXPORT_SYMBOL(ssb_bus_powerup);
+
+u32 ssb_admatch_base(u32 adm)
+{
+	u32 base = 0;
+
+	switch (adm & SSB_ADM_TYPE) {
+	case SSB_ADM_TYPE0:
+		base = (adm & SSB_ADM_BASE0);
+		break;
+	case SSB_ADM_TYPE1:
+		SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */
+		base = (adm & SSB_ADM_BASE1);
+		break;
+	case SSB_ADM_TYPE2:
+		SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */
+		base = (adm & SSB_ADM_BASE2);
+		break;
+	default:
+		SSB_WARN_ON(1);
+	}
+
+	return base;
+}
+EXPORT_SYMBOL(ssb_admatch_base);
+
+u32 ssb_admatch_size(u32 adm)
+{
+	u32 size = 0;
+
+	switch (adm & SSB_ADM_TYPE) {
+	case SSB_ADM_TYPE0:
+		size = ((adm & SSB_ADM_SZ0) >> SSB_ADM_SZ0_SHIFT);
+		break;
+	case SSB_ADM_TYPE1:
+		SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */
+		size = ((adm & SSB_ADM_SZ1) >> SSB_ADM_SZ1_SHIFT);
+		break;
+	case SSB_ADM_TYPE2:
+		SSB_WARN_ON(adm & SSB_ADM_NEG); /* unsupported */
+		size = ((adm & SSB_ADM_SZ2) >> SSB_ADM_SZ2_SHIFT);
+		break;
+	default:
+		SSB_WARN_ON(1);
+	}
+	size = (1 << (size + 1));
+
+	return size;
+}
+EXPORT_SYMBOL(ssb_admatch_size);
+
+static int __init ssb_modinit(void)
+{
+	int err;
+
+	/* See the comment at the ssb_is_early_boot definition */
+	ssb_is_early_boot = 0;
+	err = bus_register(&ssb_bustype);
+	if (err)
+		return err;
+
+	/* Maybe we already registered some buses at early boot.
+	 * Check for this and attach them
+	 */
+	ssb_buses_lock();
+	err = ssb_attach_queued_buses();
+	ssb_buses_unlock();
+	if (err)
+		bus_unregister(&ssb_bustype);
+
+	err = b43_pci_ssb_bridge_init();
+	if (err) {
+		ssb_printk(KERN_ERR "Broadcom 43xx PCI-SSB-bridge "
+			   "initialization failed");
+		/* don't fail SSB init because of this */
+		err = 0;
+	}
+
+	return err;
+}
+subsys_initcall(ssb_modinit);
+
+static void __exit ssb_modexit(void)
+{
+	b43_pci_ssb_bridge_exit();
+	bus_unregister(&ssb_bustype);
+}
+module_exit(ssb_modexit)
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
new file mode 100644
index 0000000..0ab095c
--- /dev/null
+++ b/drivers/ssb/pci.c
@@ -0,0 +1,740 @@
+/*
+ * Sonics Silicon Backplane PCI-Hostbus related functions.
+ *
+ * Copyright (C) 2005-2006 Michael Buesch <mb@bu3sch.de>
+ * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+ * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+ * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ *
+ * Derived from the Broadcom 4400 device driver.
+ * Copyright (C) 2002 David S. Miller (davem@redhat.com)
+ * Fixed by Pekka Pietikainen (pp@ee.oulu.fi)
+ * Copyright (C) 2006 Broadcom Corporation.
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_regs.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "ssb_private.h"
+
+
+/* Define the following to 1 to enable a printk on each coreswitch. */
+#define SSB_VERBOSE_PCICORESWITCH_DEBUG		0
+
+
+/* Lowlevel coreswitching */
+int ssb_pci_switch_coreidx(struct ssb_bus *bus, u8 coreidx)
+{
+	int err;
+	int attempts = 0;
+	u32 cur_core;
+
+	while (1) {
+		err = pci_write_config_dword(bus->host_pci, SSB_BAR0_WIN,
+					     (coreidx * SSB_CORE_SIZE)
+					     + SSB_ENUM_BASE);
+		if (err)
+			goto error;
+		err = pci_read_config_dword(bus->host_pci, SSB_BAR0_WIN,
+					    &cur_core);
+		if (err)
+			goto error;
+		cur_core = (cur_core - SSB_ENUM_BASE)
+			   / SSB_CORE_SIZE;
+		if (cur_core == coreidx)
+			break;
+
+		if (attempts++ > SSB_BAR0_MAX_RETRIES)
+			goto error;
+		udelay(10);
+	}
+	return 0;
+error:
+	ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
+	return -ENODEV;
+}
+
+int ssb_pci_switch_core(struct ssb_bus *bus,
+			struct ssb_device *dev)
+{
+	int err;
+	unsigned long flags;
+
+#if SSB_VERBOSE_PCICORESWITCH_DEBUG
+	ssb_printk(KERN_INFO PFX
+		   "Switching to %s core, index %d\n",
+		   ssb_core_name(dev->id.coreid),
+		   dev->core_index);
+#endif
+
+	spin_lock_irqsave(&bus->bar_lock, flags);
+	err = ssb_pci_switch_coreidx(bus, dev->core_index);
+	if (!err)
+		bus->mapped_device = dev;
+	spin_unlock_irqrestore(&bus->bar_lock, flags);
+
+	return err;
+}
+
+/* Enable/disable the on board crystal oscillator and/or PLL. */
+int ssb_pci_xtal(struct ssb_bus *bus, u32 what, int turn_on)
+{
+	int err;
+	u32 in, out, outenable;
+	u16 pci_status;
+
+	if (bus->bustype != SSB_BUSTYPE_PCI)
+		return 0;
+
+	err = pci_read_config_dword(bus->host_pci, SSB_GPIO_IN, &in);
+	if (err)
+		goto err_pci;
+	err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT, &out);
+	if (err)
+		goto err_pci;
+	err = pci_read_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, &outenable);
+	if (err)
+		goto err_pci;
+
+	outenable |= what;
+
+	if (turn_on) {
+		/* Avoid glitching the clock if GPRS is already using it.
+		 * We can't actually read the state of the PLLPD so we infer it
+		 * by the value of XTAL_PU which *is* readable via gpioin.
+		 */
+		if (!(in & SSB_GPIO_XTAL)) {
+			if (what & SSB_GPIO_XTAL) {
+				/* Turn the crystal on */
+				out |= SSB_GPIO_XTAL;
+				if (what & SSB_GPIO_PLL)
+					out |= SSB_GPIO_PLL;
+				err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
+				if (err)
+					goto err_pci;
+				err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE,
+							     outenable);
+				if (err)
+					goto err_pci;
+				msleep(1);
+			}
+			if (what & SSB_GPIO_PLL) {
+				/* Turn the PLL on */
+				out &= ~SSB_GPIO_PLL;
+				err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
+				if (err)
+					goto err_pci;
+				msleep(5);
+			}
+		}
+
+		err = pci_read_config_word(bus->host_pci, PCI_STATUS, &pci_status);
+		if (err)
+			goto err_pci;
+		pci_status &= ~PCI_STATUS_SIG_TARGET_ABORT;
+		err = pci_write_config_word(bus->host_pci, PCI_STATUS, pci_status);
+		if (err)
+			goto err_pci;
+	} else {
+		if (what & SSB_GPIO_XTAL) {
+			/* Turn the crystal off */
+			out &= ~SSB_GPIO_XTAL;
+		}
+		if (what & SSB_GPIO_PLL) {
+			/* Turn the PLL off */
+			out |= SSB_GPIO_PLL;
+		}
+		err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT, out);
+		if (err)
+			goto err_pci;
+		err = pci_write_config_dword(bus->host_pci, SSB_GPIO_OUT_ENABLE, outenable);
+		if (err)
+			goto err_pci;
+	}
+
+out:
+	return err;
+
+err_pci:
+	printk(KERN_ERR PFX "Error: ssb_pci_xtal() could not access PCI config space!\n");
+	err = -EBUSY;
+	goto out;
+}
+
+/* Get the word-offset for a SSB_SPROM_XXX define. */
+#define SPOFF(offset)	(((offset) - SSB_SPROM_BASE) / sizeof(u16))
+/* Helper to extract some _offset, which is one of the SSB_SPROM_XXX defines. */
+#define SPEX(_outvar, _offset, _mask, _shift)	\
+	out->_outvar = ((in[SPOFF(_offset)] & (_mask)) >> (_shift))
+
+static inline u8 ssb_crc8(u8 crc, u8 data)
+{
+	/* Polynomial:   x^8 + x^7 + x^6 + x^4 + x^2 + 1   */
+	static const u8 t[] = {
+		0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
+		0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
+		0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
+		0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
+		0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
+		0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
+		0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
+		0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
+		0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
+		0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
+		0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
+		0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
+		0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
+		0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
+		0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
+		0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
+		0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
+		0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
+		0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
+		0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
+		0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
+		0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
+		0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
+		0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
+		0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
+		0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
+		0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
+		0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
+		0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
+		0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
+		0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
+		0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
+	};
+	return t[crc ^ data];
+}
+
+static u8 ssb_sprom_crc(const u16 *sprom)
+{
+	int word;
+	u8 crc = 0xFF;
+
+	for (word = 0; word < SSB_SPROMSIZE_WORDS - 1; word++) {
+		crc = ssb_crc8(crc, sprom[word] & 0x00FF);
+		crc = ssb_crc8(crc, (sprom[word] & 0xFF00) >> 8);
+	}
+	crc = ssb_crc8(crc, sprom[SPOFF(SSB_SPROM_REVISION)] & 0x00FF);
+	crc ^= 0xFF;
+
+	return crc;
+}
+
+static int sprom_check_crc(const u16 *sprom)
+{
+	u8 crc;
+	u8 expected_crc;
+	u16 tmp;
+
+	crc = ssb_sprom_crc(sprom);
+	tmp = sprom[SPOFF(SSB_SPROM_REVISION)] & SSB_SPROM_REVISION_CRC;
+	expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
+	if (crc != expected_crc)
+		return -EPROTO;
+
+	return 0;
+}
+
+static void sprom_do_read(struct ssb_bus *bus, u16 *sprom)
+{
+	int i;
+
+	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++)
+		sprom[i] = readw(bus->mmio + SSB_SPROM_BASE + (i * 2));
+}
+
+static int sprom_do_write(struct ssb_bus *bus, const u16 *sprom)
+{
+	struct pci_dev *pdev = bus->host_pci;
+	int i, err;
+	u32 spromctl;
+
+	ssb_printk(KERN_NOTICE PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");
+	err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
+	if (err)
+		goto err_ctlreg;
+	spromctl |= SSB_SPROMCTL_WE;
+	err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
+	if (err)
+		goto err_ctlreg;
+	ssb_printk(KERN_NOTICE PFX "[ 0%%");
+	msleep(500);
+	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
+		if (i == SSB_SPROMSIZE_WORDS / 4)
+			ssb_printk("25%%");
+		else if (i == SSB_SPROMSIZE_WORDS / 2)
+			ssb_printk("50%%");
+		else if (i == (SSB_SPROMSIZE_WORDS / 4) * 3)
+			ssb_printk("75%%");
+		else if (i % 2)
+			ssb_printk(".");
+		writew(sprom[i], bus->mmio + SSB_SPROM_BASE + (i * 2));
+		mmiowb();
+		msleep(20);
+	}
+	err = pci_read_config_dword(pdev, SSB_SPROMCTL, &spromctl);
+	if (err)
+		goto err_ctlreg;
+	spromctl &= ~SSB_SPROMCTL_WE;
+	err = pci_write_config_dword(pdev, SSB_SPROMCTL, spromctl);
+	if (err)
+		goto err_ctlreg;
+	msleep(500);
+	ssb_printk("100%% ]\n");
+	ssb_printk(KERN_NOTICE PFX "SPROM written.\n");
+
+	return 0;
+err_ctlreg:
+	ssb_printk(KERN_ERR PFX "Could not access SPROM control register.\n");
+	return err;
+}
+
+static void sprom_extract_r1(struct ssb_sprom_r1 *out, const u16 *in)
+{
+	int i;
+	u16 v;
+
+	SPEX(pci_spid, SSB_SPROM1_SPID, 0xFFFF, 0);
+	SPEX(pci_svid, SSB_SPROM1_SVID, 0xFFFF, 0);
+	SPEX(pci_pid, SSB_SPROM1_PID, 0xFFFF, 0);
+	for (i = 0; i < 3; i++) {
+		v = in[SPOFF(SSB_SPROM1_IL0MAC) + i];
+		*(((__be16 *)out->il0mac) + i) = cpu_to_be16(v);
+	}
+	for (i = 0; i < 3; i++) {
+		v = in[SPOFF(SSB_SPROM1_ET0MAC) + i];
+		*(((__be16 *)out->et0mac) + i) = cpu_to_be16(v);
+	}
+	for (i = 0; i < 3; i++) {
+		v = in[SPOFF(SSB_SPROM1_ET1MAC) + i];
+		*(((__be16 *)out->et1mac) + i) = cpu_to_be16(v);
+	}
+	SPEX(et0phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0A, 0);
+	SPEX(et1phyaddr, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1A,
+	     SSB_SPROM1_ETHPHY_ET1A_SHIFT);
+	SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14);
+	SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15);
+	SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0);
+	SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE,
+	     SSB_SPROM1_BINF_CCODE_SHIFT);
+	SPEX(antenna_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA,
+	     SSB_SPROM1_BINF_ANTA_SHIFT);
+	SPEX(antenna_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG,
+	     SSB_SPROM1_BINF_ANTBG_SHIFT);
+	SPEX(pa0b0, SSB_SPROM1_PA0B0, 0xFFFF, 0);
+	SPEX(pa0b1, SSB_SPROM1_PA0B1, 0xFFFF, 0);
+	SPEX(pa0b2, SSB_SPROM1_PA0B2, 0xFFFF, 0);
+	SPEX(pa1b0, SSB_SPROM1_PA1B0, 0xFFFF, 0);
+	SPEX(pa1b1, SSB_SPROM1_PA1B1, 0xFFFF, 0);
+	SPEX(pa1b2, SSB_SPROM1_PA1B2, 0xFFFF, 0);
+	SPEX(gpio0, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P0, 0);
+	SPEX(gpio1, SSB_SPROM1_GPIOA, SSB_SPROM1_GPIOA_P1,
+	     SSB_SPROM1_GPIOA_P1_SHIFT);
+	SPEX(gpio2, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P2, 0);
+	SPEX(gpio3, SSB_SPROM1_GPIOB, SSB_SPROM1_GPIOB_P3,
+	     SSB_SPROM1_GPIOB_P3_SHIFT);
+	SPEX(maxpwr_a, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_A,
+	     SSB_SPROM1_MAXPWR_A_SHIFT);
+	SPEX(maxpwr_bg, SSB_SPROM1_MAXPWR, SSB_SPROM1_MAXPWR_BG, 0);
+	SPEX(itssi_a, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_A,
+	     SSB_SPROM1_ITSSI_A_SHIFT);
+	SPEX(itssi_bg, SSB_SPROM1_ITSSI, SSB_SPROM1_ITSSI_BG, 0);
+	SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0);
+	SPEX(antenna_gain_a, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_A, 0);
+	SPEX(antenna_gain_bg, SSB_SPROM1_AGAIN, SSB_SPROM1_AGAIN_BG,
+	     SSB_SPROM1_AGAIN_BG_SHIFT);
+	for (i = 0; i < 4; i++) {
+		v = in[SPOFF(SSB_SPROM1_OEM) + i];
+		*(((__le16 *)out->oem) + i) = cpu_to_le16(v);
+	}
+}
+
+static void sprom_extract_r2(struct ssb_sprom_r2 *out, const u16 *in)
+{
+	int i;
+	u16 v;
+
+	SPEX(boardflags_hi, SSB_SPROM2_BFLHI,  0xFFFF, 0);
+	SPEX(maxpwr_a_hi, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_HI, 0);
+	SPEX(maxpwr_a_lo, SSB_SPROM2_MAXP_A, SSB_SPROM2_MAXP_A_LO,
+	     SSB_SPROM2_MAXP_A_LO_SHIFT);
+	SPEX(pa1lob0, SSB_SPROM2_PA1LOB0, 0xFFFF, 0);
+	SPEX(pa1lob1, SSB_SPROM2_PA1LOB1, 0xFFFF, 0);
+	SPEX(pa1lob2, SSB_SPROM2_PA1LOB2, 0xFFFF, 0);
+	SPEX(pa1hib0, SSB_SPROM2_PA1HIB0, 0xFFFF, 0);
+	SPEX(pa1hib1, SSB_SPROM2_PA1HIB1, 0xFFFF, 0);
+	SPEX(pa1hib2, SSB_SPROM2_PA1HIB2, 0xFFFF, 0);
+	SPEX(ofdm_pwr_off, SSB_SPROM2_OPO, SSB_SPROM2_OPO_VALUE, 0);
+	for (i = 0; i < 4; i++) {
+		v = in[SPOFF(SSB_SPROM2_CCODE) + i];
+		*(((__le16 *)out->country_str) + i) = cpu_to_le16(v);
+	}
+}
+
+static void sprom_extract_r3(struct ssb_sprom_r3 *out, const u16 *in)
+{
+	out->ofdmapo  = (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0xFF00) >> 8;
+	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 0] & 0x00FF) << 8;
+	out->ofdmapo <<= 16;
+	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0xFF00) >> 8;
+	out->ofdmapo |= (in[SPOFF(SSB_SPROM3_OFDMAPO) + 1] & 0x00FF) << 8;
+
+	out->ofdmalpo  = (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0xFF00) >> 8;
+	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 0] & 0x00FF) << 8;
+	out->ofdmalpo <<= 16;
+	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0xFF00) >> 8;
+	out->ofdmalpo |= (in[SPOFF(SSB_SPROM3_OFDMALPO) + 1] & 0x00FF) << 8;
+
+	out->ofdmahpo  = (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0xFF00) >> 8;
+	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 0] & 0x00FF) << 8;
+	out->ofdmahpo <<= 16;
+	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0xFF00) >> 8;
+	out->ofdmahpo |= (in[SPOFF(SSB_SPROM3_OFDMAHPO) + 1] & 0x00FF) << 8;
+
+	SPEX(gpioldc_on_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_ON,
+	     SSB_SPROM3_GPIOLDC_ON_SHIFT);
+	SPEX(gpioldc_off_cnt, SSB_SPROM3_GPIOLDC, SSB_SPROM3_GPIOLDC_OFF,
+	     SSB_SPROM3_GPIOLDC_OFF_SHIFT);
+	SPEX(cckpo_1M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_1M, 0);
+	SPEX(cckpo_2M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_2M,
+	     SSB_SPROM3_CCKPO_2M_SHIFT);
+	SPEX(cckpo_55M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_55M,
+	     SSB_SPROM3_CCKPO_55M_SHIFT);
+	SPEX(cckpo_11M, SSB_SPROM3_CCKPO, SSB_SPROM3_CCKPO_11M,
+	     SSB_SPROM3_CCKPO_11M_SHIFT);
+
+	out->ofdmgpo  = (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0xFF00) >> 8;
+	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 0] & 0x00FF) << 8;
+	out->ofdmgpo <<= 16;
+	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0xFF00) >> 8;
+	out->ofdmgpo |= (in[SPOFF(SSB_SPROM3_OFDMGPO) + 1] & 0x00FF) << 8;
+}
+
+static int sprom_extract(struct ssb_bus *bus,
+			 struct ssb_sprom *out, const u16 *in)
+{
+	memset(out, 0, sizeof(*out));
+
+	SPEX(revision, SSB_SPROM_REVISION, SSB_SPROM_REVISION_REV, 0);
+	SPEX(crc, SSB_SPROM_REVISION, SSB_SPROM_REVISION_CRC,
+	     SSB_SPROM_REVISION_CRC_SHIFT);
+
+	if ((bus->chip_id & 0xFF00) == 0x4400) {
+		/* Workaround: The BCM44XX chip has a stupid revision
+		 * number stored in the SPROM.
+		 * Always extract r1. */
+		sprom_extract_r1(&out->r1, in);
+	} else {
+		if (out->revision == 0)
+			goto unsupported;
+		if (out->revision >= 1 && out->revision <= 3)
+			sprom_extract_r1(&out->r1, in);
+		if (out->revision >= 2 && out->revision <= 3)
+			sprom_extract_r2(&out->r2, in);
+		if (out->revision == 3)
+			sprom_extract_r3(&out->r3, in);
+		if (out->revision >= 4)
+			goto unsupported;
+	}
+
+	return 0;
+unsupported:
+	ssb_printk(KERN_WARNING PFX "Unsupported SPROM revision %d "
+		   "detected. Will extract v1\n", out->revision);
+	sprom_extract_r1(&out->r1, in);
+	return 0;
+}
+
+static int ssb_pci_sprom_get(struct ssb_bus *bus,
+			     struct ssb_sprom *sprom)
+{
+	int err = -ENOMEM;
+	u16 *buf;
+
+	buf = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
+	if (!buf)
+		goto out;
+	sprom_do_read(bus, buf);
+	err = sprom_check_crc(buf);
+	if (err) {
+		ssb_printk(KERN_WARNING PFX
+			   "WARNING: Invalid SPROM CRC (corrupt SPROM)\n");
+	}
+	err = sprom_extract(bus, sprom, buf);
+
+	kfree(buf);
+out:
+	return err;
+}
+
+static void ssb_pci_get_boardinfo(struct ssb_bus *bus,
+				  struct ssb_boardinfo *bi)
+{
+	pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_VENDOR_ID,
+			     &bi->vendor);
+	pci_read_config_word(bus->host_pci, PCI_SUBSYSTEM_ID,
+			     &bi->type);
+	pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
+			     &bi->rev);
+}
+
+int ssb_pci_get_invariants(struct ssb_bus *bus,
+			   struct ssb_init_invariants *iv)
+{
+	int err;
+
+	err = ssb_pci_sprom_get(bus, &iv->sprom);
+	if (err)
+		goto out;
+	ssb_pci_get_boardinfo(bus, &iv->boardinfo);
+
+out:
+	return err;
+}
+
+#ifdef CONFIG_SSB_DEBUG
+static int ssb_pci_assert_buspower(struct ssb_bus *bus)
+{
+	if (likely(bus->powered_up))
+		return 0;
+
+	printk(KERN_ERR PFX "FATAL ERROR: Bus powered down "
+	       "while accessing PCI MMIO space\n");
+	if (bus->power_warn_count <= 10) {
+		bus->power_warn_count++;
+		dump_stack();
+	}
+
+	return -ENODEV;
+}
+#else /* DEBUG */
+static inline int ssb_pci_assert_buspower(struct ssb_bus *bus)
+{
+	return 0;
+}
+#endif /* DEBUG */
+
+static u16 ssb_pci_read16(struct ssb_device *dev, u16 offset)
+{
+	struct ssb_bus *bus = dev->bus;
+
+	if (unlikely(ssb_pci_assert_buspower(bus)))
+		return 0xFFFF;
+	if (unlikely(bus->mapped_device != dev)) {
+		if (unlikely(ssb_pci_switch_core(bus, dev)))
+			return 0xFFFF;
+	}
+	return ioread16(bus->mmio + offset);
+}
+
+static u32 ssb_pci_read32(struct ssb_device *dev, u16 offset)
+{
+	struct ssb_bus *bus = dev->bus;
+
+	if (unlikely(ssb_pci_assert_buspower(bus)))
+		return 0xFFFFFFFF;
+	if (unlikely(bus->mapped_device != dev)) {
+		if (unlikely(ssb_pci_switch_core(bus, dev)))
+			return 0xFFFFFFFF;
+	}
+	return ioread32(bus->mmio + offset);
+}
+
+static void ssb_pci_write16(struct ssb_device *dev, u16 offset, u16 value)
+{
+	struct ssb_bus *bus = dev->bus;
+
+	if (unlikely(ssb_pci_assert_buspower(bus)))
+		return;
+	if (unlikely(bus->mapped_device != dev)) {
+		if (unlikely(ssb_pci_switch_core(bus, dev)))
+			return;
+	}
+	iowrite16(value, bus->mmio + offset);
+}
+
+static void ssb_pci_write32(struct ssb_device *dev, u16 offset, u32 value)
+{
+	struct ssb_bus *bus = dev->bus;
+
+	if (unlikely(ssb_pci_assert_buspower(bus)))
+		return;
+	if (unlikely(bus->mapped_device != dev)) {
+		if (unlikely(ssb_pci_switch_core(bus, dev)))
+			return;
+	}
+	iowrite32(value, bus->mmio + offset);
+}
+
+/* Not "static", as it's used in main.c */
+const struct ssb_bus_ops ssb_pci_ops = {
+	.read16		= ssb_pci_read16,
+	.read32		= ssb_pci_read32,
+	.write16	= ssb_pci_write16,
+	.write32	= ssb_pci_write32,
+};
+
+static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len)
+{
+	int i, pos = 0;
+
+	for (i = 0; i < SSB_SPROMSIZE_WORDS; i++) {
+		pos += snprintf(buf + pos, buf_len - pos - 1,
+				"%04X", swab16(sprom[i]) & 0xFFFF);
+	}
+	pos += snprintf(buf + pos, buf_len - pos - 1, "\n");
+
+	return pos + 1;
+}
+
+static int hex2sprom(u16 *sprom, const char *dump, size_t len)
+{
+	char tmp[5] = { 0 };
+	int cnt = 0;
+	unsigned long parsed;
+
+	if (len < SSB_SPROMSIZE_BYTES * 2)
+		return -EINVAL;
+
+	while (cnt < SSB_SPROMSIZE_WORDS) {
+		memcpy(tmp, dump, 4);
+		dump += 4;
+		parsed = simple_strtoul(tmp, NULL, 16);
+		sprom[cnt++] = swab16((u16)parsed);
+	}
+
+	return 0;
+}
+
+static ssize_t ssb_pci_attr_sprom_show(struct device *pcidev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
+	struct ssb_bus *bus;
+	u16 *sprom;
+	int err = -ENODEV;
+	ssize_t count = 0;
+
+	bus = ssb_pci_dev_to_bus(pdev);
+	if (!bus)
+		goto out;
+	err = -ENOMEM;
+	sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
+	if (!sprom)
+		goto out;
+
+	/* Use interruptible locking, as the SPROM write might
+	 * be holding the lock for several seconds. So allow userspace
+	 * to cancel operation. */
+	err = -ERESTARTSYS;
+	if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
+		goto out_kfree;
+	sprom_do_read(bus, sprom);
+	mutex_unlock(&bus->pci_sprom_mutex);
+
+	count = sprom2hex(sprom, buf, PAGE_SIZE);
+	err = 0;
+
+out_kfree:
+	kfree(sprom);
+out:
+	return err ? err : count;
+}
+
+static ssize_t ssb_pci_attr_sprom_store(struct device *pcidev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct pci_dev *pdev = container_of(pcidev, struct pci_dev, dev);
+	struct ssb_bus *bus;
+	u16 *sprom;
+	int res = 0, err = -ENODEV;
+
+	bus = ssb_pci_dev_to_bus(pdev);
+	if (!bus)
+		goto out;
+	err = -ENOMEM;
+	sprom = kcalloc(SSB_SPROMSIZE_WORDS, sizeof(u16), GFP_KERNEL);
+	if (!sprom)
+		goto out;
+	err = hex2sprom(sprom, buf, count);
+	if (err) {
+		err = -EINVAL;
+		goto out_kfree;
+	}
+	err = sprom_check_crc(sprom);
+	if (err) {
+		err = -EINVAL;
+		goto out_kfree;
+	}
+
+	/* Use interruptible locking, as the SPROM write might
+	 * be holding the lock for several seconds. So allow userspace
+	 * to cancel operation. */
+	err = -ERESTARTSYS;
+	if (mutex_lock_interruptible(&bus->pci_sprom_mutex))
+		goto out_kfree;
+	err = ssb_devices_freeze(bus);
+	if (err == -EOPNOTSUPP) {
+		ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze devices. "
+			   "No suspend support. Is CONFIG_PM enabled?\n");
+		goto out_unlock;
+	}
+	if (err) {
+		ssb_printk(KERN_ERR PFX "SPROM write: Could not freeze all devices\n");
+		goto out_unlock;
+	}
+	res = sprom_do_write(bus, sprom);
+	err = ssb_devices_thaw(bus);
+	if (err)
+		ssb_printk(KERN_ERR PFX "SPROM write: Could not thaw all devices\n");
+out_unlock:
+	mutex_unlock(&bus->pci_sprom_mutex);
+out_kfree:
+	kfree(sprom);
+out:
+	if (res)
+		return res;
+	return err ? err : count;
+}
+
+static DEVICE_ATTR(ssb_sprom, 0600,
+		   ssb_pci_attr_sprom_show,
+		   ssb_pci_attr_sprom_store);
+
+void ssb_pci_exit(struct ssb_bus *bus)
+{
+	struct pci_dev *pdev;
+
+	if (bus->bustype != SSB_BUSTYPE_PCI)
+		return;
+
+	pdev = bus->host_pci;
+	device_remove_file(&pdev->dev, &dev_attr_ssb_sprom);
+}
+
+int ssb_pci_init(struct ssb_bus *bus)
+{
+	struct pci_dev *pdev;
+	int err;
+
+	if (bus->bustype != SSB_BUSTYPE_PCI)
+		return 0;
+
+	pdev = bus->host_pci;
+	mutex_init(&bus->pci_sprom_mutex);
+	err = device_create_file(&pdev->dev, &dev_attr_ssb_sprom);
+	if (err)
+		goto out;
+
+out:
+	return err;
+}
diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c
new file mode 100644
index 0000000..82a10ab
--- /dev/null
+++ b/drivers/ssb/pcihost_wrapper.c
@@ -0,0 +1,104 @@
+/*
+ * Sonics Silicon Backplane
+ * PCI Hostdevice wrapper
+ *
+ * Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>
+ * Copyright (c) 2005 Stefano Brivio <st3@riseup.net>
+ * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ * Copyright (c) 2005-2007 Michael Buesch <mbuesch@freenet.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/pci.h>
+#include <linux/ssb/ssb.h>
+
+
+#ifdef CONFIG_PM
+static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state)
+{
+	pci_save_state(dev);
+	pci_disable_device(dev);
+	pci_set_power_state(dev, pci_choose_state(dev, state));
+
+	return 0;
+}
+
+static int ssb_pcihost_resume(struct pci_dev *dev)
+{
+	int err;
+
+	pci_set_power_state(dev, 0);
+	err = pci_enable_device(dev);
+	if (err)
+		return err;
+	pci_restore_state(dev);
+
+	return 0;
+}
+#else /* CONFIG_PM */
+# define ssb_pcihost_suspend	NULL
+# define ssb_pcihost_resume	NULL
+#endif /* CONFIG_PM */
+
+static int ssb_pcihost_probe(struct pci_dev *dev,
+			     const struct pci_device_id *id)
+{
+	struct ssb_bus *ssb;
+	int err = -ENOMEM;
+	const char *name;
+
+	ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
+	if (!ssb)
+		goto out;
+	err = pci_enable_device(dev);
+	if (err)
+		goto err_kfree_ssb;
+	name = dev->dev.bus_id;
+	if (dev->driver && dev->driver->name)
+		name = dev->driver->name;
+	err = pci_request_regions(dev, name);
+	if (err)
+		goto err_pci_disable;
+	pci_set_master(dev);
+
+	err = ssb_bus_pcibus_register(ssb, dev);
+	if (err)
+		goto err_pci_release_regions;
+
+	pci_set_drvdata(dev, ssb);
+
+out:
+	return err;
+
+err_pci_release_regions:
+	pci_release_regions(dev);
+err_pci_disable:
+	pci_disable_device(dev);
+err_kfree_ssb:
+	kfree(ssb);
+	return err;
+}
+
+static void ssb_pcihost_remove(struct pci_dev *dev)
+{
+	struct ssb_bus *ssb = pci_get_drvdata(dev);
+
+	ssb_bus_unregister(ssb);
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+	kfree(ssb);
+	pci_set_drvdata(dev, NULL);
+}
+
+int ssb_pcihost_register(struct pci_driver *driver)
+{
+	driver->probe = ssb_pcihost_probe;
+	driver->remove = ssb_pcihost_remove;
+	driver->suspend = ssb_pcihost_suspend;
+	driver->resume = ssb_pcihost_resume;
+
+	return pci_register_driver(driver);
+}
+EXPORT_SYMBOL(ssb_pcihost_register);
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c
new file mode 100644
index 0000000..7c77360
--- /dev/null
+++ b/drivers/ssb/pcmcia.c
@@ -0,0 +1,271 @@
+/*
+ * Sonics Silicon Backplane
+ * PCMCIA-Hostbus related functions
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/delay.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#include "ssb_private.h"
+
+
+/* Define the following to 1 to enable a printk on each coreswitch. */
+#define SSB_VERBOSE_PCMCIACORESWITCH_DEBUG		0
+
+
+int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
+			      u8 coreidx)
+{
+	struct pcmcia_device *pdev = bus->host_pcmcia;
+	int err;
+	int attempts = 0;
+	u32 cur_core;
+	conf_reg_t reg;
+	u32 addr;
+	u32 read_addr;
+
+	addr = (coreidx * SSB_CORE_SIZE) + SSB_ENUM_BASE;
+	while (1) {
+		reg.Action = CS_WRITE;
+		reg.Offset = 0x2E;
+		reg.Value = (addr & 0x0000F000) >> 12;
+		err = pcmcia_access_configuration_register(pdev, &reg);
+		if (err != CS_SUCCESS)
+			goto error;
+		reg.Offset = 0x30;
+		reg.Value = (addr & 0x00FF0000) >> 16;
+		err = pcmcia_access_configuration_register(pdev, &reg);
+		if (err != CS_SUCCESS)
+			goto error;
+		reg.Offset = 0x32;
+		reg.Value = (addr & 0xFF000000) >> 24;
+		err = pcmcia_access_configuration_register(pdev, &reg);
+		if (err != CS_SUCCESS)
+			goto error;
+
+		read_addr = 0;
+
+		reg.Action = CS_READ;
+		reg.Offset = 0x2E;
+		err = pcmcia_access_configuration_register(pdev, &reg);
+		if (err != CS_SUCCESS)
+			goto error;
+		read_addr |= (reg.Value & 0xF) << 12;
+		reg.Offset = 0x30;
+		err = pcmcia_access_configuration_register(pdev, &reg);
+		if (err != CS_SUCCESS)
+			goto error;
+		read_addr |= reg.Value << 16;
+		reg.Offset = 0x32;
+		err = pcmcia_access_configuration_register(pdev, &reg);
+		if (err != CS_SUCCESS)
+			goto error;
+		read_addr |= reg.Value << 24;
+
+		cur_core = (read_addr - SSB_ENUM_BASE) / SSB_CORE_SIZE;
+		if (cur_core == coreidx)
+			break;
+
+		if (attempts++ > SSB_BAR0_MAX_RETRIES)
+			goto error;
+		udelay(10);
+	}
+
+	return 0;
+error:
+	ssb_printk(KERN_ERR PFX "Failed to switch to core %u\n", coreidx);
+	return -ENODEV;
+}
+
+int ssb_pcmcia_switch_core(struct ssb_bus *bus,
+			   struct ssb_device *dev)
+{
+	int err;
+	unsigned long flags;
+
+#if SSB_VERBOSE_PCMCIACORESWITCH_DEBUG
+	ssb_printk(KERN_INFO PFX
+		   "Switching to %s core, index %d\n",
+		   ssb_core_name(dev->id.coreid),
+		   dev->core_index);
+#endif
+
+	spin_lock_irqsave(&bus->bar_lock, flags);
+	err = ssb_pcmcia_switch_coreidx(bus, dev->core_index);
+	if (!err)
+		bus->mapped_device = dev;
+	spin_unlock_irqrestore(&bus->bar_lock, flags);
+
+	return err;
+}
+
+int ssb_pcmcia_switch_segment(struct ssb_bus *bus, u8 seg)
+{
+	int attempts = 0;
+	unsigned long flags;
+	conf_reg_t reg;
+	int res, err = 0;
+
+	SSB_WARN_ON((seg != 0) && (seg != 1));
+	reg.Offset = 0x34;
+	reg.Function = 0;
+	spin_lock_irqsave(&bus->bar_lock, flags);
+	while (1) {
+		reg.Action = CS_WRITE;
+		reg.Value = seg;
+		res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
+		if (unlikely(res != CS_SUCCESS))
+			goto error;
+		reg.Value = 0xFF;
+		reg.Action = CS_READ;
+		res = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
+		if (unlikely(res != CS_SUCCESS))
+			goto error;
+
+		if (reg.Value == seg)
+			break;
+
+		if (unlikely(attempts++ > SSB_BAR0_MAX_RETRIES))
+			goto error;
+		udelay(10);
+	}
+	bus->mapped_pcmcia_seg = seg;
+out_unlock:
+	spin_unlock_irqrestore(&bus->bar_lock, flags);
+	return err;
+error:
+	ssb_printk(KERN_ERR PFX "Failed to switch pcmcia segment\n");
+	err = -ENODEV;
+	goto out_unlock;
+}
+
+/* These are the main device register access functions.
+ * do_select_core is inline to have the likely hotpath inline.
+ * All unlikely codepaths are out-of-line. */
+static inline int do_select_core(struct ssb_bus *bus,
+				 struct ssb_device *dev,
+				 u16 *offset)
+{
+	int err;
+	u8 need_seg = (*offset >= 0x800) ? 1 : 0;
+
+	if (unlikely(dev != bus->mapped_device)) {
+		err = ssb_pcmcia_switch_core(bus, dev);
+		if (unlikely(err))
+			return err;
+	}
+	if (unlikely(need_seg != bus->mapped_pcmcia_seg)) {
+		err = ssb_pcmcia_switch_segment(bus, need_seg);
+		if (unlikely(err))
+			return err;
+	}
+	if (need_seg == 1)
+		*offset -= 0x800;
+
+	return 0;
+}
+
+static u16 ssb_pcmcia_read16(struct ssb_device *dev, u16 offset)
+{
+	struct ssb_bus *bus = dev->bus;
+	u16 x;
+
+	if (unlikely(do_select_core(bus, dev, &offset)))
+		return 0xFFFF;
+	x = readw(bus->mmio + offset);
+
+	return x;
+}
+
+static u32 ssb_pcmcia_read32(struct ssb_device *dev, u16 offset)
+{
+	struct ssb_bus *bus = dev->bus;
+	u32 x;
+
+	if (unlikely(do_select_core(bus, dev, &offset)))
+		return 0xFFFFFFFF;
+	x = readl(bus->mmio + offset);
+
+	return x;
+}
+
+static void ssb_pcmcia_write16(struct ssb_device *dev, u16 offset, u16 value)
+{
+	struct ssb_bus *bus = dev->bus;
+
+	if (unlikely(do_select_core(bus, dev, &offset)))
+		return;
+	writew(value, bus->mmio + offset);
+}
+
+static void ssb_pcmcia_write32(struct ssb_device *dev, u16 offset, u32 value)
+{
+	struct ssb_bus *bus = dev->bus;
+
+	if (unlikely(do_select_core(bus, dev, &offset)))
+		return;
+	readw(bus->mmio + offset);
+	writew(value >> 16, bus->mmio + offset + 2);
+	readw(bus->mmio + offset);
+	writew(value, bus->mmio + offset);
+}
+
+/* Not "static", as it's used in main.c */
+const struct ssb_bus_ops ssb_pcmcia_ops = {
+	.read16		= ssb_pcmcia_read16,
+	.read32		= ssb_pcmcia_read32,
+	.write16	= ssb_pcmcia_write16,
+	.write32	= ssb_pcmcia_write32,
+};
+
+int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
+			      struct ssb_init_invariants *iv)
+{
+	//TODO
+	return 0;
+}
+
+int ssb_pcmcia_init(struct ssb_bus *bus)
+{
+	conf_reg_t reg;
+	int err;
+
+	if (bus->bustype != SSB_BUSTYPE_PCMCIA)
+		return 0;
+
+	/* Switch segment to a known state and sync
+	 * bus->mapped_pcmcia_seg with hardware state. */
+	ssb_pcmcia_switch_segment(bus, 0);
+
+	/* Init IRQ routing */
+	reg.Action = CS_READ;
+	reg.Function = 0;
+	if (bus->chip_id == 0x4306)
+		reg.Offset = 0x00;
+	else
+		reg.Offset = 0x80;
+	err = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
+	if (err != CS_SUCCESS)
+		goto error;
+	reg.Action = CS_WRITE;
+	reg.Value |= 0x04 | 0x01;
+	err = pcmcia_access_configuration_register(bus->host_pcmcia, &reg);
+	if (err != CS_SUCCESS)
+		goto error;
+
+	return 0;
+error:
+	return -ENODEV;
+}
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
new file mode 100644
index 0000000..96258c6
--- /dev/null
+++ b/drivers/ssb/scan.c
@@ -0,0 +1,413 @@
+/*
+ * Sonics Silicon Backplane
+ * Bus scanning
+ *
+ * Copyright (C) 2005-2007 Michael Buesch <mb@bu3sch.de>
+ * Copyright (C) 2005 Martin Langer <martin-langer@gmx.de>
+ * Copyright (C) 2005 Stefano Brivio <st3@riseup.net>
+ * Copyright (C) 2005 Danny van Dyk <kugelfang@gentoo.org>
+ * Copyright (C) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
+ * Copyright (C) 2006 Broadcom Corporation.
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_regs.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include "ssb_private.h"
+
+
+const char *ssb_core_name(u16 coreid)
+{
+	switch (coreid) {
+	case SSB_DEV_CHIPCOMMON:
+		return "ChipCommon";
+	case SSB_DEV_ILINE20:
+		return "ILine 20";
+	case SSB_DEV_SDRAM:
+		return "SDRAM";
+	case SSB_DEV_PCI:
+		return "PCI";
+	case SSB_DEV_MIPS:
+		return "MIPS";
+	case SSB_DEV_ETHERNET:
+		return "Fast Ethernet";
+	case SSB_DEV_V90:
+		return "V90";
+	case SSB_DEV_USB11_HOSTDEV:
+		return "USB 1.1 Hostdev";
+	case SSB_DEV_ADSL:
+		return "ADSL";
+	case SSB_DEV_ILINE100:
+		return "ILine 100";
+	case SSB_DEV_IPSEC:
+		return "IPSEC";
+	case SSB_DEV_PCMCIA:
+		return "PCMCIA";
+	case SSB_DEV_INTERNAL_MEM:
+		return "Internal Memory";
+	case SSB_DEV_MEMC_SDRAM:
+		return "MEMC SDRAM";
+	case SSB_DEV_EXTIF:
+		return "EXTIF";
+	case SSB_DEV_80211:
+		return "IEEE 802.11";
+	case SSB_DEV_MIPS_3302:
+		return "MIPS 3302";
+	case SSB_DEV_USB11_HOST:
+		return "USB 1.1 Host";
+	case SSB_DEV_USB11_DEV:
+		return "USB 1.1 Device";
+	case SSB_DEV_USB20_HOST:
+		return "USB 2.0 Host";
+	case SSB_DEV_USB20_DEV:
+		return "USB 2.0 Device";
+	case SSB_DEV_SDIO_HOST:
+		return "SDIO Host";
+	case SSB_DEV_ROBOSWITCH:
+		return "Roboswitch";
+	case SSB_DEV_PARA_ATA:
+		return "PATA";
+	case SSB_DEV_SATA_XORDMA:
+		return "SATA XOR-DMA";
+	case SSB_DEV_ETHERNET_GBIT:
+		return "GBit Ethernet";
+	case SSB_DEV_PCIE:
+		return "PCI-E";
+	case SSB_DEV_MIMO_PHY:
+		return "MIMO PHY";
+	case SSB_DEV_SRAM_CTRLR:
+		return "SRAM Controller";
+	case SSB_DEV_MINI_MACPHY:
+		return "Mini MACPHY";
+	case SSB_DEV_ARM_1176:
+		return "ARM 1176";
+	case SSB_DEV_ARM_7TDMI:
+		return "ARM 7TDMI";
+	}
+	return "UNKNOWN";
+}
+
+static u16 pcidev_to_chipid(struct pci_dev *pci_dev)
+{
+	u16 chipid_fallback = 0;
+
+	switch (pci_dev->device) {
+	case 0x4301:
+		chipid_fallback = 0x4301;
+		break;
+	case 0x4305 ... 0x4307:
+		chipid_fallback = 0x4307;
+		break;
+	case 0x4403:
+		chipid_fallback = 0x4402;
+		break;
+	case 0x4610 ... 0x4615:
+		chipid_fallback = 0x4610;
+		break;
+	case 0x4710 ... 0x4715:
+		chipid_fallback = 0x4710;
+		break;
+	case 0x4320 ... 0x4325:
+		chipid_fallback = 0x4309;
+		break;
+	case PCI_DEVICE_ID_BCM4401:
+	case PCI_DEVICE_ID_BCM4401B0:
+	case PCI_DEVICE_ID_BCM4401B1:
+		chipid_fallback = 0x4401;
+		break;
+	default:
+		ssb_printk(KERN_ERR PFX
+			   "PCI-ID not in fallback list\n");
+	}
+
+	return chipid_fallback;
+}
+
+static u8 chipid_to_nrcores(u16 chipid)
+{
+	switch (chipid) {
+	case 0x5365:
+		return 7;
+	case 0x4306:
+		return 6;
+	case 0x4310:
+		return 8;
+	case 0x4307:
+	case 0x4301:
+		return 5;
+	case 0x4401:
+	case 0x4402:
+		return 3;
+	case 0x4710:
+	case 0x4610:
+	case 0x4704:
+		return 9;
+	default:
+		ssb_printk(KERN_ERR PFX
+			   "CHIPID not in nrcores fallback list\n");
+	}
+
+	return 1;
+}
+
+static u32 scan_read32(struct ssb_bus *bus, u8 current_coreidx,
+		       u16 offset)
+{
+	switch (bus->bustype) {
+	case SSB_BUSTYPE_SSB:
+		offset += current_coreidx * SSB_CORE_SIZE;
+		break;
+	case SSB_BUSTYPE_PCI:
+		break;
+	case SSB_BUSTYPE_PCMCIA:
+		if (offset >= 0x800) {
+			ssb_pcmcia_switch_segment(bus, 1);
+			offset -= 0x800;
+		} else
+			ssb_pcmcia_switch_segment(bus, 0);
+		break;
+	}
+	return readl(bus->mmio + offset);
+}
+
+static int scan_switchcore(struct ssb_bus *bus, u8 coreidx)
+{
+	switch (bus->bustype) {
+	case SSB_BUSTYPE_SSB:
+		break;
+	case SSB_BUSTYPE_PCI:
+		return ssb_pci_switch_coreidx(bus, coreidx);
+	case SSB_BUSTYPE_PCMCIA:
+		return ssb_pcmcia_switch_coreidx(bus, coreidx);
+	}
+	return 0;
+}
+
+void ssb_iounmap(struct ssb_bus *bus)
+{
+	switch (bus->bustype) {
+	case SSB_BUSTYPE_SSB:
+	case SSB_BUSTYPE_PCMCIA:
+		iounmap(bus->mmio);
+		break;
+	case SSB_BUSTYPE_PCI:
+#ifdef CONFIG_SSB_PCIHOST
+		pci_iounmap(bus->host_pci, bus->mmio);
+#else
+		SSB_BUG_ON(1); /* Can't reach this code. */
+#endif
+		break;
+	}
+	bus->mmio = NULL;
+	bus->mapped_device = NULL;
+}
+
+static void __iomem *ssb_ioremap(struct ssb_bus *bus,
+				 unsigned long baseaddr)
+{
+	void __iomem *mmio = NULL;
+
+	switch (bus->bustype) {
+	case SSB_BUSTYPE_SSB:
+		/* Only map the first core for now. */
+		/* fallthrough... */
+	case SSB_BUSTYPE_PCMCIA:
+		mmio = ioremap(baseaddr, SSB_CORE_SIZE);
+		break;
+	case SSB_BUSTYPE_PCI:
+#ifdef CONFIG_SSB_PCIHOST
+		mmio = pci_iomap(bus->host_pci, 0, ~0UL);
+#else
+		SSB_BUG_ON(1); /* Can't reach this code. */
+#endif
+		break;
+	}
+
+	return mmio;
+}
+
+static int we_support_multiple_80211_cores(struct ssb_bus *bus)
+{
+	/* More than one 802.11 core is only supported by special chips.
+	 * There are chips with two 802.11 cores, but with dangling
+	 * pins on the second core. Be careful and reject them here.
+	 */
+
+#ifdef CONFIG_SSB_PCIHOST
+	if (bus->bustype == SSB_BUSTYPE_PCI) {
+		if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
+		    bus->host_pci->device == 0x4324)
+			return 1;
+	}
+#endif /* CONFIG_SSB_PCIHOST */
+	return 0;
+}
+
+int ssb_bus_scan(struct ssb_bus *bus,
+		 unsigned long baseaddr)
+{
+	int err = -ENOMEM;
+	void __iomem *mmio;
+	u32 idhi, cc, rev, tmp;
+	int dev_i, i;
+	struct ssb_device *dev;
+	int nr_80211_cores = 0;
+
+	mmio = ssb_ioremap(bus, baseaddr);
+	if (!mmio)
+		goto out;
+	bus->mmio = mmio;
+
+	err = scan_switchcore(bus, 0); /* Switch to first core */
+	if (err)
+		goto err_unmap;
+
+	idhi = scan_read32(bus, 0, SSB_IDHIGH);
+	cc = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
+	rev = (idhi & SSB_IDHIGH_RCLO);
+	rev |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
+
+	bus->nr_devices = 0;
+	if (cc == SSB_DEV_CHIPCOMMON) {
+		tmp = scan_read32(bus, 0, SSB_CHIPCO_CHIPID);
+
+		bus->chip_id = (tmp & SSB_CHIPCO_IDMASK);
+		bus->chip_rev = (tmp & SSB_CHIPCO_REVMASK) >>
+				SSB_CHIPCO_REVSHIFT;
+		bus->chip_package = (tmp & SSB_CHIPCO_PACKMASK) >>
+				    SSB_CHIPCO_PACKSHIFT;
+		if (rev >= 4) {
+			bus->nr_devices = (tmp & SSB_CHIPCO_NRCORESMASK) >>
+					  SSB_CHIPCO_NRCORESSHIFT;
+		}
+		tmp = scan_read32(bus, 0, SSB_CHIPCO_CAP);
+		bus->chipco.capabilities = tmp;
+	} else {
+		if (bus->bustype == SSB_BUSTYPE_PCI) {
+			bus->chip_id = pcidev_to_chipid(bus->host_pci);
+			pci_read_config_word(bus->host_pci, PCI_REVISION_ID,
+					     &bus->chip_rev);
+			bus->chip_package = 0;
+		} else {
+			bus->chip_id = 0x4710;
+			bus->chip_rev = 0;
+			bus->chip_package = 0;
+		}
+	}
+	if (!bus->nr_devices)
+		bus->nr_devices = chipid_to_nrcores(bus->chip_id);
+	if (bus->nr_devices > ARRAY_SIZE(bus->devices)) {
+		ssb_printk(KERN_ERR PFX
+			   "More than %d ssb cores found (%d)\n",
+			   SSB_MAX_NR_CORES, bus->nr_devices);
+		goto err_unmap;
+	}
+	if (bus->bustype == SSB_BUSTYPE_SSB) {
+		/* Now that we know the number of cores,
+		 * remap the whole IO space for all cores.
+		 */
+		err = -ENOMEM;
+		iounmap(mmio);
+		mmio = ioremap(baseaddr, SSB_CORE_SIZE * bus->nr_devices);
+		if (!mmio)
+			goto out;
+		bus->mmio = mmio;
+	}
+
+	/* Fetch basic information about each core/device */
+	for (i = 0, dev_i = 0; i < bus->nr_devices; i++) {
+		err = scan_switchcore(bus, i);
+		if (err)
+			goto err_unmap;
+		dev = &(bus->devices[dev_i]);
+
+		idhi = scan_read32(bus, i, SSB_IDHIGH);
+		dev->id.coreid = (idhi & SSB_IDHIGH_CC) >> SSB_IDHIGH_CC_SHIFT;
+		dev->id.revision = (idhi & SSB_IDHIGH_RCLO);
+		dev->id.revision |= (idhi & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT;
+		dev->id.vendor = (idhi & SSB_IDHIGH_VC) >> SSB_IDHIGH_VC_SHIFT;
+		dev->core_index = i;
+		dev->bus = bus;
+		dev->ops = bus->ops;
+
+		ssb_dprintk(KERN_INFO PFX
+			    "Core %d found: %s "
+			    "(cc 0x%03X, rev 0x%02X, vendor 0x%04X)\n",
+			    i, ssb_core_name(dev->id.coreid),
+			    dev->id.coreid, dev->id.revision, dev->id.vendor);
+
+		switch (dev->id.coreid) {
+		case SSB_DEV_80211:
+			nr_80211_cores++;
+			if (nr_80211_cores > 1) {
+				if (!we_support_multiple_80211_cores(bus)) {
+					ssb_dprintk(KERN_INFO PFX "Ignoring additional "
+						    "802.11 core\n");
+					continue;
+				}
+			}
+			break;
+		case SSB_DEV_EXTIF:
+#ifdef CONFIG_SSB_DRIVER_EXTIF
+			if (bus->extif.dev) {
+				ssb_printk(KERN_WARNING PFX
+					   "WARNING: Multiple EXTIFs found\n");
+				break;
+			}
+			bus->extif.dev = dev;
+#endif /* CONFIG_SSB_DRIVER_EXTIF */
+			break;
+		case SSB_DEV_CHIPCOMMON:
+			if (bus->chipco.dev) {
+				ssb_printk(KERN_WARNING PFX
+					   "WARNING: Multiple ChipCommon found\n");
+				break;
+			}
+			bus->chipco.dev = dev;
+			break;
+		case SSB_DEV_MIPS:
+		case SSB_DEV_MIPS_3302:
+#ifdef CONFIG_SSB_DRIVER_MIPS
+			if (bus->mipscore.dev) {
+				ssb_printk(KERN_WARNING PFX
+					   "WARNING: Multiple MIPS cores found\n");
+				break;
+			}
+			bus->mipscore.dev = dev;
+#endif /* CONFIG_SSB_DRIVER_MIPS */
+			break;
+		case SSB_DEV_PCI:
+		case SSB_DEV_PCIE:
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+			if (bus->pcicore.dev) {
+				ssb_printk(KERN_WARNING PFX
+					   "WARNING: Multiple PCI(E) cores found\n");
+				break;
+			}
+			bus->pcicore.dev = dev;
+#endif /* CONFIG_SSB_DRIVER_PCICORE */
+			break;
+		default:
+			break;
+		}
+
+		dev_i++;
+	}
+	bus->nr_devices = dev_i;
+
+	err = 0;
+out:
+	return err;
+err_unmap:
+	ssb_iounmap(bus);
+	goto out;
+}
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h
new file mode 100644
index 0000000..a789364
--- /dev/null
+++ b/drivers/ssb/ssb_private.h
@@ -0,0 +1,136 @@
+#ifndef LINUX_SSB_PRIVATE_H_
+#define LINUX_SSB_PRIVATE_H_
+
+#include <linux/ssb/ssb.h>
+#include <linux/types.h>
+
+
+#define PFX	"ssb: "
+
+#ifdef CONFIG_SSB_SILENT
+# define ssb_printk(fmt, x...)	do { /* nothing */ } while (0)
+#else
+# define ssb_printk		printk
+#endif /* CONFIG_SSB_SILENT */
+
+/* dprintk: Debugging printk; vanishes for non-debug compilation */
+#ifdef CONFIG_SSB_DEBUG
+# define ssb_dprintk(fmt, x...)	ssb_printk(fmt , ##x)
+#else
+# define ssb_dprintk(fmt, x...)	do { /* nothing */ } while (0)
+#endif
+
+#ifdef CONFIG_SSB_DEBUG
+# define SSB_WARN_ON(x)		WARN_ON(x)
+# define SSB_BUG_ON(x)		BUG_ON(x)
+#else
+static inline int __ssb_do_nothing(int x) { return x; }
+# define SSB_WARN_ON(x)		__ssb_do_nothing(unlikely(!!(x)))
+# define SSB_BUG_ON(x)		__ssb_do_nothing(unlikely(!!(x)))
+#endif
+
+
+/* pci.c */
+#ifdef CONFIG_SSB_PCIHOST
+extern int ssb_pci_switch_core(struct ssb_bus *bus,
+			       struct ssb_device *dev);
+extern int ssb_pci_switch_coreidx(struct ssb_bus *bus,
+				  u8 coreidx);
+extern int ssb_pci_xtal(struct ssb_bus *bus, u32 what,
+			int turn_on);
+extern int ssb_pci_get_invariants(struct ssb_bus *bus,
+				  struct ssb_init_invariants *iv);
+extern void ssb_pci_exit(struct ssb_bus *bus);
+extern int ssb_pci_init(struct ssb_bus *bus);
+extern const struct ssb_bus_ops ssb_pci_ops;
+
+#else /* CONFIG_SSB_PCIHOST */
+
+static inline int ssb_pci_switch_core(struct ssb_bus *bus,
+				      struct ssb_device *dev)
+{
+	return 0;
+}
+static inline int ssb_pci_switch_coreidx(struct ssb_bus *bus,
+					 u8 coreidx)
+{
+	return 0;
+}
+static inline int ssb_pci_xtal(struct ssb_bus *bus, u32 what,
+			       int turn_on)
+{
+	return 0;
+}
+static inline void ssb_pci_exit(struct ssb_bus *bus)
+{
+}
+static inline int ssb_pci_init(struct ssb_bus *bus)
+{
+	return 0;
+}
+#endif /* CONFIG_SSB_PCIHOST */
+
+
+/* pcmcia.c */
+#ifdef CONFIG_SSB_PCMCIAHOST
+extern int ssb_pcmcia_switch_core(struct ssb_bus *bus,
+				  struct ssb_device *dev);
+extern int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
+				     u8 coreidx);
+extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus,
+				     u8 seg);
+extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus,
+				     struct ssb_init_invariants *iv);
+extern int ssb_pcmcia_init(struct ssb_bus *bus);
+extern const struct ssb_bus_ops ssb_pcmcia_ops;
+#else /* CONFIG_SSB_PCMCIAHOST */
+static inline int ssb_pcmcia_switch_core(struct ssb_bus *bus,
+					 struct ssb_device *dev)
+{
+	return 0;
+}
+static inline int ssb_pcmcia_switch_coreidx(struct ssb_bus *bus,
+					    u8 coreidx)
+{
+	return 0;
+}
+static inline int ssb_pcmcia_switch_segment(struct ssb_bus *bus,
+					    u8 seg)
+{
+	return 0;
+}
+static inline int ssb_pcmcia_init(struct ssb_bus *bus)
+{
+	return 0;
+}
+#endif /* CONFIG_SSB_PCMCIAHOST */
+
+
+/* scan.c */
+extern const char *ssb_core_name(u16 coreid);
+extern int ssb_bus_scan(struct ssb_bus *bus,
+			unsigned long baseaddr);
+extern void ssb_iounmap(struct ssb_bus *ssb);
+
+
+/* core.c */
+extern u32 ssb_calc_clock_rate(u32 plltype, u32 n, u32 m);
+extern int ssb_devices_freeze(struct ssb_bus *bus);
+extern int ssb_devices_thaw(struct ssb_bus *bus);
+extern struct ssb_bus *ssb_pci_dev_to_bus(struct pci_dev *pdev);
+
+/* b43_pci_bridge.c */
+#ifdef CONFIG_SSB_PCIHOST
+extern int __init b43_pci_ssb_bridge_init(void);
+extern void __exit b43_pci_ssb_bridge_exit(void);
+#else /* CONFIG_SSB_PCIHOST */
+static inline int b43_pci_ssb_bridge_init(void)
+{
+	return 0;
+}
+static inline void b43_pci_ssb_bridge_exit(void)
+{
+}
+#endif /* CONFIG_SSB_PCIHOST */
+
+#endif /* LINUX_SSB_PRIVATE_H_ */
diff --git a/drivers/tc/Makefile b/drivers/tc/Makefile
index 9673426..c899246 100644
--- a/drivers/tc/Makefile
+++ b/drivers/tc/Makefile
@@ -5,7 +5,6 @@
 # Object file lists.
 
 obj-$(CONFIG_TC) += tc.o tc-driver.o
-obj-$(CONFIG_ZS) += zs.o
 obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o
 
 $(obj)/lk201-map.o: $(obj)/lk201-map.c
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c
deleted file mode 100644
index ed979f1..0000000
--- a/drivers/tc/zs.c
+++ /dev/null
@@ -1,2203 +0,0 @@
-/*
- * decserial.c: Serial port driver for IOASIC DECstations.
- *
- * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
- * Derived from drivers/macintosh/macserial.c by Harald Koerfgen.
- *
- * DECstation changes
- * Copyright (C) 1998-2000 Harald Koerfgen
- * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005  Maciej W. Rozycki
- *
- * For the rest of the code the original Copyright applies:
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- *
- *
- * Note: for IOASIC systems the wiring is as follows:
- *
- * mouse/keyboard:
- * DIN-7 MJ-4  signal        SCC
- * 2     1     TxD       <-  A.TxD
- * 3     4     RxD       ->  A.RxD
- *
- * EIA-232/EIA-423:
- * DB-25 MMJ-6 signal        SCC
- * 2     2     TxD       <-  B.TxD
- * 3     5     RxD       ->  B.RxD
- * 4           RTS       <- ~A.RTS
- * 5           CTS       -> ~B.CTS
- * 6     6     DSR       -> ~A.SYNC
- * 8           CD        -> ~B.DCD
- * 12          DSRS(DCE) -> ~A.CTS  (*)
- * 15          TxC       ->  B.TxC
- * 17          RxC       ->  B.RxC
- * 20    1     DTR       <- ~A.DTR
- * 22          RI        -> ~A.DCD
- * 23          DSRS(DTE) <- ~B.RTS
- *
- * (*) EIA-232 defines the signal at this pin to be SCD, while DSRS(DCE)
- *     is shared with DSRS(DTE) at pin 23.
- */
-
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#ifdef CONFIG_SERIAL_DEC_CONSOLE
-#include <linux/console.h>
-#endif
-
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/bootinfo.h>
-
-#include <asm/dec/interrupts.h>
-#include <asm/dec/ioasic_addrs.h>
-#include <asm/dec/machtype.h>
-#include <asm/dec/serial.h>
-#include <asm/dec/system.h>
-
-#ifdef CONFIG_KGDB
-#include <asm/kgdb.h>
-#endif
-#ifdef CONFIG_MAGIC_SYSRQ
-#include <linux/sysrq.h>
-#endif
-
-#include "zs.h"
-
-/*
- * It would be nice to dynamically allocate everything that
- * depends on NUM_SERIAL, so we could support any number of
- * Z8530s, but for now...
- */
-#define NUM_SERIAL	2		/* Max number of ZS chips supported */
-#define NUM_CHANNELS	(NUM_SERIAL * 2)	/* 2 channels per chip */
-#define CHANNEL_A_NR  (zs_parms->channel_a_offset > zs_parms->channel_b_offset)
-                                        /* Number of channel A in the chip */
-#define ZS_CHAN_IO_SIZE 8
-#define ZS_CLOCK        7372800 	/* Z8530 RTxC input clock rate */
-
-#define RECOVERY_DELAY  udelay(2)
-
-struct zs_parms {
-	unsigned long scc0;
-	unsigned long scc1;
-	int channel_a_offset;
-	int channel_b_offset;
-	int irq0;
-	int irq1;
-	int clock;
-};
-
-static struct zs_parms *zs_parms;
-
-#ifdef CONFIG_MACH_DECSTATION
-static struct zs_parms ds_parms = {
-	scc0 : IOASIC_SCC0,
-	scc1 : IOASIC_SCC1,
-	channel_a_offset : 1,
-	channel_b_offset : 9,
-	irq0 : -1,
-	irq1 : -1,
-	clock : ZS_CLOCK
-};
-#endif
-
-#ifdef CONFIG_MACH_DECSTATION
-#define DS_BUS_PRESENT (IOASIC)
-#else
-#define DS_BUS_PRESENT 0
-#endif
-
-#define BUS_PRESENT (DS_BUS_PRESENT)
-
-DEFINE_SPINLOCK(zs_lock);
-
-struct dec_zschannel zs_channels[NUM_CHANNELS];
-struct dec_serial zs_soft[NUM_CHANNELS];
-int zs_channels_found;
-struct dec_serial *zs_chain;	/* list of all channels */
-
-struct tty_struct zs_ttys[NUM_CHANNELS];
-
-#ifdef CONFIG_SERIAL_DEC_CONSOLE
-static struct console zs_console;
-#endif
-#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
-   !defined(MODULE)
-static unsigned long break_pressed; /* break, really ... */
-#endif
-
-static unsigned char zs_init_regs[16] __initdata = {
-	0,				/* write 0 */
-	0,				/* write 1 */
-	0,				/* write 2 */
-	0,				/* write 3 */
-	(X16CLK),			/* write 4 */
-	0,				/* write 5 */
-	0, 0, 0,			/* write 6, 7, 8 */
-	(MIE | DLC | NV),		/* write 9 */
-	(NRZ),				/* write 10 */
-	(TCBR | RCBR),			/* write 11 */
-	0, 0,				/* BRG time constant, write 12 + 13 */
-	(BRSRC | BRENABL),		/* write 14 */
-	0				/* write 15 */
-};
-
-static struct tty_driver *serial_driver;
-
-/* 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_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_THROTTLE
-#undef SERIAL_PARANOIA_CHECK
-
-#undef ZS_DEBUG_REGS
-
-#ifdef SERIAL_DEBUG_THROTTLE
-#define _tty_name(tty,buf) tty_name(tty,buf)
-#endif
-
-#define RS_STROBE_TIME 10
-#define RS_ISR_PASS_LIMIT 256
-
-static void probe_sccs(void);
-static void change_speed(struct dec_serial *info);
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
-
-static inline int serial_paranoia_check(struct dec_serial *info,
-					char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
-	static const char *badmagic =
-		"Warning: bad magic number for serial struct %s in %s\n";
-	static const char *badinfo =
-		"Warning: null 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;
-}
-
-/*
- * This is used to figure out the divisor speeds and the timeouts
- */
-static int baud_table[] = {
-	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
-	9600, 19200, 38400, 57600, 115200, 0 };
-
-/*
- * Reading and writing Z8530 registers.
- */
-static inline unsigned char read_zsreg(struct dec_zschannel *channel,
-				       unsigned char reg)
-{
-	unsigned char retval;
-
-	if (reg != 0) {
-		*channel->control = reg & 0xf;
-		fast_iob(); RECOVERY_DELAY;
-	}
-	retval = *channel->control;
-	RECOVERY_DELAY;
-	return retval;
-}
-
-static inline void write_zsreg(struct dec_zschannel *channel,
-			       unsigned char reg, unsigned char value)
-{
-	if (reg != 0) {
-		*channel->control = reg & 0xf;
-		fast_iob(); RECOVERY_DELAY;
-	}
-	*channel->control = value;
-	fast_iob(); RECOVERY_DELAY;
-	return;
-}
-
-static inline unsigned char read_zsdata(struct dec_zschannel *channel)
-{
-	unsigned char retval;
-
-	retval = *channel->data;
-	RECOVERY_DELAY;
-	return retval;
-}
-
-static inline void write_zsdata(struct dec_zschannel *channel,
-				unsigned char value)
-{
-	*channel->data = value;
-	fast_iob(); RECOVERY_DELAY;
-	return;
-}
-
-static inline void load_zsregs(struct dec_zschannel *channel,
-			       unsigned char *regs)
-{
-/*	ZS_CLEARERR(channel);
-	ZS_CLEARFIFO(channel); */
-	/* Load 'em up */
-	write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
-	write_zsreg(channel, R5, regs[R5] & ~TxENAB);
-	write_zsreg(channel, R4, regs[R4]);
-	write_zsreg(channel, R9, regs[R9]);
-	write_zsreg(channel, R1, regs[R1]);
-	write_zsreg(channel, R2, regs[R2]);
-	write_zsreg(channel, R10, regs[R10]);
-	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 dec_serial *info, int which, int set)
-{
-        unsigned long flags;
-
-	spin_lock_irqsave(&zs_lock, flags);
-	if (info->zs_channel != info->zs_chan_a) {
-		if (set) {
-			info->zs_chan_a->curregs[5] |= (which & (RTS | DTR));
-		} else {
-			info->zs_chan_a->curregs[5] &= ~(which & (RTS | DTR));
-		}
-		write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
-	}
-	spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-/* Utility routines for the Zilog */
-static inline int get_zsbaud(struct dec_serial *ss)
-{
-	struct dec_zschannel *channel = ss->zs_channel;
-	int brg;
-
-	/* The baud rate is split up between two 8-bit registers in
-	 * what is termed 'BRG time constant' format in my docs for
-	 * the chip, it is a function of the clk rate the chip is
-	 * receiving which happens to be constant.
-	 */
-	brg = (read_zsreg(channel, 13) << 8);
-	brg |= read_zsreg(channel, 12);
-	return BRG_TO_BPS(brg, (zs_parms->clock/(ss->clk_divisor)));
-}
-
-/* On receive, this clears errors and the receiver interrupts */
-static inline void rs_recv_clear(struct dec_zschannel *zsc)
-{
-	write_zsreg(zsc, 0, ERR_RES);
-	write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines.  All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt().  They were separated out for readability's sake.
- *
- * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- */
-static void rs_sched_event(struct dec_serial *info, int event)
-{
-	info->event |= 1 << event;
-	tasklet_schedule(&info->tlet);
-}
-
-static void receive_chars(struct dec_serial *info)
-{
-	struct tty_struct *tty = info->tty;
-	unsigned char ch, stat, flag;
-
-	while ((read_zsreg(info->zs_channel, R0) & Rx_CH_AV) != 0) {
-
-		stat = read_zsreg(info->zs_channel, R1);
-		ch = read_zsdata(info->zs_channel);
-
-		if (!tty && (!info->hook || !info->hook->rx_char))
-			continue;
-
-		flag = TTY_NORMAL;
-		if (info->tty_break) {
-			info->tty_break = 0;
-			flag = TTY_BREAK;
-			if (info->flags & ZILOG_SAK)
-				do_SAK(tty);
-			/* Ignore the null char got when BREAK is removed.  */
-			if (ch == 0)
-				continue;
-		} else {
-			if (stat & Rx_OVR) {
-				flag = TTY_OVERRUN;
-			} else if (stat & FRM_ERR) {
-				flag = TTY_FRAME;
-			} else if (stat & PAR_ERR) {
-				flag = TTY_PARITY;
-			}
-			if (flag != TTY_NORMAL)
-				/* reset the error indication */
-				write_zsreg(info->zs_channel, R0, ERR_RES);
-		}
-
-#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
-   !defined(MODULE)
-		if (break_pressed && info->line == zs_console.index) {
-			/* Ignore the null char got when BREAK is removed.  */
-			if (ch == 0)
-				continue;
-			if (time_before(jiffies, break_pressed + HZ * 5)) {
-				handle_sysrq(ch, NULL);
-				break_pressed = 0;
-				continue;
-			}
-			break_pressed = 0;
-		}
-#endif
-
-		if (info->hook && info->hook->rx_char) {
-			(*info->hook->rx_char)(ch, flag);
-			return;
-  		}
-
-		tty_insert_flip_char(tty, ch, flag);
-	}
-	if (tty)
-		tty_flip_buffer_push(tty);
-}
-
-static void transmit_chars(struct dec_serial *info)
-{
-	if ((read_zsreg(info->zs_channel, R0) & Tx_BUF_EMP) == 0)
-		return;
-	info->tx_active = 0;
-
-	if (info->x_char) {
-		/* 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 && info->tty->stopped)
-	    || info->tx_stopped) {
-		write_zsreg(info->zs_channel, R0, 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 status_handle(struct dec_serial *info)
-{
-	unsigned char stat;
-
-	/* Get status from Read Register 0 */
-	stat = read_zsreg(info->zs_channel, R0);
-
-	if ((stat & BRK_ABRT) && !(info->read_reg_zero & BRK_ABRT)) {
-#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
-   !defined(MODULE)
-		if (info->line == zs_console.index) {
-			if (!break_pressed)
-				break_pressed = jiffies;
-		} else
-#endif
-			info->tty_break = 1;
-	}
-
-	if (info->zs_channel != info->zs_chan_a) {
-
-		/* Check for DCD transitions */
-		if (info->tty && !C_CLOCAL(info->tty) &&
-		    ((stat ^ info->read_reg_zero) & DCD) != 0 ) {
-			if (stat & DCD) {
-				wake_up_interruptible(&info->open_wait);
-			} else {
-				tty_hangup(info->tty);
-			}
-		}
-
-		/* Check for CTS transitions */
-		if (info->tty && C_CRTSCTS(info->tty)) {
-			if ((stat & CTS) != 0) {
-				if (info->tx_stopped) {
-					info->tx_stopped = 0;
-					if (!info->tx_active)
-						transmit_chars(info);
-				}
-			} else {
-				info->tx_stopped = 1;
-			}
-		}
-
-	}
-
-	/* Clear status condition... */
-	write_zsreg(info->zs_channel, R0, RES_EXT_INT);
-	info->read_reg_zero = stat;
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-static irqreturn_t rs_interrupt(int irq, void *dev_id)
-{
-	struct dec_serial *info = (struct dec_serial *) dev_id;
-	irqreturn_t status = IRQ_NONE;
-	unsigned char zs_intreg;
-	int shift;
-
-	/* NOTE: The read register 3, which holds the irq status,
-	 *       does so for both channels on each chip.  Although
-	 *       the status value itself must be read from the A
-	 *       channel and is only valid when read from channel A.
-	 *       Yes... broken hardware...
-	 */
-#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
-
-	if (info->zs_chan_a == info->zs_channel)
-		shift = 3;	/* Channel A */
-	else
-		shift = 0;	/* Channel B */
-
-	for (;;) {
-		zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift;
-		if ((zs_intreg & CHAN_IRQMASK) == 0)
-			break;
-
-		status = IRQ_HANDLED;
-
-		if (zs_intreg & CHBRxIP) {
-			receive_chars(info);
-		}
-		if (zs_intreg & CHBTxIP) {
-			transmit_chars(info);
-		}
-		if (zs_intreg & CHBEXT) {
-			status_handle(info);
-		}
-	}
-
-	/* Why do we need this ? */
-	write_zsreg(info->zs_channel, 0, RES_H_IUS);
-
-	return status;
-}
-
-#ifdef ZS_DEBUG_REGS
-void zs_dump (void) {
-	int i, j;
-	for (i = 0; i < zs_channels_found; i++) {
-		struct dec_zschannel *ch = &zs_channels[i];
-		if ((long)ch->control == UNI_IO_BASE+UNI_SCC1A_CTRL) {
-			for (j = 0; j < 15; j++) {
-				printk("W%d = 0x%x\t",
-				       j, (int)ch->curregs[j]);
-			}
-			for (j = 0; j < 15; j++) {
-				printk("R%d = 0x%x\t",
-				       j, (int)read_zsreg(ch,j));
-			}
-			printk("\n\n");
-		}
-	}
-}
-#endif
-
-/*
- * -------------------------------------------------------------------
- * 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 dec_serial *info = (struct dec_serial *)tty->driver_data;
-	unsigned long flags;
-
-	if (serial_paranoia_check(info, tty->name, "rs_stop"))
-		return;
-
-#if 1
-	spin_lock_irqsave(&zs_lock, flags);
-	if (info->zs_channel->curregs[5] & TxENAB) {
-		info->zs_channel->curregs[5] &= ~TxENAB;
-		write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
-	}
-	spin_unlock_irqrestore(&zs_lock, flags);
-#endif
-}
-
-static void rs_start(struct tty_struct *tty)
-{
-	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-	unsigned long flags;
-
-	if (serial_paranoia_check(info, tty->name, "rs_start"))
-		return;
-
-	spin_lock_irqsave(&zs_lock, flags);
-#if 1
-	if (info->xmit_cnt && info->xmit_buf && !(info->zs_channel->curregs[5] & TxENAB)) {
-		info->zs_channel->curregs[5] |= TxENAB;
-		write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
-	}
-#else
-	if (info->xmit_cnt && info->xmit_buf && !info->tx_active) {
-		transmit_chars(info);
-	}
-#endif
-	spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using rs_sched_event(), and they get done here.
- */
-
-static void do_softint(unsigned long private_)
-{
-	struct dec_serial	*info = (struct dec_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 zs_startup(struct dec_serial * info)
-{
-	unsigned long flags;
-
-	if (info->flags & ZILOG_INITIALIZED)
-		return 0;
-
-	if (!info->xmit_buf) {
-		info->xmit_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
-		if (!info->xmit_buf)
-			return -ENOMEM;
-	}
-
-	spin_lock_irqsave(&zs_lock, flags);
-
-#ifdef SERIAL_DEBUG_OPEN
-	printk("starting up ttyS%d (irq %d)...", info->line, info->irq);
-#endif
-
-	/*
-	 * Clear the receive FIFO.
-	 */
-	ZS_CLEARFIFO(info->zs_channel);
-	info->xmit_fifo_size = 1;
-
-	/*
-	 * Clear the interrupt registers.
-	 */
-	write_zsreg(info->zs_channel, R0, ERR_RES);
-	write_zsreg(info->zs_channel, R0, RES_H_IUS);
-
-	/*
-	 * Set the speed of the serial port
-	 */
-	change_speed(info);
-
-	/*
-	 * Turn on RTS and DTR.
-	 */
-	zs_rtsdtr(info, RTS | DTR, 1);
-
-	/*
-	 * Finally, enable sequencing and interrupts
-	 */
-	info->zs_channel->curregs[R1] &= ~RxINT_MASK;
-	info->zs_channel->curregs[R1] |= (RxINT_ALL | TxINT_ENAB |
-					  EXT_INT_ENAB);
-	info->zs_channel->curregs[R3] |= RxENABLE;
-	info->zs_channel->curregs[R5] |= TxENAB;
-	info->zs_channel->curregs[R15] |= (DCDIE | CTSIE | TxUIE | BRKIE);
-	write_zsreg(info->zs_channel, R1, info->zs_channel->curregs[R1]);
-	write_zsreg(info->zs_channel, R3, info->zs_channel->curregs[R3]);
-	write_zsreg(info->zs_channel, R5, info->zs_channel->curregs[R5]);
-	write_zsreg(info->zs_channel, R15, info->zs_channel->curregs[R15]);
-
-	/*
-	 * And clear the interrupt registers again for luck.
-	 */
-	write_zsreg(info->zs_channel, R0, ERR_RES);
-	write_zsreg(info->zs_channel, R0, RES_H_IUS);
-
-	/* Save the current value of RR0 */
-	info->read_reg_zero = read_zsreg(info->zs_channel, R0);
-
-	if (info->tty)
-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
-	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
-	info->flags |= ZILOG_INITIALIZED;
-	spin_unlock_irqrestore(&zs_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 dec_serial * info)
-{
-	unsigned long	flags;
-
-	if (!(info->flags & ZILOG_INITIALIZED))
-		return;
-
-#ifdef SERIAL_DEBUG_OPEN
-	printk("Shutting down serial port %d (irq %d)....", info->line,
-	       info->irq);
-#endif
-
-	spin_lock_irqsave(&zs_lock, flags);
-
-	if (info->xmit_buf) {
-		free_page((unsigned long) info->xmit_buf);
-		info->xmit_buf = 0;
-	}
-
-	info->zs_channel->curregs[1] = 0;
-	write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]);	/* no interrupts */
-
-	info->zs_channel->curregs[3] &= ~RxENABLE;
-	write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
-
-	info->zs_channel->curregs[5] &= ~TxENAB;
-	write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
-	if (!info->tty || C_HUPCL(info->tty)) {
-		zs_rtsdtr(info, RTS | DTR, 0);
-	}
-
-	if (info->tty)
-		set_bit(TTY_IO_ERROR, &info->tty->flags);
-
-	info->flags &= ~ZILOG_INITIALIZED;
-	spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(struct dec_serial *info)
-{
-	unsigned cflag;
-	int	i;
-	int	brg, bits;
-	unsigned long flags;
-
-	if (!info->hook) {
-		if (!info->tty || !info->tty->termios)
-			return;
-		cflag = info->tty->termios->c_cflag;
-		if (!info->port)
-			return;
-	} else {
-		cflag = info->hook->cflags;
-	}
-
-	i = cflag & CBAUD;
-	if (i & CBAUDEX) {
-		i &= ~CBAUDEX;
-		if (i < 1 || i > 2) {
-			if (!info->hook)
-				info->tty->termios->c_cflag &= ~CBAUDEX;
-			else
-				info->hook->cflags &= ~CBAUDEX;
-		} else
-			i += 15;
-	}
-
-	spin_lock_irqsave(&zs_lock, flags);
-	info->zs_baud = baud_table[i];
-	if (info->zs_baud) {
-		brg = BPS_TO_BRG(info->zs_baud, zs_parms->clock/info->clk_divisor);
-		info->zs_channel->curregs[12] = (brg & 255);
-		info->zs_channel->curregs[13] = ((brg >> 8) & 255);
-		zs_rtsdtr(info, DTR, 1);
-	} else {
-		zs_rtsdtr(info, RTS | DTR, 0);
-		return;
-	}
-
-	/* byte size and parity */
-	info->zs_channel->curregs[3] &= ~RxNBITS_MASK;
-	info->zs_channel->curregs[5] &= ~TxNBITS_MASK;
-	switch (cflag & CSIZE) {
-	case CS5:
-		bits = 7;
-		info->zs_channel->curregs[3] |= Rx5;
-		info->zs_channel->curregs[5] |= Tx5;
-		break;
-	case CS6:
-		bits = 8;
-		info->zs_channel->curregs[3] |= Rx6;
-		info->zs_channel->curregs[5] |= Tx6;
-		break;
-	case CS7:
-		bits = 9;
-		info->zs_channel->curregs[3] |= Rx7;
-		info->zs_channel->curregs[5] |= Tx7;
-		break;
-	case CS8:
-	default: /* defaults to 8 bits */
-		bits = 10;
-		info->zs_channel->curregs[3] |= Rx8;
-		info->zs_channel->curregs[5] |= Tx8;
-		break;
-	}
-
-	info->timeout = ((info->xmit_fifo_size*HZ*bits) / info->zs_baud);
-        info->timeout += HZ/50;         /* Add .02 seconds of slop */
-
-	info->zs_channel->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
-	if (cflag & CSTOPB) {
-		info->zs_channel->curregs[4] |= SB2;
-	} else {
-		info->zs_channel->curregs[4] |= SB1;
-	}
-	if (cflag & PARENB) {
-		info->zs_channel->curregs[4] |= PAR_ENA;
-	}
-	if (!(cflag & PARODD)) {
-		info->zs_channel->curregs[4] |= PAR_EVEN;
-	}
-
-	if (!(cflag & CLOCAL)) {
-		if (!(info->zs_channel->curregs[15] & DCDIE))
-			info->read_reg_zero = read_zsreg(info->zs_channel, 0);
-		info->zs_channel->curregs[15] |= DCDIE;
-	} else
-		info->zs_channel->curregs[15] &= ~DCDIE;
-	if (cflag & CRTSCTS) {
-		info->zs_channel->curregs[15] |= CTSIE;
-		if ((read_zsreg(info->zs_channel, 0) & CTS) == 0)
-			info->tx_stopped = 1;
-	} else {
-		info->zs_channel->curregs[15] &= ~CTSIE;
-		info->tx_stopped = 0;
-	}
-
-	/* Load up the new values */
-	load_zsregs(info->zs_channel, info->zs_channel->curregs);
-
-	spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
-	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-	unsigned long flags;
-
-	if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
-		return;
-
-	if (info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped ||
-	    !info->xmit_buf)
-		return;
-
-	/* Enable transmitter */
-	spin_lock_irqsave(&zs_lock, flags);
-	transmit_chars(info);
-	spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-static int rs_write(struct tty_struct * tty,
-		    const unsigned char *buf, int count)
-{
-	int	c, total = 0;
-	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-	unsigned long flags;
-
-	if (serial_paranoia_check(info, tty->name, "rs_write"))
-		return 0;
-
-	if (!tty || !info->xmit_buf)
-		return 0;
-
-	while (1) {
-		spin_lock_irqsave(&zs_lock, flags);
-		c = min(count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-				   SERIAL_XMIT_SIZE - info->xmit_head));
-		if (c <= 0)
-			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(&zs_lock, flags);
-		buf += c;
-		count -= c;
-		total += c;
-	}
-
-	if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
-	    && !info->tx_active)
-		transmit_chars(info);
-	spin_unlock_irqrestore(&zs_lock, flags);
-	return total;
-}
-
-static int rs_write_room(struct tty_struct *tty)
-{
-	struct dec_serial *info = (struct dec_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 dec_serial *info = (struct dec_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 dec_serial *info = (struct dec_serial *)tty->driver_data;
-
-	if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
-		return;
-	spin_lock_irq(&zs_lock);
-	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-	spin_unlock_irq(&zs_lock);
-	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 dec_serial *info = (struct dec_serial *)tty->driver_data;
-	unsigned long flags;
-
-#ifdef SERIAL_DEBUG_THROTTLE
-	char	buf[64];
-
-	printk("throttle %s: %d....\n", _tty_name(tty, buf),
-	       tty->ldisc.chars_in_buffer(tty));
-#endif
-
-	if (serial_paranoia_check(info, tty->name, "rs_throttle"))
-		return;
-
-	if (I_IXOFF(tty)) {
-		spin_lock_irqsave(&zs_lock, flags);
-		info->x_char = STOP_CHAR(tty);
-		if (!info->tx_active)
-			transmit_chars(info);
-		spin_unlock_irqrestore(&zs_lock, flags);
-	}
-
-	if (C_CRTSCTS(tty)) {
-		zs_rtsdtr(info, RTS, 0);
-	}
-}
-
-static void rs_unthrottle(struct tty_struct * tty)
-{
-	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-	unsigned long flags;
-
-#ifdef SERIAL_DEBUG_THROTTLE
-	char	buf[64];
-
-	printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
-	       tty->ldisc.chars_in_buffer(tty));
-#endif
-
-	if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
-		return;
-
-	if (I_IXOFF(tty)) {
-		spin_lock_irqsave(&zs_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(&zs_lock, flags);
-	}
-
-	if (C_CRTSCTS(tty)) {
-		zs_rtsdtr(info, RTS, 1);
-	}
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct dec_serial * info,
-			   struct serial_struct * 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;
-	return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0;
-}
-
-static int set_serial_info(struct dec_serial * info,
-			   struct serial_struct * new_info)
-{
-	struct serial_struct new_serial;
-	struct dec_serial old_info;
-	int 			retval = 0;
-
-	if (!new_info)
-		return -EFAULT;
-	copy_from_user(&new_serial,new_info,sizeof(new_serial));
-	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:
-	retval = zs_startup(info);
-	return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * 	    is emptied.  On bus types like RS485, the transmitter must
- * 	    release the bus after transmitting. This must be done when
- * 	    the transmit shift register is empty, not be done when the
- * 	    transmit holding register is empty.  This functionality
- * 	    allows an RS485 driver to be written in user space.
- */
-static int get_lsr_info(struct dec_serial * info, unsigned int *value)
-{
-	unsigned char status;
-
-	spin_lock(&zs_lock);
-	status = read_zsreg(info->zs_channel, 0);
-	spin_unlock_irq(&zs_lock);
-	put_user(status,value);
-	return 0;
-}
-
-static int rs_tiocmget(struct tty_struct *tty, struct file *file)
-{
-	struct dec_serial * info = (struct dec_serial *)tty->driver_data;
-	unsigned char control, status_a, status_b;
-	unsigned int result;
-
-	if (info->hook)
-		return -ENODEV;
-
-	if (serial_paranoia_check(info, tty->name, __FUNCTION__))
-		return -ENODEV;
-
-	if (tty->flags & (1 << TTY_IO_ERROR))
-		return -EIO;
-
-	if (info->zs_channel == info->zs_chan_a)
-		result = 0;
-	else {
-		spin_lock(&zs_lock);
-		control = info->zs_chan_a->curregs[5];
-		status_a = read_zsreg(info->zs_chan_a, 0);
-		status_b = read_zsreg(info->zs_channel, 0);
-		spin_unlock_irq(&zs_lock);
-		result =  ((control  & RTS) ? TIOCM_RTS: 0)
-			| ((control  & DTR) ? TIOCM_DTR: 0)
-			| ((status_b & DCD) ? TIOCM_CAR: 0)
-			| ((status_a & DCD) ? TIOCM_RNG: 0)
-			| ((status_a & SYNC_HUNT) ? TIOCM_DSR: 0)
-			| ((status_b & CTS) ? TIOCM_CTS: 0);
-	}
-	return result;
-}
-
-static int rs_tiocmset(struct tty_struct *tty, struct file *file,
-                       unsigned int set, unsigned int clear)
-{
-	struct dec_serial * info = (struct dec_serial *)tty->driver_data;
-
-	if (info->hook)
-		return -ENODEV;
-
-	if (serial_paranoia_check(info, tty->name, __FUNCTION__))
-		return -ENODEV;
-
-	if (tty->flags & (1 << TTY_IO_ERROR))
-		return -EIO;
-
-	if (info->zs_channel == info->zs_chan_a)
-		return 0;
-
-	spin_lock(&zs_lock);
-	if (set & TIOCM_RTS)
-		info->zs_chan_a->curregs[5] |= RTS;
-	if (set & TIOCM_DTR)
-		info->zs_chan_a->curregs[5] |= DTR;
-	if (clear & TIOCM_RTS)
-		info->zs_chan_a->curregs[5] &= ~RTS;
-	if (clear & TIOCM_DTR)
-		info->zs_chan_a->curregs[5] &= ~DTR;
-	write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);
-	spin_unlock_irq(&zs_lock);
-	return 0;
-}
-
-/*
- * rs_break - turn transmit break condition on/off
- */
-static void rs_break(struct tty_struct *tty, int break_state)
-{
-	struct dec_serial *info = (struct dec_serial *) tty->driver_data;
-	unsigned long flags;
-
-	if (serial_paranoia_check(info, tty->name, "rs_break"))
-		return;
-	if (!info->port)
-		return;
-
-	spin_lock_irqsave(&zs_lock, flags);
-	if (break_state == -1)
-		info->zs_channel->curregs[5] |= SND_BRK;
-	else
-		info->zs_channel->curregs[5] &= ~SND_BRK;
-	write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
-	spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-static int rs_ioctl(struct tty_struct *tty, struct file * file,
-		    unsigned int cmd, unsigned long arg)
-{
-	struct dec_serial * info = (struct dec_serial *)tty->driver_data;
-
-	if (info->hook)
-		return -ENODEV;
-
-	if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
-		return -ENODEV;
-
-	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
-	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
-	    (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
-		if (tty->flags & (1 << TTY_IO_ERROR))
-		    return -EIO;
-	}
-
-	switch (cmd) {
-	case TIOCGSERIAL:
-		if (!access_ok(VERIFY_WRITE, (void *)arg,
-			       sizeof(struct serial_struct)))
-			return -EFAULT;
-		return get_serial_info(info, (struct serial_struct *)arg);
-
-	case TIOCSSERIAL:
-		return set_serial_info(info, (struct serial_struct *)arg);
-
-	case TIOCSERGETLSR:			/* Get line status register */
-		if (!access_ok(VERIFY_WRITE, (void *)arg,
-			       sizeof(unsigned int)))
-			return -EFAULT;
-		return get_lsr_info(info, (unsigned int *)arg);
-
-	case TIOCSERGSTRUCT:
-		if (!access_ok(VERIFY_WRITE, (void *)arg,
-			       sizeof(struct dec_serial)))
-			return -EFAULT;
-		copy_from_user((struct dec_serial *)arg, info,
-			       sizeof(struct dec_serial));
-		return 0;
-
-	default:
-		return -ENOIOCTLCMD;
-	}
-	return 0;
-}
-
-static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
-{
-	struct dec_serial *info = (struct dec_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);
-
-	if (was_stopped && !info->tx_stopped)
-		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 dec_serial * info = (struct dec_serial *)tty->driver_data;
-	unsigned long flags;
-
-	if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
-		return;
-
-	spin_lock_irqsave(&zs_lock, flags);
-
-	if (tty_hung_up_p(filp)) {
-		spin_unlock_irqrestore(&zs_lock, flags);
-		return;
-	}
-
-#ifdef SERIAL_DEBUG_OPEN
-	printk("rs_close ttyS%d, count = %d\n", info->line, info->count);
-#endif
-	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("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("rs_close: bad serial port count for ttyS%d: %d\n",
-		       info->line, info->count);
-		info->count = 0;
-	}
-	if (info->count) {
-		spin_unlock_irqrestore(&zs_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.
-	 */
-	tty->closing = 1;
-	if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE)
-		tty_wait_until_sent(tty, info->closing_wait);
-	/*
-	 * At this point we stop accepting input.  To do this, we
-	 * disable the receiver and receive interrupts.
-	 */
-	info->zs_channel->curregs[3] &= ~RxENABLE;
-	write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
-	info->zs_channel->curregs[1] = 0;	/* disable any rx ints */
-	write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]);
-	ZS_CLEARFIFO(info->zs_channel);
-	if (info->flags & ZILOG_INITIALIZED) {
-		/*
-		 * Before we drop DTR, make sure the SCC transmitter
-		 * has completely drained.
-		 */
-		rs_wait_until_sent(tty, info->timeout);
-	}
-
-	shutdown(info);
-	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);
-	spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
-	struct dec_serial *info = (struct dec_serial *) tty->driver_data;
-	unsigned long orig_jiffies;
-	int char_time;
-
-	if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
-		return;
-
-	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.
-	 */
-	char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
-	char_time = char_time / 5;
-	if (char_time == 0)
-		char_time = 1;
-	if (timeout)
-		char_time = min(char_time, timeout);
-	while ((read_zsreg(info->zs_channel, 1) & Tx_BUF_EMP) == 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 dec_serial * info = (struct dec_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 dec_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);
-#ifdef SERIAL_DO_RESTART
-		return ((info->flags & ZILOG_HUP_NOTIFY) ?
-			-EAGAIN : -ERESTARTSYS);
-#else
-		return -EAGAIN;
-#endif
-	}
-
-	/*
-	 * 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);
-#ifdef SERIAL_DEBUG_OPEN
-	printk("block_til_ready before block: ttyS%d, count = %d\n",
-	       info->line, info->count);
-#endif
-	spin_lock(&zs_lock);
-	if (!tty_hung_up_p(filp))
-		info->count--;
-	spin_unlock_irq(&zs_lock);
-	info->blocked_open++;
-	while (1) {
-		spin_lock(&zs_lock);
-		if (tty->termios->c_cflag & CBAUD)
-			zs_rtsdtr(info, RTS | DTR, 1);
-		spin_unlock_irq(&zs_lock);
-		set_current_state(TASK_INTERRUPTIBLE);
-		if (tty_hung_up_p(filp) ||
-		    !(info->flags & ZILOG_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
-			if (info->flags & ZILOG_HUP_NOTIFY)
-				retval = -EAGAIN;
-			else
-				retval = -ERESTARTSYS;
-#else
-			retval = -EAGAIN;
-#endif
-			break;
-		}
-		if (!(info->flags & ZILOG_CLOSING) &&
-		    (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD)))
-			break;
-		if (signal_pending(current)) {
-			retval = -ERESTARTSYS;
-			break;
-		}
-#ifdef SERIAL_DEBUG_OPEN
-		printk("block_til_ready blocking: ttyS%d, count = %d\n",
-		       info->line, info->count);
-#endif
-		schedule();
-	}
-	current->state = TASK_RUNNING;
-	remove_wait_queue(&info->open_wait, &wait);
-	if (!tty_hung_up_p(filp))
-		info->count++;
-	info->blocked_open--;
-#ifdef SERIAL_DEBUG_OPEN
-	printk("block_til_ready after blocking: ttyS%d, count = %d\n",
-	       info->line, info->count);
-#endif
-	if (retval)
-		return retval;
-	info->flags |= ZILOG_NORMAL_ACTIVE;
-	return 0;
-}
-
-/*
- * This routine is called whenever a serial port is opened.  It
- * 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 dec_serial	*info;
-	int 			retval, line;
-
-	line = tty->index;
-	if ((line < 0) || (line >= zs_channels_found))
-		return -ENODEV;
-	info = zs_soft + line;
-
-	if (info->hook)
-		return -ENODEV;
-
-	if (serial_paranoia_check(info, tty->name, "rs_open"))
-		return -ENODEV;
-#ifdef SERIAL_DEBUG_OPEN
-	printk("rs_open %s, count = %d\n", tty->name, info->count);
-#endif
-
-	info->count++;
-	tty->driver_data = info;
-	info->tty = tty;
-
-	/*
-	 * 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);
-#ifdef SERIAL_DO_RESTART
-		return ((info->flags & ZILOG_HUP_NOTIFY) ?
-			-EAGAIN : -ERESTARTSYS);
-#else
-		return -EAGAIN;
-#endif
-	}
-
-	/*
-	 * Start up serial port
-	 */
-	retval = zs_startup(info);
-	if (retval)
-		return retval;
-
-	retval = block_til_ready(tty, filp, info);
-	if (retval) {
-#ifdef SERIAL_DEBUG_OPEN
-		printk("rs_open returning after block_til_ready with %d\n",
-		       retval);
-#endif
-		return retval;
-	}
-
-#ifdef CONFIG_SERIAL_DEC_CONSOLE
-	if (zs_console.cflag && zs_console.index == line) {
-		tty->termios->c_cflag = zs_console.cflag;
-		zs_console.cflag = 0;
-		change_speed(info);
-	}
-#endif
-
-#ifdef SERIAL_DEBUG_OPEN
-	printk("rs_open %s successful...", tty->name);
-#endif
-/* tty->low_latency = 1; */
-	return 0;
-}
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void __init show_serial_version(void)
-{
-	printk("DECstation Z8530 serial driver version 0.09\n");
-}
-
-/*  Initialize Z8530s zs_channels
- */
-
-static void __init probe_sccs(void)
-{
-	struct dec_serial **pp;
-	int i, n, n_chips = 0, n_channels, chip, channel;
-	unsigned long flags;
-
-	/*
-	 * did we get here by accident?
-	 */
-	if(!BUS_PRESENT) {
-		printk("Not on JUNKIO machine, skipping probe_sccs\n");
-		return;
-	}
-
-	switch(mips_machtype) {
-#ifdef CONFIG_MACH_DECSTATION
-	case MACH_DS5000_2X0:
-	case MACH_DS5900:
-		n_chips = 2;
-		zs_parms = &ds_parms;
-		zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
-		zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
-		break;
-	case MACH_DS5000_1XX:
-		n_chips = 2;
-		zs_parms = &ds_parms;
-		zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
-		zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
-		break;
-	case MACH_DS5000_XX:
-		n_chips = 1;
-		zs_parms = &ds_parms;
-		zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
-		break;
-#endif
-	default:
-		panic("zs: unsupported bus");
-	}
-	if (!zs_parms)
-		panic("zs: uninitialized parms");
-
-	pp = &zs_chain;
-
-	n_channels = 0;
-
-	for (chip = 0; chip < n_chips; chip++) {
-		for (channel = 0; channel <= 1; channel++) {
-			/*
-			 * The sccs reside on the high byte of the 16 bit IOBUS
-			 */
-			zs_channels[n_channels].control =
-				(volatile void *)CKSEG1ADDR(dec_kn_slot_base +
-			  (0 == chip ? zs_parms->scc0 : zs_parms->scc1) +
-			  (0 == channel ? zs_parms->channel_a_offset :
-			                  zs_parms->channel_b_offset));
-			zs_channels[n_channels].data =
-				zs_channels[n_channels].control + 4;
-
-#ifndef CONFIG_SERIAL_DEC_CONSOLE
-			/*
-			 * We're called early and memory managment isn't up, yet.
-			 * Thus request_region would fail.
-			 */
-			if (!request_region((unsigned long)
-					 zs_channels[n_channels].control,
-					 ZS_CHAN_IO_SIZE, "SCC"))
-				panic("SCC I/O region is not free");
-#endif
-			zs_soft[n_channels].zs_channel = &zs_channels[n_channels];
-			/* HACK alert! */
-			if (!(chip & 1))
-				zs_soft[n_channels].irq = zs_parms->irq0;
-			else
-				zs_soft[n_channels].irq = zs_parms->irq1;
-
-			/*
-			 *  Identification of channel A. Location of channel A
-                         *  inside chip depends on mapping of internal address
-			 *  the chip decodes channels by.
-			 *  CHANNEL_A_NR returns either 0 (in case of
-			 *  DECstations) or 1 (in case of Baget).
-			 */
-			if (CHANNEL_A_NR == channel)
-				zs_soft[n_channels].zs_chan_a =
-				    &zs_channels[n_channels+1-2*CHANNEL_A_NR];
-			else
-				zs_soft[n_channels].zs_chan_a =
-				    &zs_channels[n_channels];
-
-			*pp = &zs_soft[n_channels];
-			pp = &zs_soft[n_channels].zs_next;
-			n_channels++;
-		}
-	}
-
-	*pp = 0;
-	zs_channels_found = n_channels;
-
-	for (n = 0; n < zs_channels_found; n++) {
-		for (i = 0; i < 16; i++) {
-			zs_soft[n].zs_channel->curregs[i] = zs_init_regs[i];
-		}
-	}
-
-	spin_lock_irqsave(&zs_lock, flags);
-	for (n = 0; n < zs_channels_found; n++) {
-		if (n % 2 == 0) {
-			write_zsreg(zs_soft[n].zs_chan_a, R9, FHWRES);
-			udelay(10);
-			write_zsreg(zs_soft[n].zs_chan_a, R9, 0);
-		}
-		load_zsregs(zs_soft[n].zs_channel,
-			    zs_soft[n].zs_channel->curregs);
-	}
-	spin_unlock_irqrestore(&zs_lock, flags);
-}
-
-static const 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,
-	.tiocmget = rs_tiocmget,
-	.tiocmset = rs_tiocmset,
-};
-
-/* zs_init inits the driver */
-int __init zs_init(void)
-{
-	int channel, i;
-	struct dec_serial *info;
-
-	if(!BUS_PRESENT)
-		return -ENODEV;
-
-	/* 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;
-
-	show_serial_version();
-
-	/* Initialize the tty_driver structure */
-	/* Not all of this is exactly right for us. */
-
-	serial_driver->owner = THIS_MODULE;
-	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 =
-		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-	serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-	tty_set_operations(serial_driver, &serial_ops);
-
-	if (tty_register_driver(serial_driver))
-		panic("Couldn't register serial driver");
-
-	for (info = zs_chain, i = 0; info; info = info->zs_next, i++) {
-
-		/* Needed before interrupts are enabled. */
-		info->tty = 0;
-		info->x_char = 0;
-
-		if (info->hook && info->hook->init_info) {
-			(*info->hook->init_info)(info);
-			continue;
-		}
-
-		info->magic = SERIAL_MAGIC;
-		info->port = (int) info->zs_channel->control;
-		info->line = i;
-		info->custom_divisor = 16;
-		info->close_delay = 50;
-		info->closing_wait = 3000;
-		info->event = 0;
-		info->count = 0;
-		info->blocked_open = 0;
-		tasklet_init(&info->tlet, do_softint, (unsigned long)info);
-		init_waitqueue_head(&info->open_wait);
-		init_waitqueue_head(&info->close_wait);
-		printk("ttyS%02d at 0x%08x (irq = %d) is a Z85C30 SCC\n",
-		       info->line, info->port, info->irq);
-		tty_register_device(serial_driver, info->line, NULL);
-
-	}
-
-	for (channel = 0; channel < zs_channels_found; ++channel) {
-		zs_soft[channel].clk_divisor = 16;
-		zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
-
-		if (request_irq(zs_soft[channel].irq, rs_interrupt, IRQF_SHARED,
-				"scc", &zs_soft[channel]))
-			printk(KERN_ERR "decserial: can't get irq %d\n",
-			       zs_soft[channel].irq);
-
-		if (zs_soft[channel].hook) {
-			zs_startup(&zs_soft[channel]);
-			if (zs_soft[channel].hook->init_channel)
-				(*zs_soft[channel].hook->init_channel)
-					(&zs_soft[channel]);
-		}
-	}
-
-	return 0;
-}
-
-/*
- * polling I/O routines
- */
-static int zs_poll_tx_char(void *handle, unsigned char ch)
-{
-	struct dec_serial *info = handle;
-	struct dec_zschannel *chan = info->zs_channel;
-	int    ret;
-
-	if(chan) {
-		int loops = 10000;
-
-		while (loops && !(read_zsreg(chan, 0) & Tx_BUF_EMP))
-			loops--;
-
-		if (loops) {
-			write_zsdata(chan, ch);
-			ret = 0;
-		} else
-			ret = -EAGAIN;
-
-		return ret;
-	} else
-		return -ENODEV;
-}
-
-static int zs_poll_rx_char(void *handle)
-{
-	struct dec_serial *info = handle;
-        struct dec_zschannel *chan = info->zs_channel;
-        int    ret;
-
-	if(chan) {
-                int loops = 10000;
-
-		while (loops && !(read_zsreg(chan, 0) & Rx_CH_AV))
-			loops--;
-
-                if (loops)
-                        ret = read_zsdata(chan);
-                else
-                        ret = -EAGAIN;
-
-		return ret;
-	} else
-		return -ENODEV;
-}
-
-int register_zs_hook(unsigned int channel, struct dec_serial_hook *hook)
-{
-	struct dec_serial *info = &zs_soft[channel];
-
-	if (info->hook) {
-		printk("%s: line %d has already a hook registered\n",
-		       __FUNCTION__, channel);
-
-		return 0;
-	} else {
-		hook->poll_rx_char = zs_poll_rx_char;
-		hook->poll_tx_char = zs_poll_tx_char;
-		info->hook = hook;
-
-		return 1;
-	}
-}
-
-int unregister_zs_hook(unsigned int channel)
-{
-	struct dec_serial *info = &zs_soft[channel];
-
-        if (info->hook) {
-                info->hook = NULL;
-                return 1;
-        } else {
-                printk("%s: trying to unregister hook on line %d,"
-                       " but none is registered\n", __FUNCTION__, channel);
-                return 0;
-        }
-}
-
-/*
- * ------------------------------------------------------------
- * Serial console driver
- * ------------------------------------------------------------
- */
-#ifdef CONFIG_SERIAL_DEC_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 dec_serial *info;
-	int i;
-
-	info = zs_soft + co->index;
-
-	for (i = 0; i < count; i++, s++) {
-		if(*s == '\n')
-			zs_poll_tx_char(info, '\r');
-		zs_poll_tx_char(info, *s);
-	}
-}
-
-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 dec_serial *info;
-	int baud = 9600;
-	int bits = 8;
-	int parity = 'n';
-	int cflag = CREAD | HUPCL | CLOCAL;
-	int clk_divisor = 16;
-	int brg;
-	char *s;
-	unsigned long flags;
-
-	if(!BUS_PRESENT)
-		return -ENODEV;
-
-	info = zs_soft + co->index;
-
-	if (zs_chain == 0)
-		probe_sccs();
-
-	info->is_cons = 1;
-
-	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 19200:
-		cflag |= B19200;
-		break;
-	case 38400:
-		cflag |= B38400;
-		break;
-	case 57600:
-		cflag |= B57600;
-		break;
-	case 115200:
-		cflag |= B115200;
-		break;
-	case 9600:
-	default:
-		cflag |= B9600;
-		/*
-		 * Set this to a sane value to prevent a divide error.
-		 */
-		baud  = 9600;
-		break;
-	}
-	switch(bits) {
-	case 7:
-		cflag |= CS7;
-		break;
-	default:
-	case 8:
-		cflag |= CS8;
-		break;
-	}
-	switch(parity) {
-	case 'o': case 'O':
-		cflag |= PARODD;
-		break;
-	case 'e': case 'E':
-		cflag |= PARENB;
-		break;
-	}
-	co->cflag = cflag;
-
-	spin_lock_irqsave(&zs_lock, flags);
-
-	/*
-	 * Set up the baud rate generator.
-	 */
-	brg = BPS_TO_BRG(baud, zs_parms->clock / clk_divisor);
-	info->zs_channel->curregs[R12] = (brg & 255);
-	info->zs_channel->curregs[R13] = ((brg >> 8) & 255);
-
-	/*
-	 * Set byte size and parity.
-	 */
-	if (bits == 7) {
-		info->zs_channel->curregs[R3] |= Rx7;
-		info->zs_channel->curregs[R5] |= Tx7;
-	} else {
-		info->zs_channel->curregs[R3] |= Rx8;
-		info->zs_channel->curregs[R5] |= Tx8;
-	}
-	if (cflag & PARENB) {
-		info->zs_channel->curregs[R4] |= PAR_ENA;
-	}
-	if (!(cflag & PARODD)) {
-		info->zs_channel->curregs[R4] |= PAR_EVEN;
-	}
-	info->zs_channel->curregs[R4] |= SB1;
-
-	/*
-	 * Turn on RTS and DTR.
-	 */
-	zs_rtsdtr(info, RTS | DTR, 1);
-
-	/*
-	 * Finally, enable sequencing.
-	 */
-	info->zs_channel->curregs[R3] |= RxENABLE;
-	info->zs_channel->curregs[R5] |= TxENAB;
-
-	/*
-	 * Clear the interrupt registers.
-	 */
-	write_zsreg(info->zs_channel, R0, ERR_RES);
-	write_zsreg(info->zs_channel, R0, RES_H_IUS);
-
-	/*
-	 * Load up the new values.
-	 */
-	load_zsregs(info->zs_channel, info->zs_channel->curregs);
-
-	/* Save the current value of RR0 */
-	info->read_reg_zero = read_zsreg(info->zs_channel, R0);
-
-	zs_soft[co->index].clk_divisor = clk_divisor;
-	zs_soft[co->index].zs_baud = get_zsbaud(&zs_soft[co->index]);
-
-	spin_unlock_irqrestore(&zs_lock, flags);
-
-	return 0;
-}
-
-static struct console zs_console = {
-	.name		= "ttyS",
-	.write		= serial_console_write,
-	.device		= serial_console_device,
-	.setup		= serial_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-};
-
-/*
- *	Register console.
- */
-void __init zs_serial_console_init(void)
-{
-	register_console(&zs_console);
-}
-#endif /* ifdef CONFIG_SERIAL_DEC_CONSOLE */
-
-#ifdef CONFIG_KGDB
-struct dec_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)*/
-};
-
-/* These are for receiving and sending characters under the kgdb
- * source level kernel debugger.
- */
-void putDebugChar(char kgdb_char)
-{
-	struct dec_zschannel *chan = zs_kgdbchan;
-	while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
-		RECOVERY_DELAY;
-	write_zsdata(chan, kgdb_char);
-}
-char getDebugChar(void)
-{
-	struct dec_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 dec_zschannel *chan = zs_kgdbchan;
-	int one, nine;
-	nine = read_zsreg(chan, 9);
-	if (yes == 1) {
-		one = EXT_INT_ENAB|RxINT_ALL;
-		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);
-}
-
-static int kgdbhook_init_channel(void *handle)
-{
-	return 0;
-}
-
-static void kgdbhook_init_info(void *handle)
-{
-}
-
-static void kgdbhook_rx_char(void *handle, unsigned char ch, unsigned char fl)
-{
-	struct dec_serial *info = handle;
-
-	if (fl != TTY_NORMAL)
-		return;
-	if (ch == 0x03 || ch == '$')
-		breakpoint();
-}
-
-/* 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 dec_zschannel *ms, int intson, int bps)
-{
-	int brg;
-	int i, x;
-	volatile char *sccc = ms->control;
-	brg = BPS_TO_BRG(bps, zs_parms->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.
- */
-struct dec_serial_hook zs_kgdbhook = {
-	.init_channel	= kgdbhook_init_channel,
-	.init_info	= kgdbhook_init_info,
-	.rx_char	= kgdbhook_rx_char,
-	.cflags		= B38400 | CS8 | CLOCAL,
-};
-
-void __init zs_kgdb_hook(int tty_num)
-{
-	/* Find out how many Z8530 SCCs we have */
-	if (zs_chain == 0)
-		probe_sccs();
-	zs_soft[tty_num].zs_channel = &zs_channels[tty_num];
-	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].hook = &zs_kgdbhook; /* 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 */
diff --git a/drivers/tc/zs.h b/drivers/tc/zs.h
deleted file mode 100644
index 1351220..0000000
--- a/drivers/tc/zs.h
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * drivers/tc/zs.h: Definitions for the DECstation Z85C30 serial driver.
- *
- * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
- * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen.
- *
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 2004, 2005  Maciej W. Rozycki
- */
-#ifndef _DECSERIAL_H
-#define _DECSERIAL_H
-
-#include <asm/dec/serial.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 */
-
-/* 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 dec_zschannel {
-	volatile unsigned char *control;
-	volatile unsigned char *data;
-
-	/* Current write register values */
-	unsigned char curregs[NUM_ZSREGS];
-};
-
-struct dec_serial {
-	struct dec_serial	*zs_next;	/* For IRQ servicing chain.  */
-	struct dec_zschannel	*zs_channel;	/* Channel registers.  */
-	struct dec_zschannel	*zs_chan_a;	/* A side registers.  */
-	unsigned char		read_reg_zero;
-
-	struct dec_serial_hook	*hook;		/* Hook on this channel.  */
-	int			tty_break;	/* Set on BREAK condition.  */
-	int			is_cons;	/* Is this our console.  */
-	int			tx_active;	/* Char is being xmitted.  */
-	int			tx_stopped;	/* Output is suspended.  */
-
-	/*
-	 * We need to know the current clock divisor
-	 * to read the bps rate the chip has currently loaded.
-	 */
-	int			clk_divisor;	/* May be 1, 16, 32, or 64.  */
-	int			zs_baud;
-
-	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 fds on device.  */
-	int			blocked_open;	/* # of blocked opens.  */
-	unsigned char 		*xmit_buf;
-	int			xmit_head;
-	int			xmit_tail;
-	int			xmit_cnt;
-	struct tasklet_struct	tlet;
-	wait_queue_head_t	open_wait;
-	wait_queue_head_t	close_wait;
-};
-
-
-#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	RxINT_ALL	0x10	/* Int on all Rx Characters or error */
-#define	RxINT_ERR	0x18	/* Int on error only */
-#define	RxINT_MASK	0x18
-
-#define	WT_RDY_RT	0x20	/* Wait/Ready on R/T */
-#define	WT_FN_RDYFN	0x40	/* Wait/FN/Ready FN */
-#define	WT_RDY_ENAB	0x80	/* Wait/Ready Enable */
-
-/* Write Register #2 (Interrupt Vector) */
-
-/* Write Register 3 */
-
-#define	RxENABLE	0x1	/* Rx Enable */
-#define	SYNC_L_INH	0x2	/* Sync Character Load Inhibit */
-#define	ADD_SM		0x4	/* Address Search Mode (SDLC) */
-#define	RxCRC_ENAB	0x8	/* Rx CRC Enable */
-#define	ENT_HM		0x10	/* Enter Hunt Mode */
-#define	AUTO_ENAB	0x20	/* Auto Enables */
-#define	Rx5		0x0	/* Rx 5 Bits/Character */
-#define	Rx7		0x40	/* Rx 7 Bits/Character */
-#define	Rx6		0x80	/* Rx 6 Bits/Character */
-#define	Rx8		0xc0	/* Rx 8 Bits/Character */
-#define RxNBITS_MASK	0xc0
-
-/* Write Register 4 */
-
-#define	PAR_ENA		0x1	/* Parity Enable */
-#define	PAR_EVEN	0x2	/* Parity Even/Odd* */
-
-#define	SYNC_ENAB	0	/* Sync Modes Enable */
-#define	SB1		0x4	/* 1 stop bit/char */
-#define	SB15		0x8	/* 1.5 stop bits/char */
-#define	SB2		0xc	/* 2 stop bits/char */
-#define SB_MASK		0xc
-
-#define	MONSYNC		0	/* 8 Bit Sync character */
-#define	BISYNC		0x10	/* 16 bit sync character */
-#define	SDLC		0x20	/* SDLC Mode (01111110 Sync Flag) */
-#define	EXTSYNC		0x30	/* External Sync Mode */
-
-#define	X1CLK		0x0	/* x1 clock mode */
-#define	X16CLK		0x40	/* x16 clock mode */
-#define	X32CLK		0x80	/* x32 clock mode */
-#define	X64CLK		0xC0	/* x64 clock mode */
-#define XCLK_MASK	0xC0
-
-/* Write Register 5 */
-
-#define	TxCRC_ENAB	0x1	/* Tx CRC Enable */
-#define	RTS		0x2	/* RTS */
-#define	SDLC_CRC	0x4	/* SDLC/CRC-16 */
-#define	TxENAB		0x8	/* Tx Enable */
-#define	SND_BRK		0x10	/* Send Break */
-#define	Tx5		0x0	/* Tx 5 bits (or less)/character */
-#define	Tx7		0x20	/* Tx 7 bits/character */
-#define	Tx6		0x40	/* Tx 6 bits/character */
-#define	Tx8		0x60	/* Tx 8 bits/character */
-#define TxNBITS_MASK	0x60
-#define	DTR		0x80	/* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 8 (transmit buffer) */
-
-/* Write Register 9 (Master interrupt control) */
-#define	VIS	1	/* Vector Includes Status */
-#define	NV	2	/* No Vector */
-#define	DLC	4	/* Disable Lower Chain */
-#define	MIE	8	/* Master Interrupt Enable */
-#define	STATHI	0x10	/* Status high */
-#define	SOFTACK	0x20	/* Software Interrupt Acknowledge */
-#define	NORESET	0	/* No reset on write to R9 */
-#define	CHRB	0x40	/* Reset channel B */
-#define	CHRA	0x80	/* Reset channel A */
-#define	FHWRES	0xc0	/* Force hardware reset */
-
-/* Write Register 10 (misc control bits) */
-#define	BIT6	1	/* 6 bit/8bit sync */
-#define	LOOPMODE 2	/* SDLC Loop mode */
-#define	ABUNDER	4	/* Abort/flag on SDLC xmit underrun */
-#define	MARKIDLE 8	/* Mark/flag on idle */
-#define	GAOP	0x10	/* Go active on poll */
-#define	NRZ	0	/* NRZ mode */
-#define	NRZI	0x20	/* NRZI mode */
-#define	FM1	0x40	/* FM1 (transition = 1) */
-#define	FM0	0x60	/* FM0 (transition = 0) */
-#define	CRCPS	0x80	/* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode control) */
-#define	TRxCXT	0	/* TRxC = Xtal output */
-#define	TRxCTC	1	/* TRxC = Transmit clock */
-#define	TRxCBR	2	/* TRxC = BR Generator Output */
-#define	TRxCDP	3	/* TRxC = DPLL output */
-#define	TRxCOI	4	/* TRxC O/I */
-#define	TCRTxCP	0	/* Transmit clock = RTxC pin */
-#define	TCTRxCP	8	/* Transmit clock = TRxC pin */
-#define	TCBR	0x10	/* Transmit clock = BR Generator output */
-#define	TCDPLL	0x18	/* Transmit clock = DPLL output */
-#define	RCRTxCP	0	/* Receive clock = RTxC pin */
-#define	RCTRxCP	0x20	/* Receive clock = TRxC pin */
-#define	RCBR	0x40	/* Receive clock = BR Generator output */
-#define	RCDPLL	0x60	/* Receive clock = DPLL output */
-#define	RTxCX	0x80	/* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (lower byte of baud rate generator time constant) */
-
-/* Write Register 13 (upper byte of baud rate generator time constant) */
-
-/* Write Register 14 (Misc control bits) */
-#define	BRENABL	1	/* Baud rate generator enable */
-#define	BRSRC	2	/* Baud rate generator source */
-#define	DTRREQ	4	/* DTR/Request function */
-#define	AUTOECHO 8	/* Auto Echo */
-#define	LOOPBAK	0x10	/* Local loopback */
-#define	SEARCH	0x20	/* Enter search mode */
-#define	RMC	0x40	/* Reset missing clock */
-#define	DISDPLL	0x60	/* Disable DPLL */
-#define	SSBR	0x80	/* Set DPLL source = BR generator */
-#define	SSRTxC	0xa0	/* Set DPLL source = RTxC */
-#define	SFMM	0xc0	/* Set FM mode */
-#define	SNRZI	0xe0	/* Set NRZI mode */
-
-/* Write Register 15 (external/status interrupt control) */
-#define	ZCIE	2	/* Zero count IE */
-#define	DCDIE	8	/* DCD IE */
-#define	SYNCIE	0x10	/* Sync/hunt IE */
-#define	CTSIE	0x20	/* CTS IE */
-#define	TxUIE	0x40	/* Tx Underrun/EOM IE */
-#define	BRKIE	0x80	/* Break/Abort IE */
-
-
-/* Read Register 0 */
-#define	Rx_CH_AV	0x1	/* Rx Character Available */
-#define	ZCOUNT		0x2	/* Zero count */
-#define	Tx_BUF_EMP	0x4	/* Tx Buffer empty */
-#define	DCD		0x8	/* DCD */
-#define	SYNC_HUNT	0x10	/* Sync/hunt */
-#define	CTS		0x20	/* CTS */
-#define	TxEOM		0x40	/* Tx underrun */
-#define	BRK_ABRT	0x80	/* Break/Abort */
-
-/* Read Register 1 */
-#define	ALL_SNT		0x1	/* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define	RES3		0x8	/* 0/3 */
-#define	RES4		0x4	/* 0/4 */
-#define	RES5		0xc	/* 0/5 */
-#define	RES6		0x2	/* 0/6 */
-#define	RES7		0xa	/* 0/7 */
-#define	RES8		0x6	/* 0/8 */
-#define	RES18		0xe	/* 1/8 */
-#define	RES28		0x0	/* 2/8 */
-/* Special Rx Condition Interrupts */
-#define	PAR_ERR		0x10	/* Parity error */
-#define	Rx_OVR		0x20	/* Rx Overrun Error */
-#define	FRM_ERR		0x40	/* CRC/Framing Error */
-#define	END_FR		0x80	/* End of Frame (SDLC) */
-
-/* Read Register 2 (channel b only) - Interrupt vector */
-
-/* Read Register 3 (interrupt pending register) ch a only */
-#define	CHBEXT	0x1		/* Channel B Ext/Stat IP */
-#define	CHBTxIP	0x2		/* Channel B Tx IP */
-#define	CHBRxIP	0x4		/* Channel B Rx IP */
-#define	CHAEXT	0x8		/* Channel A Ext/Stat IP */
-#define	CHATxIP	0x10		/* Channel A Tx IP */
-#define	CHARxIP	0x20		/* Channel A Rx IP */
-
-/* Read Register 8 (receive data register) */
-
-/* Read Register 10  (misc status bits) */
-#define	ONLOOP	2		/* On loop */
-#define	LOOPSEND 0x10		/* Loop sending */
-#define	CLK2MIS	0x40		/* Two clocks missing */
-#define	CLK1MIS	0x80		/* One clock missing */
-
-/* Read Register 12 (lower byte of baud rate generator constant) */
-
-/* Read Register 13 (upper byte of baud rate generator constant) */
-
-/* Read Register 15 (value of WR 15) */
-
-/* Misc macros */
-#define ZS_CLEARERR(channel)	(write_zsreg(channel, 0, ERR_RES))
-#define ZS_CLEARFIFO(channel)	do { volatile unsigned char garbage; \
-				     garbage = read_zsdata(channel); \
-				     garbage = read_zsdata(channel); \
-				     garbage = read_zsdata(channel); \
-				} while(0)
-
-#endif /* !(_DECSERIAL_H) */
diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c
index 3e658dc..ff9a29b 100644
--- a/drivers/telephony/ixj_pcmcia.c
+++ b/drivers/telephony/ixj_pcmcia.c
@@ -45,11 +45,10 @@
 	p_dev->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
 	p_dev->io.IOAddrLines = 3;
 	p_dev->conf.IntType = INT_MEMORY_AND_IO;
-	p_dev->priv = kmalloc(sizeof(struct ixj_info_t), GFP_KERNEL);
+	p_dev->priv = kzalloc(sizeof(struct ixj_info_t), GFP_KERNEL);
 	if (!p_dev->priv) {
 		return -ENOMEM;
 	}
-	memset(p_dev->priv, 0, sizeof(struct ixj_info_t));
 
 	return ixj_config(p_dev);
 }
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
new file mode 100644
index 0000000..b778ed71
--- /dev/null
+++ b/drivers/uio/Kconfig
@@ -0,0 +1,29 @@
+menu "Userspace I/O"
+	depends on !S390
+
+config UIO
+	tristate "Userspace I/O drivers"
+	default n
+	help
+	  Enable this to allow the userspace driver core code to be
+	  built.  This code allows userspace programs easy access to
+	  kernel interrupts and memory locations, allowing some drivers
+	  to be written in userspace.  Note that a small kernel driver
+	  is also required for interrupt handling to work properly.
+
+	  If you don't know what to do here, say N.
+
+config UIO_CIF
+	tristate "generic Hilscher CIF Card driver"
+	depends on UIO && PCI
+	default n
+	help
+	  Driver for Hilscher CIF DeviceNet and Profibus cards.  This
+	  driver requires a userspace component that handles all of the
+	  heavy lifting and can be found at:
+	  	http://www.osadl.org/projects/downloads/UIO/user/cif-*
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called uio_cif.
+
+endmenu
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
new file mode 100644
index 0000000..7fecfb4
--- /dev/null
+++ b/drivers/uio/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_UIO)	+= uio.o
+obj-$(CONFIG_UIO_CIF)	+= uio_cif.o
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
new file mode 100644
index 0000000..865f32b6
--- /dev/null
+++ b/drivers/uio/uio.c
@@ -0,0 +1,701 @@
+/*
+ * drivers/uio/uio.c
+ *
+ * Copyright(C) 2005, Benedikt Spranger <b.spranger@linutronix.de>
+ * Copyright(C) 2005, Thomas Gleixner <tglx@linutronix.de>
+ * Copyright(C) 2006, Hans J. Koch <hjk@linutronix.de>
+ * Copyright(C) 2006, Greg Kroah-Hartman <greg@kroah.com>
+ *
+ * Userspace IO
+ *
+ * Base Functions
+ *
+ * Licensed under the GPLv2 only.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/idr.h>
+#include <linux/string.h>
+#include <linux/kobject.h>
+#include <linux/uio_driver.h>
+
+#define UIO_MAX_DEVICES 255
+
+struct uio_device {
+	struct module		*owner;
+	struct device		*dev;
+	int			minor;
+	atomic_t		event;
+	struct fasync_struct	*async_queue;
+	wait_queue_head_t	wait;
+	int			vma_count;
+	struct uio_info		*info;
+	struct kset 		map_attr_kset;
+};
+
+static int uio_major;
+static DEFINE_IDR(uio_idr);
+static struct file_operations uio_fops;
+
+/* UIO class infrastructure */
+static struct uio_class {
+	struct kref kref;
+	struct class *class;
+} *uio_class;
+
+/*
+ * attributes
+ */
+
+static struct attribute attr_addr = {
+	.name  = "addr",
+	.mode  = S_IRUGO,
+};
+
+static struct attribute attr_size = {
+	.name  = "size",
+	.mode  = S_IRUGO,
+};
+
+static struct attribute* map_attrs[] = {
+	&attr_addr, &attr_size, NULL
+};
+
+static ssize_t map_attr_show(struct kobject *kobj, struct attribute *attr,
+			     char *buf)
+{
+	struct uio_mem *mem = container_of(kobj, struct uio_mem, kobj);
+
+	if (strncmp(attr->name,"addr",4) == 0)
+		return sprintf(buf, "0x%lx\n", mem->addr);
+
+	if (strncmp(attr->name,"size",4) == 0)
+		return sprintf(buf, "0x%lx\n", mem->size);
+
+	return -ENODEV;
+}
+
+static void map_attr_release(struct kobject *kobj)
+{
+	/* TODO ??? */
+}
+
+static struct sysfs_ops map_attr_ops = {
+	.show  = map_attr_show,
+};
+
+static struct kobj_type map_attr_type = {
+	.release	= map_attr_release,
+	.sysfs_ops	= &map_attr_ops,
+	.default_attrs	= map_attrs,
+};
+
+static ssize_t show_name(struct device *dev,
+			 struct device_attribute *attr, char *buf)
+{
+	struct uio_device *idev = dev_get_drvdata(dev);
+	if (idev)
+		return sprintf(buf, "%s\n", idev->info->name);
+	else
+		return -ENODEV;
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static ssize_t show_version(struct device *dev,
+			    struct device_attribute *attr, char *buf)
+{
+	struct uio_device *idev = dev_get_drvdata(dev);
+	if (idev)
+		return sprintf(buf, "%s\n", idev->info->version);
+	else
+		return -ENODEV;
+}
+static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
+
+static ssize_t show_event(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	struct uio_device *idev = dev_get_drvdata(dev);
+	if (idev)
+		return sprintf(buf, "%u\n",
+				(unsigned int)atomic_read(&idev->event));
+	else
+		return -ENODEV;
+}
+static DEVICE_ATTR(event, S_IRUGO, show_event, NULL);
+
+static struct attribute *uio_attrs[] = {
+	&dev_attr_name.attr,
+	&dev_attr_version.attr,
+	&dev_attr_event.attr,
+	NULL,
+};
+
+static struct attribute_group uio_attr_grp = {
+	.attrs = uio_attrs,
+};
+
+/*
+ * device functions
+ */
+static int uio_dev_add_attributes(struct uio_device *idev)
+{
+	int ret;
+	int mi;
+	int map_found = 0;
+	struct uio_mem *mem;
+
+	ret = sysfs_create_group(&idev->dev->kobj, &uio_attr_grp);
+	if (ret)
+		goto err_group;
+
+	for (mi = 0; mi < MAX_UIO_MAPS; mi++) {
+		mem = &idev->info->mem[mi];
+		if (mem->size == 0)
+			break;
+		if (!map_found) {
+			map_found = 1;
+			kobject_set_name(&idev->map_attr_kset.kobj,"maps");
+			idev->map_attr_kset.ktype = &map_attr_type;
+			idev->map_attr_kset.kobj.parent = &idev->dev->kobj;
+			ret = kset_register(&idev->map_attr_kset);
+			if (ret)
+				goto err_remove_group;
+		}
+		kobject_init(&mem->kobj);
+		kobject_set_name(&mem->kobj,"map%d",mi);
+		mem->kobj.parent = &idev->map_attr_kset.kobj;
+		mem->kobj.kset = &idev->map_attr_kset;
+		ret = kobject_add(&mem->kobj);
+		if (ret)
+			goto err_remove_maps;
+	}
+
+	return 0;
+
+err_remove_maps:
+	for (mi--; mi>=0; mi--) {
+		mem = &idev->info->mem[mi];
+		kobject_unregister(&mem->kobj);
+	}
+	kset_unregister(&idev->map_attr_kset); /* Needed ? */
+err_remove_group:
+	sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
+err_group:
+	dev_err(idev->dev, "error creating sysfs files (%d)\n", ret);
+	return ret;
+}
+
+static void uio_dev_del_attributes(struct uio_device *idev)
+{
+	int mi;
+	struct uio_mem *mem;
+	for (mi = 0; mi < MAX_UIO_MAPS; mi++) {
+		mem = &idev->info->mem[mi];
+		if (mem->size == 0)
+			break;
+		kobject_unregister(&mem->kobj);
+	}
+	kset_unregister(&idev->map_attr_kset);
+	sysfs_remove_group(&idev->dev->kobj, &uio_attr_grp);
+}
+
+static int uio_get_minor(struct uio_device *idev)
+{
+	static DEFINE_MUTEX(minor_lock);
+	int retval = -ENOMEM;
+	int id;
+
+	mutex_lock(&minor_lock);
+	if (idr_pre_get(&uio_idr, GFP_KERNEL) == 0)
+		goto exit;
+
+	retval = idr_get_new(&uio_idr, idev, &id);
+	if (retval < 0) {
+		if (retval == -EAGAIN)
+			retval = -ENOMEM;
+		goto exit;
+	}
+	idev->minor = id & MAX_ID_MASK;
+exit:
+	mutex_unlock(&minor_lock);
+	return retval;
+}
+
+static void uio_free_minor(struct uio_device *idev)
+{
+	idr_remove(&uio_idr, idev->minor);
+}
+
+/**
+ * uio_event_notify - trigger an interrupt event
+ * @info: UIO device capabilities
+ */
+void uio_event_notify(struct uio_info *info)
+{
+	struct uio_device *idev = info->uio_dev;
+
+	atomic_inc(&idev->event);
+	wake_up_interruptible(&idev->wait);
+	kill_fasync(&idev->async_queue, SIGIO, POLL_IN);
+}
+EXPORT_SYMBOL_GPL(uio_event_notify);
+
+/**
+ * uio_interrupt - hardware interrupt handler
+ * @irq: IRQ number, can be UIO_IRQ_CYCLIC for cyclic timer
+ * @dev_id: Pointer to the devices uio_device structure
+ */
+static irqreturn_t uio_interrupt(int irq, void *dev_id)
+{
+	struct uio_device *idev = (struct uio_device *)dev_id;
+	irqreturn_t ret = idev->info->handler(irq, idev->info);
+
+	if (ret == IRQ_HANDLED)
+		uio_event_notify(idev->info);
+
+	return ret;
+}
+
+struct uio_listener {
+	struct uio_device *dev;
+	s32 event_count;
+};
+
+static int uio_open(struct inode *inode, struct file *filep)
+{
+	struct uio_device *idev;
+	struct uio_listener *listener;
+	int ret = 0;
+
+	idev = idr_find(&uio_idr, iminor(inode));
+	if (!idev)
+		return -ENODEV;
+
+	listener = kmalloc(sizeof(*listener), GFP_KERNEL);
+	if (!listener)
+		return -ENOMEM;
+
+	listener->dev = idev;
+	listener->event_count = atomic_read(&idev->event);
+	filep->private_data = listener;
+
+	if (idev->info->open) {
+		if (!try_module_get(idev->owner))
+			return -ENODEV;
+		ret = idev->info->open(idev->info, inode);
+		module_put(idev->owner);
+	}
+
+	if (ret)
+		kfree(listener);
+
+	return ret;
+}
+
+static int uio_fasync(int fd, struct file *filep, int on)
+{
+	struct uio_listener *listener = filep->private_data;
+	struct uio_device *idev = listener->dev;
+
+	return fasync_helper(fd, filep, on, &idev->async_queue);
+}
+
+static int uio_release(struct inode *inode, struct file *filep)
+{
+	int ret = 0;
+	struct uio_listener *listener = filep->private_data;
+	struct uio_device *idev = listener->dev;
+
+	if (idev->info->release) {
+		if (!try_module_get(idev->owner))
+			return -ENODEV;
+		ret = idev->info->release(idev->info, inode);
+		module_put(idev->owner);
+	}
+	if (filep->f_flags & FASYNC)
+		ret = uio_fasync(-1, filep, 0);
+	kfree(listener);
+	return ret;
+}
+
+static unsigned int uio_poll(struct file *filep, poll_table *wait)
+{
+	struct uio_listener *listener = filep->private_data;
+	struct uio_device *idev = listener->dev;
+
+	if (idev->info->irq == UIO_IRQ_NONE)
+		return -EIO;
+
+	poll_wait(filep, &idev->wait, wait);
+	if (listener->event_count != atomic_read(&idev->event))
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+static ssize_t uio_read(struct file *filep, char __user *buf,
+			size_t count, loff_t *ppos)
+{
+	struct uio_listener *listener = filep->private_data;
+	struct uio_device *idev = listener->dev;
+	DECLARE_WAITQUEUE(wait, current);
+	ssize_t retval;
+	s32 event_count;
+
+	if (idev->info->irq == UIO_IRQ_NONE)
+		return -EIO;
+
+	if (count != sizeof(s32))
+		return -EINVAL;
+
+	add_wait_queue(&idev->wait, &wait);
+
+	do {
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		event_count = atomic_read(&idev->event);
+		if (event_count != listener->event_count) {
+			if (copy_to_user(buf, &event_count, count))
+				retval = -EFAULT;
+			else {
+				listener->event_count = event_count;
+				retval = count;
+			}
+			break;
+		}
+
+		if (filep->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
+			break;
+		}
+
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+		schedule();
+	} while (1);
+
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&idev->wait, &wait);
+
+	return retval;
+}
+
+static int uio_find_mem_index(struct vm_area_struct *vma)
+{
+	int mi;
+	struct uio_device *idev = vma->vm_private_data;
+
+	for (mi = 0; mi < MAX_UIO_MAPS; mi++) {
+		if (idev->info->mem[mi].size == 0)
+			return -1;
+		if (vma->vm_pgoff == mi)
+			return mi;
+	}
+	return -1;
+}
+
+static void uio_vma_open(struct vm_area_struct *vma)
+{
+	struct uio_device *idev = vma->vm_private_data;
+	idev->vma_count++;
+}
+
+static void uio_vma_close(struct vm_area_struct *vma)
+{
+	struct uio_device *idev = vma->vm_private_data;
+	idev->vma_count--;
+}
+
+static struct page *uio_vma_nopage(struct vm_area_struct *vma,
+				   unsigned long address, int *type)
+{
+	struct uio_device *idev = vma->vm_private_data;
+	struct page* page = NOPAGE_SIGBUS;
+
+	int mi = uio_find_mem_index(vma);
+	if (mi < 0)
+		return page;
+
+	if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL)
+		page = virt_to_page(idev->info->mem[mi].addr);
+	else
+		page = vmalloc_to_page((void*)idev->info->mem[mi].addr);
+	get_page(page);
+	if (type)
+		*type = VM_FAULT_MINOR;
+	return page;
+}
+
+static struct vm_operations_struct uio_vm_ops = {
+	.open = uio_vma_open,
+	.close = uio_vma_close,
+	.nopage = uio_vma_nopage,
+};
+
+static int uio_mmap_physical(struct vm_area_struct *vma)
+{
+	struct uio_device *idev = vma->vm_private_data;
+	int mi = uio_find_mem_index(vma);
+	if (mi < 0)
+		return -EINVAL;
+
+	vma->vm_flags |= VM_IO | VM_RESERVED;
+
+	return remap_pfn_range(vma,
+			       vma->vm_start,
+			       idev->info->mem[mi].addr >> PAGE_SHIFT,
+			       vma->vm_end - vma->vm_start,
+			       vma->vm_page_prot);
+}
+
+static int uio_mmap_logical(struct vm_area_struct *vma)
+{
+	vma->vm_flags |= VM_RESERVED;
+	vma->vm_ops = &uio_vm_ops;
+	uio_vma_open(vma);
+	return 0;
+}
+
+static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+	struct uio_listener *listener = filep->private_data;
+	struct uio_device *idev = listener->dev;
+	int mi;
+	unsigned long requested_pages, actual_pages;
+	int ret = 0;
+
+	if (vma->vm_end < vma->vm_start)
+		return -EINVAL;
+
+	vma->vm_private_data = idev;
+
+	mi = uio_find_mem_index(vma);
+	if (mi < 0)
+		return -EINVAL;
+
+	requested_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+	actual_pages = (idev->info->mem[mi].size + PAGE_SIZE -1) >> PAGE_SHIFT;
+	if (requested_pages > actual_pages)
+		return -EINVAL;
+
+	if (idev->info->mmap) {
+		if (!try_module_get(idev->owner))
+			return -ENODEV;
+		ret = idev->info->mmap(idev->info, vma);
+		module_put(idev->owner);
+		return ret;
+	}
+
+	switch (idev->info->mem[mi].memtype) {
+		case UIO_MEM_PHYS:
+			return uio_mmap_physical(vma);
+		case UIO_MEM_LOGICAL:
+		case UIO_MEM_VIRTUAL:
+			return uio_mmap_logical(vma);
+		default:
+			return -EINVAL;
+	}
+}
+
+static struct file_operations uio_fops = {
+	.owner		= THIS_MODULE,
+	.open		= uio_open,
+	.release	= uio_release,
+	.read		= uio_read,
+	.mmap		= uio_mmap,
+	.poll		= uio_poll,
+	.fasync		= uio_fasync,
+};
+
+static int uio_major_init(void)
+{
+	uio_major = register_chrdev(0, "uio", &uio_fops);
+	if (uio_major < 0)
+		return uio_major;
+	return 0;
+}
+
+static void uio_major_cleanup(void)
+{
+	unregister_chrdev(uio_major, "uio");
+}
+
+static int init_uio_class(void)
+{
+	int ret = 0;
+
+	if (uio_class != NULL) {
+		kref_get(&uio_class->kref);
+		goto exit;
+	}
+
+	/* This is the first time in here, set everything up properly */
+	ret = uio_major_init();
+	if (ret)
+		goto exit;
+
+	uio_class = kzalloc(sizeof(*uio_class), GFP_KERNEL);
+	if (!uio_class) {
+		ret = -ENOMEM;
+		goto err_kzalloc;
+	}
+
+	kref_init(&uio_class->kref);
+	uio_class->class = class_create(THIS_MODULE, "uio");
+	if (IS_ERR(uio_class->class)) {
+		ret = IS_ERR(uio_class->class);
+		printk(KERN_ERR "class_create failed for uio\n");
+		goto err_class_create;
+	}
+	return 0;
+
+err_class_create:
+	kfree(uio_class);
+	uio_class = NULL;
+err_kzalloc:
+	uio_major_cleanup();
+exit:
+	return ret;
+}
+
+static void release_uio_class(struct kref *kref)
+{
+	/* Ok, we cheat as we know we only have one uio_class */
+	class_destroy(uio_class->class);
+	kfree(uio_class);
+	uio_major_cleanup();
+	uio_class = NULL;
+}
+
+static void uio_class_destroy(void)
+{
+	if (uio_class)
+		kref_put(&uio_class->kref, release_uio_class);
+}
+
+/**
+ * uio_register_device - register a new userspace IO device
+ * @owner:	module that creates the new device
+ * @parent:	parent device
+ * @info:	UIO device capabilities
+ *
+ * returns zero on success or a negative error code.
+ */
+int __uio_register_device(struct module *owner,
+			  struct device *parent,
+			  struct uio_info *info)
+{
+	struct uio_device *idev;
+	int ret = 0;
+
+	if (!parent || !info || !info->name || !info->version)
+		return -EINVAL;
+
+	info->uio_dev = NULL;
+
+	ret = init_uio_class();
+	if (ret)
+		return ret;
+
+	idev = kzalloc(sizeof(*idev), GFP_KERNEL);
+	if (!idev) {
+		ret = -ENOMEM;
+		goto err_kzalloc;
+	}
+
+	idev->owner = owner;
+	idev->info = info;
+	init_waitqueue_head(&idev->wait);
+	atomic_set(&idev->event, 0);
+
+	ret = uio_get_minor(idev);
+	if (ret)
+		goto err_get_minor;
+
+	idev->dev = device_create(uio_class->class, parent,
+				  MKDEV(uio_major, idev->minor),
+				  "uio%d", idev->minor);
+	if (IS_ERR(idev->dev)) {
+		printk(KERN_ERR "UIO: device register failed\n");
+		ret = PTR_ERR(idev->dev);
+		goto err_device_create;
+	}
+	dev_set_drvdata(idev->dev, idev);
+
+	ret = uio_dev_add_attributes(idev);
+	if (ret)
+		goto err_uio_dev_add_attributes;
+
+	info->uio_dev = idev;
+
+	if (idev->info->irq >= 0) {
+		ret = request_irq(idev->info->irq, uio_interrupt,
+				  idev->info->irq_flags, idev->info->name, idev);
+		if (ret)
+			goto err_request_irq;
+	}
+
+	return 0;
+
+err_request_irq:
+	uio_dev_del_attributes(idev);
+err_uio_dev_add_attributes:
+	device_destroy(uio_class->class, MKDEV(uio_major, idev->minor));
+err_device_create:
+	uio_free_minor(idev);
+err_get_minor:
+	kfree(idev);
+err_kzalloc:
+	uio_class_destroy();
+	return ret;
+}
+EXPORT_SYMBOL_GPL(__uio_register_device);
+
+/**
+ * uio_unregister_device - unregister a industrial IO device
+ * @info:	UIO device capabilities
+ *
+ */
+void uio_unregister_device(struct uio_info *info)
+{
+	struct uio_device *idev;
+
+	if (!info || !info->uio_dev)
+		return;
+
+	idev = info->uio_dev;
+
+	uio_free_minor(idev);
+
+	if (info->irq >= 0)
+		free_irq(info->irq, idev);
+
+	uio_dev_del_attributes(idev);
+
+	dev_set_drvdata(idev->dev, NULL);
+	device_destroy(uio_class->class, MKDEV(uio_major, idev->minor));
+	kfree(idev);
+	uio_class_destroy();
+
+	return;
+}
+EXPORT_SYMBOL_GPL(uio_unregister_device);
+
+static int __init uio_init(void)
+{
+	return 0;
+}
+
+static void __exit uio_exit(void)
+{
+}
+
+module_init(uio_init)
+module_exit(uio_exit)
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/uio/uio_cif.c b/drivers/uio/uio_cif.c
new file mode 100644
index 0000000..838bae4
--- /dev/null
+++ b/drivers/uio/uio_cif.c
@@ -0,0 +1,156 @@
+/*
+ * UIO Hilscher CIF card driver
+ *
+ * (C) 2007 Hans J. Koch <hjk@linutronix.de>
+ * Original code (C) 2005 Benedikt Spranger <b.spranger@linutronix.de>
+ *
+ * Licensed under GPL version 2 only.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/uio_driver.h>
+
+#include <asm/io.h>
+
+#ifndef PCI_DEVICE_ID_PLX_9030
+#define PCI_DEVICE_ID_PLX_9030	0x9030
+#endif
+
+#define PLX9030_INTCSR		0x4C
+#define INTSCR_INT1_ENABLE	0x01
+#define INTSCR_INT1_STATUS	0x04
+#define INT1_ENABLED_AND_ACTIVE	(INTSCR_INT1_ENABLE | INTSCR_INT1_STATUS)
+
+#define PCI_SUBVENDOR_ID_PEP	0x1518
+#define CIF_SUBDEVICE_PROFIBUS	0x430
+#define CIF_SUBDEVICE_DEVICENET	0x432
+
+
+static irqreturn_t hilscher_handler(int irq, struct uio_info *dev_info)
+{
+	void __iomem *plx_intscr = dev_info->mem[0].internal_addr
+					+ PLX9030_INTCSR;
+
+	if ((ioread8(plx_intscr) & INT1_ENABLED_AND_ACTIVE)
+	    != INT1_ENABLED_AND_ACTIVE)
+		return IRQ_NONE;
+
+	/* Disable interrupt */
+	iowrite8(ioread8(plx_intscr) & ~INTSCR_INT1_ENABLE, plx_intscr);
+	return IRQ_HANDLED;
+}
+
+static int __devinit hilscher_pci_probe(struct pci_dev *dev,
+					const struct pci_device_id *id)
+{
+	struct uio_info *info;
+
+	info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+
+	if (pci_enable_device(dev))
+		goto out_free;
+
+	if (pci_request_regions(dev, "hilscher"))
+		goto out_disable;
+
+	info->mem[0].addr = pci_resource_start(dev, 0);
+	if (!info->mem[0].addr)
+		goto out_release;
+	info->mem[0].internal_addr = ioremap(pci_resource_start(dev, 0),
+					     pci_resource_len(dev, 0));
+	if (!info->mem[0].internal_addr)
+		goto out_release;
+
+	info->mem[0].size = pci_resource_len(dev, 0);
+	info->mem[0].memtype = UIO_MEM_PHYS;
+	info->mem[1].addr = pci_resource_start(dev, 2);
+	info->mem[1].size = pci_resource_len(dev, 2);
+	info->mem[1].memtype = UIO_MEM_PHYS;
+	switch (id->subdevice) {
+		case CIF_SUBDEVICE_PROFIBUS:
+			info->name = "CIF_Profibus";
+			break;
+		case CIF_SUBDEVICE_DEVICENET:
+			info->name = "CIF_Devicenet";
+			break;
+		default:
+			info->name = "CIF_???";
+	}
+	info->version = "0.0.1";
+	info->irq = dev->irq;
+	info->irq_flags = IRQF_DISABLED | IRQF_SHARED;
+	info->handler = hilscher_handler;
+
+	if (uio_register_device(&dev->dev, info))
+		goto out_unmap;
+
+	pci_set_drvdata(dev, info);
+
+	return 0;
+out_unmap:
+	iounmap(info->mem[0].internal_addr);
+out_release:
+	pci_release_regions(dev);
+out_disable:
+	pci_disable_device(dev);
+out_free:
+	kfree (info);
+	return -ENODEV;
+}
+
+static void hilscher_pci_remove(struct pci_dev *dev)
+{
+	struct uio_info *info = pci_get_drvdata(dev);
+
+	uio_unregister_device(info);
+	pci_release_regions(dev);
+	pci_disable_device(dev);
+	pci_set_drvdata(dev, NULL);
+	iounmap(info->mem[0].internal_addr);
+
+	kfree (info);
+}
+
+static struct pci_device_id hilscher_pci_ids[] = {
+	{
+		.vendor =	PCI_VENDOR_ID_PLX,
+		.device =	PCI_DEVICE_ID_PLX_9030,
+		.subvendor =	PCI_SUBVENDOR_ID_PEP,
+		.subdevice =	CIF_SUBDEVICE_PROFIBUS,
+	},
+	{
+		.vendor =	PCI_VENDOR_ID_PLX,
+		.device =	PCI_DEVICE_ID_PLX_9030,
+		.subvendor =	PCI_SUBVENDOR_ID_PEP,
+		.subdevice =	CIF_SUBDEVICE_DEVICENET,
+	},
+	{ 0, }
+};
+
+static struct pci_driver hilscher_pci_driver = {
+	.name = "hilscher",
+	.id_table = hilscher_pci_ids,
+	.probe = hilscher_pci_probe,
+	.remove = hilscher_pci_remove,
+};
+
+static int __init hilscher_init_module(void)
+{
+	return pci_register_driver(&hilscher_pci_driver);
+}
+
+static void __exit hilscher_exit_module(void)
+{
+	pci_unregister_driver(&hilscher_pci_driver);
+}
+
+module_init(hilscher_init_module);
+module_exit(hilscher_exit_module);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Hans J. Koch, Benedikt Spranger");
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 7dd7354..7580aa5d 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -6,6 +6,9 @@
 	bool "USB support"
 	depends on HAS_IOMEM
 	default y
+	---help---
+	  This option adds core support for Universal Serial Bus (USB).
+	  You will also need drivers from the following menu to make use of it.
 
 if USB_SUPPORT
 
@@ -18,6 +21,7 @@
 	default y if USB_ARCH_HAS_EHCI
 	default y if PCMCIA && !M32R			# sl811_cs
 	default y if ARM				# SL-811
+	default y if SUPERH				# r8a66597-hcd
 	default PCI
 
 # many non-PCI SOC chips embed OHCI
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index befff5f..516a640 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -28,26 +28,7 @@
 
 obj-$(CONFIG_USB_SERIAL)	+= serial/
 
-obj-$(CONFIG_USB_ADUTUX)	+= misc/
-obj-$(CONFIG_USB_APPLEDISPLAY)	+= misc/
-obj-$(CONFIG_USB_AUERSWALD)	+= misc/
-obj-$(CONFIG_USB_BERRY_CHARGE)	+= misc/
-obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/
-obj-$(CONFIG_USB_CYTHERM)	+= misc/
-obj-$(CONFIG_USB_EMI26)		+= misc/
-obj-$(CONFIG_USB_EMI62)		+= misc/
-obj-$(CONFIG_USB_FTDI_ELAN)	+= misc/
-obj-$(CONFIG_USB_IDMOUSE)	+= misc/
-obj-$(CONFIG_USB_LCD)		+= misc/
-obj-$(CONFIG_USB_LD)		+= misc/
-obj-$(CONFIG_USB_LED)		+= misc/
-obj-$(CONFIG_USB_LEGOTOWER)	+= misc/
-obj-$(CONFIG_USB_PHIDGETSERVO)	+= misc/
-obj-$(CONFIG_USB_RIO500)	+= misc/
-obj-$(CONFIG_USB_SISUSBVGA)	+= misc/
-obj-$(CONFIG_USB_TEST)		+= misc/
-obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/
-obj-$(CONFIG_USB_USS720)	+= misc/
+obj-$(CONFIG_USB)		+= misc/
 
 obj-$(CONFIG_USB_ATM)		+= atm/
 obj-$(CONFIG_USB_SPEEDTOUCH)	+= atm/
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 1bc8840..a51eeed 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -456,7 +456,6 @@
 				 int* actual_length)
 {
 	struct timer_list timer;
-	int status;
 
 	init_timer(&timer);
 	timer.expires = jiffies + msecs_to_jiffies(CMD_TIMEOUT);
@@ -464,12 +463,11 @@
 	timer.function = cxacru_timeout_kill;
 	add_timer(&timer);
 	wait_for_completion(done);
-	status = urb->status;
 	del_timer_sync(&timer);
 
 	if (actual_length)
 		*actual_length = urb->actual_length;
-	return status;
+	return urb->status; /* must read status after completion */
 }
 
 static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
@@ -484,7 +482,9 @@
 	int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE;
 
 	if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) {
-		dbg("too big transfer requested");
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "requested transfer size too large (%d, %d)\n",
+				wbuflen, rbuflen);
 		ret = -ENOMEM;
 		goto fail;
 	}
@@ -495,8 +495,9 @@
 	init_completion(&instance->rcv_done);
 	ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL);
 	if (ret < 0) {
-		dbg("submitting read urb for cm %#x failed", cm);
-		ret = ret;
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "submit of read urb for cm %#x failed (%d)\n",
+				cm, ret);
 		goto fail;
 	}
 
@@ -512,27 +513,29 @@
 	init_completion(&instance->snd_done);
 	ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL);
 	if (ret < 0) {
-		dbg("submitting write urb for cm %#x failed", cm);
-		ret = ret;
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "submit of write urb for cm %#x failed (%d)\n",
+				cm, ret);
 		goto fail;
 	}
 
 	ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL);
 	if (ret < 0) {
-		dbg("sending cm %#x failed", cm);
-		ret = ret;
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "send of cm %#x failed (%d)\n", cm, ret);
 		goto fail;
 	}
 
 	ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen);
 	if (ret < 0) {
-		dbg("receiving cm %#x failed", cm);
-		ret = ret;
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "receive of cm %#x failed (%d)\n", cm, ret);
 		goto fail;
 	}
 	if (actlen % CMD_PACKET_SIZE || !actlen) {
-		dbg("response is not a positive multiple of %d: %#x",
-				CMD_PACKET_SIZE, actlen);
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "invalid response length to cm %#x: %d\n",
+				cm, actlen);
 		ret = -EIO;
 		goto fail;
 	}
@@ -540,12 +543,16 @@
 	/* check the return status and copy the data to the output buffer, if needed */
 	for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) {
 		if (rbuf[offb] != cm) {
-			dbg("wrong cm %#x in response", rbuf[offb]);
+			if (printk_ratelimit())
+				usb_err(instance->usbatm, "wrong cm %#x in response to cm %#x\n",
+					rbuf[offb], cm);
 			ret = -EIO;
 			goto fail;
 		}
 		if (rbuf[offb + 1] != CM_STATUS_SUCCESS) {
-			dbg("response failed: %#x", rbuf[offb + 1]);
+			if (printk_ratelimit())
+				usb_err(instance->usbatm, "response to cm %#x failed: %#x\n",
+					cm, rbuf[offb + 1]);
 			ret = -EIO;
 			goto fail;
 		}
@@ -584,14 +591,18 @@
 	for (offb = 0; offb < len; ) {
 		int l = le32_to_cpu(buf[offb++]);
 		if (l > stride || l > (len - offb) / 2) {
-			dbg("wrong data length %#x in response", l);
+			if (printk_ratelimit())
+				usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n",
+					cm, l);
 			ret = -EIO;
 			goto cleanup;
 		}
 		while (l--) {
 			offd = le32_to_cpu(buf[offb++]);
 			if (offd >= size) {
-				dbg("wrong index %#x in response", offd);
+				if (printk_ratelimit())
+					usb_err(instance->usbatm, "wrong index #%x in response to cm #%x\n",
+						offd, cm);
 				ret = -EIO;
 				goto cleanup;
 			}
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 638b800..8b132c4 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -251,7 +251,6 @@
 {
 	unsigned char *buffer;
 	struct usbatm_data *usbatm = instance->usbatm;
-	struct usb_interface *intf;
 	struct usb_device *usb_dev = usbatm->usb_dev;
 	int actual_length;
 	int ret = 0;
@@ -265,7 +264,7 @@
 		goto out;
 	}
 
-	if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
+	if (!usb_ifnum_to_if(usb_dev, 2)) {
 		ret = -ENODEV;
 		usb_dbg(usbatm, "%s: interface not found!\n", __func__);
 		goto out_free;
@@ -612,7 +611,8 @@
 	struct speedtch_instance_data *instance = int_urb->context;
 	struct usbatm_data *usbatm = instance->usbatm;
 	unsigned int count = int_urb->actual_length;
-	int ret = int_urb->status;
+	int status = int_urb->status;
+	int ret;
 
 	/* The magic interrupt for "up state" */
 	static const unsigned char up_int[6]   = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 };
@@ -621,8 +621,8 @@
 
 	atm_dbg(usbatm, "%s entered\n", __func__);
 
-	if (ret < 0) {
-		atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, ret);
+	if (status < 0) {
+		atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, status);
 		goto fail;
 	}
 
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 8f04665..389c5b1 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -2,7 +2,8 @@
  * Copyright (c) 2003, 2004
  *	Damien Bergamini <damien.bergamini@free.fr>. All rights reserved.
  *
- * Copyright (c) 2005 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2005-2007 Matthieu Castet <castet.matthieu@free.fr>
+ * Copyright (c) 2005-2007 Stanislaw Gruszka <stf_xl@wp.pl>
  *
  * 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
@@ -107,18 +108,51 @@
 #define uea_info(usb_dev, format,args...) \
 	dev_info(&(usb_dev)->dev ,"[ueagle-atm] " format, ##args)
 
-struct uea_cmvs {
+struct intr_pkt;
+
+/* cmv's from firmware */
+struct uea_cmvs_v1 {
 	u32 address;
 	u16 offset;
 	u32 data;
 } __attribute__ ((packed));
 
+struct uea_cmvs_v2 {
+	u32 group;
+	u32 address;
+	u32 offset;
+	u32 data;
+} __attribute__ ((packed));
+
+/* information about currently processed cmv */
+struct cmv_dsc_e1 {
+	u8 function;
+	u16 idx;
+	u32 address;
+	u16 offset;
+};
+
+struct cmv_dsc_e4 {
+	u16 function;
+	u16 offset;
+	u16 address;
+	u16 group;
+};
+
+union cmv_dsc {
+	struct cmv_dsc_e1 e1;
+	struct cmv_dsc_e4 e4;
+};
+
 struct uea_softc {
 	struct usb_device *usb_dev;
 	struct usbatm_data *usbatm;
 
 	int modem_index;
 	unsigned int driver_info;
+	int annex;
+#define ANNEXA 0
+#define ANNEXB 1
 
 	int booting;
 	int reset;
@@ -127,20 +161,23 @@
 
 	struct task_struct *kthread;
 	u32 data;
-	wait_queue_head_t cmv_ack_wait;
+	u32 data1;
+
 	int cmv_ack;
+	union cmv_dsc cmv_dsc;
 
 	struct work_struct task;
+	struct workqueue_struct *work_q;
 	u16 pageno;
 	u16 ovl;
 
 	const struct firmware *dsp_firm;
 	struct urb *urb_int;
 
-	u8 cmv_function;
-	u16 cmv_idx;
-	u32 cmv_address;
-	u16 cmv_offset;
+	void (*dispatch_cmv) (struct uea_softc *, struct intr_pkt *);
+	void (*schedule_load_page) (struct uea_softc *, struct intr_pkt *);
+	int (*stat) (struct uea_softc *);
+	int (*send_cmvs) (struct uea_softc *);
 
 	/* keep in sync with eaglectl */
 	struct uea_stats {
@@ -174,10 +211,34 @@
 #define ELSA_PID_PSTFIRM	0x3350
 #define ELSA_PID_PREFIRM	0x3351
 
+#define ELSA_PID_A_PREFIRM	0x3352
+#define ELSA_PID_A_PSTFIRM	0x3353
+#define ELSA_PID_B_PREFIRM	0x3362
+#define ELSA_PID_B_PSTFIRM	0x3363
+
 /*
- * Sagem USB IDs
+ * Devolo IDs : pots if (pid & 0x10)
  */
-#define EAGLE_VID		0x1110
+#define DEVOLO_VID			0x1039
+#define DEVOLO_EAGLE_I_A_PID_PSTFIRM	0x2110
+#define DEVOLO_EAGLE_I_A_PID_PREFIRM	0x2111
+
+#define DEVOLO_EAGLE_I_B_PID_PSTFIRM	0x2100
+#define DEVOLO_EAGLE_I_B_PID_PREFIRM	0x2101
+
+#define DEVOLO_EAGLE_II_A_PID_PSTFIRM	0x2130
+#define DEVOLO_EAGLE_II_A_PID_PREFIRM	0x2131
+
+#define DEVOLO_EAGLE_II_B_PID_PSTFIRM	0x2120
+#define DEVOLO_EAGLE_II_B_PID_PREFIRM	0x2121
+
+/*
+ * Reference design USB IDs
+ */
+#define ANALOG_VID		0x1110
+#define ADI930_PID_PREFIRM	0x9001
+#define ADI930_PID_PSTFIRM	0x9000
+
 #define EAGLE_I_PID_PREFIRM	0x9010	/* Eagle I */
 #define EAGLE_I_PID_PSTFIRM	0x900F	/* Eagle I */
 
@@ -187,12 +248,12 @@
 #define EAGLE_II_PID_PREFIRM	0x9022	/* Eagle II */
 #define EAGLE_II_PID_PSTFIRM	0x9021	/* Eagle II */
 
-/*
- *  Eagle III Pid
- */
 #define EAGLE_III_PID_PREFIRM	0x9032	/* Eagle III */
 #define EAGLE_III_PID_PSTFIRM	0x9031	/* Eagle III */
 
+#define EAGLE_IV_PID_PREFIRM	0x9042  /* Eagle IV */
+#define EAGLE_IV_PID_PSTFIRM	0x9041  /* Eagle IV */
+
 /*
  * USR USB IDs
  */
@@ -208,11 +269,15 @@
 
 #define PREFIRM 0
 #define PSTFIRM (1<<7)
+#define AUTO_ANNEX_A (1<<8)
+#define AUTO_ANNEX_B (1<<9)
+
 enum {
 	ADI930 = 0,
 	EAGLE_I,
 	EAGLE_II,
-	EAGLE_III
+	EAGLE_III,
+	EAGLE_IV
 };
 
 /* macros for both struct usb_device_id and struct uea_softc */
@@ -221,15 +286,18 @@
 #define UEA_CHIP_VERSION(x) \
 	((x)->driver_info & 0xf)
 
-#define IS_ISDN(usb_dev) \
-	(le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80)
+#define IS_ISDN(x) \
+	((x)->annex & ANNEXB)
 
 #define INS_TO_USBDEV(ins) ins->usb_dev
 
 #define GET_STATUS(data) \
 	((data >> 8) & 0xf)
+
 #define IS_OPERATIONAL(sc) \
-	(GET_STATUS(sc->stats.phy.state) == 2)
+	((UEA_CHIP_VERSION(sc) != EAGLE_IV) ? \
+	(GET_STATUS(sc->stats.phy.state) == 2) : \
+	(sc->stats.phy.state == 7))
 
 /*
  * Set of macros to handle unaligned data in the firmware blob.
@@ -259,7 +327,8 @@
 #define UEA_INTR_PIPE		0x04
 #define UEA_ISO_DATA_PIPE	0x08
 
-#define UEA_SET_BLOCK    	0x0001
+#define UEA_E1_SET_BLOCK    	0x0001
+#define UEA_E4_SET_BLOCK	0x002c
 #define UEA_SET_MODE     	0x0003
 #define UEA_SET_2183_DATA	0x0004
 #define UEA_SET_TIMEOUT		0x0011
@@ -275,71 +344,179 @@
 #define UEA_MPTX_MAILBOX	(0x3fd6 | 0x4000)
 #define UEA_MPRX_MAILBOX	(0x3fdf | 0x4000)
 
-/* structure describing a block within a DSP page */
-struct block_info {
+/* block information in eagle4 dsp firmware  */
+struct block_index {
+	__le32 PageOffset;
+	__le32 NotLastBlock;
+	__le32 dummy;
+	__le32 PageSize;
+	__le32 PageAddress;
+	__le16 dummy1;
+	__le16 PageNumber;
+} __attribute__ ((packed));
+
+#define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000)
+#define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4)
+
+#define E4_L1_STRING_HEADER 0x10
+#define E4_MAX_PAGE_NUMBER 0x58
+#define E4_NO_SWAPPAGE_HEADERS 0x31
+
+/* l1_code is eagle4 dsp firmware format */
+struct l1_code {
+	u8 string_header[E4_L1_STRING_HEADER];
+	u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER];
+	struct block_index page_header[E4_NO_SWAPPAGE_HEADERS];
+	u8 code [0];
+} __attribute__ ((packed));
+
+/* structures describing a block within a DSP page */
+struct block_info_e1 {
 	__le16 wHdr;
-#define UEA_BIHDR 0xabcd
 	__le16 wAddress;
 	__le16 wSize;
 	__le16 wOvlOffset;
 	__le16 wOvl;		/* overlay */
 	__le16 wLast;
 } __attribute__ ((packed));
-#define BLOCK_INFO_SIZE 12
+#define E1_BLOCK_INFO_SIZE 12
 
-/* structure representing a CMV (Configuration and Management Variable) */
-struct cmv {
-	__le16 wPreamble;
-#define PREAMBLE 0x535c
-	__u8 bDirection;
-#define MODEMTOHOST 0x01
-#define HOSTTOMODEM 0x10
-	__u8 bFunction;
-#define FUNCTION_TYPE(f)    ((f) >> 4)
-#define MEMACCESS	0x1
-#define ADSLDIRECTIVE	0x7
+struct block_info_e4 {
+	__be16 wHdr;
+	__u8 bBootPage;
+	__u8 bPageNumber;
+	__be32 dwSize;
+	__be32 dwAddress;
+	__be16 wReserved;
+} __attribute__ ((packed));
+#define E4_BLOCK_INFO_SIZE 14
 
-#define FUNCTION_SUBTYPE(f) ((f) & 0x0f)
+#define UEA_BIHDR 0xabcd
+#define UEA_RESERVED 0xffff
+
+/* constants describing cmv type */
+#define E1_PREAMBLE 0x535c
+#define E1_MODEMTOHOST 0x01
+#define E1_HOSTTOMODEM 0x10
+
+#define E1_MEMACCESS 0x1
+#define E1_ADSLDIRECTIVE 0x7
+#define E1_FUNCTION_TYPE(f) ((f) >> 4)
+#define E1_FUNCTION_SUBTYPE(f) ((f) & 0x0f)
+
+#define E4_MEMACCESS 0
+#define E4_ADSLDIRECTIVE 0xf
+#define E4_FUNCTION_TYPE(f) ((f) >> 8)
+#define E4_FUNCTION_SIZE(f) ((f) & 0x0f)
+#define E4_FUNCTION_SUBTYPE(f) (((f) >> 4) & 0x0f)
+
 /* for MEMACCESS */
-#define REQUESTREAD	0x0
-#define REQUESTWRITE	0x1
-#define REPLYREAD	0x2
-#define REPLYWRITE	0x3
-/* for ADSLDIRECTIVE */
-#define KERNELREADY	0x0
-#define MODEMREADY	0x1
+#define E1_REQUESTREAD	0x0
+#define E1_REQUESTWRITE	0x1
+#define E1_REPLYREAD	0x2
+#define E1_REPLYWRITE	0x3
 
-#define MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
-	__le16 wIndex;
-	__le32 dwSymbolicAddress;
-#define MAKESA(a, b, c, d)						\
+#define E4_REQUESTREAD	0x0
+#define E4_REQUESTWRITE	0x4
+#define E4_REPLYREAD	(E4_REQUESTREAD | 1)
+#define E4_REPLYWRITE	(E4_REQUESTWRITE | 1)
+
+/* for ADSLDIRECTIVE */
+#define E1_KERNELREADY 0x0
+#define E1_MODEMREADY  0x1
+
+#define E4_KERNELREADY 0x0
+#define E4_MODEMREADY  0x1
+
+#define E1_MAKEFUNCTION(t, s) (((t) & 0xf) << 4 | ((s) & 0xf))
+#define E4_MAKEFUNCTION(t, st, s) (((t) & 0xf) << 8 | ((st) & 0xf) << 4 | ((s) & 0xf))
+
+#define E1_MAKESA(a, b, c, d)						\
 	(((c) & 0xff) << 24 |						\
 	 ((d) & 0xff) << 16 |						\
 	 ((a) & 0xff) << 8  |						\
 	 ((b) & 0xff))
-#define GETSA1(a) ((a >> 8) & 0xff)
-#define GETSA2(a) (a & 0xff)
-#define GETSA3(a) ((a >> 24) & 0xff)
-#define GETSA4(a) ((a >> 16) & 0xff)
 
-#define SA_CNTL MAKESA('C', 'N', 'T', 'L')
-#define SA_DIAG MAKESA('D', 'I', 'A', 'G')
-#define SA_INFO MAKESA('I', 'N', 'F', 'O')
-#define SA_OPTN MAKESA('O', 'P', 'T', 'N')
-#define SA_RATE MAKESA('R', 'A', 'T', 'E')
-#define SA_STAT MAKESA('S', 'T', 'A', 'T')
+#define E1_GETSA1(a) ((a >> 8) & 0xff)
+#define E1_GETSA2(a) (a & 0xff)
+#define E1_GETSA3(a) ((a >> 24) & 0xff)
+#define E1_GETSA4(a) ((a >> 16) & 0xff)
+
+#define E1_SA_CNTL E1_MAKESA('C', 'N', 'T', 'L')
+#define E1_SA_DIAG E1_MAKESA('D', 'I', 'A', 'G')
+#define E1_SA_INFO E1_MAKESA('I', 'N', 'F', 'O')
+#define E1_SA_OPTN E1_MAKESA('O', 'P', 'T', 'N')
+#define E1_SA_RATE E1_MAKESA('R', 'A', 'T', 'E')
+#define E1_SA_STAT E1_MAKESA('S', 'T', 'A', 'T')
+
+#define E4_SA_CNTL 1
+#define E4_SA_STAT 2
+#define E4_SA_INFO 3
+#define E4_SA_TEST 4
+#define E4_SA_OPTN 5
+#define E4_SA_RATE 6
+#define E4_SA_DIAG 7
+#define E4_SA_CNFG 8
+
+/* structures representing a CMV (Configuration and Management Variable) */
+struct cmv_e1 {
+	__le16 wPreamble;
+	__u8 bDirection;
+	__u8 bFunction;
+	__le16 wIndex;
+	__le32 dwSymbolicAddress;
 	__le16 wOffsetAddress;
 	__le32 dwData;
 } __attribute__ ((packed));
-#define CMV_SIZE 16
 
-/* structure representing swap information */
-struct swap_info {
+struct cmv_e4 {
+	__be16 wGroup;
+	__be16 wFunction;
+	__be16 wOffset;
+	__be16 wAddress;
+	__be32 dwData [6];
+} __attribute__ ((packed));
+
+/* structures representing swap information */
+struct swap_info_e1 {
 	__u8 bSwapPageNo;
 	__u8 bOvl;		/* overlay */
 } __attribute__ ((packed));
 
-/* structure representing interrupt data */
+struct swap_info_e4 {
+	__u8 bSwapPageNo;
+} __attribute__ ((packed));
+
+/* structures representing interrupt data */
+#define e1_bSwapPageNo	u.e1.s1.swapinfo.bSwapPageNo
+#define e1_bOvl		u.e1.s1.swapinfo.bOvl
+#define e4_bSwapPageNo  u.e4.s1.swapinfo.bSwapPageNo
+
+#define INT_LOADSWAPPAGE 0x0001
+#define INT_INCOMINGCMV  0x0002
+
+union intr_data_e1 {
+	struct {
+		struct swap_info_e1 swapinfo;
+		__le16 wDataSize;
+	} __attribute__ ((packed)) s1;
+	struct {
+		struct cmv_e1 cmv;
+		__le16 wDataSize;
+	} __attribute__ ((packed)) s2;
+} __attribute__ ((packed));
+
+union intr_data_e4 {
+	struct {
+		struct swap_info_e4 swapinfo;
+		__le16 wDataSize;
+	} __attribute__ ((packed)) s1;
+	struct {
+		struct cmv_e4 cmv;
+		__le16 wDataSize;
+	} __attribute__ ((packed)) s2;
+} __attribute__ ((packed));
+
 struct intr_pkt {
 	__u8 bType;
 	__u8 bNotification;
@@ -347,43 +524,48 @@
 	__le16 wIndex;
 	__le16 wLength;
 	__le16 wInterrupt;
-#define INT_LOADSWAPPAGE 0x0001
-#define INT_INCOMINGCMV  0x0002
 	union {
-		struct {
-			struct swap_info swapinfo;
-			__le16 wDataSize;
-		} __attribute__ ((packed)) s1;
-
-		struct {
-			struct cmv cmv;
-			__le16 wDataSize;
-		} __attribute__ ((packed)) s2;
-	} __attribute__ ((packed)) u;
-#define bSwapPageNo	u.s1.swapinfo.bSwapPageNo
-#define bOvl		u.s1.swapinfo.bOvl
+		union intr_data_e1 e1;
+		union intr_data_e4 e4;
+	} u;
 } __attribute__ ((packed));
-#define INTR_PKT_SIZE 28
+
+#define E1_INTR_PKT_SIZE 28
+#define E4_INTR_PKT_SIZE 64
 
 static struct usb_driver uea_driver;
 static DEFINE_MUTEX(uea_mutex);
-static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III"};
+static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"};
 
 static int modem_index;
 static unsigned int debug;
-static int use_iso[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = 1};
+static unsigned int altsetting[NB_MODEM] = {[0 ... (NB_MODEM - 1)] = FASTEST_ISO_INTF};
 static int sync_wait[NB_MODEM];
 static char *cmv_file[NB_MODEM];
+static int annex[NB_MODEM];
 
 module_param(debug, uint, 0644);
 MODULE_PARM_DESC(debug, "module debug level (0=off,1=on,2=verbose)");
-module_param_array(use_iso, bool, NULL, 0644);
-MODULE_PARM_DESC(use_iso, "use isochronous usb pipe for incoming traffic");
+module_param_array(altsetting, uint, NULL, 0644);
+MODULE_PARM_DESC(altsetting, "alternate setting for incoming traffic: 0=bulk, "
+			     "1=isoc slowest, ... , 8=isoc fastest (default)");
 module_param_array(sync_wait, bool, NULL, 0644);
 MODULE_PARM_DESC(sync_wait, "wait the synchronisation before starting ATM");
 module_param_array(cmv_file, charp, NULL, 0644);
 MODULE_PARM_DESC(cmv_file,
 		"file name with configuration and management variables");
+module_param_array(annex, uint, NULL, 0644);
+MODULE_PARM_DESC(annex,
+                 "manually set annex a/b (0=auto, 1=annex a, 2=annex b)");
+
+#define uea_wait(sc, cond, timeo) \
+({ \
+	int _r = wait_event_interruptible_timeout(sc->sync_q, \
+			(cond) || kthread_should_stop(), timeo); \
+	if (kthread_should_stop()) \
+		_r = -ENODEV; \
+	_r; \
+})
 
 #define UPDATE_ATM_STAT(type, val) \
 	do { \
@@ -519,6 +701,9 @@
 	case EAGLE_III:
 		fw_name = FW_DIR "eagleIII.fw";
 		break;
+	case EAGLE_IV:
+		fw_name = FW_DIR "eagleIV.fw";
+		break;
 	}
 
 	ret = request_firmware_nowait(THIS_MODULE, 1, fw_name, &usb->dev, usb, uea_upload_pre_firmware);
@@ -537,7 +722,7 @@
 /*
  * Make sure that the DSP code provided is safe to use.
  */
-static int check_dsp(u8 *dsp, unsigned int len)
+static int check_dsp_e1(u8 *dsp, unsigned int len)
 {
 	u8 pagecount, blockcount;
 	u16 blocksize;
@@ -588,6 +773,51 @@
 	return 0;
 }
 
+static int check_dsp_e4(u8 *dsp, int len)
+{
+	int i;
+	struct l1_code *p = (struct l1_code *) dsp;
+	unsigned int sum = p->code - dsp;
+
+	if (len < sum)
+		return 1;
+
+	if (strcmp("STRATIPHY ANEXA", p->string_header) != 0 &&
+	    strcmp("STRATIPHY ANEXB", p->string_header) != 0)
+		return 1;
+
+	for (i = 0; i < E4_MAX_PAGE_NUMBER; i++) {
+		struct block_index *blockidx;
+		u8 blockno = p->page_number_to_block_index[i];
+		if (blockno >= E4_NO_SWAPPAGE_HEADERS)
+			continue;
+
+		do {
+			u64 l;
+
+			if (blockno >= E4_NO_SWAPPAGE_HEADERS)
+				return 1;
+
+			blockidx = &p->page_header[blockno++];
+			if ((u8 *)(blockidx + 1) - dsp  >= len)
+				return 1;
+
+			if (le16_to_cpu(blockidx->PageNumber) != i)
+				return 1;
+
+			l = E4_PAGE_BYTES(blockidx->PageSize);
+			sum += l;
+			l += le32_to_cpu(blockidx->PageOffset);
+			if (l > len)
+				return 1;
+
+		/* zero is zero regardless endianes */
+		} while (blockidx->NotLastBlock);
+	}
+
+	return (sum == len) ? 0 : 1;
+}
+
 /*
  * send data to the idma pipe
  * */
@@ -624,13 +854,18 @@
 	int ret;
 	char *dsp_name;
 
-	if (UEA_CHIP_VERSION(sc) == ADI930) {
-		if (IS_ISDN(sc->usb_dev))
+	if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+		if (IS_ISDN(sc))
+			dsp_name = FW_DIR "DSP4i.bin";
+		else
+			dsp_name = FW_DIR "DSP4p.bin";
+	} else if (UEA_CHIP_VERSION(sc) == ADI930) {
+		if (IS_ISDN(sc))
 			dsp_name = FW_DIR "DSP9i.bin";
 		else
 			dsp_name = FW_DIR "DSP9p.bin";
 	} else {
-		if (IS_ISDN(sc->usb_dev))
+		if (IS_ISDN(sc))
 			dsp_name = FW_DIR "DSPei.bin";
 		else
 			dsp_name = FW_DIR "DSPep.bin";
@@ -640,11 +875,16 @@
 	if (ret < 0) {
 		uea_err(INS_TO_USBDEV(sc),
 		       "requesting firmware %s failed with error %d\n",
-		       dsp_name, ret);
+		        dsp_name, ret);
 		return ret;
 	}
 
-	if (check_dsp(sc->dsp_firm->data, sc->dsp_firm->size)) {
+	if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+		ret = check_dsp_e4(sc->dsp_firm->data, sc->dsp_firm->size);
+	else
+		ret = check_dsp_e1(sc->dsp_firm->data, sc->dsp_firm->size);
+
+	if (ret) {
 		uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n",
 		       dsp_name);
 		release_firmware(sc->dsp_firm);
@@ -658,12 +898,12 @@
 /*
  * The uea_load_page() function must be called within a process context
  */
-static void uea_load_page(struct work_struct *work)
+static void uea_load_page_e1(struct work_struct *work)
 {
 	struct uea_softc *sc = container_of(work, struct uea_softc, task);
 	u16 pageno = sc->pageno;
 	u16 ovl = sc->ovl;
-	struct block_info bi;
+	struct block_info_e1 bi;
 
 	u8 *p;
 	u8 pagecount, blockcount;
@@ -716,7 +956,7 @@
 		bi.wLast = cpu_to_le16((i == blockcount - 1) ? 1 : 0);
 
 		/* send block info through the IDMA pipe */
-		if (uea_idma_write(sc, &bi, BLOCK_INFO_SIZE))
+		if (uea_idma_write(sc, &bi, E1_BLOCK_INFO_SIZE))
 			goto bad2;
 
 		/* send block data through the IDMA pipe */
@@ -735,17 +975,114 @@
 	uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
 }
 
+static void __uea_load_page_e4(struct uea_softc *sc, u8 pageno, int boot)
+{
+	struct block_info_e4 bi;
+	struct block_index *blockidx;
+	struct l1_code *p = (struct l1_code *) sc->dsp_firm->data;
+	u8 blockno = p->page_number_to_block_index[pageno];
+
+	bi.wHdr = cpu_to_be16(UEA_BIHDR);
+	bi.bBootPage = boot;
+	bi.bPageNumber = pageno;
+	bi.wReserved = cpu_to_be16(UEA_RESERVED);
+
+	do {
+		u8 *blockoffset;
+		unsigned int blocksize;
+
+		blockidx = &p->page_header[blockno];
+		blocksize = E4_PAGE_BYTES(blockidx->PageSize);
+		blockoffset = sc->dsp_firm->data + le32_to_cpu(blockidx->PageOffset);
+
+		bi.dwSize = cpu_to_be32(blocksize);
+		bi.dwAddress = swab32(blockidx->PageAddress);
+
+		uea_dbg(INS_TO_USBDEV(sc),
+		       "sending block %u for DSP page %u size %u adress %x\n",
+		       blockno, pageno, blocksize, le32_to_cpu(blockidx->PageAddress));
+
+		/* send block info through the IDMA pipe */
+		if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
+			goto bad;
+
+		/* send block data through the IDMA pipe */
+		if (uea_idma_write(sc, blockoffset, blocksize))
+			goto bad;
+
+		blockno++;
+	} while (blockidx->NotLastBlock);
+
+	return;
+
+bad:
+	uea_err(INS_TO_USBDEV(sc), "sending DSP block %u failed\n", blockno);
+	return;
+}
+
+static void uea_load_page_e4(struct work_struct *work)
+{
+	struct uea_softc *sc = container_of(work, struct uea_softc, task);
+	u8 pageno = sc->pageno;
+	int i;
+	struct block_info_e4 bi;
+	struct l1_code *p;
+
+	uea_dbg(INS_TO_USBDEV(sc), "sending DSP page %u\n", pageno);
+
+	/* reload firmware when reboot start and it's loaded already */
+	if (pageno == 0 && sc->dsp_firm) {
+		release_firmware(sc->dsp_firm);
+		sc->dsp_firm = NULL;
+	}
+
+	if (sc->dsp_firm == NULL && request_dsp(sc) < 0)
+		return;
+
+	p = (struct l1_code *) sc->dsp_firm->data;
+	if (pageno >= p->page_header[0].PageNumber) {
+		uea_err(INS_TO_USBDEV(sc), "invalid DSP page %u requested\n", pageno);
+		return;
+	}
+
+	if (pageno != 0) {
+		__uea_load_page_e4(sc, pageno, 0);
+		return;
+	}
+
+	uea_dbg(INS_TO_USBDEV(sc),
+	       "sending Main DSP page %u\n", p->page_header[0].PageNumber);
+
+	for (i = 0; i < le16_to_cpu(p->page_header[0].PageNumber); i++) {
+		if (E4_IS_BOOT_PAGE(p->page_header[i].PageSize))
+			__uea_load_page_e4(sc, i, 1);
+	}
+
+	uea_dbg(INS_TO_USBDEV(sc),"sending start bi\n");
+
+	bi.wHdr = cpu_to_be16(UEA_BIHDR);
+	bi.bBootPage = 0;
+	bi.bPageNumber = 0xff;
+	bi.wReserved = cpu_to_be16(UEA_RESERVED);
+	bi.dwSize = cpu_to_be32(E4_PAGE_BYTES(p->page_header[0].PageSize));
+	bi.dwAddress = swab32(p->page_header[0].PageAddress);
+
+	/* send block info through the IDMA pipe */
+	if (uea_idma_write(sc, &bi, E4_BLOCK_INFO_SIZE))
+		uea_err(INS_TO_USBDEV(sc), "sending DSP start bi failed\n");
+}
+
 static inline void wake_up_cmv_ack(struct uea_softc *sc)
 {
 	BUG_ON(sc->cmv_ack);
 	sc->cmv_ack = 1;
-	wake_up(&sc->cmv_ack_wait);
+	wake_up(&sc->sync_q);
 }
 
 static inline int wait_cmv_ack(struct uea_softc *sc)
 {
-	int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait,
-						   sc->cmv_ack, ACK_TIMEOUT);
+	int ret = uea_wait(sc, sc->cmv_ack , ACK_TIMEOUT);
+
 	sc->cmv_ack = 0;
 
 	uea_dbg(INS_TO_USBDEV(sc), "wait_event_timeout : %d ms\n",
@@ -792,33 +1129,34 @@
 	return 0;
 }
 
-static int uea_cmv(struct uea_softc *sc,
+static int uea_cmv_e1(struct uea_softc *sc,
 		u8 function, u32 address, u16 offset, u32 data)
 {
-	struct cmv cmv;
+	struct cmv_e1 cmv;
 	int ret;
 
 	uea_enters(INS_TO_USBDEV(sc));
 	uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Address : %c%c%c%c, "
 			"offset : 0x%04x, data : 0x%08x\n",
-			FUNCTION_TYPE(function), FUNCTION_SUBTYPE(function),
-			GETSA1(address), GETSA2(address), GETSA3(address),
-			GETSA4(address), offset, data);
-	/* we send a request, but we expect a reply */
-	sc->cmv_function = function | 0x2;
-	sc->cmv_idx++;
-	sc->cmv_address = address;
-	sc->cmv_offset = offset;
+			E1_FUNCTION_TYPE(function), E1_FUNCTION_SUBTYPE(function),
+			E1_GETSA1(address), E1_GETSA2(address), E1_GETSA3(address),
+			E1_GETSA4(address), offset, data);
 
-	cmv.wPreamble = cpu_to_le16(PREAMBLE);
-	cmv.bDirection = HOSTTOMODEM;
+	/* we send a request, but we expect a reply */
+	sc->cmv_dsc.e1.function = function | 0x2;
+	sc->cmv_dsc.e1.idx++;
+	sc->cmv_dsc.e1.address = address;
+	sc->cmv_dsc.e1.offset = offset;
+
+	cmv.wPreamble = cpu_to_le16(E1_PREAMBLE);
+	cmv.bDirection = E1_HOSTTOMODEM;
 	cmv.bFunction = function;
-	cmv.wIndex = cpu_to_le16(sc->cmv_idx);
+	cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx);
 	put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress);
 	cmv.wOffsetAddress = cpu_to_le16(offset);
 	put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData);
 
-	ret = uea_request(sc, UEA_SET_BLOCK, UEA_MPTX_START, CMV_SIZE, &cmv);
+	ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
 	if (ret < 0)
 		return ret;
 	ret = wait_cmv_ack(sc);
@@ -826,10 +1164,44 @@
 	return ret;
 }
 
-static inline int uea_read_cmv(struct uea_softc *sc,
+static int uea_cmv_e4(struct uea_softc *sc,
+		u16 function, u16 group, u16 address, u16 offset, u32 data)
+{
+	struct cmv_e4 cmv;
+	int ret;
+
+	uea_enters(INS_TO_USBDEV(sc));
+	memset(&cmv, 0, sizeof(cmv));
+
+	uea_vdbg(INS_TO_USBDEV(sc), "Function : %d-%d, Group : 0x%04x, "
+		 "Address : 0x%04x, offset : 0x%04x, data : 0x%08x\n",
+		 E4_FUNCTION_TYPE(function), E4_FUNCTION_SUBTYPE(function),
+		 group, address, offset, data);
+
+	/* we send a request, but we expect a reply */
+	sc->cmv_dsc.e4.function = function | (0x1 << 4);
+	sc->cmv_dsc.e4.offset = offset;
+	sc->cmv_dsc.e4.address = address;
+	sc->cmv_dsc.e4.group = group;
+
+	cmv.wFunction = cpu_to_be16(function);
+	cmv.wGroup = cpu_to_be16(group);
+	cmv.wAddress = cpu_to_be16(address);
+	cmv.wOffset = cpu_to_be16(offset);
+	cmv.dwData[0] = cpu_to_be32(data);
+
+	ret = uea_request(sc, UEA_E4_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
+	if (ret < 0)
+		return ret;
+	ret = wait_cmv_ack(sc);
+	uea_leaves(INS_TO_USBDEV(sc));
+	return ret;
+}
+
+static inline int uea_read_cmv_e1(struct uea_softc *sc,
 		u32 address, u16 offset, u32 *data)
 {
-	int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTREAD),
+	int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTREAD),
 			  address, offset, 0);
 	if (ret < 0)
 		uea_err(INS_TO_USBDEV(sc),
@@ -840,10 +1212,27 @@
 	return ret;
 }
 
-static inline int uea_write_cmv(struct uea_softc *sc,
+static inline int uea_read_cmv_e4(struct uea_softc *sc,
+		u8 size, u16 group, u16 address, u16 offset, u32 *data)
+{
+	int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTREAD, size),
+			  group, address, offset, 0);
+	if (ret < 0)
+		uea_err(INS_TO_USBDEV(sc),
+			"reading cmv failed with error %d\n", ret);
+	else {
+	 	*data = sc->data;
+		/* size is in 16-bit word quantities */
+		if (size > 2)
+			*(data + 1) = sc->data1;
+	}
+	return ret;
+}
+
+static inline int uea_write_cmv_e1(struct uea_softc *sc,
 		u32 address, u16 offset, u32 data)
 {
-	int ret = uea_cmv(sc, MAKEFUNCTION(MEMACCESS, REQUESTWRITE),
+	int ret = uea_cmv_e1(sc, E1_MAKEFUNCTION(E1_MEMACCESS, E1_REQUESTWRITE),
 			  address, offset, data);
 	if (ret < 0)
 		uea_err(INS_TO_USBDEV(sc),
@@ -852,12 +1241,48 @@
 	return ret;
 }
 
+static inline int uea_write_cmv_e4(struct uea_softc *sc,
+		u8 size, u16 group, u16 address, u16 offset, u32 data)
+{
+	int ret = uea_cmv_e4(sc, E4_MAKEFUNCTION(E4_MEMACCESS, E4_REQUESTWRITE, size),
+			  group, address, offset, data);
+	if (ret < 0)
+		uea_err(INS_TO_USBDEV(sc),
+			"writing cmv failed with error %d\n", ret);
+
+	return ret;
+}
+
+static void uea_set_bulk_timeout(struct uea_softc *sc, u32 dsrate)
+{
+	int ret;
+	u16 timeout;
+
+	/* in bulk mode the modem have problem with high rate
+	 * changing internal timing could improve things, but the
+	 * value is misterious.
+	 * ADI930 don't support it (-EPIPE error).
+	 */
+
+	if (UEA_CHIP_VERSION(sc) == ADI930 ||
+	    altsetting[sc->modem_index] > 0 ||
+	    sc->stats.phy.dsrate == dsrate)
+		return;
+
+	/* Original timming (1Mbit/s) from ADI (used in windows driver) */
+	timeout = (dsrate <= 1024*1024) ? 0 : 1;
+	ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL);
+	uea_info(INS_TO_USBDEV(sc), "setting new timeout %d%s\n",
+		 timeout,  ret < 0 ? " failed" : "");
+
+}
+
 /*
  * Monitor the modem and update the stat
  * return 0 if everything is ok
  * return < 0 if an error occurs (-EAGAIN reboot needed)
  */
-static int uea_stat(struct uea_softc *sc)
+static int uea_stat_e1(struct uea_softc *sc)
 {
 	u32 data;
 	int ret;
@@ -865,7 +1290,7 @@
 	uea_enters(INS_TO_USBDEV(sc));
 	data = sc->stats.phy.state;
 
-	ret = uea_read_cmv(sc, SA_STAT, 0, &sc->stats.phy.state);
+	ret = uea_read_cmv_e1(sc, E1_SA_STAT, 0, &sc->stats.phy.state);
 	if (ret < 0)
 		return ret;
 
@@ -885,7 +1310,7 @@
 
 	case 3:		/* fail ... */
 		uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
-				" (may be try other cmv/dsp)\n");
+					" (may be try other cmv/dsp)\n");
 		return -EAGAIN;
 
 	case 4 ... 6:	/* test state */
@@ -923,7 +1348,7 @@
 	/* wake up processes waiting for synchronization */
 	wake_up(&sc->sync_q);
 
-	ret = uea_read_cmv(sc, SA_DIAG, 2, &sc->stats.phy.flags);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 2, &sc->stats.phy.flags);
 	if (ret < 0)
 		return ret;
 	sc->stats.phy.mflags |= sc->stats.phy.flags;
@@ -937,105 +1362,223 @@
 		return 0;
 	}
 
-	ret = uea_read_cmv(sc, SA_RATE, 0, &data);
+	ret = uea_read_cmv_e1(sc, E1_SA_RATE, 0, &data);
 	if (ret < 0)
 		return ret;
 
-	/* in bulk mode the modem have problem with high rate
-	 * changing internal timing could improve things, but the
-	 * value is misterious.
-	 * ADI930 don't support it (-EPIPE error).
-	 */
-	if (UEA_CHIP_VERSION(sc) != ADI930
-		    && !use_iso[sc->modem_index]
-		    && sc->stats.phy.dsrate != (data >> 16) * 32) {
-		/* Original timming from ADI(used in windows driver)
-		 * 0x20ffff>>16 * 32 = 32 * 32 = 1Mbits
-		 */
-		u16 timeout = (data <= 0x20ffff) ? 0 : 1;
-		ret = uea_request(sc, UEA_SET_TIMEOUT, timeout, 0, NULL);
-		uea_info(INS_TO_USBDEV(sc),
-				"setting new timeout %d%s\n", timeout,
-				ret < 0?" failed":"");
-	}
+	uea_set_bulk_timeout(sc, (data >> 16) * 32);
 	sc->stats.phy.dsrate = (data >> 16) * 32;
 	sc->stats.phy.usrate = (data & 0xffff) * 32;
 	UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424);
 
-	ret = uea_read_cmv(sc, SA_DIAG, 23, &data);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 23, &data);
 	if (ret < 0)
 		return ret;
 	sc->stats.phy.dsattenuation = (data & 0xff) / 2;
 
-	ret = uea_read_cmv(sc, SA_DIAG, 47, &data);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 47, &data);
 	if (ret < 0)
 		return ret;
 	sc->stats.phy.usattenuation = (data & 0xff) / 2;
 
-	ret = uea_read_cmv(sc, SA_DIAG, 25, &sc->stats.phy.dsmargin);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 25, &sc->stats.phy.dsmargin);
 	if (ret < 0)
 		return ret;
 
-	ret = uea_read_cmv(sc, SA_DIAG, 49, &sc->stats.phy.usmargin);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 49, &sc->stats.phy.usmargin);
 	if (ret < 0)
 		return ret;
 
-	ret = uea_read_cmv(sc, SA_DIAG, 51, &sc->stats.phy.rxflow);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 51, &sc->stats.phy.rxflow);
 	if (ret < 0)
 		return ret;
 
-	ret = uea_read_cmv(sc, SA_DIAG, 52, &sc->stats.phy.txflow);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 52, &sc->stats.phy.txflow);
 	if (ret < 0)
 		return ret;
 
-	ret = uea_read_cmv(sc, SA_DIAG, 54, &sc->stats.phy.dsunc);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 54, &sc->stats.phy.dsunc);
 	if (ret < 0)
 		return ret;
 
 	/* only for atu-c */
-	ret = uea_read_cmv(sc, SA_DIAG, 58, &sc->stats.phy.usunc);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 58, &sc->stats.phy.usunc);
 	if (ret < 0)
 		return ret;
 
-	ret = uea_read_cmv(sc, SA_DIAG, 53, &sc->stats.phy.dscorr);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 53, &sc->stats.phy.dscorr);
 	if (ret < 0)
 		return ret;
 
 	/* only for atu-c */
-	ret = uea_read_cmv(sc, SA_DIAG, 57, &sc->stats.phy.uscorr);
+	ret = uea_read_cmv_e1(sc, E1_SA_DIAG, 57, &sc->stats.phy.uscorr);
 	if (ret < 0)
 		return ret;
 
-	ret = uea_read_cmv(sc, SA_INFO, 8, &sc->stats.phy.vidco);
+	ret = uea_read_cmv_e1(sc, E1_SA_INFO, 8, &sc->stats.phy.vidco);
 	if (ret < 0)
 		return ret;
 
-	ret = uea_read_cmv(sc, SA_INFO, 13, &sc->stats.phy.vidcpe);
+	ret = uea_read_cmv_e1(sc, E1_SA_INFO, 13, &sc->stats.phy.vidcpe);
 	if (ret < 0)
 		return ret;
 
 	return 0;
 }
 
-static int request_cmvs(struct uea_softc *sc,
-		 struct uea_cmvs **cmvs, const struct firmware **fw)
+static int uea_stat_e4(struct uea_softc *sc)
 {
-	int ret, size;
-	u8 *data;
-	char *file;
-	char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+	u32 data;
+	u32 tmp_arr[2];
+	int ret;
 
+	uea_enters(INS_TO_USBDEV(sc));
+	data = sc->stats.phy.state;
+
+	/* XXX only need to be done before operationnal... */
+	ret = uea_read_cmv_e4(sc, 1, E4_SA_STAT, 0, 0, &sc->stats.phy.state);
+	if (ret < 0)
+		return ret;
+
+	switch (sc->stats.phy.state) {
+		case 0x0:	/* not yet synchronized */
+		case 0x1:
+		case 0x3:
+		case 0x4:
+			uea_dbg(INS_TO_USBDEV(sc), "modem not yet synchronized\n");
+			return 0;
+		case 0x5:	/* initialization */
+		case 0x6:
+		case 0x9:
+		case 0xa:
+			uea_dbg(INS_TO_USBDEV(sc), "modem initializing\n");
+			return 0;
+		case 0x2:	/* fail ... */
+			uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
+					" (may be try other cmv/dsp)\n");
+			return -EAGAIN;
+		case 0x7: 	/* operational */
+			break;
+		default:
+			uea_warn(INS_TO_USBDEV(sc), "unknown state: %x\n", sc->stats.phy.state);
+			return 0;
+	}
+
+	if (data != 7) {
+		uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_OFF, 0, NULL);
+		uea_info(INS_TO_USBDEV(sc), "modem operational\n");
+
+		/* release the dsp firmware as it is not needed until
+		 * the next failure
+		 */
+		if (sc->dsp_firm) {
+			release_firmware(sc->dsp_firm);
+			sc->dsp_firm = NULL;
+		}
+	}
+
+	/* always update it as atm layer could not be init when we switch to
+	 * operational state
+	 */
+	UPDATE_ATM_STAT(signal, ATM_PHY_SIG_FOUND);
+
+	/* wake up processes waiting for synchronization */
+	wake_up(&sc->sync_q);
+
+	/* TODO improve this state machine :
+	 * we need some CMV info : what they do and their unit
+	 * we should find the equivalent of eagle3- CMV
+	 */
+	/* check flags */
+	ret = uea_read_cmv_e4(sc, 1, E4_SA_DIAG, 0, 0, &sc->stats.phy.flags);
+	if (ret < 0)
+		return ret;
+	sc->stats.phy.mflags |= sc->stats.phy.flags;
+
+	/* in case of a flags ( for example delineation LOSS (& 0x10)),
+	 * we check the status again in order to detect the failure earlier
+	 */
+	if (sc->stats.phy.flags) {
+		uea_dbg(INS_TO_USBDEV(sc), "Stat flag = 0x%x\n",
+		       sc->stats.phy.flags);
+		if (sc->stats.phy.flags & 1) //delineation LOSS
+			return -EAGAIN;
+		if (sc->stats.phy.flags & 0x4000) //Reset Flag
+			return -EAGAIN;
+		return 0;
+	}
+
+	/* rate data may be in upper or lower half of 64 bit word, strange */
+	ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 0, 0, tmp_arr);
+	if (ret < 0)
+		return ret;
+	data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
+	sc->stats.phy.usrate = data / 1000;
+
+	ret = uea_read_cmv_e4(sc, 4, E4_SA_RATE, 1, 0, tmp_arr);
+	if (ret < 0)
+		return ret;
+	data = (tmp_arr[0]) ? tmp_arr[0] : tmp_arr[1];
+	uea_set_bulk_timeout(sc, data / 1000);
+	sc->stats.phy.dsrate = data / 1000;
+	UPDATE_ATM_STAT(link_rate, sc->stats.phy.dsrate * 1000 / 424);
+
+	ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 1, &data);
+	if (ret < 0)
+		return ret;
+	sc->stats.phy.dsattenuation = data / 10;
+
+	ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 1, &data);
+	if (ret < 0)
+		return ret;
+	sc->stats.phy.usattenuation = data / 10;
+
+	ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 68, 3, &data);
+	if (ret < 0)
+		return ret;
+	sc->stats.phy.dsmargin = data / 2;
+
+	ret = uea_read_cmv_e4(sc, 1, E4_SA_INFO, 69, 3, &data);
+	if (ret < 0)
+		return ret;
+	sc->stats.phy.usmargin = data / 10;
+
+	return 0;
+}
+
+static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver)
+{
+	char file_arr[] = "CMVxy.bin";
+	char *file;
+
+	/* set proper name corresponding modem version and line type */
 	if (cmv_file[sc->modem_index] == NULL) {
 		if (UEA_CHIP_VERSION(sc) == ADI930)
-			file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin";
+			file_arr[3] = '9';
+		else if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+			file_arr[3] = '4';
 		else
-			file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin";
+			file_arr[3] = 'e';
+
+		file_arr[4] = IS_ISDN(sc) ? 'i' : 'p';
+		file = file_arr;
 	} else
 		file = cmv_file[sc->modem_index];
 
 	strcpy(cmv_name, FW_DIR);
-	strlcat(cmv_name, file, sizeof(cmv_name));
+	strlcat(cmv_name, file, FIRMWARE_NAME_MAX);
+	if (ver == 2)
+		strlcat(cmv_name, ".v2", FIRMWARE_NAME_MAX);
+}
 
+static int request_cmvs_old(struct uea_softc *sc,
+		 void **cmvs, const struct firmware **fw)
+{
+	int ret, size;
+	u8 *data;
+	char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+
+	cmvs_file_name(sc, cmv_name, 1);
 	ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
 	if (ret < 0) {
 		uea_err(INS_TO_USBDEV(sc),
@@ -1045,16 +1588,197 @@
 	}
 
 	data = (u8 *) (*fw)->data;
-	size = *data * sizeof(struct uea_cmvs) + 1;
-	if (size != (*fw)->size) {
-		uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n",
-		       cmv_name);
-		release_firmware(*fw);
-		return -EILSEQ;
+	size = (*fw)->size;
+	if (size < 1)
+		goto err_fw_corrupted;
+
+	if (size != *data * sizeof(struct uea_cmvs_v1) + 1)
+		goto err_fw_corrupted;
+
+	*cmvs = (void *)(data + 1);
+	return *data;
+
+err_fw_corrupted:
+	uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);
+	release_firmware(*fw);
+	return -EILSEQ;
+}
+
+static int request_cmvs(struct uea_softc *sc,
+		 void **cmvs, const struct firmware **fw, int *ver)
+{
+	int ret, size;
+	u32 crc;
+	u8 *data;
+	char cmv_name[FIRMWARE_NAME_MAX]; /* 30 bytes stack variable */
+
+	cmvs_file_name(sc, cmv_name, 2);
+	ret = request_firmware(fw, cmv_name, &sc->usb_dev->dev);
+	if (ret < 0) {
+		/* if caller can handle old version, try to provide it */
+		if (*ver == 1) {
+			uea_warn(INS_TO_USBDEV(sc), "requesting firmware %s failed, "
+				"try to get older cmvs\n", cmv_name);
+			return request_cmvs_old(sc, cmvs, fw);
+		}
+		uea_err(INS_TO_USBDEV(sc),
+		       "requesting firmware %s failed with error %d\n",
+		       cmv_name, ret);
+		return ret;
 	}
 
-	*cmvs = (struct uea_cmvs *)(data + 1);
+	size = (*fw)->size;
+	data = (u8 *) (*fw)->data;
+	if (size < 4 || strncmp(data, "cmv2", 4) != 0) {
+		if (*ver == 1) {
+			uea_warn(INS_TO_USBDEV(sc), "firmware %s is corrupted, "
+				"try to get older cmvs\n", cmv_name);
+			release_firmware(*fw);
+			return request_cmvs_old(sc, cmvs, fw);
+		}
+		goto err_fw_corrupted;
+	}
+
+	*ver = 2;
+
+	data += 4;
+	size -= 4;
+	if (size < 5)
+		goto err_fw_corrupted;
+
+	crc = FW_GET_LONG(data);
+	data += 4;
+	size -= 4;
+	if (crc32_be(0, data, size) != crc)
+		goto err_fw_corrupted;
+
+	if (size != *data * sizeof(struct uea_cmvs_v2) + 1)
+		goto err_fw_corrupted;
+
+	*cmvs = (void *) (data + 1);
 	return *data;
+
+err_fw_corrupted:
+	uea_err(INS_TO_USBDEV(sc), "firmware %s is corrupted\n", cmv_name);
+	release_firmware(*fw);
+	return -EILSEQ;
+}
+
+static int uea_send_cmvs_e1(struct uea_softc *sc)
+{
+	int i, ret, len;
+	void *cmvs_ptr;
+	const struct firmware *cmvs_fw;
+	int ver = 1; // we can handle v1 cmv firmware version;
+
+	/* Enter in R-IDLE (cmv) until instructed otherwise */
+	ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 1);
+	if (ret < 0)
+		return ret;
+
+	/* Dump firmware version */
+	ret = uea_read_cmv_e1(sc, E1_SA_INFO, 10, &sc->stats.phy.firmid);
+	if (ret < 0)
+		return ret;
+	uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+			sc->stats.phy.firmid);
+
+	/* get options */
+ 	ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
+	if (ret < 0)
+		return ret;
+
+	/* send options */
+	if (ver == 1) {
+		struct uea_cmvs_v1 *cmvs_v1 = cmvs_ptr;
+
+		uea_warn(INS_TO_USBDEV(sc), "use deprecated cmvs version, "
+			"please update your firmware\n");
+
+		for (i = 0; i < len; i++) {
+			ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address),
+						FW_GET_WORD(&cmvs_v1[i].offset),
+						FW_GET_LONG(&cmvs_v1[i].data));
+			if (ret < 0)
+				goto out;
+		}
+	} else if (ver == 2) {
+		struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
+
+		for (i = 0; i < len; i++) {
+			ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address),
+						(u16) FW_GET_LONG(&cmvs_v2[i].offset),
+						FW_GET_LONG(&cmvs_v2[i].data));
+			if (ret < 0)
+				goto out;
+		}
+	} else {
+		/* This realy should not happen */
+		uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);
+		goto out;
+	}
+
+	/* Enter in R-ACT-REQ */
+	ret = uea_write_cmv_e1(sc, E1_SA_CNTL, 0, 2);
+	uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+	uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
+out:
+	release_firmware(cmvs_fw);
+	return ret;
+}
+
+static int uea_send_cmvs_e4(struct uea_softc *sc)
+{
+	int i, ret, len;
+	void *cmvs_ptr;
+	const struct firmware *cmvs_fw;
+	int ver = 2; // we can only handle v2 cmv firmware version;
+
+	/* Enter in R-IDLE (cmv) until instructed otherwise */
+	ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 1);
+	if (ret < 0)
+		return ret;
+
+	/* Dump firmware version */
+	/* XXX don't read the 3th byte as it is always 6 */
+	ret = uea_read_cmv_e4(sc, 2, E4_SA_INFO, 55, 0, &sc->stats.phy.firmid);
+	if (ret < 0)
+		return ret;
+	uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+			sc->stats.phy.firmid);
+
+
+	/* get options */
+ 	ret = len = request_cmvs(sc, &cmvs_ptr, &cmvs_fw, &ver);
+	if (ret < 0)
+		return ret;
+
+	/* send options */
+	if (ver == 2) {
+		struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
+
+		for (i = 0; i < len; i++) {
+			ret = uea_write_cmv_e4(sc, 1,
+						FW_GET_LONG(&cmvs_v2[i].group),
+						FW_GET_LONG(&cmvs_v2[i].address),
+						FW_GET_LONG(&cmvs_v2[i].offset),
+						FW_GET_LONG(&cmvs_v2[i].data));
+			if (ret < 0)
+				goto out;
+		}
+	} else {
+		/* This realy should not happen */
+		uea_err(INS_TO_USBDEV(sc), "bad cmvs version %d\n", ver);
+		goto out;
+	}
+
+	/* Enter in R-ACT-REQ */
+	ret = uea_write_cmv_e4(sc, 1, E4_SA_CNTL, 0, 0, 2);
+	uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+	uea_info(INS_TO_USBDEV(sc), "modem started, waiting synchronization...\n");
+out:
+	release_firmware(cmvs_fw);
+	return ret;
 }
 
 /* Start boot post firmware modem:
@@ -1066,9 +1790,7 @@
 static int uea_start_reset(struct uea_softc *sc)
 {
 	u16 zero = 0;	/* ;-) */
-	int i, len, ret;
-	struct uea_cmvs *cmvs;
-	const struct firmware *cmvs_fw;
+	int ret;
 
 	uea_enters(INS_TO_USBDEV(sc));
 	uea_info(INS_TO_USBDEV(sc), "(re)booting started\n");
@@ -1093,25 +1815,36 @@
 	uea_request(sc, UEA_SET_MODE, UEA_START_RESET, 0, NULL);
 
 	/* original driver use 200ms, but windows driver use 100ms */
-	msleep(100);
+	ret = uea_wait(sc, 0, msecs_to_jiffies(100));
+	if (ret < 0)
+		return ret;
 
 	/* leave reset mode */
 	uea_request(sc, UEA_SET_MODE, UEA_END_RESET, 0, NULL);
 
- 	/* clear tx and rx mailboxes */
-	uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
-	uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
-	uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
+	if (UEA_CHIP_VERSION(sc) != EAGLE_IV) {
+ 		/* clear tx and rx mailboxes */
+		uea_request(sc, UEA_SET_2183_DATA, UEA_MPTX_MAILBOX, 2, &zero);
+		uea_request(sc, UEA_SET_2183_DATA, UEA_MPRX_MAILBOX, 2, &zero);
+		uea_request(sc, UEA_SET_2183_DATA, UEA_SWAP_MAILBOX, 2, &zero);
+	}
 
-	msleep(1000);
-	sc->cmv_function = MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY);
+	ret = uea_wait(sc, 0, msecs_to_jiffies(1000));
+	if (ret < 0)
+		return ret;
+
+	if (UEA_CHIP_VERSION(sc) == EAGLE_IV)
+		sc->cmv_dsc.e4.function = E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1);
+	else
+		sc->cmv_dsc.e1.function = E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY);
+
 	/* demask interrupt */
 	sc->booting = 0;
 
 	/* start loading DSP */
 	sc->pageno = 0;
 	sc->ovl = 0;
-	schedule_work(&sc->task);
+	queue_work(sc->work_q, &sc->task);
 
 	/* wait for modem ready CMV */
 	ret = wait_cmv_ack(sc);
@@ -1120,38 +1853,10 @@
 
 	uea_vdbg(INS_TO_USBDEV(sc), "Ready CMV received\n");
 
-	/* Enter in R-IDLE (cmv) until instructed otherwise */
-	ret = uea_write_cmv(sc, SA_CNTL, 0, 1);
+	ret = sc->send_cmvs(sc);
 	if (ret < 0)
 		return ret;
 
-	/* Dump firmware version */
-	ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
-	if (ret < 0)
-		return ret;
-	uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
-			sc->stats.phy.firmid);
-
-	/* get options */
- 	ret = len = request_cmvs(sc, &cmvs, &cmvs_fw);
-	if (ret < 0)
-		return ret;
-
-	/* send options */
-	for (i = 0; i < len; i++) {
-		ret = uea_write_cmv(sc, FW_GET_LONG(&cmvs[i].address),
-					FW_GET_WORD(&cmvs[i].offset),
-					FW_GET_LONG(&cmvs[i].data));
-		if (ret < 0)
-			goto out;
-	}
-	/* Enter in R-ACT-REQ */
-	ret = uea_write_cmv(sc, SA_CNTL, 0, 2);
-	uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
-	uea_info(INS_TO_USBDEV(sc), "Modem started, "
-		"waiting synchronization\n");
-out:
-	release_firmware(cmvs_fw);
 	sc->reset = 0;
 	uea_leaves(INS_TO_USBDEV(sc));
 	return ret;
@@ -1174,12 +1879,10 @@
 		if (ret < 0 || sc->reset)
 			ret = uea_start_reset(sc);
 		if (!ret)
-			ret = uea_stat(sc);
+			ret = sc->stat(sc);
 		if (ret != -EAGAIN)
-			msleep_interruptible(1000);
- 		if (try_to_freeze())
-			uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, "
-				"please unplug/replug your modem\n");
+			uea_wait(sc, 0, msecs_to_jiffies(1000));
+		try_to_freeze();
 	}
 	uea_leaves(INS_TO_USBDEV(sc));
 	return ret;
@@ -1234,7 +1937,6 @@
 	if (ret < 0)
 		uea_err(sc->usb_dev, "elsa de-assert failed with error %d\n", ret);
 
-
 err1:
 	release_firmware(fw_entry);
 err0:
@@ -1243,40 +1945,41 @@
 }
 
 /* The modem send us an ack. First with check if it right */
-static void uea_dispatch_cmv(struct uea_softc *sc, struct cmv* cmv)
+static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr)
 {
+	struct cmv_dsc_e1 *dsc = &sc->cmv_dsc.e1;
+	struct cmv_e1 *cmv = &intr->u.e1.s2.cmv;
+
 	uea_enters(INS_TO_USBDEV(sc));
-	if (le16_to_cpu(cmv->wPreamble) != PREAMBLE)
+	if (le16_to_cpu(cmv->wPreamble) != E1_PREAMBLE)
 		goto bad1;
 
-	if (cmv->bDirection != MODEMTOHOST)
+	if (cmv->bDirection != E1_MODEMTOHOST)
 		goto bad1;
 
 	/* FIXME : ADI930 reply wrong preambule (func = 2, sub = 2) to
 	 * the first MEMACESS cmv. Ignore it...
 	 */
-	if (cmv->bFunction != sc->cmv_function) {
+	if (cmv->bFunction != dsc->function) {
 		if (UEA_CHIP_VERSION(sc) == ADI930
-				&& cmv->bFunction ==  MAKEFUNCTION(2, 2)) {
-			cmv->wIndex = cpu_to_le16(sc->cmv_idx);
-			put_unaligned(cpu_to_le32(sc->cmv_address), &cmv->dwSymbolicAddress);
-			cmv->wOffsetAddress = cpu_to_le16(sc->cmv_offset);
-		}
-		else
+				&& cmv->bFunction ==  E1_MAKEFUNCTION(2, 2)) {
+			cmv->wIndex = cpu_to_le16(dsc->idx);
+			put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress);
+			cmv->wOffsetAddress = cpu_to_le16(dsc->offset);
+		} else
 			goto bad2;
 	}
 
-	if (cmv->bFunction == MAKEFUNCTION(ADSLDIRECTIVE, MODEMREADY)) {
+	if (cmv->bFunction == E1_MAKEFUNCTION(E1_ADSLDIRECTIVE, E1_MODEMREADY)) {
 		wake_up_cmv_ack(sc);
 		uea_leaves(INS_TO_USBDEV(sc));
 		return;
 	}
 
 	/* in case of MEMACCESS */
-	if (le16_to_cpu(cmv->wIndex) != sc->cmv_idx ||
-	    le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) !=
-	    sc->cmv_address
-	    || le16_to_cpu(cmv->wOffsetAddress) != sc->cmv_offset)
+	if (le16_to_cpu(cmv->wIndex) != dsc->idx ||
+	    le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address ||
+	    le16_to_cpu(cmv->wOffsetAddress) != dsc->offset)
 		goto bad2;
 
 	sc->data = le32_to_cpu(get_unaligned(&cmv->dwData));
@@ -1289,8 +1992,8 @@
 bad2:
 	uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
 			"Function : %d, Subfunction : %d\n",
-			FUNCTION_TYPE(cmv->bFunction),
-			FUNCTION_SUBTYPE(cmv->bFunction));
+			E1_FUNCTION_TYPE(cmv->bFunction),
+			E1_FUNCTION_SUBTYPE(cmv->bFunction));
 	uea_leaves(INS_TO_USBDEV(sc));
 	return;
 
@@ -1301,6 +2004,61 @@
 	uea_leaves(INS_TO_USBDEV(sc));
 }
 
+/* The modem send us an ack. First with check if it right */
+static void uea_dispatch_cmv_e4(struct uea_softc *sc, struct intr_pkt *intr)
+{
+	struct cmv_dsc_e4 *dsc = &sc->cmv_dsc.e4;
+	struct cmv_e4 *cmv = &intr->u.e4.s2.cmv;
+
+	uea_enters(INS_TO_USBDEV(sc));
+	uea_dbg(INS_TO_USBDEV(sc), "cmv %x %x %x %x %x %x\n",
+		be16_to_cpu(cmv->wGroup), be16_to_cpu(cmv->wFunction),
+		be16_to_cpu(cmv->wOffset), be16_to_cpu(cmv->wAddress),
+		be32_to_cpu(cmv->dwData[0]), be32_to_cpu(cmv->dwData[1]));
+
+	if (be16_to_cpu(cmv->wFunction) != dsc->function)
+		goto bad2;
+
+	if (be16_to_cpu(cmv->wFunction) == E4_MAKEFUNCTION(E4_ADSLDIRECTIVE, E4_MODEMREADY, 1)) {
+		wake_up_cmv_ack(sc);
+		uea_leaves(INS_TO_USBDEV(sc));
+		return;
+	}
+
+	/* in case of MEMACCESS */
+	if (be16_to_cpu(cmv->wOffset) != dsc->offset ||
+	    be16_to_cpu(cmv->wGroup) != dsc->group ||
+	    be16_to_cpu(cmv->wAddress) != dsc->address)
+		goto bad2;
+
+	sc->data = be32_to_cpu(cmv->dwData[0]);
+	sc->data1 = be32_to_cpu(cmv->dwData[1]);
+	wake_up_cmv_ack(sc);
+	uea_leaves(INS_TO_USBDEV(sc));
+	return;
+
+bad2:
+	uea_err(INS_TO_USBDEV(sc), "unexpected cmv received,"
+			"Function : %d, Subfunction : %d\n",
+			E4_FUNCTION_TYPE(cmv->wFunction),
+			E4_FUNCTION_SUBTYPE(cmv->wFunction));
+	uea_leaves(INS_TO_USBDEV(sc));
+	return;
+}
+
+static void uea_schedule_load_page_e1(struct uea_softc *sc, struct intr_pkt *intr)
+{
+	sc->pageno = intr->e1_bSwapPageNo;
+	sc->ovl = intr->e1_bOvl >> 4 | intr->e1_bOvl << 4;
+	queue_work(sc->work_q, &sc->task);
+}
+
+static void uea_schedule_load_page_e4(struct uea_softc *sc, struct intr_pkt *intr)
+{
+	sc->pageno = intr->e4_bSwapPageNo;
+	queue_work(sc->work_q, &sc->task);
+}
+
 /*
  * interrupt handler
  */
@@ -1308,11 +2066,13 @@
 {
 	struct uea_softc *sc = urb->context;
 	struct intr_pkt *intr = urb->transfer_buffer;
+	int status = urb->status;
+
 	uea_enters(INS_TO_USBDEV(sc));
 
-	if (unlikely(urb->status < 0)) {
+	if (unlikely(status < 0)) {
 		uea_err(INS_TO_USBDEV(sc), "uea_intr() failed with %d\n",
-		       urb->status);
+		       status);
 		return;
 	}
 
@@ -1324,13 +2084,11 @@
 
 	switch (le16_to_cpu(intr->wInterrupt)) {
 	case INT_LOADSWAPPAGE:
-		sc->pageno = intr->bSwapPageNo;
-		sc->ovl = intr->bOvl >> 4 | intr->bOvl << 4;
-		schedule_work(&sc->task);
+		sc->schedule_load_page(sc, intr);
 		break;
 
 	case INT_INCOMINGCMV:
-		uea_dispatch_cmv(sc, &intr->u.s2.cmv);
+		sc->dispatch_cmv(sc, intr);
 		break;
 
 	default:
@@ -1347,35 +2105,55 @@
  */
 static int uea_boot(struct uea_softc *sc)
 {
-	int ret;
+	int ret, size;
 	struct intr_pkt *intr;
 
 	uea_enters(INS_TO_USBDEV(sc));
 
-	INIT_WORK(&sc->task, uea_load_page);
+	if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+		size = E4_INTR_PKT_SIZE;
+		sc->dispatch_cmv = uea_dispatch_cmv_e4;
+		sc->schedule_load_page = uea_schedule_load_page_e4;
+		sc->stat = uea_stat_e4;
+		sc->send_cmvs = uea_send_cmvs_e4;
+		INIT_WORK(&sc->task, uea_load_page_e4);
+	} else {
+		size = E1_INTR_PKT_SIZE;
+		sc->dispatch_cmv = uea_dispatch_cmv_e1;
+		sc->schedule_load_page = uea_schedule_load_page_e1;
+		sc->stat = uea_stat_e1;
+		sc->send_cmvs = uea_send_cmvs_e1;
+		INIT_WORK(&sc->task, uea_load_page_e1);
+	}
+
 	init_waitqueue_head(&sc->sync_q);
-	init_waitqueue_head(&sc->cmv_ack_wait);
+
+	sc->work_q = create_workqueue("ueagle-dsp");
+	if (!sc->work_q) {
+		uea_err(INS_TO_USBDEV(sc), "cannot allocate workqueue\n");
+		uea_leaves(INS_TO_USBDEV(sc));
+		return -ENOMEM;
+	}
 
 	if (UEA_CHIP_VERSION(sc) == ADI930)
 		load_XILINX_firmware(sc);
 
-	intr = kmalloc(INTR_PKT_SIZE, GFP_KERNEL);
+	intr = kmalloc(size, GFP_KERNEL);
 	if (!intr) {
 		uea_err(INS_TO_USBDEV(sc),
 		       "cannot allocate interrupt package\n");
-		uea_leaves(INS_TO_USBDEV(sc));
-		return -ENOMEM;
+		goto err0;
 	}
 
 	sc->urb_int = usb_alloc_urb(0, GFP_KERNEL);
 	if (!sc->urb_int) {
 		uea_err(INS_TO_USBDEV(sc), "cannot allocate interrupt URB\n");
-		goto err;
+		goto err1;
 	}
 
 	usb_fill_int_urb(sc->urb_int, sc->usb_dev,
 			 usb_rcvintpipe(sc->usb_dev, UEA_INTR_PIPE),
-			 intr, INTR_PKT_SIZE, uea_intr, sc,
+			 intr, size, uea_intr, sc,
 			 sc->usb_dev->actconfig->interface[0]->altsetting[0].
 			 endpoint[0].desc.bInterval);
 
@@ -1383,7 +2161,7 @@
 	if (ret < 0) {
 		uea_err(INS_TO_USBDEV(sc),
 		       "urb submition failed with error %d\n", ret);
-		goto err;
+		goto err1;
 	}
 
 	sc->kthread = kthread_run(uea_kthread, sc, "ueagle-atm");
@@ -1397,10 +2175,12 @@
 
 err2:
 	usb_kill_urb(sc->urb_int);
-err:
+err1:
 	usb_free_urb(sc->urb_int);
 	sc->urb_int = NULL;
 	kfree(intr);
+err0:
+	destroy_workqueue(sc->work_q);
 	uea_leaves(INS_TO_USBDEV(sc));
 	return -ENOMEM;
 }
@@ -1415,15 +2195,15 @@
 	ret = kthread_stop(sc->kthread);
 	uea_dbg(INS_TO_USBDEV(sc), "kthread finish with status %d\n", ret);
 
-	/* stop any pending boot process */
-	flush_scheduled_work();
-
 	uea_request(sc, UEA_SET_MODE, UEA_LOOPBACK_ON, 0, NULL);
 
 	usb_kill_urb(sc->urb_int);
 	kfree(sc->urb_int->transfer_buffer);
 	usb_free_urb(sc->urb_int);
 
+	/* stop any pending boot process, when no one can schedule work */
+	destroy_workqueue(sc->work_q);
+
 	if (sc->dsp_firm)
 		release_firmware(sc->dsp_firm);
 	uea_leaves(INS_TO_USBDEV(sc));
@@ -1485,6 +2265,7 @@
 		char *buf)
 {
 	int ret = -ENODEV;
+	int modem_state;
 	struct uea_softc *sc;
 
 	mutex_lock(&uea_mutex);
@@ -1492,7 +2273,34 @@
 	if (!sc)
 		goto out;
 
-	switch (GET_STATUS(sc->stats.phy.state)) {
+	if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+		switch (sc->stats.phy.state) {
+		case 0x0:	/* not yet synchronized */
+		case 0x1:
+		case 0x3:
+		case 0x4:
+			modem_state = 0;
+			break;
+		case 0x5:	/* initialization */
+		case 0x6:
+		case 0x9:
+		case 0xa:
+			modem_state = 1;
+			break;
+		case 0x7: 	/* operational */
+			modem_state = 2;
+			break;
+		case 0x2:	/* fail ... */
+			modem_state = 3;
+			break;
+		default:	/* unknown */
+			modem_state = 4;
+			break;
+		}
+	} else
+		modem_state = GET_STATUS(sc->stats.phy.state);
+
+	switch (modem_state) {
 	case 0:
 		ret = sprintf(buf, "Modem is booting\n");
 		break;
@@ -1502,9 +2310,12 @@
 	case 2:
 		ret = sprintf(buf, "Modem is operational\n");
 		break;
-	default:
+	case 3:
 		ret = sprintf(buf, "Modem synchronization failed\n");
 		break;
+	default:
+		ret = sprintf(buf, "Modem state is unknown\n");
+		break;
 	}
 out:
 	mutex_unlock(&uea_mutex);
@@ -1518,18 +2329,26 @@
 {
 	int ret = -ENODEV;
 	struct uea_softc *sc;
+	char *delin = "GOOD";
 
 	mutex_lock(&uea_mutex);
 	sc = dev_to_uea(dev);
 	if (!sc)
 		goto out;
 
-	if (sc->stats.phy.flags & 0x0C00)
-		ret = sprintf(buf, "ERROR\n");
-	else if (sc->stats.phy.flags & 0x0030)
-		ret = sprintf(buf, "LOSS\n");
-	else
-		ret = sprintf(buf, "GOOD\n");
+	if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
+		if (sc->stats.phy.flags & 0x4000)
+			delin = "RESET";
+		else if (sc->stats.phy.flags & 0x0001)
+			delin = "LOSS";
+	} else {
+		if (sc->stats.phy.flags & 0x0C00)
+			delin = "ERROR";
+		else if (sc->stats.phy.flags & 0x0030)
+			delin = "LOSS";
+	}
+
+	ret = sprintf(buf, "%s\n", delin);
 out:
 	mutex_unlock(&uea_mutex);
 	return ret;
@@ -1660,6 +2479,7 @@
 	struct usb_device *usb = interface_to_usbdev(intf);
 	struct uea_softc *sc;
 	int ret, ifnum = intf->altsetting->desc.bInterfaceNumber;
+	unsigned int alt;
 
 	uea_enters(usb);
 
@@ -1694,22 +2514,29 @@
 	sc->modem_index = (modem_index < NB_MODEM) ? modem_index++ : 0;
 	sc->driver_info = id->driver_info;
 
+	/* first try to use module parameter */
+	if (annex[sc->modem_index] == 1)
+		sc->annex = ANNEXA;
+	else if (annex[sc->modem_index] == 2)
+		sc->annex = ANNEXB;
+	/* try to autodetect annex */
+	else if (sc->driver_info & AUTO_ANNEX_A)
+		sc->annex = ANNEXA;
+	else if (sc->driver_info & AUTO_ANNEX_B)
+		sc->annex = ANNEXB;
+	else
+		sc->annex = (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)?ANNEXB:ANNEXA;
+
+	alt = altsetting[sc->modem_index];
 	/* ADI930 don't support iso */
-	if (UEA_CHIP_VERSION(id) != ADI930 && use_iso[sc->modem_index]) {
-		int i;
-
-		/* try set fastest alternate for inbound traffic interface */
-		for (i = FASTEST_ISO_INTF; i > 0; i--)
-			if (usb_set_interface(usb, UEA_DS_IFACE_NO, i) == 0)
-				break;
-
-		if (i > 0) {
-			uea_dbg(usb, "set alternate %d for 2 interface\n", i);
+	if (UEA_CHIP_VERSION(id) != ADI930 && alt > 0) {
+		if (alt <= 8 && usb_set_interface(usb, UEA_DS_IFACE_NO, alt) == 0) {
+			uea_dbg(usb, "set alternate %u for 2 interface\n", alt);
 			uea_info(usb, "using iso mode\n");
 			usbatm->flags |= UDSL_USE_ISOC | UDSL_IGNORE_EILSEQ;
 		} else {
-			uea_err(usb, "setting any alternate failed for "
-					"2 interface, using bulk mode\n");
+			uea_err(usb, "setting alternate %u failed for "
+					"2 interface, using bulk mode\n", alt);
 		}
 	}
 
@@ -1719,9 +2546,12 @@
 
 	ret = uea_boot(sc);
 	if (ret < 0)
-		goto error;
+		goto error_rm_grp;
 
 	return 0;
+
+error_rm_grp:
+	sysfs_remove_group(&intf->dev.kobj, &attr_grp);
 error:
 	kfree(sc);
 	return ret;
@@ -1752,10 +2582,11 @@
 	struct usb_device *usb = interface_to_usbdev(intf);
 
 	uea_enters(usb);
-	uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n",
-	       le16_to_cpu(usb->descriptor.idVendor),
-	       le16_to_cpu(usb->descriptor.idProduct),
-	       chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots");
+	uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) Rev (%#X): %s\n",
+		le16_to_cpu(usb->descriptor.idVendor),
+		le16_to_cpu(usb->descriptor.idProduct),
+		le16_to_cpu(usb->descriptor.bcdDevice),
+		chip_name[UEA_CHIP_VERSION(id)]);
 
 	usb_reset_device(usb);
 
@@ -1788,24 +2619,40 @@
  * List of supported VID/PID
  */
 static const struct usb_device_id uea_ids[] = {
+	{USB_DEVICE(ANALOG_VID,	ADI930_PID_PREFIRM),	.driver_info = ADI930 | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	ADI930_PID_PSTFIRM),	.driver_info = ADI930 | PSTFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_I_PID_PREFIRM),	.driver_info = EAGLE_I | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_I_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_II_PID_PREFIRM),	.driver_info = EAGLE_II | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_II_PID_PSTFIRM),	.driver_info = EAGLE_II | PSTFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_IIC_PID_PREFIRM),	.driver_info = EAGLE_II | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_IIC_PID_PSTFIRM),	.driver_info = EAGLE_II | PSTFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_III_PID_PREFIRM),	.driver_info = EAGLE_III | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_III_PID_PSTFIRM),	.driver_info = EAGLE_III | PSTFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_IV_PID_PREFIRM),	.driver_info = EAGLE_IV | PREFIRM},
+	{USB_DEVICE(ANALOG_VID,	EAGLE_IV_PID_PSTFIRM),	.driver_info = EAGLE_IV | PSTFIRM},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_I_A_PID_PREFIRM),	.driver_info = EAGLE_I | PREFIRM},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_I_A_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_I_B_PID_PREFIRM),	.driver_info = EAGLE_I | PREFIRM},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_I_B_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_II_A_PID_PREFIRM),	.driver_info = EAGLE_II | PREFIRM},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_II_A_PID_PSTFIRM),	.driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_A},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_II_B_PID_PREFIRM),	.driver_info = EAGLE_II | PREFIRM},
+	{USB_DEVICE(DEVOLO_VID,	DEVOLO_EAGLE_II_B_PID_PSTFIRM),	.driver_info = EAGLE_II | PSTFIRM | AUTO_ANNEX_B},
 	{USB_DEVICE(ELSA_VID,	ELSA_PID_PREFIRM),	.driver_info = ADI930 | PREFIRM},
 	{USB_DEVICE(ELSA_VID,	ELSA_PID_PSTFIRM),	.driver_info = ADI930 | PSTFIRM},
-	{USB_DEVICE(EAGLE_VID,	EAGLE_I_PID_PREFIRM),	.driver_info = EAGLE_I | PREFIRM},
-	{USB_DEVICE(EAGLE_VID,	EAGLE_I_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM},
-	{USB_DEVICE(EAGLE_VID,	EAGLE_II_PID_PREFIRM),	.driver_info = EAGLE_II | PREFIRM},
-	{USB_DEVICE(EAGLE_VID,	EAGLE_II_PID_PSTFIRM),	.driver_info = EAGLE_II | PSTFIRM},
-	{USB_DEVICE(EAGLE_VID,	EAGLE_IIC_PID_PREFIRM),	.driver_info = EAGLE_II | PREFIRM},
-	{USB_DEVICE(EAGLE_VID,	EAGLE_IIC_PID_PSTFIRM),	.driver_info = EAGLE_II | PSTFIRM},
-	{USB_DEVICE(EAGLE_VID,	EAGLE_III_PID_PREFIRM),	.driver_info = EAGLE_III | PREFIRM},
-	{USB_DEVICE(EAGLE_VID,	EAGLE_III_PID_PSTFIRM),	.driver_info = EAGLE_III | PSTFIRM},
+	{USB_DEVICE(ELSA_VID,	ELSA_PID_A_PREFIRM),	.driver_info = ADI930 | PREFIRM},
+	{USB_DEVICE(ELSA_VID,	ELSA_PID_A_PSTFIRM),	.driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_A},
+	{USB_DEVICE(ELSA_VID,	ELSA_PID_B_PREFIRM),	.driver_info = ADI930 | PREFIRM},
+	{USB_DEVICE(ELSA_VID,	ELSA_PID_B_PSTFIRM),	.driver_info = ADI930 | PSTFIRM | AUTO_ANNEX_B},
 	{USB_DEVICE(USR_VID,	MILLER_A_PID_PREFIRM),	.driver_info = EAGLE_I | PREFIRM},
-	{USB_DEVICE(USR_VID,	MILLER_A_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM},
+	{USB_DEVICE(USR_VID,	MILLER_A_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM  | AUTO_ANNEX_A},
 	{USB_DEVICE(USR_VID,	MILLER_B_PID_PREFIRM),	.driver_info = EAGLE_I | PREFIRM},
-	{USB_DEVICE(USR_VID,	MILLER_B_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM},
+	{USB_DEVICE(USR_VID,	MILLER_B_PID_PSTFIRM),	.driver_info = EAGLE_I | PSTFIRM  | AUTO_ANNEX_B},
 	{USB_DEVICE(USR_VID,	HEINEKEN_A_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
-	{USB_DEVICE(USR_VID,	HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM},
+	{USB_DEVICE(USR_VID,	HEINEKEN_A_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_A},
 	{USB_DEVICE(USR_VID,	HEINEKEN_B_PID_PREFIRM),.driver_info = EAGLE_I | PREFIRM},
-	{USB_DEVICE(USR_VID,	HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM},
+	{USB_DEVICE(USR_VID,	HEINEKEN_B_PID_PSTFIRM),.driver_info = EAGLE_I | PSTFIRM | AUTO_ANNEX_B},
 	{}
 };
 
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index 11e9b15..e717f5b 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -257,9 +257,10 @@
 {
 	struct usbatm_channel *channel = urb->context;
 	unsigned long flags;
+	int status = urb->status;
 
 	vdbg("%s: urb 0x%p, status %d, actual_length %d",
-	     __func__, urb, urb->status, urb->actual_length);
+	     __func__, urb, status, urb->actual_length);
 
 	/* usually in_interrupt(), but not always */
 	spin_lock_irqsave(&channel->lock, flags);
@@ -269,16 +270,16 @@
 
 	spin_unlock_irqrestore(&channel->lock, flags);
 
-	if (unlikely(urb->status) &&
+	if (unlikely(status) &&
 			(!(channel->usbatm->flags & UDSL_IGNORE_EILSEQ) ||
-			 urb->status != -EILSEQ ))
+			 status != -EILSEQ ))
 	{
-		if (urb->status == -ESHUTDOWN)
+		if (status == -ESHUTDOWN)
 			return;
 
 		if (printk_ratelimit())
 			atm_warn(channel->usbatm, "%s: urb 0x%p failed (%d)!\n",
-				__func__, urb, urb->status);
+				__func__, urb, status);
 		/* throttle processing in case of an error */
 		mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS));
 	} else
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index cd51520c..f51e224 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -257,9 +257,10 @@
 	struct usb_cdc_notification *dr = urb->transfer_buffer;
 	unsigned char *data;
 	int newctrl;
-	int status;
+	int retval;
+	int status = urb->status;
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:
 		/* success */
 		break;
@@ -267,10 +268,10 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+		dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+		dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
 		goto exit;
 	}
 
@@ -311,10 +312,10 @@
 			break;
 	}
 exit:
-	status = usb_submit_urb (urb, GFP_ATOMIC);
-	if (status)
+	retval = usb_submit_urb (urb, GFP_ATOMIC);
+	if (retval)
 		err ("%s - usb_submit_urb failed with result %d",
-		     __FUNCTION__, status);
+		     __FUNCTION__, retval);
 }
 
 /* data interface returns incoming bytes, or we got unthrottled */
@@ -324,7 +325,8 @@
 	struct acm_ru *rcv = urb->context;
 	struct acm *acm = rcv->instance;
 	int status = urb->status;
-	dbg("Entering acm_read_bulk with status %d", urb->status);
+
+	dbg("Entering acm_read_bulk with status %d", status);
 
 	if (!ACM_READY(acm))
 		return;
@@ -919,6 +921,10 @@
 			return -EINVAL;
 		}
 	}
+
+	/* Accept probe requests only for the control interface */
+	if (intf != control_interface)
+		return -ENODEV;
 	
 	if (usb_interface_claimed(data_interface)) { /* valid in this context */
 		dev_dbg(&intf->dev,"The data interface isn't available");
@@ -1107,10 +1113,12 @@
 		return;
 	}
 	if (acm->country_codes){
-		device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
-		device_remove_file(&intf->dev, &dev_attr_iCountryCodeRelDate);
+		device_remove_file(&acm->control->dev,
+				&dev_attr_wCountryCodes);
+		device_remove_file(&acm->control->dev,
+				&dev_attr_iCountryCodeRelDate);
 	}
-	device_remove_file(&intf->dev, &dev_attr_bmCapabilities);
+	device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
 	acm->dev = NULL;
 	usb_set_intfdata(acm->control, NULL);
 	usb_set_intfdata(acm->data, NULL);
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 9a14789..ad632f2 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -28,6 +28,7 @@
  *	v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
  *	v0.13 - alloc space for statusbuf (<status> not on stack);
  *		use usb_buffer_alloc() for read buf & write buf;
+ *      none  - Maintained in Linux kernel after v0.13
  */
 
 /*
@@ -69,7 +70,6 @@
 #define USBLP_DEVICE_ID_SIZE	1024
 
 /* ioctls: */
-#define LPGETSTATUS		0x060b		/* same as in drivers/char/lp.c */
 #define IOCNR_GET_DEVICE_ID		1
 #define IOCNR_GET_PROTOCOLS		2
 #define IOCNR_SET_PROTOCOL		3
@@ -115,7 +115,7 @@
 #define USBLP_MINORS		16
 #define USBLP_MINOR_BASE	0
 
-#define USBLP_WRITE_TIMEOUT	(5000)			/* 5 seconds */
+#define USBLP_CTL_TIMEOUT	5000			/* 5 seconds */
 
 #define USBLP_FIRST_PROTOCOL	1
 #define USBLP_LAST_PROTOCOL	3
@@ -159,10 +159,12 @@
 	int			wstatus;	/* bytes written or error */
 	int			rstatus;	/* bytes ready or error */
 	unsigned int		quirks;			/* quirks flags */
+	unsigned int		flags;			/* mode flags */
 	unsigned char		used;			/* True if open */
 	unsigned char		present;		/* True if not disconnected */
 	unsigned char		bidir;			/* interface is bidirectional */
 	unsigned char		sleeping;		/* interface is suspended */
+	unsigned char		no_paper;		/* Paper Out happened */
 	unsigned char		*device_id_string;	/* IEEE 1284 DEVICE ID string (ptr) */
 							/* first 2 bytes are (big-endian) length */
 };
@@ -259,7 +261,7 @@
 
 	retval = usb_control_msg(usblp->dev,
 		dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
-		request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT);
+		request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT);
 	dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d",
 		request, !!dir, recip, value, index, len, retval);
 	return retval < 0 ? retval : 0;
@@ -289,16 +291,17 @@
 static void usblp_bulk_read(struct urb *urb)
 {
 	struct usblp *usblp = urb->context;
+	int status = urb->status;
 
 	if (usblp->present && usblp->used) {
-		if (urb->status)
+		if (status)
 			printk(KERN_WARNING "usblp%d: "
 			    "nonzero read bulk status received: %d\n",
-			    usblp->minor, urb->status);
+			    usblp->minor, status);
 	}
 	spin_lock(&usblp->lock);
-	if (urb->status < 0)
-		usblp->rstatus = urb->status;
+	if (status < 0)
+		usblp->rstatus = status;
 	else
 		usblp->rstatus = urb->actual_length;
 	usblp->rcomplete = 1;
@@ -311,25 +314,24 @@
 static void usblp_bulk_write(struct urb *urb)
 {
 	struct usblp *usblp = urb->context;
+	int status = urb->status;
 
 	if (usblp->present && usblp->used) {
-		if (urb->status)
+		if (status)
 			printk(KERN_WARNING "usblp%d: "
 			    "nonzero write bulk status received: %d\n",
-			    usblp->minor, urb->status);
+			    usblp->minor, status);
 	}
 	spin_lock(&usblp->lock);
-	if (urb->status < 0)
-		usblp->wstatus = urb->status;
+	if (status < 0)
+		usblp->wstatus = status;
 	else
 		usblp->wstatus = urb->actual_length;
+	usblp->no_paper = 0;
 	usblp->wcomplete = 1;
 	wake_up(&usblp->wwait);
 	spin_unlock(&usblp->lock);
 
-	/* XXX Use usb_setup_bulk_urb when available. Talk to Marcel. */
-	kfree(urb->transfer_buffer);
-	urb->transfer_buffer = NULL;	/* Not refcounted, so to be safe... */
 	usb_free_urb(urb);
 }
 
@@ -344,16 +346,17 @@
 	unsigned char status, newerr = 0;
 	int error;
 
-	error = usblp_read_status (usblp, usblp->statusbuf);
-	if (error < 0) {
+	mutex_lock(&usblp->mut);
+	if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) {
+		mutex_unlock(&usblp->mut);
 		if (printk_ratelimit())
 			printk(KERN_ERR
 				"usblp%d: error %d reading printer status\n",
 				usblp->minor, error);
 		return 0;
 	}
-
 	status = *usblp->statusbuf;
+	mutex_unlock(&usblp->mut);
 
 	if (~status & LP_PERRORP)
 		newerr = 3;
@@ -409,18 +412,10 @@
 		goto out;
 
 	/*
-	 * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
-	 * This is #if 0-ed because we *don't* want to fail an open
-	 * just because the printer is off-line.
+	 * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons:
+	 *  - We do not want persistent state which close(2) does not clear
+	 *  - It is not used anyway, according to CUPS people
 	 */
-#if 0
-	if ((retval = usblp_check_status(usblp, 0))) {
-		retval = retval > 1 ? -EIO : -ENOSPC;
-		goto out;
-	}
-#else
-	retval = 0;
-#endif
 
 	retval = usb_autopm_get_interface(intf);
 	if (retval < 0)
@@ -461,6 +456,8 @@
 {
 	struct usblp *usblp = file->private_data;
 
+	usblp->flags &= ~LP_ABORT;
+
 	mutex_lock (&usblp_mutex);
 	usblp->used = 0;
 	if (usblp->present) {
@@ -483,8 +480,8 @@
 	poll_wait(file, &usblp->rwait, wait);
 	poll_wait(file, &usblp->wwait, wait);
 	spin_lock_irqsave(&usblp->lock, flags);
-	ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN  | POLLRDNORM)
- 			       | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM);
+	ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN  | POLLRDNORM : 0) |
+	   ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0);
 	spin_unlock_irqrestore(&usblp->lock, flags);
 	return ret;
 }
@@ -673,6 +670,13 @@
 					retval = -EFAULT;
 				break;
 
+			case LPABORT:
+				if (arg)
+					usblp->flags |= LP_ABORT;
+				else
+					usblp->flags &= ~LP_ABORT;
+				break;
+
 			default:
 				retval = -ENOTTY;
 		}
@@ -682,10 +686,30 @@
 	return retval;
 }
 
+static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length)
+{
+	struct urb *urb;
+	char *writebuf;
+
+	if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL)
+		return NULL;
+	if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
+		kfree(writebuf);
+		return NULL;
+	}
+
+	usb_fill_bulk_urb(urb, usblp->dev,
+		usb_sndbulkpipe(usblp->dev,
+		 usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
+		writebuf, transfer_length, usblp_bulk_write, usblp);
+	urb->transfer_flags |= URB_FREE_BUFFER;
+
+	return urb;
+}
+
 static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 {
 	struct usblp *usblp = file->private_data;
-	char *writebuf;
 	struct urb *writeurb;
 	int rv;
 	int transfer_length;
@@ -706,17 +730,11 @@
 			transfer_length = USBLP_BUF_SIZE;
 
 		rv = -ENOMEM;
-		if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL)
-			goto raise_buf;
-		if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
+		if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL)
 			goto raise_urb;
-		usb_fill_bulk_urb(writeurb, usblp->dev,
-			usb_sndbulkpipe(usblp->dev,
-			  usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
-			writebuf, transfer_length, usblp_bulk_write, usblp);
 		usb_anchor_urb(writeurb, &usblp->urbs);
 
-		if (copy_from_user(writebuf,
+		if (copy_from_user(writeurb->transfer_buffer,
 				   buffer + writecount, transfer_length)) {
 			rv = -EFAULT;
 			goto raise_badaddr;
@@ -728,6 +746,7 @@
 		if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
 			usblp->wstatus = 0;
 			spin_lock_irq(&usblp->lock);
+			usblp->no_paper = 0;
 			usblp->wcomplete = 1;
 			wake_up(&usblp->wwait);
 			spin_unlock_irq(&usblp->lock);
@@ -741,15 +760,21 @@
 		 */
 		rv = usblp_wwait(usblp, !!(file->f_flags&O_NONBLOCK));
 		if (rv < 0) {
-			/*
-			 * If interrupted, we simply leave the URB to dangle,
-			 * so the ->release will call usb_kill_urb().
-			 */
+			if (rv == -EAGAIN) {
+				/* Presume that it's going to complete well. */
+				writecount += transfer_length;
+			}
+			if (rv == -ENOSPC) {
+				spin_lock_irq(&usblp->lock);
+				usblp->no_paper = 1;	/* Mark for poll(2) */
+				spin_unlock_irq(&usblp->lock);
+				writecount += transfer_length;
+			}
+			/* Leave URB dangling, to be cleaned on close. */
 			goto collect_error;
 		}
 
 		if (usblp->wstatus < 0) {
-			usblp_check_status(usblp, 0);
 			rv = -EIO;
 			goto collect_error;
 		}
@@ -768,8 +793,6 @@
 	usb_unanchor_urb(writeurb);
 	usb_free_urb(writeurb);
 raise_urb:
-	kfree(writebuf);
-raise_buf:
 raise_wait:
 collect_error:		/* Out of raise sequence */
 	mutex_unlock(&usblp->wmut);
@@ -835,32 +858,36 @@
  * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
  * select(2) or poll(2) to wait for the buffer to drain before closing.
  * Alternatively, set blocking mode with fcntl and issue a zero-size write.
- *
- * Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot
- * to check the return code for timeout expiration, so it had no effect.
- * Apparently, it was intended to check for error conditons, such as out
- * of paper. It is going to return when we settle things with CUPS. XXX
  */
 static int usblp_wwait(struct usblp *usblp, int nonblock)
 {
 	DECLARE_WAITQUEUE(waita, current);
 	int rc;
+	int err = 0;
 
 	add_wait_queue(&usblp->wwait, &waita);
 	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
 		if (mutex_lock_interruptible(&usblp->mut)) {
 			rc = -EINTR;
 			break;
 		}
-		set_current_state(TASK_INTERRUPTIBLE);
-		if ((rc = usblp_wtest(usblp, nonblock)) < 0) {
-			mutex_unlock(&usblp->mut);
-			break;
-		}
+		rc = usblp_wtest(usblp, nonblock);
 		mutex_unlock(&usblp->mut);
-		if (rc == 0)
+		if (rc <= 0)
 			break;
-		schedule();
+
+		if (usblp->flags & LP_ABORT) {
+			if (schedule_timeout(msecs_to_jiffies(5000)) == 0) {
+				err = usblp_check_status(usblp, err);
+				if (err == 1) {	/* Paper out */
+					rc = -ENOSPC;
+					break;
+				}
+			}
+		} else {
+			schedule();
+		}
 	}
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&usblp->wwait, &waita);
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index cb69aa1..1a8edce 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -507,18 +507,30 @@
 }
 
 
-// hub-only!! ... and only in reset path, or usb_new_device()
-// (used by real hubs and virtual root hubs)
+/*
+ * Get the USB config descriptors, cache and parse'em
+ *
+ * hub-only!! ... and only in reset path, or usb_new_device()
+ * (used by real hubs and virtual root hubs)
+ *
+ * NOTE: if this is a WUSB device and is not authorized, we skip the
+ *       whole thing. A non-authorized USB device has no
+ *       configurations.
+ */
 int usb_get_configuration(struct usb_device *dev)
 {
 	struct device *ddev = &dev->dev;
 	int ncfg = dev->descriptor.bNumConfigurations;
-	int result = -ENOMEM;
+	int result = 0;
 	unsigned int cfgno, length;
 	unsigned char *buffer;
 	unsigned char *bigbuffer;
  	struct usb_config_descriptor *desc;
 
+	cfgno = 0;
+	if (dev->authorized == 0)	/* Not really an error */
+		goto out_not_authorized;
+	result = -ENOMEM;
 	if (ncfg > USB_MAXCONFIG) {
 		dev_warn(ddev, "too many configurations: %d, "
 		    "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
@@ -545,14 +557,15 @@
 		goto err2;
 	desc = (struct usb_config_descriptor *)buffer;
 
-	for (cfgno = 0; cfgno < ncfg; cfgno++) {
+	result = 0;
+	for (; cfgno < ncfg; cfgno++) {
 		/* We grab just the first descriptor so we know how long
 		 * the whole configuration is */
 		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
 		    buffer, USB_DT_CONFIG_SIZE);
 		if (result < 0) {
 			dev_err(ddev, "unable to read config index %d "
-			    "descriptor/%s\n", cfgno, "start");
+			    "descriptor/%s: %d\n", cfgno, "start", result);
 			dev_err(ddev, "chopping to %d config(s)\n", cfgno);
 			dev->descriptor.bNumConfigurations = cfgno;
 			break;
@@ -599,6 +612,7 @@
 
 err:
 	kfree(buffer);
+out_not_authorized:
 	dev->descriptor.bNumConfigurations = cfgno;
 err2:
 	if (result == -ENOMEM)
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 927a181..f013b40 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -71,6 +71,7 @@
 	void __user *userbuffer;
 	void __user *userurb;
 	struct urb *urb;
+	int status;
 	u32 secid;
 };
 
@@ -289,10 +290,8 @@
 	if (!usbfs_snoop)
 		return;
 
-	if (urb->pipe & USB_DIR_IN)
-		dev_info(&urb->dev->dev, "direction=IN\n");
-	else
-		dev_info(&urb->dev->dev, "direction=OUT\n");
+	dev_info(&urb->dev->dev, "direction=%s\n",
+			usb_urb_dir_in(urb) ? "IN" : "OUT");
 	dev_info(&urb->dev->dev, "userurb=%p\n", userurb);
 	dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n",
 		 urb->transfer_buffer_length);
@@ -312,9 +311,10 @@
         spin_lock(&ps->lock);
         list_move_tail(&as->asynclist, &ps->async_completed);
         spin_unlock(&ps->lock);
+	as->status = urb->status;
 	if (as->signr) {
 		sinfo.si_signo = as->signr;
-		sinfo.si_errno = as->urb->status;
+		sinfo.si_errno = as->status;
 		sinfo.si_code = SI_ASYNCIO;
 		sinfo.si_addr = as->userurb;
 		kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
@@ -910,6 +910,7 @@
 	struct usb_ctrlrequest *dr = NULL;
 	unsigned int u, totlen, isofrmlen;
 	int ret, ifnum = -1;
+	int is_in;
 
 	if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
 			   URB_NO_FSBR|URB_ZERO_PACKET))
@@ -924,16 +925,18 @@
 		if ((ret = checkintf(ps, ifnum)))
 			return ret;
 	}
-	if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0)
-		ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
-	else
-		ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+	if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) {
+		is_in = 1;
+		ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+	} else {
+		is_in = 0;
+		ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+	}
 	if (!ep)
 		return -ENOENT;
 	switch(uurb->type) {
 	case USBDEVFS_URB_TYPE_CONTROL:
-		if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-				!= USB_ENDPOINT_XFER_CONTROL)
+		if (!usb_endpoint_xfer_control(&ep->desc))
 			return -EINVAL;
 		/* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */
 		if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
@@ -952,23 +955,32 @@
 			kfree(dr);
 			return ret;
 		}
-		uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
 		uurb->number_of_packets = 0;
 		uurb->buffer_length = le16_to_cpup(&dr->wLength);
 		uurb->buffer += 8;
-		if (!access_ok((uurb->endpoint & USB_DIR_IN) ?  VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) {
+		if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
+			is_in = 1;
+			uurb->endpoint |= USB_DIR_IN;
+		} else {
+			is_in = 0;
+			uurb->endpoint &= ~USB_DIR_IN;
+		}
+		if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+				uurb->buffer, uurb->buffer_length)) {
 			kfree(dr);
 			return -EFAULT;
 		}
 		snoop(&ps->dev->dev, "control urb: bRequest=%02x "
 			"bRrequestType=%02x wValue=%04x "
 			"wIndex=%04x wLength=%04x\n",
-			dr->bRequest, dr->bRequestType, dr->wValue,
-			dr->wIndex, dr->wLength);
+			dr->bRequest, dr->bRequestType,
+			__le16_to_cpup(&dr->wValue),
+			__le16_to_cpup(&dr->wIndex),
+			__le16_to_cpup(&dr->wLength));
 		break;
 
 	case USBDEVFS_URB_TYPE_BULK:
-		switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+		switch (usb_endpoint_type(&ep->desc)) {
 		case USB_ENDPOINT_XFER_CONTROL:
 		case USB_ENDPOINT_XFER_ISOC:
 			return -EINVAL;
@@ -977,7 +989,8 @@
 		uurb->number_of_packets = 0;
 		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
 			return -EINVAL;
-		if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
+		if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+				uurb->buffer, uurb->buffer_length))
 			return -EFAULT;
 		snoop(&ps->dev->dev, "bulk urb\n");
 		break;
@@ -986,8 +999,7 @@
 		/* arbitrary limit */
 		if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
 			return -EINVAL;
-		if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-				!= USB_ENDPOINT_XFER_ISOC)
+		if (!usb_endpoint_xfer_isoc(&ep->desc))
 			return -EINVAL;
 		isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
 		if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
@@ -1014,12 +1026,12 @@
 
 	case USBDEVFS_URB_TYPE_INTERRUPT:
 		uurb->number_of_packets = 0;
-		if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-				!= USB_ENDPOINT_XFER_INT)
+		if (!usb_endpoint_xfer_int(&ep->desc))
 			return -EINVAL;
 		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
 			return -EINVAL;
-		if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
+		if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+				uurb->buffer, uurb->buffer_length))
 			return -EFAULT;
 		snoop(&ps->dev->dev, "interrupt urb\n");
 		break;
@@ -1039,8 +1051,11 @@
 		return -ENOMEM;
 	}
         as->urb->dev = ps->dev;
-        as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN);
-        as->urb->transfer_flags = uurb->flags;
+        as->urb->pipe = (uurb->type << 30) |
+			__create_pipe(ps->dev, uurb->endpoint & 0xf) |
+			(uurb->endpoint & USB_DIR_IN);
+        as->urb->transfer_flags = uurb->flags |
+			(is_in ? URB_DIR_IN : URB_DIR_OUT);
 	as->urb->transfer_buffer_length = uurb->buffer_length;
 	as->urb->setup_packet = (unsigned char*)dr;
 	as->urb->start_frame = uurb->start_frame;
@@ -1070,13 +1085,13 @@
 	as->uid = current->uid;
 	as->euid = current->euid;
 	security_task_getsecid(current, &as->secid);
-	if (!(uurb->endpoint & USB_DIR_IN)) {
-		if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
+	if (!is_in) {
+		if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
+				as->urb->transfer_buffer_length)) {
 			free_async(as);
 			return -EFAULT;
 		}
 	}
-	snoop(&as->urb->dev->dev, "submit urb\n");
 	snoop_urb(as->urb, as->userurb);
         async_newpending(as);
         if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
@@ -1119,14 +1134,14 @@
 	if (as->userbuffer)
 		if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
 			return -EFAULT;
-	if (put_user(urb->status, &userurb->status))
+	if (put_user(as->status, &userurb->status))
 		return -EFAULT;
 	if (put_user(urb->actual_length, &userurb->actual_length))
 		return -EFAULT;
 	if (put_user(urb->error_count, &userurb->error_count))
 		return -EFAULT;
 
-	if (usb_pipeisoc(urb->pipe)) {
+	if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
 		for (i = 0; i < urb->number_of_packets; i++) {
 			if (put_user(urb->iso_frame_desc[i].actual_length,
 				     &userurb->iso_frame_desc[i].actual_length))
@@ -1233,14 +1248,14 @@
 	if (as->userbuffer)
 		if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
 			return -EFAULT;
-	if (put_user(urb->status, &userurb->status))
+	if (put_user(as->status, &userurb->status))
 		return -EFAULT;
 	if (put_user(urb->actual_length, &userurb->actual_length))
 		return -EFAULT;
 	if (put_user(urb->error_count, &userurb->error_count))
 		return -EFAULT;
 
-	if (usb_pipeisoc(urb->pipe)) {
+	if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
 		for (i = 0; i < urb->number_of_packets; i++) {
 			if (put_user(urb->iso_frame_desc[i].actual_length,
 				     &userurb->iso_frame_desc[i].actual_length))
@@ -1576,6 +1591,7 @@
 }
 
 const struct file_operations usbdev_file_operations = {
+	.owner = 	THIS_MODULE,
 	.llseek =	usbdev_lseek,
 	.read =		usbdev_read,
 	.poll =		usbdev_poll,
@@ -1625,10 +1641,7 @@
 };
 #endif
 
-static struct cdev usb_device_cdev = {
-	.kobj   = {.name = "usb_device", },
-	.owner  = THIS_MODULE,
-};
+static struct cdev usb_device_cdev;
 
 int __init usb_devio_init(void)
 {
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 73c4936..8586817 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -29,13 +29,6 @@
 #include "hcd.h"
 #include "usb.h"
 
-#define VERBOSE_DEBUG	0
-
-#if VERBOSE_DEBUG
-#define dev_vdbg	dev_dbg
-#else
-#define dev_vdbg(dev, fmt, args...)	do { } while (0)
-#endif
 
 #ifdef CONFIG_HOTPLUG
 
@@ -67,7 +60,7 @@
 	dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
 
 	spin_lock(&dynids->lock);
-	list_add_tail(&dynids->list, &dynid->node);
+	list_add_tail(&dynid->node, &dynids->list);
 	spin_unlock(&dynids->lock);
 
 	if (get_driver(driver)) {
@@ -209,6 +202,11 @@
 	intf = to_usb_interface(dev);
 	udev = interface_to_usbdev(intf);
 
+ 	if (udev->authorized == 0) {
+ 		dev_err(&intf->dev, "Device is not authorized for usage\n");
+ 		return -ENODEV;
+ 	}
+
 	id = usb_match_id(intf, driver->id_table);
 	if (!id)
 		id = usb_match_dynamic_id(intf, driver);
@@ -583,12 +581,9 @@
 }
 
 #ifdef	CONFIG_HOTPLUG
-static int usb_uevent(struct device *dev, char **envp, int num_envp,
-		      char *buffer, int buffer_size)
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct usb_device *usb_dev;
-	int i = 0;
-	int length = 0;
 
 	if (!dev)
 		return -ENODEV;
@@ -617,51 +612,39 @@
 	 * all the device descriptors we don't tell them about.  Or
 	 * act as usermode drivers.
 	 */
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "DEVICE=/proc/bus/usb/%03d/%03d",
+	if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
 			   usb_dev->bus->busnum, usb_dev->devnum))
 		return -ENOMEM;
 #endif
 
 	/* per-device configurations are common */
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "PRODUCT=%x/%x/%x",
+	if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
 			   le16_to_cpu(usb_dev->descriptor.idVendor),
 			   le16_to_cpu(usb_dev->descriptor.idProduct),
 			   le16_to_cpu(usb_dev->descriptor.bcdDevice)))
 		return -ENOMEM;
 
 	/* class-based driver binding models */
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "TYPE=%d/%d/%d",
+	if (add_uevent_var(env, "TYPE=%d/%d/%d",
 			   usb_dev->descriptor.bDeviceClass,
 			   usb_dev->descriptor.bDeviceSubClass,
 			   usb_dev->descriptor.bDeviceProtocol))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "BUSNUM=%03d",
+	if (add_uevent_var(env, "BUSNUM=%03d",
 			   usb_dev->bus->busnum))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-			   buffer, buffer_size, &length,
-			   "DEVNUM=%03d",
+	if (add_uevent_var(env, "DEVNUM=%03d",
 			   usb_dev->devnum))
 		return -ENOMEM;
 
-	envp[i] = NULL;
 	return 0;
 }
 
 #else
 
-static int usb_uevent(struct device *dev, char **envp,
-		      int num_envp, char *buffer, int buffer_size)
+static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	return -ENODEV;
 }
@@ -952,11 +935,11 @@
 #ifdef	CONFIG_USB_SUSPEND
 
 /* Internal routine to check whether we may autosuspend a device. */
-static int autosuspend_check(struct usb_device *udev)
+static int autosuspend_check(struct usb_device *udev, int reschedule)
 {
 	int			i;
 	struct usb_interface	*intf;
-	unsigned long		suspend_time;
+	unsigned long		suspend_time, j;
 
 	/* For autosuspend, fail fast if anything is in use or autosuspend
 	 * is disabled.  Also fail if any interfaces require remote wakeup
@@ -998,20 +981,20 @@
 	}
 
 	/* If everything is okay but the device hasn't been idle for long
-	 * enough, queue a delayed autosuspend request.
+	 * enough, queue a delayed autosuspend request.  If the device
+	 * _has_ been idle for long enough and the reschedule flag is set,
+	 * likewise queue a delayed (1 second) autosuspend request.
 	 */
-	if (time_after(suspend_time, jiffies)) {
+	j = jiffies;
+	if (time_before(j, suspend_time))
+		reschedule = 1;
+	else
+		suspend_time = j + HZ;
+	if (reschedule) {
 		if (!timer_pending(&udev->autosuspend.timer)) {
-
-			/* The value of jiffies may change between the
-			 * time_after() comparison above and the subtraction
-			 * below.  That's okay; the system behaves sanely
-			 * when a timer is registered for the present moment
-			 * or for the past.
-			 */
 			queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
-				round_jiffies_relative(suspend_time - jiffies));
-			}
+				round_jiffies_relative(suspend_time - j));
+		}
 		return -EAGAIN;
 	}
 	return 0;
@@ -1019,7 +1002,7 @@
 
 #else
 
-static inline int autosuspend_check(struct usb_device *udev)
+static inline int autosuspend_check(struct usb_device *udev, int reschedule)
 {
 	return 0;
 }
@@ -1076,7 +1059,7 @@
 	udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
 
 	if (udev->auto_pm) {
-		status = autosuspend_check(udev);
+		status = autosuspend_check(udev, 0);
 		if (status < 0)
 			goto done;
 	}
@@ -1090,15 +1073,8 @@
 				break;
 		}
 	}
-	if (status == 0) {
-
-		/* Non-root devices don't need to do anything for FREEZE
-		 * or PRETHAW. */
-		if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
-				msg.event == PM_EVENT_PRETHAW))
-			goto done;
+	if (status == 0)
 		status = usb_suspend_device(udev, msg);
-	}
 
 	/* If the suspend failed, resume interfaces that did get suspended */
 	if (status != 0) {
@@ -1109,12 +1085,24 @@
 
 		/* Try another autosuspend when the interfaces aren't busy */
 		if (udev->auto_pm)
-			autosuspend_check(udev);
+			autosuspend_check(udev, status == -EBUSY);
 
-	/* If the suspend succeeded, propagate it up the tree */
+	/* If the suspend succeeded then prevent any more URB submissions,
+	 * flush any outstanding URBs, and propagate the suspend up the tree.
+	 */
 	} else {
 		cancel_delayed_work(&udev->autosuspend);
-		if (parent)
+		udev->can_submit = 0;
+		for (i = 0; i < 16; ++i) {
+			usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
+			usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
+		}
+
+		/* If this is just a FREEZE or a PRETHAW, udev might
+		 * not really be suspended.  Only true suspends get
+		 * propagated up the device tree.
+		 */
+		if (parent && udev->state == USB_STATE_SUSPENDED)
 			usb_autosuspend_device(parent);
 	}
 
@@ -1163,6 +1151,7 @@
 		status = -ENODEV;
 		goto done;
 	}
+	udev->can_submit = 1;
 
 	/* Propagate the resume up the tree, if necessary */
 	if (udev->state == USB_STATE_SUSPENDED) {
@@ -1231,6 +1220,8 @@
 	udev->auto_pm = 1;
 	udev->pm_usage_cnt += inc_usage_cnt;
 	WARN_ON(udev->pm_usage_cnt < 0);
+	if (inc_usage_cnt)
+		udev->last_busy = jiffies;
 	if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) {
 		if (udev->state == USB_STATE_SUSPENDED)
 			status = usb_resume_both(udev);
@@ -1239,8 +1230,6 @@
 		else if (inc_usage_cnt)
 			udev->last_busy = jiffies;
 	} else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) {
-		if (inc_usage_cnt)
-			udev->last_busy = jiffies;
 		status = usb_suspend_both(udev, PMSG_SUSPEND);
 	}
 	usb_pm_unlock(udev);
@@ -1349,16 +1338,15 @@
 	else {
 		udev->auto_pm = 1;
 		intf->pm_usage_cnt += inc_usage_cnt;
+		udev->last_busy = jiffies;
 		if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) {
 			if (udev->state == USB_STATE_SUSPENDED)
 				status = usb_resume_both(udev);
 			if (status != 0)
 				intf->pm_usage_cnt -= inc_usage_cnt;
-			else if (inc_usage_cnt)
+			else
 				udev->last_busy = jiffies;
 		} else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) {
-			if (inc_usage_cnt)
-				udev->last_busy = jiffies;
 			status = usb_suspend_both(udev, PMSG_SUSPEND);
 		}
 	}
@@ -1537,9 +1525,21 @@
 
 static int usb_suspend(struct device *dev, pm_message_t message)
 {
+	struct usb_device	*udev;
+
 	if (!is_usb_device(dev))	/* Ignore PM for interfaces */
 		return 0;
-	return usb_external_suspend_device(to_usb_device(dev), message);
+	udev = to_usb_device(dev);
+
+	/* If udev is already suspended, we can skip this suspend and
+	 * we should also skip the upcoming system resume. */
+	if (udev->state == USB_STATE_SUSPENDED) {
+		udev->skip_sys_resume = 1;
+		return 0;
+	}
+
+	udev->skip_sys_resume = 0;
+	return usb_external_suspend_device(udev, message);
 }
 
 static int usb_resume(struct device *dev)
@@ -1550,13 +1550,14 @@
 		return 0;
 	udev = to_usb_device(dev);
 
-	/* If autoresume is disabled then we also want to prevent resume
-	 * during system wakeup.  However, a "persistent-device" reset-resume
-	 * after power loss counts as a wakeup event.  So allow a
-	 * reset-resume to occur if remote wakeup is enabled. */
-	if (udev->autoresume_disabled) {
+	/* If udev->skip_sys_resume is set then udev was already suspended
+	 * when the system suspend started, so we don't want to resume
+	 * udev during this system wakeup.  However a reset-resume counts
+	 * as a wakeup event, so allow a reset-resume to occur if remote
+	 * wakeup is enabled. */
+	if (udev->skip_sys_resume) {
 		if (!(udev->reset_resume && udev->do_remote_wakeup))
-			return -EPERM;
+			return -EHOSTUNREACH;
 	}
 	return usb_external_resume_device(udev);
 }
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index e0ec704..7dc123d 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -267,7 +267,6 @@
 {
 	struct ep_device *ep_dev = to_ep_device(dev);
 
-	dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id);
 	endpoint_free_minor(ep_dev);
 	kfree(ep_dev);
 }
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index b2fc2b1..c1cb94e 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -40,7 +40,7 @@
 		&& desc->bInterfaceProtocol == 1;
 }
 
-static int choose_configuration(struct usb_device *udev)
+int usb_choose_configuration(struct usb_device *udev)
 {
 	int i;
 	int num_configs;
@@ -161,17 +161,20 @@
 	/* Choose and set the configuration.  This registers the interfaces
 	 * with the driver core and lets interface drivers bind to them.
 	 */
-	c = choose_configuration(udev);
-	if (c >= 0) {
-		err = usb_set_configuration(udev, c);
-		if (err) {
-			dev_err(&udev->dev, "can't set config #%d, error %d\n",
+	if (udev->authorized == 0)
+		dev_err(&udev->dev, "Device is not authorized for usage\n");
+	else {
+		c = usb_choose_configuration(udev);
+		if (c >= 0) {
+			err = usb_set_configuration(udev, c);
+			if (err) {
+				dev_err(&udev->dev, "can't set config #%d, error %d\n",
 					c, err);
-			/* This need not be fatal.  The user can try to
-			 * set other configurations. */
+				/* This need not be fatal.  The user can try to
+				 * set other configurations. */
+			}
 		}
 	}
-
 	/* USB device state == configured ... usable */
 	usb_notify_add_device(udev);
 
@@ -203,8 +206,13 @@
 	 */
 	if (!udev->parent)
 		rc = hcd_bus_suspend(udev);
+
+	/* Non-root devices don't need to do anything for FREEZE or PRETHAW */
+	else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+		rc = 0;
 	else
 		rc = usb_port_suspend(udev);
+
 	return rc;
 }
 
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 963520f..3dd997d 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -99,12 +99,17 @@
 /* used for controlling access to virtual root hubs */
 static DEFINE_SPINLOCK(hcd_root_hub_lock);
 
-/* used when updating hcd data */
-static DEFINE_SPINLOCK(hcd_data_lock);
+/* used when updating an endpoint's URB list */
+static DEFINE_SPINLOCK(hcd_urb_list_lock);
 
 /* wait queue for synchronous unlinks */
 DECLARE_WAIT_QUEUE_HEAD(usb_kill_urb_queue);
 
+static inline int is_root_hub(struct usb_device *udev)
+{
+	return (udev->parent == NULL);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -351,10 +356,18 @@
 	const u8	*bufp = tbuf;
 	int		len = 0;
 	int		patch_wakeup = 0;
-	unsigned long	flags;
-	int		status = 0;
+	int		status;
 	int		n;
 
+	might_sleep();
+
+	spin_lock_irq(&hcd_root_hub_lock);
+	status = usb_hcd_link_urb_to_ep(hcd, urb);
+	spin_unlock_irq(&hcd_root_hub_lock);
+	if (status)
+		return status;
+	urb->hcpriv = hcd;	/* Indicate it's queued */
+
 	cmd = (struct usb_ctrlrequest *) urb->setup_packet;
 	typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;
 	wValue   = le16_to_cpu (cmd->wValue);
@@ -518,13 +531,18 @@
 	}
 
 	/* any errors get returned through the urb completion */
-	local_irq_save (flags);
-	spin_lock (&urb->lock);
-	if (urb->status == -EINPROGRESS)
-		urb->status = status;
-	spin_unlock (&urb->lock);
-	usb_hcd_giveback_urb (hcd, urb);
-	local_irq_restore (flags);
+	spin_lock_irq(&hcd_root_hub_lock);
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+	/* This peculiar use of spinlocks echoes what real HC drivers do.
+	 * Avoiding calls to local_irq_disable/enable makes the code
+	 * RT-friendly.
+	 */
+	spin_unlock(&hcd_root_hub_lock);
+	usb_hcd_giveback_urb(hcd, urb, status);
+	spin_lock(&hcd_root_hub_lock);
+
+	spin_unlock_irq(&hcd_root_hub_lock);
 	return 0;
 }
 
@@ -554,31 +572,23 @@
 	if (length > 0) {
 
 		/* try to complete the status urb */
-		local_irq_save (flags);
-		spin_lock(&hcd_root_hub_lock);
+		spin_lock_irqsave(&hcd_root_hub_lock, flags);
 		urb = hcd->status_urb;
 		if (urb) {
-			spin_lock(&urb->lock);
-			if (urb->status == -EINPROGRESS) {
-				hcd->poll_pending = 0;
-				hcd->status_urb = NULL;
-				urb->status = 0;
-				urb->hcpriv = NULL;
-				urb->actual_length = length;
-				memcpy(urb->transfer_buffer, buffer, length);
-			} else		/* urb has been unlinked */
-				length = 0;
-			spin_unlock(&urb->lock);
-		} else
-			length = 0;
-		spin_unlock(&hcd_root_hub_lock);
+			hcd->poll_pending = 0;
+			hcd->status_urb = NULL;
+			urb->actual_length = length;
+			memcpy(urb->transfer_buffer, buffer, length);
 
-		/* local irqs are always blocked in completions */
-		if (length > 0)
-			usb_hcd_giveback_urb (hcd, urb);
-		else
+			usb_hcd_unlink_urb_from_ep(hcd, urb);
+			spin_unlock(&hcd_root_hub_lock);
+			usb_hcd_giveback_urb(hcd, urb, 0);
+			spin_lock(&hcd_root_hub_lock);
+		} else {
+			length = 0;
 			hcd->poll_pending = 1;
-		local_irq_restore (flags);
+		}
+		spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
 	}
 
 	/* The USB 2.0 spec says 256 ms.  This is close enough and won't
@@ -606,33 +616,35 @@
 	int		len = 1 + (urb->dev->maxchild / 8);
 
 	spin_lock_irqsave (&hcd_root_hub_lock, flags);
-	if (urb->status != -EINPROGRESS)	/* already unlinked */
-		retval = urb->status;
-	else if (hcd->status_urb || urb->transfer_buffer_length < len) {
+	if (hcd->status_urb || urb->transfer_buffer_length < len) {
 		dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
 		retval = -EINVAL;
-	} else {
-		hcd->status_urb = urb;
-		urb->hcpriv = hcd;	/* indicate it's queued */
-
-		if (!hcd->uses_new_polling)
-			mod_timer (&hcd->rh_timer,
-				(jiffies/(HZ/4) + 1) * (HZ/4));
-
-		/* If a status change has already occurred, report it ASAP */
-		else if (hcd->poll_pending)
-			mod_timer (&hcd->rh_timer, jiffies);
-		retval = 0;
+		goto done;
 	}
+
+	retval = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (retval)
+		goto done;
+
+	hcd->status_urb = urb;
+	urb->hcpriv = hcd;	/* indicate it's queued */
+	if (!hcd->uses_new_polling)
+		mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
+
+	/* If a status change has already occurred, report it ASAP */
+	else if (hcd->poll_pending)
+		mod_timer(&hcd->rh_timer, jiffies);
+	retval = 0;
+ done:
 	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
 	return retval;
 }
 
 static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
 {
-	if (usb_pipeint (urb->pipe))
+	if (usb_endpoint_xfer_int(&urb->ep->desc))
 		return rh_queue_status (hcd, urb);
-	if (usb_pipecontrol (urb->pipe))
+	if (usb_endpoint_xfer_control(&urb->ep->desc))
 		return rh_call_control (hcd, urb);
 	return -EINVAL;
 }
@@ -642,32 +654,96 @@
 /* Unlinks of root-hub control URBs are legal, but they don't do anything
  * since these URBs always execute synchronously.
  */
-static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	unsigned long	flags;
+	int		rc;
 
-	if (usb_pipeendpoint(urb->pipe) == 0) {	/* Control URB */
+	spin_lock_irqsave(&hcd_root_hub_lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
+
+	if (usb_endpoint_num(&urb->ep->desc) == 0) {	/* Control URB */
 		;	/* Do nothing */
 
 	} else {				/* Status URB */
 		if (!hcd->uses_new_polling)
 			del_timer (&hcd->rh_timer);
-		local_irq_save (flags);
-		spin_lock (&hcd_root_hub_lock);
 		if (urb == hcd->status_urb) {
 			hcd->status_urb = NULL;
-			urb->hcpriv = NULL;
-		} else
-			urb = NULL;		/* wasn't fully queued */
-		spin_unlock (&hcd_root_hub_lock);
-		if (urb)
-			usb_hcd_giveback_urb (hcd, urb);
-		local_irq_restore (flags);
-	}
+			usb_hcd_unlink_urb_from_ep(hcd, urb);
 
-	return 0;
+			spin_unlock(&hcd_root_hub_lock);
+			usb_hcd_giveback_urb(hcd, urb, status);
+			spin_lock(&hcd_root_hub_lock);
+		}
+	}
+ done:
+	spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
+	return rc;
 }
 
+
+
+/*
+ * Show & store the current value of authorized_default
+ */
+static ssize_t usb_host_authorized_default_show(struct device *dev,
+						struct device_attribute *attr,
+						char *buf)
+{
+	struct usb_device *rh_usb_dev = to_usb_device(dev);
+	struct usb_bus *usb_bus = rh_usb_dev->bus;
+	struct usb_hcd *usb_hcd;
+
+	if (usb_bus == NULL)	/* FIXME: not sure if this case is possible */
+		return -ENODEV;
+	usb_hcd = bus_to_hcd(usb_bus);
+	return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default);
+}
+
+static ssize_t usb_host_authorized_default_store(struct device *dev,
+						 struct device_attribute *attr,
+						 const char *buf, size_t size)
+{
+	ssize_t result;
+	unsigned val;
+	struct usb_device *rh_usb_dev = to_usb_device(dev);
+	struct usb_bus *usb_bus = rh_usb_dev->bus;
+	struct usb_hcd *usb_hcd;
+
+	if (usb_bus == NULL)	/* FIXME: not sure if this case is possible */
+		return -ENODEV;
+	usb_hcd = bus_to_hcd(usb_bus);
+	result = sscanf(buf, "%u\n", &val);
+	if (result == 1) {
+		usb_hcd->authorized_default = val? 1 : 0;
+		result = size;
+	}
+	else
+		result = -EINVAL;
+	return result;
+}
+
+static DEVICE_ATTR(authorized_default, 0644,
+	    usb_host_authorized_default_show,
+	    usb_host_authorized_default_store);
+
+
+/* Group all the USB bus attributes */
+static struct attribute *usb_bus_attrs[] = {
+		&dev_attr_authorized_default.attr,
+		NULL,
+};
+
+static struct attribute_group usb_bus_attr_group = {
+	.name = NULL,	/* we want them in the same directory */
+	.attrs = usb_bus_attrs,
+};
+
+
+
 /*-------------------------------------------------------------------------*/
 
 static struct class *usb_host_class;
@@ -721,27 +797,23 @@
  */
 static int usb_register_bus(struct usb_bus *bus)
 {
+	int result = -E2BIG;
 	int busnum;
 
 	mutex_lock(&usb_bus_list_lock);
 	busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
-	if (busnum < USB_MAXBUS) {
-		set_bit (busnum, busmap.busmap);
-		bus->busnum = busnum;
-	} else {
+	if (busnum >= USB_MAXBUS) {
 		printk (KERN_ERR "%s: too many buses\n", usbcore_name);
-		mutex_unlock(&usb_bus_list_lock);
-		return -E2BIG;
+		goto error_find_busnum;
 	}
-
+	set_bit (busnum, busmap.busmap);
+	bus->busnum = busnum;
 	bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0),
-					     bus->controller, "usb_host%d", busnum);
-	if (IS_ERR(bus->class_dev)) {
-		clear_bit(busnum, busmap.busmap);
-		mutex_unlock(&usb_bus_list_lock);
-		return PTR_ERR(bus->class_dev);
-	}
-
+					     bus->controller, "usb_host%d",
+					     busnum);
+	result = PTR_ERR(bus->class_dev);
+	if (IS_ERR(bus->class_dev))
+		goto error_create_class_dev;
 	class_set_devdata(bus->class_dev, bus);
 
 	/* Add it to the local list of buses */
@@ -750,8 +822,15 @@
 
 	usb_notify_add_bus(bus);
 
-	dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
+	dev_info (bus->controller, "new USB bus registered, assigned bus "
+		  "number %d\n", bus->busnum);
 	return 0;
+
+error_create_class_dev:
+	clear_bit(busnum, busmap.busmap);
+error_find_busnum:
+	mutex_unlock(&usb_bus_list_lock);
+	return result;
 }
 
 /**
@@ -903,104 +982,145 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
-{
-	unsigned long		flags;
-	int at_root_hub = (urb->dev == hcd->self.root_hub);
-
-	/* clear all state linking urb to this dev (and hcd) */
-	spin_lock_irqsave (&hcd_data_lock, flags);
-	list_del_init (&urb->urb_list);
-	spin_unlock_irqrestore (&hcd_data_lock, flags);
-
-	if (hcd->self.uses_dma && !at_root_hub) {
-		if (usb_pipecontrol (urb->pipe)
-			&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
-			dma_unmap_single (hcd->self.controller, urb->setup_dma,
-					sizeof (struct usb_ctrlrequest),
-					DMA_TO_DEVICE);
-		if (urb->transfer_buffer_length != 0
-			&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
-			dma_unmap_single (hcd->self.controller,
-					urb->transfer_dma,
-					urb->transfer_buffer_length,
-					usb_pipein (urb->pipe)
-					    ? DMA_FROM_DEVICE
-					    : DMA_TO_DEVICE);
-	}
-}
-
-/* may be called in any context with a valid urb->dev usecount
- * caller surrenders "ownership" of urb
- * expects usb_submit_urb() to have sanity checked and conditioned all
- * inputs in the urb
+/**
+ * usb_hcd_link_urb_to_ep - add an URB to its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being submitted
+ *
+ * Host controller drivers should call this routine in their enqueue()
+ * method.  The HCD's private spinlock must be held and interrupts must
+ * be disabled.  The actions carried out here are required for URB
+ * submission, as well as for endpoint shutdown and for usb_kill_urb.
+ *
+ * Returns 0 for no error, otherwise a negative error code (in which case
+ * the enqueue() method must fail).  If no error occurs but enqueue() fails
+ * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing
+ * the private spinlock and returning.
  */
-int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
+int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb)
 {
-	int			status;
-	struct usb_hcd		*hcd = bus_to_hcd(urb->dev->bus);
-	struct usb_host_endpoint *ep;
-	unsigned long		flags;
+	int		rc = 0;
 
-	if (!hcd)
-		return -ENODEV;
+	spin_lock(&hcd_urb_list_lock);
 
-	usbmon_urb_submit(&hcd->self, urb);
-
-	/*
-	 * Atomically queue the urb,  first to our records, then to the HCD.
-	 * Access to urb->status is controlled by urb->lock ... changes on
-	 * i/o completion (normal or fault) or unlinking.
-	 */
-
-	// FIXME:  verify that quiescing hc works right (RH cleans up)
-
-	spin_lock_irqsave (&hcd_data_lock, flags);
-	ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
-			[usb_pipeendpoint(urb->pipe)];
-	if (unlikely (!ep))
-		status = -ENOENT;
-	else if (unlikely (urb->reject))
-		status = -EPERM;
-	else switch (hcd->state) {
-	case HC_STATE_RUNNING:
-	case HC_STATE_RESUMING:
-		list_add_tail (&urb->urb_list, &ep->urb_list);
-		status = 0;
-		break;
-	default:
-		status = -ESHUTDOWN;
-		break;
-	}
-	spin_unlock_irqrestore (&hcd_data_lock, flags);
-	if (status) {
-		INIT_LIST_HEAD (&urb->urb_list);
-		usbmon_urb_submit_error(&hcd->self, urb, status);
-		return status;
-	}
-
-	/* increment urb's reference count as part of giving it to the HCD
-	 * (which now controls it).  HCD guarantees that it either returns
-	 * an error or calls giveback(), but not both.
-	 */
-	urb = usb_get_urb (urb);
-	atomic_inc (&urb->use_count);
-
-	if (urb->dev == hcd->self.root_hub) {
-		/* NOTE:  requirement on hub callers (usbfs and the hub
-		 * driver, for now) that URBs' urb->transfer_buffer be
-		 * valid and usb_buffer_{sync,unmap}() not be needed, since
-		 * they could clobber root hub response data.
-		 */
-		status = rh_urb_enqueue (hcd, urb);
+	/* Check that the URB isn't being killed */
+	if (unlikely(urb->reject)) {
+		rc = -EPERM;
 		goto done;
 	}
 
-	/* lower level hcd code should use *_dma exclusively,
+	if (unlikely(!urb->ep->enabled)) {
+		rc = -ENOENT;
+		goto done;
+	}
+
+	if (unlikely(!urb->dev->can_submit)) {
+		rc = -EHOSTUNREACH;
+		goto done;
+	}
+
+	/*
+	 * Check the host controller's state and add the URB to the
+	 * endpoint's queue.
+	 */
+	switch (hcd->state) {
+	case HC_STATE_RUNNING:
+	case HC_STATE_RESUMING:
+		urb->unlinked = 0;
+		list_add_tail(&urb->urb_list, &urb->ep->urb_list);
+		break;
+	default:
+		rc = -ESHUTDOWN;
+		goto done;
+	}
+ done:
+	spin_unlock(&hcd_urb_list_lock);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep);
+
+/**
+ * usb_hcd_check_unlink_urb - check whether an URB may be unlinked
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being checked for unlinkability
+ * @status: error code to store in @urb if the unlink succeeds
+ *
+ * Host controller drivers should call this routine in their dequeue()
+ * method.  The HCD's private spinlock must be held and interrupts must
+ * be disabled.  The actions carried out here are required for making
+ * sure than an unlink is valid.
+ *
+ * Returns 0 for no error, otherwise a negative error code (in which case
+ * the dequeue() method must fail).  The possible error codes are:
+ *
+ *	-EIDRM: @urb was not submitted or has already completed.
+ *		The completion function may not have been called yet.
+ *
+ *	-EBUSY: @urb has already been unlinked.
+ */
+int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+		int status)
+{
+	struct list_head	*tmp;
+
+	/* insist the urb is still queued */
+	list_for_each(tmp, &urb->ep->urb_list) {
+		if (tmp == &urb->urb_list)
+			break;
+	}
+	if (tmp != &urb->urb_list)
+		return -EIDRM;
+
+	/* Any status except -EINPROGRESS means something already started to
+	 * unlink this URB from the hardware.  So there's no more work to do.
+	 */
+	if (urb->unlinked)
+		return -EBUSY;
+	urb->unlinked = status;
+
+	/* IRQ setup can easily be broken so that USB controllers
+	 * never get completion IRQs ... maybe even the ones we need to
+	 * finish unlinking the initial failed usb_set_address()
+	 * or device descriptor fetch.
+	 */
+	if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
+			!is_root_hub(urb->dev)) {
+		dev_warn(hcd->self.controller, "Unlink after no-IRQ?  "
+			"Controller is probably using the wrong IRQ.\n");
+		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb);
+
+/**
+ * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being unlinked
+ *
+ * Host controller drivers should call this routine before calling
+ * usb_hcd_giveback_urb().  The HCD's private spinlock must be held and
+ * interrupts must be disabled.  The actions carried out here are required
+ * for URB completion.
+ */
+void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb)
+{
+	/* clear all state linking urb to this dev (and hcd) */
+	spin_lock(&hcd_urb_list_lock);
+	list_del_init(&urb->urb_list);
+	spin_unlock(&hcd_urb_list_lock);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
+
+static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+	/* Map the URB's buffers for DMA access.
+	 * Lower level HCD code should use *_dma exclusively,
 	 * unless it uses pio or talks to another transport.
 	 */
-	if (hcd->self.uses_dma) {
-		if (usb_pipecontrol (urb->pipe)
+	if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+		if (usb_endpoint_xfer_control(&urb->ep->desc)
 			&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
 			urb->setup_dma = dma_map_single (
 					hcd->self.controller,
@@ -1013,26 +1133,264 @@
 					hcd->self.controller,
 					urb->transfer_buffer,
 					urb->transfer_buffer_length,
-					usb_pipein (urb->pipe)
+					usb_urb_dir_in(urb)
 					    ? DMA_FROM_DEVICE
 					    : DMA_TO_DEVICE);
 	}
+}
 
-	status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
-done:
-	if (unlikely (status)) {
-		urb_unlink(hcd, urb);
-		atomic_dec (&urb->use_count);
-		if (urb->reject)
-			wake_up (&usb_kill_urb_queue);
+static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+	if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+		if (usb_endpoint_xfer_control(&urb->ep->desc)
+			&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+			dma_unmap_single(hcd->self.controller, urb->setup_dma,
+					sizeof(struct usb_ctrlrequest),
+					DMA_TO_DEVICE);
+		if (urb->transfer_buffer_length != 0
+			&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+			dma_unmap_single(hcd->self.controller,
+					urb->transfer_dma,
+					urb->transfer_buffer_length,
+					usb_urb_dir_in(urb)
+					    ? DMA_FROM_DEVICE
+					    : DMA_TO_DEVICE);
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* may be called in any context with a valid urb->dev usecount
+ * caller surrenders "ownership" of urb
+ * expects usb_submit_urb() to have sanity checked and conditioned all
+ * inputs in the urb
+ */
+int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
+{
+	int			status;
+	struct usb_hcd		*hcd = bus_to_hcd(urb->dev->bus);
+
+	/* increment urb's reference count as part of giving it to the HCD
+	 * (which will control it).  HCD guarantees that it either returns
+	 * an error or calls giveback(), but not both.
+	 */
+	usb_get_urb(urb);
+	atomic_inc(&urb->use_count);
+	atomic_inc(&urb->dev->urbnum);
+	usbmon_urb_submit(&hcd->self, urb);
+
+	/* NOTE requirements on root-hub callers (usbfs and the hub
+	 * driver, for now):  URBs' urb->transfer_buffer must be
+	 * valid and usb_buffer_{sync,unmap}() not be needed, since
+	 * they could clobber root hub response data.  Also, control
+	 * URBs must be submitted in process context with interrupts
+	 * enabled.
+	 */
+	map_urb_for_dma(hcd, urb);
+	if (is_root_hub(urb->dev))
+		status = rh_urb_enqueue(hcd, urb);
+	else
+		status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
+
+	if (unlikely(status)) {
 		usbmon_urb_submit_error(&hcd->self, urb, status);
-		usb_put_urb (urb);
+		unmap_urb_for_dma(hcd, urb);
+		urb->hcpriv = NULL;
+		INIT_LIST_HEAD(&urb->urb_list);
+		atomic_dec(&urb->use_count);
+		atomic_dec(&urb->dev->urbnum);
+		if (urb->reject)
+			wake_up(&usb_kill_urb_queue);
+		usb_put_urb(urb);
 	}
 	return status;
 }
 
 /*-------------------------------------------------------------------------*/
 
+/* this makes the hcd giveback() the urb more quickly, by kicking it
+ * off hardware queues (which may take a while) and returning it as
+ * soon as practical.  we've already set up the urb's return status,
+ * but we can't know if the callback completed already.
+ */
+static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+	int		value;
+
+	if (is_root_hub(urb->dev))
+		value = usb_rh_urb_dequeue(hcd, urb, status);
+	else {
+
+		/* The only reason an HCD might fail this call is if
+		 * it has not yet fully queued the urb to begin with.
+		 * Such failures should be harmless. */
+		value = hcd->driver->urb_dequeue(hcd, urb, status);
+	}
+	return value;
+}
+
+/*
+ * called in any context
+ *
+ * caller guarantees urb won't be recycled till both unlink()
+ * and the urb's completion function return
+ */
+int usb_hcd_unlink_urb (struct urb *urb, int status)
+{
+	struct usb_hcd		*hcd;
+	int			retval;
+
+	hcd = bus_to_hcd(urb->dev->bus);
+	retval = unlink1(hcd, urb, status);
+
+	if (retval == 0)
+		retval = -EINPROGRESS;
+	else if (retval != -EIDRM && retval != -EBUSY)
+		dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n",
+				urb, retval);
+	return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_hcd_giveback_urb - return URB from HCD to device driver
+ * @hcd: host controller returning the URB
+ * @urb: urb being returned to the USB device driver.
+ * @status: completion status code for the URB.
+ * Context: in_interrupt()
+ *
+ * This hands the URB from HCD to its USB device driver, using its
+ * completion function.  The HCD has freed all per-urb resources
+ * (and is done using urb->hcpriv).  It also released all HCD locks;
+ * the device driver won't cause problems if it frees, modifies,
+ * or resubmits this URB.
+ *
+ * If @urb was unlinked, the value of @status will be overridden by
+ * @urb->unlinked.  Erroneous short transfers are detected in case
+ * the HCD hasn't checked for them.
+ */
+void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+	urb->hcpriv = NULL;
+	if (unlikely(urb->unlinked))
+		status = urb->unlinked;
+	else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+			urb->actual_length < urb->transfer_buffer_length &&
+			!status))
+		status = -EREMOTEIO;
+
+	unmap_urb_for_dma(hcd, urb);
+	usbmon_urb_complete(&hcd->self, urb, status);
+	usb_unanchor_urb(urb);
+
+	/* pass ownership to the completion handler */
+	urb->status = status;
+	urb->complete (urb);
+	atomic_dec (&urb->use_count);
+	if (unlikely (urb->reject))
+		wake_up (&usb_kill_urb_queue);
+	usb_put_urb (urb);
+}
+EXPORT_SYMBOL (usb_hcd_giveback_urb);
+
+/*-------------------------------------------------------------------------*/
+
+/* Cancel all URBs pending on this endpoint and wait for the endpoint's
+ * queue to drain completely.  The caller must first insure that no more
+ * URBs can be submitted for this endpoint.
+ */
+void usb_hcd_flush_endpoint(struct usb_device *udev,
+		struct usb_host_endpoint *ep)
+{
+	struct usb_hcd		*hcd;
+	struct urb		*urb;
+
+	if (!ep)
+		return;
+	might_sleep();
+	hcd = bus_to_hcd(udev->bus);
+
+	/* No more submits can occur */
+rescan:
+	spin_lock_irq(&hcd_urb_list_lock);
+	list_for_each_entry (urb, &ep->urb_list, urb_list) {
+		int	is_in;
+
+		if (urb->unlinked)
+			continue;
+		usb_get_urb (urb);
+		is_in = usb_urb_dir_in(urb);
+		spin_unlock(&hcd_urb_list_lock);
+
+		/* kick hcd */
+		unlink1(hcd, urb, -ESHUTDOWN);
+		dev_dbg (hcd->self.controller,
+			"shutdown urb %p ep%d%s%s\n",
+			urb, usb_endpoint_num(&ep->desc),
+			is_in ? "in" : "out",
+			({	char *s;
+
+				 switch (usb_endpoint_type(&ep->desc)) {
+				 case USB_ENDPOINT_XFER_CONTROL:
+					s = ""; break;
+				 case USB_ENDPOINT_XFER_BULK:
+					s = "-bulk"; break;
+				 case USB_ENDPOINT_XFER_INT:
+					s = "-intr"; break;
+				 default:
+			 		s = "-iso"; break;
+				};
+				s;
+			}));
+		usb_put_urb (urb);
+
+		/* list contents may have changed */
+		goto rescan;
+	}
+	spin_unlock_irq(&hcd_urb_list_lock);
+
+	/* Wait until the endpoint queue is completely empty */
+	while (!list_empty (&ep->urb_list)) {
+		spin_lock_irq(&hcd_urb_list_lock);
+
+		/* The list may have changed while we acquired the spinlock */
+		urb = NULL;
+		if (!list_empty (&ep->urb_list)) {
+			urb = list_entry (ep->urb_list.prev, struct urb,
+					urb_list);
+			usb_get_urb (urb);
+		}
+		spin_unlock_irq(&hcd_urb_list_lock);
+
+		if (urb) {
+			usb_kill_urb (urb);
+			usb_put_urb (urb);
+		}
+	}
+}
+
+/* Disables the endpoint: synchronizes with the hcd to make sure all
+ * endpoint state is gone from hardware.  usb_hcd_flush_endpoint() must
+ * have been called previously.  Use for set_configuration, set_interface,
+ * driver removal, physical disconnect.
+ *
+ * example:  a qh stored in ep->hcpriv, holding state related to endpoint
+ * type, maxpacket size, toggle, halt status, and scheduling.
+ */
+void usb_hcd_disable_endpoint(struct usb_device *udev,
+		struct usb_host_endpoint *ep)
+{
+	struct usb_hcd		*hcd;
+
+	might_sleep();
+	hcd = bus_to_hcd(udev->bus);
+	if (hcd->driver->endpoint_disable)
+		hcd->driver->endpoint_disable(hcd, ep);
+}
+
+/*-------------------------------------------------------------------------*/
+
 /* called in any context */
 int usb_hcd_get_frame_number (struct usb_device *udev)
 {
@@ -1045,221 +1403,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* this makes the hcd giveback() the urb more quickly, by kicking it
- * off hardware queues (which may take a while) and returning it as
- * soon as practical.  we've already set up the urb's return status,
- * but we can't know if the callback completed already.
- */
-static int
-unlink1 (struct usb_hcd *hcd, struct urb *urb)
-{
-	int		value;
-
-	if (urb->dev == hcd->self.root_hub)
-		value = usb_rh_urb_dequeue (hcd, urb);
-	else {
-
-		/* The only reason an HCD might fail this call is if
-		 * it has not yet fully queued the urb to begin with.
-		 * Such failures should be harmless. */
-		value = hcd->driver->urb_dequeue (hcd, urb);
-	}
-
-	if (value != 0)
-		dev_dbg (hcd->self.controller, "dequeue %p --> %d\n",
-				urb, value);
-	return value;
-}
-
-/*
- * called in any context
- *
- * caller guarantees urb won't be recycled till both unlink()
- * and the urb's completion function return
- */
-int usb_hcd_unlink_urb (struct urb *urb, int status)
-{
-	struct usb_host_endpoint	*ep;
-	struct usb_hcd			*hcd = NULL;
-	struct device			*sys = NULL;
-	unsigned long			flags;
-	struct list_head		*tmp;
-	int				retval;
-
-	if (!urb)
-		return -EINVAL;
-	if (!urb->dev || !urb->dev->bus)
-		return -ENODEV;
-	ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
-			[usb_pipeendpoint(urb->pipe)];
-	if (!ep)
-		return -ENODEV;
-
-	/*
-	 * we contend for urb->status with the hcd core,
-	 * which changes it while returning the urb.
-	 *
-	 * Caller guaranteed that the urb pointer hasn't been freed, and
-	 * that it was submitted.  But as a rule it can't know whether or
-	 * not it's already been unlinked ... so we respect the reversed
-	 * lock sequence needed for the usb_hcd_giveback_urb() code paths
-	 * (urb lock, then hcd_data_lock) in case some other CPU is now
-	 * unlinking it.
-	 */
-	spin_lock_irqsave (&urb->lock, flags);
-	spin_lock (&hcd_data_lock);
-
-	sys = &urb->dev->dev;
-	hcd = bus_to_hcd(urb->dev->bus);
-	if (hcd == NULL) {
-		retval = -ENODEV;
-		goto done;
-	}
-
-	/* insist the urb is still queued */
-	list_for_each(tmp, &ep->urb_list) {
-		if (tmp == &urb->urb_list)
-			break;
-	}
-	if (tmp != &urb->urb_list) {
-		retval = -EIDRM;
-		goto done;
-	}
-
-	/* Any status except -EINPROGRESS means something already started to
-	 * unlink this URB from the hardware.  So there's no more work to do.
-	 */
-	if (urb->status != -EINPROGRESS) {
-		retval = -EBUSY;
-		goto done;
-	}
-
-	/* IRQ setup can easily be broken so that USB controllers
-	 * never get completion IRQs ... maybe even the ones we need to
-	 * finish unlinking the initial failed usb_set_address()
-	 * or device descriptor fetch.
-	 */
-	if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags)
-	    && hcd->self.root_hub != urb->dev) {
-		dev_warn (hcd->self.controller, "Unlink after no-IRQ?  "
-			"Controller is probably using the wrong IRQ."
-			"\n");
-		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
-	}
-
-	urb->status = status;
-
-	spin_unlock (&hcd_data_lock);
-	spin_unlock_irqrestore (&urb->lock, flags);
-
-	retval = unlink1 (hcd, urb);
-	if (retval == 0)
-		retval = -EINPROGRESS;
-	return retval;
-
-done:
-	spin_unlock (&hcd_data_lock);
-	spin_unlock_irqrestore (&urb->lock, flags);
-	if (retval != -EIDRM && sys && sys->driver)
-		dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
-	return retval;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* disables the endpoint: cancels any pending urbs, then synchronizes with
- * the hcd to make sure all endpoint state is gone from hardware, and then
- * waits until the endpoint's queue is completely drained. use for
- * set_configuration, set_interface, driver removal, physical disconnect.
- *
- * example:  a qh stored in ep->hcpriv, holding state related to endpoint
- * type, maxpacket size, toggle, halt status, and scheduling.
- */
-void usb_hcd_endpoint_disable (struct usb_device *udev,
-		struct usb_host_endpoint *ep)
-{
-	struct usb_hcd		*hcd;
-	struct urb		*urb;
-
-	hcd = bus_to_hcd(udev->bus);
-	local_irq_disable ();
-
-	/* ep is already gone from udev->ep_{in,out}[]; no more submits */
-rescan:
-	spin_lock (&hcd_data_lock);
-	list_for_each_entry (urb, &ep->urb_list, urb_list) {
-		int	tmp;
-
-		/* the urb may already have been unlinked */
-		if (urb->status != -EINPROGRESS)
-			continue;
-		usb_get_urb (urb);
-		spin_unlock (&hcd_data_lock);
-
-		spin_lock (&urb->lock);
-		tmp = urb->status;
-		if (tmp == -EINPROGRESS)
-			urb->status = -ESHUTDOWN;
-		spin_unlock (&urb->lock);
-
-		/* kick hcd unless it's already returning this */
-		if (tmp == -EINPROGRESS) {
-			tmp = urb->pipe;
-			unlink1 (hcd, urb);
-			dev_dbg (hcd->self.controller,
-				"shutdown urb %p pipe %08x ep%d%s%s\n",
-				urb, tmp, usb_pipeendpoint (tmp),
-				(tmp & USB_DIR_IN) ? "in" : "out",
-				({ char *s; \
-				 switch (usb_pipetype (tmp)) { \
-				 case PIPE_CONTROL:	s = ""; break; \
-				 case PIPE_BULK:	s = "-bulk"; break; \
-				 case PIPE_INTERRUPT:	s = "-intr"; break; \
-				 default: 		s = "-iso"; break; \
-				}; s;}));
-		}
-		usb_put_urb (urb);
-
-		/* list contents may have changed */
-		goto rescan;
-	}
-	spin_unlock (&hcd_data_lock);
-	local_irq_enable ();
-
-	/* synchronize with the hardware, so old configuration state
-	 * clears out immediately (and will be freed).
-	 */
-	might_sleep ();
-	if (hcd->driver->endpoint_disable)
-		hcd->driver->endpoint_disable (hcd, ep);
-
-	/* Wait until the endpoint queue is completely empty.  Most HCDs
-	 * will have done this already in their endpoint_disable method,
-	 * but some might not.  And there could be root-hub control URBs
-	 * still pending since they aren't affected by the HCDs'
-	 * endpoint_disable methods.
-	 */
-	while (!list_empty (&ep->urb_list)) {
-		spin_lock_irq (&hcd_data_lock);
-
-		/* The list may have changed while we acquired the spinlock */
-		urb = NULL;
-		if (!list_empty (&ep->urb_list)) {
-			urb = list_entry (ep->urb_list.prev, struct urb,
-					urb_list);
-			usb_get_urb (urb);
-		}
-		spin_unlock_irq (&hcd_data_lock);
-
-		if (urb) {
-			usb_kill_urb (urb);
-			usb_put_urb (urb);
-		}
-	}
-}
-
-/*-------------------------------------------------------------------------*/
-
 #ifdef	CONFIG_PM
 
 int hcd_bus_suspend(struct usb_device *rhdev)
@@ -1395,35 +1538,6 @@
 /*-------------------------------------------------------------------------*/
 
 /**
- * usb_hcd_giveback_urb - return URB from HCD to device driver
- * @hcd: host controller returning the URB
- * @urb: urb being returned to the USB device driver.
- * Context: in_interrupt()
- *
- * This hands the URB from HCD to its USB device driver, using its
- * completion function.  The HCD has freed all per-urb resources
- * (and is done using urb->hcpriv).  It also released all HCD locks;
- * the device driver won't cause problems if it frees, modifies,
- * or resubmits this URB.
- */
-void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
-{
-	urb_unlink(hcd, urb);
-	usbmon_urb_complete (&hcd->self, urb);
-	usb_unanchor_urb(urb);
-
-	/* pass ownership to the completion handler */
-	urb->complete (urb);
-	atomic_dec (&urb->use_count);
-	if (unlikely (urb->reject))
-		wake_up (&usb_kill_urb_queue);
-	usb_put_urb (urb);
-}
-EXPORT_SYMBOL (usb_hcd_giveback_urb);
-
-/*-------------------------------------------------------------------------*/
-
-/**
  * usb_hcd_irq - hook IRQs to HCD framework (bus glue)
  * @irq: the IRQ being raised
  * @__hcd: pointer to the HCD whose IRQ is being signaled
@@ -1522,7 +1636,6 @@
 	hcd->driver = driver;
 	hcd->product_desc = (driver->product_desc) ? driver->product_desc :
 			"USB Host Controller";
-
 	return hcd;
 }
 EXPORT_SYMBOL (usb_create_hcd);
@@ -1567,6 +1680,7 @@
 
 	dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
 
+	hcd->authorized_default = hcd->wireless? 0 : 1;
 	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 
 	/* HC is in reset state, but accessible.  Now do the one-time init,
@@ -1643,10 +1757,20 @@
 	if ((retval = register_root_hub(hcd)) != 0)
 		goto err_register_root_hub;
 
+	retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
+	if (retval < 0) {
+		printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
+		       retval);
+		goto error_create_attr_group;
+	}
 	if (hcd->uses_new_polling && hcd->poll_rh)
 		usb_hcd_poll_rh_status(hcd);
 	return retval;
 
+error_create_attr_group:
+	mutex_lock(&usb_bus_list_lock);
+	usb_disconnect(&hcd->self.root_hub);
+	mutex_unlock(&usb_bus_list_lock);
 err_register_root_hub:
 	hcd->driver->stop(hcd);
 err_hcd_driver_start:
@@ -1688,6 +1812,7 @@
 	cancel_work_sync(&hcd->wakeup_work);
 #endif
 
+	sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group);
 	mutex_lock(&usb_bus_list_lock);
 	usb_disconnect(&hcd->self.root_hub);
 	mutex_unlock(&usb_bus_list_lock);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index b5ebb73..98e2419 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -19,6 +19,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/rwsem.h>
+
 /* This file contains declarations of usbcore internals that are mostly
  * used or exposed by Host Controller Drivers.
  */
@@ -51,6 +53,12 @@
  *
  * Since "struct usb_bus" is so thin, you can't share much code in it.
  * This framework is a layer over that, and should be more sharable.
+ *
+ * @authorized_default: Specifies if new devices are authorized to
+ *                      connect by default or they require explicit
+ *                      user space authorization; this bit is settable
+ *                      through /sys/class/usb_host/X/authorized_default.
+ *                      For the rest is RO, so we don't lock to r/w it.
  */
 
 /*-------------------------------------------------------------------------*/
@@ -90,6 +98,7 @@
 	unsigned		poll_rh:1;	/* poll for rh status? */
 	unsigned		poll_pending:1;	/* status has changed? */
 	unsigned		wireless:1;	/* Wireless USB HCD */
+	unsigned		authorized_default:1;
 
 	int			irq;		/* irq allocated */
 	void __iomem		*regs;		/* device memory/io */
@@ -182,11 +191,10 @@
 	int	(*get_frame_number) (struct usb_hcd *hcd);
 
 	/* manage i/o requests, device state */
-	int	(*urb_enqueue) (struct usb_hcd *hcd,
-					struct usb_host_endpoint *ep,
-					struct urb *urb,
-					gfp_t mem_flags);
-	int	(*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
+	int	(*urb_enqueue)(struct usb_hcd *hcd,
+				struct urb *urb, gfp_t mem_flags);
+	int	(*urb_dequeue)(struct usb_hcd *hcd,
+				struct urb *urb, int status);
 
 	/* hw synch, freeing endpoint resources that urb_dequeue can't */
 	void 	(*endpoint_disable)(struct usb_hcd *hcd,
@@ -204,10 +212,18 @@
 		/* Needed only if port-change IRQs are level-triggered */
 };
 
+extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
+extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+		int status);
+extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
+
 extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
 extern int usb_hcd_unlink_urb (struct urb *urb, int status);
-extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
-extern void usb_hcd_endpoint_disable (struct usb_device *udev,
+extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
+		int status);
+extern void usb_hcd_flush_endpoint(struct usb_device *udev,
+		struct usb_host_endpoint *ep);
+extern void usb_hcd_disable_endpoint(struct usb_device *udev,
 		struct usb_host_endpoint *ep);
 extern int usb_hcd_get_frame_number (struct usb_device *udev);
 
@@ -402,7 +418,7 @@
 struct usb_mon_operations {
 	void (*urb_submit)(struct usb_bus *bus, struct urb *urb);
 	void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
-	void (*urb_complete)(struct usb_bus *bus, struct urb *urb);
+	void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status);
 	/* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
 };
 
@@ -421,10 +437,11 @@
 		(*mon_ops->urb_submit_error)(bus, urb, error);
 }
 
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb)
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+		int status)
 {
 	if (bus->monitored)
-		(*mon_ops->urb_complete)(bus, urb);
+		(*mon_ops->urb_complete)(bus, urb, status);
 }
 
 int usb_mon_register(struct usb_mon_operations *ops);
@@ -435,7 +452,8 @@
 static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {}
 static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
     int error) {}
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+		int status) {}
 
 #endif /* CONFIG_USB_MON */
 
@@ -454,5 +472,9 @@
 		: (in_interrupt () ? "in_interrupt" : "can sleep"))
 
 
-#endif /* __KERNEL__ */
+/* This rwsem is for use only by the hub driver and ehci-hcd.
+ * Nobody else should touch it.
+ */
+extern struct rw_semaphore ehci_cf_port_reset_rwsem;
 
+#endif /* __KERNEL__ */
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index fd74c50..d20cb54 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -125,6 +125,12 @@
 		"try the other device initialization scheme if the "
 		"first one fails");
 
+/* Mutual exclusion for EHCI CF initialization.  This interferes with
+ * port reset on some companion controllers.
+ */
+DECLARE_RWSEM(ehci_cf_port_reset_rwsem);
+EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
+
 
 static inline char *portspeed(int portstatus)
 {
@@ -347,11 +353,11 @@
 static void hub_irq(struct urb *urb)
 {
 	struct usb_hub *hub = urb->context;
-	int status;
+	int status = urb->status;
 	int i;
 	unsigned long bits;
 
-	switch (urb->status) {
+	switch (status) {
 	case -ENOENT:		/* synchronous unlink */
 	case -ECONNRESET:	/* async unlink */
 	case -ESHUTDOWN:	/* hardware going away */
@@ -359,10 +365,10 @@
 
 	default:		/* presumably an error */
 		/* Cause a hub reset after 10 consecutive errors */
-		dev_dbg (hub->intfdev, "transfer --> %d\n", urb->status);
+		dev_dbg (hub->intfdev, "transfer --> %d\n", status);
 		if ((++hub->nerrors < 10) || hub->error)
 			goto resubmit;
-		hub->error = urb->status;
+		hub->error = status;
 		/* FALL THROUGH */
 
 	/* let khubd handle things */
@@ -1220,54 +1226,14 @@
 #endif
 
 /**
- * usb_new_device - perform initial device setup (usbcore-internal)
+ * usb_configure_device_otg - FIXME (usbcore-internal)
  * @udev: newly addressed device (in ADDRESS state)
  *
- * This is called with devices which have been enumerated, but not yet
- * configured.  The device descriptor is available, but not descriptors
- * for any device configuration.  The caller must have locked either
- * the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
- * udev has already been installed, but udev is not yet visible through
- * sysfs or other filesystem code.
- *
- * It will return if the device is configured properly or not.  Zero if
- * the interface was registered with the driver core; else a negative
- * errno value.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver or root-hub registrar should ever call this.
+ * Do configuration for On-The-Go devices
  */
-int usb_new_device(struct usb_device *udev)
+static int usb_configure_device_otg(struct usb_device *udev)
 {
-	int err;
-
-	/* Determine quirks */
-	usb_detect_quirks(udev);
-
-	err = usb_get_configuration(udev);
-	if (err < 0) {
-		dev_err(&udev->dev, "can't read configurations, error %d\n",
-			err);
-		goto fail;
-	}
-
-	/* read the standard strings and cache them if present */
-	udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
-	udev->manufacturer = usb_cache_string(udev,
-			udev->descriptor.iManufacturer);
-	udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
-
-	/* Tell the world! */
-	dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
-			"SerialNumber=%d\n",
-			udev->descriptor.iManufacturer,
-			udev->descriptor.iProduct,
-			udev->descriptor.iSerialNumber);
-	show_string(udev, "Product", udev->product);
-	show_string(udev, "Manufacturer", udev->manufacturer);
-	show_string(udev, "SerialNumber", udev->serial);
+	int err = 0;
 
 #ifdef	CONFIG_USB_OTG
 	/*
@@ -1329,12 +1295,90 @@
 		err = -ENOTSUPP;
 		goto fail;
 	}
+fail:
 #endif
+	return err;
+}
 
+
+/**
+ * usb_configure_device - Detect and probe device intfs/otg (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is only called by usb_new_device() and usb_authorize_device()
+ * and FIXME -- all comments that apply to them apply here wrt to
+ * environment.
+ *
+ * If the device is WUSB and not authorized, we don't attempt to read
+ * the string descriptors, as they will be errored out by the device
+ * until it has been authorized.
+ */
+static int usb_configure_device(struct usb_device *udev)
+{
+	int err;
+
+	if (udev->config == NULL) {
+		err = usb_get_configuration(udev);
+		if (err < 0) {
+			dev_err(&udev->dev, "can't read configurations, error %d\n",
+				err);
+			goto fail;
+		}
+	}
+	if (udev->wusb == 1 && udev->authorized == 0) {
+		udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+		udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+		udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+	}
+	else {
+		/* read the standard strings and cache them if present */
+		udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
+		udev->manufacturer = usb_cache_string(udev,
+						      udev->descriptor.iManufacturer);
+		udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
+	}
+	err = usb_configure_device_otg(udev);
+fail:
+	return err;
+}
+
+
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been enumerated, but not yet
+ * configured.  The device descriptor is available, but not descriptors
+ * for any device configuration.  The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * It will return if the device is configured properly or not.  Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ */
+int usb_new_device(struct usb_device *udev)
+{
+	int err;
+
+	usb_detect_quirks(udev);		/* Determine quirks */
+	err = usb_configure_device(udev);	/* detect & probe dev/intfs */
+	if (err < 0)
+		goto fail;
 	/* export the usbdev device-node for libusb */
 	udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
 			(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
 
+	/* Increment the parent's count of unsuspended children */
+	if (udev->parent)
+		usb_autoresume_device(udev->parent);
+
 	/* Register the device.  The device driver is responsible
 	 * for adding the device files to sysfs and for configuring
 	 * the device.
@@ -1345,18 +1389,103 @@
 		goto fail;
 	}
 
-	/* Increment the parent's count of unsuspended children */
-	if (udev->parent)
-		usb_autoresume_device(udev->parent);
-
-exit:
+	/* Tell the world! */
+	dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
+		"SerialNumber=%d\n",
+		udev->descriptor.iManufacturer,
+		udev->descriptor.iProduct,
+		udev->descriptor.iSerialNumber);
+	show_string(udev, "Product", udev->product);
+	show_string(udev, "Manufacturer", udev->manufacturer);
+	show_string(udev, "SerialNumber", udev->serial);
 	return err;
 
 fail:
 	usb_set_device_state(udev, USB_STATE_NOTATTACHED);
-	goto exit;
+	return err;
 }
 
+
+/**
+ * Similar to usb_disconnect()
+ *
+ * We share a lock (that we have) with device_del(), so we need to
+ * defer its call.
+ */
+int usb_deauthorize_device(struct usb_device *usb_dev)
+{
+	unsigned cnt;
+	usb_lock_device(usb_dev);
+	if (usb_dev->authorized == 0)
+		goto out_unauthorized;
+	usb_dev->authorized = 0;
+	usb_set_configuration(usb_dev, -1);
+	usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+	usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+	usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+	kfree(usb_dev->config);
+	usb_dev->config = NULL;
+	for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++)
+		kfree(usb_dev->rawdescriptors[cnt]);
+	usb_dev->descriptor.bNumConfigurations = 0;
+	kfree(usb_dev->rawdescriptors);
+out_unauthorized:
+	usb_unlock_device(usb_dev);
+	return 0;
+}
+
+
+int usb_authorize_device(struct usb_device *usb_dev)
+{
+	int result = 0, c;
+	usb_lock_device(usb_dev);
+	if (usb_dev->authorized == 1)
+		goto out_authorized;
+	kfree(usb_dev->product);
+	usb_dev->product = NULL;
+	kfree(usb_dev->manufacturer);
+	usb_dev->manufacturer = NULL;
+	kfree(usb_dev->serial);
+	usb_dev->serial = NULL;
+	result = usb_autoresume_device(usb_dev);
+	if (result < 0) {
+		dev_err(&usb_dev->dev,
+			"can't autoresume for authorization: %d\n", result);
+		goto error_autoresume;
+	}
+	result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
+	if (result < 0) {
+		dev_err(&usb_dev->dev, "can't re-read device descriptor for "
+			"authorization: %d\n", result);
+		goto error_device_descriptor;
+	}
+	usb_dev->authorized = 1;
+	result = usb_configure_device(usb_dev);
+	if (result < 0)
+		goto error_configure;
+	/* Choose and set the configuration.  This registers the interfaces
+	 * with the driver core and lets interface drivers bind to them.
+	 */
+	c = usb_choose_configuration(usb_dev);
+	if (c >= 0) {
+		result = usb_set_configuration(usb_dev, c);
+		if (result) {
+			dev_err(&usb_dev->dev,
+				"can't set config #%d, error %d\n", c, result);
+			/* This need not be fatal.  The user can try to
+			 * set other configurations. */
+		}
+	}
+	dev_info(&usb_dev->dev, "authorized to connect\n");
+error_configure:
+error_device_descriptor:
+error_autoresume:
+out_authorized:
+	usb_unlock_device(usb_dev);	// complements locktree
+	return result;
+}
+
+
 static int hub_port_status(struct usb_hub *hub, int port1,
 			       u16 *status, u16 *change)
 {
@@ -1458,6 +1587,11 @@
 {
 	int i, status;
 
+	/* Block EHCI CF initialization during the port reset.
+	 * Some companion controllers don't like it when they mix.
+	 */
+	down_read(&ehci_cf_port_reset_rwsem);
+
 	/* Reset the port */
 	for (i = 0; i < PORT_RESET_TRIES; i++) {
 		status = set_port_feature(hub->hdev,
@@ -1479,6 +1613,7 @@
 		case 0:
 			/* TRSTRCY = 10 ms; plus some extra */
 			msleep(10 + 40);
+		  	udev->devnum = 0;	/* Device now at address 0 */
 			/* FALL THROUGH */
 		case -ENOTCONN:
 		case -ENODEV:
@@ -1488,7 +1623,7 @@
 			usb_set_device_state(udev, status
 					? USB_STATE_NOTATTACHED
 					: USB_STATE_DEFAULT);
-			return status;
+			goto done;
 		}
 
 		dev_dbg (hub->intfdev,
@@ -1501,6 +1636,8 @@
 		"Cannot enable port %i.  Maybe the USB cable is bad?\n",
 		port1);
 
+ done:
+	up_read(&ehci_cf_port_reset_rwsem);
 	return status;
 }
 
@@ -1642,9 +1779,10 @@
 	 * and device drivers will know about any resume quirks.
 	 */
 	if (status == 0) {
+		devstatus = 0;
 		status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
 		if (status >= 0)
-			status = (status == 2 ? 0 : -ENODEV);
+			status = (status > 0 ? 0 : -ENODEV);
 	}
 
 	if (status) {
@@ -1830,14 +1968,7 @@
 		struct usb_device	*udev;
 
 		udev = hdev->children [port1-1];
-		if (udev && msg.event == PM_EVENT_SUSPEND &&
-#ifdef	CONFIG_USB_SUSPEND
-				udev->state != USB_STATE_SUSPENDED
-#else
-				udev->dev.power.power_state.event
-					== PM_EVENT_ON
-#endif
-				) {
+		if (udev && udev->can_submit) {
 			if (!hdev->auto_pm)
 				dev_dbg(&intf->dev, "port %d nyet suspended\n",
 						port1);
@@ -1996,26 +2127,27 @@
 {
 	usb_disable_endpoint(udev, 0 + USB_DIR_IN);
 	usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
-	udev->ep_in[0] = udev->ep_out[0] = &udev->ep0;
+	usb_enable_endpoint(udev, &udev->ep0);
 }
 
 #define usb_sndaddr0pipe()	(PIPE_CONTROL << 30)
 #define usb_rcvaddr0pipe()	((PIPE_CONTROL << 30) | USB_DIR_IN)
 
-static int hub_set_address(struct usb_device *udev)
+static int hub_set_address(struct usb_device *udev, int devnum)
 {
 	int retval;
 
-	if (udev->devnum == 0)
+	if (devnum <= 1)
 		return -EINVAL;
 	if (udev->state == USB_STATE_ADDRESS)
 		return 0;
 	if (udev->state != USB_STATE_DEFAULT)
 		return -EINVAL;
 	retval = usb_control_msg(udev, usb_sndaddr0pipe(),
-		USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
+		USB_REQ_SET_ADDRESS, 0, devnum, 0,
 		NULL, 0, USB_CTRL_SET_TIMEOUT);
 	if (retval == 0) {
+		udev->devnum = devnum;	/* Device now using proper address */
 		usb_set_device_state(udev, USB_STATE_ADDRESS);
 		ep0_reinit(udev);
 	}
@@ -2042,6 +2174,7 @@
 	unsigned		delay = HUB_SHORT_RESET_TIME;
 	enum usb_device_speed	oldspeed = udev->speed;
 	char 			*speed, *type;
+	int			devnum = udev->devnum;
 
 	/* root hub ports have a slightly longer reset period
 	 * (from USB 2.0 spec, section 7.1.7.5)
@@ -2071,7 +2204,7 @@
 		goto fail;
 	}
 	oldspeed = udev->speed;
-  
+
 	/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
 	 * it's fixed size except for full speed devices.
 	 * For Wireless USB devices, ep0 max packet is always 512 (tho
@@ -2112,7 +2245,7 @@
 	dev_info (&udev->dev,
 		  "%s %s speed %sUSB device using %s and address %d\n",
 		  (udev->config) ? "reset" : "new", speed, type,
-		  udev->bus->controller->driver->name, udev->devnum);
+		  udev->bus->controller->driver->name, devnum);
 
 	/* Set up TT records, if needed  */
 	if (hdev->tt) {
@@ -2199,7 +2332,7 @@
 		}
 
 		for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
-			retval = hub_set_address(udev);
+			retval = hub_set_address(udev, devnum);
 			if (retval >= 0)
 				break;
 			msleep(200);
@@ -2207,7 +2340,7 @@
 		if (retval < 0) {
 			dev_err(&udev->dev,
 				"device not accepting address %d, error %d\n",
-				udev->devnum, retval);
+				devnum, retval);
 			goto fail;
 		}
  
@@ -2260,8 +2393,10 @@
 	retval = 0;
 
 fail:
-	if (retval)
+	if (retval) {
 		hub_port_disable(hub, port1, 0);
+		udev->devnum = devnum;	/* for disconnect processing */
+	}
 	mutex_unlock(&usb_address0_mutex);
 	return retval;
 }
@@ -2696,9 +2831,9 @@
 				clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
 				if (hubstatus & HUB_STATUS_LOCAL_POWER)
 					/* FIXME: Is this always true? */
-					hub->limited_power = 0;
-				else
 					hub->limited_power = 1;
+				else
+					hub->limited_power = 0;
 			}
 			if (hubchange & HUB_CHANGE_OVERCURRENT) {
 				dev_dbg (hub_dev, "overcurrent change\n");
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 530e854..c021af3 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -18,9 +18,17 @@
 #include "hcd.h"	/* for usbcore internals */
 #include "usb.h"
 
+struct api_context {
+	struct completion	done;
+	int			status;
+};
+
 static void usb_api_blocking_completion(struct urb *urb)
 {
-	complete((struct completion *)urb->context);
+	struct api_context *ctx = urb->context;
+
+	ctx->status = urb->status;
+	complete(&ctx->done);
 }
 
 
@@ -32,38 +40,37 @@
  */
 static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
 { 
-	struct completion done;
+	struct api_context ctx;
 	unsigned long expire;
-	int status;
+	int retval;
 
-	init_completion(&done); 	
-	urb->context = &done;
+	init_completion(&ctx.done);
+	urb->context = &ctx;
 	urb->actual_length = 0;
-	status = usb_submit_urb(urb, GFP_NOIO);
-	if (unlikely(status))
+	retval = usb_submit_urb(urb, GFP_NOIO);
+	if (unlikely(retval))
 		goto out;
 
 	expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
-	if (!wait_for_completion_timeout(&done, expire)) {
+	if (!wait_for_completion_timeout(&ctx.done, expire)) {
+		usb_kill_urb(urb);
+		retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);
 
 		dev_dbg(&urb->dev->dev,
 			"%s timed out on ep%d%s len=%d/%d\n",
 			current->comm,
-			usb_pipeendpoint(urb->pipe),
-			usb_pipein(urb->pipe) ? "in" : "out",
+			usb_endpoint_num(&urb->ep->desc),
+			usb_urb_dir_in(urb) ? "in" : "out",
 			urb->actual_length,
 			urb->transfer_buffer_length);
-
-		usb_kill_urb(urb);
-		status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status;
 	} else
-		status = urb->status;
+		retval = ctx.status;
 out:
 	if (actual_length)
 		*actual_length = urb->actual_length;
 
 	usb_free_urb(urb);
-	return status;
+	return retval;
 }
 
 /*-------------------------------------------------------------------*/
@@ -243,13 +250,15 @@
 		io->urbs = NULL;
 	}
 	if (io->dev->dev.dma_mask != NULL)
-		usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
+		usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe),
+				io->sg, io->nents);
 	io->dev = NULL;
 }
 
 static void sg_complete (struct urb *urb)
 {
 	struct usb_sg_request	*io = urb->context;
+	int status = urb->status;
 
 	spin_lock (&io->lock);
 
@@ -265,21 +274,21 @@
 	 */
 	if (io->status
 			&& (io->status != -ECONNRESET
-				|| urb->status != -ECONNRESET)
+				|| status != -ECONNRESET)
 			&& urb->actual_length) {
 		dev_err (io->dev->bus->controller,
 			"dev %s ep%d%s scatterlist error %d/%d\n",
 			io->dev->devpath,
-			usb_pipeendpoint (urb->pipe),
-			usb_pipein (urb->pipe) ? "in" : "out",
-			urb->status, io->status);
+			usb_endpoint_num(&urb->ep->desc),
+			usb_urb_dir_in(urb) ? "in" : "out",
+			status, io->status);
 		// BUG ();
 	}
 
-	if (io->status == 0 && urb->status && urb->status != -ECONNRESET) {
-		int		i, found, status;
+	if (io->status == 0 && status && status != -ECONNRESET) {
+		int i, found, retval;
 
-		io->status = urb->status;
+		io->status = status;
 
 		/* the previous urbs, and this one, completed already.
 		 * unlink pending urbs so they won't rx/tx bad data.
@@ -290,13 +299,13 @@
 			if (!io->urbs [i] || !io->urbs [i]->dev)
 				continue;
 			if (found) {
-				status = usb_unlink_urb (io->urbs [i]);
-				if (status != -EINPROGRESS
-						&& status != -ENODEV
-						&& status != -EBUSY)
+				retval = usb_unlink_urb (io->urbs [i]);
+				if (retval != -EINPROGRESS &&
+				    retval != -ENODEV &&
+				    retval != -EBUSY)
 					dev_err (&io->dev->dev,
 						"%s, unlink --> %d\n",
-						__FUNCTION__, status);
+						__FUNCTION__, retval);
 			} else if (urb == io->urbs [i])
 				found = 1;
 		}
@@ -371,7 +380,8 @@
 	 */
 	dma = (dev->dev.dma_mask != NULL);
 	if (dma)
-		io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
+		io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
+				sg, nents);
 	else
 		io->entries = nents;
 
@@ -409,15 +419,22 @@
 		 * Some systems need to revert to PIO when DMA is temporarily
 		 * unavailable.  For their sakes, both transfer_buffer and
 		 * transfer_dma are set when possible.  However this can only
-		 * work on systems without HIGHMEM, since DMA buffers located
-		 * in high memory are not directly addressable by the CPU for
-		 * PIO ... so when HIGHMEM is in use, transfer_buffer is NULL
+		 * work on systems without:
+		 *
+		 *  - HIGHMEM, since DMA buffers located in high memory are
+		 *    not directly addressable by the CPU for PIO;
+		 *
+		 *  - IOMMU, since dma_map_sg() is allowed to use an IOMMU to
+		 *    make virtually discontiguous buffers be "dma-contiguous"
+		 *    so that PIO and DMA need diferent numbers of URBs.
+		 *
+		 * So when HIGHMEM or IOMMU are in use, transfer_buffer is NULL
 		 * to prevent stale pointers and to help spot bugs.
 		 */
 		if (dma) {
 			io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
 			len = sg_dma_len (sg + i);
-#ifdef CONFIG_HIGHMEM
+#if defined(CONFIG_HIGHMEM) || defined(CONFIG_IOMMU)
 			io->urbs[i]->transfer_buffer = NULL;
 #else
 			io->urbs[i]->transfer_buffer =
@@ -622,12 +639,12 @@
 	memset(buf,0,size);	// Make sure we parse really received data
 
 	for (i = 0; i < 3; ++i) {
-		/* retry on length 0 or stall; some devices are flakey */
+		/* retry on length 0 or error; some devices are flakey */
 		result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
 				USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
 				(type << 8) + index, 0, buf, size,
 				USB_CTRL_GET_TIMEOUT);
-		if (result == 0 || result == -EPIPE)
+		if (result <= 0 && result != -ETIMEDOUT)
 			continue;
 		if (result > 1 && ((u8 *)buf)[1] != type) {
 			result = -EPROTO;
@@ -998,8 +1015,11 @@
 		ep = dev->ep_in[epnum];
 		dev->ep_in[epnum] = NULL;
 	}
-	if (ep && dev->bus)
-		usb_hcd_endpoint_disable(dev, ep);
+	if (ep) {
+		ep->enabled = 0;
+		usb_hcd_flush_endpoint(dev, ep);
+		usb_hcd_disable_endpoint(dev, ep);
+	}
 }
 
 /**
@@ -1081,23 +1101,21 @@
  * Resets the endpoint toggle, and sets dev->ep_{in,out} pointers.
  * For control endpoints, both the input and output sides are handled.
  */
-static void
-usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
+void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
 {
-	unsigned int epaddr = ep->desc.bEndpointAddress;
-	unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
-	int is_control;
+	int epnum = usb_endpoint_num(&ep->desc);
+	int is_out = usb_endpoint_dir_out(&ep->desc);
+	int is_control = usb_endpoint_xfer_control(&ep->desc);
 
-	is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-			== USB_ENDPOINT_XFER_CONTROL);
-	if (usb_endpoint_out(epaddr) || is_control) {
+	if (is_out || is_control) {
 		usb_settoggle(dev, epnum, 1, 0);
 		dev->ep_out[epnum] = ep;
 	}
-	if (!usb_endpoint_out(epaddr) || is_control) {
+	if (!is_out || is_control) {
 		usb_settoggle(dev, epnum, 0, 0);
 		dev->ep_in[epnum] = ep;
 	}
+	ep->enabled = 1;
 }
 
 /*
@@ -1156,6 +1174,7 @@
 	struct usb_host_interface *alt;
 	int ret;
 	int manual = 0;
+	int changed;
 
 	if (dev->state == USB_STATE_SUSPENDED)
 		return -EHOSTUNREACH;
@@ -1195,7 +1214,8 @@
 	 */
 
 	/* prevent submissions using previous endpoint settings */
-	if (device_is_registered(&iface->dev))
+	changed = (iface->cur_altsetting != alt);
+	if (changed && device_is_registered(&iface->dev))
 		usb_remove_sysfs_intf_files(iface);
 	usb_disable_interface(dev, iface);
 
@@ -1232,7 +1252,7 @@
 	 * (Likewise, EP0 never "halts" on well designed devices.)
 	 */
 	usb_enable_interface(dev, iface);
-	if (device_is_registered(&iface->dev))
+	if (changed && device_is_registered(&iface->dev))
 		usb_create_sysfs_intf_files(iface);
 
 	return 0;
@@ -1313,7 +1333,7 @@
 	return 0;
 }
 
-void usb_release_interface(struct device *dev)
+static void usb_release_interface(struct device *dev)
 {
 	struct usb_interface *intf = to_usb_interface(dev);
 	struct usb_interface_cache *intfc =
@@ -1324,14 +1344,11 @@
 }
 
 #ifdef	CONFIG_HOTPLUG
-static int usb_if_uevent(struct device *dev, char **envp, int num_envp,
-		 char *buffer, int buffer_size)
+static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct usb_device *usb_dev;
 	struct usb_interface *intf;
 	struct usb_host_interface *alt;
-	int i = 0;
-	int length = 0;
 
 	if (!dev)
 		return -ENODEV;
@@ -1343,16 +1360,31 @@
 	usb_dev = interface_to_usbdev(intf);
 	alt = intf->cur_altsetting;
 
-	if (add_uevent_var(envp, num_envp, &i,
-		   buffer, buffer_size, &length,
-		   "INTERFACE=%d/%d/%d",
+#ifdef CONFIG_USB_DEVICEFS
+	if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",
+			   usb_dev->bus->busnum, usb_dev->devnum))
+		return -ENOMEM;
+#endif
+
+	if (add_uevent_var(env, "PRODUCT=%x/%x/%x",
+			   le16_to_cpu(usb_dev->descriptor.idVendor),
+			   le16_to_cpu(usb_dev->descriptor.idProduct),
+			   le16_to_cpu(usb_dev->descriptor.bcdDevice)))
+		return -ENOMEM;
+
+	if (add_uevent_var(env, "TYPE=%d/%d/%d",
+			   usb_dev->descriptor.bDeviceClass,
+			   usb_dev->descriptor.bDeviceSubClass,
+			   usb_dev->descriptor.bDeviceProtocol))
+		return -ENOMEM;
+
+	if (add_uevent_var(env, "INTERFACE=%d/%d/%d",
 		   alt->desc.bInterfaceClass,
 		   alt->desc.bInterfaceSubClass,
 		   alt->desc.bInterfaceProtocol))
 		return -ENOMEM;
 
-	if (add_uevent_var(envp, num_envp, &i,
-		   buffer, buffer_size, &length,
+	if (add_uevent_var(env,
 		   "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
 		   le16_to_cpu(usb_dev->descriptor.idVendor),
 		   le16_to_cpu(usb_dev->descriptor.idProduct),
@@ -1365,14 +1397,12 @@
 		   alt->desc.bInterfaceProtocol))
 		return -ENOMEM;
 
-	envp[i] = NULL;
 	return 0;
 }
 
 #else
 
-static int usb_if_uevent(struct device *dev, char **envp,
-			 int num_envp, char *buffer, int buffer_size)
+static int usb_if_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	return -ENODEV;
 }
@@ -1442,6 +1472,9 @@
  * channels are available independently; and choosing between open
  * standard device protocols (like CDC) or proprietary ones.
  *
+ * Note that a non-authorized device (dev->authorized == 0) will only
+ * be put in unconfigured mode.
+ *
  * Note that USB has an additional level of device configurability,
  * associated with interfaces.  That configurability is accessed using
  * usb_set_interface().
@@ -1463,7 +1496,7 @@
 	struct usb_interface **new_interfaces = NULL;
 	int n, nintf;
 
-	if (configuration == -1)
+	if (dev->authorized == 0 || configuration == -1)
 		configuration = 0;
 	else {
 		for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index aa21b38..d42c561 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -28,42 +28,26 @@
  * devices is broken...
  */
 static const struct usb_device_id usb_quirk_list[] = {
+	/* CBM - Flash disk */
+	{ USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
 	/* HP 5300/5370C scanner */
 	{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
-	/* Benq S2W 3300U */
-	{ USB_DEVICE(0x04a5, 0x20b0), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Seiko Epson Corp. Perfection 1200 */
-	{ USB_DEVICE(0x04b8, 0x0104), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Seiko Epson Corp - Perfection 1670 */
-	{ USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Samsung ML-2510 Series printer */
-	{ USB_DEVICE(0x04e8, 0x327e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Elsa MicroLink 56k (V.250) */
-	{ USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Ultima Electronics Corp.*/
-	{ USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Umax [hex] Astra 3400U */
-	{ USB_DEVICE(0x1606, 0x0060), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
+	/* INTEL VALUE SSD */
+	{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* M-Systems Flash Disk Pioneers */
+	{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
 
 	/* Philips PSC805 audio device */
 	{ USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
 
-	/* RIM Blackberry */
-	{ USB_DEVICE(0x0fca, 0x0001), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	{ USB_DEVICE(0x0fca, 0x0004), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	{ USB_DEVICE(0x0fca, 0x0006), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+	/* SKYMEDI USB_DRIVE */
+	{ USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
 
 	{ }  /* terminating entry must be last */
 };
 
-static void usb_autosuspend_quirk(struct usb_device *udev)
-{
-#ifdef	CONFIG_USB_SUSPEND
-	/* disable autosuspend, but allow the user to re-enable it via sysfs */
-	udev->autosuspend_disabled = 1;
-#endif
-}
-
 static const struct usb_device_id *find_id(struct usb_device *udev)
 {
 	const struct usb_device_id *id = usb_quirk_list;
@@ -90,7 +74,9 @@
 		dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
 				udev->quirks);
 
-	/* do any special quirk handling here if needed */
-	if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND)
-		usb_autosuspend_quirk(udev);
+	/* By default, disable autosuspend for all non-hubs */
+#ifdef	CONFIG_USB_SUSPEND
+	if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
+		udev->autosuspend_disabled = 1;
+#endif
 }
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index d47ae89..b04afd0 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -169,6 +169,16 @@
 }
 static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
 
+static ssize_t
+show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct usb_device *udev;
+
+	udev = to_usb_device(dev);
+	return sprintf(buf, "%d\n", atomic_read(&udev->urbnum));
+}
+static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
+
 
 #if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND)
 static const char power_group[] = "power";
@@ -413,6 +423,44 @@
 usb_descriptor_attr(bNumConfigurations, "%d\n")
 usb_descriptor_attr(bMaxPacketSize0, "%d\n")
 
+
+
+/* show if the device is authorized (1) or not (0) */
+static ssize_t usb_dev_authorized_show(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	struct usb_device *usb_dev = to_usb_device(dev);
+	return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized);
+}
+
+
+/*
+ * Authorize a device to be used in the system
+ *
+ * Writing a 0 deauthorizes the device, writing a 1 authorizes it.
+ */
+static ssize_t usb_dev_authorized_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t size)
+{
+	ssize_t result;
+	struct usb_device *usb_dev = to_usb_device(dev);
+	unsigned val;
+	result = sscanf(buf, "%u\n", &val);
+	if (result != 1)
+		result = -EINVAL;
+	else if (val == 0)
+		result = usb_deauthorize_device(usb_dev);
+	else
+		result = usb_authorize_device(usb_dev);
+	return result < 0? result : size;
+}
+
+static DEVICE_ATTR(authorized, 0644,
+	    usb_dev_authorized_show, usb_dev_authorized_store);
+
+
 static struct attribute *dev_attrs[] = {
 	/* current configuration's attributes */
 	&dev_attr_configuration.attr,
@@ -420,6 +468,7 @@
 	&dev_attr_bConfigurationValue.attr,
 	&dev_attr_bmAttributes.attr,
 	&dev_attr_bMaxPower.attr,
+	&dev_attr_urbnum.attr,
 	/* device attributes */
 	&dev_attr_idVendor.attr,
 	&dev_attr_idProduct.attr,
@@ -435,12 +484,61 @@
 	&dev_attr_version.attr,
 	&dev_attr_maxchild.attr,
 	&dev_attr_quirks.attr,
+	&dev_attr_authorized.attr,
 	NULL,
 };
 static struct attribute_group dev_attr_grp = {
 	.attrs = dev_attrs,
 };
 
+/* Binary descriptors */
+
+static ssize_t
+read_descriptors(struct kobject *kobj, struct bin_attribute *attr,
+		char *buf, loff_t off, size_t count)
+{
+	struct usb_device *udev = to_usb_device(
+			container_of(kobj, struct device, kobj));
+	size_t nleft = count;
+	size_t srclen, n;
+
+	usb_lock_device(udev);
+
+	/* The binary attribute begins with the device descriptor */
+	srclen = sizeof(struct usb_device_descriptor);
+	if (off < srclen) {
+		n = min_t(size_t, nleft, srclen - off);
+		memcpy(buf, off + (char *) &udev->descriptor, n);
+		nleft -= n;
+		buf += n;
+		off = 0;
+	} else {
+		off -= srclen;
+	}
+
+	/* Then follows the raw descriptor entry for the current
+	 * configuration (config plus subsidiary descriptors).
+	 */
+	if (udev->actconfig) {
+		int cfgno = udev->actconfig - udev->config;
+
+		srclen = __le16_to_cpu(udev->actconfig->desc.wTotalLength);
+		if (off < srclen) {
+			n = min_t(size_t, nleft, srclen - off);
+			memcpy(buf, off + udev->rawdescriptors[cfgno], n);
+			nleft -= n;
+		}
+	}
+	usb_unlock_device(udev);
+	return count - nleft;
+}
+
+static struct bin_attribute dev_bin_attr_descriptors = {
+	.attr = {.name = "descriptors", .mode = 0444},
+	.read = read_descriptors,
+	.size = 18 + 65535,	/* dev descr + max-size raw descriptor */
+};
+
 int usb_create_sysfs_dev_files(struct usb_device *udev)
 {
 	struct device *dev = &udev->dev;
@@ -450,6 +548,10 @@
 	if (retval)
 		return retval;
 
+	retval = device_create_bin_file(dev, &dev_bin_attr_descriptors);
+	if (retval)
+		goto error;
+
 	retval = add_persist_attributes(dev);
 	if (retval)
 		goto error;
@@ -492,6 +594,7 @@
 	device_remove_file(dev, &dev_attr_serial);
 	remove_power_attributes(dev);
 	remove_persist_attributes(dev);
+	device_remove_bin_file(dev, &dev_bin_attr_descriptors);
 	sysfs_remove_group(&dev->kobj, &dev_attr_grp);
 }
 
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 52ec44b..c20c03a 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -3,6 +3,7 @@
 #include <linux/bitops.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/log2.h>
 #include <linux/usb.h>
 #include <linux/wait.h>
 #include "hcd.h"
@@ -38,7 +39,6 @@
 	if (urb) {
 		memset(urb, 0, sizeof(*urb));
 		kref_init(&urb->kref);
-		spin_lock_init(&urb->lock);
 		INIT_LIST_HEAD(&urb->anchor_list);
 	}
 }
@@ -277,44 +277,58 @@
  */
 int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 {
-	int			pipe, temp, max;
-	struct usb_device	*dev;
-	int			is_out;
+	int				xfertype, max;
+	struct usb_device		*dev;
+	struct usb_host_endpoint	*ep;
+	int				is_out;
 
 	if (!urb || urb->hcpriv || !urb->complete)
 		return -EINVAL;
-	if (!(dev = urb->dev) ||
-	    (dev->state < USB_STATE_DEFAULT) ||
-	    (!dev->bus) || (dev->devnum <= 0))
+	if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT)
 		return -ENODEV;
-	if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
-			|| dev->state == USB_STATE_SUSPENDED)
-		return -EHOSTUNREACH;
 
+	/* For now, get the endpoint from the pipe.  Eventually drivers
+	 * will be required to set urb->ep directly and we will eliminate
+	 * urb->pipe.
+	 */
+	ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
+			[usb_pipeendpoint(urb->pipe)];
+	if (!ep)
+		return -ENOENT;
+
+	urb->ep = ep;
 	urb->status = -EINPROGRESS;
 	urb->actual_length = 0;
 
 	/* Lots of sanity checks, so HCDs can rely on clean data
 	 * and don't need to duplicate tests
 	 */
-	pipe = urb->pipe;
-	temp = usb_pipetype(pipe);
-	is_out = usb_pipeout(pipe);
+	xfertype = usb_endpoint_type(&ep->desc);
+	if (xfertype == USB_ENDPOINT_XFER_CONTROL) {
+		struct usb_ctrlrequest *setup =
+				(struct usb_ctrlrequest *) urb->setup_packet;
 
-	if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
+		if (!setup)
+			return -ENOEXEC;
+		is_out = !(setup->bRequestType & USB_DIR_IN) ||
+				!setup->wLength;
+	} else {
+		is_out = usb_endpoint_dir_out(&ep->desc);
+	}
+
+	/* Cache the direction for later use */
+	urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) |
+			(is_out ? URB_DIR_OUT : URB_DIR_IN);
+
+	if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
+			dev->state < USB_STATE_CONFIGURED)
 		return -ENODEV;
 
-	/* FIXME there should be a sharable lock protecting us against
-	 * config/altsetting changes and disconnects, kicking in here.
-	 * (here == before maxpacket, and eventually endpoint type,
-	 * checks get made.)
-	 */
-
-	max = usb_maxpacket(dev, pipe, is_out);
+	max = le16_to_cpu(ep->desc.wMaxPacketSize);
 	if (max <= 0) {
 		dev_dbg(&dev->dev,
 			"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
-			usb_pipeendpoint(pipe), is_out ? "out" : "in",
+			usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
 			__FUNCTION__, max);
 		return -EMSGSIZE;
 	}
@@ -323,7 +337,7 @@
 	 * but drivers only control those sizes for ISO.
 	 * while we're checking, initialize return status.
 	 */
-	if (temp == PIPE_ISOCHRONOUS) {
+	if (xfertype == USB_ENDPOINT_XFER_ISOC) {
 		int	n, len;
 
 		/* "high bandwidth" mode, 1-3 packets/uframe? */
@@ -358,20 +372,20 @@
 
 	/* enforce simple/standard policy */
 	allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
-			URB_NO_INTERRUPT);
-	switch (temp) {
-	case PIPE_BULK:
+			URB_NO_INTERRUPT | URB_DIR_MASK);
+	switch (xfertype) {
+	case USB_ENDPOINT_XFER_BULK:
 		if (is_out)
 			allowed |= URB_ZERO_PACKET;
 		/* FALLTHROUGH */
-	case PIPE_CONTROL:
+	case USB_ENDPOINT_XFER_CONTROL:
 		allowed |= URB_NO_FSBR;	/* only affects UHCI */
 		/* FALLTHROUGH */
 	default:			/* all non-iso endpoints */
 		if (!is_out)
 			allowed |= URB_SHORT_NOT_OK;
 		break;
-	case PIPE_ISOCHRONOUS:
+	case USB_ENDPOINT_XFER_ISOC:
 		allowed |= URB_ISO_ASAP;
 		break;
 	}
@@ -393,9 +407,9 @@
 	 * supports different values... this uses EHCI/UHCI defaults (and
 	 * EHCI can use smaller non-default values).
 	 */
-	switch (temp) {
-	case PIPE_ISOCHRONOUS:
-	case PIPE_INTERRUPT:
+	switch (xfertype) {
+	case USB_ENDPOINT_XFER_ISOC:
+	case USB_ENDPOINT_XFER_INT:
 		/* too small? */
 		if (urb->interval <= 0)
 			return -EINVAL;
@@ -405,29 +419,27 @@
 			// NOTE usb handles 2^15
 			if (urb->interval > (1024 * 8))
 				urb->interval = 1024 * 8;
-			temp = 1024 * 8;
+			max = 1024 * 8;
 			break;
 		case USB_SPEED_FULL:	/* units are frames/msec */
 		case USB_SPEED_LOW:
-			if (temp == PIPE_INTERRUPT) {
+			if (xfertype == USB_ENDPOINT_XFER_INT) {
 				if (urb->interval > 255)
 					return -EINVAL;
 				// NOTE ohci only handles up to 32
-				temp = 128;
+				max = 128;
 			} else {
 				if (urb->interval > 1024)
 					urb->interval = 1024;
 				// NOTE usb and ohci handle up to 2^15
-				temp = 1024;
+				max = 1024;
 			}
 			break;
 		default:
 			return -EINVAL;
 		}
-		/* power of two? */
-		while (temp > urb->interval)
-			temp >>= 1;
-		urb->interval = temp;
+		/* Round down to a power of 2, no more than max */
+		urb->interval = min(max, 1 << ilog2(urb->interval));
 	}
 
 	return usb_hcd_submit_urb(urb, mem_flags);
@@ -440,62 +452,66 @@
  * @urb: pointer to urb describing a previously submitted request,
  *	may be NULL
  *
- * This routine cancels an in-progress request.  URBs complete only
- * once per submission, and may be canceled only once per submission.
- * Successful cancellation means the requests's completion handler will
- * be called with a status code indicating that the request has been
- * canceled (rather than any other code) and will quickly be removed
- * from host controller data structures.
+ * This routine cancels an in-progress request.  URBs complete only once
+ * per submission, and may be canceled only once per submission.
+ * Successful cancellation means termination of @urb will be expedited
+ * and the completion handler will be called with a status code
+ * indicating that the request has been canceled (rather than any other
+ * code).
  *
- * This request is always asynchronous.
- * Success is indicated by returning -EINPROGRESS,
- * at which time the URB will normally have been unlinked but not yet
- * given back to the device driver.  When it is called, the completion
- * function will see urb->status == -ECONNRESET.  Failure is indicated
- * by any other return value.  Unlinking will fail when the URB is not
- * currently "linked" (i.e., it was never submitted, or it was unlinked
- * before, or the hardware is already finished with it), even if the
- * completion handler has not yet run.
+ * This request is always asynchronous.  Success is indicated by
+ * returning -EINPROGRESS, at which time the URB will probably not yet
+ * have been given back to the device driver.  When it is eventually
+ * called, the completion function will see @urb->status == -ECONNRESET.
+ * Failure is indicated by usb_unlink_urb() returning any other value.
+ * Unlinking will fail when @urb is not currently "linked" (i.e., it was
+ * never submitted, or it was unlinked before, or the hardware is already
+ * finished with it), even if the completion handler has not yet run.
  *
  * Unlinking and Endpoint Queues:
  *
+ * [The behaviors and guarantees described below do not apply to virtual
+ * root hubs but only to endpoint queues for physical USB devices.]
+ *
  * Host Controller Drivers (HCDs) place all the URBs for a particular
  * endpoint in a queue.  Normally the queue advances as the controller
  * hardware processes each request.  But when an URB terminates with an
- * error its queue stops, at least until that URB's completion routine
- * returns.  It is guaranteed that the queue will not restart until all
- * its unlinked URBs have been fully retired, with their completion
- * routines run, even if that's not until some time after the original
- * completion handler returns.  Normally the same behavior and guarantees
- * apply when an URB terminates because it was unlinked; however if an
- * URB is unlinked before the hardware has started to execute it, then
- * its queue is not guaranteed to stop until all the preceding URBs have
- * completed.
+ * error its queue generally stops (see below), at least until that URB's
+ * completion routine returns.  It is guaranteed that a stopped queue
+ * will not restart until all its unlinked URBs have been fully retired,
+ * with their completion routines run, even if that's not until some time
+ * after the original completion handler returns.  The same behavior and
+ * guarantee apply when an URB terminates because it was unlinked.
  *
- * This means that USB device drivers can safely build deep queues for
- * large or complex transfers, and clean them up reliably after any sort
- * of aborted transfer by unlinking all pending URBs at the first fault.
+ * Bulk and interrupt endpoint queues are guaranteed to stop whenever an
+ * URB terminates with any sort of error, including -ECONNRESET, -ENOENT,
+ * and -EREMOTEIO.  Control endpoint queues behave the same way except
+ * that they are not guaranteed to stop for -EREMOTEIO errors.  Queues
+ * for isochronous endpoints are treated differently, because they must
+ * advance at fixed rates.  Such queues do not stop when an URB
+ * encounters an error or is unlinked.  An unlinked isochronous URB may
+ * leave a gap in the stream of packets; it is undefined whether such
+ * gaps can be filled in.
  *
- * Note that an URB terminating early because a short packet was received
- * will count as an error if and only if the URB_SHORT_NOT_OK flag is set.
- * Also, that all unlinks performed in any URB completion handler must
- * be asynchronous.
+ * Note that early termination of an URB because a short packet was
+ * received will generate a -EREMOTEIO error if and only if the
+ * URB_SHORT_NOT_OK flag is set.  By setting this flag, USB device
+ * drivers can build deep queues for large or complex bulk transfers
+ * and clean them up reliably after any sort of aborted transfer by
+ * unlinking all pending URBs at the first fault.
  *
- * Queues for isochronous endpoints are treated differently, because they
- * advance at fixed rates.  Such queues do not stop when an URB is unlinked.
- * An unlinked URB may leave a gap in the stream of packets.  It is undefined
- * whether such gaps can be filled in.
- *
- * When a control URB terminates with an error, it is likely that the
- * status stage of the transfer will not take place, even if it is merely
- * a soft error resulting from a short-packet with URB_SHORT_NOT_OK set.
+ * When a control URB terminates with an error other than -EREMOTEIO, it
+ * is quite likely that the status stage of the transfer will not take
+ * place.
  */
 int usb_unlink_urb(struct urb *urb)
 {
 	if (!urb)
 		return -EINVAL;
-	if (!(urb->dev && urb->dev->bus))
+	if (!urb->dev)
 		return -ENODEV;
+	if (!urb->ep)
+		return -EIDRM;
 	return usb_hcd_unlink_urb(urb, -ECONNRESET);
 }
 
@@ -521,19 +537,21 @@
  */
 void usb_kill_urb(struct urb *urb)
 {
+	static DEFINE_MUTEX(reject_mutex);
+
 	might_sleep();
-	if (!(urb && urb->dev && urb->dev->bus))
+	if (!(urb && urb->dev && urb->ep))
 		return;
-	spin_lock_irq(&urb->lock);
+	mutex_lock(&reject_mutex);
 	++urb->reject;
-	spin_unlock_irq(&urb->lock);
+	mutex_unlock(&reject_mutex);
 
 	usb_hcd_unlink_urb(urb, -ENOENT);
 	wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
 
-	spin_lock_irq(&urb->lock);
+	mutex_lock(&reject_mutex);
 	--urb->reject;
-	spin_unlock_irq(&urb->lock);
+	mutex_unlock(&reject_mutex);
 }
 
 /**
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 0fee5c6..c99938d 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -223,6 +223,15 @@
 
 #endif	/* CONFIG_PM */
 
+
+/* Returns 1 if @usb_bus is WUSB, 0 otherwise */
+static unsigned usb_bus_is_wusb(struct usb_bus *bus)
+{
+	struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self);
+	return hcd->wireless;
+}
+
+
 /**
  * usb_alloc_dev - usb device constructor (usbcore-internal)
  * @parent: hub to which device is connected; null to allocate a root hub
@@ -239,6 +248,8 @@
 usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 {
 	struct usb_device *dev;
+	struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
+	unsigned root_hub = 0;
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev)
@@ -255,12 +266,14 @@
 	dev->dev.dma_mask = bus->controller->dma_mask;
 	set_dev_node(&dev->dev, dev_to_node(bus->controller));
 	dev->state = USB_STATE_ATTACHED;
+	atomic_set(&dev->urbnum, 0);
 
 	INIT_LIST_HEAD(&dev->ep0.urb_list);
 	dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
 	dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
 	/* ep0 maxpacket comes later, from device descriptor */
-	dev->ep_in[0] = dev->ep_out[0] = &dev->ep0;
+	usb_enable_endpoint(dev, &dev->ep0);
+	dev->can_submit = 1;
 
 	/* Save readable and stable topology id, distinguishing devices
 	 * by location for diagnostics, tools, driver model, etc.  The
@@ -275,6 +288,7 @@
 
 		dev->dev.parent = bus->controller;
 		sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
+		root_hub = 1;
 	} else {
 		/* match any labeling on the hubs; it's one-based */
 		if (parent->devpath[0] == '0')
@@ -301,6 +315,12 @@
 	INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
 	dev->autosuspend_delay = usb_autosuspend_delay * HZ;
 #endif
+	if (root_hub)	/* Root hub always ok [and always wired] */
+		dev->authorized = 1;
+	else {
+		dev->authorized = usb_hcd->authorized_default;
+		dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
+	}
 	return dev;
 }
 
@@ -748,7 +768,7 @@
 /**
  * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
  * @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
  * @sg: the scatterlist to map
  * @nents: the number of entries in the scatterlist
  *
@@ -771,14 +791,13 @@
  *
  * Reverse the effect of this call with usb_buffer_unmap_sg().
  */
-int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
+int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
 		      struct scatterlist *sg, int nents)
 {
 	struct usb_bus		*bus;
 	struct device		*controller;
 
 	if (!dev
-			|| usb_pipecontrol(pipe)
 			|| !(bus = dev->bus)
 			|| !(controller = bus->controller)
 			|| !controller->dma_mask)
@@ -786,7 +805,7 @@
 
 	// FIXME generic api broken like pci, can't report errors
 	return dma_map_sg(controller, sg, nents,
-			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+			is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* XXX DISABLED, no users currently.  If you wish to re-enable this
@@ -799,14 +818,14 @@
 /**
  * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s)
  * @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
  * @sg: the scatterlist to synchronize
  * @n_hw_ents: the positive return value from usb_buffer_map_sg
  *
  * Use this when you are re-using a scatterlist's data buffers for
  * another USB request.
  */
-void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
 			   struct scatterlist *sg, int n_hw_ents)
 {
 	struct usb_bus		*bus;
@@ -819,20 +838,20 @@
 		return;
 
 	dma_sync_sg(controller, sg, n_hw_ents,
-			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+			is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 #endif
 
 /**
  * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
  * @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
  * @sg: the scatterlist to unmap
  * @n_hw_ents: the positive return value from usb_buffer_map_sg
  *
  * Reverses the effect of usb_buffer_map_sg().
  */
-void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
 			 struct scatterlist *sg, int n_hw_ents)
 {
 	struct usb_bus		*bus;
@@ -845,7 +864,7 @@
 		return;
 
 	dma_unmap_sg(controller, sg, n_hw_ents,
-			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+			is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* format to disable USB on kernel command line is: nousb */
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index ad5fa03..c52626c 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -8,17 +8,22 @@
 				struct usb_device *udev);
 extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
 
+extern void usb_enable_endpoint(struct usb_device *dev,
+		struct usb_host_endpoint *ep);
 extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
 extern void usb_disable_interface (struct usb_device *dev,
 		struct usb_interface *intf);
 extern void usb_release_interface_cache(struct kref *ref);
 extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
+extern int usb_deauthorize_device (struct usb_device *);
+extern int usb_authorize_device (struct usb_device *);
 extern void usb_detect_quirks(struct usb_device *udev);
 
 extern int usb_get_device_descriptor(struct usb_device *dev,
 		unsigned int size);
 extern char *usb_cache_string(struct usb_device *udev, int index);
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
+extern int usb_choose_configuration(struct usb_device *udev);
 
 extern void usb_kick_khubd(struct usb_device *dev);
 extern int usb_match_device(struct usb_device *dev,
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 45e01e2..f81d08d 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -67,6 +67,17 @@
 	   driver on a new board.   Enable these files by choosing "Y"
 	   here.  If in doubt, or to conserve kernel memory, say "N".
 
+config USB_GADGET_DEBUG_FS
+	boolean "Debugging information files in debugfs"
+	depends on USB_GADGET && DEBUG_FS
+	help
+	   Some of the drivers in the "gadget" framework can expose
+	   debugging information in files under /sys/kernel/debug/.
+	   The information in these files may help when you're
+	   troubleshooting or bringing up a driver on a new board.
+	   Enable these files by choosing "Y" here.  If in doubt, or
+	   to conserve kernel memory, say "N".
+
 config	USB_GADGET_SELECTED
 	boolean
 
@@ -82,6 +93,41 @@
 	   Many controller drivers are platform-specific; these
 	   often need board-specific hooks.
 
+config USB_GADGET_AMD5536UDC
+	boolean "AMD5536 UDC"
+	depends on PCI
+	select USB_GADGET_DUALSPEED
+	help
+	   The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
+	   It is a USB Highspeed DMA capable USB device controller. Beside ep0
+	   it provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+	   The UDC port supports OTG operation, and may be used as a host port
+	   if it's not being used to implement peripheral or OTG roles.
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "amd5536udc" and force all
+	   gadget drivers to also be dynamically linked.
+
+config USB_AMD5536UDC
+	tristate
+	depends on USB_GADGET_AMD5536UDC
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+
+config USB_GADGET_ATMEL_USBA
+	boolean "Atmel USBA"
+	select USB_GADGET_DUALSPEED
+	depends on AVR32
+	help
+	  USBA is the integrated high-speed USB Device controller on
+	  the AT32AP700x processors from Atmel.
+
+config USB_ATMEL_USBA
+	tristate
+	depends on USB_GADGET_ATMEL_USBA
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+
 config USB_GADGET_FSL_USB2
 	boolean "Freescale Highspeed USB DR Peripheral Controller"
 	depends on MPC834x || PPC_MPC831x
@@ -156,6 +202,24 @@
 	default y if USB_ETH
 	default y if USB_G_SERIAL
 
+config USB_GADGET_M66592
+	boolean "Renesas M66592 USB Peripheral Controller"
+	select USB_GADGET_DUALSPEED
+	help
+	   M66592 is a discrete USB peripheral controller chip that
+	   supports both full and high speed USB 2.0 data transfers.
+	   It has seven configurable endpoints, and endpoint zero.
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "m66592_udc" and force all
+	   gadget drivers to also be dynamically linked.
+
+config USB_M66592
+	tristate
+	depends on USB_GADGET_M66592
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+
 config USB_GADGET_GOKU
 	boolean "Toshiba TC86C001 'Goku-S'"
 	depends on PCI
@@ -189,7 +253,6 @@
 	default USB_GADGET
 	select USB_GADGET_SELECTED
 
-
 config USB_GADGET_OMAP
 	boolean "OMAP USB Device Controller"
 	depends on ARCH_OMAP
@@ -261,24 +324,6 @@
 	depends on USB_GADGET_AT91
 	default USB_GADGET
 
-config USB_GADGET_M66592
-	boolean "M66592 driver"
-	select USB_GADGET_DUALSPEED
-	help
-	   M66592 is a USB 2.0 peripheral controller.
-
-	   It has seven configurable endpoints, and endpoint zero.
-
-	   Say "y" to link the driver statically, or "m" to build a
-	   dynamically linked module called "m66592_udc" and force all
-	   gadget drivers to also be dynamically linked.
-
-config USB_M66592
-	tristate
-	depends on USB_GADGET_M66592
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
 config USB_GADGET_DUMMY_HCD
 	boolean "Dummy HCD (DEVELOPMENT)"
 	depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 8ae76f7..904e57b 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -7,12 +7,14 @@
 
 obj-$(CONFIG_USB_DUMMY_HCD)	+= dummy_hcd.o
 obj-$(CONFIG_USB_NET2280)	+= net2280.o
+obj-$(CONFIG_USB_AMD5536UDC)	+= amd5536udc.o
 obj-$(CONFIG_USB_PXA2XX)	+= pxa2xx_udc.o
 obj-$(CONFIG_USB_GOKU)		+= goku_udc.o
 obj-$(CONFIG_USB_OMAP)		+= omap_udc.o
 obj-$(CONFIG_USB_LH7A40X)	+= lh7a40x_udc.o
 obj-$(CONFIG_USB_S3C2410)	+= s3c2410_udc.o
 obj-$(CONFIG_USB_AT91)		+= at91_udc.o
+obj-$(CONFIG_USB_ATMEL_USBA)	+= atmel_usba_udc.o
 obj-$(CONFIG_USB_FSL_USB2)	+= fsl_usb2_udc.o
 obj-$(CONFIG_USB_M66592)	+= m66592-udc.o
 
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
new file mode 100644
index 0000000..1c80406
--- /dev/null
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -0,0 +1,3451 @@
+/*
+ * amd5536.c -- AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2005-2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * 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
+ */
+
+/*
+ * The AMD5536 UDC is part of the x86 southbridge AMD Geode CS5536.
+ * It is a USB Highspeed DMA capable USB device controller. Beside ep0 it
+ * provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
+ *
+ * Make sure that UDC is assigned to port 4 by BIOS settings (port can also
+ * be used as host port) and UOC bits PAD_EN and APU are set (should be done
+ * by BIOS init).
+ *
+ * UDC DMA requires 32-bit aligned buffers so DMA with gadget ether does not
+ * work without updating NET_IP_ALIGN. Or PIO mode (module param "use_dma=0")
+ * can be used with gadget ether.
+ */
+
+/* debug control */
+/* #define UDC_VERBOSE */
+
+/* Driver strings */
+#define UDC_MOD_DESCRIPTION		"AMD 5536 UDC - USB Device Controller"
+#define UDC_DRIVER_VERSION_STRING	"01.00.0206 - $Revision: #3 $"
+
+/* system */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/dmapool.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+/* gadget stack */
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/* udc specific */
+#include "amd5536udc.h"
+
+
+static void udc_tasklet_disconnect(unsigned long);
+static void empty_req_queue(struct udc_ep *);
+static int udc_probe(struct udc *dev);
+static void udc_basic_init(struct udc *dev);
+static void udc_setup_endpoints(struct udc *dev);
+static void udc_soft_reset(struct udc *dev);
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep);
+static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq);
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req);
+static int udc_create_dma_chain(struct udc_ep *ep, struct udc_request *req,
+				unsigned long buf_len, gfp_t gfp_flags);
+static int udc_remote_wakeup(struct udc *dev);
+static int udc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id);
+static void udc_pci_remove(struct pci_dev *pdev);
+
+/* description */
+static const char mod_desc[] = UDC_MOD_DESCRIPTION;
+static const char name[] = "amd5536udc";
+
+/* structure to hold endpoint function pointers */
+static const struct usb_ep_ops udc_ep_ops;
+
+/* received setup data */
+static union udc_setup_data setup_data;
+
+/* pointer to device object */
+static struct udc *udc;
+
+/* irq spin lock for soft reset */
+static DEFINE_SPINLOCK(udc_irq_spinlock);
+/* stall spin lock */
+static DEFINE_SPINLOCK(udc_stall_spinlock);
+
+/*
+* slave mode: pending bytes in rx fifo after nyet,
+* used if EPIN irq came but no req was available
+*/
+static unsigned int udc_rxfifo_pending;
+
+/* count soft resets after suspend to avoid loop */
+static int soft_reset_occured;
+static int soft_reset_after_usbreset_occured;
+
+/* timer */
+static struct timer_list udc_timer;
+static int stop_timer;
+
+/* set_rde -- Is used to control enabling of RX DMA. Problem is
+ * that UDC has only one bit (RDE) to enable/disable RX DMA for
+ * all OUT endpoints. So we have to handle race conditions like
+ * when OUT data reaches the fifo but no request was queued yet.
+ * This cannot be solved by letting the RX DMA disabled until a
+ * request gets queued because there may be other OUT packets
+ * in the FIFO (important for not blocking control traffic).
+ * The value of set_rde controls the correspondig timer.
+ *
+ * set_rde -1 == not used, means it is alloed to be set to 0 or 1
+ * set_rde  0 == do not touch RDE, do no start the RDE timer
+ * set_rde  1 == timer function will look whether FIFO has data
+ * set_rde  2 == set by timer function to enable RX DMA on next call
+ */
+static int set_rde = -1;
+
+static DECLARE_COMPLETION(on_exit);
+static struct timer_list udc_pollstall_timer;
+static int stop_pollstall_timer;
+static DECLARE_COMPLETION(on_pollstall_exit);
+
+/* tasklet for usb disconnect */
+static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
+		(unsigned long) &udc);
+
+
+/* endpoint names used for print */
+static const char ep0_string[] = "ep0in";
+static const char *ep_string[] = {
+	ep0_string,
+	"ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk",
+	"ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk",
+	"ep11in-bulk", "ep12in-bulk", "ep13in-bulk", "ep14in-bulk",
+	"ep15in-bulk", "ep0out", "ep1out-bulk", "ep2out-bulk", "ep3out-bulk",
+	"ep4out-bulk", "ep5out-bulk", "ep6out-bulk", "ep7out-bulk",
+	"ep8out-bulk", "ep9out-bulk", "ep10out-bulk", "ep11out-bulk",
+	"ep12out-bulk", "ep13out-bulk", "ep14out-bulk", "ep15out-bulk"
+};
+
+/* DMA usage flag */
+static int use_dma = 1;
+/* packet per buffer dma */
+static int use_dma_ppb = 1;
+/* with per descr. update */
+static int use_dma_ppb_du;
+/* buffer fill mode */
+static int use_dma_bufferfill_mode;
+/* full speed only mode */
+static int use_fullspeed;
+/* tx buffer size for high speed */
+static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE;
+
+/* module parameters */
+module_param(use_dma, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma, "true for DMA");
+module_param(use_dma_ppb, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode");
+module_param(use_dma_ppb_du, bool, S_IRUGO);
+MODULE_PARM_DESC(use_dma_ppb_du,
+	"true for DMA in packet per buffer mode with descriptor update");
+module_param(use_fullspeed, bool, S_IRUGO);
+MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
+
+/*---------------------------------------------------------------------------*/
+/* Prints UDC device registers and endpoint irq registers */
+static void print_regs(struct udc *dev)
+{
+	DBG(dev, "------- Device registers -------\n");
+	DBG(dev, "dev config     = %08x\n", readl(&dev->regs->cfg));
+	DBG(dev, "dev control    = %08x\n", readl(&dev->regs->ctl));
+	DBG(dev, "dev status     = %08x\n", readl(&dev->regs->sts));
+	DBG(dev, "\n");
+	DBG(dev, "dev int's      = %08x\n", readl(&dev->regs->irqsts));
+	DBG(dev, "dev intmask    = %08x\n", readl(&dev->regs->irqmsk));
+	DBG(dev, "\n");
+	DBG(dev, "dev ep int's   = %08x\n", readl(&dev->regs->ep_irqsts));
+	DBG(dev, "dev ep intmask = %08x\n", readl(&dev->regs->ep_irqmsk));
+	DBG(dev, "\n");
+	DBG(dev, "USE DMA        = %d\n", use_dma);
+	if (use_dma && use_dma_ppb && !use_dma_ppb_du) {
+		DBG(dev, "DMA mode       = PPBNDU (packet per buffer "
+			"WITHOUT desc. update)\n");
+		dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBNDU");
+	} else if (use_dma && use_dma_ppb_du && use_dma_ppb_du) {
+		DBG(dev, "DMA mode       = PPBDU (packet per buffer "
+			"WITH desc. update)\n");
+		dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBDU");
+	}
+	if (use_dma && use_dma_bufferfill_mode) {
+		DBG(dev, "DMA mode       = BF (buffer fill mode)\n");
+		dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF");
+	}
+	if (!use_dma) {
+		dev_info(&dev->pdev->dev, "FIFO mode\n");
+	}
+	DBG(dev, "-------------------------------------------------------\n");
+}
+
+/* Masks unused interrupts */
+static int udc_mask_unused_interrupts(struct udc *dev)
+{
+	u32 tmp;
+
+	/* mask all dev interrupts */
+	tmp =	AMD_BIT(UDC_DEVINT_SVC) |
+		AMD_BIT(UDC_DEVINT_ENUM) |
+		AMD_BIT(UDC_DEVINT_US) |
+		AMD_BIT(UDC_DEVINT_UR) |
+		AMD_BIT(UDC_DEVINT_ES) |
+		AMD_BIT(UDC_DEVINT_SI) |
+		AMD_BIT(UDC_DEVINT_SOF)|
+		AMD_BIT(UDC_DEVINT_SC);
+	writel(tmp, &dev->regs->irqmsk);
+
+	/* mask all ep interrupts */
+	writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqmsk);
+
+	return 0;
+}
+
+/* Enables endpoint 0 interrupts */
+static int udc_enable_ep0_interrupts(struct udc *dev)
+{
+	u32 tmp;
+
+	DBG(dev, "udc_enable_ep0_interrupts()\n");
+
+	/* read irq mask */
+	tmp = readl(&dev->regs->ep_irqmsk);
+	/* enable ep0 irq's */
+	tmp &= AMD_UNMASK_BIT(UDC_EPINT_IN_EP0)
+		& AMD_UNMASK_BIT(UDC_EPINT_OUT_EP0);
+	writel(tmp, &dev->regs->ep_irqmsk);
+
+	return 0;
+}
+
+/* Enables device interrupts for SET_INTF and SET_CONFIG */
+static int udc_enable_dev_setup_interrupts(struct udc *dev)
+{
+	u32 tmp;
+
+	DBG(dev, "enable device interrupts for setup data\n");
+
+	/* read irq mask */
+	tmp = readl(&dev->regs->irqmsk);
+
+	/* enable SET_INTERFACE, SET_CONFIG and other needed irq's */
+	tmp &= AMD_UNMASK_BIT(UDC_DEVINT_SI)
+		& AMD_UNMASK_BIT(UDC_DEVINT_SC)
+		& AMD_UNMASK_BIT(UDC_DEVINT_UR)
+		& AMD_UNMASK_BIT(UDC_DEVINT_SVC)
+		& AMD_UNMASK_BIT(UDC_DEVINT_ENUM);
+	writel(tmp, &dev->regs->irqmsk);
+
+	return 0;
+}
+
+/* Calculates fifo start of endpoint based on preceeding endpoints */
+static int udc_set_txfifo_addr(struct udc_ep *ep)
+{
+	struct udc	*dev;
+	u32 tmp;
+	int i;
+
+	if (!ep || !(ep->in))
+		return -EINVAL;
+
+	dev = ep->dev;
+	ep->txfifo = dev->txfifo;
+
+	/* traverse ep's */
+	for (i = 0; i < ep->num; i++) {
+		if (dev->ep[i].regs) {
+			/* read fifo size */
+			tmp = readl(&dev->ep[i].regs->bufin_framenum);
+			tmp = AMD_GETBITS(tmp, UDC_EPIN_BUFF_SIZE);
+			ep->txfifo += tmp;
+		}
+	}
+	return 0;
+}
+
+/* CNAK pending field: bit0 = ep0in, bit16 = ep0out */
+static u32 cnak_pending;
+
+static void UDC_QUEUE_CNAK(struct udc_ep *ep, unsigned num)
+{
+	if (readl(&ep->regs->ctl) & AMD_BIT(UDC_EPCTL_NAK)) {
+		DBG(ep->dev, "NAK could not be cleared for ep%d\n", num);
+		cnak_pending |= 1 << (num);
+		ep->naking = 1;
+	} else
+		cnak_pending = cnak_pending & (~(1 << (num)));
+}
+
+
+/* Enables endpoint, is called by gadget driver */
+static int
+udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
+{
+	struct udc_ep		*ep;
+	struct udc		*dev;
+	u32			tmp;
+	unsigned long		iflags;
+	u8 udc_csr_epix;
+
+	if (!usbep
+			|| usbep->name == ep0_string
+			|| !desc
+			|| desc->bDescriptorType != USB_DT_ENDPOINT)
+		return -EINVAL;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	dev = ep->dev;
+
+	DBG(dev, "udc_ep_enable() ep %d\n", ep->num);
+
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	spin_lock_irqsave(&dev->lock, iflags);
+	ep->desc = desc;
+
+	ep->halted = 0;
+
+	/* set traffic type */
+	tmp = readl(&dev->ep[ep->num].regs->ctl);
+	tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_EPCTL_ET);
+	writel(tmp, &dev->ep[ep->num].regs->ctl);
+
+	/* set max packet size */
+	tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
+	tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_EP_MAX_PKT_SIZE);
+	ep->ep.maxpacket = desc->wMaxPacketSize;
+	writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt);
+
+	/* IN ep */
+	if (ep->in) {
+
+		/* ep ix in UDC CSR register space */
+		udc_csr_epix = ep->num;
+
+		/* set buffer size (tx fifo entries) */
+		tmp = readl(&dev->ep[ep->num].regs->bufin_framenum);
+		/* double buffering: fifo size = 2 x max packet size */
+		tmp = AMD_ADDBITS(
+				tmp,
+				desc->wMaxPacketSize * UDC_EPIN_BUFF_SIZE_MULT
+						/ UDC_DWORD_BYTES,
+				UDC_EPIN_BUFF_SIZE);
+		writel(tmp, &dev->ep[ep->num].regs->bufin_framenum);
+
+		/* calc. tx fifo base addr */
+		udc_set_txfifo_addr(ep);
+
+		/* flush fifo */
+		tmp = readl(&ep->regs->ctl);
+		tmp |= AMD_BIT(UDC_EPCTL_F);
+		writel(tmp, &ep->regs->ctl);
+
+	/* OUT ep */
+	} else {
+		/* ep ix in UDC CSR register space */
+		udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+
+		/* set max packet size UDC CSR	*/
+		tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+		tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize,
+					UDC_CSR_NE_MAX_PKT);
+		writel(tmp, &dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]);
+
+		if (use_dma && !ep->in) {
+			/* alloc and init BNA dummy request */
+			ep->bna_dummy_req = udc_alloc_bna_dummy(ep);
+			ep->bna_occurred = 0;
+		}
+
+		if (ep->num != UDC_EP0OUT_IX)
+			dev->data_ep_enabled = 1;
+	}
+
+	/* set ep values */
+	tmp = readl(&dev->csr->ne[udc_csr_epix]);
+	/* max packet */
+	tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT);
+	/* ep number */
+	tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM);
+	/* ep direction */
+	tmp = AMD_ADDBITS(tmp, ep->in, UDC_CSR_NE_DIR);
+	/* ep type */
+	tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_CSR_NE_TYPE);
+	/* ep config */
+	tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, UDC_CSR_NE_CFG);
+	/* ep interface */
+	tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, UDC_CSR_NE_INTF);
+	/* ep alt */
+	tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, UDC_CSR_NE_ALT);
+	/* write reg */
+	writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+	/* enable ep irq */
+	tmp = readl(&dev->regs->ep_irqmsk);
+	tmp &= AMD_UNMASK_BIT(ep->num);
+	writel(tmp, &dev->regs->ep_irqmsk);
+
+	/*
+	 * clear NAK by writing CNAK
+	 * avoid BNA for OUT DMA, don't clear NAK until DMA desc. written
+	 */
+	if (!use_dma || ep->in) {
+		tmp = readl(&ep->regs->ctl);
+		tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+		writel(tmp, &ep->regs->ctl);
+		ep->naking = 0;
+		UDC_QUEUE_CNAK(ep, ep->num);
+	}
+	tmp = desc->bEndpointAddress;
+	DBG(dev, "%s enabled\n", usbep->name);
+
+	spin_unlock_irqrestore(&dev->lock, iflags);
+	return 0;
+}
+
+/* Resets endpoint */
+static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)
+{
+	u32		tmp;
+
+	VDBG(ep->dev, "ep-%d reset\n", ep->num);
+	ep->desc = NULL;
+	ep->ep.ops = &udc_ep_ops;
+	INIT_LIST_HEAD(&ep->queue);
+
+	ep->ep.maxpacket = (u16) ~0;
+	/* set NAK */
+	tmp = readl(&ep->regs->ctl);
+	tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+	writel(tmp, &ep->regs->ctl);
+	ep->naking = 1;
+
+	/* disable interrupt */
+	tmp = readl(&regs->ep_irqmsk);
+	tmp |= AMD_BIT(ep->num);
+	writel(tmp, &regs->ep_irqmsk);
+
+	if (ep->in) {
+		/* unset P and IN bit of potential former DMA */
+		tmp = readl(&ep->regs->ctl);
+		tmp &= AMD_UNMASK_BIT(UDC_EPCTL_P);
+		writel(tmp, &ep->regs->ctl);
+
+		tmp = readl(&ep->regs->sts);
+		tmp |= AMD_BIT(UDC_EPSTS_IN);
+		writel(tmp, &ep->regs->sts);
+
+		/* flush the fifo */
+		tmp = readl(&ep->regs->ctl);
+		tmp |= AMD_BIT(UDC_EPCTL_F);
+		writel(tmp, &ep->regs->ctl);
+
+	}
+	/* reset desc pointer */
+	writel(0, &ep->regs->desptr);
+}
+
+/* Disables endpoint, is called by gadget driver */
+static int udc_ep_disable(struct usb_ep *usbep)
+{
+	struct udc_ep	*ep = NULL;
+	unsigned long	iflags;
+
+	if (!usbep)
+		return -EINVAL;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (usbep->name == ep0_string || !ep->desc)
+		return -EINVAL;
+
+	DBG(ep->dev, "Disable ep-%d\n", ep->num);
+
+	spin_lock_irqsave(&ep->dev->lock, iflags);
+	udc_free_request(&ep->ep, &ep->bna_dummy_req->req);
+	empty_req_queue(ep);
+	ep_init(ep->dev->regs, ep);
+	spin_unlock_irqrestore(&ep->dev->lock, iflags);
+
+	return 0;
+}
+
+/* Allocates request packet, called by gadget driver */
+static struct usb_request *
+udc_alloc_request(struct usb_ep *usbep, gfp_t gfp)
+{
+	struct udc_request	*req;
+	struct udc_data_dma	*dma_desc;
+	struct udc_ep	*ep;
+
+	if (!usbep)
+		return NULL;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+
+	VDBG(ep->dev, "udc_alloc_req(): ep%d\n", ep->num);
+	req = kzalloc(sizeof(struct udc_request), gfp);
+	if (!req)
+		return NULL;
+
+	req->req.dma = DMA_DONT_USE;
+	INIT_LIST_HEAD(&req->queue);
+
+	if (ep->dma) {
+		/* ep0 in requests are allocated from data pool here */
+		dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp,
+						&req->td_phys);
+		if (!dma_desc) {
+			kfree(req);
+			return NULL;
+		}
+
+		VDBG(ep->dev, "udc_alloc_req: req = %p dma_desc = %p, "
+				"td_phys = %lx\n",
+				req, dma_desc,
+				(unsigned long)req->td_phys);
+		/* prevent from using desc. - set HOST BUSY */
+		dma_desc->status = AMD_ADDBITS(dma_desc->status,
+						UDC_DMA_STP_STS_BS_HOST_BUSY,
+						UDC_DMA_STP_STS_BS);
+		dma_desc->bufptr = __constant_cpu_to_le32(DMA_DONT_USE);
+		req->td_data = dma_desc;
+		req->td_data_last = NULL;
+		req->chain_len = 1;
+	}
+
+	return &req->req;
+}
+
+/* Frees request packet, called by gadget driver */
+static void
+udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+	struct udc_ep	*ep;
+	struct udc_request	*req;
+
+	if (!usbep || !usbreq)
+		return;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	req = container_of(usbreq, struct udc_request, req);
+	VDBG(ep->dev, "free_req req=%p\n", req);
+	BUG_ON(!list_empty(&req->queue));
+	if (req->td_data) {
+		VDBG(ep->dev, "req->td_data=%p\n", req->td_data);
+
+		/* free dma chain if created */
+		if (req->chain_len > 1) {
+			udc_free_dma_chain(ep->dev, req);
+		}
+
+		pci_pool_free(ep->dev->data_requests, req->td_data,
+							req->td_phys);
+	}
+	kfree(req);
+}
+
+/* Init BNA dummy descriptor for HOST BUSY and pointing to itself */
+static void udc_init_bna_dummy(struct udc_request *req)
+{
+	if (req) {
+		/* set last bit */
+		req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+		/* set next pointer to itself */
+		req->td_data->next = req->td_phys;
+		/* set HOST BUSY */
+		req->td_data->status
+			= AMD_ADDBITS(req->td_data->status,
+					UDC_DMA_STP_STS_BS_DMA_DONE,
+					UDC_DMA_STP_STS_BS);
+#ifdef UDC_VERBOSE
+		pr_debug("bna desc = %p, sts = %08x\n",
+			req->td_data, req->td_data->status);
+#endif
+	}
+}
+
+/* Allocate BNA dummy descriptor */
+static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep)
+{
+	struct udc_request *req = NULL;
+	struct usb_request *_req = NULL;
+
+	/* alloc the dummy request */
+	_req = udc_alloc_request(&ep->ep, GFP_ATOMIC);
+	if (_req) {
+		req = container_of(_req, struct udc_request, req);
+		ep->bna_dummy_req = req;
+		udc_init_bna_dummy(req);
+	}
+	return req;
+}
+
+/* Write data to TX fifo for IN packets */
+static void
+udc_txfifo_write(struct udc_ep *ep, struct usb_request *req)
+{
+	u8			*req_buf;
+	u32			*buf;
+	int			i, j;
+	unsigned		bytes = 0;
+	unsigned		remaining = 0;
+
+	if (!req || !ep)
+		return;
+
+	req_buf = req->buf + req->actual;
+	prefetch(req_buf);
+	remaining = req->length - req->actual;
+
+	buf = (u32 *) req_buf;
+
+	bytes = ep->ep.maxpacket;
+	if (bytes > remaining)
+		bytes = remaining;
+
+	/* dwords first */
+	for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+		writel(*(buf + i), ep->txfifo);
+	}
+
+	/* remaining bytes must be written by byte access */
+	for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+		writeb((u8)(*(buf + i) >> (j << UDC_BITS_PER_BYTE_SHIFT)),
+							ep->txfifo);
+	}
+
+	/* dummy write confirm */
+	writel(0, &ep->regs->confirm);
+}
+
+/* Read dwords from RX fifo for OUT transfers */
+static int udc_rxfifo_read_dwords(struct udc *dev, u32 *buf, int dwords)
+{
+	int i;
+
+	VDBG(dev, "udc_read_dwords(): %d dwords\n", dwords);
+
+	for (i = 0; i < dwords; i++) {
+		*(buf + i) = readl(dev->rxfifo);
+	}
+	return 0;
+}
+
+/* Read bytes from RX fifo for OUT transfers */
+static int udc_rxfifo_read_bytes(struct udc *dev, u8 *buf, int bytes)
+{
+	int i, j;
+	u32 tmp;
+
+	VDBG(dev, "udc_read_bytes(): %d bytes\n", bytes);
+
+	/* dwords first */
+	for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+		*((u32 *)(buf + (i<<2))) = readl(dev->rxfifo);
+	}
+
+	/* remaining bytes must be read by byte access */
+	if (bytes % UDC_DWORD_BYTES) {
+		tmp = readl(dev->rxfifo);
+		for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
+			*(buf + (i<<2) + j) = (u8)(tmp & UDC_BYTE_MASK);
+			tmp = tmp >> UDC_BITS_PER_BYTE;
+		}
+	}
+
+	return 0;
+}
+
+/* Read data from RX fifo for OUT transfers */
+static int
+udc_rxfifo_read(struct udc_ep *ep, struct udc_request *req)
+{
+	u8 *buf;
+	unsigned buf_space;
+	unsigned bytes = 0;
+	unsigned finished = 0;
+
+	/* received number bytes */
+	bytes = readl(&ep->regs->sts);
+	bytes = AMD_GETBITS(bytes, UDC_EPSTS_RX_PKT_SIZE);
+
+	buf_space = req->req.length - req->req.actual;
+	buf = req->req.buf + req->req.actual;
+	if (bytes > buf_space) {
+		if ((buf_space % ep->ep.maxpacket) != 0) {
+			DBG(ep->dev,
+				"%s: rx %d bytes, rx-buf space = %d bytesn\n",
+				ep->ep.name, bytes, buf_space);
+			req->req.status = -EOVERFLOW;
+		}
+		bytes = buf_space;
+	}
+	req->req.actual += bytes;
+
+	/* last packet ? */
+	if (((bytes % ep->ep.maxpacket) != 0) || (!bytes)
+		|| ((req->req.actual == req->req.length) && !req->req.zero))
+		finished = 1;
+
+	/* read rx fifo bytes */
+	VDBG(ep->dev, "ep %s: rxfifo read %d bytes\n", ep->ep.name, bytes);
+	udc_rxfifo_read_bytes(ep->dev, buf, bytes);
+
+	return finished;
+}
+
+/* create/re-init a DMA descriptor or a DMA descriptor chain */
+static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp)
+{
+	int	retval = 0;
+	u32	tmp;
+
+	VDBG(ep->dev, "prep_dma\n");
+	VDBG(ep->dev, "prep_dma ep%d req->td_data=%p\n",
+			ep->num, req->td_data);
+
+	/* set buffer pointer */
+	req->td_data->bufptr = req->req.dma;
+
+	/* set last bit */
+	req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+
+	/* build/re-init dma chain if maxpkt scatter mode, not for EP0 */
+	if (use_dma_ppb) {
+
+		retval = udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp);
+		if (retval != 0) {
+			if (retval == -ENOMEM)
+				DBG(ep->dev, "Out of DMA memory\n");
+			return retval;
+		}
+		if (ep->in) {
+			if (req->req.length == ep->ep.maxpacket) {
+				/* write tx bytes */
+				req->td_data->status =
+					AMD_ADDBITS(req->td_data->status,
+						ep->ep.maxpacket,
+						UDC_DMA_IN_STS_TXBYTES);
+
+			}
+		}
+
+	}
+
+	if (ep->in) {
+		VDBG(ep->dev, "IN: use_dma_ppb=%d req->req.len=%d "
+				"maxpacket=%d ep%d\n",
+				use_dma_ppb, req->req.length,
+				ep->ep.maxpacket, ep->num);
+		/*
+		 * if bytes < max packet then tx bytes must
+		 * be written in packet per buffer mode
+		 */
+		if (!use_dma_ppb || req->req.length < ep->ep.maxpacket
+				|| ep->num == UDC_EP0OUT_IX
+				|| ep->num == UDC_EP0IN_IX) {
+			/* write tx bytes */
+			req->td_data->status =
+				AMD_ADDBITS(req->td_data->status,
+						req->req.length,
+						UDC_DMA_IN_STS_TXBYTES);
+			/* reset frame num */
+			req->td_data->status =
+				AMD_ADDBITS(req->td_data->status,
+						0,
+						UDC_DMA_IN_STS_FRAMENUM);
+		}
+		/* set HOST BUSY */
+		req->td_data->status =
+			AMD_ADDBITS(req->td_data->status,
+				UDC_DMA_STP_STS_BS_HOST_BUSY,
+				UDC_DMA_STP_STS_BS);
+	} else {
+		VDBG(ep->dev, "OUT set host ready\n");
+		/* set HOST READY */
+		req->td_data->status =
+			AMD_ADDBITS(req->td_data->status,
+				UDC_DMA_STP_STS_BS_HOST_READY,
+				UDC_DMA_STP_STS_BS);
+
+
+			/* clear NAK by writing CNAK */
+			if (ep->naking) {
+				tmp = readl(&ep->regs->ctl);
+				tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+				writel(tmp, &ep->regs->ctl);
+				ep->naking = 0;
+				UDC_QUEUE_CNAK(ep, ep->num);
+			}
+
+	}
+
+	return retval;
+}
+
+/* Completes request packet ... caller MUST hold lock */
+static void
+complete_req(struct udc_ep *ep, struct udc_request *req, int sts)
+__releases(ep->dev->lock)
+__acquires(ep->dev->lock)
+{
+	struct udc		*dev;
+	unsigned		halted;
+
+	VDBG(ep->dev, "complete_req(): ep%d\n", ep->num);
+
+	dev = ep->dev;
+	/* unmap DMA */
+	if (req->dma_mapping) {
+		if (ep->in)
+			pci_unmap_single(dev->pdev,
+					req->req.dma,
+					req->req.length,
+					PCI_DMA_TODEVICE);
+		else
+			pci_unmap_single(dev->pdev,
+					req->req.dma,
+					req->req.length,
+					PCI_DMA_FROMDEVICE);
+		req->dma_mapping = 0;
+		req->req.dma = DMA_DONT_USE;
+	}
+
+	halted = ep->halted;
+	ep->halted = 1;
+
+	/* set new status if pending */
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = sts;
+
+	/* remove from ep queue */
+	list_del_init(&req->queue);
+
+	VDBG(ep->dev, "req %p => complete %d bytes at %s with sts %d\n",
+		&req->req, req->req.length, ep->ep.name, sts);
+
+	spin_unlock(&dev->lock);
+	req->req.complete(&ep->ep, &req->req);
+	spin_lock(&dev->lock);
+	ep->halted = halted;
+}
+
+/* frees pci pool descriptors of a DMA chain */
+static int udc_free_dma_chain(struct udc *dev, struct udc_request *req)
+{
+
+	int ret_val = 0;
+	struct udc_data_dma	*td;
+	struct udc_data_dma	*td_last = NULL;
+	unsigned int i;
+
+	DBG(dev, "free chain req = %p\n", req);
+
+	/* do not free first desc., will be done by free for request */
+	td_last = req->td_data;
+	td = phys_to_virt(td_last->next);
+
+	for (i = 1; i < req->chain_len; i++) {
+
+		pci_pool_free(dev->data_requests, td,
+				(dma_addr_t) td_last->next);
+		td_last = td;
+		td = phys_to_virt(td_last->next);
+	}
+
+	return ret_val;
+}
+
+/* Iterates to the end of a DMA chain and returns last descriptor */
+static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req)
+{
+	struct udc_data_dma	*td;
+
+	td = req->td_data;
+	while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+		td = phys_to_virt(td->next);
+	}
+
+	return td;
+
+}
+
+/* Iterates to the end of a DMA chain and counts bytes received */
+static u32 udc_get_ppbdu_rxbytes(struct udc_request *req)
+{
+	struct udc_data_dma	*td;
+	u32 count;
+
+	td = req->td_data;
+	/* received number bytes */
+	count = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES);
+
+	while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+		td = phys_to_virt(td->next);
+		/* received number bytes */
+		if (td) {
+			count += AMD_GETBITS(td->status,
+				UDC_DMA_OUT_STS_RXBYTES);
+		}
+	}
+
+	return count;
+
+}
+
+/* Creates or re-inits a DMA chain */
+static int udc_create_dma_chain(
+	struct udc_ep *ep,
+	struct udc_request *req,
+	unsigned long buf_len, gfp_t gfp_flags
+)
+{
+	unsigned long bytes = req->req.length;
+	unsigned int i;
+	dma_addr_t dma_addr;
+	struct udc_data_dma	*td = NULL;
+	struct udc_data_dma	*last = NULL;
+	unsigned long txbytes;
+	unsigned create_new_chain = 0;
+	unsigned len;
+
+	VDBG(ep->dev, "udc_create_dma_chain: bytes=%ld buf_len=%ld\n",
+			bytes, buf_len);
+	dma_addr = DMA_DONT_USE;
+
+	/* unset L bit in first desc for OUT */
+	if (!ep->in) {
+		req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
+	}
+
+	/* alloc only new desc's if not already available */
+	len = req->req.length / ep->ep.maxpacket;
+	if (req->req.length % ep->ep.maxpacket) {
+		len++;
+	}
+
+	if (len > req->chain_len) {
+		/* shorter chain already allocated before */
+		if (req->chain_len > 1) {
+			udc_free_dma_chain(ep->dev, req);
+		}
+		req->chain_len = len;
+		create_new_chain = 1;
+	}
+
+	td = req->td_data;
+	/* gen. required number of descriptors and buffers */
+	for (i = buf_len; i < bytes; i += buf_len) {
+		/* create or determine next desc. */
+		if (create_new_chain) {
+
+			td = pci_pool_alloc(ep->dev->data_requests,
+					gfp_flags, &dma_addr);
+			if (!td)
+				return -ENOMEM;
+
+			td->status = 0;
+		} else if (i == buf_len) {
+			/* first td */
+			td = (struct udc_data_dma *) phys_to_virt(
+						req->td_data->next);
+			td->status = 0;
+		} else {
+			td = (struct udc_data_dma *) phys_to_virt(last->next);
+			td->status = 0;
+		}
+
+
+		if (td)
+			td->bufptr = req->req.dma + i; /* assign buffer */
+		else
+			break;
+
+		/* short packet ? */
+		if ((bytes - i) >= buf_len) {
+			txbytes = buf_len;
+		} else {
+			/* short packet */
+			txbytes = bytes - i;
+		}
+
+		/* link td and assign tx bytes */
+		if (i == buf_len) {
+			if (create_new_chain) {
+				req->td_data->next = dma_addr;
+			} else {
+				/* req->td_data->next = virt_to_phys(td); */
+			}
+			/* write tx bytes */
+			if (ep->in) {
+				/* first desc */
+				req->td_data->status =
+					AMD_ADDBITS(req->td_data->status,
+							ep->ep.maxpacket,
+							UDC_DMA_IN_STS_TXBYTES);
+				/* second desc */
+				td->status = AMD_ADDBITS(td->status,
+							txbytes,
+							UDC_DMA_IN_STS_TXBYTES);
+			}
+		} else {
+			if (create_new_chain) {
+				last->next = dma_addr;
+			} else {
+				/* last->next = virt_to_phys(td); */
+			}
+			if (ep->in) {
+				/* write tx bytes */
+				td->status = AMD_ADDBITS(td->status,
+							txbytes,
+							UDC_DMA_IN_STS_TXBYTES);
+			}
+		}
+		last = td;
+	}
+	/* set last bit */
+	if (td) {
+		td->status |= AMD_BIT(UDC_DMA_IN_STS_L);
+		/* last desc. points to itself */
+		req->td_data_last = td;
+	}
+
+	return 0;
+}
+
+/* Enabling RX DMA */
+static void udc_set_rde(struct udc *dev)
+{
+	u32 tmp;
+
+	VDBG(dev, "udc_set_rde()\n");
+	/* stop RDE timer */
+	if (timer_pending(&udc_timer)) {
+		set_rde = 0;
+		mod_timer(&udc_timer, jiffies - 1);
+	}
+	/* set RDE */
+	tmp = readl(&dev->regs->ctl);
+	tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+	writel(tmp, &dev->regs->ctl);
+}
+
+/* Queues a request packet, called by gadget driver */
+static int
+udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
+{
+	int			retval = 0;
+	u8			open_rxfifo = 0;
+	unsigned long		iflags;
+	struct udc_ep		*ep;
+	struct udc_request	*req;
+	struct udc		*dev;
+	u32			tmp;
+
+	/* check the inputs */
+	req = container_of(usbreq, struct udc_request, req);
+
+	if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf
+			|| !list_empty(&req->queue))
+		return -EINVAL;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+		return -EINVAL;
+
+	VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in);
+	dev = ep->dev;
+
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	/* map dma (usually done before) */
+	if (ep->dma && usbreq->length != 0
+			&& (usbreq->dma == DMA_DONT_USE || usbreq->dma == 0)) {
+		VDBG(dev, "DMA map req %p\n", req);
+		if (ep->in)
+			usbreq->dma = pci_map_single(dev->pdev,
+						usbreq->buf,
+						usbreq->length,
+						PCI_DMA_TODEVICE);
+		else
+			usbreq->dma = pci_map_single(dev->pdev,
+						usbreq->buf,
+						usbreq->length,
+						PCI_DMA_FROMDEVICE);
+		req->dma_mapping = 1;
+	}
+
+	VDBG(dev, "%s queue req %p, len %d req->td_data=%p buf %p\n",
+			usbep->name, usbreq, usbreq->length,
+			req->td_data, usbreq->buf);
+
+	spin_lock_irqsave(&dev->lock, iflags);
+	usbreq->actual = 0;
+	usbreq->status = -EINPROGRESS;
+	req->dma_done = 0;
+
+	/* on empty queue just do first transfer */
+	if (list_empty(&ep->queue)) {
+		/* zlp */
+		if (usbreq->length == 0) {
+			/* IN zlp's are handled by hardware */
+			complete_req(ep, req, 0);
+			VDBG(dev, "%s: zlp\n", ep->ep.name);
+			/*
+			 * if set_config or set_intf is waiting for ack by zlp
+			 * then set CSR_DONE
+			 */
+			if (dev->set_cfg_not_acked) {
+				tmp = readl(&dev->regs->ctl);
+				tmp |= AMD_BIT(UDC_DEVCTL_CSR_DONE);
+				writel(tmp, &dev->regs->ctl);
+				dev->set_cfg_not_acked = 0;
+			}
+			/* setup command is ACK'ed now by zlp */
+			if (dev->waiting_zlp_ack_ep0in) {
+				/* clear NAK by writing CNAK in EP0_IN */
+				tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+				tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+				writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+				dev->ep[UDC_EP0IN_IX].naking = 0;
+				UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX],
+							UDC_EP0IN_IX);
+				dev->waiting_zlp_ack_ep0in = 0;
+			}
+			goto finished;
+		}
+		if (ep->dma) {
+			retval = prep_dma(ep, req, gfp);
+			if (retval != 0)
+				goto finished;
+			/* write desc pointer to enable DMA */
+			if (ep->in) {
+				/* set HOST READY */
+				req->td_data->status =
+					AMD_ADDBITS(req->td_data->status,
+						UDC_DMA_IN_STS_BS_HOST_READY,
+						UDC_DMA_IN_STS_BS);
+			}
+
+			/* disabled rx dma while descriptor update */
+			if (!ep->in) {
+				/* stop RDE timer */
+				if (timer_pending(&udc_timer)) {
+					set_rde = 0;
+					mod_timer(&udc_timer, jiffies - 1);
+				}
+				/* clear RDE */
+				tmp = readl(&dev->regs->ctl);
+				tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+				writel(tmp, &dev->regs->ctl);
+				open_rxfifo = 1;
+
+				/*
+				 * if BNA occurred then let BNA dummy desc.
+				 * point to current desc.
+				 */
+				if (ep->bna_occurred) {
+					VDBG(dev, "copy to BNA dummy desc.\n");
+					memcpy(ep->bna_dummy_req->td_data,
+						req->td_data,
+						sizeof(struct udc_data_dma));
+				}
+			}
+			/* write desc pointer */
+			writel(req->td_phys, &ep->regs->desptr);
+
+			/* clear NAK by writing CNAK */
+			if (ep->naking) {
+				tmp = readl(&ep->regs->ctl);
+				tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+				writel(tmp, &ep->regs->ctl);
+				ep->naking = 0;
+				UDC_QUEUE_CNAK(ep, ep->num);
+			}
+
+			if (ep->in) {
+				/* enable ep irq */
+				tmp = readl(&dev->regs->ep_irqmsk);
+				tmp &= AMD_UNMASK_BIT(ep->num);
+				writel(tmp, &dev->regs->ep_irqmsk);
+			}
+		}
+
+	} else if (ep->dma) {
+
+		/*
+		 * prep_dma not used for OUT ep's, this is not possible
+		 * for PPB modes, because of chain creation reasons
+		 */
+		if (ep->in) {
+			retval = prep_dma(ep, req, gfp);
+			if (retval != 0)
+				goto finished;
+		}
+	}
+	VDBG(dev, "list_add\n");
+	/* add request to ep queue */
+	if (req) {
+
+		list_add_tail(&req->queue, &ep->queue);
+
+		/* open rxfifo if out data queued */
+		if (open_rxfifo) {
+			/* enable DMA */
+			req->dma_going = 1;
+			udc_set_rde(dev);
+			if (ep->num != UDC_EP0OUT_IX)
+				dev->data_ep_queued = 1;
+		}
+		/* stop OUT naking */
+		if (!ep->in) {
+			if (!use_dma && udc_rxfifo_pending) {
+				DBG(dev, "udc_queue(): pending bytes in"
+					"rxfifo after nyet\n");
+				/*
+				 * read pending bytes afer nyet:
+				 * referring to isr
+				 */
+				if (udc_rxfifo_read(ep, req)) {
+					/* finish */
+					complete_req(ep, req, 0);
+				}
+				udc_rxfifo_pending = 0;
+
+			}
+		}
+	}
+
+finished:
+	spin_unlock_irqrestore(&dev->lock, iflags);
+	return retval;
+}
+
+/* Empty request queue of an endpoint; caller holds spinlock */
+static void empty_req_queue(struct udc_ep *ep)
+{
+	struct udc_request	*req;
+
+	ep->halted = 1;
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next,
+			struct udc_request,
+			queue);
+		complete_req(ep, req, -ESHUTDOWN);
+	}
+}
+
+/* Dequeues a request packet, called by gadget driver */
+static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq)
+{
+	struct udc_ep		*ep;
+	struct udc_request	*req;
+	unsigned		halted;
+	unsigned long		iflags;
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (!usbep || !usbreq || (!ep->desc && (ep->num != 0
+				&& ep->num != UDC_EP0OUT_IX)))
+		return -EINVAL;
+
+	req = container_of(usbreq, struct udc_request, req);
+
+	spin_lock_irqsave(&ep->dev->lock, iflags);
+	halted = ep->halted;
+	ep->halted = 1;
+	/* request in processing or next one */
+	if (ep->queue.next == &req->queue) {
+		if (ep->dma && req->dma_going) {
+			if (ep->in)
+				ep->cancel_transfer = 1;
+			else {
+				u32 tmp;
+				u32 dma_sts;
+				/* stop potential receive DMA */
+				tmp = readl(&udc->regs->ctl);
+				writel(tmp & AMD_UNMASK_BIT(UDC_DEVCTL_RDE),
+							&udc->regs->ctl);
+				/*
+				 * Cancel transfer later in ISR
+				 * if descriptor was touched.
+				 */
+				dma_sts = AMD_GETBITS(req->td_data->status,
+							UDC_DMA_OUT_STS_BS);
+				if (dma_sts != UDC_DMA_OUT_STS_BS_HOST_READY)
+					ep->cancel_transfer = 1;
+				else {
+					udc_init_bna_dummy(ep->req);
+					writel(ep->bna_dummy_req->td_phys,
+						&ep->regs->desptr);
+				}
+				writel(tmp, &udc->regs->ctl);
+			}
+		}
+	}
+	complete_req(ep, req, -ECONNRESET);
+	ep->halted = halted;
+
+	spin_unlock_irqrestore(&ep->dev->lock, iflags);
+	return 0;
+}
+
+/* Halt or clear halt of endpoint */
+static int
+udc_set_halt(struct usb_ep *usbep, int halt)
+{
+	struct udc_ep	*ep;
+	u32 tmp;
+	unsigned long iflags;
+	int retval = 0;
+
+	if (!usbep)
+		return -EINVAL;
+
+	pr_debug("set_halt %s: halt=%d\n", usbep->name, halt);
+
+	ep = container_of(usbep, struct udc_ep, ep);
+	if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))
+		return -EINVAL;
+	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	spin_lock_irqsave(&udc_stall_spinlock, iflags);
+	/* halt or clear halt */
+	if (halt) {
+		if (ep->num == 0)
+			ep->dev->stall_ep0in = 1;
+		else {
+			/*
+			 * set STALL
+			 * rxfifo empty not taken into acount
+			 */
+			tmp = readl(&ep->regs->ctl);
+			tmp |= AMD_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);
+			ep->halted = 1;
+
+			/* setup poll timer */
+			if (!timer_pending(&udc_pollstall_timer)) {
+				udc_pollstall_timer.expires = jiffies +
+					HZ * UDC_POLLSTALL_TIMER_USECONDS
+					/ (1000 * 1000);
+				if (!stop_pollstall_timer) {
+					DBG(ep->dev, "start polltimer\n");
+					add_timer(&udc_pollstall_timer);
+				}
+			}
+		}
+	} else {
+		/* ep is halted by set_halt() before */
+		if (ep->halted) {
+			tmp = readl(&ep->regs->ctl);
+			/* clear stall bit */
+			tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+			/* clear NAK by writing CNAK */
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &ep->regs->ctl);
+			ep->halted = 0;
+			UDC_QUEUE_CNAK(ep, ep->num);
+		}
+	}
+	spin_unlock_irqrestore(&udc_stall_spinlock, iflags);
+	return retval;
+}
+
+/* gadget interface */
+static const struct usb_ep_ops udc_ep_ops = {
+	.enable		= udc_ep_enable,
+	.disable	= udc_ep_disable,
+
+	.alloc_request	= udc_alloc_request,
+	.free_request	= udc_free_request,
+
+	.queue		= udc_queue,
+	.dequeue	= udc_dequeue,
+
+	.set_halt	= udc_set_halt,
+	/* fifo ops not implemented */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Get frame counter (not implemented) */
+static int udc_get_frame(struct usb_gadget *gadget)
+{
+	return -EOPNOTSUPP;
+}
+
+/* Remote wakeup gadget interface */
+static int udc_wakeup(struct usb_gadget *gadget)
+{
+	struct udc		*dev;
+
+	if (!gadget)
+		return -EINVAL;
+	dev = container_of(gadget, struct udc, gadget);
+	udc_remote_wakeup(dev);
+
+	return 0;
+}
+
+/* gadget operations */
+static const struct usb_gadget_ops udc_ops = {
+	.wakeup		= udc_wakeup,
+	.get_frame	= udc_get_frame,
+};
+
+/* Setups endpoint parameters, adds endpoints to linked list */
+static void make_ep_lists(struct udc *dev)
+{
+	/* make gadget ep lists */
+	INIT_LIST_HEAD(&dev->gadget.ep_list);
+	list_add_tail(&dev->ep[UDC_EPIN_STATUS_IX].ep.ep_list,
+						&dev->gadget.ep_list);
+	list_add_tail(&dev->ep[UDC_EPIN_IX].ep.ep_list,
+						&dev->gadget.ep_list);
+	list_add_tail(&dev->ep[UDC_EPOUT_IX].ep.ep_list,
+						&dev->gadget.ep_list);
+
+	/* fifo config */
+	dev->ep[UDC_EPIN_STATUS_IX].fifo_depth = UDC_EPIN_SMALLINT_BUFF_SIZE;
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		dev->ep[UDC_EPIN_IX].fifo_depth = UDC_FS_EPIN_BUFF_SIZE;
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		dev->ep[UDC_EPIN_IX].fifo_depth = hs_tx_buf;
+	dev->ep[UDC_EPOUT_IX].fifo_depth = UDC_RXFIFO_SIZE;
+}
+
+/* init registers at driver load time */
+static int startup_registers(struct udc *dev)
+{
+	u32 tmp;
+
+	/* init controller by soft reset */
+	udc_soft_reset(dev);
+
+	/* mask not needed interrupts */
+	udc_mask_unused_interrupts(dev);
+
+	/* put into initial config */
+	udc_basic_init(dev);
+	/* link up all endpoints */
+	udc_setup_endpoints(dev);
+
+	/* program speed */
+	tmp = readl(&dev->regs->cfg);
+	if (use_fullspeed) {
+		tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+	} else {
+		tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
+	}
+	writel(tmp, &dev->regs->cfg);
+
+	return 0;
+}
+
+/* Inits UDC context */
+static void udc_basic_init(struct udc *dev)
+{
+	u32	tmp;
+
+	DBG(dev, "udc_basic_init()\n");
+
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+	/* stop RDE timer */
+	if (timer_pending(&udc_timer)) {
+		set_rde = 0;
+		mod_timer(&udc_timer, jiffies - 1);
+	}
+	/* stop poll stall timer */
+	if (timer_pending(&udc_pollstall_timer)) {
+		mod_timer(&udc_pollstall_timer, jiffies - 1);
+	}
+	/* disable DMA */
+	tmp = readl(&dev->regs->ctl);
+	tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
+	tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_TDE);
+	writel(tmp, &dev->regs->ctl);
+
+	/* enable dynamic CSR programming */
+	tmp = readl(&dev->regs->cfg);
+	tmp |= AMD_BIT(UDC_DEVCFG_CSR_PRG);
+	/* set self powered */
+	tmp |= AMD_BIT(UDC_DEVCFG_SP);
+	/* set remote wakeupable */
+	tmp |= AMD_BIT(UDC_DEVCFG_RWKP);
+	writel(tmp, &dev->regs->cfg);
+
+	make_ep_lists(dev);
+
+	dev->data_ep_enabled = 0;
+	dev->data_ep_queued = 0;
+}
+
+/* Sets initial endpoint parameters */
+static void udc_setup_endpoints(struct udc *dev)
+{
+	struct udc_ep	*ep;
+	u32	tmp;
+	u32	reg;
+
+	DBG(dev, "udc_setup_endpoints()\n");
+
+	/* read enum speed */
+	tmp = readl(&dev->regs->sts);
+	tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED);
+	if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH) {
+		dev->gadget.speed = USB_SPEED_HIGH;
+	} else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL) {
+		dev->gadget.speed = USB_SPEED_FULL;
+	}
+
+	/* set basic ep parameters */
+	for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+		ep = &dev->ep[tmp];
+		ep->dev = dev;
+		ep->ep.name = ep_string[tmp];
+		ep->num = tmp;
+		/* txfifo size is calculated at enable time */
+		ep->txfifo = dev->txfifo;
+
+		/* fifo size */
+		if (tmp < UDC_EPIN_NUM) {
+			ep->fifo_depth = UDC_TXFIFO_SIZE;
+			ep->in = 1;
+		} else {
+			ep->fifo_depth = UDC_RXFIFO_SIZE;
+			ep->in = 0;
+
+		}
+		ep->regs = &dev->ep_regs[tmp];
+		/*
+		 * ep will be reset only if ep was not enabled before to avoid
+		 * disabling ep interrupts when ENUM interrupt occurs but ep is
+		 * not enabled by gadget driver
+		 */
+		if (!ep->desc) {
+			ep_init(dev->regs, ep);
+		}
+
+		if (use_dma) {
+			/*
+			 * ep->dma is not really used, just to indicate that
+			 * DMA is active: remove this
+			 * dma regs = dev control regs
+			 */
+			ep->dma = &dev->regs->ctl;
+
+			/* nak OUT endpoints until enable - not for ep0 */
+			if (tmp != UDC_EP0IN_IX && tmp != UDC_EP0OUT_IX
+						&& tmp > UDC_EPIN_NUM) {
+				/* set NAK */
+				reg = readl(&dev->ep[tmp].regs->ctl);
+				reg |= AMD_BIT(UDC_EPCTL_SNAK);
+				writel(reg, &dev->ep[tmp].regs->ctl);
+				dev->ep[tmp].naking = 1;
+
+			}
+		}
+	}
+	/* EP0 max packet */
+	if (dev->gadget.speed == USB_SPEED_FULL) {
+		dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE;
+		dev->ep[UDC_EP0OUT_IX].ep.maxpacket =
+						UDC_FS_EP0OUT_MAX_PKT_SIZE;
+	} else if (dev->gadget.speed == USB_SPEED_HIGH) {
+		dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE;
+		dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE;
+	}
+
+	/*
+	 * with suspend bug workaround, ep0 params for gadget driver
+	 * are set at gadget driver bind() call
+	 */
+	dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+	dev->ep[UDC_EP0IN_IX].halted = 0;
+	INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+
+	/* init cfg/alt/int */
+	dev->cur_config = 0;
+	dev->cur_intf = 0;
+	dev->cur_alt = 0;
+}
+
+/* Bringup after Connect event, initial bringup to be ready for ep0 events */
+static void usb_connect(struct udc *dev)
+{
+
+	dev_info(&dev->pdev->dev, "USB Connect\n");
+
+	dev->connected = 1;
+
+	/* put into initial config */
+	udc_basic_init(dev);
+
+	/* enable device setup interrupts */
+	udc_enable_dev_setup_interrupts(dev);
+}
+
+/*
+ * Calls gadget with disconnect event and resets the UDC and makes
+ * initial bringup to be ready for ep0 events
+ */
+static void usb_disconnect(struct udc *dev)
+{
+
+	dev_info(&dev->pdev->dev, "USB Disconnect\n");
+
+	dev->connected = 0;
+
+	/* mask interrupts */
+	udc_mask_unused_interrupts(dev);
+
+	/* REVISIT there doesn't seem to be a point to having this
+	 * talk to a tasklet ... do it directly, we already hold
+	 * the spinlock needed to process the disconnect.
+	 */
+
+	tasklet_schedule(&disconnect_tasklet);
+}
+
+/* Tasklet for disconnect to be outside of interrupt context */
+static void udc_tasklet_disconnect(unsigned long par)
+{
+	struct udc *dev = (struct udc *)(*((struct udc **) par));
+	u32 tmp;
+
+	DBG(dev, "Tasklet disconnect\n");
+	spin_lock_irq(&dev->lock);
+
+	if (dev->driver) {
+		spin_unlock(&dev->lock);
+		dev->driver->disconnect(&dev->gadget);
+		spin_lock(&dev->lock);
+
+		/* empty queues */
+		for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+			empty_req_queue(&dev->ep[tmp]);
+		}
+
+	}
+
+	/* disable ep0 */
+	ep_init(dev->regs,
+			&dev->ep[UDC_EP0IN_IX]);
+
+
+	if (!soft_reset_occured) {
+		/* init controller by soft reset */
+		udc_soft_reset(dev);
+		soft_reset_occured++;
+	}
+
+	/* re-enable dev interrupts */
+	udc_enable_dev_setup_interrupts(dev);
+	/* back to full speed ? */
+	if (use_fullspeed) {
+		tmp = readl(&dev->regs->cfg);
+		tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
+		writel(tmp, &dev->regs->cfg);
+	}
+
+	spin_unlock_irq(&dev->lock);
+}
+
+/* Reset the UDC core */
+static void udc_soft_reset(struct udc *dev)
+{
+	unsigned long	flags;
+
+	DBG(dev, "Soft reset\n");
+	/*
+	 * reset possible waiting interrupts, because int.
+	 * status is lost after soft reset,
+	 * ep int. status reset
+	 */
+	writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqsts);
+	/* device int. status reset */
+	writel(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts);
+
+	spin_lock_irqsave(&udc_irq_spinlock, flags);
+	writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+	readl(&dev->regs->cfg);
+	spin_unlock_irqrestore(&udc_irq_spinlock, flags);
+
+}
+
+/* RDE timer callback to set RDE bit */
+static void udc_timer_function(unsigned long v)
+{
+	u32 tmp;
+
+	spin_lock_irq(&udc_irq_spinlock);
+
+	if (set_rde > 0) {
+		/*
+		 * open the fifo if fifo was filled on last timer call
+		 * conditionally
+		 */
+		if (set_rde > 1) {
+			/* set RDE to receive setup data */
+			tmp = readl(&udc->regs->ctl);
+			tmp |= AMD_BIT(UDC_DEVCTL_RDE);
+			writel(tmp, &udc->regs->ctl);
+			set_rde = -1;
+		} else if (readl(&udc->regs->sts)
+				& AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+			/*
+			 * if fifo empty setup polling, do not just
+			 * open the fifo
+			 */
+			udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV;
+			if (!stop_timer) {
+				add_timer(&udc_timer);
+			}
+		} else {
+			/*
+			 * fifo contains data now, setup timer for opening
+			 * the fifo when timer expires to be able to receive
+			 * setup packets, when data packets gets queued by
+			 * gadget layer then timer will forced to expire with
+			 * set_rde=0 (RDE is set in udc_queue())
+			 */
+			set_rde++;
+			/* debug: lhadmot_timer_start = 221070 */
+			udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS;
+			if (!stop_timer) {
+				add_timer(&udc_timer);
+			}
+		}
+
+	} else
+		set_rde = -1; /* RDE was set by udc_queue() */
+	spin_unlock_irq(&udc_irq_spinlock);
+	if (stop_timer)
+		complete(&on_exit);
+
+}
+
+/* Handle halt state, used in stall poll timer */
+static void udc_handle_halt_state(struct udc_ep *ep)
+{
+	u32 tmp;
+	/* set stall as long not halted */
+	if (ep->halted == 1) {
+		tmp = readl(&ep->regs->ctl);
+		/* STALL cleared ? */
+		if (!(tmp & AMD_BIT(UDC_EPCTL_S))) {
+			/*
+			 * FIXME: MSC spec requires that stall remains
+			 * even on receivng of CLEAR_FEATURE HALT. So
+			 * we would set STALL again here to be compliant.
+			 * But with current mass storage drivers this does
+			 * not work (would produce endless host retries).
+			 * So we clear halt on CLEAR_FEATURE.
+			 *
+			DBG(ep->dev, "ep %d: set STALL again\n", ep->num);
+			tmp |= AMD_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);*/
+
+			/* clear NAK by writing CNAK */
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &ep->regs->ctl);
+			ep->halted = 0;
+			UDC_QUEUE_CNAK(ep, ep->num);
+		}
+	}
+}
+
+/* Stall timer callback to poll S bit and set it again after */
+static void udc_pollstall_timer_function(unsigned long v)
+{
+	struct udc_ep *ep;
+	int halted = 0;
+
+	spin_lock_irq(&udc_stall_spinlock);
+	/*
+	 * only one IN and OUT endpoints are handled
+	 * IN poll stall
+	 */
+	ep = &udc->ep[UDC_EPIN_IX];
+	udc_handle_halt_state(ep);
+	if (ep->halted)
+		halted = 1;
+	/* OUT poll stall */
+	ep = &udc->ep[UDC_EPOUT_IX];
+	udc_handle_halt_state(ep);
+	if (ep->halted)
+		halted = 1;
+
+	/* setup timer again when still halted */
+	if (!stop_pollstall_timer && halted) {
+		udc_pollstall_timer.expires = jiffies +
+					HZ * UDC_POLLSTALL_TIMER_USECONDS
+					/ (1000 * 1000);
+		add_timer(&udc_pollstall_timer);
+	}
+	spin_unlock_irq(&udc_stall_spinlock);
+
+	if (stop_pollstall_timer)
+		complete(&on_pollstall_exit);
+}
+
+/* Inits endpoint 0 so that SETUP packets are processed */
+static void activate_control_endpoints(struct udc *dev)
+{
+	u32 tmp;
+
+	DBG(dev, "activate_control_endpoints\n");
+
+	/* flush fifo */
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+	tmp |= AMD_BIT(UDC_EPCTL_F);
+	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+	/* set ep0 directions */
+	dev->ep[UDC_EP0IN_IX].in = 1;
+	dev->ep[UDC_EP0OUT_IX].in = 0;
+
+	/* set buffer size (tx fifo entries) of EP0_IN */
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp = AMD_ADDBITS(tmp, UDC_FS_EPIN0_BUFF_SIZE,
+					UDC_EPIN_BUFF_SIZE);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp = AMD_ADDBITS(tmp, UDC_EPIN0_BUFF_SIZE,
+					UDC_EPIN_BUFF_SIZE);
+	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufin_framenum);
+
+	/* set max packet size of EP0_IN */
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp = AMD_ADDBITS(tmp, UDC_FS_EP0IN_MAX_PKT_SIZE,
+					UDC_EP_MAX_PKT_SIZE);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp = AMD_ADDBITS(tmp, UDC_EP0IN_MAX_PKT_SIZE,
+				UDC_EP_MAX_PKT_SIZE);
+	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt);
+
+	/* set max packet size of EP0_OUT */
+	tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+					UDC_EP_MAX_PKT_SIZE);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+					UDC_EP_MAX_PKT_SIZE);
+	writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt);
+
+	/* set max packet size of EP0 in UDC CSR */
+	tmp = readl(&dev->csr->ne[0]);
+	if (dev->gadget.speed == USB_SPEED_FULL)
+		tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE,
+					UDC_CSR_NE_MAX_PKT);
+	else if (dev->gadget.speed == USB_SPEED_HIGH)
+		tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE,
+					UDC_CSR_NE_MAX_PKT);
+	writel(tmp, &dev->csr->ne[0]);
+
+	if (use_dma) {
+		dev->ep[UDC_EP0OUT_IX].td->status |=
+			AMD_BIT(UDC_DMA_OUT_STS_L);
+		/* write dma desc address */
+		writel(dev->ep[UDC_EP0OUT_IX].td_stp_dma,
+			&dev->ep[UDC_EP0OUT_IX].regs->subptr);
+		writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+			&dev->ep[UDC_EP0OUT_IX].regs->desptr);
+		/* stop RDE timer */
+		if (timer_pending(&udc_timer)) {
+			set_rde = 0;
+			mod_timer(&udc_timer, jiffies - 1);
+		}
+		/* stop pollstall timer */
+		if (timer_pending(&udc_pollstall_timer)) {
+			mod_timer(&udc_pollstall_timer, jiffies - 1);
+		}
+		/* enable DMA */
+		tmp = readl(&dev->regs->ctl);
+		tmp |= AMD_BIT(UDC_DEVCTL_MODE)
+				| AMD_BIT(UDC_DEVCTL_RDE)
+				| AMD_BIT(UDC_DEVCTL_TDE);
+		if (use_dma_bufferfill_mode) {
+			tmp |= AMD_BIT(UDC_DEVCTL_BF);
+		} else if (use_dma_ppb_du) {
+			tmp |= AMD_BIT(UDC_DEVCTL_DU);
+		}
+		writel(tmp, &dev->regs->ctl);
+	}
+
+	/* clear NAK by writing CNAK for EP0IN */
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+	tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+	writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+	dev->ep[UDC_EP0IN_IX].naking = 0;
+	UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+	/* clear NAK by writing CNAK for EP0OUT */
+	tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+	tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+	writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+	dev->ep[UDC_EP0OUT_IX].naking = 0;
+	UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+}
+
+/* Make endpoint 0 ready for control traffic */
+static int setup_ep0(struct udc *dev)
+{
+	activate_control_endpoints(dev);
+	/* enable ep0 interrupts */
+	udc_enable_ep0_interrupts(dev);
+	/* enable device setup interrupts */
+	udc_enable_dev_setup_interrupts(dev);
+
+	return 0;
+}
+
+/* Called by gadget driver to register itself */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct udc		*dev = udc;
+	int			retval;
+	u32 tmp;
+
+	if (!driver || !driver->bind || !driver->setup
+			|| driver->speed != USB_SPEED_HIGH)
+		return -EINVAL;
+	if (!dev)
+		return -ENODEV;
+	if (dev->driver)
+		return -EBUSY;
+
+	driver->driver.bus = NULL;
+	dev->driver = driver;
+	dev->gadget.dev.driver = &driver->driver;
+
+	retval = driver->bind(&dev->gadget);
+
+	/* Some gadget drivers use both ep0 directions.
+	 * NOTE: to gadget driver, ep0 is just one endpoint...
+	 */
+	dev->ep[UDC_EP0OUT_IX].ep.driver_data =
+		dev->ep[UDC_EP0IN_IX].ep.driver_data;
+
+	if (retval) {
+		DBG(dev, "binding to %s returning %d\n",
+				driver->driver.name, retval);
+		dev->driver = NULL;
+		dev->gadget.dev.driver = NULL;
+		return retval;
+	}
+
+	/* get ready for ep0 traffic */
+	setup_ep0(dev);
+
+	/* clear SD */
+	tmp = readl(&dev->regs->ctl);
+	tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD);
+	writel(tmp, &dev->regs->ctl);
+
+	usb_connect(dev);
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+/* shutdown requests and disconnect from gadget */
+static void
+shutdown(struct udc *dev, struct usb_gadget_driver *driver)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+	int tmp;
+
+	/* empty queues and init hardware */
+	udc_basic_init(dev);
+	for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+		empty_req_queue(&dev->ep[tmp]);
+	}
+
+	if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
+		spin_unlock(&dev->lock);
+		driver->disconnect(&dev->gadget);
+		spin_lock(&dev->lock);
+	}
+	/* init */
+	udc_setup_endpoints(dev);
+}
+
+/* Called by gadget driver to unregister itself */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct udc	*dev = udc;
+	unsigned long	flags;
+	u32 tmp;
+
+	if (!dev)
+		return -ENODEV;
+	if (!driver || driver != dev->driver || !driver->unbind)
+		return -EINVAL;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	udc_mask_unused_interrupts(dev);
+	shutdown(dev, driver);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	driver->unbind(&dev->gadget);
+	dev->driver = NULL;
+
+	/* set SD */
+	tmp = readl(&dev->regs->ctl);
+	tmp |= AMD_BIT(UDC_DEVCTL_SD);
+	writel(tmp, &dev->regs->ctl);
+
+
+	DBG(dev, "%s: unregistered\n", driver->driver.name);
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+
+/* Clear pending NAK bits */
+static void udc_process_cnak_queue(struct udc *dev)
+{
+	u32 tmp;
+	u32 reg;
+
+	/* check epin's */
+	DBG(dev, "CNAK pending queue processing\n");
+	for (tmp = 0; tmp < UDC_EPIN_NUM_USED; tmp++) {
+		if (cnak_pending & (1 << tmp)) {
+			DBG(dev, "CNAK pending for ep%d\n", tmp);
+			/* clear NAK by writing CNAK */
+			reg = readl(&dev->ep[tmp].regs->ctl);
+			reg |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(reg, &dev->ep[tmp].regs->ctl);
+			dev->ep[tmp].naking = 0;
+			UDC_QUEUE_CNAK(&dev->ep[tmp], dev->ep[tmp].num);
+		}
+	}
+	/* ...	and ep0out */
+	if (cnak_pending & (1 << UDC_EP0OUT_IX)) {
+		DBG(dev, "CNAK pending for ep%d\n", UDC_EP0OUT_IX);
+		/* clear NAK by writing CNAK */
+		reg = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+		reg |= AMD_BIT(UDC_EPCTL_CNAK);
+		writel(reg, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+		dev->ep[UDC_EP0OUT_IX].naking = 0;
+		UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX],
+				dev->ep[UDC_EP0OUT_IX].num);
+	}
+}
+
+/* Enabling RX DMA after setup packet */
+static void udc_ep0_set_rde(struct udc *dev)
+{
+	if (use_dma) {
+		/*
+		 * only enable RXDMA when no data endpoint enabled
+		 * or data is queued
+		 */
+		if (!dev->data_ep_enabled || dev->data_ep_queued) {
+			udc_set_rde(dev);
+		} else {
+			/*
+			 * setup timer for enabling RDE (to not enable
+			 * RXFIFO DMA for data endpoints to early)
+			 */
+			if (set_rde != 0 && !timer_pending(&udc_timer)) {
+				udc_timer.expires =
+					jiffies + HZ/UDC_RDE_TIMER_DIV;
+				set_rde = 1;
+				if (!stop_timer) {
+					add_timer(&udc_timer);
+				}
+			}
+		}
+	}
+}
+
+
+/* Interrupt handler for data OUT traffic */
+static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
+{
+	irqreturn_t		ret_val = IRQ_NONE;
+	u32			tmp;
+	struct udc_ep		*ep;
+	struct udc_request	*req;
+	unsigned int		count;
+	struct udc_data_dma	*td = NULL;
+	unsigned		dma_done;
+
+	VDBG(dev, "ep%d irq\n", ep_ix);
+	ep = &dev->ep[ep_ix];
+
+	tmp = readl(&ep->regs->sts);
+	if (use_dma) {
+		/* BNA event ? */
+		if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+			DBG(dev, "BNA ep%dout occured - DESPTR = %x \n",
+					ep->num, readl(&ep->regs->desptr));
+			/* clear BNA */
+			writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts);
+			if (!ep->cancel_transfer)
+				ep->bna_occurred = 1;
+			else
+				ep->cancel_transfer = 0;
+			ret_val = IRQ_HANDLED;
+			goto finished;
+		}
+	}
+	/* HE event ? */
+	if (tmp & AMD_BIT(UDC_EPSTS_HE)) {
+		dev_err(&dev->pdev->dev, "HE ep%dout occured\n", ep->num);
+
+		/* clear HE */
+		writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+		ret_val = IRQ_HANDLED;
+		goto finished;
+	}
+
+	if (!list_empty(&ep->queue)) {
+
+		/* next request */
+		req = list_entry(ep->queue.next,
+			struct udc_request, queue);
+	} else {
+		req = NULL;
+		udc_rxfifo_pending = 1;
+	}
+	VDBG(dev, "req = %p\n", req);
+	/* fifo mode */
+	if (!use_dma) {
+
+		/* read fifo */
+		if (req && udc_rxfifo_read(ep, req)) {
+			ret_val = IRQ_HANDLED;
+
+			/* finish */
+			complete_req(ep, req, 0);
+			/* next request */
+			if (!list_empty(&ep->queue) && !ep->halted) {
+				req = list_entry(ep->queue.next,
+					struct udc_request, queue);
+			} else
+				req = NULL;
+		}
+
+	/* DMA */
+	} else if (!ep->cancel_transfer && req != NULL) {
+		ret_val = IRQ_HANDLED;
+
+		/* check for DMA done */
+		if (!use_dma_ppb) {
+			dma_done = AMD_GETBITS(req->td_data->status,
+						UDC_DMA_OUT_STS_BS);
+		/* packet per buffer mode - rx bytes */
+		} else {
+			/*
+			 * if BNA occurred then recover desc. from
+			 * BNA dummy desc.
+			 */
+			if (ep->bna_occurred) {
+				VDBG(dev, "Recover desc. from BNA dummy\n");
+				memcpy(req->td_data, ep->bna_dummy_req->td_data,
+						sizeof(struct udc_data_dma));
+				ep->bna_occurred = 0;
+				udc_init_bna_dummy(ep->req);
+			}
+			td = udc_get_last_dma_desc(req);
+			dma_done = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_BS);
+		}
+		if (dma_done == UDC_DMA_OUT_STS_BS_DMA_DONE) {
+			/* buffer fill mode - rx bytes */
+			if (!use_dma_ppb) {
+				/* received number bytes */
+				count = AMD_GETBITS(req->td_data->status,
+						UDC_DMA_OUT_STS_RXBYTES);
+				VDBG(dev, "rx bytes=%u\n", count);
+			/* packet per buffer mode - rx bytes */
+			} else {
+				VDBG(dev, "req->td_data=%p\n", req->td_data);
+				VDBG(dev, "last desc = %p\n", td);
+				/* received number bytes */
+				if (use_dma_ppb_du) {
+					/* every desc. counts bytes */
+					count = udc_get_ppbdu_rxbytes(req);
+				} else {
+					/* last desc. counts bytes */
+					count = AMD_GETBITS(td->status,
+						UDC_DMA_OUT_STS_RXBYTES);
+					if (!count && req->req.length
+						== UDC_DMA_MAXPACKET) {
+						/*
+						 * on 64k packets the RXBYTES
+						 * field is zero
+						 */
+						count = UDC_DMA_MAXPACKET;
+					}
+				}
+				VDBG(dev, "last desc rx bytes=%u\n", count);
+			}
+
+			tmp = req->req.length - req->req.actual;
+			if (count > tmp) {
+				if ((tmp % ep->ep.maxpacket) != 0) {
+					DBG(dev, "%s: rx %db, space=%db\n",
+						ep->ep.name, count, tmp);
+					req->req.status = -EOVERFLOW;
+				}
+				count = tmp;
+			}
+			req->req.actual += count;
+			req->dma_going = 0;
+			/* complete request */
+			complete_req(ep, req, 0);
+
+			/* next request */
+			if (!list_empty(&ep->queue) && !ep->halted) {
+				req = list_entry(ep->queue.next,
+					struct udc_request,
+					queue);
+				/*
+				 * DMA may be already started by udc_queue()
+				 * called by gadget drivers completion
+				 * routine. This happens when queue
+				 * holds one request only.
+				 */
+				if (req->dma_going == 0) {
+					/* next dma */
+					if (prep_dma(ep, req, GFP_ATOMIC) != 0)
+						goto finished;
+					/* write desc pointer */
+					writel(req->td_phys,
+						&ep->regs->desptr);
+					req->dma_going = 1;
+					/* enable DMA */
+					udc_set_rde(dev);
+				}
+			} else {
+				/*
+				 * implant BNA dummy descriptor to allow
+				 * RXFIFO opening by RDE
+				 */
+				if (ep->bna_dummy_req) {
+					/* write desc pointer */
+					writel(ep->bna_dummy_req->td_phys,
+						&ep->regs->desptr);
+					ep->bna_occurred = 0;
+				}
+
+				/*
+				 * schedule timer for setting RDE if queue
+				 * remains empty to allow ep0 packets pass
+				 * through
+				 */
+				if (set_rde != 0
+						&& !timer_pending(&udc_timer)) {
+					udc_timer.expires =
+						jiffies
+						+ HZ*UDC_RDE_TIMER_SECONDS;
+					set_rde = 1;
+					if (!stop_timer) {
+						add_timer(&udc_timer);
+					}
+				}
+				if (ep->num != UDC_EP0OUT_IX)
+					dev->data_ep_queued = 0;
+			}
+
+		} else {
+			/*
+			* RX DMA must be reenabled for each desc in PPBDU mode
+			* and must be enabled for PPBNDU mode in case of BNA
+			*/
+			udc_set_rde(dev);
+		}
+
+	} else if (ep->cancel_transfer) {
+		ret_val = IRQ_HANDLED;
+		ep->cancel_transfer = 0;
+	}
+
+	/* check pending CNAKS */
+	if (cnak_pending) {
+		/* CNAk processing when rxfifo empty only */
+		if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+			udc_process_cnak_queue(dev);
+		}
+	}
+
+	/* clear OUT bits in ep status */
+	writel(UDC_EPSTS_OUT_CLEAR, &ep->regs->sts);
+finished:
+	return ret_val;
+}
+
+/* Interrupt handler for data IN traffic */
+static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
+{
+	irqreturn_t ret_val = IRQ_NONE;
+	u32 tmp;
+	u32 epsts;
+	struct udc_ep *ep;
+	struct udc_request *req;
+	struct udc_data_dma *td;
+	unsigned dma_done;
+	unsigned len;
+
+	ep = &dev->ep[ep_ix];
+
+	epsts = readl(&ep->regs->sts);
+	if (use_dma) {
+		/* BNA ? */
+		if (epsts & AMD_BIT(UDC_EPSTS_BNA)) {
+			dev_err(&dev->pdev->dev,
+				"BNA ep%din occured - DESPTR = %08lx \n",
+				ep->num,
+				(unsigned long) readl(&ep->regs->desptr));
+
+			/* clear BNA */
+			writel(epsts, &ep->regs->sts);
+			ret_val = IRQ_HANDLED;
+			goto finished;
+		}
+	}
+	/* HE event ? */
+	if (epsts & AMD_BIT(UDC_EPSTS_HE)) {
+		dev_err(&dev->pdev->dev,
+			"HE ep%dn occured - DESPTR = %08lx \n",
+			ep->num, (unsigned long) readl(&ep->regs->desptr));
+
+		/* clear HE */
+		writel(epsts | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts);
+		ret_val = IRQ_HANDLED;
+		goto finished;
+	}
+
+	/* DMA completion */
+	if (epsts & AMD_BIT(UDC_EPSTS_TDC)) {
+		VDBG(dev, "TDC set- completion\n");
+		ret_val = IRQ_HANDLED;
+		if (!ep->cancel_transfer && !list_empty(&ep->queue)) {
+			req = list_entry(ep->queue.next,
+					struct udc_request, queue);
+			if (req) {
+				/*
+				 * length bytes transfered
+				 * check dma done of last desc. in PPBDU mode
+				 */
+				if (use_dma_ppb_du) {
+					td = udc_get_last_dma_desc(req);
+					if (td) {
+						dma_done =
+							AMD_GETBITS(td->status,
+							UDC_DMA_IN_STS_BS);
+						/* don't care DMA done */
+						req->req.actual =
+							req->req.length;
+					}
+				} else {
+					/* assume all bytes transferred */
+					req->req.actual = req->req.length;
+				}
+
+				if (req->req.actual == req->req.length) {
+					/* complete req */
+					complete_req(ep, req, 0);
+					req->dma_going = 0;
+					/* further request available ? */
+					if (list_empty(&ep->queue)) {
+						/* disable interrupt */
+						tmp = readl(
+							&dev->regs->ep_irqmsk);
+						tmp |= AMD_BIT(ep->num);
+						writel(tmp,
+							&dev->regs->ep_irqmsk);
+					}
+
+				}
+			}
+		}
+		ep->cancel_transfer = 0;
+
+	}
+	/*
+	 * status reg has IN bit set and TDC not set (if TDC was handled,
+	 * IN must not be handled (UDC defect) ?
+	 */
+	if ((epsts & AMD_BIT(UDC_EPSTS_IN))
+			&& !(epsts & AMD_BIT(UDC_EPSTS_TDC))) {
+		ret_val = IRQ_HANDLED;
+		if (!list_empty(&ep->queue)) {
+			/* next request */
+			req = list_entry(ep->queue.next,
+					struct udc_request, queue);
+			/* FIFO mode */
+			if (!use_dma) {
+				/* write fifo */
+				udc_txfifo_write(ep, &req->req);
+				len = req->req.length - req->req.actual;
+						if (len > ep->ep.maxpacket)
+							len = ep->ep.maxpacket;
+						req->req.actual += len;
+				if (req->req.actual == req->req.length
+					|| (len != ep->ep.maxpacket)) {
+					/* complete req */
+					complete_req(ep, req, 0);
+				}
+			/* DMA */
+			} else if (req && !req->dma_going) {
+				VDBG(dev, "IN DMA : req=%p req->td_data=%p\n",
+					req, req->td_data);
+				if (req->td_data) {
+
+					req->dma_going = 1;
+
+					/*
+					 * unset L bit of first desc.
+					 * for chain
+					 */
+					if (use_dma_ppb && req->req.length >
+							ep->ep.maxpacket) {
+						req->td_data->status &=
+							AMD_CLEAR_BIT(
+							UDC_DMA_IN_STS_L);
+					}
+
+					/* write desc pointer */
+					writel(req->td_phys, &ep->regs->desptr);
+
+					/* set HOST READY */
+					req->td_data->status =
+						AMD_ADDBITS(
+						req->td_data->status,
+						UDC_DMA_IN_STS_BS_HOST_READY,
+						UDC_DMA_IN_STS_BS);
+
+					/* set poll demand bit */
+					tmp = readl(&ep->regs->ctl);
+					tmp |= AMD_BIT(UDC_EPCTL_P);
+					writel(tmp, &ep->regs->ctl);
+				}
+			}
+
+		}
+	}
+	/* clear status bits */
+	writel(epsts, &ep->regs->sts);
+
+finished:
+	return ret_val;
+
+}
+
+/* Interrupt handler for Control OUT traffic */
+static irqreturn_t udc_control_out_isr(struct udc *dev)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+	irqreturn_t ret_val = IRQ_NONE;
+	u32 tmp;
+	int setup_supported;
+	u32 count;
+	int set = 0;
+	struct udc_ep	*ep;
+	struct udc_ep	*ep_tmp;
+
+	ep = &dev->ep[UDC_EP0OUT_IX];
+
+	/* clear irq */
+	writel(AMD_BIT(UDC_EPINT_OUT_EP0), &dev->regs->ep_irqsts);
+
+	tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+	/* check BNA and clear if set */
+	if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
+		VDBG(dev, "ep0: BNA set\n");
+		writel(AMD_BIT(UDC_EPSTS_BNA),
+			&dev->ep[UDC_EP0OUT_IX].regs->sts);
+		ep->bna_occurred = 1;
+		ret_val = IRQ_HANDLED;
+		goto finished;
+	}
+
+	/* type of data: SETUP or DATA 0 bytes */
+	tmp = AMD_GETBITS(tmp, UDC_EPSTS_OUT);
+	VDBG(dev, "data_typ = %x\n", tmp);
+
+	/* setup data */
+	if (tmp == UDC_EPSTS_OUT_SETUP) {
+		ret_val = IRQ_HANDLED;
+
+		ep->dev->stall_ep0in = 0;
+		dev->waiting_zlp_ack_ep0in = 0;
+
+		/* set NAK for EP0_IN */
+		tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+		tmp |= AMD_BIT(UDC_EPCTL_SNAK);
+		writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+		dev->ep[UDC_EP0IN_IX].naking = 1;
+		/* get setup data */
+		if (use_dma) {
+
+			/* clear OUT bits in ep status */
+			writel(UDC_EPSTS_OUT_CLEAR,
+				&dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+			setup_data.data[0] =
+				dev->ep[UDC_EP0OUT_IX].td_stp->data12;
+			setup_data.data[1] =
+				dev->ep[UDC_EP0OUT_IX].td_stp->data34;
+			/* set HOST READY */
+			dev->ep[UDC_EP0OUT_IX].td_stp->status =
+					UDC_DMA_STP_STS_BS_HOST_READY;
+		} else {
+			/* read fifo */
+			udc_rxfifo_read_dwords(dev, setup_data.data, 2);
+		}
+
+		/* determine direction of control data */
+		if ((setup_data.request.bRequestType & USB_DIR_IN) != 0) {
+			dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep;
+			/* enable RDE */
+			udc_ep0_set_rde(dev);
+			set = 0;
+		} else {
+			dev->gadget.ep0 = &dev->ep[UDC_EP0OUT_IX].ep;
+			/*
+			 * implant BNA dummy descriptor to allow RXFIFO opening
+			 * by RDE
+			 */
+			if (ep->bna_dummy_req) {
+				/* write desc pointer */
+				writel(ep->bna_dummy_req->td_phys,
+					&dev->ep[UDC_EP0OUT_IX].regs->desptr);
+				ep->bna_occurred = 0;
+			}
+
+			set = 1;
+			dev->ep[UDC_EP0OUT_IX].naking = 1;
+			/*
+			 * setup timer for enabling RDE (to not enable
+			 * RXFIFO DMA for data to early)
+			 */
+			set_rde = 1;
+			if (!timer_pending(&udc_timer)) {
+				udc_timer.expires = jiffies +
+							HZ/UDC_RDE_TIMER_DIV;
+				if (!stop_timer) {
+					add_timer(&udc_timer);
+				}
+			}
+		}
+
+		/*
+		 * mass storage reset must be processed here because
+		 * next packet may be a CLEAR_FEATURE HALT which would not
+		 * clear the stall bit when no STALL handshake was received
+		 * before (autostall can cause this)
+		 */
+		if (setup_data.data[0] == UDC_MSCRES_DWORD0
+				&& setup_data.data[1] == UDC_MSCRES_DWORD1) {
+			DBG(dev, "MSC Reset\n");
+			/*
+			 * clear stall bits
+			 * only one IN and OUT endpoints are handled
+			 */
+			ep_tmp = &udc->ep[UDC_EPIN_IX];
+			udc_set_halt(&ep_tmp->ep, 0);
+			ep_tmp = &udc->ep[UDC_EPOUT_IX];
+			udc_set_halt(&ep_tmp->ep, 0);
+		}
+
+		/* call gadget with setup data received */
+		spin_unlock(&dev->lock);
+		setup_supported = dev->driver->setup(&dev->gadget,
+						&setup_data.request);
+		spin_lock(&dev->lock);
+
+		tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+		/* ep0 in returns data (not zlp) on IN phase */
+		if (setup_supported >= 0 && setup_supported <
+				UDC_EP0IN_MAXPACKET) {
+			/* clear NAK by writing CNAK in EP0_IN */
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+			dev->ep[UDC_EP0IN_IX].naking = 0;
+			UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX);
+
+		/* if unsupported request then stall */
+		} else if (setup_supported < 0) {
+			tmp |= AMD_BIT(UDC_EPCTL_S);
+			writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl);
+		} else
+			dev->waiting_zlp_ack_ep0in = 1;
+
+
+		/* clear NAK by writing CNAK in EP0_OUT */
+		if (!set) {
+			tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl);
+			tmp |= AMD_BIT(UDC_EPCTL_CNAK);
+			writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl);
+			dev->ep[UDC_EP0OUT_IX].naking = 0;
+			UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);
+		}
+
+		if (!use_dma) {
+			/* clear OUT bits in ep status */
+			writel(UDC_EPSTS_OUT_CLEAR,
+				&dev->ep[UDC_EP0OUT_IX].regs->sts);
+		}
+
+	/* data packet 0 bytes */
+	} else if (tmp == UDC_EPSTS_OUT_DATA) {
+		/* clear OUT bits in ep status */
+		writel(UDC_EPSTS_OUT_CLEAR, &dev->ep[UDC_EP0OUT_IX].regs->sts);
+
+		/* get setup data: only 0 packet */
+		if (use_dma) {
+			/* no req if 0 packet, just reactivate */
+			if (list_empty(&dev->ep[UDC_EP0OUT_IX].queue)) {
+				VDBG(dev, "ZLP\n");
+
+				/* set HOST READY */
+				dev->ep[UDC_EP0OUT_IX].td->status =
+					AMD_ADDBITS(
+					dev->ep[UDC_EP0OUT_IX].td->status,
+					UDC_DMA_OUT_STS_BS_HOST_READY,
+					UDC_DMA_OUT_STS_BS);
+				/* enable RDE */
+				udc_ep0_set_rde(dev);
+				ret_val = IRQ_HANDLED;
+
+			} else {
+				/* control write */
+				ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+				/* re-program desc. pointer for possible ZLPs */
+				writel(dev->ep[UDC_EP0OUT_IX].td_phys,
+					&dev->ep[UDC_EP0OUT_IX].regs->desptr);
+				/* enable RDE */
+				udc_ep0_set_rde(dev);
+			}
+		} else {
+
+			/* received number bytes */
+			count = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts);
+			count = AMD_GETBITS(count, UDC_EPSTS_RX_PKT_SIZE);
+			/* out data for fifo mode not working */
+			count = 0;
+
+			/* 0 packet or real data ? */
+			if (count != 0) {
+				ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX);
+			} else {
+				/* dummy read confirm */
+				readl(&dev->ep[UDC_EP0OUT_IX].regs->confirm);
+				ret_val = IRQ_HANDLED;
+			}
+		}
+	}
+
+	/* check pending CNAKS */
+	if (cnak_pending) {
+		/* CNAk processing when rxfifo empty only */
+		if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+			udc_process_cnak_queue(dev);
+		}
+	}
+
+finished:
+	return ret_val;
+}
+
+/* Interrupt handler for Control IN traffic */
+static irqreturn_t udc_control_in_isr(struct udc *dev)
+{
+	irqreturn_t ret_val = IRQ_NONE;
+	u32 tmp;
+	struct udc_ep *ep;
+	struct udc_request *req;
+	unsigned len;
+
+	ep = &dev->ep[UDC_EP0IN_IX];
+
+	/* clear irq */
+	writel(AMD_BIT(UDC_EPINT_IN_EP0), &dev->regs->ep_irqsts);
+
+	tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->sts);
+	/* DMA completion */
+	if (tmp & AMD_BIT(UDC_EPSTS_TDC)) {
+		VDBG(dev, "isr: TDC clear \n");
+		ret_val = IRQ_HANDLED;
+
+		/* clear TDC bit */
+		writel(AMD_BIT(UDC_EPSTS_TDC),
+				&dev->ep[UDC_EP0IN_IX].regs->sts);
+
+	/* status reg has IN bit set ? */
+	} else if (tmp & AMD_BIT(UDC_EPSTS_IN)) {
+		ret_val = IRQ_HANDLED;
+
+		if (ep->dma) {
+			/* clear IN bit */
+			writel(AMD_BIT(UDC_EPSTS_IN),
+				&dev->ep[UDC_EP0IN_IX].regs->sts);
+		}
+		if (dev->stall_ep0in) {
+			DBG(dev, "stall ep0in\n");
+			/* halt ep0in */
+			tmp = readl(&ep->regs->ctl);
+			tmp |= AMD_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);
+		} else {
+			if (!list_empty(&ep->queue)) {
+				/* next request */
+				req = list_entry(ep->queue.next,
+						struct udc_request, queue);
+
+				if (ep->dma) {
+					/* write desc pointer */
+					writel(req->td_phys, &ep->regs->desptr);
+					/* set HOST READY */
+					req->td_data->status =
+						AMD_ADDBITS(
+						req->td_data->status,
+						UDC_DMA_STP_STS_BS_HOST_READY,
+						UDC_DMA_STP_STS_BS);
+
+					/* set poll demand bit */
+					tmp =
+					readl(&dev->ep[UDC_EP0IN_IX].regs->ctl);
+					tmp |= AMD_BIT(UDC_EPCTL_P);
+					writel(tmp,
+					&dev->ep[UDC_EP0IN_IX].regs->ctl);
+
+					/* all bytes will be transferred */
+					req->req.actual = req->req.length;
+
+					/* complete req */
+					complete_req(ep, req, 0);
+
+				} else {
+					/* write fifo */
+					udc_txfifo_write(ep, &req->req);
+
+					/* lengh bytes transfered */
+					len = req->req.length - req->req.actual;
+					if (len > ep->ep.maxpacket)
+						len = ep->ep.maxpacket;
+
+					req->req.actual += len;
+					if (req->req.actual == req->req.length
+						|| (len != ep->ep.maxpacket)) {
+						/* complete req */
+						complete_req(ep, req, 0);
+					}
+				}
+
+			}
+		}
+		ep->halted = 0;
+		dev->stall_ep0in = 0;
+		if (!ep->dma) {
+			/* clear IN bit */
+			writel(AMD_BIT(UDC_EPSTS_IN),
+				&dev->ep[UDC_EP0IN_IX].regs->sts);
+		}
+	}
+
+	return ret_val;
+}
+
+
+/* Interrupt handler for global device events */
+static irqreturn_t udc_dev_isr(struct udc *dev, u32 dev_irq)
+__releases(dev->lock)
+__acquires(dev->lock)
+{
+	irqreturn_t ret_val = IRQ_NONE;
+	u32 tmp;
+	u32 cfg;
+	struct udc_ep *ep;
+	u16 i;
+	u8 udc_csr_epix;
+
+	/* SET_CONFIG irq ? */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_SC)) {
+		ret_val = IRQ_HANDLED;
+
+		/* read config value */
+		tmp = readl(&dev->regs->sts);
+		cfg = AMD_GETBITS(tmp, UDC_DEVSTS_CFG);
+		DBG(dev, "SET_CONFIG interrupt: config=%d\n", cfg);
+		dev->cur_config = cfg;
+		dev->set_cfg_not_acked = 1;
+
+		/* make usb request for gadget driver */
+		memset(&setup_data, 0 , sizeof(union udc_setup_data));
+		setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION;
+		setup_data.request.wValue = dev->cur_config;
+
+		/* programm the NE registers */
+		for (i = 0; i < UDC_EP_NUM; i++) {
+			ep = &dev->ep[i];
+			if (ep->in) {
+
+				/* ep ix in UDC CSR register space */
+				udc_csr_epix = ep->num;
+
+
+			/* OUT ep */
+			} else {
+				/* ep ix in UDC CSR register space */
+				udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+			}
+
+			tmp = readl(&dev->csr->ne[udc_csr_epix]);
+			/* ep cfg */
+			tmp = AMD_ADDBITS(tmp, ep->dev->cur_config,
+						UDC_CSR_NE_CFG);
+			/* write reg */
+			writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+			/* clear stall bits */
+			ep->halted = 0;
+			tmp = readl(&ep->regs->ctl);
+			tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);
+		}
+		/* call gadget zero with setup data received */
+		spin_unlock(&dev->lock);
+		tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+		spin_lock(&dev->lock);
+
+	} /* SET_INTERFACE ? */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_SI)) {
+		ret_val = IRQ_HANDLED;
+
+		dev->set_cfg_not_acked = 1;
+		/* read interface and alt setting values */
+		tmp = readl(&dev->regs->sts);
+		dev->cur_alt = AMD_GETBITS(tmp, UDC_DEVSTS_ALT);
+		dev->cur_intf = AMD_GETBITS(tmp, UDC_DEVSTS_INTF);
+
+		/* make usb request for gadget driver */
+		memset(&setup_data, 0 , sizeof(union udc_setup_data));
+		setup_data.request.bRequest = USB_REQ_SET_INTERFACE;
+		setup_data.request.bRequestType = USB_RECIP_INTERFACE;
+		setup_data.request.wValue = dev->cur_alt;
+		setup_data.request.wIndex = dev->cur_intf;
+
+		DBG(dev, "SET_INTERFACE interrupt: alt=%d intf=%d\n",
+				dev->cur_alt, dev->cur_intf);
+
+		/* programm the NE registers */
+		for (i = 0; i < UDC_EP_NUM; i++) {
+			ep = &dev->ep[i];
+			if (ep->in) {
+
+				/* ep ix in UDC CSR register space */
+				udc_csr_epix = ep->num;
+
+
+			/* OUT ep */
+			} else {
+				/* ep ix in UDC CSR register space */
+				udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS;
+			}
+
+			/* UDC CSR reg */
+			/* set ep values */
+			tmp = readl(&dev->csr->ne[udc_csr_epix]);
+			/* ep interface */
+			tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf,
+						UDC_CSR_NE_INTF);
+			/* tmp = AMD_ADDBITS(tmp, 2, UDC_CSR_NE_INTF); */
+			/* ep alt */
+			tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt,
+						UDC_CSR_NE_ALT);
+			/* write reg */
+			writel(tmp, &dev->csr->ne[udc_csr_epix]);
+
+			/* clear stall bits */
+			ep->halted = 0;
+			tmp = readl(&ep->regs->ctl);
+			tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S);
+			writel(tmp, &ep->regs->ctl);
+		}
+
+		/* call gadget zero with setup data received */
+		spin_unlock(&dev->lock);
+		tmp = dev->driver->setup(&dev->gadget, &setup_data.request);
+		spin_lock(&dev->lock);
+
+	} /* USB reset */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_UR)) {
+		DBG(dev, "USB Reset interrupt\n");
+		ret_val = IRQ_HANDLED;
+
+		/* allow soft reset when suspend occurs */
+		soft_reset_occured = 0;
+
+		dev->waiting_zlp_ack_ep0in = 0;
+		dev->set_cfg_not_acked = 0;
+
+		/* mask not needed interrupts */
+		udc_mask_unused_interrupts(dev);
+
+		/* call gadget to resume and reset configs etc. */
+		spin_unlock(&dev->lock);
+		if (dev->sys_suspended && dev->driver->resume) {
+			dev->driver->resume(&dev->gadget);
+			dev->sys_suspended = 0;
+		}
+		dev->driver->disconnect(&dev->gadget);
+		spin_lock(&dev->lock);
+
+		/* disable ep0 to empty req queue */
+		empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+		ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+		/* soft reset when rxfifo not empty */
+		tmp = readl(&dev->regs->sts);
+		if (!(tmp & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
+				&& !soft_reset_after_usbreset_occured) {
+			udc_soft_reset(dev);
+			soft_reset_after_usbreset_occured++;
+		}
+
+		/*
+		 * DMA reset to kill potential old DMA hw hang,
+		 * POLL bit is already reset by ep_init() through
+		 * disconnect()
+		 */
+		DBG(dev, "DMA machine reset\n");
+		tmp = readl(&dev->regs->cfg);
+		writel(tmp | AMD_BIT(UDC_DEVCFG_DMARST), &dev->regs->cfg);
+		writel(tmp, &dev->regs->cfg);
+
+		/* put into initial config */
+		udc_basic_init(dev);
+
+		/* enable device setup interrupts */
+		udc_enable_dev_setup_interrupts(dev);
+
+		/* enable suspend interrupt */
+		tmp = readl(&dev->regs->irqmsk);
+		tmp &= AMD_UNMASK_BIT(UDC_DEVINT_US);
+		writel(tmp, &dev->regs->irqmsk);
+
+	} /* USB suspend */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_US)) {
+		DBG(dev, "USB Suspend interrupt\n");
+		ret_val = IRQ_HANDLED;
+		if (dev->driver->suspend) {
+			spin_unlock(&dev->lock);
+			dev->sys_suspended = 1;
+			dev->driver->suspend(&dev->gadget);
+			spin_lock(&dev->lock);
+		}
+	} /* new speed ? */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_ENUM)) {
+		DBG(dev, "ENUM interrupt\n");
+		ret_val = IRQ_HANDLED;
+		soft_reset_after_usbreset_occured = 0;
+
+		/* disable ep0 to empty req queue */
+		empty_req_queue(&dev->ep[UDC_EP0IN_IX]);
+		ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]);
+
+		/* link up all endpoints */
+		udc_setup_endpoints(dev);
+		if (dev->gadget.speed == USB_SPEED_HIGH) {
+			dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
+				"high");
+		} else if (dev->gadget.speed == USB_SPEED_FULL) {
+			dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
+				"full");
+		}
+
+		/* init ep 0 */
+		activate_control_endpoints(dev);
+
+		/* enable ep0 interrupts */
+		udc_enable_ep0_interrupts(dev);
+	}
+	/* session valid change interrupt */
+	if (dev_irq & AMD_BIT(UDC_DEVINT_SVC)) {
+		DBG(dev, "USB SVC interrupt\n");
+		ret_val = IRQ_HANDLED;
+
+		/* check that session is not valid to detect disconnect */
+		tmp = readl(&dev->regs->sts);
+		if (!(tmp & AMD_BIT(UDC_DEVSTS_SESSVLD))) {
+			/* disable suspend interrupt */
+			tmp = readl(&dev->regs->irqmsk);
+			tmp |= AMD_BIT(UDC_DEVINT_US);
+			writel(tmp, &dev->regs->irqmsk);
+			DBG(dev, "USB Disconnect (session valid low)\n");
+			/* cleanup on disconnect */
+			usb_disconnect(udc);
+		}
+
+	}
+
+	return ret_val;
+}
+
+/* Interrupt Service Routine, see Linux Kernel Doc for parameters */
+static irqreturn_t udc_irq(int irq, void *pdev)
+{
+	struct udc *dev = pdev;
+	u32 reg;
+	u16 i;
+	u32 ep_irq;
+	irqreturn_t ret_val = IRQ_NONE;
+
+	spin_lock(&dev->lock);
+
+	/* check for ep irq */
+	reg = readl(&dev->regs->ep_irqsts);
+	if (reg) {
+		if (reg & AMD_BIT(UDC_EPINT_OUT_EP0))
+			ret_val |= udc_control_out_isr(dev);
+		if (reg & AMD_BIT(UDC_EPINT_IN_EP0))
+			ret_val |= udc_control_in_isr(dev);
+
+		/*
+		 * data endpoint
+		 * iterate ep's
+		 */
+		for (i = 1; i < UDC_EP_NUM; i++) {
+			ep_irq = 1 << i;
+			if (!(reg & ep_irq) || i == UDC_EPINT_OUT_EP0)
+				continue;
+
+			/* clear irq status */
+			writel(ep_irq, &dev->regs->ep_irqsts);
+
+			/* irq for out ep ? */
+			if (i > UDC_EPIN_NUM)
+				ret_val |= udc_data_out_isr(dev, i);
+			else
+				ret_val |= udc_data_in_isr(dev, i);
+		}
+
+	}
+
+
+	/* check for dev irq */
+	reg = readl(&dev->regs->irqsts);
+	if (reg) {
+		/* clear irq */
+		writel(reg, &dev->regs->irqsts);
+		ret_val |= udc_dev_isr(dev, reg);
+	}
+
+
+	spin_unlock(&dev->lock);
+	return ret_val;
+}
+
+/* Tears down device */
+static void gadget_release(struct device *pdev)
+{
+	struct amd5536udc *dev = dev_get_drvdata(pdev);
+	kfree(dev);
+}
+
+/* Cleanup on device remove */
+static void udc_remove(struct udc *dev)
+{
+	/* remove timer */
+	stop_timer++;
+	if (timer_pending(&udc_timer))
+		wait_for_completion(&on_exit);
+	if (udc_timer.data)
+		del_timer_sync(&udc_timer);
+	/* remove pollstall timer */
+	stop_pollstall_timer++;
+	if (timer_pending(&udc_pollstall_timer))
+		wait_for_completion(&on_pollstall_exit);
+	if (udc_pollstall_timer.data)
+		del_timer_sync(&udc_pollstall_timer);
+	udc = NULL;
+}
+
+/* Reset all pci context */
+static void udc_pci_remove(struct pci_dev *pdev)
+{
+	struct udc		*dev;
+
+	dev = pci_get_drvdata(pdev);
+
+	/* gadget driver must not be registered */
+	BUG_ON(dev->driver != NULL);
+
+	/* dma pool cleanup */
+	if (dev->data_requests)
+		pci_pool_destroy(dev->data_requests);
+
+	if (dev->stp_requests) {
+		/* cleanup DMA desc's for ep0in */
+		pci_pool_free(dev->stp_requests,
+			dev->ep[UDC_EP0OUT_IX].td_stp,
+			dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+		pci_pool_free(dev->stp_requests,
+			dev->ep[UDC_EP0OUT_IX].td,
+			dev->ep[UDC_EP0OUT_IX].td_phys);
+
+		pci_pool_destroy(dev->stp_requests);
+	}
+
+	/* reset controller */
+	writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
+	if (dev->irq_registered)
+		free_irq(pdev->irq, dev);
+	if (dev->regs)
+		iounmap(dev->regs);
+	if (dev->mem_region)
+		release_mem_region(pci_resource_start(pdev, 0),
+				pci_resource_len(pdev, 0));
+	if (dev->active)
+		pci_disable_device(pdev);
+
+	device_unregister(&dev->gadget.dev);
+	pci_set_drvdata(pdev, NULL);
+
+	udc_remove(dev);
+}
+
+/* create dma pools on init */
+static int init_dma_pools(struct udc *dev)
+{
+	struct udc_stp_dma	*td_stp;
+	struct udc_data_dma	*td_data;
+	int retval;
+
+	/* consistent DMA mode setting ? */
+	if (use_dma_ppb) {
+		use_dma_bufferfill_mode = 0;
+	} else {
+		use_dma_ppb_du = 0;
+		use_dma_bufferfill_mode = 1;
+	}
+
+	/* DMA setup */
+	dev->data_requests = dma_pool_create("data_requests", NULL,
+		sizeof(struct udc_data_dma), 0, 0);
+	if (!dev->data_requests) {
+		DBG(dev, "can't get request data pool\n");
+		retval = -ENOMEM;
+		goto finished;
+	}
+
+	/* EP0 in dma regs = dev control regs */
+	dev->ep[UDC_EP0IN_IX].dma = &dev->regs->ctl;
+
+	/* dma desc for setup data */
+	dev->stp_requests = dma_pool_create("setup requests", NULL,
+		sizeof(struct udc_stp_dma), 0, 0);
+	if (!dev->stp_requests) {
+		DBG(dev, "can't get stp request pool\n");
+		retval = -ENOMEM;
+		goto finished;
+	}
+	/* setup */
+	td_stp = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+				&dev->ep[UDC_EP0OUT_IX].td_stp_dma);
+	if (td_stp == NULL) {
+		retval = -ENOMEM;
+		goto finished;
+	}
+	dev->ep[UDC_EP0OUT_IX].td_stp = td_stp;
+
+	/* data: 0 packets !? */
+	td_data = dma_pool_alloc(dev->stp_requests, GFP_KERNEL,
+				&dev->ep[UDC_EP0OUT_IX].td_phys);
+	if (td_data == NULL) {
+		retval = -ENOMEM;
+		goto finished;
+	}
+	dev->ep[UDC_EP0OUT_IX].td = td_data;
+	return 0;
+
+finished:
+	return retval;
+}
+
+/* Called by pci bus driver to init pci context */
+static int udc_pci_probe(
+	struct pci_dev *pdev,
+	const struct pci_device_id *id
+)
+{
+	struct udc		*dev;
+	unsigned long		resource;
+	unsigned long		len;
+	int			retval = 0;
+
+	/* one udc only */
+	if (udc) {
+		dev_dbg(&pdev->dev, "already probed\n");
+		return -EBUSY;
+	}
+
+	/* init */
+	dev = kzalloc(sizeof(struct udc), GFP_KERNEL);
+	if (!dev) {
+		retval = -ENOMEM;
+		goto finished;
+	}
+
+	/* pci setup */
+	if (pci_enable_device(pdev) < 0) {
+		retval = -ENODEV;
+		goto finished;
+	}
+	dev->active = 1;
+
+	/* PCI resource allocation */
+	resource = pci_resource_start(pdev, 0);
+	len = pci_resource_len(pdev, 0);
+
+	if (!request_mem_region(resource, len, name)) {
+		dev_dbg(&pdev->dev, "pci device used already\n");
+		retval = -EBUSY;
+		goto finished;
+	}
+	dev->mem_region = 1;
+
+	dev->virt_addr = ioremap_nocache(resource, len);
+	if (dev->virt_addr == NULL) {
+		dev_dbg(&pdev->dev, "start address cannot be mapped\n");
+		retval = -EFAULT;
+		goto finished;
+	}
+
+	if (!pdev->irq) {
+		dev_err(&dev->pdev->dev, "irq not set\n");
+		retval = -ENODEV;
+		goto finished;
+	}
+
+	if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
+		dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq);
+		retval = -EBUSY;
+		goto finished;
+	}
+	dev->irq_registered = 1;
+
+	pci_set_drvdata(pdev, dev);
+
+	/* chip revision for Hs AMD5536 */
+	dev->chiprev = pdev->revision;
+
+	pci_set_master(pdev);
+	pci_set_mwi(pdev);
+
+	/* init dma pools */
+	if (use_dma) {
+		retval = init_dma_pools(dev);
+		if (retval != 0)
+			goto finished;
+	}
+
+	dev->phys_addr = resource;
+	dev->irq = pdev->irq;
+	dev->pdev = pdev;
+	dev->gadget.dev.parent = &pdev->dev;
+	dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+	/* general probing */
+	if (udc_probe(dev) == 0)
+		return 0;
+
+finished:
+	if (dev)
+		udc_pci_remove(pdev);
+	return retval;
+}
+
+/* general probe */
+static int udc_probe(struct udc *dev)
+{
+	char		tmp[128];
+	u32		reg;
+	int		retval;
+
+	/* mark timer as not initialized */
+	udc_timer.data = 0;
+	udc_pollstall_timer.data = 0;
+
+	/* device struct setup */
+	spin_lock_init(&dev->lock);
+	dev->gadget.ops = &udc_ops;
+
+	strcpy(dev->gadget.dev.bus_id, "gadget");
+	dev->gadget.dev.release = gadget_release;
+	dev->gadget.name = name;
+	dev->gadget.name = name;
+	dev->gadget.is_dualspeed = 1;
+
+	/* udc csr registers base */
+	dev->csr = dev->virt_addr + UDC_CSR_ADDR;
+	/* dev registers base */
+	dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
+	/* ep registers base */
+	dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
+	/* fifo's base */
+	dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
+	dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
+
+	/* init registers, interrupts, ... */
+	startup_registers(dev);
+
+	dev_info(&dev->pdev->dev, "%s\n", mod_desc);
+
+	snprintf(tmp, sizeof tmp, "%d", dev->irq);
+	dev_info(&dev->pdev->dev,
+		"irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n",
+		tmp, dev->phys_addr, dev->chiprev,
+		(dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1");
+	strcpy(tmp, UDC_DRIVER_VERSION_STRING);
+	if (dev->chiprev == UDC_HSA0_REV) {
+		dev_err(&dev->pdev->dev, "chip revision is A0; too old\n");
+		retval = -ENODEV;
+		goto finished;
+	}
+	dev_info(&dev->pdev->dev,
+		"driver version: %s(for Geode5536 B1)\n", tmp);
+	udc = dev;
+
+	retval = device_register(&dev->gadget.dev);
+	if (retval)
+		goto finished;
+
+	/* timer init */
+	init_timer(&udc_timer);
+	udc_timer.function = udc_timer_function;
+	udc_timer.data = 1;
+	/* timer pollstall init */
+	init_timer(&udc_pollstall_timer);
+	udc_pollstall_timer.function = udc_pollstall_timer_function;
+	udc_pollstall_timer.data = 1;
+
+	/* set SD */
+	reg = readl(&dev->regs->ctl);
+	reg |= AMD_BIT(UDC_DEVCTL_SD);
+	writel(reg, &dev->regs->ctl);
+
+	/* print dev register info */
+	print_regs(dev);
+
+	return 0;
+
+finished:
+	return retval;
+}
+
+/* Initiates a remote wakeup */
+static int udc_remote_wakeup(struct udc *dev)
+{
+	unsigned long flags;
+	u32 tmp;
+
+	DBG(dev, "UDC initiates remote wakeup\n");
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	tmp = readl(&dev->regs->ctl);
+	tmp |= AMD_BIT(UDC_DEVCTL_RES);
+	writel(tmp, &dev->regs->ctl);
+	tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES);
+	writel(tmp, &dev->regs->ctl);
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+	return 0;
+}
+
+/* PCI device parameters */
+static const struct pci_device_id pci_id[] = {
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),
+		.class =	(PCI_CLASS_SERIAL_USB << 8) | 0xfe,
+		.class_mask =	0xffffffff,
+	},
+	{},
+};
+MODULE_DEVICE_TABLE(pci, pci_id);
+
+/* PCI functions */
+static struct pci_driver udc_pci_driver = {
+	.name =		(char *) name,
+	.id_table =	pci_id,
+	.probe =	udc_pci_probe,
+	.remove =	udc_pci_remove,
+};
+
+/* Inits driver */
+static int __init init(void)
+{
+	return pci_register_driver(&udc_pci_driver);
+}
+module_init(init);
+
+/* Cleans driver */
+static void __exit cleanup(void)
+{
+	pci_unregister_driver(&udc_pci_driver);
+}
+module_exit(cleanup);
+
+MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
+MODULE_AUTHOR("Thomas Dahlmann");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h
new file mode 100644
index 0000000..4bbabbb
--- /dev/null
+++ b/drivers/usb/gadget/amd5536udc.h
@@ -0,0 +1,626 @@
+/*
+ * amd5536.h -- header for AMD 5536 UDC high/full speed USB device controller
+ *
+ * Copyright (C) 2007 AMD (http://www.amd.com)
+ * Author: Thomas Dahlmann
+ *
+ * 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
+ */
+
+#ifndef AMD5536UDC_H
+#define AMD5536UDC_H
+
+/* various constants */
+#define UDC_RDE_TIMER_SECONDS		1
+#define UDC_RDE_TIMER_DIV		10
+#define UDC_POLLSTALL_TIMER_USECONDS	500
+
+/* Hs AMD5536 chip rev. */
+#define UDC_HSA0_REV 1
+#define UDC_HSB1_REV 2
+
+/*
+ * SETUP usb commands
+ * needed, because some SETUP's are handled in hw, but must be passed to
+ * gadget driver above
+ * SET_CONFIG
+ */
+#define UDC_SETCONFIG_DWORD0			0x00000900
+#define UDC_SETCONFIG_DWORD0_VALUE_MASK		0xffff0000
+#define UDC_SETCONFIG_DWORD0_VALUE_OFS		16
+
+#define UDC_SETCONFIG_DWORD1			0x00000000
+
+/* SET_INTERFACE */
+#define UDC_SETINTF_DWORD0			0x00000b00
+#define UDC_SETINTF_DWORD0_ALT_MASK		0xffff0000
+#define UDC_SETINTF_DWORD0_ALT_OFS		16
+
+#define UDC_SETINTF_DWORD1			0x00000000
+#define UDC_SETINTF_DWORD1_INTF_MASK		0x0000ffff
+#define UDC_SETINTF_DWORD1_INTF_OFS		0
+
+/* Mass storage reset */
+#define UDC_MSCRES_DWORD0			0x0000ff21
+#define UDC_MSCRES_DWORD1			0x00000000
+
+/* Global CSR's -------------------------------------------------------------*/
+#define UDC_CSR_ADDR				0x500
+
+/* EP NE bits */
+/* EP number */
+#define UDC_CSR_NE_NUM_MASK			0x0000000f
+#define UDC_CSR_NE_NUM_OFS			0
+/* EP direction */
+#define UDC_CSR_NE_DIR_MASK			0x00000010
+#define UDC_CSR_NE_DIR_OFS			4
+/* EP type */
+#define UDC_CSR_NE_TYPE_MASK			0x00000060
+#define UDC_CSR_NE_TYPE_OFS			5
+/* EP config number */
+#define UDC_CSR_NE_CFG_MASK			0x00000780
+#define UDC_CSR_NE_CFG_OFS			7
+/* EP interface number */
+#define UDC_CSR_NE_INTF_MASK			0x00007800
+#define UDC_CSR_NE_INTF_OFS			11
+/* EP alt setting */
+#define UDC_CSR_NE_ALT_MASK			0x00078000
+#define UDC_CSR_NE_ALT_OFS			15
+
+/* max pkt */
+#define UDC_CSR_NE_MAX_PKT_MASK			0x3ff80000
+#define UDC_CSR_NE_MAX_PKT_OFS			19
+
+/* Device Config Register ---------------------------------------------------*/
+#define UDC_DEVCFG_ADDR				0x400
+
+#define UDC_DEVCFG_SOFTRESET			31
+#define UDC_DEVCFG_HNPSFEN			30
+#define UDC_DEVCFG_DMARST			29
+#define UDC_DEVCFG_SET_DESC			18
+#define UDC_DEVCFG_CSR_PRG			17
+#define UDC_DEVCFG_STATUS			7
+#define UDC_DEVCFG_DIR				6
+#define UDC_DEVCFG_PI				5
+#define UDC_DEVCFG_SS				4
+#define UDC_DEVCFG_SP				3
+#define UDC_DEVCFG_RWKP				2
+
+#define UDC_DEVCFG_SPD_MASK			0x3
+#define UDC_DEVCFG_SPD_OFS			0
+#define UDC_DEVCFG_SPD_HS			0x0
+#define UDC_DEVCFG_SPD_FS			0x1
+#define UDC_DEVCFG_SPD_LS			0x2
+/*#define UDC_DEVCFG_SPD_FS			0x3*/
+
+
+/* Device Control Register --------------------------------------------------*/
+#define UDC_DEVCTL_ADDR				0x404
+
+#define UDC_DEVCTL_THLEN_MASK			0xff000000
+#define UDC_DEVCTL_THLEN_OFS			24
+
+#define UDC_DEVCTL_BRLEN_MASK			0x00ff0000
+#define UDC_DEVCTL_BRLEN_OFS			16
+
+#define UDC_DEVCTL_CSR_DONE			13
+#define UDC_DEVCTL_DEVNAK			12
+#define UDC_DEVCTL_SD				10
+#define UDC_DEVCTL_MODE				9
+#define UDC_DEVCTL_BREN				8
+#define UDC_DEVCTL_THE				7
+#define UDC_DEVCTL_BF				6
+#define UDC_DEVCTL_BE				5
+#define UDC_DEVCTL_DU				4
+#define UDC_DEVCTL_TDE				3
+#define UDC_DEVCTL_RDE				2
+#define UDC_DEVCTL_RES				0
+
+
+/* Device Status Register ---------------------------------------------------*/
+#define UDC_DEVSTS_ADDR				0x408
+
+#define UDC_DEVSTS_TS_MASK			0xfffc0000
+#define UDC_DEVSTS_TS_OFS			18
+
+#define UDC_DEVSTS_SESSVLD			17
+#define UDC_DEVSTS_PHY_ERROR			16
+#define UDC_DEVSTS_RXFIFO_EMPTY			15
+
+#define UDC_DEVSTS_ENUM_SPEED_MASK		0x00006000
+#define UDC_DEVSTS_ENUM_SPEED_OFS		13
+#define UDC_DEVSTS_ENUM_SPEED_FULL		1
+#define UDC_DEVSTS_ENUM_SPEED_HIGH		0
+
+#define UDC_DEVSTS_SUSP				12
+
+#define UDC_DEVSTS_ALT_MASK			0x00000f00
+#define UDC_DEVSTS_ALT_OFS			8
+
+#define UDC_DEVSTS_INTF_MASK			0x000000f0
+#define UDC_DEVSTS_INTF_OFS			4
+
+#define UDC_DEVSTS_CFG_MASK			0x0000000f
+#define UDC_DEVSTS_CFG_OFS			0
+
+
+/* Device Interrupt Register ------------------------------------------------*/
+#define UDC_DEVINT_ADDR				0x40c
+
+#define UDC_DEVINT_SVC				7
+#define UDC_DEVINT_ENUM				6
+#define UDC_DEVINT_SOF				5
+#define UDC_DEVINT_US				4
+#define UDC_DEVINT_UR				3
+#define UDC_DEVINT_ES				2
+#define UDC_DEVINT_SI				1
+#define UDC_DEVINT_SC				0
+
+/* Device Interrupt Mask Register -------------------------------------------*/
+#define UDC_DEVINT_MSK_ADDR			0x410
+
+#define UDC_DEVINT_MSK				0x7f
+
+/* Endpoint Interrupt Register ----------------------------------------------*/
+#define UDC_EPINT_ADDR				0x414
+
+#define UDC_EPINT_OUT_MASK			0xffff0000
+#define UDC_EPINT_OUT_OFS			16
+#define UDC_EPINT_IN_MASK			0x0000ffff
+#define UDC_EPINT_IN_OFS			0
+
+#define UDC_EPINT_IN_EP0			0
+#define UDC_EPINT_IN_EP1			1
+#define UDC_EPINT_IN_EP2			2
+#define UDC_EPINT_IN_EP3			3
+#define UDC_EPINT_OUT_EP0			16
+#define UDC_EPINT_OUT_EP1			17
+#define UDC_EPINT_OUT_EP2			18
+#define UDC_EPINT_OUT_EP3			19
+
+#define UDC_EPINT_EP0_ENABLE_MSK		0x001e001e
+
+/* Endpoint Interrupt Mask Register -----------------------------------------*/
+#define UDC_EPINT_MSK_ADDR			0x418
+
+#define UDC_EPINT_OUT_MSK_MASK			0xffff0000
+#define UDC_EPINT_OUT_MSK_OFS			16
+#define UDC_EPINT_IN_MSK_MASK			0x0000ffff
+#define UDC_EPINT_IN_MSK_OFS			0
+
+#define UDC_EPINT_MSK_DISABLE_ALL		0xffffffff
+/* mask non-EP0 endpoints */
+#define UDC_EPDATAINT_MSK_DISABLE		0xfffefffe
+/* mask all dev interrupts */
+#define UDC_DEV_MSK_DISABLE			0x7f
+
+/* Endpoint-specific CSR's --------------------------------------------------*/
+#define UDC_EPREGS_ADDR				0x0
+#define UDC_EPIN_REGS_ADDR			0x0
+#define UDC_EPOUT_REGS_ADDR			0x200
+
+#define UDC_EPCTL_ADDR				0x0
+
+#define UDC_EPCTL_RRDY				9
+#define UDC_EPCTL_CNAK				8
+#define UDC_EPCTL_SNAK				7
+#define UDC_EPCTL_NAK				6
+
+#define UDC_EPCTL_ET_MASK			0x00000030
+#define UDC_EPCTL_ET_OFS			4
+#define UDC_EPCTL_ET_CONTROL			0
+#define UDC_EPCTL_ET_ISO			1
+#define UDC_EPCTL_ET_BULK			2
+#define UDC_EPCTL_ET_INTERRUPT			3
+
+#define UDC_EPCTL_P				3
+#define UDC_EPCTL_SN				2
+#define UDC_EPCTL_F				1
+#define UDC_EPCTL_S				0
+
+/* Endpoint Status Registers ------------------------------------------------*/
+#define UDC_EPSTS_ADDR				0x4
+
+#define UDC_EPSTS_RX_PKT_SIZE_MASK		0x007ff800
+#define UDC_EPSTS_RX_PKT_SIZE_OFS		11
+
+#define UDC_EPSTS_TDC				10
+#define UDC_EPSTS_HE				9
+#define UDC_EPSTS_BNA				7
+#define UDC_EPSTS_IN				6
+
+#define UDC_EPSTS_OUT_MASK			0x00000030
+#define UDC_EPSTS_OUT_OFS			4
+#define UDC_EPSTS_OUT_DATA			1
+#define UDC_EPSTS_OUT_DATA_CLEAR		0x10
+#define UDC_EPSTS_OUT_SETUP			2
+#define UDC_EPSTS_OUT_SETUP_CLEAR		0x20
+#define UDC_EPSTS_OUT_CLEAR			0x30
+
+/* Endpoint Buffer Size IN/ Receive Packet Frame Number OUT Registers ------*/
+#define UDC_EPIN_BUFF_SIZE_ADDR			0x8
+#define UDC_EPOUT_FRAME_NUMBER_ADDR		0x8
+
+#define UDC_EPIN_BUFF_SIZE_MASK			0x0000ffff
+#define UDC_EPIN_BUFF_SIZE_OFS			0
+/* EP0in txfifo = 128 bytes*/
+#define UDC_EPIN0_BUFF_SIZE			32
+/* EP0in fullspeed txfifo = 128 bytes*/
+#define UDC_FS_EPIN0_BUFF_SIZE			32
+
+/* fifo size mult = fifo size / max packet */
+#define UDC_EPIN_BUFF_SIZE_MULT			2
+
+/* EPin data fifo size = 1024 bytes DOUBLE BUFFERING */
+#define UDC_EPIN_BUFF_SIZE			256
+/* EPin small INT data fifo size = 128 bytes */
+#define UDC_EPIN_SMALLINT_BUFF_SIZE		32
+
+/* EPin fullspeed data fifo size = 128 bytes DOUBLE BUFFERING */
+#define UDC_FS_EPIN_BUFF_SIZE			32
+
+#define UDC_EPOUT_FRAME_NUMBER_MASK		0x0000ffff
+#define UDC_EPOUT_FRAME_NUMBER_OFS		0
+
+/* Endpoint Buffer Size OUT/Max Packet Size Registers -----------------------*/
+#define UDC_EPOUT_BUFF_SIZE_ADDR		0x0c
+#define UDC_EP_MAX_PKT_SIZE_ADDR		0x0c
+
+#define UDC_EPOUT_BUFF_SIZE_MASK		0xffff0000
+#define UDC_EPOUT_BUFF_SIZE_OFS			16
+#define UDC_EP_MAX_PKT_SIZE_MASK		0x0000ffff
+#define UDC_EP_MAX_PKT_SIZE_OFS			0
+/* EP0in max packet size = 64 bytes */
+#define UDC_EP0IN_MAX_PKT_SIZE			64
+/* EP0out max packet size = 64 bytes */
+#define UDC_EP0OUT_MAX_PKT_SIZE			64
+/* EP0in fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0IN_MAX_PKT_SIZE		64
+/* EP0out fullspeed max packet size = 64 bytes */
+#define UDC_FS_EP0OUT_MAX_PKT_SIZE		64
+
+/*
+ * Endpoint dma descriptors ------------------------------------------------
+ *
+ * Setup data, Status dword
+ */
+#define UDC_DMA_STP_STS_CFG_MASK		0x0fff0000
+#define UDC_DMA_STP_STS_CFG_OFS			16
+#define UDC_DMA_STP_STS_CFG_ALT_MASK		0x000f0000
+#define UDC_DMA_STP_STS_CFG_ALT_OFS		16
+#define UDC_DMA_STP_STS_CFG_INTF_MASK		0x00f00000
+#define UDC_DMA_STP_STS_CFG_INTF_OFS		20
+#define UDC_DMA_STP_STS_CFG_NUM_MASK		0x0f000000
+#define UDC_DMA_STP_STS_CFG_NUM_OFS		24
+#define UDC_DMA_STP_STS_RX_MASK			0x30000000
+#define UDC_DMA_STP_STS_RX_OFS			28
+#define UDC_DMA_STP_STS_BS_MASK			0xc0000000
+#define UDC_DMA_STP_STS_BS_OFS			30
+#define UDC_DMA_STP_STS_BS_HOST_READY		0
+#define UDC_DMA_STP_STS_BS_DMA_BUSY		1
+#define UDC_DMA_STP_STS_BS_DMA_DONE		2
+#define UDC_DMA_STP_STS_BS_HOST_BUSY		3
+/* IN data, Status dword */
+#define UDC_DMA_IN_STS_TXBYTES_MASK		0x0000ffff
+#define UDC_DMA_IN_STS_TXBYTES_OFS		0
+#define	UDC_DMA_IN_STS_FRAMENUM_MASK		0x07ff0000
+#define UDC_DMA_IN_STS_FRAMENUM_OFS		0
+#define UDC_DMA_IN_STS_L			27
+#define UDC_DMA_IN_STS_TX_MASK			0x30000000
+#define UDC_DMA_IN_STS_TX_OFS			28
+#define UDC_DMA_IN_STS_BS_MASK			0xc0000000
+#define UDC_DMA_IN_STS_BS_OFS			30
+#define UDC_DMA_IN_STS_BS_HOST_READY		0
+#define UDC_DMA_IN_STS_BS_DMA_BUSY		1
+#define UDC_DMA_IN_STS_BS_DMA_DONE		2
+#define UDC_DMA_IN_STS_BS_HOST_BUSY		3
+/* OUT data, Status dword */
+#define UDC_DMA_OUT_STS_RXBYTES_MASK		0x0000ffff
+#define UDC_DMA_OUT_STS_RXBYTES_OFS		0
+#define UDC_DMA_OUT_STS_FRAMENUM_MASK		0x07ff0000
+#define UDC_DMA_OUT_STS_FRAMENUM_OFS		0
+#define UDC_DMA_OUT_STS_L			27
+#define UDC_DMA_OUT_STS_RX_MASK			0x30000000
+#define UDC_DMA_OUT_STS_RX_OFS			28
+#define UDC_DMA_OUT_STS_BS_MASK			0xc0000000
+#define UDC_DMA_OUT_STS_BS_OFS			30
+#define UDC_DMA_OUT_STS_BS_HOST_READY		0
+#define UDC_DMA_OUT_STS_BS_DMA_BUSY		1
+#define UDC_DMA_OUT_STS_BS_DMA_DONE		2
+#define UDC_DMA_OUT_STS_BS_HOST_BUSY		3
+/* max ep0in packet */
+#define UDC_EP0IN_MAXPACKET			1000
+/* max dma packet */
+#define UDC_DMA_MAXPACKET			65536
+
+/* un-usable DMA address */
+#define DMA_DONT_USE				(~(dma_addr_t) 0 )
+
+/* other Endpoint register addresses and values-----------------------------*/
+#define UDC_EP_SUBPTR_ADDR			0x10
+#define UDC_EP_DESPTR_ADDR			0x14
+#define UDC_EP_WRITE_CONFIRM_ADDR		0x1c
+
+/* EP number as layouted in AHB space */
+#define UDC_EP_NUM				32
+#define UDC_EPIN_NUM				16
+#define UDC_EPIN_NUM_USED			5
+#define UDC_EPOUT_NUM				16
+/* EP number of EP's really used = EP0 + 8 data EP's */
+#define UDC_USED_EP_NUM				9
+/* UDC CSR regs are aligned but AHB regs not - offset for OUT EP's */
+#define UDC_CSR_EP_OUT_IX_OFS			12
+
+#define UDC_EP0OUT_IX				16
+#define UDC_EP0IN_IX				0
+
+/* Rx fifo address and size = 1k -------------------------------------------*/
+#define UDC_RXFIFO_ADDR				0x800
+#define UDC_RXFIFO_SIZE				0x400
+
+/* Tx fifo address and size = 1.5k -----------------------------------------*/
+#define UDC_TXFIFO_ADDR				0xc00
+#define UDC_TXFIFO_SIZE				0x600
+
+/* default data endpoints --------------------------------------------------*/
+#define UDC_EPIN_STATUS_IX			1
+#define UDC_EPIN_IX				2
+#define UDC_EPOUT_IX				18
+
+/* general constants -------------------------------------------------------*/
+#define UDC_DWORD_BYTES				4
+#define UDC_BITS_PER_BYTE_SHIFT			3
+#define UDC_BYTE_MASK				0xff
+#define UDC_BITS_PER_BYTE			8
+
+/*---------------------------------------------------------------------------*/
+/* UDC CSR's */
+struct udc_csrs {
+
+	/* sca - setup command address */
+	u32 sca;
+
+	/* ep ne's */
+	u32 ne[UDC_USED_EP_NUM];
+} __attribute__ ((packed));
+
+/* AHB subsystem CSR registers */
+struct udc_regs {
+
+	/* device configuration */
+	u32 cfg;
+
+	/* device control */
+	u32 ctl;
+
+	/* device status */
+	u32 sts;
+
+	/* device interrupt */
+	u32 irqsts;
+
+	/* device interrupt mask */
+	u32 irqmsk;
+
+	/* endpoint interrupt */
+	u32 ep_irqsts;
+
+	/* endpoint interrupt mask */
+	u32 ep_irqmsk;
+} __attribute__ ((packed));
+
+/* endpoint specific registers */
+struct udc_ep_regs {
+
+	/* endpoint control */
+	u32 ctl;
+
+	/* endpoint status */
+	u32 sts;
+
+	/* endpoint buffer size in/ receive packet frame number out */
+	u32 bufin_framenum;
+
+	/* endpoint buffer size out/max packet size */
+	u32 bufout_maxpkt;
+
+	/* endpoint setup buffer pointer */
+	u32 subptr;
+
+	/* endpoint data descriptor pointer */
+	u32 desptr;
+
+	/* reserverd */
+	u32 reserved;
+
+	/* write/read confirmation */
+	u32 confirm;
+
+} __attribute__ ((packed));
+
+/* control data DMA desc */
+struct udc_stp_dma {
+	/* status quadlet */
+	u32	status;
+	/* reserved */
+	u32	_reserved;
+	/* first setup word */
+	u32	data12;
+	/* second setup word */
+	u32	data34;
+} __attribute__ ((aligned (16)));
+
+/* normal data DMA desc */
+struct udc_data_dma {
+	/* status quadlet */
+	u32	status;
+	/* reserved */
+	u32	_reserved;
+	/* buffer pointer */
+	u32	bufptr;
+	/* next descriptor pointer */
+	u32	next;
+} __attribute__ ((aligned (16)));
+
+/* request packet */
+struct udc_request {
+	/* embedded gadget ep */
+	struct usb_request		req;
+
+	/* flags */
+	unsigned			dma_going : 1,
+					dma_mapping : 1,
+					dma_done : 1;
+	/* phys. address */
+	dma_addr_t			td_phys;
+	/* first dma desc. of chain */
+	struct udc_data_dma		*td_data;
+	/* last dma desc. of chain */
+	struct udc_data_dma		*td_data_last;
+	struct list_head		queue;
+
+	/* chain length */
+	unsigned			chain_len;
+
+};
+
+/* UDC specific endpoint parameters */
+struct udc_ep {
+	struct usb_ep			ep;
+	struct udc_ep_regs __iomem	*regs;
+	u32 __iomem			*txfifo;
+	u32 __iomem			*dma;
+	dma_addr_t			td_phys;
+	dma_addr_t			td_stp_dma;
+	struct udc_stp_dma		*td_stp;
+	struct udc_data_dma		*td;
+	/* temp request */
+	struct udc_request		*req;
+	unsigned			req_used;
+	unsigned			req_completed;
+	/* dummy DMA desc for BNA dummy */
+	struct udc_request		*bna_dummy_req;
+	unsigned			bna_occurred;
+
+	/* NAK state */
+	unsigned			naking;
+
+	struct udc			*dev;
+
+	/* queue for requests */
+	struct list_head		queue;
+	const struct usb_endpoint_descriptor	*desc;
+	unsigned			halted;
+	unsigned			cancel_transfer;
+	unsigned			num : 5,
+					fifo_depth : 14,
+					in : 1;
+};
+
+/* device struct */
+struct udc {
+	struct usb_gadget		gadget;
+	spinlock_t			lock;	/* protects all state */
+	/* all endpoints */
+	struct udc_ep			ep[UDC_EP_NUM];
+	struct usb_gadget_driver	*driver;
+	/* operational flags */
+	unsigned			active : 1,
+					stall_ep0in : 1,
+					waiting_zlp_ack_ep0in : 1,
+					set_cfg_not_acked : 1,
+					irq_registered : 1,
+					data_ep_enabled : 1,
+					data_ep_queued : 1,
+					mem_region : 1,
+					sys_suspended : 1,
+					connected;
+
+	u16				chiprev;
+
+	/* registers */
+	struct pci_dev			*pdev;
+	struct udc_csrs __iomem		*csr;
+	struct udc_regs __iomem		*regs;
+	struct udc_ep_regs __iomem	*ep_regs;
+	u32 __iomem			*rxfifo;
+	u32 __iomem			*txfifo;
+
+	/* DMA desc pools */
+	struct pci_pool			*data_requests;
+	struct pci_pool			*stp_requests;
+
+	/* device data */
+	unsigned long			phys_addr;
+	void __iomem			*virt_addr;
+	unsigned			irq;
+
+	/* states */
+	u16				cur_config;
+	u16				cur_intf;
+	u16				cur_alt;
+};
+
+/* setup request data */
+union udc_setup_data {
+	u32			data[2];
+	struct usb_ctrlrequest	request;
+};
+
+/*
+ *---------------------------------------------------------------------------
+ * SET and GET bitfields in u32 values
+ * via constants for mask/offset:
+ * <bit_field_stub_name> is the text between
+ * UDC_ and _MASK|_OFS of appropiate
+ * constant
+ *
+ * set bitfield value in u32 u32Val
+ */
+#define AMD_ADDBITS(u32Val, bitfield_val, bitfield_stub_name)		\
+	(((u32Val) & (((u32) ~((u32) bitfield_stub_name##_MASK))))	\
+	| (((bitfield_val) << ((u32) bitfield_stub_name##_OFS))		\
+		& ((u32) bitfield_stub_name##_MASK)))
+
+/*
+ * set bitfield value in zero-initialized u32 u32Val
+ * => bitfield bits in u32Val are all zero
+ */
+#define AMD_INIT_SETBITS(u32Val, bitfield_val, bitfield_stub_name)	\
+	((u32Val)							\
+	| (((bitfield_val) << ((u32) bitfield_stub_name##_OFS))		\
+		& ((u32) bitfield_stub_name##_MASK)))
+
+/* get bitfield value from u32 u32Val */
+#define AMD_GETBITS(u32Val, bitfield_stub_name)				\
+	((u32Val & ((u32) bitfield_stub_name##_MASK))			\
+		>> ((u32) bitfield_stub_name##_OFS))
+
+/* SET and GET bits in u32 values ------------------------------------------*/
+#define AMD_BIT(bit_stub_name) (1 << bit_stub_name)
+#define AMD_UNMASK_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+#define AMD_CLEAR_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name))
+
+/* debug macros ------------------------------------------------------------*/
+
+#define DBG(udc , args...)	dev_dbg(&(udc)->pdev->dev, args)
+
+#ifdef UDC_VERBOSE
+#define VDBG			DBG
+#else
+#define VDBG(udc , args...)	do {} while (0)
+#endif
+
+#endif /* #ifdef AMD5536UDC_H */
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 63d7d65..a6adf7e 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -38,7 +38,7 @@
 #include <linux/proc_fs.h>
 #include <linux/clk.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/hardware.h>
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
new file mode 100644
index 0000000..4fb5ff4
--- /dev/null
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -0,0 +1,2077 @@
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ *
+ * Copyright (C) 2005-2007 Atmel 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.
+ */
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/delay.h>
+
+#include <asm/gpio.h>
+#include <asm/arch/board.h>
+
+#include "atmel_usba_udc.h"
+
+
+static struct usba_udc the_udc;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+static int queue_dbg_open(struct inode *inode, struct file *file)
+{
+	struct usba_ep *ep = inode->i_private;
+	struct usba_request *req, *req_copy;
+	struct list_head *queue_data;
+
+	queue_data = kmalloc(sizeof(*queue_data), GFP_KERNEL);
+	if (!queue_data)
+		return -ENOMEM;
+	INIT_LIST_HEAD(queue_data);
+
+	spin_lock_irq(&ep->udc->lock);
+	list_for_each_entry(req, &ep->queue, queue) {
+		req_copy = kmalloc(sizeof(*req_copy), GFP_ATOMIC);
+		if (!req_copy)
+			goto fail;
+		memcpy(req_copy, req, sizeof(*req_copy));
+		list_add_tail(&req_copy->queue, queue_data);
+	}
+	spin_unlock_irq(&ep->udc->lock);
+
+	file->private_data = queue_data;
+	return 0;
+
+fail:
+	spin_unlock_irq(&ep->udc->lock);
+	list_for_each_entry_safe(req, req_copy, queue_data, queue) {
+		list_del(&req->queue);
+		kfree(req);
+	}
+	kfree(queue_data);
+	return -ENOMEM;
+}
+
+/*
+ * bbbbbbbb llllllll IZS sssss nnnn FDL\n\0
+ *
+ * b: buffer address
+ * l: buffer length
+ * I/i: interrupt/no interrupt
+ * Z/z: zero/no zero
+ * S/s: short ok/short not ok
+ * s: status
+ * n: nr_packets
+ * F/f: submitted/not submitted to FIFO
+ * D/d: using/not using DMA
+ * L/l: last transaction/not last transaction
+ */
+static ssize_t queue_dbg_read(struct file *file, char __user *buf,
+		size_t nbytes, loff_t *ppos)
+{
+	struct list_head *queue = file->private_data;
+	struct usba_request *req, *tmp_req;
+	size_t len, remaining, actual = 0;
+	char tmpbuf[38];
+
+	if (!access_ok(VERIFY_WRITE, buf, nbytes))
+		return -EFAULT;
+
+	mutex_lock(&file->f_dentry->d_inode->i_mutex);
+	list_for_each_entry_safe(req, tmp_req, queue, queue) {
+		len = snprintf(tmpbuf, sizeof(tmpbuf),
+				"%8p %08x %c%c%c %5d %c%c%c\n",
+				req->req.buf, req->req.length,
+				req->req.no_interrupt ? 'i' : 'I',
+				req->req.zero ? 'Z' : 'z',
+				req->req.short_not_ok ? 's' : 'S',
+				req->req.status,
+				req->submitted ? 'F' : 'f',
+				req->using_dma ? 'D' : 'd',
+				req->last_transaction ? 'L' : 'l');
+		len = min(len, sizeof(tmpbuf));
+		if (len > nbytes)
+			break;
+
+		list_del(&req->queue);
+		kfree(req);
+
+		remaining = __copy_to_user(buf, tmpbuf, len);
+		actual += len - remaining;
+		if (remaining)
+			break;
+
+		nbytes -= len;
+		buf += len;
+	}
+	mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+
+	return actual;
+}
+
+static int queue_dbg_release(struct inode *inode, struct file *file)
+{
+	struct list_head *queue_data = file->private_data;
+	struct usba_request *req, *tmp_req;
+
+	list_for_each_entry_safe(req, tmp_req, queue_data, queue) {
+		list_del(&req->queue);
+		kfree(req);
+	}
+	kfree(queue_data);
+	return 0;
+}
+
+static int regs_dbg_open(struct inode *inode, struct file *file)
+{
+	struct usba_udc *udc;
+	unsigned int i;
+	u32 *data;
+	int ret = -ENOMEM;
+
+	mutex_lock(&inode->i_mutex);
+	udc = inode->i_private;
+	data = kmalloc(inode->i_size, GFP_KERNEL);
+	if (!data)
+		goto out;
+
+	spin_lock_irq(&udc->lock);
+	for (i = 0; i < inode->i_size / 4; i++)
+		data[i] = __raw_readl(udc->regs + i * 4);
+	spin_unlock_irq(&udc->lock);
+
+	file->private_data = data;
+	ret = 0;
+
+out:
+	mutex_unlock(&inode->i_mutex);
+
+	return ret;
+}
+
+static ssize_t regs_dbg_read(struct file *file, char __user *buf,
+		size_t nbytes, loff_t *ppos)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	int ret;
+
+	mutex_lock(&inode->i_mutex);
+	ret = simple_read_from_buffer(buf, nbytes, ppos,
+			file->private_data,
+			file->f_dentry->d_inode->i_size);
+	mutex_unlock(&inode->i_mutex);
+
+	return ret;
+}
+
+static int regs_dbg_release(struct inode *inode, struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+const struct file_operations queue_dbg_fops = {
+	.owner		= THIS_MODULE,
+	.open		= queue_dbg_open,
+	.llseek		= no_llseek,
+	.read		= queue_dbg_read,
+	.release	= queue_dbg_release,
+};
+
+const struct file_operations regs_dbg_fops = {
+	.owner		= THIS_MODULE,
+	.open		= regs_dbg_open,
+	.llseek		= generic_file_llseek,
+	.read		= regs_dbg_read,
+	.release	= regs_dbg_release,
+};
+
+static void usba_ep_init_debugfs(struct usba_udc *udc,
+		struct usba_ep *ep)
+{
+	struct dentry *ep_root;
+
+	ep_root = debugfs_create_dir(ep->ep.name, udc->debugfs_root);
+	if (!ep_root)
+		goto err_root;
+	ep->debugfs_dir = ep_root;
+
+	ep->debugfs_queue = debugfs_create_file("queue", 0400, ep_root,
+						ep, &queue_dbg_fops);
+	if (!ep->debugfs_queue)
+		goto err_queue;
+
+	if (ep->can_dma) {
+		ep->debugfs_dma_status
+			= debugfs_create_u32("dma_status", 0400, ep_root,
+					&ep->last_dma_status);
+		if (!ep->debugfs_dma_status)
+			goto err_dma_status;
+	}
+	if (ep_is_control(ep)) {
+		ep->debugfs_state
+			= debugfs_create_u32("state", 0400, ep_root,
+					&ep->state);
+		if (!ep->debugfs_state)
+			goto err_state;
+	}
+
+	return;
+
+err_state:
+	if (ep->can_dma)
+		debugfs_remove(ep->debugfs_dma_status);
+err_dma_status:
+	debugfs_remove(ep->debugfs_queue);
+err_queue:
+	debugfs_remove(ep_root);
+err_root:
+	dev_err(&ep->udc->pdev->dev,
+		"failed to create debugfs directory for %s\n", ep->ep.name);
+}
+
+static void usba_ep_cleanup_debugfs(struct usba_ep *ep)
+{
+	debugfs_remove(ep->debugfs_queue);
+	debugfs_remove(ep->debugfs_dma_status);
+	debugfs_remove(ep->debugfs_state);
+	debugfs_remove(ep->debugfs_dir);
+	ep->debugfs_dma_status = NULL;
+	ep->debugfs_dir = NULL;
+}
+
+static void usba_init_debugfs(struct usba_udc *udc)
+{
+	struct dentry *root, *regs;
+	struct resource *regs_resource;
+
+	root = debugfs_create_dir(udc->gadget.name, NULL);
+	if (IS_ERR(root) || !root)
+		goto err_root;
+	udc->debugfs_root = root;
+
+	regs = debugfs_create_file("regs", 0400, root, udc, &regs_dbg_fops);
+	if (!regs)
+		goto err_regs;
+
+	regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM,
+				CTRL_IOMEM_ID);
+	regs->d_inode->i_size = regs_resource->end - regs_resource->start + 1;
+	udc->debugfs_regs = regs;
+
+	usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0));
+
+	return;
+
+err_regs:
+	debugfs_remove(root);
+err_root:
+	udc->debugfs_root = NULL;
+	dev_err(&udc->pdev->dev, "debugfs is not available\n");
+}
+
+static void usba_cleanup_debugfs(struct usba_udc *udc)
+{
+	usba_ep_cleanup_debugfs(to_usba_ep(udc->gadget.ep0));
+	debugfs_remove(udc->debugfs_regs);
+	debugfs_remove(udc->debugfs_root);
+	udc->debugfs_regs = NULL;
+	udc->debugfs_root = NULL;
+}
+#else
+static inline void usba_ep_init_debugfs(struct usba_udc *udc,
+					 struct usba_ep *ep)
+{
+
+}
+
+static inline void usba_ep_cleanup_debugfs(struct usba_ep *ep)
+{
+
+}
+
+static inline void usba_init_debugfs(struct usba_udc *udc)
+{
+
+}
+
+static inline void usba_cleanup_debugfs(struct usba_udc *udc)
+{
+
+}
+#endif
+
+static int vbus_is_present(struct usba_udc *udc)
+{
+	if (udc->vbus_pin != -1)
+		return gpio_get_value(udc->vbus_pin);
+
+	/* No Vbus detection: Assume always present */
+	return 1;
+}
+
+static void copy_to_fifo(void __iomem *fifo, const void *buf, int len)
+{
+	unsigned long tmp;
+
+	DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len);
+	for (; len > 0; len -= 4, buf += 4, fifo += 4) {
+		tmp = *(unsigned long *)buf;
+		if (len >= 4) {
+			DBG(DBG_FIFO, "  -> %08lx\n", tmp);
+			__raw_writel(tmp, fifo);
+		} else {
+			do {
+				DBG(DBG_FIFO, "  -> %02lx\n", tmp >> 24);
+				__raw_writeb(tmp >> 24, fifo);
+				fifo++;
+				tmp <<= 8;
+			} while (--len);
+			break;
+		}
+	}
+}
+
+static void copy_from_fifo(void *buf, void __iomem *fifo, int len)
+{
+	union {
+		unsigned long *w;
+		unsigned char *b;
+	} p;
+	unsigned long tmp;
+
+	DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len);
+	for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) {
+		if (len >= 4) {
+			tmp = __raw_readl(fifo);
+			*p.w = tmp;
+			DBG(DBG_FIFO, "  -> %08lx\n", tmp);
+		} else {
+			do {
+				tmp = __raw_readb(fifo);
+				*p.b = tmp;
+				DBG(DBG_FIFO, " -> %02lx\n", tmp);
+				fifo++, p.b++;
+			} while (--len);
+		}
+	}
+}
+
+static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
+{
+	unsigned int transaction_len;
+
+	transaction_len = req->req.length - req->req.actual;
+	req->last_transaction = 1;
+	if (transaction_len > ep->ep.maxpacket) {
+		transaction_len = ep->ep.maxpacket;
+		req->last_transaction = 0;
+	} else if (transaction_len == ep->ep.maxpacket && req->req.zero)
+		req->last_transaction = 0;
+
+	DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n",
+		ep->ep.name, req, transaction_len,
+		req->last_transaction ? ", done" : "");
+
+	copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len);
+	usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+	req->req.actual += transaction_len;
+}
+
+static void submit_request(struct usba_ep *ep, struct usba_request *req)
+{
+	DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d)\n",
+		ep->ep.name, req, req->req.length);
+
+	req->req.actual = 0;
+	req->submitted = 1;
+
+	if (req->using_dma) {
+		if (req->req.length == 0) {
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+			return;
+		}
+
+		if (req->req.zero)
+			usba_ep_writel(ep, CTL_ENB, USBA_SHORT_PACKET);
+		else
+			usba_ep_writel(ep, CTL_DIS, USBA_SHORT_PACKET);
+
+		usba_dma_writel(ep, ADDRESS, req->req.dma);
+		usba_dma_writel(ep, CONTROL, req->ctrl);
+	} else {
+		next_fifo_transaction(ep, req);
+		if (req->last_transaction) {
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+		} else {
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+		}
+	}
+}
+
+static void submit_next_request(struct usba_ep *ep)
+{
+	struct usba_request *req;
+
+	if (list_empty(&ep->queue)) {
+		usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY);
+		return;
+	}
+
+	req = list_entry(ep->queue.next, struct usba_request, queue);
+	if (!req->submitted)
+		submit_request(ep, req);
+}
+
+static void send_status(struct usba_udc *udc, struct usba_ep *ep)
+{
+	ep->state = STATUS_STAGE_IN;
+	usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+	usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+}
+
+static void receive_data(struct usba_ep *ep)
+{
+	struct usba_udc *udc = ep->udc;
+	struct usba_request *req;
+	unsigned long status;
+	unsigned int bytecount, nr_busy;
+	int is_complete = 0;
+
+	status = usba_ep_readl(ep, STA);
+	nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+	DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy);
+
+	while (nr_busy > 0) {
+		if (list_empty(&ep->queue)) {
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+			break;
+		}
+		req = list_entry(ep->queue.next,
+				 struct usba_request, queue);
+
+		bytecount = USBA_BFEXT(BYTE_COUNT, status);
+
+		if (status & (1 << 31))
+			is_complete = 1;
+		if (req->req.actual + bytecount >= req->req.length) {
+			is_complete = 1;
+			bytecount = req->req.length - req->req.actual;
+		}
+
+		copy_from_fifo(req->req.buf + req->req.actual,
+				ep->fifo, bytecount);
+		req->req.actual += bytecount;
+
+		usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+
+		if (is_complete) {
+			DBG(DBG_QUEUE, "%s: request done\n", ep->ep.name);
+			req->req.status = 0;
+			list_del_init(&req->queue);
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+			spin_unlock(&udc->lock);
+			req->req.complete(&ep->ep, &req->req);
+			spin_lock(&udc->lock);
+		}
+
+		status = usba_ep_readl(ep, STA);
+		nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+		if (is_complete && ep_is_control(ep)) {
+			send_status(udc, ep);
+			break;
+		}
+	}
+}
+
+static void
+request_complete(struct usba_ep *ep, struct usba_request *req, int status)
+{
+	struct usba_udc *udc = ep->udc;
+
+	WARN_ON(!list_empty(&req->queue));
+
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = status;
+
+	if (req->mapped) {
+		dma_unmap_single(
+			&udc->pdev->dev, req->req.dma, req->req.length,
+			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		req->req.dma = DMA_ADDR_INVALID;
+		req->mapped = 0;
+	}
+
+	DBG(DBG_GADGET | DBG_REQ,
+		"%s: req %p complete: status %d, actual %u\n",
+		ep->ep.name, req, req->req.status, req->req.actual);
+
+	spin_unlock(&udc->lock);
+	req->req.complete(&ep->ep, &req->req);
+	spin_lock(&udc->lock);
+}
+
+static void
+request_complete_list(struct usba_ep *ep, struct list_head *list, int status)
+{
+	struct usba_request *req, *tmp_req;
+
+	list_for_each_entry_safe(req, tmp_req, list, queue) {
+		list_del_init(&req->queue);
+		request_complete(ep, req, status);
+	}
+}
+
+static int
+usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	unsigned long flags, ept_cfg, maxpacket;
+	unsigned int nr_trans;
+
+	DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc);
+
+	maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
+
+	if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index)
+			|| ep->index == 0
+			|| desc->bDescriptorType != USB_DT_ENDPOINT
+			|| maxpacket == 0
+			|| maxpacket > ep->fifo_size) {
+		DBG(DBG_ERR, "ep_enable: Invalid argument");
+		return -EINVAL;
+	}
+
+	ep->is_isoc = 0;
+	ep->is_in = 0;
+
+	if (maxpacket <= 8)
+		ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8);
+	else
+		/* LSB is bit 1, not 0 */
+		ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3);
+
+	DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n",
+			ep->ep.name, ept_cfg, maxpacket);
+
+	if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+		ep->is_in = 1;
+		ept_cfg |= USBA_EPT_DIR_IN;
+	}
+
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL);
+		ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE);
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		if (!ep->can_isoc) {
+			DBG(DBG_ERR, "ep_enable: %s is not isoc capable\n",
+					ep->ep.name);
+			return -EINVAL;
+		}
+
+		/*
+		 * Bits 11:12 specify number of _additional_
+		 * transactions per microframe.
+		 */
+		nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1;
+		if (nr_trans > 3)
+			return -EINVAL;
+
+		ep->is_isoc = 1;
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO);
+
+		/*
+		 * Do triple-buffering on high-bandwidth iso endpoints.
+		 */
+		if (nr_trans > 1 && ep->nr_banks == 3)
+			ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE);
+		else
+			ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+		ept_cfg |= USBA_BF(NB_TRANS, nr_trans);
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK);
+		ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT);
+		ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+		break;
+	}
+
+	spin_lock_irqsave(&ep->udc->lock, flags);
+
+	if (ep->desc) {
+		spin_unlock_irqrestore(&ep->udc->lock, flags);
+		DBG(DBG_ERR, "ep%d already enabled\n", ep->index);
+		return -EBUSY;
+	}
+
+	ep->desc = desc;
+	ep->ep.maxpacket = maxpacket;
+
+	usba_ep_writel(ep, CFG, ept_cfg);
+	usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+
+	if (ep->can_dma) {
+		u32 ctrl;
+
+		usba_writel(udc, INT_ENB,
+				(usba_readl(udc, INT_ENB)
+					| USBA_BF(EPT_INT, 1 << ep->index)
+					| USBA_BF(DMA_INT, 1 << ep->index)));
+		ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
+		usba_ep_writel(ep, CTL_ENB, ctrl);
+	} else {
+		usba_writel(udc, INT_ENB,
+				(usba_readl(udc, INT_ENB)
+					| USBA_BF(EPT_INT, 1 << ep->index)));
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index,
+			(unsigned long)usba_ep_readl(ep, CFG));
+	DBG(DBG_HW, "INT_ENB after init: %#08lx\n",
+			(unsigned long)usba_readl(udc, INT_ENB));
+
+	return 0;
+}
+
+static int usba_ep_disable(struct usb_ep *_ep)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	LIST_HEAD(req_list);
+	unsigned long flags;
+
+	DBG(DBG_GADGET, "ep_disable: %s\n", ep->ep.name);
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	if (!ep->desc) {
+		spin_unlock_irqrestore(&udc->lock, flags);
+		DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name);
+		return -EINVAL;
+	}
+	ep->desc = NULL;
+
+	list_splice_init(&ep->queue, &req_list);
+	if (ep->can_dma) {
+		usba_dma_writel(ep, CONTROL, 0);
+		usba_dma_writel(ep, ADDRESS, 0);
+		usba_dma_readl(ep, STATUS);
+	}
+	usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
+	usba_writel(udc, INT_ENB,
+			usba_readl(udc, INT_ENB)
+			& ~USBA_BF(EPT_INT, 1 << ep->index));
+
+	request_complete_list(ep, &req_list, -ESHUTDOWN);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+static struct usb_request *
+usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct usba_request *req;
+
+	DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags);
+
+	req = kzalloc(sizeof(*req), gfp_flags);
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD(&req->queue);
+	req->req.dma = DMA_ADDR_INVALID;
+
+	return &req->req;
+}
+
+static void
+usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct usba_request *req = to_usba_req(_req);
+
+	DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req);
+
+	kfree(req);
+}
+
+static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
+		struct usba_request *req, gfp_t gfp_flags)
+{
+	unsigned long flags;
+	int ret;
+
+	DBG(DBG_DMA, "%s: req l/%u d/%08x %c%c%c\n",
+		ep->ep.name, req->req.length, req->req.dma,
+		req->req.zero ? 'Z' : 'z',
+		req->req.short_not_ok ? 'S' : 's',
+		req->req.no_interrupt ? 'I' : 'i');
+
+	if (req->req.length > 0x10000) {
+		/* Lengths from 0 to 65536 (inclusive) are supported */
+		DBG(DBG_ERR, "invalid request length %u\n", req->req.length);
+		return -EINVAL;
+	}
+
+	req->using_dma = 1;
+
+	if (req->req.dma == DMA_ADDR_INVALID) {
+		req->req.dma = dma_map_single(
+			&udc->pdev->dev, req->req.buf, req->req.length,
+			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		req->mapped = 1;
+	} else {
+		dma_sync_single_for_device(
+			&udc->pdev->dev, req->req.dma, req->req.length,
+			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		req->mapped = 0;
+	}
+
+	req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
+			| USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
+			| USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE;
+
+	if (ep->is_in)
+		req->ctrl |= USBA_DMA_END_BUF_EN;
+
+	/*
+	 * Add this request to the queue and submit for DMA if
+	 * possible. Check if we're still alive first -- we may have
+	 * received a reset since last time we checked.
+	 */
+	ret = -ESHUTDOWN;
+	spin_lock_irqsave(&udc->lock, flags);
+	if (ep->desc) {
+		if (list_empty(&ep->queue))
+			submit_request(ep, req);
+
+		list_add_tail(&req->queue, &ep->queue);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return ret;
+}
+
+static int
+usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct usba_request *req = to_usba_req(_req);
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	unsigned long flags;
+	int ret;
+
+	DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n",
+			ep->ep.name, req, _req->length);
+
+	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc)
+		return -ESHUTDOWN;
+
+	req->submitted = 0;
+	req->using_dma = 0;
+	req->last_transaction = 0;
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	if (ep->can_dma)
+		return queue_dma(udc, ep, req, gfp_flags);
+
+	/* May have received a reset since last time we checked */
+	ret = -ESHUTDOWN;
+	spin_lock_irqsave(&udc->lock, flags);
+	if (ep->desc) {
+		list_add_tail(&req->queue, &ep->queue);
+
+		if (ep->is_in || (ep_is_control(ep)
+				&& (ep->state == DATA_STAGE_IN
+					|| ep->state == STATUS_STAGE_IN)))
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+		else
+			usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return ret;
+}
+
+static void
+usba_update_req(struct usba_ep *ep, struct usba_request *req, u32 status)
+{
+	req->req.actual = req->req.length - USBA_BFEXT(DMA_BUF_LEN, status);
+}
+
+static int stop_dma(struct usba_ep *ep, u32 *pstatus)
+{
+	unsigned int timeout;
+	u32 status;
+
+	/*
+	 * Stop the DMA controller. When writing both CH_EN
+	 * and LINK to 0, the other bits are not affected.
+	 */
+	usba_dma_writel(ep, CONTROL, 0);
+
+	/* Wait for the FIFO to empty */
+	for (timeout = 40; timeout; --timeout) {
+		status = usba_dma_readl(ep, STATUS);
+		if (!(status & USBA_DMA_CH_EN))
+			break;
+		udelay(1);
+	}
+
+	if (pstatus)
+		*pstatus = status;
+
+	if (timeout == 0) {
+		dev_err(&ep->udc->pdev->dev,
+			"%s: timed out waiting for DMA FIFO to empty\n",
+			ep->ep.name);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	struct usba_request *req = to_usba_req(_req);
+	unsigned long flags;
+	u32 status;
+
+	DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n",
+			ep->ep.name, req);
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	if (req->using_dma) {
+		/*
+		 * If this request is currently being transferred,
+		 * stop the DMA controller and reset the FIFO.
+		 */
+		if (ep->queue.next == &req->queue) {
+			status = usba_dma_readl(ep, STATUS);
+			if (status & USBA_DMA_CH_EN)
+				stop_dma(ep, &status);
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+			ep->last_dma_status = status;
+#endif
+
+			usba_writel(udc, EPT_RST, 1 << ep->index);
+
+			usba_update_req(ep, req, status);
+		}
+	}
+
+	/*
+	 * Errors should stop the queue from advancing until the
+	 * completion function returns.
+	 */
+	list_del_init(&req->queue);
+
+	request_complete(ep, req, -ECONNRESET);
+
+	/* Process the next request if any */
+	submit_next_request(ep);
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+static int usba_ep_set_halt(struct usb_ep *_ep, int value)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	unsigned long flags;
+	int ret = 0;
+
+	DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name,
+			value ? "set" : "clear");
+
+	if (!ep->desc) {
+		DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n",
+				ep->ep.name);
+		return -ENODEV;
+	}
+	if (ep->is_isoc) {
+		DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n",
+				ep->ep.name);
+		return -ENOTTY;
+	}
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/*
+	 * We can't halt IN endpoints while there are still data to be
+	 * transferred
+	 */
+	if (!list_empty(&ep->queue)
+			|| ((value && ep->is_in && (usba_ep_readl(ep, STA)
+					& USBA_BF(BUSY_BANKS, -1L))))) {
+		ret = -EAGAIN;
+	} else {
+		if (value)
+			usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+		else
+			usba_ep_writel(ep, CLR_STA,
+					USBA_FORCE_STALL | USBA_TOGGLE_CLR);
+		usba_ep_readl(ep, STA);
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return ret;
+}
+
+static int usba_ep_fifo_status(struct usb_ep *_ep)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+
+	return USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+}
+
+static void usba_ep_fifo_flush(struct usb_ep *_ep)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+
+	usba_writel(udc, EPT_RST, 1 << ep->index);
+}
+
+static const struct usb_ep_ops usba_ep_ops = {
+	.enable		= usba_ep_enable,
+	.disable	= usba_ep_disable,
+	.alloc_request	= usba_ep_alloc_request,
+	.free_request	= usba_ep_free_request,
+	.queue		= usba_ep_queue,
+	.dequeue	= usba_ep_dequeue,
+	.set_halt	= usba_ep_set_halt,
+	.fifo_status	= usba_ep_fifo_status,
+	.fifo_flush	= usba_ep_fifo_flush,
+};
+
+static int usba_udc_get_frame(struct usb_gadget *gadget)
+{
+	struct usba_udc *udc = to_usba_udc(gadget);
+
+	return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM));
+}
+
+static int usba_udc_wakeup(struct usb_gadget *gadget)
+{
+	struct usba_udc *udc = to_usba_udc(gadget);
+	unsigned long flags;
+	u32 ctrl;
+	int ret = -EINVAL;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
+		ctrl = usba_readl(udc, CTRL);
+		usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return ret;
+}
+
+static int
+usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
+{
+	struct usba_udc *udc = to_usba_udc(gadget);
+	unsigned long flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (is_selfpowered)
+		udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
+	else
+		udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+static const struct usb_gadget_ops usba_udc_ops = {
+	.get_frame		= usba_udc_get_frame,
+	.wakeup			= usba_udc_wakeup,
+	.set_selfpowered	= usba_udc_set_selfpowered,
+};
+
+#define EP(nam, idx, maxpkt, maxbk, dma, isoc)			\
+{								\
+	.ep	= {						\
+		.ops		= &usba_ep_ops,			\
+		.name		= nam,				\
+		.maxpacket	= maxpkt,			\
+	},							\
+	.udc		= &the_udc,				\
+	.queue		= LIST_HEAD_INIT(usba_ep[idx].queue),	\
+	.fifo_size	= maxpkt,				\
+	.nr_banks	= maxbk,				\
+	.index		= idx,					\
+	.can_dma	= dma,					\
+	.can_isoc	= isoc,					\
+}
+
+static struct usba_ep usba_ep[] = {
+	EP("ep0", 0, 64, 1, 0, 0),
+	EP("ep1in-bulk", 1, 512, 2, 1, 1),
+	EP("ep2out-bulk", 2, 512, 2, 1, 1),
+	EP("ep3in-int", 3, 64, 3, 1, 0),
+	EP("ep4out-int", 4, 64, 3, 1, 0),
+	EP("ep5in-iso", 5, 1024, 3, 1, 1),
+	EP("ep6out-iso", 6, 1024, 3, 1, 1),
+};
+#undef EP
+
+static struct usb_endpoint_descriptor usba_ep0_desc = {
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = 0,
+	.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize = __constant_cpu_to_le16(64),
+	/* FIXME: I have no idea what to put here */
+	.bInterval = 1,
+};
+
+static void nop_release(struct device *dev)
+{
+
+}
+
+static struct usba_udc the_udc = {
+	.gadget	= {
+		.ops		= &usba_udc_ops,
+		.ep0		= &usba_ep[0].ep,
+		.ep_list	= LIST_HEAD_INIT(the_udc.gadget.ep_list),
+		.is_dualspeed	= 1,
+		.name		= "atmel_usba_udc",
+		.dev	= {
+			.bus_id		= "gadget",
+			.release	= nop_release,
+		},
+	},
+
+	.lock	= SPIN_LOCK_UNLOCKED,
+};
+
+/*
+ * Called with interrupts disabled and udc->lock held.
+ */
+static void reset_all_endpoints(struct usba_udc *udc)
+{
+	struct usba_ep *ep;
+	struct usba_request *req, *tmp_req;
+
+	usba_writel(udc, EPT_RST, ~0UL);
+
+	ep = to_usba_ep(udc->gadget.ep0);
+	list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) {
+		list_del_init(&req->queue);
+		request_complete(ep, req, -ECONNRESET);
+	}
+
+	list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+		if (ep->desc) {
+			spin_unlock(&udc->lock);
+			usba_ep_disable(&ep->ep);
+			spin_lock(&udc->lock);
+		}
+	}
+}
+
+static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex)
+{
+	struct usba_ep *ep;
+
+	if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
+		return to_usba_ep(udc->gadget.ep0);
+
+	list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
+		u8 bEndpointAddress;
+
+		if (!ep->desc)
+			continue;
+		bEndpointAddress = ep->desc->bEndpointAddress;
+		if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
+			continue;
+		if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
+				== (wIndex & USB_ENDPOINT_NUMBER_MASK))
+			return ep;
+	}
+
+	return NULL;
+}
+
+/* Called with interrupts disabled and udc->lock held */
+static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep)
+{
+	usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+	ep->state = WAIT_FOR_SETUP;
+}
+
+static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep)
+{
+	if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL)
+		return 1;
+	return 0;
+}
+
+static inline void set_address(struct usba_udc *udc, unsigned int addr)
+{
+	u32 regval;
+
+	DBG(DBG_BUS, "setting address %u...\n", addr);
+	regval = usba_readl(udc, CTRL);
+	regval = USBA_BFINS(DEV_ADDR, addr, regval);
+	usba_writel(udc, CTRL, regval);
+}
+
+static int do_test_mode(struct usba_udc *udc)
+{
+	static const char test_packet_buffer[] = {
+		/* JKJKJKJK * 9 */
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		/* JJKKJJKK * 8 */
+		0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+		/* JJKKJJKK * 8 */
+		0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
+		/* JJJJJJJKKKKKKK * 8 */
+		0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+		/* JJJJJJJK * 8 */
+		0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD,
+		/* {JKKKKKKK * 10}, JK */
+		0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E
+	};
+	struct usba_ep *ep;
+	struct device *dev = &udc->pdev->dev;
+	int test_mode;
+
+	test_mode = udc->test_mode;
+
+	/* Start from a clean slate */
+	reset_all_endpoints(udc);
+
+	switch (test_mode) {
+	case 0x0100:
+		/* Test_J */
+		usba_writel(udc, TST, USBA_TST_J_MODE);
+		dev_info(dev, "Entering Test_J mode...\n");
+		break;
+	case 0x0200:
+		/* Test_K */
+		usba_writel(udc, TST, USBA_TST_K_MODE);
+		dev_info(dev, "Entering Test_K mode...\n");
+		break;
+	case 0x0300:
+		/*
+		 * Test_SE0_NAK: Force high-speed mode and set up ep0
+		 * for Bulk IN transfers
+		 */
+		ep = &usba_ep[0];
+		usba_writel(udc, TST,
+				USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH));
+		usba_ep_writel(ep, CFG,
+				USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+				| USBA_EPT_DIR_IN
+				| USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+				| USBA_BF(BK_NUMBER, 1));
+		if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+			set_protocol_stall(udc, ep);
+			dev_err(dev, "Test_SE0_NAK: ep0 not mapped\n");
+		} else {
+			usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+			dev_info(dev, "Entering Test_SE0_NAK mode...\n");
+		}
+		break;
+	case 0x0400:
+		/* Test_Packet */
+		ep = &usba_ep[0];
+		usba_ep_writel(ep, CFG,
+				USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+				| USBA_EPT_DIR_IN
+				| USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+				| USBA_BF(BK_NUMBER, 1));
+		if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+			set_protocol_stall(udc, ep);
+			dev_err(dev, "Test_Packet: ep0 not mapped\n");
+		} else {
+			usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+			usba_writel(udc, TST, USBA_TST_PKT_MODE);
+			copy_to_fifo(ep->fifo, test_packet_buffer,
+					sizeof(test_packet_buffer));
+			usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+			dev_info(dev, "Entering Test_Packet mode...\n");
+		}
+		break;
+	default:
+		dev_err(dev, "Invalid test mode: 0x%04x\n", test_mode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Avoid overly long expressions */
+static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq)
+{
+	if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP))
+		return true;
+	return false;
+}
+
+static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq)
+{
+	if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_TEST_MODE))
+		return true;
+	return false;
+}
+
+static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq)
+{
+	if (crq->wValue == __constant_cpu_to_le16(USB_ENDPOINT_HALT))
+		return true;
+	return false;
+}
+
+static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
+		struct usb_ctrlrequest *crq)
+{
+	int retval = 0;;
+
+	switch (crq->bRequest) {
+	case USB_REQ_GET_STATUS: {
+		u16 status;
+
+		if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) {
+			status = cpu_to_le16(udc->devstatus);
+		} else if (crq->bRequestType
+				== (USB_DIR_IN | USB_RECIP_INTERFACE)) {
+			status = __constant_cpu_to_le16(0);
+		} else if (crq->bRequestType
+				== (USB_DIR_IN | USB_RECIP_ENDPOINT)) {
+			struct usba_ep *target;
+
+			target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+			if (!target)
+				goto stall;
+
+			status = 0;
+			if (is_stalled(udc, target))
+				status |= __constant_cpu_to_le16(1);
+		} else
+			goto delegate;
+
+		/* Write directly to the FIFO. No queueing is done. */
+		if (crq->wLength != __constant_cpu_to_le16(sizeof(status)))
+			goto stall;
+		ep->state = DATA_STAGE_IN;
+		__raw_writew(status, ep->fifo);
+		usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+		break;
+	}
+
+	case USB_REQ_CLEAR_FEATURE: {
+		if (crq->bRequestType == USB_RECIP_DEVICE) {
+			if (feature_is_dev_remote_wakeup(crq))
+				udc->devstatus
+					&= ~(1 << USB_DEVICE_REMOTE_WAKEUP);
+			else
+				/* Can't CLEAR_FEATURE TEST_MODE */
+				goto stall;
+		} else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+			struct usba_ep *target;
+
+			if (crq->wLength != __constant_cpu_to_le16(0)
+					|| !feature_is_ep_halt(crq))
+				goto stall;
+			target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+			if (!target)
+				goto stall;
+
+			usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL);
+			if (target->index != 0)
+				usba_ep_writel(target, CLR_STA,
+						USBA_TOGGLE_CLR);
+		} else {
+			goto delegate;
+		}
+
+		send_status(udc, ep);
+		break;
+	}
+
+	case USB_REQ_SET_FEATURE: {
+		if (crq->bRequestType == USB_RECIP_DEVICE) {
+			if (feature_is_dev_test_mode(crq)) {
+				send_status(udc, ep);
+				ep->state = STATUS_STAGE_TEST;
+				udc->test_mode = le16_to_cpu(crq->wIndex);
+				return 0;
+			} else if (feature_is_dev_remote_wakeup(crq)) {
+				udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP;
+			} else {
+				goto stall;
+			}
+		} else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+			struct usba_ep *target;
+
+			if (crq->wLength != __constant_cpu_to_le16(0)
+					|| !feature_is_ep_halt(crq))
+				goto stall;
+
+			target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+			if (!target)
+				goto stall;
+
+			usba_ep_writel(target, SET_STA, USBA_FORCE_STALL);
+		} else
+			goto delegate;
+
+		send_status(udc, ep);
+		break;
+	}
+
+	case USB_REQ_SET_ADDRESS:
+		if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
+			goto delegate;
+
+		set_address(udc, le16_to_cpu(crq->wValue));
+		send_status(udc, ep);
+		ep->state = STATUS_STAGE_ADDR;
+		break;
+
+	default:
+delegate:
+		spin_unlock(&udc->lock);
+		retval = udc->driver->setup(&udc->gadget, crq);
+		spin_lock(&udc->lock);
+	}
+
+	return retval;
+
+stall:
+	printk(KERN_ERR
+		"udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, "
+		"halting endpoint...\n",
+		ep->ep.name, crq->bRequestType, crq->bRequest,
+		le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex),
+		le16_to_cpu(crq->wLength));
+	set_protocol_stall(udc, ep);
+	return -1;
+}
+
+static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+	struct usba_request *req;
+	u32 epstatus;
+	u32 epctrl;
+
+restart:
+	epstatus = usba_ep_readl(ep, STA);
+	epctrl = usba_ep_readl(ep, CTL);
+
+	DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n",
+			ep->ep.name, ep->state, epstatus, epctrl);
+
+	req = NULL;
+	if (!list_empty(&ep->queue))
+		req = list_entry(ep->queue.next,
+				 struct usba_request, queue);
+
+	if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+		if (req->submitted)
+			next_fifo_transaction(ep, req);
+		else
+			submit_request(ep, req);
+
+		if (req->last_transaction) {
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+		}
+		goto restart;
+	}
+	if ((epstatus & epctrl) & USBA_TX_COMPLETE) {
+		usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);
+
+		switch (ep->state) {
+		case DATA_STAGE_IN:
+			usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = STATUS_STAGE_OUT;
+			break;
+		case STATUS_STAGE_ADDR:
+			/* Activate our new address */
+			usba_writel(udc, CTRL, (usba_readl(udc, CTRL)
+						| USBA_FADDR_EN));
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = WAIT_FOR_SETUP;
+			break;
+		case STATUS_STAGE_IN:
+			if (req) {
+				list_del_init(&req->queue);
+				request_complete(ep, req, 0);
+				submit_next_request(ep);
+			}
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = WAIT_FOR_SETUP;
+			break;
+		case STATUS_STAGE_TEST:
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = WAIT_FOR_SETUP;
+			if (do_test_mode(udc))
+				set_protocol_stall(udc, ep);
+			break;
+		default:
+			printk(KERN_ERR
+				"udc: %s: TXCOMP: Invalid endpoint state %d, "
+				"halting endpoint...\n",
+				ep->ep.name, ep->state);
+			set_protocol_stall(udc, ep);
+			break;
+		}
+
+		goto restart;
+	}
+	if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+		switch (ep->state) {
+		case STATUS_STAGE_OUT:
+			usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+
+			if (req) {
+				list_del_init(&req->queue);
+				request_complete(ep, req, 0);
+			}
+			ep->state = WAIT_FOR_SETUP;
+			break;
+
+		case DATA_STAGE_OUT:
+			receive_data(ep);
+			break;
+
+		default:
+			usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+			printk(KERN_ERR
+				"udc: %s: RXRDY: Invalid endpoint state %d, "
+				"halting endpoint...\n",
+				ep->ep.name, ep->state);
+			set_protocol_stall(udc, ep);
+			break;
+		}
+
+		goto restart;
+	}
+	if (epstatus & USBA_RX_SETUP) {
+		union {
+			struct usb_ctrlrequest crq;
+			unsigned long data[2];
+		} crq;
+		unsigned int pkt_len;
+		int ret;
+
+		if (ep->state != WAIT_FOR_SETUP) {
+			/*
+			 * Didn't expect a SETUP packet at this
+			 * point. Clean up any pending requests (which
+			 * may be successful).
+			 */
+			int status = -EPROTO;
+
+			/*
+			 * RXRDY and TXCOMP are dropped when SETUP
+			 * packets arrive.  Just pretend we received
+			 * the status packet.
+			 */
+			if (ep->state == STATUS_STAGE_OUT
+					|| ep->state == STATUS_STAGE_IN) {
+				usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+				status = 0;
+			}
+
+			if (req) {
+				list_del_init(&req->queue);
+				request_complete(ep, req, status);
+			}
+		}
+
+		pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+		DBG(DBG_HW, "Packet length: %u\n", pkt_len);
+		if (pkt_len != sizeof(crq)) {
+			printk(KERN_WARNING "udc: Invalid packet length %u "
+				"(expected %lu)\n", pkt_len, sizeof(crq));
+			set_protocol_stall(udc, ep);
+			return;
+		}
+
+		DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo);
+		copy_from_fifo(crq.data, ep->fifo, sizeof(crq));
+
+		/* Free up one bank in the FIFO so that we can
+		 * generate or receive a reply right away. */
+		usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);
+
+		/* printk(KERN_DEBUG "setup: %d: %02x.%02x\n",
+			ep->state, crq.crq.bRequestType,
+			crq.crq.bRequest); */
+
+		if (crq.crq.bRequestType & USB_DIR_IN) {
+			/*
+			 * The USB 2.0 spec states that "if wLength is
+			 * zero, there is no data transfer phase."
+			 * However, testusb #14 seems to actually
+			 * expect a data phase even if wLength = 0...
+			 */
+			ep->state = DATA_STAGE_IN;
+		} else {
+			if (crq.crq.wLength != __constant_cpu_to_le16(0))
+				ep->state = DATA_STAGE_OUT;
+			else
+				ep->state = STATUS_STAGE_IN;
+		}
+
+		ret = -1;
+		if (ep->index == 0)
+			ret = handle_ep0_setup(udc, ep, &crq.crq);
+		else {
+			spin_unlock(&udc->lock);
+			ret = udc->driver->setup(&udc->gadget, &crq.crq);
+			spin_lock(&udc->lock);
+		}
+
+		DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n",
+			crq.crq.bRequestType, crq.crq.bRequest,
+			le16_to_cpu(crq.crq.wLength), ep->state, ret);
+
+		if (ret < 0) {
+			/* Let the host know that we failed */
+			set_protocol_stall(udc, ep);
+		}
+	}
+}
+
+static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+	struct usba_request *req;
+	u32 epstatus;
+	u32 epctrl;
+
+	epstatus = usba_ep_readl(ep, STA);
+	epctrl = usba_ep_readl(ep, CTL);
+
+	DBG(DBG_INT, "%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus);
+
+	while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+		DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name);
+
+		if (list_empty(&ep->queue)) {
+			dev_warn(&udc->pdev->dev, "ep_irq: queue empty\n");
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+			return;
+		}
+
+		req = list_entry(ep->queue.next, struct usba_request, queue);
+
+		if (req->using_dma) {
+			/* Send a zero-length packet */
+			usba_ep_writel(ep, SET_STA,
+					USBA_TX_PK_RDY);
+			usba_ep_writel(ep, CTL_DIS,
+					USBA_TX_PK_RDY);
+			list_del_init(&req->queue);
+			submit_next_request(ep);
+			request_complete(ep, req, 0);
+		} else {
+			if (req->submitted)
+				next_fifo_transaction(ep, req);
+			else
+				submit_request(ep, req);
+
+			if (req->last_transaction) {
+				list_del_init(&req->queue);
+				submit_next_request(ep);
+				request_complete(ep, req, 0);
+			}
+		}
+
+		epstatus = usba_ep_readl(ep, STA);
+		epctrl = usba_ep_readl(ep, CTL);
+	}
+	if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+		DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name);
+		receive_data(ep);
+		usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+	}
+}
+
+static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+	struct usba_request *req;
+	u32 status, control, pending;
+
+	status = usba_dma_readl(ep, STATUS);
+	control = usba_dma_readl(ep, CONTROL);
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+	ep->last_dma_status = status;
+#endif
+	pending = status & control;
+	DBG(DBG_INT | DBG_DMA, "dma irq, s/%#08x, c/%#08x\n", status, control);
+
+	if (status & USBA_DMA_CH_EN) {
+		dev_err(&udc->pdev->dev,
+			"DMA_CH_EN is set after transfer is finished!\n");
+		dev_err(&udc->pdev->dev,
+			"status=%#08x, pending=%#08x, control=%#08x\n",
+			status, pending, control);
+
+		/*
+		 * try to pretend nothing happened. We might have to
+		 * do something here...
+		 */
+	}
+
+	if (list_empty(&ep->queue))
+		/* Might happen if a reset comes along at the right moment */
+		return;
+
+	if (pending & (USBA_DMA_END_TR_ST | USBA_DMA_END_BUF_ST)) {
+		req = list_entry(ep->queue.next, struct usba_request, queue);
+		usba_update_req(ep, req, status);
+
+		list_del_init(&req->queue);
+		submit_next_request(ep);
+		request_complete(ep, req, 0);
+	}
+}
+
+static irqreturn_t usba_udc_irq(int irq, void *devid)
+{
+	struct usba_udc *udc = devid;
+	u32 status;
+	u32 dma_status;
+	u32 ep_status;
+
+	spin_lock(&udc->lock);
+
+	status = usba_readl(udc, INT_STA);
+	DBG(DBG_INT, "irq, status=%#08x\n", status);
+
+	if (status & USBA_DET_SUSPEND) {
+		usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
+		DBG(DBG_BUS, "Suspend detected\n");
+		if (udc->gadget.speed != USB_SPEED_UNKNOWN
+				&& udc->driver && udc->driver->suspend) {
+			spin_unlock(&udc->lock);
+			udc->driver->suspend(&udc->gadget);
+			spin_lock(&udc->lock);
+		}
+	}
+
+	if (status & USBA_WAKE_UP) {
+		usba_writel(udc, INT_CLR, USBA_WAKE_UP);
+		DBG(DBG_BUS, "Wake Up CPU detected\n");
+	}
+
+	if (status & USBA_END_OF_RESUME) {
+		usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
+		DBG(DBG_BUS, "Resume detected\n");
+		if (udc->gadget.speed != USB_SPEED_UNKNOWN
+				&& udc->driver && udc->driver->resume) {
+			spin_unlock(&udc->lock);
+			udc->driver->resume(&udc->gadget);
+			spin_lock(&udc->lock);
+		}
+	}
+
+	dma_status = USBA_BFEXT(DMA_INT, status);
+	if (dma_status) {
+		int i;
+
+		for (i = 1; i < USBA_NR_ENDPOINTS; i++)
+			if (dma_status & (1 << i))
+				usba_dma_irq(udc, &usba_ep[i]);
+	}
+
+	ep_status = USBA_BFEXT(EPT_INT, status);
+	if (ep_status) {
+		int i;
+
+		for (i = 0; i < USBA_NR_ENDPOINTS; i++)
+			if (ep_status & (1 << i)) {
+				if (ep_is_control(&usba_ep[i]))
+					usba_control_irq(udc, &usba_ep[i]);
+				else
+					usba_ep_irq(udc, &usba_ep[i]);
+			}
+	}
+
+	if (status & USBA_END_OF_RESET) {
+		struct usba_ep *ep0;
+
+		usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
+		reset_all_endpoints(udc);
+
+		if (status & USBA_HIGH_SPEED) {
+			DBG(DBG_BUS, "High-speed bus reset detected\n");
+			udc->gadget.speed = USB_SPEED_HIGH;
+		} else {
+			DBG(DBG_BUS, "Full-speed bus reset detected\n");
+			udc->gadget.speed = USB_SPEED_FULL;
+		}
+
+		ep0 = &usba_ep[0];
+		ep0->desc = &usba_ep0_desc;
+		ep0->state = WAIT_FOR_SETUP;
+		usba_ep_writel(ep0, CFG,
+				(USBA_BF(EPT_SIZE, EP0_EPT_SIZE)
+				| USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL)
+				| USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
+		usba_ep_writel(ep0, CTL_ENB,
+				USBA_EPT_ENABLE | USBA_RX_SETUP);
+		usba_writel(udc, INT_ENB,
+				(usba_readl(udc, INT_ENB)
+				| USBA_BF(EPT_INT, 1)
+				| USBA_DET_SUSPEND
+				| USBA_END_OF_RESUME));
+
+		if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED))
+			dev_warn(&udc->pdev->dev,
+				 "WARNING: EP0 configuration is invalid!\n");
+	}
+
+	spin_unlock(&udc->lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t usba_vbus_irq(int irq, void *devid)
+{
+	struct usba_udc *udc = devid;
+	int vbus;
+
+	/* debounce */
+	udelay(10);
+
+	spin_lock(&udc->lock);
+
+	/* May happen if Vbus pin toggles during probe() */
+	if (!udc->driver)
+		goto out;
+
+	vbus = gpio_get_value(udc->vbus_pin);
+	if (vbus != udc->vbus_prev) {
+		if (vbus) {
+			usba_writel(udc, CTRL, USBA_EN_USBA);
+			usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+		} else {
+			udc->gadget.speed = USB_SPEED_UNKNOWN;
+			reset_all_endpoints(udc);
+			usba_writel(udc, CTRL, 0);
+			spin_unlock(&udc->lock);
+			udc->driver->disconnect(&udc->gadget);
+			spin_lock(&udc->lock);
+		}
+		udc->vbus_prev = vbus;
+	}
+
+out:
+	spin_unlock(&udc->lock);
+
+	return IRQ_HANDLED;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct usba_udc *udc = &the_udc;
+	unsigned long flags;
+	int ret;
+
+	if (!udc->pdev)
+		return -ENODEV;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (udc->driver) {
+		spin_unlock_irqrestore(&udc->lock, flags);
+		return -EBUSY;
+	}
+
+	udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
+	udc->driver = driver;
+	udc->gadget.dev.driver = &driver->driver;
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	clk_enable(udc->pclk);
+	clk_enable(udc->hclk);
+
+	ret = driver->bind(&udc->gadget);
+	if (ret) {
+		DBG(DBG_ERR, "Could not bind to driver %s: error %d\n",
+			driver->driver.name, ret);
+		goto err_driver_bind;
+	}
+
+	DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name);
+
+	udc->vbus_prev = 0;
+	if (udc->vbus_pin != -1)
+		enable_irq(gpio_to_irq(udc->vbus_pin));
+
+	/* If Vbus is present, enable the controller and wait for reset */
+	spin_lock_irqsave(&udc->lock, flags);
+	if (vbus_is_present(udc) && udc->vbus_prev == 0) {
+		usba_writel(udc, CTRL, USBA_EN_USBA);
+		usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+	}
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+
+err_driver_bind:
+	udc->driver = NULL;
+	udc->gadget.dev.driver = NULL;
+	return ret;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct usba_udc *udc = &the_udc;
+	unsigned long flags;
+
+	if (!udc->pdev)
+		return -ENODEV;
+	if (driver != udc->driver)
+		return -EINVAL;
+
+	if (udc->vbus_pin != -1)
+		disable_irq(gpio_to_irq(udc->vbus_pin));
+
+	spin_lock_irqsave(&udc->lock, flags);
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	reset_all_endpoints(udc);
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	/* This will also disable the DP pullup */
+	usba_writel(udc, CTRL, 0);
+
+	driver->unbind(&udc->gadget);
+	udc->gadget.dev.driver = NULL;
+	udc->driver = NULL;
+
+	clk_disable(udc->hclk);
+	clk_disable(udc->pclk);
+
+	DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name);
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+static int __init usba_udc_probe(struct platform_device *pdev)
+{
+	struct usba_platform_data *pdata = pdev->dev.platform_data;
+	struct resource *regs, *fifo;
+	struct clk *pclk, *hclk;
+	struct usba_udc *udc = &the_udc;
+	int irq, ret, i;
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);
+	fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID);
+	if (!regs || !fifo)
+		return -ENXIO;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	pclk = clk_get(&pdev->dev, "pclk");
+	if (IS_ERR(pclk))
+		return PTR_ERR(pclk);
+	hclk = clk_get(&pdev->dev, "hclk");
+	if (IS_ERR(hclk)) {
+		ret = PTR_ERR(hclk);
+		goto err_get_hclk;
+	}
+
+	udc->pdev = pdev;
+	udc->pclk = pclk;
+	udc->hclk = hclk;
+	udc->vbus_pin = -1;
+
+	ret = -ENOMEM;
+	udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+	if (!udc->regs) {
+		dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n");
+		goto err_map_regs;
+	}
+	dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",
+		 (unsigned long)regs->start, udc->regs);
+	udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1);
+	if (!udc->fifo) {
+		dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n");
+		goto err_map_fifo;
+	}
+	dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",
+		 (unsigned long)fifo->start, udc->fifo);
+
+	device_initialize(&udc->gadget.dev);
+	udc->gadget.dev.parent = &pdev->dev;
+	udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+	platform_set_drvdata(pdev, udc);
+
+	/* Make sure we start from a clean slate */
+	clk_enable(pclk);
+	usba_writel(udc, CTRL, 0);
+	clk_disable(pclk);
+
+	INIT_LIST_HEAD(&usba_ep[0].ep.ep_list);
+	usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0);
+	usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0);
+	usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0);
+	for (i = 1; i < ARRAY_SIZE(usba_ep); i++) {
+		struct usba_ep *ep = &usba_ep[i];
+
+		ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+		ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+		ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
+
+		list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+	}
+
+	ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc);
+	if (ret) {
+		dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n",
+			irq, ret);
+		goto err_request_irq;
+	}
+	udc->irq = irq;
+
+	ret = device_add(&udc->gadget.dev);
+	if (ret) {
+		dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret);
+		goto err_device_add;
+	}
+
+	if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) {
+		if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
+			udc->vbus_pin = pdata->vbus_pin;
+
+			ret = request_irq(gpio_to_irq(udc->vbus_pin),
+					usba_vbus_irq, 0,
+					"atmel_usba_udc", udc);
+			if (ret) {
+				gpio_free(udc->vbus_pin);
+				udc->vbus_pin = -1;
+				dev_warn(&udc->pdev->dev,
+					 "failed to request vbus irq; "
+					 "assuming always on\n");
+			} else {
+				disable_irq(gpio_to_irq(udc->vbus_pin));
+			}
+		}
+	}
+
+	usba_init_debugfs(udc);
+	for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
+		usba_ep_init_debugfs(udc, &usba_ep[i]);
+
+	return 0;
+
+err_device_add:
+	free_irq(irq, udc);
+err_request_irq:
+	iounmap(udc->fifo);
+err_map_fifo:
+	iounmap(udc->regs);
+err_map_regs:
+	clk_put(hclk);
+err_get_hclk:
+	clk_put(pclk);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return ret;
+}
+
+static int __exit usba_udc_remove(struct platform_device *pdev)
+{
+	struct usba_udc *udc;
+	int i;
+
+	udc = platform_get_drvdata(pdev);
+
+	for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
+		usba_ep_cleanup_debugfs(&usba_ep[i]);
+	usba_cleanup_debugfs(udc);
+
+	if (udc->vbus_pin != -1)
+		gpio_free(udc->vbus_pin);
+
+	free_irq(udc->irq, udc);
+	iounmap(udc->fifo);
+	iounmap(udc->regs);
+	clk_put(udc->hclk);
+	clk_put(udc->pclk);
+
+	device_unregister(&udc->gadget.dev);
+
+	return 0;
+}
+
+static struct platform_driver udc_driver = {
+	.remove		= __exit_p(usba_udc_remove),
+	.driver		= {
+		.name		= "atmel_usba_udc",
+	},
+};
+
+static int __init udc_init(void)
+{
+	return platform_driver_probe(&udc_driver, usba_udc_probe);
+}
+module_init(udc_init);
+
+static void __exit udc_exit(void)
+{
+	platform_driver_unregister(&udc_driver);
+}
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION("Atmel USBA UDC driver");
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h
new file mode 100644
index 0000000..a68304e
--- /dev/null
+++ b/drivers/usb/gadget/atmel_usba_udc.h
@@ -0,0 +1,352 @@
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ *
+ * Copyright (C) 2005-2007 Atmel 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.
+ */
+#ifndef __LINUX_USB_GADGET_USBA_UDC_H__
+#define __LINUX_USB_GADGET_USBA_UDC_H__
+
+/* USB register offsets */
+#define USBA_CTRL				0x0000
+#define USBA_FNUM				0x0004
+#define USBA_INT_ENB				0x0010
+#define USBA_INT_STA				0x0014
+#define USBA_INT_CLR				0x0018
+#define USBA_EPT_RST				0x001c
+#define USBA_TST				0x00e0
+
+/* USB endpoint register offsets */
+#define USBA_EPT_CFG				0x0000
+#define USBA_EPT_CTL_ENB			0x0004
+#define USBA_EPT_CTL_DIS			0x0008
+#define USBA_EPT_CTL				0x000c
+#define USBA_EPT_SET_STA			0x0014
+#define USBA_EPT_CLR_STA			0x0018
+#define USBA_EPT_STA				0x001c
+
+/* USB DMA register offsets */
+#define USBA_DMA_NXT_DSC			0x0000
+#define USBA_DMA_ADDRESS			0x0004
+#define USBA_DMA_CONTROL			0x0008
+#define USBA_DMA_STATUS				0x000c
+
+/* Bitfields in CTRL */
+#define USBA_DEV_ADDR_OFFSET			0
+#define USBA_DEV_ADDR_SIZE			7
+#define USBA_FADDR_EN				(1 <<  7)
+#define USBA_EN_USBA				(1 <<  8)
+#define USBA_DETACH				(1 <<  9)
+#define USBA_REMOTE_WAKE_UP			(1 << 10)
+
+/* Bitfields in FNUM */
+#define USBA_MICRO_FRAME_NUM_OFFSET		0
+#define USBA_MICRO_FRAME_NUM_SIZE		3
+#define USBA_FRAME_NUMBER_OFFSET		3
+#define USBA_FRAME_NUMBER_SIZE			11
+#define USBA_FRAME_NUM_ERROR			(1 << 31)
+
+/* Bitfields in INT_ENB/INT_STA/INT_CLR */
+#define USBA_HIGH_SPEED				(1 <<  0)
+#define USBA_DET_SUSPEND			(1 <<  1)
+#define USBA_MICRO_SOF				(1 <<  2)
+#define USBA_SOF				(1 <<  3)
+#define USBA_END_OF_RESET			(1 <<  4)
+#define USBA_WAKE_UP				(1 <<  5)
+#define USBA_END_OF_RESUME			(1 <<  6)
+#define USBA_UPSTREAM_RESUME			(1 <<  7)
+#define USBA_EPT_INT_OFFSET			8
+#define USBA_EPT_INT_SIZE			16
+#define USBA_DMA_INT_OFFSET			24
+#define USBA_DMA_INT_SIZE			8
+
+/* Bitfields in EPT_RST */
+#define USBA_RST_OFFSET				0
+#define USBA_RST_SIZE				16
+
+/* Bitfields in USBA_TST */
+#define USBA_SPEED_CFG_OFFSET			0
+#define USBA_SPEED_CFG_SIZE			2
+#define USBA_TST_J_MODE				(1 <<  2)
+#define USBA_TST_K_MODE				(1 <<  3)
+#define USBA_TST_PKT_MODE			(1 <<  4)
+#define USBA_OPMODE2				(1 <<  5)
+
+/* Bitfields in EPT_CFG */
+#define USBA_EPT_SIZE_OFFSET			0
+#define USBA_EPT_SIZE_SIZE			3
+#define USBA_EPT_DIR_IN				(1 <<  3)
+#define USBA_EPT_TYPE_OFFSET			4
+#define USBA_EPT_TYPE_SIZE			2
+#define USBA_BK_NUMBER_OFFSET			6
+#define USBA_BK_NUMBER_SIZE			2
+#define USBA_NB_TRANS_OFFSET			8
+#define USBA_NB_TRANS_SIZE			2
+#define USBA_EPT_MAPPED				(1 << 31)
+
+/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */
+#define USBA_EPT_ENABLE				(1 <<  0)
+#define USBA_AUTO_VALID				(1 <<  1)
+#define USBA_INTDIS_DMA				(1 <<  3)
+#define USBA_NYET_DIS				(1 <<  4)
+#define USBA_DATAX_RX				(1 <<  6)
+#define USBA_MDATA_RX				(1 <<  7)
+/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */
+#define USBA_BUSY_BANK_IE			(1 << 18)
+
+/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */
+#define USBA_FORCE_STALL			(1 <<  5)
+#define USBA_TOGGLE_CLR				(1 <<  6)
+#define USBA_TOGGLE_SEQ_OFFSET			6
+#define USBA_TOGGLE_SEQ_SIZE			2
+#define USBA_ERR_OVFLW				(1 <<  8)
+#define USBA_RX_BK_RDY				(1 <<  9)
+#define USBA_KILL_BANK				(1 <<  9)
+#define USBA_TX_COMPLETE			(1 << 10)
+#define USBA_TX_PK_RDY				(1 << 11)
+#define USBA_ISO_ERR_TRANS			(1 << 11)
+#define USBA_RX_SETUP				(1 << 12)
+#define USBA_ISO_ERR_FLOW			(1 << 12)
+#define USBA_STALL_SENT				(1 << 13)
+#define USBA_ISO_ERR_CRC			(1 << 13)
+#define USBA_ISO_ERR_NBTRANS			(1 << 13)
+#define USBA_NAK_IN				(1 << 14)
+#define USBA_ISO_ERR_FLUSH			(1 << 14)
+#define USBA_NAK_OUT				(1 << 15)
+#define USBA_CURRENT_BANK_OFFSET		16
+#define USBA_CURRENT_BANK_SIZE			2
+#define USBA_BUSY_BANKS_OFFSET			18
+#define USBA_BUSY_BANKS_SIZE			2
+#define USBA_BYTE_COUNT_OFFSET			20
+#define USBA_BYTE_COUNT_SIZE			11
+#define USBA_SHORT_PACKET			(1 << 31)
+
+/* Bitfields in DMA_CONTROL */
+#define USBA_DMA_CH_EN				(1 <<  0)
+#define USBA_DMA_LINK				(1 <<  1)
+#define USBA_DMA_END_TR_EN			(1 <<  2)
+#define USBA_DMA_END_BUF_EN			(1 <<  3)
+#define USBA_DMA_END_TR_IE			(1 <<  4)
+#define USBA_DMA_END_BUF_IE			(1 <<  5)
+#define USBA_DMA_DESC_LOAD_IE			(1 <<  6)
+#define USBA_DMA_BURST_LOCK			(1 <<  7)
+#define USBA_DMA_BUF_LEN_OFFSET			16
+#define USBA_DMA_BUF_LEN_SIZE			16
+
+/* Bitfields in DMA_STATUS */
+#define USBA_DMA_CH_ACTIVE			(1 <<  1)
+#define USBA_DMA_END_TR_ST			(1 <<  4)
+#define USBA_DMA_END_BUF_ST			(1 <<  5)
+#define USBA_DMA_DESC_LOAD_ST			(1 <<  6)
+
+/* Constants for SPEED_CFG */
+#define USBA_SPEED_CFG_NORMAL			0
+#define USBA_SPEED_CFG_FORCE_HIGH		2
+#define USBA_SPEED_CFG_FORCE_FULL		3
+
+/* Constants for EPT_SIZE */
+#define USBA_EPT_SIZE_8				0
+#define USBA_EPT_SIZE_16			1
+#define USBA_EPT_SIZE_32			2
+#define USBA_EPT_SIZE_64			3
+#define USBA_EPT_SIZE_128			4
+#define USBA_EPT_SIZE_256			5
+#define USBA_EPT_SIZE_512			6
+#define USBA_EPT_SIZE_1024			7
+
+/* Constants for EPT_TYPE */
+#define USBA_EPT_TYPE_CONTROL			0
+#define USBA_EPT_TYPE_ISO			1
+#define USBA_EPT_TYPE_BULK			2
+#define USBA_EPT_TYPE_INT			3
+
+/* Constants for BK_NUMBER */
+#define USBA_BK_NUMBER_ZERO			0
+#define USBA_BK_NUMBER_ONE			1
+#define USBA_BK_NUMBER_DOUBLE			2
+#define USBA_BK_NUMBER_TRIPLE			3
+
+/* Bit manipulation macros */
+#define USBA_BF(name, value)					\
+	(((value) & ((1 << USBA_##name##_SIZE) - 1))		\
+	 << USBA_##name##_OFFSET)
+#define USBA_BFEXT(name, value)					\
+	(((value) >> USBA_##name##_OFFSET)			\
+	 & ((1 << USBA_##name##_SIZE) - 1))
+#define USBA_BFINS(name, value, old)				\
+	(((old) & ~(((1 << USBA_##name##_SIZE) - 1)		\
+		    << USBA_##name##_OFFSET))			\
+	 | USBA_BF(name, value))
+
+/* Register access macros */
+#define usba_readl(udc, reg)					\
+	__raw_readl((udc)->regs + USBA_##reg)
+#define usba_writel(udc, reg, value)				\
+	__raw_writel((value), (udc)->regs + USBA_##reg)
+#define usba_ep_readl(ep, reg)					\
+	__raw_readl((ep)->ep_regs + USBA_EPT_##reg)
+#define usba_ep_writel(ep, reg, value)				\
+	__raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg)
+#define usba_dma_readl(ep, reg)					\
+	__raw_readl((ep)->dma_regs + USBA_DMA_##reg)
+#define usba_dma_writel(ep, reg, value)				\
+	__raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg)
+
+/* Calculate base address for a given endpoint or DMA controller */
+#define USBA_EPT_BASE(x)	(0x100 + (x) * 0x20)
+#define USBA_DMA_BASE(x)	(0x300 + (x) * 0x10)
+#define USBA_FIFO_BASE(x)	((x) << 16)
+
+/* Synth parameters */
+#define USBA_NR_ENDPOINTS	7
+
+#define EP0_FIFO_SIZE		64
+#define EP0_EPT_SIZE		USBA_EPT_SIZE_64
+#define EP0_NR_BANKS		1
+
+/*
+ * REVISIT: Try to eliminate this value. Can we rely on req->mapped to
+ * provide this information?
+ */
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+#define FIFO_IOMEM_ID	0
+#define CTRL_IOMEM_ID	1
+
+#ifdef DEBUG
+#define DBG_ERR		0x0001	/* report all error returns */
+#define DBG_HW		0x0002	/* debug hardware initialization */
+#define DBG_GADGET	0x0004	/* calls to/from gadget driver */
+#define DBG_INT		0x0008	/* interrupts */
+#define DBG_BUS		0x0010	/* report changes in bus state */
+#define DBG_QUEUE	0x0020  /* debug request queue processing */
+#define DBG_FIFO	0x0040  /* debug FIFO contents */
+#define DBG_DMA		0x0080  /* debug DMA handling */
+#define DBG_REQ		0x0100	/* print out queued request length */
+#define DBG_ALL		0xffff
+#define DBG_NONE	0x0000
+
+#define DEBUG_LEVEL	(DBG_ERR)
+#define DBG(level, fmt, ...)					\
+	do {							\
+		if ((level) & DEBUG_LEVEL)			\
+			printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__);	\
+	} while (0)
+#else
+#define DBG(level, fmt...)
+#endif
+
+enum usba_ctrl_state {
+	WAIT_FOR_SETUP,
+	DATA_STAGE_IN,
+	DATA_STAGE_OUT,
+	STATUS_STAGE_IN,
+	STATUS_STAGE_OUT,
+	STATUS_STAGE_ADDR,
+	STATUS_STAGE_TEST,
+};
+/*
+  EP_STATE_IDLE,
+  EP_STATE_SETUP,
+  EP_STATE_IN_DATA,
+  EP_STATE_OUT_DATA,
+  EP_STATE_SET_ADDR_STATUS,
+  EP_STATE_RX_STATUS,
+  EP_STATE_TX_STATUS,
+  EP_STATE_HALT,
+*/
+
+struct usba_dma_desc {
+	dma_addr_t next;
+	dma_addr_t addr;
+	u32 ctrl;
+};
+
+struct usba_ep {
+	int					state;
+	void __iomem				*ep_regs;
+	void __iomem				*dma_regs;
+	void __iomem				*fifo;
+	struct usb_ep				ep;
+	struct usba_udc				*udc;
+
+	struct list_head			queue;
+	const struct usb_endpoint_descriptor	*desc;
+
+	u16					fifo_size;
+	u8					nr_banks;
+	u8					index;
+	unsigned int				can_dma:1;
+	unsigned int				can_isoc:1;
+	unsigned int				is_isoc:1;
+	unsigned int				is_in:1;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+	u32					last_dma_status;
+	struct dentry				*debugfs_dir;
+	struct dentry				*debugfs_queue;
+	struct dentry				*debugfs_dma_status;
+	struct dentry				*debugfs_state;
+#endif
+};
+
+struct usba_request {
+	struct usb_request			req;
+	struct list_head			queue;
+
+	u32					ctrl;
+
+	unsigned int				submitted:1;
+	unsigned int				last_transaction:1;
+	unsigned int				using_dma:1;
+	unsigned int				mapped:1;
+};
+
+struct usba_udc {
+	/* Protect hw registers from concurrent modifications */
+	spinlock_t lock;
+
+	void __iomem *regs;
+	void __iomem *fifo;
+
+	struct usb_gadget gadget;
+	struct usb_gadget_driver *driver;
+	struct platform_device *pdev;
+	int irq;
+	int vbus_pin;
+	struct clk *pclk;
+	struct clk *hclk;
+
+	u16 devstatus;
+
+	u16 test_mode;
+	int vbus_prev;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+	struct dentry *debugfs_root;
+	struct dentry *debugfs_regs;
+#endif
+};
+
+static inline struct usba_ep *to_usba_ep(struct usb_ep *ep)
+{
+	return container_of(ep, struct usba_ep, ep);
+}
+
+static inline struct usba_request *to_usba_req(struct usb_request *req)
+{
+	return container_of(req, struct usba_request, req);
+}
+
+static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget)
+{
+	return container_of(gadget, struct usba_udc, gadget);
+}
+
+#define ep_is_control(ep)	((ep)->index == 0)
+#define ep_is_idle(ep)		((ep)->state == EP_STATE_IDLE)
+
+#endif /* __LINUX_USB_GADGET_USBA_UDC_H */
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index d18901b..a4e54b2 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -25,7 +25,7 @@
 #include <linux/device.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 /**
@@ -50,7 +50,7 @@
 		return -EINVAL;
 
 	/* fill buffer from src[] until null descriptor ptr */
-	for (; 0 != *src; src++) {
+	for (; NULL != *src; src++) {
 		unsigned		len = (*src)->bLength;
 
 		if (len > buflen)
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index f2fbdc7..9db2482 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -34,8 +34,6 @@
  * bypassing some hardware (and driver) issues.  UML could help too.
  */
 
-#define DEBUG
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
@@ -48,7 +46,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/usb.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -964,13 +962,13 @@
 
 static int dummy_urb_enqueue (
 	struct usb_hcd			*hcd,
-	struct usb_host_endpoint	*ep,
 	struct urb			*urb,
 	gfp_t				mem_flags
 ) {
 	struct dummy	*dum;
 	struct urbp	*urbp;
 	unsigned long	flags;
+	int		rc;
 
 	if (!urb->transfer_buffer && urb->transfer_buffer_length)
 		return -EINVAL;
@@ -982,6 +980,11 @@
 
 	dum = hcd_to_dummy (hcd);
 	spin_lock_irqsave (&dum->lock, flags);
+	rc = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (rc) {
+		kfree(urbp);
+		goto done;
+	}
 
 	if (!dum->udev) {
 		dum->udev = urb->dev;
@@ -998,36 +1001,35 @@
 	if (!timer_pending (&dum->timer))
 		mod_timer (&dum->timer, jiffies + 1);
 
-	spin_unlock_irqrestore (&dum->lock, flags);
-	return 0;
+ done:
+	spin_unlock_irqrestore(&dum->lock, flags);
+	return rc;
 }
 
-static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	struct dummy	*dum;
 	unsigned long	flags;
+	int		rc;
 
 	/* giveback happens automatically in timer callback,
 	 * so make sure the callback happens */
 	dum = hcd_to_dummy (hcd);
 	spin_lock_irqsave (&dum->lock, flags);
-	if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list))
-		mod_timer (&dum->timer, jiffies);
-	spin_unlock_irqrestore (&dum->lock, flags);
-	return 0;
-}
 
-static void maybe_set_status (struct urb *urb, int status)
-{
-	spin_lock (&urb->lock);
-	if (urb->status == -EINPROGRESS)
-		urb->status = status;
-	spin_unlock (&urb->lock);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (!rc && dum->rh_state != DUMMY_RH_RUNNING &&
+			!list_empty(&dum->urbp_list))
+		mod_timer (&dum->timer, jiffies);
+
+	spin_unlock_irqrestore (&dum->lock, flags);
+	return rc;
 }
 
 /* transfer up to a frame's worth; caller must own lock */
 static int
-transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit)
+transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
+		int *status)
 {
 	struct dummy_request	*req;
 
@@ -1090,24 +1092,20 @@
 		 *
 		 * partially filling a buffer optionally blocks queue advances
 		 * (so completion handlers can clean up the queue) but we don't
-		 * need to emulate such data-in-flight.  so we only show part
-		 * of the URB_SHORT_NOT_OK effect: completion status.
+		 * need to emulate such data-in-flight.
 		 */
 		if (is_short) {
 			if (host_len == dev_len) {
 				req->req.status = 0;
-				maybe_set_status (urb, 0);
+				*status = 0;
 			} else if (to_host) {
 				req->req.status = 0;
 				if (dev_len > host_len)
-					maybe_set_status (urb, -EOVERFLOW);
+					*status = -EOVERFLOW;
 				else
-					maybe_set_status (urb,
-						(urb->transfer_flags
-							& URB_SHORT_NOT_OK)
-						? -EREMOTEIO : 0);
+					*status = 0;
 			} else if (!to_host) {
-				maybe_set_status (urb, 0);
+				*status = 0;
 				if (host_len > dev_len)
 					req->req.status = -EOVERFLOW;
 				else
@@ -1121,9 +1119,8 @@
 				req->req.status = 0;
 			if (urb->transfer_buffer_length == urb->actual_length
 					&& !(urb->transfer_flags
-						& URB_ZERO_PACKET)) {
-				maybe_set_status (urb, 0);
-			}
+						& URB_ZERO_PACKET))
+				*status = 0;
 		}
 
 		/* device side completion --> continuable */
@@ -1139,7 +1136,7 @@
 		}
 
 		/* host side completion --> terminate */
-		if (urb->status != -EINPROGRESS)
+		if (*status != -EINPROGRESS)
 			break;
 
 		/* rescan to continue with any other queued i/o */
@@ -1250,12 +1247,12 @@
 		u8			address;
 		struct dummy_ep		*ep = NULL;
 		int			type;
+		int			status = -EINPROGRESS;
 
 		urb = urbp->urb;
-		if (urb->status != -EINPROGRESS) {
-			/* likely it was just unlinked */
+		if (urb->unlinked)
 			goto return_urb;
-		} else if (dum->rh_state != DUMMY_RH_RUNNING)
+		else if (dum->rh_state != DUMMY_RH_RUNNING)
 			continue;
 		type = usb_pipetype (urb->pipe);
 
@@ -1276,7 +1273,7 @@
 			dev_dbg (dummy_dev(dum),
 				"no ep configured for urb %p\n",
 				urb);
-			maybe_set_status (urb, -EPROTO);
+			status = -EPROTO;
 			goto return_urb;
 		}
 
@@ -1291,7 +1288,7 @@
 			/* NOTE: must not be iso! */
 			dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
 					ep->ep.name, urb);
-			maybe_set_status (urb, -EPIPE);
+			status = -EPIPE;
 			goto return_urb;
 		}
 		/* FIXME make sure both ends agree on maxpacket */
@@ -1309,7 +1306,7 @@
 			w_value = le16_to_cpu(setup.wValue);
 			if (le16_to_cpu(setup.wLength) !=
 					urb->transfer_buffer_length) {
-				maybe_set_status (urb, -EOVERFLOW);
+				status = -EOVERFLOW;
 				goto return_urb;
 			}
 
@@ -1339,7 +1336,7 @@
 				if (setup.bRequestType != Dev_Request)
 					break;
 				dum->address = w_value;
-				maybe_set_status (urb, 0);
+				status = 0;
 				dev_dbg (udc_dev(dum), "set_address = %d\n",
 						w_value);
 				value = 0;
@@ -1366,7 +1363,7 @@
 					if (value == 0) {
 						dum->devstatus |=
 							(1 << w_value);
-						maybe_set_status (urb, 0);
+						status = 0;
 					}
 
 				} else if (setup.bRequestType == Ep_Request) {
@@ -1378,7 +1375,7 @@
 					}
 					ep2->halted = 1;
 					value = 0;
-					maybe_set_status (urb, 0);
+					status = 0;
 				}
 				break;
 			case USB_REQ_CLEAR_FEATURE:
@@ -1388,7 +1385,7 @@
 						dum->devstatus &= ~(1 <<
 							USB_DEVICE_REMOTE_WAKEUP);
 						value = 0;
-						maybe_set_status (urb, 0);
+						status = 0;
 						break;
 					default:
 						value = -EOPNOTSUPP;
@@ -1403,7 +1400,7 @@
 					}
 					ep2->halted = 0;
 					value = 0;
-					maybe_set_status (urb, 0);
+					status = 0;
 				}
 				break;
 			case USB_REQ_GET_STATUS:
@@ -1440,7 +1437,7 @@
 					urb->actual_length = min (2,
 						urb->transfer_buffer_length);
 					value = 0;
-					maybe_set_status (urb, 0);
+					status = 0;
 				}
 				break;
 			}
@@ -1467,7 +1464,7 @@
 					dev_dbg (udc_dev(dum),
 						"setup --> %d\n",
 						value);
-				maybe_set_status (urb, -EPIPE);
+				status = -EPIPE;
 				urb->actual_length = 0;
 			}
 
@@ -1484,7 +1481,7 @@
 			 * report random errors, to debug drivers.
 			 */
 			limit = max (limit, periodic_bytes (dum, ep));
-			maybe_set_status (urb, -ENOSYS);
+			status = -ENOSYS;
 			break;
 
 		case PIPE_INTERRUPT:
@@ -1498,23 +1495,23 @@
 		default:
 		treat_control_like_bulk:
 			ep->last_io = jiffies;
-			total = transfer (dum, urb, ep, limit);
+			total = transfer(dum, urb, ep, limit, &status);
 			break;
 		}
 
 		/* incomplete transfer? */
-		if (urb->status == -EINPROGRESS)
+		if (status == -EINPROGRESS)
 			continue;
 
 return_urb:
-		urb->hcpriv = NULL;
 		list_del (&urbp->urbp_list);
 		kfree (urbp);
 		if (ep)
 			ep->already_seen = ep->setup_stage = 0;
 
+		usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb);
 		spin_unlock (&dum->lock);
-		usb_hcd_giveback_urb (dummy_to_hcd(dum), urb);
+		usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status);
 		spin_lock (&dum->lock);
 
 		goto restart;
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 6042364..f9d0710 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -28,7 +28,7 @@
 #include <linux/string.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
@@ -71,7 +71,7 @@
 	u16		max;
 
 	/* endpoint already claimed? */
-	if (0 != ep->driver_data)
+	if (NULL != ep->driver_data)
 		return 0;
 
 	/* only support ep0 for portable CONTROL traffic */
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index dbaf867..9e732bf 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -19,40 +19,18 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+/* #define VERBOSE_DEBUG */
 
-// #define DEBUG 1
-// #define VERBOSE
-
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/utsname.h>
 #include <linux/device.h>
-#include <linux/moduleparam.h>
 #include <linux/ctype.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/unaligned.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
-#include <linux/usb_gadget.h>
-
-#include <linux/random.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
@@ -305,6 +283,10 @@
 #define DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define	DEV_CONFIG_CDC
+#endif
+
 
 /*-------------------------------------------------------------------------*/
 
@@ -352,15 +334,15 @@
 #define qlen(gadget) \
 	(DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1))
 
-/* also defer IRQs on highspeed TX */
-#define TX_DELAY	qmult
-
 static inline int BITRATE(struct usb_gadget *g)
 {
 	return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;
 }
 
 #else	/* full speed (low speed doesn't do bulk) */
+
+#define qmult		1
+
 #define	DEVSPEED	USB_SPEED_FULL
 
 #define qlen(gadget) DEFAULT_QLEN
@@ -386,7 +368,7 @@
 	do { } while (0)
 #endif /* DEBUG */
 
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
 #define VDEBUG	DEBUG
 #else
 #define VDEBUG(dev,fmt,args...) \
@@ -826,8 +808,6 @@
 };
 #endif
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-
 /*
  * usb 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -930,18 +910,15 @@
 
 
 /* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
-
-#else
-
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) (((void)(g)), (fs))
-
-static inline void __init hs_subset_descriptors(void)
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+		struct usb_endpoint_descriptor *fs)
 {
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
 }
 
-#endif	/* !CONFIG_USB_GADGET_DUALSPEED */
 
 /*-------------------------------------------------------------------------*/
 
@@ -985,22 +962,19 @@
  * complications: class descriptors, and an altsetting.
  */
 static int
-config_buf (enum usb_device_speed speed,
-	u8 *buf, u8 type,
-	unsigned index, int is_otg)
+config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg)
 {
 	int					len;
 	const struct usb_config_descriptor	*config;
 	const struct usb_descriptor_header	**function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	int				hs = (speed == USB_SPEED_HIGH);
+	int					hs = 0;
 
-	if (type == USB_DT_OTHER_SPEED_CONFIG)
-		hs = !hs;
+	if (gadget_is_dualspeed(g)) {
+		hs = (g->speed == USB_SPEED_HIGH);
+		if (type == USB_DT_OTHER_SPEED_CONFIG)
+			hs = !hs;
+	}
 #define which_fn(t)	(hs ? hs_ ## t ## _function : fs_ ## t ## _function)
-#else
-#define	which_fn(t)	(fs_ ## t ## _function)
-#endif
 
 	if (index >= device_desc.bNumConfigurations)
 		return -EINVAL;
@@ -1213,7 +1187,7 @@
 		if (number)
 			eth_reset_config (dev);
 		usb_gadget_vbus_draw(dev->gadget,
-				dev->gadget->is_otg ? 8 : 100);
+				gadget_is_otg(dev->gadget) ? 8 : 100);
 	} else {
 		char *speed;
 		unsigned power;
@@ -1395,24 +1369,22 @@
 			value = min (wLength, (u16) sizeof device_desc);
 			memcpy (req->buf, &device_desc, value);
 			break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			value = min (wLength, (u16) sizeof dev_qualifier);
 			memcpy (req->buf, &dev_qualifier, value);
 			break;
 
 		case USB_DT_OTHER_SPEED_CONFIG:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			// FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
 		case USB_DT_CONFIG:
-			value = config_buf (gadget->speed, req->buf,
+			value = config_buf(gadget, req->buf,
 					wValue >> 8,
 					wValue & 0xff,
-					gadget->is_otg);
+					gadget_is_otg(gadget));
 			if (value >= 0)
 				value = min (wLength, (u16) value);
 			break;
@@ -1581,12 +1553,12 @@
 				&& rndis_control_intf.bInterfaceNumber
 					== wIndex) {
 			u8 *buf;
+			u32 n;
 
 			/* return the result */
-			buf = rndis_get_next_response (dev->rndis_config,
-						       &value);
+			buf = rndis_get_next_response(dev->rndis_config, &n);
 			if (buf) {
-				memcpy (req->buf, buf, value);
+				memcpy(req->buf, buf, n);
 				req->complete = rndis_response_complete;
 				rndis_free_response(dev->rndis_config, buf);
 			}
@@ -1719,7 +1691,8 @@
 		size += sizeof (struct rndis_packet_msg_type);
 	size -= size % dev->out_ep->maxpacket;
 
-	if ((skb = alloc_skb (size + NET_IP_ALIGN, gfp_flags)) == 0) {
+	skb = alloc_skb(size + NET_IP_ALIGN, gfp_flags);
+	if (skb == NULL) {
 		DEBUG (dev, "no rx skb\n");
 		goto enomem;
 	}
@@ -1984,8 +1957,20 @@
 	}
 
 	spin_lock_irqsave(&dev->req_lock, flags);
+	/*
+	 * this freelist can be empty if an interrupt triggered disconnect()
+	 * and reconfigured the gadget (shutting down this queue) after the
+	 * network stack decided to xmit but before we got the spinlock.
+	 */
+	if (list_empty(&dev->tx_reqs)) {
+		spin_unlock_irqrestore(&dev->req_lock, flags);
+		return 1;
+	}
+
 	req = container_of (dev->tx_reqs.next, struct usb_request, list);
 	list_del (&req->list);
+
+	/* temporarily stop TX queue when the freelist empties */
 	if (list_empty (&dev->tx_reqs))
 		netif_stop_queue (net);
 	spin_unlock_irqrestore(&dev->req_lock, flags);
@@ -2021,12 +2006,11 @@
 
 	req->length = length;
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
 	/* throttle highspeed IRQ rate back slightly */
-	req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
-		? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0)
-		: 0;
-#endif
+	if (gadget_is_dualspeed(dev->gadget))
+		req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
+			? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
+			: 0;
 
 	retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
 	switch (retval) {
@@ -2183,8 +2167,7 @@
 	}
 
 	if (rndis_active(dev)) {
-		rndis_set_param_medium (dev->rndis_config,
-					NDIS_MEDIUM_802_3, 0);
+		rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0);
 		(void) rndis_signal_disconnect (dev->rndis_config);
 	}
 
@@ -2438,26 +2421,28 @@
 	if (rndis)
 		device_desc.bNumConfigurations = 2;
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-	if (rndis)
-		dev_qualifier.bNumConfigurations = 2;
-	else if (!cdc)
-		dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+	if (gadget_is_dualspeed(gadget)) {
+		if (rndis)
+			dev_qualifier.bNumConfigurations = 2;
+		else if (!cdc)
+			dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
 
-	/* assumes ep0 uses the same value for both speeds ... */
-	dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+		/* assumes ep0 uses the same value for both speeds ... */
+		dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
 
-	/* and that all endpoints are dual-speed */
-	hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
-	hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
+		/* and that all endpoints are dual-speed */
+		hs_source_desc.bEndpointAddress =
+				fs_source_desc.bEndpointAddress;
+		hs_sink_desc.bEndpointAddress =
+				fs_sink_desc.bEndpointAddress;
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-	if (status_ep)
-		hs_status_desc.bEndpointAddress =
-				fs_status_desc.bEndpointAddress;
+		if (status_ep)
+			hs_status_desc.bEndpointAddress =
+					fs_status_desc.bEndpointAddress;
 #endif
-#endif	/* DUALSPEED */
+	}
 
-	if (gadget->is_otg) {
+	if (gadget_is_otg(gadget)) {
 		otg_descriptor.bmAttributes |= USB_OTG_HNP,
 		eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		eth_config.bMaxPower = 4;
@@ -2479,7 +2464,6 @@
 
 	/* network device setup */
 	dev->net = net;
-	SET_MODULE_OWNER (net);
 	strcpy (net->name, "usb%d");
 	dev->cdc = cdc;
 	dev->zlp = zlp;
@@ -2594,12 +2578,11 @@
 		if (rndis_set_param_dev (dev->rndis_config, dev->net,
 					 &dev->stats, &dev->cdc_filter))
 			goto fail0;
-		if (rndis_set_param_vendor (dev->rndis_config, vendorID,
-					    manufacturer))
+		if (rndis_set_param_vendor(dev->rndis_config, vendorID,
+					manufacturer))
 			goto fail0;
-		if (rndis_set_param_medium (dev->rndis_config,
-					    NDIS_MEDIUM_802_3,
-					    0))
+		if (rndis_set_param_medium(dev->rndis_config,
+					NDIS_MEDIUM_802_3, 0))
 			goto fail0;
 		INFO (dev, "RNDIS ready\n");
 	}
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index be7a1bd..73726c5 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -1,7 +1,7 @@
 /*
  * file_storage.c -- File-backed USB Storage Gadget, for USB development
  *
- * Copyright (C) 2003-2005 Alan Stern
+ * Copyright (C) 2003-2007 Alan Stern
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -217,17 +217,11 @@
  */
 
 
-#undef DEBUG
-#undef VERBOSE
-#undef DUMP_MSGS
+/* #define VERBOSE_DEBUG */
+/* #define DUMP_MSGS */
 
 
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#include <linux/bitops.h>
 #include <linux/blkdev.h>
-#include <linux/compiler.h>
 #include <linux/completion.h>
 #include <linux/dcache.h>
 #include <linux/delay.h>
@@ -235,18 +229,10 @@
 #include <linux/fcntl.h>
 #include <linux/file.h>
 #include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
 #include <linux/kref.h>
 #include <linux/kthread.h>
 #include <linux/limits.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/pagemap.h>
 #include <linux/rwsem.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
@@ -254,7 +240,7 @@
 #include <linux/utsname.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
@@ -263,7 +249,7 @@
 
 #define DRIVER_DESC		"File-backed Storage Gadget"
 #define DRIVER_NAME		"g_file_storage"
-#define DRIVER_VERSION		"28 November 2005"
+#define DRIVER_VERSION		"7 August 2007"
 
 static const char longname[] = DRIVER_DESC;
 static const char shortname[] = DRIVER_NAME;
@@ -289,57 +275,48 @@
 
 /*-------------------------------------------------------------------------*/
 
-#define xprintk(f,level,fmt,args...) \
-	dev_printk(level , &(f)->gadget->dev , fmt , ## args)
-#define yprintk(l,level,fmt,args...) \
-	dev_printk(level , &(l)->dev , fmt , ## args)
-
 #ifdef DEBUG
-#define DBG(fsg,fmt,args...) \
-	xprintk(fsg , KERN_DEBUG , fmt , ## args)
 #define LDBG(lun,fmt,args...) \
-	yprintk(lun , KERN_DEBUG , fmt , ## args)
+	dev_dbg(&(lun)->dev , fmt , ## args)
 #define MDBG(fmt,args...) \
 	printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args)
 #else
-#define DBG(fsg,fmt,args...) \
-	do { } while (0)
 #define LDBG(lun,fmt,args...) \
 	do { } while (0)
 #define MDBG(fmt,args...) \
 	do { } while (0)
-#undef VERBOSE
+#undef VERBOSE_DEBUG
 #undef DUMP_MSGS
 #endif /* DEBUG */
 
-#ifdef VERBOSE
-#define VDBG	DBG
+#ifdef VERBOSE_DEBUG
 #define VLDBG	LDBG
 #else
-#define VDBG(fsg,fmt,args...) \
-	do { } while (0)
 #define VLDBG(lun,fmt,args...) \
 	do { } while (0)
-#endif /* VERBOSE */
+#endif /* VERBOSE_DEBUG */
 
-#define ERROR(fsg,fmt,args...) \
-	xprintk(fsg , KERN_ERR , fmt , ## args)
 #define LERROR(lun,fmt,args...) \
-	yprintk(lun , KERN_ERR , fmt , ## args)
-
-#define WARN(fsg,fmt,args...) \
-	xprintk(fsg , KERN_WARNING , fmt , ## args)
+	dev_err(&(lun)->dev , fmt , ## args)
 #define LWARN(lun,fmt,args...) \
-	yprintk(lun , KERN_WARNING , fmt , ## args)
-
-#define INFO(fsg,fmt,args...) \
-	xprintk(fsg , KERN_INFO , fmt , ## args)
+	dev_warn(&(lun)->dev , fmt , ## args)
 #define LINFO(lun,fmt,args...) \
-	yprintk(lun , KERN_INFO , fmt , ## args)
+	dev_info(&(lun)->dev , fmt , ## args)
 
 #define MINFO(fmt,args...) \
 	printk(KERN_INFO DRIVER_NAME ": " fmt , ## args)
 
+#define DBG(d, fmt, args...) \
+	dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+	dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+	dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+	dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+	dev_info(&(d)->gadget->dev , fmt , ## args)
+
 
 /*-------------------------------------------------------------------------*/
 
@@ -350,8 +327,8 @@
 static struct {
 	char		*file[MAX_LUNS];
 	int		ro[MAX_LUNS];
-	int		num_filenames;
-	int		num_ros;
+	unsigned int	num_filenames;
+	unsigned int	num_ros;
 	unsigned int	nluns;
 
 	int		removable;
@@ -578,7 +555,7 @@
 
 #define backing_file_is_open(curlun)	((curlun)->filp != NULL)
 
-static inline struct lun *dev_to_lun(struct device *dev)
+static struct lun *dev_to_lun(struct device *dev)
 {
 	return container_of(dev, struct lun, dev);
 }
@@ -599,7 +576,6 @@
 
 struct fsg_buffhd {
 	void				*buf;
-	dma_addr_t			dma;
 	enum fsg_buffer_state		state;
 	struct fsg_buffhd		*next;
 
@@ -712,13 +688,13 @@
 
 typedef void (*fsg_routine_t)(struct fsg_dev *);
 
-static int inline exception_in_progress(struct fsg_dev *fsg)
+static int exception_in_progress(struct fsg_dev *fsg)
 {
 	return (fsg->state > FSG_STATE_IDLE);
 }
 
 /* Make bulk-out requests be divisible by the maxpacket size */
-static void inline set_bulk_out_req_length(struct fsg_dev *fsg,
+static void set_bulk_out_req_length(struct fsg_dev *fsg,
 		struct fsg_buffhd *bh, unsigned int length)
 {
 	unsigned int	rem;
@@ -744,50 +720,36 @@
 static void dump_msg(struct fsg_dev *fsg, const char *label,
 		const u8 *buf, unsigned int length)
 {
-	unsigned int	start, num, i;
-	char		line[52], *p;
-
-	if (length >= 512)
-		return;
-	DBG(fsg, "%s, length %u:\n", label, length);
-
-	start = 0;
-	while (length > 0) {
-		num = min(length, 16u);
-		p = line;
-		for (i = 0; i < num; ++i) {
-			if (i == 8)
-				*p++ = ' ';
-			sprintf(p, " %02x", buf[i]);
-			p += 3;
-		}
-		*p = 0;
-		printk(KERN_DEBUG "%6x: %s\n", start, line);
-		buf += num;
-		start += num;
-		length -= num;
+	if (length < 512) {
+		DBG(fsg, "%s, length %u:\n", label, length);
+		print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,
+				16, 1, buf, length, 0);
 	}
 }
 
-static void inline dump_cdb(struct fsg_dev *fsg)
+static void dump_cdb(struct fsg_dev *fsg)
 {}
 
 #else
 
-static void inline dump_msg(struct fsg_dev *fsg, const char *label,
+static void dump_msg(struct fsg_dev *fsg, const char *label,
 		const u8 *buf, unsigned int length)
 {}
 
-static void inline dump_cdb(struct fsg_dev *fsg)
-{
-	int	i;
-	char	cmdbuf[3*MAX_COMMAND_SIZE + 1];
+#ifdef VERBOSE_DEBUG
 
-	for (i = 0; i < fsg->cmnd_size; ++i)
-		sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]);
-	VDBG(fsg, "SCSI CDB: %s\n", cmdbuf);
+static void dump_cdb(struct fsg_dev *fsg)
+{
+	print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,
+			16, 1, fsg->cmnd, fsg->cmnd_size, 0);
 }
 
+#else
+
+static void dump_cdb(struct fsg_dev *fsg)
+{}
+
+#endif /* VERBOSE_DEBUG */
 #endif /* DUMP_MSGS */
 
 
@@ -810,24 +772,24 @@
 
 /* Routines for unaligned data access */
 
-static u16 inline get_be16(u8 *buf)
+static u16 get_be16(u8 *buf)
 {
 	return ((u16) buf[0] << 8) | ((u16) buf[1]);
 }
 
-static u32 inline get_be32(u8 *buf)
+static u32 get_be32(u8 *buf)
 {
 	return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) |
 			((u32) buf[2] << 8) | ((u32) buf[3]);
 }
 
-static void inline put_be16(u8 *buf, u16 val)
+static void put_be16(u8 *buf, u16 val)
 {
 	buf[0] = val >> 8;
 	buf[1] = val;
 }
 
-static void inline put_be32(u8 *buf, u32 val)
+static void put_be32(u8 *buf, u32 val)
 {
 	buf[0] = val >> 24;
 	buf[1] = val >> 16;
@@ -951,8 +913,6 @@
 #define FS_FUNCTION_PRE_EP_ENTRIES	2
 
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-
 /*
  * USB 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -1015,14 +975,14 @@
 #define HS_FUNCTION_PRE_EP_ENTRIES	2
 
 /* Maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,fs,hs)	(((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs))
-
-#else
-
-/* If there's no high speed support, always use the full-speed descriptor. */
-#define ep_desc(g,fs,hs)	fs
-
-#endif	/* !CONFIG_USB_GADGET_DUALSPEED */
+static struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
+		struct usb_endpoint_descriptor *hs)
+{
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
+}
 
 
 /* The CBI specification limits the serial string to 12 uppercase hexadecimal
@@ -1054,26 +1014,22 @@
 static int populate_config_buf(struct usb_gadget *gadget,
 		u8 *buf, u8 type, unsigned index)
 {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 	enum usb_device_speed			speed = gadget->speed;
-#endif
 	int					len;
 	const struct usb_descriptor_header	**function;
 
 	if (index > 0)
 		return -EINVAL;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	if (type == USB_DT_OTHER_SPEED_CONFIG)
+	if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
 		speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
-	if (speed == USB_SPEED_HIGH)
+	if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH)
 		function = hs_function;
 	else
-#endif
 		function = fs_function;
 
 	/* for now, don't advertise srp-only devices */
-	if (!gadget->is_otg)
+	if (!gadget_is_otg(gadget))
 		function++;
 
 	len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
@@ -1295,6 +1251,7 @@
 	struct usb_request	*req = fsg->ep0req;
 	int			value = -EOPNOTSUPP;
 	u16			w_index = le16_to_cpu(ctrl->wIndex);
+	u16                     w_value = le16_to_cpu(ctrl->wValue);
 	u16			w_length = le16_to_cpu(ctrl->wLength);
 
 	if (!fsg->config)
@@ -1308,7 +1265,7 @@
 			if (ctrl->bRequestType != (USB_DIR_OUT |
 					USB_TYPE_CLASS | USB_RECIP_INTERFACE))
 				break;
-			if (w_index != 0) {
+			if (w_index != 0 || w_value != 0) {
 				value = -EDOM;
 				break;
 			}
@@ -1324,7 +1281,7 @@
 			if (ctrl->bRequestType != (USB_DIR_IN |
 					USB_TYPE_CLASS | USB_RECIP_INTERFACE))
 				break;
-			if (w_index != 0) {
+			if (w_index != 0 || w_value != 0) {
 				value = -EDOM;
 				break;
 			}
@@ -1343,7 +1300,7 @@
 			if (ctrl->bRequestType != (USB_DIR_OUT |
 					USB_TYPE_CLASS | USB_RECIP_INTERFACE))
 				break;
-			if (w_index != 0) {
+			if (w_index != 0 || w_value != 0) {
 				value = -EDOM;
 				break;
 			}
@@ -1394,10 +1351,9 @@
 			value = sizeof device_desc;
 			memcpy(req->buf, &device_desc, value);
 			break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
 			VDBG(fsg, "get device qualifier\n");
-			if (!fsg->gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(fsg->gadget))
 				break;
 			value = sizeof dev_qualifier;
 			memcpy(req->buf, &dev_qualifier, value);
@@ -1405,15 +1361,12 @@
 
 		case USB_DT_OTHER_SPEED_CONFIG:
 			VDBG(fsg, "get other-speed config descriptor\n");
-			if (!fsg->gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(fsg->gadget))
 				break;
 			goto get_config;
-#endif
 		case USB_DT_CONFIG:
 			VDBG(fsg, "get configuration descriptor\n");
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-		get_config:
-#endif
+get_config:
 			value = populate_config_buf(fsg->gadget,
 					req->buf,
 					w_value >> 8,
@@ -1646,7 +1599,8 @@
 		/* Wait for the next buffer to become available */
 		bh = fsg->next_buffhd_to_fill;
 		while (bh->state != BUF_STATE_EMPTY) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
 		}
 
@@ -1885,7 +1839,8 @@
 		}
 
 		/* Wait for something to happen */
-		if ((rc = sleep_thread(fsg)) != 0)
+		rc = sleep_thread(fsg);
+		if (rc)
 			return rc;
 	}
 
@@ -2369,7 +2324,8 @@
 
 		/* Wait for the next buffer to be free */
 		while (bh->state != BUF_STATE_EMPTY) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
 		}
 
@@ -2429,7 +2385,8 @@
 		}
 
 		/* Otherwise wait for something to happen */
-		if ((rc = sleep_thread(fsg)) != 0)
+		rc = sleep_thread(fsg);
+		if (rc)
 			return rc;
 	}
 	return 0;
@@ -2551,7 +2508,8 @@
 	/* Wait for the next buffer to become available */
 	bh = fsg->next_buffhd_to_fill;
 	while (bh->state != BUF_STATE_EMPTY) {
-		if ((rc = sleep_thread(fsg)) != 0)
+		rc = sleep_thread(fsg);
+		if (rc)
 			return rc;
 	}
 
@@ -2611,7 +2569,6 @@
 
 		fsg->intr_buffhd = bh;		// Point to the right buffhd
 		fsg->intreq->buf = bh->inreq->buf;
-		fsg->intreq->dma = bh->inreq->dma;
 		fsg->intreq->context = bh;
 		start_transfer(fsg, fsg->intr_in, fsg->intreq,
 				&fsg->intreq_busy, &bh->state);
@@ -2772,9 +2729,10 @@
 	/* Wait for the next buffer to become available for data or status */
 	bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
 	while (bh->state != BUF_STATE_EMPTY) {
-		if ((rc = sleep_thread(fsg)) != 0)
+		rc = sleep_thread(fsg);
+		if (rc)
 			return rc;
-		}
+	}
 	fsg->phase_error = 0;
 	fsg->short_packet_received = 0;
 
@@ -3006,7 +2964,7 @@
 
 	/* Is the CBW meaningful? */
 	if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
-			cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) {
+			cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
 		DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
 				"cmdlen %u\n",
 				cbw->Lun, cbw->Flags, cbw->Length);
@@ -3046,9 +3004,10 @@
 		/* Wait for the next buffer to become available */
 		bh = fsg->next_buffhd_to_fill;
 		while (bh->state != BUF_STATE_EMPTY) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
-			}
+		}
 
 		/* Queue a request to read a Bulk-only CBW */
 		set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
@@ -3062,9 +3021,10 @@
 
 		/* Wait for the CBW to arrive */
 		while (bh->state != BUF_STATE_FULL) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
-			}
+		}
 		smp_rmb();
 		rc = received_cbw(fsg, bh);
 		bh->state = BUF_STATE_EMPTY;
@@ -3073,9 +3033,10 @@
 
 		/* Wait for the next command to arrive */
 		while (fsg->cbbuf_cmnd_size == 0) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
-			}
+		}
 
 		/* Is the previous status interrupt request still busy?
 		 * The host is allowed to skip reading the status,
@@ -3200,7 +3161,6 @@
 		if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0)
 			goto reset;
 		bh->inreq->buf = bh->outreq->buf = bh->buf;
-		bh->inreq->dma = bh->outreq->dma = bh->dma;
 		bh->inreq->context = bh->outreq->context = bh;
 		bh->inreq->complete = bulk_in_complete;
 		bh->outreq->complete = bulk_out_complete;
@@ -3597,7 +3557,8 @@
 	return sprintf(buf, "%d\n", curlun->ro);
 }
 
-static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_file(struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
 	struct lun	*curlun = dev_to_lun(dev);
 	struct fsg_dev	*fsg = dev_get_drvdata(dev);
@@ -3606,8 +3567,8 @@
 
 	down_read(&fsg->filesem);
 	if (backing_file_is_open(curlun)) {	// Get the complete pathname
-		p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt,
-				buf, PAGE_SIZE - 1);
+		p = d_path(curlun->filp->f_path.dentry,
+				curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1);
 		if (IS_ERR(p))
 			rc = PTR_ERR(p);
 		else {
@@ -3625,7 +3586,8 @@
 }
 
 
-static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_ro(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
 {
 	ssize_t		rc = count;
 	struct lun	*curlun = dev_to_lun(dev);
@@ -3649,7 +3611,8 @@
 	return rc;
 }
 
-static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_file(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
 {
 	struct lun	*curlun = dev_to_lun(dev);
 	struct fsg_dev	*fsg = dev_get_drvdata(dev);
@@ -3861,7 +3824,7 @@
 	/* Find out how many LUNs there should be */
 	i = mod_data.nluns;
 	if (i == 0)
-		i = max(mod_data.num_filenames, 1);
+		i = max(mod_data.num_filenames, 1u);
 	if (i > MAX_LUNS) {
 		ERROR(fsg, "invalid number of LUNs: %d\n", i);
 		rc = -EINVAL;
@@ -3946,22 +3909,24 @@
 	intf_desc.bInterfaceProtocol = mod_data.transport_type;
 	fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
+	if (gadget_is_dualspeed(gadget)) {
+		hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
 
-	/* Assume ep0 uses the same maxpacket value for both speeds */
-	dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
+		/* Assume ep0 uses the same maxpacket value for both speeds */
+		dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
 
-	/* Assume that all endpoint addresses are the same for both speeds */
-	hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress;
-	hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress;
-	hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress;
-#endif
-
-	if (gadget->is_otg) {
-		otg_desc.bmAttributes |= USB_OTG_HNP;
+		/* Assume endpoint addresses are the same for both speeds */
+		hs_bulk_in_desc.bEndpointAddress =
+				fs_bulk_in_desc.bEndpointAddress;
+		hs_bulk_out_desc.bEndpointAddress =
+				fs_bulk_out_desc.bEndpointAddress;
+		hs_intr_in_desc.bEndpointAddress =
+				fs_intr_in_desc.bEndpointAddress;
 	}
 
+	if (gadget_is_otg(gadget))
+		otg_desc.bmAttributes |= USB_OTG_HNP;
+
 	rc = -ENOMEM;
 
 	/* Allocate the request and buffer for endpoint 0 */
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
index 10b2b33..9bb7f64 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.c
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -35,7 +35,7 @@
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
@@ -1090,14 +1090,11 @@
  */
 static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 {
-#ifdef CONFIG_USB_OTG
 	struct fsl_udc *udc;
 
 	udc = container_of(gadget, struct fsl_udc, gadget);
-
 	if (udc->transceiver)
 		return otg_set_power(udc->transceiver, mA);
-#endif
 	return -ENOTSUPP;
 }
 
@@ -1120,7 +1117,7 @@
 	return 0;
 }
 
-/* defined in usb_gadget.h */
+/* defined in gadget.h */
 static struct usb_gadget_ops fsl_gadget_ops = {
 	.get_frame = fsl_get_frame,
 	.wakeup = fsl_wakeup,
@@ -1277,31 +1274,32 @@
 
 	udc_reset_ep_queue(udc, 0);
 
+	/* We process some stardard setup requests here */
 	switch (setup->bRequest) {
-		/* Request that need Data+Status phase from udc */
 	case USB_REQ_GET_STATUS:
-		if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_STANDARD))
+		/* Data+Status phase from udc */
+		if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))
 					!= (USB_DIR_IN | USB_TYPE_STANDARD))
 			break;
 		ch9getstatus(udc, setup->bRequestType, wValue, wIndex, wLength);
-		break;
+		return;
 
-		/* Requests that need Status phase from udc */
 	case USB_REQ_SET_ADDRESS:
+		/* Status phase from udc */
 		if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD
 						| USB_RECIP_DEVICE))
 			break;
 		ch9setaddress(udc, wValue, wIndex, wLength);
-		break;
+		return;
 
-		/* Handled by udc, no data, status by udc */
 	case USB_REQ_CLEAR_FEATURE:
 	case USB_REQ_SET_FEATURE:
-	{	/* status transaction */
+		/* Status phase from udc */
+	{
 		int rc = -EOPNOTSUPP;
 
-		if ((setup->bRequestType & USB_RECIP_MASK)
-				== USB_RECIP_ENDPOINT) {
+		if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK))
+				== (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) {
 			int pipe = get_pipe_by_windex(wIndex);
 			struct fsl_ep *ep;
 
@@ -1315,11 +1313,12 @@
 						? 1 : 0);
 			spin_lock(&udc->lock);
 
-		} else if ((setup->bRequestType & USB_RECIP_MASK)
-				== USB_RECIP_DEVICE) {
+		} else if ((setup->bRequestType & (USB_RECIP_MASK
+				| USB_TYPE_MASK)) == (USB_RECIP_DEVICE
+				| USB_TYPE_STANDARD)) {
 			/* Note: The driver has not include OTG support yet.
 			 * This will be set when OTG support is added */
-			if (!udc->gadget.is_otg)
+			if (!gadget_is_otg(udc->gadget))
 				break;
 			else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
 				udc->gadget.b_hnp_enable = 1;
@@ -1328,39 +1327,44 @@
 			else if (setup->bRequest ==
 					USB_DEVICE_A_ALT_HNP_SUPPORT)
 				udc->gadget.a_alt_hnp_support = 1;
+			else
+				break;
 			rc = 0;
-		}
+		} else
+			break;
+
 		if (rc == 0) {
 			if (ep0_prime_status(udc, EP_DIR_IN))
 				ep0stall(udc);
 		}
+		return;
+	}
+
+	default:
 		break;
 	}
-		/* Requests handled by gadget */
-	default:
-		if (wLength) {
-			/* Data phase from gadget, status phase from udc */
-			udc->ep0_dir = (setup->bRequestType & USB_DIR_IN)
-					?  USB_DIR_IN : USB_DIR_OUT;
-			spin_unlock(&udc->lock);
-			if (udc->driver->setup(&udc->gadget,
-					&udc->local_setup_buff) < 0)
-				ep0stall(udc);
-			spin_lock(&udc->lock);
-			udc->ep0_state = (setup->bRequestType & USB_DIR_IN)
-					?  DATA_STATE_XMIT : DATA_STATE_RECV;
 
-		} else {
-			/* No data phase, IN status from gadget */
-			udc->ep0_dir = USB_DIR_IN;
-			spin_unlock(&udc->lock);
-			if (udc->driver->setup(&udc->gadget,
-					&udc->local_setup_buff) < 0)
-				ep0stall(udc);
-			spin_lock(&udc->lock);
-			udc->ep0_state = WAIT_FOR_OUT_STATUS;
-		}
-		break;
+	/* Requests handled by gadget */
+	if (wLength) {
+		/* Data phase from gadget, status phase from udc */
+		udc->ep0_dir = (setup->bRequestType & USB_DIR_IN)
+				?  USB_DIR_IN : USB_DIR_OUT;
+		spin_unlock(&udc->lock);
+		if (udc->driver->setup(&udc->gadget,
+				&udc->local_setup_buff) < 0)
+			ep0stall(udc);
+		spin_lock(&udc->lock);
+		udc->ep0_state = (setup->bRequestType & USB_DIR_IN)
+				?  DATA_STATE_XMIT : DATA_STATE_RECV;
+	} else {
+		/* No data phase, IN status from gadget */
+		udc->ep0_dir = USB_DIR_IN;
+		spin_unlock(&udc->lock);
+		if (udc->driver->setup(&udc->gadget,
+				&udc->local_setup_buff) < 0)
+			ep0stall(udc);
+		spin_lock(&udc->lock);
+		udc->ep0_state = WAIT_FOR_OUT_STATUS;
 	}
 }
 
@@ -1835,10 +1839,8 @@
 	if (!driver || driver != udc_controller->driver || !driver->unbind)
 		return -EINVAL;
 
-#ifdef CONFIG_USB_OTG
 	if (udc_controller->transceiver)
 		(void)otg_set_peripheral(udc_controller->transceiver, 0);
-#endif
 
 	/* stop DR, disable intr */
 	dr_controller_stop(udc_controller);
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index 53e9139..f7f159c 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -17,6 +17,12 @@
 #define	gadget_is_net2280(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_AMD5536UDC
+#define	gadget_is_amd5536udc(g)	!strcmp("amd5536udc", (g)->name)
+#else
+#define	gadget_is_amd5536udc(g)	0
+#endif
+
 #ifdef CONFIG_USB_GADGET_DUMMY_HCD
 #define	gadget_is_dummy(g)	!strcmp("dummy_udc", (g)->name)
 #else
@@ -202,7 +208,9 @@
 		return 0x18;
 	else if (gadget_is_fsl_usb2(gadget))
 		return 0x19;
-	else if (gadget_is_m66592(gadget))
+	else if (gadget_is_amd5536udc(gadget))
 		return 0x20;
+	else if (gadget_is_m66592(gadget))
+		return 0x21;
 	return -ENOENT;
 }
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 1c5aa49..0689189 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -18,17 +18,11 @@
  * http://www.usb.org/developers/devclass_docs/midi10.pdf
  */
 
-#define DEBUG 1
-// #define VERBOSE
+/* #define VERBOSE_DEBUG */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
 #include <linux/utsname.h>
 #include <linux/device.h>
-#include <linux/moduleparam.h>
 
 #include <sound/driver.h>
 #include <sound/core.h>
@@ -36,7 +30,7 @@
 #include <sound/rawmidi.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/midi.h>
 
@@ -139,30 +133,16 @@
 static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req);
 
 
-#define xprintk(d,level,fmt,args...) \
-	dev_printk(level , &(d)->gadget->dev , fmt , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
-	xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
-	do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG	DBG
-#else
-#define VDBG(dev,fmt,args...) \
-	do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
-	xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
-	xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
-	xprintk(dev , KERN_INFO , fmt , ## args)
+#define DBG(d, fmt, args...) \
+	dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+	dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+	dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+	dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+	dev_info(&(d)->gadget->dev , fmt , ## args)
 
 
 static unsigned buflen = 256;
@@ -425,7 +405,7 @@
 	return len;
 }
 
-static struct usb_request* alloc_ep_req(struct usb_ep *ep, unsigned length)
+static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
 {
 	struct usb_request	*req;
 
@@ -455,7 +435,7 @@
  * Receives a chunk of MIDI data.
  */
 static void gmidi_read_data(struct usb_ep *ep, int cable,
-				   uint8_t* data, int length)
+				   uint8_t *data, int length)
 {
 	struct gmidi_device *dev = ep->driver_data;
 	/* cable is ignored, because for now we only have one. */
@@ -541,7 +521,7 @@
 {
 	int err = 0;
 	struct usb_request *req;
-	struct usb_ep* ep;
+	struct usb_ep *ep;
 	unsigned i;
 
 	err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
@@ -628,7 +608,7 @@
 
 	if (gadget_is_sa1100(gadget) && dev->config) {
 		/* tx fifo is full, but we can't clear it...*/
-		INFO(dev, "can't change configurations\n");
+		ERROR(dev, "can't change configurations\n");
 		return -ESPIPE;
 	}
 	gmidi_reset_config(dev);
@@ -843,7 +823,7 @@
 static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget)
 {
 	struct gmidi_device *dev = get_gadget_data(gadget);
-	struct snd_card* card;
+	struct snd_card *card;
 
 	DBG(dev, "unbind\n");
 
@@ -867,12 +847,12 @@
 	return 0;
 }
 
-static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0,
+static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0,
 					uint8_t p1, uint8_t p2, uint8_t p3)
 {
 	unsigned length = req->length;
+	u8 *buf = (u8 *)req->buf + length;
 
-	uint8_t* buf = (uint8_t*)req->buf + length;
 	buf[0] = p0;
 	buf[1] = p1;
 	buf[2] = p2;
@@ -883,8 +863,8 @@
 /*
  * Converts MIDI commands to USB MIDI packets.
  */
-static void gmidi_transmit_byte(struct usb_request* req,
-				struct gmidi_in_port* port, uint8_t b)
+static void gmidi_transmit_byte(struct usb_request *req,
+				struct gmidi_in_port *port, uint8_t b)
 {
 	uint8_t p0 = port->cable;
 
@@ -981,10 +961,10 @@
 	}
 }
 
-static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
+static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req)
 {
-	struct usb_ep* ep = dev->in_ep;
-	struct gmidi_in_port* port = &dev->in_port;
+	struct usb_ep *ep = dev->in_ep;
+	struct gmidi_in_port *port = &dev->in_port;
 
 	if (!ep) {
 		return;
@@ -1020,14 +1000,14 @@
 
 static void gmidi_in_tasklet(unsigned long data)
 {
-	struct gmidi_device* dev = (struct gmidi_device*)data;
+	struct gmidi_device *dev = (struct gmidi_device *)data;
 
 	gmidi_transmit(dev, NULL);
 }
 
 static int gmidi_in_open(struct snd_rawmidi_substream *substream)
 {
-	struct gmidi_device* dev = substream->rmidi->private_data;
+	struct gmidi_device *dev = substream->rmidi->private_data;
 
 	VDBG(dev, "gmidi_in_open\n");
 	dev->in_substream = substream;
@@ -1037,13 +1017,15 @@
 
 static int gmidi_in_close(struct snd_rawmidi_substream *substream)
 {
+	struct gmidi_device *dev = substream->rmidi->private_data;
+
 	VDBG(dev, "gmidi_in_close\n");
 	return 0;
 }
 
 static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
 {
-	struct gmidi_device* dev = substream->rmidi->private_data;
+	struct gmidi_device *dev = substream->rmidi->private_data;
 
 	VDBG(dev, "gmidi_in_trigger %d\n", up);
 	dev->in_port.active = up;
@@ -1054,7 +1036,7 @@
 
 static int gmidi_out_open(struct snd_rawmidi_substream *substream)
 {
-	struct gmidi_device* dev = substream->rmidi->private_data;
+	struct gmidi_device *dev = substream->rmidi->private_data;
 
 	VDBG(dev, "gmidi_out_open\n");
 	dev->out_substream = substream;
@@ -1063,13 +1045,15 @@
 
 static int gmidi_out_close(struct snd_rawmidi_substream *substream)
 {
+	struct gmidi_device *dev = substream->rmidi->private_data;
+
 	VDBG(dev, "gmidi_out_close\n");
 	return 0;
 }
 
 static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up)
 {
-	struct gmidi_device* dev = substream->rmidi->private_data;
+	struct gmidi_device *dev = substream->rmidi->private_data;
 
 	VDBG(dev, "gmidi_out_trigger %d\n", up);
 	if (up) {
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index d6c5f11..2ec9d19 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -37,7 +37,7 @@
 #include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -1777,14 +1777,13 @@
 	}
 
 	/* alloc, and start init */
-	dev = kmalloc (sizeof *dev, GFP_KERNEL);
+	dev = kzalloc (sizeof *dev, GFP_KERNEL);
 	if (dev == NULL){
 		pr_debug("enomem %s\n", pci_name(pdev));
 		retval = -ENOMEM;
 		goto done;
 	}
 
-	memset(dev, 0, sizeof *dev);
 	spin_lock_init(&dev->lock);
 	dev->pdev = pdev;
 	dev->gadget.ops = &goku_ops;
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index e60745ff..47ef8bd 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -20,8 +20,7 @@
  */
 
 
-// #define	DEBUG			/* data to help fault diagnosis */
-// #define	VERBOSE		/* extra debug messages (success too) */
+/* #define VERBOSE_DEBUG */
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -38,7 +37,7 @@
 #include <linux/moduleparam.h>
 
 #include <linux/usb/gadgetfs.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 /*
@@ -253,7 +252,7 @@
 	do { } while (0)
 #endif /* DEBUG */
 
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
 #define VDEBUG	DBG
 #else
 #define VDEBUG(dev,fmt,args...) \
@@ -964,7 +963,7 @@
 	}
 	if (len > sizeof (dev->rbuf))
 		req->buf = kmalloc(len, GFP_ATOMIC);
-	if (req->buf == 0) {
+	if (req->buf == NULL) {
 		req->buf = dev->rbuf;
 		return -ENOMEM;
 	}
@@ -1010,11 +1009,12 @@
 			/* assume that was SET_CONFIGURATION */
 			if (dev->current_config) {
 				unsigned power;
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-				if (dev->gadget->speed == USB_SPEED_HIGH)
+
+				if (gadget_is_dualspeed(dev->gadget)
+						&& (dev->gadget->speed
+							== USB_SPEED_HIGH))
 					power = dev->hs_config->bMaxPower;
 				else
-#endif
 					power = dev->config->bMaxPower;
 				usb_gadget_vbus_draw(dev->gadget, 2 * power);
 			}
@@ -1355,24 +1355,21 @@
 config_buf (struct dev_data *dev, u8 type, unsigned index)
 {
 	int		len;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	int		hs;
-#endif
+	int		hs = 0;
 
 	/* only one configuration */
 	if (index > 0)
 		return -EINVAL;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	hs = (dev->gadget->speed == USB_SPEED_HIGH);
-	if (type == USB_DT_OTHER_SPEED_CONFIG)
-		hs = !hs;
+	if (gadget_is_dualspeed(dev->gadget)) {
+		hs = (dev->gadget->speed == USB_SPEED_HIGH);
+		if (type == USB_DT_OTHER_SPEED_CONFIG)
+			hs = !hs;
+	}
 	if (hs) {
 		dev->req->buf = dev->hs_config;
 		len = le16_to_cpu(dev->hs_config->wTotalLength);
-	} else
-#endif
-	{
+	} else {
 		dev->req->buf = dev->config;
 		len = le16_to_cpu(dev->config->wTotalLength);
 	}
@@ -1393,13 +1390,13 @@
 	spin_lock (&dev->lock);
 	dev->setup_abort = 0;
 	if (dev->state == STATE_DEV_UNCONNECTED) {
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-		if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) {
+		if (gadget_is_dualspeed(gadget)
+				&& gadget->speed == USB_SPEED_HIGH
+				&& dev->hs_config == NULL) {
 			spin_unlock(&dev->lock);
 			ERROR (dev, "no high speed config??\n");
 			return -EINVAL;
 		}
-#endif	/* CONFIG_USB_GADGET_DUALSPEED */
 
 		dev->state = STATE_DEV_CONNECTED;
 		dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
@@ -1469,13 +1466,12 @@
 			// user mode expected to disable endpoints
 		} else {
 			u8	config, power;
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-			if (gadget->speed == USB_SPEED_HIGH) {
+
+			if (gadget_is_dualspeed(gadget)
+					&& gadget->speed == USB_SPEED_HIGH) {
 				config = dev->hs_config->bConfigurationValue;
 				power = dev->hs_config->bMaxPower;
-			} else
-#endif
-			{
+			} else {
 				config = dev->config->bConfigurationValue;
 				power = dev->config->bMaxPower;
 			}
diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h
index b3fe197..1ecfd63 100644
--- a/drivers/usb/gadget/lh7a40x_udc.h
+++ b/drivers/usb/gadget/lh7a40x_udc.h
@@ -50,7 +50,7 @@
 #include <asm/hardware.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 /*
  * Memory map
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 0174a32..ebc5536 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -21,26 +21,18 @@
  */
 
 #include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/list.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/io.h>
 #include <linux/platform_device.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
 
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
 
 #include "m66592-udc.h"
 
-MODULE_DESCRIPTION("M66592 USB gadget driiver");
+
+MODULE_DESCRIPTION("M66592 USB gadget driver");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Yoshihiro Shimoda");
 
@@ -49,16 +41,21 @@
 /* module parameters */
 static unsigned short clock = M66592_XTAL24;
 module_param(clock, ushort, 0644);
-MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0(default=16384)");
+MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
+		"(default=16384)");
+
 static unsigned short vif = M66592_LDRV;
 module_param(vif, ushort, 0644);
-MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)");
-static unsigned short endian = 0;
+MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0 (default=32768)");
+
+static unsigned short endian;
 module_param(endian, ushort, 0644);
-MODULE_PARM_DESC(endian, "data endian: big=256, little=0(default=0)");
+MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
+
 static unsigned short irq_sense = M66592_INTL;
 module_param(irq_sense, ushort, 0644);
-MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0(default=2)");
+MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 "
+		"(default=2)");
 
 static const char udc_name[] = "m66592_udc";
 static const char *m66592_ep_name[] = {
@@ -72,8 +69,8 @@
 			gfp_t gfp_flags);
 
 static void transfer_complete(struct m66592_ep *ep,
-			      struct m66592_request *req,
-			      int status);
+		struct m66592_request *req, int status);
+
 /*-------------------------------------------------------------------------*/
 static inline u16 get_usb_speed(struct m66592 *m66592)
 {
@@ -81,25 +78,25 @@
 }
 
 static void enable_pipe_irq(struct m66592 *m66592, u16 pipenum,
-			    unsigned long reg)
+		unsigned long reg)
 {
 	u16 tmp;
 
 	tmp = m66592_read(m66592, M66592_INTENB0);
 	m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
-		    M66592_INTENB0);
+			M66592_INTENB0);
 	m66592_bset(m66592, (1 << pipenum), reg);
 	m66592_write(m66592, tmp, M66592_INTENB0);
 }
 
 static void disable_pipe_irq(struct m66592 *m66592, u16 pipenum,
-			     unsigned long reg)
+		unsigned long reg)
 {
 	u16 tmp;
 
 	tmp = m66592_read(m66592, M66592_INTENB0);
 	m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
-		    M66592_INTENB0);
+			M66592_INTENB0);
 	m66592_bclr(m66592, (1 << pipenum), reg);
 	m66592_write(m66592, tmp, M66592_INTENB0);
 }
@@ -108,17 +105,19 @@
 {
 	m66592_bset(m66592, M66592_CTRE, M66592_INTENB0);
 	m66592_bset(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
-		    M66592_INTENB0);
+			M66592_INTENB0);
 	m66592_bset(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
 
 	m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG);
 }
 
 static void m66592_usb_disconnect(struct m66592 *m66592)
+__releases(m66592->lock)
+__acquires(m66592->lock)
 {
 	m66592_bclr(m66592, M66592_CTRE, M66592_INTENB0);
 	m66592_bclr(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
-		    M66592_INTENB0);
+			M66592_INTENB0);
 	m66592_bclr(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
 	m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
 
@@ -148,7 +147,7 @@
 }
 
 static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum,
-				       u16 pid)
+		u16 pid)
 {
 	unsigned long offset;
 
@@ -250,7 +249,7 @@
 }
 
 static int pipe_buffer_setting(struct m66592 *m66592,
-			       struct m66592_pipe_info *info)
+		struct m66592_pipe_info *info)
 {
 	u16 bufnum = 0, buf_bsize = 0;
 	u16 pipecfg = 0;
@@ -287,7 +286,7 @@
 	}
 	if (m66592->bi_bufnum > M66592_MAX_BUFNUM) {
 		printk(KERN_ERR "m66592 pipe memory is insufficient(%d)\n",
-		       m66592->bi_bufnum);
+				m66592->bi_bufnum);
 		return -ENOMEM;
 	}
 
@@ -328,7 +327,7 @@
 			m66592->bulk--;
 	} else
 		printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n",
-		       info->pipe);
+				info->pipe);
 }
 
 static void pipe_initialize(struct m66592_ep *ep)
@@ -350,8 +349,8 @@
 }
 
 static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
-			      const struct usb_endpoint_descriptor *desc,
-			      u16 pipenum, int dma)
+		const struct usb_endpoint_descriptor *desc,
+		u16 pipenum, int dma)
 {
 	if ((pipenum != 0) && dma) {
 		if (m66592->num_dma == 0) {
@@ -385,7 +384,7 @@
 
 	ep->pipectr = get_pipectr_addr(pipenum);
 	ep->pipenum = pipenum;
-	ep->ep.maxpacket = desc->wMaxPacketSize;
+	ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
 	m66592->pipenum2ep[pipenum] = ep;
 	m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep;
 	INIT_LIST_HEAD(&ep->queue);
@@ -407,7 +406,7 @@
 }
 
 static int alloc_pipe_config(struct m66592_ep *ep,
-			     const struct usb_endpoint_descriptor *desc)
+		const struct usb_endpoint_descriptor *desc)
 {
 	struct m66592 *m66592 = ep->m66592;
 	struct m66592_pipe_info info;
@@ -419,15 +418,15 @@
 
 	BUG_ON(ep->pipenum);
 
-	switch(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
 	case USB_ENDPOINT_XFER_BULK:
 		if (m66592->bulk >= M66592_MAX_NUM_BULK) {
 			if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
 				printk(KERN_ERR "bulk pipe is insufficient\n");
 				return -ENODEV;
 			} else {
-				info.pipe = M66592_BASE_PIPENUM_ISOC +
-					    m66592->isochronous;
+				info.pipe = M66592_BASE_PIPENUM_ISOC
+						+ m66592->isochronous;
 				counter = &m66592->isochronous;
 			}
 		} else {
@@ -462,7 +461,7 @@
 	ep->type = info.type;
 
 	info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-	info.maxpacket = desc->wMaxPacketSize;
+	info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
 	info.interval = desc->bInterval;
 	if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
 		info.dir_in = 1;
@@ -525,8 +524,8 @@
 
 	pipe_change(m66592, ep->pipenum);
 	m66592_mdfy(m66592, M66592_ISEL | M66592_PIPE0,
-		    (M66592_ISEL | M66592_CURPIPE),
-		    M66592_CFIFOSEL);
+			(M66592_ISEL | M66592_CURPIPE),
+			M66592_CFIFOSEL);
 	m66592_write(m66592, M66592_BCLR, ep->fifoctr);
 	if (req->req.length == 0) {
 		m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
@@ -561,8 +560,8 @@
 
 	if (ep->pipenum == 0) {
 		m66592_mdfy(m66592, M66592_PIPE0,
-			    (M66592_ISEL | M66592_CURPIPE),
-			    M66592_CFIFOSEL);
+				(M66592_ISEL | M66592_CURPIPE),
+				M66592_CFIFOSEL);
 		m66592_write(m66592, M66592_BCLR, ep->fifoctr);
 		pipe_start(m66592, pipenum);
 		pipe_irq_enable(m66592, pipenum);
@@ -572,8 +571,9 @@
 			pipe_change(m66592, pipenum);
 			m66592_bset(m66592, M66592_TRENB, ep->fifosel);
 			m66592_write(m66592,
-				     (req->req.length + ep->ep.maxpacket - 1) /
-				     ep->ep.maxpacket, ep->fifotrn);
+				(req->req.length + ep->ep.maxpacket - 1)
+					/ ep->ep.maxpacket,
+				ep->fifotrn);
 		}
 		pipe_start(m66592, pipenum);	/* trigger once */
 		pipe_irq_enable(m66592, pipenum);
@@ -614,7 +614,7 @@
 static void init_controller(struct m66592 *m66592)
 {
 	m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND),
-		    M66592_PINCFG);
+			M66592_PINCFG);
 	m66592_bset(m66592, M66592_HSE, M66592_SYSCFG);		/* High spd */
 	m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL, M66592_SYSCFG);
 
@@ -634,7 +634,7 @@
 
 	m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1);
 	m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR,
-		     M66592_DMA0CFG);
+			M66592_DMA0CFG);
 }
 
 static void disable_controller(struct m66592 *m66592)
@@ -659,8 +659,9 @@
 
 /*-------------------------------------------------------------------------*/
 static void transfer_complete(struct m66592_ep *ep,
-			      struct m66592_request *req,
-			      int status)
+		struct m66592_request *req, int status)
+__releases(m66592->lock)
+__acquires(m66592->lock)
 {
 	int restart = 0;
 
@@ -680,8 +681,9 @@
 	if (!list_empty(&ep->queue))
 		restart = 1;
 
-	if (likely(req->req.complete))
-		req->req.complete(&ep->ep, &req->req);
+	spin_unlock(&ep->m66592->lock);
+	req->req.complete(&ep->ep, &req->req);
+	spin_lock(&ep->m66592->lock);
 
 	if (restart) {
 		req = list_entry(ep->queue.next, struct m66592_request, queue);
@@ -693,7 +695,7 @@
 static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
 {
 	int i;
-	volatile u16 tmp;
+	u16 tmp;
 	unsigned bufsize;
 	size_t size;
 	void *buf;
@@ -731,8 +733,9 @@
 	req->req.actual += size;
 
 	/* check transfer finish */
-	if ((!req->req.zero && (req->req.actual == req->req.length)) ||
-	    (size % ep->ep.maxpacket) || (size == 0)) {
+	if ((!req->req.zero && (req->req.actual == req->req.length))
+			|| (size % ep->ep.maxpacket)
+			|| (size == 0)) {
 		disable_irq_ready(m66592, pipenum);
 		disable_irq_empty(m66592, pipenum);
 	} else {
@@ -768,16 +771,19 @@
 	/* write fifo */
 	if (req->req.buf) {
 		m66592_write_fifo(m66592, ep->fifoaddr, buf, size);
-		if ((size == 0) || ((size % ep->ep.maxpacket) != 0) ||
-		    ((bufsize != ep->ep.maxpacket) && (bufsize > size)))
+		if ((size == 0)
+				|| ((size % ep->ep.maxpacket) != 0)
+				|| ((bufsize != ep->ep.maxpacket)
+					&& (bufsize > size)))
 			m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
 	}
 
 	/* update parameters */
 	req->req.actual += size;
 	/* check transfer finish */
-	if ((!req->req.zero && (req->req.actual == req->req.length)) ||
-	    (size % ep->ep.maxpacket) || (size == 0)) {
+	if ((!req->req.zero && (req->req.actual == req->req.length))
+			|| (size % ep->ep.maxpacket)
+			|| (size == 0)) {
 		disable_irq_ready(m66592, pipenum);
 		enable_irq_empty(m66592, pipenum);
 	} else {
@@ -821,8 +827,9 @@
 	req->req.actual += size;
 
 	/* check transfer finish */
-	if ((!req->req.zero && (req->req.actual == req->req.length)) ||
-	    (size % ep->ep.maxpacket) || (size == 0)) {
+	if ((!req->req.zero && (req->req.actual == req->req.length))
+			|| (size % ep->ep.maxpacket)
+			|| (size == 0)) {
 		pipe_stop(m66592, pipenum);
 		pipe_irq_disable(m66592, pipenum);
 		finish = 1;
@@ -850,7 +857,7 @@
 	if ((status & M66592_BRDY0) && (enb & M66592_BRDY0)) {
 		m66592_write(m66592, ~M66592_BRDY0, M66592_BRDYSTS);
 		m66592_mdfy(m66592, M66592_PIPE0, M66592_CURPIPE,
-			    M66592_CFIFOSEL);
+				M66592_CFIFOSEL);
 
 		ep = &m66592->ep[0];
 		req = list_entry(ep->queue.next, struct m66592_request, queue);
@@ -909,23 +916,26 @@
 }
 
 static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+__releases(m66592->lock)
+__acquires(m66592->lock)
 {
 	struct m66592_ep *ep;
 	u16 pid;
 	u16 status = 0;
+	u16 w_index = le16_to_cpu(ctrl->wIndex);
 
 	switch (ctrl->bRequestType & USB_RECIP_MASK) {
 	case USB_RECIP_DEVICE:
-		status = 1;	/* selfpower */
+		status = 1 << USB_DEVICE_SELF_POWERED;
 		break;
 	case USB_RECIP_INTERFACE:
 		status = 0;
 		break;
 	case USB_RECIP_ENDPOINT:
-		ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+		ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
 		pid = control_reg_get_pid(m66592, ep->pipenum);
 		if (pid == M66592_PID_STALL)
-			status = 1;
+			status = 1 << USB_ENDPOINT_HALT;
 		else
 			status = 0;
 		break;
@@ -934,11 +944,13 @@
 		return;		/* exit */
 	}
 
-	*m66592->ep0_buf = status;
-	m66592->ep0_req->buf = m66592->ep0_buf;
+	m66592->ep0_data = cpu_to_le16(status);
+	m66592->ep0_req->buf = &m66592->ep0_data;
 	m66592->ep0_req->length = 2;
 	/* AV: what happens if we get called again before that gets through? */
+	spin_unlock(&m66592->lock);
 	m66592_queue(m66592->gadget.ep0, m66592->ep0_req, GFP_KERNEL);
+	spin_lock(&m66592->lock);
 }
 
 static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
@@ -953,8 +965,9 @@
 	case USB_RECIP_ENDPOINT: {
 		struct m66592_ep *ep;
 		struct m66592_request *req;
+		u16 w_index = le16_to_cpu(ctrl->wIndex);
 
-		ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+		ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
 		pipe_stop(m66592, ep->pipenum);
 		control_reg_sqclr(m66592, ep->pipenum);
 
@@ -989,8 +1002,9 @@
 		break;
 	case USB_RECIP_ENDPOINT: {
 		struct m66592_ep *ep;
+		u16 w_index = le16_to_cpu(ctrl->wIndex);
 
-		ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+		ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK];
 		pipe_stall(m66592, ep->pipenum);
 
 		control_end(m66592, 1);
@@ -1066,14 +1080,16 @@
 	}
 	if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG)
 		m66592_update_usb_speed(m66592);
-	if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS) &&
-	    m66592->gadget.speed == USB_SPEED_UNKNOWN)
+	if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS)
+			&& m66592->gadget.speed == USB_SPEED_UNKNOWN)
 		m66592_update_usb_speed(m66592);
 
 	m66592->old_dvsq = dvsq;
 }
 
 static void irq_control_stage(struct m66592 *m66592)
+__releases(m66592->lock)
+__acquires(m66592->lock)
 {
 	struct usb_ctrlrequest ctrl;
 	u16 ctsq;
@@ -1095,8 +1111,10 @@
 	case M66592_CS_WRDS:
 	case M66592_CS_WRND:
 		if (setup_packet(m66592, &ctrl)) {
+			spin_unlock(&m66592->lock);
 			if (m66592->driver->setup(&m66592->gadget, &ctrl) < 0)
 				pipe_stall(m66592, 0);
+			spin_lock(&m66592->lock);
 		}
 		break;
 	case M66592_CS_RDSS:
@@ -1119,6 +1137,8 @@
 	u16 savepipe;
 	u16 mask0;
 
+	spin_lock(&m66592->lock);
+
 	intsts0 = m66592_read(m66592, M66592_INTSTS0);
 	intenb0 = m66592_read(m66592, M66592_INTENB0);
 
@@ -1134,27 +1154,27 @@
 		bempenb = m66592_read(m66592, M66592_BEMPENB);
 
 		if (mask0 & M66592_VBINT) {
-			m66592_write(m66592, (u16)~M66592_VBINT,
-				     M66592_INTSTS0);
+			m66592_write(m66592,  0xffff & ~M66592_VBINT,
+					M66592_INTSTS0);
 			m66592_start_xclock(m66592);
 
 			/* start vbus sampling */
 			m66592->old_vbus = m66592_read(m66592, M66592_INTSTS0)
-					   & M66592_VBSTS;
+					& M66592_VBSTS;
 			m66592->scount = M66592_MAX_SAMPLING;
 
 			mod_timer(&m66592->timer,
-				  jiffies + msecs_to_jiffies(50));
+					jiffies + msecs_to_jiffies(50));
 		}
 		if (intsts0 & M66592_DVSQ)
 			irq_device_state(m66592);
 
-		if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE) &&
-		    (brdysts & brdyenb)) {
+		if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE)
+				&& (brdysts & brdyenb)) {
 			irq_pipe_ready(m66592, brdysts, brdyenb);
 		}
-		if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE) &&
-		    (bempsts & bempenb)) {
+		if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE)
+				&& (bempsts & bempenb)) {
 			irq_pipe_empty(m66592, bempsts, bempenb);
 		}
 
@@ -1164,6 +1184,7 @@
 
 	m66592_write(m66592, savepipe, M66592_CFIFOSEL);
 
+	spin_unlock(&m66592->lock);
 	return IRQ_HANDLED;
 }
 
@@ -1191,13 +1212,13 @@
 					m66592_usb_disconnect(m66592);
 			} else {
 				mod_timer(&m66592->timer,
-					  jiffies + msecs_to_jiffies(50));
+					jiffies + msecs_to_jiffies(50));
 			}
 		} else {
 			m66592->scount = M66592_MAX_SAMPLING;
 			m66592->old_vbus = tmp;
 			mod_timer(&m66592->timer,
-				  jiffies + msecs_to_jiffies(50));
+					jiffies + msecs_to_jiffies(50));
 		}
 	}
 	spin_unlock_irqrestore(&m66592->lock, flags);
@@ -1278,7 +1299,7 @@
 	req->req.actual = 0;
 	req->req.status = -EINPROGRESS;
 
-	if (ep->desc == 0)	/* control */
+	if (ep->desc == NULL)	/* control */
 		start_ep0(ep, req);
 	else {
 		if (request && !ep->busy)
@@ -1335,11 +1356,6 @@
 	return ret;
 }
 
-static int m66592_fifo_status(struct usb_ep *_ep)
-{
-	return -EOPNOTSUPP;
-}
-
 static void m66592_fifo_flush(struct usb_ep *_ep)
 {
 	struct m66592_ep *ep;
@@ -1365,7 +1381,6 @@
 	.dequeue	= m66592_dequeue,
 
 	.set_halt	= m66592_set_halt,
-	.fifo_status	= m66592_fifo_status,
 	.fifo_flush	= m66592_fifo_flush,
 };
 
@@ -1377,11 +1392,10 @@
 	struct m66592 *m66592 = the_controller;
 	int retval;
 
-	if (!driver ||
-	    driver->speed != USB_SPEED_HIGH ||
-	    !driver->bind ||
-	    !driver->unbind ||
-	    !driver->setup)
+	if (!driver
+			|| driver->speed != USB_SPEED_HIGH
+			|| !driver->bind
+			|| !driver->setup)
 		return -EINVAL;
 	if (!m66592)
 		return -ENODEV;
@@ -1413,8 +1427,7 @@
 		m66592->old_vbus = m66592_read(m66592,
 					 M66592_INTSTS0) & M66592_VBSTS;
 		m66592->scount = M66592_MAX_SAMPLING;
-		mod_timer(&m66592->timer,
-			  jiffies + msecs_to_jiffies(50));
+		mod_timer(&m66592->timer, jiffies + msecs_to_jiffies(50));
 	}
 
 	return 0;
@@ -1432,6 +1445,9 @@
 	struct m66592 *m66592 = the_controller;
 	unsigned long flags;
 
+	if (driver != m66592->driver || !driver->unbind)
+		return -EINVAL;
+
 	spin_lock_irqsave(&m66592->lock, flags);
 	if (m66592->gadget.speed != USB_SPEED_UNKNOWN)
 		m66592_usb_disconnect(m66592);
@@ -1461,46 +1477,35 @@
 	.get_frame		= m66592_get_frame,
 };
 
-#if defined(CONFIG_PM)
-static int m66592_suspend(struct platform_device *pdev, pm_message_t state)
-{
-	pdev->dev.power.power_state = state;
-	return 0;
-}
-
-static int m66592_resume(struct platform_device *pdev)
-{
-	pdev->dev.power.power_state = PMSG_ON;
-	return 0;
-}
-#else	/* if defined(CONFIG_PM) */
-#define m66592_suspend		NULL
-#define m66592_resume		NULL
-#endif
-
-static int __init_or_module m66592_remove(struct platform_device *pdev)
+static int __exit m66592_remove(struct platform_device *pdev)
 {
 	struct m66592		*m66592 = dev_get_drvdata(&pdev->dev);
 
 	del_timer_sync(&m66592->timer);
 	iounmap(m66592->reg);
 	free_irq(platform_get_irq(pdev, 0), m66592);
+	m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
 	kfree(m66592);
 	return 0;
 }
 
+static void nop_completion(struct usb_ep *ep, struct usb_request *r)
+{
+}
+
 #define resource_len(r) (((r)->end - (r)->start) + 1)
+
 static int __init m66592_probe(struct platform_device *pdev)
 {
-	struct resource *res = NULL;
-	int irq = -1;
+	struct resource *res;
+	int irq;
 	void __iomem *reg = NULL;
 	struct m66592 *m66592 = NULL;
 	int ret = 0;
 	int i;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
-					   (char *)udc_name);
+			(char *)udc_name);
 	if (!res) {
 		ret = -ENODEV;
 		printk(KERN_ERR "platform_get_resource_byname error.\n");
@@ -1548,7 +1553,7 @@
 	m66592->bi_bufnum = M66592_BASE_BUFNUM;
 
 	ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
-			  udc_name, m66592);
+			udc_name, m66592);
 	if (ret < 0) {
 		printk(KERN_ERR "request_irq error (%d)\n", ret);
 		goto clean_up;
@@ -1563,7 +1568,7 @@
 		if (i != 0) {
 			INIT_LIST_HEAD(&m66592->ep[i].ep.ep_list);
 			list_add_tail(&m66592->ep[i].ep.ep_list,
-				      &m66592->gadget.ep_list);
+					&m66592->gadget.ep_list);
 		}
 		ep->m66592 = m66592;
 		INIT_LIST_HEAD(&ep->queue);
@@ -1583,20 +1588,18 @@
 
 	the_controller = m66592;
 
-	/* AV: leaks */
 	m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL);
 	if (m66592->ep0_req == NULL)
-		goto clean_up;
-	/* AV: leaks, and do we really need it separately allocated? */
-	m66592->ep0_buf = kzalloc(2, GFP_KERNEL);
-	if (m66592->ep0_buf == NULL)
-		goto clean_up;
+		goto clean_up2;
+	m66592->ep0_req->complete = nop_completion;
 
 	init_controller(m66592);
 
-	printk("driver %s, %s\n", udc_name, DRIVER_VERSION);
+	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
 	return 0;
 
+clean_up2:
+	free_irq(irq, m66592);
 clean_up:
 	if (m66592) {
 		if (m66592->ep0_req)
@@ -1611,10 +1614,7 @@
 
 /*-------------------------------------------------------------------------*/
 static struct platform_driver m66592_driver = {
-	.probe =	m66592_probe,
-	.remove =	m66592_remove,
-	.suspend =	m66592_suspend,
-	.resume =	m66592_resume,
+	.remove =	__exit_p(m66592_remove),
 	.driver		= {
 		.name =	(char *) udc_name,
 	},
@@ -1622,7 +1622,7 @@
 
 static int __init m66592_udc_init(void)
 {
-	return platform_driver_register(&m66592_driver);
+	return platform_driver_probe(&m66592_driver, m66592_probe);
 }
 module_init(m66592_udc_init);
 
@@ -1631,4 +1631,3 @@
 	platform_driver_unregister(&m66592_driver);
 }
 module_exit(m66592_udc_cleanup);
-
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
index 26b54f8..bfa0c64 100644
--- a/drivers/usb/gadget/m66592-udc.h
+++ b/drivers/usb/gadget/m66592-udc.h
@@ -24,73 +24,73 @@
 #define __M66592_UDC_H__
 
 #define M66592_SYSCFG		0x00
-#define	M66592_XTAL		0xC000	/* b15-14: Crystal selection */
-#define	  M66592_XTAL48		 0x8000		  /* 48MHz */
-#define   M66592_XTAL24		 0x4000		  /* 24MHz */
-#define	  M66592_XTAL12		 0x0000		  /* 12MHz */
-#define	M66592_XCKE		0x2000	/* b13: External clock enable */
-#define	M66592_RCKE		0x1000	/* b12: Register clock enable */
-#define	M66592_PLLC		0x0800	/* b11: PLL control */
-#define	M66592_SCKE		0x0400	/* b10: USB clock enable */
-#define	M66592_ATCKM		0x0100	/* b8: Automatic supply functional enable */
-#define	M66592_HSE		0x0080	/* b7: Hi-speed enable */
-#define	M66592_DCFM		0x0040	/* b6: Controller function select  */
-#define	M66592_DMRPD		0x0020	/* b5: D- pull down control */
-#define	M66592_DPRPU		0x0010	/* b4: D+ pull up control */
-#define	M66592_FSRPC		0x0004	/* b2: Full-speed receiver enable */
-#define	M66592_PCUT		0x0002	/* b1: Low power sleep enable */
-#define	M66592_USBE		0x0001	/* b0: USB module operation enable */
+#define M66592_XTAL		0xC000	/* b15-14: Crystal selection */
+#define   M66592_XTAL48		 0x8000		/* 48MHz */
+#define   M66592_XTAL24		 0x4000		/* 24MHz */
+#define   M66592_XTAL12		 0x0000		/* 12MHz */
+#define M66592_XCKE		0x2000	/* b13: External clock enable */
+#define M66592_RCKE		0x1000	/* b12: Register clock enable */
+#define M66592_PLLC		0x0800	/* b11: PLL control */
+#define M66592_SCKE		0x0400	/* b10: USB clock enable */
+#define M66592_ATCKM		0x0100	/* b8: Automatic clock supply */
+#define M66592_HSE		0x0080	/* b7: Hi-speed enable */
+#define M66592_DCFM		0x0040	/* b6: Controller function select  */
+#define M66592_DMRPD		0x0020	/* b5: D- pull down control */
+#define M66592_DPRPU		0x0010	/* b4: D+ pull up control */
+#define M66592_FSRPC		0x0004	/* b2: Full-speed receiver enable */
+#define M66592_PCUT		0x0002	/* b1: Low power sleep enable */
+#define M66592_USBE		0x0001	/* b0: USB module operation enable */
 
 #define M66592_SYSSTS		0x02
-#define	M66592_LNST		0x0003	/* b1-0: D+, D- line status */
-#define	  M66592_SE1		 0x0003		  /* SE1 */
-#define	  M66592_KSTS		 0x0002		  /* K State */
-#define	  M66592_JSTS		 0x0001		  /* J State */
-#define	  M66592_SE0		 0x0000		  /* SE0 */
+#define M66592_LNST		0x0003	/* b1-0: D+, D- line status */
+#define   M66592_SE1		 0x0003		/* SE1 */
+#define   M66592_KSTS		 0x0002		/* K State */
+#define   M66592_JSTS		 0x0001		/* J State */
+#define   M66592_SE0		 0x0000		/* SE0 */
 
 #define M66592_DVSTCTR		0x04
-#define	M66592_WKUP		0x0100	/* b8: Remote wakeup */
-#define	M66592_RWUPE		0x0080	/* b7: Remote wakeup sense */
-#define	M66592_USBRST		0x0040	/* b6: USB reset enable */
-#define	M66592_RESUME		0x0020	/* b5: Resume enable */
-#define	M66592_UACT		0x0010	/* b4: USB bus enable */
-#define	M66592_RHST		0x0003	/* b1-0: Reset handshake status */
-#define	  M66592_HSMODE		 0x0003		  /* Hi-Speed mode */
-#define	  M66592_FSMODE		 0x0002		  /* Full-Speed mode */
-#define	  M66592_HSPROC		 0x0001		  /* HS handshake is processing */
+#define M66592_WKUP		0x0100	/* b8: Remote wakeup */
+#define M66592_RWUPE		0x0080	/* b7: Remote wakeup sense */
+#define M66592_USBRST		0x0040	/* b6: USB reset enable */
+#define M66592_RESUME		0x0020	/* b5: Resume enable */
+#define M66592_UACT		0x0010	/* b4: USB bus enable */
+#define M66592_RHST		0x0003	/* b1-0: Reset handshake status */
+#define   M66592_HSMODE		 0x0003		/* Hi-Speed mode */
+#define   M66592_FSMODE		 0x0002		/* Full-Speed mode */
+#define   M66592_HSPROC		 0x0001		/* HS handshake is processing */
 
 #define M66592_TESTMODE		0x06
-#define	M66592_UTST		0x000F	/* b4-0: Test select */
-#define	  M66592_H_TST_PACKET	 0x000C		  /* HOST TEST Packet */
-#define	  M66592_H_TST_SE0_NAK	 0x000B		  /* HOST TEST SE0 NAK */
-#define	  M66592_H_TST_K	 0x000A		  /* HOST TEST K */
-#define	  M66592_H_TST_J	 0x0009		  /* HOST TEST J */
-#define	  M66592_H_TST_NORMAL	 0x0000		  /* HOST Normal Mode */
-#define	  M66592_P_TST_PACKET	 0x0004		  /* PERI TEST Packet */
-#define	  M66592_P_TST_SE0_NAK	 0x0003		  /* PERI TEST SE0 NAK */
-#define	  M66592_P_TST_K	 0x0002		  /* PERI TEST K */
-#define	  M66592_P_TST_J	 0x0001		  /* PERI TEST J */
-#define	  M66592_P_TST_NORMAL	 0x0000		  /* PERI Normal Mode */
+#define M66592_UTST		0x000F	/* b4-0: Test select */
+#define   M66592_H_TST_PACKET	 0x000C		/* HOST TEST Packet */
+#define   M66592_H_TST_SE0_NAK	 0x000B		/* HOST TEST SE0 NAK */
+#define   M66592_H_TST_K	 0x000A		/* HOST TEST K */
+#define   M66592_H_TST_J	 0x0009		/* HOST TEST J */
+#define   M66592_H_TST_NORMAL	 0x0000		/* HOST Normal Mode */
+#define   M66592_P_TST_PACKET	 0x0004		/* PERI TEST Packet */
+#define   M66592_P_TST_SE0_NAK	 0x0003		/* PERI TEST SE0 NAK */
+#define   M66592_P_TST_K	 0x0002		/* PERI TEST K */
+#define   M66592_P_TST_J	 0x0001		/* PERI TEST J */
+#define   M66592_P_TST_NORMAL	 0x0000		/* PERI Normal Mode */
 
 #define M66592_PINCFG		0x0A
-#define	M66592_LDRV		0x8000	/* b15: Drive Current Adjust */
-#define	M66592_BIGEND		0x0100	/* b8: Big endian mode */
+#define M66592_LDRV		0x8000	/* b15: Drive Current Adjust */
+#define M66592_BIGEND		0x0100	/* b8: Big endian mode */
 
 #define M66592_DMA0CFG		0x0C
 #define M66592_DMA1CFG		0x0E
-#define	M66592_DREQA		0x4000	/* b14: Dreq active select */
-#define	M66592_BURST		0x2000	/* b13: Burst mode */
-#define	M66592_DACKA		0x0400	/* b10: Dack active select */
-#define	M66592_DFORM		0x0380	/* b9-7: DMA mode select */
-#define	  M66592_CPU_ADR_RD_WR	 0x0000		  /* Address + RD/WR mode (CPU bus) */
-#define	  M66592_CPU_DACK_RD_WR	 0x0100		  /* DACK + RD/WR mode (CPU bus) */
-#define	  M66592_CPU_DACK_ONLY	 0x0180		  /* DACK only mode (CPU bus) */
-#define	  M66592_SPLIT_DACK_ONLY	 0x0200		  /* DACK only mode (SPLIT bus) */
-#define	  M66592_SPLIT_DACK_DSTB	 0x0300		  /* DACK + DSTB0 mode (SPLIT bus) */
-#define	M66592_DENDA		0x0040	/* b6: Dend active select */
-#define	M66592_PKTM		0x0020	/* b5: Packet mode */
-#define	M66592_DENDE		0x0010	/* b4: Dend enable */
-#define	M66592_OBUS		0x0004	/* b2: OUTbus mode */
+#define M66592_DREQA		0x4000	/* b14: Dreq active select */
+#define M66592_BURST		0x2000	/* b13: Burst mode */
+#define M66592_DACKA		0x0400	/* b10: Dack active select */
+#define M66592_DFORM		0x0380	/* b9-7: DMA mode select */
+#define   M66592_CPU_ADR_RD_WR	 0x0000   /* Address + RD/WR mode (CPU bus) */
+#define   M66592_CPU_DACK_RD_WR	 0x0100   /* DACK + RD/WR mode (CPU bus) */
+#define   M66592_CPU_DACK_ONLY	 0x0180   /* DACK only mode (CPU bus) */
+#define   M66592_SPLIT_DACK_ONLY 0x0200   /* DACK only mode (SPLIT bus) */
+#define   M66592_SPLIT_DACK_DSTB 0x0300   /* DACK + DSTB0 mode (SPLIT bus) */
+#define M66592_DENDA		0x0040	/* b6: Dend active select */
+#define M66592_PKTM		0x0020	/* b5: Packet mode */
+#define M66592_DENDE		0x0010	/* b4: Dend enable */
+#define M66592_OBUS		0x0004	/* b2: OUTbus mode */
 
 #define M66592_CFIFO		0x10
 #define M66592_D0FIFO		0x14
@@ -99,300 +99,300 @@
 #define M66592_CFIFOSEL		0x1E
 #define M66592_D0FIFOSEL	0x24
 #define M66592_D1FIFOSEL	0x2A
-#define	M66592_RCNT		0x8000	/* b15: Read count mode */
-#define	M66592_REW		0x4000	/* b14: Buffer rewind */
-#define	M66592_DCLRM		0x2000	/* b13: DMA buffer clear mode */
-#define	M66592_DREQE		0x1000	/* b12: DREQ output enable */
-#define	M66592_MBW		0x0400	/* b10: Maximum bit width for FIFO access */
-#define	  M66592_MBW_8		 0x0000	  /*  8bit */
-#define	  M66592_MBW_16		 0x0400		  /* 16bit */
-#define	M66592_TRENB		0x0200	/* b9: Transaction counter enable */
-#define	M66592_TRCLR		0x0100	/* b8: Transaction counter clear */
-#define	M66592_DEZPM		0x0080	/* b7: Zero-length packet additional mode */
-#define	M66592_ISEL		0x0020	/* b5: DCP FIFO port direction select */
-#define	M66592_CURPIPE		0x0007	/* b2-0: PIPE select */
+#define M66592_RCNT		0x8000	/* b15: Read count mode */
+#define M66592_REW		0x4000	/* b14: Buffer rewind */
+#define M66592_DCLRM		0x2000	/* b13: DMA buffer clear mode */
+#define M66592_DREQE		0x1000	/* b12: DREQ output enable */
+#define M66592_MBW		0x0400	/* b10: Maximum bit width for FIFO */
+#define   M66592_MBW_8		 0x0000   /*  8bit */
+#define   M66592_MBW_16		 0x0400   /* 16bit */
+#define M66592_TRENB		0x0200	/* b9: Transaction counter enable */
+#define M66592_TRCLR		0x0100	/* b8: Transaction counter clear */
+#define M66592_DEZPM		0x0080	/* b7: Zero-length packet mode */
+#define M66592_ISEL		0x0020	/* b5: DCP FIFO port direction select */
+#define M66592_CURPIPE		0x0007	/* b2-0: PIPE select */
 
 #define M66592_CFIFOCTR		0x20
 #define M66592_D0FIFOCTR	0x26
 #define M66592_D1FIFOCTR	0x2c
-#define	M66592_BVAL		0x8000	/* b15: Buffer valid flag */
-#define	M66592_BCLR		0x4000	/* b14: Buffer clear */
-#define	M66592_FRDY		0x2000	/* b13: FIFO ready */
-#define	M66592_DTLN		0x0FFF	/* b11-0: FIFO received data length */
+#define M66592_BVAL		0x8000	/* b15: Buffer valid flag */
+#define M66592_BCLR		0x4000	/* b14: Buffer clear */
+#define M66592_FRDY		0x2000	/* b13: FIFO ready */
+#define M66592_DTLN		0x0FFF	/* b11-0: FIFO received data length */
 
 #define M66592_CFIFOSIE		0x22
-#define	M66592_TGL		0x8000	/* b15: Buffer toggle */
-#define	M66592_SCLR		0x4000	/* b14: Buffer clear */
-#define	M66592_SBUSY		0x2000	/* b13: SIE_FIFO busy */
+#define M66592_TGL		0x8000	/* b15: Buffer toggle */
+#define M66592_SCLR		0x4000	/* b14: Buffer clear */
+#define M66592_SBUSY		0x2000	/* b13: SIE_FIFO busy */
 
 #define M66592_D0FIFOTRN	0x28
 #define M66592_D1FIFOTRN	0x2E
-#define	M66592_TRNCNT		0xFFFF	/* b15-0: Transaction counter */
+#define M66592_TRNCNT		0xFFFF	/* b15-0: Transaction counter */
 
 #define M66592_INTENB0	0x30
-#define	M66592_VBSE	0x8000	/* b15: VBUS interrupt */
-#define	M66592_RSME	0x4000	/* b14: Resume interrupt */
-#define	M66592_SOFE	0x2000	/* b13: Frame update interrupt */
-#define	M66592_DVSE	0x1000	/* b12: Device state transition interrupt */
-#define	M66592_CTRE	0x0800	/* b11: Control transfer stage transition interrupt */
-#define	M66592_BEMPE	0x0400	/* b10: Buffer empty interrupt */
-#define	M66592_NRDYE	0x0200	/* b9: Buffer not ready interrupt */
-#define	M66592_BRDYE	0x0100	/* b8: Buffer ready interrupt */
-#define	M66592_URST	0x0080	/* b7: USB reset detected interrupt */
-#define	M66592_SADR	0x0040	/* b6: Set address executed interrupt */
-#define	M66592_SCFG	0x0020	/* b5: Set configuration executed interrupt */
-#define	M66592_SUSP	0x0010	/* b4: Suspend detected interrupt */
-#define	M66592_WDST	0x0008	/* b3: Control write data stage completed interrupt */
-#define	M66592_RDST	0x0004	/* b2: Control read data stage completed interrupt */
-#define	M66592_CMPL	0x0002	/* b1: Control transfer complete interrupt */
-#define	M66592_SERR	0x0001	/* b0: Sequence error interrupt */
+#define M66592_VBSE	0x8000	/* b15: VBUS interrupt */
+#define M66592_RSME	0x4000	/* b14: Resume interrupt */
+#define M66592_SOFE	0x2000	/* b13: Frame update interrupt */
+#define M66592_DVSE	0x1000	/* b12: Device state transition interrupt */
+#define M66592_CTRE	0x0800	/* b11: Control transfer stage transition irq */
+#define M66592_BEMPE	0x0400	/* b10: Buffer empty interrupt */
+#define M66592_NRDYE	0x0200	/* b9: Buffer not ready interrupt */
+#define M66592_BRDYE	0x0100	/* b8: Buffer ready interrupt */
+#define M66592_URST	0x0080	/* b7: USB reset detected interrupt */
+#define M66592_SADR	0x0040	/* b6: Set address executed interrupt */
+#define M66592_SCFG	0x0020	/* b5: Set configuration executed interrupt */
+#define M66592_SUSP	0x0010	/* b4: Suspend detected interrupt */
+#define M66592_WDST	0x0008	/* b3: Control write data stage completed irq */
+#define M66592_RDST	0x0004	/* b2: Control read data stage completed irq */
+#define M66592_CMPL	0x0002	/* b1: Control transfer complete interrupt */
+#define M66592_SERR	0x0001	/* b0: Sequence error interrupt */
 
 #define M66592_INTENB1	0x32
-#define	M66592_BCHGE	0x4000	/* b14: USB us chenge interrupt */
-#define	M66592_DTCHE	0x1000	/* b12: Detach sense interrupt */
-#define	M66592_SIGNE	0x0020	/* b5: SETUP IGNORE interrupt */
-#define	M66592_SACKE	0x0010	/* b4: SETUP ACK interrupt */
-#define	M66592_BRDYM	0x0004	/* b2: BRDY clear timing */
-#define	M66592_INTL	0x0002	/* b1: Interrupt sense select */
-#define	M66592_PCSE	0x0001	/* b0: PCUT enable by CS assert */
+#define M66592_BCHGE	0x4000	/* b14: USB us chenge interrupt */
+#define M66592_DTCHE	0x1000	/* b12: Detach sense interrupt */
+#define M66592_SIGNE	0x0020	/* b5: SETUP IGNORE interrupt */
+#define M66592_SACKE	0x0010	/* b4: SETUP ACK interrupt */
+#define M66592_BRDYM	0x0004	/* b2: BRDY clear timing */
+#define M66592_INTL	0x0002	/* b1: Interrupt sense select */
+#define M66592_PCSE	0x0001	/* b0: PCUT enable by CS assert */
 
 #define M66592_BRDYENB		0x36
 #define M66592_BRDYSTS		0x46
-#define	M66592_BRDY7		0x0080	/* b7: PIPE7 */
-#define	M66592_BRDY6		0x0040	/* b6: PIPE6 */
-#define	M66592_BRDY5		0x0020	/* b5: PIPE5 */
-#define	M66592_BRDY4		0x0010	/* b4: PIPE4 */
-#define	M66592_BRDY3		0x0008	/* b3: PIPE3 */
-#define	M66592_BRDY2		0x0004	/* b2: PIPE2 */
-#define	M66592_BRDY1		0x0002	/* b1: PIPE1 */
-#define	M66592_BRDY0		0x0001	/* b1: PIPE0 */
+#define M66592_BRDY7		0x0080	/* b7: PIPE7 */
+#define M66592_BRDY6		0x0040	/* b6: PIPE6 */
+#define M66592_BRDY5		0x0020	/* b5: PIPE5 */
+#define M66592_BRDY4		0x0010	/* b4: PIPE4 */
+#define M66592_BRDY3		0x0008	/* b3: PIPE3 */
+#define M66592_BRDY2		0x0004	/* b2: PIPE2 */
+#define M66592_BRDY1		0x0002	/* b1: PIPE1 */
+#define M66592_BRDY0		0x0001	/* b1: PIPE0 */
 
 #define M66592_NRDYENB		0x38
 #define M66592_NRDYSTS		0x48
-#define	M66592_NRDY7		0x0080	/* b7: PIPE7 */
-#define	M66592_NRDY6		0x0040	/* b6: PIPE6 */
-#define	M66592_NRDY5		0x0020	/* b5: PIPE5 */
-#define	M66592_NRDY4		0x0010	/* b4: PIPE4 */
-#define	M66592_NRDY3		0x0008	/* b3: PIPE3 */
-#define	M66592_NRDY2		0x0004	/* b2: PIPE2 */
-#define	M66592_NRDY1		0x0002	/* b1: PIPE1 */
-#define	M66592_NRDY0		0x0001	/* b1: PIPE0 */
+#define M66592_NRDY7		0x0080	/* b7: PIPE7 */
+#define M66592_NRDY6		0x0040	/* b6: PIPE6 */
+#define M66592_NRDY5		0x0020	/* b5: PIPE5 */
+#define M66592_NRDY4		0x0010	/* b4: PIPE4 */
+#define M66592_NRDY3		0x0008	/* b3: PIPE3 */
+#define M66592_NRDY2		0x0004	/* b2: PIPE2 */
+#define M66592_NRDY1		0x0002	/* b1: PIPE1 */
+#define M66592_NRDY0		0x0001	/* b1: PIPE0 */
 
 #define M66592_BEMPENB		0x3A
 #define M66592_BEMPSTS		0x4A
-#define	M66592_BEMP7		0x0080	/* b7: PIPE7 */
-#define	M66592_BEMP6		0x0040	/* b6: PIPE6 */
-#define	M66592_BEMP5		0x0020	/* b5: PIPE5 */
-#define	M66592_BEMP4		0x0010	/* b4: PIPE4 */
-#define	M66592_BEMP3		0x0008	/* b3: PIPE3 */
-#define	M66592_BEMP2		0x0004	/* b2: PIPE2 */
-#define	M66592_BEMP1		0x0002	/* b1: PIPE1 */
-#define	M66592_BEMP0		0x0001	/* b0: PIPE0 */
+#define M66592_BEMP7		0x0080	/* b7: PIPE7 */
+#define M66592_BEMP6		0x0040	/* b6: PIPE6 */
+#define M66592_BEMP5		0x0020	/* b5: PIPE5 */
+#define M66592_BEMP4		0x0010	/* b4: PIPE4 */
+#define M66592_BEMP3		0x0008	/* b3: PIPE3 */
+#define M66592_BEMP2		0x0004	/* b2: PIPE2 */
+#define M66592_BEMP1		0x0002	/* b1: PIPE1 */
+#define M66592_BEMP0		0x0001	/* b0: PIPE0 */
 
 #define M66592_SOFCFG		0x3C
-#define	M66592_SOFM		0x000C	/* b3-2: SOF palse mode */
-#define	  M66592_SOF_125US	 0x0008		  /* SOF OUT 125us uFrame Signal */
-#define	  M66592_SOF_1MS	 0x0004		  /* SOF OUT 1ms Frame Signal */
-#define	  M66592_SOF_DISABLE	 0x0000		  /* SOF OUT Disable */
+#define M66592_SOFM		0x000C	/* b3-2: SOF palse mode */
+#define   M66592_SOF_125US	 0x0008   /* SOF OUT 125us uFrame Signal */
+#define   M66592_SOF_1MS	 0x0004   /* SOF OUT 1ms Frame Signal */
+#define   M66592_SOF_DISABLE	 0x0000   /* SOF OUT Disable */
 
 #define M66592_INTSTS0		0x40
-#define	M66592_VBINT		0x8000	/* b15: VBUS interrupt */
-#define	M66592_RESM		0x4000	/* b14: Resume interrupt */
-#define	M66592_SOFR		0x2000	/* b13: SOF frame update interrupt */
-#define	M66592_DVST		0x1000	/* b12: Device state transition interrupt */
-#define	M66592_CTRT		0x0800	/* b11: Control transfer stage transition interrupt */
-#define	M66592_BEMP		0x0400	/* b10: Buffer empty interrupt */
-#define	M66592_NRDY		0x0200	/* b9: Buffer not ready interrupt */
-#define	M66592_BRDY		0x0100	/* b8: Buffer ready interrupt */
-#define	M66592_VBSTS		0x0080	/* b7: VBUS input port */
-#define	M66592_DVSQ		0x0070	/* b6-4: Device state */
-#define	  M66592_DS_SPD_CNFG	 0x0070		  /* Suspend Configured */
-#define	  M66592_DS_SPD_ADDR	 0x0060		  /* Suspend Address */
-#define	  M66592_DS_SPD_DFLT	 0x0050		  /* Suspend Default */
-#define	  M66592_DS_SPD_POWR	 0x0040		  /* Suspend Powered */
-#define	  M66592_DS_SUSP	 0x0040		  /* Suspend */
-#define	  M66592_DS_CNFG	 0x0030		  /* Configured */
-#define	  M66592_DS_ADDS	 0x0020		  /* Address */
-#define	  M66592_DS_DFLT	 0x0010		  /* Default */
-#define	  M66592_DS_POWR	 0x0000		  /* Powered */
-#define	M66592_DVSQS		0x0030	/* b5-4: Device state */
-#define	M66592_VALID		0x0008	/* b3: Setup packet detected flag */
-#define	M66592_CTSQ		0x0007	/* b2-0: Control transfer stage */
-#define	  M66592_CS_SQER	 0x0006		  /* Sequence error */
-#define	  M66592_CS_WRND	 0x0005		  /* Control write nodata status stage */
-#define	  M66592_CS_WRSS	 0x0004		  /* Control write status stage */
-#define	  M66592_CS_WRDS	 0x0003		  /* Control write data stage */
-#define	  M66592_CS_RDSS	 0x0002		  /* Control read status stage */
-#define	  M66592_CS_RDDS	 0x0001		  /* Control read data stage */
-#define	  M66592_CS_IDST	 0x0000		  /* Idle or setup stage */
+#define M66592_VBINT		0x8000	/* b15: VBUS interrupt */
+#define M66592_RESM		0x4000	/* b14: Resume interrupt */
+#define M66592_SOFR		0x2000	/* b13: SOF frame update interrupt */
+#define M66592_DVST		0x1000	/* b12: Device state transition */
+#define M66592_CTRT		0x0800	/* b11: Control stage transition */
+#define M66592_BEMP		0x0400	/* b10: Buffer empty interrupt */
+#define M66592_NRDY		0x0200	/* b9: Buffer not ready interrupt */
+#define M66592_BRDY		0x0100	/* b8: Buffer ready interrupt */
+#define M66592_VBSTS		0x0080	/* b7: VBUS input port */
+#define M66592_DVSQ		0x0070	/* b6-4: Device state */
+#define   M66592_DS_SPD_CNFG	 0x0070	   /* Suspend Configured */
+#define   M66592_DS_SPD_ADDR	 0x0060	   /* Suspend Address */
+#define   M66592_DS_SPD_DFLT	 0x0050	   /* Suspend Default */
+#define   M66592_DS_SPD_POWR	 0x0040	   /* Suspend Powered */
+#define   M66592_DS_SUSP	 0x0040	   /* Suspend */
+#define   M66592_DS_CNFG	 0x0030	   /* Configured */
+#define   M66592_DS_ADDS	 0x0020	   /* Address */
+#define   M66592_DS_DFLT	 0x0010	   /* Default */
+#define   M66592_DS_POWR	 0x0000	   /* Powered */
+#define M66592_DVSQS		0x0030	/* b5-4: Device state */
+#define M66592_VALID		0x0008	/* b3: Setup packet detected flag */
+#define M66592_CTSQ		0x0007	/* b2-0: Control transfer stage */
+#define   M66592_CS_SQER	 0x0006	  /* Sequence error */
+#define   M66592_CS_WRND	 0x0005	  /* Control write nodata status */
+#define   M66592_CS_WRSS	 0x0004	  /* Control write status stage */
+#define   M66592_CS_WRDS	 0x0003	  /* Control write data stage */
+#define   M66592_CS_RDSS	 0x0002	  /* Control read status stage */
+#define   M66592_CS_RDDS	 0x0001	  /* Control read data stage */
+#define   M66592_CS_IDST	 0x0000	  /* Idle or setup stage */
 
 #define M66592_INTSTS1		0x42
-#define	M66592_BCHG		0x4000	/* b14: USB bus chenge interrupt */
-#define	M66592_DTCH		0x1000	/* b12: Detach sense interrupt */
-#define	M66592_SIGN		0x0020	/* b5: SETUP IGNORE interrupt */
-#define	M66592_SACK		0x0010	/* b4: SETUP ACK interrupt */
+#define M66592_BCHG		0x4000	/* b14: USB bus chenge interrupt */
+#define M66592_DTCH		0x1000	/* b12: Detach sense interrupt */
+#define M66592_SIGN		0x0020	/* b5: SETUP IGNORE interrupt */
+#define M66592_SACK		0x0010	/* b4: SETUP ACK interrupt */
 
 #define M66592_FRMNUM		0x4C
-#define	M66592_OVRN		0x8000	/* b15: Overrun error */
-#define	M66592_CRCE		0x4000	/* b14: Received data error */
-#define	M66592_SOFRM		0x0800	/* b11: SOF output mode */
-#define	M66592_FRNM		0x07FF	/* b10-0: Frame number */
+#define M66592_OVRN		0x8000	/* b15: Overrun error */
+#define M66592_CRCE		0x4000	/* b14: Received data error */
+#define M66592_SOFRM		0x0800	/* b11: SOF output mode */
+#define M66592_FRNM		0x07FF	/* b10-0: Frame number */
 
 #define M66592_UFRMNUM		0x4E
-#define	M66592_UFRNM		0x0007	/* b2-0: Micro frame number */
+#define M66592_UFRNM		0x0007	/* b2-0: Micro frame number */
 
 #define M66592_RECOVER		0x50
-#define	M66592_STSRECOV		0x0700	/* Status recovery */
-#define	  M66592_STSR_HI	 0x0400		  /* FULL(0) or HI(1) Speed */
-#define	  M66592_STSR_DEFAULT	 0x0100		  /* Default state */
-#define	  M66592_STSR_ADDRESS	 0x0200		  /* Address state */
-#define	  M66592_STSR_CONFIG	 0x0300		  /* Configured state */
-#define	M66592_USBADDR		0x007F	/* b6-0: USB address */
+#define M66592_STSRECOV		0x0700	/* Status recovery */
+#define   M66592_STSR_HI	 0x0400		  /* FULL(0) or HI(1) Speed */
+#define   M66592_STSR_DEFAULT	 0x0100		  /* Default state */
+#define   M66592_STSR_ADDRESS	 0x0200		  /* Address state */
+#define   M66592_STSR_CONFIG	 0x0300		  /* Configured state */
+#define M66592_USBADDR		0x007F	/* b6-0: USB address */
 
 #define M66592_USBREQ			0x54
-#define	M66592_bRequest			0xFF00	/* b15-8: bRequest */
-#define	  M66592_GET_STATUS		 0x0000
-#define	  M66592_CLEAR_FEATURE		 0x0100
-#define	  M66592_ReqRESERVED		 0x0200
-#define	  M66592_SET_FEATURE		 0x0300
-#define	  M66592_ReqRESERVED1		 0x0400
-#define	  M66592_SET_ADDRESS		 0x0500
-#define	  M66592_GET_DESCRIPTOR		 0x0600
-#define	  M66592_SET_DESCRIPTOR		 0x0700
-#define	  M66592_GET_CONFIGURATION	 0x0800
-#define	  M66592_SET_CONFIGURATION	 0x0900
-#define	  M66592_GET_INTERFACE		 0x0A00
-#define	  M66592_SET_INTERFACE		 0x0B00
-#define	  M66592_SYNCH_FRAME		 0x0C00
-#define	M66592_bmRequestType		0x00FF	/* b7-0: bmRequestType */
-#define	M66592_bmRequestTypeDir		0x0080	/* b7  : Data transfer direction */
-#define	  M66592_HOST_TO_DEVICE		 0x0000
-#define	  M66592_DEVICE_TO_HOST		 0x0080
-#define	M66592_bmRequestTypeType	0x0060	/* b6-5: Type */
-#define	  M66592_STANDARD		 0x0000
-#define	  M66592_CLASS			 0x0020
-#define	  M66592_VENDOR			 0x0040
-#define	M66592_bmRequestTypeRecip	0x001F	/* b4-0: Recipient */
-#define	  M66592_DEVICE			 0x0000
-#define	  M66592_INTERFACE		 0x0001
-#define	  M66592_ENDPOINT		 0x0002
+#define M66592_bRequest			0xFF00	/* b15-8: bRequest */
+#define   M66592_GET_STATUS		 0x0000
+#define   M66592_CLEAR_FEATURE		 0x0100
+#define   M66592_ReqRESERVED		 0x0200
+#define   M66592_SET_FEATURE		 0x0300
+#define   M66592_ReqRESERVED1		 0x0400
+#define   M66592_SET_ADDRESS		 0x0500
+#define   M66592_GET_DESCRIPTOR		 0x0600
+#define   M66592_SET_DESCRIPTOR		 0x0700
+#define   M66592_GET_CONFIGURATION	 0x0800
+#define   M66592_SET_CONFIGURATION	 0x0900
+#define   M66592_GET_INTERFACE		 0x0A00
+#define   M66592_SET_INTERFACE		 0x0B00
+#define   M66592_SYNCH_FRAME		 0x0C00
+#define M66592_bmRequestType		0x00FF	/* b7-0: bmRequestType */
+#define M66592_bmRequestTypeDir		0x0080	/* b7  : Data direction */
+#define   M66592_HOST_TO_DEVICE		 0x0000
+#define   M66592_DEVICE_TO_HOST		 0x0080
+#define M66592_bmRequestTypeType	0x0060	/* b6-5: Type */
+#define   M66592_STANDARD		 0x0000
+#define   M66592_CLASS			 0x0020
+#define   M66592_VENDOR			 0x0040
+#define M66592_bmRequestTypeRecip	0x001F	/* b4-0: Recipient */
+#define   M66592_DEVICE			 0x0000
+#define   M66592_INTERFACE		 0x0001
+#define   M66592_ENDPOINT		 0x0002
 
 #define M66592_USBVAL				0x56
-#define	M66592_wValue				0xFFFF	/* b15-0: wValue */
+#define M66592_wValue				0xFFFF	/* b15-0: wValue */
 /* Standard Feature Selector */
-#define	  M66592_ENDPOINT_HALT			0x0000
-#define	  M66592_DEVICE_REMOTE_WAKEUP		0x0001
-#define	  M66592_TEST_MODE			0x0002
+#define   M66592_ENDPOINT_HALT			0x0000
+#define   M66592_DEVICE_REMOTE_WAKEUP		0x0001
+#define   M66592_TEST_MODE			0x0002
 /* Descriptor Types */
-#define	M66592_DT_TYPE				0xFF00
-#define	M66592_GET_DT_TYPE(v)			(((v) & DT_TYPE) >> 8)
-#define	  M66592_DT_DEVICE			0x01
-#define	  M66592_DT_CONFIGURATION		0x02
-#define	  M66592_DT_STRING			0x03
-#define	  M66592_DT_INTERFACE			0x04
-#define	  M66592_DT_ENDPOINT			0x05
-#define	  M66592_DT_DEVICE_QUALIFIER		0x06
-#define	  M66592_DT_OTHER_SPEED_CONFIGURATION	0x07
-#define	  M66592_DT_INTERFACE_POWER		0x08
-#define	M66592_DT_INDEX				0x00FF
-#define	M66592_CONF_NUM				0x00FF
-#define	M66592_ALT_SET				0x00FF
+#define M66592_DT_TYPE				0xFF00
+#define M66592_GET_DT_TYPE(v)			(((v) & DT_TYPE) >> 8)
+#define   M66592_DT_DEVICE			0x01
+#define   M66592_DT_CONFIGURATION		0x02
+#define   M66592_DT_STRING			0x03
+#define   M66592_DT_INTERFACE			0x04
+#define   M66592_DT_ENDPOINT			0x05
+#define   M66592_DT_DEVICE_QUALIFIER		0x06
+#define   M66592_DT_OTHER_SPEED_CONFIGURATION	0x07
+#define   M66592_DT_INTERFACE_POWER		0x08
+#define M66592_DT_INDEX				0x00FF
+#define M66592_CONF_NUM				0x00FF
+#define M66592_ALT_SET				0x00FF
 
 #define M66592_USBINDEX			0x58
-#define	M66592_wIndex			0xFFFF	/* b15-0: wIndex */
-#define	M66592_TEST_SELECT		0xFF00	/* b15-b8: Test Mode Selectors */
-#define	  M66592_TEST_J			 0x0100		  /* Test_J */
-#define	  M66592_TEST_K			 0x0200		  /* Test_K */
-#define	  M66592_TEST_SE0_NAK		 0x0300		  /* Test_SE0_NAK */
-#define	  M66592_TEST_PACKET		 0x0400		  /* Test_Packet */
-#define	  M66592_TEST_FORCE_ENABLE	 0x0500		  /* Test_Force_Enable */
-#define	  M66592_TEST_STSelectors	 0x0600		  /* Standard test selectors */
-#define	  M66592_TEST_Reserved		 0x4000		  /* Reserved */
-#define	  M66592_TEST_VSTModes		 0xC000		  /* Vendor-specific test modes */
-#define	M66592_EP_DIR			0x0080	/* b7: Endpoint Direction */
-#define	  M66592_EP_DIR_IN		 0x0080
-#define	  M66592_EP_DIR_OUT		 0x0000
+#define M66592_wIndex			0xFFFF	/* b15-0: wIndex */
+#define M66592_TEST_SELECT		0xFF00	/* b15-b8: Test Mode */
+#define   M66592_TEST_J			 0x0100	  /* Test_J */
+#define   M66592_TEST_K			 0x0200	  /* Test_K */
+#define   M66592_TEST_SE0_NAK		 0x0300	  /* Test_SE0_NAK */
+#define   M66592_TEST_PACKET		 0x0400	  /* Test_Packet */
+#define   M66592_TEST_FORCE_ENABLE	 0x0500	  /* Test_Force_Enable */
+#define   M66592_TEST_STSelectors	 0x0600	  /* Standard test selectors */
+#define   M66592_TEST_Reserved		 0x4000	  /* Reserved */
+#define   M66592_TEST_VSTModes		 0xC000	  /* Vendor-specific tests */
+#define M66592_EP_DIR			0x0080	/* b7: Endpoint Direction */
+#define   M66592_EP_DIR_IN		 0x0080
+#define   M66592_EP_DIR_OUT		 0x0000
 
 #define M66592_USBLENG		0x5A
-#define	M66592_wLength		0xFFFF	/* b15-0: wLength */
+#define M66592_wLength		0xFFFF	/* b15-0: wLength */
 
 #define M66592_DCPCFG		0x5C
-#define	M66592_CNTMD		0x0100	/* b8: Continuous transfer mode select */
-#define	M66592_DIR		0x0010	/* b4: Control transfer DIR select */
+#define M66592_CNTMD		0x0100	/* b8: Continuous transfer mode */
+#define M66592_DIR		0x0010	/* b4: Control transfer DIR select */
 
 #define M66592_DCPMAXP		0x5E
-#define	M66592_DEVSEL		0xC000	/* b15-14: Device address select */
-#define	  M66592_DEVICE_0	 0x0000		  /* Device address 0 */
-#define	  M66592_DEVICE_1	 0x4000		  /* Device address 1 */
-#define	  M66592_DEVICE_2	 0x8000		  /* Device address 2 */
-#define	  M66592_DEVICE_3	 0xC000		  /* Device address 3 */
-#define	M66592_MAXP		0x007F	/* b6-0: Maxpacket size of default control pipe */
+#define M66592_DEVSEL		0xC000	/* b15-14: Device address select */
+#define   M66592_DEVICE_0	 0x0000		  /* Device address 0 */
+#define   M66592_DEVICE_1	 0x4000		  /* Device address 1 */
+#define   M66592_DEVICE_2	 0x8000		  /* Device address 2 */
+#define   M66592_DEVICE_3	 0xC000		  /* Device address 3 */
+#define M66592_MAXP		0x007F	/* b6-0: Maxpacket size of ep0 */
 
 #define M66592_DCPCTR		0x60
-#define	M66592_BSTS		0x8000	/* b15: Buffer status */
-#define	M66592_SUREQ		0x4000	/* b14: Send USB request  */
-#define	M66592_SQCLR		0x0100	/* b8: Sequence toggle bit clear */
-#define	M66592_SQSET		0x0080	/* b7: Sequence toggle bit set */
-#define	M66592_SQMON		0x0040	/* b6: Sequence toggle bit monitor */
-#define	M66592_CCPL		0x0004	/* b2: Enable control transfer complete */
-#define	M66592_PID		0x0003	/* b1-0: Response PID */
-#define	  M66592_PID_STALL	 0x0002		  /* STALL */
-#define	  M66592_PID_BUF	 0x0001		  /* BUF */
-#define	  M66592_PID_NAK	 0x0000		  /* NAK */
+#define M66592_BSTS		0x8000	/* b15: Buffer status */
+#define M66592_SUREQ		0x4000	/* b14: Send USB request  */
+#define M66592_SQCLR		0x0100	/* b8: Sequence toggle bit clear */
+#define M66592_SQSET		0x0080	/* b7: Sequence toggle bit set */
+#define M66592_SQMON		0x0040	/* b6: Sequence toggle bit monitor */
+#define M66592_CCPL		0x0004	/* b2: control transfer complete */
+#define M66592_PID		0x0003	/* b1-0: Response PID */
+#define   M66592_PID_STALL	 0x0002		  /* STALL */
+#define   M66592_PID_BUF	 0x0001		  /* BUF */
+#define   M66592_PID_NAK	 0x0000		  /* NAK */
 
 #define M66592_PIPESEL		0x64
-#define	M66592_PIPENM		0x0007	/* b2-0: Pipe select */
-#define	  M66592_PIPE0		 0x0000		  /* PIPE 0 */
-#define	  M66592_PIPE1		 0x0001		  /* PIPE 1 */
-#define	  M66592_PIPE2		 0x0002		  /* PIPE 2 */
-#define	  M66592_PIPE3		 0x0003		  /* PIPE 3 */
-#define	  M66592_PIPE4		 0x0004		  /* PIPE 4 */
-#define	  M66592_PIPE5		 0x0005		  /* PIPE 5 */
-#define	  M66592_PIPE6		 0x0006		  /* PIPE 6 */
-#define	  M66592_PIPE7		 0x0007		  /* PIPE 7 */
+#define M66592_PIPENM		0x0007	/* b2-0: Pipe select */
+#define   M66592_PIPE0		 0x0000		  /* PIPE 0 */
+#define   M66592_PIPE1		 0x0001		  /* PIPE 1 */
+#define   M66592_PIPE2		 0x0002		  /* PIPE 2 */
+#define   M66592_PIPE3		 0x0003		  /* PIPE 3 */
+#define   M66592_PIPE4		 0x0004		  /* PIPE 4 */
+#define   M66592_PIPE5		 0x0005		  /* PIPE 5 */
+#define   M66592_PIPE6		 0x0006		  /* PIPE 6 */
+#define   M66592_PIPE7		 0x0007		  /* PIPE 7 */
 
 #define M66592_PIPECFG		0x66
-#define	M66592_TYP		0xC000	/* b15-14: Transfer type */
-#define	  M66592_ISO		 0xC000		  /* Isochronous */
-#define	  M66592_INT		 0x8000		  /* Interrupt */
-#define	  M66592_BULK		 0x4000		  /* Bulk */
-#define	M66592_BFRE		0x0400	/* b10: Buffer ready interrupt mode select */
-#define	M66592_DBLB		0x0200	/* b9: Double buffer mode select */
-#define	M66592_CNTMD		0x0100	/* b8: Continuous transfer mode select */
-#define	M66592_SHTNAK		0x0080	/* b7: Transfer end NAK */
-#define	M66592_DIR		0x0010	/* b4: Transfer direction select */
-#define	  M66592_DIR_H_OUT	 0x0010		  /* HOST OUT */
-#define	  M66592_DIR_P_IN	 0x0010		  /* PERI IN */
-#define	  M66592_DIR_H_IN	 0x0000		  /* HOST IN */
-#define	  M66592_DIR_P_OUT	 0x0000		  /* PERI OUT */
-#define	M66592_EPNUM		0x000F	/* b3-0: Eendpoint number select */
-#define	  M66592_EP1		 0x0001
-#define	  M66592_EP2		 0x0002
-#define	  M66592_EP3		 0x0003
-#define	  M66592_EP4		 0x0004
-#define	  M66592_EP5		 0x0005
-#define	  M66592_EP6		 0x0006
-#define	  M66592_EP7		 0x0007
-#define	  M66592_EP8		 0x0008
-#define	  M66592_EP9		 0x0009
-#define	  M66592_EP10		 0x000A
-#define	  M66592_EP11		 0x000B
-#define	  M66592_EP12		 0x000C
-#define	  M66592_EP13		 0x000D
-#define	  M66592_EP14		 0x000E
-#define	  M66592_EP15		 0x000F
+#define M66592_TYP		0xC000	/* b15-14: Transfer type */
+#define   M66592_ISO		 0xC000		  /* Isochronous */
+#define   M66592_INT		 0x8000		  /* Interrupt */
+#define   M66592_BULK		 0x4000		  /* Bulk */
+#define M66592_BFRE		0x0400	/* b10: Buffer ready interrupt mode */
+#define M66592_DBLB		0x0200	/* b9: Double buffer mode select */
+#define M66592_CNTMD		0x0100	/* b8: Continuous transfer mode */
+#define M66592_SHTNAK		0x0080	/* b7: Transfer end NAK */
+#define M66592_DIR		0x0010	/* b4: Transfer direction select */
+#define   M66592_DIR_H_OUT	 0x0010		  /* HOST OUT */
+#define   M66592_DIR_P_IN	 0x0010		  /* PERI IN */
+#define   M66592_DIR_H_IN	 0x0000		  /* HOST IN */
+#define   M66592_DIR_P_OUT	 0x0000		  /* PERI OUT */
+#define M66592_EPNUM		0x000F	/* b3-0: Eendpoint number select */
+#define   M66592_EP1		 0x0001
+#define   M66592_EP2		 0x0002
+#define   M66592_EP3		 0x0003
+#define   M66592_EP4		 0x0004
+#define   M66592_EP5		 0x0005
+#define   M66592_EP6		 0x0006
+#define   M66592_EP7		 0x0007
+#define   M66592_EP8		 0x0008
+#define   M66592_EP9		 0x0009
+#define   M66592_EP10		 0x000A
+#define   M66592_EP11		 0x000B
+#define   M66592_EP12		 0x000C
+#define   M66592_EP13		 0x000D
+#define   M66592_EP14		 0x000E
+#define   M66592_EP15		 0x000F
 
 #define M66592_PIPEBUF		0x68
-#define	M66592_BUFSIZE		0x7C00	/* b14-10: Pipe buffer size */
-#define	M66592_BUF_SIZE(x)	((((x) / 64) - 1) << 10)
-#define	M66592_BUFNMB		0x00FF	/* b7-0: Pipe buffer number */
+#define M66592_BUFSIZE		0x7C00	/* b14-10: Pipe buffer size */
+#define M66592_BUF_SIZE(x)	((((x) / 64) - 1) << 10)
+#define M66592_BUFNMB		0x00FF	/* b7-0: Pipe buffer number */
 
 #define M66592_PIPEMAXP		0x6A
-#define	M66592_MXPS		0x07FF	/* b10-0: Maxpacket size */
+#define M66592_MXPS		0x07FF	/* b10-0: Maxpacket size */
 
 #define M66592_PIPEPERI		0x6C
-#define	M66592_IFIS		0x1000	/* b12: Isochronous in-buffer flush mode select */
-#define	M66592_IITV		0x0007	/* b2-0: Isochronous interval */
+#define M66592_IFIS		0x1000	/* b12: ISO in-buffer flush mode */
+#define M66592_IITV		0x0007	/* b2-0: ISO interval */
 
 #define M66592_PIPE1CTR		0x70
 #define M66592_PIPE2CTR		0x72
@@ -401,19 +401,17 @@
 #define M66592_PIPE5CTR		0x78
 #define M66592_PIPE6CTR		0x7A
 #define M66592_PIPE7CTR		0x7C
-#define	M66592_BSTS		0x8000	/* b15: Buffer status */
-#define	M66592_INBUFM		0x4000	/* b14: IN buffer monitor (Only for PIPE1 to 5) */
-#define	M66592_ACLRM		0x0200	/* b9: Out buffer auto clear mode */
-#define	M66592_SQCLR		0x0100	/* b8: Sequence toggle bit clear */
-#define	M66592_SQSET		0x0080	/* b7: Sequence toggle bit set */
-#define	M66592_SQMON		0x0040	/* b6: Sequence toggle bit monitor */
-#define	M66592_PID		0x0003	/* b1-0: Response PID */
+#define M66592_BSTS		0x8000	/* b15: Buffer status */
+#define M66592_INBUFM		0x4000	/* b14: IN buffer monitor (PIPE 1-5) */
+#define M66592_ACLRM		0x0200	/* b9: Out buffer auto clear mode */
+#define M66592_SQCLR		0x0100	/* b8: Sequence toggle bit clear */
+#define M66592_SQSET		0x0080	/* b7: Sequence toggle bit set */
+#define M66592_SQMON		0x0040	/* b6: Sequence toggle bit monitor */
+#define M66592_PID		0x0003	/* b1-0: Response PID */
 
 #define M66592_INVALID_REG	0x7E
 
 
-#define __iomem
-
 #define get_pipectr_addr(pipenum)	(M66592_PIPE1CTR + (pipenum - 1) * 2)
 
 #define M66592_MAX_SAMPLING	10
@@ -449,7 +447,7 @@
 	struct m66592		*m66592;
 
 	struct list_head	queue;
-	unsigned 		busy:1;
+	unsigned		busy:1;
 	unsigned		internal_ccpl:1;	/* use only control */
 
 	/* this member can able to after m66592_enable */
@@ -477,7 +475,7 @@
 	struct m66592_ep	*epaddr2ep[16];
 
 	struct usb_request	*ep0_req;	/* for internal request */
-	u16			*ep0_buf;	/* for internal request */
+	u16			ep0_data;	/* for internal request */
 
 	struct timer_list	timer;
 
@@ -527,8 +525,8 @@
 }
 
 static inline void m66592_read_fifo(struct m66592 *m66592,
-				    unsigned long offset,
-				    void *buf, unsigned long len)
+		unsigned long offset,
+		void *buf, unsigned long len)
 {
 	unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
 
@@ -543,8 +541,8 @@
 }
 
 static inline void m66592_write_fifo(struct m66592 *m66592,
-				     unsigned long offset,
-				     void *buf, unsigned long len)
+		unsigned long offset,
+		void *buf, unsigned long len)
 {
 	unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
 	unsigned long odd = len & 0x0001;
@@ -558,7 +556,7 @@
 }
 
 static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
-			       unsigned long offset)
+		unsigned long offset)
 {
 	u16 tmp;
 	tmp = m66592_read(m66592, offset);
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index c3d364e..d5d473f 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -62,7 +62,7 @@
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 9b0f092..87c4f50 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -38,7 +38,7 @@
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
 #include <linux/clk.h>
@@ -1241,19 +1241,15 @@
 	udc->gadget.dev.parent->power.power_state = PMSG_ON;
 	udc->gadget.dev.power.power_state = PMSG_ON;
 	UDC_SYSCON1_REG |= UDC_PULLUP_EN;
-#ifndef CONFIG_USB_OTG
-	if (!cpu_is_omap15xx())
+	if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
 		OTG_CTRL_REG |= OTG_BSESSVLD;
-#endif
 	UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
 }
 
 static void pullup_disable(struct omap_udc *udc)
 {
-#ifndef CONFIG_USB_OTG
-	if (!cpu_is_omap15xx())
+	if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
 		OTG_CTRL_REG &= ~OTG_BSESSVLD;
-#endif
 	UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
 	UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
 }
@@ -1390,7 +1386,7 @@
 {
 	u16	devstat;
 
-	if (!udc->gadget.is_otg)
+	if (!gadget_is_otg(udc->gadget))
 		return;
 
 	if (OTG_CTRL_REG & OTG_ID)
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index 63b9521..3e71508 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -54,7 +54,7 @@
 #include <asm/hardware.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/mach/udc_pxa2xx.h>
 
@@ -93,8 +93,6 @@
 static const char ep0name [] = "ep0";
 
 
-// #define	DISABLE_TEST_MODE
-
 #ifdef CONFIG_ARCH_IXP4XX
 
 /* cpu-specific register addresses are compiled in to this code */
@@ -113,17 +111,6 @@
 #define SIZE_STR	""
 #endif
 
-#ifdef DISABLE_TEST_MODE
-/* (mode == 0) == no undocumented chip tweaks
- * (mode & 1)  == double buffer bulk IN
- * (mode & 2)  == double buffer bulk OUT
- * ... so mode = 3 (or 7, 15, etc) does it for both
- */
-static ushort fifo_mode = 0;
-module_param(fifo_mode, ushort, 0);
-MODULE_PARM_DESC (fifo_mode, "pxa2xx udc fifo mode");
-#endif
-
 /* ---------------------------------------------------------------------------
  *	endpoint related parts of the api to the usb controller hardware,
  *	used by gadget driver; and the inner talker-to-hardware core.
@@ -980,7 +967,7 @@
 	udc = container_of(_gadget, struct pxa2xx_udc, gadget);
 
 	/* not all boards support pullup control */
-	if (!udc->mach->udc_command)
+	if (!udc->mach->gpio_pullup && !udc->mach->udc_command)
 		return -EOPNOTSUPP;
 
 	is_active = (is_active != 0);
@@ -1252,23 +1239,6 @@
 		UDC_RES2 = 0x00;
 	}
 
-#ifdef	DISABLE_TEST_MODE
-	/* "test mode" seems to have become the default in later chip
-	 * revs, preventing double buffering (and invalidating docs).
-	 * this EXPERIMENT enables it for bulk endpoints by tweaking
-	 * undefined/reserved register bits (that other drivers clear).
-	 * Belcarra code comments noted this usage.
-	 */
-	if (fifo_mode & 1) {	/* IN endpoints */
-		UDC_RES1 |= USIR0_IR1|USIR0_IR6;
-		UDC_RES2 |= USIR1_IR11;
-	}
-	if (fifo_mode & 2) {	/* OUT endpoints */
-		UDC_RES1 |= USIR0_IR2|USIR0_IR7;
-		UDC_RES2 |= USIR1_IR12;
-	}
-#endif
-
 	/* enable suspend/resume and reset irqs */
 	udc_clear_mask_UDCCR(UDCCR_SRM | UDCCR_REM);
 
@@ -2339,7 +2309,7 @@
 {
 	struct pxa2xx_udc	*udc = platform_get_drvdata(dev);
 
-	if (!udc->mach->udc_command)
+	if (!udc->mach->gpio_pullup && !udc->mach->udc_command)
 		WARN("USB host won't detect disconnect!\n");
 	pullup(udc, 0);
 
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 0be80c6..e3e90f8 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -42,7 +42,7 @@
 #include <linux/seq_file.h>
 
 #include <linux/usb.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index dd33ff0..f5738eb 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -17,33 +17,15 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/utsname.h>
-#include <linux/wait.h>
-#include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
-#include <asm/uaccess.h>
-
 #include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
@@ -88,30 +70,29 @@
 #define GS_DEFAULT_PARITY		USB_CDC_NO_PARITY
 #define GS_DEFAULT_CHAR_FORMAT		USB_CDC_1_STOP_BITS
 
-/* select highspeed/fullspeed, hiding highspeed if not configured */
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs))
-#else
-#define GS_SPEED_SELECT(is_hs,hs,fs) (fs)
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+/* maxpacket and other transfer characteristics vary by speed. */
+static inline struct usb_endpoint_descriptor *
+choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+		struct usb_endpoint_descriptor *fs)
+{
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
+}
+
 
 /* debug settings */
-#ifdef GS_DEBUG
+#ifdef DEBUG
 static int debug = 1;
+#else
+#define	debug 0
+#endif
 
 #define gs_debug(format, arg...) \
 	do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
 #define gs_debug_level(level, format, arg...) \
 	do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0)
 
-#else
-
-#define gs_debug(format, arg...) \
-	do { } while(0)
-#define gs_debug_level(level, format, arg...) \
-	do { } while(0)
-
-#endif /* GS_DEBUG */
 
 /* Thanks to NetChip Technologies for donating this product ID.
  *
@@ -146,10 +127,10 @@
 
 /* the port structure holds info for each port, one for each minor number */
 struct gs_port {
-	struct gs_dev 		*port_dev;	/* pointer to device struct */
+	struct gs_dev		*port_dev;	/* pointer to device struct */
 	struct tty_struct	*port_tty;	/* pointer to tty struct */
 	spinlock_t		port_lock;
-	int 			port_num;
+	int			port_num;
 	int			port_open_count;
 	int			port_in_use;	/* open/close in progress */
 	wait_queue_head_t	port_write_wait;/* waiting to write */
@@ -187,7 +168,7 @@
 /* tty driver */
 static int gs_open(struct tty_struct *tty, struct file *file);
 static void gs_close(struct tty_struct *tty, struct file *file);
-static int gs_write(struct tty_struct *tty, 
+static int gs_write(struct tty_struct *tty,
 	const unsigned char *buf, int count);
 static void gs_put_char(struct tty_struct *tty, unsigned char ch);
 static void gs_flush_chars(struct tty_struct *tty);
@@ -221,7 +202,7 @@
 static void gs_disconnect(struct usb_gadget *gadget);
 static int gs_set_config(struct gs_dev *dev, unsigned config);
 static void gs_reset_config(struct gs_dev *dev);
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
 		u8 type, unsigned int index, int is_otg);
 
 static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
@@ -258,7 +239,7 @@
 static const char *EP_OUT_NAME;
 static const char *EP_NOTIFY_NAME;
 
-static struct semaphore	gs_open_close_sem[GS_NUM_PORTS];
+static struct mutex gs_open_close_lock[GS_NUM_PORTS];
 
 static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE;
 static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE;
@@ -414,18 +395,18 @@
 };
 
 static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = {
-	.bLength =  		sizeof(gs_call_mgmt_descriptor),
-	.bDescriptorType = 	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType = 	USB_CDC_CALL_MANAGEMENT_TYPE,
-	.bmCapabilities = 	0,
-	.bDataInterface = 	1,	/* index of data interface */
+	.bLength =		sizeof(gs_call_mgmt_descriptor),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_CALL_MANAGEMENT_TYPE,
+	.bmCapabilities =	0,
+	.bDataInterface =	1,	/* index of data interface */
 };
 
 static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
-	.bLength =  		sizeof(gs_acm_descriptor),
-	.bDescriptorType = 	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType = 	USB_CDC_ACM_TYPE,
-	.bmCapabilities = 	0,
+	.bLength =		sizeof(gs_acm_descriptor),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_ACM_TYPE,
+	.bmCapabilities =	0,
 };
 
 static const struct usb_cdc_union_desc gs_union_desc = {
@@ -435,7 +416,7 @@
 	.bMasterInterface0 =	0,	/* index of control interface */
 	.bSlaveInterface0 =	1,	/* index of data interface */
 };
- 
+
 static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
@@ -481,7 +462,6 @@
 	NULL,
 };
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 static struct usb_endpoint_descriptor gs_highspeed_notify_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
@@ -535,15 +515,13 @@
 	NULL,
 };
 
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
-
 
 /* Module */
 MODULE_DESCRIPTION(GS_LONG_NAME);
 MODULE_AUTHOR("Al Borchers");
 MODULE_LICENSE("GPL");
 
-#ifdef GS_DEBUG
+#ifdef DEBUG
 module_param(debug, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
 #endif
@@ -595,7 +573,7 @@
 	tty_set_operations(gs_tty_driver, &gs_tty_ops);
 
 	for (i=0; i < GS_NUM_PORTS; i++)
-		sema_init(&gs_open_close_sem[i], 1);
+		mutex_init(&gs_open_close_lock[i]);
 
 	retval = tty_register_driver(gs_tty_driver);
 	if (retval) {
@@ -635,7 +613,7 @@
 	struct gs_port *port;
 	struct gs_dev *dev;
 	struct gs_buf *buf;
-	struct semaphore *sem;
+	struct mutex *mtx;
 	int ret;
 
 	port_num = tty->index;
@@ -656,10 +634,10 @@
 		return -ENODEV;
 	}
 
-	sem = &gs_open_close_sem[port_num];
-	if (down_interruptible(sem)) {
+	mtx = &gs_open_close_lock[port_num];
+	if (mutex_lock_interruptible(mtx)) {
 		printk(KERN_ERR
-		"gs_open: (%d,%p,%p) interrupted waiting for semaphore\n",
+		"gs_open: (%d,%p,%p) interrupted waiting for mutex\n",
 			port_num, tty, file);
 		return -ERESTARTSYS;
 	}
@@ -754,12 +732,12 @@
 
 exit_unlock_port:
 	spin_unlock_irqrestore(&port->port_lock, flags);
-	up(sem);
+	mutex_unlock(mtx);
 	return ret;
 
 exit_unlock_dev:
 	spin_unlock_irqrestore(&dev->dev_lock, flags);
-	up(sem);
+	mutex_unlock(mtx);
 	return ret;
 
 }
@@ -781,7 +759,7 @@
 static void gs_close(struct tty_struct *tty, struct file *file)
 {
 	struct gs_port *port = tty->driver_data;
-	struct semaphore *sem;
+	struct mutex *mtx;
 
 	if (port == NULL) {
 		printk(KERN_ERR "gs_close: NULL port pointer\n");
@@ -790,8 +768,8 @@
 
 	gs_debug("gs_close: (%d,%p,%p)\n", port->port_num, tty, file);
 
-	sem = &gs_open_close_sem[port->port_num];
-	down(sem);
+	mtx = &gs_open_close_lock[port->port_num];
+	mutex_lock(mtx);
 
 	spin_lock_irq(&port->port_lock);
 
@@ -846,7 +824,7 @@
 
 exit:
 	spin_unlock_irq(&port->port_lock);
-	up(sem);
+	mutex_unlock(mtx);
 }
 
 /*
@@ -914,7 +892,8 @@
 		return;
 	}
 
-	gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p, %p, %p\n", port->port_num, tty, ch, __builtin_return_address(0), __builtin_return_address(1), __builtin_return_address(2));
+	gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
+		port->port_num, tty, ch, __builtin_return_address(0));
 
 	spin_lock_irqsave(&port->port_lock, flags);
 
@@ -1115,7 +1094,11 @@
 		len = gs_send_packet(dev, req->buf, ep->maxpacket);
 
 		if (len > 0) {
-gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2));
+			gs_debug_level(3, "gs_send: len=%d, 0x%2.2x "
+					"0x%2.2x 0x%2.2x ...\n", len,
+					*((unsigned char *)req->buf),
+					*((unsigned char *)req->buf+1),
+					*((unsigned char *)req->buf+2));
 			list_del(&req_entry->re_entry);
 			req->length = len;
 			spin_unlock_irqrestore(&dev->dev_lock, flags);
@@ -1268,7 +1251,7 @@
 
 	switch(req->status) {
 	case 0:
- 		/* normal completion */
+		/* normal completion */
 		gs_recv_packet(dev, req->buf, req->actual);
 requeue:
 		req->length = ep->maxpacket;
@@ -1405,29 +1388,30 @@
 		? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
 	gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	gs_qualifier_desc.bDeviceClass = use_acm
-		? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
-	/* assume ep0 uses the same packet size for both speeds */
-	gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0;
-	/* assume endpoints are dual-speed */
-	gs_highspeed_notify_desc.bEndpointAddress =
-		gs_fullspeed_notify_desc.bEndpointAddress;
-	gs_highspeed_in_desc.bEndpointAddress =
-		gs_fullspeed_in_desc.bEndpointAddress;
-	gs_highspeed_out_desc.bEndpointAddress =
-		gs_fullspeed_out_desc.bEndpointAddress;
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+	if (gadget_is_dualspeed(gadget)) {
+		gs_qualifier_desc.bDeviceClass = use_acm
+			? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
+		/* assume ep0 uses the same packet size for both speeds */
+		gs_qualifier_desc.bMaxPacketSize0 =
+			gs_device_desc.bMaxPacketSize0;
+		/* assume endpoints are dual-speed */
+		gs_highspeed_notify_desc.bEndpointAddress =
+			gs_fullspeed_notify_desc.bEndpointAddress;
+		gs_highspeed_in_desc.bEndpointAddress =
+			gs_fullspeed_in_desc.bEndpointAddress;
+		gs_highspeed_out_desc.bEndpointAddress =
+			gs_fullspeed_out_desc.bEndpointAddress;
+	}
 
 	usb_gadget_set_selfpowered(gadget);
 
-	if (gadget->is_otg) {
+	if (gadget_is_otg(gadget)) {
 		gs_otg_descriptor.bmAttributes |= USB_OTG_HNP,
 		gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 	}
 
-	gs_device = dev = kmalloc(sizeof(struct gs_dev), GFP_KERNEL);
+	gs_device = dev = kzalloc(sizeof(struct gs_dev), GFP_KERNEL);
 	if (dev == NULL)
 		return -ENOMEM;
 
@@ -1435,7 +1419,6 @@
 		init_utsname()->sysname, init_utsname()->release,
 		gadget->name);
 
-	memset(dev, 0, sizeof(struct gs_dev));
 	dev->dev_gadget = gadget;
 	spin_lock_init(&dev->dev_lock);
 	INIT_LIST_HEAD(&dev->dev_req_list);
@@ -1487,6 +1470,12 @@
 			dev->dev_ctrl_req = NULL;
 		}
 		gs_free_ports(dev);
+		if (dev->dev_notify_ep)
+			usb_ep_disable(dev->dev_notify_ep);
+		if (dev->dev_in_ep)
+			usb_ep_disable(dev->dev_in_ep);
+		if (dev->dev_out_ep)
+			usb_ep_disable(dev->dev_out_ep);
 		kfree(dev);
 		set_gadget_data(gadget, NULL);
 	}
@@ -1570,9 +1559,8 @@
 			memcpy(req->buf, &gs_device_desc, ret);
 			break;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			ret = min(wLength,
 				(u16)sizeof(struct usb_qualifier_descriptor));
@@ -1580,14 +1568,13 @@
 			break;
 
 		case USB_DT_OTHER_SPEED_CONFIG:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			/* fall through */
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
 		case USB_DT_CONFIG:
-			ret = gs_build_config_buf(req->buf, gadget->speed,
+			ret = gs_build_config_buf(req->buf, gadget,
 				wValue >> 8, wValue & 0xff,
-				gadget->is_otg);
+				gadget_is_otg(gadget));
 			if (ret >= 0)
 				ret = min(wLength, (u16)ret);
 			break;
@@ -1691,14 +1678,12 @@
 
 	switch (ctrl->bRequest) {
 	case USB_CDC_REQ_SET_LINE_CODING:
-		ret = min(wLength,
-			(u16)sizeof(struct usb_cdc_line_coding));
-		if (port) {
-			spin_lock(&port->port_lock);
-			memcpy(&port->port_line_coding, req->buf, ret);
-			spin_unlock(&port->port_lock);
-		}
-		ret = 0;
+		/* FIXME Submit req to read the data; have its completion
+		 * handler copy that data to port->port_line_coding (iff
+		 * it's valid) and maybe pass it on.  Until then, fail.
+		 */
+		printk(KERN_WARNING "gs_setup: set_line_coding "
+				"unuspported\n");
 		break;
 
 	case USB_CDC_REQ_GET_LINE_CODING:
@@ -1713,11 +1698,18 @@
 		break;
 
 	case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
-		ret = 0;
+		/* FIXME Submit req to read the data; have its completion
+		 * handler use that to set the state (iff it's valid) and
+		 * maybe pass it on.  Until then, fail.
+		 */
+		printk(KERN_WARNING "gs_setup: set_control_line_state "
+				"unuspported\n");
 		break;
 
 	default:
-		printk(KERN_ERR "gs_setup: unknown class request, type=%02x, request=%02x, value=%04x, index=%04x, length=%d\n",
+		printk(KERN_ERR "gs_setup: unknown class request, "
+				"type=%02x, request=%02x, value=%04x, "
+				"index=%04x, length=%d\n",
 			ctrl->bRequestType, ctrl->bRequest,
 			wValue, wIndex, wLength);
 		break;
@@ -1822,8 +1814,7 @@
 
 		if (EP_NOTIFY_NAME
 		&& strcmp(ep->name, EP_NOTIFY_NAME) == 0) {
-			ep_desc = GS_SPEED_SELECT(
-				gadget->speed == USB_SPEED_HIGH,
+			ep_desc = choose_ep_desc(gadget,
 				&gs_highspeed_notify_desc,
 				&gs_fullspeed_notify_desc);
 			ret = usb_ep_enable(ep,ep_desc);
@@ -1839,9 +1830,8 @@
 		}
 
 		else if (strcmp(ep->name, EP_IN_NAME) == 0) {
-			ep_desc = GS_SPEED_SELECT(
-				gadget->speed == USB_SPEED_HIGH,
- 				&gs_highspeed_in_desc,
+			ep_desc = choose_ep_desc(gadget,
+				&gs_highspeed_in_desc,
 				&gs_fullspeed_in_desc);
 			ret = usb_ep_enable(ep,ep_desc);
 			if (ret == 0) {
@@ -1856,8 +1846,7 @@
 		}
 
 		else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
-			ep_desc = GS_SPEED_SELECT(
-				gadget->speed == USB_SPEED_HIGH,
+			ep_desc = choose_ep_desc(gadget,
 				&gs_highspeed_out_desc,
 				&gs_fullspeed_out_desc);
 			ret = usb_ep_enable(ep,ep_desc);
@@ -1976,11 +1965,11 @@
  * Builds the config descriptors in the given buffer and returns the
  * length, or a negative error number.
  */
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
 	u8 type, unsigned int index, int is_otg)
 {
 	int len;
-	int high_speed;
+	int high_speed = 0;
 	const struct usb_config_descriptor *config_desc;
 	const struct usb_descriptor_header **function;
 
@@ -1988,20 +1977,22 @@
 		return -EINVAL;
 
 	/* other speed switches high and full speed */
-	high_speed = (speed == USB_SPEED_HIGH);
-	if (type == USB_DT_OTHER_SPEED_CONFIG)
-		high_speed = !high_speed;
+	if (gadget_is_dualspeed(g)) {
+		high_speed = (g->speed == USB_SPEED_HIGH);
+		if (type == USB_DT_OTHER_SPEED_CONFIG)
+			high_speed = !high_speed;
+	}
 
 	if (use_acm) {
 		config_desc = &gs_acm_config_desc;
-		function = GS_SPEED_SELECT(high_speed,
-			gs_acm_highspeed_function,
-			gs_acm_fullspeed_function);
+		function = high_speed
+			? gs_acm_highspeed_function
+			: gs_acm_fullspeed_function;
 	} else {
 		config_desc = &gs_bulk_config_desc;
-		function = GS_SPEED_SELECT(high_speed,
-			gs_bulk_highspeed_function,
-			gs_bulk_fullspeed_function);
+		function = high_speed
+			? gs_bulk_highspeed_function
+			: gs_bulk_fullspeed_function;
 	}
 
 	/* for now, don't advertise srp-only devices */
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index 3459ea6..878e428 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -15,7 +15,7 @@
 #include <linux/init.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/unaligned.h>
 
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index a2e6e3fc..fcde5d9 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -1,38 +1,22 @@
 /*
  * zero.c -- Gadget Zero, for USB development
  *
- * Copyright (C) 2003-2004 David Brownell
+ * Copyright (C) 2003-2007 David Brownell
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * 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.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation, either version 2 of that 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.
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 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
  */
 
 
@@ -57,40 +41,28 @@
  * Many drivers will only have one configuration, letting them be much
  * simpler if they also don't support high speed operation (like this
  * driver does).
+ *
+ * Why is *this* driver using two configurations, rather than setting up
+ * two interfaces with different functions?  To help verify that multiple
+ * configuration infrastucture is working correctly; also, so that it can
+ * work with low capability USB controllers without four bulk endpoints.
  */
 
-#define DEBUG 1
-// #define VERBOSE
+/* #define VERBOSE_DEBUG */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/utsname.h>
 #include <linux/device.h>
-#include <linux/moduleparam.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
 
 /*-------------------------------------------------------------------------*/
 
-#define DRIVER_VERSION		"St Patrick's Day 2004"
+#define DRIVER_VERSION		"Lughnasadh, 2007"
 
 static const char shortname [] = "zero";
 static const char longname [] = "Gadget Zero";
@@ -131,30 +103,16 @@
 	struct timer_list	resume;
 };
 
-#define xprintk(d,level,fmt,args...) \
-	dev_printk(level , &(d)->gadget->dev , fmt , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
-	xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
-	do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG	DBG
-#else
-#define VDBG(dev,fmt,args...) \
-	do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
-	xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
-	xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
-	xprintk(dev , KERN_INFO , fmt , ## args)
+#define DBG(d, fmt, args...) \
+	dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+	dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+	dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+	dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+	dev_info(&(d)->gadget->dev , fmt , ## args)
 
 /*-------------------------------------------------------------------------*/
 
@@ -326,8 +284,6 @@
 	NULL,
 };
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-
 /*
  * usb 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -383,17 +339,20 @@
 };
 
 /* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+		struct usb_endpoint_descriptor *fs)
+{
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
+}
 
-#else
+static char manufacturer[50];
 
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) fs
+/* default serial number takes at least two packets */
+static char serial[] = "0123456789.0123456789.0123456789";
 
-#endif	/* !CONFIG_USB_GADGET_DUALSPEED */
-
-static char				manufacturer [50];
-static char				serial [40];
 
 /* static strings, in UTF-8 */
 static struct usb_string		strings [] = {
@@ -435,30 +394,29 @@
 	int				is_source_sink;
 	int				len;
 	const struct usb_descriptor_header **function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	int				hs = (gadget->speed == USB_SPEED_HIGH);
-#endif
+	int				hs = 0;
 
 	/* two configurations will always be index 0 and index 1 */
 	if (index > 1)
 		return -EINVAL;
 	is_source_sink = loopdefault ? (index == 1) : (index == 0);
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	if (type == USB_DT_OTHER_SPEED_CONFIG)
-		hs = !hs;
+	if (gadget_is_dualspeed(gadget)) {
+		hs = (gadget->speed == USB_SPEED_HIGH);
+		if (type == USB_DT_OTHER_SPEED_CONFIG)
+			hs = !hs;
+	}
 	if (hs)
 		function = is_source_sink
 			? hs_source_sink_function
 			: hs_loopback_function;
 	else
-#endif
 		function = is_source_sink
 			? fs_source_sink_function
 			: fs_loopback_function;
 
 	/* for now, don't advertise srp-only devices */
-	if (!gadget->is_otg)
+	if (!gadget_is_otg(gadget))
 		function++;
 
 	len = usb_gadget_config_buf (is_source_sink
@@ -498,6 +456,19 @@
 
 /*-------------------------------------------------------------------------*/
 
+/*
+ * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripherals,
+ * this just sinks bulk packets OUT to the peripheral and sources them IN
+ * to the host, optionally with specific data patterns.
+ *
+ * In terms of control messaging, this supports all the standard requests
+ * plus two that support control-OUT tests.
+ *
+ * Note that because this doesn't queue more than one request at a time,
+ * some other function must be used to test queueing logic.  The network
+ * link (g_ether) is probably the best option for that.
+ */
+
 /* optionally require specific source/sink data patterns  */
 
 static int
@@ -534,12 +505,7 @@
 	return 0;
 }
 
-static void
-reinit_write_data (
-	struct zero_dev		*dev,
-	struct usb_ep		*ep,
-	struct usb_request	*req
-)
+static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
 {
 	unsigned	i;
 	u8		*buf = req->buf;
@@ -566,16 +532,16 @@
 
 	switch (status) {
 
-	case 0: 			/* normal completion? */
+	case 0:				/* normal completion? */
 		if (ep == dev->out_ep) {
 			check_read_data (dev, ep, req);
 			memset (req->buf, 0x55, req->length);
 		} else
-			reinit_write_data (dev, ep, req);
+			reinit_write_data(ep, req);
 		break;
 
 	/* this endpoint is normally active while we're configured */
-	case -ECONNABORTED: 		/* hardware forced ep reset */
+	case -ECONNABORTED:		/* hardware forced ep reset */
 	case -ECONNRESET:		/* request dequeued */
 	case -ESHUTDOWN:		/* disconnect from host */
 		VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
@@ -607,8 +573,7 @@
 	}
 }
 
-static struct usb_request *
-source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
+static struct usb_request *source_sink_start_ep(struct usb_ep *ep)
 {
 	struct usb_request	*req;
 	int			status;
@@ -621,11 +586,11 @@
 	req->complete = source_sink_complete;
 
 	if (strcmp (ep->name, EP_IN_NAME) == 0)
-		reinit_write_data (ep->driver_data, ep, req);
+		reinit_write_data(ep, req);
 	else
 		memset (req->buf, 0x55, req->length);
 
-	status = usb_ep_queue (ep, req, gfp_flags);
+	status = usb_ep_queue(ep, req, GFP_ATOMIC);
 	if (status) {
 		struct zero_dev	*dev = ep->driver_data;
 
@@ -637,8 +602,7 @@
 	return req;
 }
 
-static int
-set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
+static int set_source_sink_config(struct zero_dev *dev)
 {
 	int			result = 0;
 	struct usb_ep		*ep;
@@ -653,7 +617,7 @@
 			result = usb_ep_enable (ep, d);
 			if (result == 0) {
 				ep->driver_data = dev;
-				if (source_sink_start_ep (ep, gfp_flags) != 0) {
+				if (source_sink_start_ep(ep) != NULL) {
 					dev->in_ep = ep;
 					continue;
 				}
@@ -667,7 +631,7 @@
 			result = usb_ep_enable (ep, d);
 			if (result == 0) {
 				ep->driver_data = dev;
-				if (source_sink_start_ep (ep, gfp_flags) != 0) {
+				if (source_sink_start_ep(ep) != NULL) {
 					dev->out_ep = ep;
 					continue;
 				}
@@ -699,7 +663,7 @@
 
 	switch (status) {
 
-	case 0: 			/* normal completion? */
+	case 0:				/* normal completion? */
 		if (ep == dev->out_ep) {
 			/* loop this OUT packet back IN to the host */
 			req->zero = (req->actual < req->length);
@@ -733,7 +697,7 @@
 	 * rely on the hardware driver to clean up on disconnect or
 	 * endpoint disable.
 	 */
-	case -ECONNABORTED: 		/* hardware forced ep reset */
+	case -ECONNABORTED:		/* hardware forced ep reset */
 	case -ECONNRESET:		/* request dequeued */
 	case -ESHUTDOWN:		/* disconnect from host */
 		free_ep_req (ep, req);
@@ -741,8 +705,7 @@
 	}
 }
 
-static int
-set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags)
+static int set_loopback_config(struct zero_dev *dev)
 {
 	int			result = 0;
 	struct usb_ep		*ep;
@@ -842,8 +805,7 @@
  * code can do, perhaps by disallowing more than one configuration or
  * by limiting configuration choices (like the pxa2xx).
  */
-static int
-zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
+static int zero_set_config(struct zero_dev *dev, unsigned number)
 {
 	int			result = 0;
 	struct usb_gadget	*gadget = dev->gadget;
@@ -853,17 +815,17 @@
 
 	if (gadget_is_sa1100 (gadget) && dev->config) {
 		/* tx fifo is full, but we can't clear it...*/
-		INFO (dev, "can't change configurations\n");
+		ERROR(dev, "can't change configurations\n");
 		return -ESPIPE;
 	}
 	zero_reset_config (dev);
 
 	switch (number) {
 	case CONFIG_SOURCE_SINK:
-		result = set_source_sink_config (dev, gfp_flags);
+		result = set_source_sink_config(dev);
 		break;
 	case CONFIG_LOOPBACK:
-		result = set_loopback_config (dev, gfp_flags);
+		result = set_loopback_config(dev);
 		break;
 	default:
 		result = -EINVAL;
@@ -883,7 +845,7 @@
 		case USB_SPEED_LOW:	speed = "low"; break;
 		case USB_SPEED_FULL:	speed = "full"; break;
 		case USB_SPEED_HIGH:	speed = "high"; break;
-		default: 		speed = "?"; break;
+		default:		speed = "?"; break;
 		}
 
 		dev->config = number;
@@ -936,19 +898,17 @@
 			value = min (w_length, (u16) sizeof device_desc);
 			memcpy (req->buf, &device_desc, value);
 			break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			value = min (w_length, (u16) sizeof dev_qualifier);
 			memcpy (req->buf, &dev_qualifier, value);
 			break;
 
 		case USB_DT_OTHER_SPEED_CONFIG:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			// FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
 		case USB_DT_CONFIG:
 			value = config_buf (gadget, req->buf,
 					w_value >> 8,
@@ -982,7 +942,7 @@
 		else
 			VDBG (dev, "HNP inactive\n");
 		spin_lock (&dev->lock);
-		value = zero_set_config (dev, w_value, GFP_ATOMIC);
+		value = zero_set_config(dev, w_value);
 		spin_unlock (&dev->lock);
 		break;
 	case USB_REQ_GET_CONFIGURATION:
@@ -1011,7 +971,7 @@
 			 * use this "reset the config" shortcut.
 			 */
 			zero_reset_config (dev);
-			zero_set_config (dev, config, GFP_ATOMIC);
+			zero_set_config(dev, config);
 			value = 0;
 		}
 		spin_unlock (&dev->lock);
@@ -1161,7 +1121,7 @@
 	}
 	EP_IN_NAME = ep->name;
 	ep->driver_data = ep;	/* claim */
-	
+
 	ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
 	if (!ep)
 		goto autoconf_fail;
@@ -1205,16 +1165,18 @@
 
 	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	/* assume ep0 uses the same value for both speeds ... */
-	dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+	if (gadget_is_dualspeed(gadget)) {
+		/* assume ep0 uses the same value for both speeds ... */
+		dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
 
-	/* and that all endpoints are dual-speed */
-	hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
-	hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
-#endif
+		/* and that all endpoints are dual-speed */
+		hs_source_desc.bEndpointAddress =
+				fs_source_desc.bEndpointAddress;
+		hs_sink_desc.bEndpointAddress =
+				fs_sink_desc.bEndpointAddress;
+	}
 
-	if (gadget->is_otg) {
+	if (gadget_is_otg(gadget)) {
 		otg_descriptor.bmAttributes |= USB_OTG_HNP,
 		source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1292,23 +1254,18 @@
 	.suspend	= zero_suspend,
 	.resume		= zero_resume,
 
-	.driver 	= {
+	.driver		= {
 		.name		= (char *) shortname,
 		.owner		= THIS_MODULE,
 	},
 };
 
-MODULE_AUTHOR ("David Brownell");
-MODULE_LICENSE ("Dual BSD/GPL");
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
 
 
 static int __init init (void)
 {
-	/* a real value would likely come through some id prom
-	 * or module option.  this one takes at least two packets.
-	 */
-	strlcpy (serial, "0123456789.0123456789.0123456789", sizeof serial);
-
 	return usb_gadget_register_driver (&zero_driver);
 }
 module_init (init);
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 2f52982..c978d62 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -154,6 +154,19 @@
 	  Enables support for PCI-bus plug-in USB controller cards.
 	  If unsure, say Y.
 
+config USB_OHCI_HCD_SSB
+	bool "OHCI support for Broadcom SSB OHCI core"
+	depends on USB_OHCI_HCD && SSB && EXPERIMENTAL
+	default n
+	---help---
+	  Support for the Sonics Silicon Backplane (SSB) attached
+	  Broadcom USB OHCI core.
+
+	  This device is present in some embedded devices with
+	  Broadcom based SSB bus.
+
+	  If unsure, say N.
+
 config USB_OHCI_BIG_ENDIAN_DESC
 	bool
 	depends on USB_OHCI_HCD
@@ -237,7 +250,7 @@
 	  module will be called "sl811_cs".
 
 config USB_R8A66597_HCD
-	tristate "R8A66597 HCD suppoort"
+	tristate "R8A66597 HCD support"
 	depends on USB
 	help
 	  The R8A66597 is a USB 2.0 host and peripheral controller.
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index 5d1b12a..766ef68 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -1,8 +1,6 @@
 /*
  * EHCI HCD (Host Controller Driver) for USB.
  *
- * (C) Copyright 2000-2004 David Brownell <dbrownell@users.sourceforge.net>
- *
  * Bus Glue for AMD Alchemy Au1xxx
  *
  * Based on "ohci-au1xxx.c" by Matt Porter <mporter@kernel.crashing.org>
@@ -196,6 +194,9 @@
 
 	/*
 	 * basic lifecycle operations
+	 *
+	 * FIXME -- ehci_init() doesn't do enough here.
+	 * See ehci-ppc-soc for a complete implementation.
 	 */
 	.reset = ehci_init,
 	.start = ehci_run,
@@ -219,10 +220,8 @@
 	 */
 	.hub_status_data = ehci_hub_status_data,
 	.hub_control = ehci_hub_control,
-#ifdef	CONFIG_PM
-	.hub_suspend = ehci_hub_suspend,
-	.hub_resume = ehci_hub_resume,
-#endif
+	.bus_suspend = ehci_bus_suspend,
+	.bus_resume = ehci_bus_resume,
 };
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c4e15ed..c151444 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -275,58 +275,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef CONFIG_CPU_FREQ
-
-#include <linux/cpufreq.h>
-
-static void ehci_cpufreq_pause (struct ehci_hcd *ehci)
-{
-	unsigned long	flags;
-
-	spin_lock_irqsave(&ehci->lock, flags);
-	if (!ehci->cpufreq_changing++)
-		qh_inactivate_split_intr_qhs(ehci);
-	spin_unlock_irqrestore(&ehci->lock, flags);
-}
-
-static void ehci_cpufreq_unpause (struct ehci_hcd *ehci)
-{
-	unsigned long	flags;
-
-	spin_lock_irqsave(&ehci->lock, flags);
-	if (!--ehci->cpufreq_changing)
-		qh_reactivate_split_intr_qhs(ehci);
-	spin_unlock_irqrestore(&ehci->lock, flags);
-}
-
-/*
- * ehci_cpufreq_notifier is needed to avoid MMF errors that occur when
- * EHCI controllers that don't cache many uframes get delayed trying to
- * read main memory during CPU frequency transitions.  This can cause
- * split interrupt transactions to not be completed in the required uframe.
- * This has been observed on the Broadcom/ServerWorks HT1000 controller.
- */
-static int ehci_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
-				 void *data)
-{
-	struct ehci_hcd *ehci = container_of(nb, struct ehci_hcd,
-					     cpufreq_transition);
-
-	switch (val) {
-	case CPUFREQ_PRECHANGE:
-		ehci_cpufreq_pause(ehci);
-		break;
-	case CPUFREQ_POSTCHANGE:
-		ehci_cpufreq_unpause(ehci);
-		break;
-	}
-	return 0;
-}
-
-#endif
-
-/*-------------------------------------------------------------------------*/
-
 static void ehci_watchdog (unsigned long param)
 {
 	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
@@ -460,10 +408,6 @@
 	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 	spin_unlock_irq(&ehci->lock);
 
-#ifdef CONFIG_CPU_FREQ
-	cpufreq_unregister_notifier(&ehci->cpufreq_transition,
-				    CPUFREQ_TRANSITION_NOTIFIER);
-#endif
 	/* let companion controllers work when we aren't */
 	ehci_writel(ehci, 0, &ehci->regs->configured_flag);
 
@@ -569,17 +513,6 @@
 	}
 	ehci->command = temp;
 
-#ifdef CONFIG_CPU_FREQ
-	INIT_LIST_HEAD(&ehci->split_intr_qhs);
-	/*
-	 * If the EHCI controller caches enough uframes, this probably
-	 * isn't needed unless there are so many low/full speed devices
-	 * that the controller's can't cache it all.
-	 */
-	ehci->cpufreq_transition.notifier_call = ehci_cpufreq_notifier;
-	cpufreq_register_notifier(&ehci->cpufreq_transition,
-				  CPUFREQ_TRANSITION_NOTIFIER);
-#endif
 	return 0;
 }
 
@@ -637,10 +570,18 @@
 	 * are explicitly handed to companion controller(s), so no TT is
 	 * involved with the root hub.  (Except where one is integrated,
 	 * and there's no companion controller unless maybe for USB OTG.)
+	 *
+	 * Turning on the CF flag will transfer ownership of all ports
+	 * from the companions to the EHCI controller.  If any of the
+	 * companions are in the middle of a port reset at the time, it
+	 * could cause trouble.  Write-locking ehci_cf_port_reset_rwsem
+	 * guarantees that no resets are in progress.
 	 */
+	down_write(&ehci_cf_port_reset_rwsem);
 	hcd->state = HC_STATE_RUNNING;
 	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
 	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
+	up_write(&ehci_cf_port_reset_rwsem);
 
 	temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
 	ehci_info (ehci,
@@ -786,7 +727,6 @@
  */
 static int ehci_urb_enqueue (
 	struct usb_hcd	*hcd,
-	struct usb_host_endpoint *ep,
 	struct urb	*urb,
 	gfp_t		mem_flags
 ) {
@@ -801,12 +741,12 @@
 	default:
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
 			return -ENOMEM;
-		return submit_async (ehci, ep, urb, &qtd_list, mem_flags);
+		return submit_async(ehci, urb, &qtd_list, mem_flags);
 
 	case PIPE_INTERRUPT:
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
 			return -ENOMEM;
-		return intr_submit (ehci, ep, urb, &qtd_list, mem_flags);
+		return intr_submit(ehci, urb, &qtd_list, mem_flags);
 
 	case PIPE_ISOCHRONOUS:
 		if (urb->dev->speed == USB_SPEED_HIGH)
@@ -844,13 +784,18 @@
  * completions normally happen asynchronously
  */
 
-static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	struct ehci_qh		*qh;
 	unsigned long		flags;
+	int			rc;
 
 	spin_lock_irqsave (&ehci->lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
+
 	switch (usb_pipetype (urb->pipe)) {
 	// case PIPE_CONTROL:
 	// case PIPE_BULK:
@@ -905,7 +850,7 @@
 	}
 done:
 	spin_unlock_irqrestore (&ehci->lock, flags);
-	return 0;
+	return rc;
 }
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index 8816d09..0431397 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -94,9 +94,6 @@
 	qh->qh_dma = dma;
 	// INIT_LIST_HEAD (&qh->qh_list);
 	INIT_LIST_HEAD (&qh->qtd_list);
-#ifdef CONFIG_CPU_FREQ
-	INIT_LIST_HEAD (&qh->split_intr_qhs);
-#endif
 
 	/* dummy td enables safe urb queuing */
 	qh->dummy = ehci_qtd_alloc (ehci, flags);
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index a7816e3..ad0d496 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -58,8 +58,6 @@
 	if (!retval)
 		ehci_dbg(ehci, "MWI active\n");
 
-	ehci_port_power(ehci, 0);
-
 	return 0;
 }
 
@@ -156,8 +154,7 @@
 		break;
 	}
 
-	if (ehci_is_TDI(ehci))
-		ehci_reset(ehci);
+	ehci_reset(ehci);
 
 	/* at least the Genesys GL880S needs fixup here */
 	temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
diff --git a/drivers/usb/host/ehci-ppc-soc.c b/drivers/usb/host/ehci-ppc-soc.c
index c2cedb0..452d4b1 100644
--- a/drivers/usb/host/ehci-ppc-soc.c
+++ b/drivers/usb/host/ehci-ppc-soc.c
@@ -6,7 +6,7 @@
  * Bus Glue for PPC On-Chip EHCI driver
  * Tested on AMCC 440EPx
  *
- * Based on "ehci-au12xx.c" by David Brownell <dbrownell@users.sourceforge.net>
+ * Based on "ehci-au1xxx.c" by K.Boge <karsten.boge@amd.com>
  *
  * This file is licenced under the GPL.
  */
@@ -15,6 +15,24 @@
 
 extern int usb_disabled(void);
 
+/* called during probe() after chip reset completes */
+static int ehci_ppc_soc_setup(struct usb_hcd *hcd)
+{
+	struct ehci_hcd	*ehci = hcd_to_ehci(hcd);
+	int		retval;
+
+	retval = ehci_halt(ehci);
+	if (retval)
+		return retval;
+
+	retval = ehci_init(hcd);
+	if (retval)
+		return retval;
+
+	ehci->sbrn = 0x20;
+	return ehci_reset(ehci);
+}
+
 /**
  * usb_ehci_ppc_soc_probe - initialize PPC-SoC-based HCDs
  * Context: !in_interrupt()
@@ -120,7 +138,7 @@
 	/*
 	 * basic lifecycle operations
 	 */
-	.reset = ehci_init,
+	.reset = ehci_ppc_soc_setup,
 	.start = ehci_run,
 	.stop = ehci_stop,
 	.shutdown = ehci_shutdown,
@@ -142,10 +160,8 @@
 	 */
 	.hub_status_data = ehci_hub_status_data,
 	.hub_control = ehci_hub_control,
-#ifdef	CONFIG_PM
-	.hub_suspend = ehci_hub_suspend,
-	.hub_resume = ehci_hub_resume,
-#endif
+	.bus_suspend = ehci_bus_suspend,
+	.bus_resume = ehci_bus_resume,
 };
 
 static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index 829fe64..03a6b2f 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -47,7 +47,7 @@
 	if (result)
 		return result;
 
-	ehci_port_power(ehci, 0);
+	ehci_reset(ehci);
 
 	return result;
 }
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 2284028..b10f39c 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -139,63 +139,65 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void qtd_copy_status (
+static int qtd_copy_status (
 	struct ehci_hcd *ehci,
 	struct urb *urb,
 	size_t length,
 	u32 token
 )
 {
+	int	status = -EINPROGRESS;
+
 	/* count IN/OUT bytes, not SETUP (even short packets) */
 	if (likely (QTD_PID (token) != 2))
 		urb->actual_length += length - QTD_LENGTH (token);
 
 	/* don't modify error codes */
-	if (unlikely (urb->status != -EINPROGRESS))
-		return;
+	if (unlikely(urb->unlinked))
+		return status;
 
 	/* force cleanup after short read; not always an error */
 	if (unlikely (IS_SHORT_READ (token)))
-		urb->status = -EREMOTEIO;
+		status = -EREMOTEIO;
 
 	/* serious "can't proceed" faults reported by the hardware */
 	if (token & QTD_STS_HALT) {
 		if (token & QTD_STS_BABBLE) {
 			/* FIXME "must" disable babbling device's port too */
-			urb->status = -EOVERFLOW;
+			status = -EOVERFLOW;
 		} else if (token & QTD_STS_MMF) {
 			/* fs/ls interrupt xfer missed the complete-split */
-			urb->status = -EPROTO;
+			status = -EPROTO;
 		} else if (token & QTD_STS_DBE) {
-			urb->status = (QTD_PID (token) == 1) /* IN ? */
+			status = (QTD_PID (token) == 1) /* IN ? */
 				? -ENOSR  /* hc couldn't read data */
 				: -ECOMM; /* hc couldn't write data */
 		} else if (token & QTD_STS_XACT) {
 			/* timeout, bad crc, wrong PID, etc; retried */
 			if (QTD_CERR (token))
-				urb->status = -EPIPE;
+				status = -EPIPE;
 			else {
 				ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
 					urb->dev->devpath,
 					usb_pipeendpoint (urb->pipe),
 					usb_pipein (urb->pipe) ? "in" : "out");
-				urb->status = -EPROTO;
+				status = -EPROTO;
 			}
 		/* CERR nonzero + no errors + halt --> stall */
 		} else if (QTD_CERR (token))
-			urb->status = -EPIPE;
+			status = -EPIPE;
 		else	/* unknown */
-			urb->status = -EPROTO;
+			status = -EPROTO;
 
 		ehci_vdbg (ehci,
 			"dev%d ep%d%s qtd token %08x --> status %d\n",
 			usb_pipedevice (urb->pipe),
 			usb_pipeendpoint (urb->pipe),
 			usb_pipein (urb->pipe) ? "in" : "out",
-			token, urb->status);
+			token, status);
 
 		/* if async CSPLIT failed, try cleaning out the TT buffer */
-		if (urb->status != -EPIPE
+		if (status != -EPIPE
 				&& urb->dev->tt && !usb_pipeint (urb->pipe)
 				&& ((token & QTD_STS_MMF) != 0
 					|| QTD_CERR(token) == 0)
@@ -212,10 +214,12 @@
 			usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
 		}
 	}
+
+	return status;
 }
 
 static void
-ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb)
+ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
 __releases(ehci->lock)
 __acquires(ehci->lock)
 {
@@ -231,25 +235,13 @@
 		qh_put (qh);
 	}
 
-	spin_lock (&urb->lock);
-	urb->hcpriv = NULL;
-	switch (urb->status) {
-	case -EINPROGRESS:		/* success */
-		urb->status = 0;
-	default:			/* fault */
-		COUNT (ehci->stats.complete);
-		break;
-	case -EREMOTEIO:		/* fault or normal */
-		if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
-			urb->status = 0;
-		COUNT (ehci->stats.complete);
-		break;
-	case -ECONNRESET:		/* canceled */
-	case -ENOENT:
-		COUNT (ehci->stats.unlink);
-		break;
+	if (unlikely(urb->unlinked)) {
+		COUNT(ehci->stats.unlink);
+	} else {
+		if (likely(status == -EINPROGRESS))
+			status = 0;
+		COUNT(ehci->stats.complete);
 	}
-	spin_unlock (&urb->lock);
 
 #ifdef EHCI_URB_TRACE
 	ehci_dbg (ehci,
@@ -257,13 +249,14 @@
 		__FUNCTION__, urb->dev->devpath, urb,
 		usb_pipeendpoint (urb->pipe),
 		usb_pipein (urb->pipe) ? "in" : "out",
-		urb->status,
+		status,
 		urb->actual_length, urb->transfer_buffer_length);
 #endif
 
 	/* complete() can reenter this HCD */
+	usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
 	spin_unlock (&ehci->lock);
-	usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb);
+	usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status);
 	spin_lock (&ehci->lock);
 }
 
@@ -283,6 +276,7 @@
 {
 	struct ehci_qtd		*last = NULL, *end = qh->dummy;
 	struct list_head	*entry, *tmp;
+	int			last_status = -EINPROGRESS;
 	int			stopped;
 	unsigned		count = 0;
 	int			do_status = 0;
@@ -311,10 +305,7 @@
 		struct ehci_qtd	*qtd;
 		struct urb	*urb;
 		u32		token = 0;
-
-		/* ignore QHs that are currently inactive */
-		if (qh->hw_info1 & __constant_cpu_to_le32(QH_INACTIVATE))
-			break;
+		int		qtd_status;
 
 		qtd = list_entry (entry, struct ehci_qtd, qtd_list);
 		urb = qtd->urb;
@@ -322,11 +313,12 @@
 		/* clean up any state from previous QTD ...*/
 		if (last) {
 			if (likely (last->urb != urb)) {
-				ehci_urb_done (ehci, last->urb);
+				ehci_urb_done(ehci, last->urb, last_status);
 				count++;
 			}
 			ehci_qtd_free (ehci, last);
 			last = NULL;
+			last_status = -EINPROGRESS;
 		}
 
 		/* ignore urbs submitted during completions we reported */
@@ -362,13 +354,14 @@
 			stopped = 1;
 
 			if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)))
-				urb->status = -ESHUTDOWN;
+				last_status = -ESHUTDOWN;
 
 			/* ignore active urbs unless some previous qtd
 			 * for the urb faulted (including short read) or
 			 * its urb was canceled.  we may patch qh or qtds.
 			 */
-			if (likely (urb->status == -EINPROGRESS))
+			if (likely(last_status == -EINPROGRESS &&
+					!urb->unlinked))
 				continue;
 
 			/* issue status after short control reads */
@@ -396,11 +389,14 @@
 		}
 
 		/* remove it from the queue */
-		spin_lock (&urb->lock);
-		qtd_copy_status (ehci, urb, qtd->length, token);
-		do_status = (urb->status == -EREMOTEIO)
-				&& usb_pipecontrol (urb->pipe);
-		spin_unlock (&urb->lock);
+		qtd_status = qtd_copy_status(ehci, urb, qtd->length, token);
+		if (unlikely(qtd_status == -EREMOTEIO)) {
+			do_status = (!urb->unlinked &&
+					usb_pipecontrol(urb->pipe));
+			qtd_status = 0;
+		}
+		if (likely(last_status == -EINPROGRESS))
+			last_status = qtd_status;
 
 		if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
 			last = list_entry (qtd->qtd_list.prev,
@@ -413,7 +409,7 @@
 
 	/* last urb's completion might still need calling */
 	if (likely (last != NULL)) {
-		ehci_urb_done (ehci, last->urb);
+		ehci_urb_done(ehci, last->urb, last_status);
 		count++;
 		ehci_qtd_free (ehci, last);
 	}
@@ -917,7 +913,6 @@
 static int
 submit_async (
 	struct ehci_hcd		*ehci,
-	struct usb_host_endpoint *ep,
 	struct urb		*urb,
 	struct list_head	*qtd_list,
 	gfp_t			mem_flags
@@ -926,10 +921,10 @@
 	int			epnum;
 	unsigned long		flags;
 	struct ehci_qh		*qh = NULL;
-	int			rc = 0;
+	int			rc;
 
 	qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
-	epnum = ep->desc.bEndpointAddress;
+	epnum = urb->ep->desc.bEndpointAddress;
 
 #ifdef EHCI_URB_TRACE
 	ehci_dbg (ehci,
@@ -937,7 +932,7 @@
 		__FUNCTION__, urb->dev->devpath, urb,
 		epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
 		urb->transfer_buffer_length,
-		qtd, ep->hcpriv);
+		qtd, urb->ep->hcpriv);
 #endif
 
 	spin_lock_irqsave (&ehci->lock, flags);
@@ -946,9 +941,13 @@
 		rc = -ESHUTDOWN;
 		goto done;
 	}
+	rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+	if (unlikely(rc))
+		goto done;
 
-	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+	qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
 	if (unlikely(qh == NULL)) {
+		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
 		rc = -ENOMEM;
 		goto done;
 	}
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index d4a8ace..80d99bc 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -479,109 +479,6 @@
 }
 
 /*-------------------------------------------------------------------------*/
-#ifdef CONFIG_CPU_FREQ
-
-static int safe_to_modify_i (struct ehci_hcd *ehci, struct ehci_qh *qh)
-{
-	int now; /* current (frame * 8) + uframe */
-	int prev_start, next_start; /* uframes from/to split start */
-	int start_uframe = ffs(le32_to_cpup (&qh->hw_info2) & QH_SMASK);
-	int end_uframe = fls((le32_to_cpup (&qh->hw_info2) & QH_CMASK) >> 8);
-	int split_duration = end_uframe - start_uframe;
-
-	now = readl(&ehci->regs->frame_index) % (ehci->periodic_size << 3);
-
-	next_start = ((1024 << 3) + (qh->start << 3) + start_uframe - now)
-			% (qh->period << 3);
-	prev_start = (qh->period << 3) - next_start;
-
-	/*
-	 * Make sure there will be at least one uframe when qh is safe.
-	 */
-	if ((qh->period << 3) <= (ehci->i_thresh + 2 + split_duration))
-		/* never safe */
-		return -EINVAL;
-
-	/*
-	 * Wait 1 uframe after transaction should have started, to make
-	 * sure controller has time to write back overlay, so we can
-	 * check QTD_STS_STS to see if transaction is in progress.
-	 */
-	if ((next_start > ehci->i_thresh) && (prev_start > 1))
-		/* safe to set "i" bit if split isn't in progress */
-		return (qh->hw_token & STATUS_BIT(ehci)) ? 0 : 1;
-	else
-		return 0;
-}
-
-/* Set inactivate bit for all the split interrupt QHs. */
-static void qh_inactivate_split_intr_qhs (struct ehci_hcd *ehci)
-{
-	struct ehci_qh	*qh;
-	int		not_done, safe;
-	u32		inactivate = INACTIVATE_BIT(ehci);
-	u32		active = ACTIVE_BIT(ehci);
-
-	do {
-		not_done = 0;
-		list_for_each_entry(qh, &ehci->split_intr_qhs,
-				split_intr_qhs) {
-			if (qh->hw_info1 & inactivate)
-				/* already off */
-				continue;
-			/*
-			 * To avoid setting "I" after the start split happens,
-			 * don't set it if the QH might be cached in the
-			 * controller.  Some HCs (Broadcom/ServerWorks HT1000)
-			 * will stop in the middle of a split transaction when
-			 * the "I" bit is set.
-			 */
-			safe = safe_to_modify_i(ehci, qh);
-			if (safe == 0) {
-				not_done = 1;
-			} else if (safe > 0) {
-				qh->was_active = qh->hw_token & active;
-				qh->hw_info1 |= inactivate;
-			}
-		}
-	} while (not_done);
-	wmb();
-}
-
-static void qh_reactivate_split_intr_qhs (struct ehci_hcd *ehci)
-{
-	struct ehci_qh	*qh;
-	u32		token;
-	int		not_done, safe;
-	u32		inactivate = INACTIVATE_BIT(ehci);
-	u32		active = ACTIVE_BIT(ehci);
-	u32		halt = HALT_BIT(ehci);
-
-	do {
-		not_done = 0;
-		list_for_each_entry(qh, &ehci->split_intr_qhs, split_intr_qhs) {
-			if (!(qh->hw_info1 & inactivate)) /* already on */
-				continue;
-			/*
-			 * Don't reactivate if cached, or controller might
-			 * overwrite overlay after we modify it!
-			 */
-			safe = safe_to_modify_i(ehci, qh);
-			if (safe == 0) {
-				not_done = 1;
-			} else if (safe > 0) {
-				/* See EHCI 1.0 section 4.15.2.4. */
-				token = qh->hw_token;
-				qh->hw_token = (token | halt) & ~active;
-				wmb();
-				qh->hw_info1 &= ~inactivate;
-				wmb();
-				qh->hw_token = (token & ~halt) | qh->was_active;
-			}
-		}
-	} while (not_done);
-}
-#endif
 
 /* periodic schedule slots have iso tds (normal or split) first, then a
  * sparse tree for active interrupt transfers.
@@ -599,17 +496,6 @@
 		period, hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK),
 		qh, qh->start, qh->usecs, qh->c_usecs);
 
-#ifdef CONFIG_CPU_FREQ
-	/*
-	 * If low/full speed interrupt QHs are inactive (because of
-	 * cpufreq changing processor speeds), start QH with I flag set--
-	 * it will automatically be cleared when cpufreq is done.
-	 */
-	if (ehci->cpufreq_changing)
-		if (!(qh->hw_info1 & (cpu_to_le32(1 << 13))))
-			qh->hw_info1 |= INACTIVATE_BIT(ehci);
-#endif
-
 	/* high bandwidth, or otherwise every microframe */
 	if (period == 0)
 		period = 1;
@@ -658,12 +544,6 @@
 		? ((qh->usecs + qh->c_usecs) / qh->period)
 		: (qh->usecs * 8);
 
-#ifdef CONFIG_CPU_FREQ
-	/* add qh to list of low/full speed interrupt QHs, if applicable */
-	if (!(qh->hw_info1 & (cpu_to_le32(1 << 13)))) {
-		list_add(&qh->split_intr_qhs, &ehci->split_intr_qhs);
-	}
-#endif
 	/* maybe enable periodic schedule processing */
 	if (!ehci->periodic_sched++)
 		return enable_periodic (ehci);
@@ -683,13 +563,6 @@
 	// THEN
 	//   qh->hw_info1 |= __constant_cpu_to_hc32(1 << 7 /* "ignore" */);
 
-#ifdef CONFIG_CPU_FREQ
-	/* remove qh from list of low/full speed interrupt QHs */
-	if (!(qh->hw_info1 & (cpu_to_le32(1 << 13)))) {
-		list_del_init(&qh->split_intr_qhs);
-	}
-#endif
-
 	/* high bandwidth, or otherwise part of every microframe */
 	if ((period = qh->period) == 0)
 		period = 1;
@@ -924,7 +797,6 @@
 
 static int intr_submit (
 	struct ehci_hcd		*ehci,
-	struct usb_host_endpoint *ep,
 	struct urb		*urb,
 	struct list_head	*qtd_list,
 	gfp_t			mem_flags
@@ -932,23 +804,26 @@
 	unsigned		epnum;
 	unsigned long		flags;
 	struct ehci_qh		*qh;
-	int			status = 0;
+	int			status;
 	struct list_head	empty;
 
 	/* get endpoint and transfer/schedule data */
-	epnum = ep->desc.bEndpointAddress;
+	epnum = urb->ep->desc.bEndpointAddress;
 
 	spin_lock_irqsave (&ehci->lock, flags);
 
 	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
 			&ehci_to_hcd(ehci)->flags))) {
 		status = -ESHUTDOWN;
-		goto done;
+		goto done_not_linked;
 	}
+	status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+	if (unlikely(status))
+		goto done_not_linked;
 
 	/* get qh and force any scheduling errors */
 	INIT_LIST_HEAD (&empty);
-	qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv);
+	qh = qh_append_tds(ehci, urb, &empty, epnum, &urb->ep->hcpriv);
 	if (qh == NULL) {
 		status = -ENOMEM;
 		goto done;
@@ -959,13 +834,16 @@
 	}
 
 	/* then queue the urb's tds to the qh */
-	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+	qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
 	BUG_ON (qh == NULL);
 
 	/* ... update usbfs periodic stats */
 	ehci_to_hcd(ehci)->self.bandwidth_int_reqs++;
 
 done:
+	if (unlikely(status))
+		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
 	spin_unlock_irqrestore (&ehci->lock, flags);
 	if (status)
 		qtd_list_free (ehci, urb, qtd_list);
@@ -1749,7 +1627,7 @@
 
 	/* give urb back to the driver ... can be out-of-order */
 	dev = urb->dev;
-	ehci_urb_done (ehci, urb);
+	ehci_urb_done(ehci, urb, 0);
 	urb = NULL;
 
 	/* defer stopping schedule; completion can submit */
@@ -1813,12 +1691,19 @@
 	/* schedule ... need to lock */
 	spin_lock_irqsave (&ehci->lock, flags);
 	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
-			       &ehci_to_hcd(ehci)->flags)))
+			       &ehci_to_hcd(ehci)->flags))) {
 		status = -ESHUTDOWN;
-	else
-		status = iso_stream_schedule (ehci, urb, stream);
+		goto done_not_linked;
+	}
+	status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+	if (unlikely(status))
+		goto done_not_linked;
+	status = iso_stream_schedule(ehci, urb, stream);
 	if (likely (status == 0))
 		itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+	else
+		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
 	spin_unlock_irqrestore (&ehci->lock, flags);
 
 done:
@@ -2115,7 +2000,7 @@
 
 	/* give urb back to the driver */
 	dev = urb->dev;
-	ehci_urb_done (ehci, urb);
+	ehci_urb_done(ehci, urb, 0);
 	urb = NULL;
 
 	/* defer stopping schedule; completion can submit */
@@ -2176,12 +2061,19 @@
 	/* schedule ... need to lock */
 	spin_lock_irqsave (&ehci->lock, flags);
 	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
-			       &ehci_to_hcd(ehci)->flags)))
+			       &ehci_to_hcd(ehci)->flags))) {
 		status = -ESHUTDOWN;
-	else
-		status = iso_stream_schedule (ehci, urb, stream);
+		goto done_not_linked;
+	}
+	status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+	if (unlikely(status))
+		goto done_not_linked;
+	status = iso_stream_schedule(ehci, urb, stream);
 	if (status == 0)
 		sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+	else
+		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
 	spin_unlock_irqrestore (&ehci->lock, flags);
 
 done:
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 2c68a04..951d69f 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -71,12 +71,6 @@
 	__u32			hcs_params;	/* cached register copy */
 	spinlock_t		lock;
 
-#ifdef CONFIG_CPU_FREQ
-	struct notifier_block	cpufreq_transition;
-	int			cpufreq_changing;
-	struct list_head	split_intr_qhs;
-#endif
-
 	/* async schedule support */
 	struct ehci_qh		*async;
 	struct ehci_qh		*reclaim;
@@ -439,10 +433,6 @@
 	__hc32			hw_next;	/* see EHCI 3.6.1 */
 	__hc32			hw_info1;       /* see EHCI 3.6.2 */
 #define	QH_HEAD		0x00008000
-#define	QH_INACTIVATE	0x00000080
-
-#define INACTIVATE_BIT(ehci)	cpu_to_hc32(ehci, QH_INACTIVATE)
-
 	__hc32			hw_info2;        /* see EHCI 3.6.2 */
 #define	QH_SMASK	0x000000ff
 #define	QH_CMASK	0x0000ff00
@@ -492,10 +482,6 @@
 	unsigned short		start;		/* where polling starts */
 #define NO_FRAME ((unsigned short)~0)			/* pick new start */
 	struct usb_device	*dev;		/* access to TT */
-#ifdef CONFIG_CPU_FREQ
-	struct list_head	split_intr_qhs; /* list of split qhs */
-	__le32			was_active;	/* active bit before "i" set */
-#endif
 } __attribute__ ((aligned (32)));
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 46873f2..c27417f 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -228,7 +228,6 @@
 				   struct urb, urb_list);
 		ptd = &ep->ptd;
 		len = ep->length;
-		spin_lock(&urb->lock);
 		ep->data = (unsigned char *)urb->transfer_buffer
 		    + urb->actual_length;
 
@@ -264,7 +263,6 @@
 		    | PTD_EP(ep->epnum);
 		ptd->len = PTD_LEN(len) | PTD_DIR(dir);
 		ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe));
-		spin_unlock(&urb->lock);
 		if (!ep->active) {
 			ptd->mps |= PTD_LAST_MSK;
 			isp116x->atl_last_dir = dir;
@@ -275,6 +273,61 @@
 }
 
 /*
+  Take done or failed requests out of schedule. Give back
+  processed urbs.
+*/
+static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
+			   struct urb *urb, int status)
+__releases(isp116x->lock) __acquires(isp116x->lock)
+{
+	unsigned i;
+
+	ep->error_count = 0;
+
+	if (usb_pipecontrol(urb->pipe))
+		ep->nextpid = USB_PID_SETUP;
+
+	urb_dbg(urb, "Finish");
+
+	usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb);
+	spin_unlock(&isp116x->lock);
+	usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, status);
+	spin_lock(&isp116x->lock);
+
+	/* take idle endpoints out of the schedule */
+	if (!list_empty(&ep->hep->urb_list))
+		return;
+
+	/* async deschedule */
+	if (!list_empty(&ep->schedule)) {
+		list_del_init(&ep->schedule);
+		return;
+	}
+
+	/* periodic deschedule */
+	DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+	for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
+		struct isp116x_ep *temp;
+		struct isp116x_ep **prev = &isp116x->periodic[i];
+
+		while (*prev && ((temp = *prev) != ep))
+			prev = &temp->next;
+		if (*prev)
+			*prev = ep->next;
+		isp116x->load[i] -= ep->load;
+	}
+	ep->branch = PERIODIC_SIZE;
+	isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
+	    ep->load / ep->period;
+
+	/* switch irq type? */
+	if (!--isp116x->periodic_count) {
+		isp116x->irqenb &= ~HCuPINT_SOF;
+		isp116x->irqenb |= HCuPINT_ATL;
+	}
+}
+
+/*
   Analyze transfer results, handle partial transfers and errors
 */
 static void postproc_atl_queue(struct isp116x *isp116x)
@@ -284,6 +337,7 @@
 	struct usb_device *udev;
 	struct ptd *ptd;
 	int short_not_ok;
+	int status;
 	u8 cc;
 
 	for (ep = isp116x->atl_active; ep; ep = ep->active) {
@@ -294,7 +348,7 @@
 		ptd = &ep->ptd;
 		cc = PTD_GET_CC(ptd);
 		short_not_ok = 1;
-		spin_lock(&urb->lock);
+		status = -EINPROGRESS;
 
 		/* Data underrun is special. For allowed underrun
 		   we clear the error and continue as normal. For
@@ -302,47 +356,36 @@
 		   immediately while for control transfer,
 		   we do a STATUS stage. */
 		if (cc == TD_DATAUNDERRUN) {
-			if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) {
-				DBG("Allowed data underrun\n");
+			if (!(urb->transfer_flags & URB_SHORT_NOT_OK) ||
+					usb_pipecontrol(urb->pipe)) {
+				DBG("Allowed or control data underrun\n");
 				cc = TD_CC_NOERROR;
 				short_not_ok = 0;
 			} else {
 				ep->error_count = 1;
-				if (usb_pipecontrol(urb->pipe))
-					ep->nextpid = USB_PID_ACK;
-				else
-					usb_settoggle(udev, ep->epnum,
-						      ep->nextpid ==
-						      USB_PID_OUT,
-						      PTD_GET_TOGGLE(ptd));
+				usb_settoggle(udev, ep->epnum,
+					      ep->nextpid == USB_PID_OUT,
+					      PTD_GET_TOGGLE(ptd));
 				urb->actual_length += PTD_GET_COUNT(ptd);
-				urb->status = cc_to_error[TD_DATAUNDERRUN];
-				spin_unlock(&urb->lock);
-				continue;
+				status = cc_to_error[TD_DATAUNDERRUN];
+				goto done;
 			}
 		}
-		/* Keep underrun error through the STATUS stage */
-		if (urb->status == cc_to_error[TD_DATAUNDERRUN])
-			cc = TD_DATAUNDERRUN;
 
 		if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED
 		    && (++ep->error_count >= 3 || cc == TD_CC_STALL
 			|| cc == TD_DATAOVERRUN)) {
-			if (urb->status == -EINPROGRESS)
-				urb->status = cc_to_error[cc];
+			status = cc_to_error[cc];
 			if (ep->nextpid == USB_PID_ACK)
 				ep->nextpid = 0;
-			spin_unlock(&urb->lock);
-			continue;
+			goto done;
 		}
 		/* According to usb spec, zero-length Int transfer signals
 		   finishing of the urb. Hey, does this apply only
 		   for IN endpoints? */
 		if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) {
-			if (urb->status == -EINPROGRESS)
-				urb->status = 0;
-			spin_unlock(&urb->lock);
-			continue;
+			status = 0;
+			goto done;
 		}
 
 		/* Relax after previously failed, but later succeeded
@@ -381,8 +424,8 @@
 			/* All data for this URB is transferred, let's finish */
 			if (usb_pipecontrol(urb->pipe))
 				ep->nextpid = USB_PID_ACK;
-			else if (urb->status == -EINPROGRESS)
-				urb->status = 0;
+			else
+				status = 0;
 			break;
 		case USB_PID_SETUP:
 			if (PTD_GET_ACTIVE(ptd)
@@ -402,69 +445,16 @@
 			if (PTD_GET_ACTIVE(ptd)
 			    || (cc != TD_CC_NOERROR && cc < 0x0E))
 				break;
-			if (urb->status == -EINPROGRESS)
-				urb->status = 0;
+			status = 0;
 			ep->nextpid = 0;
 			break;
 		default:
 			BUG();
 		}
-		spin_unlock(&urb->lock);
-	}
-}
 
-/*
-  Take done or failed requests out of schedule. Give back
-  processed urbs.
-*/
-static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
-			   struct urb *urb)
-__releases(isp116x->lock) __acquires(isp116x->lock)
-{
-	unsigned i;
-
-	urb->hcpriv = NULL;
-	ep->error_count = 0;
-
-	if (usb_pipecontrol(urb->pipe))
-		ep->nextpid = USB_PID_SETUP;
-
-	urb_dbg(urb, "Finish");
-
-	spin_unlock(&isp116x->lock);
-	usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
-	spin_lock(&isp116x->lock);
-
-	/* take idle endpoints out of the schedule */
-	if (!list_empty(&ep->hep->urb_list))
-		return;
-
-	/* async deschedule */
-	if (!list_empty(&ep->schedule)) {
-		list_del_init(&ep->schedule);
-		return;
-	}
-
-	/* periodic deschedule */
-	DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
-	for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
-		struct isp116x_ep *temp;
-		struct isp116x_ep **prev = &isp116x->periodic[i];
-
-		while (*prev && ((temp = *prev) != ep))
-			prev = &temp->next;
-		if (*prev)
-			*prev = ep->next;
-		isp116x->load[i] -= ep->load;
-	}
-	ep->branch = PERIODIC_SIZE;
-	isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
-	    ep->load / ep->period;
-
-	/* switch irq type? */
-	if (!--isp116x->periodic_count) {
-		isp116x->irqenb &= ~HCuPINT_SOF;
-		isp116x->irqenb |= HCuPINT_ATL;
+ done:
+		if (status != -EINPROGRESS || urb->unlinked)
+			finish_request(isp116x, ep, urb, status);
 	}
 }
 
@@ -570,9 +560,6 @@
 */
 static void finish_atl_transfers(struct isp116x *isp116x)
 {
-	struct isp116x_ep *ep;
-	struct urb *urb;
-
 	if (!isp116x->atl_active)
 		return;
 	/* Fifo not ready? */
@@ -582,16 +569,6 @@
 	atomic_inc(&isp116x->atl_finishing);
 	unpack_fifo(isp116x);
 	postproc_atl_queue(isp116x);
-	for (ep = isp116x->atl_active; ep; ep = ep->active) {
-		urb =
-		    container_of(ep->hep->urb_list.next, struct urb, urb_list);
-		/* USB_PID_ACK check here avoids finishing of
-		   control transfers, for which TD_DATAUNDERRUN
-		   occured, while URB_SHORT_NOT_OK was set */
-		if (urb && urb->status != -EINPROGRESS
-		    && ep->nextpid != USB_PID_ACK)
-			finish_request(isp116x, ep, urb);
-	}
 	atomic_dec(&isp116x->atl_finishing);
 }
 
@@ -685,7 +662,7 @@
 /*-----------------------------------------------------------------*/
 
 static int isp116x_urb_enqueue(struct usb_hcd *hcd,
-			       struct usb_host_endpoint *hep, struct urb *urb,
+			       struct urb *urb,
 			       gfp_t mem_flags)
 {
 	struct isp116x *isp116x = hcd_to_isp116x(hcd);
@@ -694,6 +671,7 @@
 	int is_out = !usb_pipein(pipe);
 	int type = usb_pipetype(pipe);
 	int epnum = usb_pipeendpoint(pipe);
+	struct usb_host_endpoint *hep = urb->ep;
 	struct isp116x_ep *ep = NULL;
 	unsigned long flags;
 	int i;
@@ -717,7 +695,12 @@
 	if (!HC_IS_RUNNING(hcd->state)) {
 		kfree(ep);
 		ret = -ENODEV;
-		goto fail;
+		goto fail_not_linked;
+	}
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (ret) {
+		kfree(ep);
+		goto fail_not_linked;
 	}
 
 	if (hep->hcpriv)
@@ -820,19 +803,13 @@
 		}
 	}
 
-	/* in case of unlink-during-submit */
-	spin_lock(&urb->lock);
-	if (urb->status != -EINPROGRESS) {
-		spin_unlock(&urb->lock);
-		finish_request(isp116x, ep, urb);
-		ret = 0;
-		goto fail;
-	}
 	urb->hcpriv = hep;
-	spin_unlock(&urb->lock);
 	start_atl_transfers(isp116x);
 
       fail:
+	if (ret)
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+      fail_not_linked:
 	spin_unlock_irqrestore(&isp116x->lock, flags);
 	return ret;
 }
@@ -840,20 +817,21 @@
 /*
    Dequeue URBs.
 */
-static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+		int status)
 {
 	struct isp116x *isp116x = hcd_to_isp116x(hcd);
 	struct usb_host_endpoint *hep;
 	struct isp116x_ep *ep, *ep_act;
 	unsigned long flags;
+	int rc;
 
 	spin_lock_irqsave(&isp116x->lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
+
 	hep = urb->hcpriv;
-	/* URB already unlinked (or never linked)? */
-	if (!hep) {
-		spin_unlock_irqrestore(&isp116x->lock, flags);
-		return 0;
-	}
 	ep = hep->hcpriv;
 	WARN_ON(hep != ep->hep);
 
@@ -870,10 +848,10 @@
 			}
 
 	if (urb)
-		finish_request(isp116x, ep, urb);
-
+		finish_request(isp116x, ep, urb, status);
+ done:
 	spin_unlock_irqrestore(&isp116x->lock, flags);
-	return 0;
+	return rc;
 }
 
 static void isp116x_endpoint_disable(struct usb_hcd *hcd,
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index 6f9e43e..ebab5ce 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -24,7 +24,7 @@
  * small: 0) header + data packets 1) just header
  */
 static void __maybe_unused
-urb_print (struct urb * urb, char * str, int small)
+urb_print(struct urb * urb, char * str, int small, int status)
 {
 	unsigned int pipe= urb->pipe;
 
@@ -34,7 +34,7 @@
 	}
 
 #ifndef	OHCI_VERBOSE_DEBUG
-	if (urb->status != 0)
+	if (status != 0)
 #endif
 	dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
 		    str,
@@ -46,7 +46,7 @@
 		    urb->transfer_flags,
 		    urb->actual_length,
 		    urb->transfer_buffer_length,
-		    urb->status);
+		    status);
 
 #ifdef	OHCI_VERBOSE_DEBUG
 	if (!small) {
@@ -66,7 +66,7 @@
 						urb->transfer_buffer_length: urb->actual_length;
 			for (i = 0; i < 16 && i < len; i++)
 				printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
-			printk ("%s stat:%d\n", i < len? "...": "", urb->status);
+			printk ("%s stat:%d\n", i < len? "...": "", status);
 		}
 	}
 #endif
@@ -74,7 +74,7 @@
 
 #define ohci_dbg_sw(ohci, next, size, format, arg...) \
 	do { \
-	if (next) { \
+	if (next != NULL) { \
 		unsigned s_len; \
 		s_len = scnprintf (*next, *size, format, ## arg ); \
 		*size -= s_len; *next += s_len; \
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 2038125..240c7f5 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -81,7 +81,6 @@
 static int ohci_init (struct ohci_hcd *ohci);
 static void ohci_stop (struct usb_hcd *hcd);
 static int ohci_restart (struct ohci_hcd *ohci);
-static void ohci_quirk_nec_worker (struct work_struct *work);
 
 #include "ohci-hub.c"
 #include "ohci-dbg.c"
@@ -118,7 +117,6 @@
  */
 static int ohci_urb_enqueue (
 	struct usb_hcd	*hcd,
-	struct usb_host_endpoint *ep,
 	struct urb	*urb,
 	gfp_t		mem_flags
 ) {
@@ -131,11 +129,11 @@
 	int		retval = 0;
 
 #ifdef OHCI_VERBOSE_DEBUG
-	urb_print (urb, "SUB", usb_pipein (pipe));
+	urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS);
 #endif
 
 	/* every endpoint has a ed, locate and maybe (re)initialize it */
-	if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval)))
+	if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval)))
 		return -ENOMEM;
 
 	/* for the private part of the URB we need the number of TDs (size) */
@@ -171,11 +169,10 @@
 	}
 
 	/* allocate the private part of the URB */
-	urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
+	urb_priv = kzalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
 			mem_flags);
 	if (!urb_priv)
 		return -ENOMEM;
-	memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
 	INIT_LIST_HEAD (&urb_priv->pending);
 	urb_priv->length = size;
 	urb_priv->ed = ed;
@@ -201,22 +198,17 @@
 		retval = -ENODEV;
 		goto fail;
 	}
-
-	/* in case of unlink-during-submit */
-	spin_lock (&urb->lock);
-	if (urb->status != -EINPROGRESS) {
-		spin_unlock (&urb->lock);
-		urb->hcpriv = urb_priv;
-		finish_urb (ohci, urb);
-		retval = 0;
+	retval = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (retval)
 		goto fail;
-	}
 
 	/* schedule the ed if needed */
 	if (ed->state == ED_IDLE) {
 		retval = ed_schedule (ohci, ed);
-		if (retval < 0)
-			goto fail0;
+		if (retval < 0) {
+			usb_hcd_unlink_urb_from_ep(hcd, urb);
+			goto fail;
+		}
 		if (ed->type == PIPE_ISOCHRONOUS) {
 			u16	frame = ohci_frame_no(ohci);
 
@@ -240,8 +232,6 @@
 	urb->hcpriv = urb_priv;
 	td_submit_urb (ohci, urb);
 
-fail0:
-	spin_unlock (&urb->lock);
 fail:
 	if (retval)
 		urb_free_priv (ohci, urb_priv);
@@ -250,22 +240,26 @@
 }
 
 /*
- * decouple the URB from the HC queues (TDs, urb_priv); it's
- * already marked using urb->status.  reporting is always done
+ * decouple the URB from the HC queues (TDs, urb_priv).
+ * reporting is always done
  * asynchronously, and we might be dealing with an urb that's
  * partially transferred, or an ED with other urbs being unlinked.
  */
-static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 	unsigned long		flags;
+	int			rc;
 
 #ifdef OHCI_VERBOSE_DEBUG
-	urb_print (urb, "UNLINK", 1);
+	urb_print(urb, "UNLINK", 1, status);
 #endif
 
 	spin_lock_irqsave (&ohci->lock, flags);
-	if (HC_IS_RUNNING(hcd->state)) {
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc) {
+		;	/* Do nothing */
+	} else if (HC_IS_RUNNING(hcd->state)) {
 		urb_priv_t  *urb_priv;
 
 		/* Unless an IRQ completed the unlink while it was being
@@ -283,10 +277,10 @@
 		 * any more ... just clean up every urb's memory.
 		 */
 		if (urb->hcpriv)
-			finish_urb (ohci, urb);
+			finish_urb(ohci, urb, status);
 	}
 	spin_unlock_irqrestore (&ohci->lock, flags);
-	return 0;
+	return rc;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -315,6 +309,8 @@
 	if (!HC_IS_RUNNING (hcd->state)) {
 sanitize:
 		ed->state = ED_IDLE;
+		if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+			ohci->eds_scheduled--;
 		finish_unlinks (ohci, 0);
 	}
 
@@ -322,7 +318,12 @@
 	case ED_UNLINK:		/* wait for hw to finish? */
 		/* major IRQ delivery trouble loses INTR_SF too... */
 		if (limit-- == 0) {
-			ohci_warn (ohci, "IRQ INTR_SF lossage\n");
+			ohci_warn(ohci, "ED unlink timeout\n");
+			if (quirk_zfmicro(ohci)) {
+				ohci_warn(ohci, "Attempting ZF TD recovery\n");
+				ohci->ed_to_check = ed;
+				ohci->zf_delay = 2;
+			}
 			goto sanitize;
 		}
 		spin_unlock_irqrestore (&ohci->lock, flags);
@@ -380,6 +381,93 @@
 	(void) ohci_readl (ohci, &ohci->regs->control);
 }
 
+static int check_ed(struct ohci_hcd *ohci, struct ed *ed)
+{
+	return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0
+		&& (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK)
+			== (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK)
+		&& !list_empty(&ed->td_list);
+}
+
+/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes
+ * an interrupt TD but neglects to add it to the donelist.  On systems with
+ * this chipset, we need to periodically check the state of the queues to look
+ * for such "lost" TDs.
+ */
+static void unlink_watchdog_func(unsigned long _ohci)
+{
+	long		flags;
+	unsigned	max;
+	unsigned	seen_count = 0;
+	unsigned	i;
+	struct ed	**seen = NULL;
+	struct ohci_hcd	*ohci = (struct ohci_hcd *) _ohci;
+
+	spin_lock_irqsave(&ohci->lock, flags);
+	max = ohci->eds_scheduled;
+	if (!max)
+		goto done;
+
+	if (ohci->ed_to_check)
+		goto out;
+
+	seen = kcalloc(max, sizeof *seen, GFP_ATOMIC);
+	if (!seen)
+		goto out;
+
+	for (i = 0; i < NUM_INTS; i++) {
+		struct ed	*ed = ohci->periodic[i];
+
+		while (ed) {
+			unsigned	temp;
+
+			/* scan this branch of the periodic schedule tree */
+			for (temp = 0; temp < seen_count; temp++) {
+				if (seen[temp] == ed) {
+					/* we've checked it and what's after */
+					ed = NULL;
+					break;
+				}
+			}
+			if (!ed)
+				break;
+			seen[seen_count++] = ed;
+			if (!check_ed(ohci, ed)) {
+				ed = ed->ed_next;
+				continue;
+			}
+
+			/* HC's TD list is empty, but HCD sees at least one
+			 * TD that's not been sent through the donelist.
+			 */
+			ohci->ed_to_check = ed;
+			ohci->zf_delay = 2;
+
+			/* The HC may wait until the next frame to report the
+			 * TD as done through the donelist and INTR_WDH.  (We
+			 * just *assume* it's not a multi-TD interrupt URB;
+			 * those could defer the IRQ more than one frame, using
+			 * DI...)  Check again after the next INTR_SF.
+			 */
+			ohci_writel(ohci, OHCI_INTR_SF,
+					&ohci->regs->intrstatus);
+			ohci_writel(ohci, OHCI_INTR_SF,
+					&ohci->regs->intrenable);
+
+			/* flush those writes */
+			(void) ohci_readl(ohci, &ohci->regs->control);
+
+			goto out;
+		}
+	}
+out:
+	kfree(seen);
+	if (ohci->eds_scheduled)
+		mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
+done:
+	spin_unlock_irqrestore(&ohci->lock, flags);
+}
+
 /*-------------------------------------------------------------------------*
  * HC functions
  *-------------------------------------------------------------------------*/
@@ -617,6 +705,15 @@
 	mdelay ((temp >> 23) & 0x1fe);
 	hcd->state = HC_STATE_RUNNING;
 
+	if (quirk_zfmicro(ohci)) {
+		/* Create timer to watch for bad queue state on ZF Micro */
+		setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func,
+				(unsigned long) ohci);
+
+		ohci->eds_scheduled = 0;
+		ohci->ed_to_check = NULL;
+	}
+
 	ohci_dump (ohci, 1);
 
 	return 0;
@@ -630,10 +727,11 @@
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 	struct ohci_regs __iomem *regs = ohci->regs;
- 	int			ints; 
+	int			ints;
 
 	/* we can eliminate a (slow) ohci_readl()
-	   if _only_ WDH caused this irq */
+	 * if _only_ WDH caused this irq
+	 */
 	if ((ohci->hcca->done_head != 0)
 			&& ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
 				& 0x01)) {
@@ -652,7 +750,7 @@
 
 	if (ints & OHCI_INTR_UE) {
 		// e.g. due to PCI Master/Target Abort
-		if (ohci->flags & OHCI_QUIRK_NEC) {
+		if (quirk_nec(ohci)) {
 			/* Workaround for a silicon bug in some NEC chips used
 			 * in Apple's PowerBooks. Adapted from Darwin code.
 			 */
@@ -714,6 +812,31 @@
 			ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable);
 	}
 
+	if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
+		spin_lock(&ohci->lock);
+		if (ohci->ed_to_check) {
+			struct ed *ed = ohci->ed_to_check;
+
+			if (check_ed(ohci, ed)) {
+				/* HC thinks the TD list is empty; HCD knows
+				 * at least one TD is outstanding
+				 */
+				if (--ohci->zf_delay == 0) {
+					struct td *td = list_entry(
+						ed->td_list.next,
+						struct td, td_list);
+					ohci_warn(ohci,
+						  "Reclaiming orphan TD %p\n",
+						  td);
+					takeback_td(ohci, td);
+					ohci->ed_to_check = NULL;
+				}
+			} else
+				ohci->ed_to_check = NULL;
+		}
+		spin_unlock(&ohci->lock);
+	}
+
 	/* could track INTR_SO to reduce available PCI/... bandwidth */
 
 	/* handle any pending URB/ED unlinks, leaving INTR_SF enabled
@@ -722,7 +845,9 @@
 	spin_lock (&ohci->lock);
 	if (ohci->ed_rm_list)
 		finish_unlinks (ohci, ohci_frame_no(ohci));
-	if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
+	if ((ints & OHCI_INTR_SF) != 0
+			&& !ohci->ed_rm_list
+			&& !ohci->ed_to_check
 			&& HC_IS_RUNNING(hcd->state))
 		ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
 	spin_unlock (&ohci->lock);
@@ -752,6 +877,9 @@
 	free_irq(hcd->irq, hcd);
 	hcd->irq = -1;
 
+	if (quirk_zfmicro(ohci))
+		del_timer(&ohci->unlink_watchdog);
+
 	remove_debug_files (ohci);
 	ohci_mem_cleanup (ohci);
 	if (ohci->hcca) {
@@ -799,9 +927,8 @@
 					ed, ed->state);
 		}
 
-		spin_lock (&urb->lock);
-		urb->status = -ESHUTDOWN;
-		spin_unlock (&urb->lock);
+		if (!urb->unlinked)
+			urb->unlinked = -ESHUTDOWN;
 	}
 	finish_unlinks (ohci, 0);
 	spin_unlock_irq(&ohci->lock);
@@ -829,27 +956,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* NEC workaround */
-static void ohci_quirk_nec_worker(struct work_struct *work)
-{
-	struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
-	int status;
-
-	status = ohci_init(ohci);
-	if (status != 0) {
-		ohci_err(ohci, "Restarting NEC controller failed "
-			 "in ohci_init, %d\n", status);
-		return;
-	}
-
-	status = ohci_restart(ohci);
-	if (status != 0)
-		ohci_err(ohci, "Restarting NEC controller failed "
-			 "in ohci_restart, %d\n", status);
-}
-
-/*-------------------------------------------------------------------------*/
-
 #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
 
 MODULE_AUTHOR (DRIVER_AUTHOR);
@@ -927,11 +1033,17 @@
 #define PS3_SYSTEM_BUS_DRIVER	ps3_ohci_driver
 #endif
 
+#ifdef CONFIG_USB_OHCI_HCD_SSB
+#include "ohci-ssb.c"
+#define SSB_OHCI_DRIVER		ssb_ohci_driver
+#endif
+
 #if	!defined(PCI_DRIVER) &&		\
 	!defined(PLATFORM_DRIVER) &&	\
 	!defined(OF_PLATFORM_DRIVER) &&	\
 	!defined(SA1111_DRIVER) &&	\
-	!defined(PS3_SYSTEM_BUS_DRIVER)
+	!defined(PS3_SYSTEM_BUS_DRIVER) && \
+	!defined(SSB_OHCI_DRIVER)
 #error "missing bus glue for ohci-hcd"
 #endif
 
@@ -976,10 +1088,20 @@
 		goto error_pci;
 #endif
 
+#ifdef SSB_OHCI_DRIVER
+	retval = ssb_driver_register(&SSB_OHCI_DRIVER);
+	if (retval)
+		goto error_ssb;
+#endif
+
 	return retval;
 
 	/* Error path */
+#ifdef SSB_OHCI_DRIVER
+ error_ssb:
+#endif
 #ifdef PCI_DRIVER
+	pci_unregister_driver(&PCI_DRIVER);
  error_pci:
 #endif
 #ifdef SA1111_DRIVER
@@ -1004,6 +1126,9 @@
 
 static void __exit ohci_hcd_mod_exit(void)
 {
+#ifdef SSB_OHCI_DRIVER
+	ssb_driver_unregister(&SSB_OHCI_DRIVER);
+#endif
 #ifdef PCI_DRIVER
 	pci_unregister_driver(&PCI_DRIVER);
 #endif
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index 450c7b4..2f20d3d 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -28,7 +28,6 @@
 	ohci->next_statechange = jiffies;
 	spin_lock_init (&ohci->lock);
 	INIT_LIST_HEAD (&ohci->pending);
-	INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker);
 }
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index a5e2eb8..d0360f6 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -84,7 +84,7 @@
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 
 	ohci->flags |= OHCI_QUIRK_ZFMICRO;
-	ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
+	ohci_dbg(ohci, "enabled Compaq ZFMicro chipset quirks\n");
 
 	return 0;
 }
@@ -113,11 +113,31 @@
 
 /* Check for NEC chip and apply quirk for allegedly lost interrupts.
  */
+
+static void ohci_quirk_nec_worker(struct work_struct *work)
+{
+	struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
+	int status;
+
+	status = ohci_init(ohci);
+	if (status != 0) {
+		ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
+			 "ohci_init", status);
+		return;
+	}
+
+	status = ohci_restart(ohci);
+	if (status != 0)
+		ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
+			 "ohci_restart", status);
+}
+
 static int ohci_quirk_nec(struct usb_hcd *hcd)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 
 	ohci->flags |= OHCI_QUIRK_NEC;
+	INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker);
 	ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
 
 	return 0;
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index c43b66a..0a74269 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -134,8 +134,11 @@
 	}
 
 	ohci = hcd_to_ohci(hcd);
-	if (is_bigendian)
+	if (is_bigendian) {
 		ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+		if (of_device_is_compatible(dn, "mpc5200-ohci"))
+			ohci->flags |= OHCI_QUIRK_FRAME_NO;
+	}
 
 	ohci_hcd_init(ohci);
 
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index 1a2e177..f95be189 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -73,6 +73,11 @@
 
 	ohci = hcd_to_ohci(hcd);
 	ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+
+#ifdef CONFIG_PPC_MPC52xx
+	/* MPC52xx doesn't need frame_no shift */
+	ohci->flags |= OHCI_QUIRK_FRAME_NO;
+#endif
 	ohci_hcd_init(ohci);
 
 	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index 830a3fe..5181732 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -36,29 +36,15 @@
  * PRECONDITION:  ohci lock held, irqs blocked.
  */
 static void
-finish_urb (struct ohci_hcd *ohci, struct urb *urb)
+finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status)
 __releases(ohci->lock)
 __acquires(ohci->lock)
 {
 	// ASSERT (urb->hcpriv != 0);
 
 	urb_free_priv (ohci, urb->hcpriv);
-	urb->hcpriv = NULL;
-
-	spin_lock (&urb->lock);
-	if (likely (urb->status == -EINPROGRESS))
-		urb->status = 0;
-	/* report short control reads right even though the data TD always
-	 * has TD_R set.  (much simpler, but creates the 1-td limit.)
-	 */
-	if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK)
-			&& unlikely (usb_pipecontrol (urb->pipe))
-			&& urb->actual_length < urb->transfer_buffer_length
-			&& usb_pipein (urb->pipe)
-			&& urb->status == 0) {
-		urb->status = -EREMOTEIO;
-	}
-	spin_unlock (&urb->lock);
+	if (likely(status == -EINPROGRESS))
+		status = 0;
 
 	switch (usb_pipetype (urb->pipe)) {
 	case PIPE_ISOCHRONOUS:
@@ -70,12 +56,13 @@
 	}
 
 #ifdef OHCI_VERBOSE_DEBUG
-	urb_print (urb, "RET", usb_pipeout (urb->pipe));
+	urb_print(urb, "RET", usb_pipeout (urb->pipe), status);
 #endif
 
 	/* urb->complete() can reenter this HCD */
+	usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb);
 	spin_unlock (&ohci->lock);
-	usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb);
+	usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status);
 	spin_lock (&ohci->lock);
 
 	/* stop periodic dma if it's not needed */
@@ -179,6 +166,10 @@
 	ed->ed_prev = NULL;
 	ed->ed_next = NULL;
 	ed->hwNextED = 0;
+	if (quirk_zfmicro(ohci)
+			&& (ed->type == PIPE_INTERRUPT)
+			&& !(ohci->eds_scheduled++))
+		mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
 	wmb ();
 
 	/* we care about rm_list when setting CLE/BLE in case the HC was at
@@ -708,19 +699,18 @@
  * Done List handling functions
  *-------------------------------------------------------------------------*/
 
-/* calculate transfer length/status and update the urb
- * PRECONDITION:  irqsafe (only for urb->status locking)
- */
-static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
+/* calculate transfer length/status and update the urb */
+static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td)
 {
 	u32	tdINFO = hc32_to_cpup (ohci, &td->hwINFO);
 	int	cc = 0;
+	int	status = -EINPROGRESS;
 
 	list_del (&td->td_list);
 
 	/* ISO ... drivers see per-TD length/status */
 	if (tdINFO & TD_ISO) {
-		u16	tdPSW = ohci_hwPSW (ohci, td, 0);
+		u16	tdPSW = ohci_hwPSW(ohci, td, 0);
 		int	dlen = 0;
 
 		/* NOTE:  assumes FC in tdINFO == 0, and that
@@ -729,7 +719,7 @@
 
 		cc = (tdPSW >> 12) & 0xF;
 		if (tdINFO & TD_CC)	/* hc didn't touch? */
-			return;
+			return status;
 
 		if (usb_pipeout (urb->pipe))
 			dlen = urb->iso_frame_desc [td->index].length;
@@ -762,12 +752,8 @@
 		if (cc == TD_DATAUNDERRUN
 				&& !(urb->transfer_flags & URB_SHORT_NOT_OK))
 			cc = TD_CC_NOERROR;
-		if (cc != TD_CC_NOERROR && cc < 0x0E) {
-			spin_lock (&urb->lock);
-			if (urb->status == -EINPROGRESS)
-				urb->status = cc_to_error [cc];
-			spin_unlock (&urb->lock);
-		}
+		if (cc != TD_CC_NOERROR && cc < 0x0E)
+			status = cc_to_error[cc];
 
 		/* count all non-empty packets except control SETUP packet */
 		if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) {
@@ -786,14 +772,15 @@
 				urb->actual_length,
 				urb->transfer_buffer_length);
 	}
+	return status;
 }
 
 /*-------------------------------------------------------------------------*/
 
-static inline struct td *
-ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
+static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc)
 {
 	struct urb		*urb = td->urb;
+	urb_priv_t		*urb_priv = urb->hcpriv;
 	struct ed		*ed = td->ed;
 	struct list_head	*tmp = td->td_list.next;
 	__hc32			toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C);
@@ -805,13 +792,12 @@
 	wmb ();
 	ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H);
 
-	/* put any later tds from this urb onto the donelist, after 'td',
-	 * order won't matter here: no errors, and nothing was transferred.
-	 * also patch the ed so it looks as if those tds completed normally.
+	/* Get rid of all later tds from this urb.  We don't have
+	 * to be careful: no errors and nothing was transferred.
+	 * Also patch the ed so it looks as if those tds completed normally.
 	 */
 	while (tmp != &ed->td_list) {
 		struct td	*next;
-		__hc32		info;
 
 		next = list_entry (tmp, struct td, td_list);
 		tmp = next->td_list.next;
@@ -826,14 +812,9 @@
 		 * then we need to leave the control STATUS packet queued
 		 * and clear ED_SKIP.
 		 */
-		info = next->hwINFO;
-		info |= cpu_to_hc32 (ohci, TD_DONE);
-		info &= ~cpu_to_hc32 (ohci, TD_CC);
-		next->hwINFO = info;
 
-		next->next_dl_td = rev;
-		rev = next;
-
+		list_del(&next->td_list);
+		urb_priv->td_cnt++;
 		ed->hwHeadP = next->hwNextTD | toggle;
 	}
 
@@ -859,8 +840,6 @@
 			hc32_to_cpu (ohci, td->hwINFO),
 			cc, cc_to_error [cc]);
 	}
-
-	return rev;
 }
 
 /* replies to the request have to be on a FIFO basis so
@@ -897,7 +876,7 @@
 		 */
 		if (cc != TD_CC_NOERROR
 				&& (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H)))
-			td_rev = ed_halted (ohci, td, cc, td_rev);
+			ed_halted(ohci, td, cc);
 
 		td->next_dl_td = td_rev;
 		td_rev = td;
@@ -940,8 +919,12 @@
 								TD_MASK;
 
 				/* INTR_WDH may need to clean up first */
-				if (td->td_dma != head)
-					goto skip_ed;
+				if (td->td_dma != head) {
+					if (ed == ohci->ed_to_check)
+						ohci->ed_to_check = NULL;
+					else
+						goto skip_ed;
+				}
 			}
 		}
 
@@ -974,7 +957,7 @@
 			urb = td->urb;
 			urb_priv = td->urb->hcpriv;
 
-			if (urb->status == -EINPROGRESS) {
+			if (!urb->unlinked) {
 				prev = &td->hwNextTD;
 				continue;
 			}
@@ -990,7 +973,7 @@
 			/* if URB is done, clean up */
 			if (urb_priv->td_cnt == urb_priv->length) {
 				modified = completed = 1;
-				finish_urb (ohci, urb);
+				finish_urb(ohci, urb, 0);
 			}
 		}
 		if (completed && !list_empty (&ed->td_list))
@@ -998,6 +981,8 @@
 
 		/* ED's now officially unlinked, hc doesn't see */
 		ed->state = ED_IDLE;
+		if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+			ohci->eds_scheduled--;
 		ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
 		ed->hwNextED = 0;
 		wmb ();
@@ -1021,7 +1006,7 @@
 
 		if (ohci->ed_controltail) {
 			command |= OHCI_CLF;
-			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+			if (quirk_zfmicro(ohci))
 				mdelay(1);
 			if (!(ohci->hc_control & OHCI_CTRL_CLE)) {
 				control |= OHCI_CTRL_CLE;
@@ -1031,7 +1016,7 @@
 		}
 		if (ohci->ed_bulktail) {
 			command |= OHCI_BLF;
-			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+			if (quirk_zfmicro(ohci))
 				mdelay(1);
 			if (!(ohci->hc_control & OHCI_CTRL_BLE)) {
 				control |= OHCI_CTRL_BLE;
@@ -1043,13 +1028,13 @@
 		/* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
 		if (control) {
 			ohci->hc_control |= control;
-			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+			if (quirk_zfmicro(ohci))
 				mdelay(1);
 			ohci_writel (ohci, ohci->hc_control,
 					&ohci->regs->control);
 		}
 		if (command) {
-			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+			if (quirk_zfmicro(ohci))
 				mdelay(1);
 			ohci_writel (ohci, command, &ohci->regs->cmdstatus);
 		}
@@ -1061,11 +1046,60 @@
 /*-------------------------------------------------------------------------*/
 
 /*
+ * Used to take back a TD from the host controller. This would normally be
+ * called from within dl_done_list, however it may be called directly if the
+ * HC no longer sees the TD and it has not appeared on the donelist (after
+ * two frames).  This bug has been observed on ZF Micro systems.
+ */
+static void takeback_td(struct ohci_hcd *ohci, struct td *td)
+{
+	struct urb	*urb = td->urb;
+	urb_priv_t	*urb_priv = urb->hcpriv;
+	struct ed	*ed = td->ed;
+	int		status;
+
+	/* update URB's length and status from TD */
+	status = td_done(ohci, urb, td);
+	urb_priv->td_cnt++;
+
+	/* If all this urb's TDs are done, call complete() */
+	if (urb_priv->td_cnt == urb_priv->length)
+		finish_urb(ohci, urb, status);
+
+	/* clean schedule:  unlink EDs that are no longer busy */
+	if (list_empty(&ed->td_list)) {
+		if (ed->state == ED_OPER)
+			start_ed_unlink(ohci, ed);
+
+	/* ... reenabling halted EDs only after fault cleanup */
+	} else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE))
+			== cpu_to_hc32(ohci, ED_SKIP)) {
+		td = list_entry(ed->td_list.next, struct td, td_list);
+		if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) {
+			ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP);
+			/* ... hc may need waking-up */
+			switch (ed->type) {
+			case PIPE_CONTROL:
+				ohci_writel(ohci, OHCI_CLF,
+						&ohci->regs->cmdstatus);
+				break;
+			case PIPE_BULK:
+				ohci_writel(ohci, OHCI_BLF,
+						&ohci->regs->cmdstatus);
+				break;
+			}
+		}
+	}
+}
+
+/*
  * Process normal completions (error or success) and clean the schedules.
  *
  * This is the main path for handing urbs back to drivers.  The only other
- * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of
- * scanning the (re-reversed) donelist as this does.
+ * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list,
+ * instead of scanning the (re-reversed) donelist as this does.  There's
+ * an abnormal path too, handling a quirk in some Compaq silicon:  URBs
+ * with TDs that appear to be orphaned are directly reclaimed.
  */
 static void
 dl_done_list (struct ohci_hcd *ohci)
@@ -1074,44 +1108,7 @@
 
 	while (td) {
 		struct td	*td_next = td->next_dl_td;
-		struct urb	*urb = td->urb;
-		urb_priv_t	*urb_priv = urb->hcpriv;
-		struct ed	*ed = td->ed;
-
-		/* update URB's length and status from TD */
-		td_done (ohci, urb, td);
-		urb_priv->td_cnt++;
-
-		/* If all this urb's TDs are done, call complete() */
-		if (urb_priv->td_cnt == urb_priv->length)
-			finish_urb (ohci, urb);
-
-		/* clean schedule:  unlink EDs that are no longer busy */
-		if (list_empty (&ed->td_list)) {
-			if (ed->state == ED_OPER)
-				start_ed_unlink (ohci, ed);
-
-		/* ... reenabling halted EDs only after fault cleanup */
-		} else if ((ed->hwINFO & cpu_to_hc32 (ohci,
-						ED_SKIP | ED_DEQUEUE))
-					== cpu_to_hc32 (ohci, ED_SKIP)) {
-			td = list_entry (ed->td_list.next, struct td, td_list);
-			if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) {
-				ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP);
-				/* ... hc may need waking-up */
-				switch (ed->type) {
-				case PIPE_CONTROL:
-					ohci_writel (ohci, OHCI_CLF,
-						&ohci->regs->cmdstatus);
-					break;
-				case PIPE_BULK:
-					ohci_writel (ohci, OHCI_BLF,
-						&ohci->regs->cmdstatus);
-					break;
-				}
-			}
-		}
-
+		takeback_td(ohci, td);
 		td = td_next;
 	}
 }
diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c
new file mode 100644
index 0000000..bc3e785
--- /dev/null
+++ b/drivers/usb/host/ohci-ssb.c
@@ -0,0 +1,247 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom USB-core OHCI driver
+ *
+ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * Derived from the OHCI-PCI driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Derived from the USBcore related parts of Broadcom-SB
+ * Copyright 2005 Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/ssb/ssb.h>
+
+
+#define SSB_OHCI_TMSLOW_HOSTMODE	(1 << 29)
+
+struct ssb_ohci_device {
+	struct ohci_hcd ohci; /* _must_ be at the beginning. */
+
+	u32 enable_flags;
+};
+
+static inline
+struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd)
+{
+	return (struct ssb_ohci_device *)(hcd->hcd_priv);
+}
+
+
+static int ssb_ohci_reset(struct usb_hcd *hcd)
+{
+	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+	struct ohci_hcd *ohci = &ohcidev->ohci;
+	int err;
+
+	ohci_hcd_init(ohci);
+	err = ohci_init(ohci);
+
+	return err;
+}
+
+static int ssb_ohci_start(struct usb_hcd *hcd)
+{
+	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+	struct ohci_hcd *ohci = &ohcidev->ohci;
+	int err;
+
+	err = ohci_run(ohci);
+	if (err < 0) {
+		ohci_err(ohci, "can't start\n");
+		ohci_stop(hcd);
+	}
+
+	return err;
+}
+
+#ifdef CONFIG_PM
+static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message)
+{
+	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+	struct ohci_hcd *ohci = &ohcidev->ohci;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ohci->lock, flags);
+
+	ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+	ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */
+
+	/* make sure snapshot being resumed re-enumerates everything */
+	if (message.event == PM_EVENT_PRETHAW)
+		ohci_usb_reset(ohci);
+
+	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+	spin_unlock_irqrestore(&ohci->lock, flags);
+	return 0;
+}
+
+static int ssb_ohci_hcd_resume(struct usb_hcd *hcd)
+{
+	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+	usb_hcd_resume_root_hub(hcd);
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct hc_driver ssb_ohci_hc_driver = {
+	.description		= "ssb-usb-ohci",
+	.product_desc		= "SSB OHCI Controller",
+	.hcd_priv_size		= sizeof(struct ssb_ohci_device),
+
+	.irq			= ohci_irq,
+	.flags			= HCD_MEMORY | HCD_USB11,
+
+	.reset			= ssb_ohci_reset,
+	.start			= ssb_ohci_start,
+	.stop			= ohci_stop,
+	.shutdown		= ohci_shutdown,
+
+#ifdef CONFIG_PM
+	.suspend		= ssb_ohci_hcd_suspend,
+	.resume			= ssb_ohci_hcd_resume,
+#endif
+
+	.urb_enqueue		= ohci_urb_enqueue,
+	.urb_dequeue		= ohci_urb_dequeue,
+	.endpoint_disable	= ohci_endpoint_disable,
+
+	.get_frame_number	= ohci_get_frame,
+
+	.hub_status_data	= ohci_hub_status_data,
+	.hub_control		= ohci_hub_control,
+	.hub_irq_enable		= ohci_rhsc_enable,
+	.bus_suspend		= ohci_bus_suspend,
+	.bus_resume		= ohci_bus_resume,
+
+	.start_port_reset	= ohci_start_port_reset,
+};
+
+static void ssb_ohci_detach(struct ssb_device *dev)
+{
+	struct usb_hcd *hcd = ssb_get_drvdata(dev);
+
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	usb_put_hcd(hcd);
+	ssb_device_disable(dev, 0);
+}
+
+static int ssb_ohci_attach(struct ssb_device *dev)
+{
+	struct ssb_ohci_device *ohcidev;
+	struct usb_hcd *hcd;
+	int err = -ENOMEM;
+	u32 tmp, flags = 0;
+
+	if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
+		flags |= SSB_OHCI_TMSLOW_HOSTMODE;
+
+	ssb_device_enable(dev, flags);
+
+	hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
+			dev->dev->bus_id);
+	if (!hcd)
+		goto err_dev_disable;
+	ohcidev = hcd_to_ssb_ohci(hcd);
+	ohcidev->enable_flags = flags;
+
+	tmp = ssb_read32(dev, SSB_ADMATCH0);
+	hcd->rsrc_start = ssb_admatch_base(tmp);
+	hcd->rsrc_len = ssb_admatch_size(tmp);
+	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs)
+		goto err_put_hcd;
+	err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
+	if (err)
+		goto err_iounmap;
+
+	ssb_set_drvdata(dev, hcd);
+
+	return err;
+
+err_iounmap:
+	iounmap(hcd->regs);
+err_put_hcd:
+	usb_put_hcd(hcd);
+err_dev_disable:
+	ssb_device_disable(dev, flags);
+	return err;
+}
+
+static int ssb_ohci_probe(struct ssb_device *dev,
+		const struct ssb_device_id *id)
+{
+	int err;
+	u16 chipid_top;
+
+	/* USBcores are only connected on embedded devices. */
+	chipid_top = (dev->bus->chip_id & 0xFF00);
+	if (chipid_top != 0x4700 && chipid_top != 0x5300)
+		return -ENODEV;
+
+	/* TODO: Probably need checks here; is the core connected? */
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	/* We currently always attach SSB_DEV_USB11_HOSTDEV
+	 * as HOST OHCI. If we want to attach it as Client device,
+	 * we must branch here and call into the (yet to
+	 * be written) Client mode driver. Same for remove(). */
+
+	err = ssb_ohci_attach(dev);
+
+	return err;
+}
+
+static void ssb_ohci_remove(struct ssb_device *dev)
+{
+	ssb_ohci_detach(dev);
+}
+
+#ifdef CONFIG_PM
+
+static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
+{
+	ssb_device_disable(dev, 0);
+
+	return 0;
+}
+
+static int ssb_ohci_resume(struct ssb_device *dev)
+{
+	struct usb_hcd *hcd = ssb_get_drvdata(dev);
+	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+
+	ssb_device_enable(dev, ohcidev->enable_flags);
+
+	return 0;
+}
+
+#else /* !CONFIG_PM */
+#define ssb_ohci_suspend	NULL
+#define ssb_ohci_resume	NULL
+#endif /* CONFIG_PM */
+
+static const struct ssb_device_id ssb_ohci_table[] = {
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
+	SSB_DEVTABLE_END
+};
+MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
+
+static struct ssb_driver ssb_ohci_driver = {
+	.name		= KBUILD_MODNAME,
+	.id_table	= ssb_ohci_table,
+	.probe		= ssb_ohci_probe,
+	.remove		= ssb_ohci_remove,
+	.suspend	= ssb_ohci_suspend,
+	.resume		= ssb_ohci_resume,
+};
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 4ada43c..47c5c66 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -398,11 +398,38 @@
 #define	OHCI_QUIRK_BE_MMIO	0x10			/* BE registers */
 #define	OHCI_QUIRK_ZFMICRO	0x20			/* Compaq ZFMicro chipset*/
 #define	OHCI_QUIRK_NEC		0x40			/* lost interrupts */
+#define	OHCI_QUIRK_FRAME_NO	0x80			/* no big endian frame_no shift */
 	// there are also chip quirks/bugs in init logic
 
 	struct work_struct	nec_work;	/* Worker for NEC quirk */
+
+	/* Needed for ZF Micro quirk */
+	struct timer_list	unlink_watchdog;
+	unsigned		eds_scheduled;
+	struct ed		*ed_to_check;
+	unsigned		zf_delay;
 };
 
+#ifdef CONFIG_PCI
+static inline int quirk_nec(struct ohci_hcd *ohci)
+{
+	return ohci->flags & OHCI_QUIRK_NEC;
+}
+static inline int quirk_zfmicro(struct ohci_hcd *ohci)
+{
+	return ohci->flags & OHCI_QUIRK_ZFMICRO;
+}
+#else
+static inline int quirk_nec(struct ohci_hcd *ohci)
+{
+	return 0;
+}
+static inline int quirk_zfmicro(struct ohci_hcd *ohci)
+{
+	return 0;
+}
+#endif
+
 /* convert between an hcd pointer and the corresponding ohci_hcd */
 static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd)
 {
@@ -607,15 +634,12 @@
 /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
  * hardware handles 16 bit reads.  That creates a different confusion on
  * some big-endian SOC implementations.  Same thing happens with PSW access.
- *
- * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
- * to arch/powerpc
  */
 
-#ifdef CONFIG_STB03xxx
-#define OHCI_BE_FRAME_NO_SHIFT	16
+#ifdef CONFIG_PPC_MPC52xx
+#define big_endian_frame_no_quirk(ohci)	(ohci->flags & OHCI_QUIRK_FRAME_NO)
 #else
-#define OHCI_BE_FRAME_NO_SHIFT	0
+#define big_endian_frame_no_quirk(ohci)	0
 #endif
 
 static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
@@ -623,7 +647,8 @@
 	u32 tmp;
 	if (big_endian_desc(ohci)) {
 		tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
-		tmp >>= OHCI_BE_FRAME_NO_SHIFT;
+		if (!big_endian_frame_no_quirk(ohci))
+			tmp >>= 16;
 	} else
 		tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no);
 
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index a7a7070..ae8ec44 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -35,10 +35,8 @@
 #include <linux/interrupt.h>
 #include <linux/usb.h>
 #include <linux/platform_device.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
+#include <linux/io.h>
+#include <linux/irq.h>
 
 #include "../core/hcd.h"
 #include "r8a66597.h"
@@ -54,16 +52,21 @@
 /* module parameters */
 static unsigned short clock = XTAL12;
 module_param(clock, ushort, 0644);
-MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0(default=0)");
+MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
+		"(default=0)");
+
 static unsigned short vif = LDRV;
 module_param(vif, ushort, 0644);
 MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)");
-static unsigned short endian = 0;
+
+static unsigned short endian;
 module_param(endian, ushort, 0644);
-MODULE_PARM_DESC(endian, "data endian: big=256, little=0(default=0)");
+MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
+
 static unsigned short irq_sense = INTL;
 module_param(irq_sense, ushort, 0644);
-MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0(default=32)");
+MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0 "
+		"(default=32)");
 
 static void packet_write(struct r8a66597 *r8a66597, u16 pipenum);
 static int r8a66597_get_frame(struct usb_hcd *hcd);
@@ -308,7 +311,7 @@
 	struct r8a66597_device *dev;
 	int usb_address = urb->setup_packet[2];	/* urb->pipe is address 0 */
 
-	dev = kzalloc(sizeof(struct r8a66597_device), GFP_KERNEL);
+	dev = kzalloc(sizeof(struct r8a66597_device), GFP_ATOMIC);
 	if (dev == NULL)
 		return -ENOMEM;
 
@@ -611,33 +614,33 @@
 	u16 array[R8A66597_MAX_NUM_PIPE], i = 0, min;
 
 	memset(array, 0, sizeof(array));
-        switch(ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
-        case USB_ENDPOINT_XFER_BULK:
+	switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_BULK:
 		if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
 			array[i++] = 4;
 		else {
 			array[i++] = 3;
 			array[i++] = 5;
 		}
-                break;
-        case USB_ENDPOINT_XFER_INT:
+		break;
+	case USB_ENDPOINT_XFER_INT:
 		if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
 			array[i++] = 6;
 			array[i++] = 7;
 			array[i++] = 8;
 		} else
 			array[i++] = 9;
-                break;
-        case USB_ENDPOINT_XFER_ISOC:
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
 		if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
 			array[i++] = 2;
 		else
 			array[i++] = 1;
-                break;
-        default:
-                err("Illegal type");
-                return 0;
-        }
+		break;
+	default:
+		err("Illegal type");
+		return 0;
+	}
 
 	i = 1;
 	min = array[0];
@@ -654,7 +657,7 @@
 {
 	u16 r8a66597_type;
 
-	switch(type) {
+	switch (type) {
 	case USB_ENDPOINT_XFER_BULK:
 		r8a66597_type = R8A66597_BULK;
 		break;
@@ -779,10 +782,12 @@
 		kfree(td);
 
 		if (urb) {
-			urb->status = -ENODEV;
-			urb->hcpriv = NULL;
+			usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597),
+					urb);
+
 			spin_unlock(&r8a66597->lock);
-			usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb);
+			usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb,
+					-ENODEV);
 			spin_lock(&r8a66597->lock);
 		}
 		break;
@@ -829,7 +834,7 @@
 	info.pipenum = get_empty_pipenum(r8a66597, ep);
 	info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
 	info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-	info.maxpacket = ep->wMaxPacketSize;
+	info.maxpacket = le16_to_cpu(ep->wMaxPacketSize);
 	info.type = get_r8a66597_type(ep->bmAttributes
 				      & USB_ENDPOINT_XFERTYPE_MASK);
 	info.bufnum = get_bufnum(info.pipenum);
@@ -874,7 +879,7 @@
 {
 	r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION)
 					 | (1 << USB_PORT_FEAT_C_CONNECTION);
-	r8a66597_write(r8a66597, (u16)~DTCH, get_intsts_reg(port));
+	r8a66597_write(r8a66597, ~DTCH, get_intsts_reg(port));
 	r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port));
 }
 
@@ -917,10 +922,10 @@
 
 	r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket,
 		       DCPMAXP);
-	r8a66597_write(r8a66597, (u16)~(SIGN | SACK), INTSTS1);
+	r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
 
 	for (i = 0; i < 4; i++) {
-		r8a66597_write(r8a66597, p[i], setup_addr);
+		r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr);
 		setup_addr += 2;
 	}
 	r8a66597_write(r8a66597, SUREQ, DCPCTR);
@@ -948,19 +953,18 @@
 			pipe_irq_disable(r8a66597, td->pipenum);
 			pipe_setting(r8a66597, td);
 			pipe_stop(r8a66597, td->pipe);
-			r8a66597_write(r8a66597, (u16)~(1 << td->pipenum),
-				       BRDYSTS);
+			r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);
 
 			if (td->pipe->pipetre) {
 				r8a66597_write(r8a66597, TRCLR,
-					        td->pipe->pipetre);
+						td->pipe->pipetre);
 				r8a66597_write(r8a66597,
-					       (urb->transfer_buffer_length
-					       + td->maxpacket - 1)
-					       / td->maxpacket,
-					       td->pipe->pipetrn);
+						(urb->transfer_buffer_length
+						+ td->maxpacket - 1)
+						/ td->maxpacket,
+						td->pipe->pipetrn);
 				r8a66597_bset(r8a66597, TRENB,
-					      td->pipe->pipetre);
+						td->pipe->pipetre);
 			}
 
 			pipe_start(r8a66597, td->pipe);
@@ -991,7 +995,7 @@
 		if (td->pipe->pipetre)
 			r8a66597_bclr(r8a66597, TRENB, td->pipe->pipetre);
 	}
-	r8a66597_write(r8a66597, (u16)~(1 << td->pipenum), BRDYSTS);
+	r8a66597_write(r8a66597, ~(1 << td->pipenum), BRDYSTS);
 
 	fifo_change_from_pipe(r8a66597, td->pipe);
 	tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
@@ -1009,27 +1013,36 @@
 	struct urb *urb = td->urb;
 
 	r8a66597_pipe_toggle(r8a66597, td->pipe, 1);
+	pipe_stop(r8a66597, td->pipe);
 
 	if (urb->setup_packet[0] & USB_ENDPOINT_DIR_MASK) {
 		r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
 		r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
 		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
-		r8a66597_write(r8a66597, BVAL | BCLR, CFIFOCTR);
-		r8a66597_write(r8a66597, (u16)~BEMP0, BEMPSTS);
+		r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
+		r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+		r8a66597_write(r8a66597, BVAL, CFIFOCTR);
 		enable_irq_empty(r8a66597, 0);
 	} else {
 		r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
 		r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
 		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
 		r8a66597_write(r8a66597, BCLR, CFIFOCTR);
-		r8a66597_write(r8a66597, (u16)~BRDY0, BRDYSTS);
-		r8a66597_write(r8a66597, (u16)~BEMP0, BEMPSTS);
 		enable_irq_ready(r8a66597, 0);
 	}
 	enable_irq_nrdy(r8a66597, 0);
 	pipe_start(r8a66597, td->pipe);
 }
 
+static int is_set_address(unsigned char *setup_packet)
+{
+	if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) &&
+			setup_packet[1] == USB_REQ_SET_ADDRESS)
+		return 1;
+	else
+		return 0;
+}
+
 /* this function must be called with interrupt disabled */
 static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
 {
@@ -1037,7 +1050,7 @@
 
 	switch (td->type) {
 	case USB_PID_SETUP:
-		if (td->urb->setup_packet[1] == USB_REQ_SET_ADDRESS) {
+		if (is_set_address(td->urb->setup_packet)) {
 			td->set_address = 1;
 			td->urb->setup_packet[2] = alloc_usb_address(r8a66597,
 								     td->urb);
@@ -1104,8 +1117,9 @@
 }
 
 /* this function must be called with interrupt disabled */
-static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
-		 u16 pipenum, struct urb *urb)
+static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
+		u16 pipenum, struct urb *urb, int status)
+__releases(r8a66597->lock) __acquires(r8a66597->lock)
 {
 	int restart = 0;
 	struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
@@ -1113,7 +1127,7 @@
 	r8a66597->timeout_map &= ~(1 << pipenum);
 
 	if (likely(td)) {
-		if (td->set_address && urb->status != 0)
+		if (td->set_address && (status != 0 || urb->unlinked))
 			r8a66597->address_map &= ~(1 << urb->setup_packet[2]);
 
 		pipe_toggle_save(r8a66597, td->pipe, urb);
@@ -1128,9 +1142,9 @@
 		if (usb_pipeisoc(urb->pipe))
 			urb->start_frame = r8a66597_get_frame(hcd);
 
-		urb->hcpriv = NULL;
+		usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb);
 		spin_unlock(&r8a66597->lock);
-		usb_hcd_giveback_urb(hcd, urb);
+		usb_hcd_giveback_urb(hcd, urb, status);
 		spin_lock(&r8a66597->lock);
 	}
 
@@ -1144,14 +1158,6 @@
 	}
 }
 
-/* this function must be called with interrupt disabled */
-static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
-			   u16 pipenum, struct urb *urb)
-__releases(r8a66597->lock) __acquires(r8a66597->lock)
-{
-	done(r8a66597, td, pipenum, urb);
-}
-
 static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
 {
 	u16 tmp;
@@ -1160,6 +1166,7 @@
 	struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
 	struct urb *urb;
 	int finish = 0;
+	int status = 0;
 
 	if (unlikely(!td))
 		return;
@@ -1168,17 +1175,15 @@
 	fifo_change_from_pipe(r8a66597, td->pipe);
 	tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
 	if (unlikely((tmp & FRDY) == 0)) {
-		urb->status = -EPIPE;
 		pipe_stop(r8a66597, td->pipe);
 		pipe_irq_disable(r8a66597, pipenum);
 		err("in fifo not ready (%d)", pipenum);
-		finish_request(r8a66597, td, pipenum, td->urb);
+		finish_request(r8a66597, td, pipenum, td->urb, -EPIPE);
 		return;
 	}
 
 	/* prepare parameters */
 	rcv_len = tmp & DTLN;
-	bufsize = td->maxpacket;
 	if (usb_pipeisoc(urb->pipe)) {
 		buf = (u16 *)(urb->transfer_buffer +
 				urb->iso_frame_desc[td->iso_cnt].offset);
@@ -1187,29 +1192,31 @@
 		buf = (void *)urb->transfer_buffer + urb->actual_length;
 		urb_len = urb->transfer_buffer_length - urb->actual_length;
 	}
-	if (rcv_len < bufsize)
-		size = min(rcv_len, urb_len);
-	else
-		size = min(bufsize, urb_len);
+	bufsize = min(urb_len, (int) td->maxpacket);
+	if (rcv_len <= bufsize) {
+		size = rcv_len;
+	} else {
+		size = bufsize;
+		status = -EOVERFLOW;
+		finish = 1;
+	}
 
 	/* update parameters */
 	urb->actual_length += size;
 	if (rcv_len == 0)
 		td->zero_packet = 1;
-	if ((size % td->maxpacket) > 0) {
+	if (rcv_len < bufsize) {
 		td->short_packet = 1;
-		if (urb->transfer_buffer_length != urb->actual_length &&
-		    urb->transfer_flags & URB_SHORT_NOT_OK)
-			td->urb->status = -EREMOTEIO;
 	}
 	if (usb_pipeisoc(urb->pipe)) {
 		urb->iso_frame_desc[td->iso_cnt].actual_length = size;
-		urb->iso_frame_desc[td->iso_cnt].status = 0;
+		urb->iso_frame_desc[td->iso_cnt].status = status;
 		td->iso_cnt++;
+		finish = 0;
 	}
 
 	/* check transfer finish */
-	if (check_transfer_finish(td, urb)) {
+	if (finish || check_transfer_finish(td, urb)) {
 		pipe_stop(r8a66597, td->pipe);
 		pipe_irq_disable(r8a66597, pipenum);
 		finish = 1;
@@ -1224,11 +1231,8 @@
 					   buf, size);
 	}
 
-	if (finish && pipenum != 0) {
-		if (td->urb->status == -EINPROGRESS)
-			td->urb->status = 0;
-		finish_request(r8a66597, td, pipenum, urb);
-	}
+	if (finish && pipenum != 0)
+		finish_request(r8a66597, td, pipenum, urb, status);
 }
 
 static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
@@ -1246,11 +1250,10 @@
 	fifo_change_from_pipe(r8a66597, td->pipe);
 	tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
 	if (unlikely((tmp & FRDY) == 0)) {
-		urb->status = -EPIPE;
 		pipe_stop(r8a66597, td->pipe);
 		pipe_irq_disable(r8a66597, pipenum);
 		err("out write fifo not ready. (%d)", pipenum);
-		finish_request(r8a66597, td, pipenum, td->urb);
+		finish_request(r8a66597, td, pipenum, urb, -EPIPE);
 		return;
 	}
 
@@ -1269,7 +1272,7 @@
 
 	/* write fifo */
 	if (pipenum > 0)
-		r8a66597_write(r8a66597, (u16)~(1 << pipenum), BEMPSTS);
+		r8a66597_write(r8a66597, ~(1 << pipenum), BEMPSTS);
 	if (urb->transfer_buffer) {
 		r8a66597_write_fifo(r8a66597, td->pipe->fifoaddr, buf, size);
 		if (!usb_pipebulk(urb->pipe) || td->maxpacket != size)
@@ -1295,7 +1298,7 @@
 }
 
 
-static void check_next_phase(struct r8a66597 *r8a66597)
+static void check_next_phase(struct r8a66597 *r8a66597, int status)
 {
 	struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0);
 	struct urb *urb;
@@ -1308,49 +1311,41 @@
 	switch (td->type) {
 	case USB_PID_IN:
 	case USB_PID_OUT:
-		if (urb->status != -EINPROGRESS) {
-			finish = 1;
-			break;
-		}
 		if (check_transfer_finish(td, urb))
 			td->type = USB_PID_ACK;
 		break;
 	case USB_PID_SETUP:
-		if (urb->status != -EINPROGRESS)
-			finish = 1;
-		else if (urb->transfer_buffer_length == urb->actual_length) {
+		if (urb->transfer_buffer_length == urb->actual_length)
 			td->type = USB_PID_ACK;
-			urb->status = 0;
-		} else if (usb_pipeout(urb->pipe))
+		else if (usb_pipeout(urb->pipe))
 			td->type = USB_PID_OUT;
 		else
 			td->type = USB_PID_IN;
 		break;
 	case USB_PID_ACK:
 		finish = 1;
-		if (urb->status == -EINPROGRESS)
-			urb->status = 0;
 		break;
 	}
 
-	if (finish)
-		finish_request(r8a66597, td, 0, urb);
+	if (finish || status != 0 || urb->unlinked)
+		finish_request(r8a66597, td, 0, urb, status);
 	else
 		start_transfer(r8a66597, td);
 }
 
-static void set_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
+static int get_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
 {
 	struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
 
-	if (td && td->urb) {
+	if (td) {
 		u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID;
 
 		if (pid == PID_NAK)
-			td->urb->status = -ECONNRESET;
+			return -ECONNRESET;
 		else
-			td->urb->status = -EPIPE;
+			return -EPIPE;
 	}
+	return 0;
 }
 
 static void irq_pipe_ready(struct r8a66597 *r8a66597)
@@ -1362,14 +1357,14 @@
 
 	mask = r8a66597_read(r8a66597, BRDYSTS)
 	       & r8a66597_read(r8a66597, BRDYENB);
-	r8a66597_write(r8a66597, (u16)~mask, BRDYSTS);
+	r8a66597_write(r8a66597, ~mask, BRDYSTS);
 	if (mask & BRDY0) {
 		td = r8a66597_get_td(r8a66597, 0);
 		if (td && td->type == USB_PID_IN)
 			packet_read(r8a66597, 0);
 		else
 			pipe_irq_disable(r8a66597, 0);
-		check_next_phase(r8a66597);
+		check_next_phase(r8a66597, 0);
 	}
 
 	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1397,13 +1392,13 @@
 
 	mask = r8a66597_read(r8a66597, BEMPSTS)
 	       & r8a66597_read(r8a66597, BEMPENB);
-	r8a66597_write(r8a66597, (u16)~mask, BEMPSTS);
+	r8a66597_write(r8a66597, ~mask, BEMPSTS);
 	if (mask & BEMP0) {
 		cfifo_change(r8a66597, 0);
 		td = r8a66597_get_td(r8a66597, 0);
 		if (td && td->type != USB_PID_OUT)
 			disable_irq_empty(r8a66597, 0);
-		check_next_phase(r8a66597);
+		check_next_phase(r8a66597, 0);
 	}
 
 	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1418,9 +1413,8 @@
 			if ((tmp & INBUFM) == 0) {
 				disable_irq_empty(r8a66597, pipenum);
 				pipe_irq_disable(r8a66597, pipenum);
-				if (td->urb->status == -EINPROGRESS)
-					td->urb->status = 0;
-				finish_request(r8a66597, td, pipenum, td->urb);
+				finish_request(r8a66597, td, pipenum, td->urb,
+						0);
 			}
 		}
 	}
@@ -1431,15 +1425,16 @@
 	u16 check;
 	u16 pipenum;
 	u16 mask;
+	int status;
 
 	mask = r8a66597_read(r8a66597, NRDYSTS)
 	       & r8a66597_read(r8a66597, NRDYENB);
-	r8a66597_write(r8a66597, (u16)~mask, NRDYSTS);
+	r8a66597_write(r8a66597, ~mask, NRDYSTS);
 	if (mask & NRDY0) {
 		cfifo_change(r8a66597, 0);
-		set_urb_error(r8a66597, 0);
+		status = get_urb_error(r8a66597, 0);
 		pipe_irq_disable(r8a66597, 0);
-		check_next_phase(r8a66597);
+		check_next_phase(r8a66597, status);
 	}
 
 	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1450,10 +1445,10 @@
 			if (unlikely(!td))
 				continue;
 
-			set_urb_error(r8a66597, pipenum);
+			status = get_urb_error(r8a66597, pipenum);
 			pipe_irq_disable(r8a66597, pipenum);
 			pipe_stop(r8a66597, td->pipe);
-			finish_request(r8a66597, td, pipenum, td->urb);
+			finish_request(r8a66597, td, pipenum, td->urb, status);
 		}
 	}
 }
@@ -1473,6 +1468,7 @@
 	u16 intsts0, intsts1, intsts2;
 	u16 intenb0, intenb1, intenb2;
 	u16 mask0, mask1, mask2;
+	int status;
 
 	spin_lock(&r8a66597->lock);
 
@@ -1488,14 +1484,14 @@
 	mask0 = intsts0 & intenb0 & (BEMP | NRDY | BRDY);
 	if (mask2) {
 		if (mask2 & ATTCH) {
-			r8a66597_write(r8a66597, (u16)~ATTCH, INTSTS2);
+			r8a66597_write(r8a66597, ~ATTCH, INTSTS2);
 			r8a66597_bclr(r8a66597, ATTCHE, INTENB2);
 
 			/* start usb bus sampling */
 			start_root_hub_sampling(r8a66597, 1);
 		}
 		if (mask2 & DTCH) {
-			r8a66597_write(r8a66597, (u16)~DTCH, INTSTS2);
+			r8a66597_write(r8a66597, ~DTCH, INTSTS2);
 			r8a66597_bclr(r8a66597, DTCHE, INTENB2);
 			r8a66597_usb_disconnect(r8a66597, 1);
 		}
@@ -1503,25 +1499,25 @@
 
 	if (mask1) {
 		if (mask1 & ATTCH) {
-			r8a66597_write(r8a66597, (u16)~ATTCH, INTSTS1);
+			r8a66597_write(r8a66597, ~ATTCH, INTSTS1);
 			r8a66597_bclr(r8a66597, ATTCHE, INTENB1);
 
 			/* start usb bus sampling */
 			start_root_hub_sampling(r8a66597, 0);
 		}
 		if (mask1 & DTCH) {
-			r8a66597_write(r8a66597, (u16)~DTCH, INTSTS1);
+			r8a66597_write(r8a66597, ~DTCH, INTSTS1);
 			r8a66597_bclr(r8a66597, DTCHE, INTENB1);
 			r8a66597_usb_disconnect(r8a66597, 0);
 		}
 		if (mask1 & SIGN) {
-			r8a66597_write(r8a66597, (u16)~SIGN, INTSTS1);
-			set_urb_error(r8a66597, 0);
-			check_next_phase(r8a66597);
+			r8a66597_write(r8a66597, ~SIGN, INTSTS1);
+			status = get_urb_error(r8a66597, 0);
+			check_next_phase(r8a66597, status);
 		}
 		if (mask1 & SACK) {
-			r8a66597_write(r8a66597, (u16)~SACK, INTSTS1);
-			check_next_phase(r8a66597);
+			r8a66597_write(r8a66597, ~SACK, INTSTS1);
+			check_next_phase(r8a66597, 0);
 		}
 	}
 	if (mask0) {
@@ -1663,13 +1659,9 @@
 static int r8a66597_start(struct usb_hcd *hcd)
 {
 	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
-	int ret;
 
 	hcd->state = HC_STATE_RUNNING;
-	if ((ret = enable_controller(r8a66597)) < 0)
-		return ret;
-
-	return 0;
+	return enable_controller(r8a66597);
 }
 
 static void r8a66597_stop(struct usb_hcd *hcd)
@@ -1696,13 +1688,12 @@
 
 static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597,
 					    struct urb *urb,
-					    struct usb_host_endpoint *hep,
-					    gfp_t mem_flags)
+					    struct usb_host_endpoint *hep)
 {
 	struct r8a66597_td *td;
 	u16 pipenum;
 
-	td = kzalloc(sizeof(struct r8a66597_td), mem_flags);
+	td = kzalloc(sizeof(struct r8a66597_td), GFP_ATOMIC);
 	if (td == NULL)
 		return NULL;
 
@@ -1725,23 +1716,28 @@
 }
 
 static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
-				struct usb_host_endpoint *hep,
 				struct urb *urb,
 				gfp_t mem_flags)
 {
+	struct usb_host_endpoint *hep = urb->ep;
 	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
 	struct r8a66597_td *td = NULL;
-	int ret = 0, request = 0;
+	int ret, request = 0;
 	unsigned long flags;
 
 	spin_lock_irqsave(&r8a66597->lock, flags);
 	if (!get_urb_to_r8a66597_dev(r8a66597, urb)) {
 		ret = -ENODEV;
-		goto error;
+		goto error_not_linked;
 	}
 
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (ret)
+		goto error_not_linked;
+
 	if (!hep->hcpriv) {
-		hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe), mem_flags);
+		hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
+				GFP_ATOMIC);
 		if (!hep->hcpriv) {
 			ret = -ENOMEM;
 			goto error;
@@ -1755,7 +1751,7 @@
 		init_pipe_config(r8a66597, urb);
 
 	set_address_zero(r8a66597, urb);
-	td = r8a66597_make_td(r8a66597, urb, hep, mem_flags);
+	td = r8a66597_make_td(r8a66597, urb, hep);
 	if (td == NULL) {
 		ret = -ENOMEM;
 		goto error;
@@ -1763,15 +1759,7 @@
 	if (list_empty(&r8a66597->pipe_queue[td->pipenum]))
 		request = 1;
 	list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]);
-
-	spin_lock(&urb->lock);
-	if (urb->status != -EINPROGRESS) {
-		spin_unlock(&urb->lock);
-		ret = -EPIPE;
-		goto error;
-	}
 	urb->hcpriv = td;
-	spin_unlock(&urb->lock);
 
 	if (request) {
 		ret = start_transfer(r8a66597, td);
@@ -1783,26 +1771,36 @@
 		set_td_timer(r8a66597, td);
 
 error:
+	if (ret)
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+error_not_linked:
 	spin_unlock_irqrestore(&r8a66597->lock, flags);
 	return ret;
 }
 
-static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+		int status)
 {
 	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
 	struct r8a66597_td *td;
 	unsigned long flags;
+	int rc;
 
 	spin_lock_irqsave(&r8a66597->lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
+
 	if (urb->hcpriv) {
 		td = urb->hcpriv;
 		pipe_stop(r8a66597, td->pipe);
 		pipe_irq_disable(r8a66597, td->pipenum);
 		disable_irq_empty(r8a66597, td->pipenum);
-		done(r8a66597, td, td->pipenum, urb);
+		finish_request(r8a66597, td, td->pipenum, urb, status);
 	}
+ done:
 	spin_unlock_irqrestore(&r8a66597->lock, flags);
-	return 0;
+	return rc;
 }
 
 static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
@@ -1832,7 +1830,7 @@
 	td = r8a66597_get_td(r8a66597, pipenum);
 	if (td)
 		urb = td->urb;
-	done(r8a66597, td, pipenum, urb);
+	finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN);
 	kfree(hep->hcpriv);
 	hep->hcpriv = NULL;
 	spin_unlock_irqrestore(&r8a66597->lock, flags);
@@ -2029,7 +2027,7 @@
 	case GetPortStatus:
 		if (wIndex > R8A66597_MAX_ROOT_HUB)
 			goto error;
-		*(u32 *)buf = rh->port;
+		*(u32 *)buf = cpu_to_le32(rh->port);
 		break;
 	case SetPortFeature:
 		if (wIndex > R8A66597_MAX_ROOT_HUB)
@@ -2128,8 +2126,8 @@
 	struct usb_hcd		*hcd = r8a66597_to_hcd(r8a66597);
 
 	del_timer_sync(&r8a66597->rh_timer);
-	iounmap((void *)r8a66597->reg);
 	usb_remove_hcd(hcd);
+	iounmap((void *)r8a66597->reg);
 	usb_put_hcd(hcd);
 	return 0;
 }
@@ -2210,8 +2208,6 @@
 clean_up:
 	if (reg)
 		iounmap(reg);
-	if (res)
-		release_mem_region(res->start, 1);
 
 	return ret;
 }
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
index 97c2a71..fe9ceb0 100644
--- a/drivers/usb/host/r8a66597.h
+++ b/drivers/usb/host/r8a66597.h
@@ -203,14 +203,14 @@
 #define	DTLN		0x0FFF	/* b11-0: FIFO received data length */
 
 /* Interrupt Enable Register 0 */
-#define	VBSE		0x8000	/* b15: VBUS interrupt */
-#define	RSME		0x4000	/* b14: Resume interrupt */
-#define	SOFE		0x2000	/* b13: Frame update interrupt */
-#define	DVSE		0x1000	/* b12: Device state transition interrupt */
-#define	CTRE		0x0800	/* b11: Control transfer stage transition interrupt */
-#define	BEMPE		0x0400	/* b10: Buffer empty interrupt */
-#define	NRDYE		0x0200	/* b9: Buffer not ready interrupt */
-#define	BRDYE		0x0100	/* b8: Buffer ready interrupt */
+#define	VBSE	0x8000	/* b15: VBUS interrupt */
+#define	RSME	0x4000	/* b14: Resume interrupt */
+#define	SOFE	0x2000	/* b13: Frame update interrupt */
+#define	DVSE	0x1000	/* b12: Device state transition interrupt */
+#define	CTRE	0x0800	/* b11: Control transfer stage transition interrupt */
+#define	BEMPE	0x0400	/* b10: Buffer empty interrupt */
+#define	NRDYE	0x0200	/* b9: Buffer not ready interrupt */
+#define	BRDYE	0x0100	/* b8: Buffer ready interrupt */
 
 /* Interrupt Enable Register 1 */
 #define	OVRCRE		0x8000	/* b15: Over-current interrupt */
@@ -268,16 +268,16 @@
 #define	  SOF_DISABLE	 0x0000	  /* SOF OUT Disable */
 
 /* Interrupt Status Register 0 */
-#define	VBINT		0x8000	/* b15: VBUS interrupt */
-#define	RESM		0x4000	/* b14: Resume interrupt */
-#define	SOFR		0x2000	/* b13: SOF frame update interrupt */
-#define	DVST		0x1000	/* b12: Device state transition interrupt */
-#define	CTRT		0x0800	/* b11: Control transfer stage transition interrupt */
-#define	BEMP		0x0400	/* b10: Buffer empty interrupt */
-#define	NRDY		0x0200	/* b9: Buffer not ready interrupt */
-#define	BRDY		0x0100	/* b8: Buffer ready interrupt */
-#define	VBSTS		0x0080	/* b7: VBUS input port */
-#define	DVSQ		0x0070	/* b6-4: Device state */
+#define	VBINT	0x8000	/* b15: VBUS interrupt */
+#define	RESM	0x4000	/* b14: Resume interrupt */
+#define	SOFR	0x2000	/* b13: SOF frame update interrupt */
+#define	DVST	0x1000	/* b12: Device state transition interrupt */
+#define	CTRT	0x0800	/* b11: Control transfer stage transition interrupt */
+#define	BEMP	0x0400	/* b10: Buffer empty interrupt */
+#define	NRDY	0x0200	/* b9: Buffer not ready interrupt */
+#define	BRDY	0x0100	/* b8: Buffer ready interrupt */
+#define	VBSTS	0x0080	/* b7: VBUS input port */
+#define	DVSQ	0x0070	/* b6-4: Device state */
 #define	  DS_SPD_CNFG	 0x0070	  /* Suspend Configured */
 #define	  DS_SPD_ADDR	 0x0060	  /* Suspend Address */
 #define	  DS_SPD_DFLT	 0x0050	  /* Suspend Default */
@@ -315,13 +315,10 @@
 /* Micro Frame Number Register */
 #define	UFRNM		0x0007	/* b2-0: Micro frame number */
 
-/* USB Address / Low Power Status Recovery Register */
-//#define	USBADDR		0x007F	/* b6-0: USB address */
-
 /* Default Control Pipe Maxpacket Size Register */
 /* Pipe Maxpacket Size Register */
-#define	DEVSEL		0xF000	/* b15-14: Device address select */
-#define	MAXP		0x007F	/* b6-0: Maxpacket size of default control pipe */
+#define	DEVSEL	0xF000	/* b15-14: Device address select */
+#define	MAXP	0x007F	/* b6-0: Maxpacket size of default control pipe */
 
 /* Default Control Pipe Control Register */
 #define	BSTS		0x8000	/* b15: Buffer status */
@@ -366,21 +363,21 @@
 #define	MXPS		0x07FF	/* b10-0: Maxpacket size */
 
 /* Pipe Cycle Configuration Register */
-#define	IFIS		0x1000	/* b12: Isochronous in-buffer flush mode select */
-#define	IITV		0x0007	/* b2-0: Isochronous interval */
+#define	IFIS	0x1000	/* b12: Isochronous in-buffer flush mode select */
+#define	IITV	0x0007	/* b2-0: Isochronous interval */
 
 /* Pipex Control Register */
-#define	BSTS		0x8000	/* b15: Buffer status */
-#define	INBUFM		0x4000	/* b14: IN buffer monitor (Only for PIPE1 to 5) */
-#define	CSCLR		0x2000	/* b13: complete-split status clear */
-#define	CSSTS		0x1000	/* b12: complete-split status */
-#define	ATREPM		0x0400	/* b10: Auto repeat mode */
-#define	ACLRM		0x0200	/* b9: Out buffer auto clear mode */
-#define	SQCLR		0x0100	/* b8: Sequence toggle bit clear */
-#define	SQSET		0x0080	/* b7: Sequence toggle bit set */
-#define	SQMON		0x0040	/* b6: Sequence toggle bit monitor */
-#define	PBUSY		0x0020	/* b5: pipe busy */
-#define	PID		0x0003	/* b1-0: Response PID */
+#define	BSTS	0x8000	/* b15: Buffer status */
+#define	INBUFM	0x4000	/* b14: IN buffer monitor (Only for PIPE1 to 5) */
+#define	CSCLR	0x2000	/* b13: complete-split status clear */
+#define	CSSTS	0x1000	/* b12: complete-split status */
+#define	ATREPM	0x0400	/* b10: Auto repeat mode */
+#define	ACLRM	0x0200	/* b9: Out buffer auto clear mode */
+#define	SQCLR	0x0100	/* b8: Sequence toggle bit clear */
+#define	SQSET	0x0080	/* b7: Sequence toggle bit set */
+#define	SQMON	0x0040	/* b6: Sequence toggle bit monitor */
+#define	PBUSY	0x0020	/* b5: pipe busy */
+#define	PID	0x0003	/* b1-0: Response PID */
 
 /* PIPExTRE */
 #define	TRENB		0x0200	/* b9: Transaction counter enable */
@@ -407,15 +404,15 @@
 #define make_devsel(addr)		(addr << 12)
 
 struct r8a66597_pipe_info {
-        u16 pipenum;
-        u16 address;	/* R8A66597 HCD usb addres */
-        u16 epnum;
-        u16 maxpacket;
-        u16 type;
-        u16 bufnum;
-        u16 buf_bsize;
-        u16 interval;
-        u16 dir_in;
+	u16 pipenum;
+	u16 address;	/* R8A66597 HCD usb addres */
+	u16 epnum;
+	u16 maxpacket;
+	u16 type;
+	u16 bufnum;
+	u16 buf_bsize;
+	u16 interval;
+	u16 dir_in;
 };
 
 struct r8a66597_pipe {
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 4cfa3ff..94d859a 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -435,14 +435,9 @@
 	if (usb_pipecontrol(urb->pipe))
 		ep->nextpid = USB_PID_SETUP;
 
-	spin_lock(&urb->lock);
-	if (urb->status == -EINPROGRESS)
-		urb->status = status;
-	urb->hcpriv = NULL;
-	spin_unlock(&urb->lock);
-
+	usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb);
 	spin_unlock(&sl811->lock);
-	usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb);
+	usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, status);
 	spin_lock(&sl811->lock);
 
 	/* leave active endpoints in the schedule */
@@ -538,35 +533,21 @@
 						bank + SL11H_XFERCNTREG);
 			if (len > ep->length) {
 				len = ep->length;
-				urb->status = -EOVERFLOW;
+				urbstat = -EOVERFLOW;
 			}
 			urb->actual_length += len;
 			sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0),
 					buf, len);
 			usb_dotoggle(udev, ep->epnum, 0);
-			if (urb->actual_length == urb->transfer_buffer_length)
-				urbstat = 0;
-			else if (len < ep->maxpacket) {
-				if (urb->transfer_flags & URB_SHORT_NOT_OK)
-					urbstat = -EREMOTEIO;
+			if (urbstat == -EINPROGRESS &&
+					(len < ep->maxpacket ||
+						urb->actual_length ==
+						urb->transfer_buffer_length)) {
+				if (usb_pipecontrol(urb->pipe))
+					ep->nextpid = USB_PID_ACK;
 				else
 					urbstat = 0;
 			}
-			if (usb_pipecontrol(urb->pipe)
-					&& (urbstat == -EREMOTEIO
-						|| urbstat == 0)) {
-
-				/* NOTE if the status stage STALLs (why?),
-				 * this reports the wrong urb status.
-				 */
-				spin_lock(&urb->lock);
-				if (urb->status == -EINPROGRESS)
-					urb->status = urbstat;
-				spin_unlock(&urb->lock);
-
-				urb = NULL;
-				ep->nextpid = USB_PID_ACK;
-			}
 			break;
 		case USB_PID_SETUP:
 			// PACKET("...ACK/setup_%02x qh%p\n", bank, ep);
@@ -605,7 +586,7 @@
 				bank, status, ep, urbstat);
 	}
 
-	if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS))
+	if (urbstat != -EINPROGRESS || urb->unlinked)
 		finish_request(sl811, ep, urb, urbstat);
 }
 
@@ -807,7 +788,6 @@
 
 static int sl811h_urb_enqueue(
 	struct usb_hcd		*hcd,
-	struct usb_host_endpoint *hep,
 	struct urb		*urb,
 	gfp_t			mem_flags
 ) {
@@ -820,7 +800,8 @@
 	struct sl811h_ep	*ep = NULL;
 	unsigned long		flags;
 	int			i;
-	int			retval = 0;
+	int			retval;
+	struct usb_host_endpoint	*hep = urb->ep;
 
 #ifdef	DISABLE_ISO
 	if (type == PIPE_ISOCHRONOUS)
@@ -838,7 +819,12 @@
 			|| !HC_IS_RUNNING(hcd->state)) {
 		retval = -ENODEV;
 		kfree(ep);
-		goto fail;
+		goto fail_not_linked;
+	}
+	retval = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (retval) {
+		kfree(ep);
+		goto fail_not_linked;
 	}
 
 	if (hep->hcpriv) {
@@ -951,37 +937,31 @@
 		sofirq_on(sl811);
 	}
 
-	/* in case of unlink-during-submit */
-	spin_lock(&urb->lock);
-	if (urb->status != -EINPROGRESS) {
-		spin_unlock(&urb->lock);
-		finish_request(sl811, ep, urb, 0);
-		retval = 0;
-		goto fail;
-	}
 	urb->hcpriv = hep;
-	spin_unlock(&urb->lock);
-
 	start_transfer(sl811);
 	sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
 fail:
+	if (retval)
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+fail_not_linked:
 	spin_unlock_irqrestore(&sl811->lock, flags);
 	return retval;
 }
 
-static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	struct sl811		*sl811 = hcd_to_sl811(hcd);
 	struct usb_host_endpoint *hep;
 	unsigned long		flags;
 	struct sl811h_ep	*ep;
-	int			retval = 0;
+	int			retval;
 
 	spin_lock_irqsave(&sl811->lock, flags);
-	hep = urb->hcpriv;
-	if (!hep)
+	retval = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (retval)
 		goto fail;
 
+	hep = urb->hcpriv;
 	ep = hep->hcpriv;
 	if (ep) {
 		/* finish right away if this urb can't be active ...
@@ -1029,8 +1009,8 @@
 			VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
 				(sl811->active_a == ep) ? "A" : "B");
 	} else
-fail:
 		retval = -EINVAL;
+ fail:
 	spin_unlock_irqrestore(&sl811->lock, flags);
 	return retval;
 }
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c
index 2d0e73b..5da63f5 100644
--- a/drivers/usb/host/sl811_cs.c
+++ b/drivers/usb/host/sl811_cs.c
@@ -278,10 +278,9 @@
 {
 	local_info_t *local;
 
-	local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+	local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
 	if (!local)
 		return -ENOMEM;
-	memset(local, 0, sizeof(local_info_t));
 	local->p_dev = link;
 	link->priv = local;
 
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index e98df2e..ac283b0 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -51,7 +51,7 @@
 #include <linux/usb.h>
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
-#include <linux/pci_ids.h>
+#include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/system.h>
@@ -83,7 +83,7 @@
 * u132_module_lock exists to protect access to global variables
 *
 */
-static struct semaphore u132_module_lock;
+static struct mutex u132_module_lock;
 static int u132_exiting = 0;
 static int u132_instances = 0;
 static struct list_head u132_static_list;
@@ -183,7 +183,7 @@
 struct u132 {
         struct kref kref;
         struct list_head u132_list;
-        struct semaphore sw_lock;
+        struct mutex sw_lock;
         struct semaphore scheduler_lock;
         struct u132_platform_data *board;
         struct platform_device *platform_dev;
@@ -258,10 +258,10 @@
         struct platform_device *pdev = u132->platform_dev;
         struct usb_hcd *hcd = u132_to_hcd(u132);
         u132->going += 1;
-        down(&u132_module_lock);
+        mutex_lock(&u132_module_lock);
         list_del_init(&u132->u132_list);
         u132_instances -= 1;
-        up(&u132_module_lock);
+        mutex_unlock(&u132_module_lock);
         dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13"
                 "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev);
         usb_put_hcd(hcd);
@@ -492,20 +492,20 @@
                 return;
         } else {
                 int retval;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 retval = read_roothub_info(u132);
                 if (retval) {
                         struct usb_hcd *hcd = u132_to_hcd(u132);
                         u132_disable(u132);
                         u132->going = 1;
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         usb_hc_died(hcd);
                         ftdi_elan_gone_away(u132->platform_dev);
                         u132_monitor_put_kref(u132);
                         return;
                 } else {
                         u132_monitor_requeue_work(u132, 500);
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         return;
                 }
         }
@@ -518,9 +518,8 @@
         unsigned long irqs;
         struct usb_hcd *hcd = u132_to_hcd(u132);
         urb->error_count = 0;
-        urb->status = status;
-        urb->hcpriv = NULL;
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
         endp->queue_next += 1;
         if (ENDP_QUEUE_SIZE > --endp->queue_size) {
                 endp->active = 0;
@@ -542,7 +541,7 @@
         u132_ring_queue_work(u132, ring, 0);
         up(&u132->scheduler_lock);
         u132_endp_put_kref(u132, endp);
-        usb_hcd_giveback_urb(hcd, urb);
+	usb_hcd_giveback_urb(hcd, urb, status);
         return;
 }
 
@@ -558,9 +557,8 @@
         unsigned long irqs;
         struct usb_hcd *hcd = u132_to_hcd(u132);
         urb->error_count = 0;
-        urb->status = status;
-        urb->hcpriv = NULL;
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
         endp->queue_next += 1;
         if (ENDP_QUEUE_SIZE > --endp->queue_size) {
                 endp->active = 0;
@@ -575,7 +573,7 @@
                 endp->active = 0;
                 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                 kfree(urbq);
-        } usb_hcd_giveback_urb(hcd, urb);
+	} usb_hcd_giveback_urb(hcd, urb, status);
         return;
 }
 
@@ -645,12 +643,12 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer + urb->actual_length;
                 u8 *b = buf;
@@ -716,10 +714,10 @@
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -744,12 +742,12 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 urb->actual_length += len;
                 endp->toggle_bits = toggle_bits;
@@ -768,10 +766,10 @@
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -797,12 +795,12 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer + urb->actual_length;
                 u8 *b = buf;
@@ -871,10 +869,10 @@
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -898,20 +896,20 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -936,12 +934,12 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer;
                 u8 *b = buf;
@@ -980,10 +978,10 @@
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1007,20 +1005,20 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1045,12 +1043,12 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 if (usb_pipein(urb->pipe)) {
                         int retval;
                         struct u132_ring *ring = endp->ring;
@@ -1077,10 +1075,10 @@
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1106,22 +1104,22 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 u132->addr[0].address = 0;
                 endp->usb_addr = udev->usb_addr;
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1145,12 +1143,12 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 up(&u132->scheduler_lock);
@@ -1162,10 +1160,10 @@
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1189,20 +1187,20 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1227,12 +1225,12 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer;
@@ -1251,10 +1249,10 @@
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1279,12 +1277,12 @@
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 up(&u132->scheduler_lock);
@@ -1296,10 +1294,10 @@
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1519,12 +1517,15 @@
                 }
         }
 }
+#ifdef CONFIG_PM
 
 static void port_power(struct u132 *u132, int pn, int is_on)
 {
         u132->port[pn].power = is_on;
 }
 
+#endif
+
 static void u132_power(struct u132 *u132, int is_on)
 {
         struct usb_hcd *hcd = u132_to_hcd(u132)
@@ -1801,10 +1802,10 @@
                 dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
                         "ed\n", hcd);
         } else {
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 msleep(100);
                 u132_power(u132, 0);
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
         }
 }
 
@@ -1826,7 +1827,7 @@
                         (pdev->dev.platform_data))->vendor;
                 u16 device = ((struct u132_platform_data *)
                         (pdev->dev.platform_data))->device;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 msleep(10);
                 if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
                         u132->flags = OHCI_QUIRK_AMD756;
@@ -1841,7 +1842,7 @@
                         u132->going = 1;
                 }
                 msleep(100);
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
         } else {
                 dev_err(&u132->platform_dev->dev, "platform_device missing\n");
@@ -1861,32 +1862,44 @@
                 return -ESHUTDOWN;
         } else {
                 int retval;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 retval = u132_init(u132);
                 if (retval) {
                         u132_disable(u132);
                         u132->going = 1;
                 }
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
         }
 }
 
 static int create_endpoint_and_queue_int(struct u132 *u132,
-        struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+	struct u132_udev *udev, struct urb *urb,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
         gfp_t mem_flags)
 {
         struct u132_ring *ring;
         unsigned long irqs;
-        u8 endp_number = ++u132->num_endpoints;
-        struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
-                kmalloc(sizeof(struct u132_endp), mem_flags);
+	int rc;
+	u8 endp_number;
+	struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
         if (!endp) {
                 return -ENOMEM;
         }
+
+	spin_lock_init(&endp->queue_lock.slock);
+	spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+	if (rc) {
+		spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+		kfree(endp);
+		return rc;
+	}
+
+	endp_number = ++u132->num_endpoints;
+	urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         ring = endp->ring = &u132->ring[0];
         if (ring->curr_endp) {
@@ -1902,7 +1915,7 @@
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->u132 = u132;
-        endp->hep = hep;
+	endp->hep = urb->ep;
         endp->pipetype = usb_pipetype(urb->pipe);
         u132_endp_init_kref(u132, endp);
         if (usb_pipein(urb->pipe)) {
@@ -1921,7 +1934,6 @@
                 u132_udev_get_kref(u132, udev);
         }
         urb->hcpriv = u132;
-        spin_lock_irqsave(&endp->queue_lock.slock, irqs);
         endp->delayed = 1;
         endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
         endp->udev_number = address;
@@ -1936,8 +1948,8 @@
         return 0;
 }
 
-static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
-        struct usb_host_endpoint *hep, struct urb *urb,
+static int queue_int_on_old_endpoint(struct u132 *u132,
+	struct u132_udev *udev, struct urb *urb,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp, u8 address)
 {
@@ -1961,21 +1973,33 @@
 }
 
 static int create_endpoint_and_queue_bulk(struct u132 *u132,
-        struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+	struct u132_udev *udev, struct urb *urb,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
         gfp_t mem_flags)
 {
         int ring_number;
         struct u132_ring *ring;
         unsigned long irqs;
-        u8 endp_number = ++u132->num_endpoints;
-        struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
-                kmalloc(sizeof(struct u132_endp), mem_flags);
+	int rc;
+	u8 endp_number;
+	struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
         if (!endp) {
                 return -ENOMEM;
         }
+
+	spin_lock_init(&endp->queue_lock.slock);
+	spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+	if (rc) {
+		spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+		kfree(endp);
+		return rc;
+	}
+
+	endp_number = ++u132->num_endpoints;
+	urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         endp->dequeueing = 0;
         endp->edset_flush = 0;
@@ -1983,7 +2007,7 @@
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->u132 = u132;
-        endp->hep = hep;
+	endp->hep = urb->ep;
         endp->pipetype = usb_pipetype(urb->pipe);
         u132_endp_init_kref(u132, endp);
         if (usb_pipein(urb->pipe)) {
@@ -2012,7 +2036,6 @@
         }
         ring->length += 1;
         urb->hcpriv = u132;
-        spin_lock_irqsave(&endp->queue_lock.slock, irqs);
         endp->udev_number = address;
         endp->usb_addr = usb_addr;
         endp->usb_endp = usb_endp;
@@ -2026,7 +2049,7 @@
 }
 
 static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
-         struct usb_host_endpoint *hep, struct urb *urb,
+	struct urb *urb,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp, u8 address)
 {
@@ -2048,19 +2071,32 @@
 }
 
 static int create_endpoint_and_queue_control(struct u132 *u132,
-        struct usb_host_endpoint *hep, struct urb *urb,
+	struct urb *urb,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
         gfp_t mem_flags)
 {
         struct u132_ring *ring;
-        u8 endp_number = ++u132->num_endpoints;
-        struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
-                kmalloc(sizeof(struct u132_endp), mem_flags);
+	unsigned long irqs;
+	int rc;
+	u8 endp_number;
+	struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
         if (!endp) {
                 return -ENOMEM;
         }
+
+	spin_lock_init(&endp->queue_lock.slock);
+	spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+	if (rc) {
+		spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+		kfree(endp);
+		return rc;
+	}
+
+	endp_number = ++u132->num_endpoints;
+	urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         ring = endp->ring = &u132->ring[0];
         if (ring->curr_endp) {
@@ -2076,11 +2112,10 @@
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->u132 = u132;
-        endp->hep = hep;
+	endp->hep = urb->ep;
         u132_endp_init_kref(u132, endp);
         u132_endp_get_kref(u132, endp);
         if (usb_addr == 0) {
-                unsigned long irqs;
                 u8 address = u132->addr[usb_addr].address;
                 struct u132_udev *udev = &u132->udev[address];
                 endp->udev_number = address;
@@ -2094,7 +2129,6 @@
                 udev->endp_number_in[usb_endp] = endp_number;
                 udev->endp_number_out[usb_endp] = endp_number;
                 urb->hcpriv = u132;
-                spin_lock_irqsave(&endp->queue_lock.slock, irqs);
                 endp->queue_size = 1;
                 endp->queue_last = 0;
                 endp->queue_next = 0;
@@ -2103,7 +2137,6 @@
                 u132_endp_queue_work(u132, endp, 0);
                 return 0;
         } else {                /*(usb_addr > 0) */
-                unsigned long irqs;
                 u8 address = u132->addr[usb_addr].address;
                 struct u132_udev *udev = &u132->udev[address];
                 endp->udev_number = address;
@@ -2117,7 +2150,6 @@
                 udev->endp_number_in[usb_endp] = endp_number;
                 udev->endp_number_out[usb_endp] = endp_number;
                 urb->hcpriv = u132;
-                spin_lock_irqsave(&endp->queue_lock.slock, irqs);
                 endp->queue_size = 1;
                 endp->queue_last = 0;
                 endp->queue_next = 0;
@@ -2129,7 +2161,7 @@
 }
 
 static int queue_control_on_old_endpoint(struct u132 *u132,
-        struct usb_host_endpoint *hep, struct urb *urb,
+	struct urb *urb,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp)
 {
@@ -2229,8 +2261,8 @@
         }
 }
 
-static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
-        struct urb *urb, gfp_t mem_flags)
+static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+		gfp_t mem_flags)
 {
         struct u132 *u132 = hcd_to_u132(hcd);
         if (irqs_disabled()) {
@@ -2245,8 +2277,8 @@
                         , u132->going);
                 return -ENODEV;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 return -ESHUTDOWN;
         } else {
                 u8 usb_addr = usb_pipedevice(urb->pipe);
@@ -2255,16 +2287,24 @@
                 if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
                         u8 address = u132->addr[usb_addr].address;
                         struct u132_udev *udev = &u132->udev[address];
-                        struct u132_endp *endp = hep->hcpriv;
+                        struct u132_endp *endp = urb->ep->hcpriv;
                         urb->actual_length = 0;
                         if (endp) {
                                 unsigned long irqs;
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
-                                retval = queue_int_on_old_endpoint(u132, udev,
-                                        hep, urb, usb_dev, endp, usb_addr,
-                                        usb_endp, address);
+				retval = usb_hcd_link_urb_to_ep(hcd, urb);
+				if (retval == 0) {
+					retval = queue_int_on_old_endpoint(
+							u132, udev, urb,
+							usb_dev, endp,
+							usb_addr, usb_endp,
+							address);
+					if (retval)
+						usb_hcd_unlink_urb_from_ep(
+								hcd, urb);
+				}
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                 if (retval) {
@@ -2279,8 +2319,8 @@
                                 return -EINVAL;
                         } else {        /*(endp == NULL) */
                                 return create_endpoint_and_queue_int(u132, udev,
-                                         hep, urb, usb_dev, usb_addr, usb_endp,
-                                        address, mem_flags);
+						urb, usb_dev, usb_addr,
+						usb_endp, address, mem_flags);
                         }
                 } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
                         dev_err(&u132->platform_dev->dev, "the hardware does no"
@@ -2289,16 +2329,24 @@
                 } else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
                         u8 address = u132->addr[usb_addr].address;
                         struct u132_udev *udev = &u132->udev[address];
-                        struct u132_endp *endp = hep->hcpriv;
+                        struct u132_endp *endp = urb->ep->hcpriv;
                         urb->actual_length = 0;
                         if (endp) {
                                 unsigned long irqs;
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
-                                retval = queue_bulk_on_old_endpoint(u132, udev,
-                                        hep, urb, usb_dev, endp, usb_addr,
-                                        usb_endp, address);
+				retval = usb_hcd_link_urb_to_ep(hcd, urb);
+				if (retval == 0) {
+					retval = queue_bulk_on_old_endpoint(
+							u132, udev, urb,
+							usb_dev, endp,
+							usb_addr, usb_endp,
+							address);
+					if (retval)
+						usb_hcd_unlink_urb_from_ep(
+								hcd, urb);
+				}
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                 if (retval) {
@@ -2311,10 +2359,10 @@
                                 return -EINVAL;
                         } else
                                 return create_endpoint_and_queue_bulk(u132,
-                                        udev, hep, urb, usb_dev, usb_addr,
+					udev, urb, usb_dev, usb_addr,
                                         usb_endp, address, mem_flags);
                 } else {
-                        struct u132_endp *endp = hep->hcpriv;
+                        struct u132_endp *endp = urb->ep->hcpriv;
                         u16 urb_size = 8;
                         u8 *b = urb->setup_packet;
                         int i = 0;
@@ -2337,9 +2385,16 @@
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
-                                retval = queue_control_on_old_endpoint(u132,
-                                        hep, urb, usb_dev, endp, usb_addr,
-                                        usb_endp);
+				retval = usb_hcd_link_urb_to_ep(hcd, urb);
+				if (retval == 0) {
+					retval = queue_control_on_old_endpoint(
+							u132, urb, usb_dev,
+							endp, usb_addr,
+							usb_endp);
+					if (retval)
+						usb_hcd_unlink_urb_from_ep(
+								hcd, urb);
+				}
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                 if (retval) {
@@ -2352,7 +2407,7 @@
                                 return -EINVAL;
                         } else
                                 return create_endpoint_and_queue_control(u132,
-                                        hep, urb, usb_dev, usb_addr, usb_endp,
+					urb, usb_dev, usb_addr, usb_endp,
                                         mem_flags);
                 }
         }
@@ -2371,8 +2426,7 @@
                         list_del(scan);
                         endp->queue_size -= 1;
                         urb->error_count = 0;
-                        urb->hcpriv = NULL;
-                        usb_hcd_giveback_urb(hcd, urb);
+			usb_hcd_giveback_urb(hcd, urb, 0);
                         return 0;
                 } else
                         continue;
@@ -2387,10 +2441,17 @@
 }
 
 static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
-        struct urb *urb)
+		struct urb *urb, int status)
 {
         unsigned long irqs;
+	int rc;
+
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status);
+	if (rc) {
+		spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+		return rc;
+	}
         if (endp->queue_size == 0) {
                 dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
                         "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
@@ -2406,11 +2467,10 @@
                         endp->edset_flush = 1;
                         u132_endp_queue_work(u132, endp, 0);
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
-                        urb->hcpriv = NULL;
                         return 0;
                 } else {
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
-                        u132_hcd_abandon_urb(u132, endp, urb, urb->status);
+			u132_hcd_abandon_urb(u132, endp, urb, status);
                         return 0;
                 }
         } else {
@@ -2435,6 +2495,8 @@
                 }
                 if (urb_slot) {
                         struct usb_hcd *hcd = u132_to_hcd(u132);
+
+			usb_hcd_unlink_urb_from_ep(hcd, urb);
                         endp->queue_size -= 1;
                         if (list_empty(&endp->urb_more)) {
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
@@ -2449,8 +2511,7 @@
                                         irqs);
                                 kfree(urbq);
                         } urb->error_count = 0;
-                        urb->hcpriv = NULL;
-                        usb_hcd_giveback_urb(hcd, urb);
+			usb_hcd_giveback_urb(hcd, urb, status);
                         return 0;
                 } else if (list_empty(&endp->urb_more)) {
                         dev_err(&u132->platform_dev->dev, "urb=%p not found in "
@@ -2464,7 +2525,10 @@
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                         return -EINVAL;
                 } else {
-                        int retval = dequeue_from_overflow_chain(u132, endp,
+			int retval;
+
+			usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb);
+			retval = dequeue_from_overflow_chain(u132, endp,
                                 urb);
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                         return retval;
@@ -2472,7 +2536,7 @@
         }
 }
 
-static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
         struct u132 *u132 = hcd_to_u132(hcd);
         if (u132->going > 2) {
@@ -2487,11 +2551,11 @@
                 if (usb_pipein(urb->pipe)) {
                         u8 endp_number = udev->endp_number_in[usb_endp];
                         struct u132_endp *endp = u132->endp[endp_number - 1];
-                        return u132_endp_urb_dequeue(u132, endp, urb);
+                        return u132_endp_urb_dequeue(u132, endp, urb, status);
                 } else {
                         u8 endp_number = udev->endp_number_out[usb_endp];
                         struct u132_endp *endp = u132->endp[endp_number - 1];
-                        return u132_endp_urb_dequeue(u132, endp, urb);
+                        return u132_endp_urb_dequeue(u132, endp, urb, status);
                 }
         }
 }
@@ -2801,7 +2865,7 @@
                 return -ESHUTDOWN;
         } else {
                 int retval = 0;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 switch (typeReq) {
                 case ClearHubFeature:
                         switch (wValue) {
@@ -2864,7 +2928,7 @@
                       stall:retval = -EPIPE;
                         break;
                 }
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
         }
 }
@@ -3000,7 +3064,7 @@
                         dev_err(&u132->platform_dev->dev, "removing device u132"
 				".%d\n", u132->sequence_num);
                         msleep(100);
-                        down(&u132->sw_lock);
+                        mutex_lock(&u132->sw_lock);
                         u132_monitor_cancel_work(u132);
                         while (rings-- > 0) {
                                 struct u132_ring *ring = &u132->ring[rings];
@@ -3013,7 +3077,7 @@
                         u132->going += 1;
                         printk(KERN_INFO "removing device u132.%d\n",
                                 u132->sequence_num);
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         usb_remove_hcd(hcd);
                         u132_u132_put_kref(u132);
                         return 0;
@@ -3033,7 +3097,7 @@
         u132->platform_dev = pdev;
         u132->power = 0;
         u132->reset = 0;
-        init_MUTEX(&u132->sw_lock);
+        mutex_init(&u132->sw_lock);
         init_MUTEX(&u132->scheduler_lock);
         while (rings-- > 0) {
                 struct u132_ring *ring = &u132->ring[rings];
@@ -3043,7 +3107,7 @@
                 ring->curr_endp = NULL;
                 INIT_DELAYED_WORK(&ring->scheduler,
 				  u132_hcd_ring_work_scheduler);
-        } down(&u132->sw_lock);
+        } mutex_lock(&u132->sw_lock);
         INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work);
         while (ports-- > 0) {
                 struct u132_port *port = &u132->port[ports];
@@ -3073,7 +3137,7 @@
         while (endps-- > 0) {
                 u132->endp[endps] = NULL;
         }
-        up(&u132->sw_lock);
+        mutex_unlock(&u132->sw_lock);
         return;
 }
 
@@ -3111,10 +3175,10 @@
                 int retval = 0;
                 struct u132 *u132 = hcd_to_u132(hcd);
                 hcd->rsrc_start = 0;
-                down(&u132_module_lock);
+                mutex_lock(&u132_module_lock);
                 list_add_tail(&u132->u132_list, &u132_static_list);
                 u132->sequence_num = ++u132_instances;
-                up(&u132_module_lock);
+                mutex_unlock(&u132_module_lock);
                 u132_u132_init_kref(u132);
                 u132_initialise(u132, pdev);
                 hcd->product_desc = "ELAN U132 Host Controller";
@@ -3216,7 +3280,7 @@
         INIT_LIST_HEAD(&u132_static_list);
         u132_instances = 0;
         u132_exiting = 0;
-        init_MUTEX(&u132_module_lock);
+        mutex_init(&u132_module_lock);
         if (usb_disabled())
                 return -ENODEV;
         printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__,
@@ -3232,9 +3296,9 @@
 {
         struct u132 *u132;
         struct u132 *temp;
-        down(&u132_module_lock);
+        mutex_lock(&u132_module_lock);
         u132_exiting += 1;
-        up(&u132_module_lock);
+        mutex_unlock(&u132_module_lock);
         list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) {
                 platform_device_unregister(u132->platform_dev);
         } platform_driver_unregister(&u132_platform_driver);
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 1497371..20cc58b 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -120,8 +120,8 @@
 	out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
 	out += sprintf(out, " Actlen=%d", urbp->urb->actual_length);
 
-	if (urbp->urb->status != -EINPROGRESS)
-		out += sprintf(out, " Status=%d", urbp->urb->status);
+	if (urbp->urb->unlinked)
+		out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked);
 	out += sprintf(out, "\n");
 
 	i = nactive = ninactive = 0;
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 76c555a..4db17f7 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -237,7 +237,7 @@
 static int remote_wakeup_is_broken(struct uhci_hcd *uhci)
 {
 	int port;
-	char *sys_info;
+	const char *sys_info;
 	static char bad_Asus_board[] = "A7V8X";
 
 	/* One of Asus's motherboards has a bug which causes it to
@@ -933,7 +933,7 @@
 	}
 
 	uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
-		sizeof(struct urb_priv), 0, 0, NULL, NULL);
+		sizeof(struct urb_priv), 0, 0, NULL);
 	if (!uhci_up_cachep)
 		goto up_failed;
 
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 1b3d234..340d6ed 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -146,7 +146,6 @@
 	short phase;			/* Between 0 and period-1 */
 	short load;			/* Periodic time requirement, in us */
 	unsigned int iso_frame;		/* Frame # for iso_packet_desc */
-	int iso_status;			/* Status for Isochronous URBs */
 
 	int state;			/* QH_STATE_xxx; see above */
 	int type;			/* Queue type (control, bulk, etc) */
@@ -457,21 +456,6 @@
 };
 
 
-/*
- * Locking in uhci.c
- *
- * Almost everything relating to the hardware schedule and processing
- * of URBs is protected by uhci->lock.  urb->status is protected by
- * urb->lock; that's the one exception.
- *
- * To prevent deadlocks, never lock uhci->lock while holding urb->lock.
- * The safe order of locking is:
- *
- * #1 uhci->lock
- * #2 urb->lock
- */
-
-
 /* Some special IDs */
 
 #define PCI_VENDOR_ID_GENESYS		0x17a0
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 4aed305..e5d60d5 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -757,7 +757,6 @@
 		uhci_free_td(uhci, td);
 	}
 
-	urbp->urb->hcpriv = NULL;
 	kmem_cache_free(uhci_up_cachep, urbp);
 }
 
@@ -827,8 +826,10 @@
 	 * If direction is "send", change the packet ID from SETUP (0x2D)
 	 * to OUT (0xE1).  Else change it from SETUP to IN (0x69) and
 	 * set Short Packet Detect (SPD) for all data packets.
+	 *
+	 * 0-length transfers always get treated as "send".
 	 */
-	if (usb_pipeout(urb->pipe))
+	if (usb_pipeout(urb->pipe) || len == 0)
 		destination ^= (USB_PID_SETUP ^ USB_PID_OUT);
 	else {
 		destination ^= (USB_PID_SETUP ^ USB_PID_IN);
@@ -839,7 +840,12 @@
 	 * Build the DATA TDs
 	 */
 	while (len > 0) {
-		int pktsze = min(len, maxsze);
+		int pktsze = maxsze;
+
+		if (len <= pktsze) {		/* The last data packet */
+			pktsze = len;
+			status &= ~TD_CTRL_SPD;
+		}
 
 		td = uhci_alloc_td(uhci);
 		if (!td)
@@ -866,20 +872,10 @@
 		goto nomem;
 	*plink = LINK_TO_TD(td);
 
-	/*
-	 * It's IN if the pipe is an output pipe or we're not expecting
-	 * data back.
-	 */
-	destination &= ~TD_TOKEN_PID_MASK;
-	if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)
-		destination |= USB_PID_IN;
-	else
-		destination |= USB_PID_OUT;
-
+	/* Change direction for the status transaction */
+	destination ^= (USB_PID_IN ^ USB_PID_OUT);
 	destination |= TD_TOKEN_TOGGLE;		/* End in Data1 */
 
-	status &= ~TD_CTRL_SPD;
-
 	uhci_add_td_to_urbp(td, urbp);
 	uhci_fill_td(td, status | TD_CTRL_IOC,
 			destination | uhci_explen(0), 0);
@@ -1185,10 +1181,18 @@
 				}
 			}
 
+		/* Did we receive a short packet? */
 		} else if (len < uhci_expected_length(td_token(td))) {
 
-			/* We received a short packet */
-			if (urb->transfer_flags & URB_SHORT_NOT_OK)
+			/* For control transfers, go to the status TD if
+			 * this isn't already the last data TD */
+			if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
+				if (td->list.next != urbp->td_list.prev)
+					ret = 1;
+			}
+
+			/* For bulk and interrupt, this may be an error */
+			else if (urb->transfer_flags & URB_SHORT_NOT_OK)
 				ret = -EREMOTEIO;
 
 			/* Fixup needed only if this isn't the URB's last TD */
@@ -1208,10 +1212,6 @@
 
 err:
 	if (ret < 0) {
-		/* In case a control transfer gets an error
-		 * during the setup stage */
-		urb->actual_length = max(urb->actual_length, 0);
-
 		/* Note that the queue has stopped and save
 		 * the next toggle value */
 		qh->element = UHCI_PTR_TERM;
@@ -1323,7 +1323,6 @@
 	if (list_empty(&qh->queue)) {
 		qh->iso_packet_desc = &urb->iso_frame_desc[0];
 		qh->iso_frame = urb->start_frame;
-		qh->iso_status = 0;
 	}
 
 	qh->skel = SKEL_ISO;
@@ -1360,22 +1359,18 @@
 			qh->iso_packet_desc->actual_length = actlength;
 			qh->iso_packet_desc->status = status;
 		}
-
-		if (status) {
+		if (status)
 			urb->error_count++;
-			qh->iso_status = status;
-		}
 
 		uhci_remove_td_from_urbp(td);
 		uhci_free_td(uhci, td);
 		qh->iso_frame += qh->period;
 		++qh->iso_packet_desc;
 	}
-	return qh->iso_status;
+	return 0;
 }
 
 static int uhci_urb_enqueue(struct usb_hcd *hcd,
-		struct usb_host_endpoint *hep,
 		struct urb *urb, gfp_t mem_flags)
 {
 	int ret;
@@ -1386,19 +1381,19 @@
 
 	spin_lock_irqsave(&uhci->lock, flags);
 
-	ret = urb->status;
-	if (ret != -EINPROGRESS)		/* URB already unlinked! */
-		goto done;
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (ret)
+		goto done_not_linked;
 
 	ret = -ENOMEM;
 	urbp = uhci_alloc_urb_priv(uhci, urb);
 	if (!urbp)
 		goto done;
 
-	if (hep->hcpriv)
-		qh = (struct uhci_qh *) hep->hcpriv;
+	if (urb->ep->hcpriv)
+		qh = urb->ep->hcpriv;
 	else {
-		qh = uhci_alloc_qh(uhci, urb->dev, hep);
+		qh = uhci_alloc_qh(uhci, urb->dev, urb->ep);
 		if (!qh)
 			goto err_no_qh;
 	}
@@ -1439,27 +1434,29 @@
 err_submit_failed:
 	if (qh->state == QH_STATE_IDLE)
 		uhci_make_qh_idle(uhci, qh);	/* Reclaim unused QH */
-
 err_no_qh:
 	uhci_free_urb_priv(uhci, urbp);
-
 done:
+	if (ret)
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+done_not_linked:
 	spin_unlock_irqrestore(&uhci->lock, flags);
 	return ret;
 }
 
-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	unsigned long flags;
-	struct urb_priv *urbp;
 	struct uhci_qh *qh;
+	int rc;
 
 	spin_lock_irqsave(&uhci->lock, flags);
-	urbp = urb->hcpriv;
-	if (!urbp)			/* URB was never linked! */
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
 		goto done;
-	qh = urbp->qh;
+
+	qh = ((struct urb_priv *) urb->hcpriv)->qh;
 
 	/* Remove Isochronous TDs from the frame list ASAP */
 	if (qh->type == USB_ENDPOINT_XFER_ISOC) {
@@ -1476,22 +1473,31 @@
 
 done:
 	spin_unlock_irqrestore(&uhci->lock, flags);
-	return 0;
+	return rc;
 }
 
 /*
  * Finish unlinking an URB and give it back
  */
 static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh,
-		struct urb *urb)
+		struct urb *urb, int status)
 __releases(uhci->lock)
 __acquires(uhci->lock)
 {
 	struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
 
+	if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
+
+		/* urb->actual_length < 0 means the setup transaction didn't
+		 * complete successfully.  Either it failed or the URB was
+		 * unlinked first.  Regardless, don't confuse people with a
+		 * negative length. */
+		urb->actual_length = max(urb->actual_length, 0);
+	}
+
 	/* When giving back the first URB in an Isochronous queue,
 	 * reinitialize the QH's iso-related members for the next URB. */
-	if (qh->type == USB_ENDPOINT_XFER_ISOC &&
+	else if (qh->type == USB_ENDPOINT_XFER_ISOC &&
 			urbp->node.prev == &qh->queue &&
 			urbp->node.next != &qh->queue) {
 		struct urb *nurb = list_entry(urbp->node.next,
@@ -1499,7 +1505,6 @@
 
 		qh->iso_packet_desc = &nurb->iso_frame_desc[0];
 		qh->iso_frame = nurb->start_frame;
-		qh->iso_status = 0;
 	}
 
 	/* Take the URB off the QH's queue.  If the queue is now empty,
@@ -1512,9 +1517,10 @@
 	}
 
 	uhci_free_urb_priv(uhci, urbp);
+	usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb);
 
 	spin_unlock(&uhci->lock);
-	usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
+	usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, status);
 	spin_lock(&uhci->lock);
 
 	/* If the queue is now empty, we can unlink the QH and give up its
@@ -1550,24 +1556,17 @@
 		if (status == -EINPROGRESS)
 			break;
 
-		spin_lock(&urb->lock);
-		if (urb->status == -EINPROGRESS)	/* Not dequeued */
-			urb->status = status;
-		else
-			status = ECONNRESET;		/* Not -ECONNRESET */
-		spin_unlock(&urb->lock);
-
 		/* Dequeued but completed URBs can't be given back unless
 		 * the QH is stopped or has finished unlinking. */
-		if (status == ECONNRESET) {
+		if (urb->unlinked) {
 			if (QH_FINISHED_UNLINKING(qh))
 				qh->is_stopped = 1;
 			else if (!qh->is_stopped)
 				return;
 		}
 
-		uhci_giveback_urb(uhci, qh, urb);
-		if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC)
+		uhci_giveback_urb(uhci, qh, urb, status);
+		if (status < 0)
 			break;
 	}
 
@@ -1582,7 +1581,7 @@
 restart:
 	list_for_each_entry(urbp, &qh->queue, node) {
 		urb = urbp->urb;
-		if (urb->status != -EINPROGRESS) {
+		if (urb->unlinked) {
 
 			/* Fix up the TD links and save the toggles for
 			 * non-Isochronous queues.  For Isochronous queues,
@@ -1591,7 +1590,7 @@
 				qh->is_stopped = 0;
 				return;
 			}
-			uhci_giveback_urb(uhci, qh, urb);
+			uhci_giveback_urb(uhci, qh, urb, 0);
 			goto restart;
 		}
 	}
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 36502a0..d1131a8 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -284,9 +284,9 @@
 	int data_received=0, wake_up;
 	unsigned char* b=urb->transfer_buffer;
 	struct mdc800_data* mdc800=urb->context;
+	int status = urb->status;
 
-	if (urb->status >= 0)
-	{
+	if (status >= 0) {
 
 		//dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]);
 
@@ -324,7 +324,7 @@
 		||
 			((mdc800->camera_request_ready == 3) && (mdc800->camera_busy))
 		||
-			(urb->status < 0)
+			(status < 0)
 		);
 
 	if (wake_up)
@@ -376,15 +376,12 @@
 static void mdc800_usb_write_notify (struct urb *urb)
 {
 	struct mdc800_data* mdc800=urb->context;
+	int status = urb->status;
 
-	if (urb->status != 0)
-	{
-		err ("writing command fails (status=%i)", urb->status);
-	}
+	if (status != 0)
+		err ("writing command fails (status=%i)", status);
 	else
-	{	
 		mdc800->state=READY;
-	}
 	mdc800->written = 1;
 	wake_up (&mdc800->write_wait);
 }
@@ -396,9 +393,9 @@
 static void mdc800_usb_download_notify (struct urb *urb)
 {
 	struct mdc800_data* mdc800=urb->context;
+	int status = urb->status;
 
-	if (urb->status == 0)
-	{
+	if (status == 0) {
 		/* Fill output buffer with these data */
 		memcpy (mdc800->out,  urb->transfer_buffer, 64);
 		mdc800->out_count=64;
@@ -408,10 +405,8 @@
 		{
 			mdc800->state=READY;
 		}
-	}
-	else
-	{
-		err ("request bytes fails (status:%i)", urb->status);
+	} else {
+		err ("request bytes fails (status:%i)", status);
 	}
 	mdc800->downloaded = 1;
 	wake_up (&mdc800->download_wait);
@@ -649,9 +644,9 @@
 
 	retval=0;
 	mdc800->irq_urb->dev = mdc800->dev;
-	if (usb_submit_urb (mdc800->irq_urb, GFP_KERNEL))
-	{
-		err ("request USB irq fails (submit_retval=%i urb_status=%i).",retval, mdc800->irq_urb->status);
+	retval = usb_submit_urb (mdc800->irq_urb, GFP_KERNEL);
+	if (retval) {
+		err ("request USB irq fails (submit_retval=%i).", retval);
 		errn = -EIO;
 		goto error_out;
 	}
@@ -698,6 +693,7 @@
 {
 	size_t left=len, sts=len; /* single transfer size */
 	char __user *ptr = buf;
+	int retval;
 
 	mutex_lock(&mdc800->io_lock);
 	if (mdc800->state == NOT_CONNECTED)
@@ -737,9 +733,9 @@
 
 				/* Download -> Request new bytes */
 				mdc800->download_urb->dev = mdc800->dev;
-				if (usb_submit_urb (mdc800->download_urb, GFP_KERNEL))
-				{
-					err ("Can't submit download urb (status=%i)",mdc800->download_urb->status);
+				retval = usb_submit_urb (mdc800->download_urb, GFP_KERNEL);
+				if (retval) {
+					err ("Can't submit download urb (retval=%i)",retval);
 					mutex_unlock(&mdc800->io_lock);
 					return len-left;
 				}
@@ -788,6 +784,7 @@
 static ssize_t mdc800_device_write (struct file *file, const char __user *buf, size_t len, loff_t *pos)
 {
 	size_t i=0;
+	int retval;
 
 	mutex_lock(&mdc800->io_lock);
 	if (mdc800->state != READY)
@@ -854,9 +851,9 @@
 			mdc800->state=WORKING;
 			memcpy (mdc800->write_urb->transfer_buffer, mdc800->in,8);
 			mdc800->write_urb->dev = mdc800->dev;
-			if (usb_submit_urb (mdc800->write_urb, GFP_KERNEL))
-			{
-				err ("submitting write urb fails (status=%i)", mdc800->write_urb->status);
+			retval = usb_submit_urb (mdc800->write_urb, GFP_KERNEL);
+			if (retval) {
+				err ("submitting write urb fails (retval=%i)", retval);
 				mutex_unlock(&mdc800->io_lock);
 				return -EIO;
 			}
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 51bd80d..768b2c1 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -189,7 +189,7 @@
 #define MTS_DEBUG_INT() \
 	do { MTS_DEBUG_GOT_HERE(); \
 	     MTS_DEBUG("transfer = 0x%x context = 0x%x\n",(int)transfer,(int)context ); \
-	     MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",(int)transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
+	     MTS_DEBUG("status = 0x%x data-length = 0x%x sent = 0x%x\n",transfer->status,(int)context->data_length, (int)transfer->actual_length ); \
              mts_debug_dump(context->instance);\
 	   } while(0)
 #else
@@ -393,8 +393,6 @@
 		      context
 		);
 
-	transfer->status = 0;
-
 	res = usb_submit_urb( transfer, GFP_ATOMIC );
 	if ( unlikely(res) ) {
 		MTS_INT_ERROR( "could not submit URB! Error was %d\n",(int)res );
@@ -444,12 +442,13 @@
 static void mts_data_done( struct urb* transfer )
 /* Interrupt context! */
 {
+	int status = transfer->status;
 	MTS_INT_INIT();
 
 	if ( context->data_length != transfer->actual_length ) {
 		context->srb->resid = context->data_length - transfer->actual_length;
-	} else if ( unlikely(transfer->status) ) {
-		context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
+	} else if ( unlikely(status) ) {
+		context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
 	}
 
 	mts_get_status(transfer);
@@ -461,10 +460,11 @@
 static void mts_command_done( struct urb *transfer )
 /* Interrupt context! */
 {
+	int status = transfer->status;
 	MTS_INT_INIT();
 
-	if ( unlikely(transfer->status) ) {
-	        if (transfer->status == -ENOENT) {
+	if ( unlikely(status) ) {
+	        if (status == -ENOENT) {
 		        /* We are being killed */
 			MTS_DEBUG_GOT_HERE();
 			context->srb->result = DID_ABORT<<16;
@@ -502,12 +502,13 @@
 static void mts_do_sg (struct urb* transfer)
 {
 	struct scatterlist * sg;
+	int status = transfer->status;
 	MTS_INT_INIT();
 
 	MTS_DEBUG("Processing fragment %d of %d\n", context->fragment,context->srb->use_sg);
 
-	if (unlikely(transfer->status)) {
-                context->srb->result = (transfer->status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
+	if (unlikely(status)) {
+                context->srb->result = (status == -ENOENT ? DID_ABORT : DID_ERROR)<<16;
 		mts_transfer_cleanup(transfer);
         }
 
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index d72c42e..5131cbf 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -24,6 +24,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/usb.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #ifdef CONFIG_USB_DEBUG
@@ -80,7 +81,7 @@
 
 /* Structure to hold all of our device specific stuff */
 struct adu_device {
-	struct semaphore	sem; /* locks this structure */
+	struct mutex		mtx; /* locks this structure */
 	struct usb_device*	udev; /* save off the usb device pointer */
 	struct usb_interface*	interface;
 	unsigned char		minor; /* the starting minor number for this device */
@@ -178,17 +179,19 @@
 static void adu_interrupt_in_callback(struct urb *urb)
 {
 	struct adu_device *dev = urb->context;
+	int status = urb->status;
 
-	dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+	dbg(4," %s : enter, status %d", __FUNCTION__, status);
 	adu_debug_data(5, __FUNCTION__, urb->actual_length,
 		       urb->transfer_buffer);
 
 	spin_lock(&dev->buflock);
 
-	if (urb->status != 0) {
-		if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)) {
+	if (status != 0) {
+		if ((status != -ENOENT) && (status != -ECONNRESET) &&
+			(status != -ESHUTDOWN)) {
 			dbg(1," %s : nonzero status received: %d",
-			    __FUNCTION__, urb->status);
+			    __FUNCTION__, status);
 		}
 		goto exit;
 	}
@@ -216,21 +219,22 @@
 	wake_up_interruptible(&dev->read_wait);
 	adu_debug_data(5, __FUNCTION__, urb->actual_length,
 		       urb->transfer_buffer);
-	dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+	dbg(4," %s : leave, status %d", __FUNCTION__, status);
 }
 
 static void adu_interrupt_out_callback(struct urb *urb)
 {
 	struct adu_device *dev = urb->context;
+	int status = urb->status;
 
-	dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+	dbg(4," %s : enter, status %d", __FUNCTION__, status);
 	adu_debug_data(5,__FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
-	if (urb->status != 0) {
-		if ((urb->status != -ENOENT) &&
-		    (urb->status != -ECONNRESET)) {
+	if (status != 0) {
+		if ((status != -ENOENT) &&
+		    (status != -ECONNRESET)) {
 			dbg(1, " %s :nonzero status received: %d",
-			    __FUNCTION__, urb->status);
+			    __FUNCTION__, status);
 		}
 		goto exit;
 	}
@@ -240,7 +244,7 @@
 
 	adu_debug_data(5, __FUNCTION__, urb->actual_length,
 		       urb->transfer_buffer);
-	dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+	dbg(4," %s : leave, status %d", __FUNCTION__, status);
 }
 
 static int adu_open(struct inode *inode, struct file *file)
@@ -269,8 +273,8 @@
 	}
 
 	/* lock this device */
-	if ((retval = down_interruptible(&dev->sem))) {
-		dbg(2, "%s : sem down failed", __FUNCTION__);
+	if ((retval = mutex_lock_interruptible(&dev->mtx))) {
+		dbg(2, "%s : mutex lock failed", __FUNCTION__);
 		goto exit_no_device;
 	}
 
@@ -299,7 +303,7 @@
 		if (retval)
 			--dev->open_count;
 	}
-	up(&dev->sem);
+	mutex_unlock(&dev->mtx);
 
 exit_no_device:
 	dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval);
@@ -347,7 +351,7 @@
 	}
 
 	/* lock our device */
-	down(&dev->sem); /* not interruptible */
+	mutex_lock(&dev->mtx); /* not interruptible */
 
 	if (dev->open_count <= 0) {
 		dbg(1," %s : device not opened", __FUNCTION__);
@@ -357,7 +361,7 @@
 
 	if (dev->udev == NULL) {
 		/* the device was unplugged before the file was released */
-		up(&dev->sem);
+		mutex_unlock(&dev->mtx);
 		adu_delete(dev);
 		dev = NULL;
 	} else {
@@ -367,7 +371,7 @@
 
 exit:
 	if (dev)
-		up(&dev->sem);
+		mutex_unlock(&dev->mtx);
 	dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
 	return retval;
 }
@@ -390,7 +394,7 @@
 	dev = file->private_data;
 	dbg(2," %s : dev=%p", __FUNCTION__, dev);
 	/* lock this object */
-	if (down_interruptible(&dev->sem))
+	if (mutex_lock_interruptible(&dev->mtx))
 		return -ERESTARTSYS;
 
 	/* verify that the device wasn't unplugged */
@@ -522,7 +526,7 @@
 
 exit:
 	/* unlock the device */
-	up(&dev->sem);
+	mutex_unlock(&dev->mtx);
 
 	dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
 	return retval;
@@ -543,7 +547,7 @@
 	dev = file->private_data;
 
 	/* lock this object */
-	retval = down_interruptible(&dev->sem);
+	retval = mutex_lock_interruptible(&dev->mtx);
 	if (retval)
 		goto exit_nolock;
 
@@ -571,9 +575,9 @@
 				retval = -EINTR;
 				goto exit;
 			}
-			up(&dev->sem);
+			mutex_unlock(&dev->mtx);
 			timeout = interruptible_sleep_on_timeout(&dev->write_wait, timeout);
-			retval = down_interruptible(&dev->sem);
+			retval = mutex_lock_interruptible(&dev->mtx);
 			if (retval) {
 				retval = bytes_written ? bytes_written : retval;
 				goto exit_nolock;
@@ -638,7 +642,7 @@
 
 exit:
 	/* unlock the device */
-	up(&dev->sem);
+	mutex_unlock(&dev->mtx);
 exit_nolock:
 
 	dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
@@ -698,7 +702,7 @@
 		goto exit;
 	}
 
-	init_MUTEX(&dev->sem);
+	mutex_init(&dev->mtx);
 	spin_lock_init(&dev->buflock);
 	dev->udev = udev;
 	init_waitqueue_head(&dev->read_wait);
@@ -835,16 +839,16 @@
 	usb_deregister_dev(interface, &adu_class);
 	dev->minor = 0;
 
-	down(&dev->sem); /* not interruptible */
+	mutex_lock(&dev->mtx); /* not interruptible */
 
 	/* if the device is not opened, then we clean up right now */
 	dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
 	if (!dev->open_count) {
-		up(&dev->sem);
+		mutex_unlock(&dev->mtx);
 		adu_delete(dev);
 	} else {
 		dev->udev = NULL;
-		up(&dev->sem);
+		mutex_unlock(&dev->mtx);
 	}
 
 	dev_info(&interface->dev, "ADU device adutux%d now disconnected",
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index cf70c16..1cb56f2 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -88,9 +88,10 @@
 {
 	struct appledisplay *pdata = urb->context;
 	unsigned long flags;
+	int status = urb->status;
 	int retval;
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:
 		/* success */
 		break;
@@ -102,12 +103,12 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* This urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d",
-			__FUNCTION__, urb->status);
+		dbg("%s - urb shuttingdown with status: %d",
+			__FUNCTION__, status);
 		return;
 	default:
 		dbg("%s - nonzero urb status received: %d",
-			__FUNCTION__, urb->status);
+			__FUNCTION__, status);
 		goto exit;
 	}
 
@@ -137,7 +138,7 @@
 
 static int appledisplay_bl_update_status(struct backlight_device *bd)
 {
-	struct appledisplay *pdata = class_get_devdata(&bd->class_dev);
+	struct appledisplay *pdata = bl_get_data(bd);
 	int retval;
 
 	pdata->msgdata[0] = 0x10;
@@ -158,7 +159,7 @@
 
 static int appledisplay_bl_get_brightness(struct backlight_device *bd)
 {
-	struct appledisplay *pdata = class_get_devdata(&bd->class_dev);
+	struct appledisplay *pdata = bl_get_data(bd);
 	int retval;
 
 	retval = usb_control_msg(
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index 42d4e64..df7e1ec 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -862,14 +862,16 @@
         pauerbuf_t bp = (pauerbuf_t) urb->context;
         pauerswald_t cp;
 	int ret;
+	int status = urb->status;
+
         dbg ("auerswald_ctrlread_wretcomplete called");
-        dbg ("complete with status: %d", urb->status);
+        dbg ("complete with status: %d", status);
 	cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
 
 	/* check if it is possible to advance */
-	if (!auerswald_status_retry (urb->status) || !cp->usbdev) {
+	if (!auerswald_status_retry(status) || !cp->usbdev) {
 		/* reuse the buffer */
-		err ("control dummy: transmission error %d, can not retry", urb->status);
+		err ("control dummy: transmission error %d, can not retry", status);
 		auerbuf_releasebuf (bp);
 		/* Wake up all processes waiting for a buffer */
 		wake_up (&cp->bufferwait);
@@ -902,21 +904,23 @@
         pauerswald_t  cp;
         pauerscon_t   scp;
         pauerbuf_t    bp  = (pauerbuf_t) urb->context;
+	int status = urb->status;
 	int ret;
+
         dbg ("auerswald_ctrlread_complete called");
 
 	cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
 
 	/* check if there is valid data in this urb */
-        if (urb->status) {
-		dbg ("complete with non-zero status: %d", urb->status);
+        if (status) {
+		dbg ("complete with non-zero status: %d", status);
 		/* should we do a retry? */
-		if (!auerswald_status_retry (urb->status)
+		if (!auerswald_status_retry(status)
 		 || !cp->usbdev
 		 || (cp->version < AUV_RETRY)
                  || (bp->retries >= AU_RETRIES)) {
 			/* reuse the buffer */
-			err ("control read: transmission error %d, can not retry", urb->status);
+			err ("control read: transmission error %d, can not retry", status);
 			auerbuf_releasebuf (bp);
 			/* Wake up all processes waiting for a buffer */
 			wake_up (&cp->bufferwait);
@@ -974,12 +978,13 @@
         unsigned  int channelid;
         unsigned  int bytecount;
         int ret;
+	int status = urb->status;
         pauerbuf_t   bp = NULL;
         pauerswald_t cp = (pauerswald_t) urb->context;
 
         dbg ("%s called", __FUNCTION__);
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:
 		/* success */
 		break;
@@ -987,10 +992,10 @@
 	case -ENOENT:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+		dbg("%s - urb shutting down with status: %d", __FUNCTION__, status);
 		return;
 	default:
-		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+		dbg("%s - nonzero urb status received: %d", __FUNCTION__, status);
 		goto exit;
 	}
 
diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c
index 92c1d27..24e2dc3 100644
--- a/drivers/usb/misc/berry_charge.c
+++ b/drivers/usb/misc/berry_charge.c
@@ -71,7 +71,7 @@
 	if (retval != 2) {
 		dev_err(&udev->dev, "First magic command failed: %d.\n",
 			retval);
-		return retval;
+		goto exit;
 	}
 
 	dbg(&udev->dev, "Sending second magic command\n");
@@ -80,7 +80,7 @@
 	if (retval != 0) {
 		dev_err(&udev->dev, "Second magic command failed: %d.\n",
 			retval);
-		return retval;
+		goto exit;
 	}
 
 	dbg(&udev->dev, "Calling set_configuration\n");
@@ -88,6 +88,8 @@
 	if (retval)
 		dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
 
+exit:
+	kfree(dummy_buffer);
 	return retval;
 }
 
@@ -112,6 +114,7 @@
 	if (retval)
 		dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
 
+	kfree(dummy_buffer);
 	return retval;
 }
 
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index e0f122e..d3d8cd6 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -44,6 +44,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/kref.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 #include <linux/workqueue.h>
@@ -64,7 +65,7 @@
 * ftdi_module_lock exists to protect access to global variables
 *
 */
-static struct semaphore ftdi_module_lock;
+static struct mutex ftdi_module_lock;
 static int ftdi_instances = 0;
 static struct list_head ftdi_static_list;
 /*
@@ -199,10 +200,10 @@
         dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi);
         usb_put_dev(ftdi->udev);
         ftdi->disconnected += 1;
-        down(&ftdi_module_lock);
+        mutex_lock(&ftdi_module_lock);
         list_del_init(&ftdi->ftdi_list);
         ftdi_instances -= 1;
-        up(&ftdi_module_lock);
+        mutex_unlock(&ftdi_module_lock);
         kfree(ftdi->bulk_in_buffer);
         ftdi->bulk_in_buffer = NULL;
 }
@@ -746,10 +747,12 @@
 static void ftdi_elan_write_bulk_callback(struct urb *urb)
 {
         struct usb_ftdi *ftdi = (struct usb_ftdi *)urb->context;
-        if (urb->status && !(urb->status == -ENOENT || urb->status ==
-                -ECONNRESET || urb->status == -ESHUTDOWN)) {
+	int status = urb->status;
+
+	if (status && !(status == -ENOENT || status == -ECONNRESET ||
+	    status == -ESHUTDOWN)) {
                 dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %"
-                        "d\n", urb, urb->status);
+                        "d\n", urb, status);
         }
         usb_buffer_free(urb->dev, urb->transfer_buffer_length,
                 urb->transfer_buffer, urb->transfer_dma);
@@ -2774,16 +2777,18 @@
         size_t buffer_size;
         int i;
         int retval = -ENOMEM;
-        struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
-        if (ftdi == NULL) {
+        struct usb_ftdi *ftdi;
+
+	ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
+	if (!ftdi) {
                 printk(KERN_ERR "Out of memory\n");
                 return -ENOMEM;
         }
-        memset(ftdi, 0x00, sizeof(struct usb_ftdi));
-        down(&ftdi_module_lock);
+
+        mutex_lock(&ftdi_module_lock);
         list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
         ftdi->sequence_num = ++ftdi_instances;
-        up(&ftdi_module_lock);
+        mutex_unlock(&ftdi_module_lock);
         ftdi_elan_init_kref(ftdi);
         init_MUTEX(&ftdi->sw_lock);
         ftdi->udev = usb_get_dev(interface_to_usbdev(interface));
@@ -2909,7 +2914,7 @@
         int result;
         printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name,
 	       __TIME__, __DATE__);
-        init_MUTEX(&ftdi_module_lock);
+        mutex_init(&ftdi_module_lock);
         INIT_LIST_HEAD(&ftdi_static_list);
         status_queue = create_singlethread_workqueue("ftdi-status-control");
 	if (!status_queue)
diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index 28548d1..46d9f27 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -158,9 +158,10 @@
 	int read_idx;
 	int aux_idx;
 	int offset;
-	int status;
+	int status = urb->status;
+	int retval;
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:
 		/* success */
 		break;
@@ -213,10 +214,10 @@
 	wake_up_interruptible(&dev->read_wait);
 
 exit:
-	status = usb_submit_urb(urb, GFP_ATOMIC);
-	if (status)
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
 		dev_err(&dev->interface->dev, "%s - usb_submit_urb failed with result %d",
-			__FUNCTION__, status);
+			__FUNCTION__, retval);
 
 }
 
@@ -226,13 +227,15 @@
 static void iowarrior_write_callback(struct urb *urb)
 {
 	struct iowarrior *dev;
+	int status = urb->status;
+
 	dev = (struct iowarrior *)urb->context;
 	/* sync/async unlink faults aren't errors */
-	if (urb->status &&
-	    !(urb->status == -ENOENT ||
-	      urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) {
+	if (status &&
+	    !(status == -ENOENT ||
+	      status == -ECONNRESET || status == -ESHUTDOWN)) {
 		dbg("%s - nonzero write bulk status received: %d",
-		    __func__, urb->status);
+		    __func__, status);
 	}
 	/* free up our allocated buffer */
 	usb_buffer_free(urb->dev, urb->transfer_buffer_length,
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 5e950b9..8208496 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -219,16 +219,17 @@
 	struct ld_usb *dev = urb->context;
 	size_t *actual_buffer;
 	unsigned int next_ring_head;
+	int status = urb->status;
 	int retval;
 
-	if (urb->status) {
-		if (urb->status == -ENOENT ||
-		    urb->status == -ECONNRESET ||
-		    urb->status == -ESHUTDOWN) {
+	if (status) {
+		if (status == -ENOENT ||
+		    status == -ECONNRESET ||
+		    status == -ESHUTDOWN) {
 			goto exit;
 		} else {
 			dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
-				 __FUNCTION__, urb->status);
+				 __FUNCTION__, status);
 			spin_lock(&dev->rbsl);
 			goto resubmit; /* maybe we can recover */
 		}
@@ -275,14 +276,15 @@
 static void ld_usb_interrupt_out_callback(struct urb *urb)
 {
 	struct ld_usb *dev = urb->context;
+	int status = urb->status;
 
 	/* sync/async unlink faults aren't errors */
-	if (urb->status && !(urb->status == -ENOENT ||
-			     urb->status == -ECONNRESET ||
-			     urb->status == -ESHUTDOWN))
+	if (status && !(status == -ENOENT ||
+			status == -ECONNRESET ||
+			status == -ESHUTDOWN))
 		dbg_info(&dev->intf->dev,
 			 "%s - nonzero write interrupt status received: %d\n",
-			 __FUNCTION__, urb->status);
+			 __FUNCTION__, status);
 
 	dev->interrupt_out_busy = 0;
 	wake_up_interruptible(&dev->write_wait);
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 2ed0dae..561970b 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -742,19 +742,20 @@
 static void tower_interrupt_in_callback (struct urb *urb)
 {
 	struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+	int status = urb->status;
 	int retval;
 
-	dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
+	dbg(4, "%s: enter, status %d", __FUNCTION__, status);
 
 	lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
-	if (urb->status) {
-		if (urb->status == -ENOENT ||
-		    urb->status == -ECONNRESET ||
-		    urb->status == -ESHUTDOWN) {
+	if (status) {
+		if (status == -ENOENT ||
+		    status == -ECONNRESET ||
+		    status == -ESHUTDOWN) {
 			goto exit;
 		} else {
-			dbg(1, "%s: nonzero status received: %d", __FUNCTION__, urb->status);
+			dbg(1, "%s: nonzero status received: %d", __FUNCTION__, status);
 			goto resubmit; /* maybe we can recover */
 		}
 	}
@@ -788,7 +789,7 @@
 	wake_up_interruptible (&dev->read_wait);
 
 	lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
-	dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
+	dbg(4, "%s: leave, status %d", __FUNCTION__, status);
 }
 
 
@@ -798,23 +799,24 @@
 static void tower_interrupt_out_callback (struct urb *urb)
 {
 	struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
+	int status = urb->status;
 
-	dbg(4, "%s: enter, status %d", __FUNCTION__, urb->status);
+	dbg(4, "%s: enter, status %d", __FUNCTION__, status);
 	lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
 
 	/* sync/async unlink faults aren't errors */
-	if (urb->status && !(urb->status == -ENOENT ||
-			     urb->status == -ECONNRESET ||
-			     urb->status == -ESHUTDOWN)) {
+	if (status && !(status == -ENOENT ||
+			status == -ECONNRESET ||
+			status == -ESHUTDOWN)) {
 		dbg(1, "%s - nonzero write bulk status received: %d",
-		    __FUNCTION__, urb->status);
+		    __FUNCTION__, status);
 	}
 
 	dev->interrupt_out_busy = 0;
 	wake_up_interruptible(&dev->write_wait);
 
 	lego_usb_tower_debug_data(5, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
-	dbg(4, "%s: leave, status %d", __FUNCTION__, urb->status);
+	dbg(4, "%s: leave, status %d", __FUNCTION__, status);
 }
 
 
diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c
index 371bf2b..aa9bcce 100644
--- a/drivers/usb/misc/phidgetkit.c
+++ b/drivers/usb/misc/phidgetkit.c
@@ -305,9 +305,10 @@
 	struct interfacekit *kit = urb->context;
 	unsigned char *buffer = kit->data;
 	int i, level, sensor;
-	int status;
+	int retval;
+	int status = urb->status;
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:			/* success */
 		break;
 	case -ECONNRESET:	/* unlink */
@@ -377,11 +378,11 @@
 		schedule_delayed_work(&kit->do_notify, 0);
 
 resubmit:
-	status = usb_submit_urb(urb, GFP_ATOMIC);
-	if (status)
-		err("can't resubmit intr, %s-%s/interfacekit0, status %d",
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
+		err("can't resubmit intr, %s-%s/interfacekit0, retval %d",
 			kit->udev->bus->bus_name,
-			kit->udev->devpath, status);
+			kit->udev->devpath, retval);
 }
 
 static void do_notify(struct work_struct *work)
diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c
index 5727e1e..df0ebcd 100644
--- a/drivers/usb/misc/phidgetmotorcontrol.c
+++ b/drivers/usb/misc/phidgetmotorcontrol.c
@@ -95,9 +95,10 @@
 	struct motorcontrol *mc = urb->context;
 	unsigned char *buffer = mc->data;
 	int i, level;
-	int status;
+	int retval;
+	int status = urb->status;;
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:			/* success */
 		break;
 	case -ECONNRESET:	/* unlink */
@@ -151,12 +152,12 @@
 		schedule_delayed_work(&mc->do_notify, 0);
 
 resubmit:
-	status = usb_submit_urb(urb, GFP_ATOMIC);
-	if (status)
+	retval = usb_submit_urb(urb, GFP_ATOMIC);
+	if (retval)
 		dev_err(&mc->intf->dev,
-			"can't resubmit intr, %s-%s/motorcontrol0, status %d",
+			"can't resubmit intr, %s-%s/motorcontrol0, retval %d",
 			mc->udev->bus->bus_name,
-			mc->udev->devpath, status);
+			mc->udev->devpath, retval);
 }
 
 static void do_notify(struct work_struct *work)
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index 9f37ba4..9244d06 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -32,7 +32,7 @@
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
@@ -962,12 +962,12 @@
 			   packet.address = 0x00000194;
 			   packet.data    = addr;
 			   ret = sisusb_send_bridge_packet(sisusb, 10,
-			   					&packet, 0);
+								&packet, 0);
 			   packet.header  = 0x001f;
 			   packet.address = 0x00000190;
 			   packet.data    = (length & ~3);
 			   ret |= sisusb_send_bridge_packet(sisusb, 10,
-			   					&packet, 0);
+								&packet, 0);
 			   if (sisusb->flagb0 != 0x16) {
 				packet.header  = 0x001f;
 				packet.address = 0x00000180;
@@ -1003,23 +1003,17 @@
 			if (ret) {
 				msgcount++;
 				if (msgcount < 500)
-					printk(KERN_ERR
-						"sisusbvga[%d]: Wrote %zd of "
-						"%d bytes, error %d\n",
-						sisusb->minor, *bytes_written,
-						length, ret);
+					dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n",
+						*bytes_written, length, ret);
 				else if (msgcount == 500)
-					printk(KERN_ERR
-						"sisusbvga[%d]: Too many errors"
-						", logging stopped\n",
-						sisusb->minor);
+					dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n");
 			}
 			addr += (*bytes_written);
 			length -= (*bytes_written);
 	    }
 
 	    if (ret)
-	    	break;
+		break;
 
 	}
 
@@ -1261,51 +1255,10 @@
 				addr += 4;
 				length -= 4;
 			}
-#if 0		/* That does not work, as EP 2 is an OUT EP! */
-		default:
-			CLEARPACKET(&packet);
-			packet.header  = 0x001f;
-			packet.address = 0x000001a0;
-			packet.data    = 0x00000006;
-			ret |= sisusb_send_bridge_packet(sisusb, 10,
-								&packet, 0);
-			packet.header  = 0x001f;
-			packet.address = 0x000001b0;
-			packet.data    = (length & ~3) | 0x40000000;
-			ret |= sisusb_send_bridge_packet(sisusb, 10,
-								&packet, 0);
-			packet.header  = 0x001f;
-			packet.address = 0x000001b4;
-			packet.data    = addr;
-			ret |= sisusb_send_bridge_packet(sisusb, 10,
-								&packet, 0);
-			packet.header  = 0x001f;
-			packet.address = 0x000001a4;
-			packet.data    = 0x00000001;
-			ret |= sisusb_send_bridge_packet(sisusb, 10,
-								&packet, 0);
-			if (userbuffer) {
-				ret |= sisusb_recv_bulk_msg(sisusb,
-							SISUSB_EP_GFX_BULK_IN,
-							(length & ~3),
-							NULL, userbuffer,
-							bytes_read, 0);
-				if (!ret) userbuffer += (*bytes_read);
-			} else {
-				ret |= sisusb_recv_bulk_msg(sisusb,
-							SISUSB_EP_GFX_BULK_IN,
-							(length & ~3),
-							kernbuffer, NULL,
-							bytes_read, 0);
-				if (!ret) kernbuffer += (*bytes_read);
-			}
-			addr += (*bytes_read);
-			length -= (*bytes_read);
-#endif
 	    }
 
 	    if (ret)
-	    	break;
+		break;
 	}
 
 	return ret;
@@ -1401,22 +1354,6 @@
 	return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
 }
 
-#if 0
-
-int
-sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
-{
-	return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
-}
-
-int
-sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
-{
-	return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
-}
-
-#endif  /*  0  */
-
 int
 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
 			u32 dest, int length, size_t *bytes_written)
@@ -1446,10 +1383,10 @@
     sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
 
     for(i = 1; i <= 7; i++) {
-        printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
+        dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i);
 	sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
 	for(j = 0; j < i; j++) {
-	     printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
+	     dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]);
 	}
     }
 }
@@ -1533,9 +1470,9 @@
 #define SETIREGAND(r,i,a)	sisusb_setidxregand(sisusb, r, i, a)
 #define SETIREGANDOR(r,i,a,o)	sisusb_setidxregandor(sisusb, r, i, a, o)
 #define READL(a,d)	sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
-#define WRITEL(a,d) 	sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEL(a,d)	sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
 #define READB(a,d)	sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
-#define WRITEB(a,d) 	sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEB(a,d)	sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
 
 static int
 sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
@@ -2008,7 +1945,7 @@
 		SETIREG(SISSR, 0x26, 0x00);
 	}
 
-	SETIREG(SISCR, 0x34, 0x44);  	/* we just set std mode #44 */
+	SETIREG(SISCR, 0x34, 0x44);	/* we just set std mode #44 */
 
 	return ret;
 }
@@ -2168,17 +2105,12 @@
 		if (ramtype <= 1) {
 			ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
 			if (iret) {
-				printk(KERN_ERR "sisusbvga[%d]: RAM size "
-					"detection failed, "
-					"assuming 8MB video RAM\n",
-					sisusb->minor);
+				dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n");
 				ret |= SETIREG(SISSR,0x14,0x31);
 				/* TODO */
 			}
 		} else {
-			printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
-					"assuming 8MB video RAM\n",
-					sisusb->minor);
+			dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n");
 			ret |= SETIREG(SISSR,0x14,0x31);
 			/* *** TODO *** */
 		}
@@ -2249,8 +2181,7 @@
 		break;
 	}
 
-	printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
-			sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
+	dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1,
 			ramtypetext2[ramtype], bw);
 }
 
@@ -2509,11 +2440,8 @@
 	struct usb_interface *interface;
 	int subminor = iminor(inode);
 
-	if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
-		printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
-				subminor);
+	if (!(interface = usb_find_interface(&sisusb_driver, subminor)))
 		return -ENODEV;
-	}
 
 	if (!(sisusb = usb_get_intfdata(interface)))
 		return -ENODEV;
@@ -2534,18 +2462,12 @@
 		if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
 			if (sisusb_init_gfxdevice(sisusb, 0)) {
 				mutex_unlock(&sisusb->lock);
-				printk(KERN_ERR
-					"sisusbvga[%d]: Failed to initialize "
-					"device\n",
-					sisusb->minor);
+				dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n");
 				return -EIO;
 			}
 		} else {
 			mutex_unlock(&sisusb->lock);
-			printk(KERN_ERR
-				"sisusbvga[%d]: Device not attached to "
-				"USB 2.0 hub\n",
-				sisusb->minor);
+			dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n");
 			return -EIO;
 		}
 	}
@@ -2586,7 +2508,6 @@
 sisusb_release(struct inode *inode, struct file *file)
 {
 	struct sisusb_usb_data *sisusb;
-	int myminor;
 
 	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
 		return -ENODEV;
@@ -2599,8 +2520,6 @@
 			sisusb_kill_all_busy(sisusb);
 	}
 
-	myminor = sisusb->minor;
-
 	sisusb->isopen = 0;
 	file->private_data = NULL;
 
@@ -2942,7 +2861,7 @@
 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
 							unsigned long arg)
 {
-	int 	retval, port, length;
+	int	retval, port, length;
 	u32	address;
 
 	/* All our commands require the device
@@ -3065,12 +2984,12 @@
 
 static int
 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-	     						unsigned long arg)
+							unsigned long arg)
 {
 	struct sisusb_usb_data *sisusb;
 	struct sisusb_info x;
 	struct sisusb_command y;
-	int 	retval = 0;
+	int	retval = 0;
 	u32 __user *argp = (u32 __user *)arg;
 
 	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
@@ -3095,7 +3014,7 @@
 
 		case SISUSB_GET_CONFIG:
 
-			x.sisusb_id   	    = SISUSB_ID;
+			x.sisusb_id	    = SISUSB_ID;
 			x.sisusb_version    = SISUSB_VERSION;
 			x.sisusb_revision   = SISUSB_REVISION;
 			x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
@@ -3164,7 +3083,7 @@
 	.release =	sisusb_release,
 	.read =		sisusb_read,
 	.write =	sisusb_write,
-	.llseek = 	sisusb_lseek,
+	.llseek =	sisusb_lseek,
 #ifdef SISUSB_NEW_CONFIG_COMPAT
 	.compat_ioctl = sisusb_compat_ioctl,
 #endif
@@ -3183,17 +3102,13 @@
 	struct usb_device *dev = interface_to_usbdev(intf);
 	struct sisusb_usb_data *sisusb;
 	int retval = 0, i;
-	const char *memfail =
-		KERN_ERR
-		"sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
 
-	printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
+	dev_info(&dev->dev, "USB2VGA dongle found at address %d\n",
 		dev->devnum);
 
 	/* Allocate memory for our private */
 	if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
-		printk(KERN_ERR
-			"sisusb: Failed to allocate memory for private data\n");
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n");
 		return -ENOMEM;
 	}
 	kref_init(&sisusb->kref);
@@ -3202,8 +3117,7 @@
 
 	/* Register device */
 	if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
-		printk(KERN_ERR
-			"sisusb: Failed to get a minor for device %d\n",
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n",
 			dev->devnum);
 		retval = -ENODEV;
 		goto error_1;
@@ -3221,7 +3135,7 @@
 	sisusb->ibufsize = SISUSB_IBUF_SIZE;
 	if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
 					GFP_KERNEL, &sisusb->transfer_dma_in))) {
-		printk(memfail, "input", sisusb->minor);
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer");
 		retval = -ENOMEM;
 		goto error_2;
 	}
@@ -3233,7 +3147,7 @@
 					GFP_KERNEL,
 					&sisusb->transfer_dma_out[i]))) {
 			if (i == 0) {
-				printk(memfail, "output", sisusb->minor);
+				dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n");
 				retval = -ENOMEM;
 				goto error_3;
 			}
@@ -3245,9 +3159,7 @@
 
 	/* Allocate URBs */
 	if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
-		printk(KERN_ERR
-			"sisusbvga[%d]: Failed to allocate URBs\n",
-			sisusb->minor);
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
 		retval = -ENOMEM;
 		goto error_3;
 	}
@@ -3255,9 +3167,7 @@
 
 	for (i = 0; i < sisusb->numobufs; i++) {
 		if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
-			printk(KERN_ERR
-				"sisusbvga[%d]: Failed to allocate URBs\n",
-				sisusb->minor);
+			dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
 			retval = -ENOMEM;
 			goto error_4;
 		}
@@ -3266,15 +3176,12 @@
 		sisusb->urbstatus[i] = 0;
 	}
 
-	printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
-					sisusb->minor, sisusb->numobufs);
+	dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs);
 
 #ifdef INCL_SISUSB_CON
 	/* Allocate our SiS_Pr */
 	if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
-		printk(KERN_ERR
-			"sisusbvga[%d]: Failed to allocate SiS_Pr\n",
-			sisusb->minor);
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n");
 	}
 #endif
 
@@ -3296,10 +3203,7 @@
 	ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG,      NULL);
 	ret |= register_ioctl32_conversion(SISUSB_COMMAND,         NULL);
 	if (ret)
-		printk(KERN_ERR
-			"sisusbvga[%d]: Error registering ioctl32 "
-			"translations\n",
-			sisusb->minor);
+		dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n");
 	else
 		sisusb->ioctl32registered = 1;
 	}
@@ -3315,23 +3219,17 @@
 			initscreen = 0;
 #endif
 		if (sisusb_init_gfxdevice(sisusb, initscreen))
-			printk(KERN_ERR
-				"sisusbvga[%d]: Failed to early "
-				"initialize device\n",
-				sisusb->minor);
+			dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n");
 
 	} else
-		printk(KERN_INFO
-			"sisusbvga[%d]: Not attached to USB 2.0 hub, "
-			"deferring init\n",
-			sisusb->minor);
+		dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n");
 
 	sisusb->ready = 1;
 
 #ifdef SISUSBENDIANTEST
-	printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
+	dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n");
 	sisusb_testreadwrite(sisusb);
-	printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
+	dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n");
 #endif
 
 #ifdef INCL_SISUSB_CON
@@ -3354,7 +3252,6 @@
 static void sisusb_disconnect(struct usb_interface *intf)
 {
 	struct sisusb_usb_data *sisusb;
-	int minor;
 
 	/* This should *not* happen */
 	if (!(sisusb = usb_get_intfdata(intf)))
@@ -3364,8 +3261,6 @@
 	sisusb_console_exit(sisusb);
 #endif
 
-	minor = sisusb->minor;
-
 	usb_deregister_dev(intf, &usb_sisusb_class);
 
 	mutex_lock(&sisusb->lock);
@@ -3384,10 +3279,7 @@
 		ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
 		ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
 		if (ret) {
-			printk(KERN_ERR
-				"sisusbvga[%d]: Error unregistering "
-				"ioctl32 translations\n",
-				minor);
+			dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n");
 		}
 	}
 #endif
@@ -3400,10 +3292,11 @@
 	/* decrement our usage count */
 	kref_put(&sisusb->kref, sisusb_delete);
 
-	printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
+	dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n");
 }
 
 static struct usb_device_id sisusb_table [] = {
+	{ USB_DEVICE(0x0711, 0x0550) },
 	{ USB_DEVICE(0x0711, 0x0900) },
 	{ USB_DEVICE(0x0711, 0x0901) },
 	{ USB_DEVICE(0x0711, 0x0902) },
@@ -3423,22 +3316,12 @@
 
 static int __init usb_sisusb_init(void)
 {
-	int retval;
 
 #ifdef INCL_SISUSB_CON
 	sisusb_init_concode();
 #endif
 
-	if (!(retval = usb_register(&sisusb_driver))) {
-
-		printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
-			SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
-		printk(KERN_INFO
-			"sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
-
-	}
-
-	return retval;
+	return usb_register(&sisusb_driver);
 }
 
 static void __exit usb_sisusb_exit(void)
diff --git a/drivers/usb/misc/sisusbvga/sisusb.h b/drivers/usb/misc/sisusbvga/sisusb.h
index 8e1120a..d2d7872 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.h
+++ b/drivers/usb/misc/sisusbvga/sisusb.h
@@ -8,29 +8,29 @@
  *
  * Otherwise, the following license terms apply:
  *
- * * Redistribution and use in source and binary forms, with or without
- * * modification, are permitted provided that the following conditions
- * * are met:
- * * 1) Redistributions of source code must retain the above copyright
- * *    notice, this list of conditions and the following disclaimer.
- * * 2) Redistributions in binary form must reproduce the above copyright
- * *    notice, this list of conditions and the following disclaimer in the
- * *    documentation and/or other materials provided with the distribution.
- * * 3) The name of the author may not be used to endorse or promote products
- * *    derived from this software without specific prior written permission.
- * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
- * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1) Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2) Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3) The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
  *
- * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
@@ -44,16 +44,14 @@
 #include <linux/mutex.h>
 
 /* For older kernels, support for text consoles is by default
- * off. To ensable text console support, change the following:
+ * off. To enable text console support, change the following:
  */
-#if 0
-#define CONFIG_USB_SISUSBVGA_CON
-#endif
+/* #define CONFIG_USB_SISUSBVGA_CON */
 
 /* Version Information */
 
 #define SISUSB_VERSION		0
-#define SISUSB_REVISION 	0
+#define SISUSB_REVISION		0
 #define SISUSB_PATCHLEVEL	8
 
 /* Include console and mode switching code? */
@@ -74,7 +72,7 @@
 #define SISUSB_IBUF_SIZE  0x01000
 #define SISUSB_OBUF_SIZE  0x10000	/* fixed */
 
-#define NUMOBUFS 8			/* max number of output buffers/output URBs */
+#define NUMOBUFS 8		/* max number of output buffers/output URBs */
 
 /* About endianness:
  *
@@ -93,7 +91,7 @@
  */
 
 #ifdef __BIG_ENDIAN
-#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) 		\
+#define SISUSB_CORRECT_ENDIANNESS_PACKET(p)		\
 	do {						\
 		p->header  = cpu_to_le16(p->header);	\
 		p->address = cpu_to_le32(p->address);	\
@@ -105,7 +103,7 @@
 
 struct sisusb_usb_data;
 
-struct sisusb_urb_context {		/* urb->context for outbound bulk URBs */
+struct sisusb_urb_context {	/* urb->context for outbound bulk URBs */
 	struct sisusb_usb_data *sisusb;
 	int urbindex;
 	int *actual_length;
@@ -116,16 +114,16 @@
 	struct usb_interface *interface;
 	struct kref kref;
 	wait_queue_head_t wait_q;	/* for syncind and timeouts */
-	struct mutex lock;		/* general race avoidance */
-	unsigned int ifnum;		/* interface number of the USB device */
-	int minor;			/* minor (for logging clarity) */
-	int isopen;			/* !=0 if open */
-	int present;			/* !=0 if device is present on the bus */
-	int ready;			/* !=0 if device is ready for userland */
+	struct mutex lock;	/* general race avoidance */
+	unsigned int ifnum;	/* interface number of the USB device */
+	int minor;		/* minor (for logging clarity) */
+	int isopen;		/* !=0 if open */
+	int present;		/* !=0 if device is present on the bus */
+	int ready;		/* !=0 if device is ready for userland */
 #ifdef SISUSB_OLD_CONFIG_COMPAT
 	int ioctl32registered;
 #endif
-	int numobufs;			/* number of obufs = number of out urbs */
+	int numobufs;		/* number of obufs = number of out urbs */
 	char *obuf[NUMOBUFS], *ibuf;	/* transfer buffers */
 	int obufsize, ibufsize;
 	dma_addr_t transfer_dma_out[NUMOBUFS];
@@ -136,13 +134,13 @@
 	unsigned char completein;
 	struct sisusb_urb_context urbout_context[NUMOBUFS];
 	unsigned long flagb0;
-	unsigned long vrambase;		/* framebuffer base */
-	unsigned int vramsize;		/* framebuffer size (bytes) */
+	unsigned long vrambase;	/* framebuffer base */
+	unsigned int vramsize;	/* framebuffer size (bytes) */
 	unsigned long mmiobase;
 	unsigned int mmiosize;
 	unsigned long ioportbase;
-	unsigned char devinit;		/* device initialized? */
-	unsigned char gfxinit;		/* graphics core initialized? */
+	unsigned char devinit;	/* device initialized? */
+	unsigned char gfxinit;	/* graphics core initialized? */
 	unsigned short chipid, chipvendor;
 	unsigned short chiprevision;
 #ifdef INCL_SISUSB_CON
@@ -152,7 +150,7 @@
 	int haveconsole, con_first, con_last;
 	int havethisconsole[MAX_NR_CONSOLES];
 	int textmodedestroyed;
-	unsigned int sisusb_num_columns; /* real number, not vt's idea */
+	unsigned int sisusb_num_columns;	/* real number, not vt's idea */
 	int cur_start_addr, con_rolled_over;
 	int sisusb_cursor_loc, bad_cursor_pos;
 	int sisusb_cursor_size_from;
@@ -197,7 +195,7 @@
 	unsigned short header;
 	u32 address;
 	u32 data;
-} __attribute__((__packed__));
+} __attribute__ ((__packed__));
 
 #define CLEARPACKET(packet) memset(packet, 0, 10)
 
@@ -265,36 +263,36 @@
 
 /* Structure argument for SISUSB_GET_INFO ioctl  */
 struct sisusb_info {
-	__u32	sisusb_id;		/* for identifying sisusb */
-#define SISUSB_ID  0x53495355		/* Identify myself with 'SISU' */
-	__u8	sisusb_version;
-	__u8	sisusb_revision;
-	__u8	sisusb_patchlevel;
-	__u8	sisusb_gfxinit;		/* graphics core initialized? */
+	__u32 sisusb_id;	/* for identifying sisusb */
+#define SISUSB_ID  0x53495355	/* Identify myself with 'SISU' */
+	__u8 sisusb_version;
+	__u8 sisusb_revision;
+	__u8 sisusb_patchlevel;
+	__u8 sisusb_gfxinit;	/* graphics core initialized? */
 
-	__u32	sisusb_vrambase;
-	__u32	sisusb_mmiobase;
-	__u32	sisusb_iobase;
-	__u32	sisusb_pcibase;
+	__u32 sisusb_vrambase;
+	__u32 sisusb_mmiobase;
+	__u32 sisusb_iobase;
+	__u32 sisusb_pcibase;
 
-	__u32	sisusb_vramsize;	/* framebuffer size in bytes */
+	__u32 sisusb_vramsize;	/* framebuffer size in bytes */
 
-	__u32	sisusb_minor;
+	__u32 sisusb_minor;
 
-	__u32   sisusb_fbdevactive;	/* != 0 if framebuffer device active */
+	__u32 sisusb_fbdevactive;	/* != 0 if framebuffer device active */
 
-	__u32   sisusb_conactive;	/* != 0 if console driver active */
+	__u32 sisusb_conactive;	/* != 0 if console driver active */
 
-	__u8	sisusb_reserved[28];	/* for future use */
+	__u8 sisusb_reserved[28];	/* for future use */
 };
 
 struct sisusb_command {
-	__u8   operation;	/* see below */
-	__u8   data0;		/* operation dependent */
-	__u8   data1;		/* operation dependent */
-	__u8   data2;		/* operation dependent */
-	__u32  data3;		/* operation dependent */
-	__u32  data4;		/* for future use */
+	__u8 operation;		/* see below */
+	__u8 data0;		/* operation dependent */
+	__u8 data1;		/* operation dependent */
+	__u8 data2;		/* operation dependent */
+	__u32 data3;		/* operation dependent */
+	__u32 data4;		/* for future use */
 };
 
 #define SUCMD_GET	0x01	/* for all: data0 = index, data3 = port */
@@ -306,7 +304,7 @@
 
 #define SUCMD_CLRSCR	0x07	/* data0:1:2 = length, data3 = address */
 
-#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */
+#define SUCMD_HANDLETEXTMODE 0x08	/* Reset/destroy text mode */
 
 #define SUCMD_SETMODE	0x09	/* Set a display mode (data3 = SiS mode) */
 #define SUCMD_SETVESAMODE 0x0a	/* Set a display mode (data3 = VESA mode) */
@@ -315,6 +313,4 @@
 #define SISUSB_GET_CONFIG_SIZE	_IOR(0xF3,0x3E,__u32)
 #define SISUSB_GET_CONFIG	_IOR(0xF3,0x3F,struct sisusb_info)
 
-
 #endif /* SISUSB_H */
-
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index 8d0edc8..43722e5 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -52,6 +52,7 @@
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/fs.h>
+#include <linux/usb.h>
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/string.h>
@@ -373,14 +374,6 @@
 		return;
 
 	/* sisusb->lock is down */
-
-	/* Don't need to put the character into buffer ourselves,
-	 * because the vt does this BEFORE calling us.
-	 */
-#if 0
-	sisusbcon_writew(ch, SISUSB_VADDR(x, y));
-#endif
-
 	if (sisusb_is_inactive(c, sisusb)) {
 		mutex_unlock(&sisusb->lock);
 		return;
@@ -490,10 +483,6 @@
 	struct sisusb_usb_data *sisusb;
 	ssize_t written;
 	int cols, length;
-#if 0
-	u16 *src, *dest;
-	int i;
-#endif
 
 	if (width <= 0 || height <= 0)
 		return;
@@ -505,41 +494,6 @@
 
 	cols = sisusb->sisusb_num_columns;
 
-	/* Don't need to move data outselves, because
-	 * vt does this BEFORE calling us.
-	 * This is only used by vt's insert/deletechar.
-	 */
-#if 0
-	if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) {
-
-		sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy),
-					height * width * 2);
-
-	} else if (dy < sy || (dy == sy && dx < sx)) {
-
-		src  = SISUSB_VADDR(sx, sy);
-		dest = SISUSB_VADDR(dx, dy);
-
-		for (i = height; i > 0; i--) {
-			sisusbcon_memmovew(dest, src, width * 2);
-			src  += cols;
-			dest += cols;
-		}
-
-	} else {
-
-		src  = SISUSB_VADDR(sx, sy + height - 1);
-		dest = SISUSB_VADDR(dx, dy + height - 1);
-
-		for (i = height; i > 0; i--) {
-			sisusbcon_memmovew(dest, src, width * 2);
-			src  -= cols;
-			dest -= cols;
-		}
-
-	}
-#endif
-
 	if (sisusb_is_inactive(c, sisusb)) {
 		mutex_unlock(&sisusb->lock);
 		return;
@@ -584,7 +538,7 @@
 	 */
 	if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
 		mutex_unlock(&sisusb->lock);
-		printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n");
+		dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n");
 		return 0;
 	}
 
@@ -1475,7 +1429,7 @@
 int
 sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
 {
-	int i, ret, minor = sisusb->minor;
+	int i, ret;
 
 	mutex_lock(&sisusb->lock);
 
@@ -1508,9 +1462,7 @@
 	/* Set up text mode (and upload  default font) */
 	if (sisusb_reset_text_mode(sisusb, 1)) {
 		mutex_unlock(&sisusb->lock);
-		printk(KERN_ERR
-			"sisusbvga[%d]: Failed to set up text mode\n",
-			minor);
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n");
 		return 1;
 	}
 
@@ -1531,9 +1483,7 @@
 	/* Allocate screen buffer */
 	if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
 		mutex_unlock(&sisusb->lock);
-		printk(KERN_ERR
-			"sisusbvga[%d]: Failed to allocate screen buffer\n",
-			minor);
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n");
 		return 1;
 	}
 
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c
index 9b30f89..273de5d 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_init.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.c
@@ -32,7 +32,7 @@
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
@@ -55,131 +55,39 @@
 /*         POINTER INITIALIZATION            */
 /*********************************************/
 
-static void
-SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
+static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
 {
-	SiS_Pr->SiS_ModeResInfo   = SiSUSB_ModeResInfo;
-	SiS_Pr->SiS_StandTable    = SiSUSB_StandTable;
+	SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo;
+	SiS_Pr->SiS_StandTable = SiSUSB_StandTable;
 
-	SiS_Pr->SiS_SModeIDTable  = SiSUSB_SModeIDTable;
-	SiS_Pr->SiS_EModeIDTable  = SiSUSB_EModeIDTable;
-	SiS_Pr->SiS_RefIndex      = SiSUSB_RefIndex;
-	SiS_Pr->SiS_CRT1Table     = SiSUSB_CRT1Table;
+	SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable;
+	SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable;
+	SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex;
+	SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table;
 
-	SiS_Pr->SiS_VCLKData      = SiSUSB_VCLKData;
+	SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData;
 }
 
 /*********************************************/
-/*            HELPER: Get ModeID             */
-/*********************************************/
-
-#if 0
-unsigned short
-SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
-{
-	unsigned short ModeIndex = 0;
-
-	switch (HDisplay)
-	{
-		case 320:
-			if (VDisplay == 200)
-				ModeIndex = ModeIndex_320x200[Depth];
-			else if (VDisplay == 240)
-				ModeIndex = ModeIndex_320x240[Depth];
-			break;
-		case 400:
-			if (VDisplay == 300)
-				ModeIndex = ModeIndex_400x300[Depth];
-			break;
-		case 512:
-			if (VDisplay == 384)
-				ModeIndex = ModeIndex_512x384[Depth];
-			break;
-		case 640:
-			if (VDisplay == 480)
-				ModeIndex = ModeIndex_640x480[Depth];
-			else if (VDisplay == 400)
-				ModeIndex = ModeIndex_640x400[Depth];
-			break;
-		case 720:
-			if (VDisplay == 480)
-				ModeIndex = ModeIndex_720x480[Depth];
-			else if (VDisplay == 576)
-				ModeIndex = ModeIndex_720x576[Depth];
-			break;
-		case 768:
-			if (VDisplay == 576)
-				ModeIndex = ModeIndex_768x576[Depth];
-			break;
-		case 800:
-			if (VDisplay == 600)
-				ModeIndex = ModeIndex_800x600[Depth];
-			else if (VDisplay == 480)
-				ModeIndex = ModeIndex_800x480[Depth];
-			break;
-		case 848:
-			if (VDisplay == 480)
-				ModeIndex = ModeIndex_848x480[Depth];
-			break;
-		case 856:
-			if (VDisplay == 480)
-				ModeIndex = ModeIndex_856x480[Depth];
-			break;
-		case 960:
-			if (VDisplay == 540)
-				ModeIndex = ModeIndex_960x540[Depth];
-			else if (VDisplay == 600)
-				ModeIndex = ModeIndex_960x600[Depth];
-			break;
-		case 1024:
-			if (VDisplay == 576)
-				ModeIndex = ModeIndex_1024x576[Depth];
-			else if (VDisplay == 768)
-				ModeIndex = ModeIndex_1024x768[Depth];
-			break;
-		case 1152:
-			if (VDisplay == 864)
-				ModeIndex = ModeIndex_1152x864[Depth];
-			break;
-		case 1280:
-			switch (VDisplay) {
-				case 720:
-					ModeIndex = ModeIndex_1280x720[Depth];
-					break;
-				case 768:
-					ModeIndex = ModeIndex_1280x768[Depth];
-					break;
-				case 1024:
-					ModeIndex = ModeIndex_1280x1024[Depth];
-					break;
-			}
-	}
-
-	return ModeIndex;
-}
-#endif  /*  0  */
-
-/*********************************************/
 /*          HELPER: SetReg, GetReg           */
 /*********************************************/
 
 static void
 SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port,
-			unsigned short index, unsigned short data)
+	   unsigned short index, unsigned short data)
 {
 	sisusb_setidxreg(SiS_Pr->sisusb, port, index, data);
 }
 
 static void
 SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port,
-						unsigned short data)
+	       unsigned short data)
 {
 	sisusb_setreg(SiS_Pr->sisusb, port, data);
 }
 
 static unsigned char
-SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port,
-						unsigned short index)
+SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index)
 {
 	u8 data;
 
@@ -200,22 +108,22 @@
 
 static void
 SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port,
-			unsigned short index, unsigned short DataAND,
-						unsigned short DataOR)
+		unsigned short index, unsigned short DataAND,
+		unsigned short DataOR)
 {
 	sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR);
 }
 
 static void
 SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port,
-			unsigned short index, unsigned short DataAND)
+	      unsigned short index, unsigned short DataAND)
 {
 	sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND);
 }
 
 static void
-SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
-			unsigned short index, unsigned short DataOR)
+SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port,
+	     unsigned short index, unsigned short DataOR)
 {
 	sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR);
 }
@@ -224,8 +132,7 @@
 /*      HELPER: DisplayOn, DisplayOff        */
 /*********************************************/
 
-static void
-SiS_DisplayOn(struct SiS_Private *SiS_Pr)
+static void SiS_DisplayOn(struct SiS_Private *SiS_Pr)
 {
 	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF);
 }
@@ -234,8 +141,7 @@
 /*        HELPER: Init Port Addresses        */
 /*********************************************/
 
-static void
-SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
+static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
 {
 	SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
 	SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
@@ -258,8 +164,7 @@
 /*             HELPER: GetSysFlags           */
 /*********************************************/
 
-static void
-SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
+static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
 {
 	SiS_Pr->SiS_MyCR63 = 0x63;
 }
@@ -268,8 +173,7 @@
 /*         HELPER: Init PCI & Engines        */
 /*********************************************/
 
-static void
-SiSInitPCIetc(struct SiS_Private *SiS_Pr)
+static void SiSInitPCIetc(struct SiS_Private *SiS_Pr)
 {
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1);
 	/*  - Enable 2D (0x40)
@@ -285,8 +189,7 @@
 /*        HELPER: SET SEGMENT REGISTERS      */
 /*********************************************/
 
-static void
-SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
 {
 	unsigned short temp;
 
@@ -299,8 +202,7 @@
 	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
 }
 
-static void
-SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
 {
 	unsigned short temp;
 
@@ -313,15 +215,13 @@
 	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
 }
 
-static void
-SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
 {
 	SiS_SetSegRegLower(SiS_Pr, value);
 	SiS_SetSegRegUpper(SiS_Pr, value);
 }
 
-static void
-SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
 {
 	SiS_SetSegmentReg(SiS_Pr, 0);
 }
@@ -337,14 +237,12 @@
 	SiS_SetSegmentReg(SiS_Pr, value);
 }
 
-static void
-SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
 {
 	SiS_SetSegmentRegOver(SiS_Pr, 0);
 }
 
-static void
-SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
 {
 	SiS_ResetSegmentReg(SiS_Pr);
 	SiS_ResetSegmentRegOver(SiS_Pr);
@@ -356,7 +254,7 @@
 
 static int
 SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
-						unsigned short *ModeIdIndex)
+		 unsigned short *ModeIdIndex)
 {
 	if ((*ModeNo) <= 0x13) {
 
@@ -367,12 +265,14 @@
 
 	} else {
 
-		for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) {
+		for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
 
-			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo))
+			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+			    (*ModeNo))
 				break;
 
-			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)
+			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+			    0xFF)
 				return 0;
 		}
 
@@ -385,8 +285,7 @@
 /*            HELPER: ENABLE CRT1            */
 /*********************************************/
 
-static void
-SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
+static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
 {
 	/* Enable CRT1 gating */
 	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf);
@@ -398,9 +297,9 @@
 
 static unsigned short
 SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-		unsigned short ModeIdIndex)
+		  unsigned short ModeIdIndex)
 {
-	static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8};
+	static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 };
 	unsigned short modeflag;
 	short index;
 
@@ -411,7 +310,8 @@
 	}
 
 	index = (modeflag & ModeTypeMask) - ModeEGA;
-	if (index < 0) index = 0;
+	if (index < 0)
+		index = 0;
 	return ColorDepth[index];
 }
 
@@ -421,7 +321,7 @@
 
 static unsigned short
 SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-		unsigned short ModeIdIndex, unsigned short rrti)
+	      unsigned short ModeIdIndex, unsigned short rrti)
 {
 	unsigned short xres, temp, colordepth, infoflag;
 
@@ -458,8 +358,8 @@
 	SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20;
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata);
 
-	for(i = 2; i <= 4; i++) {
-		SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1];
+	for (i = 2; i <= 4; i++) {
+		SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1];
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata);
 	}
 }
@@ -488,7 +388,7 @@
 
 	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
 
-	for(i = 0; i <= 0x18; i++) {
+	for (i = 0; i <= 0x18; i++) {
 		CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata);
 	}
@@ -504,7 +404,7 @@
 	unsigned char ARdata;
 	unsigned short i;
 
-	for(i = 0; i <= 0x13; i++) {
+	for (i = 0; i <= 0x13; i++) {
 		ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
 		SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
 		SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i);
@@ -529,7 +429,7 @@
 	unsigned char GRdata;
 	unsigned short i;
 
-	for(i = 0; i <= 0x08; i++) {
+	for (i = 0; i <= 0x08; i++) {
 		GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata);
 	}
@@ -544,12 +444,11 @@
 /*          CLEAR EXTENDED REGISTERS         */
 /*********************************************/
 
-static void
-SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 {
 	int i;
 
-	for(i = 0x0A; i <= 0x0E; i++) {
+	for (i = 0x0A; i <= 0x0E; i++) {
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00);
 	}
 
@@ -562,15 +461,16 @@
 
 static unsigned short
 SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-					unsigned short ModeIdIndex)
+	       unsigned short ModeIdIndex)
 {
 	unsigned short rrti, i, index, temp;
 
 	if (ModeNo <= 0x13)
 		return 0xFFFF;
 
-	index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
-	if (index > 0) index--;
+	index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
+	if (index > 0)
+		index--;
 
 	rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
 	ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID;
@@ -580,13 +480,14 @@
 		if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo)
 			break;
 
-		temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
+		temp =
+		    SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
 		if (temp < SiS_Pr->SiS_ModeType)
 			break;
 
 		i++;
 		index--;
-	} while(index != 0xFFFF);
+	} while (index != 0xFFFF);
 
 	i--;
 
@@ -597,8 +498,7 @@
 /*                  SYNC                     */
 /*********************************************/
 
-static void
-SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
+static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
 {
 	unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8;
 	sync &= 0xC0;
@@ -612,39 +512,40 @@
 
 static void
 SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-			unsigned short ModeIdIndex, unsigned short rrti)
+		unsigned short ModeIdIndex, unsigned short rrti)
 {
-	unsigned char  index;
+	unsigned char index;
 	unsigned short temp, i, j, modeflag;
 
-	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f);
+	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
 
 	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
 	index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC;
 
-	for(i = 0,j = 0; i <= 7; i++, j++) {
+	for (i = 0, j = 0; i <= 7; i++, j++) {
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
-				SiS_Pr->SiS_CRT1Table[index].CR[i]);
+			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
 	}
-	for(j = 0x10; i <= 10; i++, j++) {
+	for (j = 0x10; i <= 10; i++, j++) {
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
-				SiS_Pr->SiS_CRT1Table[index].CR[i]);
+			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
 	}
-	for(j = 0x15; i <= 12; i++, j++) {
+	for (j = 0x15; i <= 12; i++, j++) {
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
-				SiS_Pr->SiS_CRT1Table[index].CR[i]);
+			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
 	}
-	for(j = 0x0A; i <= 15; i++, j++) {
+	for (j = 0x0A; i <= 15; i++, j++) {
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j,
-				SiS_Pr->SiS_CRT1Table[index].CR[i]);
+			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
 	}
 
 	temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
-	SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp);
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp);
 
 	temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
-	if (modeflag & DoubleScanMode)  temp |= 0x80;
+	if (modeflag & DoubleScanMode)
+		temp |= 0x80;
 	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp);
 
 	if (SiS_Pr->SiS_ModeType > ModeVGA)
@@ -659,10 +560,10 @@
 
 static void
 SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-			unsigned short ModeIdIndex, unsigned short rrti)
+		  unsigned short ModeIdIndex, unsigned short rrti)
 {
 	unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
-	unsigned short infoflag =  SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
+	unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
 	unsigned short temp;
 
 	temp = (du >> 8) & 0x0f;
@@ -670,11 +571,13 @@
 
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF));
 
-	if (infoflag & InterlaceMode) du >>= 1;
+	if (infoflag & InterlaceMode)
+		du >>= 1;
 
 	du <<= 5;
 	temp = (du >> 8) & 0xff;
-	if (du & 0xff) temp++;
+	if (du & 0xff)
+		temp++;
 	temp++;
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp);
 }
@@ -685,17 +588,17 @@
 
 static void
 SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-						unsigned short rrti)
+		unsigned short rrti)
 {
 	unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
 	unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B;
 	unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
 
-	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF);
+	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF);
 
-	SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka);
-	SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb);
-	SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01);
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka);
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb);
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01);
 }
 
 /*********************************************/
@@ -704,7 +607,7 @@
 
 static void
 SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-							unsigned short mi)
+		    unsigned short mi)
 {
 	unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
 
@@ -729,7 +632,7 @@
 
 static void
 SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-							unsigned short rrti)
+		 unsigned short rrti)
 {
 	unsigned short data = 0, VCLK = 0, index = 0;
 
@@ -738,7 +641,8 @@
 		VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
 	}
 
-	if (VCLK >= 166) data |= 0x0c;
+	if (VCLK >= 166)
+		data |= 0x0c;
 	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data);
 
 	if (VCLK >= 166)
@@ -758,7 +662,7 @@
 
 static void
 SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-			unsigned short ModeIdIndex, unsigned short rrti)
+		    unsigned short ModeIdIndex, unsigned short rrti)
 {
 	unsigned short data, infoflag = 0, modeflag;
 
@@ -778,17 +682,22 @@
 			data |= 0x02;
 			data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
 		}
-		if (infoflag & InterlaceMode) data |= 0x20;
+		if (infoflag & InterlaceMode)
+			data |= 0x20;
 	}
 	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data);
 
 	data = 0;
 	if (infoflag & InterlaceMode) {
 		/* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */
-		unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
-			((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3;
-		unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
-			((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5;
+		unsigned short hrs =
+		    (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
+		     ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2))
+		    - 3;
+		unsigned short hto =
+		    (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
+		     ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8))
+		    + 5;
 		data = hrs - (hto >> 1) + 3;
 	}
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF));
@@ -829,20 +738,26 @@
 
 static void
 SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
-		unsigned short shiftflag, unsigned short dl, unsigned short ah,
-		unsigned short al, unsigned short dh)
+	     unsigned short shiftflag, unsigned short dl, unsigned short ah,
+	     unsigned short al, unsigned short dh)
 {
 	unsigned short d1, d2, d3;
 
 	switch (dl) {
-		case  0:
-			d1 = dh; d2 = ah; d3 = al;
-			break;
-		case  1:
-			d1 = ah; d2 = al; d3 = dh;
-			break;
-		default:
-			d1 = al; d2 = dh; d3 = ah;
+	case 0:
+		d1 = dh;
+		d2 = ah;
+		d3 = al;
+		break;
+	case 1:
+		d1 = ah;
+		d2 = al;
+		d3 = dh;
+		break;
+	default:
+		d1 = al;
+		d2 = dh;
+		d3 = ah;
 	}
 	SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag));
 	SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag));
@@ -850,7 +765,8 @@
 }
 
 static void
-SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi)
+SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+	    unsigned short mi)
 {
 	unsigned short data, data2, time, i, j, k, m, n, o;
 	unsigned short si, di, bx, sf;
@@ -884,41 +800,45 @@
 
 	SiS_SetRegByte(SiS_Pr, DACAddr, 0x00);
 
-	for(i = 0; i < j; i++) {
+	for (i = 0; i < j; i++) {
 		data = table[i];
-		for(k = 0; k < 3; k++) {
+		for (k = 0; k < 3; k++) {
 			data2 = 0;
-			if (data & 0x01) data2 += 0x2A;
-			if (data & 0x02) data2 += 0x15;
+			if (data & 0x01)
+				data2 += 0x2A;
+			if (data & 0x02)
+				data2 += 0x15;
 			SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf));
 			data >>= 2;
 		}
 	}
 
 	if (time == 256) {
-		for(i = 16; i < 32; i++) {
+		for (i = 16; i < 32; i++) {
 			data = table[i] << sf;
-			for(k = 0; k < 3; k++)
+			for (k = 0; k < 3; k++)
 				SiS_SetRegByte(SiS_Pr, DACData, data);
 		}
 		si = 32;
-		for(m = 0; m < 9; m++) {
+		for (m = 0; m < 9; m++) {
 			di = si;
 			bx = si + 4;
-			for(n = 0; n < 3; n++) {
-				for(o = 0; o < 5; o++) {
+			for (n = 0; n < 3; n++) {
+				for (o = 0; o < 5; o++) {
 					SiS_WriteDAC(SiS_Pr, DACData, sf, n,
-						table[di], table[bx], table[si]);
+						     table[di], table[bx],
+						     table[si]);
 					si++;
 				}
 				si -= 2;
-				for(o = 0; o < 3; o++) {
+				for (o = 0; o < 3; o++) {
 					SiS_WriteDAC(SiS_Pr, DACData, sf, n,
-						table[di], table[si], table[bx]);
+						     table[di], table[si],
+						     table[bx]);
 					si--;
 				}
 			}
-		si += 5;
+			si += 5;
 		}
 	}
 }
@@ -929,7 +849,7 @@
 
 static void
 SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-					unsigned short ModeIdIndex)
+		 unsigned short ModeIdIndex)
 {
 	unsigned short StandTableIndex, rrti;
 
@@ -970,11 +890,10 @@
 /*                 SiSSetMode()              */
 /*********************************************/
 
-int
-SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 {
 	unsigned short ModeIdIndex;
-	unsigned long  BaseAddr = SiS_Pr->IOAddress;
+	unsigned long BaseAddr = SiS_Pr->IOAddress;
 
 	SiSUSB_InitPtr(SiS_Pr);
 	SiSUSBRegInit(SiS_Pr, BaseAddr);
@@ -990,7 +909,7 @@
 	ModeNo &= 0x7f;
 
 	SiS_Pr->SiS_ModeType =
-		SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
+	    SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
 
 	SiS_Pr->SiS_SetFlag = LowModeTests;
 
@@ -1008,8 +927,7 @@
 	return 1;
 }
 
-int
-SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
+int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
 {
 	unsigned short ModeNo = 0;
 	int i;
@@ -1041,7 +959,3 @@
 }
 
 #endif /* INCL_SISUSB_CON */
-
-
-
-
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.h b/drivers/usb/misc/sisusbvga/sisusb_init.h
index 864bc0e..c46ce42 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_init.h
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.h
@@ -46,7 +46,7 @@
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
@@ -76,21 +76,21 @@
 #define CRT2Mode		0x0800
 #define HalfDCLK		0x1000
 #define NoSupportSimuTV		0x2000
-#define NoSupportLCDScale	0x4000 /* SiS bridge: No scaling possible (no matter what panel) */
+#define NoSupportLCDScale	0x4000	/* SiS bridge: No scaling possible (no matter what panel) */
 #define DoubleScanMode		0x8000
 
 /* Infoflag */
 #define SupportTV		0x0008
 #define SupportTV1024		0x0800
-#define SupportCHTV 		0x0800
-#define Support64048060Hz	0x0800  /* Special for 640x480 LCD */
+#define SupportCHTV		0x0800
+#define Support64048060Hz	0x0800	/* Special for 640x480 LCD */
 #define SupportHiVision		0x0010
 #define SupportYPbPr750p	0x1000
 #define SupportLCD		0x0020
 #define SupportRAMDAC2		0x0040	/* All           (<= 100Mhz) */
-#define SupportRAMDAC2_135	0x0100  /* All except DH (<= 135Mhz) */
-#define SupportRAMDAC2_162	0x0200  /* B, C          (<= 162Mhz) */
-#define SupportRAMDAC2_202	0x0400  /* C             (<= 202Mhz) */
+#define SupportRAMDAC2_135	0x0100	/* All except DH (<= 135Mhz) */
+#define SupportRAMDAC2_162	0x0200	/* B, C          (<= 162Mhz) */
+#define SupportRAMDAC2_202	0x0400	/* C             (<= 202Mhz) */
 #define InterlaceMode		0x0080
 #define SyncPP			0x0000
 #define SyncPN			0x4000
@@ -129,7 +129,7 @@
 #define SIS_RI_856x480		19
 #define SIS_RI_1280x768		20
 #define SIS_RI_1400x1050	21
-#define SIS_RI_1152x864		22  /* Up to here SiS conforming */
+#define SIS_RI_1152x864		22	/* Up to here SiS conforming */
 #define SIS_RI_848x480		23
 #define SIS_RI_1360x768		24
 #define SIS_RI_1024x600		25
@@ -147,691 +147,691 @@
 #define SIS_CRT2_PORT_04	0x04 - 0x30
 
 /* Mode numbers */
-static const unsigned short ModeIndex_320x200[]   = {0x59, 0x41, 0x00, 0x4f};
-static const unsigned short ModeIndex_320x240[]   = {0x50, 0x56, 0x00, 0x53};
-static const unsigned short ModeIndex_400x300[]   = {0x51, 0x57, 0x00, 0x54};
-static const unsigned short ModeIndex_512x384[]   = {0x52, 0x58, 0x00, 0x5c};
-static const unsigned short ModeIndex_640x400[]   = {0x2f, 0x5d, 0x00, 0x5e};
-static const unsigned short ModeIndex_640x480[]   = {0x2e, 0x44, 0x00, 0x62};
-static const unsigned short ModeIndex_720x480[]   = {0x31, 0x33, 0x00, 0x35};
-static const unsigned short ModeIndex_720x576[]   = {0x32, 0x34, 0x00, 0x36};
-static const unsigned short ModeIndex_768x576[]   = {0x5f, 0x60, 0x00, 0x61};
-static const unsigned short ModeIndex_800x480[]   = {0x70, 0x7a, 0x00, 0x76};
-static const unsigned short ModeIndex_800x600[]   = {0x30, 0x47, 0x00, 0x63};
-static const unsigned short ModeIndex_848x480[]   = {0x39, 0x3b, 0x00, 0x3e};
-static const unsigned short ModeIndex_856x480[]   = {0x3f, 0x42, 0x00, 0x45};
-static const unsigned short ModeIndex_960x540[]   = {0x1d, 0x1e, 0x00, 0x1f};
-static const unsigned short ModeIndex_960x600[]   = {0x20, 0x21, 0x00, 0x22};
-static const unsigned short ModeIndex_1024x768[]  = {0x38, 0x4a, 0x00, 0x64};
-static const unsigned short ModeIndex_1024x576[]  = {0x71, 0x74, 0x00, 0x77};
-static const unsigned short ModeIndex_1152x864[]  = {0x29, 0x2a, 0x00, 0x2b};
-static const unsigned short ModeIndex_1280x720[]  = {0x79, 0x75, 0x00, 0x78};
-static const unsigned short ModeIndex_1280x768[]  = {0x23, 0x24, 0x00, 0x25};
-static const unsigned short ModeIndex_1280x1024[] = {0x3a, 0x4d, 0x00, 0x65};
+static const unsigned short ModeIndex_320x200[] = { 0x59, 0x41, 0x00, 0x4f };
+static const unsigned short ModeIndex_320x240[] = { 0x50, 0x56, 0x00, 0x53 };
+static const unsigned short ModeIndex_400x300[] = { 0x51, 0x57, 0x00, 0x54 };
+static const unsigned short ModeIndex_512x384[] = { 0x52, 0x58, 0x00, 0x5c };
+static const unsigned short ModeIndex_640x400[] = { 0x2f, 0x5d, 0x00, 0x5e };
+static const unsigned short ModeIndex_640x480[] = { 0x2e, 0x44, 0x00, 0x62 };
+static const unsigned short ModeIndex_720x480[] = { 0x31, 0x33, 0x00, 0x35 };
+static const unsigned short ModeIndex_720x576[] = { 0x32, 0x34, 0x00, 0x36 };
+static const unsigned short ModeIndex_768x576[] = { 0x5f, 0x60, 0x00, 0x61 };
+static const unsigned short ModeIndex_800x480[] = { 0x70, 0x7a, 0x00, 0x76 };
+static const unsigned short ModeIndex_800x600[] = { 0x30, 0x47, 0x00, 0x63 };
+static const unsigned short ModeIndex_848x480[] = { 0x39, 0x3b, 0x00, 0x3e };
+static const unsigned short ModeIndex_856x480[] = { 0x3f, 0x42, 0x00, 0x45 };
+static const unsigned short ModeIndex_960x540[] = { 0x1d, 0x1e, 0x00, 0x1f };
+static const unsigned short ModeIndex_960x600[] = { 0x20, 0x21, 0x00, 0x22 };
+static const unsigned short ModeIndex_1024x768[] = { 0x38, 0x4a, 0x00, 0x64 };
+static const unsigned short ModeIndex_1024x576[] = { 0x71, 0x74, 0x00, 0x77 };
+static const unsigned short ModeIndex_1152x864[] = { 0x29, 0x2a, 0x00, 0x2b };
+static const unsigned short ModeIndex_1280x720[] = { 0x79, 0x75, 0x00, 0x78 };
+static const unsigned short ModeIndex_1280x768[] = { 0x23, 0x24, 0x00, 0x25 };
+static const unsigned short ModeIndex_1280x1024[] = { 0x3a, 0x4d, 0x00, 0x65 };
 
-static const unsigned char SiS_MDA_DAC[] =
-{
-	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-        0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
-        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-        0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
-        0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F
+static const unsigned char SiS_MDA_DAC[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+	0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+	0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15,
+	0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F
 };
 
-static const unsigned char SiS_CGA_DAC[] =
-{
-        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-        0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+static const unsigned char SiS_CGA_DAC[] = {
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
 };
 
-static const unsigned char SiS_EGA_DAC[] =
-{
-        0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15,
-        0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35,
-        0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D,
-        0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D,
-        0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17,
-        0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37,
-        0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F,
-        0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F
+static const unsigned char SiS_EGA_DAC[] = {
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x05, 0x15,
+	0x20, 0x30, 0x24, 0x34, 0x21, 0x31, 0x25, 0x35,
+	0x08, 0x18, 0x0C, 0x1C, 0x09, 0x19, 0x0D, 0x1D,
+	0x28, 0x38, 0x2C, 0x3C, 0x29, 0x39, 0x2D, 0x3D,
+	0x02, 0x12, 0x06, 0x16, 0x03, 0x13, 0x07, 0x17,
+	0x22, 0x32, 0x26, 0x36, 0x23, 0x33, 0x27, 0x37,
+	0x0A, 0x1A, 0x0E, 0x1E, 0x0B, 0x1B, 0x0F, 0x1F,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F
 };
 
-static const unsigned char SiS_VGA_DAC[] =
-{
-	0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
-	0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
-	0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18,
-	0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F,
-	0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F,
-	0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00,
-	0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18,
-	0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04,
-	0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10,
-	0x0B,0x0C,0x0D,0x0F,0x10
+static const unsigned char SiS_VGA_DAC[] = {
+	0x00, 0x10, 0x04, 0x14, 0x01, 0x11, 0x09, 0x15,
+	0x2A, 0x3A, 0x2E, 0x3E, 0x2B, 0x3B, 0x2F, 0x3F,
+	0x00, 0x05, 0x08, 0x0B, 0x0E, 0x11, 0x14, 0x18,
+	0x1C, 0x20, 0x24, 0x28, 0x2D, 0x32, 0x38, 0x3F,
+	0x00, 0x10, 0x1F, 0x2F, 0x3F, 0x1F, 0x27, 0x2F,
+	0x37, 0x3F, 0x2D, 0x31, 0x36, 0x3A, 0x3F, 0x00,
+	0x07, 0x0E, 0x15, 0x1C, 0x0E, 0x11, 0x15, 0x18,
+	0x1C, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x04,
+	0x08, 0x0C, 0x10, 0x08, 0x0A, 0x0C, 0x0E, 0x10,
+	0x0B, 0x0C, 0x0D, 0x0F, 0x10
 };
 
-static const struct SiS_St SiSUSB_SModeIDTable[] =
-{
-	{0x03,0x0010,0x18,0x02,0x02,0x00,0x01,0x03,0x40},
-	{0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
+static const struct SiS_St SiSUSB_SModeIDTable[] = {
+	{0x03, 0x0010, 0x18, 0x02, 0x02, 0x00, 0x01, 0x03, 0x40},
+	{0xff, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
 };
 
-static const struct SiS_StResInfo_S SiSUSB_StResInfo[] =
-{
-	{ 640,400},
-	{ 640,350},
-	{ 720,400},
-	{ 720,350},
-	{ 640,480}
+static const struct SiS_StResInfo_S SiSUSB_StResInfo[] = {
+	{640, 400},
+	{640, 350},
+	{720, 400},
+	{720, 350},
+	{640, 480}
 };
 
-static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] =
-{
-	{  320, 200, 8, 8},   /* 0x00 */
-	{  320, 240, 8, 8},   /* 0x01 */
-	{  320, 400, 8, 8},   /* 0x02 */
-	{  400, 300, 8, 8},   /* 0x03 */
-	{  512, 384, 8, 8},   /* 0x04 */
-	{  640, 400, 8,16},   /* 0x05 */
-	{  640, 480, 8,16},   /* 0x06 */
-	{  800, 600, 8,16},   /* 0x07 */
-	{ 1024, 768, 8,16},   /* 0x08 */
-	{ 1280,1024, 8,16},   /* 0x09 */
-	{ 1600,1200, 8,16},   /* 0x0a */
-	{ 1920,1440, 8,16},   /* 0x0b */
-	{ 2048,1536, 8,16},   /* 0x0c */
-	{  720, 480, 8,16},   /* 0x0d */
-	{  720, 576, 8,16},   /* 0x0e */
-	{ 1280, 960, 8,16},   /* 0x0f */
-	{  800, 480, 8,16},   /* 0x10 */
-	{ 1024, 576, 8,16},   /* 0x11 */
-	{ 1280, 720, 8,16},   /* 0x12 */
-	{  856, 480, 8,16},   /* 0x13 */
-	{ 1280, 768, 8,16},   /* 0x14 */
-	{ 1400,1050, 8,16},   /* 0x15 */
-	{ 1152, 864, 8,16},   /* 0x16 */
-	{  848, 480, 8,16},   /* 0x17 */
-	{ 1360, 768, 8,16},   /* 0x18 */
-	{ 1024, 600, 8,16},   /* 0x19 */
-	{ 1152, 768, 8,16},   /* 0x1a */
-	{  768, 576, 8,16},   /* 0x1b */
-	{ 1360,1024, 8,16},   /* 0x1c */
-	{ 1680,1050, 8,16},   /* 0x1d */
-	{ 1280, 800, 8,16},   /* 0x1e */
-	{ 1920,1080, 8,16},   /* 0x1f */
-	{  960, 540, 8,16},   /* 0x20 */
-	{  960, 600, 8,16}    /* 0x21 */
+static const struct SiS_ModeResInfo SiSUSB_ModeResInfo[] = {
+	{320, 200, 8, 8},	/* 0x00 */
+	{320, 240, 8, 8},	/* 0x01 */
+	{320, 400, 8, 8},	/* 0x02 */
+	{400, 300, 8, 8},	/* 0x03 */
+	{512, 384, 8, 8},	/* 0x04 */
+	{640, 400, 8, 16},	/* 0x05 */
+	{640, 480, 8, 16},	/* 0x06 */
+	{800, 600, 8, 16},	/* 0x07 */
+	{1024, 768, 8, 16},	/* 0x08 */
+	{1280, 1024, 8, 16},	/* 0x09 */
+	{1600, 1200, 8, 16},	/* 0x0a */
+	{1920, 1440, 8, 16},	/* 0x0b */
+	{2048, 1536, 8, 16},	/* 0x0c */
+	{720, 480, 8, 16},	/* 0x0d */
+	{720, 576, 8, 16},	/* 0x0e */
+	{1280, 960, 8, 16},	/* 0x0f */
+	{800, 480, 8, 16},	/* 0x10 */
+	{1024, 576, 8, 16},	/* 0x11 */
+	{1280, 720, 8, 16},	/* 0x12 */
+	{856, 480, 8, 16},	/* 0x13 */
+	{1280, 768, 8, 16},	/* 0x14 */
+	{1400, 1050, 8, 16},	/* 0x15 */
+	{1152, 864, 8, 16},	/* 0x16 */
+	{848, 480, 8, 16},	/* 0x17 */
+	{1360, 768, 8, 16},	/* 0x18 */
+	{1024, 600, 8, 16},	/* 0x19 */
+	{1152, 768, 8, 16},	/* 0x1a */
+	{768, 576, 8, 16},	/* 0x1b */
+	{1360, 1024, 8, 16},	/* 0x1c */
+	{1680, 1050, 8, 16},	/* 0x1d */
+	{1280, 800, 8, 16},	/* 0x1e */
+	{1920, 1080, 8, 16},	/* 0x1f */
+	{960, 540, 8, 16},	/* 0x20 */
+	{960, 600, 8, 16}	/* 0x21 */
 };
 
-static const struct SiS_StandTable SiSUSB_StandTable[] =
-{
+static const struct SiS_StandTable SiSUSB_StandTable[] = {
 	/* MD_3_400 - mode 0x03 - 400 */
 	{
-		0x50,0x18,0x10,0x1000,
-		{ 0x00,0x03,0x00,0x02 },
-		0x67,
-		{ 0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-		  0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
-		  0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
-		  0xff },
-		{ 0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
-		  0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
-		  0x0c,0x00,0x0f,0x08 },
-		{ 0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00, 0xff }
-	},
+	 0x50, 0x18, 0x10, 0x1000,
+	 {0x00, 0x03, 0x00, 0x02},
+	 0x67,
+	 {0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+	  0x00, 0x4f, 0x0d, 0x0e, 0x00, 0x00, 0x00, 0x00,
+	  0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96, 0xb9, 0xa3,
+	  0xff},
+	 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
+	  0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+	  0x0c, 0x00, 0x0f, 0x08},
+	 {0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff}
+	 },
 	/* Generic for VGA and higher */
 	{
-		0x00,0x00,0x00,0x0000,
-		{ 0x01,0x0f,0x00,0x0e },
-		0x23,
-		{ 0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
-		  0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
-		  0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
-		  0xff },
-		{ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
-		  0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
-		  0x01,0x00,0x00,0x00 },
-		{ 0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f, 0xff }
-	}
+	 0x00, 0x00, 0x00, 0x0000,
+	 {0x01, 0x0f, 0x00, 0x0e},
+	 0x23,
+	 {0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0x0b, 0x3e,
+	  0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	  0xea, 0x8c, 0xdf, 0x28, 0x40, 0xe7, 0x04, 0xa3,
+	  0xff},
+	 {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+	  0x01, 0x00, 0x00, 0x00},
+	 {0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff}
+	 }
 };
 
-static const struct SiS_Ext SiSUSB_EModeIDTable[] =
-{
-	{0x2e,0x0a1b,0x0101,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x8 */
-	{0x2f,0x0a1b,0x0100,SIS_RI_640x400,  0x00,0x00,0x05,0x05,0x10, 0}, /* 640x400x8 */
-	{0x30,0x2a1b,0x0103,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x8 */
-	{0x31,0x4a1b,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x8 */
-	{0x32,0x4a1b,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x8 */
-	{0x33,0x4a1d,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x16 */
-	{0x34,0x6a1d,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x16 */
-	{0x35,0x4a1f,0x0000,SIS_RI_720x480,  0x00,0x00,0x06,0x06,0x11,-1}, /* 720x480x32 */
-	{0x36,0x6a1f,0x0000,SIS_RI_720x576,  0x00,0x00,0x06,0x06,0x12,-1}, /* 720x576x32 */
-	{0x38,0x0a1b,0x0105,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x8 */
-	{0x3a,0x0e3b,0x0107,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x8 */
-	{0x41,0x9a1d,0x010e,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x16 */
-	{0x44,0x0a1d,0x0111,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x16 */
-	{0x47,0x2a1d,0x0114,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x16 */
-	{0x4a,0x0a3d,0x0117,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x16 */
-	{0x4d,0x0e7d,0x011a,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x16 */
-	{0x50,0x9a1b,0x0132,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x8  */
-	{0x51,0xba1b,0x0133,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x8  */
-	{0x52,0xba1b,0x0134,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x8  */
-	{0x56,0x9a1d,0x0135,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x16 */
-	{0x57,0xba1d,0x0136,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x16 */
-	{0x58,0xba1d,0x0137,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x16 */
-	{0x59,0x9a1b,0x0138,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x8  */
-	{0x5c,0xba1f,0x0000,SIS_RI_512x384,  0x00,0x00,0x00,0x00,0x1d, 4}, /* 512x384x32 */
-	{0x5d,0x0a1d,0x0139,SIS_RI_640x400,  0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x16 */
-	{0x5e,0x0a1f,0x0000,SIS_RI_640x400,  0x00,0x00,0x05,0x07,0x10, 0}, /* 640x400x32 */
-	{0x62,0x0a3f,0x013a,SIS_RI_640x480,  0x00,0x00,0x05,0x05,0x08, 2}, /* 640x480x32 */
-	{0x63,0x2a3f,0x013b,SIS_RI_800x600,  0x00,0x00,0x07,0x06,0x00, 3}, /* 800x600x32 */
-	{0x64,0x0a7f,0x013c,SIS_RI_1024x768, 0x00,0x00,0x08,0x07,0x13, 4}, /* 1024x768x32 */
-	{0x65,0x0eff,0x013d,SIS_RI_1280x1024,0x00,0x00,0x00,0x00,0x2f, 8}, /* 1280x1024x32 */
-	{0x70,0x6a1b,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x8 */
-	{0x71,0x4a1b,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x8 */
-	{0x74,0x4a1d,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x16 */
-	{0x75,0x0a3d,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x16 */
-	{0x76,0x6a1f,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x32 */
-	{0x77,0x4a1f,0x0000,SIS_RI_1024x576, 0x00,0x00,0x00,0x00,0x21,-1}, /* 1024x576x32 */
-	{0x78,0x0a3f,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x32 */
-	{0x79,0x0a3b,0x0000,SIS_RI_1280x720, 0x00,0x00,0x00,0x00,0x24, 5}, /* 1280x720x8 */
-	{0x7a,0x6a1d,0x0000,SIS_RI_800x480,  0x00,0x00,0x07,0x07,0x1e,-1}, /* 800x480x16 */
-	{0x23,0x0e3b,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x8 */
-	{0x24,0x0e7d,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x16 */
-	{0x25,0x0eff,0x0000,SIS_RI_1280x768, 0x00,0x00,0x00,0x00,0x27, 6}, /* 1280x768x32 */
-	{0x39,0x6a1b,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x28,-1}, /* 848x480 */
-	{0x3b,0x6a3d,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x28,-1},
-	{0x3e,0x6a7f,0x0000,SIS_RI_848x480,  0x00,0x00,0x00,0x00,0x28,-1},
-	{0x3f,0x6a1b,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x2a,-1}, /* 856x480 */
-	{0x42,0x6a3d,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x2a,-1},
-	{0x45,0x6a7f,0x0000,SIS_RI_856x480,  0x00,0x00,0x00,0x00,0x2a,-1},
-	{0x4f,0x9a1f,0x0000,SIS_RI_320x200,  0x00,0x00,0x04,0x04,0x1a, 0}, /* 320x200x32 */
-	{0x53,0x9a1f,0x0000,SIS_RI_320x240,  0x00,0x00,0x04,0x04,0x1b, 2}, /* 320x240x32 */
-	{0x54,0xba1f,0x0000,SIS_RI_400x300,  0x00,0x00,0x07,0x07,0x1c, 3}, /* 400x300x32 */
-	{0x5f,0x6a1b,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x2c,-1}, /* 768x576 */
-	{0x60,0x6a1d,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x2c,-1},
-	{0x61,0x6a3f,0x0000,SIS_RI_768x576,  0x00,0x00,0x06,0x06,0x2c,-1},
-	{0x1d,0x6a1b,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x2d,-1}, /* 960x540 */
-	{0x1e,0x6a3d,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x2d,-1},
-	{0x1f,0x6a7f,0x0000,SIS_RI_960x540,  0x00,0x00,0x00,0x00,0x2d,-1},
-	{0x20,0x6a1b,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x2e,-1}, /* 960x600 */
-	{0x21,0x6a3d,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x2e,-1},
-	{0x22,0x6a7f,0x0000,SIS_RI_960x600,  0x00,0x00,0x00,0x00,0x2e,-1},
-	{0x29,0x4e1b,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1}, /* 1152x864 */
-	{0x2a,0x4e3d,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
-	{0x2b,0x4e7f,0x0000,SIS_RI_1152x864, 0x00,0x00,0x00,0x00,0x33,-1},
-	{0xff,0x0000,0x0000,0,               0x00,0x00,0x00,0x00,0x00,-1}
+static const struct SiS_Ext SiSUSB_EModeIDTable[] = {
+	{0x2e, 0x0a1b, 0x0101, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2},	/* 640x480x8 */
+	{0x2f, 0x0a1b, 0x0100, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x05, 0x10, 0},	/* 640x400x8 */
+	{0x30, 0x2a1b, 0x0103, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3},	/* 800x600x8 */
+	{0x31, 0x4a1b, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1},	/* 720x480x8 */
+	{0x32, 0x4a1b, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1},	/* 720x576x8 */
+	{0x33, 0x4a1d, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1},	/* 720x480x16 */
+	{0x34, 0x6a1d, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1},	/* 720x576x16 */
+	{0x35, 0x4a1f, 0x0000, SIS_RI_720x480, 0x00, 0x00, 0x06, 0x06, 0x11, -1},	/* 720x480x32 */
+	{0x36, 0x6a1f, 0x0000, SIS_RI_720x576, 0x00, 0x00, 0x06, 0x06, 0x12, -1},	/* 720x576x32 */
+	{0x38, 0x0a1b, 0x0105, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4},	/* 1024x768x8 */
+	{0x3a, 0x0e3b, 0x0107, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8},	/* 1280x1024x8 */
+	{0x41, 0x9a1d, 0x010e, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0},	/* 320x200x16 */
+	{0x44, 0x0a1d, 0x0111, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2},	/* 640x480x16 */
+	{0x47, 0x2a1d, 0x0114, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3},	/* 800x600x16 */
+	{0x4a, 0x0a3d, 0x0117, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4},	/* 1024x768x16 */
+	{0x4d, 0x0e7d, 0x011a, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8},	/* 1280x1024x16 */
+	{0x50, 0x9a1b, 0x0132, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2},	/* 320x240x8  */
+	{0x51, 0xba1b, 0x0133, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3},	/* 400x300x8  */
+	{0x52, 0xba1b, 0x0134, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4},	/* 512x384x8  */
+	{0x56, 0x9a1d, 0x0135, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2},	/* 320x240x16 */
+	{0x57, 0xba1d, 0x0136, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3},	/* 400x300x16 */
+	{0x58, 0xba1d, 0x0137, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4},	/* 512x384x16 */
+	{0x59, 0x9a1b, 0x0138, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0},	/* 320x200x8  */
+	{0x5c, 0xba1f, 0x0000, SIS_RI_512x384, 0x00, 0x00, 0x00, 0x00, 0x1d, 4},	/* 512x384x32 */
+	{0x5d, 0x0a1d, 0x0139, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0},	/* 640x400x16 */
+	{0x5e, 0x0a1f, 0x0000, SIS_RI_640x400, 0x00, 0x00, 0x05, 0x07, 0x10, 0},	/* 640x400x32 */
+	{0x62, 0x0a3f, 0x013a, SIS_RI_640x480, 0x00, 0x00, 0x05, 0x05, 0x08, 2},	/* 640x480x32 */
+	{0x63, 0x2a3f, 0x013b, SIS_RI_800x600, 0x00, 0x00, 0x07, 0x06, 0x00, 3},	/* 800x600x32 */
+	{0x64, 0x0a7f, 0x013c, SIS_RI_1024x768, 0x00, 0x00, 0x08, 0x07, 0x13, 4},	/* 1024x768x32 */
+	{0x65, 0x0eff, 0x013d, SIS_RI_1280x1024, 0x00, 0x00, 0x00, 0x00, 0x2f, 8},	/* 1280x1024x32 */
+	{0x70, 0x6a1b, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1},	/* 800x480x8 */
+	{0x71, 0x4a1b, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1},	/* 1024x576x8 */
+	{0x74, 0x4a1d, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1},	/* 1024x576x16 */
+	{0x75, 0x0a3d, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5},	/* 1280x720x16 */
+	{0x76, 0x6a1f, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1},	/* 800x480x32 */
+	{0x77, 0x4a1f, 0x0000, SIS_RI_1024x576, 0x00, 0x00, 0x00, 0x00, 0x21, -1},	/* 1024x576x32 */
+	{0x78, 0x0a3f, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5},	/* 1280x720x32 */
+	{0x79, 0x0a3b, 0x0000, SIS_RI_1280x720, 0x00, 0x00, 0x00, 0x00, 0x24, 5},	/* 1280x720x8 */
+	{0x7a, 0x6a1d, 0x0000, SIS_RI_800x480, 0x00, 0x00, 0x07, 0x07, 0x1e, -1},	/* 800x480x16 */
+	{0x23, 0x0e3b, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6},	/* 1280x768x8 */
+	{0x24, 0x0e7d, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6},	/* 1280x768x16 */
+	{0x25, 0x0eff, 0x0000, SIS_RI_1280x768, 0x00, 0x00, 0x00, 0x00, 0x27, 6},	/* 1280x768x32 */
+	{0x39, 0x6a1b, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28, -1},	/* 848x480 */
+	{0x3b, 0x6a3d, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28,
+	 -1},
+	{0x3e, 0x6a7f, 0x0000, SIS_RI_848x480, 0x00, 0x00, 0x00, 0x00, 0x28,
+	 -1},
+	{0x3f, 0x6a1b, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a, -1},	/* 856x480 */
+	{0x42, 0x6a3d, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a,
+	 -1},
+	{0x45, 0x6a7f, 0x0000, SIS_RI_856x480, 0x00, 0x00, 0x00, 0x00, 0x2a,
+	 -1},
+	{0x4f, 0x9a1f, 0x0000, SIS_RI_320x200, 0x00, 0x00, 0x04, 0x04, 0x1a, 0},	/* 320x200x32 */
+	{0x53, 0x9a1f, 0x0000, SIS_RI_320x240, 0x00, 0x00, 0x04, 0x04, 0x1b, 2},	/* 320x240x32 */
+	{0x54, 0xba1f, 0x0000, SIS_RI_400x300, 0x00, 0x00, 0x07, 0x07, 0x1c, 3},	/* 400x300x32 */
+	{0x5f, 0x6a1b, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c, -1},	/* 768x576 */
+	{0x60, 0x6a1d, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c,
+	 -1},
+	{0x61, 0x6a3f, 0x0000, SIS_RI_768x576, 0x00, 0x00, 0x06, 0x06, 0x2c,
+	 -1},
+	{0x1d, 0x6a1b, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d, -1},	/* 960x540 */
+	{0x1e, 0x6a3d, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d,
+	 -1},
+	{0x1f, 0x6a7f, 0x0000, SIS_RI_960x540, 0x00, 0x00, 0x00, 0x00, 0x2d,
+	 -1},
+	{0x20, 0x6a1b, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e, -1},	/* 960x600 */
+	{0x21, 0x6a3d, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e,
+	 -1},
+	{0x22, 0x6a7f, 0x0000, SIS_RI_960x600, 0x00, 0x00, 0x00, 0x00, 0x2e,
+	 -1},
+	{0x29, 0x4e1b, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33, -1},	/* 1152x864 */
+	{0x2a, 0x4e3d, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33,
+	 -1},
+	{0x2b, 0x4e7f, 0x0000, SIS_RI_1152x864, 0x00, 0x00, 0x00, 0x00, 0x33,
+	 -1},
+	{0xff, 0x0000, 0x0000, 0, 0x00, 0x00, 0x00, 0x00, 0x00, -1}
 };
 
-static const struct SiS_Ext2 SiSUSB_RefIndex[] =
-{
-	{0x085f,0x0d,0x03,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x0 */
-	{0x0067,0x0e,0x04,0x05,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x1 */
-	{0x0067,0x0f,0x08,0x48,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x2 */
-	{0x0067,0x10,0x07,0x8b,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x3 */
-	{0x0047,0x11,0x0a,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x4 */
-	{0x0047,0x12,0x0d,0x00,0x05,0x30, 800, 600, 0x40, 0x00, 0x00}, /* 0x5 */
-	{0x0047,0x13,0x13,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x6 */
-	{0x0107,0x14,0x1c,0x00,0x05,0x30, 800, 600, 0x20, 0x00, 0x00}, /* 0x7 */
-	{0xc85f,0x05,0x00,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x8 */
-	{0xc067,0x06,0x02,0x04,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0x9 */
-	{0xc067,0x07,0x02,0x47,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xa */
-	{0xc067,0x08,0x03,0x8a,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xb */
-	{0xc047,0x09,0x05,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xc */
-	{0xc047,0x0a,0x09,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xd */
-	{0xc047,0x0b,0x0e,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xe */
-	{0xc047,0x0c,0x15,0x00,0x04,0x2e, 640, 480, 0x40, 0x00, 0x00}, /* 0xf */
-	{0x487f,0x04,0x00,0x00,0x00,0x2f, 640, 400, 0x30, 0x55, 0x6e}, /* 0x10 */
-	{0xc06f,0x3c,0x01,0x06,0x13,0x31, 720, 480, 0x30, 0x00, 0x00}, /* 0x11 */
-	{0x006f,0x3d,0x6f,0x06,0x14,0x32, 720, 576, 0x30, 0x00, 0x00}, /* 0x12 (6f was 03) */
-	{0x0087,0x15,0x06,0x00,0x06,0x38,1024, 768, 0x30, 0x00, 0x00}, /* 0x13 */
-	{0xc877,0x16,0x0b,0x06,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x14 */
-	{0xc067,0x17,0x0f,0x49,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x15 */
-	{0x0067,0x18,0x11,0x00,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x16 */
-	{0x0047,0x19,0x16,0x8c,0x06,0x38,1024, 768, 0x20, 0x00, 0x00}, /* 0x17 */
-	{0x0107,0x1a,0x1b,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x18 */
-	{0x0107,0x1b,0x1f,0x00,0x06,0x38,1024, 768, 0x10, 0x00, 0x00}, /* 0x19 */
-	{0x407f,0x00,0x00,0x00,0x00,0x41, 320, 200, 0x30, 0x56, 0x4e}, /* 0x1a */
-	{0xc07f,0x01,0x00,0x04,0x04,0x50, 320, 240, 0x30, 0x00, 0x00}, /* 0x1b */
-	{0x007f,0x02,0x04,0x05,0x05,0x51, 400, 300, 0x30, 0x00, 0x00}, /* 0x1c */
-	{0xc077,0x03,0x0b,0x06,0x06,0x52, 512, 384, 0x30, 0x00, 0x00}, /* 0x1d */
-	{0x0077,0x32,0x40,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1e */
-	{0x0047,0x33,0x07,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x1f */
-	{0x0047,0x34,0x0a,0x08,0x18,0x70, 800, 480, 0x30, 0x00, 0x00}, /* 0x20 */
-	{0x0077,0x35,0x0b,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x21 */
-	{0x0047,0x36,0x11,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x22 */
-	{0x0047,0x37,0x16,0x09,0x19,0x71,1024, 576, 0x30, 0x00, 0x00}, /* 0x23 */
-	{0x1137,0x38,0x19,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x24 */
-	{0x1107,0x39,0x1e,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x25 */
-	{0x1307,0x3a,0x20,0x0a,0x0c,0x75,1280, 720, 0x30, 0x00, 0x00}, /* 0x26 */
-	{0x0077,0x42,0x5b,0x08,0x11,0x23,1280, 768, 0x30, 0x00, 0x00}, /* 0x27 */
-	{0x0087,0x45,0x57,0x00,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x28 38Hzi  */
-	{0xc067,0x46,0x55,0x0b,0x16,0x39, 848, 480, 0x30, 0x00, 0x00}, /* 0x29 848x480-60Hz   */
-	{0x0087,0x47,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2a 856x480-38Hzi  */
-	{0xc067,0x48,0x57,0x00,0x17,0x3f, 856, 480, 0x30, 0x00, 0x00}, /* 0x2b 856x480-60Hz   */
-	{0x006f,0x4d,0x71,0x06,0x15,0x5f, 768, 576, 0x30, 0x00, 0x00}, /* 0x2c 768x576-56Hz   */
-	{0x0067,0x52,0x6a,0x00,0x1c,0x1d, 960, 540, 0x30, 0x00, 0x00}, /* 0x2d 960x540 60Hz */
-	{0x0077,0x53,0x6b,0x0b,0x1d,0x20, 960, 600, 0x30, 0x00, 0x00}, /* 0x2e 960x600 60Hz */
-	{0x0087,0x1c,0x11,0x00,0x07,0x3a,1280,1024, 0x30, 0x00, 0x00}, /* 0x2f */
-	{0x0137,0x1d,0x19,0x07,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x30 */
-	{0x0107,0x1e,0x1e,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x31 */
-	{0x0207,0x1f,0x20,0x00,0x07,0x3a,1280,1024, 0x00, 0x00, 0x00}, /* 0x32 */
-	{0x0127,0x54,0x6d,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x33 1152x864-60Hz  */
-	{0x0127,0x44,0x19,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x34 1152x864-75Hz  */
-	{0x0127,0x4a,0x1e,0x00,0x1a,0x29,1152, 864, 0x30, 0x00, 0x00}, /* 0x35 1152x864-85Hz  */
-	{0xffff,0x00,0x00,0x00,0x00,0x00,   0,   0,    0, 0x00, 0x00}
+static const struct SiS_Ext2 SiSUSB_RefIndex[] = {
+	{0x085f, 0x0d, 0x03, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x0 */
+	{0x0067, 0x0e, 0x04, 0x05, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x1 */
+	{0x0067, 0x0f, 0x08, 0x48, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x2 */
+	{0x0067, 0x10, 0x07, 0x8b, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x3 */
+	{0x0047, 0x11, 0x0a, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x4 */
+	{0x0047, 0x12, 0x0d, 0x00, 0x05, 0x30, 800, 600, 0x40, 0x00, 0x00},	/* 0x5 */
+	{0x0047, 0x13, 0x13, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00},	/* 0x6 */
+	{0x0107, 0x14, 0x1c, 0x00, 0x05, 0x30, 800, 600, 0x20, 0x00, 0x00},	/* 0x7 */
+	{0xc85f, 0x05, 0x00, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0x8 */
+	{0xc067, 0x06, 0x02, 0x04, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0x9 */
+	{0xc067, 0x07, 0x02, 0x47, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xa */
+	{0xc067, 0x08, 0x03, 0x8a, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xb */
+	{0xc047, 0x09, 0x05, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xc */
+	{0xc047, 0x0a, 0x09, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xd */
+	{0xc047, 0x0b, 0x0e, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xe */
+	{0xc047, 0x0c, 0x15, 0x00, 0x04, 0x2e, 640, 480, 0x40, 0x00, 0x00},	/* 0xf */
+	{0x487f, 0x04, 0x00, 0x00, 0x00, 0x2f, 640, 400, 0x30, 0x55, 0x6e},	/* 0x10 */
+	{0xc06f, 0x3c, 0x01, 0x06, 0x13, 0x31, 720, 480, 0x30, 0x00, 0x00},	/* 0x11 */
+	{0x006f, 0x3d, 0x6f, 0x06, 0x14, 0x32, 720, 576, 0x30, 0x00, 0x00},	/* 0x12 (6f was 03) */
+	{0x0087, 0x15, 0x06, 0x00, 0x06, 0x38, 1024, 768, 0x30, 0x00, 0x00},	/* 0x13 */
+	{0xc877, 0x16, 0x0b, 0x06, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},	/* 0x14 */
+	{0xc067, 0x17, 0x0f, 0x49, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},	/* 0x15 */
+	{0x0067, 0x18, 0x11, 0x00, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},	/* 0x16 */
+	{0x0047, 0x19, 0x16, 0x8c, 0x06, 0x38, 1024, 768, 0x20, 0x00, 0x00},	/* 0x17 */
+	{0x0107, 0x1a, 0x1b, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00},	/* 0x18 */
+	{0x0107, 0x1b, 0x1f, 0x00, 0x06, 0x38, 1024, 768, 0x10, 0x00, 0x00},	/* 0x19 */
+	{0x407f, 0x00, 0x00, 0x00, 0x00, 0x41, 320, 200, 0x30, 0x56, 0x4e},	/* 0x1a */
+	{0xc07f, 0x01, 0x00, 0x04, 0x04, 0x50, 320, 240, 0x30, 0x00, 0x00},	/* 0x1b */
+	{0x007f, 0x02, 0x04, 0x05, 0x05, 0x51, 400, 300, 0x30, 0x00, 0x00},	/* 0x1c */
+	{0xc077, 0x03, 0x0b, 0x06, 0x06, 0x52, 512, 384, 0x30, 0x00, 0x00},	/* 0x1d */
+	{0x0077, 0x32, 0x40, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00},	/* 0x1e */
+	{0x0047, 0x33, 0x07, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00},	/* 0x1f */
+	{0x0047, 0x34, 0x0a, 0x08, 0x18, 0x70, 800, 480, 0x30, 0x00, 0x00},	/* 0x20 */
+	{0x0077, 0x35, 0x0b, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00},	/* 0x21 */
+	{0x0047, 0x36, 0x11, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00},	/* 0x22 */
+	{0x0047, 0x37, 0x16, 0x09, 0x19, 0x71, 1024, 576, 0x30, 0x00, 0x00},	/* 0x23 */
+	{0x1137, 0x38, 0x19, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00},	/* 0x24 */
+	{0x1107, 0x39, 0x1e, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00},	/* 0x25 */
+	{0x1307, 0x3a, 0x20, 0x0a, 0x0c, 0x75, 1280, 720, 0x30, 0x00, 0x00},	/* 0x26 */
+	{0x0077, 0x42, 0x5b, 0x08, 0x11, 0x23, 1280, 768, 0x30, 0x00, 0x00},	/* 0x27 */
+	{0x0087, 0x45, 0x57, 0x00, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00},	/* 0x28 38Hzi  */
+	{0xc067, 0x46, 0x55, 0x0b, 0x16, 0x39, 848, 480, 0x30, 0x00, 0x00},	/* 0x29 848x480-60Hz   */
+	{0x0087, 0x47, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00},	/* 0x2a 856x480-38Hzi  */
+	{0xc067, 0x48, 0x57, 0x00, 0x17, 0x3f, 856, 480, 0x30, 0x00, 0x00},	/* 0x2b 856x480-60Hz   */
+	{0x006f, 0x4d, 0x71, 0x06, 0x15, 0x5f, 768, 576, 0x30, 0x00, 0x00},	/* 0x2c 768x576-56Hz   */
+	{0x0067, 0x52, 0x6a, 0x00, 0x1c, 0x1d, 960, 540, 0x30, 0x00, 0x00},	/* 0x2d 960x540 60Hz */
+	{0x0077, 0x53, 0x6b, 0x0b, 0x1d, 0x20, 960, 600, 0x30, 0x00, 0x00},	/* 0x2e 960x600 60Hz */
+	{0x0087, 0x1c, 0x11, 0x00, 0x07, 0x3a, 1280, 1024, 0x30, 0x00, 0x00},	/* 0x2f */
+	{0x0137, 0x1d, 0x19, 0x07, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00},	/* 0x30 */
+	{0x0107, 0x1e, 0x1e, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00},	/* 0x31 */
+	{0x0207, 0x1f, 0x20, 0x00, 0x07, 0x3a, 1280, 1024, 0x00, 0x00, 0x00},	/* 0x32 */
+	{0x0127, 0x54, 0x6d, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00},	/* 0x33 1152x864-60Hz  */
+	{0x0127, 0x44, 0x19, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00},	/* 0x34 1152x864-75Hz  */
+	{0x0127, 0x4a, 0x1e, 0x00, 0x1a, 0x29, 1152, 864, 0x30, 0x00, 0x00},	/* 0x35 1152x864-85Hz  */
+	{0xffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0x00, 0x00}
 };
 
-static const struct SiS_CRT1Table SiSUSB_CRT1Table[] =
-{
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
-   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x00,
-   0x00}}, /* 0x0 */
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
-   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
-   0x00}}, /* 0x1 */
- {{0x3d,0x31,0x31,0x81,0x37,0x1f,0x72,0xf0,
-   0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x05,
-   0x01}}, /* 0x2 */
- {{0x4f,0x3f,0x3f,0x93,0x45,0x0d,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x01,
-   0x01}}, /* 0x3 */
- {{0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
-   0x9c,0x8e,0x8f,0x96,0xb9,0x30,0x00,0x05,
-   0x00}}, /* 0x4 */
- {{0x5f,0x4f,0x4f,0x83,0x55,0x81,0x0b,0x3e,
-   0xe9,0x8b,0xdf,0xe8,0x0c,0x00,0x00,0x05,
-   0x00}}, /* 0x5 */
- {{0x63,0x4f,0x4f,0x87,0x56,0x9b,0x06,0x3e,
-   0xe8,0x8a,0xdf,0xe7,0x07,0x00,0x00,0x01,
-   0x00}}, /* 0x6 */
- {{0x64,0x4f,0x4f,0x88,0x55,0x9d,0xf2,0x1f,
-   0xe0,0x83,0xdf,0xdf,0xf3,0x10,0x00,0x01,
-   0x00}}, /* 0x7 */
- {{0x63,0x4f,0x4f,0x87,0x5a,0x81,0xfb,0x1f,
-   0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
-   0x00}}, /* 0x8 */
- {{0x65,0x4f,0x4f,0x89,0x58,0x80,0xfb,0x1f,
-   0xe0,0x83,0xdf,0xdf,0xfc,0x10,0x00,0x05,
-   0x61}}, /* 0x9 */
- {{0x65,0x4f,0x4f,0x89,0x58,0x80,0x01,0x3e,
-   0xe0,0x83,0xdf,0xdf,0x02,0x00,0x00,0x05,
-   0x61}}, /* 0xa */
- {{0x67,0x4f,0x4f,0x8b,0x58,0x81,0x0d,0x3e,
-   0xe0,0x83,0xdf,0xdf,0x0e,0x00,0x00,0x05,
-   0x61}}, /* 0xb */
- {{0x65,0x4f,0x4f,0x89,0x57,0x9f,0xfb,0x1f,
-   0xe6,0x8a,0xdf,0xdf,0xfc,0x10,0x00,0x01,
-   0x00}}, /* 0xc */
- {{0x7b,0x63,0x63,0x9f,0x6a,0x93,0x6f,0xf0,
-   0x58,0x8a,0x57,0x57,0x70,0x20,0x00,0x05,
-   0x01}}, /* 0xd */
- {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xf0,
-   0x58,0x8c,0x57,0x57,0x73,0x20,0x00,0x06,
-   0x01}}, /* 0xe */
- {{0x7d,0x63,0x63,0x81,0x6e,0x1d,0x98,0xf0,
-   0x7c,0x82,0x57,0x57,0x99,0x00,0x00,0x06,
-   0x01}}, /* 0xf */
- {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xf0,
-   0x58,0x8b,0x57,0x57,0x70,0x20,0x00,0x06,
-   0x01}}, /* 0x10 */
- {{0x7e,0x63,0x63,0x82,0x6b,0x13,0x75,0xf0,
-   0x58,0x8b,0x57,0x57,0x76,0x20,0x00,0x06,
-   0x01}}, /* 0x11 */
- {{0x81,0x63,0x63,0x85,0x6d,0x18,0x7a,0xf0,
-   0x58,0x8b,0x57,0x57,0x7b,0x20,0x00,0x06,
-   0x61}}, /* 0x12 */
- {{0x83,0x63,0x63,0x87,0x6e,0x19,0x81,0xf0,
-   0x58,0x8b,0x57,0x57,0x82,0x20,0x00,0x06,
-   0x61}}, /* 0x13 */
- {{0x85,0x63,0x63,0x89,0x6f,0x1a,0x91,0xf0,
-   0x58,0x8b,0x57,0x57,0x92,0x20,0x00,0x06,
-   0x61}}, /* 0x14 */
- {{0x99,0x7f,0x7f,0x9d,0x84,0x1a,0x96,0x1f,
-   0x7f,0x83,0x7f,0x7f,0x97,0x10,0x00,0x02,
-   0x00}}, /* 0x15 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-   0x01}}, /* 0x16 */
- {{0xa1,0x7f,0x7f,0x85,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-   0x01}}, /* 0x17 */
- {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf5,
-   0x00,0x83,0xff,0xff,0x1f,0x10,0x00,0x02,
-   0x01}}, /* 0x18 */
- {{0xa7,0x7f,0x7f,0x8b,0x89,0x95,0x26,0xf5,
-   0x00,0x83,0xff,0xff,0x27,0x10,0x00,0x02,
-   0x01}}, /* 0x19 */
- {{0xa9,0x7f,0x7f,0x8d,0x8c,0x9a,0x2c,0xf5,
-   0x00,0x83,0xff,0xff,0x2d,0x14,0x00,0x02,
-   0x62}}, /* 0x1a */
- {{0xab,0x7f,0x7f,0x8f,0x8d,0x9b,0x35,0xf5,
-   0x00,0x83,0xff,0xff,0x36,0x14,0x00,0x02,
-   0x62}}, /* 0x1b */
- {{0xcf,0x9f,0x9f,0x93,0xb2,0x01,0x14,0xba,
-   0x00,0x83,0xff,0xff,0x15,0x00,0x00,0x03,
-   0x00}}, /* 0x1c */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0x5a,
-   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
-   0x01}}, /* 0x1d */
- {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0x5a,
-   0x00,0x83,0xff,0xff,0x29,0x09,0x00,0x07,
-   0x01}}, /* 0x1e */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0x5a,
-   0x00,0x83,0xff,0xff,0x2f,0x09,0x00,0x07,
-   0x01}}, /* 0x1f */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x20 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x21 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x22 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x23 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x24 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x25 */
- {{0x09,0xc7,0xc7,0x8d,0xd3,0x0b,0xe0,0x10,
-   0xb0,0x83,0xaf,0xaf,0xe1,0x2f,0x01,0x04,
-   0x00}}, /* 0x26 */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-   0x00}}, /* 0x27 */
- {{0x43,0xef,0xef,0x87,0x06,0x00,0xd4,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xd5,0x1f,0x41,0x05,
-   0x63}}, /* 0x28 */
- {{0x45,0xef,0xef,0x89,0x07,0x01,0xd9,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xda,0x1f,0x41,0x05,
-   0x63}}, /* 0x29 */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-   0x00}}, /* 0x2a */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-   0x00}}, /* 0x2b */
- {{0x40,0xef,0xef,0x84,0x03,0x1d,0xda,0x1f,
-   0xa0,0x83,0x9f,0x9f,0xdb,0x1f,0x41,0x01,
-   0x00}}, /* 0x2c */
- {{0x59,0xff,0xff,0x9d,0x17,0x13,0x33,0xba,
-   0x00,0x83,0xff,0xff,0x34,0x0f,0x41,0x05,
-   0x44}}, /* 0x2d */
- {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x38,0xba,
-   0x00,0x83,0xff,0xff,0x39,0x0f,0x41,0x05,
-   0x44}}, /* 0x2e */
- {{0x5b,0xff,0xff,0x9f,0x18,0x14,0x3d,0xba,
-   0x00,0x83,0xff,0xff,0x3e,0x0f,0x41,0x05,
-   0x44}}, /* 0x2f */
- {{0x5d,0xff,0xff,0x81,0x19,0x95,0x41,0xba,
-   0x00,0x84,0xff,0xff,0x42,0x0f,0x41,0x05,
-   0x44}}, /* 0x30 */
- {{0x55,0xff,0xff,0x99,0x0d,0x0c,0x3e,0xba,
-   0x00,0x84,0xff,0xff,0x3f,0x0f,0x41,0x05,
-   0x00}}, /* 0x31 */
- {{0x7f,0x63,0x63,0x83,0x6c,0x1c,0x72,0xba,
-   0x27,0x8b,0xdf,0xdf,0x73,0x00,0x00,0x06,
-   0x01}}, /* 0x32 */
- {{0x7f,0x63,0x63,0x83,0x69,0x13,0x6f,0xba,
-   0x26,0x89,0xdf,0xdf,0x6f,0x00,0x00,0x06,
-   0x01}}, /* 0x33 */
- {{0x7f,0x63,0x63,0x82,0x6b,0x13,0x75,0xba,
-   0x29,0x8c,0xdf,0xdf,0x75,0x00,0x00,0x06,
-   0x01}}, /* 0x34 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf1,
-   0xaf,0x85,0x3f,0x3f,0x25,0x30,0x00,0x02,
-   0x01}}, /* 0x35 */
- {{0x9f,0x7f,0x7f,0x83,0x85,0x91,0x1e,0xf1,
-   0xad,0x81,0x3f,0x3f,0x1f,0x30,0x00,0x02,
-   0x01}}, /* 0x36 */
- {{0xa7,0x7f,0x7f,0x88,0x89,0x95,0x26,0xf1,
-   0xb1,0x85,0x3f,0x3f,0x27,0x30,0x00,0x02,
-   0x01}}, /* 0x37 */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x28,0xc4,
-   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
-   0x01}}, /* 0x38 */
- {{0xce,0x9f,0x9f,0x92,0xa5,0x17,0x28,0xd4,
-   0x7a,0x8e,0xcf,0xcf,0x29,0x21,0x00,0x07,
-   0x01}}, /* 0x39 */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0x2e,0xd4,
-   0x7d,0x81,0xcf,0xcf,0x2f,0x21,0x00,0x07,
-   0x01}}, /* 0x3a */
- {{0xdc,0x9f,0x9f,0x80,0xaf,0x9d,0xe6,0xff,
-   0xc0,0x83,0xbf,0xbf,0xe7,0x10,0x00,0x07,
-   0x01}}, /* 0x3b */
- {{0x6b,0x59,0x59,0x8f,0x5e,0x8c,0x0b,0x3e,
-   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x05,
-   0x00}}, /* 0x3c */
- {{0x6d,0x59,0x59,0x91,0x60,0x89,0x53,0xf0,
-   0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
-   0x41}}, /* 0x3d */
- {{0x86,0x6a,0x6a,0x8a,0x74,0x06,0x8c,0x15,
-   0x4f,0x83,0xef,0xef,0x8d,0x30,0x00,0x02,
-   0x00}}, /* 0x3e */
- {{0x81,0x6a,0x6a,0x85,0x70,0x00,0x0f,0x3e,
-   0xeb,0x8e,0xdf,0xdf,0x10,0x00,0x00,0x02,
-   0x00}}, /* 0x3f */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x1e,0xf1,
-   0xae,0x85,0x57,0x57,0x1f,0x30,0x00,0x02,
-   0x01}},  /* 0x40 */
- {{0xa3,0x7f,0x7f,0x87,0x86,0x97,0x24,0xf5,
-   0x02,0x88,0xff,0xff,0x25,0x10,0x00,0x02,
-   0x01}},  /* 0x41 */
- {{0xce,0x9f,0x9f,0x92,0xa9,0x17,0x20,0xf5,
-   0x03,0x88,0xff,0xff,0x21,0x10,0x00,0x07,
-   0x01}},  /* 0x42 */
- {{0xe6,0xae,0xae,0x8a,0xbd,0x90,0x3d,0x10,
-   0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x00,0x03,
-   0x00}},  /* 0x43 */
- {{0xc3,0x8f,0x8f,0x87,0x9b,0x0b,0x82,0xef,
-   0x60,0x83,0x5f,0x5f,0x83,0x10,0x00,0x07,
-   0x01}},  /* 0x44 */
- {{0x86,0x69,0x69,0x8A,0x74,0x06,0x8C,0x15,
-   0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
-   0x00}},  /* 0x45 */
- {{0x83,0x69,0x69,0x87,0x6f,0x1d,0x03,0x3E,
-   0xE5,0x8d,0xDF,0xe4,0x04,0x00,0x00,0x06,
-   0x00}},  /* 0x46 */
- {{0x86,0x6A,0x6A,0x8A,0x74,0x06,0x8C,0x15,
-   0x4F,0x83,0xEF,0xEF,0x8D,0x30,0x00,0x02,
-   0x00}},  /* 0x47 */
- {{0x81,0x6A,0x6A,0x85,0x70,0x00,0x0F,0x3E,
-   0xEB,0x8E,0xDF,0xDF,0x10,0x00,0x00,0x02,
-   0x00}},  /* 0x48 */
- {{0xdd,0xa9,0xa9,0x81,0xb4,0x97,0x26,0xfd,
-   0x01,0x8d,0xff,0x00,0x27,0x10,0x00,0x03,
-   0x01}},  /* 0x49 */
- {{0xd9,0x8f,0x8f,0x9d,0xba,0x0a,0x8a,0xff,
-   0x60,0x8b,0x5f,0x5f,0x8b,0x10,0x00,0x03,
-   0x01}},  /* 0x4a */
- {{0xea,0xae,0xae,0x8e,0xba,0x82,0x40,0x10,
-   0x1b,0x87,0x19,0x1a,0x41,0x0f,0x00,0x03,
-   0x00}},  /* 0x4b */
- {{0xd3,0x9f,0x9f,0x97,0xab,0x1f,0xf1,0xff,
-   0xc0,0x83,0xbf,0xbf,0xf2,0x10,0x00,0x07,
-   0x01}},  /* 0x4c */
- {{0x75,0x5f,0x5f,0x99,0x66,0x90,0x53,0xf0,
-   0x41,0x84,0x3f,0x3f,0x54,0x00,0x00,0x05,
-   0x41}},
- {{0x2d,0x27,0x28,0x90,0x2c,0x80,0x0b,0x3e,
-   0xe9,0x8b,0xdf,0xe7,0x04,0x00,0x00,0x00,
-   0x00}},  /* 0x4e */
- {{0xcd,0x9f,0x9f,0x91,0xab,0x1c,0x3a,0xff,
-   0x20,0x83,0x1f,0x1f,0x3b,0x10,0x00,0x07,
-   0x21}},  /* 0x4f */
- {{0x15,0xd1,0xd1,0x99,0xe2,0x19,0x3d,0x10,
-   0x1a,0x8d,0x19,0x19,0x3e,0x2f,0x01,0x0c,
-   0x20}},  /* 0x50 */
- {{0x0e,0xef,0xef,0x92,0xfe,0x03,0x30,0xf0,
-   0x1e,0x83,0x1b,0x1c,0x31,0x00,0x01,0x00,
-   0x61}},  /* 0x51 */
- {{0x85,0x77,0x77,0x89,0x7d,0x01,0x31,0xf0,
-   0x1e,0x84,0x1b,0x1c,0x32,0x00,0x00,0x02,
-   0x41}},  /* 0x52 */
- {{0x87,0x77,0x77,0x8b,0x81,0x0b,0x68,0xf0,
-   0x5a,0x80,0x57,0x57,0x69,0x00,0x00,0x02,
-   0x01}},  /* 0x53 */
- {{0xcd,0x8f,0x8f,0x91,0x9b,0x1b,0x7a,0xff,
-   0x64,0x8c,0x5f,0x62,0x7b,0x10,0x00,0x07,
-   0x41}}   /* 0x54 */
+static const struct SiS_CRT1Table SiSUSB_CRT1Table[] = {
+	{{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0xbf, 0x1f,
+	  0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x00,
+	  0x00}},		/* 0x0 */
+	{{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e,
+	  0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00,
+	  0x00}},		/* 0x1 */
+	{{0x3d, 0x31, 0x31, 0x81, 0x37, 0x1f, 0x72, 0xf0,
+	  0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x05,
+	  0x01}},		/* 0x2 */
+	{{0x4f, 0x3f, 0x3f, 0x93, 0x45, 0x0d, 0x24, 0xf5,
+	  0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x01,
+	  0x01}},		/* 0x3 */
+	{{0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f,
+	  0x9c, 0x8e, 0x8f, 0x96, 0xb9, 0x30, 0x00, 0x05,
+	  0x00}},		/* 0x4 */
+	{{0x5f, 0x4f, 0x4f, 0x83, 0x55, 0x81, 0x0b, 0x3e,
+	  0xe9, 0x8b, 0xdf, 0xe8, 0x0c, 0x00, 0x00, 0x05,
+	  0x00}},		/* 0x5 */
+	{{0x63, 0x4f, 0x4f, 0x87, 0x56, 0x9b, 0x06, 0x3e,
+	  0xe8, 0x8a, 0xdf, 0xe7, 0x07, 0x00, 0x00, 0x01,
+	  0x00}},		/* 0x6 */
+	{{0x64, 0x4f, 0x4f, 0x88, 0x55, 0x9d, 0xf2, 0x1f,
+	  0xe0, 0x83, 0xdf, 0xdf, 0xf3, 0x10, 0x00, 0x01,
+	  0x00}},		/* 0x7 */
+	{{0x63, 0x4f, 0x4f, 0x87, 0x5a, 0x81, 0xfb, 0x1f,
+	  0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05,
+	  0x00}},		/* 0x8 */
+	{{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0xfb, 0x1f,
+	  0xe0, 0x83, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x05,
+	  0x61}},		/* 0x9 */
+	{{0x65, 0x4f, 0x4f, 0x89, 0x58, 0x80, 0x01, 0x3e,
+	  0xe0, 0x83, 0xdf, 0xdf, 0x02, 0x00, 0x00, 0x05,
+	  0x61}},		/* 0xa */
+	{{0x67, 0x4f, 0x4f, 0x8b, 0x58, 0x81, 0x0d, 0x3e,
+	  0xe0, 0x83, 0xdf, 0xdf, 0x0e, 0x00, 0x00, 0x05,
+	  0x61}},		/* 0xb */
+	{{0x65, 0x4f, 0x4f, 0x89, 0x57, 0x9f, 0xfb, 0x1f,
+	  0xe6, 0x8a, 0xdf, 0xdf, 0xfc, 0x10, 0x00, 0x01,
+	  0x00}},		/* 0xc */
+	{{0x7b, 0x63, 0x63, 0x9f, 0x6a, 0x93, 0x6f, 0xf0,
+	  0x58, 0x8a, 0x57, 0x57, 0x70, 0x20, 0x00, 0x05,
+	  0x01}},		/* 0xd */
+	{{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xf0,
+	  0x58, 0x8c, 0x57, 0x57, 0x73, 0x20, 0x00, 0x06,
+	  0x01}},		/* 0xe */
+	{{0x7d, 0x63, 0x63, 0x81, 0x6e, 0x1d, 0x98, 0xf0,
+	  0x7c, 0x82, 0x57, 0x57, 0x99, 0x00, 0x00, 0x06,
+	  0x01}},		/* 0xf */
+	{{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xf0,
+	  0x58, 0x8b, 0x57, 0x57, 0x70, 0x20, 0x00, 0x06,
+	  0x01}},		/* 0x10 */
+	{{0x7e, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xf0,
+	  0x58, 0x8b, 0x57, 0x57, 0x76, 0x20, 0x00, 0x06,
+	  0x01}},		/* 0x11 */
+	{{0x81, 0x63, 0x63, 0x85, 0x6d, 0x18, 0x7a, 0xf0,
+	  0x58, 0x8b, 0x57, 0x57, 0x7b, 0x20, 0x00, 0x06,
+	  0x61}},		/* 0x12 */
+	{{0x83, 0x63, 0x63, 0x87, 0x6e, 0x19, 0x81, 0xf0,
+	  0x58, 0x8b, 0x57, 0x57, 0x82, 0x20, 0x00, 0x06,
+	  0x61}},		/* 0x13 */
+	{{0x85, 0x63, 0x63, 0x89, 0x6f, 0x1a, 0x91, 0xf0,
+	  0x58, 0x8b, 0x57, 0x57, 0x92, 0x20, 0x00, 0x06,
+	  0x61}},		/* 0x14 */
+	{{0x99, 0x7f, 0x7f, 0x9d, 0x84, 0x1a, 0x96, 0x1f,
+	  0x7f, 0x83, 0x7f, 0x7f, 0x97, 0x10, 0x00, 0x02,
+	  0x00}},		/* 0x15 */
+	{{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5,
+	  0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+	  0x01}},		/* 0x16 */
+	{{0xa1, 0x7f, 0x7f, 0x85, 0x86, 0x97, 0x24, 0xf5,
+	  0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+	  0x01}},		/* 0x17 */
+	{{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf5,
+	  0x00, 0x83, 0xff, 0xff, 0x1f, 0x10, 0x00, 0x02,
+	  0x01}},		/* 0x18 */
+	{{0xa7, 0x7f, 0x7f, 0x8b, 0x89, 0x95, 0x26, 0xf5,
+	  0x00, 0x83, 0xff, 0xff, 0x27, 0x10, 0x00, 0x02,
+	  0x01}},		/* 0x19 */
+	{{0xa9, 0x7f, 0x7f, 0x8d, 0x8c, 0x9a, 0x2c, 0xf5,
+	  0x00, 0x83, 0xff, 0xff, 0x2d, 0x14, 0x00, 0x02,
+	  0x62}},		/* 0x1a */
+	{{0xab, 0x7f, 0x7f, 0x8f, 0x8d, 0x9b, 0x35, 0xf5,
+	  0x00, 0x83, 0xff, 0xff, 0x36, 0x14, 0x00, 0x02,
+	  0x62}},		/* 0x1b */
+	{{0xcf, 0x9f, 0x9f, 0x93, 0xb2, 0x01, 0x14, 0xba,
+	  0x00, 0x83, 0xff, 0xff, 0x15, 0x00, 0x00, 0x03,
+	  0x00}},		/* 0x1c */
+	{{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0x5a,
+	  0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07,
+	  0x01}},		/* 0x1d */
+	{{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0x5a,
+	  0x00, 0x83, 0xff, 0xff, 0x29, 0x09, 0x00, 0x07,
+	  0x01}},		/* 0x1e */
+	{{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0x5a,
+	  0x00, 0x83, 0xff, 0xff, 0x2f, 0x09, 0x00, 0x07,
+	  0x01}},		/* 0x1f */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x20 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x21 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x22 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x23 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x24 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x25 */
+	{{0x09, 0xc7, 0xc7, 0x8d, 0xd3, 0x0b, 0xe0, 0x10,
+	  0xb0, 0x83, 0xaf, 0xaf, 0xe1, 0x2f, 0x01, 0x04,
+	  0x00}},		/* 0x26 */
+	{{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+	  0x00}},		/* 0x27 */
+	{{0x43, 0xef, 0xef, 0x87, 0x06, 0x00, 0xd4, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xd5, 0x1f, 0x41, 0x05,
+	  0x63}},		/* 0x28 */
+	{{0x45, 0xef, 0xef, 0x89, 0x07, 0x01, 0xd9, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xda, 0x1f, 0x41, 0x05,
+	  0x63}},		/* 0x29 */
+	{{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+	  0x00}},		/* 0x2a */
+	{{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+	  0x00}},		/* 0x2b */
+	{{0x40, 0xef, 0xef, 0x84, 0x03, 0x1d, 0xda, 0x1f,
+	  0xa0, 0x83, 0x9f, 0x9f, 0xdb, 0x1f, 0x41, 0x01,
+	  0x00}},		/* 0x2c */
+	{{0x59, 0xff, 0xff, 0x9d, 0x17, 0x13, 0x33, 0xba,
+	  0x00, 0x83, 0xff, 0xff, 0x34, 0x0f, 0x41, 0x05,
+	  0x44}},		/* 0x2d */
+	{{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x38, 0xba,
+	  0x00, 0x83, 0xff, 0xff, 0x39, 0x0f, 0x41, 0x05,
+	  0x44}},		/* 0x2e */
+	{{0x5b, 0xff, 0xff, 0x9f, 0x18, 0x14, 0x3d, 0xba,
+	  0x00, 0x83, 0xff, 0xff, 0x3e, 0x0f, 0x41, 0x05,
+	  0x44}},		/* 0x2f */
+	{{0x5d, 0xff, 0xff, 0x81, 0x19, 0x95, 0x41, 0xba,
+	  0x00, 0x84, 0xff, 0xff, 0x42, 0x0f, 0x41, 0x05,
+	  0x44}},		/* 0x30 */
+	{{0x55, 0xff, 0xff, 0x99, 0x0d, 0x0c, 0x3e, 0xba,
+	  0x00, 0x84, 0xff, 0xff, 0x3f, 0x0f, 0x41, 0x05,
+	  0x00}},		/* 0x31 */
+	{{0x7f, 0x63, 0x63, 0x83, 0x6c, 0x1c, 0x72, 0xba,
+	  0x27, 0x8b, 0xdf, 0xdf, 0x73, 0x00, 0x00, 0x06,
+	  0x01}},		/* 0x32 */
+	{{0x7f, 0x63, 0x63, 0x83, 0x69, 0x13, 0x6f, 0xba,
+	  0x26, 0x89, 0xdf, 0xdf, 0x6f, 0x00, 0x00, 0x06,
+	  0x01}},		/* 0x33 */
+	{{0x7f, 0x63, 0x63, 0x82, 0x6b, 0x13, 0x75, 0xba,
+	  0x29, 0x8c, 0xdf, 0xdf, 0x75, 0x00, 0x00, 0x06,
+	  0x01}},		/* 0x34 */
+	{{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf1,
+	  0xaf, 0x85, 0x3f, 0x3f, 0x25, 0x30, 0x00, 0x02,
+	  0x01}},		/* 0x35 */
+	{{0x9f, 0x7f, 0x7f, 0x83, 0x85, 0x91, 0x1e, 0xf1,
+	  0xad, 0x81, 0x3f, 0x3f, 0x1f, 0x30, 0x00, 0x02,
+	  0x01}},		/* 0x36 */
+	{{0xa7, 0x7f, 0x7f, 0x88, 0x89, 0x95, 0x26, 0xf1,
+	  0xb1, 0x85, 0x3f, 0x3f, 0x27, 0x30, 0x00, 0x02,
+	  0x01}},		/* 0x37 */
+	{{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x28, 0xc4,
+	  0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07,
+	  0x01}},		/* 0x38 */
+	{{0xce, 0x9f, 0x9f, 0x92, 0xa5, 0x17, 0x28, 0xd4,
+	  0x7a, 0x8e, 0xcf, 0xcf, 0x29, 0x21, 0x00, 0x07,
+	  0x01}},		/* 0x39 */
+	{{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0x2e, 0xd4,
+	  0x7d, 0x81, 0xcf, 0xcf, 0x2f, 0x21, 0x00, 0x07,
+	  0x01}},		/* 0x3a */
+	{{0xdc, 0x9f, 0x9f, 0x80, 0xaf, 0x9d, 0xe6, 0xff,
+	  0xc0, 0x83, 0xbf, 0xbf, 0xe7, 0x10, 0x00, 0x07,
+	  0x01}},		/* 0x3b */
+	{{0x6b, 0x59, 0x59, 0x8f, 0x5e, 0x8c, 0x0b, 0x3e,
+	  0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x05,
+	  0x00}},		/* 0x3c */
+	{{0x6d, 0x59, 0x59, 0x91, 0x60, 0x89, 0x53, 0xf0,
+	  0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05,
+	  0x41}},		/* 0x3d */
+	{{0x86, 0x6a, 0x6a, 0x8a, 0x74, 0x06, 0x8c, 0x15,
+	  0x4f, 0x83, 0xef, 0xef, 0x8d, 0x30, 0x00, 0x02,
+	  0x00}},		/* 0x3e */
+	{{0x81, 0x6a, 0x6a, 0x85, 0x70, 0x00, 0x0f, 0x3e,
+	  0xeb, 0x8e, 0xdf, 0xdf, 0x10, 0x00, 0x00, 0x02,
+	  0x00}},		/* 0x3f */
+	{{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x1e, 0xf1,
+	  0xae, 0x85, 0x57, 0x57, 0x1f, 0x30, 0x00, 0x02,
+	  0x01}},		/* 0x40 */
+	{{0xa3, 0x7f, 0x7f, 0x87, 0x86, 0x97, 0x24, 0xf5,
+	  0x02, 0x88, 0xff, 0xff, 0x25, 0x10, 0x00, 0x02,
+	  0x01}},		/* 0x41 */
+	{{0xce, 0x9f, 0x9f, 0x92, 0xa9, 0x17, 0x20, 0xf5,
+	  0x03, 0x88, 0xff, 0xff, 0x21, 0x10, 0x00, 0x07,
+	  0x01}},		/* 0x42 */
+	{{0xe6, 0xae, 0xae, 0x8a, 0xbd, 0x90, 0x3d, 0x10,
+	  0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x00, 0x03,
+	  0x00}},		/* 0x43 */
+	{{0xc3, 0x8f, 0x8f, 0x87, 0x9b, 0x0b, 0x82, 0xef,
+	  0x60, 0x83, 0x5f, 0x5f, 0x83, 0x10, 0x00, 0x07,
+	  0x01}},		/* 0x44 */
+	{{0x86, 0x69, 0x69, 0x8A, 0x74, 0x06, 0x8C, 0x15,
+	  0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02,
+	  0x00}},		/* 0x45 */
+	{{0x83, 0x69, 0x69, 0x87, 0x6f, 0x1d, 0x03, 0x3E,
+	  0xE5, 0x8d, 0xDF, 0xe4, 0x04, 0x00, 0x00, 0x06,
+	  0x00}},		/* 0x46 */
+	{{0x86, 0x6A, 0x6A, 0x8A, 0x74, 0x06, 0x8C, 0x15,
+	  0x4F, 0x83, 0xEF, 0xEF, 0x8D, 0x30, 0x00, 0x02,
+	  0x00}},		/* 0x47 */
+	{{0x81, 0x6A, 0x6A, 0x85, 0x70, 0x00, 0x0F, 0x3E,
+	  0xEB, 0x8E, 0xDF, 0xDF, 0x10, 0x00, 0x00, 0x02,
+	  0x00}},		/* 0x48 */
+	{{0xdd, 0xa9, 0xa9, 0x81, 0xb4, 0x97, 0x26, 0xfd,
+	  0x01, 0x8d, 0xff, 0x00, 0x27, 0x10, 0x00, 0x03,
+	  0x01}},		/* 0x49 */
+	{{0xd9, 0x8f, 0x8f, 0x9d, 0xba, 0x0a, 0x8a, 0xff,
+	  0x60, 0x8b, 0x5f, 0x5f, 0x8b, 0x10, 0x00, 0x03,
+	  0x01}},		/* 0x4a */
+	{{0xea, 0xae, 0xae, 0x8e, 0xba, 0x82, 0x40, 0x10,
+	  0x1b, 0x87, 0x19, 0x1a, 0x41, 0x0f, 0x00, 0x03,
+	  0x00}},		/* 0x4b */
+	{{0xd3, 0x9f, 0x9f, 0x97, 0xab, 0x1f, 0xf1, 0xff,
+	  0xc0, 0x83, 0xbf, 0xbf, 0xf2, 0x10, 0x00, 0x07,
+	  0x01}},		/* 0x4c */
+	{{0x75, 0x5f, 0x5f, 0x99, 0x66, 0x90, 0x53, 0xf0,
+	  0x41, 0x84, 0x3f, 0x3f, 0x54, 0x00, 0x00, 0x05,
+	  0x41}},
+	{{0x2d, 0x27, 0x28, 0x90, 0x2c, 0x80, 0x0b, 0x3e,
+	  0xe9, 0x8b, 0xdf, 0xe7, 0x04, 0x00, 0x00, 0x00,
+	  0x00}},		/* 0x4e */
+	{{0xcd, 0x9f, 0x9f, 0x91, 0xab, 0x1c, 0x3a, 0xff,
+	  0x20, 0x83, 0x1f, 0x1f, 0x3b, 0x10, 0x00, 0x07,
+	  0x21}},		/* 0x4f */
+	{{0x15, 0xd1, 0xd1, 0x99, 0xe2, 0x19, 0x3d, 0x10,
+	  0x1a, 0x8d, 0x19, 0x19, 0x3e, 0x2f, 0x01, 0x0c,
+	  0x20}},		/* 0x50 */
+	{{0x0e, 0xef, 0xef, 0x92, 0xfe, 0x03, 0x30, 0xf0,
+	  0x1e, 0x83, 0x1b, 0x1c, 0x31, 0x00, 0x01, 0x00,
+	  0x61}},		/* 0x51 */
+	{{0x85, 0x77, 0x77, 0x89, 0x7d, 0x01, 0x31, 0xf0,
+	  0x1e, 0x84, 0x1b, 0x1c, 0x32, 0x00, 0x00, 0x02,
+	  0x41}},		/* 0x52 */
+	{{0x87, 0x77, 0x77, 0x8b, 0x81, 0x0b, 0x68, 0xf0,
+	  0x5a, 0x80, 0x57, 0x57, 0x69, 0x00, 0x00, 0x02,
+	  0x01}},		/* 0x53 */
+	{{0xcd, 0x8f, 0x8f, 0x91, 0x9b, 0x1b, 0x7a, 0xff,
+	  0x64, 0x8c, 0x5f, 0x62, 0x7b, 0x10, 0x00, 0x07,
+	  0x41}}		/* 0x54 */
 };
 
-static const struct SiS_VCLKData SiSUSB_VCLKData[] =
-{
-	{ 0x1b,0xe1, 25}, /* 0x00 */
-	{ 0x4e,0xe4, 28}, /* 0x01 */
-	{ 0x57,0xe4, 31}, /* 0x02 */
-	{ 0xc3,0xc8, 36}, /* 0x03 */
-	{ 0x42,0xe2, 40}, /* 0x04 */
-	{ 0xfe,0xcd, 43}, /* 0x05 */
-	{ 0x5d,0xc4, 44}, /* 0x06 */
-	{ 0x52,0xe2, 49}, /* 0x07 */
-	{ 0x53,0xe2, 50}, /* 0x08 */
-	{ 0x74,0x67, 52}, /* 0x09 */
-	{ 0x6d,0x66, 56}, /* 0x0a */
-	{ 0x5a,0x64, 65}, /* 0x0b */
-	{ 0x46,0x44, 67}, /* 0x0c */
-	{ 0xb1,0x46, 68}, /* 0x0d */
-	{ 0xd3,0x4a, 72}, /* 0x0e */
-	{ 0x29,0x61, 75}, /* 0x0f */
-	{ 0x6e,0x46, 76}, /* 0x10 */
-	{ 0x2b,0x61, 78}, /* 0x11 */
-	{ 0x31,0x42, 79}, /* 0x12 */
-	{ 0xab,0x44, 83}, /* 0x13 */
-	{ 0x46,0x25, 84}, /* 0x14 */
-	{ 0x78,0x29, 86}, /* 0x15 */
-	{ 0x62,0x44, 94}, /* 0x16 */
-	{ 0x2b,0x41,104}, /* 0x17 */
-	{ 0x3a,0x23,105}, /* 0x18 */
-	{ 0x70,0x44,108}, /* 0x19 */
-	{ 0x3c,0x23,109}, /* 0x1a */
-	{ 0x5e,0x43,113}, /* 0x1b */
-	{ 0xbc,0x44,116}, /* 0x1c */
-	{ 0xe0,0x46,132}, /* 0x1d */
-	{ 0x54,0x42,135}, /* 0x1e */
-	{ 0xea,0x2a,139}, /* 0x1f */
-	{ 0x41,0x22,157}, /* 0x20 */
-	{ 0x70,0x24,162}, /* 0x21 */
-	{ 0x30,0x21,175}, /* 0x22 */
-	{ 0x4e,0x22,189}, /* 0x23 */
-	{ 0xde,0x26,194}, /* 0x24 */
-	{ 0x62,0x06,202}, /* 0x25 */
-	{ 0x3f,0x03,229}, /* 0x26 */
-	{ 0xb8,0x06,234}, /* 0x27 */
-	{ 0x34,0x02,253}, /* 0x28 */
-	{ 0x58,0x04,255}, /* 0x29 */
-	{ 0x24,0x01,265}, /* 0x2a */
-	{ 0x9b,0x02,267}, /* 0x2b */
-	{ 0x70,0x05,270}, /* 0x2c */
-	{ 0x25,0x01,272}, /* 0x2d */
-	{ 0x9c,0x02,277}, /* 0x2e */
-	{ 0x27,0x01,286}, /* 0x2f */
-	{ 0x3c,0x02,291}, /* 0x30 */
-	{ 0xef,0x0a,292}, /* 0x31 */
-	{ 0xf6,0x0a,310}, /* 0x32 */
-	{ 0x95,0x01,315}, /* 0x33 */
-	{ 0xf0,0x09,324}, /* 0x34 */
-	{ 0xfe,0x0a,331}, /* 0x35 */
-	{ 0xf3,0x09,332}, /* 0x36 */
-	{ 0xea,0x08,340}, /* 0x37 */
-	{ 0xe8,0x07,376}, /* 0x38 */
-	{ 0xde,0x06,389}, /* 0x39 */
-	{ 0x52,0x2a, 54}, /* 0x3a 301 TV */
-	{ 0x52,0x6a, 27}, /* 0x3b 301 TV */
-	{ 0x62,0x24, 70}, /* 0x3c 301 TV */
-	{ 0x62,0x64, 70}, /* 0x3d 301 TV */
-	{ 0xa8,0x4c, 30}, /* 0x3e 301 TV */
-	{ 0x20,0x26, 33}, /* 0x3f 301 TV */
-	{ 0x31,0xc2, 39}, /* 0x40 */
-	{ 0x60,0x36, 30}, /* 0x41 Chrontel */
-	{ 0x40,0x4a, 28}, /* 0x42 Chrontel */
-	{ 0x9f,0x46, 44}, /* 0x43 Chrontel */
-	{ 0x97,0x2c, 26}, /* 0x44 */
-	{ 0x44,0xe4, 25}, /* 0x45 Chrontel */
-	{ 0x7e,0x32, 47}, /* 0x46 Chrontel */
-	{ 0x8a,0x24, 31}, /* 0x47 Chrontel */
-	{ 0x97,0x2c, 26}, /* 0x48 Chrontel */
-	{ 0xce,0x3c, 39}, /* 0x49 */
-	{ 0x52,0x4a, 36}, /* 0x4a Chrontel */
-	{ 0x34,0x61, 95}, /* 0x4b */
-	{ 0x78,0x27,108}, /* 0x4c - was 102 */
-	{ 0x66,0x43,123}, /* 0x4d Modes 0x26-0x28 (1400x1050) */
-	{ 0x41,0x4e, 21}, /* 0x4e */
-	{ 0xa1,0x4a, 29}, /* 0x4f Chrontel */
-	{ 0x19,0x42, 42}, /* 0x50 */
-	{ 0x54,0x46, 58}, /* 0x51 Chrontel */
-	{ 0x25,0x42, 61}, /* 0x52 */
-	{ 0x44,0x44, 66}, /* 0x53 Chrontel */
-	{ 0x3a,0x62, 70}, /* 0x54 Chrontel */
-	{ 0x62,0xc6, 34}, /* 0x55 848x480-60 */
-	{ 0x6a,0xc6, 37}, /* 0x56 848x480-75 - TEMP */
-	{ 0xbf,0xc8, 35}, /* 0x57 856x480-38i,60 */
-	{ 0x30,0x23, 88}, /* 0x58 1360x768-62 (is 60Hz!) */
-	{ 0x52,0x07,149}, /* 0x59 1280x960-85 */
-	{ 0x56,0x07,156}, /* 0x5a 1400x1050-75 */
-	{ 0x70,0x29, 81}, /* 0x5b 1280x768 LCD */
-	{ 0x45,0x25, 83}, /* 0x5c 1280x800  */
-	{ 0x70,0x0a,147}, /* 0x5d 1680x1050 */
-	{ 0x70,0x24,162}, /* 0x5e 1600x1200 */
-	{ 0x5a,0x64, 65}, /* 0x5f 1280x720 - temp */
-	{ 0x63,0x46, 68}, /* 0x60 1280x768_2 */
-	{ 0x31,0x42, 79}, /* 0x61 1280x768_3 - temp */
-	{    0,   0,  0}, /* 0x62 - custom (will be filled out at run-time) */
-	{ 0x5a,0x64, 65}, /* 0x63 1280x720 (LCD LVDS) */
-	{ 0x70,0x28, 90}, /* 0x64 1152x864@60 */
-	{ 0x41,0xc4, 32}, /* 0x65 848x480@60 */
-	{ 0x5c,0xc6, 32}, /* 0x66 856x480@60 */
-	{ 0x76,0xe7, 27}, /* 0x67 720x480@60 */
-	{ 0x5f,0xc6, 33}, /* 0x68 720/768x576@60 */
-	{ 0x52,0x27, 75}, /* 0x69 1920x1080i 60Hz interlaced */
-	{ 0x7c,0x6b, 38}, /* 0x6a 960x540@60 */
-	{ 0xe3,0x56, 41}, /* 0x6b 960x600@60 */
-	{ 0x45,0x25, 83}, /* 0x6c 1280x800 */
-	{ 0x70,0x28, 90}, /* 0x6d 1152x864@60 */
-	{ 0x15,0xe1, 20}, /* 0x6e 640x400@60 (fake, not actually used) */
-	{ 0x5f,0xc6, 33}, /* 0x6f 720x576@60 */
-	{ 0x37,0x5a, 10}, /* 0x70 320x200@60 (fake, not actually used) */
-	{ 0x2b,0xc2, 35}  /* 0x71 768@576@60 */
+static const struct SiS_VCLKData SiSUSB_VCLKData[] = {
+	{0x1b, 0xe1, 25},	/* 0x00 */
+	{0x4e, 0xe4, 28},	/* 0x01 */
+	{0x57, 0xe4, 31},	/* 0x02 */
+	{0xc3, 0xc8, 36},	/* 0x03 */
+	{0x42, 0xe2, 40},	/* 0x04 */
+	{0xfe, 0xcd, 43},	/* 0x05 */
+	{0x5d, 0xc4, 44},	/* 0x06 */
+	{0x52, 0xe2, 49},	/* 0x07 */
+	{0x53, 0xe2, 50},	/* 0x08 */
+	{0x74, 0x67, 52},	/* 0x09 */
+	{0x6d, 0x66, 56},	/* 0x0a */
+	{0x5a, 0x64, 65},	/* 0x0b */
+	{0x46, 0x44, 67},	/* 0x0c */
+	{0xb1, 0x46, 68},	/* 0x0d */
+	{0xd3, 0x4a, 72},	/* 0x0e */
+	{0x29, 0x61, 75},	/* 0x0f */
+	{0x6e, 0x46, 76},	/* 0x10 */
+	{0x2b, 0x61, 78},	/* 0x11 */
+	{0x31, 0x42, 79},	/* 0x12 */
+	{0xab, 0x44, 83},	/* 0x13 */
+	{0x46, 0x25, 84},	/* 0x14 */
+	{0x78, 0x29, 86},	/* 0x15 */
+	{0x62, 0x44, 94},	/* 0x16 */
+	{0x2b, 0x41, 104},	/* 0x17 */
+	{0x3a, 0x23, 105},	/* 0x18 */
+	{0x70, 0x44, 108},	/* 0x19 */
+	{0x3c, 0x23, 109},	/* 0x1a */
+	{0x5e, 0x43, 113},	/* 0x1b */
+	{0xbc, 0x44, 116},	/* 0x1c */
+	{0xe0, 0x46, 132},	/* 0x1d */
+	{0x54, 0x42, 135},	/* 0x1e */
+	{0xea, 0x2a, 139},	/* 0x1f */
+	{0x41, 0x22, 157},	/* 0x20 */
+	{0x70, 0x24, 162},	/* 0x21 */
+	{0x30, 0x21, 175},	/* 0x22 */
+	{0x4e, 0x22, 189},	/* 0x23 */
+	{0xde, 0x26, 194},	/* 0x24 */
+	{0x62, 0x06, 202},	/* 0x25 */
+	{0x3f, 0x03, 229},	/* 0x26 */
+	{0xb8, 0x06, 234},	/* 0x27 */
+	{0x34, 0x02, 253},	/* 0x28 */
+	{0x58, 0x04, 255},	/* 0x29 */
+	{0x24, 0x01, 265},	/* 0x2a */
+	{0x9b, 0x02, 267},	/* 0x2b */
+	{0x70, 0x05, 270},	/* 0x2c */
+	{0x25, 0x01, 272},	/* 0x2d */
+	{0x9c, 0x02, 277},	/* 0x2e */
+	{0x27, 0x01, 286},	/* 0x2f */
+	{0x3c, 0x02, 291},	/* 0x30 */
+	{0xef, 0x0a, 292},	/* 0x31 */
+	{0xf6, 0x0a, 310},	/* 0x32 */
+	{0x95, 0x01, 315},	/* 0x33 */
+	{0xf0, 0x09, 324},	/* 0x34 */
+	{0xfe, 0x0a, 331},	/* 0x35 */
+	{0xf3, 0x09, 332},	/* 0x36 */
+	{0xea, 0x08, 340},	/* 0x37 */
+	{0xe8, 0x07, 376},	/* 0x38 */
+	{0xde, 0x06, 389},	/* 0x39 */
+	{0x52, 0x2a, 54},	/* 0x3a 301 TV */
+	{0x52, 0x6a, 27},	/* 0x3b 301 TV */
+	{0x62, 0x24, 70},	/* 0x3c 301 TV */
+	{0x62, 0x64, 70},	/* 0x3d 301 TV */
+	{0xa8, 0x4c, 30},	/* 0x3e 301 TV */
+	{0x20, 0x26, 33},	/* 0x3f 301 TV */
+	{0x31, 0xc2, 39},	/* 0x40 */
+	{0x60, 0x36, 30},	/* 0x41 Chrontel */
+	{0x40, 0x4a, 28},	/* 0x42 Chrontel */
+	{0x9f, 0x46, 44},	/* 0x43 Chrontel */
+	{0x97, 0x2c, 26},	/* 0x44 */
+	{0x44, 0xe4, 25},	/* 0x45 Chrontel */
+	{0x7e, 0x32, 47},	/* 0x46 Chrontel */
+	{0x8a, 0x24, 31},	/* 0x47 Chrontel */
+	{0x97, 0x2c, 26},	/* 0x48 Chrontel */
+	{0xce, 0x3c, 39},	/* 0x49 */
+	{0x52, 0x4a, 36},	/* 0x4a Chrontel */
+	{0x34, 0x61, 95},	/* 0x4b */
+	{0x78, 0x27, 108},	/* 0x4c - was 102 */
+	{0x66, 0x43, 123},	/* 0x4d Modes 0x26-0x28 (1400x1050) */
+	{0x41, 0x4e, 21},	/* 0x4e */
+	{0xa1, 0x4a, 29},	/* 0x4f Chrontel */
+	{0x19, 0x42, 42},	/* 0x50 */
+	{0x54, 0x46, 58},	/* 0x51 Chrontel */
+	{0x25, 0x42, 61},	/* 0x52 */
+	{0x44, 0x44, 66},	/* 0x53 Chrontel */
+	{0x3a, 0x62, 70},	/* 0x54 Chrontel */
+	{0x62, 0xc6, 34},	/* 0x55 848x480-60 */
+	{0x6a, 0xc6, 37},	/* 0x56 848x480-75 - TEMP */
+	{0xbf, 0xc8, 35},	/* 0x57 856x480-38i,60 */
+	{0x30, 0x23, 88},	/* 0x58 1360x768-62 (is 60Hz!) */
+	{0x52, 0x07, 149},	/* 0x59 1280x960-85 */
+	{0x56, 0x07, 156},	/* 0x5a 1400x1050-75 */
+	{0x70, 0x29, 81},	/* 0x5b 1280x768 LCD */
+	{0x45, 0x25, 83},	/* 0x5c 1280x800  */
+	{0x70, 0x0a, 147},	/* 0x5d 1680x1050 */
+	{0x70, 0x24, 162},	/* 0x5e 1600x1200 */
+	{0x5a, 0x64, 65},	/* 0x5f 1280x720 - temp */
+	{0x63, 0x46, 68},	/* 0x60 1280x768_2 */
+	{0x31, 0x42, 79},	/* 0x61 1280x768_3 - temp */
+	{0, 0, 0},		/* 0x62 - custom (will be filled out at run-time) */
+	{0x5a, 0x64, 65},	/* 0x63 1280x720 (LCD LVDS) */
+	{0x70, 0x28, 90},	/* 0x64 1152x864@60 */
+	{0x41, 0xc4, 32},	/* 0x65 848x480@60 */
+	{0x5c, 0xc6, 32},	/* 0x66 856x480@60 */
+	{0x76, 0xe7, 27},	/* 0x67 720x480@60 */
+	{0x5f, 0xc6, 33},	/* 0x68 720/768x576@60 */
+	{0x52, 0x27, 75},	/* 0x69 1920x1080i 60Hz interlaced */
+	{0x7c, 0x6b, 38},	/* 0x6a 960x540@60 */
+	{0xe3, 0x56, 41},	/* 0x6b 960x600@60 */
+	{0x45, 0x25, 83},	/* 0x6c 1280x800 */
+	{0x70, 0x28, 90},	/* 0x6d 1152x864@60 */
+	{0x15, 0xe1, 20},	/* 0x6e 640x400@60 (fake, not actually used) */
+	{0x5f, 0xc6, 33},	/* 0x6f 720x576@60 */
+	{0x37, 0x5a, 10},	/* 0x70 320x200@60 (fake, not actually used) */
+	{0x2b, 0xc2, 35}	/* 0x71 768@576@60 */
 };
 
-int		SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
-int		SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
+int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
+int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
 
-extern int	sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
-extern int	sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 *data);
-extern int	sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
-					u8 index, u8 data);
-extern int	sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
-					u8 index, u8 *data);
-extern int	sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
-					u8 idx,	u8 myand, u8 myor);
-extern int	sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
-					u8 index, u8 myor);
-extern int	sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
-					u8 idx, u8 myand);
+extern int sisusb_setreg(struct sisusb_usb_data *sisusb, int port, u8 data);
+extern int sisusb_getreg(struct sisusb_usb_data *sisusb, int port, u8 * data);
+extern int sisusb_setidxreg(struct sisusb_usb_data *sisusb, int port,
+			    u8 index, u8 data);
+extern int sisusb_getidxreg(struct sisusb_usb_data *sisusb, int port,
+			    u8 index, u8 * data);
+extern int sisusb_setidxregandor(struct sisusb_usb_data *sisusb, int port,
+				 u8 idx, u8 myand, u8 myor);
+extern int sisusb_setidxregor(struct sisusb_usb_data *sisusb, int port,
+			      u8 index, u8 myor);
+extern int sisusb_setidxregand(struct sisusb_usb_data *sisusb, int port,
+			       u8 idx, u8 myand);
 
 void sisusb_delete(struct kref *kref);
 int sisusb_writeb(struct sisusb_usb_data *sisusb, u32 adr, u8 data);
-int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data);
+int sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 * data);
 int sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
-		       u32 dest, int length, size_t *bytes_written);
+		       u32 dest, int length, size_t * bytes_written);
 int sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init);
 int sisusbcon_do_font_op(struct sisusb_usb_data *sisusb, int set, int slot,
-			 u8 *arg, int cmapsz, int ch512, int dorecalc,
+			 u8 * arg, int cmapsz, int ch512, int dorecalc,
 			 struct vc_data *c, int fh, int uplock);
 void sisusb_set_cursor(struct sisusb_usb_data *sisusb, unsigned int location);
 int sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last);
@@ -839,4 +839,3 @@
 void sisusb_init_concode(void);
 
 #endif
-
diff --git a/drivers/usb/misc/sisusbvga/sisusb_struct.h b/drivers/usb/misc/sisusbvga/sisusb_struct.h
index f325ecb..1c4240e 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_struct.h
+++ b/drivers/usb/misc/sisusbvga/sisusb_struct.h
@@ -44,7 +44,7 @@
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
@@ -52,85 +52,78 @@
 #define _SISUSB_STRUCT_H_
 
 struct SiS_St {
-	unsigned char	St_ModeID;
-	unsigned short	St_ModeFlag;
-	unsigned char	St_StTableIndex;
-	unsigned char	St_CRT2CRTC;
-	unsigned char	St_ResInfo;
-	unsigned char	VB_StTVFlickerIndex;
-	unsigned char	VB_StTVEdgeIndex;
-	unsigned char	VB_StTVYFilterIndex;
-	unsigned char	St_PDC;
+	unsigned char St_ModeID;
+	unsigned short St_ModeFlag;
+	unsigned char St_StTableIndex;
+	unsigned char St_CRT2CRTC;
+	unsigned char St_ResInfo;
+	unsigned char VB_StTVFlickerIndex;
+	unsigned char VB_StTVEdgeIndex;
+	unsigned char VB_StTVYFilterIndex;
+	unsigned char St_PDC;
 };
 
-struct SiS_StandTable
-{
-	unsigned char	CRT_COLS;
-	unsigned char	ROWS;
-	unsigned char	CHAR_HEIGHT;
-	unsigned short	CRT_LEN;
-	unsigned char	SR[4];
-	unsigned char	MISC;
-	unsigned char	CRTC[0x19];
-	unsigned char	ATTR[0x14];
-	unsigned char	GRC[9];
+struct SiS_StandTable {
+	unsigned char CRT_COLS;
+	unsigned char ROWS;
+	unsigned char CHAR_HEIGHT;
+	unsigned short CRT_LEN;
+	unsigned char SR[4];
+	unsigned char MISC;
+	unsigned char CRTC[0x19];
+	unsigned char ATTR[0x14];
+	unsigned char GRC[9];
 };
 
 struct SiS_StResInfo_S {
-	unsigned short	HTotal;
-	unsigned short	VTotal;
+	unsigned short HTotal;
+	unsigned short VTotal;
 };
 
-struct SiS_Ext
-{
-	unsigned char	Ext_ModeID;
-	unsigned short	Ext_ModeFlag;
-	unsigned short	Ext_VESAID;
-	unsigned char	Ext_RESINFO;
-	unsigned char	VB_ExtTVFlickerIndex;
-	unsigned char	VB_ExtTVEdgeIndex;
-	unsigned char	VB_ExtTVYFilterIndex;
-	unsigned char	VB_ExtTVYFilterIndexROM661;
-	unsigned char	REFindex;
-	char		ROMMODEIDX661;
+struct SiS_Ext {
+	unsigned char Ext_ModeID;
+	unsigned short Ext_ModeFlag;
+	unsigned short Ext_VESAID;
+	unsigned char Ext_RESINFO;
+	unsigned char VB_ExtTVFlickerIndex;
+	unsigned char VB_ExtTVEdgeIndex;
+	unsigned char VB_ExtTVYFilterIndex;
+	unsigned char VB_ExtTVYFilterIndexROM661;
+	unsigned char REFindex;
+	char ROMMODEIDX661;
 };
 
-struct SiS_Ext2
-{
-	unsigned short	Ext_InfoFlag;
-	unsigned char	Ext_CRT1CRTC;
-	unsigned char	Ext_CRTVCLK;
-	unsigned char	Ext_CRT2CRTC;
-	unsigned char	Ext_CRT2CRTC_NS;
-	unsigned char	ModeID;
-	unsigned short	XRes;
-	unsigned short	YRes;
-	unsigned char	Ext_PDC;
-	unsigned char	Ext_FakeCRT2CRTC;
-	unsigned char	Ext_FakeCRT2Clk;
+struct SiS_Ext2 {
+	unsigned short Ext_InfoFlag;
+	unsigned char Ext_CRT1CRTC;
+	unsigned char Ext_CRTVCLK;
+	unsigned char Ext_CRT2CRTC;
+	unsigned char Ext_CRT2CRTC_NS;
+	unsigned char ModeID;
+	unsigned short XRes;
+	unsigned short YRes;
+	unsigned char Ext_PDC;
+	unsigned char Ext_FakeCRT2CRTC;
+	unsigned char Ext_FakeCRT2Clk;
 };
 
-struct SiS_CRT1Table
-{
-	unsigned char	CR[17];
+struct SiS_CRT1Table {
+	unsigned char CR[17];
 };
 
-struct SiS_VCLKData
-{
-	unsigned char	SR2B,SR2C;
-	unsigned short	CLOCK;
+struct SiS_VCLKData {
+	unsigned char SR2B, SR2C;
+	unsigned short CLOCK;
 };
 
-struct SiS_ModeResInfo
-{
-	unsigned short	HTotal;
-	unsigned short	VTotal;
-	unsigned char	XChar;
-	unsigned char	YChar;
+struct SiS_ModeResInfo {
+	unsigned short HTotal;
+	unsigned short VTotal;
+	unsigned char XChar;
+	unsigned char YChar;
 };
 
-struct SiS_Private
-{
+struct SiS_Private {
 	void *sisusb;
 
 	unsigned long IOAddress;
@@ -151,19 +144,18 @@
 	unsigned long SiS_P3da;
 	unsigned long SiS_Part1Port;
 
-	unsigned char	SiS_MyCR63;
-	unsigned short	SiS_CRT1Mode;
-	unsigned short	SiS_ModeType;
-	unsigned short	SiS_SetFlag;
+	unsigned char SiS_MyCR63;
+	unsigned short SiS_CRT1Mode;
+	unsigned short SiS_ModeType;
+	unsigned short SiS_SetFlag;
 
-	const struct SiS_StandTable	*SiS_StandTable;
-	const struct SiS_St		*SiS_SModeIDTable;
-	const struct SiS_Ext		*SiS_EModeIDTable;
-	const struct SiS_Ext2		*SiS_RefIndex;
-	const struct SiS_CRT1Table	*SiS_CRT1Table;
-	const struct SiS_VCLKData	*SiS_VCLKData;
-	const struct SiS_ModeResInfo	*SiS_ModeResInfo;
+	const struct SiS_StandTable *SiS_StandTable;
+	const struct SiS_St *SiS_SModeIDTable;
+	const struct SiS_Ext *SiS_EModeIDTable;
+	const struct SiS_Ext2 *SiS_RefIndex;
+	const struct SiS_CRT1Table *SiS_CRT1Table;
+	const struct SiS_VCLKData *SiS_VCLKData;
+	const struct SiS_ModeResInfo *SiS_ModeResInfo;
 };
 
 #endif
-
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index 504f722..7198420 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -176,16 +176,17 @@
 static void lcd_write_bulk_callback(struct urb *urb)
 {
 	struct usb_lcd *dev;
+	int status = urb->status;
 
 	dev = (struct usb_lcd *)urb->context;
 
 	/* sync/async unlink faults aren't errors */
-	if (urb->status &&
-	    !(urb->status == -ENOENT ||
-	      urb->status == -ECONNRESET ||
-              urb->status == -ESHUTDOWN)) {
+	if (status &&
+	    !(status == -ENOENT ||
+	      status == -ECONNRESET ||
+              status == -ESHUTDOWN)) {
 		dbg("USBLCD: %s - nonzero write bulk status received: %d",
-		    __FUNCTION__, urb->status);
+		    __FUNCTION__, status);
 	}
 
 	/* free up our allocated buffer */
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index fb32186..e901d31 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -768,8 +768,8 @@
 
 		/* some faults are allowed, not required */
 		if (subcase->expected > 0 && (
-			  ((urb->status == -subcase->expected	/* happened */
-			   || urb->status == 0))))		/* didn't */
+			  ((status == -subcase->expected	/* happened */
+			   || status == 0))))			/* didn't */
 			status = 0;
 		/* sometimes more than one fault is allowed */
 		else if (subcase->number == 12 && status == -EPIPE)
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 1a60f9c..2734fe2 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -111,12 +111,13 @@
 	struct uss720_async_request *rq;
 	struct parport *pp;
 	struct parport_uss720_private *priv;
+	int status = urb->status;
 
 	rq = urb->context;
 	priv = rq->priv;
 	pp = priv->pp;
-	if (urb->status) {
-		err("async_complete: urb error %d", urb->status);
+	if (status) {
+		err("async_complete: urb error %d", status);
 	} else if (rq->dr.bRequest == 3) {
 		memcpy(priv->reg, rq->reg, sizeof(priv->reg));
 #if 0
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
index c03dfd7..f06e4e2 100644
--- a/drivers/usb/mon/mon_bin.c
+++ b/drivers/usb/mon/mon_bin.c
@@ -172,6 +172,10 @@
 
 #define MON_RING_EMPTY(rp)	((rp)->b_cnt == 0)
 
+static unsigned char xfer_to_pipe[4] = {
+	PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+};
+
 static struct class *mon_bin_class;
 static dev_t mon_bin_dev0;
 static struct cdev mon_bin_cdev;
@@ -354,13 +358,9 @@
     const struct urb *urb, char ev_type)
 {
 
-	if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+	if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S')
 		return '-';
 
-	if (urb->dev->bus->uses_dma &&
-	    (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
-		return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
-	}
 	if (urb->setup_packet == NULL)
 		return 'Z';
 
@@ -386,13 +386,15 @@
 }
 
 static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
-    char ev_type)
+    char ev_type, int status)
 {
+	const struct usb_endpoint_descriptor *epd = &urb->ep->desc;
 	unsigned long flags;
 	struct timeval ts;
 	unsigned int urb_length;
 	unsigned int offset;
 	unsigned int length;
+	unsigned char dir;
 	struct mon_bin_hdr *ep;
 	char data_tag = 0;
 
@@ -410,16 +412,19 @@
 	if (length >= rp->b_size/5)
 		length = rp->b_size/5;
 
-	if (usb_pipein(urb->pipe)) {
+	if (usb_urb_dir_in(urb)) {
 		if (ev_type == 'S') {
 			length = 0;
 			data_tag = '<';
 		}
+		/* Cannot rely on endpoint number in case of control ep.0 */
+		dir = USB_DIR_IN;
 	} else {
 		if (ev_type == 'C') {
 			length = 0;
 			data_tag = '>';
 		}
+		dir = 0;
 	}
 
 	if (rp->mmap_active)
@@ -440,15 +445,14 @@
 	 */
 	memset(ep, 0, PKT_SIZE);
 	ep->type = ev_type;
-	ep->xfer_type = usb_pipetype(urb->pipe);
-	/* We use the fact that usb_pipein() returns 0x80 */
-	ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
-	ep->devnum = usb_pipedevice(urb->pipe);
+	ep->xfer_type = xfer_to_pipe[usb_endpoint_type(epd)];
+	ep->epnum = dir | usb_endpoint_num(epd);
+	ep->devnum = urb->dev->devnum;
 	ep->busnum = urb->dev->bus->busnum;
 	ep->id = (unsigned long) urb;
 	ep->ts_sec = ts.tv_sec;
 	ep->ts_usec = ts.tv_usec;
-	ep->status = urb->status;
+	ep->status = status;
 	ep->len_urb = urb_length;
 	ep->len_cap = length;
 
@@ -471,13 +475,13 @@
 static void mon_bin_submit(void *data, struct urb *urb)
 {
 	struct mon_reader_bin *rp = data;
-	mon_bin_event(rp, urb, 'S');
+	mon_bin_event(rp, urb, 'S', -EINPROGRESS);
 }
 
-static void mon_bin_complete(void *data, struct urb *urb)
+static void mon_bin_complete(void *data, struct urb *urb, int status)
 {
 	struct mon_reader_bin *rp = data;
-	mon_bin_event(rp, urb, 'C');
+	mon_bin_event(rp, urb, 'C', status);
 }
 
 static void mon_bin_error(void *data, struct urb *urb, int error)
@@ -500,10 +504,10 @@
 
 	memset(ep, 0, PKT_SIZE);
 	ep->type = 'E';
-	ep->xfer_type = usb_pipetype(urb->pipe);
-	/* We use the fact that usb_pipein() returns 0x80 */
-	ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
-	ep->devnum = usb_pipedevice(urb->pipe);
+	ep->xfer_type = xfer_to_pipe[usb_endpoint_type(&urb->ep->desc)];
+	ep->epnum = usb_urb_dir_in(urb) ? USB_DIR_IN : 0;
+	ep->epnum |= usb_endpoint_num(&urb->ep->desc);
+	ep->devnum = urb->dev->devnum;
 	ep->busnum = urb->dev->bus->busnum;
 	ep->id = (unsigned long) urb;
 	ep->status = error;
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index ce61d8b..b371ffd 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -129,7 +129,8 @@
 
 /*
  */
-static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
+static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb,
+		int status)
 {
 	unsigned long flags;
 	struct list_head *pos;
@@ -139,28 +140,18 @@
 	mbus->cnt_events++;
 	list_for_each (pos, &mbus->r_list) {
 		r = list_entry(pos, struct mon_reader, r_link);
-		r->rnf_complete(r->r_data, urb);
+		r->rnf_complete(r->r_data, urb, status);
 	}
 	spin_unlock_irqrestore(&mbus->lock, flags);
 }
 
-static void mon_complete(struct usb_bus *ubus, struct urb *urb)
+static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status)
 {
 	struct mon_bus *mbus;
 
-	mbus = ubus->mon_bus;
-	if (mbus == NULL) {
-		/*
-		 * This should not happen.
-		 * At this point we do not even know the bus number...
-		 */
-		printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n",
-		    urb->pipe);
-		return;
-	}
-
-	mon_bus_complete(mbus, urb);
-	mon_bus_complete(&mon_bus0, urb);
+	if ((mbus = ubus->mon_bus) != NULL)
+		mon_bus_complete(mbus, urb, status);
+	mon_bus_complete(&mon_bus0, urb, status);
 }
 
 /* int (*unlink_urb) (struct urb *urb, int status); */
@@ -170,7 +161,7 @@
  */
 static void mon_stop(struct mon_bus *mbus)
 {
-	struct usb_bus *ubus = mbus->u_bus;
+	struct usb_bus *ubus;
 	struct list_head *p;
 
 	if (mbus == &mon_bus0) {
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index 982b773..ebb04ac 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -50,10 +50,13 @@
 struct mon_event_text {
 	struct list_head e_link;
 	int type;		/* submit, complete, etc. */
-	unsigned int pipe;	/* Pipe */
 	unsigned long id;	/* From pointer, most of the time */
 	unsigned int tstamp;
 	int busnum;
+	char devnum;
+	char epnum;
+	char is_in;
+	char xfertype;
 	int length;		/* Depends on type: xfer length or act length */
 	int status;
 	int interval;
@@ -121,13 +124,9 @@
     struct urb *urb, char ev_type, struct mon_bus *mbus)
 {
 
-	if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+	if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S')
 		return '-';
 
-	if (urb->dev->bus->uses_dma &&
-	    (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
-		return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX);
-	}
 	if (urb->setup_packet == NULL)
 		return 'Z';	/* '0' would be not as pretty. */
 
@@ -138,14 +137,12 @@
 static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
     int len, char ev_type, struct mon_bus *mbus)
 {
-	int pipe = urb->pipe;
-
 	if (len <= 0)
 		return 'L';
 	if (len >= DATA_MAX)
 		len = DATA_MAX;
 
-	if (usb_pipein(pipe)) {
+	if (ep->is_in) {
 		if (ev_type != 'C')
 			return '<';
 	} else {
@@ -186,7 +183,7 @@
 }
 
 static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
-    char ev_type)
+    char ev_type, int status)
 {
 	struct mon_event_text *ep;
 	unsigned int stamp;
@@ -203,24 +200,28 @@
 	}
 
 	ep->type = ev_type;
-	ep->pipe = urb->pipe;
 	ep->id = (unsigned long) urb;
 	ep->busnum = urb->dev->bus->busnum;
+	ep->devnum = urb->dev->devnum;
+	ep->epnum = usb_endpoint_num(&urb->ep->desc);
+	ep->xfertype = usb_endpoint_type(&urb->ep->desc);
+	ep->is_in = usb_urb_dir_in(urb);
 	ep->tstamp = stamp;
 	ep->length = (ev_type == 'S') ?
 	    urb->transfer_buffer_length : urb->actual_length;
 	/* Collecting status makes debugging sense for submits, too */
-	ep->status = urb->status;
+	ep->status = status;
 
-	if (usb_pipeint(urb->pipe)) {
+	if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
 		ep->interval = urb->interval;
-	} else if (usb_pipeisoc(urb->pipe)) {
+	} else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
 		ep->interval = urb->interval;
 		ep->start_frame = urb->start_frame;
 		ep->error_count = urb->error_count;
 	}
 	ep->numdesc = urb->number_of_packets;
-	if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) {
+	if (ep->xfertype == USB_ENDPOINT_XFER_ISOC &&
+			urb->number_of_packets > 0) {
 		if ((ndesc = urb->number_of_packets) > ISODESC_MAX)
 			ndesc = ISODESC_MAX;
 		fp = urb->iso_frame_desc;
@@ -247,13 +248,13 @@
 static void mon_text_submit(void *data, struct urb *urb)
 {
 	struct mon_reader_text *rp = data;
-	mon_text_event(rp, urb, 'S');
+	mon_text_event(rp, urb, 'S', -EINPROGRESS);
 }
 
-static void mon_text_complete(void *data, struct urb *urb)
+static void mon_text_complete(void *data, struct urb *urb, int status)
 {
 	struct mon_reader_text *rp = data;
-	mon_text_event(rp, urb, 'C');
+	mon_text_event(rp, urb, 'C', status);
 }
 
 static void mon_text_error(void *data, struct urb *urb, int error)
@@ -268,9 +269,12 @@
 	}
 
 	ep->type = 'E';
-	ep->pipe = urb->pipe;
 	ep->id = (unsigned long) urb;
 	ep->busnum = 0;
+	ep->devnum = urb->dev->devnum;
+	ep->epnum = usb_endpoint_num(&urb->ep->desc);
+	ep->xfertype = usb_endpoint_type(&urb->ep->desc);
+	ep->is_in = usb_urb_dir_in(urb);
 	ep->tstamp = 0;
 	ep->length = 0;
 	ep->status = error;
@@ -340,7 +344,7 @@
 	snprintf(rp->slab_name, SLAB_NAME_SZ, "mon_text_%p", rp);
 	rp->e_slab = kmem_cache_create(rp->slab_name,
 	    sizeof(struct mon_event_text), sizeof(long), 0,
-	    mon_text_ctor, NULL);
+	    mon_text_ctor);
 	if (rp->e_slab == NULL) {
 		rc = -ENOMEM;
 		goto err_slab;
@@ -413,10 +417,10 @@
 	mon_text_read_head_u(rp, &ptr, ep);
 	if (ep->type == 'E') {
 		mon_text_read_statset(rp, &ptr, ep);
-	} else if (usb_pipeisoc(ep->pipe)) {
+	} else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
 		mon_text_read_isostat(rp, &ptr, ep);
 		mon_text_read_isodesc(rp, &ptr, ep);
-	} else if (usb_pipeint(ep->pipe)) {
+	} else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
 		mon_text_read_intstat(rp, &ptr, ep);
 	} else {
 		mon_text_read_statset(rp, &ptr, ep);
@@ -468,18 +472,17 @@
 {
 	char udir, utype;
 
-	udir = usb_pipein(ep->pipe) ? 'i' : 'o';
-	switch (usb_pipetype(ep->pipe)) {
-	case PIPE_ISOCHRONOUS:	utype = 'Z'; break;
-	case PIPE_INTERRUPT:	utype = 'I'; break;
-	case PIPE_CONTROL:	utype = 'C'; break;
+	udir = (ep->is_in ? 'i' : 'o');
+	switch (ep->xfertype) {
+	case USB_ENDPOINT_XFER_ISOC:	utype = 'Z'; break;
+	case USB_ENDPOINT_XFER_INT:	utype = 'I'; break;
+	case USB_ENDPOINT_XFER_CONTROL:	utype = 'C'; break;
 	default: /* PIPE_BULK */  utype = 'B';
 	}
 	p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
 	    "%lx %u %c %c%c:%03u:%02u",
 	    ep->id, ep->tstamp, ep->type,
-	    utype, udir,
-	    usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+	    utype, udir, ep->devnum, ep->epnum);
 }
 
 static void mon_text_read_head_u(struct mon_reader_text *rp,
@@ -487,18 +490,17 @@
 {
 	char udir, utype;
 
-	udir = usb_pipein(ep->pipe) ? 'i' : 'o';
-	switch (usb_pipetype(ep->pipe)) {
-	case PIPE_ISOCHRONOUS:	utype = 'Z'; break;
-	case PIPE_INTERRUPT:	utype = 'I'; break;
-	case PIPE_CONTROL:	utype = 'C'; break;
+	udir = (ep->is_in ? 'i' : 'o');
+	switch (ep->xfertype) {
+	case USB_ENDPOINT_XFER_ISOC:	utype = 'Z'; break;
+	case USB_ENDPOINT_XFER_INT:	utype = 'I'; break;
+	case USB_ENDPOINT_XFER_CONTROL:	utype = 'C'; break;
 	default: /* PIPE_BULK */  utype = 'B';
 	}
 	p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
 	    "%lx %u %c %c%c:%d:%03u:%u",
 	    ep->id, ep->tstamp, ep->type,
-	    utype, udir,
-	    ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+	    utype, udir, ep->busnum, ep->devnum, ep->epnum);
 }
 
 static void mon_text_read_statset(struct mon_reader_text *rp,
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
index f68ad6d..f5d84ff 100644
--- a/drivers/usb/mon/usb_mon.h
+++ b/drivers/usb/mon/usb_mon.h
@@ -46,7 +46,7 @@
 
 	void (*rnf_submit)(void *data, struct urb *urb);
 	void (*rnf_error)(void *data, struct urb *urb, int error);
-	void (*rnf_complete)(void *data, struct urb *urb);
+	void (*rnf_complete)(void *data, struct urb *urb, int status);
 };
 
 void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 43d6db6..99fefed 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -92,6 +92,16 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called belkin_sa.
 
+config USB_SERIAL_CH341
+	tristate "USB Winchiphead CH341 Single Port Serial Driver"
+	depends on USB_SERIAL
+	help
+	  Say Y here if you want to use a Winchiphead CH341 single port
+	  USB to serial adapter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ch341.
+
 config USB_SERIAL_WHITEHEAT
 	tristate "USB ConnectTech WhiteHEAT Serial Driver"
 	depends on USB_SERIAL
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 07a976e..d6fb384 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -15,6 +15,7 @@
 obj-$(CONFIG_USB_SERIAL_AIRPRIME)		+= airprime.o
 obj-$(CONFIG_USB_SERIAL_ARK3116)		+= ark3116.o
 obj-$(CONFIG_USB_SERIAL_BELKIN)			+= belkin_sa.o
+obj-$(CONFIG_USB_SERIAL_CH341)			+= ch341.o
 obj-$(CONFIG_USB_SERIAL_CP2101)			+= cp2101.o
 obj-$(CONFIG_USB_SERIAL_CYBERJACK)		+= cyberjack.o
 obj-$(CONFIG_USB_SERIAL_CYPRESS_M8)		+= cypress_m8.o
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index cff6fd1..77bb893 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -18,7 +18,6 @@
 
 static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
-	{ USB_DEVICE(0x413c, 0x8115) }, /* Dell Wireless HSDPA 5500 */
 	{ },
 };
 MODULE_DEVICE_TABLE(usb, id_table);
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index c9fd486..2a8e537 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -172,11 +172,6 @@
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	if (!port->tty || !port->tty->termios) {
-		dbg("%s - no tty structures", __FUNCTION__);
-		return;
-	}
-
 	spin_lock_irqsave(&priv->lock, flags);
 	if (!priv->termios_initialized) {
 		*(port->tty->termios) = tty_std_termios;
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index e67ce25..86724e8 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -383,6 +383,10 @@
 	}
 
 	baud = tty_get_baud_rate(port->tty);
+	if (baud == 0) {
+		dbg("%s - tty_get_baud_rate says 0 baud", __FUNCTION__);
+		return;
+	}
 	urb_value = BELKIN_SA_BAUD(baud);
 	/* Clip to maximum speed */
 	if (urb_value == 0)
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index c08a384..0b14aea 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -36,6 +36,16 @@
 	return 0;
 }
 
+static ssize_t show_port_number(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct usb_serial_port *port = to_usb_serial_port(dev);
+
+	return sprintf(buf, "%d\n", port->number - port->serial->minor);
+}
+
+static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL);
+
 static int usb_serial_device_probe (struct device *dev)
 {
 	struct usb_serial_driver *driver;
@@ -62,6 +72,10 @@
 			goto exit;
 	}
 
+	retval = device_create_file(dev, &dev_attr_port_number);
+	if (retval)
+		goto exit;
+
 	minor = port->number;
 	tty_register_device (usb_serial_tty_driver, minor, dev);
 	dev_info(&port->serial->dev->dev, 
@@ -84,6 +98,8 @@
 		return -ENODEV;
 	}
 
+	device_remove_file(&port->dev, &dev_attr_port_number);
+
 	driver = port->serial->type;
 	if (driver->port_remove) {
 		if (!try_module_get(driver->driver.owner)) {
@@ -138,7 +154,7 @@
 static struct driver_attribute drv_attrs[] = {
 	__ATTR_NULL,
 };
-static inline void free_dynids(struct usb_driver *drv)
+static inline void free_dynids(struct usb_serial_driver *drv)
 {
 }
 #endif
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
new file mode 100644
index 0000000..6b252ce
--- /dev/null
+++ b/drivers/usb/serial/ch341.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2007, Frank A Kingswood <frank@kingswood-consulting.co.uk>
+ *
+ * ch341.c implements a serial port driver for the Winchiphead CH341.
+ *
+ * The CH341 device can be used to implement an RS232 asynchronous
+ * serial port, an IEEE-1284 parallel printer port or a memory-like
+ * interface. In all cases the CH341 supports an I2C interface as well.
+ * This driver only supports the asynchronous serial interface.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/serial.h>
+
+#define DEFAULT_BAUD_RATE 2400
+#define DEFAULT_TIMEOUT   1000
+
+static int debug;
+
+static struct usb_device_id id_table [] = {
+	{ USB_DEVICE(0x4348, 0x5523) },
+	{ },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+struct ch341_private {
+	unsigned baud_rate;
+	u8 dtr;
+	u8 rts;
+};
+
+static int ch341_control_out(struct usb_device *dev, u8 request,
+			     u16 value, u16 index)
+{
+	int r;
+	dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40,
+		(int)request, (int)value, (int)index);
+
+	r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
+			    USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+			    value, index, NULL, 0, DEFAULT_TIMEOUT);
+
+	return r;
+}
+
+static int ch341_control_in(struct usb_device *dev,
+			    u8 request, u16 value, u16 index,
+			    char *buf, unsigned bufsize)
+{
+	int r;
+	dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40,
+		(int)request, (int)value, (int)index, buf, (int)bufsize);
+
+	r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
+			    USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+			    value, index, buf, bufsize, DEFAULT_TIMEOUT);
+	return r;
+}
+
+static int ch341_set_baudrate(struct usb_device *dev,
+			      struct ch341_private *priv)
+{
+	short a, b;
+	int r;
+
+	dbg("ch341_set_baudrate(%d)", priv->baud_rate);
+	switch (priv->baud_rate) {
+	case 2400:
+		a = 0xd901;
+		b = 0x0038;
+		break;
+	case 4800:
+		a = 0x6402;
+		b = 0x001f;
+		break;
+	case 9600:
+		a = 0xb202;
+		b = 0x0013;
+		break;
+	case 19200:
+		a = 0xd902;
+		b = 0x000d;
+		break;
+	case 38400:
+		a = 0x6403;
+		b = 0x000a;
+		break;
+	case 115200:
+		a = 0xcc03;
+		b = 0x0008;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	r = ch341_control_out(dev, 0x9a, 0x1312, a);
+	if (!r)
+		r = ch341_control_out(dev, 0x9a, 0x0f2c, b);
+
+	return r;
+}
+
+static int ch341_set_handshake(struct usb_device *dev,
+			       struct ch341_private *priv)
+{
+	dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts);
+	return ch341_control_out(dev, 0xa4,
+		~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0);
+}
+
+static int ch341_get_status(struct usb_device *dev)
+{
+	char *buffer;
+	int r;
+	const unsigned size = 8;
+
+	dbg("ch341_get_status()");
+
+	buffer = kmalloc(size, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
+	if ( r < 0)
+		goto out;
+
+	/* Not having the datasheet for the CH341, we ignore the bytes returned
+	 * from the device. Return error if the device did not respond in time.
+	 */
+	r = 0;
+
+out:	kfree(buffer);
+	return r;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
+{
+	char *buffer;
+	int r;
+	const unsigned size = 8;
+
+	dbg("ch341_configure()");
+
+	buffer = kmalloc(size, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	/* expect two bytes 0x27 0x00 */
+	r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size);
+	if (r < 0)
+		goto out;
+
+	r = ch341_control_out(dev, 0xa1, 0, 0);
+	if (r < 0)
+		goto out;
+
+	r = ch341_set_baudrate(dev, priv);
+	if (r < 0)
+		goto out;
+
+	/* expect two bytes 0x56 0x00 */
+	r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size);
+	if (r < 0)
+		goto out;
+
+	r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050);
+	if (r < 0)
+		goto out;
+
+	/* expect 0xff 0xee */
+	r = ch341_get_status(dev);
+	if (r < 0)
+		goto out;
+
+	r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a);
+	if (r < 0)
+		goto out;
+
+	r = ch341_set_baudrate(dev, priv);
+	if (r < 0)
+		goto out;
+
+	r = ch341_set_handshake(dev, priv);
+	if (r < 0)
+		goto out;
+
+	/* expect 0x9f 0xee */
+	r = ch341_get_status(dev);
+
+out:	kfree(buffer);
+	return r;
+}
+
+/* allocate private data */
+static int ch341_attach(struct usb_serial *serial)
+{
+	struct ch341_private *priv;
+	int r;
+
+	dbg("ch341_attach()");
+
+	/* private data */
+	priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->baud_rate = DEFAULT_BAUD_RATE;
+	priv->dtr = 1;
+	priv->rts = 1;
+
+	r = ch341_configure(serial->dev, priv);
+	if (r < 0)
+		goto error;
+
+	usb_set_serial_port_data(serial->port[0], priv);
+	return 0;
+
+error:	kfree(priv);
+	return r;
+}
+
+/* open this device, set default parameters */
+static int ch341_open(struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial *serial = port->serial;
+	struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]);
+	int r;
+
+	dbg("ch341_open()");
+
+	priv->baud_rate = DEFAULT_BAUD_RATE;
+	priv->dtr = 1;
+	priv->rts = 1;
+
+	r = ch341_configure(serial->dev, priv);
+	if (r)
+		goto out;
+
+	r = ch341_set_handshake(serial->dev, priv);
+	if (r)
+		goto out;
+
+	r = ch341_set_baudrate(serial->dev, priv);
+	if (r)
+		goto out;
+
+	r = usb_serial_generic_open(port, filp);
+
+out:	return r;
+}
+
+/* Old_termios contains the original termios settings and
+ * tty->termios contains the new setting to be used.
+ */
+static void ch341_set_termios(struct usb_serial_port *port,
+			      struct ktermios *old_termios)
+{
+	struct ch341_private *priv = usb_get_serial_port_data(port);
+	struct tty_struct *tty = port->tty;
+	unsigned baud_rate;
+
+	dbg("ch341_set_termios()");
+
+	if (!tty || !tty->termios)
+		return;
+
+	baud_rate = tty_get_baud_rate(tty);
+
+	switch (baud_rate) {
+	case 2400:
+	case 4800:
+	case 9600:
+	case 19200:
+	case 38400:
+	case 115200:
+		priv->baud_rate = baud_rate;
+		break;
+	default:
+		dbg("Rate %d not supported, using %d",
+			baud_rate, DEFAULT_BAUD_RATE);
+		priv->baud_rate = DEFAULT_BAUD_RATE;
+	}
+
+	ch341_set_baudrate(port->serial->dev, priv);
+
+	/* Unimplemented:
+	 * (cflag & CSIZE) : data bits [5, 8]
+	 * (cflag & PARENB) : parity {NONE, EVEN, ODD}
+	 * (cflag & CSTOPB) : stop bits [1, 2]
+	 */
+}
+
+static struct usb_driver ch341_driver = {
+	.name		= "ch341",
+	.probe		= usb_serial_probe,
+	.disconnect	= usb_serial_disconnect,
+	.id_table	= id_table,
+	.no_dynamic_id	= 1,
+};
+
+static struct usb_serial_driver ch341_device = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "ch341-uart",
+	},
+	.id_table         = id_table,
+	.usb_driver       = &ch341_driver,
+	.num_interrupt_in = NUM_DONT_CARE,
+	.num_bulk_in      = 1,
+	.num_bulk_out     = 1,
+	.num_ports        = 1,
+	.open             = ch341_open,
+	.set_termios      = ch341_set_termios,
+	.attach           = ch341_attach,
+};
+
+static int __init ch341_init(void)
+{
+	int retval;
+
+	retval = usb_serial_register(&ch341_device);
+	if (retval)
+		return retval;
+	retval = usb_register(&ch341_driver);
+	if (retval)
+		usb_serial_deregister(&ch341_device);
+	return retval;
+}
+
+static void __exit ch341_exit(void)
+{
+	usb_deregister(&ch341_driver);
+	usb_serial_deregister(&ch341_device);
+}
+
+module_init(ch341_init);
+module_exit(ch341_exit);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+/* EOF ch341.c */
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index e831cb7..eb7df18 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -53,6 +53,7 @@
 static int debug;
 
 static struct usb_device_id id_table [] = {
+	{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
 	{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
 	{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
 	{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
@@ -356,7 +357,7 @@
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	if ((!port->tty) || (!port->tty->termios)) {
+	if (!port->tty || !port->tty->termios) {
 		dbg("%s - no tty structures", __FUNCTION__);
 		return;
 	}
@@ -521,55 +522,40 @@
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	if ((!port->tty) || (!port->tty->termios)) {
+	if (!port->tty || !port->tty->termios) {
 		dbg("%s - no tty structures", __FUNCTION__);
 		return;
 	}
 	cflag = port->tty->termios->c_cflag;
-
-	/* Check that they really want us to change something */
-	if (old_termios) {
-		if ((cflag == old_termios->c_cflag) &&
-				(RELEVANT_IFLAG(port->tty->termios->c_iflag)
-				== RELEVANT_IFLAG(old_termios->c_iflag))) {
-			dbg("%s - nothing to change...", __FUNCTION__);
-			return;
-		}
-
-		old_cflag = old_termios->c_cflag;
-	}
+	old_cflag = old_termios->c_cflag;
+	baud = tty_get_baud_rate(port->tty);
 
 	/* If the baud rate is to be updated*/
-	if ((cflag & CBAUD) != (old_cflag & CBAUD)) {
-		switch (cflag & CBAUD) {
-			/*
-			 * The baud rates which are commented out below
-			 * appear to be supported by the device
-			 * but are non-standard
-			 */
-			case B0:	baud = 0;	break;
-			case B600:	baud = 600;	break;
-			case B1200:	baud = 1200;	break;
-			case B1800:	baud = 1800;	break;
-			case B2400:	baud = 2400;	break;
-			case B4800:	baud = 4800;	break;
-			/*case B7200:	baud = 7200;	break;*/
-			case B9600:	baud = 9600;	break;
-			/*ase B14400:	baud = 14400;	break;*/
-			case B19200:	baud = 19200;	break;
-			/*case B28800:	baud = 28800;	break;*/
-			case B38400:	baud = 38400;	break;
-			/*case B55854:	baud = 55054;	break;*/
-			case B57600:	baud = 57600;	break;
-			case B115200:	baud = 115200;	break;
-			/*case B127117:	baud = 127117;	break;*/
-			case B230400:	baud = 230400;	break;
-			case B460800:	baud = 460800;	break;
-			case B921600:	baud = 921600;	break;
-			/*case B3686400:	baud = 3686400;	break;*/
+	if (baud != tty_termios_baud_rate(old_termios)) {
+		switch (baud) {
+			case 0:
+			case 600:
+			case 1200:
+			case 1800:
+			case 2400:
+			case 4800:
+			case 7200:
+			case 9600:
+			case 14400:
+			case 19200:
+			case 28800:
+			case 38400:
+			case 55854:
+			case 57600:
+			case 115200:
+			case 127117:
+			case 230400:
+			case 460800:
+			case 921600:
+			case 3686400:
+				break;
 			default:
-				dev_err(&port->dev, "cp2101 driver does not "
-					"support the baudrate requested\n");
+				baud = 9600;
 				break;
 		}
 
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 976f54e..dab2e66 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -433,38 +433,38 @@
 
 /* Local Function Declarations */
 
-static void digi_wakeup_write( struct usb_serial_port *port );
+static void digi_wakeup_write(struct usb_serial_port *port);
 static void digi_wakeup_write_lock(struct work_struct *work);
-static int digi_write_oob_command( struct usb_serial_port *port,
-	unsigned char *buf, int count, int interruptible );
-static int digi_write_inb_command( struct usb_serial_port *port,
-	unsigned char *buf, int count, unsigned long timeout );
-static int digi_set_modem_signals( struct usb_serial_port *port,
-	unsigned int modem_signals, int interruptible );
-static int digi_transmit_idle( struct usb_serial_port *port,
-	unsigned long timeout );
+static int digi_write_oob_command(struct usb_serial_port *port,
+	unsigned char *buf, int count, int interruptible);
+static int digi_write_inb_command(struct usb_serial_port *port,
+	unsigned char *buf, int count, unsigned long timeout);
+static int digi_set_modem_signals(struct usb_serial_port *port,
+	unsigned int modem_signals, int interruptible);
+static int digi_transmit_idle(struct usb_serial_port *port,
+	unsigned long timeout);
 static void digi_rx_throttle (struct usb_serial_port *port);
 static void digi_rx_unthrottle (struct usb_serial_port *port);
-static void digi_set_termios( struct usb_serial_port *port, 
-	struct ktermios *old_termios );
-static void digi_break_ctl( struct usb_serial_port *port, int break_state );
-static int digi_ioctl( struct usb_serial_port *port, struct file *file,
-	unsigned int cmd, unsigned long arg );
-static int digi_tiocmget( struct usb_serial_port *port, struct file *file );
-static int digi_tiocmset( struct usb_serial_port *port, struct file *file,
-	unsigned int set, unsigned int clear );
-static int digi_write( struct usb_serial_port *port, const unsigned char *buf, int count );
-static void digi_write_bulk_callback( struct urb *urb );
-static int digi_write_room( struct usb_serial_port *port );
-static int digi_chars_in_buffer( struct usb_serial_port *port );
-static int digi_open( struct usb_serial_port *port, struct file *filp );
-static void digi_close( struct usb_serial_port *port, struct file *filp );
-static int digi_startup_device( struct usb_serial *serial );
-static int digi_startup( struct usb_serial *serial );
-static void digi_shutdown( struct usb_serial *serial );
-static void digi_read_bulk_callback( struct urb *urb );
-static int digi_read_inb_callback( struct urb *urb );
-static int digi_read_oob_callback( struct urb *urb );
+static void digi_set_termios(struct usb_serial_port *port,
+	struct ktermios *old_termios);
+static void digi_break_ctl(struct usb_serial_port *port, int break_state);
+static int digi_ioctl(struct usb_serial_port *port, struct file *file,
+	unsigned int cmd, unsigned long arg);
+static int digi_tiocmget(struct usb_serial_port *port, struct file *file);
+static int digi_tiocmset(struct usb_serial_port *port, struct file *file,
+	unsigned int set, unsigned int clear);
+static int digi_write(struct usb_serial_port *port, const unsigned char *buf, int count);
+static void digi_write_bulk_callback(struct urb *urb);
+static int digi_write_room(struct usb_serial_port *port);
+static int digi_chars_in_buffer(struct usb_serial_port *port);
+static int digi_open(struct usb_serial_port *port, struct file *filp);
+static void digi_close(struct usb_serial_port *port, struct file *filp);
+static int digi_startup_device(struct usb_serial *serial);
+static int digi_startup(struct usb_serial *serial);
+static void digi_shutdown(struct usb_serial *serial);
+static void digi_read_bulk_callback(struct urb *urb);
+static int digi_read_inb_callback(struct urb *urb);
+static int digi_read_oob_callback(struct urb *urb);
 
 
 /* Statics */
@@ -576,9 +576,9 @@
 *  with the equivalent code.
 */
 
-static inline long cond_wait_interruptible_timeout_irqrestore(
+static long cond_wait_interruptible_timeout_irqrestore(
 	wait_queue_head_t *q, long timeout,
-	spinlock_t *lock, unsigned long flags )
+	spinlock_t *lock, unsigned long flags)
 {
 	DEFINE_WAIT(wait);
 
@@ -600,18 +600,16 @@
 
 static void digi_wakeup_write_lock(struct work_struct *work)
 {
-	struct digi_port *priv =
-		container_of(work, struct digi_port, dp_wakeup_work);
+	struct digi_port *priv = container_of(work, struct digi_port, dp_wakeup_work);
 	struct usb_serial_port *port = priv->dp_port;
 	unsigned long flags;
 
-
-	spin_lock_irqsave( &priv->dp_port_lock, flags );
-	digi_wakeup_write( port );
-	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+	spin_lock_irqsave(&priv->dp_port_lock, flags);
+	digi_wakeup_write(port);
+	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
 }
 
-static void digi_wakeup_write( struct usb_serial_port *port )
+static void digi_wakeup_write(struct usb_serial_port *port)
 {
 	tty_wakeup(port->tty);
 }
@@ -628,8 +626,8 @@
 *  returned by usb_submit_urb.
 */
 
-static int digi_write_oob_command( struct usb_serial_port *port,
-	unsigned char *buf, int count, int interruptible )
+static int digi_write_oob_command(struct usb_serial_port *port,
+	unsigned char *buf, int count, int interruptible)
 {
 
 	int ret = 0;
@@ -638,49 +636,37 @@
 	struct digi_port *oob_priv = usb_get_serial_port_data(oob_port);
 	unsigned long flags = 0;
 
+	dbg("digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, count);
 
-dbg( "digi_write_oob_command: TOP: port=%d, count=%d", oob_priv->dp_port_num, count );
-
-	spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
-
-	while( count > 0 ) {
-
-		while( oob_port->write_urb->status == -EINPROGRESS
-		|| oob_priv->dp_write_urb_in_use ) {
+	spin_lock_irqsave(&oob_priv->dp_port_lock, flags);
+	while(count > 0) {
+		while(oob_port->write_urb->status == -EINPROGRESS
+			|| oob_priv->dp_write_urb_in_use) {
 			cond_wait_interruptible_timeout_irqrestore(
 				&oob_port->write_wait, DIGI_RETRY_TIMEOUT,
-				&oob_priv->dp_port_lock, flags );
-			if( interruptible && signal_pending(current) ) {
-				return( -EINTR );
-			}
-			spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
+				&oob_priv->dp_port_lock, flags);
+			if (interruptible && signal_pending(current))
+				return -EINTR;
+			spin_lock_irqsave(&oob_priv->dp_port_lock, flags);
 		}
 
 		/* len must be a multiple of 4, so commands are not split */
-		len = min(count, oob_port->bulk_out_size );
-		if( len > 4 )
+		len = min(count, oob_port->bulk_out_size);
+		if (len > 4)
 			len &= ~3;
-
-		memcpy( oob_port->write_urb->transfer_buffer, buf, len );
+		memcpy(oob_port->write_urb->transfer_buffer, buf, len);
 		oob_port->write_urb->transfer_buffer_length = len;
 		oob_port->write_urb->dev = port->serial->dev;
-
-		if( (ret=usb_submit_urb(oob_port->write_urb, GFP_ATOMIC)) == 0 ) {
+		if ((ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC)) == 0) {
 			oob_priv->dp_write_urb_in_use = 1;
 			count -= len;
 			buf += len;
 		}
-
 	}
-
-	spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags );
-
-	if( ret ) {
-		err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__,
-			ret );
-	}
-
-	return( ret );
+	spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags);
+	if (ret)
+		err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__, ret);
+	return ret;
 
 }
 
@@ -697,63 +683,58 @@
 *  error returned by digi_write.
 */
 
-static int digi_write_inb_command( struct usb_serial_port *port,
-	unsigned char *buf, int count, unsigned long timeout )
+static int digi_write_inb_command(struct usb_serial_port *port,
+	unsigned char *buf, int count, unsigned long timeout)
 {
-
 	int ret = 0;
 	int len;
 	struct digi_port *priv = usb_get_serial_port_data(port);
 	unsigned char *data = port->write_urb->transfer_buffer;
 	unsigned long flags = 0;
 
+	dbg("digi_write_inb_command: TOP: port=%d, count=%d",
+		priv->dp_port_num, count);
 
-dbg( "digi_write_inb_command: TOP: port=%d, count=%d", priv->dp_port_num,
-count );
-
-	if( timeout )
+	if (timeout)
 		timeout += jiffies;
 	else
 		timeout = ULONG_MAX;
 
-	spin_lock_irqsave( &priv->dp_port_lock, flags );
-
-	while( count > 0 && ret == 0 ) {
-
-		while( (port->write_urb->status == -EINPROGRESS
-		|| priv->dp_write_urb_in_use) && time_before(jiffies, timeout)) {
+	spin_lock_irqsave(&priv->dp_port_lock, flags);
+	while(count > 0 && ret == 0) {
+		while((port->write_urb->status == -EINPROGRESS
+			|| priv->dp_write_urb_in_use) && time_before(jiffies, timeout)) {
 			cond_wait_interruptible_timeout_irqrestore(
 				&port->write_wait, DIGI_RETRY_TIMEOUT,
-				&priv->dp_port_lock, flags );
-			if( signal_pending(current) ) {
-				return( -EINTR );
-			}
-			spin_lock_irqsave( &priv->dp_port_lock, flags );
+				&priv->dp_port_lock, flags);
+			if (signal_pending(current))
+				return -EINTR;
+			spin_lock_irqsave(&priv->dp_port_lock, flags);
 		}
 
 		/* len must be a multiple of 4 and small enough to */
 		/* guarantee the write will send buffered data first, */
 		/* so commands are in order with data and not split */
-		len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len );
-		if( len > 4 )
+		len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len);
+		if (len > 4)
 			len &= ~3;
 
 		/* write any buffered data first */
-		if( priv->dp_out_buf_len > 0 ) {
+		if (priv->dp_out_buf_len > 0) {
 			data[0] = DIGI_CMD_SEND_DATA;
 			data[1] = priv->dp_out_buf_len;
-			memcpy( data+2, priv->dp_out_buf,
-				priv->dp_out_buf_len );
-			memcpy( data+2+priv->dp_out_buf_len, buf, len );
+			memcpy(data + 2, priv->dp_out_buf,
+				priv->dp_out_buf_len);
+			memcpy(data + 2 + priv->dp_out_buf_len, buf, len);
 			port->write_urb->transfer_buffer_length
-				= priv->dp_out_buf_len+2+len;
+				= priv->dp_out_buf_len + 2 + len;
 		} else {
-			memcpy( data, buf, len );
+			memcpy(data, buf, len);
 			port->write_urb->transfer_buffer_length = len;
 		}
 		port->write_urb->dev = port->serial->dev;
 
-		if( (ret=usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0 ) {
+		if ((ret = usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0) {
 			priv->dp_write_urb_in_use = 1;
 			priv->dp_out_buf_len = 0;
 			count -= len;
@@ -761,16 +742,12 @@
 		}
 
 	}
+	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
 
-	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-
-	if( ret ) {
-		err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__,
-		ret, priv->dp_port_num );
-	}
-
-	return( ret );
-
+	if (ret)
+		err("%s: usb_submit_urb failed, ret=%d, port=%d",
+			__FUNCTION__, ret, priv->dp_port_num);
+	return ret;
 }
 
 
@@ -784,8 +761,8 @@
 *  returned by usb_submit_urb.
 */
 
-static int digi_set_modem_signals( struct usb_serial_port *port,
-	unsigned int modem_signals, int interruptible )
+static int digi_set_modem_signals(struct usb_serial_port *port,
+	unsigned int modem_signals, int interruptible)
 {
 
 	int ret;
@@ -796,60 +773,47 @@
 	unsigned long flags = 0;
 
 
-dbg( "digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x",
-port_priv->dp_port_num, modem_signals );
+	dbg("digi_set_modem_signals: TOP: port=%d, modem_signals=0x%x",
+		port_priv->dp_port_num, modem_signals);
 
-	spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
-	spin_lock( &port_priv->dp_port_lock );
+	spin_lock_irqsave(&oob_priv->dp_port_lock, flags);
+	spin_lock(&port_priv->dp_port_lock);
 
-	while( oob_port->write_urb->status == -EINPROGRESS
-	|| oob_priv->dp_write_urb_in_use ) {
-		spin_unlock( &port_priv->dp_port_lock );
+	while(oob_port->write_urb->status == -EINPROGRESS || oob_priv->dp_write_urb_in_use) {
+		spin_unlock(&port_priv->dp_port_lock);
 		cond_wait_interruptible_timeout_irqrestore(
 			&oob_port->write_wait, DIGI_RETRY_TIMEOUT,
-			&oob_priv->dp_port_lock, flags );
-		if( interruptible && signal_pending(current) ) {
-			return( -EINTR );
-		}
-		spin_lock_irqsave( &oob_priv->dp_port_lock, flags );
-		spin_lock( &port_priv->dp_port_lock );
+			&oob_priv->dp_port_lock, flags);
+		if (interruptible && signal_pending(current))
+			return -EINTR;
+		spin_lock_irqsave(&oob_priv->dp_port_lock, flags);
+		spin_lock(&port_priv->dp_port_lock);
 	}
-
 	data[0] = DIGI_CMD_SET_DTR_SIGNAL;
 	data[1] = port_priv->dp_port_num;
-	data[2] = (modem_signals&TIOCM_DTR) ?
-		DIGI_DTR_ACTIVE : DIGI_DTR_INACTIVE;
+	data[2] = (modem_signals&TIOCM_DTR) ? DIGI_DTR_ACTIVE : DIGI_DTR_INACTIVE;
 	data[3] = 0;
-
 	data[4] = DIGI_CMD_SET_RTS_SIGNAL;
 	data[5] = port_priv->dp_port_num;
-	data[6] = (modem_signals&TIOCM_RTS) ?
-		DIGI_RTS_ACTIVE : DIGI_RTS_INACTIVE;
+	data[6] = (modem_signals&TIOCM_RTS) ? DIGI_RTS_ACTIVE : DIGI_RTS_INACTIVE;
 	data[7] = 0;
 
 	oob_port->write_urb->transfer_buffer_length = 8;
 	oob_port->write_urb->dev = port->serial->dev;
 
-	if( (ret=usb_submit_urb(oob_port->write_urb, GFP_ATOMIC)) == 0 ) {
+	if ((ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC)) == 0) {
 		oob_priv->dp_write_urb_in_use = 1;
 		port_priv->dp_modem_signals =
 			(port_priv->dp_modem_signals&~(TIOCM_DTR|TIOCM_RTS))
 			| (modem_signals&(TIOCM_DTR|TIOCM_RTS));
 	}
-
-	spin_unlock( &port_priv->dp_port_lock );
-	spin_unlock_irqrestore( &oob_priv->dp_port_lock, flags );
-
-	if( ret ) {
-		err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__,
-		ret );
-	}
-
-	return( ret );
-
+	spin_unlock(&port_priv->dp_port_lock);
+	spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags);
+	if (ret)
+		err("%s: usb_submit_urb failed, ret=%d", __FUNCTION__, ret);
+	return ret;
 }
 
-
 /*
 *  Digi Transmit Idle
 *
@@ -862,203 +826,182 @@
 *  port at a time, so its ok.
 */
 
-static int digi_transmit_idle( struct usb_serial_port *port,
-	unsigned long timeout )
+static int digi_transmit_idle(struct usb_serial_port *port,
+	unsigned long timeout)
 {
-
 	int ret;
 	unsigned char buf[2];
 	struct digi_port *priv = usb_get_serial_port_data(port);
 	unsigned long flags = 0;
 
-
-	spin_lock_irqsave( &priv->dp_port_lock, flags );
+	spin_lock_irqsave(&priv->dp_port_lock, flags);
 	priv->dp_transmit_idle = 0;
-	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
 
 	buf[0] = DIGI_CMD_TRANSMIT_IDLE;
 	buf[1] = 0;
 
 	timeout += jiffies;
 
-	if( (ret=digi_write_inb_command( port, buf, 2, timeout-jiffies )) != 0 )
-		return( ret );
+	if ((ret = digi_write_inb_command(port, buf, 2, timeout - jiffies)) != 0)
+		return ret;
 
-	spin_lock_irqsave( &priv->dp_port_lock, flags );
+	spin_lock_irqsave(&priv->dp_port_lock, flags);
 
-	while( time_before(jiffies, timeout) && !priv->dp_transmit_idle ) {
+	while(time_before(jiffies, timeout) && !priv->dp_transmit_idle) {
 		cond_wait_interruptible_timeout_irqrestore(
 			&priv->dp_transmit_idle_wait, DIGI_RETRY_TIMEOUT,
-			&priv->dp_port_lock, flags );
-		if( signal_pending(current) ) {
-			return( -EINTR );
-		}
-		spin_lock_irqsave( &priv->dp_port_lock, flags );
+			&priv->dp_port_lock, flags);
+		if (signal_pending(current))
+			return -EINTR;
+		spin_lock_irqsave(&priv->dp_port_lock, flags);
 	}
-
 	priv->dp_transmit_idle = 0;
-	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-
-	return( 0 );
+	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+	return 0;
 
 }
 
 
-static void digi_rx_throttle( struct usb_serial_port *port )
+static void digi_rx_throttle(struct usb_serial_port *port)
 {
-
 	unsigned long flags;
 	struct digi_port *priv = usb_get_serial_port_data(port);
 
 
-dbg( "digi_rx_throttle: TOP: port=%d", priv->dp_port_num );
+	dbg("digi_rx_throttle: TOP: port=%d", priv->dp_port_num);
 
 	/* stop receiving characters by not resubmitting the read urb */
-	spin_lock_irqsave( &priv->dp_port_lock, flags );
+	spin_lock_irqsave(&priv->dp_port_lock, flags);
 	priv->dp_throttled = 1;
 	priv->dp_throttle_restart = 0;
-	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-
+	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
 }
 
 
-static void digi_rx_unthrottle( struct usb_serial_port *port )
+static void digi_rx_unthrottle(struct usb_serial_port *port)
 {
-
 	int ret = 0;
 	unsigned long flags;
 	struct digi_port *priv = usb_get_serial_port_data(port);
 
-dbg( "digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num );
+	dbg("digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num);
 
-	spin_lock_irqsave( &priv->dp_port_lock, flags );
+	spin_lock_irqsave(&priv->dp_port_lock, flags);
 
 	/* turn throttle off */
 	priv->dp_throttled = 0;
 	priv->dp_throttle_restart = 0;
 
 	/* restart read chain */
-	if( priv->dp_throttle_restart ) {
+	if (priv->dp_throttle_restart) {
 		port->read_urb->dev = port->serial->dev;
-		ret = usb_submit_urb( port->read_urb, GFP_ATOMIC );
+		ret = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 	}
 
-	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
 
-	if( ret ) {
-		err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__,
-			ret, priv->dp_port_num );
-	}
-
+	if (ret)
+		err("%s: usb_submit_urb failed, ret=%d, port=%d",
+			__FUNCTION__, ret, priv->dp_port_num);
 }
 
 
-static void digi_set_termios( struct usb_serial_port *port, 
-	struct ktermios *old_termios )
+static void digi_set_termios(struct usb_serial_port *port,
+					struct ktermios *old_termios)
 {
 
 	struct digi_port *priv = usb_get_serial_port_data(port);
-	unsigned int iflag = port->tty->termios->c_iflag;
-	unsigned int cflag = port->tty->termios->c_cflag;
+	struct tty_struct *tty = port->tty;
+	unsigned int iflag = tty->termios->c_iflag;
+	unsigned int cflag = tty->termios->c_cflag;
 	unsigned int old_iflag = old_termios->c_iflag;
 	unsigned int old_cflag = old_termios->c_cflag;
 	unsigned char buf[32];
 	unsigned int modem_signals;
 	int arg,ret;
 	int i = 0;
+	speed_t baud;
 
-
-dbg( "digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x", priv->dp_port_num, iflag, old_iflag, cflag, old_cflag );
+	dbg("digi_set_termios: TOP: port=%d, iflag=0x%x, old_iflag=0x%x, cflag=0x%x, old_cflag=0x%x", priv->dp_port_num, iflag, old_iflag, cflag, old_cflag);
 
 	/* set baud rate */
-	if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
-
+	if ((baud = tty_get_baud_rate(tty)) != tty_termios_baud_rate(old_termios)) {
 		arg = -1;
 
 		/* reassert DTR and (maybe) RTS on transition from B0 */
-		if( (old_cflag&CBAUD) == B0 ) {
+		if ((old_cflag&CBAUD) == B0) {
 			/* don't set RTS if using hardware flow control */
 			/* and throttling input */
 			modem_signals = TIOCM_DTR;
-			if( !(port->tty->termios->c_cflag & CRTSCTS) ||
-			!test_bit(TTY_THROTTLED, &port->tty->flags) ) {
+			if (!(tty->termios->c_cflag & CRTSCTS) ||
+			    !test_bit(TTY_THROTTLED, &tty->flags))
 				modem_signals |= TIOCM_RTS;
-			}
-			digi_set_modem_signals( port, modem_signals, 1 );
+			digi_set_modem_signals(port, modem_signals, 1);
 		}
-
-		switch( (cflag&CBAUD) ) {
+		switch (baud) {
 			/* drop DTR and RTS on transition to B0 */
-		case B0: digi_set_modem_signals( port, 0, 1 ); break;
-		case B50: arg = DIGI_BAUD_50; break;
-		case B75: arg = DIGI_BAUD_75; break;
-		case B110: arg = DIGI_BAUD_110; break;
-		case B150: arg = DIGI_BAUD_150; break;
-		case B200: arg = DIGI_BAUD_200; break;
-		case B300: arg = DIGI_BAUD_300; break;
-		case B600: arg = DIGI_BAUD_600; break;
-		case B1200: arg = DIGI_BAUD_1200; break;
-		case B1800: arg = DIGI_BAUD_1800; break;
-		case B2400: arg = DIGI_BAUD_2400; break;
-		case B4800: arg = DIGI_BAUD_4800; break;
-		case B9600: arg = DIGI_BAUD_9600; break;
-		case B19200: arg = DIGI_BAUD_19200; break;
-		case B38400: arg = DIGI_BAUD_38400; break;
-		case B57600: arg = DIGI_BAUD_57600; break;
-		case B115200: arg = DIGI_BAUD_115200; break;
-		case B230400: arg = DIGI_BAUD_230400; break;
-		case B460800: arg = DIGI_BAUD_460800; break;
-		default:
-			dbg( "digi_set_termios: can't handle baud rate 0x%x",
-				(cflag&CBAUD) );
-			break;
+			case 0: digi_set_modem_signals(port, 0, 1); break;
+			case 50: arg = DIGI_BAUD_50; break;
+			case 75: arg = DIGI_BAUD_75; break;
+			case 110: arg = DIGI_BAUD_110; break;
+			case 150: arg = DIGI_BAUD_150; break;
+			case 200: arg = DIGI_BAUD_200; break;
+			case 300: arg = DIGI_BAUD_300; break;
+			case 600: arg = DIGI_BAUD_600; break;
+			case 1200: arg = DIGI_BAUD_1200; break;
+			case 1800: arg = DIGI_BAUD_1800; break;
+			case 2400: arg = DIGI_BAUD_2400; break;
+			case 4800: arg = DIGI_BAUD_4800; break;
+			case 9600: arg = DIGI_BAUD_9600; break;
+			case 19200: arg = DIGI_BAUD_19200; break;
+			case 38400: arg = DIGI_BAUD_38400; break;
+			case 57600: arg = DIGI_BAUD_57600; break;
+			case 115200: arg = DIGI_BAUD_115200; break;
+			case 230400: arg = DIGI_BAUD_230400; break;
+			case 460800: arg = DIGI_BAUD_460800; break;
+			default:
+				arg = DIGI_BAUD_9600;
+				baud = 9600;
+				break;
 		}
-
-		if( arg != -1 ) {
+		if (arg != -1) {
 			buf[i++] = DIGI_CMD_SET_BAUD_RATE;
 			buf[i++] = priv->dp_port_num;
 			buf[i++] = arg;
 			buf[i++] = 0;
 		}
-
 	}
-
 	/* set parity */
-	if( (cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD)) ) {
-
-		if( (cflag&PARENB) ) {
-			if( (cflag&PARODD) )
+	if ((cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD))) {
+		if (cflag&PARENB) {
+			if (cflag&PARODD)
 				arg = DIGI_PARITY_ODD;
 			else
 				arg = DIGI_PARITY_EVEN;
 		} else {
 			arg = DIGI_PARITY_NONE;
 		}
-
 		buf[i++] = DIGI_CMD_SET_PARITY;
 		buf[i++] = priv->dp_port_num;
 		buf[i++] = arg;
 		buf[i++] = 0;
-
 	}
-
 	/* set word size */
-	if( (cflag&CSIZE) != (old_cflag&CSIZE) ) {
-
+	if ((cflag&CSIZE) != (old_cflag&CSIZE)) {
 		arg = -1;
-
-		switch( (cflag&CSIZE) ) {
+		switch (cflag&CSIZE) {
 		case CS5: arg = DIGI_WORD_SIZE_5; break;
 		case CS6: arg = DIGI_WORD_SIZE_6; break;
 		case CS7: arg = DIGI_WORD_SIZE_7; break;
 		case CS8: arg = DIGI_WORD_SIZE_8; break;
 		default:
-			dbg( "digi_set_termios: can't handle word size %d",
-				(cflag&CSIZE) );
+			dbg("digi_set_termios: can't handle word size %d",
+				(cflag&CSIZE));
 			break;
 		}
 
-		if( arg != -1 ) {
+		if (arg != -1) {
 			buf[i++] = DIGI_CMD_SET_WORD_SIZE;
 			buf[i++] = priv->dp_port_num;
 			buf[i++] = arg;
@@ -1068,9 +1011,9 @@
 	}
 
 	/* set stop bits */
-	if( (cflag&CSTOPB) != (old_cflag&CSTOPB) ) {
+	if ((cflag&CSTOPB) != (old_cflag&CSTOPB)) {
 
-		if( (cflag&CSTOPB) )
+		if ((cflag&CSTOPB))
 			arg = DIGI_STOP_BITS_2;
 		else
 			arg = DIGI_STOP_BITS_1;
@@ -1083,18 +1026,15 @@
 	}
 
 	/* set input flow control */
-	if( (iflag&IXOFF) != (old_iflag&IXOFF)
-	|| (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) {
-
+	if ((iflag&IXOFF) != (old_iflag&IXOFF)
+	    || (cflag&CRTSCTS) != (old_cflag&CRTSCTS)) {
 		arg = 0;
-
-		if( (iflag&IXOFF) )
+		if (iflag&IXOFF)
 			arg |= DIGI_INPUT_FLOW_CONTROL_XON_XOFF;
 		else
 			arg &= ~DIGI_INPUT_FLOW_CONTROL_XON_XOFF;
 
-		if( (cflag&CRTSCTS) ) {
-
+		if (cflag&CRTSCTS) {
 			arg |= DIGI_INPUT_FLOW_CONTROL_RTS;
 
 			/* On USB-4 it is necessary to assert RTS prior */
@@ -1107,43 +1047,37 @@
 		} else {
 			arg &= ~DIGI_INPUT_FLOW_CONTROL_RTS;
 		}
-
 		buf[i++] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
 		buf[i++] = priv->dp_port_num;
 		buf[i++] = arg;
 		buf[i++] = 0;
-
 	}
 
 	/* set output flow control */
-	if( (iflag&IXON) != (old_iflag&IXON)
-	|| (cflag&CRTSCTS) != (old_cflag&CRTSCTS) ) {
-
+	if ((iflag&IXON) != (old_iflag&IXON)
+	    || (cflag&CRTSCTS) != (old_cflag&CRTSCTS)) {
 		arg = 0;
-
-		if( (iflag&IXON) )
+		if (iflag&IXON)
 			arg |= DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF;
 		else
 			arg &= ~DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF;
 
-		if( (cflag&CRTSCTS) ) {
+		if (cflag&CRTSCTS) {
 			arg |= DIGI_OUTPUT_FLOW_CONTROL_CTS;
 		} else {
 			arg &= ~DIGI_OUTPUT_FLOW_CONTROL_CTS;
-			port->tty->hw_stopped = 0;
+			tty->hw_stopped = 0;
 		}
 
 		buf[i++] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL;
 		buf[i++] = priv->dp_port_num;
 		buf[i++] = arg;
 		buf[i++] = 0;
-
 	}
 
 	/* set receive enable/disable */
-	if( (cflag&CREAD) != (old_cflag&CREAD) ) {
-
-		if( (cflag&CREAD) )
+	if ((cflag&CREAD) != (old_cflag&CREAD)) {
+		if (cflag&CREAD)
 			arg = DIGI_ENABLE;
 		else
 			arg = DIGI_DISABLE;
@@ -1152,32 +1086,26 @@
 		buf[i++] = priv->dp_port_num;
 		buf[i++] = arg;
 		buf[i++] = 0;
-
 	}
-
-	if( (ret=digi_write_oob_command( port, buf, i, 1 )) != 0 )
-		dbg( "digi_set_termios: write oob failed, ret=%d", ret );
+	if ((ret = digi_write_oob_command(port, buf, i, 1)) != 0)
+		dbg("digi_set_termios: write oob failed, ret=%d", ret);
 
 }
 
 
-static void digi_break_ctl( struct usb_serial_port *port, int break_state )
+static void digi_break_ctl(struct usb_serial_port *port, int break_state)
 {
-
 	unsigned char buf[4];
 
-
 	buf[0] = DIGI_CMD_BREAK_CONTROL;
 	buf[1] = 2;				/* length */
 	buf[2] = break_state ? 1 : 0;
 	buf[3] = 0;				/* pad */
-
-	digi_write_inb_command( port, buf, 4, 0 );
-
+	digi_write_inb_command(port, buf, 4, 0);
 }
 
 
-static int digi_tiocmget( struct usb_serial_port *port, struct file *file )
+static int digi_tiocmget(struct usb_serial_port *port, struct file *file)
 {
 	struct digi_port *priv = usb_get_serial_port_data(port);
 	unsigned int val;
@@ -1185,15 +1113,15 @@
 
 	dbg("%s: TOP: port=%d", __FUNCTION__, priv->dp_port_num);
 
-	spin_lock_irqsave( &priv->dp_port_lock, flags );
+	spin_lock_irqsave(&priv->dp_port_lock, flags);
 	val = priv->dp_modem_signals;
-	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
 	return val;
 }
 
 
-static int digi_tiocmset( struct usb_serial_port *port, struct file *file,
-	unsigned int set, unsigned int clear )
+static int digi_tiocmset(struct usb_serial_port *port, struct file *file,
+	unsigned int set, unsigned int clear)
 {
 	struct digi_port *priv = usb_get_serial_port_data(port);
 	unsigned int val;
@@ -1201,41 +1129,34 @@
 
 	dbg("%s: TOP: port=%d", __FUNCTION__, priv->dp_port_num);
 
-	spin_lock_irqsave( &priv->dp_port_lock, flags );
+	spin_lock_irqsave(&priv->dp_port_lock, flags);
 	val = (priv->dp_modem_signals & ~clear) | set;
-	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-	return digi_set_modem_signals( port, val, 1 );
+	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+	return digi_set_modem_signals(port, val, 1);
 }
 
 
-static int digi_ioctl( struct usb_serial_port *port, struct file *file,
-	unsigned int cmd, unsigned long arg )
+static int digi_ioctl(struct usb_serial_port *port, struct file *file,
+	unsigned int cmd, unsigned long arg)
 {
-
 	struct digi_port *priv = usb_get_serial_port_data(port);
-
-dbg( "digi_ioctl: TOP: port=%d, cmd=0x%x", priv->dp_port_num, cmd );
+	dbg("digi_ioctl: TOP: port=%d, cmd=0x%x", priv->dp_port_num, cmd);
 
 	switch (cmd) {
-
 	case TIOCMIWAIT:
 		/* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
 		/* TODO */
-		return( 0 );
-
+		return 0;
 	case TIOCGICOUNT:
 		/* return count of modemline transitions */
 		/* TODO */
 		return 0;
-
 	}
-
-	return( -ENOIOCTLCMD );
+	return -ENOIOCTLCMD;
 
 }
 
-
-static int digi_write( struct usb_serial_port *port, const unsigned char *buf, int count )
+static int digi_write(struct usb_serial_port *port, const unsigned char *buf, int count)
 {
 
 	int ret,data_len,new_len;
@@ -1243,35 +1164,29 @@
 	unsigned char *data = port->write_urb->transfer_buffer;
 	unsigned long flags = 0;
 
-
-dbg( "digi_write: TOP: port=%d, count=%d, in_interrupt=%ld",
-priv->dp_port_num, count, in_interrupt() );
+	dbg("digi_write: TOP: port=%d, count=%d, in_interrupt=%ld",
+		priv->dp_port_num, count, in_interrupt());
 
 	/* copy user data (which can sleep) before getting spin lock */
-	count = min( count, port->bulk_out_size-2 );
-	count = min( 64, count);
+	count = min(count, port->bulk_out_size-2);
+	count = min(64, count);
 
 	/* be sure only one write proceeds at a time */
 	/* there are races on the port private buffer */
 	/* and races to check write_urb->status */
-	spin_lock_irqsave( &priv->dp_port_lock, flags );
+	spin_lock_irqsave(&priv->dp_port_lock, flags);
 
 	/* wait for urb status clear to submit another urb */
-	if( port->write_urb->status == -EINPROGRESS
-	|| priv->dp_write_urb_in_use ) {
-
+	if (port->write_urb->status == -EINPROGRESS || priv->dp_write_urb_in_use) {
 		/* buffer data if count is 1 (probably put_char) if possible */
-		if( count == 1 && priv->dp_out_buf_len < DIGI_OUT_BUF_SIZE ) {
+		if (count == 1 && priv->dp_out_buf_len < DIGI_OUT_BUF_SIZE) {
 			priv->dp_out_buf[priv->dp_out_buf_len++] = *buf;
 			new_len = 1;
 		} else {
 			new_len = 0;
 		}
-
-		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-
-		return( new_len );
-
+		spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+		return new_len;
 	}
 
 	/* allow space for any buffered data and for new data, up to */
@@ -1279,9 +1194,9 @@
 	new_len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len);
 	data_len = new_len + priv->dp_out_buf_len;
 
-	if( data_len == 0 ) {
-		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-		return( 0 );
+	if (data_len == 0) {
+		spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+		return 0;
 	}
 
 	port->write_urb->transfer_buffer_length = data_len+2;
@@ -1291,32 +1206,29 @@
 	*data++ = data_len;
 
 	/* copy in buffered data first */
-	memcpy( data, priv->dp_out_buf, priv->dp_out_buf_len );
+	memcpy(data, priv->dp_out_buf, priv->dp_out_buf_len);
 	data += priv->dp_out_buf_len;
 
 	/* copy in new data */
-	memcpy( data, buf, new_len );
+	memcpy(data, buf, new_len);
 
-	if( (ret=usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0 ) {
+	if ((ret = usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0) {
 		priv->dp_write_urb_in_use = 1;
 		ret = new_len;
 		priv->dp_out_buf_len = 0;
 	}
 
 	/* return length of new data written, or error */
-	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-	if( ret < 0 ) {
-		err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__,
-			ret, priv->dp_port_num );
-	}
-
-dbg( "digi_write: returning %d", ret );
-	return( ret );
+	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+	if (ret < 0)
+		err("%s: usb_submit_urb failed, ret=%d, port=%d",
+			__FUNCTION__, ret, priv->dp_port_num);
+	dbg("digi_write: returning %d", ret);
+	return ret;
 
 } 
 
-
-static void digi_write_bulk_callback( struct urb *urb )
+static void digi_write_bulk_callback(struct urb *urb)
 {
 
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -1326,153 +1238,136 @@
 	int ret = 0;
 	int status = urb->status;
 
-
-	dbg("digi_write_bulk_callback: TOP, urb status=%d", status);
+	dbg("digi_write_bulk_callback: TOP, urb->status=%d", status);
 
 	/* port and serial sanity check */
-	if( port == NULL || (priv=usb_get_serial_port_data(port)) == NULL ) {
+	if (port == NULL || (priv=usb_get_serial_port_data(port)) == NULL) {
 		err("%s: port or port->private is NULL, status=%d",
 		    __FUNCTION__, status);
 		return;
 	}
 	serial = port->serial;
-	if( serial == NULL || (serial_priv=usb_get_serial_data(serial)) == NULL ) {
+	if (serial == NULL || (serial_priv=usb_get_serial_data(serial)) == NULL) {
 		err("%s: serial or serial->private is NULL, status=%d",
 		    __FUNCTION__, status);
 		return;
 	}
 
 	/* handle oob callback */
-	if( priv->dp_port_num == serial_priv->ds_oob_port_num ) {
-		dbg( "digi_write_bulk_callback: oob callback" );
-		spin_lock( &priv->dp_port_lock );
+	if (priv->dp_port_num == serial_priv->ds_oob_port_num) {
+		dbg("digi_write_bulk_callback: oob callback");
+		spin_lock(&priv->dp_port_lock);
 		priv->dp_write_urb_in_use = 0;
-		wake_up_interruptible( &port->write_wait );
-		spin_unlock( &priv->dp_port_lock );
+		wake_up_interruptible(&port->write_wait);
+		spin_unlock(&priv->dp_port_lock);
 		return;
 	}
 
 	/* try to send any buffered data on this port, if it is open */
-	spin_lock( &priv->dp_port_lock );
+	spin_lock(&priv->dp_port_lock);
 	priv->dp_write_urb_in_use = 0;
-	if( port->open_count && port->write_urb->status != -EINPROGRESS
-	&& priv->dp_out_buf_len > 0 ) {
-
+	if (port->open_count && port->write_urb->status != -EINPROGRESS
+	    && priv->dp_out_buf_len > 0) {
 		*((unsigned char *)(port->write_urb->transfer_buffer))
 			= (unsigned char)DIGI_CMD_SEND_DATA;
 		*((unsigned char *)(port->write_urb->transfer_buffer)+1)
 			= (unsigned char)priv->dp_out_buf_len;
-
-		port->write_urb->transfer_buffer_length
-			= priv->dp_out_buf_len+2;
+		port->write_urb->transfer_buffer_length = priv->dp_out_buf_len+2;
 		port->write_urb->dev = serial->dev;
-
-		memcpy( port->write_urb->transfer_buffer+2, priv->dp_out_buf,
-			priv->dp_out_buf_len );
-
-		if( (ret=usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0 ) {
+		memcpy(port->write_urb->transfer_buffer+2, priv->dp_out_buf,
+			priv->dp_out_buf_len);
+		if ((ret = usb_submit_urb(port->write_urb, GFP_ATOMIC)) == 0) {
 			priv->dp_write_urb_in_use = 1;
 			priv->dp_out_buf_len = 0;
 		}
-
 	}
-
 	/* wake up processes sleeping on writes immediately */
-	digi_wakeup_write( port );
-
+	digi_wakeup_write(port);
 	/* also queue up a wakeup at scheduler time, in case we */
 	/* lost the race in write_chan(). */
 	schedule_work(&priv->dp_wakeup_work);
 
-	spin_unlock( &priv->dp_port_lock );
-
-	if( ret ) {
-		err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__,
-			ret, priv->dp_port_num );
-	}
-
+	spin_unlock(&priv->dp_port_lock);
+	if (ret)
+		err("%s: usb_submit_urb failed, ret=%d, port=%d",
+			__FUNCTION__, ret, priv->dp_port_num);
 }
 
-
-static int digi_write_room( struct usb_serial_port *port )
+static int digi_write_room(struct usb_serial_port *port)
 {
 
 	int room;
 	struct digi_port *priv = usb_get_serial_port_data(port);
 	unsigned long flags = 0;
 
+	spin_lock_irqsave(&priv->dp_port_lock, flags);
 
-	spin_lock_irqsave( &priv->dp_port_lock, flags );
-
-	if( port->write_urb->status == -EINPROGRESS
-	|| priv->dp_write_urb_in_use )
+	if (port->write_urb->status == -EINPROGRESS || priv->dp_write_urb_in_use)
 		room = 0;
 	else
 		room = port->bulk_out_size - 2 - priv->dp_out_buf_len;
 
-	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-
-dbg( "digi_write_room: port=%d, room=%d", priv->dp_port_num, room );
-	return( room );
+	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+	dbg("digi_write_room: port=%d, room=%d", priv->dp_port_num, room);
+	return room;
 
 }
 
-
-static int digi_chars_in_buffer( struct usb_serial_port *port )
+static int digi_chars_in_buffer(struct usb_serial_port *port)
 {
 
 	struct digi_port *priv = usb_get_serial_port_data(port);
 
 
-	if( port->write_urb->status == -EINPROGRESS
-	|| priv->dp_write_urb_in_use ) {
-dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, port->bulk_out_size - 2 );
-		/* return( port->bulk_out_size - 2 ); */
-		return( 256 );
+	if (port->write_urb->status == -EINPROGRESS
+	    || priv->dp_write_urb_in_use) {
+		dbg("digi_chars_in_buffer: port=%d, chars=%d",
+			priv->dp_port_num, port->bulk_out_size - 2);
+		/* return(port->bulk_out_size - 2); */
+		return 256;
 	} else {
-dbg( "digi_chars_in_buffer: port=%d, chars=%d", priv->dp_port_num, priv->dp_out_buf_len );
-		return( priv->dp_out_buf_len );
+		dbg("digi_chars_in_buffer: port=%d, chars=%d",
+			priv->dp_port_num, priv->dp_out_buf_len);
+		return priv->dp_out_buf_len;
 	}
 
 }
 
 
-static int digi_open( struct usb_serial_port *port, struct file *filp )
+static int digi_open(struct usb_serial_port *port, struct file *filp)
 {
-
 	int ret;
 	unsigned char buf[32];
 	struct digi_port *priv = usb_get_serial_port_data(port);
 	struct ktermios not_termios;
 	unsigned long flags = 0;
 
-
-dbg( "digi_open: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_count );
+	dbg("digi_open: TOP: port=%d, open_count=%d",
+		priv->dp_port_num, port->open_count);
 
 	/* be sure the device is started up */
-	if( digi_startup_device( port->serial ) != 0 )
-		return( -ENXIO );
+	if (digi_startup_device(port->serial) != 0)
+		return -ENXIO;
 
-	spin_lock_irqsave( &priv->dp_port_lock, flags );
+	spin_lock_irqsave(&priv->dp_port_lock, flags);
 
 	/* don't wait on a close in progress for non-blocking opens */
-	if( priv->dp_in_close && (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) {
-		spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-		return( -EAGAIN );
+	if (priv->dp_in_close && (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0) {
+		spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+		return -EAGAIN;
 	}
 
 	/* wait for a close in progress to finish */
-	while( priv->dp_in_close ) {
+	while(priv->dp_in_close) {
 		cond_wait_interruptible_timeout_irqrestore(
 			&priv->dp_close_wait, DIGI_RETRY_TIMEOUT,
-			&priv->dp_port_lock, flags );
-		if( signal_pending(current) ) {
-			return( -EINTR );
-		}
-		spin_lock_irqsave( &priv->dp_port_lock, flags );
+			&priv->dp_port_lock, flags);
+		if (signal_pending(current))
+			return -EINTR;
+		spin_lock_irqsave(&priv->dp_port_lock, flags);
 	}
 
-	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
  
 	/* read modem signals automatically whenever they change */
 	buf[0] = DIGI_CMD_READ_INPUT_SIGNALS;
@@ -1486,23 +1381,22 @@
 	buf[6] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
 	buf[7] = 0;
 
-	if( (ret=digi_write_oob_command( port, buf, 8, 1 )) != 0 )
-		dbg( "digi_open: write oob failed, ret=%d", ret );
+	if ((ret = digi_write_oob_command(port, buf, 8, 1)) != 0)
+		dbg("digi_open: write oob failed, ret=%d", ret);
 
 	/* set termios settings */
 	not_termios.c_cflag = ~port->tty->termios->c_cflag;
 	not_termios.c_iflag = ~port->tty->termios->c_iflag;
-	digi_set_termios( port, &not_termios );
+	digi_set_termios(port, &not_termios);
 
 	/* set DTR and RTS */
-	digi_set_modem_signals( port, TIOCM_DTR|TIOCM_RTS, 1 );
+	digi_set_modem_signals(port, TIOCM_DTR|TIOCM_RTS, 1);
 
-	return( 0 );
-
+	return 0;
 }
 
 
-static void digi_close( struct usb_serial_port *port, struct file *filp )
+static void digi_close(struct usb_serial_port *port, struct file *filp)
 {
 	DEFINE_WAIT(wait);
 	int ret;
@@ -1511,40 +1405,37 @@
 	struct digi_port *priv = usb_get_serial_port_data(port);
 	unsigned long flags = 0;
 
-
-dbg( "digi_close: TOP: port=%d, open_count=%d", priv->dp_port_num, port->open_count );
-
+	dbg("digi_close: TOP: port=%d, open_count=%d",
+		priv->dp_port_num, port->open_count);
 
 	/* if disconnected, just clear flags */
 	if (!usb_get_intfdata(port->serial->interface))
 		goto exit;
 
 	/* do cleanup only after final close on this port */
-	spin_lock_irqsave( &priv->dp_port_lock, flags );
+	spin_lock_irqsave(&priv->dp_port_lock, flags);
 	priv->dp_in_close = 1;
-	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
+	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
 
 	/* tell line discipline to process only XON/XOFF */
 	tty->closing = 1;
 
 	/* wait for output to drain */
-	if( (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) {
-		tty_wait_until_sent( tty, DIGI_CLOSE_TIMEOUT );
-	}
+	if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0)
+		tty_wait_until_sent(tty, DIGI_CLOSE_TIMEOUT);
 
 	/* flush driver and line discipline buffers */
-	if( tty->driver->flush_buffer )
-		tty->driver->flush_buffer( tty );
+	if (tty->driver->flush_buffer)
+		tty->driver->flush_buffer(tty);
 	tty_ldisc_flush(tty);
 
 	if (port->serial->dev) {
 		/* wait for transmit idle */
-		if( (filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0 ) {
-			digi_transmit_idle( port, DIGI_CLOSE_TIMEOUT );
+		if ((filp->f_flags&(O_NDELAY|O_NONBLOCK)) == 0) {
+			digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT);
 		}
-
 		/* drop DTR and RTS */
-		digi_set_modem_signals( port, 0, 0 );
+		digi_set_modem_signals(port, 0, 0);
 
 		/* disable input flow control */
 		buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL;
@@ -1576,8 +1467,8 @@
 		buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX;
 		buf[19] = 0;
 
-		if( (ret=digi_write_oob_command( port, buf, 20, 0 )) != 0 )
-			dbg( "digi_close: write oob failed, ret=%d", ret );
+		if ((ret = digi_write_oob_command(port, buf, 20, 0)) != 0)
+			dbg("digi_close: write oob failed, ret=%d", ret);
 
 		/* wait for final commands on oob port to complete */
 		prepare_to_wait(&priv->dp_flush_wait, &wait, TASK_INTERRUPTIBLE);
@@ -1587,17 +1478,14 @@
 		/* shutdown any outstanding bulk writes */
 		usb_kill_urb(port->write_urb);
 	}
-
 	tty->closing = 0;
-
 exit:
-	spin_lock_irqsave( &priv->dp_port_lock, flags );
+	spin_lock_irqsave(&priv->dp_port_lock, flags);
 	priv->dp_write_urb_in_use = 0;
 	priv->dp_in_close = 0;
-	wake_up_interruptible( &priv->dp_close_wait );
-	spin_unlock_irqrestore( &priv->dp_port_lock, flags );
-
-dbg( "digi_close: done" );
+	wake_up_interruptible(&priv->dp_close_wait);
+	spin_unlock_irqrestore(&priv->dp_port_lock, flags);
+	dbg("digi_close: done");
 }
 
 
@@ -1608,155 +1496,136 @@
 *  urbs initialized.  Returns 0 if successful, non-zero error otherwise.
 */
 
-static int digi_startup_device( struct usb_serial *serial )
+static int digi_startup_device(struct usb_serial *serial)
 {
-
 	int i,ret = 0;
 	struct digi_serial *serial_priv = usb_get_serial_data(serial);
 	struct usb_serial_port *port;
 
-
 	/* be sure this happens exactly once */
-	spin_lock( &serial_priv->ds_serial_lock );
-	if( serial_priv->ds_device_started ) {
-		spin_unlock( &serial_priv->ds_serial_lock );
-		return( 0 );
+	spin_lock(&serial_priv->ds_serial_lock);
+	if (serial_priv->ds_device_started) {
+		spin_unlock(&serial_priv->ds_serial_lock);
+		return 0;
 	}
 	serial_priv->ds_device_started = 1;
-	spin_unlock( &serial_priv->ds_serial_lock );
+	spin_unlock(&serial_priv->ds_serial_lock);
 
 	/* start reading from each bulk in endpoint for the device */
 	/* set USB_DISABLE_SPD flag for write bulk urbs */
-	for( i=0; i<serial->type->num_ports+1; i++ ) {
-
+	for (i = 0; i < serial->type->num_ports + 1; i++) {
 		port = serial->port[i];
-
 		port->write_urb->dev = port->serial->dev;
-
-		if( (ret=usb_submit_urb(port->read_urb, GFP_KERNEL)) != 0 ) {
-			err("%s: usb_submit_urb failed, ret=%d, port=%d", __FUNCTION__,
-			ret, i );
+		if ((ret = usb_submit_urb(port->read_urb, GFP_KERNEL)) != 0) {
+			err("%s: usb_submit_urb failed, ret=%d, port=%d",
+					__FUNCTION__, ret, i);
 			break;
 		}
-
 	}
-
-	return( ret );
-
+	return ret;
 }
 
 
-static int digi_startup( struct usb_serial *serial )
+static int digi_startup(struct usb_serial *serial)
 {
 
 	int i;
 	struct digi_port *priv;
 	struct digi_serial *serial_priv;
 
-
-dbg( "digi_startup: TOP" );
+	dbg("digi_startup: TOP");
 
 	/* allocate the private data structures for all ports */
 	/* number of regular ports + 1 for the out-of-band port */
-	for( i=0; i<serial->type->num_ports+1; i++ ) {
-
+	for(i = 0; i < serial->type->num_ports + 1; i++) {
 		/* allocate port private structure */
-		priv = kmalloc( sizeof(struct digi_port),
-			GFP_KERNEL );
-		if( priv == (struct digi_port *)0 ) {
-			while( --i >= 0 )
-				kfree( usb_get_serial_port_data(serial->port[i]) );
-			return( 1 );			/* error */
+		priv = kmalloc(sizeof(struct digi_port), GFP_KERNEL);
+		if (priv == NULL) {
+			while (--i >= 0)
+				kfree(usb_get_serial_port_data(serial->port[i]));
+			return 1;			/* error */
 		}
 
 		/* initialize port private structure */
-		spin_lock_init( &priv->dp_port_lock );
+		spin_lock_init(&priv->dp_port_lock);
 		priv->dp_port_num = i;
 		priv->dp_out_buf_len = 0;
 		priv->dp_write_urb_in_use = 0;
 		priv->dp_modem_signals = 0;
-		init_waitqueue_head( &priv->dp_modem_change_wait );
+		init_waitqueue_head(&priv->dp_modem_change_wait);
 		priv->dp_transmit_idle = 0;
-		init_waitqueue_head( &priv->dp_transmit_idle_wait );
+		init_waitqueue_head(&priv->dp_transmit_idle_wait);
 		priv->dp_throttled = 0;
 		priv->dp_throttle_restart = 0;
-		init_waitqueue_head( &priv->dp_flush_wait );
+		init_waitqueue_head(&priv->dp_flush_wait);
 		priv->dp_in_close = 0;
-		init_waitqueue_head( &priv->dp_close_wait );
+		init_waitqueue_head(&priv->dp_close_wait);
 		INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock);
 		priv->dp_port = serial->port[i];
-
 		/* initialize write wait queue for this port */
-		init_waitqueue_head( &serial->port[i]->write_wait );
+		init_waitqueue_head(&serial->port[i]->write_wait);
 
 		usb_set_serial_port_data(serial->port[i], priv);
 	}
 
 	/* allocate serial private structure */
-	serial_priv = kmalloc( sizeof(struct digi_serial),
-		GFP_KERNEL );
-	if( serial_priv == (struct digi_serial *)0 ) {
-		for( i=0; i<serial->type->num_ports+1; i++ )
-			kfree( usb_get_serial_port_data(serial->port[i]) );
-		return( 1 );			/* error */
+	serial_priv = kmalloc(sizeof(struct digi_serial), GFP_KERNEL);
+	if (serial_priv == NULL) {
+		for (i = 0; i < serial->type->num_ports + 1; i++)
+			kfree(usb_get_serial_port_data(serial->port[i]));
+		return 1;			/* error */
 	}
 
 	/* initialize serial private structure */
-	spin_lock_init( &serial_priv->ds_serial_lock );
+	spin_lock_init(&serial_priv->ds_serial_lock);
 	serial_priv->ds_oob_port_num = serial->type->num_ports;
 	serial_priv->ds_oob_port = serial->port[serial_priv->ds_oob_port_num];
 	serial_priv->ds_device_started = 0;
 	usb_set_serial_data(serial, serial_priv);
 
-	return( 0 );
-
+	return 0;
 }
 
 
-static void digi_shutdown( struct usb_serial *serial )
+static void digi_shutdown(struct usb_serial *serial)
 {
-
 	int i;
-
-
-dbg( "digi_shutdown: TOP, in_interrupt()=%ld", in_interrupt() );
+	dbg("digi_shutdown: TOP, in_interrupt()=%ld", in_interrupt());
 
 	/* stop reads and writes on all ports */
-	for( i=0; i<serial->type->num_ports+1; i++ ) {
+	for (i = 0; i < serial->type->num_ports + 1; i++) {
 		usb_kill_urb(serial->port[i]->read_urb);
 		usb_kill_urb(serial->port[i]->write_urb);
 	}
 
 	/* free the private data structures for all ports */
 	/* number of regular ports + 1 for the out-of-band port */
-	for( i=0; i<serial->type->num_ports+1; i++ )
-		kfree( usb_get_serial_port_data(serial->port[i]) );
-	kfree( usb_get_serial_data(serial) );
+	for(i = 0; i < serial->type->num_ports + 1; i++)
+		kfree(usb_get_serial_port_data(serial->port[i]));
+	kfree(usb_get_serial_data(serial));
 }
 
 
-static void digi_read_bulk_callback( struct urb *urb )
+static void digi_read_bulk_callback(struct urb *urb)
 {
-
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct digi_port *priv;
 	struct digi_serial *serial_priv;
 	int ret;
 	int status = urb->status;
 
-
-dbg( "digi_read_bulk_callback: TOP" );
+	dbg("digi_read_bulk_callback: TOP");
 
 	/* port sanity check, do not resubmit if port is not valid */
-	if( port == NULL || (priv=usb_get_serial_port_data(port)) == NULL ) {
+	if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) {
 		err("%s: port or port->private is NULL, status=%d",
 		    __FUNCTION__, status);
 		return;
 	}
-	if( port->serial == NULL
-	|| (serial_priv=usb_get_serial_data(port->serial)) == NULL ) {
+	if (port->serial == NULL ||
+		(serial_priv=usb_get_serial_data(port->serial)) == NULL) {
 		err("%s: serial is bad or serial->private is NULL, status=%d",
-		    __FUNCTION__, status);
+			__FUNCTION__, status);
 		return;
 	}
 
@@ -1768,24 +1637,23 @@
 	}
 
 	/* handle oob or inb callback, do not resubmit if error */
-	if( priv->dp_port_num == serial_priv->ds_oob_port_num ) {
-		if( digi_read_oob_callback( urb ) != 0 )
+	if (priv->dp_port_num == serial_priv->ds_oob_port_num) {
+		if (digi_read_oob_callback(urb) != 0)
 			return;
 	} else {
-		if( digi_read_inb_callback( urb ) != 0 )
+		if (digi_read_inb_callback(urb) != 0)
 			return;
 	}
 
 	/* continue read */
 	urb->dev = port->serial->dev;
-	if( (ret=usb_submit_urb(urb, GFP_ATOMIC)) != 0 ) {
-		err("%s: failed resubmitting urb, ret=%d, port=%d", __FUNCTION__,
-			ret, priv->dp_port_num );
+	if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) != 0) {
+		err("%s: failed resubmitting urb, ret=%d, port=%d",
+		    __FUNCTION__, ret, priv->dp_port_num);
 	}
 
 }
 
-
 /* 
 *  Digi Read INB Callback
 *
@@ -1796,7 +1664,7 @@
 *  throttled, and -1 if the sanity checks failed.
 */
 
-static int digi_read_inb_callback( struct urb *urb )
+static int digi_read_inb_callback(struct urb *urb)
 {
 
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -1812,72 +1680,67 @@
 
 	/* do not process callbacks on closed ports */
 	/* but do continue the read chain */
-	if( port->open_count == 0 )
-		return( 0 );
+	if (port->open_count == 0)
+		return 0;
 
 	/* short/multiple packet check */
-	if( urb->actual_length != len + 2 ) {
-		err("%s: INCOMPLETE OR MULTIPLE PACKET, urb status=%d, "
+	if (urb->actual_length != len + 2) {
+     		err("%s: INCOMPLETE OR MULTIPLE PACKET, urb->status=%d, "
 		    "port=%d, opcode=%d, len=%d, actual_length=%d, "
-		    "port_status=%d", __FUNCTION__, status, priv->dp_port_num,
+		    "status=%d", __FUNCTION__, status, priv->dp_port_num,
 		    opcode, len, urb->actual_length, port_status);
-		return( -1 );
+		return -1;
 	}
 
-	spin_lock( &priv->dp_port_lock );
+	spin_lock(&priv->dp_port_lock);
 
 	/* check for throttle; if set, do not resubmit read urb */
 	/* indicate the read chain needs to be restarted on unthrottle */
 	throttled = priv->dp_throttled;
-	if( throttled )
+	if (throttled)
 		priv->dp_throttle_restart = 1;
 
 	/* receive data */
-	if( opcode == DIGI_CMD_RECEIVE_DATA ) {
-
+	if (opcode == DIGI_CMD_RECEIVE_DATA) {
 		/* get flag from port_status */
 		flag = 0;
 
 		/* overrun is special, not associated with a char */
-		if (port_status & DIGI_OVERRUN_ERROR) {
-			tty_insert_flip_char( tty, 0, TTY_OVERRUN );
-		}
+		if (port_status & DIGI_OVERRUN_ERROR)
+			tty_insert_flip_char(tty, 0, TTY_OVERRUN);
 
 		/* break takes precedence over parity, */
 		/* which takes precedence over framing errors */
-		if (port_status & DIGI_BREAK_ERROR) {
+		if (port_status & DIGI_BREAK_ERROR)
 			flag = TTY_BREAK;
-		} else if (port_status & DIGI_PARITY_ERROR) {
+		else if (port_status & DIGI_PARITY_ERROR)
 			flag = TTY_PARITY;
-		} else if (port_status & DIGI_FRAMING_ERROR) {
+		else if (port_status & DIGI_FRAMING_ERROR)
 			flag = TTY_FRAME;
-		}
 
 		/* data length is len-1 (one byte of len is port_status) */
 		--len;
 
 		len = tty_buffer_request_room(tty, len);
-		if( len > 0 ) {
+		if (len > 0) {
 			/* Hot path */
-			if(flag == TTY_NORMAL)
+			if (flag == TTY_NORMAL)
 				tty_insert_flip_string(tty, data, len);
 			else {
 				for(i = 0; i < len; i++)
 					tty_insert_flip_char(tty, data[i], flag);
 			}
-			tty_flip_buffer_push( tty );
+			tty_flip_buffer_push(tty);
 		}
 	}
+	spin_unlock(&priv->dp_port_lock);
 
-	spin_unlock( &priv->dp_port_lock );
+	if (opcode == DIGI_CMD_RECEIVE_DISABLE)
+		dbg("%s: got RECEIVE_DISABLE", __FUNCTION__);
+	else if (opcode != DIGI_CMD_RECEIVE_DATA)
+		dbg("%s: unknown opcode: %d", __FUNCTION__, opcode);
 
-	if( opcode == DIGI_CMD_RECEIVE_DISABLE ) {
-		dbg("%s: got RECEIVE_DISABLE", __FUNCTION__ );
-	} else if( opcode != DIGI_CMD_RECEIVE_DATA ) {
-		dbg("%s: unknown opcode: %d", __FUNCTION__, opcode );
-	}
-
-	return( throttled ? 1 : 0 );
+	return(throttled ? 1 : 0);
 
 }
 
@@ -1891,7 +1754,7 @@
 *  -1 if the sanity checks failed.
 */
 
-static int digi_read_oob_callback( struct urb *urb )
+static int digi_read_oob_callback(struct urb *urb)
 {
 
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -1900,87 +1763,75 @@
 	int opcode, line, status, val;
 	int i;
 
-
-dbg( "digi_read_oob_callback: port=%d, len=%d", priv->dp_port_num,
-urb->actual_length );
+	dbg("digi_read_oob_callback: port=%d, len=%d",
+			priv->dp_port_num, urb->actual_length);
 
 	/* handle each oob command */
-	for( i=0; i<urb->actual_length-3; ) {
-
+	for(i = 0; i < urb->actual_length - 3;) {
 		opcode = ((unsigned char *)urb->transfer_buffer)[i++];
 		line = ((unsigned char *)urb->transfer_buffer)[i++];
 		status = ((unsigned char *)urb->transfer_buffer)[i++];
 		val = ((unsigned char *)urb->transfer_buffer)[i++];
 
-dbg( "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d",
-opcode, line, status, val );
+		dbg("digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d",
+			opcode, line, status, val);
 
-		if( status != 0 || line >= serial->type->num_ports )
+		if (status != 0 || line >= serial->type->num_ports)
 			continue;
 
 		port = serial->port[line];
 
-		if ((priv=usb_get_serial_port_data(port)) == NULL )
+		if ((priv=usb_get_serial_port_data(port)) == NULL)
 			return -1;
 
-		if( opcode == DIGI_CMD_READ_INPUT_SIGNALS ) {
-
-			spin_lock( &priv->dp_port_lock );
-
+		if (opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
+			spin_lock(&priv->dp_port_lock);
 			/* convert from digi flags to termiox flags */
-			if( val & DIGI_READ_INPUT_SIGNALS_CTS ) {
+			if (val & DIGI_READ_INPUT_SIGNALS_CTS) {
 				priv->dp_modem_signals |= TIOCM_CTS;
 				/* port must be open to use tty struct */
-				if( port->open_count
-				&& port->tty->termios->c_cflag & CRTSCTS ) {
+				if (port->open_count
+					&& port->tty->termios->c_cflag & CRTSCTS) {
 					port->tty->hw_stopped = 0;
-					digi_wakeup_write( port );
+					digi_wakeup_write(port);
 				}
 			} else {
 				priv->dp_modem_signals &= ~TIOCM_CTS;
 				/* port must be open to use tty struct */
-				if( port->open_count
-				&& port->tty->termios->c_cflag & CRTSCTS ) {
+				if (port->open_count
+					&& port->tty->termios->c_cflag & CRTSCTS) {
 					port->tty->hw_stopped = 1;
 				}
 			}
-			if( val & DIGI_READ_INPUT_SIGNALS_DSR )
+			if (val & DIGI_READ_INPUT_SIGNALS_DSR)
 				priv->dp_modem_signals |= TIOCM_DSR;
 			else
 				priv->dp_modem_signals &= ~TIOCM_DSR;
-			if( val & DIGI_READ_INPUT_SIGNALS_RI )
+			if (val & DIGI_READ_INPUT_SIGNALS_RI)
 				priv->dp_modem_signals |= TIOCM_RI;
 			else
 				priv->dp_modem_signals &= ~TIOCM_RI;
-			if( val & DIGI_READ_INPUT_SIGNALS_DCD )
+			if (val & DIGI_READ_INPUT_SIGNALS_DCD)
 				priv->dp_modem_signals |= TIOCM_CD;
 			else
 				priv->dp_modem_signals &= ~TIOCM_CD;
 
-			wake_up_interruptible( &priv->dp_modem_change_wait );
-			spin_unlock( &priv->dp_port_lock );
-
-		} else if( opcode == DIGI_CMD_TRANSMIT_IDLE ) {
-
-			spin_lock( &priv->dp_port_lock );
+			wake_up_interruptible(&priv->dp_modem_change_wait);
+			spin_unlock(&priv->dp_port_lock);
+		} else if (opcode == DIGI_CMD_TRANSMIT_IDLE) {
+			spin_lock(&priv->dp_port_lock);
 			priv->dp_transmit_idle = 1;
-			wake_up_interruptible( &priv->dp_transmit_idle_wait );
-			spin_unlock( &priv->dp_port_lock );
-
-		} else if( opcode == DIGI_CMD_IFLUSH_FIFO ) {
-
-			wake_up_interruptible( &priv->dp_flush_wait );
-
+			wake_up_interruptible(&priv->dp_transmit_idle_wait);
+			spin_unlock(&priv->dp_port_lock);
+		} else if (opcode == DIGI_CMD_IFLUSH_FIFO) {
+			wake_up_interruptible(&priv->dp_flush_wait);
 		}
-
 	}
-
-	return( 0 );
+	return 0;
 
 }
 
-
-static int __init digi_init (void)
+static int __init digi_init(void)
 {
 	int retval;
 	retval = usb_serial_register(&digi_acceleport_2_device);
@@ -2002,12 +1853,11 @@
 	return retval;
 }
 
-
 static void __exit digi_exit (void)
 {
-	usb_deregister (&digi_driver);
-	usb_serial_deregister (&digi_acceleport_2_device);
-	usb_serial_deregister (&digi_acceleport_4_device);
+	usb_deregister(&digi_driver);
+	usb_serial_deregister(&digi_acceleport_2_device);
+	usb_serial_deregister(&digi_acceleport_4_device);
 }
 
 
@@ -2015,8 +1865,8 @@
 module_exit(digi_exit);
 
 
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 7b1673a..e4c248c 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -538,6 +538,8 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_VCP_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_TERATRONIK_D2XX_PID) },
 	{ USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) },
+	{ USB_DEVICE(EVOLUTION_VID, EVO_HYBRID_PID) },
+	{ USB_DEVICE(EVOLUTION_VID, EVO_RCM4_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ARTEMIS_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16C_PID) },
@@ -566,6 +568,7 @@
 	{ USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) },
 	{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_MAXSTREAM_PID) },
+	{ USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) },
 	{ USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID),
 		.driver_info = (kernel_ulong_t)&ftdi_olimex_quirk },
 	{ },					/* Optional parameter entry */
@@ -1166,7 +1169,9 @@
 	/* XXX see create_sysfs_attrs */
 	if (priv->chip_type != SIO) {
 		device_remove_file(&port->dev, &dev_attr_event_char);
-		if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
+		if (priv->chip_type == FT232BM ||
+		    priv->chip_type == FT2232C ||
+		    priv->chip_type == FT232RL) {
 			device_remove_file(&port->dev, &dev_attr_latency_timer);
 		}
 	}
@@ -2099,6 +2104,7 @@
 	case FT8U232AM:
 	case FT232BM:
 	case FT2232C:
+	case FT232RL:
 		/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
 		   format as the data returned from the in point */
 		if ((ret = usb_control_msg(port->serial->dev,
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index d9e4971..b57b90a 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -430,6 +430,9 @@
  */
 #define EVOLUTION_VID		0xDEEE	/* Vendor ID */
 #define EVOLUTION_ER1_PID	0x0300	/* ER1 Control Module */
+#define EVO_8U232AM_PID	0x02FF	/* Evolution robotics RCM2 (FT232AM)*/
+#define EVO_HYBRID_PID		0x0302	/* Evolution robotics RCM4 PID (FT232BM)*/
+#define EVO_RCM4_PID		0x0303	/* Evolution robotics RCM4 PID */
 
 /* Pyramid Computer GmbH */
 #define FTDI_PYRAMID_PID	0xE6C8	/* Pyramid Appliance Display */
@@ -531,6 +534,14 @@
 #define OLIMEX_VID			0x15BA
 #define OLIMEX_ARM_USB_OCD_PID		0x0003
 
+
+/*
+ * The Mobility Lab (TML)
+ * Submitted by Pierre Castella
+ */
+#define TML_VID			0x1B91	/* Vendor ID */
+#define TML_USB_SERIAL_PID	0x0064	/* USB - Serial Converter */
+
 /* Commands */
 #define FTDI_SIO_RESET 		0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL 	1 /* Set the modem control register */
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 4092f6d..b5194dc 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -24,26 +24,6 @@
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static int funsoft_ioctl(struct usb_serial_port *port, struct file *file,
-			 unsigned int cmd, unsigned long arg)
-{
-	struct ktermios t;
-
-	dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd);
-
-	if (cmd == TCSETSF) {
-		if (user_termios_to_kernel_termios(&t, (struct termios __user *)arg))
-			return -EFAULT;
-
-		dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__,
-		    t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag);
-
-		if (!(t.c_lflag & ICANON))
-			return -EINVAL;
-	}
-	return -ENOIOCTLCMD;
-}
-
 static struct usb_driver funsoft_driver = {
 	.name =		"funsoft",
 	.probe =	usb_serial_probe,
@@ -63,7 +43,6 @@
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
 	.num_ports =		1,
-	.ioctl =		funsoft_ioctl,
 };
 
 static int __init funsoft_init(void)
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 04bd3b7..f1c90cf 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1,7 +1,7 @@
 /*
  * Garmin GPS driver
  *
- * Copyright (C) 2006 Hermann Kneissel herkne@users.sourceforge.net
+ * Copyright (C) 2006,2007 Hermann Kneissel herkne@users.sourceforge.net
  *
  * The latest version of the driver can be found at
  * http://sourceforge.net/projects/garmin-gps/
@@ -34,6 +34,7 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <asm/uaccess.h>
+#include <asm/atomic.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
@@ -52,7 +53,7 @@
  */
 
 #define VERSION_MAJOR	0
-#define VERSION_MINOR	28
+#define VERSION_MINOR	31
 
 #define _STR(s) #s
 #define _DRIVER_VERSION(a,b) "v" _STR(a) "." _STR(b)
@@ -141,6 +142,8 @@
 	__u8   inbuffer [GPS_IN_BUFSIZ];  /* tty -> usb */
 	__u8   outbuffer[GPS_OUT_BUFSIZ]; /* usb -> tty */
 	__u8   privpkt[4*6];
+	atomic_t req_count;
+	atomic_t resp_count;
 	spinlock_t lock;
 	struct list_head pktlist;
 };
@@ -171,8 +174,6 @@
 #define CLEAR_HALT_REQUIRED       0x0001
 
 #define FLAGS_QUEUING             0x0100
-#define FLAGS_APP_RESP_SEEN       0x0200
-#define FLAGS_APP_REQ_SEEN        0x0400
 #define FLAGS_DROP_DATA           0x0800
 
 #define FLAGS_GSP_SKIP            0x1000
@@ -186,7 +187,8 @@
 /* function prototypes */
 static void gsp_next_packet(struct garmin_data * garmin_data_p);
 static int  garmin_write_bulk(struct usb_serial_port *port,
-			     const unsigned char *buf, int count);
+			     const unsigned char *buf, int count,
+			     int dismiss_ack);
 
 /* some special packets to be send or received */
 static unsigned char const GARMIN_START_SESSION_REQ[]
@@ -233,9 +235,7 @@
 
 static inline int noResponseFromAppLayer(struct garmin_data * garmin_data_p)
 {
-	return ((garmin_data_p->flags
-				& (FLAGS_APP_REQ_SEEN|FLAGS_APP_RESP_SEEN))
-	        == FLAGS_APP_REQ_SEEN);
+	return atomic_read(&garmin_data_p->req_count) == atomic_read(&garmin_data_p->resp_count);
 }
 
 
@@ -463,7 +463,7 @@
 	usbdata[2] = __cpu_to_le32(size);
 
 	garmin_write_bulk (garmin_data_p->port, garmin_data_p->inbuffer,
-			   GARMIN_PKTHDR_LENGTH+size);
+			   GARMIN_PKTHDR_LENGTH+size, 0);
 
 	/* if this was an abort-transfer command, flush all
 	   queued data. */
@@ -818,7 +818,7 @@
 			if (garmin_data_p->insize >= len) {
 				garmin_write_bulk (garmin_data_p->port,
 				                   garmin_data_p->inbuffer,
-				                   len);
+				                   len, 0);
 				garmin_data_p->insize = 0;
 
 				/* if this was an abort-transfer command,
@@ -893,10 +893,11 @@
 
 	struct usb_serial_port *port = garmin_data_p->port;
 
-	if (port != NULL && garmin_data_p->flags & FLAGS_APP_RESP_SEEN) {
+	if (port != NULL && atomic_read(&garmin_data_p->resp_count)) {
 		/* send a terminate command */
 		status = garmin_write_bulk(port, GARMIN_STOP_TRANSFER_REQ,
-		                           sizeof(GARMIN_STOP_TRANSFER_REQ));
+		                           sizeof(GARMIN_STOP_TRANSFER_REQ),
+					   1);
 	}
 
 	/* flush all queued data */
@@ -939,7 +940,8 @@
 		dbg("%s - starting session ...", __FUNCTION__);
 		garmin_data_p->state = STATE_ACTIVE;
 		status = garmin_write_bulk(port, GARMIN_START_SESSION_REQ,
-		                           sizeof(GARMIN_START_SESSION_REQ));
+		                           sizeof(GARMIN_START_SESSION_REQ),
+					   0);
 
 		if (status >= 0) {
 
@@ -950,7 +952,8 @@
 			/* not needed, but the win32 driver does it too ... */
 			status = garmin_write_bulk(port,
 						   GARMIN_START_SESSION_REQ2,
-			                           sizeof(GARMIN_START_SESSION_REQ2));
+			                           sizeof(GARMIN_START_SESSION_REQ2),
+						   0);
 			if (status >= 0) {
 				status = 0;
 				spin_lock_irqsave(&garmin_data_p->lock, flags);
@@ -987,6 +990,8 @@
 	garmin_data_p->mode  = initial_mode;
 	garmin_data_p->count = 0;
 	garmin_data_p->flags = 0;
+	atomic_set(&garmin_data_p->req_count, 0);
+	atomic_set(&garmin_data_p->resp_count, 0);
 	spin_unlock_irqrestore(&garmin_data_p->lock, flags);
 
 	/* shutdown any bulk reads that might be going on */
@@ -1035,28 +1040,39 @@
 {
 	unsigned long flags;
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
-	struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
 	int status = urb->status;
 
+	if (port) {
+		struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
+
+		dbg("%s - port %d", __FUNCTION__, port->number);
+
+		if (GARMIN_LAYERID_APPL == getLayerId(urb->transfer_buffer)
+		    && (garmin_data_p->mode == MODE_GARMIN_SERIAL))  {
+			gsp_send_ack(garmin_data_p, ((__u8 *)urb->transfer_buffer)[4]);
+		}
+
+		if (status) {
+			dbg("%s - nonzero write bulk status received: %d",
+			    __FUNCTION__, urb->status);
+			spin_lock_irqsave(&garmin_data_p->lock, flags);
+			garmin_data_p->flags |= CLEAR_HALT_REQUIRED;
+			spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+		}
+
+		usb_serial_port_softint(port);
+	}
+
+	/* Ignore errors that resulted from garmin_write_bulk with dismiss_ack=1 */
+
 	/* free up the transfer buffer, as usb_free_urb() does not do this */
 	kfree (urb->transfer_buffer);
-
-	dbg("%s - port %d", __FUNCTION__, port->number);
-
-	if (status) {
-		dbg("%s - nonzero write bulk status received: %d",
-			__FUNCTION__, status);
-		spin_lock_irqsave(&garmin_data_p->lock, flags);
-		garmin_data_p->flags |= CLEAR_HALT_REQUIRED;
-		spin_unlock_irqrestore(&garmin_data_p->lock, flags);
-	}
-
-	usb_serial_port_softint(port);
 }
 
 
 static int garmin_write_bulk (struct usb_serial_port *port,
-			      const unsigned char *buf, int count)
+			      const unsigned char *buf, int count,
+			      int dismiss_ack)
 {
 	unsigned long flags;
 	struct usb_serial *serial = port->serial;
@@ -1093,13 +1109,12 @@
 			 	usb_sndbulkpipe (serial->dev,
 				port->bulk_out_endpointAddress),
 				buffer, count,
-				garmin_write_bulk_callback, port);
+				garmin_write_bulk_callback,
+				dismiss_ack ? NULL : port);
 	urb->transfer_flags |= URB_ZERO_PACKET;
 
 	if (GARMIN_LAYERID_APPL == getLayerId(buffer)) {
-		spin_lock_irqsave(&garmin_data_p->lock, flags);
-		garmin_data_p->flags |= FLAGS_APP_REQ_SEEN;
-		spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+		atomic_inc(&garmin_data_p->req_count);
 		if (garmin_data_p->mode == MODE_GARMIN_SERIAL)  {
 			pkt_clear(garmin_data_p);
 			garmin_data_p->state = STATE_GSP_WAIT_DATA;
@@ -1114,13 +1129,6 @@
 		        "failed with status = %d\n",
 				__FUNCTION__, status);
 		count = status;
-	} else {
-
-		if (GARMIN_LAYERID_APPL == getLayerId(buffer)
-		    && (garmin_data_p->mode == MODE_GARMIN_SERIAL))  {
-
-			gsp_send_ack(garmin_data_p, buffer[4]);
-		}
 	}
 
 	/* we are done with this urb, so let the host driver
@@ -1135,7 +1143,6 @@
 static int garmin_write (struct usb_serial_port *port,
 			 const unsigned char *buf, int count)
 {
-	unsigned long flags;
 	int pktid, pktsiz, len;
 	struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
 	__le32 *privpkt = (__le32 *)garmin_data_p->privpkt;
@@ -1186,9 +1193,7 @@
 				break;
 
 			case PRIV_PKTID_RESET_REQ:
-				spin_lock_irqsave(&garmin_data_p->lock, flags);
-				garmin_data_p->flags |= FLAGS_APP_REQ_SEEN;
-				spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+				atomic_inc(&garmin_data_p->req_count);
 				break;
 
 			case PRIV_PKTID_SET_DEF_MODE:
@@ -1241,8 +1246,6 @@
 static void garmin_read_process(struct garmin_data * garmin_data_p,
 				 unsigned char *data, unsigned data_length)
 {
-	unsigned long flags;
-
 	if (garmin_data_p->flags & FLAGS_DROP_DATA) {
 		/* abort-transfer cmd is actice */
 		dbg("%s - pkt dropped", __FUNCTION__);
@@ -1254,9 +1257,7 @@
 		   the device */
 		if (0 == memcmp(data, GARMIN_APP_LAYER_REPLY,
 		                sizeof(GARMIN_APP_LAYER_REPLY))) {
-			spin_lock_irqsave(&garmin_data_p->lock, flags);
-			garmin_data_p->flags |= FLAGS_APP_RESP_SEEN;
-			spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+			atomic_inc(&garmin_data_p->resp_count);
 		}
 
 		/* if throttling is active or postprecessing is required
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index dd42f57..2ecb1d2 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -2366,9 +2366,8 @@
 	int status;
 	unsigned char number = edge_port->port->number - edge_port->port->serial->minor;
 
-	if ((!edge_serial->is_epic) ||
-	    ((edge_serial->is_epic) &&
-	     (!edge_serial->epic_descriptor.Supports.IOSPSetBaudRate))) {
+	if (edge_serial->is_epic &&
+	    !edge_serial->epic_descriptor.Supports.IOSPSetBaudRate) {
 		dbg("SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d",
 		    edge_port->port->number, baudRate);
 		return 0;
@@ -2461,18 +2460,16 @@
 
 	dbg("%s - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", __FUNCTION__, regValue);
 
-	if ((!edge_serial->is_epic) ||
-	    ((edge_serial->is_epic) &&
-	     (!edge_serial->epic_descriptor.Supports.IOSPWriteMCR) &&
-	     (regNum == MCR))) {
+	if (edge_serial->is_epic &&
+	    !edge_serial->epic_descriptor.Supports.IOSPWriteMCR &&
+	    regNum == MCR) {
 		dbg("SendCmdWriteUartReg - Not writing to MCR Register");
 		return 0;
 	}
 
-	if ((!edge_serial->is_epic) ||
-	    ((edge_serial->is_epic) &&
-	     (!edge_serial->epic_descriptor.Supports.IOSPWriteLCR) &&
-	     (regNum == LCR))) {
+	if (edge_serial->is_epic &&
+	    !edge_serial->epic_descriptor.Supports.IOSPWriteLCR &&
+	    regNum == LCR) {
 		dbg ("SendCmdWriteUartReg - Not writing to LCR Register");
 		return 0;
 	}
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 0d39036..b867090 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2794,16 +2794,14 @@
 
 	dbg ("%s", __FUNCTION__);
 
-	for (i=0; i < serial->num_ports; ++i) {
+	for (i = 0; i < serial->num_ports; ++i) {
 		edge_port = usb_get_serial_port_data(serial->port[i]);
 		edge_remove_sysfs_attrs(edge_port->port);
-		if (edge_port) {
-			edge_buf_free(edge_port->ep_out_buf);
-			kfree(edge_port);
-		}
+		edge_buf_free(edge_port->ep_out_buf);
+		kfree(edge_port);
 		usb_set_serial_port_data(serial->port[i], NULL);
 	}
-	kfree (usb_get_serial_data(serial));
+	kfree(usb_get_serial_data(serial));
 	usb_set_serial_data(serial, NULL);
 }
 
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 0455c15..e836ad0 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -256,6 +256,7 @@
 	{ USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */
 	{ USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */
 	{ USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */
+	{ USB_DEVICE(0x04DD, 0x91AC) }, /* SHARP WS011SH USB Modem */
 	{ USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */
 	{ USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
 	{ USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */
@@ -545,6 +546,7 @@
 	{ USB_DEVICE(0x413C, 0x4009) }, /* Dell Axim USB Sync */
 	{ USB_DEVICE(0x4505, 0x0010) }, /* Smartphone */
 	{ USB_DEVICE(0x5E04, 0xCE00) }, /* SAGEM Wireless Assistant */
+	{ USB_DEVICE(0x0BB4, 0x00CF) }, /* HTC smartphone modems */
 	{ }                             /* Terminating entry */
 };
 
@@ -645,11 +647,13 @@
 	kfree(port->bulk_out_buffer);
 	port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
 	if (port->bulk_in_buffer == NULL) {
+		port->bulk_out_buffer = NULL; /* prevent double free */
 		goto enomem;
 	}
 	port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
 	if (port->bulk_out_buffer == NULL) {
 		kfree(port->bulk_in_buffer);
+		port->bulk_in_buffer = NULL;
 		goto enomem;
 	}
 	port->read_urb->transfer_buffer = port->bulk_in_buffer;
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 5a4127e..90e3216 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -728,24 +728,32 @@
 #endif
 		}
 		
-		switch(cflag & CBAUD) {
-		case B0: /* handled below */
+		switch(tty_get_baud_rate(port->tty)) {
+		case 0: /* handled below */
 			break;
-		case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200;
+		case 1200:
+			priv->cfg.baudrate = kl5kusb105a_sio_b1200;
 			break;
-		case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400;
+		case 2400:
+			priv->cfg.baudrate = kl5kusb105a_sio_b2400;
 			break;
-		case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800;
+		case 4800:
+			priv->cfg.baudrate = kl5kusb105a_sio_b4800;
 			break;
-		case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+		case 9600:
+			priv->cfg.baudrate = kl5kusb105a_sio_b9600;
 			break;
-		case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200;
+		case 19200:
+			priv->cfg.baudrate = kl5kusb105a_sio_b19200;
 			break;
-		case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400;
+		case 38400:
+			priv->cfg.baudrate = kl5kusb105a_sio_b38400;
 			break;
-		case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600;
+		case 57600:
+			priv->cfg.baudrate = kl5kusb105a_sio_b57600;
 			break;
-		case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200;
+		case 115200:
+			priv->cfg.baudrate = kl5kusb105a_sio_b115200;
 			break;
 		default:
 			err("KLSI USB->Serial converter:"
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 02a86db..6f22419 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -82,6 +82,7 @@
 			   unsigned int set, unsigned int clear);
 static void kobil_read_int_callback( struct urb *urb );
 static void kobil_write_callback( struct urb *purb );
+static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old);
 
 
 static struct usb_device_id id_table [] = {
@@ -119,6 +120,7 @@
 	.attach =		kobil_startup,
 	.shutdown =		kobil_shutdown,
 	.ioctl =		kobil_ioctl,
+	.set_termios =		kobil_set_termios,
 	.tiocmget =		kobil_tiocmget,
 	.tiocmset =		kobil_tiocmset,
 	.open =			kobil_open,
@@ -137,7 +139,6 @@
 	int cur_pos; // index of the next char to send in buf
 	__u16 device_type;
 	int line_state;
-	struct ktermios internal_termios;
 };
 
 
@@ -216,7 +217,7 @@
 
 static int kobil_open (struct usb_serial_port *port, struct file *filp)
 {
-	int i, result = 0;
+	int result = 0;
 	struct kobil_private *priv;
 	unsigned char *transfer_buffer;
 	int transfer_buffer_length = 8;
@@ -242,16 +243,6 @@
 	port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
 	port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D)
 	
-	// set up internal termios structure 
-	priv->internal_termios.c_iflag = port->tty->termios->c_iflag;
-	priv->internal_termios.c_oflag = port->tty->termios->c_oflag;
-	priv->internal_termios.c_cflag = port->tty->termios->c_cflag;
-	priv->internal_termios.c_lflag = port->tty->termios->c_lflag;
-
-	for (i=0; i<NCCS; i++) {
-		priv->internal_termios.c_cc[i] = port->tty->termios->c_cc[i];
-	}
-	
 	// allocate memory for transfer buffer
 	transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
 	if (! transfer_buffer) {
@@ -607,102 +598,79 @@
 	return (result < 0) ? result : 0;
 }
 
-
-static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
-			unsigned int cmd, unsigned long arg)
+static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old)
 {
 	struct kobil_private * priv;
 	int result;
 	unsigned short urb_val = 0;
-	unsigned char *transfer_buffer;
-	int transfer_buffer_length = 8;
-	char *settings;
-	void __user *user_arg = (void __user *)arg;
+	int c_cflag = port->tty->termios->c_cflag;
+	speed_t speed;
+	void * settings;
 
 	priv = usb_get_serial_port_data(port);
-	if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) {
+	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
 		// This device doesn't support ioctl calls
-		return 0;
-	}
+		return;
 
-	switch (cmd) {
-	case TCGETS:   // 0x5401
-		if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) {
-			dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
-			return -EFAULT;
-		}
-		if (kernel_termios_to_user_termios((struct ktermios __user *)arg,
-						   &priv->internal_termios))
-			return -EFAULT;
-		return 0;
-
-	case TCSETS:   // 0x5402
-		if (!(port->tty->termios)) {
-			dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
-			return -ENOTTY;
-		}
-		if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) {
-			dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
-			return -EFAULT;
-		}
-		if (user_termios_to_kernel_termios(&priv->internal_termios,
-						   (struct ktermios __user *)arg))
-			return -EFAULT;
-		
-		settings = kzalloc(50, GFP_KERNEL);
-		if (! settings) {
-			return -ENOBUFS;
-		}
-
-		switch (priv->internal_termios.c_cflag & CBAUD) {
-		case B1200:
+	switch (speed = tty_get_baud_rate(port->tty)) {
+		case 1200:
 			urb_val = SUSBCR_SBR_1200;
-			strcat(settings, "1200 ");
 			break;
-		case B9600:
+		case 9600:
 		default:
 			urb_val = SUSBCR_SBR_9600;
-			strcat(settings, "9600 ");
 			break;
-		}
+	}
+	urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
 
-		urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
-		strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit ");
+	settings = kzalloc(50, GFP_KERNEL);
+	if (! settings)
+		return;
 
-		if (priv->internal_termios.c_cflag & PARENB) {
-			if  (priv->internal_termios.c_cflag & PARODD) {
-				urb_val |= SUSBCR_SPASB_OddParity;
-				strcat(settings, "Odd Parity");
-			} else {
-				urb_val |= SUSBCR_SPASB_EvenParity;
-				strcat(settings, "Even Parity");
-			}
+	sprintf(settings, "%d ", speed);
+
+	if (c_cflag & PARENB) {
+		if  (c_cflag & PARODD) {
+			urb_val |= SUSBCR_SPASB_OddParity;
+			strcat(settings, "Odd Parity");
 		} else {
-			urb_val |= SUSBCR_SPASB_NoParity;
-			strcat(settings, "No Parity");
+			urb_val |= SUSBCR_SPASB_EvenParity;
+			strcat(settings, "Even Parity");
 		}
-		dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings );
+	} else {
+		urb_val |= SUSBCR_SPASB_NoParity;
+		strcat(settings, "No Parity");
+	}
 
-		result = usb_control_msg( port->serial->dev, 
-					  usb_rcvctrlpipe(port->serial->dev, 0 ), 
-					  SUSBCRequest_SetBaudRateParityAndStopBits,
-					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
-					  urb_val,
-					  0,
-					  settings,
-					  0,
-					  KOBIL_TIMEOUT
-			);
+	result = usb_control_msg( port->serial->dev,
+				  usb_rcvctrlpipe(port->serial->dev, 0 ),
+				  SUSBCRequest_SetBaudRateParityAndStopBits,
+				  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+				  urb_val,
+				  0,
+				  settings,
+				  0,
+				  KOBIL_TIMEOUT
+		);
+	kfree(settings);
+}
 
-		dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
-		kfree(settings);
+static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+	struct kobil_private * priv = usb_get_serial_port_data(port);
+	unsigned char *transfer_buffer;
+	int transfer_buffer_length = 8;
+	int result;
+
+	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
+		// This device doesn't support ioctl calls
 		return 0;
 
+	switch (cmd) {
 	case TCFLSH:   // 0x540B
 		transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL);
-		if (! transfer_buffer) {
+		if (! transfer_buffer)
 		 	return -ENOBUFS;
-		}
 
 		result = usb_control_msg( port->serial->dev, 
 		 			  usb_rcvctrlpipe(port->serial->dev, 0 ), 
@@ -716,15 +684,13 @@
 			);
 		
 		dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result);
-
 		kfree(transfer_buffer);
-		return ((result < 0) ? -EFAULT : 0);
-
+		return (result < 0) ? -EFAULT : 0;
+	default:
+		return -ENOIOCTLCMD;
 	}
-	return -ENOIOCTLCMD;
 }
 
-
 static int __init kobil_init (void)
 {
 	int retval;
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 2a3fabc..0dc99f7 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -184,21 +184,21 @@
  * we do not know how to support. We ignore them for the moment.
  * XXX Rate-limit the error message, it's user triggerable.
  */
-static int mct_u232_calculate_baud_rate(struct usb_serial *serial, int value)
+static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value)
 {
 	if (le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_SITECOM_PID
 	  || le16_to_cpu(serial->dev->descriptor.idProduct) == MCT_U232_BELKIN_F5U109_PID) {
 		switch (value) {
-		case    B300: return 0x01;
-		case    B600: return 0x02; /* this one not tested */
-		case   B1200: return 0x03;
-		case   B2400: return 0x04;
-		case   B4800: return 0x06;
-		case   B9600: return 0x08;
-		case  B19200: return 0x09;
-		case  B38400: return 0x0a;
-		case  B57600: return 0x0b;
-		case B115200: return 0x0c;
+		case    300: return 0x01;
+		case    600: return 0x02; /* this one not tested */
+		case   1200: return 0x03;
+		case   2400: return 0x04;
+		case   4800: return 0x06;
+		case   9600: return 0x08;
+		case  19200: return 0x09;
+		case  38400: return 0x0a;
+		case  57600: return 0x0b;
+		case 115200: return 0x0c;
 		default:
 			err("MCT USB-RS232: unsupported baudrate request 0x%x,"
 			    " using default of B9600", value);
@@ -206,16 +206,16 @@
 		}
 	} else {
 		switch (value) {
-		case    B300: value =     300; break;
-		case    B600: value =     600; break;
-		case   B1200: value =    1200; break;
-		case   B2400: value =    2400; break;
-		case   B4800: value =    4800; break;
-		case   B9600: value =    9600; break;
-		case  B19200: value =   19200; break;
-		case  B38400: value =   38400; break;
-		case  B57600: value =   57600; break;
-		case B115200: value =  115200; break;
+		case 300: break;
+		case 600: break;
+		case 1200: break;
+		case 2400: break;
+		case 4800: break;
+		case 9600: break;
+		case 19200: break;
+		case 38400: break;
+		case 57600: break;
+		case 115200: break;
 		default:
 			err("MCT USB-RS232: unsupported baudrate request 0x%x,"
 			    " using default of B9600", value);
@@ -226,7 +226,7 @@
 }
 
 static int mct_u232_set_baud_rate(struct usb_serial *serial, struct usb_serial_port *port,
-				  int value)
+				  speed_t value)
 {
 	__le32 divisor;
         int rc;
@@ -634,7 +634,7 @@
 		mct_u232_set_modem_ctrl(serial, control_state);
 	}
 
-	mct_u232_set_baud_rate(serial, port, cflag & CBAUD);
+	mct_u232_set_baud_rate(serial, port, tty_get_baud_rate(port->tty));
 
 	if ((cflag & CBAUD) == B0 ) {
 		dbg("%s: baud is B0", __FUNCTION__);
diff --git a/drivers/usb/serial/mct_u232.h b/drivers/usb/serial/mct_u232.h
index a61bac8..aae10c8 100644
--- a/drivers/usb/serial/mct_u232.h
+++ b/drivers/usb/serial/mct_u232.h
@@ -79,7 +79,7 @@
  * and "Intel solution". They are the regular MCT and "Sitecom" for us.
  * This is pointless to document in the header, see the code for the bits.
  */
-static int mct_u232_calculate_baud_rate(struct usb_serial *serial, int value);
+static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value);
 
 /*
  * Line Control Register (LCR)
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 231b584..01e811b 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -110,11 +110,6 @@
 
 	dbg("%s"," : Entering\n");
 
-	if (!urb) {
-		dbg("%s","Invalid Pointer !!!!:\n");
-		return;
-	}
-
 	switch (status) {
 	case 0:
 		/* success */
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 37f41f5..f76480f 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -436,11 +436,6 @@
 	int result = 0;
 	int status = urb->status;
 
-	if (!urb) {
-		dbg("%s", "Invalid Pointer !!!!:\n");
-		return;
-	}
-
 	mos7840_port = (struct moschip_port *)urb->context;
 
 	switch (status) {
@@ -525,10 +520,6 @@
 	int status = urb->status;
 
 	dbg("%s", " : Entering\n");
-	if (!urb) {
-		dbg("%s", "Invalid Pointer !!!!:\n");
-		return;
-	}
 
 	switch (status) {
 	case 0:
@@ -676,11 +667,6 @@
 	struct tty_struct *tty;
 	int status = urb->status;
 
-	if (!urb) {
-		dbg("%s", "Invalid Pointer !!!!:\n");
-		return;
-	}
-
 	if (status) {
 		dbg("nonzero read bulk status received: %d", status);
 		return;
@@ -753,11 +739,6 @@
 	int status = urb->status;
 	int i;
 
-	if (!urb) {
-		dbg("%s", "Invalid Pointer !!!!:\n");
-		return;
-	}
-
 	mos7840_port = (struct moschip_port *)urb->context;
 	spin_lock(&mos7840_port->pool_lock);
 	for (i = 0; i < NUM_URBS; i++) {
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 84c12b5..a18659e 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -108,8 +108,10 @@
 #define HUAWEI_VENDOR_ID			0x12D1
 #define HUAWEI_PRODUCT_E600			0x1001
 #define HUAWEI_PRODUCT_E220			0x1003
+#define HUAWEI_PRODUCT_E220BIS			0x1004
 
 #define NOVATELWIRELESS_VENDOR_ID		0x1410
+#define DELL_VENDOR_ID				0x413C
 
 #define ANYDATA_VENDOR_ID			0x16d5
 #define ANYDATA_PRODUCT_ADU_E100A		0x6501
@@ -119,8 +121,6 @@
 #define BANDRICH_PRODUCT_C100_1			0x1002
 #define BANDRICH_PRODUCT_C100_2			0x1003
 
-#define DELL_VENDOR_ID				0x413C
-
 static struct usb_device_id option_ids[] = {
 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -159,6 +159,7 @@
 	{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_ETNA_KOI_NETWORK) },
 	{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
 	{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220) },
+	{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS) },
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1100) }, /* Novatel Merlin XS620/S640 */
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1110) }, /* Novatel Merlin S620 */
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x1120) }, /* Novatel Merlin EX720 */
@@ -171,11 +172,17 @@
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2110) }, /* Novatel Merlin ES620 / Merlin ES720 / Ovation U720 */
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2130) }, /* Novatel Merlin ES620 SM Bus */
 	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, 0x2410) }, /* Novatel EU740 */
+	{ USB_DEVICE(DELL_VENDOR_ID, 0x8114) },	/* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite EV620 CDMA/EV-DO */
+	{ USB_DEVICE(DELL_VENDOR_ID, 0x8115) },	/* Dell Wireless 5500 Mobile Broadband HSDPA Mini-Card == Novatel Expedite EU740 HSDPA/3G */
+	{ USB_DEVICE(DELL_VENDOR_ID, 0x8116) },	/* Dell Wireless 5505 Mobile Broadband HSDPA Mini-Card == Novatel Expedite EU740 HSDPA/3G */
+	{ USB_DEVICE(DELL_VENDOR_ID, 0x8117) },	/* Dell Wireless 5700 Mobile Broadband CDMA/EVDO ExpressCard == Novatel Merlin XV620 CDMA/EV-DO */
+	{ USB_DEVICE(DELL_VENDOR_ID, 0x8118) },	/* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard == Novatel Merlin XU870 HSDPA/3G */
+	{ USB_DEVICE(DELL_VENDOR_ID, 0x8128) },	/* Dell Wireless 5700 Mobile Broadband CDMA/EVDO Mini-Card == Novatel Expedite E720 CDMA/EV-DO */
+	{ USB_DEVICE(DELL_VENDOR_ID, 0x8137) },	/* Dell Wireless HSDPA 5520 */
 	{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) },
 	{ USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
 	{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_1) },
 	{ USB_DEVICE(BANDRICH_VENDOR_ID, BANDRICH_PRODUCT_C100_2) },
-	{ USB_DEVICE(DELL_VENDOR_ID, 0x8118) },		/* Dell Wireless 5510 Mobile Broadband HSDPA ExpressCard */
 	{ } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index d7db71e..d198611 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -817,23 +817,6 @@
 				__FUNCTION__, port->number, cmd, arg);
 
 	switch (cmd) {
-		case TCGETS:
-			if (copy_to_user(user_arg, port->tty->termios,
-						sizeof(struct ktermios))) {
-				return -EFAULT;
-			}
-			return 0;
-
-		case TCSETS:
-		case TCSETSW:	/* FIXME: this is not the same! */
-		case TCSETSF:	/* FIXME: this is not the same! */
-			if (copy_from_user(port->tty->termios, user_arg,
-						sizeof(struct ktermios))) {
-				return -EFAULT;
-			}
-			oti6858_set_termios(port, NULL);
-			return 0;
-
 		case TCFLSH:
 			/* FIXME */
 			return 0;
@@ -1161,7 +1144,7 @@
 	if (size == 0)
 		return NULL;
 
-	pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
+	pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
 	if (pb == NULL)
 		return NULL;
 
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index f9f85f5..1da57fd 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -73,6 +73,7 @@
 	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
 	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
 	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
+	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
 	{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
 	{ USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
 	{ USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index f9a71d0..c39bace 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -59,6 +59,7 @@
 #define SIEMENS_PRODUCT_ID_SX1	0x0001
 #define SIEMENS_PRODUCT_ID_X65	0x0003
 #define SIEMENS_PRODUCT_ID_X75	0x0004
+#define SIEMENS_PRODUCT_ID_EF81	0x0005
 
 #define SYNTECH_VENDOR_ID	0x0745
 #define SYNTECH_PRODUCT_ID	0x0001
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 86899d5..4e6dcc19 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -74,13 +74,13 @@
 #include <linux/usb/serial.h>
 
 
-#ifndef CONFIG_USB_SAFE_PADDED
-#define CONFIG_USB_SAFE_PADDED 0
+#ifndef CONFIG_USB_SERIAL_SAFE_PADDED
+#define CONFIG_USB_SERIAL_SAFE_PADDED 0
 #endif
 
 static int debug;
 static int safe = 1;
-static int padded = CONFIG_USB_SAFE_PADDED;
+static int padded = CONFIG_USB_SERIAL_SAFE_PADDED;
 
 #define DRIVER_VERSION "v0.0b"
 #define DRIVER_AUTHOR "sl@lineo.com, tbr@lineo.com"
@@ -90,18 +90,12 @@
 MODULE_DESCRIPTION (DRIVER_DESC);
 MODULE_LICENSE("GPL");
 
-#if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT)
-#error "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT"
-#endif
-
-#if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR)
 static __u16 vendor;		// no default
 static __u16 product;		// no default
 module_param(vendor, ushort, 0);
 MODULE_PARM_DESC(vendor, "User specified USB idVendor (required)");
 module_param(product, ushort, 0);
 MODULE_PARM_DESC(product, "User specified USB idProduct (required)");
-#endif
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
@@ -145,11 +139,6 @@
 	{MY_USB_DEVICE (0x4dd, 0x8003, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	// Collie 
 	{MY_USB_DEVICE (0x4dd, 0x8004, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	// Collie 
 	{MY_USB_DEVICE (0x5f9, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	// Sharp tmp
-#if defined(CONFIG_USB_SAFE_SERIAL_VENDOR)
-	{MY_USB_DEVICE
-	 (CONFIG_USB_SAFE_SERIAL_VENDOR, CONFIG_USB_SAFE_SERIAL_PRODUCT, CDC_DEVICE_CLASS,
-	  LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
-#endif
 	// extra null entry for module 
 	// vendor/produc parameters
 	{MY_USB_DEVICE (0, 0, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index e7db203..0bb8de4 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -1,7 +1,7 @@
 /*
   USB Driver for Sierra Wireless
 
-  Copyright (C) 2006  Kevin Lloyd <linux@sierrawireless.com>
+  Copyright (C) 2006, 2007  Kevin Lloyd <linux@sierrawireless.com>
 
   IMPORTANT DISCLAIMER: This driver is not commercially supported by
   Sierra Wireless. Use at your own risk.
@@ -12,10 +12,9 @@
 
   Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
   Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
-
 */
 
-#define DRIVER_VERSION "v.1.0.6"
+#define DRIVER_VERSION "v.1.2.5b"
 #define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
 #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
 
@@ -28,23 +27,99 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
+#define SWIMS_USB_REQUEST_SetMode	0x0B
+#define SWIMS_USB_REQUEST_TYPE_SetMode	0x40
+#define SWIMS_USB_INDEX_SetMode		0x0000
+#define SWIMS_SET_MODE_Modem		0x0001
+
+/* per port private data */
+#define N_IN_URB	4
+#define N_OUT_URB	4
+#define IN_BUFLEN	4096
+
+static int debug;
+
+enum devicetype {
+	DEVICE_3_PORT =		0,
+	DEVICE_1_PORT =		1,
+	DEVICE_INSTALLER =	2,
+};
+
+static int sierra_set_power_state(struct usb_device *udev, __u16 swiState)
+{
+	int result;
+	dev_dbg(&udev->dev, "%s", "SET POWER STATE");
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			0x00,			/* __u8 request      */
+			0x40,			/* __u8 request type */
+			swiState,		/* __u16 value       */
+			0,			/* __u16 index       */
+			NULL,			/* void *data        */
+			0,			/* __u16 size 	     */
+			USB_CTRL_SET_TIMEOUT);	/* int timeout 	     */
+	return result;
+}
+
+static int sierra_set_ms_mode(struct usb_device *udev, __u16 eSocMode)
+{
+	int result;
+	dev_dbg(&udev->dev, "%s", "DEVICE MODE SWITCH");
+	result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+			SWIMS_USB_REQUEST_SetMode,	/* __u8 request      */
+			SWIMS_USB_REQUEST_TYPE_SetMode,	/* __u8 request type */
+			eSocMode,			/* __u16 value       */
+			SWIMS_USB_INDEX_SetMode,	/* __u16 index       */
+			NULL,				/* void *data        */
+			0,				/* __u16 size 	     */
+			USB_CTRL_SET_TIMEOUT);		/* int timeout       */
+	return result;
+}
+
+static int sierra_probe(struct usb_interface *iface,
+			const struct usb_device_id *id)
+{
+	int result;
+	struct usb_device *udev;
+
+	udev = usb_get_dev(interface_to_usbdev(iface));
+
+	/* Check if in installer mode */
+	if (id->driver_info == DEVICE_INSTALLER) {
+		dev_dbg(&udev->dev, "%s", "FOUND DEVICE(SW)\n");
+		result = sierra_set_ms_mode(udev, SWIMS_SET_MODE_Modem);
+		/*We do not want to bind to the device when in installer mode*/
+		return -EIO;
+	}
+
+	return usb_serial_probe(iface, id);
+}
 
 static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(0x1199, 0x0017) },	/* Sierra Wireless EM5625 */
 	{ USB_DEVICE(0x1199, 0x0018) },	/* Sierra Wireless MC5720 */
 	{ USB_DEVICE(0x1199, 0x0218) },	/* Sierra Wireless MC5720 */
+	{ USB_DEVICE(0x0f30, 0x1b1d) },	/* Sierra Wireless MC5720 */
 	{ USB_DEVICE(0x1199, 0x0020) },	/* Sierra Wireless MC5725 */
 	{ USB_DEVICE(0x1199, 0x0019) },	/* Sierra Wireless AirCard 595 */
-	{ USB_DEVICE(0x1199, 0x0120) },	/* Sierra Wireless AirCard 595U */
 	{ USB_DEVICE(0x1199, 0x0021) },	/* Sierra Wireless AirCard 597E */
+	{ USB_DEVICE(0x1199, 0x0120) },	/* Sierra Wireless USB Dongle 595U */
+
 	{ USB_DEVICE(0x1199, 0x6802) },	/* Sierra Wireless MC8755 */
 	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 */
 	{ USB_DEVICE(0x1199, 0x6803) },	/* Sierra Wireless MC8765 */
-	{ USB_DEVICE(0x1199, 0x6812) },	/* Sierra Wireless MC8775 */
+	{ USB_DEVICE(0x1199, 0x6812) },	/* Sierra Wireless MC8775 & AC 875U */
 	{ USB_DEVICE(0x1199, 0x6820) },	/* Sierra Wireless AirCard 875 */
+	{ USB_DEVICE(0x1199, 0x6832) },	/* Sierra Wireless MC8780*/
+	{ USB_DEVICE(0x1199, 0x6833) },	/* Sierra Wireless MC8781*/
+	{ USB_DEVICE(0x1199, 0x6850) },	/* Sierra Wireless AirCard 880 */
+	{ USB_DEVICE(0x1199, 0x6851) },	/* Sierra Wireless AirCard 881 */
+	{ USB_DEVICE(0x1199, 0x6852) },	/* Sierra Wireless AirCard 880 E */
+	{ USB_DEVICE(0x1199, 0x6853) },	/* Sierra Wireless AirCard 881 E */
 
-	{ USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
-	{ USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
+	{ USB_DEVICE(0x1199, 0x0112), .driver_info = DEVICE_1_PORT }, /* Sierra Wireless AirCard 580 */
+	{ USB_DEVICE(0x0F3D, 0x0112), .driver_info = DEVICE_1_PORT }, /* Airprime/Sierra PC 5220 */
+
+	{ USB_DEVICE(0x1199, 0x0FFF), .driver_info = DEVICE_INSTALLER},
 	{ }
 };
 MODULE_DEVICE_TABLE(usb, id_table);
@@ -58,35 +133,36 @@
 static struct usb_device_id id_table_3port [] = {
 	{ USB_DEVICE(0x1199, 0x0017) },	/* Sierra Wireless EM5625 */
 	{ USB_DEVICE(0x1199, 0x0018) },	/* Sierra Wireless MC5720 */
+	{ USB_DEVICE(0x0f30, 0x1b1d) },	/* Sierra Wireless MC5720 */
 	{ USB_DEVICE(0x1199, 0x0218) },	/* Sierra Wireless MC5720 */
 	{ USB_DEVICE(0x1199, 0x0020) },	/* Sierra Wireless MC5725 */
 	{ USB_DEVICE(0x1199, 0x0019) },	/* Sierra Wireless AirCard 595 */
-	{ USB_DEVICE(0x1199, 0x0120) },	/* Sierra Wireless AirCard 595U */
 	{ USB_DEVICE(0x1199, 0x0021) },	/* Sierra Wireless AirCard 597E */
+	{ USB_DEVICE(0x1199, 0x0120) },	/* Sierra Wireless USB Dongle 595U*/
+
 	{ USB_DEVICE(0x1199, 0x6802) },	/* Sierra Wireless MC8755 */
 	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 */
 	{ USB_DEVICE(0x1199, 0x6803) },	/* Sierra Wireless MC8765 */
-	{ USB_DEVICE(0x1199, 0x6812) },	/* Sierra Wireless MC8775 */
+	{ USB_DEVICE(0x1199, 0x6812) },	/* Sierra Wireless MC8775 & AC 875U */
 	{ USB_DEVICE(0x1199, 0x6820) },	/* Sierra Wireless AirCard 875 */
+	{ USB_DEVICE(0x1199, 0x6832) },	/* Sierra Wireless MC8780*/
+	{ USB_DEVICE(0x1199, 0x6833) },	/* Sierra Wireless MC8781*/
+	{ USB_DEVICE(0x1199, 0x6850) },	/* Sierra Wireless AirCard 880 */
+	{ USB_DEVICE(0x1199, 0x6851) },	/* Sierra Wireless AirCard 881 */
+	{ USB_DEVICE(0x1199, 0x6852) },	/* Sierra Wireless AirCard 880E */
+	{ USB_DEVICE(0x1199, 0x6853) },	/* Sierra Wireless AirCard 881E */
 	{ }
 };
 
 static struct usb_driver sierra_driver = {
 	.name       = "sierra",
-	.probe      = usb_serial_probe,
+	.probe      = sierra_probe,
 	.disconnect = usb_serial_disconnect,
 	.id_table   = id_table,
 	.no_dynamic_id = 	1,
 };
 
 
-static int debug;
-
-/* per port private data */
-#define N_IN_URB	4
-#define N_OUT_URB	4
-#define IN_BUFLEN	4096
-
 struct sierra_port_private {
 	spinlock_t lock;	/* lock the structure */
 	int outstanding_urbs;	/* number of out urbs in flight */
@@ -421,7 +497,6 @@
 	int i;
 	struct urb *urb;
 	int result;
-	__u16 set_mode_dzero = 0x0000;
 
 	portdata = usb_get_serial_port_data(port);
 
@@ -457,12 +532,6 @@
 
 	port->tty->low_latency = 1;
 
-	/* set mode to D0 */
-	result = usb_control_msg(serial->dev,
-				 usb_rcvctrlpipe(serial->dev, 0),
-				 0x00, 0x40, set_mode_dzero, 0, NULL,
-				 0, USB_CTRL_SET_TIMEOUT);
-
 	sierra_send_setup(port);
 
 	/* start up the interrupt endpoint if we have one */
@@ -510,6 +579,9 @@
 
 	dbg("%s", __FUNCTION__);
 
+	/*Set Device mode to D0 */
+	sierra_set_power_state(serial->dev, 0x0000);
+
 	/* Now setup per port private data */
 	for (i = 0; i < serial->num_ports; i++) {
 		port = serial->port[i];
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index a366565..4b1bd7d 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -60,19 +60,19 @@
 
 static int debug;
 static struct usb_serial *serial_table[SERIAL_TTY_MINORS];	/* initially all NULL */
-static spinlock_t table_lock;
+static DEFINE_MUTEX(table_lock);
 static LIST_HEAD(usb_serial_driver_list);
 
 struct usb_serial *usb_serial_get_by_index(unsigned index)
 {
 	struct usb_serial *serial;
 
-	spin_lock(&table_lock);
+	mutex_lock(&table_lock);
 	serial = serial_table[index];
 
 	if (serial)
 		kref_get(&serial->kref);
-	spin_unlock(&table_lock);
+	mutex_unlock(&table_lock);
 	return serial;
 }
 
@@ -84,7 +84,7 @@
 	dbg("%s %d", __FUNCTION__, num_ports);
 
 	*minor = 0;
-	spin_lock(&table_lock);
+	mutex_lock(&table_lock);
 	for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
 		if (serial_table[i])
 			continue;
@@ -106,10 +106,10 @@
 			serial_table[i] = serial;
 			serial->port[j++]->number = i;
 		}
-		spin_unlock(&table_lock);
+		mutex_unlock(&table_lock);
 		return serial;
 	}
-	spin_unlock(&table_lock);
+	mutex_unlock(&table_lock);
 	return NULL;
 }
 
@@ -172,9 +172,9 @@
 
 void usb_serial_put(struct usb_serial *serial)
 {
-	spin_lock(&table_lock);
+	mutex_lock(&table_lock);
 	kref_put(&serial->kref, destroy_serial);
-	spin_unlock(&table_lock);
+	mutex_unlock(&table_lock);
 }
 
 /*****************************************************************************
@@ -578,6 +578,17 @@
 {
 	usb_kill_urb(port->read_urb);
 	usb_kill_urb(port->write_urb);
+	/*
+	 * This is tricky.
+	 * Some drivers submit the read_urb in the
+	 * handler for the write_urb or vice versa
+	 * this order determines the order in which
+	 * usb_kill_urb() must be used to reliably
+	 * kill the URBs. As it is unknown here,
+	 * both orders must be used in turn.
+	 * The call below is not redundant.
+	 */
+	usb_kill_urb(port->read_urb);
 	usb_kill_urb(port->interrupt_in_urb);
 	usb_kill_urb(port->interrupt_out_urb);
 }
@@ -651,16 +662,14 @@
 
 static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
 {
-	struct list_head *p;
 	const struct usb_device_id *id;
-	struct usb_serial_driver *t;
+	struct usb_serial_driver *drv;
 
 	/* Check if the usb id matches a known device */
-	list_for_each(p, &usb_serial_driver_list) {
-		t = list_entry(p, struct usb_serial_driver, driver_list);
-		id = get_iface_id(t, iface);
+	list_for_each_entry(drv, &usb_serial_driver_list, driver_list) {
+		id = get_iface_id(drv, iface);
 		if (id)
-			return t;
+			return drv;
 	}
 
 	return NULL;
@@ -800,9 +809,6 @@
 	/* END HORRIBLE HACK FOR PL2303 */
 #endif
 
-	/* found all that we need */
-	dev_info(&interface->dev, "%s converter detected\n", type->description);
-
 #ifdef CONFIG_USB_SERIAL_GENERIC
 	if (type == &usb_serial_generic_device) {
 		num_ports = num_bulk_out;
@@ -836,6 +842,24 @@
 	serial->num_interrupt_in = num_interrupt_in;
 	serial->num_interrupt_out = num_interrupt_out;
 
+	/* check that the device meets the driver's requirements */
+	if ((type->num_interrupt_in != NUM_DONT_CARE &&
+				type->num_interrupt_in != num_interrupt_in)
+			|| (type->num_interrupt_out != NUM_DONT_CARE &&
+				type->num_interrupt_out != num_interrupt_out)
+			|| (type->num_bulk_in != NUM_DONT_CARE &&
+				type->num_bulk_in != num_bulk_in)
+			|| (type->num_bulk_out != NUM_DONT_CARE &&
+				type->num_bulk_out != num_bulk_out)) {
+		dbg("wrong number of endpoints");
+		kfree(serial);
+		return -EIO;
+	}
+
+	/* found all that we need */
+	dev_info(&interface->dev, "%s converter detected\n",
+			type->description);
+
 	/* create our ports, we need as many as the max endpoints */
 	/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
 	max_endpoints = max(num_bulk_in, num_bulk_out);
@@ -1077,16 +1101,17 @@
 	struct usb_serial_port *port;
 	int i, r = 0;
 
-	if (serial) {
-		for (i = 0; i < serial->num_ports; ++i) {
-			port = serial->port[i];
-			if (port)
-				kill_traffic(port);
-		}
+	if (!serial) /* device has been disconnected */
+		return 0;
+
+	for (i = 0; i < serial->num_ports; ++i) {
+		port = serial->port[i];
+		if (port)
+			kill_traffic(port);
 	}
 
 	if (serial->type->suspend)
-		serial->type->suspend(serial, message);
+		r = serial->type->suspend(serial, message);
 
 	return r;
 }
@@ -1128,7 +1153,6 @@
 		return -ENOMEM;
 
 	/* Initialize our global data */
-	spin_lock_init(&table_lock);
 	for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
 		serial_table[i] = NULL;
 	}
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 7d84a76..7ee087f 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -46,7 +46,6 @@
 static int  visor_calc_num_ports(struct usb_serial *serial);
 static void visor_shutdown	(struct usb_serial *serial);
 static int  visor_ioctl		(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-static void visor_set_termios	(struct usb_serial_port *port, struct ktermios *old_termios);
 static void visor_write_bulk_callback	(struct urb *urb);
 static void visor_read_bulk_callback	(struct urb *urb);
 static void visor_read_int_callback	(struct urb *urb);
@@ -104,6 +103,8 @@
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_TJ25_ID),
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
+	{ USB_DEVICE(ACER_VENDOR_ID, ACER_S10_ID),
+		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SCH_I330_ID), 
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID), 
@@ -201,7 +202,6 @@
 	.calc_num_ports =	visor_calc_num_ports,
 	.shutdown =		visor_shutdown,
 	.ioctl =		visor_ioctl,
-	.set_termios =		visor_set_termios,
 	.write =		visor_write,
 	.write_room =		visor_write_room,
 	.chars_in_buffer =	visor_chars_in_buffer,
@@ -232,7 +232,6 @@
 	.calc_num_ports =	visor_calc_num_ports,
 	.shutdown =		visor_shutdown,
 	.ioctl =		visor_ioctl,
-	.set_termios =		visor_set_termios,
 	.write =		visor_write,
 	.write_room =		visor_write_room,
 	.chars_in_buffer =	visor_chars_in_buffer,
@@ -260,7 +259,6 @@
 	.unthrottle =		visor_unthrottle,
 	.attach =		clie_3_5_startup,
 	.ioctl =		visor_ioctl,
-	.set_termios =		visor_set_termios,
 	.write =		visor_write,
 	.write_room =		visor_write_room,
 	.chars_in_buffer =	visor_chars_in_buffer,
@@ -934,66 +932,6 @@
 	return -ENOIOCTLCMD;
 }
 
-
-/* This function is all nice and good, but we don't change anything based on it :) */
-static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios)
-{
-	unsigned int cflag;
-
-	dbg("%s - port %d", __FUNCTION__, port->number);
-
-	if ((!port->tty) || (!port->tty->termios)) {
-		dbg("%s - no tty structures", __FUNCTION__);
-		return;
-	}
-
-	cflag = port->tty->termios->c_cflag;
-
-	/* get the byte size */
-	switch (cflag & CSIZE) {
-		case CS5:	dbg("%s - data bits = 5", __FUNCTION__);   break;
-		case CS6:	dbg("%s - data bits = 6", __FUNCTION__);   break;
-		case CS7:	dbg("%s - data bits = 7", __FUNCTION__);   break;
-		default:
-		case CS8:	dbg("%s - data bits = 8", __FUNCTION__);   break;
-	}
-	
-	/* determine the parity */
-	if (cflag & PARENB)
-		if (cflag & PARODD)
-			dbg("%s - parity = odd", __FUNCTION__);
-		else
-			dbg("%s - parity = even", __FUNCTION__);
-	else
-		dbg("%s - parity = none", __FUNCTION__);
-
-	/* figure out the stop bits requested */
-	if (cflag & CSTOPB)
-		dbg("%s - stop bits = 2", __FUNCTION__);
-	else
-		dbg("%s - stop bits = 1", __FUNCTION__);
-
-	
-	/* figure out the flow control settings */
-	if (cflag & CRTSCTS)
-		dbg("%s - RTS/CTS is enabled", __FUNCTION__);
-	else
-		dbg("%s - RTS/CTS is disabled", __FUNCTION__);
-	
-	/* determine software flow control */
-	if (I_IXOFF(port->tty))
-		dbg("%s - XON/XOFF is enabled, XON = %2x, XOFF = %2x",
-		    __FUNCTION__, START_CHAR(port->tty), STOP_CHAR(port->tty));
-	else
-		dbg("%s - XON/XOFF is disabled", __FUNCTION__);
-
-	/* get the baud rate wanted */
-	dbg("%s - baud rate = %d", __FUNCTION__, tty_get_baud_rate(port->tty));
-
-	return;
-}
-
-
 static int __init visor_init (void)
 {
 	int i, retval;
diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
index 4ce6f62..57229cf 100644
--- a/drivers/usb/serial/visor.h
+++ b/drivers/usb/serial/visor.h
@@ -48,6 +48,9 @@
 #define SONY_CLIE_UX50_ID		0x0144
 #define SONY_CLIE_TJ25_ID		0x0169
 
+#define ACER_VENDOR_ID			0x0502
+#define ACER_S10_ID			0x0001
+
 #define SAMSUNG_VENDOR_ID		0x04E8
 #define SAMSUNG_SCH_I330_ID		0x8001
 #define SAMSUNG_SPH_I500_ID		0x6601
diff --git a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c
index 1628cb2..9a410b5 100644
--- a/drivers/usb/storage/dpcm.c
+++ b/drivers/usb/storage/dpcm.c
@@ -46,43 +46,43 @@
  */
 int dpcm_transport(struct scsi_cmnd *srb, struct us_data *us)
 {
-  int ret;
+	int ret;
 
-  if(srb == NULL)
-    return USB_STOR_TRANSPORT_ERROR;
+	if (srb == NULL)
+		return USB_STOR_TRANSPORT_ERROR;
 
-  US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
+	US_DEBUGP("dpcm_transport: LUN=%d\n", srb->device->lun);
 
-  switch(srb->device->lun) {
-  case 0:
+	switch (srb->device->lun) {
+		case 0:
 
-    /*
-     * LUN 0 corresponds to the CompactFlash card reader.
-     */
-    ret = usb_stor_CB_transport(srb, us);
-    break;
+			/*
+			 * LUN 0 corresponds to the CompactFlash card reader.
+			 */
+			ret = usb_stor_CB_transport(srb, us);
+			break;
 
 #ifdef CONFIG_USB_STORAGE_SDDR09
-  case 1:
+		case 1:
 
-    /*
-     * LUN 1 corresponds to the SmartMedia card reader.
-     */
+			/*
+			 * LUN 1 corresponds to the SmartMedia card reader.
+			 */
 
-    /*
-     * Set the LUN to 0 (just in case).
-     */
-    srb->device->lun = 0; us->srb->device->lun = 0;
-    ret = sddr09_transport(srb, us);
-    srb->device->lun = 1; us->srb->device->lun = 1;
-    break;
+			/*
+			 * Set the LUN to 0 (just in case).
+			 */
+			srb->device->lun = 0; us->srb->device->lun = 0;
+			ret = sddr09_transport(srb, us);
+			srb->device->lun = 1; us->srb->device->lun = 1;
+			break;
 
 #endif
 
-  default:
-    US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
-    ret = USB_STOR_TRANSPORT_ERROR;
-    break;
-  }
-  return ret;
+		default:
+			US_DEBUGP("dpcm_transport: Invalid LUN %d\n", srb->device->lun);
+			ret = USB_STOR_TRANSPORT_ERROR;
+			break;
+	}
+	return ret;
 }
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
index 3a41740..ee5b42a 100644
--- a/drivers/usb/storage/initializers.c
+++ b/drivers/usb/storage/initializers.c
@@ -90,3 +90,17 @@
 
 	return (res ? -1 : 0);
 }
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us)
+{
+	int result;
+
+	us->iobuf[0] = 0x1;
+	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
+				      USB_REQ_SET_FEATURE,
+				      USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+				      0x01, 0x0, us->iobuf, 0x1, 1000);
+	US_DEBUGP("usb_control_msg performing result is %d\n", result);
+	return (result ? 0 : -1);
+}
diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h
index e2967a4..ad3ffd4 100644
--- a/drivers/usb/storage/initializers.h
+++ b/drivers/usb/storage/initializers.h
@@ -47,3 +47,6 @@
 /* This function is required to activate all four slots on the UCR-61S2B
  * flash reader */
 int usb_stor_ucr61s2b_init(struct us_data *us);
+
+/* This places the HUAWEI E220 devices in multi-port mode */
+int usb_stor_huawei_e220_init(struct us_data *us);
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index d353693..dfd42fe 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -57,9 +57,10 @@
 	struct usb_onetouch *onetouch = urb->context;
 	signed char *data = onetouch->data;
 	struct input_dev *dev = onetouch->dev;
-	int status;
+	int status = urb->status;
+	int retval;
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:			/* success */
 		break;
 	case -ECONNRESET:	/* unlink */
@@ -75,11 +76,11 @@
 	input_sync(dev);
 
 resubmit:
-	status = usb_submit_urb (urb, GFP_ATOMIC);
-	if (status)
-		err ("can't resubmit intr, %s-%s/input0, status %d",
+	retval = usb_submit_urb (urb, GFP_ATOMIC);
+	if (retval)
+		err ("can't resubmit intr, %s-%s/input0, retval %d",
 			onetouch->udev->bus->bus_name,
-			onetouch->udev->devpath, status);
+			onetouch->udev->devpath, retval);
 }
 
 static int usb_onetouch_open(struct input_dev *dev)
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 47e5607..1ba19ea 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -285,15 +285,10 @@
 
 	US_DEBUGP("%s called\n", __FUNCTION__);
 
-	result = usb_autopm_get_interface(us->pusb_intf);
-	if (result == 0) {
-
-		/* lock the device pointers and do the reset */
-		mutex_lock(&(us->dev_mutex));
-		result = us->transport_reset(us);
-		mutex_unlock(&us->dev_mutex);
-		usb_autopm_put_interface(us->pusb_intf);
-	}
+	/* lock the device pointers and do the reset */
+	mutex_lock(&(us->dev_mutex));
+	result = us->transport_reset(us);
+	mutex_unlock(&us->dev_mutex);
 
 	return result < 0 ? FAILED : SUCCESS;
 }
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index 5e27297..17ca4d7 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -190,9 +190,6 @@
 	unsigned char *reply = us->iobuf;
 	int rc;
 
-	if (!us)
-		return USB_STOR_TRANSPORT_ERROR;
-
 	rc = usbat_get_status(us, reply);
 	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_FAILED;
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index b6bf31a..9b656ec 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -198,7 +198,7 @@
 		US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
 
 /* Reported by Bardur Arantsson <bardur@scientician.net> */
-UNUSUAL_DEV(  0x0421, 0x047c, 0x0370, 0x0370,
+UNUSUAL_DEV(  0x0421, 0x047c, 0x0370, 0x0610,
 		"Nokia",
 		"6131",
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -313,6 +313,20 @@
 		US_SC_DEVICE, US_PR_DEVICE,NULL,
 		US_FL_NOT_LOCKABLE ),
 
+/* Reported by Stefan de Konink <skinkie@xs4all.nl> */
+UNUSUAL_DEV(  0x04b0, 0x0401, 0x0200, 0x0200,
+		"NIKON",
+		"NIKON DSC D100",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY),
+
+/* Reported by Milinevsky Dmitry <niam.niam@gmail.com> */
+UNUSUAL_DEV(  0x04b0, 0x0409, 0x0100, 0x0100,
+		"NIKON",
+		"NIKON DSC D50",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY),
+
 /* Reported by Andreas Bockhold <andreas@bockionline.de> */
 UNUSUAL_DEV(  0x04b0, 0x0405, 0x0100, 0x0100,
 		"NIKON",
@@ -327,13 +341,41 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_CAPACITY),
 
+/* Reported by Graber and Mike Pagano <mpagano-kernel@mpagano.com> */
+UNUSUAL_DEV(  0x04b0, 0x040f, 0x0200, 0x0200,
+       "NIKON",
+       "NIKON DSC D200",
+       US_SC_DEVICE, US_PR_DEVICE, NULL,
+       US_FL_FIX_CAPACITY),
+
 /* Reported by Emil Larsson <emil@swip.net> */
-UNUSUAL_DEV(  0x04b0, 0x0411, 0x0100, 0x0100,
+UNUSUAL_DEV(  0x04b0, 0x0411, 0x0100, 0x0101,
 		"NIKON",
 		"NIKON DSC D80",
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_CAPACITY),
 
+/* Reported by Ortwin Glueck <odi@odi.ch> */
+UNUSUAL_DEV(  0x04b0, 0x0413, 0x0110, 0x0110,
+		"NIKON",
+		"NIKON DSC D40",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY),
+
+/* Reported by Paul Check <paul@openstreet.com> */
+UNUSUAL_DEV(  0x04b0, 0x0415, 0x0100, 0x0100,
+		"NIKON",
+		"NIKON DSC D2Xs",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY),
+
+/* Reported by Shan Destromp (shansan@gmail.com) */
+UNUSUAL_DEV(  0x04b0, 0x0417, 0x0100, 0x0100,
+		"NIKON",
+		"NIKON DSC D40X",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY),
+
 /* BENQ DC5330
  * Reported by Manuel Fombuena <mfombuena@ya.com> and
  * Frank Copeland <fjc@thingy.apana.org.au> */
@@ -883,6 +925,22 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_CAPACITY ),
 
+/* Reported by Massimiliano Ghilardi <massimiliano.ghilardi@gmail.com>
+ * This USB MP3/AVI player device fails and disconnects if more than 128
+ * sectors (64kB) are read/written in a single command, and may be present
+ * at least in the following products:
+ *   "Magnex Digital Video Panel DVP 1800"
+ *   "MP4 AIGO 4GB SLOT SD"
+ *   "Teclast TL-C260 MP3"
+ *   "i.Meizu PMP MP3/MP4"
+ *   "Speed MV8 MP4 Audio Player"
+ */
+UNUSUAL_DEV(  0x071b, 0x3203, 0x0100, 0x0100,
+		"RockChip",
+		"ROCK MP3",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_MAX_SECTORS_64),
+
 /* Reported by Olivier Blondeau <zeitoun@gmail.com> */
 UNUSUAL_DEV(  0x0727, 0x0306, 0x0100, 0x0100,
 		"ATMEL",
@@ -1350,6 +1408,20 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_IGNORE_RESIDUE ),
 
+/* Jeremy Katz <katzj@redhat.com>:
+ * The Blackberry Pearl can run in two modes; a usb-storage only mode
+ * and a mode that allows access via mass storage and to its database.
+ * The berry_charge module will set the device to dual mode and thus we
+ * should ignore its native mode if that module is built
+ */
+#ifdef CONFIG_USB_BERRY_CHARGE
+UNUSUAL_DEV(  0x0fca, 0x0006, 0x0001, 0x0001,
+		"RIM",
+		"Blackberry Pearl",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_DEVICE ),
+#endif
+
 /* Reported by Michael Stattmann <michael@stattmann.com> */
 UNUSUAL_DEV(  0x0fce, 0xd008, 0x0000, 0x0000,
 		"Sony Ericsson",
@@ -1365,6 +1437,13 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ),
 
+/* Reported by Ricardo Barberis <ricardo@dattatec.com> */
+UNUSUAL_DEV(  0x0fce, 0xe092, 0x0000, 0x0000,
+		"Sony Ericsson",
+		"P1i",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
 /* Reported by Emmanuel Vasilakis <evas@forthnet.gr> */
 UNUSUAL_DEV(  0x0fce, 0xe031, 0x0000, 0x0000,
 		"Sony Ericsson",
@@ -1384,6 +1463,17 @@
 		US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init,
 		0 ),
 
+/* Reported by Kevin Lloyd <linux@sierrawireless.com>
+ * Entry is needed for the initializer function override,
+ * which instructs the device to load as a modem
+ * device.
+ */
+UNUSUAL_DEV(  0x1199, 0x0fff, 0x0000, 0x9999,
+		"Sierra Wireless",
+		"USB MMC Storage",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_DEVICE),
+
 /* Reported by Jaco Kroon <jaco@kroon.co.za>
  * The usb-storage module found on the Digitech GNX4 (and supposedly other
  * devices) misbehaves and causes a bunch of invalid I/O errors.
@@ -1394,6 +1484,17 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_IGNORE_RESIDUE ),
 
+/* Reported by fangxiaozhi <fangxiaozhi60675@huawei.com>
+ * and by linlei <linlei83@huawei.com>
+ * Patch reworked by Johann Wilhelm <johann.wilhelm@student.tugraz.at>
+ * This brings the HUAWEI E220 devices into multi-port mode
+ */
+UNUSUAL_DEV( 0x12d1, 0x1003, 0x0000, 0x0000,
+		"HUAWEI MOBILE",
+		"Mass Storage",
+		US_SC_DEVICE, US_PR_DEVICE, usb_stor_huawei_e220_init,
+		0),
+
 /* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */
 UNUSUAL_DEV(  0x132b, 0x000b, 0x0001, 0x0001,
 		"Minolta",
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 28842d2..3451e8d0 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -112,13 +112,6 @@
 MODULE_PARM_DESC(delay_use, "seconds to delay before using a new device");
 
 
-/* These are used to make sure the module doesn't unload before all the
- * threads have exited.
- */
-static atomic_t total_threads = ATOMIC_INIT(0);
-static DECLARE_COMPLETION(threads_gone);
-
-
 /*
  * The entries in this table correspond, line for line,
  * with the entries of us_unusual_dev_list[].
@@ -191,14 +184,16 @@
 {
 	struct us_data *us = usb_get_intfdata(iface);
 
-	US_DEBUGP("%s\n", __FUNCTION__);
-
 	/* Wait until no command is running */
 	mutex_lock(&us->dev_mutex);
 
+	US_DEBUGP("%s\n", __FUNCTION__);
 	if (us->suspend_resume_hook)
 		(us->suspend_resume_hook)(us, US_SUSPEND);
 
+	/* When runtime PM is working, we'll set a flag to indicate
+	 * whether we should autoresume when a SCSI request arrives. */
+
 	mutex_unlock(&us->dev_mutex);
 	return 0;
 }
@@ -207,11 +202,13 @@
 {
 	struct us_data *us = usb_get_intfdata(iface);
 
-	US_DEBUGP("%s\n", __FUNCTION__);
+	mutex_lock(&us->dev_mutex);
 
+	US_DEBUGP("%s\n", __FUNCTION__);
 	if (us->suspend_resume_hook)
 		(us->suspend_resume_hook)(us, US_RESUME);
 
+	mutex_unlock(&us->dev_mutex);
 	return 0;
 }
 
@@ -309,7 +306,6 @@
 {
 	struct us_data *us = (struct us_data *)__us;
 	struct Scsi_Host *host = us_to_host(us);
-	int autopm_rc;
 
 	for(;;) {
 		US_DEBUGP("*** thread sleeping.\n");
@@ -318,9 +314,6 @@
 			
 		US_DEBUGP("*** thread awakened.\n");
 
-		/* Autoresume the device */
-		autopm_rc = usb_autopm_get_interface(us->pusb_intf);
-
 		/* lock the device pointers */
 		mutex_lock(&(us->dev_mutex));
 
@@ -379,12 +372,6 @@
 			us->srb->result = SAM_STAT_GOOD;
 		}
 
-		/* Did the autoresume fail? */
-		else if (autopm_rc < 0) {
-			US_DEBUGP("Could not wake device\n");
-			us->srb->result = DID_ERROR << 16;
-		}
-
 		/* we've got a command, let's do it! */
 		else {
 			US_DEBUG(usb_stor_show_command(us->srb));
@@ -427,10 +414,6 @@
 
 		/* unlock the device pointers */
 		mutex_unlock(&us->dev_mutex);
-
-		/* Start an autosuspend */
-		if (autopm_rc == 0)
-			usb_autopm_put_interface(us->pusb_intf);
 	} /* for (;;) */
 
 	/* Wait until we are told to stop */
@@ -879,9 +862,6 @@
 	usb_stor_stop_transport(us);
 	wake_up(&us->delay_wait);
 
-	/* It doesn't matter if the SCSI-scanning thread is still running.
-	 * The thread will exit when it sees the DISCONNECTING flag. */
-
 	/* queuecommand won't accept any new commands and the control
 	 * thread won't execute a previously-queued command.  If there
 	 * is such a command pending, complete it with an error. */
@@ -891,12 +871,16 @@
 		scsi_lock(host);
 		us->srb->scsi_done(us->srb);
 		us->srb = NULL;
+		complete(&us->notify);		/* in case of an abort */
 		scsi_unlock(host);
 	}
 	mutex_unlock(&us->dev_mutex);
 
 	/* Now we own no commands so it's safe to remove the SCSI host */
 	scsi_remove_host(host);
+
+	/* Wait for the SCSI-scanning thread to stop */
+	wait_for_completion(&us->scanning_done);
 }
 
 /* Second stage of disconnect processing: deallocate all resources */
@@ -947,9 +931,7 @@
 		/* Should we unbind if no devices were detected? */
 	}
 
-	scsi_host_put(us_to_host(us));
-	usb_autopm_put_interface(us->pusb_intf);
-	complete_and_exit(&threads_gone, 0);
+	complete_and_exit(&us->scanning_done, 0);
 }
 
 
@@ -978,12 +960,17 @@
 		return -ENOMEM;
 	}
 
+	/*
+	 * Allow 16-byte CDBs and thus > 2TB
+	 */
+	host->max_cmd_len = 16;
 	us = host_to_us(host);
 	memset(us, 0, sizeof(struct us_data));
 	mutex_init(&(us->dev_mutex));
 	init_MUTEX_LOCKED(&(us->sema));
 	init_completion(&(us->notify));
 	init_waitqueue_head(&us->delay_wait);
+	init_completion(&us->scanning_done);
 
 	/* Associate the us_data structure with the USB device */
 	result = associate_dev(us, intf);
@@ -1033,12 +1020,6 @@
 		goto BadDevice;
 	}
 
-	/* Take a reference to the host for the scanning thread and
-	 * count it among all the threads we have launched.  Then
-	 * start it up. */
-	scsi_host_get(us_to_host(us));
-	atomic_inc(&total_threads);
-	usb_autopm_get_interface(intf); /* dropped in the scanning thread */
 	wake_up_process(th);
 
 	return 0;
@@ -1076,7 +1057,6 @@
 	.pre_reset =	storage_pre_reset,
 	.post_reset =	storage_post_reset,
 	.id_table =	storage_usb_ids,
-	.supports_autosuspend = 1,
 };
 
 static int __init usb_stor_init(void)
@@ -1104,16 +1084,6 @@
 	US_DEBUGP("-- calling usb_deregister()\n");
 	usb_deregister(&usb_storage_driver) ;
 
-	/* Don't return until all of our control and scanning threads
-	 * have exited.  Since each thread signals threads_gone as its
-	 * last act, we have to call wait_for_completion the right number
-	 * of times.
-	 */
-	while (atomic_read(&total_threads) > 0) {
-		wait_for_completion(&threads_gone);
-		atomic_dec(&total_threads);
-	}
-
 	usb_usual_clear_present(USB_US_TYPE_STOR);
 }
 
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index 6445665..8d87503 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -150,6 +150,7 @@
 	struct semaphore	sema;		 /* to sleep thread on	    */
 	struct completion	notify;		 /* thread begin/end	    */
 	wait_queue_head_t	delay_wait;	 /* wait during scan, reset */
+	struct completion	scanning_done;	 /* wait for scan thread    */
 
 	/* subdriver information */
 	void			*extra;		 /* Any extra data          */
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 8de11de..c815a40 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -125,6 +125,7 @@
 
 	/* save our object in the file's private structure */
 	file->private_data = dev;
+	mutex_unlock(&dev->io_mutex);
 
 exit:
 	return retval;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 0c5644bb..5216c11 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -12,6 +12,13 @@
        tristate
        default n
 
+config VIDEO_OUTPUT_CONTROL
+	tristate "Lowlevel video output switch controls"
+	default m
+	help
+	  This framework adds support for low-level control of the video 
+	  output switch.
+
 config FB
 	tristate "Support for frame buffer devices"
 	---help---
@@ -849,6 +856,16 @@
 	  Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want
 	  to let frame buffer in external SDRAM.
 
+config FB_ATMEL_STN
+	bool "Use a STN display with AT91/AT32 LCD Controller"
+	depends on FB_ATMEL && MACH_AT91SAM9261EK
+	default n
+	help
+	  Say Y if you want to connect a STN LCD display to the AT91/AT32 LCD
+	  Controller. Say N if you want to connect a TFT.
+
+	  If unsure, say N.
+
 config FB_NVIDIA
 	tristate "nVidia Framebuffer Support"
 	depends on FB && PCI
@@ -1554,7 +1571,14 @@
 
 config FB_AU1100
 	bool "Au1100 LCD Driver"
-	depends on (FB = y) && EXPERIMENTAL && PCI && MIPS && MIPS_PB1100=y
+	depends on (FB = y) && MIPS && SOC_AU1100
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This is the framebuffer driver for the AMD Au1100 SOC.  It can drive
+	  various panels and CRTs by passing in kernel cmd line option
+	  au1100fb:panel=<name>.
 
 config FB_AU1200
 	bool "Au1200 LCD Driver"
@@ -1621,18 +1645,6 @@
 	  DECstation series (Personal DECstation 5000/20, /25, /33, /50,
 	  Codename "Maxine").
 
-config FB_TX3912
-	bool "TMPTX3912/PR31700 frame buffer support"
-	depends on (FB = y) && NINO
-	select FB_CFB_FILLRECT
-	select FB_CFB_COPYAREA
-	select FB_CFB_IMAGEBLIT
-	help
-	  The TX3912 is a Toshiba RISC processor based on the MIPS 3900 core
-	  see <http://www.toshiba.com/taec/components/Generic/risc/tx3912.htm>.
-
-	  Say Y here to enable kernel support for the on-board framebuffer.
-
 config FB_G364
 	bool "G364 frame buffer support"
 	depends on (FB = y) && (MIPS_MAGNUM_4000 || OLIVETTI_M700)
@@ -1796,13 +1808,14 @@
 	select FB_SYS_COPYAREA
 	select FB_SYS_IMAGEBLIT
 	select FB_SYS_FOPS
+	select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
 	---help---
 	  Include support for the virtual frame buffer in the PS3 platform.
 
 config FB_PS3_DEFAULT_SIZE_M
 	int "PS3 default frame buffer size (in MiB)"
 	depends on FB_PS3
-	default 18
+	default 9
 	---help---
 	  This is the default size (in MiB) of the virtual frame buffer in
 	  the PS3.
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index a562f9d..06eec7b 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -103,7 +103,6 @@
 obj-$(CONFIG_FB_PMAG_BA)	  += pmag-ba-fb.o
 obj-$(CONFIG_FB_PMAGB_B)	  += pmagb-b-fb.o
 obj-$(CONFIG_FB_MAXINE)		  += maxinefb.o
-obj-$(CONFIG_FB_TX3912)		  += tx3912fb.o
 obj-$(CONFIG_FB_S1D13XXX)	  += s1d13xxxfb.o
 obj-$(CONFIG_FB_IMX)              += imxfb.o
 obj-$(CONFIG_FB_S3C2410)	  += s3c2410fb.o
@@ -123,3 +122,6 @@
 
 # the test framebuffer is last
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
+
+#video output switch sysfs driver
+obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c
index 61a8bf1..eedb828 100644
--- a/drivers/video/acornfb.c
+++ b/drivers/video/acornfb.c
@@ -138,17 +138,6 @@
 	{  41250,  42083, VIDC_CTRL_DIV1,   VID_CTL_24MHz },	/* 24.000MHz */
 };
 
-#ifdef CONFIG_ARCH_A5K
-static struct pixclock a5k_clocks[] = {
-	{ 117974, 120357, VIDC_CTRL_DIV3,   VID_CTL_25MHz },	/*  8.392MHz */
-	{  78649,  80238, VIDC_CTRL_DIV2,   VID_CTL_25MHz },	/* 12.588MHz */
-	{  58987,  60178, VIDC_CTRL_DIV1_5, VID_CTL_25MHz },	/* 16.588MHz */
-	{  55000,  56111, VIDC_CTRL_DIV2,   VID_CTL_36MHz },	/* 18.000MHz */
-	{  39325,  40119, VIDC_CTRL_DIV1,   VID_CTL_25MHz },	/* 25.175MHz */
-	{  27500,  28055, VIDC_CTRL_DIV1,   VID_CTL_36MHz },	/* 36.000MHz */
-};
-#endif
-
 static struct pixclock *
 acornfb_valid_pixrate(struct fb_var_screeninfo *var)
 {
@@ -163,15 +152,6 @@
 		    pixclock < arc_clocks[i].max_clock)
 			return arc_clocks + i;
 
-#ifdef CONFIG_ARCH_A5K
-	if (machine_is_a5k()) {
-		for (i = 0; i < ARRAY_SIZE(a5k_clocks); i++)
-			if (pixclock > a5k_clocks[i].min_clock &&
-			    pixclock < a5k_clocks[i].max_clock)
-				return a5k_clocks + i;
-	}
-#endif
-
 	return NULL;
 }
 
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
index 6c9dc2e..a7a1c89 100644
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -447,13 +447,12 @@
 		goto out;
 	}
 
-	fb = kmalloc(sizeof(struct clcd_fb), GFP_KERNEL);
+	fb = kzalloc(sizeof(struct clcd_fb), GFP_KERNEL);
 	if (!fb) {
 		printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n");
 		ret = -ENOMEM;
 		goto free_region;
 	}
-	memset(fb, 0, sizeof(struct clcd_fb));
 
 	fb->dev = dev;
 	fb->board = board;
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index e1d5bd0..235b618 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -79,6 +79,29 @@
 	.accel		= FB_ACCEL_NONE,
 };
 
+static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2)
+{
+	unsigned long value;
+
+	if (!(cpu_is_at91sam9261() || cpu_is_at32ap7000()))
+		return xres;
+
+	value = xres;
+	if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) {
+		/* STN display */
+		if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) {
+			value *= 3;
+		}
+		if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4
+		   || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8
+		      && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL ))
+			value = DIV_ROUND_UP(value, 4);
+		else
+			value = DIV_ROUND_UP(value, 8);
+	}
+
+	return value;
+}
 
 static void atmel_lcdfb_update_dma(struct fb_info *info,
 			       struct fb_var_screeninfo *var)
@@ -181,6 +204,7 @@
 	var->xoffset = var->yoffset = 0;
 
 	switch (var->bits_per_pixel) {
+	case 1:
 	case 2:
 	case 4:
 	case 8:
@@ -195,8 +219,11 @@
 		var->blue.offset = 10;
 		var->red.length = var->green.length = var->blue.length = 5;
 		break;
-	case 24:
 	case 32:
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		/* fall through */
+	case 24:
 		var->red.offset = 0;
 		var->green.offset = 8;
 		var->blue.offset = 16;
@@ -228,8 +255,10 @@
 static int atmel_lcdfb_set_par(struct fb_info *info)
 {
 	struct atmel_lcdfb_info *sinfo = info->par;
+	unsigned long hozval_linesz;
 	unsigned long value;
 	unsigned long clk_value_khz;
+	unsigned long bits_per_line;
 
 	dev_dbg(info->device, "%s:\n", __func__);
 	dev_dbg(info->device, "  * resolution: %ux%u (%ux%u virtual)\n",
@@ -241,12 +270,15 @@
 
 	lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
 
-	if (info->var.bits_per_pixel <= 8)
+	if (info->var.bits_per_pixel == 1)
+		info->fix.visual = FB_VISUAL_MONO01;
+	else if (info->var.bits_per_pixel <= 8)
 		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
 	else
 		info->fix.visual = FB_VISUAL_TRUECOLOR;
 
-	info->fix.line_length = info->var.xres_virtual * (info->var.bits_per_pixel / 8);
+	bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel;
+	info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8);
 
 	/* Re-initialize the DMA engine... */
 	dev_dbg(info->device, "  * update DMA engine\n");
@@ -262,18 +294,21 @@
 	/* Set pixel clock */
 	clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
 
-	value = clk_value_khz / PICOS2KHZ(info->var.pixclock);
-
-	if (clk_value_khz % PICOS2KHZ(info->var.pixclock))
-		value++;
+	value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock));
 
 	value = (value / 2) - 1;
+	dev_dbg(info->device, "  * programming CLKVAL = 0x%08lx\n", value);
 
 	if (value <= 0) {
 		dev_notice(info->device, "Bypassing pixel clock divider\n");
 		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
-	} else
+	} else {
 		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET);
+		info->var.pixclock = KHZ2PICOS(clk_value_khz / (2 * (value + 1)));
+		dev_dbg(info->device, "  updated pixclk:     %lu KHz\n",
+					PICOS2KHZ(info->var.pixclock));
+	}
+
 
 	/* Initialize control register 2 */
 	value = sinfo->default_lcdcon2;
@@ -311,9 +346,14 @@
 	dev_dbg(info->device, "  * LCDTIM2 = %08lx\n", value);
 	lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
 
+	/* Horizontal value (aka line size) */
+	hozval_linesz = compute_hozval(info->var.xres,
+					lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2));
+
 	/* Display size */
-	value = (info->var.xres - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+	value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
 	value |= info->var.yres - 1;
+	dev_dbg(info->device, "  * LCDFRMCFG = %08lx\n", value);
 	lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
 
 	/* FIFO Threshold: Use formula from data sheet */
@@ -421,6 +461,15 @@
 			ret = 0;
 		}
 		break;
+
+	case FB_VISUAL_MONO01:
+		if (regno < 2) {
+			val = (regno == 0) ? 0x00 : 0x1F;
+			lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val);
+			ret = 0;
+		}
+		break;
+
 	}
 
 	return ret;
diff --git a/drivers/video/aty/ati_ids.h b/drivers/video/aty/ati_ids.h
index 685a754..dca2eb8 100644
--- a/drivers/video/aty/ati_ids.h
+++ b/drivers/video/aty/ati_ids.h
@@ -192,6 +192,12 @@
 #define PCI_CHIP_RS300_5835		0x5835
 #define PCI_CHIP_RS300_5836		0x5836
 #define PCI_CHIP_RS300_5837		0x5837
+#define PCI_CHIP_RS480_5955             0x5955
+#define PCI_CHIP_RV280_5960		0x5960
+#define PCI_CHIP_RV280_5961		0x5961
+#define PCI_CHIP_RV280_5962		0x5962
+#define PCI_CHIP_RV280_5964		0x5964
+#define PCI_CHIP_RS482_5975		0x5975
 #define PCI_CHIP_RV370_5B60             0x5B60
 #define PCI_CHIP_RV370_5B61             0x5B61
 #define PCI_CHIP_RV370_5B62             0x5B62
@@ -200,14 +206,8 @@
 #define PCI_CHIP_RV370_5B65             0x5B65
 #define PCI_CHIP_RV370_5B66             0x5B66
 #define PCI_CHIP_RV370_5B67             0x5B67
-#define PCI_CHIP_RV280_5960		0x5960
-#define PCI_CHIP_RV280_5961		0x5961
-#define PCI_CHIP_RV280_5962		0x5962
-#define PCI_CHIP_RV280_5964		0x5964
-#define PCI_CHIP_RS485_5975		0x5975
 #define PCI_CHIP_RV280_5C61		0x5C61
 #define PCI_CHIP_RV280_5C63		0x5C63
 #define PCI_CHIP_R423_5D57              0x5D57
 #define PCI_CHIP_RS350_7834             0x7834
 #define PCI_CHIP_RS350_7835             0x7835
-#define PCI_CHIP_RS480_5955             0x5955
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 7fea4d8..cfcbe37 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -1733,7 +1733,7 @@
 
 static int aty128_bl_update_status(struct backlight_device *bd)
 {
-	struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
+	struct aty128fb_par *par = bl_get_data(bd);
 	unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
 	int level;
 
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index ef330e3..bc6f009 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2141,7 +2141,7 @@
 
 static int aty_bl_update_status(struct backlight_device *bd)
 {
-	struct atyfb_par *par = class_get_devdata(&bd->class_dev);
+	struct atyfb_par *par = bl_get_data(bd);
 	unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
 	int level;
 
@@ -2913,10 +2913,6 @@
 	int node, len, i, j, ret;
 	u32 mem, chip_id;
 
-	/* Do not attach when we have a serial console. */
-	if (!con_is_present())
-		return -ENXIO;
-
 	/*
 	 * Map memory-mapped registers.
 	 */
@@ -2937,12 +2933,11 @@
 		/* nothing */ ;
 	j = i + 4;
 
-	par->mmap_map = kmalloc(j * sizeof(*par->mmap_map), GFP_ATOMIC);
+	par->mmap_map = kcalloc(j, sizeof(*par->mmap_map), GFP_ATOMIC);
 	if (!par->mmap_map) {
 		PRINTKE("atyfb_setup_sparc() can't alloc mmap_map\n");
 		return -ENOMEM;
 	}
-	memset(par->mmap_map, 0, j * sizeof(*par->mmap_map));
 
 	for (i = 0, j = 2; i < 6 && pdev->resource[i].start; i++) {
 		struct resource *rp = &pdev->resource[i];
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
index 0be25fa..1a056ad 100644
--- a/drivers/video/aty/radeon_backlight.c
+++ b/drivers/video/aty/radeon_backlight.c
@@ -47,7 +47,7 @@
 
 static int radeon_bl_update_status(struct backlight_device *bd)
 {
-	struct radeon_bl_privdata *pdata = class_get_devdata(&bd->class_dev);
+	struct radeon_bl_privdata *pdata = bl_get_data(bd);
 	struct radeonfb_info *rinfo = pdata->rinfo;
 	u32 lvds_gen_cntl, tmpPixclksCntl;
 	int level;
@@ -206,7 +206,7 @@
 	if (bd) {
 		struct radeon_bl_privdata *pdata;
 
-		pdata = class_get_devdata(&bd->class_dev);
+		pdata = bl_get_data(bd);
 		backlight_device_unregister(bd);
 		kfree(pdata);
 		rinfo->info->bl_dev = NULL;
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 47ca62f..4b747bd 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -102,6 +102,7 @@
 static struct pci_device_id radeonfb_pci_table[] = {
         /* Radeon Xpress 200m */
 	CHIP_DEF(PCI_CHIP_RS480_5955,   RS480,  CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
+	CHIP_DEF(PCI_CHIP_RS482_5975,	RS480,	CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
 	/* Mobility M6 */
 	CHIP_DEF(PCI_CHIP_RADEON_LY, 	RV100,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
 	CHIP_DEF(PCI_CHIP_RADEON_LZ,	RV100,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
@@ -153,8 +154,6 @@
 	/* Mobility 9200 (M9+) */
 	CHIP_DEF(PCI_CHIP_RV280_5C61,	RV280,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
 	CHIP_DEF(PCI_CHIP_RV280_5C63,	RV280,	CHIP_HAS_CRTC2 | CHIP_IS_MOBILITY),
-	/*Mobility Xpress 200 */
-	CHIP_DEF(PCI_CHIP_RS485_5975,	R300,	CHIP_HAS_CRTC2 | CHIP_IS_IGP | CHIP_IS_MOBILITY),
 	/* 9200 */
 	CHIP_DEF(PCI_CHIP_RV280_5960,	RV280,	CHIP_HAS_CRTC2),
 	CHIP_DEF(PCI_CHIP_RV280_5961,	RV280,	CHIP_HAS_CRTC2),
@@ -1285,7 +1284,8 @@
 	if (rinfo->family == CHIP_FAMILY_R300 ||
 	    rinfo->family == CHIP_FAMILY_RS300 ||
 	    rinfo->family == CHIP_FAMILY_R350 ||
-	    rinfo->family == CHIP_FAMILY_RV350) {
+	    rinfo->family == CHIP_FAMILY_RV350 ||
+	    rinfo->family == CHIP_FAMILY_RV380 ) {
 		if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
 			/* When restoring console mode, use saved PPLL_REF_DIV
 			 * setting.
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index 80a81ec..832e461 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -115,6 +115,52 @@
 module_param(nocursor, int, 0644);
 MODULE_PARM_DESC(nocursor, "cursor enable/disable");
 
+/* fb_blank
+ * Blank the screen. Depending on the mode, the screen will be
+ * activated with the backlight color, or desactivated
+ */
+static int au1100fb_fb_blank(int blank_mode, struct fb_info *fbi)
+{
+	struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
+
+	print_dbg("fb_blank %d %p", blank_mode, fbi);
+
+	switch (blank_mode) {
+
+	case VESA_NO_BLANKING:
+			/* Turn on panel */
+			fbdev->regs->lcd_control |= LCD_CONTROL_GO;
+#ifdef CONFIG_MIPS_PB1100
+			if (drv_info.panel_idx == 1) {
+				au_writew(au_readw(PB1100_G_CONTROL)
+					  | (PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD),
+			PB1100_G_CONTROL);
+			}
+#endif
+		au_sync();
+		break;
+
+	case VESA_VSYNC_SUSPEND:
+	case VESA_HSYNC_SUSPEND:
+	case VESA_POWERDOWN:
+			/* Turn off panel */
+			fbdev->regs->lcd_control &= ~LCD_CONTROL_GO;
+#ifdef CONFIG_MIPS_PB1100
+			if (drv_info.panel_idx == 1) {
+				au_writew(au_readw(PB1100_G_CONTROL)
+				  	  & ~(PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD),
+			PB1100_G_CONTROL);
+			}
+#endif
+		au_sync();
+		break;
+	default:
+		break;
+
+	}
+	return 0;
+}
+
 /*
  * Set hardware with var settings. This will enable the controller with a specific
  * mode, normally validated with the fb_check_var method
@@ -272,52 +318,6 @@
 	return 0;
 }
 
-/* fb_blank
- * Blank the screen. Depending on the mode, the screen will be
- * activated with the backlight color, or desactivated
- */
-int au1100fb_fb_blank(int blank_mode, struct fb_info *fbi)
-{
-	struct au1100fb_device *fbdev = to_au1100fb_device(fbi);
-
-	print_dbg("fb_blank %d %p", blank_mode, fbi);
-
-	switch (blank_mode) {
-
-	case VESA_NO_BLANKING:
-			/* Turn on panel */
-			fbdev->regs->lcd_control |= LCD_CONTROL_GO;
-#ifdef CONFIG_MIPS_PB1100
-			if (drv_info.panel_idx == 1) {
-				au_writew(au_readw(PB1100_G_CONTROL)
-					  | (PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD),
-			PB1100_G_CONTROL);
-			}
-#endif
-		au_sync();
-		break;
-
-	case VESA_VSYNC_SUSPEND:
-	case VESA_HSYNC_SUSPEND:
-	case VESA_POWERDOWN:
-			/* Turn off panel */
-			fbdev->regs->lcd_control &= ~LCD_CONTROL_GO;
-#ifdef CONFIG_MIPS_PB1100
-			if (drv_info.panel_idx == 1) {
-				au_writew(au_readw(PB1100_G_CONTROL)
-				  	  & ~(PB1100_G_CONTROL_BL | PB1100_G_CONTROL_VDD),
-			PB1100_G_CONTROL);
-			}
-#endif
-		au_sync();
-		break;
-	default:
-		break;
-
-	}
-	return 0;
-}
-
 /* fb_pan_display
  * Pan display in x and/or y as specified
  */
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c
index dbf4ec3..03e57ef 100644
--- a/drivers/video/au1200fb.c
+++ b/drivers/video/au1200fb.c
@@ -1589,11 +1589,10 @@
 		return -EFAULT;
 	}
 
-	fbi->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+	fbi->pseudo_palette = kcalloc(16, sizeof(u32), GFP_KERNEL);
 	if (!fbi->pseudo_palette) {
 		return -ENOMEM;
 	}
-	memset(fbi->pseudo_palette, 0, sizeof(u32) * 16);
 
 	if (fb_alloc_cmap(&fbi->cmap, AU1200_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
 		print_err("Fail to allocate colormap (%d entries)",
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index fbef663..9609a6c 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -8,17 +8,9 @@
 	  Enable this to be able to choose the drivers for controlling the
 	  backlight and the LCD panel on some platforms, for example on PDAs.
 
-config BACKLIGHT_CLASS_DEVICE
-        tristate "Lowlevel Backlight controls"
-	depends on BACKLIGHT_LCD_SUPPORT
-	default m
-	help
-	  This framework adds support for low-level control of the LCD
-          backlight. This includes support for brightness and power.
-
-	  To have support for your specific LCD panel you will have to
-	  select the proper drivers which depend on this option.
-
+#
+# LCD
+#
 config LCD_CLASS_DEVICE
         tristate "Lowlevel LCD controls"
 	depends on BACKLIGHT_LCD_SUPPORT
@@ -32,13 +24,40 @@
 	  To have support for your specific LCD panel you will have to
 	  select the proper drivers which depend on this option.
 
-config BACKLIGHT_CORGI
-	tristate "Sharp Corgi Backlight Driver (SL Series)"
-	depends on BACKLIGHT_CLASS_DEVICE && PXA_SHARPSL
-	default y
+config LCD_LTV350QV
+	tristate "Samsung LTV350QV LCD Panel"
+	depends on LCD_CLASS_DEVICE && SPI_MASTER
+	default n
 	help
-	  If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y to enable the
-	  backlight driver.
+	  If you have a Samsung LTV350QV LCD panel, say y to include a
+	  power control driver for it.  The panel starts up in power
+	  off state, so you need this driver in order to see any
+	  output.
+
+	  The LTV350QV panel is present on all ATSTK1000 boards.
+
+#
+# Backlight
+#
+config BACKLIGHT_CLASS_DEVICE
+        tristate "Lowlevel Backlight controls"
+	depends on BACKLIGHT_LCD_SUPPORT
+	default m
+	help
+	  This framework adds support for low-level control of the LCD
+          backlight. This includes support for brightness and power.
+
+	  To have support for your specific LCD panel you will have to
+	  select the proper drivers which depend on this option.
+
+config BACKLIGHT_CORGI
+	tristate "Generic (aka Sharp Corgi) Backlight Driver"
+	depends on BACKLIGHT_CLASS_DEVICE
+	default n
+	help
+	  Say y to enable the generic platform backlight driver previously
+	  known as the Corgi backlight driver. If you have a Sharp Zaurus
+	  SL-C7xx, SL-Cxx00 or SL-6000x say y. Most users can say n.
 
 config BACKLIGHT_LOCOMO
 	tristate "Sharp LOCOMO LCD/Backlight Driver"
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index c6e2266..965a78b 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -1,6 +1,8 @@
 # Backlight & LCD drivers
 
 obj-$(CONFIG_LCD_CLASS_DEVICE)     += lcd.o
+obj-$(CONFIG_LCD_LTV350QV)	+= ltv350qv.o
+
 obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
 obj-$(CONFIG_BACKLIGHT_CORGI)	+= corgi_bl.o
 obj-$(CONFIG_BACKLIGHT_HP680)	+= hp680_bl.o
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 7e06223..4840fe2 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -69,18 +69,20 @@
 }
 #endif /* CONFIG_FB */
 
-static ssize_t backlight_show_power(struct class_device *cdev, char *buf)
+static ssize_t backlight_show_power(struct device *dev,
+		struct device_attribute *attr,char *buf)
 {
-	struct backlight_device *bd = to_backlight_device(cdev);
+	struct backlight_device *bd = to_backlight_device(dev);
 
 	return sprintf(buf, "%d\n", bd->props.power);
 }
 
-static ssize_t backlight_store_power(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t backlight_store_power(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
 {
 	int rc = -ENXIO;
 	char *endp;
-	struct backlight_device *bd = to_backlight_device(cdev);
+	struct backlight_device *bd = to_backlight_device(dev);
 	int power = simple_strtoul(buf, &endp, 0);
 	size_t size = endp - buf;
 
@@ -101,18 +103,20 @@
 	return rc;
 }
 
-static ssize_t backlight_show_brightness(struct class_device *cdev, char *buf)
+static ssize_t backlight_show_brightness(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
-	struct backlight_device *bd = to_backlight_device(cdev);
+	struct backlight_device *bd = to_backlight_device(dev);
 
 	return sprintf(buf, "%d\n", bd->props.brightness);
 }
 
-static ssize_t backlight_store_brightness(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t backlight_store_brightness(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
 {
 	int rc = -ENXIO;
 	char *endp;
-	struct backlight_device *bd = to_backlight_device(cdev);
+	struct backlight_device *bd = to_backlight_device(dev);
 	int brightness = simple_strtoul(buf, &endp, 0);
 	size_t size = endp - buf;
 
@@ -138,18 +142,19 @@
 	return rc;
 }
 
-static ssize_t backlight_show_max_brightness(struct class_device *cdev, char *buf)
+static ssize_t backlight_show_max_brightness(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
-	struct backlight_device *bd = to_backlight_device(cdev);
+	struct backlight_device *bd = to_backlight_device(dev);
 
 	return sprintf(buf, "%d\n", bd->props.max_brightness);
 }
 
-static ssize_t backlight_show_actual_brightness(struct class_device *cdev,
-						char *buf)
+static ssize_t backlight_show_actual_brightness(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
 	int rc = -ENXIO;
-	struct backlight_device *bd = to_backlight_device(cdev);
+	struct backlight_device *bd = to_backlight_device(dev);
 
 	mutex_lock(&bd->ops_lock);
 	if (bd->ops && bd->ops->get_brightness)
@@ -159,31 +164,22 @@
 	return rc;
 }
 
-static void backlight_class_release(struct class_device *dev)
+static struct class *backlight_class;
+
+static void bl_device_release(struct device *dev)
 {
 	struct backlight_device *bd = to_backlight_device(dev);
 	kfree(bd);
 }
 
-static struct class backlight_class = {
-	.name = "backlight",
-	.release = backlight_class_release,
-};
-
-#define DECLARE_ATTR(_name,_mode,_show,_store)			\
-{							 	\
-	.attr	= { .name = __stringify(_name), .mode = _mode }, \
-	.show	= _show,					\
-	.store	= _store,					\
-}
-
-static const struct class_device_attribute bl_class_device_attributes[] = {
-	DECLARE_ATTR(power, 0644, backlight_show_power, backlight_store_power),
-	DECLARE_ATTR(brightness, 0644, backlight_show_brightness,
+static struct device_attribute bl_device_attributes[] = {
+	__ATTR(bl_power, 0644, backlight_show_power, backlight_store_power),
+	__ATTR(brightness, 0644, backlight_show_brightness,
 		     backlight_store_brightness),
-	DECLARE_ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
+	__ATTR(actual_brightness, 0444, backlight_show_actual_brightness,
 		     NULL),
-	DECLARE_ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
+	__ATTR(max_brightness, 0444, backlight_show_max_brightness, NULL),
+	__ATTR_NULL,
 };
 
 /**
@@ -191,22 +187,20 @@
  *   backlight_device class.
  * @name: the name of the new object(must be the same as the name of the
  *   respective framebuffer device).
- * @devdata: an optional pointer to be stored in the class_device. The
- *   methods may retrieve it by using class_get_devdata(&bd->class_dev).
+ * @devdata: an optional pointer to be stored for private driver use. The
+ *   methods may retrieve it by using bl_get_data(bd).
  * @ops: the backlight operations structure.
  *
- * Creates and registers new backlight class_device. Returns either an
+ * Creates and registers new backlight device. Returns either an
  * ERR_PTR() or a pointer to the newly allocated device.
  */
 struct backlight_device *backlight_device_register(const char *name,
-	struct device *dev,
-	void *devdata,
-	struct backlight_ops *ops)
+		struct device *parent, void *devdata, struct backlight_ops *ops)
 {
-	int i, rc;
 	struct backlight_device *new_bd;
+	int rc;
 
-	pr_debug("backlight_device_alloc: name=%s\n", name);
+	pr_debug("backlight_device_register: name=%s\n", name);
 
 	new_bd = kzalloc(sizeof(struct backlight_device), GFP_KERNEL);
 	if (!new_bd)
@@ -214,13 +208,14 @@
 
 	mutex_init(&new_bd->update_lock);
 	mutex_init(&new_bd->ops_lock);
-	new_bd->ops = ops;
-	new_bd->class_dev.class = &backlight_class;
-	new_bd->class_dev.dev = dev;
-	strlcpy(new_bd->class_dev.class_id, name, KOBJ_NAME_LEN);
-	class_set_devdata(&new_bd->class_dev, devdata);
 
-	rc = class_device_register(&new_bd->class_dev);
+	new_bd->dev.class = backlight_class;
+	new_bd->dev.parent = parent;
+	new_bd->dev.release = bl_device_release;
+	strlcpy(new_bd->dev.bus_id, name, BUS_ID_SIZE);
+	dev_set_drvdata(&new_bd->dev, devdata);
+
+	rc = device_register(&new_bd->dev);
 	if (rc) {
 		kfree(new_bd);
 		return ERR_PTR(rc);
@@ -228,23 +223,11 @@
 
 	rc = backlight_register_fb(new_bd);
 	if (rc) {
-		class_device_unregister(&new_bd->class_dev);
+		device_unregister(&new_bd->dev);
 		return ERR_PTR(rc);
 	}
 
-
-	for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++) {
-		rc = class_device_create_file(&new_bd->class_dev,
-					      &bl_class_device_attributes[i]);
-		if (rc) {
-			while (--i >= 0)
-				class_device_remove_file(&new_bd->class_dev,
-							 &bl_class_device_attributes[i]);
-			class_device_unregister(&new_bd->class_dev);
-			/* No need to kfree(new_bd) since release() method was called */
-			return ERR_PTR(rc);
-		}
-	}
+	new_bd->ops = ops;
 
 #ifdef CONFIG_PMAC_BACKLIGHT
 	mutex_lock(&pmac_backlight_mutex);
@@ -265,42 +248,40 @@
  */
 void backlight_device_unregister(struct backlight_device *bd)
 {
-	int i;
-
 	if (!bd)
 		return;
 
-	pr_debug("backlight_device_unregister: name=%s\n", bd->class_dev.class_id);
-
 #ifdef CONFIG_PMAC_BACKLIGHT
 	mutex_lock(&pmac_backlight_mutex);
 	if (pmac_backlight == bd)
 		pmac_backlight = NULL;
 	mutex_unlock(&pmac_backlight_mutex);
 #endif
-
-	for (i = 0; i < ARRAY_SIZE(bl_class_device_attributes); i++)
-		class_device_remove_file(&bd->class_dev,
-					 &bl_class_device_attributes[i]);
-
 	mutex_lock(&bd->ops_lock);
 	bd->ops = NULL;
 	mutex_unlock(&bd->ops_lock);
 
 	backlight_unregister_fb(bd);
-
-	class_device_unregister(&bd->class_dev);
+	device_unregister(&bd->dev);
 }
 EXPORT_SYMBOL(backlight_device_unregister);
 
 static void __exit backlight_class_exit(void)
 {
-	class_unregister(&backlight_class);
+	class_destroy(backlight_class);
 }
 
 static int __init backlight_class_init(void)
 {
-	return class_register(&backlight_class);
+	backlight_class = class_create(THIS_MODULE, "backlight");
+	if (IS_ERR(backlight_class)) {
+		printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n",
+				PTR_ERR(backlight_class));
+		return PTR_ERR(backlight_class);
+	}
+
+	backlight_class->dev_attrs = bl_device_attributes;
+	return 0;
 }
 
 /*
diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c
index ce00e18..4d4d037 100644
--- a/drivers/video/backlight/corgi_bl.c
+++ b/drivers/video/backlight/corgi_bl.c
@@ -18,13 +18,11 @@
 #include <linux/mutex.h>
 #include <linux/fb.h>
 #include <linux/backlight.h>
-#include <asm/arch/sharpsl.h>
-#include <asm/hardware/sharpsl_pm.h>
 
 static int corgibl_intensity;
 static struct backlight_properties corgibl_data;
 static struct backlight_device *corgi_backlight_device;
-static struct corgibl_machinfo *bl_machinfo;
+static struct generic_bl_info *bl_machinfo;
 
 static unsigned long corgibl_flags;
 #define CORGIBL_SUSPENDED     0x01
@@ -32,7 +30,6 @@
 
 static int corgibl_send_intensity(struct backlight_device *bd)
 {
-	void (*corgi_kick_batt)(void);
 	int intensity = bd->props.brightness;
 
 	if (bd->props.power != FB_BLANK_UNBLANK)
@@ -48,11 +45,8 @@
 
 	corgibl_intensity = intensity;
 
- 	corgi_kick_batt = symbol_get(sharpsl_battery_kick);
- 	if (corgi_kick_batt) {
- 		corgi_kick_batt();
- 		symbol_put(sharpsl_battery_kick);
- 	}
+	if (bl_machinfo->kick_battery)
+		bl_machinfo->kick_battery();
 
 	return 0;
 }
@@ -107,13 +101,17 @@
 
 static int corgibl_probe(struct platform_device *pdev)
 {
-	struct corgibl_machinfo *machinfo = pdev->dev.platform_data;
+	struct generic_bl_info *machinfo = pdev->dev.platform_data;
+	const char *name = "generic-bl";
 
 	bl_machinfo = machinfo;
 	if (!machinfo->limit_mask)
 		machinfo->limit_mask = -1;
 
-	corgi_backlight_device = backlight_device_register ("corgi-bl",
+	if (machinfo->name)
+		name = machinfo->name;
+
+	corgi_backlight_device = backlight_device_register (name,
 		&pdev->dev, NULL, &corgibl_ops);
 	if (IS_ERR (corgi_backlight_device))
 		return PTR_ERR (corgi_backlight_device);
@@ -149,7 +147,7 @@
 	.suspend	= corgibl_suspend,
 	.resume		= corgibl_resume,
 	.driver		= {
-		.name	= "corgi-bl",
+		.name	= "generic-bl",
 	},
 };
 
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c
index e9bbc34..92e201e 100644
--- a/drivers/video/backlight/cr_bllcd.c
+++ b/drivers/video/backlight/cr_bllcd.c
@@ -171,13 +171,11 @@
 
 static int cr_backlight_probe(struct platform_device *pdev)
 {
+	struct backlight_device *bdp;
+	struct lcd_device *ldp;
 	struct cr_panel *crp;
 	u8 dev_en;
 
-	crp = kzalloc(sizeof(crp), GFP_KERNEL);
-	if (crp == NULL)
-		return -ENOMEM;
-
 	lpc_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
 					CRVML_DEVICE_LPC, NULL);
 	if (!lpc_dev) {
@@ -193,27 +191,34 @@
 		return -ENODEV;
 	}
 
-	crp->cr_backlight_device = backlight_device_register("cr-backlight",
-							     &pdev->dev, NULL,
-							     &cr_backlight_ops);
-	if (IS_ERR(crp->cr_backlight_device)) {
+	bdp = backlight_device_register("cr-backlight",
+					&pdev->dev, NULL, &cr_backlight_ops);
+	if (IS_ERR(bdp)) {
 		pci_dev_put(lpc_dev);
-		return PTR_ERR(crp->cr_backlight_device);
+		return PTR_ERR(bdp);
 	}
 
-	crp->cr_lcd_device = lcd_device_register("cr-lcd",
-							&pdev->dev,
-							&cr_lcd_ops);
-
-	if (IS_ERR(crp->cr_lcd_device)) {
+	ldp = lcd_device_register("cr-lcd", &pdev->dev, NULL, &cr_lcd_ops);
+	if (IS_ERR(ldp)) {
+		backlight_device_unregister(bdp);
 		pci_dev_put(lpc_dev);
-		return PTR_ERR(crp->cr_backlight_device);
+		return PTR_ERR(bdp);
 	}
 
 	pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR,
 			      &gpio_bar);
 	gpio_bar &= ~0x3F;
 
+	crp = kzalloc(sizeof(*crp), GFP_KERNEL);
+	if (!crp) {
+		lcd_device_unregister(ldp);
+		backlight_device_unregister(bdp);
+		pci_dev_put(lpc_dev);
+		return -ENOMEM;
+	}
+
+	crp->cr_backlight_device = bdp;
+	crp->cr_lcd_device = ldp;
 	crp->cr_backlight_device->props.power = FB_BLANK_UNBLANK;
 	crp->cr_backlight_device->props.brightness = 0;
 	crp->cr_backlight_device->props.max_brightness = 0;
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index 648b53c..299fd31 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -61,10 +61,11 @@
 }
 #endif /* CONFIG_FB */
 
-static ssize_t lcd_show_power(struct class_device *cdev, char *buf)
+static ssize_t lcd_show_power(struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
 	int rc;
-	struct lcd_device *ld = to_lcd_device(cdev);
+	struct lcd_device *ld = to_lcd_device(dev);
 
 	mutex_lock(&ld->ops_lock);
 	if (ld->ops && ld->ops->get_power)
@@ -76,11 +77,12 @@
 	return rc;
 }
 
-static ssize_t lcd_store_power(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t lcd_store_power(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
 {
 	int rc = -ENXIO;
 	char *endp;
-	struct lcd_device *ld = to_lcd_device(cdev);
+	struct lcd_device *ld = to_lcd_device(dev);
 	int power = simple_strtoul(buf, &endp, 0);
 	size_t size = endp - buf;
 
@@ -100,10 +102,11 @@
 	return rc;
 }
 
-static ssize_t lcd_show_contrast(struct class_device *cdev, char *buf)
+static ssize_t lcd_show_contrast(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
 	int rc = -ENXIO;
-	struct lcd_device *ld = to_lcd_device(cdev);
+	struct lcd_device *ld = to_lcd_device(dev);
 
 	mutex_lock(&ld->ops_lock);
 	if (ld->ops && ld->ops->get_contrast)
@@ -113,11 +116,12 @@
 	return rc;
 }
 
-static ssize_t lcd_store_contrast(struct class_device *cdev, const char *buf, size_t count)
+static ssize_t lcd_store_contrast(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
 {
 	int rc = -ENXIO;
 	char *endp;
-	struct lcd_device *ld = to_lcd_device(cdev);
+	struct lcd_device *ld = to_lcd_device(dev);
 	int contrast = simple_strtoul(buf, &endp, 0);
 	size_t size = endp - buf;
 
@@ -137,53 +141,45 @@
 	return rc;
 }
 
-static ssize_t lcd_show_max_contrast(struct class_device *cdev, char *buf)
+static ssize_t lcd_show_max_contrast(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
-	struct lcd_device *ld = to_lcd_device(cdev);
+	struct lcd_device *ld = to_lcd_device(dev);
 
 	return sprintf(buf, "%d\n", ld->props.max_contrast);
 }
 
-static void lcd_class_release(struct class_device *dev)
+static struct class *lcd_class;
+
+static void lcd_device_release(struct device *dev)
 {
 	struct lcd_device *ld = to_lcd_device(dev);
 	kfree(ld);
 }
 
-static struct class lcd_class = {
-	.name = "lcd",
-	.release = lcd_class_release,
-};
-
-#define DECLARE_ATTR(_name,_mode,_show,_store)			\
-{							 	\
-	.attr	= { .name = __stringify(_name), .mode = _mode }, \
-	.show	= _show,					\
-	.store	= _store,					\
-}
-
-static const struct class_device_attribute lcd_class_device_attributes[] = {
-	DECLARE_ATTR(power, 0644, lcd_show_power, lcd_store_power),
-	DECLARE_ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast),
-	DECLARE_ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL),
+static struct device_attribute lcd_device_attributes[] = {
+	__ATTR(lcd_power, 0644, lcd_show_power, lcd_store_power),
+	__ATTR(contrast, 0644, lcd_show_contrast, lcd_store_contrast),
+	__ATTR(max_contrast, 0444, lcd_show_max_contrast, NULL),
+	__ATTR_NULL,
 };
 
 /**
  * lcd_device_register - register a new object of lcd_device class.
  * @name: the name of the new object(must be the same as the name of the
  *   respective framebuffer device).
- * @devdata: an optional pointer to be stored in the class_device. The
- *   methods may retrieve it by using class_get_devdata(ld->class_dev).
+ * @devdata: an optional pointer to be stored in the device. The
+ *   methods may retrieve it by using lcd_get_data(ld).
  * @ops: the lcd operations structure.
  *
- * Creates and registers a new lcd class_device. Returns either an ERR_PTR()
+ * Creates and registers a new lcd device. Returns either an ERR_PTR()
  * or a pointer to the newly allocated device.
  */
-struct lcd_device *lcd_device_register(const char *name, void *devdata,
-				       struct lcd_ops *ops)
+struct lcd_device *lcd_device_register(const char *name, struct device *parent,
+		void *devdata, struct lcd_ops *ops)
 {
-	int i, rc;
 	struct lcd_device *new_ld;
+	int rc;
 
 	pr_debug("lcd_device_register: name=%s\n", name);
 
@@ -193,12 +189,14 @@
 
 	mutex_init(&new_ld->ops_lock);
 	mutex_init(&new_ld->update_lock);
-	new_ld->ops = ops;
-	new_ld->class_dev.class = &lcd_class;
-	strlcpy(new_ld->class_dev.class_id, name, KOBJ_NAME_LEN);
-	class_set_devdata(&new_ld->class_dev, devdata);
 
-	rc = class_device_register(&new_ld->class_dev);
+	new_ld->dev.class = lcd_class;
+	new_ld->dev.parent = parent;
+	new_ld->dev.release = lcd_device_release;
+	strlcpy(new_ld->dev.bus_id, name, BUS_ID_SIZE);
+	dev_set_drvdata(&new_ld->dev, devdata);
+
+	rc = device_register(&new_ld->dev);
 	if (rc) {
 		kfree(new_ld);
 		return ERR_PTR(rc);
@@ -206,22 +204,11 @@
 
 	rc = lcd_register_fb(new_ld);
 	if (rc) {
-		class_device_unregister(&new_ld->class_dev);
+		device_unregister(&new_ld->dev);
 		return ERR_PTR(rc);
 	}
 
-	for (i = 0; i < ARRAY_SIZE(lcd_class_device_attributes); i++) {
-		rc = class_device_create_file(&new_ld->class_dev,
-					      &lcd_class_device_attributes[i]);
-		if (rc) {
-			while (--i >= 0)
-				class_device_remove_file(&new_ld->class_dev,
-							 &lcd_class_device_attributes[i]);
-			class_device_unregister(&new_ld->class_dev);
-			/* No need to kfree(new_ld) since release() method was called */
-			return ERR_PTR(rc);
-		}
-	}
+	new_ld->ops = ops;
 
 	return new_ld;
 }
@@ -235,33 +222,34 @@
  */
 void lcd_device_unregister(struct lcd_device *ld)
 {
-	int i;
-
 	if (!ld)
 		return;
 
-	pr_debug("lcd_device_unregister: name=%s\n", ld->class_dev.class_id);
-
-	for (i = 0; i < ARRAY_SIZE(lcd_class_device_attributes); i++)
-		class_device_remove_file(&ld->class_dev,
-					 &lcd_class_device_attributes[i]);
-
 	mutex_lock(&ld->ops_lock);
 	ld->ops = NULL;
 	mutex_unlock(&ld->ops_lock);
 	lcd_unregister_fb(ld);
-	class_device_unregister(&ld->class_dev);
+
+	device_unregister(&ld->dev);
 }
 EXPORT_SYMBOL(lcd_device_unregister);
 
 static void __exit lcd_class_exit(void)
 {
-	class_unregister(&lcd_class);
+	class_destroy(lcd_class);
 }
 
 static int __init lcd_class_init(void)
 {
-	return class_register(&lcd_class);
+	lcd_class = class_create(THIS_MODULE, "lcd");
+	if (IS_ERR(lcd_class)) {
+		printk(KERN_WARNING "Unable to create backlight class; errno = %ld\n",
+				PTR_ERR(lcd_class));
+		return PTR_ERR(lcd_class);
+	}
+
+	lcd_class->dev_attrs = lcd_device_attributes;
+	return 0;
 }
 
 /*
diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c
new file mode 100644
index 0000000..2eb206b
--- /dev/null
+++ b/drivers/video/backlight/ltv350qv.c
@@ -0,0 +1,330 @@
+/*
+ * Power control for Samsung LTV350QV Quarter VGA LCD Panel
+ *
+ * Copyright (C) 2006, 2007 Atmel 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.
+ */
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/lcd.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include "ltv350qv.h"
+
+#define POWER_IS_ON(pwr)	((pwr) <= FB_BLANK_NORMAL)
+
+struct ltv350qv {
+	struct spi_device	*spi;
+	u8			*buffer;
+	int			power;
+	struct lcd_device	*ld;
+};
+
+/*
+ * The power-on and power-off sequences are taken from the
+ * LTV350QV-F04 data sheet from Samsung. The register definitions are
+ * taken from the S6F2002 command list also from Samsung. Both
+ * documents are distributed with the AVR32 Linux BSP CD from Atmel.
+ *
+ * There's still some voodoo going on here, but it's a lot better than
+ * in the first incarnation of the driver where all we had was the raw
+ * numbers from the initialization sequence.
+ */
+static int ltv350qv_write_reg(struct ltv350qv *lcd, u8 reg, u16 val)
+{
+	struct spi_message msg;
+	struct spi_transfer index_xfer = {
+		.len		= 3,
+		.cs_change	= 1,
+	};
+	struct spi_transfer value_xfer = {
+		.len		= 3,
+	};
+
+	spi_message_init(&msg);
+
+	/* register index */
+	lcd->buffer[0] = LTV_OPC_INDEX;
+	lcd->buffer[1] = 0x00;
+	lcd->buffer[2] = reg & 0x7f;
+	index_xfer.tx_buf = lcd->buffer;
+	spi_message_add_tail(&index_xfer, &msg);
+
+	/* register value */
+	lcd->buffer[4] = LTV_OPC_DATA;
+	lcd->buffer[5] = val >> 8;
+	lcd->buffer[6] = val;
+	value_xfer.tx_buf = lcd->buffer + 4;
+	spi_message_add_tail(&value_xfer, &msg);
+
+	return spi_sync(lcd->spi, &msg);
+}
+
+/* The comments are taken straight from the data sheet */
+static int ltv350qv_power_on(struct ltv350qv *lcd)
+{
+	int ret;
+
+	/* Power On Reset Display off State */
+	if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, 0x0000))
+		goto err;
+	msleep(15);
+
+	/* Power Setting Function 1 */
+	if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE))
+		goto err;
+	if (ltv350qv_write_reg(lcd, LTV_PWRCTL2, LTV_VCOML_ENABLE))
+		goto err_power1;
+
+	/* Power Setting Function 2 */
+	if (ltv350qv_write_reg(lcd, LTV_PWRCTL1,
+			       LTV_VCOM_DISABLE | LTV_DRIVE_CURRENT(5)
+			       | LTV_SUPPLY_CURRENT(5)))
+		goto err_power2;
+
+	msleep(55);
+
+	/* Instruction Setting */
+	ret = ltv350qv_write_reg(lcd, LTV_IFCTL,
+				 LTV_NMD | LTV_REV | LTV_NL(0x1d));
+	ret |= ltv350qv_write_reg(lcd, LTV_DATACTL,
+				  LTV_DS_SAME | LTV_CHS_480
+				  | LTV_DF_RGB | LTV_RGB_BGR);
+	ret |= ltv350qv_write_reg(lcd, LTV_ENTRY_MODE,
+				  LTV_VSPL_ACTIVE_LOW
+				  | LTV_HSPL_ACTIVE_LOW
+				  | LTV_DPL_SAMPLE_RISING
+				  | LTV_EPL_ACTIVE_LOW
+				  | LTV_SS_RIGHT_TO_LEFT);
+	ret |= ltv350qv_write_reg(lcd, LTV_GATECTL1, LTV_CLW(3));
+	ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2,
+				  LTV_NW_INV_1LINE | LTV_FWI(3));
+	ret |= ltv350qv_write_reg(lcd, LTV_VBP, 0x000a);
+	ret |= ltv350qv_write_reg(lcd, LTV_HBP, 0x0021);
+	ret |= ltv350qv_write_reg(lcd, LTV_SOTCTL, LTV_SDT(3) | LTV_EQ(0));
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(0), 0x0103);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(1), 0x0301);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(2), 0x1f0f);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(3), 0x1f0f);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(4), 0x0707);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(5), 0x0307);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(6), 0x0707);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(7), 0x0000);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(8), 0x0004);
+	ret |= ltv350qv_write_reg(lcd, LTV_GAMMA(9), 0x0000);
+	if (ret)
+		goto err_settings;
+
+	/* Wait more than 2 frames */
+	msleep(20);
+
+	/* Display On Sequence */
+	ret = ltv350qv_write_reg(lcd, LTV_PWRCTL1,
+				 LTV_VCOM_DISABLE | LTV_VCOMOUT_ENABLE
+				 | LTV_POWER_ON | LTV_DRIVE_CURRENT(5)
+				 | LTV_SUPPLY_CURRENT(5));
+	ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2,
+				  LTV_NW_INV_1LINE | LTV_DSC | LTV_FWI(3));
+	if (ret)
+		goto err_disp_on;
+
+	/* Display should now be ON. Phew. */
+	return 0;
+
+err_disp_on:
+	/*
+	 * Try to recover. Error handling probably isn't very useful
+	 * at this point, just make a best effort to switch the panel
+	 * off.
+	 */
+	ltv350qv_write_reg(lcd, LTV_PWRCTL1,
+			   LTV_VCOM_DISABLE | LTV_DRIVE_CURRENT(5)
+			   | LTV_SUPPLY_CURRENT(5));
+	ltv350qv_write_reg(lcd, LTV_GATECTL2,
+			   LTV_NW_INV_1LINE | LTV_FWI(3));
+err_settings:
+err_power2:
+err_power1:
+	ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000);
+	msleep(1);
+err:
+	ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE);
+	return -EIO;
+}
+
+static int ltv350qv_power_off(struct ltv350qv *lcd)
+{
+	int ret;
+
+	/* Display Off Sequence */
+	ret = ltv350qv_write_reg(lcd, LTV_PWRCTL1,
+				 LTV_VCOM_DISABLE
+				 | LTV_DRIVE_CURRENT(5)
+				 | LTV_SUPPLY_CURRENT(5));
+	ret |= ltv350qv_write_reg(lcd, LTV_GATECTL2,
+				  LTV_NW_INV_1LINE | LTV_FWI(3));
+
+	/* Power down setting 1 */
+	ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000);
+
+	/* Wait at least 1 ms */
+	msleep(1);
+
+	/* Power down setting 2 */
+	ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE);
+
+	/*
+	 * No point in trying to recover here. If we can't switch the
+	 * panel off, what are we supposed to do other than inform the
+	 * user about the failure?
+	 */
+	if (ret)
+		return -EIO;
+
+	/* Display power should now be OFF */
+	return 0;
+}
+
+static int ltv350qv_power(struct ltv350qv *lcd, int power)
+{
+	int ret = 0;
+
+	if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power))
+		ret = ltv350qv_power_on(lcd);
+	else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power))
+		ret = ltv350qv_power_off(lcd);
+
+	if (!ret)
+		lcd->power = power;
+
+	return ret;
+}
+
+static int ltv350qv_set_power(struct lcd_device *ld, int power)
+{
+	struct ltv350qv *lcd = lcd_get_data(ld);
+
+	return ltv350qv_power(lcd, power);
+}
+
+static int ltv350qv_get_power(struct lcd_device *ld)
+{
+	struct ltv350qv *lcd = lcd_get_data(ld);
+
+	return lcd->power;
+}
+
+static struct lcd_ops ltv_ops = {
+	.get_power	= ltv350qv_get_power,
+	.set_power	= ltv350qv_set_power,
+};
+
+static int __devinit ltv350qv_probe(struct spi_device *spi)
+{
+	struct ltv350qv *lcd;
+	struct lcd_device *ld;
+	int ret;
+
+	lcd = kzalloc(sizeof(struct ltv350qv), GFP_KERNEL);
+	if (!lcd)
+		return -ENOMEM;
+
+	lcd->spi = spi;
+	lcd->power = FB_BLANK_POWERDOWN;
+	lcd->buffer = kzalloc(8, GFP_KERNEL);
+
+	ld = lcd_device_register("ltv350qv", &spi->dev, lcd, &ltv_ops);
+	if (IS_ERR(ld)) {
+		ret = PTR_ERR(ld);
+		goto out_free_lcd;
+	}
+	lcd->ld = ld;
+
+	ret = ltv350qv_power(lcd, FB_BLANK_UNBLANK);
+	if (ret)
+		goto out_unregister;
+
+	dev_set_drvdata(&spi->dev, lcd);
+
+	return 0;
+
+out_unregister:
+	lcd_device_unregister(ld);
+out_free_lcd:
+	kfree(lcd);
+	return ret;
+}
+
+static int __devexit ltv350qv_remove(struct spi_device *spi)
+{
+	struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+
+	ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
+	lcd_device_unregister(lcd->ld);
+	kfree(lcd);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int ltv350qv_suspend(struct spi_device *spi, pm_message_t state)
+{
+	struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+
+	return ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static int ltv350qv_resume(struct spi_device *spi)
+{
+	struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+
+	return ltv350qv_power(lcd, FB_BLANK_UNBLANK);
+}
+#else
+#define ltv350qv_suspend	NULL
+#define ltv350qv_resume		NULL
+#endif
+
+/* Power down all displays on reboot, poweroff or halt */
+static void ltv350qv_shutdown(struct spi_device *spi)
+{
+	struct ltv350qv *lcd = dev_get_drvdata(&spi->dev);
+
+	ltv350qv_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static struct spi_driver ltv350qv_driver = {
+	.driver = {
+		.name		= "ltv350qv",
+		.bus		= &spi_bus_type,
+		.owner		= THIS_MODULE,
+	},
+
+	.probe		= ltv350qv_probe,
+	.remove		= __devexit_p(ltv350qv_remove),
+	.shutdown	= ltv350qv_shutdown,
+	.suspend	= ltv350qv_suspend,
+	.resume		= ltv350qv_resume,
+};
+
+static int __init ltv350qv_init(void)
+{
+	return spi_register_driver(&ltv350qv_driver);
+}
+
+static void __exit ltv350qv_exit(void)
+{
+	spi_unregister_driver(&ltv350qv_driver);
+}
+module_init(ltv350qv_init);
+module_exit(ltv350qv_exit);
+
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_DESCRIPTION("Samsung LTV350QV LCD Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/ltv350qv.h b/drivers/video/backlight/ltv350qv.h
new file mode 100644
index 0000000..189112e
--- /dev/null
+++ b/drivers/video/backlight/ltv350qv.h
@@ -0,0 +1,95 @@
+/*
+ * Register definitions for Samsung LTV350QV Quarter VGA LCD Panel
+ *
+ * Copyright (C) 2006, 2007 Atmel 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.
+ */
+#ifndef __LTV350QV_H
+#define __LTV350QV_H
+
+#define LTV_OPC_INDEX	0x74
+#define LTV_OPC_DATA	0x76
+
+#define LTV_ID		0x00		/* ID Read */
+#define LTV_IFCTL	0x01		/* Display Interface Control */
+#define LTV_DATACTL	0x02		/* Display Data Control */
+#define LTV_ENTRY_MODE	0x03		/* Entry Mode */
+#define LTV_GATECTL1	0x04		/* Gate Control 1 */
+#define LTV_GATECTL2	0x05		/* Gate Control 2 */
+#define LTV_VBP		0x06		/* Vertical Back Porch */
+#define LTV_HBP		0x07		/* Horizontal Back Porch */
+#define LTV_SOTCTL	0x08		/* Source Output Timing Control */
+#define LTV_PWRCTL1	0x09		/* Power Control 1 */
+#define LTV_PWRCTL2	0x0a		/* Power Control 2 */
+#define LTV_GAMMA(x)	(0x10 + (x))	/* Gamma control */
+
+/* Bit definitions for LTV_IFCTL */
+#define LTV_IM			(1 << 15)
+#define LTV_NMD			(1 << 14)
+#define LTV_SSMD		(1 << 13)
+#define LTV_REV			(1 <<  7)
+#define LTV_NL(x)		(((x) & 0x001f) << 0)
+
+/* Bit definitions for LTV_DATACTL */
+#define LTV_DS_SAME		(0 << 12)
+#define LTV_DS_D_TO_S		(1 << 12)
+#define LTV_DS_S_TO_D		(2 << 12)
+#define LTV_CHS_384		(0 <<  9)
+#define LTV_CHS_480		(1 <<  9)
+#define LTV_CHS_492		(2 <<  9)
+#define LTV_DF_RGB		(0 <<  6)
+#define LTV_DF_RGBX		(1 <<  6)
+#define LTV_DF_XRGB		(2 <<  6)
+#define LTV_RGB_RGB		(0 <<  2)
+#define LTV_RGB_BGR		(1 <<  2)
+#define LTV_RGB_GRB		(2 <<  2)
+#define LTV_RGB_RBG		(3 <<  2)
+
+/* Bit definitions for LTV_ENTRY_MODE */
+#define LTV_VSPL_ACTIVE_LOW	(0 << 15)
+#define LTV_VSPL_ACTIVE_HIGH	(1 << 15)
+#define LTV_HSPL_ACTIVE_LOW	(0 << 14)
+#define LTV_HSPL_ACTIVE_HIGH	(1 << 14)
+#define LTV_DPL_SAMPLE_RISING	(0 << 13)
+#define LTV_DPL_SAMPLE_FALLING	(1 << 13)
+#define LTV_EPL_ACTIVE_LOW	(0 << 12)
+#define LTV_EPL_ACTIVE_HIGH	(1 << 12)
+#define LTV_SS_LEFT_TO_RIGHT	(0 <<  8)
+#define LTV_SS_RIGHT_TO_LEFT	(1 <<  8)
+#define LTV_STB			(1 <<  1)
+
+/* Bit definitions for LTV_GATECTL1 */
+#define LTV_CLW(x)		(((x) & 0x0007) << 12)
+#define LTV_GAON		(1 <<  5)
+#define LTV_SDR			(1 <<  3)
+
+/* Bit definitions for LTV_GATECTL2 */
+#define LTV_NW_INV_FRAME	(0 << 14)
+#define LTV_NW_INV_1LINE	(1 << 14)
+#define LTV_NW_INV_2LINE	(2 << 14)
+#define LTV_DSC			(1 << 12)
+#define LTV_GIF			(1 <<  8)
+#define LTV_FHN			(1 <<  7)
+#define LTV_FTI(x)		(((x) & 0x0003) << 4)
+#define LTV_FWI(x)		(((x) & 0x0003) << 0)
+
+/* Bit definitions for LTV_SOTCTL */
+#define LTV_SDT(x)		(((x) & 0x0007) << 10)
+#define LTV_EQ(x)		(((x) & 0x0007) <<  2)
+
+/* Bit definitions for LTV_PWRCTL1 */
+#define LTV_VCOM_DISABLE	(1 << 14)
+#define LTV_VCOMOUT_ENABLE	(1 << 11)
+#define LTV_POWER_ON		(1 <<  9)
+#define LTV_DRIVE_CURRENT(x)	(((x) & 0x0007) << 4)	/* 0=off, 5=max */
+#define LTV_SUPPLY_CURRENT(x)	(((x) & 0x0007) << 0)	/* 0=off, 5=max */
+
+/* Bit definitions for LTV_PWRCTL2 */
+#define LTV_VCOML_ENABLE	(1 << 13)
+#define LTV_VCOML_VOLTAGE(x)	(((x) & 0x001f) << 8)	/* 0=1V, 31=-1V */
+#define LTV_VCOMH_VOLTAGE(x)	(((x) & 0x001f) << 0)	/* 0=3V, 31=4.5V */
+
+#endif /* __LTV350QV_H */
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
index b0b2e40..833b10c 100644
--- a/drivers/video/bw2.c
+++ b/drivers/video/bw2.c
@@ -233,9 +233,9 @@
 	0x10, 0x20,	0
 };
 
-static void __devinit bw2_do_default_mode(struct bw2_par *par,
-					  struct fb_info *info,
-					  int *linebytes)
+static int __devinit bw2_do_default_mode(struct bw2_par *par,
+					 struct fb_info *info,
+					 int *linebytes)
 {
 	u8 status, mon;
 	u8 *p;
@@ -266,103 +266,108 @@
 		break;
 
 	case BWTWO_SR_ID_NOCONN:
-		return;
+		return 0;
 
 	default:
-		prom_printf("bw2: can't handle SR %02x\n",
-			    status);
-		prom_halt();
+		printk(KERN_ERR "bw2: can't handle SR %02x\n",
+		       status);
+		return -EINVAL;
 	}
 	for ( ; *p; p += 2) {
 		u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];
 		sbus_writeb(p[1], regp);
 	}
-}
-
-struct all_info {
-	struct fb_info info;
-	struct bw2_par par;
-};
-
-static int __devinit bw2_init_one(struct of_device *op)
-{
-	struct device_node *dp = op->node;
-	struct all_info *all;
-	int linebytes, err;
-
-	all = kzalloc(sizeof(*all), GFP_KERNEL);
-	if (!all)
-		return -ENOMEM;
-
-	spin_lock_init(&all->par.lock);
-
-	all->par.physbase = op->resource[0].start;
-	all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
-
-	sbusfb_fill_var(&all->info.var, dp->node, 1);
-	linebytes = of_getintprop_default(dp, "linebytes",
-					  all->info.var.xres);
-
-	all->info.var.red.length = all->info.var.green.length =
-		all->info.var.blue.length = all->info.var.bits_per_pixel;
-	all->info.var.red.offset = all->info.var.green.offset =
-		all->info.var.blue.offset = 0;
-
-	all->par.regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET,
-				   sizeof(struct bw2_regs), "bw2 regs");
-
-	if (!of_find_property(dp, "width", NULL))
-		bw2_do_default_mode(&all->par, &all->info, &linebytes);
-
-	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
-
-	all->info.flags = FBINFO_DEFAULT;
-	all->info.fbops = &bw2_ops;
-
-	all->info.screen_base =
-		of_ioremap(&op->resource[0], 0, all->par.fbsize, "bw2 ram");
-	all->info.par = &all->par;
-
-	bw2_blank(0, &all->info);
-
-	bw2_init_fix(&all->info, linebytes);
-
-	err= register_framebuffer(&all->info);
-	if (err < 0) {
-		of_iounmap(&op->resource[0],
-			   all->par.regs, sizeof(struct bw2_regs));
-		of_iounmap(&op->resource[0],
-			   all->info.screen_base, all->par.fbsize);
-		kfree(all);
-		return err;
-	}
-
-	dev_set_drvdata(&op->dev, all);
-
-	printk("%s: bwtwo at %lx:%lx\n",
-	       dp->full_name,
-	       all->par.which_io, all->par.physbase);
-
 	return 0;
 }
 
-static int __devinit bw2_probe(struct of_device *dev, const struct of_device_id *match)
+static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *match)
 {
-	struct of_device *op = to_of_device(&dev->dev);
+	struct device_node *dp = op->node;
+	struct fb_info *info;
+	struct bw2_par *par;
+	int linebytes, err;
 
-	return bw2_init_one(op);
+	info = framebuffer_alloc(sizeof(struct bw2_par), &op->dev);
+
+	err = -ENOMEM;
+	if (!info)
+		goto out_err;
+	par = info->par;
+
+	spin_lock_init(&par->lock);
+
+	par->physbase = op->resource[0].start;
+	par->which_io = op->resource[0].flags & IORESOURCE_BITS;
+
+	sbusfb_fill_var(&info->var, dp->node, 1);
+	linebytes = of_getintprop_default(dp, "linebytes",
+					  info->var.xres);
+
+	info->var.red.length = info->var.green.length =
+		info->var.blue.length = info->var.bits_per_pixel;
+	info->var.red.offset = info->var.green.offset =
+		info->var.blue.offset = 0;
+
+	par->regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET,
+			       sizeof(struct bw2_regs), "bw2 regs");
+	if (!par->regs)
+		goto out_release_fb;
+
+	if (!of_find_property(dp, "width", NULL)) {
+		err = bw2_do_default_mode(par, info, &linebytes);
+		if (err)
+			goto out_unmap_regs;
+	}
+
+	par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
+
+	info->flags = FBINFO_DEFAULT;
+	info->fbops = &bw2_ops;
+
+	info->screen_base = of_ioremap(&op->resource[0], 0,
+				       par->fbsize, "bw2 ram");
+	if (!info->screen_base)
+		goto out_unmap_regs;
+
+	bw2_blank(0, info);
+
+	bw2_init_fix(info, linebytes);
+
+	err = register_framebuffer(info);
+	if (err < 0)
+		goto out_unmap_screen;
+
+	dev_set_drvdata(&op->dev, info);
+
+	printk("%s: bwtwo at %lx:%lx\n",
+	       dp->full_name, par->which_io, par->physbase);
+
+	return 0;
+
+out_unmap_screen:
+	of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
+
+out_unmap_regs:
+	of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
+
+out_release_fb:
+	framebuffer_release(info);
+
+out_err:
+	return err;
 }
 
 static int __devexit bw2_remove(struct of_device *op)
 {
-	struct all_info *all = dev_get_drvdata(&op->dev);
+	struct fb_info *info = dev_get_drvdata(&op->dev);
+	struct bw2_par *par = info->par;
 
-	unregister_framebuffer(&all->info);
+	unregister_framebuffer(info);
 
-	of_iounmap(&op->resource[0], all->par.regs, sizeof(struct bw2_regs));
-	of_iounmap(&op->resource[0], all->info.screen_base, all->par.fbsize);
+	of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
+	of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
 
-	kfree(all);
+	framebuffer_release(info);
 
 	dev_set_drvdata(&op->dev, NULL);
 
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c
index b071bb6..41f6dbf 100644
--- a/drivers/video/cg14.c
+++ b/drivers/video/cg14.c
@@ -448,81 +448,79 @@
 	{ .size = 0 }
 };
 
-struct all_info {
-	struct fb_info info;
-	struct cg14_par par;
-};
-
-static void cg14_unmap_regs(struct of_device *op, struct all_info *all)
+static void cg14_unmap_regs(struct of_device *op, struct fb_info *info,
+			    struct cg14_par *par)
 {
-	if (all->par.regs)
+	if (par->regs)
 		of_iounmap(&op->resource[0],
-			   all->par.regs, sizeof(struct cg14_regs));
-	if (all->par.clut)
+			   par->regs, sizeof(struct cg14_regs));
+	if (par->clut)
 		of_iounmap(&op->resource[0],
-			   all->par.clut, sizeof(struct cg14_clut));
-	if (all->par.cursor)
+			   par->clut, sizeof(struct cg14_clut));
+	if (par->cursor)
 		of_iounmap(&op->resource[0],
-			   all->par.cursor, sizeof(struct cg14_cursor));
-	if (all->info.screen_base)
+			   par->cursor, sizeof(struct cg14_cursor));
+	if (info->screen_base)
 		of_iounmap(&op->resource[1],
-			   all->info.screen_base, all->par.fbsize);
+			   info->screen_base, par->fbsize);
 }
 
-static int __devinit cg14_init_one(struct of_device *op)
+static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match)
 {
 	struct device_node *dp = op->node;
-	struct all_info *all;
+	struct fb_info *info;
+	struct cg14_par *par;
 	int is_8mb, linebytes, i, err;
 
-	all = kzalloc(sizeof(*all), GFP_KERNEL);
-	if (!all)
-		return -ENOMEM;
+	info = framebuffer_alloc(sizeof(struct cg14_par), &op->dev);
 
-	spin_lock_init(&all->par.lock);
+	err = -ENOMEM;
+	if (!info)
+		goto out_err;
+	par = info->par;
 
-	sbusfb_fill_var(&all->info.var, dp->node, 8);
-	all->info.var.red.length = 8;
-	all->info.var.green.length = 8;
-	all->info.var.blue.length = 8;
+	spin_lock_init(&par->lock);
+
+	sbusfb_fill_var(&info->var, dp->node, 8);
+	info->var.red.length = 8;
+	info->var.green.length = 8;
+	info->var.blue.length = 8;
 
 	linebytes = of_getintprop_default(dp, "linebytes",
-					  all->info.var.xres);
-	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+					  info->var.xres);
+	par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
 
 	if (!strcmp(dp->parent->name, "sbus") ||
 	    !strcmp(dp->parent->name, "sbi")) {
-		all->par.physbase = op->resource[0].start;
-		all->par.iospace = op->resource[0].flags & IORESOURCE_BITS;
+		par->physbase = op->resource[0].start;
+		par->iospace = op->resource[0].flags & IORESOURCE_BITS;
 	} else {
-		all->par.physbase = op->resource[1].start;
-		all->par.iospace = op->resource[0].flags & IORESOURCE_BITS;
+		par->physbase = op->resource[1].start;
+		par->iospace = op->resource[0].flags & IORESOURCE_BITS;
 	}
 
-	all->par.regs = of_ioremap(&op->resource[0], 0,
-				   sizeof(struct cg14_regs), "cg14 regs");
-	all->par.clut = of_ioremap(&op->resource[0], CG14_CLUT1,
-				   sizeof(struct cg14_clut), "cg14 clut");
-	all->par.cursor = of_ioremap(&op->resource[0], CG14_CURSORREGS,
-				   sizeof(struct cg14_cursor), "cg14 cursor");
+	par->regs = of_ioremap(&op->resource[0], 0,
+			       sizeof(struct cg14_regs), "cg14 regs");
+	par->clut = of_ioremap(&op->resource[0], CG14_CLUT1,
+			       sizeof(struct cg14_clut), "cg14 clut");
+	par->cursor = of_ioremap(&op->resource[0], CG14_CURSORREGS,
+				 sizeof(struct cg14_cursor), "cg14 cursor");
 
-	all->info.screen_base = of_ioremap(&op->resource[1], 0,
-					   all->par.fbsize, "cg14 ram");
+	info->screen_base = of_ioremap(&op->resource[1], 0,
+				       par->fbsize, "cg14 ram");
 
-	if (!all->par.regs || !all->par.clut || !all->par.cursor ||
-	    !all->info.screen_base)
-		cg14_unmap_regs(op, all);
+	if (!par->regs || !par->clut || !par->cursor || !info->screen_base)
+		goto out_unmap_regs;
 
 	is_8mb = (((op->resource[1].end - op->resource[1].start) + 1) ==
 		  (8 * 1024 * 1024));
 
-	BUILD_BUG_ON(sizeof(all->par.mmap_map) != sizeof(__cg14_mmap_map));
+	BUILD_BUG_ON(sizeof(par->mmap_map) != sizeof(__cg14_mmap_map));
 		
-	memcpy(&all->par.mmap_map, &__cg14_mmap_map,
-	       sizeof(all->par.mmap_map));
+	memcpy(&par->mmap_map, &__cg14_mmap_map, sizeof(par->mmap_map));
 
 	for (i = 0; i < CG14_MMAP_ENTRIES; i++) {
-		struct sbus_mmap_map *map = &all->par.mmap_map[i];
+		struct sbus_mmap_map *map = &par->mmap_map[i];
 
 		if (!map->size)
 			break;
@@ -536,59 +534,55 @@
 			map->size *= 2;
 	}
 
-	all->par.mode = MDI_8_PIX;
-	all->par.ramsize = (is_8mb ? 0x800000 : 0x400000);
+	par->mode = MDI_8_PIX;
+	par->ramsize = (is_8mb ? 0x800000 : 0x400000);
 
-	all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
-	all->info.fbops = &cg14_ops;
-	all->info.par = &all->par;
+	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+	info->fbops = &cg14_ops;
 
-	__cg14_reset(&all->par);
+	__cg14_reset(par);
 
-	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
-		cg14_unmap_regs(op, all);
-		kfree(all);
-		return -ENOMEM;
-	}
-	fb_set_cmap(&all->info.cmap, &all->info);
+	if (fb_alloc_cmap(&info->cmap, 256, 0))
+		goto out_unmap_regs;
 
-	cg14_init_fix(&all->info, linebytes, dp);
+	fb_set_cmap(&info->cmap, info);
 
-	err = register_framebuffer(&all->info);
-	if (err < 0) {
-		fb_dealloc_cmap(&all->info.cmap);
-		cg14_unmap_regs(op, all);
-		kfree(all);
-		return err;
-	}
+	cg14_init_fix(info, linebytes, dp);
 
-	dev_set_drvdata(&op->dev, all);
+	err = register_framebuffer(info);
+	if (err < 0)
+		goto out_dealloc_cmap;
+
+	dev_set_drvdata(&op->dev, info);
 
 	printk("%s: cgfourteen at %lx:%lx, %dMB\n",
 	       dp->full_name,
-	       all->par.iospace, all->par.physbase,
-	       all->par.ramsize >> 20);
+	       par->iospace, par->physbase,
+	       par->ramsize >> 20);
 
 	return 0;
-}
 
-static int __devinit cg14_probe(struct of_device *dev, const struct of_device_id *match)
-{
-	struct of_device *op = to_of_device(&dev->dev);
+out_dealloc_cmap:
+	fb_dealloc_cmap(&info->cmap);
 
-	return cg14_init_one(op);
+out_unmap_regs:
+	cg14_unmap_regs(op, info, par);
+
+out_err:
+	return err;
 }
 
 static int __devexit cg14_remove(struct of_device *op)
 {
-	struct all_info *all = dev_get_drvdata(&op->dev);
+	struct fb_info *info = dev_get_drvdata(&op->dev);
+	struct cg14_par *par = info->par;
 
-	unregister_framebuffer(&all->info);
-	fb_dealloc_cmap(&all->info.cmap);
+	unregister_framebuffer(info);
+	fb_dealloc_cmap(&info->cmap);
 
-	cg14_unmap_regs(op, all);
+	cg14_unmap_regs(op, info, par);
 
-	kfree(all);
+	framebuffer_release(info);
 
 	dev_set_drvdata(&op->dev, NULL);
 
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index f042428..a5c7fb3 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -315,7 +315,7 @@
 	4, 0xff,	5, 0x00,	6, 0x70,	7, 0x00,	0
 };
 
-static void __devinit cg3_do_default_mode(struct cg3_par *par)
+static int __devinit cg3_do_default_mode(struct cg3_par *par)
 {
 	enum cg3_type type;
 	u8 *p;
@@ -332,10 +332,9 @@
 			else
 				type = CG3_AT_66HZ;
 		} else {
-			prom_printf("cgthree: can't handle SR %02x\n",
-				    status);
-			prom_halt();
-			return;
+			printk(KERN_ERR "cgthree: can't handle SR %02x\n",
+			       status);
+			return -EINVAL;
 		}
 	}
 
@@ -351,106 +350,108 @@
 		regp = (u8 __iomem *)&par->regs->cmap.control;
 		sbus_writeb(p[1], regp);
 	}
-}
-
-struct all_info {
-	struct fb_info info;
-	struct cg3_par par;
-};
-
-static int __devinit cg3_init_one(struct of_device *op)
-{
-	struct device_node *dp = op->node;
-	struct all_info *all;
-	int linebytes, err;
-
-	all = kzalloc(sizeof(*all), GFP_KERNEL);
-	if (!all)
-		return -ENOMEM;
-
-	spin_lock_init(&all->par.lock);
-
-	all->par.physbase = op->resource[0].start;
-	all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
-
-	sbusfb_fill_var(&all->info.var, dp->node, 8);
-	all->info.var.red.length = 8;
-	all->info.var.green.length = 8;
-	all->info.var.blue.length = 8;
-	if (!strcmp(dp->name, "cgRDI"))
-		all->par.flags |= CG3_FLAG_RDI;
-	if (all->par.flags & CG3_FLAG_RDI)
-		cg3_rdi_maybe_fixup_var(&all->info.var, dp);
-
-	linebytes = of_getintprop_default(dp, "linebytes",
-					  all->info.var.xres);
-	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
-
-	all->par.regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET,
-				   sizeof(struct cg3_regs), "cg3 regs");
-
-	all->info.flags = FBINFO_DEFAULT;
-	all->info.fbops = &cg3_ops;
-	all->info.screen_base =
-		of_ioremap(&op->resource[0], CG3_RAM_OFFSET,
-			   all->par.fbsize, "cg3 ram");
-	all->info.par = &all->par;
-
-	cg3_blank(0, &all->info);
-
-	if (!of_find_property(dp, "width", NULL))
-		cg3_do_default_mode(&all->par);
-
-	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
-		of_iounmap(&op->resource[0],
-			   all->par.regs, sizeof(struct cg3_regs));
-		of_iounmap(&op->resource[0],
-			   all->info.screen_base, all->par.fbsize);
-		kfree(all);
-		return -ENOMEM;
-	}
-	fb_set_cmap(&all->info.cmap, &all->info);
-
-	cg3_init_fix(&all->info, linebytes, dp);
-
-	err = register_framebuffer(&all->info);
-	if (err < 0) {
-		fb_dealloc_cmap(&all->info.cmap);
-		of_iounmap(&op->resource[0],
-			   all->par.regs, sizeof(struct cg3_regs));
-		of_iounmap(&op->resource[0],
-			   all->info.screen_base, all->par.fbsize);
-		kfree(all);
-		return err;
-	}
-
-	dev_set_drvdata(&op->dev, all);
-
-	printk("%s: cg3 at %lx:%lx\n",
-	       dp->full_name, all->par.which_io, all->par.physbase);
-
 	return 0;
 }
 
-static int __devinit cg3_probe(struct of_device *dev,
+static int __devinit cg3_probe(struct of_device *op,
 			       const struct of_device_id *match)
 {
-	struct of_device *op = to_of_device(&dev->dev);
+	struct device_node *dp = op->node;
+	struct fb_info *info;
+	struct cg3_par *par;
+	int linebytes, err;
 
-	return cg3_init_one(op);
+	info = framebuffer_alloc(sizeof(struct cg3_par), &op->dev);
+
+	err = -ENOMEM;
+	if (!info)
+		goto out_err;
+	par = info->par;
+
+	spin_lock_init(&par->lock);
+
+	par->physbase = op->resource[0].start;
+	par->which_io = op->resource[0].flags & IORESOURCE_BITS;
+
+	sbusfb_fill_var(&info->var, dp->node, 8);
+	info->var.red.length = 8;
+	info->var.green.length = 8;
+	info->var.blue.length = 8;
+	if (!strcmp(dp->name, "cgRDI"))
+		par->flags |= CG3_FLAG_RDI;
+	if (par->flags & CG3_FLAG_RDI)
+		cg3_rdi_maybe_fixup_var(&info->var, dp);
+
+	linebytes = of_getintprop_default(dp, "linebytes",
+					  info->var.xres);
+	par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
+
+	par->regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET,
+			       sizeof(struct cg3_regs), "cg3 regs");
+	if (!par->regs)
+		goto out_release_fb;
+
+	info->flags = FBINFO_DEFAULT;
+	info->fbops = &cg3_ops;
+	info->screen_base = of_ioremap(&op->resource[0], CG3_RAM_OFFSET,
+				       par->fbsize, "cg3 ram");
+	if (!info->screen_base)
+		goto out_unmap_regs;
+
+	cg3_blank(0, info);
+
+	if (!of_find_property(dp, "width", NULL)) {
+		err = cg3_do_default_mode(par);
+		if (err)
+			goto out_unmap_screen;
+	}
+
+	if (fb_alloc_cmap(&info->cmap, 256, 0))
+		goto out_unmap_screen;
+
+	fb_set_cmap(&info->cmap, info);
+
+	cg3_init_fix(info, linebytes, dp);
+
+	err = register_framebuffer(info);
+	if (err < 0)
+		goto out_dealloc_cmap;
+
+	dev_set_drvdata(&op->dev, info);
+
+	printk("%s: cg3 at %lx:%lx\n",
+	       dp->full_name, par->which_io, par->physbase);
+
+	return 0;
+
+out_dealloc_cmap:
+	fb_dealloc_cmap(&info->cmap);
+
+out_unmap_screen:
+	of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
+
+out_unmap_regs:
+	of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));
+
+out_release_fb:
+	framebuffer_release(info);
+
+out_err:
+	return err;
 }
 
 static int __devexit cg3_remove(struct of_device *op)
 {
-	struct all_info *all = dev_get_drvdata(&op->dev);
+	struct fb_info *info = dev_get_drvdata(&op->dev);
+	struct cg3_par *par = info->par;
 
-	unregister_framebuffer(&all->info);
-	fb_dealloc_cmap(&all->info.cmap);
+	unregister_framebuffer(info);
+	fb_dealloc_cmap(&info->cmap);
 
-	of_iounmap(&op->resource[0], all->par.regs, sizeof(struct cg3_regs));
-	of_iounmap(&op->resource[0], all->info.screen_base, all->par.fbsize);
+	of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));
+	of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
 
-	kfree(all);
+	framebuffer_release(info);
 
 	dev_set_drvdata(&op->dev, NULL);
 
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c
index 4dad23a..ee9046d 100644
--- a/drivers/video/cg6.c
+++ b/drivers/video/cg6.c
@@ -653,135 +653,123 @@
 	sbus_writel(info->var.yres - 1, &fbc->clipmaxy);
 }
 
-struct all_info {
-	struct fb_info info;
-	struct cg6_par par;
-};
-
-static void cg6_unmap_regs(struct of_device *op, struct all_info *all)
+static void cg6_unmap_regs(struct of_device *op, struct fb_info *info,
+			   struct cg6_par *par)
 {
-	if (all->par.fbc)
-		of_iounmap(&op->resource[0], all->par.fbc, 4096);
-	if (all->par.tec)
-		of_iounmap(&op->resource[0],
-			   all->par.tec, sizeof(struct cg6_tec));
-	if (all->par.thc)
-		of_iounmap(&op->resource[0],
-			   all->par.thc, sizeof(struct cg6_thc));
-	if (all->par.bt)
-		of_iounmap(&op->resource[0],
-			   all->par.bt, sizeof(struct bt_regs));
-	if (all->par.fhc)
-		of_iounmap(&op->resource[0],
-			   all->par.fhc, sizeof(u32));
+	if (par->fbc)
+		of_iounmap(&op->resource[0], par->fbc, 4096);
+	if (par->tec)
+		of_iounmap(&op->resource[0], par->tec, sizeof(struct cg6_tec));
+	if (par->thc)
+		of_iounmap(&op->resource[0], par->thc, sizeof(struct cg6_thc));
+	if (par->bt)
+		of_iounmap(&op->resource[0], par->bt, sizeof(struct bt_regs));
+	if (par->fhc)
+		of_iounmap(&op->resource[0], par->fhc, sizeof(u32));
 
-	if (all->info.screen_base)
-		of_iounmap(&op->resource[0],
-			   all->info.screen_base, all->par.fbsize);
+	if (info->screen_base)
+		of_iounmap(&op->resource[0], info->screen_base, par->fbsize);
 }
 
-static int __devinit cg6_init_one(struct of_device *op)
+static int __devinit cg6_probe(struct of_device *op, const struct of_device_id *match)
 {
 	struct device_node *dp = op->node;
-	struct all_info *all;
+	struct fb_info *info;
+	struct cg6_par *par;
 	int linebytes, err;
+	int dblbuf;
 
-	all = kzalloc(sizeof(*all), GFP_KERNEL);
-	if (!all)
-		return -ENOMEM;
+	info = framebuffer_alloc(sizeof(struct cg6_par), &op->dev);
 
-	spin_lock_init(&all->par.lock);
+	err = -ENOMEM;
+	if (!info)
+		goto out_err;
+	par = info->par;
 
-	all->par.physbase = op->resource[0].start;
-	all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
+	spin_lock_init(&par->lock);
 
-	sbusfb_fill_var(&all->info.var, dp->node, 8);
-	all->info.var.red.length = 8;
-	all->info.var.green.length = 8;
-	all->info.var.blue.length = 8;
+	par->physbase = op->resource[0].start;
+	par->which_io = op->resource[0].flags & IORESOURCE_BITS;
+
+	sbusfb_fill_var(&info->var, dp->node, 8);
+	info->var.red.length = 8;
+	info->var.green.length = 8;
+	info->var.blue.length = 8;
 
 	linebytes = of_getintprop_default(dp, "linebytes",
-					  all->info.var.xres);
-	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
-	if (of_find_property(dp, "dblbuf", NULL))
-		all->par.fbsize *= 4;
+					  info->var.xres);
+	par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
 
-	all->par.fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET,
+	dblbuf = of_getintprop_default(dp, "dblbuf", 0);
+	if (dblbuf)
+		par->fbsize *= 4;
+
+	par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET,
 				  4096, "cgsix fbc");
-	all->par.tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET,
+	par->tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET,
 				  sizeof(struct cg6_tec), "cgsix tec");
-	all->par.thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET,
+	par->thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET,
 				  sizeof(struct cg6_thc), "cgsix thc");
-	all->par.bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET,
+	par->bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET,
 				 sizeof(struct bt_regs), "cgsix dac");
-	all->par.fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET,
+	par->fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET,
 				  sizeof(u32), "cgsix fhc");
 
-	all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT |
+	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT |
                           FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
-	all->info.fbops = &cg6_ops;
+	info->fbops = &cg6_ops;
 
-	all->info.screen_base =  of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
-					    all->par.fbsize, "cgsix ram");
-	if (!all->par.fbc || !all->par.tec || !all->par.thc ||
-	    !all->par.bt || !all->par.fhc || !all->info.screen_base) {
-		cg6_unmap_regs(op, all);
-		kfree(all);
-		return -ENOMEM;
-	}
+	info->screen_base =  of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
+					    par->fbsize, "cgsix ram");
+	if (!par->fbc || !par->tec || !par->thc ||
+	    !par->bt || !par->fhc || !info->screen_base)
+		goto out_unmap_regs;
 
-	all->info.par = &all->par;
+	info->var.accel_flags = FB_ACCELF_TEXT;
 
-	all->info.var.accel_flags = FB_ACCELF_TEXT;
+	cg6_bt_init(par);
+	cg6_chip_init(info);
+	cg6_blank(0, info);
 
-	cg6_bt_init(&all->par);
-	cg6_chip_init(&all->info);
-	cg6_blank(0, &all->info);
+	if (fb_alloc_cmap(&info->cmap, 256, 0))
+		goto out_unmap_regs;
 
-	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
-		cg6_unmap_regs(op, all);
-		kfree(all);
-		return -ENOMEM;
-	}
+	fb_set_cmap(&info->cmap, info);
+	cg6_init_fix(info, linebytes);
 
-	fb_set_cmap(&all->info.cmap, &all->info);
-	cg6_init_fix(&all->info, linebytes);
+	err = register_framebuffer(info);
+	if (err < 0)
+		goto out_dealloc_cmap;
 
-	err = register_framebuffer(&all->info);
-	if (err < 0) {
-		cg6_unmap_regs(op, all);
-		fb_dealloc_cmap(&all->info.cmap);
-		kfree(all);
-		return err;
-	}
-
-	dev_set_drvdata(&op->dev, all);
+	dev_set_drvdata(&op->dev, info);
 
 	printk("%s: CGsix [%s] at %lx:%lx\n",
-	       dp->full_name,
-	       all->info.fix.id,
-	       all->par.which_io, all->par.physbase);
+	       dp->full_name, info->fix.id,
+	       par->which_io, par->physbase);
 
 	return 0;
-}
 
-static int __devinit cg6_probe(struct of_device *dev, const struct of_device_id *match)
-{
-	struct of_device *op = to_of_device(&dev->dev);
+out_dealloc_cmap:
+	fb_dealloc_cmap(&info->cmap);
 
-	return cg6_init_one(op);
+out_unmap_regs:
+	cg6_unmap_regs(op, info, par);
+
+out_err:
+	return err;
 }
 
 static int __devexit cg6_remove(struct of_device *op)
 {
-	struct all_info *all = dev_get_drvdata(&op->dev);
+	struct fb_info *info = dev_get_drvdata(&op->dev);
+	struct cg6_par *par = info->par;
 
-	unregister_framebuffer(&all->info);
-	fb_dealloc_cmap(&all->info.cmap);
+	unregister_framebuffer(info);
+	fb_dealloc_cmap(&info->cmap);
 
-	cg6_unmap_regs(op, all);
+	cg6_unmap_regs(op, info, par);
 
-	kfree(all);
+	framebuffer_release(info);
 
 	dev_set_drvdata(&op->dev, NULL);
 
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
index f48e8c5..6796ba6 100644
--- a/drivers/video/chipsfb.c
+++ b/drivers/video/chipsfb.c
@@ -24,6 +24,7 @@
 #include <linux/delay.h>
 #include <linux/interrupt.h>
 #include <linux/fb.h>
+#include <linux/pm.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/console.h>
@@ -458,7 +459,7 @@
 
 	if (state.event == pdev->dev.power.power_state.event)
 		return 0;
-	if (state.event != PM_SUSPEND_MEM)
+	if (state.event != PM_EVENT_SUSPEND)
 		goto done;
 
 	acquire_console_sem();
diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c
index 50b78af..dea6579 100644
--- a/drivers/video/clps711xfb.c
+++ b/drivers/video/clps711xfb.c
@@ -366,11 +366,10 @@
 	if (fb_get_options("clps711xfb", NULL))
 		return -ENODEV;
 
-	cfb = kmalloc(sizeof(*cfb), GFP_KERNEL);
+	cfb = kzalloc(sizeof(*cfb), GFP_KERNEL);
 	if (!cfb)
 		goto out;
 
-	memset(cfb, 0, sizeof(*cfb));
 	strcpy(cfb->fix.id, "clps711x");
 
 	cfb->fbops		= &clps7111fb_ops;
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 4964396..a22ccf9 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -145,7 +145,7 @@
          oriented.
 
 config STI_CONSOLE
-        tristate "STI text console" 
+        bool "STI text console"
         depends on PARISC
         default y
         help
@@ -182,7 +182,7 @@
 
 config FONT_8x16
 	bool "VGA 8x16 font" if FONTS
-	depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE=y || STI_CONSOLE || USB_SISUSBVGA_CON 
+	depends on FRAMEBUFFER_CONSOLE || SGI_NEWPORT_CONSOLE || STI_CONSOLE || USB_SISUSBVGA_CON
 	default y if !SPARC && !FONTS
 	help
 	  This is the "high resolution" font for the VGA frame buffer (the one
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index decfdc8..e58c87b 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -127,8 +127,20 @@
 static int fbcon_is_default = 1; 
 static int fbcon_has_exited;
 static int primary_device = -1;
+
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
 static int map_override;
 
+static inline void fbcon_map_override(void)
+{
+	map_override = 1;
+}
+#else
+static inline void fbcon_map_override(void)
+{
+}
+#endif /* CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY */
+
 /* font data */
 static char fontname[40];
 
@@ -506,7 +518,7 @@
 						(options[j++]-'0') % FB_MAX;
 				}
 
-				map_override = 1;
+				fbcon_map_override();
 			}
 
 			return 1;
diff --git a/drivers/video/console/fonts.c b/drivers/video/console/fonts.c
index a6828d0..96979c3 100644
--- a/drivers/video/console/fonts.c
+++ b/drivers/video/console/fonts.c
@@ -133,8 +133,8 @@
 	if ((yres < 400) == (f->height <= 8))
 	    c += 1000;
 
-	if (!(font_w & (1 << (f->width - 1))) ||
-	    !(font_w & (1 << (f->height - 1))))
+	if ((font_w & (1 << (f->width - 1))) &&
+	    (font_h & (1 << (f->height - 1))))
 	    c += 1000;
 
 	if (c > cc) {
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index 7fa1afe..dda0586 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -738,9 +738,8 @@
 #ifdef MODULE
 static int __init newport_console_init(void)
 {
-
 	if (!sgi_gfxaddr)
-		return NULL;
+		return 0;
 
 	if (!npregs)
 		npregs = (struct newport_regs *)/* ioremap cannot fail */
diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c
index 870017d4..e9ab657 100644
--- a/drivers/video/console/sticore.c
+++ b/drivers/video/console/sticore.c
@@ -232,18 +232,14 @@
 }
 
 
-/* FIXME: Do we have another solution for this ? */
-static void sti_flush(unsigned long from, unsigned long len)
+static void sti_flush(unsigned long start, unsigned long end)
 {
-	flush_data_cache();
-	flush_kernel_dcache_range(from, len);
-	flush_icache_range(from, from+len);
+	flush_icache_range(start, end);
 }
 
 void __devinit
 sti_rom_copy(unsigned long base, unsigned long count, void *dest)
 {
-	unsigned long dest_len = count;
 	unsigned long dest_start = (unsigned long) dest;
 
 	/* this still needs to be revisited (see arch/parisc/mm/init.c:246) ! */
@@ -260,7 +256,7 @@
 		dest++;
 	}
 
-	sti_flush(dest_start, dest_len);
+	sti_flush(dest_start, (unsigned long)dest);
 }
 
 
@@ -663,7 +659,6 @@
 static void __devinit
 sti_bmode_rom_copy(unsigned long base, unsigned long count, void *dest)
 {
-	unsigned long dest_len = count;
 	unsigned long dest_start = (unsigned long) dest;
 
 	while (count) {
@@ -672,7 +667,8 @@
 		base += 4;
 		dest++;
 	}
-	sti_flush(dest_start, dest_len);
+
+	sti_flush(dest_start, (unsigned long)dest);
 }
 
 static struct sti_rom * __devinit
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index f46fe95..d18b73a 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -187,7 +187,11 @@
 	}
 }
 
-static void vgacon_scrollback_startup(void)
+/*
+ * Called only duing init so call of alloc_bootmen is ok.
+ * Marked __init_refok to silence modpost.
+ */
+static void __init_refok vgacon_scrollback_startup(void)
 {
 	vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE
 					  * 1024);
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
index 7a6eeda..30ede6e 100644
--- a/drivers/video/cyber2000fb.c
+++ b/drivers/video/cyber2000fb.c
@@ -1221,11 +1221,10 @@
 {
 	struct cfb_info *cfb;
 
-	cfb = kmalloc(sizeof(struct cfb_info), GFP_KERNEL);
+	cfb = kzalloc(sizeof(struct cfb_info), GFP_KERNEL);
 	if (!cfb)
 		return NULL;
 
-	memset(cfb, 0, sizeof(struct cfb_info));
 
 	cfb->id			= id;
 
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 215ac57..0740272 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -244,8 +244,17 @@
 	u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0;
 	u8 fg = 1, d;
 
-	if (fb_get_color_depth(&info->var, &info->fix) == 3)
+	switch (fb_get_color_depth(&info->var, &info->fix)) {
+	case 1:
+		fg = 1;
+		break;
+	case 2:
+		fg = 3;
+		break;
+	default:
 		fg = 7;
+		break;
+	}
 
 	if (info->fix.visual == FB_VISUAL_MONO01 ||
 	    info->fix.visual == FB_VISUAL_MONO10)
@@ -564,21 +573,6 @@
 		depth = 4;
 	}
 
-	if (depth >= 8) {
-		switch (info->fix.visual) {
-		case FB_VISUAL_TRUECOLOR:
-			fb_logo.needs_truepalette = 1;
-			break;
-		case FB_VISUAL_DIRECTCOLOR:
-			fb_logo.needs_directpalette = 1;
-			fb_logo.needs_cmapreset = 1;
-			break;
-		case FB_VISUAL_PSEUDOCOLOR:
-			fb_logo.needs_cmapreset = 1;
-			break;
-		}
-	}
-
 	/* Return if no suitable logo was found */
 	fb_logo.logo = fb_find_logo(depth);
 
@@ -604,6 +598,22 @@
 	else
 		fb_logo.depth = 1;
 
+
+ 	if (fb_logo.depth > 4 && depth > 4) {
+ 		switch (info->fix.visual) {
+ 		case FB_VISUAL_TRUECOLOR:
+ 			fb_logo.needs_truepalette = 1;
+ 			break;
+ 		case FB_VISUAL_DIRECTCOLOR:
+ 			fb_logo.needs_directpalette = 1;
+ 			fb_logo.needs_cmapreset = 1;
+ 			break;
+ 		case FB_VISUAL_PSEUDOCOLOR:
+ 			fb_logo.needs_cmapreset = 1;
+ 			break;
+ 		}
+ 	}
+
 	return fb_prepare_extra_logos(info, fb_logo.logo->height, yres);
 }
 
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index 3f6c98f..4b520b5 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -371,6 +371,8 @@
 	unsigned long		fbsize;
 
 	int			board_type;
+
+	u32			pseudo_palette[16];
 };
 
 static void FFBFifo(struct ffb_par *par, int n)
@@ -900,75 +902,67 @@
 	info->fix.accel = FB_ACCEL_SUN_CREATOR;
 }
 
-struct all_info {
-	struct fb_info info;
-	struct ffb_par par;
-	u32 pseudo_palette[16];
-};
-
-static int ffb_init_one(struct of_device *op)
+static int __devinit ffb_probe(struct of_device *op, const struct of_device_id *match)
 {
 	struct device_node *dp = op->node;
 	struct ffb_fbc __iomem *fbc;
 	struct ffb_dac __iomem *dac;
-	struct all_info *all;
-	int err;
+	struct fb_info *info;
+	struct ffb_par *par;
 	u32 dac_pnum, dac_rev, dac_mrev;
+	int err;
 
-	all = kzalloc(sizeof(*all), GFP_KERNEL);
-	if (!all)
-		return -ENOMEM;
+	info = framebuffer_alloc(sizeof(struct ffb_par), &op->dev);
 
-	spin_lock_init(&all->par.lock);
-	all->par.fbc = of_ioremap(&op->resource[2], 0,
-				  sizeof(struct ffb_fbc), "ffb fbc");
-	if (!all->par.fbc) {
-		kfree(all);
-		return -ENOMEM;
-	}
+	err = -ENOMEM;
+	if (!info)
+		goto out_err;
 
-	all->par.dac = of_ioremap(&op->resource[1], 0,
-				  sizeof(struct ffb_dac), "ffb dac");
-	if (!all->par.dac) {
-		of_iounmap(&op->resource[2],
-			   all->par.fbc, sizeof(struct ffb_fbc));
-		kfree(all);
-		return -ENOMEM;
-	}
+	par = info->par;
 
-	all->par.rop_cache = FFB_ROP_NEW;
-	all->par.physbase = op->resource[0].start;
+	spin_lock_init(&par->lock);
+	par->fbc = of_ioremap(&op->resource[2], 0,
+			      sizeof(struct ffb_fbc), "ffb fbc");
+	if (!par->fbc)
+		goto out_release_fb;
+
+	par->dac = of_ioremap(&op->resource[1], 0,
+			      sizeof(struct ffb_dac), "ffb dac");
+	if (!par->dac)
+		goto out_unmap_fbc;
+
+	par->rop_cache = FFB_ROP_NEW;
+	par->physbase = op->resource[0].start;
 
 	/* Don't mention copyarea, so SCROLL_REDRAW is always
 	 * used.  It is the fastest on this chip.
 	 */
-	all->info.flags = (FBINFO_DEFAULT |
-			   /* FBINFO_HWACCEL_COPYAREA | */
-			   FBINFO_HWACCEL_FILLRECT |
-			   FBINFO_HWACCEL_IMAGEBLIT);
-	all->info.fbops = &ffb_ops;
-	all->info.screen_base = (char *) all->par.physbase + FFB_DFB24_POFF;
-	all->info.par = &all->par;
-	all->info.pseudo_palette = all->pseudo_palette;
+	info->flags = (FBINFO_DEFAULT |
+		       /* FBINFO_HWACCEL_COPYAREA | */
+		       FBINFO_HWACCEL_FILLRECT |
+		       FBINFO_HWACCEL_IMAGEBLIT);
 
-	sbusfb_fill_var(&all->info.var, dp->node, 32);
-	all->par.fbsize = PAGE_ALIGN(all->info.var.xres *
-				     all->info.var.yres *
-				     4);
-	ffb_fixup_var_rgb(&all->info.var);
+	info->fbops = &ffb_ops;
 
-	all->info.var.accel_flags = FB_ACCELF_TEXT;
+	info->screen_base = (char *) par->physbase + FFB_DFB24_POFF;
+	info->pseudo_palette = par->pseudo_palette;
+
+	sbusfb_fill_var(&info->var, dp->node, 32);
+	par->fbsize = PAGE_ALIGN(info->var.xres * info->var.yres * 4);
+	ffb_fixup_var_rgb(&info->var);
+
+	info->var.accel_flags = FB_ACCELF_TEXT;
 
 	if (!strcmp(dp->name, "SUNW,afb"))
-		all->par.flags |= FFB_FLAG_AFB;
+		par->flags |= FFB_FLAG_AFB;
 
-	all->par.board_type = of_getintprop_default(dp, "board_type", 0);
+	par->board_type = of_getintprop_default(dp, "board_type", 0);
 
-	fbc = all->par.fbc;
+	fbc = par->fbc;
 	if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)
 		upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
 
-	dac = all->par.dac;
+	dac = par->dac;
 	upa_writel(FFB_DAC_DID, &dac->type);
 	dac_pnum = upa_readl(&dac->value);
 	dac_rev = (dac_pnum & FFB_DAC_DID_REV) >> FFB_DAC_DID_REV_SHIFT;
@@ -985,76 +979,70 @@
 	 * cursor logic.  We identify Pacifica 1 as not Pacifica 2, the
 	 * latter having a part number value of 0x236e.
 	 */
-	if ((all->par.flags & FFB_FLAG_AFB) || dac_pnum == 0x236e) {
-		all->par.flags &= ~FFB_FLAG_INVCURSOR;
+	if ((par->flags & FFB_FLAG_AFB) || dac_pnum == 0x236e) {
+		par->flags &= ~FFB_FLAG_INVCURSOR;
 	} else {
 		if (dac_mrev < 3)
-			all->par.flags |= FFB_FLAG_INVCURSOR;
+			par->flags |= FFB_FLAG_INVCURSOR;
 	}
 
-	ffb_switch_from_graph(&all->par);
+	ffb_switch_from_graph(par);
 
 	/* Unblank it just to be sure.  When there are multiple
 	 * FFB/AFB cards in the system, or it is not the OBP
 	 * chosen console, it will have video outputs off in
 	 * the DAC.
 	 */
-	ffb_blank(0, &all->info);
+	ffb_blank(0, info);
 
-	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
-		printk(KERN_ERR "ffb: Could not allocate color map.\n");
-		of_iounmap(&op->resource[2],
-			   all->par.fbc, sizeof(struct ffb_fbc));
-		of_iounmap(&op->resource[1],
-			   all->par.dac, sizeof(struct ffb_dac));
-		kfree(all);
-		return -ENOMEM;
-	}
+	if (fb_alloc_cmap(&info->cmap, 256, 0))
+		goto out_unmap_dac;
 
-	ffb_init_fix(&all->info);
+	ffb_init_fix(info);
 
-	err = register_framebuffer(&all->info);
-	if (err < 0) {
-		printk(KERN_ERR "ffb: Could not register framebuffer.\n");
-		fb_dealloc_cmap(&all->info.cmap);
-		of_iounmap(&op->resource[2],
-			   all->par.fbc, sizeof(struct ffb_fbc));
-		of_iounmap(&op->resource[1],
-			   all->par.dac, sizeof(struct ffb_dac));
-		kfree(all);
-		return err;
-	}
+	err = register_framebuffer(info);
+	if (err < 0)
+		goto out_dealloc_cmap;
 
-	dev_set_drvdata(&op->dev, all);
+	dev_set_drvdata(&op->dev, info);
 
 	printk("%s: %s at %016lx, type %d, "
 	       "DAC pnum[%x] rev[%d] manuf_rev[%d]\n",
 	       dp->full_name,
-	       ((all->par.flags & FFB_FLAG_AFB) ? "AFB" : "FFB"),
-	       all->par.physbase, all->par.board_type,
+	       ((par->flags & FFB_FLAG_AFB) ? "AFB" : "FFB"),
+	       par->physbase, par->board_type,
 	       dac_pnum, dac_rev, dac_mrev);
 
 	return 0;
-}
 
-static int __devinit ffb_probe(struct of_device *dev, const struct of_device_id *match)
-{
-	struct of_device *op = to_of_device(&dev->dev);
+out_dealloc_cmap:
+	fb_dealloc_cmap(&info->cmap);
 
-	return ffb_init_one(op);
+out_unmap_dac:
+	of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));
+
+out_unmap_fbc:
+	of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));
+
+out_release_fb:
+	framebuffer_release(info);
+
+out_err:
+	return err;
 }
 
 static int __devexit ffb_remove(struct of_device *op)
 {
-	struct all_info *all = dev_get_drvdata(&op->dev);
+	struct fb_info *info = dev_get_drvdata(&op->dev);
+	struct ffb_par *par = info->par;
 
-	unregister_framebuffer(&all->info);
-	fb_dealloc_cmap(&all->info.cmap);
+	unregister_framebuffer(info);
+	fb_dealloc_cmap(&info->cmap);
 
-	of_iounmap(&op->resource[2], all->par.fbc, sizeof(struct ffb_fbc));
-	of_iounmap(&op->resource[1], all->par.dac, sizeof(struct ffb_dac));
+	of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));
+	of_iounmap(&op->resource[1], par->dac, sizeof(struct ffb_dac));
 
-	kfree(all);
+	framebuffer_release(info);
 
 	dev_set_drvdata(&op->dev, NULL);
 
diff --git a/drivers/video/geode/Kconfig b/drivers/video/geode/Kconfig
index a814b6c..7608429 100644
--- a/drivers/video/geode/Kconfig
+++ b/drivers/video/geode/Kconfig
@@ -8,6 +8,21 @@
 	  Say 'Y' here to allow you to select framebuffer drivers for
 	  the AMD Geode family of processors.
 
+config FB_GEODE_LX
+	tristate "AMD Geode LX framebuffer support (EXPERIMENTAL)"
+	depends on FB && FB_GEODE
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	---help---
+	  Framebuffer driver for the display controller integrated into the
+	  AMD Geode LX processors.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called lxfb.
+
+	  If unsure, say N.
+
 config FB_GEODE_GX
 	tristate "AMD Geode GX framebuffer support (EXPERIMENTAL)"
 	depends on FB && FB_GEODE && EXPERIMENTAL
diff --git a/drivers/video/geode/Makefile b/drivers/video/geode/Makefile
index f896565..957304b 100644
--- a/drivers/video/geode/Makefile
+++ b/drivers/video/geode/Makefile
@@ -2,6 +2,8 @@
 
 obj-$(CONFIG_FB_GEODE_GX1) += gx1fb.o
 obj-$(CONFIG_FB_GEODE_GX)  += gxfb.o
+obj-$(CONFIG_FB_GEODE_LX)  += lxfb.o
 
 gx1fb-objs := gx1fb_core.o display_gx1.o video_cs5530.o
 gxfb-objs  := gxfb_core.o display_gx.o video_gx.o
+lxfb-objs  := lxfb_core.o lxfb_ops.o
diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h
new file mode 100644
index 0000000..6c227f9
--- /dev/null
+++ b/drivers/video/geode/lxfb.h
@@ -0,0 +1,199 @@
+#ifndef _LXFB_H_
+#define _LXFB_H_
+
+#include <linux/fb.h>
+
+#define OUTPUT_CRT   0x01
+#define OUTPUT_PANEL 0x02
+
+struct lxfb_par {
+	int output;
+	int panel_width;
+	int panel_height;
+
+	void __iomem *gp_regs;
+	void __iomem *dc_regs;
+	void __iomem *df_regs;
+};
+
+static inline unsigned int lx_get_pitch(unsigned int xres, int bpp)
+{
+	return (((xres * (bpp >> 3)) + 7) & ~7);
+}
+
+void lx_set_mode(struct fb_info *);
+void lx_get_gamma(struct fb_info *, unsigned int *, int);
+void lx_set_gamma(struct fb_info *, unsigned int *, int);
+unsigned int lx_framebuffer_size(void);
+int lx_blank_display(struct fb_info *, int);
+void lx_set_palette_reg(struct fb_info *, unsigned int, unsigned int,
+			unsigned int, unsigned int);
+
+/* MSRS */
+
+#define MSR_LX_GLD_CONFIG    0x48002001
+#define MSR_LX_GLCP_DOTPLL   0x4c000015
+#define MSR_LX_DF_PADSEL     0x48000011
+#define MSR_LX_DC_SPARE      0x80000011
+#define MSR_LX_DF_GLCONFIG   0x48002001
+
+#define MSR_LX_GLIU0_P2D_RO0 0x10000029
+
+#define GLCP_DOTPLL_RESET    (1 << 0)
+#define GLCP_DOTPLL_BYPASS   (1 << 15)
+#define GLCP_DOTPLL_HALFPIX  (1 << 24)
+#define GLCP_DOTPLL_LOCK     (1 << 25)
+
+#define DF_CONFIG_OUTPUT_MASK       0x38
+#define DF_OUTPUT_PANEL             0x08
+#define DF_OUTPUT_CRT               0x00
+#define DF_SIMULTANEOUS_CRT_AND_FP  (1 << 15)
+
+#define DF_DEFAULT_TFT_PAD_SEL_LOW  0xDFFFFFFF
+#define DF_DEFAULT_TFT_PAD_SEL_HIGH 0x0000003F
+
+#define DC_SPARE_DISABLE_CFIFO_HGO         0x00000800
+#define DC_SPARE_VFIFO_ARB_SELECT          0x00000400
+#define DC_SPARE_WM_LPEN_OVRD              0x00000200
+#define DC_SPARE_LOAD_WM_LPEN_MASK         0x00000100
+#define DC_SPARE_DISABLE_INIT_VID_PRI      0x00000080
+#define DC_SPARE_DISABLE_VFIFO_WM          0x00000040
+#define DC_SPARE_DISABLE_CWD_CHECK         0x00000020
+#define DC_SPARE_PIX8_PAN_FIX              0x00000010
+#define DC_SPARE_FIRST_REQ_MASK            0x00000002
+
+/* Registers */
+
+#define DC_UNLOCK         0x00
+#define  DC_UNLOCK_CODE   0x4758
+
+#define DC_GENERAL_CFG    0x04
+#define  DC_GCFG_DFLE     (1 << 0)
+#define  DC_GCFG_VIDE     (1 << 3)
+#define  DC_GCFG_VGAE     (1 << 7)
+#define  DC_GCFG_CMPE     (1 << 5)
+#define  DC_GCFG_DECE     (1 << 6)
+#define  DC_GCFG_FDTY     (1 << 17)
+
+#define DC_DISPLAY_CFG    0x08
+#define  DC_DCFG_TGEN     (1 << 0)
+#define  DC_DCFG_GDEN     (1 << 3)
+#define  DC_DCFG_VDEN     (1 << 4)
+#define  DC_DCFG_TRUP     (1 << 6)
+#define  DC_DCFG_DCEN     (1 << 24)
+#define  DC_DCFG_PALB     (1 << 25)
+#define  DC_DCFG_VISL     (1 << 27)
+
+#define  DC_DCFG_16BPP           0x0
+
+#define  DC_DCFG_DISP_MODE_MASK  0x00000300
+#define  DC_DCFG_DISP_MODE_8BPP  0x00000000
+#define  DC_DCFG_DISP_MODE_16BPP 0x00000100
+#define  DC_DCFG_DISP_MODE_24BPP 0x00000200
+#define  DC_DCFG_DISP_MODE_32BPP 0x00000300
+
+
+#define DC_ARB_CFG        0x0C
+
+#define DC_FB_START       0x10
+#define DC_CB_START       0x14
+#define DC_CURSOR_START   0x18
+
+#define DC_DV_TOP          0x2C
+#define DC_DV_TOP_ENABLE   (1 << 0)
+
+#define DC_LINE_SIZE       0x30
+#define DC_GRAPHICS_PITCH  0x34
+#define DC_H_ACTIVE_TIMING 0x40
+#define DC_H_BLANK_TIMING  0x44
+#define DC_H_SYNC_TIMING   0x48
+#define DC_V_ACTIVE_TIMING 0x50
+#define DC_V_BLANK_TIMING  0x54
+#define DC_V_SYNC_TIMING   0x58
+#define DC_FB_ACTIVE       0x5C
+
+#define DC_PAL_ADDRESS     0x70
+#define DC_PAL_DATA        0x74
+
+#define DC_PHY_MEM_OFFSET  0x84
+
+#define DC_DV_CTL          0x88
+#define DC_DV_LINE_SIZE_MASK               0x00000C00
+#define DC_DV_LINE_SIZE_1024               0x00000000
+#define DC_DV_LINE_SIZE_2048               0x00000400
+#define DC_DV_LINE_SIZE_4096               0x00000800
+#define DC_DV_LINE_SIZE_8192               0x00000C00
+
+
+#define DC_GFX_SCALE       0x90
+#define DC_IRQ_FILT_CTL    0x94
+
+
+#define DC_IRQ               0xC8
+#define  DC_IRQ_MASK         (1 << 0)
+#define  DC_VSYNC_IRQ_MASK   (1 << 1)
+#define  DC_IRQ_STATUS       (1 << 20)
+#define  DC_VSYNC_IRQ_STATUS (1 << 21)
+
+#define DC_GENLCK_CTRL      0xD4
+#define  DC_GENLCK_ENABLE   (1 << 18)
+#define  DC_GC_ALPHA_FLICK_ENABLE  (1 << 25)
+#define  DC_GC_FLICKER_FILTER_ENABLE (1 << 24)
+#define  DC_GC_FLICKER_FILTER_MASK (0x0F << 28)
+
+#define DC_COLOR_KEY       0xB8
+#define DC_CLR_KEY_ENABLE (1 << 24)
+
+
+#define DC3_DV_LINE_SIZE_MASK               0x00000C00
+#define DC3_DV_LINE_SIZE_1024               0x00000000
+#define DC3_DV_LINE_SIZE_2048               0x00000400
+#define DC3_DV_LINE_SIZE_4096               0x00000800
+#define DC3_DV_LINE_SIZE_8192               0x00000C00
+
+#define DF_VIDEO_CFG       0x0
+#define  DF_VCFG_VID_EN    (1 << 0)
+
+#define DF_DISPLAY_CFG     0x08
+
+#define DF_DCFG_CRT_EN     (1 << 0)
+#define DF_DCFG_HSYNC_EN   (1 << 1)
+#define DF_DCFG_VSYNC_EN   (1 << 2)
+#define DF_DCFG_DAC_BL_EN  (1 << 3)
+#define DF_DCFG_CRT_HSYNC_POL  (1 << 8)
+#define DF_DCFG_CRT_VSYNC_POL  (1 << 9)
+#define DF_DCFG_GV_PAL_BYP     (1 << 21)
+
+#define DF_DCFG_CRT_SYNC_SKW_INIT 0x10000
+#define DF_DCFG_CRT_SYNC_SKW_MASK  0x1c000
+
+#define DF_DCFG_PWR_SEQ_DLY_INIT     0x80000
+#define DF_DCFG_PWR_SEQ_DLY_MASK     0xe0000
+
+#define DF_MISC            0x50
+
+#define  DF_MISC_GAM_BYPASS (1 << 0)
+#define  DF_MISC_DAC_PWRDN  (1 << 10)
+#define  DF_MISC_A_PWRDN    (1 << 11)
+
+#define DF_PAR             0x38
+#define DF_PDR             0x40
+#define DF_ALPHA_CONTROL_1 0xD8
+#define DF_VIDEO_REQUEST   0x120
+
+#define DF_PANEL_TIM1      0x400
+#define DF_DEFAULT_TFT_PMTIM1 0x0
+
+#define DF_PANEL_TIM2      0x408
+#define DF_DEFAULT_TFT_PMTIM2 0x08000000
+
+#define DF_FP_PM             0x410
+#define  DF_FP_PM_P          (1 << 24)
+
+#define DF_DITHER_CONTROL    0x418
+#define DF_DEFAULT_TFT_DITHCTL                  0x00000070
+#define GP_BLT_STATUS      0x44
+#define  GP_BS_BLT_BUSY    (1 << 0)
+#define  GP_BS_CB_EMPTY    (1 << 4)
+
+#endif
diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c
new file mode 100644
index 0000000..5e30b40
--- /dev/null
+++ b/drivers/video/geode/lxfb_core.c
@@ -0,0 +1,621 @@
+/*
+ * Geode LX framebuffer driver.
+ *
+ * Copyright (C) 2007 Advanced Micro Devices, Inc.
+ * Built from gxfb (which is Copyright (C) 2006 Arcom Control Systems Ltd.)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/console.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/uaccess.h>
+
+#include "lxfb.h"
+
+static char *mode_option;
+static int noclear, nopanel, nocrt;
+static int fbsize;
+
+/* Most of these modes are sorted in ascending order, but
+ * since the first entry in this table is the "default" mode,
+ * we try to make it something sane - 640x480-60 is sane
+ */
+
+const struct fb_videomode geode_modedb[] __initdata = {
+	/* 640x480-60 */
+	{ NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, 0 },
+	/* 640x400-70 */
+	{ NULL, 70, 640, 400, 39770, 40, 8, 28, 5, 96, 2,
+	  FB_SYNC_HOR_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, 0 },
+	/* 640x480-70 */
+	{ NULL, 70, 640, 480, 35014, 88, 24, 15, 2, 64, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 640x480-72 */
+	{ NULL, 72, 640, 480, 32102, 120, 16, 20, 1, 40, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, 0 },
+	/* 640x480-75 */
+	{ NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, 0 },
+	/* 640x480-85 */
+	{ NULL, 85, 640, 480, 27780, 80, 56, 25, 1, 56, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, 0 },
+	/* 640x480-90 */
+	{ NULL, 90, 640, 480, 26392, 96, 32, 22, 1, 64, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 640x480-100 */
+	{ NULL, 100, 640, 480, 23167, 104, 40, 25, 1, 64, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 640x480-60 */
+	{ NULL, 60, 640, 480, 39682, 48, 16, 25, 10, 88, 2,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, 0 },
+	/* 800x600-56 */
+	{ NULL, 56, 800, 600, 27901, 128, 24, 22, 1, 72, 2,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 800x600-60 */
+	{ NULL, 60, 800, 600, 25131, 72, 32, 23, 1, 136, 4,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 800x600-70 */
+	{ NULL, 70, 800, 600, 21873, 120, 40, 21, 4, 80, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 800x600-72 */
+	{ NULL, 72, 800, 600, 20052, 64, 56, 23, 37, 120, 6,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 800x600-75 */
+	{ NULL, 75, 800, 600, 20202, 160, 16, 21, 1, 80, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 800x600-85 */
+	{ NULL, 85, 800, 600, 17790, 152, 32, 27, 1, 64, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 800x600-90 */
+	{ NULL, 90, 800, 600, 16648, 128, 40, 28, 1, 88, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 800x600-100 */
+	{ NULL, 100, 800, 600, 14667, 136, 48, 27, 1, 88, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 800x600-60 */
+	{ NULL, 60, 800, 600, 25131, 88, 40, 23, 1, 128, 4,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, 0 },
+	/* 1024x768-60 */
+	{ NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, 0 },
+	/* 1024x768-70 */
+	{ NULL, 70, 1024, 768, 13346, 144, 24, 29, 3, 136, 6,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, 0 },
+	/* 1024x768-72 */
+	{ NULL, 72, 1024, 768, 12702, 168, 56, 29, 4, 112, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1024x768-75 */
+	{ NULL, 75, 1024, 768, 12703, 176, 16, 28, 1, 96, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1024x768-85 */
+	{ NULL, 85, 1024, 768, 10581, 208, 48, 36, 1, 96, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1024x768-90 */
+	{ NULL, 90, 1024, 768, 9981, 176, 64, 37, 1, 112, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1024x768-100 */
+	{ NULL, 100, 1024, 768, 8825, 184, 72, 42, 1, 112, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1024x768-60 */
+	{ NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, 0 },
+	/* 1152x864-60 */
+	{ NULL, 60, 1152, 864, 12251, 184, 64, 27, 1, 120, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1152x864-70 */
+	{ NULL, 70, 1152, 864, 10254, 192, 72, 32, 8, 120, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1152x864-72 */
+	{ NULL, 72, 1152, 864, 9866, 200, 72, 33, 7, 128, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1152x864-75 */
+	{ NULL, 75, 1152, 864, 9259, 256, 64, 32, 1, 128, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1152x864-85 */
+	{ NULL, 85, 1152, 864, 8357, 200, 72, 37, 3, 128, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1152x864-90 */
+	{ NULL, 90, 1152, 864, 7719, 208, 80, 42, 9, 128, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1152x864-100 */
+	{ NULL, 100, 1152, 864, 6947, 208, 80, 48, 3, 128, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1152x864-60 */
+	{ NULL, 60, 1152, 864, 12251, 184, 64, 27, 1, 120, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, 0 },
+	/* 1280x1024-60 */
+	{ NULL, 60, 1280, 1024, 9262, 248, 48, 38, 1, 112, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1280x1024-70 */
+	{ NULL, 70, 1280, 1024, 7719, 224, 88, 38, 6, 136, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1280x1024-72 */
+	{ NULL, 72, 1280, 1024, 7490, 224, 88, 39, 7, 136, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1280x1024-75 */
+	{ NULL, 75, 1280, 1024, 7409, 248, 16, 38, 1, 144, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1280x1024-85 */
+	{ NULL, 85, 1280, 1024, 6351, 224, 64, 44, 1, 160, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1280x1024-90 */
+	{ NULL, 90, 1280, 1024, 5791, 240, 96, 51, 12, 144, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1280x1024-100 */
+	{ NULL, 100, 1280, 1024, 5212, 240, 96, 57, 6, 144, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1280x1024-60 */
+	{ NULL, 60, 1280, 1024, 9262, 248, 48, 38, 1, 112, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, 0 },
+	/* 1600x1200-60 */
+	{ NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1600x1200-70 */
+	{ NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1600x1200-72 */
+	{ NULL, 72, 1600, 1200, 5053, 288, 112, 47, 13, 176, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1600x1200-75 */
+	{ NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1600x1200-85 */
+	{ NULL, 85, 1600, 1200, 4357, 304, 64, 46, 1, 192, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1600x1200-90 */
+	{ NULL, 90, 1600, 1200, 3981, 304, 128, 60, 1, 176, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1600x1200-100 */
+	{ NULL, 100, 1600, 1200, 3563, 304, 128, 67, 1, 176, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1600x1200-60 */
+	{ NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3,
+	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+	  FB_VMODE_NONINTERLACED, 0 },
+	/* 1920x1440-60 */
+	{ NULL, 60, 1920, 1440, 4273, 344, 128, 56, 1, 208, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1920x1440-70 */
+	{ NULL, 70, 1920, 1440, 3593, 360, 152, 55, 8, 208, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1920x1440-72 */
+	{ NULL, 72, 1920, 1440, 3472, 360, 152, 68, 4, 208, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1920x1440-75 */
+	{ NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+	/* 1920x1440-85 */
+	{ NULL, 85, 1920, 1440, 2929, 368, 152, 68, 1, 216, 3,
+	  0, FB_VMODE_NONINTERLACED, 0 },
+};
+
+static int lxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	if (var->xres > 1920 || var->yres > 1440)
+		return -EINVAL;
+
+	if (var->bits_per_pixel == 32) {
+		var->red.offset   = 16; var->red.length   = 8;
+		var->green.offset =  8; var->green.length = 8;
+		var->blue.offset  =  0; var->blue.length  = 8;
+	} else if (var->bits_per_pixel == 16) {
+		var->red.offset   = 11; var->red.length   = 5;
+		var->green.offset =  5; var->green.length = 6;
+		var->blue.offset  =  0; var->blue.length  = 5;
+	} else if (var->bits_per_pixel == 8) {
+		var->red.offset   = 0; var->red.length   = 8;
+		var->green.offset = 0; var->green.length = 8;
+		var->blue.offset  = 0; var->blue.length  = 8;
+	} else
+		return -EINVAL;
+
+	var->transp.offset = 0; var->transp.length = 0;
+
+	/* Enough video memory? */
+	if ((lx_get_pitch(var->xres, var->bits_per_pixel) * var->yres)
+	    > info->fix.smem_len)
+	  return -EINVAL;
+
+	return 0;
+}
+
+static int lxfb_set_par(struct fb_info *info)
+{
+	if (info->var.bits_per_pixel > 8) {
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+		fb_dealloc_cmap(&info->cmap);
+	} else {
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0);
+	}
+
+	info->fix.line_length = lx_get_pitch(info->var.xres,
+		info->var.bits_per_pixel);
+
+	lx_set_mode(info);
+	return 0;
+}
+
+static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+static int lxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info)
+{
+	if (info->var.grayscale) {
+		/* grayscale = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+
+	/* Truecolor has hardware independent palette */
+	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+		u32 *pal = info->pseudo_palette;
+		u32 v;
+
+		if (regno >= 16)
+			return -EINVAL;
+
+		v  = chan_to_field(red, &info->var.red);
+		v |= chan_to_field(green, &info->var.green);
+		v |= chan_to_field(blue, &info->var.blue);
+
+		pal[regno] = v;
+	} else {
+		if (regno >= 256)
+			return -EINVAL;
+
+		lx_set_palette_reg(info, regno, red, green, blue);
+	}
+
+	return 0;
+}
+
+static int lxfb_blank(int blank_mode, struct fb_info *info)
+{
+	return lx_blank_display(info, blank_mode);
+}
+
+
+static int __init lxfb_map_video_memory(struct fb_info *info,
+					struct pci_dev *dev)
+{
+	struct lxfb_par *par = info->par;
+	int ret;
+
+	ret = pci_enable_device(dev);
+
+	if (ret)
+		return ret;
+
+	ret = pci_request_region(dev, 0, "lxfb-framebuffer");
+
+	if (ret)
+		return ret;
+
+	ret = pci_request_region(dev, 1, "lxfb-gp");
+
+	if (ret)
+		return ret;
+
+	ret = pci_request_region(dev, 2, "lxfb-vg");
+
+	if (ret)
+		return ret;
+
+	ret = pci_request_region(dev, 3, "lxfb-vip");
+
+	if (ret)
+		return ret;
+
+	info->fix.smem_start = pci_resource_start(dev, 0);
+	info->fix.smem_len = fbsize ? fbsize : lx_framebuffer_size();
+
+	info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+
+	ret = -ENOMEM;
+
+	if (info->screen_base == NULL)
+		return ret;
+
+	par->gp_regs = ioremap(pci_resource_start(dev, 1),
+				pci_resource_len(dev, 1));
+
+	if (par->gp_regs == NULL)
+		return ret;
+
+	par->dc_regs = ioremap(pci_resource_start(dev, 2),
+			       pci_resource_len(dev, 2));
+
+	if (par->dc_regs == NULL)
+		return ret;
+
+	par->df_regs = ioremap(pci_resource_start(dev, 3),
+			       pci_resource_len(dev, 3));
+
+	if (par->df_regs == NULL)
+		return ret;
+
+	writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
+
+	writel(info->fix.smem_start & 0xFF000000,
+	       par->dc_regs + DC_PHY_MEM_OFFSET);
+
+	writel(0, par->dc_regs + DC_UNLOCK);
+
+	dev_info(&dev->dev, "%d KB of video memory at 0x%lx\n",
+		 info->fix.smem_len / 1024, info->fix.smem_start);
+
+	return 0;
+}
+
+static struct fb_ops lxfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= lxfb_check_var,
+	.fb_set_par	= lxfb_set_par,
+	.fb_setcolreg	= lxfb_setcolreg,
+	.fb_blank       = lxfb_blank,
+	/* No HW acceleration for now. */
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
+
+static struct fb_info * __init lxfb_init_fbinfo(struct device *dev)
+{
+	struct lxfb_par *par;
+	struct fb_info *info;
+
+	/* Alloc enough space for the pseudo palette. */
+	info = framebuffer_alloc(sizeof(struct lxfb_par) + sizeof(u32) * 16,
+				 dev);
+	if (!info)
+		return NULL;
+
+	par = info->par;
+
+	strcpy(info->fix.id, "Geode LX");
+
+	info->fix.type		= FB_TYPE_PACKED_PIXELS;
+	info->fix.type_aux	= 0;
+	info->fix.xpanstep	= 0;
+	info->fix.ypanstep	= 0;
+	info->fix.ywrapstep	= 0;
+	info->fix.accel		= FB_ACCEL_NONE;
+
+	info->var.nonstd	= 0;
+	info->var.activate	= FB_ACTIVATE_NOW;
+	info->var.height	= -1;
+	info->var.width	= -1;
+	info->var.accel_flags = 0;
+	info->var.vmode	= FB_VMODE_NONINTERLACED;
+
+	info->fbops		= &lxfb_ops;
+	info->flags		= FBINFO_DEFAULT;
+	info->node		= -1;
+
+	info->pseudo_palette	= (void *)par + sizeof(struct lxfb_par);
+
+	info->var.grayscale	= 0;
+
+	return info;
+}
+
+static int __init lxfb_probe(struct pci_dev *pdev,
+			     const struct pci_device_id *id)
+{
+	struct lxfb_par *par;
+	struct fb_info *info;
+	int ret;
+
+	struct fb_videomode *modedb_ptr;
+	int modedb_size;
+
+	info = lxfb_init_fbinfo(&pdev->dev);
+
+	if (info == NULL)
+		return -ENOMEM;
+
+	par = info->par;
+
+	ret = lxfb_map_video_memory(info, pdev);
+
+	if (ret < 0) {
+		dev_err(&pdev->dev,
+			"failed to map frame buffer or controller registers\n");
+		goto err;
+	}
+
+	/* Set up the desired outputs */
+
+	par->output = 0;
+	par->output |= (nopanel) ? 0 : OUTPUT_PANEL;
+	par->output |= (nocrt) ? 0 : OUTPUT_CRT;
+
+	/* Set up the mode database */
+
+	modedb_ptr = (struct fb_videomode *) geode_modedb;
+	modedb_size = ARRAY_SIZE(geode_modedb);
+
+	ret = fb_find_mode(&info->var, info, mode_option,
+			   modedb_ptr, modedb_size, NULL, 16);
+
+	if (ret == 0 || ret == 4) {
+		dev_err(&pdev->dev, "could not find valid video mode\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	/* Clear the screen of garbage, unless noclear was specified,
+	 * in which case we assume the user knows what he is doing */
+
+	if (!noclear)
+		memset_io(info->screen_base, 0, info->fix.smem_len);
+
+	/* Set the mode */
+
+	lxfb_check_var(&info->var, info);
+	lxfb_set_par(info);
+
+	if (register_framebuffer(info) < 0) {
+		ret = -EINVAL;
+		goto err;
+	}
+	pci_set_drvdata(pdev, info);
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+		info->node, info->fix.id);
+
+	return 0;
+
+err:
+	if (info->screen_base) {
+		iounmap(info->screen_base);
+		pci_release_region(pdev, 0);
+	}
+	if (par->gp_regs) {
+		iounmap(par->gp_regs);
+		pci_release_region(pdev, 1);
+	}
+	if (par->dc_regs) {
+		iounmap(par->dc_regs);
+		pci_release_region(pdev, 2);
+	}
+	if (par->df_regs) {
+		iounmap(par->df_regs);
+		pci_release_region(pdev, 3);
+	}
+
+	if (info)
+		framebuffer_release(info);
+
+	return ret;
+}
+
+static void lxfb_remove(struct pci_dev *pdev)
+{
+	struct fb_info *info = pci_get_drvdata(pdev);
+	struct lxfb_par *par = info->par;
+
+	unregister_framebuffer(info);
+
+	iounmap(info->screen_base);
+	pci_release_region(pdev, 0);
+
+	iounmap(par->gp_regs);
+	pci_release_region(pdev, 1);
+
+	iounmap(par->dc_regs);
+	pci_release_region(pdev, 2);
+
+	iounmap(par->df_regs);
+	pci_release_region(pdev, 3);
+
+	pci_set_drvdata(pdev, NULL);
+	framebuffer_release(info);
+}
+
+static struct pci_device_id lxfb_id_table[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_VIDEO) },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, lxfb_id_table);
+
+static struct pci_driver lxfb_driver = {
+	.name		= "lxfb",
+	.id_table	= lxfb_id_table,
+	.probe		= lxfb_probe,
+	.remove		= lxfb_remove,
+};
+
+#ifndef MODULE
+static int __init lxfb_setup(char *options)
+{
+	char *opt;
+
+	if (!options || !*options)
+		return 0;
+
+	while (1) {
+		char *opt = strsep(&options, ",");
+
+		if (opt == NULL)
+			break;
+
+		if (!*opt)
+			continue;
+
+		if (!strncmp(opt, "fbsize:", 7))
+			fbsize = simple_strtoul(opt+7, NULL, 0);
+		else if (!strcmp(opt, "noclear"))
+			noclear = 1;
+		else if (!strcmp(opt, "nopanel"))
+			nopanel = 1;
+		else if (!strcmp(opt, "nocrt"))
+			nocrt = 1;
+		else
+			mode_option = opt;
+	}
+
+	return 0;
+}
+#endif
+
+static int __init lxfb_init(void)
+{
+#ifndef MODULE
+	char *option = NULL;
+
+	if (fb_get_options("lxfb", &option))
+		return -ENODEV;
+
+	lxfb_setup(option);
+#endif
+	return pci_register_driver(&lxfb_driver);
+}
+static void __exit lxfb_cleanup(void)
+{
+	pci_unregister_driver(&lxfb_driver);
+}
+
+module_init(lxfb_init);
+module_exit(lxfb_cleanup);
+
+module_param(mode_option, charp, 0);
+MODULE_PARM_DESC(mode_option, "video mode (<x>x<y>[-<bpp>][@<refr>])");
+
+module_param(fbsize, int, 0);
+MODULE_PARM_DESC(fbsize, "video memory size");
+
+MODULE_DESCRIPTION("Framebuffer driver for the AMD Geode LX");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/geode/lxfb_ops.c b/drivers/video/geode/lxfb_ops.c
new file mode 100644
index 0000000..4fbc99b
--- /dev/null
+++ b/drivers/video/geode/lxfb_ops.c
@@ -0,0 +1,536 @@
+/* Geode LX framebuffer driver
+ *
+ * Copyright (C) 2006-2007, Advanced Micro Devices,Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+
+#include "lxfb.h"
+
+/* TODO
+ * Support panel scaling
+ * Add acceleration
+ * Add support for interlacing (TV out)
+ * Support compression
+ */
+
+/* This is the complete list of PLL frequencies that we can set -
+ * we will choose the closest match to the incoming clock.
+ * freq is the frequency of the dotclock * 1000 (for example,
+ * 24823 = 24.983 Mhz).
+ * pllval is the corresponding PLL value
+*/
+
+static const struct {
+  unsigned int pllval;
+  unsigned int freq;
+} pll_table[] = {
+  { 0x000031AC, 24923 },
+  { 0x0000215D, 25175 },
+  { 0x00001087, 27000 },
+  { 0x0000216C, 28322 },
+  { 0x0000218D, 28560 },
+  { 0x000010C9, 31200 },
+  { 0x00003147, 31500 },
+  { 0x000010A7, 33032 },
+  { 0x00002159, 35112 },
+  { 0x00004249, 35500 },
+  { 0x00000057, 36000 },
+  { 0x0000219A, 37889 },
+  { 0x00002158, 39168 },
+  { 0x00000045, 40000 },
+  { 0x00000089, 43163 },
+  { 0x000010E7, 44900 },
+  { 0x00002136, 45720 },
+  { 0x00003207, 49500 },
+  { 0x00002187, 50000 },
+  { 0x00004286, 56250 },
+  { 0x000010E5, 60065 },
+  { 0x00004214, 65000 },
+  { 0x00001105, 68179 },
+  { 0x000031E4, 74250 },
+  { 0x00003183, 75000 },
+  { 0x00004284, 78750 },
+  { 0x00001104, 81600 },
+  { 0x00006363, 94500 },
+  { 0x00005303, 97520 },
+  { 0x00002183, 100187 },
+  { 0x00002122, 101420 },
+  { 0x00001081, 108000 },
+  { 0x00006201, 113310 },
+  { 0x00000041, 119650 },
+  { 0x000041A1, 129600 },
+  { 0x00002182, 133500 },
+  { 0x000041B1, 135000 },
+  { 0x00000051, 144000 },
+  { 0x000041E1, 148500 },
+  { 0x000062D1, 157500 },
+  { 0x000031A1, 162000 },
+  { 0x00000061, 169203 },
+  { 0x00004231, 172800 },
+  { 0x00002151, 175500 },
+  { 0x000052E1, 189000 },
+  { 0x00000071, 192000 },
+  { 0x00003201, 198000 },
+  { 0x00004291, 202500 },
+  { 0x00001101, 204750 },
+  { 0x00007481, 218250 },
+  { 0x00004170, 229500 },
+  { 0x00006210, 234000 },
+  { 0x00003140, 251182 },
+  { 0x00006250, 261000 },
+  { 0x000041C0, 278400 },
+  { 0x00005220, 280640 },
+  { 0x00000050, 288000 },
+  { 0x000041E0, 297000 },
+  { 0x00002130, 320207 }
+};
+
+
+static void lx_set_dotpll(u32 pllval)
+{
+	u32 dotpll_lo, dotpll_hi;
+	int i;
+
+	rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
+
+	if ((dotpll_lo & GLCP_DOTPLL_LOCK) && (dotpll_hi == pllval))
+		return;
+
+	dotpll_hi = pllval;
+	dotpll_lo &= ~(GLCP_DOTPLL_BYPASS | GLCP_DOTPLL_HALFPIX);
+	dotpll_lo |= GLCP_DOTPLL_RESET;
+
+	wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
+
+	/* Wait 100us for the PLL to lock */
+
+	udelay(100);
+
+	/* Now, loop for the lock bit */
+
+	for (i = 0; i < 1000; i++) {
+		rdmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
+		if (dotpll_lo & GLCP_DOTPLL_LOCK)
+			break;
+	}
+
+	/* Clear the reset bit */
+
+	dotpll_lo &= ~GLCP_DOTPLL_RESET;
+	wrmsr(MSR_LX_GLCP_DOTPLL, dotpll_lo, dotpll_hi);
+}
+
+/* Set the clock based on the frequency specified by the current mode */
+
+static void lx_set_clock(struct fb_info *info)
+{
+	unsigned int diff, min, best = 0;
+	unsigned int freq, i;
+
+	freq = (unsigned int) (0x3b9aca00 / info->var.pixclock);
+
+	min = abs(pll_table[0].freq - freq);
+
+	for (i = 0; i < ARRAY_SIZE(pll_table); i++) {
+		diff = abs(pll_table[i].freq - freq);
+		if (diff < min) {
+			min = diff;
+			best = i;
+		}
+	}
+
+	lx_set_dotpll(pll_table[best].pllval & 0x7FFF);
+}
+
+static void lx_graphics_disable(struct fb_info *info)
+{
+	struct lxfb_par *par = info->par;
+	unsigned int val, gcfg;
+
+	/* Note:  This assumes that the video is in a quitet state */
+
+	writel(0, par->df_regs + DF_ALPHA_CONTROL_1);
+	writel(0, par->df_regs + DF_ALPHA_CONTROL_1 + 32);
+	writel(0, par->df_regs + DF_ALPHA_CONTROL_1 + 64);
+
+	/* Turn off the VGA and video enable */
+	val = readl (par->dc_regs + DC_GENERAL_CFG) &
+		~(DC_GCFG_VGAE | DC_GCFG_VIDE);
+
+	writel(val, par->dc_regs + DC_GENERAL_CFG);
+
+	val = readl(par->df_regs + DF_VIDEO_CFG) & ~DF_VCFG_VID_EN;
+	writel(val, par->df_regs + DF_VIDEO_CFG);
+
+	writel( DC_IRQ_MASK | DC_VSYNC_IRQ_MASK |
+		DC_IRQ_STATUS | DC_VSYNC_IRQ_STATUS,
+		par->dc_regs + DC_IRQ);
+
+	val = readl(par->dc_regs + DC_GENLCK_CTRL) & ~DC_GENLCK_ENABLE;
+	writel(val, par->dc_regs + DC_GENLCK_CTRL);
+
+	val = readl(par->dc_regs + DC_COLOR_KEY) & ~DC_CLR_KEY_ENABLE;
+	writel(val & ~DC_CLR_KEY_ENABLE, par->dc_regs + DC_COLOR_KEY);
+
+	/* We don't actually blank the panel, due to the long latency
+	   involved with bringing it back */
+
+	val = readl(par->df_regs + DF_MISC) | DF_MISC_DAC_PWRDN;
+	writel(val, par->df_regs + DF_MISC);
+
+	/* Turn off the display */
+
+	val = readl(par->df_regs + DF_DISPLAY_CFG);
+	writel(val & ~(DF_DCFG_CRT_EN | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN |
+		       DF_DCFG_DAC_BL_EN), par->df_regs + DF_DISPLAY_CFG);
+
+	gcfg = readl(par->dc_regs + DC_GENERAL_CFG);
+	gcfg &= ~(DC_GCFG_CMPE | DC_GCFG_DECE);
+	writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+	/* Turn off the TGEN */
+	val = readl(par->dc_regs + DC_DISPLAY_CFG);
+	val &= ~DC_DCFG_TGEN;
+	writel(val, par->dc_regs + DC_DISPLAY_CFG);
+
+	/* Wait 1000 usecs to ensure that the TGEN is clear */
+	udelay(1000);
+
+	/* Turn off the FIFO loader */
+
+	gcfg &= ~DC_GCFG_DFLE;
+	writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+	/* Lastly, wait for the GP to go idle */
+
+	do {
+		val = readl(par->gp_regs + GP_BLT_STATUS);
+	} while ((val & GP_BS_BLT_BUSY) || !(val & GP_BS_CB_EMPTY));
+}
+
+static void lx_graphics_enable(struct fb_info *info)
+{
+	struct lxfb_par *par = info->par;
+	u32 temp, config;
+
+	/* Set the video request register */
+	writel(0, par->df_regs + DF_VIDEO_REQUEST);
+
+	/* Set up the polarities */
+
+	config = readl(par->df_regs + DF_DISPLAY_CFG);
+
+	config &= ~(DF_DCFG_CRT_SYNC_SKW_MASK | DF_DCFG_PWR_SEQ_DLY_MASK |
+		  DF_DCFG_CRT_HSYNC_POL     | DF_DCFG_CRT_VSYNC_POL);
+
+	config |= (DF_DCFG_CRT_SYNC_SKW_INIT | DF_DCFG_PWR_SEQ_DLY_INIT  |
+		   DF_DCFG_GV_PAL_BYP);
+
+	if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
+		config |= DF_DCFG_CRT_HSYNC_POL;
+
+	if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
+		config |= DF_DCFG_CRT_VSYNC_POL;
+
+	if (par->output & OUTPUT_PANEL) {
+		u32 msrlo, msrhi;
+
+		writel(DF_DEFAULT_TFT_PMTIM1,
+		       par->df_regs + DF_PANEL_TIM1);
+		writel(DF_DEFAULT_TFT_PMTIM2,
+		       par->df_regs + DF_PANEL_TIM2);
+		writel(DF_DEFAULT_TFT_DITHCTL,
+		       par->df_regs + DF_DITHER_CONTROL);
+
+		msrlo = DF_DEFAULT_TFT_PAD_SEL_LOW;
+		msrhi = DF_DEFAULT_TFT_PAD_SEL_HIGH;
+
+		wrmsr(MSR_LX_DF_PADSEL, msrlo, msrhi);
+	}
+
+	if (par->output & OUTPUT_CRT) {
+		config |= DF_DCFG_CRT_EN   | DF_DCFG_HSYNC_EN |
+			DF_DCFG_VSYNC_EN | DF_DCFG_DAC_BL_EN;
+	}
+
+	writel(config, par->df_regs + DF_DISPLAY_CFG);
+
+	/* Turn the CRT dacs back on */
+
+	if (par->output & OUTPUT_CRT) {
+		temp = readl(par->df_regs + DF_MISC);
+		temp &= ~(DF_MISC_DAC_PWRDN  | DF_MISC_A_PWRDN);
+		writel(temp, par->df_regs + DF_MISC);
+	}
+
+	/* Turn the panel on (if it isn't already) */
+
+	if (par->output & OUTPUT_PANEL) {
+		temp = readl(par->df_regs + DF_FP_PM);
+
+		if (!(temp & 0x09))
+			writel(temp | DF_FP_PM_P, par->df_regs + DF_FP_PM);
+	}
+
+	temp = readl(par->df_regs + DF_MISC);
+	temp = readl(par->df_regs + DF_DISPLAY_CFG);
+}
+
+unsigned int lx_framebuffer_size(void)
+{
+	unsigned int val;
+
+	/* The frame buffer size is reported by a VSM in VSA II */
+	/* Virtual Register Class    = 0x02                     */
+	/* VG_MEM_SIZE (1MB units)   = 0x00                     */
+
+	outw(0xFC53, 0xAC1C);
+	outw(0x0200, 0xAC1C);
+
+	val = (unsigned int)(inw(0xAC1E)) & 0xFE;
+	return (val << 20);
+}
+
+void lx_set_mode(struct fb_info *info)
+{
+	struct lxfb_par *par = info->par;
+	u64 msrval;
+
+	unsigned int max, dv, val, size;
+
+	unsigned int gcfg, dcfg;
+	int hactive, hblankstart, hsyncstart, hsyncend, hblankend, htotal;
+	int vactive, vblankstart, vsyncstart, vsyncend, vblankend, vtotal;
+
+	/* Unlock the DC registers */
+	writel(DC_UNLOCK_CODE, par->dc_regs + DC_UNLOCK);
+
+	lx_graphics_disable(info);
+
+	lx_set_clock(info);
+
+	/* Set output mode */
+
+	rdmsrl(MSR_LX_DF_GLCONFIG, msrval);
+	msrval &= ~DF_CONFIG_OUTPUT_MASK;
+
+	if (par->output & OUTPUT_PANEL) {
+		msrval |= DF_OUTPUT_PANEL;
+
+		if (par->output & OUTPUT_CRT)
+			msrval |= DF_SIMULTANEOUS_CRT_AND_FP;
+		else
+			msrval &= ~DF_SIMULTANEOUS_CRT_AND_FP;
+	} else {
+		msrval |= DF_OUTPUT_CRT;
+	}
+
+	wrmsrl(MSR_LX_DF_GLCONFIG, msrval);
+
+	/* Clear the various buffers */
+	/* FIXME:  Adjust for panning here */
+
+	writel(0, par->dc_regs + DC_FB_START);
+	writel(0, par->dc_regs + DC_CB_START);
+	writel(0, par->dc_regs + DC_CURSOR_START);
+
+	/* FIXME: Add support for interlacing */
+	/* FIXME: Add support for scaling */
+
+	val = readl(par->dc_regs + DC_GENLCK_CTRL);
+	val &= ~(DC_GC_ALPHA_FLICK_ENABLE |
+		 DC_GC_FLICKER_FILTER_ENABLE | DC_GC_FLICKER_FILTER_MASK);
+
+	/* Default scaling params */
+
+	writel((0x4000 << 16) | 0x4000, par->dc_regs + DC_GFX_SCALE);
+	writel(0, par->dc_regs + DC_IRQ_FILT_CTL);
+	writel(val, par->dc_regs + DC_GENLCK_CTRL);
+
+	/* FIXME:  Support compression */
+
+	if (info->fix.line_length > 4096)
+		dv = DC_DV_LINE_SIZE_8192;
+	else if (info->fix.line_length > 2048)
+		dv = DC_DV_LINE_SIZE_4096;
+	else if (info->fix.line_length > 1024)
+		dv = DC_DV_LINE_SIZE_2048;
+	else
+		dv = DC_DV_LINE_SIZE_1024;
+
+	max = info->fix.line_length * info->var.yres;
+	max = (max + 0x3FF) & 0xFFFFFC00;
+
+	writel(max | DC_DV_TOP_ENABLE, par->dc_regs + DC_DV_TOP);
+
+	val = readl(par->dc_regs + DC_DV_CTL) & ~DC_DV_LINE_SIZE_MASK;
+	writel(val | dv, par->dc_regs + DC_DV_CTL);
+
+	size = info->var.xres * (info->var.bits_per_pixel >> 3);
+
+	writel(info->fix.line_length >> 3, par->dc_regs + DC_GRAPHICS_PITCH);
+	writel((size + 7) >> 3, par->dc_regs + DC_LINE_SIZE);
+
+	/* Set default watermark values */
+
+	rdmsrl(MSR_LX_DC_SPARE, msrval);
+
+	msrval &= ~(DC_SPARE_DISABLE_CFIFO_HGO | DC_SPARE_VFIFO_ARB_SELECT |
+		    DC_SPARE_LOAD_WM_LPEN_MASK | DC_SPARE_WM_LPEN_OVRD |
+		    DC_SPARE_DISABLE_INIT_VID_PRI | DC_SPARE_DISABLE_VFIFO_WM);
+	msrval |= DC_SPARE_DISABLE_VFIFO_WM | DC_SPARE_DISABLE_INIT_VID_PRI;
+	wrmsrl(MSR_LX_DC_SPARE, msrval);
+
+	gcfg = DC_GCFG_DFLE;   /* Display fifo enable */
+	gcfg |= 0xB600;         /* Set default priority */
+	gcfg |= DC_GCFG_FDTY;  /* Set the frame dirty mode */
+
+	dcfg  = DC_DCFG_VDEN;  /* Enable video data */
+	dcfg |= DC_DCFG_GDEN;  /* Enable graphics */
+	dcfg |= DC_DCFG_TGEN;  /* Turn on the timing generator */
+	dcfg |= DC_DCFG_TRUP;  /* Update timings immediately */
+	dcfg |= DC_DCFG_PALB;  /* Palette bypass in > 8 bpp modes */
+	dcfg |= DC_DCFG_VISL;
+	dcfg |= DC_DCFG_DCEN;  /* Always center the display */
+
+	/* Set the current BPP mode */
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		dcfg |= DC_DCFG_DISP_MODE_8BPP;
+		break;
+
+	case 16:
+		dcfg |= DC_DCFG_DISP_MODE_16BPP | DC_DCFG_16BPP;
+		break;
+
+	case 32:
+	case 24:
+		dcfg |= DC_DCFG_DISP_MODE_24BPP;
+		break;
+	}
+
+	/* Now - set up the timings */
+
+	hactive = info->var.xres;
+	hblankstart = hactive;
+	hsyncstart = hblankstart + info->var.right_margin;
+	hsyncend =  hsyncstart + info->var.hsync_len;
+	hblankend = hsyncend + info->var.left_margin;
+	htotal = hblankend;
+
+	vactive = info->var.yres;
+	vblankstart = vactive;
+	vsyncstart = vblankstart + info->var.lower_margin;
+	vsyncend =  vsyncstart + info->var.vsync_len;
+	vblankend = vsyncend + info->var.upper_margin;
+	vtotal = vblankend;
+
+	writel((hactive - 1) | ((htotal - 1) << 16),
+	       par->dc_regs + DC_H_ACTIVE_TIMING);
+	writel((hblankstart - 1) | ((hblankend - 1) << 16),
+	       par->dc_regs + DC_H_BLANK_TIMING);
+	writel((hsyncstart - 1) | ((hsyncend - 1) << 16),
+	       par->dc_regs + DC_H_SYNC_TIMING);
+
+	writel((vactive - 1) | ((vtotal - 1) << 16),
+	       par->dc_regs + DC_V_ACTIVE_TIMING);
+
+	writel((vblankstart - 1) | ((vblankend - 1) << 16),
+	       par->dc_regs + DC_V_BLANK_TIMING);
+
+	writel((vsyncstart - 1)  | ((vsyncend - 1) << 16),
+	       par->dc_regs + DC_V_SYNC_TIMING);
+
+	writel( (info->var.xres - 1) << 16 | (info->var.yres - 1),
+		par->dc_regs + DC_FB_ACTIVE);
+
+	/* And re-enable the graphics output */
+	lx_graphics_enable(info);
+
+	/* Write the two main configuration registers */
+	writel(dcfg, par->dc_regs + DC_DISPLAY_CFG);
+	writel(0, par->dc_regs + DC_ARB_CFG);
+	writel(gcfg, par->dc_regs + DC_GENERAL_CFG);
+
+	/* Lock the DC registers */
+	writel(0, par->dc_regs + DC_UNLOCK);
+}
+
+void lx_set_palette_reg(struct fb_info *info, unsigned regno,
+			unsigned red, unsigned green, unsigned blue)
+{
+	struct lxfb_par *par = info->par;
+	int val;
+
+	/* Hardware palette is in RGB 8-8-8 format. */
+
+	val  = (red   << 8) & 0xff0000;
+	val |= (green)      & 0x00ff00;
+	val |= (blue  >> 8) & 0x0000ff;
+
+	writel(regno, par->dc_regs + DC_PAL_ADDRESS);
+	writel(val, par->dc_regs + DC_PAL_DATA);
+}
+
+int lx_blank_display(struct fb_info *info, int blank_mode)
+{
+	struct lxfb_par *par = info->par;
+	u32 dcfg, fp_pm;
+	int blank, hsync, vsync;
+
+	/* CRT power saving modes. */
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		blank = 0; hsync = 1; vsync = 1;
+		break;
+	case FB_BLANK_NORMAL:
+		blank = 1; hsync = 1; vsync = 1;
+		break;
+	case FB_BLANK_VSYNC_SUSPEND:
+		blank = 1; hsync = 1; vsync = 0;
+		break;
+	case FB_BLANK_HSYNC_SUSPEND:
+		blank = 1; hsync = 0; vsync = 1;
+		break;
+	case FB_BLANK_POWERDOWN:
+		blank = 1; hsync = 0; vsync = 0;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	dcfg = readl(par->df_regs + DF_DISPLAY_CFG);
+	dcfg &= ~(DF_DCFG_DAC_BL_EN
+		  | DF_DCFG_HSYNC_EN | DF_DCFG_VSYNC_EN);
+	if (!blank)
+		dcfg |= DF_DCFG_DAC_BL_EN;
+	if (hsync)
+		dcfg |= DF_DCFG_HSYNC_EN;
+	if (vsync)
+		dcfg |= DF_DCFG_VSYNC_EN;
+	writel(dcfg, par->df_regs + DF_DISPLAY_CFG);
+
+	/* Power on/off flat panel */
+
+	if (par->output & OUTPUT_PANEL) {
+		fp_pm = readl(par->df_regs + DF_FP_PM);
+		if (blank_mode == FB_BLANK_POWERDOWN)
+			fp_pm &= ~DF_FP_PM_P;
+		else
+			fp_pm |= DF_FP_PM_P;
+		writel(fp_pm, par->df_regs + DF_FP_PM);
+	}
+
+	return 0;
+}
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index eb1a481..b87ea21 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -379,10 +379,6 @@
 	if (fb_get_options("igafb", NULL))
 		return -ENODEV;
 
-        /* Do not attach when we have a serial console. */
-        if (!con_is_present())
-                return -ENXIO;
-
         pdev = pci_get_device(PCI_VENDOR_ID_INTERG,
                                PCI_DEVICE_ID_INTERG_1682, 0);
 	if (pdev == NULL) {
diff --git a/drivers/video/imacfb.c b/drivers/video/imacfb.c
index 18ea4a5..6455fd2 100644
--- a/drivers/video/imacfb.c
+++ b/drivers/video/imacfb.c
@@ -58,7 +58,7 @@
 static int manual_height;
 static int manual_width;
 
-static int set_system(struct dmi_system_id *id)
+static int set_system(const struct dmi_system_id *id)
 {
 	printk(KERN_INFO "imacfb: %s detected - set system to %ld\n",
 		id->ident, (long)id->driver_data);
diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c
index 5715b8a..94f4511 100644
--- a/drivers/video/imsttfb.c
+++ b/drivers/video/imsttfb.c
@@ -1391,7 +1391,7 @@
 		}
 	}
 
-#if USE_NV_MODES && defined(CONFIG_PPC)
+#if USE_NV_MODES && defined(CONFIG_PPC32)
 	{
 		int vmode = init_vmode, cmode = init_cmode;
 
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 16bc8d7..6a47682 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -924,10 +924,10 @@
 			if (m > pll->max_m)
 				m = pll->max_m - 1;
 			for (testm = m - 1; testm <= m; testm++) {
-				f_out = calc_vclock3(index, m, n, p);
+				f_out = calc_vclock3(index, testm, n, p);
 				if (splitm(index, testm, &m1, &m2)) {
-					WRN_MSG("cannot split m = %d\n", m);
-					n++;
+					WRN_MSG("cannot split m = %d\n",
+						testm);
 					continue;
 				}
 				if (clock > f_out)
@@ -1352,7 +1352,7 @@
 
 	/* turn off PLL */
 	tmp = INREG(dpll_reg);
-	dpll_reg &= ~DPLL_VCO_ENABLE;
+	tmp &= ~DPLL_VCO_ENABLE;
 	OUTREG(dpll_reg, tmp);
 
 	/* Set PLL parameters */
diff --git a/drivers/video/leo.c b/drivers/video/leo.c
index a038aa5..45b9a5d 100644
--- a/drivers/video/leo.c
+++ b/drivers/video/leo.c
@@ -525,130 +525,123 @@
 	var->transp.length = 0;
 }
 
-struct all_info {
-	struct fb_info info;
-	struct leo_par par;
-};
-
-static void leo_unmap_regs(struct of_device *op, struct all_info *all)
+static void leo_unmap_regs(struct of_device *op, struct fb_info *info,
+			   struct leo_par *par)
 {
-	if (all->par.lc_ss0_usr)
-		of_iounmap(&op->resource[0], all->par.lc_ss0_usr, 0x1000);
-	if (all->par.ld_ss0)
-		of_iounmap(&op->resource[0], all->par.ld_ss0, 0x1000);
-	if (all->par.ld_ss1)
-		of_iounmap(&op->resource[0], all->par.ld_ss1, 0x1000);
-	if (all->par.lx_krn)
-		of_iounmap(&op->resource[0], all->par.lx_krn, 0x1000);
-	if (all->par.cursor)
+	if (par->lc_ss0_usr)
+		of_iounmap(&op->resource[0], par->lc_ss0_usr, 0x1000);
+	if (par->ld_ss0)
+		of_iounmap(&op->resource[0], par->ld_ss0, 0x1000);
+	if (par->ld_ss1)
+		of_iounmap(&op->resource[0], par->ld_ss1, 0x1000);
+	if (par->lx_krn)
+		of_iounmap(&op->resource[0], par->lx_krn, 0x1000);
+	if (par->cursor)
 		of_iounmap(&op->resource[0],
-			   all->par.cursor, sizeof(struct leo_cursor));
-	if (all->info.screen_base)
-		of_iounmap(&op->resource[0], all->info.screen_base, 0x800000);
+			   par->cursor, sizeof(struct leo_cursor));
+	if (info->screen_base)
+		of_iounmap(&op->resource[0], info->screen_base, 0x800000);
 }
 
-static int __devinit leo_init_one(struct of_device *op)
+static int __devinit leo_probe(struct of_device *op, const struct of_device_id *match)
 {
 	struct device_node *dp = op->node;
-	struct all_info *all;
+	struct fb_info *info;
+	struct leo_par *par;
 	int linebytes, err;
 
-	all = kzalloc(sizeof(*all), GFP_KERNEL);
-	if (!all)
-		return -ENOMEM;
+	info = framebuffer_alloc(sizeof(struct leo_par), &op->dev);
 
-	spin_lock_init(&all->par.lock);
+	err = -ENOMEM;
+	if (!info)
+		goto out_err;
+	par = info->par;
 
-	all->par.physbase = op->resource[0].start;
-	all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
+	spin_lock_init(&par->lock);
 
-	sbusfb_fill_var(&all->info.var, dp->node, 32);
-	leo_fixup_var_rgb(&all->info.var);
+	par->physbase = op->resource[0].start;
+	par->which_io = op->resource[0].flags & IORESOURCE_BITS;
+
+	sbusfb_fill_var(&info->var, dp->node, 32);
+	leo_fixup_var_rgb(&info->var);
 
 	linebytes = of_getintprop_default(dp, "linebytes",
-					  all->info.var.xres);
-	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+					  info->var.xres);
+	par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
 
-	all->par.lc_ss0_usr =
+	par->lc_ss0_usr =
 		of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR,
 			   0x1000, "leolc ss0usr");
-	all->par.ld_ss0 =
+	par->ld_ss0 =
 		of_ioremap(&op->resource[0], LEO_OFF_LD_SS0,
 			   0x1000, "leold ss0");
-	all->par.ld_ss1 =
+	par->ld_ss1 =
 		of_ioremap(&op->resource[0], LEO_OFF_LD_SS1,
 			   0x1000, "leold ss1");
-	all->par.lx_krn =
+	par->lx_krn =
 		of_ioremap(&op->resource[0], LEO_OFF_LX_KRN,
 			   0x1000, "leolx krn");
-	all->par.cursor =
+	par->cursor =
 		of_ioremap(&op->resource[0], LEO_OFF_LX_CURSOR,
 			   sizeof(struct leo_cursor), "leolx cursor");
-	all->info.screen_base = 
+	info->screen_base =
 		of_ioremap(&op->resource[0], LEO_OFF_SS0,
 			   0x800000, "leo ram");
-	if (!all->par.lc_ss0_usr ||
-	    !all->par.ld_ss0 ||
-	    !all->par.ld_ss1 ||
-	    !all->par.lx_krn ||
-	    !all->par.cursor ||
-	    !all->info.screen_base) {
-		leo_unmap_regs(op, all);
-		kfree(all);
-		return -ENOMEM;
-	}
+	if (!par->lc_ss0_usr ||
+	    !par->ld_ss0 ||
+	    !par->ld_ss1 ||
+	    !par->lx_krn ||
+	    !par->cursor ||
+	    !info->screen_base)
+		goto out_unmap_regs;
 
-	all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
-	all->info.fbops = &leo_ops;
-	all->info.par = &all->par;
+	info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+	info->fbops = &leo_ops;
 
-	leo_init_wids(&all->info);
-	leo_init_hw(&all->info);
+	leo_init_wids(info);
+	leo_init_hw(info);
 
-	leo_blank(0, &all->info);
+	leo_blank(0, info);
 
-	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
-		leo_unmap_regs(op, all);
-		kfree(all);
-		return -ENOMEM;;
-	}
+	if (fb_alloc_cmap(&info->cmap, 256, 0))
+		goto out_unmap_regs;
 
-	leo_init_fix(&all->info, dp);
+	leo_init_fix(info, dp);
 
-	err = register_framebuffer(&all->info);
-	if (err < 0) {
-		fb_dealloc_cmap(&all->info.cmap);
-		leo_unmap_regs(op, all);
-		kfree(all);
-		return err;
-	}
+	err = register_framebuffer(info);
+	if (err < 0)
+		goto out_dealloc_cmap;
 
-	dev_set_drvdata(&op->dev, all);
+	dev_set_drvdata(&op->dev, info);
 
 	printk("%s: leo at %lx:%lx\n",
 	       dp->full_name,
-	       all->par.which_io, all->par.physbase);
+	       par->which_io, par->physbase);
 
 	return 0;
-}
 
-static int __devinit leo_probe(struct of_device *dev, const struct of_device_id *match)
-{
-	struct of_device *op = to_of_device(&dev->dev);
+out_dealloc_cmap:
+	fb_dealloc_cmap(&info->cmap);
 
-	return leo_init_one(op);
+out_unmap_regs:
+	leo_unmap_regs(op, info, par);
+	framebuffer_release(info);
+
+out_err:
+	return err;
 }
 
 static int __devexit leo_remove(struct of_device *op)
 {
-	struct all_info *all = dev_get_drvdata(&op->dev);
+	struct fb_info *info = dev_get_drvdata(&op->dev);
+	struct leo_par *par = info->par;
 
-	unregister_framebuffer(&all->info);
-	fb_dealloc_cmap(&all->info.cmap);
+	unregister_framebuffer(info);
+	fb_dealloc_cmap(&info->cmap);
 
-	leo_unmap_regs(op, all);
+	leo_unmap_regs(op, info, par);
 
-	kfree(all);
+	framebuffer_release(info);
 
 	dev_set_drvdata(&op->dev, NULL);
 
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
index da219c0..9de1c11 100644
--- a/drivers/video/logo/Kconfig
+++ b/drivers/video/logo/Kconfig
@@ -12,7 +12,7 @@
 
 config FB_LOGO_EXTRA
 	bool
-	depends on FB
+	depends on FB=y
 	default y if SPU_BASE
 
 config LOGO_LINUX_MONO
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
index 80c0361..2b0f799 100644
--- a/drivers/video/logo/logo.c
+++ b/drivers/video/logo/logo.c
@@ -34,8 +34,11 @@
 extern const struct linux_logo logo_superh_clut224;
 extern const struct linux_logo logo_m32r_clut224;
 
-
-const struct linux_logo *fb_find_logo(int depth)
+/* logo's are marked __initdata. Use __init_refok to tell
+ * modpost that it is intended that this function uses data
+ * marked __initdata.
+ */
+const struct linux_logo * __init_refok fb_find_logo(int depth)
 {
 	const struct linux_logo *logo = NULL;
 
diff --git a/drivers/video/matrox/g450_pll.c b/drivers/video/matrox/g450_pll.c
index 7c76e07..d42346e 100644
--- a/drivers/video/matrox/g450_pll.c
+++ b/drivers/video/matrox/g450_pll.c
@@ -331,16 +331,19 @@
 					tmp |= M1064_XPIXCLKCTRL_PLL_UP;
 				}
 				matroxfb_DAC_out(PMINFO M1064_XPIXCLKCTRL, tmp);
-#ifdef __powerpc__
-				/* This is necessary to avoid jitter on PowerPC
-				 * (OpenFirmware) systems, but apparently
-				 * introduces jitter, at least on a x86-64
-				 * using DVI.
-				 * A simple workaround is disable for non-PPC.
-				 */
-				matroxfb_DAC_out(PMINFO M1064_XDVICLKCTRL, 0);
-#endif /* __powerpc__ */
-				matroxfb_DAC_out(PMINFO M1064_XPWRCTRL, xpwrctrl);
+				/* DVI PLL preferred for frequencies up to
+				   panel link max, standard PLL otherwise */
+				if (fout >= MINFO->max_pixel_clock_panellink)
+					tmp = 0;
+				else tmp =
+					M1064_XDVICLKCTRL_DVIDATAPATHSEL |
+					M1064_XDVICLKCTRL_C1DVICLKSEL |
+					M1064_XDVICLKCTRL_C1DVICLKEN |
+					M1064_XDVICLKCTRL_DVILOOPCTL |
+					M1064_XDVICLKCTRL_P1LOOPBWDTCTL;
+				matroxfb_DAC_out(PMINFO M1064_XDVICLKCTRL,tmp);
+				matroxfb_DAC_out(PMINFO M1064_XPWRCTRL,
+						 xpwrctrl);
 
 				matroxfb_DAC_unlock_irqrestore(flags);
 			}
diff --git a/drivers/video/matrox/matroxfb_DAC1064.h b/drivers/video/matrox/matroxfb_DAC1064.h
index df39c31..7a98ce8 100644
--- a/drivers/video/matrox/matroxfb_DAC1064.h
+++ b/drivers/video/matrox/matroxfb_DAC1064.h
@@ -33,6 +33,21 @@
 #define     M1064_XCURCTRL_3COLOR	0x01	/* transparent, 0, 1, 2 */
 #define     M1064_XCURCTRL_XGA		0x02	/* 0, 1, transparent, complement */
 #define     M1064_XCURCTRL_XWIN		0x03	/* transparent, transparent, 0, 1 */
+	/* drive DVI by standard(0)/DVI(1) PLL */
+	/* if set(1), C?DVICLKEN and C?DVICLKSEL must be set(1) */
+#define      M1064_XDVICLKCTRL_DVIDATAPATHSEL   0x01
+	/* drive CRTC1 by standard(0)/DVI(1) PLL */
+#define      M1064_XDVICLKCTRL_C1DVICLKSEL      0x02
+	/* drive CRTC2 by standard(0)/DVI(1) PLL */
+#define      M1064_XDVICLKCTRL_C2DVICLKSEL      0x04
+	/* pixel clock allowed to(0)/blocked from(1) driving CRTC1 */
+#define      M1064_XDVICLKCTRL_C1DVICLKEN       0x08
+	/* DVI PLL loop filter bandwidth selection bits */
+#define      M1064_XDVICLKCTRL_DVILOOPCTL       0x30
+	/* CRTC2 pixel clock allowed to(0)/blocked from(1) driving CRTC2 */
+#define      M1064_XDVICLKCTRL_C2DVICLKEN       0x40
+	/* P1PLL loop filter bandwith selection */
+#define      M1064_XDVICLKCTRL_P1LOOPBWDTCTL    0x80
 #define M1064_XCURCOL0RED	0x08
 #define M1064_XCURCOL0GREEN	0x09
 #define M1064_XCURCOL0BLUE	0x0A
diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h
index d59577c..f3107ad 100644
--- a/drivers/video/matrox/matroxfb_base.h
+++ b/drivers/video/matrox/matroxfb_base.h
@@ -424,6 +424,7 @@
 		      } mmio;
 
 	unsigned int	max_pixel_clock;
+	unsigned int	max_pixel_clock_panellink;
 
 	struct matrox_switch*	hw_switch;
 
diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c
index 5948e54..ab7fb50 100644
--- a/drivers/video/matrox/matroxfb_misc.c
+++ b/drivers/video/matrox/matroxfb_misc.c
@@ -658,6 +658,7 @@
 		MINFO->values.reg.mctlwtst_core = (MINFO->values.reg.mctlwtst & ~7) |
 		                                  wtst_xlat[MINFO->values.reg.mctlwtst & 7];
 	}
+	MINFO->max_pixel_clock_panellink = bd->pins[47] * 4000;
 	return 0;
 }
 
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
index 43f62d8..443e3c8 100644
--- a/drivers/video/nvidia/nv_backlight.c
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -50,7 +50,7 @@
 
 static int nvidia_bl_update_status(struct backlight_device *bd)
 {
-	struct nvidia_par *par = class_get_devdata(&bd->class_dev);
+	struct nvidia_par *par = bl_get_data(bd);
 	u32 tmp_pcrt, tmp_pmc, fpcontrol;
 	int level;
 
diff --git a/drivers/video/output.c b/drivers/video/output.c
index 1473f2c..f2df551 100644
--- a/drivers/video/output.c
+++ b/drivers/video/output.c
@@ -31,7 +31,8 @@
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Luming Yu <luming.yu@intel.com>");
 
-static ssize_t video_output_show_state(struct class_device *dev,char *buf)
+static ssize_t video_output_show_state(struct device *dev,
+				       struct device_attribute *attr, char *buf)
 {
 	ssize_t ret_size = 0;
 	struct output_device *od = to_output_device(dev);
@@ -40,8 +41,9 @@
 	return ret_size;
 }
 
-static ssize_t video_output_store_state(struct class_device *dev,
-	const char *buf,size_t count)
+static ssize_t video_output_store_state(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf,size_t count)
 {
 	char *endp;
 	struct output_device *od = to_output_device(dev);
@@ -60,21 +62,22 @@
 	return count;
 }
 
-static void video_output_class_release(struct class_device *dev)
+static void video_output_release(struct device *dev)
 {
 	struct output_device *od = to_output_device(dev);
 	kfree(od);
 }
 
-static struct class_device_attribute video_output_attributes[] = {
+static struct device_attribute video_output_attributes[] = {
 	__ATTR(state, 0644, video_output_show_state, video_output_store_state),
 	__ATTR_NULL,
 };
 
+
 static struct class video_output_class = {
 	.name = "video_output",
-	.release = video_output_class_release,
-	.class_dev_attrs = video_output_attributes,
+	.dev_release = video_output_release,
+	.dev_attrs = video_output_attributes,
 };
 
 struct output_device *video_output_register(const char *name,
@@ -91,11 +94,11 @@
 		goto error_return;
 	}
 	new_dev->props = op;
-	new_dev->class_dev.class = &video_output_class;
-	new_dev->class_dev.dev = dev;
-	strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN);
-	class_set_devdata(&new_dev->class_dev,devdata);
-	ret_code = class_device_register(&new_dev->class_dev);
+	new_dev->dev.class = &video_output_class;
+	new_dev->dev.parent = dev;
+	strlcpy(new_dev->dev.bus_id,name, BUS_ID_SIZE);
+	dev_set_drvdata(&new_dev->dev, devdata);
+	ret_code = device_register(&new_dev->dev);
 	if (ret_code) {
 		kfree(new_dev);
 		goto error_return;
@@ -111,7 +114,7 @@
 {
 	if (!dev)
 		return;
-	class_device_unregister(&dev->class_dev);
+	device_unregister(&dev->dev);
 }
 EXPORT_SYMBOL(video_output_unregister);
 
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c
index 637b78b..5849606 100644
--- a/drivers/video/p9100.c
+++ b/drivers/video/p9100.c
@@ -255,107 +255,95 @@
 	info->fix.accel = FB_ACCEL_SUN_CGTHREE;
 }
 
-struct all_info {
-	struct fb_info info;
-	struct p9100_par par;
-};
-
-static int __devinit p9100_init_one(struct of_device *op)
+static int __devinit p9100_probe(struct of_device *op, const struct of_device_id *match)
 {
 	struct device_node *dp = op->node;
-	struct all_info *all;
+	struct fb_info *info;
+	struct p9100_par *par;
 	int linebytes, err;
 
-	all = kzalloc(sizeof(*all), GFP_KERNEL);
-	if (!all)
-		return -ENOMEM;
+	info = framebuffer_alloc(sizeof(struct p9100_par), &op->dev);
 
-	spin_lock_init(&all->par.lock);
+	err = -ENOMEM;
+	if (!info)
+		goto out_err;
+	par = info->par;
+
+	spin_lock_init(&par->lock);
 
 	/* This is the framebuffer and the only resource apps can mmap.  */
-	all->par.physbase = op->resource[2].start;
-	all->par.which_io = op->resource[2].flags & IORESOURCE_BITS;
+	par->physbase = op->resource[2].start;
+	par->which_io = op->resource[2].flags & IORESOURCE_BITS;
 
-	sbusfb_fill_var(&all->info.var, dp->node, 8);
-	all->info.var.red.length = 8;
-	all->info.var.green.length = 8;
-	all->info.var.blue.length = 8;
+	sbusfb_fill_var(&info->var, dp->node, 8);
+	info->var.red.length = 8;
+	info->var.green.length = 8;
+	info->var.blue.length = 8;
 
-	linebytes = of_getintprop_default(dp, "linebytes",
-					  all->info.var.xres);
-	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+	linebytes = of_getintprop_default(dp, "linebytes", info->var.xres);
+	par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
 
-	all->par.regs = of_ioremap(&op->resource[0], 0,
-				   sizeof(struct p9100_regs), "p9100 regs");
-	if (!all->par.regs) {
-		kfree(all);
-		return -ENOMEM;
-	}
+	par->regs = of_ioremap(&op->resource[0], 0,
+			       sizeof(struct p9100_regs), "p9100 regs");
+	if (!par->regs)
+		goto out_release_fb;
 
-	all->info.flags = FBINFO_DEFAULT;
-	all->info.fbops = &p9100_ops;
-	all->info.screen_base = of_ioremap(&op->resource[2], 0,
-					   all->par.fbsize, "p9100 ram");
-	if (!all->info.screen_base) {
-		of_iounmap(&op->resource[0],
-			   all->par.regs, sizeof(struct p9100_regs));
-		kfree(all);
-		return -ENOMEM;
-	}
-	all->info.par = &all->par;
+	info->flags = FBINFO_DEFAULT;
+	info->fbops = &p9100_ops;
+	info->screen_base = of_ioremap(&op->resource[2], 0,
+				       par->fbsize, "p9100 ram");
+	if (!info->screen_base)
+		goto out_unmap_regs;
 
-	p9100_blank(0, &all->info);
+	p9100_blank(0, info);
 
-	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
-		of_iounmap(&op->resource[0],
-			   all->par.regs, sizeof(struct p9100_regs));
-		of_iounmap(&op->resource[2],
-			   all->info.screen_base, all->par.fbsize);
-		kfree(all);
-		return -ENOMEM;
-	}
+	if (fb_alloc_cmap(&info->cmap, 256, 0))
+		goto out_unmap_screen;
 
-	p9100_init_fix(&all->info, linebytes, dp);
+	p9100_init_fix(info, linebytes, dp);
 
-	err = register_framebuffer(&all->info);
-	if (err < 0) {
-		fb_dealloc_cmap(&all->info.cmap);
-		of_iounmap(&op->resource[0],
-			   all->par.regs, sizeof(struct p9100_regs));
-		of_iounmap(&op->resource[2],
-			   all->info.screen_base, all->par.fbsize);
-		kfree(all);
-		return err;
-	}
-	fb_set_cmap(&all->info.cmap, &all->info);
+	err = register_framebuffer(info);
+	if (err < 0)
+		goto out_dealloc_cmap;
 
-	dev_set_drvdata(&op->dev, all);
+	fb_set_cmap(&info->cmap, info);
+
+	dev_set_drvdata(&op->dev, info);
 
 	printk("%s: p9100 at %lx:%lx\n",
 	       dp->full_name,
-	       all->par.which_io, all->par.physbase);
+	       par->which_io, par->physbase);
 
 	return 0;
-}
 
-static int __devinit p9100_probe(struct of_device *dev, const struct of_device_id *match)
-{
-	struct of_device *op = to_of_device(&dev->dev);
+out_dealloc_cmap:
+	fb_dealloc_cmap(&info->cmap);
 
-	return p9100_init_one(op);
+out_unmap_screen:
+	of_iounmap(&op->resource[2], info->screen_base, par->fbsize);
+
+out_unmap_regs:
+	of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs));
+
+out_release_fb:
+	framebuffer_release(info);
+
+out_err:
+	return err;
 }
 
 static int __devexit p9100_remove(struct of_device *op)
 {
-	struct all_info *all = dev_get_drvdata(&op->dev);
+	struct fb_info *info = dev_get_drvdata(&op->dev);
+	struct p9100_par *par = info->par;
 
-	unregister_framebuffer(&all->info);
-	fb_dealloc_cmap(&all->info.cmap);
+	unregister_framebuffer(info);
+	fb_dealloc_cmap(&info->cmap);
 
-	of_iounmap(&op->resource[0], all->par.regs, sizeof(struct p9100_regs));
-	of_iounmap(&op->resource[2], all->info.screen_base, all->par.fbsize);
+	of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs));
+	of_iounmap(&op->resource[2], info->screen_base, par->fbsize);
 
-	kfree(all);
+	framebuffer_release(info);
 
 	dev_set_drvdata(&op->dev, NULL);
 
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index 8503e73..cbe71a5 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -17,6 +17,8 @@
  *  more details.
  */
 
+#undef DEBUG
+
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -535,33 +537,35 @@
 	volatile __u8		*fbuffer;
 	int			bank0, bank1, bank2, bank3, rc;
 
-	printk(KERN_INFO "platinumfb: Found Apple Platinum video hardware\n");
+	dev_info(&odev->dev, "Found Apple Platinum video hardware\n");
 
 	info = framebuffer_alloc(sizeof(*pinfo), &odev->dev);
-	if (info == NULL)
+	if (info == NULL) {
+		dev_err(&odev->dev, "Failed to allocate fbdev !\n");
 		return -ENOMEM;
+	}
 	pinfo = info->par;
 
 	if (of_address_to_resource(dp, 0, &pinfo->rsrc_reg) ||
 	    of_address_to_resource(dp, 1, &pinfo->rsrc_fb)) {
-		printk(KERN_ERR "platinumfb: Can't get resources\n");
+		dev_err(&odev->dev, "Can't get resources\n");
 		framebuffer_release(info);
 		return -ENXIO;
 	}
-	if (!request_mem_region(pinfo->rsrc_reg.start,
-				pinfo->rsrc_reg.start -
-				pinfo->rsrc_reg.end + 1,
-				"platinumfb registers")) {
-		framebuffer_release(info);
-		return -ENXIO;
-	}
+	dev_dbg(&odev->dev, " registers  : 0x%llx...0x%llx\n",
+		(unsigned long long)pinfo->rsrc_reg.start,
+		(unsigned long long)pinfo->rsrc_reg.end);
+	dev_dbg(&odev->dev, " framebuffer: 0x%llx...0x%llx\n",
+		(unsigned long long)pinfo->rsrc_fb.start,
+		(unsigned long long)pinfo->rsrc_fb.end);
+
+	/* Do not try to request register space, they overlap with the
+	 * northbridge and that can fail. Only request framebuffer
+	 */
 	if (!request_mem_region(pinfo->rsrc_fb.start,
-				pinfo->rsrc_fb.start
-				- pinfo->rsrc_fb.end + 1,
+				pinfo->rsrc_fb.end - pinfo->rsrc_fb.start + 1,
 				"platinumfb framebuffer")) {
-		release_mem_region(pinfo->rsrc_reg.start,
-				   pinfo->rsrc_reg.end -
-				   pinfo->rsrc_reg.start + 1);
+		printk(KERN_ERR "platinumfb: Can't request framebuffer !\n");
 		framebuffer_release(info);
 		return -ENXIO;
 	}
@@ -600,7 +604,8 @@
 	bank2 = fbuffer[0x200000] == 0x56;
 	bank3 = fbuffer[0x300000] == 0x78;
 	pinfo->total_vram = (bank0 + bank1 + bank2 + bank3) * 0x100000;
-	printk(KERN_INFO "platinumfb: Total VRAM = %dMB (%d%d%d%d)\n", (int) (pinfo->total_vram / 1024 / 1024),
+	printk(KERN_INFO "platinumfb: Total VRAM = %dMB (%d%d%d%d)\n",
+	       (unsigned int) (pinfo->total_vram / 1024 / 1024),
 	       bank3, bank2, bank1, bank0);
 
 	/*
@@ -644,16 +649,15 @@
         unregister_framebuffer (info);
 	
 	/* Unmap frame buffer and registers */
+	iounmap(pinfo->frame_buffer);
+	iounmap(pinfo->platinum_regs);
+	iounmap(pinfo->cmap_regs);
+
 	release_mem_region(pinfo->rsrc_fb.start,
 			   pinfo->rsrc_fb.end -
 			   pinfo->rsrc_fb.start + 1);
-	release_mem_region(pinfo->rsrc_reg.start,
-			   pinfo->rsrc_reg.end -
-			   pinfo->rsrc_reg.start + 1);
-	iounmap(pinfo->frame_buffer);
-	iounmap(pinfo->platinum_regs);
+
 	release_mem_region(pinfo->cmap_regs_phys, 0x1000);
-	iounmap(pinfo->cmap_regs);
 
 	framebuffer_release(info);
 
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c
index 3972aa8..646ec82 100644
--- a/drivers/video/ps3fb.c
+++ b/drivers/video/ps3fb.c
@@ -1067,7 +1067,7 @@
 	info->fix.smem_len = ps3fb_videomemory.size - offset;
 	info->pseudo_palette = info->par;
 	info->par = NULL;
-	info->flags = FBINFO_FLAG_DEFAULT;
+	info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST;
 
 	retval = fb_alloc_cmap(&info->cmap, 256, 0);
 	if (retval < 0)
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
index 0f88c30..7d6c298 100644
--- a/drivers/video/pvr2fb.c
+++ b/drivers/video/pvr2fb.c
@@ -94,6 +94,7 @@
 #define DISP_DIWCONF (DISP_BASE + 0xe8)
 #define DISP_DIWHSTRT (DISP_BASE + 0xec)
 #define DISP_DIWVSTRT (DISP_BASE + 0xf0)
+#define DISP_PIXDEPTH (DISP_BASE + 0x108)
 
 /* Pixel clocks, one for TV output, doubled for VGA output */
 #define TV_CLK 74239
@@ -143,6 +144,7 @@
 	unsigned char is_lowres;	/* Is horizontal pixel-doubling enabled? */
 
 	unsigned long mmio_base;	/* MMIO base */
+	u32 palette[16];
 } *currentpar;
 
 static struct fb_info *fb_info;
@@ -599,6 +601,7 @@
 
 	/* bits per pixel */
 	fb_writel(fb_readl(DISP_DIWMODE) | (--bytesperpixel << 2), DISP_DIWMODE);
+	fb_writel(bytesperpixel << 2, DISP_PIXDEPTH);
 
 	/* video enable, color sync, interlace,
 	 * hsync and vsync polarity (currently unused) */
@@ -790,7 +793,7 @@
 	fb_info->fbops		= &pvr2fb_ops;
 	fb_info->fix		= pvr2_fix;
 	fb_info->par		= currentpar;
-	fb_info->pseudo_palette	= (void *)(fb_info->par + 1);
+	fb_info->pseudo_palette	= currentpar->palette;
 	fb_info->flags		= FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
 
 	if (video_output == VO_VGA)
@@ -807,6 +810,8 @@
 
 	if (register_framebuffer(fb_info) < 0)
 		goto out_err;
+	/*Must write PIXDEPTH to register before anything is displayed - so force init */
+	pvr2_init_display(fb_info);
 
 	modememused = get_line_length(fb_info->var.xres_virtual,
 				      fb_info->var.bits_per_pixel);
@@ -1082,15 +1087,15 @@
 #endif
 	size = sizeof(struct fb_info) + sizeof(struct pvr2fb_par) + 16 * sizeof(u32);
 
-	fb_info = kmalloc(size, GFP_KERNEL);
+	fb_info = framebuffer_alloc(sizeof(struct pvr2fb_par), NULL);
+
 	if (!fb_info) {
 		printk(KERN_ERR "Failed to allocate memory for fb_info\n");
 		return -ENOMEM;
 	}
 
-	memset(fb_info, 0, size);
 
-	currentpar = (struct pvr2fb_par *)(fb_info + 1);
+	currentpar = fb_info->par;
 
 	for (i = 0; i < ARRAY_SIZE(board_driver); i++) {
 		struct pvr2_board *pvr_board = board_driver + i;
@@ -1103,7 +1108,7 @@
 		if (ret != 0) {
 			printk(KERN_ERR "pvr2fb: Failed init of %s device\n",
 				pvr_board->name);
-			kfree(fb_info);
+			framebuffer_release(fb_info);
 			break;
 		}
 	}
@@ -1127,7 +1132,7 @@
 #endif
 
 	unregister_framebuffer(fb_info);
-	kfree(fb_info);
+	framebuffer_release(fb_info);
 }
 
 module_init(pvr2fb_init);
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 81e571d..a280a52 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -66,7 +66,7 @@
 
 #ifdef CONFIG_FB_PXA_PARAMETERS
 #define PXAFB_OPTIONS_SIZE 256
-static char g_options[PXAFB_OPTIONS_SIZE] __initdata = "";
+static char g_options[PXAFB_OPTIONS_SIZE] __devinitdata = "";
 #endif
 
 static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state)
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 0fe5478..5c47968 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -307,7 +307,7 @@
 
 static int riva_bl_update_status(struct backlight_device *bd)
 {
-	struct riva_par *par = class_get_devdata(&bd->class_dev);
+	struct riva_par *par = bl_get_data(bd);
 	U032 tmp_pcrt, tmp_pmc;
 	int level;
 
@@ -2146,7 +2146,7 @@
  * ------------------------------------------------------------------------- */
 
 #ifndef MODULE
-static int __init rivafb_setup(char *options)
+static int __devinit rivafb_setup(char *options)
 {
 	char *this_opt;
 
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index ed34260..8a4c647 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -474,6 +474,7 @@
 {
 	unsigned long flags;
 	unsigned long irqen;
+	void __iomem *regs = fbi->io;
 
 	local_irq_save(flags);
 
@@ -483,9 +484,9 @@
 		fbi->palette_ready = 1;
 
 		/* enable IRQ */
-		irqen = readl(S3C2410_LCDINTMSK);
+		irqen = readl(regs + S3C2410_LCDINTMSK);
 		irqen &= ~S3C2410_LCDINT_FRSYNC;
-		writel(irqen, S3C2410_LCDINTMSK);
+		writel(irqen, regs + S3C2410_LCDINTMSK);
 	}
 
 	local_irq_restore(flags);
@@ -680,6 +681,7 @@
 static int s3c2410fb_init_registers(struct s3c2410fb_info *fbi)
 {
 	unsigned long flags;
+	void __iomem *regs = fbi->io;
 
 	/* Initialise LCD with values from haret */
 
@@ -694,25 +696,25 @@
 
 	local_irq_restore(flags);
 
-	writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);
-	writel(fbi->regs.lcdcon2, S3C2410_LCDCON2);
-	writel(fbi->regs.lcdcon3, S3C2410_LCDCON3);
-	writel(fbi->regs.lcdcon4, S3C2410_LCDCON4);
-	writel(fbi->regs.lcdcon5, S3C2410_LCDCON5);
+	writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1);
+	writel(fbi->regs.lcdcon2, regs + S3C2410_LCDCON2);
+	writel(fbi->regs.lcdcon3, regs + S3C2410_LCDCON3);
+	writel(fbi->regs.lcdcon4, regs + S3C2410_LCDCON4);
+	writel(fbi->regs.lcdcon5, regs + S3C2410_LCDCON5);
 
  	s3c2410fb_set_lcdaddr(fbi);
 
 	dprintk("LPCSEL    = 0x%08lx\n", mach_info->lpcsel);
-	writel(mach_info->lpcsel, S3C2410_LPCSEL);
+	writel(mach_info->lpcsel, regs + S3C2410_LPCSEL);
 
-	dprintk("replacing TPAL %08x\n", readl(S3C2410_TPAL));
+	dprintk("replacing TPAL %08x\n", readl(regs + S3C2410_TPAL));
 
 	/* ensure temporary palette disabled */
-	writel(0x00, S3C2410_TPAL);
+	writel(0x00, regs + S3C2410_TPAL);
 
 	/* Enable video by setting the ENVID bit to 1 */
 	fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID;
-	writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);
+	writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1);
 	return 0;
 }
 
@@ -720,6 +722,7 @@
 {
 	unsigned int i;
 	unsigned long ent;
+	void __iomem *regs = fbi->io;
 
 	fbi->palette_ready = 0;
 
@@ -727,14 +730,14 @@
 		if ((ent = fbi->palette_buffer[i]) == PALETTE_BUFF_CLEAR)
 			continue;
 
-		writel(ent, S3C2410_TFTPAL(i));
+		writel(ent, regs + S3C2410_TFTPAL(i));
 
 		/* it seems the only way to know exactly
 		 * if the palette wrote ok, is to check
 		 * to see if the value verifies ok
 		 */
 
-		if (readw(S3C2410_TFTPAL(i)) == ent)
+		if (readw(regs + S3C2410_TFTPAL(i)) == ent)
 			fbi->palette_buffer[i] = PALETTE_BUFF_CLEAR;
 		else
 			fbi->palette_ready = 1;   /* retry */
@@ -744,14 +747,15 @@
 static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
 {
 	struct s3c2410fb_info *fbi = dev_id;
-	unsigned long lcdirq = readl(S3C2410_LCDINTPND);
+	void __iomem *regs = fbi->io;
+	unsigned long lcdirq = readl(regs + S3C2410_LCDINTPND);
 
 	if (lcdirq & S3C2410_LCDINT_FRSYNC) {
 		if (fbi->palette_ready)
 			s3c2410fb_write_palette(fbi);
 
-		writel(S3C2410_LCDINT_FRSYNC, S3C2410_LCDINTPND);
-		writel(S3C2410_LCDINT_FRSYNC, S3C2410_LCDSRCPND);
+		writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDINTPND);
+		writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDSRCPND);
 	}
 
 	return IRQ_HANDLED;
@@ -764,9 +768,11 @@
 	struct s3c2410fb_info *info;
 	struct fb_info	   *fbinfo;
 	struct s3c2410fb_hw *mregs;
+	struct resource *res;
 	int ret;
 	int irq;
 	int i;
+	int size;
 	u32 lcdcon1;
 
 	mach_info = pdev->dev.platform_data;
@@ -788,11 +794,32 @@
 		return -ENOMEM;
 	}
 
-
 	info = fbinfo->par;
 	info->fb = fbinfo;
 	info->dev = &pdev->dev;
 
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res == NULL) {
+		dev_err(&pdev->dev, "failed to get memory registersn");
+		ret = -ENXIO;
+		goto dealloc_fb;
+	}
+
+	size = (res->end - res->start)+1;
+	info->mem = request_mem_region(res->start, size, pdev->name);
+	if (info->mem == NULL) {
+		dev_err(&pdev->dev, "failed to get memory region\n");
+		ret = -ENOENT;
+		goto dealloc_fb;
+	}
+
+	info->io = ioremap(res->start, size);
+	if (info->io == NULL) {
+		dev_err(&pdev->dev, "ioremap() of registers failed\n");
+		ret = -ENXIO;
+		goto release_mem;
+	}
+
 	platform_set_drvdata(pdev, fbinfo);
 
 	dprintk("devinit\n");
@@ -803,8 +830,8 @@
 
 	/* Stop the video and unset ENVID if set */
 	info->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;
-	lcdcon1 = readl(S3C2410_LCDCON1);
-	writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);
+	lcdcon1 = readl(info->io + S3C2410_LCDCON1);
+	writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1);
 
 	info->mach_info		    = pdev->dev.platform_data;
 
@@ -855,19 +882,11 @@
 	for (i = 0; i < 256; i++)
 		info->palette_buffer[i] = PALETTE_BUFF_CLEAR;
 
-	if (!request_mem_region((unsigned long)S3C24XX_VA_LCD, SZ_1M, "s3c2410-lcd")) {
-		ret = -EBUSY;
-		goto dealloc_fb;
-	}
-
-
-	dprintk("got LCD region\n");
-
 	ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);
 	if (ret) {
 		dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret);
 		ret = -EBUSY;
-		goto release_mem;
+		goto release_regs;
 	}
 
 	info->clk = clk_get(NULL, "lcd");
@@ -889,6 +908,7 @@
 		ret = -ENOMEM;
 		goto release_clock;
 	}
+
 	dprintk("got video memory\n");
 
 	ret = s3c2410fb_init_registers(info);
@@ -916,8 +936,11 @@
 	clk_put(info->clk);
 release_irq:
 	free_irq(irq,info);
+release_regs:
+	iounmap(info->io);
 release_mem:
- 	release_mem_region((unsigned long)S3C24XX_VA_LCD, S3C24XX_SZ_LCD);
+	release_resource(info->mem);
+	kfree(info->mem);
 dealloc_fb:
 	framebuffer_release(fbinfo);
 	return ret;
@@ -935,7 +958,7 @@
 	local_irq_save(flags);
 
 	fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;
-	writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);
+	writel(fbi->regs.lcdcon1, fbi->io + S3C2410_LCDCON1);
 
 	local_irq_restore(flags);
 }
@@ -962,7 +985,10 @@
 
 	irq = platform_get_irq(pdev, 0);
 	free_irq(irq,info);
-	release_mem_region((unsigned long)S3C24XX_VA_LCD, S3C24XX_SZ_LCD);
+
+	release_resource(info->mem);
+	kfree(info->mem);
+	iounmap(info->io);
 	unregister_framebuffer(fbinfo);
 
 	return 0;
diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h
index f3f8a8e..17c7915 100644
--- a/drivers/video/s3c2410fb.h
+++ b/drivers/video/s3c2410fb.h
@@ -30,6 +30,9 @@
 	struct device		*dev;
 	struct clk		*clk;
 
+	struct resource		*mem;
+	void __iomem		*io;
+
 	struct s3c2410fb_mach_info *mach_info;
 
 	/* raw memory addresses */
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index 3d7507a..b855f4a 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -2174,11 +2174,10 @@
 
 #if defined(CONFIG_FB_SAVAGE_ACCEL)
 	/* FIFO size + padding for commands */
-	info->pixmap.addr = kmalloc(8*1024, GFP_KERNEL);
+	info->pixmap.addr = kcalloc(8, 1024, GFP_KERNEL);
 
 	err = -ENOMEM;
 	if (info->pixmap.addr) {
-		memset(info->pixmap.addr, 0, 8*1024);
 		info->pixmap.size = 8*1024;
 		info->pixmap.scan_align = 4;
 		info->pixmap.buf_align = 4;
diff --git a/drivers/video/sbuslib.c b/drivers/video/sbuslib.c
index 34ef859..963a454 100644
--- a/drivers/video/sbuslib.c
+++ b/drivers/video/sbuslib.c
@@ -190,17 +190,6 @@
 EXPORT_SYMBOL(sbusfb_ioctl_helper);
 
 #ifdef CONFIG_COMPAT
-struct  fbcmap32 {
-	int             index;          /* first element (0 origin) */
-	int             count;
-	u32		red;
-	u32		green;
-	u32		blue;
-};
-
-#define FBIOPUTCMAP32	_IOW('F', 3, struct fbcmap32)
-#define FBIOGETCMAP32	_IOW('F', 4, struct fbcmap32)
-
 static int fbiogetputcmap(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
 	struct fbcmap32 __user *argp = (void __user *)arg;
@@ -223,20 +212,6 @@
 			(unsigned long)p);
 }
 
-struct fbcursor32 {
-	short set;		/* what to set, choose from the list above */
-	short enable;		/* cursor on/off */
-	struct fbcurpos pos;	/* cursor position */
-	struct fbcurpos hot;	/* cursor hot spot */
-	struct fbcmap32 cmap;	/* color map info */
-	struct fbcurpos size;	/* cursor bit map size */
-	u32	image;		/* cursor image bits */
-	u32	mask;		/* cursor mask bits */
-};
-
-#define FBIOSCURSOR32	_IOW('F', 24, struct fbcursor32)
-#define FBIOGCURSOR32	_IOW('F', 25, struct fbcursor32)
-
 static int fbiogscursor(struct fb_info *info, unsigned long arg)
 {
 	struct fbcursor __user *p = compat_alloc_user_space(sizeof(*p));
diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c
index c97709e..e7c8db2 100644
--- a/drivers/video/stifb.c
+++ b/drivers/video/stifb.c
@@ -1100,13 +1100,18 @@
 	/* only supported cards are allowed */
 	switch (fb->id) {
 	case CRT_ID_VISUALIZE_EG:
-		/* look for a double buffering device like e.g. the 
-		   "INTERNAL_EG_DX1024" in the RDI precisionbook laptop
-		   which won't work. The same device in non-double 
-		   buffering mode returns "INTERNAL_EG_X1024". */
-		if (strstr(sti->outptr.dev_name, "EG_DX")) {
-		   printk(KERN_WARNING 
-			"stifb: ignoring '%s'. Disable double buffering in IPL menu.\n",
+		/* Visualize cards can run either in "double buffer" or
+ 		  "standard" mode. Depending on the mode, the card reports
+		  a different device name, e.g. "INTERNAL_EG_DX1024" in double
+		  buffer mode and "INTERNAL_EG_X1024" in standard mode.
+		  Since this driver only supports standard mode, we check
+		  if the device name contains the string "DX" and tell the
+		  user how to reconfigure the card. */
+		if (strstr(sti->outptr.dev_name, "DX")) {
+		   printk(KERN_WARNING "WARNING: stifb framebuffer driver does not "
+			"support '%s' in double-buffer mode.\n"
+			KERN_WARNING "WARNING: Please disable the double-buffer mode "
+			"in IPL menu (the PARISC-BIOS).\n",
 			sti->outptr.dev_name);
 		   goto out_err0;
 		}
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
index 5a99669..e5a9ddb 100644
--- a/drivers/video/tcx.c
+++ b/drivers/video/tcx.c
@@ -345,88 +345,82 @@
 	info->fix.accel = FB_ACCEL_SUN_TCX;
 }
 
-struct all_info {
-	struct fb_info info;
-	struct tcx_par par;
-};
-
-static void tcx_unmap_regs(struct of_device *op, struct all_info *all)
+static void tcx_unmap_regs(struct of_device *op, struct fb_info *info,
+			   struct tcx_par *par)
 {
-	if (all->par.tec)
+	if (par->tec)
 		of_iounmap(&op->resource[7],
-			   all->par.tec, sizeof(struct tcx_tec));
-	if (all->par.thc)
+			   par->tec, sizeof(struct tcx_tec));
+	if (par->thc)
 		of_iounmap(&op->resource[9],
-			   all->par.thc, sizeof(struct tcx_thc));
-	if (all->par.bt)
+			   par->thc, sizeof(struct tcx_thc));
+	if (par->bt)
 		of_iounmap(&op->resource[8],
-			   all->par.bt, sizeof(struct bt_regs));
-	if (all->par.cplane)
+			   par->bt, sizeof(struct bt_regs));
+	if (par->cplane)
 		of_iounmap(&op->resource[4],
-			   all->par.cplane, all->par.fbsize * sizeof(u32));
-	if (all->info.screen_base)
+			   par->cplane, par->fbsize * sizeof(u32));
+	if (info->screen_base)
 		of_iounmap(&op->resource[0],
-			   all->info.screen_base, all->par.fbsize);
+			   info->screen_base, par->fbsize);
 }
 
 static int __devinit tcx_init_one(struct of_device *op)
 {
 	struct device_node *dp = op->node;
-	struct all_info *all;
+	struct fb_info *info;
+	struct tcx_par *par;
 	int linebytes, i, err;
 
-	all = kzalloc(sizeof(*all), GFP_KERNEL);
-	if (!all)
-		return -ENOMEM;
+	info = framebuffer_alloc(sizeof(struct tcx_par), &op->dev);
 
-	spin_lock_init(&all->par.lock);
+	err = -ENOMEM;
+	if (!info)
+		goto out_err;
+	par = info->par;
 
-	all->par.lowdepth =
+	spin_lock_init(&par->lock);
+
+	par->lowdepth =
 		(of_find_property(dp, "tcx-8-bit", NULL) != NULL);
 
-	sbusfb_fill_var(&all->info.var, dp->node, 8);
-	all->info.var.red.length = 8;
-	all->info.var.green.length = 8;
-	all->info.var.blue.length = 8;
+	sbusfb_fill_var(&info->var, dp->node, 8);
+	info->var.red.length = 8;
+	info->var.green.length = 8;
+	info->var.blue.length = 8;
 
 	linebytes = of_getintprop_default(dp, "linebytes",
-					  all->info.var.xres);
-	all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
+					  info->var.xres);
+	par->fbsize = PAGE_ALIGN(linebytes * info->var.yres);
 
-	all->par.tec = of_ioremap(&op->resource[7], 0,
+	par->tec = of_ioremap(&op->resource[7], 0,
 				  sizeof(struct tcx_tec), "tcx tec");
-	all->par.thc = of_ioremap(&op->resource[9], 0,
+	par->thc = of_ioremap(&op->resource[9], 0,
 				  sizeof(struct tcx_thc), "tcx thc");
-	all->par.bt = of_ioremap(&op->resource[8], 0,
+	par->bt = of_ioremap(&op->resource[8], 0,
 				 sizeof(struct bt_regs), "tcx dac");
-	all->info.screen_base = of_ioremap(&op->resource[0], 0,
-					   all->par.fbsize, "tcx ram");
-	if (!all->par.tec || !all->par.thc ||
-	    !all->par.bt || !all->info.screen_base) {
-		tcx_unmap_regs(op, all);
-		kfree(all);
-		return -ENOMEM;
-	}
+	info->screen_base = of_ioremap(&op->resource[0], 0,
+					   par->fbsize, "tcx ram");
+	if (!par->tec || !par->thc ||
+	    !par->bt || !info->screen_base)
+		goto out_unmap_regs;
 
-	memcpy(&all->par.mmap_map, &__tcx_mmap_map, sizeof(all->par.mmap_map));
-	if (!all->par.lowdepth) {
-		all->par.cplane = of_ioremap(&op->resource[4], 0,
-					     all->par.fbsize * sizeof(u32),
+	memcpy(&par->mmap_map, &__tcx_mmap_map, sizeof(par->mmap_map));
+	if (!par->lowdepth) {
+		par->cplane = of_ioremap(&op->resource[4], 0,
+					     par->fbsize * sizeof(u32),
 					     "tcx cplane");
-		if (!all->par.cplane) {
-			tcx_unmap_regs(op, all);
-			kfree(all);
-			return -ENOMEM;
-		}
+		if (!par->cplane)
+			goto out_unmap_regs;
 	} else {
-		all->par.mmap_map[1].size = SBUS_MMAP_EMPTY;
-		all->par.mmap_map[4].size = SBUS_MMAP_EMPTY;
-		all->par.mmap_map[5].size = SBUS_MMAP_EMPTY;
-		all->par.mmap_map[6].size = SBUS_MMAP_EMPTY;
+		par->mmap_map[1].size = SBUS_MMAP_EMPTY;
+		par->mmap_map[4].size = SBUS_MMAP_EMPTY;
+		par->mmap_map[5].size = SBUS_MMAP_EMPTY;
+		par->mmap_map[6].size = SBUS_MMAP_EMPTY;
 	}
 
-	all->par.physbase = 0;
-	all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
+	par->physbase = 0;
+	par->which_io = op->resource[0].flags & IORESOURCE_BITS;
 
 	for (i = 0; i < TCX_MMAP_ENTRIES; i++) {
 		int j;
@@ -444,53 +438,54 @@
 			j = i;
 			break;
 		};
-		all->par.mmap_map[i].poff = op->resource[j].start;
+		par->mmap_map[i].poff = op->resource[j].start;
 	}
 
-	all->info.flags = FBINFO_DEFAULT;
-	all->info.fbops = &tcx_ops;
-	all->info.par = &all->par;
+	info->flags = FBINFO_DEFAULT;
+	info->fbops = &tcx_ops;
 
 	/* Initialize brooktree DAC. */
-	sbus_writel(0x04 << 24, &all->par.bt->addr);         /* color planes */
-	sbus_writel(0xff << 24, &all->par.bt->control);
-	sbus_writel(0x05 << 24, &all->par.bt->addr);
-	sbus_writel(0x00 << 24, &all->par.bt->control);
-	sbus_writel(0x06 << 24, &all->par.bt->addr);         /* overlay plane */
-	sbus_writel(0x73 << 24, &all->par.bt->control);
-	sbus_writel(0x07 << 24, &all->par.bt->addr);
-	sbus_writel(0x00 << 24, &all->par.bt->control);
+	sbus_writel(0x04 << 24, &par->bt->addr);         /* color planes */
+	sbus_writel(0xff << 24, &par->bt->control);
+	sbus_writel(0x05 << 24, &par->bt->addr);
+	sbus_writel(0x00 << 24, &par->bt->control);
+	sbus_writel(0x06 << 24, &par->bt->addr);         /* overlay plane */
+	sbus_writel(0x73 << 24, &par->bt->control);
+	sbus_writel(0x07 << 24, &par->bt->addr);
+	sbus_writel(0x00 << 24, &par->bt->control);
 
-	tcx_reset(&all->info);
+	tcx_reset(info);
 
-	tcx_blank(FB_BLANK_UNBLANK, &all->info);
+	tcx_blank(FB_BLANK_UNBLANK, info);
 
-	if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
-		tcx_unmap_regs(op, all);
-		kfree(all);
-		return -ENOMEM;
-	}
+	if (fb_alloc_cmap(&info->cmap, 256, 0))
+		goto out_unmap_regs;
 
-	fb_set_cmap(&all->info.cmap, &all->info);
-	tcx_init_fix(&all->info, linebytes);
+	fb_set_cmap(&info->cmap, info);
+	tcx_init_fix(info, linebytes);
 
-	err = register_framebuffer(&all->info);
-	if (err < 0) {
-		fb_dealloc_cmap(&all->info.cmap);
-		tcx_unmap_regs(op, all);
-		kfree(all);
-		return err;
-	}
+	err = register_framebuffer(info);
+	if (err < 0)
+		goto out_dealloc_cmap;
 
-	dev_set_drvdata(&op->dev, all);
+	dev_set_drvdata(&op->dev, info);
 
 	printk("%s: TCX at %lx:%lx, %s\n",
 	       dp->full_name,
-	       all->par.which_io,
+	       par->which_io,
 	       op->resource[0].start,
-	       all->par.lowdepth ? "8-bit only" : "24-bit depth");
+	       par->lowdepth ? "8-bit only" : "24-bit depth");
 
 	return 0;
+
+out_dealloc_cmap:
+	fb_dealloc_cmap(&info->cmap);
+
+out_unmap_regs:
+	tcx_unmap_regs(op, info, par);
+
+out_err:
+	return err;
 }
 
 static int __devinit tcx_probe(struct of_device *dev, const struct of_device_id *match)
@@ -502,14 +497,15 @@
 
 static int __devexit tcx_remove(struct of_device *op)
 {
-	struct all_info *all = dev_get_drvdata(&op->dev);
+	struct fb_info *info = dev_get_drvdata(&op->dev);
+	struct tcx_par *par = info->par;
 
-	unregister_framebuffer(&all->info);
-	fb_dealloc_cmap(&all->info.cmap);
+	unregister_framebuffer(info);
+	fb_dealloc_cmap(&info->cmap);
 
-	tcx_unmap_regs(op, all);
+	tcx_unmap_regs(op, info, par);
 
-	kfree(all);
+	framebuffer_release(info);
 
 	dev_set_drvdata(&op->dev, NULL);
 
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
index 89facb7..d292a37 100644
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -849,7 +849,7 @@
 	u32 *palette = ((u32 *)info->pseudo_palette);
 	unsigned long pos, line_length, i, j;
 	const unsigned char *data;
-	void *regs_base, *fb_base;
+	void __iomem *regs_base, *fb_base;
 
 	dx = image->dx;
 	dy = image->dy;
diff --git a/drivers/video/tx3912fb.c b/drivers/video/tx3912fb.c
deleted file mode 100644
index e6f7c78..0000000
--- a/drivers/video/tx3912fb.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- *  drivers/video/tx3912fb.c
- *
- *  Copyright (C) 1999 Harald Koerfgen
- *  Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.com)
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
- *
- *  Framebuffer for LCD controller in TMPR3912/05 and PR31700 processors
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/pm.h>
-#include <linux/fb.h>
-#include <asm/io.h>
-#include <asm/bootinfo.h>
-#include <asm/uaccess.h>
-#include <asm/tx3912.h>
-#include <video/tx3912.h>
-
-/*
- * Frame buffer, palette and console structures
- */
-static struct fb_info fb_info;
-static u32 cfb8[16];
-
-static struct fb_fix_screeninfo tx3912fb_fix __initdata = {
-	.id =		"tx3912fb",
-	.smem_len =	((240 * 320)/2),
-	.type =		FB_TYPE_PACKED_PIXELS,
-	.visual =	FB_VISUAL_TRUECOLOR, 
-	.xpanstep =	1,
-	.ypanstep =	1,
-	.ywrapstep =	1,
-	.accel =	FB_ACCEL_NONE,
-};
-
-static struct fb_var_screeninfo tx3912fb_var = {
-	.xres =		240,
-	.yres =		320,
-	.xres_virtual =	240,
-	.yres_virtual =	320,
-	.bits_per_pixel =4,
-	.red =		{ 0, 4, 0 },	/* ??? */
-	.green =	{ 0, 4, 0 },
-	.blue =		{ 0, 4, 0 },
-	.activate =	FB_ACTIVATE_NOW,
-	.width =	-1,
-	.height =	-1,
-	.pixclock =	20000,
-	.left_margin =	64,
-	.right_margin =	64,
-	.upper_margin =	32,
-	.lower_margin =	32,
-	.hsync_len =	64,
-	.vsync_len =	2,
-	.vmode =	FB_VMODE_NONINTERLACED,
-};
-
-/*
- * Interface used by the world
- */
-int tx3912fb_init(void);
-
-static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green,
-			      u_int blue, u_int transp,
-			      struct fb_info *info);
-
-/*
- * Macros
- */
-#define get_line_length(xres_virtual, bpp) \
-                (u_long) (((int) xres_virtual * (int) bpp + 7) >> 3)
-
-/*
- * Frame buffer operations structure used by console driver
- */
-static struct fb_ops tx3912fb_ops = {
-	.owner		= THIS_MODULE,
-	.fb_setcolreg	= tx3912fb_setcolreg,
-	.fb_fillrect	= cfb_fillrect,
-	.fb_copyarea	= cfb_copyarea,
-	.fb_imageblit	= cfb_imageblit,
-};
-
-static int tx3912fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
-{
-	/*
-	 * Memory limit
-	 */
-	line_length =
-	    get_line_length(var->xres_virtual, var->bits_per_pixel);
-	if ((line_length * var->yres_virtual) > info->fix.smem_len)
-		return -ENOMEM;
-
-	return 0;
-}
-
-static int tx3912fb_set_par(struct fb_info *info)
-{
-	u_long tx3912fb_paddr = 0;
-
-	/* Disable the video logic */
-	outl(inl(TX3912_VIDEO_CTRL1) &
-	     ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
-	     TX3912_VIDEO_CTRL1);
-	udelay(200);
-
-	/* Set start address for DMA transfer */
-	outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3);
-
-	/* Set end address for DMA transfer */
-	outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4);
-
-	/* Set the pixel depth */
-	switch (info->var.bits_per_pixel) {
-	case 1:
-		/* Monochrome */
-		outl(inl(TX3912_VIDEO_CTRL1) &
-		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
-		info->fix.visual = FB_VISUAL_MONO10;
-		break;
-	case 4:
-		/* 4-bit gray */
-		outl(inl(TX3912_VIDEO_CTRL1) &
-		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
-		outl(inl(TX3912_VIDEO_CTRL1) |
-		     TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY,
-		     TX3912_VIDEO_CTRL1);
-		info->fix.visual = FB_VISUAL_TRUECOLOR;
-		break;
-	case 8:
-		/* 8-bit color */
-		outl(inl(TX3912_VIDEO_CTRL1) &
-		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
-		outl(inl(TX3912_VIDEO_CTRL1) |
-		     TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR,
-		     TX3912_VIDEO_CTRL1);
-		info->fix.visual = FB_VISUAL_TRUECOLOR;
-		break;
-	case 2:
-	default:
-		/* 2-bit gray */
-		outl(inl(TX3912_VIDEO_CTRL1) &
-		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
-		outl(inl(TX3912_VIDEO_CTRL1) |
-		     TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY,
-		     TX3912_VIDEO_CTRL1);
-		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
-		break;
-	}
-
-	/* Enable the video clock */
-	outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK,
-	     TX3912_CLK_CTRL);
-
-	/* Unfreeze video logic and enable DF toggle */
-	outl(inl(TX3912_VIDEO_CTRL1) &
-	     ~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME |
-	       TX3912_VIDEO_CTRL1_DFMODE)
-	     , TX3912_VIDEO_CTRL1);
-	udelay(200);
-
-	/* Enable the video logic */
-	outl(inl(TX3912_VIDEO_CTRL1) |
-	     (TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
-	     TX3912_VIDEO_CTRL1);
-
-	info->fix.line_length = get_line_length(var->xres_virtual,
-					    var->bits_per_pixel);
-}
-
-/*
- * Set a single color register
- */
-static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green,
-			      u_int blue, u_int transp,
-			      struct fb_info *info)
-{
-	if (regno > 255)
-		return 1;
-
-	if (regno < 16)
-		((u32 *)(info->pseudo_palette))[regno] = ((red & 0xe000) >> 8)
-		    | ((green & 0xe000) >> 11)
-		    | ((blue & 0xc000) >> 14);
-	return 0;
-}
-
-int __init tx3912fb_setup(char *options);
-
-/*
- * Initialization of the framebuffer
- */
-int __init tx3912fb_init(void)
-{
-	u_long tx3912fb_paddr = 0;
-	int size = (info->var.bits_per_pixel == 8) ? 256 : 16;
-	char *option = NULL;
-
-	if (fb_get_options("tx3912fb", &option))
-		return -ENODEV;
-	tx3912fb_setup(option);
-
-	/* Disable the video logic */
-	outl(inl(TX3912_VIDEO_CTRL1) &
-	     ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
-	     TX3912_VIDEO_CTRL1);
-	udelay(200);
-
-	/* Set start address for DMA transfer */
-	outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3);
-
-	/* Set end address for DMA transfer */
-	outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4);
-
-	/* Set the pixel depth */
-	switch (tx3912fb_var.bits_per_pixel) {
-	case 1:
-		/* Monochrome */
-		outl(inl(TX3912_VIDEO_CTRL1) &
-		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
-		tx3912fb_fix.visual = FB_VISUAL_MONO10;
-		break;
-	case 4:
-		/* 4-bit gray */
-		outl(inl(TX3912_VIDEO_CTRL1) &
-		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
-		outl(inl(TX3912_VIDEO_CTRL1) |
-		     TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY,
-		     TX3912_VIDEO_CTRL1);
-		tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR;
-		tx3912fb_fix.grayscale = 1;
-		break;
-	case 8:
-		/* 8-bit color */
-		outl(inl(TX3912_VIDEO_CTRL1) &
-		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
-		outl(inl(TX3912_VIDEO_CTRL1) |
-		     TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR,
-		     TX3912_VIDEO_CTRL1);
-		tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR;
-		break;
-	case 2:
-	default:
-		/* 2-bit gray */
-		outl(inl(TX3912_VIDEO_CTRL1) &
-		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
-		outl(inl(TX3912_VIDEO_CTRL1) |
-		     TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY,
-		     TX3912_VIDEO_CTRL1);
-		tx3912fb_fix.visual = FB_VISUAL_PSEUDOCOLOR;
-		tx3912fb_fix.grayscale = 1;
-		break;
-	}
-
-	/* Enable the video clock */
-	outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK,
-		TX3912_CLK_CTRL);
-
-	/* Unfreeze video logic and enable DF toggle */
-	outl(inl(TX3912_VIDEO_CTRL1) &
-		~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME | TX3912_VIDEO_CTRL1_DFMODE),
-		TX3912_VIDEO_CTRL1);
-	udelay(200);
-
-	/* Clear the framebuffer */
-	memset((void *) tx3912fb_fix.smem_start, 0xff, tx3912fb_fix.smem_len);
-	udelay(200);
-
-	/* Enable the video logic */
-	outl(inl(TX3912_VIDEO_CTRL1) |
-		(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
-		TX3912_VIDEO_CTRL1);
-
-	/*
-	 * Memory limit
-	 */
-	tx3912fb_fix.line_length =
-	    get_line_length(tx3912fb_var.xres_virtual, tx3912fb_var.bits_per_pixel);
-	if ((tx3912fb_fix.line_length * tx3912fb_var.yres_virtual) > tx3912fb_fix.smem_len)
-		return -ENOMEM;
-
-	fb_info.fbops = &tx3912fb_ops;
-	fb_info.var = tx3912fb_var;
-	fb_info.fix = tx3912fb_fix;
-	fb_info.pseudo_palette = cfb8;
-	fb_info.flags = FBINFO_DEFAULT;
-
-	/* Clear the framebuffer */
-	memset((void *) fb_info.fix.smem_start, 0xff, fb_info.fix.smem_len);
-	udelay(200);
-
-	fb_alloc_cmap(&info->cmap, size, 0);
-
-	if (register_framebuffer(&fb_info) < 0)
-		return -1;
-
-	printk(KERN_INFO "fb%d: TX3912 frame buffer using %uKB.\n",
-	       fb_info.node, (u_int) (fb_info.fix.smem_len >> 10));
-	return 0;
-}
-
-int __init tx3912fb_setup(char *options)
-{
-	char *this_opt;
-
-	if (!options || !*options)
-		return 0;
-
-	while ((this_opt = strsep(&options, ","))) {
-		if (!strncmp(options, "bpp:", 4))	
-			tx3912fb_var.bits_per_pixel = simple_strtoul(options+4, NULL, 0);
-	}	
-	return 0;
-}
-
-module_init(tx3912fb_init);
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
index ad66f07..7b0cef9 100644
--- a/drivers/video/valkyriefb.c
+++ b/drivers/video/valkyriefb.c
@@ -356,10 +356,9 @@
 	}
 #endif /* ppc (!CONFIG_MAC) */
 
-	p = kmalloc(sizeof(*p), GFP_ATOMIC);
+	p = kzalloc(sizeof(*p), GFP_ATOMIC);
 	if (p == 0)
 		return -ENOMEM;
-	memset(p, 0, sizeof(*p));
 
 	/* Map in frame buffer and registers */
 	if (!request_mem_region(frame_buffer_phys, 0x100000, "valkyriefb")) {
diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index 1d29a89..6ef99b2 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -6,9 +6,12 @@
  * Author: MontaVista Software, Inc.
  *         source@mvista.com
  *
- * 2002-2007 (c) MontaVista Software, Inc.  This file is licensed under the
- * terms of the GNU General Public License version 2.  This program is licensed
- * "as is" without any warranty of any kind, whether express or implied.
+ * 2002-2007 (c) MontaVista Software, Inc.
+ * 2007 (c) Secret Lab Technologies, Ltd.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
  */
 
 /*
@@ -18,6 +21,7 @@
  * Geert Uytterhoeven.
  */
 
+#include <linux/device.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/version.h>
@@ -28,9 +32,12 @@
 #include <linux/init.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
-
+#if defined(CONFIG_OF)
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#endif
 #include <asm/io.h>
-#include <syslib/virtex_devices.h>
+#include <linux/xilinxfb.h>
 
 #define DRIVER_NAME		"xilinxfb"
 #define DRIVER_DESCRIPTION	"Xilinx TFT LCD frame buffer driver"
@@ -63,12 +70,6 @@
  */
 #define BYTES_PER_PIXEL	4
 #define BITS_PER_PIXEL	(BYTES_PER_PIXEL * 8)
-#define XRES		640
-#define YRES		480
-#define XRES_VIRTUAL	1024
-#define YRES_VIRTUAL	YRES
-#define LINE_LENGTH	(XRES_VIRTUAL * BYTES_PER_PIXEL)
-#define FB_SIZE		(YRES_VIRTUAL * LINE_LENGTH)
 
 #define RED_SHIFT	16
 #define GREEN_SHIFT	8
@@ -77,23 +78,26 @@
 #define PALETTE_ENTRIES_NO	16	/* passed to fb_alloc_cmap() */
 
 /*
+ * Default xilinxfb configuration
+ */
+static struct xilinxfb_platform_data xilinx_fb_default_pdata = {
+	.xres = 640,
+	.yres = 480,
+	.xvirt = 1024,
+	.yvirt = 480;
+};
+
+/*
  * Here are the default fb_fix_screeninfo and fb_var_screeninfo structures
  */
-static struct fb_fix_screeninfo xilinx_fb_fix __initdata = {
+static struct fb_fix_screeninfo xilinx_fb_fix = {
 	.id =		"Xilinx",
 	.type =		FB_TYPE_PACKED_PIXELS,
 	.visual =	FB_VISUAL_TRUECOLOR,
-	.smem_len =	FB_SIZE,
-	.line_length =	LINE_LENGTH,
 	.accel =	FB_ACCEL_NONE
 };
 
-static struct fb_var_screeninfo xilinx_fb_var __initdata = {
-	.xres =			XRES,
-	.yres =			YRES,
-	.xres_virtual =		XRES_VIRTUAL,
-	.yres_virtual =		YRES_VIRTUAL,
-
+static struct fb_var_screeninfo xilinx_fb_var = {
 	.bits_per_pixel =	BITS_PER_PIXEL,
 
 	.red =		{ RED_SHIFT, 8, 0 },
@@ -111,8 +115,9 @@
 	u32		regs_phys;	/* phys. address of the control registers */
 	u32 __iomem	*regs;		/* virt. address of the control registers */
 
-	unsigned char __iomem	*fb_virt;	/* virt. address of the frame buffer */
+	void		*fb_virt;	/* virt. address of the frame buffer */
 	dma_addr_t	fb_phys;	/* phys. address of the frame buffer */
+	int		fb_alloced;	/* Flag, was the fb memory alloced? */
 
 	u32		reg_ctrl_default;
 
@@ -195,135 +200,136 @@
 	.fb_imageblit		= cfb_imageblit,
 };
 
-/* === The device driver === */
+/* ---------------------------------------------------------------------
+ * Bus independent setup/teardown
+ */
 
-static int
-xilinxfb_drv_probe(struct device *dev)
+static int xilinxfb_assign(struct device *dev, unsigned long physaddr,
+			   struct xilinxfb_platform_data *pdata)
 {
-	struct platform_device *pdev;
-	struct xilinxfb_platform_data *pdata;
 	struct xilinxfb_drvdata *drvdata;
-	struct resource *regs_res;
-	int retval;
+	int rc;
+	int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL;
 
-	if (!dev)
-		return -EINVAL;
-
-	pdev = to_platform_device(dev);
-	pdata = pdev->dev.platform_data;
-
-	if (pdata == NULL) {
-		printk(KERN_ERR "Couldn't find platform data.\n");
-		return -EFAULT;
-	}
-
+	/* Allocate the driver data region */
 	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
 	if (!drvdata) {
-		printk(KERN_ERR "Couldn't allocate device private record\n");
+		dev_err(dev, "Couldn't allocate device private record\n");
 		return -ENOMEM;
 	}
 	dev_set_drvdata(dev, drvdata);
 
 	/* Map the control registers in */
-	regs_res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!regs_res || (regs_res->end - regs_res->start + 1 < 8)) {
-		printk(KERN_ERR "Couldn't get registers resource\n");
-		retval = -EFAULT;
-		goto failed1;
+	if (!request_mem_region(physaddr, 8, DRIVER_NAME)) {
+		dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
+			physaddr);
+		rc = -ENODEV;
+		goto err_region;
 	}
-
-	if (!request_mem_region(regs_res->start, 8, DRIVER_NAME)) {
-		printk(KERN_ERR
-		       "Couldn't lock memory region at 0x%08X\n",
-		       regs_res->start);
-		retval = -EBUSY;
-		goto failed1;
+	drvdata->regs_phys = physaddr;
+	drvdata->regs = ioremap(physaddr, 8);
+	if (!drvdata->regs) {
+		dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
+			physaddr);
+		rc = -ENODEV;
+		goto err_map;
 	}
-	drvdata->regs = (u32 __iomem*) ioremap(regs_res->start, 8);
-	drvdata->regs_phys = regs_res->start;
 
 	/* Allocate the framebuffer memory */
-	drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(FB_SIZE),
-				&drvdata->fb_phys, GFP_KERNEL);
+	if (pdata->fb_phys) {
+		drvdata->fb_phys = pdata->fb_phys;
+		drvdata->fb_virt = ioremap(pdata->fb_phys, fbsize);
+	} else {
+		drvdata->fb_alloced = 1;
+		drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize),
+					&drvdata->fb_phys, GFP_KERNEL);
+	}
+
 	if (!drvdata->fb_virt) {
-		printk(KERN_ERR "Could not allocate frame buffer memory\n");
-		retval = -ENOMEM;
-		goto failed2;
+		dev_err(dev, "Could not allocate frame buffer memory\n");
+		rc = -ENOMEM;
+		goto err_fbmem;
 	}
 
 	/* Clear (turn to black) the framebuffer */
-	memset_io((void *) drvdata->fb_virt, 0, FB_SIZE);
+	memset_io((void __iomem *)drvdata->fb_virt, 0, fbsize);
 
 	/* Tell the hardware where the frame buffer is */
 	xilinx_fb_out_be32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
 
 	/* Turn on the display */
-	if (pdata->rotate_screen) {
-		drvdata->reg_ctrl_default = REG_CTRL_ENABLE | REG_CTRL_ROTATE;
-	} else {
-		drvdata->reg_ctrl_default = REG_CTRL_ENABLE;
-	}
+	drvdata->reg_ctrl_default = REG_CTRL_ENABLE;
+	if (pdata->rotate_screen)
+		drvdata->reg_ctrl_default |= REG_CTRL_ROTATE;
 	xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
 
 	/* Fill struct fb_info */
 	drvdata->info.device = dev;
-	drvdata->info.screen_base = drvdata->fb_virt;
+	drvdata->info.screen_base = (void __iomem *)drvdata->fb_virt;
 	drvdata->info.fbops = &xilinxfb_ops;
 	drvdata->info.fix = xilinx_fb_fix;
 	drvdata->info.fix.smem_start = drvdata->fb_phys;
+	drvdata->info.fix.smem_len = fbsize;
+	drvdata->info.fix.line_length = pdata->xvirt * BYTES_PER_PIXEL;
+
 	drvdata->info.pseudo_palette = drvdata->pseudo_palette;
-
-	if (fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0) < 0) {
-		printk(KERN_ERR "Fail to allocate colormap (%d entries)\n",
-			PALETTE_ENTRIES_NO);
-		retval = -EFAULT;
-		goto failed3;
-	}
-
 	drvdata->info.flags = FBINFO_DEFAULT;
-	xilinx_fb_var.height = pdata->screen_height_mm;
-	xilinx_fb_var.width = pdata->screen_width_mm;
 	drvdata->info.var = xilinx_fb_var;
+	drvdata->info.var.height = pdata->screen_height_mm;
+	drvdata->info.var.width = pdata->screen_width_mm;
+	drvdata->info.var.xres = pdata->xres;
+	drvdata->info.var.yres = pdata->yres;
+	drvdata->info.var.xres_virtual = pdata->xvirt;
+	drvdata->info.var.yres_virtual = pdata->yvirt;
+
+	/* Allocate a colour map */
+	rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0);
+	if (rc) {
+		dev_err(dev, "Fail to allocate colormap (%d entries)\n",
+			PALETTE_ENTRIES_NO);
+		goto err_cmap;
+	}
 
 	/* Register new frame buffer */
-	if (register_framebuffer(&drvdata->info) < 0) {
-		printk(KERN_ERR "Could not register frame buffer\n");
-		retval = -EINVAL;
-		goto failed4;
+	rc = register_framebuffer(&drvdata->info);
+	if (rc) {
+		dev_err(dev, "Could not register frame buffer\n");
+		goto err_regfb;
 	}
 
+	/* Put a banner in the log (for DEBUG) */
+	dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr, drvdata->regs);
+	dev_dbg(dev, "fb: phys=%p, virt=%p, size=%x\n",
+		(void*)drvdata->fb_phys, drvdata->fb_virt, fbsize);
+
 	return 0;	/* success */
 
-failed4:
+err_regfb:
 	fb_dealloc_cmap(&drvdata->info.cmap);
 
-failed3:
-	dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt,
-		drvdata->fb_phys);
-
+err_cmap:
+	if (drvdata->fb_alloced)
+		dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt,
+			drvdata->fb_phys);
 	/* Turn off the display */
 	xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
+
+err_fbmem:
 	iounmap(drvdata->regs);
 
-failed2:
-	release_mem_region(regs_res->start, 8);
+err_map:
+	release_mem_region(physaddr, 8);
 
-failed1:
+err_region:
 	kfree(drvdata);
 	dev_set_drvdata(dev, NULL);
 
-	return retval;
+	return rc;
 }
 
-static int
-xilinxfb_drv_remove(struct device *dev)
+static int xilinxfb_release(struct device *dev)
 {
-	struct xilinxfb_drvdata *drvdata;
-
-	if (!dev)
-		return -ENODEV;
-
-	drvdata = (struct xilinxfb_drvdata *) dev_get_drvdata(dev);
+	struct xilinxfb_drvdata *drvdata = dev_get_drvdata(dev);
 
 #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
 	xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info);
@@ -333,8 +339,9 @@
 
 	fb_dealloc_cmap(&drvdata->info.cmap);
 
-	dma_free_coherent(dev, PAGE_ALIGN(FB_SIZE), drvdata->fb_virt,
-		drvdata->fb_phys);
+	if (drvdata->fb_alloced)
+		dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len),
+				  drvdata->fb_virt, drvdata->fb_phys);
 
 	/* Turn off the display */
 	xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
@@ -348,29 +355,168 @@
 	return 0;
 }
 
+/* ---------------------------------------------------------------------
+ * Platform bus binding
+ */
 
-static struct device_driver xilinxfb_driver = {
-	.name		= DRIVER_NAME,
-	.bus		= &platform_bus_type,
+static int
+xilinxfb_platform_probe(struct platform_device *pdev)
+{
+	struct xilinxfb_platform_data *pdata;
+	struct resource *res;
 
-	.probe		= xilinxfb_drv_probe,
-	.remove		= xilinxfb_drv_remove
+	/* Find the registers address */
+	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+	if (!res) {
+		dev_err(&pdev->dev, "Couldn't get registers resource\n");
+		return -ENODEV;
+	}
+
+	/* If a pdata structure is provided, then extract the parameters */
+	pdata = &xilinx_fb_default_pdata;
+	if (pdev->dev.platform_data) {
+		pdata = pdev->dev.platform_data;
+		if (!pdata->xres)
+			pdata->xres = xilinx_fb_default_pdata.xres;
+		if (!pdata->yres)
+			pdata->yres = xilinx_fb_default_pdata.yres;
+		if (!pdata->xvirt)
+			pdata->xvirt = xilinx_fb_default_pdata.xvirt;
+		if (!pdata->yvirt)
+			pdata->yvirt = xilinx_fb_default_pdata.yvirt;
+	}
+
+	return xilinxfb_assign(&pdev->dev, res->start, pdata);
+}
+
+static int
+xilinxfb_platform_remove(struct platform_device *pdev)
+{
+	return xilinxfb_release(&pdev->dev);
+}
+
+
+static struct platform_driver xilinxfb_platform_driver = {
+	.probe		= xilinxfb_platform_probe,
+	.remove		= xilinxfb_platform_remove,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = DRIVER_NAME,
+	},
 };
 
+/* ---------------------------------------------------------------------
+ * OF bus binding
+ */
+
+#if defined(CONFIG_OF)
+static int __devinit
+xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+	struct resource res;
+	const u32 *prop;
+	struct xilinxfb_platform_data pdata;
+	int size, rc;
+
+	/* Copy with the default pdata (not a ptr reference!) */
+	pdata = xilinx_fb_default_pdata;
+
+	dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, match);
+
+	rc = of_address_to_resource(op->node, 0, &res);
+	if (rc) {
+		dev_err(&op->dev, "invalid address\n");
+		return rc;
+	}
+
+	prop = of_get_property(op->node, "phys-size", &size);
+	if ((prop) && (size >= sizeof(u32)*2)) {
+		pdata.screen_width_mm = prop[0];
+		pdata.screen_height_mm = prop[1];
+	}
+
+	prop = of_get_property(op->node, "resolution", &size);
+	if ((prop) && (size >= sizeof(u32)*2)) {
+		pdata.xres = prop[0];
+		pdata.yres = prop[1];
+	}
+
+	prop = of_get_property(op->node, "virtual-resolution", &size);
+	if ((prop) && (size >= sizeof(u32)*2)) {
+		pdata.xvirt = prop[0];
+		pdata.yvirt = prop[1];
+	}
+
+	if (of_find_property(op->node, "rotate-display", NULL))
+		pdata.rotate_screen = 1;
+
+	return xilinxfb_assign(&op->dev, res.start, &pdata);
+}
+
+static int __devexit xilinxfb_of_remove(struct of_device *op)
+{
+	return xilinxfb_release(&op->dev);
+}
+
+/* Match table for of_platform binding */
+static struct of_device_id __devinit xilinxfb_of_match[] = {
+	{ .compatible = "xilinx,ml300-fb", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, xilinxfb_of_match);
+
+static struct of_platform_driver xilinxfb_of_driver = {
+	.owner = THIS_MODULE,
+	.name = DRIVER_NAME,
+	.match_table = xilinxfb_of_match,
+	.probe = xilinxfb_of_probe,
+	.remove = __devexit_p(xilinxfb_of_remove),
+	.driver = {
+		.name = DRIVER_NAME,
+	},
+};
+
+/* Registration helpers to keep the number of #ifdefs to a minimum */
+static inline int __init xilinxfb_of_register(void)
+{
+	pr_debug("xilinxfb: calling of_register_platform_driver()\n");
+	return of_register_platform_driver(&xilinxfb_of_driver);
+}
+
+static inline void __exit xilinxfb_of_unregister(void)
+{
+	of_unregister_platform_driver(&xilinxfb_of_driver);
+}
+#else /* CONFIG_OF */
+/* CONFIG_OF not enabled; do nothing helpers */
+static inline int __init xilinxfb_of_register(void) { return 0; }
+static inline void __exit xilinxfb_of_unregister(void) { }
+#endif /* CONFIG_OF */
+
+/* ---------------------------------------------------------------------
+ * Module setup and teardown
+ */
+
 static int __init
 xilinxfb_init(void)
 {
-	/*
-	 * No kernel boot options used,
-	 * so we just need to register the driver
-	 */
-	return driver_register(&xilinxfb_driver);
+	int rc;
+	rc = xilinxfb_of_register();
+	if (rc)
+		return rc;
+
+	rc = platform_driver_register(&xilinxfb_platform_driver);
+	if (rc)
+		xilinxfb_of_unregister();
+
+	return rc;
 }
 
 static void __exit
 xilinxfb_cleanup(void)
 {
-	driver_unregister(&xilinxfb_driver);
+	platform_driver_unregister(&xilinxfb_platform_driver);
+	xilinxfb_of_unregister();
 }
 
 module_init(xilinxfb_init);
diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c
index 763bc73..4b69664 100644
--- a/drivers/w1/masters/ds1wm.c
+++ b/drivers/w1/masters/ds1wm.c
@@ -85,7 +85,7 @@
 };
 
 struct ds1wm_data {
-	void		*map;
+	void		__iomem *map;
 	int		bus_shift; /* # of shifts to calc register offsets */
 	struct platform_device *pdev;
 	struct ds1wm_platform_data *pdata;
diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c
index 6f9d880..d356da5 100644
--- a/drivers/w1/masters/matrox_w1.c
+++ b/drivers/w1/masters/matrox_w1.c
@@ -164,7 +164,7 @@
 	if (pdev->vendor != PCI_VENDOR_ID_MATROX || pdev->device != PCI_DEVICE_ID_MATROX_G400)
 		return -ENODEV;
 
-	dev = kmalloc(sizeof(struct matrox_device) +
+	dev = kzalloc(sizeof(struct matrox_device) +
 		       sizeof(struct w1_bus_master), GFP_KERNEL);
 	if (!dev) {
 		dev_err(&pdev->dev,
@@ -173,7 +173,6 @@
 		return -ENOMEM;
 	}
 
-	memset(dev, 0, sizeof(struct matrox_device) + sizeof(struct w1_bus_master));
 
 	dev->bus_master = (struct w1_bus_master *)(dev + 1);
 
diff --git a/drivers/w1/slaves/w1_ds2433.c b/drivers/w1/slaves/w1_ds2433.c
index cab5600..858c16a 100644
--- a/drivers/w1/slaves/w1_ds2433.c
+++ b/drivers/w1/slaves/w1_ds2433.c
@@ -266,10 +266,9 @@
 #ifdef CONFIG_W1_SLAVE_DS2433_CRC
 	struct w1_f23_data *data;
 
-	data = kmalloc(sizeof(struct w1_f23_data), GFP_KERNEL);
+	data = kzalloc(sizeof(struct w1_f23_data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
-	memset(data, 0, sizeof(struct w1_f23_data));
 	sl->family_data = data;
 
 #endif	/* CONFIG_W1_SLAVE_DS2433_CRC */
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index c633210..0702173 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -197,7 +197,7 @@
 	.fops = &w1_default_fops,
 };
 
-static int w1_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env);
 
 static struct bus_type w1_bus_type = {
 	.name = "w1",
@@ -396,13 +396,12 @@
 }
 
 #ifdef CONFIG_HOTPLUG
-static int w1_uevent(struct device *dev, char **envp, int num_envp,
-			char *buffer, int buffer_size)
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	struct w1_master *md = NULL;
 	struct w1_slave *sl = NULL;
 	char *event_owner, *name;
-	int err, cur_index=0, cur_len=0;
+	int err;
 
 	if (dev->driver == &w1_master_driver) {
 		md = container_of(dev, struct w1_master, dev);
@@ -423,22 +422,19 @@
 	if (dev->driver != &w1_slave_driver || !sl)
 		return 0;
 
-	err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size,
-			&cur_len, "W1_FID=%02X", sl->reg_num.family);
+	err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family);
 	if (err)
 		return err;
 
-	err = add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size,
-			&cur_len, "W1_SLAVE_ID=%024LX",
-			(unsigned long long)sl->reg_num.id);
+	err = add_uevent_var(env, "W1_SLAVE_ID=%024LX",
+			     (unsigned long long)sl->reg_num.id);
 	if (err)
 		return err;
 
 	return 0;
 };
 #else
-static int w1_uevent(struct device *dev, char **envp, int num_envp,
-			char *buffer, int buffer_size)
+static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 	return 0;
 }
@@ -520,7 +516,7 @@
 	int err;
 	struct w1_netlink_msg msg;
 
-	sl = kmalloc(sizeof(struct w1_slave), GFP_KERNEL);
+	sl = kzalloc(sizeof(struct w1_slave), GFP_KERNEL);
 	if (!sl) {
 		dev_err(&dev->dev,
 			 "%s: failed to allocate new slave device.\n",
@@ -528,7 +524,6 @@
 		return -ENOMEM;
 	}
 
-	memset(sl, 0, sizeof(*sl));
 
 	sl->owner = THIS_MODULE;
 	sl->master = dev;
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 258defd..6840dfe 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -41,7 +41,7 @@
 	/*
 	 * We are in process context(kernel thread), so can sleep.
 	 */
-	dev = kmalloc(sizeof(struct w1_master) + sizeof(struct w1_bus_master), GFP_KERNEL);
+	dev = kzalloc(sizeof(struct w1_master) + sizeof(struct w1_bus_master), GFP_KERNEL);
 	if (!dev) {
 		printk(KERN_ERR
 			"Failed to allocate %zd bytes for new w1 device.\n",
@@ -49,7 +49,6 @@
 		return NULL;
 	}
 
-	memset(dev, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
 
 	dev->bus_master = (struct w1_bus_master *)(dev + 1);
 
@@ -171,22 +170,24 @@
 
 void w1_remove_master_device(struct w1_bus_master *bm)
 {
-	struct w1_master *dev = NULL;
+	struct w1_master *dev, *found = NULL;
 
 	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
 		if (!dev->initialized)
 			continue;
 
-		if (dev->bus_master->data == bm->data)
+		if (dev->bus_master->data == bm->data) {
+			found = dev;
 			break;
+		}
 	}
 
-	if (!dev) {
+	if (!found) {
 		printk(KERN_ERR "Device doesn't exist.\n");
 		return;
 	}
 
-	__w1_remove_master_device(dev);
+	__w1_remove_master_device(found);
 }
 
 EXPORT_SYMBOL(w1_add_master_device);
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
new file mode 100644
index 0000000..56592f0
--- /dev/null
+++ b/drivers/xen/Makefile
@@ -0,0 +1,2 @@
+obj-y	+= grant-table.o
+obj-y	+= xenbus/
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
new file mode 100644
index 0000000..ea94dba
--- /dev/null
+++ b/drivers/xen/grant-table.c
@@ -0,0 +1,582 @@
+/******************************************************************************
+ * grant_table.c
+ *
+ * Granting foreign access to our memory reservation.
+ *
+ * Copyright (c) 2005-2006, Christopher Clark
+ * Copyright (c) 2004-2005, K A Fraser
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+
+#include <xen/interface/xen.h>
+#include <xen/page.h>
+#include <xen/grant_table.h>
+
+#include <asm/pgtable.h>
+#include <asm/sync_bitops.h>
+
+
+/* External tools reserve first few grant table entries. */
+#define NR_RESERVED_ENTRIES 8
+#define GNTTAB_LIST_END 0xffffffff
+#define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(struct grant_entry))
+
+static grant_ref_t **gnttab_list;
+static unsigned int nr_grant_frames;
+static unsigned int boot_max_nr_grant_frames;
+static int gnttab_free_count;
+static grant_ref_t gnttab_free_head;
+static DEFINE_SPINLOCK(gnttab_list_lock);
+
+static struct grant_entry *shared;
+
+static struct gnttab_free_callback *gnttab_free_callback_list;
+
+static int gnttab_expand(unsigned int req_entries);
+
+#define RPP (PAGE_SIZE / sizeof(grant_ref_t))
+
+static inline grant_ref_t *__gnttab_entry(grant_ref_t entry)
+{
+	return &gnttab_list[(entry) / RPP][(entry) % RPP];
+}
+/* This can be used as an l-value */
+#define gnttab_entry(entry) (*__gnttab_entry(entry))
+
+static int get_free_entries(unsigned count)
+{
+	unsigned long flags;
+	int ref, rc;
+	grant_ref_t head;
+
+	spin_lock_irqsave(&gnttab_list_lock, flags);
+
+	if ((gnttab_free_count < count) &&
+	    ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) {
+		spin_unlock_irqrestore(&gnttab_list_lock, flags);
+		return rc;
+	}
+
+	ref = head = gnttab_free_head;
+	gnttab_free_count -= count;
+	while (count-- > 1)
+		head = gnttab_entry(head);
+	gnttab_free_head = gnttab_entry(head);
+	gnttab_entry(head) = GNTTAB_LIST_END;
+
+	spin_unlock_irqrestore(&gnttab_list_lock, flags);
+
+	return ref;
+}
+
+static void do_free_callbacks(void)
+{
+	struct gnttab_free_callback *callback, *next;
+
+	callback = gnttab_free_callback_list;
+	gnttab_free_callback_list = NULL;
+
+	while (callback != NULL) {
+		next = callback->next;
+		if (gnttab_free_count >= callback->count) {
+			callback->next = NULL;
+			callback->fn(callback->arg);
+		} else {
+			callback->next = gnttab_free_callback_list;
+			gnttab_free_callback_list = callback;
+		}
+		callback = next;
+	}
+}
+
+static inline void check_free_callbacks(void)
+{
+	if (unlikely(gnttab_free_callback_list))
+		do_free_callbacks();
+}
+
+static void put_free_entry(grant_ref_t ref)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&gnttab_list_lock, flags);
+	gnttab_entry(ref) = gnttab_free_head;
+	gnttab_free_head = ref;
+	gnttab_free_count++;
+	check_free_callbacks();
+	spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+
+static void update_grant_entry(grant_ref_t ref, domid_t domid,
+			       unsigned long frame, unsigned flags)
+{
+	/*
+	 * Introducing a valid entry into the grant table:
+	 *  1. Write ent->domid.
+	 *  2. Write ent->frame:
+	 *      GTF_permit_access:   Frame to which access is permitted.
+	 *      GTF_accept_transfer: Pseudo-phys frame slot being filled by new
+	 *                           frame, or zero if none.
+	 *  3. Write memory barrier (WMB).
+	 *  4. Write ent->flags, inc. valid type.
+	 */
+	shared[ref].frame = frame;
+	shared[ref].domid = domid;
+	wmb();
+	shared[ref].flags = flags;
+}
+
+/*
+ * Public grant-issuing interface functions
+ */
+void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
+				     unsigned long frame, int readonly)
+{
+	update_grant_entry(ref, domid, frame,
+			   GTF_permit_access | (readonly ? GTF_readonly : 0));
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);
+
+int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
+				int readonly)
+{
+	int ref;
+
+	ref = get_free_entries(1);
+	if (unlikely(ref < 0))
+		return -ENOSPC;
+
+	gnttab_grant_foreign_access_ref(ref, domid, frame, readonly);
+
+	return ref;
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
+
+int gnttab_query_foreign_access(grant_ref_t ref)
+{
+	u16 nflags;
+
+	nflags = shared[ref].flags;
+
+	return (nflags & (GTF_reading|GTF_writing));
+}
+EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);
+
+int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
+{
+	u16 flags, nflags;
+
+	nflags = shared[ref].flags;
+	do {
+		flags = nflags;
+		if (flags & (GTF_reading|GTF_writing)) {
+			printk(KERN_ALERT "WARNING: g.e. still in use!\n");
+			return 0;
+		}
+	} while ((nflags = sync_cmpxchg(&shared[ref].flags, flags, 0)) != flags);
+
+	return 1;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
+
+void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
+			       unsigned long page)
+{
+	if (gnttab_end_foreign_access_ref(ref, readonly)) {
+		put_free_entry(ref);
+		if (page != 0)
+			free_page(page);
+	} else {
+		/* XXX This needs to be fixed so that the ref and page are
+		   placed on a list to be freed up later. */
+		printk(KERN_WARNING
+		       "WARNING: leaking g.e. and page still in use!\n");
+	}
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
+
+int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
+{
+	int ref;
+
+	ref = get_free_entries(1);
+	if (unlikely(ref < 0))
+		return -ENOSPC;
+	gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
+
+	return ref;
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer);
+
+void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
+				       unsigned long pfn)
+{
+	update_grant_entry(ref, domid, pfn, GTF_accept_transfer);
+}
+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref);
+
+unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
+{
+	unsigned long frame;
+	u16           flags;
+
+	/*
+	 * If a transfer is not even yet started, try to reclaim the grant
+	 * reference and return failure (== 0).
+	 */
+	while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
+		if (sync_cmpxchg(&shared[ref].flags, flags, 0) == flags)
+			return 0;
+		cpu_relax();
+	}
+
+	/* If a transfer is in progress then wait until it is completed. */
+	while (!(flags & GTF_transfer_completed)) {
+		flags = shared[ref].flags;
+		cpu_relax();
+	}
+
+	rmb();	/* Read the frame number /after/ reading completion status. */
+	frame = shared[ref].frame;
+	BUG_ON(frame == 0);
+
+	return frame;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref);
+
+unsigned long gnttab_end_foreign_transfer(grant_ref_t ref)
+{
+	unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
+	put_free_entry(ref);
+	return frame;
+}
+EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer);
+
+void gnttab_free_grant_reference(grant_ref_t ref)
+{
+	put_free_entry(ref);
+}
+EXPORT_SYMBOL_GPL(gnttab_free_grant_reference);
+
+void gnttab_free_grant_references(grant_ref_t head)
+{
+	grant_ref_t ref;
+	unsigned long flags;
+	int count = 1;
+	if (head == GNTTAB_LIST_END)
+		return;
+	spin_lock_irqsave(&gnttab_list_lock, flags);
+	ref = head;
+	while (gnttab_entry(ref) != GNTTAB_LIST_END) {
+		ref = gnttab_entry(ref);
+		count++;
+	}
+	gnttab_entry(ref) = gnttab_free_head;
+	gnttab_free_head = head;
+	gnttab_free_count += count;
+	check_free_callbacks();
+	spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_free_grant_references);
+
+int gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
+{
+	int h = get_free_entries(count);
+
+	if (h < 0)
+		return -ENOSPC;
+
+	*head = h;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(gnttab_alloc_grant_references);
+
+int gnttab_empty_grant_references(const grant_ref_t *private_head)
+{
+	return (*private_head == GNTTAB_LIST_END);
+}
+EXPORT_SYMBOL_GPL(gnttab_empty_grant_references);
+
+int gnttab_claim_grant_reference(grant_ref_t *private_head)
+{
+	grant_ref_t g = *private_head;
+	if (unlikely(g == GNTTAB_LIST_END))
+		return -ENOSPC;
+	*private_head = gnttab_entry(g);
+	return g;
+}
+EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
+
+void gnttab_release_grant_reference(grant_ref_t *private_head,
+				    grant_ref_t release)
+{
+	gnttab_entry(release) = *private_head;
+	*private_head = release;
+}
+EXPORT_SYMBOL_GPL(gnttab_release_grant_reference);
+
+void gnttab_request_free_callback(struct gnttab_free_callback *callback,
+				  void (*fn)(void *), void *arg, u16 count)
+{
+	unsigned long flags;
+	spin_lock_irqsave(&gnttab_list_lock, flags);
+	if (callback->next)
+		goto out;
+	callback->fn = fn;
+	callback->arg = arg;
+	callback->count = count;
+	callback->next = gnttab_free_callback_list;
+	gnttab_free_callback_list = callback;
+	check_free_callbacks();
+out:
+	spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_request_free_callback);
+
+void gnttab_cancel_free_callback(struct gnttab_free_callback *callback)
+{
+	struct gnttab_free_callback **pcb;
+	unsigned long flags;
+
+	spin_lock_irqsave(&gnttab_list_lock, flags);
+	for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) {
+		if (*pcb == callback) {
+			*pcb = callback->next;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&gnttab_list_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback);
+
+static int grow_gnttab_list(unsigned int more_frames)
+{
+	unsigned int new_nr_grant_frames, extra_entries, i;
+
+	new_nr_grant_frames = nr_grant_frames + more_frames;
+	extra_entries       = more_frames * GREFS_PER_GRANT_FRAME;
+
+	for (i = nr_grant_frames; i < new_nr_grant_frames; i++) {
+		gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC);
+		if (!gnttab_list[i])
+			goto grow_nomem;
+	}
+
+
+	for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames;
+	     i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++)
+		gnttab_entry(i) = i + 1;
+
+	gnttab_entry(i) = gnttab_free_head;
+	gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames;
+	gnttab_free_count += extra_entries;
+
+	nr_grant_frames = new_nr_grant_frames;
+
+	check_free_callbacks();
+
+	return 0;
+
+grow_nomem:
+	for ( ; i >= nr_grant_frames; i--)
+		free_page((unsigned long) gnttab_list[i]);
+	return -ENOMEM;
+}
+
+static unsigned int __max_nr_grant_frames(void)
+{
+	struct gnttab_query_size query;
+	int rc;
+
+	query.dom = DOMID_SELF;
+
+	rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1);
+	if ((rc < 0) || (query.status != GNTST_okay))
+		return 4; /* Legacy max supported number of frames */
+
+	return query.max_nr_frames;
+}
+
+static inline unsigned int max_nr_grant_frames(void)
+{
+	unsigned int xen_max = __max_nr_grant_frames();
+
+	if (xen_max > boot_max_nr_grant_frames)
+		return boot_max_nr_grant_frames;
+	return xen_max;
+}
+
+static int map_pte_fn(pte_t *pte, struct page *pmd_page,
+		      unsigned long addr, void *data)
+{
+	unsigned long **frames = (unsigned long **)data;
+
+	set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL));
+	(*frames)++;
+	return 0;
+}
+
+static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,
+			unsigned long addr, void *data)
+{
+
+	set_pte_at(&init_mm, addr, pte, __pte(0));
+	return 0;
+}
+
+static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
+{
+	struct gnttab_setup_table setup;
+	unsigned long *frames;
+	unsigned int nr_gframes = end_idx + 1;
+	int rc;
+
+	frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC);
+	if (!frames)
+		return -ENOMEM;
+
+	setup.dom        = DOMID_SELF;
+	setup.nr_frames  = nr_gframes;
+	setup.frame_list = frames;
+
+	rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
+	if (rc == -ENOSYS) {
+		kfree(frames);
+		return -ENOSYS;
+	}
+
+	BUG_ON(rc || setup.status);
+
+	if (shared == NULL) {
+		struct vm_struct *area;
+		area = alloc_vm_area(PAGE_SIZE * max_nr_grant_frames());
+		BUG_ON(area == NULL);
+		shared = area->addr;
+	}
+	rc = apply_to_page_range(&init_mm, (unsigned long)shared,
+				 PAGE_SIZE * nr_gframes,
+				 map_pte_fn, &frames);
+	BUG_ON(rc);
+	frames -= nr_gframes; /* adjust after map_pte_fn() */
+
+	kfree(frames);
+
+	return 0;
+}
+
+static int gnttab_resume(void)
+{
+	if (max_nr_grant_frames() < nr_grant_frames)
+		return -ENOSYS;
+	return gnttab_map(0, nr_grant_frames - 1);
+}
+
+static int gnttab_suspend(void)
+{
+	apply_to_page_range(&init_mm, (unsigned long)shared,
+			    PAGE_SIZE * nr_grant_frames,
+			    unmap_pte_fn, NULL);
+
+	return 0;
+}
+
+static int gnttab_expand(unsigned int req_entries)
+{
+	int rc;
+	unsigned int cur, extra;
+
+	cur = nr_grant_frames;
+	extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) /
+		 GREFS_PER_GRANT_FRAME);
+	if (cur + extra > max_nr_grant_frames())
+		return -ENOSPC;
+
+	rc = gnttab_map(cur, cur + extra - 1);
+	if (rc == 0)
+		rc = grow_gnttab_list(extra);
+
+	return rc;
+}
+
+static int __devinit gnttab_init(void)
+{
+	int i;
+	unsigned int max_nr_glist_frames;
+	unsigned int nr_init_grefs;
+
+	if (!is_running_on_xen())
+		return -ENODEV;
+
+	nr_grant_frames = 1;
+	boot_max_nr_grant_frames = __max_nr_grant_frames();
+
+	/* Determine the maximum number of frames required for the
+	 * grant reference free list on the current hypervisor.
+	 */
+	max_nr_glist_frames = (boot_max_nr_grant_frames *
+			       GREFS_PER_GRANT_FRAME /
+			       (PAGE_SIZE / sizeof(grant_ref_t)));
+
+	gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *),
+			      GFP_KERNEL);
+	if (gnttab_list == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i < nr_grant_frames; i++) {
+		gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL);
+		if (gnttab_list[i] == NULL)
+			goto ini_nomem;
+	}
+
+	if (gnttab_resume() < 0)
+		return -ENODEV;
+
+	nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME;
+
+	for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
+		gnttab_entry(i) = i + 1;
+
+	gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END;
+	gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
+	gnttab_free_head  = NR_RESERVED_ENTRIES;
+
+	printk("Grant table initialized\n");
+	return 0;
+
+ ini_nomem:
+	for (i--; i >= 0; i--)
+		free_page((unsigned long)gnttab_list[i]);
+	kfree(gnttab_list);
+	return -ENOMEM;
+}
+
+core_initcall(gnttab_init);
diff --git a/drivers/xen/xenbus/Makefile b/drivers/xen/xenbus/Makefile
new file mode 100644
index 0000000..5571f5b
--- /dev/null
+++ b/drivers/xen/xenbus/Makefile
@@ -0,0 +1,7 @@
+obj-y	+= xenbus.o
+
+xenbus-objs =
+xenbus-objs += xenbus_client.o
+xenbus-objs += xenbus_comms.o
+xenbus-objs += xenbus_xs.o
+xenbus-objs += xenbus_probe.o
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
new file mode 100644
index 0000000..9fd2f70
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_client.c
@@ -0,0 +1,569 @@
+/******************************************************************************
+ * Client-facing interface for the Xenbus driver.  In other words, the
+ * interface between the Xenbus and the device-specific code, be it the
+ * frontend or the backend of that driver.
+ *
+ * Copyright (C) 2005 XenSource Ltd
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/event_channel.h>
+#include <xen/events.h>
+#include <xen/grant_table.h>
+#include <xen/xenbus.h>
+
+const char *xenbus_strstate(enum xenbus_state state)
+{
+	static const char *const name[] = {
+		[ XenbusStateUnknown      ] = "Unknown",
+		[ XenbusStateInitialising ] = "Initialising",
+		[ XenbusStateInitWait     ] = "InitWait",
+		[ XenbusStateInitialised  ] = "Initialised",
+		[ XenbusStateConnected    ] = "Connected",
+		[ XenbusStateClosing      ] = "Closing",
+		[ XenbusStateClosed	  ] = "Closed",
+	};
+	return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
+}
+EXPORT_SYMBOL_GPL(xenbus_strstate);
+
+/**
+ * xenbus_watch_path - register a watch
+ * @dev: xenbus device
+ * @path: path to watch
+ * @watch: watch to register
+ * @callback: callback to register
+ *
+ * Register a @watch on the given path, using the given xenbus_watch structure
+ * for storage, and the given @callback function as the callback.  Return 0 on
+ * success, or -errno on error.  On success, the given @path will be saved as
+ * @watch->node, and remains the caller's to free.  On error, @watch->node will
+ * be NULL, the device will switch to %XenbusStateClosing, and the error will
+ * be saved in the store.
+ */
+int xenbus_watch_path(struct xenbus_device *dev, const char *path,
+		      struct xenbus_watch *watch,
+		      void (*callback)(struct xenbus_watch *,
+				       const char **, unsigned int))
+{
+	int err;
+
+	watch->node = path;
+	watch->callback = callback;
+
+	err = register_xenbus_watch(watch);
+
+	if (err) {
+		watch->node = NULL;
+		watch->callback = NULL;
+		xenbus_dev_fatal(dev, err, "adding watch on %s", path);
+	}
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_watch_path);
+
+
+/**
+ * xenbus_watch_pathfmt - register a watch on a sprintf-formatted path
+ * @dev: xenbus device
+ * @watch: watch to register
+ * @callback: callback to register
+ * @pathfmt: format of path to watch
+ *
+ * Register a watch on the given @path, using the given xenbus_watch
+ * structure for storage, and the given @callback function as the callback.
+ * Return 0 on success, or -errno on error.  On success, the watched path
+ * (@path/@path2) will be saved as @watch->node, and becomes the caller's to
+ * kfree().  On error, watch->node will be NULL, so the caller has nothing to
+ * free, the device will switch to %XenbusStateClosing, and the error will be
+ * saved in the store.
+ */
+int xenbus_watch_pathfmt(struct xenbus_device *dev,
+			 struct xenbus_watch *watch,
+			 void (*callback)(struct xenbus_watch *,
+					const char **, unsigned int),
+			 const char *pathfmt, ...)
+{
+	int err;
+	va_list ap;
+	char *path;
+
+	va_start(ap, pathfmt);
+	path = kvasprintf(GFP_KERNEL, pathfmt, ap);
+	va_end(ap);
+
+	if (!path) {
+		xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch");
+		return -ENOMEM;
+	}
+	err = xenbus_watch_path(dev, path, watch, callback);
+
+	if (err)
+		kfree(path);
+	return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_watch_pathfmt);
+
+
+/**
+ * xenbus_switch_state
+ * @dev: xenbus device
+ * @xbt: transaction handle
+ * @state: new state
+ *
+ * Advertise in the store a change of the given driver to the given new_state.
+ * Return 0 on success, or -errno on error.  On error, the device will switch
+ * to XenbusStateClosing, and the error will be saved in the store.
+ */
+int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state)
+{
+	/* We check whether the state is currently set to the given value, and
+	   if not, then the state is set.  We don't want to unconditionally
+	   write the given state, because we don't want to fire watches
+	   unnecessarily.  Furthermore, if the node has gone, we don't write
+	   to it, as the device will be tearing down, and we don't want to
+	   resurrect that directory.
+
+	   Note that, because of this cached value of our state, this function
+	   will not work inside a Xenstore transaction (something it was
+	   trying to in the past) because dev->state would not get reset if
+	   the transaction was aborted.
+
+	 */
+
+	int current_state;
+	int err;
+
+	if (state == dev->state)
+		return 0;
+
+	err = xenbus_scanf(XBT_NIL, dev->nodename, "state", "%d",
+			   &current_state);
+	if (err != 1)
+		return 0;
+
+	err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%d", state);
+	if (err) {
+		if (state != XenbusStateClosing) /* Avoid looping */
+			xenbus_dev_fatal(dev, err, "writing new state");
+		return err;
+	}
+
+	dev->state = state;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_switch_state);
+
+int xenbus_frontend_closed(struct xenbus_device *dev)
+{
+	xenbus_switch_state(dev, XenbusStateClosed);
+	complete(&dev->down);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_frontend_closed);
+
+/**
+ * Return the path to the error node for the given device, or NULL on failure.
+ * If the value returned is non-NULL, then it is the caller's to kfree.
+ */
+static char *error_path(struct xenbus_device *dev)
+{
+	return kasprintf(GFP_KERNEL, "error/%s", dev->nodename);
+}
+
+
+static void xenbus_va_dev_error(struct xenbus_device *dev, int err,
+				const char *fmt, va_list ap)
+{
+	int ret;
+	unsigned int len;
+	char *printf_buffer = NULL;
+	char *path_buffer = NULL;
+
+#define PRINTF_BUFFER_SIZE 4096
+	printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
+	if (printf_buffer == NULL)
+		goto fail;
+
+	len = sprintf(printf_buffer, "%i ", -err);
+	ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap);
+
+	BUG_ON(len + ret > PRINTF_BUFFER_SIZE-1);
+
+	dev_err(&dev->dev, "%s\n", printf_buffer);
+
+	path_buffer = error_path(dev);
+
+	if (path_buffer == NULL) {
+		dev_err(&dev->dev, "failed to write error node for %s (%s)\n",
+		       dev->nodename, printf_buffer);
+		goto fail;
+	}
+
+	if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) {
+		dev_err(&dev->dev, "failed to write error node for %s (%s)\n",
+		       dev->nodename, printf_buffer);
+		goto fail;
+	}
+
+fail:
+	kfree(printf_buffer);
+	kfree(path_buffer);
+}
+
+
+/**
+ * xenbus_dev_error
+ * @dev: xenbus device
+ * @err: error to report
+ * @fmt: error message format
+ *
+ * Report the given negative errno into the store, along with the given
+ * formatted message.
+ */
+void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	xenbus_va_dev_error(dev, err, fmt, ap);
+	va_end(ap);
+}
+EXPORT_SYMBOL_GPL(xenbus_dev_error);
+
+/**
+ * xenbus_dev_fatal
+ * @dev: xenbus device
+ * @err: error to report
+ * @fmt: error message format
+ *
+ * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by
+ * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly
+ * closedown of this driver and its peer.
+ */
+
+void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	xenbus_va_dev_error(dev, err, fmt, ap);
+	va_end(ap);
+
+	xenbus_switch_state(dev, XenbusStateClosing);
+}
+EXPORT_SYMBOL_GPL(xenbus_dev_fatal);
+
+/**
+ * xenbus_grant_ring
+ * @dev: xenbus device
+ * @ring_mfn: mfn of ring to grant
+
+ * Grant access to the given @ring_mfn to the peer of the given device.  Return
+ * 0 on success, or -errno on error.  On error, the device will switch to
+ * XenbusStateClosing, and the error will be saved in the store.
+ */
+int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn)
+{
+	int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0);
+	if (err < 0)
+		xenbus_dev_fatal(dev, err, "granting access to ring page");
+	return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_grant_ring);
+
+
+/**
+ * Allocate an event channel for the given xenbus_device, assigning the newly
+ * created local port to *port.  Return 0 on success, or -errno on error.  On
+ * error, the device will switch to XenbusStateClosing, and the error will be
+ * saved in the store.
+ */
+int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port)
+{
+	struct evtchn_alloc_unbound alloc_unbound;
+	int err;
+
+	alloc_unbound.dom = DOMID_SELF;
+	alloc_unbound.remote_dom = dev->otherend_id;
+
+	err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
+					  &alloc_unbound);
+	if (err)
+		xenbus_dev_fatal(dev, err, "allocating event channel");
+	else
+		*port = alloc_unbound.port;
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_alloc_evtchn);
+
+
+/**
+ * Bind to an existing interdomain event channel in another domain. Returns 0
+ * on success and stores the local port in *port. On error, returns -errno,
+ * switches the device to XenbusStateClosing, and saves the error in XenStore.
+ */
+int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port)
+{
+	struct evtchn_bind_interdomain bind_interdomain;
+	int err;
+
+	bind_interdomain.remote_dom = dev->otherend_id;
+	bind_interdomain.remote_port = remote_port;
+
+	err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
+					  &bind_interdomain);
+	if (err)
+		xenbus_dev_fatal(dev, err,
+				 "binding to event channel %d from domain %d",
+				 remote_port, dev->otherend_id);
+	else
+		*port = bind_interdomain.local_port;
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_bind_evtchn);
+
+
+/**
+ * Free an existing event channel. Returns 0 on success or -errno on error.
+ */
+int xenbus_free_evtchn(struct xenbus_device *dev, int port)
+{
+	struct evtchn_close close;
+	int err;
+
+	close.port = port;
+
+	err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
+	if (err)
+		xenbus_dev_error(dev, err, "freeing event channel %d", port);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_free_evtchn);
+
+
+/**
+ * xenbus_map_ring_valloc
+ * @dev: xenbus device
+ * @gnt_ref: grant reference
+ * @vaddr: pointer to address to be filled out by mapping
+ *
+ * Based on Rusty Russell's skeleton driver's map_page.
+ * Map a page of memory into this domain from another domain's grant table.
+ * xenbus_map_ring_valloc allocates a page of virtual address space, maps the
+ * page to that address, and sets *vaddr to that address.
+ * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h)
+ * or -ENOMEM on error. If an error is returned, device will switch to
+ * XenbusStateClosing and the error message will be saved in XenStore.
+ */
+int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr)
+{
+	struct gnttab_map_grant_ref op = {
+		.flags = GNTMAP_host_map,
+		.ref   = gnt_ref,
+		.dom   = dev->otherend_id,
+	};
+	struct vm_struct *area;
+
+	*vaddr = NULL;
+
+	area = alloc_vm_area(PAGE_SIZE);
+	if (!area)
+		return -ENOMEM;
+
+	op.host_addr = (unsigned long)area->addr;
+
+	if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+		BUG();
+
+	if (op.status != GNTST_okay) {
+		free_vm_area(area);
+		xenbus_dev_fatal(dev, op.status,
+				 "mapping in shared page %d from domain %d",
+				 gnt_ref, dev->otherend_id);
+		return op.status;
+	}
+
+	/* Stuff the handle in an unused field */
+	area->phys_addr = (unsigned long)op.handle;
+
+	*vaddr = area->addr;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc);
+
+
+/**
+ * xenbus_map_ring
+ * @dev: xenbus device
+ * @gnt_ref: grant reference
+ * @handle: pointer to grant handle to be filled
+ * @vaddr: address to be mapped to
+ *
+ * Map a page of memory into this domain from another domain's grant table.
+ * xenbus_map_ring does not allocate the virtual address space (you must do
+ * this yourself!). It only maps in the page to the specified address.
+ * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h)
+ * or -ENOMEM on error. If an error is returned, device will switch to
+ * XenbusStateClosing and the error message will be saved in XenStore.
+ */
+int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref,
+		    grant_handle_t *handle, void *vaddr)
+{
+	struct gnttab_map_grant_ref op = {
+		.host_addr = (unsigned long)vaddr,
+		.flags     = GNTMAP_host_map,
+		.ref       = gnt_ref,
+		.dom       = dev->otherend_id,
+	};
+
+	if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+		BUG();
+
+	if (op.status != GNTST_okay) {
+		xenbus_dev_fatal(dev, op.status,
+				 "mapping in shared page %d from domain %d",
+				 gnt_ref, dev->otherend_id);
+	} else
+		*handle = op.handle;
+
+	return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_map_ring);
+
+
+/**
+ * xenbus_unmap_ring_vfree
+ * @dev: xenbus device
+ * @vaddr: addr to unmap
+ *
+ * Based on Rusty Russell's skeleton driver's unmap_page.
+ * Unmap a page of memory in this domain that was imported from another domain.
+ * Use xenbus_unmap_ring_vfree if you mapped in your memory with
+ * xenbus_map_ring_valloc (it will free the virtual address space).
+ * Returns 0 on success and returns GNTST_* on error
+ * (see xen/include/interface/grant_table.h).
+ */
+int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr)
+{
+	struct vm_struct *area;
+	struct gnttab_unmap_grant_ref op = {
+		.host_addr = (unsigned long)vaddr,
+	};
+
+	/* It'd be nice if linux/vmalloc.h provided a find_vm_area(void *addr)
+	 * method so that we don't have to muck with vmalloc internals here.
+	 * We could force the user to hang on to their struct vm_struct from
+	 * xenbus_map_ring_valloc, but these 6 lines considerably simplify
+	 * this API.
+	 */
+	read_lock(&vmlist_lock);
+	for (area = vmlist; area != NULL; area = area->next) {
+		if (area->addr == vaddr)
+			break;
+	}
+	read_unlock(&vmlist_lock);
+
+	if (!area) {
+		xenbus_dev_error(dev, -ENOENT,
+				 "can't find mapped virtual address %p", vaddr);
+		return GNTST_bad_virt_addr;
+	}
+
+	op.handle = (grant_handle_t)area->phys_addr;
+
+	if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+		BUG();
+
+	if (op.status == GNTST_okay)
+		free_vm_area(area);
+	else
+		xenbus_dev_error(dev, op.status,
+				 "unmapping page at handle %d error %d",
+				 (int16_t)area->phys_addr, op.status);
+
+	return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree);
+
+
+/**
+ * xenbus_unmap_ring
+ * @dev: xenbus device
+ * @handle: grant handle
+ * @vaddr: addr to unmap
+ *
+ * Unmap a page of memory in this domain that was imported from another domain.
+ * Returns 0 on success and returns GNTST_* on error
+ * (see xen/include/interface/grant_table.h).
+ */
+int xenbus_unmap_ring(struct xenbus_device *dev,
+		      grant_handle_t handle, void *vaddr)
+{
+	struct gnttab_unmap_grant_ref op = {
+		.host_addr = (unsigned long)vaddr,
+		.handle    = handle,
+	};
+
+	if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+		BUG();
+
+	if (op.status != GNTST_okay)
+		xenbus_dev_error(dev, op.status,
+				 "unmapping page at handle %d error %d",
+				 handle, op.status);
+
+	return op.status;
+}
+EXPORT_SYMBOL_GPL(xenbus_unmap_ring);
+
+
+/**
+ * xenbus_read_driver_state
+ * @path: path for driver
+ *
+ * Return the state of the driver rooted at the given store path, or
+ * XenbusStateUnknown if no state can be read.
+ */
+enum xenbus_state xenbus_read_driver_state(const char *path)
+{
+	enum xenbus_state result;
+	int err = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL);
+	if (err)
+		result = XenbusStateUnknown;
+
+	return result;
+}
+EXPORT_SYMBOL_GPL(xenbus_read_driver_state);
diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c
new file mode 100644
index 0000000..6efbe3f
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_comms.c
@@ -0,0 +1,233 @@
+/******************************************************************************
+ * xenbus_comms.c
+ *
+ * Low level code to talks to Xen Store: ringbuffer and event channel.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <xen/xenbus.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/events.h>
+#include <xen/page.h>
+#include "xenbus_comms.h"
+
+static int xenbus_irq;
+
+static DECLARE_WORK(probe_work, xenbus_probe);
+
+static DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
+
+static irqreturn_t wake_waiting(int irq, void *unused)
+{
+	if (unlikely(xenstored_ready == 0)) {
+		xenstored_ready = 1;
+		schedule_work(&probe_work);
+	}
+
+	wake_up(&xb_waitq);
+	return IRQ_HANDLED;
+}
+
+static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
+{
+	return ((prod - cons) <= XENSTORE_RING_SIZE);
+}
+
+static void *get_output_chunk(XENSTORE_RING_IDX cons,
+			      XENSTORE_RING_IDX prod,
+			      char *buf, uint32_t *len)
+{
+	*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
+	if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
+		*len = XENSTORE_RING_SIZE - (prod - cons);
+	return buf + MASK_XENSTORE_IDX(prod);
+}
+
+static const void *get_input_chunk(XENSTORE_RING_IDX cons,
+				   XENSTORE_RING_IDX prod,
+				   const char *buf, uint32_t *len)
+{
+	*len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
+	if ((prod - cons) < *len)
+		*len = prod - cons;
+	return buf + MASK_XENSTORE_IDX(cons);
+}
+
+/**
+ * xb_write - low level write
+ * @data: buffer to send
+ * @len: length of buffer
+ *
+ * Returns 0 on success, error otherwise.
+ */
+int xb_write(const void *data, unsigned len)
+{
+	struct xenstore_domain_interface *intf = xen_store_interface;
+	XENSTORE_RING_IDX cons, prod;
+	int rc;
+
+	while (len != 0) {
+		void *dst;
+		unsigned int avail;
+
+		rc = wait_event_interruptible(
+			xb_waitq,
+			(intf->req_prod - intf->req_cons) !=
+			XENSTORE_RING_SIZE);
+		if (rc < 0)
+			return rc;
+
+		/* Read indexes, then verify. */
+		cons = intf->req_cons;
+		prod = intf->req_prod;
+		if (!check_indexes(cons, prod)) {
+			intf->req_cons = intf->req_prod = 0;
+			return -EIO;
+		}
+
+		dst = get_output_chunk(cons, prod, intf->req, &avail);
+		if (avail == 0)
+			continue;
+		if (avail > len)
+			avail = len;
+
+		/* Must write data /after/ reading the consumer index. */
+		mb();
+
+		memcpy(dst, data, avail);
+		data += avail;
+		len -= avail;
+
+		/* Other side must not see new producer until data is there. */
+		wmb();
+		intf->req_prod += avail;
+
+		/* Implies mb(): other side will see the updated producer. */
+		notify_remote_via_evtchn(xen_store_evtchn);
+	}
+
+	return 0;
+}
+
+int xb_data_to_read(void)
+{
+	struct xenstore_domain_interface *intf = xen_store_interface;
+	return (intf->rsp_cons != intf->rsp_prod);
+}
+
+int xb_wait_for_data_to_read(void)
+{
+	return wait_event_interruptible(xb_waitq, xb_data_to_read());
+}
+
+int xb_read(void *data, unsigned len)
+{
+	struct xenstore_domain_interface *intf = xen_store_interface;
+	XENSTORE_RING_IDX cons, prod;
+	int rc;
+
+	while (len != 0) {
+		unsigned int avail;
+		const char *src;
+
+		rc = xb_wait_for_data_to_read();
+		if (rc < 0)
+			return rc;
+
+		/* Read indexes, then verify. */
+		cons = intf->rsp_cons;
+		prod = intf->rsp_prod;
+		if (!check_indexes(cons, prod)) {
+			intf->rsp_cons = intf->rsp_prod = 0;
+			return -EIO;
+		}
+
+		src = get_input_chunk(cons, prod, intf->rsp, &avail);
+		if (avail == 0)
+			continue;
+		if (avail > len)
+			avail = len;
+
+		/* Must read data /after/ reading the producer index. */
+		rmb();
+
+		memcpy(data, src, avail);
+		data += avail;
+		len -= avail;
+
+		/* Other side must not see free space until we've copied out */
+		mb();
+		intf->rsp_cons += avail;
+
+		pr_debug("Finished read of %i bytes (%i to go)\n", avail, len);
+
+		/* Implies mb(): other side will see the updated consumer. */
+		notify_remote_via_evtchn(xen_store_evtchn);
+	}
+
+	return 0;
+}
+
+/**
+ * xb_init_comms - Set up interrupt handler off store event channel.
+ */
+int xb_init_comms(void)
+{
+	struct xenstore_domain_interface *intf = xen_store_interface;
+	int err;
+
+	if (intf->req_prod != intf->req_cons)
+		printk(KERN_ERR "XENBUS request ring is not quiescent "
+		       "(%08x:%08x)!\n", intf->req_cons, intf->req_prod);
+
+	if (intf->rsp_prod != intf->rsp_cons) {
+		printk(KERN_WARNING "XENBUS response ring is not quiescent "
+		       "(%08x:%08x): fixing up\n",
+		       intf->rsp_cons, intf->rsp_prod);
+		intf->rsp_cons = intf->rsp_prod;
+	}
+
+	if (xenbus_irq)
+		unbind_from_irqhandler(xenbus_irq, &xb_waitq);
+
+	err = bind_evtchn_to_irqhandler(
+		xen_store_evtchn, wake_waiting,
+		0, "xenbus", &xb_waitq);
+	if (err <= 0) {
+		printk(KERN_ERR "XENBUS request irq failed %i\n", err);
+		return err;
+	}
+
+	xenbus_irq = err;
+
+	return 0;
+}
diff --git a/drivers/xen/xenbus/xenbus_comms.h b/drivers/xen/xenbus/xenbus_comms.h
new file mode 100644
index 0000000..c21db75
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_comms.h
@@ -0,0 +1,46 @@
+/*
+ * Private include for xenbus communications.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _XENBUS_COMMS_H
+#define _XENBUS_COMMS_H
+
+int xs_init(void);
+int xb_init_comms(void);
+
+/* Low level routines. */
+int xb_write(const void *data, unsigned len);
+int xb_read(void *data, unsigned len);
+int xb_data_to_read(void);
+int xb_wait_for_data_to_read(void);
+int xs_input_avail(void);
+extern struct xenstore_domain_interface *xen_store_interface;
+extern int xen_store_evtchn;
+
+#endif /* _XENBUS_COMMS_H */
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
new file mode 100644
index 0000000..0b769f7
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -0,0 +1,935 @@
+/******************************************************************************
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 Mike Wray, Hewlett-Packard
+ * Copyright (C) 2005, 2006 XenSource Ltd
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#define DPRINTK(fmt, args...)				\
+	pr_debug("xenbus_probe (%s:%d) " fmt ".\n",	\
+		 __func__, __LINE__, ##args)
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/notifier.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/xen/hypervisor.h>
+#include <xen/xenbus.h>
+#include <xen/events.h>
+#include <xen/page.h>
+
+#include "xenbus_comms.h"
+#include "xenbus_probe.h"
+
+int xen_store_evtchn;
+struct xenstore_domain_interface *xen_store_interface;
+static unsigned long xen_store_mfn;
+
+static BLOCKING_NOTIFIER_HEAD(xenstore_chain);
+
+static void wait_for_devices(struct xenbus_driver *xendrv);
+
+static int xenbus_probe_frontend(const char *type, const char *name);
+
+static void xenbus_dev_shutdown(struct device *_dev);
+
+/* If something in array of ids matches this device, return it. */
+static const struct xenbus_device_id *
+match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
+{
+	for (; *arr->devicetype != '\0'; arr++) {
+		if (!strcmp(arr->devicetype, dev->devicetype))
+			return arr;
+	}
+	return NULL;
+}
+
+int xenbus_match(struct device *_dev, struct device_driver *_drv)
+{
+	struct xenbus_driver *drv = to_xenbus_driver(_drv);
+
+	if (!drv->ids)
+		return 0;
+
+	return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
+}
+
+/* device/<type>/<id> => <type>-<id> */
+static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
+{
+	nodename = strchr(nodename, '/');
+	if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) {
+		printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename);
+		return -EINVAL;
+	}
+
+	strlcpy(bus_id, nodename + 1, BUS_ID_SIZE);
+	if (!strchr(bus_id, '/')) {
+		printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id);
+		return -EINVAL;
+	}
+	*strchr(bus_id, '/') = '-';
+	return 0;
+}
+
+
+static void free_otherend_details(struct xenbus_device *dev)
+{
+	kfree(dev->otherend);
+	dev->otherend = NULL;
+}
+
+
+static void free_otherend_watch(struct xenbus_device *dev)
+{
+	if (dev->otherend_watch.node) {
+		unregister_xenbus_watch(&dev->otherend_watch);
+		kfree(dev->otherend_watch.node);
+		dev->otherend_watch.node = NULL;
+	}
+}
+
+
+int read_otherend_details(struct xenbus_device *xendev,
+				 char *id_node, char *path_node)
+{
+	int err = xenbus_gather(XBT_NIL, xendev->nodename,
+				id_node, "%i", &xendev->otherend_id,
+				path_node, NULL, &xendev->otherend,
+				NULL);
+	if (err) {
+		xenbus_dev_fatal(xendev, err,
+				 "reading other end details from %s",
+				 xendev->nodename);
+		return err;
+	}
+	if (strlen(xendev->otherend) == 0 ||
+	    !xenbus_exists(XBT_NIL, xendev->otherend, "")) {
+		xenbus_dev_fatal(xendev, -ENOENT,
+				 "unable to read other end from %s.  "
+				 "missing or inaccessible.",
+				 xendev->nodename);
+		free_otherend_details(xendev);
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
+
+static int read_backend_details(struct xenbus_device *xendev)
+{
+	return read_otherend_details(xendev, "backend-id", "backend");
+}
+
+
+/* Bus type for frontend drivers. */
+static struct xen_bus_type xenbus_frontend = {
+	.root = "device",
+	.levels = 2, 		/* device/type/<id> */
+	.get_bus_id = frontend_bus_id,
+	.probe = xenbus_probe_frontend,
+	.bus = {
+		.name     = "xen",
+		.match    = xenbus_match,
+		.probe    = xenbus_dev_probe,
+		.remove   = xenbus_dev_remove,
+		.shutdown = xenbus_dev_shutdown,
+	},
+};
+
+static void otherend_changed(struct xenbus_watch *watch,
+			     const char **vec, unsigned int len)
+{
+	struct xenbus_device *dev =
+		container_of(watch, struct xenbus_device, otherend_watch);
+	struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
+	enum xenbus_state state;
+
+	/* Protect us against watches firing on old details when the otherend
+	   details change, say immediately after a resume. */
+	if (!dev->otherend ||
+	    strncmp(dev->otherend, vec[XS_WATCH_PATH],
+		    strlen(dev->otherend))) {
+		dev_dbg(&dev->dev, "Ignoring watch at %s", vec[XS_WATCH_PATH]);
+		return;
+	}
+
+	state = xenbus_read_driver_state(dev->otherend);
+
+	dev_dbg(&dev->dev, "state is %d, (%s), %s, %s",
+		state, xenbus_strstate(state), dev->otherend_watch.node,
+		vec[XS_WATCH_PATH]);
+
+	/*
+	 * Ignore xenbus transitions during shutdown. This prevents us doing
+	 * work that can fail e.g., when the rootfs is gone.
+	 */
+	if (system_state > SYSTEM_RUNNING) {
+		struct xen_bus_type *bus = bus;
+		bus = container_of(dev->dev.bus, struct xen_bus_type, bus);
+		/* If we're frontend, drive the state machine to Closed. */
+		/* This should cause the backend to release our resources. */
+		if ((bus == &xenbus_frontend) && (state == XenbusStateClosing))
+			xenbus_frontend_closed(dev);
+		return;
+	}
+
+	if (drv->otherend_changed)
+		drv->otherend_changed(dev, state);
+}
+
+
+static int talk_to_otherend(struct xenbus_device *dev)
+{
+	struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver);
+
+	free_otherend_watch(dev);
+	free_otherend_details(dev);
+
+	return drv->read_otherend_details(dev);
+}
+
+
+static int watch_otherend(struct xenbus_device *dev)
+{
+	return xenbus_watch_pathfmt(dev, &dev->otherend_watch, otherend_changed,
+				    "%s/%s", dev->otherend, "state");
+}
+
+
+int xenbus_dev_probe(struct device *_dev)
+{
+	struct xenbus_device *dev = to_xenbus_device(_dev);
+	struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
+	const struct xenbus_device_id *id;
+	int err;
+
+	DPRINTK("%s", dev->nodename);
+
+	if (!drv->probe) {
+		err = -ENODEV;
+		goto fail;
+	}
+
+	id = match_device(drv->ids, dev);
+	if (!id) {
+		err = -ENODEV;
+		goto fail;
+	}
+
+	err = talk_to_otherend(dev);
+	if (err) {
+		dev_warn(&dev->dev, "talk_to_otherend on %s failed.\n",
+			 dev->nodename);
+		return err;
+	}
+
+	err = drv->probe(dev, id);
+	if (err)
+		goto fail;
+
+	err = watch_otherend(dev);
+	if (err) {
+		dev_warn(&dev->dev, "watch_otherend on %s failed.\n",
+		       dev->nodename);
+		return err;
+	}
+
+	return 0;
+fail:
+	xenbus_dev_error(dev, err, "xenbus_dev_probe on %s", dev->nodename);
+	xenbus_switch_state(dev, XenbusStateClosed);
+	return -ENODEV;
+}
+
+int xenbus_dev_remove(struct device *_dev)
+{
+	struct xenbus_device *dev = to_xenbus_device(_dev);
+	struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
+
+	DPRINTK("%s", dev->nodename);
+
+	free_otherend_watch(dev);
+	free_otherend_details(dev);
+
+	if (drv->remove)
+		drv->remove(dev);
+
+	xenbus_switch_state(dev, XenbusStateClosed);
+	return 0;
+}
+
+static void xenbus_dev_shutdown(struct device *_dev)
+{
+	struct xenbus_device *dev = to_xenbus_device(_dev);
+	unsigned long timeout = 5*HZ;
+
+	DPRINTK("%s", dev->nodename);
+
+	get_device(&dev->dev);
+	if (dev->state != XenbusStateConnected) {
+		printk(KERN_INFO "%s: %s: %s != Connected, skipping\n", __func__,
+		       dev->nodename, xenbus_strstate(dev->state));
+		goto out;
+	}
+	xenbus_switch_state(dev, XenbusStateClosing);
+	timeout = wait_for_completion_timeout(&dev->down, timeout);
+	if (!timeout)
+		printk(KERN_INFO "%s: %s timeout closing device\n",
+		       __func__, dev->nodename);
+ out:
+	put_device(&dev->dev);
+}
+
+int xenbus_register_driver_common(struct xenbus_driver *drv,
+				  struct xen_bus_type *bus,
+				  struct module *owner,
+				  const char *mod_name)
+{
+	drv->driver.name = drv->name;
+	drv->driver.bus = &bus->bus;
+	drv->driver.owner = owner;
+	drv->driver.mod_name = mod_name;
+
+	return driver_register(&drv->driver);
+}
+
+int __xenbus_register_frontend(struct xenbus_driver *drv,
+			       struct module *owner, const char *mod_name)
+{
+	int ret;
+
+	drv->read_otherend_details = read_backend_details;
+
+	ret = xenbus_register_driver_common(drv, &xenbus_frontend,
+					    owner, mod_name);
+	if (ret)
+		return ret;
+
+	/* If this driver is loaded as a module wait for devices to attach. */
+	wait_for_devices(drv);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(__xenbus_register_frontend);
+
+void xenbus_unregister_driver(struct xenbus_driver *drv)
+{
+	driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(xenbus_unregister_driver);
+
+struct xb_find_info
+{
+	struct xenbus_device *dev;
+	const char *nodename;
+};
+
+static int cmp_dev(struct device *dev, void *data)
+{
+	struct xenbus_device *xendev = to_xenbus_device(dev);
+	struct xb_find_info *info = data;
+
+	if (!strcmp(xendev->nodename, info->nodename)) {
+		info->dev = xendev;
+		get_device(dev);
+		return 1;
+	}
+	return 0;
+}
+
+struct xenbus_device *xenbus_device_find(const char *nodename,
+					 struct bus_type *bus)
+{
+	struct xb_find_info info = { .dev = NULL, .nodename = nodename };
+
+	bus_for_each_dev(bus, NULL, &info, cmp_dev);
+	return info.dev;
+}
+
+static int cleanup_dev(struct device *dev, void *data)
+{
+	struct xenbus_device *xendev = to_xenbus_device(dev);
+	struct xb_find_info *info = data;
+	int len = strlen(info->nodename);
+
+	DPRINTK("%s", info->nodename);
+
+	/* Match the info->nodename path, or any subdirectory of that path. */
+	if (strncmp(xendev->nodename, info->nodename, len))
+		return 0;
+
+	/* If the node name is longer, ensure it really is a subdirectory. */
+	if ((strlen(xendev->nodename) > len) && (xendev->nodename[len] != '/'))
+		return 0;
+
+	info->dev = xendev;
+	get_device(dev);
+	return 1;
+}
+
+static void xenbus_cleanup_devices(const char *path, struct bus_type *bus)
+{
+	struct xb_find_info info = { .nodename = path };
+
+	do {
+		info.dev = NULL;
+		bus_for_each_dev(bus, NULL, &info, cleanup_dev);
+		if (info.dev) {
+			device_unregister(&info.dev->dev);
+			put_device(&info.dev->dev);
+		}
+	} while (info.dev);
+}
+
+static void xenbus_dev_release(struct device *dev)
+{
+	if (dev)
+		kfree(to_xenbus_device(dev));
+}
+
+static ssize_t xendev_show_nodename(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename);
+}
+DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL);
+
+static ssize_t xendev_show_devtype(struct device *dev,
+				   struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype);
+}
+DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL);
+
+
+int xenbus_probe_node(struct xen_bus_type *bus,
+		      const char *type,
+		      const char *nodename)
+{
+	int err;
+	struct xenbus_device *xendev;
+	size_t stringlen;
+	char *tmpstring;
+
+	enum xenbus_state state = xenbus_read_driver_state(nodename);
+
+	if (state != XenbusStateInitialising) {
+		/* Device is not new, so ignore it.  This can happen if a
+		   device is going away after switching to Closed.  */
+		return 0;
+	}
+
+	stringlen = strlen(nodename) + 1 + strlen(type) + 1;
+	xendev = kzalloc(sizeof(*xendev) + stringlen, GFP_KERNEL);
+	if (!xendev)
+		return -ENOMEM;
+
+	xendev->state = XenbusStateInitialising;
+
+	/* Copy the strings into the extra space. */
+
+	tmpstring = (char *)(xendev + 1);
+	strcpy(tmpstring, nodename);
+	xendev->nodename = tmpstring;
+
+	tmpstring += strlen(tmpstring) + 1;
+	strcpy(tmpstring, type);
+	xendev->devicetype = tmpstring;
+	init_completion(&xendev->down);
+
+	xendev->dev.bus = &bus->bus;
+	xendev->dev.release = xenbus_dev_release;
+
+	err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename);
+	if (err)
+		goto fail;
+
+	/* Register with generic device framework. */
+	err = device_register(&xendev->dev);
+	if (err)
+		goto fail;
+
+	err = device_create_file(&xendev->dev, &dev_attr_nodename);
+	if (err)
+		goto fail_unregister;
+
+	err = device_create_file(&xendev->dev, &dev_attr_devtype);
+	if (err)
+		goto fail_remove_file;
+
+	return 0;
+fail_remove_file:
+	device_remove_file(&xendev->dev, &dev_attr_nodename);
+fail_unregister:
+	device_unregister(&xendev->dev);
+fail:
+	kfree(xendev);
+	return err;
+}
+
+/* device/<typename>/<name> */
+static int xenbus_probe_frontend(const char *type, const char *name)
+{
+	char *nodename;
+	int err;
+
+	nodename = kasprintf(GFP_KERNEL, "%s/%s/%s",
+			     xenbus_frontend.root, type, name);
+	if (!nodename)
+		return -ENOMEM;
+
+	DPRINTK("%s", nodename);
+
+	err = xenbus_probe_node(&xenbus_frontend, type, nodename);
+	kfree(nodename);
+	return err;
+}
+
+static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
+{
+	int err = 0;
+	char **dir;
+	unsigned int dir_n = 0;
+	int i;
+
+	dir = xenbus_directory(XBT_NIL, bus->root, type, &dir_n);
+	if (IS_ERR(dir))
+		return PTR_ERR(dir);
+
+	for (i = 0; i < dir_n; i++) {
+		err = bus->probe(type, dir[i]);
+		if (err)
+			break;
+	}
+	kfree(dir);
+	return err;
+}
+
+int xenbus_probe_devices(struct xen_bus_type *bus)
+{
+	int err = 0;
+	char **dir;
+	unsigned int i, dir_n;
+
+	dir = xenbus_directory(XBT_NIL, bus->root, "", &dir_n);
+	if (IS_ERR(dir))
+		return PTR_ERR(dir);
+
+	for (i = 0; i < dir_n; i++) {
+		err = xenbus_probe_device_type(bus, dir[i]);
+		if (err)
+			break;
+	}
+	kfree(dir);
+	return err;
+}
+
+static unsigned int char_count(const char *str, char c)
+{
+	unsigned int i, ret = 0;
+
+	for (i = 0; str[i]; i++)
+		if (str[i] == c)
+			ret++;
+	return ret;
+}
+
+static int strsep_len(const char *str, char c, unsigned int len)
+{
+	unsigned int i;
+
+	for (i = 0; str[i]; i++)
+		if (str[i] == c) {
+			if (len == 0)
+				return i;
+			len--;
+		}
+	return (len == 0) ? i : -ERANGE;
+}
+
+void xenbus_dev_changed(const char *node, struct xen_bus_type *bus)
+{
+	int exists, rootlen;
+	struct xenbus_device *dev;
+	char type[BUS_ID_SIZE];
+	const char *p, *root;
+
+	if (char_count(node, '/') < 2)
+		return;
+
+	exists = xenbus_exists(XBT_NIL, node, "");
+	if (!exists) {
+		xenbus_cleanup_devices(node, &bus->bus);
+		return;
+	}
+
+	/* backend/<type>/... or device/<type>/... */
+	p = strchr(node, '/') + 1;
+	snprintf(type, BUS_ID_SIZE, "%.*s", (int)strcspn(p, "/"), p);
+	type[BUS_ID_SIZE-1] = '\0';
+
+	rootlen = strsep_len(node, '/', bus->levels);
+	if (rootlen < 0)
+		return;
+	root = kasprintf(GFP_KERNEL, "%.*s", rootlen, node);
+	if (!root)
+		return;
+
+	dev = xenbus_device_find(root, &bus->bus);
+	if (!dev)
+		xenbus_probe_node(bus, type, root);
+	else
+		put_device(&dev->dev);
+
+	kfree(root);
+}
+
+static void frontend_changed(struct xenbus_watch *watch,
+			     const char **vec, unsigned int len)
+{
+	DPRINTK("");
+
+	xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend);
+}
+
+/* We watch for devices appearing and vanishing. */
+static struct xenbus_watch fe_watch = {
+	.node = "device",
+	.callback = frontend_changed,
+};
+
+static int suspend_dev(struct device *dev, void *data)
+{
+	int err = 0;
+	struct xenbus_driver *drv;
+	struct xenbus_device *xdev;
+
+	DPRINTK("");
+
+	if (dev->driver == NULL)
+		return 0;
+	drv = to_xenbus_driver(dev->driver);
+	xdev = container_of(dev, struct xenbus_device, dev);
+	if (drv->suspend)
+		err = drv->suspend(xdev);
+	if (err)
+		printk(KERN_WARNING
+		       "xenbus: suspend %s failed: %i\n", dev->bus_id, err);
+	return 0;
+}
+
+static int suspend_cancel_dev(struct device *dev, void *data)
+{
+	int err = 0;
+	struct xenbus_driver *drv;
+	struct xenbus_device *xdev;
+
+	DPRINTK("");
+
+	if (dev->driver == NULL)
+		return 0;
+	drv = to_xenbus_driver(dev->driver);
+	xdev = container_of(dev, struct xenbus_device, dev);
+	if (drv->suspend_cancel)
+		err = drv->suspend_cancel(xdev);
+	if (err)
+		printk(KERN_WARNING
+		       "xenbus: suspend_cancel %s failed: %i\n",
+		       dev->bus_id, err);
+	return 0;
+}
+
+static int resume_dev(struct device *dev, void *data)
+{
+	int err;
+	struct xenbus_driver *drv;
+	struct xenbus_device *xdev;
+
+	DPRINTK("");
+
+	if (dev->driver == NULL)
+		return 0;
+
+	drv = to_xenbus_driver(dev->driver);
+	xdev = container_of(dev, struct xenbus_device, dev);
+
+	err = talk_to_otherend(xdev);
+	if (err) {
+		printk(KERN_WARNING
+		       "xenbus: resume (talk_to_otherend) %s failed: %i\n",
+		       dev->bus_id, err);
+		return err;
+	}
+
+	xdev->state = XenbusStateInitialising;
+
+	if (drv->resume) {
+		err = drv->resume(xdev);
+		if (err) {
+			printk(KERN_WARNING
+			       "xenbus: resume %s failed: %i\n",
+			       dev->bus_id, err);
+			return err;
+		}
+	}
+
+	err = watch_otherend(xdev);
+	if (err) {
+		printk(KERN_WARNING
+		       "xenbus_probe: resume (watch_otherend) %s failed: "
+		       "%d.\n", dev->bus_id, err);
+		return err;
+	}
+
+	return 0;
+}
+
+void xenbus_suspend(void)
+{
+	DPRINTK("");
+
+	bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
+	xenbus_backend_suspend(suspend_dev);
+	xs_suspend();
+}
+EXPORT_SYMBOL_GPL(xenbus_suspend);
+
+void xenbus_resume(void)
+{
+	xb_init_comms();
+	xs_resume();
+	bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
+	xenbus_backend_resume(resume_dev);
+}
+EXPORT_SYMBOL_GPL(xenbus_resume);
+
+void xenbus_suspend_cancel(void)
+{
+	xs_suspend_cancel();
+	bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_cancel_dev);
+	xenbus_backend_resume(suspend_cancel_dev);
+}
+EXPORT_SYMBOL_GPL(xenbus_suspend_cancel);
+
+/* A flag to determine if xenstored is 'ready' (i.e. has started) */
+int xenstored_ready = 0;
+
+
+int register_xenstore_notifier(struct notifier_block *nb)
+{
+	int ret = 0;
+
+	if (xenstored_ready > 0)
+		ret = nb->notifier_call(nb, 0, NULL);
+	else
+		blocking_notifier_chain_register(&xenstore_chain, nb);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(register_xenstore_notifier);
+
+void unregister_xenstore_notifier(struct notifier_block *nb)
+{
+	blocking_notifier_chain_unregister(&xenstore_chain, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_xenstore_notifier);
+
+void xenbus_probe(struct work_struct *unused)
+{
+	BUG_ON((xenstored_ready <= 0));
+
+	/* Enumerate devices in xenstore and watch for changes. */
+	xenbus_probe_devices(&xenbus_frontend);
+	register_xenbus_watch(&fe_watch);
+	xenbus_backend_probe_and_watch();
+
+	/* Notify others that xenstore is up */
+	blocking_notifier_call_chain(&xenstore_chain, 0, NULL);
+}
+
+static int __init xenbus_probe_init(void)
+{
+	int err = 0;
+
+	DPRINTK("");
+
+	err = -ENODEV;
+	if (!is_running_on_xen())
+		goto out_error;
+
+	/* Register ourselves with the kernel bus subsystem */
+	err = bus_register(&xenbus_frontend.bus);
+	if (err)
+		goto out_error;
+
+	err = xenbus_backend_bus_register();
+	if (err)
+		goto out_unreg_front;
+
+	/*
+	 * Domain0 doesn't have a store_evtchn or store_mfn yet.
+	 */
+	if (is_initial_xendomain()) {
+		/* dom0 not yet supported */
+	} else {
+		xenstored_ready = 1;
+		xen_store_evtchn = xen_start_info->store_evtchn;
+		xen_store_mfn = xen_start_info->store_mfn;
+	}
+	xen_store_interface = mfn_to_virt(xen_store_mfn);
+
+	/* Initialize the interface to xenstore. */
+	err = xs_init();
+	if (err) {
+		printk(KERN_WARNING
+		       "XENBUS: Error initializing xenstore comms: %i\n", err);
+		goto out_unreg_back;
+	}
+
+	if (!is_initial_xendomain())
+		xenbus_probe(NULL);
+
+	return 0;
+
+  out_unreg_back:
+	xenbus_backend_bus_unregister();
+
+  out_unreg_front:
+	bus_unregister(&xenbus_frontend.bus);
+
+  out_error:
+	return err;
+}
+
+postcore_initcall(xenbus_probe_init);
+
+MODULE_LICENSE("GPL");
+
+static int is_disconnected_device(struct device *dev, void *data)
+{
+	struct xenbus_device *xendev = to_xenbus_device(dev);
+	struct device_driver *drv = data;
+
+	/*
+	 * A device with no driver will never connect. We care only about
+	 * devices which should currently be in the process of connecting.
+	 */
+	if (!dev->driver)
+		return 0;
+
+	/* Is this search limited to a particular driver? */
+	if (drv && (dev->driver != drv))
+		return 0;
+
+	return (xendev->state != XenbusStateConnected);
+}
+
+static int exists_disconnected_device(struct device_driver *drv)
+{
+	return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
+				is_disconnected_device);
+}
+
+static int print_device_status(struct device *dev, void *data)
+{
+	struct xenbus_device *xendev = to_xenbus_device(dev);
+	struct device_driver *drv = data;
+
+	/* Is this operation limited to a particular driver? */
+	if (drv && (dev->driver != drv))
+		return 0;
+
+	if (!dev->driver) {
+		/* Information only: is this too noisy? */
+		printk(KERN_INFO "XENBUS: Device with no driver: %s\n",
+		       xendev->nodename);
+	} else if (xendev->state != XenbusStateConnected) {
+		printk(KERN_WARNING "XENBUS: Timeout connecting "
+		       "to device: %s (state %d)\n",
+		       xendev->nodename, xendev->state);
+	}
+
+	return 0;
+}
+
+/* We only wait for device setup after most initcalls have run. */
+static int ready_to_wait_for_devices;
+
+/*
+ * On a 10 second timeout, wait for all devices currently configured.  We need
+ * to do this to guarantee that the filesystems and / or network devices
+ * needed for boot are available, before we can allow the boot to proceed.
+ *
+ * This needs to be on a late_initcall, to happen after the frontend device
+ * drivers have been initialised, but before the root fs is mounted.
+ *
+ * A possible improvement here would be to have the tools add a per-device
+ * flag to the store entry, indicating whether it is needed at boot time.
+ * This would allow people who knew what they were doing to accelerate their
+ * boot slightly, but of course needs tools or manual intervention to set up
+ * those flags correctly.
+ */
+static void wait_for_devices(struct xenbus_driver *xendrv)
+{
+	unsigned long timeout = jiffies + 10*HZ;
+	struct device_driver *drv = xendrv ? &xendrv->driver : NULL;
+
+	if (!ready_to_wait_for_devices || !is_running_on_xen())
+		return;
+
+	while (exists_disconnected_device(drv)) {
+		if (time_after(jiffies, timeout))
+			break;
+		schedule_timeout_interruptible(HZ/10);
+	}
+
+	bus_for_each_dev(&xenbus_frontend.bus, NULL, drv,
+			 print_device_status);
+}
+
+#ifndef MODULE
+static int __init boot_wait_for_devices(void)
+{
+	ready_to_wait_for_devices = 1;
+	wait_for_devices(NULL);
+	return 0;
+}
+
+late_initcall(boot_wait_for_devices);
+#endif
diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h
new file mode 100644
index 0000000..e09b194
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_probe.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * xenbus_probe.h
+ *
+ * Talks to Xen Store to figure out what devices we have.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 XenSource Ltd.
+ *
+ * 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _XENBUS_PROBE_H
+#define _XENBUS_PROBE_H
+
+#ifdef CONFIG_XEN_BACKEND
+extern void xenbus_backend_suspend(int (*fn)(struct device *, void *));
+extern void xenbus_backend_resume(int (*fn)(struct device *, void *));
+extern void xenbus_backend_probe_and_watch(void);
+extern int xenbus_backend_bus_register(void);
+extern void xenbus_backend_bus_unregister(void);
+#else
+static inline void xenbus_backend_suspend(int (*fn)(struct device *, void *)) {}
+static inline void xenbus_backend_resume(int (*fn)(struct device *, void *)) {}
+static inline void xenbus_backend_probe_and_watch(void) {}
+static inline int xenbus_backend_bus_register(void) { return 0; }
+static inline void xenbus_backend_bus_unregister(void) {}
+#endif
+
+struct xen_bus_type
+{
+	char *root;
+	unsigned int levels;
+	int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);
+	int (*probe)(const char *type, const char *dir);
+	struct bus_type bus;
+};
+
+extern int xenbus_match(struct device *_dev, struct device_driver *_drv);
+extern int xenbus_dev_probe(struct device *_dev);
+extern int xenbus_dev_remove(struct device *_dev);
+extern int xenbus_register_driver_common(struct xenbus_driver *drv,
+					 struct xen_bus_type *bus,
+					 struct module *owner,
+					 const char *mod_name);
+extern int xenbus_probe_node(struct xen_bus_type *bus,
+			     const char *type,
+			     const char *nodename);
+extern int xenbus_probe_devices(struct xen_bus_type *bus);
+
+extern void xenbus_dev_changed(const char *node, struct xen_bus_type *bus);
+
+#endif
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c
new file mode 100644
index 0000000..227d53b1
--- /dev/null
+++ b/drivers/xen/xenbus/xenbus_xs.c
@@ -0,0 +1,861 @@
+/******************************************************************************
+ * xenbus_xs.c
+ *
+ * This is the kernel equivalent of the "xs" library.  We don't need everything
+ * and we use xenbus_comms for communication.
+ *
+ * Copyright (C) 2005 Rusty Russell, IBM 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; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/unistd.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/uio.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/kthread.h>
+#include <linux/rwsem.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <xen/xenbus.h>
+#include "xenbus_comms.h"
+
+struct xs_stored_msg {
+	struct list_head list;
+
+	struct xsd_sockmsg hdr;
+
+	union {
+		/* Queued replies. */
+		struct {
+			char *body;
+		} reply;
+
+		/* Queued watch events. */
+		struct {
+			struct xenbus_watch *handle;
+			char **vec;
+			unsigned int vec_size;
+		} watch;
+	} u;
+};
+
+struct xs_handle {
+	/* A list of replies. Currently only one will ever be outstanding. */
+	struct list_head reply_list;
+	spinlock_t reply_lock;
+	wait_queue_head_t reply_waitq;
+
+	/*
+	 * Mutex ordering: transaction_mutex -> watch_mutex -> request_mutex.
+	 * response_mutex is never taken simultaneously with the other three.
+	 */
+
+	/* One request at a time. */
+	struct mutex request_mutex;
+
+	/* Protect xenbus reader thread against save/restore. */
+	struct mutex response_mutex;
+
+	/* Protect transactions against save/restore. */
+	struct rw_semaphore transaction_mutex;
+
+	/* Protect watch (de)register against save/restore. */
+	struct rw_semaphore watch_mutex;
+};
+
+static struct xs_handle xs_state;
+
+/* List of registered watches, and a lock to protect it. */
+static LIST_HEAD(watches);
+static DEFINE_SPINLOCK(watches_lock);
+
+/* List of pending watch callback events, and a lock to protect it. */
+static LIST_HEAD(watch_events);
+static DEFINE_SPINLOCK(watch_events_lock);
+
+/*
+ * Details of the xenwatch callback kernel thread. The thread waits on the
+ * watch_events_waitq for work to do (queued on watch_events list). When it
+ * wakes up it acquires the xenwatch_mutex before reading the list and
+ * carrying out work.
+ */
+static pid_t xenwatch_pid;
+static DEFINE_MUTEX(xenwatch_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq);
+
+static int get_error(const char *errorstring)
+{
+	unsigned int i;
+
+	for (i = 0; strcmp(errorstring, xsd_errors[i].errstring) != 0; i++) {
+		if (i == ARRAY_SIZE(xsd_errors) - 1) {
+			printk(KERN_WARNING
+			       "XENBUS xen store gave: unknown error %s",
+			       errorstring);
+			return EINVAL;
+		}
+	}
+	return xsd_errors[i].errnum;
+}
+
+static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
+{
+	struct xs_stored_msg *msg;
+	char *body;
+
+	spin_lock(&xs_state.reply_lock);
+
+	while (list_empty(&xs_state.reply_list)) {
+		spin_unlock(&xs_state.reply_lock);
+		/* XXX FIXME: Avoid synchronous wait for response here. */
+		wait_event(xs_state.reply_waitq,
+			   !list_empty(&xs_state.reply_list));
+		spin_lock(&xs_state.reply_lock);
+	}
+
+	msg = list_entry(xs_state.reply_list.next,
+			 struct xs_stored_msg, list);
+	list_del(&msg->list);
+
+	spin_unlock(&xs_state.reply_lock);
+
+	*type = msg->hdr.type;
+	if (len)
+		*len = msg->hdr.len;
+	body = msg->u.reply.body;
+
+	kfree(msg);
+
+	return body;
+}
+
+void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
+{
+	void *ret;
+	struct xsd_sockmsg req_msg = *msg;
+	int err;
+
+	if (req_msg.type == XS_TRANSACTION_START)
+		down_read(&xs_state.transaction_mutex);
+
+	mutex_lock(&xs_state.request_mutex);
+
+	err = xb_write(msg, sizeof(*msg) + msg->len);
+	if (err) {
+		msg->type = XS_ERROR;
+		ret = ERR_PTR(err);
+	} else
+		ret = read_reply(&msg->type, &msg->len);
+
+	mutex_unlock(&xs_state.request_mutex);
+
+	if ((msg->type == XS_TRANSACTION_END) ||
+	    ((req_msg.type == XS_TRANSACTION_START) &&
+	     (msg->type == XS_ERROR)))
+		up_read(&xs_state.transaction_mutex);
+
+	return ret;
+}
+
+/* Send message to xs, get kmalloc'ed reply.  ERR_PTR() on error. */
+static void *xs_talkv(struct xenbus_transaction t,
+		      enum xsd_sockmsg_type type,
+		      const struct kvec *iovec,
+		      unsigned int num_vecs,
+		      unsigned int *len)
+{
+	struct xsd_sockmsg msg;
+	void *ret = NULL;
+	unsigned int i;
+	int err;
+
+	msg.tx_id = t.id;
+	msg.req_id = 0;
+	msg.type = type;
+	msg.len = 0;
+	for (i = 0; i < num_vecs; i++)
+		msg.len += iovec[i].iov_len;
+
+	mutex_lock(&xs_state.request_mutex);
+
+	err = xb_write(&msg, sizeof(msg));
+	if (err) {
+		mutex_unlock(&xs_state.request_mutex);
+		return ERR_PTR(err);
+	}
+
+	for (i = 0; i < num_vecs; i++) {
+		err = xb_write(iovec[i].iov_base, iovec[i].iov_len);
+		if (err) {
+			mutex_unlock(&xs_state.request_mutex);
+			return ERR_PTR(err);
+		}
+	}
+
+	ret = read_reply(&msg.type, len);
+
+	mutex_unlock(&xs_state.request_mutex);
+
+	if (IS_ERR(ret))
+		return ret;
+
+	if (msg.type == XS_ERROR) {
+		err = get_error(ret);
+		kfree(ret);
+		return ERR_PTR(-err);
+	}
+
+	if (msg.type != type) {
+		if (printk_ratelimit())
+			printk(KERN_WARNING
+			       "XENBUS unexpected type [%d], expected [%d]\n",
+			       msg.type, type);
+		kfree(ret);
+		return ERR_PTR(-EINVAL);
+	}
+	return ret;
+}
+
+/* Simplified version of xs_talkv: single message. */
+static void *xs_single(struct xenbus_transaction t,
+		       enum xsd_sockmsg_type type,
+		       const char *string,
+		       unsigned int *len)
+{
+	struct kvec iovec;
+
+	iovec.iov_base = (void *)string;
+	iovec.iov_len = strlen(string) + 1;
+	return xs_talkv(t, type, &iovec, 1, len);
+}
+
+/* Many commands only need an ack, don't care what it says. */
+static int xs_error(char *reply)
+{
+	if (IS_ERR(reply))
+		return PTR_ERR(reply);
+	kfree(reply);
+	return 0;
+}
+
+static unsigned int count_strings(const char *strings, unsigned int len)
+{
+	unsigned int num;
+	const char *p;
+
+	for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1)
+		num++;
+
+	return num;
+}
+
+/* Return the path to dir with /name appended. Buffer must be kfree()'ed. */
+static char *join(const char *dir, const char *name)
+{
+	char *buffer;
+
+	if (strlen(name) == 0)
+		buffer = kasprintf(GFP_KERNEL, "%s", dir);
+	else
+		buffer = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
+	return (!buffer) ? ERR_PTR(-ENOMEM) : buffer;
+}
+
+static char **split(char *strings, unsigned int len, unsigned int *num)
+{
+	char *p, **ret;
+
+	/* Count the strings. */
+	*num = count_strings(strings, len);
+
+	/* Transfer to one big alloc for easy freeing. */
+	ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL);
+	if (!ret) {
+		kfree(strings);
+		return ERR_PTR(-ENOMEM);
+	}
+	memcpy(&ret[*num], strings, len);
+	kfree(strings);
+
+	strings = (char *)&ret[*num];
+	for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
+		ret[(*num)++] = p;
+
+	return ret;
+}
+
+char **xenbus_directory(struct xenbus_transaction t,
+			const char *dir, const char *node, unsigned int *num)
+{
+	char *strings, *path;
+	unsigned int len;
+
+	path = join(dir, node);
+	if (IS_ERR(path))
+		return (char **)path;
+
+	strings = xs_single(t, XS_DIRECTORY, path, &len);
+	kfree(path);
+	if (IS_ERR(strings))
+		return (char **)strings;
+
+	return split(strings, len, num);
+}
+EXPORT_SYMBOL_GPL(xenbus_directory);
+
+/* Check if a path exists. Return 1 if it does. */
+int xenbus_exists(struct xenbus_transaction t,
+		  const char *dir, const char *node)
+{
+	char **d;
+	int dir_n;
+
+	d = xenbus_directory(t, dir, node, &dir_n);
+	if (IS_ERR(d))
+		return 0;
+	kfree(d);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(xenbus_exists);
+
+/* Get the value of a single file.
+ * Returns a kmalloced value: call free() on it after use.
+ * len indicates length in bytes.
+ */
+void *xenbus_read(struct xenbus_transaction t,
+		  const char *dir, const char *node, unsigned int *len)
+{
+	char *path;
+	void *ret;
+
+	path = join(dir, node);
+	if (IS_ERR(path))
+		return (void *)path;
+
+	ret = xs_single(t, XS_READ, path, len);
+	kfree(path);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_read);
+
+/* Write the value of a single file.
+ * Returns -err on failure.
+ */
+int xenbus_write(struct xenbus_transaction t,
+		 const char *dir, const char *node, const char *string)
+{
+	const char *path;
+	struct kvec iovec[2];
+	int ret;
+
+	path = join(dir, node);
+	if (IS_ERR(path))
+		return PTR_ERR(path);
+
+	iovec[0].iov_base = (void *)path;
+	iovec[0].iov_len = strlen(path) + 1;
+	iovec[1].iov_base = (void *)string;
+	iovec[1].iov_len = strlen(string);
+
+	ret = xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));
+	kfree(path);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_write);
+
+/* Create a new directory. */
+int xenbus_mkdir(struct xenbus_transaction t,
+		 const char *dir, const char *node)
+{
+	char *path;
+	int ret;
+
+	path = join(dir, node);
+	if (IS_ERR(path))
+		return PTR_ERR(path);
+
+	ret = xs_error(xs_single(t, XS_MKDIR, path, NULL));
+	kfree(path);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_mkdir);
+
+/* Destroy a file or directory (directories must be empty). */
+int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node)
+{
+	char *path;
+	int ret;
+
+	path = join(dir, node);
+	if (IS_ERR(path))
+		return PTR_ERR(path);
+
+	ret = xs_error(xs_single(t, XS_RM, path, NULL));
+	kfree(path);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_rm);
+
+/* Start a transaction: changes by others will not be seen during this
+ * transaction, and changes will not be visible to others until end.
+ */
+int xenbus_transaction_start(struct xenbus_transaction *t)
+{
+	char *id_str;
+
+	down_read(&xs_state.transaction_mutex);
+
+	id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL);
+	if (IS_ERR(id_str)) {
+		up_read(&xs_state.transaction_mutex);
+		return PTR_ERR(id_str);
+	}
+
+	t->id = simple_strtoul(id_str, NULL, 0);
+	kfree(id_str);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_transaction_start);
+
+/* End a transaction.
+ * If abandon is true, transaction is discarded instead of committed.
+ */
+int xenbus_transaction_end(struct xenbus_transaction t, int abort)
+{
+	char abortstr[2];
+	int err;
+
+	if (abort)
+		strcpy(abortstr, "F");
+	else
+		strcpy(abortstr, "T");
+
+	err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL));
+
+	up_read(&xs_state.transaction_mutex);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(xenbus_transaction_end);
+
+/* Single read and scanf: returns -errno or num scanned. */
+int xenbus_scanf(struct xenbus_transaction t,
+		 const char *dir, const char *node, const char *fmt, ...)
+{
+	va_list ap;
+	int ret;
+	char *val;
+
+	val = xenbus_read(t, dir, node, NULL);
+	if (IS_ERR(val))
+		return PTR_ERR(val);
+
+	va_start(ap, fmt);
+	ret = vsscanf(val, fmt, ap);
+	va_end(ap);
+	kfree(val);
+	/* Distinctive errno. */
+	if (ret == 0)
+		return -ERANGE;
+	return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_scanf);
+
+/* Single printf and write: returns -errno or 0. */
+int xenbus_printf(struct xenbus_transaction t,
+		  const char *dir, const char *node, const char *fmt, ...)
+{
+	va_list ap;
+	int ret;
+#define PRINTF_BUFFER_SIZE 4096
+	char *printf_buffer;
+
+	printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
+	if (printf_buffer == NULL)
+		return -ENOMEM;
+
+	va_start(ap, fmt);
+	ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap);
+	va_end(ap);
+
+	BUG_ON(ret > PRINTF_BUFFER_SIZE-1);
+	ret = xenbus_write(t, dir, node, printf_buffer);
+
+	kfree(printf_buffer);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_printf);
+
+/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
+int xenbus_gather(struct xenbus_transaction t, const char *dir, ...)
+{
+	va_list ap;
+	const char *name;
+	int ret = 0;
+
+	va_start(ap, dir);
+	while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
+		const char *fmt = va_arg(ap, char *);
+		void *result = va_arg(ap, void *);
+		char *p;
+
+		p = xenbus_read(t, dir, name, NULL);
+		if (IS_ERR(p)) {
+			ret = PTR_ERR(p);
+			break;
+		}
+		if (fmt) {
+			if (sscanf(p, fmt, result) == 0)
+				ret = -EINVAL;
+			kfree(p);
+		} else
+			*(char **)result = p;
+	}
+	va_end(ap);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(xenbus_gather);
+
+static int xs_watch(const char *path, const char *token)
+{
+	struct kvec iov[2];
+
+	iov[0].iov_base = (void *)path;
+	iov[0].iov_len = strlen(path) + 1;
+	iov[1].iov_base = (void *)token;
+	iov[1].iov_len = strlen(token) + 1;
+
+	return xs_error(xs_talkv(XBT_NIL, XS_WATCH, iov,
+				 ARRAY_SIZE(iov), NULL));
+}
+
+static int xs_unwatch(const char *path, const char *token)
+{
+	struct kvec iov[2];
+
+	iov[0].iov_base = (char *)path;
+	iov[0].iov_len = strlen(path) + 1;
+	iov[1].iov_base = (char *)token;
+	iov[1].iov_len = strlen(token) + 1;
+
+	return xs_error(xs_talkv(XBT_NIL, XS_UNWATCH, iov,
+				 ARRAY_SIZE(iov), NULL));
+}
+
+static struct xenbus_watch *find_watch(const char *token)
+{
+	struct xenbus_watch *i, *cmp;
+
+	cmp = (void *)simple_strtoul(token, NULL, 16);
+
+	list_for_each_entry(i, &watches, list)
+		if (i == cmp)
+			return i;
+
+	return NULL;
+}
+
+/* Register callback to watch this node. */
+int register_xenbus_watch(struct xenbus_watch *watch)
+{
+	/* Pointer in ascii is the token. */
+	char token[sizeof(watch) * 2 + 1];
+	int err;
+
+	sprintf(token, "%lX", (long)watch);
+
+	down_read(&xs_state.watch_mutex);
+
+	spin_lock(&watches_lock);
+	BUG_ON(find_watch(token));
+	list_add(&watch->list, &watches);
+	spin_unlock(&watches_lock);
+
+	err = xs_watch(watch->node, token);
+
+	/* Ignore errors due to multiple registration. */
+	if ((err != 0) && (err != -EEXIST)) {
+		spin_lock(&watches_lock);
+		list_del(&watch->list);
+		spin_unlock(&watches_lock);
+	}
+
+	up_read(&xs_state.watch_mutex);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(register_xenbus_watch);
+
+void unregister_xenbus_watch(struct xenbus_watch *watch)
+{
+	struct xs_stored_msg *msg, *tmp;
+	char token[sizeof(watch) * 2 + 1];
+	int err;
+
+	sprintf(token, "%lX", (long)watch);
+
+	down_read(&xs_state.watch_mutex);
+
+	spin_lock(&watches_lock);
+	BUG_ON(!find_watch(token));
+	list_del(&watch->list);
+	spin_unlock(&watches_lock);
+
+	err = xs_unwatch(watch->node, token);
+	if (err)
+		printk(KERN_WARNING
+		       "XENBUS Failed to release watch %s: %i\n",
+		       watch->node, err);
+
+	up_read(&xs_state.watch_mutex);
+
+	/* Make sure there are no callbacks running currently (unless
+	   its us) */
+	if (current->pid != xenwatch_pid)
+		mutex_lock(&xenwatch_mutex);
+
+	/* Cancel pending watch events. */
+	spin_lock(&watch_events_lock);
+	list_for_each_entry_safe(msg, tmp, &watch_events, list) {
+		if (msg->u.watch.handle != watch)
+			continue;
+		list_del(&msg->list);
+		kfree(msg->u.watch.vec);
+		kfree(msg);
+	}
+	spin_unlock(&watch_events_lock);
+
+	if (current->pid != xenwatch_pid)
+		mutex_unlock(&xenwatch_mutex);
+}
+EXPORT_SYMBOL_GPL(unregister_xenbus_watch);
+
+void xs_suspend(void)
+{
+	down_write(&xs_state.transaction_mutex);
+	down_write(&xs_state.watch_mutex);
+	mutex_lock(&xs_state.request_mutex);
+	mutex_lock(&xs_state.response_mutex);
+}
+
+void xs_resume(void)
+{
+	struct xenbus_watch *watch;
+	char token[sizeof(watch) * 2 + 1];
+
+	mutex_unlock(&xs_state.response_mutex);
+	mutex_unlock(&xs_state.request_mutex);
+	up_write(&xs_state.transaction_mutex);
+
+	/* No need for watches_lock: the watch_mutex is sufficient. */
+	list_for_each_entry(watch, &watches, list) {
+		sprintf(token, "%lX", (long)watch);
+		xs_watch(watch->node, token);
+	}
+
+	up_write(&xs_state.watch_mutex);
+}
+
+void xs_suspend_cancel(void)
+{
+	mutex_unlock(&xs_state.response_mutex);
+	mutex_unlock(&xs_state.request_mutex);
+	up_write(&xs_state.watch_mutex);
+	up_write(&xs_state.transaction_mutex);
+}
+
+static int xenwatch_thread(void *unused)
+{
+	struct list_head *ent;
+	struct xs_stored_msg *msg;
+
+	for (;;) {
+		wait_event_interruptible(watch_events_waitq,
+					 !list_empty(&watch_events));
+
+		if (kthread_should_stop())
+			break;
+
+		mutex_lock(&xenwatch_mutex);
+
+		spin_lock(&watch_events_lock);
+		ent = watch_events.next;
+		if (ent != &watch_events)
+			list_del(ent);
+		spin_unlock(&watch_events_lock);
+
+		if (ent != &watch_events) {
+			msg = list_entry(ent, struct xs_stored_msg, list);
+			msg->u.watch.handle->callback(
+				msg->u.watch.handle,
+				(const char **)msg->u.watch.vec,
+				msg->u.watch.vec_size);
+			kfree(msg->u.watch.vec);
+			kfree(msg);
+		}
+
+		mutex_unlock(&xenwatch_mutex);
+	}
+
+	return 0;
+}
+
+static int process_msg(void)
+{
+	struct xs_stored_msg *msg;
+	char *body;
+	int err;
+
+	/*
+	 * We must disallow save/restore while reading a xenstore message.
+	 * A partial read across s/r leaves us out of sync with xenstored.
+	 */
+	for (;;) {
+		err = xb_wait_for_data_to_read();
+		if (err)
+			return err;
+		mutex_lock(&xs_state.response_mutex);
+		if (xb_data_to_read())
+			break;
+		/* We raced with save/restore: pending data 'disappeared'. */
+		mutex_unlock(&xs_state.response_mutex);
+	}
+
+
+	msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+	if (msg == NULL) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	err = xb_read(&msg->hdr, sizeof(msg->hdr));
+	if (err) {
+		kfree(msg);
+		goto out;
+	}
+
+	body = kmalloc(msg->hdr.len + 1, GFP_KERNEL);
+	if (body == NULL) {
+		kfree(msg);
+		err = -ENOMEM;
+		goto out;
+	}
+
+	err = xb_read(body, msg->hdr.len);
+	if (err) {
+		kfree(body);
+		kfree(msg);
+		goto out;
+	}
+	body[msg->hdr.len] = '\0';
+
+	if (msg->hdr.type == XS_WATCH_EVENT) {
+		msg->u.watch.vec = split(body, msg->hdr.len,
+					 &msg->u.watch.vec_size);
+		if (IS_ERR(msg->u.watch.vec)) {
+			err = PTR_ERR(msg->u.watch.vec);
+			kfree(msg);
+			goto out;
+		}
+
+		spin_lock(&watches_lock);
+		msg->u.watch.handle = find_watch(
+			msg->u.watch.vec[XS_WATCH_TOKEN]);
+		if (msg->u.watch.handle != NULL) {
+			spin_lock(&watch_events_lock);
+			list_add_tail(&msg->list, &watch_events);
+			wake_up(&watch_events_waitq);
+			spin_unlock(&watch_events_lock);
+		} else {
+			kfree(msg->u.watch.vec);
+			kfree(msg);
+		}
+		spin_unlock(&watches_lock);
+	} else {
+		msg->u.reply.body = body;
+		spin_lock(&xs_state.reply_lock);
+		list_add_tail(&msg->list, &xs_state.reply_list);
+		spin_unlock(&xs_state.reply_lock);
+		wake_up(&xs_state.reply_waitq);
+	}
+
+ out:
+	mutex_unlock(&xs_state.response_mutex);
+	return err;
+}
+
+static int xenbus_thread(void *unused)
+{
+	int err;
+
+	for (;;) {
+		err = process_msg();
+		if (err)
+			printk(KERN_WARNING "XENBUS error %d while reading "
+			       "message\n", err);
+		if (kthread_should_stop())
+			break;
+	}
+
+	return 0;
+}
+
+int xs_init(void)
+{
+	int err;
+	struct task_struct *task;
+
+	INIT_LIST_HEAD(&xs_state.reply_list);
+	spin_lock_init(&xs_state.reply_lock);
+	init_waitqueue_head(&xs_state.reply_waitq);
+
+	mutex_init(&xs_state.request_mutex);
+	mutex_init(&xs_state.response_mutex);
+	init_rwsem(&xs_state.transaction_mutex);
+	init_rwsem(&xs_state.watch_mutex);
+
+	/* Initialize the shared memory rings to talk to xenstored */
+	err = xb_init_comms();
+	if (err)
+		return err;
+
+	task = kthread_run(xenwatch_thread, NULL, "xenwatch");
+	if (IS_ERR(task))
+		return PTR_ERR(task);
+	xenwatch_pid = task->pid;
+
+	task = kthread_run(xenbus_thread, NULL, "xenbus");
+	if (IS_ERR(task))
+		return PTR_ERR(task);
+
+	return 0;
+}
diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c
index 9130f1c..808b4f8 100644
--- a/drivers/zorro/zorro-sysfs.c
+++ b/drivers/zorro/zorro-sysfs.c
@@ -78,7 +78,7 @@
 static struct bin_attribute zorro_config_attr = {
 	.attr =	{
 		.name = "config",
-		.mode = S_IRUGO | S_IWUSR,
+		.mode = S_IRUGO,
 	},
 	.size = sizeof(struct ConfigDev),
 	.read = zorro_read_config,